commit 433e7649896bfcf9f7473a7b91313680ce632e4a Author: Babylon Date: Sun Sep 6 05:43:07 2020 -0700 first commit diff --git a/License.txt b/License.txt new file mode 100644 index 0000000..8e1041e --- /dev/null +++ b/License.txt @@ -0,0 +1,45 @@ +Whatever the law says, so it applies here. + +Note that the changes to the original Dead Souls release +of 1998 are copyrighted by me, Bill Sanchez, and +are NOT GPL. Understanding what that means and +due compliance with applicable laws is left as an +exercise to the reader. + +MudOS/FluffOS is being packaged with the lib pursuant to +standard LPmud practice. Please note that MudOS and FluffOS +are copyrighted, and should we be asked to stop +distributing them by their respective copyright holders, +we will be obligated to do so. + +For explicit details on Dead Souls and MudOS +bundled distribution, please see: + +http://dead-souls.net/articles/copyright.html + +A few details, for the license fetishists: + +* It's ok to run a mud with this. Modify it as you +wish, and do what people normally associate with +"running a mud." You can change anything about the +lib after you download it. It's your mud game. I don't +care what you do with it. But you're encouraged +to share your work with me. + +* If you need to do something like forking development +and distributing your own DS-based lib, you should +use the Public Domain version, not this version. For +info, see: http://dead-souls.net/ds-II-faq.html + +* I expect this to be enough information so you +know what you can and can't do lawfully with +this software. I can't stand licensing discussion, +and will not enter into a debate with you about +what copyright means. I will not answer any +further questions on the subject. This document +is the final word on the matter. If in doubt, +refer to your local laws and regulations concerning +intellectual property. + +- Bill Sanchez aka Cratylus @ Dead Souls, aka Cratylus @ Frontiers +November 2007 diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..e137142 --- /dev/null +++ b/README.txt @@ -0,0 +1,37 @@ + The Dead Souls 2 Mud Library + Released December 2005 + +GENERAL FAQ: http://dead-souls.net/ds-faq.html + +ADMIN FAQ: http://dead-souls.net/ds-admin-faq.html + +CREATOR FAQ: http://dead-souls.net/ds-creator-faq.html + +INSTALL FAQ: http://dead-souls.net/ds-inst-faq.html + +ED TUTORIAL: http://dead-souls.net/editor.html + +CREATION SYSTEM (aka OLC, aka QCS) : http://dead-souls.net/example.html + + This software is provided as-is. Getting it running +and getting it working is on you, not me. make sure you go +through the install FAQ. There's a version archived here in +the ./www subdirectory. + + Some years ago, Descartes @ Nightmare chose to retire his +Nightmare mudlib from distribution. Yet some folks felt +that it was a fine lib, and many were sorry to see it go. + + This mudlib is based on that old warhorse. It is entirely +free from those NM IV licensing problems. It is in a state +as bug-free as I could make it, with my limited resources +and faculties. I make it available so that a new generation of +mudders can experience the joy of creating with LPC in a way +that is easy to set up, intuitive to modify, and simple to maintain. + + Please review /doc/old/README for more historical background. + + Have fun! + +-Cratylus @ Dead Souls +This document last updated: 28 Jan 2008 diff --git a/UNIX_INSTRUCTIONS.txt b/UNIX_INSTRUCTIONS.txt new file mode 100644 index 0000000..649ae3b --- /dev/null +++ b/UNIX_INSTRUCTIONS.txt @@ -0,0 +1,46 @@ +If you're on Ubuntu, you may need to apt-get bison and libc6. +See: http://dead-souls.net/ds-inst-faq.html#9 for details. + +Then perform the following steps: + +1) cd to the directory where all mud files reside. Called $MUDHOME + in the rest of this document. + +2) cd to fluffos-2* + +3) type ./configure + +4) type: make install + +5) edit $MUDHOME/bin/mudos.cfg (provided). The two to change are: +mudlib directory and binary directory. For example, if your $MUDHOME +is /home/joe/mud, then the mudlib directory line will look like this: + +/home/joe/mud/lib + +and bin: + +/home/joe/mud/bin + +6) edit $MUDHOME/bin/startmud (provided) and change the $MUDHOME + stuff. + +7) manually run the mud $MUDHOME/bin/driver $MUDHOME/bin/mudos.cfg + +8) telnet to your machine, using the port specified in mudos.cfg. For +example: telnet localhost 6666 + +9) Create a new user. Just answer the questions. Make sure you are +the first person to log in, because that person is automatically +given admin privileges. + +10) You'll get booted out. Reboot the MUD, telnet back in, and you're +now running Your Very Own MUD. + +11) If you have problems, review the FAQ: http://dead-souls.net/ds-inst-faq.html + +12) If this doesn't help, search http://lpmuds.net/forum/ for clues. This procedure works perfectly on SuSE 10 32/64bit, Solaris 10 SPARC/x86, OSX, and various other systems, but I can't possibly vouch for every unix flavor and compiler suite out there. If the compile fails, try the local_options file in extra/ + +13) If there is something actually wrong or missing in this documentation, please +ask for help on the Dead Souls support forum at http://lpmuds.net/forum/ + diff --git a/WINDOWS_INSTRUCTIONS.txt b/WINDOWS_INSTRUCTIONS.txt new file mode 100644 index 0000000..d64ba3e --- /dev/null +++ b/WINDOWS_INSTRUCTIONS.txt @@ -0,0 +1,42 @@ +YOU MUST READ THIS URL: http://dead-souls.net/ds-inst-faq.html + + +------------------------------------------------------------- +WARNING: Do NOT modify the file called +mudos.cfg. Doing so WILL cause the driver to fail. +You must use c:\ds as your mud folder. To rename the +mud, use the admintool command after you log in. + + + +WARNING: Dead Souls is NOT supported on WinME or Win98 or earlier +versions of windows. +------------------------------------------------------------- + + +1) unzip the distribution file. + +2) move the directory to c:\ + +3) there should now be a c:\ds folder, containing bin, lib, etc. If + there isn't one, rename the directory you just created to c:\ds + If Dead Souls isn't in c:\ds , it won't run. + For example, there should be a c:\ds\bin, c:\ds\lib, etc. + +4) double-click on runmud.bat + +5) telnet to your machine, using the port specified in bin/mudos.cfg. For example: telnet localhost 6666 + +6) Create a new user. Just answer the questions. Make sure you are +the first person to log in, because that person is automatically +given admin privileges. + +7) You'll get booted out. Telnet back in, and you're now running Your +Very Own MUD. + +8) If there is something actually wrong or missing in this documentation, please +ask for help on the Dead Souls support forum at http://lpmuds.net/forum/ + +9) If you have connection problems, try again with your firewall disabled. + +10) See the FAQ if you still have problems: http://dead-souls.net/ds-inst-faq.html diff --git a/bin/README b/bin/README new file mode 100644 index 0000000..4bc60c7 --- /dev/null +++ b/bin/README @@ -0,0 +1,14 @@ +To allow name and port changes from admintool, mudos.cfg +is not a link to a file inside the mudlib. + +If you hose that file or that link, copy the original +in this directory (mudos.cfg.bak) to ../lib/secure/cfg/mudos.cfg +and recreate the link. + +The commands, from this directory, are: +-------------------------------------- + +cp mudos.cfg.bak ../lib/secure/cfg/mudos.cfg + +ln -s ../lib/secure/cfg/mudos.cfg mudos.cfg + diff --git a/bin/mudos.cfg b/bin/mudos.cfg new file mode 100644 index 0000000..bc677d7 --- /dev/null +++ b/bin/mudos.cfg @@ -0,0 +1,150 @@ +############################################################################### +# Customizable runtime config file for MudOS # +# NOTE: All paths specified here are relative to the mudlib directory except # +# for mudlib directory, and binary directory. # +# Lines beginning with a # or a newline are ignored. # +############################################################################### +# name of this mud +name : DeadSoulsNew + +# port number to accept users on +external_port_1 : telnet 6666 + +# pathname of mudlib +mudlib directory : ../lib + +# pathname of driver/config dir +binary directory : ../bin + +# the address server is an external program that lets the mud translate +# internet names to numbers (and vice versa). select an unused port. +address server ip : localhost +address server port : 8099 + +# fd6 stuff is what allows portbind to work properly. If +# you want to have the mud accept connections on port 23 but run +# as non-root, you uncomment the two fd6 lines below and issue the +# appropriate portbind command to start the mud. +#fd6 port : 23 +#fd6 kind : telnet + +# debug.log and author/domain stats are stored here +log directory : /log + +# the directories which are searched by #include <...> +# for multiple dirs, separate each path with a ':' +include directories : /secure/include:/include + +# Directory to save binaries in. (if BINARIES is defined) +save binaries directory : /secure/save/binaries + +# the file which defines the master object +master file : /secure/daemon/master + +# the file where all global simulated efuns are defined. +simulated efun file : /secure/sefun/sefun + +# file to swap out objects; not used if time to swap is 0 +swap file : /secure/tmp/swap + +# alternate debug.log file name (assumed to be in specified 'log directory') +debug log file : runtime + +# This is an include file which is automatically #include'd in all objects +global include file : + +# if an object is left alone for a certain time, then the +# function clean_up will be called. This function can do anything, +# like destructing the object. If the function isn't defined by the +# object, then nothing will happen. +# This time should be substantially longer than the swapping time. +time to clean up : 2100000000 + +# How long time until an unused object is swapped out. +# Machine with too many players and too little memory: 900 (15 minutes) +# Machine with few players and lot of memory: 10000 +# Machine with infinite memory: 0 (never swap). +time to swap : 0 + +# How many seconds until an object is reset again. +time to reset : 2100000000 + +# Maximum number of bits in a bit field. They are stored in printable +# strings, 6 bits per byte. +maximum bits in a bitfield : 1200 + +# Max number of local variables in a function. +maximum local variables : 35 + +# Maximum amount of "eval cost" per thread - execution is halted when +# it is exceeded. +maximum evaluation cost : 5000000 + +# This is the maximum array size allowed for one single array. +maximum array size : 64000 + +# This is the maximum allowed size of a variable of type 'buffer'. +maximum buffer size : 400000 + +# Max size for a mapping +maximum mapping size : 64000 + +# Max inherit chain size +inherit chain size : 30 + +# maximum length of a string variable +maximum string length : 200000 + +# Max size of a file allowed to be read by 'read_file()'. +maximum read file size : 200000 + +# max number of bytes you allow to be read and written with read_bytes +# and write_bytes +maximum byte transfer : 10000 + +# Reserve an extra memory area from malloc(), to free when we run out +# of memory and allow the mudlib to shutdown. +# If this value is 0, no area will be reserved. +reserved size : 0 + +# Define the size of the shared string hash table. This number should +# a prime, probably between 1000 and 30000; if you set it to about 1/5 +# of the number of distinct strings you have, you will get a hit ratio +# (number of comparisons to find a string) very close to 1, as found strings +# are automatically moved to the head of a hash chain. You will never +# need more, and you will still get good results with a smaller table. +hash table size : 7001 + +# Object hash table size. +# Define this like you did with the strings; probably set to about 1/4 of +# the number of objects in a game, as the distribution of accesses to +# objects is somewhat more uniform than that of strings. +object table size : 1501 + +# default no-matching-action message +default fail message : What? + +# default message when error() occurs (optional) +default error message : Something *REALLY* bad just happened. + +############################################################################### +# The following aren't currently used or implemented (yet) # +############################################################################### + +# maximum number of users in the game (unused currently) +maximum users : 40 + +# Define the maximum stack size of the stack machine. This stack will also +# contain all local variables and arguments. (unused currently) +evaluator stack size : 1000 + +# Define the size of the compiler stack. This defines how complex +# expressions the compiler can parse. (unused currently) +compiler stack size : 200 + +# Define the maximum call depth for functions. (unused currently) +maximum call depth : 30 + +# There is a hash table for living objects, used by find_living(). +# (unused currently) +living hash table size : 100 diff --git a/bin/mudos.cfg.orig b/bin/mudos.cfg.orig new file mode 100644 index 0000000..bc677d7 --- /dev/null +++ b/bin/mudos.cfg.orig @@ -0,0 +1,150 @@ +############################################################################### +# Customizable runtime config file for MudOS # +# NOTE: All paths specified here are relative to the mudlib directory except # +# for mudlib directory, and binary directory. # +# Lines beginning with a # or a newline are ignored. # +############################################################################### +# name of this mud +name : DeadSoulsNew + +# port number to accept users on +external_port_1 : telnet 6666 + +# pathname of mudlib +mudlib directory : ../lib + +# pathname of driver/config dir +binary directory : ../bin + +# the address server is an external program that lets the mud translate +# internet names to numbers (and vice versa). select an unused port. +address server ip : localhost +address server port : 8099 + +# fd6 stuff is what allows portbind to work properly. If +# you want to have the mud accept connections on port 23 but run +# as non-root, you uncomment the two fd6 lines below and issue the +# appropriate portbind command to start the mud. +#fd6 port : 23 +#fd6 kind : telnet + +# debug.log and author/domain stats are stored here +log directory : /log + +# the directories which are searched by #include <...> +# for multiple dirs, separate each path with a ':' +include directories : /secure/include:/include + +# Directory to save binaries in. (if BINARIES is defined) +save binaries directory : /secure/save/binaries + +# the file which defines the master object +master file : /secure/daemon/master + +# the file where all global simulated efuns are defined. +simulated efun file : /secure/sefun/sefun + +# file to swap out objects; not used if time to swap is 0 +swap file : /secure/tmp/swap + +# alternate debug.log file name (assumed to be in specified 'log directory') +debug log file : runtime + +# This is an include file which is automatically #include'd in all objects +global include file : + +# if an object is left alone for a certain time, then the +# function clean_up will be called. This function can do anything, +# like destructing the object. If the function isn't defined by the +# object, then nothing will happen. +# This time should be substantially longer than the swapping time. +time to clean up : 2100000000 + +# How long time until an unused object is swapped out. +# Machine with too many players and too little memory: 900 (15 minutes) +# Machine with few players and lot of memory: 10000 +# Machine with infinite memory: 0 (never swap). +time to swap : 0 + +# How many seconds until an object is reset again. +time to reset : 2100000000 + +# Maximum number of bits in a bit field. They are stored in printable +# strings, 6 bits per byte. +maximum bits in a bitfield : 1200 + +# Max number of local variables in a function. +maximum local variables : 35 + +# Maximum amount of "eval cost" per thread - execution is halted when +# it is exceeded. +maximum evaluation cost : 5000000 + +# This is the maximum array size allowed for one single array. +maximum array size : 64000 + +# This is the maximum allowed size of a variable of type 'buffer'. +maximum buffer size : 400000 + +# Max size for a mapping +maximum mapping size : 64000 + +# Max inherit chain size +inherit chain size : 30 + +# maximum length of a string variable +maximum string length : 200000 + +# Max size of a file allowed to be read by 'read_file()'. +maximum read file size : 200000 + +# max number of bytes you allow to be read and written with read_bytes +# and write_bytes +maximum byte transfer : 10000 + +# Reserve an extra memory area from malloc(), to free when we run out +# of memory and allow the mudlib to shutdown. +# If this value is 0, no area will be reserved. +reserved size : 0 + +# Define the size of the shared string hash table. This number should +# a prime, probably between 1000 and 30000; if you set it to about 1/5 +# of the number of distinct strings you have, you will get a hit ratio +# (number of comparisons to find a string) very close to 1, as found strings +# are automatically moved to the head of a hash chain. You will never +# need more, and you will still get good results with a smaller table. +hash table size : 7001 + +# Object hash table size. +# Define this like you did with the strings; probably set to about 1/4 of +# the number of objects in a game, as the distribution of accesses to +# objects is somewhat more uniform than that of strings. +object table size : 1501 + +# default no-matching-action message +default fail message : What? + +# default message when error() occurs (optional) +default error message : Something *REALLY* bad just happened. + +############################################################################### +# The following aren't currently used or implemented (yet) # +############################################################################### + +# maximum number of users in the game (unused currently) +maximum users : 40 + +# Define the maximum stack size of the stack machine. This stack will also +# contain all local variables and arguments. (unused currently) +evaluator stack size : 1000 + +# Define the size of the compiler stack. This defines how complex +# expressions the compiler can parse. (unused currently) +compiler stack size : 200 + +# Define the maximum call depth for functions. (unused currently) +maximum call depth : 30 + +# There is a hash table for living objects, used by find_living(). +# (unused currently) +living hash table size : 100 diff --git a/bin/startmud b/bin/startmud new file mode 100644 index 0000000..b7a362d --- /dev/null +++ b/bin/startmud @@ -0,0 +1,65 @@ +#!/bin/bash + +if [ $1 ] +then +export DRIVER=$1 +else +export DRIVER="driver" +fi + +if [ $2 ] +then +export CFG="mudos."$2".cfg" +else +export CFG="mudos.cfg" +fi + +echo "driver: "$DRIVER +echo "cfg: "$CFG + +# Specify your mud dir here. +MUDHOME="" + +# It has been reported that non-US users have problems +# with some .o files because their systems default to +# commas for decimal notation and not periods. The +# following language exports are for the benefit of +# people who run into this problem. + +LANG=en_US +LANGUAGE=en_US +LC_ALL=en_US + +# Uncomment the following if you're on Solaris 10 with a +# 32 bit compiler and need to get around the 256 FD limit. +# NOTE: It will break things. The correct fix is to compile +# with a 64 bit compiler and set ENABLE_M64 in build.FluffOS to 1 +#LD_PRELOAD_32=/usr/lib/extendedFILE.so.1 +#export LD_PRELOAD_32 + +export LANG LANGUAGE LC_ALL MUDHOME + +umask 007 + +ulimit -a +ulimit -n 2048 +ulimit -a + +while [ true ]; do + + cat $MUDHOME/lib/log/runtime >> $MUDHOME/lib/log/runtime.boot + rm $MUDHOME/lib/log/runtime + + if [ $MUDHOME ] && [ -f $MUDHOME/bin/$DRIVER ] && [ -f $MUDHOME/bin/$CFG ] + then + $MUDHOME/bin/$DRIVER $MUDHOME/bin/$CFG + else + if [ -f ./$DRIVER ] && [ -f ./$CFG ] + then + ./$DRIVER ./$CFG + else + break + fi + fi + +done diff --git a/extra/README.txt b/extra/README.txt new file mode 100644 index 0000000..d773d8f --- /dev/null +++ b/extra/README.txt @@ -0,0 +1,15 @@ +Extras directory + +- restore_cfg If you screw up your mudos.cfg file, you can use this to + get it back. + +- I added a creremote/ dir with stuff you'll need to take advantage + of Dead Souls RCP support. However, the stuff in this dir is not + Dead Souls stuff, so it is not supported by me. + +- crat/ has some scripts I use, if you understand them, great, if + not, don't worry. They're not for you. + +- wolfpaw/ has some includes and stuff that are necessary to + run in one of the servers provided by Wolfpaw. If you're not + a customer of theirs, disregard that stuff. diff --git a/extra/crat/column_parse b/extra/crat/column_parse new file mode 100644 index 0000000..0c73389 --- /dev/null +++ b/extra/crat/column_parse @@ -0,0 +1,24 @@ +#!/usr/bin/bash + +#echo $# +if [ $# -eq 4 ] +then +#echo `awk {'print $1 " " $2 " " $3 " " $4'}` +#echo "whee" +echo $1 $2 $3 $4 >> copyfiles3 +else +#echo "Oh NOES!" +if echo $1 | grep "\cp" +then +#echo "ok trying to rewrite" +export FIX=`(echo $3 | perl -pi -e s/"new\/"/"next\/"/)` +echo $1 $2 $3 $FIX +echo $1 $2 $3 $FIX >> copyfiles3 +else +export BAR=`(echo $3 | perl -pi -e s/"\/lib"/"next\/lib"/)` +#echo "NEVER MIND, it's a delete: " $1 $2 $BAR $4 +echo $1 $2 $BAR $4 >> copyfiles3 +fi +fi + +echo "ok then" diff --git a/extra/crat/d.c b/extra/crat/d.c new file mode 100644 index 0000000..3a723f1 --- /dev/null +++ b/extra/crat/d.c @@ -0,0 +1,55 @@ +#include +#include + +inherit LIB_DAEMON; + +mixed pkginst, name, category, arch, version, desc, pstamp, instdate, status, basedir, vendor, hotline, email; + +static void create() { +} + +mixed b(string file){ + string ret = "", foo = read_file(file); + string *foo_arr = explode(foo, "\n\n"); + int i = 0; + string path = path_prefix(file); + string fname = last_string_element(file, "/"); + string thingy; + tc("foo_arr: "+sizeof(foo_arr)); + foreach(string tmp in foo_arr){ + string tmp2, sub = "", *lines = explode(tmp, "\n"); + pkginst = name = category = arch = version = desc = pstamp = instdate = status = basedir = vendor = hotline = email = 0; + foreach(string line in lines){ + line = trim(line); + if(!strsrch(line, "PKGINST:")) pkginst = replace_string(line, "PKGINST: ", "") + "^"; + if(!strsrch(line, "NAME:")) name = replace_string(line, "NAME: ", "") + "^"; + if(!strsrch(line, "CATEGORY:")) category = replace_string(line, "CATEGORY: ", "") + "^"; + if(!strsrch(line, "ARCH:")) arch = replace_string(line, "ARCH: ", "") + "^"; + if(!strsrch(line, "VERSION:")) version = replace_string(line, "VERSION: ", "") + "^"; + if(!strsrch(line, "DESC:")) desc = replace_string(line, "DESC: ", "") + "^"; + if(!strsrch(line, "PSTAMP:")) pstamp = replace_string(line, "PSTAMP: ", "") + "^"; + if(!strsrch(line, "INSTDATE:")) instdate = replace_string(line, "INSTDATE: ", "") + "^"; + if(!strsrch(line, "STATUS:")) status = replace_string(line, "STATUS: ", "") + "^"; + if(!strsrch(line, "BASEDIR:")) basedir = replace_string(line, "BASEDIR: ", "") + "^"; + if(!strsrch(line, "VENDOR:")) vendor = replace_string(line, "VENDOR: ", "") + "^"; + if(!strsrch(line, "HOTLINE:")) hotline = replace_string(line, "HOTLINE: ", "") + "^"; + if(!strsrch(line, "EMAIL:")) email = replace_string(line, "EMAIL: ", "") + "^"; + } + foreach(string element in ({"pkginst", "name", "category", "arch", "version", "basedir", "vendor", "desc", "pstamp", "instdate", "hotline", "status", "email"})){ + mixed mx = fetch_variable(element); + string ret2; + if(!mx) ret2 = "NULL^"; + else ret2 = mx; + sub += ret2; + } + i++; + //tc("file: "+file+i); + //write_file(file+i, ""+tmp); + //tc("\n\ntmp: "+tmp); + tc("\n\nsub: "+sub); + ret += sub + "\n"; + } + thingy = path+"/"+time()+"_"+fname; + tc("thingy: "+thingy); + write_file(thingy, ret, 1); +} diff --git a/extra/crat/enters b/extra/crat/enters new file mode 100644 index 0000000..171dac1 --- /dev/null +++ b/extra/crat/enters @@ -0,0 +1,6 @@ +#!/bin/bash + +if !(grep $1 /tmp/foo/diff.txt); then +\rm -f $1 +fi + diff --git a/extra/crat/gdbinit b/extra/crat/gdbinit new file mode 100644 index 0000000..9d0ec20 --- /dev/null +++ b/extra/crat/gdbinit @@ -0,0 +1,3 @@ +handle SIGPIPE nostop noprint pass +set print pretty on +run ./mudos.cfg diff --git a/extra/crat/indentall b/extra/crat/indentall new file mode 100644 index 0000000..3131c7d --- /dev/null +++ b/extra/crat/indentall @@ -0,0 +1,14 @@ +#!/bin/bash +rm /tmp/thingy.txt +for i in `find .|grep "\.c"|grep -v "\.cfg"|grep -v "\.css"` +do +if cat $i | grep "@EndText" +then +echo "Skipping $i" +echo $i >> /tmp/thingy.txt +else +echo "Indenting "$i +vim -c "set tabstop=4 shiftwidth=4 expandtab retab" -esc "normal gg=G" -c "wq" $i +fi +done + diff --git a/extra/crat/livepatch b/extra/crat/livepatch new file mode 100644 index 0000000..a31fda2 --- /dev/null +++ b/extra/crat/livepatch @@ -0,0 +1,167 @@ +# syntax: livepatch ds2.9a17 limpet [1] +export INDENT=$3 +export NEWLIB=$2 +export OLDLIB=$1 + +#vi /root/updaterr$OLD\_r$NEW.c + +cd / +date + +mkdir /tmp/foo 1>/dev/null 2>/dev/null +rm -rf /tmp/foo/* + +cd /tmp/foo + +unzip -qd $OLDLIB $HOME/mud/$OLDLIB.zip +#unzip -qd $NEWLIB /misc/data/mud/deadsouls/$NEWLIB.zip +cd /mud/ +chmod -R 755 $NEWLIB/lib +tar cfp - $NEWLIB|(cd /tmp/foo;tar xfp -) +cd /tmp/foo + +mv $OLDLIB/*/* $OLDLIB/ + +#mv $NEWLIB/*/* $NEWLIB/ + + +#\rm -f $OLDLIB/lib/secure/include/config.h +#\rm -f $NEWLIB/lib/secure/include/config.h + +\rm -f $OLDLIB/lib/secure/cfg/groups*cfg +\rm -f $OLDLIB/lib/secure/cfg/mudos*cfg +\rm -f $OLDLIB/lib/secure/cfg/mudos*win32 + +\rm -f $NEWLIB/lib/secure/cfg/groups*cfg +\rm -f $NEWLIB/lib/secure/cfg/mudos*cfg +\rm -f $NEWLIB/lib/secure/cfg/mudos*win32 + +\rm -rf $OLDLIB/lib/secure/save +\rm -rf $OLDLIB/lib/save +\rm -rf $OLDLIB/lib/secure/log +\rm -rf $OLDLIB/lib/secure/upgrades +\rm -rf $OLDLIB/lib/tmp +\rm -rf $OLDLIB/lib/daemon/tmp +\rm -rf $OLDLIB/lib/open +\rm -rf $OLDLIB/lib/log +\rm -rf $NEWLIB/lib/log +\rm -rf $NEWLIB/lib/tmp +\rm -rf $NEWLIB/lib/daemon/tmp +\rm -rf $NEWLIB/lib/open +\rm -rf $NEWLIB/lib/secure/save +\rm -rf $NEWLIB/lib/secure/log +\rm -rf $NEWLIB/lib/secure/upgrades +\rm -rf $NEWLIB/lib/save + +\rm -r $NEWLIB/lib/core $OLDLIB/lib/core 1>/dev/null 2>/dev/null +\rm -r $NEWLIB/lib/secure/sefun/native_version.c $OLDLIB/lib/secure/sefun/native_version.c + +\cp -f $NEWLIB/lib/secure/daemon/update.patch $NEWLIB/lib/secure/daemon/update.c +\cp -f $OLDLIB/lib/secure/daemon/update.patch $OLDLIB/lib/secure/daemon/update.c + +mkdir $OLDLIB/lib/www/cgi 1>/dev/null 2>/dev/null +mkdir $OLDLIB/lib/lib/daemons 1>/dev/null 2>/dev/null +mkdir $OLDLIB/lib/verbs/builders 1>/dev/null 2>/dev/null +mkdir $OLDLIB/lib/cmds/builders 1>/dev/null 2>/dev/null +mkdir $OLDLIB/lib/secure/cmds/builders 1>/dev/null 2>/dev/null +mkdir $OLDLIB/lib/secure/daemon/imc2server 1>/dev/null 2>/dev/null +mkdir $OLDLIB/lib/lib/daemon 1>/dev/null 2>/dev/null +mkdir $OLDLIB/lib/lib/daemon/include 1>/dev/null 2>/dev/null +mkdir $OLDLIB/lib/domains/cave 1>/dev/null 2>/dev/null +mkdir $OLDLIB/lib/domains/cave/adm 1>/dev/null 2>/dev/null +mkdir $OLDLIB/lib/domains/cave/armor 1>/dev/null 2>/dev/null +mkdir $OLDLIB/lib/domains/cave/doors 1>/dev/null 2>/dev/null +mkdir $OLDLIB/lib/domains/cave/etc 1>/dev/null 2>/dev/null +mkdir $OLDLIB/lib/domains/cave/meals 1>/dev/null 2>/dev/null +mkdir $OLDLIB/lib/domains/cave/npc 1>/dev/null 2>/dev/null +mkdir $OLDLIB/lib/domains/cave/obj 1>/dev/null 2>/dev/null +mkdir $OLDLIB/lib/domains/cave/room 1>/dev/null 2>/dev/null +mkdir $OLDLIB/lib/domains/cave/save 1>/dev/null 2>/dev/null +mkdir $OLDLIB/lib/domains/cave/txt 1>/dev/null 2>/dev/null +mkdir $OLDLIB/lib/domains/cave/virtual 1>/dev/null 2>/dev/null +mkdir $OLDLIB/lib/domains/cave/weap 1>/dev/null 2>/dev/null +mkdir $OLDLIB/lib/doc/phints 1>/dev/null 2>/dev/null +mkdir $OLDLIB/lib/domains/campus/chamber 1>/dev/null 2>/dev/null + +if [ $3 ] +then +echo "indenting" +cd $NEWLIB/lib +/contrib/indentall +cd ../../$OLDLIB/lib +/contrib/indentall +cd ../../ +else +echo "not indenting" +fi + +mv $NEWLIB/lib/secure/lib/connect.c $NEWLIB/lib/secure/lib/connect.real + +diff -rq $OLDLIB/lib $NEWLIB/lib > diff.txt + +perl -pi -e s/"\:\ "/"\/"/g diff.txt + +cd $NEWLIB/ + +find ./lib -type f -exec /contrib/enters {} \; +rm lib/secure/include/config.h +rm lib/secure/cfg/mudos.cfg +rm lib/secure/cfg/groups.cfg +\rm -rf lib/tmp +\rm -rf lib/log +\rm -rf lib/secure/log +\rm -rf lib/open +\rm -rf lib/secure/save +\rm -rf lib/secure/log +\rm -rf lib/secure/tmp +\rm -rf lib/secure/upgrades +\rm -rf lib/save +tar cfp ../patch.tar lib +cd .. +mv $NEWLIB fukt +unzip -qd $NEWLIB /export/home/$HOME/mud/$NEWLIB.zip +mv $NEWLIB/*/* $NEWLIB/ +cd $OLDLIB +tar xfp ../patch.tar +cd .. +\rm -rf $NEWLIB/lib/tmp +\rm -rf $NEWLIB/lib/log +\rm -rf $NEWLIB/lib/secure/log +\rm -rf $NEWLIB/lib/open +\rm -rf $NEWLIB/lib/secure/save +\rm -rf $NEWLIB/lib/secure/log +\rm -rf $NEWLIB/lib/secure/tmp +\rm -rf $NEWLIB/lib/secure/upgrades +\rm -rf $NEWLIB/lib/save + +diff -rq $OLDLIB/ $NEWLIB/ > diff2.txt +echo "Anything after this is an imperfection except for the connect.c" +cat diff2.txt +\mv -f lib lib.foo 1>/dev/null 2>/dev/null +tar xfp patch.tar +find ./lib -type f|sort -dr > lib.txt +\mv -f patch patch.foo 1>/dev/null 2>/dev/null +mkdir patch +#\cp -f ~/updaterr$OLD\_r$NEW.c lib/secure/daemon/update.c +\cp -f ~/update.blank lib/secure/daemon/ 1>/dev/null 2>/dev/null +\cp -f ~/instructions\_$OLD\_$NEW.txt patch/instructions.txt 1>/dev/null 2>/dev/null +chown -R 513:513 lib 1>/dev/null 2>/dev/null +chmod -R 775 lib 1>/dev/null 2>/dev/null +mv lib patch/ +cat diff2.txt +echo "End imperfections." +date +echo "" +cd patch/lib +find ./ -type f|grep -v "upgrades\.txt" |grep -v "\.html"|grep -v "\.gif" |grep -v "\.o" |grep -v "/news/" > upgrades.txt +find ./ -type f|grep "\.orig" >> upgrades.txt +perl -pi -e s/"\.\/lib"/"\/lib"/g upgrades.txt +perl -pi -e s/"\.\/"/"\/"/g upgrades.txt +echo "/secure/lib/connect.c" >> upgrades.txt +echo "/secure/daemon/master.h" >> upgrades.txt +cp upgrades.txt /tmp/foo/ +\cp -f upgrades.txt /mud/$NEWLIB/lib/ +echo "-------" +cat upgrades.txt +chmod 755 upgrades.txt +echo "-------" diff --git a/extra/crat/newpatch b/extra/crat/newpatch new file mode 100644 index 0000000..32f51b2 --- /dev/null +++ b/extra/crat/newpatch @@ -0,0 +1,136 @@ +#!/bin/bash -x + +export NEWLIB=$2 +export OLDLIB=$1 + +#vi /root/updaterr$OLD\_r$NEW.c + +cd / +date + +mkdir /tmp/foo +rm -rf /tmp/foo/* + +cd /tmp/foo + +unzip -qd $OLDLIB $HOME/mud/$OLDLIB.zip +unzip -qd $NEWLIB $HOME/mud/$NEWLIB.zip + +mv $OLDLIB/*/* $OLDLIB/ + +mv $NEWLIB/*/* $NEWLIB/ + +#\rm -f $OLDLIB/lib/secure/include/config.h +#\rm -f $NEWLIB/lib/secure/include/config.h + +\rm -f $OLDLIB/lib/secure/cfg/groups.cfg +\rm -f $OLDLIB/lib/secure/cfg/mudos.cfg +\rm -f $OLDLIB/lib/secure/cfg/mudos.win32 + +\rm -f $NEWLIB/lib/secure/cfg/groups.cfg +\rm -f $NEWLIB/lib/secure/cfg/mudos.cfg +\rm -f $NEWLIB/lib/secure/cfg/mudos.win32 + +\rm -r $NEWLIB/lib/core $OLDLIB/lib/core +\rm -r $NEWLIB/lib/secure/sefun/native_version.c $OLDLIB/lib/secure/sefun/native_version.c +#\rm -r $NEWLIB/lib/secure/sefun/mud_info.c $OLDLIB/lib/secure/sefun/mud_info.c + +\cp -f $NEWLIB/lib/secure/lib/connect.real $NEWLIB/lib/secure/lib/connect.c +#\rm -r $NEWLIB/lib/secure/lib/connect.c $OLDLIB/lib/secure/lib/connect.c + +\cp -f $NEWLIB/lib/secure/daemon/update.patch $NEWLIB/lib/secure/daemon/update.c +\cp -f $OLDLIB/lib/secure/daemon/update.patch $OLDLIB/lib/secure/daemon/update.c + +echo "foo" > $NEWLIB/lib/secure/upgrades/files/0^0tmp0^0foo.txt +mkdir $OLDLIB/lib/www/cgi +mkdir $OLDLIB/lib/lib/daemons +mkdir $OLDLIB/lib/verbs/builders +mkdir $OLDLIB/lib/cmds/builders +mkdir $OLDLIB/lib/secure/cmds/builders +mkdir $OLDLIB/lib/secure/daemon/imc2server +mkdir $OLDLIB/lib/lib/daemon +mkdir $OLDLIB/lib/lib/daemon/include +mkdir $OLDLIB/lib/domains/cave +mkdir $OLDLIB/lib/domains/cave/adm +mkdir $OLDLIB/lib/domains/cave/armor +mkdir $OLDLIB/lib/domains/cave/doors +mkdir $OLDLIB/lib/domains/cave/etc +mkdir $OLDLIB/lib/domains/cave/meals +mkdir $OLDLIB/lib/domains/cave/npc +mkdir $OLDLIB/lib/domains/cave/obj +mkdir $OLDLIB/lib/domains/cave/room +mkdir $OLDLIB/lib/domains/cave/save +mkdir $OLDLIB/lib/domains/cave/txt +mkdir $OLDLIB/lib/domains/cave/virtual +mkdir $OLDLIB/lib/domains/cave/weap +mkdir $OLDLIB/lib/doc/phints +mkdir $OLDLIB/lib/domains/campus/chamber +mkdir $OLDLIB/lib/domains/amigara +mkdir $OLDLIB/lib/domains/amigara/adm +mkdir $OLDLIB/lib/domains/amigara/armor +mkdir $OLDLIB/lib/domains/amigara/doors +mkdir $OLDLIB/lib/domains/amigara/etc +mkdir $OLDLIB/lib/domains/amigara/meals +mkdir $OLDLIB/lib/domains/amigara/npc +mkdir $OLDLIB/lib/domains/amigara/obj +mkdir $OLDLIB/lib/domains/amigara/room +mkdir $OLDLIB/lib/domains/amigara/save +mkdir $OLDLIB/lib/domains/amigara/txt +mkdir $OLDLIB/lib/domains/amigara/virtual +mkdir $OLDLIB/lib/domains/amigara/weap +mkdir $OLDLIB/lib/doc/cheats + +if [ $3 ] +then +echo "indenting" +cd $NEWLIB/lib +/contrib/indentall +cd ../../$OLDLIB/lib +/contrib/indentall +cd ../../ +else +echo "not indenting" +fi + +cd /tmp/foo +diff -rq $OLDLIB/lib $NEWLIB/lib > diff.txt + +perl -pi -e s/"\:\ "/"\/"/g diff.txt + +cd $NEWLIB/ + +find ./lib -type f -exec /contrib/enters {} \; +rm lib/secure/include/config.h +rm lib/secure/cfg/mudos.cfg +rm lib/secure/cfg/groups.cfg +tar cfp ../patch.tar lib +cd .. +mv $NEWLIB fukt +unzip -qd $NEWLIB /export/home/$HOME/mud/$NEWLIB.zip +mv $NEWLIB/*/* $NEWLIB/ +cd $OLDLIB +tar xfp ../patch.tar +cd .. +diff -rq $OLDLIB/ $NEWLIB/ > diff2.txt +echo "Anything after this is an imperfection except for the connect.c" +cat diff2.txt +\mv -f lib lib.foo +tar xfp patch.tar +find ./lib -type f|sort -dr > lib.txt +\mv -f patch patch.foo +mkdir patch +#\cp -f ~/updaterr$OLD\_r$NEW.c lib/secure/daemon/update.c +\cp -f ~/update.blank lib/secure/daemon/ +\cp -f ~/instructions\_$OLD\_$NEW.txt patch/instructions.txt +chown -R 513:513 lib +chmod -R 775 lib +mv lib patch/ +date +cat diff2.txt +cd patch/lib +find ./ -type f|grep -v "\.html"|grep -v "\.gif" |grep -v "\.o" |grep -v "/news/" > upgrades.txt +find ./ -type f|grep "\.orig" >> upgrades.txt +perl -pi -e s/"\.\/lib"/"\/lib"/g upgrades.txt +perl -pi -e s/"\.\/"/"\/"/g upgrades.txt +mv upgrades.txt ../ + diff --git a/extra/crat/newver b/extra/crat/newver new file mode 100644 index 0000000..d65b23e --- /dev/null +++ b/extra/crat/newver @@ -0,0 +1,182 @@ +#!/bin/bash -x + +export INDENT=$3 +export NEWLIB=$2 +export OLDLIB=$1 + +cd / +rm -rf /run/shm/foo +mkdir /run/shm/foo +rm -rf /tmp/foo +ln -s /run/shm/foo /tmp/foo + + +cd /run/shm/foo +unzip -qd $OLDLIB $HOME/mud/$OLDLIB.zip +mv $OLDLIB/ds* next +mkdir new + +cd /mud/alpha +tar cfp - . |(cd /run/shm/foo/new;tar xfp -) + +rm -rf /run/shm/foo/new/lib/secure/daemon/i3router/bak +rm -rf /run/shm/foo/next/lib/secure/daemon/i3router/bak +rm -rf /run/shm/foo/new/lib/secure/daemon/imc2server/bak +rm -rf /run/shm/foo/next/lib/secure/daemon/imc2server/bak +rm -rf /run/shm/foo/new/lib/upgrades.txt +rm -rf /run/shm/foo/next/lib/upgrades.txt +chmod -R a+r /run/shm/foo/next/lib +chmod -R a+r /run/shm/foo/new/lib + +rm -rf /run/shm/foo/new/lib/daemon/tmp +rm -rf /run/shm/foo/new/lib/secure/upgrades +rm -rf /run/shm/foo/new/lib/tmp +mv /run/shm/foo/new/lib/realms/template . +rm -rf /run/shm/foo/new/lib/realms/* +rm -rf /run/shm/foo/new/lib/open/* +mv template /run/shm/foo/new/lib/realms/ +rm -rf /run/shm/foo/new/lib/log +rm -rf /run/shm/foo/new/lib/secure/log +rm -rf /run/shm/foo/new/lib/secure/save/postal +rm -rf /run/shm/foo/new/lib/secure/save/players +rm -rf /run/shm/foo/new/lib/secure/save/creators +\rm -rf /run/shm/foo/*~ +\rm -rf /run/shm/foo/*/*~ +\rm -rf /run/shm/foo/*/*/*~ +\rm -rf /run/shm/foo/*/*/*/*~ +\rm -rf /run/shm/foo/*/*/*/*/*~ +\rm -rf /run/shm/foo/*/*/*/*/*/*~ +\rm -rf /run/shm/foo/*/*/*/*/*/*/*~ +\rm -rf /run/shm/foo/*/*/*/*/*/*/*/*~ +\rm -rf /run/shm/foo/*/*/*/*/*/*/*/*/*~ + +mkdir /run/shm/foo/next/lib/www/cgi +mkdir /run/shm/foo/next/lib/cmds/builders +mkdir /run/shm/foo/next/lib/secure/cmds/builders +mkdir /run/shm/foo/next/lib/verbs/builders +mkdir /run/shm/foo/next/lib/domains/cave +mkdir /run/shm/foo/next/lib/domains/cave/room +mkdir /run/shm/foo/next/lib/domains/cave/npc +mkdir /run/shm/foo/next/lib/domains/cave/weap +mkdir /run/shm/foo/next/lib/domains/cave/obj +mkdir /run/shm/foo/next/lib/domains/cave/meals +mkdir /run/shm/foo/next/lib/domains/cave/etc +mkdir /run/shm/foo/next/lib/domains/cave/doors +mkdir /run/shm/foo/next/lib/domains/cave/armor +mkdir /run/shm/foo/next/lib/domains/cave/adm +mkdir /run/shm/foo/next/lib/domains/cave/save +mkdir /run/shm/foo/next/lib/domains/cave/txt +mkdir /run/shm/foo/next/lib/domains/cave/virtual +mkdir /run/shm/foo/next/doc/phints +mkdir /run/shm/foo/next/lib/domains/campus/chamber + +cd /run/shm/foo + +\rm -f new/lib/secure/cfg/*.????.cfg +\rm -f new/lib/secure/cfg/*.????.win32 +\rm -f new/lib/secure/include/*.????.h +\rm -f new/lib/secure/cfg/mudos.autobak.???? +\rm -f new/lib/news/*.???? + +\rm -f new/lib/domains/campus/save/charl* +\rm -f next/lib/domains/campus/save/charl* +\rm -f next/lib/domains/town/save/charit* + +\cp -f new/lib/secure/daemon/update.patch next/lib/secure/daemon/update.patch +\mv -f new/lib/secure/lib/connect.c new/lib/secure/lib/connect.real +\cp -f new/lib/secure/lib/connect.first.c new/lib/secure/lib/connect.c +\cp -f new/lib/secure/save/backup/config.orig new/lib/secure/include/config.h +\cp -f new/lib/secure/save/backup/config.orig next/lib/secure/save/backup/config.orig +\cp -f new/lib/secure/save/backup/secrets.orig new/lib/secure/include/secrets.h +\cp -f new/lib/secure/save/backup/secrets.orig next/lib/secure/save/backup/secrets.orig +\cp -f new/lib/secure/daemon/imc2.c next/lib/secure/save/backup/imc2.orig +\rm -f next/lib/lib/remote.c +\rm -f new/lib/lib/remote.c + +if [ $3 ] +then +echo "indenting new" +#cd $NEWLIB/lib +cd new/lib +/contrib/indentall +cd ../../$OLDLIB/lib +echo "" +echo "indenting next" +sleep 5 +/contrib/indentall +cd ../../ +else +echo "not indenting" +fi + +#/opt/sfw/bin/gdiff -rq new/lib next/lib > diff.txt +cd /run/shm/foo +diff -rq new/lib next/lib > diff.txt + +perl -pi -e s/"\:\ "/"\/"/g diff.txt +perl -pi -e s/"\ and\ "/"\ "/g diff.txt +perl -pi -e s/"\ differ"/"\ "/g diff.txt + +echo "#!/bin/bash" > diff.sh.1 +echo "" >> diff.sh.1 +cat diff.txt |grep Files >> diff.sh.1 + +perl -pi -e s/"Files\ "/"\\\\cp\ \-f\ "/g diff.txt +perl -pi -e s/"Only\ in\ next"/"\\\\rm\ \-f\ "/g diff.txt +perl -pi -e s/"Only\ in\ "/"\\\\cp\ \-rf\ "/g diff.txt + +perl -pi -e s/"Files\ "/"diff\ -Nur\ "/g diff.sh.1 + + +cat diff.txt | grep -v "\.prime" | grep -v "lib/core" |grep -v "\.o"|grep -v CMD_EVAL_TMP_FILE|grep -v "lib/secure/tmp/"|grep -v "/lib/estates/"|grep -v "lib/secure/save"| grep -v "lib/save/"|grep -v "/mudos.cfg" |grep -v "/groups.cfg" |grep -v "\.bak"|grep -v "\.swp"> diff2.txt +cat diff.sh.1 | grep -v CMD_EVAL_TMP_FILE|grep -v "lib/secure/tmp/"|grep -v "/lib/estates/"|grep -v "lib/secure/save"| grep -v "lib/save/"|grep -v "/mudos.cfg" |grep -v "/groups.cfg" |grep -v "\.bak"|grep -v "\.swp"> diff.sh + +chmod 755 diff.sh +chmod 755 diff.sh.1 + +#vim diff.txt +#echo "#!/usr/bin/bash" > copyfiles3 +echo "#!/bin/bash" > copyfiles3 +chmod 755 copyfiles3 +cat diff2.txt > copyfiles +cat diff2.txt > copyfiles2 +perl -pi -e s/"\ "/"\^\^"/g copyfiles2 +#/contrib/parse_test +for i in `cat copyfiles2` +do +export LINE=`(echo $i | perl -pi -e s/"\^\^"/"\ "/g)` +#echo $LINE +echo `/contrib/column_parse $LINE` +done + +echo "mkdir next/lib/secure/log/intermud" >> copyfiles3 +echo "rm -f /run/shm/foo/next/lib/upgrades.txt" >> copyfiles3 +echo "cp -f next/lib/log/open/foo.txt next/lib/secure/log/intermud/" >> copyfiles3 +echo "cp -f new/lib/save/books.o next/lib/save/" >> copyfiles3 +echo "cp -f new/lib/save/soul.o next/lib/save/" >> copyfiles3 +echo "cp -f new/lib/save/rooms.o next/lib/save/" >> copyfiles3 +echo "cp -f new/lib/save/races.o next/lib/save/" >> copyfiles3 +echo "cp -f new/lib/save/map.o next/lib/save/" >> copyfiles3 +echo "cp -f new/lib/save/economy.o next/lib/save/" >> copyfiles3 +echo "cp -f new/lib/save/classes.o next/lib/save/" >> copyfiles3 +echo "cp -f new/lib/secure/save/inet.o next/lib/secure/save/" >> copyfiles3 +echo "cp -f new/lib/secure/save/functions.o next/lib/secure/save/" >> copyfiles3 +echo "cp -f new/lib/secure/save/files.o next/lib/secure/save/" >> copyfiles3 +echo "cp -f /contrib/newver next/extra/crat/" >> copyfiles3 +echo "cp -f /contrib/newpatch next/extra/crat/" >> copyfiles3 +echo "cp -f /contrib/livepatch next/extra/crat/" >> copyfiles3 +echo "cp -f /contrib/indentall next/extra/crat/" >> copyfiles3 + +#BLAH BLAH COPY COPY + +#cd /run/shm/foo +#mv next $NEWLIB +#chown -R 513:513 $NEWLIB +#chmod -R g+rwx $NEWLIB +#zip -q9r $NEWLIB.zip $NEWLIB +#\cp -f $NEWLIB.zip /mnt/data/mud/deadsouls/ +#\cp -f $NEWLIB.zip /mnt/media/open/ +#\cp -f $NEWLIB.zip /export/home/$HOME/mud/ + +bash ./diff.sh.1 > /run/shm/foo/diff.out + diff --git a/extra/crat/rr b/extra/crat/rr new file mode 100644 index 0000000..39c650b --- /dev/null +++ b/extra/crat/rr @@ -0,0 +1,34 @@ +#!/bin/bash +cd i3router +rm * +wget http://$1/router/blacklist.cfg +wget http://$1/router/broadcast_chanlist.h +wget http://$1/router/broadcast_mudlist.h +wget http://$1/router/clean_fd.h +wget http://$1/router/core_stuff.h +wget http://$1/router/debug.h +wget http://$1/router/funcs.h +wget http://$1/router/hosted_channels.h +wget http://$1/router/irn.h +wget http://$1/router/process_channel.h +wget http://$1/router/process_startup_req.h +wget http://$1/router/read_callback.h +wget http://$1/router/readme.txt +wget http://$1/router/remove_mud.h +wget http://$1/router/rsocket.c +wget http://$1/router/send_chanlist_reply.h +wget http://$1/router/send_error.h +wget http://$1/router/send_full_mudlist.h +wget http://$1/router/send_mudlist_updates.h +wget http://$1/router/send_startup_reply.h +wget http://$1/router/server.c +wget http://$1/router/server_log.h +cd .. +mkdir imc2server +cd imc2server +rm * +wget http://$1/server/server.c +wget http://$1/server/server_log.h +wget http://$1/server/ssocket.c + + diff --git a/extra/creremote/README.creremote b/extra/creremote/README.creremote new file mode 100644 index 0000000..21828ae --- /dev/null +++ b/extra/creremote/README.creremote @@ -0,0 +1,81 @@ +This is part of the Foundation II lib and NOT part of +Dead Souls AT ALL. It's provided as a convenience, but +if it doesn't work, or screws your lib, or you get pwnt +because of it, it's not my fault, and not my problem. + +Creremote allows you to edit stuff remotely. + +Basically, a creremote session looks like this: + +$ ./creremote +CreRemote> connect foo +Character name: cratylus +Password: +foo ip: 192.168.0.70 +port: 6656 +Connection to Dead Souls. +ls +fee> Directory: /realms/cratylus/ +.plan .profile +adm/ area/ bak/ +cmds/ customdefs.h log/ +tmp/ workroom.bak workroom.c + +quit +CreRemote> exit +$ + +The really cool thing is that you can cd to your +homedir, and from there type, for example: + +edit workroom.c + +And you'll be editing workroom.c in your local editor, so +you can use vi, or whatever. When you finish, the file +is magically sent to the mud...no need for ftp. + +Another cool thing is that it works through routers and +firewalls, so assuming you've set up your router's +port-forwarding correctly, you can use this where ftp +was not available. + +Summary: + + PROS +* Can cross firewalls (if you do your port forwarding right) + * Uses authentication based on your mud privs. + * Lets you edit files with your favorite UNIX editor (yay!). + + CONS + * Probably insecure as hell. + * The windows version is unavailable. Only creremote for UNIX works. + * It probably is buggy. Feel free to submit fixes, but don't expect me to fix it myself. + + Instructions: + 1) If you're using Solaris, edit creremote and make this line: + $SOCK_STREAM = 1; + Look like this: + $SOCK_STREAM = 2; + 2) Copy creremote to your /usr/local/bin/ or wherever you put such stuff. + 3) Copy remote.c to $MUDHOME/lib/lib/remote.c + 4) You may need to enable it with the mudconfig command, just log into + the mud and type: help mudconfig . As of Alpha 17, updating /secure/daemon/inet + is enough to activate RCP support. Type: netstat to know if the RCP port is open. + 5) You may need to edit this line: + $Editor = '/usr/bin/vi'; + To reflect your favorite editor, such as: + $Editor = '/usr/local/bin/gvim'; + 6) Type: ./creremote or /usr/local/bin/creremote, or whatever. + 7) Type: connect foo, where "foo" is what you'll call this connection, not the mud. + 8) Enter your mud character name. + 9) Enter your mud character password. + 10) Enter the ip address of the mud. + 11) Enter the RCP PORT of the mud (NOT the telnet port). This is usually 10 less + than the telnet port, so if your mud is running on port 6666, the RCP port will be 6656 + 12) You should connect, unless you messed up or you have network problems. Play + around, enjoy. If it doesn't work, figure it out and tell me what fixed it. + 13) To disconnect, type: quit + 14) To close creremote, type: exit + + -Cratylus + 28Nov06 diff --git a/extra/creremote/creremote b/extra/creremote/creremote new file mode 100644 index 0000000..a1e82a0 --- /dev/null +++ b/extra/creremote/creremote @@ -0,0 +1,254 @@ +#!/usr/bin/perl + +$MUD = ""; +$Character = ""; +$Password = ""; +$Machine = ""; +$Port = 0; +$Editor = '/usr/bin/vi'; +$LocalEditFile = "/tmp/creremote.$$"; +print "CreRemote> "; + +while(<>) { + chop; + if( $_ ) { + @tmp = split(/ /, $_); + $cmd = shift(@tmp); + $args = join(' ', @tmp); + if( ! $MUD ) { + if( $cmd eq "connect" ) { + &cmdConnect($args); + } + elsif( $cmd eq "help" ) { + &cmdHelp($args); + } + elsif( $cmd eq "exit" ) { + exit; + } + elsif( substr($cmd, 0, 1) eq "!" ) { + system(substr($cmd, 1, length($cmd) - 1)); + } + else { + print "Bad command: $cmd $args\n"; + } + } + else { + if( $cmd eq "connect" ) { + print "You are already connected to $MUD.\n"; + } + elsif( $cmd eq "quit" ) { + close(S); + $MUD = ""; + $Buffer = ""; + $InEdit = 0; + $EditFile = ""; + } + elsif( $cmd eq "edit" ) { + $EditFile = $args; + system("rm $LocalEditFile") if -f $LocalEditFile; + print S "$cmd $args\n"; + $x = 1; + while( $x ) { if( -f $LocalEditFile ) { $x = 0; } } + @bugger = stat($LocalEditFile); + $sz = $bugger[7]; + $tme = $bugger[9]; + system("$Editor $LocalEditFile"); + @bugger = stat($LocalEditFile); + if( $bugger[7] == 0 || $tme == $bugger[9] ) { + $EditFile = ""; + system("rm $LocalEditFile"); + } + else { + $Buffer = ""; + open(LEF, $LocalEditFile); + while() { $Buffer = "$Buffer$_"; } + close(LEF); + print S "100 ".length($Buffer)." $EditFile\n"; + $EditFile = ""; + sleep(2); + print S $Buffer; + $Buffer = ""; + system("rm $LocalEditFile"); + } + } + elsif( $cmd eq "100" ) { + print "Illegal command.\n"; + } + elsif( substr($cmd, 0, 1) eq "!" ) { + system(substr($cmd, 1, length($cmd) - 1)); + } + else { + print S "$cmd $args\n"; + } + } + } + print "CreRemote> " unless $MUD; +} + + +sub cmdConnect { + local($mud) = shift(@_); + local($rcfile) = $ENV{'HOME'} || './'; + $rcfile = $rcfile."/.creremoterc"; + local($found) = 0; + local($writerc) = 0; + if( -f $rcfile ) { + open(RCFILE, $rcfile); + while() { + chop; + local(@words) = split; + local($thismud) = shift(@words); + if( ! $charname && $thismud eq $mud ) { + $Character = shift(@words); + $Password = shift(@words); + $Machine= shift(@words); + $Port = shift(@words); + $found = 1; + } + } + close(RCFILE); + } + if( ! $found ) { + print "Character name: "; + chop($Character = <>); + print "Password: "; + system 'stty', '-echo'; + chop($Password = <>); + system 'stty', 'echo'; + print "\n$mud ip: "; + chop($Machine = <>); + print "port: "; + chop($Port = <>); + $writerc = 1; + } + $MUD = $mud; + if( ! $Character || !$MUD || ! $Password || ! $Machine || ! $Port ) { + print "Vital information is missing\n"; + return; + } + + $AF_INET = 2; + $SOCK_STREAM = 1; + $SIG{'INT'} = 'killconnection'; + + $port = $Port; + $sockaddr = 'S n a4 x8'; + chop($hostname = `hostname`); + ($name, $aliases, $proto) = getprotobyname('tcp'); + ($name, $aliases, $port) = getservbyname($port, 'tcp') + unless $port =~ /^\d+$/; + ($name, $aliases, $type, $len, $thisaddr) = + gethostbyname($hostname); + ($name, $aliases, $type, $len, $thataddr) = gethostbyname($Machine); + + $this = pack($sockaddr, $AF_INET, 0, $thisaddr); + $that = pack($sockaddr, $AF_INET, $port, $thataddr); + + if( !socket(S, $AF_INET, $SOCK_STREAM, $proto) ) { + print "Error creating socket for $MUD: $!\n"; + $MUD = ""; + $Character = ""; + $Password = ""; + $Machine = ""; + $Port = ""; + return; + } + if( !bind(S, $this) ) { + print "Error binding to $MUD: $!\n"; + $MUD = ""; + $Character = ""; + $Password = ""; + $Machine = ""; + $Port = ""; + return; + } + if( !connect(S, $that) ) { + print "Error connecting to $MUD: $!\n"; + $MUD = ""; + $Character = ""; + $Password = ""; + $Machine = ""; + $Port = ""; + return; + } + if( $writerc ) { + open(NRCFILE, ">> $rcfile"); + print NRCFILE "$MUD $Character $Password $Machine $Port\n"; + close(NRCFILE); + } + + select(S); $| = 1; select(STDOUT); + + if( $child = fork ) { + print S "login $Character $Password\n"; + return; + } + else { + while() { + if( $InEdit > 0 ) { + $Buffer = "$Buffer$_"; + if( length($Buffer) == $InEdit ) { + $InEdit = 0; + open(LEF, ">$LocalEditFile"); + print LEF $Buffer; + close(LEF); + while( -f $LocalEditFile ) { } + $Buffer = ""; + $InEdit = 0; + print "$MUD> "; + } + } + else { + chop; + local(@borg) = split; + $remcmd = shift(@borg); + if ( $remcmd == 100 ) { + $InEdit = shift(@borg); + if( ! $InEdit ) { + system("touch $LocalEditFile"); + while( -f $LocalEditFile ) { } + $Buffer = ""; + $InEdit = 0; + print "$MUD> "; + } + } + elsif( $remcmd == 500 ) { + $format = "Directory: %s\n"; + $tmpx = @borg - 1; + if( $tmpx ) { + while($tmpx--) { + if( $tmpx % 3 == 0 ) { $format = "$format%20s\n"; } + else { $format = "$format%20s"; } + } + } + printf($format, @borg); + print "\n$MUD> "; + } + else { + local($out) = join(' ', @borg); + print "$out\n$MUD> "; + } + } + } + exit; + } +} + +sub cmdHelp { + print "CreRemote is a way to work on a MUD without physically\n"; + print "being on that MUD. When you first issue the CreRemote\n"; + print "command, you are given the CreRemote prompt. At that time\n"; + print "you are not connected to any MUD. You can issue the\n"; + print "following commands from the CreRemote prompt:\n"; + print "\tconnect \n"; + print "\texit\n\n"; + print "Once connect to a MUD, the commands available to you may\n"; + print "vary from MUD to MUD, generally you will have commands like:\n"; + print "cd, ls, update, mkdir, rmdir, rm, mv, cp, etc.\n"; + print "No matter whcih MUD, you will have the command \"edit\"\n"; + print "which allows you to edit your files with your favourite UNIX\n"; + print "editor. The default is vi, however, it will use the value\n"; + print "of your EDITOR environment variable.\n"; + print "When connecting to a MUD, remember to specify its RCP port,\n"; + print "NOT its MUD port. This is generally MUD port - 10.\n"; +} diff --git a/extra/creremote/remote.c b/extra/creremote/remote.c new file mode 100644 index 0000000..6af5b19 --- /dev/null +++ b/extra/creremote/remote.c @@ -0,0 +1,101 @@ +/* /lib/remote.c + * from the Foundation II LPC Library + * handles security for cre access via the remote creator protocol + * created by Descartes of Borg 950505 + */ + +#include + +inherit LIB_DAEMON; + +private static string Directory, Home; + +static void create() { + daemon::create(); + SetNoClean(1); + Directory = Home = "/" + + implode(explode(file_name(this_object()), "/")[0..<3], "/"); + if( strsrch(Directory, REALMS_DIRS) ) call_out( (: Destruct :), 0 ); +} + +string eventWriteFile(string file, string str) { + file = absolute_path(Directory, file); + if( base_name(this_object()) == LIB_REMOTE ) + return "50 Failed to write file: " + file; + if( file_size(file) > -1 && !rm(file) ) + return "50 Failed to write file: " + file; + if( !write_file(file, str) ) return "50 Failed to write file: " + file; + else return "110 File " + file + " written."; +} + +string eventReadFile(string file) { + string tmp; + + if( base_name(this_object()) == LIB_REMOTE ) return ""; + file = absolute_path(Directory, file); + if( !(tmp = read_file(file)) ) return ""; + else return tmp; +} + +string eventCommand(string cmd, string arg) { + string *files; + object ob; + string tmp; + + if( base_name(this_object()) == LIB_REMOTE ) return 0; + switch(cmd) { + case "ls": + if( !arg || arg == "" ) arg = Directory; + switch(file_size(arg)) { + case -2: + if( arg[<1] != '/' ) arg += "/"; + files = ({ arg }); + files += map(get_dir(arg), + (: (file_size($(arg) + $1) == -2) ? $1 + "/" : $1 :)); + return implode(files, "\t"); + case -1: + return 0; + default: + return arg; + } + case "mkdir": + arg = absolute_path(Directory, arg); + if( file_size(arg) != -1 ) return 0; + if( !mkdir(arg) ) return 0; + else return "Directory created."; + case "cd": + arg = absolute_path(Directory, arg); + if( !arg || arg == "" ) Directory = Home; + else if( !((int)master()->valid_read(arg, this_object(), "cd")) ) + return 0; + else Directory = arg; + return Directory; + case "rm": + arg = absolute_path(Directory, arg); + if( !rm(arg) ) return 0; + else return arg + " deleted."; + case "rmdir": + arg = absolute_path(Directory, arg); + if( !rmdir(arg) ) return 0; + else return arg + " deleted."; + case "mv": + files = explode(arg, " "); + if( sizeof(files) != 2 ) return 0; + files[0] = absolute_path(Directory, files[0]); + files[1] = absolute_path(Directory, files[1]); + if( !rename(files[0], files[1]) ) return 0; + else return files[0] + " renamed to " + files[1] + "."; + case "update": + arg = absolute_path(Directory, arg); + if( arg[<2..] == ".c" ) arg = arg[0..<3]; + if( ob = find_object(arg) ) { + if( !((int)ob->eventDestruct()) ) + return "Failed to destruct original object."; + } + tmp = catch(call_other(arg, "???")); + if( tmp ) + return "Error in loading object: " + replace_string(tmp, "\n", "\t"); + else return arg + ": successfully loaded."; + } + return 0; +} diff --git a/extra/mingw/configuration b/extra/mingw/configuration new file mode 100644 index 0000000..3cb821a --- /dev/null +++ b/extra/mingw/configuration @@ -0,0 +1 @@ +Machine MINGW32_NT-5.1 REMORA 1.0.10(0.46/3/2) 2004-03-15 07:17 i686 unknown Configure version 5 diff --git a/extra/mingw/configure.h b/extra/mingw/configure.h new file mode 100644 index 0000000..0f7e271 --- /dev/null +++ b/extra/mingw/configure.h @@ -0,0 +1,24 @@ +#define INCL_STDLIB_H +#define INCL_TIME_H +#define INCL_FCNTL_H +#define INCL_DOS_H +#define INCL_SYS_STAT_H +#define INCL_LIMITS_H +#define USE_STRUCT_DIRENT +#define INCL_STDARG_H +#define HAS_MEMMOVE +#define RAND +#define HAS_STRERROR +#define HAS_GETCWD + +#define SIZEOF_INT 4 +#define SIZEOF_PTR 4 +#define SIZEOF_SHORT 2 +#define SIZEOF_FLOAT 4 +#define SIZEOF_INT 4 +#define SIZEOF_PTR 4 +#define SIZEOF_SHORT 2 +#define SIZEOF_FLOAT 4 +#define UINT32 unsigned long +#define CONFIGURE_VERSION 5 + diff --git a/extra/restore_cfg b/extra/restore_cfg new file mode 100644 index 0000000..4919b8e --- /dev/null +++ b/extra/restore_cfg @@ -0,0 +1,150 @@ +############################################################################### +# Customizable runtime config file for MudOS # +# NOTE: All paths specified here are relative to the mudlib directory except # +# for mudlib directory, and binary directory. # +# Lines beginning with a # or a newline are ignored. # +############################################################################### +# name of this mud +name : DeadSoulsNew + +# port number to accept users on +external_port_1 : telnet 6666 + +# absolute pathname of mudlib +mudlib directory : /CHANGE/THIS/PATH/lib + +# absolute pathname of driver/config dir +binary directory : /CHANGE/THIS/PATH/bin + +# the address server is an external program that lets the mud translate +# internet names to numbers (and vice versa). select an unused port. +address server ip : localhost +address server port : 8099 + +# fd6 stuff is what allows portbind to work properly. If +# you want to have the mud accept connections on port 23 but run +# as non-root, you uncomment the two fd6 lines below and issue the +# appropriate portbind command to start the mud. +#fd6 port : 23 +#fd6 kind : telnet + +# debug.log and author/domain stats are stored here +log directory : /log + +# the directories which are searched by #include <...> +# for multiple dirs, separate each path with a ':' +include directories : /secure/include:/include + +# Directory to save binaries in. (if BINARIES is defined) +save binaries directory : /secure/save/binaries + +# the file which defines the master object +master file : /secure/daemon/master + +# the file where all global simulated efuns are defined. +simulated efun file : /secure/sefun/sefun + +# file to swap out objects; not used if time to swap is 0 +swap file : /secure/tmp/swap + +# alternate debug.log file name (assumed to be in specified 'log directory') +debug log file : runtime + +# This is an include file which is automatically #include'd in all objects +global include file : + +# if an object is left alone for a certain time, then the +# function clean_up will be called. This function can do anything, +# like destructing the object. If the function isn't defined by the +# object, then nothing will happen. +# This time should be substantially longer than the swapping time. +time to clean up : 2100000000 + +# How long time until an unused object is swapped out. +# Machine with too many players and too little memory: 900 (15 minutes) +# Machine with few players and lot of memory: 10000 +# Machine with infinite memory: 0 (never swap). +time to swap : 0 + +# How many seconds until an object is reset again. +time to reset : 2100000000 + +# Maximum number of bits in a bit field. They are stored in printable +# strings, 6 bits per byte. +maximum bits in a bitfield : 1200 + +# Max number of local variables in a function. +maximum local variables : 35 + +# Maximum amount of "eval cost" per thread - execution is halted when +# it is exceeded. +maximum evaluation cost : 5000000 + +# This is the maximum array size allowed for one single array. +maximum array size : 64000 + +# This is the maximum allowed size of a variable of type 'buffer'. +maximum buffer size : 400000 + +# Max size for a mapping +maximum mapping size : 64000 + +# Max inherit chain size +inherit chain size : 30 + +# maximum length of a string variable +maximum string length : 200000 + +# Max size of a file allowed to be read by 'read_file()'. +maximum read file size : 200000 + +# max number of bytes you allow to be read and written with read_bytes +# and write_bytes +maximum byte transfer : 10000 + +# Reserve an extra memory area from malloc(), to free when we run out +# of memory and allow the mudlib to shutdown. +# If this value is 0, no area will be reserved. +reserved size : 0 + +# Define the size of the shared string hash table. This number should +# a prime, probably between 1000 and 30000; if you set it to about 1/5 +# of the number of distinct strings you have, you will get a hit ratio +# (number of comparisons to find a string) very close to 1, as found strings +# are automatically moved to the head of a hash chain. You will never +# need more, and you will still get good results with a smaller table. +hash table size : 7001 + +# Object hash table size. +# Define this like you did with the strings; probably set to about 1/4 of +# the number of objects in a game, as the distribution of accesses to +# objects is somewhat more uniform than that of strings. +object table size : 1501 + +# default no-matching-action message +default fail message : What? + +# default message when error() occurs (optional) +default error message : Something *REALLY* bad just happened. + +############################################################################### +# The following aren't currently used or implemented (yet) # +############################################################################### + +# maximum number of users in the game (unused currently) +maximum users : 40 + +# Define the maximum stack size of the stack machine. This stack will also +# contain all local variables and arguments. (unused currently) +evaluator stack size : 1000 + +# Define the size of the compiler stack. This defines how complex +# expressions the compiler can parse. (unused currently) +compiler stack size : 200 + +# Define the maximum call depth for functions. (unused currently) +maximum call depth : 30 + +# There is a hash table for living objects, used by find_living(). +# (unused currently) +living hash table size : 100 diff --git a/extra/wolfpaw/configure.h b/extra/wolfpaw/configure.h new file mode 100644 index 0000000..bdd3141 --- /dev/null +++ b/extra/wolfpaw/configure.h @@ -0,0 +1,51 @@ +#define INCL_STDLIB_H +#define INCL_UNISTD_H +#define INCL_TIME_H +#define USE_TZSET +#define INCL_SYS_TIMES_H +#define INCL_FCNTL_H +#define INCL_SYS_TIME_H +#define INCL_LIMITS_H +#define INCL_LOCALE_H +#define INCL_NETINET_IN_H +#define INCL_ARPA_INET_H +#define INCL_SYS_TYPES_H +#define INCL_SYS_IOCTL_H +#define INCL_SYS_SOCKET_H +#define INCL_NETDB_H +#define INCL_ARPA_TELNET_H +#define INCL_SYS_SOCKETVAR_H +#define INCL_SYS_STAT_H +#define INCL_DIRENT_H +#define USE_STRUCT_DIRENT +#define INCL_SYS_RESOURCE_H +#define INCL_SYS_WAIT_H +#define INCL_CRYPT_H +#define INCL_SYS_SYSMACROS_H +#define INCL_STDARG_H +#define INCL_DLFCN_H +#define DRAND48 +#define USE_BSD_SIGNALS +#define SIGNAL_ERROR SIG_ERR +#define INLINE inline +#define CONST const +#define HAS_UALARM +#define HAS_STRERROR +#define HAS_GETCWD +#define RUSAGE +#define TIMES +#define HAS_GETTIMEOFDAY +#define HAS_FCHMOD +#define SIZEOF_INT 4 +#define SIZEOF_PTR 4 +#define SIZEOF_SHORT 2 +#define SIZEOF_LONG 4 +#define SIZEOF_FLOAT 4 +#define UINT32 unsigned long +#define CONFIGURE_VERSION 5 + +#define MAXSHORT ((1 << (sizeof(short)*8)) - 1) +#define USHRT_MAX (MAXSHORT) +#define USE_STRUCT_DIRENT +#define RTLD_LAZY 1 +#define INADDR_NONE (unsigned int)0xffffffff diff --git a/extra/wolfpaw/macros.h b/extra/wolfpaw/macros.h new file mode 100644 index 0000000..6536a80 --- /dev/null +++ b/extra/wolfpaw/macros.h @@ -0,0 +1,270 @@ +#ifndef MACROS_H +#define MACROS_H + +#ifdef __STDC__ +#define ANSI_STRING_HACK(x) #x +#define DONT_ASK_WHY(x) (x) +#define WHERE (__FILE__ ":" DONT_ASK_WHY(x)) +#else +#define WHERE "non-ansi compilers are a pain" +#endif + +/* + * Some useful macros... + */ +#ifdef BUFSIZ +# define PROT_STDIO(x) (x () +#endif /* BUFSIZ */ + +/* ANSI/K&R compatibility stuff; + * + * The correct way to prototype a function now is: + * + * foobar (int, char *); + * + * foobar (int x, char * y) { ... } + */ +/* xlc can't handle an ANSI protoype followed by a K&R def, and varargs + * functions must be done K&R (b/c va_dcl is K&R style) so don't prototype + * vararg function arguments under AIX + */ +#if defined(__STDC__) || defined(WIN32) +# define VOLATILE volatile +# define SIGNED signed +#else /* __STDC__ */ +# define VOLATILE +# define SIGNED +#endif /* __STDC__ */ + +/* do things both ways ... */ +#define V_START(vlist, last_arg) va_start(vlist, last_arg) +#define V_VAR(type, var, vlist) +#define SAFE(x) do { x } while (0) + + +/* + Define for MALLOC, FREE, REALLOC, and CALLOC depend upon what malloc + package and optional wrapper is used. This technique is used because + overlaying system malloc with another function also named malloc doesn't + work on most mahines that have shared libraries. It will also let + us keep malloc stats even when system malloc is used. + + Please refer to options.h for selecting malloc package and wrapper. +*/ +#if (defined(SYSMALLOC) + defined(SMALLOC) + defined(BSDMALLOC) + defined(MMALLOC)) > 1 +!Only one malloc package should be defined +#endif + +#if (defined(WRAPPEDMALLOC) + defined(DEBUGMALLOC)) > 1 +!Only one wrapper (at most) should be defined +#endif + +#if defined(DO_MSTATS) && defined(SYSMALLOC) +!'DO_MSTATS' not available with 'SYSMALLOC' +#endif + +#if defined (WRAPPEDMALLOC) && !defined(IN_MALLOC_WRAPPER) + +# define MALLOC(x) wrappedmalloc(x) +# define FREE(x) wrappedfree(x) +# define REALLOC(x, y) wrappedrealloc(x, y) +# define CALLOC(x, y) wrappedcalloc(x, y) +# define DXALLOC(x, t, d) xalloc(x) +# define DMALLOC(x, t, d) MALLOC(x) +# define DREALLOC(x, y, t, d) REALLOC(x,y) +# define DCALLOC(x, y, t, d) CALLOC(x,y) + +#else + +# if defined(DEBUGMALLOC) && !defined(IN_MALLOC_WRAPPER) + +# define MALLOC(x) debugmalloc(x, 0, (char *)0) +# define DMALLOC(x, t, d) debugmalloc(x, t, d) +# define DXALLOC(x, t, d) debugmalloc(x, t, d) +# define FREE(x) debugfree(x) +# define REALLOC(x,y) debugrealloc(x,y,0,(char *)0) +# define DREALLOC(x,y,tag,desc) debugrealloc(x,y,tag,desc) +# define CALLOC(x,y) debugcalloc(x,y,0,(char *)0) +# define DCALLOC(x,y,tag,desc) debugcalloc(x,y,tag,desc) + +# else + +# include "my_malloc.h" + +# endif +#endif + +#if !defined(MALLOC) && !defined(EDIT_SOURCE) +!You need to specify a malloc package in local_options/options.h +#endif + +#define ALLOCATE(type, tag, desc) ((type *)DXALLOC(sizeof(type), tag, desc)) +#define CALLOCATE(num, type, tag, desc) ((type *)DXALLOC(sizeof(type[1]) * (num), tag, desc)) +#define RESIZE(ptr, num, type, tag, desc) ((type *)DREALLOC((void *)ptr, sizeof(type) * (num), tag, desc)) + +#ifdef DEBUG +# define IF_DEBUG(x) x +# define DEBUG_CHECK(x, y) if (x) fatal(y) +# define DEBUG_CHECK1(x, y, a) if (x) fatal(y, a) +# define DEBUG_CHECK2(x, y, a, b) if (x) fatal(y, a, b) +#else +# define IF_DEBUG(x) +# define DEBUG_CHECK(x, y) +# define DEBUG_CHECK1(x, y, a) +# define DEBUG_CHECK2(x, y, a, b) +#endif + +#if !defined(EDIT_SOURCE) && !defined(_FUNC_SPEC_) +#define COPY2(x, y) ((char *)(x))[0] = ((char *)(y))[0]; \ + ((char *)(x))[1] = ((char *)(y))[1] +#define LOAD2(x, y) ((char *)&(x))[0] = *y++; \ + ((char *)&(x))[1] = *y++ +#define STORE2(x, y) *x++ = ((char *)(&(y)))[0]; \ + *x++ = ((char *)(&(y)))[1] + +#define COPY4(x, y) ((char *)(x))[0] = ((char *)(y))[0]; \ + ((char *)(x))[1] = ((char *)(y))[1]; \ + ((char *)(x))[2] = ((char *)(y))[2]; \ + ((char *)(x))[3] = ((char *)(y))[3] +#define LOAD4(x, y) ((char *)&(x))[0] = *y++; \ + ((char *)&(x))[1] = *y++; \ + ((char *)&(x))[2] = *y++; \ + ((char *)&(x))[3] = *y++ +#define STORE4(x, y) *x++ = ((char *)(&(y)))[0]; \ + *x++ = ((char *)(&(y)))[1]; \ + *x++ = ((char *)(&(y)))[2]; \ + *x++ = ((char *)(&(y)))[3] + +#define COPY8(x, y) ((char *)(x))[0] = ((char *)(y))[0]; \ + ((char *)(x))[1] = ((char *)(y))[1]; \ + ((char *)(x))[2] = ((char *)(y))[2]; \ + ((char *)(x))[3] = ((char *)(y))[3]; \ + ((char *)(x))[4] = ((char *)(y))[4]; \ + ((char *)(x))[5] = ((char *)(y))[5]; \ + ((char *)(x))[6] = ((char *)(y))[6]; \ + ((char *)(x))[7] = ((char *)(y))[7] +#define LOAD8(x, y) ((char *)&(x))[0] = *y++; \ + ((char *)&(x))[1] = *y++; \ + ((char *)&(x))[2] = *y++; \ + ((char *)&(x))[3] = *y++; \ + ((char *)&(x))[4] = *y++; \ + ((char *)&(x))[5] = *y++; \ + ((char *)&(x))[6] = *y++; \ + ((char *)&(x))[7] = *y++; +#define STORE8(x, y) *x++ = ((char *)(&(y)))[0]; \ + *x++ = ((char *)(&(y)))[1]; \ + *x++ = ((char *)(&(y)))[2]; \ + *x++ = ((char *)(&(y)))[3]; \ + *x++ = ((char *)(&(y)))[4]; \ + *x++ = ((char *)(&(y)))[5]; \ + *x++ = ((char *)(&(y)))[6]; \ + *x++ = ((char *)(&(y)))[7] + +#if SIZEOF_SHORT == 2 +#define COPY_SHORT(x, y) COPY2(x,y) +#define LOAD_SHORT(x, y) LOAD2(x,y) +#define STORE_SHORT(x, y) STORE2(x,y) +#else +#endif + +#if SIZEOF_INT == 4 +#define INT_32 int +#endif + +#if SIZEOF_LONG == 4 +#define COPY_INT(x, y) COPY4(x,y) +#define LOAD_INT(x, y) LOAD4(x,y) +#define STORE_INT(x, y) STORE4(x,y) +#else +#if SIZEOF_LONG == 8 +#define COPY_INT(x, y) COPY8(x,y) +#define LOAD_INT(x, y) LOAD8(x,y) +#define STORE_INT(x, y) STORE8(x,y) +#else +#endif +#endif + +#if SIZEOF_FLOAT == 4 +#define COPY_FLOAT(x, y) COPY4(x,y) +#define LOAD_FLOAT(x, y) LOAD4(x,y) +#define STORE_FLOAT(x, y) STORE4(x,y) +#else +#endif + +#if SIZEOF_PTR == 4 +# define COPY_PTR(x, y) COPY4(x,y) +# define LOAD_PTR(x, y) LOAD4(x,y) +# define STORE_PTR(x, y) STORE4(x,y) + +# define POINTER_INT int +# define INS_POINTER ins_int +#else +# if SIZEOF_PTR == 8 +# define COPY_PTR(x, y) COPY8(x,y) +# define LOAD_PTR(x, y) LOAD8(x,y) +# define STORE_PTR(x, y) STORE8(x,y) + +# define POINTER_INT long +# define INS_POINTER ins_long +# else +# endif +#endif +#endif + +#ifndef _FUNC_SPEC_ + char *xalloc (int); +# ifdef DEBUGMALLOC + char *int_string_copy (const char * const, char *); + char *int_string_unlink (const char *, char *); + char *int_new_string (int, char *); + char *int_alloc_cstring (const char *, char *); +# else + char *int_string_copy (const char * const); + char *int_string_unlink (const char *); + char *int_new_string (int); + char *int_alloc_cstring (const char *); +# endif +#endif + +#ifdef DEBUGMALLOC +# define string_copy(x,y) int_string_copy(x, y) +# define string_unlink(x,y) int_string_unlink(x, y) +# define new_string(x,y) int_new_string(x, y) +# define alloc_cstring(x,y) int_alloc_cstring(x, y) +#else +# define string_copy(x,y) int_string_copy(x) +# define string_unlink(x,y) int_string_unlink(x) +# define new_string(x,y) int_new_string(x) +# define alloc_cstring(x,y) int_alloc_cstring(x) +#endif + +#ifndef INLINE +# ifdef WIN32 +# define INLINE extern __inline +# define INLINE_STATIC __inline +# else +# define INLINE +# endif +#endif + +#ifndef INLINE_STATIC +# define INLINE_STATIC static INLINE +#endif + +/* The ANSI versions must take an unsigned char, and must work on EOF. These + * versions take a (possibly signed) char, and do not work correctly on EOF. + * + * Note that calling isdigit(x) where x is a signed char with x < 0 (i.e. + * high bit set) invokes undefined behavior. + */ +#define uisdigit(x) isdigit((unsigned char)x) +#define uislower(x) islower((unsigned char)x) +#define uisspace(x) isspace((unsigned char)x) +#define uisalnum(x) isalnum((unsigned char)x) +#define uisupper(x) isupper((unsigned char)x) +#define uisalpha(x) isalpha((unsigned char)x) +#define uisxdigit(x) isxdigit((unsigned char)x) +#define uisascii(x) isascii((unsigned char)x) +#define uisprint(x) isprint((unsigned char)x) + +#endif diff --git a/extra/wolfpaw/system_libs b/extra/wolfpaw/system_libs new file mode 100644 index 0000000..1ad1158 --- /dev/null +++ b/extra/wolfpaw/system_libs @@ -0,0 +1 @@ + -lresolv -lcrypt -lnsl -lm -lz diff --git a/fluffos-2.23-ds03/32bitmalloc.c b/fluffos-2.23-ds03/32bitmalloc.c new file mode 100644 index 0000000..99b363b --- /dev/null +++ b/fluffos-2.23-ds03/32bitmalloc.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include + +void *malloc32(int size){ + register unsigned long *res = (unsigned long *)malloc(size+sizeof(long)); + if(!res){ + perror("malloc: "); + exit(-1); + } + *res=size; + return &res[1]; +} + +void free32(void *p){ + register unsigned long *mem = (unsigned long *)p; + mem--; + free(mem); +} + +void *realloc32(void *p, int size){ + register unsigned long *mem = (unsigned long *)p; + unsigned int oldsize; + oldsize = mem[-1]; + void *newmem = malloc32(size); + oldsize = oldsize +#include +#include +#include +#include + +struct freeblocks{ + unsigned long *block; + struct freeblocks *next; +} *freelist = NULL; + +static char *where = NULL; +static long blocksize = 0; + +void *malloc64(int size){ + if(!blocksize){ + char *tmp = (char *)sbrk(0); //end of heap + char *tmp2 = (char *)&size; //end of stack + char *tmp3 = (char *)0x4000000000; //libs, how do we get the actual address?? + //printf("%ul %ul %ul", tmp, tmp2, tmp3); + if(tmp3 < tmp2 && tmp < tmp3){ //oops libraries in the middle, find the biggest gap we're assuming libs are smaller than 4GB total + if((tmp3 - tmp) > (tmp2 - tmp3)){ + tmp2 = tmp3 - (long)4 * 1024 * 1024 * 1024; + } else { + tmp = tmp3 + (long)4 * 1024 * 1024 * 1024; + } + } + + + long total = tmp2 - tmp; //memory available + total -= (long)4 * 1024 * 1024 * 1024; //leave some for the libc malloc (4GB) + blocksize = total/10000000; //10 million allocations of over 4k should be enough for anyone (at least 40 Gb requested at that point, in reality probably at least 10 times more!) + blocksize -= blocksize % 4096; + where = tmp + (long)4 * 1024 * 1024 * 1024; + where -= (long)where % 4096; + //printf("start %xl: blocksize: %xl\n", (long)where, blocksize); + } + + if(size < 4088){ + register unsigned long *res = (unsigned long *)malloc(size+sizeof(long)); + if(!res){ + perror("malloc: "); + exit(-1); + } + *res=size; + return &res[1]; + } + + register unsigned long *res; + if(size < blocksize){ + if(!freelist){ + res = (unsigned long *)mmap(where, size+sizeof(long),MAP_FIXED|PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0); + if(res != where){ + perror("mmap failed! (55)"); + printf("where = %lx\n", where); + res = (unsigned long *)malloc(size+sizeof(long)); + if(!res){ + perror("malloc: "); + exit(-1); + } + *res=size; + return &res[1]; + } + where += blocksize; + }else{ + res = (unsigned long *)mmap(freelist->block, size+sizeof(long),MAP_FIXED|PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0); + if(res != freelist->block) + perror("mmap failed! (60)"); + + struct freeblocks *tmp = freelist; + freelist = freelist->next; + free(tmp); + } + } else { + //just in case something big comes along + int thissize = size / 4096; + thissize++; + res = (unsigned long *)mmap(where, size+sizeof(long),MAP_FIXED|PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0); + if(res != where) + perror("mmap failed! (72)"); + where += (thissize*4096); + } + if((long)res == -1){ + perror("malloc: "); + exit(-1); + } + *res=size; + return &res[1]; +} + +void free64(void *p){ + register unsigned long *mem = (unsigned long *)p; + mem--; + if(mem < (unsigned long *)sbrk(0) || mem > (unsigned long *)where) + free(mem); + else{ + munmap(mem, *mem+sizeof(long)); + struct freeblocks *bl = (struct freeblocks *)malloc(sizeof(struct freeblocks)); + bl->block = mem; + bl->next = freelist; + freelist = bl; + } +} + +void *realloc64(void *p, int size){ + register unsigned long *mem = (unsigned long *)p; + unsigned int oldsize; + mem--; + oldsize = *mem+sizeof(long); + if(mem < (unsigned long *)sbrk(0) || mem > (unsigned long *)where){ + if(size < 4088){ + mem = (unsigned long *)realloc(mem, size + sizeof(long)); + *mem = size; + return (void *)&mem[1]; + } else { + mem++; + unsigned long *newmem = (unsigned long *)malloc64(size); + memcpy(newmem, mem, oldsize-sizeof(long)); + mem--; + free(mem); + return (void *)newmem; + } + } + if(size < 4088){ + mem++; + unsigned long *newmem = (unsigned long *)malloc(size+sizeof(long)); + *newmem = size; + newmem++; + memcpy(newmem, mem, size); + free64(mem); + return (void *)newmem; + } + mem = (unsigned long *)mremap(mem, oldsize, size+sizeof(long), 1); + *mem = size; + return (void *)&mem[1]; +} + +void *calloc64(int num, int size){ + register void *p; + size *= num; + if ((p = malloc64(size))) + memset(p, 0, size); + return (p); +} diff --git a/fluffos-2.23-ds03/Artistic.README b/fluffos-2.23-ds03/Artistic.README new file mode 100644 index 0000000..4177e2e --- /dev/null +++ b/fluffos-2.23-ds03/Artistic.README @@ -0,0 +1,9 @@ +The file "Artistic" is included because a small part of the driver source +is derived from Larry Wall's Perl package (namely the hashing code +used in the mappings implementation). Previously, we used the GNU Copyleft +because the "Artistic" option wasn't then available. Since the "Artistic" +license is more similar to Lars Pensk|'s original Copyright than is the GNU +Copyleft, we have chosen to use Artistic instead of the Copyleft (as +is allowed by the terms Larry Wall sets forth in the Perl 4.036 README). +Where there is any conflict between Lars' copyright and the Artistic license, +Lars' copyright should take precedence. diff --git a/fluffos-2.23-ds03/Bugs b/fluffos-2.23-ds03/Bugs new file mode 100644 index 0000000..602ddce --- /dev/null +++ b/fluffos-2.23-ds03/Bugs @@ -0,0 +1,318 @@ +The internal message passing functions should be cleaned up. Currently, a lot +of stuff calls add_message() directly, while other stuff uses tell_object() +and friends. One consequence of this is that even with INTERACTIVE_CATCH_TELL +defined, not all of the output flows through catch_tell() [ed, for example, +doesn't, as well as some other efuns]. + +----- + +In the MudOS v22a36 the livings efun gives back HIDDEN things too. +I don't know why objects used that strange construction. +I think, it's new form would be more usable. +As i see this HIDDEN stuff has many leaks, like: +you can always create an object that you put into all rooms, and look +for this_player() in the init apply. +So even if you correct all efuns like livings, heartbeats, named_livings +and so on, it will never be perfect. +solve for livings and objects: +------------------------------- cut here ---------------------------------- +1831c1831 +< int nob, apply_valid_hide, hide_is_valid = 0; +--- +> int nob, display_hidden=-1; +1836d1835 +< apply_valid_hide = 1; +1844,1848c1843,1845 +< if (apply_valid_hide) { +< apply_valid_hide = 0; +< hide_is_valid = valid_hide(current_object); +< } +< if (hide_is_valid) +--- +> if (display_hidden==-1) +> display_hidden = valid_hide(current_object); +> if (!display_hidden) +1876c1873 +< int display_hidden = 0, t_sz, i,j, num_arg = st_num_arg; +--- +> int display_hidden = -1, t_sz, i,j, num_arg = st_num_arg; +1890a1888,1889 +> if (display_hidden==-1) +> display_hidden = valid_hide(current_object); +1892,1893d1890 +< display_hidden = 1 + !!valid_hide(current_object); +< if (!(display_hidden & 2)) +---------------------------------- cut here -------------------------------- + +Comment: possibly a better solution is to check O_HIDDEN where O_DESTRUCTED +is checked. valid_hide() would be checked when objects load, and would +set a O_CAN_SEE_HIDDEN bit. Then every time we run across a +FRAME_OB_CHANGE, do: + +if (current_object & O_CAN_SEE_HIDDEN) + object_mask = O_DESTRUCTED; +else + object_mask = O_DESTRUCTED | O_HIDDEN; + +Code elsewhere would then look something like: + +if (sv->type == T_OBJECT && (sv->u.ob->flags & object_mask)) { + free_object(sv->u.ob, "..."); + *sv = const0; +} + +This would be much more effective at preventing objects from detecting the +existence of hidden objects. It would also fix this one: + +Various efuns which call valid_hide() don't realize it can error, causing +them to leak if master::valid_hide() throws an error. + +----- + +If an include file doesn't end in a newline, something screws up in the +linked buffer code, causing odd compile errors. + +Line numbers get messed up when files don't end in a newline? + +----- + +RUNTIME_LOADING needs -rdynamic passed in the link on some OS's? +(reported for a gcc-linux system; possibly a mixed a.out/elf?) + +----- + +This gives the wrong error message: + +unlock the door with the key +Trying interpretation: unlock:the:door:with:the:key: +Trying rule: OBJ with OBJ + parse_rule + parse_obj: + Found noun: door + parse_rule + Matched literal: with + parse_obj: + Found noun: key + parse_rule + we_are_finished + Trying can_unlock_obj_with_obj ... + Trying can_unlock_obj_word_obj ... + Trying can_verb_obj_word_obj ... + Trying can_verb_rule ... + Trying can_unlock_obj_with_obj ... + Return value was: 1 + Trying direct_unlock_obj_with_obj ... + Return value was: 1 + Trying indirect_unlock_obj_with_obj ... + Return value was: 0 + You can't unlock the thing with that. + + exiting parse_rule ... + parse_rule + exiting parse_rule ... + parse_rule + we_are_finished + Trying can_unlock_obj_with_obj ... + Trying can_unlock_obj_word_obj ... + Trying can_verb_obj_word_obj ... + Trying can_verb_rule ... + Trying can_unlock_obj_with_obj ... + Return value was: 1 + exiting parse_rule ... + Done trying to match OBJ + parse_rule + last match to error ... + Changing last match. + parse_obj: + Found noun: key + parse_rule + we_are_finished + Trying can_unlock_obj_with_obj ... + Trying can_unlock_obj_word_obj ... + Trying can_verb_obj_word_obj ... + Trying can_verb_rule ... + Trying can_unlock_obj_with_obj ... + Return value was: 1 + Trying indirect_unlock_obj_with_obj ... + Return value was: 0 + You can't unlock the thing with that. + + exiting parse_rule ... + parse_rule + exiting parse_rule ... + parse_rule + + we_are_finished + Trying can_unlock_obj_with_obj ... + Trying can_unlock_obj_word_obj ... + Trying can_verb_obj_word_obj ... + Trying can_verb_rule ... + Trying can_unlock_obj_with_obj ... + Return value was: 1 + Have better match; aborting ... + exiting parse_rule ... + Done trying to match OBJ + parse_rule + Matched literal: with + parse_obj: + Found noun: key + parse_rule + we_are_finished + Trying can_unlock_obj_with_obj ... + Trying can_unlock_obj_word_obj ... + Trying can_verb_obj_word_obj ... + Trying can_verb_rule ... + Trying can_unlock_obj_with_obj ... + Return value was: 1 + Trying indirect_unlock_obj_with_obj ... + Return value was: 0 + You can't unlock the thing with that. + + exiting parse_rule ... + parse_rule + exiting parse_rule ... + parse_rule + we_are_finished + Trying can_unlock_obj_with_obj ... + Trying can_unlock_obj_word_obj ... + Trying can_verb_obj_word_obj ... + Trying can_verb_rule ... + Trying can_unlock_obj_with_obj ... + Return value was: 1 + Have better match; aborting ... + exiting parse_rule ... + Done trying to match OBJ + parse_rule + last match to error ... + Literal not found in forward search + parse_rule + last match to error ... + Literal not found in forward search + parse_rule + Ran out of words to parse. + Done trying to match OBJ +There is no door here. + +----- + +It still seems possible for regexp(explode(read_file(...), "\n"), ...) to +crash, but I can't reproduce it. + +----- + +#pragma optimize bug: + +;; Function room_of +049d: local LV0 +049f: ! +04a0: || 0006 (04a7) +04a3: transfer_local LV0 +04a5: objectp +04a6: ! +04a7: branch_when_zero 0003 (04ab) +04aa: return_zero +04ab: branch 0007 (04b3) +04ae: local LV1 +04b0: (void)assign_local LV0 +04b2: break_point +04b3: local LV0 +04b5: environment +04b7: local_lvalue LV1 +04b9: assign +04ba: bbranch_when_non_zero 000d (04ae) +04bd: transfer_local LV0 +04bf: return +04c0: return_zero + +object room_of(object obj) { + object ob; + if(!obj || !objectp(obj)) return 0; + while(ob=environment(obj)) obj=ob; + return obj; +} + +----- + +heart_beat() is not shadowable + +----- + + mixed a; + do {} while (a = ({ a, "" })); + +Profezzorn@TMI-2 + +Comment: + It would be nice if things like this, where all the memory (VM too) + is sucked up by a runaway program, didn't cause the driver to + shutdown ("Out of memory"). + +### Nope, this evals out, need to do more work to make it run out of memory + -Sym (note: which is not the same as if the driver errors with "Out + of memory) + +Yet another comment: Whether it evals out or runs out of mem obviously depends +on the ratio of MAX_EVAL_COST to available memory ... + +----- + +Range/switch search should be binary, not linear. (in LPC->C) + +----- + +Probably need a test to see if bison's output actually compiles in +./build.Mudos; on a lot of AIX systems bison's use of alloca() fails. + +-Beek + +------- + +One can call private functions in inherited objects via call_out. + +------ + +verbs that no longer have handlers should be deleted from the parser list + +--- + +Line numbers can be screwed up by macro expansion. Consider the following: + +#define IGNORE(x) +#define USE_ONCE(x) x +#define USE_TWICE(x) x + +// The end of the next line never gets counted. +IGNORE("foo\ +bar") + +// The end of the next line is counted once. +USE_ONCE("foo\ +bar") + +// The end of the next line is counted twice. +USE_TWICE("foo\ +bar") + +So the IGNORE() and USE_TWICE() cases with screw up line numbering. +Fixing this is non-trivial, since macro expansions are reinserted into +the input stream. Outside of quotes, it was handled by replacing +'\n' with ' ' which is semantically equivalent. Inside quotes, one has +to do something like count the newlines as they are parsed, and then +have add_input() keep track of how many artificial newlines it has created, +so these can be ignored, which requires a check every time current_line++ +is done ... + +There must be a better fix :) + +--- + +codefor int i,j; ({ i++, j})[1]; return i; + +;; Function eval_function +0000: break_point +/* Missing: + * local_lvalue LV0 + * inc(x) + */ +0001: local LV0 +0003: return diff --git a/fluffos-2.23-ds03/ChangeLog b/fluffos-2.23-ds03/ChangeLog new file mode 100644 index 0000000..827a325 --- /dev/null +++ b/fluffos-2.23-ds03/ChangeLog @@ -0,0 +1,2217 @@ +This file is the *brief* version of what has been changed; see +ChangeLog.alpha, ChangeLog.beta, and ChangeLog.old/ for all the gory +details. + +(pre-v22.2 changes) + * new options: + . GET_CHAR_IS_BUFFERED + . USE_32BIT_ADDRESSING + . NUM_EXTERNAL_CMDS + * features: + . new efun: socket_status() + . classes can be inherited multiple times so long as the definitions + are consistent + . implemented MUD mode external ports + . improved warnings for code with no side effects + . resolve() can now take a function pointer as the second arg + . filter() can now iterate over each character of a string + . LPC programs can now exceed 64k in size with USE_32BIT_ADDRESSING + . deep_inventory() and living() now default to this_object() + . cp() now errors like mv() when source and dest are the same + . -> syntax now uses call_other() simul_efun if one exists + . function tables are now always compressed + . '&' is now a synonym for 'ref' when COMPAT_32 is defined + . added #warn and #error preprocess directives + . when no address server connection exists, an attempt will be made + once every fifteen minutes to establish one. + . (s)printf() is now re-entrant, so it can be used from the + object_name() master apply. + . on most platforms, localtime() efun adds a new element to the array + it returns indicating daylight savings time + . the 3rd argument to tell_room() can now be an object + . when COMPAT_32 is defined, closeurep becomes an alias for functionp + . added extensive socket statistics and network_stats() as a new + contrib efun to retrieve these stats. + . socket_bind() now takes an optional 3rd argument that is the address + to bind to rather than INADDR_ANY or the 'mud ip' config address. + . socket_address() now takes an optional 2nd argument to get the local + address for a socket + . all objects now 'inherit' the class definitions from the simul_efun + object if there are any. + . restructured PACKAGE_DB to make it easier to add more database + support + . added support for MySQL in addition to MSQL to PACKAGE_DB + . compile_object() master apply now gets a second argument indicating + whether or not a clone is being done + . compile_object() master apply now gets arguments passed to new() + when cloning a virtual object as they'd be passed to create() in a + real object. + . implemented rfc 1184 (telnet linemode option) to be support running + on port 23. + * parser enhancements: + . new error ERR_MANY_PATHS + . new modifier ':c' that means just choose the first one found + . two object rules are examined more thoroughly. This changes the + semantics for direct_ and indirect_ applies. They can now be called + with 0s as the object-type arguments, but it is now guaranteed that + they will be called with filled object arguments at least once + during the processing of a rule. + . added optional 3rd and 4th arguments to parse_sentence(). The 3rd + is an array of objects to use in the parse instead of the inventory + of the user's environment. Nested arrays indicate containment. The + 4th is mapping of string -> object which can be used to supply + nicknames and similar things. + * COMPAT BUSTERs: + . dump_socket_status() efun is gone, see socket_status() + . SERVER_IP is no longer a compile-time option. it is now a runtime + configuration option called "mud ip" + . when COMPAT_32 is defined with PACKAGE_UIDS, the uid assigned to a + new object is the euid of the current object rather than the uid of + the current object. + . when loading/cloning a virtual object, mudlib stats, uid/euid and + privs are now properly reset with the newly assigned object name. + +(pre-v22.1 changes) + * new options: + . NO_SNOOP + * features: + . support for token quoting in the preprocessor (#x) + . 'array' is used in error messages with ARRAY_RESERVED_WORD is on + . added array | + Works analogously to &: + ({ 1, 2, 3 }) & ({ 2, 4 }) = ({ 2 }) + ({ 1, 2, 3 }) | ({ 2, 4 }) = ({ 1, 2, 3, 4 }) + . both &= and |= now work with arrays + . The requirement that a snooper must be interactive has been lifted + (though this isn't particularly useful unless RECIEVE_SNOOP) + objects may now snoop other users (logging output to logs, + output redirection, etc) + . #'foo is now the same as (: foo :) when COMPAT_32 is defined + . added a 'portbind' program; see v22.1a7 for details + . MudOS now checks if file descriptor #6 is a valid socket when + it starts up; if it is, it is used as a login port. + . support for binding a specific IP number for machines with more + than one + . It is now legal to use a class member of something of type mixed, + as long as it is unambigous (e.g. foo->x is ok as long as only + one class in scope has a member named 'x', or if 'x' is in the + same position in all classes in scope) + . Unused local variables now generate warnings + . function arguments no longer need to have names (and not naming + them inhibits 'unused' warnings) + . more than one access specifier (e.g. 'public private protected') + generates a warning + . If SENSIBLE_MODIFIERS is defined, then: + (1) 'static' no longer exists, and is replaced by 'nosave' and + 'protected' + (2) 'public' no longer means what it used to; it now means the + default visibility + . if REF_RESERVED_WORD is defined, the 'ref' can be used to declare + arguments to functions to be by reference instead of by value. + example: + int foo(int ref i) { + i++; + } + void create() { + int y = 1; foo(ref y); write(y); + } + prints '2'. Note that ref is required both in the declaration + and the call. + . added an 'efun_defined' pseudo function to the preprocessor. It + works just like 'defined', except that it looks up efuns. Example: + #if !efun_defined(snoop) + write("snoop efun not available.\n"); + #endif + * bug fixes: + . hidden object fixes for present() and environment() + . token pasting and preprocessor macro expansion + * COMPAT_BUSTERs: + . log_error() filenames have a leading / + . tail() efun was removed; compat simul in compat/simuls + . #include <...> now no longer searches based on + relative paths; #include "..." still does. + . ORIGIN_CALL_OUT is now ORIGIN_INTERNAL; in addition + most driver callbacks which do not use hard coded function names + also use ORIGIN_INTERNAL (add_action, socket callbacks, etc). + The practical fallout of this is that such routines may be static, + but *not* private. + . COMPAT_BUSTER: modifiers from a ':' declaration only + affect declarations which have no modifiers of their own. I.e. + 'private: nomask x;' no longer declares x to be private + +(pre-v22 changes) + * new options: + . NO_RESETS + . added a COMPAT_32 option, which tweaks a few things to allow + some 3.2/3.2.1 code to be ported easier + . added REVERSIBLE_EXPLODE_STRING + . added CALLOUT_HANDLES; see v22a28 for details. Allows a specific + call_out to be tracked and removed instead of having to specify + the function name. + . Added a FLUSH_OUTPUT_IMMEDIATELY option, which disables buffering + of output. Useful for debugging. + * features: + . It is legal to define variables in foreach() statements, e.g.: + foreach (string x, object y in z) + . various indexing error messages are now more information + . many changes/improvements to the parsing package + . added a package for running/communicating with external commands + (tar, gzip, etc) See the v22a15 entry for details. + . carriage returns are now considered white space by the parser, + so DOS style files don't cause errors + . new(class X) can now specify values for the members. Examples: + class foo { int x; string y; } + class foo f1 = new(class foo, x : 5); + class foo f2 = new(class foo, y : "foo", x : 1); + . added named_livings() contrib efun, which is faster than livings(), + but only finds livings which have called set_living_name(). + . bind(f, ob) now always succeeds if f is already bound to ob + . function(...) { ... } is now rebindable if it does not reference + local functions or global variables + . the message of message() may be of any type + . replaceable now can be optionally passed a second array argument + which is a list of function names to ignore; if the second arg + is left out, ({ "create" }) is assumed, which gives the old + behavior. + . made the message queue flushing a bit lazier which should result + in smoother output and larger packet sizes + . added a flush_messages(void | object) efun for manually flushing + message queues (during a long thread of execution, for example) + . \012 octal codes and \x1e hex codes are now allowed in string + and character constants + . added a classp() efun + . fixed sort_array() to work correctly when called from inside + itself + . added repeat_string() contrib efun. Example: + repeat_string("-=", 10) == "-=-=-=-=-=-=-=-" + . added a memory_summary() contrib efun, which returns a mapping + of with entries: map["program name"]["variable name"] + Each entry contains the number of bytes used by that variable in + all active instances of that program. The size of shared structures + is divided up evenly between all values that reference it. + . terminal_colour() now has two more optional args; the 3rd is the + width to wrap at, and the 4th is the indent for lines after the + first + . characters in user input with the 8th bit set are no longer ignored + . function_exists(string, object, flag); if flag is nonzero, private + and static functions are checked too. + . SIGUSR2 will now cause the driver to eval out immediately + * optimizations: + . sprintf() is about 3 times faster than it used to be + . optimized present(), terminal_colour() + . call_out() is now O(1), not O(n) + . function tables are sorted, so they can be searched in O(log n) + time instead of O(n). Speeds up call_other(), function_exists(), + etc. + * memory usage: + . fixed leaks in call_out(), illegal arguments to call_stack(), + errors in id() + . function overhead is now 15 bytes per function defined and 5 bytes + per function inherited, not 14 bytes for both. Typically cuts + function memory usage in half or more, also: + . if COMPRESS_FUNCTION_TABLES is defined, the function tables are + compressed even further (estimated compression: 2-3x) at the cost + of slowing down function calls slightly (seems to be <10%) + . variable information is now stored only in the program in which + the variable is defined; estimated compression ratio is about + 10:1 on typical libs + * bug fixes: + . testsuite now compiles with almost any option settings + . sprintf()'s %O handles recursive structures gracefully + . many fixes to center/left justification in sprintf + . function arguments and variables no longer may be of type 'void' + . leading and trailing whitespace in the config file is now ignored + . switch (...) { case 0: function() { break; }; }, + while (...) { function() { continue; }; }, + while (...) { e = catch { break; } } + and similar pathological code is no longer allowed. + . message() now behaves correctly when called from inside + recieve_message() [i.e. recursively] + . a number of changes to $() notation. See v22a38. + . several fixes to sscanf(): format strings ending in %, %% as + the last pattern + . fixed socket_close() to not close sockets immediately when data + is buffered internally; this adds a new socket state 'CLOSING' + which will transparently change to 'CLOSED' when the data has + been written. + . cleaned up the disk full logic a bit; also added error checking + on the fclose(), which apparently the call that usually errors. + should prevent .o files from getting lost when the disk is full + . fixed read_file() to return "" and not 0 for zero-length files + . sending a SIGUSR2 to the mud will now cause it to eval out; temporary + fix until eval_cost gets rewritten. + . sscanf() no longer errors on some legal uses of %% + * crasher fixes: + . removing heart_beats during a heart_beat() + . lots in the parsing package + . extremely long tables in sprintf(), negative field widths, etc, + etc, etc + . recursive structures in error traces + . function_owner() + . unterminated @ and @@ blocks + . some too deep recursion errors + . mapping composition + . quite a number of other rare ones + * COMPAT_BUSTERS: + . previous_object() is now 0 in heart_beat() + . the scope of variables defined in for() and foreach() is inside + the loop ONLY; it used to extend to the end of the function + . "%^" is no longer considered "special" by sprintf(); see + terminal_colour() if you want to wrap strings containing it. + . removed break_string(), process_string(), process_value(). + See compat/simuls/ for replacements + . call_stack(3) now uses strings, like origin() + . call_out_info() elements now have only 3 elements, + not 4; this is due to argument handling restructuring, as well + as mild security concerns for reference types. Maybe an option + will be added to get the arguments at a latter date if it is + desired. + . all inherits must now precede all global variable definitions + . Added slashes to the front of many object/program names. The most + noteworthy are: deep_inherit_list(), inherit_list(), call_stack(), + names passed to author_file(), domain_file(), privs_file(), + creator_file(), a few error messages and tons of debug messages + . The third argument passed to valid_override() now has a leading + slash + . The filename passed to compile_object() has a leading slash + +Thu May 30 14:35:06 EDT 1996 (tim@wfn-shop.princeton.edu (Beek)) + * bumped version number to v21.7 + * new options: + . NO_ENVIRONMENT + * features: + . destruct()'ing the master or simul_efun object now fails if a + new copy can't be loaded, leaving the old copy loaded + . copy() supports classes + . the simul_efun object is optional; simply don't specify one in + the runtime config file if you don't want one + . outside functions, "modifier:" can be used to make all + functions, variables, and inherits automatically include + "modifier" until the next such definition. For example, + "private static:" makes all definitions that follow it both + private and static + . ed ranges can now extend past the end of the file; any line # + larger than the last one refers to the last line + . foreach (int in string) + . preliminary Windows 95 support, though I'd recommend using + a v22 beta instead + * new warnings: + . return type doesn't match prototype + * contrib efuns: + . query_ip_port(), for figuring out which of the external ports + an interactive object connected to (the port number is also + passed to connect; this causes it to be stored internally) + * optimizations: + . better code generation for some loops, empty blocks in if + statements, x[y..<1], elimination of expressions with no + side effects + . sprintf() is significantly faster + . most mapping operations are significantly faster + * memory usage: + . mapping memory is down about 20% + * bug fixes: + . A number of bugs which allowed private functions to be called + were removed + . problems with comments in long #define's + . various problems with the 'array' keyword + . testsuite works again + . literally hundreds of fixes to the parsing package, though + if you use it I'd suggest using a v22 beta instead. + . ranlib is run on subdirectory archives, for systems that need it + . using the values of (void) efuns in some cases + . ... syntax varargs expansion in some cases + . several bug fixes in macro expansion + . @@ blocks work again + . a few crasher and leak fixes in parse_command() + . query_verb() returns the entire verb even when only part of it + was matched again + . SIGFPE and SIGPIPE no longer take down the driver on some + systems + . case 0 now works in string switches again + . (int constant)/(real constant) is a real, not an int + . the telnet option code is more robust to protect against buggy + telnet clients + . a number of other fixes for rare crashers + * COMPAT_BUSTERS: + . the each() efun is gone. Use foreach(). + * minor changes: + . objects with environments may be cloned + * LPC->C: + . valid_compile_to_c() in the master object now controls the use + of generate_source() + . RUNTIME_LOADING works if your system supports dlopen()/dlsym(); + see ChangeLog.alpha:v21.7a1 for details + +Fri Oct 6 18:58:01 EDT 1995 (tim@handel.princeton.edu (Beek)) + * bumped version number to v21.6 + * LPC->C support: + . annonymous functions, function pointers, and foreach now work + . classes now work + . faster string constants + . a number of small fixes to code generation + * compiler changes: + . warning for negative constants not meaning indexing from end + . internal representation was changed to support better + optimization + . warning for (: string constant :) + * optimizations: + . calling of efuns is significantly faster + . faster calling of efun function pointers + . last use of local variables when #pragma optimize is on + * removed support for: + . #pragma efun + . contrib/compat.c + * features: + . variables() has an optional flag like functions() + . new contrib parsing package added + . implode(array, function) now takes a third arg (the value to + start with) + . more extensive configure checks + . 'array' is now a legal type, meaning 'mixed *'. See the + v21.6a8 ChangeLog for more info + . catch { ... } and time_expression { ... } are now legal + . if a function is defined as: void foo(int x, array args...) + then all the additional arguments after x are put in args + . regexp(string, string) now exists, returns 1/0 + . remove_call_out() [no args] now removes ALL of this_object()'s + call_outs + * crasher fixes: + . remove_interactive() + . illegal indexes to array constants, e.g ({ 1, 2 })[5] + . regexp() with 8 bit chars when host char is signed + . two in parse_command() + . don't go down on floating point exceptions on systems which + crash when a SIGFPE is raised + * bug fixes: + . replace_string() behavior in some cases + . compilation fixes for DEC alpha + . ranlib is run on the archives for systems that need it. + * COMPAT BUSTERs: + . origin() and typeof() now return strings. If you used the + defines in the driver includes, that should be fine + . filter_mapping() now passes the value as the second element, + just like map_mapping() + +Sun Jul 30 10:14:15 EDT 1995 (tim@handel.princeton.edu (Beek)) + * bumped version number to v21.5 + * features: + . a ... operator which expands an array into a list of arguments + . %(regexp) format for sscanf() + . added implode(array, function) + . added foreach() + . added \a and \e for bell and escape + . a 'local_options' file can be used to override options.h + * fixed crashers in: + . empty sefun objects + . non-existent socket callbacks + * bugfixes in: + . type errors including classes + . consecutive tokens in sscanf() like %s%% + . calling set_heart_beat() from from a heart_beat + . LPC->C switch statements + . MUD mode sockets + . unterminated @ and @@ blocks + . load_object() + . better configure checks + . pluralize() + * optimizations: + . array call_other() + . replace_string() + . calling function pointers + . replace_program() + . heart_beats + . member_array(), string compares, string hashing + . more efficient handling of errors + * contrib efuns: + . remove_interactive(), variables(), heart_beats() + * COMPAT_BUSTERS: + . the apply() efun is gone. There is a simul for it in compat/simuls + . Now, if process_input() returns a non-zero number, no further + processing takes place. Also, returning zero does not disable + the function + . this_player() is now zero in get_save_file_name(); a new 2nd + argument is the player + . 'foreach' and 'in' are now reserved words + . map_mapping now passes the key and the value + . It is now illegal to any of the following from a + verb action which return zero: + call remove_action() + destruct an object which defines commands + move an object which defines commands + move a living object + . the following efuns now return strings and print nothing to + this_player(): + malloc_status(), cache_stats(), lpc_info(), mud_status(), + dump_file_descriptors(), program_info(), + debug_info(), dump_socket_status() + +Sun Jun 11 03:33:40 EDT 1995 (tim@handel.princeton.edu (Beek)) + * bumped version number to v21.4 + * features: + . a file named 'local_options' with the defines from options.h in + it will override options.h. You will be warned if new options + that don't exist in your local_options file have been added. + . cleaned up the data written to stdout/debug.log. The same + info now goes to both. + . the logon() function is no longer required. + . sizeof(class) now returns the number of members + . '\a' is now bell, '\e' is the escape char + . foreach ( [, ] in + for looping over arrays/mappings + . memmove() checks done by edit_source -configure + . implode(mixed *, function). See the v21.4a6 changelog for + some uses/examples + . '%x' can be used for hexidecimal in sscanf() + . w->x[y] = z, w->x[y]++ and w->x[y]-- are legal now + * fixed crashers in: + . people going linkdead in ed + . add_action parsing when objects move/get destructed + . calling non-existent socket callbacks + . simul efuns objects with no simuls + . socket_address() + . calling function pointers in swapped objects + . x->foo compilation errors when x was not a class + * new contrib efuns: + . string variables(object), object *heart_beats(), + int remove_interactive(object) + * memory leak fixes: + . an array in mudlib error tracebacks + . throw() + . [0..n] array ranges on ref 1 arrays + . functionals keeping programs from freeing + * bugfixes: + . previous_object(-1) after an lfun or functional pointer; an + extra object is no longer mistakenly inserted + . numerous fixes to the pluralize contrib efun + . load_object() doesn't error if the file doesn't exist now, + like the documentation claims + . fixed MUD mode sockets on machines where sizeof(long) > 4 + . window sizes with widths or heights of 255 + . '/' is now a legal log file directory + . wierd error messages for unterminated @ or @@ blocks + . fixed a bug that truncated arrays/mappings on MUD mode sockets + . replace_program() objects now look like clones again (clonep) + . workarround for a GNU make 'feature' that caused 'can't find + rule for obj/grammar.tab.o' errors + . str[n..] returns "" when n > strlen(str) + * optimizations: + . replace_string(), member_array(), string comparisons, hashing + . shared string deallocations + * COMPAT BUSTERS: + . The following efuns now return their output as strings: + malloc_status(), cache_stats(), lpc_info(), mud_status(), + dump_file_descriptors(), program_info(), debug_info(), + dump_socket_status() + . this_player() no longer exists in some places where it + previously did + . It is now illegal to any of the following from a verb action + which return zero: call remove_action(), destruct an object + which defines commands, move an object which defines commands, + move a living object + . 'foreach' and 'in' are reserved words + . map_mapping() now passes both the key and the value + . get_safe_file_name() is now get_save_file_name(string fname, + object who); this_player() is now zero in it + . previous_object() is now zero in add_action()'ed functions; + this fixes several crashers + +Wed May 17 14:54:59 EDT 1995 (tim@handel.princeton.edu (Beek)) + * bumped version number to v21.3 + * features: + . new ed option 'verbose' + . optional flag to functions() contrib efun gives more extensive + info + . this_user() is now equivalent to this_player() + * fixed crashers in: + . self-destructing objects with call_outs + . call_outs to function pointers + . reload_object() on a swapped object + . reclaim_objects() and function pointers with no arguments + * bugfixes: + . problems with too wide columns in sprintf's column mode + . calling reclaim_objects() no longer corrupts mappings whose + keys contain destructed objects + . classes now save/restore correctly + . various fixes to the configure scripts + . fixed non-typechecked functions to not give type errors + . TELOPT_NAWS fixed to handle zero bytes correctly + . fixed a bug in adding an int to a string + * optimizations: + . explode() and implode() + . counted strings + . eliminated switches over types for all refcounted types + . shared string frees + . read_buffer() + * COMPAT BUSTERS: + . ALWAYS_SAVE_COMPILED_BINARIES removed + . map_mapping() now passes the value, not the key, to the + function pointer + +Fri Apr 28 20:24:42 EDT 1995 (tim@handel.princeton.edu (Beek)) + * bumped version number to v21.2 + * features: + . packages are now specified in options.h; #define + PACKAGE_ANYTHING in options.h will cause packages/anything.c + to be compiled in + . classes can contain instances of themselves now + . NAWS window size negotiation: the callback is + window_size(int width, int height) + . to compile MudOS, now type './build.MudOS' and follow the + instructions + . support for multiple login ports, as well as binary/ascii + ports as well as telnet; see ChangeLog.alpha + . sockets are now initialized before preload() is called so + socket objects can preload normally + * Two new contrib efuns + . store_variable/fetch_variable + * fixed crashers in: + . pointers to void valued efuns + . anonymous function pointers + . set_hide() + * bugfixes: + . fixed a bug where 'continue' would some jump to the wrong + point + . typeof() efun + . a strsrch() hanger + * optimizations: + . assignment to locals + . pushing of call_out arguments + . return zero, loop conditions, logical expressions + . multiple pushes + * source changes: + . merged intermediate programs that edit the source code into one + main program + * COMPAT BUSTERS: + . privs_file() is now called to get new privs for virtual + objects; see ChangeLog.alpha for full details + . a bunch of LPC predefines which weren't of the __FOO__ + variety changed names; see ChangeLog.alpha for a list + . 'efun', 'new', and 'asm' are no longer valid variable/function + names + +Thu Mar 30 14:56:48 EST 1995 (tim@handel.princeton.edu (Beek)) + * bumped version number to v21.1 + * three new contrib efuns: + . int replaceable(object) - returns 1 if the object consists only + of a create() function and inherited functions + . void program_info() - prints out memory usage of programs + divided up by sections + . string upper_case() - similar to lower_case(), but ... :) + * fixed crashers in: + . the compilation of switch tables to C code + . duplicate objects in the hash table with LPC objects + precompiled and DEBUG on + . type errors in division + . the inherits() efun + . call_out(function, ...) + . regular expressions that end in '\' + * optimized: + . some of the compile time type checking + . void valued efuns (they are all guaranteed to return zero now + as well) + . mapping operations. A custom allocator was added, which + should decrease mem overhead as well + . changed program ref counts to shorts, saving 2 bytes/program + * removed: + . errorp() efun + . RUNTIME_LOADING in options.h + * bug fixes: + . a division error message that indicated multiplication + . a problem with the types of locals in anonymous functions + . a few errors in smalloc accounting + . type checking involving classes + . it is no longer to illegal to overload a function to have a + different number of arguments + * porting fixes for CX/UX 6.1, IRIX 5.3, amiga + * COMPAT_BUSTERs: + . removed OLD_HEARTBEAT, OLD_COMMAND, IGNORE_STRICT_PRAGMA + . removed STRICT_TYPE_CHECKING; use PRAGMA_STRICT_TYPES + . removed ALWAYS_SAVE_BINARIES; use PRAGMA_SAVE_BINARIES + . move_object() only takes one arg; change + move_object(this_object(), foo) to move_object(foo) + +Fri Mar 10 11:03:09 EST 1995 (tim@handel.princeton.edu (Beek)) + * bumped version number to v21 + * fixes up to v21.1b4 included. + --- Robocoder + * fixed smalloc accounting stats, and small leak in small block handler + * more amiga fixes, and compilation tweaks + * fixed a memory leak in parse_command() + * save size of buffer in binaries.c to cut down on allocations a bit + * a few more fixes to clear_bit() and set_bit() + * fixed the Amiga port to handle problems with read() and + write() macros more cleanly + * fixed some socket problems by changing recv() to read() in + the socket handler + * fixed a problem that would sometimes allocate a string table + that was twice as big as requested + * fixed some OSF/1 V3.0 cc compile problems with source code + formatting + * fixed Alpha crasher with intersect_array() and alist_sort() + -- reported by Dana + * fixed debugmalloc portability problems for AIX - reported by + Curax; and undef'd SBRK_OK automatically for AIX + * added prototypes that were missing in places + * added some include files to fix some implicit definitions + * removed some more unused locals + * otable.c: copied Beek's power of 2 HTABLE_SIZE test for checking + OTABLE_SIZE; increased the max number of characters to hash from + 20 to 40, to handle longer pathnames (FWIW, this was 100 in + 0.9.20); cleaned up show_otable_status() to be more consistent + with other stats reporting functions + * eoperators.c: copied Beek's f_sscanf() return value fix to + f_parse_command(); also removed a redundant check_for_destr() + * array.h: removed an unused #include (of itself? *boggle*) + * parse.c: bumped refcounts to a couple of arrays before calls to + splice_array(), and rearranged some code to avoid an uninit'd + svalue + * Makefile, GNUmakefile: to find on Solaris (5.4), + add -I/usr/bsdinclude to OSFLAGS + * malloc.h, smalloc.c: fixed for SBRK_OK defined; and some changes + for the Alpha + * some Amiga tweaks so that the driver actually works there =) + * fixed a crasher in parse_command() + --- Beek + * COMPAT_BUSTER: objects that call replace_program() no longer + return true to clonep() or virtualp(). + * fixed a crasher in binaries (program name is now a shared + string) + * fixed some memory accounting errors + * sockets are now closed before calling shutdown, since the + operating system doesn't always close them right + * reorganized the logic of parse.c in places; fixed uncountably + many memory leaks; added a stack of globals so that it doesn't + leak even in the event of an error + * fixed a leak involving destructing users with notify_fail() + messages pending + * fixed a ref count bug in domain/author_stats() + * fixed a problem/crasher in compiling files which can't be opened + * added a non-varargs version of add_message(); profiling shows + that the telnet support is slow without it; generally optimized + and cleaned up sending of telnet codes; use add_vmessage() if + you need varargs support. + * fixed a crasher in referencing local functions/globals from + within a functional in some contexts + * fixed a crasher in string < string + * removed some (unused?) prototypes from lint.h + * fixed a crasher in prototypes in the simul_efun object with no + corresponding procedure + * fixed a bug in the disassembler with non-bindable functionals + * removed outdated MALLOC defines from GNUMakefile + * fixed the error message for reverse sorts of arrays to indicate + that arrays of arrays are legal + * fixed some serious bugs in clear_bit() and set_bit() introduced + while optimizing + * fixed crashers in illegal arguments to snoop(); cyclic etc + * fixed compilation with TRACE defined + * fixed compilation problems with NO_SOCKETS; awaiting better + Amiga patches from Robo :) + * fixed a bug in show_otable_status() that would print information + to this_player()/stdout when memory_info() is used + * fixed the new ed efuns to return "" rather than 0 when there is + no output. + * un-ANSI-ized the source for archaic/lame/braindead compilers + that only understand K&R + * as part of the above, made the dispatching in generate.c use + defines and not token pasting; also optimized a bit + * fixed a typo in lex.c that could crash on extremely long lines + * fixed the case for the -d option with DEBUG off + * COMPAT_BUSTER: previous_object() is now zero when crash() is + called in the master object + * expanded the error messages printed by the creator_file() master + apply; revised it to use apply_master_ob() + * fixed a memory leak in the 'table' feature of sprintf ('%#5s') + * set the tag of linenumbers correctly when they are swapped back in + * removed prototypes for some removed functions, some unused + locals and globals + * added a 'block_or_semi: error' rule to the grammar so that + the back half of the function definition rule is always called + This is important since the function name is saved on the yacc + stack and will otherwise be leaked + * fixed the switch grammar to accept any constant string + expression using () + and concatenation as case labes, same + goes for inherit file names + * fixed some definitions to use Pn() + * small ed tweaks: + . hitting return to get the next line at the end of a file + now prints 'End of file.' and not 'Bad line range.' + . 3,5 is now the same as 3,5p instead of just printing line 3 + * COMPAT_BUSTER: slight change to the behavior of having two + variables with the same name in an object: + old one is made static only if the new one is not hidden + (so inheriting an object with private foo; wont make the + variable in the current object static), also if the new + one is hidden, dont make it the 'foo' variable for this + object. Problem reported by Angus. + * fixed #undef OLD_ED compilation + * fixed a crasher in ed_start() + * modified a few references to non-existent files "efuns.h" and + "exec.h" + * fixed a crasher in the optimization of icode (didn't know about + F_SHORT_STRING) + * fixed a bug that caused numbers returned by sscanf() to often + be undefined/null + * fixed a memory leak in constant mappings with duplicate keys + * compilation fix for DEBUGMALLOC but not DEBUGMALLOC_EXTENSIONS + * commented out an unused variable in smalloc.c; also cast sbrk() + to (char *) since I don't know where to find the prototype and + AIX complains ... + * fixed in_edit() to work with #undef OLD_ED + * optimized/made the snoop() code more sensible + * fixed a crasher in call_out(function, ...) + * disabled the report_holes debugging code + * updated the generate_source() efun for symmetry's efun changes + * fixed a bug in loop optimizations: + for (...; local_var < integer_constant; ...) + when local_var was *not* of type int. + * removed the mkdir prototype for SunOS 4.1.x; evidentally it + exists in a standard include now? (blame Dseven if it doesnt) + * fixed the GNUmakefile to create mallocwrapper.c + * put the clear_state() back into backend.c for now + * fixed the source to actually use the BINARIES define; it + was mistakenly using SAVE_BINARIES + * fixed a memory leak in ed regular expressions + * fixed array->foo() to set origin() correctly + * fixed a crasher in locals left behind by errors + * fixed some really odd (and inefficient) logic in address server + callbacks; this implements the multiple query on the same + address fix from 0.8.35 more sanely. + * Added mallocwrapper.c to the GNUmakefile + * fixed a memory leak in array ranges that return ({ }) + (array that was indexed was leaked) + * slight optimization to array addition + * fixed a memory leak in array intersection (intermediate table) + * fixed a memory leak in reg_assoc() (regexps not freed) + * fixed a memory leak in PRIVS (not freed when ob destructed) + * fixed a few memory leaks in errors in regular expressions + * in check_memory(), count the shared strings in the ip number + table, count FP_FUNCTIONAL | FP_NOT_BINDABLE as a functional, + count refs inside of function pointers, count refs from input_to + and get_char, print out contents of arrays that are leaked, + count references in swapped objects + * fixed undefinedp() and nullp() to return defined and non-null + answers, respectively + * ( string ) and string + string are legal in case statements + now/again, respectively. + * fixed compilation problems with PROFILE_FUNCTIONS on + * fixed a crasher in set_this_player() + * fixed compilation with NEW_FUNCTIONS off + * fixed a compilation problem with NO_ADD_ACTION and + THIS_PLAYER_IN_CALL_OUT + * fixed a bunch of compilation warnings from gcc re: inline functions + * Fixed replace_program to not crash if called in an object + with expression function pointers. Global variables and + functions can still cause problems tho. + * COMPAT_BUSTER: the values of funtionp() no longer use origin. + use /include/function.h. Now also returns info as to whether + the fp is bindable, and whether it's owner has been dested + * added: function bind(function, object) + returns a function pointer that behaves the same as the one + that was passed to it, except the new function pointer belongs + to the object passed to bind. Security is handled through + int valid_bind(object binder, object old_owner, object new_owner) + (master apply) + * fixed a bug that would dest any user that sent more than 2k + of data to the mud without a pause (pasting into ed, etc) + * fixed some cast problems in the switch code + * fixed binaries and string switch to work on machines with 8 + byte pointers (DEC Alpha) + * added in the v20.26b3-4.diffs since whoever released them didn't + include them in an alpha release and I forgot to add them to + mine ... + * extra arguments passed to new (clone_object) are passed along + to create() of the clone. + * fixed the put_* defines to work as single statements + * fixed several bugs in the new ed() functionality + * made reset_object(foo, 0) and reset_object(foo, 1) separate + functions + * added help for '/' and '?' in ed + * fixed a crasher in save_ed_buffer() + * added about 15 more different error messages to ed so it's a bit + more friendly + * added a new interface for ed(), which is used if OLD_ED is not + defined in options.h + . Three new efuns replace ed(): + string ed_start(string | void, int | void) - start a new ed + session on file file. ed_start(foo, 1) means use + restricted mode. Only one ed session may be started + per object. + string ed_cmd(string) - send the command line to ed + int query_ed_mode() - returns: + 0 - the current object is at a normal ed prompt (':') + -1 - the current object isn't in ed + -2 - the current object is at the more prompt in the + middle of help + >0 - the object is at a prompt for a line. The number + is the line number. + . The string result of ed_cmd() and ed_start() is the output + that would have been sent to the user + . The mudlib is responsible for setting the user's prompt + (see query_ed_mode()) + * added an NO_ADD_ACTION define which has the following effects: + . adds an efun: set_this_player() + . removes many efuns: + add_action(), remove_action(), query_verb(), + command(), commands(), enable_commands(), disable_commands(), + living(), set_living_name(), livings(), find_living(), + find_player() + . based on the above, the only way to handle user input is + through the process_input() apply; but this is better than + having add_action(..., "", 1) + . the efuns that need to know if an object is living (say, + tell_room, shout) now send messages to any object that + defines a catch_tell() function. + . note that NO_ANSI has no effect b/c it happens after + process_input is called + . %l removed from parse_command() + * added a NO_WIZARDS define. combined with the following defines + it has the following effects: + . if MUDLIB_ERROR_HANDLER is undefined: + all users are wizards (get verbose error messages) + . if NO_MUDLIB_STATS is undefined: + for the purposes of mudlib stats, no one is a wizard + (the 'moves' field includes everyone) + . if RESTRICTED_ED is defined: + everyone is a wizard (defaults to unrestricted mode) + the mudlib should explicitly start ed in restricted mode + if this is needed + * added call_out(function, ...) + * added apply(function, mixed *) which allows a variable number + of arguments to be passed to the function + --- Symmetry + * Fixed a possible crasher with #pragma show_error_context + * Correctly adjusted total array size and mudlib stats + for slice_array with ref 1 arrays + *** Since v21a3 *** + * Fixed a bug when some efun names are also used as names for + local vars + * Allow $(expression) to be a valid indexable lvalue, i.e. + $(m)[5] = 3 is valid + * Fixed a crasher involving Illegal LHS errors + * Don't call clear_state() within the backend loop + * Allowed + #define FOO\ + 12 + where the \ is right after the macro identifier + * Added a missing check for stack overflow during an apply + call using a ref 1 array for e.g. + * New efuns : unique_mapping(), filter_mapping() + * optimized slice_array() + * Some bug fixes to apply() + * Fixed a constant-folding optimization bug which gave + erroneous results for simple subtraction as in 11 - 2 + --- Robocoder + * Fixed a bug in lex.c concerning array blocks + +Sat Jan 21 20:25:44 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v20.26 + * fixed a problem that would sometimes claim the maximum include + depth was exceeded + * fixed the tags on a bunch of memory allocations + * removed a memory leak in function overloading warnings + * fixed ref count problems/crashers in move_object()/tell_room() + * fixed a crasher in the illegal use of private variables + * added buffer and function support to sameval(), this means + functions and buffers compare equal to themselves for the + purposes of unique_array() and also match themselves as + mapping keys + * added function and buffer support to svalue_to_int(); this makes + buffers and functions as mapping keys more efficient + * == and != can now be used to tell if two buffers or functions + are in fact the same buffer/function + * removed debug_message_svalue(); unused and obviously a throwback + to Larsian days + * Solaris compilation tweaks from Robocoder: + . gcc defines SunOS_5 so we don't have to + . M_ERROR is used; used SPRINTF_ERROR() instead + * Fixed the contrib efuns to compile again + * Added some Linux compilation fixes received from marius (?) + * removed a redundant apply to #global_init# + * Fixed a compilation problem with call___INIT + * Fixed a crasher using the 128th thru 255th string constant + in an object + * Fixed a crasher in $() outside function pointers + * Fixed warnings for clashes between functions inherited at + different branches to not be printed if the function is + overloaded, or either of the inherited functions is private. + * Fixed nomask to give errors correctly regardless of inheritance + order + * Fixed a bug in member_array() that caused member_array(x, "") + to give an error + * Fixed the undefined function error message to not give a + redeclaration error if the function is defined later + * Fix a crasher on evaluation of anonymous functions in an + inherited program + * Fixed a crasher in make_range_node + * added map(string, ...) works just like map_array, except it + works on the characters that make up the string. If the return + value is not an integer or is zero, that character is left + unchanged. + * removed the ancient ref count checking code + * the -d option is now only available when the driver is compiled + with DEBUG on + * added add_action( function, string ), updated commands() to + return "" for function pointer commands + * added input_to( function ) and get_char( function ) + * fixed the inherit from multiple branches warning o actually work + * fixed a bug in inheriting nomask functions + * fixed a few problems with nested calls to expression or + functional function pointers, and dangling of pointers when + the associated program objects swap. + * fixed a ref count bug in string constants for string cases + * added check_memory(1) which also prints out a summary of all + allocated memory + * changed shared string ref count debugging code to allow tracking + of a particular string + * several changes to DEBUGMALLOC: + . changed the tag numbers to be meaningful + . use temporary tag info to find leaked blocks with the + memory_check() efun (available with DEBUGMALLOC_EXTENSIONS) + . added magic numbers to start and end of blocks to catch + corrupted blocks + . added code to check all ref counts and allocated blocks + * changed program names to be shared strings + * changed call_other cache entry names for missing functions + to be shared strings + * Fixed a memory leak in (s)printf which leaked 8 bytes per %O + and per (null) + * converted swap.c to use DXALLOC and FREE + * added ALLOCATE, CALLOCATE, RESIZE, RESIZE_VECTOR defines to + simplify code; note that CALLOCATE does *not* zero the memory + * move compilation info about functions to a stack so they can + be pushed so we can do anonymous functions + * added support for pass-by-value to function pointers. The + syntax is $(expression), where "expression" will be run when + the function pointer is made, not when it is evaluated. + Note the difference between (: this_object() :) and + (: $(this_object()) :) + * added anonymous functions. The syntax is: + function( ) { } + for example: + create() { + function f; + + f = function(int x) { + int i; + for (i = 0; i < x; i++) { write(i+""); } + }; + evaluate(f, 10); + } + * fixed a few bugs/crashers regarding the number 0x80000000 + --- Symmetry: + *** Since v20.26a5 *** + * Check the type of 3rd argument passed to regexp, optimized + match_regexp + * Free some unused memory, added some %pragmas in make_func + * Rewrote the automatic echo_line to be more robust, added + check for starting a new compiler case before ending the + previous when echo_line mode is on and fixed some line number + bugs associated with reading from buffered input in + make_func + * The compiler return type of the efun call_other is now + TYPE_ANY if CAST_CALL_OTHERS is not defined + * If __bsdi__ is defined, don't define HAS_STDARG_H in + portability.h + * Introduced range lvalues and limited the possible lvalues + syntactically + * Introduced ranging/indexing from the end + * Added some missing checks for division by 0 or 0.0 + * L_BASIC_TYPE now covers all basic types in grammar.pre + * Removed some unused fields in YYSTYPE + * Local variables now have proper (block) scope + * Switch grammar is more restrictive, but make more sense + * Don't include getpeername and shutdown prototypes in lint.h + for bsdi + * Optimized the array allocation is get_svalue_trace() for + trace information on the topmost control stack + * Fixed crasher in get_inherit_index + * Included port.h in port.c to fix the random() bug again for + AIX + * Fix crasher/memory leak in sprintf when buffer size is + overflowed (in some cases, the fix actually amounts to + truncation of the input string near the end of the buffer) + * Optimized read_file() a little bit more + * Fixed restore_string and restore_hash_string to work for + AIX 3.1.5 (bug reported by Chuck@IdeaExchange) + * Added an options.h define OLD_RANGE_BEHAVIOR for string/buffer + range values with negative indexes to mean counting from the + end + * Added a doc 'substructures' describing the new lvalue, + indexing and ranging features + * Generate the opcode F_BREAK_POINT only on DEBUG mode + * Fixed a crasher when a prototype is used before inheriting + a function of the same name when that function is overloaded + by inheritance again later + * Optimized the addition of argument type information during + compile time + *** Since v20.26a7 *** + * Implement the restore_string change (apparently I forgot it + in v20.26a5 even though it was done in restore_hash_string) + * Small optimization to byte insertion for function pointer + construction at compile time + * Minimal jump threading for a && b && c and a || b || c is + always supported at compile-time + * Fixed the compile-time assigned return type of a ? b : c + * Optimized the handling of break and continue jumps in compile + time, and removed the compiler stack + * Fixed a typo in passing a default of 1 for efun function + pointers during runtime + * COMPAT BUSTER: No longer allow foo::bar() to work if foo + is actually only part the ending of an inherited program + whose name can be e.g. "/.../abcfoo.c" + * COMPAT BUSTER: No longer allow foo::bar() to work if foo + is inherited later than when the function was called + * Some small changes to the substructures doc + * Removed the runtime pushing of nulls for local variables + defined within blocks + * explicit calls to inherited functions (i.e. foo::bar()) no + longer create a new function in the current function table + * Slight optimization to !x + * Less opcodes generated for F_LOOP_COND optimization of + while or for loops + * Introduced F_SHORT_STRING as a first attempt at getting less + program size + * Fast ___INIT calls and checks for ___INIT's existence in + inherited function tables, no longer copy ___INIT in inherited + programs to the current function table + * Fixed a compiler type-checking problem associated with local + vars in blocks after other complete blocks with local vars in + them e.g. foo() { int a; { int b; } { int c; c = a; } }, the type + of c was wrong + * Fixed a compiler type-checking problem for anonymous functions + E.g. in + string foo() { + function f = function() { return 5; }; + } + an error was produced because the function pointer was assumed to + return a string. Anonymous functions are now taken to return type + mixed instead. + +Fri Jan 13 20:17:20 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v20.25 + --- Beek: + * changed string *get_dir() to mixed *get_dir() since get_dir() + can return an array of arrays + * removed contrib efun map_string(); it's slow, and it leaks. + * added terminal_colour() contrib efun. + * fixed void foo(string str) { string str; ... } to give an + error message + * added for (int i = 0; ... + * optimized the insertion of bytes into program blocks + * mudlib_stats.c: include std.h before checking NO_MUDLIB_STATS + * fixed call_others not to give type errors with CAST_CALL_OTHERS + off + * crasher fix/optimized ++, -- (all three forms), +=, assignment + * removed some unecessary code from skip_comment() + * added COPY_SHORT, COPY_INT, COPY_PTR, COPY_FLOAT, LOAD_SHORT, + STORE_SHORT, etc for code clarity and portability; slight + optimizations in places + --- Symmetry: + * optimized allocate_array, explode(), implode(), users(), array + copying, commands(), filter_array(), sameval, unique_array(), + array addition, array subtraction, all_inventory(), map_array(), + deep_inventory(), array intersection, regexp(), + deep_inherit_list(), inherit_list(), children(), livings(), + objects(), typeof(), regexp(), each(), keys(), values(), + allocate(), function_profile(), stat(), call_out(), + call_out_list(), get_dir(), localtime() + matrix package efun identity() + contrib package efuns functions() and copy() on arrays + * optimized check_valid_socket() + * optimized ++x, while_dec, local lvalues, F_BYTE and F_NBYTE, + branches, &&/||, local values, <, +, +=, array constants, + mapping constants, =, --x, >, >=, global values, indexing, + <=, %, !, global lvalues, string constants + * optimized array->foo(), removed a memory leak + * optimized get_svalue_trace (used by the mudlib error handler) + * optimized type name + * small optimization to assign_svalue_no_free + * optimized add_slash, push_indexed_lvalue, bad_argument + * optimized stack overflow checks, made stack overflow an error + * optimized function calls (push_nulls, copy_some_svalues, apply_low) + * optimized stack pushes: + No STACK_CHECK checks here, because end_of_stack is 5 below + the actual end, and 5 pushes is infrequent. Anything that + is going to push that many values should check. + * optimized setup_new_frame(), check_for_destr() + * removed a memory leak in unique_array() + * added a flag to regexp() to get line number / index info + * added a reg_assoc() efun + * introduced an error callback mechanism (used to solve the + unique_array leak) + *** Following since v20.25a3 *** + * changed to use only one unsigned short local in eval_instruction + * fixed crasher in global initialization + * optimized copy_variables() + * fixed error message for illegal type array indexing of arrays + * fixed a crasher in while_dec + * added code generation for do-while loops + * fixed a memory munger in unique_array + * added a prototype for drand48 which otherwise causes random() + to behave inappropriately for AIX + * fixed a crasher in call_out_info + * optimized efun calling by not passing number of args or + instruction code in eval_instruction(). + * various optimizations to add_action(), all_inventory(), + allocate_mapping(), break_string(), call_other(), capitalize(), + children(), clear_bit(), clonep(), commands(), cp(), crc32(), + creator(), ctime(), deep_inherit_list(), set_debug_level(), + deep_inventory(), destruct(), dumpallobj(), each(), errorp(), + environment(), exec(), explode(), file_name(), file_size(), + find_call_out(), find_living(), find_object(), find_player(), + function_exists(), function_profile(), get_char(), get_dir(), + implode(), in_edit(), in_input(), inherits(), inherit_list(), + input_to(), interactive(), intp(), functionp(), keys(), link(), + lower_case(), member_array(), mkdir(), move_object(), + new(), notify_fail(), nullp(), objectp(), opcprof(), + previous_object(), process_string(), process_value(), + query_host_name(), query_idle(), query_ip_name(), query_privs(), + query_snooping(), query_snoop(), remove_action(), + remove_call_out(), rename(), replace_string(), resolve(), + restore_object(), rm(), rmdir(), restore_variable(), + save_object(), set_bit(), set_heart_beat(), query_heart_beat(), + set_privs(), shadow(), shutdown(), snoop(), sprintf(), stat(), + strsrch(), strcmp(), stringp(), bufferp(), tail(), tell_object(), + tell_room(), test_bit(), this_player(), to_float(), to_int(), + typeof(), undefinedp(), userp(), wizardp(), virtualp(), write(), + write_bytes(), write_buffer(), write_file(), memory_info(), + reload_object(), query_shadowing(), set_reset(), floatp(), + first_inventory(), next_inventory(), crypt(), localtime() + * optimized all socket and math efuns + * optimized uid efuns, domain_stats(), author_stats() + * optimized the freeing of arguments in the matrix efuns + * optimized refs(), trace(), traceprefix(), evaluate() + * optimized next_living(), cat(), log_file() (in packages/compat.c) + * Fixed a crasher in type_name + * Fixed a typo in find_or_add_perm_ident in lex.c which causes + some bogus "Unknown efun : ... " errors + * Fixed possible crashers in clear_bit and test_bit when the 2nd + argument passed is negative + * Fixed a possible crasher in member_array for searching in strings + when the starting index given as 3rd arg is too large + * Fixed a possible crasher (typo?) in socket_acquire + * removed first_inventory and next_inventory from packages/compat.c + * remove extra stack for error callbacks, and use the interpreter + stack instead. This slows down freeing of svalues somewhat, but + unfortunately is the best way I can think of to allow catching of + errors from unique_array for e.g. without a memory leak. + * no longer do clear_state() if a master apply fails, but rather + recover the stack conditions before the apply. This fixes some + crashers if for e.g. master::valid_override has an error. + * simul efun is updatable again + *** Since v20.25a6 *** + * Fixed crashers in previous_object(-1), query_ip_name(), + query_host_name() + * More optimizations to read_file() + * Optimized match_path(), -= for arrays + * Fixed bugs in subtract_array(), alist_sort() + * Fixed a memory leak in intersect_array() + * Fixed a nasty crasher in scratchpad.c dealing with long strings + * Minor scratchpad optimizations + * Small optimization to simul_efun calling and call_all_other() + * Optimized void_assign in interpret.c + * Fixed compilation type checking for: assignments, &, ==, !=, >, + <, >=, <=, +, - (define OLD_TYPE_BEHAVIOR to not check types for + >, <, >=, <=, ==, != and +) + * Optimized compilation type checking for: assignments, ?:, |, ^, + <<, >>, %, -, *, /, ++x, --x, ~, -x, x++, x--, a[b..c], + a[b] + * The compiler now generates a warning instead of an error + if in a ? b : c, the types of b and c do not match + * indexing of sscanf(..), parse_command(..) , time_expression(..), + real or integer constants are no longer syntactically valid at + the parser level + * Compactified grammar a bit by grouping <, >, <= and >= under + the same L_ORDER token + * Run time defines using the -D flag are now added as + permanent defines for speed + * Fixed a possible crasher in scratchpad when it is almost (or + completely) used up in scratch_copy_string + * Fixed a crasher when string literals of "literal length" (\n + counted as 2 for e.g.) greater than 1016 are used + * Fixed crashers when errors are reported for unidentified + variables or illegal use of private variables when the + variable names have length greater than about 236 + * Rewrote the lexer to read chunks from the current file at + a time, which allows optimization of lexical parsing + * Implement linked buffers in the lexer to allow for larger + add_input such as those due to macro expansions + * Disallowed newlines right after a # symbol and + before a preprocessor directive + * Added #pragma show_error_context to show approximately + where an error occurs before/around in a line + * Corrected line numbers when literal strings with newlines + not directly after a \ are used + * Optimized the generation of string literals by copying to + the scratchpad directly if possible + * Made literal strings error only when real length is > 1023 + * Optimized the check for global include files in lex.c + * Added a missing '{' to f_copy in packages/contrib.c (reported + by Artagel) + * don't define MAXSHORT in stralloc.c if it's already defined in + math.h (problem reported by Artagel on a NeXT) + * Added INLINE to some prototypes in interpret.h + * Changed the interpretation of the 3rd arg in regexp, if it has + bit 1 set, then only non-matches are returned. If bit 0 is + set, indexes to matches/non-matches are returned as well. + * Updated doc for regexp and added doc for reg_assoc + * crasher in long error messages + --- Robocoder: + * revamped malloc package and wrapper selection to centralize it + all in options.h; added malloc.h and plainwrapper.c; changed + config.h, options.h, make_malloc.c, debugmalloc.c, wrappedmalloc.c + and Makefile + * smalloc.c: removed small bit of text left over from cutting and + pasting from bsdmalloc.c; renamed functions; removed SBRK_OK + requirement...so it'll fall back onto system malloc; + (Note: apparently there is a small leak in accounting stats) + (Beek: I believe it's in restore_array, haven't had time to + check) + * bsdmalloc.c: renamed func names to avoid conflict with system + malloc packages; (Note: even though it still only supports + sbrk()) + * Makefile: renamed references to config.h to options.h instead + (since config.h is static) (Note: out of sync with GNUmakefile) + *** Since v20.25a5 *** + * Corrected some bad_arg calls in packages/matrix.c and + packages/compat.c + +Tue Jan 3 10:19:00 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v20.24 + * various Amiga and Solaris tweaks for cleaner compiles + * compiler.c: added Alpha/OSF patch to clean_parser() to properly + handle 64 bit pointers to strings -- crasher reported by Dana + * socket_efuns.c: changed send(blah, 0) to write(blah) ... fixes + socket_write() hang reported by Dm for SunOS5/Solaris 486 + * removed lock_expressions and all related things because it + is no longer needed + * fixed make_func.y to properly protect backslahes in defines + in options.h + * second arg to dump_prog: now a set of flags; 1 = do disassembly; + 2 = dump line number info + * changed code generation to occur at the code block level instead + of the expression level; rewrote switch and loop code generation + to work with this + * macro-ized compile node creation (for speed), removed compile + node flags + * added a warning for inheriting the same function from two + branches; should be fixed to not give an error if it is + overloaded later ... + * fixed a few prototypes for OS/2 + * fixed several instances in the OS/2 code which used the old + interactive flags, instead of iflags + * rewrote line number tracking; the new way handles include files + using a more compact format, and never messes up even if the + mapping lines -> program bytes is not monotonic (i.e. order + preserving). Fixed line number bugs in things like: + for ( ... ; error ; ... ) { ... several lines ... } + * optimized the memory leak fix from v20.23 + * removed references to efuns.h from the Makefile + * Updated Credits.MudOS; added Symmetry + * vastly reorganized the .h files, made compatibility checks more + consistent. + * redesigned/optimized the identifier hash table + +Mon Dec 5 12:14:46 EST 1994 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v20.23 + * __DIR__ now has a leading slash; "/u/b/beek/", not "u/b/beek" + * removed all LPC_OPTIMIZE_LOOPS ifdefs + * fixed a ref count bug in array + ({ }) + * comm.c: fixed so "address server ip" in config file can be + in dotted decimal (quad) form + * fixed sprintf("%n.ndfoo", whatever) to not truncate after + the number + * fixed binaries to only add the correct functions to the + function tree + * resync'd "clean" and "neat" rules in makefiles + * main.c: #undef'd write macro for Amiga SAS/C (see amiga/socket.h) + * file.c: removed a useless #undef for Amiga SAS/C + * added a few sanity checks to swap() to make it harder to crash + * various compilation fixes for AUX from Magician + * fixed an incorrect DEBUG check in scratch_join + * fixed a crasher for unterminated string constants + * added malloc.c to the 'make clean' list + * Added Symmetry's fix for parse_command, where parsing + "all of my X" could hang the driver + * SMakefile, make_func.y: fixed for Amiga + * icode.c: removed i_generate_continues() as it was copied and + renamed to i_update_continues() + * generate.c: added missing #include to clear up warnings about + missing prototypes + * lex: fixed memory leak in free_defines; removed some unused + prototypes and variable + * added push_funp() back in, since query_notify_fail() needs it + * prototyped scratch_large_alloc() to avoid warnings + * added #ifdef's around to avoid redefinition errors + * fixed the LIVING_HASH_SIZE to be a power of 2 + * modified scratchpad.c to correctly mark the start of the + scratchpad + * fixed the definition of HDR_SIZE (crasher fix on large blocks) + * added some more DEBUG checks to scratchpad.c to ensure it + doesn't break + * added some casts to fix unsigned char */char * problems + * fixed two crashers in scratch_realloc() on large blocks + * fixed scratch_join to leave the resulting string in a consistent + state, else joining 3 or more strings will corrupt them + * commented the authors of the contrib efuns + * added Gudu@VR's copy(), functions(), and map_string() efuns + as contrib efuns; anyone who uses %^FOO%^ colors should look + at map_string() ... + +Mon Nov 21 13:51:25 EST 1994 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v20.22 + --- Beek section + * COMPAT_BUSTER: The environment_destructing() master apply has + been removed. move_or_destruct() is now called in all objects + in the inventory of a destructed object, regardless of whether + the object being destructed has an environment. This + consolidates the behavior of the old move() apply and + the destruct_env_of/environment_destructing() apply. + * Fixed a bunch of cases where non-scratchpad strings were + misrepresented as scratchpad strings (possible crashers?) + * Rewrote scratchpad.c since it was accidentally based on FIFO + and not LIFO order; tests show the correct implementation + of the optimization speeds up compiling by something like 30% + * fixed @BLOCK blocks to work correctly again + * inlined string(), number(), and real() in lex.c + number() and real() were pointlessly short; string() is mostly + in scratch_copy_string now, as it's optimized to copy to the + scratchpad. + * added a check to make sure the LIVING_HASH_SIZE is an even power + of 2; other hash tables are safe b/c we don't actually use the + numbers from the config file (!), we get them from options.h + instead. + * fixed the int x = destruct(this_object()); crasher. I'd love to + see the code that found it if Drevreck really ran into it ... :) + --- Symmetry section + * crasher/memory munger fix in switch() + * fixed and optimized the subtraction case in interpret.c + * crasher/memory munger fix in add_define + * crasher fix in free_unused_identifiers + --- Robocoder section + * updated Smakefile, file.c and amiga/ support directory from + adr32 hosts/amiga dir support by Lars Duening + * make_func.y: creates packages/Smakefile; added this file to the + "neat" cleanup in Makefile and GNUmakefile + * cleaned up a bunch of files to avoid/suppress various warnings + * func_spec.c: changed comments around a few #include to + preprocessor conditionals + * lex.c fixed a possible problem with using an uninitialized + auto variable in skip_comment() + +Sun Nov 20 12:56:33 EST 1994 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v20.21 + * fixed some serious bugs in restore_object(foo, 1); + * fixed a crasher in the saving of negative integers + * fixed call_outs so that they can be static again + * changed a bunch of !c to c == '\0'; evidentally some compilers + are that stupid... + * fixed a couple of problems with the static'ing of duplicate + variable names, also improved the handling of private variables + slightly. + * fixed a crasher in the copying of large (>204 entry) function + tables + +Wed Nov 15 12:04:11 EST 1994 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v20.20 + * changed all MALLOC() calls to DMALLOC() calls + * implemented the grammar for anonymous functions and expression + by value in functionals + * Added some debugging code to clear_state() + * fixed a bug that caused the size of mappings not to be set + right, which causes memory to be corrupted when keys() is called + on the mapping. Fixes several rather nasty and delayed crashes + in array -= and elsewhere. + * fixed a bug that caused the number of references in the + identifier hash table to be too high when the simul_efun object + was updated; this could cause a crash if the first simul was + deleted. + * updated the following docs: + __INIT + environment_destructing + implode + notify_fail + origin + restore_object + restore_variable + save_variable + telnet_suboption + terminal_type + * removed an unused variable from copy_functions + * converted #define's to use whashstr instead of hashstr (it's + faster) + * converted the living hash table to use whashstr + * added a warning to options.h that certain mudlibs require + certain options + * converted the object hash table to use whashstr + * COMPAT_BUSTER: if you redefine a variable, the old copy becomes + static. previously, the first one was the one that was saved. + * COMPAT_BUSTER: if a function is inherited from two different + objects, the second one is used. Previously, the first one + was. + +Mon Nov 14 12:56:40 EST 1994 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v20.19 + * fixed a bug in the real/real case of /=; fix from + Aleas@Nightmare + * new apply: + void terminal_type(string term) + called in the object returned by connect() in the master object. + 'term' is the terminal type of the user, as reported by terminal + negotiation; e.g. "xterm" + * the telnet GA characters are only printed if the connection + responds to terminal negotiation + * fixed a crasher in implode() + * include file names are made shared strings early, instead of + malloc'ing a copy and making a shared string later + * fixed a bug in the calling of ::#global_init# functions + * fixed a crasher in object::foo() compilation + * function table aliases are now replaced after compiling; fixes + the 'function not compiled with type testing' bug and two + crashers + * fixed a problem with nomask prototypes causing odd errors + * fixed it so that if the function actually isn't compiled with + type testing, you only get 1 error message, not two + * fixed a typo that caused compilation to fail with + LOCALS_IN_TRACEBACK on + * fixed a memory leak in restoring a value with duplicate keys + * fixed several crashers in attempting to restore illegal strings + * COMPAT_BUSTER: restore_object now leaves the affected variable + untouched when in finds a syntax error in a nested structure, + then gives an error. + previous behavior was to leave the value partly restored, + and to silently move on. + * fixed a typo in mudlib_stats.c that caused compilation to fail + with NO_MUDLIB_STATS off + * fixed a line in scratchpad.c that caused a compilation error + for some compilers + * optimized variable name lookup for restore_object a lot. Now + uses shared string comparisions, and is optimized for the + case where the variables are in the order they're defined + in the object (i.e. guesses that the save file was made + by save_object) + +Thu Nov 10 09:08:26 EST 1994 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v20.18 + * removed a number of unused variables + * added prototypes for some functions that were missing them + * fixed alloc_local_name to actually return the name it allocated + * fixed a crasher in check_valid_socket call from socket_create() + * Rewrote the handling of inheritance and function tables; + only useful functions are put into the function trees, making + function searches even faster. + * The above changes remove the nomask inheritance problem + mentioned in the Bugs file + * removed the entry in the Bugs file for f=(: ob, ({ func, a, b }) :) + since NEW_FUNCTIONS fixes this already + * Fixed a crasher in destruct(); if the object was dested again as + a result of moving it's inventory out of itself the mud would + crash. (old bug from Bugs file of 19.3) + * changed the move() master apply since many mudlibs use move() + and it's a bad name anyway; now named "environment_destructing" + * fixed a crasher for when tell_object() was passed a string + larger than LARGEST_PRINTABLE_STRING; as a result successfully + sent a 500k message to an interactive user. + * Added Nightmare LPmud to the Credits file + * COMPAT_BUSTER: the driver no longer uses __INIT for global + initializations, so anything that uses call_other(ob, "__INIT") + or ::__INIT() won't work any more. The new function is: + private void #global_init#, so it can't be called explicitly + or played with. + * origin() will now be right in all cases; functions called from + efuns (sort_array(), etc) get ORIGIN_EFUN. + * added a case for function pointers in sameval(), which should + make function pointers act sanely as mapping keys. + * optimized explode(); COMPAT_BUSTER: + if the first element of the array is not a string, a leading + delimeter is not printed, making it more consistent since + extra delimeters are not added internally, e.g. + old: implode( ({ 0, "a", "b", 5, "c" }), "," ) -> ",a,b,c" + new: implode( ({ 0, "a", "b", 5, "c" }), "," ) -> "a,b,c" + * All driver applies can now be static or private. + * previous_object is now zero in logon(), call outs, input_to + functions, socket and resolve callbacks + * removed the need for '::' checks in call_other (optimization) + * fixed a crasher in (: global_var :) with NEW_FUNCTIONS on + * the heart_beat function is found via the function search tables + in epilog, instead of looking for it as we go + * fixed a crasher for reporting runtime errors in the last line + of a file + * removed the flags field of variables, saving 2 bytes/global var + per program + * updated the disassembler with the new function flags + * fixed some prototypes which didn't use Pn() in compiler_shared.c + * changed the name of ORIGIN_BACKEND to ORIGIN_DRIVER; + /include/origin.h keeps both names for compat + * Fixed the old 'Warning: redefinition of #define ...' error that + was sent to users to actually be a real warning. + * Removed almost all need for calling malloc() during compilation; + use various optimized allocators instead + * Added a identifier hash table for quicker lookup of identifiers + and keywords + * fixed restore_object to report which variable had a problem + * fixed a crasher in string constants greater than 1k in size + * added the start of a set_prompt() efun; not completed + +Tue Nov 1 23:59:06 EST 1994 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v20.17 + * fixed a typo in compiler.pre that caused yacc to fail with + NEW_FUNCTIONS defined + * fixed a problem with an IF_DEBUG define in apply_low and sapply that + prevented compilation with DEBUG off + * moved the TRACE defines to interpret.h to allow the driver to + with TRACE_CODE on again. + * fixed a crasher based on incorrect code generation for + conditional expressions whose value was unused. + * Fixed a crasher in errors going through the error handler + when current object was zero (This is possible for some internal + errors like "No action linked to verb") + * adding ({}) now copies the array again if it is referenced more + than once, fixes COMPAT_BUSTER accidentally introduced in + v20.2 + * Small optimization to sapply() + * added some debugging code to get better error messages on double + frees + * added push_refed_vector() and friends, allowing referenced + arrays to be pushed onto the stack without having to fudge + the ref count afterwards. + * added a check_valid_socket() routine, which eliminates a large + ammount of code duplication for calling valid_socket() + * added a improved system for allocation of temporaries during + compilation, with several advantages: (1) it avoids calling + malloc(), (2) it doesn't leak memory on syntax errors + * added an identifier hash table, speeding up the lookup of + identifiers during compilation + * benchmarks show compilation is approx 15% faster + * changed pop_n_elems(2) -> pop_2_elems(), etc + * fixed a bug that caused crashes when optimizing + * fixed a typo, allowing LOCALS_IN_TRACEBACK && + !ARGUMENTS_IN_TRACEBACK to compile + * moved the TRACE defines to interpret.h so eoperators.c can find + them + * added a check for a maximum include file depth, for systems that + don't run out of file descriptors + * fixed a bug that gave warnings for '\'' + * defines now allocate 1 chunk, not 3 + * fixed a use of FREE in make_func.y; make_func should compile + with wrappedmalloc or mallocdebug now + * fixed a problem with saving/restoring integers within a factor + of 10 of MAXINT + * fixed saving and restoring of real variables + * fixed a bug that caused create() to sometimes not get called + with NO_UIDS defined + +Mon Oct 31 15:24:20 EST 1994 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v20.16 + * changed a typo in c_filter_array in array.c + * added back in a check for maximum array size that had gotten + removed from array addition + * removed some old debuging code in ccode.c + * added a few new macros: + IF_DEBUG(x) evaluates to x only if DEBUG is on + DEBUG_CHECK(x,y) issues fatal(y) if x is true + this simplifies much of the debugging code since #ifdef + .. #endif isn't required + * converted most of the debugging code to use the new macros + * removed a reference to comp_stackp in ccode.c that caused + linking problems with LPC_TO_C on + * fixed the code for preventing catch()ing of too deep recursion + and eval_cost errors. Several wierd design flaws caused the old + code to work in many but not all situations. Code is now + airtight. + (also resulted in a small optimization to function calls) + * fixed a typo in the attempt to call a simul_efun while loading + the simul_efun object error message + * added defines/functions call_program/call_absolute for running + code; with LPC_TO_C off they just call eval_instruction; with it + on they centralize the dispatch code. + * added an error for Function is no longer a simul_efun + * fixed a typo in the is_static fatal error message + * removed the DEBUG check around TRACE_CODE again + * removed an archaic prototype for comp_stackp in lint.h + * fixed a bug that added the line '#include ""' to files if the + global include file line was missing from the config file + * added several missing %ifdef and #ifdef NEW_FUNCTIONS lines + * fixed a crasher in previous_object(-1) + * fixed previous_object(-1) to return ({ }) instead of ({ 0 }) + when there is no previous_object(). + * Lots of work cleaning up LPC_TO_C code so bring it closer to + compiling again + +Tue Oct 17 22:59:30 EDT 1994 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v20.15 + * added some files that were missing from the Makefile + * fixed a typo in a comment in backend.c + * removed a line that caused crashes for Demon@TMI-2 (optimizer + bug in xlc? The change is essentially x &= ~2; x = 0; -> x = 0;) + * fixed some cases that can cause fatal errors if code get + generated for them (it shouldn't, but evidentally it is ...) + from Symmetry + * mapping and array constants are no longer marked as E_CONST + internally; check kind == F_AGGREGATE instead. + * prevent cascading errors in the case of an undefined var, also + give the undefined var message in more cases; from Symmetry + * fixed a typo in an error message for illegal index to a constant + mapping. + * fixed a crasher where the flags were set wrong for function + calls; from Symmetry + * changed the optimization of sizeof(constant mapping) slightly + * moved generate_source() to the correct spot in alphabetical + order + * fixed the tail() problem; from Symmetry + * optimize_expr() now walks the tree; still does nothing + * optimized generate_node() somewhat + * fixed a problem that causes crashes for optimizable loops + of size > 256 + * added Symmetry's fixes for functionals + * added a string addition optimization back in that got removed + some how + * added a missing break; for NEW_FUNCTIONS undefined; probably + the cause of Drevreck's crasher + * optimized and unspaghetified part of lex.c + * added a warning for unimplemented \x escapes + * added the HAS_STATUS_TYPES define to options.h + * removed unused variables from generate_lvalue_list, + assert_master_ob_loaded + +Wed Oct 12 01:56:14 EDT 1994 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v20.14 + * rewrote the compiler (!) to use parse trees; numerous + optimizations possible b/c of this; also greatly simplified + the fix for the lvalue lifetime bug, etc + * removed some code duplication in checking efuns + * removed F_JUMP; all branches are relative now (F_BBRANCH added) + * renamed a lot of stuff to be more informative: + F_GLOBAL, F_GLOBAL_LVALUE, F_LOCAL, F_LOCAL_LVALUE + instead of the previous inconsistent names + * only put () after the instruction name if it's an efun + in bad argument error messages + * F_LOOP_COND constant can now by F_BYTE etc and not just F_NUMBER + * added a string out of range debug message in F_STRING + * simplifications to the grammar: + * all types are now returned as L_BASIC_TYPE with semantic value + of the type ("object" is an exception b/c of object:: parsing) + * same with L_TYPE_MODIFIER + * same with L_ASSIGN + * new pragma: #pragma optimize + #pragma optimize - do default optimizations + #pragma optimize high - do all optimizations, and assume that + the declared types are correct + #pragma optimize all - all optimizations; currently the same as + high + * fixed a bug in printing out of floating point numbers with %0 + * fixed a crasher resulting from the simul_efun object swapping + out and leaving the simul_efun pointers dangling; the simul_efun + object no longer swaps. + * fixed the 'declare a temporary function to prevent tons of + errors' fix to not give redeclaration errors if the function + does show up later. + * fixed a crasher when an object loaded without a current program + and an error occured and the error handler tried to call the + master object. Caused crashes when the master object failed + to load off the boot. + * If your global include file doesn't have "'s around it, they are + added. + * Really fixed the crasher that was claimed fixed in v20.12 + (moving an interactive and then returning zero from a command) + evidentally dates back to 0.9.16.18 + * fixed a crasher when OPCPROF and TRACE_CODE or TRACE was defined; + this also makes OPCPROF functional again + * 'w' and 'W' with no argument now work in restricted ed mode; + this allows 'w', 'q' instead of 'x' to be used as well + * Fixed ed to print tabs correctly with line numbers on; + caused the indentor to appear broken + +Thu Oct 6 19:22:48 EDT 1994 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v20.13 + * removed an unnecessary clear_notify() call in notify_fail() + * moved f_simul_efun to eoperators.c since it is an eop + * eoperators are now void f_eop(void) and not void f_eop(int, int); + the first argument was always -1 and the second was always the + same ... + * fixed eoperators.h, which obviously hadn't been touched in + years ... + * fixed the write_bytes error message; the two arguments were + backwards: "Wrong permissions for opening file /foo for + File does not exist. (append)" + * Fixed a bug that caused write_bytes() to fail if the file didn't + exist. + * slight optimization to <, >, <=, >= + * fixed the DEBUG checks to check the stack after evaluation of + eoperators again + * fixed some code that could in very rare cases miscalculate the + number of svalues to pop when an error occured + * removed F_DUP + * removed the type 'status' which was identical to 'int'; define + HAS_STATUS_TYPE in options.h to get it back + * reorganized options.h a bit; put the compatibility defines + together up top, and noted what driver version each corresponds + to + * Minor editing of some old changelogs + * added query_notify_fail() as a contrib efun + * added Symmetry's fix for the restore_object() memory leak + * packed several interactive flags into one int saving about + 1K memory + * only include trace_level and trace_prefix in the interactive + struct if TRACE is defined + * notify_fail() no longer implictly calls process_string(); do so + explicitly if you want to use it + * added notify_fail(function); the function is called when the + message is printed. If a string is returned, it is printed + (tell_object or write can be used too; write() will go to the + person the message would have gone to if it were a string) + +Tue Sep 27 21:21:47 EDT 1994 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v20.12 + * fixed a definition of function_context in compiler_shared.c + * improved the error message for bad argument 3 to message() + * improved the error message for bad argument 1 to memory_info() + * improved the error message for bad argument 1 to reload_object() + * improved the error message for bad argument 2 to tell_room() + * improved the error message for bad argument 1 to first_inventory() + * fixed a bug in restore_variable + * removed some code duplication in the routines for building + mappings (used by the error handler) + * fixed some problems where 'signed' was used instead of 'SIGNED'; + pre-ANSI compilers can't understand it + * fixed a bug that caused write_bytes() to fail to write to the + correct position on some systems + * fixed a bug that gave the wrong line numbers in tracebacks in + the error mapping + * removed a prototype of mapping_too_large() since it's a macro + now + * fixed a bug that caused .o files to occasionally be corrupted + * added the file name to some error messages (Illegal path name, + Error in loading object, etc) + * Fixed a bug that caused disable_commands() to remove the object + from it's environment + * fixed a crasher when an object moves itself as the result of a + command then returns zero + * added a debugging error message that prints the file name and + line if a crash occurs during compilation + * small optimization to ref_string + * fixed a type bug involving the use of casts in initializers, for + example: int i = sizeof( (string *)foo->bar() ) used to give + type mismatch (string vs int) while initializing i. + * fixed a crasher involving using an efun name as an undefined + variable + * debug_info(ob, 2) now prints out a brief summary of the global + variables in an object + +Sun Sep 25 16:04:31 EDT 1994 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v20.11 + * Fixed a compile time line number bug that crept in when runtime + line numbers in include files was added. + * Fixed a problem where default argument were not getting put into + efun pointers + * fixed a bunch of definitions in object.c that didn't use Pn() + * added string save_variable( mixed ) and mixed + restore_variable( string ) for converting variables to and + from save_object's form + * added a missing #ifndef NO_UIDS in set_privs_for_object() + * Changed 'Error in look_for_objects_to_swap' to + 'Error in clean_up() or reset()' + * Fixed a typo in efuns_main.c (wrong number of args to + load_object()) + * fixed an incorrect prototype of previous_object() in func_spec.c + * significantly optimized eval_instruction; made the code flow + clearer and easier to read + * Fixed a bug that could leave constant strings dangling on when + objects were destructed + * Added the start of a system to automatically put %line in the + grammar; not functional yet + * Added a error message in make_func if you have more than 510 + opcodes (which implies 430 efuns or so ...) + * Fixed a crasher due to root_author and backbone_domain being + based on uids even when uids don't exists; with + #undef NO_MUDLIB_STATS and #define NO_UIDS the backbone + domain is now hard coded to "BACKBONE" and the root_author + is "NONAME". Also, the root_author was changed to master_author + throughout the source as this is more accurate. + * AUTO_SETEUID now works for the simul_efun object too + * Added debugging code for easier debugging of future string + reference problems + * The create() function doesn't need a type even if strict_types + is on this follows common LPC usage and C++ syntax; create() + is implicitly void unless defined otherwise + +Sat Sep 24 16:51:06 EDT 1994 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v20.10 + * Updated the following docs: + doc/concepts/message_doc + doc/lpc/types/function + doc/efuns/core/map.3 + doc/efuns/core/evaluate.3 + doc/efuns/communication/message.3 + doc/efuns/properties/add_action.3 + doc/efuns/system/eval_cost.3 + doc/efuns/system/reset_eval_cost.3 + doc/efuns/system/shadow.3 + doc/efuns/system/max_eval_cost.3 + doc/efuns/mappings/map_mapping.3 + doc/efuns/filesystem/write_file.3 + doc/efuns/objects/objects.3 + doc/efuns/objects/load_object.3 + doc/efuns/state/all_previous_objects.3 + doc/efuns/types/sizeof.3 + doc/efuns/types/typeof.3 + doc/efuns/types/pointerp.3 + doc/efuns/types/arrayp.3 + doc/efuns/interactive/commands.3 + doc/efuns/interactive/in_edit.3 + doc/efuns/interactive/snoop.3 + doc/efuns/arrays/map_array.3 + doc/efuns/arrays/filter_array.3 + doc/efuns/arrays/sort_array.3 + doc/efuns/arrays/member_array.3 + doc/applies/error_handler.4 + doc/defines/__FILE__ + doc/defines/README + * Fixed another two "Anomaly" messages + * added disassembler support for function pointers + * fixed a problem that caused recursion if log_error used a + simul_efun to try to report an error in the simul_efun object + * fixed a crasher (dangling pointer) in simul_efun object updating + after it had failed to load + * Fixed a problem with runtime line numbers; they should be right + again now + * made nesting of (: $var :) functionals work correctly + * fixed a problem with using local variables in functionals + * fixed some add_defines which should have been add_predefines + (snuck in via the v20 source) + * move the -y flag to allow YYDEBUG to be used on the master and + simul_efun objects + * variable names are not necessary for prototypes; i.e. + int stupid_function(int, string); + is legal + * cleaned of the handling of argument names in the grammar + * fixed a mistake in the "Undefined function foo" error message + * prototyped yywarn() + * define a varargs function when an undefined function is + encountered to reduce the number of errors produced + +Wed Sep 21 08:46:51 EDT 1994 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v20.9 + * added Thorin@TMI-2's patches to compile on SCO Unix + * fixed problems (on some systems) with *= and /= based on + undefined behavior. + * added changes from 0.9.19.26 -> v20 + * fixed a few "<< =" 's that survived since indent screwed them + up, spotted by Dana@TMI-2 + * remove some unused code in some of the function pointer + constructors + * Fixed some function pointers to make errors before the function + pointer was called to not show the trace as in the function + * Fixed a few bugs in restore_object(); should work correctly now + * Fixed a counting problem with array statistics + * Fixed a bug that reported ridiculous sizes for function pointers + in memory_info() - Noticed by Meph@TMI-2 + * Added missing support for sprintf("%O", ...) when passed an + simul_efun pointer + * Reorganized the tokens and made sure every expression returns + a start address (necessary for expression function pointers) + * "Extra ';'. Ignored." is now a warning instead of a fatal + error. + * Simplified the grammar by condensing two comma_expr cases + * COMPAT BUSTER: support for this_object function pointers + ( i.e. (: "foo" :) ) has been removed with NEW_FUNCTIONS + defined. Use (: foo :) instead. (: "foo" :) is now a + function which returns "foo" (see below). + * Added support for the second to last version of function + pointers; "(: expression :)". Arguments to the function + are represented as $1, $2, $3 ... + For example: + sort_array(arr, (: sizeof($1) < sizeof($2) :) ); + +Mon Sep 19 18:28:08 EDT 1994 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v20.8 + * snoop() can now be called when this_player() is zero; the + restriction dated back to when snoop() used this_player() + * removed two extraneous calls to store_line_number_info() that + were causing runtime line numbers to be off; they're now off + by exactly 1 I believe; still looking into it. + * Several bugfixes to restore/save_object; they should work + correctly again + * fixed a few potential crashers in parse_command + * fixed a problem which caused extraneous printing of "Error in + error handler" when no error handler was in use + * cleared the error state after a error in error handler; + previously the error handler became non-functional + * added a call to end_new_file() when epilog() returns because + of errors or inheritance; fixes a bug which would erroneously + report "missing #endif" + +Mon Sep 19 15:25:34 EDT 1994 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v20.7 + * removed outdated rules for compiler.y and lpc_compiler.y in the + GNUmakefile + * function arguments specified when a function pointer is made can + be used with arguments specified when it is called, and the + order is what you would expect, i.e. + function f = (: foo, a, b :); + (*f)(c); + is the same as foo(a,b,c); + * classes for the message() efun may be of any type, not only a + string (idea from Misery@TMI-2) + * used Px() defines for function definitions where they weren't + being used (reported by Drevreck@TMI-2) + * moved contrib.c and contrib.spec to the packages/ directory + * moved a bunch of ed defines to a new file (ed.h) + * in_edit() now returns the file that is being edited + (idea from someone whose post has scrolled of the board) + * print out compile errors to stderr if master::log_error doesn't + exist + * fixed a problem with the definition of unique_array that + prevented function pointers from working with it + * evaluating a function pointer created by an object which has + since been destructed is now an error + * fixed a bug that caused mappings to crash + * added #ifdef NEW_FUNCTIONS around a reference to fake_prog + * fixed a crasher in get_line_number_info + * traces no longer go to stdout, only the debug.log + * fixed some incorrect prototypes (add_define, etc) + * fixed a few bugs in linenumbers, some involving the global + include file + * added a warning for unknown pragmas + * fixed a crasher involving the simul_efun not loading at startup + * added a better message than 'Anomaly in the fabric of world + space.' + * fixed a crasher with MUDLIB_ERROR_HANDLER and LOG_CATCHES + * don't try to print a trace if the call to the mudlib error + handler fails, it will have been destroyed + * gzip'ed two of the old changelogs + * check arguments to efun function pointers + +Sun Sep 18 07:22:17 EDT 1994 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v20.6 + * optimized commands() + * fixed a typo in commands() + * optimized check_for_destr() + * cleaned up the Bugs file + * updated the GNUmakefile on the make_func changes from v20.5 + * added evaluate(f, ...) which is the same as (* f)(...) + * evaluate(f, ...) now returns f if f is not a function + * added global include file option based on diffs from + Marius@Savage.Garden + * rewrote smart_log + * added a max_eval_cost() efun + * runtime errors now report the correct file and line for errors, + even if it was in a #include'd file + * pragmas now use bits; change from Marius@Savage.Garden + * predefined symbols (like HAS_SOCKETS) are added only once + instead of whenever a new file is started + * Added support for compiler warnings; enabled with #pragma warnings + * added a warning for '/*' inside of a comment + * added a warning for unused conditional expressions, as in: + if (x == 0) x == 1; + * any define in options.h is now sent to the mudlib surrounded by + '__' i.e. if LOG_CATCHES is defined in options.h, then + __LOG_CATCHES__ will be defined in all LPC objects. This + adds a number of useful new predefines like __NEW_FUNCTIONS__ + * added a __FILE__ define + * added support to turn some pragmas (warnings for example) on + by default in options.h + * fixed an instance of add_map_stats with NO_MUDLIB_STATS defined + in object.c + * removed light and object info from the object struct if they + aren't in use + * fixed a compilation warning for NeXT + * made scan_config_line iterative instead of recursive + * moved start_new_file() into compile_file + * the mudlib error handler now gets a 'file' field in addition to + the 'line' field in tracebacks + * improved the bad arg x to efun ... error message + * fixed a bug that caused type errors on simul efuns which had + type modifiers (varargs string vs string) + * changed testsuite/clone/user.c's commandHook to use load_object + + * More diffs from Symmetry@TMI-2: + * filter_array() can now pass multiple arguments to the function, + i.e. filter_array(arr, fun, a1, a2, a3, ...) + same with map() + * Support for @foo and @@foo blocks in the indentor + +Mon Sep 12 07:53:11 EDT 1994 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v20.5 + * Fixed the generation of packages/GNUmakefile and dependencies in + the GNUmakefile + * the array from commands() now includes the function as well as + the object; from Decker@TMI-2 + * optimized load_mapping_from_aggregate + * write_file now takes a second arg, 1 means overwrite instead of + append. Idea from Decker@TMI-2 + * Improved a lot of compile time error messages + * Added type checking to save_object() + * Fixed a crasher in updating of the simul_efun object on + some systems + * New efuns: + . load_object(string) - finds an object, loading it if necessary + . find_object(string, 1) - see load_object + - idea from Decker@TMI-2 + . member_array(int, string) - find a character in a string + . third argument to member_array is now the start index; + support for the old flag removed + . sizeof(string) == strlen(string), and optimized sizeof + . this_interactive() == this_player(1) + . all_previous_objects() == previous_object(-1) + . arrayp(mixed) == pointerp(mixed) + - idea from Cygnus@TMI-2 + . shadow(ob) == shadow(ob, 1) + . reset_eval_cost() == set_eval_limit(0); + . eval_cost() == set_eval_limit(-1); + + * Changes from Symmetry@TMI-2: + * compiler.y and lpc_compiler.y are generated by make_func now + instead of via cat. + * Fixed the function pointer grammar to compile on bison + * optimized use of string function names in map_array etc. + (use them directly instead of simulating them with function pointers) + * Fixed a really nasty bug in compatible_types() which effectively + disabled compile time type checking. OLD_TYPE_BEHAVIOR is + offered for those who would rather have their buggy code + compile instead of fixing it. + * Optimized and improved type checking in many of the eoperators + * Optimized ident() in lex.c + * optimized mapping operations + * optimized save/restore_object + +Fri Sep 9 02:14:18 EDT 1994 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v20.4 + * Added tracebacks for errors in error handlers + * Changed strdup() to string_copy() where it has snuck in + * Added a Makefile option for bsdcc + * Added support for efun packages + . package 'foo' has the functions specified by packages/foo.spec + and source in packages/foo.c; it is enabled with a + #include "packages/foo.spec" in func_spec + . Added a contrib package, currently empty (Send in those efuns!) + . moved efuns which deal with driver internals to 'develop' + package + . moved uid efuns to 'uid' package + . moved domain and author stats to 'mudlib_stats' package + . moved socket efuns to the 'socket' package + . moved math efuns to the 'math' package + . moved matrix efuns to the 'matrix' package + * optimized eval_instruction() + * Added the typeof() efun back in + * added /include/type.h for return values of typeof() + * Moved a prototype AIX complained about + * Code for 2 byte efuns is not compiled in if there are less than + 256 efuns, offering extra speed to those who trim their efun + list below 256 opcodes + * Improved handling of efun name aliases; fixed several bugs in + map(), map_array(), map_mapping() + * ({ string, string })->func() is now legal; previously only + objects could be used - idea from Inspiral@TMI-2 + +Mon Aug 29 17:47:41 EDT 1994 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v20.3 + * fixed virtual objects + * added function pointer support for: + filter_array( mixed *, function, void | mixed ) + unique_array( mixed *, function, void | mixed ) + map_array( mixed *, function, void | mixed ) + objects( function ) + sort_array( mixed *, function ) + * Made map_mapping work, as well as function pointer support for + it + * Added map(mapping | mixed *, ...) which is what map_mapping and + map_array are really aliases for + * slight change to sort_array: + sort_array(arr, 1) is now forward, and + sort_array(arr, -1) is reverse. + sort_array(arr, 0) is forward as well + * LPC_TO_C compiles again; compiler still needs some of the + function pointer code tho + * added new simul_efun format support to the disassembler + * Error message for illegal local variable number with DEBUG on + * Fixed a crasher for errors in function pointers + * Fixed a crasher involving updating of the master object, cleaned + up the master object handling even more + * "efun" and "asm" are legal argument names for functions + arguments again + * Fixed a 'should be a push!' crasher when an function name was used + as a variable but not defined as one + * Added changes from 0.9.19.26 + +Mon Aug 29 17:47:41 EDT 1994 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v20.2 + * Note: This version is also based on 0.9.19.25, not v20. + * split and reorganized the Changelogs. Old Changelogs are now in + ChangeLog.old/... + * finally remembered to remove the __builtin_valist from lint.h + * moved the defined_named typedef to exec.h so lint.h would be + happy + * Added a NO_UIDS option - Idea from Alexus@TMI-2 + btw, the old old USE_EUID which used to always be defined + on MudOS drivers works with this change; so you can use: + simul_efun: + getuid(ob) { + #ifdef USE_EUID + return efun::getuid(ob); + #else + return "NONE"; + #endif + } + * Fixed miscellaneous typos etc from the function pointer merge + * added 'make remake' == 'make neat; make all' + * added 'make neat', which removes object files but leaves + .orig, .rej, driver.old, addr_server etc alone + * moved the defined_name definition so lint.h will compile + * added support for an array as the second argument to add_action, + i.e: + add_action( "look", ({ "look", "l", "glance" }) ); + idea from Decker@TMI-2 + * fixed a bug that caused add_array to complain it was out of + memory when it really wasn't on some systems + * fixed a bug that caused the first argument of lfun pointers + to be ignored + * fixed a typo in the definition of get_simul_efuns + * fixed a crasher with LOG_CATCHES and MUDLIB_ERROR_HANDLER + * fixed a problem with write_prompt and process_input after + an error with LOG_CATCHES and MUDLIB_ERROR_HANDLER + * fixed some indented preprocessor defines from the patching + * Added a __MAX_USERS__ LPC define which has the value of + MAX_USERS in the driver + idea from Misery@TMI-2 + * changed the default MAX_USERS from 5 to 50 + * Changed handling of the master object: + - you should be able to to just about anything in your master + object now and it will still be updateable, even stuff like + efun::, even really nasty ideas like calling shadow() from + the master's create() or having + create() { destruct(this_object()); } won't crash the mud. + - Errors in master compilation are actually printed now, + instead of a cryptic message + - The mud WILL NOT go down if the master object stops working; + all file accesses etc will simply fail. When the master is + fixed the mud will resume normally. + * indentor fixes: + fixed // comments + removed quoted array, closure etc support + added function datatype support + +Mon Aug 29 17:47:41 EDT 1994 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v20.1 + * Note: This version is based on 0.9.19.25, not v20. + * Name change: The 0.9 part of the version number is being dropped. + * Large number of function pointer changes: + * A fake frame is inserted when function calls are evaluated now. + The practical outcome is that previous_object() will be the + object that created the function pointer, not the object that + used it. The object that used it is previous_object(2) + * efun, lfun, and simul_efun pointers are now available. + Examples: + function f = (: previous_object, -1 :); + + int foo() { } + ... + function f = (: foo :); + + * arguments can be passed either by including them in the + definition: + function f = (: write_file, "/log/fp", "evaluated.\n" :) + + or when evaluated: + function f = (: explode :); + result = (*f)("this is a test", " "); diff --git a/fluffos-2.23-ds03/ChangeLog.alpha b/fluffos-2.23-ds03/ChangeLog.alpha new file mode 100644 index 0000000..589ce6e --- /dev/null +++ b/fluffos-2.23-ds03/ChangeLog.alpha @@ -0,0 +1,5201 @@ +------------------------------------------------------------- +(v22.2a37 promoted to v22.2b1) + +Sat Jul 29 21:32:05 CDT 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.2a37 + * updated with respect to v22.1b32 + * fixed miscellaneous typos and compile errors in a36 + * moved most all add_action code into add_action.c + * corrected db_connect in PACKAGE_DB to take only four + arguments rather than five. + * strings in PACKAGE_DB are now malloced/counted rather + than shared [suggestion from Beek] + * fixed a memory overwrite crasher in handling prototypes + of inherited functions [reported by Zifnab, Loriel, + Mystic, and others. thanks to Javelin@VH for a test + case to reliable reproduce] + * Fix error messages generated when PACKAGE_UIDS is defined + and get_root_uid() or get_backbone_uid() either do not exist + in the master object or do not work. Error messages were + causing a crash [reported by Mystic] + +Fri Jul 7 21:16:16 CDT 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.2a36 + * updated with respect to v22.1b31 + * fixed process_input() so that the modified command is passed + on to parse_command() rather than the original unmodified + [reported by Beyond@LimaBean] + * added debug code for tracing object references and finding + destructed objects that never get freed. + * fix receive_snoop() to handle non-nul terminated buffers + passed -- use the len argument [reported by Passerby@IoT] + * prepend slashes to filenames for display in ed (f, w, x + commands) [reported by Avenger@AtP -- missed from v22.1b25] + * implemented rfc 1184 (telnet linemode option) to better + support running on port 23. the implementation is partial + at present, but sufficient to serve its purpose. + +Tue Jul 4 19:45:03 CDT 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.2a35 + * updated with respect to v22.1b30 + * fixed escape_command() so that ! command escaping + works again. + * if there's no master object present when attempting a + virtual object clone (shouldn't ever happen, but ...), + be sure to clean up the stack before returning failure + * removed recently added debug checks for destructed + objects pushed onto/assigned into the stack. + +Sun Jul 2 19:00:55 CDT 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.2a34 + * updated with respect to v22.1b29 + * fixed lower_case() and upper_case(), both broken in a32 by + locale changes + * updated PACKAGE_DB support to include MySQL support and + restructured to ease adding new database support [based on + patches from Andrew@Nanvaent] + * COMPAT BUSTER: When loading/cloning a virtual object, mudlib + stats, uid/euid and privs are now properly reset with the + newly assigned object name. + * compile_object() in master.c will now be passed a second + argument indicating whether the operation is a clone or not. + * If arguments are now passed to clone_object() for create() when + cloning a virtual object, the arguments will be aggregated and + passed on to compile_object() in master.c as the third arg. + The prototype for compile_object() is now as follows: + + varargs + object compile_object(string filename, int cloning, mixed args...); + * Don't bail out of edit_source if PACKAGE_DB is defined and it + can't find msql.h, mysql.h, libmsql.a, or libmysql.a. If they + can't be found, you'll have to hack the source for now. + +Sat Jul 1 13:18:19 CDT 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.2a33 + * don't save command_giver on the runtime stack. use a separate + stack instead. + * add missing add_ref in save_command_giver() to match the + free_object() in restore_command_giver() + +Tue Jun 20 18:41:51 CDT 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.2a32 + * updated with respect to v22.1b28 + * for the network_stats() contrib efun, return the external ports with + port number rather than index position in the internal port list + * restructured more code in comm.c for command handling. broke out + duplicated code into new functions and generally cleaned some stuff + up. This makes way for the next change: + * command_giver is now reference counted and properly restored on + error, etc. no more need for it to be reset to 0 in the backend. + * all objects now get the class definitions from the simul_efun object + if there are any, just as if they had inherited the simul_efun + object. This resolves problems with class related errors when the + simul_efun object is involved [reported by Pinkfish@Discworld] + +Sat Jun 17 12:15:08 CDT 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.2a31 + * updated with respect to v22.1b27 + * added extensive packet/volume statistic gathering to comm.c and + socket_efuns.c when the network_stats() contrib efun is compiled into + the driver [based on patches from Skullslayer@RoD] + * Patches from Turrican@Discworld: + . added an optional 3rd argument to socket_bind efun to specify the + address and port to bind to (in the same format as socket_connect) + . added an optional 2nd argument to socket_address efun to return the + socket's local address when specified as non-zero + +Thu Jun 15 17:11:07 CDT 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.2a30 + * NUL terminate user input buffer before passing it to handle_snoop(). + [reported by Passerby@IoT] + * correct handling of cr/lf when processing commands [reported by + Loriel@Lima Bean] + +Mon Jun 12 09:06:09 CDT 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.2a29 + * updated with respect to v22.1b26 + * handle backspace in user input because some clients send everything + and don't filter out local edits [reported by Requiem@SG] + * handle both \r and \n for command delimiters in user input + [reported by Requiem@SG] + * respect NO_IP_DEMON option and -N driver command line option in the + new address server reconnection code [reported by Skullslayer@RoD] + * expanded the array returned from the localtime() efun to include + LT_ISDST. This is supported on most platforms. For those that it is + not, the value will be -1. + * the third argument to tell_room() can now be an object (from Ideas) + * when COMPAT_32 is defined, closurep becomes an alias for functionp + [reported by Passerby@IoT] + * made PACKAGE_PARSER compile with NO_ENVIRONMENT again + * added an error handler to (s)printf to clean up its state when an + error occurs (usually only caused by the object_name master apply) + * edit_source will load options.h/local_options for -configure, but will + not yet check the validity of these files. this is done so that proper + configuration can be done for PACKAGE_DB + * when NO_ANSI and STRIP_BEFORE_PROCESS_INPUT are both defined, escape + characters are stripped as they're copied into the user buffer, saving + alot of unnecessary work stripping them out later. + * removed dead telnet_neg() function from comm.c + * check for tzset() and the need to prototype it in configure phase + +Mon Jun 5 13:16:25 CDT 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.2a28 + * updated with respect to v22.1b25 + * rewrote user command handling in comm.c: + . several buffer over-run fixes + . flush existing buffer before flushing a new OOB buffer + . ignore other than IAC IAC and IAC SE while in an IAC SB + . remove the space/backspace empty command hack + . some optimizations, less string scanning/copying than before + . fixed a memory leak when there are more than two lines to be + processed in PORT_ASCII and the object is destructed + . user input that exceeds the input buffer is now completely + thrown away. + * additional cleanups to parser package from brett@stummies.org + * check the reference time of the object before calling reset to + determine if the object needs cleanup, the same way it's checked + for swapping. + * line number information is now stored as an int rather than a + short if USE_32BIT_ADDRESSES is defined. + * COMPAT_BUSTER: when COMPAT_32 is defined with PACKAGE_UIDS, + the uid assigned to a new object is the euid of the current + object rather than the uid of the current object. + * fixed #warn to be properly recognized [fix from Skullslayer@RoD] + * fix a parser crasher in interrogate_object() when the object has + both PI_SETUP and PI_REFRESH flags [reported by Dvarsk@Nightmare] + +Wed May 24 12:01:34 CDT 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.2a27 + * updated with respect to v22.1b24 + * fixed (s)printf() to be re-entrant. This allows for the removal + of the master()->object_name() restriction which would cause an + infinite loop and crash the driver anyway. + * contrib efun replaceable() does the checks that replace_program() + actually does now, and also adds a check for APPLY___INIT in + addition to APPLY_CREATE. + * added a query_replaced_program() contrib efun to return the name + of the program that was replaced by replace_program(). Returns 0 + if replace_program() has not been called on the object. + * save_object() will save the name of the program that was replaced + by replace_program() if it has been replaced rather than the program + it was replaced with. + * fixed crasher when number of locals to pop in the compiler was 0. + * added GET_CHAR_IS_BUFFERED to options.h. Not defined by default, + but when it is defined, get_char() will be buffered. See the comment + in options.h for more information. + * an attempt will now be made once every 15 minutes to reconnect to the + address server if the connection has been lost (or not made at start- + up to begin with). + * if THIS_PLAYER_IN_CALL_OUT is defined, reclaim_objects() will only + zero the saved command_giver if that object has been destructed. + +Thu Nov 12 12:53:35 EST 1998 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a26 + * updated with respect to v22.1b22 + * added Skullslayer@RoD's patch for #warn and #error + +Wed Mar 4 04:57:16 EST 1998 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a25 + * updated with respect to v22.1b21 + * paranoid debugging check added in compiler.c + * fixed typo in string_copy() call in add_slash() + * Fixes from Belgarat: + . update patch_in() to take into account the v22.2a17 switch + changes + . remove obsolete code in DEBUG_MALLOC_EXTENSIONS (privs_file_fname + no longer used) + . fixed typo that caused parse_refresh() to be ignored + * SERVER_IP stuff moved to the runtime config file. SERVER_IP defines + in local_options files will still work. [change from Gorta] + * '&' is now a synonym for 'ref' when COMPAT_32 is defined + * fixed crasher when ref was used in function calls inside function + arguments, e.g. func(foo, bar(ref x), ref x) + +Thu Feb 26 00:34:42 EST 1998 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a24 + * more EOF fixes in lex.c [reported by Lathander] + * fixes from Turrican@DW + . call set_non_blocking() on all new accepted sockets since there + evidentally exists OSs that don't do this + . NUM_EXTERNAL_CMDS is now in options.h + . removed name field from lpc_socket_t (was unused, and the lookup + didn't use addr_server, ack) + . external_start can now take an array of string arguments as the + second arg + * call_stack(0) now correctly returns "" and not + "/"; actual fix is in add_slash() so this may fix other + instances of this behavior as well [reported by Donky] + +Mon Nov 24 14:58:27 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a23 + * added leading / to filename in function return type warning + message [reported by Aragorn] + * fixed crasher in explode() when result exceeds the max array size + [reported by Aragorn] + * fixed EOF handling in lex.c + * Errors no longer turn off the heartbeat (and send the heartbeat + message) if MUDLIB_ERROR_HANDLER is enabled. + * program_info() now returns a mapping + +Wed Nov 12 21:42:54 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a22 + * recompute runtime_index instead of storing it in the apply_low + cache + * fixed all uses of is*() functions on signed chars with the high + bit set + * fixed typo in apply_low() cache check + * reference programs in the apply_low() cache to avoid being confused + by dangled pointers. fixes crasher reported by Aragorn, Jihad. + See discussion in interpret.c for additional details. + +Wed Nov 12 13:17:52 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a21 + * fixed BINARIES to work with the new switch() format + * updated loop generation for LPC->C + * fixed a typo in grammar.y.pre (patch was backwards last patchlevel) + * made the "Multiple access modifiers" error message a bit less + ambiguous + +Tue Nov 11 18:34:44 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a20 + * three typo fixes from Aragorn (edit_source.c, grammar.y.pre, + packages/contrib.c) + * one from Symmetry (grammar.y.pre) + +Fri Nov 7 12:35:42 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a19 + * updated with respect to v22.1b19 + * reduced call_other cache overhead by a factor of two. + * fixed compilation with PRIVS on [reported by Jihad] and + PACKAGE_UIDS/PACKAGE_MUDLIB_STATS defines [reported by Leto] + * fixed the disassembler to know F_SWITCH addresses are relative now + * don't warn about m[-1] if m is type mapping + * fixed crasher in map_mapping() + * fixed non-existent master applies + * call pop_value() on the first_for_expr before parsing the body + of the loop, so any warnings generated have the correct line number + [reported by Aragorn] + * from Symmetry: + . fixed unused warnings for things like {int x = 1; } { int y; } + . fixed checks for multiple access modifiers + . fixed bug in switch ranges + +Tue Nov 4 16:53:54 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a18 + * updated with respect to v22.1b17 + * cp() now also errors (like mv()) if the src and dest files are + the same. Previously, it just truncated the file. [suggested + by Zod@Delirium] + * -> syntax now uses a call_other() sefun, if one exists. Type + checking for it was also improved somewhat. + * master applies are now cached the same way simul_efuns are. + applies.h is now autogenerated from 'applies'. Heartbeats also + use the same calling mechanism now. + * global 's/){/) {/' on the source code (sorry Sym :-)) + * Removed strstr.c; OS's definition is undoubtably better in most + cases + * Correct line number info is now generated for initializers (this + is actually almost a side effect of one of Symmetry's changes) + * Changes from Symmetry: + . varargs int global = 2; is an error now + . More restrictive, but sensible type order: + <*|> + Earlier one could also do basic_type ref array etc. + . ref cannot be used in global vars, casting (also an earlier + crasher), function declaration, local declarations + . Can have at most 64 classes now, earlier it was 32 but one + would also be able to crash it at 32 I believe + . Make sure that variables/functions have appropriate types after + inheriting classes + . Better error message if a previous func definition does not match + an about to be defined function + . Fixed some unused local var warnings which were erroneously + (not) generated e.g. in { int x; } { int y; write(y); } + Also fixed the order of such warnings in the case of { int x,y; } + . fixed a crasher/hanger in scratchpad for having a + scratch_copy_string when the scratchpad is completely filled + (reported by Curuntar@Lima Bean) + . Actually free the scratchpad immediately after + new(class foo, x:1, y:2) instead of waiting until + the end of compilation + . Give error message for new(class foo, x:1, x:2) + . Global modifiers now work a little differently. + There is the notion of access modifiers (private, public, + protected/static). + + Other modifiers are (varargs, nomask, nosave/static). + + The modifier now affects everything until the next such modifier: + + private: + varargs int foo(mixed a, mixed b){ + } + + means that foo is private varargs. It is an error to have two + different access modifiers (such as public private) for any + function, global var or inheritance. + + This is the case only if SENSIBLE_MODIFIERS is defined, since + old libs often use private static etc. Also fixed the + check of 'public private:'. Earlier it wasn't causing the + warning that would have been given. + . Significantly reduced program size, especially function tables. + A prototypical example of the savings for /std/race/human + on Lima, which normally has 533 functions, 526 of which is + inherited: The function table size is about 3k normally in + prev versions, 2k if COMPRESS_FUNCTION_TABLES is used, and + about 1k currently (even though one actually saves 601 + functions currently, which amounts to 140 bytes extra, which + could be removed but at a cost in speed in local calls). + This example is typical of most mud programs which inherit + many functions but only add a few themselves. + + The 1st call_other and local_calls should be better than + previously having defined COMP_FUNC_TABLES, but worse than + previously not defining it. + + The program header has also been cut down 8 bytes. + + If BINARIES is not defined, one saves an additional 4 bytes + per non-inherited function. + program_info(object ob|void) is a good way to find out about + program sizes. + . The order of name resolution for multiple inheritance is as + follows: + inherited prototypes < non-inherited prototypes < + inherited functions < non-inherited function (can only be one) + Within each class sequential order is used for resolution (later + inh prototypes win over earlier for e.g.). + + The use of prototypes is dual: + (1) As an abstract method (see java). You can call prototypes + and only let inheriting programs define the actual functions. + (2) A typesetter. At this moment this is semi-strict. A warning + is produced for return type not being compatible. Argument types + are not checked however. + + While it is not crucial in principle, programmers are encouraged + not to be too lax about types. In the future (possibly far), it + may be that meaningful compile-time types are the only way to + progress. + . If BINARIES is defined, only save string switch info if + PRAGMA_SAVE_BINARY is true + . LPC->C RUNTIME_LOADING support for alpha + +Tue Oct 7 01:39:30 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a17 + * updated with respect to v22.1b16 + * Don't generate unused argument warnings for variables in prototypes + [reported by Jihad] + * Generate a warning for global variables with the same name as + another global variable (unfortunately, historically this hasn't + been illegal) + * improved RUNTIME_LOADING support on Linux from Alaron@RetroMUD + * fixed crasher/garbage error for replace_program(non_string) + * -Wmissing-declarations added to the develop compile options; + lots of local procedures declared static. + * compat/simuls/apply.c extended to have all the functionality of + 3.2's apply(). + * added a warning for declaring a global variable with the same + name as another global variable + * fixed the disassembler not to crash on out of range simul_efuns + and zero opcodes + * added USE_32BIT_ADDRESSING which allows up to 4GB of bytecode + as long as all branches are less than 64k. When LPC->C is + defined, this is always on. + * switch() offsets are now all relative + * deep_inventory() and living() default to this_object() + * added F_SHORT_INT opcode for two byte integer constants + * optimized map_mapping() to not copy ref 1 mappings + +Sun Oct 5 12:26:39 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a16 + * fixed crashes in attempting to use ::func() to call a private + function [reported by Random et al, fix from Cloud] + * if gcc is being used, try using __USE_FIXED_PROTOTYPES__ to have + the gcc header files define prototypes for functions that are + missing (hopefully this can get rid of more of lint.h especially + on SunOS. Anyone care to test on SunOS?) + * fixed typo in Makefiles ($(DRIVER) -> $(DRIVER_BIN)) + * added reclaim_call_outs() prototype + * added debug() accounting code for COMPRESS_FUNCTION_TABLES; + uses "comp_func_tab" as a label + * added "LPC" and "LPC_line" debug() labels; the former uses line + number information to print out the file and line of code as it + executes. The latter pulls the line itself out of the source + file and prints it too. + * fixed crasher in safe_apply() due to args left on stack when an + error is caught. (This is the LIMA "crash when updating SECURE_D + or master object and getting a warning" bug) + * The starting debug_level can now be set from the command line; + use -d followed by the name of the flag that set_debug_level() uses. + e.g. "-dLPC -dLPC_line -dsockets" + +Sat Oct 4 23:29:51 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a15 + * updated with respect to v22.1b15 + * added implementation for filter(string, ...) + +Sat Oct 4 23:29:51 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * (v22.2a14 release bungled; number skipped) + +Thu Sep 25 00:22:45 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a13 + * updated with respect to v22.1b14 + * improved warnings for code with no side effects + * changed optimizations for casted string constants to obey their + new type (just for consistency) + * resolve() can now take a function pointer as the second arg + +Wed Sep 10 01:14:10 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a12 + * added a Perl script compat/fixstatic that does a pretty good job + of converting static to nomask/protected + +Fri Sep 5 01:01:54 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a11 + * fixed ASCII external ports + * implemented MUD mode external ports (use "MUD" in the config file; + the mixed value gets passed to process_input) + * Parsing package changes: + . parse_sentence has an optional 3rd and 4th arg. + . The 3rd arg an array of objects to use in the parse instead of + the inventory of the environment of the user. Nested arrays + indicate containment, i.e. ({ ob1, ({ object inside ob1 }), + ob2, ob3, ({ first ob in ob3, second ob in ob3 }), ... }) + . The 4th argument is a mapping of string -> object which can + be used to supply nicknames and similar things. For this parse, + the 'object' acts as if 'string' were returned by pc_id_list(). + Entries that do not correspond to objects involved in the current + parse are ignored. + . fixed crashes in calling parse_refresh() from within a parser + callback. This is now the correct way to say "I'm returning this + answer, but ask again next time too" + +Wed Sep 3 13:30:07 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a10 + * updated with respect to v22.1b12 + * added missing 'return ret' in dump_socket_status() compat simul + * added parser packages fixes from Belgarat: + . new error: ERR_MANY_PATHS + returned when the number of possibilities needed to figure out + the meaning of a sentence exceeds a certain number (i.e. figuring + out certain highly ambiguous sentences isn't worth the CPU) + . PARSE_DEBUG can be used to get parser debugging without compiling + with DEBUG on + . evil new :c modifier that means just choose the first one you + find, for MUDs that want to make a mistake they will regret for + the rest of their lives, and be hated by their players + [nah, the maintainer would _never_ insert personal opinions into + the ChangeLog] + . "finally, two-object rules are examined more thoroughly and some + strange parse errors are eliminated. + + Changed semantic for applies: + direct_ and indirect_ applies can be called with 0s as the + object-type arguments. However it's now guaranteed that they + will be called with filled object arguments at least once during + the processing of a rule. + This allows objects to do explicit checks. + The direct_ and indirect_ applies should work as usual when they + receive 0 as object argument - they simply should return if the + object can or can not participate in the rule. + When the arguments are filled, the direct_/indirect_ applies can + perform thorough checks and return errors." + +Sat Aug 30 19:23:35 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a9 + * updated with respect to v22.1b11 + * fixed typo in '\\' handling in #defines; also added overflow check + * removed unused local in interpret.c + * added a #breakpoint preprocessor directive which calls + lex_breakpoint(), which does nothing. Useful for setting debugger + breakpoints that stop at a particular point in LPC compilation + +Wed Jul 23 18:30:27 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a8 + * added lex.c fixes from Burty: + . Handle '\\' correctly in defines + . preserve whitespace when expanding defines + . added quote checks in expand_all_defines() + +Thu May 15 14:14:42 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a7 + * reformatted the trace information with MUDLIB_ERROR_HANDLER off; + should be a bit easier to read now. + +Wed Apr 16 07:54:45 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a6 + * updated with respect to v22.1b8 + * object_present() now depends on #ifdef F_PRESENT instead of + NO_ENVIRONMENT so it disappears in the !NO_ENVIRONMENT && !F_PRESENT + case too. [idea from Jihad] + * name change: the file "Install" is now "INSTALL" to make it slightly + more visible + * fixed file.h to check file_incl.h for S_IS* first [fix from Leto] + * fixed the multiple class inherit code to work [fix from + Wodan@Discworld] + +Sun Apr 13 23:59:02 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a5 + * updated with respect to v22.1b7 + * fixed compilation with DEBUGMALLOC off + * (: efun::foo :) is now a valid efun pointer (assuming + master()::valid_override() doesn't complain) + +Sat Apr 12 15:06:30 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a4 + * updated with respect to v22.1b6 + * reclaim_objects() now cleans destructed this_player's and objects + out of the call_out() list + * commenting out input_to() or get_char() in func_spec.c now removes + all related code and variables + +Sun Apr 6 18:00:43 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a3 + * updated with respect to v22.1b5 + * classes can now be inherited multiple times, as long as the + definitions are consistent. + * fixed macro expansion to expand all arguments to macros immediately. + in particular, the ANSI stringize hack: + #define S(x) #x + #define STRINGIZE(x) S(x) + now works. E.g. after #define FOO bar, STRINGIZE(FOO) gives "bar" + and not "FOO" + +Wed Apr 2 15:11:10 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a2 + * updated with respect to v22.1b4 + * specifying both left and center justification in sprintf() now + pushes odd-length strings to the left instead of the right, e.g. + sprintf("%|8s", "foo") == " foo " + sprintf("%|-8s", "foo") == " foo " + * fixed crasher in calling socket_status() for a socket owned by + a destructed object [reported by Jihad] + +Tue Apr 1 13:59:43 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a1 + * added a slightly improved version of Tim's socket_status() efun. + Usage: + socket_status(int fd) returns an array with: + . ret[0] = (int) fd + . ret[1] = (string) state + . ret[2] = (string) mode + . ret[3] = (string) local address + . ret[4] = (string) remote address + . ret[5] = (object) owner + socket_status() returns an array of arrays; one for each socket. + * COMPAT_BUSTER: dump_socket_status() is gone; see compat/simuls + for a replacement [written using socket_status] + * socket status information is now cleared when the socket is closed + * fixed a bug that caused the close callback not to be called for + sockets that went through the CLOSING state + +---------------------------------------------------------------------------- +(v22.1a17 promoted to v22.1b1) + +Wed Jan 29 19:15:44 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a17 + * updated with respect to v22b27 + * fixed origin() to not return "call_out" for ORIGIN_INTERNAL + [reported by Jihad] + * added Marius' patch to make the parsing package work with + NO_ENVIRONMENT. Requires the following new master applies: + . parse_get_first_inventory(object ob) + { must behave like first_inventory(ob) } + . parse_get_next_inventory(object parent, object current) + { must behave like next_inventory(current); + parent == environment(current) in case you need it } + . parse_get_environment(object ob) + { must behave like environment(ob) } + [I'm not in love with this interface, but it will do for now] + * fixed a number of warnings + +Sat Jan 25 18:14:00 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a16 + * wrapped debug.c in #ifdef DEBUG_MACRO + * fixed crasher in file operations very early in the boot process + (before the master object loads); evidentally some libs actually + do this [both reported by Aragorn] + +Thu Jan 9 20:20:40 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a15 + * updated with respect to v22b26 + * added Raistlin@IE's patches to make the Win32 build procedure much + cleaner and not depend on so many GNU utilities; also did a wonderful + job of cleaning up the OS specific Win32 code. Fixes a number of + bugs, as well. + [ also, I can't test these, since I still don't have a Win32 + compiler, so I'd appreciate it if someone would let me know + if I messed something up ] + * fixed crasher in explode("foofoo", "foo") with SANE_EXPLODE_STRING + on and REVERSIBLE_EXPLODE_STRING off + * enhanced DEBUG_MACRO a bit; things are now in terms of identifiers + instead of impossible to remember numbers. To add a new one, + add the define to debug.h and the entry near the top of debug.c + Then do: + debug(mylevel, (...)) + new efuns: + . set_debug_level("mylevel") + . clear_debug_level("mylevel") + . debug_levels() [returns a mapping showing which messages are + enabled] + * A few changes to call_out: + . 0 delay call_outs are legal + . call_outs to the same time are in the order they are set up, not + in reverse order + . call_outs() from w/in call_outs() are relative to the time the + call_out was scheduled to go off, not the actual time; this is + because: + . the current time is slowly advanced as call_outs are executed + until the current time reaches the real time, instead of taking + a huge leap forward (in the event that the MUD is busy enough + that it is getting behind) + +Mon Dec 30 04:08:08 EST 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a14 + * fixed compilation with UIDS enabled [reported by Leto] + * added support for: + . allocate(int n, mixed v): + allocates an array of n elements. The i-th element is set to + evaluate(v, i) [i is in the range 0..n-1] + . allocate_mapping(array keys, mixed v): + - if v is an array, the returned array has keys 'keys' and values + 'v' (like 3.2.x's mkmapping) + - if it is a function, the the mapping has keys 'keys' and values + evaluate(v, key) + - otherwise, each key has the value 'v' + +Mon Dec 9 13:27:42 EST 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a13 + * updated with respect to v22b25 + * fixed a bug introduced recently which caused random() to always + return zero when drand48() was being used [reported by Leto] + * changed restore_object() to ignore ^M's at the end of lines in + save files + * added leading / to get_save_file_name() argument [reported by + Leto] + * fixed ARCH define for Linux/alpha + * fixed some implicitly defined functions which cause warnings on + the alpha + * fixed crasher/wild pointer write in code like: + foreach (string s, ref r in m) { map_delete(m, s); r = 0; } + +Sun Dec 8 23:50:32 EST 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a12 + * fixed a bug that would cause implicitly defined functions (ones + with no prototype in scope allowed by strict types being off) + to become invisible when inherited [reported and tracked by + Aragorn; also reported to affect NM muds on alpha drivers] + +Fri Nov 8 12:03:53 EST 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a11 + * updated with respect to v22b24 + * changed function pointers whose owners are destructed to be + ignored by call_out_list() and to not error when they fire. + Changed so that "foo" and (: foo :) have the same/similar + behavior. This isn't strictly an equivalent case, since + (theoretically) the function could be owned by a different + object than the one that did the call_out(), but that is + probably restricted to code doing call_out()s on behalf of + other objects anyway, and the runtime error is more annoying + than useful. [Suggested by Mordred@RoD] + * to_int() now returns undefined if no valid characters were converted. + * leading slash added to in_edit() [reported by Mystic] + * call srand48() if using drand48() to make random numbers [fix + from Turrican@DW] + * fixed compilation with NO_ADD_ACTION off or OLD_ED on, or + NO_BUFFER_TYPE on + * fixed the order of .o files for RUNTIME_LOADING + * fixed switch() when two cases differ by more than 2^31 + * better local_options error message + +Sat Nov 2 18:00:04 EST 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a10 + * use -m486 for pentium too + * added /'s in non mudlib error_handler traces + * fixed compilation with SUPPRESS_ARGUMENT_WARNINGS off + * receive() can now take a buffer as its argument (useful for + PORT_BINARY connections) + * fixed PROFILE_FUNCTIONS not to miss calls which miss the apply_low + cache + * fixed the driver not to loop if more than one -D option is passed + on the command line + * the debug.log file is no longer opened and closed every time it + needs to be written to; it is held open instead + * made the DEBUGMALLOC hash a bit more efficient + * fixed a bug that caused terminal_colour() not to strip spaces of + the starts of all lines, instead of just continuations of wrapped + lines + * parser callbacks went back to being ORIGIN_DRIVER, since they + are restricted to the 'can_', 'do_' and 'indirect_' namespaces + * various fixes to compilation with uids enabled + * add to the errors field of mudlib stats, even if a mudlib error + handler exists + * added parser support for 'a', 'any', 'my' + +Tue Oct 29 20:41:26 EST 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a9 + * updated with respect to v22b21 + * fixed possible crashers in code like 'call_out(something, 1, ref x)' + * fixed wild pointer into stack in code like: + mixed global; + void foo(mixed args...) { global = args; } + void create() { int x; foo(ref x); } + void inc(int ref x) { x++; } + void increment_random_location_on_stack() { inc(global...); } + * fixed the 'multiple access modifiers' warning not to consider + nomask and nosave to be access modifiers + * disabled the multiple access modifier error message with + SENSIBLE_MODIFIERS off + * fix for compiling with COMPRESS_FUNCTION_TABLES off from Mystic + * fixed compilation with FD6 code disabled + * fixed various crashers in the unused locals warnings + * various changes to func_spec.c so that built in efuns can be + disabled or renamed (e.g. remove or rename clone_object(), etc) + [idea from Mystic] + * added support for foreach (ref x in array), + foreach (x, ref y in mapping) + * better error message for indexing an illegal type using a range + * enabled the 'public' keyword with SENSIBLE_MODIFIERS on; it was + accidentally disabled. Also fixed the options.h entry to be + clearer + * added a SUPPRESS_ARGUMENT_WARNINGS option, to cut down on the + number of warnings generated by code which existed before + omitting the argument name was legal + * fixed terminal_colour() to treat multiple spaces as one space + when wrapping [reported by Jihad] + * fix for errors writing to flushing sockets + +Mon Oct 28 17:14:29 EST 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a8 + * COMPAT_BUSTER: ORIGIN_CALL_OUT is now ORIGIN_INTERNAL; in addition + most driver callbacks which do not use hard coded function names + also use ORIGIN_INTERNAL (add_action, socket callbacks, etc). + The practical fallout of this is that such routines may be static, + but *not* private. + * Use fd #6 instead of fd #3, since Solaris uses fd #3 while + starting the program [reported by Aragorn] + * fixed crasher in the parsing package generating the object list + [fix from Aragorn] + * It is now legal to use a class member of something of type mixed, + as long as it is unambigous (e.g. foo->x is ok as long as only + one class in scope has a member named 'x', or if 'x' is in the + same position in all classes in scope) + * Unused local variables now generate warnings + * function arguments no longer need to have names (and not naming + them inhibits 'unused' warnings) + * more than one access specifier (e.g. 'public private protected') + generates a warning + * If SENSIBLE_MODIFIERS is defined, then: + (1) 'static' no longer exists, and is replaced by 'nosave' and + 'protected' + (2) 'public' no longer means what it used to; it now means the + default visibility + * COMPAT_BUSTER: modifiers from a ':' declaration only + affect declarations which have no modifiers of their own. I.e. + 'private: nomask x;' no longer declares x to be private + * if VIRTUAL_RESERVED_WORD is defined, then 'virtual' is a + reserved word. Doesn't do anything, though. + * if REF_RESERVED_WORD is defined, the 'ref' can be used to declare + arguments to functions to be by reference instead of by value. + example: + int foo(int ref i) { + i++; + } + void create() { + int y = 1; foo(ref y); write(y); + } + prints '2'. Note that ref is required both in the declaration + and the call. + * fixed a bug that would cause compile errors when indexing something + of type 'mixed' + * added an 'efun_defined' pseudo function to the preprocessor. It + works just like 'defined', except that it looks up efuns. Example: + #if !efun_defined(snoop) + write("snoop efun not available.\n"); + #endif + +Mon Oct 21 17:48:12 EDT 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a7 + * updated with respect to v22b20 + * added Burty@Nanvaent's fixes for stringizing and macro + expansion + * added support for array &= and |= [idea from Avenger@CoreDump] + * added the object name to the "Saving successful match" parser + debugging message [idea from Aragorn] + * added Leto's SERVER_IP patch + * abort compilation after getting 5 errors, since we don't print + any more anyway, and the leaks this was supposed to prevent + were fixed years ago + * MudOS now checks if file descriptor #3 is a valid socket when + it starts up; if it is, it is used as a login port. + * added a 'portbind' program: + syntax: portbind [-p port#] [-d drivername] [-u uid] [-g gid] [args ...] + + All it does it bind the specified port, then execv() the driver, + passing the bound port as file descriptor #3 (see above). + drivername defaults to ./driver, and port# defaults to 23. + if uid or gid is specified, setuid() and setgid() are called + before exec'ing the driver. + + This means one can bind the telnet port by making portbind setuid, + and using: + + portbind -u -g config.mud + + to run the driver + +Wed Oct 9 15:26:37 EDT 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a6 + * updated with respect to v22b19 + * fixed compilation with NO_ADD_ACTION off, PRIVS on, or + PROFILE_FUNCTIONS on [re: the 'ob' global recently removed; + reported by Aragorn, Jihad, Avenger, etc] + * only do promotions (int)<->(float) on assignment, not op=; in + the second case the conversion will be done by the efun (if + legal) so there is no need. + +Mon Oct 7 16:43:45 EDT 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a5 + * hidden checks are now compiled out if set_hide() is disabled in + func_spec.c [idea from Avenger@CD] + * buffer code is compiled out if NO_BUFFER_TYPE is defined; also + fixed a few old references to DISABLE_BUFFER_TYPE. [idea from + Avenger@CD] Also, a binary port in the config file will cause + a sensible error message, and attempting to create a binary + socket will return EEMODENOTSUPP. + * removed the 'ob' global in efuns_main.c and related hacks with + respect to object_visible(); also fixes a bug in the return + value of environment() when it is hidden (and probably other + bugs elsewhere too) [reported by Jihad] + * fixed crasher in using the name of a file that doesn't exist + as the object in an efun callback (e.g. filter(({}), "foo", "bar")) + * fixed a couple compile problems and a crasher in + PACKAGE_MUDLIB_STATS [reported by Avenger@CD] + +Thu Oct 3 18:16:53 EDT 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a4 + * updated with respect to v22b17 + * need to include "master.h" in the uid package now [fix from Leto], + mas well as md.c, and master.c needs comm.h when tracing is + enabled + * fixed Makefiles on non-GNUmake systems to include the two new + files introduced last pl + * fixed crasher in the handling of refreshing the master object; + also the literals are cached but are *not* affected by + parse_refresh(). The reasoning is that if they change, it + would cause all hell to break loose with existing rules. + So parse_refresh() only needs to be called when the return + value of parse_command_users() changes. + +Tue Oct 1 19:14:42 EDT 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a3 + * updated with respect to v22b16 + * fixed various crashers in the new snoop code [reported by Jihad] + * Many thanks to DrFeelgood for helping clean up header file + dependencies, and pointing out typos in options.h + * Warning for using both a 'port number : ' line and an + 'external_port_1 : ' line + * moved master object and function pointer handling to their own + files + +Mon Sep 30 18:56:54 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22.1a2 + * updated with respect to v22b15 + * #'foo is now the same as (: foo :) when COMPAT_32 is defined + [suggested by Bubbs] + * added NO_SNOOP option + * The requirement that a snooper must be interactive has been lifted + (though this isn't particularly useful unless RECIEVE_SNOOP is + also defined) [suggested by Larnen] + +Tue Jun 4 00:57:30 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22.1a1 + * COMPAT_BUSTER: #include <...> now no longer searches based on + relative paths; #include "..." still does. + * added Blackheart's diffs for using gdbm. See PACKAGE_GDBM for + details; probably this should be merged with Descartes' + PACKAGE_DB stuff ... + * added Avenger@CD's diffs for a union array operator (|) + (with trivial changes and a array stat fix) + Works analogously to &: + ({ 1, 2, 3 }) & ({ 2, 4 }) = ({ 2 }) + ({ 1, 2, 3 }) | ({ 2, 4 }) = ({ 1, 2, 3, 4 }) + * if ARRAY_RESERVED_WORD is defined, use "array" instead of "*" + in error messages [e.g. "Bad assignment ( mapping vs array )"] + * added Marius@Prilnari's fixes to lex.c: token pasting in + preprocessor macro expansion and adds token quoting + * added the -c option to the RUNTIME_LOADING compile flags since + it disappeared somehow + * Hidden object fixes for present() and environment() + * COMPAT_BUSTER: removed the tail() efun; a simul_efun is in the + compat dir + * added leading / to log_error() filenames + * cleaned up a bunch of duplicated code in array.c, and corrected + a few statistic bugs + * Parser package changes: + . added the object name to some parser debugging messages + . moved names of the applies to top of parser.c as #defines + . information from the master object is now cached + (parse_command_users, parse_command_prepos_list) + COMPAT_BUSTER: this means parse_refresh() must be called + if the information changes + . livings_are_remote() is now rechecked when a parse_refresh() + is done + +---------------------------------------------------------------------------- +(v22a41 promoted to v22b1) + +Mon May 27 16:20:09 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a41 + * variable information is now stored only in the program in which + the variable is defined; estimated compression ratio is about + 10:1. YMMV + * COMPAT_BUSTER: all inherits must now precede all global variable + definitions + * Added Ceda@IdeaExchange's fixes to the Windows '95 port + * fixed compilation error in c_prepare_catch() + * added a COMPRESS_FUNCTION_TABLES option, which compresses function + tables even further (estimated compression: 2-3x) at the cost of + slowing down function calls slightly (<5-10%) + * Fixed error() to correctly added a trailing \n to error messages + that are missing them + * Crasher fix in mapping composition (from Avenger@CoreDump) + +Sun May 26 00:37:08 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a40 + * internal function aliases are handled a little smarter, anticipating + more function table memory optimizations later + * fixed some crashers/problems involving #pragma optimize and some + compiler errors + * fixed a crasher in passing a filename that wasn't a string constant + to dump_prog() + * program_info() can now take an object as a first arg + * fixed a problem that would cause functions that were prototyped + before inherited to call the first function defined in the + object instead. + +Fri May 24 00:30:10 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a39 + * terminal_colour() now has two more optional args; the 3rd is the + width to wrap at, and the 4th is the indent for lines after the + first + * Fixed a crasher in some Too deep recursion errors + * Fixed crashers in constructs like while (...){ e = catch { break; } } + Jumping out of a catch block is now illegal. + * Fixed a crasher in program_info() when there are objects without + type information loaded + +Thu May 23 15:46:10 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a38 + * YYTYPE's size changed from 10 to 8, which should make the compiler + slightly more efficient. + * Fixed a bug in the generation of information to pass to mudlib + error handlers, which would cause an "Illegal array size" error + to be flagged before the error handler was even called. + * A few changes to $() notation: + . $() now moves out one level, not all the way out. So, to use a + local variable in a function from inside a doubly nested function + pointer, one needs to use $($()), e.g.: + string x; function f = (: (: $($(x)) :) :); + . Due to the above change, constructs like $($1) are now legal, and + work as one might expect, e.g.: + function f = (: (: write($($1)) :) :); // The inner function + // function pointer writes whatever is passed + // as the first arg of the outer one + function g = evaluate(f, "hi"); // creates a function pointer that + // writes "hi" + . this isn't really that complex; just remeber the rule "Each $() + temporarily removes one level of (: :) nesting." Familiarity + with functional programming is also recomended; (: (: :) :) + constructs are function pointers that create and return function + pointers when evaluated, _not_ simply composite functions. + . there is now a limit to function pointer nesting; the default is + 10. (Anyone who needs more is sick, but I thought I'd mention it) + . this also fixes a few crashers in using $() inside doubly nested + function pointers + +Mon May 13 23:16:05 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a37 + * Fixed a crasher in redefined functions + * added a STRIP_BEFORE_PROCESS_INPUT option for NO_ANSI + * fixed call_out() to pass zero args if zero args were specified, + instead of always passing a first arg of 0. (Usually, you'd never + notice, but it makes a difference when scheduling call_outs to + efun pointers to efuns which take no arguments) + * COMPAT_BUSTER: call_out_info() elements now have only 3 elements, + not 4; this is due to argument handling restructuring, as well + as mild security concerns for reference types. Maybe an option + will be added to get the arguments at a latter date if it is + desired. + * minor tweaks to the cleanup rules in the makefiles to get rid + of a few irrelevant files in the diffs + * added Maarten de Jong's documentation on compiling MudOS on + an Amiga using gcc as amiga/README-gcc. + * Changed ED_MAXLINE from 512 to 2048 + * Warning for using | or & when both arguments are "boolean" values + (e.g. the result of !, ==, !=, <, etc) + +Mon May 13 00:29:11 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a36 + * Fixed a crasher in memory_summary() when some objects are swapped. + * Fixed a crasher in check_memory() when BINARIES was #undef'd + * '\"' -> '"' in rc.c, since the former confuses emacs's hilit19 mode + * Better fix for the undefined function problem; the old solution + occasionally didn't work on some systems + * Fixed a problem with aliases in the function table that would + sometimes cause ... args not to be handled right + * Fixed a crasher involving prototypes preceding inherit statements + * program_info() now calculates the overhead of save_types as well + +Sat May 11 20:28:19 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a35 + * Reversed the function table search order in the new call_other + search code to be consistent with overload search order + * fixed a crasher in generated error messages for OBS rules which + have an indirect object + * added some entries to the files Bugs and Ideas + * load_binary() now sorts the function table so it is in the correct + order again since the order of shared strings is different from + when it was saved + * fixed a bug in the apply_low cache code which was accidentally using + 'prog', a global, with disastrous consequences when valid_save_binary + was called during the tail end of compilation. 'prog' is no longer + a global, and is returned where needed. + * fixed a bug which caused the identifier hash table to become trashed + when a function was used before it was defined + * 'make clean' now removes the testsuite's compile error log too + +Fri May 10 22:21:39 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a34 + * moved strput() from the parsing package to the main distribution + so it can be used internally + * Changed the building of compiler error messages to use strput(), + avoiding possible buffer overruns. Normalized the max length of + most compiler error messages to 256 bytes. + * Fixed compilation of PROFILE_FUNCTIONS + * Fixed a bug introduced last pl that caused the call_other cache + to malfunction + * Fixed octal escapes in strings; they were getting omitted + * Fixed a crasher in unterminated @ blocks (which, by the way, + had absolutely nothing to do with /V\\age) + +Tue May 7 14:23:45 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a33 + * moved the call to save the ed buffer of a user to before the + call to net_dead() + * Rewrote most of the function table handling code. Memory overhead + is now 15 bytes per function defined and 5 bytes per function + inherited, instead of 14 bytes per function inherited or defined + This cuts function table memory usage about in half on a stock + Lima lib. YMMV. Large open MUDs may see larger decreases; + the program_info() efun is a good way to check. + * Removed the last traces of OLD_PREVIOUS_OBJECT_BEHAVIOR + * The inheritance warning is now a bit clearer, e.g.: + foo() inherited from both /std/foo.c (via /std/bar.c) and + /std/bazz.c; using the definition in /std/foo.c + * Fixed the parsing package to not crash on reference to 'me' when + 'me' isn't within sight (admittedly, an odd situation :-) ) + * Fixed the testsuite to realize call_stack(3) now returns strings + * Tables of defined functions are now sorted, so they can be binary + searched; call_other time is now approximately O(m log n) instead + of O(m n) when the cache is missed (m = # of inherits, n = # of + functions in each) + * Removed OPTIMIZE_FUNCTION_TABLE_SEARCH: the new search method + is just as fast with no overhead + * added Raistlin's patch for a parser bug that would cause the + verb name to get inserted at the start of the 'real names' section + of parser callbacks + +Mon May 6 21:47:59 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a32 + * Small optimization to arrange_call_inherited() + * Small cleanup to C function pointer handling in dumpstat.c + * fixed a bug that caused dumpstat.c to ignore the size of array + headers + * Fixed the check_memory(1) table to be formatted nicer + * removed outdated code from program_info(); also fixed a bug that + caused the header size to be an absurd value + * fixed a crasher in function_owner() [ref count bug] + * added a memory_summary() contrib efun, which returns a mapping + of with entries: map["program name"]["variable name"] + Each entry contains the number of bytes used by that variable in + all active instances of that program. The size of shared structures + is divided up evenly between all values that reference it. + * Made the parser end of buffer checks a bit easier to maintain + * added parse_remove(string verb) which removes all rules for the + verb 'verb' which were added by this_object() + +Mon May 6 14:23:47 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a31 + * Added a FLUSH_OUTPUT_IMMEDIATELY option, which disables buffering + of output. Useful for debugging. + * Parsing package fixes: + . Fixed a bug that caused OBS rules to silently do nothing if + all the possible matches return errors beginning with '#' + . COMPAT_BUSTER: Now, zeros are passed for args that aren't + available yet (i.e. the indirect object in + direct_foo_obj_bar_obj()). Also, the arg which is currently + being worked on is now passed again (i.e. the direct object in + direct_foo_obj_bar_obj()) + Summary: "foo sword bar wiggle" would call: + . can_foo_obj_bar_obj(0, 0, "sword", "wiggle") + . direct_foo_obj_bar_obj(OBJ(sword), 0, "sword", "wiggle") + . indirect_foo_obj_bar_obj(OBJ(sword), OBJ(wiggle), "sword", + "wiggle") + among other things + . Fixed a number of bugs and buglets in disambiguating parses + and generating error messages, especially in cases where all of + the attempts produce nonsense + +Sun May 5 14:52:20 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a30 + * added NAME_TRUE_VARARGS flag to disassembly listings + * propagate NAME_TRUE_VARARGS up the inheritance tree to avoid + incorrect argument type errors when #pragma save_types is in use + * Parsing package fixes: + . made the maximum tokens per parser rule configurable at the top of + the parsing package [MAX_MATCHES] + . Optimizations to bitvec routines: bitvec_count(), get_single() in + the parser + . Fixed several spots where > MAX_NUM_OBJECTS involved in a parse + would cause crashes + . Fixed strput/strput_words to not write past the end of their buffer + when constructing long strings + . Fixed a crasher in parse_add_synonym() (though it wouldn't crash + until the synonym or parse_dump() was used) + +Thu Apr 25 01:32:46 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a29 + * fixed a bug that would cause call_outs which were exact + multiples of CALL_OUT_CYCLE to be delayed by one CALL_OUT_CYCLE + (sometimes could happen with call_outs that differed by a small + multiple of 2 from this) + * removed an unused local in repeat_string + * Fixed the parsing package to not crash when given a line containing + more than 256 words (now it just returns; the limit can be set at + the top of parser.c) + +Tue Apr 23 16:58:34 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a28 + * added a contrib efun: repeat_string(string s, int n) which + essentially does: sprintf("%-*'"+s+"'s", n, ""), but is readable. + e.g. repeat_string("-=", 10) == "-=-=-=-=-=-=-=-" + * redesigned call_outs slightly to allow constant time insertion + * added a CALLOUT_HANDLES option, which has the following effects: + . call_out returns an int, which can be passed to the following + two efuns: + remove_call_out(int handle) + find_call_out(int handle) + . Note that using the handle is more efficient than using the + ob, function name version + +Tue Apr 16 11:29:13 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a27 + * updated with respect to v21.7b21 + * Fixed sort_array to work correctly when called from a sort callback + +Sun Mar 10 05:32:19 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a26 + * updated with respect to v21.7b20 + * Added Raistlin@IE's fix for a bug in replaceable()'s one argument + case introduced in v22a23 which caused the one argument form to + quit working + * Fixed the ARCH define for 386bsd to not override the FreeBSD define + * changed "stuf!" -> "unknown architecture", when ARCH cannot + be determined + * added a classp() efun + * added support for \012 octal escapes and \x1e hex escapes in + strings and character constants + * added a comment about what the legal values of CFG_LIVING_HASH_SIZE + are + * crasher fix in the database package + * put a remove_interactive() call back in that accidentally got removed + at one point, which caused the driver to busy loop until a message + was sent to the object whose link had died + * COMPAT_BUSTER: two changes to call_stack(3): first, use strings + instead of numbers to be consistent with origin(); second, a bug + was fixed which was reporting the origin of the frame below the + indicated frame, not the frame itself. + * fixed compilation on systems that use _SC_PAGE_SIZE, not _SC_PAGESIZE + +Mon Mar 4 20:36:27 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a25 + * updated with respect to v21.7b19 + * added code to flush message queues when closing connections and + shutting down + * added a flush_messages(void | object) efun for manually flushing + message queues (during a long thread of execution, for example) + * fixed a bug that would cause some anonymous functions to not + be bindable + * fixed a crasher in recursive structures in error traces + * fixed a bug in sprintf() column mode that would wrap early if + a fit exactly in the width given + +Fri Mar 1 13:33:14 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a24 + * added Pace@Callandor's patch for REVERSIBLE_EXPLODE_STRING + * made PARSE_NUMERIC() into a routine instead of a macro, and + added support for scientific notation so that very large/small + floating point values restore correctly in restore_svalue() and + friends + +Mon Feb 5 09:43:36 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a23 + * updated with respect to v21.7b18 + * added a 'parallel' target for parallel makes when using gmake + * protected process_command against this_player() changing or + being destructed during process_input() and other nasty places + * removed the DEBUG_COMM_FREEZE code + * made the message queue flushing a bit lazier which should result + in smoother output and larger packet sizes + * added Descartes' database package + * added heart_beat_info() as a synonym for heart_beats() when + COMPAT_32 is on + * replaceable now can be optionally passed a second array argument + which is a list of function names to ignore; if the second arg + is left out, ({ "create" }) is assumed, which gives the old + behavior. + * added a function_owner(function) contrib efun. + * made #undef PACKAGE_SOCKETS/#define PACKAGE_EXTERNAL compilation + fail more gracefully + * fixed a parser callback bug that caused the 'real names' of + omitted args to be omitted too + * added an error message for using the debug mode of parse_sentence + when the driver wasn't compiled with DEBUG on + * fixed a bug that would cause parse_sentence() to return large + numbers instead of error strings + * fixed a typo in the Incorrect argument to type %s error message. + * fixed compilation when first_inventory() is disabled. + +Sat Feb 3 13:06:23 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a22 + * fixed seteuid() to pass the correct second arg to valid_seteuid() + * fixed the parsing package to not crash if parser_error_message() + doesn't exist + +Sun Jan 21 21:29:34 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a21 + * updated with respect to v21.7b16 + * The master object and simul_efun object can be updated again when + LPC_TO_C is not defined; patch from d.collins@ic.ac.uk + * unified the code handling function pointers/extra args in + various efuns; fixes crashers in rare cases. Also, sort_array() + now takes additional args which are passed down the the function, + like filter() et al. + * Added a check for the /usr/ucbinclude directory in ./build.MudOS; + Solaris needs from there + * Removed push_string() internally; push_constant_string() should + now only be used on string constants. The following changes + will preserve previous behavior: + . push_string(x, STRING_MALLOC) -> copy_and_push_string(x) + . push_string(x, STRING_SHARED) -> share_and_push_string(x) + . push_string(x, STRING_CONSTANT) -> push_constant_string(x) + . push_constant_string(x) -> share_and_push_string(x) + also, new function: push_shared_string(), which pushes and + references a known shared string. + * optimized the PORT_ASCII code a bit, and fixed some problems/loops + in it in the presence of bad input/errors + * fixed a bug that would cause message() to send messages/avoid the + wrong people if the target/avoid argument was _not_ an array, + and the function was called during the processing of another + message call whose target/avoid was also not an array + * removed XALLOC(), since it isn't used any more + * fixed mapping hash distribution and centralized the definition of + it + * optimized terminal_colour a bit + * optimized present() a bit; also fixed a leak in errors in id() + functions + * the message of the message() efun may now be of any type; this + actually was side effect of a fix that makes message() more + efficient :-) + * fixed a crasher in sprintf() table mode, when no number of + columns was specified (best fit) + * improved the packages/ and mudlib/ dependencies a bit + * configure.h is now remade if the information in 'uname -a' changes + * no longer log a 'double call to remove_interactive()' if an object + self-destructs in net_dead() + * There is no longer a limit on the number of sockets available; + if a limit is wanted it should be enforced in valid_socket() + * fixed sprintf() column mode to wrap at the column width, not one + before + * added a couple testsuite tests for sprintf table mode + * ./build.MudOS now prints an error message if an unknown kind of + build is attempted instead of silently assuming the default + * Parser changes: + . Two new restrictions; only one plural token is allowed per rule, + and only two object tokens are allowed per rule. The second may + disappear after I clean it up a bit. + . fixed a crasher in having more than MAX_NUM_OBJECTS involved in + a parse + . 'all' is now supported, also 'all of ...', 'all red swords', etc + . Cases where more than one object are matches, but only one makes + sense now work + . in callbacks, only objects that have been completely parsed can + be refered to. This means can_ and direct_ functions can't + reference the direct or indirect objects. The corresponding + spots in the argument list are missing. + . OBS rules use the _obj_ callbacks, with the exception of do_ + . error handling is now up to the master object via the + parser_error_message() apply. The first argument is a int + indicating the error type. The second is an object if this + message corresponds to part of a plural match, otherwise it + is zero. The third and following args depend on the error + type (from include/parser_error.h): + ERR_IS_NOT, ERR_NO_LIVING, ERR_NOT_ACCESSIBLE: + the noun used, and then 0/1 depending on whether there + ambiguity + ERR_AMBIG: + an array of objects that might have matched + ERR_ORDINAL: + The number that was refered to + ERR_THERE_IS_NO: + The string that couldn't be matched + ERR_ALLOCATED: + The error message returned by the mudlib + ERR_BAD_MULTIPLE: + nothing + [note: if you want more info that you think the parser might + have, let me know] + compat/parser_error.c has a decent approximation of the old + behavior + . do_foo_obs() gets an array of objects and error messages as + the arg corresponding to obs + . Returned error strings which start with '#' are assumed to + be nonsense messages, and aren't counted for the purpose of + ordinals and all. Useful to prevent 'get all' from printing + an error for yourself and the room, and to keep 'drop first sword' + from counting swords in the room. + +Sat Jan 20 15:47:06 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a20 + * removed process_string() and process_value(); simul_efuns are + availaible in the compat/simuls directory + * Fixed a memory leak in new(class foo, bar : baz, ...) + * fixed compilation problems in grammar.y.pre, shallow_inherit_list, + object.c + * fixed a typo: m_indices() is keys(), not values(); also added + m_delete + * pluralization fixes: 'are', 'mackerel' + * added Rust's timezone efuns to contrib; turned off by default + since they may not compile everywhere + +Wed Jan 3 16:12:50 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a19 + * updated with respect to v21.7b15 + * All values which were previously 'null' are now undefined instead; + nullp() is now exactly the same as undefinedp() + * added a COMPAT_32 option, which tweaks a few things to allow + some 3.2/3.2.1 code to be ported easier; see options.h for + what changes + * shallow_inherit_list() is now the same as inherit_list() [unless + COMPAT_32 is on, in which shallow_inherit_list() is the MudOS + behavior, and inherit_list() becomes deep_inherit_list() ] + * error message change: + Missing type -> Missing type for global variable + * Don't raise type mismatch errors for code of the form + 'identifier = expr'; 'Missing type for global variable' is good + enough + * Don't manually include and in + interpret.c; trust configure instead + * fixed a parser crasher in refering to 'noun', when more than + 4 adjectives are possible + * Fixed sprintf table mode to not stretch the last line to fit + the field width + +Wed Jan 3 14:29:43 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a18 + * fixed some serious flaws in class member lookup introduced in a17 + +Tue Jan 2 17:59:42 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a17 + * updated with respect to v21.7b14 + * fixed a crasher in the call_out leak fix from v22a1 + * turned off PACKAGE_EXTERNAL by default + * fixed a bug that caused the messages from saving the ed buffer + of an object which was dested while in ed to be appended to the + start of the next message sent to an object using ed. + * check for wait3() as well before using BSD signals + * removed wait() from lint.h since we include now + * fixed a couple bugs in the handling of functions in the memory + leak tracking code + * fixed a crasher in add_action(function) when the driver is + run with the -d flag + * fixed the addr_server not to crash if gethostbyname() fails for + some reason + * function(...) { ... } is now rebindable if it does not reference + local functions or global variables + * switch (...) { case 0: function() { break; }; }, + while (...) { function() { continue; }; }, + and similar pathological code is no longer allowed. + * bind(f, ob) now always succeeds if f is already bound to ob + * added back the fast version of livings() from v22a14 as a contrib + efun named_livings(); also fixed it to not return objects which + are no longer living() + * added class support in reclaim_objects() + * trailing justification is no longer added to the last line of + tables if no pad string was specified + * The following is now legal: + class foo { int x; string y; } + class foo f1 = new(class foo, x : 5); + class foo f2 = new(class foo, y : "foo", x : 1); + +Sat Dec 30 20:55:41 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a16 + * updated with respect to v21.7b13 + * changed the name of strerror to port_strerror to avoid prototypes + on SunOS, which prototypes the function but never defines it + * Removed a number of prototypes in lint.h for functions which are + also prototyped in SunOS headers now + * Fixed a bug that would prevent two way communication with external + commands + * Small optimization to the string case of socket_write + * Tracked down the real problem which caused sprintf() to crash + on empty tables; also fixed a crasher empty lines in column mode + * reversed the livings() patch, since not all living objects are + in the hash table + * #ifdef'd out some unnecessary code for when LPC_TO_C is off + * Remember to wait on our children, so we don't create zombies; + configure checks to figure out whether to do it the BSD or + Sys V way + * Removed some archaic defines from portability.h + * Changed the parse_sentence return codes again: + 1 - success + 0 - no such verb + -1 - verb exists, but no rule matched + -2 - a rule made sense, but can_ or direct_ failed + * Fixed a typo in the 'Illegal master object file name' error message + +Fri Dec 8 20:53:11 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a15 + * updated with respect to v21.7b12 + * changed livings() to walk the living hash table instead of the + full object list; idea from Jihad + * '\r' is now treated as whitespace by the compiler + * The success return code of parse_sentence is now 3, not 1. + * changed the return type of parse_sentence from 'int' to 'mixed' + * Fixed a crasher in using a function pointer as a read callback + * If PACKAGE_EXTERNAL is defined, then lines of the form: + + external_cmd_1: /usr/local/bin/gzip + + in the config file allow the mud to run the command using the + following efun: + + int external_start(int which, string args, + mixed read_cb, mixed write_cb, mixed close_cb) + + which is the command number (e.g. 1 from the example above) + args is the argument passed to the command. A socket is returned, + which can be used to communicate with stdin/stdout of the command. + + valid_socket() is passed "external" as the operation. + Up to 5 commands are allowed. + +Thu Dec 21 01:33:34 PST 1995 (gstein@svpal.org (Deathblade)) + * raised patchlevel to v22a14 + * fixed varargs by tweaking grammar.y.pre to not turn off the + TYPE_MOD_ARRAY flag for the varargs variable + * fixed sprintf() crasher when tables are used (Rust and Zakk) + +Thu Dec 7 12:30:20 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a13 + * fixed crasher in disabling a heart_beat during a heart_beat + * fixed sprintf() to not add trailing padding onto wrapped strings + * removed the break_string() efun. See compat/simuls/break_string.c + for a replacement. + * fixed a few more misoptimizations of last variable references by + the optimizer. + * added a warning for putting varargs args into a variable of + non-array type, also fix a bug that would cause type errors + if the prototype was in scope + * parse_sentence now returns: + 0 - no such verb + 1 - verb exists, but no rule matched + 2 - a rule made sense, but can_ or direct_ failed + in the cases where it used to return zero. + * parse_add_rule no longer has a third arg; it is always this_object() + * New parse efun: + parse_add_synonym(string new, string old): + . interpret the verb 'new' as if it were the verb 'old', and + parse using 'old's rules and routines + parse_add_synonym(string new, string old, string rule): + . 'new' acts like 'old' for only the rule 'rule', which must + have been previously added. Can be called multiple times. + +Wed Dec 6 18:00:15 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a12 + * fixed a crasher in passing a negative number as the field width + via the '*' specifier + * fixed a crasher in strings which were too long to fit into tables + in table mode + +Tue Dec 5 19:30:12 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a11 + * fixed two crashers in the table generation logic of sprintf(), + also fixed a bug that would cause the second and following + lines to be indented wrong + * fixed tables to fully fill the space allocated to them in + the format description + * The fill pattern for tables and columns always fills out the + entire 'box' now; e.g. + printf("%#|30'.'s\n", "apple\nbannana\ncherry\ndonut\nelf\nfruit\n") + gives: + ...apple....cherry......elf... + ..bannana....donut.....fruit.. + and not: + ...apple....cherry......elf + ..bannana....donut.....fruit + +Mon Dec 4 16:13:59 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a10 + * updated with respect to v21.7b11 + * moved values_list in function_context_t and node in decl to + align slightly better + * fixed the direct/dirent check to include std_incl.h in case it + has some defines needed by those files + * removed some really old and unused files of the compiler %union + (address and funp; the second of which predates me ...) + * small optimization to the lexer's handling of comments in + preprocessor lines + * major changes to sprintf.c: + . COMPAT_BUSTER: error messages are never returned any more, but + are thrown as errors instead. + . 'clean' is no longer used, so cannot be leaked + . COMPAT_BUSTER: "%^" is no longer special (for efficiency reasons, + as well as disagreements on the exact algorithm) + . The format string is never written into, eliminating the need + for savechars and related hacks; fixes a crasher in extremely + long strings in tables (>2k) + . The setjmp()/longjmp() is gone, since the cleanup can be done + on the next call to sprintf() now + . sprintf() is now officially not reentrant, and you will get + an error if you try. It probably crashed before if you tried + it. The only LPC code called by sprintf() is object_name(), + so this shouldn't be a problem + . on the whole, things should be significantly faster (slightly + more than 3 times faster on the small example I used), + mostly due to collecting sets of characters instead of adding + characters individually, and removing redundant length calculations + . large portions of the file are now actually readable + +Mon Nov 27 22:51:35 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a9 + * updated with respect to v21.7b10 + * COMPAT_BUSTER: The scope of for and foreach loop variables is now + only the inside of the loop. This also fixes a bug demonstrated + by the following: + { int i; for (int j;;) ; } { int i; } + * Some error message changes: + . Indexing on illegal type + -> Value being indexed is zero/Cannot index value of type 'foo'. + . Indexing a (string/array) with an illegal type + -> (String/Array) indexes must be integers + . Negative index passed to array + -> Array index must be positive or zero + +Wed Nov 22 12:52:13 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a8 + * updated with respect to v21.7b9 + * fixed a typo in ./build.MudOS (CC -> $CC) + * fixed a crasher in copying parse_command_* arrays which are empty + +Tue Nov 21 17:16:10 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a7 + * updated with respect to v21.7b8 + * fixed the ar test to make sure comptest.o exists in ./build.MudOS + * Leading and trailing whitespace in the values in the config file + is now ignored + +Wed Nov 15 14:41:20 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a6 + * updated with respect to v21.7b7 + * Better system for reporting bad malloc configurations (two malloc + packages, etc) and system configuration errors + * Report a redefinition error if classes with the same name are + inherited from different files + * Fixed the "Return type doesn't match prototype' error message + to only be printed once per occurance, not twice + +Tue Nov 14 12:53:51 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a5 + * updated with respect to v21.7b6 + * A few small tweaks to the testsuite cleanup + * fixed crasher in printing a string containing a '%' when + NONINTERACTIVE_STDERR_WRITE was defined + * some small cleanups to includes in socket_ctrl.c + +Tue Nov 7 17:50:22 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a4 + * updated with respect to v21.7b5 + * updated all the Makefiles with respect to Makefile.master + * minor change: use 0 instead of -1 for master_ob not loaded yet since + we no longer have to distinguish between unloaded/not loaded yet + * added MDmemcheck() which can be inserted into the source to do + internal memory consistency checks and abort if corruption is found + * added back some parser fixes that were missing due to reversed + patches + * Two new options to ./build.MudOS: + - ./build.MudOS develop -> turn on warnings and debugging code + - ./build.MudOS debug -> turn on debugging symbols and code + +Fri Nov 3 16:41:11 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a3 + * updated with respect to v21.7b4 + * couple changes to void handling, basically (int)->(void) is no longer + legal. The following are now errors: + . int f(void x) { ... } + . ... { void x; } ... + . void x; + . class foo { void x; } + . void f() { return 1; } + * defining a variable is now allowed in foreach, e.g.: + . foreach (string x, object y in z) + * fixed a crasher in errors in parse_* callbacks + +Sun Oct 8 19:48:21 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a2 + * updated with respect to v21.7b3 + * COMPAT_BUSTER: previous_object() == 0 and not this_object() in + heart_beats + * remove_call_out(/* no arg */) now returns 0 always, not -1 + * fixed a bug in the replace_string() with all 5 arguments in + some cases + * fixed a bug in restoring mappings which had arrays/mappings/ + floats as keys + * added some missing newlines to regexp() error messages + * fix to the center/left justify case for ints; remember to + add the padding to the right side as well in sprintf() + * more testsuite efun tests; finished through 'sprintf()' + or so + * made it illegal to undefine or redefine a global define like + __VERSION__ + * added a NO_RESETS option + * better error message for people who don't choose a malloc package + * fixed various crashers involving passing garbage back to the + parser inside arrays + * fixed leak in sprintf() for printing recursive structures; attempting + to do so no longer errors. + +Sun Oct 8 19:27:28 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a1 + * removed some outdated code (c_filter() and f_creator()) + * fixed a crasher in removing heart_beats during a heart_beat + * fixed a leak in call_outs with more than one extra argument + * fixed a leak in illegal arguments to call_stack() + * fixed set_light() to compile with NO_ENVIRONMENT (for the + ultimate in bleeding edge uses of archaic efuns :) ) + * added some checks to make compilation bomb more informatively + if two malloc packages/wrappers are specified + * cleaned up the signal handling code a bit + * fixed compilation of the matrix package + * fixed compilation with NO_ENVIRONMENT and !NO_ADD_ACTION + * fixed compilation with DO_MSTATS and SYSMALLOC + * fixed testsuite to compile and work with either setting of + INTERACTIVE_CATCH_TELL, NO_ADD_ACTION, PACKAGE_UIDS, + NO_ENVIRONMENT, NO_WIZARDS, PRIVS + * revamped the testsuite efun tests, and added tests for most of + the efuns 'a' through 'r' or so + * testsuite now logs compilation errors to /log/compile + +---------------------------------------------------------------------------- +v21.7a10 promoted to v21.7b1 + +Fri Sep 22 22:51:20 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7a10 + * fixed a bug that caused case 0: to not work in string switches + * fixed a typo in the unknown pragma error message + * rule priority is now calculated beforehand in the parser; this + fixes the precedence of some errors and allows earlier shortcutting + * 1st through 9th and first through ninth are now understood by the + parser + * "Which X do you mean?" is now more verbose + * 'myself' is now the same as 'me' + +Mon Sep 11 03:37:53 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7a9 + * fixed debug_info(2, ...) to put all the info in the string; + it was still sending some of it directly to this_user() + * slight optimization (condense two consecutive strlen() calls) + in regular expressions + * -DPEDANTIC now allows the use of inline to be turned off, since + gcc only defines __STRICT_ANSI__ when -ansi is used, and not + when -pedantic is used, but -pedantic complains loudly about inline, + and -ansi causes the SGI headers to break. Unfortunately, gcc + only gives some useful warnings when -pedantic is on + * fixed up some (unsigned char *) <-> (char *) problems + * fixed an optimizer bug that would clobber range expressions and + generate incorrect code + * Added documentation of makefile targets to the makefiles + * Added a .DEFAULT rule for the decoy makefiles so better errors + are generated when the wrong make is used with a target + * Made the SIGPIPE always reenable the handler, not just on Linux, + since other OS's (Solaris) behave this way as well + * Fixed the gettimeofday() check to use two args, so it wouldn't + fail on BSD based systems + * fixed a compile error in OPTIMIZE_FUNCTION_TABLE_SEARCH + * added a handler to ignore SIGFPE for those systems that raise it + * changed "create" to APPLY_CREATE in replaceable() + * fixed a parser crasher when parse_command_users() doesn't exist + * removed a if (pointer >= 0) check in the parser + * fixed a crasher in the 'last match to error' handling in the parser + * fixed a crasher in parse_command() when the object array had + non-objects in it + * fixed some NO_ENVIRONMENT compilation problems, especially when + NO_ADD_ACTION was NOT also defined. (add_action w/o environments + is a tad pointless, but it works now) + * fixed a bug that cause query_verb() to only return the matched + portion and not the entire verb + * fixed (s)printf() to not print destructed objects + +Fri Sep 8 03:34:50 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7a8 + * updated match_path() to know about the mapping changes + * preliminary OBS changes; OBS and LVS are recognized as tokens now; + currently they behave exactly the same as OBJ and LIV + * fixed a few uses of new_string as a variable name + * fixed a parser in generating arguments for parser callbacks + +Sun Sep 3 21:47:54 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7a7 + * cleaned up -Wall compile + * better code to check the string statistics, leading to: + * fixed the string stats bug(s); the figure should be correct again now + * improved the error message for "owner of function pointer destructed" + * removed the storing of the hash value in mapping nodes; mapping + memory usage should be down ~20%; also optimized a bit, so + most mapping operations should be faster + * crasher fix in %o case of parse_command() + +Wed Aug 30 19:36:35 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7a6 + * crasher fix in edit_source -configure from Valodin + * moved the CONFIGURE_VERSION define to the end of configure.h so + incomplete configure.h files are detected as corrupt + * removed the each() efun + * crasher fix in the optimizer (no local variables again) + * updated the tag info in check_memory(1) + * fixed check_memory() to not accidentally complain about the string + it is building + * fixed a bug in the mark and sweep memory debugging of the parser + * fixed a crasher in verb handlers that call parse_refresh() + * fixed a memory leak in objects that call parse_refresh() + * remember to add the real names when calling can_* callbacks + * fixed a bug that would cause parser error messages to be truncated + * fixed a memory leak in incoming MUD mode socket packets + * added a bunch of bug reports to Bugs + * fixed a line number bug in '\' + * fixed @@ to work again, evidentally noone has used in in over a + year since it hasn't worked since Robocoder added L_ARRAY_OPEN ... + * fixed odd errors if the end of the input buffer is hit while + parsing a macro expansion; found by Tensor + * fixed a line number bug in macro arguments with newlines in them + +Tue Aug 29 17:11:06 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7a5 + * updated with respect to v21.6b6 + * Merged in Descartes' diffs for Windows NT and Windows 95. Someone + please check these; I fixed/changed a bunch of things, but have no + way of testing them, and there are probably some mistakes. + * removed the old OS2 code, since noone ever got it to work ... + * added support for foreach (int in string) + * fixed a fatal error when a string > 64k in size was added to an + outbuffer. + * changed sprintf() to use outbuffers, speeding up sprintf a bit, + and expanding the size limit to 64k + * fixed type error for sizeof(array constant) + * it's now legal for an ed range to go past the end of the file; + any line # greater than the file size refers to the last line. + * fixed a bug that caused varargs contraction to not be done when + the call_other cache was hit, or when one does inh::foo() + +Sat Aug 26 19:37:38 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7a4 + * reorganized the function_t struct slightly to save a bit of memory + * added a warning for return types that don't match their prototypes; + currently ignores modifiers, since accepted usage is so gross in + this respect it isn't even funny. The next item might help: + * added "private:" which makes all function definitions/globals after + it private (until the next such section). Works with any type + modifier (static, private, protected, public, nomask, varargs) + * optimization fix: remember to put the replacement node in the tree + when doing: if (x) {} else y -> if (!x) y + * catch, time_expression, and __TREE__ now generate explicit code + to pop the value instead of doing it inside F_END_CATCH. This + makes the grammar a bit simpler, and generates better code for + catch { ... } and catch(x = ...), which are common cases + * fixed sizeof( ({ ... }) ) to preserve side effects inside the + array constant, for crappy code like sizeof( ({ i++ }) ), + which now compiles to: i++, 1 + * changed edit_source to include configuration info when doing tests, + so we can check for defines in include files + * run ranlib on the mudlib/ and packages/ files for systems that need/ + like it. + * added a WRD token in the parser, which is just like a STR but only + matches one WoRD. + * fixed a bug that chopped a letter off the results returned by STR + rules + * xxx_verb_yyy() callbacks now include the name of the verb in the + 'real names' part of the argument list, so for example "kick! beek" + would call (among other things): + can_verb_obj("kick", OBJ(beek), "kick!", "beek") + This should satisfy the people who have been mailbombing me asking + for a way to get at the real form of the verb :) + * fixed a few warnings in the parser + * When the return value of a construct is unused, and the construct + has no side effects, replace it by it's arguments (recursively) + possibly eliminating the construct entirely. + i.e. the following generates no code: + + int x; class bar y; array z; + ((({ ~x })[!x..foo)[(x*2)-1..] : ([1:2, 3:x])), -z[x]); + +Thu Aug 24 06:58:46 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7a3 + * configuration checks for broken libg.a Linux configurations, + , -ldl, RTLD_LAZY + * try cc -E -traditional-cpp as a possible preprocessor in build.MudOS + * Use ANSI USHRT_MAX instead of MAXSHORT if availiable + * reworked the handling of novalue efuns to be more robust; fixed + crashers in (void efun) || (void efun) among other things. + * Patches from Symmetry: + . made Config.Example match the testsuite setup + . fixed mapping case in dump_variable() for testsuite + . bugfix in resolve_path() in testsuite + . allow (: function() { return $1; } :) + . optimize x[y..<1] to x[y..] + . optimize dested obs in F_TRANSFER_LOCAL + . crasher fix for swapped objects in program_info() + . fixed disassembly of efun function pointers + +Mon Aug 21 03:58:32 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7a2 + * fixes from Symmetry for #undef RUNTIME_LOADING + * added Zakk's query_ip_port() contrib efun for finding out which + port an object connected to + * fixed a parser bug that would sometimes cause objects to fail + to be recognized the first time they were referenced. Many, many + thanks to Deathblade for helping to track down this one + * Added filenames to the parser error messages + * improved the handling of punctuation; verbs do NOT include + punctuation again, although this may change; stay tuned ... + +Thu Aug 3 20:25:27 EDT 1995 (tim@handel.princeton.edu (Beek)) + * created v21.7a1 from v21.6b3 + * valid_compile_to_c() in the master object now controls the use + of the generate_source efun. + * RUNTIME_LOADING works if your system supports dlopen()/dlsym(); + define it in options.h, then use generate_source(filename) + to load the object. Note that /lpc2c in the mudlib must be + a symbolic link to the driver source. Objects loaded in this + manner do not show up on lpc_info() [yet] + * The restriction which disallowed cloning of objects with + environments was removed + * destruct()'ing the master or simul_efun object now fails if a new + copy can't be loaded. This means that once the mud starts, a + master or simul_object is ALWAYS loaded. + * preliminary changes for disallowing calls to private functions; + you can still get past it in odd cases (e.g. calling the function + before you inherit it) More changes in a patchlevel or two. + * fixed a bug that caused // and /* to be interpreted as comments + within continuation lines in #define's + * fixed the F_WHILE_DEC optimization, and added support for it + in loops of the form 'for (...; x--; ...) { ... }'. Centralized + the handling of loop test optimization. + * optimize empty blocks for if's + * removed some mentions of 'actlab' in the docs + * added some new exit codes to the Exit_Codes doc + * added NO_ENVIRONMENT in options.h + * fixed the disassembly of F_LOOP_COND_NUMBER + * fixed a crasher/wierd behavior in using 'array' to declare arrays + * fixed a bug that made using a (blank) simul_efun object necessary + * added DEBUGMALLOC support for the parsing package + * added support for classes in copy() + * fixed a bug that chopped the last letter off of some + parser error messages + * updated the testsuite lib to run under the default driver + configuration + +---------------------------------------------------------------------------- +(v21.6a11 promoted to v21.6b1) + +Tue Jul 18 02:23:22 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6a11 + * updated with respect to v21.5b10 + * fix from Marius for a crasher in x[C + introduced during the compiler rewrite + * only include if MAXSHORT isn't in + * fixed a crasher in filter() + * fixed 'safe' -> 'saves' in pluralize() + * fixed TRACE compilation with NO_WIZARDS + * fixed regexp() to not crash on eight-bit characters in the format + on hosts where 'char' is signed + +Sat Jul 15 14:35:50 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6a10 + * updated with respect to v21.5b9 + * backed out the VOLATILE changes to compile_file.c since it relies + on a gcc extension + * fixed a crasher in true varargs functions with local variables + * added configure checks for and + * fixed a crasher in undefined functions + * COMPAT_BUSTER: filter_mapping() now passes the value as the + second element, just like map_mapping() + * fixed the Makefile to support options in grammar.y.pre; this + probably should be changed to use a %include "options_incl.h" + * added y.output and tmpdepend to 'make clean' + * fixed `system_libs` -> `cat system_libs` in the Makefile + * fixed a few DEBUG crashers in the parser package + +Thu Jul 13 04:05:49 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6a9 + * updated with respect to v21.5b8 + * backed out the VOLATILE changes to sprintf.c since it relies on a + gcc extension + * updated the Makefile not to define EDIT_SOURCE any more + * implemented the parser generated error messages for the parsing + package + * added the other half of varargs support, allowing the following: + void log(string file, string fmt, array args ...) { + write_file(file, sprintf(fmt, args ...)); + } + void foo(int x) { + log("/log/foo", "foo() was called with: %i\n", x); + } + +Thu Jul 6 03:52:27 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6a8 + * fixed to_float("illegal string") to always return 0.000000 + * added testsuite tests for to_int() and to_float() + * fixed a crasher in illegal indexes to array constants + * 'make depend' now works again when using GNU make + * edit_source -configure is never rerun if configure.h exists, + even if the file is out of date (it takes too long, and the + info shouldn't change). + * fixed a dependency problem that caused configure.h not to get built + * DEBUG is now visible to %ifdefs + * check for ; MAXSHORT is there on SGI + * removed some unused variables + * added __TREE__(expr) and __TREE__{ ... } which evaluate to arrays + representing the compiler's internal representation (IR) of the + given code. For example, + __TREE__(x + y) gives: ({ "binary op", "+", ({ "opcode_1", "local", + 0 }), ({ "opcode_1", "local", 1 }) }) + * catch { ... } and time_expression { ... } are now legal. + * if ARRAY_RESERVED_WORD is on, then 'array' now associates with the + type and not the var, for example: + int array x, y == int *x, *y and not int *x, y + * 'array' by itself is now allowed, meaning 'mixed *' + * fixed a bug in type checking that allowed 'x *' and 'x' to be + compatible in one order, but not the reverse + +Fri Jun 30 16:44:33 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6a7 + * updated with respect to v21.5b6 + * merged Makefile.MudOS back into the main Makefile + * added implode(array, function, mixed) where the third + argument is the value to start with, as in: + flatten(arr) { + if (arrayp(arr)) return implode(arr,(: $1 + flatten($2) :),({})); + else return arr; + } + * fixed make_func.y to give file and line numbers on fatal errors + * added configure checks for getrusage(), times(), gettimeofday(), + and fchmod() instead of using hard coded information + * figure out the correct type for UINT32 in configure + * removed the 0.9.18 compat efun package + * fixed a crasher in remove_interactive() + * disabled the lookat_rotate2 efun in the matrix package as it + uses more arguments than the compiler currently supports + +Tue Jun 27 01:10:27 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6a6 + * fixed the debug checks to not panic on nested foreach's + * fixed edit_source -configure to not get fooled by OSF's queer + non-standard BSD compatibility includes + * fixed a crasher in passing a bad argument to call_stack() + * optimized upper_case() and lower_case() + * fixed an ANSI style declaration in eoperators.c + * a couple minor fixes for alpha; also fixed DEBUGMALLOC to work + correctly on alphas + +Fri Jun 23 02:39:02 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6a5 + * updated with respect to v21.5b4 + * fixed a bug that caused sizeof(array constant) to always be 16 + +Tue Jun 20 16:25:14 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6a4 + * updated with respect to v21.5b3 + * fixed a few bug in using x[y..z] as an lvalue + * fixed an error in setting the return type of time_expression() + * added packages/parser.c, a flexible parsing system for interactive + fiction applications + * fixed a crasher in variables() + * added a workaround for getting EINTR while trying to seek the swap + file + +Sun Jun 18 11:33:07 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6a3 + * fixed a bunch of warnings from gcc -Wall + * fixed c_update_branch_list() to not generate unused labels + * COMPAT_BUSTER: + origin() and typeof() now return strings. If you use the defines + in the driver include/ files, you're fine (assuming you update your + includes) + * fixed some compilation problems with local variable optimizations + * put the mudlib/ directory back to the default one + * fixed a bug that was disabling the while_dec optimization + * efun::new() is legal again + * the type info in functions() are now strings + * variables now has an optional flag just like functions + * fixed a bug in replace_string() that would not copy the elements + which matched the search string which were not replaced in the + case when the replace string is longer than the search string + +Thu Jun 15 09:15:23 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6a2 + * updated with respect to v21.5b2 + * made functional procedures in LPC->C static so they don't interfere + across multiple files + * fixed a bug that inserted extra to_int/to_float() calls even when + the expression had already been reduced as a constant, i.e. + 1 + 2.3 -> 3.3 and not to_float(3.3) + * reorganized the compiler's intermediate representation to be + easier to optimize/generate code from. nodes now have general + types like NODE_BINARY_OP instead of the old form. + * removed support for PRAGMA_EFUN + * optimized the last use of a local in a frame by transfering + instead of copying. If the last use is in a switch() or loop + it is ignored. The same trick is also done for use of a local + right before an assignment, as in: write(x); x = 1; + (only done when #pragma optimize is on) + * split F_LOOP_COND up into F_LOOP_COND_NUMBER and F_LOOP_COND_LOCAL + +Mon Jun 12 04:45:44 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6a1 + * expression function pointers, anonymous functions, and foreach + now work in LPC->C code. + * added class support in LPC->C code + * updated ccode.c with the icode.c cleanups + * added a warning for [x] and [y..x] when x is a negative constant + * optimized LPC->C string constants + * optimized the calling of efuns. All arguments are now checked + automatically. The format is now: + . efuns which _always_ take one arg have opcodes like eoperators + . New efun eops which includes the number of arguments F_EFUN0, + F_EFUN1, F_EFUN2, F_EFUN3 which is followed by the efun index + . F_EFUNV for efun calls using 4 or more args + * some reorganization and cleaning up of make_func.y to allow the + above + * inlined efun calling for efun pointers. This should make + (: efun, ... :) significantly faster than (: efun(...) :) + +--------------------------------------------------------------------------- +(v21.5a6 promoted to v21.5b1) + +Sat Jun 3 21:32:15 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.5a6 + * updated with respect to v21.4b11 + * fixed a bug in replace_string(x, y, z) when strlen(y)==strlen(z)==1 + and another one when strlen(z) < strlen(y) + * added a ... operator which expands an array into a list of arguments. + it is legal in varargs efuns, function calls, varargs efun pointers, + and array constants (the last can be useful; ({ x, y..., z }) is the + same as ({ x }) + y + ({ z }), but slightly faster) + * COMPAT_BUSTER: removed the apply() efun. A replacement is in the + (new) directory compat/simuls. Basically, apply(f, arr) is now + the same as evaluate(f, arr...) + * fixed the space saving code that only generates a return 0 if the + function doesn't end in a return to recognize the return_zero opcode + +Sat Jun 3 05:33:46 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.5a5 + * fixed a bug in call_all_other that would return zero for all items + other than the first + +Thu Jun 1 14:55:53 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.5a4 + * updated with respect to v21.4b10 + * COMPAT_BUSTER: If process_input returns a string, it behaves as + before. If it returns a non-zero integer, no further processing + will be done. In all cases, process_input will continue to be + called if it exists. + +Mon May 29 22:28:50 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.5a3 + * updated with respect to v21.4b9 + * fixed a crasher in call_all_other + +Sat May 27 02:44:33 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.5a2 + * updated with respect to v21.4b7 + * optimized replace_string(foo, bar, bazz) when strlen(bar) is 0 or 1 + +Fri May 26 15:58:23 1995 (tim@handel.princeton.edu (Beek)) + * created v21.5a1 from v21.4b6 + * added the following diffs from Symmetry with minor modifications: + . fixed type error messages to handle classes + . optimized merge_arg_lists + . optimized call_function_pointer a little + . optimized call_all_other + . support more general sscanf specifiers, including %(regexp), + as well as %s%x and %s%% having the typical non-greedy %s support + . small optimization to replace_program + . made it so that set_heart_beat(0) and set_heart_beat(1) behave + more consistently when called during a heart_beat + . implemented heart_beats as an array which saves ~12 bytes in + objects that don't have heartbeats + +--------------------------------------------------------------------------- +(v21.4a9 promoted to v21.4b1) + +Tue May 16 07:07:17 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4a9 + * fixed a crasher in calling sprintf("...%O...") before the + master had finished loading + * fixed a few bugs in LPC->C compilation of string switch statements + * fixed a problem with the GNUmakefile made by LPC->C + * implemented ranges in switch statements for LPC->C + * fixed a crasher in parse_command() + * fixed catch() to work again from LPC->C code + * fixed a crasher in dumpallobjects with respect to some function + pointers + * fixed a bug accidentally added last patchlevel which caused + arrays and mappings to not restore when the 'noclear' flag was + passed to restore_object + +Mon May 15 04:12:47 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4a8 + * fixed a bug that would truncate arrays/mappings sent over + MUD mode sockets + * added a missing #include of cfuns.h that caused undefined + identifier errors during LPC->C compilation + * specifying an address server in the config file is no longer + necessary + * fixed a crasher when the simul_efun object had no simuls in it + * fixed a crasher in implode(array, function) + * fixed a bug that caused catch() and function profiling to be + ignored + * fixed wierd behavior with respect to unterminated @ and @@ blocks + * fixed a problem that would cause logging to fail of the log dir + in the config file was specified as '/' + +Sat May 6 22:41:22 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4a7 + * updated with respect to v21.3b5 + * fixed a ref count problem in heart_beats() + * fixed a compilation problem for people who don't use 'local_options' + * put the v21 README into the distribution + * optimized implode_array + * recognize IAC IAC as a quoted IAC character; this has two effects: + . IAC can now be received by the mudlib + . window sizes with widths and heights of 255 work again + * fixed MUD mode sockets to work on machines where sizeof(long) > 4 + * optimized member_array(), string compares, string hashing etc + to check string length first; idea from Aragorn + * fixed load_object() to not error if the file doesn't exist, + also fixed the error messages to be better than 'Failed to load + file' in many places + * fixed a crasher in calling non-existent socket callbacks + * fixed a few syntax errors in ed commands to not dump you out of + ed + * Added a bunch of stuff to Bugs/Ideas files; I'm going to try to + keep them more up to date; dumped a lot of stuff from my todo list + there + * fixed generate_source() to not leak a file on some errors + * fixed a bunch of problems with the upper_case() contrib efun; + it was out of date with respect to counted strings + * added Magician's remove_interactive() efun to the contrib package + +Sat May 6 19:03:29 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4a6 + * added 'mixed implode(mixed *, function)' + /* sum all the elements in an array */ + int sum(int *x) { return implode(x, (: $1 + $2 :)); } + /* find the largest element */ + mixed max(mixed *x) { return implode(x, (: $1 > $2 ? $1 : $2 :)); } + /* with respect to an arbitrary function ... */ + mixed max(mixed *x, function f) { + return implode(x, (: evaluate($(f), $1, $2) > 0 ? $1 : $2 :)); + } + /* comma separated list of numbers */ + string list(int *x) { return implode(x, (: $1 + ", " + $2 :)); } + * cleaned up a lot of the Makefile dependencies + +Fri May 5 21:36:29 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4a5 + * fixed a typo in wrappedmalloc.h + * memmove() is now checked in edit_source -configure + * COMPAT_BUSTER: this_player() is zero is get_save_file_name(). + The apply is now get_save_file_name(string fname, object who) + * added foreach (, in ), which should behave + the same as k = keys(m); for (i = 0; i < sizeof(k); k++) { + x = k[i]; y = m[k[i]]; ... } + * fixed a bug that gave odd error messages for illegal simulefun + overrides + * returned options.h to the MudOS distribution options + * fixed crashers in terminal_colour() + +Fri May 5 03:25:54 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4a4 + * fixed some bad logic in rc.c that would sometimes write past + the end of it's temporary buffer (rc.c needs a rewrite....) + * fixed a Makefile bug that caused edit_source to try to include + configure.h + * added 'foreach ( in ) ' + . currently only legal when is an array + . foreach (x in y) { ... } should behave identically to + for (i = 0; i < sizeof(y); i++) { x = y[i]; ... } + with the exception that y is only evaluated once + * fixed another crasher in people going linkdead in ed + * added some output in edit_source.c related to local_options + * fixed a bug in replace_string() that would miss occurences at + the end of the string + * fixed a typo in the alpha fix from last release + * COMPAT_BUSTER: 'foreach' and 'in' are reserved words + * COMPAT_BUSTER: map_mapping now passes the key and the value + to the function + * crasher fix in the contrib efun pluralize(); also corrects a bug + that caused it to strip adjectives + * fixed a few typos in smalloc.[ch] + * added Symmetry's changes to testsuite's master and simul_efun obs + +Tue May 2 20:38:08 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4a3 + * fixed a bug that would ignore 'local_options' during compilation + * fixed a bug in the handling of _OPTIONS_H_ + * modified the OBJDIR rules not to recompile excessively + * rewrote the error context handling, propagating Symmetry's error + popping tricks everywhere, cleaning up the code, and removing + some ancient code + * fixed a bug in generate_source(string, ...) that produced an + error message where there shouldn't be one + * put ins_long() back in since 64 bit machines need it + * fixed some incorrect calls to add_message in DO_MSTATS and TRACE_CODE + * cleaned up user_parser; fixed some crashers + * COMPAT_BUSTER: It is now illegal to any of the following from a + verb action which return zero: + . call remove_action() + . destruct an object which defines commands + . move an object which defines commands + . move a living object + * cleaned up the mudlib error handler code; fixed a leak therein + * added ;'s in a few places in socket_efuns.c for strict ANSI + compilation + * optimized deallocate_string() in the same way free_string previously + was + * added Robocoder's patch to allow '\a' and '\e' (bell and escape) + * fixed the stringified efuns to set the type of the return value + to 'string' + * fixed a crasher in clear_notify() + * fixed a crasher in people going linkdead in ed + * fixed a bug that would add an extra object on previous_object(-1) + for lfun and functional pointers + +Tue May 2 19:34:55 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4a2 + * fixed a crasher when replace_string() was called on a string with + more than one reference, and the replacement was smaller than the + thing being replaced + * fixed addr_server to compile again + * fixed a crasher in string creation for the reworked efuns + * added a case for the new F_WHILE_DEC code in the disassembler + * slight optimization to replace_string :) + * sizeof(class) now returns the number of members, not zero + * fixed #undef OLD_ED compile + * New contrib efuns: string *variables(object), object *heart_beats() + +Sun Apr 30 03:53:32 EDT 1995 (tim@handel.princeton.edu (Beek)) + * created v21.4a1 from v21.3b1 + * updated with respect to v21.3b4 + * added Truilkan's optimized replace_string(): + should be '15% to 40% faster' depending on the use. + also modified it to work with counted strings, and slightly + optimized the brute force (pattern length == 1) case + * the logon() function is no longer required to exist + * rearranged the output of the driver a bit, and cleaned up + a lot of the related code. stdout and debug.log now both + get the same information (with the exception of some stuff + that only goes to stdout before debug.log is ready) + * removed a lot of fidgeting with the value of command_giver + COMPAT_BUSTER: the definition/existence of this_player() + changed in some places. + * COMPAT_BUSTER: A number of efuns now return strings instead + of dumping info to this_player(): malloc_status(), cache_stats(), + lpc_info(), mud_status(), dump_file_descriptors(), program_info(), + debug_info(), dump_socket_status() + * reorganized/rewrote varargs handling; default to the ANSI way + if possible + * function pointers can now be used for socket callbacks + * New Feature: if you have a file 'local_options', it will be used + instead of options.h. Also, edit_source will issue an error message + if an option has been added to options.h that you don't have a + setting for. + +--------------------------------------------------------------------------- +(v21.3a7 promoted to v21.3b1) + +Tue Apr 25 15:43:47 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.3a7 + * updated with respect to v21.2b8 + * added Robocoder's optimization to read_buffer() + * fixed a lot of things gcc -Wall complained about + * fixed a crasher in disassembling code involving classes + * fixed type checking to not give an error for missing type + for arguments when type checking is off + * fixed a bug which could cause type errors in non-type checked + functions, especially wrt 'return x;' + * fixed a problem that would cause edit_source -configure to run + on every make + * check return values and report file errors in edit_source -malloc + * configure checks for , and if DEBUG + is on (sgi prototypes for bzero, which is used by FD_ZERO is there) + * only add -lmalloc if malloc() isn't in a standard library + +Tue Apr 25 15:25:06 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.3a6 + * fixed misoptimizations of nullp() and undefinedp() + * fixed a bug in array subtraction, intersection, and other + operations (next person who uses & when they mean == will be + shot) + * fixed two typos in the build.MudOS script + +Sun Apr 23 18:53:24 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.3a5 + * updated with respect to v21.2b7 + * fixed a bug in the STRFUNCS check in ./build.MudOS + * fixed some compilation problems with string functions and + DEBUGMALLOC + +Sat Apr 22 21:38:11 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.3a4 + * fixed some compilation problems with DEBUGMALLOC tags in function + calls + * fixed a typo in the T_REFED optimization that would cause the + gamedriver to crash right after booting + * fixed save/restore of classes + * fixed reclaim_objects() to correctly handle destructed objects + as mapping keys; the equivalent of map_delete() is now done + on them + * optimized free_string() with some ideas from Armand@TMI-2 + +Fri Apr 21 02:06:38 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.3a3 + * updated with respect to v21.2b6 + * optimized free_svalue() and assign_svalue_no_free() by + handling all refed objects similarly and saving a switch() + * fixed some compilation problems in interpret.c + * fixed some of the tagged routines to depend on DEBUGMALLOC, + not DEBUG + * fixed the external declaration of svalue_strlen_size + +Tue Apr 11 12:23:36 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.3a2 + * updated with respect to v21.2b5 + * fixed a variable name clash (type_names) between interpret.c and + compiler.c + * edit_source -configure now checks for the existence of strerror() + for better POSIX compatibility + * fixed catch() to work from LPC->C code + * if the compiler found is 'cc', check if it is gcc and if so use + gcc's optimization flags + * MAX_USERS no longer exists; instead, space is allocated as needed. + a limit should probably be enforced by the mudlib to avoid running + out of file descriptors ... + * new efun alias: this_user() == this_player() + * compile hash.o with optimization since it is used in the main + driver as well as edit_source + * added an optional flag to the functions() contrib efun: + functions(object, 1) returns: + ({ "function_name", num_arg, ret_type, arg1type, arg2type, ... }) + where the types are the type numbers given by typeof() + * COMPAT BUSTER: map_mapping now passes the value, not the key, + to the function pointer. + * evaluate() and apply() now return 'mixed' and don't need casting + with CAST_CALL_OTHERS defined + * rewrote malloc'ed strings to be ref counted and remember their + lengths. This gives a factor of 2-5 speed gain on many string + operations at the cost of 4 bytes of memory per string. However, + the reference counts means that malloc'ed strings are not duplicated + when copied, so despite the new overhead, many muds may see a + reduction in memory used by strings. Note: If you are trying + to test this, note that check_memory() and mud_status() now + report ALL memory used by strings; previously only the memory + used by shared strings was reported, the memory used by malloc'ed + strings wasn't reported anywhere. + * made strings statistics optional since they can have an impact + on the speed of string operations. + * driver guru info: + where you used to do: now do: + x = (char *)DXALLOC(n+1, ... x = new_string(n, "foo") + FREE(x) FREE_MSTR(x) + x = DREALLOC(x, ... x = extend_string(x, ... + strlen(shared_string) SHARED_STRLEN(shared_string) + + note that string_copy() now returns a ref'd, counted string. + if you really do just want a copy of an area as a normal + allocated block, see alloc_cstring() + + Also, it isn't safe to assume you can write into a malloc'ed + string now. See unlink_string_svalue() if you need to do it. + * optimized explode() and implode() to use SVALUE_STRLEN to + find the length of their arguments + * removed some unused ed flags + * added a new ed set option 'verbose' which shows number of lines + and bytes in files, etc + * added a check not to add -lcrypt if crypt() is defined in libc.a + +Tue Apr 11 00:36:00 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.3a1 + * updated with respect to v21.2b3 + * successfully compiled and ran the driver with all loaded objects + compiled into the driver (LPC->C); the only things that may not + work are catch() and defining functionals/expression pointers + (although calling function pointers will work fine) + * fixed a typo in the type checking code generated for to_float/to_int + (LPC->C) + * precompiled objects now depend upon binaries which are saved with + the .B extension so they don't conflict with normal binaries + * fixed in generation of the following LPC->C code: + . while (i--) ... + . for or while (x < y) ... + * added support for (--x), (++x), void_assign_local, x--, (-x), (~x), + x[C compiled code + * generate_source() now sends precompiled objects into a mudlib/ + subdir of the binaries dir if passed an array of files, and + creates multiple source files there instead of one huge source + file. The mudlib/ dir can be copied unchanged into the driver + source dir and compiled. + * removed support for ALWAYS_SAVE_COMPILED_BINARIES + * made the output of lpc_info() more readable + * F_WHILE_DEC now uses up one less byte + * removed an unused version of find_status() + * fixed a bug in sprintf's column option that would omit a character + if a line was too wide + +---------------------------------------------------------------------------- +Thu Mar 30 15:45:30 EST 1995 + * promoted to beta status (see v21.1b1) + * updated with respect to v21 + * Two new contrib efuns: + . void store_variable(string name, mixed value) + . mixed fetch_variable(string name) + These can be used for simulating set(), implementing debuggers, + etc: + foo = bar <-> store_variable("foo", bar) + return foo <-> return fetch_variable("foo") + set(string foo, mixed bar) { + switch (foo) { + case "name": case "hp": + store_variable(foo, bar); + break; + default: + ... + * fixed a number of typos/problems with the Makefile/GNUmakefile + that would cause compilation to fail + * Added an option to have up to 5 external ports + These can be specified in the config file. The format is: + external_port_x : kind # + where x is 1, 2, 3, 4, 5; kind is telnet, binary, or ascii + and # is the port number. For compatibility, the line: + mud port : 5555 + is the same as + external_port_1 : telnet 5555 + 'telnet' ports act the same as previously. 'ascii' ports + send no telnet characters, and don't do any interpretation of + the text they receive except to pass it one line at a time + to process_input(). 'binary' ports act very much like 'ascii' + ports, except that buffers are passed to process_input() + * Added in a fix from Robocoder for using smalloc or bsdmalloc + with debugmalloc or wrappedmalloc; previous smalloc or bsdmalloc + was erroneously ignored and sysmalloc used + * Added in a fix from Jeearr for build.MudOS which would cause + it to die if GNU make wasn't present + * optimizations: + return 0 is now 1 opcode + loop conditions involving < + multiple pushes in a row compressed into a quick format + x == y, !(x != y), x < y, !(x >= y), x > y, !(x <= y), + x != y, !(x == y) in if statements and ( ? : ) + !x, x==0, etc in ( ? : ) + * connect() is now passed the port # to which the user connected + * reworked rc.c a bit + * changed all the references to NO_UIDS to PACKAGE_UIDS; this was + causing compilation to fail with NO_UIDS off + * re-indented interpret.c + * fixed compilation of functions(), replaceable() and pluralize() + (contrib) + * COMPAT_BUSTER: "efun", "new", and "asm" are no longer valid + function/variable names + * all type names are now valid in foo::bar + +Fri Mar 24 20:59:08 EST 1995 (tim@handel.princeton.edu (Beek)) + * bumped patchlevel to v21.2a6 + * updated with respect to v21.1b7 + * The build procedure has changed drastically: + (1) edit the top of build.MudOS to configure a few things. + You should only have to do this if you have an obscure + operating system or want to change INSTALL_DIR, etc + (2) "./build.MudOS" + The script will munge for a while, then print out the + configuration it determines. + (3) if you don't like what build.MudOS decided, edit the top + of Makefile/GNUmakefile. + (4) type make/gmake, as appropriate + (5) type make install, or move the binary to whereever you want it + * technical details: + The build process goes more or less as follows: + (1) ./build.MudOS determines enough system parameters to allow the + compilation of edit_source + (2) edit_source is built, then run to process options, configure + malloc, create various makefiles and check which libraries + and include files exist + (3) Makefile.MudOS is then executed in order to build the main + driver executable + * stage (2) of the compilation is run with optimization off, as + edit_source takes longer to compile than to run ... + * Both GNUmakefiles and Makefiles are generated from a common file. + developers should edit Makefile.master and then run 'make Makefiles' + if changes to the build process are wanted. + (This was actually added last pl, but now applies to 3 makefiles) + * modified terminal_type negotiation to comply with the relevant RFC's; + this may increase the number of systems it works with. + * added NAWS window size automatic negotiation; the callback is: + void window_size(int width, int height) + * optimized the pushing of call_out arguments + * added a missing prototype for c_generate_node() + * fixed/kludged errors in #include to report the right line number + * renamed DISALLOW_BUFFER_TYPE to NO_BUFFER_TYPE + +Wed Mar 22 23:37:55 EST 1995 (tim@handel.princeton.edu (Beek)) + * bumped patchlevel to v21.2a5 + * added a mudlib/ directory to hold LPC->C compiled code + * mudlib/ and packages/ compilation now use libaries to + avoid packages/*.c kludges and the like + * added Symmetry's diffs to allow for recursive class definitions, + allowing linked lists, etc to be constructed + * packages are now specified in options.h instead of fooling with + func_spec.c. This will work for any package, even ones not + included with MudOS (PACKAGE_AURORA, for example, will automatically + compile and use packages/aurora.c and packages/aurora.spec) + in addition, a #include in func_spec is no longer necessary + * removed all references to the MIRE package + * in the driver source: + NO_MUDLIB_STATS -> !PACKAGE_MUDLIB_STATS + SOCKET_EFUNS -> PACKAGE_SOCKETS + * Fixed a number of instances where messages including filenames + had no leading '/' + * added F_VOID_ASSIGN_LOCAL: x = ... is now a single opcode + * applied Robocoder's fix for a problem where 'continue' would + get confused in nested loops + * removed some useless code from F_VOID_ASSIGN + * removed make_malloc and make_func and replaced them with + edit_source; cleaned up the associated code + * added preprocess.c which centralizes some of the code used by + both lex.c and edit_source.c; more work needed here. Unfortunately, + it has to be #included since edit_source.c can't stand MALLOC + * COMPAT_BUSTER: removed a bunch of LPC predefines + SAVE_EXTENSION: use __SAVE_EXTENSION__ + USE_EUID: use ! __NO_UIDS__ + HAS_BUFFER_TYPE: use ! __DISALLOW_BUFFER_TYPE__ + HAS_SOCKETS: use __PACKAGE_SOCKETS__ + HAS_SHADOWS: use ! __NO_SHADOWS__ + HAS_DEBUGMALLOC: use __DEBUGMALLOC__ && __DEBUGMALLOC_EXTENSIONS__ + HAS_MATH: use __PACKAGE_MATH__ + HAS_PROFILE_FUNCTIONS: use __PROFILE_FUNCTIONS__ + HAS_MATRIX: use __PACKAGE_MATRIX__ + HAS_PRIVS: use __PRIVS__ + HAS_EACH: use __EACH__ + HAS_CACHE_STATS: use __CACHE_STATS__ + HAS_OPCPROF: use __OPCPROF__ + HAS_MUDLIB_ERROR_HANDER: use __MUDLIB_ERROR_HANDLER + HAS_MUDLIB_STATS:use ! __NO_MUDLIB_STATS__ + HAS_LIGHT: use ! __NO_LIGHT__ + * removed the debugging code from the identifier hash table code + since it appears to be bug free + * fixed a crasher in Robocoder's config file fix when lines were + missing from the config file + * consolidated some of the error reporting code + * both GNUmakefile and Makefile are now generated from Makefile.master + via GNUmakefile.pre and Makefile.pre; one side effect of this is + that you can use 'make Makefiles' to return your Makefile to + it's unedited state + * fixed a crasher in objects dested from some socket callbacks + +Sun Mar 19 02:32:56 EST 1995 (tim@handel.princeton.edu (Beek)) + * bumped patchlevel to v21.2a4 + * updated with respect to v21.1b6 + * REALLY added in the diffs from v21.1b5 (I forgot to run patch + last patchlevel) + +Sun Mar 19 02:32:56 EST 1995 (tim@handel.princeton.edu (Beek)) + * bumped patchlevel to v21.2a3 + * updated with respect to v21.1b5 + +Sat Mar 4 16:14:17 EST 1995 (tim@handel.princeton.edu (Beek)) + * bumped patchlevel to v21.2a2 + * updated with respect to v21.1b4 + * fixed compilation with #undef OLD_ED (object_ed_output() changed + to global scope; it's used by regexp_error()) + * fixed a bug that would incorrectly claim filenames had // in them + on some operating systems + * changed the above error message to say what the filename was :) + * COMPAT_BUSTER: privs_file is now called to get new privs for + virtual objects which are loaded. This is a bit of an oddity; + virtual objects actually get created twice, so it's hard to say + what should be done when. Possibly, mudlib_stats should be + also be reinitialized. Currently, they behave the same way + as the object returned from compile_file() which is inconsistent + with their filename (which was the old behavior of PRIVS as well) + The same problem exists with UIDS. This may change in the future. + +Sat Mar 4 16:14:17 EST 1995 (tim@handel.princeton.edu (Beek)) + * v21.2a1 created from v21.1b3 + * added code to not generate unreachable code in LPC->C generation + since SGI cc is very noisy about that and it happens a lot. + * protect special characters string constant case labels with '\' + when generating switch tables (LPC->C) + * fixed a cases for int switches to use the correct field (LPC->C) + * added more name mangling for switch table names so they don't + collide (LPC->C) + +---------------------------------------------------------------------------- +Wed Mar 1 18:14:01 EST 1995 (tim@handel.princeton.edu (Beek)) + * v21.1a5 promoted to beta status (see v21.1b1) + +Fri Feb 24 23:48:38 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.1a5 + * brought up to date with respect to v21b15 + * MASSIVE source cleanup + . 'arrays' are always refered to as arrays and never vectors/pointers + . all types now use foo_t syntax instead of struct foo + . several header files cleaned up and includes reorganized + . removed internal distinction between internal and external + programs (i.e. foo->p.i.bar is now foo->bar) + * centralized the processing of "/foo/bar.c" -> "foo/bar" + * removed support for RUNTIME_LOADING + * removed support for #undef NEW_FUNCTIONS + * in addition to the above, call_other pointers are gone. + (: x, y :) should be converted to (: call_other, x, y :) + the functionality remains unchanged, since that's all they really + did ... + * function pointers reorganized to use less memory (the size is + now variable based on the ammount of space needed, so a lfun + pointer can be significantly smaller) + * added OPCPROF_2D which keeps statistics on the most commonly + executed *pairs* of instructions + * regexp errors in regexp efuns now use error(), instead of printing + a message to this_player() which eroneously refers to ed ... + * LPC_TO_C now works for compiling objects into the driver. + (1) make sure #pragma save_binary is on in all objects to be compiled + (2) do a generate_source( ) + (3) copy /binaries/interface.c into your source dir (replacing the + provided one) + (4) recompile the driver + (5) the lpc_info() efun can be used to see if the new programs are + being used; other than that there should be no visible + difference, other than speed. + +Wed Feb 15 00:16:55 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.1a4 + * brought up to date with respect to v21b10 + * optimized the handling of the redefinable keywords 'efun', 'asm', + and 'new' + * Floats and ints are now automatically interconverted in the + following cases: + . Passing an int to a efun that takes a float and not an int, and + vice versa. Hence, sqrt(5) is legal. + . during initialization (as in float x = 5) + . Note: the above depends on compile time checks so if you exploit + mixed, etc to put an int in a float variable it will misbehave + * added limited support for classes (no member functions): + . structure definitions are stored in programs, which means they + can be passed down via inheritance + + . definition of the type is as follows: + class { + ; + ... + } + Ex: class my_first_class { int my_number; string my_string; } + + . declaring a variable of that type: + class ; + Ex: class my_first_class my_var; + + . instantiating a class: + = new(class ); + Ex: my_var = new(class my_first_class); + + . assigning to/using a member + -> = whatever ... + Ex: my_var->my_string = "It worked!"; + +Thu Feb 2 00:16:55 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.1a3 + * brought up to date with respect to v21b8 + * fixed the define used by cfuns.h to be different from the one + ccode.h used + * generate_source() now returns zero if there were compilation errors + * modified lower_case() to be slightly more portable and easier to + read + * inlined sapply() into apply() and apply_master_ob() by hand + * fixed a unrecognized #pragma crasher (the list wasn't terminated) + * fiddled with the default settings of options.h + * new contrib efuns: + string pluralize(string) + int file_length(string) + string upper_case(string) + +Thu Feb 2 00:16:55 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.1a2 + * brought up to date with respect to v21b7 + * added prototypes for all the c_* functions in ccode.c + * fixed the Makefile and GNUmakefile; removed obsolete files + * fixed generate_source() to use 'package fname;' instead of + 'package lpc_to_c;' when outputting to 'fname.c' and 'fname.spec' + * removed support for add_action(string); all it did was cause + errors anyway ... + +Thu Feb 2 00:16:55 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.1a1 + * brought up to date with respect to v21b5 + * COMPAT_BUSTER: removed the following options.h defines and + related behavior: OLD_HEARTBEAT, OLD_COMMAND, IGNORE_STRICT_PRAGMA + * COMPAT_BUSTER: STRICT_TYPE_CHECKING removed, use + PRAGMA_STRICT_TYPES as a default pragma + * COMPAT_BUSTER: ALWAYS_SAVE_BINARIES removed, use + PRAGMA_SAVE_BINARY as a default pragma + * COMPAT_BUSTER: move_object only takes 1 argument. + change move_object(this_object(), foo) to move_object(foo) + * LPC->C restored to working condition in a limited sense: + . new pragma #pragma efun ignored during regular compiling + . generate_source("source_file.c", "destination_file.c") + will compile "source_file.c" into an efun package made + up of "destination_file.c" and "destination_file.spec" + which can be linked into the driver + . note that it is illegal to do the following in an efun: + - call a local function -> this really can't be done + - call a simul_efun -> see above. Use efun:: to get around + write simul_efuns, etc; the driver won't complain about + illegal overrides while generating efun source + - use a global variable -> wait for future fixes + . LPC->C for objects doesn't work as of this release; only + creation of efuns in packages (useful for efunizing simuls) + . various things not supported yet; most notably functionals, + also string switches are supported but buggy; let me know + if you have other problems (esp. linking errors) + * added some internal stuff for structures; work in progress. + ignore the 1 shift/reduce conflict as it won't affect normal + LPC code. + * define_new_function() doesn't take the offset any more; this + is set explicitly where needed (2 places) + * argument types are actually saved why #pragma save_types is + used. They still aren't used yet tho. + * the format of switch parse trees was tweaked a bit to help + LPC->C compilation + * removed some unused i_generate_* functions + * push_indexed_lvalue in interpret.c is no longer static; compiled + C code needs it + * removed call_absolute() + * removed optimization flag, as it was unused + * rewrote pragma handling to work off of a table for easier addition + of pragmas + * added #pragma no_whatever which turns off the effect of + #pragma whatever + * added program argument types to md.c's list of permanent blocks; + not checked for leakage yet tho + +Thu Oct 2 01:29:26 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a14 + * fix for crasher when using a stale reference [reported by Tigran, + fix by Cloud] + * added implementation for filter(string, ...) + +Thu Sep 25 00:22:45 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a13 + * updated with respect to v22.1b14 + * improved warnings for code with no side effects + * changed optimizations for casted string constants to obey their + new type (just for consistency) + * resolve() can now take a function pointer as the second arg + +Wed Sep 10 01:14:10 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a12 + * added a Perl script compat/fixstatic that does a pretty good job + of converting static to nomask/protected + +Fri Sep 5 01:01:54 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a11 + * fixed ASCII external ports + * implemented MUD mode external ports (use "MUD" in the config file; + the mixed value gets passed to process_input) + * Parsing package changes: + . parse_sentence has an optional 3rd and 4th arg. + . The 3rd arg an array of objects to use in the parse instead of + the inventory of the environment of the user. Nested arrays + indicate containment, i.e. ({ ob1, ({ object inside ob1 }), + ob2, ob3, ({ first ob in ob3, second ob in ob3 }), ... }) + . The 4th argument is a mapping of string -> object which can + be used to supply nicknames and similar things. For this parse, + the 'object' acts as if 'string' were returned by pc_id_list(). + Entries that do not correspond to objects involved in the current + parse are ignored. + . fixed crashes in calling parse_refresh() from within a parser + callback. This is now the correct way to say "I'm returning this + answer, but ask again next time too" + +Wed Sep 3 13:30:07 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a10 + * updated with respect to v22.1b12 + * added missing 'return ret' in dump_socket_status() compat simul + * added parser packages fixes from Belgarat: + . new error: ERR_MANY_PATHS + returned when the number of possibilities needed to figure out + the meaning of a sentence exceeds a certain number (i.e. figuring + out certain highly ambiguous sentences isn't worth the CPU) + . PARSE_DEBUG can be used to get parser debugging without compiling + with DEBUG on + . evil new :c modifier that means just choose the first one you + find, for MUDs that want to make a mistake they will regret for + the rest of their lives, and be hated by their players + [nah, the maintainer would _never_ insert personal opinions into + the ChangeLog] + . "finally, two-object rules are examined more thoroughly and some + strange parse errors are eliminated. + + Changed semantic for applies: + direct_ and indirect_ applies can be called with 0s as the + object-type arguments. However it's now guaranteed that they + will be called with filled object arguments at least once during + the processing of a rule. + This allows objects to do explicit checks. + The direct_ and indirect_ applies should work as usual when they + receive 0 as object argument - they simply should return if the + object can or can not participate in the rule. + When the arguments are filled, the direct_/indirect_ applies can + perform thorough checks and return errors." + +Sat Aug 30 19:23:35 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a9 + * updated with respect to v22.1b11 + * fixed typo in '\\' handling in #defines; also added overflow check + * removed unused local in interpret.c + * added a #breakpoint preprocessor directive which calls + lex_breakpoint(), which does nothing. Useful for setting debugger + breakpoints that stop at a particular point in LPC compilation + +Wed Jul 23 18:30:27 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a8 + * added lex.c fixes from Burty: + . Handle '\\' correctly in defines + . preserve whitespace when expanding defines + . added quote checks in expand_all_defines() + +Thu May 15 14:14:42 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a7 + * reformatted the trace information with MUDLIB_ERROR_HANDLER off; + should be a bit easier to read now. + +Wed Apr 16 07:54:45 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a6 + * updated with respect to v22.1b8 + * object_present() now depends on #ifdef F_PRESENT instead of + NO_ENVIRONMENT so it disappears in the !NO_ENVIRONMENT && !F_PRESENT + case too. [idea from Jihad] + * name change: the file "Install" is now "INSTALL" to make it slightly + more visible + * fixed file.h to check file_incl.h for S_IS* first [fix from Leto] + * fixed the multiple class inherit code to work [fix from + Wodan@Discworld] + +Sun Apr 13 23:59:02 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a5 + * updated with respect to v22.1b7 + * fixed compilation with DEBUGMALLOC off + * (: efun::foo :) is now a valid efun pointer (assuming + master()::valid_override() doesn't complain) + +Sat Apr 12 15:06:30 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a4 + * updated with respect to v22.1b6 + * reclaim_objects() now cleans destructed this_player's and objects + out of the call_out() list + * commenting out input_to() or get_char() in func_spec.c now removes + all related code and variables + +Sun Apr 6 18:00:43 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a3 + * updated with respect to v22.1b5 + * classes can now be inherited multiple times, as long as the + definitions are consistent. + * fixed macro expansion to expand all arguments to macros immediately. + in particular, the ANSI stringize hack: + #define S(x) #x + #define STRINGIZE(x) S(x) + now works. E.g. after #define FOO bar, STRINGIZE(FOO) gives "bar" + and not "FOO" + +Wed Apr 2 15:11:10 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a2 + * updated with respect to v22.1b4 + * specifying both left and center justification in sprintf() now + pushes odd-length strings to the left instead of the right, e.g. + sprintf("%|8s", "foo") == " foo " + sprintf("%|-8s", "foo") == " foo " + * fixed crasher in calling socket_status() for a socket owned by + a destructed object [reported by Jihad] + +Tue Apr 1 13:59:43 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.2a1 + * added a slightly improved version of Tim's socket_status() efun. + Usage: + socket_status(int fd) returns an array with: + . ret[0] = (int) fd + . ret[1] = (string) state + . ret[2] = (string) mode + . ret[3] = (string) local address + . ret[4] = (string) remote address + . ret[5] = (object) owner + socket_status() returns an array of arrays; one for each socket. + * COMPAT_BUSTER: dump_socket_status() is gone; see compat/simuls + for a replacement [written using socket_status] + * socket status information is now cleared when the socket is closed + * fixed a bug that caused the close callback not to be called for + sockets that went through the CLOSING state + +---------------------------------------------------------------------------- +(v22.1a17 promoted to v22.1b1) + +Wed Jan 29 19:15:44 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a17 + * updated with respect to v22b27 + * fixed origin() to not return "call_out" for ORIGIN_INTERNAL + [reported by Jihad] + * added Marius' patch to make the parsing package work with + NO_ENVIRONMENT. Requires the following new master applies: + . parse_get_first_inventory(object ob) + { must behave like first_inventory(ob) } + . parse_get_next_inventory(object parent, object current) + { must behave like next_inventory(current); + parent == environment(current) in case you need it } + . parse_get_environment(object ob) + { must behave like environment(ob) } + [I'm not in love with this interface, but it will do for now] + * fixed a number of warnings + +Sat Jan 25 18:14:00 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a16 + * wrapped debug.c in #ifdef DEBUG_MACRO + * fixed crasher in file operations very early in the boot process + (before the master object loads); evidentally some libs actually + do this [both reported by Aragorn] + +Thu Jan 9 20:20:40 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a15 + * updated with respect to v22b26 + * added Raistlin@IE's patches to make the Win32 build procedure much + cleaner and not depend on so many GNU utilities; also did a wonderful + job of cleaning up the OS specific Win32 code. Fixes a number of + bugs, as well. + [ also, I can't test these, since I still don't have a Win32 + compiler, so I'd appreciate it if someone would let me know + if I messed something up ] + * fixed crasher in explode("foofoo", "foo") with SANE_EXPLODE_STRING + on and REVERSIBLE_EXPLODE_STRING off + * enhanced DEBUG_MACRO a bit; things are now in terms of identifiers + instead of impossible to remember numbers. To add a new one, + add the define to debug.h and the entry near the top of debug.c + Then do: + debug(mylevel, (...)) + new efuns: + . set_debug_level("mylevel") + . clear_debug_level("mylevel") + . debug_levels() [returns a mapping showing which messages are + enabled] + * A few changes to call_out: + . 0 delay call_outs are legal + . call_outs to the same time are in the order they are set up, not + in reverse order + . call_outs() from w/in call_outs() are relative to the time the + call_out was scheduled to go off, not the actual time; this is + because: + . the current time is slowly advanced as call_outs are executed + until the current time reaches the real time, instead of taking + a huge leap forward (in the event that the MUD is busy enough + that it is getting behind) + +Mon Dec 30 04:08:08 EST 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a14 + * fixed compilation with UIDS enabled [reported by Leto] + * added support for: + . allocate(int n, mixed v): + allocates an array of n elements. The i-th element is set to + evaluate(v, i) [i is in the range 0..n-1] + . allocate_mapping(array keys, mixed v): + - if v is an array, the returned array has keys 'keys' and values + 'v' (like 3.2.x's mkmapping) + - if it is a function, the the mapping has keys 'keys' and values + evaluate(v, key) + - otherwise, each key has the value 'v' + +Mon Dec 9 13:27:42 EST 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a13 + * updated with respect to v22b25 + * fixed a bug introduced recently which caused random() to always + return zero when drand48() was being used [reported by Leto] + * changed restore_object() to ignore ^M's at the end of lines in + save files + * added leading / to get_save_file_name() argument [reported by + Leto] + * fixed ARCH define for Linux/alpha + * fixed some implicitly defined functions which cause warnings on + the alpha + * fixed crasher/wild pointer write in code like: + foreach (string s, ref r in m) { map_delete(m, s); r = 0; } + +Sun Dec 8 23:50:32 EST 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a12 + * fixed a bug that would cause implicitly defined functions (ones + with no prototype in scope allowed by strict types being off) + to become invisible when inherited [reported and tracked by + Aragorn; also reported to affect NM muds on alpha drivers] + +Fri Nov 8 12:03:53 EST 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a11 + * updated with respect to v22b24 + * changed function pointers whose owners are destructed to be + ignored by call_out_list() and to not error when they fire. + Changed so that "foo" and (: foo :) have the same/similar + behavior. This isn't strictly an equivalent case, since + (theoretically) the function could be owned by a different + object than the one that did the call_out(), but that is + probably restricted to code doing call_out()s on behalf of + other objects anyway, and the runtime error is more annoying + than useful. [Suggested by Mordred@RoD] + * to_int() now returns undefined if no valid characters were converted. + * leading slash added to in_edit() [reported by Mystic] + * call srand48() if using drand48() to make random numbers [fix + from Turrican@DW] + * fixed compilation with NO_ADD_ACTION off or OLD_ED on, or + NO_BUFFER_TYPE on + * fixed the order of .o files for RUNTIME_LOADING + * fixed switch() when two cases differ by more than 2^31 + * better local_options error message + +Sat Nov 2 18:00:04 EST 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a10 + * use -m486 for pentium too + * added /'s in non mudlib error_handler traces + * fixed compilation with SUPPRESS_ARGUMENT_WARNINGS off + * receive() can now take a buffer as its argument (useful for + PORT_BINARY connections) + * fixed PROFILE_FUNCTIONS not to miss calls which miss the apply_low + cache + * fixed the driver not to loop if more than one -D option is passed + on the command line + * the debug.log file is no longer opened and closed every time it + needs to be written to; it is held open instead + * made the DEBUGMALLOC hash a bit more efficient + * fixed a bug that caused terminal_colour() not to strip spaces of + the starts of all lines, instead of just continuations of wrapped + lines + * parser callbacks went back to being ORIGIN_DRIVER, since they + are restricted to the 'can_', 'do_' and 'indirect_' namespaces + * various fixes to compilation with uids enabled + * add to the errors field of mudlib stats, even if a mudlib error + handler exists + * added parser support for 'a', 'any', 'my' + +Tue Oct 29 20:41:26 EST 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a9 + * updated with respect to v22b21 + * fixed possible crashers in code like 'call_out(something, 1, ref x)' + * fixed wild pointer into stack in code like: + mixed global; + void foo(mixed args...) { global = args; } + void create() { int x; foo(ref x); } + void inc(int ref x) { x++; } + void increment_random_location_on_stack() { inc(global...); } + * fixed the 'multiple access modifiers' warning not to consider + nomask and nosave to be access modifiers + * disabled the multiple access modifier error message with + SENSIBLE_MODIFIERS off + * fix for compiling with COMPRESS_FUNCTION_TABLES off from Mystic + * fixed compilation with FD6 code disabled + * fixed various crashers in the unused locals warnings + * various changes to func_spec.c so that built in efuns can be + disabled or renamed (e.g. remove or rename clone_object(), etc) + [idea from Mystic] + * added support for foreach (ref x in array), + foreach (x, ref y in mapping) + * better error message for indexing an illegal type using a range + * enabled the 'public' keyword with SENSIBLE_MODIFIERS on; it was + accidentally disabled. Also fixed the options.h entry to be + clearer + * added a SUPPRESS_ARGUMENT_WARNINGS option, to cut down on the + number of warnings generated by code which existed before + omitting the argument name was legal + * fixed terminal_colour() to treat multiple spaces as one space + when wrapping [reported by Jihad] + * fix for errors writing to flushing sockets + +Mon Oct 28 17:14:29 EST 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a8 + * COMPAT_BUSTER: ORIGIN_CALL_OUT is now ORIGIN_INTERNAL; in addition + most driver callbacks which do not use hard coded function names + also use ORIGIN_INTERNAL (add_action, socket callbacks, etc). + The practical fallout of this is that such routines may be static, + but *not* private. + * Use fd #6 instead of fd #3, since Solaris uses fd #3 while + starting the program [reported by Aragorn] + * fixed crasher in the parsing package generating the object list + [fix from Aragorn] + * It is now legal to use a class member of something of type mixed, + as long as it is unambigous (e.g. foo->x is ok as long as only + one class in scope has a member named 'x', or if 'x' is in the + same position in all classes in scope) + * Unused local variables now generate warnings + * function arguments no longer need to have names (and not naming + them inhibits 'unused' warnings) + * more than one access specifier (e.g. 'public private protected') + generates a warning + * If SENSIBLE_MODIFIERS is defined, then: + (1) 'static' no longer exists, and is replaced by 'nosave' and + 'protected' + (2) 'public' no longer means what it used to; it now means the + default visibility + * COMPAT_BUSTER: modifiers from a ':' declaration only + affect declarations which have no modifiers of their own. I.e. + 'private: nomask x;' no longer declares x to be private + * if VIRTUAL_RESERVED_WORD is defined, then 'virtual' is a + reserved word. Doesn't do anything, though. + * if REF_RESERVED_WORD is defined, the 'ref' can be used to declare + arguments to functions to be by reference instead of by value. + example: + int foo(int ref i) { + i++; + } + void create() { + int y = 1; foo(ref y); write(y); + } + prints '2'. Note that ref is required both in the declaration + and the call. + * fixed a bug that would cause compile errors when indexing something + of type 'mixed' + * added an 'efun_defined' pseudo function to the preprocessor. It + works just like 'defined', except that it looks up efuns. Example: + #if !efun_defined(snoop) + write("snoop efun not available.\n"); + #endif + +Mon Oct 21 17:48:12 EDT 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a7 + * updated with respect to v22b20 + * added Burty@Nanvaent's fixes for stringizing and macro + expansion + * added support for array &= and |= [idea from Avenger@CoreDump] + * added the object name to the "Saving successful match" parser + debugging message [idea from Aragorn] + * added Leto's SERVER_IP patch + * abort compilation after getting 5 errors, since we don't print + any more anyway, and the leaks this was supposed to prevent + were fixed years ago + * MudOS now checks if file descriptor #3 is a valid socket when + it starts up; if it is, it is used as a login port. + * added a 'portbind' program: + syntax: portbind [-p port#] [-d drivername] [-u uid] [-g gid] [args ...] + + All it does it bind the specified port, then execv() the driver, + passing the bound port as file descriptor #3 (see above). + drivername defaults to ./driver, and port# defaults to 23. + if uid or gid is specified, setuid() and setgid() are called + before exec'ing the driver. + + This means one can bind the telnet port by making portbind setuid, + and using: + + portbind -u -g config.mud + + to run the driver + +Wed Oct 9 15:26:37 EDT 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a6 + * updated with respect to v22b19 + * fixed compilation with NO_ADD_ACTION off, PRIVS on, or + PROFILE_FUNCTIONS on [re: the 'ob' global recently removed; + reported by Aragorn, Jihad, Avenger, etc] + * only do promotions (int)<->(float) on assignment, not op=; in + the second case the conversion will be done by the efun (if + legal) so there is no need. + +Mon Oct 7 16:43:45 EDT 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a5 + * hidden checks are now compiled out if set_hide() is disabled in + func_spec.c [idea from Avenger@CD] + * buffer code is compiled out if NO_BUFFER_TYPE is defined; also + fixed a few old references to DISABLE_BUFFER_TYPE. [idea from + Avenger@CD] Also, a binary port in the config file will cause + a sensible error message, and attempting to create a binary + socket will return EEMODENOTSUPP. + * removed the 'ob' global in efuns_main.c and related hacks with + respect to object_visible(); also fixes a bug in the return + value of environment() when it is hidden (and probably other + bugs elsewhere too) [reported by Jihad] + * fixed crasher in using the name of a file that doesn't exist + as the object in an efun callback (e.g. filter(({}), "foo", "bar")) + * fixed a couple compile problems and a crasher in + PACKAGE_MUDLIB_STATS [reported by Avenger@CD] + +Thu Oct 3 18:16:53 EDT 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a4 + * updated with respect to v22b17 + * need to include "master.h" in the uid package now [fix from Leto], + mas well as md.c, and master.c needs comm.h when tracing is + enabled + * fixed Makefiles on non-GNUmake systems to include the two new + files introduced last pl + * fixed crasher in the handling of refreshing the master object; + also the literals are cached but are *not* affected by + parse_refresh(). The reasoning is that if they change, it + would cause all hell to break loose with existing rules. + So parse_refresh() only needs to be called when the return + value of parse_command_users() changes. + +Tue Oct 1 19:14:42 EDT 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1a3 + * updated with respect to v22b16 + * fixed various crashers in the new snoop code [reported by Jihad] + * Many thanks to DrFeelgood for helping clean up header file + dependencies, and pointing out typos in options.h + * Warning for using both a 'port number : ' line and an + 'external_port_1 : ' line + * moved master object and function pointer handling to their own + files + +Mon Sep 30 18:56:54 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22.1a2 + * updated with respect to v22b15 + * #'foo is now the same as (: foo :) when COMPAT_32 is defined + [suggested by Bubbs] + * added NO_SNOOP option + * The requirement that a snooper must be interactive has been lifted + (though this isn't particularly useful unless RECIEVE_SNOOP is + also defined) [suggested by Larnen] + +Tue Jun 4 00:57:30 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22.1a1 + * COMPAT_BUSTER: #include <...> now no longer searches based on + relative paths; #include "..." still does. + * added Blackheart's diffs for using gdbm. See PACKAGE_GDBM for + details; probably this should be merged with Descartes' + PACKAGE_DB stuff ... + * added Avenger@CD's diffs for a union array operator (|) + (with trivial changes and a array stat fix) + Works analogously to &: + ({ 1, 2, 3 }) & ({ 2, 4 }) = ({ 2 }) + ({ 1, 2, 3 }) | ({ 2, 4 }) = ({ 1, 2, 3, 4 }) + * if ARRAY_RESERVED_WORD is defined, use "array" instead of "*" + in error messages [e.g. "Bad assignment ( mapping vs array )"] + * added Marius@Prilnari's fixes to lex.c: token pasting in + preprocessor macro expansion and adds token quoting + * added the -c option to the RUNTIME_LOADING compile flags since + it disappeared somehow + * Hidden object fixes for present() and environment() + * COMPAT_BUSTER: removed the tail() efun; a simul_efun is in the + compat dir + * added leading / to log_error() filenames + * cleaned up a bunch of duplicated code in array.c, and corrected + a few statistic bugs + * Parser package changes: + . added the object name to some parser debugging messages + . moved names of the applies to top of parser.c as #defines + . information from the master object is now cached + (parse_command_users, parse_command_prepos_list) + COMPAT_BUSTER: this means parse_refresh() must be called + if the information changes + . livings_are_remote() is now rechecked when a parse_refresh() + is done + +---------------------------------------------------------------------------- +(v22a41 promoted to v22b1) + +Mon May 27 16:20:09 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a41 + * variable information is now stored only in the program in which + the variable is defined; estimated compression ratio is about + 10:1. YMMV + * COMPAT_BUSTER: all inherits must now precede all global variable + definitions + * Added Ceda@IdeaExchange's fixes to the Windows '95 port + * fixed compilation error in c_prepare_catch() + * added a COMPRESS_FUNCTION_TABLES option, which compresses function + tables even further (estimated compression: 2-3x) at the cost of + slowing down function calls slightly (<5-10%) + * Fixed error() to correctly added a trailing \n to error messages + that are missing them + * Crasher fix in mapping composition (from Avenger@CoreDump) + +Sun May 26 00:37:08 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a40 + * internal function aliases are handled a little smarter, anticipating + more function table memory optimizations later + * fixed some crashers/problems involving #pragma optimize and some + compiler errors + * fixed a crasher in passing a filename that wasn't a string constant + to dump_prog() + * program_info() can now take an object as a first arg + * fixed a problem that would cause functions that were prototyped + before inherited to call the first function defined in the + object instead. + +Fri May 24 00:30:10 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a39 + * terminal_colour() now has two more optional args; the 3rd is the + width to wrap at, and the 4th is the indent for lines after the + first + * Fixed a crasher in some Too deep recursion errors + * Fixed crashers in constructs like while (...){ e = catch { break; } } + Jumping out of a catch block is now illegal. + * Fixed a crasher in program_info() when there are objects without + type information loaded + +Thu May 23 15:46:10 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a38 + * YYTYPE's size changed from 10 to 8, which should make the compiler + slightly more efficient. + * Fixed a bug in the generation of information to pass to mudlib + error handlers, which would cause an "Illegal array size" error + to be flagged before the error handler was even called. + * A few changes to $() notation: + . $() now moves out one level, not all the way out. So, to use a + local variable in a function from inside a doubly nested function + pointer, one needs to use $($()), e.g.: + string x; function f = (: (: $($(x)) :) :); + . Due to the above change, constructs like $($1) are now legal, and + work as one might expect, e.g.: + function f = (: (: write($($1)) :) :); // The inner function + // function pointer writes whatever is passed + // as the first arg of the outer one + function g = evaluate(f, "hi"); // creates a function pointer that + // writes "hi" + . this isn't really that complex; just remeber the rule "Each $() + temporarily removes one level of (: :) nesting." Familiarity + with functional programming is also recomended; (: (: :) :) + constructs are function pointers that create and return function + pointers when evaluated, _not_ simply composite functions. + . there is now a limit to function pointer nesting; the default is + 10. (Anyone who needs more is sick, but I thought I'd mention it) + . this also fixes a few crashers in using $() inside doubly nested + function pointers + +Mon May 13 23:16:05 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a37 + * Fixed a crasher in redefined functions + * added a STRIP_BEFORE_PROCESS_INPUT option for NO_ANSI + * fixed call_out() to pass zero args if zero args were specified, + instead of always passing a first arg of 0. (Usually, you'd never + notice, but it makes a difference when scheduling call_outs to + efun pointers to efuns which take no arguments) + * COMPAT_BUSTER: call_out_info() elements now have only 3 elements, + not 4; this is due to argument handling restructuring, as well + as mild security concerns for reference types. Maybe an option + will be added to get the arguments at a latter date if it is + desired. + * minor tweaks to the cleanup rules in the makefiles to get rid + of a few irrelevant files in the diffs + * added Maarten de Jong's documentation on compiling MudOS on + an Amiga using gcc as amiga/README-gcc. + * Changed ED_MAXLINE from 512 to 2048 + * Warning for using | or & when both arguments are "boolean" values + (e.g. the result of !, ==, !=, <, etc) + +Mon May 13 00:29:11 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a36 + * Fixed a crasher in memory_summary() when some objects are swapped. + * Fixed a crasher in check_memory() when BINARIES was #undef'd + * '\"' -> '"' in rc.c, since the former confuses emacs's hilit19 mode + * Better fix for the undefined function problem; the old solution + occasionally didn't work on some systems + * Fixed a problem with aliases in the function table that would + sometimes cause ... args not to be handled right + * Fixed a crasher involving prototypes preceding inherit statements + * program_info() now calculates the overhead of save_types as well + +Sat May 11 20:28:19 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a35 + * Reversed the function table search order in the new call_other + search code to be consistent with overload search order + * fixed a crasher in generated error messages for OBS rules which + have an indirect object + * added some entries to the files Bugs and Ideas + * load_binary() now sorts the function table so it is in the correct + order again since the order of shared strings is different from + when it was saved + * fixed a bug in the apply_low cache code which was accidentally using + 'prog', a global, with disastrous consequences when valid_save_binary + was called during the tail end of compilation. 'prog' is no longer + a global, and is returned where needed. + * fixed a bug which caused the identifier hash table to become trashed + when a function was used before it was defined + * 'make clean' now removes the testsuite's compile error log too + +Fri May 10 22:21:39 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a34 + * moved strput() from the parsing package to the main distribution + so it can be used internally + * Changed the building of compiler error messages to use strput(), + avoiding possible buffer overruns. Normalized the max length of + most compiler error messages to 256 bytes. + * Fixed compilation of PROFILE_FUNCTIONS + * Fixed a bug introduced last pl that caused the call_other cache + to malfunction + * Fixed octal escapes in strings; they were getting omitted + * Fixed a crasher in unterminated @ blocks (which, by the way, + had absolutely nothing to do with /V\\age) + +Tue May 7 14:23:45 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a33 + * moved the call to save the ed buffer of a user to before the + call to net_dead() + * Rewrote most of the function table handling code. Memory overhead + is now 15 bytes per function defined and 5 bytes per function + inherited, instead of 14 bytes per function inherited or defined + This cuts function table memory usage about in half on a stock + Lima lib. YMMV. Large open MUDs may see larger decreases; + the program_info() efun is a good way to check. + * Removed the last traces of OLD_PREVIOUS_OBJECT_BEHAVIOR + * The inheritance warning is now a bit clearer, e.g.: + foo() inherited from both /std/foo.c (via /std/bar.c) and + /std/bazz.c; using the definition in /std/foo.c + * Fixed the parsing package to not crash on reference to 'me' when + 'me' isn't within sight (admittedly, an odd situation :-) ) + * Fixed the testsuite to realize call_stack(3) now returns strings + * Tables of defined functions are now sorted, so they can be binary + searched; call_other time is now approximately O(m log n) instead + of O(m n) when the cache is missed (m = # of inherits, n = # of + functions in each) + * Removed OPTIMIZE_FUNCTION_TABLE_SEARCH: the new search method + is just as fast with no overhead + * added Raistlin's patch for a parser bug that would cause the + verb name to get inserted at the start of the 'real names' section + of parser callbacks + +Mon May 6 21:47:59 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a32 + * Small optimization to arrange_call_inherited() + * Small cleanup to C function pointer handling in dumpstat.c + * fixed a bug that caused dumpstat.c to ignore the size of array + headers + * Fixed the check_memory(1) table to be formatted nicer + * removed outdated code from program_info(); also fixed a bug that + caused the header size to be an absurd value + * fixed a crasher in function_owner() [ref count bug] + * added a memory_summary() contrib efun, which returns a mapping + of with entries: map["program name"]["variable name"] + Each entry contains the number of bytes used by that variable in + all active instances of that program. The size of shared structures + is divided up evenly between all values that reference it. + * Made the parser end of buffer checks a bit easier to maintain + * added parse_remove(string verb) which removes all rules for the + verb 'verb' which were added by this_object() + +Mon May 6 14:23:47 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a31 + * Added a FLUSH_OUTPUT_IMMEDIATELY option, which disables buffering + of output. Useful for debugging. + * Parsing package fixes: + . Fixed a bug that caused OBS rules to silently do nothing if + all the possible matches return errors beginning with '#' + . COMPAT_BUSTER: Now, zeros are passed for args that aren't + available yet (i.e. the indirect object in + direct_foo_obj_bar_obj()). Also, the arg which is currently + being worked on is now passed again (i.e. the direct object in + direct_foo_obj_bar_obj()) + Summary: "foo sword bar wiggle" would call: + . can_foo_obj_bar_obj(0, 0, "sword", "wiggle") + . direct_foo_obj_bar_obj(OBJ(sword), 0, "sword", "wiggle") + . indirect_foo_obj_bar_obj(OBJ(sword), OBJ(wiggle), "sword", + "wiggle") + among other things + . Fixed a number of bugs and buglets in disambiguating parses + and generating error messages, especially in cases where all of + the attempts produce nonsense + +Sun May 5 14:52:20 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a30 + * added NAME_TRUE_VARARGS flag to disassembly listings + * propagate NAME_TRUE_VARARGS up the inheritance tree to avoid + incorrect argument type errors when #pragma save_types is in use + * Parsing package fixes: + . made the maximum tokens per parser rule configurable at the top of + the parsing package [MAX_MATCHES] + . Optimizations to bitvec routines: bitvec_count(), get_single() in + the parser + . Fixed several spots where > MAX_NUM_OBJECTS involved in a parse + would cause crashes + . Fixed strput/strput_words to not write past the end of their buffer + when constructing long strings + . Fixed a crasher in parse_add_synonym() (though it wouldn't crash + until the synonym or parse_dump() was used) + +Thu Apr 25 01:32:46 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a29 + * fixed a bug that would cause call_outs which were exact + multiples of CALL_OUT_CYCLE to be delayed by one CALL_OUT_CYCLE + (sometimes could happen with call_outs that differed by a small + multiple of 2 from this) + * removed an unused local in repeat_string + * Fixed the parsing package to not crash when given a line containing + more than 256 words (now it just returns; the limit can be set at + the top of parser.c) + +Tue Apr 23 16:58:34 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a28 + * added a contrib efun: repeat_string(string s, int n) which + essentially does: sprintf("%-*'"+s+"'s", n, ""), but is readable. + e.g. repeat_string("-=", 10) == "-=-=-=-=-=-=-=-" + * redesigned call_outs slightly to allow constant time insertion + * added a CALLOUT_HANDLES option, which has the following effects: + . call_out returns an int, which can be passed to the following + two efuns: + remove_call_out(int handle) + find_call_out(int handle) + . Note that using the handle is more efficient than using the + ob, function name version + +Tue Apr 16 11:29:13 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a27 + * updated with respect to v21.7b21 + * Fixed sort_array to work correctly when called from a sort callback + +Sun Mar 10 05:32:19 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a26 + * updated with respect to v21.7b20 + * Added Raistlin@IE's fix for a bug in replaceable()'s one argument + case introduced in v22a23 which caused the one argument form to + quit working + * Fixed the ARCH define for 386bsd to not override the FreeBSD define + * changed "stuf!" -> "unknown architecture", when ARCH cannot + be determined + * added a classp() efun + * added support for \012 octal escapes and \x1e hex escapes in + strings and character constants + * added a comment about what the legal values of CFG_LIVING_HASH_SIZE + are + * crasher fix in the database package + * put a remove_interactive() call back in that accidentally got removed + at one point, which caused the driver to busy loop until a message + was sent to the object whose link had died + * COMPAT_BUSTER: two changes to call_stack(3): first, use strings + instead of numbers to be consistent with origin(); second, a bug + was fixed which was reporting the origin of the frame below the + indicated frame, not the frame itself. + * fixed compilation on systems that use _SC_PAGE_SIZE, not _SC_PAGESIZE + +Mon Mar 4 20:36:27 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a25 + * updated with respect to v21.7b19 + * added code to flush message queues when closing connections and + shutting down + * added a flush_messages(void | object) efun for manually flushing + message queues (during a long thread of execution, for example) + * fixed a bug that would cause some anonymous functions to not + be bindable + * fixed a crasher in recursive structures in error traces + * fixed a bug in sprintf() column mode that would wrap early if + a fit exactly in the width given + +Fri Mar 1 13:33:14 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a24 + * added Pace@Callandor's patch for REVERSIBLE_EXPLODE_STRING + * made PARSE_NUMERIC() into a routine instead of a macro, and + added support for scientific notation so that very large/small + floating point values restore correctly in restore_svalue() and + friends + +Mon Feb 5 09:43:36 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a23 + * updated with respect to v21.7b18 + * added a 'parallel' target for parallel makes when using gmake + * protected process_command against this_player() changing or + being destructed during process_input() and other nasty places + * removed the DEBUG_COMM_FREEZE code + * made the message queue flushing a bit lazier which should result + in smoother output and larger packet sizes + * added Descartes' database package + * added heart_beat_info() as a synonym for heart_beats() when + COMPAT_32 is on + * replaceable now can be optionally passed a second array argument + which is a list of function names to ignore; if the second arg + is left out, ({ "create" }) is assumed, which gives the old + behavior. + * added a function_owner(function) contrib efun. + * made #undef PACKAGE_SOCKETS/#define PACKAGE_EXTERNAL compilation + fail more gracefully + * fixed a parser callback bug that caused the 'real names' of + omitted args to be omitted too + * added an error message for using the debug mode of parse_sentence + when the driver wasn't compiled with DEBUG on + * fixed a bug that would cause parse_sentence() to return large + numbers instead of error strings + * fixed a typo in the Incorrect argument to type %s error message. + * fixed compilation when first_inventory() is disabled. + +Sat Feb 3 13:06:23 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a22 + * fixed seteuid() to pass the correct second arg to valid_seteuid() + * fixed the parsing package to not crash if parser_error_message() + doesn't exist + +Sun Jan 21 21:29:34 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a21 + * updated with respect to v21.7b16 + * The master object and simul_efun object can be updated again when + LPC_TO_C is not defined; patch from d.collins@ic.ac.uk + * unified the code handling function pointers/extra args in + various efuns; fixes crashers in rare cases. Also, sort_array() + now takes additional args which are passed down the the function, + like filter() et al. + * Added a check for the /usr/ucbinclude directory in ./build.MudOS; + Solaris needs from there + * Removed push_string() internally; push_constant_string() should + now only be used on string constants. The following changes + will preserve previous behavior: + . push_string(x, STRING_MALLOC) -> copy_and_push_string(x) + . push_string(x, STRING_SHARED) -> share_and_push_string(x) + . push_string(x, STRING_CONSTANT) -> push_constant_string(x) + . push_constant_string(x) -> share_and_push_string(x) + also, new function: push_shared_string(), which pushes and + references a known shared string. + * optimized the PORT_ASCII code a bit, and fixed some problems/loops + in it in the presence of bad input/errors + * fixed a bug that would cause message() to send messages/avoid the + wrong people if the target/avoid argument was _not_ an array, + and the function was called during the processing of another + message call whose target/avoid was also not an array + * removed XALLOC(), since it isn't used any more + * fixed mapping hash distribution and centralized the definition of + it + * optimized terminal_colour a bit + * optimized present() a bit; also fixed a leak in errors in id() + functions + * the message of the message() efun may now be of any type; this + actually was side effect of a fix that makes message() more + efficient :-) + * fixed a crasher in sprintf() table mode, when no number of + columns was specified (best fit) + * improved the packages/ and mudlib/ dependencies a bit + * configure.h is now remade if the information in 'uname -a' changes + * no longer log a 'double call to remove_interactive()' if an object + self-destructs in net_dead() + * There is no longer a limit on the number of sockets available; + if a limit is wanted it should be enforced in valid_socket() + * fixed sprintf() column mode to wrap at the column width, not one + before + * added a couple testsuite tests for sprintf table mode + * ./build.MudOS now prints an error message if an unknown kind of + build is attempted instead of silently assuming the default + * Parser changes: + . Two new restrictions; only one plural token is allowed per rule, + and only two object tokens are allowed per rule. The second may + disappear after I clean it up a bit. + . fixed a crasher in having more than MAX_NUM_OBJECTS involved in + a parse + . 'all' is now supported, also 'all of ...', 'all red swords', etc + . Cases where more than one object are matches, but only one makes + sense now work + . in callbacks, only objects that have been completely parsed can + be refered to. This means can_ and direct_ functions can't + reference the direct or indirect objects. The corresponding + spots in the argument list are missing. + . OBS rules use the _obj_ callbacks, with the exception of do_ + . error handling is now up to the master object via the + parser_error_message() apply. The first argument is a int + indicating the error type. The second is an object if this + message corresponds to part of a plural match, otherwise it + is zero. The third and following args depend on the error + type (from include/parser_error.h): + ERR_IS_NOT, ERR_NO_LIVING, ERR_NOT_ACCESSIBLE: + the noun used, and then 0/1 depending on whether there + ambiguity + ERR_AMBIG: + an array of objects that might have matched + ERR_ORDINAL: + The number that was refered to + ERR_THERE_IS_NO: + The string that couldn't be matched + ERR_ALLOCATED: + The error message returned by the mudlib + ERR_BAD_MULTIPLE: + nothing + [note: if you want more info that you think the parser might + have, let me know] + compat/parser_error.c has a decent approximation of the old + behavior + . do_foo_obs() gets an array of objects and error messages as + the arg corresponding to obs + . Returned error strings which start with '#' are assumed to + be nonsense messages, and aren't counted for the purpose of + ordinals and all. Useful to prevent 'get all' from printing + an error for yourself and the room, and to keep 'drop first sword' + from counting swords in the room. + +Sat Jan 20 15:47:06 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a20 + * removed process_string() and process_value(); simul_efuns are + availaible in the compat/simuls directory + * Fixed a memory leak in new(class foo, bar : baz, ...) + * fixed compilation problems in grammar.y.pre, shallow_inherit_list, + object.c + * fixed a typo: m_indices() is keys(), not values(); also added + m_delete + * pluralization fixes: 'are', 'mackerel' + * added Rust's timezone efuns to contrib; turned off by default + since they may not compile everywhere + +Wed Jan 3 16:12:50 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a19 + * updated with respect to v21.7b15 + * All values which were previously 'null' are now undefined instead; + nullp() is now exactly the same as undefinedp() + * added a COMPAT_32 option, which tweaks a few things to allow + some 3.2/3.2.1 code to be ported easier; see options.h for + what changes + * shallow_inherit_list() is now the same as inherit_list() [unless + COMPAT_32 is on, in which shallow_inherit_list() is the MudOS + behavior, and inherit_list() becomes deep_inherit_list() ] + * error message change: + Missing type -> Missing type for global variable + * Don't raise type mismatch errors for code of the form + 'identifier = expr'; 'Missing type for global variable' is good + enough + * Don't manually include and in + interpret.c; trust configure instead + * fixed a parser crasher in refering to 'noun', when more than + 4 adjectives are possible + * Fixed sprintf table mode to not stretch the last line to fit + the field width + +Wed Jan 3 14:29:43 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a18 + * fixed some serious flaws in class member lookup introduced in a17 + +Tue Jan 2 17:59:42 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a17 + * updated with respect to v21.7b14 + * fixed a crasher in the call_out leak fix from v22a1 + * turned off PACKAGE_EXTERNAL by default + * fixed a bug that caused the messages from saving the ed buffer + of an object which was dested while in ed to be appended to the + start of the next message sent to an object using ed. + * check for wait3() as well before using BSD signals + * removed wait() from lint.h since we include now + * fixed a couple bugs in the handling of functions in the memory + leak tracking code + * fixed a crasher in add_action(function) when the driver is + run with the -d flag + * fixed the addr_server not to crash if gethostbyname() fails for + some reason + * function(...) { ... } is now rebindable if it does not reference + local functions or global variables + * switch (...) { case 0: function() { break; }; }, + while (...) { function() { continue; }; }, + and similar pathological code is no longer allowed. + * bind(f, ob) now always succeeds if f is already bound to ob + * added back the fast version of livings() from v22a14 as a contrib + efun named_livings(); also fixed it to not return objects which + are no longer living() + * added class support in reclaim_objects() + * trailing justification is no longer added to the last line of + tables if no pad string was specified + * The following is now legal: + class foo { int x; string y; } + class foo f1 = new(class foo, x : 5); + class foo f2 = new(class foo, y : "foo", x : 1); + +Sat Dec 30 20:55:41 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a16 + * updated with respect to v21.7b13 + * changed the name of strerror to port_strerror to avoid prototypes + on SunOS, which prototypes the function but never defines it + * Removed a number of prototypes in lint.h for functions which are + also prototyped in SunOS headers now + * Fixed a bug that would prevent two way communication with external + commands + * Small optimization to the string case of socket_write + * Tracked down the real problem which caused sprintf() to crash + on empty tables; also fixed a crasher empty lines in column mode + * reversed the livings() patch, since not all living objects are + in the hash table + * #ifdef'd out some unnecessary code for when LPC_TO_C is off + * Remember to wait on our children, so we don't create zombies; + configure checks to figure out whether to do it the BSD or + Sys V way + * Removed some archaic defines from portability.h + * Changed the parse_sentence return codes again: + 1 - success + 0 - no such verb + -1 - verb exists, but no rule matched + -2 - a rule made sense, but can_ or direct_ failed + * Fixed a typo in the 'Illegal master object file name' error message + +Fri Dec 8 20:53:11 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a15 + * updated with respect to v21.7b12 + * changed livings() to walk the living hash table instead of the + full object list; idea from Jihad + * '\r' is now treated as whitespace by the compiler + * The success return code of parse_sentence is now 3, not 1. + * changed the return type of parse_sentence from 'int' to 'mixed' + * Fixed a crasher in using a function pointer as a read callback + * If PACKAGE_EXTERNAL is defined, then lines of the form: + + external_cmd_1: /usr/local/bin/gzip + + in the config file allow the mud to run the command using the + following efun: + + int external_start(int which, string args, + mixed read_cb, mixed write_cb, mixed close_cb) + + which is the command number (e.g. 1 from the example above) + args is the argument passed to the command. A socket is returned, + which can be used to communicate with stdin/stdout of the command. + + valid_socket() is passed "external" as the operation. + Up to 5 commands are allowed. + +Thu Dec 21 01:33:34 PST 1995 (gstein@svpal.org (Deathblade)) + * raised patchlevel to v22a14 + * fixed varargs by tweaking grammar.y.pre to not turn off the + TYPE_MOD_ARRAY flag for the varargs variable + * fixed sprintf() crasher when tables are used (Rust and Zakk) + +Thu Dec 7 12:30:20 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a13 + * fixed crasher in disabling a heart_beat during a heart_beat + * fixed sprintf() to not add trailing padding onto wrapped strings + * removed the break_string() efun. See compat/simuls/break_string.c + for a replacement. + * fixed a few more misoptimizations of last variable references by + the optimizer. + * added a warning for putting varargs args into a variable of + non-array type, also fix a bug that would cause type errors + if the prototype was in scope + * parse_sentence now returns: + 0 - no such verb + 1 - verb exists, but no rule matched + 2 - a rule made sense, but can_ or direct_ failed + in the cases where it used to return zero. + * parse_add_rule no longer has a third arg; it is always this_object() + * New parse efun: + parse_add_synonym(string new, string old): + . interpret the verb 'new' as if it were the verb 'old', and + parse using 'old's rules and routines + parse_add_synonym(string new, string old, string rule): + . 'new' acts like 'old' for only the rule 'rule', which must + have been previously added. Can be called multiple times. + +Wed Dec 6 18:00:15 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a12 + * fixed a crasher in passing a negative number as the field width + via the '*' specifier + * fixed a crasher in strings which were too long to fit into tables + in table mode + +Tue Dec 5 19:30:12 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a11 + * fixed two crashers in the table generation logic of sprintf(), + also fixed a bug that would cause the second and following + lines to be indented wrong + * fixed tables to fully fill the space allocated to them in + the format description + * The fill pattern for tables and columns always fills out the + entire 'box' now; e.g. + printf("%#|30'.'s\n", "apple\nbannana\ncherry\ndonut\nelf\nfruit\n") + gives: + ...apple....cherry......elf... + ..bannana....donut.....fruit.. + and not: + ...apple....cherry......elf + ..bannana....donut.....fruit + +Mon Dec 4 16:13:59 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a10 + * updated with respect to v21.7b11 + * moved values_list in function_context_t and node in decl to + align slightly better + * fixed the direct/dirent check to include std_incl.h in case it + has some defines needed by those files + * removed some really old and unused files of the compiler %union + (address and funp; the second of which predates me ...) + * small optimization to the lexer's handling of comments in + preprocessor lines + * major changes to sprintf.c: + . COMPAT_BUSTER: error messages are never returned any more, but + are thrown as errors instead. + . 'clean' is no longer used, so cannot be leaked + . COMPAT_BUSTER: "%^" is no longer special (for efficiency reasons, + as well as disagreements on the exact algorithm) + . The format string is never written into, eliminating the need + for savechars and related hacks; fixes a crasher in extremely + long strings in tables (>2k) + . The setjmp()/longjmp() is gone, since the cleanup can be done + on the next call to sprintf() now + . sprintf() is now officially not reentrant, and you will get + an error if you try. It probably crashed before if you tried + it. The only LPC code called by sprintf() is object_name(), + so this shouldn't be a problem + . on the whole, things should be significantly faster (slightly + more than 3 times faster on the small example I used), + mostly due to collecting sets of characters instead of adding + characters individually, and removing redundant length calculations + . large portions of the file are now actually readable + +Mon Nov 27 22:51:35 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a9 + * updated with respect to v21.7b10 + * COMPAT_BUSTER: The scope of for and foreach loop variables is now + only the inside of the loop. This also fixes a bug demonstrated + by the following: + { int i; for (int j;;) ; } { int i; } + * Some error message changes: + . Indexing on illegal type + -> Value being indexed is zero/Cannot index value of type 'foo'. + . Indexing a (string/array) with an illegal type + -> (String/Array) indexes must be integers + . Negative index passed to array + -> Array index must be positive or zero + +Wed Nov 22 12:52:13 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a8 + * updated with respect to v21.7b9 + * fixed a typo in ./build.MudOS (CC -> $CC) + * fixed a crasher in copying parse_command_* arrays which are empty + +Tue Nov 21 17:16:10 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a7 + * updated with respect to v21.7b8 + * fixed the ar test to make sure comptest.o exists in ./build.MudOS + * Leading and trailing whitespace in the values in the config file + is now ignored + +Wed Nov 15 14:41:20 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a6 + * updated with respect to v21.7b7 + * Better system for reporting bad malloc configurations (two malloc + packages, etc) and system configuration errors + * Report a redefinition error if classes with the same name are + inherited from different files + * Fixed the "Return type doesn't match prototype' error message + to only be printed once per occurance, not twice + +Tue Nov 14 12:53:51 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a5 + * updated with respect to v21.7b6 + * A few small tweaks to the testsuite cleanup + * fixed crasher in printing a string containing a '%' when + NONINTERACTIVE_STDERR_WRITE was defined + * some small cleanups to includes in socket_ctrl.c + +Tue Nov 7 17:50:22 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a4 + * updated with respect to v21.7b5 + * updated all the Makefiles with respect to Makefile.master + * minor change: use 0 instead of -1 for master_ob not loaded yet since + we no longer have to distinguish between unloaded/not loaded yet + * added MDmemcheck() which can be inserted into the source to do + internal memory consistency checks and abort if corruption is found + * added back some parser fixes that were missing due to reversed + patches + * Two new options to ./build.MudOS: + - ./build.MudOS develop -> turn on warnings and debugging code + - ./build.MudOS debug -> turn on debugging symbols and code + +Fri Nov 3 16:41:11 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a3 + * updated with respect to v21.7b4 + * couple changes to void handling, basically (int)->(void) is no longer + legal. The following are now errors: + . int f(void x) { ... } + . ... { void x; } ... + . void x; + . class foo { void x; } + . void f() { return 1; } + * defining a variable is now allowed in foreach, e.g.: + . foreach (string x, object y in z) + * fixed a crasher in errors in parse_* callbacks + +Sun Oct 8 19:48:21 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a2 + * updated with respect to v21.7b3 + * COMPAT_BUSTER: previous_object() == 0 and not this_object() in + heart_beats + * remove_call_out(/* no arg */) now returns 0 always, not -1 + * fixed a bug in the replace_string() with all 5 arguments in + some cases + * fixed a bug in restoring mappings which had arrays/mappings/ + floats as keys + * added some missing newlines to regexp() error messages + * fix to the center/left justify case for ints; remember to + add the padding to the right side as well in sprintf() + * more testsuite efun tests; finished through 'sprintf()' + or so + * made it illegal to undefine or redefine a global define like + __VERSION__ + * added a NO_RESETS option + * better error message for people who don't choose a malloc package + * fixed various crashers involving passing garbage back to the + parser inside arrays + * fixed leak in sprintf() for printing recursive structures; attempting + to do so no longer errors. + +Sun Oct 8 19:27:28 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v22a1 + * removed some outdated code (c_filter() and f_creator()) + * fixed a crasher in removing heart_beats during a heart_beat + * fixed a leak in call_outs with more than one extra argument + * fixed a leak in illegal arguments to call_stack() + * fixed set_light() to compile with NO_ENVIRONMENT (for the + ultimate in bleeding edge uses of archaic efuns :) ) + * added some checks to make compilation bomb more informatively + if two malloc packages/wrappers are specified + * cleaned up the signal handling code a bit + * fixed compilation of the matrix package + * fixed compilation with NO_ENVIRONMENT and !NO_ADD_ACTION + * fixed compilation with DO_MSTATS and SYSMALLOC + * fixed testsuite to compile and work with either setting of + INTERACTIVE_CATCH_TELL, NO_ADD_ACTION, PACKAGE_UIDS, + NO_ENVIRONMENT, NO_WIZARDS, PRIVS + * revamped the testsuite efun tests, and added tests for most of + the efuns 'a' through 'r' or so + * testsuite now logs compilation errors to /log/compile + +---------------------------------------------------------------------------- +v21.7a10 promoted to v21.7b1 + +Fri Sep 22 22:51:20 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7a10 + * fixed a bug that caused case 0: to not work in string switches + * fixed a typo in the unknown pragma error message + * rule priority is now calculated beforehand in the parser; this + fixes the precedence of some errors and allows earlier shortcutting + * 1st through 9th and first through ninth are now understood by the + parser + * "Which X do you mean?" is now more verbose + * 'myself' is now the same as 'me' + +Mon Sep 11 03:37:53 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7a9 + * fixed debug_info(2, ...) to put all the info in the string; + it was still sending some of it directly to this_user() + * slight optimization (condense two consecutive strlen() calls) + in regular expressions + * -DPEDANTIC now allows the use of inline to be turned off, since + gcc only defines __STRICT_ANSI__ when -ansi is used, and not + when -pedantic is used, but -pedantic complains loudly about inline, + and -ansi causes the SGI headers to break. Unfortunately, gcc + only gives some useful warnings when -pedantic is on + * fixed up some (unsigned char *) <-> (char *) problems + * fixed an optimizer bug that would clobber range expressions and + generate incorrect code + * Added documentation of makefile targets to the makefiles + * Added a .DEFAULT rule for the decoy makefiles so better errors + are generated when the wrong make is used with a target + * Made the SIGPIPE always reenable the handler, not just on Linux, + since other OS's (Solaris) behave this way as well + * Fixed the gettimeofday() check to use two args, so it wouldn't + fail on BSD based systems + * fixed a compile error in OPTIMIZE_FUNCTION_TABLE_SEARCH + * added a handler to ignore SIGFPE for those systems that raise it + * changed "create" to APPLY_CREATE in replaceable() + * fixed a parser crasher when parse_command_users() doesn't exist + * removed a if (pointer >= 0) check in the parser + * fixed a crasher in the 'last match to error' handling in the parser + * fixed a crasher in parse_command() when the object array had + non-objects in it + * fixed some NO_ENVIRONMENT compilation problems, especially when + NO_ADD_ACTION was NOT also defined. (add_action w/o environments + is a tad pointless, but it works now) + * fixed a bug that cause query_verb() to only return the matched + portion and not the entire verb + * fixed (s)printf() to not print destructed objects + +Fri Sep 8 03:34:50 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7a8 + * updated match_path() to know about the mapping changes + * preliminary OBS changes; OBS and LVS are recognized as tokens now; + currently they behave exactly the same as OBJ and LIV + * fixed a few uses of new_string as a variable name + * fixed a parser in generating arguments for parser callbacks + +Sun Sep 3 21:47:54 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7a7 + * cleaned up -Wall compile + * better code to check the string statistics, leading to: + * fixed the string stats bug(s); the figure should be correct again now + * improved the error message for "owner of function pointer destructed" + * removed the storing of the hash value in mapping nodes; mapping + memory usage should be down ~20%; also optimized a bit, so + most mapping operations should be faster + * crasher fix in %o case of parse_command() + +Wed Aug 30 19:36:35 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7a6 + * crasher fix in edit_source -configure from Valodin + * moved the CONFIGURE_VERSION define to the end of configure.h so + incomplete configure.h files are detected as corrupt + * removed the each() efun + * crasher fix in the optimizer (no local variables again) + * updated the tag info in check_memory(1) + * fixed check_memory() to not accidentally complain about the string + it is building + * fixed a bug in the mark and sweep memory debugging of the parser + * fixed a crasher in verb handlers that call parse_refresh() + * fixed a memory leak in objects that call parse_refresh() + * remember to add the real names when calling can_* callbacks + * fixed a bug that would cause parser error messages to be truncated + * fixed a memory leak in incoming MUD mode socket packets + * added a bunch of bug reports to Bugs + * fixed a line number bug in '\' + * fixed @@ to work again, evidentally noone has used in in over a + year since it hasn't worked since Robocoder added L_ARRAY_OPEN ... + * fixed odd errors if the end of the input buffer is hit while + parsing a macro expansion; found by Tensor + * fixed a line number bug in macro arguments with newlines in them + +Tue Aug 29 17:11:06 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7a5 + * updated with respect to v21.6b6 + * Merged in Descartes' diffs for Windows NT and Windows 95. Someone + please check these; I fixed/changed a bunch of things, but have no + way of testing them, and there are probably some mistakes. + * removed the old OS2 code, since noone ever got it to work ... + * added support for foreach (int in string) + * fixed a fatal error when a string > 64k in size was added to an + outbuffer. + * changed sprintf() to use outbuffers, speeding up sprintf a bit, + and expanding the size limit to 64k + * fixed type error for sizeof(array constant) + * it's now legal for an ed range to go past the end of the file; + any line # greater than the file size refers to the last line. + * fixed a bug that caused varargs contraction to not be done when + the call_other cache was hit, or when one does inh::foo() + +Sat Aug 26 19:37:38 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7a4 + * reorganized the function_t struct slightly to save a bit of memory + * added a warning for return types that don't match their prototypes; + currently ignores modifiers, since accepted usage is so gross in + this respect it isn't even funny. The next item might help: + * added "private:" which makes all function definitions/globals after + it private (until the next such section). Works with any type + modifier (static, private, protected, public, nomask, varargs) + * optimization fix: remember to put the replacement node in the tree + when doing: if (x) {} else y -> if (!x) y + * catch, time_expression, and __TREE__ now generate explicit code + to pop the value instead of doing it inside F_END_CATCH. This + makes the grammar a bit simpler, and generates better code for + catch { ... } and catch(x = ...), which are common cases + * fixed sizeof( ({ ... }) ) to preserve side effects inside the + array constant, for crappy code like sizeof( ({ i++ }) ), + which now compiles to: i++, 1 + * changed edit_source to include configuration info when doing tests, + so we can check for defines in include files + * run ranlib on the mudlib/ and packages/ files for systems that need/ + like it. + * added a WRD token in the parser, which is just like a STR but only + matches one WoRD. + * fixed a bug that chopped a letter off the results returned by STR + rules + * xxx_verb_yyy() callbacks now include the name of the verb in the + 'real names' part of the argument list, so for example "kick! beek" + would call (among other things): + can_verb_obj("kick", OBJ(beek), "kick!", "beek") + This should satisfy the people who have been mailbombing me asking + for a way to get at the real form of the verb :) + * fixed a few warnings in the parser + * When the return value of a construct is unused, and the construct + has no side effects, replace it by it's arguments (recursively) + possibly eliminating the construct entirely. + i.e. the following generates no code: + + int x; class bar y; array z; + ((({ ~x })[!x..foo)[(x*2)-1..] : ([1:2, 3:x])), -z[x]); + +Thu Aug 24 06:58:46 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7a3 + * configuration checks for broken libg.a Linux configurations, + , -ldl, RTLD_LAZY + * try cc -E -traditional-cpp as a possible preprocessor in build.MudOS + * Use ANSI USHRT_MAX instead of MAXSHORT if availiable + * reworked the handling of novalue efuns to be more robust; fixed + crashers in (void efun) || (void efun) among other things. + * Patches from Symmetry: + . made Config.Example match the testsuite setup + . fixed mapping case in dump_variable() for testsuite + . bugfix in resolve_path() in testsuite + . allow (: function() { return $1; } :) + . optimize x[y..<1] to x[y..] + . optimize dested obs in F_TRANSFER_LOCAL + . crasher fix for swapped objects in program_info() + . fixed disassembly of efun function pointers + +Mon Aug 21 03:58:32 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7a2 + * fixes from Symmetry for #undef RUNTIME_LOADING + * added Zakk's query_ip_port() contrib efun for finding out which + port an object connected to + * fixed a parser bug that would sometimes cause objects to fail + to be recognized the first time they were referenced. Many, many + thanks to Deathblade for helping to track down this one + * Added filenames to the parser error messages + * improved the handling of punctuation; verbs do NOT include + punctuation again, although this may change; stay tuned ... + +Thu Aug 3 20:25:27 EDT 1995 (tim@handel.princeton.edu (Beek)) + * created v21.7a1 from v21.6b3 + * valid_compile_to_c() in the master object now controls the use + of the generate_source efun. + * RUNTIME_LOADING works if your system supports dlopen()/dlsym(); + define it in options.h, then use generate_source(filename) + to load the object. Note that /lpc2c in the mudlib must be + a symbolic link to the driver source. Objects loaded in this + manner do not show up on lpc_info() [yet] + * The restriction which disallowed cloning of objects with + environments was removed + * destruct()'ing the master or simul_efun object now fails if a new + copy can't be loaded. This means that once the mud starts, a + master or simul_object is ALWAYS loaded. + * preliminary changes for disallowing calls to private functions; + you can still get past it in odd cases (e.g. calling the function + before you inherit it) More changes in a patchlevel or two. + * fixed a bug that caused // and /* to be interpreted as comments + within continuation lines in #define's + * fixed the F_WHILE_DEC optimization, and added support for it + in loops of the form 'for (...; x--; ...) { ... }'. Centralized + the handling of loop test optimization. + * optimize empty blocks for if's + * removed some mentions of 'actlab' in the docs + * added some new exit codes to the Exit_Codes doc + * added NO_ENVIRONMENT in options.h + * fixed the disassembly of F_LOOP_COND_NUMBER + * fixed a crasher/wierd behavior in using 'array' to declare arrays + * fixed a bug that made using a (blank) simul_efun object necessary + * added DEBUGMALLOC support for the parsing package + * added support for classes in copy() + * fixed a bug that chopped the last letter off of some + parser error messages + * updated the testsuite lib to run under the default driver + configuration + +---------------------------------------------------------------------------- +(v21.6a11 promoted to v21.6b1) + +Tue Jul 18 02:23:22 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6a11 + * updated with respect to v21.5b10 + * fix from Marius for a crasher in x[C + introduced during the compiler rewrite + * only include if MAXSHORT isn't in + * fixed a crasher in filter() + * fixed 'safe' -> 'saves' in pluralize() + * fixed TRACE compilation with NO_WIZARDS + * fixed regexp() to not crash on eight-bit characters in the format + on hosts where 'char' is signed + +Sat Jul 15 14:35:50 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6a10 + * updated with respect to v21.5b9 + * backed out the VOLATILE changes to compile_file.c since it relies + on a gcc extension + * fixed a crasher in true varargs functions with local variables + * added configure checks for and + * fixed a crasher in undefined functions + * COMPAT_BUSTER: filter_mapping() now passes the value as the + second element, just like map_mapping() + * fixed the Makefile to support options in grammar.y.pre; this + probably should be changed to use a %include "options_incl.h" + * added y.output and tmpdepend to 'make clean' + * fixed `system_libs` -> `cat system_libs` in the Makefile + * fixed a few DEBUG crashers in the parser package + +Thu Jul 13 04:05:49 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6a9 + * updated with respect to v21.5b8 + * backed out the VOLATILE changes to sprintf.c since it relies on a + gcc extension + * updated the Makefile not to define EDIT_SOURCE any more + * implemented the parser generated error messages for the parsing + package + * added the other half of varargs support, allowing the following: + void log(string file, string fmt, array args ...) { + write_file(file, sprintf(fmt, args ...)); + } + void foo(int x) { + log("/log/foo", "foo() was called with: %i\n", x); + } + +Thu Jul 6 03:52:27 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6a8 + * fixed to_float("illegal string") to always return 0.000000 + * added testsuite tests for to_int() and to_float() + * fixed a crasher in illegal indexes to array constants + * 'make depend' now works again when using GNU make + * edit_source -configure is never rerun if configure.h exists, + even if the file is out of date (it takes too long, and the + info shouldn't change). + * fixed a dependency problem that caused configure.h not to get built + * DEBUG is now visible to %ifdefs + * check for ; MAXSHORT is there on SGI + * removed some unused variables + * added __TREE__(expr) and __TREE__{ ... } which evaluate to arrays + representing the compiler's internal representation (IR) of the + given code. For example, + __TREE__(x + y) gives: ({ "binary op", "+", ({ "opcode_1", "local", + 0 }), ({ "opcode_1", "local", 1 }) }) + * catch { ... } and time_expression { ... } are now legal. + * if ARRAY_RESERVED_WORD is on, then 'array' now associates with the + type and not the var, for example: + int array x, y == int *x, *y and not int *x, y + * 'array' by itself is now allowed, meaning 'mixed *' + * fixed a bug in type checking that allowed 'x *' and 'x' to be + compatible in one order, but not the reverse + +Fri Jun 30 16:44:33 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6a7 + * updated with respect to v21.5b6 + * merged Makefile.MudOS back into the main Makefile + * added implode(array, function, mixed) where the third + argument is the value to start with, as in: + flatten(arr) { + if (arrayp(arr)) return implode(arr,(: $1 + flatten($2) :),({})); + else return arr; + } + * fixed make_func.y to give file and line numbers on fatal errors + * added configure checks for getrusage(), times(), gettimeofday(), + and fchmod() instead of using hard coded information + * figure out the correct type for UINT32 in configure + * removed the 0.9.18 compat efun package + * fixed a crasher in remove_interactive() + * disabled the lookat_rotate2 efun in the matrix package as it + uses more arguments than the compiler currently supports + +Tue Jun 27 01:10:27 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6a6 + * fixed the debug checks to not panic on nested foreach's + * fixed edit_source -configure to not get fooled by OSF's queer + non-standard BSD compatibility includes + * fixed a crasher in passing a bad argument to call_stack() + * optimized upper_case() and lower_case() + * fixed an ANSI style declaration in eoperators.c + * a couple minor fixes for alpha; also fixed DEBUGMALLOC to work + correctly on alphas + +Fri Jun 23 02:39:02 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6a5 + * updated with respect to v21.5b4 + * fixed a bug that caused sizeof(array constant) to always be 16 + +Tue Jun 20 16:25:14 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6a4 + * updated with respect to v21.5b3 + * fixed a few bug in using x[y..z] as an lvalue + * fixed an error in setting the return type of time_expression() + * added packages/parser.c, a flexible parsing system for interactive + fiction applications + * fixed a crasher in variables() + * added a workaround for getting EINTR while trying to seek the swap + file + +Sun Jun 18 11:33:07 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6a3 + * fixed a bunch of warnings from gcc -Wall + * fixed c_update_branch_list() to not generate unused labels + * COMPAT_BUSTER: + origin() and typeof() now return strings. If you use the defines + in the driver include/ files, you're fine (assuming you update your + includes) + * fixed some compilation problems with local variable optimizations + * put the mudlib/ directory back to the default one + * fixed a bug that was disabling the while_dec optimization + * efun::new() is legal again + * the type info in functions() are now strings + * variables now has an optional flag just like functions + * fixed a bug in replace_string() that would not copy the elements + which matched the search string which were not replaced in the + case when the replace string is longer than the search string + +Thu Jun 15 09:15:23 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6a2 + * updated with respect to v21.5b2 + * made functional procedures in LPC->C static so they don't interfere + across multiple files + * fixed a bug that inserted extra to_int/to_float() calls even when + the expression had already been reduced as a constant, i.e. + 1 + 2.3 -> 3.3 and not to_float(3.3) + * reorganized the compiler's intermediate representation to be + easier to optimize/generate code from. nodes now have general + types like NODE_BINARY_OP instead of the old form. + * removed support for PRAGMA_EFUN + * optimized the last use of a local in a frame by transfering + instead of copying. If the last use is in a switch() or loop + it is ignored. The same trick is also done for use of a local + right before an assignment, as in: write(x); x = 1; + (only done when #pragma optimize is on) + * split F_LOOP_COND up into F_LOOP_COND_NUMBER and F_LOOP_COND_LOCAL + +Mon Jun 12 04:45:44 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6a1 + * expression function pointers, anonymous functions, and foreach + now work in LPC->C code. + * added class support in LPC->C code + * updated ccode.c with the icode.c cleanups + * added a warning for [x] and [y..x] when x is a negative constant + * optimized LPC->C string constants + * optimized the calling of efuns. All arguments are now checked + automatically. The format is now: + . efuns which _always_ take one arg have opcodes like eoperators + . New efun eops which includes the number of arguments F_EFUN0, + F_EFUN1, F_EFUN2, F_EFUN3 which is followed by the efun index + . F_EFUNV for efun calls using 4 or more args + * some reorganization and cleaning up of make_func.y to allow the + above + * inlined efun calling for efun pointers. This should make + (: efun, ... :) significantly faster than (: efun(...) :) + +--------------------------------------------------------------------------- +(v21.5a6 promoted to v21.5b1) + +Sat Jun 3 21:32:15 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.5a6 + * updated with respect to v21.4b11 + * fixed a bug in replace_string(x, y, z) when strlen(y)==strlen(z)==1 + and another one when strlen(z) < strlen(y) + * added a ... operator which expands an array into a list of arguments. + it is legal in varargs efuns, function calls, varargs efun pointers, + and array constants (the last can be useful; ({ x, y..., z }) is the + same as ({ x }) + y + ({ z }), but slightly faster) + * COMPAT_BUSTER: removed the apply() efun. A replacement is in the + (new) directory compat/simuls. Basically, apply(f, arr) is now + the same as evaluate(f, arr...) + * fixed the space saving code that only generates a return 0 if the + function doesn't end in a return to recognize the return_zero opcode + +Sat Jun 3 05:33:46 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.5a5 + * fixed a bug in call_all_other that would return zero for all items + other than the first + +Thu Jun 1 14:55:53 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.5a4 + * updated with respect to v21.4b10 + * COMPAT_BUSTER: If process_input returns a string, it behaves as + before. If it returns a non-zero integer, no further processing + will be done. In all cases, process_input will continue to be + called if it exists. + +Mon May 29 22:28:50 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.5a3 + * updated with respect to v21.4b9 + * fixed a crasher in call_all_other + +Sat May 27 02:44:33 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.5a2 + * updated with respect to v21.4b7 + * optimized replace_string(foo, bar, bazz) when strlen(bar) is 0 or 1 + +Fri May 26 15:58:23 1995 (tim@handel.princeton.edu (Beek)) + * created v21.5a1 from v21.4b6 + * added the following diffs from Symmetry with minor modifications: + . fixed type error messages to handle classes + . optimized merge_arg_lists + . optimized call_function_pointer a little + . optimized call_all_other + . support more general sscanf specifiers, including %(regexp), + as well as %s%x and %s%% having the typical non-greedy %s support + . small optimization to replace_program + . made it so that set_heart_beat(0) and set_heart_beat(1) behave + more consistently when called during a heart_beat + . implemented heart_beats as an array which saves ~12 bytes in + objects that don't have heartbeats + +--------------------------------------------------------------------------- +(v21.4a9 promoted to v21.4b1) + +Tue May 16 07:07:17 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4a9 + * fixed a crasher in calling sprintf("...%O...") before the + master had finished loading + * fixed a few bugs in LPC->C compilation of string switch statements + * fixed a problem with the GNUmakefile made by LPC->C + * implemented ranges in switch statements for LPC->C + * fixed a crasher in parse_command() + * fixed catch() to work again from LPC->C code + * fixed a crasher in dumpallobjects with respect to some function + pointers + * fixed a bug accidentally added last patchlevel which caused + arrays and mappings to not restore when the 'noclear' flag was + passed to restore_object + +Mon May 15 04:12:47 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4a8 + * fixed a bug that would truncate arrays/mappings sent over + MUD mode sockets + * added a missing #include of cfuns.h that caused undefined + identifier errors during LPC->C compilation + * specifying an address server in the config file is no longer + necessary + * fixed a crasher when the simul_efun object had no simuls in it + * fixed a crasher in implode(array, function) + * fixed a bug that caused catch() and function profiling to be + ignored + * fixed wierd behavior with respect to unterminated @ and @@ blocks + * fixed a problem that would cause logging to fail of the log dir + in the config file was specified as '/' + +Sat May 6 22:41:22 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4a7 + * updated with respect to v21.3b5 + * fixed a ref count problem in heart_beats() + * fixed a compilation problem for people who don't use 'local_options' + * put the v21 README into the distribution + * optimized implode_array + * recognize IAC IAC as a quoted IAC character; this has two effects: + . IAC can now be received by the mudlib + . window sizes with widths and heights of 255 work again + * fixed MUD mode sockets to work on machines where sizeof(long) > 4 + * optimized member_array(), string compares, string hashing etc + to check string length first; idea from Aragorn + * fixed load_object() to not error if the file doesn't exist, + also fixed the error messages to be better than 'Failed to load + file' in many places + * fixed a crasher in calling non-existent socket callbacks + * fixed a few syntax errors in ed commands to not dump you out of + ed + * Added a bunch of stuff to Bugs/Ideas files; I'm going to try to + keep them more up to date; dumped a lot of stuff from my todo list + there + * fixed generate_source() to not leak a file on some errors + * fixed a bunch of problems with the upper_case() contrib efun; + it was out of date with respect to counted strings + * added Magician's remove_interactive() efun to the contrib package + +Sat May 6 19:03:29 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4a6 + * added 'mixed implode(mixed *, function)' + /* sum all the elements in an array */ + int sum(int *x) { return implode(x, (: $1 + $2 :)); } + /* find the largest element */ + mixed max(mixed *x) { return implode(x, (: $1 > $2 ? $1 : $2 :)); } + /* with respect to an arbitrary function ... */ + mixed max(mixed *x, function f) { + return implode(x, (: evaluate($(f), $1, $2) > 0 ? $1 : $2 :)); + } + /* comma separated list of numbers */ + string list(int *x) { return implode(x, (: $1 + ", " + $2 :)); } + * cleaned up a lot of the Makefile dependencies + +Fri May 5 21:36:29 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4a5 + * fixed a typo in wrappedmalloc.h + * memmove() is now checked in edit_source -configure + * COMPAT_BUSTER: this_player() is zero is get_save_file_name(). + The apply is now get_save_file_name(string fname, object who) + * added foreach (, in ), which should behave + the same as k = keys(m); for (i = 0; i < sizeof(k); k++) { + x = k[i]; y = m[k[i]]; ... } + * fixed a bug that gave odd error messages for illegal simulefun + overrides + * returned options.h to the MudOS distribution options + * fixed crashers in terminal_colour() + +Fri May 5 03:25:54 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4a4 + * fixed some bad logic in rc.c that would sometimes write past + the end of it's temporary buffer (rc.c needs a rewrite....) + * fixed a Makefile bug that caused edit_source to try to include + configure.h + * added 'foreach ( in ) ' + . currently only legal when is an array + . foreach (x in y) { ... } should behave identically to + for (i = 0; i < sizeof(y); i++) { x = y[i]; ... } + with the exception that y is only evaluated once + * fixed another crasher in people going linkdead in ed + * added some output in edit_source.c related to local_options + * fixed a bug in replace_string() that would miss occurences at + the end of the string + * fixed a typo in the alpha fix from last release + * COMPAT_BUSTER: 'foreach' and 'in' are reserved words + * COMPAT_BUSTER: map_mapping now passes the key and the value + to the function + * crasher fix in the contrib efun pluralize(); also corrects a bug + that caused it to strip adjectives + * fixed a few typos in smalloc.[ch] + * added Symmetry's changes to testsuite's master and simul_efun obs + +Tue May 2 20:38:08 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4a3 + * fixed a bug that would ignore 'local_options' during compilation + * fixed a bug in the handling of _OPTIONS_H_ + * modified the OBJDIR rules not to recompile excessively + * rewrote the error context handling, propagating Symmetry's error + popping tricks everywhere, cleaning up the code, and removing + some ancient code + * fixed a bug in generate_source(string, ...) that produced an + error message where there shouldn't be one + * put ins_long() back in since 64 bit machines need it + * fixed some incorrect calls to add_message in DO_MSTATS and TRACE_CODE + * cleaned up user_parser; fixed some crashers + * COMPAT_BUSTER: It is now illegal to any of the following from a + verb action which return zero: + . call remove_action() + . destruct an object which defines commands + . move an object which defines commands + . move a living object + * cleaned up the mudlib error handler code; fixed a leak therein + * added ;'s in a few places in socket_efuns.c for strict ANSI + compilation + * optimized deallocate_string() in the same way free_string previously + was + * added Robocoder's patch to allow '\a' and '\e' (bell and escape) + * fixed the stringified efuns to set the type of the return value + to 'string' + * fixed a crasher in clear_notify() + * fixed a crasher in people going linkdead in ed + * fixed a bug that would add an extra object on previous_object(-1) + for lfun and functional pointers + +Tue May 2 19:34:55 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4a2 + * fixed a crasher when replace_string() was called on a string with + more than one reference, and the replacement was smaller than the + thing being replaced + * fixed addr_server to compile again + * fixed a crasher in string creation for the reworked efuns + * added a case for the new F_WHILE_DEC code in the disassembler + * slight optimization to replace_string :) + * sizeof(class) now returns the number of members, not zero + * fixed #undef OLD_ED compile + * New contrib efuns: string *variables(object), object *heart_beats() + +Sun Apr 30 03:53:32 EDT 1995 (tim@handel.princeton.edu (Beek)) + * created v21.4a1 from v21.3b1 + * updated with respect to v21.3b4 + * added Truilkan's optimized replace_string(): + should be '15% to 40% faster' depending on the use. + also modified it to work with counted strings, and slightly + optimized the brute force (pattern length == 1) case + * the logon() function is no longer required to exist + * rearranged the output of the driver a bit, and cleaned up + a lot of the related code. stdout and debug.log now both + get the same information (with the exception of some stuff + that only goes to stdout before debug.log is ready) + * removed a lot of fidgeting with the value of command_giver + COMPAT_BUSTER: the definition/existence of this_player() + changed in some places. + * COMPAT_BUSTER: A number of efuns now return strings instead + of dumping info to this_player(): malloc_status(), cache_stats(), + lpc_info(), mud_status(), dump_file_descriptors(), program_info(), + debug_info(), dump_socket_status() + * reorganized/rewrote varargs handling; default to the ANSI way + if possible + * function pointers can now be used for socket callbacks + * New Feature: if you have a file 'local_options', it will be used + instead of options.h. Also, edit_source will issue an error message + if an option has been added to options.h that you don't have a + setting for. + +--------------------------------------------------------------------------- +(v21.3a7 promoted to v21.3b1) + +Tue Apr 25 15:43:47 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.3a7 + * updated with respect to v21.2b8 + * added Robocoder's optimization to read_buffer() + * fixed a lot of things gcc -Wall complained about + * fixed a crasher in disassembling code involving classes + * fixed type checking to not give an error for missing type + for arguments when type checking is off + * fixed a bug which could cause type errors in non-type checked + functions, especially wrt 'return x;' + * fixed a problem that would cause edit_source -configure to run + on every make + * check return values and report file errors in edit_source -malloc + * configure checks for , and if DEBUG + is on (sgi prototypes for bzero, which is used by FD_ZERO is there) + * only add -lmalloc if malloc() isn't in a standard library + +Tue Apr 25 15:25:06 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.3a6 + * fixed misoptimizations of nullp() and undefinedp() + * fixed a bug in array subtraction, intersection, and other + operations (next person who uses & when they mean == will be + shot) + * fixed two typos in the build.MudOS script + +Sun Apr 23 18:53:24 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.3a5 + * updated with respect to v21.2b7 + * fixed a bug in the STRFUNCS check in ./build.MudOS + * fixed some compilation problems with string functions and + DEBUGMALLOC + +Sat Apr 22 21:38:11 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.3a4 + * fixed some compilation problems with DEBUGMALLOC tags in function + calls + * fixed a typo in the T_REFED optimization that would cause the + gamedriver to crash right after booting + * fixed save/restore of classes + * fixed reclaim_objects() to correctly handle destructed objects + as mapping keys; the equivalent of map_delete() is now done + on them + * optimized free_string() with some ideas from Armand@TMI-2 + +Fri Apr 21 02:06:38 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.3a3 + * updated with respect to v21.2b6 + * optimized free_svalue() and assign_svalue_no_free() by + handling all refed objects similarly and saving a switch() + * fixed some compilation problems in interpret.c + * fixed some of the tagged routines to depend on DEBUGMALLOC, + not DEBUG + * fixed the external declaration of svalue_strlen_size + +Tue Apr 11 12:23:36 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.3a2 + * updated with respect to v21.2b5 + * fixed a variable name clash (type_names) between interpret.c and + compiler.c + * edit_source -configure now checks for the existence of strerror() + for better POSIX compatibility + * fixed catch() to work from LPC->C code + * if the compiler found is 'cc', check if it is gcc and if so use + gcc's optimization flags + * MAX_USERS no longer exists; instead, space is allocated as needed. + a limit should probably be enforced by the mudlib to avoid running + out of file descriptors ... + * new efun alias: this_user() == this_player() + * compile hash.o with optimization since it is used in the main + driver as well as edit_source + * added an optional flag to the functions() contrib efun: + functions(object, 1) returns: + ({ "function_name", num_arg, ret_type, arg1type, arg2type, ... }) + where the types are the type numbers given by typeof() + * COMPAT BUSTER: map_mapping now passes the value, not the key, + to the function pointer. + * evaluate() and apply() now return 'mixed' and don't need casting + with CAST_CALL_OTHERS defined + * rewrote malloc'ed strings to be ref counted and remember their + lengths. This gives a factor of 2-5 speed gain on many string + operations at the cost of 4 bytes of memory per string. However, + the reference counts means that malloc'ed strings are not duplicated + when copied, so despite the new overhead, many muds may see a + reduction in memory used by strings. Note: If you are trying + to test this, note that check_memory() and mud_status() now + report ALL memory used by strings; previously only the memory + used by shared strings was reported, the memory used by malloc'ed + strings wasn't reported anywhere. + * made strings statistics optional since they can have an impact + on the speed of string operations. + * driver guru info: + where you used to do: now do: + x = (char *)DXALLOC(n+1, ... x = new_string(n, "foo") + FREE(x) FREE_MSTR(x) + x = DREALLOC(x, ... x = extend_string(x, ... + strlen(shared_string) SHARED_STRLEN(shared_string) + + note that string_copy() now returns a ref'd, counted string. + if you really do just want a copy of an area as a normal + allocated block, see alloc_cstring() + + Also, it isn't safe to assume you can write into a malloc'ed + string now. See unlink_string_svalue() if you need to do it. + * optimized explode() and implode() to use SVALUE_STRLEN to + find the length of their arguments + * removed some unused ed flags + * added a new ed set option 'verbose' which shows number of lines + and bytes in files, etc + * added a check not to add -lcrypt if crypt() is defined in libc.a + +Tue Apr 11 00:36:00 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.3a1 + * updated with respect to v21.2b3 + * successfully compiled and ran the driver with all loaded objects + compiled into the driver (LPC->C); the only things that may not + work are catch() and defining functionals/expression pointers + (although calling function pointers will work fine) + * fixed a typo in the type checking code generated for to_float/to_int + (LPC->C) + * precompiled objects now depend upon binaries which are saved with + the .B extension so they don't conflict with normal binaries + * fixed in generation of the following LPC->C code: + . while (i--) ... + . for or while (x < y) ... + * added support for (--x), (++x), void_assign_local, x--, (-x), (~x), + x[C compiled code + * generate_source() now sends precompiled objects into a mudlib/ + subdir of the binaries dir if passed an array of files, and + creates multiple source files there instead of one huge source + file. The mudlib/ dir can be copied unchanged into the driver + source dir and compiled. + * removed support for ALWAYS_SAVE_COMPILED_BINARIES + * made the output of lpc_info() more readable + * F_WHILE_DEC now uses up one less byte + * removed an unused version of find_status() + * fixed a bug in sprintf's column option that would omit a character + if a line was too wide + +---------------------------------------------------------------------------- +Thu Mar 30 15:45:30 EST 1995 + * promoted to beta status (see v21.1b1) + * updated with respect to v21 + * Two new contrib efuns: + . void store_variable(string name, mixed value) + . mixed fetch_variable(string name) + These can be used for simulating set(), implementing debuggers, + etc: + foo = bar <-> store_variable("foo", bar) + return foo <-> return fetch_variable("foo") + set(string foo, mixed bar) { + switch (foo) { + case "name": case "hp": + store_variable(foo, bar); + break; + default: + ... + * fixed a number of typos/problems with the Makefile/GNUmakefile + that would cause compilation to fail + * Added an option to have up to 5 external ports + These can be specified in the config file. The format is: + external_port_x : kind # + where x is 1, 2, 3, 4, 5; kind is telnet, binary, or ascii + and # is the port number. For compatibility, the line: + mud port : 5555 + is the same as + external_port_1 : telnet 5555 + 'telnet' ports act the same as previously. 'ascii' ports + send no telnet characters, and don't do any interpretation of + the text they receive except to pass it one line at a time + to process_input(). 'binary' ports act very much like 'ascii' + ports, except that buffers are passed to process_input() + * Added in a fix from Robocoder for using smalloc or bsdmalloc + with debugmalloc or wrappedmalloc; previous smalloc or bsdmalloc + was erroneously ignored and sysmalloc used + * Added in a fix from Jeearr for build.MudOS which would cause + it to die if GNU make wasn't present + * optimizations: + return 0 is now 1 opcode + loop conditions involving < + multiple pushes in a row compressed into a quick format + x == y, !(x != y), x < y, !(x >= y), x > y, !(x <= y), + x != y, !(x == y) in if statements and ( ? : ) + !x, x==0, etc in ( ? : ) + * connect() is now passed the port # to which the user connected + * reworked rc.c a bit + * changed all the references to NO_UIDS to PACKAGE_UIDS; this was + causing compilation to fail with NO_UIDS off + * re-indented interpret.c + * fixed compilation of functions(), replaceable() and pluralize() + (contrib) + * COMPAT_BUSTER: "efun", "new", and "asm" are no longer valid + function/variable names + * all type names are now valid in foo::bar + +Fri Mar 24 20:59:08 EST 1995 (tim@handel.princeton.edu (Beek)) + * bumped patchlevel to v21.2a6 + * updated with respect to v21.1b7 + * The build procedure has changed drastically: + (1) edit the top of build.MudOS to configure a few things. + You should only have to do this if you have an obscure + operating system or want to change INSTALL_DIR, etc + (2) "./build.MudOS" + The script will munge for a while, then print out the + configuration it determines. + (3) if you don't like what build.MudOS decided, edit the top + of Makefile/GNUmakefile. + (4) type make/gmake, as appropriate + (5) type make install, or move the binary to whereever you want it + * technical details: + The build process goes more or less as follows: + (1) ./build.MudOS determines enough system parameters to allow the + compilation of edit_source + (2) edit_source is built, then run to process options, configure + malloc, create various makefiles and check which libraries + and include files exist + (3) Makefile.MudOS is then executed in order to build the main + driver executable + * stage (2) of the compilation is run with optimization off, as + edit_source takes longer to compile than to run ... + * Both GNUmakefiles and Makefiles are generated from a common file. + developers should edit Makefile.master and then run 'make Makefiles' + if changes to the build process are wanted. + (This was actually added last pl, but now applies to 3 makefiles) + * modified terminal_type negotiation to comply with the relevant RFC's; + this may increase the number of systems it works with. + * added NAWS window size automatic negotiation; the callback is: + void window_size(int width, int height) + * optimized the pushing of call_out arguments + * added a missing prototype for c_generate_node() + * fixed/kludged errors in #include to report the right line number + * renamed DISALLOW_BUFFER_TYPE to NO_BUFFER_TYPE + +Wed Mar 22 23:37:55 EST 1995 (tim@handel.princeton.edu (Beek)) + * bumped patchlevel to v21.2a5 + * added a mudlib/ directory to hold LPC->C compiled code + * mudlib/ and packages/ compilation now use libaries to + avoid packages/*.c kludges and the like + * added Symmetry's diffs to allow for recursive class definitions, + allowing linked lists, etc to be constructed + * packages are now specified in options.h instead of fooling with + func_spec.c. This will work for any package, even ones not + included with MudOS (PACKAGE_AURORA, for example, will automatically + compile and use packages/aurora.c and packages/aurora.spec) + in addition, a #include in func_spec is no longer necessary + * removed all references to the MIRE package + * in the driver source: + NO_MUDLIB_STATS -> !PACKAGE_MUDLIB_STATS + SOCKET_EFUNS -> PACKAGE_SOCKETS + * Fixed a number of instances where messages including filenames + had no leading '/' + * added F_VOID_ASSIGN_LOCAL: x = ... is now a single opcode + * applied Robocoder's fix for a problem where 'continue' would + get confused in nested loops + * removed some useless code from F_VOID_ASSIGN + * removed make_malloc and make_func and replaced them with + edit_source; cleaned up the associated code + * added preprocess.c which centralizes some of the code used by + both lex.c and edit_source.c; more work needed here. Unfortunately, + it has to be #included since edit_source.c can't stand MALLOC + * COMPAT_BUSTER: removed a bunch of LPC predefines + SAVE_EXTENSION: use __SAVE_EXTENSION__ + USE_EUID: use ! __NO_UIDS__ + HAS_BUFFER_TYPE: use ! __DISALLOW_BUFFER_TYPE__ + HAS_SOCKETS: use __PACKAGE_SOCKETS__ + HAS_SHADOWS: use ! __NO_SHADOWS__ + HAS_DEBUGMALLOC: use __DEBUGMALLOC__ && __DEBUGMALLOC_EXTENSIONS__ + HAS_MATH: use __PACKAGE_MATH__ + HAS_PROFILE_FUNCTIONS: use __PROFILE_FUNCTIONS__ + HAS_MATRIX: use __PACKAGE_MATRIX__ + HAS_PRIVS: use __PRIVS__ + HAS_EACH: use __EACH__ + HAS_CACHE_STATS: use __CACHE_STATS__ + HAS_OPCPROF: use __OPCPROF__ + HAS_MUDLIB_ERROR_HANDER: use __MUDLIB_ERROR_HANDLER + HAS_MUDLIB_STATS:use ! __NO_MUDLIB_STATS__ + HAS_LIGHT: use ! __NO_LIGHT__ + * removed the debugging code from the identifier hash table code + since it appears to be bug free + * fixed a crasher in Robocoder's config file fix when lines were + missing from the config file + * consolidated some of the error reporting code + * both GNUmakefile and Makefile are now generated from Makefile.master + via GNUmakefile.pre and Makefile.pre; one side effect of this is + that you can use 'make Makefiles' to return your Makefile to + it's unedited state + * fixed a crasher in objects dested from some socket callbacks + +Sun Mar 19 02:32:56 EST 1995 (tim@handel.princeton.edu (Beek)) + * bumped patchlevel to v21.2a4 + * updated with respect to v21.1b6 + * REALLY added in the diffs from v21.1b5 (I forgot to run patch + last patchlevel) + +Sun Mar 19 02:32:56 EST 1995 (tim@handel.princeton.edu (Beek)) + * bumped patchlevel to v21.2a3 + * updated with respect to v21.1b5 + +Sat Mar 4 16:14:17 EST 1995 (tim@handel.princeton.edu (Beek)) + * bumped patchlevel to v21.2a2 + * updated with respect to v21.1b4 + * fixed compilation with #undef OLD_ED (object_ed_output() changed + to global scope; it's used by regexp_error()) + * fixed a bug that would incorrectly claim filenames had // in them + on some operating systems + * changed the above error message to say what the filename was :) + * COMPAT_BUSTER: privs_file is now called to get new privs for + virtual objects which are loaded. This is a bit of an oddity; + virtual objects actually get created twice, so it's hard to say + what should be done when. Possibly, mudlib_stats should be + also be reinitialized. Currently, they behave the same way + as the object returned from compile_file() which is inconsistent + with their filename (which was the old behavior of PRIVS as well) + The same problem exists with UIDS. This may change in the future. + +Sat Mar 4 16:14:17 EST 1995 (tim@handel.princeton.edu (Beek)) + * v21.2a1 created from v21.1b3 + * added code to not generate unreachable code in LPC->C generation + since SGI cc is very noisy about that and it happens a lot. + * protect special characters string constant case labels with '\' + when generating switch tables (LPC->C) + * fixed a cases for int switches to use the correct field (LPC->C) + * added more name mangling for switch table names so they don't + collide (LPC->C) + +---------------------------------------------------------------------------- +Wed Mar 1 18:14:01 EST 1995 (tim@handel.princeton.edu (Beek)) + * v21.1a5 promoted to beta status (see v21.1b1) + +Fri Feb 24 23:48:38 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.1a5 + * brought up to date with respect to v21b15 + * MASSIVE source cleanup + . 'arrays' are always refered to as arrays and never vectors/pointers + . all types now use foo_t syntax instead of struct foo + . several header files cleaned up and includes reorganized + . removed internal distinction between internal and external + programs (i.e. foo->p.i.bar is now foo->bar) + * centralized the processing of "/foo/bar.c" -> "foo/bar" + * removed support for RUNTIME_LOADING + * removed support for #undef NEW_FUNCTIONS + * in addition to the above, call_other pointers are gone. + (: x, y :) should be converted to (: call_other, x, y :) + the functionality remains unchanged, since that's all they really + did ... + * function pointers reorganized to use less memory (the size is + now variable based on the ammount of space needed, so a lfun + pointer can be significantly smaller) + * added OPCPROF_2D which keeps statistics on the most commonly + executed *pairs* of instructions + * regexp errors in regexp efuns now use error(), instead of printing + a message to this_player() which eroneously refers to ed ... + * LPC_TO_C now works for compiling objects into the driver. + (1) make sure #pragma save_binary is on in all objects to be compiled + (2) do a generate_source( ) + (3) copy /binaries/interface.c into your source dir (replacing the + provided one) + (4) recompile the driver + (5) the lpc_info() efun can be used to see if the new programs are + being used; other than that there should be no visible + difference, other than speed. + +Wed Feb 15 00:16:55 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.1a4 + * brought up to date with respect to v21b10 + * optimized the handling of the redefinable keywords 'efun', 'asm', + and 'new' + * Floats and ints are now automatically interconverted in the + following cases: + . Passing an int to a efun that takes a float and not an int, and + vice versa. Hence, sqrt(5) is legal. + . during initialization (as in float x = 5) + . Note: the above depends on compile time checks so if you exploit + mixed, etc to put an int in a float variable it will misbehave + * added limited support for classes (no member functions): + . structure definitions are stored in programs, which means they + can be passed down via inheritance + + . definition of the type is as follows: + class { + ; + ... + } + Ex: class my_first_class { int my_number; string my_string; } + + . declaring a variable of that type: + class ; + Ex: class my_first_class my_var; + + . instantiating a class: + = new(class ); + Ex: my_var = new(class my_first_class); + + . assigning to/using a member + -> = whatever ... + Ex: my_var->my_string = "It worked!"; + +Thu Feb 2 00:16:55 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.1a3 + * brought up to date with respect to v21b8 + * fixed the define used by cfuns.h to be different from the one + ccode.h used + * generate_source() now returns zero if there were compilation errors + * modified lower_case() to be slightly more portable and easier to + read + * inlined sapply() into apply() and apply_master_ob() by hand + * fixed a unrecognized #pragma crasher (the list wasn't terminated) + * fiddled with the default settings of options.h + * new contrib efuns: + string pluralize(string) + int file_length(string) + string upper_case(string) + +Thu Feb 2 00:16:55 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.1a2 + * brought up to date with respect to v21b7 + * added prototypes for all the c_* functions in ccode.c + * fixed the Makefile and GNUmakefile; removed obsolete files + * fixed generate_source() to use 'package fname;' instead of + 'package lpc_to_c;' when outputting to 'fname.c' and 'fname.spec' + * removed support for add_action(string); all it did was cause + errors anyway ... + +Thu Feb 2 00:16:55 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.1a1 + * brought up to date with respect to v21b5 + * COMPAT_BUSTER: removed the following options.h defines and + related behavior: OLD_HEARTBEAT, OLD_COMMAND, IGNORE_STRICT_PRAGMA + * COMPAT_BUSTER: STRICT_TYPE_CHECKING removed, use + PRAGMA_STRICT_TYPES as a default pragma + * COMPAT_BUSTER: ALWAYS_SAVE_BINARIES removed, use + PRAGMA_SAVE_BINARY as a default pragma + * COMPAT_BUSTER: move_object only takes 1 argument. + change move_object(this_object(), foo) to move_object(foo) + * LPC->C restored to working condition in a limited sense: + . new pragma #pragma efun ignored during regular compiling + . generate_source("source_file.c", "destination_file.c") + will compile "source_file.c" into an efun package made + up of "destination_file.c" and "destination_file.spec" + which can be linked into the driver + . note that it is illegal to do the following in an efun: + - call a local function -> this really can't be done + - call a simul_efun -> see above. Use efun:: to get around + write simul_efuns, etc; the driver won't complain about + illegal overrides while generating efun source + - use a global variable -> wait for future fixes + . LPC->C for objects doesn't work as of this release; only + creation of efuns in packages (useful for efunizing simuls) + . various things not supported yet; most notably functionals, + also string switches are supported but buggy; let me know + if you have other problems (esp. linking errors) + * added some internal stuff for structures; work in progress. + ignore the 1 shift/reduce conflict as it won't affect normal + LPC code. + * define_new_function() doesn't take the offset any more; this + is set explicitly where needed (2 places) + * argument types are actually saved why #pragma save_types is + used. They still aren't used yet tho. + * the format of switch parse trees was tweaked a bit to help + LPC->C compilation + * removed some unused i_generate_* functions + * push_indexed_lvalue in interpret.c is no longer static; compiled + C code needs it + * removed call_absolute() + * removed optimization flag, as it was unused + * rewrote pragma handling to work off of a table for easier addition + of pragmas + * added #pragma no_whatever which turns off the effect of + #pragma whatever + * added program argument types to md.c's list of permanent blocks; + not checked for leakage yet tho + diff --git a/fluffos-2.23-ds03/ChangeLog.beta b/fluffos-2.23-ds03/ChangeLog.beta new file mode 100644 index 0000000..f204388 --- /dev/null +++ b/fluffos-2.23-ds03/ChangeLog.beta @@ -0,0 +1,2072 @@ +Fri Dec 12 12:10:04 2003 (marius@mudos.org (Marius)) + * raised patchlevel to v22.2b14 + * made changes to fix building on Mac OS X 10.3 (Panther) + * fixed logon() in backend.c to check for the object's + destructed status before making the apply [reported by + Arren@Anarres] + * moved the #include of std.h to before the HAS_UALARM + check in ualarm.c [reported by Loriel@Lima] + * fixed pluralization of some words ending in f [reported + by Loriel@Lima] + * fixed pluralization of pants [reported by Malic@Lima] + * fixed std_incl.h to avoid varargs.h if __GNUC__ > 2 + [reported by Loriel@Lima] + * fixed reference counting in f_bind [reported by Beyond] + +Sun Sep 15 17:53:16 2002 (marius@mudos.org (Marius)) + * raised patchlevel to v22.2b13 + * added a newline after the BIGENDIAN define in edit_source. + * fixed extra_ref accesses in the parser package when DEBUG + is not defined [reported by Tigran@Lima Bean] + * #167: Sprintf missing vars [reported by Andrew@Nanvaent] + * #170: Fixed up some reference problems where dangling + pointers could be left in any number of places. [reported + by Uranus] + * #168: Buffer overflow on doing sprintf("%*d", 300, 1); + [reported by Andrew@Nanvaent] + * #171: Crasher caused by array overflow [reported by + Andrew@Nanvaent] + * #172: Crashers due to outbuf_* failing [reported by + Andrew@Nanvaent] + * #173: Crasher when heart_beats() is called [reported by + Andrew@Nanvaent] + * #180: copy() on a buffer performs no useful action + [reported by Beyond, fixed by Andrew@Nanvaent] + * #181: Memory allocation success not checked properly + [reported by Andrew@Nanvaent] + * #182: Telnet handling flaws [reported by Andrew@Nanvaent] + * #185: allocate_mapping() not freeing input arrays + [reported by Reio Remma] + * #186: check_memory() leaving a string with bad refs + [reported by Reio Remma] + * #178: Oddity in unlink_string_svalue() [reported by + Andrew@Nanvaent] + * #184: Crasher in debug mode while calling clean_up(). + [reported by Reio Remma] + +Thu Feb 7 18:39:16 2002 (marius@mudos.org (Marius)) + * raised patchlevel to v22.2b12 + * #152: Fixed a crasher using nested references. Fix supplied + by Avenger@AtP. + * #153: Fixed crasher in debug builds with an invalid assert. + [reported by Pickett@Sumu] + * #159, #162: Fixed a crasher in repeat_string() when the max + string length is exceeded [reported by Eleinor@Arkansia] + * Ported to Mac OS X (Darwin) + * #166: this_player() will now always be this_object() when + the net_dead apply is called from remove_interactive(). This + should fix the write() oddities reported by Uranus. I'm not + labelling this as a COMPAT BUSTER because previously there was + no guarantee what this_player() would be. + * #165: pluralizing -ff words gives incorrect -fves suffix + [reported by Avenger@AtP] + * #161: everyone can see hidden object in named_livings() and + heart_beats(). Applied the fixes suggested by Ben Hoogterp. + [reported by Eleinor@Arkansia] + +Fri Mar 30 17:14:07 2001 (marius@mudos.org (Marius)) + * raised patchlevel to v22.2b11 + * #143: Fixed crashes when destructing various objects involved + in APPLY_INIT calls. Based on patches from Mark G. Adams + * Removed the definition of FP_THIS_OBJECT from + include/function.h since it is not used anywhere and conflicts + with FP_HAS_ARGUMENTS [reported by Arren@AnarresII] + * #148: Disallow load_object() with a filename containing a # + (indicative of a clone). [reported by Pickett@Sumu] + * #149: Crash when removing a function from the simul_efun when + that function is also defined by another object that is then + inherited and recompiled the second time after the function is + removed from the simul_efun object (whew!) [reported by + Avenger@AtP] + * #141: __FILE__ cannot be included multiple times [reported by + Arren@Anarres] + * #140: Fixed a crasher in kill_ref(). Problem occured using a + ref in foreach on a string [reported by Uranus, test case that + finally exposed the problem reported by Pickett@Sumu] + * Fixed foreach() in LPC2C generated code. Updated it to add + the "new" support for the ref keyword in foreach. + * #48: sprintf() from master::error_handler() dumps int instead + of string in 'locals'. Should be fixed up now [reported by + Javelin@Vincent's Hollow] + +Mon Feb 12 16:09:42 2001 (marius@mudos.org (Marius)) + * raised patchlevel to v22.2b10 + * #129: Added SLC_NAMELIST to the telnet.h included with MudOS + for broken systems that are missing + [reported by Andrew@Nanvaent] + * #120: Fixed compilation problems when NO_RESETS is defined. + [reported by Arren@Anarres II] + * #139: Fixed a crasher when using a foreach ref within another + foreach loop [reported by Pickett@Sumu] + * #136: Fixed a problem with compiling a program after the + previous program had a compile error inside of a function + pointer [reported by Avenger@AtP] + * #131: Fixed some oddness with to_int(), in particular, a + single digit followed by a whitespace character would return + undefined which is incorrect [reported by + kriton@gameworkshop.com] + * #135: Macro names must begin with either an underscore or a + letter. Successive characters may be digits [reported by + Arren@Anarres II] + +Mon Nov 6 18:48:25 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.2b9 + * #104: Corrected the spelling of "ninth" which is used by + the parse_sentence() efun. [reported by lundberg@vr.net] + * #97: More fixes for get_char() when GET_CHAR_IS_BUFFERED is + enabled [fixes from Pelle Johansson] + * #111: Plural of "lotus" is "lotuses" [reported by + Turrican@Discworld] + * #109: Fixed inline program reference increments to use the + reference_prog() function. [Reported by Andrew@Nanvaent] + * #110: Fix a bad call to free_string_svalue() in + f_write_buffer(). The call should be free_svalue() instead. + [reported by Beyond] + * #103: Runtime errors in heart_beat will no longer stop the + entire process. The next heart_beat will run, call_outs + will run, and the time will continue to advance. This is a + bug that is older than old [reported by Scatter] + +Wed Sep 27 08:20:05 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.2b8 + * #83: Fixed get_char() when GET_CHAR_IS_BUFFERED is enabled. + Make sure that the string returned is null terminated and + TELOPT_SGA is handled properly [patch from Pelle Johansson] + * #84: Fixed a ref count problem with the connect() master + apply when 0 is returned. + * #86: Using default access modifiers, do not issue an error + if a conflicting modifier is used [reported by Mystic] + * #77: Fixed a crasher when calling map_delete() from filter() + on the mapping being filtered. [reported by Andrew@Nanvaent] + * #79: In certain cases generating a loop, a flag indicating + the code that follows is not reached was being erroneously + set, causing the code to not generate/compile properly + [reported by Uranus] + * #80: If a function is declared but not defined, don't enter + it in the function table when generating C source for LPC. + [reported by Uranus] + * #90: Fixed a problem with inheriting multiple objects that + each define classes and have functions with arguments using + those classes. Properly adjust the types for validating + arguments [reported by Randor@Aurora] + * #81: Filled in missing definitions for reference support for + LPC_TO_C [reported by Uranus] + +Thu Sep 21 14:16:49 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.2b7 + * #75: Fixed a typo in C_TRANSFER_LOCAL macro added in v22.2b6 + [reported by Uranus] + * #63: Fixed heart_beat errors for optimized builds. + [reported by scatter@thevortex.com] + * #71: For MySQL support, all string/char/text/blob field types + will now be returned as strings by default unless the field + has the BINARY modifier applied to it, in which case a buffer + will be returned. + * #76: Filenames containing '//' are now allowed -- multiple + slashes are stripped down to a single slash [patch from + Skullslayer@RoD] + * Loading a binary now checks the simul_efun date to see if it + has been modified (in addition to driver, includes, config, + etc.) [from Bugs] + +Mon Sep 18 20:19:20 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.2b6 + * #57: Fixed a problem with single quotes inside of a macro + expansion [reported by Mystic] + * #64: Fixed unresolved symbol c_transfer_local for LPC_TO_C. + Only used when LPC optimization is on [reported by Uranus] + * #63: Fixed an error in heart_beat causing heart_beat() to + get called repeatedly [reported by scatter@thevortex.com] + * #65: Added some intelligence to build.MudOS on FreeBSD to + try and determine if -export-dynamic or -rdynamic will work + for compiling. Old versions of FreeBSD do not support + them [reported by darren@nighttide.net] + * Enabled #pragma optimize + * #73: Fixed memory_summary() efun to handle recursive data + structures [reported by Avenger@AtP] + * If NO_BUFFER_TYPE is defined, MySQL BLOB fields will be + treated as TEXT fields. + * #50: Fixed a crasher with recursive inherits deeper than the + maximum call depth [reported by Beyond] + +Sat Sep 9 16:16:54 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.2b5 + * #16: 'ref' works in foreach again [originally reported by + Uranus] + * #54: Added a new search location for mysql.h to satisfy RPM + installs on Linux from MySQL.com. Also fixed edit_source to + search for libmysqlclient.so properly [reported by jytong] + * #49: Fixed oldcrypt() to actually be oldcrypt() when + CUSTOM_CRYPT is defined [reported by Beyond] + * Fixed a crasher when heart beats and the command_giver is + shadowed [reported by Andrew@Nanvaent] + * Removed Beek's expand_all_defines hack introduced in v22.2a3. + This caused an undesirable compat buster from older versions + of MudOS. Instead, fixed macro expansion to work according + to the ANSI C standard -- almost. The only major difference + now is that comments are not considered whitespace everywhere + that they should be. + +Sat Sep 2 09:40:38 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.2b4 + * updated with respect to v22.1pre4 + * #40: Fixed compilation error in add_action.c [reported by + Loriel@LimaBean] + * Don't call the first heart_beat until after saving the + initial error context, otherwise an error in heart_beats + or call_outs (set by preloads) will cause a crash. + * #47: When using OLD_ED with a broken client that does not + send CRLF for end of line, don't inadvertantly strip off the + first character of the next command if there are multiple + commands in the input buffer [reportd by fchen@uno.edu] + * #45: Added 'an' as a special word equivilent to 'a' and 'any' + Also, change ordinal for 'a', 'an' and 'any' to 1 from -1. + I'm not sure of the original intent in supporting -1, but the + end result is the same -- at least it's supposed to be. 1 + works, -1 doesn't. [reported by Zifnab@Red Dragon] + +Mon Aug 28 08:16:50 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.2b3 + * updated with respect to v22.1pre3 + * #15: Picked up the fix from v22.1pre2 that was missed in the + last revision for some reason + * #17, #26: Removed a chunk of old dead code for binaries + support that has been obsoleted since function tables are + always sorted and compressed now. Other new code had since + been written assuming this and not handling the (unnecessary) + binaries cases, causing the driver to crash in certain + instances [reported by ackers@coolnet.net, Beyond@Lima] + * #30: If an object has had its program replace, mark the + string that holds its name. Also make sure that it gets + freed properly when the object is deallocated [reported by + Uranus] + +Wed Aug 23 05:08:05 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.2b2 + * updated with respect to v22.1pre2 + * #4: fixed a problem with using the third defined class in an + object as an argument to a function getting treated + incorrectly as void [reported by Loriel@LimaBean] + * #8: Fix compile problem when both DEBUGMALLOC_EXTENSIONS and + PACKAGE_UIDS are defined [reported by Skullslayer@RoD] + * #16: With COMPAT_32 defined, '&' is now a synonym for 'ref' + everywhere that is appropriate [reported by Uranus] + * #19: Made fixes so that RUNTIME_LOADING will work on FreeBSD + [problem reported by Uranus] + * #23: Corrected arguments passed to compile_object() master + apply when cloning a virtual object [reported by Uranus] + +Sun Aug 13 22:25:28 CDT 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.2b1 + * updated with respect to v22.1pre1 + * fixed a memory leak with MUD port external ports leaking + ref counted objects received (arrays, mappings, etc.) + * fixed up check_memory() code to do proper checks: + . mark_apply_low_cache now bumps extra_ref for each + cache entry's oprogp and progp as appropriate + . dangling object list is checked for missing objects, + and if found, a more appropriate error is reported. + . TAG_SIMULS is used for master applies, so changed the + test in md.c to 3 rather than 2 uses for this tag. + . added marks to objects on the command_giver stack + * PACKAGE_DB compiles again + * properly free an added reference when establishing a new + user connection after APPLY_CONNECT is called. + * fixed a memory leak when updating the master object. The + master apply table reallocated memory without freeing the + previous table. + * 'void' is now acceptable as an argument list for a function + that takes no arguments. If used, it must be the first and + only argument, and it must not be named. Also updated the + testsuite to handle this. + * COMPAT BUSTER: SERVER_IP is no longer supported. Use the + runtime config option 'mud ip' to bind to a specific address. + addr_server and portbind have both been updated to accept a + parameter to specify a dotted decimal ip address to bind to. + Examples: + . portbind -i 192.168.1.1 -p 4000 + . addr_server 7334 192.168.1.1 + * COMPAT BUSTER: FD6_KIND and FD6_PORT are no longer supported + as compile time options. Set 'fd6 kind' and 'fd6 port' in + your config file to use them. You may use 'telnet', 'mud', + 'binary' or 'ascii' as the kind. Additionally, you must now + always specify -p to portbind to specify the port to bind to. + * fixed various crashers in handling eof conditions while + compiling, particularly in unexpected locations (comment, + array block, text block, etc.) + * when DEBUGMALLOC_EXTENSIONS is enabled, free up some compiler + scribble space that is normally reused (cleans up errors that + check_memory() reports) + * fixed a crasher involving BINARIES being defined, functions + being inherited and prototypes, and all sorts of other weird + assorted nonsense [reported by Mystic] + +----------------------------------------------------------------------- +Wed Aug 30 18:58:56 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.1pre4 + * Backported a fix from v22.2a24 for add_slash() to not prepend + a slash when the filename is '' + * #42: Added \n to the two new error messages introduced in + v22.1pre3 + * #34: Fixed another instance of regular expression memory + leaking using OLD_ED and an exit function passed to ed() + [reported by Skullslayer@RoD] + * #30: Fixed a problem with marking references for objects in + sentences with get_char() and input_to() [reported by Uranus] + +Mon Aug 28 08:11:42 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.1pre3 + * Check for INADDR_NONE is now done in edit_source rather than + on os specific check in portability.h. [suggested by Beek] + * #27: Fixed socket_write() to return EESUCCESS if no data is + passed to be sent (i.e., socket_write(fd, "")) [reported by + Uranus] + * #33: Fixed a crasher when destructing command_giver from a fp + set to notify_fail was executed for command failure. + * #28: Do not call LPC code when a too deep recursion or eval + cost exceeded error is raised. Especially in the former + case, there is no stack space to run the code and it results + in an unstable environment after the error is supposedly + recovered from. LPC code means the mudlib error handler or + the object_name() apply from (s)printf(). + [reported by Pinkfish@Discworld] + * #35: Do not allow lfun or functional binding after to an + object after replace_program() has been called on it, but + before the current thread of execution has completed. + Prevents bad code from creating dangling references to + programs [reported by Skullslayer@RoD] + * Backport from v22.2a27 fixes to contrib efun replaceable() so + that it works properly. + * #34: sscanf() efun was leaking memory in some cases if using + regular expressions [reported by Skullslayer@RoD] + * #32, #38: Fixed a crasher problem with add_action weirdness. + Involves using disable_commands() or destructing an object + in the sentence chain for command_giver and returning 1 from + the function. [reported by Loriel@NS and Uranus] + +Wed Aug 23 04:59:44 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.1pre2 + * #1: fixed compilation error on Solaris where INADDR_NONE is + not defined in system headers [reported by Dvarsk@Nightmare] + * Fix a braindead check in socket_write_select_handler() for + S_LINKDEAD. Also properly close and flag the socket as + linkdead in socket_write() when an error occurs in sending. + [reported by Eddy@MidnightSun] + * #7: Fix a crasher on some platforms in debug_message() where + variable arguments are reset between calls to vfprintf() + [fix from reetnem@bigfoot.com] + * #10: Remove completely (brain)dead code in the socket_accept + efun that called gethostbyaddr on the accepted socket, which + would cause the driver to possibly block unacceptably. This + information was then never used anywhere at all again. + [reported by Eddy@MidnightSun] + * #11: Make sure the accepted socket is set to be nonblocking + in the address server [reported by Eddy@MidnightSun] + * #5: Fixed a memory leak when LPC optimization was turned on + using either #pragma optimize or by setting PRAGMA_OPTIMIZE + in DEFAULT_PRAGMAS in local_options/options.h [reported by + Skullslayer@RoD] + * #15: Fixed a crasher in implode() efun with some older + versions of gcc (reported specifically against 2.7.2.3). + Compiler optimization error [reported by Mystic] + * #2: children(), livings(), and objects() have been rewritten + to better handle destructed objects and things of that + nature. Particularly objects(). + * #22: Backport a fix from v22.2a27 to make the (s)printf efun + re-entrant. Allows the no-(s)printf in object_name() master + apply restriction to be lifted. Fixes error handler crashes + [reported by Zifnab@Red Dragon] + +Wed Aug 13 22:03:44 CDT 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.1pre1 + * patched a memory leak with MUD type LPC sockets + leaking arrays/strings/mappings/classes received. + * fix a bad stack crasher when 0x2 passed in the mask + to check_memory() PACKAGE_DEVELOP efun + * fixed the testsuite to work when: + . NO_ENVIRONMENT is defined + . NO_ADD_ACTION is defined + . SENSIBLE_MODIFIERS is defined + . OLD_ED is not defined + . any form of explode() is configured for use. + . any default max eval limit is set (for automated tests) + * fix up rename and cp efuns so that strings tucked away are + not reported as leaking with check_memory efun [backported + from v22.2a37] + * if OLD_ED is not defined, cleanup ed buffer when interactive + object goes netdead (from remove_interactive()). + * more fixes to socket efuns to help prevent hangs on FreeBSD + when a socket closes unexpectedly. + +Sat Jul 29 21:30:19 CDT 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.1b32 + * fixed a crasher with reclaim_objects() and function + pointers introduced in b31 [reported by Skullslayer@RoD] + * rewrote hname_handler to properly handle fragmented response + packets from addr_esrver. + * When read fails in get_user_data(), flag the user as net_dead + before calling remove_interactive(). Don't flush messages in + flush_message() if NET_DEAD is set. Eliminates hangs on BSD + when a user connection is lost [fix from Eddy@LimaBean] + * If an LPC socket is blocked and the connection is unexpectedly + lost, clear the blocked state so that it doesn't hang in limbo + indefinitely. Similar problem to above. + * display a more appropriate error message when the global include + file cannot be included for some reason [reported by Mystic] + +Fri Jul 7 20:43:00 CDT 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.1b31 + * objectp() efun now returns 0 for a destructed object + [reported by Ehan@MedievalTimes] + * reclaim_objects() now reclaims destructed objects + that own function pointers + * fixed some compiler warnings + * fixed ordinal handling in parser package added in b29 + [reported by Dvarsk@Nightmare] + * added checks to prevent string concatenation from + exceeding the maximum string length [patch by Meph@LimaBean] + * process_efun_callback: save st_num_arg because it can get + blown away by the call to object_visible() [fixes crashers + reported by Ehan@MedievalTimes] + * FP_LOCAL function pointers now hold a reference to the + program of the object that they're bound to. this results + in replace_program() and swapping being prevented on the + object [fixes crashers reported by Avenger@AtP] + * backed out earlier changes to dont telopt_linemode. much + more support in the driver is necessary to properly support + this. it's too late to put it in now. it's in v22.2a36. + * fixed crasher when MAX_NUM_OBJECTS objects are found by the + parser using plural modifier [reported by Dvarsk@Nightmare] + +Tue Jul 4 19:36:09 CDT 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.1b30 + * virtual objects can be cloned again + * moved STACK_INC into interpret.h from interpret.c so + that it is accessible throughout the driver + * use STACK_INC instead of sp++/++sp throught the driver + * made sure that all destructed objects are actually + const0u (undefined) rather than just const0. done to + be consistent and also to match the documentation + * added stack overflow checks throughout the driver + * fixed a potential crasher in allocate_mapping() if + a function is specified as the filler and an error + occurs evaluating it. + * fixed several locations where the stack pointer was + incremented but unset before an error check. if the + error occured, a garbage svalue would be popped in the + handler + * made sure all swapped object checks are done by checking + O_SWAPPED rather than prog==0 + * fixed a crasher that reared its ugly head in various forms + caused by a bad call to free_object() when dereferencing + a class member that held a destructed object + +Sat Jul 1 13:14:32 CDT 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.1b29 + * various fixes from Alaron@RetroMud: + . make db.c compile + . fix an infinite loop problem in db code + . add support for more mSQL datatypes + . miscellaneous typos (error messages and the like) + . correct ambigious if/else in md.c + . move #include of dlfcn.h to std_incl.h + . cleanup some compiler warnings + . check return from fork() in external.c + * the 'say' command in the testsuite will now compile + with #pragma strict_types + * Cloning a virtual object now ensures that O_CLONE is set + on the new object. + * Loading a virtual object that would result in a duplicate + object name now fails with a runtime error rather than + silently allowing the operation and corrupting the object + name hash table (or crashing in a debug build) + * Parser fixes: + . object count passed with ERR_ORDINAL was one too high + [reported by Zifnab@Red Dragon] + . can now access any number of objects in an inventory, + not just the first nine. above 9 requires 10th, 11th, + etc. and will not accept tenth, eleventh, etc. + [reported by Reflection] + * fixed up error messages for defining variables with an + undefined class name and attempting to create an instance + of an undefined class with new() + +Tue Jun 20 18:40:18 CDT 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.1b28 + * fixed the changes made to ed in the last revision. Turrican's + patches were merged in wrong. + * Changes to the pluralize() contrib efun: + . Add an exception for bonus -> bonuses + . Add exceptions for datum -> data and forum -> fora + . Remove the rule *um -> *a (see comment in code for why) + * Cleanups to previous change to add slashes in error tracebacks + * prepend a slash to filename passed to the write callback when + OLD_ED is defined + * correct potentially fatal references to freed arrays and mappings in + F_MEMBER, F_INDEX and F_INDEXR cases by doing destructed object checks + before pushing onto the stack. + * fix crasher when socket_error(-33) is done [reported by Megaboz@Lima] + * added locale support [based on patches from Naebator@Remedy] + * reset command_giver when current_interactive is reset in the backend + to fix random crashes/fatals caused by use of set_this_player() and + command_giver not holding a reference to the object + * raise class redefinition error only if member names and/or types differ + [reported by Pinkfish@Discworld] + +Thu Jun 15 17:07:32 CDT 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.1b27 + * if ARGUMENTS_IN_TRACEBACK or LOCALS_IN_TRACEBACK is defined, save + error context in dump_trace() so as to maintain a consistent state if + svalue_to_string() errors (due to object_name in master_ob generating + an error) + * if LOG_CATCHES is defined, bump num_error before dumping trace on a + catch so that we don't loop indefinitely in the event of an error in + dump_trace(). + * fix a crasher when write permission is denied for the file specified + for dumpstat() [reported by Mystic] + * removed redundant code in smart_log() in file.c [reported by Mystic] + * if multiple address server replies are received in a single socket + read, handle all of them, not just the first and throw the rest away + * set nonblocking on newly accepted sockets for all platforms - not + just Linux [numerous reports / various platforms] + * fixed another crasher in (mapping) x *= x [reported by Avenger@AtP] + * removed -fomit-frame-pointer from default optimization flags in + build.MudOS due to problems with stack checkers + * Fixes from Turrican@Discworld: + . fix telnet negotiation when using fd 6 and port 23 with portbind. + . fix bad references in ed if the exit callback function uses + call_out() or input_to() + . remove an inappropriate warning when negative indices are used on a + mapping + * fix a crasher when a class is defined in the simul_efun object and + another object generates a compiler error referencing that class type. + [reported by Pinkfish@Discworld] + * fix another crasher returning from a catch { ... } block [reported by + Mystic] + +Mon Jun 12 08:46:33 CDT 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.1b26 + * don't shut down the driver if a new connection fails to set + non-blocking on linux, just dump the connection and move on + * PACKAGE_EXTERNAL will compile without PACKAGE_SOCKETS now. + * if EWOULDBLOCK is not defined by the OS but EAGAIN is, make + EWOULDBLOCK equivilent to EAGAIN. + * in shutdownMudOS, use OS_socket_close instead of close + * set non-blocking on newly accepted sockets in the socket_accept + efun. + * in socket flushing code, ignore EWOULDBLOCK as well as EINTR. + * error when number of global variables reaches 256 to prevent + overflow in various opcodes [reported by Zifnab@Red Dragon] + * all conversions from lpc float to string now use %f as the + format specifier passed [eventually] to (v)(s)printf. + * restoring a numeric value from a string (restore_variable or + restore_object) will count the last character being a decimal + as a 0 rather than erroring. this is for backwards compatibility + in loading existing .o files that have data saved this way. + [reported by Zifnab@Red Dragon] + * correct index to local variable for warning about unused local + variables [reported by Andrew@Nanvaent] + +Mon Jun 5 13:05:02 CDT 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.1b25 + * several fixes to the terminal_colour() contrib efun: + . bad stack/crash when string contains only %^'s + . reallocate parts array only if needed (when NSTRSEGS + 1 + instead of when NSTRSEGS) + . properly support tabs in wrapping [reported by Tigran] + . fix crasher in wrapping caused by uninitialized variable + [reported by Zifnab@Red Dragon] + . allocate the proper amount of space for the temporary wrapping + buffer when constructing the final string. + * fixed crasher in (mapping) x *= x [reported by brett@stummies.org] + * several parser fixes for problems reported by brett@stummies.org + . bitvec_count() only counts the bottom half of each bitvec_t element + . local_error is unused in we_are_finished() + . DEBUG_DEC missing before return in parse_rule() and we_are_finished() + . miscellaneous cleanups in debugging code + . don't reset debug_parse_depth in free_parse_globals() (causes DEBUG_P + to break if used in do_the_call() if it is and is set in + f_parse_sentence() anyway) + . ERR_ORDINAL shouldn't be negative + * fix crasher when input to parse_sentence() exceeds MAX_WORD_LENGTH. + [reported by Zifnab@Red Dragon] + * prepend slashes to filenames for display in ed (f, w, x commands) + [reported by Avenger@AtP] + * added exceptions for plum and virus in the contrib efun pluralize(). + [reported by Avenger@AtP] + +Wed May 24 12:00:20 CDT 2000 (marius@mudos.org (Marius)) + * raised patchlevel to v22.1b24 + * updated contact information for reporting bugs + * remove undefined status with += when rhs is real (completes + the fix made in v22.1b23) + * cleaned up a handful of compile-time warnings + * fixed crashers when trying to return from a catch { ... } or + time_expression { ... } block + * corrected the filename and added the line numbers for overlapping + range cases in switch blocks + * moved sentence cleanup from dealloc_object() in object.c to + destruct2() in simulate.c because a sentence with a function + pointer callback could (and likely does) hold a reference to the + object being destructed [reported by Belgarat@Realms of Sorcery] + * add slashes to program and file name in error traces and also for + mudlib error handler + * corrected OS_socket_read and OS_socket_write on Unix to use recv + and send respectively. All socket io is now done with send/recv + instead of mixing with read/write + * fixed crasher in (mapping) x += x [reported by Xavier@AtP] + +Tue Jan 12 17:50:55 EST 1999 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1b23 + * fix += and -= and clear undefined status [reported by Gorta] + * fixed crash in functions() on objects that define no new + functions [reported by Beyond, fix from Alaron@RetroMud] + +Mon Nov 9 12:47:38 EST 1998 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1b22 + * fixed signed variable not to be declared as unsigned in sprintf.c + [reported by Maarten D. de Jong] + * remove unnecessary WIN32 crypt() prototype in port.h; evidentally + it causes MS VC5 builds to fail. + * in read_bytes() make sure the file gets closed when errors occur + [reported by Hamlet] + * fixed remove_shadow to remove all shadows on an object, like + the documentation says [reported by Skullslayer@Realms of the Dragon] + * added support for string[idx] -= ... [reported by Donky] + * fixed traceprefix() to use paths with leading slashes [reported + by Randor] + +Wed Feb 25 21:12:30 EST 1998 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1b21 + * renamed STACK_CHECK to STACK_INC, since it increments the stack + pointer too + * add { } to make binding of else clearer (simulate.c, ed.c, + eoperators.c) + * remove implicit int from prototype (lex.c) + * fixed crasher when terminal_colour() string contains only %^ + [fix from Skullslayer@ROD] + * Fixes from Belgarat: + . fixed crasher in explode() when result array was too large + . __cdecl funkiness in backend.c, comm.h, etc; why can't MS + support standard C? No other compiler needs anything this gross. + . remove WIN32 specific code in time() efun ... it is wrong, and + will cause call_outs to misbehave + . fixed off-by-one error in WIN32 code for file_size() + . push_ and push_refed should use STACK_INC not sp++ + . fixed crasher in terminal_colour + . added UINT32 define to WIN32 configure.h + +Tue Nov 11 12:47:22 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1b20 + * in portbind.c, change our gid before our uid, while we still + have permission to do so [reported by Radagast] + * slightly clearer error message for end of file while looking for + #endif [reported by Aragorn] + +Mon Nov 10 17:56:57 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1b19 + * added support for classes in != and == [reported by Emeradii] + * fix for float += int [fix from Symmetry] + +Tue Nov 4 22:55:49 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1b18 + * fixed program size check to check correct size + +Tue Nov 4 15:57:10 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1b17 + * fixed typo in grammar.y.pre + * fixed restore_object() to choose the nonstatic version when more + than one var has the same name + * fixed compilation with NO_ADD_ACTION off + +Sat Oct 4 23:17:32 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1b16 + * pluralize() fixes from DrFeelgood: skiff, sniff, gaff, etc. + Handle staff as an exception. + * fixed crasher in function() {} [reported by Kaolin] + * Enforce the 64k bytecode limit + * fixed unterminated comment in options.h + +Thu Oct 2 01:21:02 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1b15 + * typo fix in addr_server.c [from Cloud@IdeaExchange] + * fixed the type of '((mixed)class)->member' [reported by Mystic] + * fixed parsing of code like (: identifier identifier :) + * took filter(string, ...) back out of func_spec.c since it isn't + implemented yet + +Wed Sep 24 23:38:36 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1b14 + * fixed resolve() to pass (0, "255.255.255.255", key) and not + (0, 0, key) to the callback when the lookup fails + * resolve() now calls the callback even when inet_ntoa() fails + [both reported by ekusters@wabi.curinfo.an] + +Fri Sep 5 00:40:03 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1b13 + * added prototype for allocate_empty_class_by_size() to class.h + [from Turrican@Discworld] + * fixed 'alot' -> 'a lot' everwhere it occurs + * compilation fixes for IRIX 6.2; handled by configure, + "my_malloc.h" is now "my_malloc.h" + * fixed read_file() to only strip '\r's before '\n's [reported by + Burty] + * fixed unused local variable errors to report the correct variable + name in the presence of nested blocks of variables (e.g. {int x; + { int y; } } ) + [reported by Aragorn] + * some unused local variables that were previously overlooked are now + reported + * the parser now accepts "my xth obj" [reported by Lathander] + +Tue Sep 2 20:40:31 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1b12 + * really fixed those invalid declarations this time + * added Dworkin's patches for RUNTIME_LOADING support on NetBSD + * updated Credits.MudOS a bunch. If you have submitted anything, + or your entry is incomplete or inaccurate, email me. + +Sat Aug 30 19:14:34 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1b11 + * fixed invalid declarations in the named_livings() contrib efun + [reported by Qualin and others] + * added Maarten de Jong's updated README-gcc for Amiga compilation + * added missing fclose(f) to read_file() + +Wed Jul 23 17:43:48 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1b10 + * updated with respect to v22pre10 + * more fixes for set_hide disabled (named_livings() and find_living()) + [patch from Alaron@RetroMud] + * fixed crasher in (array) x += x [reported by Qualin] + * added leading slash to log_error() filename [reported by Jihad] + * fixed func_spec to allow filter(string, ...) + * rewrote read_file(). New version is: + 1. readable + 2. platform independent (\r translation is now done on UNIX too) + 3. catches \0's in all cases + 4. doesnt ignore start when called with 2 args [reported by Nameless] + * fixed compilation warnings about S_IS*() + * fixed set_inc_list not to mangle the include list, so get_config() + reports the right value + * fixed array stat bug when copy() is used on classes [reported by + Alaron@RetroMud] + * foreach (x, y in z) { ... } no longer warns about x,y being unused + [reported by Qualin] + * fixed unsafe uses of push_svalue() in link() + +Thu May 15 14:08:11 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1b9 + * added a missing newline to the end of trace lines when + MUDLIB_ERROR_HANDLER is off + * added Burty's fix for the macro expansion bug + * fixed compilation with set_hide disabled and add_action enabled + [reported by Mystic] + * fixed compilation with input_to and get_char disabled [patch from + Mystic] + * typo fixes in the break_string() simul [reported by Randor] + * some minor changes to ChangeLog.beta + * some changes to IT_CRASHED + * fixed compilation of tail() with COMPAT_TAIL on + +Wed Apr 16 07:34:13 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1b8 + * updated with respect to v22pre8 + * fixed type checking for functions that don't use all there arguments + [SUPPRESS_ARGUMENT_WARINGS off; fix from Wodan@Discworld] + * added missing #ifdef DEBUG in simulate.c [fix from Jesse@Doom] + +Sun Apr 13 23:36:52 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1b7 + * added Belgarat's Win32 compilation fixes + * fixed compile error in simulate.c [Ailima, Aragorn, Avenger, etc] + * fixed dumpstat() not to crash on recursive structures + +Sat Apr 12 14:57:49 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1b6 + * updated with respect to v22pre7 + * fixed the max_eval_cost error check in call_out.c to pop the + error context correctly [fix from Ceda] + * Don't crash if an object which is snooping another object gets + destructed + +Sun Apr 6 17:55:11 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1b5 + * updated with respect to v22pre6 + * fixed a bug in the (mixed)->y code that caused it to never find + a class member. Code like: mixed x; x->y or mapping m; m["foo"]->y + should work now assuming it is unambiguous. + +Wed Apr 2 14:15:48 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1b4 + * updated with respect to v22pre5 + * check if my_string is allocated before trying to mark it + [reported by Ceda] + * mark the master_user_list in the parser package + [reported by Ceda] + * 255 -> LEX_EOF in lex.c [reported by Avenger@CoreDump] + +Sat Mar 1 23:32:01 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1b3 + * updated with respect to v22pre4 + * fixed the error context for error messages at the end of the file + [reported by Jihad] + * don't treat directories as source files, even if they end in .c + [reported by Jihad] + * fixed a bug that allowed the type of a global variable to be omitted + if a modifier was used + * fixed crasher in ref code [reported by Qualin] + * fixed #undef SENSIBLE_MODIFIERS not to claim static variables are + also nosave in the variables() output [found while tracking a bug + report from Aragorn though I'm not entirely sure this is what he + meant :-)] + * fixed leak in errors during fprintf() in save_object + * moved init_instrs (was init_num_args) earlier so it gets the names + of internal efuns (_call_other, etc) correct for LPC->C. Moved the + name fixing to be part of query_instr_name(). + +Fri Feb 7 15:31:47 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1b2 + * added Burty's fix for something involving backslashes, quotes, + and #defines [please describe patches ;-)] + * fixed crasher in mapping composition (reported by Andrew) + * fixed foreach () with a global as the loop variable [reported + by Jihad] + * fixed crashes related to errors in object_name() + +Fri Feb 7 15:22:52 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22.1b1 + * updated with respect to v22pre2 + +---------------------------------------------------------------------------- +Sat Aug 30 19:24:51 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22pre11 + * fixed ed_start() with no args to set the type of its return value + [fix from Jalh@LimaBean] + * fixed 'buffer[i] = 0' to work again + * fixed save_object() to save '0.000' as a float and not as int '0' + [reported by Descartes; patch from Aragorn] + +Wed Jul 23 17:39:48 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22pre10 + * added workaround for Ultrix sh bug (returns error code on if + without else) [patch from Hamlet@IdeaExchange] + * disabled function argument checking for foo::bar() since the patch + that was added could find the wrong function entry if the function + was overloaded, and the fix isn't trivial. 'private' is now handled + as a special case. [bug reported by Qualin] + +Thu May 15 13:58:13 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22pre9 + * when NO_ADD_ACTION is defined, set O_LISTENER for objects which + define a receive_message() function so message() calls it + +Fri Apr 25 13:58:36 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22pre8 + * using line numbers with quit in ed ('12q') no longer clears the + buffer [reported by Jihad] + * fixed replaceable() not to consider the internal function + #global_init# [reported by Donky] + * added Wodan@Discworld's fixes for PACKAGE_EXTERNAL + * another fix for file operations when the master object isn't loaded + yet or doesn't have a valid_{read,write} function + * Use 128 instead of SOMAXCONN for listen(2) since some BSD derived + operating systems have a ridiculously low value for SOMAXCONN. + [fix from Aule@The Two Towers] + * clear in_mblock in the ed indentor in case a block was unterminated + during the last use [fix from Aule@The Two Towers] + +Sat Apr 12 05:25:31 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22pre7 + * __OPTIMIZATION__ and __COMPILER__ are defined again; lex.c needed + to include cc.h [reported by Decker] + * fixed false alarm ("Bad stack after evaluation") when + time_expression { ... } was used with DEBUG defined + * fixed foo::bar() not to allow all sorts of nasties: + . type checking is now done + . private functions can't be called + . (: foo::bar() :) is not a bindable function pointer + +Sun Apr 6 17:45:49 EDT 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22pre6 + * fixed terminal_colour() to add indentation to lines which just barely + didn't fit (i.e. were one character short of fitting) on the + previous line [reported by Jihad] + * fixed a bug that caused synonyms for OBJ rules not to work + * removed a #include that caused some malloc packages to fail to work + on Solaris [reported by Aragorn] + * fixed an incorrect typecheck in socket_connect() which disallowed + function pointers as one of the callbacks [reported by Deathblade] + * fixed the LARGEST_PRINTABLE_STRING checks to allow printing of + strings with length == LARGEST_PRINTABLE_STRING + * added a missing newline to the Inherit chain too deep error message + +Wed Apr 2 13:31:44 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22pre5 + * fixed leak in check_valid_path() [reported by Fermat] + * fixed crashers in function pointer add_actions() when the driver + is run in -d -d mode [reported by Aragorn] + * ported back the socket close callback fix + * disabled #pragma optimize + +Tue Apr 1 23:53:07 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22pre4 + * Added Leslie@StyleGates' fix for a leak in REVERSIBLE_EXPLODE_STRING + * added Eggjon@Nameless Sorrows' fix for a typo in WIN32 code in file.c + * fixed crasher in using functions() on an object with no functions + [reported by Valentino] + * fixed compilation error in PACKAGE_EXTERNAL + * fixed save_object() not to call valid_read() [typo in src] + * added Deathblade's fix for filter_mapping() when the result mapping + is large + +Tue Feb 25 21:30:57 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22pre3 + * fixed bug in rename() efun [used Turrican@DW's fix (essentially); + tons of people reported this one] + * fixed crasher in PACKAGE_EXTERNAL (reported by Turrican@DW) + * fixed livings() not to return hidden objects (the check was + backwards) + +Sun Feb 2 14:09:47 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22pre2 + * custom_crypt() now never returns NULL, and can deal with + arbitrarily long salts; also a number of compilation fixes + * fixed crypt() to use the password as the password, not the + salt; also fixes a crasher when salt == 0 + * added the old version of crypt as an oldcrypt() efun; useful + for converting old passwords to the new format, or on systems where + the new crypt is not backwards compatible (FreeBSD) + * fixed edit_source to catch options that are #undef'ed in options.h + but not set in local_options + +Sun Feb 2 14:08:33 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22pre1 + * added documentation and setup the release directory structure + +Sat Jan 25 03:40:07 EST 1997 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22b27 + * increased the salt length to 8; salts from the mudlib are no + longer truncated at 2 characters + * added Fermat's crypt package; use CUSTOM_CRYPT to enable it + * fixed problems with cp() and rename() [reported by Jihad] + * fixed crasher in restore_object() + +Mon Dec 30 03:57:55 EST 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22b26 + * fixed restore_variable()/restore_object() not to lose precision on + values between 0.01 and 0.0001 + * fixed sprintf of integer types not to ignore the precision field, and + fixed the '+' option in connection with 'f' and a precision (e.g. "%+.5f") + * added two patches from Ceda for Win95 crashers + * added ARCH entry for NetBSD + * valid_read/write now get passed the real name of the save file for save/restore_object + (e.g. including the .o) + * save and restore_object no longer tack on a .o if the filename already has one + * the value returned by valid_read/write, if a string, is used as the filename again + [allows ~ expansion, etc] + * added dchen@sei.xjtu.edu.cn's fix for a problem with STR rules on HP/UX + * fixed bug in 'nomask' error message + +Sun Dec 8 22:54:36 EST 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22b25 + * fixed crasher in trying to call_out() from a destructed object + * fixed read_file() not to read \0's into strings + * fixed a number of builtin operators not to return undefined values + * added Marius' patch to not warn about '\"' + * fixed reclaim_objects() not to leak destructed objects found as + mapping keys + +Fri Dec 6 17:36:10 EST 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22b24 + * fixed typo in INLINE_STATIC changes + +Fri Nov 8 11:45:33 EST 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22b23 + * function_exists() no longer finds #global_init# + * don't include #global_init# in functions() + * fixed a bug that would cause (mixed)[' + crasher] + * Reduced the weight of rules where OBJ matches due to an error. + Should eliminate cases where the parser erroneously reports + 'There is no ... here' instead of a more sensible error message. + * socket_error() message change: EEBADF is now 'Socket is closed' + and not 'Descriptor is invalid' + +Thu Jun 27 20:46:06 EDT 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22b11 + * Fixed a crasher in updating a simul_efun which inherits an + unloaded object (this also happens to be the Lima Bean + 'loadall /secure' crasher) + * Cleaned up destruct_object() a bit + * fixed more ARRAY_STATS problems + * fixed an unitialized use of version_buf when a config file + isn't specified + +Sun Jun 16 18:08:32 EDT 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22b10 + * Fixed a compilation problem with ARRAY_STATS undefined; reported + by a number of people + * Added the ChangeLog entries for v21.7b14 back in + * fixed a typo in the Makefile: -rm instead of rm in a shell section + * fixed a crasher in destructed function pointers in call_outs when + PROFILE_FUNCTIONS was enabled; should also fix a number of other + possible crashers in errors thrown in odd situations before calling + functions + * Check if wait3()'s return value is positive, not just nonzero so + we don't loop on errors (most notably ECHILD). Fixes + external_start() to not hang the MUD on BSDish systems + * The two characters recognized by terminal_colour (defaults to "%^") + is now configurable near the top of the routine + +Fri Jun 7 11:13:14 EDT 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22b9 + * Fixed typos in GNUmakefile, efuns_main.c, grammar.y.pre, simulate.c + * Added someone's patch for printing out the version and architecture + before the 'You must specify a configuration filename' error message + * Note: static clean_up() functions are now called again; same with + catch_tell() when NO_ADD_ACTION is on + +Tue Jun 4 18:00:31 EDT 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22b8 + * The third argument passed to valid_override() now has a leading + slash + * The filename passed to compile_object() has a leading slash + [fix from Descartes] + * Made the "Program size miscalculated" debug message non-fatal, + since it doesn't really cause anything to break. + * function_exists(string, object, flag); if flag is nonzero, private + and static functions are checked too. + * Fixed two bugs in terminal_colour(): + . if wrap is specified and is zero, do no wrapping + . pull indent and wrap off the stack in the right order if both + are specified [fix from Descartes] + +Tue Jun 4 16:26:49 EDT 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22b7 + * fixed a few compilation problems in interpret.c + +Tue Jun 4 12:19:09 EDT 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22b6 + * Fixed a typo in the BSD readdir() configure check + * Added slashes to the front of many object/program names. The most + noteworthy are: deep_inherit_list(), inherit_list(), call_stack(), + names passed to author_file(), domain_file(), privs_file(), + creator_file(), a few error messages and tons of debug messages + * fixed the parser package to mark it's error messages when + CHECK_MEMORY is on + * fixed a bug that caused " and \'s on the line of the terminator + of an @ block to have \'s inserted before them causing syntax + errors + * call_out, input_to, socket callbacks and add_action can no longer + be used to call ##global_init## + * a few more testsuite tests + * it is now illegal to insert the character '\0' in to the middle + of a string + +Mon Jun 3 15:03:16 EDT 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22b5 + * fixed pluralization of "gum" + * added Blackheart's fix for a compilation error when CALLOUT_HANDLES + is turned off + * fixed various bugs with string statistics + * fixed a few bugs bug where classes would cause num_arrays to be + wrong + * added an ARRAY_STATS option for those who want to turn array + statistics off + * added DEBUG checks for allocd_bytes and allocd_strings + * added a debugging check to make sure FREE_MSTR isn't called on + a string with more than one reference + * fixed crasher in switch() on a non-shared string + +Sun Jun 2 20:10:59 EDT 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22b4 + * fixed a bug in epilog that allocated space for A_FILE_INFO + in the program structure, even though that data isn't stored there, + wasting approximately 100 bytes/program + * fixed the configuration checks to be a bit more robust with respect + to various files not existing or being outdated ('configuration' + in particular). Fixes compilation errors on OSF reported by Yaynu + and onSun 4.1.4 as reported by Pace + * When NO_SHADOWS is off, and INTERACTIVE_CATCH_TELL is on, + add_message() doesn't need to call catch_tell() since the shadows + already got a chance via tell_npc(). Also fixes a bug reported by + Cire that caused two deep recursion errors when a user was shadowed + with those option settings. shadow_catch_message() also moved to + comm.c, since it is only called from there. + * typo fix from Darrin Wilson for compilation with DEBUG not defined + * a few small optimizations to switch() + * changed POINTER_INT back to a signed type; the fact that it was + unsigned caused switch to misbehave on negative numbers and/or + other cases + * program_info() now calculates class size as well; also fixed a + bug in the calculation of function table size. + * changed an instance of "catch_tell" to APPLY_CATCH_TELL + * characters with the 8th bit set are no longer ignored + +Thu May 30 21:11:57 EDT 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22b3 + * added Kaolin's fix for a crasher in terminal_colour() + * fixed another crasher in the prototype-before-inheriting fix + (from Ceda) + * added some more Windows 95 fixes from Ceda + * made all the calls qsort() strictly conforming + * configure now checks for 'const' and 'inline' + * debugmalloc now fills freed blocks with 0x78 so using a block + after it has been freed will crash/misbehave + +Thu May 30 15:12:42 EDT 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22b2 + * fixed a crasher when more than 65535 instances of a shared string + are allocated + * minor fixes to various pointer hashes to avoid warnings on 64-bit + architectures + * turned RUNTIME_LOADING off by default since not all architectures + support it + * Fixes for terminal_colour() with illegal/negative widths/indents, + also fix for crasher introduced last patchlevel + +Wed May 29 01:39:20 EDT 1996 (tim@wfn-shop.princeton.edu (Beek)) + * raised patchlevel to v22b1 + * fixed typo in backend.c in Windows 95 code + * Bumped the maximum byte transfer setting in the example config + file up to 200k + * Added some Solaris compilation fixes based on information from + Aragorn, Darrin Wilson, Descartes, et al + * fixed terminal_colour() to do wrapping even if there are no %^'s + in the string + * mud_status() now notes when STRING_STATS is off + +---------------------------------------------------------------------------- +(v21.7b22 promoted to v21.7) + +Thu Apr 11 21:04:27 EDT 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7b21 + * fixed a bug in replace_program() which would sometimes zero out + too many/the wrong variables + +Sun Mar 10 04:49:28 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7b20 + * removed abort() prototype from lint.h; SunOS defines it as int + abort(), which is very odd since it never returns ... + * made a zero return value from domain_file() legal again + +Fri Mar 1 12:20:12 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7b19 + * set the telnet flag for anything that responds to telnet queries, + even if it refuses terminal negotiation + * fixed debugmalloc compilation problem (had old name for CFG_MAX_EFUN_SOCKS) + * fixed crasher in author/domain_file() returning bad types + +Thu Feb 22 10:38:57 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7b18 + * Fixed ./build.MudOS to create comptest.o so it exists for the ar + test + * tried a new fix for the namespace collision between automatic + options.h defines and include/runtime_config.h; the options.h + names are now in the CFG_* namespace + +Sat Jan 27 16:36:52 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7b17 + * added Quango's patch for the file_length() efun + * fixed clear_notify() to not assume this_player(); this means + destructing an interactive no longer cancels notify_fail() messages + for whoever this_player() really is + * tidyed up remove_interactive() a bit + * fixed include/runtime_config.h to not define some things which + conflict with predefines from options.h + +Sat Jan 20 15:03:54 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7b16 + * fixed a crasher in using set_this_player(0) from inside a player + command + * fixed a crasher in loading an object while another object was + compiling + * fixed compilation on systems where GNU make isn't present; RANLIB + wasn't being passed to the subdirectories + * removed the restriction that a non nomask function can't be + overloaded and made nomask + +Wed Jan 3 14:24:12 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7b15 + * fixed add_action() to check if it's flag is in the legal range; + prevents crashes when bit 4 is passed, since that is used internally + to mean 'function pointer' + * In the parsing package, fixed a crasher on sentences of the form: + " prep " + when a rule of the form: + "OBJ prep OBJ" + existed + * When checking includes, include file_incl.h as well to check for + conflicts there. Fixes a compilation problem on BSDI where + is _NOT_ protected from multiple inclusion + * fixed the 'q' and 'Q' commands to not clear the buffer it there + is a syntax error + +Tue Jan 2 17:43:55 EST 1996 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7b14 + * ported back the fixed call_out leak fix from v22a17 + * fixed leak in illegal patterns to reg_assoc() + * fixed a string reference bug in parse errors very near the end + of a function + * fixed a leak in using F_TRANSFER_LOCAL on a variable containing + a dested object + +Sat Dec 30 20:50:17 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7b13 + * Fixes from ngreen@plains.nodak.edu: + . crasher in lpc_info() when one of the objects was swapped + . implemented time_expression() from compiled code + * Fixed crasher in defining a function, then inheriting a copy + of it (as opposed to inheriting first) with #pragma warnings on + [reported by Lima Bean, Vonotar, Aragorn, Jihad, ...] + * Linux compilation fix: check for SOMAXCONN in + +Tue Dec 5 19:24:06 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7b12 + * really corrected the order of arguments to fread() in file_length() + * fixed a crasher in the removal of heartbeats from objects. + +Mon Dec 4 15:52:24 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7b11 + * fixed a misplaced parenthesis in the file_length() contrib efun + +Mon Nov 27 22:45:28 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7b10 + * fixed a optimizer bug that would clobber parse_command() calls + * Two fixes from Raistin@IE: + . chop off y before adding ies in pluralize() + . initialize verb_entry->flags to zero so that the parsing packages' + hash tables aren't unnecessarily set up. + * Fix from Aragorn: pass args in correct order to fread(), and use + memchr() instead of strchr() to handle binary files correctly in + the contrib efun file_length() + * fixed the ranlib check to work correctly + +Wed Nov 22 12:47:40 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7b9 + * fixed a crasher in x->y->foo() when x->y was a destructed object. + * fixed a crasher in the parser error message "The foo isn't bar." + +Tue Nov 21 15:07:27 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7b8 + * fixed a // comment in generate.c [gcc 2.7.1 allows it *roll*] + * Following patches from Quango's DW version of v21.7b7: + . added Linux/m68k to arch.h + . "thief" -> "thieves" in pluralize() + +Wed Nov 15 14:30:44 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7b7 + * #include "file_incl.h" in addr_server.c so that + is included and SVR4 systems are happy. + * check for the existence of ranlib on build.MudOS, so systems + that don't have it (Solaris) don't complain + * Added a missing newline to the end of the 'Q' help in ed. + * Fixed a crasher when a trailing slash was included in the first + argument to rename(), and valid_read() didn't strip it off + * Fixed a misoptimization of code where local variables died + inside arguments to a function pointer. + * Fixed the initialization chain to be made even if the object + being inherited defines no functions, just initialized variables. + * Fixed a bug that would cause (: private_inherited_var :) to + either go unnoticed, or print a garbage variable name in the + error + * Changed the 'internal disaster' regexp error message to + 'unexpected ]' which I think is right. Let me know if it + shows up in other cases. + +Tue Nov 14 12:47:48 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7b6 + * Don't crash when buggy telnet clients send an IAC SE (end suboption) + without ever having send a IAC SB (begin suboption) + [as a side note, there is a windows 95 client that sends: + IAC WILL TELOPT_TTYPE "vt100\0" IAC SE + (1) (2) (3) + 1. should be SB, which differs by 1 from WILL + 2. missing TELQUAL_IS + 3. terminating null isn't part of terminal types + more high quality PC software, I guess ...] + * fixed #pragma optimize to not kill variables that only die along + one branch of an if/switch + +Tue Nov 7 17:46:21 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7b5 + * fixed a crasher with #pragma save_types + * fixed indentation errors in ed when OLD_ED was off to report correct + line numbers and send errors to the correct place + * fixed a crasher in using an expression of type (class foo *) + as the left side of -> + * fixed a crasher if a socket had a file descriptor greater than 32. + Also, function pointers as callbacks should get called/not crash now. + +Fri Nov 3 16:24:49 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7b4 + * check for overflow of suboption buffer when recieving quoted IAC's + * fixed crasher in __TREE__ on blocks containing (opcode_2) nodes + * fixed a bug in (int constant)/(real constant) + +Sun Oct 8 19:52:11 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7b3 + * added Kalinash's fixes for FreeBSD compilation + * fixed some crashers in parse_command_users(): returning the + environment of a user, returning an object unknown to the + parser, or destructing objects involved in the parse + * added a possible workaround to get around a possible non-feature + of FreeBSD/NetBSD make commands (can't find rule for malloc.o) + * added a patch from Yakko so bsdmalloc compiles on Linux + * fixed a crasher in the verbose version of functions() on objects + with global class variables + +Fri Oct 6 20:26:51 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7b2 + * fixed a crasher in disabling a heartbeat from a heartbeat + (usually only if a large number were deleted, like most of + the heart_beats on the mud) + * reorganized the signal handling to be a bit simpler + * fixed some compilation problems with the matrix package + +Fri Oct 6 20:26:51 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.7b1 + * updated with respect to v21.6 + * fixed the handling of call_outs (especially to function pointers) + in the ref count checking code + * take objects on the destruct list into account in the ref checking + code + * fixed a crasher when the master object self-destructs during + connect() + * fixed a number of warnings and improved -pedantic support + * errors in get_save_file_name() will no longer cause zeros in + users() + * fixed a memory leak in the cached ids of interactive objects + * fixed a crasher in replace_program() + * more verbose error message for inherit chain too deep + +-------------------------------------------------------------------------- +v21.6b7 promoted to v21.6 with the following changes: + + * fixed a bug that would cause the driver to busy-wait when an + object had it's heart_beat enabled, but had no such function. + * trap SIGFPE to avoid going down on floating point exceptions + * run runlib on the archives for systems that need it + * Actually use the limits.h configure info + +Thu Aug 24 06:53:08 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6b6 + * crasher fix in loading objects with a .c.c suffix. The current + fix entails stripping multiple .c's off the end instead of just one. + * edit_source -configure now checks if the configure.h file needs to + be remade due to new config checks + +Mon Aug 21 03:18:45 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6b5 + * fixed a crasher in parse_command() [reported by Magician] + * fixed a few bad free's in parse_value() [reported by Aragorn] + * added Symmetry's fix for Tensor's 'Couldn't find enabled object in + heart_beat list' crasher + * fixed a crasher with #pragma optimize on + * added pluralization for do, go, was + +Mon Aug 21 03:16:33 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6b4 + * make configure.h early enough so that it can be included in + func_spec.c, so that the rusage() efun can be included + * added in Deathblade's fixes for remove_call_out() + +Thu Aug 3 11:29:56 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6b3 + * added REALLY verbose parsing mode for those really hard to find + parser bugs; use flag > 1 to parse_sentence + * LPC->C fixes: + . fixed a crasher in compilation of control jumps [break, continue] + . fixed an error in adding labels that could write one byte + past the end of the program block + . fixed a syntax error in code for objects using function() {} + . don't generate typechecks after the 4th efun arg + . fixed incorrect argument number in errors from above type checks + . varargs support + . fixed several bugs in foreach handling + . reordered code to fix forward references to functionals when they + occur in global initializers + . fixed continue and break branches for files which generate > 32k + of source + . added a lot of prototypes to cfuns.h so LPC->C code compiles more + quietly + . fixed a crasher in __TREE__ { /* something involving foreach */ } + +Sun Jul 30 11:11:12 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6b2 + * fixed error() to add a \n to the end of the string if one is not + present + * remove_call_out() [no args] now removes ALL this_object()'s call_outs + * added pluralize() prototype + * parser fixes: + . remote livings are always within reach + . fixed a bug that caused direct/indirect objects to not get + callbacks + . fixed a crasher when parse_my_rules tried to return an error + +Sat Jul 29 20:12:46 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.6b1 + * updated with respect to v21.5 + * added next_bit(). next_bit(string str, int foo) returns the + next bit set in str after foo, or -1 if foo is the last one + (str is a set_bit/clear_bit string). For example, to loop over + set bits: + int bit = -1; while ((bit = next_bit(str, bit)) != -1) { ... } + * Added a warning for (: string constant :) + * fixed another crasher in filter_mapping + * fixed crashers in promote_to_float and promote_to_int + * clarified the error message for passing x... to a non-varargs + function + * parser stuff: + . added parser support for 'me' and 'myself' + . fixed 'the' and 'a' support to not inappropriately gobble them + . added a debug mode turned on with an optional flag to + parse_sentence: parse_sentence(foo, 1) + . Added parser support for visibility: + ob->inventory_accessible() can objects inside be used? + ob->inventory_visible() can objects inside be seen? + as usual, they are cached, so call parse_refresh() if they change + . Added extra attributes for tokens; the for is XXX:wxyz + where w, x, y, z are one of: + l - must be living v - need not be accessible (visible only) + so "OBJ:l" is the same as "LIV", and "LIV:v" is someone you can + see. + . fixed a bug introduced in the get_single optimization that + erroneously reported ambiguous parses + . fixed STR to return the original text, not the sanitized version + . the 'verb' passed to verb_* rules are also no longer sanitized + . same with 'real names' of objects + . finished implementing the error messages, including 'There is no + X here' + . optimized STR rules a bit + . fixed a few bugs in finding interpretations with multi-word + tokens + . parse_sentence() can legally be called from do_* callbacks now + +--------------------------------------------------------------------------- +(v21.5b10 promoted to v21.5 with the following fixes) + + * fixed a crasher in deallocating classes with PACKAGE_MUDLIB_STATS + defined + * fixed a crasher in read_file() when reading just a portion of the + file + +Tue Jul 18 01:39:53 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.5b10 + * made push_lvalue_range() non-static; it's used in LPC->C code + * fixed a crasher in the F_SHORT_STRING fix + * fixed a crasher in ed messages when is used + +Sat Jul 15 14:30:37 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.5b9 + * Fix from Marius: define the crdir_fopen() function even if BINARIES + isn't defined + * fixed an LPC->C code generation bug that would change the third + character of the first function to a ')' in some files + * in LPC->C compilation, generate 'case x:;' and 'default:;' instead + of 'case x:' and 'default:' to satisfy picky compilers. + +Thu Jul 13 01:52:40 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.5b8 + * another F_SHORT_STRING string disassembly fix from Sym + * fixed a bug that caused classes to fail to restore from inside + classes/arrays/mappings + * fixed a bug that caused 'Inherit chain too deep' errors when + load_object() was called repeatedly on non-existent objects + * fixed the alpha crasher fix (I changed the wrong #ifdef merging + the changes into my local version) + * (: foo :) when foo is both a local function and a simul now gives + a pointer to the lfun, not the simul in line with the normal + visibility rules. + +Thu Jul 6 03:29:37 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.5b7 + * fix from Symmetry: use EXTRACT_UCHAR when disassembling + F_SHORT_STRING + * Alpha crasher fix: make sure there isn't any padding at the end + of the shared string and malloc'ed string structs so that they + overlap correctly + * don't use bison on AIX when compiling with xlC; xlC won't grok + bison's use of alloca + +Fri Jun 30 16:02:44 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.5b6 + * fixed a typo in socket_efuns.c + * fixed a bug that caused socket callbacks not to be called + (introduced with the v21.5b4 fix) + +Tue Jun 27 01:01:27 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.5b5 + * fixed MUD mode sockets to not abort the driver if they can't + allocate enough memory for a packet (due to garbage for the + length field, for example). The connection is killed instead. + +Thu Jun 15 09:00:09 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.5b3 + * fixed a LPC->C compilation error in range switch tables + +Mon Jun 12 04:03:58 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.5b2 + * fixed a bug that generated incorrect code for string switches + * fixed a typeclash in grammar.y.pre + * better fix for the obj/grammar.tab.o problem + * fixed a crasher in some assignments in LPC->C code + * fixed a crasher in casting a void valued efun, i.e. + return (int) destruct(ob) + +Sun Jun 11 04:04:49 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.5b1 + * updated with respect to v21.4 + * fixed a bunch of warning messages and unsafe casts for DEC Alpha + * added a call_stack() efun: for each internal as well as external + frame: + . call_stack(), call_stack(0) : an array of program names + . call_stack(1) : array of current objects (in that frame) + . call_stack(2) : array of function names + . call_stack(3) : array of what origin() returns in that frame + all the arrays are the same length; i.e. element 5 of call_stack(0) + is the same frame as element 5 of call_stack(2) + e.g. printf("I got called from %s in %s", call_stack(2)[0], + call_stack(0)[0]); + +--------------------------------------------------------------------------- +(v21.4b11 promoted to v21.4 with the following fix) + + * fixed a fatal error in compiling switches to C + +Sat Jun 3 05:24:08 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4b11 + * added Magician's fixes for pluralize() for words starting with 'b' + and 'c' + +Thu Jun 1 14:28:38 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4b10 + * added support for w->x[y] = z, w->x[y]++ and w->x[y]-- which was + accidentally omitted (generated 'Illegal lvalue' errors) + * fixed a crasher in strings longer than 64k + * fixed a compilation error crasher in x->foo when x was not a class + +Thu Jun 1 01:52:29 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4b9 + * removed a kludge to help older TMI-2 libs run. It was causing + delayed crashers after errors in add_actions(), as well as + screwing up the previous_object(-1) lists. I also think it was + the cause of the unresolved backend crashers around v21 or so. + * COMPAT_BUSTER: due to the above, previous_object() is now zero + in add_action()'ed functions + +Mon May 29 21:24:55 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4b8 + * fixed a bug that caused str[n..] to return garbage if n > strlen(str) + * fixed a compilation problem with LPC_TO_C off + * fixed a bad free() in edit_source that would cause defines to + mutate + * fixed a crasher when a socket which had a function pointer as a + callback was closed and then reused + * if a unbound socket is marked as needing a read, print an error + message and close it. This shouldn't ever happen, but evidentally + does and causes the CPU to race + +Sat May 27 00:39:07 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4b7 + * fixed a crasher in set_privs(ob, 0) + * fixed a crasher in message() when the destinatination was a string + that doesn't correspond to an object + * fixed a crasher in calling a function pointer in a swapped object + * fixed a bug that caused ./build.MudOS not to find 'make' if GNU + make wasn't installed + * fixed a bug in disassembling F_BBRANCH_LT and F_NEXT_FOREACH + (print as backwards, not forward branches) + * removed the switch stack; explicit jumps are used instead + * fixed a crasher in exiting foreach() via break or return + * cleaned up duplicated code in code generation for loops + * added support for verifying string lengths in md.c + +Tue May 23 17:59:12 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4b6 + * fixed a bug in the makefile dependencies that would cause the + wrong system libs to be used + * fixed a bug that when using older versions of gmake would give the + 'can't find rule for obj/grammar.tab.o' error + * updated the Makefiles, fixed a uid compilation problem + * removed some extra newlines at the end of compiler error messages + * fixed a crasher in calling functions() on a swapped object + * fixed a crasher in pluralize() + * fixed a bug that would cause parse errors/wierd error messages + if (: was followed by the end of a line + +Mon May 22 15:54:58 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4b5 + * fixed a read_file() to set it's return string size correctly + * fixed a bug that would kick you out of ed if you went to line -1 + * fixed pluralize() to make sure the string is zero terminated + * swapped two include files to prevent a definition of SE in + from overriding one in ; it causes + terminal negotiation to freeze output to the user + * fixed a bug that caused type errors when inheriting from a + program with #pragma save_types on which was saved as a binary + * upped the default optimization to -O3 on xlc + * fixed a crasher in assigning to indexed strings/array ranges + in LPC->C + * added LPC->C support for parse_command() and evaluate() + * put the O_CLONE flag back on replace_program() objects; makes + memory accounting efuns return slightly more intuitive values + and makes some sense. This means you can't clone from such an + object, but that's probably good since create() isn't what you'd + expect anyway + * fixed a bug that generated illegal LPC->C code if the last case in a + switch was empty (it's legal in LPC but not ANSI C) + * fixed a few typos in LPC->C code generation (i -> lpc_int) + * made the error messages for trying to compile something with a + functional more friendly (LPC->C) + +Sun May 21 09:17:34 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4b4 + * fixed a bug that caused void and int to be compatible + * modified svalue_to_string and sprintf() to use outbuffers + * modified bad_argument() to use an outbuffer + * modified *_IN_TRACEBACK to use an outbuffer + * fixed outbuffers to truncate if they accumulate > 64k of data + * fixed a bunch of lines in interpret.c which had a space + before the preprocessor directive + * cleaned up some more uses of MSTR_SIZE/COUNTED_STRLEN to fix + more bugs with > 64k strings + * fixed a typo in the string switch type error message + * optimized STRING_STATS a bit (only do COUNTED_STRLEN() once + in places) + * set up an error context before calling flag() in master in case + there is an error + * check_memory() updated to know about the new malloc'ed strings + * optimized/cleaned up break_string() + * fixed a memory leak due to functionals keeping programs loaded + * fixed a memory leak in throw() + * fixed a memory leak in [0..n] array ranges on ref 1 arrays + +Sat May 20 10:21:58 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4b3 + * fixed a syntax error with PACKAGE_MUDLIB_STATS defined + * fixed a name conflict between mudlib_stats.c and + packages/mudlib_stats.c; moved all mudlib_stats and uid + code into the appropriate package file + * removed some remaining DEALLOCATE_MEMORY_AT_SHUTDOWN code + * edit_source -configure now checks for POSIX getcwd() + and + * fixed a problem where edit_source would abort if a define + in local_options and options.h had different values (it died + with a redefinition warning) + * fixed a lot of compilation warnings under SGI cc -fullwarn + * fixed a bug where __PORT__ was zero when specifying sockets + as external_port_x + * fixed a crasher in socket_address() + +Wed May 17 15:30:02 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4b2 + * fixed a typo in cfuns.h + * fixed a problem with parsing of line specifiers which was causing + search in ed to not return an error message; changed the message + for search failing + * fixed a bug in SVALUE_STRLEN that would cause crashes involving + strings longer than 64k + +Tue May 16 16:24:21 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.4b1 + * fixed a typo in dumpstat.c + * added Aragorn's patch to allow %x to specify hexidecimal in sscanf + * partially rewrote the contrib efun pluralize() to handle 'X of Y' + and clear up some crashers, as well as be a bit more robust/efficient + * cleaned up some gcc -Wall warnings + * include configure.h as well as std_incl.h when testing for existence + of header files. This fixes misconfiguration bugs with respect to + rusage() on some systems (SunOS, ...) + * fixed outbuf_t compilation problems in comm.c on some systems + * fixed a crasher when explode() returned an array that was truncated + due to max_array_size + +--------------------------------------------------------------------------- +(v21.3b5 promoted to v21.3) + +Mon May 15 02:46:10 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.3b5 + * fixed a bug in code generation for addition; would produce incorrect + code when LHS was a number or real and RHS was type string or mixed + +Sat Apr 29 23:59:18 CDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.3b4 + * fixed a badly indented line in the GNUmakefile + * fixed some OBJDIR rules to not cause recompilation of a lot of + things when using GNU make + * fixed generation of package Makefiles + +Sat Apr 29 23:59:18 CDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.3b3 + * fixed some compilation problems with LPC->C off + * put in a better fix for the function pointer to void valued efun + problem; a debug check was erroneously misfiring on the old + version + +Sat Apr 29 20:58:34 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.3b2 + * changed some #ifdef 0's to #if 0's + * added a check to use -m486 when compiling using gcc on a 486 + * fixed a crasher in self-destructing objects with call_outs + * fixed a crasher with calling reload_object() when call_outs to + function pointers existed + * fixed TELOPT_NAWS to properly handle zero bytes; caused the + reported screen size to be in the 17000 range + * fixed a typo in the missing type for argument fix in v21.3a7 + * fixed a macro that xlc complained about in lex.c + * fixed a crasher in calling reload_object() on a swapped object + * fixed a crasher in reclaim_objects() with function pointers with + no arguments + * fixed a crasher in edit_source + * #ifdefs are now legal in packages/*_spec.c + * updated 'Install' with the new build procedure + +Sat Apr 29 20:58:34 EDT 1995 (tim@handel.princeton.edu (Beek)) + * v21.3a7 promoted to v21.3b1 + +--------------------------------------------------------------------------- +(v21.2b8 promoted to v21.2) + +Sun Apr 23 21:02:52 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.2b8 + * fixed a crasher in efun pointers to void valued efuns + +Fri Apr 21 01:17:24 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.2b6 + * fixed a bug that caused all the login ports to try to use the + same port number + * fixed a crasher in PORT_ASCII objects which dest themselves + from inside process_input() + * fixed a crasher that would occasionally generate the wrong + code for default arguments + * Added a missing \n in the Function is no longer a simul error + message + * Fixed a crasher in short style efun pointers (: efun, x, y ... :) + * changed a bunch of references to 'vec' in the source to 'arr' + since we no longer refer to arrays as 'vectors' :) + * removed the port_number variable internally, the external_port + array is used everywhere now + * changed the -p switch to change the port of external_port_1 + * added some missing commas in the %O output of function pointers + * the refs() contrib efun was updated to know about classes + +Tue Apr 18 17:30:51 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.2b5 + * fixed a crasher in bind() on lfun/efun/simul function pointers + with no arguments + * fixed a crasher in call_out_list() when a destructed object + had a pending call_out + * fixed socket_address(object) to convert the port number back + to host byte ordering (from Angus@Styx) + * fixed a crasher after compiling 256 break statements + * fixed a typo in the GNUmakefile + * sockets are now initialized before preload() is called, so it + is possible to preload socket objects + * name the spec files in packages/ foo_spec.c instead of foo.spec + to avoid a gcc bug + * include all include files found up to a given point in include + tests; needs etc. + * make sure TELNET_NAWS is in , otherwise use the + one in the MudOS distribution + * fixed a crasher in set_hide() when the valid_hide() check failed + * fixed a crasher in anonymous functions with empty blocks + function(...) {} + * removed some unnecessary prototypes from lint.h; the configuration + process now finds the appropriate includes + * mark the config strings as being correctly allocated for + check_memory() + * fixed a bug where Linux 1.2.1 sometimes returns ECONNREFUSED + from recvfrom() for UDP sockets when an ICMP_PORT_UNREACHED + is generated internally + * fixed a compiling problem with pluralize() in the contrib packages + +Tue Apr 18 17:30:51 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.2b4 + * fixed a crasher in calling process_input() for PORT_BINARY and + PORT_ASCII ports + * fixed a bug that would cause the first efun (alphabetically) to + do nothing + * fixed a typo in a call to debug_message_with_location() in simulate.c + * fixed a mis-optimization of typeof() that caused it to always + return 2 + +Mon Apr 10 23:41:33 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.2b3 + * added Symmetry's fix so OSFLAGS gets propagated to the makefiles + for AIX + * fixed a typo in the v21.1b2 regexp fix + * removed an unused definition of find_status() + +Fri Apr 7 12:57:56 EDT 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.2b2 + * reorganized the v21.1 changelog entry to be more concise/clear + * fixed a bug that would loop forever on partial matches when + finding a substring in a string using strsrch() search from the + right + * fixed regexp.c on Linux to define CHARBITS correctly; won't work + on systems with non-8 bit chars, but the old code seems to be + incorrect. + * Next two fixes from Aragorn: + . Fixed the warning about too many file descriptors to print the + right number + . Don't free 'use_name' until after we're done using 'file' since + 'file' may point at it + +Fri Mar 24 20:59:08 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.2b1 + * v21.1b7 promoted to minor version status (see v21.1) + * Changed the error message for arr[ sizeof(arr) + to 'Array index out of bounds' from 'Negative index passed to array' + * fixed the extern definition of control_stack[] to use MAX_TRACE + instead of being hardcoded at the default + +------------------------------------------------------------------------------ +Fri Mar 24 20:59:08 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.1b7 + * fixed a crasher in call_out(function, ...) when NO_SHADOWS + was off + * removed a check for destructed objects in get_all_call_outs() + which: + (a) didn't remove destructed objects + (b) removed call_outs to function pointers + * added in the config file crasher fix from v21.2a5 + +Sun Mar 19 21:02:18 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.1b6 + * fixed a small optimization to backend.c introduced in v21.1b5 + * fixed a typo in the v21.1b5 type check fix + * Robocoder: in config files, restrict sscanf() matches to + the current line + +Sat Mar 4 16:04:43 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.1b5 + * some amiga compilation fixes from Robocoder + * added some smalloc accounting fixes from Robocoder; keep track + of wasted memory as well as some more overhead + * cast IAC to signed char so it is compatible with (char *) + * fixed a bug in type checking that made (class foo *) and (mixed *) + incompatible + * fixed a typo in the prototype fix from v21.1b4 + * defining two classes with the same name is now an error + * compilation fix for IRIX 5.3 (needs ) + +Sat Mar 4 16:04:43 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.1b4 + * fixed a ref count error/crasher in inherits() + * fixed a ref count bug/memory leak (programs referenced by + non-bindable function pointers weren't being freed) + * added code to check function references to programs in md.c + * added in some porting fixes for CX/UX 6.1 (from DrFeelgood) + * fixed a memory munger in regular expressions that end in '\' + * fixed inherited functions which have a different number of + arguments than the functions they replace to not error + +Sat Mar 4 16:04:43 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.1b3 + * removed some debugging code in lex.c + * fixed a typo that prevented #undef OLD_ED compilation + * fixed compilation with #undef NO_MUDLIB_STATS + * fixed a crasher in type errors in division + * fixed a division error message that erroneously indicated + multiplication + * fixed a type error in locals used in anonymous functions + * fixed a bug in smalloc accounting + +Wed Mar 1 18:14:01 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.1b2 + * brought up to date with respect to v21c1 + +Wed Mar 1 18:14:01 EST 1995 (tim@handel.princeton.edu (Beek)) + * raised patchlevel to v21.1b1 + * added three new contrib efuns: + . int replaceable(object) - returns 1 if the object consists only + of a create() function and inherited functions + . void program_info() - prints out memory usage of programs + divided up by sections + . string upper_case() - similar to lower_case(), but ... :) + * fixed a crasher in the compilation of switch tables to C code + * rewrote/optimized some of the compile time type checking + * void efuns no longer return a value on the stack. If the value + is used (c.f. x = write("hi")) a F_CONST0 instruction is inserted + * removed the errorp() efun + * added a customized allocator for mapping nodes. This should reduce + memory usage and increase speed of additions/deletions + * removed RUNTIME_LOADING from options.h + * fixed a crasher involving finding duplicate objects in the hash + table with LPC objects precompiled and DEBUG on + * changed program ref counts to shorts diff --git a/fluffos-2.23-ds03/ChangeLog.fluffos b/fluffos-2.23-ds03/ChangeLog.fluffos new file mode 100644 index 0000000..a2e6e99 --- /dev/null +++ b/fluffos-2.23-ds03/ChangeLog.fluffos @@ -0,0 +1,220 @@ +As MudOS is moving too slow to keep our driver hacks apart, we now call our own +FluffOS :) +new in FluffOS 1.36 +Fixed crasher when doing restore_variable("(//)") +Fixed crasher when using 256 local variables in a function pointer + +new in FluffOS 1.35 +Fixed crasher when too many classes are used (parser using error result) +Fixed crasher with efun:: in function pointers when the efun override wasn't allowed + +new in FluffOS 1.34 +Fixed crashers in the reference keeping linked list +Fixed crasher when connections are not routed to any object +Changed compiling for -DDEBUG to work with modern glibc (turrican) +Fixed bug in regprop() (turrican) +Fixed crasher in max/min (woom) + +new in FluffOS 1.33 +Fixed typo in above line +Added vowel/add_a and num_classes efuns (Woom) +Added max/min/rell_MdN efuns (Woom) +Corrected functions/variables prototype (reported by Woom) +Changed makefile so make -j works most of the time +Fixed ++ on LPC floats (reported by Woom) +Fixed error message + crasher in element_of() + +new in FluffOS 1.32 +Fix for nomask and shadows (simon@boo.org) +Make tab warnings optional (Skullslayer@Realms of the Dragon) +Compile fix in interpret.c (Skullslayer@Realms of the Dragon) +this_object() is now the default argument to base_name(); +Fixed crasher in terminal_colour() + +new in FluffOS 1.31 +Fixed crasher in terminal_colour() +Changed heartbeats to run relative to mud time (time() in the mud) and never + never skip them anymore +Changed eval cost code to use signals, removed kernel module code and the + (VERY) slow fallback code there was before + +new in FluffOS 1.30 +added driver apply for mxp reply tags received from clients +fixed crasher in functions() (DEBUG mode, probably corrupted memory) +fixed optimizer bug (Pelle Johansson peljo105 at student.liu.se) (from the + mudos develop mailing list) + +new in FluffOS 1.29 +fixed bug in terminal_colour() +can now be compiled with tcc (you need to add a -DTCC flag) +no longer use alloca in bison + +new in FluffOS 1.28 +fixes to compile with other settings than the DW ones (Skullslayer@Realms of the Dragon) +fix in reverse DNS lookup (Skullslayer@Realms of the Dragon) +properly do the zlib stuff (Skullslayer@Realms of the Dragon) +terminal_colour fix (pinkfish) +new element_of efun which takes a random element from an array +readded pluralize cases that were accidently lost in the last version + +new in FluffOS 1.27 +update to terminal_colour() (Pinkfish) +added option to use mmap instead of sbrk for included malloc packages + +new in FluffOS 1.26 +check resets every 5 minutes +new malloc package (GNU) + +new in FluffOS 1.25 +fixed crasher in icode.c (Pinkfish) +close external ports for external commands(they don't need the telnet port etc) + +new in FluffOS 1.24 +added mxp support (Pinkfish) +updated with respect to MudOS v22.2b14 + +new in FluffOS 1.23 +fixed crasher in sprintf +fixed crasher in compressed files (by pinkfish) + +new in FluffOS 1.22 +fixed compiling a development version +eval_cost reset for each call_out()ed function +some fixes to pluralize() + +new in FluffOS 1.21 +changed allocating structure for efun function pointers to allocate space for + a full function pointer struct +fixed the bug in mapping *map=({([])}); map[0]["bing"] = 1; +no longer convert floats to doubles and back when they go on the LPC stack +warn for tabs and MSDOS ^M chars in source code +removed some debugging printfs + +new in FluffOS 1.20 +fixed some array size issues +cleaned up some source (used pointer + x to index instead of pointer[x]) +fixed some lint warnings +fixed compiling a DEBUG driver +fixed compiling with TRACE defined +added check for corrupted objects in debug mode +fixed buffer overruns and underruns in pluralize +new get_garbage() efun, return objects with no external references that are + not in other objects and not shadowing anything + +new in FluffOS 1.19 +unlink the shared function name string in functions() before returning it. +fixed compile errors with the intel(R) C++ compiler(7.0) + +new in FluffOS 1.18 +call the mudlib crash function even when printing the error trace gave a + fatal error as well. +added check for destructed objects in apply_low() + +new in FluffOS 1.17 +fixed writing over shared strings (yay const!) +fixed some buffer overflows + +new in FluffOS 1.16 +stop parsing after illegal to inherit error (crasher) +fixed some uninitialised variables +started using 'const' + +new in FluffOS 1.15 +many local buffers (on the stack) are now bigger to avoid overflow +class names, class member names and function names are no longer stored as + name, but as classname, membername and funcname instead (for easier + debugging) +now uses the v22.2 database code instead of forward ported v22.1 +fixed bug in call_other type warnings + +new in FluffOS 1.14 +changed size of a local sprintf buffer from 100 to 1024 (100 must be really + easy to reach) +changed object struct name field to obname, there are too many struct fields + called name. +fixed malloc selecting code +removed part of the crasher fix of 1.13 + +new in FluffOS 1.13 +fixed crasher in global_ref_list cleanup (just the crasher, i suspect the + list is borken as well +added base_name() efun + +new in FluffOS 1.12 +updated with respect to MudOS v22.2b13 +removed some mixing of signed and unsigned chars +added mmap based malloc option (MMALLOC) +added option to make call_other type errors warnings + +new in FluffOS 1.11 +shuffle() efun by Taffyd +crasher fixes (copied from divided skys) +memory leak fix (also from DS) + +new in FluffOS 1.10: +fixed bug in reference_allowed where invis would stop working +changed the return value of save_object to the amount of bytes (uncompressed) + after the line with the object name (#/global/player) +exit forked driver if exec fails in external commands, rather than having + multiple drivers going. + +new in FluffOS 1.9: +some small fixes to reference_allowed +fixed (i hope) endless loop in compressed output + +new in FluffOS 1.8: +reference_allowed efun (by Taffyd) +fixed crasher in ... when used in building arrays (reported by Presto). + avoid using it for that though, it's _very_ inefficient. + +new in FluffOS 1.7: +return of the event() efun +member_array extended for partial searches and searching from the end of the + array +query_num(): returns the int argument as a string in the (1 -> one), optional + second argument specifies where it starts returning "many" +query_multiple_short(): see discworld lib docs, done by Taffyd. + +new in FluffOS 1.6: +this changelog is now in the FluffOS archive! +fixed crasher in dumpstat (used by mem_info) +added (optional) type checking for call_other calls +changed variable assignment type checking from warnings to errors, using the + parser's warning system changed the current file/line variables, and + this could happen during compilation... +updated options.h + +new in FluffOS 1.5: +fixed crasher after errors in save_object. (reported by pinkfish) +fixed crasher in interpret caused by find_line return a pointer to a local var +fixed crasher with switch statements that only contain a default case, they + are no longer allowed (reported by Vashti) + +new in FluffOS 1.4: +added compressedp efun, it shows if an interactive uses MCCP (pinkfish) +fixed crasher in type checking code during compilation error (reported by + sightblinder) +fixed crasher in compressedp + +new in FluffOS 1.3: +fixed crasher with buffer overflow in output +fixed loading compressed save files + +new in FluffOS 1.2: +updated with respect to MudOS v22.2b12 +fixed eval cost bug for first object loaded after the preload +increased line buffer size for loading compressed save files + +new in FluffOS 1.1: +Uses a kernal module to get cpu times. + +FluffOS 1.0: +changes since MudOS v22.2b11 (as far as i can remember) +Type warnings added +compressed save files +eval limit is now based on time taken, rather than substracting random numbers + to account for actions. + +Many bug fixes :) + +Wodan. diff --git a/fluffos-2.23-ds03/ChangeLog.fluffos-2.x b/fluffos-2.23-ds03/ChangeLog.fluffos-2.x new file mode 100644 index 0000000..5eeca52 --- /dev/null +++ b/fluffos-2.23-ds03/ChangeLog.fluffos-2.x @@ -0,0 +1,460 @@ +As MudOS is moving too slow to keep our driver hacks apart, we now call our own +FluffOS :), note: where it says Cratylus, I got it from his version, usually +someone else did the work, but I don't know how to find who did what there. + +FluffOS 2.23 +added a terminal_colour_replace apply, this will be called with every string between two %^ delimiters, and will be replaced with whatever is returned. +fixed protocol number for GMCP +fixed sprintf code for MSSP uptime +added defer efun, it takes a function pointer that will be called when the current function ends (even if that was caused by a runtime) +the old range behaviour warning for negative array indexes is now optional +the driver can now be compiled to use either struct or class for structs, or even allow both +fixed crasher in uniq_array +fixed crasher in socket_status +added missing ',' in non iconv driver pcre support +FluffOS 2.22 +fixed potential crasher in pcre_extract +removed limit for number of matches in pcre efuns +added classes() efun (woom) + classes(ob) returns a list of class names available in ob + classes(ob, 1) returns the same list, with all the fields in the class (type and name) +you can now have more than 256 Globals (qwer@lpmuds.net) +added postgres support (unagi@lpmuds.net) +fixed zmp crash +removed some obsolete malloc options +FluffOS 2.21 +small cleanup in malloc32 +added gmcp support + gmcp_enable() gets called when a user has gmcp + gmcp() will get called with any received message + send_gmcp(string) will send the string as a gmcp message + has_gmcp(object) returns if the object supports gmcp +fixed sorting when the compare function returns values that don't fit in a 32 bit int. +fixed memory leak in sorting +new deep_inventory functionality (tiz) + it can now take an array of objects, and a function pointer that can return + 0 don't include this object or it's contents + 1 do include + 2 include this object but not it's contents + 3 don't include this object but do add the contents + the function will be called with one object from the inventory (for each object looked at) +fixed memory leak in new deep_inventory +added pcre support (Volothamp@Final Realms) + string pcre_version(void); + version of the pcre lib + mixed pcre_match(string | string *, string, void | int); + like the regexp efun + mixed *pcre_assoc(string, string *, mixed *, mixed | void); + like reg_assoc + string *pcre_extract(string, string); + extract matching parts + string pcre_replace(string, string, string *); + string replace, one entry in the array for each match + string pcre_replace_callback(string, string, string | function, ...); + string replace uses a callback to get the replace string (called with the matched string and match number, starting with 0) + mapping pcre_cache(void); + returns content of the pcre cache (not all that useful) +fixed memory leaks in pcre efuns +fixed crashers in pcre efuns +small optimisation in reg_assoc and pcre_assoc +fixed memory leak in compiling files +restore_object will no longer randomly set 0 values as undefined +fixed crasher in asking for an unused config setting +sprintf buffer is now big enough for max string size +fixed crasher in async_db_exec (never seen for real, but it was possible!) +db_fetch will no longer randomly return some 0s as undefined +dwlib package now has a replace_dollars function which searches for patterns starting with a $ only, otherwise the same as replace() (but faster as it only scans once) + +FluffOS 2.20 +more error checks in malloc64 +bigger arrays (up to 2^31 elements) +bigger mappings (see arrays) +more efficient clean_up() +setting sockets to close on exec done in a more compatible way (only worked on rather new linux kernels) +no longer sends mccp messages when already compressed (fixes older cmud versions) +some cleanups for compiler warnings +new roulette_wheel() efun in the dwlib package (Woom) +new replace_objects() efun int the dwlib package (replaces all object references in the argument with filenames recursively) +check_valid_path apply now also used for compile paths (source files) +32BIT fix (Kalinash) +use less chars for string hashes (faster) +correctly do tables in (s)printf with utf-8 strings +use the already existing precalculated string hashes more often +save string length for bigger strings as well instead of using strlen on strings > 64k all the time +NetBSD IPV6 fix (Tiz) +fixed crasher in reference_allowed() (in dwlib.c) + +FluffOS 2.19 +attempt to fix string block alignments. hopefuly helps sparc64 +open sockets as close on exec if available (so they don't end up in external programs started from the driver) +fix conflict between ed and solaris (both used the same define!) +fix bug with freeing an object table in backend.c +some fixes for sparc64 (Kalinash) +added missing Mysql data types so they don't always get returned as 0 anymore +changed some optional efun args to default to 0 instead for slightly cleaner code (Woom) +new addition to pluralize() (diff from Cratylus) + +FluffOS 2.18 +compiles for netbsd (tiz) +make more empty arrays point to the_null_array, saves memory and allows + comparing with ({}) to see if arrays are empty (reported by Woom) +clear this_user etc when runtimes get us all the way back to backend() +fix the inherits() return value if the inherit was indirectly inherited + (reported by Woom) +member_array now return -1 for failure if you search beyond the end of the array + (reported by Woom) +no longer loops forever when adding a reference whole destructing things with + too many references +fixed crasher in async db_exec +fixed crasher in filedescriptor leak fix +parser changed to be less strict (Cratylus) +stop wasting memory if repeat_string would exceed max string size (reported by woom) +fixed crasher in pragma optimize + +FluffOS 2.17 +math package updates: Added vector norm, dotprod, distance, angle. + Also added log2() and round() which works on floats (surprisingly useful). + Added int args to the efuns as apppropriate (Hamlet) +fixed above so the int args actually work without needing casts for the result +fixed 64bit malloc for large allocations (never happened on dw, so I doubt it was a problem!) +added 32bit malloc (malloc32) which is sysmalloc with realloc replaced by + malloc->memcpy->free, saves lots of memory +telnet environment support (Cratylus) +windows compile fix for add_action (Cratylus) +added dtrace support! just define DTRACE in local_options if you have it +zmp support + zmp calls from the client result in an apply on the player object + zmp_command(string command, string *args); + sending zmp is done with + send_zmp(string command, string *args); + check if a player supports zmp, returns 1 if they do, 0 otherwise. + has_zmp(object player) + note: zmp protocol is just a way to transfer information for zmp packages, + You'll still need to implement those in LPC +fixed the use of select() +compiles with C++ again (with dw's local_options anyway) +even more places to look for mysql libs +fixed profiling recursive functions +fixed profiling when a runtime error happens +fixed filedescriptor leak with compressed save files +fixed crasher in unloading object programs (this should have happened constantly + , so there's probably a bug preventing this from actually happening most + of the time). +the driver now finishes all async IO before finishing shutdown() +blocked socket fix for lpc network sockets (Hamlet) +package async now does sql! + async_db_exec(int db, string request, function callback); + don't use the same database handle with this call if you also use it + with db_exec(), just make an extra connection for your async sql. +new efun restore_from_string(string savedata), does what it says on the tin, + the string format is the same as a save file. +added optional int argument to request_term_size(). If 0, the client is asked + _not_ to offer any further term size updates (Hamlet, suggested by Detah) + +FluffOS 2.16 +improved single char mode support (Cratylus) + this includes some new efuns: + int query_charmode(object); + int remove_charmode(object); + int remove_get_char(object); +efun to send nullbytes (Raudhrskal) + int send_nullbyte(object); +improved ed failure mess (Cratylus) +new no arguments version of save_object, which returns the save string +fix to stop iconv looping forever +faster hashing for big strings (now stops after 1000 chars) +some new predefines (Cratylus) +async io fixes, sadly now requires pthreads +parser update (Cratylus) +sqlite support (Ajandurah@Demonslair) +compile warning fixes (Ajandurah@Demonslair) +crypto and sha1 package (Ajandurah@Demonslair) +added MSSP support, the driver will call get_mud_stats() on the master ob, + which should return a mapping with the keys/values, if a value is an + array of strings they'll all be sent as values for that key. The driver + send the NAME (from config file) PLAYERS and UPTIME values if the + function doesn't exist, if it does but didn't include one of those fields + the driver will add the field as those are required. +new malloc option malloc64 which tries to avoid needing big copies on realloc by spreading all allocations a few MB apart in virtual memory. + +FluffOS 2.15: +IPV6 support +class stats (Skullslayer@Realms of the Dragon) +some console additions see 'help' in the console (Hamlet) +some 64 bit fixes (Woom) +compiles with C90 compilers (that's 19!!! years ago now) (Kalinash@lpmuds.net) +added string_difference(string, string) which returns the difference between strings as a number (Woom) +updated MySQL support (Shadyman@lpmuds.net) +fixed crasher when the master apply doesn't allow an object to be created + + +FluffOS 2.14: +fixed crasher in async writes. +fixed bug in switch/case when using more than 2GB memory +check 64 bit lib before 32 bit version for mysql +support classes in member_array +fixed copyright statement in regex file +fixed memory leak in large shared strings +fixed some memory leaks in async io +use clone_object sefun (if present) when cloning objects with new() (Kalinash) + +FluffOS 2.13: +oh no! unlucky number +removed binaries support +fixed crasher in restore_string +fixed some new compiler warnings (gcc 4.3) +some cleanups in comm.c (Cratylus@Dead souls) +cygwin and other changes in build.FluffOS (Cratylus@Dead souls) +set program_t to {0} for silly OSes that don't clear BBS memory (Cratylus@Dead souls) + (I think there may be more places that could go wrong!) +changed locale to "C" (Cratylus@Dead souls) +Added a console, mostly for debugging use. If driver is started directly + rather than through a script, add argument -C and it has a + command-line. try 'help'. HAS_CONSOLE must be defined in + local_options. (hamlet) +fixed crasher where we did remove_interactive when people go netdead, bad idea! + +FluffOS 2.12: +Crasher fixes in using a mudlib error handler (Cratylus@Dead souls) +some mingw fixes (Cratylus@Dead souls) +new localoptions.ds (Cratylus@Dead souls) +rework of ed to do larger output chunks, more configurability, and bugfixes: + mixed receive_ed(string msg, string fname) apply in playerob to + doctor the text (return 0 to have ed output to screen, 1 to have ed + output nothing, or return a new string for ed to output). Need to + define RECEIVE_ED in options.h. ed_start() and ed() take optional + final arg specifying lines on user's screen. Indentant fixed for + 'foreach' and lines with only '//'. z++ and z-- now work. Optional + new compile-time defines: ED_INDENT_CASE (should we indent 'case' + after 'switch'?) and ED_INDENT_SPACES for how far autoindent + will indent each level. (hamlet) +fixed several crashers (comm.c and simulate.c) related to using vsprintf + instead of vsnprintf. (hamlet) +added CFG_MAX_GLOBAL_VARIABLES to options.h. Old setting was an arbitrary 256. + (hamlet) +async writes with compression +fixed some memory leaks +stuff I forgot, it's been too long! +slightly useful sfuns if you use async: + +void decode(object ob, int flag, function cb, string saved){ + string *lines = explode(saved, "\n"); + mixed vars = filter(variables(ob,1), (:strsrch($1[1], "nosave") == -1:)); + vars = map(vars, (:$1[0]:)); + if(!flag) + map(vars, bind((:store_variable($1, 0):), ob)); + vars = allocate_mapping(vars, 1); + + foreach(string line in lines){ + if(line[0] == '#') + continue; + else { + int i = strsrch(line, ' '); + if(vars[line[0..i-1]]) + evaluate(bind((:store_variable, line[0..i-1], restore_variable(line[i+1\..]):), ob)); + } + } + evaluate(cb); +} + +void restore_object_async(string name, int flag, function cb){ + async_read(name, (: decode, previous_object(), flag, cb :)); +} + +void save_object_async(string name, int flag, function cb){ + mixed vars = filter(variables(previous_object(),1), (:strsrch($1[1], "nosave"\) == -1:)); + string *lines = allocate(sizeof(vars)+1); + vars = map(vars, (:$1[0]:)); + lines[0] = "#"+base_name(previous_object())+".c"; + for(int i = 0; i < sizeof(vars); i++){ + string val = save_variable(evaluate(bind((:fetch_variable, vars[i]:), previ\ous_object()))); + if(flag & 1 || val) + lines[i+1] = vars[i] + " " + val; + } + async_write(name, implode(lines, "\n"), flag | 1, cb); +} + +FluffOS 2.11: +stop eval_cost() adding to the time you're allowed to run. (libc return a time + longer than the set time if you query the remaining time right after + restarting the timer! +reset_eval_cost() now stops working after 100*max eval cost. +hopefully fixed readfile with lines beyond max readsize. + +FluffOS 2.10: +can be compiled with g++ +fix bugs in using arrays as sets + int *a=({1<<31,0}); return a-a +fixed crash in the children efun (hamlet) + +FluffOS 2.9: +removed amiga support. +included most DS changes, should work on windows now (except for over + evaluation errors) +changed alist_cmp to work on longs rather than int, and store program offsets + as 32 bit ints (instead of 64 (with room for 32) which fixed crashing + with 64 bit on solaris and stopped crashing on linux when using over + 2GB memory. +added package async for async read and write support. +removed some dead code +fixed crasher in read_file() (i hope) +fixed makefile so it doesn't rebuild everything all the time +slightly bigger buffers for lex.c so it can load files quicker. +made buffer handling in loading compressed save files a bit smarter +fixed bug in children() +actually calculate the hash values for objects again, oops. +fixed crasher in event() +moved some functions to package contrib: +int num_classes( object ); + returns the amount of class definitions in the object +mixed assemble_class( mixed * ); + returns a class with fields filled in from the array arg +mixed *disassemble_class( mixed ); + returns an array with all class elements +mixed fetch_class_member( mixed, int ); + same as disassemble_class(mixed)[int]; +mixed store_class_member( mixed, int, mixed ); + set a class member by offset +mixed *shuffle(mixed *); + shuffle array members around and return the array (original is changed as + well!) +mixed element_of(mixed *); + same as array[random(sizeof(array))] +mixed max( mixed *, int | void ); + returns the max value in the array, or the index of that value if the + second argument is present and not 0 +mixed min( mixed *, int | void ); + see max, but then lowest +mixed abs( int | float ); + guess. +FluffOS 2.8: +use a hash table for the children() efun +set the usec field in the select timeout +fixed sending sending byte value 255 (this will break any code that tries to + send telnet code, but that shouldn't be needed anyway and it didn't work + on UTF enabled drivers already. +removed a lot of casts to int, C does that by default, so it's not needed. +replaced whashstr with a simpler, faster (on modern CPUs) hash that isn't + limited to 16 bit results +fixed to_int so it doesn't truncate to 32 bit on 64 bit systems +now fills in maxrss in rusage on linux +changed from SIGALRM to SIGVTALRM, so other processes can't mess up the eval + time +added a __LINE__ predefine for the line number +changed mappings to use the hash function rather than pointer values for a + better spread over the hash table +the flag argument to functions() now uses 1 for extra info, 2 for limiting + the returned functions to those that are not inherited, those can be + combined (3) +replace_html and replace_mxp do the < to < etc conversions +random() can now return larger than 32 bit numbers +commented out a recursion check in the parser so DS can parse its commands + +FluffOS 2.7: +fixes to compile with a Dead Souls config +changed free_object() and free_program() to overwrite the freed address + (idea and first version by Pinkfish) +terminate string results of filter_string() +disable run time type checking if strict types isn't on +allow adding objects to strings (adds filename) +fixed crasher in DEBUG mode +send too long eval errors to the mudlib error handler, there's no real reason + not to! +fixed crasher for 64 bit dead souls +possibly fixed some bugs in shuffling around code for free_object +allow string a="dsfsd"; a+=10; it used to give a parse error! the code to + handle it was there though +read_file() can now read compressed files. +write_file() now has an extra flag (2) that can be ORed with the existing one + to write/append compressed files +add_ref() destruct objects with high ref counts (they're usually on the way to + wrap around to 0, which is where you crash). + +FluffOS 2.6: +current_time is now 64 bit on 64 bit platforms, all ready for 2038 now, I think :) +fixed crasher in ed on big files with long lines (i hope) +new default arguments for destruct, virtualp, inherits (this_object) and ctime (time()) +removed some code duplication in call_function_pointer() +switch(number){ + case ..1: + return "low"; + case 2: + return "middle"; + case 3..: + return "high"; +} +now works! + +new WOMBLES config option that disallows spaces in ({ ([ (: :) ]) }) when used + for arrays, mappings and functionals. + +fixed 64 bit compiles so you don't need to use one specific compiler with no optimisations anymore + +made the objects list double linked so destruct doesn't have to walk the whole + list to find the previous object in the list. +fixed compiling without shadows support + +FluffOS 2.5: +some pluralize() fixes (woom) +fixed zonetime() and is_daylight_savings_time() + +FluffOS 2.4: +new efuns for sending telnet sequences: + void request_term_type(); + void start_request_term_type(); + void request_term_size(); +restore_object now calls restore_lost_variable() if a variable in the save file + doesn't exist in the object, the arguments are the value and name of + the saved variable. +fixed crasher in event() when one of the earlier objects destructs an object + that still would have gotten the event. + +FluffOS 2.3: +fixed event efun (from 1.40) +added MAX_INT and SIZEOFINT predefines (from 1.40) +fixed leftover PROT1V macro use +replace is an efun now +virtual base obs are no longer seen as clones + +FluffOS 2.2: +removed some more object swapping code +fixed memory leak in restoring gzipped save files +improved LPC function profiling +fixed ref counts in class/array efuns + +FluffOS 2.1: +added str_to_arr, and arr_to_str efuns to convert between strings and UTF-32 arrays +added strwidth efun +fixed refs() for strings + +FluffOS 2.0: +different from Fluffos 1.36: + +changed integer type to 64 bit, and some other 64 bit cleanups, as 64 bit ints +change the way things work for the LPC side of things, I changed the major +number to 2. +removed swapping, the OS can do it much better than us. +removed LPC_TO_C as it has been broken for as long as i can remember (MudOSv21 + times) +removed the annoying PROT P1 etc macros if you still use a K&R compiler it's + time to upgrade! +removed varargs.h support +removed warnings during compiling (with supplied localoptions file) +removed gdbm files as they couldn't even be used (no spec file!) +removed dw specific debugging code +added iconv support + If activated: + All text in the mud is UTF-8 + + int set_encoding(string); //sets the encoding for this_players + string to_utf8(string, string); //convert enc encoded str to UTF-8 + string utf8_to(string, string); //convert UTF-8 encoded str to enc + +some additions to pluralize() (woom) +new functions in dwlib package (woom) + mixed abs( int | float ); + mixed assemble_class( mixed * ); + mixed *disassemble_class( mixed ); + mixed fetch_class_member( mixed, int ); + void store_class_member( mixed, int, mixed ); + diff --git a/fluffos-2.23-ds03/Config.example b/fluffos-2.23-ds03/Config.example new file mode 100644 index 0000000..5ea7ec3 --- /dev/null +++ b/fluffos-2.23-ds03/Config.example @@ -0,0 +1,158 @@ +############################################################################### +# Customizable runtime config file for MudOS v21 # +############################################################################### +# NOTE: All paths specified here are relative to the mudlib directory except # +# for mudlib directory, and binary directory. # +# Lines beginning with a # or a newline are ignored. # +############################################################################### + +# name of this mud +name : testsuite + +# for machines with multiple IP addresses, this specifies which one to use. this +# replaces the SERVER_IP compile-time define. +#mud ip : 255.255.255.255 + +# if MudOS inherits an open file descriptor #6 from its parent process, it uses +# that as an additional login port. the 'port #' for internal purposes (debug +# messages, argument to connect, etc.) and kind should be set here. acceptable +# port types are: ascii, binary, mud or telnet. this replaces the FD6_KIND and +# FD6_PORT compile-time defines. +#fd6 kind : telnet +#fd6 port : 23 + +# the address server is an external program that lets the mud translate +# internet names to numbers (and vice versa). select an unused port. +address server ip : localhost +address server port : 9997 + +# absolute pathname of mudlib +mudlib directory : /home/mmessier/mudos/mudos/beta/testsuite + +# absolute pathname of driver/config dir +binary directory : /home/mmessier/mudos/mudos/beta/testsuite + +# debug.log and author/domain stats are stored here +log directory : /log + +# the directories which are searched by #include <...> +# for multiple dirs, separate each path with a ':' +include directories : /include + +# Directory to save binaries in. (if BINARIES is defined) +save binaries directory : /binaries + +# the file which defines the master object +master file : /single/master + +# the file where all global simulated efuns are defined. +simulated efun file : /single/simul_efun + +# file to swap out objects; not used if time to swap is 0 +swap file : /single/swapfile + +# alternate debug.log file name (assumed to be in specified 'log directory') +debug log file : debug.log + +# This is an include file which is automatically #include'd in all objects +global include file : "/include/globals.h" + +# if an object is left alone for a certain time, then the +# function clean_up will be called. This function can do anything, +# like destructing the object. If the function isn't defined by the +# object, then nothing will happen. +# This time should be substantially longer than the swapping time. +time to clean up : 1200 + +# How long time until an unused object is swapped out. +# Machine with too many players and too little memory: 900 (15 minutes) +# Machine with few players and lot of memory: 10000 +# Machine with infinite memory: 0 (never swap). +time to swap : 600 + +# How many seconds until an object is reset again. +time to reset : 1800 + +# Maximum number of bits in a bit field. They are stored in printable +# strings, 6 bits per byte. +maximum bits in a bitfield : 1200 + +# Max number of local variables in a function. +maximum local variables : 30 + +# Maximum amount of "eval cost" per thread - execution is halted when +# it is exceeded. +maximum evaluation cost : 500000 + +# This is the maximum array size allowed for one single array. +maximum array size : 15000 + +# This is the maximum allowed size of a variable of type 'buffer'. +maximum buffer size : 400000 + +# Max size for a mapping +maximum mapping size : 15000 + +# Max inherit chain size +inherit chain size : 30 + +# maximum length of a string variable +maximum string length : 200000 + +# Max size of a file allowed to be read by 'read_file()'. +maximum read file size : 200000 + +# max number of bytes you allow to be read and written with read_bytes +# and write_bytes +maximum byte transfer : 200000 + +# Reserve an extra memory area from malloc(), to free when we run out +# of memory and allow the mudlib to shutdown. +# If this value is 0, no area will be reserved. +reserved size : 0 + +# Define the size of the shared string hash table. This number should +# a prime, probably between 1000 and 30000; if you set it to about 1/5 +# of the number of distinct strings you have, you will get a hit ratio +# (number of comparisons to find a string) very close to 1, as found strings +# are automatically moved to the head of a hash chain. You will never +# need more, and you will still get good results with a smaller table. +hash table size : 7001 + +# Object hash table size. +# Define this like you did with the strings; probably set to about 1/4 of +# the number of objects in a game, as the distribution of accesses to +# objects is somewhat more uniform than that of strings. +object table size : 1501 + +# default no-matching-action message +default fail message : What? + +# default message when error() occurs (optional) +default error message : + +# the external ports we support +external_port_1 : telnet 4000 +external_port_2 : binary 4001 + +############################################################################### +# The following aren't currently used or implemented (yet) # +############################################################################### + +# maximum number of users in the game (unused currently) +maximum users : 40 + +# Define the maximum stack size of the stack machine. This stack will also +# contain all local variables and arguments. (unused currently) +evaluator stack size : 1000 + +# Define the size of the compiler stack. This defines how complex +# expressions the compiler can parse. (unused currently) +compiler stack size : 200 + +# Define the maximum call depth for functions. (unused currently) +maximum call depth : 30 + +# There is a hash table for living objects, used by find_living(). +# (unused currently) +living hash table size : 100 diff --git a/fluffos-2.23-ds03/Copyright b/fluffos-2.23-ds03/Copyright new file mode 100644 index 0000000..d2b4c26 --- /dev/null +++ b/fluffos-2.23-ds03/Copyright @@ -0,0 +1,19 @@ +This game, LPmud, is copyright by Lars Pensj|, 1990, 1991. + +Source code herein refers to the source code, and any executables +created from the same source code. + +All rights reserved. Permission is granted to extend and modify the +source code provided subject to the restriction that the source code may +not be used in any way whatsoever for monetary gain. + +****** + +The name MudOS is copyright 1991-1992 by Erik Kay, Adam Beeman, Stephan Iannce +and John Garnett. LPmud copyright restrictions still apply. + +In addition, the entire package is copyright 1995 by Tim Hollebeek. + +****** +FluffOS is a range of patches to MudOS distributed as the patched source tree for convenience. +LPmud and MudOS copyright restrictions still apply. \ No newline at end of file diff --git a/fluffos-2.23-ds03/Credits.LPmud b/fluffos-2.23-ds03/Credits.LPmud new file mode 100644 index 0000000..e7aca12 --- /dev/null +++ b/fluffos-2.23-ds03/Credits.LPmud @@ -0,0 +1,31 @@ +The program was written originally by + +Lars Pensj|, April 1989 (lars@cd.chalmers.se). + +Other credits: + +The regexp package was made by Henry Spencer. + +The ed package was not done by me. See the file ed.c for information. + +Bit manipulations was implemented by pell@lysator.liu.se who also found +several bugs that had eluded me for months. + +Valuable help and hints from: Mark Nagel, James Seidman, Moonchilde and more. + +Roland Dunkerley III fixed for-loops, do-while and the operators ++ and --. + +Sean T Barrett made smalloc.c. + +Lennart Augustsson convinced me to implement a compiler for a virtual +stack machine. He also implemented the built-in preprocessor. + +John S. Price found and fixed many bugs. + +The shadow idea was "forwarded" to me by John S. Price from Team Cthulhu +(Bill Burdick, Roy Riggs, Mitch Adler). + +Michael Malone, Michael O'Reilly, Klaus Rennecke, J|rn Rennecke and +Germano Caronni found and fixed a large amount of bugs. + +Petri Wessman fixed changes for SCO unix and AIX. diff --git a/fluffos-2.23-ds03/Credits.MudOS b/fluffos-2.23-ds03/Credits.MudOS new file mode 100644 index 0000000..d420976 --- /dev/null +++ b/fluffos-2.23-ds03/Credits.MudOS @@ -0,0 +1,99 @@ +Read the Credits.LPmud file for credit information on the original LPmud +driver (that upon which MudOS is based). LPmud was originally written +by Lars Pensj|, April 1989. + +The following information is not guaranteed to be complete. (I +apologize in advance if I have forgotten anyone). For more information +read the './doc/driver/done-mudos' and './src/ChangeLog' files. + +We would like to thank the following muds for extensive testing and numerous +bug reports: + +TMI, Portals, Overdrive, Genocide, TMI-2, Vincent's Hollow, DreamShadow, +Nightmare, Nanvaent, and many others. + +The MudOS driver was a team effort with specific contributions from the +following people: + +Erik Kay (Wayfarer) - runtime config system, message() efun, and others. + +John Garnett (Truilkan) - improved mappings implementation, process_input + and write_prompt callbacks, C++ style comments, lazy resets, + master::valid_override callback, improved shared string management, and + others. + +Dwayne Fontenot (Jacques) - major rewrite of comm.c, TCP socket efuns, + ported to AIX 3.2. + +Dave Richards (Cynosure/Cygnus) - UDP socket efuns, enhanced TCP socket efuns, + ported MudOS to the Sequent Symmetry (System V Release 3), + and the time_expression() efun. + +Stephen Iannce (Huthar) - children() and message() efuns, extensive testing of + the socket efunctions. + +Joel York (Shadowhawk) - multiple arguments version of input_to(), dprint + option to ed. + +Bob Farmer (Blackthorn) - fixed various efuns to honor the hidden object + flags, several new efuns, porting to DEC Alpha and others, bug fixes, + and others. + +James Waldrop (Sulam) - helped with reorganizing the huge switch in + interpret.c into efunctions.c. + +Michael Bundy - provided patches allowing MudOS to run on System V Release 4. + (built on Dave Richard's System V Release 3 port). + +Luke Mewborn (Zak) - provided patches allowing MudOS to run on 386BSD + +Olav Kolbu (Aragorn) - provided patches allowing MudOS to run on Linux 0.99.3, + many bug reports and misc fixes, countless compilation errors + +Darin Johnson (Darin) - provided various patches and optimizations (including + combining prelang.y and postlang.y into compiler.y). + +David Bennett (Pinkfish) - provided enhancements for parse_command and for the + telnet negotiation code in comm.c (as well as various other small bug + fixes), and the resolve() efun. + +John Fehr (Wildcard) - provided patches allowing MudOS to run on Amiga + +Anthon Pang (Robocoder) - provided various patches, optimize function + table search, amiga support + +Tim Hollebeek (Beek) - LPC->C and patches, compiler rewrite, new function + pointers, etc + +Ti-Ming Chiang (Symmetry, Cloud) - Countless optimizations; array, mapping and + save_object rewrites + +Svata Dedic (Belgarat) - Win32 fixes, parser fixes, misc fixes + +Martin Tyler (Burty) - lex.c fixes, other misc fixes + +Troels Therkelsen (Qualin) - numerous bug reports and ideas + +Maarten de Jong - amiga compilation via gcc + +George Reese (Descartes) - bug reports, original Win32 port, mSQL support + +Mark ? (Mystic) - tons of ideas; fixes for exotic options settings + +Skeeter Hartwig (Jihad) - numerous bug reports + +David Rudy (Aule) - optimizations; high usage testing and stability patches + +Greg Stein (Deathblade) - various fixes and bug reports + +Ben Gras (Fermat) - MD5 crypt(), various fixes + +Kars de Jong (Turrican) - various bug fixes + +Simon Matthews (Andrew) - MySQL support, various patches and bug reports + +and tons of others who have accidentally been omitted +-- +Thanks to Adam Beeman (Buddha) for making numerous suggestions on +improving the MudOS driver and for providing the TMI site as the original +MudOS development site. diff --git a/fluffos-2.23-ds03/Dependencies b/fluffos-2.23-ds03/Dependencies new file mode 100644 index 0000000..e69de29 diff --git a/fluffos-2.23-ds03/Exit_Codes b/fluffos-2.23-ds03/Exit_Codes new file mode 100644 index 0000000..3321218 --- /dev/null +++ b/fluffos-2.23-ds03/Exit_Codes @@ -0,0 +1,59 @@ +addr_server: + 1 - error creating the socket or first arg was not a port # + 2 - setsockopt() failed or port # was not a number + 3 - error binding the socket (socket in use?) + 4 - getsockname() failed + 5 - couldn't create SIGPIPE handler + 8 - set_socket_nonblocking() failed + 10 - listen() failed + +make_func: + 1 - general fatal error + -1 - error opening a file + -2 - error opening OPC_PROF + -3 - error opening OPCODES + +driver exit codes: + Note: the mudlib can send a shutdown code as an argument to shutdown. + Check your mudlib for documentation. + -3 - a crash occured while trying to exit via master::crash() + -2 - driver successfully shutdown via master::crash() + -1 - (a) The config file 'include dirs' setting was malformed + (b) bad definition of EXTRACT_UCHAR or memmove() + (c) no config file + (d) Illegal flag syntax + (e) Bad mudlib directory + (f) Master object failed to load + (g) Simul efun object failed to load + (one existed, but had errors) + (h) SIGUSR1 was recieved + (i) error in comfing file + 0 - normal shutdown + 1 - error creating user connection socket + or obscure fatal error in set_inc_list + or master called shutdown() from create() + or memset() failed + 2 - setsockopt() failed + or driver out of memory and no reserve exists + 3 - bind() failed + or driver ran out of memory again after freeing reserve + 4 - getsockname() failed + 5 - error setting up SIGPIPE handler + 8 - error in set_socket_nonblocking() + + 129 - uncaught SIGHUP + 130 - uncaught SIGINT (control-C) + 131 - uncaught SIGQUIT (control-\) + 132 - uncaught SIGILL (illegal instruction) + 133 - uncaught SIGTRAP (trace trap) + 134 - uncaught SIGABRT (MudOS abort due to failed assertion) + 135 - uncaught SIGEMT + 136 - uncaught SIGFPE (arithmetic exception) + 137 - uncaught SIGKILL + 138 - uncaught SIGBUS (bus error) + 139 - uncaught SIGSEGV (seg fault) + 140 - uncaught SIGSYS (bad system call) + 143 - uncaught SIGTERM + 144 - uncaught SIGUSR1 + 145 - uncaught SIGUSR2 + diff --git a/fluffos-2.23-ds03/GNUmakefile b/fluffos-2.23-ds03/GNUmakefile new file mode 100644 index 0000000..35397ab --- /dev/null +++ b/fluffos-2.23-ds03/GNUmakefile @@ -0,0 +1,257 @@ +# YOU DO NOT NEED TO CONFIGURE ANYTHING IN THIS FILE. +# +# RUN THE SHELL SCRIPT ./build.MudOS to generate the Makefiles, and follow +# its instructions. +# +############################################################################ +# +# **** TARGETS AND THEIR CORRECT USAGE **** +# +# COMPILATION TARGETS: +# +# all: compile all the files +# +# install: make all, then move the files to the correct directories +# +# remake: remove the object files and generated files, and recompile +# NO reconfiguration is done, etc. +# +# depend: automatically create dependency info +# +# +# 'CLEAN' TARGETS: +# +# neat: remove object files and generated files (used by remake) +# +# clean: in addition to neat, also remove .orig and .rej files, +# cores, lint files, emacs backups, tag files, yacc debug +# files, generated Makefiles, generated binaries, and +# generated dependency info +# +# spotless: make clean, then remove ALL CONFIGURATION AND CUSTOMIZATION +# useful for creating distributions +# +# ---- REALLY COMPLEX OPTIONS YOU PROBABLY DON'T WANT TO TOUCH ----- +# +# NeXT: link with MallocDebug if you have a NeXT with NeXTOS 2.1 or later and +# you wish to search for memory leaks (see /NextDeveloper/Apps/MallocDebug). +# Note: linking with MallocDebug will cause the virtual size of the +# driver process to reach appoximately 40MB however the amount of real memory +# used will remain close to normal. +#EXTRALIBS=-lMallocDebug -lsys_s +# +# ---- DO NOT EDIT ANYTHING BELOW HERE UNLESS YOU KNOW ALOT ABOUT HOW +# MUDOS WORKS INTERNALLY ---- + +OVERRIDES=$(MAKEOVERRIDES) + +# ************************************************************************** +# **** NOTE: If you add something here, also add it to the OBJ= rule below, +# **** or non-GNU makes will die +# ************************************************************************** +SRC=grammar.tab.c lex.c main.c rc.c interpret.c simulate.c file.c object.c \ + backend.c array.c mapping.c comm.c ed.c regexp.c buffer.c crc32.c \ + malloc.c mallocwrapper.c class.c efuns_main.c efuns_port.c \ + call_out.c otable.c dumpstat.c stralloc.c hash.c \ + port.c reclaim.c parse.c simul_efun.c sprintf.c program.c \ + compiler.c avltree.c icode.c trees.c generate.c scratchpad.c \ + socket_efuns.c socket_ctrl.c qsort.c eoperators.c socket_err.c md.c \ + disassembler.c uvalarm.c $(STRFUNCS) \ + replace_program.c master.c function.c \ + debug.c crypt.c applies_table.c add_action.c eval.c fliconv.c console.c + +all: $(OBJDIR) cc.h main_build +main_build2: $(DRIVER_BIN) addr_server portbind + +main_build: files + $(MAKE) main_build2 + +VPATH = $(OBJDIR) + +OBJ=$(addprefix $(OBJDIR)/,$(subst .c,.o,$(SRC))) + +$(OBJDIR)/%.o: %.c + $(CC) $(CFLAGS) $(OPTIMIZE) -o $@ -c $< + +$(OBJDIR)/lex.o: lex.c preprocess.c cc.h grammar.tab.c + +$(OBJDIR)/grammar.tab.o: grammar.tab.c opcodes.h + +$(OBJDIR): + mkdir -p $(OBJDIR) + +which_makefile: + echo MakeIsGNU + +grammar.tab.c: grammar.y + $(YACC) grammar.y + -rm -f grammar.tab.* + sed "s/y.tab.c/grammar.tab.c/g" y.tab.c > grammar.tab.c + -mv y.tab.h grammar.tab.h + +packages/packages.a: packages/*.c + $(MAKE) -C packages 'CC=$(CC)' 'CFLAGS=$(CFLAGS) $(OPTIMIZE)' 'OBJDIR=../$(OBJDIR)' 'RANLIB=$(RANLIB)' 'A=$(A)' 'O=$(O)' + +$(DRIVER_BIN): packages/packages.a $(OBJ) dtrace_compile + -mv -f $(DRIVER_BIN) $(DRIVER_BIN).old + $(PROOF) $(CC) $(CFLAGS) $(OPTIMIZE) $(OBJ) `./dtrace_compile` -o $(DRIVER_BIN) packages/packages.a $(EXTRALIBS) `cat system_libs` + +dtrace_compile: dtrace_compile.c local_options + $(CC) dtrace_compile.c -o dtrace_compile + +addr_server: files $(OBJDIR)/addr_server.o $(OBJDIR)/socket_ctrl.o $(OBJDIR)/port.o addr_server.h + $(CC) $(CFLAGS) $(OPTIMIZE) $(OBJDIR)/socket_ctrl.o $(OBJDIR)/addr_server.o $(OBJDIR)/port.o \ + -o addr_server `cat system_libs` + +portbind: $(OBJDIR)/portbind.o + $(CC) $(CFLAGS) $(OPTIMIZE) $(OBJDIR)/portbind.o -o portbind `cat system_libs` + + +remake: neat all + +customize: + -cp ../local_options . + -cp ../system_libs . + -cp ../configure.h . + +depend: opcodes.h grammar.tab.c cc.h efunctions.h efun_defs.c configure.h + -rm tmpdepend + for i in *.c; do $(CC) -MM -DDEPEND $$i >>tmpdepend; done + sed -e "s!^[^ ]!$(OBJDIR)/&!" Dependencies + -rm tmpdepend + +cc.h: GNUmakefile + rm -f cc.h + echo "/* this file automatically generated by the Makefile */" > cc.h + echo '#define COMPILER "$(CC)"' >> cc.h + echo '#define OPTIMIZE "$(OPTIMIZE)"' >> cc.h + echo '#define CFLAGS "$(CFLAGS) $(OPTIMIZE)"' >> cc.h + echo '#define OBJDIR "$(OBJDIR)"' >> cc.h + +# the touches here are necessary to fix the modification times; link(2) does +# 'modify' a file +files: edit_source sysmalloc.c debugmalloc.c wrappedmalloc.c options.h op_spec.c func_spec.c packages/Makefile.pre packages/GNUmakefile.pre configure.h grammar.y.pre + ./edit_source -options -malloc -build_func_spec '$(CPP) $(CFLAGS)' \ + -process grammar.y.pre + ./edit_source -process packages/Makefile.pre + ./edit_source -process packages/GNUmakefile.pre + ./edit_source -build_efuns -build_applies + touch mallocwrapper.c + touch malloc.c + touch files + +make_func.tab.c: make_func.y cc.h + $(YACC) $(YFLAGS) make_func.y + -rm -f make_func.tab.c + mv y.tab.c make_func.tab.c + +configure.h: edit_source build.FluffOS + -if test \( ! -r configure.h \) -o \( ! -r configuration \); then \ + rm -f configuration; \ + touch configuration; \ + fi + if test "Machine `uname -a` Configure version 5" = "`cat configuration`"; then \ + echo "Skipping configuration ..."; \ + else \ + ./edit_source -configure; \ + echo "Machine `uname -a` Configure version 5" > configuration; \ + fi + +$(OBJDIR)/edit_source.o: edit_source.c preprocess.c cc.h + +edit_source: $(OBJDIR)/edit_source.o $(OBJDIR)/hash.o $(OBJDIR)/make_func.tab.o + $(CC) $(CFLAGS) $(OBJDIR)/edit_source.o $(OBJDIR)/hash.o $(OBJDIR)/make_func.tab.o -o edit_source + +# don't optimize these two +$(OBJDIR)/edit_source.o: edit_source.c + $(CC) $(CFLAGS) -o $@ -c $< + +$(OBJDIR)/make_func.tab.o: make_func.tab.c + $(CC) $(CFLAGS) -o $@ -c $< + +tags: $(SRC) + ctags $(SRC) + +TAGS: $(SRC) + etags $(SRC) + +install: all + -mkdir $(INSTALL_DIR) + $(INSTALL) $(DRIVER_BIN) $(INSTALL_DIR) + $(INSTALL) addr_server $(INSTALL_DIR) + $(INSTALL) portbind $(INSTALL_DIR) + +Makefiles: Makefile.in NMakefile.in + +Makefile.in: edit_source Makefile.in.pre Makefile.master + ./edit_source -process Makefile.in.pre + +NMakefile.in: edit_source NMakefile.in.pre Makefile.master + ./edit_source -process NMakefile.in.pre + +nothing: + +# remove local configuration +spotless: clean + -rm -f configure.h local_options system_libs configuration + -rm -f options_incl.h + -rm -f *.diffs + -find . -name "*~" -print | xargs rm + -rm -f 1.out 2.out + +# get ready for recompile +neat: + -(cd packages; $(MAKE) "A=$(A)" "O=$(O)" clean) + -rm -rf $(OBJDIR) *.$(O) *.tab.c *.tab.h + -rm -f efun_defs.c option_defs.c + -rm -f opcodes.h efunctions.h opc.h efun_protos.h + -rm -f malloc.c mallocwrapper.c + -rm -f func_spec.cpp applies.h applies_table.c files + -rm -f grammar.y comptest* a.out *.exe + -rm -f packages/Makefile packages/GNUmakefile packages/packages + +# remove everything except configuration +clean: neat + -rm -f Makefile.MudOS GNUmakefile.MudOS + -rm -f cc.h edit_source + -rm -f core y.output testsuite/core testsuite/tmp/* + -rm -f testsuite/OPCPROF.* testsuite/opc.* + -rm -rf testsuite/binaries testsuite/single/swapfile.* + -rm -f testsuite/OBJ_DUMP* testsuite/test_file testsuite/testfile + -rm -f testsuite/tmp_eval_file.c testsuite/sf.o testsuite/ed_test + -rm -f testsuite/log/log testsuite/log/debug.log testsuite/log/compile + -find . -name "*~" -print | xargs rm + -find . -name "*.orig" -print | xargs rm + -find . -name "*.rej" -print | xargs rm + -rm -f *.ln tags TAGS + -rm -f $(DRIVER_BIN) $(DRIVER_BIN).old addr_server portbind *.exe + -rm -f Dependencies tmpdepend + -touch Dependencies + +# remove everything +distclean: neat + -rm -f Makefile.MudOS GNUmakefile.MudOS + -rm -f cc.h edit_source + -rm -f core y.output testsuite/core testsuite/tmp/* + -rm -f testsuite/OPCPROF.* testsuite/opc.* + -rm -rf testsuite/binaries testsuite/single/swapfile.* + -rm -f testsuite/OBJ_DUMP* testsuite/test_file testsuite/testfile + -rm -f testsuite/tmp_eval_file.c testsuite/sf.o testsuite/ed_test + -rm -f testsuite/log/log testsuite/log/debug.log testsuite/log/compile + -find . -name "*~" -print | xargs rm + -find . -name "*.orig" -print | xargs rm + -find . -name "*.rej" -print | xargs rm + -rm -f *.ln tags TAGS + -rm -f $(DRIVER_BIN) $(DRIVER_BIN).old addr_server portbind + -rm -f *.exe + -rm -f configure.h system_libs options_incl.h insttest configuration + -rm -f 1.out 2.out + -rm -f local_options + -rm -f dtrace_compile + -rm -f trash_me.bat trash_me.err + -cp -f GNUmakefile.in GNUmakefile + -rm -f Dependencies tmpdepend + -rm -f semantic* packages/semantic* + -touch Dependencies + +include Dependencies diff --git a/fluffos-2.23-ds03/GNUmakefile.debug b/fluffos-2.23-ds03/GNUmakefile.debug new file mode 100644 index 0000000..4cf55da --- /dev/null +++ b/fluffos-2.23-ds03/GNUmakefile.debug @@ -0,0 +1,256 @@ +MAKE=gmake +SHELL=/bin/sh +OBJDIR=obj +DRIVER_BIN=driver +PROOF= +STRFUNCS= +INSTALL=install -c +INSTALL_DIR=../bin +OPTIMIZE=-Wall -Wundef -DPEDANTIC -Wmissing-declarations +CPP=gcc -E +CFLAGS=-D__USE_FIXED_PROTOTYPES__ -DHAVE_ZLIB -g -DDEBUG -DDEBUG_MACRO -rdynamic +CC=gcc +YACC=bison -d -y +RANLIB=ranlib +A=a +O=o + +# YOU DO NOT NEED TO CONFIGURE ANYTHING IN THIS FILE. +# +# RUN THE SHELL SCRIPT ./build.MudOS to generate the Makefiles, and follow +# its instructions. +# +############################################################################ +# +# **** TARGETS AND THEIR CORRECT USAGE **** +# +# COMPILATION TARGETS: +# +# all: compile all the files +# +# install: make all, then move the files to the correct directories +# +# remake: remove the object files and generated files, and recompile +# NO reconfiguration is done, etc. +# +# depend: automatically create dependency info +# +# Makefiles: update Makefile.in and GNUmakefile.in from Makefile.master +# (only necessary after making changes to Makefile.master) +# +# 'CLEAN' TARGETS: +# +# neat: remove object files and generated files (used by remake) +# +# clean: in addition to neat, also remove .orig and .rej files, +# cores, lint files, emacs backups, tag files, yacc debug +# files, generated Makefiles, generated binaries, and +# generated dependency info +# +# spotless: make clean, then remove ALL CONFIGURATION AND CUSTOMIZATION +# useful for creating distributions +# +# ---- REALLY COMPLEX OPTIONS YOU PROBABLY DON'T WANT TO TOUCH ----- +# +# NeXT: link with MallocDebug if you have a NeXT with NeXTOS 2.1 or later and +# you wish to search for memory leaks (see /NextDeveloper/Apps/MallocDebug). +# Note: linking with MallocDebug will cause the virtual size of the +# driver process to reach appoximately 40MB however the amount of real memory +# used will remain close to normal. +#EXTRALIBS=-lMallocDebug -lsys_s +# +# ---- DO NOT EDIT ANYTHING BELOW HERE UNLESS YOU KNOW ALOT ABOUT HOW +# MUDOS WORKS INTERNALLY ---- + +OVERRIDES=$(MAKEOVERRIDES) + +# ************************************************************************** +# **** NOTE: If you add something here, also add it to the OBJ= rule below, +# **** or non-GNU makes will die +# ************************************************************************** +SRC=grammar.tab.c lex.c main.c rc.c interpret.c simulate.c file.c object.c \ + backend.c array.c mapping.c comm.c ed.c regexp.c swap.c buffer.c crc32.c \ + malloc.c mallocwrapper.c class.c efuns_main.c efuns_port.c \ + call_out.c otable.c dumpstat.c stralloc.c hash.c \ + port.c reclaim.c parse.c simul_efun.c sprintf.c program.c \ + compiler.c avltree.c icode.c trees.c generate.c scratchpad.c \ + socket_efuns.c socket_ctrl.c qsort.c eoperators.c socket_err.c md.c \ + disassembler.c binaries.c ualarm.c $(STRFUNCS) \ + replace_program.c ccode.c cfuns.c compile_file.c master.c function.c \ + debug.c crypt.c applies_table.c add_action.c + +all: $(OBJDIR) cc.h files main_build + +main_build: $(DRIVER_BIN) addr_server portbind + +parallel: + $(MAKE) -k -l -j 6 cc.h files + $(MAKE) -k -l -j 6 main_build + +VPATH = $(OBJDIR) + +OBJ=$(addprefix $(OBJDIR)/,$(subst .c,.o,$(SRC))) + +$(OBJDIR)/%.o: %.c + $(CC) $(CFLAGS) $(OPTIMIZE) -o $@ -c $< + +$(OBJDIR)/lex.o: lex.c preprocess.c cc.h grammar.tab.c + +$(OBJDIR)/grammar.tab.o: grammar.tab.c opcodes.h + +$(OBJDIR): + mkdir -p $(OBJDIR) + +which_makefile: + echo MakeIsGNU + +grammar.tab.c: grammar.y + $(YACC) grammar.y + -rm -f grammar.tab.* + sed "s/y.tab.c/grammar.tab.c/g" y.tab.c > grammar.tab.c + -mv y.tab.h grammar.tab.h + +packages/packages.a: packages/parser.c packages/contrib.c + $(MAKE) -C packages 'CC=$(CC)' 'CFLAGS=$(CFLAGS) $(OPTIMIZE)' 'OBJDIR=../$(OBJDIR)' 'RANLIB=$(RANLIB)' 'A=$(A)' 'O=$(O)' + +mudlib/mudlib.a: + $(MAKE) -C mudlib 'CC=$(CC)' 'CFLAGS=$(CFLAGS) $(OPTIMIZE)' 'OBJDIR=../$(OBJDIR)' 'RANLIB=$(RANLIB)' 'A=$(A)' 'O=$(O)' +$(DRIVER_BIN): packages/packages.a mudlib/mudlib.a $(OBJ) + -mv -f $(DRIVER_BIN) $(DRIVER_BIN).old + $(PROOF) $(CC) $(CFLAGS) $(OPTIMIZE) $(OBJ) -o $(DRIVER_BIN) packages/packages.a mudlib/mudlib.a $(EXTRALIBS) `cat system_libs` + +addr_server: files $(OBJDIR)/addr_server.o $(OBJDIR)/socket_ctrl.o $(OBJDIR)/port.o addr_server.h + $(CC) $(CFLAGS) $(OPTIMIZE) $(OBJDIR)/socket_ctrl.o $(OBJDIR)/addr_server.o $(OBJDIR)/port.o \ + -o addr_server `cat system_libs` + +portbind: $(OBJDIR)/portbind.o + $(CC) $(CFLAGS) $(OPTIMIZE) $(OBJDIR)/portbind.o -o portbind `cat system_libs` + + +remake: neat all + +customize: + -cp ../local_options . + -cp ../system_libs . + -cp ../configure.h . + +depend: opcodes.h grammar.tab.c cc.h efunctions.h efun_defs.c configure.h + -rm tmpdepend + for i in *.c; do $(CC) -MM -DDEPEND $$i >>tmpdepend; done + sed -e "s!^[^ ]!$(OBJDIR)/&!" Dependencies + -rm tmpdepend + +cc.h: GNUmakefile + rm -f cc.h + echo "/* this file automatically generated by the Makefile */" > cc.h + echo '#define COMPILER "$(CC)"' >> cc.h + echo '#define OPTIMIZE "$(OPTIMIZE)"' >> cc.h + echo '#define CFLAGS "$(CFLAGS) $(OPTIMIZE)"' >> cc.h + echo '#define OBJDIR "$(OBJDIR)"' >> cc.h + +# the touches here are necessary to fix the modification times; link(2) does +# 'modify' a file +files: edit_source sysmalloc.c smalloc.c bsdmalloc.c debugmalloc.c wrappedmalloc.c options.h op_spec.c func_spec.c mudlib/Makefile.pre mudlib/GNUmakefile.pre packages/Makefile.pre packages/GNUmakefile.pre configure.h grammar.y.pre + ./edit_source -options -malloc -build_func_spec '$(CPP) $(CFLAGS)' \ + -process grammar.y.pre + ./edit_source -process packages/Makefile.pre + ./edit_source -process packages/GNUmakefile.pre + ./edit_source -process mudlib/Makefile.pre + ./edit_source -process mudlib/GNUmakefile.pre + ./edit_source -build_efuns -build_applies + touch mallocwrapper.c + touch malloc.c + touch files + +make_func.tab.c: make_func.y cc.h + $(YACC) $(YFLAGS) make_func.y + -rm -f make_func.tab.c + mv y.tab.c make_func.tab.c + +configure.h: edit_source build.MudOS + -if test \( ! -r configure.h \) -o \( ! -r configuration \); then \ + rm -f configuration; \ + touch configuration; \ + fi + if test "Machine `uname -a` Configure version 5" = "`cat configuration`"; then \ + echo "Skipping configuration ..."; \ + else \ + ./edit_source -configure; \ + echo "Machine `uname -a` Configure version 5" > configuration; \ + fi + +$(OBJDIR)/edit_source.o: edit_source.c preprocess.c cc.h + +edit_source: $(OBJDIR)/edit_source.o $(OBJDIR)/hash.o $(OBJDIR)/make_func.tab.o + $(CC) $(CFLAGS) $(OBJDIR)/edit_source.o $(OBJDIR)/hash.o $(OBJDIR)/make_func.tab.o -o edit_source + +# don't optimize these two +$(OBJDIR)/edit_source.o: edit_source.c + $(CC) $(CFLAGS) -o $@ -c $< + +$(OBJDIR)/make_func.tab.o: make_func.tab.c + $(CC) $(CFLAGS) -o $@ -c $< + +tags: $(SRC) + ctags $(SRC) + +TAGS: $(SRC) + etags $(SRC) + +install: all + -mkdir $(INSTALL_DIR) + $(INSTALL) $(DRIVER_BIN) $(INSTALL_DIR) + $(INSTALL) addr_server $(INSTALL_DIR) + $(INSTALL) portbind $(INSTALL_DIR) + +Makefiles: Makefile.in GNUmakefile.in NMakefile.in + +Makefile.in: edit_source Makefile.in.pre Makefile.master + ./edit_source -process Makefile.in.pre + +GNUmakefile.in: edit_source GNUmakefile.in.pre Makefile.master + ./edit_source -process GNUmakefile.in.pre + +NMakefile.in: edit_source NMakefile.in.pre Makefile.master + ./edit_source -process NMakefile.in.pre + +nothing: + +# remove local configuration +spotless: clean + -rm -f configure.h local_options system_libs configuration + -rm -f options_incl.h + -rm -f *.diffs + -find . -name "*~" -print | xargs rm + +# get ready for recompile +neat: + -(cd packages; $(MAKE) "A=$(A)" "O=$(O)" clean) + -(cd mudlib; $(MAKE) "A=$(A)" "O=$(O)" clean) + -rm -rf $(OBJDIR) *.$(O) *.tab.c *.tab.h + -rm -f efun_defs.c option_defs.c + -rm -f opcodes.h efunctions.h opc.h efun_protos.h + -rm -f malloc.c mallocwrapper.c + -rm -f func_spec.cpp applies.h applies_table.c files + -rm -f grammar.y comptest* a.out + -rm -f packages/Makefile packages/GNUmakefile packages/packages + +# remove everything except configuration +clean: neat + -rm -f Makefile.MudOS GNUmakefile.MudOS + -rm -f cc.h edit_source + -rm -f core y.output testsuite/core testsuite/tmp/* + -rm -f testsuite/OPCPROF.* testsuite/opc.* + -rm -rf testsuite/binaries testsuite/single/swapfile.* + -rm -f testsuite/OBJ_DUMP* testsuite/test_file testsuite/testfile + -rm -f testsuite/tmp_eval_file.c testsuite/sf.o testsuite/ed_test + -rm -f testsuite/log/log testsuite/log/debug.log testsuite/log/compile + -find . -name "*~" -print | xargs rm + -find . -name "*.orig" -print | xargs rm + -find . -name "*.rej" -print | xargs rm + -rm -f *.ln tags TAGS + -rm -f $(DRIVER_BIN) $(DRIVER_BIN).old addr_server portbind + -rm -f Dependencies tmpdepend + -touch Dependencies + +include Dependencies diff --git a/fluffos-2.23-ds03/GNUmakefile.in b/fluffos-2.23-ds03/GNUmakefile.in new file mode 100644 index 0000000..35397ab --- /dev/null +++ b/fluffos-2.23-ds03/GNUmakefile.in @@ -0,0 +1,257 @@ +# YOU DO NOT NEED TO CONFIGURE ANYTHING IN THIS FILE. +# +# RUN THE SHELL SCRIPT ./build.MudOS to generate the Makefiles, and follow +# its instructions. +# +############################################################################ +# +# **** TARGETS AND THEIR CORRECT USAGE **** +# +# COMPILATION TARGETS: +# +# all: compile all the files +# +# install: make all, then move the files to the correct directories +# +# remake: remove the object files and generated files, and recompile +# NO reconfiguration is done, etc. +# +# depend: automatically create dependency info +# +# +# 'CLEAN' TARGETS: +# +# neat: remove object files and generated files (used by remake) +# +# clean: in addition to neat, also remove .orig and .rej files, +# cores, lint files, emacs backups, tag files, yacc debug +# files, generated Makefiles, generated binaries, and +# generated dependency info +# +# spotless: make clean, then remove ALL CONFIGURATION AND CUSTOMIZATION +# useful for creating distributions +# +# ---- REALLY COMPLEX OPTIONS YOU PROBABLY DON'T WANT TO TOUCH ----- +# +# NeXT: link with MallocDebug if you have a NeXT with NeXTOS 2.1 or later and +# you wish to search for memory leaks (see /NextDeveloper/Apps/MallocDebug). +# Note: linking with MallocDebug will cause the virtual size of the +# driver process to reach appoximately 40MB however the amount of real memory +# used will remain close to normal. +#EXTRALIBS=-lMallocDebug -lsys_s +# +# ---- DO NOT EDIT ANYTHING BELOW HERE UNLESS YOU KNOW ALOT ABOUT HOW +# MUDOS WORKS INTERNALLY ---- + +OVERRIDES=$(MAKEOVERRIDES) + +# ************************************************************************** +# **** NOTE: If you add something here, also add it to the OBJ= rule below, +# **** or non-GNU makes will die +# ************************************************************************** +SRC=grammar.tab.c lex.c main.c rc.c interpret.c simulate.c file.c object.c \ + backend.c array.c mapping.c comm.c ed.c regexp.c buffer.c crc32.c \ + malloc.c mallocwrapper.c class.c efuns_main.c efuns_port.c \ + call_out.c otable.c dumpstat.c stralloc.c hash.c \ + port.c reclaim.c parse.c simul_efun.c sprintf.c program.c \ + compiler.c avltree.c icode.c trees.c generate.c scratchpad.c \ + socket_efuns.c socket_ctrl.c qsort.c eoperators.c socket_err.c md.c \ + disassembler.c uvalarm.c $(STRFUNCS) \ + replace_program.c master.c function.c \ + debug.c crypt.c applies_table.c add_action.c eval.c fliconv.c console.c + +all: $(OBJDIR) cc.h main_build +main_build2: $(DRIVER_BIN) addr_server portbind + +main_build: files + $(MAKE) main_build2 + +VPATH = $(OBJDIR) + +OBJ=$(addprefix $(OBJDIR)/,$(subst .c,.o,$(SRC))) + +$(OBJDIR)/%.o: %.c + $(CC) $(CFLAGS) $(OPTIMIZE) -o $@ -c $< + +$(OBJDIR)/lex.o: lex.c preprocess.c cc.h grammar.tab.c + +$(OBJDIR)/grammar.tab.o: grammar.tab.c opcodes.h + +$(OBJDIR): + mkdir -p $(OBJDIR) + +which_makefile: + echo MakeIsGNU + +grammar.tab.c: grammar.y + $(YACC) grammar.y + -rm -f grammar.tab.* + sed "s/y.tab.c/grammar.tab.c/g" y.tab.c > grammar.tab.c + -mv y.tab.h grammar.tab.h + +packages/packages.a: packages/*.c + $(MAKE) -C packages 'CC=$(CC)' 'CFLAGS=$(CFLAGS) $(OPTIMIZE)' 'OBJDIR=../$(OBJDIR)' 'RANLIB=$(RANLIB)' 'A=$(A)' 'O=$(O)' + +$(DRIVER_BIN): packages/packages.a $(OBJ) dtrace_compile + -mv -f $(DRIVER_BIN) $(DRIVER_BIN).old + $(PROOF) $(CC) $(CFLAGS) $(OPTIMIZE) $(OBJ) `./dtrace_compile` -o $(DRIVER_BIN) packages/packages.a $(EXTRALIBS) `cat system_libs` + +dtrace_compile: dtrace_compile.c local_options + $(CC) dtrace_compile.c -o dtrace_compile + +addr_server: files $(OBJDIR)/addr_server.o $(OBJDIR)/socket_ctrl.o $(OBJDIR)/port.o addr_server.h + $(CC) $(CFLAGS) $(OPTIMIZE) $(OBJDIR)/socket_ctrl.o $(OBJDIR)/addr_server.o $(OBJDIR)/port.o \ + -o addr_server `cat system_libs` + +portbind: $(OBJDIR)/portbind.o + $(CC) $(CFLAGS) $(OPTIMIZE) $(OBJDIR)/portbind.o -o portbind `cat system_libs` + + +remake: neat all + +customize: + -cp ../local_options . + -cp ../system_libs . + -cp ../configure.h . + +depend: opcodes.h grammar.tab.c cc.h efunctions.h efun_defs.c configure.h + -rm tmpdepend + for i in *.c; do $(CC) -MM -DDEPEND $$i >>tmpdepend; done + sed -e "s!^[^ ]!$(OBJDIR)/&!" Dependencies + -rm tmpdepend + +cc.h: GNUmakefile + rm -f cc.h + echo "/* this file automatically generated by the Makefile */" > cc.h + echo '#define COMPILER "$(CC)"' >> cc.h + echo '#define OPTIMIZE "$(OPTIMIZE)"' >> cc.h + echo '#define CFLAGS "$(CFLAGS) $(OPTIMIZE)"' >> cc.h + echo '#define OBJDIR "$(OBJDIR)"' >> cc.h + +# the touches here are necessary to fix the modification times; link(2) does +# 'modify' a file +files: edit_source sysmalloc.c debugmalloc.c wrappedmalloc.c options.h op_spec.c func_spec.c packages/Makefile.pre packages/GNUmakefile.pre configure.h grammar.y.pre + ./edit_source -options -malloc -build_func_spec '$(CPP) $(CFLAGS)' \ + -process grammar.y.pre + ./edit_source -process packages/Makefile.pre + ./edit_source -process packages/GNUmakefile.pre + ./edit_source -build_efuns -build_applies + touch mallocwrapper.c + touch malloc.c + touch files + +make_func.tab.c: make_func.y cc.h + $(YACC) $(YFLAGS) make_func.y + -rm -f make_func.tab.c + mv y.tab.c make_func.tab.c + +configure.h: edit_source build.FluffOS + -if test \( ! -r configure.h \) -o \( ! -r configuration \); then \ + rm -f configuration; \ + touch configuration; \ + fi + if test "Machine `uname -a` Configure version 5" = "`cat configuration`"; then \ + echo "Skipping configuration ..."; \ + else \ + ./edit_source -configure; \ + echo "Machine `uname -a` Configure version 5" > configuration; \ + fi + +$(OBJDIR)/edit_source.o: edit_source.c preprocess.c cc.h + +edit_source: $(OBJDIR)/edit_source.o $(OBJDIR)/hash.o $(OBJDIR)/make_func.tab.o + $(CC) $(CFLAGS) $(OBJDIR)/edit_source.o $(OBJDIR)/hash.o $(OBJDIR)/make_func.tab.o -o edit_source + +# don't optimize these two +$(OBJDIR)/edit_source.o: edit_source.c + $(CC) $(CFLAGS) -o $@ -c $< + +$(OBJDIR)/make_func.tab.o: make_func.tab.c + $(CC) $(CFLAGS) -o $@ -c $< + +tags: $(SRC) + ctags $(SRC) + +TAGS: $(SRC) + etags $(SRC) + +install: all + -mkdir $(INSTALL_DIR) + $(INSTALL) $(DRIVER_BIN) $(INSTALL_DIR) + $(INSTALL) addr_server $(INSTALL_DIR) + $(INSTALL) portbind $(INSTALL_DIR) + +Makefiles: Makefile.in NMakefile.in + +Makefile.in: edit_source Makefile.in.pre Makefile.master + ./edit_source -process Makefile.in.pre + +NMakefile.in: edit_source NMakefile.in.pre Makefile.master + ./edit_source -process NMakefile.in.pre + +nothing: + +# remove local configuration +spotless: clean + -rm -f configure.h local_options system_libs configuration + -rm -f options_incl.h + -rm -f *.diffs + -find . -name "*~" -print | xargs rm + -rm -f 1.out 2.out + +# get ready for recompile +neat: + -(cd packages; $(MAKE) "A=$(A)" "O=$(O)" clean) + -rm -rf $(OBJDIR) *.$(O) *.tab.c *.tab.h + -rm -f efun_defs.c option_defs.c + -rm -f opcodes.h efunctions.h opc.h efun_protos.h + -rm -f malloc.c mallocwrapper.c + -rm -f func_spec.cpp applies.h applies_table.c files + -rm -f grammar.y comptest* a.out *.exe + -rm -f packages/Makefile packages/GNUmakefile packages/packages + +# remove everything except configuration +clean: neat + -rm -f Makefile.MudOS GNUmakefile.MudOS + -rm -f cc.h edit_source + -rm -f core y.output testsuite/core testsuite/tmp/* + -rm -f testsuite/OPCPROF.* testsuite/opc.* + -rm -rf testsuite/binaries testsuite/single/swapfile.* + -rm -f testsuite/OBJ_DUMP* testsuite/test_file testsuite/testfile + -rm -f testsuite/tmp_eval_file.c testsuite/sf.o testsuite/ed_test + -rm -f testsuite/log/log testsuite/log/debug.log testsuite/log/compile + -find . -name "*~" -print | xargs rm + -find . -name "*.orig" -print | xargs rm + -find . -name "*.rej" -print | xargs rm + -rm -f *.ln tags TAGS + -rm -f $(DRIVER_BIN) $(DRIVER_BIN).old addr_server portbind *.exe + -rm -f Dependencies tmpdepend + -touch Dependencies + +# remove everything +distclean: neat + -rm -f Makefile.MudOS GNUmakefile.MudOS + -rm -f cc.h edit_source + -rm -f core y.output testsuite/core testsuite/tmp/* + -rm -f testsuite/OPCPROF.* testsuite/opc.* + -rm -rf testsuite/binaries testsuite/single/swapfile.* + -rm -f testsuite/OBJ_DUMP* testsuite/test_file testsuite/testfile + -rm -f testsuite/tmp_eval_file.c testsuite/sf.o testsuite/ed_test + -rm -f testsuite/log/log testsuite/log/debug.log testsuite/log/compile + -find . -name "*~" -print | xargs rm + -find . -name "*.orig" -print | xargs rm + -find . -name "*.rej" -print | xargs rm + -rm -f *.ln tags TAGS + -rm -f $(DRIVER_BIN) $(DRIVER_BIN).old addr_server portbind + -rm -f *.exe + -rm -f configure.h system_libs options_incl.h insttest configuration + -rm -f 1.out 2.out + -rm -f local_options + -rm -f dtrace_compile + -rm -f trash_me.bat trash_me.err + -cp -f GNUmakefile.in GNUmakefile + -rm -f Dependencies tmpdepend + -rm -f semantic* packages/semantic* + -touch Dependencies + +include Dependencies diff --git a/fluffos-2.23-ds03/GNUmakefile.keep b/fluffos-2.23-ds03/GNUmakefile.keep new file mode 100644 index 0000000..ba4b914 --- /dev/null +++ b/fluffos-2.23-ds03/GNUmakefile.keep @@ -0,0 +1,257 @@ +MAKE=gmake +SHELL=/bin/sh +OBJDIR=obj +DRIVER_BIN=driver +PROOF= +STRFUNCS= +INSTALL=install -c +INSTALL_DIR=../bin +OPTIMIZE= -O2 +CPP=gcc -E +CFLAGS=-D__USE_FIXED_PROTOTYPES__ -DHAVE_ZLIB -rdynamic +CC=icc -ip -wd864,1173 -xK +#CC=gcc -g +YACC=bison -d -y +RANLIB=ranlib +A=a +O=o + +# YOU DO NOT NEED TO CONFIGURE ANYTHING IN THIS FILE. +# +# RUN THE SHELL SCRIPT ./build.MudOS to generate the Makefiles, and follow +# its instructions. +# +############################################################################ +# +# **** TARGETS AND THEIR CORRECT USAGE **** +# +# COMPILATION TARGETS: +# +# all: compile all the files +# +# install: make all, then move the files to the correct directories +# +# remake: remove the object files and generated files, and recompile +# NO reconfiguration is done, etc. +# +# depend: automatically create dependency info +# +# Makefiles: update Makefile.in and GNUmakefile.in from Makefile.master +# (only necessary after making changes to Makefile.master) +# +# 'CLEAN' TARGETS: +# +# neat: remove object files and generated files (used by remake) +# +# clean: in addition to neat, also remove .orig and .rej files, +# cores, lint files, emacs backups, tag files, yacc debug +# files, generated Makefiles, generated binaries, and +# generated dependency info +# +# spotless: make clean, then remove ALL CONFIGURATION AND CUSTOMIZATION +# useful for creating distributions +# +# ---- REALLY COMPLEX OPTIONS YOU PROBABLY DON'T WANT TO TOUCH ----- +# +# NeXT: link with MallocDebug if you have a NeXT with NeXTOS 2.1 or later and +# you wish to search for memory leaks (see /NextDeveloper/Apps/MallocDebug). +# Note: linking with MallocDebug will cause the virtual size of the +# driver process to reach appoximately 40MB however the amount of real memory +# used will remain close to normal. +#EXTRALIBS=-lMallocDebug -lsys_s +# +# ---- DO NOT EDIT ANYTHING BELOW HERE UNLESS YOU KNOW ALOT ABOUT HOW +# MUDOS WORKS INTERNALLY ---- + +OVERRIDES=$(MAKEOVERRIDES) + +# ************************************************************************** +# **** NOTE: If you add something here, also add it to the OBJ= rule below, +# **** or non-GNU makes will die +# ************************************************************************** +SRC=grammar.tab.c lex.c main.c rc.c interpret.c simulate.c file.c object.c \ + backend.c array.c mapping.c comm.c ed.c regexp.c swap.c buffer.c crc32.c \ + malloc.c mallocwrapper.c class.c efuns_main.c efuns_port.c \ + call_out.c otable.c dumpstat.c stralloc.c hash.c \ + port.c reclaim.c parse.c simul_efun.c sprintf.c program.c \ + compiler.c avltree.c icode.c trees.c generate.c scratchpad.c \ + socket_efuns.c socket_ctrl.c qsort.c eoperators.c socket_err.c md.c \ + disassembler.c binaries.c ualarm.c $(STRFUNCS) \ + replace_program.c ccode.c cfuns.c compile_file.c master.c function.c \ + debug.c crypt.c applies_table.c add_action.c + +all: $(OBJDIR) cc.h files main_build + +main_build: $(DRIVER_BIN) addr_server portbind + +parallel: + $(MAKE) -k -l -j 6 cc.h files + $(MAKE) -k -l -j 6 main_build + +VPATH = $(OBJDIR) + +OBJ=$(addprefix $(OBJDIR)/,$(subst .c,.o,$(SRC))) + +$(OBJDIR)/%.o: %.c + $(CC) $(CFLAGS) $(OPTIMIZE) -o $@ -c $< + +$(OBJDIR)/lex.o: lex.c preprocess.c cc.h grammar.tab.c + +$(OBJDIR)/grammar.tab.o: grammar.tab.c opcodes.h + +$(OBJDIR): + mkdir -p $(OBJDIR) + +which_makefile: + echo MakeIsGNU + +grammar.tab.c: grammar.y + $(YACC) grammar.y + -rm -f grammar.tab.* + sed "s/y.tab.c/grammar.tab.c/g" y.tab.c > grammar.tab.c + -mv y.tab.h grammar.tab.h + +packages/packages.a: packages/parser.c packages/contrib.c + $(MAKE) -C packages 'CC=$(CC)' 'CFLAGS=$(CFLAGS) $(OPTIMIZE)' 'OBJDIR=../$(OBJDIR)' 'RANLIB=$(RANLIB)' 'A=$(A)' 'O=$(O)' + +mudlib/mudlib.a: + $(MAKE) -C mudlib 'CC=$(CC)' 'CFLAGS=$(CFLAGS) $(OPTIMIZE)' 'OBJDIR=../$(OBJDIR)' 'RANLIB=$(RANLIB)' 'A=$(A)' 'O=$(O)' +$(DRIVER_BIN): packages/packages.a mudlib/mudlib.a $(OBJ) + -mv -f $(DRIVER_BIN) $(DRIVER_BIN).old + $(PROOF) $(CC) $(CFLAGS) $(OPTIMIZE) $(OBJ) -o $(DRIVER_BIN) packages/packages.a mudlib/mudlib.a $(EXTRALIBS) `cat system_libs` + +addr_server: files $(OBJDIR)/addr_server.o $(OBJDIR)/socket_ctrl.o $(OBJDIR)/port.o addr_server.h + $(CC) $(CFLAGS) $(OPTIMIZE) $(OBJDIR)/socket_ctrl.o $(OBJDIR)/addr_server.o $(OBJDIR)/port.o \ + -o addr_server `cat system_libs` + +portbind: $(OBJDIR)/portbind.o + $(CC) $(CFLAGS) $(OPTIMIZE) $(OBJDIR)/portbind.o -o portbind `cat system_libs` + + +remake: neat all + +customize: + -cp ../local_options . + -cp ../system_libs . + -cp ../configure.h . + +depend: opcodes.h grammar.tab.c cc.h efunctions.h efun_defs.c configure.h + -rm tmpdepend + for i in *.c; do $(CC) -MM -DDEPEND $$i >>tmpdepend; done + sed -e "s!^[^ ]!$(OBJDIR)/&!" Dependencies + -rm tmpdepend + +cc.h: GNUmakefile + rm -f cc.h + echo "/* this file automatically generated by the Makefile */" > cc.h + echo '#define COMPILER "$(CC)"' >> cc.h + echo '#define OPTIMIZE "$(OPTIMIZE)"' >> cc.h + echo '#define CFLAGS "$(CFLAGS) $(OPTIMIZE)"' >> cc.h + echo '#define OBJDIR "$(OBJDIR)"' >> cc.h + +# the touches here are necessary to fix the modification times; link(2) does +# 'modify' a file +files: edit_source sysmalloc.c smalloc.c bsdmalloc.c debugmalloc.c wrappedmalloc.c options.h op_spec.c func_spec.c mudlib/Makefile.pre mudlib/GNUmakefile.pre packages/Makefile.pre packages/GNUmakefile.pre configure.h grammar.y.pre + ./edit_source -options -malloc -build_func_spec '$(CPP) $(CFLAGS)' \ + -process grammar.y.pre + ./edit_source -process packages/Makefile.pre + ./edit_source -process packages/GNUmakefile.pre + ./edit_source -process mudlib/Makefile.pre + ./edit_source -process mudlib/GNUmakefile.pre + ./edit_source -build_efuns -build_applies + touch mallocwrapper.c + touch malloc.c + touch files + +make_func.tab.c: make_func.y cc.h + $(YACC) $(YFLAGS) make_func.y + -rm -f make_func.tab.c + mv y.tab.c make_func.tab.c + +configure.h: edit_source build.MudOS + -if test \( ! -r configure.h \) -o \( ! -r configuration \); then \ + rm -f configuration; \ + touch configuration; \ + fi + if test "Machine `uname -a` Configure version 5" = "`cat configuration`"; then \ + echo "Skipping configuration ..."; \ + else \ + ./edit_source -configure; \ + echo "Machine `uname -a` Configure version 5" > configuration; \ + fi + +$(OBJDIR)/edit_source.o: edit_source.c preprocess.c cc.h + +edit_source: $(OBJDIR)/edit_source.o $(OBJDIR)/hash.o $(OBJDIR)/make_func.tab.o + $(CC) $(CFLAGS) $(OBJDIR)/edit_source.o $(OBJDIR)/hash.o $(OBJDIR)/make_func.tab.o -o edit_source + +# don't optimize these two +$(OBJDIR)/edit_source.o: edit_source.c + $(CC) $(CFLAGS) -o $@ -c $< + +$(OBJDIR)/make_func.tab.o: make_func.tab.c + $(CC) $(CFLAGS) -o $@ -c $< + +tags: $(SRC) + ctags $(SRC) + +TAGS: $(SRC) + etags $(SRC) + +install: all + -mkdir $(INSTALL_DIR) + $(INSTALL) $(DRIVER_BIN) $(INSTALL_DIR) + $(INSTALL) addr_server $(INSTALL_DIR) + $(INSTALL) portbind $(INSTALL_DIR) + +Makefiles: Makefile.in GNUmakefile.in NMakefile.in + +Makefile.in: edit_source Makefile.in.pre Makefile.master + ./edit_source -process Makefile.in.pre + +GNUmakefile.in: edit_source GNUmakefile.in.pre Makefile.master + ./edit_source -process GNUmakefile.in.pre + +NMakefile.in: edit_source NMakefile.in.pre Makefile.master + ./edit_source -process NMakefile.in.pre + +nothing: + +# remove local configuration +spotless: clean + -rm -f configure.h local_options system_libs configuration + -rm -f options_incl.h + -rm -f *.diffs + -find . -name "*~" -print | xargs rm + +# get ready for recompile +neat: + -(cd packages; $(MAKE) "A=$(A)" "O=$(O)" clean) + -(cd mudlib; $(MAKE) "A=$(A)" "O=$(O)" clean) + -rm -rf $(OBJDIR) *.$(O) *.tab.c *.tab.h + -rm -f efun_defs.c option_defs.c + -rm -f opcodes.h efunctions.h opc.h efun_protos.h + -rm -f malloc.c mallocwrapper.c + -rm -f func_spec.cpp applies.h applies_table.c files + -rm -f grammar.y comptest* a.out + -rm -f packages/Makefile packages/GNUmakefile packages/packages + +# remove everything except configuration +clean: neat + -rm -f Makefile.MudOS GNUmakefile.MudOS + -rm -f cc.h edit_source + -rm -f core y.output testsuite/core testsuite/tmp/* + -rm -f testsuite/OPCPROF.* testsuite/opc.* + -rm -rf testsuite/binaries testsuite/single/swapfile.* + -rm -f testsuite/OBJ_DUMP* testsuite/test_file testsuite/testfile + -rm -f testsuite/tmp_eval_file.c testsuite/sf.o testsuite/ed_test + -rm -f testsuite/log/log testsuite/log/debug.log testsuite/log/compile + -find . -name "*~" -print | xargs rm + -find . -name "*.orig" -print | xargs rm + -find . -name "*.rej" -print | xargs rm + -rm -f *.ln tags TAGS + -rm -f $(DRIVER_BIN) $(DRIVER_BIN).old addr_server portbind + -rm -f Dependencies tmpdepend + -touch Dependencies + +include Dependencies diff --git a/fluffos-2.23-ds03/INSTALL b/fluffos-2.23-ds03/INSTALL new file mode 100644 index 0000000..22e5a4e --- /dev/null +++ b/fluffos-2.23-ds03/INSTALL @@ -0,0 +1,16 @@ +Complete installation instructions are available in major releases +(as opposed to minor releases). The major releases also contain +documentation, etc. + +Short instructions: + +1) edit options.h to suit your tastes +2) type: ./build.MudOS +3) follow the instructions printed on the screen +4) you will need a runtime config file and a mudlib in order to use the driver. +5) look at the example config file in this directory (Config.example) +6) get a MudOS-compatible mudlib. Note that many mudlibs require certain + setting in options.h, so the documentation of the mudlib should be + consulted. Also, note that many mudlibs come prepackaged with a + version of MudOS they are known to work well with. +7) have fun. diff --git a/fluffos-2.23-ds03/IT_CRASHED b/fluffos-2.23-ds03/IT_CRASHED new file mode 100644 index 0000000..1473382 --- /dev/null +++ b/fluffos-2.23-ds03/IT_CRASHED @@ -0,0 +1,130 @@ + + It Crashed!!! + + by Beek and Robocoder + +*** +*** Contents +*** + 1) Introduction + 2) General Notes + 3) Unattended operation/automation + 4) Debugging core files + 5) Notes for SAS/C Amiga users + +*** +*** Introduction +*** +This file documents some methods of obtaining crash information which +the MudOS developers may find useful in tracking down hard to reproduce +crashers (serious bugs). + +*** +*** General Notes +*** +Ok, if your driver crashes, and you want to be helpful, here's what you do: + +1. recompile the driver with the -g flag. Turning off optimization + is a good idea too. [This can be done by doing a 'make neat' (or gmake), + reruning ./build.MudOS as follows: './build.MudOS debug', then recompile] +2. go to your bin dir and type 'gdb driver' where driver is the name of your + driver executable +3. It should startup, etc. When it's ready, type 'run config.foo' or + whatever you normally do to run the driver, with 'run' instead of the + driver executable name. +4. Wait for the driver to crash (or cause it to crash, if you know how) +5. gdb should give you a prompt again. type 'where' +6. Post the output of the where command along with anything you know + about where/how/why the driver crashed on the MudOS bug report board. + Stuff like example LPC source code, a tail of driver.err and/or + debug.log, etc may be helpful. In some cases the driver writes important + information to those files as it goes down. + +If you actually get a traceback, it makes crashes somewhere between +10-100x easier to fix (at least!). Remember to also specify your +driver version (eg 0.9.19), operating system/architecture, and its +version (eg SunOS 5.3). + +Note: + If you didn't use 'gcc', but 'cc' instead (for example), to compile the + driver, you will have to use 'dbx' (if you have it). The same + instructions as above apply...just replace instances of 'gdb' with 'dbx'. + +*** +*** Unattended operation/automation +*** +If you want to automate the process of collecting this crash information, +something you can stick this into your startmud script, read this section. +Begin by creating a batchfile with the following contents: + + run config.foo >driver.err + where + +Replace 'config.foo' with the name of your config file, and 'driver.err' +with whatever you've set up for redirecting the driver's stderr to. +Where you have 'driver' (or whatever you named the executable) in your +startmud script, use (depending on the compiler used): + + gdb -batch -x batchfile driver >report + + or: + + dbx -i driver report + +If/when it crashes, send us a copy of the report. + +*** +*** Debugging core files +*** +This section applies to you, if the driver has crashed, leaving a +core file behind. A large core file is a good sign. =) Some users or +systems may set a resource limit on the size of core files, eg + + limit coredumpsize 0 + +preventing them from debugging from the core file. Remove the limit +or skip this section. HP/Apollo (Domain OS) users may be able to use +'/com/tb' to get traceback information. + +Using dbx: Using gdb: + + dbx driver core gdb driver core + where where + quit quit + +Replace 'driver' with the path of your driver executable. + +Another useful command is 'print', which can be used to print the +values of variables in the current function, eg + + print str + +'dbx' users can also use the 'dump' command to display the names and +variable values in a function, eg + + dump main >file + +*** +*** SAS/C (Amiga) +*** +If you are using SAS/C, compile with Debug=Symbol and link with AddSym. +It's a good to turn off optimizations with NoOpt and NoOptPeep. +You can use either 'cpr' or 'tb'. For 'cpr', use: + + cpr -line -command "where -a; register" driver config.foo >report + +Using 'tb' is a bit more involved. In building the driver, you must: + + slink with catch.o or catchnr.o to generate snapshot files + +so that if/when the driver crashes, the 'tb' utility can be used to process +the snapshot file. catch.o will ask first before creating a snapshot file, +while catchnr.o will not ask -- if the system is in a bad state, and +catchnr.o is unable to complete writing the snapshot file, the filesystem +can be potentially corrupted. Once you have a 'Snapshot.TB' file, use: + + tb -l + +to obtain detailed traceback information + + --- EOF --- diff --git a/fluffos-2.23-ds03/Ideas b/fluffos-2.23-ds03/Ideas new file mode 100644 index 0000000..2c15da6 --- /dev/null +++ b/fluffos-2.23-ds03/Ideas @@ -0,0 +1,268 @@ +The current implementation of swapping could use a lot of work. Swapping +an object in/out isn't that expensive CPU wise, and can save a decent amount +of memory. The problem is that cloned programs can't swap, which disables +swapping for much of the mud ... + +-Beek + +----- + +7. It would be more real, if a new call_out happen after all the previous + call_outs of the same delay. (because it were called later) + example: call_out("foo",1); + call_out("bar",1); + now bar will be called first and not foo! It's unreal. + could be possible a call_out with 0 delay ? we would use it for + safe destruct object. + +Comment: + +Ideally, a better fix would be for call_out to have a smaller +granularity, so the second call_out follows the first by whatever the +time difference between the two was. This problem will always happen +if the call_outs are within the granularity, and real small +granularities (microsecond?) may/may not be desirable. + +----- + +The names of includes which define no code don't have to be saved for +line number purposes (although they are still needed for binaries; see +the other note about merging the two lists) + +----- + +Master applies should be cached like sefuns are. Currently, APPLY_* +are string constants so they always miss the call_other cache, making +master applies slow. APPLY_CREATE also always misses the cache, but +it's always going to miss anyway so no problem :-). Others like APPLY_ID +etc should be changed to use shared strings so they can hit. + +----- + +There should be a NO_HEART_BEATS option + +----- + +we need to made a single-user option for MudOS that doesn't use sockets +at all so that people wanting to run MudOS at schools where programs +aren't allowed to listen on socket (anti-mud policies) can use MudOS +for developing LPC code for another mud. + +--john + +----- + +From: John Garnett + + +It'd be cool if there were efuns like this: + +mapping x; + +attach_mapping(mapping x, string filename); + +detach_mapping(x); + +which would attach mapping x to the database named by filename. + +any accesses to the mapping x would in fact manipulate the database. + +This would work much the way attached mappings work in Perl. + +We could use the dbm database code in UNIX(tm). Only problem is +not all UNIX's have dbm's that support multiple databases per +UNIX process. + +----- + +In message <9303080120.AA26940@rock.concert.net> Dank writes: +>powerful. This seems "grossly unfair" to our more serious gamers. That's +>why i need to know the best way to implement (either in the driver or in LPC) +>an hb_call_out() efun, that operates exactly as call_out() does, except that +>it calls its function after a set number of _heartbeats_ have elapsed, not +>after a set number of seconds. +> I ran this by Mobydick, and he thought the solution should be sought from +>you driver folks rather than in the mudlib (course, that may be because +>he's a mudlib coder :) + +I agree; it does seem that we need a variant of call_out that operates in terms +of number of heartbeats rather than absolute # of seconds. A few ways +to do this. + +// optionally change the way call_out() works so that muds can change it if +// they like. +#define CALL_OUT_UNITS_EQUAL_HEARTBEAT /* or some shorter similar thing */ + +Or we could make a call_out2() efun that operates in the desired heartbeat units +(name it something more appropriate than call_out2()). + +----- + +hmm, save_object() should probably somehow save the subtype of numbers. +(ie null, undefined, error, etc) + +ucs_brf@pip.shsu.edu + +Comment: with some of the optimizations lately, the subtype of numbers is + not always reliable longterm ... + +----- + +An option for persistent swap files (that the driver can restore/recover +from), saving clones and the contents of variables. + +### This seems to be a fad and a bad idea, but I'll get flamed for saying + that ... + +----- + +mudlib_stats uses a linked list, it is fast for insertion; however + lookup is O(n)...this should be hacked to use an AVL tree (ala uid.c) + +-- robo + +----- + +#pragma no_inherit +#pragma no_clone + +-- Cygnus & Descartes + +Comment: + Unlike regular C, should these two pragmas should generate warnings + (or error out) if the driver wasn't compiled with this option enabled? + + Also, adapt Tensor's idea for uniquep() efun...which queries these + flags, telling whether an object is cloneable and/or inheritable + (or not, depending on your point of view). + + These aren't object flags as first believed...they have to be stored + in the program structure, so that it can be restored from binaries. + pragma_no_inherit & pragma_no_clone flags should probably be in + simulate.c, disjoint from those in lex.c. + clone_object() + ob = find_object_no_load() + if (ob->prog->flags & P_NO_CLONE) + error("Illegal object to clone\n"); + + find_object() + find_object2() <- avoid calling this again (for performance) + load_object() + + inheritance: (compiler/grammar & lpc_compiler/grammar) + ob = find_object2() + + if (ob->prog->flags & P_NO_INHERIT) + yyerror("Illegal object to inherit\n"); + + lex.c + init pragma_no_inherit + pragma_no_clone + + compiler/grammar & lpc_compiler/grammar + set prog flags + +----- + +Implement compile stacks so we don't have to dump an object (and later +restart the compile) if an inherited object isn't defined yet. + +Note: This would entail requiring the use of bison or pre-yacc'ed grammars +since most versions of yacc parsers aren't reentrant. -Beek + +Actually, I take this back. One could make the inherit rule look like: + +inheritance: type_modifier_list L_INHERIT string_con1 ';' + { + ... + ob = find_object2(file); + if (ob == 0) { + push_compiler_globals(); + lex_inherit_hook(file); + } else { + lex_loaded_inherit_hook(); + } + } + program terminator + { + ... import symbols ... + } + +terminator: + L_ALREADY_LOADED + | L_JUST_LOADED + { + pop_compiler_globals(); + } + +etc ... lex_inherit_hook() cues lex to push it's globals and start a new +file; lex_loaded_inherit_hook() cues lex to just return L_ALREADY_LOADED +as the next token (note: in deep inherits this could require a rather +deep yacc stack) + +--- + +Set up grammar dir for pre-byacc'd and/or pre-bison'd parsers for people + with broken 'yacc's. + +Support L_ARRAY_CLOSE, L_FUNCTION_CLOSE, and L_MAPPING_CLOSE for consistency; +L_MAPPING_CLOSE requires a bit more work... + +-- robo + +----- + +Threads :) + +----- + +Exceptions :) + +----- + +A make_mapping() efun that obeys the tautology: + +make_mapping( keys(m), values(m) ) == m + +----- + +include_list() efun; also, BINARIES saves a list of includes, but error +line numbers do as well; the former should be modified to use the latter's +list (which was added after binaries were) + +----- + +maybe: + +foreach (i, x in ({ 1, 2 })) + +foreach (x in ([ 1 : 2, 3 : 4 ])) + +foreach (i, j in ({ 1, 2 }), ({ 3, 4, 5 })) + for parallel walking + +--- + +The handling of || and && is still suboptimal; it tests twice, and does +a uneccessary pop for expressions like: (x && y); it completely blows it +on expressions like 1 || 1 || 1; + +--- + +Profiling shows that a significant amount of CPU is wasted copying stack +values around in the parser due to the large size of %union. In most +cases, only 4 (assuming 32 bit) bytes is needed: + +4: /* most stuff */ +5: decl +8: func_block + +so this is a huge waste. The larger ones could be managed from temporary +pools (they might even have FIFO ordering, but be careful about parse errors) +decl seems unavoidable, but 6 should be possible, cutting the size of +the compile stack and mem that needs to be copied down a bit. +func_block is only used by function pointers anyway, so isn't that common. +There is already a stack for the other function temporary and a depth limit +... + +-Beek diff --git a/fluffos-2.23-ds03/Makefile b/fluffos-2.23-ds03/Makefile new file mode 100644 index 0000000..1d32945 --- /dev/null +++ b/fluffos-2.23-ds03/Makefile @@ -0,0 +1,12 @@ +all: + @echo MudOS is currently configured to use 'GNUmakefile'. Edit 'build.MudOS' + @echo if this is not what you want. + +.DEFAULT: + @echo MudOS is currently configured to use 'GNUmakefile'. Edit 'build.MudOS' + @echo if this is not what you want. + +nothing: + +which_makefile: + echo MakeIsMake diff --git a/fluffos-2.23-ds03/Makefile.in b/fluffos-2.23-ds03/Makefile.in new file mode 100644 index 0000000..49efed2 --- /dev/null +++ b/fluffos-2.23-ds03/Makefile.in @@ -0,0 +1,243 @@ + +# YOU DO NOT NEED TO CONFIGURE ANYTHING IN THIS FILE. +# +# RUN THE SHELL SCRIPT ./build.MudOS to generate the Makefiles, and follow +# its instructions. +# +############################################################################ +# +# **** TARGETS AND THEIR CORRECT USAGE **** +# +# COMPILATION TARGETS: +# +# all: compile all the files +# +# install: make all, then move the files to the correct directories +# +# remake: remove the object files and generated files, and recompile +# NO reconfiguration is done, etc. +# +# depend: automatically create dependency info +# +# Makefiles: update Makefile.in and GNUmakefile.in from Makefile.master +# (only necessary after making changes to Makefile.master) +# +# 'CLEAN' TARGETS: +# +# neat: remove object files and generated files (used by remake) +# +# clean: in addition to neat, also remove .orig and .rej files, +# cores, lint files, emacs backups, tag files, yacc debug +# files, generated Makefiles, generated binaries, and +# generated dependency info +# +# spotless: make clean, then remove ALL CONFIGURATION AND CUSTOMIZATION +# useful for creating distributions +# +# ---- REALLY COMPLEX OPTIONS YOU PROBABLY DON'T WANT TO TOUCH ----- +# +# NeXT: link with MallocDebug if you have a NeXT with NeXTOS 2.1 or later and +# you wish to search for memory leaks (see /NextDeveloper/Apps/MallocDebug). +# Note: linking with MallocDebug will cause the virtual size of the +# driver process to reach appoximately 40MB however the amount of real memory +# used will remain close to normal. +#EXTRALIBS=-lMallocDebug -lsys_s +# +# ---- DO NOT EDIT ANYTHING BELOW HERE UNLESS YOU KNOW ALOT ABOUT HOW +# MUDOS WORKS INTERNALLY ---- + +OVERRIDES=$(MAKEOVERRIDES) + +# ************************************************************************** +# **** NOTE: If you add something here, also add it to the OBJ= rule below, +# **** or non-GNU makes will die +# ************************************************************************** +SRC=grammar.tab.c lex.c main.c rc.c interpret.c simulate.c file.c object.c \ + backend.c array.c mapping.c comm.c ed.c regexp.c buffer.c crc32.c \ + malloc.c mallocwrapper.c class.c efuns_main.c efuns_port.c \ + call_out.c otable.c dumpstat.c stralloc.c hash.c \ + port.c reclaim.c parse.c simul_efun.c sprintf.c program.c \ + compiler.c avltree.c icode.c trees.c generate.c scratchpad.c \ + socket_efuns.c socket_ctrl.c qsort.c eoperators.c socket_err.c md.c \ + disassembler.c uvalarm.c $(STRFUNCS) \ + replace_program.c master.c function.c \ + debug.c crypt.c add_action.c eval.c fliconv.c console.c applies_table.c + +all: cc.h files main_build +main_build2: $(DRIVER_BIN) addr_server portbind + +main_build: files + $(MAKE) main_build2 + +parallel: + $(MAKE) -k -l -j 6 cc.h files + $(MAKE) -k -l -j 6 main_build + +OBJ=grammar.tab.o lex.o main.o rc.o interpret.o simulate.o file.o object.o \ + backend.o array.o mapping.o comm.o ed.o regexp.o buffer.o crc32.o \ + malloc.o mallocwrapper.o class.o efuns_main.o efuns_port.o \ + call_out.o otable.o dumpstat.o stralloc.o hash.o \ + port.o reclaim.o parse.o simul_efun.o sprintf.o program.o \ + compiler.o avltree.o icode.o trees.o generate.o scratchpad.o \ + socket_efuns.o socket_ctrl.o qsort.o eoperators.o socket_err.o md.o \ + disassembler.o uvalarm.o $(STRFUNCS) \ + replace_program.o master.o function.o \ + debug.o crypt.o add_action.o eval.o fliconv.o console.o applies_table.o + +.c.o: + $(CC) $(CFLAGS) $(OPTIMIZE) -c $*.c + +# Some OS's can't deal with these being created during the make process? +malloc.o: malloc.c + +mallocwrapper.o: mallocwrapper.c + +lex.o: lex.c preprocess.c cc.h grammar.tab.c + +grammar.tab.o: grammar.tab.c opcodes.h + +which_makefile: + echo MakeIsMake + +grammar.tab.c: grammar.y + $(YACC) grammar.y + -rm -f grammar.tab.* + sed "s/y.tab.c/grammar.tab.c/g" y.tab.c > grammar.tab.c + -mv y.tab.h grammar.tab.h + +packages/packages.a: packages/parser.c packages/contrib.c + (cd packages; $(MAKE) 'CC=$(CC)' 'CFLAGS=$(CFLAGS) $(OPTIMIZE)' 'RANLIB=$(RANLIB)' 'A=$(A)' 'O=$(O)') + +$(DRIVER_BIN): packages/packages.a $(OBJ) + -mv -f $(DRIVER_BIN) $(DRIVER_BIN).old + $(PROOF) $(CC) $(CFLAGS) $(OPTIMIZE) $(OBJ) -o $(DRIVER_BIN) packages/packages.a $(EXTRALIBS) `cat system_libs` + +addr_server: files addr_server.o socket_ctrl.o port.o addr_server.h + $(CC) $(CFLAGS) $(OPTIMIZE) socket_ctrl.o addr_server.o port.o \ + -o addr_server `cat system_libs` + +portbind: portbind.o + $(CC) $(CFLAGS) $(OPTIMIZE) portbind.o -o portbind `cat system_libs` + +remake: neat all + +customize: + -cp ../local_options . + -cp ../system_libs . + -cp ../configure.h . + +depend: opcodes.h grammar.tab.c cc.h efunctions.h efun_defs.c configure.h + makedepend *.c + +cc.h: Makefile + rm -f cc.h + echo "/* this file automatically generated by the Makefile */" > cc.h + echo '#define COMPILER "$(CC)"' >> cc.h + echo '#define OPTIMIZE "$(OPTIMIZE)"' >> cc.h + echo '#define CFLAGS "$(CFLAGS) $(OPTIMIZE)"' >> cc.h + echo '#define OBJDIR "$(OBJDIR)"' >> cc.h + +# the touches here are necessary to fix the modification times; link(2) does +# 'modify' a file +files: edit_source sysmalloc.c smalloc.c bsdmalloc.c debugmalloc.c wrappedmalloc.c options.h op_spec.c func_spec.c packages/Makefile.pre packages/GNUmakefile.pre configure.h grammar.y.pre + ./edit_source -options -malloc -build_func_spec '$(CPP) $(CFLAGS)' \ + -process grammar.y.pre + ./edit_source -process packages/Makefile.pre + ./edit_source -process packages/GNUmakefile.pre + ./edit_source -build_efuns -build_applies + touch mallocwrapper.c + touch malloc.c + touch files + +make_func.tab.c: make_func.y cc.h + $(YACC) $(YFLAGS) make_func.y + -rm -f make_func.tab.c + mv y.tab.c make_func.tab.c + +configure.h: edit_source build.FluffOS + -if test \( ! -r configure.h \) -o \( ! -r configuration \); then \ + rm -f configuration; \ + touch configuration; \ + fi + if test "Machine `uname -a` Configure version 5" = "`cat configuration`"; then \ + echo "Skipping configuration ..."; \ + else \ + ./edit_source -configure; \ + echo "Machine `uname -a` Configure version 5" > configuration; \ + fi + +edit_source.o: edit_source.c preprocess.c cc.h + +edit_source: edit_source.o hash.o make_func.tab.o + $(CC) $(CFLAGS) edit_source.o hash.o make_func.tab.o -o edit_source + +edit_source.o: edit_source.c + $(CC) $(CFLAGS) -c $*.c + +make_func.tab.o: make_func.tab.c + $(CC) $(CFLAGS) -c $*.c + +hash.o: hash.c + $(CC) $(CFLAGS) $(OPTIMIZE) -c $*.c + +tags: force + ctags *.c *.y + +TAGS: force + etags *.c *.y + +force: + +install: all + -mkdir $(INSTALL_DIR) + $(INSTALL) $(DRIVER_BIN) $(INSTALL_DIR) + $(INSTALL) addr_server $(INSTALL_DIR) + $(INSTALL) portbind $(INSTALL_DIR) + +Makefiles: Makefile.in GNUmakefile.in NMakefile.in + +Makefile.in: edit_source Makefile.in.pre Makefile.master + ./edit_source -process Makefile.in.pre + +GNUmakefile.in: edit_source GNUmakefile.in.pre Makefile.master + ./edit_source -process GNUmakefile.in.pre + +NMakefile.in: edit_source NMakefile.in.pre Makefile.master + ./edit_source -process NMakefile.in.pre + +nothing: + +# remove local configuration +spotless: clean + -rm -f configure.h local_options system_libs configuration + -rm -f options_incl.h + -rm -f *.diffs + -find . -name "*~" -print | xargs rm + +# get ready for recompile +neat: + -(cd packages; $(MAKE) "A=$(A)" "O=$(O)" clean) + -rm -rf $(OBJDIR) *.$(O) *.tab.c *.tab.h + -rm -f efun_defs.c option_defs.c + -rm -f opcodes.h efunctions.h opc.h efun_protos.h + -rm -f malloc.c mallocwrapper.c + -rm -f func_spec.cpp applies.h applies_table.c files + -rm -f grammar.y comptest* a.out + -rm -f packages/Makefile packages/GNUmakefile packages/packages + +# remove everything except configuration +clean: neat + -rm -f Makefile.MudOS GNUmakefile.MudOS + -rm -f cc.h edit_source + -rm -f core y.output testsuite/core testsuite/tmp/* + -rm -f testsuite/OPCPROF.* testsuite/opc.* + -rm -rf testsuite/binaries testsuite/single/swapfile.* + -rm -f testsuite/OBJ_DUMP* testsuite/test_file testsuite/testfile + -rm -f testsuite/tmp_eval_file.c testsuite/sf.o testsuite/ed_test + -rm -f testsuite/log/log testsuite/log/debug.log testsuite/log/compile + -find . -name "*~" -print | xargs rm + -find . -name "*.orig" -print | xargs rm + -find . -name "*.rej" -print | xargs rm + -rm -f *.ln tags TAGS + -rm -f $(DRIVER_BIN) $(DRIVER_BIN).old addr_server portbind +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/fluffos-2.23-ds03/Makefile.in.pre b/fluffos-2.23-ds03/Makefile.in.pre new file mode 100644 index 0000000..c87391e --- /dev/null +++ b/fluffos-2.23-ds03/Makefile.in.pre @@ -0,0 +1,3 @@ +%define NORMAL + +%include "Makefile.master" diff --git a/fluffos-2.23-ds03/NMakefile.in b/fluffos-2.23-ds03/NMakefile.in new file mode 100644 index 0000000..48b5411 --- /dev/null +++ b/fluffos-2.23-ds03/NMakefile.in @@ -0,0 +1,266 @@ + +# YOU DO NOT NEED TO CONFIGURE ANYTHING IN THIS FILE. +# +# RUN THE SHELL SCRIPT ./build.MudOS to generate the Makefiles, and follow +# its instructions. +# +############################################################################ +# +# **** TARGETS AND THEIR CORRECT USAGE **** +# +# COMPILATION TARGETS: +# +# all: compile all the files +# +# install: make all, then move the files to the correct directories +# +# remake: remove the object files and generated files, and recompile +# NO reconfiguration is done, etc. +# +# depend: automatically create dependency info +# +# Makefiles: update Makefile.in and GNUmakefile.in from Makefile.master +# (only necessary after making changes to Makefile.master) +# +# 'CLEAN' TARGETS: +# +# neat: remove object files and generated files (used by remake) +# +# clean: in addition to neat, also remove .orig and .rej files, +# cores, lint files, emacs backups, tag files, yacc debug +# files, generated Makefiles, generated binaries, and +# generated dependency info +# +# spotless: make clean, then remove ALL CONFIGURATION AND CUSTOMIZATION +# useful for creating distributions +# +# ---- REALLY COMPLEX OPTIONS YOU PROBABLY DON'T WANT TO TOUCH ----- +# +# NeXT: link with MallocDebug if you have a NeXT with NeXTOS 2.1 or later and +# you wish to search for memory leaks (see /NextDeveloper/Apps/MallocDebug). +# Note: linking with MallocDebug will cause the virtual size of the +# driver process to reach appoximately 40MB however the amount of real memory +# used will remain close to normal. +#EXTRALIBS=-lMallocDebug -lsys_s +# +# ---- DO NOT EDIT ANYTHING BELOW HERE UNLESS YOU KNOW ALOT ABOUT HOW +# MUDOS WORKS INTERNALLY ---- + +OVERRIDES=$(MAKEOVERRIDES) + +# ************************************************************************** +# **** NOTE: If you add something here, also add it to the OBJ= rule below, +# **** or non-GNU makes will die +# ************************************************************************** +SRC=grammar$(TAB_EXT).c lex.c main.c rc.c interpret.c simulate.c file.c object.c \ + backend.c array.c mapping.c comm.c ed.c regexp.c swap.c buffer.c crc32.c \ + malloc.c mallocwrapper.c class.c efuns_main.c efuns_port.c \ + call_out.c otable.c dumpstat.c stralloc.c hash.c \ + port.c reclaim.c parse.c simul_efun.c sprintf.c program.c \ + compiler.c avltree.c icode.c trees.c generate.c scratchpad.c \ + socket_efuns.c socket_ctrl.c qsort.c eoperators.c socket_err.c md.c \ + disassembler.c binaries.c $(STRFUNCS) \ + replace_program.c ccode.c cfuns.c compile_file.c master.c function.c \ + debug.c crypt.c applies_table.c add_action.c + +all: utils cc.h files main_build + +main_build: $(DRIVER_BIN) addr_server + + +OBJ=$(OBJDIR)\grammar$(TAB_EXT).obj $(OBJDIR)\lex.obj $(OBJDIR)\main.obj $(OBJDIR)\rc.obj $(OBJDIR)\interpret.obj \ + $(OBJDIR)\simulate.obj $(OBJDIR)\file.obj $(OBJDIR)\object.obj $(OBJDIR)\backend.obj $(OBJDIR)\array.obj \ + $(OBJDIR)\mapping.obj $(OBJDIR)\comm.obj $(OBJDIR)\ed.obj $(OBJDIR)\regexp.obj $(OBJDIR)\swap.obj \ + $(OBJDIR)\buffer.obj $(OBJDIR)\crc32.obj $(OBJDIR)\malloc.obj $(OBJDIR)\mallocwrapper.obj \ + $(OBJDIR)\class.obj $(OBJDIR)\efuns_main.obj $(OBJDIR)\efuns_port.obj $(OBJDIR)\call_out.obj \ + $(OBJDIR)\otable.obj $(OBJDIR)\dumpstat.obj $(OBJDIR)\stralloc.obj $(OBJDIR)\hash.obj $(OBJDIR)\port.obj \ + $(OBJDIR)\reclaim.obj $(OBJDIR)\parse.obj $(OBJDIR)\simul_efun.obj $(OBJDIR)\sprintf.obj \ + $(OBJDIR)\program.obj $(OBJDIR)\compiler.obj $(OBJDIR)\avltree.obj $(OBJDIR)\icode.obj $(OBJDIR)\trees.obj \ + $(OBJDIR)\generate.obj $(OBJDIR)\scratchpad.obj $(OBJDIR)\socket_efuns.obj $(OBJDIR)\socket_ctrl.obj \ + $(OBJDIR)\qsort.obj $(OBJDIR)\eoperators.obj $(OBJDIR)\socket_err.obj $(OBJDIR)\md.obj \ + $(OBJDIR)\disassembler.obj $(OBJDIR)\binaries.obj $(OBJDIR)\add_action.obj \ + $(OBJDIR)\replace_program.obj $(OBJDIR)\ccode.obj $(OBJDIR)\cfuns.obj $(OBJDIR)\compile_file.obj \ + $(OBJDIR)\crypt.obj $(OBJDIR)\debug.obj $(OBJDIR)\master.obj $(OBJDIR)\function.obj $(OBJDIR)\applies_table.obj + +.c{$(OBJDIR)/}.obj: + $(CC) $(CFLAGS) $(OPTIMIZE) -Fo$(OBJDIR)\ -c $< + +$(OBJDIR)/lex.obj: lex.c preprocess.c cc.h grammar$(TAB_EXT).c + +$(OBJDIR)/grammar$(TAB_EXT).obj: grammar$(TAB_EXT).c opcodes.h + +which_makefile: + echo MakeIsNmake + +grammar$(TAB_EXT).c: grammar.y + $(YACC) grammar.y + -rm -f grammar$(TAB_EXT).* + sed "s/y$(TAB_EXT).c/grammar$(TAB_EXT).c/g" y$(TAB_EXT).c > grammar$(TAB_EXT).c + -mv y$(TAB_EXT).h grammar$(TAB_EXT).h + +packages/packages.lib: packages/parser.c packages/contrib.c + cd packages + $(MAKE) /nologo "CC=$(CC)" "CFLAGS=$(CFLAGS) $(OPTIMIZE)" "OBJDIR=../$(OBJDIR)" \ + "RANLIB=$(RANLIB)" "O=$(O)" "A=$(A)" + cd .. + +mudlib/mudlib.lib: + cd mudlib + $(MAKE) /nologo "CC=$(CC)" "CFLAGS=$(CFLAGS) $(OPTIMIZE)" "OBJDIR=../$(OBJDIR)" \ + "RANLIB=$(RANLIB)" "O=$(O)" "A=$(A)" + cd .. +$(DRIVER_BIN): $(DRIVER_BIN).exe + +$(DRIVER_BIN).exe: packages/packages.lib mudlib/mudlib.lib $(OBJ) + -mv -f $(DRIVER_BIN).exe $(DRIVER_BIN).old + $(CC) $(CFLAGS) $(OPTIMIZE) $(OBJ) -Fe$(DRIVER_BIN).exe packages/packages.lib mudlib/mudlib.lib \ + $(EXTRALIBS) @system_libs + +addr_server: addr_server.exe + +addr_server.exe: $(OBJDIR)/addr_server.obj $(OBJDIR)/socket_ctrl.obj $(OBJDIR)/port.obj addr_server.h + $(CC) $(CFLAGS) $(OPTIMIZE) $(OBJDIR)/socket_ctrl.obj $(OBJDIR)/addr_server.obj $(OBJDIR)/port.obj \ + -Feaddr_server.exe @system_libs + +remake: neat all + +customize: cp.bat + -cp ..\local_options . + -cp ..\system_libs . + -cp ..\configure.h . + +cc.h: Makefile + rm -f cc.h + echo /* this file automatically generated by the Makefile */ > cc.h + echo #define COMPILER "$(CC)" >> cc.h + echo #define OPTIMIZE "$(OPTIMIZE)" >> cc.h + echo #define CFLAGS "$(CFLAGS) $(OPTIMIZE)" >> cc.h + echo #define OBJDIR "$(OBJDIR)" >> cc.h + +# the touches here are necessary to fix the modification times; link(2) does +# 'modify' a file +files: edit_source sysmalloc.c smalloc.c bsdmalloc.c debugmalloc.c wrappedmalloc.c options.h op_spec.c func_spec.c mudlib/Makefile.pre mudlib/GNUmakefile.pre packages/Makefile.pre packages/GNUmakefile.pre configure.h grammar.y.pre + .\edit_source -options -malloc -build_func_spec "$(CPP) $(CFLAGS)" \ + -process grammar.y.pre + .\edit_source -process packages/Makefile.pre + .\edit_source -process packages/GNUmakefile.pre + .\edit_source -process mudlib/Makefile.pre + .\edit_source -process mudlib/GNUmakefile.pre + .\edit_source -build_efuns -build_applies + touch mallocwrapper.c + touch malloc.c + touch files + +make_func$(TAB_EXT).c: make_func.y cc.h + $(YACC) $(YFLAGS) make_func.y + -rm -f make_func$(TAB_EXT).c + mv y$(TAB_EXT).c make_func$(TAB_EXT).c + +configure.h: edit_source.exe build.MudOS + if not exist configure.h rm -f configuration + touch configuration + .\edit_source -configure + +build.MudOS: buildMudOS.bat + +$(OBJDIR)/crypt.obj: ./amiga/crypt.c + $(CC) $(CFLAGS) $(OPTIMIZE) -Fo$(OBJDIR)\ -c .\amiga\crypt.c + +utils: touch.exe mudlib/ar.exe packages/ar.exe mv.bat rm.bat packages/rm.bat mudlib/rm.bat cp.bat + +rm.bat: Win32/rm.bat + copy Win32\rm.bat . + +packages/rm.bat: Win32/rm.bat + copy Win32\rm.bat packages + +mudlib/rm.bat: Win32/rm.bat + copy Win32\rm.bat mudlib + +mv.bat: Win32/mv.bat + copy Win32\mv.bat . + +cp.bat: Win32/cp.bat + copy Win32\cp.bat . + +touch.exe: Win32/touch.c + $(CC) Win32/touch.c + +packages/ar.exe: mudlib/ar.exe + copy mudlib\ar.exe packages + +mudlib/ar.exe: Win32/ar.c + $(CC) -Femudlib/ Win32/ar.c + + +$(OBJDIR)/edit_source.obj: edit_source.c preprocess.c cc.h + +edit_source: edit_source.exe + +edit_source.exe: $(OBJDIR)/edit_source.obj $(OBJDIR)/hash.obj $(OBJDIR)/make_func$(TAB_EXT).obj + $(CC) $(CFLAGS) $(OBJDIR)\edit_source.obj $(OBJDIR)\hash.obj $(OBJDIR)\make_func$(TAB_EXT).obj -Feedit_source.exe + +# don't optimize these two +$(OBJDIR)/edit_source.obj: edit_source.c + $(CC) $(CFLAGS) -Fo$(OBJDIR)\ -c edit_source.c + +$(OBJDIR)/make_func$(TAB_EXT).obj: make_func$(TAB_EXT).c + $(CC) $(CFLAGS) -Fo$(OBJDIR)\ -c make_func$(TAB_EXT).c + +install: all + -mkdir $(INSTALL_DIR) + $(INSTALL) $(DRIVER_BIN).exe $(INSTALL_DIR) + $(INSTALL) addr_server.exe $(INSTALL_DIR) + +Makefiles: utils Makefile.in GNUmakefile.in NMakefile.in + +Makefile.in: edit_source.exe Makefile.in.pre Makefile.master + .\edit_source -process Makefile.in.pre + +GNUmakefile.in: edit_source.exe GNUmakefile.in.pre Makefile.master + .\edit_source -process GNUmakefile.in.pre + +NMakefile.in: edit_source.exe NMakefile.in.pre Makefile.master + .\edit_source -process NMakefile.in.pre + +nothing: + +# remove local configuration +spotless: clean + -rm -f configure.h local_options system_libs configuration + -rm -f options_incl.h + -rm -f *.diffs + -find . -name "*~" -print | xargs rm + -rm -f touch.exe mudlib\ar.exe packages\ar.exe mv.bat packages\rm.bat mudlib\rm.bat cp.bat + del rm.bat + +# get ready for recompile +neat: rm.bat packages/rm.bat mudlib/rm.bat + -cd packages + -$(MAKE) /nologo "O=$(O)" "A=$(A)" clean + -cd.. + -cd mudlib + -$(MAKE) /nologo "O=$(O)" "A=$(A)" clean + -cd.. + -deltree /y $(OBJDIR) + -rm *.obj *$(TAB_EXT).c *$(TAB_EXT).h trash_me.bat *.ilk *.pdb + -rm -f efun_defs.c option_defs.c + -rm -f opcodes.h efunctions.h opc.h efun_protos.h + -rm -f malloc.c mallocwrapper.c + -rm -f func_spec.cpp applies.h applies_table.c files + -rm -f grammar.y comptest* a.out + -rm packages\Makefile packages\GNUmakefile packages\packages + -rm packages\*.pdb mudlib\*.pdb + +# remove everything except configuration +clean: neat + -rm -f cc.h edit_source.exe + -rm core y.output testsuite\core testsuite\single\swapfile.* + -rm testsuite\OPCPROF.* testsuite\opc.* + -echo y | del testsuite\tmp\* + -deltree /y testsuite\binaries + -rm testsuite\OBJ_DUMP* testsuite\test_file testsuite\testfile + -rm testsuite\tmp_eval_file.c testsuite\sf.o testsuite\ed_test + -rm testsuite\log\log testsuite\log\debug.log testsuite\log\compile + -rm -f $(DRIVER_BIN).exe $(DRIVER_BIN).old addr_server.exe +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/fluffos-2.23-ds03/NMakefile.in.pre b/fluffos-2.23-ds03/NMakefile.in.pre new file mode 100644 index 0000000..b8c45f3 --- /dev/null +++ b/fluffos-2.23-ds03/NMakefile.in.pre @@ -0,0 +1,3 @@ +%define NMAKE + +%include "Makefile.master" diff --git a/fluffos-2.23-ds03/Performance b/fluffos-2.23-ds03/Performance new file mode 100644 index 0000000..7134a2a --- /dev/null +++ b/fluffos-2.23-ds03/Performance @@ -0,0 +1,53 @@ +How to make MudOS run as fast as possible on your machine. + +1) use appropriate optimization flags for your compiler. If you are using +gcc 2.3+, then you might want to try the following flags: + +-O2 -fomit-frame-pointer -fstrength-reduce + +Note that some compilers can produce incorrect code at the higher levels of +optimization. If the driver behaves inexplicably, trying lowering the +optimization level. See the Platforms file for more information on +optimization flags for specific platforms. Also type 'man cc' or ask your +system guru if you are interested in finding out optimization flag information +for your particular compiler. + +2) choose an appropriate memory management (malloc) package. Some systems +have very slow system mallocs (like the HP snake on which malloc used 30% +of the CPU time allocated to the MudOS driver (according to gprof) for one +popular mud). Both smalloc and bsdmalloc are much more efficient, typically +using less than 1% of the CPU time allocated to the driver. Note that +smalloc is more space efficient than bsdmalloc (though slightly slower). + +3) Try to make your mudlib as memory efficient as possible. Include +clean_up() functions in your objects whenever reasonable and remember +to use map_delete() to remove elements from mappings when those elements +are no longer needed. Also take a look at the reclaim_objects() and +reload_object() efuns for saving memory. Don't use array addition +any more than necessary (especially try not to use it inside a loop +for building arrays). + +4) Do _not_ define TRACE_CODE in options.h. TRACE_CODE can be useful +when debugging code but it slows down most simple LPC instructions (in +eval_instruction()) by a factor of two. + +5) Don't give objects heartbeats (set_heart_beat(1)) unless really +necessary. Do as little in heart_beat() functions as reasonable. +Consider turning off heartbeats when not needed and then restarting +them when again needed. + +6) Read the comments in the example config file about hash table size, and +object hash table size--setting proper (large enough) values for these +two hash tables greatly increases overall speed. + +7) The opcprof() efun can be used to find out which efunctions are being used +the most. Rewriting mudlib code that makes extensive use of expensive efuns +can improve performance somewhat. In order to find out which efuns are +expensive, compile the driver with the profiling flags (-pg if using gcc) +and produce a gmon.out file. This file can be processed with the gprof +command to find out the percentage of cpu time spent in various different +driver functions. + +8) try using the time_expression(expr) function to measure the cpu time used +by various different expressions (time_expression uses the same syntax as +catch()). diff --git a/fluffos-2.23-ds03/Platforms b/fluffos-2.23-ds03/Platforms new file mode 100644 index 0000000..e2681d1 --- /dev/null +++ b/fluffos-2.23-ds03/Platforms @@ -0,0 +1,37 @@ +MudOS v22.2 should compile and run on the following systems: + +DEC Alpha (OSF/1 1.2) +NeXTstation/NeXTcube (NeXT 2.1 and 3.0, 3.1, 3.2) +RS/6000 (AIX 3.x, 4.x) +Sun3 (SunOS) +Sun4 (SunOS 4.x) +Sun4 (SunOS 5.x) +DECstation 2100/3100/5000 (Ultrix 3.1, 4.x) +VAX (Ultrix) +HP Apollo +HP PA-RISC (HP-UX 7.x, 8.x, 9.0x) +HP 68k Motorola (HP-UX) +HP 68k Motorola (BSD 4.3) +Silicon Graphics Indigo, 4D/x and RS4000 Series (IRIX release 4.0.5F, 5.2, 5.3) +Sequent Symmetry (DYNIX/ptx 1.4, 2.0) +Mac Quadra (A/UX 3.0) +Ridge (RISC/os) +IBM PC (Linux 2.2.x and higher) +IBM PC (System V Release 4) +IBM PC (NetBSD, FreeBSD, 386BSD, etc.) +IBM PC (Windows 95/NT using Visual C++; see the windows/ subdirectory) +Macintosh OS X (Darwin) + +*Send mail to marius@mudos.org if you experience any problems +compiling or running on these systems. Note that some of these machines have +old versions of yacc and do require bison (a yacc replacement) to compile +MudOS correctly. If you manage to compile and run MudOS on a system other +than one listed here, please send the diffs along with machine and OS +information to the mudos-bugs address. + +NOTE: MudOS is NOT officially supported on Windows 95/98/NT/2K. If you can get +it to work, great. If not, too bad. Official support will be forthcoming in +v23. + +MSDOS versions of MudOS are available in the /pub/mud/servers/lpc/mudos/msdos +directory on ftp.ccs.neu.edu. diff --git a/fluffos-2.23-ds03/README b/fluffos-2.23-ds03/README new file mode 100644 index 0000000..f1de9e9 --- /dev/null +++ b/fluffos-2.23-ds03/README @@ -0,0 +1,69 @@ +MudOS is an LPmud server (driver) which was originally distributed as an +enhanced version of the LPmud 3.x driver. It does not support COMPAT mode, +but a number of newer mudlibs are available. + +This is the source (src) directory from the MudOS v21.x distribution. + +Minor releases of MudOS (those with a minor version number after the decimal, +e.g. v20.26) are typically released without installation +instructions, usage instructions, documentation, or other supporting +material (since the size of this other material is fairly large). Releases +of MudOS with version numbers having only one component (e.g. v21) will +be released as a combined source/documentation package (e.g. +MudOS_v21.tar.Z which is the most recent such release) + +The minor releases are intended for those who are already familiar with +installing and running MudOS. These fix bugs in older drivers and introduce +new features. + +Alpha and beta versions of future versions are available only in the form +of patches. + +Typically, only those interested in testing for bugs or in being on the +bleeding edge need install the alpha/beta releases. + +When deciding to upgrade, be sure to read the ChangeLog file in the same +directory as this README to find out about the latest changes to MudOS. +In the case of alpha and beta releases, also check out ChangeLog.alpha +and ChangeLog.beta. +In particular, note the changes marked "compat buster" since these describe +changes to the driver which may cause pre-existing mudlibs (such as Lil) +to break in some minor fashion (the ChangeLog should give enough information +to allow affected mudlibs to be fixed). + +Notes: + +The official support site for MudOS is http://www.mudos.org/ + +If you believe that you have found a bug in MudOS that is not listed in the +Bugs file, please visit the support site and check through the existing bugs +in the bug database to see if someone else has reported your bug. If nobody +has reported the bug, please submit a bug report. Please try to include as +much information as you possibly can about the bug. If you can provide +details on how to reproduce the problem, that's the best kind of information +you can give. If the driver has crashed, read the file IT_CRASHED included +in this distribution to find out how to collect information for reporting +your crash. + +The 'addr_server' file replaces the old hname program. Unlike hname, +addr_server must be started up manually (it takes a single argument which +is the port # the addr_server should listen on -- this port # must also be +specified in the runtime config file). If addr_server doesn't work on your +machine, its okay to run the driver without it (just set your config file +up to point to someone else's addr_server). + +If the driver errors out at runtime with a message saying that the +operation is not supported on the socket, then try using cc instead of gcc +(assuming you were using gcc). Alternatively, try uncommenting +NEED_OLD_CPP in the Makefile and then 'make clean' and 'make'. + +For more information about LPmuds and MUDs in general try reading +the USENET groups rec.games.mud.{admin,announce,misc,lp,tiny,diku}. + +On subdirectories: + +amiga/ Contains amiga support files; a crypt package is also + provided for systems missing DES crypt() +include/ Useful #defines for the mudlib to have access to (used by + various efuns) +packages/ This is where efun packages and user efuns should reside diff --git a/fluffos-2.23-ds03/Version b/fluffos-2.23-ds03/Version new file mode 100644 index 0000000..8acff63 --- /dev/null +++ b/fluffos-2.23-ds03/Version @@ -0,0 +1 @@ +MudOS v22.2 beta diff --git a/fluffos-2.23-ds03/Win32/ar.c b/fluffos-2.23-ds03/Win32/ar.c new file mode 100644 index 0000000..1ef2021 --- /dev/null +++ b/fluffos-2.23-ds03/Win32/ar.c @@ -0,0 +1,26 @@ +#include +#include +#include + +#define MAX_LEN 1024 + +int main(int argc, char *argv[]) { + char command[MAX_LEN]; + int i; + + if (strcmp(argv[1], "rcu")) + return -1; + if (!strstr(argv[2], ".lib")) + return -1; + strcpy(command, "lib "); + for (i = 3; i < argc; i++) { + if (!strstr(argv[i], ".obj")) + return -1; + strcat(command, argv[i]); + strcat(command, " "); + } + strcat(command, "/OUT:"); + strcat(command, argv[2]); + system(command); + return 0; +} diff --git a/fluffos-2.23-ds03/Win32/configure.h b/fluffos-2.23-ds03/Win32/configure.h new file mode 100644 index 0000000..79538fd --- /dev/null +++ b/fluffos-2.23-ds03/Win32/configure.h @@ -0,0 +1,17 @@ +#define INCL_STDLIB_H +#define INCL_TIME_H +#define INCL_FCNTL_H +#define INCL_DOS_H +#define INCL_LIMITS_H +#define USE_STRUCT_DIRENT +#define INCL_SYS_STAT_H +#define INCL_STDARG_H +#define HAS_MEMMOVE +#define RAND +#define HAS_STRERROR +#define HAS_GETCWD + +#define CONST const +#define INLINE +#define UINT32 unsigned long +#define UINT32 unsigned long diff --git a/fluffos-2.23-ds03/Win32/cp.bat b/fluffos-2.23-ds03/Win32/cp.bat new file mode 100644 index 0000000..fac204e --- /dev/null +++ b/fluffos-2.23-ds03/Win32/cp.bat @@ -0,0 +1,10 @@ +@echo off +:loop +if "%1" == "-f" shift +if "%1" == "." shift +if "%1" == ".." shift +if "%1x" == "x" goto end +copy %1 +shift +goto loop +:end diff --git a/fluffos-2.23-ds03/Win32/mv.bat b/fluffos-2.23-ds03/Win32/mv.bat new file mode 100644 index 0000000..0247a87 --- /dev/null +++ b/fluffos-2.23-ds03/Win32/mv.bat @@ -0,0 +1,3 @@ +@echo off +if "%1" == "-f" shift +move %1 %2 diff --git a/fluffos-2.23-ds03/Win32/rm.bat b/fluffos-2.23-ds03/Win32/rm.bat new file mode 100644 index 0000000..6bf990a --- /dev/null +++ b/fluffos-2.23-ds03/Win32/rm.bat @@ -0,0 +1,8 @@ +@echo off +:loop +if "%1x" == "x" goto end +if "%1" == "-f" shift +del %1 >nul +shift +goto loop +:end diff --git a/fluffos-2.23-ds03/Win32/touch.c b/fluffos-2.23-ds03/Win32/touch.c new file mode 100644 index 0000000..73747f7 --- /dev/null +++ b/fluffos-2.23-ds03/Win32/touch.c @@ -0,0 +1,19 @@ +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + int i, handle; + + for (i = 1; i <= argc; i++) { + if (access(argv[i], 0) == -1) { + handle = open(argv[i], _O_RDWR | _O_CREAT, _S_IREAD | _S_IWRITE); + close(handle); + } else { + utime(argv[i], NULL); + } + } + return 0; +} diff --git a/fluffos-2.23-ds03/add_action.c b/fluffos-2.23-ds03/add_action.c new file mode 100644 index 0000000..0e463f9 --- /dev/null +++ b/fluffos-2.23-ds03/add_action.c @@ -0,0 +1,758 @@ +#include "std.h" +#include "comm.h" +#include "backend.h" +#include "add_action.h" +#include "eval.h" +#ifndef NO_ADD_ACTION + +#define MAX_VERB_BUFF 100 + +object_t * hashed_living[CFG_LIVING_HASH_SIZE] = { 0 }; + +static int num_living_names; +static int num_searches = 1; +static int search_length = 1; +static int illegal_sentence_action; +static char * last_verb; +static object_t * illegal_sentence_ob; + +static void notify_no_command (void) +{ + union string_or_func p; + svalue_t *v; + + if (!command_giver || !command_giver->interactive) + return; + p = command_giver->interactive->default_err_message; + if (command_giver->interactive->iflags & NOTIFY_FAIL_FUNC) { + save_command_giver(command_giver); + v = call_function_pointer(p.f, 0); + restore_command_giver(); + free_funp(p.f); + if (command_giver && command_giver->interactive) { + if (v && v->type == T_STRING) { + tell_object(command_giver, v->u.string, SVALUE_STRLEN(v)); + } + command_giver->interactive->iflags &= ~NOTIFY_FAIL_FUNC; + command_giver->interactive->default_err_message.s = 0; + } + } else { + if (p.s) { + tell_object(command_giver, p.s, strlen(p.s)); + free_string(p.s); + command_giver->interactive->default_err_message.s = 0; + } else { + tell_object(command_giver, default_fail_message, strlen(default_fail_message)); + } + } +} + +void clear_notify (object_t * ob) +{ + union string_or_func dem; + interactive_t *ip = ob->interactive; + + dem = ip->default_err_message; + if (ip->iflags & NOTIFY_FAIL_FUNC) { + free_funp(dem.f); + ip->iflags &= ~NOTIFY_FAIL_FUNC; + } + else if (dem.s) + free_string(dem.s); + ip->default_err_message.s = 0; +} + +INLINE_STATIC int hash_living_name (const char *str) +{ + return whashstr(str) & (CFG_LIVING_HASH_SIZE - 1); +} + +object_t *find_living_object (const char* str, int user) +{ + object_t **obp, *tmp; + object_t **hl; + + if (!str) + return 0; + num_searches++; + hl = &hashed_living[hash_living_name(str)]; + for (obp = hl; *obp; obp = &(*obp)->next_hashed_living) { + search_length++; +#ifdef F_SET_HIDE + if ((*obp)->flags & O_HIDDEN) { + if (!valid_hide(current_object)) + continue; + } +#endif + if (user && !((*obp)->flags & O_ONCE_INTERACTIVE)) + continue; + if (!((*obp)->flags & O_ENABLE_COMMANDS)) + continue; + if (strcmp((*obp)->living_name, str) == 0) + break; + } + if (*obp == 0) + return 0; + /* Move the found ob first. */ + if (obp == hl) + return *obp; + tmp = *obp; + *obp = tmp->next_hashed_living; + tmp->next_hashed_living = *hl; + *hl = tmp; + return tmp; +} + +void remove_living_name (object_t * ob) +{ + object_t **hl; + + ob->flags &= ~O_ENABLE_COMMANDS; + if (!ob->living_name) + return; + + num_living_names--; + DEBUG_CHECK(!ob->living_name, "remove_living_name: no living name set.\n"); + hl = &hashed_living[hash_living_name(ob->living_name)]; + while (*hl) { + if (*hl == ob) + break; + hl = &(*hl)->next_hashed_living; + } + DEBUG_CHECK1(*hl == 0, + "remove_living_name: Object named %s no in hash list.\n", + ob->living_name); + *hl = ob->next_hashed_living; + free_string(ob->living_name); + ob->next_hashed_living = 0; + ob->living_name = 0; +} + +static void set_living_name (object_t * ob, const char *str) +{ + int flags = ob->flags & O_ENABLE_COMMANDS; + object_t **hl; + + if (ob->flags & O_DESTRUCTED) + return; + remove_living_name(ob); + num_living_names++; + hl = &hashed_living[hash_living_name(str)]; + ob->next_hashed_living = *hl; + *hl = ob; + ob->living_name = make_shared_string(str); + ob->flags |= flags; +} + +void stat_living_objects (outbuffer_t * out) +{ + outbuf_add(out, "Hash table of living objects:\n"); + outbuf_add(out, "-----------------------------\n"); + outbuf_addv(out, "%d living named objects, average search length: %4.2f\n\n", + num_living_names, (double) search_length / num_searches); +} + +void setup_new_commands (object_t * dest, object_t * item) +{ + object_t *next_ob, *ob; + + /* + * Setup the new commands. The order is very important, as commands in + * the room should override commands defined by the room. Beware that + * init() in the room may have moved 'item' ! + * + * The call of init() should really be done by the object itself (except in + * the -o mode). It might be too slow, though :-( + */ + if (item->flags & O_ENABLE_COMMANDS) { + save_command_giver(item); + (void) apply(APPLY_INIT, dest, 0, ORIGIN_DRIVER); + restore_command_giver(); + if (item->super != dest) + return; + } + /* + * Run init of the item once for every present user, and for the + * environment (which can be a user). + */ + for (ob = dest->contains; ob; ob = next_ob) { + next_ob = ob->next_inv; + if (ob == item) + continue; + if (ob->flags & O_DESTRUCTED) + error("An object was destructed at call of " APPLY_INIT "()\n"); + if (ob->flags & O_ENABLE_COMMANDS) { + save_command_giver(ob); + (void) apply(APPLY_INIT, item, 0, ORIGIN_DRIVER); + restore_command_giver(); + if (dest != item->super) + return; + } + if (item->flags & O_DESTRUCTED) /* marion */ + error("The object to be moved was destructed at call of " APPLY_INIT "()\n"); + if (ob->flags & O_DESTRUCTED) /* Alaron */ + error("An object was destructed at call of " APPLY_INIT "()\n"); + if (item->flags & O_ENABLE_COMMANDS) { + save_command_giver(item); + (void) apply(APPLY_INIT, ob, 0, ORIGIN_DRIVER); + restore_command_giver(); + if (dest != item->super) + return; + } + } + if (dest->flags & O_DESTRUCTED) /* marion */ + error("The destination to move to was destructed at call of " APPLY_INIT "()\n"); + if (item->flags & O_DESTRUCTED) /* Alaron */ + error("The object to be moved was destructed at call of " APPLY_INIT "()\n"); + if (dest->flags & O_ENABLE_COMMANDS) { + save_command_giver(dest); + (void) apply(APPLY_INIT, item, 0, ORIGIN_DRIVER); + restore_command_giver(); + } +} + +/* + * This will enable an object to use commands normally only + * accessible by interactive users. + * Also check if the user is a wizard. Wizards must not affect the + * value of the wizlist ranking. + */ +static void enable_commands (int num) +{ +#ifndef NO_ENVIRONMENT + object_t *pp; +#endif + + if (current_object->flags & O_DESTRUCTED) + return; + + debug(d_flag, ("Enable commands /%s (ref %d)", + current_object->obname, current_object->ref)); + + if (num) { + current_object->flags |= O_ENABLE_COMMANDS; + set_command_giver(current_object); + } else { +#ifndef NO_ENVIRONMENT + /* Remove all sentences defined for the object */ + if (current_object->flags & O_ENABLE_COMMANDS) { + if (current_object->super) { + remove_sent(current_object->super, current_object); + for (pp = current_object->super->contains; pp; pp = pp->next_inv) + remove_sent(pp, current_object); + } + for (pp = current_object->contains; pp; pp = pp->next_inv) + remove_sent(pp, current_object); + } +#endif + current_object->flags &= ~O_ENABLE_COMMANDS; + if (current_object == command_giver) + set_command_giver(0); + } +} + +/* + * Find the sentence for a command from the user. + * Return success status. + */ + +static int user_parser (char * buff) +{ + char verb_buff[MAX_VERB_BUFF]; + sentence_t *s; + char *p; + int length; + char *user_verb = 0; + int where; + int save_illegal_sentence_action; + + debug(d_flag, ("cmd [/%s]: %s\n", command_giver->obname, buff)); + + /* strip trailing spaces. */ + for (p = buff + strlen(buff) - 1; p >= buff; p--) { + if (*p != ' ') + break; + *p = '\0'; + } + if (buff[0] == '\0') + return 0; + length = p - buff + 1; + p = strchr(buff, ' '); + if (p == 0) { + user_verb = findstring(buff); + } else { + *p = '\0'; + user_verb = findstring(buff); + *p = ' '; + length = p - buff; + } + if (!user_verb) { + /* either an xverb or a verb without a specific add_action */ + user_verb = buff; + } + /* + * copy user_verb into a static character buffer to be pointed to by + * last_verb. + */ + strncpy(verb_buff, user_verb, MAX_VERB_BUFF - 1); + if (p) { + int pos; + + pos = p - buff; + if (pos < MAX_VERB_BUFF) { + verb_buff[pos] = '\0'; + } + } + + save_illegal_sentence_action = illegal_sentence_action; + illegal_sentence_action = 0; + for (s = command_giver->sent; s; s = s->next) { + svalue_t *ret; + object_t *command_object; + + if (s->flags & (V_NOSPACE | V_SHORT)) { + if (strncmp(buff, s->verb, strlen(s->verb)) != 0) + continue; + } else { + /* note: if was add_action(blah, "") then accept it */ + if (s->verb[0] && (user_verb != s->verb)) + continue; + } + /* + * Now we have found a special sentence ! + */ + + if (!(s->flags & V_FUNCTION)) + debug(d_flag, ("Local command %s on /%s", + s->function.s, s->ob->obname)); + + if (s->flags & V_NOSPACE) { + int l1 = strlen(s->verb); + int l2 = strlen(verb_buff); + + if (l1 < l2) + last_verb = verb_buff + l1; + else + last_verb = ""; + } else { + if (!s->verb[0] || (s->flags & V_SHORT)) + last_verb = verb_buff; + else + last_verb = s->verb; + } + /* + * If the function is static and not defined by current object, then + * it will fail. If this is called directly from user input, then + * the origin is the driver and it will be allowed. + */ + where = (current_object ? ORIGIN_EFUN : ORIGIN_DRIVER); + + /* + * Remember the object, to update moves. + */ + command_object = s->ob; + save_command_giver(command_giver); + if (s->flags & V_NOSPACE) { + copy_and_push_string(&buff[strlen(s->verb)]); + } else if (buff[length] == ' ') { + copy_and_push_string(&buff[length + 1]); + } else { + push_undefined(); + } + if (s->flags & V_FUNCTION) { + ret = call_function_pointer(s->function.f, 1); + } else { + if (s->function.s[0] == APPLY___INIT_SPECIAL_CHAR) + error("Illegal function name.\n"); + ret = apply(s->function.s, s->ob, 1, where); + } + /* s may be dangling at this point */ + + restore_command_giver(); + + last_verb = 0; + + /* was this the right verb? */ + if (ret == 0) { + /* is it still around? Otherwise, ignore this ... + it moved somewhere or dested itself */ + if (s == command_giver->sent) { + char buf[256]; + if (s->flags & V_FUNCTION) { + sprintf(buf, "Verb '%s' bound to uncallable function pointer.\n", s->verb); + error(buf); + } else { + sprintf(buf, "Function for verb '%s' not found.\n", + s->verb); + error(buf); + } + } + } + + if (ret && (ret->type != T_NUMBER || ret->u.number != 0)) { +#ifdef PACKAGE_MUDLIB_STATS + if (command_giver && command_giver->interactive +#ifndef NO_WIZARDS + && !(command_giver->flags & O_IS_WIZARD) +#endif + ) + add_moves(&command_object->stats, 1); +#endif + if (!illegal_sentence_action) + illegal_sentence_action = save_illegal_sentence_action; + return 1; + } + if (illegal_sentence_action) { + switch (illegal_sentence_action) { + case 1: + error("Illegal to call remove_action() [caller was /%s] from a verb returning zero.\n", illegal_sentence_ob->obname); + case 2: + error("Illegal to move or destruct an object (/%s) defining actions from a verb function which returns zero.\n", illegal_sentence_ob->obname); + } + } + } + notify_no_command(); + illegal_sentence_action = save_illegal_sentence_action; + + return 0; +} + +/* + * Take a user command and parse it. + * The command can also come from a NPC. + * Beware that 'str' can be modified and extended ! + */ +int parse_command (char * str, object_t * ob) +{ + int res; + + /* disallow users to issue commands containing ansi escape codes */ +#if defined(NO_ANSI) && !defined(STRIP_BEFORE_PROCESS_INPUT) + char *c; + + for (c = str; *c; c++) { + if (*c == 27) { + *c = ' '; /* replace ESC with ' ' */ + } + } +#endif + + save_command_giver(ob); + res = user_parser(str); + restore_command_giver(); + + return res; +} + +/* + * Associate a command with function in this object. + * + * The optinal third argument is a flag that will state that the verb should + * only match against leading characters. + * + * The object must be near the command giver, so that we ensure that the + * sentence is removed when the command giver leaves. + * + * If the call is from a shadow, make it look like it is really from + * the shadowed object. + */ +static void add_action (svalue_t * str, const char *cmd, int flag) +{ + sentence_t *p; + object_t *ob; + + if (current_object->flags & O_DESTRUCTED) + return; + ob = current_object; +#ifndef NO_SHADOWS + while (ob->shadowing) { + ob = ob->shadowing; + } + /* don't allow add_actions of a static function from a shadowing object */ + if ((ob != current_object) && str->type == T_STRING && is_static(str->u.string, ob)) { + return; + } +#endif + if (command_giver == 0 || (command_giver->flags & O_DESTRUCTED)) + return; + if (ob != command_giver +#ifndef NO_ENVIRONMENT + && ob->super != command_giver && + ob->super != command_giver->super && ob != command_giver->super +#endif + ) + return; /* No need for an error, they know what they + * did wrong. */ + p = alloc_sentence(); + if (str->type == T_STRING) { + debug(d_flag, ("--Add action %s", str->u.string)); + p->function.s = make_shared_string(str->u.string); + p->flags = flag; + } else { + debug(d_flag, ("--Add action ")); + + p->function.f = str->u.fp; + str->u.fp->hdr.ref++; + p->flags = flag | V_FUNCTION; + } + p->ob = ob; + p->verb = make_shared_string(cmd); + /* This is ok; adding to the top of the list doesn't harm anything */ + p->next = command_giver->sent; + command_giver->sent = p; +} + +/* + * Remove sentence with specified verb and action. Return 1 + * if success. If command_giver, remove his action, otherwise + * remove current_object's action. + */ +static int remove_action (const char *act, const char *verb) +{ + object_t *ob; + sentence_t **s; + + if (command_giver) + ob = command_giver; + else + ob = current_object; + + if (ob) { + for (s = &ob->sent; *s; s = &((*s)->next)) { + sentence_t *tmp; + + if (((*s)->ob == current_object) && (!((*s)->flags & V_FUNCTION)) + && !strcmp((*s)->function.s, act) + && !strcmp((*s)->verb, verb)) { + tmp = *s; + *s = tmp->next; + free_sentence(tmp); + illegal_sentence_action = 1; + illegal_sentence_ob = current_object; + return 1; + } + } + } + return 0; +} + +/* + * Remove all commands (sentences) defined by object 'ob' in object + * 'user' + */ +#ifndef NO_ENVIRONMENT +void remove_sent (object_t * ob, object_t * user) +{ + sentence_t **s; + + if (!(user->flags & O_ENABLE_COMMANDS)) + return; + + for (s = &user->sent; *s;) { + sentence_t *tmp; + + if ((*s)->ob == ob) { +#ifdef DEBUG + if (!((*s)->flags & V_FUNCTION)) + debug(d_flag, ("--Unlinking sentence %s\n", (*s)->function.s)); +#endif + + tmp = *s; + *s = tmp->next; + free_sentence(tmp); + illegal_sentence_action = 2; + illegal_sentence_ob = ob; + } else + s = &((*s)->next); + } +} +#endif + +#ifdef F_ADD_ACTION +void +f_add_action (void) +{ + long flag; + + if (st_num_arg == 3) { + flag = (sp--)->u.number; + } else flag = 0; + + if (sp->type == T_ARRAY) { + int i, n = sp->u.arr->size; + svalue_t *sv = sp->u.arr->item; + + for (i = 0; i < n; i++) { + if (sv[i].type == T_STRING) { + add_action(sp-1, sv[i].u.string, flag & 3); + } + } + free_array((sp--)->u.arr); + } else { + add_action((sp-1), sp->u.string, flag & 3); + free_string_svalue(sp--); + } + pop_stack(); +} +#endif + +#ifdef F_COMMAND +/* + * Execute a command for an object. Copy the command into a + * new buffer, because 'parse_command()' can modify the command. + * If the object is not current object, static functions will not + * be executed. This will prevent forcing users to do illegal things. + * + * Return cost of the command executed if success (> 0). + * When failure, return 0. + */ +void f_command (void) +{ + long rc = 0; + + if (current_object && !(current_object->flags & O_DESTRUCTED)) + { + char buff[1000]; + int save_eval_cost = get_eval(); + + if (SVALUE_STRLEN(sp) > sizeof(buff) - 1) + error("Too long command.\n"); + + strncpy(buff, sp->u.string, sizeof(buff)); + buff[sizeof(buff) - 1] = 0; + + if (parse_command(buff, current_object)) +#ifndef WIN32 + rc = save_eval_cost - get_eval(); +#else + rc = 1; +#endif + } + + free_string_svalue(sp); + put_number(rc); +} +#endif + +#ifdef F_COMMANDS +void f_commands (void) +{ + push_refed_array(commands(current_object)); +} +#endif + +#ifdef F_DISABLE_COMMANDS +void f_disable_commands (void) +{ + enable_commands(0); +} +#endif + +#ifdef F_ENABLE_COMMANDS +void f_enable_commands (void) +{ + enable_commands(1); +} +#endif + +#ifdef F_FIND_LIVING +void f_find_living (void) +{ + object_t *ob; + + ob = find_living_object(sp->u.string, 0); + free_string_svalue(sp); + /* safe b/c destructed objects have had their living names removed */ + if (ob) { + put_unrefed_undested_object(ob, "find_living"); + } else { + *sp = const0; + } +} +#endif + +#ifdef F_FIND_PLAYER +void f_find_player (void) +{ + object_t *ob; + + ob = find_living_object(sp->u.string, 1); + free_string_svalue(sp); + /* safe b/c destructed objects have had their living names removed */ + if (ob) { + put_unrefed_undested_object(ob, "find_living"); + } else { + *sp = const0; + } +} +#endif + +#ifdef F_LIVING +void f_living (void) +{ + if (sp->u.ob->flags & O_ENABLE_COMMANDS) { + free_object(&sp->u.ob, "f_living:1"); + *sp = const1; + } else { + free_object(&sp->u.ob, "f_living:2"); + *sp = const0; + } +} +#endif + +#ifdef F_LIVINGS +void f_livings (void) +{ + push_refed_array(livings()); +} +#endif + +#ifdef F_NOTIFY_FAIL +void f_notify_fail (void) +{ + if (command_giver && command_giver->interactive) { + clear_notify(command_giver); + if (sp->type == T_STRING) { + command_giver->interactive->default_err_message.s = make_shared_string(sp->u.string); + } else { + command_giver->interactive->iflags |= NOTIFY_FAIL_FUNC; + command_giver->interactive->default_err_message.f = sp->u.fp; + sp->u.fp->hdr.ref++; + } + } + pop_stack(); +} +#endif + +#ifdef F_QUERY_VERB +void f_query_verb (void) +{ + if (!last_verb) { + push_number(0); + return; + } + share_and_push_string(last_verb); +} +#endif + +#ifdef F_REMOVE_ACTION +void f_remove_action (void) +{ + long success; + + success = remove_action((sp - 1)->u.string, sp->u.string); + free_string_svalue(sp--); + free_string_svalue(sp); + put_number(success); +} +#endif + +#ifdef F_SET_LIVING_NAME +void f_set_living_name (void) +{ + set_living_name(current_object, sp->u.string); + free_string_svalue(sp--); +} +#endif + +#endif /* ! NO_ADD_ACTION */ diff --git a/fluffos-2.23-ds03/add_action.h b/fluffos-2.23-ds03/add_action.h new file mode 100644 index 0000000..a0614ab --- /dev/null +++ b/fluffos-2.23-ds03/add_action.h @@ -0,0 +1,26 @@ +#ifndef ADD_ACTION_H +#define ADD_ACTION_H 1 + +#ifndef NO_ADD_ACTION +extern object_t *hashed_living[CFG_LIVING_HASH_SIZE]; + +int parse_command (char *, object_t *); +void clear_notify (object_t *); +void stat_living_objects (outbuffer_t *); +void remove_living_name (object_t *); +object_t * find_living_object (const char *, int); +void setup_new_commands (object_t *, object_t *); +#ifndef NO_ENVIRONMENT +void remove_sent (object_t *, object_t *); +#endif +#else +/* STUBS */ +#define parse_command(x, y) do{}while(0) +#define clear_notify(x) do{}while(0) +#define stat_living_objects(x) do{}while(0) +#define remove_living_name(x) do{}while(0) +#define remove_sent(x, y) do{}while(0) +#define setup_new_commands(x, y) do{}while(0) +#endif + +#endif /* ADD_ACTION_H */ diff --git a/fluffos-2.23-ds03/addr_server.c b/fluffos-2.23-ds03/addr_server.c new file mode 100644 index 0000000..ba8639c --- /dev/null +++ b/fluffos-2.23-ds03/addr_server.c @@ -0,0 +1,682 @@ +/* + * addr_server.c -- socket-based ip address server. + * 8-92 : Dwayne Fontenot : original coding + */ + +#include "std.h" +#include "addr_server.h" +#include "socket_ctrl.h" +#include "file_incl.h" +#include "port.h" + +#ifdef MINGW +#include +#endif + +#ifdef DEBUG_MACRO +int debug_level = DBG_addr_server; +#endif /* DEBUG_MACRO */ + +#define DBG(x) debug(addr_server, x) + +/* + * private local variables. + */ +static connection all_conns[MAX_CONNS]; +static int total_conns = 0; +static queue_element_ptr queue_head = NULL; +static queue_element_ptr queue_tail = NULL; +static queue_element_ptr stack_head = NULL; +static int queue_length = 0; +static int conn_fd; + +fd_set readmask; + +int name_by_ip (int, char *); +int ip_by_name (int, char *); +INLINE_STATIC void process_queue (void); +void init_conns (void); +void init_conn_sock (int, char *); + +#ifdef SIGNAL_FUNC_TAKES_INT +void sigpipe_handler (int); +#else +void sigpipe_handler (void); +#endif + +INLINE void aserv_process_io (int); +void enqueue_datapending (int, int); +void handle_top_event (void); +void dequeue_top_event (void); +void pop_queue_element (queue_element_ptr *); +void push_queue_element (queue_element_ptr); +void new_conn_handler (void); +void conn_data_handler (int); +int index_by_fd (int); +void terminate (int); + +void debug_perror (const char *, const char *); + +void debug_perror (const char * what, const char * file) { + if (file) + fprintf(stderr, "System Error: %s:%s:%s\n", what, file, port_strerror(errno)); + else + fprintf(stderr, "System Error: %s:%s\n", what, port_strerror(errno)); +} + +void init_conns() +{ + int i; + + for (i = 0; i < MAX_CONNS; i++) { + all_conns[i].fd = -1; + all_conns[i].state = CONN_CLOSED; + all_conns[i].sname[0] = '\0'; + + /* ensure 'leftover' buffer is _always_ null terminated */ + all_conns[i].buf[0] = '\0'; + all_conns[i].buf[IN_BUF_SIZE - 1] = '\0'; + all_conns[i].leftover = 0; + } +} + +/* + * Initialize connection socket. + */ +void init_conn_sock (int port_num, char * ipaddress) +{ +#ifdef IPV6 + struct sockaddr_in6 sin; +#else + struct sockaddr_in sin; +#endif + socklen_t sin_len; + int optval; +#ifdef WINSOCK + WSADATA WSAData; + + WSAStartup(MAKEWORD(1,1), &WSAData); + atexit(cleanup_sockets); +#endif + + /* + * create socket of proper type. + */ +#ifdef IPV6 + if ((conn_fd = socket(AF_INET6, SOCK_STREAM, 0)) == INVALID_SOCKET) { +#else + if ((conn_fd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { +#endif + socket_perror("init_conn_sock: socket", 0); + exit(1); + } + /* + * enable local address reuse. + */ + optval = 1; + if (setsockopt(conn_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &optval, + sizeof(optval)) == -1) { + socket_perror("init_conn_sock: setsockopt", 0); + exit(2); + } + /* + * fill in socket address information. + */ +#ifdef IPV6 + sin.sin6_family = AF_INET6; + if(ipaddress) + inet_pton(AF_INET6, ipaddress, &(sin.sin6_addr)); + else + sin.sin6_addr = in6addr_any; + sin.sin6_port = htons((u_short) port_num); +#else + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = (ipaddress ? inet_addr(ipaddress) : INADDR_ANY); + sin.sin_port = htons((u_short) port_num); +#endif + /* + * bind name to socket. + */ + if (bind(conn_fd, (struct sockaddr *) & sin, sizeof(sin)) == -1) { + socket_perror("init_conn_sock: bind", 0); + exit(3); + } + /* + * get socket name. + */ + sin_len = sizeof(sin); + if (getsockname(conn_fd, (struct sockaddr *) & sin, &sin_len) == -1) { + socket_perror("init_conn_sock: getsockname", 0); + exit(4); + } + /* + * register signal handler for SIGPIPE. + */ +#if defined(SIGPIPE) && defined(SIGNAL_ERROR)/* windows has no SIGPIPE */ + if (signal(SIGPIPE, sigpipe_handler) == SIGNAL_ERROR) { + socket_perror("init_conn_sock: signal SIGPIPE", 0); + exit(5); + } +#endif + /* + * set socket non-blocking + */ + if (set_socket_nonblocking(conn_fd, 1) == -1) { + socket_perror("init_conn_sock: set_socket_nonblocking 1", 0); + exit(8); + } + /* + * listen on socket for connections. + */ + if (listen(conn_fd, 128) == -1) { + socket_perror("init_conn_sock: listen", 0); + exit(10); + } + DBG(("listening for connections on port %d", port_num)); +} + +/* + * SIGPIPE handler -- does very little for now. + */ +#ifdef SIGNAL_FUNC_TAKES_INT +void sigpipe_handler (int sig) +{ +#else +void sigpipe_handler() +{ +#endif + fprintf(stderr, "SIGPIPE received.\n"); +} + +/* + * I/O handler. + */ +INLINE void aserv_process_io (int nb) +{ + int i; + + switch (nb) { + case -1: + debug_perror("sigio_handler: select", 0); + break; + case 0: + break; + default: + /* + * check for new connection. + */ + if (FD_ISSET(conn_fd, &readmask)) { + DBG(("sigio_handler: NEW_CONN")); + enqueue_datapending(conn_fd, NEW_CONN); + } + /* + * check for data pending on established connections. + */ + for (i = 0; i < MAX_CONNS; i++) { + if (FD_ISSET(all_conns[i].fd, &readmask)) { + DBG(("sigio_handler: CONN")); + enqueue_datapending(all_conns[i].fd, CONN); + } + } + break; + } +} + +INLINE_STATIC void process_queue() +{ + int i; + + for (i = 0; queue_head && (i < MAX_EVENTS_TO_PROCESS); i++) { + handle_top_event(); + dequeue_top_event(); + } +} + +void enqueue_datapending (int fd, int fd_type) +{ + queue_element_ptr new_queue_element; + + pop_queue_element(&new_queue_element); + new_queue_element->event_type = fd_type; + new_queue_element->fd = fd; + new_queue_element->next = NULL; + if (queue_head) { + queue_tail->next = new_queue_element; + } else { + queue_head = new_queue_element; + } + queue_tail = new_queue_element; +} + +void dequeue_top_event() +{ + queue_element_ptr top_queue_element; + + if (queue_head) { + top_queue_element = queue_head; + queue_head = queue_head->next; + push_queue_element(top_queue_element); + } else { + fprintf(stderr, "dequeue_top_event: tried to dequeue from empty queue!\n"); + } +} + +void pop_queue_element (queue_element_ptr * the_queue_element) +{ + if ((*the_queue_element = stack_head)) + stack_head = stack_head->next; + else + *the_queue_element = (queue_element_ptr) malloc(sizeof(queue_element)); + queue_length++; +} + +void push_queue_element (queue_element_ptr the_queue_element) +{ + the_queue_element->next = stack_head; + stack_head = the_queue_element; + queue_length--; +} + +void handle_top_event() +{ + switch (queue_head->event_type) { + case NEW_CONN: + DBG(("handle_top_event: NEW_CONN")); + new_conn_handler(); + break; + case CONN: + DBG(("handle_top_event: CONN data on fd %d", queue_head->fd)); + conn_data_handler(queue_head->fd); + break; + default: + fprintf(stderr, "handle_top_event: unknown event type %d\n", + queue_head->event_type); + break; + } +} + +/* + * This is the new connection handler. This function is called by the + * event handler when data is pending on the listening socket (conn_fd). + * If space is available, an interactive data structure is initialized and + * the connected is established. + */ +void new_conn_handler() +{ + +#ifdef IPV6 + struct sockaddr_in6 client; +#else + struct sockaddr_in client; +#endif + socklen_t client_len; + struct hostent *c_hostent; + int new_fd; + int conn_index; + + client_len = sizeof(client); + new_fd = accept(conn_fd, (struct sockaddr *) & client, &client_len); + if (new_fd == -1) { + socket_perror("new_conn_handler: accept", 0); + return; + } + if (set_socket_nonblocking(new_fd, 1) == -1) { + socket_perror("new_conn_handler: set_socket_nonblocking 1", 0); + OS_socket_close(new_fd); + return; + } + if (total_conns >= MAX_CONNS) { + char *message = "no available slots -- closing connection.\n"; + + fprintf(stderr, "new_conn_handler: no available connection slots.\n"); + OS_socket_write(new_fd, message, strlen(message)); + if (OS_socket_close(new_fd) == -1) + socket_perror("new_conn_handler: close", 0); + return; + } + /* get some information about new connection */ + for (conn_index = 0; conn_index < MAX_CONNS; conn_index++) { + if (all_conns[conn_index].state == CONN_CLOSED) { + DBG(("new_conn_handler: opening conn index %d", conn_index)); + /* update global data for new fd */ + all_conns[conn_index].fd = new_fd; + all_conns[conn_index].state = CONN_OPEN; + all_conns[conn_index].addr = client; + + char portname[256]; + if(getnameinfo((struct sockaddr *)&client, sizeof(client), all_conns[conn_index].sname, SNAME_LEN, portname, 255, NI_NAMEREQD|NI_NUMERICHOST)) + strcpy(all_conns[conn_index].sname, ""); + total_conns++; + return; + } + } + fprintf(stderr, "new_conn_handler: sanity check failed!\n"); +} + +void conn_data_handler (int fd) +{ + int conn_index; + int buf_index; + int num_bytes; + int msgtype; + int leftover; + char *buf; + int res, msglen, expecting; + long unread_bytes; + + if ((conn_index = index_by_fd(fd)) == -1) { + fprintf(stderr, "conn_data_handler: invalid fd.\n"); + return; + } + DBG(("conn_data_handler: read on fd %d", fd)); + + /* append new data to end of leftover data (if any) */ + leftover = all_conns[conn_index].leftover; + buf = (char *) &all_conns[conn_index].buf[0]; + num_bytes = OS_socket_read(fd, buf + leftover, (IN_BUF_SIZE - 1) - leftover); + + switch (num_bytes) { + case -1: + switch (socket_errno) { + case EWOULDBLOCK: + DBG(("conn_data_handler: read on fd %d: Operation would block.", + fd)); + break; + default: + socket_perror("conn_data_handler: read", 0); + terminate(conn_index); + break; + } + break; + case 0: + if (all_conns[conn_index].state == CONN_CLOSED) + fprintf(stderr, "get_user_data: tried to read from closed fd.\n"); + terminate(conn_index); + break; + default: + DBG(("conn_data_handler: read %d bytes on fd %d", num_bytes, fd)); + num_bytes += leftover; + buf_index = 0; + expecting = 0; + while (num_bytes > sizeof(int) && buf_index < (IN_BUF_SIZE - 1)) { + /* get message type */ + memcpy((char *) &msgtype, (char *) &buf[buf_index], sizeof(int)); + DBG(("conn_data_handler: message type: %d", msgtype)); + + if (msgtype == NAMEBYIP) { + if (buf[buf_index + sizeof(int)] == '\0') { + /* no data here...resync */ + buf_index++; + num_bytes--; + continue; + } + if (expecting && num_bytes < expecting) { + /* + * message truncated...back up to DATALEN message; exit + * loop...and try again later + */ + buf_index -= (sizeof(int) + sizeof(int)); + num_bytes += (sizeof(int) + sizeof(int)); + break; + } + res = name_by_ip(conn_index, &buf[buf_index]); + } else if (msgtype == IPBYNAME) { + if (buf[buf_index + sizeof(int)] == '\0') { + /* no data here...resync */ + buf_index++; + num_bytes--; + continue; + } + if (expecting && num_bytes < expecting) { + /* + * message truncated...back up to DATALEN message; exit + * loop...and try again later + */ + buf_index -= (sizeof(int) + sizeof(int)); + num_bytes += (sizeof(int) + sizeof(int)); + break; + } + res = ip_by_name(conn_index, &buf[buf_index]); + } else if (msgtype == DATALEN) { + if (num_bytes > (sizeof(int) + sizeof(int))) { + memcpy((char *) &expecting, (char *) &buf[buf_index + sizeof(int)], sizeof(int)); + /* + * advance to next message + */ + buf_index += (sizeof(int) + sizeof(int)); + num_bytes -= (sizeof(int) + sizeof(int)); + if (expecting > IN_BUF_SIZE || expecting <= 0) { + fprintf(stderr, "conn_data_handler: bad data length %d\n", expecting); + expecting = 0; + } + continue; + } else { + /* + * not enough bytes...assume truncated; exit loop...we'll + * handle this message later + */ + break; + } + } else { + fprintf(stderr, "conn_data_handler: unknown message type %08x\n", msgtype); + /* advance through buffer */ + buf_index++; + num_bytes--; + continue; + } + + msglen = (int) (sizeof(int) + strlen(&buf[buf_index + sizeof(int)]) +1); + if (res) { + /* + * ok...advance to next message + */ + buf_index += msglen; + num_bytes -= msglen; + } else if (msglen < num_bytes || (expecting && expecting == msglen)) { + /* + * failed... + */ + + /* + * this was a complete message...advance to the next one + */ + msglen = (int) (sizeof(int) + strlen(&buf[buf_index + sizeof(int)]) +1); + buf_index += msglen; + num_bytes -= msglen; + expecting = 0; + } + else if (!OS_socket_ioctl(fd, FIONREAD, &unread_bytes) && + unread_bytes > 0) { + /* + * msglen == num_bytes could be a complete message... if + * there's unread data we'll assume it was truncated + */ + break; + } else { + /* + * nothing more? then discard message (it was the last one) + */ + buf_index = 0; + num_bytes = 0; + break; + } + } + + /* keep track of leftover buffer contents */ + if (num_bytes && buf_index) + memmove(buf, &buf[buf_index], num_bytes); + buf[num_bytes] = '\0'; + all_conns[conn_index].leftover = num_bytes; + + break; + } +} + +#define OUT_BUF_SIZE 80 + +int ip_by_name (int conn_index, char * buf) +{ + struct hostent *hp; + struct in_addr my_in_addr; + static char out_buf[OUT_BUF_SIZE]; + + hp = gethostbyname(&buf[sizeof(int)]); + if (hp == NULL) { +/* Failed :( */ + sprintf(out_buf, "%s 0\n", &buf[sizeof(int)]); + DBG(("%s", out_buf)); + OS_socket_write(all_conns[conn_index].fd, out_buf, strlen(out_buf)); + return 0; + } else { +/* Success! */ + memcpy(&my_in_addr, hp->h_addr, sizeof(struct in_addr)); + sprintf(out_buf, "%s %s\n", &buf[sizeof(int)], + inet_ntoa(my_in_addr)); + DBG(("%s", out_buf)); + OS_socket_write(all_conns[conn_index].fd, out_buf, strlen(out_buf)); + return 1; + } +} /* ip_by_name() */ + +int name_by_ip (int conn_index, char * buf) +{ + struct addrinfo hints, *res; + int ret; + + hints.ai_family = AF_INET6; + hints.ai_socktype = 0; + hints.ai_protocol = 0; +#if defined(AI_V4MAPPED) + hints.ai_flags = AI_CANONNAME| AI_V4MAPPED; +#else + hints.ai_flags = AI_CANONNAME; +#endif + static char out_buf[OUT_BUF_SIZE]; + + if((ret = getaddrinfo(&buf[sizeof(int)], NULL, &hints, &res))){ + //failed + sprintf(out_buf, "%s 0\n", &buf[sizeof(int)]); + DBG(("name_by_ip: malformed address request (%d).", ret)); + OS_socket_write(all_conns[conn_index].fd, out_buf, strlen(out_buf)); + return 0; + } + char tmpbuf[80], tmpp[80]; + if(ret = getnameinfo(res->ai_addr, res->ai_addrlen, tmpbuf, 79, tmpp, 79, NI_NAMEREQD|NI_NUMERICSERV)){ + sprintf(out_buf, "%s 0\n", &buf[sizeof(int)]); + DBG(("%s", out_buf)); + OS_socket_write(all_conns[conn_index].fd, out_buf, strlen(out_buf)); + DBG(("name_by_ip: unable to resolve address.")); + freeaddrinfo(res); + return 0; + } + sprintf(out_buf, "%s %s\n", &buf[sizeof(int)], tmpbuf); + DBG(("%s", out_buf)); + OS_socket_write(all_conns[conn_index].fd, out_buf, strlen(out_buf)); + freeaddrinfo(res); + return 1; +} + +int index_by_fd (int fd) +{ + int i; + + for (i = 0; i < MAX_CONNS; i++) { + if ((all_conns[i].state == CONN_OPEN) && (all_conns[i].fd == fd)) + return (i); + } + return (-1); +} + +void terminate (int conn_index) +{ + if (conn_index < 0 || conn_index >= MAX_CONNS) { + fprintf(stderr, "terminate: conn_index %d out of range.\n", conn_index); + return; + } + if (all_conns[conn_index].state == CONN_CLOSED) { + fprintf(stderr, "terminate: connection %d already closed.\n", conn_index); + return; + } + DBG(("terminating connection %d", conn_index)); + + if (OS_socket_close(all_conns[conn_index].fd) == -1) { + socket_perror("terminate: close", 0); + return; + } + all_conns[conn_index].state = CONN_CLOSED; + total_conns--; +} + +int main (int argc, char ** argv) +{ + int addr_server_port; + struct timeval timeout; + int i; + int nb; + char *ipaddress = 0; + + if (argc > 1) { + if ((addr_server_port = atoi(argv[1])) == 0) { + fprintf(stderr, "addr_server: malformed port number.\n"); + exit(2); + } + if (argc > 2) { + if (inet_addr((ipaddress = argv[2])) == INADDR_NONE) { + fprintf(stderr, "addr_server: malformed ip address.\n"); + exit(3); + } + } + } else { + fprintf(stderr, "addr_server: first arg must be port number.\n"); + exit(1); + } + init_conn_sock(addr_server_port, ipaddress); + while (1) { + /* + * use finite timeout for robustness. + */ + timeout.tv_sec = 2; + timeout.tv_usec = 0; + /* + * clear selectmasks. + */ + FD_ZERO(&readmask); + /* + * set new connection accept fd in readmask. + */ + FD_SET(conn_fd, &readmask); + /* + * set active fds in readmask. + */ + for (i = 0; i < MAX_CONNS; i++) { + if (all_conns[i].state == CONN_OPEN) + FD_SET(all_conns[i].fd, &readmask); + } +#ifndef hpux + nb = select(FD_SETSIZE, &readmask, (fd_set *) 0, (fd_set *) 0, &timeout); +#else + nb = select(FD_SETSIZE, (int *) &readmask, (int *) 0, (int *) 0, &timeout); +#endif + if (nb != 0) + aserv_process_io(nb); + process_queue(); + } + /* the following is to shut lint up */ + /*NOTREACHED*/ + return 0; /* never reached */ +} + +#ifdef WIN32 +void debug_message(char *fmt, ...) +{ + static char deb_buf[1024]; + static char *deb = deb_buf; + va_list args; + + V_START(args, fmt); + V_VAR(char *, fmt, args); + vfprintf(stderr, fmt, args); + fflush(stderr); + va_end(args); +} +#endif diff --git a/fluffos-2.23-ds03/addr_server.h b/fluffos-2.23-ds03/addr_server.h new file mode 100644 index 0000000..e2d78c3 --- /dev/null +++ b/fluffos-2.23-ds03/addr_server.h @@ -0,0 +1,53 @@ +/* + * addr_server.h -- definitions and prototypes for addr_server.c + * 8-92 : Dwayne Fontenot : original coding. + */ + +#ifndef ADDR_SERVER_H +#define ADDR_SERVER_H + +#include "network_incl.h" + +#define DFAULT_PROTO 0 /* use the appropriate protocol */ +#define MAX_CONNS 4 /* max number of connections */ +#define SNAME_LEN 64 /* length of symbolic name string */ +#define MAX_EVENTS_IN_QUEUE 100 +#define MAX_EVENTS_TO_PROCESS 100 +#define IN_BUF_SIZE 100 + +enum conn_states { + CONN_CLOSED, CONN_OPEN +}; + +enum ev_type { + NEW_CONN, CONN +}; + +enum msgtypes { + NAMEBYIP = 0, IPBYNAME, DATALEN +}; + +typedef struct conn *conn_ptr; + +typedef struct conn { + int fd; /* file descriptor */ + int state; /* connection state */ +#ifndef IPV6 + struct sockaddr_in addr; /* address struct for connected */ +#else + struct sockaddr_in6 addr; +#endif + char sname[SNAME_LEN]; /* symbolic name of connected host */ + int leftover; /* unprocessed bytes in data queue */ + char buf[IN_BUF_SIZE]; +} connection; + +typedef struct queue_elem *queue_element_ptr; + +typedef struct queue_elem { + short event_type; /* event type */ + int fd; /* file descriptor on which data is pending */ + queue_element_ptr next; +} queue_element; + +#endif /* _ADDR_SERVER_H_ */ diff --git a/fluffos-2.23-ds03/applies b/fluffos-2.23-ds03/applies new file mode 100644 index 0000000..1dc147b --- /dev/null +++ b/fluffos-2.23-ds03/applies @@ -0,0 +1,74 @@ +__INIT:#global_init# +ADJECTIVE:parse_command_adjectiv_id_list +CATCH_TELL +CLEAN_UP +CREATE +DESTRUCTOR +ID +INIT +LOGON +MOVE:move_or_destruct +NET_DEAD +NOUN:parse_command_id_list +PLURAL:parse_command_plural_id_list +PROCESS_INPUT +QGET_ADJID:parse_command_adjective_id_list +QGET_ID:parse_command_id_list +QGET_PLURID:parse_command_plural_id_list +RECEIVE_MESSAGE +RECEIVE_SNOOP +RECEIVE_ED +RESET +TELNET_SUBOPTION +TERMINAL_TYPE +TERMINAL_COLOUR_REPLACE +WINDOW_SIZE +WRITE_PROMPT +MXP_ENABLE +MXP_TAG +ZMP:zmp_command +GMCP_ENABLE +GMCP +RECEIVE_ENVIRON +# master applies +AUTHOR_FILE +COMPILE_OBJECT +CONNECT +CRASH +CREATOR_FILE +DOMAIN_FILE +EPILOG +ERROR_HANDLER +GET_BACKBONE_UID:get_bb_uid +GET_ED_BUFFER_SAVE_FILE_NAME:get_save_file_name +GET_ROOT_UID +LOG_ERROR +MAKE_PATH_ABSOLUTE +FLAG +OBJECT_NAME +PARSER_ERROR_MESSAGE +PRELOAD +PRIVS_FILE +RETRIEVE_ED_SETUP +SAVE_ED_SETUP +SLOW_SHUTDOWN +USERS:parse_command_users +VALID_ASM +VALID_BIND +VALID_DATABASE +VALID_HIDE +VALID_LINK +LITERALS:parse_command_prepos_list +VALID_OBJECT +VALID_OVERRIDE +QGET_ALLWORD:parse_command_all_word +QGET_PREPOS:parse_command_prepos_list +VALID_READ +VALID_SETEUID +VALID_SHADOW +VALID_SOCKET +VALID_WRITE +PARSE_FIRST_INVENTORY:parse_get_first_inventory +PARSE_NEXT_INVENTORY:parse_get_next_inventory +PARSE_ENVIRONMENT:parse_get_environment +GET_MUD_STATS diff --git a/fluffos-2.23-ds03/arch.h b/fluffos-2.23-ds03/arch.h new file mode 100644 index 0000000..e548a27 --- /dev/null +++ b/fluffos-2.23-ds03/arch.h @@ -0,0 +1,159 @@ +/* arch.h: __ARCH__ - a predefined macro exported to all LPC objects */ + +#ifndef _ARCH_H_ +#define _ARCH_H_ + +#ifdef sequent +#define ARCH "Sequent DYNIX" +#endif + +/* + * Note - Cygwin runs under windows and automatically + * defines a number of windows related things. These + * must be undef'd so that the 'normal' windows port code + * in MudOS is not used. + */ +#ifdef __CYGWIN__ +#undef WINNT +#undef WIN95 +#undef WIN98 +#undef WINSOCK +#undef WIN32 +#define ARCH "Cygwin-32" +#endif + +#ifdef WINNT +#define ARCH "Microsoft Windows NT" +#endif + +#ifdef WIN95 +#define ARCH "Microsoft Windows 95" +#endif + +#ifdef _SEQUENT_ +#define ARCH "Sequent DYNIX/ptx" +#endif + +#ifdef __FreeBSD__ +#define ARCH "FreeBSD" +#endif + +#ifdef __NetBSD__ +#ifdef sparc +#define ARCH "NetBSD/sparc" +#else +#define ARCH "NetBSD" +#endif +#endif + +#ifdef NeXT +#ifdef m68k +#define ARCH "NeXT/68k" +#else +#define ARCH "NeXT" +#endif +#endif + +#ifdef _AIX +#define ARCH "AIX" +#endif + +#ifdef accel +#define ARCH "Accel" +#endif + +/* Attempt to guess whether we are running Solaris or not */ +#if defined(sun) && !defined(SunOS_5) +# if defined(__svr4__) || defined(__sol__) || defined(SVR4) +# define SunOS_5 +# else +# ifdef sun4 +# define ARCH "Sun4" +# else + +# ifdef sun3 +# define ARCH "Sun3" +# else +# define ARCH "Sun" +# endif +# endif +# endif +#endif + +#if defined(SunOS_5) +# ifdef sparc +# define ARCH "Solaris SPARC" +# else +# define ARCH "Solaris x86" +# endif +#endif + +#ifdef _AUX_SOURCE +#define ARCH "A/UX" +#endif + +#ifdef linux +# ifdef __mc68000 +# define ARCH "Linux/m68k" +# else +# ifdef __alpha +# define ARCH "Linux/alpha" +# else +# define ARCH "Linux" +# endif +# endif +#endif + +#ifdef hp68k +#define ARCH "HP/68k" +#endif + +#ifdef hppa +#define ARCH "HP/PA-RISC" +#endif + +#ifdef cray +#define ARCH "Cray" +#endif + +#if !defined(ARCH) && defined(__alpha) +#define ARCH "Alpha" +#endif + +#if !defined(ARCH) && defined(__bsdi__) +#define ARCH "BSDI" +#endif + +#if !defined(ARCH) && defined(__386BSD__) +#define ARCH "386bsd" +#endif + +#if !defined(ARCH) && defined(ultrix) +#define ARCH "Ultrix" +#endif + +#if !defined(ARCH) && defined(hpux) +#define ARCH "HP/UX" +#endif + +#if !defined(ARCH) && defined(sgi) +#define ARCH "IRIX" +#endif + +#if (!defined(ARCH) && defined(SVR4)) +#define ARCH "SVR4" +#endif + +#if !defined(ARCH) && defined(OSF) +#define ARCH "OSF/1" +#endif + +#if !defined(ARCH) && defined(__APPLE__) && defined(__GNUC__) +#define ARCH "Mac OS X" +#endif + +#ifndef ARCH +#define ARCH "unknown architecture" +#endif + +#endif diff --git a/fluffos-2.23-ds03/array.c b/fluffos-2.23-ds03/array.c new file mode 100644 index 0000000..bb75495 --- /dev/null +++ b/fluffos-2.23-ds03/array.c @@ -0,0 +1,2344 @@ +#include "std.h" +#include "lpc_incl.h" +#include "comm.h" +#include "regexp.h" +#include "backend.h" +#include "qsort.h" +#include "md.h" +#include "efun_protos.h" + +/* + * This file contains functions used to manipulate arrays. + * Some of them are connected to efuns, and some are only used internally + * by the MudOS driver. + */ + +#ifdef ARRAY_STATS +int num_arrays; +int total_array_size; +#endif + +INLINE_STATIC int builtin_sort_array_cmp_fwd (void *, void *); +INLINE_STATIC int builtin_sort_array_cmp_rev (void *, void *); +INLINE_STATIC int sort_array_cmp (void *, void *); +INLINE_STATIC long alist_cmp (svalue_t *, svalue_t *); +/* + * Make an empty array for everyone to use, never to be deallocated. + * It is cheaper to reuse it, than to use MALLOC() and allocate. + */ + +array_t the_null_array = +{ + 1, /* Ref count, which will ensure that it will + * never be deallocated */ +#ifdef DEBUG + 1, /* extra ref */ +#endif + 0, /* size */ +}; + +#ifdef PACKAGE_MUDLIB_STATS +static void ms_setup_stats (array_t * p) { + if (current_object) { + assign_stats(&p->stats, current_object); + add_array_size(&p->stats, p->size); + } else { + null_stats(&p->stats); + } +} + +#define ms_remove_stats(p) add_array_size(&(p)->stats, -((p)->size)) +#define ms_add_array_size(p, n) add_array_size(p, n) +#else +#define ms_setup_stats(x) +#define ms_remove_stats(x) +#define ms_add_array_size(p, n) +#endif + +/* Array allocation routines: + * + * the prefix int_ indicates error checking is not performed. It is up to + * the caller to guarantee 0 < n <= max_array_size [note that the first + * inequality is strict]. + * + * _empty_ indicates that the internal svalues are not initialized to zero; + * this saves some time if the calling routine is simply going to overwrite + * the entries. In the case of free_ and dealloc_, it means the entries + * have already been moved somewhere else or freed, and should be ignored. + * + * Note that we rely a bit on gcc automatically inlining small routines. + * Speed maniacs may wish to add INLINE liberally. + */ +static array_t *int_allocate_empty_array (unsigned int n) { + array_t *p; + +#ifdef ARRAY_STATS + num_arrays++; + total_array_size += sizeof(array_t) + sizeof(svalue_t) * (n-1); +#endif + p = ALLOC_ARRAY(n); + p->ref = 1; + p->size = n; + ms_setup_stats(p); + + return p; +} + +array_t *allocate_empty_array (int n) +{ + if (n < 0 || n > max_array_size) + error("Illegal array size.\n"); + if (!n) return &the_null_array; + + return int_allocate_empty_array(n); +} + +static array_t *int_allocate_array (int n) +{ + array_t *p = int_allocate_empty_array(n); + + while (n--) + p->item[n] = const0; + + return p; +} + +array_t *allocate_array (int n) +{ + array_t *p = allocate_empty_array(n); + + while (n--) + p->item[n] = const0; + + return p; +} + +array_t *allocate_array2 (int n, svalue_t * svp) { + int i; + array_t *ret; + + if (svp->type == T_FUNCTION) { + ret = allocate_array(n); + + for (i = 0; i < n; i++) { + svalue_t *r; + + push_number(i); + r = call_function_pointer(svp->u.fp, 1); + ret->item[i] = *r; + r->type = T_NUMBER; + } + } else { + ret = allocate_empty_array(n); + + for (i = 0; i < n; i++) + assign_svalue_no_free(ret->item + i, svp); + } + + return ret; +} + +static void dealloc_empty_array (array_t * p) { + ms_remove_stats(p); +#ifdef ARRAY_STATS + num_arrays--; + total_array_size -= sizeof(array_t) + sizeof(svalue_t) * + (p->size - 1); +#endif + FREE((char *) p); +} + +void dealloc_array (array_t * p) +{ + int i; + + for (i = p->size; i--;) + free_svalue(&p->item[i], "free_array"); + dealloc_empty_array(p); +} + +void free_array (array_t * p) +{ + if (--(p->ref) > 0 || (p == &the_null_array)) + return; + + dealloc_array(p); +} + +void free_empty_array (array_t * p) +{ + if ((--(p->ref) > 0) || (p == &the_null_array)) + return; + + dealloc_empty_array(p); +} + +/* Finish setting up an array allocated with ALLOC_ARRAY, resizing it to + size n */ +static array_t *fix_array (array_t * p, unsigned int n) { + if(n){ +#ifdef ARRAY_STATS + num_arrays++; + total_array_size += sizeof(array_t) + sizeof(svalue_t) * (n-1); +#endif + p->size = n; + p->ref = 1; + ms_setup_stats(p); +// if(n>65535) +// fatal("big array2"); + return RESIZE_ARRAY(p, n); + } + if(p!=&the_null_array) + FREE(p); + return &the_null_array; +} + +array_t *resize_array (array_t * p, unsigned int n) { +#ifdef ARRAY_STATS + total_array_size += (n - p->size) * sizeof(svalue_t); +#endif + if(n){ + ms_remove_stats(p); + p = RESIZE_ARRAY(p, n); +// if(n>65535) +// fatal("big array3"); + + if (!p) + fatal("Out of memory.\n"); + p->size = n; + ms_setup_stats(p); + } else { + if(p != &the_null_array) + FREE(p); + return &the_null_array; + } + return p; +} + +array_t *explode_string (const char * str, int slen, const char * del, int len) +{ + const char *p, *beg, *lastdel = 0; + int num, j, limit; + array_t *ret; + char *buff, *tmp; + int sz; + + if (!slen) + return &the_null_array; + + /* return an array of length strlen(str) -w- one character per element */ + if (len == 0) { + sz = 1; + + if (slen > max_array_size) { + slen = max_array_size; + } + ret = int_allocate_empty_array(slen); + for (j = 0; j < slen; j++) { + ret->item[j].type = T_STRING; + ret->item[j].subtype = STRING_MALLOC; + ret->item[j].u.string = tmp = new_string(1, "explode_string: tmp"); + tmp[0] = str[j]; + tmp[1] = '\0'; + } + return ret; + } + if (len == 1) { + char delimeter; + + delimeter = *del; + +#ifndef REVERSIBLE_EXPLODE_STRING + /* + * Skip leading 'del' strings, if any. + */ + while (*str == delimeter) { + str++; + slen--; + if (str[0] == '\0') { + return &the_null_array; + } +# ifdef SANE_EXPLODE_STRING + break; +# endif + } +#endif + /* + * Find number of occurences of the delimiter 'del'. + */ + for (p = str, num = 0; *p;) { + if (*p == delimeter) { + num++; + lastdel = p; + } + p++; + } + + /* + * Compute number of array items. It is either number of delimiters, + * or, one more. + */ + limit = max_array_size; +#ifdef REVERSIBLE_EXPLODE_STRING + num++; + limit--; +#else + if (lastdel != (str + slen - 1)) { + num++; + limit--; + } +#endif + if (num > max_array_size) { + num = max_array_size; + } + ret = int_allocate_empty_array(num); + for (p = str, beg = str, num = 0; *p && (num < limit);) { + if (*p == delimeter) { + DEBUG_CHECK(num >= ret->size, "Index out of bounds in explode!\n"); + sz = p - beg; + ret->item[num].type = T_STRING; + ret->item[num].subtype = STRING_MALLOC; + ret->item[num].u.string = buff = new_string(sz, "explode_string: buff"); + + strncpy(buff, beg, sz); + buff[sz] = '\0'; + num++; + beg = ++p; + } else { + p++; + } + } + +#ifdef REVERSIBLE_EXPLODE_STRING + ret->item[num].type = T_STRING; + ret->item[num].subtype = STRING_MALLOC; + ret->item[num].u.string = string_copy(beg, "explode_string: last, len == 1"); +#else + /* Copy last occurence, if there was not a 'del' at the end. */ + if (*beg != '\0' && num != limit) { + ret->item[num].type = T_STRING; + ret->item[num].subtype = STRING_MALLOC; + ret->item[num].u.string = string_copy(beg, "explode_string: last, len == 1"); + } +#endif + return ret; + } /* len == 1 */ +#ifndef REVERSIBLE_EXPLODE_STRING + /* + * Skip leading 'del' strings, if any. + */ + while (strncmp(str, del, len) == 0) { + str += len; + slen -= len; + if (str[0] == '\0') { + return &the_null_array; + } +# ifdef SANE_EXPLODE_STRING + break; +# endif + } +#endif + + /* + * Find number of occurences of the delimiter 'del'. + */ + for (p = str, num = 0; *p;) { + if (strncmp(p, del, len) == 0) { + num++; + lastdel = p; + p += len; + } else { + p++; + } + } + + /* + * Compute number of array items. It is either number of delimiters, or, + * one more. + */ +#ifdef REVERSIBLE_EXPLODE_STRING + num++; +#else + if (lastdel != (str + slen - len)) { + num++; + } +#endif + if (num > max_array_size) { + num = max_array_size; + } + ret = int_allocate_empty_array(num); + limit = max_array_size - 1; /* extra element can be added after loop */ + for (p = str, beg = str, num = 0; *p && (num < limit);) { + if (strncmp(p, del, len) == 0) { + if (num >= ret->size) + fatal("Index out of bounds in explode!\n"); + + ret->item[num].type = T_STRING; + ret->item[num].subtype = STRING_MALLOC; + ret->item[num].u.string = buff = new_string(p - beg, + "explode_string: buff"); + + strncpy(buff, beg, p - beg); + buff[p - beg] = '\0'; + num++; + beg = p + len; + p = beg; + } else { + p++; + } + } + + /* Copy last occurence, if there was not a 'del' at the end. */ +#ifdef REVERSIBLE_EXPLODE_STRING + ret->item[num].type = T_STRING; + ret->item[num].subtype = STRING_MALLOC; + ret->item[num].u.string = string_copy(beg, "explode_string: last, len != 1"); +#else + if (*beg != '\0' && num != limit) { + ret->item[num].type = T_STRING; + ret->item[num].subtype = STRING_MALLOC; + ret->item[num].u.string = string_copy(beg, "explode_string: last, len != 1"); + } +#endif + return ret; +} + +char *implode_string (array_t * arr, const char * del, int del_len) +{ + int size, i, num; + char *p, *q; + + for (i = arr->size, size = 0, num = 0; i--;) { + if (arr->item[i].type == T_STRING) { + size += SVALUE_STRLEN(&arr->item[i]); + num++; + } + } + if (num == 0) + return string_copy("", "implode_string"); + + p = new_string(size + (num - 1) * del_len, "implode_string: p"); + q = p; + for (i = 0, num = 0; i < arr->size; i++) { + if (arr->item[i].type == T_STRING) { + if (num) { + strncpy(p, del, del_len); + p += del_len; + } + size = SVALUE_STRLEN(&arr->item[i]); + strncpy(p, arr->item[i].u.string, size); + p += size; + num++; + } + } + *p = 0; + return q; +} + +void implode_array (funptr_t * fptr, array_t * arr, + svalue_t * dest, int first_on_stack) { + int i = 0, n; + svalue_t *v; + + if (first_on_stack) { + if (!(n = arr->size)) { + *dest = *sp--; + return; + } + } else { + if (!(n = arr->size)) { + *dest = const0; + return; + } else if (n == 1) { + assign_svalue_no_free(dest, &arr->item[0]); + free_array(arr); + return; + } + } + + if (!first_on_stack) + push_svalue(&arr->item[i++]); + + while (1) { + push_svalue(&arr->item[i++]); + v = call_function_pointer(fptr, 2); + if (!v) { + *dest = const0; + return; + } + if (i < n) + push_svalue(v); + else + break; + } + assign_svalue_no_free(dest, v); + free_array(arr); +} + +array_t *users() +{ + register object_t *ob; + int i, j; + array_t *ret; +#ifdef F_SET_HIDE + int display_hidden = 0; + + if (num_hidden_users > 0) { + if (current_object->flags & O_HIDDEN) { + display_hidden = 1; + } else { + display_hidden = valid_hide(current_object); + } + } + ret = allocate_empty_array(num_user - (display_hidden ? 0 : num_hidden_users)); +#else + ret = allocate_empty_array(num_user); +#endif + for (i = j = 0; i < max_users; i++) { + if (!all_users[i]) { + continue; + } + ob = all_users[i]->ob; +#ifdef F_SET_HIDE + if (!display_hidden && (ob->flags & O_HIDDEN)) + continue; +#endif + ret->item[j].type = T_OBJECT; + ret->item[j].u.ob = ob; + add_ref(ob, "users"); + j++; + } + return ret; +} + +/* + * Slice of an array. + * It now frees the passed array + */ +array_t *slice_array (array_t * p, int from, int to) +{ + int cnt; + svalue_t *sv1, *sv2; + + if (from < 0) + from = 0; + if (to >= p->size) + to = p->size - 1; + if (from > to) { + free_array(p); + return &the_null_array; + } + + if (!(--p->ref)) { + if (from) { + sv1 = p->item + from; + cnt = from; + while (cnt--) free_svalue(--sv1, "slice_array:2"); + cnt = to - from + 1; + sv1 = p->item; + sv2 = p->item + from; + while (cnt--) *sv1++ = *sv2++; + } else { + sv2 = p->item + to + 1; + } + cnt = (p->size - 1) - to; + while (cnt--) free_svalue(sv2++, "slice_array:3"); + if(to-from+1 > max_array_size) + error("array slice too big"); //can't happen in theory + p = resize_array(p, to-from+1); + p->ref = 1; + return p; + } else { + array_t *d; + if(to-from+1 > max_array_size) + error("array slice too big"); //can't happen in theory + d = int_allocate_empty_array(to - from + 1); + sv1 = d->item - from; + sv2 = p->item; + for (cnt = from; cnt <= to; cnt++) + assign_svalue_no_free(sv1 + cnt, sv2 + cnt); + return d; + } +} + +/* + * Copy of an array + */ +array_t *copy_array (array_t * p) +{ + array_t *d; + int n; + svalue_t *sv1 = p->item, *sv2; + + d = allocate_empty_array(n = p->size); + sv2 = d->item; + while (n--) + assign_svalue_no_free(&sv2[n], &sv1[n]); + return d; +} + +#ifdef F_COMMANDS +array_t *commands (object_t * ob) +{ + sentence_t *s; + array_t *v, *p; + int cnt = 0; + svalue_t *sv; + + for (s = ob->sent; s && s->verb; s = s->next) { + if (++cnt == max_array_size) break; + } + v = allocate_empty_array(cnt); + sv = v->item; + for (s = ob->sent; cnt-- && s && s->verb; s = s->next) { + sv->type = T_ARRAY; + (sv++)->u.arr = p = int_allocate_empty_array(4); + p->item[0].type = T_STRING; + p->item[0].u.string = ref_string(s->verb); /* the verb is shared */ + p->item[0].subtype = STRING_SHARED; + p->item[1].type = T_NUMBER; + p->item[1].u.number = s->flags; + p->item[2].type = T_OBJECT; + p->item[2].u.ob = s->ob; + p->item[3].type = T_STRING; + if (s->flags & V_FUNCTION) { + p->item[3].u.string = ""; + p->item[3].subtype = STRING_CONSTANT; + } else { + p->item[3].u.string = ref_string(s->function.s); + p->item[3].subtype = STRING_SHARED; + } + add_ref(s->ob, "commands"); + } + return v; +} +#endif + +/* EFUN: filter_array + + Runs all elements of an array through ob->func() + and returns an array holding those elements that ob->func + returned 1 for. + */ + +#ifdef F_FILTER +void +filter_array(svalue_t * arg, int num_arg) +{ + array_t *vec = arg->u.arr, *r; + int size; + + if ((size = vec->size) < 1) { + pop_n_elems(num_arg - 1); + return; + } else { + svalue_t *v; + int res = 0, cnt; + function_to_call_t ftc; + + process_efun_callback(1, &ftc, F_FILTER); + + /* allocate a full size array and push it onto the stack so that if an + * error occurs, it'll get cleaned up. can't use empty array because + * if an error occurs, it'll contain garbage and crash the driver + */ + r = allocate_array(size); + push_refed_array(r); + + for (cnt = 0; cnt < size; cnt++) { + push_svalue(&vec->item[cnt]); + v = call_efun_callback(&ftc, 1); + if (!IS_ZERO(v)) + assign_svalue_no_free(&r->item[res++], &vec->item[cnt]); + } + + sp--;/* pull the work array off the stack without freeing it */ + if (res) + r = resize_array(r, res); + else { + free_array(r); + r = &the_null_array; + } + + pop_n_elems(num_arg - 1); + free_array(vec); + sp->u.arr = r; + } +} + +void +filter_string (svalue_t * arg, int num_arg) +{ + if (arg->u.string[0] == 0) { + pop_n_elems(num_arg - 1); + return; + } else { + int size; + svalue_t *v; + int idx = 0, cnt; + function_to_call_t ftc; + char *str; + + unlink_string_svalue(arg); + size = SVALUE_STRLEN(arg); + str = (char *) arg->u.string; + + process_efun_callback(1, &ftc, F_FILTER); + + for (cnt = 0; cnt < size; cnt++) { + push_number(str[cnt]); + v = call_efun_callback(&ftc, 1); + if (!IS_ZERO(v)) + str[idx++] = str[cnt]; + } + str[idx] = 0; + + if (idx != cnt) + arg->u.string = extend_string(arg->u.string, idx); + + pop_n_elems(num_arg - 1); + } +} +#endif + +/* Unique maker + + These routines takes an array of objects and calls the function 'func' + in them. The return values are used to decide which of the objects are + unique. Then an array on the below form are returned: + + ({ + ({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 }), + }) + + i.e an array of arrays consisting of lists of objectpointers + to all the nonunique objects for each unique set of objects. + + The basic purpose of this routine is to speed up the preparing of the + array used for describing. + + */ + +/* nonstatic, is used in mappings too */ +int sameval (svalue_t * arg1, svalue_t * arg2) +{ + DEBUG_CHECK(!arg1 || !arg2, "Null pointer passed to sameval.\n"); + + switch (arg1->type | arg2->type) { + case T_NUMBER: + return arg1->u.number == arg2->u.number; + case T_ARRAY: + case T_CLASS: + return arg1->u.arr == arg2->u.arr; + case T_STRING: + if (SVALUE_STRLEN_DIFFERS(arg1, arg2)) return 0; + return !strcmp(arg1->u.string, arg2->u.string); + case T_OBJECT: + return arg1->u.ob == arg2->u.ob; + case T_MAPPING: + return arg1->u.map == arg2->u.map; + case T_FUNCTION: + return arg1->u.fp == arg2->u.fp; + case T_REAL: + return arg1->u.real == arg2->u.real; +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + return arg1->u.buf == arg2->u.buf; +#endif + } + return 0; +} + +#ifdef F_UNIQUE_ARRAY + +typedef struct unique_s { + svalue_t mark; + int count; + struct unique_s *next; + int *indices; +} unique_t; + +typedef struct unique_list_s { + unique_t *head; + struct unique_list_s *next; +} unique_list_t; + +static unique_list_t *g_u_list = 0; + +static void unique_array_error_handler (void) { + unique_list_t *unlist = g_u_list; + unique_t *uptr = unlist->head, *nptr; + + g_u_list = g_u_list->next; + while (uptr) { + nptr = uptr->next; + FREE((char *) uptr->indices); + free_svalue(&uptr->mark, "unique_array_error_handler"); + FREE((char *) uptr); + uptr = nptr; + } + FREE((char *)unlist); +} + +void f_unique_array (void) { + array_t *v, *ret; + long size, i, numkeys = 0, num_arg = st_num_arg; + int *ind; + svalue_t *skipval, *sv, *svp; + unique_list_t *unlist; + unique_t **head, *uptr, *nptr; + funptr_t *fptr = 0; + const char *func; + + size = (v = (sp - num_arg + 1)->u.arr)->size; + if (!size) { + if (num_arg == 3) free_svalue(sp--, "f_unique_array"); + free_svalue(sp--, "f_unique_array"); + return; + } + + if (num_arg == 3) { + skipval = sp; + if ((sp-1)->type == T_FUNCTION) + fptr = (sp-1)->u.fp; + else + func = (sp-1)->u.string; + } + else { + skipval = &const0; + if (sp->type == T_FUNCTION) + fptr = sp->u.fp; + else + func = sp->u.string; + } + + unlist = ALLOCATE(unique_list_t, TAG_TEMPORARY, "f_unique_array:1"); + unlist->next = g_u_list; + unlist->head = 0; + head = &unlist->head; + g_u_list = unlist; + + STACK_INC; + sp->type = T_ERROR_HANDLER; + sp->u.error_handler = unique_array_error_handler; + + for (i = 0; i < size; i++) { + if (fptr) { + push_svalue(v->item + i); + sv = call_function_pointer(fptr, 1); + } else if (v->item[i].type == T_OBJECT) { + sv = apply(func, v->item[i].u.ob, 0, ORIGIN_EFUN); + } else sv = 0; + + if (sv && !sameval(sv, skipval)) { + uptr = *head; + while (uptr) { + if (sameval(sv, &uptr->mark)) { + uptr->indices = RESIZE(uptr->indices, uptr->count + 1, int, + TAG_TEMPORARY, "f_unique_array:2"); + uptr->indices[uptr->count++] = i; + break; + } + uptr = uptr->next; + } + if (!uptr) { + numkeys++; + uptr = ALLOCATE(unique_t, TAG_TEMPORARY, "f_unique_array:3"); + uptr->indices = ALLOCATE(int, TAG_TEMPORARY, "f_unique_array:4"); + uptr->count = 1; + uptr->indices[0] = i; + uptr->next = *head; + assign_svalue_no_free(&uptr->mark, sv); + *head = uptr; + } + } + } + + ret = allocate_empty_array(numkeys); + uptr = *head; + svp = v->item; + while (numkeys--) { + nptr = uptr->next; + (sv = ret->item + numkeys)->type = T_ARRAY; + sv->u.arr = allocate_empty_array(i = uptr->count); + skipval = sv->u.arr->item + i; + ind = uptr->indices; + while (i--) { + assign_svalue_no_free(--skipval, svp + ind[i]); + } + FREE((char *)ind); + free_svalue(&uptr->mark, "f_unique_array"); + FREE((char *)uptr); + uptr = nptr; + } + + unlist = g_u_list->next; + FREE((char *)g_u_list); + g_u_list = unlist; + sp--; + pop_n_elems(num_arg - 1); + free_array(v); + sp->u.arr = ret; +} + +/* + * End of Unique maker + ************************* + */ +#endif + +/* Concatenation of two arrays into one + */ +array_t *add_array (array_t * p, array_t * r) +{ + int cnt, res; + array_t *d; /* destination */ + + /* + * have to be careful with size zero arrays because they could be + * the_null_array. REALLOC(the_null_array, ...) is bad :( + */ + if (p->size == 0) { + p->ref--; + return r->ref > 1 ? (r->ref--, copy_array(r)) : r; + } + if (r->size == 0) { + r->ref--; + return p->ref > 1 ? (p->ref--, copy_array(p)) : p; + } + + res = p->size + r->size; + if (res < 0 || res > max_array_size) + error("result of array addition is greater than maximum array size.\n"); + + /* x += x */ + if ((p == r) && (p->ref == 2)) { + int osize = p->size; + + p->ref = 1; + d = resize_array(p, res); + + /* copy myself */ + for (cnt = osize; cnt--; ) + assign_svalue_no_free(&d->item[--res], &d->item[cnt]); + + return d; + } + + /* transfer svalues for ref 1 target array */ + if (p->ref == 1) { + d = resize_array(p, res); + /* note that d->ref is already 1, which is right */ + } else { + d = int_allocate_empty_array(res); + + for (cnt = p->size; cnt--;) + assign_svalue_no_free(&d->item[cnt], &p->item[cnt]); + p->ref--; + } + + /* transfer svalues from ref 1 source array */ + if (r->ref == 1) { + for (cnt = r->size; cnt--;) + d->item[--res] = r->item[cnt]; + dealloc_empty_array(r); + } else { + for (cnt = r->size; cnt--;) + assign_svalue_no_free(&d->item[--res], &r->item[cnt]); + r->ref--; + } + + return d; +} + +#ifndef NO_ENVIRONMENT +/* Returns an array of all objects contained in 'ob' */ +array_t *all_inventory (object_t * ob, int override) +{ + array_t *d; + object_t *cur; + int cnt, res; + int display_hidden; + + if (override) { + display_hidden = 1; + } else { + display_hidden = -1; + } + cnt = 0; + for (cur = ob->contains; cur; cur = cur->next_inv) { +#ifdef F_SET_HIDE + if (cur->flags & O_HIDDEN) { + if (display_hidden == -1) { + display_hidden = valid_hide(current_object); + } + if (display_hidden) + cnt++; + } else +#endif + cnt++; + } + + if (!cnt) + return &the_null_array; + + if(cnt > max_array_size) + cnt = max_array_size; + + d = int_allocate_empty_array(cnt); + cur = ob->contains; + + for (res = 0; res < cnt; res++) { +#ifdef F_SET_HIDE + if ((cur->flags & O_HIDDEN) && !display_hidden) { + cur = cur->next_inv; + res--; + continue; + } +#endif + d->item[res].type = T_OBJECT; + d->item[res].u.ob = cur; + add_ref(cur, "all_inventory"); + cur = cur->next_inv; + } + return d; +} +#endif + +/* Runs all elements of an array through ob::func + and replaces each value in arr by the value returned by ob::func + */ +#ifdef F_MAP +void +map_array (svalue_t * arg, int num_arg) +{ + array_t *arr = arg->u.arr; + array_t *r; + int size; + + if ((size = arr->size) == 0) r = &the_null_array; + else { + function_to_call_t ftc; + int cnt; + svalue_t *v; + + process_efun_callback(1, &ftc, F_MAP); + + r = int_allocate_array(size); + + push_refed_array(r); + + for (cnt = 0; cnt < size; cnt++) { + push_svalue(arr->item + cnt); + v = call_efun_callback(&ftc, 1); + if (v) assign_svalue_no_free(&r->item[cnt], v); + else break; + } + sp--; + } + + pop_n_elems(num_arg); + push_refed_array(r); +} + +void +map_string (svalue_t * arg, int num_arg) +{ + char *arr; + char *p; + funptr_t *fptr = 0; + int numex = 0; + object_t *ob = 0; + svalue_t *extra, *v; + const char *func; + + /* get a modifiable string */ + /* do not use arg after this; it has been copied or freed. + Put our result string on the stack where it belongs in case of an + error (note it is also in the right spot for the return value). + */ + unlink_string_svalue(arg); + arr = (char *)arg->u.string; + + if (arg[1].type == T_FUNCTION) { + fptr = arg[1].u.fp; + if (num_arg > 2) { + extra = arg + 2; + numex = num_arg - 2; + } + } else { + func = arg[1].u.string; + if (num_arg < 3) + ob = current_object; + else { + if (arg[2].type == T_OBJECT) + ob = arg[2].u.ob; + else if (arg[2].type == T_STRING) { + if ((ob = find_object(arg[2].u.string)) && !object_visible(ob)) + ob = 0; + } + if (num_arg > 3) { + extra = arg + 3; + numex = num_arg - 3; + } + if (!ob) + error("Bad argument 3 to map_string.\n"); + } + } + + for (p = arr; *p; p++) { + push_number((unsigned char)*p); + if (numex) + push_some_svalues(extra, numex); + v = fptr ? call_function_pointer(fptr, numex + 1) : apply(func, ob, 1 + numex, ORIGIN_EFUN); + /* no function or illegal return value is unaltered. + * Anyone got a better idea? A few idea: + * (1) insert strings? - algorithm needs changing + * (2) ignore them? - again, could require a realloc, since size would + * change + * (3) become ' ' or something + */ + if (!v) + break; + if (v->type == T_NUMBER && v->u.number != 0) + *p = ((char)(v->u.number)); + } + + pop_n_elems(num_arg - 1); + /* return value on stack */ +} +#endif + +#ifdef F_SORT_ARRAY +static function_to_call_t *sort_array_ftc; + +#define COMPARE_NUMS(x,y) (x < y ? -1 : (x > y ? 1 : 0)) + +array_t *builtin_sort_array (array_t * inlist, int dir) +{ + quickSort((char *) inlist->item, inlist->size, sizeof(inlist->item), + (dir<0) ? builtin_sort_array_cmp_rev : builtin_sort_array_cmp_fwd); + + return inlist; +} + +INLINE_STATIC int builtin_sort_array_cmp_fwd (void *vp1, void *vp2) +{ + svalue_t *p1 = (svalue_t *)vp1; + svalue_t *p2 = (svalue_t *)vp2; + switch(p1->type | p2->type) { + case T_STRING: + { + return strcmp(p1->u.string, p2->u.string); + } + + case T_NUMBER: + { + return COMPARE_NUMS(p1->u.number, p2->u.number); + } + + case T_REAL: + { + return COMPARE_NUMS(p1->u.real, p2->u.real); + } + + case T_ARRAY: + { + array_t *v1 = p1->u.arr, *v2 = p2->u.arr; + if (!v1->size || !v2->size) + error("Illegal to have empty array in array for sort_array()\n"); + + + switch(v1->item[0].type | v2->item[0].type) { + case T_STRING: + { + return strcmp(v1->item[0].u.string, v2->item[0].u.string); + } + + case T_NUMBER: + { + return COMPARE_NUMS(v1->item[0].u.number, v2->item[0].u.number); + } + + case T_REAL: + { + return COMPARE_NUMS(v1->item[0].u.real, v2->item[0].u.real); + } + default: + { + /* Temp. long err msg till I can think of a better one - Sym */ + error("sort_array() cannot handle arrays of arrays whose 1st elems\naren't strings/ints/floats\n"); + } + } + } + + } + error("built-in sort_array() can only handle homogeneous arrays of strings/ints/floats/arrays\n"); + return 0; +} + +INLINE_STATIC int builtin_sort_array_cmp_rev (void *vp1, void *vp2) +{ + svalue_t *p1 = (svalue_t *)vp1; + svalue_t *p2 = (svalue_t *)vp2; + switch(p1->type | p2->type) { + case T_STRING: + { + return strcmp(p2->u.string, p1->u.string); + } + + case T_NUMBER: + { + return COMPARE_NUMS(p2->u.number, p1->u.number); + } + + case T_REAL: + { + return COMPARE_NUMS(p2->u.real, p1->u.real); + } + + case T_ARRAY: + { + array_t *v1 = p1->u.arr, *v2 = p2->u.arr; + if (!v1->size || !v2->size) + error("Illegal to have empty array in array for sort_array()\n"); + + + switch(v1->item[0].type | v2->item[0].type) { + case T_STRING: + { + return strcmp(v2->item[0].u.string, v1->item[0].u.string); + } + + case T_NUMBER: + { + return COMPARE_NUMS(v2->item[0].u.number, v1->item[0].u.number); + } + + case T_REAL: + { + return COMPARE_NUMS(v2->item[0].u.real, v1->item[0].u.real); + } + default: + { + /* Temp. long err msg till I can think of a better one - Sym */ + error("sort_array() cannot handle arrays of arrays whose 1st elems\naren't strings/ints/floats\n"); + } + } + } + + } + error("built-in sort_array() can only handle homogeneous arrays of strings/ints/floats/arrays\n"); + return 0; +} + +INLINE_STATIC +int sort_array_cmp (void *vp1, void *vp2) { + svalue_t *p1 = (svalue_t *)vp1; + svalue_t *p2 = (svalue_t *)vp2; + svalue_t *d; + + push_svalue(p1); + push_svalue(p2); + + d = call_efun_callback(sort_array_ftc, 2); + if (!d || d->type != T_NUMBER) { + return 0; + } else { + long n = d->u.number; + //the sort functions all use int, so sometimes the numbers don't fit! + if(n) + if(n>0) + n=1; + else + n=-1; + return n; + } +} + +void +f_sort_array (void) +{ + svalue_t *arg = sp - st_num_arg + 1; + array_t *tmp = arg->u.arr; + int num_arg = st_num_arg; + + check_for_destr(tmp); + + switch(arg[1].type) { + case T_NUMBER: + { + tmp = builtin_sort_array(copy_array(tmp), arg[1].u.number); + break; + } + + case T_FUNCTION: + case T_STRING: + { + /* + * We use a global to communicate with the comparison function, + * so we have to be careful to make sure we can recurse (the + * callback might call sort_array itself). For this reason, the + * ftc structure is on the stack, and we just keep a pointer + * to it in a global, being careful to save and restore the old + * value. + */ + function_to_call_t ftc, *old_ptr; + + old_ptr = sort_array_ftc; + sort_array_ftc = &ftc; + process_efun_callback(1, &ftc, F_SORT_ARRAY); + + tmp = copy_array(tmp); + push_refed_array(tmp); + quickSort((char *) tmp->item, tmp->size, sizeof(tmp->item), sort_array_cmp); + sort_array_ftc = old_ptr; + sp--;//remove tmp from stack, but we don't want to free it! + break; + } + } + pop_n_elems(num_arg); + push_refed_array(tmp); //put it back +} +#endif + +/* + * deep_inventory() + * + * This function returns the recursive inventory of an object. The returned + * array of objects is flat, ie there is no structure reflecting the + * internal containment relations. + * + * This is Robocoder's deep_inventory(). It uses two passes in order to + * avoid costly temporary arrays (allocating, copying, adding, freeing, etc). + * The recursive call routines are: + * deep_inventory_count() and deep_inventory_collect() + * + * 20100824 Tiz added function parameter to allow filtering of result. + */ +#ifndef NO_ENVIRONMENT +static int valid_hide_flag; + +static int deep_inventory_count (object_t * ob) +{ + object_t *cur; + int cnt; + + cnt = 0; + + /* step through object's inventory and count visible objects */ + for (cur = ob->contains; cur; cur = cur->next_inv) { +#ifdef F_SET_HIDE + if (cur->flags & O_HIDDEN) { + if (!valid_hide_flag) + valid_hide_flag = 1 + + (valid_hide(current_object) ? 1 : 0); + if (valid_hide_flag & 2) { + cnt++; + cnt += deep_inventory_count(cur); + } + } else { +#endif + cnt++; + cnt += deep_inventory_count(cur); +#ifdef F_SET_HIDE + } +#endif + } + + return cnt; +} + +static void deep_inventory_collect (object_t * ob, array_t * inv, int * i, int max, funptr_t *fp) +{ + object_t *cur,*next; + svalue_t *fp_result; + + /* step through object's inventory and look for visible objects */ + for (cur = ob->contains; cur && *inext_inv; + if(fp) { + push_object(cur); + fp_result=call_function_pointer(fp,1); + if(!fp_result || (current_object->flags & O_DESTRUCTED)) { + *i=0; + return; + } + } + if(!fp || fp && fp_result->type==T_NUMBER && fp_result->u.number>0 && !(cur->flags & O_DESTRUCTED)) { +#ifdef F_SET_HIDE + if (cur->flags & O_HIDDEN) { + if (valid_hide_flag & 2) { + if(!fp || fp && fp_result->type==T_NUMBER && fp_result->u.number!=3) { + inv->item[*i].type = T_OBJECT; + inv->item[*i].u.ob = cur; + (*i)++; + add_ref(cur, "deep_inventory_collect"); + } + if(!fp || fp && fp_result->type==T_NUMBER && (fp_result->u.number==1 || fp_result->u.number==3)) + deep_inventory_collect(cur, inv, i, max, fp); + } + } else { +#endif + if(!fp || fp && fp_result->type==T_NUMBER && fp_result->u.number!=3) { + inv->item[*i].type = T_OBJECT; + inv->item[*i].u.ob = cur; + (*i)++; + add_ref(cur, "deep_inventory_collect"); + } + if(!fp || fp && fp_result->type==T_NUMBER && (fp_result->u.number==1 || fp_result->u.number==3)) + deep_inventory_collect(cur, inv, i, max, fp); +#ifdef F_SET_HIDE + } +#endif + } + } +} + +array_t *deep_inventory (object_t * ob, int take_top, funptr_t *fp) +{ + array_t *dinv; + int i,o; + svalue_t *fp_result; + + valid_hide_flag = 0; + + /* + * count visible objects in an object's inventory, and in their + * inventory, etc + */ + i = deep_inventory_count(ob); + if (take_top) + i++; + + if (i == 0) + return &the_null_array; + + if (i > max_array_size) + i = max_array_size; + + /* + * allocate an array + */ + dinv = int_allocate_array(o=i); + push_refed_array(dinv); + /* + * collect visible inventory objects recursively + */ + if (take_top) { + if(fp) { + push_object(ob); + fp_result=call_function_pointer(fp,1); + if(!fp_result || (current_object->flags & O_DESTRUCTED)){ + pop_stack(); //dinv + return &the_null_array; + } + } + if(!fp || fp && fp_result->type==T_NUMBER && fp_result->u.number>0 && + !(ob->flags & O_DESTRUCTED)) { + if(!fp || fp && fp_result->type==T_NUMBER && fp_result->u.number!=3) { + dinv->item[0].type = T_OBJECT; + dinv->item[0].u.ob = ob; + add_ref(ob, "deep_inventory"); + i=1; + } + if(!fp || fp && fp_result->type==T_NUMBER && (fp_result->u.number==1 || fp_result->u.number==3)) + deep_inventory_collect(ob, dinv, &i, o, fp); + } + } + else { + i = 0; + deep_inventory_collect(ob, dinv, &i, o, fp); + } + + // resize the array if we have filtered out values + if(fp && isize;c++) { + if(arr->item[c].type==T_OBJECT) { + i += deep_inventory_count(arr->item[c].u.ob); + if(take_top) + i++; + } + } + + if (i == 0) + return &the_null_array; + + if (i > max_array_size) + i = max_array_size; + + /* + * allocate an array + */ + dinv = int_allocate_array(o=i); + push_refed_array(dinv); + /* + * collect visible inventory objects recursively + */ + i=0; + for(c=0;isize;c++) { + if(arr->item[c].type==T_OBJECT) { + if(take_top){ + if(fp) { + push_object(arr->item[c].u.ob); + fp_result=call_function_pointer(fp,1); + if(!fp_result || (current_object->flags & O_DESTRUCTED)){ + pop_stack(); //free dinv + return &the_null_array; + } + } + if(!fp || fp && fp_result->type==T_NUMBER && fp_result->u.number>0 && + !(arr->item[c].u.ob->flags & O_DESTRUCTED)) { + if(!fp || fp && fp_result->type==T_NUMBER && fp_result->u.number!=3) { + dinv->item[i].type = T_OBJECT; + dinv->item[i].u.ob = arr->item[c].u.ob; + add_ref(arr->item[c].u.ob, "deep_inventory"); + i++; + } + if(!fp || fp && fp_result->type==T_NUMBER && (fp_result->u.number==1 || fp_result->u.number==3)) + deep_inventory_collect(arr->item[c].u.ob, dinv, &i, o, fp); + } + } + else + deep_inventory_collect(arr->item[c].u.ob, dinv, &i, o, fp); + } + } + + // resize the array if we have filtered out values + if(fp && iu.number - p2->u.number)){ + if(d == LONG_MIN) + d = p1->u.number > p2->u.number; + return d; + } + if ((d = p1->type - p2->type)) + return d; + return 0; +} + +INLINE_STATIC svalue_t *alist_sort (array_t * inlist) { + long size, j, curix, parix, child1, child2, flag; + svalue_t *sv_tab, *tmp, *table, *sv_ptr, val; + char *str; + + if (!(size = inlist->size)) return (svalue_t *)NULL; + if ((flag = (inlist->ref > 1))) { + sv_tab = CALLOCATE(size, svalue_t, TAG_TEMPORARY, "alist_sort: sv_tab"); + sv_ptr = inlist->item; + for (j = 0; j < size; j++) { + if (((tmp = (sv_ptr + j))->type == T_OBJECT) && (tmp->u.ob->flags & O_DESTRUCTED)) { + free_object(&tmp->u.ob, "alist_sort"); + sv_tab[j] = *tmp = const0u; + } else if ((tmp->type == T_STRING) && !(tmp->subtype == STRING_SHARED)) { + sv_tab[j].u.string = make_shared_string(tmp->u.string); + (tmp = sv_tab + j)->subtype = STRING_SHARED; + tmp->type = T_STRING; + } else assign_svalue_no_free(sv_tab + j, tmp); + + if ((curix = j)) { + val = *tmp; + + do { + parix = (curix - 1) >> 1; + if (alist_cmp(sv_tab + parix, sv_tab + curix) > 0) { + sv_tab[curix] = sv_tab[parix]; + sv_tab[parix] = val; + } + } while ((curix = parix)); + } + } + } else { + sv_tab = inlist->item; + for (j = 0; j < size; j++) { + if (((tmp = (sv_tab + j))->type == T_OBJECT) && (tmp->u.ob->flags & O_DESTRUCTED)) { + free_object(&tmp->u.ob, "alist_sort"); + *tmp = const0u; + } else if ((tmp->type == T_STRING) && !(tmp->subtype == STRING_SHARED)) { + str = make_shared_string(tmp->u.string); + free_string_svalue(tmp); + tmp->u.string = str; + tmp->subtype = STRING_SHARED; + } + + if ((curix = j)) { + val = *tmp; + + do { + parix = (curix - 1) >> 1; + if (alist_cmp(sv_tab + parix, sv_tab + curix) > 0) { + sv_tab[curix] = sv_tab[parix]; + sv_tab[parix] = val; + } + } while ((curix = parix)); + } + } + } + + table = CALLOCATE(size, svalue_t, TAG_TEMPORARY, "alist_sort: table"); + + for (j = 0; j < size; j++) { + table[j] = sv_tab[0]; + + for (curix = 0; ; ) { + child1 = (curix << 1) + 1; + child2 = child1 + 1; + + if (child2 < size && sv_tab[child2].type != T_INVALID && + (sv_tab[child1].type == T_INVALID || + alist_cmp(sv_tab+child1, sv_tab+child2) > 0)) { + child1 = child2; + } + if (child1 < size && sv_tab[child1].type != T_INVALID) { + sv_tab[curix] = sv_tab[child1]; + curix = child1; + } else break; + } + + sv_tab[curix].type = T_INVALID; + } + + if (flag) FREE((char *)sv_tab); + return table; +} + +array_t *subtract_array (array_t * minuend, array_t * subtrahend) { + array_t *difference; + svalue_t *source, *dest, *svt; + long i, size, o, d, l, h, msize; + + if (!(size = subtrahend->size)) { + subtrahend->ref--; + return minuend->ref > 1 ? (minuend->ref--, copy_array(minuend)) : minuend; + } + if (!(msize = minuend->size)) { + free_array(subtrahend); + return &the_null_array; + } + svt = alist_sort(subtrahend); + difference = ALLOC_ARRAY(msize); + for (source = minuend->item, dest = difference->item, i = msize; + i--; source++) { + + l = 0; + o = (h = size - 1) >> 1; + + if ((source->type == T_OBJECT) && (source->u.ob->flags & O_DESTRUCTED)) { + free_object(&source->u.ob, "subtract_array"); + *source = const0u; + } else if ((source->type == T_STRING) && !(source->subtype == STRING_SHARED)) { + svalue_t stmp = {T_STRING, STRING_SHARED}; + + if (!(stmp.u.string = findstring(source->u.string))) { + assign_svalue_no_free(dest++, source); + continue; + } + while ((d = alist_cmp(&stmp, svt + o))) { + if (d < 0) h = o - 1; + else l = o + 1; + if (l > h) { + assign_svalue_no_free(dest++, source); + break; + } + o = (l + h) >> 1; + } + continue; + } + + while ((d = alist_cmp(source, svt + o))) { + if (d < 0) h = o - 1; + else l = o + 1; + if (l > h) { + assign_svalue_no_free(dest++, source); + break; + } + o = (l + h) >> 1; + } + + } + i = size; + while (i--) free_svalue(svt + i, "subtract_array"); + FREE((char *) svt); + free_empty_array(subtrahend); + free_array(minuend); + msize = dest - difference->item; + return fix_array(difference, msize); +} + +array_t *intersect_array (array_t * a1, array_t * a2) { + array_t *a3; + long d, l, j, i, a1s = a1->size, a2s = a2->size, flag; + svalue_t *svt_1, *ntab, *sv_tab, *sv_ptr, val, *tmp; + long curix, parix, child1, child2; + + if (!a1s || !a2s) { + free_array(a1); + free_array(a2); + return &the_null_array; + } + + svt_1 = alist_sort(a1); + if ((flag = (a2->ref > 1))) { + sv_tab = CALLOCATE(a2s, svalue_t, TAG_TEMPORARY, "intersect_array: sv2_tab"); + sv_ptr = a2->item; + for (j = 0; j < a2s; j++) { + if (((tmp = (sv_ptr + j))->type == T_OBJECT) && (tmp->u.ob->flags & O_DESTRUCTED)) { + free_object(&tmp->u.ob, "intersect_array"); + sv_tab[j] = *tmp = const0u; + } else if ((tmp->type == T_STRING) && !(tmp->subtype == STRING_SHARED)) { + sv_tab[j].u.string = make_shared_string(tmp->u.string); + (tmp = sv_tab + j)->subtype = STRING_SHARED; + tmp->type = T_STRING; + } else assign_svalue_no_free(sv_tab + j, tmp); + + if ((curix = j)) { + val = *tmp; + + do { + parix = (curix - 1) >> 1; + if (alist_cmp(sv_tab + parix, sv_tab + curix) > 0) { + sv_tab[curix] = sv_tab[parix]; + sv_tab[parix] = val; + } + } while ((curix = parix)); + } + } + } else { + char *str; + + sv_tab = a2->item; + for (j = 0; j < a2s; j++) { + if (((tmp = (sv_tab + j))->type == T_OBJECT) && (tmp->u.ob->flags & O_DESTRUCTED)) { + free_object(&tmp->u.ob, "alist_sort"); + *tmp = const0u; + } else if ((tmp->type == T_STRING) && !(tmp->subtype == STRING_SHARED)) { + str = make_shared_string(tmp->u.string); + free_string_svalue(tmp); + tmp->u.string = str; + tmp->subtype = STRING_SHARED; + } + + if ((curix = j)) { + val = *tmp; + + do { + parix = (curix - 1) >> 1; + if (alist_cmp(sv_tab + parix, sv_tab + curix) > 0) { + sv_tab[curix] = sv_tab[parix]; + sv_tab[parix] = val; + } + } while ((curix = parix)); + } + } + } + + a3 = ALLOC_ARRAY(a2s); + ntab = a3->item; + + l = i = 0; + + for (j = 0; j < a2s; j++) { + val = sv_tab[0]; + + while ((d = alist_cmp(&val, &svt_1[i])) > 0) { + if (++i >= a1s) goto settle_business; + } + + if (!d) { + ntab[l++] = val; + } else { + free_svalue(&val, "intersect_array"); + } + + for (curix = 0;; ) { + child1 = (curix << 1) + 1; + child2 = child1 + 1; + + if (child2 < a2s && sv_tab[child2].type != T_INVALID && + (sv_tab[child1].type == T_INVALID || + alist_cmp(sv_tab + child1, sv_tab + child2) > 0)) { + child1 = child2; + } + + if (child1 < a2s && sv_tab[child1].type != T_INVALID) { + sv_tab[curix] = sv_tab[child1]; + curix = child1; + } else break; + } + + sv_tab[curix].type = T_INVALID; + } + + settle_business: + + curix = a2s; + while (curix--) { + if (sv_tab[curix].type != T_INVALID) free_svalue(sv_tab + curix, "intersect_array:2"); + } + + i = a1s; + while (i--) free_svalue(svt_1 + i, "intersect_array"); + FREE((char *)svt_1); + + free_empty_array(a1); + + if (flag) { + a2->ref--; + FREE((char *) sv_tab); + } else + dealloc_empty_array(a2); + + return fix_array(a3, l); +} + +array_t *union_array (array_t * a1, array_t * a2) { + int a1s = a1->size, a2s = a2->size; + long d, l, j, i, cnt, flag; + array_t *a3; /* destination */ + svalue_t *svt_1, *ntab, *sv_tab, *tmp, *sv_ptr, val; + long curix, parix, child1, child2; + + if (a1s == 0) { + a1->ref--; + return a2->ref > 1 ? (a2->ref--, copy_array(a2)) : a2; + } + + if (a2s == 0 || a1 == a2) { + a2->ref--; + return a1->ref > 1 ? (a1->ref--, copy_array(a1)) : a1; + } + /* allocating a new place, a1s + a2s must be enough */ + d = a1s + a2s; + if (d < 0 || d > max_array_size) + error("result of array union could be greater than maximum array size.\n"); + a3 = int_allocate_empty_array(d); + tmp = a1->item; + ntab = a3->item; + l = cnt = a1s; + while (cnt--) + assign_svalue_no_free(ntab + cnt, tmp + cnt); + + svt_1 = alist_sort(a1); + if ((flag = (a2->ref > 1))) { + sv_tab = CALLOCATE(a2s, svalue_t, TAG_TEMPORARY, "union_array: sv2_tab"); + sv_ptr = a2->item; + for (j = 0; j < a2s; j++) { + if (((tmp = (sv_ptr + j))->type == T_OBJECT) && (tmp->u.ob->flags & O_DESTRUCTED)) { + free_object(&tmp->u.ob, "union_array"); + sv_tab[j] = *tmp = const0u; + } + else if ((tmp->type == T_STRING) && !(tmp->subtype == STRING_SHARED)) { + sv_tab[j].u.string = make_shared_string(tmp->u.string); + (tmp = sv_tab + j)->subtype = STRING_SHARED; + tmp->type = T_STRING; + } + else assign_svalue_no_free(sv_tab + j, tmp); + + if ((curix = j)) { + val = *tmp; + + do { + parix = (curix - 1) >> 1; + if (alist_cmp(sv_tab + parix, sv_tab + curix) > 0) { + sv_tab[curix] = sv_tab[parix]; + sv_tab[parix] = val; + } + } while ((curix = parix)); + } + } + } else { + char *str; + + sv_tab = a2->item; + for (j = 0; j < a2s; j++) { + if (((tmp = (sv_tab + j))->type == T_OBJECT) && (tmp->u.ob->flags & O_DESTRUCTED)) { + free_object(&tmp->u.ob, "union_array"); + *tmp = const0u; + } + else if ((tmp->type == T_STRING) && !(tmp->subtype == STRING_SHARED)) { + str = make_shared_string(tmp->u.string); + free_string_svalue(tmp); + tmp->u.string = str; + tmp->subtype = STRING_SHARED; + } + + if ((curix = j)) { + val = *tmp; + + do { + parix = (curix - 1) >> 1; + if (alist_cmp(sv_tab + parix, sv_tab + curix) > 0) { + sv_tab[curix] = sv_tab[parix]; + sv_tab[parix] = val; + } + } while ((curix = parix)); + } + } + } + + i = 0; + + for (j = 0; j < a2s; j++) { + val = sv_tab[0]; + + while (i < a1s && (d = alist_cmp(&val, &svt_1[i])) > 0) { + i++; + } + + if (d) { + ntab[l++] = val; + } else { + free_svalue(&val, "union_array"); + } + + for (curix = 0;; ) { + child1 = (curix << 1) + 1; + child2 = child1 + 1; + + if (child2 < a2s && sv_tab[child2].type != T_INVALID && + (sv_tab[child1].type == T_INVALID || + alist_cmp(sv_tab + child1, sv_tab + child2) > 0)) { + child1 = child2; + } + + if (child1 < a2s && sv_tab[child1].type != T_INVALID) { + sv_tab[curix] = sv_tab[child1]; + curix = child1; + } + else break; + } + + sv_tab[curix].type = T_INVALID; + } + + curix = a2s; + while (curix--) { + if (sv_tab[curix].type != T_INVALID) + free_svalue(sv_tab + curix, "union_array:2"); + } + + i = a1s; + while (i--) free_svalue(svt_1 + i, "union_array"); + FREE((char *)svt_1); + + free_empty_array(a1); + + if (flag) { + a2->ref--; + FREE((char *)sv_tab); + } else { + dealloc_empty_array(a2); + } + a3 = resize_array(a3, l); + a3->ref = 1; + + return a3; +} + +int match_single_regexp (const char * str, const char * pattern) { + struct regexp *reg; + int ret; + + regexp_user = EFUN_REGEXP; + reg = regcomp((unsigned char *)pattern, 0); + if (!reg) error(regexp_error); + ret = regexec(reg, str); + FREE(reg); + return ret; +} + +array_t *match_regexp (array_t * v, const char * pattern, int flag) { + struct regexp *reg; + char *res; + int num_match, size, match = !(flag & 2); + array_t *ret; + svalue_t *sv1, *sv2; + + regexp_user = EFUN_REGEXP; + if (!(size = v->size)) return &the_null_array; + reg = regcomp((unsigned char *)pattern, 0); + if (!reg) error(regexp_error); + res = (char *)DMALLOC(size, TAG_TEMPORARY, "match_regexp: res"); + sv1 = v->item + size; + num_match = 0; + while (size--) { + if (!((--sv1)->type == T_STRING) || (regexec(reg, sv1->u.string) != match)) { + res[size] = 0; + } else { + res[size] = 1; + num_match++; + } + } + + flag &= 1; + ret = allocate_empty_array(num_match << flag); + sv2 = ret->item + (num_match << flag); + size = v->size; + while (size--) { + if (res[size]) { + if (flag) { + (--sv2)->type = T_NUMBER; + sv2->u.number = size + 1; + } + (--sv2)->type = T_STRING; + sv1 = v->item + size; + *sv2 = *sv1; + if (sv1->subtype & STRING_COUNTED) { + INC_COUNTED_REF(sv1->u.string); + ADD_STRING(MSTR_SIZE(sv1->u.string)); + } + if (!--num_match) break; + } + } + FREE(res); + FREE((char *) reg); + return ret; +} + +/* + * Returns a list of all inherited files. + * + * Must be fixed so that any number of files can be returned, now max 256 + * (Sounds like a contradiction to me /Lars). + */ +array_t *deep_inherit_list (object_t * ob) +{ + array_t *ret; + program_t *pr, *plist[256]; + int il, il2, next, cur; + + plist[0] = ob->prog; + next = 1; + cur = 0; + + for (; cur < next && next < 256; cur++) { + pr = plist[cur]; + for (il2 = 0; il2 < pr->num_inherited; il2++) + plist[next++] = pr->inherit[il2].prog; + } + + next--; + ret = allocate_empty_array(next); + + for (il = 0; il < next; il++) { + pr = plist[il + 1]; + ret->item[il].type = T_STRING; + ret->item[il].subtype = STRING_MALLOC; + ret->item[il].u.string = add_slash(pr->filename); + } + return ret; +} + +/* + * Returns a list of the immediate inherited files. + * + */ +array_t *inherit_list (object_t * ob) +{ + array_t *ret; + program_t *pr, *plist[256]; + int il, il2, next, cur; + + plist[0] = ob->prog; + next = 1; + cur = 0; + + pr = plist[cur]; + for (il2 = 0; il2 < pr->num_inherited; il2++) { + plist[next++] = pr->inherit[il2].prog; + } + + next--; /* don't count the file itself */ + ret = allocate_empty_array(next); + + for (il = 0; il < next; il++) { + pr = plist[il + 1]; + ret->item[il].type = T_STRING; + ret->item[il].subtype = STRING_MALLOC; + ret->item[il].u.string = add_slash(pr->filename); + } + return ret; +} + +#ifdef F_LIVINGS +static int livings_filter (object_t * ob, void * data) +{ + return (ob->flags & O_ENABLE_COMMANDS); +} + +array_t *livings() +{ + int count; + object_t **list; + array_t *ret; + + get_objects(&list, &count, livings_filter, 0); + + if (count > max_array_size) + count = max_array_size; + ret = allocate_empty_array(count); + while (count--) { + ret->item[count].type = T_OBJECT; + ret->item[count].u.ob = list[count]; + add_ref(list[count], "livings"); + } + + pop_stack(); + return ret; +} +#endif + +#ifdef F_OBJECTS +void f_objects (void) +{ + int count, i; + const char *func = 0; + object_t **list; + array_t *ret; + funptr_t *f = 0; + + int num_arg = st_num_arg; + + if (!num_arg) func = 0; + else if (sp->type == T_FUNCTION) f = sp->u.fp; + else func = sp->u.string; + + get_objects(&list, &count, 0, 0); + if (f || func) { + /* NOTE: If an object's hidden status changes during a callback, that + * change will NOT be reflected in the returned array. If the caller + * is destructed in a callback or the callback function does not exist, + * abort and return the_null_array. + */ + for (i = 0; i < count; i++) { + svalue_t *v; + + push_object(list[i]); + if (f){ + v = call_function_pointer(f, 1); + } else + v = apply(func, current_object, 1, ORIGIN_EFUN); + if (!v || (current_object->flags & O_DESTRUCTED)) { + pop_n_elems(num_arg + 1); + push_refed_array(&the_null_array); + return; + } + if (v->type == T_NUMBER && !v->u.number) + list[i] = 0; + } + for (i = 0; i < count; i++) { + if (!list[i] || (list[i]->flags & O_DESTRUCTED)) + list[i--] = list[--count]; + } + } + + if (count > max_array_size) + count = max_array_size; + ret = allocate_empty_array(count); + for (i = 0; i < count; i++) { + ret->item[i].type = T_OBJECT; + ret->item[i].u.ob = list[i]; + add_ref(list[i], "f_objects"); + } + + pop_n_elems(num_arg + 1); /* include our temporary 'string' */ + push_refed_array(ret); +} +#endif + +#ifdef F_REG_ASSOC +/* + * write(sprintf("%O", reg_assoc("testhahatest", ({ "haha", "te" }), + * ({ 2,3 }), 4))); + + * -------- + * ({ + * ({ "", "te", "st", "haha", "", "te", "st" }), + * ({ 4, 3, 4, 2, 4, 3, 4 }) + * }) + * + */ +array_t *reg_assoc (svalue_t *str, array_t *pat, array_t *tok, svalue_t *def) { + int i, size; + const char *tmp; + array_t *ret; + + regexp_user = EFUN_REGEXP; + if ((size = pat->size) != tok->size) + error("Pattern and token array sizes must be identical.\n"); + + for (i = 0; i < size; i++) { + if (!(pat->item[i].type == T_STRING)) + error("Non-string found in pattern array.\n"); + } + + ret = int_allocate_empty_array(2); + + if (size) { + struct regexp **rgpp; + struct reg_match { + int tok_i; + const char *begin, *end; + struct reg_match *next; + } *rmp = (struct reg_match *) 0, *rmph = (struct reg_match *) 0; + int num_match = 0, length; + svalue_t *sv1, *sv2, *sv; + int regindex; + struct regexp *tmpreg; + const char *laststart, *currstart; + + rgpp = CALLOCATE(size, struct regexp *, TAG_TEMPORARY, "reg_assoc : rgpp"); + for (i = 0; i < size; i++) { + if (!(rgpp[i] = regcomp((unsigned char *)pat->item[i].u.string, 0))) { + while (i--) + FREE((char *)rgpp[i]); + FREE((char *) rgpp); + free_empty_array(ret); + error(regexp_error); + } + } + + tmp = str->u.string; + while (*tmp) { + + /* Sigh - need a kludge here - Randor */ + /* In the future I may alter regexp.c to include branch info */ + /* so as to minimize checks here - Randor 5/30/94 */ + + laststart = 0; + regindex = -1; + + for (i = 0; i < size; i++) { + if (regexec(tmpreg = rgpp[i], tmp)) { + currstart = tmpreg->startp[0]; + if (tmp == currstart) { + regindex = i; + break; + } + if (!laststart || currstart < laststart) { + laststart = currstart; + regindex = i; + } + } + } + + if (regindex >= 0) { + num_match++; + if (rmp) { + rmp->next = ALLOCATE(struct reg_match, + TAG_TEMPORARY, "reg_assoc : rmp->next"); + rmp = rmp->next; + } + else rmph = rmp = + ALLOCATE(struct reg_match, TAG_TEMPORARY, "reg_assoc : rmp"); + tmpreg = rgpp[regindex]; + rmp->begin = tmpreg->startp[0]; + rmp->end = tmp = tmpreg->endp[0]; + rmp->tok_i = regindex; + rmp->next = (struct reg_match *) 0; + } + else break; + + /* The following is from regexplode, to prevent i guess infinite */ + /* loops on "" patterns - Randor 5/29/94 */ + if (rmp->begin == tmp && (!*++tmp)) break; + } + + sv = ret->item; + sv->type = T_ARRAY; + sv1 = (sv->u.arr = allocate_empty_array(2*num_match + 1))->item; + + sv++; + sv->type = T_ARRAY; + sv2 = (sv->u.arr = allocate_empty_array(2*num_match + 1))->item; + + rmp = rmph; + + if(!rmp && num_match) + error("internal error in reg_assoc\n"); + + tmp = str->u.string; + + while (num_match--) { + char *svtmp; + + length = rmp->begin - tmp; + sv1->type = T_STRING; + sv1->subtype = STRING_MALLOC; + sv1->u.string = svtmp= new_string(length, "reg_assoc : sv1"); + strncpy(svtmp, tmp, length); + svtmp[length] = 0; + sv1++; + assign_svalue_no_free(sv2++, def); + tmp += length; + length = rmp->end - rmp->begin; + sv1->type = T_STRING; + sv1->subtype = STRING_MALLOC; + sv1->u.string = svtmp = new_string(length, "reg_assoc : sv1"); + strncpy(svtmp, tmp, length); + svtmp[length] = 0; + sv1++; + assign_svalue_no_free(sv2++, &tok->item[rmp->tok_i]); + tmp += length; + rmp = rmp->next; + } + sv1->type = T_STRING; + sv1->subtype = STRING_MALLOC; + sv1->u.string = string_copy(tmp, "reg_assoc"); + assign_svalue_no_free(sv2, def); + for (i=0; inext; + FREE((char *) rmp); + } + return ret; + } + else { /* Default match */ + svalue_t *temp; + svalue_t *sv; + + (sv = ret->item)->type = T_ARRAY; + temp = (sv->u.arr = int_allocate_empty_array(1))->item; + assign_svalue_no_free(temp, str); + sv = &ret->item[1]; + sv->type = T_ARRAY; + assign_svalue_no_free((sv->u.arr = allocate_empty_array(1))->item, def); + return ret; + } +} +#endif diff --git a/fluffos-2.23-ds03/array.h b/fluffos-2.23-ds03/array.h new file mode 100644 index 0000000..eab2cbb --- /dev/null +++ b/fluffos-2.23-ds03/array.h @@ -0,0 +1,76 @@ +#ifndef ARRAY_H +#define ARRAY_H + +/* It is usually better to include "lpc_incl.h" instead of including this + directly */ + +typedef struct array_s { + unsigned short ref; +#ifdef DEBUG + int extra_ref; +#endif + int size; +#ifdef PACKAGE_MUDLIB_STATS + statgroup_t stats; /* creator of the array */ +#endif + svalue_t item[1]; +} array_t; + +extern array_t the_null_array; + +/* + * array.c + */ +#ifdef ARRAY_STATS +extern int num_arrays; +extern int total_array_size; +#endif + +int sameval (svalue_t *, svalue_t *); +array_t *allocate_array2 (int, svalue_t *); +array_t *allocate_array (int); +array_t *allocate_empty_array (int); +void free_array (array_t *); +void free_empty_array (array_t *); +array_t *add_array (array_t *, array_t *); +void implode_array (funptr_t *, array_t *, svalue_t *, int); +array_t *subtract_array (array_t *, array_t *); +array_t *slice_array (array_t *, int, int); +array_t *explode_string (const char *, int, const char *, int); +char *implode_string (array_t *, const char *, int); +array_t *users (void); +array_t *commands (object_t *); +void filter_array (svalue_t *, int); +void filter_string (svalue_t *, int); +array_t *deep_inherit_list (object_t *); +array_t *inherit_list (object_t *); +array_t *children (const char *); +array_t *livings (void); +array_t *objects (funptr_t *); +array_t *all_inventory (object_t *, int); +array_t *deep_inventory (object_t *, int, funptr_t *); +array_t *deep_inventory_array (array_t *, int, funptr_t *); +array_t *filter (array_t *, funptr_t *, svalue_t *); +array_t *builtin_sort_array (array_t *, int); +array_t *fp_sort_array (array_t *, funptr_t *); +array_t *sort_array (array_t *, char *, object_t *); +array_t *make_unique (array_t *, char *, funptr_t *, svalue_t *); +void map_string (svalue_t *arg, int num_arg); +void map_array (svalue_t *arg, int num_arg); +array_t *intersect_array (array_t *, array_t *); +int match_single_regexp (const char *, const char *); +array_t *match_regexp (array_t *, const char *, int); +array_t *reg_assoc (svalue_t *, array_t *, array_t *, svalue_t *); +void dealloc_array (array_t *); +array_t *union_array (array_t *, array_t *); +array_t *copy_array (array_t * p); +array_t *resize_array (array_t * p, unsigned int n); + +#define ALLOC_ARRAY(nelem) \ + (array_t *)DXALLOC(sizeof (array_t) + \ + sizeof(svalue_t) * (nelem - 1), TAG_ARRAY, "ALLOC_ARRAY") +#define RESIZE_ARRAY(vec, nelem) \ + (array_t *)DREALLOC(vec, sizeof (array_t) + \ + sizeof(svalue_t) * (nelem - 1), TAG_ARRAY, "RESIZE_ARRAY") + +#endif diff --git a/fluffos-2.23-ds03/avltree.c b/fluffos-2.23-ds03/avltree.c new file mode 100644 index 0000000..99b4df3 --- /dev/null +++ b/fluffos-2.23-ds03/avltree.c @@ -0,0 +1,414 @@ +/* + * avltree.c + * + * This program text was created by Paul Vixie using examples from the book: + * "Algorithms & Data Structures," Niklaus Wirth, Prentice-Hall, 1986, ISBN + * 0-13-022005-1. This code and associated documentation is hereby placed + * in the public domain. + */ + +/********************************* README ********************************* + +AVL Trees V1.0 +24-July-1987 +Paul Vixie + +This library and test program are useful for creating and using balanced +binary trees (AVL trees). The tree is held in memory, using malloc(3) to +allocate storage. A better version would allow file-based trees in +addition; once memory mapped files hit the UNIX(tm) community, this will +be much easier to do. In the meanwhile, these routines have been very +useful to be for symbol tables and the like. (Yes, I'm sure hashing is +better in some way, but I've used this for symbol tables, just the same.) + +I cannot take credit for the algorithms. See "Algorithms & Data Structures," +Niklaus Wirth, Prentice-Hall 1986, ISBN 0-13-022005-1. This is an update of +Wirth's previous book, titled "Algorythms + Data Structures = Programs," +which used Pascal as the language for examples. This later book uses the +newer Modula-2 for it's examples; this tree code was created using the +Modula-2 examples as guidelines. At the time I typed this stuff in (about +a year ago, in July 1987), I understood how it all worked. Today, well... + +This code is hereby placed in the public domain, unless restrictions apply +from Prentice-Hall on the algorithms themselves. If you use or redistribute +this code, please leave my name (and Wirth's) in the comments. + +**************************************************************************/ + +#include "std.h" +#include "avltree.h" + +/* + * Prototypes for local functions + */ +static void sprout (tree **, char *, int *, int (*) (void *, void *), int (*) (void *)); +static int avldelete (tree **, int (*) (void *, void *), char *, int (*) (void *), int *, int *); +static void del (tree **, int *, tree **, int (*) (void *), int *); +static void balanceL (tree **, int *); +static void balanceR (tree **, int *); + + +void tree_init (tree ** ppr_tree) +{ + *ppr_tree = NULL; + return; +} + + +char *tree_srch(tree *ppr_tree, int (*pfi_compare) (void *, void *), char *pc_user){ + register int i_comp; + + while (ppr_tree) { + i_comp = (*pfi_compare) (pc_user, ppr_tree->tree_p); + if (i_comp > 0) { + ppr_tree = ppr_tree->tree_r; + continue; + } + if (i_comp < 0) { + ppr_tree = ppr_tree->tree_l; + continue; + } + /* + * not higher, not lower... this must be the one. + */ + return ppr_tree->tree_p; + } + + /* + * grounded. NOT found. + */ + return NULL; +} + + +void tree_add(tree **ppr_tree, int (*pfi_compare) (void *, void *), char *pc_user, int (*pfi_delete) (void *)){ + int i_balance = 0; + + sprout(ppr_tree, pc_user, &i_balance, pfi_compare, pfi_delete); + return; +} + + +static void sprout(tree **ppr, char *pc_data, int *pi_balance, int (*pfi_compare) (void *, void *), int (*pfi_delete) (void *)){ + tree *p1, *p2; + int cmp; + + /* + * are we grounded? if so, add the node "here" and set the rebalance + * flag, then exit. + */ + if (!*ppr) { + *ppr = ALLOCATE(tree, TAG_UID, "sprout"); + (*ppr)->tree_l = NULL; + (*ppr)->tree_r = NULL; + (*ppr)->tree_b = 0; + (*ppr)->tree_p = pc_data; + *pi_balance = 1; + return; + } + /* + * compare the data using routine passed by caller. + */ + cmp = (*pfi_compare) (pc_data, (*ppr)->tree_p); + + /* + * if LESS, prepare to move to the left. + */ + if (cmp < 0) { + sprout(&(*ppr)->tree_l, pc_data, pi_balance, + pfi_compare, pfi_delete); + if (*pi_balance) { /* left branch has grown longer */ + switch ((*ppr)->tree_b) { + case 1: /* right branch WAS longer; balance is ok now */ + (*ppr)->tree_b = 0; + *pi_balance = 0; + break; + case 0: /* balance WAS okay; now left branch longer */ + (*ppr)->tree_b = -1; + break; + case -1: + /* left branch was already too long. rebalnce */ + p1 = (*ppr)->tree_l; + if (p1->tree_b == -1) { /* LL */ + (*ppr)->tree_l = p1->tree_r; + p1->tree_r = *ppr; + (*ppr)->tree_b = 0; + *ppr = p1; + } else { /* double LR */ + p2 = p1->tree_r; + p1->tree_r = p2->tree_l; + p2->tree_l = p1; + + (*ppr)->tree_l = p2->tree_r; + p2->tree_r = *ppr; + + if (p2->tree_b == -1) + (*ppr)->tree_b = 1; + else + (*ppr)->tree_b = 0; + + if (p2->tree_b == 1) + p1->tree_b = -1; + else + p1->tree_b = 0; + *ppr = p2; + } /* else */ + (*ppr)->tree_b = 0; + *pi_balance = 0; + } /* switch */ + } /* if */ + return; + } /* if */ + /* + * if MORE, prepare to move to the right. + */ + if (cmp > 0) { + sprout(&(*ppr)->tree_r, pc_data, pi_balance, + pfi_compare, pfi_delete); + if (*pi_balance) { /* right branch has grown longer */ + switch ((*ppr)->tree_b) { + case -1: + (*ppr)->tree_b = 0; + *pi_balance = 0; + break; + case 0: + (*ppr)->tree_b = 1; + break; + case 1: + p1 = (*ppr)->tree_r; + if (p1->tree_b == 1) { /* RR */ + (*ppr)->tree_r = p1->tree_l; + p1->tree_l = *ppr; + (*ppr)->tree_b = 0; + *ppr = p1; + } else { /* double RL */ + p2 = p1->tree_l; + p1->tree_l = p2->tree_r; + p2->tree_r = p1; + + (*ppr)->tree_r = p2->tree_l; + p2->tree_l = *ppr; + + if (p2->tree_b == 1) + (*ppr)->tree_b = -1; + else + (*ppr)->tree_b = 0; + + if (p2->tree_b == -1) + p1->tree_b = 1; + else + p1->tree_b = 0; + + *ppr = p2; + } /* else */ + (*ppr)->tree_b = 0; + *pi_balance = 0; + } /* switch */ + } /* if */ + return; + } /* if */ + /* + * not less, not more: this is the same key! replace... + */ + *pi_balance = 0; + if (pfi_delete) + (*pfi_delete) ((*ppr)->tree_p); + (*ppr)->tree_p = pc_data; + return; +} + + +int tree_delete(tree **ppr_p, int (*pfi_compare) (void *, void *), char *pc_user, int (*pfi_uar) (void *)){ + int i_balance = 0, i_uar_called = 0; + + return avldelete(ppr_p, pfi_compare, pc_user, pfi_uar, + &i_balance, &i_uar_called); +} + + +static int avldelete(tree **ppr_p, int (*pfi_compare) (void *, void *), char *pc_user, int (*pfi_uar) (void *), int *pi_balance, int *pi_uar_called){ + tree *pr_q; + int i_comp, i_ret; + + if (*ppr_p == NULL) { + return 0; + } + i_comp = (*pfi_compare) ((*ppr_p)->tree_p, pc_user); + if (i_comp > 0) { + i_ret = avldelete(&(*ppr_p)->tree_l, pfi_compare, pc_user, pfi_uar, + pi_balance, pi_uar_called); + if (*pi_balance) + balanceL(ppr_p, pi_balance); + } else if (i_comp < 0) { + i_ret = avldelete(&(*ppr_p)->tree_r, pfi_compare, pc_user, pfi_uar, + pi_balance, pi_uar_called); + if (*pi_balance) + balanceR(ppr_p, pi_balance); + } else { + pr_q = *ppr_p; + if (pr_q->tree_r == NULL) { + *ppr_p = pr_q->tree_l; + *pi_balance = 1; + } else if (pr_q->tree_l == NULL) { + *ppr_p = pr_q->tree_r; + *pi_balance = 1; + } else { + del(&pr_q->tree_l, pi_balance, &pr_q, pfi_uar, + pi_uar_called); + if (*pi_balance) + balanceL(ppr_p, pi_balance); + } + FREE(pr_q); + if (!*pi_uar_called && pfi_uar) + (*pfi_uar) (pr_q->tree_p); + i_ret = 1; + } + return i_ret; +} + + +static void del(tree **ppr_r, int *pi_balance, tree **ppr_q, int (*pfi_uar) (void *), int *pi_uar_called){ + if ((*ppr_r)->tree_r != NULL) { + del(&(*ppr_r)->tree_r, pi_balance, ppr_q, pfi_uar, + pi_uar_called); + if (*pi_balance) + balanceR(ppr_r, pi_balance); + } else { + if (pfi_uar) + (*pfi_uar) ((*ppr_q)->tree_p); + *pi_uar_called = 1; + (*ppr_q)->tree_p = (*ppr_r)->tree_p; + *ppr_q = *ppr_r; + *ppr_r = (*ppr_r)->tree_l; + *pi_balance = 1; + } + + return; +} + + +static void balanceL (tree ** ppr_p, int * pi_balance){ + tree *p1, *p2; + int b1, b2; + + switch ((*ppr_p)->tree_b) { + case -1: + (*ppr_p)->tree_b = 0; + break; + case 0: + (*ppr_p)->tree_b = 1; + *pi_balance = 0; + break; + case 1: + p1 = (*ppr_p)->tree_r; + b1 = p1->tree_b; + if (b1 >= 0) { + (*ppr_p)->tree_r = p1->tree_l; + p1->tree_l = *ppr_p; + if (b1 == 0) { + (*ppr_p)->tree_b = 1; + p1->tree_b = -1; + *pi_balance = 0; + } else { + (*ppr_p)->tree_b = 0; + p1->tree_b = 0; + } + *ppr_p = p1; + } else { + p2 = p1->tree_l; + b2 = p2->tree_b; + p1->tree_l = p2->tree_r; + p2->tree_r = p1; + (*ppr_p)->tree_r = p2->tree_l; + p2->tree_l = *ppr_p; + if (b2 == 1) + (*ppr_p)->tree_b = -1; + else + (*ppr_p)->tree_b = 0; + if (b2 == -1) + p1->tree_b = 1; + else + p1->tree_b = 0; + *ppr_p = p2; + p2->tree_b = 0; + } + } + return; +} + + +static void balanceR (tree ** ppr_p, int * pi_balance){ + tree *p1, *p2; + int b1, b2; + + switch ((*ppr_p)->tree_b) { + case 1: + (*ppr_p)->tree_b = 0; + break; + case 0: + (*ppr_p)->tree_b = -1; + *pi_balance = 0; + break; + case -1: + p1 = (*ppr_p)->tree_l; + b1 = p1->tree_b; + if (b1 <= 0) { + (*ppr_p)->tree_l = p1->tree_r; + p1->tree_r = *ppr_p; + if (b1 == 0) { + (*ppr_p)->tree_b = -1; + p1->tree_b = 1; + *pi_balance = 0; + } else { + (*ppr_p)->tree_b = 0; + p1->tree_b = 0; + } + *ppr_p = p1; + } else { + p2 = p1->tree_r; + b2 = p2->tree_b; + p1->tree_r = p2->tree_l; + p2->tree_l = p1; + (*ppr_p)->tree_l = p2->tree_r; + p2->tree_r = *ppr_p; + if (b2 == -1) + (*ppr_p)->tree_b = 1; + else + (*ppr_p)->tree_b = 0; + if (b2 == 1) + p1->tree_b = -1; + else + p1->tree_b = 0; + *ppr_p = p2; + p2->tree_b = 0; + } + } + return; +} + + +int tree_trav(tree **ppr_tree, int (*pfi_uar) (void *)){ + if (!*ppr_tree) + return 1; + + if (!tree_trav(&(**ppr_tree).tree_l, pfi_uar)) + return 0; + if (!(*pfi_uar) ((**ppr_tree).tree_p)) + return 0; + if (!tree_trav(&(**ppr_tree).tree_r, pfi_uar)) + return 0; + return 1; +} + + +void tree_mung(tree **ppr_tree, int (*pfi_uar) (void *)){ + if (*ppr_tree) { + tree_mung(&(**ppr_tree).tree_l, pfi_uar); + tree_mung(&(**ppr_tree).tree_r, pfi_uar); + if (pfi_uar) + (*pfi_uar) ((**ppr_tree).tree_p); + FREE(*ppr_tree); + *ppr_tree = NULL; + } + return; +} diff --git a/fluffos-2.23-ds03/avltree.h b/fluffos-2.23-ds03/avltree.h new file mode 100644 index 0000000..5b471c4 --- /dev/null +++ b/fluffos-2.23-ds03/avltree.h @@ -0,0 +1,23 @@ +/* + * avltree.h + * + * Written by Paul Vixie + */ + +#ifndef _AVLTREE_H_ +#define _AVLTREE_H_ + +typedef struct tree_s { + struct tree_s *tree_l, *tree_r; /* left & right branches */ + char *tree_p; /* data */ + short tree_b; /* balance information */ +} tree; + +void tree_init (tree **); +char *tree_srch (tree *, int (*) (void *, void *), char *); +void tree_add (tree **, int (*) (void *, void *), char *, int (*) (void *)); +int tree_delete (tree **, int (*) (void *, void *), char *, int (*) (void *)); +int tree_trav (tree **, int (*) (void *)); +void tree_mung (tree **, int (*) (void *)); + +#endif /* _AVLTREE_H_ */ diff --git a/fluffos-2.23-ds03/backend.c b/fluffos-2.23-ds03/backend.c new file mode 100644 index 0000000..1b1842e --- /dev/null +++ b/fluffos-2.23-ds03/backend.c @@ -0,0 +1,669 @@ +/* 92/04/18 - cleaned up stylistically by Sulam@TMI */ +#include "std.h" +#include "lpc_incl.h" +#include "backend.h" +#include "comm.h" +#include "replace_program.h" +#include "socket_efuns.h" +#include "call_out.h" +#include "port.h" +#include "master.h" +#include "eval.h" + +#ifdef PACKAGE_ASYNC +#include "packages/async.h" +#endif + +#ifdef WIN32 +#include +void CDECL alarm_loop (void *); +#endif + +error_context_t *current_error_context = 0; + +/* + * The 'current_time' is updated in the call_out cycles + */ +long current_time; + +object_t *current_heart_beat; +static void look_for_objects_to_swap (void); +void call_heart_beat (void); + +#if 0 +static void report_holes (void); +#endif + +/* + * There are global variables that must be zeroed before any execution. + * In case of errors, there will be a LONGJMP(), and the variables will + * have to be cleared explicitely. They are normally maintained by the + * code that use them. + * + * This routine must only be called from top level, not from inside + * stack machine execution (as stack will be cleared). + */ +void clear_state() +{ + current_object = 0; + set_command_giver(0); + current_interactive = 0; + previous_ob = 0; + current_prog = 0; + caller_type = 0; + reset_machine(0); /* Pop down the stack. */ +} /* clear_state() */ + +#if 0 +static void report_holes() { + if (current_object && current_object->name) + debug_message("current_object is /%s\n", current_object->name); + if (command_giver && command_giver->name) + debug_message("command_giver is /%s\n", command_giver->name); + if (current_interactive && current_interactive->name) + debug_message("current_interactive is /%s\n", current_interactive->name); + if (previous_ob && previous_ob->name) + debug_message("previous_ob is /%s\n", previous_ob->name); + if (current_prog && current_prog->name) + debug_message("current_prog is /%s\n", current_prog->name); + if (caller_type) + debug_message("caller_type is %s\n", caller_type); +} +#endif + +void logon (object_t * ob) +{ + if(ob->flags & O_DESTRUCTED){ + return; + } + /* current_object no longer set */ + apply(APPLY_LOGON, ob, 0, ORIGIN_DRIVER); + /* function not existing is no longer fatal */ +} + +/* + * This is the backend. We will stay here for ever (almost). + */ +extern int max_fd; +void backend() +{ + struct timeval timeout; + int i, nb; + volatile int first_call = 1; + int there_is_a_port = 0; + error_context_t econ; + + debug_message("Initializations complete.\n\n"); + for (i = 0; i < 5; i++) { + if (external_port[i].port) { + debug_message("Accepting connections on port %d.\n", + external_port[i].port); + there_is_a_port = 1; + } + } + + if (!there_is_a_port) + debug_message("No external ports specified.\n"); + + init_user_conn(); /* initialize user connection socket */ +#ifdef SIGHUP + signal(SIGHUP, startshutdownMudOS); +#endif + clear_state(); + save_context(&econ); + if (SETJMP(econ.context)) + restore_context(&econ); + clear_state(); + if (!t_flag && first_call) { + first_call = 0; + call_heart_beat(); + } + + while (1) { + /* Has to be cleared if we jumped out of process_user_command() */ + current_interactive = 0; + set_eval(max_cost); + + if (obj_list_replace || obj_list_destruct) + remove_destructed_objects(); + + /* + * shut down MudOS if MudOS_is_being_shut_down is set. + */ + if (MudOS_is_being_shut_down) + shutdownMudOS(0); + if (slow_shut_down_to_do) { + int tmp = slow_shut_down_to_do; + + slow_shut_down_to_do = 0; + slow_shut_down(tmp); + } + /* + * select + */ + make_selectmasks(); + timeout.tv_sec = 1; + timeout.tv_usec = 0; +#ifndef hpux + nb = select(max_fd + 1, &readmask, &writemask, (fd_set *) 0, &timeout); +#else + nb = select(max_fd + 1, (int *) &readmask, (int *) &writemask, + (int *) 0, &timeout); +#endif + /* + * process I/O if necessary. + */ + if (nb > 0) { + process_io(); + } + /* + * process user commands. + */ + for (i = 0; process_user_command() && i < max_users; i++) + ; + + /* + * call outs + */ + call_out(); +#ifdef PACKAGE_ASYNC + check_reqs(); +#endif + } +} /* backend() */ + + +/* + * Despite the name, this routine takes care of several things. + * It will run once every 15 minutes. + * + * . It will attempt to reconnect to the address server if the connection has + * been lost. + * . It will loop through all objects. + * + * . If an object is found in a state of not having done reset, and the + * delay to next reset has passed, then reset() will be done. + * + * . If the object has a existed more than the time limit given for swapping, + * then 'clean_up' will first be called in the object + * + * There are some problems if the object self-destructs in clean_up, so + * special care has to be taken of how the linked list is used. + */ +static void look_for_objects_to_swap() +{ + static int next_time; +#ifndef NO_IP_DEMON + extern int no_ip_demon; + static int next_server_time; +#endif + object_t *ob; + VOLATILE object_t *next_ob, *last_good_ob; + error_context_t econ; + +#ifndef NO_IP_DEMON + if (current_time >= next_server_time) { + /* initialize the address server. if it is already initialized, then + * this is a nop. this will cause the driver to reattempt connecting + * to the address server once every 15 minutes in the event that it + * has gone down. + */ + if (!no_ip_demon && next_server_time) + init_addr_server(ADDR_SERVER_IP, ADDR_SERVER_PORT); + next_server_time = current_time + 15 * 60; + } +#endif + + if (current_time < next_time) + return; /* Not time to look yet */ + next_time = current_time + 5 * 60; /* Next time is in 5 minutes */ + + /* + * Objects object can be destructed, which means that next object to + * investigate is saved in next_ob. If very unlucky, that object can be + * destructed too. In that case, the loop is simply restarted. + */ + next_ob = obj_list; + last_good_ob = obj_list; + save_context(&econ); + if (SETJMP(econ.context)) + restore_context(&econ); + + while ((ob = (object_t *)next_ob)) { + int ready_for_clean_up = 0; + + if (ob->flags & O_DESTRUCTED){ + if(last_good_ob->flags & O_DESTRUCTED) + ob = obj_list; /* restart */ + else + ob = (object_t *)last_good_ob; + } + next_ob = ob->next_all; + + /* + * Check reference time before reset() is called. + */ + if (current_time - ob->time_of_ref > time_to_clean_up) + ready_for_clean_up = 1; +#if !defined(NO_RESETS) && !defined(LAZY_RESETS) + /* + * Should this object have reset(1) called ? + */ + if ((ob->flags & O_WILL_RESET) && (ob->next_reset < current_time) + && !(ob->flags & O_RESET_STATE)) { + debug(d_flag, ("RESET /%s\n", ob->obname)); + set_eval(max_cost); + reset_object(ob); + if(ob->flags & O_DESTRUCTED) + continue; + } +#endif + if (time_to_clean_up > 0) { + /* + * Has enough time passed, to give the object a chance to + * self-destruct ? Save the O_RESET_STATE, which will be cleared. + * + * Only call clean_up in objects that has defined such a function. + * + * Only if the clean_up returns a non-zero value, will it be called + * again. + */ + + if (ready_for_clean_up && (ob->flags & O_WILL_CLEAN_UP)) { + int save_reset_state = ob->flags & O_RESET_STATE; + svalue_t *svp; + + debug(d_flag, ("clean up /%s\n", ob->obname)); + + /* + * Supply a flag to the object that says if this program is + * inherited by other objects. Cloned objects might as well + * believe they are not inherited. Swapped objects will not + * have a ref count > 1 (and will have an invalid ob->prog + * pointer). + * + * Note that if it is in the apply_low cache, it will also + * get a flag of 1, which may cause the mudlib not to clean + * up the object. This isn't bad because: + * (1) one expects it is rare for objects that have untouched + * long enough to clean_up to still be in the cache, especially + * on busy MUDs. + * (2) the ones that are are the more heavily used ones, so + * keeping them around seems justified. + */ + + push_number(ob->flags & (O_CLONE) ? 0 : ob->prog->ref); + set_eval(max_cost); + svp = apply(APPLY_CLEAN_UP, ob, 1, ORIGIN_DRIVER); + if (ob->flags & O_DESTRUCTED) + continue; + if (!svp || (svp->type == T_NUMBER && svp->u.number == 0)) + ob->flags &= ~O_WILL_CLEAN_UP; + ob->flags |= save_reset_state; + } + } + last_good_ob = ob; + } + pop_context(&econ); +} /* look_for_objects_to_swap() */ + +/* Call all heart_beat() functions in all objects. Also call the next reset, + * and the call out. + * We do heart beats by moving each object done to the end of the heart beat + * list before we call its function, and always using the item at the head + * of the list as our function to call. We keep calling heart beats until + * a timeout or we have done num_heart_objs calls. It is done this way so + * that objects can delete heart beating objects from the list from within + * their heart beat without truncating the current round of heart beats. + * + * Set command_giver to current_object if it is a living object. If the object + * is shadowed, check the shadowed object if living. There is no need to save + * the value of the command_giver, as the caller resets it to 0 anyway. */ + +typedef struct { + object_t *ob; + short heart_beat_ticks; + short time_to_heart_beat; +} heart_beat_t; + +static heart_beat_t *heart_beats = 0; +static int max_heart_beats = 0; +static int heart_beat_index = 0; +static int num_hb_objs = 0; +static int num_hb_to_do = 0; + +static int num_hb_calls = 0; /* starts */ +static float perc_hb_probes = 100.0; /* decaying avge of how many complete */ + +void call_heart_beat() +{ + object_t *ob; + heart_beat_t *curr_hb; + error_context_t econ; + + current_interactive = 0; + + if ((num_hb_to_do = num_hb_objs)) { + num_hb_calls++; + heart_beat_index = 0; + save_context(&econ); + while (1) { + ob = (curr_hb = &heart_beats[heart_beat_index])->ob; + DEBUG_CHECK(!(ob->flags & O_HEART_BEAT), + "Heartbeat not set in object on heartbeat list!"); + /* is it time to do a heart beat ? */ + curr_hb->heart_beat_ticks--; + + if (ob->prog->heart_beat != 0) { + if (curr_hb->heart_beat_ticks < 1) { + object_t *new_command_giver; + curr_hb->heart_beat_ticks = curr_hb->time_to_heart_beat; + current_heart_beat = ob; + new_command_giver = ob; +#ifndef NO_SHADOWS + while (new_command_giver->shadowing) + new_command_giver = new_command_giver->shadowing; +#endif +#ifndef NO_ADD_ACTION + if (!(new_command_giver->flags & O_ENABLE_COMMANDS)) + new_command_giver = 0; +#endif +#ifdef PACKAGE_MUDLIB_STATS + add_heart_beats(&ob->stats, 1); +#endif + set_eval(max_cost); + + if (SETJMP(econ.context)) { + restore_context(&econ); + } else { + save_command_giver(new_command_giver); + call_direct(ob, ob->prog->heart_beat - 1, + ORIGIN_DRIVER, 0); + pop_stack(); /* pop the return value */ + restore_command_giver(); + } + + current_object = 0; + } + } + if (++heart_beat_index == num_hb_to_do) + break; + } + pop_context(&econ); + if (heart_beat_index < num_hb_to_do) + perc_hb_probes = 100 * (float) heart_beat_index / num_hb_to_do; + else + perc_hb_probes = 100.0; + heart_beat_index = num_hb_to_do = 0; + } + current_prog = 0; + current_heart_beat = 0; + look_for_objects_to_swap(); +#ifdef PACKAGE_MUDLIB_STATS + mudlib_stats_decay(); +#endif +} /* call_heart_beat() */ + +int +query_heart_beat (object_t * ob) +{ + int index; + + if (!(ob->flags & O_HEART_BEAT)) return 0; + index = num_hb_objs; + while (index--) { + if (heart_beats[index].ob == ob) + return heart_beats[index].time_to_heart_beat; + } + return 0; +} /* query_heart_beat() */ + +/* add or remove an object from the heart beat list; does the major check... + * If an object removes something from the list from within a heart beat, + * various pointers in call_heart_beat could be stuffed, so we must + * check current_heart_beat and adjust pointers. */ + +int set_heart_beat (object_t * ob, int to) +{ + int index; + + if (ob->flags & O_DESTRUCTED) return 0; + + if (!to) { + int num; + + index = num_hb_objs; + while (index--) { + if (heart_beats[index].ob == ob) break; + } + if (index < 0) return 0; + + if (num_hb_to_do) { + if (index <= heart_beat_index) + heart_beat_index--; + if (index < num_hb_to_do) + num_hb_to_do--; + } + + if ((num = (num_hb_objs - (index + 1)))) + memmove(heart_beats + index, heart_beats + (index + 1), num * sizeof(heart_beat_t)); + + num_hb_objs--; + ob->flags &= ~O_HEART_BEAT; + return 1; + } + + if (ob->flags & O_HEART_BEAT) { + if (to < 0) return 0; + + index = num_hb_objs; + while (index--) { + if (heart_beats[index].ob == ob) { + heart_beats[index].time_to_heart_beat = heart_beats[index].heart_beat_ticks = to; + break; + } + } + DEBUG_CHECK(index < 0, "Couldn't find enabled object in heart_beat list!\n"); + } else { + heart_beat_t *hb; + + if (!max_heart_beats) + heart_beats = CALLOCATE(max_heart_beats = HEART_BEAT_CHUNK, + heart_beat_t, TAG_HEART_BEAT, + "set_heart_beat: 1"); + else if (num_hb_objs == max_heart_beats) { + max_heart_beats += HEART_BEAT_CHUNK; + heart_beats = RESIZE(heart_beats, max_heart_beats, + heart_beat_t, TAG_HEART_BEAT, + "set_heart_beat: 1"); + } + + hb = &heart_beats[num_hb_objs++]; + hb->ob = ob; + if (to < 0) to = 1; + hb->time_to_heart_beat = to; + hb->heart_beat_ticks = to; + ob->flags |= O_HEART_BEAT; + } + + return 1; +} + +int heart_beat_status (outbuffer_t * ob, int verbose) +{ + char buf[20]; + + if (verbose == 1) { + outbuf_add(ob, "Heart beat information:\n"); + outbuf_add(ob, "-----------------------\n"); + outbuf_addv(ob, "Number of objects with heart beat: %d, starts: %d\n", + num_hb_objs, num_hb_calls); + + /* passing floats to varargs isn't highly portable so let sprintf + handle it */ + sprintf(buf, "%.2f", perc_hb_probes); + outbuf_addv(ob, "Percentage of HB calls completed last time: %s\n", buf); + } + return (0); +} /* heart_beat_status() */ + +/* New version used when not in -o mode. The epilog() in master.c is + * supposed to return an array of files (castles in 2.4.5) to load. The array + * returned by apply() will be freed at next call of apply(), which means that + * the ref count has to be incremented to protect against deallocation. + * + * The master object is asked to do the actual loading. + */ +void preload_objects (int eflag) +{ + VOLATILE array_t *prefiles; + svalue_t *ret; + VOLATILE int ix; + error_context_t econ; + + save_context(&econ); + if (SETJMP(econ.context)) { + restore_context(&econ); + pop_context(&econ); + return; + } + push_number(eflag); + ret = apply_master_ob(APPLY_EPILOG, 1); + pop_context(&econ); + if ((ret == 0) || (ret == (svalue_t *)-1) || (ret->type != T_ARRAY)) + return; + else + prefiles = ret->u.arr; + if ((prefiles == 0) || (prefiles->size < 1)) + return; + + debug_message("\nLoading preloaded files ...\n"); + prefiles->ref++; + ix = 0; + /* in case of an error, effectively do a 'continue' */ + save_context(&econ); + if (SETJMP(econ.context)) { + restore_context(&econ); + ix++; + } + for ( ; ix < prefiles->size; ix++) { + if (prefiles->item[ix].type != T_STRING) + continue; + + set_eval(max_cost); + + push_svalue(((array_t *)prefiles)->item + ix); + (void) apply_master_ob(APPLY_PRELOAD, 1); + } + free_array((array_t *)prefiles); + pop_context(&econ); +} /* preload_objects() */ + +/* All destructed objects are moved into a sperate linked list, + * and deallocated after program execution. */ + +INLINE void remove_destructed_objects() +{ + object_t *ob, *next; + + if (obj_list_replace) + replace_programs(); + for (ob = obj_list_destruct; ob; ob = next) { + next = ob->next_all; + destruct2(ob); + } + obj_list_destruct = 0; +} /* remove_destructed_objects() */ + +static double load_av = 0.0; + +void update_load_av() +{ + static int last_time; + int n; + double c; + static int acc = 0; + + acc++; + if (current_time == last_time) + return; + n = current_time - last_time; + if (n < NUM_CONSTS) + c = consts[n]; + else + c = exp(-n / 900.0); + load_av = c * load_av + acc * (1 - c) / n; + last_time = current_time; + acc = 0; +} /* update_load_av() */ + +static double compile_av = 0.0; + +void +update_compile_av (int lines) +{ + static int last_time; + int n; + double c; + static int acc = 0; + + acc += lines; + if (current_time == last_time) + return; + n = current_time - last_time; + if (n < NUM_CONSTS) + c = consts[n]; + else + c = exp(-n / 900.0); + compile_av = c * compile_av + acc * (1 - c) / n; + last_time = current_time; + acc = 0; +} /* update_compile_av() */ + +char *query_load_av() +{ + static char buff[100]; + + sprintf(buff, "%.2f cmds/s, %.2f comp lines/s", load_av, compile_av); + return (buff); +} /* query_load_av() */ + +#ifdef F_HEART_BEATS +array_t *get_heart_beats() { + int nob = 0, n = num_hb_objs; + heart_beat_t *hb = heart_beats; + object_t **obtab; + array_t *arr; +#ifdef F_SET_HIDE + int apply_valid_hide = 1, display_hidden = 0; +#endif + if(n) + obtab = CALLOCATE(n, object_t *, TAG_TEMPORARY, "heart_beats"); + else + obtab = NULL; + while (n--) { +#ifdef F_SET_HIDE + if (hb->ob->flags & O_HIDDEN) { + if (apply_valid_hide) { + apply_valid_hide = 0; + display_hidden = valid_hide(current_object); + } + if (!display_hidden) + continue; + } +#endif + obtab[nob++] = (hb++)->ob; + } + + arr = allocate_empty_array(nob); + while (nob--) { + arr->item[nob].type = T_OBJECT; + arr->item[nob].u.ob = obtab[nob]; + add_ref(arr->item[nob].u.ob, "get_heart_beats"); + } + if(obtab) + FREE(obtab); + + return arr; +} +#endif diff --git a/fluffos-2.23-ds03/backend.h b/fluffos-2.23-ds03/backend.h new file mode 100644 index 0000000..c48d7a5 --- /dev/null +++ b/fluffos-2.23-ds03/backend.h @@ -0,0 +1,35 @@ +#ifndef BACKEND_H +#define BACKEND_H + +#include "interpret.h" +#include "object.h" + +#define NULL_ERROR_CONTEXT 0 +#define NORMAL_ERROR_CONTEXT 1 +#define CATCH_ERROR_CONTEXT 2 +#define SAFE_APPLY_ERROR_CONTEXT 4 + +/* + * backend.c + */ +extern long current_time; +extern object_t *current_heart_beat; +extern error_context_t *current_error_context; + +void backend (void); +void clear_state (void); +void logon (object_t *); +int parse_command (char *, object_t *); +int set_heart_beat (object_t *, int); +int query_heart_beat (object_t *); +int heart_beat_status (outbuffer_t *, int); +void preload_objects (int); +INLINE void remove_destructed_objects (void); +void update_load_av (void); +void update_compile_av (int); +char *query_load_av (void); +array_t *get_heart_beats (void); +int query_time_used (void); +void call_heart_beat (void); + +#endif diff --git a/fluffos-2.23-ds03/bsdmalloc.c b/fluffos-2.23-ds03/bsdmalloc.c new file mode 100644 index 0000000..21adddf --- /dev/null +++ b/fluffos-2.23-ds03/bsdmalloc.c @@ -0,0 +1,437 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)malloc.c 5.11 (Berkeley) 2/23/91"; +#endif /* LIBC_SCCS and not lint */ + +/* + * malloc.c (Caltech) 2/21/82 + * Chris Kingsley, kingsley@cit-20. + * + * This is a very fast storage allocator. It allocates blocks of a small + * number of different sizes, and keeps free lists of each size. Blocks that + * don't exactly fit are passed up to the next larger size. In this + * implementation, the available sizes are 2^n-4 (or 2^n-10) bytes long. + * This is designed for use in a virtual memory environment. + */ + +#define IN_MALLOC_WRAPPER +#define NO_OPCODES +#include "std.h" +#include "main.h" + +#undef NULL +#define NULL 0 + +#ifdef _SEQUENT_ +typedef unsigned char u_char; +typedef unsigned short u_short; +typedef unsigned int u_int; + +#endif + +/* + * The overhead on a block is at least 4 bytes. When free, this space + * contains a pointer to the next free block, and the bottom two bits must + * be zero. When in use, the first byte is set to MAGIC, and the second + * byte is the size index. The remaining bytes are for alignment. + * If range checking is enabled then a second word holds the size of the + * requested block, less 1, rounded up to a multiple of sizeof(RMAGIC). + * The order of elements is critical: ov_magic must overlay the low order + * bits of ov_next, and ov_magic can not be a valid ov_next bit pattern. + */ +union overhead { + union overhead *ov_next; /* when free */ + struct { + u_char ovu_magic; /* magic number */ + u_char ovu_index; /* bucket # */ +#ifdef RCHECK + u_short ovu_rmagic; /* range magic number */ + u_int ovu_size; /* actual block size */ +#endif + } ovu; +#define ov_magic ovu.ovu_magic +#define ov_index ovu.ovu_index +#define ov_rmagic ovu.ovu_rmagic +#define ov_size ovu.ovu_size +}; + +#define MAGIC 0xef /* magic # on accounting info */ +#define RMAGIC 0x5555 /* magic # on range info */ + +#ifdef RCHECK +#define RSLOP sizeof (u_short) +#else +#define RSLOP 0 +#endif + +/* + * nextf[i] is the pointer to the next free block of size 2^(i+3). The + * smallest allocatable block is 8 bytes. The overhead information + * precedes the data area returned to the user. + */ +#define NBUCKETS 30 +static union overhead *nextf[NBUCKETS]; + +static int pagesz; /* page size */ +static int pagebucket; /* page size bucket */ + +static void morecore (int); +static int findbucket (union overhead *, int); +void *sbrkx(long); +#ifdef DO_MSTATS +/* + * nmalloc[i] is the difference between the number of mallocs and frees + * for a given block size. + */ +static u_int nmalloc[NBUCKETS]; + +#endif + +#if defined(DEBUG) || defined(RCHECK) +#ifdef __STDC__ +#define ASSERT(p) if (!(p)) botch(#p) +#else +#define ASSERT(p) if (!(p)) botch("?") +#endif +static int botch (char * s) +{ + debug_message("\r\nassertion botched: %s\r\n", s); + (void) fflush(stderr); /* just in case user buffered it */ + abort(); + return 0; +} +#else +#define ASSERT(p) +#endif + +#ifdef malloc +/* linux */ +#undef malloc +#endif +void *bsdmalloc_malloc (size_t nbytes) +{ + register union overhead *op; + register long bucket, n; + register unsigned amt; + + /* + * First time malloc is called, setup page size and align break pointer + * so all data will be page aligned. + */ + if (pagesz == 0) { +#ifdef MEMPAGESIZE + pagesz = n = MEMPAGESIZE; +#else + pagesz = n = getpagesize(); +#endif + op = (union overhead *) sbrkx(0); + n = n - sizeof(*op) - ((long) op & (n - 1)); + if (n < 0) + n += pagesz; + if (n) { + if ((char *)sbrkx(n) == (char *) -1) + return (NULL); + } + bucket = 0; + amt = 8; + while (pagesz > amt) { + amt <<= 1; + bucket++; + } + pagebucket = bucket; + } + /* + * Convert amount of memory requested into closest block size stored in + * hash buckets which satisfies request. Account for space used per block + * for accounting. + */ + if (nbytes <= (n = pagesz - sizeof(*op) - RSLOP)) { +#ifndef RCHECK + amt = 8; /* size of first bucket */ + bucket = 0; +#else + amt = 16; /* size of first bucket */ + bucket = 1; +#endif + n = -(sizeof(*op) + RSLOP); + } else { + amt = pagesz; + bucket = pagebucket; + } + while (nbytes > amt + n) { + amt <<= 1; + if (amt == 0) + return (NULL); + bucket++; + } + /* + * If nothing in hash bucket right now, request more memory from the + * system. + */ + if ((op = nextf[bucket]) == NULL) { + morecore(bucket); + if ((op = nextf[bucket]) == NULL) + return (NULL); + } + /* remove from linked list */ + nextf[bucket] = op->ov_next; + op->ov_magic = MAGIC; + op->ov_index = bucket; +#ifdef DO_MSTATS + nmalloc[bucket]++; +#endif +#ifdef RCHECK + /* + * Record allocated size of block and bound space with magic numbers. + */ + op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1); + op->ov_rmagic = RMAGIC; + *(u_short *) ((caddr_t) (op + 1) + op->ov_size) = RMAGIC; +#endif + return ((char *) (op + 1)); +} + +/* + * Allocate more memory to the indicated bucket. + */ +static void +morecore (int bucket) +{ + register union overhead *op; + register int sz; /* size of desired block */ + int amt; /* amount to allocate */ + int nblks; /* how many blocks we get */ + + /* + * sbrk_size <= 0 only for big, FLUFFY, requests (about 2^30 bytes on a + * VAX, I think) or for a negative arg. + */ + sz = 1 << (bucket + 3); +#ifdef DEBUG + ASSERT(sz > 0); +#else + if (sz <= 0) + return; +#endif + if (sz < pagesz) { + amt = pagesz; + nblks = amt / sz; + } else { + amt = sz + pagesz; + nblks = 1; + } + op = (union overhead *) sbrkx(amt); + /* no more room! */ + if ((long) op == -1) + return; + /* + * Add new memory allocated to that on free list for this hash bucket. + */ + nextf[bucket] = op; + while (--nblks > 0) { + op->ov_next = (union overhead *) ((caddr_t) op + sz); + op = (union overhead *) ((caddr_t) op + sz); + } +} + +INLINE void +bsdmalloc_free (void * cp) +{ + register int size; + register union overhead *op; + + if (cp == NULL) + return; + op = (union overhead *) ((caddr_t) cp - sizeof(union overhead)); +#ifdef DEBUG + ASSERT(op->ov_magic == MAGIC); /* make sure it was in use */ +#else + if (op->ov_magic != MAGIC) + return; /* sanity */ +#endif +#ifdef RCHECK + ASSERT(op->ov_rmagic == RMAGIC); + ASSERT(*(u_short *) ((caddr_t) (op + 1) + op->ov_size) == RMAGIC); +#endif + size = op->ov_index; + ASSERT(size < NBUCKETS); + op->ov_next = nextf[size]; /* also clobbers ov_magic */ + nextf[size] = op; +#ifdef DO_MSTATS + nmalloc[size]--; +#endif +} + +/* + * When a program attempts "storage compaction" as mentioned in the + * old malloc man page, it realloc's an already freed block. Usually + * this is the last block it freed; occasionally it might be farther + * back. We have to search all the free lists for the block in order + * to determine its bucket: 1st we make one pass thru the lists + * checking only the first block in each; if that fails we search + * ``realloc_srchlen'' blocks in each list for a match (the variable + * is extern so the caller can modify it). If that fails we just copy + * however many bytes was given to realloc() and hope it's not huge. + */ +int realloc_srchlen = 4; /* 4 should be plenty, -1 =>'s whole list */ + +void *bsdmalloc_realloc (void * cp, size_t nbytes) +{ + register u_int onb; + register int i; + union overhead *op; + char *res; + int was_alloced = 0; + + if (cp == NULL) + return (bsdmalloc_malloc(nbytes)); + op = (union overhead *) ((caddr_t) cp - sizeof(union overhead)); + if (op->ov_magic == MAGIC) { + was_alloced++; + i = op->ov_index; + } else { + /* + * Already free, doing "compaction". + * + * Search for the old block of memory on the free list. First, check + * the most common case (last element free'd), then (this failing) + * the last ``realloc_srchlen'' items free'd. If all lookups fail, + * then assume the size of the memory block being realloc'd is the + * largest possible (so that all "nbytes" of new memory are copied + * into). Note that this could cause a memory fault if the old area + * was tiny, and the moon is gibbous. However, that is very + * unlikely. + */ + if ((i = findbucket(op, 1)) < 0 && + (i = findbucket(op, realloc_srchlen)) < 0) + i = NBUCKETS; + } + onb = 1 << (i + 3); + if (onb < pagesz) + onb -= sizeof(*op) + RSLOP; + else + onb += pagesz - sizeof(*op) - RSLOP; + /* avoid the copy if same size block */ + if (was_alloced) { + if (i) { + i = 1 << (i + 2); + if (i < pagesz) + i -= sizeof(*op) + RSLOP; + else + i += pagesz - sizeof(*op) - RSLOP; + } + if (nbytes <= onb && nbytes > i) { +#ifdef RCHECK + op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1); + *(u_short *) ((caddr_t) (op + 1) + op->ov_size) = RMAGIC; +#endif + return (cp); + } else + bsdmalloc_free(cp); + } + if ((res = bsdmalloc_malloc(nbytes)) == NULL) + return (NULL); + if (cp != res) /* common optimization if "compacting" */ + memcpy(res, cp, (nbytes < onb) ? nbytes : onb); + return (res); +} + +/* + * Search ``srchlen'' elements of each free list for a block whose + * header starts at ``freep''. If srchlen is -1 search the whole list. + * Return bucket number, or -1 if not found. + */ +static int +findbucket (union overhead * freep, int srchlen) +{ + register union overhead *p; + register int i, j; + + for (i = 0; i < NBUCKETS; i++) { + j = 0; + for (p = nextf[i]; p && j != srchlen; p = p->ov_next) { + if (p == freep) + return (i); + j++; + } + } + return (-1); +} + +#ifdef DO_MSTATS +/* + * mstats - print out statistics about malloc + * + * Prints two lines of numbers, one showing the length of the free list + * for each size category, the second showing the number of mallocs - + * frees for each size category. + */ +void +show_mstats (outbuffer_t * ob, char * s) +{ + register int i, j; + register union overhead *p; + int totfree = 0, totused = 0; + + outbuf_addv(ob, "Memory allocation statistics %s\nfree:\t", s); + for (i = 0; i < NBUCKETS; i++) { + for (j = 0, p = nextf[i]; p; p = p->ov_next, j++); + outbuf_addv(ob, " %d", j); + totfree += j * (1 << (i + 3)); + } + outbuf_add(ob, "\nused:\t"); + for (i = 0; i < NBUCKETS; i++) { + outbuf_addv(ob, " %d", nmalloc[i]); + totused += nmalloc[i] * (1 << (i + 3)); + } + outbuf_addv(ob, "\n\tTotal in use: %d, total free: %d\n", + totused, totfree); +} +#endif + +/* calloc was originally in its own source file */ +#ifdef calloc +/* linux */ +#undef calloc +#endif +INLINE void *bsdmalloc_calloc (size_t num, register size_t size) +{ + register void *p; + + size *= num; + if ((p = bsdmalloc_malloc(size))) + memset(p, 0, size); + return (p); +} diff --git a/fluffos-2.23-ds03/bsdmalloc.h b/fluffos-2.23-ds03/bsdmalloc.h new file mode 100644 index 0000000..69908b0 --- /dev/null +++ b/fluffos-2.23-ds03/bsdmalloc.h @@ -0,0 +1,14 @@ +#ifndef BSDMALLOC_H +#define BSDMALLOC_H + +#ifdef BSDMALLOC +void *bsdmalloc_malloc (size_t); +void *bsdmalloc_calloc (size_t, size_t); +void *bsdmalloc_realloc (void *, size_t); +void bsdmalloc_free (void *); +#ifdef DO_MSTATS +void show_mstats (outbuffer_t *, char *); +#endif +#endif + +#endif diff --git a/fluffos-2.23-ds03/buffer.c b/fluffos-2.23-ds03/buffer.c new file mode 100644 index 0000000..dd86ab1 --- /dev/null +++ b/fluffos-2.23-ds03/buffer.c @@ -0,0 +1,113 @@ +/* buffer.c for MudOS 0.9.x by John Garnett, 1993/11/07 */ + +#include "std.h" + +#ifndef NO_BUFFER_TYPE +#include "crctab.h" +#include "lpc_incl.h" +#include "stralloc.h" + +buffer_t null_buf = +{ + 1, /* Ref count, which will ensure that it will + * never be deallocated */ + 0 /* size */ +}; + +INLINE buffer_t * + null_buffer() +{ + null_buf.ref++; + return &null_buf; +} /* null_buffer() */ + +INLINE void +free_buffer (buffer_t * b) +{ + b->ref--; + /* don't try to free the null_buffer (ref count might overflow) */ + if ((b->ref > 0) || (b == &null_buf)) { + return; + } + FREE((char *) b); +} /* free_buffer() */ + +buffer_t * +allocate_buffer (int size) +{ + buffer_t *buf; + +#ifndef NO_BUFFER_TYPE + if ((size < 0) || (size > max_buffer_size)) { + error("Illegal buffer size.\n"); + } + if (size == 0) { + return null_buffer(); + } + /* using calloc() so that memory will be zero'd out when allocated */ + buf = (buffer_t *) DCALLOC(sizeof(buffer_t) + size - 1, 1, + TAG_BUFFER, "allocate_buffer"); + buf->size = size; + buf->ref = 1; + return buf; +#else + return NULL; +#endif +} + +int write_buffer (buffer_t * buf, int start, const char * str, int theLength) +{ + int size; + + size = buf->size; + if (start < 0) { + start = size + start; + if (start < 0) { + return 0; + } + } + /* + * can't write past the end of the buffer since we can't reallocate the + * buffer here (no easy way to propagate back the changes to the caller + */ + if ((start + theLength) > size) { + return 0; + } + memcpy(buf->item + start, str, theLength); + return 1; +} /* write_buffer() */ + +char * +read_buffer (buffer_t * b, int start, int len, int * rlen) +{ + char *str; + unsigned int size; + + if (len < 0) + return 0; + + size = b->size; + if (start < 0) { + start = size + start; + if (start < 0) { + return 0; + } + } + if (len == 0) { + len = size; + } + if (start >= size) { + return 0; + } + if ((start + len) > size) { + len = (size - start); + } + for (str = (char *)b->item + start, size = 0; *str && size < len; str++, size++) + ; + str = new_string(size, "read_buffer: str"); + memcpy(str, b->item + start, size); + str[*rlen = size] = '\0'; + + return str; +} /* read_buffer() */ +#endif diff --git a/fluffos-2.23-ds03/buffer.h b/fluffos-2.23-ds03/buffer.h new file mode 100644 index 0000000..0903b7d --- /dev/null +++ b/fluffos-2.23-ds03/buffer.h @@ -0,0 +1,32 @@ +/* buffer.h by John Garnett, 1993/11/07 */ + +/* It is usually better to include "lpc_incl.h" instead of including this + directly */ + +#ifndef _BUFFER_H_ +#define _BUFFER_H_ + +#ifndef NO_BUFFER_TYPE +typedef struct buffer_s { + /* first two elements of struct must be 'ref' followed by 'size' */ + unsigned short ref; + unsigned int size; +#ifdef DEBUG + unsigned short extra_ref; +#endif + unsigned char item[1]; +} buffer_t; + +/* + * buffer.c + */ +extern buffer_t null_buf; + +INLINE buffer_t *null_buffer (void); +INLINE void free_buffer (buffer_t *); +buffer_t *allocate_buffer (int); +int write_buffer (buffer_t *, int, const char *, int); +char *read_buffer (buffer_t *, int, int, int *); +#endif + +#endif diff --git a/fluffos-2.23-ds03/build.FluffOS b/fluffos-2.23-ds03/build.FluffOS new file mode 100644 index 0000000..849a3ba --- /dev/null +++ b/fluffos-2.23-ds03/build.FluffOS @@ -0,0 +1,478 @@ +#!/bin/sh +ENABLE_M64=0 +export ENABLE_M64 + +if test $# -ne 0; then + case $1 in + develop) + echo Preparing to build developmental version of MudOS driver ... + OPTIMIZE="-O0 -Wall -Wundef -DPEDANTIC -pedantic -Wmissing-declarations" + DEBUG="-g -DDEBUG -DDEBUG_MACRO" + ;; + debug) + echo Preparing to build debugging version of MudOS driver ... + OPTIMIZE="-O0" + DEBUG="-g -DDEBUG" + ;; + *) + echo Unknown build type + exit 1 + ;; + esac +else + echo Preparing to build standard MudOS driver ... +fi + +# If this is uncommented, the specified 'make' is used instead of looking for +# one +#MAKE=make + +# define this to be where you want the temporary compiled files to go +# (only used with GNU make) +OBJDIR=obj + +# change this if you wish the driver binary to be named something else +DRIVER_BIN=driver + +# uncomment PROOF if using CenterLine's TestCenter to debug the driver. +#PROOF=proof + +# Set INSTALL_DIR to the directory where you want to install the executables. +INSTALL_DIR="../bin" + +#Enable warnings from the compiler (gcc), if wanted. +#WARN=-Wall + +#PIPE=-pipe + +# define profiling if you want it +# note: the gmon.out file will likely be written in the mudlib dir. +# PROFILE_ON controls whether or not monitoring is active at driver +# startup. Comment PROFILE_ON to make profiling not active at startup. +# Use moncontrol(1) efun to enable profiling and moncontrol(0) to turn +# it off. +#PROFILE_ON="-DPROFILE_ON" +# Uncomment this if you want to enable profiling of the driver (gcc) +#PROFIL="-pg -DPROFILING $(PROFILE_ON)" + +# Enable run time debugging +#DEBUG="-g" +# With extra driver debug code +#DEBUG="-g -DDEBUG" +# For DEC Alpha: to have optimization and debugging +#DEBUG="-g3 -DDEBUG" +# Prevent -DDEBUG from aborting the driver (when in -DDEBUG mode) +#DEBUG_NON_FATAL="-DDEBUG_NON_FATAL" +# Compile in debug() macro code +#DEBUG_MACRO="-DDEBUG_MACRO" + +# define this if you want to specify (compiler) optimization. +# +# if nothing is defined here, and DEBUG is not defined, something appropriate +# to the compiler in question is used. +# +# *WARNING* using high levels of optimization (e.g. -O3) can cause some +# compilers to produce incorrect code. If the driver is behaving +# inexplicably, try using a lower level of optimization (or none). +# +# Uncomment one or none of the following optimization lines. +# +# -O is usually a safe level of optimization for most compilers +#OPTIMIZE="-O" +# high optimization for gcc: +#OPTIMIZE="-O2 -fstrength-reduce" +# uncomment below for RS/6000(AIX) xlc compiler only. +# remove the -Q if xlc complains. +#OPTIMIZE="-O -Q" +# might need this one with newer versions of AIX (ie 3.2.4) +#OPTIMIZE="-O -Q -qMAXMEM=16000" +# high optimization for HP-UX 7.x/8.x's cc (don't use with 9.x) +#OPTIMIZE="+O3 +Obb3000" +# MIPS R3000 running EP/IX Version 1.4.3. Compiler is RISCompiler C 2.11 (cc). +#OPTIMIZE="-Olimit 1802" +# DEC Alpha's cc's highest optimization: -O5 +#OPTIMIZE="-O -Olimit 2000" +# DEC Ultrix's cc's highest optimization: +#OPTIMIZE="-O2 -Olimit 5000" +# high optimization for cc on SGI +#OPTIMIZE="-O2 -Olimit 2500" + +# System V Release 4 (386/486 or if using Sun's cc under Solaris 2.x) +# ARCH: need a way to detect this +#OSFLAGS=-DSVR4 + +# MIPS R3000 running EP/IX Version 1.4.3. Compiler is RISCompiler C 2.11 (cc). +# ARCH: this one too +#OSFLAGS=-I/usr/include/bsd + +# Solaris (SunOS 5): for BSD compatible ioctl() +# If using CC=cc, you can also add: +# -w to turn off warnings, in order to get a cleaner compile +# For 5.4, also add the following: +# -I/usr/bsdinclude +# ARCH: anyone figured a good hack to detect this one yet? +#OSFLAGS="-DBSD_COMP -DSunOS_5" + +# SCO 3.2v4.2 +# ARCH: *sigh* and this one ... +#OSFLAGS=-DSCO + +#Static for compiling Discworld on MINGW +#OSFLAGS=-static + +# try uncommenting this if you are using gcc and at runtime you see socket +# errors saying that the "set socket nonblocking" operation is not supported. +# That error is caused by old-style macros (that gcc doesn't normally grok) +# used by ioctl on some systems. +#NEED_OLD_CPP=-traditional-cpp + +# Location of libmsgql.a, if you are using PACKAGE_DB +#EXTRALIBS=-L/usr/local/lib -lmsql +####### END OF USER CONFIGURABLE OPTIONS + +echo "Trying out some stuff to see what works; ignore errors ..." + +# Mac OS X needs this in order to build properly with gcc < 3 +if test "`uname`" = "Darwin"; then + GCC_MAJOR="`gcc -v 2>&1 | grep "gcc version" | cut -d ' ' -f 3 | cut -d '.' -f 1`" + GCC_MINOR="`gcc -v 2>&1 | grep "gcc version" | cut -d ' ' -f 3 | cut -d '.' -f 2`" + if test "$GCC_MAJOR" -eq "2"; then + NEED_OLD_CPP=-traditional-cpp + fi +fi + +# +# Figure out what make is, and how to invoke it +# +if test "${MAKE-x}" = "x"; then + gmake nothing + if test $? -eq 0; then + MAKE=gmake + MAKEFILE=GNUmakefile + else + make nothing + if test $? -eq 0; then + MAKE=make + tmp=`make which_makefile 2>./2.out | grep -v echo` + if test "x$tmp" = "xMakeIsGNU"; then + MAKEFILE=GNUmakefile + else + MAKEFILE=Makefile + OBJDIR= + fi + else + echo 'FATAL ERROR: Cannot find make or gmake' + exit + fi + fi +else + tmp=`make which_makefile 2>./2.out | grep -v echo` + if test "x$tmp" = "xMakeIsGNU"; then + MAKEFILE=GNUmakefile + else + MAKEFILE=Makefile + OBJDIR= + fi +fi + +echo MAKE=$MAKE >Makefile.tmp + +# +# Determine if running under Cygwin-32 and use a.exe instead +# of a.out if so +# +if test $CYGWIN; then + A_OUT=a.exe + echo Using a.exe for Cygwin GNU compiler default executable +else + A_OUT=a.out + echo Using standard a.out for compiler default executable +fi + +# +# Figure out what to use for CC +# +cat >comptest.c <comptest.c <comptest.c <./1.out +if test $? -eq 0; then + CPP="$CC -E $NEED_OLD_CPP" +else + cpp comptest.c >./1.out + if test $? -eq 0; then + CPP="cpp" + else + $CC -E -traditional-cpp comptest.c >./1.out + if test $? -eq 0; then + CPP="$CC -E -traditional-cpp" + else + echo "FATAL ERROR: Can't figure out how to run the C preprocessor" + exit + fi + fi +fi + +# +# Figure out what to use for install +# +mkdir tmp +cat >insttest <comptest.c <comptest.c <comptest.y <comptest.c < +#include "arch.h" +int main() { + printf("%s\n", ARCH); +} +END +$CC $CFLAGS comptest.c +ARCH=`./$A_OUT` + +cat >comptest.c <>Makefile.tmp +echo OBJDIR=$OBJDIR >>Makefile.tmp +echo DRIVER_BIN=$DRIVER_BIN >>Makefile.tmp +echo PROOF=$PROOF >>Makefile.tmp +echo STRFUNCS=$STRFUNCS >>Makefile.tmp +echo INSTALL=$INSTALL >>Makefile.tmp +echo INSTALL_DIR=$INSTALL_DIR >>Makefile.tmp +echo OPTIMIZE=$OPTIMIZE >>Makefile.tmp +echo CPP=$CPP >>Makefile.tmp +echo CFLAGS=$CFLAGS >>Makefile.tmp +echo CC=$CC >>Makefile.tmp +echo YACC=$YACC >>Makefile.tmp +echo RANLIB=$RANLIB >>Makefile.tmp +echo A=a >>Makefile.tmp +echo O=o >>Makefile.tmp +echo A_OUT=$A_OUT >>Makefile.tmp + + +echo "***************** Configuration completed **************" +echo "Installing MudOS on $ARCH" +echo +echo "Using $INSTALL to install binaries in $INSTALL_DIR." +echo "Using $CPP for preprocessing." +echo "Using $CC $CFLAGS $OPTIMIZE to compile." +echo "Using $YACC $YFLAGS to make the compiler." +echo "Edit $MAKEFILE if this is not what you want" +echo +echo "Otherwise, type '$MAKE' to build MudOS, then '$MAKE install'." + +cat Makefile.tmp ${MAKEFILE}.in >$MAKEFILE +rm Makefile.tmp + +if test $MAKEFILE = Makefile; then +cat >GNUmakefile <Makefile <Makefile.tmp +echo SHELL=command.com >>Makefile.tmp +echo OBJDIR=%OBJDIR% >>Makefile.tmp +echo DRIVER_BIN=%DRIVER_BIN% >>Makefile.tmp +echo INSTALL=copy >>Makefile.tmp +echo INSTALL_DIR=%INSTALL_DIR% >>Makefile.tmp +echo OPTIMIZE=%OPTIMIZE% >>Makefile.tmp +echo CPP=cl -E >>Makefile.tmp +echo CFLAGS=%CFLAGS% >>Makefile.tmp +echo CC=cl >>Makefile.tmp +echo YACC=bison -d -y >>Makefile.tmp +echo RANLIB=echo >>Makefile.tmp +echo O=obj >>Makefile.tmp +echo A=lib >>Makefile.tmp +echo EDIT_SOURCE=.\edit_source >>Makefile.tmp +echo EXE=.exe >>Makefile.tmp +echo TAB_EXT=_tab >> Makefile.tmp + +echo ***************** Configuration completed ************** +echo Installing MudOS on %ARCH% +echo. +echo Using copy to install binaries in %INSTALL_DIR%. +echo Using cl -E for preprocessing. +echo Using cl %CFLAGS% %OPTIMIZE% to compile. +echo Using bison -d -y to make the compiler. +echo Edit Makefile if this is not what you want +echo. +echo Otherwise, type 'nmake' to build MudOS, then 'nmake install'. + +type Makefile.tmp > Makefile +type NMakefile.in >> Makefile +del Makefile.tmp +echo wsock32.lib > system_libs + +set CFLAGS= +set OBJDIR= +set DRIVER_BIN= +set INSTALL_DIR= +set OPTIMIZE= +set DEBUG= +set ARCH= diff --git a/fluffos-2.23-ds03/call_out.c b/fluffos-2.23-ds03/call_out.c new file mode 100644 index 0000000..7d47b91 --- /dev/null +++ b/fluffos-2.23-ds03/call_out.c @@ -0,0 +1,569 @@ +#include "std.h" +#include "call_out.h" +#include "backend.h" +#include "comm.h" +#include "port.h" +#include "eoperators.h" +#include "sprintf.h" +#include "eval.h" + +#define DBG(x) debug(call_out, x) + +/* + * This file implements delayed calls of functions. + * Static functions can not be called this way. + * + * Allocate the structures several in one chunk, to get rid of malloc + * overhead. + */ + +#define CHUNK_SIZE 20 + +typedef struct pending_call_s { + int delta; + union string_or_func function; + object_t *ob; + array_t *vs; + struct pending_call_s *next; +#ifdef THIS_PLAYER_IN_CALL_OUT + object_t *command_giver; +#endif +#ifdef CALLOUT_HANDLES + int handle; +#endif +} pending_call_t; + +static pending_call_t *call_list[CALLOUT_CYCLE_SIZE]; +static pending_call_t *call_list_free; +static int num_call; +#ifdef CALLOUT_HANDLES +static int unique = 0; +#endif + +static void free_call (pending_call_t *); +static void free_called_call (pending_call_t *); +void remove_all_call_out (object_t *); + +/* + * Free a call out structure. + */ +static void free_called_call (pending_call_t * cop) +{ + cop->next = call_list_free; + if (cop->ob) { + free_string(cop->function.s); + free_object(&cop->ob, "free_call"); + } else { + free_funp(cop->function.f); + } + cop->function.s = 0; +#ifdef THIS_PLAYER_IN_CALL_OUT + if (cop->command_giver){ + free_object(&cop->command_giver, "free_call"); + cop->command_giver = 0; + } +#endif + cop->ob = 0; + call_list_free = cop; +} + +INLINE_STATIC void free_call (pending_call_t * cop) +{ + if (cop->vs) + free_array(cop->vs); + free_called_call(cop); +} + +/* + * Setup a new call out. + */ +#ifdef CALLOUT_HANDLES +int +#else +void +#endif +new_call_out (object_t * ob, svalue_t * fun, int delay, + int num_args, svalue_t * arg) +{ + pending_call_t *cop, **copp; + int tm; + + if (delay < 0) + delay = 0; + + DBG(("new_call_out: /%s delay %i", ob->obname, delay)); + + if (!call_list_free) { + int i; + + call_list_free = CALLOCATE(CHUNK_SIZE, pending_call_t, + TAG_CALL_OUT, "new_call_out: call_list_free"); + for (i = 0; i < CHUNK_SIZE - 1; i++) + call_list_free[i].next = &call_list_free[i + 1]; + call_list_free[CHUNK_SIZE - 1].next = 0; + num_call += CHUNK_SIZE; + } + cop = call_list_free; + call_list_free = call_list_free->next; + + if (fun->type == T_STRING) { + DBG((" function: %s", fun->u.string)); + cop->function.s = make_shared_string(fun->u.string); + cop->ob = ob; + add_ref(ob, "call_out"); + } else { + DBG((" function: ")); + cop->function.f = fun->u.fp; + fun->u.fp->hdr.ref++; + cop->ob = 0; + } +#ifdef THIS_PLAYER_IN_CALL_OUT + cop->command_giver = command_giver; /* save current user context */ + if (command_giver) + add_ref(command_giver, "new_call_out"); /* Bump its ref */ +#endif + if (num_args > 0) { + cop->vs = allocate_empty_array(num_args); + memcpy(cop->vs->item, arg, sizeof(svalue_t) * num_args); + } else + cop->vs = 0; + + /* Find out which slot this one fits in */ + tm = (delay + current_time) & (CALLOUT_CYCLE_SIZE - 1); + /* number of cycles */ + delay = delay / CALLOUT_CYCLE_SIZE; + + DBG(("Current time: %i Executes at: %i Slot: %i Delay: %i", + current_time, current_time + delay, tm, delay)); + + for (copp = &call_list[tm]; *copp; copp = &(*copp)->next) { + if ((*copp)->delta > delay) { + (*copp)->delta -= delay; + cop->delta = delay; + cop->next = *copp; + *copp = cop; +#ifdef CALLOUT_HANDLES + tm += CALLOUT_CYCLE_SIZE * ++unique; + cop->handle = tm; + return tm; +#else + return; +#endif + } + delay -= (*copp)->delta; + } + *copp = cop; + cop->delta = delay; + cop->next = 0; +#ifdef CALLOUT_HANDLES + tm += CALLOUT_CYCLE_SIZE * ++unique; + cop->handle = tm; + return tm; +#endif +} + +/* + * See if there are any call outs to be called. Set the 'command_giver' + * if it is a living object. Check for shadowing objects, which may also + * be living objects. + */ +void call_out() +{ + int extra, real_time; + static pending_call_t *cop = 0; + error_context_t econ; + VOLATILE int tm; + + current_interactive = 0; + + /* could be still allocated if an error occured during a call_out */ + if (cop) { + free_called_call(cop); + cop = 0; + } + + real_time = get_current_time(); + DBG(("Calling call_outs: current_time: %i real_time: %i difference: %i", + current_time, real_time, real_time - current_time)); + + /* Slowly advance the clock forward towards real_time, doing call_outs + * as we go. + */ + save_context(&econ); + while (1) { + + tm = current_time & (CALLOUT_CYCLE_SIZE - 1); + DBG((" slot %i", tm)); + while (call_list[tm] && call_list[tm]->delta == 0) { + object_t *ob, *new_command_giver; + + /* + * Move the first call_out out of the chain. + */ + cop = call_list[tm]; + call_list[tm] = call_list[tm]->next; + ob = (cop->ob ? cop->ob : cop->function.f->hdr.owner); + + DBG((" /%s", (ob ? ob->obname : "(null)"))); + + if (!ob || (ob->flags & O_DESTRUCTED)) { + DBG((" (destructed)")); + free_call(cop); + cop = 0; + } else { + if (SETJMP(econ.context)) { + restore_context(&econ); + if (max_eval_error) { + debug_message("Maximum evaluation cost reached while trying to process call_outs\n"); + pop_context(&econ); + return; + } + } else { + object_t *ob; + + ob = cop->ob; +#ifndef NO_SHADOWS + if (ob) + while (ob->shadowing) + ob = ob->shadowing; +#endif + new_command_giver = 0; +#ifdef THIS_PLAYER_IN_CALL_OUT + if (cop->command_giver && + !(cop->command_giver->flags & O_DESTRUCTED)) { + new_command_giver = cop->command_giver; + } else if (ob && (ob->flags & O_LISTENER)) { + new_command_giver = ob; + } + if (new_command_giver) + DBG((" command_giver: /%s", new_command_giver->obname)); +#endif + save_command_giver(new_command_giver); + /* current object no longer set */ + + if (cop->vs) { + array_t *vec = cop->vs; + svalue_t *svp = vec->item + vec->size; + + while (svp-- > vec->item) { + if (svp->type == T_OBJECT && + (svp->u.ob->flags & O_DESTRUCTED)) { + free_object(&svp->u.ob, "call_out"); + *svp = const0u; + } + } + /* cop->vs is ref one */ + extra = cop->vs->size; + transfer_push_some_svalues(cop->vs->item, extra); + free_empty_array(cop->vs); + } else + extra = 0; + //reset_eval_cost(); + set_eval(max_cost); + + if (cop->ob) { + if (cop->function.s[0] == APPLY___INIT_SPECIAL_CHAR) + error("Illegal function name\n"); + + (void) apply(cop->function.s, cop->ob, extra, + ORIGIN_INTERNAL); + } else { + (void) call_function_pointer(cop->function.f, extra); + } + + restore_command_giver(); + } + free_called_call(cop); + cop = 0; + } + } + /* Ok, no more scheduled call_outs for current_time */ + if (current_time < real_time) { + /* Time marches onward! */ + if (call_list[tm]) + call_list[tm]->delta--; + current_time++; + DBG((" current_time = %i", current_time)); + if(!(current_time%HEARTBEAT_INTERVAL)) + call_heart_beat(); + } else { + /* We're done! */ + break; + } + } + DBG(("Done.")); + pop_context(&econ); +} + +static int time_left (int slot, int delay) { + int current_slot = current_time & (CALLOUT_CYCLE_SIZE - 1); + if (slot >= current_slot) { + return (slot - current_slot) + delay * CALLOUT_CYCLE_SIZE; + } else { + return (slot - current_slot) + (delay + 1) * CALLOUT_CYCLE_SIZE; + } +} + +/* + * Throw away a call out. First call to this function is discarded. + * The time left until execution is returned. + * -1 is returned if no call out pending. + */ +int remove_call_out (object_t * ob, const char * fun) +{ + pending_call_t **copp, *cop; + int delay; + int i; + + if (!ob) return -1; + + DBG(("remove_call_out: /%s \"%s\"", ob->obname, fun)); + + for (i = 0; i < CALLOUT_CYCLE_SIZE; i++) { + delay = 0; + for (copp = &call_list[i]; *copp; copp = &(*copp)->next) { + DBG((" Slot: %i\n", i)); + delay += (*copp)->delta; + if ((*copp)->ob == ob && strcmp((*copp)->function.s, fun) == 0) { + cop = *copp; + if (cop->next) + cop->next->delta += cop->delta; + *copp = cop->next; + free_call(cop); + DBG((" found.")); + return time_left(i, delay); + } + } + } + DBG((" not found.")); + return -1; +} + +#ifdef CALLOUT_HANDLES +int remove_call_out_by_handle (int handle) +{ + pending_call_t **copp, *cop; + int delay = 0; + + DBG(("remove_call_out_by_handle: handle: %i slot: %i", + handle, handle & (CALLOUT_CYCLE_SIZE - 1))); + + for (copp = &call_list[handle & (CALLOUT_CYCLE_SIZE - 1)]; *copp; copp = &(*copp)->next) { + delay += (*copp)->delta; + if ((*copp)->handle == handle) { + cop = *copp; + if (cop->next) + cop->next->delta += cop->delta; + *copp = cop->next; + free_call(cop); + return time_left(handle & (CALLOUT_CYCLE_SIZE - 1), delay); + } + } + return -1; +} + +int find_call_out_by_handle (int handle) +{ + pending_call_t *cop; + int delay = 0; + + DBG(("find_call_out_by_handle: handle: %i slot: %i", + handle, handle & (CALLOUT_CYCLE_SIZE - 1))); + + for (cop = call_list[handle & (CALLOUT_CYCLE_SIZE - 1)]; cop; cop = cop->next) { + delay += cop->delta; + if (cop->handle == handle) + return time_left(handle & (CALLOUT_CYCLE_SIZE - 1), delay); + } + return -1; +} +#endif + +int find_call_out (object_t * ob, const char * fun) +{ + pending_call_t *cop; + int delay; + int i; + + if (!ob) return -1; + + DBG(("find_call_out: /%s \"%s\"", ob->obname, fun)); + + for (i = 0; i < CALLOUT_CYCLE_SIZE; i++) { + delay = 0; + DBG((" Slot: %i", i)); + for (cop = call_list[i]; cop; cop = cop->next) { + delay += cop->delta; + if (cop->ob == ob && strcmp(cop->function.s, fun) == 0) + return time_left(i, delay); + } + } + return -1; +} + +int print_call_out_usage (outbuffer_t * ob, int verbose) +{ + int i, j; + pending_call_t *cop; + + for (i = 0, j = 0; j < CALLOUT_CYCLE_SIZE; j++) + for (cop = call_list[j]; cop; cop = cop->next) + i++; + + if (verbose == 1) { + outbuf_add(ob, "Call out information:\n"); + outbuf_add(ob, "---------------------\n"); + outbuf_addv(ob, "Number of allocated call outs: %8d, %8d bytes\n", + num_call, num_call * sizeof(pending_call_t)); + outbuf_addv(ob, "Current length: %d\n", i); + } else { + if (verbose != -1) + outbuf_addv(ob, "call out:\t\t\t%8d %8d (current length %d)\n", num_call, + num_call * sizeof(pending_call_t), i); + } + return num_call * sizeof(pending_call_t); +} + +#ifdef DEBUGMALLOC_EXTENSIONS +#ifdef DEBUG +void mark_call_outs() +{ + pending_call_t *cop; + int i; + + for (i = 0; i < CALLOUT_CYCLE_SIZE; i++) { + for (cop = call_list[i]; cop; cop = cop->next) { + if (cop->vs) + cop->vs->extra_ref++; + if (cop->ob) { + cop->ob->extra_ref++; + EXTRA_REF(BLOCK(cop->function.s))++; + } else { + cop->function.f->hdr.extra_ref++; + } +#ifdef THIS_PLAYER_IN_CALL_OUT + if (cop->command_giver) + cop->command_giver->extra_ref++; +#endif + } + } +} +#endif +#endif +/* + * Construct an array of all pending call_outs. Every item in the array + * consists of 3 items (but only if the object not is destructed): + * 0: The object. + * 1: The function (string). + * 2: The delay. + */ +array_t *get_all_call_outs() +{ + int i, j, delay, tm; + pending_call_t *cop; + array_t *v; + + for (i = 0, j = 0; j < CALLOUT_CYCLE_SIZE; j++) + for (cop = call_list[j]; cop; cop = cop->next) { + object_t *ob = (cop->ob ? cop->ob : cop->function.f->hdr.owner); + if (ob && !(ob->flags & O_DESTRUCTED)) + i++; + } + + v = allocate_empty_array(i); + tm = current_time & (CALLOUT_CYCLE_SIZE-1); + + for (i = 0, j = 0; j < CALLOUT_CYCLE_SIZE; j++) { + delay = 0; + for (cop = call_list[j]; cop; cop = cop->next) { + array_t *vv; + object_t *ob; + + delay += cop->delta; + ob = (cop->ob ? cop->ob : cop->function.f->hdr.owner); + if (!ob || (ob->flags & O_DESTRUCTED)) + continue; + vv = allocate_empty_array(3); + if (cop->ob) { + vv->item[0].type = T_OBJECT; + vv->item[0].u.ob = cop->ob; + add_ref(cop->ob, "get_all_call_outs"); + vv->item[1].type = T_STRING; + vv->item[1].subtype = STRING_SHARED; + vv->item[1].u.string = make_shared_string(cop->function.s); + } else { + outbuffer_t tmpbuf; + svalue_t tmpval; + + tmpbuf.real_size = 0; + tmpbuf.buffer = 0; + + tmpval.type = T_FUNCTION; + tmpval.u.fp = cop->function.f; + + svalue_to_string(&tmpval, &tmpbuf, 0, 0, 0); + + vv->item[0].type = T_OBJECT; + vv->item[0].u.ob = cop->function.f->hdr.owner; + add_ref(cop->function.f->hdr.owner, "get_all_call_outs"); + vv->item[1].type = T_STRING; + vv->item[1].subtype = STRING_SHARED; + vv->item[1].u.string = make_shared_string(tmpbuf.buffer); + FREE_MSTR(tmpbuf.buffer); + } + vv->item[2].type = T_NUMBER; + vv->item[2].u.number = time_left(j, delay); + + v->item[i].type = T_ARRAY; + v->item[i++].u.arr = vv; /* Ref count is already 1 */ + } + } + return v; +} + +void +remove_all_call_out (object_t * obj) +{ + pending_call_t **copp, *cop; + int i; + + for (i = 0; i < CALLOUT_CYCLE_SIZE; i++) { + copp = &call_list[i]; + while (*copp) { + if ( ((*copp)->ob && + (((*copp)->ob == obj) || ((*copp)->ob->flags & O_DESTRUCTED))) || + (!(*copp)->ob && + ((*copp)->function.f->hdr.owner == obj || + !(*copp)->function.f->hdr.owner || + (*copp)->function.f->hdr.owner->flags & O_DESTRUCTED)) ) + { + cop = *copp; + if (cop->next) + cop->next->delta += cop->delta; + *copp = cop->next; + free_call(cop); + } else + copp = &(*copp)->next; + } + } +} + +void reclaim_call_outs() { + pending_call_t *cop; + int i; + + remove_all_call_out(0); /* removes call_outs to destructed objects */ + +#ifdef THIS_PLAYER_IN_CALL_OUT + for (i = 0; i < CALLOUT_CYCLE_SIZE; i++) { + cop = call_list[i]; + while (cop) { + if (cop->command_giver && (cop->command_giver->flags & O_DESTRUCTED)) { + free_object(&cop->command_giver, "reclaim_call_outs"); + cop->command_giver = 0; + } + cop = cop->next; + } + } +#endif +} diff --git a/fluffos-2.23-ds03/call_out.h b/fluffos-2.23-ds03/call_out.h new file mode 100644 index 0000000..b27030b --- /dev/null +++ b/fluffos-2.23-ds03/call_out.h @@ -0,0 +1,26 @@ +#ifndef CALL_OUT_H +#define CALL_OUT_H + +#include "lpc_incl.h" + +/* + * call_out.c + */ +void call_out (void); +void reclaim_call_outs (void); +#ifdef CALLOUT_HANDLES +int find_call_out_by_handle (int); +int remove_call_out_by_handle (int); +int new_call_out (object_t *, svalue_t *, int, int, svalue_t *); +#else +void new_call_out (object_t *, svalue_t *, int, int, svalue_t *); +#endif +int remove_call_out (object_t *, const char *); +void remove_all_call_out (object_t *); +int find_call_out (object_t *, const char *); +array_t *get_all_call_outs (void); +int print_call_out_usage (outbuffer_t *, int); +void mark_call_outs (void); +void reclaim_call_outs (void); + +#endif diff --git a/fluffos-2.23-ds03/class.c b/fluffos-2.23-ds03/class.c new file mode 100644 index 0000000..1343715 --- /dev/null +++ b/fluffos-2.23-ds03/class.c @@ -0,0 +1,84 @@ +#include "std.h" +#include "lpc_incl.h" + +#ifdef CLASS_STATS +int num_classes; +int total_class_size; +#endif + +void dealloc_class (array_t * p) { + int i; + +#ifdef CLASS_STATS + num_classes--; + total_class_size -= sizeof(array_t) + sizeof(svalue_t) * (p->size - 1); +#endif + for (i = p->size; i--;) + free_svalue(&p->item[i], "dealloc_class"); + FREE((char *) p); +} + +void free_class (array_t * p) +{ + if (--(p->ref) > 0) + return; + + dealloc_class(p); +} + +array_t *allocate_class (class_def_t * cld, int has_values) { + array_t *p; + int n = cld->size; + if(!n) + n++; + +#ifdef CLASS_STATS + num_classes++; + total_class_size += sizeof(array_t) + sizeof(svalue_t) * (n - 1); +#endif + + p = (array_t *)DXALLOC(sizeof(array_t) + sizeof(svalue_t) * (n - 1), TAG_CLASS, "allocate_class"); + n = cld->size; + p->ref = 1; + p->size = n; + if (has_values) { + while (n--) + p->item[n] = *sp--; + } else { + while (n--) + p->item[n] = const0; + } + return p; +} + +array_t *allocate_class_by_size (int size) { + array_t *p; + +#ifdef CLASS_STATS + num_classes++; + total_class_size += sizeof(array_t) + sizeof(svalue_t) * (size - 1); +#endif + p = (array_t *)DXALLOC(sizeof(array_t) + sizeof(svalue_t) * (size - 1), TAG_CLASS, "allocate_class"); + p->ref = 1; + p->size = size; + + while (size--) + p->item[size] = const0; + + return p; +} + +array_t *allocate_empty_class_by_size (int size) { + array_t *p; + +#ifdef CLASS_STATS + num_classes++; + total_class_size += sizeof(array_t) + sizeof(svalue_t) * (size - 1); +#endif + p = (array_t *)DXALLOC(sizeof(array_t) + sizeof(svalue_t) * (size - 1), TAG_CLASS, "allocate_class"); + p->ref = 1; + p->size = size; + + return p; +} + diff --git a/fluffos-2.23-ds03/class.h b/fluffos-2.23-ds03/class.h new file mode 100644 index 0000000..0d7a67f --- /dev/null +++ b/fluffos-2.23-ds03/class.h @@ -0,0 +1,19 @@ +#ifndef CLASS_H +#define CLASS_H + +/* It is usually better to include "lpc_incl.h" instead of including this + directly */ + +#ifdef CLASS_STATS +extern int num_classes; +extern int total_class_size; +#endif + + +void dealloc_class (array_t *); +void free_class (array_t *); +array_t *allocate_class (class_def_t *, int); +array_t *allocate_class_by_size (int); +array_t *allocate_empty_class_by_size (int); + +#endif diff --git a/fluffos-2.23-ds03/comm.c b/fluffos-2.23-ds03/comm.c new file mode 100644 index 0000000..0880ede --- /dev/null +++ b/fluffos-2.23-ds03/comm.c @@ -0,0 +1,3347 @@ +/* + * comm.c -- communications functions and more. + * Dwayne Fontenot (Jacques@TMI) + */ + +#include "std.h" +#include "comm.h" +#include "main.h" +#include "socket_efuns.h" +#include "backend.h" +#include "socket_ctrl.h" +#include "debug.h" +#include "ed.h" +#include "file.h" +#include "master.h" +#include "add_action.h" +#include "eval.h" +#include "console.h" + +#ifndef ENOSR +#define ENOSR 63 +#endif + +#ifndef ANSI_SUBSTITUTE +#define ANSI_SUBSTITUTE 0x20 +#endif + +#ifndef ADDRFAIL_NOTIFY +#define ADDRFAIL_NOTIFY 0 +#endif + +#ifndef MSG_NOSIGNAL +#define MSG_NOSIGNAL 0 +#endif + +#define TELOPT_MSSP 70 +#define TELOPT_COMPRESS 85 +#define TELOPT_COMPRESS2 86 +#define TELOPT_MXP 91 // mud extension protocol +#define TELOPT_ZMP 93 // zenith mud protocol +#define TELOPT_GMCP 201 // something mud communication protocol, how many do we need? + +#define MSSP_VAR 1 +#define MSSP_VAL 2 + +#ifndef MAX +#define MAX(x,y) (((x)>(y))?(x):(y)) +#endif + +#ifndef ENV_FILLER +#define ENV_FILLER 0x1e +#endif + +#define TELOPT_NEW_ENVIRON 39 +#define NEW_ENV_IS 0 +#define NEW_ENV_SEND 1 +#define NEW_ENV_INFO 2 +#define NEW_ENV_VAR 0 +#define NEW_ENV_VALUE 1 +#define NEW_ENV_ESC 2 +#define NEW_ENV_USERVAR 3 + + +static unsigned char telnet_break_response[] = { 28, IAC, WILL, TELOPT_TM }; +static unsigned char telnet_ip_response[] = { 127, IAC, WILL, TELOPT_TM }; +static unsigned char telnet_abort_response[] = { IAC, DM }; +static unsigned char telnet_do_tm_response[] = { IAC, WILL, TELOPT_TM }; +static unsigned char telnet_do_naws[] = { IAC, DO, TELOPT_NAWS }; +static unsigned char telnet_dont_naws[] = { IAC, DONT, TELOPT_NAWS }; +static unsigned char telnet_do_ttype[] = { IAC, DO, TELOPT_TTYPE }; +static unsigned char telnet_term_query[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE }; +static unsigned char telnet_no_echo[] = { IAC, WONT, TELOPT_ECHO }; +static unsigned char telnet_no_single[] = { IAC, WONT, TELOPT_SGA }; +static unsigned char telnet_yes_echo[] = { IAC, WILL, TELOPT_ECHO }; +static unsigned char telnet_yes_single[] = { IAC, WILL, TELOPT_SGA }; +static unsigned char telnet_ga[] = { IAC, GA }; +static unsigned char telnet_ayt_response[] = { '\n', '[', '-', 'Y', 'e', 's', '-', ']', ' ', '\n' }; +static unsigned char telnet_line_mode[] = { IAC, DO, TELOPT_LINEMODE }; +static unsigned char telnet_lm_mode[] = { IAC, SB, TELOPT_LINEMODE, LM_MODE, MODE_EDIT | MODE_TRAPSIG, IAC, SE }; +static unsigned char telnet_char_mode[] = { IAC, DONT, TELOPT_LINEMODE }; + +static unsigned char slc_default_flags[] = { SLC_NOSUPPORT, SLC_CANTCHANGE, SLC_CANTCHANGE, SLC_CANTCHANGE, SLC_CANTCHANGE, SLC_NOSUPPORT, + SLC_NOSUPPORT, SLC_NOSUPPORT, SLC_CANTCHANGE, SLC_CANTCHANGE, SLC_NOSUPPORT, SLC_NOSUPPORT, + SLC_NOSUPPORT, SLC_NOSUPPORT, SLC_NOSUPPORT, SLC_NOSUPPORT, SLC_NOSUPPORT, SLC_NOSUPPORT }; +static unsigned char slc_default_chars[] = { 0x00, BREAK, IP, AO, AYT, 0x00, 0x00, 0x00, + SUSP, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 }; +#ifdef HAVE_ZLIB +static unsigned char telnet_compress_send_request_v2[] = { IAC, WILL, + TELOPT_COMPRESS2 }; + +static unsigned char telnet_compress_send_request_v1[] = { IAC, WILL, + TELOPT_COMPRESS }; + +static unsigned char telnet_compress_v1_response[] = { IAC, SB, + TELOPT_COMPRESS, WILL, + SE }; +static unsigned char telnet_compress_v2_response[] = { IAC, SB, + TELOPT_COMPRESS2, IAC, + SE }; + +#endif +static unsigned char telnet_do_mxp[] = { IAC, DO, TELOPT_MXP }; +static unsigned char telnet_will_mxp[] = { IAC, SB, TELOPT_MXP, IAC, SE }; +static unsigned char telnet_will_mssp[] = { IAC, WILL, TELOPT_MSSP }; +static unsigned char telnet_start_mssp[] = { IAC, SB, TELOPT_MSSP }; +static unsigned char telnet_mssp_value[] = {MSSP_VAR, '%', 's', MSSP_VAL, '%', 's', 0}; +static unsigned char telnet_end_sub[] = {IAC, SE}; +static unsigned char telnet_will_zmp[] = { IAC, WILL, TELOPT_ZMP}; +static unsigned char telnet_start_zmp[] = { IAC, SB, TELOPT_ZMP}; +static unsigned char telnet_do_newenv[] = { IAC, DO, TELOPT_NEW_ENVIRON }; +static unsigned char telnet_send_uservar[] = { IAC, SB, TELOPT_NEW_ENVIRON, NEW_ENV_SEND, IAC, SE }; +static unsigned char telnet_do_gmcp[] = {IAC, DO, TELOPT_GMCP}; +static unsigned char telnet_start_gmcp[] = {IAC, SB, TELOPT_GMCP}; +/* + * local function prototypes. + */ +#ifdef SIGNAL_FUNC_TAKES_INT +static void sigpipe_handler (int); +#else +static void sigpipe_handler (void); +#endif + +static void hname_handler (void); +static void get_user_data (interactive_t *); +static char *get_user_command (void); +static char *first_cmd_in_buf (interactive_t *); +static int cmd_in_buf (interactive_t *); +static int call_function_interactive (interactive_t *, char *); +static void print_prompt (interactive_t *); +static void query_addr_name (object_t *); +static void got_addr_number (char *, char *); +#ifdef IPV6 +static void add_ip_entry (struct in6_addr, char *); +#else +static void add_ip_entry (long, char *); +#endif +static void new_user_handler (int); +static void end_compression (interactive_t *); +static void start_compression (interactive_t *); +static int send_compressed (interactive_t *ip, unsigned char* data, int length); + + +#ifdef NO_SNOOP +# define handle_snoop(str, len, who) +#else +# define handle_snoop(str, len, who) if ((who)->snooped_by) receive_snoop(str, len, who->snooped_by) + +static void receive_snoop (const char *, int, object_t * ob); + +#endif + +/* + * public local variables. + */ +fd_set readmask, writemask; +int num_user; +#ifdef F_SET_HIDE +int num_hidden_users = 0; /* for the O_HIDDEN flag. This counter must + * be kept up to date at all times! If you + * modify the O_HIDDEN flag in an object, + * make sure that you update this counter if + * the object is interactive. */ +#endif +int add_message_calls = 0; +#ifdef F_NETWORK_STATS +int inet_out_packets = 0; +int inet_out_volume = 0; +int inet_in_packets = 0; +int inet_in_volume = 0; +#ifdef PACKAGE_SOCKETS +int inet_socket_in_packets = 0; +int inet_socket_in_volume = 0; +int inet_socket_out_packets = 0; +int inet_socket_out_volume = 0; +#endif +#endif +int inet_packets = 0; +int inet_volume = 0; +interactive_t **all_users = 0; +int max_users = 0; +#ifdef HAS_CONSOLE +int has_console = -1; +#endif + +/* + * private local variables. + */ +static int addr_server_fd = -1; + +static +void set_linemode (interactive_t * ip) +{ + if (ip->iflags & USING_LINEMODE) { + add_binary_message(ip->ob, telnet_line_mode, sizeof(telnet_line_mode)); + add_binary_message(ip->ob, telnet_lm_mode, sizeof(telnet_lm_mode)); + } else { + add_binary_message(ip->ob, telnet_no_single, sizeof(telnet_no_single)); + } +} + +static +void set_charmode (interactive_t * ip) +{ + if (ip->iflags & USING_LINEMODE) { + add_binary_message(ip->ob, telnet_char_mode, sizeof(telnet_char_mode)); + } else { + add_binary_message(ip->ob, telnet_yes_single, sizeof(telnet_yes_single)); + } +} + +#ifndef NO_SNOOP +static void +receive_snoop (const char * buf, int len, object_t * snooper) +{ + /* command giver no longer set to snooper */ +#ifdef RECEIVE_SNOOP + char *str; + + str = new_string(len, "receive_snoop"); + memcpy(str, buf, len); + str[len] = 0; + push_malloced_string(str); + apply(APPLY_RECEIVE_SNOOP, snooper, 1, ORIGIN_DRIVER); +#else + /* snoop output is now % in all cases */ + add_message(snooper, "%", 1); + add_message(snooper, buf, len); +#endif +} +#endif + +/* + * Initialize new user connection socket. + */ +void init_user_conn() +{ +#ifdef IPV6 + struct sockaddr_in6 sin; +#else + struct sockaddr_in sin; +#endif + memset(&sin, 0, sizeof(sin)); + socklen_t sin_len; + int optval; + int i; + int have_fd6; + int fd6_which = -1; + + /* Check for fd #6 open as a valid socket */ + optval = 1; + have_fd6 = (setsockopt(6, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval)) == 0); + + for (i=0; i < 5; i++) { +#ifdef F_NETWORK_STATS + external_port[i].in_packets = 0; + external_port[i].in_volume = 0; + external_port[i].out_packets = 0; + external_port[i].out_volume = 0; +#endif + if (!external_port[i].port) { +#if defined(FD6_KIND) && defined(FD6_PORT) + if (!have_fd6) continue; + fd6_which = i; + have_fd6 = 0; + if (FD6_KIND == PORT_UNDEFINED || FD6_PORT < 1) { + debug_message("Socket passed to fd 6 ignored (support is disabled).\n"); + continue; + } + + debug_message("Accepting connections on fd 6 (port %d).\n", FD6_PORT); + external_port[i].kind = FD6_KIND; + external_port[i].port = FD6_PORT; + external_port[i].fd = 6; +#else + continue; +#endif + } else { + /* + * create socket of proper type. + */ + int sockflags = SOCK_STREAM; +#ifdef IPV6 + if ((external_port[i].fd = socket(PF_INET6, sockflags, 0)) == -1) { +#else + if ((external_port[i].fd = socket(PF_INET, sockflags, 0)) == -1) { +#endif + debug_perror("init_user_conn: socket", 0); + exit(1); + } + + /* + * enable local address reuse. + */ + optval = 1; + if (setsockopt(external_port[i].fd, SOL_SOCKET, SO_REUSEADDR, + (char *) &optval, sizeof(optval)) == -1) { + socket_perror("init_user_conn: setsockopt", 0); + exit(2); + } +#ifdef FD_CLOEXEC + fcntl(external_port[i].fd, F_SETFD, FD_CLOEXEC); +#endif + /* + * fill in socket address information. + */ +#ifdef IPV6 + sin.sin6_family = AF_INET6; + if(MUD_IP[0]) + inet_pton(AF_INET6, MUD_IP, &(sin.sin6_addr)); + else + sin.sin6_addr = in6addr_any; + sin.sin6_port = htons((u_short) external_port[i].port); +#else + sin.sin_family = AF_INET; + if (MUD_IP[0]) + sin.sin_addr.s_addr = inet_addr(MUD_IP); + else + sin.sin_addr.s_addr = INADDR_ANY; + sin.sin_port = htons((u_short) external_port[i].port); +#endif + + /* + * bind name to socket. + */ + if (bind(external_port[i].fd, (struct sockaddr *) & sin, + sizeof(sin)) == -1) { + socket_perror("init_user_conn: bind", 0); + exit(3); + } + } + /* + * get socket name. + */ + sin_len = sizeof(sin); + if (getsockname(external_port[i].fd, (struct sockaddr *) & sin, + &sin_len) == -1) { + socket_perror("init_user_conn: getsockname", 0); + if (i != fd6_which) { + exit(4); + } + } + /* + * set socket non-blocking, + */ + if (set_socket_nonblocking(external_port[i].fd, 1) == -1) { + socket_perror("init_user_conn: set_socket_nonblocking 1", 0); + if (i != fd6_which) { + exit(8); + } + } + /* + * listen on socket for connections. + */ + if (listen(external_port[i].fd, 128) == -1) { + socket_perror("init_user_conn: listen", 0); + if (i != fd6_which) { + exit(10); + } + } + } + if (have_fd6) { + debug_message("No more ports available; fd #6 ignored.\n"); + } + /* + * register signal handler for SIGPIPE. + */ +#if defined(SIGPIPE) && defined(SIGNAL_ERROR) +#ifdef SIG_IGN + if (signal(SIGPIPE, SIG_IGN) == SIGNAL_ERROR) { + debug_perror("init_user_conn: signal SIGPIPE",0); + exit(5); + } +#else + if (signal(SIGPIPE, sigpipe_handler) == SIGNAL_ERROR) { + debug_perror("init_user_conn: signal SIGPIPE",0); + exit(5); + } +#endif +#endif +} + +/* + * Shut down new user accept file descriptor. + */ +void ipc_remove() +{ + int i; + + for (i = 0; i < 5; i++) { + if (!external_port[i].port) continue; + if (OS_socket_close(external_port[i].fd) == -1) { + socket_perror("ipc_remove: close", 0); + } + } + + debug_message("closed external ports\n"); +} + +void init_addr_server (char * hostname, int addr_server_port) +{ +#ifdef WIN32 + WORD wVersionRequested = MAKEWORD(1,1); + WSADATA wsaData; + WSAStartup(wVersionRequested, &wsaData); +#endif +#ifdef IPV6 + struct sockaddr_in6 server; +#else + struct sockaddr_in server; +#endif +#ifndef IPV6 + struct hostent *hp; + int addr; +#endif + int server_fd; + int optval; + + if (addr_server_fd >= 0) + return; + + if (!hostname) return; +#ifdef IPV6 + /* + * get network host data for hostname. + */ + struct addrinfo hints, *res; + hints.ai_family = AF_INET6; + hints.ai_socktype = 0; + hints.ai_protocol = 0; +#ifndef AI_V4MAPPED + hints.ai_flags = AI_CANONNAME; +#else + hints.ai_flags = AI_CANONNAME| AI_V4MAPPED; +#endif + + if(getaddrinfo(hostname, "1234", &hints, &res)){ + //failed + socket_perror("init_addr_server: getaddrinfo", 0); + return; + } + + memcpy(&server, res->ai_addr, sizeof(server)); + freeaddrinfo(res); + server.sin6_port = htons((u_short) addr_server_port); + //inet_pton(AF_INET6, hostname, &(server.sin6_addr)); + //memcpy((char *) &server.sin6_addr, (char *) hp->h_addr, hp->h_length); + /* + * create socket of proper type. + */ + server_fd = socket(AF_INET6, SOCK_STREAM, 0); +#else + /* + * get network host data for hostname. + */ + if (hostname[0] >= '0' && hostname[0] <= '9' && + (addr = inet_addr(hostname)) != -1) { + hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET); + } else { + hp = gethostbyname(hostname); + } + if (hp == NULL) { + socket_perror("init_addr_server: gethostbyname", 0); + return; + } + + /* + * set up address information for server. + */ + server.sin_family = AF_INET; + server.sin_port = htons((u_short) addr_server_port); + server.sin_addr.s_addr = inet_addr(hostname); + memcpy((char *) &server.sin_addr, (char *) hp->h_addr, hp->h_length); + /* + * create socket of proper type. + */ + server_fd = socket(AF_INET, SOCK_STREAM, 0); +#endif + if (server_fd == INVALID_SOCKET) { /* problem opening socket */ + socket_perror("init_addr_server: socket", 0); + return; + } + /* + * enable local address reuse. + */ + optval = 1; + if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &optval, + sizeof(optval)) == -1) { + socket_perror("init_addr_server: setsockopt", 0); + return; + } + /* + * connect socket to server address. + */ + if (connect(server_fd, (struct sockaddr *) & server, sizeof(server)) == -1) { + if(ADDRFAIL_NOTIFY){ + if (socket_errno == ECONNREFUSED && ADDRFAIL_NOTIFY) + debug_message("Connection to address server (%s %d) refused.\n", + hostname, addr_server_port); + else + socket_perror("init_addr_server: connect", 0); + } + OS_socket_close(server_fd); + return; + } + addr_server_fd = server_fd; + debug_message("Connected to address server on %s port %d\n", hostname, + addr_server_port); + /* + * set socket non-blocking. + */ + if (set_socket_nonblocking(server_fd, 1) == -1) { + socket_perror("init_addr_server: set_socket_nonblocking 1", 0); + return; + } +#ifdef WIN32 + WSACleanup(); +#endif +} + +/* + * If there is a shadow for this object, then the message should be + * sent to it. But only if catch_tell() is defined. Beware that one of the + * shadows may be the originator of the message, which means that we must + * not send the message to that shadow, or any shadows in the linked list + * before that shadow. + * + * Also note that we don't need to do this in the case of + * INTERACTIVE_CATCH_TELL, since catch_tell() was already called + * _instead of_ add_message(), and shadows got their chance then. + */ +#if !defined(INTERACTIVE_CATCH_TELL) && !defined(NO_SHADOWS) +#define SHADOW_CATCH_MESSAGE +#endif + +#ifdef SHADOW_CATCH_MESSAGE +static int shadow_catch_message (object_t * ob, const char * str) +{ + if (!ob->shadowed) + return 0; + while (ob->shadowed != 0 && ob->shadowed != current_object) + ob = ob->shadowed; + while (ob->shadowing) { + copy_and_push_string(str); + if (apply(APPLY_CATCH_TELL, ob, 1, ORIGIN_DRIVER)) + /* this will work, since we know the */ + /* function is defined */ + return 1; + ob = ob->shadowing; + } + return 0; +} +#endif + +/* + * Send a message to an interactive object. If that object is shadowed, + * special handling is done. + */ +void add_message (object_t * who, const char * data, int len) +{ + interactive_t *ip; + const char *cp; + const char *end; + char *trans; + int translen; + /* + * if who->interactive is not valid, write message on stderr. + * (maybe) + */ + if (!who || (who->flags & O_DESTRUCTED) || !who->interactive || + (who->interactive->iflags & (NET_DEAD | CLOSING))) { +#ifdef NONINTERACTIVE_STDERR_WRITE + putc(']', stderr); + fwrite(data, len, 1, stderr); +#endif + return; + } + ip = who->interactive; + trans = translate(ip->trans->outgoing, data, len, &translen); +#ifdef SHADOW_CATCH_MESSAGE + /* + * shadow handling. + */ + if (shadow_catch_message(who, data)) { +#ifdef SNOOP_SHADOWED + handle_snoop(data, len, ip); +#endif + return; + } +#endif /* NO_SHADOWS */ + + /* + * write message into ip->message_buf. + */ + end = trans + translen; + for (cp = trans; cp < end; cp++) { + if (ip->message_length == MESSAGE_BUF_SIZE) { + if (!flush_message(ip)) { + debug(connections, ("Broken connection during add_message.")); + return; + } + if (ip->message_length == MESSAGE_BUF_SIZE) + break; + } + if ((*cp == '\n' || *cp == -1) +#ifndef NO_BUFFER_TYPE + && ip->connection_type != PORT_BINARY +#endif + ) { + if (ip->message_length == (MESSAGE_BUF_SIZE - 1)) { + if (!flush_message(ip)) { + debug(connections, ("Broken connection during add_message.")); + return; + } + if (ip->message_length == (MESSAGE_BUF_SIZE - 1)) + break; + } + ip->message_buf[ip->message_producer] = (*cp == '\n')?'\r':-1; + ip->message_producer = (ip->message_producer + 1) + % MESSAGE_BUF_SIZE; + ip->message_length++; + } + ip->message_buf[ip->message_producer] = *cp; + ip->message_producer = (ip->message_producer + 1) % MESSAGE_BUF_SIZE; + ip->message_length++; + } + + handle_snoop(data, len, ip); + +#ifdef FLUSH_OUTPUT_IMMEDIATELY + flush_message(ip); +#endif + + add_message_calls++; +} /* add_message() */ + +/* WARNING: this can only handle results < LARGEST_PRINTABLE_STRING in size */ +void add_vmessage (object_t *who, const char *format, ...) +{ + int len; + interactive_t *ip; + char *cp, new_string_data[LARGEST_PRINTABLE_STRING + 1]; + va_list args; + + V_START(args, format); + V_VAR(object_t *, who, args); + V_VAR(char *, format, args); + /* + * if who->interactive is not valid, write message on stderr. + * (maybe) + */ + if (!who || (who->flags & O_DESTRUCTED) || !who->interactive || + (who->interactive->iflags & (NET_DEAD | CLOSING))) { +#ifdef NONINTERACTIVE_STDERR_WRITE + putc(']', stderr); + vfprintf(stderr, format, args); +#endif + va_end(args); + return; + } + ip = who->interactive; + new_string_data[0] = '\0'; + + vsnprintf(new_string_data, LARGEST_PRINTABLE_STRING, format, args); + va_end(args); + len = strlen(new_string_data); +#ifdef SHADOW_CATCH_MESSAGE + /* + * shadow handling. + */ + if (shadow_catch_message(who, new_string_data)) { +#ifdef SNOOP_SHADOWED + handle_snoop(new_string_data, len, ip); +#endif + return; + } +#endif /* NO_SHADOWS */ + + /* + * write message into ip->message_buf. + */ + for (cp = new_string_data; *cp != '\0'; cp++) { + if (ip->message_length == MESSAGE_BUF_SIZE) { + if (!flush_message(ip)) { + debug(connections, ("Broken connection during add_message.")); + return; + } + if (ip->message_length == MESSAGE_BUF_SIZE) + break; + } + if (*cp == '\n') { + if (ip->message_length == (MESSAGE_BUF_SIZE - 1)) { + if (!flush_message(ip)) { + debug(connections, ("Broken connection during add_message.\n")); + return; + } + if (ip->message_length == (MESSAGE_BUF_SIZE - 1)) + break; + } + ip->message_buf[ip->message_producer] = '\r'; + ip->message_producer = (ip->message_producer + 1) + % MESSAGE_BUF_SIZE; + ip->message_length++; + } + ip->message_buf[ip->message_producer] = *cp; + ip->message_producer = (ip->message_producer + 1) % MESSAGE_BUF_SIZE; + ip->message_length++; + } + if (ip->message_length != 0) { + if (!flush_message(ip)) { + debug(connections, ("Broken connection during add_message.\n")); + return; + } + } + + handle_snoop(new_string_data, len, ip); + +#ifdef FLUSH_OUTPUT_IMMEDIATELY + flush_message(ip); +#endif + + add_message_calls++; +} /* add_message() */ + +void add_binary_message (object_t * who, const unsigned char * data, int len) +{ + interactive_t *ip; + const unsigned char *cp, *end; + + /* + * if who->interactive is not valid, bail + */ + if (!who || (who->flags & O_DESTRUCTED) || !who->interactive || + (who->interactive->iflags & (NET_DEAD | CLOSING))) { + return; + } + ip = who->interactive; + + /* + * write message into ip->message_buf. + */ + end = data + len; + for (cp = data; cp < end; cp++) { + if (ip->message_length == MESSAGE_BUF_SIZE) { + if (!flush_message(ip)) { + debug(connections, ("Broken connection during add_message.")); + return; + } + if (ip->message_length == MESSAGE_BUF_SIZE) + break; + } + ip->message_buf[ip->message_producer] = *cp; + ip->message_producer = (ip->message_producer + 1) % MESSAGE_BUF_SIZE; + ip->message_length++; + } + + flush_message(ip); + add_message_calls++; +} + +/* + * Flush outgoing message buffer of current interactive object. + */ +int flush_message (interactive_t * ip) +{ + int length, num_bytes; + + /* + * if ip is not valid, do nothing. + */ + if (!ip || !ip->ob || !IP_VALID(ip, ip->ob) || + (ip->ob->flags & O_DESTRUCTED) || (ip->iflags & (NET_DEAD | CLOSING))){ + //debug(connections, ("flush_message: invalid target!\n")); + return 0; + } + /* + * write ip->message_buf[] to socket. + */ + while (ip->message_length != 0) { + if (ip->message_consumer < ip->message_producer) { + length = ip->message_producer - ip->message_consumer; + } else { + length = MESSAGE_BUF_SIZE - ip->message_consumer; + } +/* Need to use send to get out of band data + num_bytes = write(ip->fd,ip->message_buf + ip->message_consumer,length); + */ +#ifdef HAVE_ZLIB + if (ip->compressed_stream) { + num_bytes = send_compressed(ip, (unsigned char *)ip->message_buf + + ip->message_consumer, length); + } else { +#endif + num_bytes = send(ip->fd, ip->message_buf + ip->message_consumer, + length, ip->out_of_band | MSG_NOSIGNAL); +#ifdef HAVE_ZLIB + } +#endif + if (!num_bytes) { + ip->iflags |= NET_DEAD; + return 0; + } + if (num_bytes == -1) { +#ifdef EWOULDBLOCK + if (socket_errno == EWOULDBLOCK) { + //debug(connections, ("flush_message: write: Operation would block\n")); + return 1; +#else + if (0) { + ; +#endif + } else if (socket_errno == EINTR) { + //debug(connections, ("flush_message: write: Interrupted system call")); + return 1; + } else { + //socket_perror("flush_message: write", 0); + ip->iflags |= NET_DEAD; + return 0; + } + } + ip->message_consumer = (ip->message_consumer + num_bytes) % + MESSAGE_BUF_SIZE; + ip->message_length -= num_bytes; + ip->out_of_band = 0; + inet_packets++; + inet_volume += num_bytes; +#ifdef F_NETWORK_STATS + inet_out_packets++; + inet_out_volume += num_bytes; + external_port[ip->external_port].out_packets++; + external_port[ip->external_port].out_volume += num_bytes; +#endif + } + return 1; +} /* flush_message() */ + +static int send_mssp_val(mapping_t *map, mapping_node_t *el, void *obp){ + object_t *ob = (object_t *)obp; + if(el->values[0].type == T_STRING && el->values[1].type == T_STRING){ + char buf[1024]; + int len = sprintf(buf, (char *)telnet_mssp_value, el->values[0].u.string, el->values[1].u.string); + add_binary_message(ob, (unsigned char *)buf, len); + } else if (el->values[0].type == T_STRING && el->values[1].type == T_ARRAY && el->values[1].u.arr->size > 0 && el->values[1].u.arr->item[0].type == T_STRING){ + char buf[10240]; + int len = sprintf(buf, (char *)telnet_mssp_value, el->values[0].u.string, el->values[1].u.arr->item[0].u.string); + add_binary_message(ob, (unsigned char *)buf, len); + array_t *ar = el->values[1].u.arr; + int i; + unsigned char val = MSSP_VAL; + for(i=1; i < ar->size; i++){ + if(ar->item[i].type == T_STRING){ + add_binary_message(ob, &val, 1); + add_binary_message(ob, (const unsigned char *)ar->item[i].u.string, strlen(ar->item[i].u.string)); + } + } + + } + return 0; +} + +static void copy_chars (interactive_t * ip, char * from, int num_bytes) +{ + int i, start, x; + unsigned char dont_response[3] = { IAC, DONT, 0 }; + unsigned char wont_response[3] = { IAC, WONT, 0 }; + + start = ip->text_end; + for (i = 0; i < num_bytes; i++) { + switch (ip->state) { + case TS_DATA: + switch ((unsigned char)from[i]) { + case IAC: + ip->state = TS_IAC; + break; + +#if defined(NO_ANSI) && defined(STRIP_BEFORE_PROCESS_INPUT) + case 0x1b: + ip->text[ip->text_end++] = ANSI_SUBSTITUTE; + break; +#endif + + case 0x08: + case 0x7f: + if (ip->iflags & SINGLE_CHAR) + ip->text[ip->text_end++] = from[i]; + else { + if (ip->text_end > 0) + ip->text_end--; + } + break; + + default: + ip->text[ip->text_end++] = from[i]; + break; + } + break; + + case TS_IAC: + switch ((unsigned char)from[i]) { + case IAC: + ip->state = TS_DATA; + ip->text[ip->text_end++] = from[i]; + break; + + case WILL: + ip->state = TS_WILL; + break; + + case WONT: + ip->state = TS_WONT; + break; + + case DO: + ip->state = TS_DO; + break; + + case DONT: + ip->state = TS_DONT; + break; + + case SB: + ip->state = TS_SB; + ip->sb_pos = 0; + break; + + case BREAK: + add_binary_message(ip->ob, telnet_break_response, sizeof(telnet_break_response)); + break; + + case IP: /* interrupt process */ + add_binary_message(ip->ob, telnet_ip_response, sizeof(telnet_ip_response)); + break; + + case AYT: /* are you there? you bet */ + add_binary_message(ip->ob, telnet_ayt_response, sizeof(telnet_ayt_response)); + break; + + case AO: /* abort output */ + flush_message(ip); + ip->out_of_band = MSG_OOB; + add_binary_message(ip->ob, telnet_abort_response, sizeof(telnet_abort_response)); + break; + + default: + ip->state = TS_DATA; + break; + } + break; + + case TS_WILL: + ip->iflags |= USING_TELNET; + switch ((unsigned char)from[i]) { + case TELOPT_TTYPE: + add_binary_message(ip->ob, telnet_term_query, sizeof(telnet_term_query)); + break; + + case TELOPT_LINEMODE: + /* Do linemode and set the mode: EDIT + TRAPSIG */ + ip->iflags |= USING_LINEMODE; + set_linemode(ip); + break; + + case TELOPT_ECHO: + case TELOPT_NAWS: + /* do nothing, but don't send a dont response */ + break; + + case TELOPT_MXP : + /* Mxp is enabled, tell the mudlib about it. */ + apply(APPLY_MXP_ENABLE, ip->ob, 0, ORIGIN_DRIVER); + ip->iflags |= USING_MXP; + break; + case TELOPT_GMCP: + apply(APPLY_GMCP_ENABLE, ip->ob, 0, ORIGIN_DRIVER); + ip->iflags |= USING_GMCP; + break; + case TELOPT_NEW_ENVIRON : + add_binary_message(ip->ob, telnet_send_uservar, sizeof(telnet_send_uservar)); + break; + + default: + dont_response[2] = from[i]; + add_binary_message(ip->ob, dont_response, sizeof(dont_response)); + break; + } + ip->state = TS_DATA; + break; + + case TS_WONT: + ip->iflags |= USING_TELNET; + switch ((unsigned char)from[i]) { + case TELOPT_LINEMODE: + /* If we're in single char mode, we just requested for + * linemode to be disabled, so don't remove our flag. + */ + if (!(ip->iflags & SINGLE_CHAR)) + ip->iflags &= ~USING_LINEMODE; + break; + } + ip->state = TS_DATA; + break; + + case TS_DO: + switch ((unsigned char)from[i]) { + case TELOPT_TM: + add_binary_message(ip->ob, telnet_do_tm_response, sizeof(telnet_do_tm_response)); + break; + + case TELOPT_SGA: + if (ip->iflags & USING_LINEMODE) { + ip->iflags |= SUPPRESS_GA; + add_binary_message(ip->ob, telnet_yes_single, sizeof(telnet_yes_single)); + } else { + if (ip->iflags & SINGLE_CHAR) + add_binary_message(ip->ob, telnet_yes_single, sizeof(telnet_yes_single)); + else + add_binary_message(ip->ob, telnet_no_single, sizeof(telnet_no_single)); + } + break; + + case TELOPT_ECHO: + /* do nothing, but don't send a wont response */ + break; + case TELOPT_MSSP: + { + add_binary_message(ip->ob, telnet_start_mssp, sizeof(telnet_start_mssp)); + svalue_t *res = apply_master_ob(APPLY_GET_MUD_STATS, 0); + mapping_t *map; + if(res <= 0 || res->type != T_MAPPING) { + map = allocate_mapping(0); + free_svalue(&apply_ret_value, "telnet neg"); + apply_ret_value.type = T_MAPPING; + apply_ret_value.u.map = map; + } else + map = res->u.map; + //ok, so we have a mapping, first make sure we send the required values + char *tmp = findstring("NAME"); + if(tmp){ + svalue_t *name = find_string_in_mapping(map, tmp); + if(!name || name->type != T_STRING) + tmp = 0; + } + if(!tmp){ + char buf[1024]; + int len = sprintf(buf, (char *)telnet_mssp_value, "NAME", MUD_NAME); + add_binary_message(ip->ob, (unsigned char *)buf, len); + } + tmp = findstring("PLAYERS"); + if(tmp){ + svalue_t *players = find_string_in_mapping(map, tmp); + if(!players || players->type != T_STRING) + tmp = 0; + } + if(!tmp){ + char buf[1024]; + char num[5]; + sprintf(num, "%d", num_user); + int len = sprintf(buf, (char *)telnet_mssp_value, "PLAYERS", num); + add_binary_message(ip->ob, (unsigned char *)buf, len); + } + tmp = findstring("UPTIME"); + if(tmp){ + svalue_t *upt = find_string_in_mapping(map, tmp); + if(!upt || upt->type != T_STRING) + tmp = 0; + } + if(!tmp){ + char buf[1024]; + char num[20]; + + sprintf(num, "%ld", boot_time); + int len = sprintf(buf, (char *)telnet_mssp_value, "UPTIME", num); + add_binary_message(ip->ob, (unsigned char *)buf, len); + } + //now send the rest + mapTraverse(map, send_mssp_val, ip->ob); + add_binary_message(ip->ob, telnet_end_sub, sizeof(telnet_end_sub)); + } +#ifdef HAVE_ZLIB + case TELOPT_COMPRESS : + if(!ip->compressed_stream){ + add_binary_message(ip->ob, telnet_compress_v1_response, + sizeof(telnet_compress_v1_response)); + start_compression(ip); + } + break; + case TELOPT_COMPRESS2 : + if(!ip->compressed_stream){ + add_binary_message(ip->ob, telnet_compress_v2_response, + sizeof(telnet_compress_v2_response)); + start_compression(ip); + } + break; +#endif + case TELOPT_ZMP : + ip->iflags |= USING_ZMP; + break; + default: + wont_response[2] = from[i]; + add_binary_message(ip->ob, wont_response, sizeof(wont_response)); + break; + } + ip->state = TS_DATA; + break; + + case TS_DONT: + switch ((unsigned char)from[i]) { + case TELOPT_SGA: + if (ip->iflags & USING_LINEMODE) { + ip->iflags &= ~SUPPRESS_GA; + add_binary_message(ip->ob, telnet_no_single, sizeof(telnet_no_single)); + } + break; +#ifdef HAVE_ZLIB + case TELOPT_COMPRESS2: + // If we are told not to use v2, then try v1. + add_binary_message(ip->ob, telnet_compress_send_request_v1, + sizeof(telnet_compress_send_request_v1)); + break; +#endif + } + ip->state = TS_DATA; + break; + + case TS_SB: + if ((unsigned char)from[i] == IAC) { + ip->state = TS_SB_IAC; + break; + } + if (ip->sb_pos < ip->sb_size - 1) + ip->sb_buf[ip->sb_pos++] = from[i]; + else if(ip->sb_size < MAX_STRING_LENGTH){ + ip->sb_size*=2; + if(ip->sb_size > MAX_STRING_LENGTH) + ip->sb_size = MAX_STRING_LENGTH; + ip->sb_buf = (char *)REALLOC(ip->sb_buf, ip->sb_size); + if (ip->sb_pos < ip->sb_size - 1) + ip->sb_buf[ip->sb_pos++] = from[i]; + } + break; + + case TS_SB_IAC: + switch ((unsigned char)from[i]) { + case IAC: + if (ip->sb_pos < SB_SIZE - 1) { + ip->sb_buf[ip->sb_pos++] = from[i]; + ip->state = TS_SB; + } + break; + + case SE: + ip->state = TS_DATA; + ip->sb_buf[ip->sb_pos] = 0; + switch ((unsigned char)ip->sb_buf[0]) { + + case TELOPT_NEW_ENVIRON : + { + int j, k; + char env_buf[BUF_SIZE]; + j = 0; + k = 1; + while(ip->sb_buf[k] > -1 && k < (ip->sb_pos - 1)){ + k++; + if(!(ip->sb_buf[k])) env_buf[j] = ENV_FILLER; + if(ip->sb_buf[k] == 1) env_buf[j] = 1; + if((ip->sb_buf[k] > 31)){ + env_buf[j] = ip->sb_buf[k]; + } + if(env_buf[j]) j++; + } + env_buf[j] = 0; + copy_and_push_string(env_buf); + apply(APPLY_RECEIVE_ENVIRON, ip->ob, 1, ORIGIN_DRIVER); + break; + + } + case TELOPT_LINEMODE: + switch ((unsigned char)ip->sb_buf[1]) { + case LM_MODE: + /* Don't do anything with an ACK */ + if (!(ip->sb_buf[2] & MODE_ACK)) { + unsigned char sb_ack[] = { IAC, SB, TELOPT_LINEMODE, LM_MODE, MODE_EDIT | MODE_TRAPSIG | MODE_ACK, IAC, SE }; + + /* Accept only EDIT and TRAPSIG && force them too */ + add_binary_message(ip->ob, sb_ack, sizeof(sb_ack)); + } + break; + + case LM_SLC: + { + int slc_length = 4; + unsigned char slc_response[SB_SIZE + 6] = { IAC, SB, TELOPT_LINEMODE, LM_SLC }; + + for (x = 2; x < ip->sb_pos; x += 3) { + /* no response for an ack */ + if (ip->sb_buf[x + 1] & SLC_ACK) + continue; + + /* If we get { 0, SLC_DEFAULT, 0 } or { 0, SLC_VARIABLE, 0 } return a list of values */ + /* If it's SLC_DEFAULT, reset to defaults first */ + if (!ip->sb_buf[x] && !ip->sb_buf[x + 2]) { + if (ip->sb_buf[x + 1] == SLC_DEFAULT || ip->sb_buf[x + 1] == SLC_VARIABLE) { + int n; + + for (n = 0; n < NSLC; n++) { + slc_response[slc_length++] = n + 1; + if (ip->sb_buf[x + 1] == SLC_DEFAULT) { + ip->slc[n][0] = slc_default_flags[n]; + ip->slc[n][1] = slc_default_chars[n]; + slc_response[slc_length++] = SLC_DEFAULT; + } else { + slc_response[slc_length++] = ip->slc[n][0]; + } + slc_response[slc_length++] = ip->slc[n][1]; + } + break; + } + } + + slc_response[slc_length++] = ip->sb_buf[x]--; + + /* If the first octet is out of range, we don't support it */ + /* If the default flag is not supported, we don't support it */ + if (ip->sb_buf[x] >= NSLC || slc_default_flags[ip->sb_buf[x]] == SLC_NOSUPPORT) { + slc_response[slc_length++] = SLC_NOSUPPORT; + slc_response[slc_length++] = ip->sb_buf[x + 2]; + if ((unsigned char)ip->sb_buf[x + 2] == IAC) + slc_response[slc_length++] = IAC; + continue; + } + + switch ((ip->sb_buf[x + 1] & SLC_LEVELBITS)) { + case SLC_NOSUPPORT: + if (slc_default_flags[ip->sb_buf[x]] == SLC_CANTCHANGE) { + slc_response[slc_length++] = SLC_CANTCHANGE; + slc_response[slc_length++] = ip->slc[ip->sb_buf[x]][1]; + break; + } + slc_response[slc_length++] = SLC_ACK | SLC_NOSUPPORT; + slc_response[slc_length++] = ip->sb_buf[x + 2]; + ip->slc[ip->sb_buf[x]][0] = SLC_NOSUPPORT; + ip->slc[ip->sb_buf[x]][1] = 0; + break; + + case SLC_VARIABLE: + if (slc_default_flags[ip->sb_buf[x]] == SLC_CANTCHANGE) { + slc_response[slc_length++] = SLC_CANTCHANGE; + slc_response[slc_length++] = ip->slc[ip->sb_buf[x]][1]; + break; + } + slc_response[slc_length++] = SLC_ACK | SLC_VARIABLE; + slc_response[slc_length++] = ip->sb_buf[x + 2]; + ip->slc[ip->sb_buf[x]][0] = ip->sb_buf[x + 1]; + ip->slc[ip->sb_buf[x]][1] = ip->sb_buf[x + 2]; + break; + + case SLC_CANTCHANGE: + slc_response[slc_length++] = SLC_ACK | SLC_CANTCHANGE; + slc_response[slc_length++] = ip->sb_buf[x + 2]; + ip->slc[ip->sb_buf[x]][0] = ip->sb_buf[x + 1]; + ip->slc[ip->sb_buf[x]][1] = ip->sb_buf[x + 2]; + break; + + case SLC_DEFAULT: + slc_response[slc_length++] = slc_default_flags[ip->sb_buf[x]]; + slc_response[slc_length++] = slc_default_flags[ip->sb_buf[x]]; + ip->slc[ip->sb_buf[x]][0] = slc_default_flags[ip->sb_buf[x]]; + ip->slc[ip->sb_buf[x]][1] = slc_default_chars[ip->sb_buf[x]]; + break; + + default: + slc_response[slc_length++] = SLC_NOSUPPORT; + slc_response[slc_length++] = ip->sb_buf[x + 2]; + if ((unsigned char)slc_response[slc_length - 1] == IAC) + slc_response[slc_length++] = IAC; + break; + } + } + + if (slc_length > 4) { + /* send our response */ + slc_response[slc_length++] = IAC; + slc_response[slc_length++] = SE; + add_binary_message(ip->ob, slc_response, slc_length); + } + } + break; + + case DO: + { + unsigned char sb_wont[] = { IAC, SB, TELOPT_LINEMODE, WONT, 0, IAC, SE }; + + /* send back IAC SB TELOPT_LINEMODE WONT x IAC SE */ + sb_wont[4] = ip->sb_buf[2]; + add_binary_message(ip->ob, sb_wont, sizeof(sb_wont)); + } + break; + + case WILL: + { + unsigned char sb_dont[] = { IAC, SB, TELOPT_LINEMODE, DONT, 0, IAC, SE }; + + /* send back IAC SB TELOPT_LINEMODE DONT x IAC SE */ + sb_dont[4] = ip->sb_buf[2]; + add_binary_message(ip->ob, sb_dont, sizeof(sb_dont)); + } + break; + } + break; + + case TELOPT_NAWS: + if (ip->sb_pos >= 5) { + push_number(((unsigned char)ip->sb_buf[1] << 8) | (unsigned char)ip->sb_buf[2]); + push_number(((unsigned char)ip->sb_buf[3] << 8) | (unsigned char)ip->sb_buf[4]); + apply(APPLY_WINDOW_SIZE, ip->ob, 2, ORIGIN_DRIVER); + } + break; + + case TELOPT_TTYPE: + if (!ip->sb_buf[1]) { + copy_and_push_string(ip->sb_buf + 2); + apply(APPLY_TERMINAL_TYPE, ip->ob, 1, ORIGIN_DRIVER); + } + break; + case TELOPT_ZMP: + { + array_t *arr = allocate_array(max_array_size); + ip->sb_buf = (char *)REALLOC(ip->sb_buf, MAX(ip->sb_pos + 2, SB_SIZE)); + ip->sb_size = MAX(ip->sb_pos + 2, SB_SIZE); + ip->sb_buf[ip->sb_pos] = 0; + copy_and_push_string(ip->sb_buf+1); + int off=0; + int aro = 0; + while(1){ + off += strlen(ip->sb_buf+1+off)+2; + if(off >= ip->sb_pos-1) + break; + arr->item[aro].u.string = string_copy(&ip->sb_buf[off], "ZMP"); + arr->item[aro].type = T_STRING; + arr->item[aro++].subtype = STRING_MALLOC; + } + arr = resize_array(arr, aro); + push_refed_array(arr); + apply(APPLY_ZMP, ip->ob, 2, ORIGIN_DRIVER); + + } + break; + case TELOPT_GMCP: + ip->sb_buf[ip->sb_pos] = 0; + copy_and_push_string(&ip->sb_buf[1]); + apply(APPLY_GMCP, ip->ob, 1, ORIGIN_DRIVER); + break; + default: + for (x = 0; x < ip->sb_pos; x++) + ip->sb_buf[x] = (ip->sb_buf[x] ? ip->sb_buf[x] : 'I'); + copy_and_push_string(ip->sb_buf); + apply(APPLY_TELNET_SUBOPTION, ip->ob, 1, ORIGIN_DRIVER); + break; + } + break; + + default: + /* + * Apparently, old versions of MudOS would revert to TS_DATA here. + * Later versions handle the IAC, and then go back to TS_DATA mode. + * I don't think either is proper, but the related RFC documents + * aren't clear on what to do (854, 855). It is my feeling, that + * the safest thing to do here is to ignore the option. + * -- Marius, 6-Jun-2000 + */ + ip->state = TS_SB; + break; + } + break; + } + } + + if (ip->text_end > start) { + /* handle snooping - snooper does not see type-ahead due to + telnet being in linemode */ + if (!(ip->iflags & NOECHO)) + handle_snoop(ip->text + start, ip->text_end - start, ip); + } +} + +/* + * Read pending data for a user into user->interactive->text. + * This also does telnet negotiation. + */ +static void get_user_data (interactive_t * ip) +{ + int num_bytes, text_space; + char buf[MAX_TEXT]; + + /* compute how much data we can read right now */ + switch (ip->connection_type) + { + case PORT_TELNET: + text_space = MAX_TEXT - ip->text_end; + + /* check if we need more space */ + if (text_space < MAX_TEXT / 16) { + if (ip->text_start > 0) { + memmove(ip->text, ip->text + ip->text_start, ip->text_end - ip->text_start); + text_space += ip->text_start; + ip->text_end -= ip->text_start; + ip->text_start = 0; + } + + if (text_space < MAX_TEXT / 16) { + /* the user is sending too much data. flush it */ + ip->iflags |= SKIP_COMMAND; + ip->text_start = ip->text_end = 0; + text_space = MAX_TEXT; + } + } + break; + + case PORT_MUD: + if (ip->text_end < 4) + text_space = 4 - ip->text_end; + else + text_space = *(volatile int *)ip->text - ip->text_end + 4; + break; + + default: + text_space = sizeof(buf); + break; + } + + /* read the data from the socket */ + //debug(connections, ("get_user_data: read on fd %d\n", ip->fd)); + num_bytes = OS_socket_read(ip->fd, buf, text_space); + + if (!num_bytes) { + //if (ip->iflags & CLOSING) + // debug_message("get_user_data: tried to read from closing fd.\n"); + ip->iflags |= NET_DEAD; + remove_interactive(ip->ob, 0); + return; + } + + if (num_bytes == -1) { +#ifdef EWOULDBLOCK + if (socket_errno == EWOULDBLOCK) { + // debug(connections, ("get_user_data: read on fd %d: Operation would block.\n", ip->fd)); + return; + } +#endif + // debug_message("get_user_data: read on fd %d\n", ip->fd); + // socket_perror("get_user_data: read", 0); + ip->iflags |= NET_DEAD; + remove_interactive(ip->ob, 0); + return; + } + +#ifdef F_NETWORK_STATS + inet_in_packets++; + inet_in_volume += num_bytes; + external_port[ip->external_port].in_packets++; + external_port[ip->external_port].in_volume += num_bytes; +#endif + + /* process the data that we've just read */ + switch (ip->connection_type) + { + case PORT_TELNET: + copy_chars(ip, buf, num_bytes); + if (cmd_in_buf(ip)) + ip->iflags |= CMD_IN_BUF; + break; + + case PORT_MUD: + memcpy(ip->text + ip->text_end, buf, num_bytes); + ip->text_end += num_bytes; + + if (num_bytes == text_space) { + if (ip->text_end == 4) { + *(volatile int *)ip->text = ntohl(*(int *)ip->text); + if (*(volatile int *)ip->text > MAX_TEXT - 5) + remove_interactive(ip->ob, 0); + } else { + svalue_t value; + + ip->text[ip->text_end] = 0; + if (restore_svalue(ip->text + 4, &value) == 0) { + STACK_INC; + *sp = value; + } else { + push_undefined(); + } + ip->text_end = 0; + apply(APPLY_PROCESS_INPUT, ip->ob, 1, ORIGIN_DRIVER); + } + } + break; + + case PORT_ASCII: + { + char *nl, *p; + + memcpy(ip->text + ip->text_end, buf, num_bytes); + ip->text_end += num_bytes; + + p = ip->text + ip->text_start; + while ((nl = ( char *)memchr(p, '\n', ip->text_end - ip->text_start))) { + ip->text_start = (nl + 1) - ip->text; + + *nl = 0; + if (*(nl - 1) == '\r') + *--nl = 0; + + if (!(ip->ob->flags & O_DESTRUCTED)) { + char *str; + + str = new_string(nl - p, "PORT_ASCII"); + memcpy(str, p, nl - p + 1); + push_malloced_string(str); + apply(APPLY_PROCESS_INPUT, ip->ob, 1, ORIGIN_DRIVER); + } + + if (ip->text_start == ip->text_end) { + ip->text_start = ip->text_end = 0; + break; + } + + p = nl + 1; + } + } + break; + +#ifndef NO_BUFFER_TYPE + case PORT_BINARY: + { + buffer_t *buffer; + + buffer = allocate_buffer(num_bytes); + memcpy(buffer->item, buf, num_bytes); + + push_refed_buffer(buffer); + apply(APPLY_PROCESS_INPUT, ip->ob, 1, ORIGIN_DRIVER); + } + break; +#endif + } +} + +static int clean_buf (interactive_t * ip) +{ + /* skip null input */ + while (ip->text_start < ip->text_end && !*(ip->text + ip->text_start)) + ip->text_start++; + + /* if we've advanced beyond the end of the buffer, reset it */ + if (ip->text_start >= ip->text_end) { + ip->text_start = ip->text_end = 0; + } + + /* if we're skipping the current command, check to see if it has been + completed yet. if it has, flush it and clear the skip bit */ + if (ip->iflags & SKIP_COMMAND) { + char *p; + + for (p = ip->text + ip->text_start; p < ip->text + ip->text_end; p++) { + if (*p == '\r' || *p == '\n') { + ip->text_start += p - (ip->text + ip->text_start) + 1; + ip->iflags &= ~SKIP_COMMAND; + return clean_buf(ip); + } + } + } + + return (ip->text_end > ip->text_start); +} + +static int cmd_in_buf (interactive_t * ip) +{ + char *p; + + /* do standard input buffer cleanup */ + if (!clean_buf(ip)) + return 0; + + /* if we're in single character mode, we've got input */ + if (ip->iflags & SINGLE_CHAR) + return 1; + + /* search for a newline. if found, we have a command */ + for (p = ip->text + ip->text_start; p < ip->text + ip->text_end; p++) { + if (*p == '\r' || *p == '\n') + return 1; + } + + /* duh, no command */ + return 0; +} + +static char *first_cmd_in_buf (interactive_t * ip) +{ + char *p; +#ifdef GET_CHAR_IS_BUFFERED + static char tmp[2]; +#endif + + /* do standard input buffer cleanup */ + if (!clean_buf(ip)) + return 0; + + p = ip->text + ip->text_start; + + /* if we're in single character mode, we've got input */ + if (ip->iflags & SINGLE_CHAR) { + if (*p == 8 || *p == 127) + *p = 0; +#ifndef GET_CHAR_IS_BUFFERED + ip->text_start++; + if (!clean_buf(ip)) + ip->iflags &= ~CMD_IN_BUF; + return p; +#else + tmp[0] = *p; + ip->text[ip->text_start++] = 0; + if (!clean_buf(ip)) + ip->iflags &= ~CMD_IN_BUF; + return tmp; +#endif + } + + /* search for the newline */ + while (ip->text[ip->text_start] != '\n' && ip->text[ip->text_start] != '\r') + ip->text_start++; + + /* check for "\r\n" or "\n\r" */ + if (ip->text_start + 1 < ip->text_end && + ((ip->text[ip->text_start] == '\r' && ip->text[ip->text_start + 1] == '\n') || + (ip->text[ip->text_start] == '\n' && ip->text[ip->text_start + 1] == '\r'))) { + ip->text[ip->text_start++] = 0; + } + + ip->text[ip->text_start++] = 0; + if (!cmd_in_buf(ip)) + ip->iflags &= ~CMD_IN_BUF; + + return p; +} +/* + * SIGPIPE handler -- does very little for now. + */ +#ifndef SIG_IGN +#ifdef SIGNAL_FUNC_TAKES_INT +void sigpipe_handler (int sig) +#else +void sigpipe_handler() +#endif +{ + debug(connections, ("SIGPIPE received.")); + //don't comment the next line out, i'm pretty sure we'd crash on the next SIGPIPE, they're not worth it + signal(SIGPIPE, sigpipe_handler); +} /* sigpipe_handler() */ +#endif +/* + * SIGALRM handler. + */ +#ifdef SIGNAL_FUNC_TAKES_INT +void sigalrm_handler (int sig) +#else +void sigalrm_handler() +#endif +{ + outoftime = 1; +} /* sigalrm_handler() */ + +int max_fd; + +INLINE void make_selectmasks() +{ + int i; + max_fd = addr_server_fd; + /* + * generate readmask and writemask for select() call. + */ + FD_ZERO(&readmask); + FD_ZERO(&writemask); +#ifdef HAS_CONSOLE + /* set up a console */ + if(has_console > 0) + FD_SET(STDIN_FILENO, &readmask); +#endif + /* + * set new user accept fd in readmask. + */ + for (i = 0; i < 5; i++) { + if (!external_port[i].port) continue; + FD_SET(external_port[i].fd, &readmask); + if(external_port[i].fd > max_fd) + max_fd = external_port[i].fd; + } + /* + * set user fds in readmask. + */ + for (i = 0; i < max_users; i++) { + if (!all_users[i] || (all_users[i]->iflags & (CLOSING | CMD_IN_BUF))) + continue; + /* + * if this user needs more input to make a complete command, set his + * fd so we can get it. + */ + FD_SET(all_users[i]->fd, &readmask); + if(all_users[i]->fd > max_fd) + max_fd = all_users[i]->fd; + if (all_users[i]->message_length != 0) + FD_SET(all_users[i]->fd, &writemask); + } + /* + * if addr_server_fd is set, set its fd in readmask. + */ + if (addr_server_fd >= 0) { + FD_SET(addr_server_fd, &readmask); + + } +#if defined(PACKAGE_SOCKETS) || defined(PACKAGE_EXTERNAL) + /* + * set fd's for efun sockets. + */ + for (i = 0; i < max_lpc_socks; i++) { + if (lpc_socks[i].state != STATE_CLOSED) { + if (lpc_socks[i].state != STATE_FLUSHING && + (lpc_socks[i].flags & S_WACCEPT) == 0){ + FD_SET(lpc_socks[i].fd, &readmask); + if(lpc_socks[i].fd > max_fd) + max_fd = lpc_socks[i].fd; + } + if (lpc_socks[i].flags & S_BLOCKED){ + FD_SET(lpc_socks[i].fd, &writemask); + if(lpc_socks[i].fd > max_fd) + max_fd = lpc_socks[i].fd; + } + } + } +#endif +} /* make_selectmasks() */ + +/* + * Process I/O. + */ +INLINE void process_io() +{ + int i; + + /* + * check for new user connection. + */ + for (i = 0; i < 5; i++) { + if (!external_port[i].port) continue; + if (FD_ISSET(external_port[i].fd, &readmask)) { + debug(connections, ("process_io: NEW_USER\n")); + new_user_handler(i); + } + } + /* + * check for data pending on user connections. + */ + for (i = 0; i < max_users; i++) { + if (!all_users[i] || (all_users[i]->iflags & (CLOSING | CMD_IN_BUF))) + continue; + if (all_users[i]->iflags & NET_DEAD) { + remove_interactive(all_users[i]->ob, 0); + continue; + } + if (FD_ISSET(all_users[i]->fd, &readmask)) { + debug(connections, ("process_io: USER %d\n", i)); + get_user_data(all_users[i]); + if (!all_users[i]) + continue; + } + if (FD_ISSET(all_users[i]->fd, &writemask)) + flush_message(all_users[i]); + } +#if defined(PACKAGE_SOCKETS) || defined(PACKAGE_EXTERNAL) + /* + * check for data pending on efun socket connections. + */ + for (i = 0; i < max_lpc_socks; i++) { + if (lpc_socks[i].state != STATE_CLOSED) + if (FD_ISSET(lpc_socks[i].fd, &readmask)) + socket_read_select_handler(i); + if (lpc_socks[i].state != STATE_CLOSED) + if (FD_ISSET(lpc_socks[i].fd, &writemask)) + socket_write_select_handler(i); + } +#endif + /* + * check for data pending from address server. + */ + if (addr_server_fd >= 0) { + if (FD_ISSET(addr_server_fd, &readmask)) { + debug(connections, ("process_io: IP_DAEMON\n")); + hname_handler(); + } + } +#ifdef HAS_CONSOLE + /* Process console input */ + /* Note: need the has_console on the next line because linux (at least) + recycles fds, even STDIN_FILENO + */ + if((has_console > 0) && FD_ISSET(STDIN_FILENO, &readmask)) { + char s[1024]; + int sz; + + if((sz = read(STDIN_FILENO, s, 1023)) > 0) { + s[sz-1] = '\0'; + console_command(s); + } + else if(sz == 0) { + printf("Console exiting. The MUD remains.\n"); + has_console = 0; + } + else { + printf("Console read error: %d %d. Closing console.\n", sz, errno); + has_console = 0; + restore_sigttin(); + } + } +#endif + +} + +/* + * This is the new user connection handler. This function is called by the + * event handler when data is pending on the listening socket (new_user_fd). + * If space is available, an interactive data structure is initialized and + * the user is connected. + */ +static void new_user_handler (int which) +{ + int new_socket_fd; +#ifdef IPV6 + struct sockaddr_in6 addr; +#else + struct sockaddr_in addr; +#endif + socklen_t length; + int i, x; + object_t *master, *ob; + svalue_t *ret; + + length = sizeof(addr); + debug(connections, ("new_user_handler: accept on fd %d\n", external_port[which].fd)); + new_socket_fd = accept(external_port[which].fd, + (struct sockaddr *) & addr, &length); + if (new_socket_fd < 0) { +#ifdef EWOULDBLOCK + if (socket_errno == EWOULDBLOCK) { + debug(connections, ("new_user_handler: accept: Operation would block\n")); + } else { +#else + if (1) { +#endif + socket_perror("new_user_handler: accept", 0); + } + return; + } + + /* + * according to Amylaar, 'accepted' sockets in Linux 0.99p6 don't + * properly inherit the nonblocking property from the listening socket. + * Marius, 19-Jun-2000: this happens on other platforms as well, so just + * do it for everyone + */ + if (set_socket_nonblocking(new_socket_fd, 1) == -1) { + socket_perror("new_user_handler: set_socket_nonblocking 1", 0); + OS_socket_close(new_socket_fd); + return; + } +#if defined(SO_NOSIGPIPE) + i = 1; + + if (setsockopt(new_socket_fd, 1, SO_NOSIGPIPE, &i, sizeof(i)) == -1) + { + socket_perror("new_user_handler: setsockopt SO_NOSIGPIPE", 0); + /* it's ok if this fails */ + } +#endif + /* find the first available slot */ + for (i = 0; i < max_users; i++) + if (!all_users[i]) break; + + if (i == max_users) { + if (all_users) { + all_users = RESIZE(all_users, max_users + 10, interactive_t *, + TAG_USERS, "new_user_handler"); + } else { + all_users = CALLOCATE(10, interactive_t *, + TAG_USERS, "new_user_handler"); + } + while (max_users < i + 10) + all_users[max_users++] = 0; + } + + set_command_giver(master_ob); + master_ob->interactive = + (interactive_t *) + DXALLOC(sizeof(interactive_t), TAG_INTERACTIVE, + "new_user_handler"); +#ifndef NO_ADD_ACTION + master_ob->interactive->default_err_message.s = 0; +#endif + master_ob->interactive->connection_type = external_port[which].kind; + master_ob->interactive->sb_buf = (char *)MALLOC(SB_SIZE); + master_ob->interactive->sb_size = SB_SIZE; + master_ob->flags |= O_ONCE_INTERACTIVE; + /* + * initialize new user interactive data structure. + */ + master_ob->interactive->ob = master_ob; +#if defined(F_INPUT_TO) || defined(F_GET_CHAR) + master_ob->interactive->input_to = 0; +#endif + master_ob->interactive->iflags = 0; + master_ob->interactive->text[0] = '\0'; + master_ob->interactive->text_end = 0; + master_ob->interactive->text_start = 0; +#if defined(F_INPUT_TO) || defined(F_GET_CHAR) + master_ob->interactive->carryover = NULL; + master_ob->interactive->num_carry = 0; +#endif +#ifndef NO_SNOOP + master_ob->interactive->snooped_by = 0; +#endif + master_ob->interactive->last_time = current_time; +#ifdef TRACE + master_ob->interactive->trace_level = 0; + master_ob->interactive->trace_prefix = 0; +#endif +#ifdef OLD_ED + master_ob->interactive->ed_buffer = 0; +#endif +#ifdef HAVE_ZLIB + master_ob->interactive->compressed_stream = NULL; +#endif + + master_ob->interactive->message_producer = 0; + master_ob->interactive->message_consumer = 0; + master_ob->interactive->message_length = 0; + master_ob->interactive->state = TS_DATA; + master_ob->interactive->out_of_band = 0; +#ifdef USE_ICONV + master_ob->interactive->trans = get_translator("UTF-8"); +#else + master_ob->interactive->trans = (struct translation *) master_ob; + //never actually used, but avoids multiple ifdefs later on! +#endif + for (x = 0; x < NSLC; x++) { + master_ob->interactive->slc[x][0] = slc_default_flags[x]; + master_ob->interactive->slc[x][1] = slc_default_chars[x]; + } + all_users[i] = master_ob->interactive; + all_users[i]->fd = new_socket_fd; +#ifdef F_QUERY_IP_PORT + all_users[i]->local_port = external_port[which].port; +#endif +#ifdef F_NETWORK_STATS + all_users[i]->external_port = which; +#endif + set_prompt("> "); + + memcpy((char *) &all_users[i]->addr, (char *) &addr, length); +#ifdef IPV6 + char tmp[INET6_ADDRSTRLEN]; + debug(connections, ("New connection from %s.\n", inet_ntop(AF_INET6, &addr.sin6_addr, &tmp, INET6_ADDRSTRLEN))); +#else + debug(connections, ("New connection from %s.\n", inet_ntoa(addr.sin_addr))); +#endif + num_user++; + /* + * The user object has one extra reference. It is asserted that the + * master_ob is loaded. Save a pointer to the master ob incase it + * changes during APPLY_CONNECT. We want to free the reference on + * the right copy of the object. + */ + master = master_ob; + add_ref(master_ob, "new_user"); + push_number(external_port[which].port); + ret = apply_master_ob(APPLY_CONNECT, 1); + /* master_ob->interactive can be zero if the master object self + destructed in the above (don't ask) */ + set_command_giver(0); + if (ret == 0 || ret == (svalue_t *)-1 || ret->type != T_OBJECT + || !master_ob->interactive) { + if (master_ob->interactive) + remove_interactive(master_ob, 0); + else + free_object(&master, "new_user"); +#ifdef IPV6 + debug_message("Connection from %s aborted.\n", inet_ntop(AF_INET6, &addr.sin6_addr, tmp, INET6_ADDRSTRLEN)); +#else + debug_message("Connection from %s aborted.\n", inet_ntoa(addr.sin_addr)); +#endif + return; + } + /* + * There was an object returned from connect(). Use this as the user + * object. + */ + ob = ret->u.ob; +#ifdef F_SET_HIDE + if (ob->flags & O_HIDDEN) + num_hidden_users++; +#endif + ob->interactive = master_ob->interactive; + ob->interactive->ob = ob; + ob->flags |= O_ONCE_INTERACTIVE; + /* + * assume the existance of write_prompt and process_input in user.c + * until proven wrong (after trying to call them). + */ + ob->interactive->iflags |= (HAS_WRITE_PROMPT | HAS_PROCESS_INPUT); + + free_object(&master, "new_user"); + + master_ob->flags &= ~O_ONCE_INTERACTIVE; + master_ob->interactive = 0; + add_ref(ob, "new_user"); + set_command_giver(ob); + if (addr_server_fd >= 0) { + query_addr_name(ob); + } + + if (external_port[which].kind == PORT_TELNET) { + /* Ask permission to ask them for their terminal type */ + add_binary_message(ob, telnet_do_ttype, sizeof(telnet_do_ttype)); + /* Ask them for their window size */ + add_binary_message(ob, telnet_do_naws, sizeof(telnet_do_naws)); +#ifdef HAVE_ZLIB + add_binary_message(ob, telnet_compress_send_request_v2, + sizeof(telnet_compress_send_request_v2)); +#endif + // Ask them if they support mxp. + add_binary_message(ob, telnet_do_mxp, sizeof(telnet_do_mxp)); + // And mssp + add_binary_message(ob, telnet_will_mssp, sizeof(telnet_will_mssp)); + // May as well ask for zmp while we're there! + add_binary_message(ob, telnet_will_zmp, sizeof(telnet_will_zmp)); + // Also newenv + add_binary_message(ob, telnet_do_newenv, sizeof(telnet_do_newenv)); + // gmcp *yawn* + add_binary_message(ob, telnet_do_gmcp, sizeof(telnet_do_gmcp)); + } + + logon(ob); + debug(connections, ("new_user_handler: end\n")); + set_command_giver(0); +} /* new_user_handler() */ + +/* + * Return the first command of the next user in sequence that has a complete + * command in their buffer. A command is defined to be a single character + * when SINGLE_CHAR is set, or a newline terminated string otherwise. + */ +static char *get_user_command() +{ + static int NextCmdGiver = 0; + + int i; + interactive_t *ip; + char *user_command = 0; + + /* find and return a user command */ + for (i = 0; i < max_users; i++) { + ip = all_users[NextCmdGiver++]; + NextCmdGiver %= max_users; + + if (!ip || !ip->ob || ip->ob->flags & O_DESTRUCTED) + continue; + + /* if we've got text to send, try to flush it, could lose the link here */ + if (ip->message_length) { + object_t *ob = ip->ob; + flush_message(ip); + if (!IP_VALID(ip, ob) || (ip->iflags & NET_DEAD)) + continue; + } + + /* if there's a command in the buffer, pull it out! */ + if (ip->iflags & CMD_IN_BUF) { + NextCmdGiver++; + NextCmdGiver %= max_users; + user_command = first_cmd_in_buf(ip); + break; + } + } + + /* no command found - return 0 */ + if (!user_command) + return 0; + + /* got a command - return it and set command_giver */ + debug(connections, ("get_user_command: user_command = (%s)\n", user_command)); + save_command_giver(ip->ob); + +#ifndef GET_CHAR_IS_BUFFERED + if (ip->iflags & NOECHO) { +#else + if ((ip->iflags & NOECHO) && !(ip->iflags & SINGLE_CHAR)) { +#endif + /* must not enable echo before the user input is received */ + add_binary_message(command_giver, telnet_no_echo, sizeof(telnet_no_echo)); + ip->iflags &= ~NOECHO; + } + + ip->last_time = current_time; + return user_command; +} /* get_user_command() */ + +static int escape_command (interactive_t * ip, char * user_command) +{ + if (user_command[0] != '!') + return 0; +#ifdef OLD_ED + if (ip->ed_buffer) + return 1; +#endif +#if defined(F_INPUT_TO) || defined(F_GET_CHAR) + if (ip->input_to && ( !(ip->iflags & NOESC) && !(ip->iflags & I_SINGLE_CHAR) ) ) + return 1; +#endif + return 0; +} + +static void process_input (interactive_t * ip, char * user_command) +{ + svalue_t *ret; + + if (!(ip->iflags & HAS_PROCESS_INPUT)) { + parse_command(user_command, command_giver); + return; + } + + /* + * send a copy of user input back to user object to provide + * support for things like command history and mud shell + * programming languages. + */ + copy_and_push_string(user_command); + ret = apply(APPLY_PROCESS_INPUT, command_giver, 1, ORIGIN_DRIVER); + if (!IP_VALID(ip, command_giver)) + return; + if (!ret) { + ip->iflags &= ~HAS_PROCESS_INPUT; + parse_command(user_command, command_giver); + return; + } + +#ifndef NO_ADD_ACTION + if (ret->type == T_STRING) { + static char buf[MAX_TEXT]; + + strncpy(buf, ret->u.string, MAX_TEXT - 1); + parse_command(buf, command_giver); + } else { + if (ret->type != T_NUMBER || !ret->u.number) + parse_command(user_command, command_giver); + } +#endif +} + +/* + * This is the user command handler. This function is called when + * a user command needs to be processed. + * This function calls get_user_command() to get a user command. + * One user command is processed per execution of this function. + */ +int process_user_command() +{ + char *user_command; + interactive_t *ip=NULL;//for if(ip) below + + /* + * WARNING: get_user_command() sets command_giver via + * save_command_giver(), but only when the return is non-zero! + */ + if (!(user_command = get_user_command())) + return 0; + + if(command_giver) ip = command_giver->interactive; + current_interactive = command_giver; /* this is yuck phooey, sigh */ + if(ip) clear_notify(ip->ob); + update_load_av(); + debug(connections, ("process_user_command: command_giver = /%s\n", command_giver->obname)); + + if(!ip) + goto exit; + + user_command = translate_easy(ip->trans->incoming, user_command); + + if(ip->iflags & USING_MXP && user_command[0] == ' ' && user_command[1] == '[' && user_command[3] == 'z' ){ + svalue_t *ret; + copy_and_push_string(user_command); + + ret=apply(APPLY_MXP_TAG, ip->ob, 1, ORIGIN_DRIVER); + if(ret && ret->type==T_NUMBER && ret->u.number){ + goto exit; + } + } + + if (escape_command(ip, user_command)) { + if (ip->iflags & SINGLE_CHAR) { + /* only 1 char ... switch to line buffer mode */ + ip->iflags |= WAS_SINGLE_CHAR; + ip->iflags &= ~SINGLE_CHAR; +#ifdef GET_CHAR_IS_BUFFERED + ip->text_start = ip->text_end = *ip->text = 0; +#endif + set_linemode(ip); + } else { + if (ip->iflags & WAS_SINGLE_CHAR) { + /* we now have a string ... switch back to char mode */ + ip->iflags &= ~WAS_SINGLE_CHAR; + ip->iflags |= SINGLE_CHAR; + set_charmode(ip); + if (!IP_VALID(ip, command_giver)) { + goto exit; + } + } + + process_input(ip, user_command + 1); + } + + goto exit; + } + +#ifdef OLD_ED + if (ip->ed_buffer) { + ed_cmd(user_command); + goto exit; + } +#endif + +#if defined(F_INPUT_TO) || defined(F_GET_CHAR) + if (call_function_interactive(ip, user_command)) { + goto exit; + } +#endif + + process_input(ip, user_command); + +exit: + /* + * Print a prompt if user is still here. + */ + if (IP_VALID(ip, command_giver)) + print_prompt(ip); + + current_interactive = 0; + restore_command_giver(); + return 1; +} + +#define HNAME_BUF_SIZE 200 +/* + * This is the hname input data handler. This function is called by the + * master handler when data is pending on the hname socket (addr_server_fd). + */ + +static void hname_handler() +{ + static char hname_buf[HNAME_BUF_SIZE]; + static int hname_buf_pos; + int num_bytes; + + num_bytes = HNAME_BUF_SIZE - hname_buf_pos - 1; /* room for nul */ + num_bytes = OS_socket_read(addr_server_fd, hname_buf + hname_buf_pos, num_bytes); + if (num_bytes <= 0) { + if (num_bytes == -1) { +#ifdef EWOULDBLOCK + if (socket_errno == EWOULDBLOCK) { + debug(connections, ("hname_handler: read on fd %d: Operation would block.\n", + addr_server_fd)); + return; + } +#endif + debug_message("hname_handler: read on fd %d\n", addr_server_fd); + socket_perror("hname_handler: read", 0); + } else { + debug_message("hname_handler: closing address server connection.\n"); + } + OS_socket_close(addr_server_fd); + addr_server_fd = -1; + return; + } + + hname_buf_pos += num_bytes; + hname_buf[hname_buf_pos] = 0; + debug(connections, ("hname_handler: address server replies: %s", hname_buf)); + + while (hname_buf_pos) { + char *nl, *pp; + + /* if there's no newline, there's more data to come */ + if (!(nl = strchr(hname_buf, '\n'))) + break; + *nl++ = 0; + + if ((pp = strchr(hname_buf, ' ')) != 0) { + *pp++ = 0; + got_addr_number(pp, hname_buf); + + if (isdigit(hname_buf[0]) || hname_buf[0] == ':') { + +#ifdef IPV6 + struct in6_addr addr; + int ret; + if(1 ==(ret = inet_pton(AF_INET6, hname_buf, &addr))) { + if (strcmp(pp, "0") != 0) + add_ip_entry(addr, pp); + } +#else + unsigned long laddr; + + if ((laddr = inet_addr(hname_buf)) != INADDR_NONE) { + if (strcmp(pp, "0") != 0) + add_ip_entry(laddr, pp); + } +#endif + } + } + + hname_buf_pos -= (nl - hname_buf); + if (hname_buf_pos) + memmove(hname_buf, nl, hname_buf_pos + 1); /* be sure to get the nul */ + } +} + +/* + * Remove an interactive user immediately. + */ +void remove_interactive (object_t * ob, int dested) +{ + int idx; + /* don't have to worry about this dangling, since this is the routine + * that causes this to dangle elsewhere, and we are protected from + * getting called recursively by CLOSING. safe_apply() should be + * used here, since once we start this process we can't back out, + * so jumping out with an error would be bad. + */ + interactive_t *ip = ob->interactive; + + if (!ip) return; + + if (ip->iflags & CLOSING) { + if (!dested) + debug_message("Double call to remove_interactive()\n"); + return; + } + + debug(connections, ("Closing connection from %s.\n", + inet_ntoa(ip->addr.sin_addr))); + + flush_message(ip); + ip->iflags |= CLOSING; + +#ifdef OLD_ED + if (ip->ed_buffer) { + save_ed_buffer(ob); + } +#else + if (ob->flags & O_IN_EDIT) { + object_save_ed_buffer(ob); + ob->flags &= ~O_IN_EDIT; + } +#endif + + if (!dested) { + /* + * auto-notification of net death + */ + save_command_giver(ob); + safe_apply(APPLY_NET_DEAD, ob, 0, ORIGIN_DRIVER); + restore_command_giver(); + } + +#ifndef NO_SNOOP + if (ip->snooped_by) { + ip->snooped_by->flags &= ~O_SNOOP; + ip->snooped_by = 0; + } +#endif + +#ifdef HAVE_ZLIB + if (ip->compressed_stream) { + end_compression(ip); + } +#endif + + debug(connections, ("remove_interactive: closing fd %d\n", ip->fd)); + if (OS_socket_close(ip->fd) == -1) { + socket_perror("remove_interactive: close", 0); + } +#ifdef F_SET_HIDE + if (ob->flags & O_HIDDEN) + num_hidden_users--; +#endif + num_user--; + clear_notify(ip->ob); +#if defined(F_INPUT_TO) || defined(F_GET_CHAR) + if (ip->input_to) { + free_object(&ip->input_to->ob, "remove_interactive"); + free_sentence(ip->input_to); + if (ip->num_carry > 0) + free_some_svalues(ip->carryover, ip->num_carry); + ip->carryover = NULL; + ip->num_carry = 0; + ip->input_to = 0; + } +#endif + for (idx = 0; idx < max_users; idx++) + if (all_users[idx] == ip) break; + DEBUG_CHECK(idx == max_users, "remove_interactive: could not find and remove user!\n"); + FREE(ip->sb_buf); + FREE(ip); + ob->interactive = 0; + all_users[idx] = 0; + free_object(&ob, "remove_interactive"); + return; +} /* remove_interactive() */ + +#if defined(F_INPUT_TO) || defined(F_GET_CHAR) +static int call_function_interactive (interactive_t * i, char * str) +{ + object_t *ob; + funptr_t *funp; + char *function; + svalue_t *args; + sentence_t *sent; + int num_arg; +#ifdef GET_CHAR_IS_BUFFERED + int was_single = 0; + int was_noecho = 0; +#endif + + i->iflags &= ~NOESC; + if (!(sent = i->input_to)) + return (0); + + /* + * Special feature: input_to() has been called to setup a call to a + * function. + */ + if (sent->ob->flags & O_DESTRUCTED) { + /* Sorry, the object has selfdestructed ! */ + free_object(&sent->ob, "call_function_interactive"); + free_sentence(sent); + i->input_to = 0; + if (i->num_carry) + free_some_svalues(i->carryover, i->num_carry); + i->carryover = NULL; + i->num_carry = 0; + i->input_to = 0; + if (i->iflags & SINGLE_CHAR) { + /* + * clear single character mode + */ + i->iflags &= ~SINGLE_CHAR; +#ifndef GET_CHAR_IS_BUFFERED + set_linemode(i); +#else + was_single = 1; + if (i->iflags & NOECHO) { + was_noecho = 1; + i->iflags &= ~NOECHO; + } +#endif + } + + return (0); + } + /* + * We must all references to input_to fields before the call to apply(), + * because someone might want to set up a new input_to(). + */ + + /* we put the function on the stack in case of an error */ + STACK_INC; + if (sent->flags & V_FUNCTION) { + function = 0; + sp->type = T_FUNCTION; + sp->u.fp = funp = sent->function.f; + funp->hdr.ref++; + } else { + sp->type = T_STRING; + sp->subtype = STRING_SHARED; + sp->u.string = function = sent->function.s; + ref_string(function); + } + ob = sent->ob; + + free_object(&sent->ob, "call_function_interactive"); + free_sentence(sent); + + /* + * If we have args, we have to copy them, so the svalues on the + * interactive struct can be FREEd + */ + num_arg = i->num_carry; + if (num_arg) { + args = i->carryover; + i->num_carry = 0; + i->carryover = NULL; + } else + args = NULL; + + i->input_to = 0; + if (i->iflags & SINGLE_CHAR) { + /* + * clear single character mode + */ + i->iflags &= ~SINGLE_CHAR; +#ifndef GET_CHAR_IS_BUFFERED + set_linemode(i); +#else + was_single = 1; + if (i->iflags & NOECHO) { + was_noecho = 1; + i->iflags &= ~NOECHO; + } +#endif + } + + copy_and_push_string(str); + /* + * If we have args, we have to push them onto the stack in the order they + * were in when we got them. They will be popped off by the called + * function. + */ + if (args) { + transfer_push_some_svalues(args, num_arg); + FREE(args); + } + /* current_object no longer set */ + if (function) { + if (function[0] == APPLY___INIT_SPECIAL_CHAR) + error("Illegal function name.\n"); + (void) apply(function, ob, num_arg + 1, ORIGIN_INTERNAL); + } else + call_function_pointer(funp, num_arg + 1); + + pop_stack(); /* remove `function' from stack */ + +#ifdef GET_CHAR_IS_BUFFERED + if (IP_VALID(i, ob)) { + if (was_single && !(i->iflags & SINGLE_CHAR)) { + i->text_start = i->text_end = 0; + i->text[0] = '\0'; + i->iflags &= ~CMD_IN_BUF; + set_linemode(i); + } + if (was_noecho && !(i->iflags & NOECHO)) + add_binary_message(i->ob, telnet_no_echo, sizeof(telnet_no_echo)); + } +#endif + + return (1); +} /* call_function_interactive() */ + +int set_call (object_t * ob, sentence_t * sent, int flags) +{ + if (ob == 0 || sent == 0) + return (0); + if (ob->interactive == 0 || ob->interactive->input_to) + return (0); + ob->interactive->input_to = sent; + ob->interactive->iflags |= (flags & (I_NOECHO | I_NOESC | I_SINGLE_CHAR)); + if (flags & I_NOECHO) + add_binary_message(ob, telnet_yes_echo, sizeof(telnet_yes_echo)); + if (flags & I_SINGLE_CHAR) + set_charmode(ob->interactive); + return (1); +} /* set_call() */ +#endif + +void set_prompt (const char * str) +{ + if (command_giver && command_giver->interactive) { + command_giver->interactive->prompt = str; + } +} /* set_prompt() */ + +/* + * Print the prompt, but only if input_to not is disabled. + */ +static void print_prompt (interactive_t* ip) +{ + object_t *ob = ip->ob; + +#if defined(F_INPUT_TO) || defined(F_GET_CHAR) + if (ip->input_to == 0) { +#endif + /* give user object a chance to write its own prompt */ + if (!(ip->iflags & HAS_WRITE_PROMPT)) + tell_object(ip->ob, ip->prompt, strlen(ip->prompt)); +#ifdef OLD_ED + else if (ip->ed_buffer) + tell_object(ip->ob, ip->prompt, strlen(ip->prompt)); +#endif + else if (!apply(APPLY_WRITE_PROMPT, ip->ob, 0, ORIGIN_DRIVER)) { + if (!IP_VALID(ip, ob)) return; + ip->iflags &= ~HAS_WRITE_PROMPT; + tell_object(ip->ob, ip->prompt, strlen(ip->prompt)); + } +#if defined(F_INPUT_TO) || defined(F_GET_CHAR) + } +#endif + if (!IP_VALID(ip, ob)) return; + /* + * Put the IAC GA thing in here... Moved from before writing the prompt; + * vt src says it's a terminator. Should it be inside the no-input_to + * case? We'll see, I guess. + */ + if ((ip->iflags & USING_TELNET) && !(ip->iflags & SUPPRESS_GA)) + add_binary_message(command_giver, telnet_ga, sizeof(telnet_ga)); + if (!IP_VALID(ip, ob)) return; +} /* print_prompt() */ + +/* + * Let object 'me' snoop object 'you'. If 'you' is 0, then turn off + * snooping. + * + * This routine is almost identical to the old set_snoop. The main + * difference is that the routine writes nothing to user directly, + * all such communication is taken care of by the mudlib. It communicates + * with master.c in order to find out if the operation is permissble or + * not. The old routine let everyone snoop anyone. This routine also returns + * 0 or 1 depending on success. + */ +#ifndef NO_SNOOP +int new_set_snoop (object_t * by, object_t * victim) +{ + interactive_t *ip; + object_t *tmp; + + if (by->flags & O_DESTRUCTED) + return 0; + if (victim && (victim->flags & O_DESTRUCTED)) + return 0; + + if (victim) { + if (!victim->interactive) + error("Second argument of snoop() is not interactive!\n"); + ip = victim->interactive; + } else { + /* + * Stop snoop. + */ + if (by->flags & O_SNOOP) { + int i; + + for (i = 0; i < max_users; i++) { + if (all_users[i] && all_users[i]->snooped_by == by) + all_users[i]->snooped_by = 0; + } + by->flags &= ~O_SNOOP; + } + return 1; + } + + /* + * Protect against snooping loops. + */ + tmp = by; + while (tmp) { + if (tmp == victim) + return 0; + + /* the person snooping us, if any */ + tmp = (tmp->interactive ? tmp->interactive->snooped_by : 0); + } + + /* + * Terminate previous snoop, if any. + */ + if (by->flags & O_SNOOP) { + int i; + + for (i = 0; i < max_users; i++) { + if (all_users[i] && all_users[i]->snooped_by == by) + all_users[i]->snooped_by = 0; + } + } + if (ip->snooped_by) + ip->snooped_by->flags &= ~O_SNOOP; + by->flags |= O_SNOOP; + ip->snooped_by = by; + + return 1; +} /* set_new_snoop() */ +#endif + +static void query_addr_name (object_t * ob) +{ + static char buf[100]; + static char *dbuf = &buf[sizeof(int) + sizeof(int) + sizeof(int)]; + int msglen; + int msgtype; + + sprintf(dbuf, "%s", query_ip_number(ob)); + msglen = sizeof(int) + strlen(dbuf) +1; + + msgtype = DATALEN; + memcpy(buf, (char *) &msgtype, sizeof(msgtype)); + memcpy(&buf[sizeof(int)], (char *) &msglen, sizeof(msglen)); + + msgtype = NAMEBYIP; + memcpy(&buf[sizeof(int) + sizeof(int)], (char *) &msgtype, sizeof(msgtype)); + debug(connections, ("query_addr_name: sent address server %s\n", dbuf)); + + if (OS_socket_write(addr_server_fd, buf, msglen + sizeof(int) + sizeof(int)) == -1) { + switch (socket_errno) { + case EBADF: + debug_message("Address server has closed connection.\n"); + addr_server_fd = -1; + break; + default: + socket_perror("query_addr_name: write", 0); + break; + } + } +} /* query_addr_name() */ + +#define IPSIZE 200 +typedef struct { + char *name; + svalue_t call_back; + object_t *ob_to_call; +} ipnumberentry_t; + +static ipnumberentry_t ipnumbertable[IPSIZE]; + +/* + * Does a call back on the current_object with the function call_back. + */ +int query_addr_number (const char * name, svalue_t * call_back) +{ + static char buf[100]; + static char *dbuf = &buf[sizeof(int) + sizeof(int) + sizeof(int)]; + int msglen; + int msgtype; + int i; + + if ((addr_server_fd < 0) || (strlen(name) >= + 100 - (sizeof(msgtype) + sizeof(msglen) + sizeof(int)))) { + share_and_push_string(name); + push_undefined(); + if (call_back->type == T_STRING) + apply(call_back->u.string, current_object, 2, ORIGIN_INTERNAL); + else + call_function_pointer(call_back->u.fp, 2); + return 0; + } + strcpy(dbuf, name); + msglen = sizeof(int) + strlen(name) +1; + + msgtype = DATALEN; + memcpy(buf, (char *) &msgtype, sizeof(msgtype)); + memcpy(&buf[sizeof(int)], (char *) &msglen, sizeof(msglen)); + + msgtype = NAMEBYIP; + for (i = 0; i < strlen(name); i++){ + if (isalpha(name[i])) { + msgtype = IPBYNAME; + break; + } + } + + memcpy(&buf[sizeof(int) + sizeof(int)], (char *) &msgtype, sizeof(msgtype)); + + debug(connections, ("query_addr_number: sent address server %s\n", dbuf)); + + if (addr_server_fd && OS_socket_write(addr_server_fd, buf, msglen + sizeof(int) + sizeof(int)) == -1) { + switch (socket_errno) { + case EBADF: + debug_message("Address server has closed connection.\n"); + addr_server_fd = -1; + break; + default: + socket_perror("query_addr_name: write", 0); + break; + } + share_and_push_string(name); + push_undefined(); + if (call_back->type == T_STRING) + apply(call_back->u.string, current_object, 2, ORIGIN_INTERNAL); + else + call_function_pointer(call_back->u.fp, 2); + return 0; + } else { + int i; + +/* We put ourselves into the pending name lookup entry table */ +/* Find the first free entry */ + for (i = 0; i < IPSIZE && ipnumbertable[i].name; i++) + ; + if (i == IPSIZE) { +/* We need to error... */ + share_and_push_string(name); + push_undefined(); + if (call_back->type == T_STRING) + apply(call_back->u.string, current_object, 2, ORIGIN_INTERNAL); + else + call_function_pointer(call_back->u.fp, 2); + return 0; + } +/* Create our entry... */ + ipnumbertable[i].name = make_shared_string(name); + assign_svalue_no_free(&ipnumbertable[i].call_back, call_back); + ipnumbertable[i].ob_to_call = current_object; + add_ref(current_object, "query_addr_number: "); + return i + 1; + } +} /* query_addr_number() */ + +static void got_addr_number (char * number, char * name) +{ + int i; + char *theName, *theNumber; + + /* First remove all the dested ones... */ + for (i = 0; i < IPSIZE; i++) + if (ipnumbertable[i].name + && ipnumbertable[i].ob_to_call->flags & O_DESTRUCTED) { + free_svalue(&ipnumbertable[i].call_back, "got_addr_number"); + free_string(ipnumbertable[i].name); + free_object(&ipnumbertable[i].ob_to_call, "got_addr_number: "); + ipnumbertable[i].name = NULL; + } + for (i = 0; i < IPSIZE; i++) { + if (ipnumbertable[i].name && strcmp(name, ipnumbertable[i].name)== 0) { + /* Found one, do the call back... */ + theName = ipnumbertable[i].name; + theNumber = number; + + if (uisdigit(theName[0])) { + char *tmp; + + tmp = theName; + theName = theNumber; + theNumber = tmp; + } + if (strcmp(theName, "0")) { + share_and_push_string(theName); + } else { + push_undefined(); + } + if (strcmp(theNumber, "0")) { + share_and_push_string(theNumber); + } else { + push_undefined(); + } + push_number(i + 1); + if (ipnumbertable[i].call_back.type == T_STRING) + safe_apply(ipnumbertable[i].call_back.u.string, + ipnumbertable[i].ob_to_call, + 3, ORIGIN_INTERNAL); + else + safe_call_function_pointer(ipnumbertable[i].call_back.u.fp, 3); + free_svalue(&ipnumbertable[i].call_back, "got_addr_number"); + free_string(ipnumbertable[i].name); + free_object(&ipnumbertable[i].ob_to_call, "got_addr_number: "); + ipnumbertable[i].name = NULL; + } + } +} /* got_addr_number() */ + +#undef IPSIZE +#define IPSIZE 200 +typedef struct { +#ifdef IPV6 + struct in6_addr addr; +#else + long addr; +#endif + char *name; +} ipentry_t; + +static ipentry_t iptable[IPSIZE]; +static int ipcur; + +#ifdef DEBUGMALLOC_EXTENSIONS +void mark_iptable() { + int i; + + for (i=0; i < IPSIZE; i++) + if (iptable[i].name) + EXTRA_REF(BLOCK(iptable[i].name))++; +} +#endif + +#ifdef IPV6 +char ipv6addr[INET6_ADDRSTRLEN]; +#endif + +char *query_ip_name (object_t * ob) +{ + int i; + + if (ob == 0) + ob = command_giver; + if (!ob || ob->interactive == 0) + return NULL; +#ifdef IPV6 + for (i = 0; i < IPSIZE; i++) { + if (!memcmp(&iptable[i].addr, &ob->interactive->addr.sin6_addr, sizeof(ob->interactive->addr.sin6_addr)) && + iptable[i].name) + return (iptable[i].name); + } + + inet_ntop(AF_INET6, &ob->interactive->addr.sin6_addr, ipv6addr, INET6_ADDRSTRLEN); + return ipv6addr; +#else + for (i = 0; i < IPSIZE; i++) { + if (iptable[i].addr == ob->interactive->addr.sin_addr.s_addr && + iptable[i].name) + return (iptable[i].name); + } + return (inet_ntoa(ob->interactive->addr.sin_addr)); +#endif +} + +#ifdef IPV6 +static void add_ip_entry (struct in6_addr addr, char * name) +#else +static void add_ip_entry (long addr, char * name) +#endif +{ + int i; + + for (i = 0; i < IPSIZE; i++) { + if (!memcmp(&iptable[i].addr, &addr, sizeof(addr))) + return; + } + iptable[ipcur].addr = addr; + if (iptable[ipcur].name) + free_string(iptable[ipcur].name); + iptable[ipcur].name = make_shared_string(name); + ipcur = (ipcur + 1) % IPSIZE; +} + +const char *query_ip_number (object_t * ob) +{ + if (ob == 0) + ob = command_giver; + if (!ob || ob->interactive == 0) + return 0; +#ifdef IPV6 + inet_ntop(AF_INET6, &ob->interactive->addr.sin6_addr, ipv6addr, INET6_ADDRSTRLEN); + return &ipv6addr[0]; +#else + return (inet_ntoa(ob->interactive->addr.sin_addr)); +#endif +} + +#ifndef INET_NTOA_OK +/* + * Note: if the address string is "a.b.c.d" the address number is + * a * 256^3 + b * 256^2 + c * 256 + d + */ +char *inet_ntoa (struct in_addr ad) +{ + u_long s_ad; + int a, b, c, d; + static char addr[20]; /* 16 + 1 should be enough */ + + s_ad = ad.s_addr; + d = s_ad % 256; + s_ad /= 256; + c = s_ad % 256; + s_ad /= 256; + b = s_ad % 256; + a = s_ad / 256; + sprintf(addr, "%d.%d.%d.%d", a, b, c, d); + return (addr); +} +#endif /* INET_NTOA_OK */ + +char *query_host_name() +{ + static char name[400]; + + gethostname(name, sizeof(name)); + name[sizeof(name) - 1] = '\0'; /* Just to make sure */ + return (name); +} /* query_host_name() */ + +#ifndef NO_SNOOP +object_t *query_snoop (object_t * ob) +{ + if (!ob->interactive) + return 0; + return ob->interactive->snooped_by; +} /* query_snoop() */ + +object_t *query_snooping (object_t * ob) +{ + int i; + + if (!(ob->flags & O_SNOOP)) return 0; + for (i = 0; i < max_users; i++) { + if (all_users[i] && all_users[i]->snooped_by == ob) + return all_users[i]->ob; + } + fatal("couldn't find snoop target.\n"); + return 0; +} /* query_snooping() */ +#endif + +int query_idle (object_t * ob) +{ + if (!ob->interactive) + error("query_idle() of non-interactive object.\n"); + return (current_time - ob->interactive->last_time); +} /* query_idle() */ + +#ifdef F_EXEC +int replace_interactive (object_t * ob, object_t * obfrom) +{ + if (ob->interactive) { + error("Bad argument 1 to exec()\n"); + } + if (!obfrom->interactive) { + error("Bad argument 2 to exec()\n"); + } +#ifdef F_SET_HIDE + if ((ob->flags & O_HIDDEN) != (obfrom->flags & O_HIDDEN)) { + if (ob->flags & O_HIDDEN) { + num_hidden_users++; + } else { + num_hidden_users--; + } + } +#endif + ob->interactive = obfrom->interactive; + /* + * assume the existance of write_prompt and process_input in user.c until + * proven wrong (after trying to call them). + */ + ob->interactive->iflags |= (HAS_WRITE_PROMPT | HAS_PROCESS_INPUT); + obfrom->interactive = 0; + ob->interactive->ob = ob; + ob->flags |= O_ONCE_INTERACTIVE; + obfrom->flags &= ~O_ONCE_INTERACTIVE; + add_ref(ob, "exec"); + if (obfrom == command_giver) { + set_command_giver(ob); + } + + free_object(&obfrom, "exec"); + return (1); +} /* replace_interactive() */ +#endif + +void outbuf_zero (outbuffer_t * outbuf) { + outbuf->real_size = 0; + outbuf->buffer = 0; +} + +int outbuf_extend (outbuffer_t * outbuf, int l) +{ + int limit; + + DEBUG_CHECK(l < 0, "Negative length passed to outbuf_extend.\n"); + + l = (l > MAX_STRING_LENGTH ? MAX_STRING_LENGTH : l); + + if (outbuf->buffer) { + limit = MSTR_SIZE(outbuf->buffer); + if (outbuf->real_size + l > limit) { + if (outbuf->real_size == MAX_STRING_LENGTH) return 0; /* TRUNCATED */ + + /* assume it's going to grow some more */ + limit = (outbuf->real_size + l) * 2; + if (limit > MAX_STRING_LENGTH) { + limit = MAX_STRING_LENGTH; + outbuf->buffer = extend_string(outbuf->buffer, limit); + return limit - outbuf->real_size; + } + outbuf->buffer = extend_string(outbuf->buffer, limit); + } + } else { + outbuf->buffer = new_string(l, "outbuf_extend"); + outbuf->real_size = 0; + } + return l; +} + +void outbuf_add (outbuffer_t * outbuf, const char * str) +{ + int l, limit; + + if (!outbuf) return; + l = strlen(str); + if ((limit = outbuf_extend(outbuf, l)) > 0) { + strncpy(outbuf->buffer + outbuf->real_size, str, limit); + outbuf->real_size += (l > limit ? limit : l); + *(outbuf->buffer + outbuf->real_size) = 0; + } +} + +void outbuf_addchar (outbuffer_t * outbuf, char c) +{ + if(outbuf && (outbuf_extend(outbuf, 1) > 0)) { + *(outbuf->buffer + outbuf->real_size++) = c; + *(outbuf->buffer + outbuf->real_size) = 0; + } +} + +void outbuf_addv (outbuffer_t *outbuf, const char *format, ...) +{ + char buf[LARGEST_PRINTABLE_STRING + 1]; + va_list args; + + V_START(args, format); + V_VAR(outbuffer_t *, outbuf, args); + V_VAR(char *, format, args); + + vsnprintf(buf, LARGEST_PRINTABLE_STRING, format, args); + va_end(args); + + if (!outbuf) return; + + outbuf_add(outbuf, buf); +} + +void outbuf_fix (outbuffer_t * outbuf) { + if (outbuf && outbuf->buffer) + outbuf->buffer = extend_string(outbuf->buffer, outbuf->real_size); +} + +void outbuf_push (outbuffer_t * outbuf) { + STACK_INC; + sp->type = T_STRING; + if (outbuf && outbuf->buffer) { + outbuf->buffer = extend_string(outbuf->buffer, outbuf->real_size); + + sp->subtype = STRING_MALLOC; + sp->u.string = outbuf->buffer; + } else { + sp->subtype = STRING_CONSTANT; + sp->u.string = ""; + } +} + +#ifdef HAVE_ZLIB +void* zlib_alloc(void* opaque, unsigned int items, unsigned int size) { + return CALLOC(items, size); +} + +void zlib_free(void* opaque, void* address) { + FREE(address); +} + +static void end_compression (interactive_t *ip) { + unsigned char dummy[1]; + + if (!ip->compressed_stream) { + return ; + } + + ip->compressed_stream->avail_in = 0; + ip->compressed_stream->next_in = dummy; + + if (deflate(ip->compressed_stream, Z_FINISH) != Z_STREAM_END) { + } + + deflateEnd(ip->compressed_stream); + FREE(ip->compressed_stream); + ip->compressed_stream = NULL; +} + +static void start_compression (interactive_t *ip) { + z_stream* zcompress; + + if (ip->compressed_stream) { + return ; + } + zcompress = (z_stream *) DXALLOC(sizeof(z_stream), TAG_INTERACTIVE, + "start_compression"); + zcompress->next_in = NULL; + zcompress->avail_in = 0; + zcompress->next_out = ip->compress_buf; + zcompress->avail_out = COMPRESS_BUF_SIZE; + zcompress->zalloc = zlib_alloc; + zcompress->zfree = zlib_free; + zcompress->opaque = NULL; + + if (deflateInit(zcompress, 9) != Z_OK) { + FREE(zcompress); + fprintf(stderr, "Compression failed.\n"); + return ; + } + + // Ok, compressing. + ip->compressed_stream = zcompress; +} + +static int flush_compressed_output (interactive_t *ip) { + int iStart, nBlock, nWrite, len; + z_stream* zcompress; + int ret = 1; + + if (!ip->compressed_stream) { + return ret; + } + + zcompress = ip->compressed_stream; + + /* Try to write out some data.. */ + len = zcompress->next_out - ip->compress_buf; + if (len > 0) { + /* we have some data to write */ + + nWrite = 0; + for (iStart = 0; iStart < len; iStart += nWrite) + { + if (len - iStart < 4096) { + nBlock =len - iStart; + } else { + nBlock = 4096; + } + nWrite = send(ip->fd, &ip->compress_buf[iStart], nBlock, + ip->out_of_band); + if (nWrite < 0) { + fprintf(stderr, "Error sending compressed data (%d)\n", + errno); + + if (errno == EAGAIN +#ifndef WIN32 + || errno == ENOSR +#endif + ) { + ret = 2; + break; + } + + return FALSE; /* write error */ + } + + if (nWrite <= 0) { + break; + } + } + + if (iStart) { + /* We wrote "iStart" bytes */ + if (iStart < len) { + memmove(ip->compress_buf, ip->compress_buf+iStart, len - + iStart); + + } + + zcompress->next_out = ip->compress_buf + len - iStart; + } + } + + return ret; +} + + +static int send_compressed (interactive_t *ip, unsigned char* data, int length) { + z_stream* zcompress; + int wr = 1; + int first = 1; + + zcompress = ip->compressed_stream; + zcompress->next_in = data; + zcompress->avail_in = length; + while (zcompress->avail_in && (wr == 1 || first)) { + if(wr == 2) + first = 0; + zcompress->avail_out = COMPRESS_BUF_SIZE - (zcompress->next_out - + ip->compress_buf); + + if (zcompress->avail_out) { + deflate(zcompress, Z_SYNC_FLUSH); + } + + if(!( wr = flush_compressed_output(ip))) + return 0; + } + return length; +} +#endif + +#ifdef F_ACT_MXP +void f_act_mxp(){ + add_binary_message(current_object, telnet_will_mxp, sizeof(telnet_will_mxp)); +} +#endif + +#ifdef F_SEND_ZMP +void f_send_zmp(){ + add_binary_message(current_object, telnet_start_zmp, sizeof(telnet_start_zmp)); + add_binary_message(current_object, (const unsigned char *)(sp-1)->u.string, strlen((sp-1)->u.string)); + int i; + unsigned char zero = 0; + for(i=0; iu.arr->size; i++){ + if(sp->u.arr->item[i].type == T_STRING){ + add_binary_message(current_object, &zero, 1); + add_binary_message(current_object, (const unsigned char *)sp->u.arr->item[i].u.string, strlen(sp->u.arr->item[i].u.string)); + } + } + add_binary_message(current_object, &zero, 1); + add_binary_message(current_object, telnet_end_sub, sizeof(telnet_end_sub)); + pop_2_elems(); +} +#endif + +#ifdef F_SEND_GMCP +void f_send_gmcp(){ + add_binary_message(current_object, telnet_start_gmcp, sizeof(telnet_start_gmcp)); + add_binary_message(current_object, (const unsigned char *)(sp->u.string), strlen(sp->u.string)); + add_binary_message(current_object, telnet_end_sub, sizeof(telnet_end_sub)); +} +#endif + +#ifdef F_REQUEST_TERM_TYPE +void f_request_term_type(){ + add_binary_message(command_giver, telnet_term_query, sizeof(telnet_term_query)); +} +#endif + +#ifdef F_START_REQUEST_TERM_TYPE +void f_start_request_term_type(){ + add_binary_message(command_giver, telnet_do_ttype, sizeof(telnet_do_ttype)); +} +#endif + +#ifdef F_REQUEST_TERM_SIZE +void f_request_term_size(){ + if((st_num_arg == 1) && (sp->u.number == 0)) + add_binary_message(command_giver, telnet_dont_naws, + sizeof(telnet_dont_naws)); + else + add_binary_message(command_giver, telnet_do_naws, sizeof(telnet_do_naws)); + + if(st_num_arg == 1) + sp--; +} +#endif diff --git a/fluffos-2.23-ds03/comm.h b/fluffos-2.23-ds03/comm.h new file mode 100644 index 0000000..ba54a32 --- /dev/null +++ b/fluffos-2.23-ds03/comm.h @@ -0,0 +1,226 @@ +/* + * comm.h -- definitions and prototypes for comm.c + * + */ + +#ifndef COMM_H +#define COMM_H + +#ifdef HAVE_ZLIB +#include +#endif + +#include "lpc_incl.h" +#include "network_incl.h" + +#include "fliconv.h" + +#define MAX_TEXT 2048 +#define MAX_SOCKET_PACKET_SIZE 1024 +#define DESIRED_SOCKET_PACKET_SIZE 800 +#define MESSAGE_BUF_SIZE MESSAGE_BUFFER_SIZE /* from options.h */ +#define OUT_BUF_SIZE 2048 +#define DFAULT_PROTO 0 /* use the appropriate protocol */ +#define I_NOECHO 0x1 /* input_to flag */ +#define I_NOESC 0x2 /* input_to flag */ +#define I_SINGLE_CHAR 0x4 /* get_char */ +#define I_WAS_SINGLE_CHAR 0x8 /* was get_char */ +#define SB_SIZE (NSLC * 3 + 3) + +#ifdef MINGW +#define SIGPIPE 13 +#endif + +#ifdef HAVE_ZLIB +#define COMPRESS_BUF_SIZE MESSAGE_BUF_SIZE +#endif + +enum msgtypes { + NAMEBYIP = 0, IPBYNAME, DATALEN +}; + +#define TS_DATA 0 +#define TS_IAC 1 +#define TS_WILL 2 +#define TS_WONT 3 +#define TS_DO 4 +#define TS_DONT 5 +#define TS_SB 6 +#define TS_SB_IAC 7 + +/* The I_* flags are input_to flags */ +#define NOECHO I_NOECHO /* don't echo lines */ +#define NOESC I_NOESC /* don't allow shell out */ +#define SINGLE_CHAR I_SINGLE_CHAR /* get_char */ +#define WAS_SINGLE_CHAR I_WAS_SINGLE_CHAR +#define HAS_PROCESS_INPUT 0x0010 /* interactive object has process_input() */ +#define HAS_WRITE_PROMPT 0x0020 /* interactive object has write_prompt() */ +#define CLOSING 0x0040 /* true when closing this file descriptor */ +#define CMD_IN_BUF 0x0080 /* there is a full command in input buffer */ +#define NET_DEAD 0x0100 +#define NOTIFY_FAIL_FUNC 0x0200 /* default_err_mesg is a function pointer */ +#define USING_TELNET 0x0400 /* they're using telnet, or something that */ + /* understands telnet codes */ +#define SKIP_COMMAND 0x0800 /* skip current command */ +#define SUPPRESS_GA 0x1000 /* suppress go ahead */ +#define USING_LINEMODE 0x2000 /* we've negotiated linemode */ +#define USING_MXP 0x4000 /* we've negotiated mxp */ +#define USING_ZMP 0x8000 /* we've negotiated zmp */ +#define USING_GMCP 0x10000 /* we've negotiated gmcp */ + +typedef struct interactive_s { + object_t *ob; /* points to the associated object */ +#if defined(F_INPUT_TO) || defined(F_GET_CHAR) + sentence_t *input_to; /* to be called with next input line */ + svalue_t *carryover; /* points to args for input_to */ + int num_carry; /* number of args for input_to */ +#endif + int connection_type; /* the type of connection this is */ + int fd; /* file descriptor for interactive object */ +#ifdef IPV6 + struct sockaddr_in6 addr; /* socket address of interactive object */ +#else + struct sockaddr_in addr; /* socket address of interactive object */ +#endif +#ifdef F_QUERY_IP_PORT + int local_port; /* which of our ports they connected to */ +#endif +#ifdef F_NETWORK_STATS + int external_port; /* external port index for connection */ +#endif + const char *prompt; /* prompt string for interactive object */ + char text[MAX_TEXT]; /* input buffer for interactive object */ + int text_end; /* first free char in buffer */ + int text_start; /* where we are up to in user command buffer */ + int last_time; /* time of last command executed */ +#ifndef NO_SNOOP + object_t *snooped_by; +#endif +#ifndef NO_ADD_ACTION + /* this or What ? is printed when error */ + union string_or_func default_err_message; +#endif +#ifdef TRACE + int trace_level; /* debug flags -- 0 means no debugging */ + char *trace_prefix; /* trace only object which has this as name */ +#endif +#ifdef OLD_ED + struct ed_buffer_s *ed_buffer; /* local ed */ +#endif +#ifdef HAVE_ZLIB + struct z_stream_s* compressed_stream; /* Is the data stream + compressed or not */ + unsigned char compress_buf[COMPRESS_BUF_SIZE]; /* compress message buffer*/ +#endif + + int message_producer; /* message buffer producer index */ + int message_consumer; /* message buffer consumer index */ + int message_length; /* message buffer length */ + char message_buf[MESSAGE_BUF_SIZE]; /* message buffer */ + int iflags; /* interactive flags */ + char out_of_band; /* Send a telnet sync operation */ + int state; /* Current telnet state. Bingly wop */ + int sb_pos; /* Telnet suboption negotiation stuff */ + struct translation *trans; + char *sb_buf; + int sb_size; + char slc[NSLC][2]; +} interactive_t; + + /* + * This macro is for testing whether ip is still valid, since many + * functions call LPC code, which could otherwise use + * enable_commands(), set_this_player(), or destruct() to cause + * all hell to break loose by changing or dangling command_giver + * or command_giver->interactive. It also saves us a few dereferences + * since we know we can trust ip, and also increases code readability. + * + * Basically, this should be used as follows: + * + * (1) when using command_giver: + * set a variable named ip to command_giver->interactive at a point + * when you know it is valid. Then, after a call that might have + * called LPC code, check IP_VALID(command_giver), or use + * VALIDATE_IP. + * (2) some other object: + * set a variable named ip to ob->interactive, and save ob somewhere; + * or if you are just dealing with an ip as input, save ip->ob somewhere. + * After calling LPC code, check IP_VALID(ob), or use VALIDATE_IP. + * + * Yes, I know VALIDATE_IP uses a goto. It's due to C's lack of proper + * exception handling. Only use it in subroutines that are set up + * for it (i.e. define a failure label, and are set up to deal with + * branching to it from arbitrary points). + */ +#define IP_VALID(ip, ob) (ob && ip && ob->interactive == ip) +#define VALIDATE_IP(ip, ob) if (!IP_VALID(ip, ob)) goto failure + +/* + * comm.c + */ +extern fd_set readmask; +extern fd_set writemask; +extern int inet_packets; +extern int inet_volume; +#ifdef F_NETWORK_STATS +extern int inet_out_packets; +extern int inet_out_volume; +extern int inet_in_packets; +extern int inet_in_volume; +#ifdef PACKAGE_SOCKETS +extern int inet_socket_in_packets; +extern int inet_socket_in_volume; +extern int inet_socket_out_packets; +extern int inet_socket_out_volume; +#endif +#endif +extern int num_user; +#ifdef F_SET_HIDE +extern int num_hidden_users; +#endif +extern int add_message_calls; + +extern interactive_t **all_users; +extern int max_users; +#ifdef HAS_CONSOLE +extern int has_console; +extern void restore_sigttin(void); +#endif + +void CDECL add_vmessage (object_t *, const char *, ...); +void add_message (object_t *, const char *, int); +void add_binary_message (object_t *, const unsigned char *, int); + +#ifdef SIGNAL_FUNC_TAKES_INT +void sigalrm_handler (int); +#else +void sigalrm_handler (void); +#endif +void update_ref_counts_for_users (void); +INLINE void make_selectmasks (void); +void init_user_conn (void); +void init_addr_server (char *, int); +void ipc_remove (void); +void set_prompt (const char *); +INLINE void process_io (void); +int process_user_command (void); +int replace_interactive (object_t *, object_t *); +int set_call (object_t *, sentence_t *, int); +void remove_interactive (object_t *, int); +int flush_message (interactive_t *); +int query_addr_number (const char *, svalue_t *); +char *query_ip_name (object_t *); +const char *query_ip_number (object_t *); +char *query_host_name (void); +int query_idle (object_t *); +#ifndef NO_SNOOP +int new_set_snoop (object_t *, object_t *); +object_t *query_snoop (object_t *); +object_t *query_snooping (object_t *); +#endif + +#ifdef DEBUGMALLOC_EXTENSIONS +void mark_iptable (void); +#endif + +#endif /* COMM_H */ diff --git a/fluffos-2.23-ds03/compat/fixstatic b/fluffos-2.23-ds03/compat/fixstatic new file mode 100644 index 0000000..eab4ae1 --- /dev/null +++ b/fluffos-2.23-ds03/compat/fixstatic @@ -0,0 +1,50 @@ +#!/usr/local/bin/perl -pi + +# Beek - 970910 +# Perl, as a language, is far from my favorite. However, this task is +# a good example of the kind of thing it is great at. It would be hard +# to express this anywhere nearly as concisely in any other language. + +# Note: This script isn't guaranteed to get things 100% correct, but it +# does do a pretty good job of guessing what is meant, and the remaining +# cases shouldn't be hard to fix by hand. +# +# As an example, it gets every instance of 'static' in the Lima mudlib +# correct (all 513 of them!). +# +# Example usage: +# +# find mudlib -name "*.c" -print | xargs /path/to/this/script + +# Note that there is no checking whether things appear in quotes, which is +# probably the most likely way this can mess up. +# +# if it contains an open (, which is not part of a ({, ([, or (:, then it +# is a function prototype or definition +# +# Note: this is wrong for initializers that contain (. For example +# static object this = this_object(); Perhaps we should handle = +# first ... +if (/\([^{[:]/) { + s/static/protected/; +} +# commas and assignments are pretty clear indictations of variables. Note +# that we don't have to worry about commas in argument lists since we have +# already handled lines with (, which must appear between static and any comma. +elsif (/,/ || /=/) { + s/static/nosave/; +} +# static with a ; on the same line implies the entire line is here. If it +# was a prototype, it had a (. Must be a variable. +elsif (/;/) { + s/static/nosave/; +} +# This handles the common practice of doing things like: +# +# static +# void create() { +# +# which is more common than most other uses of static alone on a line +else { + s/static/protected/; +} diff --git a/fluffos-2.23-ds03/compat/parser_error.c b/fluffos-2.23-ds03/compat/parser_error.c new file mode 100644 index 0000000..635ec9c --- /dev/null +++ b/fluffos-2.23-ds03/compat/parser_error.c @@ -0,0 +1,60 @@ +string parser_error_message(int kind, object ob, mixed arg, int flag) { + string ret; + if (ob) + ret = ob->short() + ": "; + else + ret = ""; + + switch (kind) { + case 1: + if (flag) + return ret + "There is no such " + arg + " here.\n"; + else + return ret + "There is no " + arg + " here.\n"; + break; + case 2: + if (flag) + return ret + "None of the " + pluralize(arg) + " are alive.\n"; + else + return ret + "The " + arg + " isn't alive.\n"; + break; + case 3: + if (flag) + return ret + "You can't reach them.\n"; + else + return ret + "You can't reach it.\n"; + break; + case 4: + { + array descs = unique_array(arg, (: $1->the_short() :)); + string str; + + if (sizeof(descs) == 1) + return ret + "Which " + descs[0][0]->short() + " do you mean?\n"; + str = ret + "Do you mean "; + for (int i = 0; i < sizeof(descs); i++) { + if (sizeof(descs[i]) > 1) + str += "one of "; + str += descs[i][0]->the_short(); + if (i == sizeof(descs) - 1) + str += " or "; + else + str += ", "; + } + return str + "?\n"; + } + break; + case 5: + if (arg > 1) + return ret + "There are only " + arg + " of them.\n"; + else + return ret + "There is only one of them.\n"; + break; + case 6: + return ret + arg; + case 7: + return ret + "There is no " + arg + " here.\n"; + case 8: + return ret + "You can't use more than one object at a time with that verb.\n"; + } +} diff --git a/fluffos-2.23-ds03/compat/simuls/apply.c b/fluffos-2.23-ds03/compat/simuls/apply.c new file mode 100644 index 0000000..97533f3 --- /dev/null +++ b/fluffos-2.23-ds03/compat/simuls/apply.c @@ -0,0 +1,9 @@ +/* Like evaluate(), but expand out an array of arguments. No longer necessary + because of the ... syntax */ + +mixed apply(mixed f, mixed *arr...) { + if (sizeof(arr) && arrayp(arr[<1])) + arr = arr[0..<2] + arr[<1]; + + return evaluate(f, arr...); +} diff --git a/fluffos-2.23-ds03/compat/simuls/break_string.c b/fluffos-2.23-ds03/compat/simuls/break_string.c new file mode 100644 index 0000000..2fb6ec0 --- /dev/null +++ b/fluffos-2.23-ds03/compat/simuls/break_string.c @@ -0,0 +1,21 @@ +void break_string(string str, int width, mixed indent) { + int indlen; + + if (!stringp(str)) return 0; + if (intp(indent)) { + if (ident < 0) indent = 0; + indlen = indent; + indent = sprintf("%-*' 's", indlen, ""); + } else if (stringp(indent)) { + indlen = strlen(ident); + } else return str; + + if (width < indlen + 1) width = indlen + 1; + str = sprintf("%*-=s", width - indlen, str); + if (!indlen) return str; + + if (str[<1] == '\n') + return indent + replace_string(str[0..<2], "\n", "\n" + indent) + "\n"; + else + return indent + replace_string(str, "\n", "\n" + indent); +} diff --git a/fluffos-2.23-ds03/compat/simuls/dump_socket_status.c b/fluffos-2.23-ds03/compat/simuls/dump_socket_status.c new file mode 100644 index 0000000..725b094 --- /dev/null +++ b/fluffos-2.23-ds03/compat/simuls/dump_socket_status.c @@ -0,0 +1,12 @@ +string dump_socket_status() { + string ret = @END +Fd State Mode Local Address Remote Address +-- --------- -------- --------------------- --------------------- +END; + + foreach (array item in socket_status()) { + ret += sprintf("%2d %|9s %|8s %-21s %-21s\n", item[0], item[1], item[2], item[3], item[4]); + } + + return ret; +} diff --git a/fluffos-2.23-ds03/compat/simuls/parse_command.c b/fluffos-2.23-ds03/compat/simuls/parse_command.c new file mode 100644 index 0000000..89d6e7a --- /dev/null +++ b/fluffos-2.23-ds03/compat/simuls/parse_command.c @@ -0,0 +1,699 @@ +private mixed *ret; +private mixed value; + +private void +load_lpc_info(int ix, object ob) +{ + mixed *tmp, *sing; + value ret; + int il, make_plural = 0; + string str; + + if (!ob) + return; + + if (pluid_list && + sizeof(pluid_list) > ix && + pluid_list[ix] == 0) { + ret = ob->parse_command_plural_id_list(); + if (arrayp(ret)) + pluid_list[ix] = ret; + else { + make_plural = 1; + pluid_list[ix] = 1; + } + } + if (id_list && + sizeof(id_list) > ix && + id_list[ix] == 0 && + ob) { + ret = ob->parse_command_id_list(); + if (arrayp(ret)) { + id_list[ix] = ret; + if (make_plural) + pluid_list[ix] = map(ret, (: stringp($1) ? pluralize($1) : 0 :)); + } else { + id_list[ix] = 1; + } + } + if (adjid_list && + sizeof(adjid_list) > ix && + adjid_list[ix] == 0 && + ob) { + ret = ob->parse_command_adjectiv_id_list(); + if (arrayp(ret)) + adjid_list[ix] = ret; + else + adjid_list[ix] = 1; + } +} + +mixed *parse_command(string cmd, mixed obarr, string pattern) { + mixed *saved_ret = ret, *cret; + + ret = ({ }); + + /* pattern and command cannot be empty */ + if (cmd == "" || pattern = "") return ({ }); + + if (!stringp(cmd)) error("Bad argument 1 to parse_command().\n"); + if (!stringp(pattern)) error("Bad argument 3 to parse_command().\n"); + + /* array of words in command */ + parse_warr = explode(cmd, " "); + + /* array of pattern elements */ + parse_patarr = explode(pattern, " "); + +#ifndef __NO_ENVIRONMENT__ + if (objectp(obarr)) + obarr = ({ obarr }) + deep_inventory(obarr); +#endif + if (!arrayp(obarr)) error("Bad argument 2 to parse_command().\n"); + + id_list = allocate(sizeof(obarr)); + pluid_list = allocate(sizeof(obarr)); + adjid_list = allocate(sizeof(obarr)); + + id_list_d = master()->parse_command_id_list(); + pluid_list_d = master()->parse_command_plural_id_list(); + adjid_list_d = master()->parse_command_adjectiv_id_list(); + prepos_list = master()->parse_command_prepos_list(); + + allword = master()->parse_command_all_word(); + + /* + * Loop through the pattern. Handle %s but not '/' + */ + for (six = 0, cix = 0, pix = 0; pix < sizeof(parse_patarr); pix++) { + value = 0; + fail = 0; + + if (parse_patarr[pix] == "%s") { + /* + * We are at end of pattern, scrap up the remaining words and put + * them in the fill-in value. + */ + if (pix == sizeof(parse_patarr - 1)) { + store_words_slice(six++, parse_warr, cix, sizeof(parse_warr) - 1); + cix = sizeof(parse_warr); + } else { + /* + * There is something after %s, try to parse with the next + * pattern. Begin with the current word and step one word for + * each fail, until match or end of words. + */ + ocix = fword = cix; /* current word */ + fpix = ++pix; /* pix == next pattern */ + do { + /* + * Parse the following pattern, fill-in values: + * stack_args[six] = result of %s stack_args[six + 1] = + * result of following pattern, if it is a fill-in + * pattern + */ + fail = sub_parse(obarr, parse_patarr, ref pix, + parse_warr, ref cix); + if (fail) { + cix = ++ocix; + pix = fpix; + } + } while (fail && (cix < sizeof(parse_warr))); + + /* + * We found something mathing the pattern after %s. First + * stack_args[six + 1] = result of match Then stack_args[six] + * = the skipped words before match + */ + if (!fail) { + if (value) { /* A match with a value fill in param */ + store_value(six + 1, value); + store_words_slice(six, parse_warr, fword, ocix - 1); + six += 2; + } else { /* A match with a non value ie 'word' */ + store_words_slice(six++, parse_warr, fword, ocix - 1); + } + value = 0; + } + } + } + /* + * The pattern was not %s, parse the pattern if it is not '/', a '/' + * here is skipped. If match, put in fill-in value. + */ + else if (parse_patarr[pix] != "/") { + fail = sub_parse(obarr, parse_patarr, ref pix, + parse_warr, ref cix, ref fail); + if (!fail && value) + store_value(six++, value); + } + /* + * Terminate parsing if no match + */ + if (fail) + break; + } + + /* + * Also fail when there is words left to parse and pattern exhausted + */ + if (fail || cix < sizeof(parse_warr)) + return 0; + + cret = ret; + ret = saved_ret; + return cret; +} + +private void +store_value(int pos, mixed what) { + if (sizeof(ret) <= pos) + ret += allocate(ret + 1 - pos); + + ret[pos] = what; +} + +static void +store_words_slice(int pos, mixed *warr, int from, int to) { + mixed *slice = warr[from..to]; + + store_value(pos, implode(slice, " ")); +} + +private static int +sub_parse(mixed *obarr, mixed *patarr, int ref pix_in, + mixed *warr, int ref cix_in) +{ + int cix, pix; + int fail; + + /* + * Fail if we have a pattern left but no words to parse + */ + if (*cix_in == sizeof(warr)) + return 1; + + cix = *cix_in; + pix = *pix_in; + + fail = one_parse(obarr, patarr[pix], warr, ref cix); + + while (fail) { + pix++; + cix = *cix_in; + + /* + * Find the next alternative pattern, consecutive '/' are skipped + */ + while (pix < sizeof(patarr) && patarr[pix] == "/") { + pix++; + fail = 0; + } + + if (!fail && pix < sizeof(patarr)) { + fail = one_parse(obarr, patarr[pix], warr, ref cix); + } else { + *pix_in = pix - 1; + return 1; + } + } + + /* + * If there is alternatives left after the mathing pattern, skip them + */ + if (pix + 1 < sizeof(patarr) && patarr[pix+1] == "/") { + while (pix + 1 < sizeof(patarr) && patarr[pix+1] == "/") { + pix += 2; + } + if (pix >= sizeof(patarr)) + pix = sizeof(patarr->size); + } + *cix_in = cix; + *pix_in = pix; + + return fail; +} + +private int +one_parse(mixed *obarr, string pat, mixed *warr, int ref cix_in) +{ + int ch, fail; + string str1, str2; + + /* + * Fail if we have a pattern left but no words to parse + */ + if (*cix_in >= sizeof(warr)) + return 1; + + ch = pat[0]; + if (ch == '%') + ch = pat[1]; + + switch (ch) { + case 'i': + case 'I': + fail = item_parse(obarr, warr, cix_in); + break; + +#ifndef __NO_ADD_ACTION__ + case 'l': + case 'L': + fail = living_parse(obarr, warr, cix_in); + break; +#endif + + case 's': + case 'S': + value = 0; + fail = 0; + break; + + case 'w': + case 'W': + value = warr[*cix_in]; + (*cix_in)++; + fail = 0; + break; + + case 'o': + case 'O': + fail = single_parse(obarr, warr, cix_in); + break; + + case 'p': + case 'P': + fail = prepos_parse(warr, cix_in); + break; + + case 'd': + case 'D': + fail = number_parse(obarr, warr, cix_in); + break; + + case '\'': + str1 = pat[1..<2]; + str2 = warr[*cix_in]; + if (pat[<1] == '\'' && str1 == str2) { + fail = 0; + (*cix_in)++; + } else + fail = 1; + break; + + case '[': + str1 = pat[1..<2]; + str2 = warr[*cix_in]; + if (str1 == str2) + (*cix_in)++; + fail = 0; + break; + + default: + fail = 0; /* Skip invalid patterns */ + } + + return fail; +} + +string *ord1 = ({"", "first", "second", "third", "fourth", "fifth", + "sixth", "seventh", "eighth", "nineth", "tenth", + "eleventh", "twelfth", "thirteenth", "fourteenth", + "fifteenth", "sixteenth", "seventeenth", + "eighteenth", "nineteenth" }); + +string *ord10 = ({"", "", "twenty", "thirty", "forty", "fifty", "sixty", + "seventy", "eighty", "ninety"}); + +string *sord10 = ({"", "", "twentieth", "thirtieth", "fortieth", + "fiftieth", "sixtieth", "seventieth", "eightieth", + "ninetieth"}); + +string *num1 = ({"", "one", "two", "three", "four", "five", "six", + "seven", "eight", "nine", "ten", + "eleven", "twelve", "thirteen", "fourteen", "fifteen", + "sixteen", "seventeen", "eighteen", "nineteen"}); + +string *num10 = ({"", "", "twenty", "thirty", "forty", "fifty", "sixty", + "seventy", "eighty", "ninety"}); + +private int +number_parse(mixed *obarr, mixed *warr, int ref cix_in) { + int cix, ten, ones, num; + string buf; + + cix = *cix_in; + + if (sscanf(warr[cix], "%d", num)) { + if (num >= 0) { + (*cix_in)++; + value = num; + return 0; + } + return 1; /* only nonnegative numbers */ + } + if (warr[cix] == allword) { + (*cix_in)++; + value = 0; + return 0; + } + /* This next double loop is incredibly stupid. -Beek */ + for (ten = 0; ten < 10; ten++) + for (ones = 0; ones < 10; ones++) { + buf = num10[ten] + (ten > 1 ? num1[ones] : num1[ten * 10 + ones]); + if (buf == warr[cix]) { + (*cix_in)++; + value = ten * 10 + ones; + return 0; + } + } + + /* this one too */ + for (ten = 0; ten < 10; ten++) + for (ones = 0; ones < 10; ones++) { + buf = (ones ? ord10[ten] : sord10[ten]) + (ten > 1 ? ord1[ones] : ord1[ten*10 + ones]); + if (buf == warr[cix]) { + (*cix_in)++; + value = -(ten * 10 + ones); + return 0; + } + } + + return 1; +} + +private int +item_parse(mixed *obarr, mixed *warr, int ref cix_in) { + mixed *tmp, *ret; + int cix, tix, obix, plur_flag, max_cix, match_all; + + tmp = allocate(sizeof(obarr) + 1); + + if (!number_parse(obarr, warr, cix_in)) { + tmp[0] = value; + match_all = (value == 0); + plur_flag = (match_all || value > 1); + have_number = 1; + value = 0; + } else { + plur_flag = 0; + match_all = 0; + } + + for (max_cix = *cix_in, tix = 1, obix = 0; obix < sizeof(obarr); obix++) { + cix = *cix_in; + if (!objectp(obarr[obix])) + continue; + if (cix == sizeof(warr) && match_all) { + tmp[tix++] = obarr[obix]; + continue; + } + load_lpc_info(obix, obarr[obix]); + + if (match_object(obix, warr, ref cix, ref plur_flag)) { + tmp[tix++] = obarr[obix]; + max_cix = (max_cix < cix) ? cix : max_cix; + } + } + + if (tix < 2) { + if (have_number) + (*cix_in)--; + return 1; + } else { + if (*cix_in < sizeof(warr)) + *cix_in = max_cix + 1; + if (!have_number) + tmp[0] = !plur_flag; + + value = tmp[0..tix-1]; + return 0; + } +} + +#ifndef __NO_ADD_ACTION__ +private int +living_parse(mixed *obarr, array warr, int ref cix_in, int ref fail) +{ + mixed *live; + object ob; + int obix, tix; + + live = allocate(sizeof(obarr)); + tix = 0; + + for (obix = 0; obix < sizeof(obarr); obix++) + if (living(obarr[obix])) + live[tix++] = obarr[obix]; + + if (tix && !item_parse(live, warr, cix_in)) + return 0; + + ob = find_player(warr[*cix_in]); + if (!ob) + ob = find_living(warr[*cix_in]); + + if (ob) { + value = ob; + (*cix_in)++; + return 0; + } + return 1; +} +#endif + +private int +single_parse(mixed *obarr, mixed *warr, int ref cix_in) +{ + int cix, obix, plur_flag; + + for (obix = 0; obix < sizeof(obarr); obix++) { + cix = *cix_in; + if (objectp(obarr[obix])) + load_lpc_info(obix, obarr[obix]); + plur_flag = 0; + if (match_object(obix, warr, ref cix, ref plur_flag)) { + *cix_in = cix + 1; + value = obarr[obix]; + return 0; + } + } + return 1; +} + +private int +prepos_parse(mixed *warr, int ref cix_in, mixed prepos) { + mixed *tarr; + string tmp; + int pix, tix; + + if (!prepos || !arrayp(prepos)) + prepos = prepos_list; + + for (pix = 0; pix < sizeof(prepos); pix++) { + if (!stringp(prepos[pix])) + continue; + + tmp = prepos[pix]; + if (member_array(' ', tmp) == -1) { + if (tmp == warr[*cix_in]) { + (*cix_in)++; + break; + } + } else { + tarr = explode(tmp, " "); + if (*cix_in + sizeof(tarr) <= sizeof(warr)) { + for (tix = 0; tix < sizeof(tarr); tix++) { + if (*cix_in + tix >= sizeof(warr) || + warr[*cix_in + tix] != tarr[tix]) + break; + } + if (tix == sizeof(tarr)) { + (*cix_in) += sizeof(tarr); + break; + } + } + } + } + + if (pix == sizeof(prepos)) { + value = 0; + return 1; + } else { + value = prepos[pix]; + return 0; + } +} + +private int +match_object(int obix, mixed *warr, int ref cix_in, int ref plur) { + mixed *ids; + int il, pos, cplur, old_cix; + string str; + + for (cplur = (*plur * 2); cplur < 4; cplur++) { + switch (cplur) { + case 0: + if (!id_list_d) + continue; + ids = id_list_d; + break; + + case 1: + if (!d_list || + sizeof(id_list) <= obix || + !arrayp(id_list[obix])) + continue; + ids = id_list[obix]; + break; + + case 2: + if (!pluid_list_d) + continue; + ids = pluid_list_d; + break; + + case 3: + if (!pluid_list || + sizeof(gpluid_list) <= obix || + !arrayp(gpluid_list[obix])) + continue; + ids = pluid_list[obix]; + break; + + default: + ids = 0; + } + + for (il = 0; il < sizeof(ids); il++) { + if (stringp(ids[il])) { + str = ids[il]; /* A given id of the object */ + old_cix = *cix_in; + if ((pos = find_string(str, warr, cix_in)) >= 0) { + if (pos == old_cix) { + if (cplur > 1) + *plur = 1; + return 1; + } else if (check_adjectiv(obix, warr, old_cix, pos - 1)) { + if (cplur > 1) + *plur = 1; + return 1; + } + } + *cix_in = old_cix; + } + } + } + return 0; +} + +static int +find_string(string str, mixed *warr, int ref cix_in) +{ + int fpos; + string p1; + mixed *split; + + for (; *cix_in < warr->size; (*cix_in)++) { + p1 = warr[*cix_in]; + + if (p1 == str) /* str was one word and we found it */ + return *cix_in; + + if (member_array(' ', str) == -1) + continue; + + /* + * If str was multi word we need to make some special checks + */ + if (*cix_in == sizeof(warr->size) - 1) + continue; + + split = explode(str, " "); + + /* + * warr->size - *cix_in == + * 2: One extra word + * 3: Two extra words + */ + if (sizeof(split) > sizeof(warr) - *cix_in) + continue; + + fpos = *cix_in; + for (; (*cix_in - fpos) < sizeof(split); (*cix_in)++) { + if (split[*cix_in - fpos] == warr[*cix_in]) + break; + } + if ((*cix_in - fpos) == sizeof(split)) + return fpos; + + *cix_in = fpos; + } + return -1; +} + +private int +check_adjectiv(int obix, mixed *warr, int from, int to) +{ + int il, back, fail; + string adstr; + mixed *ids; + + if (arrayp(adjid_list[obix])) + ids = adjid_list[obix]; + else + ids = 0; + + for (fail = 0, il = from; il <= to; il++) { + if ((member_array(warr[il], ids) < 0) && + (member_array(warr[il], adjid_list_d) < 0)) + fail = 1; + } + + /* + * Simple case: all adjs were single word + */ + if (!fail) + return 1; + + if (from == to) + return 0; + + /* + * If we now have: "adj1 adj2 adj3 ... adjN" + * We must test in order: "adj1 adj2 adj3 .... adjN-1 adjN" + "adj1 adj2 adj3 .... adjN-1" + "adj1 adj2 adj3 ...." + .... + * if match for adj1 .. adj3 continue with: + * "adj4 adj5 .... adjN-1 adjN" + * "adj4 adj5 .... adjN-1" + * "adj4 adj5 ...." + * ..... + */ + for (il = from; il <= to;) { /* adj1 .. adjN */ + for (back = to; back >= il; back--) { /* back from adjN to adj[il] */ + /* + * Create teststring with "adj[il] .. adj[back]" + */ + adstr = ""; + for (sum = il; sum <= back; sum++) { /* test "adj[il] .. + * adj[back]" */ + if (sum > il) + adstr += " "; + adstr += warr[sum]; + } + if ((member_array(adstr, ids) < 0) && + (member_array(adstr, adjid_list_d) < 0)) + continue; + else { + il = back + 1; /* Match "adj[il] adj[il+1] .. adj[back]" */ + back = to; + break; + } + } + if (back < to) + return 0; + } + return 1; +} diff --git a/fluffos-2.23-ds03/compat/simuls/process_string.c b/fluffos-2.23-ds03/compat/simuls/process_string.c new file mode 100644 index 0000000..8fb74a0 --- /dev/null +++ b/fluffos-2.23-ds03/compat/simuls/process_string.c @@ -0,0 +1,40 @@ +mixed process_value(string func) { + int tmp; + string arg; + object obj; + mixed ret; + + if (!func || !stringp(func)) + return 0; + + if ((tmp = member_array('|', func)) != -1) { + arg = func[tmp+1..]; + func = func[0..tmp-1]; + } + if ((tmp = member_array(':', func)) != -1) { + obj = find_object(func[tmp+1..]); + func = func[0..tmp-1]; + } else { + obj = previous_object(); + } + if (!obj) + return 0; + + return call_other(obj, func, explode(arg, "|")...); +} + +string process_string(string str) { + int pr_start; + string array parts = explode(str, "@@"); + + pr_start = !(str[0..1]=="@@"); + + for (int il = pr_start; il < sizeof(parts); il += 2) { + string tmp = process_value(parts[il]); + if (stringp(tmp)) + parts[il] = tmp; + } + + return implode(parts, ""); +} + diff --git a/fluffos-2.23-ds03/compat/simuls/tail.c b/fluffos-2.23-ds03/compat/simuls/tail.c new file mode 100644 index 0000000..847a97c --- /dev/null +++ b/fluffos-2.23-ds03/compat/simuls/tail.c @@ -0,0 +1,49 @@ +#ifdef COMPAT_TAIL +/* This version is strictly compatible with the old version */ +int tail(string fname) { + string str; + int offset = file_size(fname); + + if (offset < 0) + return 0; + + offset -= 54 * 20; + if (offset < 0) offset = 0; + str = read_bytes(fname, offset, 1080); + if (!str) return 0; + if (offset) str = str[strsrch(str, "\n")+1..]; + write(str); + + return 1; +} +#else +/* This version is slightly extended and compatible in spirit, but doesn't + * reproduce the oddities of the original tail() efun. Note that it also + * returns the string, so write(tail(fname)) is needed for strict + * compatibility. + */ +varargs string tail(string fname, int nlines) { + int chunk = nlines * 80; + int offset = file_size(fname); + int num_nl, p, skip; + string str = ""; + + while (offset > 0 && num_nl <= nlines) { + num_nl = 0; + offset -= chunk; + if (offset < 0) { + chunk += offset; /* negative */ + offset = 0; + } + str = read_bytes(fname, offset, chunk) + str; + p = -1; + while (p < sizeof(str)-1 && p = member_array('\n', str, p+1)) + num_nl++; + } + skip = num_nl - nlines; + p = -1; + while (skip--) + p = member_array('\n', str, p+1); + return str[p..]; +} +#endif diff --git a/fluffos-2.23-ds03/compiler.c b/fluffos-2.23-ds03/compiler.c new file mode 100644 index 0000000..f44ccd7 --- /dev/null +++ b/fluffos-2.23-ds03/compiler.c @@ -0,0 +1,2750 @@ +#include "std.h" +#include "lpc_incl.h" +#include "compiler.h" +#include "generate.h" +#include "scratchpad.h" +#include "qsort.h" +#include "file.h" + +/* This should be moved with initializers move out of here */ +#include "icode.h" +#include "lex.h" +#include "simul_efun.h" + +static void clean_parser (void); +static void prolog (int, char *); +static program_t *epilog (void); +static void show_overload_warnings (void); + +#define CT(x) (1 << (x)) +#define CT_SIMPLE(x) (CT(TYPE_ANY) | CT(x)) + +short compatible[11] = { + /* UNKNOWN */ 0, + /* ANY */ 0xfff, + /* NOVALUE to*/CT_SIMPLE(TYPE_NOVALUE) | CT(TYPE_VOID) | CT(TYPE_NUMBER), + /* VOID to*/ CT_SIMPLE(TYPE_VOID) | CT(TYPE_NUMBER), + /* NUMBER to*/ CT_SIMPLE(TYPE_NUMBER) | CT(TYPE_REAL), + /* STRING */ CT_SIMPLE(TYPE_STRING), + /* OBJECT */ CT_SIMPLE(TYPE_OBJECT), + /* MAPPING */ CT_SIMPLE(TYPE_MAPPING), + /* FUNCTION */ CT_SIMPLE(TYPE_FUNCTION), + /* REAL */ CT_SIMPLE(TYPE_REAL) | CT(TYPE_NUMBER), + /* BUFFER */ CT_SIMPLE(TYPE_BUFFER), +}; + +short is_type[11] = { + /* UNKNOWN */ 0, + /* ANY */ 0xfff, + /* NOVALUE */ CT_SIMPLE(TYPE_NOVALUE) | CT(TYPE_VOID), + /* VOID */ CT_SIMPLE(TYPE_VOID) | CT(TYPE_NOVALUE), + /* NUMBER */ CT_SIMPLE(TYPE_NUMBER), + /* STRING */ CT_SIMPLE(TYPE_STRING), + /* OBJECT */ CT_SIMPLE(TYPE_OBJECT), + /* MAPPING */ CT_SIMPLE(TYPE_MAPPING), + /* FUNCTION */CT_SIMPLE(TYPE_FUNCTION), + /* REAL */ CT_SIMPLE(TYPE_REAL), + /* BUFFER */ CT_SIMPLE(TYPE_BUFFER), +}; + +mem_block_t mem_block[NUMAREAS]; + +parse_node_t *comp_trees[NUMTREES]; +int comp_last_inherited; +int current_tree; + +function_context_t function_context; + +int exact_types, global_modifiers; + +int current_type; +int var_defined; + +unsigned short *comp_def_index_map, *func_index_map; +unsigned short *prog_flags, *comp_sorted_funcs; + +char *prog_code; +char *prog_code_max; + +program_t NULL_program = {0}; + +program_t *prog; + +static short string_idx[0x100]; +unsigned char string_tags[0x20]; +short freed_string; + +/* x_ptr is different inside nested functions */ +unsigned short *type_of_locals, *type_of_locals_ptr; +local_info_t *locals, *locals_ptr; + +int locals_size = 0; +int type_of_locals_size = 0; +int current_number_of_locals = 0; +int max_num_locals = 0; + +/* This function has strput() semantics; see comments in simulate.c */ +char *get_two_types (char * where, char * end, int type1, int type2) +{ + where = strput(where, end, "( "); + where = get_type_name(where, end, type1); + where = strput(where, end, "vs "); + where = get_type_name(where, end, type2); + where = strput(where, end, ")"); + + return where; +} + +void init_locals() +{ + type_of_locals = CALLOCATE(CFG_MAX_LOCAL_VARIABLES,unsigned short, + TAG_LOCALS, "init_locals:1"); + locals = CALLOCATE(CFG_MAX_LOCAL_VARIABLES, local_info_t, + TAG_LOCALS, "init_locals:2"); + type_of_locals_ptr = type_of_locals; + locals_ptr = locals; + locals_size = type_of_locals_size = CFG_MAX_LOCAL_VARIABLES; + current_number_of_locals = max_num_locals = 0; +} + +void free_all_local_names (int flag) +{ + int i; + + for (i=0; i < current_number_of_locals; i++) { + if (flag && (type_of_locals_ptr[locals_ptr[i].runtime_index] & LOCAL_MOD_UNUSED)) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Unused local variable '"); + p = strput(p, end, locals_ptr[i].ihe->name); + p = strput(p, end, "'"); + yywarn(buf); + } + locals_ptr[i].ihe->sem_value--; + locals_ptr[i].ihe->dn.local_num = -1; + } + current_number_of_locals = 0; + max_num_locals = 0; +} + +void deactivate_current_locals() { + int i; + + for (i = 0; i < current_number_of_locals; i++) + locals_ptr[i].ihe->dn.local_num = -1; +} + +void reactivate_current_locals() { + int i; + + for (i = 0; i < current_number_of_locals; i++) { + locals_ptr[i].ihe->dn.local_num = locals_ptr[i].runtime_index; + locals_ptr[i].ihe->sem_value++; + } +} + +void clean_up_locals() +{ + int offset; + + offset = locals_ptr + current_number_of_locals - locals; + while (offset--) { + locals[offset].ihe->sem_value--; + locals[offset].ihe->dn.local_num = -1; + } + current_number_of_locals = 0; + max_num_locals = 0; + locals_ptr = locals; + type_of_locals_ptr = type_of_locals; +} + +void pop_n_locals (int num) { + int lcur_start; + int ltype_start, i1; + + DEBUG_CHECK(num < 0, "pop_n_locals called with num < 0"); + if (num == 0) + return; + + lcur_start = current_number_of_locals -= num; + ltype_start = locals_ptr[lcur_start].runtime_index; + + i1 = num; + while (i1--) { + if (type_of_locals_ptr[ltype_start] & LOCAL_MOD_UNUSED) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Unused local variable '"); + p = strput(p, end, locals_ptr[lcur_start].ihe->name); + p = strput(p, end, "'"); + yywarn(buf); + } + locals_ptr[lcur_start].ihe->sem_value--; + locals_ptr[lcur_start].ihe->dn.local_num = -1; + ++lcur_start; + ++ltype_start; + } +} + +int add_local_name (const char * str, int type) +{ + if (max_num_locals == CFG_MAX_LOCAL_VARIABLES) { + yyerror("Too many local variables"); + return 0; + } else { + ident_hash_elem_t *ihe; + + ihe = find_or_add_ident(str,FOA_NEEDS_MALLOC); + type_of_locals_ptr[max_num_locals] = type; + locals_ptr[current_number_of_locals].ihe = ihe; + locals_ptr[current_number_of_locals++].runtime_index = max_num_locals; + if (ihe->dn.local_num == -1) + ihe->sem_value++; + return ihe->dn.local_num = max_num_locals++; + } +} + +void reallocate_locals() { + int offset; + offset = type_of_locals_ptr - type_of_locals; + type_of_locals = RESIZE(type_of_locals, type_of_locals_size += CFG_MAX_LOCAL_VARIABLES, + unsigned short, TAG_LOCALS, "reallocate_locals:1"); + type_of_locals_ptr = type_of_locals + offset; + offset = locals_ptr - locals; + locals = RESIZE(locals, locals_size, + local_info_t, TAG_LOCALS, "reallocate_locals:2"); + locals_ptr = locals + offset; +} + +/* Fix a inherited class type for the current program */ +static void fix_class_type (int * t, program_t * from) { + ident_hash_elem_t *ihe; + int num; + + if ((*t) & TYPE_MOD_CLASS) { + ihe = lookup_ident(from->strings[from->classes[(*t) & CLASS_NUM_MASK].classname]); + if (ihe && ((num = ihe->dn.class_num) != -1)) { + (*t) = (*t & ~CLASS_NUM_MASK) | num; + } else { + if(!num_parse_error) + fatal("Cannot find class %s (%s,%d).\n",from->strings[from->classes[(*t) & CLASS_NUM_MASK].classname], current_file, current_line); + } + } +} + + +/* + * Copy all variable names from the object that is inherited from. + * It is very important that they are stored in the same order with the + * same index. + */ +void copy_variables (program_t * from, int type) { + int i; + + for (i = 0; i < from->num_inherited; i++) { + int t = DECL_MODIFY(type, from->inherit[i].type_mod); + + /* 'private' vars become 'hidden' */ + if (from->inherit[i].type_mod & DECL_PRIVATE) + t = (t & ~DECL_PRIVATE) | DECL_HIDDEN; + + t &= ~FUNC_VARARGS; /* for 'varargs inherit' */ + + copy_variables(from->inherit[i].prog, t); + } + for (i = 0; i < from->num_variables_defined; i++) { + int t = DECL_MODIFY(from->variable_types[i], type); + + /* 'private' vars become 'hidden' */ + if (from->variable_types[i] & DECL_PRIVATE) + t = (t & ~DECL_PRIVATE) | DECL_HIDDEN; + + t &= ~FUNC_VARARGS; /* for 'varargs inherit' */ + + /* Handle classes */ + fix_class_type(&t, from); + + define_variable(from->variable_table[i], t); + } +} + +static int add_new_function_entry() { + int index = mem_block[A_FUNCTION_DEFS].current_size / sizeof(compiler_temp_t); + allocate_in_mem_block(A_FUNCTION_DEFS, sizeof(compiler_temp_t)); + + return index; +} + +/* copy a function verbatim into this object, and possibly add it to the + list of functions in this object, as well + */ + +/* This is the first time the function occurs in the current program + and it happened by copying from program prog + Because program prog is assumed to be dealt with correctly, + we know if this _was_ an aliased function, it must point to + to the correct definition already in prog + If this is not the first time it occurs, use overload_function + Otherwise, consistency cannot be guaranteed. The resulting + first time copy will never be aliased, as it's presence will + be a magic marker for other similar functions that will get + removed. - Sym + */ + +static void copy_new_function (program_t * prog, int index, + program_t * defprog, int defindex, + int typemod) { + ident_hash_elem_t *ihe; + + int where = add_new_function_entry(); + int f = prog->function_flags[index]; + + if (f & FUNC_ALIAS) { + f = FUNC_ALIAS | prog->function_flags[f & ~FUNC_ALIAS]; + } + + /* 'private' functions become 'hidden' */ + if (f & DECL_PRIVATE) + f = (f & ~DECL_PRIVATE) | DECL_HIDDEN; + + f = DECL_MODIFY(typemod, f) | FUNC_INHERITED; + f &= ~DECL_NOSAVE; + + FUNCTION_FLAGS(where) = f; + + FUNCTION_TEMP(where)->prog = defprog; + FUNCTION_TEMP(where)->u.func = defprog->function_table + defindex; + FUNCTION_TEMP(where)->offset = NUM_INHERITS - 1; + FUNCTION_TEMP(where)->function_index_offset = index; + FUNCTION_NEXT(where) = 0; + + /* add the identifier */ + ihe = find_or_add_ident(defprog->function_table[defindex].funcname, + FOA_GLOBAL_SCOPE); + ihe->sem_value++; /* we knew it was the first, so dn.function_num = -1 */ + ihe->dn.function_num = where; +} + +static int find_class_member (int which, char * name, unsigned char * type) { + int i; + class_def_t *cd; + class_member_entry_t *cme; + + DEBUG_CHECK(!findstring(name), "name in find_class_member must be a shared string.\n"); + + cd = ((class_def_t *)mem_block[A_CLASS_DEF].block) + which; + cme = ((class_member_entry_t *)mem_block[A_CLASS_MEMBER].block) + cd->index; + for (i = 0; i < cd->size; i++) { + if (PROG_STRING(cme[i].membername) == name) + break; + } + if (i == cd->size) { + if (type) *type = TYPE_ANY; + return -1; + } else { + if (type) *type = cme[i].type; + return i; + } +} + +int lookup_any_class_member (char * name, unsigned char * type) { + int nc = mem_block[A_CLASS_DEF].current_size / sizeof(class_def_t); + int i, ret = -1, nret; + char *s = findstring(name); + + if (s) { + for (i = 0; i < nc; i++) { + nret = find_class_member(i, s, type); + if (nret == -1) continue; + if (ret != -1 && nret != ret) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "More than one class in scope has member '"); + p = strput(p, end, name); + p = strput(buf, end, "'; use a cast to disambiguate"); + yyerror(buf); + } + ret = nret; + } + } + + if (ret == -1) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "No class in scope has no member '"); + p = strput(p, end, name); + p = strput(p, end, "'"); + yyerror(buf); + } + + return ret; +} + +int lookup_class_member (int which, char * name, unsigned char * type) { + char *s = findstring(name); + int ret; + + if (s) + ret = find_class_member(which, s, type); + else + ret = -1; + + if (ret == -1) { + class_def_t *cd = ((class_def_t *)mem_block[A_CLASS_DEF].block) + which; + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Class '"); + p = strput(p, end, PROG_STRING(cd->classname)); + p = strput(p, end, "' has no member '"); + p = strput(p, end, name); + p = strput(p, end, "'"); + + yyerror(buf); + } + return ret; +} + +parse_node_t *reorder_class_values (int which, parse_node_t * node) { + class_def_t *cd; + parse_node_t **tmp; + int i; + + cd = ((class_def_t *)mem_block[A_CLASS_DEF].block) + which; + tmp = CALLOCATE(cd->size, parse_node_t *, TAG_COMPILER, + "reorder_class_values"); + + for (i = 0; i < cd->size; i++) + tmp[i] = 0; + + while (node) { + i = lookup_class_member(which, (char *)node->l.expr, 0); + if (i != -1) { + if (tmp[i]) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Redefinition of member '"); + p = strput(p, end, (char *) node->l.expr); + p = strput(p, end, "' in instantiation of class '"); + p = strput(p, end, PROG_STRING(cd->classname)); + p = strput(p, end, "'"); + yyerror(buf); + } else { + tmp[i] = node->v.expr; + } + } + scratch_free((char *) node->l.expr); + + node = node->r.expr; + } + i = cd->size; + node = 0; + while (i--) { + parse_node_t *newnode; + if (tmp[i]) { + CREATE_STATEMENTS(newnode, tmp[i], node); + } else { + CREATE_STATEMENTS(newnode, 0, node); + CREATE_NUMBER(newnode->l.expr, 0); + } + node = newnode; + } + + FREE(tmp); + return node; +} + +static void check_class (char * name, program_t * prog, int idx, int nidx) { + class_def_t *sd1, *sd2; + class_member_entry_t *sme1, *sme2; + int i, n; + + sd1 = &prog->classes[idx]; + sd2 = CLASS(nidx); + + n = sd1->size; + if (sd1->size != sd2->size) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Definitions of class '"); + p = strput(p, end, name); + p = strput(p, end, "' differ in size."); + yyerror(buf); + return; + } + + sme1 = &prog->class_members[sd1->index]; + sme2 = (class_member_entry_t *)mem_block[A_CLASS_MEMBER].block + sd2->index; + + for (i = 0; i < n; i++) { + int newtype; + + newtype = sme1[i].type; + + fix_class_type(&newtype, prog); + + if (sme2[i].type != newtype || + prog->strings[sme1[i].membername] != PROG_STRING(sme2[i].membername)) { + char buf[512]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Definitions of class '"); + p = strput(p, end, name); + p = strput(p, end, "' disagree."); + yyerror(buf); + return; + } + } +} + +void copy_structures (program_t * prog) { + class_def_t *sd; + class_member_entry_t *sme; + ident_hash_elem_t *ihe; + char *str; + int sm_off = mem_block[A_CLASS_MEMBER].current_size / sizeof(class_member_entry_t); + int sd_off = mem_block[A_CLASS_DEF].current_size / sizeof(class_def_t); + int i, j, offset; + + if (prog->num_classes + sd_off > CLASS_NUM_MASK) { + char buf[512]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Too many classes, max is "); + p = strput_int(p, end, CLASS_NUM_MASK - 1); + p = strput(p, end, ".\n"); + yyerror(buf); + return; + } + + for (i = 0; i < prog->num_classes; i++) { + str = prog->strings[prog->classes[i].classname]; + ihe = find_or_add_ident(str, FOA_GLOBAL_SCOPE); + if (ihe->dn.class_num == -1) { + ihe->dn.class_num = sd_off++; + ihe->sem_value++; + } else { + check_class(str, prog, i, ihe->dn.class_num); + continue; + } + sd = (class_def_t *)allocate_in_mem_block(A_CLASS_DEF, sizeof(class_def_t)); + sd->classname = store_prog_string(str); + sd->size = prog->classes[i].size; + sd->index = sm_off; + sm_off += sd->size; + sme = (class_member_entry_t *)allocate_in_mem_block(A_CLASS_MEMBER, sizeof(class_member_entry_t) * sd->size); + offset = prog->classes[i].index; + for (j = 0; j < sd->size; j++) { + int oldtype = prog->class_members[offset + j].type; + + fix_class_type(&oldtype, prog); + sme[j].type = oldtype; + sme[j].membername = store_prog_string(prog->strings[prog->class_members[offset + j].membername]); + } + } +} + +typedef struct ovlwarn_s { + struct ovlwarn_s *next; + char *func; + char *warn; +} ovlwarn_t; + +ovlwarn_t *overload_warnings = 0; + +static void remove_overload_warnings (char * func) { + ovlwarn_t **p; + ovlwarn_t *tmp; + + p = &overload_warnings; + while (*p) { + if (!func || (*p)->func == func) { + FREE((*p)->warn); + tmp = *p; + *p = (*p)->next; + FREE(tmp); + } else + p = &(*p)->next; + } +} + +static void show_overload_warnings() { + ovlwarn_t *p, *next; + p = overload_warnings; + while (p) { + yywarn(p->warn); + FREE(p->warn); + next = p->next; + FREE(p); + p = next; + } + overload_warnings = 0; +} + +/* Overload the function index with the new definition + The idea is to choose a function out of all non-aliases + inherited or at the current level. + + non-alias1 .. non-aliasK -> Final resolution + + The function at oldindex always has the most recent choice. + The fact that it is at oldindex saves changing ihe.sem_values, + among other things. + + The current resolution order is + 1st inh proto < ... < last inh proto < + 1st non-inh proto < .. < last non-inh proto < + 1st inh defined < .. < last inh defined < + defined + */ +static void overload_function (program_t * prog, int index, + program_t * defprog, int defindex, + int oldindex, int typemod) { + int f; + int oldflags = FUNCTION_FLAGS(oldindex); + function_t *definition = &defprog->function_table[defindex]; + int newflags = prog->function_flags[index]; + int replace; + compiler_temp_t *newdef; + + if (newflags & FUNC_ALIAS) + newflags = FUNC_ALIAS | prog->function_flags[newflags & ~FUNC_ALIAS]; + + /* check that we aren't overloading a nomask function */ + if ((oldflags & DECL_NOMASK) && + !((oldflags|newflags) & (FUNC_NO_CODE))) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Illegal to redefine 'nomask' function \""); + p = strput(p, end, definition->funcname); + p = strput(p, end, "\""); + yyerror(buf); + } + + /* Try to prevent some confusion re: overloading. + * Warn them about the behavior of inheriting the same function + * from two branches. + * + * Note that we don't want to scream now, b/c if the function is + * overloaded later this becomes irrelevant. + * + * Note also that this is real spammy if you inherit the same object + * twice. Something should be done about that. + */ + if ((pragmas & PRAGMA_WARNINGS) && + !((oldflags|newflags) & (FUNC_NO_CODE|DECL_PRIVATE|DECL_HIDDEN)) + && (oldflags & FUNC_INHERITED) + ) { + /* don't scream if one is private. Why not? Because I said so. + * private is pretty screwed up anyway. In the future there + * won't be such a clash b/c private won't come up the tree. + * This also give the coder a way to shut the compiler up when + * you do inherit the same object twice in different branches :) + */ + if (!(oldflags & (DECL_PRIVATE|DECL_HIDDEN)) && !(newflags & (DECL_PRIVATE|DECL_HIDDEN))) { + char buf[1024]; + char *end = EndOf(buf); + char *p; + ovlwarn_t *ow; + compiler_temp_t *func_entry = FUNCTION_TEMP(oldindex); + program_t *prog2 = INHERIT(func_entry->offset)->prog; + program_t *defprog2; + + defprog2 = func_entry->prog; + p = strput(buf, end, definition->funcname); + p = strput(p, end, "() inherited from both /"); + p = strput(p, end, defprog->filename); + if (prog != defprog) { + p = strput(p, end, " (via /"); + p = strput(p, end, prog->filename); + p = strput(p, end, ")"); + } + p = strput(p, end, " and /"); + p = strput(p, end, defprog2->filename); + if (prog2 != defprog2) { + p = strput(p, end, " (via /"); + p = strput(p, end, prog2->filename); + p = strput(p, end, ")"); + } + p = strput(p, end, "; using the definition in /"); + p = strput(p, end, prog->filename); + p = strput(p, end, "."); + + ow = ALLOCATE(ovlwarn_t, TAG_COMPILER, "overload warning"); + ow->next = overload_warnings; + ow->func = definition->funcname; + ow->warn = alloc_cstring(buf, "overload warning"); + overload_warnings = ow; + } + } + + /* A new function also has to be inserted, since this spot will be + * used when this function is called in an object inheriting us. Point + * it at the overloaded function. + * No need to set much here because epilog() will fixup this entry + * later. + */ + + newdef = ALLOCATE(compiler_temp_t, TAG_COMPILER, "overload_function"); + + /* The resolution order is given in above comments */ + if (oldflags & FUNC_ALIAS) replace = 1; + else if (newflags & FUNC_ALIAS) replace = 0; + else if (!(newflags & (FUNC_PROTOTYPE|FUNC_UNDEFINED))) { + if (oldflags & (FUNC_PROTOTYPE|FUNC_INHERITED|FUNC_UNDEFINED)) + replace = 1; + else replace = 0; + } else { + if ((oldflags & (FUNC_PROTOTYPE|FUNC_UNDEFINED)) && + (oldflags & FUNC_INHERITED)) + replace = 1; + else replace = 0; + } + + if (replace) { + /* We win */ + if (!(oldflags & FUNC_INHERITED)) { + /* Mark entry for removal */ + FUNC(FUNCTION_TEMP(oldindex)->u.index)->address = ADDRESS_MAX; + } + *newdef = *FUNCTION_TEMP(oldindex); + FUNCTION_TEMP(oldindex)->next = newdef; + newdef = FUNCTION_TEMP(oldindex); + } else { + compiler_temp_t *oldnext = FUNCTION_TEMP(oldindex)->next; + newdef->next = oldnext; + FUNCTION_TEMP(oldindex)->next = newdef; + } + + newdef->offset = NUM_INHERITS - 1; + newdef->function_index_offset = index; + newdef->prog = defprog; + newdef->u.func = defprog->function_table + defindex; + + f = (newflags & FUNC_MASK) | FUNC_INHERITED; + + /* 'private' functions become 'hidden' */ + if (f & DECL_PRIVATE) f = (f & ~DECL_PRIVATE) | DECL_HIDDEN; + + f = DECL_MODIFY(typemod, f); + f &= ~DECL_NOSAVE; + + newdef->flags = f; +} + +/* + * Copy all function definitions from an inherited object. They are added + * as undefined, so that they can be redefined by a local definition. + * If they are not redefined, then they will be updated, so that they + * point to the inherited definition. See epilog(). Types will be copied + * at that moment (if available). + * + * A call to an inherited function will not be + * done through this entry (because this entry can be replaced by a new + * definition). If an function defined by inheritance is called, then one + * special definition will be made at first call. + */ +int copy_functions (program_t * from, int typemod) +{ + int i, initializer = -1, num_functions; + ident_hash_elem_t *ihe; + int num; + + num_functions = from->num_functions_defined + from->last_inherited; + + if (from->num_functions_defined && + (from->function_table[from->num_functions_defined - 1].funcname[0] == APPLY___INIT_SPECIAL_CHAR)) + initializer = --num_functions; + + for (i = 0; i < num_functions; i++) { + program_t *prog = from; + int index = i; + function_t *funp; + int low, mid, high; + + /* Walk up the inheritance tree to the real definition */ + if (prog->function_flags[index] & FUNC_ALIAS) { + index = prog->function_flags[index] & ~FUNC_ALIAS; + } + + while (prog->function_flags[index] & FUNC_INHERITED) { + low = 0; + high = prog->num_inherited -1; + + while (high > low) { + mid = (low + high + 1) >> 1; + if (prog->inherit[mid].function_index_offset > index) + high = mid -1; + else low = mid; + } + index -= prog->inherit[low].function_index_offset; + prog = prog->inherit[low].prog; + } + + index -= prog->last_inherited; + + funp = prog->function_table + index; + + + ihe = lookup_ident(funp->funcname); + if (ihe && ((num = ihe->dn.function_num)!=-1)) { + /* The function has already been defined in this object */ + overload_function(from, i, prog,index, num, typemod); + } else { + copy_new_function(from, i, prog, index, typemod); + } + } + return initializer; +} + +void type_error (const char * str, int type) +{ + static char buff[512]; + char *end = EndOf(buff); + char *p; + + p = strput(buff, end, str); + p = strput(p, end, ": \""); + p = get_type_name(p, end, type); + p = strput(p, end, "\""); + yyerror(buff); +} + +/* + * Compare two types, and return true if they are compatible. + */ + +/* This one really is t1->t2; it isn't symmetric, since int->void isn't allowed. */ +int compatible_types (int t1, int t2) +{ +#ifdef OLD_TYPE_BEHAVIOR + /* The old version effectively was almost always was true */ + return 1; +#else + t1 &= ~DECL_MODS; + t2 &= ~DECL_MODS; + if (t1 == TYPE_ANY || t2 == TYPE_ANY) return 1; + if ((t1 == (TYPE_ANY | TYPE_MOD_ARRAY) && (t2 & TYPE_MOD_ARRAY))) + return 1; + if ((t2 == (TYPE_ANY | TYPE_MOD_ARRAY) && (t1 & TYPE_MOD_ARRAY))) + return 1; + if (t1 & TYPE_MOD_CLASS) + return t1 == t2; + if (t1 & TYPE_MOD_ARRAY) { + if (!(t2 & TYPE_MOD_ARRAY)) return 0; + return t1 == (TYPE_MOD_ARRAY | TYPE_ANY) || + t2 == (TYPE_MOD_ARRAY | TYPE_ANY) || (t1 == t2); + } else if (t2 & TYPE_MOD_ARRAY) + return 0; + if(t1>10 || t1 < 0) + fatal("compiler.c: unknown type in compatible_types()"); + return compatible[t1] & (1 << t2); +#endif +} + +/* This one is symmetric. Used for comparison operators, etc */ +int compatible_types2 (int t1, int t2) +{ +#ifdef OLD_TYPE_BEHAVIOR + /* The old version effectively was almost always was true */ + return 1; +#else + t1 &= ~DECL_MODS; + t2 &= ~DECL_MODS; + if (t1 == TYPE_ANY || t2 == TYPE_ANY) return 1; + if ((t1 == (TYPE_ANY | TYPE_MOD_ARRAY) && (t2 & TYPE_MOD_ARRAY))) + return 1; + if ((t2 == (TYPE_ANY | TYPE_MOD_ARRAY) && (t1 & TYPE_MOD_ARRAY))) + return 1; + if (t1 & TYPE_MOD_CLASS) + return t1 == t2; + if (t1 & TYPE_MOD_ARRAY) { + if (!(t2 & TYPE_MOD_ARRAY)) return 0; + return t1 == (TYPE_MOD_ARRAY | TYPE_ANY) || + t2 == (TYPE_MOD_ARRAY | TYPE_ANY) || (t1 == t2); + } else if (t2 & TYPE_MOD_ARRAY) + return 0; + if (compatible[t1] & (1 << t2)) + return 1; + return compatible[t2] & (1 << t1); +#endif +} + +/* + * Patch a function definition of an inherited function, to what it really + * should be. + * The name of the function can be one of: + * object::name + * ::name + * Where 'object' is the name of the superclass. + * + * Note: this function is now only used for resolving :: references + */ +static int find_matching_function (program_t * prog, char * name, + parse_node_t * node) { + int high = prog->num_functions_defined - 1; + int low = 0; + int i, res; + + /* Search our function table */ + while (high >= low) { + int mid = (high + low)/2; + char *p = prog->function_table[mid].funcname; + + if (name < p) + high = mid-1; + else if (name > p) + low = mid+1; + else { + int ri; + int flags; + int type; + + /* Rely on the fact that functions in the table are not inherited + or aliased */ + /* Non-inherited aliased ones are always removed anyway */ + ri = prog->last_inherited + mid; + + flags = prog->function_flags[ri]; + + if (flags & (FUNC_UNDEFINED | FUNC_PROTOTYPE)) return 0; + if (flags & DECL_PRIVATE) return -1; + + node->kind = NODE_CALL_2; + node->v.number = F_CALL_INHERITED; + node->l.number = ri; + type = prog->function_table[mid].type; + fix_class_type(&type, prog); + node->type = type; + return 1; + } + } + + /* Search inherited function tables */ + i = prog->num_inherited; + while (i--) { + if ((res = find_matching_function(prog->inherit[i].prog, name, node))) { + if ((res == -1) || (prog->inherit[i].type_mod & DECL_PRIVATE)) + return -1; + + node->l.number += prog->inherit[i].function_index_offset; + return 1; + } + } + return 0; +} + +int arrange_call_inherited (char * name, parse_node_t * node) +{ + inherit_t *ip; + int num_inherits, super_length; + char *super_name, *p, *real_name = name; + char *shared_string; + int ret; + + if (real_name[0] == ':') { + super_name = 0; + real_name += 2; /* There will be exactly two ':' */ + super_length = 0; + } else if ((p = strchr(real_name, ':'))) { + super_name = name; + real_name = p+2; + super_length = real_name - super_name - 2; + } else + fatal("no : in inherit call ???"); + + num_inherits = NUM_INHERITS; + /* no need to look for it unless its in the shared string table */ + if ((shared_string = findstring(real_name))) { + ip = (inherit_t *) mem_block[A_INHERITS].block; + for (; num_inherits > 0; ip++, num_inherits--) { + int tmp; + + if (super_name) { + int l = SHARED_STRLEN(ip->prog->filename); /* Including .c */ + + if (l - 2 < super_length) + continue; + if (strncmp(super_name, ip->prog->filename + l - 2 -super_length, + super_length) != 0 || + !((l - 2 == super_length) || + ((ip->prog->filename + l - 3 - super_length)[0] == '/'))) + continue; + } + + if ((tmp = find_matching_function(ip->prog, shared_string, node))) { + if (tmp == -1 || (ip->type_mod & DECL_PRIVATE)) { + yyerror("Called function is private."); + + goto invalid; + } + + ret = node->l.number + ip->function_index_offset; + node->l.number |= ((ip - (inherit_t *) mem_block[A_INHERITS].block) << 16); + return ret; + } + } + } /* if in shared string table */ + { + char buff[256]; + char *end = EndOf(buff); + char *p; + + p = strput(buff, end, "No such inherited function "); + p = strput(p, end, name); + yyerror(buff); + } + + invalid: + node->kind = NODE_CALL_2; + node->v.number = F_CALL_INHERITED; + node->l.number = 0; + node->type = TYPE_ANY; + + return -1; +} + +/* + * Define a new function. Note that this function is called at least twice + * for all function definitions. First as a prototype, then as the real + * function. Thus, there are tests to avoid generating error messages more + * than once by looking at (flags & NAME_PROTOTYPE). + */ +/* Warning: returns an index into A_FUNCTIONS, not the full + * function list + */ +int define_new_function (const char * name, int num_arg, int num_local, + int flags, int type) +{ + int oldindex, num, newindex; + unsigned short argument_start_index; + ident_hash_elem_t *ihe; + function_t *funp = 0; + compiler_temp_t *newfunc; + + oldindex = (ihe = lookup_ident(name)) ? ihe->dn.function_num : -1; + if (oldindex >= 0) { + int funflags = FUNCTION_FLAGS(oldindex); + + funp = FUNCTION_DEF(oldindex); + + /* + * The function was already defined. It may be one of several + * reasons: + * + * 1. There has been a prototype. + * 2. There was a function with the same name defined by inheritance. + * 3. This function has been called, but not yet defined. + * 4. The function is doubly defined. + * 5. A "late" prototype has been encountered. + */ + if (funflags & FUNC_ALIAS) { + fatal("Inconsistent aliasing of functions!\n"); + } + + if (!(funflags & (FUNC_INHERITED|FUNC_PROTOTYPE|FUNC_UNDEFINED)) + && !(flags & FUNC_PROTOTYPE)) { + char buff[256]; + char *end = EndOf(buff); + char *p; + + p = strput(buff, end, "Redeclaration of function "); + p = strput(p, end, name); + p = strput(p, end, "."); + yyerror(buff); + return -1; + } + /* + * It was either an undefined but used funtion, or an inherited + * function. In both cases, we now consider this to be THE new + * definition. It might also have been a prototype to an already + * defined function, in which case we simply return. + * + * Check arguments only when types are supposed to be tested, and if + * this function really has been defined already. + * + * 'nomask' functions may not be redefined. + */ + if ((funflags & DECL_NOMASK) && + !((flags|funflags) & (FUNC_UNDEFINED|FUNC_PROTOTYPE))) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Illegal to redefine 'nomask' function \""); + p = strput(p, end, name); + p = strput(p, end, "\""); + yyerror(buf); + } + + /* only check prototypes for matching. It shouldn't be required that + overloading a function must have the same signature */ + if (exact_types && ((flags|funflags) & FUNC_PROTOTYPE)) { + int funtype, i; + + funtype = funp->type; + if (FUNCTION_TEMP(oldindex)->prog) { + fix_class_type(&funtype, FUNCTION_TEMP(oldindex)->prog); + } + /* This should be changed to catch two prototypes which disagree */ + if (funtype != TYPE_UNKNOWN) { + if (funp->num_arg != num_arg + && !((flags|funflags) & FUNC_VARARGS)) + yywarn("Number of arguments disagrees with previous definition."); + if (!(funflags & FUNC_STRICT_TYPES)) + yywarn("Called function not compiled with type testing."); + + /* Now check that argument types wasn't changed. */ + if (!compatible_types(type, funtype)) { + char buff[512]; + char *end = EndOf(buff); + char *p; + + if (FUNCTION_TEMP(oldindex)->prog) { + p = strput(buff, end, "Function "); + p = strput(p, end, name); + p = strput(p, end, " inherited from '/"); + p = strput(p, end, FUNCTION_TEMP(oldindex)->prog->filename); + p = strput(p, end, "' does not match "); + } else { + if (funflags & FUNC_PROTOTYPE) + p = strput(buff, end, "Previous function prototype "); + else p = strput(buff, end, "Previous function declaration "); + p = strput(p, end, "for "); + p = strput(p, end, name); + p = strput(p, end, " does not match "); + } + p = strput(p, end, "current function in return type "); + p = get_two_types(p, end, funtype, type); + + yywarn(buff); + } + + for (i = 0; i < num_arg; i++) { + /* FIXME: check arg types here */ + + } + } + } + + /* If it was yet another prototype, then simply return. */ + /* provided the current winning definition is an undefined */ + /* or prototype itself */ + + if ((flags & FUNC_PROTOTYPE) && + !(funflags & (FUNC_PROTOTYPE|FUNC_UNDEFINED))) + return -1; /* unused for prototypes */ + + if (pragmas & PRAGMA_WARNINGS) + remove_overload_warnings(funp->funcname); + + /* If there was already a definition at this level (due to a + * prototype), clear it out. Don't free the function name, though; + * the name is the same, and the ident hash table might be counting + * on it to stay allocated. + */ + if (FUNCTION_PROG(oldindex) == 0) { + num = FUNCTION_TEMP(oldindex)->u.index; + funp = FUNC(num); + } else + funp = 0; + } + if (!funp) { + num = mem_block[A_FUNCTIONS].current_size / sizeof(function_t); + funp = (function_t *)allocate_in_mem_block(A_FUNCTIONS, sizeof(function_t)); + funp->funcname = make_shared_string(name); + argument_start_index = INDEX_START_NONE; + add_to_mem_block(A_ARGUMENT_INDEX, (char *) &argument_start_index, + sizeof argument_start_index); + + } + + if (oldindex < 0) { + newindex = add_new_function_entry(); + ihe = find_or_add_ident(funp->funcname, FOA_GLOBAL_SCOPE); + ihe->sem_value++; + ihe->dn.function_num = newindex; + newfunc = FUNCTION_TEMP(newindex); + newfunc->next = (compiler_temp_t *) NULL; + } else { + newfunc = ALLOCATE(compiler_temp_t, TAG_TEMPORARY, "define_new_function"); + *newfunc = *FUNCTION_TEMP(oldindex); + + /* We are going to rewrite stuff at oldindex */ + FUNCTION_TEMP(oldindex)->next = newfunc; + newfunc = FUNCTION_TEMP(oldindex); + + newindex = oldindex; + } + + newfunc->prog = 0; + newfunc->u.index = num; + + if (exact_types) + flags |= FUNC_STRICT_TYPES; + DEBUG_CHECK(!(flags & DECL_ACCESS), "No access level for function!\n"); + newfunc->flags = flags; + + + + funp->num_local = num_local; + funp->num_arg = num_arg; + funp->type = type; + funp->address = 0; +#ifdef PROFILE_FUNCTIONS + funp->calls = 0L; + funp->self = 0L; + funp->children = 0L; +#endif + + if (exact_types && num_arg) { + int i; + + if (!(flags & FUNC_PROTOTYPE)) { + for (i = 0; i < current_number_of_locals; i++) { + if (type_of_locals_ptr[locals_ptr[i].runtime_index] & LOCAL_MOD_UNUSED) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Unused local variable '"); + p = strput(p, end, locals_ptr[i].ihe->name); + p = strput(p, end, "'"); + yywarn(buf); + type_of_locals_ptr[locals_ptr[i].runtime_index] &= ~LOCAL_MOD_UNUSED; + } + } + } + *((unsigned short *)mem_block[A_ARGUMENT_INDEX].block + num) = + mem_block[A_ARGUMENT_TYPES].current_size / sizeof(unsigned short); + add_to_mem_block(A_ARGUMENT_TYPES, (char *)type_of_locals_ptr, + num_arg * sizeof(*type_of_locals_ptr)); +#ifndef SUPPRESS_ARGUMENT_WARNINGS + if (flags & FUNC_PROTOTYPE) { + int i; + + for (i = 0; i < num_arg; i++) { + if (*locals_ptr[i].ihe->name) + type_of_locals_ptr[i] |= LOCAL_MOD_UNUSED; + } + } +#endif + } + return newindex; +} + +int define_variable (char * name, int type) +{ + variable_t *dummy; + int n; + ident_hash_elem_t *ihe; + + n = (mem_block[A_VAR_TEMP].current_size / sizeof(variable_t)); + + ihe = find_or_add_ident(name, FOA_GLOBAL_SCOPE); + if (ihe->dn.global_num == -1) { + ihe->sem_value++; + ihe->dn.global_num = n; + + if (n >= CFG_MAX_GLOBAL_VARIABLES) { + yyerror("Too many global variables"); + } + } else { + char buf[CFG_MAX_GLOBAL_VARIABLES]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Redeclaration of global variable '"); + p = strput(p, end, ihe->name); + p = strput(p, end, "'."); + yywarn(buf); + + if (VAR_TEMP(ihe->dn.global_num)->type & DECL_NOMASK) { + char buf[CFG_MAX_GLOBAL_VARIABLES]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Illegal to redefine 'nomask' variable \""); + p = strput(p, end, name); + p = strput(p, end, "\""); + yyerror(buf); + } + /* Okay, the nasty idiots have two variables of the same name in + the same object. This causes headaches for save_object(). + To keep save_object sane, we need to make one static */ + if (!(VAR_TEMP(ihe->dn.global_num)->type & DECL_NOSAVE)) + type |= DECL_NOSAVE; + + /* hidden variables don't cause variables that are visible to become + invisible; we only add them above (in the !hide case) for better + error messages */ + if (!(type & DECL_HIDDEN)) + ihe->dn.global_num = n; + } + + dummy = (variable_t *)allocate_in_mem_block(A_VAR_TEMP, sizeof(variable_t)); + dummy->name = name; + dummy->type = type; + + return n; +} + +int define_new_variable (char * name, int type) { + int n; + unsigned short *tp; + char **np; + + var_defined = 1; + name = make_shared_string(name); + n = define_variable(name, type); + np = (char **)allocate_in_mem_block(A_VAR_NAME, sizeof(char*)); + *np = name; + tp = (unsigned short *)allocate_in_mem_block(A_VAR_TYPE, sizeof(unsigned short)); + *tp = type; + + return n; +} + +parse_node_t *check_refs (int num, parse_node_t * elist, parse_node_t * pn) { + int tmp = num; + + elist = elist->r.expr; + + while (elist) { + if (IS_NODE(elist->v.expr, NODE_UNARY_OP_1, F_MAKE_REF)) + tmp--; + elist = elist->r.expr; + } + DEBUG_CHECK(tmp < 0, "Oops, found more refs than is possible!\n"); + if (tmp) { + /* if we didn't find all the refs at the top level of the argument + * list, then at least one is buried; i.e. something illegal like + * func(x = ref y), func(ref y + 1), etc + */ + yyerror("Illegal use of ref"); + } + if (num) { + parse_node_t *ret; + + CREATE_UNARY_OP_1(ret, F_KILL_REFS, pn->type, pn, num); + return ret; + } + return pn; +} + +/* we know here that x has two modifiers, and hidden isn't one of them */ +int decl_fix (int x) { + int rest = x & ~DECL_ACCESS; + +#ifndef SENSIBLE_MODIFIERS + if (x & DECL_VISIBLE) + return rest | DECL_VISIBLE; +#endif + if (x & DECL_PRIVATE) + return rest | DECL_PRIVATE; + + /* only possibility left is 'public protected' */ + return rest | DECL_PROTECTED; +} + +const char *compiler_type_names[] = {"unknown", "mixed", "void", "void", + "int", "string", "object", "mapping", + "function", "float", "buffer" }; + +/* This routine has the semantics of strput(); see comments in simulate.c */ + +char *get_type_modifiers (char * where, char * end, int type) +{ +#ifdef SENSIBLE_MODIFIERS + if (type & DECL_HIDDEN) + where = strput(where, end, "hidden "); + if (type & DECL_PRIVATE) + where = strput(where, end, "private "); + if (type & DECL_PROTECTED) + where = strput(where, end, "protected "); + if (type & DECL_NOSAVE) + where = strput(where, end, "nosave "); +#else + if (type & DECL_HIDDEN) + where = strput(where, end, "hidden "); + if (type & DECL_VISIBLE) + where = strput(where, end, "public "); + if (type & DECL_PRIVATE) + where = strput(where, end, "private "); + if (type & DECL_PROTECTED) + where = strput(where, end, "static "); +#endif + /* no output for public */ + if (type & DECL_NOMASK) + where = strput(where, end, "nomask "); + if (type & FUNC_VARARGS) + where = strput(where, end, "varargs "); + + return where; +} + +char *get_type_name (char * where, char * end, int type) +{ + int pointer = 0; + + where = get_type_modifiers(where, end, type); + type &= ~DECL_MODS; + if (type & TYPE_MOD_ARRAY) { + pointer = 1; + type &= ~TYPE_MOD_ARRAY; + } + if (type & TYPE_MOD_CLASS) { + where = strput(where, end, "class "); + /* we're sometimes called from outside the compiler * / + if (current_file) + where = strput(where, end, PROG_STRING(CLASS(type & ~TYPE_MOD_CLASS)->name)); + and that just doesn't work */ + } else { + DEBUG_CHECK(type >= sizeof compiler_type_names / sizeof compiler_type_names[0], "Bad type\n"); + where = strput(where, end, compiler_type_names[type]); + } + where = strput(where, end, " "); +#ifdef ARRAY_RESERVED_WORD + if (pointer) { + /* use just "array" instead of "mixed array" */ + if (type == TYPE_ANY) { + where -= strlen(compiler_type_names[type]) + 1; + } + where = strput(where, end, "array "); + } +#else + if (pointer) + where = strput(where, end, "* "); +#endif + return where; +} + +#define STRING_HASH(var,str) \ + var = (long)str ^ (long)str >> 16; \ + var = (var ^ var >> 8) & 0xff; + +short store_prog_string (const char * str) +{ + short i, next, *next_tab, *idxp; + char **p; + unsigned char hash, mask, *tagp; + + str = make_shared_string(str); + STRING_HASH(hash, str); + idxp = &string_idx[hash]; + + /* string_tags is a big bit-array, so find correct bit */ + mask = 1 << (hash & 7); + tagp = &string_tags[hash >> 3]; + + p = (char **)&PROG_STRING(0); + next_tab = (short *) mem_block[A_STRING_NEXT].block; + + if (*tagp & mask) { + /* search hash chain to see if it's there */ + for (i = *idxp; i >= 0; i = next_tab[i]) { + if (p[i] == str) { + free_string(str); /* needed as string is only free'ed + * once. */ + ((short *) mem_block[A_STRING_REFS].block)[i]++; + return i; + } + } + next = *idxp; + } else { + *tagp |= mask; + next = -1; + } + + /* + * New string, add to table + */ + + if (freed_string >= 0) { + /* reuse freed string */ + int top; + + i = freed_string; + + top = mem_block[A_STRINGS].current_size / sizeof str; + for (freed_string++; freed_string < top; freed_string++) { + if (p[freed_string] == 0) + break; + } + if (freed_string >= top) + freed_string = -1; + } else { + /* grow by one element. */ + allocate_in_mem_block(A_STRINGS, sizeof str); + allocate_in_mem_block(A_STRING_NEXT, sizeof(short)); + allocate_in_mem_block(A_STRING_REFS, sizeof(short)); + /* test if number of strings isn't too large ? */ + i = mem_block[A_STRINGS].current_size / sizeof str - 1; + } + PROG_STRING(i) = str; + ((short *) mem_block[A_STRING_NEXT].block)[i] = next; + ((short *) mem_block[A_STRING_REFS].block)[i] = 1; + *idxp = i; + return i; +} + +void free_prog_string (short num) +{ + short i, prv, *next_tab, top, *idxp; + char **p, *str; + unsigned char hash, mask; + + top = mem_block[A_STRINGS].current_size / sizeof(char *) - 1; + if (num < 0 || num > top) { + yyerror("free_prog_string: index out of range.\n"); + return; + } + if (--((short *) mem_block[A_STRING_REFS].block)[num] >= 1) + return; + + p = (char **) mem_block[A_STRINGS].block; + next_tab = (short *) mem_block[A_STRING_NEXT].block; + + str = p[num]; + STRING_HASH(hash, str); + idxp = &string_idx[hash]; + + for (prv = -1, i = *idxp; i != num; prv = i, i = next_tab[i]) { + if (i == -1) { + yyerror("free_prog_string: string not in prog table.\n"); + return; + } + } + + if (prv == -1) { /* string is head of list */ + *idxp = next_tab[i]; + if (*idxp == -1) { + /* clear tag bit since hash chain now empty */ + mask = 1 << (hash & 7); + string_tags[hash >> 3] &= ~mask; + } + } else { /* easy unlink */ + next_tab[prv] = next_tab[i]; + } + + free_string(str); /* important */ + p[i] = 0; + if (i != top) { + if (i < freed_string || freed_string == -1) + freed_string = i; + } else { + /* shrink table */ + mem_block[A_STRINGS].current_size -= sizeof str; + mem_block[A_STRING_REFS].current_size -= sizeof(short); + mem_block[A_STRING_NEXT].current_size -= sizeof(short); + } +} + +int validate_function_call (int f, parse_node_t * args) +{ + function_t *funp = FUNCTION_DEF(f); + int funflags = FUNCTION_FLAGS(f); + int num_arg = ( args ? args->kind : 0 ); + int num_var = 0; + parse_node_t *pn = args; + unsigned short *arg_types = 0; + program_t *prog; + + while (pn) { + if (pn->type & 1) num_var++; + pn = pn->r.expr; + } + + /* Make sure it isn't private */ + if (funflags & DECL_HIDDEN) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Illegal to call inherited private function '"); + p = strput(p, end, funp->funcname); + p = strput(p, end, "'"); + yyerror(buf); + } + + /* + * Verify that the function has been defined already. + */ + if (exact_types) { + if ((funflags & FUNC_UNDEFINED)) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Function "); + p = strput(p, end, funp->funcname); + p = strput(p, end, " undefined"); + yyerror(buf); + } + /* + * Check number of arguments. + */ + if (!(funflags & FUNC_VARARGS) && + (funflags & FUNC_STRICT_TYPES)) { + char buff[256]; + char *end = EndOf(buff); + char *p; + + if (num_var) { + p = strput(buff, end, "Illegal to pass a variable number of arguments to non-varargs function "); + p = strput(p, end, funp->funcname); + p = strput(p, end, "\n"); + yyerror(buff); + } else if (funp->num_arg != num_arg) { + p = strput(buff, end, "Wrong number of arguments to "); + p = strput(p, end, funp->funcname); + p = strput(p, end, "\n Expected: "); + p = strput_int(p, end, funp->num_arg); + p = strput(p, end, " Got: "); + p = strput_int(p, end, num_arg); + yyerror(buff); + } + } + /* + * Check the argument types. + */ + if ((prog = FUNCTION_PROG(f))) { + int which = (FUNCTION_TEMP(f)->u.func - prog->function_table); + if (prog->type_start) { + int start = prog->type_start[which]; + if (start != INDEX_START_NONE) + arg_types = prog->argument_types + start; + } + } else { + int which = FUNCTION_TEMP(f)->u.index; + int start = *((unsigned short *)mem_block[A_ARGUMENT_INDEX].block + which); + if (start != INDEX_START_NONE) + arg_types = (unsigned short *)mem_block[A_ARGUMENT_TYPES].block + start; + } + + if (arg_types) { + int arg, i, tmp; + parse_node_t *enode = args; + int fnarg = funp->num_arg; + + if (funflags & FUNC_TRUE_VARARGS) + fnarg--; + + for (i = 0; (unsigned) i < fnarg && i < num_arg; i++) { + if (enode->type & 1) break; + tmp = enode->v.expr->type; + + arg = arg_types[i]; + if (prog) + fix_class_type(&arg, prog); + + if (!compatible_types(tmp, arg)) { + char buff[256]; + char *end = EndOf(buff); + char *p; + + p = strput(buff, end, "Bad type for argument "); + p = strput_int(p, end, i+1); + p = strput(p, end, " of "); + p = strput(p, end, funp->funcname); + p = strput(p, end, " "); + p = get_two_types(p, end, arg_types[i], tmp); + yyerror(buff); + } + enode = enode->r.expr; + } + } + } + return funp->type; +} + +parse_node_t * +promote_to_float (parse_node_t * node) { + parse_node_t *expr; + if (node->kind == NODE_NUMBER) { + node->kind = NODE_REAL; + node->v.real = node->v.number; + return node; + } + expr = new_node(); + expr->kind = NODE_EFUN; + expr->v.number = predefs[to_float_efun].token; + expr->type = TYPE_REAL; + expr->l.number = 1; + expr->r.expr = new_node_no_line(); + expr->r.expr->kind = 1; + expr->r.expr->l.expr = expr->r.expr; + expr->r.expr->type = 0; + expr->r.expr->v.expr = node; + expr->r.expr->r.expr = 0; + return expr; +} + +parse_node_t * +promote_to_int (parse_node_t * node) { + parse_node_t *expr; + if (node->kind == NODE_REAL) { + node->kind = NODE_NUMBER; + node->v.number = node->v.real; + return node; + } + expr = new_node(); + expr->kind = NODE_EFUN; + expr->v.number = predefs[to_int_efun].token; + expr->type = TYPE_NUMBER; + expr->l.number = 1; + expr->r.expr = new_node_no_line(); + expr->r.expr->kind = 1; + expr->r.expr->l.expr = expr->r.expr; + expr->r.expr->type = 0; + expr->r.expr->v.expr = node; + expr->r.expr->r.expr = 0; + return expr; +} + +int convert_type (int type){ + switch(type & (~DECL_MODS)) { + case TYPE_UNKNOWN: + case TYPE_NOVALUE: + case TYPE_VOID: + return T_INVALID; + case TYPE_ANY: + return T_ANY; + case TYPE_NUMBER: + return T_NUMBER; + case TYPE_STRING: + return T_STRING; + case TYPE_OBJECT: + return T_OBJECT; + case TYPE_MAPPING: + return T_MAPPING; + case TYPE_FUNCTION: + return T_FUNCTION; + case TYPE_REAL: + return T_REAL; + case TYPE_BUFFER: + return T_BUFFER; + default: + if(type & TYPE_MOD_ARRAY) + return T_ARRAY; + else if(type & TYPE_MOD_CLASS) + return T_CLASS; + else + return T_ANY; //we probably forgot one then, should we get here + } +} + +parse_node_t *add_type_check (parse_node_t * node, int intype) { + parse_node_t *expr, *expr2; + int type; + + if(!(pragmas & PRAGMA_STRICT_TYPES)) + return node; + + switch(intype & (~DECL_MODS)) { + case 0: + case 3: + //error situation, don't bother + return node; + case TYPE_NUMBER: + type = T_NUMBER; + break; + case TYPE_STRING: + type = T_STRING; + break; + case TYPE_OBJECT: + type = T_OBJECT; + break; + case TYPE_MAPPING: + type = T_MAPPING; + break; + case TYPE_FUNCTION: + type = T_FUNCTION; + break; + case TYPE_REAL: + type = T_REAL; + break; + case TYPE_BUFFER: + type = T_BUFFER; + break; + default: + if(intype & TYPE_MOD_ARRAY) + type = T_ARRAY; + else if(intype & TYPE_MOD_CLASS) + type = T_CLASS; + else + fatal("unknown type %d in type check\n", intype); + } + + CREATE_NUMBER(expr2, type); + CREATE_BINARY_OP(expr, F_TYPE_CHECK, intype, node, expr2); + return expr; +} + + +parse_node_t *do_promotions (parse_node_t * node, int type) { + if (type == TYPE_REAL) { + if (node->type == TYPE_NUMBER || node->kind == NODE_NUMBER) + return promote_to_float(node); + } + if (type == TYPE_NUMBER && node->type == TYPE_REAL) + return promote_to_int(node); + if(type != TYPE_ANY && type != node->type) + return add_type_check(node, type); + + return node; +} + +/* Take a NODE_CALL, and discard the call, preserving only the args with + side effects */ +parse_node_t * +throw_away_call (parse_node_t * pn) { + parse_node_t *enode; + parse_node_t *ret = 0; + parse_node_t *arg; + + enode = pn->r.expr; + while (enode) { + arg = insert_pop_value(enode->v.expr); + if (arg) { + /* woops. Don't lose the side effect. */ + if (ret) { + parse_node_t *tmp; + CREATE_STATEMENTS(tmp, ret, arg); + ret = tmp; + } else { + ret = arg; + } + } + enode = enode->r.expr; + } + return ret; +} + +parse_node_t * +throw_away_mapping (parse_node_t * pn) { + parse_node_t *enode; + parse_node_t *ret = 0; + parse_node_t *arg; + + enode = pn->r.expr; + while (enode) { + arg = insert_pop_value(enode->v.expr->l.expr); + if (arg) { + /* woops. Don't lose the side effect. */ + if (ret) { + parse_node_t *tmp; + CREATE_STATEMENTS(tmp, ret, arg); + ret = tmp; + } else { + ret = arg; + } + } + arg = insert_pop_value(enode->v.expr->r.expr); + if (arg) { + /* woops. Don't lose the side effect. */ + if (ret) { + parse_node_t *tmp; + CREATE_STATEMENTS(tmp, ret, arg); + ret = tmp; + } else { + ret = arg; + } + } + enode = enode->r.expr; + } + return ret; +} + +parse_node_t * +validate_efun_call (int f, parse_node_t * args) { + int num = args->v.number; + int min_arg, max_arg, def, *argp; + int num_var = 0; + parse_node_t *pn = args->r.expr; + + while (pn) { + if (pn->type & 1) num_var++; + pn = pn->r.expr; + } + + if (f != -1) { + /* should this move out of here? */ + switch (predefs[f].token) { +#ifdef F_SIZEOF + case F_SIZEOF: + /* Obscene crap like: sizeof( ({ 1, i++, x + 1, foo() }) ) + * -> i++, foo(), 4 + */ + if (!pn && num == 1 && + IS_NODE(args->r.expr->v.expr, NODE_CALL, F_AGGREGATE)) { + parse_node_t *repl, *ret, *node; + + CREATE_NUMBER(node, args->r.expr->v.expr->l.number); + ret = throw_away_call(args->r.expr->v.expr); + if (ret) { + CREATE_TWO_VALUES(repl, TYPE_NUMBER, ret, node); + return repl; + } else + return node; + } +#endif + } + + min_arg = predefs[f].min_args; + max_arg = predefs[f].max_args; + + def = predefs[f].Default; + if (!num_var && def != DEFAULT_NONE && num == min_arg -1) { + parse_node_t *tmp; + tmp = new_node_no_line(); + tmp->r.expr = 0; + tmp->type = 0; + args->l.expr->r.expr = tmp; + if (def == DEFAULT_THIS_OBJECT) { + tmp->v.expr = new_node_no_line(); + tmp->v.expr->kind = NODE_EFUN; + tmp->v.expr->v.number = predefs[this_efun].token; + tmp->v.expr->l.number = 0; + tmp->v.expr->type = TYPE_ANY; + tmp->v.expr->r.expr = 0; + } else { + CREATE_NUMBER(tmp->v.expr, def); + } + args->v.number++; + num++; + } else if (num_var && max_arg != -1) { + char buff[256]; + char *end = EndOf(buff); + char *p; + + p = strput(buff, end, "Illegal to pass variable number of arguments to non-varargs efun "); + p = strput(p, end, predefs[f].word); + yyerror(buff); + CREATE_ERROR(args); + return args; + } else if ((num - num_var) < min_arg) { + char buff[256]; + char *end = EndOf(buff); + char *p; + + p = strput(buff, end, "Too few arguments to "); + p = strput(p, end, predefs[f].word); + CREATE_ERROR(args); + yyerror(buff); + return args; + } else if (num > max_arg && max_arg != -1) { + char buff[256]; + char *end = EndOf(buff); + char *p; + + p = strput(buff, end, "Too many arguments to "); + p = strput(p, end, predefs[f].word); + yyerror(buff); + CREATE_ERROR(args); + return args; + } + if (max_arg != -1 && exact_types) { + /* + * Now check all types of arguments to efuns. + */ + int i, argn, tmp; + char buff[256]; + char *end = EndOf(buff); + char *p; + parse_node_t *enode = args; + argp = &efun_arg_types[predefs[f].arg_index]; + + for (argn = 0; argn < num; argn++) { + enode = enode->r.expr; + if (enode->type & 1) break; + /* this can happen for default args */ + if (!enode->v.expr) break; + tmp = enode->v.expr->type; + for (i=0; !compatible_types(tmp, argp[i]) && argp[i] != 0; i++) + ; + + if (argp[i] == 0) { + p = strput(buff, end, "Bad argument "); + p = strput_int(p, end, argn + 1); + p = strput(p, end, " to efun "); + p = strput(p, end, predefs[f].word); + p = strput(p, end, "()"); + yyerror(buff); + } else { + /* check for (int) -> (float) promotion */ + if (tmp == TYPE_NUMBER && argp[i] == TYPE_REAL) { + for (i++; argp[i] && argp[i] != TYPE_NUMBER; i++) + ; + if (!argp[i]) + enode->v.expr = promote_to_float(enode->v.expr); + } + else if (tmp == TYPE_REAL && argp[i] == TYPE_NUMBER) { + for (i++; argp[i] && argp[i] != TYPE_REAL; i++) + ; + if (!argp[i]) + enode->v.expr = promote_to_int(enode->v.expr); + } + } + while (argp[i] != 0) + i++; + argp += i + 1; + } + } + args->l.number = num; + args->v.number = predefs[f].token; + args->type = predefs[f].ret_type; + if (args->type == TYPE_NOVALUE) { + args->v.number += NOVALUE_USED_FLAG; + args->type = TYPE_VOID; + } + args->kind = NODE_EFUN; + } else { + CREATE_ERROR(args); + } + return args; +} + +void yyerror (const char * str) +{ + extern int num_parse_error; + + function_context.num_parameters = -1; + if (num_parse_error > 5) { + lex_fatal = 1; + return; + } + smart_log(current_file, current_line, str, 0); +#ifdef PACKAGE_MUDLIB_STATS + add_errors_for_file (current_file, 1); +#endif + num_parse_error++; +} + +void yywarn (const char * str) { + if (!(pragmas & PRAGMA_WARNINGS)) return; + + smart_log(current_file, current_line, str, 1); +} + +/* + * Compile an LPC file. + */ +program_t * +compile_file (int f, char * name) { + int yyparse (void); + static int guard = 0; + program_t *prog; + extern int func_present; + + /* The parser isn't reentrant. On a few occasions (compile + * errors, valid_override) LPC code is called during compilation, + * causing the possibility of arriving here again. + */ + if (guard || current_file) { + error("Object cannot be loaded during compilation.\n"); + } + guard = 1; + + prolog(f, name); + func_present = 0; + yyparse(); + prog = epilog(); + + guard = 0; + return prog; +} + +int get_id_number() { + static int current_id_number = 1; + return current_id_number++; +} + +INLINE_STATIC void copy_in (int which, char ** start) { + char *block; + int size; + + size = mem_block[which].current_size; + if (!size) return; + + block = mem_block[which].block; + memcpy(*start, block, size); + + *start += align(size); +} + +static int compare_funcs (void *x, void *y) { + char *n1 = FUNC(*(unsigned short *)x)->funcname; + char *n2 = FUNC(*(unsigned short *)y)->funcname; + int sp1, sp2; + + /* make sure #global_init# stays last; also shuffle empty entries to + * the end so we can delete them easily. + */ + if (n1[0] == '#') + sp1 = 1; + else if (FUNC(*(unsigned short *)x)->address == ADDRESS_MAX) + sp1 = 2; + else + sp1 = 0; + + if (n2[0] == '#') + sp2 = 1; + else if (FUNC(*(unsigned short *)y)->address == ADDRESS_MAX) + sp2 = 2; + else + sp2 = 0; + + if (sp1 < sp2) + return -1; + if (sp1 > sp2) + return 1; + + if (n1 < n2) + return -1; + if (n1 > n2) + return 1; + + return 0; +} + +static void handle_functions() { + int num_func, total_func; + int i; + compiler_temp_t *cur_def; + int new_index, num_def; + int final_index; + inherit_t *inheritp; + + /* Pass one: Sort the compiler functions first */ + + num_func = total_func = mem_block[A_FUNCTIONS].current_size / sizeof (function_t); + if (num_func) { + func_index_map = CALLOCATE(num_func, unsigned short, + TAG_TEMPORARY, "handle_functions"); + comp_sorted_funcs = CALLOCATE(num_func, unsigned short, + TAG_TEMPORARY, "handle_functions"); + + i = num_func; + while (i--) func_index_map[i] = i; + + quickSort(func_index_map, num_func, sizeof(unsigned short), + compare_funcs); + + i = num_func; + while (i--) + comp_sorted_funcs[func_index_map[i]] = i; + + while (num_func && + FUNC(func_index_map[num_func-1])->address == ADDRESS_MAX) + num_func--; + } + + if (NUM_INHERITS) { + program_t *inherited_prog; + + inheritp = INHERIT(NUM_INHERITS - 1); + + inherited_prog = inheritp->prog; + + comp_last_inherited = inheritp->function_index_offset + + inherited_prog->last_inherited + + inherited_prog->num_functions_defined; + + if (inherited_prog->num_functions_defined && + inherited_prog->function_table[inherited_prog->num_functions_defined -1].funcname[0] == APPLY___INIT_SPECIAL_CHAR) comp_last_inherited--; + } else comp_last_inherited = 0; + + /* Pass one: We allocate space for the comp_def_index_map */ + /* and prog_flags, and fill them out in sequential order */ + + num_def = mem_block[A_FUNCTION_DEFS].current_size/sizeof(compiler_temp_t); + if (num_def) { + comp_def_index_map = CALLOCATE(num_def, unsigned short, + TAG_TEMPORARY, "handle functions"); + prog_flags = CALLOCATE(comp_last_inherited + total_func, unsigned short, + TAG_TEMPORARY, "handle_functions"); + + for (i = 0; i < num_def; i++) { + cur_def = FUNCTION_TEMP(i); + + if (cur_def->flags & FUNC_INHERITED) { + final_index = INHERIT(cur_def->offset)->function_index_offset + + cur_def->function_index_offset; + } else { + final_index = comp_last_inherited + + comp_sorted_funcs[cur_def->u.index]; + } + if (cur_def->flags & FUNC_ALIAS) { + fatal("Aliasing difficulties!\n"); + exit(1); + } + + comp_def_index_map[i] = final_index; + prog_flags[final_index] = cur_def->flags; + + while ((cur_def = cur_def->next)) { + if (cur_def->flags & FUNC_INHERITED) { + new_index = INHERIT(cur_def->offset)->function_index_offset + + cur_def->function_index_offset; + } else { + new_index = comp_last_inherited + + comp_sorted_funcs[cur_def->u.index]; + } + /* We aren't worried about repeating new_indices */ + /* because it's all the same value */ + /* except the case where new_index is actually final_index */ + + if (new_index != final_index) { + prog_flags[new_index] = FUNC_ALIAS | final_index; + } + } + } + } + + if (total_func) + FREE((char *) comp_sorted_funcs); +} + +/* + * The program has been compiled. Prepare a 'program_t' to be returned. + */ +static program_t *epilog (void) { + int size, i, lnsz, lnoff; + char *p; + int num_func; + ident_hash_elem_t *ihe; + program_t *prog; + compiler_temp_t *fundefp, *nextdefp; + + if (num_parse_error > 0 || inherit_file) { + /* don't print these; they can be wrong, since we didn't parse the + entire file */ + if (pragmas & PRAGMA_WARNINGS) + remove_overload_warnings(0); + clean_parser(); + end_new_file(); + free_string(current_file); + current_file = 0; + return 0; + } + + if (pragmas & PRAGMA_WARNINGS) + show_overload_warnings(); + + /* + * Define the #global_init# function, but only if there was any code + * to initialize. + */ + UPDATE_PROGRAM_SIZE; + + if (comp_trees[TREE_INIT]) { + parse_node_t *pn, *newnode; + int fun; + /* end the __INIT function */ + CREATE_RETURN(pn, 0); + newnode = comp_trees[TREE_INIT]; + CREATE_TWO_VALUES(comp_trees[TREE_INIT], 0, + newnode, pn); + fun = define_new_function(APPLY___INIT, 0, 0, + DECL_HIDDEN | FUNC_STRICT_TYPES, TYPE_VOID); + pn = new_node_no_line(); + pn->kind = NODE_FUNCTION; + pn->v.number = fun; + pn->l.number = 0; + pn->r.expr = comp_trees[TREE_INIT]; + comp_trees[TREE_INIT] = pn; + } + + /* Do stuff with functions first */ + /* calculate comp_last_inherited also */ + handle_functions(); + + /* generate the trees */ + + current_tree = TREE_MAIN; + generate(comp_trees[TREE_MAIN]); + + current_tree = TREE_INIT; + generate(comp_trees[TREE_INIT]); + + current_tree = TREE_MAIN; + + generate_final_program(0); + UPDATE_PROGRAM_SIZE; + + if (mem_block[0].current_size > ADDRESS_MAX) { + yyerror("Program too large"); + clean_parser(); + end_new_file(); + free_string(current_file); + current_file = 0; + return 0; + } + + generate_final_program(1); + + free_tree(); + + size = align(sizeof (program_t)); + + /* delete argument information if we're not saving it */ + if (!(pragmas & PRAGMA_SAVE_TYPES)) + mem_block[A_ARGUMENT_TYPES].current_size = 0; + if (!(mem_block[A_ARGUMENT_TYPES].current_size)) + mem_block[A_ARGUMENT_INDEX].current_size = 0; + + for (i=0; iaddress == ADDRESS_MAX) + num_func--; + + size += align((num_func * sizeof(function_t))); /* A_FUNCTIONS */ + + /* function flags */ + size += align(((comp_last_inherited + num_func) * sizeof(unsigned short))); + + /* A_ARGUMENT_INDEX */ + if (mem_block[A_ARGUMENT_INDEX].current_size) + size += align(num_func * sizeof(unsigned short)); + + p = (char *)DXALLOC(size, TAG_PROGRAM, "epilog: 1"); + prog = (program_t *)p; + *prog = NULL_program; + prog->total_size = size; + prog->ref = 0; + prog->func_ref = 0; + ihe = lookup_ident("heart_beat"); + if (ihe && ihe->dn.function_num != -1) { + prog->heart_beat = comp_def_index_map[ihe->dn.function_num] + 1; + if (prog_flags && prog_flags[prog->heart_beat-1] & + (FUNC_PROTOTYPE|FUNC_UNDEFINED)) + prog->heart_beat = 0; + } else + prog->heart_beat = 0; + prog->filename = current_file; + + current_file = 0; + + total_num_prog_blocks++; + total_prog_block_size += size; + + /* Format is now: + * + */ + lnoff = 2 + (mem_block[A_FILE_INFO].current_size / sizeof(short)); + lnsz = lnoff * sizeof(short) + mem_block[A_LINENUMBERS].current_size; + + prog->file_info = (unsigned short *) DXALLOC(lnsz, TAG_LINENUMBERS + , "epilog"); + + prog->file_info[0] = (unsigned short)lnsz; + prog->file_info[1] = (unsigned short)lnoff; + + memcpy(((char*)&prog->file_info[2]), + mem_block[A_FILE_INFO].block, + mem_block[A_FILE_INFO].current_size); + + prog->line_info = (unsigned char *)(&prog->file_info[lnoff]); + memcpy(((char*)&prog->file_info[lnoff]), + mem_block[A_LINENUMBERS].block, + mem_block[A_LINENUMBERS].current_size); + + p += align(sizeof(program_t)); + prog->program = p; + prog->program_size = mem_block[A_PROGRAM].current_size; + copy_in(A_PROGRAM, &p); + + + /* copy the functions in */ + prog->last_inherited = comp_last_inherited; + prog->num_functions_defined = num_func; + + prog->function_table = (function_t *)p; + for (i = 0; i < num_func; i++) + prog->function_table[i] = *FUNC(func_index_map[i]); + + p += align(sizeof(function_t) * num_func); + + + prog->function_flags = (unsigned short *)p; + if (prog_flags) { + memcpy(p,prog_flags, + (comp_last_inherited + num_func) * sizeof(unsigned short)); + FREE((char *)prog_flags); + } + p += align(sizeof(unsigned short) * (comp_last_inherited + num_func)); + + if (mem_block[A_ARGUMENT_INDEX].current_size) { + unsigned short *dest; + + prog->argument_types = (unsigned short *)p; + copy_in(A_ARGUMENT_TYPES, &p); + + dest = prog->type_start = (unsigned short *)p; + i = num_func; + while (i--) + dest[i] = *((unsigned short *) mem_block[A_ARGUMENT_INDEX].block + + func_index_map[i]); + p += align(num_func * sizeof(unsigned short)); + } else { + prog->argument_types = 0; + prog->type_start = 0; + } + + prog->classes = (class_def_t *)p; + prog->num_classes = mem_block[A_CLASS_DEF].current_size / + sizeof (class_def_t); + copy_in(A_CLASS_DEF, &p); + + prog->class_members = (class_member_entry_t *)p; + copy_in(A_CLASS_MEMBER, &p); + + prog->strings = (char **)p; + prog->num_strings = mem_block[A_STRINGS].current_size / + sizeof (char *); + copy_in(A_STRINGS, &p); + + prog->num_variables_defined = mem_block[A_VAR_NAME].current_size / + sizeof (char *); + prog->num_variables_total = mem_block[A_VAR_TEMP].current_size / + sizeof (variable_t); + + prog->variable_table = (char **)p; + copy_in(A_VAR_NAME, &p); + prog->variable_types = (unsigned short *)p; + copy_in(A_VAR_TYPE, &p); + + prog->num_inherited = mem_block[A_INHERITS].current_size / + sizeof (inherit_t); + if (prog->num_inherited) { + prog->inherit = (inherit_t *)p; + copy_in(A_INHERITS, &p); + } else + prog->inherit = 0; + +#ifdef DEBUG + if (p - (char *)prog != size) { + fprintf(stderr, "Program size miscalculated for /%s.\n", prog->filename); + fprintf(stderr, "is: %i, expected: %i\n", p-(char *)prog, size); + } +#endif + + for (i = 0; i < mem_block[A_FUNCTION_DEFS].current_size / sizeof(*fundefp); i++) { + fundefp = FUNCTION_TEMP(i)->next; + while (fundefp) { + nextdefp = fundefp->next; + FREE((char *) fundefp); + fundefp = nextdefp; + } + } + + for (i=0; inum_inherited; i++) { + reference_prog (prog->inherit[i].prog, "inheritance"); + } + release_tree(); + uninitialize_parser(); + scratch_destroy(); + clean_up_locals(); + free_unused_identifiers(); + end_new_file(); + + return prog; +} + +/* + * Initialize the environment that the compiler needs. + */ +static void prolog (int f, char * name) { + int i; + + function_context.num_parameters = -1; + num_parse_error = 0; + global_modifiers = 0; + var_defined = 0; + + /* Initialize memory blocks where the result of the compilation + * will be stored. + */ + for (i=0; i < NUMAREAS; i++) { + mem_block[i].block = (char *)DXALLOC(START_BLOCK_SIZE, TAG_COMPILER, "prolog: 2"); + mem_block[i].current_size = 0; + mem_block[i].max_size = START_BLOCK_SIZE; + } + for (i = 0; i < NUMTREES; i++) { + comp_trees[i] = 0; + } + prog_flags = 0; + func_index_map = 0; + comp_def_index_map = 0; + + memset(string_tags, 0, sizeof(string_tags)); + freed_string = -1; + initialize_parser(); + + current_file = make_shared_string(name); + current_file_id = add_program_file(name, 1); + + /* + * if we've got a simul_efun object and we're not reloading it, make a copy + * of its class definitions in the object we're compiling now. + */ + if (simul_efun_ob && *simul_efun_ob->obname) + copy_structures(simul_efun_ob->prog); + + start_new_file(f); +} + +/* + * The program has errors, clean things up. + */ +static void clean_parser() { + int i, n; + function_t *funp; + compiler_temp_t *fundefp, *nextdefp; + + /* + * Free function stuff. + */ + for (i = 0; i < mem_block[A_FUNCTIONS].current_size / sizeof(function_t); i++) { + funp = FUNC(i); + if (funp->funcname) free_string(funp->funcname); + } + + for (i = 0; i < mem_block[A_FUNCTION_DEFS].current_size / + sizeof(compiler_temp_t); i++) { + fundefp = FUNCTION_TEMP(i)->next; + while (fundefp) { + nextdefp = fundefp->next; + FREE((char *) fundefp); + fundefp = nextdefp; + } + } + + n = mem_block[A_STRINGS].current_size / sizeof(char *); + for (i = 0; i < n; i++) { + free_string(*((char **)mem_block[A_STRINGS].block + i)); + } + n = mem_block[A_VAR_NAME].current_size / sizeof(char *); + for (i = 0; i < n; i++) { + free_string(*((char **)mem_block[A_VAR_NAME].block + i)); + } + + prog = 0; + for (i=0; ikind == NODE_DEFAULT) + return -1; + if ((*(parse_node_t **)c2)->kind == NODE_DEFAULT) + return 1; + + if ((*(parse_node_t **)c1)->r.number > (*(parse_node_t **)c2)->r.number) return 1; + if ((*(parse_node_t **)c1)->r.number < (*(parse_node_t **)c2)->r.number) return -1; + return 0; +} + +static int string_case_compare(void *c1, void *c2) { + int i1, i2; + const char *p1, *p2; + + if ((*(parse_node_t **)c1)->kind == NODE_DEFAULT) + return -1; + if ((*(parse_node_t **)c2)->kind == NODE_DEFAULT) + return 1; + + i1 = (*(parse_node_t **)c1)->r.number; + i2 = (*(parse_node_t **)c2)->r.number; + p1 = (i1 ? PROG_STRING(i1) : 0); + p2 = (i2 ? PROG_STRING(i2) : 0); + + return (p1 < p2)?-1:0; +} + +void prepare_cases (parse_node_t * pn, int start) { + parse_node_t **ce_start, **ce_end, **ce; + long end, last_key, this_key; + int direct = 1; + + ce_start = (parse_node_t **)&mem_block[A_CASES].block[start]; + end = mem_block[A_CASES].current_size; + ce_end = (parse_node_t **)&mem_block[A_CASES].block[end]; + + if (ce_start == ce_end) { + /* no cases */ + pn->v.expr = 0; + mem_block[A_CASES].current_size = start; + return; + } + + if (pn->kind == NODE_SWITCH_STRINGS) + quickSort((char *)ce_start, ce_end - ce_start, sizeof(parse_node_t *), + string_case_compare); + else + quickSort((char *)ce_start, ce_end - ce_start, sizeof(parse_node_t *), + case_compare); + + ce = ce_start; + if ((*ce)->kind == NODE_DEFAULT) { + if (ce + 1 == ce_end) { + /* only a default */ + pn->v.expr = *ce; + (*ce)->l.expr = 0; + mem_block[A_CASES].current_size = start; + return; + } + ce++; + (*(ce-1))->l.expr = *ce; + } + if ((*ce)->v.expr) { + last_key = (*ce)->v.expr->r.number; + direct = 0; + } else + last_key = (*ce)->r.number; + ce++; + while (ce < ce_end) { + this_key = (*ce)->r.number; + if (pn->kind == NODE_SWITCH_RANGES && this_key <= last_key) { + char buf[1024]; + char *end = EndOf(buf); + char *p; + const char *f1, *f2; + int fi1, fi2; + int l1, l2; + + /* make sure line numbers exist for the cases */ + save_file_info(current_file_id, current_line - current_line_saved); + current_line_saved = current_line; + + translate_absolute_line((*ce)->line, + (unsigned short *)mem_block[A_FILE_INFO].block, + &fi1, &l1); + translate_absolute_line((*(ce-1))->line, + (unsigned short *)mem_block[A_FILE_INFO].block, + &fi2, &l2); + f1 = PROG_STRING(fi1 - 1); + f2 = PROG_STRING(fi2 - 1); + + p = strput(buf, end, "Overlapping cases: "); + if (f1) { + p = strput(p, end, f1); + p = strput(p, end, ":"); + } else + p = strput(p, end, "line "); + p = strput_int(p, end, l1); + p = strput(p, end, " and "); + if (f2) { + p = strput(p, end, f2); + p = strput(p, end, ":"); + } else + p = strput(p, end, "line "); + p = strput_int(p, end, l2); + p = strput(p, end, "."); + yyerror(buf); + } + (*(ce-1))->l.expr = *ce; + if ((*ce)->v.expr) { + last_key = (*ce)->v.expr->r.number; + direct = 0; + } else { + if (last_key + 1 != this_key) direct = 0; + last_key = this_key; + } + ce++; + } + (*(ce_end-1))->l.expr = 0; + if (direct && pn->kind == NODE_SWITCH_NUMBERS) + pn->kind = NODE_SWITCH_DIRECT; + pn->v.expr = *(ce_start); + mem_block[A_CASES].current_size = start; +} + +void +save_file_info (int file_id, int lines) { + short fi[2]; + + fi[0] = lines; + fi[1] = file_id; + add_to_mem_block(A_FILE_INFO, (char *)&fi[0], sizeof(fi)); +} + +int +add_program_file (char * name, int top) { + if (!top) + add_to_mem_block(A_INCLUDES, name, strlen(name)+1); + return store_prog_string(name) + 1; +} + + + + + + + diff --git a/fluffos-2.23-ds03/compiler.h b/fluffos-2.23-ds03/compiler.h new file mode 100644 index 0000000..6c481e1 --- /dev/null +++ b/fluffos-2.23-ds03/compiler.h @@ -0,0 +1,295 @@ +#ifndef COMPILER_H +#define COMPILER_H + +#include "trees.h" +#include "lex.h" +#include "program.h" + +#define _YACC_ + +#define YYMAXDEPTH 600 + +/* + * Information for allocating a block that can grow dynamically + * using realloc. That means that no pointers should be kept into such + * an area, as it might be moved. + */ + +typedef struct { + char *block; + int current_size; + int max_size; +} mem_block_t; + +#define START_BLOCK_SIZE 4096 + +/* NUMPAREAS ares are saved with the program code after compilation, + * the rest are only temporary. + */ +#define A_PROGRAM 0 /* executable code */ +#define A_FUNCTIONS 1 +#define A_STRINGS 2 /* table of strings */ +#define A_VAR_NAME 3 +#define A_VAR_TYPE 4 +#define A_LINENUMBERS 5 /* linenumber information */ +#define A_FILE_INFO 6 /* start of file line nos */ +#define A_INHERITS 7 /* table of inherited progs */ +#define A_CLASS_DEF 8 +#define A_CLASS_MEMBER 9 +#define A_ARGUMENT_TYPES 10 /* */ +#define A_ARGUMENT_INDEX 11 /* */ +#define NUMPAREAS 12 +#define A_CASES 13 /* keep track of cases */ +#define A_STRING_NEXT 14 /* next prog string in hash chain */ +#define A_STRING_REFS 15 /* reference count of prog string */ +#define A_INCLUDES 16 /* list of included files */ +#define A_FUNCTIONALS 17 +#define A_FUNCTION_DEFS 18 +#define A_VAR_TEMP 19 /* table of variables */ +#define NUMAREAS 20 + +#define TREE_MAIN 0 +#define TREE_INIT 1 +#define NUMTREES 2 + +#define CURRENT_PROGRAM_SIZE (prog_code - mem_block[A_PROGRAM].block) +#define UPDATE_PROGRAM_SIZE mem_block[A_PROGRAM].current_size = CURRENT_PROGRAM_SIZE + +/* + * Types available. The number '0' is valid as any type. These types + * are only used by the compiler, when type checks are enabled. Compare with + * the run-time types, named T_ interpret.h. + */ + +#define TYPE_UNKNOWN 0 /* This type must be casted */ +#define TYPE_ANY 1 /* Will match any type */ +#define TYPE_NOVALUE 2 +#define TYPE_VOID 3 +#define TYPE_NUMBER 4 +#define TYPE_STRING 5 +#define TYPE_OBJECT 6 +#define TYPE_MAPPING 7 +#define TYPE_FUNCTION 8 +#define TYPE_REAL 9 +#define TYPE_BUFFER 10 +#define TYPE_MASK 0xf + +typedef struct { + int runtime_index; + ident_hash_elem_t *ihe; +} local_info_t; + +extern mem_block_t mem_block[NUMAREAS]; +extern const char *compiler_type_names[]; + +#define LOOP_CONTEXT 0x1 +#define SWITCH_CONTEXT 0x2 +#define SWITCH_STRINGS 0x4 +#define SWITCH_NUMBERS 0x8 +#define SWITCH_DEFAULT 0x10 +#define SWITCH_RANGES 0x20 +#define SWITCH_NOT_EMPTY 0x40 +#define LOOP_FOREACH 0x80 +#define SPECIAL_CONTEXT 0x100 +#define ARG_LIST 0x200 + + +typedef struct function_context_s { + parse_node_t *values_list; + short bindable; + short num_parameters; + short num_locals; + struct function_context_s *parent; +} function_context_t; + +extern function_context_t *current_function_context; +extern int var_defined; +extern parse_node_t *comp_trees[NUMTREES]; +extern unsigned short *comp_def_index_map; +extern unsigned short *func_index_map; + +typedef struct compiler_temp_t { + unsigned short flags; + unsigned short offset; + unsigned short function_index_offset; + struct program_s *prog; /* inherited if nonzero */ + union { + function_t *func; + long index; + } u; + struct compiler_temp_t *next; +} compiler_temp_t; + +/* + * Some good macros to have. + */ + +#define IS_CLASS(t) ((t & (TYPE_MOD_ARRAY | TYPE_MOD_CLASS)) == TYPE_MOD_CLASS) +#define CLASS_IDX(t) (t & ~(DECL_MODS | TYPE_MOD_CLASS)) + +#define COMP_TYPE(e, t) (!(e & (TYPE_MOD_ARRAY | TYPE_MOD_CLASS)) \ + && (compatible[(e & ~DECL_MODS)] & (1 << (t)))) +#define IS_TYPE(e, t) (!(e & (TYPE_MOD_ARRAY | TYPE_MOD_CLASS)) \ + && (is_type[(e & ~DECL_MODS)] & (1 << (t)))) + +#define FUNCTION_TEMP(n) ((compiler_temp_t *)mem_block[A_FUNCTION_DEFS].block + (n)) +#define FUNCTION_NEXT(n) (FUNCTION_TEMP(n)->next) +/* function_t from A_FUNCTIONS index */ +#define FUNC(n) ((function_t *)mem_block[A_FUNCTIONS].block + (n)) +/* program for inherited entry from full function index */ +#define FUNCTION_PROG(n) (FUNCTION_TEMP(n)->prog) +#define FUNCTION_ALIAS(n) (FUNCTION_TEMP(n)->alias_for) +/* function_t from full function index */ +#define FUNCTION_DEF(n) (FUNCTION_PROG(n) ? FUNCTION_TEMP(n)->u.func : FUNC(FUNCTION_TEMP(n)->u.index)) +/* flags from full function index */ +#define FUNCTION_FLAGS(n) (FUNCTION_TEMP(n)->flags) + +#define NUM_INHERITS (mem_block[A_INHERITS].current_size / sizeof(inherit_t)) + +#define INHERIT(n) ((inherit_t *)mem_block[A_INHERITS].block + (n)) +#define VAR_TEMP(n) ((variable_t *)mem_block[A_VAR_TEMP].block + (n)) +#define SIMUL(n) (simuls[n].func) +#define PROG_STRING(n) (((const char **)mem_block[A_STRINGS].block)[n]) +#define CLASS(n) ((class_def_t *)mem_block[A_CLASS_DEF].block + (n)) + +#if !defined(__alpha) && !defined(cray) && !defined(__sparc__) +#define align(x) (((x) + 3) & ~3) +#else +#define align(x) (((x) + 7) & ~7) +#endif + +#define SOME_NUMERIC_CASE_LABELS 0x40000 +#define NO_STRING_CASE_LABELS 0x80000 + +#define ARG_IS_PROTO 1 +#define ARG_IS_VARARGS 2 + +#define NOVALUE_USED_FLAG 1024 + +int validate_function_call (int, parse_node_t *); +parse_node_t *validate_efun_call (int, parse_node_t *); +extern mem_block_t mem_block[]; +extern int exact_types, global_modifiers; +extern int current_type; +extern char *prog_code; +extern char *prog_code_max; +extern program_t NULL_program; +extern unsigned char string_tags[0x20]; +extern short freed_string; +extern local_info_t *locals, *locals_ptr; +extern unsigned short *type_of_locals, *type_of_locals_ptr; +extern int current_number_of_locals; +extern int max_num_locals; +extern int current_tree; + +extern int type_of_locals_size; +extern int locals_size; +extern int current_number_of_locals; +extern int max_num_locals; +extern short compatible[11]; +extern short is_type[11]; +extern int comp_last_inherited; + +char *get_type_modifiers (char *, char *, int); +char *get_two_types (char *, char *, int, int); +char *get_type_name (char *, char *, int); +void init_locals (void); + +void save_file_info (int, int); +int add_program_file (char *, int); +void yyerror (const char *); +void yywarn (const char *); +char *the_file_name (char *); +void free_all_local_names (int); +void pop_n_locals (int); +void reactivate_current_locals (void); +void clean_up_locals (void); +void deactivate_current_locals (void); +int add_local_name (const char *, int); +void reallocate_locals (void); +void initialize_locals (void); +int get_id_number (void); +program_t *compile_file (int, char *); +void reset_function_blocks (void); +void copy_variables (program_t *, int); +void copy_structures (program_t *); +int copy_functions (program_t *, int); +void type_error (const char *, int); +int compatible_types (int, int); +int compatible_types2 (int, int); +int arrange_call_inherited (char *, parse_node_t *); +void add_arg_type (unsigned short); +int define_new_function (const char *, int, int, int, int); +int define_variable (char *, int); +int define_new_variable (char *, int); +short store_prog_string (const char *); +void free_prog_string (short); +#ifdef DEBUG +int dump_function_table (void); +#endif +void prepare_cases (parse_node_t *, int); +void push_func_block (void); +void pop_func_block (void); +int decl_fix (int); +parse_node_t *check_refs (int, parse_node_t *, parse_node_t *); + +int lookup_any_class_member (char *, unsigned char *); +int lookup_class_member (int, char *, unsigned char *); +parse_node_t *reorder_class_values (int, parse_node_t *); + +parse_node_t *promote_to_float (parse_node_t *); +parse_node_t *promote_to_int (parse_node_t *); +int convert_type (int); +parse_node_t *add_type_check (parse_node_t *, int); +parse_node_t *do_promotions (parse_node_t *, int); +parse_node_t *throw_away_call (parse_node_t *); +parse_node_t *throw_away_mapping (parse_node_t *); + +#define realloc_mem_block(m) do { \ + mem_block_t *M = m; \ + M->max_size <<= 1; \ + M->block = (char *)DREALLOC(M->block, M->max_size, TAG_COMPILER, "realloc_mem_block"); \ +} while (0) + +#define add_to_mem_block(n, data, size) do { \ + mem_block_t *mbp = &mem_block[n]; \ + int Size = size; \ + \ + if (mbp->current_size + Size > mbp->max_size) { \ + do { \ + mbp->max_size <<= 1; \ + } while (mbp->current_size + Size > mbp->max_size); \ + \ + mbp->block = (char *)DREALLOC(mbp->block, mbp->max_size, TAG_COMPILER, "insert_in_mem_block"); \ + } \ + memcpy(mbp->block + mbp->current_size, data, Size); \ + mbp->current_size += Size; \ +} while (0) + +#ifndef SUPPRESS_COMPILER_INLINES +INLINE_STATIC +char *allocate_in_mem_block (int n, int size) +{ + mem_block_t *mbp = &mem_block[n]; + char *ret; + + if (mbp->current_size + size > mbp->max_size) { + do { + mbp->max_size <<= 1; + } while (mbp->current_size + size > mbp->max_size); + + mbp->block = (char *)DREALLOC(mbp->block, mbp->max_size, TAG_COMPILER, "insert_in_mem_block"); + } + ret = mbp->block + mbp->current_size; + mbp->current_size += size; + return ret; +} + +#endif +#endif + + + + + + diff --git a/fluffos-2.23-ds03/config.h b/fluffos-2.23-ds03/config.h new file mode 100644 index 0000000..0c55794 --- /dev/null +++ b/fluffos-2.23-ds03/config.h @@ -0,0 +1,76 @@ +/* + config.h: do not change anything in this file. The user definable + options have been moved into the options.h file. +*/ + +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +#include "include/runtime_config.h" + +/* + * runtime config strings. change these values in the runtime configuration + * file (config.example) + */ + +#define CONFIG_STR(x) config_str[(x) - BASE_CONFIG_STR] +#define CONFIG_INT(x) config_int[(x) - BASE_CONFIG_INT] + +#define MUD_NAME CONFIG_STR(__MUD_NAME__) +#define ADDR_SERVER_IP CONFIG_STR(__ADDR_SERVER_IP__) +#define MUD_LIB CONFIG_STR(__MUD_LIB_DIR__) +#define BIN_DIR CONFIG_STR(__BIN_DIR__) +#define LOG_DIR CONFIG_STR(__LOG_DIR__) +#define INCLUDE_DIRS CONFIG_STR(__INCLUDE_DIRS__) +#define MASTER_FILE CONFIG_STR(__MASTER_FILE__) +#define SIMUL_EFUN CONFIG_STR(__SIMUL_EFUN_FILE__) +#define SWAP_FILE CONFIG_STR(__SWAP_FILE__) +#define DEBUG_LOG_FILE CONFIG_STR(__DEBUG_LOG_FILE__) +#define DEFAULT_ERROR_MESSAGE CONFIG_STR(__DEFAULT_ERROR_MESSAGE__) +#define DEFAULT_FAIL_MESSAGE CONFIG_STR(__DEFAULT_FAIL_MESSAGE__) +#define GLOBAL_INCLUDE_FILE CONFIG_STR(__GLOBAL_INCLUDE_FILE__) +#define MUD_IP CONFIG_STR(__MUD_IP__) + +/* + * runtime config ints + */ + +#define PORTNO CONFIG_INT(__MUD_PORT__) +#define ADDR_SERVER_PORT CONFIG_INT(__ADDR_SERVER_PORT__) +#define TIME_TO_CLEAN_UP CONFIG_INT(__TIME_TO_CLEAN_UP__) +#define TIME_TO_RESET CONFIG_INT(__TIME_TO_RESET__) +#define TIME_TO_SWAP CONFIG_INT(__TIME_TO_SWAP__) +#define MAX_COST CONFIG_INT(__MAX_EVAL_COST__) +#define MAX_BITS CONFIG_INT(__MAX_BITFIELD_BITS__) +#define MAX_ARRAY_SIZE CONFIG_INT(__MAX_ARRAY_SIZE__) +#define MAX_BUFFER_SIZE CONFIG_INT(__MAX_BUFFER_SIZE__) +#define MAX_MAPPING_SIZE CONFIG_INT(__MAX_MAPPING_SIZE__) +#define MAX_STRING_LENGTH CONFIG_INT(__MAX_STRING_LENGTH__) +#define READ_FILE_MAX_SIZE CONFIG_INT(__MAX_READ_FILE_SIZE__) +#define MAX_BYTE_TRANSFER CONFIG_INT(__MAX_BYTE_TRANSFER__) +#define RESERVED_SIZE CONFIG_INT(__RESERVED_MEM_SIZE__) +#define HTABLE_SIZE CONFIG_INT(__SHARED_STRING_HASH_TABLE_SIZE__) +#define OTABLE_SIZE CONFIG_INT(__OBJECT_HASH_TABLE_SIZE__) +#define INHERIT_CHAIN_SIZE CONFIG_INT(__INHERIT_CHAIN_SIZE__) +#define FD6_PORT CONFIG_INT(__FD6_PORT__) +#define FD6_KIND CONFIG_INT(__FD6_KIND__) + +#ifdef USE_POSIX_SIGNALS +#define sigblock(m) port_sigblock(m) +#define sigmask(s) port_sigmask(s) +#define signal(s,f) port_signal(s,f) +#define sigsetmask(m) port_sigsetmask(m) +#endif + +#define SETJMP(x) setjmp(x) +#define LONGJMP(x,y) longjmp(x,y) + +#define APPLY_CACHE_SIZE (1 << APPLY_CACHE_BITS) + +#define NUM_CONSTS 5 + +#define NULL_MSG "0" + +extern int config_int[NUM_CONFIG_INTS]; +extern char *config_str[NUM_CONFIG_STRS]; +#endif diff --git a/fluffos-2.23-ds03/configure b/fluffos-2.23-ds03/configure new file mode 100644 index 0000000..b30b571 --- /dev/null +++ b/fluffos-2.23-ds03/configure @@ -0,0 +1,112 @@ +#!/bin/bash + +#MINGW USERS: +#To make this script work under MinGW, change the +#top line to point to this: #!/bin/sh + +#Make the non-argument config be Dead Souls +if ! [ $1 ]; then +ARG="ds" +else +ARG=$1 +fi + +if [ $ARG == "--help" ] || [ $ARG == "-h" ]; then +echo "Available options:" +echo "A generic build: ./configure generic" +echo "For Dead Souls 2: ./configure ds" +echo "For Sapidlib: ./configure sapid" +echo "For Discworld: ./configure dw" +echo "For Lima: ./configure lima" +echo "For Skylib: ./configure skylib" +echo "For TMI-2: ./configure tmi2" +echo "For Merentha: ./configure merentha" +echo "For Nightmare 3: ./configure nm3" +echo "For LPUniversity: ./configure lpuni" +echo "For Lil: ./configure lil" +echo "For Final Realms: ./configure fr" +echo "For Foundation I: ./configure foundation" +echo "For Foundation II:./configure foundation2" +echo "For Nightmare IV: ./configure nm4" +echo "----" +echo "With no options, this script defaults to Dead Souls." +exit +fi + +echo "Option selected: $ARG $2" +sleep 1 + +./build.FluffOS $2 + +#if [ $ARG == "ds" ] || [ $ARG == "ds.debug" ]; then +#\cp -f ../extra/creremote/remote.c ../lib/lib/ +#fi + +if uname -a | grep -i "cygwin" | grep -v grep ; then +echo "Cygwin detected." +export WINDOWS='#define WINDOWS' +else +# Some stuff for Dead Souls not on Cygwin +echo "Moving around some DS specific files..." +if [ $ARG == "ds" ] || [ $ARG == "ds.debug" ]; then +if ! [ -f ../bin/mudos.bak ]; then +\rm -f ../bin/mudos.bak +\mv -f ../bin/mudos.cfg ../bin/mudos.bak +\cp -f ../bin/mudos.cfg.orig ../lib/secure/cfg/mudos.cfg +ln -s ../lib/secure/cfg/mudos.cfg ../bin/mudos.cfg +echo "File moves done" +fi +fi +fi + +#start local_options check +if [ -f local_options.$ARG ]; then + +if ! [ -f local_options ]; then +echo "Copying local_options.$ARG to local_options" +cp local_options.$ARG local_options +else +echo "local_options already exists. Not overwriting. Exiting." +echo "If you want to completely start over, type: make distclean" +exit +fi + +else +echo "local_options.$ARG not found. Exiting." +fi +#end local_options check + +if uname -a | grep "MINGW" | grep -v grep ; then +echo "MinGW detected. Adding appropriate config" +#echo " -lwsock32 -lws2_32 -lz" > system_libs +#\cp -f ../extra/mingw/configur* . +export WINDOWS='#define WINDOWS' +echo "#define MINGW" >> local_options +echo "#undef HAS_CONSOLE" >> local_options +else +echo "No MinGW config needed." +fi + +if /sbin/ifconfig -a | grep "204\.209\.44" | grep -v grep ; then +echo "Wolfpaw detected." +echo "Running Wolfpaw-specific modification." +echo "When this is done, please enter the following command line:" +echo "*********" +echo " " +echo "make -j 1" +echo " " +echo "*********" +cp -f ../extra/wolfpaw/* . +echo "#include \"../extra/wolfpaw/configure.h\"" >> local_options +else +echo "No Wolfpaw config needed." +fi + +#This will be blank if there is no Cygwin or MinGW: +echo $WINDOWS >> local_options + +ulimit -n 2048 +export ULIMIT=`ulimit -n` +echo "#define ULIMIT "$ULIMIT >> local_options + +echo "Configuration script complete." diff --git a/fluffos-2.23-ds03/console.c b/fluffos-2.23-ds03/console.c new file mode 100644 index 0000000..8604206 --- /dev/null +++ b/fluffos-2.23-ds03/console.c @@ -0,0 +1,348 @@ +/* + * console.c -- implements a command-line for the driver. + * Separate file because this is likely to grow with time. + * Note that the intent is NOT to have a full scripting language, + * since that's, er, what LPC is. This is to implement driver + * inspection that is difficult or impossible from inside the + * mud. Because of this, explicit allocation of things is + * probably a bad idea: use automatic stack variables as much + * as is possible. + * Isaac Charles (Hamlet@Discworld, etc) -- Jul 2008 + */ + +#include "std.h" + +#ifdef HAS_CONSOLE +#include "comm.h" +#include "object.h" +#include "dumpstat.h" + +#define NAME_LEN 50 + +typedef struct { + char name[NAME_LEN + 1]; + int cpy; + int ref; + long mem; + long idle; +} ITEMS; + + +static int strcmpalpha(const char *aname, const char *bname, int depth); +static int objcmpalpha(const void *, const void *); +static int itemcmpsize(const void *, const void *); +static int objcmpsize(const void *, const void *); +static int objcmpidle(const void *, const void *); + +static INLINE void print_obj(int refs, int cpy, const char *obname, long lastref, + long sz) { + printf("%4d %4d %-*s %5ld %10ld\n", refs, cpy, NAME_LEN, + obname, ((long)time(0) - lastref), sz); +} + +void console_command(char *s) { + char verb[11]; + char args[3][160]; + int numargs, num[2]; + + if(strlen(s) > 0) { + if(strncmp(s, "quit", strlen(s)) == 0) { + (void) puts("Console closing. The mud remains."); + //(void) fclose(stdin); + has_console = 0; + restore_sigttin(); + } + else if(strncmp(s, "shutdown", ((strlen(s) > 4) ? strlen(s) : 4)) == 0) { + (void) puts("Mud ending now."); + shutdownMudOS(0); + return; + } + else if(strncmp(s, "help", strlen(s)) == 0) { + (void) puts( +"Console Help\n\ + quit Close the console (the MUD remains)\n\ + shutdown End the mud (rapidly)\n\ + help This.\n\ + objects Show a listing of all active objects. Format:\n\ + objects [qualifier] [val|range] [prefix=PREFIX]\n\ + qualifiers are:\n\ + alpha sort objects alphabetically\n\ + size sort objects by (reverse) size\n\ + idle sort objects by (reverse) idle time\n\ + totals sum together usage of all clones of an obj and\n\ + display in reverse order of size\n\ + depth: sum together subdirectories past depth D.\n\ + val is a number, specifying number of objects to show,\n\ + from the beginning (positive) or from the end (negative).\n\ + range is st..fin where st and fin can be number of objects\n\ + from the beginning (positive) or from the end (negative.)\n\ + if prefix=PREFIX is present, only items beginning with PREFIX\n\ + will be displayed. Note that ranges are applied and /then/ \n\ + the prefixes are checked. Specifying both may result in \n\ + empty output\ +"); + } + else { // commands that can be followed by args + int DEPTH = 1000; /* allow summarization to dir-level */ + char *prefix = (char *) 0; + int plen = 0; + + num[0] = 0; + num[1] = INT_MAX; + + if((numargs = sscanf(s, "%10s %159s %159s %159s", verb, args[0], + args[1], args[2]) - 1) + >= 1) { + int tmp; + char *pos; + + if(numargs && (strncmp("prefix", args[numargs-1], 6) == 0) && + (strlen(args[numargs-1]) > 6)) { + prefix = args[numargs-1] + 7; + plen = strlen(prefix); + numargs--; + } + + if(numargs) { + pos = args[numargs-1]; + while((pos = strchr(pos, '<')) != NULL) + *pos++ = '-'; + + if((tmp = sscanf(args[numargs-1], "%d..%d", &num[0], &num[1])) == 2){ + } + else if(tmp == 1) { + if(args[numargs-1][strlen(args[numargs-1])-1] != '.') { + if(num[0] == 0) { + num[0] = num[1] = 0; + } + else if(num[0] > 0) { + num[1] = num[0] - 1; + num[0] = 0; + } + } + } + + if(tmp) + numargs--; + } + } + + if(strncmp(verb, "objects", strlen(verb)) == 0) { + object_t **list; + int count; + char *pos2; + int i; + long totsz = 0, sz; + char TOTALS = (char) 0; + + /* allow 'objects depth:3 10' */ + if(numargs && ((pos2 = strpbrk(args[0], ":=")) != NULL)) { + sscanf(pos2+1, "%d", &DEPTH); + if(DEPTH < 1) + DEPTH = 1; + *pos2 = '\0'; + } + + // get_objects() allocates a string and pushes it onto the stack. + // probably not a problem here as long as we remember to pop it. + get_objects(&list, &count, 0, 0); + + if(numargs) { + if(strncmp("alpha", args[0], strlen(args[0])) == 0) + qsort(list, (size_t) count, sizeof(object_t *), objcmpalpha); + else if(strncmp("size", args[0], strlen(args[0])) == 0) + qsort(list, (size_t) count, sizeof(object_t *), objcmpsize); + else if(strncmp("idle", args[0], strlen(args[0])) == 0) + qsort(list, (size_t) count, sizeof(object_t *), objcmpidle); + else { /* This should be "totals" or "depth" */ + TOTALS = (char) 1; + qsort(list, (size_t) count, sizeof(object_t *), objcmpalpha); + } + } + + printf("%4s %4s %-*s %5s %10s\n", "Rf", "Cpy", NAME_LEN, "Obj", + "Idle", "Size"); + + if(TOTALS && (count > 1)) { + ITEMS it[count+1]; + int lst = 0; + char *pound; + //char tmpnam[NAME_LEN + 1]; + + memset(it, 0, (count+1) * sizeof(ITEMS)); + + for(i=0; i < count; i++) { + if(strcmpalpha(it[lst].name, list[i]->obname, DEPTH) + != 0) { + int sl; + const char *slash = list[i]->obname; + lst++; + + for(sl = 0; sl < DEPTH; sl++) + if((slash = strchr(slash, '/')) == NULL) { + slash = list[i]->obname + strlen(list[i]->obname); + break; + } + else + slash++; + + strncpy(it[lst].name, list[i]->obname + + (((slash - list[i]->obname) > NAME_LEN) ? + ((slash - list[i]->obname) - NAME_LEN) + : 0) + , NAME_LEN); + it[lst].name[slash - list[i]->obname] = '\0'; + + pound = strchr(it[lst].name, '#'); + if(pound != NULL) + *pound = '\0'; + } + + it[lst].cpy++; + it[lst].ref += list[i]->ref; + it[lst].mem += list[i]->prog->total_size + data_size(list[i]) + + sizeof(object_t); + if(((long)list[i]->time_of_ref < it[lst].idle) || !it[lst].idle) + it[lst].idle = (long) list[i]->time_of_ref; + } + + qsort(it+1, (size_t) lst, sizeof(ITEMS), itemcmpsize); + + if(num[0] >= lst) + num[0] = lst - 1; + else if(num[0] < 0) { + num[0] = lst + num[0]; + if(num[0] < 0) + num[0] = 0; + } + num[0]++; + + if(num[1] >= lst) + num[1] = lst - 1; + else if(num[1] < 0) { + num[1] = lst + num[1]; + if(num[1] < 0) + num[1] = 0; + } + num[1]++; + + for(i=num[0]; i<=num[1]; i++) { + if(!prefix || (strncmp(it[i].name, prefix, plen) == 0)) { + print_obj(it[i].ref, it[i].cpy, it[i].name, it[i].idle, + it[i].mem); + totsz += it[i].mem; + } + } + } + else { // no totals needed + if(num[0] >= count) + num[0] = count - 1; + else if(num[0] < 0) { + num[0] = count + num[0]; + if(num[0] < 0) + num[0] = 0; + } + if(num[1] >= count) + num[1] = count - 1; + else if(num[1] < 0) { + num[1] = count + num[1]; + if(num[1] < 0) + num[1] = 0; + } + + for(i = num[0]; i <= num[1]; i++) { + if(!prefix || (strncmp(list[i]->obname, prefix, plen) == 0)) { + print_obj((int)list[i]->ref, 1, list[i]->obname, + (long) list[i]->time_of_ref, + sz = (long) list[i]->prog->total_size + + (long)data_size(list[i]) + + (long)sizeof(object_t)); + totsz += sz; + } + } + } + + printf("%4s %4s %-*s %5s %10s\n", "", "", NAME_LEN, "-----", "-----", + "----------"); + printf("%4s %4s %*d %-5s %10ld\n", "", "", NAME_LEN, 1+num[1]-num[0], + "objs", totsz); + pop_stack(); + } + else { + (void) puts("Unknown command."); + } + } + } + + if(has_console > 0) { + (void) putchar('?'); (void) putchar(' '); + (void) fflush(stdout); + } +} + +static int strcmpalpha(const char *aname, const char *bname, int depth) { + int slash = 0; + + for(;(*aname == *bname) && (*aname != '#') && (*bname != '#') && + (*aname != '\0') && (*bname != '\0'); aname++, bname++) { + if(*aname == '/') + slash++; + + if(slash == depth) + break; + } + + if((*aname == '#') || ((slash == depth) && (*aname == '/'))) { + if((*bname != '#') && (*bname != '\0') && + ((slash != depth) || (*bname != '/'))) + return 1; + return 0; + } + if((*bname == '#') || ((slash == depth) && (*bname == '/'))) { + if(*aname == '\0') + return 0; + return -1; + } + + return (int) (*aname - *bname); +} + +static int objcmpalpha(const void *a, const void *b) { + const char *aname = (*((object_t **) a))->obname; + const char *bname = (*((object_t **) b))->obname; + + return strcmpalpha(aname, bname, 1000); +} + +static int itemcmpsize(const void *a, const void *b) { + long asz = (*((ITEMS *) a)).mem; + long bsz = (*((ITEMS *) b)).mem; + + if(asz == bsz) + return strcmpalpha((*((ITEMS *) a)).name, (*((ITEMS *) b)).name, 1000); + + return (int) (bsz - asz); +} + +static int objcmpsize(const void *a, const void *b) { + object_t *aobj = (*((object_t **) a)); + object_t *bobj = (*((object_t **) b)); + int asz = aobj->prog->total_size + data_size(aobj); + int bsz = bobj->prog->total_size + data_size(bobj); + + if(asz == bsz) + return objcmpalpha(a, b); + + return bsz - asz; +} + +static int objcmpidle(const void *a, const void *b) { + int arft = (*((object_t **) a))->time_of_ref; + int brft = (*((object_t **) b))->time_of_ref; + + if(arft == brft) + return objcmpalpha(a, b); + + return arft - brft; +} +#endif diff --git a/fluffos-2.23-ds03/console.h b/fluffos-2.23-ds03/console.h new file mode 100644 index 0000000..f8bb3bd --- /dev/null +++ b/fluffos-2.23-ds03/console.h @@ -0,0 +1,16 @@ +/* + * console.h -- definitions and prototypes for console.c + * + */ + +#ifndef CONSOLE_H +#define CONSOLE_H + +#include "options_incl.h" + +#ifdef HAS_CONSOLE +extern void console_command(char *); +#endif + +#endif + diff --git a/fluffos-2.23-ds03/crc32.c b/fluffos-2.23-ds03/crc32.c new file mode 100644 index 0000000..993da12 --- /dev/null +++ b/fluffos-2.23-ds03/crc32.c @@ -0,0 +1,25 @@ +#include "std.h" +#include "crc32.h" +#define NEED_CRC_TABLE +#include "crctab.h" /* see this file for more CRC credits and + * comments */ + +/* compute_crc32: compute a cyclic redundancy code for a buffer 'buf' of a + given length 'len'. This trivial little routine was written by + John Garnett. All of the code in crctab.h (the hard stuff) was written + by others. See the comments in the file (crctab.h) for the credits. +*/ + +UINT32 +compute_crc32 (unsigned char * buf, int len) +{ + register UINT32 crc = 0xFFFFFFFFL; + register int j; + + j = len; + while (j--) { + /* the UPDC32 macro uses 1st arg only once */ + crc = UPDC32((unsigned int) *buf++, crc); + } + return crc; +} diff --git a/fluffos-2.23-ds03/crc32.h b/fluffos-2.23-ds03/crc32.h new file mode 100644 index 0000000..5744048 --- /dev/null +++ b/fluffos-2.23-ds03/crc32.h @@ -0,0 +1,9 @@ +#ifndef CRC32_H +#define CRC32_H + +/* + * crc32.c + */ +UINT32 compute_crc32 (unsigned char *, int); + +#endif diff --git a/fluffos-2.23-ds03/crctab.h b/fluffos-2.23-ds03/crctab.h new file mode 100644 index 0000000..c49903e --- /dev/null +++ b/fluffos-2.23-ds03/crctab.h @@ -0,0 +1,121 @@ +/* + * Crc calculation stuff + */ + +/* + * Copyright (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + */ + +/* First, the polynomial itself and its table of feedback terms. The */ +/* polynomial is */ +/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ +/* Note that we take it "backwards" and put the highest-order term in */ +/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ +/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ +/* the MSB being 1. */ + +/* Note that the usual hardware shift register implementation, which */ +/* is what we're using (we're merely optimizing it by doing eight-bit */ +/* chunks at a time) shifts bits into the lowest-order term. In our */ +/* implementation, that means shifting towards the right. Why do we */ +/* do it this way? Because the calculated CRC must be transmitted in */ +/* order from highest-order term to lowest-order term. UARTs transmit */ +/* characters in order from LSB to MSB. By storing the CRC this way, */ +/* we hand it to the UART in the order low-byte to high-byte; the UART */ +/* sends each low-bit to hight-bit; and the result is transmission bit */ +/* by bit from highest- to lowest-order term without requiring any bit */ +/* shuffling on our part. Reception works similarly. */ + +/* The feedback terms table consists of 256, 32-bit entries. Notes: */ +/* */ +/* The table can be generated at runtime if desired; code to do so */ +/* is shown later. It might not be obvious, but the feedback */ +/* terms simply represent the results of eight shift/xor opera- */ +/* tions for all combinations of data and CRC register values. */ +/* */ +/* The values must be right-shifted by eight bits by the "updcrc" */ +/* logic; the shift must be unsigned (bring in zeroes). On some */ +/* hardware you could probably optimize the shift in assembler by */ +/* using byte-swap instructions. */ + +#ifdef NEED_CRC_TABLE +static long cr3tab[] = +{ /* CRC polynomial 0xedb88320 */ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, + 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, + 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, + 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, + 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, + 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, + 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, + 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, + 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, + 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, + 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, + 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, + 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, + 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, + 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, + 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, + 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, + 0x5a05df1b, 0x2d02ef8d +}; +#endif + +#ifdef NFGM +long UPDC32(b, c) + long c; +{ + return (cr3tab[(c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF)); +} + +#else +#define UPDC32(b, c) (cr3tab[(c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF)) +#endif diff --git a/fluffos-2.23-ds03/crypt.c b/fluffos-2.23-ds03/crypt.c new file mode 100644 index 0000000..fcf5905 --- /dev/null +++ b/fluffos-2.23-ds03/crypt.c @@ -0,0 +1,380 @@ +/* Password hasher for the LPC crypt() function. + * + * The hasher is based on the MD5 message digest algorithm. + * In this module MD5 is implemented from scratch using RFC 1321. + * RFC 1321 is ``The MD5 Message-Digest Algorithm'', by R. Rivest. + * + * Implemented by Fermat@Equilibria for MudOS. + * + * 970125: First version. + * 970131: Added crunchbuffer() to allow the crypting of passwords + * of (practically) arbitrary length -- custom_crypt() should now + * never return NULL. + * 970205: Added fix for little-endian systems (well, fix for 486 actually), + * plus `reference results'. + * + * + * Note: + * + * This should work equally on little- and big-endian, 16, 32 and 64 bit + * systems alike (well, everywhere really), but I can't test it everywhere. + * Please mail me if you can't reproduce any of the following results (and + * are prepared to work out the fixes with me): + * + * key: "thing" + * salt: "anhlklck!" + * result: "anhlklck!ggddl`l`lg`bjblodlfcljdcnhffib`c" + * + * key: "this is a ridiculously long PW that nobody would really use" + * salt: "saltstring" + * result: "nahhdhfc!dhbeclbjk`llmhifc`jedo`adbdboc`k" + * + * key: "" + * salt: "" + * salt: "" + * result: "ijegehja!j`kacklajkljde`od`ogdmlnbfl`bjfo" + * + * This doesn't apply, of course, if you change any of the settings + * or any other code before trying this. + * + * =Fermat + * + */ + +#include "std.h" +#include "port.h" +#include "crypt.h" + +#ifdef CUSTOM_CRYPT + +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/* Can we cheat and just use network byte order (and htonl/ntohl) here? + * -Beek + */ + +/* MIRROR: inverts the order of bytes in a 32-bit quantity, if + * necessary. + * Define this to be empty on big-endian systems: + * #define MIRROR(l) + * And for little-endian systems something like: + * #define MIRROR(l) ( (l) = ( ((l) << 24) | (((l) & 0x0000ff00) << 8) +| (((l) & 0x00ff0000) >> 8) | ((l) >> 24) ) ) + */ +#ifdef BIGENDIAN +#define MIRROR(l) +#else +#define MIRROR(l) ( (l) = ( ((l) << 24) | (((l) & 0x0000ff00) << 8) | (((l) & 0x00ff0000) >> 8) | ((l) >> 24) ) ) +#endif + + +/* Functions F, G, H and I as mentioned in RFC, section 3.4. */ +#define F(X, Y, Z) (((X)&(Y))|((~(X))&(Z))) +#define G(X, Y, Z) (((X)&(Z))|((~(Z))&(Y))) +#define H(X, Y, Z) ((X)^(Y)^(Z)) +#define I(X, Y, Z) ((Y)^((X)|(~(Z)))) + +/* Left rotation. */ +#define RLEFT(a, n) (a) = (((a) << (n)) | ((a) >> (32-(n)))) + +/* Table T constructed from a sine function, mentioned in RFC, section 3.4. + * Table T[i], 1 <= i <= 64, = trunc (4294967296 * |sin i|). + */ +UINT32 T[64] = { + 0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,0xf57c0faf,0x4787c62a, + 0xa8304613,0xfd469501,0x698098d8,0x8b44f7af,0xffff5bb1,0x895cd7be, + 0x6b901122,0xfd987193,0xa679438e,0x49b40821,0xf61e2562,0xc040b340, + 0x265e5a51,0xe9b6c7aa,0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8, + 0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,0xa9e3e905,0xfcefa3f8, + 0x676f02d9,0x8d2a4c8a,0xfffa3942,0x8771f681,0x6d9d6122,0xfde5380c, + 0xa4beea44,0x4bdecfa9,0xf6bb4b60,0xbebfbc70,0x289b7ec6,0xeaa127fa, + 0xd4ef3085,0x04881d05,0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665, + 0xf4292244,0x432aff97,0xab9423a7,0xfc93a039,0x655b59c3,0x8f0ccc92, + 0xffeff47d,0x85845dd1,0x6fa87e4f,0xfe2ce6e0,0xa3014314,0x4e0811a1, + 0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391 +}; + +/* This function returns success, i.e. 0 on error. */ +int MD5Digest( BytE *buf, /* Buffer to be digested. */ + unsigned long buflen, /* Length of the buffer in bytes. + */ + BytE *Digest /* Output area: 16 raw bytes. */ + ) +{ + +#define OA 0x67452301 /* Per RFC, section 3.3. */ +#define OB 0xefcdab89 +#define OC 0x98badcfe +#define OD 0x10325476 + + UINT32 A = OA, B = OB, C = OC, D = OD; + static UINT32 Block[16]; /* One block: 512 bits. */ + + if(buflen > MD5_MAXLEN) return 0; /* Too large. */ + + /* Create the block we're going to digest: padded. */ + memset(Block, 0, sizeof(Block)); + memcpy(Block, buf, buflen); + { int i; for(i = 0; i <= buflen/4; i++) { MIRROR(Block[i]); } } + Block[buflen>>2] |= 0x00000080 << (8 * (buflen % 4)); + Block[14] = buflen << 3; /* Number of bits in original data. */ + + /* MD5 Transformation. */ +#define Tr(a, b, c, d, k, s, i, x) (a) += x(b,c,d) + Block[k] + T[(i)-1]; RLEFT(a, s); (a) += (b); + + /* Round 1 */ +Tr(A,B,C,D, 0, 7, 1,F); Tr(D,A,B,C, 1,12, 2,F); Tr(C,D,A,B, 2,17, 3,F); Tr(B,C,D,A, 3,22, 4,F); +Tr(A,B,C,D, 4, 7, 5,F); Tr(D,A,B,C, 5,12, 6,F); Tr(C,D,A,B, 6,17, 7,F); Tr(B,C,D,A, 7,22, 8,F); +Tr(A,B,C,D, 8, 7, 9,F); Tr(D,A,B,C, 9,12,10,F); Tr(C,D,A,B,10,17,11,F); Tr(B,C,D,A,11,22,12,F); +Tr(A,B,C,D,12, 7,13,F); Tr(D,A,B,C,13,12,14,F); Tr(C,D,A,B,14,17,15,F); Tr(B,C,D,A,15,22,16,F); + + /* Round 2 */ +Tr(A,B,C,D, 1, 5,17,G); Tr(D,A,B,C, 6, 9,18,G); Tr(C,D,A,B,11,14,19,G); Tr(B,C,D,A, 0,20,20,G); +Tr(A,B,C,D, 5, 5,21,G); Tr(D,A,B,C,10, 9,22,G); Tr(C,D,A,B,15,14,23,G); Tr(B,C,D,A, 4,20,24,G); +Tr(A,B,C,D, 9, 5,25,G); Tr(D,A,B,C,14, 9,26,G); Tr(C,D,A,B, 3,14,27,G); Tr(B,C,D,A, 8,20,28,G); +Tr(A,B,C,D,13, 5,29,G); Tr(D,A,B,C, 2, 9,30,G); Tr(C,D,A,B, 7,14,31,G); Tr(B,C,D,A,12,20,32,G); + + /* Round 3 */ +Tr(A,B,C,D, 5, 4,33,H); Tr(D,A,B,C, 8,11,34,H); Tr(C,D,A,B,11,16,35,H); Tr(B,C,D,A,14,23,36,H); +Tr(A,B,C,D, 1, 4,37,H); Tr(D,A,B,C, 4,11,38,H); Tr(C,D,A,B, 7,16,39,H); Tr(B,C,D,A,10,23,40,H); +Tr(A,B,C,D,13, 4,41,H); Tr(D,A,B,C, 0,11,42,H); Tr(C,D,A,B, 3,16,43,H); Tr(B,C,D,A, 6,23,44,H); +Tr(A,B,C,D, 9, 4,45,H); Tr(D,A,B,C,12,11,46,H); Tr(C,D,A,B,15,16,47,H); Tr(B,C,D,A, 2,23,48,H); + + /* Round 4 */ +Tr(A,B,C,D, 0, 6,49,I); Tr(D,A,B,C, 7,10,50,I); Tr(C,D,A,B,14,15,51,I); Tr(B,C,D,A, 5,21,52,I); +Tr(A,B,C,D,12, 6,53,I); Tr(D,A,B,C, 3,10,54,I); Tr(C,D,A,B,10,15,55,I); Tr(B,C,D,A, 1,21,56,I); +Tr(A,B,C,D, 8, 6,57,I); Tr(D,A,B,C,15,10,58,I); Tr(C,D,A,B, 6,15,59,I); Tr(B,C,D,A,13,21,60,I); +Tr(A,B,C,D, 4, 6,61,I); Tr(D,A,B,C,11,10,62,I); Tr(C,D,A,B, 2,15,63,I); Tr(B,C,D,A, 9,21,64,I); + + /* Final adjustment of registers. */ + A += OA; B += OB; C += OC; D += OD; + + /* Store output. */ + MIRROR(A); memcpy( Digest, &A, sizeof(A)); + MIRROR(B); memcpy(&(Digest[ 4]), &B, sizeof(B)); + MIRROR(C); memcpy(&(Digest[ 8]), &C, sizeof(C)); + MIRROR(D); memcpy(&(Digest[12]), &D, sizeof(D)); + + /* Burn; earlier registers are more useful in attacks. */ + A = B = C = D = 195952365; + + /* Ok. */ + return 1; +} + +/* Encode in a printable manner the raw input data. Return written bytes. + * The number of bytes required is always double the number of input + * bytes. + * + * It's pretty simple-minded encoding, but we're not scraping + * for bytes here. Besides, the only other possibilities are 5 or 6 + * bits encoding per byte (instead of 4, as here), which look really + * messy, when implemented, compared to this. + * + * Hell, perhaps sprintf (printing in hex) should be used.. + */ +int encode(unsigned char *whEre, BytE *data, int inputbytes) +{ + int i, w = 0; + +/* This number has to leave the 4 low-end bits free. */ +#define ENCODER_OFFSET 96 + + for(i = 0; i < inputbytes; i++) { + whEre[i*2] = ENCODER_OFFSET + ( data[i] & 0x0f); + whEre[1+(i*2)] = ENCODER_OFFSET + ((data[i] >> 4) & 0x0f); + w += 2; + } + + return w; +} + +/* Gets raw data from printable string; opposite of encode(). */ +void decode(BytE *whEre, BytE *string, int stringbytes) +{ + int i; + + for(i = 0; i < stringbytes; i+=2) + whEre[i/2] = (string[i] & 0x0f) | ((string[i+1] & 0x0f) << 4); +} + +/* If there is a valid salt in the input, copy it. Otherwise, + * generate a new one. + */ +void getsalt(BytE *to, BytE *from) +{ + int i; + +/* This character seperates the salt encoding from the password encoding + * in the string returned by custom_crypt(). Configurable. + */ +#define MAGIC_SALTSEP '!' + + if(from) { + BytE Digest[16]; + + if(strlen((char *)from) > MD5_SALTLEN * 2) { + if(from[2 * MD5_SALTLEN] == MAGIC_SALTSEP) { + /* It is possible, by a big fluke, + * that this string is not generated by custom_crypt() + * and encode(), and the MAGIC_SALTSEP + * is there by coincedence. That doesn't really + * matter, as long as we get consistently + * the same salt out of here, always. decode() + * takes care of this. + */ + decode(to, from, MD5_SALTLEN * 2); + return; + } + } + + /* We have a salt value, but it's not generated by + * this function. Well, suit yourself, we'll /get/ a salt + * out of there.. However, we can't do any straightforward + * copying, because the `salt' is likely to be (also) the + * plain text, to be mashed up. So to generate a salt from + * any string, we digest it first, to avoid people being able + * to pry information from the salt. + * + * It is vital, for fairly obvious reasons, that MD5_VALID_SALT + * is indeed a valid, immediately accepted salt value (as above), + * otherwise we'll end up right here again. + */ + custom_crypt((char *) from, MD5_VALID_SALT, Digest); + memset(to, strlen((char *)from), MD5_SALTLEN); + for(i = 0; i < sizeof(Digest); i++) + to[i % MD5_SALTLEN] += Digest[i]; + + return; + } + + /* We have to generate a random salt. */ + for(i = 0; i < MD5_SALTLEN; i++) + to[i] = random_number(256); /* port.c */ + + return; +} + +void crunchbuffer(BytE *buf, /* Buffer to be crunched. */ + SIGNED int *len, /* Length now used in buf. */ + char *addition, /* What to add to buf. */ + SIGNED int addlen, /* Length of addition. */ + int maxlen /* How many bytes in buf. */ + ) +{ + int used; + + used = *len; + + while(addlen > 0) { + BytE Digest[16]; + int crunched; + + /* Reduce `buf' by digesting it. */ + if(used > sizeof(Digest)) { + MD5Digest(buf, used, Digest); + memcpy(buf, Digest, sizeof(Digest)); + used = sizeof(Digest); + } + + /* Work out how many bytes we can add to `buf', and do it. */ + crunched = min((maxlen - used), addlen); + memcpy(&(buf[used]), addition, crunched); + + /* Update counters and pointers. */ + used += crunched; + addition += crunched; + addlen -= crunched; + } + + *len = used; + + return; +} + +/* Return hash of buffer `key' using salt `salt', which + * must both be null-terminated strings if given. + * - `key' must be given. This is the basic string to be hashed. + * - `salt' is optional. It can be NULL (in which case a random + * salt will be used), it can be output from a previous + * custom_crypt() call (in which case the salt used in that call + * will be used), or it can be any other string, in which case + * a salt derived from that string will be used. + * - `rawout' is optional. If non-NULL, the raw digest value + * (without any salt) is written to that buffer (16 bytes). + * + * At this point, custom_crypt() should never return NULL. + * + */ +char *custom_crypt(const char *key, const char *salt, unsigned char *rawout) +{ + BytE Digest[16]; + static BytE buffer[MD5_MAXLEN], + abuffer[MD5_MAXLEN], + thesalt[MD5_SALTLEN]; + SIGNED int used = 0, len, i; + static BytE /* encode()d salt, encode()d digest, salt seperator + * and null terminating byte: + */ + ret[(MD5_SALTLEN*2) + 1 + (sizeof(Digest)*2) + 1]; + + /* Obtain the salt we have to use (either given in salt + * arg or randomly generated one). + */ + getsalt(thesalt, (BytE *)salt); + +#define ADDBUFFER(b, l) if(used + (l) > sizeof(buffer)) \ + crunchbuffer(buffer, &used, (char *)(b), (l), sizeof(buffer)); \ + else { memcpy(&(buffer[used]), (b), (l)); \ + used += (l); } + + memset(buffer, 0, sizeof(buffer)); + + /* It's important the 0 byte is copied too. */ + len = strlen(key) + 1; ADDBUFFER(key, len); + len = strlen(MD5_MAGIC) + 1; ADDBUFFER(MD5_MAGIC, len); + + ADDBUFFER(thesalt, sizeof(thesalt)); + + memcpy(abuffer, buffer, sizeof(abuffer)); + + /* The iteration count should be high to thwart + * brute-force guessers. The choice of 3000 is + * fairly arbitrary, but you shouldn't set it much + * lower; but it's configurable. + * + * Here a `digest' value is generated to be included + * in the final to-be-digested buffer, along with the + * actual data. + * + * Make sure to make it length-dependant. + */ + len = strlen(key); + for(i = 3000+(11*len); i > 0; i--) { + if(!MD5Digest(abuffer, sizeof(abuffer), Digest)) return NULL; + memcpy(&(abuffer[(i + len) % (MD5_MAXLEN - sizeof(Digest))]), Digest, sizeof(Digest)); + } + + ADDBUFFER(Digest, sizeof(Digest)); + + /* Use this generated buffer to do the actual digesting. */ + if(!MD5Digest(buffer, sizeof(buffer), Digest)) return NULL; + + /* Pyre! */ + memset(buffer, 0, sizeof(buffer)); + + /* Now code the salt and the digest into the return string. */ + len = encode(ret, thesalt, sizeof(thesalt)); + ret[len++] = MAGIC_SALTSEP; + len += encode(&(ret[len]), Digest, sizeof(Digest)); + ret[len] = 0; + + /* Give raw output (without salt info) if requested. */ + if(rawout) + memcpy(rawout, Digest, sizeof(Digest)); + + return (char *)ret; +} +#endif diff --git a/fluffos-2.23-ds03/crypt.h b/fluffos-2.23-ds03/crypt.h new file mode 100644 index 0000000..5c6e10e --- /dev/null +++ b/fluffos-2.23-ds03/crypt.h @@ -0,0 +1,37 @@ +#ifndef CRYPT_H +#define CRYPT_H + +/* Number of bytes in salt (raw, fully used, not printable-encoded bytes). + * This is configurable, but don't set it too high (up to say 10). But 4 + * is plenty really, 2^32 salts possible (the DES-style crypt used only 4096). + */ +#define MD5_SALTLEN 4 + +/* Magic string, used in hashing. Configurable. */ +#define MD5_MAGIC "xyzz" + +/* Maximum length (in bytes) of digested data. + * This is /not/ configurable! Don't change it. + */ +#define MD5_MAXLEN 55 + +/* This salt value is used in generating salts. It must + * be a valid salt as returned by md5crypt(), or the + * routine will go into an infinite loop when generating + * a salt from an unrecognized string. Any value returned + * from md5crypt("anything", NULL, NULL) is valid here. + */ + +#define MD5_VALID_SALT "anhlklck!ggddl`l`lg`bjblodlfcljdcnhffib`c" + +typedef unsigned char BytE; + +char *custom_crypt(const char *key, const char *salt, unsigned char *rawout); + +int MD5Digest ( BytE *, unsigned long buflen, BytE *); +int encode ( unsigned char *, BytE *, int ); +void decode ( unsigned char *, BytE *, int ); +void getsalt (BytE *, BytE * ); +void crunchbuffer (BytE *buf, SIGNED int *, char *, SIGNED int, int ); + +#endif diff --git a/fluffos-2.23-ds03/debug.c b/fluffos-2.23-ds03/debug.c new file mode 100644 index 0000000..26b3357 --- /dev/null +++ b/fluffos-2.23-ds03/debug.c @@ -0,0 +1,66 @@ +#include "std.h" +#include "lpc_incl.h" + +#ifdef DEBUG_MACRO + +mapping_t *debug_levels (void); + +typedef struct { + char *name; + int bit; +} debug_t; + +#define E(x) { #x, DBG_##x } + +debug_t levels[] = { + E(call_out), + E(d_flag), + E(connections), + E(mapping), + E(sockets), + E(comp_func_tab), + E(LPC), + E(LPC_line) +}; + +#define NELEM(x) (sizeof(x)/sizeof(x[0])) + +mapping_t *debug_levels() { + int dl = debug_level; + mapping_t *ret = allocate_mapping(10); + int i; + + for (i = 0; i < NELEM(levels); i++) { + add_mapping_pair(ret, levels[i].name, dl & levels[i].bit); + dl &= ~levels[i].bit; + } + + if (dl) + add_mapping_pair(ret, "unknown", dl); + + return ret; +} + +void debug_level_set (char * level) { + int i; + + for (i = 0; i < NELEM(levels); i++) { + if (strcmp(level, levels[i].name) == 0) { + debug_level |= levels[i].bit; + return; + } + } +} + +void debug_level_clear (char * level) { + int i; + + for (i = 0; i < NELEM(levels); i++) { + if (strcmp(level, levels[i].name) == 0) { + debug_level &= ~levels[i].bit; + return; + } + } +} + +#endif diff --git a/fluffos-2.23-ds03/debug.h b/fluffos-2.23-ds03/debug.h new file mode 100644 index 0000000..d46e6a2 --- /dev/null +++ b/fluffos-2.23-ds03/debug.h @@ -0,0 +1,43 @@ +/* debug.h: added by Truilkan: 92/02/08 */ + +/* this include file adds some nice debugging capabilities. You can + use -DDEBUG_MACRO in CFLAGS in the Makefile to let the debug code + be compiled in. If DEBUG_MACRO is not defined then the debug code + is removed by the C preprocessor. The global variable debug_level + is defined in main.c. The debug_level typically starts out at zero + (0) and slowly grows larger over the life of the program. The main + advantage to this debug macro is that you can turn various sets of + debug statements of and on by changing the value of debug_level. + Say for example that debug_level is set to 7; then, all debug() + statements with a first argument of 1, 2, or 4 would be printed. If + debug_level is 6, then only debug()'s with 2 or 4 as the first arg + would be printed. Sample usage is as follows: + + debug(4,("module.c: simulate(): x = %d, y = %d\n",x,y)); +*/ + +#ifndef _FUNC_SPEC_ +extern int debug_level; + +void handle_debug_level (char *); +void debug_level_set (char *); +void debug_level_clear (char *); + +#ifdef DEBUG_MACRO +#define debug(x,y) if (debug_level & DBG_##x) { printf("%s: ", #x); printf y; putchar('\n'); fflush(stdout); } +#else +#define debug(x,y) +#endif + +/* Would be nice to have tons of these; should go to arbitrary bitsets */ +#define DBG_call_out 1 +#define DBG_addr_server 2 +#define DBG_d_flag 4 +#define DBG_connections 8 +#define DBG_mapping 16 +#define DBG_sockets 32 +#define DBG_comp_func_tab 64 +#define DBG_LPC 128 +#define DBG_LPC_line 256 + +#endif diff --git a/fluffos-2.23-ds03/debugmalloc.c b/fluffos-2.23-ds03/debugmalloc.c new file mode 100644 index 0000000..e90494e --- /dev/null +++ b/fluffos-2.23-ds03/debugmalloc.c @@ -0,0 +1,115 @@ +/* + wrapper functions for system malloc -- keep malloc stats. + Truilkan@TMI - 92/04/17 +*/ + +#define IN_MALLOC_WRAPPER +#define NO_OPCODES +#include "std.h" +#include "debugmalloc.h" +#include "my_malloc.h" +#include "md.h" + +void fatal (const char *, ...); + +#undef NOISY_MALLOC + +#ifdef NOISY_MALLOC +#define NOISY(x) printf(x) +#define NOISY1(x,y) printf(x,y) +#define NOISY2(x,y,z) printf(x,y,z) +#define NOISY3(w,x,y,z) printf(w,x,y,z) +#else +#define NOISY(x) +#define NOISY1(x,y) +#define NOISY2(x,y,z) +#define NOISY3(w,x,y,z) +#endif + +typedef struct stats_s { + unsigned int free_calls, alloc_calls, realloc_calls; +} stats_t; + +static stats_t stats; + +void debugmalloc_init() +{ + stats.free_calls = 0; + stats.alloc_calls = 0; + stats.realloc_calls = 0; + MDinit(); +} + +INLINE void *debugrealloc (void * ptr, int size, int tag, char * desc) +{ + void *tmp; + + if (size <= 0) + fatal("illegal size in debugrealloc()"); + + NOISY3("realloc: %i (%x), %s\n", size, ptr, desc); + stats.realloc_calls++; + tmp = (md_node_t *) ptr - 1; + if (MDfree(tmp)) { + tmp = (void *) REALLOC(tmp, size + MD_OVERHEAD); + MDmalloc(tmp, size, tag, desc); + return (md_node_t *) tmp + 1; + } + return (void *) 0; +} + +INLINE void *debugmalloc (int size, int tag, char * desc) +{ + void *tmp; + + if (size <= 0) + fatal("illegal size in debugmalloc()"); + stats.alloc_calls++; + tmp = (void *) MALLOC(size + MD_OVERHEAD); + MDmalloc(tmp, size, tag, desc); + NOISY3("malloc: %i (%x), %s\n", size, (md_node_t *)tmp + 1, desc); + return (md_node_t *) tmp + 1; +} + +INLINE void *debugcalloc (int nitems, int size, int tag, char * desc) +{ + void *tmp; + + if (size <= 0) + fatal("illegal size in debugcalloc()"); + + stats.alloc_calls++; + tmp = (void *) CALLOC(nitems * size + MD_OVERHEAD, 1); + MDmalloc(tmp, nitems * size, tag, desc); + NOISY3("calloc: %i (%x), %s\n", nitems*size, (md_node_t *)tmp + 1, desc); + return (md_node_t *) tmp + 1; +} + +INLINE void debugfree (void * ptr) +{ + md_node_t *tmp; + + NOISY1("free (%x)\n", ptr); + stats.free_calls++; + tmp = (md_node_t *) ptr - 1; + if (MDfree(tmp)) { + memset(ptr, 'x', tmp->size); + FREE(tmp); /* only free if safe to do so */ + } +} + +void dump_malloc_data (outbuffer_t * ob) +{ + int net; + + net = stats.alloc_calls - stats.free_calls; + outbuf_add(ob, "using debug malloc:\n\n"); + outbuf_addv(ob, "total malloc'd: %10lu\n", total_malloced); + outbuf_addv(ob, "high water mark: %10lu\n", hiwater); + outbuf_addv(ob, "overhead: %10lu\n", + (MD_TABLE_SIZE * sizeof(md_node_t *)) + (net * MD_OVERHEAD)); + outbuf_addv(ob, "#alloc calls: %10lu\n", stats.alloc_calls); + outbuf_addv(ob, "#free calls: %10lu\n", stats.free_calls); + outbuf_addv(ob, "#alloc - #free: %10lu\n", net); + outbuf_addv(ob, "#realloc calls: %10lu\n", stats.realloc_calls); +} diff --git a/fluffos-2.23-ds03/debugmalloc.h b/fluffos-2.23-ds03/debugmalloc.h new file mode 100644 index 0000000..af4052b --- /dev/null +++ b/fluffos-2.23-ds03/debugmalloc.h @@ -0,0 +1,21 @@ +#ifndef DEBUGMALLOC_H +# define DEBUGMALLOC_H +# ifdef DEBUGMALLOC +void *debugmalloc (int, int, char *); +void *debugrealloc (void *, int, int, char *); +void *debugcalloc (int, int, int, char *); +void debugfree (void *); + +void debugmalloc_init (void); +void dump_malloc_data (outbuffer_t *); + +# ifdef DEBUGMALLOC_EXTENSIONS +void set_malloc_mask (int); +char *dump_debugmalloc (char *, int); +# endif +# else + /* not DEBUGMALLOC */ +# undef DEBUGMALLOC_EXTENSIONS +# undef CHECK_MEMORY +# endif +#endif diff --git a/fluffos-2.23-ds03/disassembler.c b/fluffos-2.23-ds03/disassembler.c new file mode 100644 index 0000000..fbf0d56 --- /dev/null +++ b/fluffos-2.23-ds03/disassembler.c @@ -0,0 +1,696 @@ +/* + * Dump information about a program, optionally disassembling it. + */ + +#include "std.h" +#include "lpc_incl.h" +#include "efuns_incl.h" +#include "simul_efun.h" +#include "comm.h" +#include "lex.h" +#include "file.h" +#include "program.h" + +#ifdef F_DUMP_PROG +void dump_prog (program_t *, const char *, int); +static void disassemble (FILE *, char *, int, int, program_t *); +static const char *disassem_string (const char *); +static int CDECL short_compare (CONST void *, CONST void *); +static void dump_line_numbers (FILE *, program_t *); + +void +f_dump_prog (void) +{ + program_t *prog; + const char *where; + int d; + object_t *ob; + int narg = st_num_arg; + + if (st_num_arg == 2) { + ob = sp[-1].u.ob; + d = sp->u.number; + where = 0; + } else if (st_num_arg == 3) { + ob = sp[-2].u.ob; + d = sp[-1].u.number; + where = (sp->type == T_STRING) ? sp->u.string : 0; + } else { + ob = sp->u.ob; + d = 0; + where = 0; + } + if (!(prog = ob->prog)) { + error("No program for object.\n"); + } else { + if (!where) { + where = "/PROG_DUMP"; + } + dump_prog(prog, where, d); + } + pop_n_elems(narg); +} + +/* Current flags: + * 1 - do disassembly + * 2 - dump line number table + */ +void +dump_prog (program_t * prog, const char * fn, int flags) +{ + const char *fname; + FILE *f; + int i, j; + int num_funcs_total; + + fname = check_valid_path(fn, current_object, "dumpallobj", 1); + + if (!fname) { + error("Invalid path '%s' for writing.\n", fn); + return; + } + f = fopen(fname, "w"); + if (!f) { + error("Unable to open '/%s' for writing.\n", fname); + return; + } + fprintf(f, "NAME: /%s\n", prog->filename); + fprintf(f, "INHERITS:\n"); + fprintf(f, "\tname fio vio\n"); + fprintf(f, "\t---------------- --- ---\n"); + for (i = 0; i < prog->num_inherited; i++) + fprintf(f, "\t%-20s %5d %5d\n", + prog->inherit[i].prog->filename, + prog->inherit[i].function_index_offset, + prog->inherit[i].variable_index_offset + ); + fprintf(f, "PROGRAM:"); + for (i = 0; i < prog->program_size; i++) { + if (i % 16 == 0) + fprintf(f, "\n\t%04x: ", (unsigned int) i); + fprintf(f, "%02d ", (unsigned char) prog->program[i]); + } + fputc('\n', f); + fprintf(f, "FUNCTIONS:\n"); + fprintf(f, " name offset flags fio # locals # args\n"); + fprintf(f, " --------------------- ------ ------- --- -------- ------\n"); + num_funcs_total = prog->last_inherited + prog->num_functions_defined; + + for (i = 0; i < num_funcs_total; i++) { + char sflags[8]; + int flags; + int runtime_index; + function_t *func_entry = find_func_entry(prog, i); + register int low, high, mid; + + + flags = prog->function_flags[i]; + if (flags & FUNC_ALIAS) { + runtime_index = flags & ~FUNC_ALIAS; + sflags[4] = 'a'; + } + else { + runtime_index = i; + sflags[4] = '-'; + } + + flags = prog->function_flags[runtime_index]; + + sflags[0] = (flags & FUNC_INHERITED) ? 'i' : '-'; + sflags[1] = (flags & FUNC_UNDEFINED) ? 'u' : '-'; + sflags[2] = (flags & FUNC_STRICT_TYPES) ? 's' : '-'; + sflags[3] = (flags & FUNC_PROTOTYPE) ? 'p' : '-'; + sflags[5] = (flags & FUNC_TRUE_VARARGS) ? 'V' : '-'; + sflags[6] = (flags & FUNC_VARARGS) ? 'v' : '-'; + sflags[7] = '\0'; + + if (flags & FUNC_INHERITED) { + low = 0; + high = prog->num_inherited - 1; + while (high > low) { + mid = (low + high + 1)/2; + if (prog->inherit[mid].function_index_offset > runtime_index) + high = mid -1; + else low = mid; + } + + fprintf(f, "%4d: %-20s %5d %7s %5d\n", + i, func_entry->funcname, + low, + sflags, + runtime_index - prog->inherit[low].function_index_offset); + } else { + + fprintf(f, "%4d: %-20s %5d %7s %7d %5d\n", + i, func_entry->funcname, + runtime_index - prog->last_inherited + ,sflags, + func_entry->num_arg, + func_entry->num_local); + } + } + fprintf(f, "VARIABLES:\n"); + for (i = 0; i < prog->num_variables_defined; i++) + fprintf(f, "%4d: %-12s\n", i, + prog->variable_table[i]); + fprintf(f, "STRINGS:\n"); + for (i = 0; i < prog->num_strings; i++) { + fprintf(f, "%4d: ", i); + for (j = 0; j < 32; j++) { + char c; + + if (!(c = prog->strings[i][j])) + break; + else if (c == '\n') + fprintf(f, "\\n"); + else + fputc(c, f); + } + fputc('\n', f); + } + + if (flags & 1) { + fprintf(f, "\n;;; *** Disassembly ***\n"); + disassemble(f, prog->program, 0, prog->program_size, prog); + } + if (flags & 2) { + fprintf(f, "\n;;; *** Line Number Info ***\n"); + dump_line_numbers(f, prog); + } + fclose(f); +} + +static const char *disassem_string (const char * str) +{ + static char buf[30]; + char *b; + int i; + + if (!str) + return "0"; + + b = buf; + for (i = 0; i < 29; i++) { + if (!str[i]) + break; + if (str[i] == '\n') { + *b++ = '\\'; + *b++ = 'n'; + } else { + *b++ = str[i]; + } + } + *b++ = 0; + return buf; +} + +#define NUM_FUNS (prog->num_functions_defined + prog->last_inherited) +#define NUM_FUNS_D prog->num_functions_defined +#define VARS prog->variable_names +#define NUM_VARS prog->num_variables_total +#define STRS prog->strings +#define NUM_STRS prog->num_strings +#define CLSS prog->classes + +static int CDECL +short_compare (CONST void * a, CONST void * b) +{ + int x = *(unsigned short *)a; + int y = *(unsigned short *)b; + + return x - y; +} + +static const char *pushes[] = { "string", "number", "global", "local" }; + +static void +disassemble (FILE * f, char * code, int start, int end, program_t * prog) +{ + extern int num_simul_efun; + + long i, j, instr, iarg, is_efun, ri; + unsigned short sarg; + unsigned short offset; + char *pc, buff[2048]; + int next_func; + + short *offsets; + + if (start == 0) { + /* sort offsets of functions */ + offsets = (short *) malloc(NUM_FUNS_D * 2 * sizeof(short)); + for (i = 0; i < NUM_FUNS_D; i++) { + ri = i + prog->last_inherited; + + if (prog->function_flags[ri] & FUNC_NO_CODE) { + offsets[i << 1] = end + 1; + } + else { + offsets[i << 1] = prog->function_table[i].address; + } + offsets[(i << 1) + 1] = i; + } +#ifdef _SEQUENT_ + qsort((void *) &offsets[0], +#else + qsort((char *) &offsets[0], +#endif + NUM_FUNS_D, sizeof(short) * 2, short_compare); + next_func = 0; + } else { + offsets = 0; + next_func = -1; + } + + pc = code + start; + + while ((pc - code) < end) { + if ((next_func >= 0) && ((pc - code) >= offsets[next_func])) { + fprintf(f, "\n;; Function %s\n", prog->function_table[offsets[next_func + 1]].funcname); + next_func += 2; + if (next_func >= ( NUM_FUNS_D * 2)) + next_func = -1; + } + + fprintf(f, "%04x: ", (unsigned) (pc - code)); + + is_efun = (instr = EXTRACT_UCHAR(pc)) >= BASE; + + pc++; + buff[0] = 0; + sarg = 0; + + switch (instr) { + case F_PUSH: + fprintf(f, "push "); + i = EXTRACT_UCHAR(pc++); + while (i--) { + j = EXTRACT_UCHAR(pc++); + fprintf(f, "%s %ld", pushes[(j & PUSH_WHAT) >> 6], + j & PUSH_MASK); + if (i) + fprintf(f, ", "); + else break; + } + fprintf(f, "\n"); + continue; + /* Single numeric arg */ + case F_BRANCH_NE: + case F_BRANCH_GE: + case F_BRANCH_LE: + case F_BRANCH_EQ: + case F_BRANCH: + case F_BRANCH_WHEN_ZERO: + case F_BRANCH_WHEN_NON_ZERO: +#ifdef F_LOR + case F_LOR: + case F_LAND: +#endif + COPY_SHORT(&sarg, pc); + offset = (pc - code) + (unsigned short) sarg; + sprintf(buff, "%04x (%04x)", (unsigned) sarg, (unsigned) offset); + pc += 2; + break; + + case F_NEXT_FOREACH: + case F_BBRANCH_LT: + COPY_SHORT(&sarg, pc); + offset = (pc - code) - (unsigned short) sarg; + sprintf(buff, "%04x (%04x)", (unsigned) sarg, (unsigned) offset); + pc += 2; + break; + + case F_FOREACH: + { + int flags = EXTRACT_UCHAR(pc++); + const char *left = "local", *right = "local"; + + if (flags & FOREACH_LEFT_GLOBAL) + left = "global"; + if (flags & FOREACH_RIGHT_GLOBAL) + right = "global"; + if (flags & FOREACH_REF) { + if (flags & FOREACH_MAPPING) + right = "ref"; + else + left = "ref"; + } + + if (flags & FOREACH_MAPPING) { + char *tmp = pc++; + sprintf(buff, "(mapping) %s %i, %s %i", + left, EXTRACT_UCHAR(tmp), right, EXTRACT_UCHAR(pc++)); + } else { + sprintf(buff, "(array) %s %i", left, EXTRACT_UCHAR(pc++)); + } + break; + } + + case F_BBRANCH_WHEN_ZERO: + case F_BBRANCH_WHEN_NON_ZERO: + case F_BBRANCH: + COPY_SHORT(&sarg, pc); + offset = (pc - code) - (unsigned short) sarg; + sprintf(buff, "%04x (%04x)", (unsigned) sarg, (unsigned) offset); + pc += 2; + break; + +#ifdef F_JUMP + case F_JUMP: +#endif +#ifdef F_JUMP_WHEN_ZERO + case F_JUMP_WHEN_ZERO: + case F_JUMP_WHEN_NON_ZERO: +#endif + case F_CATCH: + COPY_SHORT(&sarg, pc); + sprintf(buff, "%04x", (unsigned) sarg); + pc += 2; + break; + + case F_AGGREGATE: + case F_AGGREGATE_ASSOC: + COPY_SHORT(&sarg, pc); + sprintf(buff, "%d", sarg); + pc += 2; + break; + + case F_MAKE_REF: + case F_KILL_REFS: + case F_MEMBER: + case F_MEMBER_LVALUE: + sprintf(buff, "%d", EXTRACT_UCHAR(pc++)); + break; + + case F_EXPAND_VARARGS: + { + int which = EXTRACT_UCHAR(pc++); + if (which) { + sprintf(buff, "%d from top of stack", which); + } else { + strcpy(buff, "top of stack"); + } + } + break; + + case F_NEW_EMPTY_CLASS: + case F_NEW_CLASS: + { + int which = EXTRACT_UCHAR(pc++); + + strcpy(buff, STRS[CLSS[which].classname]); + break; + } + + case F_CALL_FUNCTION_BY_ADDRESS: + COPY_SHORT(&sarg, pc); + pc += 3; + if (sarg < NUM_FUNS) + sprintf(buff, "%-12s %5d", function_name(prog, sarg), + sarg); + else + sprintf(buff, "", sarg); + break; + + case F_CALL_INHERITED: + { + program_t *newprog; + + newprog = (prog->inherit + EXTRACT_UCHAR(pc++))->prog; + COPY_SHORT(&sarg, pc); + pc += 3; + if (sarg < (newprog->num_functions_defined + + newprog->last_inherited)) + sprintf(buff, "%30s::%-12s %5d", newprog->filename, + function_name(newprog, sarg), sarg); + else sprintf(buff, "", newprog->filename, + sarg); + break; + } + case F_GLOBAL_LVALUE: + case F_GLOBAL: + if ((unsigned) (iarg = EXTRACT_UCHAR(pc)) < NUM_VARS) + sprintf(buff, "%s", variable_name(prog, iarg)); + else + sprintf(buff, "", iarg); + pc++; + break; + + case F_LOOP_INCR: + sprintf(buff, "LV%d", EXTRACT_UCHAR(pc)); + pc++; + break; + case F_WHILE_DEC: + COPY_SHORT(&sarg, pc + 1); + offset = (pc - code) - (unsigned short) sarg; + sprintf(buff, "LV%d--, branch %04x (%04x)", EXTRACT_UCHAR(pc), + (unsigned) sarg, (unsigned) offset); + pc += 3; + break; + case F_TRANSFER_LOCAL: + case F_LOCAL: + case F_LOCAL_LVALUE: + case F_VOID_ASSIGN_LOCAL: + case F_REF: + case F_REF_LVALUE: + sprintf(buff, "LV%d", EXTRACT_UCHAR(pc)); + pc++; + break; + case F_LOOP_COND_NUMBER: + i = EXTRACT_UCHAR(pc++); + COPY_INT(&iarg, pc); + pc += 4; + COPY_SHORT(&sarg, pc); + offset = (pc - code) - (unsigned short) sarg; + pc += 2; + sprintf(buff, "LV%ld < %ld bbranch_when_non_zero %04x (%04x)", + i, iarg, sarg, offset); + break; + case F_LOOP_COND_LOCAL: + i = EXTRACT_UCHAR(pc++); + iarg = *pc++; + COPY_SHORT(&sarg, pc); + offset = (pc - code) - (unsigned short) sarg; + pc += 2; + sprintf(buff, "LV%ld < LV%ld bbranch_when_non_zero %04x (%04x)", + i, iarg, sarg, offset); + break; + case F_STRING: + COPY_SHORT(&sarg, pc); + if (sarg < NUM_STRS) + sprintf(buff, "\"%s\"", disassem_string(STRS[sarg])); + else + sprintf(buff, "", sarg); + pc += 2; + break; + case F_SHORT_STRING: + if (EXTRACT_UCHAR(pc) < NUM_STRS) + sprintf(buff, "\"%s\"", disassem_string(STRS[EXTRACT_UCHAR(pc)])); + else + sprintf(buff, "", EXTRACT_UCHAR(pc)); + pc++; + break; + case F_SIMUL_EFUN: + COPY_SHORT(&sarg, pc); + if (sarg >= num_simul_efun) + sprintf(buff, " %d\n", sarg, pc[2]); + else + sprintf(buff, "\"%s\" %d", simuls[sarg].func->funcname, pc[2]); + pc += 3; + break; + + case F_FUNCTION_CONSTRUCTOR: + switch (EXTRACT_UCHAR(pc++)) { + case FP_SIMUL: + LOAD_SHORT(sarg, pc); + sprintf(buff, " \"%s\"", simuls[sarg].func->funcname); + break; + case FP_EFUN: + LOAD_SHORT(sarg, pc); + sprintf(buff, " %s", instrs[sarg].name); + break; + case FP_LOCAL: + LOAD_SHORT(sarg, pc); + if (sarg < NUM_FUNS) + sprintf(buff, " %s", function_name(prog, sarg)); + else + sprintf(buff, " ", sarg); + break; + case FP_FUNCTIONAL: + case FP_FUNCTIONAL | FP_NOT_BINDABLE: + sprintf(buff, "\nCode:", pc[0]); + pc += 3; + break; + case FP_ANONYMOUS: + case FP_ANONYMOUS | FP_NOT_BINDABLE: + COPY_SHORT(&sarg, &pc[2]); + sprintf(buff, "\nCode:", + pc[0], pc[1], (pc + 3 + sarg - code)); + pc += 4; + break; + } + break; + + case F_NUMBER: + + COPY_INT(&iarg, pc); + sprintf(buff, "%ld", iarg); +#if SIZEOF_LONG == 4 + pc += 4; +#else + pc += 8; +#endif + break; + + case F_REAL: + { + float farg; + + COPY_FLOAT(&farg, pc); + sprintf(buff, "%f", farg); + pc += 4; + break; + } + + case F_SSCANF: + case F_PARSE_COMMAND: + case F_BYTE: + sprintf(buff, "%d", EXTRACT_UCHAR(pc)); + pc++; + break; + + case F_NBYTE: + sprintf(buff, "-%d", EXTRACT_UCHAR(pc)); + pc++; + break; + + case F_SWITCH: + { + unsigned char ttype; + unsigned short stable, etable, def; + unsigned int addr; + char *aptr; + char *parg; + + ttype = EXTRACT_UCHAR(pc); + COPY_SHORT(&stable, pc + 1); + COPY_SHORT(&etable, pc + 3); + COPY_SHORT(&def, pc + 5); + addr = pc - code; + aptr = pc; + + fprintf(f, "switch\n"); + fprintf(f, " type: %02x table: %04x-%04x deflt: %04x\n", + (unsigned) ttype, addr + stable, + addr + etable, addr + def); + /* recursively disassemble stuff in switch */ + disassemble(f, code, pc - code + 7, addr + stable, prog); + + /* now print out table - ugly... */ + fprintf(f, " switch table (for %04x)\n", + (unsigned) (pc - code - 1)); + if (ttype == 0xfe) + ttype = 0; /* direct lookup */ + else if (ttype >> 4 == 0xf) + ttype = 1; /* normal int */ + else + ttype = 2; /* string */ + + pc += stable; + if (ttype == 0) { + i = 0; + while (pc < aptr + etable - 4) { + COPY_SHORT(&sarg, pc); + fprintf(f, "\t%2ld: %04x\n", i++, addr + sarg); + pc += 2; + } + COPY_INT(&iarg, pc); + fprintf(f, "\tminval = %ld\n", iarg); + pc += 4; + } else { + while (pc < aptr + etable) { + COPY_PTR(&parg, pc); + COPY_SHORT(&sarg, pc + SIZEOF_PTR); + if (ttype == 1 || !parg) { + if (sarg == 1) + fprintf(f, "\t%-4ld\t\n", (long)parg); + else + fprintf(f, "\t%-4ld\t%04x\n", (long)parg, addr+sarg); + } else { + fprintf(f, "\t\"%s\"\t%04x\n", + disassem_string(parg), addr+sarg); + } + pc += 2 + SIZEOF_PTR; + } + } + continue; + } + case F_EFUNV: + sprintf(buff, "%d", EXTRACT_UCHAR(pc++)); + instr = EXTRACT_UCHAR(pc++) + ONEARG_MAX; + break; + case F_EFUN0: + case F_EFUN1: + case F_EFUN2: + case F_EFUN3: + instr = EXTRACT_UCHAR(pc++) + ONEARG_MAX; + if (instrs[instr].min_arg != instrs[instr].max_arg) { + sprintf(buff, "%ld", instr - F_EFUN0); + } + break; + case 0: + fprintf(f, "*** zero opcode ***\n"); + continue; + } + fprintf(f, "%s %s\n", query_instr_name(instr), buff); + } + + if (offsets) + free(offsets); +} + +#define INCLUDE_DEPTH 10 + +static void +dump_line_numbers (FILE * f, program_t * prog) { + unsigned short *fi; + unsigned char *li_start; + unsigned char *li_end; + unsigned char *li; + int addr; + int sz; + ADDRESS_TYPE s; + + if (!prog->line_info) { + fprintf(f, "Failed to load line numbers\n"); + return; + } + + fi = prog->file_info; + li_end = (unsigned char *)(((char *)fi) + fi[0]); + li_start = (unsigned char *)(fi + fi[1]); + + fi += 2; + fprintf(f, "\nabsolute line -> (file, line) table:\n"); + while (fi < (unsigned short *)li_start) { + fprintf(f, "%i lines from %i [%s]\n", fi[0], fi[1], + prog->strings[fi[1]-1]); + fi += 2; + } + + li = li_start; + addr = 0; + fprintf(f,"\naddress -> absolute line table:\n"); + while (li < li_end) { + sz = *li++; +#if !defined(USE_32BIT_ADDRESSES) + COPY_SHORT(&s, li); +#else + COPY_INT(&s, li); +#endif + li += sizeof(ADDRESS_TYPE); + fprintf(f, "%4x-%4x: %i\n", addr, addr + sz - 1, s); + addr += sz; + } +} +#endif diff --git a/fluffos-2.23-ds03/dtrace_compile.c b/fluffos-2.23-ds03/dtrace_compile.c new file mode 100644 index 0000000..c41389c --- /dev/null +++ b/fluffos-2.23-ds03/dtrace_compile.c @@ -0,0 +1,13 @@ +#include +#include "std.h" +int main(){ +#ifdef DTRACE +#ifdef _LP64 + system("dtrace -G -64 -s fluffos.d obj/*.o > /dev/null"); +#else + system("dtrace -G -32 -s fluffos.d obj/*.o > /dev/null"); +#endif + printf("fluffos.o"); +#endif + return 0; +} diff --git a/fluffos-2.23-ds03/dumpstat.c b/fluffos-2.23-ds03/dumpstat.c new file mode 100644 index 0000000..a42391a --- /dev/null +++ b/fluffos-2.23-ds03/dumpstat.c @@ -0,0 +1,164 @@ +#include "std.h" +#include "dumpstat.h" +#include "comm.h" +#include "file.h" + +/* + * Write statistics about objects on file. + */ + +static int sumSizes (mapping_t *, mapping_node_t *, void *); +static int svalue_size (svalue_t *); + +static int sumSizes (mapping_t * m, mapping_node_t * elt, void * tp) +{ + int *t = (int *)tp; + + *t += (svalue_size(&elt->values[0]) + svalue_size(&elt->values[1])); + *t += sizeof(mapping_node_t); + return 0; +} + +int depth = 0; + +static int svalue_size (svalue_t * v) +{ + int i, total; + + switch (v->type) { + case T_OBJECT: + case T_REAL: + case T_NUMBER: + return 0; + case T_STRING: + return (strlen(v->u.string) + 1); + case T_ARRAY: + case T_CLASS: + if (++depth > 100) + return 0; + + /* first svalue is stored inside the array struct */ + total = sizeof(array_t) - sizeof(svalue_t); + for (i = 0; i < v->u.arr->size; i++) { + total += svalue_size(&v->u.arr->item[i]) + sizeof(svalue_t); + } + depth--; + return total; + case T_MAPPING: + if (++depth > 100) + return 0; + total = sizeof(mapping_t); + mapTraverse(v->u.map, sumSizes, &total); + depth--; + return total; + case T_FUNCTION: + { + svalue_t tmp; + tmp.type = T_ARRAY; + tmp.u.arr = v->u.fp->hdr.args; + + if (++depth > 100) + return 0; + + if (tmp.u.arr) + total = sizeof(funptr_hdr_t) + svalue_size(&tmp); + else + total = sizeof(funptr_hdr_t); + switch (v->u.fp->hdr.type) { + case FP_EFUN: + total += sizeof(efun_ptr_t); + break; + case FP_LOCAL | FP_NOT_BINDABLE: + total += sizeof(local_ptr_t); + break; + case FP_SIMUL: + total += sizeof(simul_ptr_t); + break; + case FP_FUNCTIONAL: + case FP_FUNCTIONAL | FP_NOT_BINDABLE: + total += sizeof(functional_t); + break; + } + + depth--; + return total; + } +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + /* first byte is stored inside the buffer struct */ + return sizeof(buffer_t) + v->u.buf->size - 1; +#endif + default: + //some freed value or a reference (!) to one (in all my test cases + //anyway), it will be removed by reclaim_objects later, Wodan + //fatal("Illegal type: %d\n", v->type); + ; + } + /* NOTREACHED */ + return 0; +} + +int data_size (object_t * ob) +{ + int total = 0, i; + + if (ob->prog) { + for (i = 0; i < ob->prog->num_variables_total; i++) { + depth = 0; + total += svalue_size(&ob->variables[i]) + sizeof(svalue_t); + } + } + return total; +} + +void dumpstat (const char * tfn) +{ + FILE *f; + object_t *ob; + const char *fn; +#ifdef F_SET_HIDE + int display_hidden; +#endif + + fn = check_valid_path(tfn, current_object, "dumpallobj", 1); + if (!fn) { + error("Invalid path '/%s' for writing.\n", tfn); + return; + } + f = fopen(fn, "w"); + if (!f) { + error("Unable to open '/%s' for writing.\n", fn); + return; + } + +#ifdef F_SET_HIDE + display_hidden = -1; +#endif + for (ob = obj_list; ob; ob = ob->next_all) { + int tmp; + +#ifdef F_SET_HIDE + if (ob->flags & O_HIDDEN) { + if (display_hidden == -1) + display_hidden = valid_hide(current_object); + if (!display_hidden) + continue; + } +#endif + /* FIXME */ + if (ob->prog && (ob->prog->ref == 1 || !(ob->flags & O_CLONE))) + tmp = ob->prog->total_size; + else + tmp = 0; + fprintf(f, "%-20s %ld ref %2d %s %s (%d)\n", ob->obname, + tmp + data_size(ob) + sizeof(object_t), ob->ref, + ob->flags & O_HEART_BEAT ? "HB" : " ", +#ifndef NO_ENVIRONMENT + ob->super ? ob->super->obname : "--", +#else + "--", +#endif + /* ob->cpu */ 0); + } + fclose(f); +} diff --git a/fluffos-2.23-ds03/dumpstat.h b/fluffos-2.23-ds03/dumpstat.h new file mode 100644 index 0000000..a7bbff6 --- /dev/null +++ b/fluffos-2.23-ds03/dumpstat.h @@ -0,0 +1,12 @@ +#ifndef DUMPSTAT_H +#define DUMPSTAT_H + +#include "lpc_incl.h" + +/* + * dumpstat.c + */ +int data_size (object_t *); +void dumpstat (const char *); + +#endif diff --git a/fluffos-2.23-ds03/ed.c b/fluffos-2.23-ds03/ed.c new file mode 100644 index 0000000..6f28010 --- /dev/null +++ b/fluffos-2.23-ds03/ed.c @@ -0,0 +1,3160 @@ +/* + * ed - standard editor + * ~~ + * Authors: Brian Beattie, Kees Bot, and others + * + * Copyright 1987 Brian Beattie Rights Reserved. + * Permission to copy or distribute granted under the following conditions: + * 1). No charge may be made other than reasonable charges for reproduction. + * 2). This notice must remain intact. + * 3). No further restrictions may be added. + * 4). Except meaningless ones. + * + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * TurboC mods and cleanup 8/17/88 RAMontante. + * Further information (posting headers, etc.) at end of file. + * RE stuff replaced with Spencerian version, sundry other bugfix+speedups + * Ian Phillipps. Version incremented to "5". + * _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + * Changed the program to use more of the #define's that are at the top of + * this file. Modified prntln() to print out a string instead of each + * individual character to make it easier to see if snooping a wizard who + * is in the editor. Got rid of putcntl() because of the change to strings + * instead of characters, and made a define with the name of putcntl() + * Incremented version to "6". + * Scott Grosch / Belgarath 08/10/91 + * _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + * + * ********--->> INDENTATION ONLINE !!!! <<----------**************** + * Indentation added by Ted Gaunt (aka Qixx) paradox@mcs.anl.gov + * help files added by Ted Gaunt + * '^' added by Ted Gaunt + * Note: this version compatible with v.3.0.34 (and probably all others too) + * but i've only tested it on v.3 please mail me if it works on your mud + * and if you like it! + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * + * Dworkin rewrote the Indentation algorithm, originally for Amylaar's driver, + * around 5/20/1992. + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * + * Inspiral grabbed indentation code from Amylaar, hacked it into MudOS version + * 0.9.18.17, around 12/11/1993. Added some hacks to provide proper support + * for "//" commenting, and took out a PROMPT define. + * + * ------------------------------------------------------------------------- + * Beek fixed Inspirals hacks, then later added the object_ed_* stuff. + * ------------------------------------------------------------------------ + * Isaac Charles (Hamlet) did some reworks 2008/March + * 1) Many ED_OUTPUTV() things combined for less calls to the output stuff. + * (this will be important with future changes and shouldn't hurt now) + * 2) added an APPLY_RECEIVE_ED to send output within the user ob before + * outputting to the user. + * Prototype: mixed receive_ed(string msg, string fname); + * If return is 0, it is a "pass" and normal output occurs. If return + * is 1, we assume receive_ed() called receive() or something else + * clever and the text is taken care of. If return is a string, + * that string is sent to the user rather than the original. + * If fname is 0, the incoming string is help text. In this case, + * an array of strings may also be returned, which will be separated by + * "more" statements. As above, if 1 is returned, no output, and if 0 + * is returned, normal output. + * 3) ed_start() and ed() now take an extra final argument telling + * how many lines on the user's screen. 'z' commands will then scroll + * that many lines (less 1 for the prompt). 'Z' commands scroll that many + * plus 5. Why? I dunno. Why was it double before? f_ed() and + * f_ed_start() do not require this arg. + * 5) Minor fixes: fixed indentation for foreach(), and for lines with only + * //. + * 6) Minor enhancements: z++ and z-- now work for double-forward or back. + * Added ED_INDENT_CASE (should 'case' be indented after switch?) and + * ED_INDENT_SPACES (how many spaces to indent with I) as defines in + * options.h. Their presence is optional. All additions to options.h + * are optional. Default behavior is mostly the same as the original ed. + */ + +#include "std.h" +#include "ed.h" +#include "comm.h" +#include "file.h" +#include "master.h" + +#ifndef ED_INDENT_SPACES +#define ED_INDENT_SPACES 4 +#endif + +#ifndef ED_TAB_WIDTH +#define ED_TAB_WIDTH 8 +#endif + +/* Regexp is Henry Spencer's package. WARNING: regsub is modified to return + * a pointer to the \0 after the destination string, and this program refers + * to the "private" reganch field in the struct regexp. + */ + +/* if you don't want ed, define OLD_ED and remove ed() from func_spec.c */ +#if defined(F_ED) || !defined(OLD_ED) + +/** Global variables **/ + +static int version = 601; + +static int EdErr = 0; + +static int append (int, int); +static int more_append (const char *); +static int ckglob (void); +static int deflt (int, int); +static int del (int, int); +static int dolst (int, int); +/* This seems completely unused; -Beek +static int esc (char **); +*/ + +static void do_output(char *); +static int doprnt (int, int); +static int prntln (char *, char *, int, int); +static int egets (char *, int, FILE *); +static int doread (int, const char *); +static int dowrite (int, int, const char *, int); +static int find (regexp *, int); +static char *getfn (int); +static int getnum (int); +static int getone (void); +static int getlst (void); +static ed_line_t *getptr (int); +static int getrhs (char *); +static int ins (const char *); +static int join (int, int); +static int move (int); +static int transfer (int); +static regexp *optpat (void); +static int set (void); +static void set_ed_buf (void); +static int subst (regexp *, char *, int, int); +static int docmd (int); +static int doglob (void); +static void free_ed_buffer (object_t *); +static void shift (char *); +static void indent (char *); +static int indent_code (void); +static void report_status (int); + +#ifndef OLD_ED +static char *object_ed_results (void); +static ed_buffer_t *add_ed_buffer (object_t *); +static void object_free_ed_buffer (void); +#endif + +static void print_help (int arg); +static void print_help2 (void); +static void count_blanks (int line); +static void _count_blanks (char *str, int blanks); + +static ed_buffer_t *current_ed_buffer; +static object_t *current_editor; /* the object responsible */ +outbuffer_t current_ed_results; + +#define ED_BUFFER (current_ed_buffer) +#ifdef OLD_ED +#define P_NET_DEAD (command_giver->interactive->iflags & NET_DEAD) +#else +#define P_NET_DEAD 0 /* objects are never net dead :) */ +#endif +#define P_NONASCII (ED_BUFFER->nonascii) +#define P_NULLCHAR (ED_BUFFER->nullchar) +#define P_TRUNCATED (ED_BUFFER->truncated) +#define P_FNAME (ED_BUFFER->fname) +#define P_FCHANGED (ED_BUFFER->fchanged) +#define P_NOFNAME (ED_BUFFER->nofname) +#define P_MARK (ED_BUFFER->mark) +#define P_OLDPAT (ED_BUFFER->oldpat) +#define P_LINE0 (ED_BUFFER->Line0) +#define P_CURLN (ED_BUFFER->CurLn) +#define P_CURPTR (ED_BUFFER->CurPtr) +#define P_LASTLN (ED_BUFFER->LastLn) +#define P_LINE1 (ED_BUFFER->Line1) +#define P_LINE2 (ED_BUFFER->Line2) +#define P_NLINES (ED_BUFFER->nlines) +#define P_HELPOUT (ED_BUFFER->helpout) +/* shiftwidth is meant to be a 4-bit-value that can be packed into an int + along with flags, therefore masks 0x1 ... 0x8 are reserved. */ +#define P_SHIFTWIDTH (ED_BUFFER->shiftwidth) +#define P_FLAGS (ED_BUFFER->flags) +#define NFLG_MASK 0x0010 +#define P_NFLG ( P_FLAGS & NFLG_MASK ) +#define LFLG_MASK 0x0020 +#define P_LFLG ( P_FLAGS & LFLG_MASK ) +#define PFLG_MASK 0x0040 +#define P_PFLG ( P_FLAGS & PFLG_MASK ) +#define EIGHTBIT_MASK 0x0080 +#define P_EIGHTBIT ( P_FLAGS & EIGHTBIT_MASK ) +#define AUTOINDFLG_MASK 0x0100 +#define P_AUTOINDFLG ( P_FLAGS & AUTOINDFLG_MASK ) +#define EXCOMPAT_MASK 0x0200 +#define P_EXCOMPAT ( P_FLAGS & EXCOMPAT_MASK ) +#define DPRINT_MASK 0x0400 +#define P_DPRINT ( P_FLAGS & DPRINT_MASK ) +#define VERBOSE_MASK 0x0800 +#define P_VERBOSE ( P_FLAGS & VERBOSE_MASK ) +#define SHIFTWIDTH_MASK 0x000f +#define ALL_FLAGS_MASK 0x0ff0 +#define P_APPENDING (ED_BUFFER->appending) +#define P_MORE (ED_BUFFER->moring) +#define P_LEADBLANKS (ED_BUFFER->leading_blanks) +#define P_CUR_AUTOIND (ED_BUFFER->cur_autoindent) +#define P_RESTRICT (ED_BUFFER->restricted) + + +static char inlin[ED_MAXLINE]; +static char *inptr; /* tty input buffer */ + +static struct tbl { + const char *t_str; + int t_and_mask; + int t_or_mask; +} *t, tbl[] = { + { "number", ~FALSE, NFLG_MASK }, + { "nonumber", ~NFLG_MASK, FALSE }, + { "list", ~FALSE, LFLG_MASK }, + { "nolist", ~LFLG_MASK, FALSE }, + { "print", ~FALSE, PFLG_MASK }, + { "noprint", ~PFLG_MASK, FALSE }, + { "eightbit", ~FALSE, EIGHTBIT_MASK }, + { "noeightbit", ~EIGHTBIT_MASK, FALSE }, + { "autoindent", ~FALSE, AUTOINDFLG_MASK }, + { "noautoindent", ~AUTOINDFLG_MASK, FALSE }, + { "excompatible", ~FALSE, EXCOMPAT_MASK }, + { "noexcompatible", ~EXCOMPAT_MASK, FALSE }, + { "dprint", ~FALSE, DPRINT_MASK }, + { "nodprint", ~DPRINT_MASK, FALSE }, + { "verbose", ~FALSE, VERBOSE_MASK }, + { "noverbose", ~VERBOSE_MASK, FALSE }, +}; + + +/*________ Macros ________________________________________________________*/ + +#ifndef max +#define max(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#define nextln(l) ((l)+1 > P_LASTLN ? 0 : (l)+1) +#define prevln(l) ((l)-1 < 0 ? P_LASTLN : (l)-1) + +#define gettxtl(lin) ((lin)->l_buff) +#define gettxt(num) (gettxtl( getptr(num) )) + +#define getnextptr(p) ((p)->l_next) +#define getprevptr(p) ((p)->l_prev) + +#define setCurLn( lin ) ( P_CURPTR = getptr( P_CURLN = (lin) ) ) +#define nextCurLn() ( P_CURLN = nextln(P_CURLN), P_CURPTR = getnextptr( P_CURPTR ) ) +#define prevCurLn() ( P_CURLN = prevln(P_CURLN), P_CURPTR = getprevptr( P_CURPTR ) ) + +#define clrbuf() del(1, P_LASTLN) + +#define Skip_White_Space {while (*inptr==SP || *inptr==HT) inptr++;} + +#define relink(a, x, y, b) { (x)->l_prev = (a); (y)->l_next = (b); } + + +/*________ functions ______________________________________________________*/ + + +/* append.c */ + + +static int append (int line, int glob) +{ + if (glob) + return SYNTAX_ERROR; + setCurLn(line); + P_APPENDING = 1; + if (P_NFLG) + ED_OUTPUTV(ED_DEST, "%6d. ", P_CURLN + 1); + if (P_CUR_AUTOIND) + ED_OUTPUTV(ED_DEST, "%*s", P_LEADBLANKS, ""); +#ifdef OLD_ED + set_prompt("*\b"); +#endif + return 0; +} + +static int more_append (const char *str) +{ + if (str[0] == '.' && str[1] == '\0') { + P_APPENDING = 0; +#ifdef OLD_ED + set_prompt(":"); +#endif + return (0); + } + if (P_NFLG) + ED_OUTPUTV(ED_DEST, "%6d. ", P_CURLN + 2); + if (P_CUR_AUTOIND) { + int i; + int less_indent_flag = 0; + + while (*str == '\004' || *str == '\013') { + str++; + P_LEADBLANKS -= P_SHIFTWIDTH; + if (P_LEADBLANKS < 0) + P_LEADBLANKS = 0; + less_indent_flag = 1; + } + for (i = 0; i < P_LEADBLANKS;) + inlin[i++] = ' '; + strncpy(inlin + P_LEADBLANKS, str, ED_MAXLINE - P_LEADBLANKS); + inlin[ED_MAXLINE - 1] = '\0'; + _count_blanks(inlin, 0); + ED_OUTPUTV(ED_DEST, "%*s", P_LEADBLANKS, ""); + if (!*str && less_indent_flag) + return 0; + str = inlin; + } + if (ins(str) < 0) + return (MEM_FAIL); + return 0; +} + +static void count_blanks (int line) +{ + _count_blanks(gettxtl(getptr(line)), 0); +} + +static void _count_blanks (char * str, int blanks) +{ + for (; *str; str++) { + if (*str == ' ') + blanks++; + else if (*str == '\t') + blanks += ED_TAB_WIDTH - blanks % ED_TAB_WIDTH; + else + break; + } + P_LEADBLANKS = blanks < ED_MAXLINE ? blanks : ED_MAXLINE; +} + +/* ckglob.c */ + +static int ckglob() +{ + regexp *glbpat; + char c, delim, *lin; + int num; + ed_line_t *ptr; + + c = *inptr; + + if (c != 'g' && c != 'v') + return (0); + if (deflt(1, P_LASTLN) < 0) + return (BAD_LINE_RANGE); + + delim = *++inptr; + if (delim <= ' ') + return (EDERR); + + glbpat = optpat(); + if (*inptr == delim) + inptr++; + ptr = getptr(1); + for (num = 1; num <= P_LASTLN; num++) { + ptr->l_stat &= ~LGLOB; + if (P_LINE1 <= num && num <= P_LINE2) { + /* + * we might have got a NULL pointer if the supplied pattern was + * invalid + */ + if (glbpat) { + lin = gettxtl(ptr); + if (regexec(glbpat, lin)) { + if (c == 'g') + ptr->l_stat |= LGLOB; + } else { + if (c == 'v') + ptr->l_stat |= LGLOB; + } + } + } + ptr = getnextptr(ptr); + } + return (1); +} + + +/* deflt.c + * Set P_LINE1 & P_LINE2 (the command-range delimiters) if the file is + * empty; Test whether they have valid values. + */ + +static int deflt (int def1, int def2) +{ + if (P_NLINES == 0) { + P_LINE1 = def1; + P_LINE2 = def2; + } + return ((P_LINE1 > P_LINE2 || P_LINE1 <= 0) ? EDERR : 0); +} + + +/* del.c */ + +/* One of the calls to this function tests its return value for an error + * condition. But del doesn't return any error value, and it isn't obvious + * to me what errors might be detectable/reportable. To silence a warning + * message, I've added a constant return statement. -- RAM + * ... It could check to<=P_LASTLN ... igp + * ... Ok...and it corrects from (or to) > P_LASTLN also -- robo + */ + +static int del (int from, int to) +{ + ed_line_t *first, *last, *next, *tmp; + + if (P_LASTLN == 0) + return (0); /* nothing to delete */ + if (from > P_LASTLN) + from = P_LASTLN; + if (to > P_LASTLN) + to = P_LASTLN; + if (from < 1) + from = 1; + if (to < 1) + to = 1; + first = getprevptr(getptr(from)); + last = getnextptr(getptr(to)); + next = first->l_next; + while (next != last && next != &P_LINE0) { + tmp = next->l_next; + FREE((char *) next); + next = tmp; + } + relink(first, last, first, last); + P_LASTLN -= (to - from) + 1; + setCurLn(prevln(from)); + return (0); +} + + +static int dolst (int line1, int line2) +{ + int oldflags = P_FLAGS, p; + + P_FLAGS |= LFLG_MASK; + p = doprnt(line1, line2); + P_FLAGS = oldflags; + return p; +} + + +/* esc.c + * Map escape sequences into their equivalent symbols. Returns the + * correct ASCII character. If no escape prefix is present then s + * is untouched and *s is returned, otherwise **s is advanced to point + * at the escaped character and the translated character is returned. + */ +/* UNUSED ---- +static int esc (char ** s) +{ + register int rval; + + if (**s != ESCAPE) { + rval = **s; + } else { + (*s)++; + switch (islower(**s) ? toupper(**s) : **s) { + case '\000': + rval = ESCAPE; + break; + case 'S': + rval = ' '; + break; + case 'N': + rval = '\n'; + break; + case 'T': + rval = '\t'; + break; + case 'B': + rval = '\b'; + break; + case 'R': + rval = '\r'; + break; + default: + rval = **s; + break; + } + } + return (rval); +} +*/ + +/* doprnt.c */ +static int doprnt (int from, int to) +{ +#if (BUFFER_SIZE) > (ED_MAXLINE) + char outbf[BUFFER_SIZE]; +#else + char outbf[ED_MAXLINE]; +#endif + char tmp[ED_MAXLINE]; + char *pos = outbf; + int count; + + from = (from < 1) ? 1 : from; + to = (to > P_LASTLN) ? P_LASTLN : to; + + if (to != 0) { + setCurLn(from); + while (P_CURLN <= to) { + count = prntln(gettxtl(P_CURPTR), tmp, P_LFLG, + (P_NFLG ? P_CURLN : 0)); + if (P_NET_DEAD) + break; +#if (BUFFER_SIZE) > (ED_MAXLINE) + if((pos + count + 1) >= (outbf + BUFFER_SIZE)) { +#else + if((pos + count + 1) >= (outbf + ED_MAXLINE)) { +#endif + do_output(outbf); + pos = outbf; + } + + if(pos > outbf) + *(pos++) = '\n'; + strcpy(pos, tmp); + pos += count; + + if(P_CURLN == to) { + do_output(outbf); + break; + } + + nextCurLn(); + } + } + return (0); +} + +static void do_output(char *str) { +#ifdef RECEIVE_ED + svalue_t *ret; + + copy_and_push_string(str); + copy_and_push_string(P_FNAME); + // One could argue that this should be safe_apply() + // Pro: ed continues to work with a runtiming receive_ed() + // Con: "I wrote a receive_ed()! Why does the driver ignore it??" + ret = apply(APPLY_RECEIVE_ED, ED_DEST, 2, ORIGIN_DRIVER); + if(!ret) + ED_OUTPUTV(ED_DEST, "%s\n", str); + else if(ret->type == T_NUMBER) { + // if 0, output ourselves, else they handled it, do nothing. + if(ret->u.number == 0) // "pass" + ED_OUTPUTV(ED_DEST, "%s\n", str); + } + else if(ret->type == T_STRING) { + ED_OUTPUTV(ED_DEST, "%s\n", ret->u.string); + } +#else + ED_OUTPUTV(ED_DEST, "%s\n", str); +#endif +} + +static void free_ed_buffer (object_t * who) +{ + clrbuf(); +#ifdef OLD_ED + if (ED_BUFFER->write_fn) { + object_t *exit_ob = ED_BUFFER->exit_ob; + FREE(ED_BUFFER->write_fn); + free_object(&exit_ob, "ed EOF"); + } + if (ED_BUFFER->exit_fn) { + char *exit_fn = ED_BUFFER->exit_fn; + object_t *exit_ob = ED_BUFFER->exit_ob; + + if (P_OLDPAT) + FREE((char *) P_OLDPAT); + FREE((char *) ED_BUFFER); + who->interactive->ed_buffer = 0; + set_prompt("> "); + + /* make this "safe" */ + safe_apply(exit_fn, exit_ob, 0, ORIGIN_INTERNAL); + FREE(exit_fn); + free_object(&exit_ob, "ed EOF"); + return; + } +#endif + + if (P_OLDPAT) + FREE((char *) P_OLDPAT); +#ifdef OLD_ED + FREE((char *) ED_BUFFER); + who->interactive->ed_buffer = 0; + set_prompt("> "); +#else + object_free_ed_buffer(); +#endif + return; +} + +#define putcntl(X) *line++ = '^'; *line++ = (X) ? ((*str&31)|'@') : '?' + +static int prntln (char * str, char * outstr, int vflg, int lineno) +{ + char *line, start[ED_MAXLINE + 100]; //need space for the bloody tabs + line = start; + + if (lineno) { + sprintf(line, "%3d ", lineno); + line += 5; + } + while (*str && *str != NL) { + if ((line - start) >= (ED_MAXLINE-1)) { + line = start + ED_MAXLINE - 33; + line += sprintf(line, "messing up end of a long line\n"); + break; + } + if (*str < ' ' || *str >= DEL) { + switch (*str) { + case '\t': + /* have to be smart about this or the indentor will fail */ + *line++ = ' '; + while ((line - start) % ED_TAB_WIDTH) + *line++ = ' '; + break; + case DEL: + putcntl(0); + break; + default: + putcntl(1); + break; + } + } else + *line++ = *str; + str++; + } +#ifndef NO_END_DOLLAR_SIGN + if (vflg) + *line++ = '$'; +#endif + *line = EOS; + + strcpy(outstr, start); + return (line - start); +} + +/* egets.c */ + +static int egets (char * str, int size, FILE * stream) +{ + int c = 0, count; + char *cp; + + for (count = 0, cp = str; size > count;) { + c = getc(stream); + if (c == EOF) { + *cp = EOS; + if (count) + ED_OUTPUT(ED_DEST, "[Incomplete last line]\n"); + return (count); + } else if (c == NL) { + *cp = EOS; + return (++count); + } else if (c == 0) + P_NULLCHAR++; /* count nulls */ + else { + if (c > 127) { + if (!P_EIGHTBIT)/* if not saving eighth bit */ + c = c & 127;/* strip eigth bit */ + P_NONASCII++; /* count it */ + } + *cp++ = c; /* not null, keep it */ + count++; + } + } + str[count - 1] = EOS; + if (c != NL) { + ED_OUTPUT(ED_DEST, "truncating line\n"); + P_TRUNCATED++; + while ((c = getc(stream)) != EOF) + if (c == NL) + break; + } + return (count); +} /* egets */ + +static int doread (int lin, const char * fname) +{ + FILE *fp; + int err; + unsigned int bytes; + unsigned int lines; + static char str[ED_MAXLINE]; + + err = 0; + P_NONASCII = P_NULLCHAR = P_TRUNCATED = 0; + + if (P_VERBOSE) + ED_OUTPUTV(ED_DEST, "\"%s\" ", fname); + if ((fp = fopen(fname, "r")) == NULL) { + ED_OUTPUT(ED_DEST, " isn't readable.\n"); + return EDERR; + } + setCurLn(lin); + for (lines = 0, bytes = 0; (err = egets(str, ED_MAXLINE, fp)) > 0;) { + bytes += err; + if (ins(str) < 0) { + err = MEM_FAIL; + break; + } + lines++; + } + fclose(fp); + if (err < 0) + return (err); + if (P_VERBOSE) { + ED_OUTPUTV(ED_DEST, "%u lines %u bytes", lines, bytes); + if (P_NONASCII) + ED_OUTPUTV(ED_DEST, " [%d non-ascii]", P_NONASCII); + if (P_NULLCHAR) + ED_OUTPUTV(ED_DEST, " [%d nul]", P_NULLCHAR); + if (P_TRUNCATED) + ED_OUTPUTV(ED_DEST, " [%d lines truncated]", P_TRUNCATED); + ED_OUTPUT(ED_DEST, "\n"); + } + return (err); +} /* doread */ + +static int dowrite (int from, int to, const char * fname, int apflg) +{ + FILE *fp; + int lin, err; + unsigned int lines; + unsigned int bytes; + char *str; + ed_line_t *lptr; + + err = 0; + lines = bytes = 0; + +#ifdef OLD_ED + if (ED_BUFFER->write_fn) { + svalue_t *res; + + push_malloced_string(add_slash(fname)); + push_number(0); + res = safe_apply(ED_BUFFER->write_fn, ED_BUFFER->exit_ob, 2, ORIGIN_INTERNAL); + if (IS_ZERO(res)) + return (EDERR); + } +#endif + + if (!P_RESTRICT) + ED_OUTPUTV(ED_DEST, "\"/%s\" ", fname); + if ((fp = fopen(fname, (apflg ? "a" : "w"))) == NULL) { + if (!P_RESTRICT) + ED_OUTPUT(ED_DEST, " can't be opened for writing!\n"); + else + ED_OUTPUT(ED_DEST, "Couldn't open file for writing!\n"); + return EDERR; + } + lptr = getptr(from); + for (lin = from; lin <= to; lin++) { + str = lptr->l_buff; + lines++; + bytes += strlen(str) + 1; /* str + '\n' */ + if (fputs(str, fp) == EOF) { + ED_OUTPUT(ED_DEST, "file write error\n"); + err++; + break; + } + fputc('\n', fp); + lptr = lptr->l_next; + } + + if (!P_RESTRICT) + ED_OUTPUTV(ED_DEST, "%u lines %lu bytes\n", lines, bytes); + fclose(fp); + +#ifdef OLD_ED + if (ED_BUFFER->write_fn) { + push_malloced_string(add_slash(fname)); + push_number(1); + safe_apply(ED_BUFFER->write_fn, ED_BUFFER->exit_ob, 2, ORIGIN_INTERNAL); + } +#endif + + return (err); +} /* dowrite */ + +/* find.c */ + +static int find (regexp * pat, int dir) +{ + int i, num; + ed_line_t *lin; + + if (!pat) + return (EDERR); + dir ? nextCurLn() : prevCurLn(); + num = P_CURLN; + lin = P_CURPTR; + for (i = 0; i < P_LASTLN; i++) { + if (regexec(pat, gettxtl(lin))) + return (num); + if (EdErr) { + EdErr = 0; + break; + } + if (dir) + num = nextln(num), lin = getnextptr(lin); + else + num = prevln(num), lin = getprevptr(lin); + } +/* Put us back to where we came from */ + dir ? prevCurLn() : nextCurLn(); + return (SEARCH_FAILED); +} /* find() */ + +/* getfn.c */ + +static char *getfn (int writeflg) +{ + static char file[MAXFNAME]; + char *cp; + const char *file2; + svalue_t *ret; + + if (*inptr == NL) { + P_NOFNAME = TRUE; + file[0] = '/'; + strcpy(file + 1, P_FNAME); + } else { + P_NOFNAME = FALSE; + Skip_White_Space; + + cp = file; + while (*inptr && *inptr != NL && *inptr != SP && *inptr != HT) + *cp++ = *inptr++; + *cp = '\0'; + + } + if (strlen(file) == 0) { + ED_OUTPUT(ED_DEST, "Bad file name.\n"); + return (0); + } + + if (file[0] != '/') { + copy_and_push_string(file); + ret = apply_master_ob(APPLY_MAKE_PATH_ABSOLUTE, 1); + if ((ret == 0) || (ret == (svalue_t *)-1) || ret->type != T_STRING) + return NULL; + strncpy(file, ret->u.string, sizeof file - 1); + file[MAXFNAME - 1] = '\0'; + } + + /* valid_read/valid_write done here */ + file2 = check_valid_path(file, current_editor, "ed_start", writeflg); + if (!file2) + return (NULL); + strncpy(file, file2, MAXFNAME - 1); + file[MAXFNAME - 1] = 0; + + if (*file == 0) { + ED_OUTPUT(ED_DEST, "no file name\n"); + return (NULL); + } + return (file); +} /* getfn */ + +static int getnum (int first) +{ + regexp *srchpat; + int num; + char c; + + Skip_White_Space; + + if (*inptr >= '0' && *inptr <= '9') { /* line number */ + for (num = 0; *inptr >= '0' && *inptr <= '9'; ++inptr) { + num = (num * 10) + (*inptr - '0'); + } + return num; + } + switch (c = *inptr) { + case '.': + inptr++; + return (P_CURLN); + + case '$': + inptr++; + return (P_LASTLN); + + case '/': + case '?': + srchpat = optpat(); + if (*inptr == c) + inptr++; + return (find(srchpat, c == '/' ? 1 : 0)); + + case '-': + case '+': + return (first ? P_CURLN : 1); + + case '\'': + inptr++; + if (*inptr < 'a' || *inptr > 'z') + return MARK_A_TO_Z; + return P_MARK[*inptr++ - 'a']; + + default: + return (first ? NO_LINE_RANGE : 1); /* unknown address */ + } +} /* getnum */ + + +/* getone.c + * Parse a number (or arithmetic expression) off the command line. + */ +#define FIRST 1 +#define NOTFIRST 0 + +static int getone() +{ + int c, i, num; + + if ((num = getnum(FIRST)) >= 0) { + for (;;) { + Skip_White_Space; + if (*inptr != '+' && *inptr != '-') + break; /* exit infinite loop */ + + c = *inptr++; + if ((i = getnum(NOTFIRST)) < 0) + return (i); + if (c == '+') + num += i; + else { + num -= i; + if (num < 1) num = 1; + } + } + } + return (num > P_LASTLN ? BAD_LINE_NUMBER : num); +} /* getone */ + + +static int getlst() +{ + int num; + + P_LINE2 = 0; + for (P_NLINES = 0; (num = getone()) >= 0 || (num == BAD_LINE_NUMBER);) { + /* if it's out of bounds, go to the end of the file. */ + if (num == BAD_LINE_NUMBER) + num = P_LASTLN; + + P_LINE1 = P_LINE2; + P_LINE2 = num; + P_NLINES++; + if (*inptr != ',' && *inptr != ';') + break; + if (*inptr == ';') + setCurLn(num); + inptr++; + } + P_NLINES = min(P_NLINES, 2); + if (P_NLINES == 0) + P_LINE2 = P_CURLN; + if (P_NLINES <= 1) + P_LINE1 = P_LINE2; + + return ((num < 0) ? num : P_NLINES); +} /* getlst */ + + +/* getptr.c */ + +static ed_line_t *getptr (int num) +{ + ed_line_t *ptr; + int j; + + if (2 * num > P_LASTLN && num <= P_LASTLN) { /* high line numbers */ + ptr = P_LINE0.l_prev; + for (j = P_LASTLN; j > num; j--) + ptr = ptr->l_prev; + } else { /* low line numbers */ + ptr = &P_LINE0; + for (j = 0; j < num; j++) + ptr = ptr->l_next; + } + return (ptr); +} + + +/* getrhs.c */ + +static int getrhs (char * sub) +{ + char delim = *inptr++; + char *outmax = sub + MAXPAT; + + if (delim == NL || *inptr == NL) /* check for eol */ + return (EDERR); + while (*inptr != delim && *inptr != NL) { + if (sub > outmax) + return EDERR; + if (*inptr == ESCAPE) { + switch (*++inptr) { + case 'r': + *sub++ = '\r'; + inptr++; + break; + case 'n': + *sub++ = '\n'; + inptr++; + break; + case 'b': + *sub++ = '\b'; + inptr++; + break; + case 't': + *sub++ = '\t'; + inptr++; + break; + case '0':{ + int i = 3; + + *sub = 0; + do { + if (*++inptr < '0' || *inptr > '7') + break; + *sub = (*sub << 3) | (*inptr - '0'); + } while (--i != 0); + sub++; + } break; + case '&': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '\\': + *sub++ = ESCAPE;/* fall through */ + default: + *sub++ = *inptr; + if (*inptr != NL) + inptr++; + } + } else + *sub++ = *inptr++; + } + *sub = '\0'; + + inptr++; /* skip over delimter */ + Skip_White_Space; + if (*inptr == 'g') { + inptr++; + return (1); + } + return (0); +} + +/* ins.c */ + +static int ins (const char *str) +{ + const char *cp; + ed_line_t *newl, *nxt; + int len; + + do { + for (cp = str; *cp && *cp != NL; cp++); + len = cp - str; + /* cp now points to end of first or only line */ + + if ((newl = (ed_line_t *) DXALLOC(sizeof(ed_line_t) + len, + TAG_ED, "ins: new")) == NULL) + return (MEM_FAIL); /* no memory */ + + newl->l_stat = 0; + strncpy(newl->l_buff, str, len); /* build new line */ + newl->l_buff[len] = EOS; + nxt = getnextptr(P_CURPTR); /* get next line */ + relink(P_CURPTR, newl, newl, nxt); /* add to linked list */ + relink(newl, nxt, P_CURPTR, newl); + P_LASTLN++; + P_CURLN++; + P_CURPTR = newl; + str = cp + 1; + } + while (*cp != EOS); + return 1; +} + + +/* join.c */ + +static int join (int first, int last) +{ + char buf[ED_MAXLINE]; + char *cp = buf, *str; + ed_line_t *lin; + int num; + + if (first <= 0 || first > last || last > P_LASTLN) + return BAD_LINE_RANGE; + if (first == last) { + setCurLn(first); + return 0; + } + lin = getptr(first); + for (num = first; num <= last; num++) { + str = gettxtl(lin); + while (*str) { + if (cp >= buf + ED_MAXLINE - 1) { + ED_OUTPUT(ED_DEST, "line too long\n"); + return EDERR; + } + *cp++ = *str++; + } + lin = getnextptr(lin); + } + *cp = EOS; + del(first, last); + if (ins(buf) < 0) + return MEM_FAIL; + P_FCHANGED = TRUE; + return 0; +} + +/* move.c + * Unlink the block of lines from P_LINE1 to P_LINE2, and relink them + * after line "num". + */ + +static int move (int num) +{ + int range; + ed_line_t *before, *first, *last, *after; + + if (P_LINE1 <= num && num <= P_LINE2) + return BAD_LINE_RANGE; + range = P_LINE2 - P_LINE1 + 1; + before = getptr(prevln(P_LINE1)); + first = getptr(P_LINE1); + last = getptr(P_LINE2); + after = getptr(nextln(P_LINE2)); + + relink(before, after, before, after); + P_LASTLN -= range; /* per AST's posted patch 2/2/88 */ + if (num > P_LINE1) + num -= range; + + before = getptr(num); + after = getptr(nextln(num)); + relink(before, first, last, after); + relink(last, after, before, first); + P_LASTLN += range; /* per AST's posted patch 2/2/88 */ + setCurLn(num + range); + return (1); +} + + +static int transfer (int num) +{ + int mid, lin, ntrans; + + if (P_LINE1 <= 0 || P_LINE1 > P_LINE2) + return (EDERR); + + mid = num < P_LINE2 ? num : P_LINE2; + + setCurLn(num); + ntrans = 0; + + for (lin = P_LINE1; lin <= mid; lin++) { + if (ins(gettxt(lin)) < 0) + return MEM_FAIL; + ntrans++; + } + lin += ntrans; + P_LINE2 += ntrans; + + for (; lin <= P_LINE2; lin += 2) { + if (ins(gettxt(lin)) < 0) + return MEM_FAIL; + P_LINE2++; + } + return (1); +} + + +/* optpat.c */ + +static regexp *optpat() +{ + char delim, str[MAXPAT], *cp; + + delim = *inptr++; + if (delim == NL) + return P_OLDPAT; + cp = str; + while (*inptr != delim && *inptr != NL && *inptr != EOS && cp < str + MAXPAT - 1) { + if (*inptr == ESCAPE && inptr[1] != NL) + *cp++ = *inptr++; + *cp++ = *inptr++; + } + + *cp = EOS; + if (*str == EOS) + return (P_OLDPAT); + if (P_OLDPAT) + FREE((char *) P_OLDPAT); + return P_OLDPAT = regcomp((unsigned char *)str, P_EXCOMPAT); +} + +static int set() +{ + char word[16]; + int i; + struct tbl *limit; + + if (*(++inptr) != 't') { + if (*inptr != SP && *inptr != HT && *inptr != NL) + return SYNTAX_ERROR; + } else + inptr++; + + if ((*inptr == NL)) { + char out[512]; + char *pos = out; + + pos += sprintf(pos, "ed version %d.%d\n", version / 100, + version % 100); + limit = tbl + (sizeof(tbl) / sizeof(struct tbl)); + for (t = tbl; t < limit; t += 2) { + pos += sprintf(pos, "%s:%s ", t->t_str, + P_FLAGS & t->t_or_mask ? "on" : "off"); + } + pos += sprintf(pos, "\nshiftwidth:%d\n", P_SHIFTWIDTH); + + ED_OUTPUT(ED_DEST, out); + return (0); + } + Skip_White_Space; + for (i = 0; *inptr != SP && *inptr != HT && *inptr != NL;) { + if (i == sizeof word - 1) { + ED_OUTPUT(ED_DEST, "Too long argument to 'set'!\n"); + return 0; + } + word[i++] = *inptr++; + } + word[i] = EOS; + limit = tbl + (sizeof(tbl) / sizeof(struct tbl)); + for (t = tbl; t < limit; t++) { + if (strcmp(word, t->t_str) == 0) { + P_FLAGS = (P_FLAGS & t->t_and_mask) | t->t_or_mask; + return (0); + } + } + if (!strcmp(word, "save")) { + svalue_t *ret; + + if (P_RESTRICT) + return (SET_FAIL); + push_object(current_editor); + push_number(P_SHIFTWIDTH | P_FLAGS); + ret = apply_master_ob(APPLY_SAVE_ED_SETUP, 2); + if (MASTER_APPROVED(ret)) + return 0; + } + if (!strcmp(word, "shiftwidth")) { + Skip_White_Space; + if (uisdigit(*inptr)) { + P_SHIFTWIDTH = *inptr - '0'; + return 0; + } + } + return SET_FAIL; +} + +#ifndef relink +void relink (LINE * a, LINE * x, LINE * y, LINE * b) +{ + x->l_prev = a; + y->l_next = b; +} +#endif + + +static void set_ed_buf() +{ + relink(&P_LINE0, &P_LINE0, &P_LINE0, &P_LINE0); + P_CURLN = P_LASTLN = 0; + P_CURPTR = &P_LINE0; +} + + +/* subst.c */ + +static int subst (regexp * pat, char * sub, int gflg, int pflag) +{ + int nchngd = 0; + const char *txtptr; + char *newc, *old, buf[ED_MAXLINE]; + int space; /* amylaar */ + int still_running = 1; + ed_line_t *lastline = getptr(P_LINE2); + + if (P_LINE1 <= 0) + return (SUB_FAIL); + nchngd = 0; /* reset count of lines changed */ + + for (setCurLn(prevln(P_LINE1)); still_running;) { + nextCurLn(); + newc = buf; + space = ED_MAXLINE; /* amylaar */ + if (P_CURPTR == lastline) + still_running = 0; + if (regexec(pat, txtptr = gettxtl(P_CURPTR))) { + do { + /* Copy leading text */ + int diff = pat->startp[0] - txtptr; + + if ((space -= diff) < 0) /* amylaar */ + return SUB_FAIL; + strncpy(newc, txtptr, diff); + newc += diff; + /* Do substitution */ + old = newc; + newc = regsub(pat, sub, newc, space); + if (!newc || (space -= newc - old) < 0) /* amylaar */ + return SUB_FAIL; + if (txtptr == pat->endp[0]) { /* amylaar : prevent infinite + * loop */ + if (!*txtptr) + break; + if (--space < 0) + return SUB_FAIL; + *newc++ = *txtptr++; + } else + txtptr = pat->endp[0]; + } + while (gflg && !pat->reganch && regexec(pat, txtptr)); + + /* Copy trailing chars */ + /* + * amylaar : always check for enough space left BEFORE altering + * memory + */ + if ((space -= strlen(txtptr) + 1) < 0) + return SUB_FAIL; + strcpy(newc, txtptr); + del(P_CURLN, P_CURLN); + if (ins(buf) < 0) + return MEM_FAIL; + nchngd++; + if (pflag) + doprnt(P_CURLN, P_CURLN); + } + } + return ((nchngd == 0 && !gflg) ? SUB_FAIL : nchngd); +} + + +/* + * Indent code from DGD editor (v0.1), adapted. No attempt has been made to + * optimize for this editor. Dworkin 920510 + */ +#define error(s) { ED_OUTPUTV(ED_DEST, s, lineno); errs++; return; } +#define bool char +static int lineno, errs; +static int shi; /* the current shift (negative for left + * shift) */ + +/* + * NAME: shift(char*) + * ACTION: Shift a line left or right according to "shi". + */ +/* amylaar: don't use identifier index, this is reserved in SYS V compatible + * environments. + */ +static void shift (register char * text) +{ + register int indent_index; + + /* first determine the number of leading spaces */ + indent_index = 0; + while (*text == ' ' || *text == '\t') { + if (*text++ == ' ') { + indent_index++; + } else { + // indent_index = (indent_index + 8) & ~7; + indent_index = indent_index + ED_TAB_WIDTH - + (indent_index % ED_TAB_WIDTH); + } + } + + if (*text != '\0') { /* don't shift lines with ws only */ + indent_index += shi; + if (indent_index < ED_MAXLINE) { + char buffer[ED_MAXLINE]; + register char *p; + + p = buffer; + /* fill with leading ws */ +#ifdef USE_TABS + while (indent_index >= ED_TAB_WIDTH) { + *p++ = '\t'; + indent_index -= ED_TAB_WIDTH; + } +#endif + while (indent_index > 0) { + *p++ = ' '; + --indent_index; + } + if (p - buffer + strlen(text) < ED_MAXLINE) { + strcpy(p, text); + del(lineno, lineno); + ins(buffer); + return; + } + } + error("Result of shift would be too long, line %d\n"); + } +} + +#define STACKSZ 1024 /* size of indent stack */ + +/* token definitions in indent */ +#define SEMICOLON 0 +#define LBRACKET 1 +#define RBRACKET 2 +#define LOPERATOR 3 +#define ROPERATOR 4 +#define LHOOK 5 +#define LHOOK2 6 +#define RHOOK 7 +#define TOKEN 8 +#define ELSE 9 +#define IF 10 +#define FOR 11 +#define WHILE 12 +#define XDO 13 +#define XEOT 14 + +static char *stack, *stackbot; /* token stack */ +static int *ind, *indbot; /* indent stack */ +static char quote; /* ' or " */ +static bool in_ppcontrol, after_keyword_t, in_mblock; /* status */ +int in_comment; +static char last_term[ED_MAXLINE+5]; +static int last_term_len; + +/* + * NAME: indent(char*) + * ACTION: Parse and indent a line of text. This isn't perfect, as + * keyword_ts could be defined as macros, comments are very hard to + * handle properly, (, [ and ({ will match any of ), ] and }), + * and last but not least everyone has his own taste of + * indentation. + */ +static void indent (char * buf) +{ + static char f[] = + {7, 1, 7, 1, 2, 1, 1, 6, 4, 2, 6, 7, 7, 2, 0,}; + static char g[] = + {2, 2, 1, 7, 1, 5, 5, 1, 3, 6, 2, 2, 2, 2, 0,}; + char text[ED_MAXLINE], ident[ED_MAXLINE]; + char *p, *sp; + register int *ip; + register long indent_index; + register int top, token; + char *start; + bool do_indent; + + /* + * Problem: in this editor memory for deleted lines is reclaimed. So we + * cannot shift the line and then continue processing it, as in DGD ed. + * Instead make a copy of the line, and process the copy. Dworkin 920510 + */ + strcpy(text, buf); + + do_indent = FALSE; + indent_index = 0; + p = text; + + /* process status vars */ + if (quote != '\0') { + shi = 0; /* in case a comment starts on this line */ + } else if (in_ppcontrol || *p == '#') { + while (*p != '\0') { + if (*p == '\\' && *++p == '\0') { + in_ppcontrol = TRUE; + return; + } + p++; + } + in_ppcontrol = FALSE; + return; + } else if (in_mblock) { + if (!strncmp(p, last_term, last_term_len)) { + in_mblock = FALSE; + p+=last_term_len; + } + else return; + } else { + /* count leading ws */ + while (*p == ' ' || *p == '\t') { + if (*p++ == ' ') { + indent_index++; + } else { + // indent_index = (indent_index + 8) & ~7; + indent_index = indent_index + ED_TAB_WIDTH - + (indent_index % ED_TAB_WIDTH); + } + } + if (*p == '\0') { + del(lineno, lineno); + ins(p); + return; + } else if (in_comment) { + shift(text); /* use previous shi */ + } else { + do_indent = TRUE; + } + } + + /* process this line */ + start = p; + while (*p != '\0') { + + /* lexical scanning: find the next token */ + ident[0] = '\0'; + if (in_comment) { + /* comment */ + while (*p != '*') { + if (*p == '\0') { + if (in_comment == 2) in_comment = 0; + return; + } + p++; + } + while (*p == '*') { + p++; + } + if (*p == '/') { + in_comment = 0; + p++; + } + continue; + + } else if (quote != '\0') { + /* string or character constant */ + for (;;) { + if (*p == quote) { + quote = '\0'; + p++; + break; + } else if (*p == '\0') { + error("Unterminated string in line %d\n"); + } else if (*p == '\\' && *++p == '\0') { + break; + } + p++; + } + token = TOKEN; + + } else { + switch (*p++) { + case ' ': /* white space */ + case '\t': + continue; + + case '\'': + case '"': /* start of string */ + quote = p[-1]; + continue; + + case '@': { + int j = 0; + + if (*p == '@') p++; + while (uisalnum(*p) || *p == '_') last_term[j++] = *p++; + last_term[j] = '\0'; + last_term_len = j; + in_mblock = TRUE; + return; + } + case '/': + if (*p == '*' || *p == '/') { /* start of a comment */ + in_comment = (*p == '*') ? 1 : 2; + if (do_indent) { + /* this line hasn't been indented yet */ + shi = *ind - indent_index; + shift(text); + do_indent = FALSE; + } else { + register char *q; + register int index2; + + /* + * find how much the comment has shifted, so the same + * shift can be used if the coment continues on the + * next line + */ + index2 = *ind; + for (q = start; q < p - 1;) { + if (*q++ == '\t') { + // indent_index = (indent_index + 8) & ~7; + // index2 = (index2 + 8) & ~7; + indent_index = indent_index + ED_TAB_WIDTH - + (indent_index % ED_TAB_WIDTH); + index2 = index2 + ED_TAB_WIDTH - + (index2 % ED_TAB_WIDTH); + + + } else { + indent_index++; + index2++; + } + } + shi = index2 - indent_index; + } + p++; + + if((*p == '\0') && (in_comment == 2)) + in_comment = 0; + + continue; + } + token = TOKEN; + break; + + case '{': + token = LBRACKET; + break; + + case '(': + if (after_keyword_t) { + /* + * LOPERATOR & ROPERATOR are a kludge. The operator + * precedence parser that is used could not work if + * parenthesis after keyword_ts was not treated specially. + */ + token = LOPERATOR; + break; + } + if (*p == '{' || *p == '[' || (*p == ':' && p[1] != ':')) { + p++; /* ({ , ([ , (: each are one token */ + token = LHOOK2; + break; + } + case '[': + token = LHOOK; + break; + + case ':': + if (*p == ')') { + p++; + token = RHOOK; + break; + } + token = TOKEN; + break; + case '}': + if (*p != ')') { + token = RBRACKET; + break; + } + /* }) is one token */ + p++; + token = RHOOK; + break; + case ']': + if (*p == ')' && + (*stack == LHOOK2 || (*stack != XEOT && + (stack[1] == LHOOK2 || + (stack[1] == ROPERATOR && stack[2] == LHOOK2))))) { + p++; + } + case ')': + token = RHOOK; + break; + + case ';': + token = SEMICOLON; + break; + + default: + if (uisalpha(*--p) || *p == '_') { + char *q; + + /* Identifier. See if it's a keyword_t. */ + q = ident; + do { + *q++ = *p++; + } while (uisalnum(*p) || *p == '_'); + *q = '\0'; + + if (strcmp(ident, "if") == 0) + token = IF; + else if (strcmp(ident, "else") == 0) + token = ELSE; + else if (strcmp(ident, "for") == 0) + token = FOR; + else if (strcmp(ident, "foreach") == 0) + token = FOR; + else if (strcmp(ident, "while") == 0) + token = WHILE; + else if (strcmp(ident, "do") == 0) + token = XDO; + else /* not a keyword_t */ + token = TOKEN; + } else { + /* anything else is a "token" */ + p++; + token = TOKEN; + } + break; + } + } + + /* parse */ + sp = stack; + ip = ind; + for (;;) { + top = *sp; + if (top == LOPERATOR && token == RHOOK) { + /* ) after LOPERATOR is ROPERATOR */ + token = ROPERATOR; + } + if (f[top] <= g[token]) { /* shift the token on the stack */ + register int i; + + if (sp == stackbot) { + /* out of stack */ + error("Nesting too deep in line %d\n"); + } + /* handle indentation */ + i = *ip; + /* if needed, reduce indentation prior to shift */ + if ((token == LBRACKET && + (*sp == ROPERATOR || *sp == ELSE || *sp == XDO)) || + token == RBRACKET || + (token == IF && *sp == ELSE)) { + /* back up */ + i -= P_SHIFTWIDTH; + } else if (token == RHOOK || token == ROPERATOR) { + i -= P_SHIFTWIDTH / 2; + } + /* shift the current line, if appropriate */ + if (do_indent) { + shi = i - indent_index; + if (token == TOKEN && *sp == LBRACKET && + (strcmp(ident, "case") == 0 || + strcmp(ident, "default") == 0)) { + /* back up if this is a switch label */ +#ifndef ED_INDENT_CASE + shi -= P_SHIFTWIDTH; +#endif + } + shift(text); + do_indent = FALSE; + } + /* change indentation after current token */ + switch (token) { + case LBRACKET: + case ROPERATOR: + case ELSE: + case XDO: + { + /* add indentation */ + i += P_SHIFTWIDTH; + break; + } + case LOPERATOR: + case LHOOK: + case LHOOK2: /* Is this right? */ + { + /* half indent after ( [ ({ ([ */ + i += P_SHIFTWIDTH / 2; + break; + } + case SEMICOLON: + { + /* in case it is followed by a comment */ + if (*sp == ROPERATOR || *sp == ELSE) { + i -= P_SHIFTWIDTH; + } + break; + } + } + + *--sp = token; + *--ip = i; + break; + } + /* reduce handle */ + do { + top = *sp++; + ip++; + } while (f[(int) *sp] >= g[top]); + } + stack = sp; + ind = ip; + after_keyword_t = (token >= IF); /* but not after ELSE */ + } +} + +static int indent_code() +{ + char s[STACKSZ]; + int i[STACKSZ]; + int last; + + /* setup stacks */ + stackbot = s; + indbot = i; + stack = stackbot + STACKSZ - 1; + *stack = XEOT; + ind = indbot + STACKSZ - 1; + *ind = 0; + + quote = '\0'; + in_ppcontrol = FALSE; + in_comment = 0; + in_mblock = 0; + + P_FCHANGED = TRUE; + last = P_LASTLN; + errs = 0; + + for (lineno = 1; lineno <= last; lineno++) { + setCurLn(lineno); + indent(gettxtl(P_CURPTR)); + if (errs != 0) { + return EDERR; + } + } + + return 0; +} + +#undef bool +#undef error +/* end of indent code */ + + +/* docmd.c + * Perform the command specified in the input buffer, as pointed to + * by inptr. Actually, this finds the command letter first. + */ + +static int docmd (int glob) +{ + static char rhs[MAXPAT]; + regexp *subpat; + int c, err, line3; + int apflg, pflag, gflag; + int nchng; + char *fptr; + int st; + int scr; + + pflag = FALSE; + Skip_White_Space; + + c = *inptr++; + switch (c) { + case NL: + if (P_NLINES == 0 && (P_LINE2 = nextln(P_CURLN)) == 0) + return END_OF_FILE; + if (P_NLINES == 2) { + if (P_LINE1 > P_LINE2 || P_LINE1 <= 0) + return BAD_LINE_RANGE; + if ((st = doprnt(P_LINE1, P_LINE2))) + return st; + return 0; + } + setCurLn(P_LINE2); + return (1); + + case '=': + ED_OUTPUTV(ED_DEST, "%d\n", P_LINE2); + break; + + case 'o': + case 'a': + case 'A': + P_CUR_AUTOIND = c == 'A' ? !P_AUTOINDFLG : P_AUTOINDFLG; + if (*inptr != NL) + return SYNTAX_ERROR; + if (P_NLINES > 1) + return RANGE_ILLEGAL; + + if (P_CUR_AUTOIND) + count_blanks(P_LINE1); + if ((st = append(P_LINE1, glob)) < 0) + return st; + P_FCHANGED = TRUE; + break; + + case 'c': + if (*inptr != NL) + return SYNTAX_ERROR; + + if (deflt(P_CURLN, P_CURLN) < 0) + return BAD_LINE_RANGE; + + P_CUR_AUTOIND = P_AUTOINDFLG; + if (P_AUTOINDFLG) + count_blanks(P_LINE1); + if ((st = del(P_LINE1, P_LINE2)) < 0) + return st; + if ((st = append(P_CURLN, glob)) < 0) + return st; + P_FCHANGED = TRUE; + break; + + case 'd': + if (*inptr != NL) + return SYNTAX_ERROR; + + if (deflt(P_CURLN, P_CURLN) < 0) + return BAD_LINE_RANGE; + + if ((st = del(P_LINE1, P_LINE2)) < 0) + return st; + if (nextln(P_CURLN) != 0) + nextCurLn(); + if (P_DPRINT) + doprnt(P_CURLN, P_CURLN); + P_FCHANGED = TRUE; + break; + + case 'e': + if (P_RESTRICT) + return IS_RESTRICTED; + if (P_NLINES > 0) + return LINE_OR_RANGE_ILL; + if (P_FCHANGED) + return CHANGED; + /* FALL THROUGH */ + case 'E': + if (P_RESTRICT) + return IS_RESTRICTED; + if (P_NLINES > 0) + return LINE_OR_RANGE_ILL; + + if (*inptr != ' ' && *inptr != HT && *inptr != NL) + return SYNTAX_ERROR; + + if ((fptr = getfn(0)) == NULL) + return FILE_NAME_ERROR; + + clrbuf(); + (void) doread(0, fptr); + + strcpy(P_FNAME, fptr); + P_FCHANGED = FALSE; + break; + + case 'f': + if (P_RESTRICT) + return IS_RESTRICTED; + if (P_NLINES > 0) + return LINE_OR_RANGE_ILL; + + if (*inptr != ' ' && *inptr != HT && *inptr != NL) + return SYNTAX_ERROR; + + fptr = getfn(0); + + if (P_NOFNAME) + ED_OUTPUTV(ED_DEST, "/%s\n", P_FNAME); + else { + if (fptr == NULL) + return FILE_NAME_ERROR; + strcpy(P_FNAME, fptr); + } + break; + + case 'O': + case 'i': + if (*inptr != NL) + return SYNTAX_ERROR; + if (P_NLINES > 1) + return RANGE_ILLEGAL; + + P_CUR_AUTOIND = P_AUTOINDFLG; + if (P_AUTOINDFLG) + count_blanks(P_LINE1); + if ((st = append(prevln(P_LINE1), glob)) < 0) + return st; + P_FCHANGED = TRUE; + break; + + case 'j': + if (*inptr != NL || deflt(P_CURLN, P_CURLN + 1) < 0) + return SYNTAX_ERROR; + + if ((st = join(P_LINE1, P_LINE2)) < 0) + return st; + break; + + case 'k': + Skip_White_Space; + + if (*inptr < 'a' || *inptr > 'z') + return MARK_A_TO_Z; + c = *inptr++; + + if (*inptr != ' ' && *inptr != HT && *inptr != NL) + return SYNTAX_ERROR; + + P_MARK[c - 'a'] = P_LINE1; + break; + + case 'l': + if (*inptr != NL) + return SYNTAX_ERROR; + if (deflt(P_CURLN, P_CURLN) < 0) + return BAD_LINE_RANGE; + if ((st = dolst(P_LINE1, P_LINE2)) < 0) + return st; + break; + + case 'm': + if ((line3 = getone()) < 0) + return line3; + if (deflt(P_CURLN, P_CURLN) < 0) + return BAD_LINE_RANGE; + if ((st = move(line3)) < 0) + return st; + P_FCHANGED = TRUE; + break; + + case 'n': + if (*inptr != NL) + return SYNTAX_ERROR; + if (P_NFLG) + P_FLAGS &= ~NFLG_MASK; + else + P_FLAGS |= NFLG_MASK; + ED_OUTPUTV(ED_DEST, "number %s, list %s\n", + P_NFLG ? "on" : "off", P_LFLG ? "on" : "off"); + break; + + case 'I': + if (P_NLINES > 0) + return LINE_OR_RANGE_ILL; + if (*inptr != NL) + return SYNTAX_ERROR; + ED_OUTPUT(ED_DEST, "Indenting entire code...\n"); + if (indent_code()) + ED_OUTPUT(ED_DEST, "Indentation halted.\n"); + else + ED_OUTPUT(ED_DEST, "Indentation complete.\n"); + break; + + case 'H': + case 'h': + print_help(*(inptr++)); + break; + + case 'P': + case 'p': + if (*inptr != NL) + return SYNTAX_ERROR; + if (deflt(P_CURLN, P_CURLN) < 0) + return BAD_LINE_RANGE; + if ((st = doprnt(P_LINE1, P_LINE2)) < 0) + return st; + break; + + case 'q': + if (P_FCHANGED) + return CHANGED; + /* FALL THROUGH */ + case 'Q': + if (*inptr != NL) + return SYNTAX_ERROR; + if (glob) + return SYNTAX_ERROR; + if (P_NLINES > 0) + return LINE_OR_RANGE_ILL; + clrbuf(); + return (EOF); + + case 'r': + if (P_RESTRICT) + return IS_RESTRICTED; + if (P_NLINES > 1) + return RANGE_ILLEGAL; + + if (P_NLINES == 0) /* The original code tested */ + P_LINE2 = P_LASTLN; /* if(P_NLINES = 0) */ + /* which looks wrong. RAM */ + + if (*inptr != ' ' && *inptr != HT && *inptr != NL) + return SYNTAX_ERROR; + + if ((fptr = getfn(0)) == NULL) + return FILE_NAME_ERROR; + + if ((err = doread(P_LINE2, fptr)) < 0) + return (err); + P_FCHANGED = TRUE; + break; + + case 's': + if (*inptr == 'e') + return (set()); + Skip_White_Space; + if ((subpat = optpat()) == NULL) + return SUB_BAD_PATTERN; + if ((gflag = getrhs(rhs)) < 0) + return SUB_BAD_REPLACEMENT; + if (*inptr == 'p') + pflag++; + if (deflt(P_CURLN, P_CURLN) < 0) + return BAD_LINE_RANGE; + if ((nchng = subst(subpat, rhs, gflag, pflag)) < 0) + return nchng; + if (nchng) + P_FCHANGED = TRUE; + if (nchng == 1 && P_PFLG) { + if ((st = doprnt(P_CURLN, P_CURLN)) < 0) + return st; + } + break; + + case 't': + if ((line3 = getone()) < 0) + return BAD_DESTINATION; + if (deflt(P_CURLN, P_CURLN) < 0) + return BAD_LINE_RANGE; + if ((st = transfer(line3)) < 0) + return st; + P_FCHANGED = TRUE; + break; + + case 'W': + case 'w': + apflg = (c == 'W'); + + if (*inptr != NL && P_RESTRICT) + return IS_RESTRICTED; + if (*inptr != ' ' && *inptr != HT && *inptr != NL) + return SYNTAX_ERROR; + + if ((fptr = getfn(1)) == NULL) + return FILE_NAME_ERROR; + + if (deflt(1, P_LASTLN) < 0) + return BAD_LINE_RANGE; + if ((st = dowrite(P_LINE1, P_LINE2, fptr, apflg)) < 0) + return st; + P_FCHANGED = FALSE; + break; + + case 'x': + if (*inptr == NL && P_NLINES == 0 && !glob) { + if ((fptr = getfn(1)) == NULL) + return FILE_NAME_ERROR; + if (dowrite(1, P_LASTLN, fptr, 0) >= 0) { + clrbuf(); + return (EOF); + } + } + if (P_NLINES) + return LINE_OR_RANGE_ILL; + return SYNTAX_ERROR; + + case 'z': + if (deflt(P_CURLN, P_CURLN) < 0) + return BAD_LINE_RANGE; + + switch (*inptr) { + case '-': + scr = 0; + + while(*inptr == '-') { + scr += ED_BUFFER->scroll_lines - 2; + inptr++; + } + + if(scr >= P_LINE1) + scr = P_LINE1 - 1; + + if ((st = doprnt(P_LINE1 - (scr), + P_LINE1 + ED_BUFFER->scroll_lines - (scr+2))) < 0) + return st; + break; + + case '.': + if ((st = doprnt(P_LINE1 - (ED_BUFFER->scroll_lines/2), + P_LINE1 + (ED_BUFFER->scroll_lines/2-1))) < 0) + return st; + break; + + case '+': + case '\n': + scr = 0; + while(*(++inptr) == '+') + scr += ED_BUFFER->scroll_lines - 2; + if ((st = doprnt(P_LINE1 + (scr), + P_LINE1 + ED_BUFFER->scroll_lines + (scr) - 2)) < 0) + return st; + break; + } + break; + + case 'Z': + if (deflt(P_CURLN, P_CURLN) < 0) + return BAD_LINE_RANGE; + + switch (*inptr) { + case '-': + scr = 0; + + while(*inptr == '-') { + scr += ED_BUFFER->scroll_lines+3; + inptr++; + } + + if(scr >= P_LINE1) + scr = P_LINE1 - 1; + + if ((st = doprnt(P_LINE1 - (scr), + P_LINE1 + ED_BUFFER->scroll_lines - (scr-3))) < 0) + + return st; + break; + + case '.': + if ((st = doprnt(P_LINE1 - (ED_BUFFER->scroll_lines/2+2), + P_LINE1 + (ED_BUFFER->scroll_lines/2+2))) < 0) + return st; + break; + + case '+': + case '\n': + scr = 0; + while(*(++inptr) == '+') + scr += ED_BUFFER->scroll_lines+3; + if ((st = doprnt(P_LINE1 + (scr), + P_LINE1 + ED_BUFFER->scroll_lines + (scr) + 3)) < 0) + return st; + break; + } + break; + default: + return (UNRECOG_COMMAND); + } + + return (0); +} /* docmd */ + +/* doglob.c */ +static int doglob() +{ + int lin, status = 0; + char *cmd; + ed_line_t *ptr; + + cmd = inptr; + + for (;;) { + ptr = getptr(1); + for (lin = 1; lin <= P_LASTLN; lin++) { + if (ptr->l_stat & LGLOB) + break; + ptr = getnextptr(ptr); + } + if (lin > P_LASTLN) + break; + + ptr->l_stat &= ~LGLOB; + P_CURLN = lin; + P_CURPTR = ptr; + inptr = cmd; + if ((status = getlst()) < 0 && status != NO_LINE_RANGE) + return (status); + if ((status = docmd(1)) < 0) + return (status); + } + return (P_CURLN); +} /* doglob */ + + +/* + * Start the editor. Because several users can edit simultaneously, + * they will each need a separate editor data block. + * + * If a write_fn and exit_ob is given, then call exit_ob->write_fn after + * any time the editor contents are written out to a file. The purpose is + * make it possible for external LPC code to do more admin logging of + * files modified. + * + * If an exit_fn and exit_ob is given, then call exit_ob->exit_fn at + * exit of editor. The purpose is to make it possible for external LPC + * code to maintain a list of locked files. + */ +#ifdef OLD_ED +void ed_start (const char * file_arg, const char * write_fn, + const char * exit_fn, int restricted, object_t * exit_ob, + int scroll_lines) +{ + svalue_t *setup; + + regexp_user = ED_REGEXP; + if (!command_giver) + error("No current user for ed().\n"); + if (!command_giver->interactive) + error("Tried to start an ed session on a non-interactive user.\n"); + if (command_giver->interactive->ed_buffer) + error("Tried to start an ed session, when already active.\n"); + + current_ed_buffer = command_giver->interactive->ed_buffer = + ALLOCATE(ed_buffer_t, TAG_ED, "ed_start: ED_BUFFER"); + memset((char *) ED_BUFFER, '\0', sizeof(ed_buffer_t)); + + current_editor = command_giver; + + ED_BUFFER->flags |= EIGHTBIT_MASK; + ED_BUFFER->shiftwidth = ED_INDENT_SPACES; + push_object(current_editor); + setup = apply_master_ob(APPLY_RETRIEVE_ED_SETUP, 1); + if (setup && setup != (svalue_t *)-1 && + setup->type == T_NUMBER && setup->u.number) { + ED_BUFFER->flags = setup->u.number & ALL_FLAGS_MASK; + ED_BUFFER->shiftwidth = setup->u.number & SHIFTWIDTH_MASK; + } + ED_BUFFER->CurPtr = &ED_BUFFER->Line0; + +#if defined(RESTRICTED_ED) && !defined(NO_WIZARDS) + if (current_editor->flags & O_IS_WIZARD) { + P_RESTRICT = 0; + } else { + P_RESTRICT = 1; + } +#endif /* RESTRICTED_ED */ + if (restricted) { + P_RESTRICT = 1; + } + if (write_fn) { + ED_BUFFER->write_fn = alloc_cstring(write_fn, "ed_start"); + exit_ob->ref++; + } else { + ED_BUFFER->write_fn = 0; + } + if (exit_fn) { + ED_BUFFER->exit_fn = alloc_cstring(exit_fn, "ed_start"); + exit_ob->ref++; + } else { + ED_BUFFER->exit_fn = 0; + } + ED_BUFFER->exit_ob = exit_ob; + if(scroll_lines) + ED_BUFFER->scroll_lines = scroll_lines; + else + ED_BUFFER->scroll_lines = 22; + + set_ed_buf(); + + /* + * Check for read on startup, since the buffer is read in. But don't + * check for write, since we may want to change the file name. + */ + if (file_arg + && (file_arg = + check_valid_path(file_arg, current_editor, + "ed_start", 0)) + && !doread(0, file_arg)) { + setCurLn(1); + } + if (file_arg) { + strncpy(P_FNAME, file_arg, MAXFNAME - 1); + P_FNAME[MAXFNAME - 1] = 0; + } else { + ED_OUTPUT(ED_DEST, "No file.\n"); + } + set_prompt(":"); + return; +} +#endif + +#ifdef OLD_ED +void ed_cmd (char * str) +{ + int status = 0; + + regexp_user = ED_REGEXP; + current_ed_buffer = command_giver->interactive->ed_buffer; + current_editor = command_giver; + + if (P_MORE) { + print_help2(); + return; + } + if (P_APPENDING) { + more_append(str); + return; + } + + strncpy(inlin, str, ED_MAXLINE - 2); + inlin[ED_MAXLINE - 2] = 0; + strcat(inlin, "\n"); + + inptr = inlin; + if ((status = getlst()) >= 0 || status == NO_LINE_RANGE) { + if ((status = ckglob()) != 0) { + if (status >= 0 && (status = doglob()) >= 0) { + setCurLn(status); + return; + } + } else { + if ((status = docmd(0)) >= 0) { + if (status == 1) + doprnt(P_CURLN, P_CURLN); + return; + } + } + } + report_status(status); +} +#endif + +static void report_status (int status) { + switch (status) { + case EOF: + ED_OUTPUT(ED_DEST, "Exit from ed.\n"); + free_ed_buffer(current_editor); + return; + case CHANGED: + ED_OUTPUT(ED_DEST, "To quit without saving: Q\nSave and quit: x\n"); + break; + case SET_FAIL: + ED_OUTPUT(ED_DEST, "`set' command failed.\n"); + break; + case SUB_FAIL: + ED_OUTPUT(ED_DEST, "string substitution failed.\n"); + break; + case MEM_FAIL: + ED_OUTPUT(ED_DEST, "Out of memory: text may have been lost.\n"); + break; + case UNRECOG_COMMAND: + ED_OUTPUT(ED_DEST, "Unrecognized command.\n"); + break; + case BAD_LINE_RANGE: + ED_OUTPUT(ED_DEST, "Bad line range.\n"); + break; + case BAD_LINE_NUMBER: + ED_OUTPUT(ED_DEST, "Bad line number.\n"); + break; + case SYNTAX_ERROR: + ED_OUTPUT(ED_DEST, "Bad command syntax.\n"); + break; + case RANGE_ILLEGAL: + ED_OUTPUT(ED_DEST, "Cannot use ranges with that command.\n"); + break; + case IS_RESTRICTED: + ED_OUTPUT(ED_DEST, "That command is restricted.\n"); + break; + case LINE_OR_RANGE_ILL: + ED_OUTPUT(ED_DEST, "Cannot use lines or ranges with that command.\n"); + break; + case FILE_NAME_ERROR: + ED_OUTPUT(ED_DEST, "File command failed.\n"); + break; + case MARK_A_TO_Z: + ED_OUTPUT(ED_DEST, "A mark must be in the range 'a to 'z.\n"); + break; + case SUB_BAD_PATTERN: + ED_OUTPUT(ED_DEST, "Bad pattern in search and replace.\n"); + break; + case SUB_BAD_REPLACEMENT: + ED_OUTPUT(ED_DEST, "Bad replacement in search and replace.\n"); + break; + case BAD_DESTINATION: + ED_OUTPUT(ED_DEST, "Bad destination for move or copy.\n"); + break; + case END_OF_FILE: + ED_OUTPUT(ED_DEST, "End of file.\n"); + break; + case SEARCH_FAILED: + ED_OUTPUT(ED_DEST, "Search failed.\n"); + break; + default: + ED_OUTPUT(ED_DEST, "Failed command.\n"); + } +} + +#ifdef OLD_ED +void save_ed_buffer (object_t * who) +{ + svalue_t *stmp; + const char *fname; + + regexp_user = ED_REGEXP; + current_ed_buffer = who->interactive->ed_buffer; + current_editor = who; + + push_malloced_string(add_slash(P_FNAME)); + push_object(who); + /* must be safe; we get called by remove_interactive() */ + stmp = safe_apply_master_ob(APPLY_GET_ED_BUFFER_SAVE_FILE_NAME, 2); + if (stmp && stmp != (svalue_t *)-1) { + if (stmp->type == T_STRING) { + fname = stmp->u.string; + if (*fname == '/') + fname++; + dowrite(1, P_LASTLN, fname, 0); + } + } + free_ed_buffer(who); +} +#endif + +static void print_help (int arg) +{ + char edout[8192]; + char *brkpt; + char *pos = edout; + char *outstr; + int n; + svalue_t *ret; + struct strlst *curp; + int i; + + switch (arg) { + case 'I': + ED_OUTPUT(ED_DEST, "\ +Automatic Indentation (V 1.0)\n\ +------------------------------------\n\ +by Qixx [Update: 7/10/91]\n\n\ +By using the command 'I', a program is run which will\n\ +automatically indent all lines in your code. As this is\n\ +being done, the program will also search for some basic\n\ +errors (which don't show up good during compiling) such as\n\ +Unterminated String, Mismatched Brackets and Parentheses,\n\ +and indented code is easy to understand and debug, since if\n\ +your brackets are off -- the code will LOOK wrong. Please\n\ +mail me at gaunt@mcs.anl.gov with any pieces of code which\n\ +don't get indented properly.\n"); + break; + case 'n': + ED_OUTPUT(ED_DEST, "\ +Command: n Usage: n\n\ +This command toggles the internal flag which will cause line\n\ +numbers to be printed whenever a line is listed.\n"); + break; + case 'a': + ED_OUTPUT(ED_DEST, "\ +Command: a Usage: a\n\ +Append causes the editor to enter input mode, inserting all text\n\ +starting AFTER the current line. Use a '.' on a blank line to exit\n\ +this mode.\n"); + break; + case 'A': + ED_OUTPUT(ED_DEST, "\ +Command: A Usage: A\n\ +Like the 'a' command, but uses inverse autoindent mode.\n"); + break; + case 'i': + ED_OUTPUT(ED_DEST, "\ +Command: i Usage: i\n\ +Insert causes the editor to enter input mode, inserting all text\n\ +starting BEFORE the current line. Use a '.' on a blank line to exit\n\ +this mode.\n"); + break; + case 'c': + ED_OUTPUT(ED_DEST, "\ +Command: c Usage: c\n\ +Change command causes the current line to be wiped from memory.\n\ +The editor enters input mode and all text is inserted where the previous\n\ +line existed.\n"); + break; + case 'd': + ED_OUTPUT(ED_DEST, "\ +Command: d Usage: d or [range]d\n\ +Deletes the current line unless preceeded with a range of lines,\n\ +then the entire range will be deleted.\n"); + break; +#ifndef RESTRICTED_ED + case 'e': + ED_OUTPUT(ED_DEST, "\ +Commmand: e Usage: e filename\n\ +Causes the current file to be wiped from memory, and the new file\n\ +to be loaded in.\n"); + break; + case 'E': + ED_OUTPUT(ED_DEST, "\ +Commmand: E Usage: E filename\n\ +Causes the current file to be wiped from memory, and the new file\n\ +to be loaded in. Different from 'e' in the fact that it will wipe\n\ +the current file even if there are unsaved modifications.\n"); + break; + case 'f': + ED_OUTPUT(ED_DEST, "\ +Command: f Usage: f or f filename\n\ +Display or set the current filename. If filename is given as \n\ +an argument, the file (f) command changes the current filename to\n\ +filename; otherwise, it prints the current filename.\n"); + break; +#endif /* RESTRICTED_ED mode */ + case 'g': + ED_OUTPUT(ED_DEST, "\ +Command: g Usage: g/re/p\n\ +Search in all lines for expression 're', and print\n\ +every match. Command 'l' can also be given\n\ +Unlike in unix ed, you can also supply a range of lines\n\ +to search in\n\ +Compare with command 'v'.\n"); + break; + case 'h': + ED_OUTPUT(ED_DEST, "\ +Command: h Usage: h or hc (where c is a command)\n\ +Help files added by Qixx.\n"); + break; + case 'j': + ED_OUTPUT(ED_DEST, "\ +Command: j Usage: j or [range]j\n\ +Join Lines. Remove the NEWLINE character from between the two\n\ +addressed lines. The defaults are the current line and the line\n\ +following. If exactly one address is given, this command does\n\ +nothing. The joined line is the resulting current line.\n"); + break; + case 'k': + ED_OUTPUT(ED_DEST, "\ +Command: k Usage: kc (where c is a character)\n\ +Mark the addressed line with the name c, a lower-case\n\ +letter. The address-form, 'c, addresses the line\n\ +marked by c. k accepts one address; the default is the\n\ +current line. The current line is left unchanged.\n"); + break; + case 'l': + ED_OUTPUT(ED_DEST, "\ +Command: l Usage: l or [range]l\n\ +List the current line or a range of lines in an unambiguous\n\ +way such that non-printing characters are represented as\n\ +symbols (specifically New-Lines).\n"); + break; + case 'm': + ED_OUTPUT(ED_DEST, "\ +Command: m Usage: mADDRESS or [range]mADDRESS\n\ +Move the current line (or range of lines if specified) to a\n\ +location just after the specified ADDRESS. Address 0 is the\n\ +beginning of the file and the default destination is the\n\ +current line.\n"); + break; + case 'p': + ED_OUTPUT(ED_DEST, "\ +Command: p Usage: p or [range]p\n\ +Print the current line (or range of lines if specified) to the\n\ +screen. See the command 'n' if line numbering is desired.\n"); + break; + case 'q': + ED_OUTPUT(ED_DEST, "\ +Command: q Usage: q\n\ +Quit the editor. Note that you can't quit this way if there\n\ +are any unsaved changes. See 'w' for writing changes to file.\n"); + break; + case 'Q': + ED_OUTPUT(ED_DEST, "\ +Command: Q Usage: Q\n\ +Force Quit. Quit the editor even if the buffer contains unsaved\n\ +modifications.\n"); + break; +#ifndef RESTRICTED_ED + case 'r': + ED_OUTPUT(ED_DEST, "\ +Command: r Usage: r filename\n\ +Reads the given filename into the current buffer starting\n\ +at the current line.\n"); + break; +#endif /* RESTRICTED_ED */ + case 't': + ED_OUTPUT(ED_DEST, "\ +Command: t Usage: tADDRESS or [range]tADDRESS\n\ +Transpose a copy of the current line (or range of lines if specified)\n\ +to a location just after the specified ADDRESS. Address 0 is the\n\ +beginning of the file and the default destination\n\ +is the current line.\n"); + break; + case 'v': + ED_OUTPUT(ED_DEST, "\ +Command: v Usage: v/re/p\n\ +Search in all lines without expression 're', and print\n\ +every match. Other commands than 'p' can also be given\n\ +Compare with command 'g'.\n"); + break; + case 'z': + n = ED_BUFFER->scroll_lines - 1; + ED_OUTPUTV(ED_DEST, "\ +Command: z Usage: z or z- or z-- or z.\n\ +Displays %d lines starting at the current line.\n\ +If the command is 'z.' then %d lines are displayed being\n\ +centered on the current line. The command 'z-' displays\n\ +the %d lines before the current line. The command 'z--' displays\n\ +the %d lines prior to what 'z-' shows.\n", n, n, n, n); + break; + case 'Z': + n = ED_BUFFER->scroll_lines + 4; + ED_OUTPUTV(ED_DEST, "\ +Command: Z Usage: Z or Z- or Z.\n\ +Displays %d lines starting at the current line.\n\ +If the command is 'Z.' then %d lines are displayed being\n\ +centered on the current line. The command 'Z-' displays\n\ +the %d lines before the current line. The command 'Z--' displays\n\ +the %d lines prior to what 'Z-' shows.\n", n, n, n, n); + break; + case 'x': + ED_OUTPUT(ED_DEST, "\ +Command: x Usage: x\n\ +Save file under the current name, and then exit from ed.\n"); + break; + case 's': + if (*inptr == 'e' && *(inptr + 1) == 't') { + ED_OUTPUT(ED_DEST, "\ +Without arguments: show current settings.\n\ +'set save' will preserve the current settings for subsequent invocations of ed.\n\ +Options:\n\ +\n\ +number will print line numbers before printing or inserting a lines\n\ +list will print control characters in p(rint) and z command like in l(ist)\n\ +print will show current line after a single substitution\n\ +eightbit\n\ +autoindent will preserve current indentation while entering text.\n\ + use ^D or ^K to get back one step back to the right.\n\ +excompatible will exchange the meaning of \\( and ( as well as \\) and )\n\ +dprint will print out the current line after deleting text.\n\ +\n\ +An option can be cleared by prepending it with 'no' in the set command, e.g.\n\ +'set nolist' to turn off the list option.\n\ +\n\ +set shiftwidth will store in the shiftwidth variable, which\n\ +determines how much blanks are removed from the current indentation when\n\ +typing ^D or ^K in the autoindent mode.\n"); + } + break; + case '/': + ED_OUTPUT(ED_DEST, "\ +Command: / Usage: /pattern\n\ +finds the next occurence of 'pattern'. Note that pattern\n\ +is a regular expression, so things like .*][() have to be preceded by a \\.\n"); + break; + case '?': + ED_OUTPUT(ED_DEST, "\ +Command: ? Usage: ?pattern\n\ +finds the last occurence of 'pattern' before the current line.\n\ +Note that pattern is a regular expression, so things like .*][() have to be\n\ + preceded by a \\.\n"); + break; + /* someone should REALLY write help for s in the near future */ +#ifndef RESTRICTED_ED + case 'w': + case 'W': + ED_OUTPUT(ED_DEST, "\ +Sorry no help yet for this command. Try again later.\n"); + break; +#endif /* RESTRICTED_ED */ + default: + /* Changed, Hamlet 3/08 -- + The plan is that we're going to send all the help text to + receive_ed() (assuming defined) and then if receive_ed() wants + us to handle the paging, we'll split it up into pieces and more + it. + */ + /* ED_OUTPUT(ED_DEST, "^\tglobal search and print for pattern\n"); */ + + /* You want to leave the spaces before the newlines. They have + relevance - Hamlet + */ + pos += sprintf(pos, "\ + Help for Ed (V 2.0) \n\ +--------------------------------- \n\ + by Qixx [Update: 7/10/91] [Hamlet tweaked 21/03/08 for cleaner output] \n\ +\n\nCommands\n-------- \n\ +/\tsearch forward for pattern \n\ +?\tsearch backward for a pattern \n\ +=\tshow current line number \n\ +a\tappend text starting after this line \n\ +A\tlike 'a' but with inverse autoindent mode \n\ +c\tchange current line, query for replacement text \n\ +d\tdelete line(s) \n"); +#ifdef RESTRICTED_ED + if (!P_RESTRICT) { + pos += sprintf(pos, "\ +e\treplace this file with another file \n\ +E\tsame as 'e' but works if file has been modified \n\ +f\tshow/change current file name \n"); + } +#endif /* restricted ed */ + pos += sprintf(pos, "\ +g\tSearch and execute command on any matching line. \n\ +h\thelp file (display this message) \n\ +i\tinsert text starting before this line \n\ +I\tindent the entire code (Qixx version 1.0) \n\ +j\tjoin lines together \n\ +k\tmark this line with a character - later referenced as 'a \n\ +l\tlist line(s) with control characters displayed \n\ +m\tmove line(s) to specified line \n\ +n\ttoggle line numbering \n\ +O\tsame as 'i' \n\ +o\tsame as 'a' \n\ +p\tprint line(s) in range \n\ +q\tquit editor \n\ +Q\tquit editor even if file modified and not saved \n\ +r\tread file into editor at end of file or behind the given line \n\ +s\tsearch and replace \n\ +set\tquery, change or save option settings \n\ +t\tmove copy of line(s) to specified line \n\ +v\tSearch and execute command on any non-matching line. \n\ +x\tsave file and quit \n"); +#ifdef RESTRICTED_ED + if (!P_RESTRICT) { + pos += sprintf(pos, "\ +w\twrite to current file (or specified file) \n\ +W\tlike the 'w' command but appends instead \n"); + } +#endif /* restricted ed */ + sprintf(pos, "\ +z\tdisplay %d lines, possible args are . + - -- \n\ +Z\tdisplay %d lines, possible args are . + - -- \n\ +\nFor further information type 'hc' where c is the command \n\ +that help is desired for. \n", ED_BUFFER->scroll_lines-1, + ED_BUFFER->scroll_lines+4); + +#ifdef RECEIVE_ED + copy_and_push_string(edout); + push_undefined(); + + ret = apply(APPLY_RECEIVE_ED, ED_DEST, 2, ORIGIN_DRIVER); + if(!ret) + outstr = edout; + else if(ret->type == T_NUMBER) { + // if 0, output it ourselves, else they handled it, we do nothing. + if(ret->u.number == 0) // "pass" + outstr = edout; + else + outstr = (char *) 0; + } + else if(ret->type == T_STRING) { + outstr = (char *) ret->u.string; + } + else if(ret->type == T_ARRAY) { + outstr = (char *) 0; + + curp = P_HELPOUT = (struct strlst *) DMALLOC(sizeof(struct strlst), + TAG_TEMPORARY, "ed: help"); + curp->screen = 0; + curp->next = 0; + + for(i=0; i < ret->u.arr->size; i++) { + if(ret->u.arr->item[i].type != T_STRING) + continue; // dumb. just skip. + + curp->next = (struct strlst *) DMALLOC(sizeof(struct strlst), + TAG_TEMPORARY, "ed: help"); + curp = curp->next; + + curp->next = 0; + curp->screen = DMALLOC(sizeof(char) * + (strlen(ret->u.arr->item[i].u.string) + 1), + TAG_TEMPORARY, "ed: help"); + strcpy(curp->screen, ret->u.arr->item[i].u.string); + } + + curp = P_HELPOUT; + P_HELPOUT = P_HELPOUT->next; + FREE(curp); + } + else { + outstr = edout; // failsafe if they sent something dumb. + } +#else + outstr = edout; +#endif + + if(outstr) { // We need to figure out the paging + char tmpc; + int lines = 0; + + curp = P_HELPOUT = (struct strlst *) DMALLOC(sizeof(struct strlst), + TAG_TEMPORARY, "ed: help"); + curp->next = 0; + + brkpt = outstr; + + /* This will miss a newline at the start of the output... wah */ + while(*brkpt != '\0') { + brkpt++; + + if((*brkpt == '\n') || (*brkpt == '\0')) { + lines++; + + if((lines == (ED_BUFFER->scroll_lines - 1)) || + (*brkpt == '\0')) { + if(*brkpt == '\0') + tmpc = '\0'; + else { + tmpc = *(brkpt+1); // the one past the newline + *(brkpt+1) = '\0'; + } + + curp->next = (struct strlst *) DMALLOC(sizeof(struct strlst), + TAG_TEMPORARY, "ed: help"); + curp = curp->next; + curp->screen = (char *)DMALLOC(sizeof(char) * (strlen(outstr) + 1), + TAG_TEMPORARY, "ed: help"); + strcpy(curp->screen, outstr); + + curp->next = 0; + + if(tmpc != '\0') { + *(brkpt+1) = tmpc; + outstr = brkpt+1; + } + lines = 0; + } + } + //else + // brkpt++; + }; + + /* free the dead head */ + curp = P_HELPOUT; + P_HELPOUT = P_HELPOUT->next; + FREE(curp); + } + + if(P_HELPOUT) + print_help2(); + } +} + +static void print_help2() +{ + struct strlst *curp; + + ED_OUTPUT(ED_DEST, P_HELPOUT->screen); + + curp = P_HELPOUT; + P_HELPOUT = P_HELPOUT->next; + FREE(curp->screen); + FREE(curp); + + if(P_HELPOUT) { + ED_OUTPUT(ED_DEST, "--Return to continue--"); + P_MORE = 1; + } + else + P_MORE = 0; +} +#endif /* ED */ + +/**************************************************************** + Stuff below here is for the new ed() interface. -Beek + ****************************************************************/ + +#ifndef OLD_ED +static char *object_ed_results() { + char *ret; + + outbuf_fix(¤t_ed_results); + ret = current_ed_results.buffer; + outbuf_zero(¤t_ed_results); + + return ret; +} + +static ed_buffer_t *ed_buffer_list; + +static ed_buffer_t *add_ed_buffer (object_t * ob) { + ed_buffer_t *ret; + + ret = ALLOCATE(ed_buffer_t, TAG_ED, "ed_start: ED_BUFFER"); + memset((char *)ret, '\0', sizeof(ed_buffer_t)); + + ob->flags |= O_IN_EDIT; + + ret->owner = ob; + ret->next_ed_buf = ed_buffer_list; + ed_buffer_list = ret; + current_editor = ob; + return ret; +} + +ed_buffer_t *find_ed_buffer (object_t * ob) { + ed_buffer_t *p; + + for (p = ed_buffer_list; p && p->owner != ob; p = p->next_ed_buf) + ; + return p; +} + +static void object_free_ed_buffer() { + ed_buffer_t **p = &ed_buffer_list; + ed_buffer_t *tmp; + + while ((*p)->owner != current_editor) + p = &((*p)->next_ed_buf); + + tmp = *p; + *p = (*p)->next_ed_buf; + FREE(tmp); + + current_editor->flags &= ~O_IN_EDIT; +} + +char *object_ed_start (object_t * ob, const char *fname, int restricted, + int scroll_lines) { + svalue_t *setup; + + /* ensure that the result buffer is initialized */ + outbuf_zero(¤t_ed_results); + + regexp_user = ED_REGEXP; + current_ed_buffer = add_ed_buffer(ob); + + ED_BUFFER->flags |= EIGHTBIT_MASK; + ED_BUFFER->shiftwidth = ED_INDENT_SPACES; + + push_object(current_editor); + setup = apply_master_ob(APPLY_RETRIEVE_ED_SETUP, 1); + if (setup && setup != (svalue_t *)-1 && setup->type == T_NUMBER && setup->u.number) { + ED_BUFFER->flags = setup->u.number & ALL_FLAGS_MASK; + ED_BUFFER->shiftwidth = setup->u.number & SHIFTWIDTH_MASK; + } + ED_BUFFER->CurPtr = &ED_BUFFER->Line0; + + if (restricted) { + P_RESTRICT = 1; + } + + if(scroll_lines) + ED_BUFFER->scroll_lines = scroll_lines; + else + ED_BUFFER->scroll_lines = 20; + + set_ed_buf(); + + /* + * Check for read on startup, since the buffer is read in. But don't + * check for write, since we may want to change the file name. + */ + if (fname + && (fname = + check_valid_path(fname, current_editor, + "ed_start", 0)) + && !doread(0, fname)) { + setCurLn(1); + } + if (fname) { + strncpy(P_FNAME, fname, MAXFNAME - 1); + P_FNAME[MAXFNAME - 1] = 0; + } else { + ED_OUTPUT(ED_DEST, "No file.\n"); + } + return object_ed_results(); +} + +void object_save_ed_buffer (object_t * ob) +{ + svalue_t *stmp; + const char *fname; + + regexp_user = ED_REGEXP; + current_ed_buffer = find_ed_buffer(ob); + current_editor = ob; + + copy_and_push_string(P_FNAME); + stmp = apply_master_ob(APPLY_GET_ED_BUFFER_SAVE_FILE_NAME, 1); + if (stmp && stmp != (svalue_t *)-1) { + if (stmp->type == T_STRING) { + fname = stmp->u.string; + if (*fname == '/') + fname++; + dowrite(1, P_LASTLN, fname, 0); + } + } + free_ed_buffer(current_editor); + outbuf_fix(¤t_ed_results); + if (current_ed_results.buffer) + FREE_MSTR(current_ed_results.buffer); + outbuf_zero(¤t_ed_results); +} + +int object_ed_mode (object_t * ob) { + regexp_user = ED_REGEXP; + current_ed_buffer = find_ed_buffer(ob); + current_editor = ob; + + if (P_MORE) + return -2; + if (P_APPENDING) + return P_CURLN + 1; + + return 0; +} + +char *object_ed_cmd (object_t * ob, const char *str) +{ + int status = 0; + + regexp_user = ED_REGEXP; + current_ed_buffer = find_ed_buffer(ob); + current_editor = ob; + + if (P_MORE) { + print_help2(); + return object_ed_results(); + } + if (P_APPENDING) { + more_append(str); + return object_ed_results(); + } + + strncpy(inlin, str, ED_MAXLINE - 2); + inlin[ED_MAXLINE - 2] = 0; + strcat(inlin, "\n"); + + inptr = inlin; + if ((status = getlst()) >= 0 || status == NO_LINE_RANGE) { + if ((status = ckglob()) != 0) { + if (status >= 0 && (status = doglob()) >= 0) { + setCurLn(status); + return object_ed_results(); + } + } else { + if ((status = docmd(0)) >= 0) { + if (status == 1) + doprnt(P_CURLN, P_CURLN); + return object_ed_results(); + } + } + } + report_status(status); + return object_ed_results(); +} +#endif + diff --git a/fluffos-2.23-ds03/ed.h b/fluffos-2.23-ds03/ed.h new file mode 100644 index 0000000..43215a8 --- /dev/null +++ b/fluffos-2.23-ds03/ed.h @@ -0,0 +1,164 @@ +#ifndef ED_H +#define ED_H + +#include "lpc_incl.h" + +#include "regexp.h" + +/* define this if you don't like the ending dollar signs in ed, in n-mode */ +#undef NO_END_DOLLAR_SIGN +/* + * #defines for non-printing ASCII characters + */ +#define NUL 0x00 /* ^@ */ +#define EOS 0x00 /* end of string */ +#define SOH 0x01 /* ^A */ +#define STX 0x02 /* ^B */ +#define ETX 0x03 /* ^C */ +#define EOT 0x04 /* ^D */ +#define ENQ 0x05 /* ^E */ +#define ACK 0x06 /* ^F */ +#define BEL 0x07 /* ^G */ +#define BS 0x08 /* ^H */ +#define HT 0x09 /* ^I */ +#define LF 0x0a /* ^J */ +#define NL '\n' +#define VT 0x0b /* ^K */ +#define FF 0x0c /* ^L */ +#define CR 0x0d /* ^M */ +#define SO 0x0e /* ^N */ +#define SI 0x0f /* ^O */ +#define DLE 0x10 /* ^P */ +#define DC1 0x11 /* ^Q */ +#define DC2 0x12 /* ^R */ +#define DC3 0x13 /* ^S */ +#define DC4 0x14 /* ^T */ +#define NAK 0x15 /* ^U */ +#define SYN 0x16 /* ^V */ +#define ETB 0x17 /* ^W */ +#define CAN 0x18 /* ^X */ +#define EM 0x19 /* ^Y */ +#define SUB 0x1a /* ^Z */ +#define ESC 0x1b /* ^[ */ +#define FS 0x1c /* ^\ */ +#define GS 0x1d /* ^] */ +#define US 0x1f /* ^_ */ +#define SP 0x20 /* space */ +#define DEL 0x7f /* DEL */ +#define ESCAPE '\\' + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif +#define EDERR -2 +#define FATAL (EDERR-1) +#define CHANGED (EDERR-2) +#define SET_FAIL (EDERR-3) +#define SUB_FAIL (EDERR-4) +#define MEM_FAIL (EDERR-5) +#define UNRECOG_COMMAND (EDERR-6) + +#define BAD_LINE_RANGE (EDERR-7) +#define BAD_LINE_NUMBER (EDERR-8) +#define SYNTAX_ERROR (EDERR-9) +#define RANGE_ILLEGAL (EDERR-10) +#define IS_RESTRICTED (EDERR-11) +#define LINE_OR_RANGE_ILL (EDERR-12) +#define FILE_NAME_ERROR (EDERR-13) +#define MARK_A_TO_Z (EDERR-14) +#define SUB_BAD_PATTERN (EDERR-15) +#define SUB_BAD_REPLACEMENT (EDERR-16) +#define BAD_DESTINATION (EDERR-17) +#define END_OF_FILE (EDERR-18) +#define SEARCH_FAILED (EDERR-19) +#define NO_LINE_RANGE (EDERR-20) + +// This one hopefully holds a screen's data for the 'z' command. +// Even if bytes per line is actually 80, this is still 50-ish lines. +#define BUFFER_SIZE 4096 + +#define LGLOB 2 /* line marked global */ + +#define ED_MAXLINE 2047 /* max number of chars per line */ +#define MAXPAT 256 /* max number of chars per replacemnt pattern */ +#define MAXFNAME 256 /* max file name size */ + +typedef struct ed_line_s { + int l_stat; /* empty, mark */ + struct ed_line_s *l_prev; + struct ed_line_s *l_next; + char l_buff[1]; +} ed_line_t; + +struct strlst { + char *screen; + struct strlst *next; +}; + +typedef struct ed_buffer_s { + int nonascii; /* count of non-ascii chars read */ + int nullchar; /* count of null chars read */ + int truncated; /* count of lines truncated */ + char fname[MAXFNAME]; + int fchanged; /* file-changed? flag */ + int nofname; + int mark['z' - 'a' + 1]; + regexp *oldpat; + + ed_line_t Line0; + int CurLn; + ed_line_t *CurPtr; /* CurLn and CurPtr must be kept in step */ + int LastLn; + int Line1, Line2, nlines; + int flags; + int appending; + int moring; /* used for the wait line of help */ + struct strlst *helpout; /* help output linked list */ +#ifdef OLD_ED + char *exit_fn; /* Function to be called when user exits */ + char *write_fn; /* Function to be called when user writes */ + object_t *exit_ob; /* in this object */ +#else + object_t *owner; + struct ed_buffer_s *next_ed_buf; +#endif + int shiftwidth; + int leading_blanks; + int cur_autoindent; + int scroll_lines; + int restricted; /* restricted access ed */ +} ed_buffer_t; + +/* + * ed.c + */ +void ed_start (const char *, const char *, const char *, int, object_t *, int); +void ed_cmd (char *); +void save_ed_buffer (object_t *); + +#ifdef OLD_ED +#define ED_OUTPUT(x, y) add_message(x, y, strlen(y)) +#define ED_OUTPUTV add_vmessage +#define ED_DEST command_giver +#else +#define ED_OUTPUT outbuf_add +#define ED_OUTPUTV outbuf_addv +#define ED_DEST ¤t_ed_results +#endif + +#ifndef OLD_ED +char *object_ed_cmd (object_t *, const char *); +char *object_ed_start (object_t *, const char *, int, int); +int object_ed_mode (object_t *); +void object_save_ed_buffer (object_t *); +ed_buffer_t *find_ed_buffer (object_t *); +void object_ed_output (char *); +void object_ed_outputv(char *, ...); + +extern outbuffer_t current_ed_results; +#endif + +#endif diff --git a/fluffos-2.23-ds03/edit_source.c b/fluffos-2.23-ds03/edit_source.c new file mode 100644 index 0000000..49a30c4 --- /dev/null +++ b/fluffos-2.23-ds03/edit_source.c @@ -0,0 +1,1744 @@ +#define CONFIGURE_VERSION 5 + +#define EDIT_SOURCE +#define NO_MALLOC +#define NO_SOCKETS +#define NO_OPCODES +#include "std.h" +#include "lex.h" +#include "preprocess.h" +#include "make_func.h" +#include "cc.h" +#include "hash.h" +#include +#include + +#ifdef WIN32 +#include +#include +#endif + +#if defined(DEBUG) || defined(WIN32) +#define TO_DEV_NULL "" +#else +#define TO_DEV_NULL ">/dev/null 2>&1" +#endif + +/* Using an include file at this point would be bad */ +#ifdef PEDANTIC +char *malloc(int); +char *realloc(char *, int); +void free(char *); +#endif + +char *outp; +static int buffered = 0; +static int nexpands = 0; + +FILE *yyin = 0, *yyout = 0; + +#define SYNTAX "edit_source [-process file] [-options] [-malloc] [-build_func_spec 'command'] [-build_efuns] [-configure]\n" + +/* The files we fool with. (Actually, there are more. See -process). + * + * TODO: teach this file how to fix bugs in the source code :) + */ +#define OPTIONS_INCL "options_incl.h" +#define PACKAGES "packages/packages" +#define OPTIONS_H "options.h" +#define LOCAL_OPTIONS "local_options" +#define OPTION_DEFINES "option_defs.c" +#define FUNC_SPEC "func_spec.c" +#define FUNC_SPEC_CPP "func_spec.cpp" +#define EFUN_TABLE "efunctions.h" +#define OPC_PROF "opc.h" +#define OPCODES "opcodes.h" +#define EFUN_PROTO "efun_protos.h" +#define EFUN_DEFS "efun_defs.c" + +#define PRAGMA_NOTE_CASE_START 1 + +int num_packages = 0; +char *packages[100]; +char ppchar; + +char *current_file = 0; +int current_line; + +int grammar_mode = 0; /* which section we're in for .y files */ +int in_c_case, cquote, pragmas, block_nest; + +char yytext[MAXLINE]; +static char defbuf[DEFMAX]; + +typedef struct incstate_t { + struct incstate_t *next; + FILE *yyin; + int line; + char *file; +} incstate; + +static incstate *inctop = 0; + +#define CHAR_QUOTE 1 +#define STRING_QUOTE 2 + +static void add_define (const char *, int, const char *); + +#ifdef WIN32 +#include + +int compile(char *command) { + FILE *tf = fopen("trash_me.bat","wt+"); + + fprintf(tf,"%s%s\n%s", + "@echo off\n", + command, + "if errorlevel == 1 goto error\n" + "del trash_me.err >nul\n" + "goto ok\n" + ":error\n" + "echo ERROR > trash_me.err\n" + ":ok\n"); + fclose(tf); + + if (!system("trash_me.bat > nul")) return 1; + if (_access("trash_me.err",0) ) return 1; + return 0; +} +#else +int compile (char * str) { + return system(str); +} +#endif + +#if defined(WIN32) +int dos_style_link (char * x, char * y) { + char link_cmd[100]; + sprintf(link_cmd, "copy %s %s", x, y); + return system(link_cmd); +} +#endif + +void yyerror (const char * str) +{ + fprintf(stderr, "%s:%d: %s\n", current_file, current_line, str); + exit(1); +} + +void mf_fatal (const char * str) +{ + yyerror(str); +} + +void yywarn (char * str) +{ + /* ignore errors :) local_options generates redefinition warnings, + which we don't want to see */ +} + +void yyerrorp (const char * str) +{ + char buff[200]; + sprintf(buff, str, ppchar); + fprintf(stderr, "%s:%d: %s\n", current_file, current_line, buff); + exit(1); +} + +static void add_input (const char * p) +{ + int l = strlen(p); + + if (outp - l < defbuf) yyerror("Macro expansion buffer overflow.\n"); + strncpy(outp - l, p, l); + outp -= l; +} + +#define SKIPW(foo) while (isspace(*foo)) foo++; + +static char *skip_comment(char *tmp, int flag) +{ + int c; + + for (;;) { + while ((c = *++tmp) != '*') { + if (c == EOF) yyerror("End of file in a comment"); + if (c == '\n') { + nexpands = 0; + current_line++; + if (!fgets(yytext, MAXLINE - 1, yyin)) yyerror("End of file in a comment"); + if (flag && yyout) fputs(yytext, yyout); + tmp = yytext - 1; + } + } + do { + if ((c = *++tmp) == '/') + return tmp + 1; + if (c == '\n') { + nexpands = 0; + current_line++; + if (!fgets(yytext, MAXLINE - 1, yyin)) yyerror("End of file in a comment"); + if (flag && yyout) fputs(yytext, yyout); + tmp = yytext - 1; + } + } while (c == '*'); + } +} + +static void refill() +{ + register char *p, *yyp; + int c; + + if (fgets(p = yyp = defbuf + (DEFMAX >> 1), MAXLINE - 1, yyin)) { + while (((c = *yyp++) != '\n') && (c != EOF)) { + if (c == '/') { + if ((c = *yyp) == '*') { + yyp = skip_comment(yyp, 0); + continue; + } + else if (c == '/') break; + } + *p++ = c; + } + } + else yyerror("End of macro definition in \\"); + nexpands = 0; + current_line++; + *p = 0; + return; +} + +static void handle_define() +{ + char namebuf[NSIZE]; + char args[NARGS][NSIZE]; + char mtext[MLEN]; + char *end; + register char *tmp = outp, *q; + + q = namebuf; + end = q + NSIZE - 1; + while (isalunum(*tmp)) { + if (q < end) *q++ = *tmp++; + else yyerror("Name too long.\n"); + } + if (q == namebuf) yyerror("Macro name missing.\n"); + if (*namebuf != '_' && !isalpha(*namebuf)) yyerror("Invalid macro name.\n"); + *q = 0; + if (*tmp == '(') { /* if "function macro" */ + int arg; + int inid; + char *ids = (char *) NULL; + + tmp++; /* skip '(' */ + SKIPW(tmp); + if (*tmp == ')') { + arg = 0; + } else { + for (arg = 0; arg < NARGS;) { + end = (q = args[arg]) + NSIZE - 1; + while (isalunum(*tmp) || (*tmp == '#')) { + if (q < end) *q++ = *tmp++; + else yyerror("Name too long.\n"); + } + if (q == args[arg]) { + char buff[200]; + sprintf(buff, "Missing argument %d in #define parameter list", arg + 1); + yyerror(buff); + } + arg++; + SKIPW(tmp); + if (*tmp == ')') + break; + if (*tmp++ != ',') { + yyerror("Missing ',' in #define parameter list"); + } + SKIPW(tmp); + } + if (arg == NARGS) yyerror("Too many macro arguments"); + } + tmp++; /* skip ')' */ + end = mtext + MLEN - 2; + for (inid = 0, q = mtext; *tmp;) { + if (isalunum(*tmp)) { + if (!inid) { + inid++; + ids = tmp; + } + } else { + if (inid) { + int idlen = tmp - ids; + int n, l; + + for (n = 0; n < arg; n++) { + l = strlen(args[n]); + if (l == idlen && strncmp(args[n], ids, l) == 0) { + q -= idlen; + *q++ = MARKS; + *q++ = n + MARKS + 1; + break; + } + } + inid = 0; + } + } + if ((*q = *tmp++) == MARKS) *++q = MARKS; + if (q < end) q++; + else yyerror("Macro text too long"); + if (!*tmp && tmp[-2] == '\\') { + q -= 2; + refill(); + tmp = defbuf + (DEFMAX >> 1); + } + } + *--q = 0; + add_define(namebuf, arg, mtext); + } else if (isspace(*tmp) || (!*tmp && (*(tmp+1) = '\0', *tmp = ' '))) { + end = mtext + MLEN - 2; + for (q = mtext; *tmp;) { + *q = *tmp++; + if (q < end) q++; + else yyerror("Macro text too long"); + if (!*tmp && tmp[-2] == '\\') { + q -= 2; + refill(); + tmp = defbuf + (DEFMAX >> 1); + } + } + *q = 0; + add_define(namebuf, -1, mtext); + } else { + yyerror("Illegal macro symbol"); + } + return; +} + +#define SKPW while (isspace(*outp)) outp++ + +static int cmygetc() { + int c; + + for (;;) { + if ((c = *outp++) == '/') { + if ((c = *outp) == '*') outp = skip_comment(outp, 0); + else if (c == '/') return -1; + else return c; + } else return c; + } +} + +/* Check if yytext is a macro and expand if it is. */ +static int expand_define() +{ + defn_t *p; + char expbuf[DEFMAX]; + char *args[NARGS]; + char buf[DEFMAX]; + char *q, *e, *b; + + if (nexpands++ > EXPANDMAX) yyerror("Too many macro expansions"); + if (!(p = lookup_define(yytext))) return 0; + if (p->nargs == -1) { + add_input(p->exps); + } else { + int c, parcnt = 0, dquote = 0, squote = 0; + int n; + + SKPW; + if (*outp++ != '(') yyerror("Missing '(' in macro call"); + SKPW; + if ((c = *outp++) == ')') + n = 0; + else { + q = expbuf; + args[0] = q; + for (n = 0; n < NARGS;) { + switch (c) { + case '"': + if (!squote) + dquote ^= 1; + break; + case '\'': + if (!dquote) + squote ^= 1; + break; + case '(': + if (!squote && !dquote) + parcnt++; + break; + case ')': + if (!squote && !dquote) + parcnt--; + break; + case '#': + if (!squote && !dquote) { + *q++ = c; + if (*outp++ != '#') yyerror("'#' expected"); + } + break; + case '\\': + if (squote || dquote) { + *q++ = c; + c = *outp++; + } break; + case '\n': + if (squote || dquote) yyerror("Newline in string"); + break; + } + if (c == ',' && !parcnt && !dquote && !squote) { + *q++ = 0; + args[++n] = q; + } else if (parcnt < 0) { + *q++ = 0; + n++; + break; + } else { + if (c == EOF) yyerror("Unexpected end of file"); + if (q >= expbuf + DEFMAX - 5) { + yyerror("Macro argument overflow"); + } else { + *q++ = c; + } + } + if (!squote && !dquote) { + if ((c = cmygetc()) < 0) yyerror("End of macro in // comment"); + } + else c = *outp++; + } + if (n == NARGS) { + yyerror("Maximum macro argument count exceeded"); + return 0; + } + } + if (n != p->nargs) { + yyerror("Wrong number of macro arguments"); + return 0; + } + /* Do expansion */ + b = buf; + e = p->exps; + while (*e) { + if (*e == '#' && *(e + 1) == '#') + e += 2; + if (*e == MARKS) { + if (*++e == MARKS) + *b++ = *e++; + else { + for (q = args[*e++ - MARKS - 1]; *q;) { + *b++ = *q++; + if (b >= buf + DEFMAX) yyerror("Macro expansion overflow"); + } + } + } else { + *b++ = *e++; + if (b >= buf + DEFMAX) yyerror("Macro expansion overflow"); + } + } + *b++ = 0; + add_input(buf); + } + return 1; +} + +static int exgetc() +{ + register char c, *yyp; + + SKPW; + while (isalpha(c = *outp) || c == '_') { + yyp = yytext; + do { + *yyp++ = c; + } while (isalnum(c = *++outp) || (c == '_')); + *yyp = '\0'; + if (!strcmp(yytext, "defined")) { + /* handle the defined "function" in #/%if */ + SKPW; + if (*outp++ != '(') yyerror("Missing ( after 'defined'"); + SKPW; + yyp = yytext; + if (isalpha(c = *outp) || c == '_') { + do { + *yyp++ = c; + } while (isalnum(c = *++outp) || (c == '_')); + *yyp = '\0'; + } + else yyerror("Incorrect definition macro after defined(\n"); + SKPW; + if (*outp != ')') yyerror("Missing ) in defined"); + if (lookup_define(yytext)) + add_input("1 "); + else + add_input("0 "); + } else { + if (!expand_define()) + add_input("0 "); + else SKPW; + } + } + return c; +} + +static int skip_to(const char *token, const char *atoken) +{ + char b[20], *p, *end; + int c; + int nest; + + for (nest = 0;;) { + if (!fgets(outp = defbuf + (DEFMAX >> 1), MAXLINE-1,yyin)) { + yyerror("Unexpected end of file while skipping"); + } + current_line++; + if ((c = *outp++) == ppchar) { + while (isspace(*outp)) outp++; + end = b + sizeof b - 1; + for (p = b; (c = *outp++) != '\n' && !isspace(c) && c != EOF;) { + if (p < end) *p++ = c; + } + *p = 0; + if (!strcmp(b, "if") || !strcmp(b, "ifdef") || !strcmp(b, "ifndef")) { + nest++; + } else if (nest > 0) { + if (!strcmp(b, "endif")) + nest--; + } else { + if (!strcmp(b, token)) { + *--outp = c; + add_input(b); + *--outp = ppchar; + buffered = 1; + return 1; + } else if (atoken && !strcmp(b, atoken)) { + *--outp = c; + add_input(b); + *--outp = ppchar; + buffered = 1; + return 0; + } else if (!strcmp(b, "elif")) { + *--outp = c; + add_input(b); + *--outp = ppchar; + buffered = 1; + return !atoken; + } + } + } + } +} + +#include "preprocess.c" + +static int maybe_open_input_file (const char * fn) { + if ((yyin = fopen(fn, "r")) == NULL) { + return 0; + } + if (current_file) free((char *)current_file); + current_file = (char *)malloc(strlen(fn) + 1); + current_line = 0; + strcpy(current_file, fn); + return 1; +} + +static void open_input_file (const char * fn) { + if (!maybe_open_input_file(fn)) { + perror(fn); + exit(-1); + } +} + +static void open_output_file (const char * fn) { + if ((yyout = fopen(fn, "w")) == NULL) { + perror(fn); + exit(-1); + } +} + +static void close_output_file() { + fclose(yyout); + yyout = 0; +} + +static char *protect (const char * p) { + static char buf[1024]; + char *bufp = buf; + + while (*p) { + if (*p=='"' || *p == '\\') *bufp++ = '\\'; + *bufp++ = *p++; + } + *bufp = 0; + return buf; +} + +static void +create_option_defines() { + defn_t *p; + int count = 0; + int i; + + fprintf(stderr, "Writing build options to %s ...\n", OPTION_DEFINES); + open_output_file(OPTION_DEFINES); + fprintf(yyout, "{\n"); + for (i = 0; i < DEFHASH; i++) { + for (p = defns[i]; p; p = p->next) + if (!(p->flags & DEF_IS_UNDEFINED)) { + count++; + fprintf(yyout, " \"__%s__\", \"%s\",\n", + p->name, protect(p->exps)); + if (strncmp(p->name, "PACKAGE_", 8)==0) { + int len; + char *tmp, *t; + + len = strlen(p->name + 8); + t = tmp = (char *)malloc(len + 1); + strcpy(tmp, p->name + 8); + while (*t) { + if (isupper(*t)) + *t = tolower(*t); + t++; + } + if (num_packages == 100) { + fprintf(stderr, "Too many packages.\n"); + exit(-1); + } + packages[num_packages++] = tmp; + } + } + } + fprintf(yyout,"};\n\n#define NUM_OPTION_DEFS %d\n\n", count); + close_output_file(); +} + +static void deltrail() { + register char *p; + + p = outp; + while (*p && !isspace(*p) && *p != '\n') { + p++; + } + *p = 0; +} + +static void +handle_include (char * name) +{ + char *p; + static char buf[1024]; + FILE *f; + incstate *is; + + if (*name != '"') { + defn_t *d; + + if ((d = lookup_define(name)) && d->nargs == -1) { + char *q; + + q = d->exps; + while (isspace(*q)) + q++; + handle_include(q); + } else { + yyerrorp("Missing leading \" in %cinclude"); + } + return; + } + for (p = ++name; *p && *p != '"'; p++); + if (!*p) yyerrorp("Missing trailing \" in %cinclude"); + + *p = 0; + if ((f = fopen(name, "r")) != NULL) { + is = (incstate *) + malloc(sizeof(incstate) /*, 61, "handle_include: 1" */); + is->yyin = yyin; + is->line = current_line; + is->file = current_file; + is->next = inctop; + inctop = is; + current_line = 0; + current_file = (char *)malloc(strlen(name) + 1 /*, 62, "handle_include: 2" */); + strcpy(current_file, name); + yyin = f; + } else { + sprintf(buf, "Cannot %cinclude %s", ppchar, name); + yyerror(buf); + } +} + +static void +handle_pragma (char * name) +{ + if (!strcmp(name, "auto_note_compiler_case_start")) + pragmas |= PRAGMA_NOTE_CASE_START; + else if (!strcmp(name, "no_auto_note_compiler_case_start")) + pragmas &= ~PRAGMA_NOTE_CASE_START; + else if (!strncmp(name, "ppchar:", 7) && *(name + 8)) + ppchar = *(name + 8); + else yyerrorp("Unidentified %cpragma"); +} + +static void +preprocess() { + register char *yyp, *yyp2; + int c; + int cond; + + while (buffered ? (yyp = yyp2 = outp) : fgets(yyp = yyp2 = defbuf + (DEFMAX >> 1), MAXLINE-1, yyin)) { + if (!buffered) current_line++; + else buffered = 0; + while (isspace(*yyp2)) yyp2++; + if ((c = *yyp2) == ppchar) { + int quote = 0; + char sp_buf = 0, *oldoutp; + + if (c == '%' && yyp2[1] == '%') + grammar_mode++; + outp = 0; + if (yyp != yyp2) yyerrorp("Misplaced '%c'.\n"); + while (isspace(*++yyp2)); + yyp++; + for (;;) { + if ((c = *yyp2++) == '"') quote ^= 1; + else{ + if (!quote && c == '/') { + if (*yyp2 == '*') { + yyp2 = skip_comment(yyp2, 0); + continue; + } + else if (*yyp2 == '/') break; + } + if (!outp && isspace(c)) outp = yyp; + if (c == '\n' || c == EOF) break; + } + *yyp++ = c; + } + + if (outp) { + if (yyout) sp_buf = *(oldoutp = outp); + *outp++ = 0; + while (isspace(*outp)) outp++; + } + else outp = yyp; + *yyp = 0; + yyp = defbuf + (DEFMAX >> 1) + 1; + + if (!strcmp("define", yyp)) { + handle_define(); + } else if (!strcmp("if", yyp)) { + cond = cond_get_exp(0); + if (*outp != '\n') yyerrorp("Condition too complex in %cif"); + else handle_cond(cond); + } else if (!strcmp("ifdef", yyp)) { + deltrail(); + handle_cond(lookup_define(outp) != 0); + } else if (!strcmp("ifndef", yyp)) { + deltrail(); + handle_cond(!lookup_define(outp)); + } else if (!strcmp("elif", yyp)) { + handle_elif(); + } else if (!strcmp("else", yyp)) { + handle_else(); + } else if (!strcmp("endif", yyp)) { + handle_endif(); + } else if (!strcmp("undef", yyp)) { + defn_t *d; + + deltrail(); + if ((d = lookup_definition(outp))) { + d->flags |= DEF_IS_UNDEFINED; + d->flags &= ~DEF_IS_NOT_LOCAL; + } else { + add_define(outp, -1, " "); + d = lookup_definition(outp); + d->flags |= DEF_IS_UNDEFINED; + d->flags &= ~DEF_IS_NOT_LOCAL; + } + } else if (!strcmp("echo", yyp)) { + fprintf(stderr, "echo at line %d of %s: %s\n", current_line, current_file, outp); + } else if (!strcmp("include", yyp)) { + handle_include(outp); + } else if (!strcmp("pragma", yyp)) { + handle_pragma(outp); + } else if (yyout) { + if (!strcmp("line", yyp)) { + fprintf(yyout, "#line %d \"%s\"\n", current_line, + current_file); + } else { + if (sp_buf) *oldoutp = sp_buf; + if (pragmas & PRAGMA_NOTE_CASE_START) { + if (*yyp == '%') pragmas &= ~PRAGMA_NOTE_CASE_START; + } + fprintf(yyout, "%s\n", yyp-1); + } + } else { + char buff[200]; + sprintf(buff, "Unrecognised %c directive : %s\n", ppchar, yyp); + yyerror(buff); + } + } + else if (c == '/') { + if ((c = *++yyp2) == '*') { + if (yyout) fputs(yyp, yyout); + yyp2 = skip_comment(yyp2, 1); + } else if (c == '/' && !yyout) continue; + else if (yyout) { + fprintf(yyout, "%s", yyp); + } + } + else if (yyout) { + fprintf(yyout, "%s", yyp); + if (pragmas & PRAGMA_NOTE_CASE_START) { + static int line_to_print; + + line_to_print = 0; + + if (!in_c_case) { + while (isalunum(*yyp2)) yyp2++; + while (isspace(*yyp2)) yyp2++; + if (*yyp2 == ':') { + in_c_case = 1; + yyp2++; + } + } + + if (in_c_case) { + while ((c = *yyp2++)) { + switch(c) { + case '{': + { + if (!cquote && (++block_nest == 1)) + line_to_print = 1; + break; + } + + case '}': + { + if (!cquote) { + if (--block_nest < 0) yyerror("Too many }'s"); + } + break; + } + + case '"': + if (!(cquote & CHAR_QUOTE)) cquote ^= STRING_QUOTE; + break; + + case '\'': + if (!(cquote & STRING_QUOTE)) cquote ^= CHAR_QUOTE; + break; + + case '\\': + if (cquote && *yyp2) yyp2++; + break; + + case '/': + if (!cquote) { + if ((c = *yyp2) == '*') { + yyp2 = skip_comment(yyp2, 1); + } else if (c == '/') { + *(yyp2-1) = '\n'; + *yyp2 = '\0'; + } + } + break; + + case ':': + if (!cquote && !block_nest) + yyerror("Case started before ending previous case with ;"); + break; + + case ';': + if (!cquote && !block_nest) in_c_case = 0; + } + } + } + + if (line_to_print) + fprintf(yyout, "#line %d \"%s\"\n", current_line + 1,current_file); + + } + } + } + if (iftop) { + ifstate_t *p = iftop; + + while (iftop) { + p = iftop; + iftop = p->next; + free((char *)p); + } + yyerrorp("Missing %cendif"); + } + fclose(yyin); + free(current_file); + current_file = 0; + nexpands = 0; + if (inctop) { + incstate *p = inctop; + + current_file = p->file; + current_line = p->line; + yyin = p->yyin; + inctop = p->next; + free((char *) p); + preprocess(); + } else yyin = 0; +} + +void make_efun_tables() +{ +#define NUM_FILES 5 + static const char* outfiles[NUM_FILES] = { + EFUN_TABLE, OPC_PROF, OPCODES, EFUN_PROTO, EFUN_DEFS + }; + FILE *files[NUM_FILES]; + int i; + + fprintf(stderr, "Building efun tables ...\n"); + for (i = 0; i < NUM_FILES; i++) { + files[i] = fopen(outfiles[i], "w"); + if (!files[i]) { + fprintf(stderr, "make_func: unable to open %s\n", outfiles[i]); + exit(-1); + } + fprintf(files[i], + "/*\n\tThis file is automatically generated by make_func.\n"); + fprintf(files[i], + "\tdo not make any manual changes to this file.\n*/\n\n"); + } + + fprintf(files[0],"\n#include \"efun_protos.h\"\n\n"); + fprintf(files[0],"\ntypedef void (*func_t) (void);\n\n"); + fprintf(files[0],"func_t efun_table[] = {\n"); + + fprintf(files[1],"\ntypedef struct opc_s { char *name; int count; } opc_t;\n\n"); + fprintf(files[1],"opc_t opc_efun[] = {\n"); + + fprintf(files[2], "\n/* operators */\n\n"); + for (i = 0; i < op_code; i++) { + fprintf(files[2],"#define %-30s %d\n", oper_codes[i], i+1); + } + + fprintf(files[2],"\n/* 1 arg efuns */\n#define BASE %d\n\n", op_code+1); + for (i = 0; i < efun1_code; i++) { + fprintf(files[0],"\tf_%s,\n", efun1_names[i]); + fprintf(files[1],"{\"%s\", 0},\n", efun1_names[i]); + fprintf(files[2],"#define %-30s %d\n", efun1_codes[i], i+op_code+1); + fprintf(files[3],"void f_%s (void);\n", efun1_names[i]); + } + + fprintf(files[2],"\n/* efuns */\n#define ONEARG_MAX %d\n\n", efun1_code + op_code+1); + for (i = 0; i < efun_code; i++) { + fprintf(files[0],"\tf_%s,\n", efun_names[i]); + fprintf(files[1],"{\"%s\", 0},\n", efun_names[i]); + fprintf(files[2],"#define %-30s %d\n", efun_codes[i], i+op_code+efun1_code+1); + fprintf(files[3],"void f_%s (void);\n", efun_names[i]); + } + fprintf(files[0], "};\n"); + fprintf(files[1], "};\n"); + + if (efun1_code + op_code >= 256) { + fprintf(stderr, "You have way too many efuns. Contact the MudOS developers if you really need this many.\n"); + } + if (efun_code >= 256) { + fprintf(stderr, "You have way too many efuns. Contact the MudOS developers if you really need this many.\n"); + } + fprintf(files[2],"\n/* efuns */\n#define NUM_OPCODES %d\n\n", efun_code + efun1_code + op_code); + + /* Now sort the main_list */ + for (i = 0; i < num_buff; i++) { + int j; + for (j = 0; j < i; j++) + if (strcmp(key[i], key[j]) < 0) { + const char *tmp; + tmp = key[i]; key[i] = key[j]; key[j] = tmp; + tmp = buf[i]; buf[i] = buf[j]; buf[j] = tmp; + } + } + + /* Now display it... */ + fprintf(files[4], "{\n"); + for (i = 0; i < num_buff; i++) + fprintf(files[4], "%s", buf[i]); + fprintf(files[4], "\n};\nint efun_arg_types[] = {\n"); + for (i=0; i < last_current_type; i++) { + if (arg_types[i] == 0) + fprintf(files[4], "0,\n"); + else + fprintf(files[4], "%s,", ctype(arg_types[i])); + } + fprintf(files[4],"};\n"); + + for (i=0; i < NUM_FILES; i++) + fclose(files[i]); +} + +static void handle_local_defines(int check) { + defn_t *p; + int i; + int problem = 0; + + for (i = 0; i < DEFHASH; i++) + for (p = defns[i]; p; p = p->next) + p->flags |= DEF_IS_NOT_LOCAL; + + /* undefine _OPTIONS_H_ so it doesn't get propagated to the mudlib + or interfere with copies of options.h */ + if ((p = lookup_define("_OPTIONS_H_"))) { + p->flags |= DEF_IS_UNDEFINED; + p->flags &= ~DEF_IS_NOT_LOCAL; + } + if ((p = lookup_define("DEBUG"))) + p->flags &= ~DEF_IS_NOT_LOCAL; + + ppchar = '#'; + preprocess(); + + if ((p = lookup_define("_OPTIONS_H_"))) + p->flags |= DEF_IS_UNDEFINED; + + if (!check) + return; + + for (i = 0; i < DEFHASH; i++) + for (p = defns[i]; p; p = p->next) + if (p->flags & DEF_IS_NOT_LOCAL) { + fprintf(stderr, "No setting for %s in '%s'.\n", + p->name, LOCAL_OPTIONS); + problem = 1; + } + + if (problem) { + fprintf(stderr, "\ +***This local_options file appears to have been written for an\n\ +***earlier version of the MudOS driver. Please lookup the new options\n\ +***(mentioned above) in the options.h file, decide how you would like them\n\ +***set, and add those settings to the local_options file.\n"); + exit(-1); + } +} + +static void write_options_incl (int local) { + open_output_file(OPTIONS_INCL); + if (local) { + fprintf(yyout, "#include \"%s\"\n", LOCAL_OPTIONS); + } else { + fprintf(yyout, "#include \"%s\"\n", OPTIONS_H); + } + close_output_file(); +} + +static void handle_options(int full) { + open_input_file(OPTIONS_H); + ppchar = '#'; + preprocess(); + + if (!full) { + /* don't do any checking, just find out what is defined */ + if (maybe_open_input_file(LOCAL_OPTIONS)) + handle_local_defines(0); + return; + } + + if (maybe_open_input_file(LOCAL_OPTIONS)) { + fprintf(stdout, "Using '%s' file ...\n", LOCAL_OPTIONS); + handle_local_defines(1); + write_options_incl(1); + } else { + fprintf(stderr, "No \"%s\" file present. If you create one from \"%s\",\nyou can use it when you get a new driver, and you will be warned if there are\nchanges to the real %s which you should include in your local file.\n", + LOCAL_OPTIONS, OPTIONS_H, OPTIONS_H); + write_options_incl(0); + } + + create_option_defines(); +} + +static void handle_build_func_spec (char * command) { + char buf[1024]; + int i; + + fprintf(stderr, "Building compiler files ...\n"); + sprintf(buf, "%s %s >%s", command, FUNC_SPEC, FUNC_SPEC_CPP); + system(buf); + for (i = 0; i < num_packages; i++) { + sprintf(buf, "%s -I. packages/%s_spec.c >>%s", + command, packages[i], FUNC_SPEC_CPP); + system(buf); + } + + open_output_file(PACKAGES); + fprintf(yyout, "SRC="); + for (i=0; i < num_packages; i++) + fprintf(yyout, "%s.c ", packages[i]); + fprintf(yyout, "\nOBJ="); + for (i=0; i < num_packages; i++) + fprintf(yyout, "%s.$(O) ", packages[i]); + fprintf(yyout, "\n"); + close_output_file(); +} + +static void handle_process (char * file) { + char buf[1024]; + int l; + + strcpy(buf, file); + l = strlen(buf); + if (strcmp(buf + l - 4, ".pre")) { + fprintf(stderr, "Filename for -process must end in .pre\n"); + exit(-1); + } + *(buf + l - 4) = 0; + + fprintf(stderr, "Creating '%s' from '%s' ...\n", buf, file); + +#ifdef DEBUG + /* pass down the DEBUG define from CFLAGS */ + add_define("DEBUG", -1, " "); +#endif + + open_input_file(file); + open_output_file(buf); + ppchar = '%'; + preprocess(); + close_output_file(); +} + +static void handle_build_efuns() { + void yyparse(); + + num_buff = op_code = efun_code = efun1_code = 0; + + open_input_file(FUNC_SPEC_CPP); + yyparse(); + make_efun_tables(); +} + +static void handle_applies() { + FILE *f = fopen("applies", "r"); + FILE *out = fopen("applies.h", "w"); + FILE *table = fopen("applies_table.c", "w"); + char buf[8192]; + char *colon; + char *p; + int apply_number = 0; + + fprintf(out, "/* autogenerated from 'applies' */\n#ifndef APPLIES_H\n#define APPLIES_H\n\nextern const char *applies_table[];\n\n/* the folowing must be the first character of __INIT */\n#define APPLY___INIT_SPECIAL_CHAR\t\t'#'\n"); + fprintf(table, "/* autogenerated from 'applies' */\n\nconst char *applies_table[] = {\n"); + + while (fgets(buf, 8192, f)) { + buf[strlen(buf)-1] = 0; + if (buf[0] == '#') break; + if ((colon = strchr(buf, ':'))) { + *colon++ = 0; + fprintf(out, "#define APPLY_%-30s\t\"%s\"\n", buf, colon); + } else { + fprintf(out, "#define APPLY_%-30s\t", buf); + p = buf; + while (*p) { + *p = tolower(*p); + p++; + } + fprintf(out, "\"%s\"\n", buf); + } + } + while (fgets(buf, 8192, f)) { + buf[strlen(buf)-1] = 0; + if ((colon = strchr(buf, ':'))) { + *colon++ = 0; + fprintf(table, "\t\"%s\",\n", colon); + fprintf(out, "#define APPLY_%-30s\t%i\n", buf, apply_number++); + } else { + fprintf(out, "#define APPLY_%-30s\t%i\n", buf, apply_number++); + p = buf; + while (*p) { + *p = tolower(*p); + p++; + } + fprintf(table, "\t\"%s\",\n", buf); + } + } + + fprintf(table, "};\n"); + fprintf(out, "\n#define NUM_MASTER_APPLIES\t%i\n\n#endif\n", apply_number); + + fclose(out); + fclose(table); + fclose(f); +} + +static void handle_malloc() { +#ifdef PEDANTIC + int unlink(char *); + int link(char *, char *); +#endif + + const char *the_malloc = 0, *the_wrapper = 0; + + if (lookup_define("SYSMALLOC")) + the_malloc = "sysmalloc.c"; + if (lookup_define("SMALLOC")) + the_malloc = "smalloc.c"; + if (lookup_define("BSDMALLOC")) + the_malloc = "bsdmalloc.c"; + if (lookup_define("MMALLOC")) + the_malloc = "mmalloc.c"; + if(lookup_define("MALLOC64")) + the_malloc = "64bitmalloc.c"; + if(lookup_define("MALLOC32")) + the_malloc = "32bitmalloc.c"; + if (lookup_define("GNUMALLOC")) + the_malloc = "gnumalloc.c"; + + if (lookup_define("WRAPPEDMALLOC")) + the_wrapper = "wrappedmalloc.c"; + if (lookup_define("DEBUGMALLOC")) + the_wrapper = "debugmalloc.c"; + + if (!the_malloc && !the_wrapper) { + fprintf(stderr, "Memory package and/or malloc wrapper incorrectly specified in options.h\n"); + exit(-1); + } + + if (unlink("malloc.c") == -1 && errno != ENOENT) + perror("unlink malloc.c"); + if (unlink("mallocwrapper.c") == -1 && errno != ENOENT) + perror("unlink mallocwrapper.c"); + + if (the_wrapper) { + printf("Using memory allocation package: %s\n\t\tWrapped with: %s\n", + the_malloc, the_wrapper); + if (link(the_wrapper, "mallocwrapper.c") == -1) + perror("link mallocwrapper.c"); + } else { + printf("Using memory allocation package: %s\n", the_malloc); + } + if (link(the_malloc, "malloc.c") == -1) + perror("link malloc.c"); +} + +static int check_include2 (const char * tag, const char * file, + const char * before, const char * after) { + char buf[1024]; + FILE *ct; + + printf("Checking for include file <%s> ... ", file); + ct = fopen("comptest.c", "w"); + fprintf(ct, "#include \"configure.h\"\n#include \"std_incl.h\"\n%s\n#include <%s>\n%s\n", + before, file, after); + fclose(ct); + + sprintf(buf, "%s %s -c comptest.c " TO_DEV_NULL, COMPILER, CFLAGS); + if (!compile(buf)) { + fprintf(yyout, "#define %s\n", tag); + /* Make sure the define exists for later checks */ + fflush(yyout); + printf("exists\n"); + return 1; + } + printf("does not exist or is unusable\n"); + return 0; +} + +static int check_include (const char * tag, const char * file) { + char buf[1024]; + FILE *ct; + + printf("Checking for include file <%s> ... ", file); + ct = fopen("comptest.c", "w"); + fprintf(ct, "#include \"configure.h\"\n#include \"std_incl.h\"\n#include \"file_incl.h\"\n#include <%s>\n", file); + fclose(ct); + + sprintf(buf, "%s %s -c comptest.c " TO_DEV_NULL, COMPILER, CFLAGS); + if (!compile(buf)) { + fprintf(yyout, "#define %s\n", tag); + /* Make sure the define exists for later checks */ + fflush(yyout); + printf("exists\n"); + return 1; + } + printf("does not exist\n"); + return 0; +} + +static int check_library (const char * lib) { + char buf[1024]; + FILE *ct; + + printf("Checking for library %s ... ", lib); + ct = fopen("comptest.c", "w"); + fprintf(ct, "int main() { return 0; }\n"); + fclose(ct); + + sprintf(buf, "%s %s comptest.c %s" TO_DEV_NULL, COMPILER, CFLAGS, lib); + if (!compile(buf)) { + fprintf(yyout, " %s", lib); + printf("exists\n"); + return 1; + } + printf("does not exist\n"); + return 0; +} + +#if 0 /* not used any more */ +static int check_ret_type (char * tag, char * pre, + char * type, char * func) { + char buf[1024]; + FILE *ct; + + printf("Checking return type of %s() ...", func); + ct = fopen("comptest.c", "w"); + fprintf(ct, "%s\n\n%s%s();\n", pre, type, func); + fclose(ct); + + sprintf(buf, "%s %s -c comptest.c >/dev/null 2>&1", COMPILER, CFLAGS); + if (!system(buf)) { + fprintf(yyout, "#define %s\n", tag); + printf("returns %s\n", type); + return 1; + } + printf("does not return %s\n", type); + return 0; +} +#endif + +/* This should check a.out existence, not exit value */ +static int check_prog (const char * tag, const char * pre, const char * code, int andrun) { + char buf[1024]; + FILE *ct; + + ct = fopen("comptest.c", "w"); + fprintf(ct, "#include \"configure.h\"\n#include \"std_incl.h\"\n%s\n\nint main() {%s}\n", (pre ? pre : ""), code); + fclose(ct); + + sprintf(buf, "%s %s comptest.c -o comptest" TO_DEV_NULL, COMPILER, CFLAGS); + if (!compile(buf) && (!andrun || !system("./comptest"))) { + if (tag) { + fprintf(yyout, "#define %s\n", tag); + fflush(yyout); + } + return 1; + } + + return 0; +} + +static int check_code (const char * pre, const char * code) { + char buf[1024]; + FILE *ct; + int rc; + + ct = fopen("comptest.c", "w"); + fprintf(ct, "#include \"configure.h\"\n#include \"std_incl.h\"\n%s\n\nint main() {%s}\n", (pre ? pre : ""), code); + fclose(ct); + + sprintf(buf, "%s %s comptest.c -o comptest" TO_DEV_NULL, COMPILER, CFLAGS); + if (compile(buf) || (rc = system("./comptest")) == 127 || rc == -1) { + return -1; + } + return rc; +} + +static void check_linux_libc() { + char buf[1024]; + FILE *ct; + + ct = fopen("comptest.c", "w"); + fprintf(ct, "int main() { }\n"); + fclose(ct); + + sprintf(buf, "%s -g comptest.c -o comptest >/dev/null 2>&1", COMPILER); + if (system(buf)) { + fprintf(stderr, " libg.a/so installed wrong, trying workaround ...\n"); + sprintf(buf, "%s -g comptest.c -lc -o comptest >/dev/null 2>&1", COMPILER); + if (system(buf)) { + fprintf(stderr, "*** FAILED.\n"); + exit(-1); + } + fprintf(yyout, " -lc"); + } +} + +static const char *memmove_prog = "\ +char buf[80];\n\ +strcpy(buf,\"0123456789ABCDEF\");\n\ +memmove(&buf[1],&buf[4],13);\n\ +if(strcmp(buf,\"0456789ABCDEF\")) exit(-1);\n\ +memmove(&buf[8],&buf[6],9);\n\ +if(strcmp(buf,\"0456789A9ABCDEF\")) exit(-1);\n\ +return 0;\n"; + +static int check_memmove (const char * tag, const char * str) { + return check_prog(tag, str, memmove_prog, 1); +} + +static void find_memmove() { + printf("Checking for memmove() ..."); + if (check_memmove(0, "")) { + printf(" exists\n"); + return; + } + if (check_memmove("USE_BCOPY", "#define memmove(a,b,c) bcopy(b,a,c)")) { + printf(" simulating via bcopy()\n"); + return; + } + printf(" missing; using MudOS's version\n"); + fprintf(yyout, "#define MEMMOVE_MISSING\n"); +} + +static void verbose_check_prog (const char * msg, const char * def, const char * pre, + const char * prog, int andrun) { + printf("%s ...", msg); + if (check_prog(def, pre, prog, andrun)) + printf(" exists\n"); + else printf(" does not exist\n"); +} + +static int check_configure_version() { + char buf[1024]; + FILE *ct; + + ct = fopen("comptest.c", "w"); + fprintf(ct, "#include \"configure.h\"\n\n#if CONFIGURE_VERSION < %i\nthrash and die\n#endif\n\nint main() { }\n", CONFIGURE_VERSION); + fclose(ct); + + sprintf(buf, "%s %s comptest.c -o comptest " TO_DEV_NULL, COMPILER, CFLAGS); + return !compile(buf); +} + +static void handle_configure() { + if (check_configure_version()) return; + + open_output_file("configure.h"); + +#ifndef WIN32 + check_include("INCL_STDLIB_H", "stdlib.h"); + check_include("INCL_UNISTD_H", "unistd.h"); + if (check_include("INCL_TIME_H", "time.h")) { + if (!check_prog(0, "#include ", "tzset();", 0)) { + if (check_prog(0, 0, "void tzset(); tzset();", 0)) + fprintf(yyout, "#define PROTO_TZSET\n#define USE_TZSET\n"); + } + else + fprintf(yyout, "#define USE_TZSET\n"); + } else { + if (check_prog(0, 0, "void tzset(); tzset();", 0)) + fprintf(yyout, "#define PROTO_TZSET\n#define USE_TZSET\n"); + } + check_include("INCL_SYS_TIMES_H", "sys/times.h"); + check_include("INCL_FCNTL_H", "fcntl.h"); + check_include("INCL_SYS_TIME_H", "sys/time.h"); + check_include("INCL_DOS_H", "dos.h"); + check_include("INCL_USCLKC_H", "usclkc.h"); + check_include("INCL_LIMITS_H", "limits.h"); + check_include("INCL_LOCALE_H", "locale.h"); + if (!check_prog(0, 0, "int x = USHRT_MAX;", 0)) { + if (!check_prog(0, 0, "int x = MAXSHORT;", 0)) + check_include("INCL_VALUES_H", "values.h"); + fprintf(yyout, "#define USHRT_MAX (MAXSHORT)\n"); + } + + check_include("INCL_NETINET_IN_H", "netinet/in.h"); + check_include("INCL_ARPA_INET_H", "arpa/inet.h"); + + check_include("INCL_SYS_TYPES_H", "sys/types.h"); + check_include("INCL_SYS_IOCTL_H", "sys/ioctl.h"); + check_include("INCL_SYS_SOCKET_H", "sys/socket.h"); + check_include("INCL_NETDB_H", "netdb.h"); + /* TELOPT_NAWS is missing from on some systems */ + check_include2("INCL_ARPA_TELNET_H", "arpa/telnet.h", "", "int i=TELOPT_NAWS;"); + check_include("INCL_SYS_SEMA_H", "sys/sema.h"); + check_include("INCL_SYS_SOCKETVAR_H", "sys/socketvar.h"); + check_include("INCL_SOCKET_H", "socket.h"); + check_include("INCL_RESOLVE_H", "resolve.h"); + + check_include("INCL_SYS_STAT_H", "sys/stat.h"); + + /* sys/dir.h is BSD, dirent is sys V. Try to do it the BSD way first. */ + /* If that fails, fall back to sys V */ + if (check_prog("BSD_READDIR", "#include ", "struct direct *d; d->d_namlen;", 0)) { + check_include("INCL_SYS_DIR_H", "sys/dir.h"); + } else { + /* could be either of these */ + check_include("INCL_DIRENT_H", "dirent.h"); + check_include("INCL_SYS_DIRENT_H", "sys/dirent.h"); + fprintf(yyout, "#define USE_STRUCT_DIRENT\n"); + } + + check_include("INCL_SYS_FILIO_H", "sys/filio.h"); + check_include("INCL_SYS_SOCKIO_H", "sys/sockio.h"); + check_include("INCL_SYS_MKDEV_H", "sys/mkdev.h"); + check_include("INCL_SYS_RESOURCE_H", "sys/resource.h"); + check_include("INCL_SYS_RUSAGE_H", "sys/rusage.h"); + check_include("INCL_SYS_WAIT_H", "sys/wait.h"); + check_include("INCL_SYS_CRYPT_H", "sys/crypt.h"); + check_include("INCL_CRYPT_H", "crypt.h"); + check_include("INCL_MALLOC_H", "my_malloc.h"); + + /* for NeXT */ + if (!check_include("INCL_MACH_MACH_H", "mach/mach.h")) + check_include("INCL_MACH_H", "mach.h"); + + /* figure out what we need to do to get major()/minor() */ + check_include("INCL_SYS_SYSMACROS_H", "sys/sysmacros.h"); + +#ifdef DEBUG + /* includes just to shut up gcc's warnings on some systems */ + check_include("INCL_BSTRING_H", "bstring.h"); +#endif + + /* Runtime loading support */ + if (check_include("INCL_DLFCN_H", "dlfcn.h")) { + if (!check_prog(0, "#include ", "int x = RTLD_LAZY;", 0)) + fprintf(yyout, "#define RTLD_LAZY 1\n"); + } else { + if (!check_prog(0, 0, "int x = RTLD_LAZY;", 0)) + fprintf(yyout, "#define RTLD_LAZY 1\n"); + } + + /* SunOS is missing definition for INADDR_NONE */ + printf("Checking for missing INADDR_NONE ... "); + if (!check_prog(0, "#include ", "int x = INADDR_NONE;", 0)) { + printf("missing\n"); + fprintf(yyout, "#define INADDR_NONE (unsigned int)0xffffffff\n"); + } else printf("ok\n"); + + printf("Checking for random number generator ..."); + if (check_prog("DRAND48", 0, "srand48(0);", 0)) { + printf(" using drand48()\n"); + } else + if (check_prog("RAND", 0, "srand(0);", 0)) { + printf(" using rand()\n"); + } else + if (check_prog("RANDOM", 0, "srandom(0);", 0)) { + printf("using random()\n"); + } else { + printf("WARNING: did not find a random number generator\n"); + exit(-1); + } + + if (check_prog("USE_BSD_SIGNALS", 0, "SIGCHLD; wait3(0, 0, 0);", 0)) { + printf("Using BSD signals.\n"); + } else { + printf("Using System V signals.\n"); + } + + printf("Checking if signal() returns SIG_ERR on error ..."); + if (check_prog("SIGNAL_ERROR SIG_ERR", 0, "if (signal(0, 0) == SIG_ERR) ;", 0)) { + printf(" yes\n"); + } else { + fprintf(yyout, "#define SIGNAL_ERROR BADSIG\n"); + printf(" no\n"); + } + + printf("Not Checking for inline ...(usage in driver code all broken anyway)"); + //if (!check_prog("INLINE inline", "inline void foo() { }", "foo();", 0)) { + //printf(" __inline ..."); + //if (!check_prog("INLINE __inline", "__inline void foo() {}", "foo();", 0)) { + fprintf(yyout, "#define INLINE\n"); + //} + //} + printf(" const ...\n"); + if (!check_prog("CONST const", "int foo(const int *, const int *);", "", 0)) + fprintf(yyout, "#define CONST\n"); + + verbose_check_prog("Checking for strerror()", "HAS_STRERROR", + "", "strerror(12);", 0); + verbose_check_prog("Checking for POSIX getcwd()", "HAS_GETCWD", + "", "getcwd(\"\", 1000);", 0); + verbose_check_prog("Checking for getrusage()", "RUSAGE", + "", "getrusage(0, 0);", 0); + verbose_check_prog("Checking for times()", "TIMES", + "", "times(0);", 0); + verbose_check_prog("Checking for gettimeofday()", "HAS_GETTIMEOFDAY", + "", "gettimeofday(0, 0);", 0); + verbose_check_prog("Checking for fchmod()", "HAS_FCHMOD", + "", "fchmod(0, 0);", 0); + + printf("Checking for big or little endian ... "); + if (!check_code("char num[] = { 0x11, 0x22, 0x33, 0x44 }; int *foo = (int *)num;", + "return (*foo == 0x44332211);")) { + printf("big\n"); + fprintf(yyout, "#define BIGENDIAN 1\n"); + fflush(yyout); + } else printf("little\n"); + + find_memmove(); +#endif + + fprintf(yyout, "#define SIZEOF_INT %i\n", sizeof(int)); + fprintf(yyout, "#define SIZEOF_PTR %i\n", sizeof(char *)); + fprintf(yyout, "#define SIZEOF_SHORT %i\n", sizeof(short)); + fprintf(yyout, "#define SIZEOF_FLOAT %i\n", sizeof(float)); + fprintf(yyout, "#define SIZEOF_LONG %i\n", sizeof(long)); + + if (sizeof(unsigned long) == 4) + fprintf(yyout, "#define UINT32 unsigned long\n"); + else if (sizeof(unsigned int) == 4) + fprintf(yyout, "#define UINT32 unsigned int\n"); + else { + printf("WARNING: could not find a 32 bit integral type.\n"); + exit(-1); + } + + /* PACKAGE_DB stuff */ + if (lookup_define("PACKAGE_DB")) { + /* -I would be nicer for added include paths, but we don't have an easy way to + * set -I paths right now + */ + if (lookup_define("USE_MSQL")) { + if (!(check_include("INCL_LOCAL_MSQL_H", "/usr/local/include/msql.h") + || check_include("INCL_LOCAL_MSQL_MSQL_H", "/usr/local/msql/include/msql.h") + || check_include("INCL_LOCAL_MINERVA_MSQL_H", "/usr/local/Minerva/include/msql.h") + || check_include("INCL_LIB_HUGHES_MSQL_H", "/usr/lib/Hughes/include/msql.h"))) { + fprintf(stderr, "Cannot find msql.h, compilation is going to fail miserably.\n"); + } + } + if (lookup_define("USE_MYSQL")) { + if (!(check_include("INCL_LOCAL_MYSQL_H", "/usr/local/include/mysql.h") + || check_include("INCL_LOCAL_INCLUDE_MYSQL_MYSQL_H", "/usr/local/include/mysql/mysql.h") + || check_include("INCL_LOCAL_MYSQL_MYSQL_H", "/usr/local/mysql/include/mysql.h") + || check_include("INCL_MYSQL_MYSQL_H", "/usr/include/mysql/mysql.h") + || check_include("INCL_MYSQL_INCLUDE_MYSQL_H", "/usr/mysql/include/mysql/mysql.h"))) { + fprintf(stderr, "Cannot find mysql.h, compilation is going to fail miserably.\n"); + } + } + if (lookup_define("USE_POSTGRES")) { + if (!(check_include("USE_POSTGRES", "/usr/include/postgresql/libpq-fe.h"))) { + fprintf(stderr, + "Cannot find libpq-fe.h, compilation is going to fail miserably.\n"); + } + } + } + + fprintf(yyout, "#define CONFIGURE_VERSION %i\n\n", CONFIGURE_VERSION); + + close_output_file(); + +#ifdef WIN32 + system("echo Windows detected. Applying libs."); + if (lookup_define("HAVE_ZLIB")){ + system("echo -lwsock32 -lws2_32 -lz> system_libs"); + } + else system("echo -lwsock32 -lws2_32 > system_libs"); + system("copy windows\\configure.h tmp.config.h"); + system("type configure.h >> tmp.config.h"); + system("del configure.h"); + system("rename tmp.config.h configure.h"); +#else + + open_output_file("system_libs"); + check_library("-lresolv"); + check_library("-lbsd"); + check_library("-lBSD"); + check_library("-ly"); + + /* don't add -lcrypt if crypt() is in libc.a */ + if (!check_prog(0, "#include \"lint.h\"", + "char *x = crypt(\"foo\", \"bar\");", 0)) + check_library("-lcrypt"); + /* don't add -lmalloc if malloc() works */ + if (!check_prog(0, "", "char *x = malloc(100);", 0)) + check_library("-lmalloc"); + + /* we don't currently use it anywhere + if (!check_prog(0, "", "void *x = dlopen(0, 0);", 0)) + check_library("-ldl"); + */ + check_library("-lsocket"); + check_library("-linet"); + check_library("-lnsl"); + check_library("-lnsl_s"); + check_library("-lseq"); + check_library("-lm"); + + if (lookup_define("CYGWIN")) + check_library("-liconv"); + + + if (lookup_define("MINGW")){ + check_library("-lwsock32"); + check_library("-lws2_32"); + } + + if (lookup_define("HAVE_ZLIB")) + check_library("-lz"); + + if (lookup_define("PACKAGE_ASYNC")) + check_library("-lpthread"); + if (lookup_define("PACKAGE_HASH")) + check_library("-lssl"); + if (lookup_define("PACKAGE_PCRE")) + check_library("-lpcre"); + fprintf(stderr, "Checking for flaky Linux systems ...\n"); + check_linux_libc(); + + /* PACKAGE_DB stuff */ + if (lookup_define("PACKAGE_DB") && lookup_define("USE_MSQL")) { + if (!(check_library("-lmsql") || + check_library("-L/usr/local/lib -lmsql") || + check_library("-L/usr/local/msql/lib -lmsql") || + check_library("-L/usr/local/Minerva/lib -lmsql") || + check_library("-L/usr/lib/Hughes/lib -lmsql"))) { + fprintf(stderr, "Cannot find libmsql.a, compilation is going to fail miserably\n"); + } + } + if (lookup_define("PACKAGE_DB") && lookup_define("USE_MYSQL")) { + if (!(check_library("-lmysqlclient") || + check_library("-L/usr/local/lib -lmysqlclient") || + check_library("-L/usr/local/lib/mysql -lmysqlclient") || + check_library("-L/usr/local/mysql/lib -lmysqlclient") || + check_library("-L/usr/lib64/mysql -lmysqlclient") || + check_library("-L/usr/lib/mysql -lmysqlclient") || + check_library("-L/usr/mysql/lib/64/mysql -lmysqlclient"))) { + fprintf(stderr, "Cannot find libmysqlclient.a, compilation is going to fail miserably\n"); + } + } + if (lookup_define("PACKAGE_DB") && lookup_define("USE_POSTGRES")) { + if (!(check_library("-lpq"))) { + fprintf(stderr, "Cannot find libpq.a, compilation is going to fail miserably\n"); + } + } + fprintf(yyout, "\n\n"); + close_output_file(); +#endif +} + +int main (int argc, char ** argv) { + int idx = 1; + + while (idx < argc) { + if (argv[idx][0] != '-') { + fprintf(stderr, SYNTAX); + exit(-1); + } + if (strcmp(argv[idx], "-configure")==0) { + handle_options(0); + handle_configure(); + } else + if (strcmp(argv[idx], "-process")==0) { + handle_process(argv[++idx]); + } else + if (strcmp(argv[idx], "-options")==0) { + handle_options(1); + } else + if (strcmp(argv[idx], "-malloc")==0) { + handle_malloc(); + } else + if (strcmp(argv[idx], "-build_applies")==0) { + handle_applies(); + } else + if (strcmp(argv[idx], "-build_func_spec")==0) { + handle_build_func_spec(argv[++idx]); + } else + if (strcmp(argv[idx], "-build_efuns")==0) { + handle_build_efuns(); + } else { + fprintf(stderr, "Unrecognized flag %s\n", argv[idx]); + exit(-1); + } + idx++; + } + printf("\n"); + return 0; +} diff --git a/fluffos-2.23-ds03/edit_source.h b/fluffos-2.23-ds03/edit_source.h new file mode 100644 index 0000000..6867ed8 --- /dev/null +++ b/fluffos-2.23-ds03/edit_source.h @@ -0,0 +1,6 @@ +#ifndef EDIT_SOURCE_H +#define EDIT_SOURCE_H + +extern FILE *yyin; + +#endif diff --git a/fluffos-2.23-ds03/efuns_incl.h b/fluffos-2.23-ds03/efuns_incl.h new file mode 100644 index 0000000..0164a04 --- /dev/null +++ b/fluffos-2.23-ds03/efuns_incl.h @@ -0,0 +1,6 @@ +#ifndef EFUNS_INCL_H +#define EFUNS_INCL_H + +#include "efun_protos.h" + +#endif diff --git a/fluffos-2.23-ds03/efuns_main.c b/fluffos-2.23-ds03/efuns_main.c new file mode 100644 index 0000000..3d081fa --- /dev/null +++ b/fluffos-2.23-ds03/efuns_main.c @@ -0,0 +1,3962 @@ +/* + efuns_main.c: this file contains the efunctions called from + inside eval_instruction() in interpret.c. Note: if you are adding + local efunctions that are specific to your driver, you would be better + off adding them to a separate source file. Doing so will make it much + easier for you to upgrade (won't have to patch this file). Be sure + to #include "lpc_incl.h" in that separate source file. +*/ + +#include "std.h" +#include "efuns_main.h" +#include "file_incl.h" +#include "file.h" +#include "comm.h" +#include "parse.h" +#include "sprintf.h" +#include "backend.h" +#include "port.h" +#include "otable.h" +#include "crc32.h" +#include "reclaim.h" +#include "dumpstat.h" +#include "call_out.h" +#include "ed.h" +#include "md.h" +#include "master.h" +#include "efun_protos.h" +#include "add_action.h" +#include "eval.h" +#include "interpret.h" + +int call_origin = 0; + +int data_size (object_t * ob); +void reload_object (object_t * obj); + +#ifdef F_ALL_INVENTORY +void +f_all_inventory (void) +{ + array_t *vec = all_inventory(sp->u.ob, 0); + free_object(&sp->u.ob, "f_all_inventory"); + sp->type = T_ARRAY; + sp->u.arr = vec; +} +#endif + +#ifdef F_ALLOCATE +void +f_allocate (void) +{ + if (st_num_arg == 2) { + (sp-1)->u.arr = allocate_array2((sp-1)->u.number, sp); + pop_stack(); + } else { + sp->u.arr = allocate_array(sp->u.number); + } + sp->type = T_ARRAY; +} +#endif + +#ifdef F_ALLOCATE_BUFFER +void +f_allocate_buffer (void) +{ + buffer_t *buf; + + buf = allocate_buffer(sp->u.number); + if (buf) { + pop_stack(); + push_refed_buffer(buf); + } else { + assign_svalue(sp, &const0); + } +} +#endif + +#ifdef F_ALLOCATE_MAPPING +void +f_allocate_mapping (void) +{ + array_t *arr; + + if (st_num_arg == 2) { + if ((sp-1)->type != T_ARRAY) + error("Bad argument 1 to allocate_mapping()\n"); + if (sp->type == T_ARRAY) { + arr = (sp-1)->u.arr; + if (sp->u.arr->size != arr->size) + error("Arrays passed to allocate_mapping() must be the same size\n"); + (sp-1)->u.map = mkmapping(arr, sp->u.arr); + } else { + arr = (sp-1)->u.arr; + (sp-1)->u.map = allocate_mapping2(arr, sp); + } + pop_stack(); + free_array(arr); + } else if (sp->type == T_NUMBER) { + sp->u.map = allocate_mapping(sp->u.number); + } else { + error("Bad argument 1 to allocate_mapping()\n"); + } + sp->type = T_MAPPING; +} +#endif + +#ifdef F_BIND +void +f_bind (void) +{ + object_t *ob = sp->u.ob; + funptr_t *old_fp = (sp-1)->u.fp; + funptr_t *new_fp; + svalue_t *res; + + if (ob == old_fp->hdr.owner) { + /* no change */ + free_object(&ob, "bind nop"); + sp--; + return; + } + + if (old_fp->hdr.type == (FP_LOCAL | FP_NOT_BINDABLE)) + error("Illegal to rebind a pointer to a local function.\n"); + if (old_fp->hdr.type & FP_NOT_BINDABLE) + error("Illegal to rebind a functional that references globals or local functions.\n"); + + /* the object doing the binding */ + push_object(current_object); + + /* the old owner */ + push_object(old_fp->hdr.owner); + + /* the new owner */ + push_object(ob); + + res = apply_master_ob(APPLY_VALID_BIND, 3); + if (!MASTER_APPROVED(res)) + error("Master object denied permission to bind() function pointer.\n"); + + new_fp = ALLOCATE(funptr_t, TAG_FUNP, "f_bind"); + *new_fp = *old_fp; + new_fp->hdr.ref = 1; + new_fp->hdr.owner = ob; /* one ref from being on stack */ + if (new_fp->hdr.args) + new_fp->hdr.args->ref++; + if ((old_fp->hdr.type & 0x0f) == FP_FUNCTIONAL) { + new_fp->f.functional.prog->func_ref++; + debug(d_flag, ("add func ref /%s: now %i\n", + new_fp->f.functional.prog->filename, + new_fp->f.functional.prog->func_ref)); + } + + free_funp(old_fp); + sp--; + sp->u.fp = new_fp; +} +#endif + +#ifdef F_CACHE_STATS +static void print_cache_stats (outbuffer_t * ob) +{ + outbuf_add(ob, "Function cache information\n"); + outbuf_add(ob, "-------------------------------\n"); + outbuf_addv(ob, "%% cache hits: %10.2f\n", + 100 * ((double) apply_low_cache_hits / apply_low_call_others)); + outbuf_addv(ob, "call_others: %10lu\n", apply_low_call_others); + outbuf_addv(ob, "cache hits: %10lu\n", apply_low_cache_hits); + outbuf_addv(ob, "cache size: %10lu\n", APPLY_CACHE_SIZE); + outbuf_addv(ob, "slots used: %10lu\n", apply_low_slots_used); + outbuf_addv(ob, "%% slots used: %10.2f\n", + 100 * ((double) apply_low_slots_used / APPLY_CACHE_SIZE)); + outbuf_addv(ob, "collisions: %10lu\n", apply_low_collisions); + outbuf_addv(ob, "%% collisions: %10.2f\n", + 100 * ((double) apply_low_collisions / apply_low_call_others)); +} + +void f_cache_stats (void) +{ + outbuffer_t ob; + + outbuf_zero(&ob); + print_cache_stats(&ob); + outbuf_push(&ob); +} +#endif + +#ifdef F__CALL_OTHER + /* enhanced call_other written 930314 by Luke Mewburn */ +void +f__call_other (void) +{ + svalue_t *arg; + const char *funcname; + int i; + int num_arg = st_num_arg; + object_t *ob; + + if (current_object->flags & O_DESTRUCTED) { /* No external calls allowed */ + pop_n_elems(num_arg); + push_undefined(); + return; + } + arg = sp - num_arg + 1; + if (arg[1].type == T_STRING) + funcname = arg[1].u.string; + else { /* must be T_ARRAY then */ + array_t *v = arg[1].u.arr; + svalue_t *sv; + + check_for_destr(v); + if (((i = v->size) < 1) || !((sv = v->item)->type == T_STRING)) + error("call_other: 1st elem of array for arg 2 must be a string\n"); + funcname = sv->u.string; + num_arg = 2 + merge_arg_lists(num_arg - 2, v, 1); + } + + if (arg[0].type == T_OBJECT) + ob = arg[0].u.ob; + else if (arg[0].type == T_ARRAY) { + array_t *ret; + + ret = call_all_other(arg[0].u.arr, funcname, num_arg - 2); + pop_stack(); + free_array(arg->u.arr); + sp->u.arr = ret; + return; + } else { + ob = find_object(arg[0].u.string); + if (!ob || !object_visible(ob)) + error("call_other() couldn't find object\n"); + } + /* Send the remaining arguments to the function. */ +#ifdef TRACE + if (TRACEP(TRACE_CALL_OTHER)) { + do_trace("Call other ", funcname, "\n"); + } +#endif + call_origin = ORIGIN_CALL_OTHER; + if (apply_low(funcname, ob, num_arg - 2) == 0) { /* Function not found */ + pop_2_elems(); + push_undefined(); + return; + } + /* + * The result of the function call is on the stack. So is the function + * name and object that was called, though. These have to be removed. + */ + free_svalue(--sp, "f_call_other:1"); + free_svalue(--sp, "f_call_other:2"); + *sp = *(sp+2); + return; +} +#endif + +#ifdef F_CALL_OUT +void +f_call_out (void) +{ + svalue_t *arg = sp - st_num_arg + 1; + int num = st_num_arg - 2; +#ifdef CALLOUT_HANDLES + int ret; + + if (!(current_object->flags & O_DESTRUCTED)) { + ret = new_call_out(current_object, arg, arg[1].u.number, num, arg + 2); + /* args have been transfered; don't free them; + also don't need to free the int */ + sp -= num + 1; + } else { + ret = 0; + pop_n_elems(num); + sp--; + } + /* the function */ + free_svalue(sp, "call_out"); + put_number(ret); +#else + if (!(current_object->flags & O_DESTRUCTED)) { + new_call_out(current_object, arg, arg[1].u.number, num, arg + 2); + sp -= num + 1; + } else { + pop_n_elems(num); + sp--; + } + free_svalue(sp--, "call_out"); +#endif +} +#endif + +#ifdef F_CALL_OUT_INFO +void +f_call_out_info (void) +{ + push_refed_array(get_all_call_outs()); +} +#endif + +#if defined(F_CALL_STACK) || defined(F_ORIGIN) +static const char *origin_name (int orig) { + /* FIXME: this should use ffs() if available (BSD) */ + int i = 0; + static const char *origins[] = { + "driver", + "local", + "call_other", + "simul", + "internal", + "efun", + "function pointer", + "functional" + }; + while (orig >>= 1) i++; + return origins[i]; +} +#endif + +#ifdef F_CALL_STACK +void +f_call_stack (void) +{ + int i, n = csp - &control_stack[0] + 1; + array_t *ret; + + if (sp->u.number < 0 || sp->u.number > 3) + error("First argument of call_stack() must be 0, 1, 2, or 3.\n"); + + ret = allocate_empty_array(n); + + switch (sp->u.number) { + case 0: + ret->item[0].type = T_STRING; + ret->item[0].subtype = STRING_MALLOC; + ret->item[0].u.string = add_slash(current_prog->filename); + for (i = 1; i < n; i++) { + ret->item[i].type = T_STRING; + ret->item[i].subtype = STRING_MALLOC; + ret->item[i].u.string = add_slash((csp - i + 1)->prog->filename); + } + break; + case 1: + ret->item[0].type = T_OBJECT; + ret->item[0].u.ob = current_object; + add_ref(current_object, "f_call_stack: curr"); + for (i = 1; i < n; i++) { + ret->item[i].type = T_OBJECT; + ret->item[i].u.ob = (csp - i + 1)->ob; + add_ref((csp - i + 1)->ob, "f_call_stack"); + } + break; + case 2: + for (i = 0; i < n; i++) { + ret->item[i].type = T_STRING; + if (((csp - i)->framekind & FRAME_MASK) == FRAME_FUNCTION) { + const program_t *prog = (i ? (csp-i+1)->prog : current_prog); + int index = (csp-i)->fr.table_index; + function_t *cfp = &prog->function_table[index]; + + ret->item[i].subtype = STRING_SHARED; + ret->item[i].u.string = cfp->funcname; + ref_string(cfp->funcname); + } else { + ret->item[i].subtype = STRING_CONSTANT; + ret->item[i].u.string = (((csp - i)->framekind & FRAME_MASK) == FRAME_CATCH) ? "CATCH" : ""; + } + } + break; + case 3: + ret->item[0].type = T_STRING; + ret->item[0].subtype = STRING_CONSTANT; + ret->item[0].u.string = origin_name(caller_type); + + for (i = 1; i < n; i++) { + ret->item[i].type = T_STRING; + ret->item[i].subtype = STRING_CONSTANT; + ret->item[i].u.string = origin_name((csp-i+1)->caller_type); + } + break; + } + put_array(ret); +} +#endif + +#ifdef F_CAPITALIZE +void +f_capitalize (void) +{ + if (uislower(sp->u.string[0])) { + unlink_string_svalue(sp); + //unlinked, so this is ok + ((char *)(sp->u.string))[0] = toupper((unsigned char)sp->u.string[0]); + } +} +#endif + +#ifdef F_CHILDREN +void +f_children (void) +{ + array_t *vec; + + vec = children(sp->u.string); + free_string_svalue(sp); + put_array(vec); +} +#endif + +#ifdef F_CLASSP +void +f_classp (void) +{ + if (sp->type == T_CLASS) { + free_class(sp->u.arr); + *sp = const1; + } else { + free_svalue(sp, "f_classp"); + *sp = const0; + } +} +#endif + +#ifdef F_CLEAR_BIT +void +f_clear_bit (void) +{ + char *str; + int len, ind, bit; + + if (sp->u.number > MAX_BITS) + error("clear_bit() bit requested : %d > maximum bits: %d\n", sp->u.number, MAX_BITS); + bit = (sp--)->u.number; + if (bit < 0) + error("Bad argument 2 (negative) to clear_bit().\n"); + ind = bit / 6; + bit %= 6; + len = SVALUE_STRLEN(sp); + if (ind >= len) + return; /* return first arg unmodified */ + unlink_string_svalue(sp); + str = (char *)sp->u.string; + + if (str[ind] > 0x3f + ' ' || str[ind] < ' ') + error("Illegal bit pattern in clear_bit character %d\n", ind); + str[ind] = ((str[ind] - ' ') & ~(1 << bit)) + ' '; +} +#endif + +#ifdef F_CLONEP +void +f_clonep (void) +{ + if ((sp->type == T_OBJECT) && (sp->u.ob->flags & O_CLONE)) { + free_object(&sp->u.ob, "f_clonep"); + *sp = const1; + } else { + free_svalue(sp, "f_clonep"); + *sp = const0; + } +} +#endif + +#ifdef F__NEW +void +f__new (void) +{ + svalue_t *arg = sp - st_num_arg + 1; + object_t *ob; + + ob = clone_object(arg->u.string, st_num_arg - 1); + + free_string_svalue(sp); + if (ob) { + put_unrefed_undested_object(ob, "f_clone_object"); + } else *sp = const0; +} +#endif + +#ifdef F_CP +void +f_cp (void) +{ + int i; + + i = copy_file(sp[-1].u.string, sp[0].u.string); + free_string_svalue(sp--); + free_string_svalue(sp); + put_number(i); +} +#endif + +#ifdef F_CRC32 +void +f_crc32 (void) +{ + int len; + unsigned char *buf; + UINT32 crc; + + if (sp->type == T_STRING) { + len = SVALUE_STRLEN(sp); + buf = (unsigned char *) sp->u.string; +#ifndef NO_BUFFER_TYPE + } else if (sp->type == T_BUFFER) { + len = sp->u.buf->size; + buf = sp->u.buf->item; +#endif + } else { +#ifdef NO_BUFFER_TYPE + bad_argument(sp, T_STRING, 1, F_CRC32); +#else + bad_argument(sp, T_STRING | T_BUFFER, 1, F_CRC32); +#endif + } + crc = compute_crc32(buf, len); + free_svalue(sp, "f_crc32"); + put_number(crc); +} +#endif + +#ifdef F_CTIME +void +f_ctime (void) +{ + const char *cp, *nl; + char *p; + int l; + if(st_num_arg) + cp = time_string((time_t)sp->u.number); + else { + push_number(0); + cp = time_string((time_t)current_time); + } + if ((nl = strchr(cp, '\n'))) + l = nl - cp; + else + l = strlen(cp); + + p = new_string(l, "f_ctime"); + strncpy(p, cp, l); + p[l] = '\0'; + put_malloced_string(p); +} +#endif + +#ifdef F_DEEP_INHERIT_LIST +void +f_deep_inherit_list (void) +{ + array_t *vec; + + vec = deep_inherit_list(sp->u.ob); + free_object(&sp->u.ob, "f_deep_inherit_list"); + put_array(vec); +} +#endif + +#ifdef DEBUG_MACRO + +#ifdef F_SET_DEBUG_LEVEL +void +f_set_debug_level (void) +{ + if (sp->type == T_STRING) { + debug_level_set(sp->u.string); + free_string_svalue(sp--); + } else + debug_level = (sp--)->u.number; +} + +void +f_clear_debug_level (void) { + debug_level_clear(sp->u.string); +} + +void +f_debug_levels (void) { + /* not in debug.h since debug.h is included in many places that don't + know about mapping_t */ + mapping_t *debug_levels (void); + + push_refed_mapping(debug_levels()); +} +#endif + +#endif + +#ifdef F_DEEP_INVENTORY +void +f_deep_inventory (void) +{ + array_t *vec; + int args = st_num_arg; + if(st_num_arg==2 && sp->type == T_FUNCTION && ((sp-1)->type==T_ARRAY || (sp-1)->type==T_OBJECT) ) { + if((sp-1)->type==T_ARRAY) + vec = deep_inventory_array((sp-1)->u.arr, 1 , sp->u.fp); + else /*(sp-1)->type==T_OBJECT*/ + vec = deep_inventory((sp-1)->u.ob, 0 , sp->u.fp); + } + else if(st_num_arg==1 && (sp->type==T_FUNCTION || sp->type==T_ARRAY || sp->type==T_OBJECT) ) { + if(sp->type==T_FUNCTION) + vec = deep_inventory(current_object, 0 , sp->u.fp); + else if(sp->type==T_ARRAY) + vec = deep_inventory_array(sp->u.arr, 1 , 0); + else /*sp->type==T_OBJECT*/ + vec = deep_inventory(sp->u.ob, 0 , 0); + } + else + vec = &the_null_array; + + pop_n_elems(args); + push_refed_array(vec); +} +#endif + +#ifdef F_DESTRUCT +void +f_destruct (void) +{ + destruct_object(sp->u.ob); + sp--; /* Ok since the object was removed from the stack */ +} +#endif + +#ifdef F_DUMPALLOBJ +void +f_dumpallobj (void) +{ + if (st_num_arg) { + dumpstat(sp->u.string); + free_string_svalue(sp--); + } else { + dumpstat("/OBJ_DUMP"); + } +} +#endif + +#ifdef F_ED +void +f_ed (void) +{ + if (!command_giver || !command_giver->interactive) { + pop_n_elems(st_num_arg); + return; + } + + if (!st_num_arg) { + /* ed() */ + ed_start(0, 0, 0, 0, 0, 0); + } else if (st_num_arg == 1) { + /* ed(fname) */ + ed_start(sp->u.string, 0, 0, 0, 0, 0); + pop_stack(); + } else if (st_num_arg == 2) { + /* ed(fname,exitfn) / ed(fname, scroll_lines) */ + if(sp->type == T_STRING) + ed_start((sp - 1)->u.string, 0, sp->u.string, 0, current_object, 0); + else if(sp->type == T_NUMBER) + ed_start((sp - 1)->u.string, 0, 0, 0, 0, sp->u.number); + else + bad_argument(sp, T_NUMBER | T_STRING, 2, F_ED); + pop_2_elems(); + } else if (st_num_arg == 3) { + /* ed(fname,exitfn,restricted) / ed(fname,writefn,exitfn) / + ed(fname,exitfn,scroll_lines) */ + if (sp->type == T_NUMBER) { + if(sp->u.number == 1) + ed_start((sp - 2)->u.string, 0, (sp - 1)->u.string, sp->u.number, + current_object, 0); + else + ed_start((sp - 2)->u.string, 0, (sp - 1)->u.string, 0, + current_object, sp->u.number); + } else if (sp->type == T_STRING) { + ed_start((sp - 2)->u.string, (sp - 1)->u.string, sp->u.string, 0, + current_object, 0); + } else { + bad_argument(sp, T_NUMBER | T_STRING, 3, F_ED); + } + pop_3_elems(); + } else if (st_num_arg == 4) { + /* ed(fname,writefn,exitfn,restricted) / + ed(fname,writefn,exitfn,scroll_lines) */ + if (!((sp - 1)->type == T_STRING)) + bad_argument(sp - 1, T_STRING, 3, F_ED); + if (!(sp->type == T_NUMBER)) + bad_argument(sp, T_NUMBER, 4, F_ED); + if(sp->u.number == 1) + ed_start((sp - 3)->u.string, (sp - 2)->u.string, (sp - 1)->u.string, + sp->u.number, current_object, 0); + else + ed_start((sp - 3)->u.string, (sp - 2)->u.string, (sp - 1)->u.string, + 0, current_object, sp->u.number); + pop_n_elems(4); + } else { /* st_num_arg == 5 */ + /* ed(fname, writefn, exitfn, restricted, scroll_lines) */ + if(!(sp->type == T_NUMBER)) + bad_argument(sp, T_NUMBER, 5, F_ED); + if(!((sp-1)->type == T_NUMBER)) + bad_argument(sp-1, T_NUMBER, 4, F_ED); + if(!((sp-2)->type == T_STRING)) + bad_argument(sp-2, T_STRING, 3, F_ED); + + ed_start((sp - 4)->u.string, (sp - 3)->u.string, (sp - 2)->u.string, + (sp - 1)->u.number, current_object, sp->u.number); + + pop_n_elems(5); + } +} +#endif + +#ifdef F_ED_CMD +void f_ed_cmd (void) +{ + char *res; + + if (current_object->flags & O_DESTRUCTED) + error("destructed objects can't use ed.\n"); + + if (!(current_object->flags & O_IN_EDIT)) + error("ed_cmd() called with no ed session active.\n"); + + res = object_ed_cmd(current_object, sp->u.string); + + free_string_svalue(sp); + if (res) { + sp->subtype = STRING_MALLOC; + sp->u.string = res; + } else { + sp->subtype = STRING_CONSTANT; + sp->u.string = ""; + } +} +#endif + +#ifdef F_ED_START +void f_ed_start (void) +{ + char *res; + const char *fname; + int restr = 0; + int scroll_lines = 20; + + if (st_num_arg == 3) { + scroll_lines = (sp--)->u.number; + restr = (sp--)->u.number; + } + + if (st_num_arg == 2) { + if(sp->u.number == 1) + restr = (sp--)->u.number; + else + scroll_lines = (sp--)->u.number; + } + + if (st_num_arg) + fname = sp->u.string; + else + fname = 0; + + if (current_object->flags & O_DESTRUCTED) + error("destructed objects can't use ed.\n"); + + if (current_object->flags & O_IN_EDIT) + error("ed_start() called while an ed session is already started.\n"); + + res = object_ed_start(current_object, fname, restr, scroll_lines); + + if (fname) free_string_svalue(sp); + else { + STACK_INC; + sp->type = T_STRING; + } + + if (res) { + sp->subtype = STRING_MALLOC; + sp->u.string = res; + } else { + sp->subtype = STRING_CONSTANT; + sp->u.string = ""; + } +} +#endif + +#ifdef F_ENABLE_WIZARD +void +f_enable_wizard (void) +{ + if (current_object->interactive) + current_object->flags |= O_IS_WIZARD; +} +#endif + +#ifdef F_ERROR +void +f_error (void) +{ + int l = SVALUE_STRLEN(sp); + char err_buf[2048]; + + if (sp->u.string[l - 1] == '\n') + l--; + if (l > 2045) l = 2045; + + err_buf[0] = '*'; + strncpy(err_buf + 1, sp->u.string, l); + err_buf[l + 1] = '\n'; + err_buf[l + 2] = 0; + + error_handler(err_buf); +} +#endif + +#ifdef F_DISABLE_WIZARD +void +f_disable_wizard (void) +{ + if (current_object->interactive) + current_object->flags &= ~O_IS_WIZARD; +} +#endif + +#ifdef F_ENVIRONMENT +void +f_environment (void) +{ + object_t *ob; + + if (st_num_arg) { + if ((ob = sp->u.ob)->flags & O_DESTRUCTED) + error("environment() of destructed object.\n"); + ob = ob->super; + free_object(&(sp--)->u.ob, "f_environment"); + } else if (!(current_object->flags & O_DESTRUCTED)) + ob = current_object->super; + else + error("environment() of destructed object.\n"); + + if (ob && object_visible(ob)) + push_object(ob); + else + push_number(0); +} +#endif + +#ifdef F_EXEC +void +f_exec (void) +{ + int i; + + i = replace_interactive((sp - 1)->u.ob, sp->u.ob); + + /* They might have been destructed */ + if (sp->type == T_OBJECT) + free_object(&sp->u.ob, "f_exec:1"); + if ((--sp)->type == T_OBJECT) + free_object(&sp->u.ob, "f_exec:2"); + put_number(i); +} +#endif + +#ifdef F_EXPLODE +void +f_explode (void) +{ + array_t *vec; + + int len = SVALUE_STRLEN(sp-1); + + vec = explode_string((sp - 1)->u.string, len, + sp->u.string, SVALUE_STRLEN(sp)); + free_string_svalue(sp--); + free_string_svalue(sp); + put_array(vec); +} +#endif + +#ifdef F_FILE_NAME +void +f_file_name (void) +{ + char *res; + + /* This function now returns a leading '/' */ + res = (char *) add_slash(sp->u.ob->obname); + free_object(&sp->u.ob, "f_file_name"); + put_malloced_string(res); +} +#endif + +#ifdef F_FILE_SIZE +void +f_file_size (void) +{ + long i = file_size(sp->u.string); + free_string_svalue(sp); + put_number(i); +} +#endif + +#ifdef F_FILTER +void +f_filter (void) +{ + svalue_t *arg = sp - st_num_arg + 1; + + if (arg->type == T_MAPPING) filter_mapping(arg, st_num_arg); + else if (arg->type == T_STRING) filter_string(arg, st_num_arg); + else filter_array(arg, st_num_arg); +} +#endif + +#ifdef F_FIND_CALL_OUT +void +f_find_call_out (void) +{ + int i; +#ifdef CALLOUT_HANDLES + if (sp->type == T_NUMBER) { + i = find_call_out_by_handle(sp->u.number); + } else { /* T_STRING */ +#endif + i = find_call_out(current_object, sp->u.string); + free_string_svalue(sp); +#ifdef CALLOUT_HANDLES + } +#endif + put_number(i); +} +#endif + +#ifdef F_FIND_OBJECT +void +f_find_object (void) +{ + object_t *ob; + + if ((sp--)->u.number) + ob = find_object(sp->u.string); + else + ob = find_object2(sp->u.string); + free_string_svalue(sp); + if (ob && object_visible(ob)) { + /* find_object only returns undested objects */ + put_unrefed_undested_object(ob, "find_object"); + } else + *sp = const0; +} +#endif + +#ifdef F_FUNCTION_PROFILE +/* f_function_profile: John Garnett, 1993/05/31, 0.9.17.3 */ +void +f_function_profile (void) +{ + array_t *vec; + mapping_t *map; + program_t *prog; + int nf, j; + object_t *ob; + + ob = sp->u.ob; + + prog = ob->prog; + nf = prog->num_functions_defined; + vec = allocate_empty_array(nf); + for (j = 0; j < nf; j++) { + map = allocate_mapping(3); + add_mapping_pair(map, "calls", prog->function_table[j].calls); + add_mapping_pair(map, "self", prog->function_table[j].self + - prog->function_table[j].children); + add_mapping_pair(map, "children", prog->function_table[j].children); + add_mapping_shared_string(map, "name", prog->function_table[j].funcname); + vec->item[j].type = T_MAPPING; + vec->item[j].u.map = map; + prog->function_table[j].calls = 0; + prog->function_table[j].self = 0; + prog->function_table[j].children = 0; + + } + free_object(&ob, "f_function_profile"); + put_array(vec); +} +#endif + +#ifdef F_FUNCTION_EXISTS +void +f_function_exists (void) +{ + const char *str; + char *res; + int l; + object_t *ob; + int flag = 0; + + if (st_num_arg > 1) { + if (st_num_arg > 2) + flag = (sp--)->u.number; + ob = sp->u.ob; + free_object(&(sp--)->u.ob, "f_function_exists"); + } else { + if (current_object->flags & O_DESTRUCTED) { + free_string_svalue(sp); + *sp = const0; + return; + } + ob = current_object; + } + + str = function_exists(sp->u.string, ob, flag); + free_string_svalue(sp); + if (str) { + l = SHARED_STRLEN(str) - 2; /* no .c */ + res = new_string(l + 1, "function_exists"); + res[0] = '/'; + strncpy(res + 1, str, l); + res[l + 1] = 0; + + sp->subtype = STRING_MALLOC; + sp->u.string = res; + } else *sp = const0; +} +#endif + +#ifdef F_GENERATE_SOURCE +void f_generate_source (void) +{ + int i; + + if (st_num_arg == 2) { + i = generate_source(sp - 1, sp->u.string); + pop_stack(); + } else + i = generate_source(sp, 0); + free_svalue(sp, "f_generate_source"); + put_number(i); +} +#endif + +#ifdef F_GET_CHAR +void +f_get_char (void) +{ + svalue_t *arg; + int i, tmp; + int flag; + + arg = sp - st_num_arg + 1; /* Points arg at first argument. */ + if (st_num_arg == 1 || !(arg[1].type == T_NUMBER)) { + tmp = 0; + flag = 0; + } else { + tmp = 1; + st_num_arg--; /* Don't count the flag as an arg */ + flag = arg[1].u.number; + } + st_num_arg--; + i = get_char(arg, flag, st_num_arg, &arg[1 + tmp]); + free_svalue(arg, "f_get_char"); + (sp = arg)->type = T_NUMBER; + sp->u.number = i; +} +#endif + +#ifdef F_GET_CONFIG +void +f_get_config (void) +{ + if (!get_config_item(sp, sp)) + error("Bad argument to get_config()\n"); +} +#endif + +#ifdef F_GET_DIR +void +f_get_dir (void) +{ + array_t *vec; + + vec = get_dir((sp - 1)->u.string, sp->u.number); + free_string_svalue(--sp); + if (vec) { put_array(vec); } + else *sp = const0; +} +#endif + +#ifdef F_IMPLODE +void +f_implode (void) +{ + array_t *arr; + int flag; + svalue_t *args; + + if (st_num_arg == 3) { + args = (sp - 2); + if (args[1].type == T_STRING) + error("Third argument to implode() is illegal with implode(array, string)\n"); + flag = 1; + } else { + args = (sp - 1); + flag = 0; + } + arr = args->u.arr; + check_for_destr(arr); + + if (args[1].type == T_STRING) { + /* st_num_arg == 2 here */ + char *str; + + str = implode_string(arr, sp->u.string, + SVALUE_STRLEN(sp)); + free_string_svalue(sp--); + free_array(arr); + put_malloced_string(str); + } else { /* function */ + funptr_t *funp = args[1].u.fp; + + /* this pulls the extra arg off the stack if it exists */ + implode_array(funp, arr, args, flag); + pop_stack(); + } +} +#endif + +#ifdef F_IN_EDIT +void +f_in_edit (void) +{ + char *fn; + ed_buffer_t *eb = 0; + +#ifdef OLD_ED + if (sp->u.ob->interactive) + eb = sp->u.ob->interactive->ed_buffer; +#else + if (sp->u.ob->flags & O_IN_EDIT) + eb = find_ed_buffer(sp->u.ob); +#endif + if (eb && (fn = eb->fname)) { + free_object(&sp->u.ob, "f_in_edit:1"); + put_malloced_string(add_slash(fn)); + return; + } + free_object(&sp->u.ob, "f_in_edit:1"); + *sp = const0; + return; +} +#endif + +#ifdef F_IN_INPUT +void +f_in_input (void) +{ + int i; + + i = sp->u.ob->interactive && sp->u.ob->interactive->input_to; + free_object(&sp->u.ob, "f_in_input"); + put_number(i != 0); +} +#endif + +#ifdef F_INHERITS +int +inherits (program_t * prog, program_t * thep) +{ + int j, k = prog->num_inherited, l; + program_t *pg; + + for (j = 0; j < k; j++) { + if ((pg = prog->inherit[j].prog) == thep) + return 1; + if (!strcmp(pg->filename, thep->filename)) + return 2; + if (l=inherits(pg, thep)) + return l; + } + return 0; +} + +void +f_inherits (void) +{ + object_t *ob, *base; + int i; + + base = (sp--)->u.ob; + ob = find_object2(sp->u.string); + if (!ob) { + free_object(&base, "f_inherits"); + assign_svalue(sp, &const0); + return; + } + i = inherits(base->prog, ob->prog); + free_object(&base, "f_inherits"); + free_string_svalue(sp); + put_number(i); +} +#endif + +#ifdef F_SHALLOW_INHERIT_LIST +void +f_shallow_inherit_list (void) +{ + array_t *vec; + + vec = inherit_list(sp->u.ob); + free_object(&sp->u.ob, "f_inherit_list"); + put_array(vec); +} +#endif + +#ifdef F_INPUT_TO +void +f_input_to (void) +{ + svalue_t *arg; + int i, tmp; + int flag; + + arg = sp - st_num_arg + 1; /* Points arg at first argument. */ + if ((st_num_arg == 1) || !(arg[1].type == T_NUMBER)) { + tmp = flag = 0; + } else { + tmp = 1; + st_num_arg--; /* Don't count the flag as an arg */ + flag = arg[1].u.number; + } + st_num_arg--; /* Don't count the name of the func either. */ + i = input_to(arg, flag, st_num_arg, &arg[1 + tmp]); + free_svalue(arg, "f_input_to"); + (sp = arg)->type = T_NUMBER; + sp->u.number = i; +} +#endif + +#ifdef F_INTERACTIVE +void +f_interactive (void) +{ + int i; + + i = (sp->u.ob->interactive != 0); + free_object(&sp->u.ob, "f_interactive"); + put_number(i); +} +#endif + +#ifdef F_HAS_MXP +void +f_has_mxp (void) +{ + int i=0; + + if (sp->u.ob->interactive) + { + i = sp->u.ob->interactive->iflags & USING_MXP; + i = !!i; //force 1 or 0 + } + free_object(&sp->u.ob, "f_has_mxp"); + put_number(i); +} +#endif + +#ifdef F_HAS_ZMP +void f_has_zmp (void) +{ + int i=0; + + if (sp->u.ob->interactive) + { + i = sp->u.ob->interactive->iflags & USING_ZMP; + i = !!i; //force 1 or 0 + } + free_object(&sp->u.ob, "f_has_zmp"); + put_number(i); +} +#endif + +#ifdef F_HAS_GMCP +void f_has_gmcp(){ + int i=0; + + if (sp->u.ob->interactive) + { + i = sp->u.ob->interactive->iflags & USING_GMCP; + i = !!i; //force 1 or 0 + } + free_object(&sp->u.ob, "f_has_zmp"); + put_number(i); +} +#endif + +#ifdef F_INTP +void +f_intp (void) +{ + if (sp->type == T_NUMBER) sp->u.number = 1; + else { + free_svalue(sp, "f_intp"); + put_number(0); + } +} +#endif + +#ifdef F_FUNCTIONP +void +f_functionp (void) +{ + int i; + + if (sp->type == T_FUNCTION) { + i = sp->u.fp->hdr.type; + if (sp->u.fp->hdr.args) + i |= FP_HAS_ARGUMENTS; + if (!sp->u.fp->hdr.owner || (sp->u.fp->hdr.owner->flags & O_DESTRUCTED)) + i |= FP_OWNER_DESTED; + free_funp(sp->u.fp); + put_number(i); + return; + } + assign_svalue(sp, &const0); +} +#endif + +#ifdef F_KEYS +void +f_keys (void) +{ + array_t *vec; + + vec = mapping_indices(sp->u.map); + free_mapping(sp->u.map); + put_array(vec); +} +#endif + +#ifdef F_VALUES +void +f_values (void) +{ + array_t *vec; + + vec = mapping_values(sp->u.map); + free_mapping(sp->u.map); + put_array(vec); +} +#endif + +#ifdef F_LINK +void +f_link (void) +{ + svalue_t *ret, *arg; + int i; + + arg = sp; + push_svalue(arg - 1); + push_svalue(arg); + ret = apply_master_ob(APPLY_VALID_LINK, 2); + if (MASTER_APPROVED(ret)) + i = do_rename((sp - 1)->u.string, sp->u.string, F_LINK); + else + i = 0; + (--sp)->type = T_NUMBER; + sp->u.number = i; + sp->subtype = 0; +} +#endif /* F_LINK */ + +#ifdef F_LOWER_CASE +void +f_lower_case (void) +{ + char *str; + + str = (char *)sp->u.string; + /* find first upper case letter, if any */ + for (; *str; str++) { + if (uisupper(*str)) { + int l = str - sp->u.string; + unlink_string_svalue(sp); + str = (char *)sp->u.string + l; + *str = tolower((unsigned char)*str); + for (str++; *str; str++) { + if (uisupper(*str)) + *str = tolower((unsigned char)*str); + } + return; + } + } +} +#endif + +#ifdef F_MALLOC_STATUS +void f_malloc_status (void) +{ + outbuffer_t ob; + + outbuf_zero(&ob); + +#ifdef MMALLOC + outbuf_add(&ob, "Using mmap malloc"); +#endif +#ifdef BSDMALLOC + outbuf_add(&ob, "Using BSD malloc"); +#endif +#ifdef SMALLOC + outbuf_add(&ob, "Using Smalloc"); +#endif +#ifdef SYSMALLOC + outbuf_add(&ob, "Using system malloc"); +#endif +#ifdef DEBUGMALLOC + outbuf_add(&ob, ", wrapped with debugmalloc"); +#endif +#ifdef WRAPPEDMALLOC + outbuf_add(&ob, ", wrapped with wrappedmalloc"); +#endif + outbuf_add(&ob, ".\n"); +#ifdef DO_MSTATS + show_mstats(&ob, "malloc_status()"); +#endif +#if (defined(WRAPPEDMALLOC) || defined(DEBUGMALLOC)) + dump_malloc_data(&ob); +#endif + outbuf_push(&ob); +} +#endif + +#ifdef F_MAP_DELETE +void +f_map_delete (void) +{ + mapping_delete((sp - 1)->u.map, sp); + pop_stack(); +#ifndef COMPAT_32 + free_mapping((sp--)->u.map); +#endif +} +#endif + +#ifdef F_MAPP +void +f_mapp (void) +{ + if (sp->type == T_MAPPING) { + free_mapping(sp->u.map); + *sp = const1; + } else { + free_svalue(sp, "f_mapp"); + *sp = const0; + } +} +#endif + +#ifdef F_MAP +void +f_map (void) +{ + svalue_t *arg = sp - st_num_arg + 1; + + if (arg->type == T_MAPPING) map_mapping(arg, st_num_arg); + else if (arg->type == T_ARRAY) map_array(arg, st_num_arg); + else map_string(arg, st_num_arg); +} +#endif + +#ifdef F_MASTER +void +f_master (void) +{ + if (!master_ob) + push_number(0); + else + push_object(master_ob); +} +#endif + +/* +This efun 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. DO NOT CHANGE THIS EFUN TIL YOU UNDERSTAND IT. It +catches folks by suprise at first, but it is coded the way it is for a reason. +It effectively implements the search loop in TMI's access object as a single +efun. + + Cygnus +*/ +#ifdef F_MATCH_PATH +void +f_match_path (void) +{ + svalue_t *value; + register const char *src; + register char *dst; + svalue_t *nvalue; + mapping_t *map; + char *tmpstr; + + value = &const0u; + + tmpstr = (char *)DMALLOC(SVALUE_STRLEN(sp) + 1, TAG_STRING, "match_path"); + + src = sp->u.string; + dst = tmpstr; + + while (*src != '\0') { + while (*src != '/' && *src != '\0') + *dst++ = *src++; + if (*src == '/') { + while (*++src == '/'); + if (*src != '\0' || dst == tmpstr) + *dst++ = '/'; + } + *dst = '\0'; + nvalue = find_string_in_mapping((sp - 1)->u.map, tmpstr); + + if (nvalue != &const0u) + value = nvalue; + } + + FREE(tmpstr); + /* Don't free mapping first, in case sometimes one uses a ref 1 mapping */ + /* Randor - 5/29/94 */ + free_string_svalue(sp--); + map = sp->u.map; + assign_svalue_no_free(sp, value); + free_mapping(map); +} +#endif /* F_MATCH_PATH */ + +#ifdef F_MEMBER_ARRAY +void +f_member_array (void) +{ + array_t *v; + int flag = 0; + int i; + int size; + + if (st_num_arg > 2) { + if (st_num_arg > 3) { + CHECK_TYPES(sp, T_NUMBER, 4, F_MEMBER_ARRAY); + flag = (sp--)->u.number; + } + CHECK_TYPES(sp, T_NUMBER, 3, F_MEMBER_ARRAY); + + i = (sp--)->u.number; + if (i<0) bad_arg(3, F_MEMBER_ARRAY); + } else + i = 0; + + if (sp->type == T_STRING) { + const char *res; + if(flag & 2) + error("member_array: can not search backwards in strings"); + CHECK_TYPES(sp-1, T_NUMBER, 1, F_MEMBER_ARRAY); + if (i > SVALUE_STRLEN(sp)) error("Index to start search from in member_array() is > string length.\n"); + if ((res = strchr(sp->u.string + i, (sp-1)->u.number))) + i = res - sp->u.string; + else + i = -1; + free_string_svalue(sp--); + } else { + svalue_t *sv; + svalue_t *find; + int flen; + + size = (v = sp->u.arr)->size; + find = (sp - 1); + /* optimize a bit */ + if (find->type == T_STRING) { + /* *not* COUNTED_STRLEN() which can do a (costly) strlen() call */ + if (find->subtype & STRING_COUNTED) + flen = MSTR_SIZE(find->u.string); + else if (flag & 1) + flen = strlen(find->u.string); + else flen = 0; + } + + for (; i < size; i++) { + int tmp = i; + if(flag & 2) + tmp = size - tmp - 1; + switch (find->type|(sv= v->item + tmp)->type) { + case T_STRING: + if (flag & 1) { + if (flen && (sv->subtype & STRING_COUNTED) + && flen > MSTR_SIZE(sv->u.string)) + continue; + if (strncmp(find->u.string, sv->u.string, flen)) continue; + } else { + if (flen && (sv->subtype & STRING_COUNTED) + && flen != MSTR_SIZE(sv->u.string)) + continue; + if (strcmp(find->u.string, sv->u.string)) continue; + } + break; + case T_NUMBER: + if (find->u.number == sv->u.number) + break; + continue; + case T_REAL: + if (find->u.real == sv->u.real) + break; + continue; + case T_ARRAY: + if (find->u.arr == sv->u.arr) + break; + continue; + case T_CLASS: + if (find->u.arr == sv->u.arr) + break; + continue; + case T_OBJECT: + { + if (sv->u.ob->flags & O_DESTRUCTED) { + assign_svalue(sv, &const0u); + continue; + } + if (find->u.ob == sv->u.ob) + break; + continue; + } + case T_MAPPING: + if (find->u.map == sv->u.map) + break; + continue; + case T_FUNCTION: + if (find->u.fp == sv->u.fp) + break; + continue; +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + if (find->u.buf == sv->u.buf) + break; + continue; +#endif + default: + if (sv->type == T_OBJECT && (sv->u.ob->flags & O_DESTRUCTED)) { + assign_svalue(sv, &const0u); + if (find->type == T_NUMBER && !find->u.number) + break; + } + continue; + } + break; + } + if (i >= size) + i = -1; /* Return -1 for failure */ + free_array(v); + free_svalue(find, "f_member_array"); + sp--; + } + if(flag & 2) + i = size - i - 1; + put_number(i); +} +#endif + +#ifdef F_MESSAGE +void +f_message (void) +{ + array_t *use, *avoid; + int num_arg = st_num_arg; + svalue_t *args; + + args = sp - num_arg + 1; + switch (args[2].type) { + case T_OBJECT: + case T_STRING: + use = allocate_empty_array(1); + use->item[0] = args[2]; + args[2].type = T_ARRAY; + args[2].u.arr = use; + break; + case T_ARRAY: + use = args[2].u.arr; + break; + case T_NUMBER: + if (args[2].u.number == 0) { + int len = SVALUE_STRLEN(args + 1); + + /* this is really bad and probably should be rm'ed -Beek; + * on the other hand, we don't have a debug_message() efun yet. + * Well, there is one in contrib now ... + */ + /* for compatibility (write() simul_efuns, etc) -bobf */ + if (len > LARGEST_PRINTABLE_STRING) + error("Printable strings limited to length of %d.\n", + LARGEST_PRINTABLE_STRING); + + add_message(command_giver, args[1].u.string, len); + pop_n_elems(num_arg); + return; + } + default: + bad_argument(&args[2], T_OBJECT | T_STRING | T_ARRAY | T_NUMBER, + 3, F_MESSAGE); + } + if (num_arg == 4) { + switch (args[3].type) { + case T_OBJECT: + avoid = allocate_empty_array(1); + avoid->item[0] = args[3]; + args[3].type = T_ARRAY; + args[3].u.arr = avoid; + break; + case T_ARRAY: + avoid = args[3].u.arr; + break; + default: + avoid = &the_null_array; + } + } else + avoid = &the_null_array; + do_message(&args[0], &args[1], use, avoid, 1); + pop_n_elems(num_arg); +} +#endif + +#ifdef F_MKDIR +void +f_mkdir (void) +{ + const char *path; + + path = check_valid_path(sp->u.string, current_object, "mkdir", 1); + if (!path || OS_mkdir(path, 0770) == -1) { + free_string_svalue(sp); + *sp = const0; + } + else{ + free_string_svalue(sp); + *sp = const1; + } +} +#endif + +#ifdef F_MOVE_OBJECT +void +f_move_object (void) +{ + object_t *o1, *o2; + + /* get destination */ + if (sp->type == T_OBJECT) + o2 = sp->u.ob; + else { + if (!(o2 = find_object(sp->u.string)) || !object_visible(o2)) + error("move_object failed: could not find destination\n"); + } + + if ((o1 = current_object)->flags & O_DESTRUCTED) + error("move_object(): can't move a destructed object\n"); + + move_object(o1, o2); + pop_stack(); +} +#endif + +#ifdef F_MUD_STATUS +void f_mud_status (void) +{ + int tot, res, verbose = 0; + outbuffer_t ob; + + outbuf_zero(&ob); + verbose = (sp--)->u.number; + + if (reserved_area) + res = RESERVED_SIZE; + else + res = 0; + + if (verbose) { + char dir_buf[1024]; + FILE *testfp; + + if ((testfp = fopen(".mudos_test_file", "w"))) { + fclose(testfp); + outbuf_add(&ob, "Open-file-test succeeded.\n"); + unlink(".mudos_test_file"); + } else { + outbuf_addv(&ob, "Open file test failed: %s\n", port_strerror(errno)); + } + + outbuf_addv(&ob, "current working directory: %s\n\n", + get_current_dir(dir_buf, 1024)); + outbuf_add(&ob, "add_message statistics\n"); + outbuf_add(&ob, "------------------------------\n"); + outbuf_addv(&ob, "Calls to add_message: %d Packets: %d Average packet size: %f\n\n", + add_message_calls, inet_packets, (float) inet_volume / inet_packets); + + stat_living_objects(&ob); + +#ifdef F_CACHE_STATS + print_cache_stats(&ob); + outbuf_add(&ob, "\n"); +#endif + tot = show_otable_status(&ob, verbose); + outbuf_add(&ob, "\n"); + tot += heart_beat_status(&ob, verbose); + outbuf_add(&ob, "\n"); + tot += add_string_status(&ob, verbose); + outbuf_add(&ob, "\n"); + tot += print_call_out_usage(&ob, verbose); + } else { + /* !verbose */ + outbuf_addv(&ob, "Sentences:\t\t\t%8d %8d\n", tot_alloc_sentence, + tot_alloc_sentence * sizeof(sentence_t)); +#ifndef DEBUG + outbuf_addv(&ob, "Objects:\t\t\t%8d %8d\n", + tot_alloc_object, tot_alloc_object_size); +#else + outbuf_addv(&ob, "Objects:\t\t\t%8d %8d (%8d dangling)\n", + tot_alloc_object, tot_alloc_object_size, tot_dangling_object); +#endif + outbuf_addv(&ob, "Prog blocks:\t\t\t%8d %8d\n", + total_num_prog_blocks, total_prog_block_size); +#ifdef ARRAY_STATS + outbuf_addv(&ob, "Arrays:\t\t\t\t%8d %8d\n", num_arrays, + total_array_size); +#else + outbuf_add(&ob, "\n"); +#endif +#ifdef CLASS_STATS + outbuf_addv(&ob, "Classes:\t\t\t%8d %8d\n", num_classes, + total_class_size); +#else + outbuf_add(&ob, "\n"); +#endif + + outbuf_addv(&ob, "Mappings:\t\t\t%8d %8d\n", num_mappings, + total_mapping_size); + outbuf_addv(&ob, "Mappings(nodes):\t\t%8d\n", total_mapping_nodes); + outbuf_addv(&ob, "Interactives:\t\t\t%8d %8d\n", num_user, + num_user * sizeof(interactive_t)); + + tot = show_otable_status(&ob, verbose) + + heart_beat_status(&ob, verbose) + + add_string_status(&ob, verbose) + + print_call_out_usage(&ob, verbose); + } + + tot += total_prog_block_size + +#ifdef ARRAY_STATS + total_array_size + +#endif +#ifdef CLASS_STATS + total_class_size + +#endif + total_mapping_size + + tot_alloc_sentence * sizeof(sentence_t) + + tot_alloc_object_size + + num_user * sizeof(interactive_t) + + res; + + if (!verbose) { + outbuf_add(&ob, "\t\t\t\t\t --------\n"); + outbuf_addv(&ob, "Total:\t\t\t\t\t %8d\n", tot); + } + outbuf_push(&ob); +} +#endif + +#ifdef F_OBJECTP +void +f_objectp (void) +{ + if (sp->type == T_OBJECT && !(sp->u.ob->flags & O_DESTRUCTED)) { + free_object(&sp->u.ob, "f_objectp"); + *sp = const1; + } else { + free_svalue(sp, "f_objectp"); + *sp = const0; + } +} +#endif + +#ifdef F_OPCPROF +void +f_opcprof (void) +{ + if (st_num_arg == 1) { + opcdump(sp->u.string); + free_string_svalue(sp--); + } else + opcdump("/OPCPROF"); +} +#endif + +#ifdef F_ORIGIN +void +f_origin (void) +{ + push_constant_string(origin_name(caller_type)); +} +#endif + +#ifdef F_POINTERP +void +f_pointerp (void) +{ + if (sp->type == T_ARRAY) { + free_array(sp->u.arr); + *sp = const1; + } else { + free_svalue(sp, "f_pointerp"); + *sp = const0; + } +} +#endif + +#ifdef F_PRESENT +void +f_present (void) +{ + int num_arg = st_num_arg; + svalue_t *arg = sp - num_arg + 1; + object_t *ob; + +#if !defined(NO_RESETS) && defined(LAZY_RESETS) + if (num_arg == 2) { + try_reset(arg[1].u.ob); + } +#endif + ob = object_present(arg, num_arg == 1 ? 0 : arg[1].u.ob); + pop_n_elems(num_arg); + if (ob && object_visible(ob)) push_object(ob); + else push_number(0); +} +#endif + +#ifdef F_PREVIOUS_OBJECT +void +f_previous_object (void) +{ + control_stack_t *p; + int i; + object_t *ob; + + if ((i = sp->u.number) > 0) { + if (i >= CFG_MAX_CALL_DEPTH) { + sp->u.number = 0; + return; + } + ob = 0; + p = csp; + do { + if ((p->framekind & FRAME_OB_CHANGE) && !(--i)) { + ob = p->prev_ob; + break; + } + } while (--p >= control_stack); + } else if (i == -1) { + array_t *v; + + i = previous_ob ? 1 : 0; + p = csp; + do { + if ((p->framekind & FRAME_OB_CHANGE) && p->prev_ob) + i++; + } while (--p >= control_stack); + v = allocate_empty_array(i); + p = csp; + if (previous_ob) { + if (!(previous_ob->flags & O_DESTRUCTED)) { + v->item[0].type = T_OBJECT; + v->item[0].u.ob = previous_ob; + add_ref(previous_ob, "previous_object(-1)"); + } else + v->item[0] = const0u; + i = 1; + } else + i = 0; + do { + if ((p->framekind & FRAME_OB_CHANGE) && (ob = p->prev_ob)) { + if (!(ob->flags & O_DESTRUCTED)) { + v->item[i].type = T_OBJECT; + v->item[i].u.ob = ob; + add_ref(ob, "previous_object(-1)"); + } else v->item[i] = const0u; + i++; + } + } while (--p >= control_stack); + put_array(v); + return; + } else if (i < 0) { + error("Illegal negative argument to previous_object()\n"); + } else + ob = previous_ob; + if (!ob || (ob->flags & O_DESTRUCTED)) + sp->u.number = 0; + else { + put_unrefed_undested_object(ob, "previous_object()"); + } +} +#endif + +#ifdef F_PRINTF +void +f_printf (void) +{ + int num_arg = st_num_arg; + char *ret; + + if (command_giver) { + ret = string_print_formatted((sp - num_arg + 1)->u.string, + num_arg - 1, sp - num_arg + 2); + if (ret) { + tell_object(command_giver, ret, COUNTED_STRLEN(ret)); + FREE_MSTR(ret); + } + } + + pop_n_elems(num_arg); +} +#endif + +#ifdef F_PROCESS_STRING +void +f_process_string (void) +{ + char *str; + + str = process_string(sp->u.string); + if (str != sp->u.string) { + free_string_svalue(sp); + put_malloced_string(str); + } +} +#endif + +#ifdef F_PROCESS_VALUE +void +f_process_value (void) +{ + svalue_t *ret; + + ret = process_value(sp->u.string); + free_string_svalue(sp); + if (ret) assign_svalue_no_free(sp, ret); + else *sp = const0; +} +#endif + +#ifdef F_QUERY_ED_MODE +void +f_query_ed_mode (void) +{ + /* n = prompt for line 'n' + 0 = normal ed prompt + -1 = not in ed + -2 = more prompt */ + if (current_object->flags & O_IN_EDIT) { + push_number(object_ed_mode(current_object)); + } else + push_number(-1); +} +#endif + +#ifdef F_QUERY_HOST_NAME +void +f_query_host_name (void) +{ + char *tmp; + + if ((tmp = query_host_name())) + push_constant_string(tmp); + else + push_number(0); +} +#endif + +#ifdef F_QUERY_IDLE +void +f_query_idle (void) +{ + int i; + + i = query_idle(sp->u.ob); + free_object(&sp->u.ob, "f_query_idle"); + put_number(i); +} +#endif + +#ifdef F_QUERY_IP_NAME +void +f_query_ip_name (void) +{ + char *tmp; + + tmp = query_ip_name(st_num_arg ? sp->u.ob : 0); + if (st_num_arg) free_object(&(sp--)->u.ob, "f_query_ip_name"); + if (!tmp) push_number(0); + else share_and_push_string(tmp); +} +#endif + +#ifdef F_QUERY_IP_NUMBER +void +f_query_ip_number (void) +{ + const char *tmp; + + tmp = query_ip_number(st_num_arg ? sp->u.ob : 0); + if (st_num_arg) free_object(&(sp--)->u.ob, "f_query_ip_number"); + if (!tmp) push_number(0); + else share_and_push_string(tmp); +} +#endif + +#ifdef F_QUERY_LOAD_AVERAGE +void +f_query_load_average (void) +{ + copy_and_push_string(query_load_av()); +} +#endif + +#ifdef F_QUERY_PRIVS +void +f_query_privs (void) +{ + object_t *ob; + + ob = sp->u.ob; + if (ob->privs != NULL) { + sp->type = T_STRING; + sp->u.string = make_shared_string(ob->privs); + sp->subtype = STRING_SHARED; + free_object(&ob, "f_query_privs"); + } else { + free_object(&ob, "f_query_privs"); + *sp = const0; + } +} +#endif + +#ifdef F_QUERY_SNOOPING +void +f_query_snooping (void) +{ + object_t *ob; + + ob = query_snooping(sp->u.ob); + free_object(&sp->u.ob, "f_query_snooping"); + if (ob) { put_unrefed_undested_object(ob, "query_snooping"); } + else *sp = const0; +} +#endif + +#ifdef F_QUERY_SNOOP +void +f_query_snoop (void) +{ + object_t *ob; + + ob = query_snoop(sp->u.ob); + free_object(&sp->u.ob, "f_query_snoop"); + if (ob) { put_unrefed_undested_object(ob, "query_snoop"); } + else *sp = const0; +} +#endif + +#ifdef F_RANDOM +void +f_random (void) +{ + if (sp->u.number <= 0) { + sp->u.number = 0; + return; + } + sp->u.number = random_number(sp->u.number); +} +#endif + +#ifdef F_READ_BYTES +void +f_read_bytes (void) +{ + char *str; + int start = 0, len = 0, rlen = 0, num_arg = st_num_arg; + svalue_t *arg; + + arg = sp - num_arg + 1; + if (num_arg > 1) + start = arg[1].u.number; + if (num_arg == 3) { + len = arg[2].u.number; + } + str = read_bytes(arg[0].u.string, start, len, &rlen); + pop_n_elems(num_arg); + if (str == 0) + push_number(0); + else { + push_malloced_string(str); + } +} +#endif + +#ifdef F_READ_BUFFER +void +f_read_buffer (void) +{ + char *str; + int start = 0, len = 0, rlen = 0, num_arg = st_num_arg; + int from_file = 0; /* new line */ + svalue_t *arg = sp - num_arg + 1; + + if (num_arg > 1) { + start = arg[1].u.number; + if (num_arg == 3) { + len = arg[2].u.number; + } + } + if (arg[0].type == T_STRING) { + from_file = 1; /* new line */ + str = read_bytes(arg[0].u.string, start, len, &rlen); + } else { /* T_BUFFER */ + str = read_buffer(arg[0].u.buf, start, len, &rlen); + } + pop_n_elems(num_arg); + if (str == 0) { + push_number(0); + } else if (from_file) { /* changed */ + buffer_t *buf; + + buf = allocate_buffer(rlen); + memcpy(buf->item, str, rlen); + STACK_INC; + sp->type = T_BUFFER; + sp->u.buf = buf; + FREE_MSTR(str); + } else { /* T_BUFFER */ + push_malloced_string(str); + } +} +#endif + +#ifdef F_READ_FILE +void +f_read_file (void) +{ + char *str; + int start,len; + + if (st_num_arg == 3) { + len = (sp--)->u.number; + } else len = 0; + if (st_num_arg > 1) + start = (sp--)->u.number; + else start = 0; + + str = read_file(sp->u.string, start, len); + free_string_svalue(sp); + if (!str) *sp = const0; + else { sp->subtype = STRING_MALLOC; sp->u.string = str; } +} +#endif + +#ifdef F_RECEIVE +void +f_receive (void) +{ + if (sp->type == T_STRING) { + if (current_object->interactive) { + int len = SVALUE_STRLEN(sp); + + if (len > LARGEST_PRINTABLE_STRING) + error("Printable strings limited to length of %d.\n", + LARGEST_PRINTABLE_STRING); + + add_message(current_object, sp->u.string, len); + } + free_string_svalue(sp--); + } +#ifndef NO_BUFFER_TYPE + else { + if (current_object->interactive) + add_message(current_object, (char *)sp->u.buf->item, sp->u.buf->size); + + free_buffer((sp--)->u.buf); + } +#endif +} +#endif + +#ifdef F_REG_ASSOC +void +f_reg_assoc (void) { + svalue_t *arg; + array_t *vec; + + arg = sp - st_num_arg + 1; + + if (!(arg[2].type == T_ARRAY)) + error("Bad argument 3 to reg_assoc()\n"); + + vec = reg_assoc(arg, arg[1].u.arr, arg[2].u.arr, st_num_arg > 3 ? &arg[3] : &const0); + + if (st_num_arg == 4) + pop_3_elems(); + else + pop_2_elems(); + free_string_svalue(sp); + sp->type = T_ARRAY; + sp->u.arr = vec; +} +#endif + +#ifdef F_REGEXP +void +f_regexp (void) +{ + array_t *v; + int flag; + + if (st_num_arg > 2) { + if (!(sp->type == T_NUMBER)) error("Bad argument 3 to regexp()\n"); + if (sp[-2].type == T_STRING) error("3rd argument illegal for regexp(string, string)\n"); + flag = (sp--)->u.number; + } else flag = 0; + if (sp[-1].type == T_STRING) { + flag = match_single_regexp((sp - 1)->u.string, sp->u.string); + free_string_svalue(sp--); + free_string_svalue(sp); + put_number(flag); + } else { + v = match_regexp((sp - 1)->u.arr, sp->u.string, flag); + + free_string_svalue(sp--); + free_array(sp->u.arr); + sp->u.arr = v; + } +} +#endif + +#ifdef F_REMOVE_CALL_OUT +void +f_remove_call_out (void) +{ + int i; + + if (st_num_arg) { +#ifdef CALLOUT_HANDLES + if (sp->type == T_STRING) { +#endif + i = remove_call_out(current_object, sp->u.string); + free_string_svalue(sp); +#ifdef CALLOUT_HANDLES + } else { + i = remove_call_out_by_handle(sp->u.number); + } +#endif + } else { + remove_all_call_out(current_object); + i = 0; + STACK_INC; + } + put_number(i); +} +#endif + +#ifdef F_RENAME +void +f_rename (void) +{ + int i; + + i = do_rename((sp - 1)->u.string, sp->u.string, F_RENAME); + free_string_svalue(sp--); + free_string_svalue(sp); + put_number(i); +} +#endif /* F_RENAME */ + +/* This is an enhancement to the f_replace_string() in efuns_main.c of + MudOS v21. When the search pattern has more than one character, + this version of f_replace_string() uses a skip table to more efficiently + search the file for the search pattern (the basic idea is to avoid + strings comparisons where possible). This version is anywhere from + 15% to 40% faster than the old version depending on the size of the + string to be searched and the length of the search string (and depending + on the relative frequency with which the letters in the search string + appear in the string to be searched). + + Note: this version should behave identically to the old version (except + for runtime). When the search pattern is only one character long, the + old algorithm is used. The new algorithm is actually about 10% slower + than the old one when the search string is only one character long. + + This enhancement to f_replace_string() was written by John Garnett + (aka Truilkan) on 1995/04/29. I believe the original replace_string() + was written by Dave Richards (Cygnus). + + I didn't come up with the idea of this algorithm (learned it in + a university programming course way back when). For those interested + in the workings of the algorithm, you can probably find it in a book on + string processing algorithms. Its also fairly easy to figure out the + algorithm by tracing through it for a small example. +*/ +#ifdef F_REPLACE_STRING + +/* +syntax for replace_string is now: + string replace_string(src, pat, rep); // or + string replace_string(src, pat, rep, max); // or + string replace_string(src, pat, rep, first, last); + +The 4th/5th args are optional (to retain backward compatibility). +- src, pat, and rep are all strings. +- max is an integer. It will replace all occurances up to max + matches (starting as 1 as the first), with a value of 0 meaning + 'replace all') +- first and last are just a range to replace between, with + the following constraints + first < 1: change all from start + last == 0 || last > max matches: change all to end + first > last: return unmodified array. +(i.e, with 4 args, it's like calling it with: + replace_string(src, pat, rep, 0, max); +) +*/ + +void +f_replace_string (void) +{ + int plen, rlen, dlen, slen, first, last, cur, j; + + const char *pattern; + const char *replace; + register const char *src; + register char *dst1, *dst2; + svalue_t *arg; + int skip_table[256]; + const char *slimit; + const char *flimit; + char *climit; + int probe; + int skip; + + if (st_num_arg > 5) { + error("Too many args to replace_string.\n"); + pop_n_elems(st_num_arg); + return; + } + arg = sp - st_num_arg + 1; + src = arg->u.string; + first = 0; + last = 0; + + if (st_num_arg >= 4) { + CHECK_TYPES((arg+3), T_NUMBER, 4, F_REPLACE_STRING); + first = (arg+3)->u.number; + + if (st_num_arg == 4) { + last = first; + first = 0; + } else if (st_num_arg == 5) { + CHECK_TYPES(sp, T_NUMBER, 5, F_REPLACE_STRING); + /* first set above. */ + last = sp->u.number; + } + } + + if (!last) + last = max_string_length; + + if (first > last) { /* just return it */ + pop_n_elems(st_num_arg - 1); + return; + } + pattern = (arg+1)->u.string; + plen = SVALUE_STRLEN(arg+1); + if (!plen) { + pop_n_elems(st_num_arg - 1); /* just return it */ + + return; + } + replace = (arg+2)->u.string; + rlen = SVALUE_STRLEN(arg+2); + dlen = 0; + cur = 0; + + if (rlen <= plen) { + /* we're going to do in string replacement */ + unlink_string_svalue(arg); + src = arg->u.string; + } + + if (plen > 1) { + /* build skip table */ + for (j = 0; j < 256; j++) { + skip_table[j] = plen; + } + for (j = 0; j < plen; j++) { + skip_table[(unsigned char)pattern[j]] = plen - j - 1; + } + slen = SVALUE_STRLEN(arg); + slimit = src + slen; + flimit = slimit - plen + 1; + probe = plen - 1; + } + + if (rlen <= plen) { + /* in string replacement */ + dst2 = dst1 = (char *)arg->u.string; + + if (plen > 1) { /* pattern length > 1, jump table most efficient */ + while (src < flimit) { + if ((skip = skip_table[(unsigned char)src[probe]])) { + for (climit = dst2 + skip; dst2 < climit; *dst2++ = *src++) + ; + } else if (memcmp(src, pattern, plen) == 0) { + cur++; + if ((cur >= first) && (cur <= last)) { + if (rlen) { + memcpy(dst2, replace, rlen); + dst2 += rlen; + } + src += plen; + if (cur == last) break; + } else { + memcpy(dst2, src, plen); + dst2 += plen; + src += plen; + } + } else { + *dst2++ = *src++; + } + } + memmove(dst2, src, slimit - src); + //memcpy(dst2, src, slimit - src); + dst2 += (slimit - src); + *dst2 = 0; + arg->u.string = extend_string(dst1, dst2 - dst1); + } else { /* pattern length <= 1, brute force most efficient */ + /* Beek - if it was zero, we already returned, so plen == 1 */ + /* assume source string is a string < maximum string length */ + if (rlen) { + while (*src) { + if (*src == *pattern) { + cur++; + + if (cur >= first && cur <= last) { + *(char *)src = *replace; + } + } + src++; + } + } else { /* rlen is zero */ + while (*src) { + if (*src++ == *pattern) { + cur++; + if (cur >= first) { + dst2 = (char *)src - 1; + while (*src) { + if (*src == *pattern) { + cur++; + if (cur <= last) { + src++; + continue; + } else { + while (*src) + *dst2++ = *src++; + break; + } + } + *dst2++ = *src++; + } + *dst2 = 0; + arg->u.string = extend_string(dst1, dst2 - dst1); + break; + } + } + } + } + } + pop_n_elems(st_num_arg - 1); + } else { + dst2 = dst1 = new_string(max_string_length, "f_replace_string: 2"); + + if (plen > 1) { + while (src < flimit) { + if ((skip = skip_table[(unsigned char)src[probe]])) { + for (climit = dst2 + skip; dst2 < climit; *dst2++ = *src++) + ; + + } else if (memcmp(src, pattern, plen) == 0) { + cur++; + if ((cur >= first) && (cur <= last)) { + if (max_string_length - dlen <= rlen) { + pop_n_elems(st_num_arg); + push_svalue(&const0u); + FREE_MSTR(dst1); + return; + } + memcpy(dst2, replace, rlen); + dst2 += rlen; + dlen += rlen; + src += plen; + if (cur == last) break; + } else { + dlen += plen; + if (max_string_length - dlen <= 0) { + pop_n_elems(st_num_arg); + push_svalue(&const0u); + + FREE_MSTR(dst1); + return; + } + memcpy(dst2, src, plen); + dst2 += plen; + src += plen; + } + } else { + if (max_string_length - dlen <= 1) { + pop_n_elems(st_num_arg); + push_svalue(&const0u); + + FREE_MSTR(dst1); + return; + } + *dst2++ = *src++; + dlen++; + } + } + if (max_string_length - dlen <= (slimit - src)) { + pop_n_elems(st_num_arg); + push_svalue(&const0u); + FREE_MSTR(dst1); + return; + } + memcpy(dst2, src, slimit - src); + dst2 += (slimit - src); + } else { /* plen <= 1 */ + /* Beek: plen == 1 */ + while (*src != '\0') { + if (*src == *pattern) { + cur++; + if (cur >= first && cur <= last) { + if (rlen != 0) { + if (max_string_length - dlen <= rlen) { + pop_n_elems(st_num_arg); + push_svalue(&const0u); + FREE_MSTR(dst1); + return; + } + strncpy(dst2, replace, rlen); + dst2 += rlen; + dlen += rlen; + } + src++; + continue; + } + } + if (max_string_length - dlen <= 1) { + pop_n_elems(st_num_arg); + push_svalue(&const0u); + FREE_MSTR(dst1); + return; + } + *dst2++ = *src++; + dlen++; + } + } + *dst2 = '\0'; + + pop_n_elems(st_num_arg); + /* + * shrink block or make a copy of exact size + */ + push_malloced_string(extend_string(dst1, dst2 - dst1)); + } +} +#endif + +#ifdef F_RESOLVE +void +f_resolve (void) +{ + int i; + + i = query_addr_number((sp - 1)->u.string, sp); + pop_stack(); + free_string_svalue(sp); + put_number(i); +} +#endif + +#ifdef F_RESTORE_OBJECT +void +f_restore_object (void) +{ + int flag; + + flag = (st_num_arg > 1) ? (sp--)->u.number : 0; + + flag = restore_object(current_object, sp->u.string, flag); + + free_string_svalue(sp); + put_number(flag); +} +#endif + +#ifdef F_RESTORE_VARIABLE +void +f_restore_variable (void) { + svalue_t v; + + unlink_string_svalue(sp); + v.type = T_NUMBER; + + //unlinked string + restore_variable(&v, (char *)sp->u.string); + FREE_MSTR(sp->u.string); + *sp = v; +} +#endif + +#ifdef F_RM +void +f_rm (void) +{ + int i; + + i = remove_file(sp->u.string); + free_string_svalue(sp); + put_number(i); +} +#endif + +#ifdef F_RMDIR +void +f_rmdir (void) +{ + const char *path; + + path = check_valid_path(sp->u.string, current_object, "rmdir", 1); + if (!path || rmdir(path) == -1) { + free_string_svalue(sp); + *sp = const0; + } + else { + free_string_svalue(sp); + *sp = const1; + } +} +#endif + +#ifdef F_SAVE_OBJECT +void +f_save_object (void) +{ + int flag; + + if (st_num_arg == 2 ) { + flag = (sp--)->u.number; + } else { + flag = 0; + } + + if(st_num_arg == 1 && sp->type == T_NUMBER) + flag = sp->u.number; + + if(st_num_arg && sp->type == T_STRING){ + flag = save_object(current_object, sp->u.string, flag); + + free_string_svalue(sp); + put_number(flag); + } else { + pop_n_elems(st_num_arg); + char *saved = new_string(MAX_STRING_LENGTH, "save_object_str"); + push_malloced_string(saved); + int left = MAX_STRING_LENGTH; + flag = save_object_str(current_object, flag, saved, left); + if(!flag){ + pop_stack(); + push_undefined(); + } else { + saved = new_string(strlen(sp->u.string), "save_object_str2"); + strcpy(saved, sp->u.string); + pop_stack(); + push_malloced_string(saved); + } + } +} +#endif + +#ifdef F_SAVE_VARIABLE +void +f_save_variable (void) { + char *p; + + p = save_variable(sp); + pop_stack(); + push_malloced_string(p); +} +#endif + +#ifdef F_SAY +void +f_say (void) +{ + array_t *avoid; + static array_t vtmp = + {1, +#ifdef DEBUG + 1, +#endif + 1, +#ifdef PACKAGE_MUDLIB_STATS + {(mudlib_stats_t *) NULL, (mudlib_stats_t *) NULL} +#endif + }; + + if (st_num_arg == 1) { + avoid = &the_null_array; + say(sp, avoid); + pop_stack(); + } else { + if (sp->type == T_OBJECT) { + vtmp.item[0].type = T_OBJECT; + vtmp.item[0].u.ob = sp->u.ob; + avoid = &vtmp; + } else { /* must be an array... */ + avoid = sp->u.arr; + } + say(sp - 1, avoid); + pop_2_elems(); + } +} +#endif + +#ifdef F_SET_EVAL_LIMIT +/* warning: do not enable this without using valid_override() in the master + object and a set_eval_limit() simul_efun to restrict access. +*/ +void +f_set_eval_limit (void) +{ + switch (sp->u.number) { + case 0: + sp->u.number = max_cost; + set_eval(max_cost); + break; + case -1: + sp->u.number = get_eval(); + break; + case 1: + sp->u.number = max_cost; + break; + default: + max_cost = sp->u.number; + break; + } +} +#endif + +#ifdef F_SET_BIT +void +f_set_bit (void) +{ + char *str; + int len, old_len, ind, bit; + + if (sp->u.number > MAX_BITS) + error("set_bit() bit requested: %d > maximum bits: %d\n", sp->u.number, MAX_BITS); + bit = (sp--)->u.number; + if (bit < 0) + error("Bad argument 2 (negative) to set_bit().\n"); + ind = bit/6; + bit %= 6; + old_len = len = SVALUE_STRLEN(sp); + if (ind >= len) + len = ind + 1; + if (ind < old_len) { + unlink_string_svalue(sp); + str = (char *)sp->u.string; + } else { + str = new_string(len, "f_set_bit: str"); + str[len] = '\0'; + if (old_len) + memcpy(str, sp->u.string, old_len); + if (len > old_len) + memset(str + old_len, ' ', len - old_len); + free_string_svalue(sp); + sp->subtype = STRING_MALLOC; + sp->u.string = str; + } + + if (str[ind] > 0x3f + ' ' || str[ind] < ' ') + error("Illegal bit pattern in set_bit character %d\n", ind); + str[ind] = ((str[ind] - ' ') | (1 << bit)) + ' '; +} +#endif + +#ifdef F_SET_HEART_BEAT +void +f_set_heart_beat (void) +{ + set_heart_beat(current_object, (sp--)->u.number); +} +#endif + +#ifdef F_QUERY_HEART_BEAT +void +f_query_heart_beat (void) +{ + int num = query_heart_beat(sp->u.ob); + free_object(&sp->u.ob, "f_query_heart_beat"); + put_number(num); +} +#endif + +#ifdef F_SET_HIDE +void +f_set_hide (void) +{ + if (!valid_hide(current_object)) { + sp--; + return; + } + if ((sp--)->u.number) { + num_hidden++; + if (!(current_object->flags & O_HIDDEN) && current_object->interactive) + num_hidden_users++; + current_object->flags |= O_HIDDEN; + } else { + num_hidden--; + if ((current_object->flags & O_HIDDEN) && current_object->interactive) + num_hidden_users--; + current_object->flags &= ~O_HIDDEN; + } +} +#endif + +#ifdef F_SET_LIGHT +void +f_set_light (void) +{ + object_t *o1; + + add_light(current_object, sp->u.number); + o1 = current_object; +#ifndef NO_ENVIRONMENT + while (o1->super) + o1 = o1->super; +#endif + sp->u.number = o1->total_light; +} +#endif + +#ifdef F_SET_PRIVS +void +f_set_privs (void) +{ + object_t *ob; + + ob = (sp - 1)->u.ob; + if (ob->privs != NULL) + free_string(ob->privs); + if (!(sp->type == T_STRING)) { + ob->privs = NULL; + sp--; /* It's a number */ + } else { + ob->privs = make_shared_string(sp->u.string); + free_string_svalue(sp--); + } + free_object(&ob, "f_set_privs"); + sp--; +} +#endif + +#ifdef F_SHADOW +void +f_shadow (void) +{ + object_t *ob; + + ob = (sp - 1)->u.ob; + if (!((sp--)->u.number)) { + ob = ob->shadowed; + free_object(&sp->u.ob, "f_shadow:1"); + if (ob) { + add_ref(ob, "shadow(ob, 0)"); + sp->u.ob = ob; + } + else *sp = const0; + return; + } + if (ob == current_object) { + error("shadow: Can't shadow self\n"); + } + if (validate_shadowing(ob)) { + if (current_object->flags & O_DESTRUCTED) { + free_object(&ob, "f_shadow:2"); + *sp = const0; + return; + } + /* + * The shadow is entered first in the chain. + */ + while (ob->shadowed) + ob = ob->shadowed; + current_object->shadowing = ob; + ob->shadowed = current_object; + free_object(&sp->u.ob, "f_shadow:3"); + add_ref(ob, "shadow(ob, 1)"); + sp->u.ob = ob; + return; + } + free_object(&sp->u.ob, "f_shadow:4"); + *sp = const0; +} +#endif + +#ifdef F_SHOUT +void +f_shout (void) +{ + shout_string(sp->u.string); + free_string_svalue(sp--); +} +#endif + +#ifdef F_SHUTDOWN +void +f_shutdown (void) +{ + if (st_num_arg) { + shutdownMudOS(sp->u.number); + } else { + shutdownMudOS(0); + push_number(0); + } +} +#endif + +#ifdef F_SIZEOF +void +f_sizeof (void) +{ + int i; + + switch (sp->type) { + case T_CLASS: + i = sp->u.arr->size; + free_class(sp->u.arr); + break; + case T_ARRAY: + i = sp->u.arr->size; + free_array(sp->u.arr); + break; + case T_MAPPING: + i = sp->u.map->count; + free_mapping(sp->u.map); + break; +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + i = sp->u.buf->size; + free_buffer(sp->u.buf); + break; +#endif + case T_STRING: + i = SVALUE_STRLEN(sp); + free_string_svalue(sp); + break; + default: + i = 0; + free_svalue(sp, "f_sizeof"); + } + sp->type = T_NUMBER; + sp->u.number = i; +} +#endif + +#ifdef F_SNOOP +void +f_snoop (void) +{ + /* + * This one takes a variable number of arguments. It returns 0 or an + * object. + */ + if (st_num_arg == 1) { + if (!new_set_snoop(sp->u.ob, 0) || (sp->u.ob->flags & O_DESTRUCTED)) { + free_object(&sp->u.ob, "f_snoop:1"); + *sp = const0; + } + } else { + if (!new_set_snoop((sp - 1)->u.ob, sp->u.ob) || + (sp->u.ob->flags & O_DESTRUCTED)) { + free_object(&(sp--)->u.ob, "f_snoop:2"); + free_object(&sp->u.ob, "f_snoop:3"); + *sp = const0; + } else { + free_object(&(--sp)->u.ob, "f_snoop:4"); + sp->u.ob = (sp+1)->u.ob; + } + } +} +#endif + +#ifdef F_SPRINTF +void +f_sprintf (void) +{ + char *s; + int num_arg = st_num_arg; + + s = string_print_formatted((sp - num_arg + 1)->u.string, + num_arg - 1, sp - num_arg + 2); + pop_n_elems(num_arg); + + STACK_INC; + sp->type = T_STRING; + if (!s) { + sp->subtype = STRING_CONSTANT; + sp->u.string = ""; + } else { + sp->subtype = STRING_MALLOC; + sp->u.string = s; + } +} +#endif + +#ifdef F_STAT +void +f_stat (void) +{ + struct stat buf; + const char *path; + array_t *v; + object_t *ob; + + path = check_valid_path((--sp)->u.string, current_object, "stat", 0); + if (!path) { + free_string_svalue(sp); + *sp = const0; + return; + } + if (stat(path, &buf) != -1) { + if (buf.st_mode & S_IFREG) { /* if a regular file */ + v = allocate_empty_array(3); + v->item[0].type = T_NUMBER; + v->item[0].u.number = buf.st_size; + v->item[1].type = T_NUMBER; + v->item[1].u.number = buf.st_mtime; + v->item[2].type = T_NUMBER; + ob = find_object2(path); + if (ob && !object_visible(ob)) + ob = 0; + if (ob) + v->item[2].u.number = ob->load_time; + else + v->item[2].u.number = 0; + free_string_svalue(sp); + put_array(v); + return; + } + } + v = get_dir(sp->u.string, (sp+1)->u.number); + free_string_svalue(sp); + if (v) { put_array(v); } + else *sp = const0; +} +#endif + +#ifdef F_STRSRCH +/* + * int strsrch(string big, string little, [ int flag ]) + * - search for little in big, starting at right if flag is set + * return int offset of little, -1 if not found + * + * Written 930706 by Luke Mewburn + */ + +void +f_strsrch (void) +{ + register const char *big, *little, *pos; + static char buf[2]; /* should be initialized to 0 */ + int i, blen, llen; + + sp--; + big = (sp - 1)->u.string; + blen = SVALUE_STRLEN(sp - 1); + if (sp->type == T_NUMBER) { + little = buf; + if ((buf[0] = (char) sp->u.number)) + llen = 1; + else + llen = 0; + } else { + little = sp->u.string; + llen = SVALUE_STRLEN(sp); + } + + if (!llen || blen < llen) { + pos = NULL; + + /* start at left */ + } else if (!((sp+1)->u.number)) { + if (!little[1]) /* 1 char srch pattern */ + pos = strchr(big, little[0]); + else + pos = (char *)strstr(big, little); + /* start at right */ + } else { /* XXX: maybe test for -1 */ + if (!little[1]) /* 1 char srch pattern */ + pos = strrchr(big, little[0]); + else { + char c = *little; + + pos = big + blen; /* find end */ + pos -= llen; /* find rightmost pos it _can_ be */ + do { + do { + if (*pos == c) break; + } while (--pos >= big); + if (pos < big) { + pos = NULL; + break; + } + for (i = 1; little[i] && (pos[i] == little[i]); i++); /* scan all chars */ + if (!little[i]) + break; + } while (--pos >= big); + } + } + + if (!pos) + i = -1; + else + i = pos - big; + if (sp->type == T_STRING) free_string_svalue(sp); + free_string_svalue(--sp); + put_number(i); +} /* strsrch */ +#endif + +#ifdef F_STRCMP +void +f_strcmp (void) +{ + int i; + + i = strcmp((sp - 1)->u.string, sp->u.string); + free_string_svalue(sp--); + free_string_svalue(sp); + put_number(i); +} +#endif + +#ifdef F_STRINGP +void +f_stringp (void) +{ + if (sp->type == T_STRING) { + free_string_svalue(sp); + *sp = const1; + } + else { + free_svalue(sp, "f_stringp"); + *sp = const0; + } +} +#endif + +#ifdef F_BUFFERP +void +f_bufferp (void) +{ + if (sp->type == T_BUFFER) { + free_buffer(sp->u.buf); + *sp = const1; + } else { + free_svalue(sp, "f_bufferp"); + *sp = const0; + } +} +#endif + +#ifdef F_TELL_OBJECT +void +f_tell_object (void) +{ + tell_object((sp - 1)->u.ob, sp->u.string, SVALUE_STRLEN(sp)); + free_string_svalue(sp--); + pop_stack(); +} +#endif + +#ifdef F_TELL_ROOM +void +f_tell_room (void) +{ + array_t *avoid; + static array_t vtmp = + {1, +#ifdef DEBUG + 1, +#endif + 1, +#ifdef PACKAGE_MUDLIB_STATS + {(mudlib_stats_t *) NULL, (mudlib_stats_t *) NULL} +#endif + }; + + int num_arg = st_num_arg; + svalue_t *arg = sp - num_arg + 1; + object_t *ob; + + if (arg->type == T_OBJECT) { + ob = arg[0].u.ob; + } else { /* must be a string... */ + ob = find_object(arg[0].u.string); + if (!ob || !object_visible(ob)) + error("Bad argument 1 to tell_room()\n"); + } + + if (num_arg == 2) { + avoid = &the_null_array; + } else { + if (arg[2].type == T_OBJECT) { + vtmp.item[0].type = T_OBJECT; + vtmp.item[0].u.ob = arg[2].u.ob; + avoid = &vtmp; + } else { + avoid = arg[2].u.arr; + } + } + + tell_room(ob, &arg[1], avoid); + if (num_arg > 2 && arg[2].type != T_OBJECT) + free_array(avoid); + free_svalue(arg + 1, "f_tell_room"); + free_svalue(arg, "f_tell_room"); + sp = arg - 1; +} +#endif + +#ifdef F_TEST_BIT +void +f_test_bit (void) +{ + int ind = (sp--)->u.number; + + if (ind / 6 >= SVALUE_STRLEN(sp)) { + free_string_svalue(sp); + *sp = const0; + return; + } + if (ind < 0) error("Bad argument 2 (negative) to test_bit().\n"); + if ((sp->u.string[ind / 6] - ' ') & (1 << (ind % 6))) { + free_string_svalue(sp); + *sp = const1; + } else { + free_string_svalue(sp); + *sp = const0; + } +} +#endif + +#ifdef F_NEXT_BIT +void +f_next_bit (void) +{ + int start = (sp--)->u.number; + int len = SVALUE_STRLEN(sp); + int which, bit=0, value; + + if (!len || start / 6 >= len) { + free_string_svalue(sp); + put_number(-1); + return; + } + /* Find the next bit AFTER start */ + if (start > 0) { + if (start % 6 == 5) { + which = (start / 6) + 1; + value = sp->u.string[which] - ' '; + } else { + /* we have a partial byte to check */ + which = start / 6; + bit = 0x3f - ((1 << ((start % 6) + 1)) - 1); + value = (sp->u.string[which] - ' ') & bit; + } + } else { + which = 0; + value = *sp->u.string - ' '; + } + + while (1) { + if (value) { + if (value & 0x07) { + if (value & 0x01) + bit = which * 6; + else if (value & 0x02) + bit = which * 6 + 1; + else if (value & 0x04) + bit = which * 6 + 2; + break; + } else if (value & 0x38) { + if (value & 0x08) + bit = which * 6 + 3; + else if (value & 0x10) + bit = which * 6 + 4; + else if (value & 0x20) + bit = which * 6 + 5; + break; + } + } + which++; + if (which == len) { + bit = -1; + break; + } + value = sp->u.string[which] - ' '; + } + + free_string_svalue(sp); + put_number(bit); +} +#endif + +#ifdef F__THIS_OBJECT +void +f__this_object (void) +{ + push_object(current_object); +} +#endif + +#ifdef F_THIS_PLAYER +void +f_this_player (void) +{ + if (sp->u.number) { + if (current_interactive) + put_unrefed_object(current_interactive, "this_player(1)"); + else sp->u.number = 0; + } else { + if (command_giver) + put_unrefed_object(command_giver, "this_player(0)"); + /* else zero is on stack already */ + } +} +#endif + +#ifdef F_SET_THIS_PLAYER +void +f_set_this_player (void) +{ + if (sp->type == T_NUMBER) + set_command_giver(0); + else + set_command_giver(sp->u.ob); + pop_stack(); +} +#endif + +#ifdef F_THROW +void +f_throw (void) +{ + free_svalue(&catch_value, "f_throw"); + catch_value = *sp--; + throw_error(); /* do the longjump, with extra checks... */ +} +#endif + +#ifdef F_TIME +void +f_time (void) +{ + push_number(current_time); +} +#endif + +#ifdef F__TO_FLOAT +void +f__to_float (void) +{ + double temp = 0; + + switch(sp->type) { + case T_NUMBER: + sp->type = T_REAL; + sp->u.real = (double) sp->u.number; + break; + case T_STRING: + sscanf(sp->u.string, "%lf", &temp); + free_string_svalue(sp); + sp->type = T_REAL; + sp->u.real = temp; + } +} +#endif + +#ifdef F__TO_INT +void +f__to_int (void) +{ + switch(sp->type) { + case T_REAL: + sp->type = T_NUMBER; + sp->u.number = (long) sp->u.real; + break; + case T_STRING: + { + long temp; + char *p; + + temp = strtol(sp->u.string, &p, 10); + if (*p) { + /* have to be a little careful here. Checkign if p == + * sp->u.string isn't good enough. + * + * Odd cases: + * to_int(" foo") // p == sp->u.string + 2 + * + * POSIX guarantees the strtol() works in terms of isspace(), + * though. If there is something other than whitespace, then + * there was a valid character consistent with the base, + * so we were successful. + * + * (note: this means to_int("10x") == 10. If you want to + * detect trailing garbage, use sscanf(str, "%d%s", ...). + */ + while (p > sp->u.string && uisspace(*(p - 1))) + p--; + + if (p == sp->u.string) { + free_string_svalue(sp); + *sp = const0u; + break; + } + } + free_string_svalue(sp); + sp->u.number = temp; + sp->type = T_NUMBER; + break; + } +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + if (sp->u.buf->size < sizeof(int)) { + free_buffer(sp->u.buf); + *sp = const0; + } else { + int hostint, netint; + + memcpy((char *) &netint, sp->u.buf->item, sizeof(int)); + hostint = ntohl(netint); + free_buffer(sp->u.buf); + put_number(hostint); + } +#endif + } +} +#endif + +#ifdef F_TYPEOF +void +f_typeof (void) +{ + const char *t = type_name(sp->type); + + free_svalue(sp, "f_typeof"); + put_constant_string(t); +} +#endif + +#ifdef F_UNDEFINEDP +void +f_undefinedp (void) +{ + if (sp->type == T_NUMBER) { + if (!sp->u.number && (sp->subtype == T_UNDEFINED)) { + *sp = const1; + } else *sp = const0; + } else { + free_svalue(sp, "f_undefinedp"); + *sp = const0; + } +} +#endif + +#ifdef F_UPTIME +void +f_uptime (void) +{ + push_number(current_time - boot_time); +} +#endif + +#ifdef F_USERP +void +f_userp (void) +{ + int i; + + i = sp->u.ob->flags & O_ONCE_INTERACTIVE; + free_object(&sp->u.ob, "f_userp"); + put_number(i != 0); +} +#endif + +#ifdef F_USERS +void +f_users (void) +{ + push_refed_array(users()); +} +#endif + +#ifdef F_WIZARDP +void +f_wizardp (void) +{ + int i; + + i = sp->u.ob->flags & O_IS_WIZARD; + free_object(&sp->u.ob, "f_wizardp"); + put_number(i != 0); +} +#endif + +#ifdef F_VIRTUALP +void +f_virtualp (void) +{ + int i; + + i = sp->u.ob->flags & O_VIRTUAL; + free_object(&sp->u.ob, "f_virtualp"); + put_number(i != 0); +} +#endif + +#ifdef F_WRITE +void +f_write (void) +{ + do_write(sp); + pop_stack(); +} +#endif + +#ifdef F_WRITE_BYTES +void +f_write_bytes (void) +{ + int i; + + switch(sp->type) { + case T_NUMBER: + { + int netint; + char *netbuf; + + if (!sp->u.number) + bad_arg(3, F_WRITE_BYTES); + netint = htonl(sp->u.number); /* convert to network + * byte-order */ + netbuf = (char *) &netint; + i = write_bytes((sp - 2)->u.string, (sp - 1)->u.number, netbuf, + sizeof(int)); + break; + } + +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + { + i = write_bytes((sp - 2)->u.string, (sp - 1)->u.number, + (char *) sp->u.buf->item, sp->u.buf->size); + break; + } +#endif + + case T_STRING: + { + i = write_bytes((sp - 2)->u.string, (sp - 1)->u.number, + sp->u.string, SVALUE_STRLEN(sp)); + break; + } + + default: + { +#ifdef NO_BUFFER_TYPE + bad_argument(sp, T_STRING | T_NUMBER, 3, F_WRITE_BYTES); +#else + bad_argument(sp, T_BUFFER | T_STRING | T_NUMBER, 3, F_WRITE_BYTES); +#endif + } + } + free_svalue(sp--, "f_write_bytes"); + free_string_svalue(--sp); + put_number(i); +} +#endif + +#ifdef F_WRITE_BUFFER +void +f_write_buffer (void) +{ + int i; + + if ((sp-2)->type == T_STRING) { + f_write_bytes(); + return; + } + + switch(sp->type) { + case T_NUMBER: + { + int netint; + char *netbuf; + + netint = htonl(sp->u.number); /* convert to network + * byte-order */ + netbuf = (char *) &netint; + i = write_buffer((sp - 2)->u.buf, (sp - 1)->u.number, netbuf, + sizeof(int)); + break; + } + + case T_BUFFER: + { + i = write_buffer((sp - 2)->u.buf, (sp - 1)->u.number, + (char *) sp->u.buf->item, sp->u.buf->size); + break; + } + + case T_STRING: + { + i = write_buffer((sp - 2)->u.buf, (sp - 1)->u.number, + sp->u.string, SVALUE_STRLEN(sp)); + break; + } + + default: + { + bad_argument(sp, T_BUFFER | T_STRING | T_NUMBER, 3, F_WRITE_BUFFER); + } + } + free_svalue(sp--, "f_write_buffer"); + free_svalue(--sp, "f_write_buffer"); + put_number(i); +} +#endif + +#ifdef F_WRITE_FILE +void +f_write_file (void) +{ + int flags = 0; + + flags = (sp--)->u.number; + flags = write_file((sp - 1)->u.string, sp->u.string, flags); + free_string_svalue(sp--); + free_string_svalue(sp); + put_number(flags); +} +#endif + +#ifdef F_DUMP_FILE_DESCRIPTORS +void +f_dump_file_descriptors (void) +{ + outbuffer_t out; + + outbuf_zero(&out); + dump_file_descriptors(&out); + outbuf_push(&out); +} +#endif + +#ifdef F_RECLAIM_OBJECTS +void f_reclaim_objects (void) +{ + push_number(reclaim_objects()); +} +#endif + +#ifdef F_MEMORY_INFO +void +f_memory_info (void) +{ + long mem; + object_t *ob; + + if (st_num_arg == 0) { + int res, tot; + + if (reserved_area) + res = RESERVED_SIZE; + else + res = 0; + tot = total_prog_block_size + +#ifdef ARRAY_STATS + total_array_size + +#endif +#ifdef CLASS_STATS + total_class_size + +#endif + total_mapping_size + + tot_alloc_object_size + + tot_alloc_sentence * sizeof(sentence_t) + + num_user * sizeof(interactive_t) + + show_otable_status(0, -1) + + heart_beat_status(0, -1) + + add_string_status(0, -1) + + print_call_out_usage(0, -1) + res; + push_number(tot); + return; + } + if (sp->type != T_OBJECT) + bad_argument(sp, T_OBJECT, 1, F_MEMORY_INFO); + ob = sp->u.ob; + /* as documented, object memory usage is not additive due to sharing of + structures, so always include the program's total size even if this + object is a clone or the program has more than one reference to it. + There's no reliable way to determine when the program size should be + included or not to be more accurate -- Marius, 30-Jul-2000 */ + mem = ob->prog->total_size; + mem += (data_size(ob) + sizeof(object_t)); + free_object(&ob, "f_memory_info"); + put_number(mem); +} +#endif + +#ifdef F_RELOAD_OBJECT +void +f_reload_object (void) +{ + reload_object(sp->u.ob); + free_object(&(sp--)->u.ob, "f_reload_object"); +} +#endif + +#ifdef F_QUERY_SHADOWING +void +f_query_shadowing (void) +{ + object_t *ob; + + if ((sp->type == T_OBJECT) && (ob = sp->u.ob)->shadowing) { + add_ref(ob->shadowing, "query_shadowing(ob)"); + sp->u.ob = ob->shadowing; + free_object(&ob, "f_query_shadowing"); + } else { + free_svalue(sp, "f_query_shadowing"); + *sp = const0; + } +} +#endif + +#ifdef F_SET_RESET +void +f_set_reset (void) +{ + if (st_num_arg == 2) { + (sp - 1)->u.ob->next_reset = current_time + sp->u.number; + free_object(&(--sp)->u.ob, "f_set_reset:1"); + sp--; + } else { + sp->u.ob->next_reset = current_time + TIME_TO_RESET / 2 + + random_number(TIME_TO_RESET / 2); + free_object(&(sp--)->u.ob, "f_set_reset:2"); + } +} +#endif + +#ifdef F_FLOATP +void +f_floatp (void) +{ + if (sp->type == T_REAL) { + sp->type = T_NUMBER; + sp->u.number = 1; + } + else { + free_svalue(sp, "f_floatp"); + *sp = const0; + } +} +#endif + +#ifdef F_FLUSH_MESSAGES +void +f_flush_messages (void) { + if (st_num_arg == 1) { + if (sp->u.ob->interactive) + flush_message(sp->u.ob->interactive); + pop_stack(); + } else { + int i; + + for (i = 0; i < max_users; i++) { + if (all_users[i] && !(all_users[i]->iflags & CLOSING)) + flush_message(all_users[i]); + } + } +} +#endif + +#ifdef F_FIRST_INVENTORY +void +f_first_inventory (void) +{ + object_t *ob; + + ob = first_inventory(sp); + free_svalue(sp, "f_first_inventory"); + if (ob) { put_unrefed_undested_object(ob, "first_inventory"); } + else *sp = const0; +} +#endif + +#ifdef F_NEXT_INVENTORY +void +f_next_inventory (void) +{ + object_t *ob; + + ob = sp->u.ob->next_inv; + free_object(&sp->u.ob, "f_next_inventory"); + +#ifdef F_SET_HIDE + while (ob && (ob->flags & O_HIDDEN) && !object_visible(ob)) + ob = ob->next_inv; +#endif + + if (ob) { + add_ref(ob, "next_inventory(ob) : 1"); + sp->u.ob = ob; + } else + *sp = const0; +} +#endif + +#ifdef F_DEFER +void f_defer(){ + struct defer_list *newlist = MALLOC(sizeof(struct defer_list)); + newlist->next = csp->defers; + newlist->func = *sp--; + if(command_giver){ + push_object(command_giver); + newlist->tp = *sp--; + } + else + newlist->tp = const0; + csp->defers = newlist; +} +#endif diff --git a/fluffos-2.23-ds03/efuns_main.h b/fluffos-2.23-ds03/efuns_main.h new file mode 100644 index 0000000..35d5bba --- /dev/null +++ b/fluffos-2.23-ds03/efuns_main.h @@ -0,0 +1,19 @@ +#ifndef EFUNS_MAIN_H +#define EFUNS_MAIN_H + +#include "lpc_incl.h" + +/* These really should be moved somewhere else */ +/* + * efuns_main.c + */ +extern int call_origin; + +int inherits (program_t *, program_t *); +void add_mapping_pair (mapping_t *, const char *, long); +void add_mapping_string (mapping_t *, const char *, const char *); +void add_mapping_object (mapping_t *, const char *, object_t *); +void add_mapping_array (mapping_t *, const char *, array_t *); +void add_mapping_shared_string (mapping_t *, const char *, char *); + +#endif diff --git a/fluffos-2.23-ds03/efuns_port.c b/fluffos-2.23-ds03/efuns_port.c new file mode 100644 index 0000000..85125c0 --- /dev/null +++ b/fluffos-2.23-ds03/efuns_port.c @@ -0,0 +1,334 @@ +/* + efunctions.c: this file contains the efunctions called from + inside eval_instruction() in interpret.c. Note: if you are adding + local efunctions that are specific to your driver, you would be better + off adding them to a separate source file. Doing so will make it much + easier for you to upgrade (won't have to patch this file). Be sure + to #include "lpc_incl.h" in that separate source file. +*/ + +#include "std.h" +#include "lpc_incl.h" +#include "file_incl.h" +#include "include/localtime.h" +#include "port.h" +#include "crypt.h" +#include "efun_protos.h" +#include + +/* get a value for CLK_TCK for use by times() */ +#if (defined(TIMES) && !defined(RUSAGE)) +/* this may need #ifdef'd to handle different types of machines */ +#include +#endif + +#ifdef F_CRYPT +#define SALT_LEN 8 +#ifdef CUSTOM_CRYPT +#define CRYPT(x, y) custom_crypt(x, y, 0) +#endif + +void +f_crypt (void) +{ + const char *res, *p; + char salt[SALT_LEN + 1]; + const char *choice = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ./"; + + if (sp->type == T_STRING && SVALUE_STRLEN(sp) >= 2) { + p = sp->u.string; + } else { + int i; + + for (i = 0; i < SALT_LEN; i++) + salt[i] = choice[random_number(strlen(choice))]; + + salt[SALT_LEN] = 0; + p = salt; + } + + res = string_copy(CRYPT((sp-1)->u.string, p), "f_crypt"); + pop_stack(); + free_string_svalue(sp); + sp->subtype = STRING_MALLOC; + sp->u.string = res; +} +#endif + +#ifdef F_OLDCRYPT +void +f_oldcrypt (void) { +#ifndef WIN32 + + char *res, salt[3]; + const char *choice = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ./"; + + if (sp->type == T_STRING && SVALUE_STRLEN(sp) >= 2) { + salt[0] = sp->u.string[0]; + salt[1] = sp->u.string[1]; + free_string_svalue(sp--); + } else { + salt[0] = choice[random_number(strlen(choice))]; + salt[1] = choice[random_number(strlen(choice))]; + pop_stack(); + } + salt[2] = 0; + res = string_copy(OLDCRYPT(sp->u.string, salt), "f_crypt"); + free_string_svalue(sp); + sp->subtype = STRING_MALLOC; + sp->u.string = res; +#endif +} +#endif + +#ifdef F_LOCALTIME +/* FIXME: most of the #ifdefs here should be based on configure checks + instead. Same for rusage() */ +void +f_localtime (void) +{ + struct tm *tm; + array_t *vec; + time_t lt; + +#ifdef sequent + struct timezone tz; +#endif + + lt = sp->u.number; + tm = localtime(<); + + vec = allocate_empty_array(11); + vec->item[LT_SEC].type = T_NUMBER; + vec->item[LT_SEC].u.number = tm->tm_sec; + vec->item[LT_MIN].type = T_NUMBER; + vec->item[LT_MIN].u.number = tm->tm_min; + vec->item[LT_HOUR].type = T_NUMBER; + vec->item[LT_HOUR].u.number = tm->tm_hour; + vec->item[LT_MDAY].type = T_NUMBER; + vec->item[LT_MDAY].u.number = tm->tm_mday; + vec->item[LT_MON].type = T_NUMBER; + vec->item[LT_MON].u.number = tm->tm_mon; + vec->item[LT_YEAR].type = T_NUMBER; + vec->item[LT_YEAR].u.number = tm->tm_year + 1900; + vec->item[LT_WDAY].type = T_NUMBER; + vec->item[LT_WDAY].u.number = tm->tm_wday; + vec->item[LT_YDAY].type = T_NUMBER; + vec->item[LT_YDAY].u.number = tm->tm_yday; + vec->item[LT_GMTOFF].type = T_NUMBER; + vec->item[LT_ZONE].type = T_STRING; + vec->item[LT_ZONE].subtype = STRING_MALLOC; + vec->item[LT_ISDST].type = T_NUMBER; +#if defined(BSD42) || defined(apollo) || defined(_AUX_SOURCE) \ + || defined(OLD_ULTRIX) + /* 4.2 BSD doesn't seem to provide any way to get these last three values */ + vec->item[LT_GMTOFF].u.number = 0; + vec->item[LT_ZONE].type = T_NUMBER; + vec->item[LT_ZONE].u.number = 0; + vec->item[LT_ISDST].u.number = -1; +#else /* BSD42 */ + vec->item[LT_ISDST].u.number = tm->tm_isdst; +#if defined(sequent) + vec->item[LT_GMTOFF].u.number = 0; + gettimeofday(NULL, &tz); + vec->item[LT_GMTOFF].u.number = tz.tz_minuteswest; + vec->item[LT_ZONE].u.string = + string_copy(timezone(tz.tz_minuteswest, tm->tm_isdst), "f_localtime"); +#else /* sequent */ +#if (defined(hpux) || defined(_SEQUENT_) || defined(_AIX) || defined(SunOS_5) \ + || defined(SVR4) || defined(sgi) || defined(linux) || defined(cray) \ + || defined(__CYGWIN__)\ + ) + if (!tm->tm_isdst) { + vec->item[LT_GMTOFF].u.number = timezone; + vec->item[LT_ZONE].u.string = string_copy(tzname[0], "f_localtime"); + } else { +#if (defined(_AIX) || defined(hpux) || defined(linux) || defined(cray) \ + || defined(__CYGWIN__)\ + ) + vec->item[LT_GMTOFF].u.number = timezone; +#else + vec->item[LT_GMTOFF].u.number = altzone; +#endif + vec->item[LT_ZONE].u.string = string_copy(tzname[1], "f_localtime"); + } +#else +#ifndef WIN32 + vec->item[LT_GMTOFF].u.number = tm->tm_gmtoff; + vec->item[LT_ZONE].u.string = string_copy(tm->tm_zone, "f_localtime"); +#else + vec->item[LT_GMTOFF].u.number = _timezone; + vec->item[LT_ZONE].u.string = string_copy(_tzname[_daylight?1:0],"f_localtime"); +#endif +#endif +#endif /* sequent */ +#endif /* BSD42 */ + put_array(vec); +} +#endif + +#ifdef F_RUSAGE +#ifdef WIN32 +void f_rusage (void) +{ + error("rusage() not supported under Windows.\n"); +} +#else + +#ifdef RUSAGE +void +f_rusage (void) +{ + struct rusage rus; + mapping_t *m; + long usertime, stime; + int maxrss; + + if (getrusage(RUSAGE_SELF, &rus) < 0) { + m = allocate_mapping(0); + } else { + char buf[256]; + int fd; + usertime = rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000; + stime = rus.ru_stime.tv_sec * 1000 + rus.ru_stime.tv_usec / 1000; + maxrss = rus.ru_maxrss; +#ifdef sun + maxrss *= getpagesize() / 1024; +#else +#ifdef __linux__ + fd = open("/proc/self/statm", O_RDONLY); + buf[read(fd, buf, 256)] = 0; + close(fd); + sscanf(buf, "%*d %d %*s", &maxrss); + maxrss *= getpagesize() / 1024; +#endif +#endif + m = allocate_mapping(16); + add_mapping_pair(m, "utime", usertime); + add_mapping_pair(m, "stime", stime); + add_mapping_pair(m, "maxrss", maxrss); + add_mapping_pair(m, "ixrss", rus.ru_ixrss); + add_mapping_pair(m, "idrss", rus.ru_idrss); + add_mapping_pair(m, "isrss", rus.ru_isrss); + add_mapping_pair(m, "minflt", rus.ru_minflt); + add_mapping_pair(m, "majflt", rus.ru_majflt); + add_mapping_pair(m, "nswap", rus.ru_nswap); + add_mapping_pair(m, "inblock", rus.ru_inblock); + add_mapping_pair(m, "oublock", rus.ru_oublock); + add_mapping_pair(m, "msgsnd", rus.ru_msgsnd); + add_mapping_pair(m, "msgrcv", rus.ru_msgrcv); + add_mapping_pair(m, "nsignals", rus.ru_nsignals); + add_mapping_pair(m, "nvcsw", rus.ru_nvcsw); + add_mapping_pair(m, "nivcsw", rus.ru_nivcsw); + } + push_refed_mapping(m); +} +#else + +#ifdef GET_PROCESS_STATS +void +f_rusage (void) +{ + struct process_stats ps; + mapping_t *m; + int utime, stime, maxrss; + + if (get_process_stats(NULL, PS_SELF, &ps, NULL) == -1) + m = allocate_mapping(0); + else { + utime = ps.ps_utime.tv_sec * 1000 + ps.ps_utime.tv_usec / 1000; + stime = ps.ps_stime.tv_sec * 1000 + ps.ps_stime.tv_usec / 1000; + maxrss = ps.ps_maxrss * getpagesize() / 1024; + + m = allocate_mapping(19); + add_mapping_pair(m, "utime", utime); + add_mapping_pair(m, "stime", stime); + add_mapping_pair(m, "maxrss", maxrss); + add_mapping_pair(m, "pagein", ps.ps_pagein); + add_mapping_pair(m, "reclaim", ps.ps_reclaim); + add_mapping_pair(m, "zerofill", ps.ps_zerofill); + add_mapping_pair(m, "pffincr", ps.ps_pffincr); + add_mapping_pair(m, "pffdecr", ps.ps_pffdecr); + add_mapping_pair(m, "swap", ps.ps_swap); + add_mapping_pair(m, "syscall", ps.ps_syscall); + add_mapping_pair(m, "volcsw", ps.ps_volcsw); + add_mapping_pair(m, "involcsw", ps.ps_involcsw); + add_mapping_pair(m, "signal", ps.ps_signal); + add_mapping_pair(m, "lread", ps.ps_lread); + add_mapping_pair(m, "lwrite", ps.ps_lwrite); + add_mapping_pair(m, "bread", ps.ps_bread); + add_mapping_pair(m, "bwrite", ps.ps_bwrite); + add_mapping_pair(m, "phread", ps.ps_phread); + add_mapping_pair(m, "phwrite", ps.ps_phwrite); + } + push_refed_mapping(m); +} +#else + +#ifdef TIMES /* has times() but not getrusage() */ + +/* + warning times are reported in processor dependent units of time. + see man pages for 'times' to figure out how long a tick is on your system. +*/ + +void +f_rusage (void) +{ + mapping_t *m; + struct tms t; + + times(&t); + m = allocate_mapping(2); + add_mapping_pair(m, "utime", t.tms_utime * 1000 / CLK_TCK); + add_mapping_pair(m, "stime", t.tms_stime * 1000 / CLK_TCK); + push_refed_mapping(m); +} + +#else + +#endif /* TIMES */ + +#endif /* GET_PROCESS_STATS */ + +#endif /* RUSAGE */ + +#endif /* WIN32 */ + +#endif + +#ifdef F_MALLOC_CHECK +/* this efun only useful on the NeXT (func_spec.c has #ifdef NeXT). A + non-zero return value indicates that some memory corruption has occurred + at some time prior to this calling of this efun. +*/ +void +f_malloc_check (void) +{ + push_number(NXMallocCheck()); +} +#endif + +#ifdef F_MALLOC_DEBUG +/* NeXT specific efun for setting the debugging level of NeXT's built-in + malloc. +*/ +void +f_malloc_debug (void) +{ + int level; + + level = sp->u.number; + if (level < 0) { + int rc; + + rc = malloc_debug(0); + malloc_singlethreaded(); + sp->u.number = rc; + } else { + sp->u.number = malloc_debug(level); + } +} +#endif diff --git a/fluffos-2.23-ds03/eoperators.c b/fluffos-2.23-ds03/eoperators.c new file mode 100644 index 0000000..8e63ac0 --- /dev/null +++ b/fluffos-2.23-ds03/eoperators.c @@ -0,0 +1,1305 @@ +/* + eoperators.c: this file contains all of the operators called from + inside eval_instruction() in interpret.c. +*/ + +#define SUPPRESS_COMPILER_INLINES +#include "std.h" +#include "lpc_incl.h" +#include "efuns_incl.h" +#include "backend.h" +#include "parse.h" +#ifdef TRACE +#include "comm.h" +#endif +#include "compiler.h" +#include "simul_efun.h" +#include "eoperators.h" + +INLINE void f_and() +{ + if (sp->type == T_ARRAY && (sp - 1)->type == T_ARRAY) { + sp--; + sp->u.arr = intersect_array((sp + 1)->u.arr, sp->u.arr); + return; + } + CHECK_TYPES(sp - 1, T_NUMBER, 1, F_AND); + CHECK_TYPES(sp, T_NUMBER, 2, F_AND); + sp--; + sp->u.number &= (sp + 1)->u.number; + sp->subtype = 0; +} + +INLINE void +f_and_eq() +{ + svalue_t *argp; + + argp = (sp--)->u.lvalue; + + if (argp->type == T_ARRAY && sp->type == T_ARRAY) { + sp->u.arr = argp->u.arr = intersect_array(argp->u.arr, sp->u.arr); + sp->u.arr->ref++; /* since we put it in two places */ + return; + } + if (argp->type != T_NUMBER) + error("Bad left type to &=\n"); + if (sp->type != T_NUMBER) + error("Bad right type to &=\n"); + sp->u.number = argp->u.number &= sp->u.number; + sp->subtype = 0; +} + +INLINE void +f_div_eq() +{ + svalue_t *argp = (sp--)->u.lvalue; + + switch (argp->type | sp->type) { + + case T_NUMBER: + { + if (!sp->u.number) error("Division by 0nn\n"); + sp->u.number = argp->u.number /= sp->u.number; + sp->subtype = 0; + break; + } + + case T_REAL: + { + if (sp->u.real == 0.0) error("Division by 0rr\n"); + sp->u.real = argp->u.real /= sp->u.real; + break; + } + + case T_NUMBER|T_REAL: + { + if (sp->type == T_NUMBER) { + if (!sp->u.number) error("Division by 0rn\n"); + sp->u.real = argp->u.real /= sp->u.number; + sp->type = T_REAL; + } else { + if (sp->u.real == 0.0) error("Division by 0nr\n"); + sp->u.real = argp->u.number /= sp->u.real; + } + break; + } + + default: + { + if (!(sp->type & (T_NUMBER|T_REAL))) error("Bad right type to /=\n"); + else error("Bad left type to /=\n"); + } + } +} + +INLINE void +f_eq() +{ + int i; + + switch (sp->type|(sp-1)->type) { + case T_NUMBER: + { + --sp; + sp->u.number = sp->u.number == (sp+1)->u.number; + sp->subtype = 0; + return; + } + + case T_REAL: + { + --sp; + sp->type = T_NUMBER; + sp->u.number = sp->u.real == (sp+1)->u.real; + sp->subtype = 0; + return; + } + + case T_NUMBER|T_REAL: + { + if ((--sp)->type == T_NUMBER) { + sp->u.number = sp->u.number == (sp+1)->u.real; + } + else { + sp->u.number = sp->u.real == (sp+1)->u.number; + sp->type = T_NUMBER; + } + sp->subtype = 0; + return; + } + + case T_ARRAY: + { + i = (sp-1)->u.arr == sp->u.arr; + free_array((sp--)->u.arr); + free_array(sp->u.arr); + break; + } + + case T_CLASS: + { + i = (sp-1)->u.arr == sp->u.arr; + free_class((sp--)->u.arr); + free_class(sp->u.arr); + break; + } + + case T_MAPPING: + { + i = (sp-1)->u.map == sp->u.map; + free_mapping((sp--)->u.map); + free_mapping(sp->u.map); + break; + } + + case T_STRING: + { + if (SVALUE_STRLEN_DIFFERS(sp-1,sp)) + i = 0; + else + i = !strcmp((sp-1)->u.string, sp->u.string); + free_string_svalue(sp--); + free_string_svalue(sp); + break; + } + + case T_OBJECT: + { + i = (sp-1)->u.ob == sp->u.ob; + free_object(&(sp--)->u.ob, "f_eq: 1"); + free_object(&sp->u.ob, "f_eq: 2"); + break; + } + + case T_FUNCTION: + { + i = (sp-1)->u.fp == sp->u.fp; + free_funp((sp--)->u.fp); + free_funp(sp->u.fp); + break; + } +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + { + i = (sp-1)->u.buf == sp->u.buf; + free_buffer((sp--)->u.buf); + free_buffer(sp->u.buf); + break; + } +#endif + default: + pop_stack(); + free_svalue(sp, "f_eq"); + i = 0; + } + /* args are freed, stack pointer points to spot for return value */ + put_number(i); +} + +INLINE void +f_ge() +{ + int i = sp->type; + switch ((--sp)->type | i) { + case T_NUMBER: + sp->u.number = sp->u.number >= (sp+1)->u.number; + sp->subtype = 0; + break; + case T_REAL: + i = sp->u.real >= (sp+1)->u.real; + put_number(i); + break; + case T_NUMBER | T_REAL: + if (i == T_NUMBER) { + sp->type = T_NUMBER; + sp->u.number = sp->u.real >= (sp+1)->u.number; + } else { + sp->u.number = sp->u.number >= (sp+1)->u.real; + } + sp->subtype = 0; + break; + case T_STRING: + i = strcmp(sp->u.string, (sp+1)->u.string) >= 0; + free_string_svalue(sp + 1); + free_string_svalue(sp); + put_number(i); + break; + default: + { + switch ((sp++)->type) { + case T_NUMBER: + case T_REAL: + bad_argument(sp, T_NUMBER | T_REAL, 2, F_GE); + case T_STRING: + bad_argument(sp, T_STRING, 2, F_GE); + default: + bad_argument(sp - 1, T_NUMBER | T_STRING | T_REAL, 1, F_GE); + } + } + } +} + +INLINE void +f_gt() { + int i = sp->type; + switch ((--sp)->type | i) { + case T_NUMBER: + sp->u.number = sp->u.number > (sp+1)->u.number; + sp->subtype = 0; + break; + case T_REAL: + sp->u.number = sp->u.real > (sp+1)->u.real; + sp->type = T_NUMBER; + sp->subtype = 0; + break; + case T_NUMBER | T_REAL: + if (i == T_NUMBER) { + sp->type = T_NUMBER; + sp->u.number = sp->u.real > (sp+1)->u.number; + } else sp->u.number = sp->u.number > (sp+1)->u.real; + sp->subtype = 0; + break; + case T_STRING: + i = strcmp(sp->u.string, (sp+1)->u.string) > 0; + free_string_svalue(sp+1); + free_string_svalue(sp); + put_number(i); + break; + default: + { + switch ((sp++)->type) { + case T_NUMBER: + case T_REAL: + bad_argument(sp, T_NUMBER | T_REAL, 2, F_GT); + case T_STRING: + bad_argument(sp, T_STRING, 2, F_GT); + default: + bad_argument(sp-1, T_NUMBER | T_REAL | T_STRING, 1, F_GT); + } + } + } +} + +INLINE void +f_le() +{ + int i = sp->type; + switch((--sp)->type|i) { + case T_NUMBER: + sp->u.number = sp->u.number <= (sp+1)->u.number; + break; + + case T_REAL: + sp->u.number = sp->u.real <= (sp+1)->u.real; + sp->type = T_NUMBER; + break; + + case T_NUMBER|T_REAL: + if (i == T_NUMBER) { + sp->type = T_NUMBER; + sp->u.number = sp->u.real <= (sp+1)->u.number; + } else sp->u.number = sp->u.number <= (sp+1)->u.real; + break; + + case T_STRING: + i = strcmp(sp->u.string, (sp+1)->u.string) <= 0; + free_string_svalue(sp+1); + free_string_svalue(sp); + sp->type = T_NUMBER; + sp->u.number = i; + break; + + default: + { + switch((sp++)->type) { + case T_NUMBER: + case T_REAL: + bad_argument(sp, T_NUMBER | T_REAL, 2, F_LE); + + case T_STRING: + bad_argument(sp, T_STRING, 2, F_LE); + + default: + bad_argument(sp - 1, T_NUMBER | T_STRING | T_REAL, 1, F_LE); + } + } + } + sp->subtype = 0; +} + +INLINE void +f_lt() { + int i = sp->type; + switch (i | (--sp)->type) { + case T_NUMBER: + sp->u.number = sp->u.number < (sp+1)->u.number; + break; + case T_REAL: + sp->u.number = sp->u.real < (sp+1)->u.real; + sp->type = T_NUMBER; + break; + case T_NUMBER|T_REAL: + if (i == T_NUMBER) { + sp->type = T_NUMBER; + sp->u.number = sp->u.real < (sp+1)->u.number; + } else sp->u.number = sp->u.number < (sp+1)->u.real; + break; + case T_STRING: + i = (strcmp(sp->u.string, (sp + 1)->u.string) < 0); + free_string_svalue(sp+1); + free_string_svalue(sp); + sp->type = T_NUMBER; + sp->u.number = i; + break; + default: + switch ((sp++)->type) { + case T_NUMBER: + case T_REAL: + bad_argument(sp, T_NUMBER | T_REAL, 2, F_LT); + case T_STRING: + bad_argument(sp, T_STRING, 2, F_LT); + default: + bad_argument(sp-1, T_NUMBER | T_STRING | T_REAL, 1, F_LT); + } + } + sp->subtype = 0; +} + +INLINE void +f_lsh() +{ + CHECK_TYPES((sp - 1), T_NUMBER, 1, F_LSH); + CHECK_TYPES(sp, T_NUMBER, 2, F_LSH); + sp--; + sp->u.number <<= (sp + 1)->u.number; +} + +INLINE void +f_lsh_eq() +{ + svalue_t *argp; + + + if ((argp = sp->u.lvalue)->type != T_NUMBER) + error("Bad left type to <<=\n"); + if ((--sp)->type != T_NUMBER) + error("Bad right type to <<=\n"); + sp->u.number = argp->u.number <<= sp->u.number; + sp->subtype = 0; +} + +INLINE void +f_mod_eq() +{ + svalue_t *argp; + + if ((argp = sp->u.lvalue)->type != T_NUMBER) + error("Bad left type to %=\n"); + if ((--sp)->type != T_NUMBER) + error("Bad right type to %=\n"); + if (sp->u.number == 0) + error("Modulo by 0\n"); + sp->u.number = argp->u.number %= sp->u.number; + sp->subtype = 0; +} + +INLINE void +f_mult_eq() +{ + svalue_t *argp = (sp--)->u.lvalue; + + switch(argp->type | sp->type) { + case T_NUMBER: + { + sp->u.number = argp->u.number *= sp->u.number; + sp->subtype = 0; + break; + } + + case T_REAL: + { + sp->u.real = argp->u.real *= sp->u.real; + break; + } + + case T_NUMBER|T_REAL: + { + if (sp->type == T_NUMBER) { + sp->type = T_REAL; + sp->u.real = argp->u.real *= sp->u.number; + } + else { + sp->u.real = argp->u.number *= sp->u.real; + } + break; + } + + case T_MAPPING: + { + mapping_t *m = compose_mapping(argp->u.map, sp->u.map,0); + if (argp->u.map != sp->u.map) { + pop_stack(); + push_mapping(m); + } + break; + } + + default: + { + if (!(sp->type & (T_NUMBER|T_REAL|T_MAPPING))) error("Bad right type to *=\n"); + else error("Bad left type to *=\n"); + } + } +} + + +INLINE void +f_ne() +{ + int i; + + switch (sp->type|(sp-1)->type) { + case T_NUMBER: + { + --sp; + sp->u.number = sp->u.number != (sp+1)->u.number; + sp->subtype = 0; + return; + } + + case T_REAL: + { + --sp; + sp->type = T_NUMBER; + sp->u.number = sp->u.real != (sp+1)->u.real; + sp->subtype = 0; + return; + } + + case T_NUMBER|T_REAL: + { + if ((--sp)->type == T_NUMBER) { + sp->u.number = sp->u.number != (sp+1)->u.real; + } + else { + sp->u.number = sp->u.real != (sp+1)->u.number; + sp->type = T_NUMBER; + } + sp->subtype = 0; + return; + } + + case T_ARRAY: + { + i = (sp-1)->u.arr != sp->u.arr; + free_array((sp--)->u.arr); + free_array(sp->u.arr); + break; + } + + case T_CLASS: + { + i = (sp-1)->u.arr != sp->u.arr; + free_class((sp--)->u.arr); + free_class(sp->u.arr); + break; + } + + case T_MAPPING: + { + i = (sp-1)->u.map != sp->u.map; + free_mapping((sp--)->u.map); + free_mapping(sp->u.map); + break; + } + + case T_STRING: + { + if (SVALUE_STRLEN_DIFFERS(sp-1, sp)) + i = 1; + else + i = !!strcmp((sp-1)->u.string, sp->u.string); + free_string_svalue(sp--); + free_string_svalue(sp); + break; + } + + case T_OBJECT: + { + i = (sp-1)->u.ob != sp->u.ob; + free_object(&(sp--)->u.ob, "f_ne: 1"); + free_object(&sp->u.ob, "f_ne: 2"); + break; + } + + case T_FUNCTION: + { + i = (sp-1)->u.fp != sp->u.fp; + free_funp((sp--)->u.fp); + free_funp(sp->u.fp); + break; + } + +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + { + i = (sp-1)->u.buf != sp->u.buf; + free_buffer((sp--)->u.buf); + free_buffer(sp->u.buf); + break; + } +#endif + + default: + pop_stack(); + free_svalue(sp, "f_ne"); + i = 1; + } + sp->type = T_NUMBER; + sp->subtype = 0; + sp->u.number = i; +} + +INLINE void +f_or() +{ + if (sp->type == T_ARRAY && (sp - 1)->type == T_ARRAY) { + sp--; + sp->u.arr = union_array(sp->u.arr, (sp+1)->u.arr); + return; + } + CHECK_TYPES((sp - 1), T_NUMBER, 1, F_OR); + CHECK_TYPES(sp, T_NUMBER, 2, F_OR); + sp--; + sp->u.number |= (sp + 1)->u.number; +} + +INLINE void +f_or_eq() +{ + svalue_t *argp; + + argp = (sp--)->u.lvalue; + if (argp->type == T_ARRAY && sp->type == T_ARRAY) { + argp->u.arr = sp->u.arr = union_array(argp->u.arr, sp->u.arr); + sp->u.arr->ref++; /* because we put it in two places */ + return; + } + + if (argp->type != T_NUMBER) + error("Bad left type to |=\n"); + if (sp->type != T_NUMBER) + error("Bad right type to |=\n"); + sp->u.number = argp->u.number |= sp->u.number; + sp->subtype = 0; +} + +INLINE void +f_parse_command() +{ + svalue_t *arg; + svalue_t *fp; + int i; + int num_arg; + + /* + * get number of lvalue args + */ + num_arg = EXTRACT_UCHAR(pc); + pc++; + + /* + * type checking on first three required parameters to parse_command() + */ + arg = sp - 2; + CHECK_TYPES(&arg[0], T_STRING, 1, F_PARSE_COMMAND); + CHECK_TYPES(&arg[1], T_OBJECT | T_ARRAY, 2, F_PARSE_COMMAND); + CHECK_TYPES(&arg[2], T_STRING, 3, F_PARSE_COMMAND); + + /* + * allocate stack frame for rvalues and return value (number of matches); + * perform some stack manipulation; + */ + fp = sp; + CHECK_STACK_OVERFLOW(num_arg + 1); + sp += num_arg + 1; + arg = sp; + *(arg--) = *(fp--); /* move pattern to top of stack */ + *(arg--) = *(fp--); /* move source object or array to just below + the pattern */ + *(arg) = *(fp); /* move source string just below the object */ + fp->type = T_NUMBER; + + /* + * prep area for rvalues + */ + for (i = 1; i <= num_arg; i++) + fp[i].type = T_INVALID; + + /* + * do it... + */ + i = parse(arg[0].u.string, &arg[1], arg[2].u.string, &fp[1], num_arg); + + /* + * remove mandatory parameters + */ + pop_3_elems(); + + /* + * save return value on stack + */ + fp->u.number = i; + fp->subtype = 0; +} + +INLINE void +f_range (int code) +{ + int from, to, len; + + if ((sp-2)->type != T_NUMBER) + error("Start of range [ .. ] interval must be a number.\n"); + if ((sp-1)->type != T_NUMBER) + error("End of range [ .. ] interval must be a number.\n"); + + switch(sp->type) { + case T_STRING: + { + const char *res = sp->u.string; + + len = SVALUE_STRLEN(sp); + to = (--sp)->u.number; + if (code & 0x01) to = len - to; +#ifdef OLD_RANGE_BEHAVIOR + else if (to < 0) + to += len; +#endif + from = (--sp)->u.number; + if (code & 0x10) from = len - from; +#ifdef OLD_RANGE_BEHAVIOR + else if (from < 0) + from += len; +#endif + if (from < 0) from = 0; + + if (to < from || from >= len) { + free_string_svalue(sp+2); + sp->type = T_STRING; + sp->subtype = STRING_CONSTANT; + sp->u.string = ""; + return; + } + + if (to >= len - 1) { + put_malloced_string(string_copy(res + from, "f_range")); + } else { + char *tmp; + tmp = new_string(to - from + 1, "f_range"); + strncpy(tmp, res + from, to - from + 1); + tmp[to - from + 1] = '\0'; + put_malloced_string(tmp); + } + free_string_svalue(sp + 2); + break; + } +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + { + buffer_t *rbuf = sp->u.buf; + + len = rbuf->size; + to = (--sp)->u.number; + if (code & 0x01) to = len - to; +#ifdef OLD_RANGE_BEHAVIOR + if (to < 0) to += len; +#endif + from = (--sp)->u.number; + if (code & 0x10) from = len - from; +#ifdef OLD_RANGE_BEHAVIOR + if (from < 0) { + if ((from += len) < 0) from = 0; + } +#else + if (from < 0) from = 0; +#endif + if (to < from || from >= len) { + free_buffer(rbuf); + put_buffer(null_buffer()); + return; + } + if (to >= len) to = len - 1; + { + buffer_t *nbuf = allocate_buffer(to - from + 1); + memcpy(nbuf->item, rbuf->item + from, to - from + 1); + free_buffer(rbuf); + put_buffer(nbuf); + } + break; + } +#endif + + case T_ARRAY: + { + array_t *v = sp->u.arr; + to = (--sp)->u.number; + if (code & 0x01) to = v->size - to; + from = (--sp)->u.number; + if (code & 0x10) from = v->size - from; + put_array(slice_array(v, from, to)); + break; + } + + default: + error("Cannot index type '%s' using [ .. ] operator.\n", + type_name(sp->type)); + } +} + +INLINE void +f_extract_range (int code) +{ + int from, len; + + if ((sp-1)->type != T_NUMBER) + error("Start of range [ .. ] interval must be a number.\n"); + + switch(sp->type) { + case T_STRING: + { + const char *res = sp->u.string; + + len = SVALUE_STRLEN(sp); + from = (--sp)->u.number; + if (code) from = len - from; +#ifdef OLD_RANGE_BEHAVIOR + if (from < 0) { + if ((from += len) < 0) from = 0; + } +#else + if (from < 0) from = 0; +#endif + if (from >= len) { + sp->type = T_STRING; + sp->subtype = STRING_CONSTANT; + sp->u.string = ""; + } else + put_malloced_string(string_copy(res + from, "f_extract_range")); + free_string_svalue(sp + 1); + break; + } +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + { + buffer_t *rbuf = sp->u.buf; + buffer_t *nbuf; + + + len = rbuf->size; + from = (--sp)->u.number; + if (code) from = len - from; +#ifdef OLD_RANGE_BEHAVIOR + if (from < 0) { + if ((from += len) < 0) from = 0; + } +#else + if (from < 0) from = 0; +#endif + if (from > len) from = len; + nbuf = allocate_buffer(len - from); + memcpy(nbuf->item, rbuf->item + from, len - from); + free_buffer(rbuf); + put_buffer(nbuf); + break; + } +#endif + + case T_ARRAY: + { + array_t *v = sp->u.arr; + from = (--sp)->u.number; + if (code) from = v->size - from; + put_array(slice_array(v, from, v->size - 1)); + break; + } + + default: + error("Bad argument to [ .. ] range operator.\n"); + } +} + +INLINE void +f_rsh() +{ + CHECK_TYPES((sp - 1), T_NUMBER, 1, F_RSH); + CHECK_TYPES(sp, T_NUMBER, 2, F_RSH); + sp--; + sp->u.number >>= (sp + 1)->u.number; +} + +INLINE void +f_rsh_eq() +{ + svalue_t *argp; + + if ((argp = sp->u.lvalue)->type != T_NUMBER) + error("Bad left type to >>=\n"); + if ((--sp)->type != T_NUMBER) + error("Bad right type to >>=\n"); + sp->u.number = argp->u.number >>= sp->u.number; + sp->subtype = 0; +} + +INLINE void +f_sub_eq() +{ + svalue_t *argp = (sp--)->u.lvalue; + + switch(argp->type | sp->type) { + case T_NUMBER: + { + sp->u.number = argp->u.number -= sp->u.number; + sp->subtype = 0; + break; + } + + case T_REAL: + { + sp->u.real = argp->u.real -= sp->u.real; + break; + } + + case T_NUMBER|T_REAL: + { + if (sp->type == T_NUMBER) { + sp->type = T_REAL; + sp->u.real = argp->u.real -= sp->u.number; + } else sp->u.real = argp->u.number -= sp->u.real; + break; + } + + case T_ARRAY: + { + sp->u.arr = argp->u.arr = subtract_array(argp->u.arr, sp->u.arr); + sp->u.arr->ref++; + break; + } + + case T_LVALUE_BYTE | T_NUMBER: + { + char c; + + c = *global_lvalue_byte.u.lvalue_byte - sp->u.number; + + if (global_lvalue_byte.subtype == 0 && c == '\0') + error("Strings cannot contain 0 bytes.\n"); + *global_lvalue_byte.u.lvalue_byte = c; + break; + } + + default: + { + if (!(sp->type & (T_NUMBER|T_REAL|T_ARRAY))) error("Bad right type to -=\n"); + else if (!(argp->type & (T_NUMBER|T_REAL|T_ARRAY))) error("Bad left type to -=\n"); + else error("Arguments to -= do not match in type.\n"); + } + } +} + +/* + * Structure of F_SWITCH: + * table type (1 byte) + * address of table (1 short) + * address of break (1 short) + * address of default (1 short) + * then all the switch code + * switch table (varies) + * + * Table type is either + * 0xfe - integer labels, direct lookup. + * Table is followed by 1 int that is minimum key value. + * Each table entry is a short address to jump to. + * 0xfN - integer labels. N is size as a power of 2. + * Each table entry is 1 long (key) followed by 1 short (address). + * 0xNf - string labels. Otherwise same as for integer labels. + * + * For normal string or integer tables, if the address is 0 or 1, + * the key is the lower end of a range, and the upper end is in + * the next entry. If it's a 0, the second address indicates a + * direct lookup table (currently this case is never generated by + * the compiler). If it's a 1, the second address is used for + * all keys in the range (corresponds to 'case x..y:' labels). + * + * Binary search is used on the normal tables. + */ + +/* offsets from 'pc' */ +#define SW_TYPE 0 +#define SW_TABLE 1 +#define SW_ENDTAB 3 +#define SW_DEFAULT 5 + +/* offsets used for range (L_ for lower member, U_ for upper member) */ +#define L_LOWER 0 +#define L_TYPE (sizeof(char *)) +#define L_UPPER (SWITCH_CASE_SIZE) +#define L_ADDR (SWITCH_CASE_SIZE + sizeof(char *)) +#define U_LOWER (-SWITCH_CASE_SIZE) +#define U_TYPE (-SWITCH_CASE_SIZE + sizeof(char *)) +#define U_UPPER 0 +#define U_ADDR (sizeof(char *)) + +INLINE void +f_switch() +{ + unsigned short offset, end_off; + long d; + POINTER_INT s; + POINTER_INT r; + long i; + char *l, *end_tab; + static unsigned short off_tab[] = + { + 0 * SWITCH_CASE_SIZE, 1 * SWITCH_CASE_SIZE, 3 * SWITCH_CASE_SIZE, + 7 * SWITCH_CASE_SIZE, 15 * SWITCH_CASE_SIZE, 31 * SWITCH_CASE_SIZE, + 63 * SWITCH_CASE_SIZE, 127 * SWITCH_CASE_SIZE, + 255 * SWITCH_CASE_SIZE, 511 * SWITCH_CASE_SIZE, + 1023 * SWITCH_CASE_SIZE, 2047 * SWITCH_CASE_SIZE, + 4095 * SWITCH_CASE_SIZE, + }; + + COPY_SHORT(&offset, pc + SW_TABLE); + COPY_SHORT(&end_off, pc + SW_ENDTAB); + + if ((i = EXTRACT_UCHAR(pc) >> 4) != 0xf) { /* String table, find correct + * key */ + if (sp->type == T_NUMBER && !sp->u.number) { + /* special case: 0 as a string */ + s = 0; + sp--; + } else if (sp->type == T_STRING) { + if (sp->subtype == STRING_SHARED) { + s = (POINTER_INT)sp->u.string; + free_string(sp->u.string); + sp--; + } else { + s = (POINTER_INT)findstring(sp->u.string); + free_string_svalue(sp--); + } + if (s == 0) { + /* + * Take default case now - else we could be get confused with + * ZERO_AS_STR_CASE_LABEL. + */ + COPY_SHORT(&offset, pc + SW_DEFAULT); + pc += offset; + return; + } + } else { + bad_argument(sp, T_STRING, 1, F_SWITCH); + } + } else { /* Integer table, check type */ + CHECK_TYPES(sp, T_NUMBER, 1, F_SWITCH); + s = (sp--)->u.number; + i = pc[0] & 0xf; + } + end_tab = pc + end_off; + /* + * i is the table size as a power of 2. Tells us where to start + * searching. i==14 is a special case. + */ + + if (i >= 13) { + if (i == 14) { + char *zz = end_tab - SIZEOF_LONG; + /* fastest switch format : lookup table */ + l = pc + offset; + COPY_INT(&d, zz); + /* d is minimum value - see if in range or not */ + s -= d; + if (s >= 0 && s < (zz-l)/sizeof(short)) { + COPY_SHORT(&offset, l + s * sizeof(short)); + if (offset) { + pc += offset; + return; + } + } + /* default */ + COPY_SHORT(&offset, pc + SW_DEFAULT); + pc += offset; + return; + } else + fatal("unsupported switch table format.\n"); + } + + /* + * l - current entry we are looking at. + * d - size to add/subtract from l each iteration. + * s - key we're looking for + * r - key l is pointing at + */ + l = pc + offset + off_tab[i]; + d = (off_tab[i] + SWITCH_CASE_SIZE) >> 1; + if (d < SWITCH_CASE_SIZE) + d = 0; + for (;;) { + COPY_PTR(&r, l); + if (s < r) { + if (d < SWITCH_CASE_SIZE) { + /* test if entry is part of a range */ + /* Don't worry about reading from F_BREAK (byte before table) */ + COPY_SHORT(&offset, l + U_TYPE); + if (offset <= 1) { + COPY_PTR(&r, l + U_LOWER); + if (s >= r) { + /* s is in the range */ + COPY_SHORT(&offset, l + U_ADDR); + if (!offset) { + /* range with lookup table */ + l = pc + offset + + (s - r) * sizeof(short); + COPY_SHORT(&offset, l); + } /* else normal range and offset is correct */ + break; + } + } + /* key not found, use default address */ + COPY_SHORT(&offset, pc + SW_DEFAULT); + break; + } else { + /* d >= SWITCH_CASE_SIZE */ + l -= d; + d >>= 1; + } + } else if (s > r) { + if (d < SWITCH_CASE_SIZE) { + /* test if entry is part of a range */ + COPY_SHORT(&offset, l + L_TYPE); + if (offset <= 1) { + COPY_PTR(&r, l + L_UPPER); + if (s <= r) { + /* s is in the range */ + COPY_SHORT(&offset, l + L_ADDR); + if (!offset) { + /* range with lookup table */ + l = pc + offset + (s - r) * sizeof(short); + COPY_SHORT(&offset, l); + } /* else normal range and offset is correct */ + break; + } + } + /* use default address */ + COPY_SHORT(&offset, pc + SW_DEFAULT); + break; + } else { /* d >= SWITCH_CASE_SIZE */ + l += d; + /* if table isn't a power of 2 in size, fix us up */ + while (l >= end_tab) { + d >>= 1; + if (d < SWITCH_CASE_SIZE) { + d = 0; + break; + } + l -= d; + } + if (l == end_tab) { + /* use default address */ + COPY_SHORT(&offset, pc + SW_DEFAULT); + break; + } + d >>= 1; + } + } else { + /* s == r */ + COPY_SHORT(&offset, l + U_ADDR); + /* found the key - but could be part of a range... */ + if (!l[U_TYPE] && !l[U_TYPE + 1]) { + /* end of range with lookup table */ + COPY_PTR(&r, l + U_LOWER); + l = pc + offset + (s - r) * sizeof(short); + COPY_SHORT(&offset, l); + } + if (offset <= 1) { + COPY_SHORT(&offset, l + L_ADDR); + if (!offset) { + /* start of range with lookup table */ + l = pc + offset; + COPY_SHORT(&offset, l); + } /* else normal range, offset is correct */ + } + break; + } + } + /* now do jump */ + pc += offset; +} + +void +call_simul_efun (unsigned short index, int num_arg) +{ + extern object_t *simul_efun_ob; + + if (current_object->flags & O_DESTRUCTED) { /* No external calls allowed */ + pop_n_elems(num_arg); + push_undefined(); + return; + } + + if (simuls[index].func) { +#ifdef TRACE + if (TRACEP(TRACE_CALL_OTHER)) { + do_trace("simul_efun ", simuls[index].func->funcname, "\n"); + } +#endif + /* Don't need to use apply() since we have the pointer directly; + * this saves function lookup. + */ + call_direct(simul_efun_ob, simuls[index].index, + ORIGIN_SIMUL_EFUN, num_arg); + } else + error("Function is no longer a simul_efun.\n"); +} + +INLINE void +f_xor() +{ + CHECK_TYPES((sp - 1), T_NUMBER, 1, F_XOR); + CHECK_TYPES(sp, T_NUMBER, 2, F_XOR); + sp--; + sp->u.number ^= (sp + 1)->u.number; +} + +INLINE void +f_xor_eq() +{ + svalue_t *argp; + + if ((argp = sp->u.lvalue)->type != T_NUMBER) + error("Bad left type to ^=\n"); + if ((--sp)->type != T_NUMBER) + error("Bad right type to ^=\n"); + sp->u.number = argp->u.number ^= sp->u.number; +} + +INLINE void +f_function_constructor() +{ + funptr_t *fp; + int kind; + unsigned short index; + + kind = EXTRACT_UCHAR(pc++); + + switch (kind) { + case FP_EFUN: + LOAD_SHORT(index, pc); + fp = make_efun_funp(index, sp); + pop_stack(); + break; + case FP_LOCAL: + LOAD_SHORT(index, pc); + fp = make_lfun_funp(index, sp); + pop_stack(); + break; + case FP_SIMUL: + LOAD_SHORT(index, pc); + fp = make_simul_funp(index, sp); + pop_stack(); + break; + case FP_FUNCTIONAL: + case FP_FUNCTIONAL | FP_NOT_BINDABLE: + { + int num_arg; + + num_arg = EXTRACT_UCHAR(pc++); /* number of arguments */ + LOAD_SHORT(index, pc); /* length of functional */ + fp = make_functional_funp(num_arg, 0, index, sp, kind & FP_NOT_BINDABLE); + pop_stack(); + break; + } + case FP_ANONYMOUS: + case FP_ANONYMOUS | FP_NOT_BINDABLE: + { + int num_arg, locals; + + num_arg = EXTRACT_UCHAR(pc++); + locals = EXTRACT_UCHAR(pc++); + LOAD_SHORT(index, pc); /* length */ + fp = make_functional_funp(num_arg, locals, index, 0, kind & FP_NOT_BINDABLE); + break; + } + default: + fatal("Tried to make unknown type of function pointer.\n"); + } + push_refed_funp(fp); +} + +INLINE void +f__evaluate (void) +{ + svalue_t *v; + svalue_t *arg = sp - st_num_arg + 1; + + if (arg->type != T_FUNCTION) { + pop_n_elems(st_num_arg-1); + return; + } + if (current_object->flags & O_DESTRUCTED) { + pop_n_elems(st_num_arg); + push_undefined(); + return; + } + v = call_function_pointer(arg->u.fp, st_num_arg - 1); + assign_svalue(sp, v); +} + +INLINE void +f_sscanf() +{ + svalue_t *fp; + int i; + int num_arg; + + /* + * get number of lvalue args + */ + num_arg = EXTRACT_UCHAR(pc); + pc++; + + /* + * allocate stack frame for rvalues and return value (number of matches); + * perform some stack manipulation; note: source and template strings are + * already on the stack by this time + */ + fp = sp; + CHECK_STACK_OVERFLOW(num_arg + 1); + sp += num_arg + 1; + *sp = *(fp--); /* move format description to top of stack */ + *(sp - 1) = *(fp); /* move source string just below the format + * desc. */ + fp->type = T_NUMBER; /* this svalue isn't invalidated below, and + * if we don't change it to something safe, + * it will get freed twice if an error occurs */ + /* + * prep area for rvalues + */ + for (i = 1; i <= num_arg; i++) + fp[i].type = T_INVALID; + + /* + * do it... + */ + i = inter_sscanf(sp - 2, sp - 1, sp, num_arg); + + /* + * remove source & template strings from top of stack + */ + pop_2_elems(); + + /* + * save number of matches on stack + */ + fp->u.number = i; + fp->subtype = 0; +} diff --git a/fluffos-2.23-ds03/eoperators.h b/fluffos-2.23-ds03/eoperators.h new file mode 100644 index 0000000..e302251 --- /dev/null +++ b/fluffos-2.23-ds03/eoperators.h @@ -0,0 +1,36 @@ +/* this file was manually generated -- don't delete it */ + +INLINE void f_ge (void); +INLINE void f_le (void); +INLINE void f_lt (void); +INLINE void f_gt (void); +INLINE void f_and (void); +INLINE void f_and_eq (void); +INLINE void f_div_eq (void); +INLINE void f_eq (void); +INLINE void f_lsh (void); +INLINE void f_lsh_eq (void); +INLINE void f_mod_eq (void); +INLINE void f_mult_eq (void); +INLINE void f_ne (void); +INLINE void f_or (void); +INLINE void f_or_eq (void); +INLINE void f_parse_command (void); +INLINE void f_range (int); +INLINE void f_extract_range (int); +INLINE void f_rsh (void); +INLINE void f_rsh_eq (void); +INLINE void f_simul_efun (void); +INLINE void f_sub_eq (void); +INLINE void f_switch (void); +INLINE void f_xor (void); +INLINE void f_xor_eq (void); +INLINE void f_function_constructor (void); +INLINE void f_evaluate (void); +INLINE void f_sscanf (void); + +/* + * eoperators.c + */ +void call_simul_efun (unsigned short, int); + diff --git a/fluffos-2.23-ds03/eval.c b/fluffos-2.23-ds03/eval.c new file mode 100644 index 0000000..bd527bd --- /dev/null +++ b/fluffos-2.23-ds03/eval.c @@ -0,0 +1,40 @@ +#include "std.h" +#include "main.h" +#include "comm.h" +#include "uvalarm.h" +#include +#include "backend.h" + +int outoftime = 0; +struct timeval tv; +int lasttime; + +void set_eval(int etime){ +#ifndef WIN32 + long diff; + gettimeofday(&tv, NULL); + if((diff = tv.tv_sec-current_time) > 1){ + diff *= 1000000; + if(diff > max_cost*100){ + //put some hard limit to eval times + outoftime = 1; + return; + } + } + signal(SIGVTALRM, sigalrm_handler); + uvalarm(etime, 0); +#endif + outoftime = 0; + +} + +int get_eval(){ +#ifndef WIN32 + struct timeval now; + gettimeofday(&now, NULL); + return max_cost - (1000000*(now.tv_sec - tv.tv_sec))-(now.tv_usec - tv.tv_usec); +#else + return 100; +#endif +} + diff --git a/fluffos-2.23-ds03/eval.h b/fluffos-2.23-ds03/eval.h new file mode 100644 index 0000000..795adf9 --- /dev/null +++ b/fluffos-2.23-ds03/eval.h @@ -0,0 +1,6 @@ +#ifndef FLUFF_EVAL_H +#define FLUFF_EVAL_H +extern int outoftime; +void set_eval(int time); +int get_eval(); +#endif diff --git a/fluffos-2.23-ds03/file.c b/fluffos-2.23-ds03/file.c new file mode 100644 index 0000000..8ac0bf2 --- /dev/null +++ b/fluffos-2.23-ds03/file.c @@ -0,0 +1,1200 @@ +/* + * file: file.c + * description: handle all file based efuns + */ + +#include "std.h" +#include "file.h" +#include "comm.h" +#include "lex.h" +#include "md.h" +#include "port.h" +#include "master.h" + +#ifdef PACKAGE_COMPRESS +#include +#endif + +int legal_path (const char *); + +static int match_string (char *, char *); +static int copy (const char *from, const char *to); +static int do_move (const char *from, const char *to, int flag); +static int CDECL pstrcmp (CONST void *, CONST void *); +static int CDECL parrcmp (CONST void *, CONST void *); +static void encode_stat (svalue_t *, int, char *, struct stat *); + +#define MAX_LINES 50 + +/* + * These are used by qsort in get_dir(). + */ +static int CDECL pstrcmp (CONST void * p1, CONST void * p2) +{ + svalue_t *x = (svalue_t *)p1; + svalue_t *y = (svalue_t *)p2; + + return strcmp(x->u.string, y->u.string); +} + +static int CDECL parrcmp (CONST void * p1, CONST void * p2) +{ + svalue_t *x = (svalue_t *)p1; + svalue_t *y = (svalue_t *)p2; + + return strcmp(x->u.arr->item[0].u.string, y->u.arr->item[0].u.string); +} + +static void encode_stat (svalue_t * vp, int flags, char * str, struct stat * st) +{ + if (flags == -1) { + array_t *v = allocate_empty_array(3); + + v->item[0].type = T_STRING; + v->item[0].subtype = STRING_MALLOC; + v->item[0].u.string = string_copy(str, "encode_stat"); + v->item[1].type = T_NUMBER; + v->item[1].u.number = + ((st->st_mode & S_IFDIR) ? -2 : st->st_size); + v->item[2].type = T_NUMBER; + v->item[2].u.number = st->st_mtime; + vp->type = T_ARRAY; + vp->u.arr = v; + } else { + vp->type = T_STRING; + vp->subtype = STRING_MALLOC; + vp->u.string = string_copy(str, "encode_stat"); + } +} + +/* + * List files in directory. This function do same as standard list_files did, + * but instead writing files right away to user this returns an array + * containing those files. Actually most of code is copied from list_files() + * function. + * Differences with list_files: + * + * - file_list("/w"); returns ({ "w" }) + * + * - file_list("/w/"); and file_list("/w/."); return contents of directory + * "/w" + * + * - file_list("/");, file_list("."); and file_list("/."); return contents + * of directory "/" + * + * With second argument equal to non-zero, instead of returning an array + * of strings, the function will return an array of arrays about files. + * The information in each array is supplied in the order: + * name of file, + * size of file, + * last update of file. + */ +/* WIN32 should be fixed to do this correctly (i.e. no ifdefs for it) */ +#define MAX_FNAME_SIZE 255 +#define MAX_PATH_LEN 1024 +array_t *get_dir (const char * path, int flags) +{ + array_t *v; + int i, count = 0; +#ifndef WIN32 + DIR *dirp; +#endif + int namelen, do_match = 0; + +#ifndef WIN32 +#ifdef USE_STRUCT_DIRENT + struct dirent *de; +#else + struct direct *de; +#endif +#endif + struct stat st; + char *endtemp; + char temppath[MAX_FNAME_SIZE + MAX_PATH_LEN + 2]; + char regexppath[MAX_FNAME_SIZE + MAX_PATH_LEN + 2]; + char *p; + +#ifdef WIN32 + struct _finddata_t FindBuffer; + long FileHandle, FileCount; +#endif + + if (!path) + return 0; + + path = check_valid_path(path, current_object, "stat", 0); + + if (path == 0) + return 0; + + if (strlen(path) < 2) { + temppath[0] = path[0] ? path[0] : '.'; + temppath[1] = '\000'; + p = temppath; + } else { + strncpy(temppath, path, MAX_FNAME_SIZE + MAX_PATH_LEN + 1); + temppath[MAX_FNAME_SIZE + MAX_PATH_LEN + 1] = '\0'; + + /* + * If path ends with '/' or "/." remove it + */ + if ((p = strrchr(temppath, '/')) == 0) + p = temppath; + if (p[0] == '/' && ((p[1] == '.' && p[2] == '\0') || p[1] == '\0')) + *p = '\0'; + } + + if (stat(temppath, &st) < 0) { + if (*p == '\0') + return 0; + if (p != temppath) { + strcpy(regexppath, p + 1); + *p = '\0'; + } else { + strcpy(regexppath, p); + strcpy(temppath, "."); + } + do_match = 1; + } else if (*p != '\0' && strcmp(temppath, ".")) { + if (*p == '/' && *(p + 1) != '\0') + p++; + v = allocate_empty_array(1); + encode_stat(&v->item[0], flags, p, &st); + return v; + } +#ifdef WIN32 + FileHandle = -1; + FileCount = 1; +/* strcat(temppath, "\\*"); */ + strcat(temppath, "/*"); + if ((FileHandle = _findfirst(temppath, &FindBuffer)) == -1) return 0; +#else + if ((dirp = opendir(temppath)) == 0) + return 0; +#endif + + /* + * Count files + */ +#ifdef WIN32 + do { + if (!do_match && (!strcmp(FindBuffer.name, ".") || + !strcmp(FindBuffer.name, ".."))) { + continue; + } + if (do_match && !match_string(regexppath, FindBuffer.name)) { + continue; + } + count++; + if (count >= max_array_size) { + break; + } + } while (!_findnext(FileHandle, &FindBuffer)); + _findclose(FileHandle); +#else + for (de = readdir(dirp); de; de = readdir(dirp)) { +#ifdef USE_STRUCT_DIRENT + namelen = strlen(de->d_name); +#else + namelen = de->d_namlen; +#endif + if (!do_match && (strcmp(de->d_name, ".") == 0 || + strcmp(de->d_name, "..") == 0)) + continue; + if (do_match && !match_string(regexppath, de->d_name)) + continue; + count++; + if (count >= max_array_size) + break; + } +#endif + + /* + * Make array and put files on it. + */ + v = allocate_empty_array(count); + if (count == 0) { + /* This is the easy case :-) */ +#ifndef WIN32 + closedir(dirp); +#endif + return v; + } +#ifdef WIN32 + FileHandle = -1; + if ((FileHandle = _findfirst(temppath, &FindBuffer)) == -1) return 0; + endtemp = temppath + strlen(temppath) - 2; + *endtemp = 0; +/* strcat(endtemp++, "\\"); */ + strcat(endtemp++, "/"); + i = 0; + do { + if (!do_match && (!strcmp(FindBuffer.name, ".") || + !strcmp(FindBuffer.name, ".."))) continue; + if (do_match && !match_string(regexppath, FindBuffer.name)) continue; + if (flags == -1) { + strcpy(endtemp, FindBuffer.name); + stat(temppath, &st); + } + encode_stat(&v->item[i], flags, FindBuffer.name, &st); + i++; + } while (!_findnext(FileHandle, &FindBuffer)); + _findclose(FileHandle); +#else /* WIN32 */ + rewinddir(dirp); + endtemp = temppath + strlen(temppath); + + strcat(endtemp++, "/"); + + for (i = 0, de = readdir(dirp); i < count; de = readdir(dirp)) { +#ifdef USE_STRUCT_DIRENT + namelen = strlen(de->d_name); +#else + namelen = de->d_namlen; +#endif + if (!do_match && (strcmp(de->d_name, ".") == 0 || + strcmp(de->d_name, "..") == 0)) + continue; + if (do_match && !match_string(regexppath, de->d_name)) + continue; + de->d_name[namelen] = '\0'; + if (flags == -1) { + /* + * We'll have to .... sigh.... stat() the file to get some add'tl + * info. + */ + strcpy(endtemp, de->d_name); + stat(temppath, &st);/* We assume it works. */ + } + encode_stat(&v->item[i], flags, de->d_name, &st); + i++; + } + closedir(dirp); +#endif /* OS2 */ + + /* Sort the names. */ + qsort((void *) v->item, count, sizeof v->item[0], + (flags == -1) ? parrcmp : pstrcmp); + return v; +} + +int remove_file (const char * path) +{ + path = check_valid_path(path, current_object, "remove_file", 1); + + if (path == 0) + return 0; + if (unlink(path) == -1) + return 0; + return 1; +} + +/* + * Check that it is an legal path. No '..' are allowed. + */ +int legal_path (const char * path) +{ + const char *p; + + if (path == NULL) + return 0; + if (path[0] == '/') + return 0; + /* + * disallowing # seems the easiest way to solve a bug involving loading + * files containing that character + */ + if (strchr(path, '#')) { + return 0; + } + p = path; + while (p) { /* Zak, 930530 - do better checking */ + if (p[0] == '.') { + if (p[1] == '\0') /* trailing `.' ok */ + break; + if (p[1] == '.') /* check for `..' or `../' */ + p++; + if (p[1] == '/' || p[1] == '\0') + return 0; /* check for `./', `..', or `../' */ + } + p = (char *)strstr(p, "/."); /* search next component */ + if (p) + p++; /* step over `/' */ + } +#if defined(WIN32) + /* + * I don't know what the proper define should be, just leaving an + * appropriate place for the right stuff to happen here - Wayfarer + */ + /* Could be a drive thingy for os2. */ + if (strchr(path, ':')) + return 0; +#endif + return 1; +} /* legal_path() */ + +/* + * There is an error in a specific file. Ask the MudOS driver to log the + * message somewhere. + */ +void smart_log (const char * error_file, int line, const char * what, int flag) +{ + char *buff; + svalue_t *mret; + extern int pragmas; + + buff = (char *) + DMALLOC(strlen(error_file) + strlen(what) + + ((pragmas & PRAGMA_ERROR_CONTEXT) ? 100 : 40), TAG_TEMPORARY, "smart_log: 1"); + + if (flag) + sprintf(buff, "/%s line %d: Warning: %s", error_file, line, what); + else + sprintf(buff, "/%s line %d: %s", error_file, line, what); + + if (pragmas & PRAGMA_ERROR_CONTEXT) { + char *ls = strrchr(buff, '\n'); + unsigned char *tmp; + if (ls) { + tmp = (unsigned char *)ls + 1; + while (*tmp && isspace(*tmp)) tmp++; + if (!*tmp) *ls = 0; + } + strcat(buff, show_error_context()); + } else strcat(buff, "\n"); + + push_malloced_string(add_slash(error_file)); + copy_and_push_string(buff); + mret = safe_apply_master_ob(APPLY_LOG_ERROR, 2); + if (!mret || mret == (svalue_t *)-1) { + debug_message("%s", buff); + } + FREE(buff); +} /* smart_log() */ + +/* + * Append string to file. Return 0 for failure, otherwise 1. + */ +int write_file (const char * file, const char * str, int flags) +{ + FILE *f; +#ifdef PACKAGE_COMPRESS + gzFile gf; +#endif +#ifdef WIN32 + char fmode[3]; +#endif + + file = check_valid_path(file, current_object, "write_file", 1); + if (!file) + return 0; +#ifdef PACKAGE_COMPRESS + if(flags & 2){ + gf = gzopen(file, (flags & 1)?"w":"a"); + if(!gf) + error("Wrong permissions for opening file /%s for %s.\n\"%s\"\n", + file, (flags & 1) ? "overwrite" : "append", port_strerror(errno)); + } else { +#endif +#ifdef WIN32 + fmode[0] = (flags & 1) ? 'w' : 'a'; + fmode[1] = 't'; + fmode[2] = '\0'; + f = fopen(file, fmode); +#else + f = fopen(file, (flags & 1) ? "w" : "a"); +#endif + if (f == 0) { + error("Wrong permissions for opening file /%s for %s.\n\"%s\"\n", + file, (flags & 1) ? "overwrite" : "append", port_strerror(errno)); + } +#ifdef PACKAGE_COMPRESS + } + if(flags & 2){ + gzwrite(gf, str, strlen(str)); + }else +#endif + fwrite(str, strlen(str), 1, f); +#ifdef PACKAGE_COMPRESS + if(flags & 2) + gzclose(gf); + else +#endif + fclose(f); + return 1; +} + +char *read_file(const char * file, int start, int len) { + struct stat st; +#ifndef PACKAGE_COMPRESS + FILE *f; +#else + gzFile f; +#endif + int chunk; + char *str, *p, *p2; + + if (len < 0) + return 0; + + file = check_valid_path(file, current_object, "read_file", 0); + + if (!file) + return 0; + + /* + * file doesn't exist, or is really a directory + */ + if (stat(file, &st) == -1 || (st.st_mode & S_IFDIR)) + return 0; +#ifndef PACKAGE_COMPRESS + f = fopen(file, FOPEN_READ); +#else + f = gzopen(file, "rb"); +#endif + if (f == 0) + return 0; + + if (start < 1) + start = 1; + if (len == 0) + len = 2*READ_FILE_MAX_SIZE; + + str = new_string(2*READ_FILE_MAX_SIZE, "read_file: str"); + if (st.st_size== 0) { + /* zero length file */ + str[0] = 0; +#ifndef PACKAGE_COMPRESS + fclose(f); +#else + gzclose(f); +#endif + str = extend_string(str, 0); /* fix string length */ + return str; + } + + do { +#ifndef PACKAGE_COMPRESS + chunk = fread(str, 1, 2*READ_FILE_MAX_SIZE, f); +#else + chunk = gzread(f, str, 2*READ_FILE_MAX_SIZE); +#endif + if (chunk < 1) + goto free_str; + p = str; + while (start > 1) { + /* skip newlines */ + p2 = (char *)memchr(p, '\n', 2*READ_FILE_MAX_SIZE+str-p); + if (p2) { + p = p2 + 1; + start--; + } else + break; + } + } while (start > 1); + + p2 = str; + while (1) { + char c; + + c = *p++; + if (p-str > chunk) { + if (chunk == 2*READ_FILE_MAX_SIZE) { + goto free_str; //file too big + } else + break; //reached the end + } + + if (p2-str > READ_FILE_MAX_SIZE) + goto free_str; //file too big + + if (c == '\0') { + FREE_MSTR(str); +#ifndef PACKAGE_COMPRESS + fclose(f); +#else + gzclose(f); +#endif + error("Attempted to read '\\0' into string!\n"); + } + if (c != '\r' || *p != '\n') { + *p2++ = c; + if (c == '\n' && --len == 0) + break; /* done */ + } + } + + *p2 = 0; + str = extend_string(str, p2 - str); /* fix string length */ + +#ifndef PACKAGE_COMPRESS + fclose(f); +#else + gzclose(f); +#endif + + return str; + + /* Error path: unwind allocated resources */ + +free_str: + FREE_MSTR(str); +#ifndef PACKAGE_COMPRESS + fclose(f); +#else + gzclose(f); +#endif + return 0; +} + +char *read_bytes (const char * file, int start, int len, int * rlen) +{ + struct stat st; + FILE *fptr; + char *str; + int size; + + if (len < 0) + return 0; + file = check_valid_path(file, current_object, + "read_bytes", 0); + if (!file) + return 0; + fptr = fopen(file, "rb"); + if (fptr == NULL) + return 0; + if (fstat(fileno(fptr), &st) == -1) + fatal("Could not stat an open file.\n"); + size = st.st_size; + if (start < 0) + start = size + start; + + if (len == 0) + len = size; + if (len > MAX_BYTE_TRANSFER) { + fclose(fptr); + error("Transfer exceeded maximum allowed number of bytes.\n"); + return 0; + } + if (start >= size) { + fclose(fptr); + return 0; + } + if ((start + len) > size) + len = (size - start); + + if ((size = fseek(fptr, start, 0)) < 0) { + fclose(fptr); + return 0; + } + + str = new_string(len, "read_bytes: str"); + + size = fread(str, 1, len, fptr); + + fclose(fptr); + + if (size <= 0) { + FREE_MSTR(str); + return 0; + } + /* + * The string has to end to '\0'!!! + */ + str[size] = '\0'; + + *rlen = size; + return str; +} + +int write_bytes (const char * file, int start, const char * str, int theLength) +{ + struct stat st; + int size; + FILE *fptr; + + file = check_valid_path(file, current_object, "write_bytes", 1); + + if (!file) + return 0; + if (theLength > MAX_BYTE_TRANSFER) + return 0; + /* Under system V, it isn't possible change existing data in a file + * opened for append, so it can't be opened for append. + * opening for r+ won't create the file if it doesn't exist. + * opening for w or w+ will truncate it if it does exist. So we + * have to check if it exists first. + */ + if (stat(file, &st) == -1) { + fptr = fopen(file, "wb"); + } else { + fptr = fopen(file, "r+b"); + } + if (fptr == NULL) { + return 0; + } + if (fstat(fileno(fptr), &st) == -1) + fatal("Could not stat an open file.\n"); + size = st.st_size; + if (start < 0) + start = size + start; + if (start < 0 || start > size) { + fclose(fptr); + return 0; + } + if ((size = fseek(fptr, start, 0)) < 0) { + fclose(fptr); + return 0; + } + size = fwrite(str, 1, theLength, fptr); + + fclose(fptr); + + if (size <= 0) { + return 0; + } + return 1; +} + +int file_size (const char * file) +{ + struct stat st; + long ret; +#ifdef WIN32 + char *t; + int needs_free = 0, len; + const char *p; +#endif + + file = check_valid_path(file, current_object, "file_size", 0); + if (!file) + return -1; + +#ifdef WIN32 + len = strlen(file); + p = file + len - 1; + if (*p == '/') { + needs_free = 1; + p = file; + t = new_string(len - 1, "file_size"); + memcpy(t, p, len - 1); + t[len-1] = 0; + file = t; + } +#endif + + if (stat(file, &st) == -1) + ret = -1; + else if (S_IFDIR & st.st_mode) + ret = -2; + else + ret = st.st_size; + +#ifdef WIN32 + if (needs_free) FREE_MSTR(file); +#endif + + return ret; +} + + +/* + * Check that a path to a file is valid for read or write. + * This is done by functions in the master object. + * The path is always treated as an absolute path, and is returned without + * a leading '/'. + * If the path was '/', then '.' is returned. + * Otherwise, the returned path is temporarily allocated by apply(), which + * means it will be deallocated at next apply(). + */ +const char *check_valid_path (const char * path, object_t * call_object, const char * const call_fun, int writeflg) +{ + svalue_t *v; + + if(!master_ob && !call_object){ + //early startup, ignore security + extern svalue_t apply_ret_value; + free_svalue(&apply_ret_value, "check_valid_path"); + apply_ret_value.type = T_STRING; + apply_ret_value.subtype = STRING_MALLOC; + path = apply_ret_value.u.string = string_copy(path, "check_valid_path"); + return path; + } + + if (call_object == 0 || call_object->flags & O_DESTRUCTED) + return 0; + +#ifdef WIN32 + { + char *p; + + for(p=path; *p; p++) if (*p == '\\') *p='/'; + } +#endif + + copy_and_push_string(path); + push_object(call_object); + push_constant_string(call_fun); + if (writeflg) + v = apply_master_ob(APPLY_VALID_WRITE, 3); + else + v = apply_master_ob(APPLY_VALID_READ, 3); + + if (v == (svalue_t *)-1) + v = 0; + + if (v && v->type == T_NUMBER && v->u.number == 0) return 0; + if (v && v->type == T_STRING) { + path = v->u.string; + } else { + extern svalue_t apply_ret_value; + + free_svalue(&apply_ret_value, "check_valid_path"); + apply_ret_value.type = T_STRING; + apply_ret_value.subtype = STRING_MALLOC; + path = apply_ret_value.u.string = string_copy(path, "check_valid_path"); + } + + if (path[0] == '/') + path++; + if (path[0] == '\0') + path = "."; + if (legal_path(path)) + return path; + + return 0; +} + +static int match_string (char * match, char * str) +{ + int i; + + again: + if (*str == '\0' && *match == '\0') + return 1; + switch (*match) { + case '?': + if (*str == '\0') + return 0; + str++; + match++; + goto again; + case '*': + match++; + if (*match == '\0') + return 1; + for (i = 0; str[i] != '\0'; i++) + if (match_string(match, str + i)) + return 1; + return 0; + case '\0': + return 0; + case '\\': + match++; + if (*match == '\0') + return 0; + /* Fall through ! */ + default: + if (*match == *str) { + match++; + str++; + goto again; + } + return 0; + } +} + +static struct stat to_stats, from_stats; + +static int copy (const char * from, const char * to) +{ + int ifd; + int ofd; + char buf[1024 * 8]; + int len; /* Number of bytes read into `buf'. */ + + if (!S_ISREG(from_stats.st_mode)) { + return 1; + } + if (unlink(to) && errno != ENOENT) { + return 1; + } + ifd = open(from, OPEN_READ); + if (ifd < 0) { + return errno; + } + ofd = open(to, OPEN_WRITE | O_CREAT | O_TRUNC, 0666); + if (ofd < 0) { + close(ifd); + return 1; + } +#ifdef HAS_FCHMOD + if (fchmod(ofd, from_stats.st_mode & 0777)) { + close(ifd); + close(ofd); + unlink(to); + return 1; + } +#endif + + while ((len = read(ifd, buf, sizeof(buf))) > 0) { + int wrote = 0; + char *bp = buf; + + do { + wrote = write(ofd, bp, len); + if (wrote < 0) { + close(ifd); + close(ofd); + unlink(to); + return 1; + } + bp += wrote; + len -= wrote; + } while (len > 0); + } + if (len < 0) { + close(ifd); + close(ofd); + unlink(to); + return 1; + } + if (close(ifd) < 0) { + close(ofd); + return 1; + } + if (close(ofd) < 0) { + return 1; + } +#ifdef FCHMOD_MISSING + if (chmod(to, from_stats.st_mode & 0777)) { + return 1; + } +#endif + + return 0; +} + +/* Move FROM onto TO. Handles cross-filesystem moves. + If TO is a directory, FROM must be also. + Return 0 if successful, 1 if an error occurred. */ + +#ifdef F_RENAME +static int do_move (const char * from, const char * to, int flag) +{ + if (lstat(from, &from_stats) != 0) { + error("/%s: lstat failed\n", from); + return 1; + } + if (lstat(to, &to_stats) == 0) { +#ifdef WIN32 + if (!strcmp(from, to)) +#else + if (from_stats.st_dev == to_stats.st_dev + && from_stats.st_ino == to_stats.st_ino) +#endif + { + error("`/%s' and `/%s' are the same file", from, to); + return 1; + } + if (S_ISDIR(to_stats.st_mode)) { + error("/%s: cannot overwrite directory", to); + return 1; + } +#ifdef WIN32 + unlink(to); +#endif + } else if (errno != ENOENT) { + error("/%s: unknown error\n", to); + return 1; + } +#ifdef SYSV + if ((flag == F_RENAME) && file_size(from) == -2) { + char cmd_buf[100]; + + sprintf(cmd_buf, "/usr/lib/mv_dir %s %s", from, to); + return system(cmd_buf); + } else +#endif /* SYSV */ + if ((flag == F_RENAME) && (rename(from, to) == 0)) + return 0; +#ifdef F_LINK + else if (flag == F_LINK) { +#ifdef WIN32 + error("link() not supported.\n"); +#else + if (link(from, to) == 0) + return 0; +#endif + } +#endif + + if (errno != EXDEV) { + if (flag == F_RENAME) + error("cannot move `/%s' to `/%s'\n", from, to); + else + error("cannot link `/%s' to `/%s'\n", from, to); + return 1; + } + /* rename failed on cross-filesystem link. Copy the file instead. */ + + if (flag == F_RENAME) { + if (copy(from, to)) + return 1; + if (unlink(from)) { + error("cannot remove `/%s'", from); + return 1; + } + } +#ifdef F_LINK + else if (flag == F_LINK) { + if (symlink(from, to) == 0) /* symbolic link */ + return 0; + } +#endif + return 0; +} +#endif + +void debug_perror (const char * what, const char * file) { + if (file) + debug_message("System Error: %s:%s:%s\n", what, file, port_strerror(errno)); + else + debug_message("System Error: %s:%s\n", what, port_strerror(errno)); +} + +/* + * do_rename is used by the efun rename. It is basically a combination + * of the unix system call rename and the unix command mv. + */ + +static svalue_t from_sv = { T_NUMBER }; +static svalue_t to_sv = { T_NUMBER }; + +#ifdef DEBUGMALLOC_EXTENSIONS +void mark_file_sv() { + mark_svalue(&from_sv); + mark_svalue(&to_sv); +} +#endif + +#ifdef F_RENAME +int do_rename (const char * fr, const char * t, int flag) +{ + const char *from; + const char *to; + char newfrom[MAX_FNAME_SIZE + MAX_PATH_LEN + 2]; + int flen; + extern svalue_t apply_ret_value; + + /* + * important that the same write access checks are done for link() as are + * done for rename(). Otherwise all kinds of security problems would + * arise (e.g. creating links to files in protected directories and then + * modifying the protected file by modifying the linked file). The idea + * is prevent linking to a file unless the person doing the linking has + * permission to move the file. + */ + from = check_valid_path(fr, current_object, "rename", 1); + if (!from) + return 1; + + assign_svalue(&from_sv, &apply_ret_value); + + to = check_valid_path(t, current_object, "rename", 1); + if (!to) + return 1; + + assign_svalue(&to_sv, &apply_ret_value); + if (!strlen(to) && !strcmp(t, "/")) { + to = "./"; + } + + /* Strip trailing slashes */ + flen = strlen(from); + if (flen > 1 && from[flen - 1] == '/') { + const char *p = from + flen - 2; + int n; + + while (*p == '/' && (p > from)) + p--; + n = p - from + 1; + memcpy(newfrom, from, n); + newfrom[n] = 0; + from = newfrom; + } + + if (file_size(to) == -2) { + /* Target is a directory; build full target filename. */ + const char *cp; + char newto[MAX_FNAME_SIZE + MAX_PATH_LEN + 2]; + + cp = strrchr(from, '/'); + if (cp) + cp++; + else + cp = from; + + sprintf(newto, "%s/%s", to, cp); + return do_move(from, newto, flag); + } else + return do_move(from, to, flag); +} +#endif /* F_RENAME */ + +int copy_file (const char * from, const char * to) +{ + char buf[128]; + int from_fd, to_fd; + int num_read, num_written; + char *write_ptr; + extern svalue_t apply_ret_value; + + from = check_valid_path(from, current_object, "move_file", 0); + assign_svalue(&from_sv, &apply_ret_value); + + to = check_valid_path(to, current_object, "move_file", 1); + assign_svalue(&to_sv, &apply_ret_value); + + if (from == 0) + return -1; + if (to == 0) + return -2; + + if (lstat(from, &from_stats) != 0) { + error("/%s: lstat failed\n", from); + return 1; + } + if (lstat(to, &to_stats) == 0) { +#ifdef WIN32 + if (!strcmp(from, to)) +#else + if (from_stats.st_dev == to_stats.st_dev + && from_stats.st_ino == to_stats.st_ino) +#endif + { + error("`/%s' and `/%s' are the same file", from, to); + return 1; + } + } else if (errno != ENOENT) { + error("/%s: unknown error\n", to); + return 1; + } + + from_fd = open(from, OPEN_READ); + if (from_fd < 0) + return -1; + + if (file_size(to) == -2) { + /* Target is a directory; build full target filename. */ + const char *cp; + char newto[MAX_FNAME_SIZE + MAX_PATH_LEN + 2]; + + cp = strrchr(from, '/'); + if (cp) + cp++; + else + cp = from; + + sprintf(newto, "%s/%s", to, cp); + close(from_fd); + return copy_file(from, newto); + } + to_fd = open(to, OPEN_WRITE | O_CREAT | O_TRUNC, 0666); + if (to_fd < 0) { + close(from_fd); + return -2; + } + while ((num_read = read(from_fd, buf, 128)) != 0) { + if (num_read < 0) { + debug_perror("copy_file: read", from); + close(from_fd); + close(to_fd); + return -3; + } + write_ptr = buf; + while (write_ptr != (buf + num_read)) { + num_written = write(to_fd, write_ptr, num_read); + if (num_written < 0) { + debug_perror("copy_file: write", to); + close(from_fd); + close(to_fd); + return -3; + } + write_ptr += num_written; + } + } + close(from_fd); + close(to_fd); + return 1; +} + +void dump_file_descriptors (outbuffer_t * out) +{ + int i; + dev_t dev; + struct stat stbuf; + + outbuf_add(out, "Fd Device Number Inode Mode Uid Gid Size\n"); + outbuf_add(out, "-- ------------- ----- ------ ----- ----- ----------\n"); + + for (i = 0; i < FD_SETSIZE; i++) { + /* bug in NeXT OS 2.1, st_mode == 0 for sockets */ + if (fstat(i, &stbuf) == -1) + continue; + +#if !defined(WIN32) + if (S_ISCHR(stbuf.st_mode) || S_ISBLK(stbuf.st_mode)) + dev = stbuf.st_rdev; + else +#endif + dev = stbuf.st_dev; + + outbuf_addv(out, "%2d", i); + outbuf_addv(out, "%13x", dev); + outbuf_addv(out, "%9d", stbuf.st_ino); + outbuf_add(out, " "); + + switch (stbuf.st_mode & S_IFMT) { + + case S_IFDIR: + outbuf_add(out, "d"); + break; + case S_IFCHR: + outbuf_add(out, "c"); + break; +#ifdef S_IFBLK + case S_IFBLK: + outbuf_add(out, "b"); + break; +#endif + case S_IFREG: + outbuf_add(out, "f"); + break; +#ifdef S_IFIFO + case S_IFIFO: + outbuf_add(out, "p"); + break; +#endif +#ifdef S_IFLNK + case S_IFLNK: + outbuf_add(out, "l"); + break; +#endif +#ifdef S_IFSOCK + case S_IFSOCK: + outbuf_add(out, "s"); + break; +#endif + default: + outbuf_add(out, "?"); + break; + } + + outbuf_addv(out, "%5o", stbuf.st_mode & ~S_IFMT); + outbuf_addv(out, "%7d", stbuf.st_uid); + outbuf_addv(out, "%7d", stbuf.st_gid); + outbuf_addv(out, "%12d", stbuf.st_size); + outbuf_add(out, "\n"); + } +} diff --git a/fluffos-2.23-ds03/file.h b/fluffos-2.23-ds03/file.h new file mode 100644 index 0000000..a79482a --- /dev/null +++ b/fluffos-2.23-ds03/file.h @@ -0,0 +1,52 @@ +#ifndef FILE_H +#define FILE_H + +#include "lpc_incl.h" +#include "file_incl.h" + +/* + * Credits for some of the code below goes to Free Software Foundation + * Copyright (C) 1990 Free Software Foundation, Inc. + * See the GNU General Public License for more details. + */ +#ifndef S_ISDIR +#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) +#endif + +#ifndef S_ISREG +#define S_ISREG(m) (((m)&S_IFMT) == S_IFREG) +#endif + +#ifndef S_ISCHR +#define S_ISCHR(m) (((m)&S_IFMT) == S_IFCHR) +#endif + +#ifndef S_ISBLK +#define S_ISBLK(m) (((m)&S_IFMT) == S_IFBLK) +#endif + +/* + * file.c + */ + +int legal_path (const char *); +const char *check_valid_path (const char *, object_t *, const char * const, int); +void smart_log (const char *, int, const char *, int); +void dump_file_descriptors (outbuffer_t *); + +char *read_file (const char *, int, int); +char *read_bytes (const char *, int, int, int *); +int write_file (const char *, const char *, int); +int write_bytes (const char *, int, const char *, int); +array_t *get_dir (const char *, int); +int tail (char *); +int file_size (const char *); +int copy_file (const char *, const char *); +int do_rename (const char *, const char *, int); +int remove_file (const char *); + +#ifdef DEBUGMALLOC_EXTENSIONS +void mark_file_sv (void); +#endif + +#endif diff --git a/fluffos-2.23-ds03/file_incl.h b/fluffos-2.23-ds03/file_incl.h new file mode 100644 index 0000000..207962a --- /dev/null +++ b/fluffos-2.23-ds03/file_incl.h @@ -0,0 +1,50 @@ +#ifndef FILE_INCL_H +#define FILE_INCL_H + +#ifdef INCL_SYS_STAT_H +# include +#endif +#ifdef INCL_SYS_DIR_H +# include +#endif + +#ifndef linux +#ifdef INCL_SYS_DIRENT_H +# include +#endif +#endif + +#ifdef INCL_DIRENT_H +# include +#endif +#ifdef INCL_SYS_FILIO_H +# include +#endif +#ifdef INCL_SYS_SOCKIO_H +# include +#endif +#ifdef INCL_SYS_MKDEV_H +# include +#endif + +#ifdef INCL_SYS_RESOURCE_H +# include +#endif +#ifdef INCL_SYS_RUSAGE_H +# include +#endif +#ifdef INCL_CRYPT_H +# include +#endif + +#ifdef WIN32 +# include +# include + +# define OS_mkdir(x, y) mkdir(x) +# define lstat(x, y) stat(x, y) +#else +# define OS_mkdir(x, y) mkdir(x, y) +#endif + +#endif diff --git a/fluffos-2.23-ds03/fliconv.c b/fluffos-2.23-ds03/fliconv.c new file mode 100644 index 0000000..77c6864 --- /dev/null +++ b/fluffos-2.23-ds03/fliconv.c @@ -0,0 +1,210 @@ +#include "fliconv.h" +#include +#include "std.h" +#include "lpc_incl.h" +#include "comm.h" + +#ifdef USE_ICONV + +struct translation *head; + +static struct translation *find_translator(const char *encoding){ + struct translation *cur = head; + while(cur){ + if(!strcmp(cur->name, encoding)) + break; + cur = cur->next; + } + return cur; +} + + +struct translation *get_translator(const char *encoding){ + struct translation *ret = find_translator(encoding); + if(ret) + return ret; + ret = (struct translation *)MALLOC(sizeof(struct translation)); + char *name = (char *)MALLOC(strlen(encoding)+18+1); + strcpy(name, encoding); +#ifdef linux + strcat(name, "//TRANSLIT//IGNORE"); +#endif + ret->name = name; + ret->incoming = iconv_open("UTF-8", encoding); + ret->outgoing = iconv_open(name, "UTF-8"); + + ret->next = 0; + if(ret->incoming == (iconv_t)-1 || ret->outgoing == (iconv_t)-1){ + FREE(name); + FREE(ret); + return 0; + } + name[strlen(encoding)] = 0; + if(!head) + head = ret; + else { + struct translation *cur = head; + while(cur->next) + cur = cur->next; + cur->next = ret; + } + return ret; +} + +char *translate(iconv_t tr, const char *mes, int inlen, int *outlen){ + size_t len = inlen; + size_t len2; + unsigned char *tmp = (unsigned char *)mes; + static char *res = 0; + static size_t reslen = 0; + char *tmp2; + + if(!res){ + res = (char *)MALLOC(1); + reslen = 1; + } + + tmp2 = res; + len2 = reslen; + + while(len){ + iconv(tr, (char **)&tmp, &len, &tmp2, &len2); +#ifdef PACKAGE_DWLIB + if(len > 1 && tmp[0] == 0xff && tmp[1] == 0xf9){ + len -=2; + tmp +=2; +#else + if(0){ +#endif + } else { + + if(E2BIG == errno){ + errno = 0; + tmp = (unsigned char *)mes; + len = strlen(mes)+1; + FREE(res); + reslen *= 2; + res = (char *)MALLOC(reslen); + tmp2 = res; + len2 = reslen; + continue; + } + tmp2[0] = 0; + *outlen = reslen - len2; + return res; + } + + } + *outlen = reslen - len2; + return res; +} + +#else +char *translate(iconv_t tr, const char *mes, int inlen, int *outlen){ + *outlen = inlen; + return (char *)mes; +} +#endif + + + +char *translate_easy(iconv_t tr, char *mes){ + int dummy; + char *res = translate(tr, mes, strlen(mes)+1, &dummy); + return res; +} + + + +#ifdef F_SET_ENCODING +void f_set_encoding(){ + if(current_object->interactive){ + struct translation *newt = get_translator((char *)sp->u.string); + if(newt){ + current_object->interactive->trans = newt; + return; + } + } + pop_stack(); + push_number(0); +} +#endif + +#ifdef F_TO_UTF8 +void f_to_utf8(){ + struct translation *newt = get_translator((char *)sp->u.string); + pop_stack(); + if(!newt) + error("unknown encoding"); + char *text = (char *)sp->u.string; + char *translated = translate_easy(newt->incoming, text); + pop_stack(); + copy_and_push_string(translated); +} +#endif + +#ifdef F_UTF8_TO +void f_utf8_to(){ + struct translation *newt = get_translator((char *)sp->u.string); + pop_stack(); + if(!newt) + error("unknown encoding"); + char *text = (char *)sp->u.string; + char *translated = translate_easy(newt->outgoing, text); + pop_stack(); + copy_and_push_string(translated); +} +#endif + +#ifdef F_STR_TO_ARR +void f_str_to_arr(){ + static struct translation *newt = 0; + if(!newt){ + newt = get_translator("UTF-32"); + translate_easy(newt->outgoing, " "); + } + int len; + int *trans = (int *)translate(newt->outgoing, sp->u.string, SVALUE_STRLEN(sp)+1, &len); + len/=4; + array_t *arr = allocate_array(len); + while(len--) + arr->item[len].u.number = trans[len]; + free_svalue(sp, "str_to_arr"); + put_array(arr); +} + +#endif + +#ifdef F_ARR_TO_STR +void f_arr_to_str(){ + static struct translation *newt = 0; + if(!newt){ + newt = get_translator("UTF-32"); + } + int len = sp->u.arr->size; + int *in = (int *)MALLOC(sizeof(int)*(len+1)); + char *trans; + in[len] = 0; + while(len--) + in[len] = sp->u.arr->item[len].u.number; + + trans = translate(newt->incoming, (char *)in, (sp->u.arr->size+1)*4, &len); + FREE(in); + pop_stack(); + copy_and_push_string(trans); +} + +#endif + +#ifdef F_STRWIDTH +void f_strwidth(){ + int len = SVALUE_STRLEN(sp); + int width = 0; + int i; + for(i=0; iu.string[i]) & 0xc0) == 0x80); + pop_stack(); + push_number(width); +} + +#endif diff --git a/fluffos-2.23-ds03/fliconv.h b/fluffos-2.23-ds03/fliconv.h new file mode 100644 index 0000000..fe07906 --- /dev/null +++ b/fluffos-2.23-ds03/fliconv.h @@ -0,0 +1,19 @@ +#ifndef FLUFFOS_ICONV_H +#define FLUFFOS_ICONV_H +#include "std.h" +#ifdef USE_ICONV +#include +#else +typedef void *iconv_t; +#endif +struct translation{ + char *name; + iconv_t incoming; + iconv_t outgoing; + struct translation *next; +}; + +char *translate(iconv_t tr, const char *mes, int inlen, int *outlen); +char *translate_easy(iconv_t tr, char *mes); +struct translation *get_translator(const char *encoding); +#endif diff --git a/fluffos-2.23-ds03/fluffos.d b/fluffos-2.23-ds03/fluffos.d new file mode 100644 index 0000000..e8c42c3 --- /dev/null +++ b/fluffos-2.23-ds03/fluffos.d @@ -0,0 +1,6 @@ +provider fluffos { + probe lpc__entry(string, string, string); + probe lpc__return(string, string, string); + probe error(string); +}; + diff --git a/fluffos-2.23-ds03/func_spec.c b/fluffos-2.23-ds03/func_spec.c new file mode 100644 index 0000000..d401b85 --- /dev/null +++ b/fluffos-2.23-ds03/func_spec.c @@ -0,0 +1,411 @@ +#include "spec.h" + +#include "op_spec.c" +/* + * This file specifies types and arguments for efuns. + * An argument can have two different types with the syntax 'type1 | type2'. + * An argument is marked as optional if it also takes the type 'void'. + * + * Comment out the efuns that you do not want. Be careful not to comment + * out something that you need. + * + * The order in which the efuns are listed here is the order in which opcode + * #'s will be assigned. It is in your interest to move the least frequently + * used efuns to the bottom of this file (and the most frequently used + * ones to the top). The opcprof() efun could help you find out which + * efuns are most often and least often used. The reason for ordering + * the efuns is that only the first 255 efuns are represented using + * a single byte. Any additional efuns require two bytes. + */ + +#ifdef NO_BUFFER_TYPE +#define OR_BUFFER +#else +#define OR_BUFFER | buffer +#endif + +/* These next few efuns are used internally; do not remove them. + * The leading _ is used to keep track of which efuns should exist, + * but not be added to the identifier lookup table. + * These names MUST exist, and may either be real efuns, or aliases + * for another efun. For example, one could remove clone_object + * above, and change the internal one to: + * + * object _new(string, ...); + */ +/* used by X->f() */ +unknown _call_other(object | string | object *, string | mixed *,...); +/* used by (*f)(...) */ +mixed _evaluate(mixed, ...); +/* default argument for some efuns */ +object _this_object(); +/* used for implicit float/int conversions */ +int _to_int(string | float | int OR_BUFFER); +float _to_float(string | float | int); +/* used by new() */ +object _new(string, ...); + +unknown call_other _call_other(object | string | object *, string | mixed *,...); +mixed evaluate _evaluate(mixed, ...); +#ifdef COMPAT_32 +mixed funcall _evaluate(mixed, ...); +#endif +object this_object _this_object(); +int to_int _to_int(string | float | int OR_BUFFER); +float to_float _to_float(string | float | int); +object clone_object _new(string, ...); + +function bind(function, object); +object this_player(int default: 0); +object this_interactive this_player( int default: 1); +object this_user this_player( int default: 0); +mixed previous_object(int default: 0); +object *all_previous_objects previous_object(int default: -1); +mixed *call_stack(int default: 0); +int sizeof(mixed); +int strlen sizeof(string); +#ifdef USE_ICONV +int strwidth(string); +#else +int strwidth sizeof(string); +#endif +void destruct(object default: F__THIS_OBJECT); +string file_name(object default: F__THIS_OBJECT); +string capitalize(string); +string *explode(string, string); +mixed implode(mixed *, string | function, void | mixed); +#ifdef CALLOUT_HANDLES +int call_out(string | function, int,...); +#else +void call_out(string | function, int,...); +#endif +int member_array(mixed, string | mixed *, void | int, void | int); +int input_to(string | function,...); +int random(int); +void defer(function); + +#ifndef NO_ENVIRONMENT +object environment(void | object); +object *all_inventory(object default: F__THIS_OBJECT); +object *deep_inventory(object | object * | function, void|function default: F__THIS_OBJECT); +object first_inventory(object|string default: F__THIS_OBJECT); +object next_inventory(object default: F__THIS_OBJECT); +void say(string, void | object | object *); +void tell_room(object | string, string | object | int | float, void | object | object *); +object present(object | string, void | object); +void move_object(object | string); +#endif + +#ifndef NO_ADD_ACTION +void add_action(string | function, string | string *, void | int); +string query_verb(); +int command(string); +int remove_action(string, string); +int living(object default: F__THIS_OBJECT); +mixed *commands(); +void disable_commands(); +void enable_commands(); +void set_living_name(string); +object *livings(); +object find_living(string); +object find_player(string); +void notify_fail(string | function); +#else +void set_this_player(object | int); +void set_this_user set_this_player(object | int); +#endif + +string lower_case(string); +string replace_string(string, string, string,...); +int restore_object(string, void | int); +mixed save_object(string | int | void, void | int); +string save_variable(mixed); +mixed restore_variable(string); +object *users(); +mixed *get_dir(string, int default: 0); +int strsrch(string, string | int, int default: 0); +#ifdef COMPAT_32 +int strstr strsrch(string, string | int, int default: 0); +#endif + +/* communication functions */ + +void write(mixed); +void tell_object(object, string); +void shout(string); +void receive(string OR_BUFFER); +void message(mixed, mixed, string | string * | object | object *, + void | object | object *); + +/* the find_* functions */ + + object find_object(string, int default: 0); + object load_object find_object(string, int default: 1); +#ifdef CALLOUT_HANDLES + int find_call_out(int|string); +#else + int find_call_out(string); +#endif + +/* mapping functions */ + + mapping allocate_mapping(int | mixed *, void | mixed); + mixed *values(mapping); + mixed *keys(mapping); +#ifdef COMPAT_32 + mapping map_delete(mapping, mixed); + mapping m_delete map_delete(mapping, mixed); + mixed *m_values values(mapping); + mixed *m_indices keys(mapping); +#else + void map_delete(mapping, mixed); +#endif + + mixed match_path(mapping, string); + +/* all the *p() type functions */ + + int clonep(mixed default: F__THIS_OBJECT); + int intp(mixed); + int undefinedp(mixed); + int nullp undefinedp(mixed); + int floatp(mixed); + int stringp(mixed); + int virtualp(object default: F__THIS_OBJECT); + int functionp(mixed); +#ifdef COMPAT_32 + int closurep functionp(mixed); +#endif + int pointerp(mixed); + int arrayp pointerp(mixed); + int objectp(mixed); + int classp(mixed); + string typeof(mixed); + +#ifndef NO_BUFFER_TYPE + int bufferp(mixed); + buffer allocate_buffer(int); +#endif + + int inherits(string, object default: F__THIS_OBJECT); + void replace_program(string); + + mixed regexp(string | string *, string, void | int); + mixed *reg_assoc(string, string *, mixed *, mixed | void); + mixed *allocate(int, void | mixed); + mixed *call_out_info(); + +/* 32-bit cyclic redundancy code - see crc32.c and crctab.h */ + int crc32(string OR_BUFFER); + +/* commands operating on files */ + +#ifndef NO_BUFFER_TYPE + mixed read_buffer(string | buffer, void | int, void | int); + int write_buffer(string | buffer, int, string | buffer | int); +#endif + int write_file(string, string, int default:0); + int rename(string, string); + int write_bytes(string, int, string); + + int file_size(string); + string read_bytes(string, void | int, void | int); + string read_file(string, void | int, void | int); + int cp(string, string); + + int link(string, string); + int mkdir(string); + int rm(string); + int rmdir(string); + +/* the bit string functions */ + + string clear_bit(string, int); + int test_bit(string, int); + string set_bit(string, int); + int next_bit(string, int); + + string crypt(string, string | int); + string oldcrypt(string, string | int); + + string ctime(int|void); + int exec(object, object); + mixed *localtime(int); + string function_exists(string, void | object, void | int); + + object *objects(void | string | function); + string query_host_name(); + int query_idle(object); + string query_ip_name(void | object); + string query_ip_number(void | object); +#ifndef NO_SNOOP + object snoop(object, void | object); + object query_snoop(object); + object query_snooping(object); +#endif +#ifdef CALLOUT_HANDLES + int remove_call_out(int | void | string); +#else + int remove_call_out(void | string); +#endif + void set_heart_beat(int); + int query_heart_beat(object default:F__THIS_OBJECT); + void set_hide(int); + +#ifndef NO_RESETS + void set_reset(object, void | int); +#endif + +#ifndef NO_SHADOWS + object shadow(object, int default: 1); + object query_shadowing(object); +#endif + mixed *sort_array(mixed *, int | string | function, ...); + void throw(mixed); + int time(); + mixed *unique_array(mixed *, string | function, void | mixed); + mapping unique_mapping(mixed *, string | function, ...); + string *deep_inherit_list(object default:F__THIS_OBJECT); + string *shallow_inherit_list(object default:F__THIS_OBJECT); +#ifdef COMPAT_32 + string *inherit_list deep_inherit_list(object default:F__THIS_OBJECT); +#else + string *inherit_list shallow_inherit_list(object default:F__THIS_OBJECT); +#endif + void printf(string,...); + string sprintf(string,...); + int mapp(mixed); + mixed *stat(string, int default: 0); + +/* + * Object properties + */ + int interactive(object default:F__THIS_OBJECT); + int has_mxp(object default:F__THIS_OBJECT); + int has_zmp(object default:F__THIS_OBJECT); + void send_zmp(string, string *); + int has_gmcp(object default:F__THIS_OBJECT); + void send_gmcp(string); + string in_edit(object default:F__THIS_OBJECT); + int in_input(object default:F__THIS_OBJECT); + int userp(object); +#ifdef COMPAT_32 + int query_once_interactive userp(object); +#endif + +#ifndef NO_WIZARDS + void enable_wizard(); + void disable_wizard(); + int wizardp(object); +#endif + + object master(); + +/* + * various mudlib statistics + */ + int memory_info(object | void); + mixed get_config(int); + +#ifdef PRIVS +/* privledge functions */ + string query_privs(object default:F__THIS_OBJECT); + void set_privs(object, int | string); +#endif /* PRIVS */ + + int get_char(string | function,...); + object *children(string); + + void reload_object(object); + + void error(string); +#ifdef COMPAT_32 + void raise_error error(string); +#endif + int uptime(); + int strcmp(string, string); + +#ifndef WIN32 +#if (defined(RUSAGE) || defined(GET_PROCESS_STATS) || defined(TIMES)) + mapping rusage(); +#endif /* RUSAGE */ +#endif + + void flush_messages(void | object); + +#ifdef OLD_ED + void ed(string | void, string | int | void, string | int | void, int | void, int | void); +#else + string ed_start(string | void, int | void, int | void); + string ed_cmd(string); + int query_ed_mode(); +#endif + +#ifdef CACHE_STATS + string cache_stats(); +#endif + + mixed filter(string | mixed * | mapping, string | function, ...); + mixed filter_array filter(mixed *, string | function, ...); + mapping filter_mapping filter(mapping, string | function, ...); + + mixed map(string | mapping | mixed *, string | function, ...); + mapping map_mapping map(mapping, string | function, ...); + mixed *map_array map(mixed *, string | function, ...); +/* + * parser 'magic' functions, turned into efuns + */ + string malloc_status(); + string mud_status(int default: 0); + void dumpallobj(string | void); + + string dump_file_descriptors(); + string query_load_average(); + +#ifndef NO_LIGHT +/* set_light should die a dark death */ + int set_light(int); +#endif + + string origin(); + +/* the infrequently used functions */ + + int reclaim_objects(); + + int set_eval_limit(int); + int reset_eval_cost set_eval_limit(int default: 0); + int eval_cost set_eval_limit(int default: -1); + int max_eval_cost set_eval_limit(int default: 1); +#ifdef COMPAT_32 + int get_eval_cost set_eval_limit(int default: -1); +#endif + +#ifdef DEBUG_MACRO + void set_debug_level(int|string); + mapping debug_levels(); + void clear_debug_level(string); +#endif + +#if defined(OPCPROF) || defined(OPCPROF_2D) + void opcprof(string | void); +#endif + +#ifdef PROFILE_FUNCTIONS + mapping *function_profile(object default:F__THIS_OBJECT); +#endif + + int resolve(string, string|function); +#ifdef USE_ICONV + int set_encoding(string); + string to_utf8(string, string); + string utf8_to(string, string); + int *str_to_arr(string); + string arr_to_str(int *); +#endif + void act_mxp(); + void request_term_type(); + void start_request_term_type(); + void request_term_size(void | int); +/* shutdown is at the end because it is only called once per boot cycle :) */ + void shutdown(void | int); diff --git a/fluffos-2.23-ds03/function.c b/fluffos-2.23-ds03/function.c new file mode 100644 index 0000000..4fecc1b --- /dev/null +++ b/fluffos-2.23-ds03/function.c @@ -0,0 +1,346 @@ +#define SUPPRESS_COMPILER_INLINES +#include "std.h" +#include "lpc_incl.h" +#include "eoperators.h" +#include "compiler.h" +#include "replace_program.h" + +INLINE void +dealloc_funp (funptr_t * fp) +{ + program_t *prog = 0; + + switch (fp->hdr.type) { + case FP_LOCAL | FP_NOT_BINDABLE: + if (fp->hdr.owner) + prog = fp->hdr.owner->prog; + break; + case FP_FUNCTIONAL: + case FP_FUNCTIONAL | FP_NOT_BINDABLE: + prog = fp->f.functional.prog; + break; + } + + if (fp->hdr.owner) + free_object(&fp->hdr.owner, "free_funp"); + if (fp->hdr.args) + free_array(fp->hdr.args); + + if (prog) { + prog->func_ref--; + debug(d_flag, ("subtr func ref /%s: now %i\n", + prog->filename, prog->func_ref)); + if (!prog->func_ref && !prog->ref) + deallocate_program(prog); + } + + FREE(fp); +} + +INLINE void +free_funp (funptr_t * fp) +{ + fp->hdr.ref--; + if (fp->hdr.ref > 0) { + return; + } + dealloc_funp(fp); +} + +INLINE void +push_refed_funp (funptr_t * fp) +{ + STACK_INC; + sp->type = T_FUNCTION; + sp->u.fp = fp; +} + +INLINE void +push_funp (funptr_t * fp) +{ + STACK_INC; + sp->type = T_FUNCTION; + sp->u.fp = fp; + fp->hdr.ref++; +} + +/* num_arg args are on the stack, and the args from the array vec should be + * put in front of them. This is so that the order of arguments is logical. + * + * evaluate( (: f, a :), b) -> f(a,b) and not f(b, a) which would happen + * if we simply pushed the args from vec at this point. (Note that the + * old function pointers are broken in this regard) + */ +int merge_arg_lists (int num_arg, array_t * arr, int start) { + int num_arr_arg = arr->size - start; + svalue_t *sptr; + + if (num_arr_arg) { + CHECK_STACK_OVERFLOW(num_arr_arg); + sptr = (sp += num_arr_arg); + if (num_arg) { + /* We need to do some stack movement so that the order + of arguments is logical */ + while (num_arg--) { + *sptr = *(sptr - num_arr_arg); + sptr--; + } + } + num_arg = arr->size; + while (--num_arg >= start) + assign_svalue_no_free(sptr--, &arr->item[num_arg]); + /* could just return num_arr_arg if num_arg is 0 but .... -Sym */ + return (sp - sptr); + } + return num_arg; +} + +INLINE funptr_t * +make_efun_funp (int opcode, svalue_t * args) +{ + funptr_t *fp; + + fp = (funptr_t *)DXALLOC(sizeof(funptr_t), + TAG_FUNP, "make_efun_funp"); + fp->hdr.owner = current_object; + add_ref( current_object, "make_efun_funp" ); + fp->hdr.type = FP_EFUN; + + fp->f.efun.index = opcode; + + if (args->type == T_ARRAY) { + fp->hdr.args = args->u.arr; + args->u.arr->ref++; + } else + fp->hdr.args = 0; + + fp->hdr.ref = 1; + return fp; +} + +INLINE funptr_t * +make_lfun_funp (int index, svalue_t * args) +{ + funptr_t *fp; + int newindex; + + if (replace_program_pending(current_object)) + error("cannot bind an lfun fp to an object with a pending replace_program()\n"); + + fp = (funptr_t *)DXALLOC(sizeof(funptr_hdr_t) + sizeof(local_ptr_t), + TAG_FUNP, "make_lfun_funp"); + fp->hdr.owner = current_object; + add_ref( current_object, "make_lfun_funp" ); + fp->hdr.type = FP_LOCAL | FP_NOT_BINDABLE; + + fp->hdr.owner->prog->func_ref++; + debug(d_flag, ("add func ref /%s: now %i\n", + fp->hdr.owner->prog->filename, + fp->hdr.owner->prog->func_ref)); + + newindex = index + function_index_offset; + if (current_object->prog->function_flags[newindex] & FUNC_ALIAS) + newindex = current_object->prog->function_flags[newindex] & ~FUNC_ALIAS; + fp->f.local.index = newindex; + + if (args->type == T_ARRAY) { + fp->hdr.args = args->u.arr; + args->u.arr->ref++; + } else + fp->hdr.args = 0; + + fp->hdr.ref = 1; + return fp; +} + +INLINE funptr_t * +make_simul_funp (int index, svalue_t * args) +{ + funptr_t *fp; + + fp = (funptr_t *)DXALLOC(sizeof(funptr_hdr_t) + sizeof(simul_ptr_t), + TAG_FUNP, "make_simul_funp"); + fp->hdr.owner = current_object; + add_ref( current_object, "make_simul_funp" ); + fp->hdr.type = FP_SIMUL; + + fp->f.simul.index = index; + + if (args->type == T_ARRAY) { + fp->hdr.args = args->u.arr; + args->u.arr->ref++; + } else + fp->hdr.args = 0; + + fp->hdr.ref = 1; + return fp; +} + +INLINE funptr_t * +make_functional_funp (short num_arg, short num_local, short len, svalue_t * args, int flag) +{ + funptr_t *fp; + + if (replace_program_pending(current_object)) + error("cannot bind a functional to an object with a pending replace_program()\n"); + + fp = (funptr_t *)DXALLOC(sizeof(funptr_hdr_t) + sizeof(functional_t), + TAG_FUNP, "make_functional_funp"); + fp->hdr.owner = current_object; + add_ref( current_object, "make_functional_funp" ); + fp->hdr.type = FP_FUNCTIONAL + flag; + + current_prog->func_ref++; + debug(d_flag, ("add func ref /%s: now %i\n", + current_prog->filename, + current_prog->func_ref)); + + fp->f.functional.prog = current_prog; + fp->f.functional.offset = pc - current_prog->program; + fp->f.functional.num_arg = num_arg; + fp->f.functional.num_local = num_local; + fp->f.functional.fio = function_index_offset; + fp->f.functional.vio = variable_index_offset; + pc += len; + + if (args && args->type == T_ARRAY) { + fp->hdr.args = args->u.arr; + args->u.arr->ref++; + fp->f.functional.num_arg += args->u.arr->size; + } else + fp->hdr.args = 0; + + fp->hdr.ref = 1; + return fp; +} + +typedef void (*func_t) (void); +extern func_t efun_table[]; + +svalue_t * +call_function_pointer (funptr_t * funp, int num_arg) +{ + static func_t *oefun_table = efun_table - BASE; + array_t *v; + int extfr = 1; + + if (!funp->hdr.owner || (funp->hdr.owner->flags & O_DESTRUCTED)) + error("Owner (/%s) of function pointer is destructed.\n", + (funp->hdr.owner ? funp->hdr.owner->obname : "(null)")); + setup_fake_frame(funp); + if ((v=funp->hdr.args)) { + check_for_destr(v); + num_arg = merge_arg_lists(num_arg, v, 0); + } + + switch (funp->hdr.type) { + case FP_SIMUL: + call_simul_efun(funp->f.simul.index, num_arg); + break; + case FP_EFUN: + { + int i, def; + fp = sp - num_arg + 1; + + i = funp->f.efun.index; + if (num_arg == instrs[i].min_arg - 1 && + ((def = instrs[i].Default) != DEFAULT_NONE)) { + if (def == DEFAULT_THIS_OBJECT) { + push_object(current_object); + } else { + push_number(def); + } + num_arg++; + } else + if (num_arg < instrs[i].min_arg) { + error("Too few arguments to efun %s in efun pointer.\n", query_instr_name(i)); + } else if (num_arg > instrs[i].max_arg && instrs[i].max_arg != -1) { + error("Too many arguments to efun %s in efun pointer.\n", query_instr_name(i)); + } + /* possibly we should add TRACE, OPC, etc here; + also on eval_cost here, which is ok for just 1 efun */ + { + int j, n = num_arg; + st_num_arg = num_arg; + + if (n >= 4 || instrs[i].max_arg == -1) + n = instrs[i].min_arg; + + for (j = 0; j < n; j++) { + CHECK_TYPES(sp - num_arg + j + 1, instrs[i].type[j], j + 1, i); + } + (*oefun_table[i])(); + + free_svalue(&apply_ret_value, "call_function_pointer"); + if (instrs[i].ret_type == TYPE_NOVALUE) + apply_ret_value = const0; + else + apply_ret_value = *sp--; + remove_fake_frame(); + return &apply_ret_value; + } + } + case FP_LOCAL | FP_NOT_BINDABLE: { + function_t *func; + + fp = sp - num_arg + 1; + + if (current_object->prog->function_flags[funp->f.local.index] & (FUNC_PROTOTYPE|FUNC_UNDEFINED)) + error("Undefined lfun pointer called: %s\n", function_name(current_object->prog, funp->f.local.index)); + push_control_stack(FRAME_FUNCTION); + current_prog = funp->hdr.owner->prog; + + caller_type = ORIGIN_LOCAL; + + csp->num_local_variables = num_arg; + func = setup_new_frame(funp->f.local.index); + + call_program(current_prog, func->address); + break; + } + case FP_FUNCTIONAL: + case FP_FUNCTIONAL | FP_NOT_BINDABLE: { + + fp = sp - num_arg + 1; + push_control_stack(FRAME_FUNP); + current_prog = funp->f.functional.prog; + csp->fr.funp = funp; + + caller_type = ORIGIN_FUNCTIONAL; + + setup_variables(num_arg, funp->f.functional.num_local, + funp->f.functional.num_arg); + + function_index_offset = funp->f.functional.fio; + variable_index_offset = funp->f.functional.vio; + call_program(funp->f.functional.prog, funp->f.functional.offset); + break; + } + default: + error("Unsupported function pointer type.\n"); + } + free_svalue(&apply_ret_value, "call_function_pointer"); + apply_ret_value = *sp--; + remove_fake_frame(); + return &apply_ret_value; +} + +svalue_t * +safe_call_function_pointer (funptr_t * funp, int num_arg) +{ + error_context_t econ; + svalue_t *ret; + + if (!save_context(&econ)) + return 0; + if (!SETJMP(econ.context)) { + ret = call_function_pointer(funp, num_arg); + } else { + restore_context(&econ); + /* condition was restored to where it was when we came in */ + pop_n_elems(num_arg); + ret = 0; + } + pop_context(&econ); + return ret; +} diff --git a/fluffos-2.23-ds03/function.h b/fluffos-2.23-ds03/function.h new file mode 100644 index 0000000..c645b9e --- /dev/null +++ b/fluffos-2.23-ds03/function.h @@ -0,0 +1,67 @@ +#ifndef FUNCTION_H +#define FUNCTION_H + +/* It is usually better to include "lpc_incl.h" instead of including this + directly */ + +/* FP_LOCAL */ +typedef struct { + short index; +} local_ptr_t; + +/* FP_SIMUL */ +typedef local_ptr_t simul_ptr_t; + +/* FP_EFUN */ +typedef local_ptr_t efun_ptr_t; + +/* FP_FUNCTIONAL */ +typedef struct { + /* these two must come first */ + unsigned char num_arg; + unsigned char num_local; + short fio; + struct program_s *prog; + int offset; + short vio; + char lpccode[80]; +} functional_t; + +/* common header */ +typedef struct { + unsigned short ref; + short type; /* FP_* is used */ +#ifdef DEBUG + int extra_ref; +#endif + struct object_s *owner; + struct array_s *args; +} funptr_hdr_t; + +typedef struct funptr_s { + funptr_hdr_t hdr; + union { + efun_ptr_t efun; + local_ptr_t local; + simul_ptr_t simul; + functional_t functional; + } f; +} funptr_t; + +union string_or_func { + funptr_t *f; + char *s; +}; + +void dealloc_funp (funptr_t *); +void push_refed_funp (funptr_t *); +INLINE void push_funp (funptr_t *); +INLINE void free_funp (funptr_t *); +int merge_arg_lists (int, struct array_s *, int); +INLINE funptr_t *make_efun_funp (int, struct svalue_s *); +INLINE funptr_t *make_lfun_funp (int, struct svalue_s *); +INLINE funptr_t *make_simul_funp (int, struct svalue_s *); +INLINE funptr_t *make_functional_funp (short, short, short, + struct svalue_s *, int); + +#endif diff --git a/fluffos-2.23-ds03/generate.c b/fluffos-2.23-ds03/generate.c new file mode 100644 index 0000000..f6dd6b1 --- /dev/null +++ b/fluffos-2.23-ds03/generate.c @@ -0,0 +1,786 @@ +#define SUPPRESS_COMPILER_INLINES +#include "std.h" +#include "generate.h" +#include "compiler.h" + +static parse_node_t *optimize (parse_node_t *); +static parse_node_t **last_local_refs = 0; +static int optimizer_num_locals; + +/* Document optimizations here so we can make sure they don't interfere. + * + * Transfer of dying variables: + * . If the last F_LOCAL was not in a loop, replace with transfer_local. + * . Similarly, if an assign is done, change the last use to a transfer if safe + * CAVEATS: we ignore while_dec, loop_cond, and loop_incr. Justification is + * that transfer_local doesn't clobber ints since it just sets type to T_NUMBER + * This optimization also can't deal with code motion. Since it assumes the + * order optimized is the same as the order emitted. + * It also can't detect that a variable dies along multiple branches, so: + * if (y) { use(x); } else { use(x); } x = 1; + * doesn't get optimized. + */ + +static void +optimize_expr_list (parse_node_t * expr) { + if (!expr) return; + do { + expr->v.expr = optimize(expr->v.expr); + } while ((expr = expr->r.expr)); +} + +static void +optimize_lvalue_list (parse_node_t * expr) { + while ((expr = expr->r.expr)) { + expr->v.expr = optimize(expr->l.expr); + } +} + +#define OPT(x) x = optimize(x) +#define OPTIMIZER_IN_LOOP 1 +#define OPTIMIZER_IN_COND 2 /* switch or if or ?: */ +static int optimizer_state = 0; + +static parse_node_t * +optimize (parse_node_t * expr) { + if (!expr) return 0; + + switch (expr->kind) { + case NODE_TERNARY_OP: + OPT(expr->l.expr); + OPT(expr->r.expr->l.expr); + OPT(expr->r.expr->r.expr); + break; + case NODE_BINARY_OP: + OPT(expr->l.expr); + if (expr->v.number == F_ASSIGN) { + if (IS_NODE(expr->r.expr, NODE_OPCODE_1, F_LOCAL_LVALUE)) { + if (!optimizer_state) { + int x = expr->r.expr->l.number; + + if (last_local_refs[x]) { + last_local_refs[x]->v.number = F_TRANSFER_LOCAL; + last_local_refs[x] = 0; + } + } + } + } + OPT(expr->r.expr); + break; + case NODE_UNARY_OP: + OPT(expr->r.expr); + break; + case NODE_OPCODE: + break; + case NODE_TERNARY_OP_1: + OPT(expr->l.expr); + OPT(expr->r.expr->l.expr); + OPT(expr->r.expr->r.expr); + break; + case NODE_BINARY_OP_1: + OPT(expr->l.expr); + OPT(expr->r.expr); + break; + case NODE_UNARY_OP_1: + OPT(expr->r.expr); + if (expr->v.number == F_VOID_ASSIGN_LOCAL) { + if (last_local_refs[expr->l.number] && !optimizer_state) { + last_local_refs[expr->l.number]->v.number = F_TRANSFER_LOCAL; + last_local_refs[expr->l.number] = 0; + } + } + break; + case NODE_OPCODE_1: + if (expr->v.number == F_LOCAL || expr->v.number == F_LOCAL_LVALUE) { + if (expr->v.number == F_LOCAL) { + if(!optimizer_state) { + last_local_refs[expr->l.number] = expr; + break; + } + } + last_local_refs[expr->l.number] = 0; + } + break; + case NODE_OPCODE_2: + break; + case NODE_RETURN: + OPT(expr->r.expr); + break; + case NODE_STRING: + case NODE_REAL: + case NODE_NUMBER: + break; + case NODE_LAND_LOR: + case NODE_BRANCH_LINK: + { + int in_cond = (optimizer_state & OPTIMIZER_IN_COND); + + OPT(expr->l.expr); + optimizer_state |= OPTIMIZER_IN_COND; + OPT(expr->r.expr); + optimizer_state &= ~OPTIMIZER_IN_COND; + optimizer_state |= in_cond; + break; + } + case NODE_CALL_2: + case NODE_CALL_1: + case NODE_CALL: + optimize_expr_list(expr->r.expr); + break; + case NODE_TWO_VALUES: + OPT(expr->l.expr); + OPT(expr->r.expr); + break; + case NODE_CONTROL_JUMP: + case NODE_PARAMETER: + case NODE_PARAMETER_LVALUE: + break; + case NODE_IF: + { + int in_cond; + OPT(expr->v.expr); + in_cond = (optimizer_state & OPTIMIZER_IN_COND); + optimizer_state |= OPTIMIZER_IN_COND; + OPT(expr->l.expr); + OPT(expr->r.expr); + optimizer_state &= ~OPTIMIZER_IN_COND; + optimizer_state |= in_cond; + break; + } + case NODE_LOOP: + { + int in_loop = (optimizer_state & OPTIMIZER_IN_LOOP); + optimizer_state |= OPTIMIZER_IN_LOOP; + OPT(expr->v.expr); + OPT(expr->l.expr); + OPT(expr->r.expr); + optimizer_state &= ~OPTIMIZER_IN_LOOP; + optimizer_state |= in_loop; + break; + } + case NODE_FOREACH: + OPT(expr->l.expr); + OPT(expr->r.expr); + OPT(expr->v.expr); + break; + case NODE_CASE_NUMBER: + case NODE_CASE_STRING: + case NODE_DEFAULT: + break; + case NODE_SWITCH_STRINGS: + case NODE_SWITCH_NUMBERS: + case NODE_SWITCH_DIRECT: + case NODE_SWITCH_RANGES: + { + int in_cond; + OPT(expr->l.expr); + in_cond = (optimizer_state & OPTIMIZER_IN_COND); + optimizer_state |= OPTIMIZER_IN_COND; + OPT(expr->r.expr); + optimizer_state &= ~OPTIMIZER_IN_COND; + optimizer_state |= in_cond; + break; + } + case NODE_CATCH: + OPT(expr->r.expr); + break; + case NODE_LVALUE_EFUN: + OPT(expr->l.expr); + optimize_lvalue_list(expr->r.expr); + break; + + case NODE_FUNCTION_CONSTRUCTOR: + /* Don't optimize inside of these; we'll get confused by local vars + * since it's a separate frame, etc + * + * OPT(expr->r.expr); + * + * BUT make sure to optimize the things which AREN'T part of that + * frame, namely, the arguments, otherwise we will screw up: + * + * use(local); return (: foo, local :); // local evaluated at + * use(local); return (: ... $(local) ... :); // construction time + */ + if (expr->r.expr) + optimize_expr_list(expr->r.expr); /* arguments */ + break; + case NODE_ANON_FUNC: + break; + case NODE_EFUN: + optimize_expr_list(expr->r.expr); + break; + default: + break; + } + return expr; +} + +#ifdef DEBUG +char *lpc_tree_name[] = { + "return", "two values", "opcode", "opcode_1", "opcode_2", + "unary op", "unary op_1", "binary op", "binary op_1", + "ternary op", "ternary op_1", "control jump", "loop", "call", + "call_1", "call_2", "&& ||", "foreach", "lvalue_efun", "switch_range", + "switch_string", "switch_direct", "switch_number", "case_number", + "case_string", "default", "if", "branch link", "parameter", + "parameter_lvalue", "efun", "anon func", "real", "number", + "string", "function", "catch" +}; + +static void lpc_tree (parse_node_t * dest, int num) { + parse_node_t *pn; + + dest->kind = NODE_CALL; + dest->v.number = F_AGGREGATE; + dest->type = TYPE_ANY | TYPE_MOD_ARRAY; + dest->l.number = num; + if (!num) + dest->r.expr = 0; + else { + dest->r.expr = new_node_no_line(); + dest->r.expr->kind = num--; + pn = dest->r.expr; + while (num--) { + pn->r.expr = new_node_no_line(); + pn->type = 0; + pn = pn->r.expr; + } + pn->type = 0; + pn->r.expr = 0; + dest->r.expr->l.expr = pn; + } +} + +static void lpc_tree_number (parse_node_t * dest, int num) { + CREATE_NUMBER(dest->v.expr, num); +} + +static void lpc_tree_real (parse_node_t * dest, float real) { + CREATE_REAL(dest->v.expr, real); +} + +static void lpc_tree_expr (parse_node_t * dest, parse_node_t * expr) { + dest->v.expr = new_node_no_line(); + lpc_tree_form(expr, dest->v.expr); +} + +static void lpc_tree_string (parse_node_t * dest, const char * str) { + CREATE_STRING(dest->v.expr, str); +} + +static void lpc_tree_list (parse_node_t * dest, parse_node_t * expr) { + parse_node_t *pn; + int num = 0; + + pn = expr; + while (pn) { + pn = pn->r.expr; + num++; + } + + dest->v.expr = new_node_no_line(); + lpc_tree(dest->v.expr, num); + dest = dest->v.expr; + while (expr) { + dest = dest->r.expr; + lpc_tree_expr(dest, expr->v.expr); + expr = expr->r.expr; + } +} + +#define lpc_tree_opc(x, y) lpc_tree_string(x, query_instr_name(y & ~NOVALUE_USED_FLAG)) + +#define ARG_1 dest->r.expr +#define ARG_2 dest->r.expr->r.expr +#define ARG_3 dest->r.expr->r.expr->r.expr +#define ARG_4 dest->r.expr->r.expr->r.expr->r.expr +#define ARG_5 dest->r.expr->r.expr->r.expr->r.expr->r.expr + +void +lpc_tree_form (parse_node_t * expr, parse_node_t * dest) { + if (!expr) { + dest->kind = NODE_NUMBER; + dest->type = TYPE_ANY; + dest->v.number = 0; + return; + } + + switch (expr->kind) { + case NODE_TERNARY_OP: + lpc_tree(dest, 4); + lpc_tree_opc(ARG_2, expr->r.expr->v.number); + lpc_tree_expr(ARG_3, expr->l.expr); + lpc_tree_expr(ARG_4, expr->r.expr); + break; + case NODE_TERNARY_OP_1: + lpc_tree(dest, 5); + lpc_tree_opc(ARG_2, expr->r.expr->v.number); + lpc_tree_number(ARG_3, expr->type); + lpc_tree_expr(ARG_4, expr->l.expr); + lpc_tree_expr(ARG_5, expr->r.expr); + break; + case NODE_BINARY_OP: + case NODE_LAND_LOR: + case NODE_BRANCH_LINK: + lpc_tree(dest, 4); + lpc_tree_opc(ARG_2, expr->v.number); + lpc_tree_expr(ARG_3, expr->l.expr); + lpc_tree_expr(ARG_4, expr->r.expr); + break; + case NODE_TWO_VALUES: + lpc_tree(dest, 3); + lpc_tree_expr(ARG_2, expr->l.expr); + lpc_tree_expr(ARG_3, expr->r.expr); + break; + case NODE_BINARY_OP_1: + lpc_tree(dest, 5); + lpc_tree_opc(ARG_2, expr->v.number); + lpc_tree_number(ARG_3, expr->type); + lpc_tree_expr(ARG_4, expr->l.expr); + lpc_tree_expr(ARG_5, expr->r.expr); + break; + case NODE_UNARY_OP: + lpc_tree(dest, 3); + lpc_tree_opc(ARG_2, expr->v.number); + lpc_tree_expr(ARG_3, expr->r.expr); + break; + case NODE_UNARY_OP_1: + lpc_tree(dest, 4); + lpc_tree_opc(ARG_2, expr->v.number); + lpc_tree_number(ARG_3, expr->l.number); + lpc_tree_expr(ARG_4, expr->r.expr); + break; + case NODE_OPCODE: + lpc_tree(dest, 2); + lpc_tree_opc(ARG_2, expr->v.number); + break; + case NODE_CONTROL_JUMP: + case NODE_PARAMETER: + case NODE_PARAMETER_LVALUE: + lpc_tree(dest, 2); + lpc_tree_number(ARG_2, expr->v.number); + break; + case NODE_OPCODE_1: + lpc_tree(dest, 3); + lpc_tree_opc(ARG_2, expr->v.number); + lpc_tree_number(ARG_3, expr->l.number); + break; + case NODE_OPCODE_2: + lpc_tree(dest, 4); + lpc_tree_opc(ARG_2, expr->v.number); + lpc_tree_number(ARG_3, expr->l.number); + lpc_tree_number(ARG_4, expr->r.number); + break; + case NODE_RETURN: + lpc_tree(dest, 2); + lpc_tree_expr(ARG_2, expr->r.expr); + break; + case NODE_STRING: + case NODE_NUMBER: + lpc_tree(dest, 2); + lpc_tree_number(ARG_2, expr->v.number); + break; + case NODE_REAL: + lpc_tree(dest, 2); + lpc_tree_real(ARG_2, expr->v.real); + break; + case NODE_CALL_2: + case NODE_CALL_1: + case NODE_CALL: + lpc_tree(dest, 4); + lpc_tree_opc(ARG_2, expr->v.number); + lpc_tree_list(ARG_3, expr->r.expr); + lpc_tree_number(ARG_4, expr->l.number); + break; + case NODE_IF: + case NODE_FOREACH: + lpc_tree(dest, 4); + lpc_tree_expr(ARG_2, expr->l.expr); + lpc_tree_expr(ARG_3, expr->r.expr); + lpc_tree_expr(ARG_4, expr->v.expr); + break; + case NODE_LOOP: + lpc_tree(dest, 5); + lpc_tree_number(ARG_2, expr->type); + lpc_tree_expr(ARG_3, expr->v.expr); + lpc_tree_expr(ARG_4, expr->r.expr); + lpc_tree_expr(ARG_5, expr->l.expr); + break; + case NODE_CASE_NUMBER: + case NODE_CASE_STRING: + case NODE_DEFAULT: + lpc_tree(dest, 1); + break; + case NODE_SWITCH_STRINGS: + case NODE_SWITCH_NUMBERS: + case NODE_SWITCH_DIRECT: + case NODE_SWITCH_RANGES: + lpc_tree(dest, 3); + lpc_tree_expr(ARG_2, expr->l.expr); + lpc_tree_expr(ARG_3, expr->r.expr); + break; + case NODE_CATCH: + lpc_tree(dest, 2); + lpc_tree_expr(ARG_2, expr->r.expr); + break; + case NODE_LVALUE_EFUN: + lpc_tree(dest, 3); + lpc_tree_expr(ARG_2, expr->l.expr); + lpc_tree_list(ARG_3, expr->r.expr); + break; + case NODE_FUNCTION_CONSTRUCTOR: + case NODE_EFUN: + lpc_tree(dest, 3); + lpc_tree_opc(ARG_2, expr->v.number); + lpc_tree_list(ARG_3, expr->r.expr); + break; + default: + lpc_tree(dest,1); + lpc_tree_string(ARG_1, "!GARBAGE!"); + return; + } + lpc_tree_string(ARG_1, lpc_tree_name[expr->kind]); +} +#endif + +ADDRESS_TYPE +generate (parse_node_t * node) { + ADDRESS_TYPE where = CURRENT_PROGRAM_SIZE; + + if (num_parse_error) return 0; + { + i_generate_node(node); + } + free_tree(); + + return where; +} + +static void optimizer_start_function (int n) { + if (n) { + last_local_refs = CALLOCATE(n, parse_node_t *, TAG_COMPILER, "c_start_function"); + optimizer_num_locals = n; + while (n--) { + last_local_refs[n] = 0; + } + } else last_local_refs = 0; +} + +static void optimizer_end_function (void) { + int i; + if (last_local_refs) { + for (i = 0; i < optimizer_num_locals; i++) + if (last_local_refs[i]) { + last_local_refs[i]->v.number = F_TRANSFER_LOCAL; + } + FREE(last_local_refs); + last_local_refs = 0; + } +} + +ADDRESS_TYPE generate_function (function_t * f, parse_node_t * node, int num) { + ADDRESS_TYPE ret; + if (pragmas & PRAGMA_OPTIMIZE) { + optimizer_start_function(num); + optimizer_state = 0; + node = optimize(node); + optimizer_end_function(); + } + ret = generate(node); + return ret; +} + +int +node_always_true (parse_node_t * node) { + if (!node) return 1; + if (node->kind == NODE_NUMBER) + return node->v.number; + return 0; +} + +int +generate_conditional_branch (parse_node_t * node) { + int branch; + + if (!node) + return F_BBRANCH; + + /* only have to handle while (x != 0) since while (x == 0) will be + * handled by the x == 0 -> !x and !x optimizations. + */ + if (IS_NODE(node, NODE_BINARY_OP, F_NE)) { + if (IS_NODE(node->r.expr, NODE_NUMBER, 0)) + node = node->l.expr; + else if (IS_NODE(node->l.expr, NODE_NUMBER, 0)) + node = node->r.expr; + } + if (IS_NODE(node, NODE_UNARY_OP, F_NOT)) { + node = node->r.expr; + branch = F_BBRANCH_WHEN_ZERO; + } else { + branch = F_BBRANCH_WHEN_NON_ZERO; + if (node->kind == NODE_NUMBER) { + if (node->v.number == 0) + branch = 0; + else + branch = F_BBRANCH; + node = 0; + } + if (node) { + if (IS_NODE(node, NODE_BINARY_OP, F_LT)) { + generate(node->l.expr); + generate(node->r.expr); + return F_BBRANCH_LT; + } + if (IS_NODE(node, NODE_OPCODE_1, F_WHILE_DEC)) { + generate(node); + return F_WHILE_DEC; + } + } + } + generate(node); + return branch; +} + +#ifdef DEBUG +void +dump_expr_list (parse_node_t * expr) { + if (!expr) return; + do { + dump_tree(expr->v.expr); + } while ((expr = expr->r.expr)); +} + +static void +dump_lvalue_list (parse_node_t * expr) { + printf("(lvalue_list "); + while ((expr = expr->r.expr)) + dump_tree(expr->l.expr); +} + +void +dump_tree (parse_node_t * expr) { + if (!expr) return; + + switch (expr->kind) { + case NODE_TERNARY_OP: + printf("(%s ", instrs[expr->r.expr->v.number].name); + dump_tree(expr->l.expr); + expr = expr->r.expr; + dump_tree(expr->l.expr); + dump_tree(expr->r.expr); + printf(")"); + break; + case NODE_BINARY_OP: + printf("(%s ", instrs[expr->v.number].name); + dump_tree(expr->l.expr); + dump_tree(expr->r.expr); + printf(")"); + break; + case NODE_UNARY_OP: + printf("(%s ", instrs[expr->v.number].name); + dump_tree(expr->r.expr); + printf(")"); + break; + case NODE_OPCODE: + printf("(%s)", instrs[expr->v.number].name); + break; + case NODE_TERNARY_OP_1: + { + int p = expr->type; + printf("(%s ", instrs[expr->r.expr->v.number].name); + dump_tree(expr->l.expr); + expr = expr->r.expr; + dump_tree(expr->l.expr); + dump_tree(expr->r.expr); + printf(" %i)", p); + break; + } + case NODE_BINARY_OP_1: + printf("(%s ", instrs[expr->v.number].name); + dump_tree(expr->l.expr); + dump_tree(expr->r.expr); + printf(" %i)", expr->type); + break; + case NODE_UNARY_OP_1: + printf("(%s ", instrs[expr->v.number].name); + dump_tree(expr->r.expr); + printf(" %i)", expr->l.number); + break; + case NODE_OPCODE_1: + printf("(%s %i)", instrs[expr->v.number].name, expr->l.number); + break; + case NODE_OPCODE_2: + printf("(%s %i %i)", instrs[expr->v.number].name, expr->l.number, expr->r.number); + break; + case NODE_RETURN: + if (expr->r.expr) { + printf("(return "); + dump_tree(expr->r.expr); + printf(")"); + } else { + printf("(return_zero)"); + } + break; + case NODE_STRING: + printf("(string %i)", expr->v.number); + break; + case NODE_REAL: + printf("(real %f)", expr->v.real); + break; + case NODE_NUMBER: + printf("(number %i)", expr->v.number); + break; + case NODE_LAND_LOR: + if (expr->v.number == F_LAND) + printf("(&& "); + else + printf("(|| "); + dump_tree(expr->l.expr); + dump_tree(expr->r.expr); + printf(")"); + break; + case NODE_BRANCH_LINK: + printf("(branch_link "); + dump_tree(expr->l.expr); + dump_tree(expr->r.expr); + printf(")"); + break; + case NODE_CALL_2: + printf("(%s %i %i %i ", instrs[expr->v.number].name, expr->l.number >> 16, + expr->l.number & 0xffff, (expr->r.expr ? expr->r.expr->kind : 0)); + dump_expr_list(expr->r.expr); + printf(")"); + break; + case NODE_CALL_1: + printf("(%s %i %i ", instrs[expr->v.number].name, expr->l.number, + (expr->r.expr ? expr->r.expr->kind : 0)); + dump_expr_list(expr->r.expr); + printf(")"); + break; + case NODE_CALL: + printf("(%s %i ", instrs[expr->v.number].name, expr->l.number); + dump_expr_list(expr->r.expr); + printf(")"); + break; + case NODE_TWO_VALUES: + dump_tree(expr->l.expr); + printf("\n"); + dump_tree(expr->r.expr); + break; + case NODE_CONTROL_JUMP: + if (expr->v.number == CJ_BREAK_SWITCH) { + printf("(break_switch)"); + } else if (expr->v.number == CJ_BREAK) { + printf("(break)"); + } else if (expr->v.number == CJ_CONTINUE) { + printf("(continue)"); + } else { + printf("(UNKNOWN CONTROL JUMP)"); + } + break; + case NODE_PARAMETER: + printf("(parameter %i)", expr->v.number); + break; + case NODE_PARAMETER_LVALUE: + printf("(parameter_lvalue %i)", expr->v.number); + break; + case NODE_IF: + printf("(if "); + dump_tree(expr->v.expr); + printf("\n"); + dump_tree(expr->l.expr); + if (expr->r.expr) { + printf("\n"); + dump_tree(expr->r.expr); + } + printf(")\n"); + break; + case NODE_LOOP: + printf("(loop %i\n", expr->type); + dump_tree(expr->v.expr); + printf("\n"); + dump_tree(expr->l.expr); + printf("\n"); + dump_tree(expr->r.expr); + printf(")\n"); + break; + case NODE_FOREACH: + printf("(foreach "); + dump_tree(expr->l.expr); + dump_tree(expr->r.expr); + dump_tree(expr->v.expr); + printf(")\n"); + break; + case NODE_CASE_NUMBER: + case NODE_CASE_STRING: + printf("(case)"); + break; + case NODE_DEFAULT: + printf("(default)"); + break; + case NODE_SWITCH_STRINGS: + case NODE_SWITCH_NUMBERS: + case NODE_SWITCH_DIRECT: + case NODE_SWITCH_RANGES: + printf("(switch "); + dump_tree(expr->l.expr); + dump_tree(expr->r.expr); + printf(")"); + break; + case NODE_CATCH: + printf("(catch "); + dump_tree(expr->r.expr); + printf(")"); + break; + case NODE_LVALUE_EFUN: + printf("(lvalue_efun "); + dump_tree(expr->l.expr); + dump_lvalue_list(expr->r.expr); + printf(")"); + break; + case NODE_FUNCTION_CONSTRUCTOR: + printf("(function %i ", expr->v.number & 0xff); + if (expr->r.expr) { + printf("(array "); + dump_expr_list(expr->r.expr); + printf(")"); + } else { + printf("(number 0)"); + } + switch (expr->v.number & 0xff) { + case FP_SIMUL: + printf("(fp-simul %i)", expr->v.number >> 8); + break; + case FP_LOCAL: + printf("(fp-local %i)", expr->v.number >> 8); + break; + case FP_EFUN: + printf("(fp-efun %s)", instrs[expr->v.number >> 8].name); + break; + case FP_FUNCTIONAL: + case FP_FUNCTIONAL | FP_NOT_BINDABLE: + printf("(fp-functional %i ", expr->v.number >> 8); + dump_tree(expr->l.expr); + printf(")"); + break; + } + printf(" %i)", expr->v.number >> 8); + break; + case NODE_ANON_FUNC: + printf("(anon-func %i %i ", expr->v.number, expr->l.number); + dump_tree(expr->r.expr); + printf(")"); + break; + case NODE_EFUN: + printf("(%s ", instrs[expr->v.number & ~NOVALUE_USED_FLAG].name); + dump_expr_list(expr->r.expr); + printf(")"); + break; + default: + printf("(unknown)"); + break; + } + fflush(stdout); +} +#endif diff --git a/fluffos-2.23-ds03/generate.h b/fluffos-2.23-ds03/generate.h new file mode 100644 index 0000000..46fc7cf --- /dev/null +++ b/fluffos-2.23-ds03/generate.h @@ -0,0 +1,26 @@ +#ifndef _GENERATE_H +#define _GENERATE_H + +#include "trees.h" +#include "lpc_incl.h" +#include "icode.h" + +#define generate_function_call i_generate_function_call +#define generate_inherited_init_call i_generate_inherited_init_call +#define generate___INIT i_generate___INIT +#define generate_final_program i_generate_final_program +#define initialize_parser i_initialize_parser +#define uninitialize_parser i_uninitialize_parser + +int node_always_true (parse_node_t *); +ADDRESS_TYPE generate (parse_node_t *); +ADDRESS_TYPE generate_function (function_t *, parse_node_t *, int); +int generate_conditional_branch (parse_node_t *); + +#ifdef DEBUG +void dump_expr_list (parse_node_t *); +void dump_tree (parse_node_t *); +void lpc_tree_form (parse_node_t *, parse_node_t *); +#endif + +#endif diff --git a/fluffos-2.23-ds03/gnumalloc.c b/fluffos-2.23-ds03/gnumalloc.c new file mode 100644 index 0000000..6fada7b --- /dev/null +++ b/fluffos-2.23-ds03/gnumalloc.c @@ -0,0 +1,567 @@ +/* calloc.c - C standard library routine. + Copyright (c) 1989, 1993 Michael J. Haertel + You may redistribute this library under the terms of the + GNU Library General Public License (version 2 or any later + version) as published by the Free Software Foundation. + THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED + WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR + WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS + SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. */ + +#include +#include +#include "gnumalloc.h" + +/* Allocate space for the given number of elements of the given + size, initializing the whole region to binary zeroes. */ +void * +gnucalloc(size_t nelem, size_t size) +{ + void *result; + + result = gnumalloc(size * nelem); + if (result) + memset(result, 0, nelem * size); + return result; +} +/* free.c - C standard library routine. + Copyright (c) 1989, 1993 Michael J. Haertel + You may redistribute this library under the terms of the + GNU Library General Public License (version 2 or any later + version) as published by the Free Software Foundation. + THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED + WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR + WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS + SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. */ + +#include +#include +#include + +/* Return memory to the heap. */ +void +gnufree(void *ptr) +{ + int block, blocks, i, type; + struct list *prev, *next; + + if (!ptr) + return; + + block = BLOCK(ptr); + + switch (type = _heapinfo[block].busy.type) { + case 0: + /* Find the free cluster previous to this one in the free list. + Start searching at the last block referenced; this may benefit + programs with locality of allocation. */ + i = _heapindex; + if (i > block) + while (i > block) + i = _heapinfo[i].free.prev; + else { + do + i = _heapinfo[i].free.next; + while (i > 0 && i < block); + i = _heapinfo[i].free.prev; + } + + /* Determine how to link this block into the free list. */ + if (block == i + _heapinfo[i].free.size) { + /* Coalesce this block with its predecessor. */ + _heapinfo[i].free.size += _heapinfo[block].busy.info.size; + block = i; + } else { + /* Really link this block back into the free list. */ + _heapinfo[block].free.size = _heapinfo[block].busy.info.size; + _heapinfo[block].free.next = _heapinfo[i].free.next; + _heapinfo[block].free.prev = i; + _heapinfo[i].free.next = block; + _heapinfo[_heapinfo[block].free.next].free.prev = block; + } + + /* Now that the block is linked in, see if we can coalesce it + with its successor (by deleting its successor from the list + and adding in its size). */ + if (block + _heapinfo[block].free.size == _heapinfo[block].free.next) { + _heapinfo[block].free.size + += _heapinfo[_heapinfo[block].free.next].free.size; + _heapinfo[block].free.next + = _heapinfo[_heapinfo[block].free.next].free.next; + _heapinfo[_heapinfo[block].free.next].free.prev = block; + } + + /* Now see if we can return stuff to the system. */ + blocks = _heapinfo[block].free.size; + if (blocks >= FINAL_FREE_BLOCKS && block + blocks == _heaplimit + && (*_morecore)(0) == ADDRESS(block + blocks)) { + _heaplimit -= blocks; + (*_morecore)(-blocks * BLOCKSIZE); + _heapinfo[_heapinfo[block].free.prev].free.next + = _heapinfo[block].free.next; + _heapinfo[_heapinfo[block].free.next].free.prev + = _heapinfo[block].free.prev; + block = _heapinfo[block].free.prev; + } + + /* Set the next search to begin at this block. */ + _heapindex = block; + break; + + default: + /* Get the address of the first free fragment in this block. */ + prev = (struct list *) ((char *) ADDRESS(block) + + (_heapinfo[block].busy.info.frag.first + << type)); + + if (_heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1 + && _fragblocks[type] > 1) { + /* If all fragments of this block are free, remove them + from the fragment list and free the whole block. */ + --_fragblocks[type]; + for (next = prev, i = 1; i < BLOCKSIZE >> type; ++i) + next = next->next; + prev->prev->next = next; + if (next) + next->prev = prev->prev; + _heapinfo[block].busy.type = 0; + _heapinfo[block].busy.info.size = 1; + gnufree(ADDRESS(block)); + } else if (_heapinfo[block].busy.info.frag.nfree) { + /* If some fragments of this block are free, link this fragment + into the fragment list after the first free fragment of + this block. */ + next = ptr; + next->next = prev->next; + next->prev = prev; + prev->next = next; + if (next->next) + next->next->prev = next; + ++_heapinfo[block].busy.info.frag.nfree; + } else { + /* No fragments of this block are free, so link this fragment + into the fragment list and announce that it is the first + free fragment of this block. */ + prev = (struct list *) ptr; + _heapinfo[block].busy.info.frag.nfree = 1; + _heapinfo[block].busy.info.frag.first + = (unsigned int) ((char *) ptr - (char *) NULL) % BLOCKSIZE + >> type; + prev->next = _fraghead[type].next; + prev->prev = &_fraghead[type]; + prev->prev->next = prev; + if (prev->next) + prev->next->prev = prev; + } + break; + } +} +/* malloc.c - C standard library routine. + Copyright (c) 1989, 1993 Michael J. Haertel + You may redistribute this library under the terms of the + GNU Library General Public License (version 2 or any later + version) as published by the Free Software Foundation. + THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED + WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR + WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS + SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. */ + +#include +#include +#include +#include + +/* How to really get more memory. */ +void *(*_morecore)(long) = _default_morecore; + +/* Pointer to the base of the first block. */ +char *_heapbase; + +/* Block information table. */ +union info *_heapinfo; + +/* Number of info entries. */ +static int heapsize; + +/* Search index in the info table. */ +int _heapindex; + +/* Limit of valid info table indices. */ +int _heaplimit; + +/* Count of large blocks allocated for each fragment size. */ +int _fragblocks[BLOCKLOG]; + +/* Free lists for each fragment size. */ +struct list _fraghead[BLOCKLOG]; + +/* Are we experienced? */ +static int initialized; + +/* Aligned allocation. */ +static void * +align(size_t size) +{ + void *result; + unsigned int adj; + + result = (*_morecore)(size); + adj = (unsigned int) ((char *) result - (char *) NULL) % BLOCKSIZE; + if (adj != 0) { + (*_morecore)(adj = BLOCKSIZE - adj); + result = (char *) result + adj; + } + return result; +} + +/* Set everything up and remember that we have. */ +static int +initialize() +{ + heapsize = HEAP / BLOCKSIZE; + _heapinfo = align(heapsize * sizeof (union info)); + if (!_heapinfo) + return 0; + memset(_heapinfo, 0, heapsize * sizeof (union info)); + _heapinfo[0].free.size = 0; + _heapinfo[0].free.next = _heapinfo[0].free.prev = 0; + _heapindex = 0; + _heapbase = (char *) _heapinfo; + initialized = 1; + return 1; +} + +/* Get neatly aligned memory, initializing or growing the + heap info table as necessary. */ +static void * +morecore(size_t size) +{ + void *result; + union info *newinfo, *oldinfo; + int newsize; + + result = align(size); + if (!result) + return NULL; + + /* Check if we need to grow the info table. */ + if (BLOCK((char *) result + size) > heapsize) { + newsize = heapsize; + while (BLOCK((char *) result + size) > newsize) + newsize *= 2; + newinfo = align(newsize * sizeof (union info)); + if (!newinfo) { + (*_morecore)(-size); + return NULL; + } + memset(newinfo, 0, newsize * sizeof (union info)); + memcpy(newinfo, _heapinfo, heapsize * sizeof (union info)); + oldinfo = _heapinfo; + newinfo[BLOCK(oldinfo)].busy.type = 0; + newinfo[BLOCK(oldinfo)].busy.info.size + = BLOCKIFY(heapsize * sizeof (union info)); + _heapinfo = newinfo; + gnufree(oldinfo); + heapsize = newsize; + } + + _heaplimit = BLOCK((char *) result + size); + return result; +} + +/* Allocate memory from the heap. */ +void * +gnumalloc(size_t size) +{ + void *result; + int log, block, blocks, i, lastblocks, start; + struct list *next; + + if (!initialized && !initialize()) + return NULL; + + if (size == 0) + return NULL; + + if (size < sizeof (struct list)) + size = sizeof (struct list); + + /* Determine the allocation policy based on the request size. */ + if (size <= BLOCKSIZE / 2) { + /* Small allocation to receive a fragment of a block. Determine + the logarithm to base two of the fragment size. */ + --size; + for (log = 1; (size >>= 1) != 0; ++log) + ; + + /* Look in the fragment lists for a free fragment of the + desired size. */ + if ((next = _fraghead[log].next) != 0) { + /* There are free fragments of this size. Pop a fragment + out of the fragment list and return it. Update the block's + nfree and first counters. */ + result = next; + next->prev->next = next->next; + if (next->next) + next->next->prev = next->prev; + block = BLOCK(result); + if (--_heapinfo[block].busy.info.frag.nfree) + _heapinfo[block].busy.info.frag.first + = (unsigned int) ((char *) next->next - (char *) NULL) + % BLOCKSIZE >> log; + } else { + /* No free fragments of the desired size, so get a new block + and break it into fragments, returning the first. */ + result = gnumalloc(BLOCKSIZE); + if (!result) + return NULL; + ++_fragblocks[log]; + + /* Link all fragments but the first into the free list. */ + for (i = 1; i < BLOCKSIZE >> log; ++i) { + next = (struct list *) ((char *) result + (i << log)); + next->next = _fraghead[log].next; + next->prev = &_fraghead[log]; + next->prev->next = next; + if (next->next) + next->next->prev = next; + } + + /* Initialize the nfree and first counters for this block. */ + block = BLOCK(result); + _heapinfo[block].busy.type = log; + _heapinfo[block].busy.info.frag.nfree = i - 1; + _heapinfo[block].busy.info.frag.first = i - 1; + } + } else { + /* Large allocation to receive one or more blocks. Search + the free list in a circle starting at the last place visited. + If we loop completely around without finding a large enough + space we will have to get more memory from the system. */ + blocks = BLOCKIFY(size); + start = block = _heapindex; + while (_heapinfo[block].free.size < blocks) { + block = _heapinfo[block].free.next; + if (block == start) { + /* Need to get more from the system. Check to see if + the new core will be contiguous with the final free + block; if so we don't need to get as much. */ + block = _heapinfo[0].free.prev; + lastblocks = _heapinfo[block].free.size; + if (_heaplimit && block + lastblocks == _heaplimit + && (*_morecore)(0) == ADDRESS(block + lastblocks) + && morecore((blocks - lastblocks) * BLOCKSIZE)) { + /* Note that morecore() can change the location of + the final block if it moves the info table and the + old one gets coalesced into the final block. */ + block = _heapinfo[0].free.prev; + _heapinfo[block].free.size += blocks - lastblocks; + continue; + } + result = morecore(blocks * BLOCKSIZE); + if (!result) + return NULL; + block = BLOCK(result); + _heapinfo[block].busy.type = 0; + _heapinfo[block].busy.info.size = blocks; + return result; + } + } + + /* At this point we have found a suitable free list entry. + Figure out how to remove what we need from the list. */ + result = ADDRESS(block); + if (_heapinfo[block].free.size > blocks) { + /* The block we found has a bit left over, so relink the + tail end back into the free list. */ + _heapinfo[block + blocks].free.size + = _heapinfo[block].free.size - blocks; + _heapinfo[block + blocks].free.next + = _heapinfo[block].free.next; + _heapinfo[block + blocks].free.prev + = _heapinfo[block].free.prev; + _heapinfo[_heapinfo[block].free.prev].free.next + = _heapinfo[_heapinfo[block].free.next].free.prev + = _heapindex = block + blocks; + } else { + /* The block exactly matches our requirements, so + just remove it from the list. */ + _heapinfo[_heapinfo[block].free.next].free.prev + = _heapinfo[block].free.prev; + _heapinfo[_heapinfo[block].free.prev].free.next + = _heapindex = _heapinfo[block].free.next; + } + + _heapinfo[block].busy.type = 0; + _heapinfo[block].busy.info.size = blocks; + } + + return result; +} +/* morecore.c - C library support routine for UNIX. + Copyright (c) 1989, 1993 Michael J. Haertel + You may redistribute this library under the terms of the + GNU Library General Public License (version 2 or any later + version) as published by the Free Software Foundation. + THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED + WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR + WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS + SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. */ + +#include +#include + +extern void *sbrkx(int); + +/* Note that morecore has to take a signed argument so + that negative values can return memory to the system. */ +void * +_default_morecore(long size) +{ + void *result; + + result = sbrkx(size); + if (result == (void *) -1) + return NULL; + return result; +} +/* realloc.c - C standard library routine. + Copyright (c) 1989, 1993 Michael J. Haertel + You may redistribute this library under the terms of the + GNU Library General Public License (version 2 or any later + version) as published by the Free Software Foundation. + THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED + WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR + WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS + SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. */ + +#include +#include +#include +#include + +#define MIN(A, B) ((A) < (B) ? (A) : (B)) + +/* Resize the given region to the new size, returning a pointer + to the (possibly moved) region. This is optimized for speed; + some benchmarks seem to indicate that greater compactness is + achieved by unconditionally allocating and copying to a + new region. */ +void * +gnurealloc(void *ptr, size_t size) +{ + void *result, *previous; + int block, blocks, type; + int oldlimit; + + if (!ptr) + return gnumalloc(size); + if (!size) { + gnufree(ptr); + return gnumalloc(0); + } + + block = BLOCK(ptr); + + switch (type = _heapinfo[block].busy.type) { + case 0: + /* Maybe reallocate a large block to a small fragment. */ + if (size <= BLOCKSIZE / 2) { + if ((result = gnumalloc(size)) != NULL) { + memcpy(result, ptr, size); + gnufree(ptr); + } + return result; + } + + /* The new size is a large allocation as well; see if + we can hold it in place. */ + blocks = BLOCKIFY(size); + if (blocks < _heapinfo[block].busy.info.size) { + /* The new size is smaller; return excess memory + to the free list. */ + _heapinfo[block + blocks].busy.type = 0; + _heapinfo[block + blocks].busy.info.size + = _heapinfo[block].busy.info.size - blocks; + _heapinfo[block].busy.info.size = blocks; + gnufree(ADDRESS(block + blocks)); + return ptr; + } else if (blocks == _heapinfo[block].busy.info.size) + /* No size change necessary. */ + return ptr; + else { + /* Won't fit, so allocate a new region that will. Free + the old region first in case there is sufficient adjacent + free space to grow without moving. */ + blocks = _heapinfo[block].busy.info.size; + /* Prevent free from actually returning memory to the system. */ + oldlimit = _heaplimit; + _heaplimit = 0; + gnufree(ptr); + _heaplimit = oldlimit; + result = gnumalloc(size); + if (!result) { + /* Now we're really in trouble. We have to unfree + the thing we just freed. Unfortunately it might + have been coalesced with its neighbors. */ + if (_heapindex == block) + gnumalloc(blocks * BLOCKSIZE); + else { + previous = gnumalloc((block - _heapindex) * BLOCKSIZE); + gnumalloc(blocks * BLOCKSIZE); + gnufree(previous); + } + return NULL; + } + if (ptr != result) + memmove(result, ptr, blocks * BLOCKSIZE); + return result; + } + break; + + default: + /* Old size is a fragment; type is logarithm to base two of + the fragment size. */ + if ((size > 1 << (type - 1)) && (size <= 1 << type)) + /* New size is the same kind of fragment. */ + return ptr; + else { + /* New size is different; allocate a new space, and copy + the lesser of the new size and the old. */ + result = gnumalloc(size); + if (!result) + return NULL; + memcpy(result, ptr, MIN(size, 1 << type)); + gnufree(ptr); + return result; + } + break; + } +} +/* valloc.c - Berkeley C Library Compatibility routine. + Copyright (c) 1989, 1993 Michael J. Haertel + You may redistribute this library under the terms of the + GNU Library General Public License (version 2 or any later + version) as published by the Free Software Foundation. + THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED + WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR + WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS + SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. */ + +#include +#include +#include + +#define MAX(A,B) ((A) > (B) ? (A) : (B)) + +/* + * WARNING: The definition of BLOCKSIZE (in "malloc.h") + * must be greater than or equal to the page size of + * your machine. We don't do getpagesize() because I + * want to keep weird Unix dependencies out of the code. + */ +void * +valloc(size_t size) +{ + return gnumalloc(MAX(BLOCKSIZE, size)); +} diff --git a/fluffos-2.23-ds03/gnumalloc.h b/fluffos-2.23-ds03/gnumalloc.h new file mode 100644 index 0000000..5644b62 --- /dev/null +++ b/fluffos-2.23-ds03/gnumalloc.h @@ -0,0 +1,96 @@ +/* malloc.h - declarations for the allocator. + Copyright (c) 1989, 1993 Michael J. Haertel + You may redistribute this library under the terms of the + GNU Library General Public License (version 2 or any later + version) as published by the Free Software Foundation. + THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED + WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR + WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS + SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. */ + +/* Underlying allocation function; successive calls should return + contiguous pieces of memory. */ + +#ifndef GNU_MALLOC_H +#define GNU_MALLOC_H +extern void *(*_morecore)(long); + +/* Default value of previous. */ +extern void *_default_morecore(long); + +/* The allocator divides the heap into blocks of fixed size; large + requests receive one or more whole blocks, and small requests + receive a fragment of a block. Fragment sizes are powers of two, + and all fragments of a block are the same size. When all the + fragments in a block have been freed, the block itself is freed. + WARNING: BLOCKSIZE must be set greater than or equal to the + machine's page size for valloc() to work correctly. The default + definition here is 4096 bytes. */ +#define INT_BIT (CHAR_BIT * sizeof (int)) +#define BLOCKLOG (INT_BIT > 16 ? 12 : 9) +#define BLOCKSIZE (1 << BLOCKLOG) +#define BLOCKIFY(SIZE) (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE) + +/* Determine the amount of memory spanned by the initial heap table + (not an absolute limit). */ +#define HEAP (INT_BIT > 16 ? 4194304 : 65536) + +/* Number of contiguous free blocks allowed to build up at the end of + memory before they will be returned to the system. */ +#define FINAL_FREE_BLOCKS 8 + +/* Data structure giving per-block information. */ +union info { + struct { + int type; /* Zero for a large block, or positive + giving the logarithm to the base two + of the fragment size. */ + union { + struct { + int nfree; /* Free fragments in a fragmented block. */ + int first; /* First free fragment of the block. */ + } frag; + int size; /* Size (in blocks) of a large cluster. */ + } info; + } busy; + struct { + int size; /* Size (in blocks) of a free cluster. */ + int next; /* Index of next free cluster. */ + int prev; /* Index of previous free cluster. */ + } free; +}; + +/* Pointer to first block of the heap. */ +extern char *_heapbase; + +/* Table indexed by block number giving per-block information. */ +extern union info *_heapinfo; + +/* Address to block number and vice versa. */ +#define BLOCK(A) (((char *) (A) - _heapbase) / BLOCKSIZE + 1) +#define ADDRESS(B) ((void *) (((B) - 1) * BLOCKSIZE + _heapbase)) + +/* Current search index for the heap table. */ +extern int _heapindex; + +/* Limit of valid info table indices. */ +extern int _heaplimit; + +/* Doubly linked lists of free fragments. */ +struct list { + struct list *next; + struct list *prev; +}; + +/* Count of blocks for each fragment size. */ +extern int _fragblocks[]; + +/* Free list headers for each fragment size. */ +extern struct list _fraghead[]; + +void *gnumalloc(size_t); +void gnufree(void *); +void *gnurealloc(void *, size_t); +void *gnucalloc(size_t,size_t); + +#endif diff --git a/fluffos-2.23-ds03/grammar.y.pre b/fluffos-2.23-ds03/grammar.y.pre new file mode 100644 index 0000000..eaa9d94 --- /dev/null +++ b/fluffos-2.23-ds03/grammar.y.pre @@ -0,0 +1,3793 @@ +/* This is to make emacs edit this in C mode: -*-C-*- */ + +%{ +extern char *outp; +#include "std.h" +#include "compiler.h" +#include "lex.h" +#include "scratchpad.h" + +#include "lpc_incl.h" +#include "simul_efun.h" +#include "generate.h" +#include "master.h" + +/* gross. Necessary? - Beek */ +#ifdef WIN32 +#define MSDOS +#endif +#define YYSTACK_USE_ALLOCA 0 +%line +/* + * This is the grammar definition of LPC, and its parse tree generator. + */ + +/* down to one global :) + bits: + SWITCH_CONTEXT - we're inside a switch + LOOP_CONTEXT - we're inside a loop + SWITCH_STRINGS - a string case has been found + SWITCH_NUMBERS - a non-zero numeric case has been found + SWITCH_RANGES - a range has been found + SWITCH_DEFAULT - a default has been found + */ +int context; +int num_refs; +int func_present; +/* + * bison & yacc don't prototype this in y.tab.h + */ +int yyparse (void); + +%} +/* + * Token definitions. + * + * Appearing in the precedence declarations are: + * '+' '-' '/' '*' '%' + * '&' '|' '<' '>' '^' + * '~' '?' + * + * Other single character tokens recognized in this grammar: + * '{' '}' ',' ';' ':' + * '(' ')' '[' ']' '$' + */ + +%token L_STRING L_NUMBER L_REAL +%token L_BASIC_TYPE L_TYPE_MODIFIER +%token L_DEFINED_NAME L_IDENTIFIER +%token L_EFUN + +%token L_INC L_DEC +%token L_ASSIGN +%token L_LAND L_LOR +%token L_LSH L_RSH +%token L_ORDER +%token L_NOT + +%token L_IF L_ELSE +%token L_SWITCH L_CASE L_DEFAULT L_RANGE L_DOT_DOT_DOT +%token L_WHILE L_DO L_FOR L_FOREACH L_IN +%token L_BREAK L_CONTINUE +%token L_RETURN +%token L_ARROW L_INHERIT L_COLON_COLON +%token L_ARRAY_OPEN L_MAPPING_OPEN L_FUNCTION_OPEN L_NEW_FUNCTION_OPEN + +%token L_SSCANF L_CATCH +%ifdef DEBUG +%token L_TREE +%endif +%ifdef ARRAY_RESERVED_WORD +%token L_ARRAY +%endif +%ifdef REF_RESERVED_WORD +%token L_REF +%endif +%token L_PARSE_COMMAND L_TIME_EXPRESSION +%token L_CLASS L_NEW +%token L_PARAMETER + +%ifdef COMPAT_32 +%token L_LAMBDA +%endif + +/* + * 'Dangling else' shift/reduce conflict is well known... + * define these precedences to shut yacc up. + */ + +%nonassoc LOWER_THAN_ELSE +%nonassoc L_ELSE + +/* + * Operator precedence and associativity... + * greatly simplify the grammar. + */ + +%right L_ASSIGN +%right '?' +%left L_LOR +%left L_LAND +%left '|' +%left '^' +%left '&' +%left L_EQ L_NE +%left L_ORDER '<' +%left L_LSH L_RSH +%left '+' '-' +%left '*' '%' '/' +%right L_NOT '~' +%nonassoc L_INC L_DEC + +/* + * YYTYPE + * + * Anything with size > 4 is commented. Sizes assume typical 32 bit + * architecture. This size of the largest element of this union should + * be kept as small as possible to optimize copying of compiler stack + * elements. + */ +%union +{ + POINTER_INT pointer_int; + long number; + float real; + char *string; + struct { short num_arg; char flags; } argument; + ident_hash_elem_t *ihe; + parse_node_t *node; + function_context_t *contextp; + struct { + parse_node_t *node; + char num; + } decl; /* 5 */ + struct { + char num_local; + char max_num_locals; + short context; + short save_current_type; + short save_exact_types; + } func_block; /* 8 */ +} + + +/* + * Type declarations. + */ + +/* These hold opcodes */ +%type efun_override L_ASSIGN L_ORDER + +/* Holds a variable index */ +%type L_PARAMETER single_new_local_def + +/* These hold arbitrary numbers */ +%type L_NUMBER + +/* These hold numbers that are going to be stuffed into pointers :) + * Don't ask :) + */ +%type constant + +/* These hold a real number */ +%type L_REAL + +/* holds a string constant */ +%type L_STRING string_con1 string_con2 + +/* Holds the number of elements in a list and whether it must be a prototype */ +%type argument_list argument + +/* These hold a list of possible interpretations of an identifier */ +%type L_DEFINED_NAME + +/* These hold a type */ +%type type optional_star type_modifier_list +%type opt_basic_type L_TYPE_MODIFIER L_BASIC_TYPE basic_type atomic_type +%type cast arg_type +%ifdef ARRAY_RESERVED_WORD +%type opt_atomic_type +%endif + +/* This holds compressed and less flexible def_name information */ +%type L_NEW_FUNCTION_OPEN l_new_function_open +%ifdef COMPAT_32 +%type simple_function_pointer +%endif + +/* holds an identifier or some sort */ +%type L_IDENTIFIER L_EFUN function_name identifier +%type new_local_name + +/* The following return a parse node */ +%type number real string expr0 comma_expr for_expr sscanf catch +%type parse_command time_expression expr_list expr_list2 expr_list3 +%type expr_list4 assoc_pair expr4 lvalue function_call lvalue_list +%type new_local_def statement while cond do switch case +%type return optional_else_part block_or_semi +%type case_label statements switch_block +%type expr_list_node expr_or_block +%type single_new_local_def_with_init +%type class_init opt_class_init all def +%type program modifier_change inheritance type_decl +%ifdef DEBUG +%type tree +%endif + +/* The following hold information about blocks and local vars */ +%type local_declarations local_name_list block decl_block +%type foreach_var foreach_vars first_for_expr foreach for + +/* This holds a flag */ +%type new_arg + +%% +%pragma auto_note_compiler_case_start + +all: + program + { + comp_trees[TREE_MAIN] = $$; + } + ; + +program: + program def possible_semi_colon + { + CREATE_TWO_VALUES($$, 0, $1, $2); + } + | /* empty */ + { + $$ = 0; + } + ; + +possible_semi_colon: + /* empty */ + | ';' + { + + yywarn("Extra ';'. Ignored."); + } + ; + + +inheritance: + type_modifier_list L_INHERIT string_con1 ';' + { + object_t *ob; + inherit_t inherit; + int initializer; +%ifdef SENSIBLE_MODIFIERS + int acc_mod; +%endif + + $1 |= global_modifiers; + +%ifdef SENSIBLE_MODIFIERS + acc_mod = ($1 & DECL_ACCESS) & ~global_modifiers; + if (acc_mod & (acc_mod - 1)) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Multiple access modifiers ("); + p = get_type_modifiers(p, end, $1); + p = strput(p, end, ") for inheritance"); + yyerror(buf); + } +%endif + + if (!($1 & DECL_ACCESS)) $1 |= DECL_PUBLIC; +#ifndef ALLOW_INHERIT_AFTER_FUNCTION + if (func_present) + yyerror("Illegal to inherit after defining functions."); +#endif + if (var_defined) + yyerror("Illegal to inherit after defining global variables."); +#ifndef ALLOW_INHERIT_AFTER_FUNCTION + if (func_present || var_defined){ +#else + if (var_defined){ +#endif + inherit_file = 0; + YYACCEPT; + } +#ifdef NEVER + } //stupid bison +#endif + ob = find_object2($3); + if (ob == 0) { + inherit_file = alloc_cstring($3, "inherit"); + /* Return back to load_object() */ + YYACCEPT; + } + scratch_free($3); + inherit.prog = ob->prog; + + if (mem_block[A_INHERITS].current_size){ + inherit_t *prev_inherit = INHERIT(NUM_INHERITS - 1); + + inherit.function_index_offset + = prev_inherit->function_index_offset + + prev_inherit->prog->num_functions_defined + + prev_inherit->prog->last_inherited; + if (prev_inherit->prog->num_functions_defined && + prev_inherit->prog->function_table[prev_inherit->prog->num_functions_defined - 1].funcname[0] == APPLY___INIT_SPECIAL_CHAR) + inherit.function_index_offset--; + } else inherit.function_index_offset = 0; + + inherit.variable_index_offset = + mem_block[A_VAR_TEMP].current_size / + sizeof (variable_t); + inherit.type_mod = $1; + add_to_mem_block(A_INHERITS, (char *)&inherit, sizeof inherit); + + /* The following has to come before copy_vars - Sym */ + copy_structures(ob->prog); + copy_variables(ob->prog, $1); + initializer = copy_functions(ob->prog, $1); + if (initializer >= 0) { + parse_node_t *node, *newnode; + /* initializer is an index into the object we're + inheriting's function table; this finds the + appropriate entry in our table and generates + a call to it */ + node = new_node_no_line(); + node->kind = NODE_CALL_2; + node->r.expr = 0; + node->v.number = F_CALL_INHERITED; + node->l.number = initializer | ((NUM_INHERITS - 1) << 16); + node->type = TYPE_ANY; + + /* The following illustrates a distinction between */ + /* macros and funcs...newnode is needed here - Sym */ + newnode = comp_trees[TREE_INIT]; + CREATE_TWO_VALUES(comp_trees[TREE_INIT],0, newnode, node); + comp_trees[TREE_INIT] = pop_value(comp_trees[TREE_INIT]); + + } + $$ = 0; + } + ; + +real: + L_REAL + { + CREATE_REAL($$, $1); + } + ; + +number: + L_NUMBER + { + CREATE_NUMBER($$, $1); + } + ; + +optional_star: + /* empty */ + { + $$ = 0; + } + | '*' +{ + $$ = TYPE_MOD_ARRAY; + } + ; + +block_or_semi: + block + { + $$ = $1.node; + if (!$$) { + CREATE_RETURN($$, 0); + } + } + | ';' + { + $$ = 0; + } + | error + { + $$ = 0; + } + ; + +identifier: + L_DEFINED_NAME + { + $$ = scratch_copy($1->name); + } + | L_IDENTIFIER + ; + +def: + type optional_star identifier + { + int flags; +%ifdef SENSIBLE_MODIFIERS + int acc_mod; +%endif + func_present = 1; + flags = ($1 >> 16); + + flags |= global_modifiers; + +%ifdef SENSIBLE_MODIFIERS + acc_mod = (flags & DECL_ACCESS) & ~global_modifiers; + if (acc_mod & (acc_mod - 1)) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Multiple access modifiers ("); + p = get_type_modifiers(p, end, flags); + p = strput(p, end, ") for function"); + yyerror(buf); + } +%endif + + if (!(flags & DECL_ACCESS)) flags |= DECL_PUBLIC; +%ifdef SENSIBLE_MODIFIERS + if (flags & DECL_NOSAVE) { + yywarn("Illegal to declare nosave function."); + flags &= ~DECL_NOSAVE; + } +%endif + $1 = (flags << 16) | ($1 & 0xffff); + /* Handle type checking here so we know whether to typecheck + 'argument' */ + if ($1 & 0xffff) { +%ifdef OLD_TYPE_BEHAVIOR + exact_types = 0; +%else + exact_types = ($1& 0xffff) | $2; +%endif + } else { + if (pragmas & PRAGMA_STRICT_TYPES) { + if (strcmp($3, "create") != 0) + yyerror("\"#pragma strict_types\" requires type of function"); + else + exact_types = TYPE_VOID; /* default for create() */ + } else + exact_types = 0; + } + } + '(' argument ')' + { + char *p = $3; + $3 = make_shared_string($3); + scratch_free(p); + + /* If we had nested functions, we would need to check */ + /* here if we have enough space for locals */ + + /* + * Define a prototype. If it is a real function, then the + * prototype will be replaced below. + */ + + $$ = FUNC_PROTOTYPE; + if ($6.flags & ARG_IS_VARARGS) { + $$ |= (FUNC_TRUE_VARARGS | FUNC_VARARGS); + } + $$ |= ($1 >> 16); + + define_new_function($3, $6.num_arg, 0, $$, ($1 & 0xffff)| $2); + /* This is safe since it is guaranteed to be in the + function table, so it can't be dangling */ + free_string($3); + context = 0; + } + block_or_semi + { + /* Either a prototype or a block */ + if ($9) { + int fun; + + $8 &= ~FUNC_PROTOTYPE; + if ($9->kind != NODE_RETURN && + ($9->kind != NODE_TWO_VALUES + || $9->r.expr->kind != NODE_RETURN)) { + parse_node_t *replacement; + CREATE_STATEMENTS(replacement, $9, 0); + CREATE_RETURN(replacement->r.expr, 0); + $9 = replacement; + } + + fun = define_new_function($3, $6.num_arg, + max_num_locals - $6.num_arg, + $8, ($1 & 0xffff) | $2); + if (fun != -1) { + $$ = new_node_no_line(); + $$->kind = NODE_FUNCTION; + $$->v.number = fun; + $$->l.number = max_num_locals; + $$->r.expr = $9; + } else + $$ = 0; + } else + $$ = 0; + free_all_local_names(!!$9); + } + | type name_list ';' + { + if (!($1 & ~(DECL_MODS)) && (pragmas & PRAGMA_STRICT_TYPES)) + yyerror("Missing type for global variable declaration"); + $$ = 0; + } + | inheritance + | type_decl + | modifier_change + ; + +modifier_change: type_modifier_list ':' + { + if (!$1) + yyerror("modifier list may not be empty."); + + if ($1 & FUNC_VARARGS) { + yyerror("Illegal modifier 'varargs' in global modifier list."); + $1 &= ~FUNC_VARARGS; + } + + if (!($1 & DECL_ACCESS)) $1 |= DECL_PUBLIC; + global_modifiers = $1; + $$ = 0; + } + ; + +member_name: + optional_star identifier + { + /* At this point, the current_type here is only a basic_type */ + /* and cannot be unused yet - Sym */ + + if (current_type == TYPE_VOID) + yyerror("Illegal to declare class member of type void."); + add_local_name($2, current_type | $1); + scratch_free($2); + } + ; + +member_name_list: + member_name + | member_name ',' member_name_list + ; + +member_list: + /* empty */ + | member_list basic_type + { + current_type = $2; + } + member_name_list ';' + ; + +type_decl: + type_modifier_list L_CLASS identifier '{' + { + ident_hash_elem_t *ihe; + + ihe = find_or_add_ident( + PROG_STRING($$ = store_prog_string($3)), + FOA_GLOBAL_SCOPE); + if (ihe->dn.class_num == -1) { + ihe->sem_value++; + ihe->dn.class_num = mem_block[A_CLASS_DEF].current_size / sizeof(class_def_t); + if (ihe->dn.class_num > CLASS_NUM_MASK){ + char buf[256]; + char *p; + + p = buf; + sprintf(p, "Too many classes, max is %d.\n", CLASS_NUM_MASK + 1); + yyerror(buf); + } + + scratch_free($3); + $2 = 0; + } + else { + $2 = ihe; + } + } + member_list '}' + { + class_def_t *sd; + class_member_entry_t *sme; + int i, raise_error = 0; + + /* check for a redefinition */ + if ($2 != 0) { + sd = CLASS($2->dn.class_num); + if (sd->size != current_number_of_locals) + raise_error = 1; + else { + i = sd->size; + sme = (class_member_entry_t *)mem_block[A_CLASS_MEMBER].block + sd->index; + while (i--) { + /* check for matching names and types */ + if (strcmp(PROG_STRING(sme[i].membername), locals_ptr[i].ihe->name) != 0 || + sme[i].type != (type_of_locals_ptr[i] & ~LOCAL_MODS)) { + raise_error = 1; + break; + } + } + } + } + + if (raise_error) { + char buf[512]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Illegal to redefine class "); + p = strput(p, end, PROG_STRING($$)); + yyerror(buf); + } else { + sd = (class_def_t *)allocate_in_mem_block(A_CLASS_DEF, sizeof(class_def_t)); + i = sd->size = current_number_of_locals; + sd->index = mem_block[A_CLASS_MEMBER].current_size / sizeof(class_member_entry_t); + sd->classname = $5; + + sme = (class_member_entry_t *)allocate_in_mem_block(A_CLASS_MEMBER, sizeof(class_member_entry_t) * current_number_of_locals); + + while (i--) { + sme[i].membername = store_prog_string(locals_ptr[i].ihe->name); + sme[i].type = type_of_locals_ptr[i] & ~LOCAL_MODS; + } + } + + free_all_local_names(0); + $$ = 0; + } + ; + +new_local_name: + L_IDENTIFIER + | L_DEFINED_NAME + { + if ($1->dn.local_num != -1) { + char buff[256]; + char *end = EndOf(buff); + char *p; + + p = strput(buff, end, "Illegal to redeclare local name '"); + p = strput(p, end, $1->name); + p = strput(p, end, "'"); + yyerror(buff); + } + $$ = scratch_copy($1->name); + } + ; + +atomic_type: + L_BASIC_TYPE + | L_CLASS L_DEFINED_NAME + { + if ($2->dn.class_num == -1) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Undefined class '"); + p = strput(p, end, $2->name); + p = strput(p, end, "'"); + yyerror(buf); + $$ = TYPE_ANY; + } else { + $$ = $2->dn.class_num | TYPE_MOD_CLASS; + } + } + | L_CLASS L_IDENTIFIER + { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Undefined class '"); + p = strput(p, end, $2); + p = strput(p, end, "'"); + yyerror(buf); + $$ = TYPE_ANY; + } + ; + +%ifdef ARRAY_RESERVED_WORD +opt_atomic_type: + atomic_type + | /* empty */ + { + $$ = TYPE_ANY; + } + ; +%endif + +basic_type: + atomic_type +%ifdef ARRAY_RESERVED_WORD + | opt_atomic_type L_ARRAY + { + $$ = $1 | TYPE_MOD_ARRAY; + } +%endif + ; + +arg_type: + basic_type +%ifdef REF_RESERVED_WORD + | basic_type ref + { + $$ = $1 | LOCAL_MOD_REF; + } +%endif + ; + +new_arg: + arg_type optional_star + { + $$ = $1 | $2; + if ($1 != TYPE_VOID) + add_local_name("", $1 | $2); + } + | arg_type optional_star new_local_name + { + if ($1 == TYPE_VOID) + yyerror("Illegal to declare argument of type void."); + add_local_name($3, $1 | $2); + scratch_free($3); + $$ = $1 | $2; + } + | new_local_name + { + if (exact_types) { + yyerror("Missing type for argument"); + } + add_local_name($1, TYPE_ANY); + scratch_free($1); + $$ = TYPE_ANY; + } + ; + +argument: + /* empty */ + { + $$.num_arg = 0; + $$.flags = 0; + } + | argument_list + | argument_list L_DOT_DOT_DOT + { + int x = type_of_locals_ptr[max_num_locals-1]; + int lt = x & ~LOCAL_MODS; + + $$ = $1; + $$.flags |= ARG_IS_VARARGS; + + if (x & LOCAL_MOD_REF) { + yyerror("Variable to hold remainder of args may not be a reference"); + x &= ~LOCAL_MOD_REF; + } + if (lt != TYPE_ANY && !(lt & TYPE_MOD_ARRAY)) + yywarn("Variable to hold remainder of arguments should be an array."); + } + ; + +argument_list: + new_arg + { + if (($1 & TYPE_MASK) == TYPE_VOID && !($1 & TYPE_MOD_CLASS)) { + if ($1 & ~TYPE_MASK) + yyerror("Illegal to declare argument of type void."); + $$.num_arg = 0; + } else { + $$.num_arg = 1; + } + $$.flags = 0; + } + | argument_list ',' new_arg + { + if (!$$.num_arg) /* first arg was void w/no name */ + yyerror("argument of type void must be the only argument."); + if (($3 & TYPE_MASK) == TYPE_VOID && !($3 & TYPE_MOD_CLASS)) + yyerror("Illegal to declare argument of type void."); + + $$ = $1; + $$.num_arg++; + } + ; + +type_modifier_list: + /* empty */ + { + $$ = 0; + } + | L_TYPE_MODIFIER type_modifier_list + { +%ifdef SENSIBLE_MODIFIERS + int acc_mod; +%endif + + $$ = $1 | $2; + +%ifdef SENSIBLE_MODIFIERS + acc_mod = ($$ & DECL_ACCESS) & ~global_modifiers; + if (acc_mod & (acc_mod - 1)) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Multiple access modifiers ("); + p = get_type_modifiers(p, end, $$); + p = strput(p, end, ") "); + yyerror(buf); + $$ = DECL_PUBLIC; + } +%endif + } + ; + +type: + type_modifier_list opt_basic_type + { + $$ = ($1 << 16) | $2; + current_type = $$; + } + ; + +cast: + '(' basic_type optional_star ')' + { + $$ = $2 | $3; + } + ; + +opt_basic_type: + basic_type + | /* empty */ + { + $$ = TYPE_UNKNOWN; + } + ; + +name_list: + new_name + | new_name ',' name_list + ; + +new_name: + optional_star identifier + { + if (current_type & (FUNC_VARARGS << 16)){ + yyerror("Illegal to declare varargs variable."); + current_type &= ~(FUNC_VARARGS << 16); + } + /* Now it is ok to merge the two + * remember that class_num and varargs was the reason for above + * Do the merging once only per row of decls + */ + + if (current_type & 0xffff0000){ + current_type = (current_type >> 16) | (current_type & 0xffff); + } + + current_type |= global_modifiers; + + if (!(current_type & DECL_ACCESS)) current_type |= DECL_PUBLIC; + + if ((current_type & ~DECL_MODS) == TYPE_VOID) + yyerror("Illegal to declare global variable of type void."); + + define_new_variable($2, current_type | $1); + scratch_free($2); + } + | optional_star identifier L_ASSIGN expr0 + { + parse_node_t *expr, *newnode; + int type; + + if (current_type & (FUNC_VARARGS << 16)){ + yyerror("Illegal to declare varargs variable."); + current_type &= ~(FUNC_VARARGS << 16); + } + + if (current_type & 0xffff0000){ + current_type = (current_type >> 16) | (current_type & 0xffff); + } + + current_type |= global_modifiers; + + if (!(current_type & DECL_ACCESS)) current_type |= DECL_PUBLIC; + + if ((current_type & ~DECL_MODS) == TYPE_VOID) + yyerror("Illegal to declare global variable of type void."); + + if ($3 != F_ASSIGN) + yyerror("Only '=' is legal in initializers."); + + /* ignore current_type == 0, which gets a missing type error + later anyway */ + if (current_type) { + type = (current_type | $1) & ~DECL_MODS; + if ((current_type & ~DECL_MODS) == TYPE_VOID) + yyerror("Illegal to declare global variable of type void."); + if (!compatible_types(type, $4->type)) { + char buff[256]; + char *end = EndOf(buff); + char *p; + + p = strput(buff, end, "Type mismatch "); + p = get_two_types(p, end, type, $4->type); + p = strput(p, end, " when initializing "); + p = strput(p, end, $2); + yyerror(buff); + } + } else type = 0; + $4 = do_promotions($4, type); + + CREATE_BINARY_OP(expr, F_VOID_ASSIGN, 0, $4, 0); + CREATE_OPCODE_1(expr->r.expr, F_GLOBAL_LVALUE, 0, + define_new_variable($2, current_type | $1)); + newnode = comp_trees[TREE_INIT]; + CREATE_TWO_VALUES(comp_trees[TREE_INIT], 0, + newnode, expr); + scratch_free($2); + } + ; + +block: + '{' local_declarations statements '}' + { + if ($2.node && $3) { + CREATE_STATEMENTS($$.node, $2.node, $3); + } else $$.node = ($2.node ? $2.node : $3); + $$.num = $2.num; + } + ; + +decl_block: block | for | foreach ; + +local_declarations: + /* empty */ + { + $$.node = 0; + $$.num = 0; + } + | local_declarations basic_type + { + if ($2 == TYPE_VOID) + yyerror("Illegal to declare local variable of type void."); + /* can't do this in basic_type b/c local_name_list contains + * expr0 which contains cast which contains basic_type + */ + current_type = $2; + } + local_name_list ';' + { + if ($1.node && $4.node) { + CREATE_STATEMENTS($$.node, $1.node, $4.node); + } else $$.node = ($1.node ? $1.node : $4.node); + $$.num = $1.num + $4.num; + } + ; + + +new_local_def: + optional_star new_local_name + { + if (current_type & LOCAL_MOD_REF) { + yyerror("Illegal to declare local variable as reference"); + current_type &= ~LOCAL_MOD_REF; + } + add_local_name($2, current_type | $1 | LOCAL_MOD_UNUSED); + + scratch_free($2); + $$ = 0; + } + | optional_star new_local_name L_ASSIGN expr0 + { + int type = (current_type | $1) & ~DECL_MODS; + + if (current_type & LOCAL_MOD_REF) { + yyerror("Illegal to declare local variable as reference"); + current_type &= ~LOCAL_MOD_REF; + type &= ~LOCAL_MOD_REF; + } + + if ($3 != F_ASSIGN) + yyerror("Only '=' is allowed in initializers."); + if (!compatible_types($4->type, type)) { + char buff[256]; + char *end = EndOf(buff); + char *p; + + p = strput(buff, end, "Type mismatch "); + p = get_two_types(p, end, type, $4->type); + p = strput(p, end, " when initializing "); + p = strput(p, end, $2); + + yyerror(buff); + } + + $4 = do_promotions($4, type); + + CREATE_UNARY_OP_1($$, F_VOID_ASSIGN_LOCAL, 0, $4, + add_local_name($2, current_type | $1 | LOCAL_MOD_UNUSED)); + scratch_free($2); + } + ; + +single_new_local_def: + arg_type optional_star new_local_name + { + if ($1 == TYPE_VOID) + yyerror("Illegal to declare local variable of type void."); + + $$ = add_local_name($3, $1 | $2); + scratch_free($3); + } + ; + +single_new_local_def_with_init: + single_new_local_def L_ASSIGN expr0 + { + int type = type_of_locals_ptr[$1]; + + if (type & LOCAL_MOD_REF) { + yyerror("Illegal to declare local variable as reference"); + type_of_locals_ptr[$1] &= ~LOCAL_MOD_REF; + } + type &= ~LOCAL_MODS; + + if ($2 != F_ASSIGN) + yyerror("Only '=' is allowed in initializers."); + if (!compatible_types($3->type, type)) { + char buff[256]; + char *end = EndOf(buff); + char *p; + + p = strput(buff, end, "Type mismatch "); + p = get_two_types(p, end, type, $3->type); + p = strput(p, end, " when initializing."); + yyerror(buff); + } + + $3 = do_promotions($3, type); + + /* this is an expression */ + CREATE_BINARY_OP($$, F_ASSIGN, 0, $3, 0); + CREATE_OPCODE_1($$->r.expr, F_LOCAL_LVALUE, 0, $1); + } + ; + +local_name_list: + new_local_def + { + $$.node = $1; + $$.num = 1; + } + | new_local_def ',' local_name_list + { + if ($1 && $3.node) { + CREATE_STATEMENTS($$.node, $1, $3.node); + } else $$.node = ($1 ? $1 : $3.node); + $$.num = 1 + $3.num; + } + ; + +statements: + /* empty */ + { + $$ = 0; + } + | statement statements + { + if ($1 && $2) { + CREATE_STATEMENTS($$, $1, $2); + } else $$ = ($1 ? $1 : $2); + } + | error ';' + { + $$ = 0; + } + ; + +statement: + comma_expr ';' + { + $$ = pop_value($1); +#ifdef DEBUG + { + parse_node_t *replacement; + CREATE_STATEMENTS(replacement, $$, 0); + CREATE_OPCODE(replacement->r.expr, F_BREAK_POINT, 0); + $$ = replacement; + } +#endif + } + | cond + | while + | do + | switch + | return + | decl_block + { + $$ = $1.node; + pop_n_locals($1.num); + } + | /* empty */ ';' + { + $$ = 0; + } + | L_BREAK ';' + { + if (context & SPECIAL_CONTEXT) { + yyerror("Cannot break out of catch { } or time_expression { }"); + $$ = 0; + } else + if (context & SWITCH_CONTEXT) { + CREATE_CONTROL_JUMP($$, CJ_BREAK_SWITCH); + } else + if (context & LOOP_CONTEXT) { + CREATE_CONTROL_JUMP($$, CJ_BREAK); + if (context & LOOP_FOREACH) { + parse_node_t *replace; + CREATE_STATEMENTS(replace, 0, $$); + CREATE_OPCODE(replace->l.expr, F_EXIT_FOREACH, 0); + $$ = replace; + } + } else { + yyerror("break statement outside loop"); + $$ = 0; + } + } + | L_CONTINUE ';' + { + if (context & SPECIAL_CONTEXT) + yyerror("Cannot continue out of catch { } or time_expression { }"); + else + if (!(context & LOOP_CONTEXT)) + yyerror("continue statement outside loop"); + CREATE_CONTROL_JUMP($$, CJ_CONTINUE); + } + ; + +while: + L_WHILE '(' comma_expr ')' + { + $1 = context; + context = LOOP_CONTEXT; + } + statement + { + CREATE_LOOP($$, 1, $6, 0, optimize_loop_test($3)); + context = $1; + } + ; + +do: + L_DO + { + $1 = context; + context = LOOP_CONTEXT; + } + statement L_WHILE '(' comma_expr ')' ';' + { + CREATE_LOOP($$, 0, $3, 0, optimize_loop_test($6)); + context = $1; + } + ; + +for: + L_FOR '(' first_for_expr ';' for_expr ';' for_expr ')' + { + $3.node = pop_value($3.node); + $1 = context; + context = LOOP_CONTEXT; + } + statement + { + $$.num = $3.num; /* number of declarations (0/1) */ + + $7 = pop_value($7); + if ($7 && IS_NODE($7, NODE_UNARY_OP, F_INC) + && IS_NODE($7->r.expr, NODE_OPCODE_1, F_LOCAL_LVALUE)) { + long lvar = $7->r.expr->l.number; + CREATE_OPCODE_1($7, F_LOOP_INCR, 0, lvar); + } + + CREATE_STATEMENTS($$.node, $3.node, 0); + CREATE_LOOP($$.node->r.expr, 1, $10, $7, optimize_loop_test($5)); + + context = $1; + } + ; + +foreach_var: L_DEFINED_NAME + { + if ($1->dn.local_num != -1) { + CREATE_OPCODE_1($$.node, F_LOCAL_LVALUE, 0, $1->dn.local_num); + type_of_locals_ptr[$1->dn.local_num] &= ~LOCAL_MOD_UNUSED; + } else + if ($1->dn.global_num != -1) { + CREATE_OPCODE_1($$.node, F_GLOBAL_LVALUE, 0, $1->dn.global_num); + } else { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "'"); + p = strput(p, end, $1->name); + p = strput(p, end, "' is not a local or a global variable."); + yyerror(buf); + CREATE_OPCODE_1($$.node, F_GLOBAL_LVALUE, 0, 0); + } + $$.num = 0; + } + | single_new_local_def + { + if (type_of_locals_ptr[$1] & LOCAL_MOD_REF) { + CREATE_OPCODE_1($$.node, F_REF_LVALUE, 0, $1); + } else { + CREATE_OPCODE_1($$.node, F_LOCAL_LVALUE, 0, $1); + type_of_locals_ptr[$1] &= ~LOCAL_MOD_UNUSED; + } + $$.num = 1; + } + | L_IDENTIFIER + { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "'"); + p = strput(p, end, $1); + p = strput(p, end, "' is not a local or a global variable."); + yyerror(buf); + CREATE_OPCODE_1($$.node, F_GLOBAL_LVALUE, 0, 0); + scratch_free($1); + $$.num = 0; + } + ; + +foreach_vars: + foreach_var + { + CREATE_FOREACH($$.node, $1.node, 0); + $$.num = $1.num; + } + | foreach_var ',' foreach_var + { + CREATE_FOREACH($$.node, $1.node, $3.node); + $$.num = $1.num + $3.num; + if ($1.node->v.number == F_REF_LVALUE) + yyerror("Mapping key may not be a reference in foreach()"); + } + ; + +foreach: + L_FOREACH '(' foreach_vars L_IN expr0 ')' + { + $3.node->v.expr = $5; + $1 = context; + context = LOOP_CONTEXT | LOOP_FOREACH; + } + statement + { + $$.num = $3.num; + + CREATE_STATEMENTS($$.node, $3.node, 0); + CREATE_LOOP($$.node->r.expr, 2, $8, 0, 0); + CREATE_OPCODE($$.node->r.expr->r.expr, F_NEXT_FOREACH, 0); + + context = $1; + } + ; + +for_expr: + /* EMPTY */ + { + $$ = 0; + } + | comma_expr + ; + +first_for_expr: + for_expr + { + $$.node = $1; + $$.num = 0; + } + | single_new_local_def_with_init + { + $$.node = $1; + $$.num = 1; + } + ; + + switch: + L_SWITCH '(' comma_expr ')' + { + $1 = context; + context &= LOOP_CONTEXT; + context |= SWITCH_CONTEXT; + $2 = mem_block[A_CASES].current_size; + } + '{' local_declarations case switch_block '}' + { + parse_node_t *node1, *node2; + + if ($9) { + CREATE_STATEMENTS(node1, $8, $9); + } else node1 = $8; + + if (context & SWITCH_STRINGS) { + NODE_NO_LINE(node2, NODE_SWITCH_STRINGS); + } else if (context & SWITCH_RANGES) { + NODE_NO_LINE(node2, NODE_SWITCH_RANGES); + } else if ((context & SWITCH_NUMBERS) || + (context & SWITCH_NOT_EMPTY)) { + NODE_NO_LINE(node2, NODE_SWITCH_NUMBERS); + } else { + // to prevent crashing during the remaining parsing bits + NODE_NO_LINE(node2, NODE_SWITCH_NUMBERS); + + yyerror("need case statements in switch/case, not just default:"); //just a default case present + } + + node2->l.expr = $3; + node2->r.expr = node1; + prepare_cases(node2, $2); + context = $1; + $$ = node2; + pop_n_locals($7.num); + } + ; + + switch_block: + case switch_block + { + if ($2){ + CREATE_STATEMENTS($$, $1, $2); + } else $$ = $1; + } + | statement switch_block + { + if ($2){ + CREATE_STATEMENTS($$, $1, $2); + } else $$ = $1; + } + | /* empty */ + { + $$ = 0; + } + + ; + + case: + L_CASE case_label ':' + { + $$ = $2; + $$->v.expr = 0; + + add_to_mem_block(A_CASES, (char *)&($2), sizeof($2)); + } + | L_CASE case_label L_RANGE case_label ':' + { + if ( $2->kind != NODE_CASE_NUMBER + || $4->kind != NODE_CASE_NUMBER ) + yyerror("String case labels not allowed as range bounds"); + if ($2->r.number > $4->r.number) break; + + context |= SWITCH_RANGES; + + $$ = $2; + $$->v.expr = $4; + + add_to_mem_block(A_CASES, (char *)&($2), sizeof($2)); + } + | L_CASE case_label L_RANGE ':' + { + if ( $2->kind != NODE_CASE_NUMBER ) + yyerror("String case labels not allowed as range bounds"); + + context |= SWITCH_RANGES; + + $$ = $2; + $$->v.expr = new_node(); + $$->v.expr->kind = NODE_CASE_NUMBER; + $$->v.expr->r.number = ((unsigned long)-1)/2; //maxint + + add_to_mem_block(A_CASES, (char *)&($2), sizeof($2)); + } + | L_CASE L_RANGE case_label ':' + { + if ( $3->kind != NODE_CASE_NUMBER ) + yyerror("String case labels not allowed as range bounds"); + + context |= SWITCH_RANGES; + $$ = new_node(); + $$->kind = NODE_CASE_NUMBER; + $$->r.number = (long) 1+ ((unsigned long)-1)/2; //maxint +1 wraps to min_int, on all computers i know, just not in the C standard iirc + $$->v.expr = $3; + + add_to_mem_block(A_CASES, (char *)&($$), sizeof($$)); + } + | L_DEFAULT ':' + { + if (context & SWITCH_DEFAULT) { + yyerror("Duplicate default"); + $$ = 0; + break; + } + $$ = new_node(); + $$->kind = NODE_DEFAULT; + $$->v.expr = 0; + add_to_mem_block(A_CASES, (char *)&($$), sizeof($$)); + context |= SWITCH_DEFAULT; + } + ; + + case_label: + constant + { + if ((context & SWITCH_STRINGS) && $1) + yyerror("Mixed case label list not allowed"); + + if ($1) + context |= SWITCH_NUMBERS; + else + context |= SWITCH_NOT_EMPTY; + + $$ = new_node(); + $$->kind = NODE_CASE_NUMBER; + $$->r.expr = (parse_node_t *)$1; + } + | string_con1 + { + int str; + + str = store_prog_string($1); + scratch_free($1); + if (context & SWITCH_NUMBERS) + yyerror("Mixed case label list not allowed"); + context |= SWITCH_STRINGS; + $$ = new_node(); + $$->kind = NODE_CASE_STRING; + $$->r.number = str; + } + ; + + constant: + constant '|' constant + { + $$ = $1 | $3; + } + | constant '^' constant + { + $$ = $1 ^ $3; + } + | constant '&' constant + { + $$ = $1 & $3; + } + | constant L_EQ constant + { + $$ = $1 == $3; + } + | constant L_NE constant + { + $$ = $1 != $3; + } + | constant L_ORDER constant + { + switch($2){ + case F_GE: $$ = $1 >= $3; break; + case F_LE: $$ = $1 <= $3; break; + case F_GT: $$ = $1 > $3; break; + } + } + | constant '<' constant + { + $$ = $1 < $3; + } + | constant L_LSH constant + { + $$ = $1 << $3; + } + | constant L_RSH constant + { + $$ = $1 >> $3; + } + | constant '+' constant + { + $$ = $1 + $3; + } + | constant '-' constant + { + $$ = $1 - $3; + } + | constant '*' constant + { + $$ = $1 * $3; + } + | constant '%' constant + { + if ($3) $$ = $1 % $3; else yyerror("Modulo by zero"); + } + | constant '/' constant + { + if ($3) $$ = $1 / $3; else yyerror("Division by zero"); + } + | '(' constant ')' + { + $$ = $2; + } + | L_NUMBER + { + $$ = $1; + } + | '-' L_NUMBER + { + $$ = -$2; + } + | L_NOT L_NUMBER + { + $$ = !$2; + } + | '~' L_NUMBER + { + $$ = ~$2; + } + ; + +comma_expr: + expr0 + { + $$ = $1; + } + | comma_expr ',' expr0 + { + CREATE_TWO_VALUES($$, $3->type, pop_value($1), $3); + } + ; + +%ifdef REF_RESERVED_WORD +ref: + L_REF +%ifdef COMPAT_32 + | '&' +%endif + ; +%endif + +expr0: +%ifdef REF_RESERVED_WORD + ref lvalue + { + int op; + + if (!(context & ARG_LIST)) + yyerror("ref illegal outside function argument list"); + else + num_refs++; + + switch ($2->kind) { + case NODE_PARAMETER_LVALUE: + op = F_LOCAL_LVALUE; + break; + case NODE_TERNARY_OP: + case NODE_OPCODE_1: + case NODE_UNARY_OP_1: + case NODE_BINARY_OP: + op = $2->v.number; + if (op > F_RINDEX_LVALUE) + yyerror("Illegal to make reference to range"); + break; + default: + op=0; //0 is harmless, i hope + yyerror("unknown lvalue kind"); + } + CREATE_UNARY_OP_1($$, F_MAKE_REF, TYPE_ANY, $2, op); + } + | +%endif + lvalue L_ASSIGN expr0 + { + parse_node_t *l = $1, *r = $3; + /* set this up here so we can change it below */ + /* assignments are backwards; rhs is evaluated before + lhs, so put the RIGHT hand side on the LEFT hand + side of the tree node. */ + CREATE_BINARY_OP($$, $2, r->type, r, l); + + if (exact_types && !compatible_types(r->type, l->type) && + !($2 == F_ADD_EQ + && l->type == TYPE_STRING && + (COMP_TYPE(r->type, TYPE_NUMBER))||r->type == TYPE_OBJECT)) { + char buf[256]; + char *end = EndOf(buf); + char *p; + p = strput(buf, end, "Bad assignment "); + p = get_two_types(p, end, l->type, r->type); + p = strput(p, end, "."); + yyerror(buf); + } + + if ($2 == F_ASSIGN) + $$->l.expr = do_promotions(r, l->type); + } + | error L_ASSIGN expr0 + { + yyerror("Illegal LHS"); + CREATE_ERROR($$); + } + | expr0 '?' expr0 ':' expr0 %prec '?' + { + parse_node_t *p1 = $3, *p2 = $5; + + if (exact_types && !compatible_types2(p1->type, p2->type)) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Types in ?: do not match "); + p = get_two_types(p, end, p1->type, p2->type); + p = strput(p, end, "."); + yywarn(buf); + } + + /* optimize if last expression did F_NOT */ + if (IS_NODE($1, NODE_UNARY_OP, F_NOT)) { + /* !a ? b : c --> a ? c : b */ + CREATE_IF($$, $1->r.expr, p2, p1); + } else { + CREATE_IF($$, $1, p1, p2); + } + $$->type = ((p1->type == p2->type) ? p1->type : TYPE_ANY); + } + | expr0 L_LOR expr0 + { + CREATE_LAND_LOR($$, F_LOR, $1, $3); + if (IS_NODE($1, NODE_LAND_LOR, F_LOR)) + $1->kind = NODE_BRANCH_LINK; + } + | expr0 L_LAND expr0 + { + CREATE_LAND_LOR($$, F_LAND, $1, $3); + if (IS_NODE($1, NODE_LAND_LOR, F_LAND)) + $1->kind = NODE_BRANCH_LINK; + } + | expr0 '|' expr0 + { + int t1 = $1->type, t3 = $3->type; + + if (is_boolean($1) && is_boolean($3)) + yywarn("bitwise operation on boolean values."); + if ((t1 & TYPE_MOD_ARRAY) || (t3 & TYPE_MOD_ARRAY)) { + if (t1 != t3) { + if ((t1 != TYPE_ANY) && (t3 != TYPE_ANY) && + !(t1 & t3 & TYPE_MOD_ARRAY)) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Incompatible types for | "); + p = get_two_types(p, end, t1, t3); + p = strput(p, end, "."); + yyerror(buf); + } + t1 = TYPE_ANY | TYPE_MOD_ARRAY; + } + CREATE_BINARY_OP($$, F_OR, t1, $1, $3); + } + else $$ = binary_int_op($1, $3, F_OR, "|"); + } + | expr0 '^' expr0 + { + $$ = binary_int_op($1, $3, F_XOR, "^"); + } + | expr0 '&' expr0 + { + int t1 = $1->type, t3 = $3->type; + if (is_boolean($1) && is_boolean($3)) + yywarn("bitwise operation on boolean values."); + if ((t1 & TYPE_MOD_ARRAY) || (t3 & TYPE_MOD_ARRAY)) { + if (t1 != t3) { + if ((t1 != TYPE_ANY) && (t3 != TYPE_ANY) && + !(t1 & t3 & TYPE_MOD_ARRAY)) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Incompatible types for & "); + p = get_two_types(p, end, t1, t3); + p = strput(p, end, "."); + yyerror(buf); + } + t1 = TYPE_ANY | TYPE_MOD_ARRAY; + } + CREATE_BINARY_OP($$, F_AND, t1, $1, $3); + } else $$ = binary_int_op($1, $3, F_AND, "&"); + } + | expr0 L_EQ expr0 + { + if (exact_types && !compatible_types2($1->type, $3->type)){ + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "== always false because of incompatible types "); + p = get_two_types(p, end, $1->type, $3->type); + p = strput(p, end, "."); + yyerror(buf); + } + /* x == 0 -> !x */ + if (IS_NODE($1, NODE_NUMBER, 0)) { + CREATE_UNARY_OP($$, F_NOT, TYPE_NUMBER, $3); + } else + if (IS_NODE($3, NODE_NUMBER, 0)) { + CREATE_UNARY_OP($$, F_NOT, TYPE_NUMBER, $1); + } else { + CREATE_BINARY_OP($$, F_EQ, TYPE_NUMBER, $1, $3); + } + } + | expr0 L_NE expr0 + { + if (exact_types && !compatible_types2($1->type, $3->type)){ + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "!= always true because of incompatible types "); + p = get_two_types(p, end, $1->type, $3->type); + p = strput(p, end, "."); + yyerror(buf); + } + CREATE_BINARY_OP($$, F_NE, TYPE_NUMBER, $1, $3); + } + | expr0 L_ORDER expr0 + { + if (exact_types) { + int t1 = $1->type; + int t3 = $3->type; + + if (!COMP_TYPE(t1, TYPE_NUMBER) + && !COMP_TYPE(t1, TYPE_STRING)) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Bad left argument to '"); + p = strput(p, end, query_instr_name($2)); + p = strput(p, end, "' : \""); + p = get_type_name(p, end, t1); + p = strput(p, end, "\""); + yyerror(buf); + } else if (!COMP_TYPE(t3, TYPE_NUMBER) + && !COMP_TYPE(t3, TYPE_STRING)) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Bad right argument to '"); + p = strput(p, end, query_instr_name($2)); + p = strput(p, end, "' : \""); + p = get_type_name(p, end, t3); + p = strput(p, end, "\""); + yyerror(buf); + } else if (!compatible_types2(t1,t3)) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Arguments to "); + p = strput(p, end, query_instr_name($2)); + p = strput(p, end, " do not have compatible types : "); + p = get_two_types(p, end, t1, t3); + yyerror(buf); + } + } + CREATE_BINARY_OP($$, $2, TYPE_NUMBER, $1, $3); + } + | expr0 '<' expr0 + { + if (exact_types) { + int t1 = $1->type, t3 = $3->type; + + if (!COMP_TYPE(t1, TYPE_NUMBER) + && !COMP_TYPE(t1, TYPE_STRING)) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Bad left argument to '<' : \""); + p = get_type_name(p, end, t1); + p = strput(p, end, "\""); + yyerror(buf); + } else if (!COMP_TYPE(t3, TYPE_NUMBER) + && !COMP_TYPE(t3, TYPE_STRING)) { + char buf[200]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Bad right argument to '<' : \""); + p = get_type_name(p, end, t3); + p = strput(p, end, "\""); + yyerror(buf); + } else if (!compatible_types2(t1,t3)) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Arguments to < do not have compatible types : "); + p = get_two_types(p, end, t1, t3); + yyerror(buf); + } + } + CREATE_BINARY_OP($$, F_LT, TYPE_NUMBER, $1, $3); + } + | expr0 L_LSH expr0 + { + $$ = binary_int_op($1, $3, F_LSH, "<<"); + } + | expr0 L_RSH expr0 + { + $$ = binary_int_op($1, $3, F_RSH, ">>"); + } + | expr0 '+' expr0 + { + int result_type; + + if (exact_types) { + int t1 = $1->type, t3 = $3->type; + + if (t1 == t3){ +#ifdef CAST_CALL_OTHERS + if (t1 == TYPE_UNKNOWN){ + yyerror("Bad arguments to '+' (unknown vs unknown)"); + result_type = TYPE_ANY; + } else +#endif + result_type = t1; + } + else if (t1 == TYPE_ANY) { + if (t3 == TYPE_FUNCTION) { + yyerror("Bad right argument to '+' (function)"); + result_type = TYPE_ANY; + } else result_type = t3; + } else if (t3 == TYPE_ANY) { + if (t1 == TYPE_FUNCTION) { + yyerror("Bad left argument to '+' (function)"); + result_type = TYPE_ANY; + } else result_type = t1; + } else { + switch(t1) { + case TYPE_OBJECT: + if(t3 == TYPE_STRING){ + result_type = TYPE_STRING; + } else goto add_error; + break; + case TYPE_STRING: + { + if (t3 == TYPE_REAL || t3 == TYPE_NUMBER || t3 == TYPE_OBJECT){ + result_type = TYPE_STRING; + } else goto add_error; + break; + } + case TYPE_NUMBER: + { + if (t3 == TYPE_REAL || t3 == TYPE_STRING) + result_type = t3; + else goto add_error; + break; + } + case TYPE_REAL: + { + if (t3 == TYPE_NUMBER) result_type = TYPE_REAL; + else if (t3 == TYPE_STRING) result_type = TYPE_STRING; + else goto add_error; + break; + } + default: + { + if (t1 & t3 & TYPE_MOD_ARRAY) { + result_type = TYPE_ANY|TYPE_MOD_ARRAY; + break; + } + add_error: + { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Invalid argument types to '+' "); + p = get_two_types(p, end, t1, t3); + yyerror(buf); + result_type = TYPE_ANY; + } + } + } + } + } else + result_type = TYPE_ANY; + + /* TODO: perhaps we should do (string)+(number) and + * (number)+(string) constant folding as well. + * + * codefor string x = "foo" + 1; + * + * 0000: push string 13, number 1 + * 0004: + + * 0005: (void)assign_local LV0 + */ + switch ($1->kind) { + case NODE_NUMBER: + /* 0 + X */ + if ($1->v.number == 0 && + ($3->type == TYPE_NUMBER || $3->type == TYPE_REAL)) { + $$ = $3; + break; + } + if ($3->kind == NODE_NUMBER) { + $$ = $1; + $1->v.number += $3->v.number; + break; + } + if ($3->kind == NODE_REAL) { + $$ = $3; + $3->v.real += $1->v.number; + break; + } + /* swapping the nodes may help later constant folding */ + if ($3->type != TYPE_STRING && $3->type != TYPE_ANY) + CREATE_BINARY_OP($$, F_ADD, result_type, $3, $1); + else + CREATE_BINARY_OP($$, F_ADD, result_type, $1, $3); + break; + case NODE_REAL: + if ($3->kind == NODE_NUMBER) { + $$ = $1; + $1->v.real += $3->v.number; + break; + } + if ($3->kind == NODE_REAL) { + $$ = $1; + $1->v.real += $3->v.real; + break; + } + /* swapping the nodes may help later constant folding */ + if ($3->type != TYPE_STRING && $3->type != TYPE_ANY) + CREATE_BINARY_OP($$, F_ADD, result_type, $3, $1); + else + CREATE_BINARY_OP($$, F_ADD, result_type, $1, $3); + break; + case NODE_STRING: + if ($3->kind == NODE_STRING) { + /* Combine strings */ + long n1, n2; + const char *s1, *s2; + char *news; + int l; + + n1 = $1->v.number; + n2 = $3->v.number; + s1 = PROG_STRING(n1); + s2 = PROG_STRING(n2); + news = (char *)DXALLOC( (l = strlen(s1))+strlen(s2)+1, TAG_COMPILER, "combine string" ); + strcpy(news, s1); + strcat(news + l, s2); + /* free old strings (ordering may help shrink table) */ + if (n1 > n2) { + free_prog_string(n1); free_prog_string(n2); + } else { + free_prog_string(n2); free_prog_string(n1); + } + $$ = $1; + $$->v.number = store_prog_string(news); + FREE(news); + break; + } + /* Yes, this can actually happen for absurd code like: + * (int)"foo" + 0 + * for which I guess we ought to generate (int)"foo" + * in order to be consistent. Then shoot the coder. + */ + /* FALLTHROUGH */ + default: + /* X + 0 */ + if (IS_NODE($3, NODE_NUMBER, 0) && + ($1->type == TYPE_NUMBER || $1->type == TYPE_REAL)) { + $$ = $1; + break; + } + CREATE_BINARY_OP($$, F_ADD, result_type, $1, $3); + break; + } + } + | expr0 '-' expr0 + { + int result_type; + + if (exact_types) { + int t1 = $1->type, t3 = $3->type; + + if (t1 == t3){ + switch(t1){ + case TYPE_ANY: + case TYPE_NUMBER: + case TYPE_REAL: + result_type = t1; + break; + default: + if (!(t1 & TYPE_MOD_ARRAY)){ + type_error("Bad argument number 1 to '-'", t1); + result_type = TYPE_ANY; + } else result_type = t1; + } + } else if (t1 == TYPE_ANY){ + switch(t3){ + case TYPE_REAL: + case TYPE_NUMBER: + result_type = t3; + break; + default: + if (!(t3 & TYPE_MOD_ARRAY)){ + type_error("Bad argument number 2 to '-'", t3); + result_type = TYPE_ANY; + } else result_type = t3; + } + } else if (t3 == TYPE_ANY){ + switch(t1){ + case TYPE_REAL: + case TYPE_NUMBER: + result_type = t1; + break; + default: + if (!(t1 & TYPE_MOD_ARRAY)){ + type_error("Bad argument number 1 to '-'", t1); + result_type = TYPE_ANY; + } else result_type = t1; + } + } else if ((t1 == TYPE_REAL && t3 == TYPE_NUMBER) || + (t3 == TYPE_REAL && t1 == TYPE_NUMBER)){ + result_type = TYPE_REAL; + } else if (t1 & t3 & TYPE_MOD_ARRAY){ + result_type = TYPE_MOD_ARRAY|TYPE_ANY; + } else { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Invalid types to '-' "); + p = get_two_types(p, end, t1, t3); + yyerror(buf); + result_type = TYPE_ANY; + } + } else result_type = TYPE_ANY; + + switch ($1->kind) { + case NODE_NUMBER: + if ($1->v.number == 0) { + CREATE_UNARY_OP($$, F_NEGATE, $3->type, $3); + } else if ($3->kind == NODE_NUMBER) { + $$ = $1; + $1->v.number -= $3->v.number; + } else if ($3->kind == NODE_REAL) { + $$ = $3; + $3->v.real = $1->v.number - $3->v.real; + } else { + CREATE_BINARY_OP($$, F_SUBTRACT, result_type, $1, $3); + } + break; + case NODE_REAL: + if ($3->kind == NODE_NUMBER) { + $$ = $1; + $1->v.real -= $3->v.number; + } else if ($3->kind == NODE_REAL) { + $$ = $1; + $1->v.real -= $3->v.real; + } else { + CREATE_BINARY_OP($$, F_SUBTRACT, result_type, $1, $3); + } + break; + default: + /* optimize X-0 */ + if (IS_NODE($3, NODE_NUMBER, 0)) { + $$ = $1; + } + CREATE_BINARY_OP($$, F_SUBTRACT, result_type, $1, $3); + } + } + | expr0 '*' expr0 + { + int result_type; + + if (exact_types){ + int t1 = $1->type, t3 = $3->type; + + if (t1 == t3){ + switch(t1){ + case TYPE_MAPPING: + case TYPE_ANY: + case TYPE_NUMBER: + case TYPE_REAL: + result_type = t1; + break; + default: + type_error("Bad argument number 1 to '*'", t1); + result_type = TYPE_ANY; + } + } else if (t1 == TYPE_ANY || t3 == TYPE_ANY){ + int t = (t1 == TYPE_ANY) ? t3 : t1; + switch(t){ + case TYPE_NUMBER: + case TYPE_REAL: + case TYPE_MAPPING: + result_type = t; + break; + default: + type_error((t1 == TYPE_ANY) ? + "Bad argument number 2 to '*'" : + "Bad argument number 1 to '*'", + t); + result_type = TYPE_ANY; + } + } else if ((t1 == TYPE_NUMBER && t3 == TYPE_REAL) || + (t1 == TYPE_REAL && t3 == TYPE_NUMBER)){ + result_type = TYPE_REAL; + } else { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Invalid types to '*' "); + p = get_two_types(p, end, t1, t3); + yyerror(buf); + result_type = TYPE_ANY; + } + } else result_type = TYPE_ANY; + + switch ($1->kind) { + case NODE_NUMBER: + if ($3->kind == NODE_NUMBER) { + $$ = $1; + $$->v.number *= $3->v.number; + break; + } + if ($3->kind == NODE_REAL) { + $$ = $3; + $3->v.real *= $1->v.number; + break; + } + CREATE_BINARY_OP($$, F_MULTIPLY, result_type, $3, $1); + break; + case NODE_REAL: + if ($3->kind == NODE_NUMBER) { + $$ = $1; + $1->v.real *= $3->v.number; + break; + } + if ($3->kind == NODE_REAL) { + $$ = $1; + $1->v.real *= $3->v.real; + break; + } + CREATE_BINARY_OP($$, F_MULTIPLY, result_type, $3, $1); + break; + default: + CREATE_BINARY_OP($$, F_MULTIPLY, result_type, $1, $3); + } + } + | expr0 '%' expr0 + { + $$ = binary_int_op($1, $3, F_MOD, "%"); + } + | expr0 '/' expr0 + { + int result_type; + + if (exact_types){ + int t1 = $1->type, t3 = $3->type; + + if (t1 == t3){ + switch(t1){ + case TYPE_NUMBER: + case TYPE_REAL: + case TYPE_ANY: + result_type = t1; + break; + default: + type_error("Bad argument 1 to '/'", t1); + result_type = TYPE_ANY; + } + } else if (t1 == TYPE_ANY || t3 == TYPE_ANY){ + int t = (t1 == TYPE_ANY) ? t3 : t1; + if (t == TYPE_REAL || t == TYPE_NUMBER) + result_type = t; + else { + type_error(t1 == TYPE_ANY ? + "Bad argument 2 to '/'" : + "Bad argument 1 to '/'", t); + result_type = TYPE_ANY; + } + } else if ((t1 == TYPE_NUMBER && t3 == TYPE_REAL) || + (t1 == TYPE_REAL && t3 == TYPE_NUMBER)) { + result_type = TYPE_REAL; + } else { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Invalid types to '/' "); + p = get_two_types(p, end, t1, t3); + yyerror(buf); + result_type = TYPE_ANY; + } + } else result_type = TYPE_ANY; + + /* constant expressions */ + switch ($1->kind) { + case NODE_NUMBER: + if ($3->kind == NODE_NUMBER) { + if ($3->v.number == 0) { + yyerror("Divide by zero in constant"); + $$ = $1; + break; + } + $$ = $1; + $1->v.number /= $3->v.number; + break; + } + if ($3->kind == NODE_REAL) { + if ($3->v.real == 0.0) { + yyerror("Divide by zero in constant"); + $$ = $1; + break; + } + $$ = $3; + $3->v.real = ($1->v.number / $3->v.real); + break; + } + CREATE_BINARY_OP($$, F_DIVIDE, result_type, $1, $3); + break; + case NODE_REAL: + if ($3->kind == NODE_NUMBER) { + if ($3->v.number == 0) { + yyerror("Divide by zero in constant"); + $$ = $1; + break; + } + $$ = $1; + $1->v.real /= $3->v.number; + break; + } + if ($3->kind == NODE_REAL) { + if ($3->v.real == 0.0) { + yyerror("Divide by zero in constant"); + $$ = $1; + break; + } + $$ = $1; + $1->v.real /= $3->v.real; + break; + } + CREATE_BINARY_OP($$, F_DIVIDE, result_type, $1, $3); + break; + default: + CREATE_BINARY_OP($$, F_DIVIDE, result_type, $1, $3); + } + } + | cast expr0 %prec L_NOT + { + $$ = $2; + $$->type = $1; + + if (exact_types && + $2->type != $1 && + $2->type != TYPE_ANY && + $2->type != TYPE_UNKNOWN && + $1 != TYPE_VOID) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Cannot cast "); + p = get_type_name(p, end, $2->type); + p = strput(p, end, "to "); + p = get_type_name(p, end, $1); + yyerror(buf); + } + } + | L_INC lvalue %prec L_NOT /* note lower precedence here */ + { + CREATE_UNARY_OP($$, F_PRE_INC, 0, $2); + if (exact_types){ + switch($2->type){ + case TYPE_NUMBER: + case TYPE_ANY: + case TYPE_REAL: + { + $$->type = $2->type; + break; + } + + default: + { + $$->type = TYPE_ANY; + type_error("Bad argument 1 to ++x", $2->type); + } + } + } else $$->type = TYPE_ANY; + } + | L_DEC lvalue %prec L_NOT /* note lower precedence here */ + { + CREATE_UNARY_OP($$, F_PRE_DEC, 0, $2); + if (exact_types){ + switch($2->type){ + case TYPE_NUMBER: + case TYPE_ANY: + case TYPE_REAL: + { + $$->type = $2->type; + break; + } + + default: + { + $$->type = TYPE_ANY; + type_error("Bad argument 1 to --x", $2->type); + } + } + } else $$->type = TYPE_ANY; + + } + | L_NOT expr0 + { + if ($2->kind == NODE_NUMBER) { + $$ = $2; + $$->v.number = !($$->v.number); + } else { + CREATE_UNARY_OP($$, F_NOT, TYPE_NUMBER, $2); + } + } + | '~' expr0 + { + if (exact_types && !IS_TYPE($2->type, TYPE_NUMBER)) + type_error("Bad argument to ~", $2->type); + if ($2->kind == NODE_NUMBER) { + $$ = $2; + $$->v.number = ~$$->v.number; + } else { + CREATE_UNARY_OP($$, F_COMPL, TYPE_NUMBER, $2); + } + } + | '-' expr0 %prec L_NOT + { + int result_type; + if (exact_types){ + int t = $2->type; + if (!COMP_TYPE(t, TYPE_NUMBER)){ + type_error("Bad argument to unary '-'", t); + result_type = TYPE_ANY; + } else result_type = t; + } else result_type = TYPE_ANY; + + switch ($2->kind) { + case NODE_NUMBER: + $$ = $2; + $$->v.number = -$$->v.number; + break; + case NODE_REAL: + $$ = $2; + $$->v.real = -$$->v.real; + break; + default: + CREATE_UNARY_OP($$, F_NEGATE, result_type, $2); + } + } + | lvalue L_INC /* normal precedence here */ + { + CREATE_UNARY_OP($$, F_POST_INC, 0, $1); + $$->v.number = F_POST_INC; + if (exact_types){ + switch($1->type){ + case TYPE_NUMBER: + case TYPE_ANY: + case TYPE_REAL: + { + $$->type = $1->type; + break; + } + + default: + { + $$->type = TYPE_ANY; + type_error("Bad argument 1 to x++", $1->type); + } + } + } else $$->type = TYPE_ANY; + } + | lvalue L_DEC + { + CREATE_UNARY_OP($$, F_POST_DEC, 0, $1); + if (exact_types){ + switch($1->type){ + case TYPE_NUMBER: + case TYPE_ANY: + case TYPE_REAL: + { + $$->type = $1->type; + break; + } + + default: + { + $$->type = TYPE_ANY; + type_error("Bad argument 1 to x--", $1->type); + } + } + } else $$->type = TYPE_ANY; + } + | expr4 + | sscanf + | parse_command + | time_expression + | number + | real + ; + +return: + L_RETURN ';' + { + if (exact_types && !IS_TYPE(exact_types, TYPE_VOID)) + yywarn("Non-void functions must return a value."); + CREATE_RETURN($$, 0); + } + | L_RETURN comma_expr ';' + { + if (exact_types && !compatible_types($2->type, exact_types)) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Type of returned value doesn't match function return type "); + p = get_two_types(p, end, $2->type, exact_types); + yyerror(buf); + } + if (IS_NODE($2, NODE_NUMBER, 0)) { + CREATE_RETURN($$, 0); + } else { + CREATE_RETURN($$, $2); + } + } + ; + +expr_list: + /* empty */ + { + CREATE_EXPR_LIST($$, 0); + } + | expr_list2 + { + CREATE_EXPR_LIST($$, $1); + } + | expr_list2 ',' + { + CREATE_EXPR_LIST($$, $1); + } + ; + +expr_list_node: + expr0 + { + CREATE_EXPR_NODE($$, $1, 0); + } + | expr0 L_DOT_DOT_DOT + { + CREATE_EXPR_NODE($$, $1, 1); + } + ; + +expr_list2: + expr_list_node + { + $1->kind = 1; + + $$ = $1; + } + | expr_list2 ',' expr_list_node + { + $3->kind = 0; + + $$ = $1; + $$->kind++; + $$->l.expr->r.expr = $3; + $$->l.expr = $3; + } + ; + +expr_list3: + /* empty */ + { + /* this is a dummy node */ + CREATE_EXPR_LIST($$, 0); + } + | expr_list4 + { + CREATE_EXPR_LIST($$, $1); + } + | expr_list4 ',' + { + CREATE_EXPR_LIST($$, $1); + } + ; + +expr_list4: + assoc_pair + { + $$ = new_node_no_line(); + $$->kind = 2; + $$->v.expr = $1; + $$->r.expr = 0; + $$->type = 0; + /* we keep track of the end of the chain in the left nodes */ + $$->l.expr = $$; + } + | expr_list4 ',' assoc_pair + { + parse_node_t *expr; + + expr = new_node_no_line(); + expr->kind = 0; + expr->v.expr = $3; + expr->r.expr = 0; + expr->type = 0; + + $1->l.expr->r.expr = expr; + $1->l.expr = expr; + $1->kind += 2; + $$ = $1; + } + ; + +assoc_pair: + expr0 ':' expr0 + { + CREATE_TWO_VALUES($$, 0, $1, $3); + } + ; + +lvalue: + expr4 + { +#define LV_ILLEGAL 1 +#define LV_RANGE 2 +#define LV_INDEX 4 + /* Restrictive lvalues, but I think they make more sense :) */ + $$ = $1; + if($$->kind == NODE_BINARY_OP && $$->v.number == F_TYPE_CHECK) + $$ = $$->l.expr; + switch($$->kind) { + default: + yyerror("Illegal lvalue"); + break; + case NODE_PARAMETER: + $$->kind = NODE_PARAMETER_LVALUE; + break; + case NODE_TERNARY_OP: + $$->v.number = $$->r.expr->v.number; + case NODE_OPCODE_1: + case NODE_UNARY_OP_1: + case NODE_BINARY_OP: + if ($$->v.number >= F_LOCAL && $$->v.number <= F_MEMBER) + $$->v.number++; /* make it an lvalue */ + else if ($$->v.number >= F_INDEX + && $$->v.number <= F_RE_RANGE) { + parse_node_t *node = $$; + int flag = 0; + do { + switch(node->kind) { + case NODE_PARAMETER: + node->kind = NODE_PARAMETER_LVALUE; + flag |= LV_ILLEGAL; + break; + case NODE_TERNARY_OP: + node->v.number = node->r.expr->v.number; + case NODE_OPCODE_1: + case NODE_UNARY_OP_1: + case NODE_BINARY_OP: + if(node->kind == NODE_BINARY_OP && + node->v.number == F_TYPE_CHECK) { + node = node->l.expr; + continue; + } + + if (node->v.number >= F_LOCAL + && node->v.number <= F_MEMBER) { + node->v.number++; + flag |= LV_ILLEGAL; + break; + } else if (node->v.number == F_INDEX || + node->v.number == F_RINDEX) { + node->v.number++; + flag |= LV_INDEX; + break; + } else if (node->v.number >= F_ADD_EQ + && node->v.number <= F_ASSIGN) { + if (!(flag & LV_INDEX)) { + yyerror("Illegal lvalue, a possible lvalue is (x y)[a]"); + } + if (node->r.expr->kind == NODE_BINARY_OP|| + node->r.expr->kind == NODE_TERNARY_OP){ + if (node->r.expr->v.number >= F_NN_RANGE_LVALUE && node->r.expr->v.number <= F_NR_RANGE_LVALUE) + yyerror("Illegal to have (x[a..b] y) to be the beginning of an lvalue"); + } + flag = LV_ILLEGAL; + break; + } else if (node->v.number >= F_NN_RANGE + && node->v.number <= F_RE_RANGE) { + if (flag & LV_RANGE) { + yyerror("Can't do range lvalue of range lvalue."); + flag |= LV_ILLEGAL; + break; + } + if (flag & LV_INDEX){ + yyerror("Can't do indexed lvalue of range lvalue."); + flag |= LV_ILLEGAL; + break; + } + if (node->v.number == F_NE_RANGE) { + /* x[foo..] -> x[foo..<1] */ + parse_node_t *rchild = node->r.expr; + node->kind = NODE_TERNARY_OP; + CREATE_BINARY_OP(node->r.expr, + F_NR_RANGE_LVALUE, + 0, 0, rchild); + CREATE_NUMBER(node->r.expr->l.expr, 1); + } else if (node->v.number == F_RE_RANGE) { + /* x[ x[r.expr; + node->kind = NODE_TERNARY_OP; + CREATE_BINARY_OP(node->r.expr, + F_RR_RANGE_LVALUE, + 0, 0, rchild); + CREATE_NUMBER(node->r.expr->l.expr, 1); + } else + node->r.expr->v.number++; + flag |= LV_RANGE; + node = node->r.expr->r.expr; + continue; + } + default: + yyerror("Illegal lvalue"); + flag = LV_ILLEGAL; + break; + } + if ((flag & LV_ILLEGAL) || !(node = node->r.expr)) break; + } while (1); + break; + } else + yyerror("Illegal lvalue"); + break; + } + } + ; + +l_new_function_open: L_NEW_FUNCTION_OPEN + | L_FUNCTION_OPEN efun_override + { + $$ = ($2 << 8) | FP_EFUN; + } + ; + +%ifdef COMPAT_32 +simple_function_pointer: l_new_function_open ':' ')' + { + $$ = $1; + } + | L_LAMBDA L_DEFINED_NAME + { + int val; + + if ((val=$2->dn.local_num) >= 0){ + $$ = (val << 8) | FP_L_VAR; + } else if ((val=$2->dn.global_num) >= 0) { + $$ = (val << 8) | FP_G_VAR; + } else if ((val=$2->dn.function_num) >=0) { + $$ = (val << 8)|FP_LOCAL; + } else if ((val=$2->dn.simul_num) >=0) { + $$ = (val << 8)|FP_SIMUL; + } else if ((val=$2->dn.efun_num) >=0) { + $$ = (val << 8)|FP_EFUN; + } + } + ; +%endif + +expr4: + function_call + | L_DEFINED_NAME + { + int i; + if ((i = $1->dn.local_num) != -1) { + type_of_locals_ptr[i] &= ~LOCAL_MOD_UNUSED; + if (type_of_locals_ptr[i] & LOCAL_MOD_REF) + CREATE_OPCODE_1($$, F_REF, type_of_locals_ptr[i] & ~LOCAL_MOD_REF,i & 0xff); + else + CREATE_OPCODE_1($$, F_LOCAL, type_of_locals_ptr[i], i & 0xff); + if (current_function_context) + current_function_context->num_locals++; + } else + if ((i = $1->dn.global_num) != -1) { + if (current_function_context) + current_function_context->bindable = FP_NOT_BINDABLE; + CREATE_OPCODE_1($$, F_GLOBAL, + VAR_TEMP(i)->type & ~DECL_MODS, i); + if (VAR_TEMP(i)->type & DECL_HIDDEN) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Illegal to use private variable '"); + p = strput(p, end, $1->name); + p = strput(p, end, "'"); + yyerror(buf); + } + } else { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Undefined variable '"); + p = strput(p, end, $1->name); + p = strput(p, end, "'"); + if (current_number_of_locals < CFG_MAX_LOCAL_VARIABLES) { + add_local_name($1->name, TYPE_ANY); + } + CREATE_ERROR($$); + yyerror(buf); + } + } + | L_IDENTIFIER + { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Undefined variable '"); + p = strput(p, end, $1); + p = strput(p, end, "'"); + if (current_number_of_locals < CFG_MAX_LOCAL_VARIABLES) { + add_local_name($1, TYPE_ANY); + } + CREATE_ERROR($$); + yyerror(buf); + scratch_free($1); + } + | L_PARAMETER + { + CREATE_PARAMETER($$, TYPE_ANY, $1); + } + | '$' '(' + { + $$ = current_function_context; + /* already flagged as an error */ + if (current_function_context) + current_function_context = current_function_context->parent; + } + comma_expr ')' + { + parse_node_t *node; + + current_function_context = $3; + + if (!current_function_context || current_function_context->num_parameters == -2) { + /* This was illegal, and error'ed when the '$' token + * was returned. + */ + CREATE_ERROR($$); + } else { + CREATE_OPCODE_1($$, F_LOCAL, $4->type, + current_function_context->values_list->kind++); + + node = new_node_no_line(); + node->type = 0; + current_function_context->values_list->l.expr->r.expr = node; + current_function_context->values_list->l.expr = node; + node->r.expr = 0; + node->v.expr = $4; + } + } + | expr4 L_ARROW identifier + { + if ($1->type == TYPE_ANY) { + int cmi; + unsigned char tp; + + if ((cmi = lookup_any_class_member($3, &tp)) != -1) { + CREATE_UNARY_OP_1($$, F_MEMBER, tp, $1, 0); + $$->l.number = cmi; + } else { + CREATE_ERROR($$); + } + } else if (!IS_CLASS($1->type)) { + yyerror("Left argument of -> is not a class"); + CREATE_ERROR($$); + } else { + CREATE_UNARY_OP_1($$, F_MEMBER, 0, $1, 0); + $$->l.number = lookup_class_member(CLASS_IDX($1->type), + $3, + &($$->type)); + } + + scratch_free($3); + } + | expr4 '[' comma_expr L_RANGE comma_expr ']' + { +%ifndef OLD_RANGE_BEHAVIOR +%ifdef WARN_OLD_RANGE_BEHAVIOR + if ($1->type != TYPE_MAPPING && + $5->kind == NODE_NUMBER && $5->v.number < 0) + yywarn("A negative constant as the second element of arr[x..y] no longer means indexing from the end. Use arr[x..kind == NODE_NUMBER && $7->v.number <= 1) + $$ = make_range_node(F_RE_RANGE, $1, $4, 0); + else + $$ = make_range_node(F_RR_RANGE, $1, $4, $7); + } + | expr4 '[' comma_expr L_RANGE '<' comma_expr ']' + { + if ($6->kind == NODE_NUMBER && $6->v.number <= 1) + $$ = make_range_node(F_NE_RANGE, $1, $3, 0); + else + $$ = make_range_node(F_NR_RANGE, $1, $3, $6); + } + | expr4 '[' comma_expr L_RANGE ']' + { + $$ = make_range_node(F_NE_RANGE, $1, $3, 0); + } + | expr4 '[' '<' comma_expr L_RANGE ']' + { + $$ = make_range_node(F_RE_RANGE, $1, $4, 0); + } + | expr4 '[' '<' comma_expr ']' + { + if (IS_NODE($1, NODE_CALL, F_AGGREGATE) + && $4->kind == NODE_NUMBER) { + int i = $4->v.number; + if (i < 1 || i > $1->l.number) + yyerror("Illegal index to array constant."); + else { + parse_node_t *node = $1->r.expr; + i = $1->l.number - i; + while (i--) + node = node->r.expr; + $$ = node->v.expr; + break; + } + } + CREATE_BINARY_OP($$, F_RINDEX, 0, $4, $1); + if (exact_types) { + switch($1->type) { + case TYPE_MAPPING: + yyerror("Illegal index for mapping."); + case TYPE_ANY: + $$->type = TYPE_ANY; + break; + case TYPE_STRING: + case TYPE_BUFFER: + $$->type = TYPE_NUMBER; + if (!IS_TYPE($4->type,TYPE_NUMBER)) + type_error("Bad type of index", $4->type); + break; + + default: + if ($1->type & TYPE_MOD_ARRAY) { + $$->type = $1->type & ~TYPE_MOD_ARRAY; + if ($$->type != TYPE_ANY) + $$ = add_type_check($$, $$->type); + if (!IS_TYPE($4->type,TYPE_NUMBER)) + type_error("Bad type of index", $4->type); + } else { + type_error("Value indexed has a bad type ", $1->type); + $$->type = TYPE_ANY; + } + } + } else $$->type = TYPE_ANY; + } + | expr4 '[' comma_expr ']' + { + /* Something stupid like ({ 1, 2, 3 })[1]; we take the + * time to optimize this because people who don't understand + * the preprocessor often write things like: + * + * #define MY_ARRAY ({ "foo", "bar", "bazz" }) + * ... + * ... MY_ARRAY[1] ... + * + * which of course expands to the above. + */ + if (IS_NODE($1, NODE_CALL, F_AGGREGATE) && $3->kind == NODE_NUMBER) { + int i = $3->v.number; + if (i < 0 || i >= $1->l.number) + yyerror("Illegal index to array constant."); + else { + parse_node_t *node = $1->r.expr; + while (i--) + node = node->r.expr; + $$ = node->v.expr; + break; + } + } +%ifndef OLD_RANGE_BEHAVIOR + if ($3->kind == NODE_NUMBER && $3->v.number < 0) + yywarn("A negative constant in arr[x] no longer means indexing from the end. Use arr[type) { + case TYPE_MAPPING: + case TYPE_ANY: + $$->type = TYPE_ANY; + break; + case TYPE_STRING: + case TYPE_BUFFER: + $$->type = TYPE_NUMBER; + if (!IS_TYPE($3->type,TYPE_NUMBER)) + type_error("Bad type of index", $3->type); + break; + + default: + if ($1->type & TYPE_MOD_ARRAY) { + $$->type = $1->type & ~TYPE_MOD_ARRAY; + if($$->type != TYPE_ANY) + $$ = add_type_check($$, $$->type); + if (!IS_TYPE($3->type,TYPE_NUMBER)) + type_error("Bad type of index", $3->type); + } else { + type_error("Value indexed has a bad type ", $1->type); + $$->type = TYPE_ANY; + } + } + } else $$->type = TYPE_ANY; + } + | string + | '(' comma_expr ')' + { + $$ = $2; + } + | catch +%ifdef DEBUG + | tree +%endif + | L_BASIC_TYPE + { + if ($1 != TYPE_FUNCTION) yyerror("Reserved type name unexpected."); + $$.num_local = current_number_of_locals; + $$.max_num_locals = max_num_locals; + $$.context = context; + $$.save_current_type = current_type; + $$.save_exact_types = exact_types; + if (type_of_locals_ptr + max_num_locals + CFG_MAX_LOCAL_VARIABLES >= &type_of_locals[type_of_locals_size]) + reallocate_locals(); + deactivate_current_locals(); + locals_ptr += current_number_of_locals; + type_of_locals_ptr += max_num_locals; + max_num_locals = current_number_of_locals = 0; + push_function_context(); + current_function_context->num_parameters = -1; + exact_types = TYPE_ANY; + context = 0; + } + '(' argument ')' block + { + if ($4.flags & ARG_IS_VARARGS) { + yyerror("Anonymous varargs functions aren't implemented"); + } + if (!$6.node) { + CREATE_RETURN($6.node, 0); + } else if ($6.node->kind != NODE_RETURN && + ($6.node->kind != NODE_TWO_VALUES || $6.node->r.expr->kind != NODE_RETURN)) { + parse_node_t *replacement; + CREATE_STATEMENTS(replacement, $6.node, 0); + CREATE_RETURN(replacement->r.expr, 0); + $6.node = replacement; + } + + $$ = new_node(); + $$->kind = NODE_ANON_FUNC; + $$->type = TYPE_FUNCTION; + $$->l.number = (max_num_locals - $4.num_arg); + $$->r.expr = $6.node; + $$->v.number = $4.num_arg; + if (current_function_context->bindable) + $$->v.number |= 0x10000; + free_all_local_names(1); + + current_number_of_locals = $2.num_local; + max_num_locals = $2.max_num_locals; + context = $2.context; + current_type = $2.save_current_type; + exact_types = $2.save_exact_types; + pop_function_context(); + + locals_ptr -= current_number_of_locals; + type_of_locals_ptr -= max_num_locals; + reactivate_current_locals(); + } +%ifdef COMPAT_32 + | simple_function_pointer +%else + | l_new_function_open ':' ')' +%endif + { +#ifdef WOMBLES + if(*(outp-2) != ':') + yyerror("End of functional not found"); +#endif + $$ = new_node(); + $$->kind = NODE_FUNCTION_CONSTRUCTOR; + $$->type = TYPE_FUNCTION; + $$->r.expr = 0; + switch ($1 & 0xff) { + case FP_L_VAR: + yyerror("Illegal to use local variable in a functional."); + CREATE_NUMBER($$->l.expr, 0); + $$->l.expr->r.expr = 0; + $$->l.expr->l.expr = 0; + $$->v.number = FP_FUNCTIONAL; + break; + case FP_G_VAR: + CREATE_OPCODE_1($$->l.expr, F_GLOBAL, 0, $1 >> 8); + $$->v.number = FP_FUNCTIONAL | FP_NOT_BINDABLE; + if (VAR_TEMP($$->l.expr->l.number)->type & DECL_HIDDEN) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Illegal to use private variable '"); + p = strput(p, end, VAR_TEMP($$->l.expr->l.number)->name); + p = strput(p, end, "'"); + yyerror(buf); + } + break; + default: + $$->v.number = $1; + break; + } + } + | l_new_function_open ',' expr_list2 ':' ')' + { +#ifdef WOMBLES + if(*(outp-2) != ':') + yyerror("End of functional not found"); +#endif + $$ = new_node(); + $$->kind = NODE_FUNCTION_CONSTRUCTOR; + $$->type = TYPE_FUNCTION; + $$->v.number = $1; + $$->r.expr = $3; + + switch ($1 & 0xff) { + case FP_EFUN: { + int *argp; + int f = $1 >>8; + int num = $3->kind; + int max_arg = predefs[f].max_args; + if(f!=-1){ + if (num > max_arg && max_arg != -1) { + parse_node_t *pn = $3; + + while (pn) { + if (pn->type & 1) break; + pn = pn->r.expr; + } + + if (!pn) { + char bff[256]; + char *end = EndOf(bff); + char *p; + + p = strput(bff, end, "Too many arguments to "); + p = strput(p, end, predefs[f].word); + yyerror(bff); + } + } else if (max_arg != -1 && exact_types) { + /* + * Now check all types of arguments to efuns. + */ + int i, argn, tmp; + parse_node_t *enode = $3; + argp = &efun_arg_types[predefs[f].arg_index]; + + for (argn = 0; argn < num; argn++) { + if (enode->type & 1) break; + + tmp = enode->v.expr->type; + for (i=0; !compatible_types(tmp, argp[i]) + && argp[i] != 0; i++) + ; + if (argp[i] == 0) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Bad argument "); + p = strput_int(p, end, argn+1); + p = strput(p, end, " to efun "); + p = strput(p, end, predefs[f].word); + p = strput(p, end, "()"); + yyerror(buf); + } else { + /* this little section necessary b/c in the + case float | int we dont want to do + promoting. */ + if (tmp == TYPE_NUMBER && argp[i] == TYPE_REAL) { + for (i++; argp[i] && argp[i] != TYPE_NUMBER; i++) + ; + if (!argp[i]) + enode->v.expr = promote_to_float(enode->v.expr); + } + if (tmp == TYPE_REAL && argp[i] == TYPE_NUMBER) { + for (i++; argp[i] && argp[i] != TYPE_REAL; i++) + ; + if (!argp[i]) + enode->v.expr = promote_to_int(enode->v.expr); + } + } + while (argp[i] != 0) + i++; + argp += i + 1; + enode = enode->r.expr; + } + } + } + break; + } + case FP_L_VAR: + case FP_G_VAR: + yyerror("Can't give parameters to functional."); + break; + } + } + | L_FUNCTION_OPEN comma_expr ':' ')' + { +#ifdef WOMBLES + if(*(outp-2) != ':') + yyerror("End of functional not found"); +#endif + if (current_function_context->num_locals) + yyerror("Illegal to use local variable in functional."); + if (current_function_context->values_list->r.expr) + current_function_context->values_list->r.expr->kind = current_function_context->values_list->kind; + + $$ = new_node(); + $$->kind = NODE_FUNCTION_CONSTRUCTOR; + $$->type = TYPE_FUNCTION; + $$->l.expr = $2; + if ($2->kind == NODE_STRING) + yywarn("Function pointer returning string constant is NOT a function call"); + $$->r.expr = current_function_context->values_list->r.expr; + $$->v.number = FP_FUNCTIONAL + current_function_context->bindable + + (current_function_context->num_parameters << 8); + pop_function_context(); + } + | L_MAPPING_OPEN expr_list3 ']' ')' + { +#ifdef WOMBLES + if(*(outp-2) != ']') + yyerror("End of mapping not found"); +#endif + CREATE_CALL($$, F_AGGREGATE_ASSOC, TYPE_MAPPING, $2); + } + | L_ARRAY_OPEN expr_list '}' ')' + { +#ifdef WOMBLES + if(*(outp-2) != '}') + yyerror("End of array not found"); +#endif + CREATE_CALL($$, F_AGGREGATE, TYPE_ANY | TYPE_MOD_ARRAY, $2); + } + ; + +expr_or_block: + block + { + $$ = $1.node; + } + | '(' comma_expr ')' + { + $$ = insert_pop_value($2); + } + ; + +catch: + L_CATCH + { + $$ = context; + context = SPECIAL_CONTEXT; + } + expr_or_block + { + CREATE_CATCH($$, $3); + context = $2; + } + ; + +%ifdef DEBUG +tree: + L_TREE block + { + $$ = new_node_no_line(); + lpc_tree_form($2.node, $$); + } + | + L_TREE '(' comma_expr ')' + { + $$ = new_node_no_line(); + lpc_tree_form($3, $$); + } + ; +%endif + +sscanf: + L_SSCANF '(' expr0 ',' expr0 lvalue_list ')' + { + int p = $6->v.number; + CREATE_LVALUE_EFUN($$, TYPE_NUMBER, $6); + CREATE_BINARY_OP_1($$->l.expr, F_SSCANF, 0, $3, $5, p); + } + ; + +parse_command: + L_PARSE_COMMAND '(' expr0 ',' expr0 ',' expr0 lvalue_list ')' + { + int p = $8->v.number; + CREATE_LVALUE_EFUN($$, TYPE_NUMBER, $8); + CREATE_TERNARY_OP_1($$->l.expr, F_PARSE_COMMAND, 0, + $3, $5, $7, p); + } + ; + +time_expression: + L_TIME_EXPRESSION + { + $$ = context; + context = SPECIAL_CONTEXT; + } + expr_or_block + { + CREATE_TIME_EXPRESSION($$, $3); + context = $2; + } + ; + +lvalue_list: + /* empty */ + { + $$ = new_node_no_line(); + $$->r.expr = 0; + $$->v.number = 0; + } + | ',' lvalue lvalue_list + { + parse_node_t *insert; + + $$ = $3; + insert = new_node_no_line(); + insert->r.expr = $3->r.expr; + insert->l.expr = $2; + $3->r.expr = insert; + $$->v.number++; + } + ; + +string: + string_con2 + { + CREATE_STRING($$, $1); + scratch_free($1); + } + ; + +string_con1: + string_con2 + | '(' string_con1 ')' + { + $$ = $2; + } + | string_con1 '+' string_con1 + { + $$ = scratch_join($1, $3); + } + ; + +string_con2: + L_STRING + | string_con2 L_STRING + { + $$ = scratch_join($1, $2); + } + ; + +class_init: identifier ':' expr0 + { + $$ = new_node(); + $$->l.expr = (parse_node_t *)$1; + $$->v.expr = $3; + $$->r.expr = 0; + } + ; + +opt_class_init: + /* empty */ + { + $$ = 0; + } + | opt_class_init ',' class_init + { + $$ = $3; + $$->r.expr = $1; + } + ; + + +function_call: + efun_override '(' + { + $$ = context; + $2 = num_refs; + context |= ARG_LIST; + } + expr_list ')' + { + context = $3; + $$ = validate_efun_call($1,$4); + $$ = check_refs(num_refs - $2, $4, $$); + num_refs = $2; + } + | L_NEW '(' + { + $$ = context; + $2 = num_refs; + context |= ARG_LIST; + } + expr_list ')' + { + ident_hash_elem_t *ihe; + int f; + + context = $3; + ihe = lookup_ident("clone_object"); + + if ((f = ihe->dn.simul_num) != -1) { + $$ = $4; + $$->kind = NODE_CALL_1; + $$->v.number = F_SIMUL_EFUN; + $$->l.number = f; + $$->type = (SIMUL(f)->type) & ~DECL_MODS; + } else { + $$ = validate_efun_call(lookup_predef("clone_object"), $4); +#ifdef CAST_CALL_OTHERS + $$->type = TYPE_UNKNOWN; +#else + $$->type = TYPE_ANY; +#endif + } + $$ = check_refs(num_refs - $2, $4, $$); + num_refs = $2; + } + | L_NEW '(' L_CLASS L_DEFINED_NAME opt_class_init ')' + { + parse_node_t *node; + + if ($4->dn.class_num == -1) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Undefined class '"); + p = strput(p, end, $4->name); + p = strput(p, end, "'"); + yyerror(buf); + CREATE_ERROR($$); + node = $5; + while (node) { + scratch_free((char *)node->l.expr); + node = node->r.expr; + } + } else { + int type = $4->dn.class_num | TYPE_MOD_CLASS; + + if ((node = $5)) { + CREATE_TWO_VALUES($$, type, 0, 0); + $$->l.expr = reorder_class_values($4->dn.class_num, + node); + CREATE_OPCODE_1($$->r.expr, F_NEW_CLASS, + type, $4->dn.class_num); + + } else { + CREATE_OPCODE_1($$, F_NEW_EMPTY_CLASS, + type, $4->dn.class_num); + } + } + } + | L_NEW '(' L_CLASS L_IDENTIFIER opt_class_init ')' + { + parse_node_t *node; + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Undefined class '"); + p = strput(p, end, $4); + p = strput(p, end, "'"); + yyerror(buf); + CREATE_ERROR($$); + node = $5; + while (node) { + scratch_free((char *)node->l.expr); + node = node->r.expr; + } + } + | L_DEFINED_NAME '(' + { + $$ = context; + $2 = num_refs; + context |= ARG_LIST; + } + expr_list ')' + { + int f; + + context = $3; + $$ = $4; + if ((f = $1->dn.function_num) != -1) { + if (current_function_context) + current_function_context->bindable = FP_NOT_BINDABLE; + + $$->kind = NODE_CALL_1; + $$->v.number = F_CALL_FUNCTION_BY_ADDRESS; + $$->l.number = f; + $$->type = validate_function_call(f, $4->r.expr); + } else if ((f=$1->dn.simul_num) != -1) { + $$->kind = NODE_CALL_1; + $$->v.number = F_SIMUL_EFUN; + $$->l.number = f; + $$->type = (SIMUL(f)->type) & ~DECL_MODS; + } else if ((f=$1->dn.efun_num) != -1) { + $$ = validate_efun_call(f, $4); + } else { + /* This here is a really nasty case that only occurs with + * exact_types off. The user has done something gross like: + * + * func() { int f; f(); } // if f was prototyped we wouldn't + * f() { } // need this case + * + * Don't complain, just grok it. + */ + + if (current_function_context) + current_function_context->bindable = FP_NOT_BINDABLE; + + f = define_new_function($1->name, 0, 0, + DECL_PUBLIC|FUNC_UNDEFINED, TYPE_ANY); + $$->kind = NODE_CALL_1; + $$->v.number = F_CALL_FUNCTION_BY_ADDRESS; + $$->l.number = f; + $$->type = TYPE_ANY; /* just a guess */ + if (exact_types) { + char buf[256]; + char *end = EndOf(buf); + char *p; + const char *n = $1->name; + if (*n == ':') n++; + /* prevent some errors; by making it look like an + * inherited function we prevent redeclaration errors + * if it shows up later + */ + + FUNCTION_FLAGS(f) &= ~FUNC_UNDEFINED; + FUNCTION_FLAGS(f) |= (FUNC_INHERITED | FUNC_VARARGS); + p = strput(buf, end, "Undefined function "); + p = strput(p, end, n); + yyerror(buf); + } + } + $$ = check_refs(num_refs - $2, $4, $$); + num_refs = $2; + } + | function_name '(' + { + $$ = context; + $2 = num_refs; + context |= ARG_LIST; + } + expr_list ')' + { + char *name = $1; + + context = $3; + $$ = $4; + + if (current_function_context) + current_function_context->bindable = FP_NOT_BINDABLE; + + if (*name == ':') { + int f; + + if ((f = arrange_call_inherited(name + 1, $$)) != -1) + /* Can't do this; f may not be the correct function + entry. It might be overloaded. + + validate_function_call(f, $$->r.expr) + */ + ; + } else { + int f; + ident_hash_elem_t *ihe; + + f = (ihe = lookup_ident(name)) ? ihe->dn.function_num : -1; + $$->kind = NODE_CALL_1; + $$->v.number = F_CALL_FUNCTION_BY_ADDRESS; + if (f!=-1) { + /* The only way this can happen is if function_name + * below made the function name. The lexer would + * return L_DEFINED_NAME instead. + */ + $$->type = validate_function_call(f, $4->r.expr); + } else { + f = define_new_function(name, 0, 0, + DECL_PUBLIC|FUNC_UNDEFINED, TYPE_ANY); + } + $$->l.number = f; + /* + * Check if this function has been defined. + * But, don't complain yet about functions defined + * by inheritance. + */ + if (exact_types && (FUNCTION_FLAGS(f) & FUNC_UNDEFINED)) { + char buf[256]; + char *end = EndOf(buf); + char *p; + char *n = $1; + if (*n == ':') n++; + /* prevent some errors */ + FUNCTION_FLAGS(f) &= ~FUNC_UNDEFINED; + FUNCTION_FLAGS(f) |= (FUNC_INHERITED | FUNC_VARARGS); + p = strput(buf, end, "Undefined function "); + p = strput(p, end, n); + yyerror(buf); + } + if (!(FUNCTION_FLAGS(f) & FUNC_UNDEFINED)) + $$->type = FUNCTION_DEF(f)->type; + else + $$->type = TYPE_ANY; /* Just a guess */ + } + $$ = check_refs(num_refs - $2, $4, $$); + num_refs = $2; + scratch_free(name); + } + | expr4 L_ARROW identifier '(' + { + $$ = context; + $4 = num_refs; + context |= ARG_LIST; + } + expr_list ')' + { + ident_hash_elem_t *ihe; + int f; + parse_node_t *pn1, *pn2; + + $6->v.number += 2; + + pn1 = new_node_no_line(); + pn1->type = 0; + pn1->v.expr = $1; + pn1->kind = $6->v.number; + + pn2 = new_node_no_line(); + pn2->type = 0; + CREATE_STRING(pn2->v.expr, $3); + scratch_free($3); + + /* insert the two nodes */ + pn2->r.expr = $6->r.expr; + pn1->r.expr = pn2; + $6->r.expr = pn1; + + if (!$6->l.expr) $6->l.expr = pn2; + + context = $5; + ihe = lookup_ident("call_other"); + + if ((f = ihe->dn.simul_num) != -1) { + $$ = $6; + $$->kind = NODE_CALL_1; + $$->v.number = F_SIMUL_EFUN; + $$->l.number = f; + $$->type = (SIMUL(f)->type) & ~DECL_MODS; + } else { + $$ = validate_efun_call(arrow_efun, $6); +#ifdef CAST_CALL_OTHERS + $$->type = TYPE_UNKNOWN; +#else + $$->type = TYPE_ANY; +#endif + } + $$ = check_refs(num_refs - $4, $6, $$); + num_refs = $4; + } + | '(' '*' comma_expr ')' '(' + { + $$ = context; + $5 = num_refs; + context |= ARG_LIST; + } + expr_list ')' + { + parse_node_t *expr; + + context = $6; + $$ = $7; + $$->kind = NODE_EFUN; + $$->l.number = $$->v.number + 1; + $$->v.number = predefs[evaluate_efun].token; +#ifdef CAST_CALL_OTHERS + $$->type = TYPE_UNKNOWN; +#else + $$->type = TYPE_ANY; +#endif + expr = new_node_no_line(); + expr->type = 0; + expr->v.expr = $3; + expr->r.expr = $$->r.expr; + $$->r.expr = expr; + $$ = check_refs(num_refs - $5, $7, $$); + num_refs = $5; + } + ; + +efun_override: L_EFUN L_COLON_COLON identifier { + svalue_t *res; + ident_hash_elem_t *ihe; + + $$ = (ihe = lookup_ident($3)) ? ihe->dn.efun_num : -1; + if ($$ == -1) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Unknown efun: "); + p = strput(p, end, $3); + yyerror(buf); + } else { + push_malloced_string(the_file_name(current_file)); + share_and_push_string($3); + push_malloced_string(add_slash(main_file_name())); + res = safe_apply_master_ob(APPLY_VALID_OVERRIDE, 3); + if (!MASTER_APPROVED(res)) { + yyerror("Invalid simulated efunction override"); + $$ = -1; + } + } + scratch_free($3); + } + | L_EFUN L_COLON_COLON L_NEW { + svalue_t *res; + + push_malloced_string(the_file_name(current_file)); + push_constant_string("new"); + push_malloced_string(add_slash(main_file_name())); + res = safe_apply_master_ob(APPLY_VALID_OVERRIDE, 3); + if (!MASTER_APPROVED(res)) { + yyerror("Invalid simulated efunction override"); + $$ = -1; + } else $$ = new_efun; + } + ; + +function_name: + L_IDENTIFIER + | L_COLON_COLON identifier + { + int l = strlen($2) + 1; + char *p; + /* here we be a bit cute. we put a : on the front so we + * don't have to strchr for it. Here we do: + * "name" -> ":::name" + */ + $$ = scratch_realloc($2, l + 3); + p = $$ + l; + while (p--,l--) + *(p+3) = *p; + strncpy($$, ":::", 3); + } + | L_BASIC_TYPE L_COLON_COLON identifier + { + int z, l = strlen($3) + 1; + char *p; + /* and "name" -> ":type::name" */ + z = strlen(compiler_type_names[$1]) + 3; /* length of :type:: */ + $$ = scratch_realloc($3, l + z); + p = $$ + l; + while (p--,l--) + *(p+z) = *p; + $$[0] = ':'; + strncpy($$ + 1, compiler_type_names[$1], z - 3); + $$[z-2] = ':'; + $$[z-1] = ':'; + } + | identifier L_COLON_COLON identifier + { + int l = strlen($1); + /* "ob" and "name" -> ":ob::name" */ + $$ = scratch_alloc(l + strlen($3) + 4); + *($$) = ':'; + strcpy($$ + 1, $1); + strcpy($$ + l + 1, "::"); + strcpy($$ + l + 3, $3); + scratch_free($1); + scratch_free($3); + } + ; + +cond: + L_IF '(' comma_expr ')' statement optional_else_part + { + /* x != 0 -> x */ + if (IS_NODE($3, NODE_BINARY_OP, F_NE)) { + if (IS_NODE($3->r.expr, NODE_NUMBER, 0)) + $3 = $3->l.expr; + else if (IS_NODE($3->l.expr, NODE_NUMBER, 0)) + $3 = $3->r.expr; + } + + /* TODO: should optimize if (0), if (1) here. + * Also generalize this. + */ + + if ($5 == 0) { + if ($6 == 0) { + /* if (x) ; -> x; */ + $$ = pop_value($3); + break; + } else { + /* if (x) {} else y; -> if (!x) y; */ + parse_node_t *repl; + + CREATE_UNARY_OP(repl, F_NOT, TYPE_NUMBER, $3); + $3 = repl; + $5 = $6; + $6 = 0; + } + } + CREATE_IF($$, $3, $5, $6); + } + ; + +optional_else_part: + /* empty */ %prec LOWER_THAN_ELSE + { + $$ = 0; + } + | L_ELSE statement + { + $$ = $2; + } + ; +%% + +%line diff --git a/fluffos-2.23-ds03/hash.c b/fluffos-2.23-ds03/hash.c new file mode 100644 index 0000000..eb78686 --- /dev/null +++ b/fluffos-2.23-ds03/hash.c @@ -0,0 +1,15 @@ +#define EDIT_SOURCE +#define NO_SOCKETS +#define NO_OPCODES + +#include "std.h" +#include "hash.h" + +unsigned int whashstr (const char * s) +{ + int i = 0; + unsigned long __h = 0; + for ( ; *s && i++ <100 ; ++s) + __h = 37 * __h + *s; + return __h; +} diff --git a/fluffos-2.23-ds03/hash.h b/fluffos-2.23-ds03/hash.h new file mode 100644 index 0000000..796a0f2 --- /dev/null +++ b/fluffos-2.23-ds03/hash.h @@ -0,0 +1,9 @@ +#ifndef HASH_H +#define HASH_H + +/* + * hash.c + */ +unsigned int whashstr (const char *); + +#endif diff --git a/fluffos-2.23-ds03/icode.c b/fluffos-2.23-ds03/icode.c new file mode 100644 index 0000000..935e9be --- /dev/null +++ b/fluffos-2.23-ds03/icode.c @@ -0,0 +1,1275 @@ +/* + * code generator for runtime LPC code + */ +#include "std.h" +#include "lpc_incl.h" +#include "icode.h" +#include "compiler.h" +#include "generate.h" + +/* + * Macro for inserting global variable indices. + */ + +#if CFG_MAX_GLOBAL_VARIABLES <= 256 +#define INS_GLOBAL_INDEX ins_byte +#elif CFG_MAX_GLOBAL_VARIABLES <= 65536 +#define INS_GLOBAL_INDEX ins_short +#else +#error CFG_MAX_GLOBAL_VARIABLES must not be greater than 65536 +#endif + +static void ins_real (double); +static void ins_short (short); +static void upd_short (int, int, const char *); +static void ins_byte (unsigned char); +static void upd_byte (int, unsigned char); +static void write_number (long); +static void ins_int (long); +#if SIZEOF_PTR == 8 +static void ins_long (long); +#endif +void i_generate_node (parse_node_t *); +static void i_generate_if_branch (parse_node_t *, int); +static void i_generate_loop (int, parse_node_t *, parse_node_t *, + parse_node_t *); +static void i_update_branch_list (parse_node_t *, const char *); +static int try_to_push (int, int); + +static int foreach_depth = 0; + +static int current_num_values; + +static unsigned int last_size_generated; +static unsigned int line_being_generated; + +static int push_state; +static int push_start; + +static parse_node_t *branch_list[3]; +static int nforward_branches, nforward_branches_max; +static int *forward_branches = 0; + +static void ins_real (double l) +{ + float f = (float)l; + + if (prog_code + 4 > prog_code_max) { + mem_block_t *mbp = &mem_block[A_PROGRAM]; + + UPDATE_PROGRAM_SIZE; + realloc_mem_block(mbp); + + prog_code = mbp->block + mbp->current_size; + prog_code_max = mbp->block + mbp->max_size; + } + STORE_FLOAT(prog_code, f); +} + +/* + * Store a 2 byte number. It is stored in such a way as to be sure + * that correct byte order is used, regardless of machine architecture. + * Also beware that some machines can't write a word to odd addresses. + */ +static void ins_short (short l) +{ + if (prog_code + 2 > prog_code_max) { + mem_block_t *mbp = &mem_block[A_PROGRAM]; + UPDATE_PROGRAM_SIZE; + realloc_mem_block(mbp); + + prog_code = mbp->block + mbp->current_size; + prog_code_max = mbp->block + mbp->max_size; + } + STORE_SHORT(prog_code, l); +} + +/* + * Store a 4 byte number. It is stored in such a way as to be sure + * that correct byte order is used, regardless of machine architecture. + */ +static void ins_int (long l) +{ + + if (prog_code + SIZEOF_LONG > prog_code_max) { + mem_block_t *mbp = &mem_block[A_PROGRAM]; + UPDATE_PROGRAM_SIZE; + realloc_mem_block(mbp); + + prog_code = mbp->block + mbp->current_size; + prog_code_max = mbp->block + mbp->max_size; + } + STORE_INT(prog_code, l); +} + +/* + * Store a 8 byte number. It is stored in such a way as to be sure + * that correct byte order is used, regardless of machine architecture. + */ +#if SIZEOF_PTR == 8 +static void ins_long (long l) +{ + if (prog_code + 8 > prog_code_max) { + mem_block_t *mbp = &mem_block[A_PROGRAM]; + UPDATE_PROGRAM_SIZE; + realloc_mem_block(mbp); + + prog_code = mbp->block + mbp->current_size; + prog_code_max = mbp->block + mbp->max_size; + } + STORE_PTR(prog_code, l); +} +#endif + +static void upd_short (int offset, int l, const char * where) +{ + unsigned short s; + + IF_DEBUG(UPDATE_PROGRAM_SIZE); + DEBUG_CHECK2(offset > CURRENT_PROGRAM_SIZE, + "patch offset %x larger than current program size %x.\n", + offset, CURRENT_PROGRAM_SIZE); + if (l > USHRT_MAX) { + char buf[256]; + + sprintf(buf, "branch limit exceeded in %s, near line %i", + where, line_being_generated); + yyerror(buf); + } + s = l; + + COPY_SHORT(mem_block[A_PROGRAM].block + offset, &s); +} + +static void ins_rel_short (int l) +{ + if (l > USHRT_MAX) { + char buf[256]; + + sprintf(buf, "branch limit exceeded in switch table, near line %i", + line_being_generated); + yyerror(buf); + } + ins_short(l); +} + +static void ins_byte (unsigned char b) +{ + if (prog_code == prog_code_max) { + mem_block_t *mbp = &mem_block[A_PROGRAM]; + UPDATE_PROGRAM_SIZE; + realloc_mem_block(mbp); + + prog_code = mbp->block + mbp->current_size; + prog_code_max = mbp->block + mbp->max_size; + } + *prog_code++ = b; +} + +static void upd_byte (int offset, unsigned char b) +{ + IF_DEBUG(UPDATE_PROGRAM_SIZE); + DEBUG_CHECK2(offset > CURRENT_PROGRAM_SIZE, + "patch offset %x larger than current program size %x.\n", + offset, CURRENT_PROGRAM_SIZE); + mem_block[A_PROGRAM].block[offset] = b; +} + +static void end_pushes (void) { + if (push_state) { + if (push_state > 1) + upd_byte(push_start, push_state); + push_state = 0; + } +} + +// +// F_PUSH pushes multiple data items onto the stack. This function +// sets up the multi push by reading the single push off the top of +// the stack and rewriting the mult-push into the stack. +// + +static void initialize_push (void) { + int what = mem_block[A_PROGRAM].block[push_start]; + int arg = 0; + + // This is only valid if it is not a one byte const target. + if (what != F_CONST0 && what != F_CONST1) { + arg = mem_block[A_PROGRAM].block[push_start + 1]; + } + prog_code = mem_block[A_PROGRAM].block + push_start; + ins_byte(F_PUSH); + push_start++; /* now points to the zero here */ + ins_byte(0); + + switch (what) { + case F_CONST0: + ins_byte(PUSH_NUMBER | 0); + break; + case F_CONST1: + ins_byte(PUSH_NUMBER | 1); + break; + case F_BYTE: + ins_byte(PUSH_NUMBER | arg); + break; + case F_SHORT_STRING: + ins_byte(PUSH_STRING | arg); + break; + case F_LOCAL: + ins_byte(PUSH_LOCAL | arg); + break; + case F_GLOBAL: + ins_byte(PUSH_GLOBAL | arg); + break; + } +} + + +/* + * Generate the code to push a number on the stack. + * This varies since there are several opcodes (for + * optimizing speed and/or size). + */ +static void write_small_number (int val) { + if (try_to_push(PUSH_NUMBER, val)) return; + ins_byte(F_BYTE); + ins_byte(val); +} + +static void write_number (long val) +{ + if ((val & ~0xff) == 0) + write_small_number(val); + else { + end_pushes(); + if (val < 0 && val > -256) { + ins_byte(F_NBYTE); + ins_byte(-val); + } else if (val >= -32768 && val <= 32767) { + ins_byte(F_SHORT_INT); + ins_short(val); + } else { + ins_byte(F_NUMBER); +#if SIZEOF_LONG == 4 + ins_int(val); +#else + ins_long(val); +#endif + } + } +} + +static void +generate_expr_list (parse_node_t * expr) { + parse_node_t *pn; + int n, flag; + + if (!expr) return; + pn = expr; + flag = n = 0; + do { + if (pn->type & 1) flag = 1; + i_generate_node(pn->v.expr); + n++; + } while ((pn = pn->r.expr)); + + if (flag) { + pn = expr; + do { + n--; + if (pn->type & 1) { + end_pushes(); + ins_byte(F_EXPAND_VARARGS); + ins_byte(n); + } + } while ((pn = pn->r.expr)); + } +} + +static void +generate_lvalue_list (parse_node_t * expr) { + while ((expr = expr->r.expr)) { + i_generate_node(expr->l.expr); + end_pushes(); + ins_byte(F_VOID_ASSIGN); + } +} + +INLINE_STATIC void +switch_to_line (unsigned int line) { + unsigned int sz = CURRENT_PROGRAM_SIZE - last_size_generated; + ADDRESS_TYPE s; + unsigned char *p; + + if (sz) { + s = line_being_generated; + + last_size_generated += sz; + while (sz > 255) { + p = (unsigned char *)allocate_in_mem_block(A_LINENUMBERS, sizeof(ADDRESS_TYPE) + 1); + *p++ = 255; +#if !defined(USE_32BIT_ADDRESSES) + STORE_SHORT(p, s); +#else + STORE4(p, s); +#endif + sz -= 255; + } + p = (unsigned char *)allocate_in_mem_block(A_LINENUMBERS, sizeof(ADDRESS_TYPE) + 1); + *p++ = sz; +#if !defined(USE_32BIT_ADDRESSES) + STORE_SHORT(p, s); +#else + STORE4(p, s); +#endif + } + line_being_generated = line; +} + +static int +try_to_push (int kind, int value) { + if (push_state) { + if (value <= PUSH_MASK) { + if (push_state == 1) + initialize_push(); + push_state++; + ins_byte(kind | value); + if (push_state == 255) + end_pushes(); + return 1; + } else end_pushes(); + } else if (value <= PUSH_MASK) { + push_start = CURRENT_PROGRAM_SIZE; + push_state = 1; + switch (kind) { + case PUSH_STRING: ins_byte(F_SHORT_STRING); break; + case PUSH_LOCAL: ins_byte(F_LOCAL); break; + case PUSH_GLOBAL: ins_byte(F_GLOBAL); break; + case PUSH_NUMBER: + if (value == 0) { + ins_byte(F_CONST0); + return 1; + } else if (value == 1) { + ins_byte(F_CONST1); + return 1; + } + ins_byte(F_BYTE); + } + if (kind == PUSH_GLOBAL) { + INS_GLOBAL_INDEX(value); + } else { + ins_byte(value); + } + return 1; + } + return 0; +} + +void +i_generate_node (parse_node_t * expr) { + if (!expr) return; + + if (expr->line && expr->line != line_being_generated) + switch_to_line(expr->line); + switch (expr->kind) { + case NODE_FUNCTION: + { + unsigned short num; + + /* In the following we know that this function wins all the */ + /* rest - Sym */ + + num = FUNCTION_TEMP(expr->v.number)->u.index; + FUNC(num)->address = generate_function(FUNC(num), + expr->r.expr, expr->l.number); + break; + } + case NODE_TERNARY_OP: + i_generate_node(expr->l.expr); + expr = expr->r.expr; + case NODE_BINARY_OP: + i_generate_node(expr->l.expr); + /* fall through */ + case NODE_UNARY_OP: + i_generate_node(expr->r.expr); + /* fall through */ + case NODE_OPCODE: + end_pushes(); + ins_byte(expr->v.number); + break; + case NODE_TERNARY_OP_1: + i_generate_node(expr->l.expr); + expr = expr->r.expr; + /* fall through */ + case NODE_BINARY_OP_1: + i_generate_node(expr->l.expr); + i_generate_node(expr->r.expr); + end_pushes(); + ins_byte(expr->v.number); + ins_byte(expr->type); + break; + case NODE_UNARY_OP_1: + i_generate_node(expr->r.expr); + /* fall through */ + case NODE_OPCODE_1: + if (expr->v.number == F_LOCAL) { + if (try_to_push(PUSH_LOCAL, expr->l.number)) break; + } else if (expr->v.number == F_GLOBAL) { + if (try_to_push(PUSH_GLOBAL, expr->l.number)) break; + } + end_pushes(); + ins_byte(expr->v.number); + + if ((expr->v.number == F_GLOBAL) || + (expr->v.number == F_GLOBAL_LVALUE)) { + INS_GLOBAL_INDEX(expr->l.number); + } else { + ins_byte(expr->l.number); + } + + break; + case NODE_OPCODE_2: + end_pushes(); + ins_byte(expr->v.number); + ins_byte(expr->l.number); + if (expr->v.number == F_LOOP_COND_NUMBER) +#if SIZEOF_LONG == 8 + ins_long(expr->r.number); +#else + ins_int(expr->r.number); +#endif + else + ins_byte(expr->r.number); + break; + case NODE_RETURN: + { + int n; + n = foreach_depth; + end_pushes(); + while (n--) + ins_byte(F_EXIT_FOREACH); + + if (expr->r.expr) { + i_generate_node(expr->r.expr); + end_pushes(); + ins_byte(F_RETURN); + } else ins_byte(F_RETURN_ZERO); + break; + } + case NODE_STRING: + if (try_to_push(PUSH_STRING, expr->v.number)) break; + if (expr->v.number <= 0xff) { + ins_byte(F_SHORT_STRING); + ins_byte(expr->v.number); + } else { + ins_byte(F_STRING); + ins_short(expr->v.number); + } + break; + case NODE_REAL: + end_pushes(); + ins_byte(F_REAL); + ins_real(expr->v.real); + break; + case NODE_NUMBER: + write_number(expr->v.number); + break; + case NODE_LAND_LOR: + i_generate_node(expr->l.expr); + i_generate_forward_branch(expr->v.number); + i_generate_node(expr->r.expr); + if (expr->l.expr->kind == NODE_BRANCH_LINK) + i_update_forward_branch_links(expr->v.number,expr->l.expr); + else + i_update_forward_branch("&& or ||"); + break; + case NODE_BRANCH_LINK: + i_generate_node(expr->l.expr); + end_pushes(); + ins_byte(0); + expr->v.number = CURRENT_PROGRAM_SIZE; + ins_short(0); + i_generate_node(expr->r.expr); + break; + case NODE_CALL_2: + generate_expr_list(expr->r.expr); + end_pushes(); + ins_byte(expr->v.number); + ins_byte(expr->l.number >> 16); + ins_short(expr->l.number & 0xffff); + ins_byte((expr->r.expr ? expr->r.expr->kind : 0)); + break; + case NODE_CALL_1: + generate_expr_list(expr->r.expr); + end_pushes(); + if (expr->v.number == F_CALL_FUNCTION_BY_ADDRESS) { + expr->l.number = comp_def_index_map[expr->l.number]; + } + ins_byte(expr->v.number); + ins_short(expr->l.number); + ins_byte((expr->r.expr ? expr->r.expr->kind : 0)); + break; + case NODE_CALL: + generate_expr_list(expr->r.expr); + end_pushes(); + ins_byte(expr->v.number); + ins_short(expr->l.number); + break; + case NODE_TWO_VALUES: + i_generate_node(expr->l.expr); + i_generate_node(expr->r.expr); + break; + case NODE_CONTROL_JUMP: + { + int kind = expr->v.number; + end_pushes(); + ins_byte(F_BRANCH); + expr->v.expr = branch_list[kind]; + expr->l.number = CURRENT_PROGRAM_SIZE; + ins_short(0); + branch_list[kind] = expr; + break; + } + case NODE_PARAMETER: + { + int which = expr->v.number + current_num_values; + if (try_to_push(PUSH_LOCAL, which)) break; + ins_byte(F_LOCAL); + ins_byte(which); + break; + } + case NODE_PARAMETER_LVALUE: + end_pushes(); + ins_byte(F_LOCAL_LVALUE); + ins_byte(expr->v.number + current_num_values); + break; + case NODE_IF: + i_generate_if_branch(expr->v.expr, 0); + i_generate_node(expr->l.expr); + if (expr->r.expr) { + i_generate_else(); + i_generate_node(expr->r.expr); + } + i_update_forward_branch("if"); + break; + case NODE_LOOP: + i_generate_loop(expr->type, expr->v.expr, expr->l.expr, expr->r.expr); + break; + case NODE_FOREACH: + { + int tmp = 0; + int left_is_global = 0; + + i_generate_node(expr->v.expr); + end_pushes(); + ins_byte(F_FOREACH); + if (expr->l.expr->v.number == F_GLOBAL_LVALUE) + tmp |= FOREACH_RIGHT_GLOBAL; + else if (expr->l.expr->v.number == F_REF_LVALUE) + tmp |= FOREACH_REF; + if (expr->r.expr) { + if (tmp & FOREACH_RIGHT_GLOBAL) + tmp = (tmp & ~FOREACH_RIGHT_GLOBAL) | FOREACH_LEFT_GLOBAL; + + tmp |= FOREACH_MAPPING; + if (expr->r.expr->v.number == F_GLOBAL_LVALUE) + tmp |= FOREACH_RIGHT_GLOBAL; + else if (expr->r.expr->v.number == F_REF_LVALUE) + tmp |= FOREACH_REF; + } + ins_byte(tmp); + + if (tmp & FOREACH_MAPPING) { + if (tmp & FOREACH_LEFT_GLOBAL) { + left_is_global = 1; + } + } else { + if (tmp & FOREACH_RIGHT_GLOBAL) { + left_is_global = 1; + } + } + + if (left_is_global == 1) { + INS_GLOBAL_INDEX(expr->l.expr->l.number); + } else { + ins_byte(expr->l.expr->l.number); + } + + if (expr->r.expr) { + + if (tmp & FOREACH_RIGHT_GLOBAL) { + INS_GLOBAL_INDEX(expr->r.expr->l.number); + } else { + ins_byte(expr->r.expr->l.number); + } + } + } + break; + case NODE_CASE_NUMBER: + case NODE_CASE_STRING: + if (expr->v.expr) { + parse_node_t *other = expr->v.expr; + expr->v.number = 1; + other->l.expr = expr->l.expr; + other->v.number = CURRENT_PROGRAM_SIZE; + expr->l.expr = other; + } else { + expr->v.number = CURRENT_PROGRAM_SIZE; + } + end_pushes(); + break; + case NODE_DEFAULT: + expr->v.number = CURRENT_PROGRAM_SIZE; + end_pushes(); + break; + case NODE_SWITCH_STRINGS: + case NODE_SWITCH_NUMBERS: + case NODE_SWITCH_DIRECT: + case NODE_SWITCH_RANGES: + { + long addr, last_break; + parse_node_t *sub = expr->l.expr; + parse_node_t *save_switch_breaks = branch_list[CJ_BREAK_SWITCH]; + + i_generate_node(sub); + branch_list[CJ_BREAK_SWITCH] = 0; + end_pushes(); + ins_byte(F_SWITCH); + addr = CURRENT_PROGRAM_SIZE; + /* all these are addresses in here are relative to addr now, + * which is also the value of pc in f_switch(). Note that + * addr is one less than it was in older drivers. + */ + ins_byte(0xff); /* kind of table */ + ins_short(0); /* address of table */ + ins_short(0); /* end of table */ + ins_short(0); /* default address */ + i_generate_node(expr->r.expr); + if (expr->v.expr && expr->v.expr->kind == NODE_DEFAULT) { + upd_short(addr + 5, expr->v.expr->v.number - addr, + "switch"); + expr->v.expr = expr->v.expr->l.expr; + } else { + upd_short(addr + 5, CURRENT_PROGRAM_SIZE - addr, "switch"); + } + /* just in case the last case doesn't have a break */ + end_pushes(); + ins_byte(F_BRANCH); + last_break = CURRENT_PROGRAM_SIZE; + ins_short(0); + /* build table */ + upd_short(addr + 1, CURRENT_PROGRAM_SIZE - addr, "switch"); + + if (expr->kind == NODE_SWITCH_DIRECT) { + parse_node_t *pn = expr->v.expr; + while (pn) { + ins_rel_short(pn->v.number - addr); + pn = pn->l.expr; + } + ins_int(expr->v.expr->r.number); + mem_block[A_PROGRAM].block[addr] = (char)0xfe; + } else { + int table_size = 0; + int power_of_two = 1; + int i = 0; + parse_node_t *pn = expr->v.expr; + + while (pn) { + if (expr->kind == NODE_SWITCH_STRINGS) { + if (pn->r.number) { + INS_POINTER((POINTER_INT) + PROG_STRING(pn->r.number)); + } else + INS_POINTER((POINTER_INT)0); + } else + INS_POINTER((POINTER_INT)pn->r.expr); + if (pn->v.number == 1) + ins_short(1); + else + ins_rel_short(pn->v.number - addr); + pn = pn->l.expr; + table_size += 1; + } + while ((power_of_two<<1) <= table_size) { + power_of_two <<= 1; + i++; + } + if (expr->kind != NODE_SWITCH_STRINGS) + mem_block[A_PROGRAM].block[addr] = (char)(0xf0+i); + else + mem_block[A_PROGRAM].block[addr] = (char)(i*0x10+0x0f); + } + i_update_branch_list(branch_list[CJ_BREAK_SWITCH], "switch break"); + branch_list[CJ_BREAK_SWITCH] = save_switch_breaks; + upd_short(last_break, CURRENT_PROGRAM_SIZE - last_break, "switch break"); + upd_short(addr+3, CURRENT_PROGRAM_SIZE - addr, "switch"); + break; + } + case NODE_CATCH: + { + int addr; + + end_pushes(); + ins_byte(F_CATCH); + addr = CURRENT_PROGRAM_SIZE; + ins_short(0); + i_generate_node(expr->r.expr); + ins_byte(F_END_CATCH); + upd_short(addr, CURRENT_PROGRAM_SIZE - addr, "catch"); + break; + } + case NODE_TIME_EXPRESSION: + { + end_pushes(); + ins_byte(F_TIME_EXPRESSION); + i_generate_node(expr->r.expr); + ins_byte(F_END_TIME_EXPRESSION); + break; + } + case NODE_LVALUE_EFUN: + i_generate_node(expr->l.expr); + generate_lvalue_list(expr->r.expr); + break; + case NODE_FUNCTION_CONSTRUCTOR: + if (expr->r.expr) { + generate_expr_list(expr->r.expr); + end_pushes(); + ins_byte(F_AGGREGATE); + ins_short(expr->r.expr->kind); + } else { + end_pushes(); + ins_byte(F_CONST0); + } + end_pushes(); + + ins_byte(F_FUNCTION_CONSTRUCTOR); + ins_byte(expr->v.number & 0xff); + + switch (expr->v.number & 0xff) { + case FP_SIMUL: + ins_short(expr->v.number >> 8); + break; + case FP_LOCAL: + ins_short(comp_def_index_map[expr->v.number >> 8]); + break; + case FP_EFUN: + ins_short(predefs[expr->v.number >> 8].token); + break; + case FP_FUNCTIONAL: + case FP_FUNCTIONAL | FP_NOT_BINDABLE: + { + int addr, save_current_num_values = current_num_values; + ins_byte(expr->v.number >> 8); + addr = CURRENT_PROGRAM_SIZE; + ins_short(0); + current_num_values = expr->r.expr ? expr->r.expr->kind : 0; + i_generate_node(expr->l.expr); + current_num_values = save_current_num_values; + end_pushes(); + ins_byte(F_RETURN); + upd_short(addr, CURRENT_PROGRAM_SIZE - addr - 2, + "function pointer"); + break; + } + } + break; + case NODE_ANON_FUNC: + { + int addr; + int save_fd = foreach_depth; + + foreach_depth = 0; + end_pushes(); + ins_byte(F_FUNCTION_CONSTRUCTOR); + if (expr->v.number & 0x10000) + ins_byte(FP_ANONYMOUS | FP_NOT_BINDABLE); + else + ins_byte(FP_ANONYMOUS); + ins_byte(expr->v.number & 0xff); + ins_byte(expr->l.number); + addr = CURRENT_PROGRAM_SIZE; + ins_short(0); + i_generate_node(expr->r.expr); + upd_short(addr, CURRENT_PROGRAM_SIZE - addr - 2, + "function pointer"); + foreach_depth = save_fd; + break; + } + case NODE_EFUN: + { + int novalue_used = expr->v.number & NOVALUE_USED_FLAG; + int f = expr->v.number & ~NOVALUE_USED_FLAG; + + generate_expr_list(expr->r.expr); + end_pushes(); + if (f < ONEARG_MAX) { + ins_byte(f); + } else { + /* max_arg == -1 must use F_EFUNV so that varargs expansion works*/ + if (expr->l.number < 4 && instrs[f].max_arg != -1) + ins_byte(F_EFUN0 + expr->l.number); + else { + ins_byte(F_EFUNV); + ins_byte(expr->l.number); + } + ins_byte(f - ONEARG_MAX); + } + if (novalue_used) { + /* the value of a void efun was used. Put in a zero. */ + ins_byte(F_CONST0); + } + break; + } + default: + fatal("Unknown node %i in i_generate_node.\n", expr->kind); + } +} + +static void i_generate_loop (int test_first, parse_node_t * block, + parse_node_t * inc, parse_node_t * test) { + parse_node_t *save_breaks = branch_list[CJ_BREAK]; + parse_node_t *save_continues = branch_list[CJ_CONTINUE]; + int forever = node_always_true(test); + int pos; + + if (test_first == 2) foreach_depth++; + branch_list[CJ_BREAK] = branch_list[CJ_CONTINUE] = 0; + end_pushes(); + if (!forever && test_first) + i_generate_forward_branch(F_BRANCH); + pos = CURRENT_PROGRAM_SIZE; + i_generate_node(block); + i_update_branch_list(branch_list[CJ_CONTINUE], "continue"); + if (inc) i_generate_node(inc); + if (!forever && test_first) i_update_forward_branch("loop"); + if (test && (test->v.number == F_LOOP_COND_LOCAL || + test->v.number == F_LOOP_COND_NUMBER || + test->v.number == F_NEXT_FOREACH)) { + i_generate_node(test); + ins_short(CURRENT_PROGRAM_SIZE - pos); + } else i_branch_backwards(generate_conditional_branch(test), pos); + i_update_branch_list(branch_list[CJ_BREAK], "break"); + branch_list[CJ_BREAK] = save_breaks; + branch_list[CJ_CONTINUE] = save_continues; + if (test_first == 2) foreach_depth--; +} + +static void +i_generate_if_branch (parse_node_t * node, int invert) { + int generate_both = 0; + int branch = (invert ? F_BRANCH_WHEN_NON_ZERO : F_BRANCH_WHEN_ZERO); + + switch (node->kind) { + case NODE_UNARY_OP: + if (node->v.number == F_NOT) { + i_generate_if_branch(node->r.expr, !invert); + return; + } + break; + case NODE_BINARY_OP: + switch (node->v.number) { + case F_EQ: + generate_both = 1; + branch = (invert ? F_BRANCH_EQ : F_BRANCH_NE); + break; + case F_GE: + if (invert) { + generate_both = 1; + branch = F_BRANCH_GE; + } + break; + case F_LE: + if (invert) { + generate_both = 1; + branch = F_BRANCH_LE; + } + break; + case F_LT: + if (!invert) { + generate_both = 1; + branch = F_BRANCH_GE; + } + break; + case F_GT: + if (!invert) { + generate_both = 1; + branch = F_BRANCH_LE; + } + break; + case F_NE: + generate_both = 1; + branch = (invert ? F_BRANCH_NE : F_BRANCH_EQ); + break; + } + } + if (generate_both) { + i_generate_node(node->l.expr); + i_generate_node(node->r.expr); + } else { + i_generate_node(node); + } + i_generate_forward_branch(branch); +} + +void +i_generate_inherited_init_call (int index, short f) { + end_pushes(); + ins_byte(F_CALL_INHERITED); + ins_byte(index); + ins_short(f); + ins_byte(0); + ins_byte(F_POP_VALUE); +} + +void i_generate_forward_branch (char b) { + end_pushes(); + ins_byte(b); + if (nforward_branches == nforward_branches_max) { + nforward_branches_max += 10; + forward_branches = RESIZE(forward_branches, nforward_branches_max, int, + TAG_COMPILER, "forward_branches"); + } + + forward_branches[nforward_branches++] = CURRENT_PROGRAM_SIZE; + ins_short(0); +} + +void +i_update_forward_branch (const char * what) { + end_pushes(); + nforward_branches--; + upd_short(forward_branches[nforward_branches], + CURRENT_PROGRAM_SIZE - forward_branches[nforward_branches], + what); +} + +void i_update_forward_branch_links (char kind, parse_node_t * link_start) { + int i; + + end_pushes(); + nforward_branches--; + upd_short(forward_branches[nforward_branches], + CURRENT_PROGRAM_SIZE - forward_branches[nforward_branches], + "&& or ||"); + do { + i = link_start->v.number; + upd_byte(i-1, kind); + upd_short(i, CURRENT_PROGRAM_SIZE - i, "&& or ||"); + link_start = link_start->l.expr; + } while (link_start->kind == NODE_BRANCH_LINK); +} + +void +i_branch_backwards (char b, int addr) { + end_pushes(); + if (b) { + if (b != F_WHILE_DEC) + ins_byte(b); + ins_short(CURRENT_PROGRAM_SIZE - addr); + } +} + +static void +i_update_branch_list (parse_node_t * bl, const char * what) { + int current_size; + + end_pushes(); + current_size = CURRENT_PROGRAM_SIZE; + + while (bl) { + upd_short(bl->l.number, current_size - bl->l.number, what); + bl = bl->v.expr; + } +} + +void +i_generate_else() { + int old; + + old = forward_branches[nforward_branches - 1]; + + /* set up a new branch to after the end of the if */ + end_pushes(); + ins_byte(F_BRANCH); + forward_branches[nforward_branches-1] = CURRENT_PROGRAM_SIZE; + ins_short(0); + + /* update the old branch to point to this point */ + upd_short(old, CURRENT_PROGRAM_SIZE - old, "if"); +} + +void +i_initialize_parser() { + foreach_depth = 0; + + if (!forward_branches) { + forward_branches = CALLOCATE(10, int, TAG_COMPILER, "forward_branches"); + nforward_branches_max = 10; + } + nforward_branches = 0; + + branch_list[CJ_BREAK] = 0; + branch_list[CJ_BREAK_SWITCH] = 0; + branch_list[CJ_CONTINUE] = 0; + + prog_code = mem_block[A_PROGRAM].block; + prog_code_max = mem_block[A_PROGRAM].block + mem_block[A_PROGRAM].max_size; + + line_being_generated = 0; + last_size_generated = 0; +} + +void +i_uninitialize_parser() { +#ifdef DEBUGMALLOC_EXTENSIONS + /* + * The intention is to keep the allocated space for forward branches + * hanging around between compiles so we don't have to keep allocating it. + * The problem is that with DEBUGMALLOC_EXENTIONS compiled in, it'll be + * reported as a memory leak, so clean it up here. Yes, it's a performance + * hit, but we're trying to debug not run a race, so deal with it. + * -- Marius, 11-Aug-2000 + */ + if (forward_branches) { + FREE(forward_branches); + forward_branches = 0; + } +#endif +} + +void +i_generate_final_program (int x) { + if (!x) { + UPDATE_PROGRAM_SIZE; + /* This needs more work */ +// if (pragmas & PRAGMA_OPTIMIZE) +// optimize_icode(0, 0, 0); + + save_file_info(current_file_id, current_line - current_line_saved); + switch_to_line(-1); /* generate line numbers for the end */ + } +} + +/* Currently, this procedure handles: + * - jump threading + */ +void +optimize_icode (char * start, char * pc, char * end) { + int instr = 0, prev; + if (start == 0) { + /* we don't optimize the initializer block right now b/c all the + * stuff we do (jump threading, etc) can't occur there. + */ + start = mem_block[A_PROGRAM].block; + pc = start; + end = pc + mem_block[A_PROGRAM].current_size; + if (*pc == 0) { + /* no initializer jump */ + pc += 3; + } + } + while (pc < end) { + prev = instr; + switch (instr = EXTRACT_UCHAR(pc++)) { +#if SIZEOF_LONG == 4 + case F_NUMBER: +#endif + case F_REAL: + case F_CALL_INHERITED: + pc += 4; + break; +#if SIZEOF_LONG == 8 + case F_NUMBER: + pc += 8; + break; +#endif + case F_SIMUL_EFUN: + case F_CALL_FUNCTION_BY_ADDRESS: + pc += 3; + break; + case F_BRANCH_NE: + case F_BRANCH_GE: + case F_BRANCH_LE: + case F_BRANCH_EQ: + case F_BRANCH: + case F_BRANCH_WHEN_ZERO: + case F_BRANCH_WHEN_NON_ZERO: + case F_BBRANCH: + case F_BBRANCH_WHEN_ZERO: + case F_BBRANCH_WHEN_NON_ZERO: + case F_BBRANCH_LT: + { + char *tmp; + short sarg; + /* thread jumps */ + COPY_SHORT(&sarg, pc); + if (instr > F_BRANCH) + tmp = pc - sarg; + else + tmp = pc + sarg; + sarg = 0; + while (1) { + if (EXTRACT_UCHAR(tmp) == F_BRANCH) { + COPY_SHORT(&sarg, tmp + 1); + tmp += sarg + 1; + } else if (EXTRACT_UCHAR(tmp) == F_BBRANCH) { + COPY_SHORT(&sarg, tmp + 1); + tmp -= sarg - 1; + } else break; + } + if (!sarg) { + pc += 2; + break; + } + /* be careful; in the process of threading a forward jump + * may have changed to a reverse one or vice versa + */ + if (tmp > pc) { + if (instr > F_BRANCH) { + pc[-1] -= 3; /* change to forward branch */ + } + sarg = tmp - pc; + } else { + if (instr <= F_BRANCH) { + pc[-1] += 3; /* change to backwards branch */ + } + sarg = pc - tmp; + } + STORE_SHORT(pc, sarg); + break; + } +#ifdef F_LOR + case F_LOR: + case F_LAND: + { + char *tmp; + short sarg; + /* thread jumps */ + COPY_SHORT(&sarg, pc); + tmp = pc + sarg; + sarg = 0; + while (1) { + if (EXTRACT_UCHAR(tmp) == F_BRANCH) { + COPY_SHORT(&sarg, tmp + 1); + tmp += sarg + 1; + } else if (EXTRACT_UCHAR(tmp) == F_BBRANCH) { + COPY_SHORT(&sarg, tmp + 1); + tmp -= sarg - 1; + } else break; + } + if (!sarg) { + pc += 2; + break; + } + /* be careful; in the process of threading a forward jump + * may have changed to a reverse one or vice versa + */ + if (tmp > pc) { + sarg = tmp - pc; + } else { +#ifdef DEBUG + fprintf(stderr,"Optimization failed; can't || or && backwards.\n"); +#endif + pc += 2; + break; + } + STORE_SHORT(pc, sarg); + break; + } +#endif + case F_CATCH: + case F_AGGREGATE: + case F_AGGREGATE_ASSOC: + case F_NEXT_FOREACH: + case F_GLOBAL: + case F_GLOBAL_LVALUE: + case F_STRING: +#ifdef F_JUMP_WHEN_ZERO + case F_JUMP_WHEN_ZERO: + case F_JUMP_WHEN_NON_ZERO: +#endif +#ifdef F_JUMP + case F_JUMP: +#endif + pc += 2; + break; + case F_SHORT_STRING: + case F_LOOP_INCR: + case F_WHILE_DEC: + case F_LOCAL: + case F_LOCAL_LVALUE: + case F_REF: + case F_REF_LVALUE: + case F_SSCANF: + case F_PARSE_COMMAND: + case F_BYTE: + case F_NBYTE: + case F_TRANSFER_LOCAL: + pc++; + break; + case F_FUNCTION_CONSTRUCTOR: + switch (EXTRACT_UCHAR(pc++)) { + case FP_SIMUL: + case FP_LOCAL: + pc += 2; + break; + case FP_FUNCTIONAL: + case FP_FUNCTIONAL | FP_NOT_BINDABLE: + pc += 3; + break; + case FP_ANONYMOUS: + case FP_ANONYMOUS | FP_NOT_BINDABLE: + pc += 4; + break; + case FP_EFUN: + pc += 2; + break; + } + break; + case F_SWITCH: + { + unsigned short stable, etable; + char *swstart = pc; + pc++; /* table type */ + LOAD_SHORT(stable, pc); + LOAD_SHORT(etable, pc); + pc += 2; /* def */ + //break; //doesn't seem to work! + printf("stable: %x pc %x swstart %x etable %x\n", stable, pc, swstart, etable); + DEBUG_CHECK(stable < pc - swstart || etable < pc - swstart + || etable < stable, + "Error in switch table found while optimizing\n"); + /* recursively optimize the inside of the switch */ + optimize_icode(start, pc, start + stable); + pc = swstart + etable; + break; + } + case F_PUSH: + { + pc+=EXTRACT_UCHAR(pc); + pc++; + break; + } + case F_EFUNV: + pc++; + case F_EFUN0: + case F_EFUN1: + case F_EFUN2: + case F_EFUN3: + instr = EXTRACT_UCHAR(pc++) + ONEARG_MAX; + default: + if(instr < BASE || instr > NUM_OPCODES) + printf("instr %d prev %d\n", instr, prev); + if(!instr || instr > NUM_OPCODES) + fatal("illegal opcode"); + prev = instr; +// if ((instr >= BASE) && +// (instrs[instr].min_arg != instrs[instr].max_arg)) +// pc++; + } + } +} + + + + diff --git a/fluffos-2.23-ds03/icode.h b/fluffos-2.23-ds03/icode.h new file mode 100644 index 0000000..22a2e62 --- /dev/null +++ b/fluffos-2.23-ds03/icode.h @@ -0,0 +1,29 @@ +/* + * Defines and types for LPC stackmachine code + */ + +#ifndef _ICODE_H +#define _ICODE_H +#include "trees.h" + +void i_generate___INIT (void); +void i_generate_node (parse_node_t *); +void i_generate_continue (void); +void i_generate_forward_jump (void); +void i_update_forward_jump (void); +void i_update_continues (void); +void i_branch_backwards (char, int); +void i_update_breaks (void); +void i_save_loop_info (parse_node_t *); +void i_restore_loop_info (void); +void i_generate_forward_branch (char); +void i_update_forward_branch (const char *); +void i_update_forward_branch_links (char, parse_node_t *); +void i_generate_else (void); +void i_initialize_parser (void); +void i_uninitialize_parser (void); +void i_generate_final_program (int); +void i_generate_inherited_init_call (int, short); + +void optimize_icode (char *, char *, char *); +#endif diff --git a/fluffos-2.23-ds03/include/function.h b/fluffos-2.23-ds03/include/function.h new file mode 100644 index 0000000..ae528e9 --- /dev/null +++ b/fluffos-2.23-ds03/include/function.h @@ -0,0 +1,17 @@ +/* codes returned by the functionp() efun */ + +#define FP_LOCAL 2 +#define FP_EFUN 3 +#define FP_SIMUL 4 +#define FP_FUNCTIONAL 5 + +/* internal use */ +#define FP_G_VAR 6 +#define FP_L_VAR 7 +#define FP_ANONYMOUS 8 + +/* additional flags */ +#define FP_MASK 0x0f +#define FP_HAS_ARGUMENTS 0x10 +#define FP_OWNER_DESTED 0x20 +#define FP_NOT_BINDABLE 0x40 diff --git a/fluffos-2.23-ds03/include/localtime.h b/fluffos-2.23-ds03/include/localtime.h new file mode 100644 index 0000000..1bea86d --- /dev/null +++ b/fluffos-2.23-ds03/include/localtime.h @@ -0,0 +1,15 @@ + +/* + * Definitions for localtime() efun + */ +#define LT_SEC 0 +#define LT_MIN 1 +#define LT_HOUR 2 +#define LT_MDAY 3 +#define LT_MON 4 +#define LT_YEAR 5 +#define LT_WDAY 6 +#define LT_YDAY 7 +#define LT_GMTOFF 8 +#define LT_ZONE 9 +#define LT_ISDST 10 diff --git a/fluffos-2.23-ds03/include/origin.h b/fluffos-2.23-ds03/include/origin.h new file mode 100644 index 0000000..4691198 --- /dev/null +++ b/fluffos-2.23-ds03/include/origin.h @@ -0,0 +1,13 @@ +/* codes returned by the origin() efun */ + +#define ORIGIN_BACKEND "driver" /* backwards compat */ +#define ORIGIN_DRIVER "driver" +#define ORIGIN_LOCAL "local" +#define ORIGIN_CALL_OTHER "call_other" +#define ORIGIN_SIMUL_EFUN "simul" +#define ORIGIN_INTERNAL "internal" +#define ORIGIN_EFUN "efun" +/* pseudo frames for call_other function pointers and efun pointer */ +#define ORIGIN_FUNCTION_POINTER "function_pointer" +/* anonymous functions */ +#define ORIGIN_FUNCTIONAL "functional" diff --git a/fluffos-2.23-ds03/include/parser_error.h b/fluffos-2.23-ds03/include/parser_error.h new file mode 100644 index 0000000..9bcd077 --- /dev/null +++ b/fluffos-2.23-ds03/include/parser_error.h @@ -0,0 +1,14 @@ +#ifndef PARSER_ERROR_H +#define PARSER_ERROR_H + +#define ERR_IS_NOT 1 +#define ERR_NOT_LIVING 2 +#define ERR_NOT_ACCESSIBLE 3 +#define ERR_AMBIG 4 +#define ERR_ORDINAL 5 +#define ERR_ALLOCATED 6 +#define ERR_THERE_IS_NO 7 +#define ERR_BAD_MULTIPLE 8 +#define ERR_MANY_PATHS 9 + +#endif diff --git a/fluffos-2.23-ds03/include/runtime_config.h b/fluffos-2.23-ds03/include/runtime_config.h new file mode 100644 index 0000000..4ba52b0 --- /dev/null +++ b/fluffos-2.23-ds03/include/runtime_config.h @@ -0,0 +1,93 @@ +/* + * runtime_config.h + * + * Copy this file to your mudlib include dir for use with the + * get_config() efun. + * + * See Config.Example describing most of these settings. Some are actually + * in options.h, but the mudlib doesn't have to know... + * + * Note for backwards compatibility: + * + * get_config(__MUD_NAME__) == MUD_NAME + * get_config(__MUD_PORT__) == __PORT__ + */ + +#ifndef RUNTIME_CONFIG_H +#define RUNTIME_CONFIG_H + +#define BASE_CONFIG_STR 0 +#define CFG_STR(x) ((x) + BASE_CONFIG_STR) +/* + * These config settings return a string + */ + +#define __MUD_NAME__ CFG_STR(0) + +#define __ADDR_SERVER_IP__ CFG_STR(1) + +#define __MUD_LIB_DIR__ CFG_STR(2) +#define __BIN_DIR__ CFG_STR(3) + +#define __LOG_DIR__ CFG_STR(4) +#define __INCLUDE_DIRS__ CFG_STR(5) + +#define __MASTER_FILE__ CFG_STR(7) +#define __SIMUL_EFUN_FILE__ CFG_STR(8) +#define __SWAP_FILE__ CFG_STR(9) +#define __DEBUG_LOG_FILE__ CFG_STR(10) + +#define __DEFAULT_ERROR_MESSAGE__ CFG_STR(11) +#define __DEFAULT_FAIL_MESSAGE__ CFG_STR(12) +#define __GLOBAL_INCLUDE_FILE__ CFG_STR(13) + +#define __MUD_IP__ CFG_STR(14) + +/* + * These config settings return an int (ie number) + */ + +#define BASE_CONFIG_INT (BASE_CONFIG_STR + 15) +#define CFG_INT(x) ((x) + BASE_CONFIG_INT) + +#define __MUD_PORT__ CFG_INT(0) +#define __ADDR_SERVER_PORT__ CFG_INT(1) + +#define __TIME_TO_CLEAN_UP__ CFG_INT(2) +#define __TIME_TO_RESET__ CFG_INT(3) +#define __TIME_TO_SWAP__ CFG_INT(4) + +#define __COMPILER_STACK_SIZE__ CFG_INT(5) +#define __EVALUATOR_STACK_SIZE__ CFG_INT(6) +#define __INHERIT_CHAIN_SIZE__ CFG_INT(7) +#define __MAX_EVAL_COST__ CFG_INT(8) +#define __MAX_LOCAL_VARIABLES__ CFG_INT(9) +#define __MAX_CALL_DEPTH__ CFG_INT(10) +#define __MAX_ARRAY_SIZE__ CFG_INT(11) +#define __MAX_BUFFER_SIZE__ CFG_INT(12) +#define __MAX_MAPPING_SIZE__ CFG_INT(13) +#define __MAX_STRING_LENGTH__ CFG_INT(14) +#define __MAX_BITFIELD_BITS__ CFG_INT(15) + +#define __MAX_BYTE_TRANSFER__ CFG_INT(16) +#define __MAX_READ_FILE_SIZE__ CFG_INT(17) + +#define __RESERVED_MEM_SIZE__ CFG_INT(18) + +#define __SHARED_STRING_HASH_TABLE_SIZE__ CFG_INT(19) +#define __OBJECT_HASH_TABLE_SIZE__ CFG_INT(20) +#define __LIVING_HASH_TABLE_SIZE__ CFG_INT(21) + +#define __FD6_PORT__ CFG_INT(22) +#define __FD6_KIND__ CFG_INT(23) + +#define RUNTIME_CONFIG_NEXT CFG_INT(24) + +/* + * The following is for internal use (ie driver) only + */ + +#define NUM_CONFIG_STRS (BASE_CONFIG_INT - BASE_CONFIG_STR) +#define NUM_CONFIG_INTS (RUNTIME_CONFIG_NEXT - BASE_CONFIG_INT) + +#endif /* RUNTIME_CONFIG_H */ diff --git a/fluffos-2.23-ds03/include/semantic.cache b/fluffos-2.23-ds03/include/semantic.cache new file mode 100644 index 0000000..6db2232 --- /dev/null +++ b/fluffos-2.23-ds03/include/semantic.cache @@ -0,0 +1,21 @@ +;; Object include/ +;; SEMANTICDB Tags save file +(semanticdb-project-database-file "include/" + :tables (list + (semanticdb-table "function.h" + :major-mode 'c-mode + :tags '(("FP_LOCAL" variable (:constant-flag t :default-value (nil)) nil [47 78]) ("FP_EFUN" variable (:constant-flag t :default-value (nil)) nil [79 110]) ("FP_SIMUL" variable (:constant-flag t :default-value (nil)) nil [111 142]) ("FP_FUNCTIONAL" variable (:constant-flag t :default-value (nil)) nil [143 174]) ("FP_G_VAR" variable (:constant-flag t :default-value (nil)) nil [195 226]) ("FP_L_VAR" variable (:constant-flag t :default-value (nil)) nil [227 258]) ("FP_ANONYMOUS" variable (:constant-flag t :default-value (nil)) nil [259 290]) ("FP_MASK" variable (:constant-flag t :default-value (nil)) nil [315 347]) ("FP_HAS_ARGUMENTS" variable (:constant-flag t :default-value (nil)) nil [348 380]) ("FP_OWNER_DESTED" variable (:constant-flag t :default-value (nil)) nil [381 413]) ("FP_NOT_BINDABLE" variable (:constant-flag t :default-value (nil)) nil [414 446])) + :file "function.h" + :pointmax 447 + ) + (semanticdb-table "localtime.h" + :major-mode 'c-mode + :tags '(("LT_SEC" variable (:constant-flag t :default-value (nil)) nil [45 70]) ("LT_MIN" variable (:constant-flag t :default-value (nil)) nil [71 96]) ("LT_HOUR" variable (:constant-flag t :default-value (nil)) nil [97 122]) ("LT_MDAY" variable (:constant-flag t :default-value (nil)) nil [123 148]) ("LT_MON" variable (:constant-flag t :default-value (nil)) nil [149 174]) ("LT_YEAR" variable (:constant-flag t :default-value (nil)) nil [175 200]) ("LT_WDAY" variable (:constant-flag t :default-value (nil)) nil [201 226]) ("LT_YDAY" variable (:constant-flag t :default-value (nil)) nil [227 252]) ("LT_GMTOFF" variable (:constant-flag t :default-value (nil)) nil [253 278]) ("LT_ZONE" variable (:constant-flag t :default-value (nil)) nil [279 304]) ("LT_ISDST" variable (:constant-flag t :default-value (nil)) nil [305 331])) + :file "localtime.h" + :pointmax 332 + ) + ) + :file "semantic.cache" + :semantic-tag-version "2.0pre3" + :semanticdb-version "2.0pre3" + ) diff --git a/fluffos-2.23-ds03/include/socket_err.h b/fluffos-2.23-ds03/include/socket_err.h new file mode 100644 index 0000000..1de487f --- /dev/null +++ b/fluffos-2.23-ds03/include/socket_err.h @@ -0,0 +1,46 @@ +/* + * socket_errors.h -- definitions for efun socket error return codes. + * 5-92 : Dwayne Fontenot (Jacques@TMI) : original coding. + * 10-92 : Dave Richards (Cynosure) : less original coding. + */ + +#ifndef _SOCKET_ERRORS_H_ +#define _SOCKET_ERRORS_H_ + +#define EESUCCESS 1 /* Call was successful */ +#define EESOCKET -1 /* Problem creating socket */ +#define EESETSOCKOPT -2 /* Problem with setsockopt */ +#define EENONBLOCK -3 /* Problem setting non-blocking mode */ +#define EENOSOCKS -4 /* UNUSED */ +#define EEFDRANGE -5 /* Descriptor out of range */ +#define EEBADF -6 /* Descriptor is invalid */ +#define EESECURITY -7 /* Security violation attempted */ +#define EEISBOUND -8 /* Socket is already bound */ +#define EEADDRINUSE -9 /* Address already in use */ +#define EEBIND -10 /* Problem with bind */ +#define EEGETSOCKNAME -11 /* Problem with getsockname */ +#define EEMODENOTSUPP -12 /* Socket mode not supported */ +#define EENOADDR -13 /* Socket not bound to an address */ +#define EEISCONN -14 /* Socket is already connected */ +#define EELISTEN -15 /* Problem with listen */ +#define EENOTLISTN -16 /* Socket not listening */ +#define EEWOULDBLOCK -17 /* Operation would block */ +#define EEINTR -18 /* Interrupted system call */ +#define EEACCEPT -19 /* Problem with accept */ +#define EEISLISTEN -20 /* Socket is listening */ +#define EEBADADDR -21 /* Problem with address format */ +#define EEALREADY -22 /* Operation already in progress */ +#define EECONNREFUSED -23 /* Connection refused */ +#define EECONNECT -24 /* Problem with connect */ +#define EENOTCONN -25 /* Socket not connected */ +#define EETYPENOTSUPP -26 /* Object type not supported */ +#define EESENDTO -27 /* Problem with sendto */ +#define EESEND -28 /* Problem with send */ +#define EECALLBACK -29 /* Wait for callback */ +#define EESOCKRLSD -30 /* Socket already released */ +#define EESOCKNOTRLSD -31 /* Socket not released */ +#define EEBADDATA -32 /* sending data with too many nested levels */ + +#define ERROR_STRINGS 33 /* sizeof (error_strings) */ + +#endif /* _SOCKET_ERRORS_H_ */ diff --git a/fluffos-2.23-ds03/include/type.h b/fluffos-2.23-ds03/include/type.h new file mode 100644 index 0000000..540df08 --- /dev/null +++ b/fluffos-2.23-ds03/include/type.h @@ -0,0 +1,15 @@ +/* /include/type.h */ + +#ifndef _TYPE_H +#define _TYPE_H + +#define INT "int" +#define STRING "string" +#define ARRAY "array" +#define OBJECT "object" +#define MAPPING "mapping" +#define FUNCTION "function" +#define FLOAT "float" +#define BUFFER "buffer" +#define CLASS "class" +#endif diff --git a/fluffos-2.23-ds03/interpret.c b/fluffos-2.23-ds03/interpret.c new file mode 100644 index 0000000..d07651e --- /dev/null +++ b/fluffos-2.23-ds03/interpret.c @@ -0,0 +1,5843 @@ +#define SUPPRESS_COMPILER_INLINES +#include "std.h" +#include "lpc_incl.h" +#include "efuns_incl.h" +#include "file.h" +#include "file_incl.h" +#include "patchlevel.h" +#include "backend.h" +#include "simul_efun.h" +#include "eoperators.h" +#include "efunctions.h" +#include "sprintf.h" +#include "comm.h" +#include "port.h" +#include "qsort.h" +#include "compiler.h" +#include "regexp.h" +#include "master.h" +#include "eval.h" + +#ifdef OPCPROF +#include "opc.h" + +static int opc_eoper[BASE]; +#endif + + +#ifdef DTRACE +#include +#else +#define DTRACE_PROBE3(x,y,z,zz,zzz) +#endif + +#ifdef OPCPROF_2D +/* warning, this is typically 4 * 100 * 100 = 40k */ +static int opc_eoper_2d[BASE+1][BASE+1]; +static int last_eop = 0; +#endif + +static const char *type_names[] = { + "int", + "string", + "array", + "object", + "mapping", + "function", + "float", + "buffer", + "class" +}; +#define TYPE_CODES_END 0x400 +#define TYPE_CODES_START 0x2 + +#ifdef PACKAGE_UIDS +extern userid_t *backbone_uid; +#endif +extern int max_cost; +extern int call_origin; +static int find_line (char *, const program_t *, const char **, int *); +INLINE void push_indexed_lvalue (int); +#ifdef TRACE +static void do_trace_call (int); +#endif +void break_point (void); +INLINE_STATIC void do_loop_cond_number (void); +INLINE_STATIC void do_loop_cond_local (void); +static void do_catch (char *, unsigned short); +int last_instructions (void); +static float _strtof (char *, char **); +#ifdef TRACE_CODE +static char *get_arg (int, int); +#endif + +#ifdef DEBUG +int stack_in_use_as_temporary = 0; +#endif + +/* + * Macro for extracting global variable indices. + */ + +#if CFG_MAX_GLOBAL_VARIABLES <= 256 +#define READ_GLOBAL_INDEX READ_UCHAR +#elif CFG_MAX_GLOBAL_VARIABLES <= 65536 +#define READ_GLOBAL_INDEX READ_USHORT +#else +#error CFG_MAX_GLOBAL_VARIABLES must not be greater than 65536 +#endif + +int inter_sscanf (svalue_t *, svalue_t *, svalue_t *, int); +program_t *current_prog; +short int caller_type; +static int tracedepth; +int num_varargs; + +/* + * Inheritance: + * An object X can inherit from another object Y. This is done with + * the statement 'inherit "file";' + * The inherit statement will clone a copy of that file, call reset + * in it, and set a pointer to Y from X. + * Y has to be removed from the linked list of all objects. + * All variables declared by Y will be copied to X, so that X has access + * to them. + * + * If Y isn't loaded when it is needed, X will be discarded, and Y will be + * loaded separately. X will then be reloaded again. + */ + +/* + * These are the registers used at runtime. + * The control stack saves registers to be restored when a function + * will return. That means that control_stack[0] will have almost no + * interesting values, as it will terminate execution. + */ +char *pc; /* Program pointer. */ +svalue_t *fp; /* Pointer to first argument. */ + +svalue_t *sp; +svalue_t const0, const1, const0u; + +int function_index_offset; /* Needed for inheritance */ +int variable_index_offset; /* Needed for inheritance */ +int st_num_arg; + +static svalue_t start_of_stack[CFG_EVALUATOR_STACK_SIZE+10]; +svalue_t *end_of_stack = start_of_stack + CFG_EVALUATOR_STACK_SIZE; + +/* Used to throw an error to a catch */ +svalue_t catch_value = {T_NUMBER}; + +/* used by routines that want to return a pointer to an svalue */ +svalue_t apply_ret_value = {T_NUMBER}; + +control_stack_t control_stack[CFG_MAX_CALL_DEPTH+5]; +control_stack_t *csp; /* Points to last element pushed */ + +int too_deep_error = 0, max_eval_error = 0; + +ref_t *global_ref_list = 0; + +void kill_ref (ref_t * ref) { + if (ref->sv.type == T_MAPPING && (ref->sv.u.map->count & MAP_LOCKED)) { + ref_t *r = global_ref_list; + + /* if some other ref references this mapping, it needs to remain + locked */ + while (r) { + if (r->sv.u.map == ref->sv.u.map) + break; + r = r->next; + } + if (!r) + unlock_mapping(ref->sv.u.map); + } + if(ref->lvalue) + free_svalue(&ref->sv, "kill_ref"); + if(ref->next) + ref->next->prev = ref->prev; + if(ref->prev) + ref->prev->next = ref->next; + else { + global_ref_list = ref->next; + if(global_ref_list) + global_ref_list->prev = 0; + } + if (ref->ref > 0) { + /* still referenced */ + ref->lvalue = 0; + ref->prev = ref; //so it doesn't get set to the global list above + ref->next = ref; + } else { + FREE(ref); + } +} + +ref_t *make_ref (void) { + ref_t *ref = ALLOCATE(ref_t, TAG_TEMPORARY, "make_ref"); + ref->next = global_ref_list; + ref->prev = NULL; + if(ref->next) + ref->next->prev = ref; + global_ref_list = ref; + ref->csp = csp; + ref->ref = 1; + return ref; +} + +void get_version (char * buff) +{ + sprintf(buff, "FluffOS %s", PATCH_LEVEL); +} + +/* + * Information about assignments of values: + * + * There are three types of l-values: Local variables, global variables + * and array elements. + * + * The local variables are allocated on the stack together with the arguments. + * the register 'frame_pointer' points to the first argument. + * + * The global variables must keep their values between executions, and + * have space allocated at the creation of the object. + * + * Elements in arrays are similar to global variables. There is a reference + * count to the whole array, that states when to deallocate the array. + * The elements consists of 'svalue_t's, and will thus have to be freed + * immediately when over written. + */ + +/* + * Push an object pointer on the stack. Note that the reference count is + * incremented. + * A destructed object must never be pushed onto the stack. + */ +INLINE +void push_object (object_t * ob) +{ + STACK_INC; + + if (!ob || (ob->flags & O_DESTRUCTED) || ob->flags & O_BEING_DESTRUCTED) { + *sp = const0u; + return; + } + + sp->type = T_OBJECT; + sp->u.ob = ob; + add_ref(ob, "push_object"); +} + +const char * type_name (int c) { + int j = 0; + int limit = TYPE_CODES_START; + + do { + if (c & limit) return type_names[j]; + j++; + } while (!((limit <<= 1) & TYPE_CODES_END)); + /* Oh crap. Take some time and figure out what we have. */ + switch (c) { + case T_INVALID: return "*invalid*"; + case T_LVALUE: return "*lvalue*"; + case T_REF: return "*ref*"; + case T_LVALUE_BYTE: return "*lvalue_byte*"; + case T_LVALUE_RANGE: return "*lvalue_range*"; + case T_ERROR_HANDLER: return "*error_handler*"; + IF_DEBUG(case T_FREED: return "*freed*"); + } + return "*unknown*"; +} + +/* + * May current_object shadow object 'ob' ? We rely heavily on the fact that + * function names are pointers to shared strings, which means that equality + * can be tested simply through pointer comparison. + */ +static program_t *ffbn_recurse (program_t *, char *, int *, int *); +static program_t *ffbn_recurse2 (program_t *, const char *, int *, int *, int *, int *); + +#ifndef NO_SHADOWS + +static char *check_shadow_functions (program_t * shadow, program_t * victim) { + int i; + int pindex, runtime_index; + program_t *prog; + char *fun; + + for (i = 0; i < shadow->num_functions_defined; i++) { + prog = ffbn_recurse(victim, shadow->function_table[i].funcname, &pindex, &runtime_index); + if (prog && (victim->function_flags[runtime_index] & DECL_NOMASK)) + return prog->function_table[pindex].funcname; + } + + /* Loop through all the inherits of the program also */ + for (i = 0; i < shadow->num_inherited; i++) { + fun = check_shadow_functions(shadow->inherit[i].prog, victim); + if (fun) + return fun; + } + return 0; +} + +int validate_shadowing (object_t * ob) +{ + program_t *shadow = current_object->prog, *victim = ob->prog; + svalue_t *ret; + char *fun; + + if (current_object->shadowing) + error("shadow: Already shadowing.\n"); + if (current_object->shadowed) + error("shadow: Can't shadow when shadowed.\n"); +#ifndef NO_ENVIRONMENT + if (current_object->super) + error("shadow: The shadow must not reside inside another object.\n"); +#endif + if (ob == master_ob) + error("shadow: cannot shadow the master object.\n"); + if (ob->shadowing) + error("shadow: Can't shadow a shadow.\n"); + + if ((fun = check_shadow_functions(shadow, victim))) + error("Illegal to shadow 'nomask' function \"%s\".\n", fun); + + push_object(ob); + ret = apply_master_ob(APPLY_VALID_SHADOW, 1); + if (!(ob->flags & O_DESTRUCTED) && MASTER_APPROVED(ret)) { + return 1; + } + return 0; +} +#endif + +/* + * Push a number on the value stack. + */ +INLINE void +push_number (long n) +{ + STACK_INC; + sp->type = T_NUMBER; + sp->subtype = 0; + sp->u.number = n; +} + +INLINE void +push_real (float n) +{ + STACK_INC; + sp->type = T_REAL; + sp->u.real = n; +} + +/* + * Push undefined (const0u) onto the value stack. + */ +INLINE +void push_undefined() +{ + STACK_INC; + *sp = const0u; +} + +INLINE_STATIC void push_undefineds (int num) +{ + CHECK_STACK_OVERFLOW(num); + while (num--) *++sp = const0u; +} + +INLINE +void copy_and_push_string (const char * p) { + STACK_INC; + sp->type = T_STRING; + sp->subtype = STRING_MALLOC; + sp->u.string = string_copy(p, "copy_and_push_string"); +} + +INLINE +void share_and_push_string (const char * p) { + STACK_INC; + sp->type = T_STRING; + sp->subtype = STRING_SHARED; + sp->u.string = make_shared_string(p); +} + +/* + * Get address to a valid global variable. + */ +#ifdef DEBUG +INLINE_STATIC svalue_t *find_value (int num) +{ + DEBUG_CHECK2(num >= current_object->prog->num_variables_total, + "Illegal variable access %d(%d).\n", + num, current_object->prog->num_variables_total); + return ¤t_object->variables[num]; +} +#else +#define find_value(num) (¤t_object->variables[num]) +#endif + +INLINE void +free_string_svalue (svalue_t * v) +{ + const char *str = v->u.string; + + if (v->subtype & STRING_COUNTED) { +#ifdef STRING_STATS + int size = MSTR_SIZE(str); +#endif + if (DEC_COUNTED_REF(str)) { + SUB_STRING(size); + NDBG(BLOCK(str)); + if (v->subtype & STRING_HASHED) { + SUB_NEW_STRING(size, sizeof(block_t)); + deallocate_string((char *)str); + CHECK_STRING_STATS; + } else { + SUB_NEW_STRING(size, sizeof(malloc_block_t)); + FREE(MSTR_BLOCK(str)); + CHECK_STRING_STATS; + } + } else { + SUB_STRING(size); + NDBG(BLOCK(str)); + } + } +} + +void unlink_string_svalue (svalue_t * s) { + char *str; + + switch (s->subtype) { + case STRING_MALLOC: + if (MSTR_REF(s->u.string) > 1) + s->u.string = string_unlink(s->u.string, "unlink_string_svalue"); + break; + case STRING_SHARED: + { + int l = SHARED_STRLEN(s->u.string); + + str = new_string(l, "unlink_string_svalue"); + strncpy(str, s->u.string, l + 1); + free_string(s->u.string); + s->subtype = STRING_MALLOC; + s->u.string = str; + break; + } + case STRING_CONSTANT: + s->u.string = string_copy(s->u.string, "unlink_string_svalue"); + s->subtype = STRING_MALLOC; + break; + } +} + +/* + * Free the data that an svalue is pointing to. Not the svalue + * itself. + * Use the free_svalue() define to call this + */ +#ifdef DEBUG +INLINE void int_free_svalue (svalue_t * v, const char * tag) +#else + INLINE void int_free_svalue (svalue_t * v) +#endif +{ + /* Marius, 30-Mar-2001: T_FREED could be OR'd in with the type now if the + * svalue has been 'freed' as an optimization by the F_TRANSFER_LOCAL op. + * This will allow us to keep the type of the variable known for error + * handler purposes but not duplicate the free. + */ + if (v->type == T_STRING) { + const char *str = v->u.string; + + if (v->subtype & STRING_COUNTED) { +#ifdef STRING_STATS + int size = MSTR_SIZE(str); +#endif + if (DEC_COUNTED_REF(str)) { + SUB_STRING(size); + NDBG(BLOCK(str)); + if (v->subtype & STRING_HASHED) { + SUB_NEW_STRING(size, sizeof(block_t)); + deallocate_string((char *)str); + CHECK_STRING_STATS; + } else { + SUB_NEW_STRING(size, sizeof(malloc_block_t)); + FREE(MSTR_BLOCK(str)); + CHECK_STRING_STATS; + } + } else { + SUB_STRING(size); + NDBG(BLOCK(str)); + } + } + } else if ((v->type & T_REFED) && !(v->type & T_FREED)) { +#ifdef DEBUG_MACRO + if (v->type == T_OBJECT) + debug(d_flag, ("Free_svalue %s (%d) from %s\n", v->u.ob->obname, v->u.ob->ref - 1, tag)); +#endif + if (!(--v->u.refed->ref)) { + switch (v->type) { + case T_OBJECT: + dealloc_object(v->u.ob, "free_svalue"); + break; + case T_CLASS: + dealloc_class(v->u.arr); + break; + case T_ARRAY: + if (v->u.arr != &the_null_array) + dealloc_array(v->u.arr); + break; +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + if (v->u.buf != &null_buf) + FREE((char *)v->u.buf); + break; +#endif + case T_MAPPING: + dealloc_mapping(v->u.map); + break; + case T_FUNCTION: + dealloc_funp(v->u.fp); + break; + case T_REF: + if (!v->u.ref->lvalue){ + kill_ref(v->u.ref); + } + break; + } + } + } else if (v->type == T_ERROR_HANDLER) { + (*v->u.error_handler)(); + } +#ifdef DEBUG + else if (v->type == T_FREED) { + fatal("T_FREED svalue freed. Previously freed by %s.\n", v->u.string); + } + v->type = T_FREED; + v->u.string = tag; +#endif +} + +void process_efun_callback (int narg, function_to_call_t * ftc, int f) { + int argc = st_num_arg; + svalue_t *arg = sp - argc + 1 + narg; + + if (arg->type == T_FUNCTION) { + ftc->f.fp = arg->u.fp; + ftc->ob = 0; + ftc->narg = argc - narg - 1; + ftc->args = arg + 1; + } else { + ftc->f.str = arg->u.string; + if (argc < narg + 2) { + ftc->ob = current_object; + ftc->narg = 0; + } else { + if ((arg+1)->type == T_OBJECT) { + ftc->ob = (arg+1)->u.ob; + } else + if ((arg+1)->type == T_STRING) { + if (!(ftc->ob = find_object((arg+1)->u.string)) || + !object_visible(ftc->ob)) + bad_argument(arg+1, T_STRING | T_OBJECT, 3, f); + } else + bad_argument(arg+1, T_STRING | T_OBJECT, 3, f); + + ftc->narg = argc - narg - 2; + ftc->args = arg + 2; + + if (ftc->ob->flags & O_DESTRUCTED) + bad_argument(arg+1, T_STRING | T_OBJECT, 3, f); + } + } +} + +svalue_t *call_efun_callback (function_to_call_t * ftc, int n) { + svalue_t *v; + + if (ftc->narg) + push_some_svalues(ftc->args, ftc->narg); + if (ftc->ob) { + if (ftc->ob->flags & O_DESTRUCTED) + error("Object destructed during efun callback.\n"); + v = apply(ftc->f.str, ftc->ob, n + ftc->narg, ORIGIN_EFUN); + } else + v = call_function_pointer(ftc->f.fp, n + ftc->narg); + return v; +} + +svalue_t *safe_call_efun_callback (function_to_call_t * ftc, int n) { + svalue_t *v; + + if (ftc->narg) + push_some_svalues(ftc->args, ftc->narg); + if (ftc->ob) { + if (ftc->ob->flags & O_DESTRUCTED) + error("Object destructed during efun callback.\n"); + v = apply(ftc->f.str, ftc->ob, n + ftc->narg, ORIGIN_EFUN); + } else + v = safe_call_function_pointer(ftc->f.fp, n + ftc->narg); + return v; +} + +/* + * Free several svalues, and free up the space used by the svalues. + * The svalues must be sequentially located. + */ +INLINE void free_some_svalues (svalue_t * v, int num) +{ + while (num--) + free_svalue(v + num, "free_some_svalues"); + FREE(v); +} + +/* + * Prepend a slash in front of a string. + */ +char *add_slash (const char * const str) +{ + char *tmp; + + if (str[0] == '<' && strcmp(str + 1, "function>") == 0) + return string_copy(str, "add_slash"); + tmp = new_string(strlen(str) + 1, "add_slash"); + *tmp = '/'; + strcpy(tmp + 1, str); + return tmp; +} + +/* + * Assign to a svalue. + * This is done either when element in array, or when to an identifier + * (as all identifiers are kept in a array pointed to by the object). + */ + +INLINE void assign_svalue_no_free (svalue_t * to, svalue_t * from) +{ + DEBUG_CHECK(from == 0, "Attempt to assign_svalue() from a null ptr.\n"); + DEBUG_CHECK(to == 0, "Attempt to assign_svalue() to a null ptr.\n"); + DEBUG_CHECK((from->type & (from->type - 1)) & ~T_FREED, "from->type is corrupt; >1 bit set.\n"); + + if (from->type == T_OBJECT && (!from->u.ob || (from->u.ob->flags & O_DESTRUCTED))) { + *to = const0u; + return; + } + + *to = *from; + + if ((to->type & T_FREED) && to->type != T_FREED) + to->type &= ~T_FREED; + + if (from->type == T_STRING) { + if (from->subtype & STRING_COUNTED) { + INC_COUNTED_REF(to->u.string); + ADD_STRING(MSTR_SIZE(to->u.string)); + NDBG(BLOCK(to->u.string)); + } + } else if (from->type & T_REFED) { +#ifdef DEBUG_MACRO + if (from->type == T_OBJECT) + add_ref(from->u.ob, "assign_svalue_no_free"); + else +#endif + from->u.refed->ref++; + } +} + +INLINE void assign_svalue (svalue_t * dest, svalue_t * v) +{ + /* First deallocate the previous value. */ + free_svalue(dest, "assign_svalue"); + assign_svalue_no_free(dest, v); +} + +INLINE void push_some_svalues (svalue_t * v, int num) +{ + while (num--) push_svalue(v++); +} + +/* + * Copies an array of svalues to another location, which should be + * free space. + */ +INLINE void copy_some_svalues (svalue_t * dest, svalue_t * v, int num) +{ + while (num--) + assign_svalue_no_free(dest+num, v+num); +} + +INLINE void transfer_push_some_svalues (svalue_t * v, int num) +{ + CHECK_STACK_OVERFLOW(num); + memcpy(sp + 1, v, num * sizeof(svalue_t)); + sp += num; +} + +/* + * Pop the top-most value of the stack. + * Don't do this if it is a value that will be used afterwards, as the + * data may be sent to FREE(), and destroyed. + */ +INLINE void pop_stack() +{ + DEBUG_CHECK(sp < start_of_stack, "Stack underflow.\n"); + free_svalue(sp--, "pop_stack"); +} + +svalue_t global_lvalue_byte = { T_LVALUE_BYTE }; + +int lv_owner_type; +refed_t *lv_owner; + +/* + * Compute the address of an array element. + */ +INLINE void push_indexed_lvalue (int code) +{ + int ind; + svalue_t *lv; + + if (sp->type == T_LVALUE) { + lv = sp->u.lvalue; + if (!code && lv->type == T_MAPPING) { + sp--; + if (!(lv = find_for_insert(lv->u.map, sp, 0))) + mapping_too_large(); + free_svalue(sp, "push_indexed_lvalue: 1"); + sp->type = T_LVALUE; + sp->u.lvalue = lv; +#ifdef REF_RESERVED_WORD + lv_owner_type = T_MAPPING; + lv_owner = (refed_t *)lv->u.map; +#endif + return; + } + + if (!((--sp)->type == T_NUMBER)) + error("Illegal type of index\n"); + + ind = sp->u.number; + + switch(lv->type) { + case T_STRING: + { + int len = SVALUE_STRLEN(lv); + + if (code) ind = len - ind; + if (ind >= len || ind < 0) + error("Index out of bounds in string index lvalue.\n"); + unlink_string_svalue(lv); + sp->type = T_LVALUE; + sp->u.lvalue = &global_lvalue_byte; + global_lvalue_byte.subtype = 0; + global_lvalue_byte.u.lvalue_byte = (unsigned char *)&lv->u.string[ind]; +#ifdef REF_RESERVED_WORD + lv_owner_type = T_STRING; + lv_owner = (refed_t *)lv->u.string; +#endif + break; + } + +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + { + if (code) ind = lv->u.buf->size - ind; + if (ind >= lv->u.buf->size || ind < 0) + error("Buffer index out of bounds.\n"); + sp->type = T_LVALUE; + sp->u.lvalue = &global_lvalue_byte; + global_lvalue_byte.subtype = 1; + global_lvalue_byte.u.lvalue_byte = &lv->u.buf->item[ind]; +#ifdef REF_RESERVED_WORD + lv_owner_type = T_BUFFER; + lv_owner = (refed_t *)lv->u.buf; +#endif + break; + } +#endif + + case T_ARRAY: + { + if (code) ind = lv->u.arr->size - ind; + if (ind >= lv->u.arr->size || ind < 0) + error("Array index out of bounds\n"); + sp->type = T_LVALUE; + sp->u.lvalue = lv->u.arr->item + ind; +#ifdef REF_RESERVED_WORD + lv_owner_type = T_ARRAY; + lv_owner = (refed_t *)lv->u.arr; +#endif + break; + } + + default: + if (lv->type == T_NUMBER && !lv->u.number) + error("Value being indexed is zero.\n"); + error("Cannot index value of type '%s'.\n", type_name(lv->type)); + } + } else { + /* It is now coming from (x y)[index]... = rhs */ + /* Where x is a _valid_ lvalue */ + /* Hence the reference to sp is at least 2 :) */ + + if (!code && (sp->type == T_MAPPING)) { + if (!(lv = find_for_insert(sp->u.map, sp-1, 0))) + mapping_too_large(); + sp->u.map->ref--; +#ifdef REF_RESERVED_WORD + lv_owner_type = T_MAPPING; + lv_owner = (refed_t *)sp->u.map; +#endif + free_svalue(--sp, "push_indexed_lvalue: 2"); + sp->type = T_LVALUE; + sp->u.lvalue = lv; + return; + } + + if (!((sp-1)->type == T_NUMBER)) + error("Illegal type of index\n"); + + ind = (sp-1)->u.number; + + switch (sp->type) { + case T_STRING: + { + error("Illegal to make char lvalue from assigned string\n"); + break; + } + +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + { + if (code) ind = sp->u.buf->size - ind; + if (ind >= sp->u.buf->size || ind < 0) + error("Buffer index out of bounds.\n"); + sp->u.buf->ref--; +#ifdef REF_RESERVED_WORD + lv_owner_type = T_BUFFER; + lv_owner = (refed_t *)sp->u.buf; +#endif + (--sp)->type = T_LVALUE; + sp->u.lvalue = &global_lvalue_byte; + global_lvalue_byte.subtype = 1; + global_lvalue_byte.u.lvalue_byte = (sp+1)->u.buf->item + ind; + break; + } +#endif + + case T_ARRAY: + { + if (code) ind = sp->u.arr->size - ind; + if (ind >= sp->u.arr->size || ind < 0) + error("Array index out of bounds.\n"); + sp->u.arr->ref--; +#ifdef REF_RESERVED_WORD + lv_owner_type = T_ARRAY; + lv_owner = (refed_t *)sp->u.arr; +#endif + (--sp)->type = T_LVALUE; + sp->u.lvalue = (sp+1)->u.arr->item + ind; + break; + } + + default: + if (sp->type == T_NUMBER && !sp->u.number) + error("Value being indexed is zero.\n"); + error("Cannot index value of type '%s'.\n", type_name(sp->type)); + } + } +} + +static struct lvalue_range { + int ind1, ind2, size; + svalue_t *owner; +} global_lvalue_range; + +static svalue_t global_lvalue_range_sv = { T_LVALUE_RANGE }; + +INLINE_STATIC void push_lvalue_range (int code) +{ + int ind1, ind2, size; + svalue_t *lv; + + if (sp->type == T_LVALUE) { + switch((lv = global_lvalue_range.owner = sp->u.lvalue)->type) { + case T_ARRAY: + size = lv->u.arr->size; + break; + case T_STRING: { + size = SVALUE_STRLEN(lv); + unlink_string_svalue(lv); + break; + } +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + size = lv->u.buf->size; + break; +#endif + default: + error("Range lvalue on illegal type\n"); + IF_DEBUG(size = 0); + } + } else + error("Range lvalue on illegal type\n"); + + if (!((--sp)->type == T_NUMBER)) error("Illegal 2nd index type to range lvalue\n"); + + ind2 = (code & 0x01) ? (size - sp->u.number) : sp->u.number; + if (++ind2 < 0 || (ind2 > size)) + error("The 2nd index to range lvalue must be >= -1 and < sizeof(indexed value)\n"); + + if (!((--sp)->type == T_NUMBER)) error("Illegal 1st index type to range lvalue\n"); + ind1 = (code & 0x10) ? (size - sp->u.number) : sp->u.number; + + if (ind1 < 0 || ind1 > size) + error("The 1st index to range lvalue must be >= 0 and <= sizeof(indexed value)\n"); + + global_lvalue_range.ind1 = ind1; + global_lvalue_range.ind2 = ind2; + global_lvalue_range.size = size; + sp->type = T_LVALUE; + sp->u.lvalue = &global_lvalue_range_sv; +} + +INLINE void copy_lvalue_range (svalue_t * from) +{ + int ind1, ind2, size, fsize; + svalue_t *owner; + + ind1 = global_lvalue_range.ind1; + ind2 = global_lvalue_range.ind2; + size = global_lvalue_range.size; + owner = global_lvalue_range.owner; + + switch(owner->type) { + case T_ARRAY: + { + array_t *fv, *dv; + svalue_t *fptr, *dptr; + if (from->type != T_ARRAY) error("Illegal rhs to array range lvalue\n"); + + fv = from->u.arr; + fptr = fv->item; + + if ((fsize = fv->size) == ind2 - ind1) { + dptr = (owner->u.arr)->item + ind1; + + if (fv->ref == 1) { + /* Transfer the svalues */ + while (fsize--) { + free_svalue(dptr, "copy_lvalue_range : 1"); + *dptr++ = *fptr++; + } + free_empty_array(fv); + } else { + while (fsize--) assign_svalue(dptr++, fptr++); + fv->ref--; + } + } else { + array_t *old_dv = owner->u.arr; + svalue_t *old_dptr = old_dv->item; + + /* Need to reallocate the array */ + dv = allocate_empty_array(size - ind2 + ind1 + fsize); + dptr = dv->item; + + /* ind1 can range from 0 to sizeof(old_dv) */ + while (ind1--) assign_svalue_no_free(dptr++, old_dptr++); + + if (fv->ref == 1) { + while (fsize--) *dptr++ = *fptr++; + free_empty_array(fv); + } else { + while (fsize--) assign_svalue_no_free(dptr++, fptr++); + fv->ref--; + } + + /* ind2 can range from 0 to sizeof(old_dv) */ + old_dptr = old_dv->item + ind2; + size -= ind2; + + while (size--) assign_svalue_no_free(dptr++, old_dptr++); + free_array(old_dv); + + owner->u.arr = dv; + } + break; + } + + case T_STRING: + { + if (from->type != T_STRING) error("Illegal rhs to string range lvalue.\n"); + + if ((fsize = SVALUE_STRLEN(from)) == ind2 - ind1) { + /* since fsize >= 0, ind2 - ind1 <= strlen(orig string) */ + /* because both of them can only range from 0 to len */ + + strncpy(((char *)(owner->u.string)) + ind1, from->u.string, fsize); + } else { + char *tmp, *dstr = (char *)(owner->u.string); + + owner->u.string = tmp = new_string(size - ind2 + ind1 + fsize, "copy_lvalue_range"); + if (ind1 >= 1) { + strncpy(tmp, dstr, ind1); + tmp += ind1; + } + strcpy(tmp, from->u.string); + tmp += fsize; + + size -= ind2; + if (size >= 1) { + strncpy(tmp, dstr + ind2, size); + *(tmp + size) = 0; + } + FREE_MSTR(dstr); + } + free_string_svalue(from); + break; + } + +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + { + if (from->type != T_BUFFER) error("Illegal rhs to buffer range lvalue.\n"); + + if ((fsize = from->u.buf->size) == ind2 - ind1) { + memcpy((owner->u.buf)->item + ind1, from->u.buf->item, fsize); + } else { + buffer_t *b; + unsigned char *old_item = (owner->u.buf)->item; + unsigned char *new_item; + + b = allocate_buffer(size - ind2 + ind1 + fsize); + new_item = b->item; + if (ind1 >= 1) { + memcpy(b->item, old_item, ind1); + new_item += ind1; + } + memcpy(new_item, from->u.buf, fsize); + new_item += fsize; + + if ((size -= ind2) >= 1) + memcpy(new_item, old_item + ind2, size); + free_buffer(owner->u.buf); + owner->u.buf = b; + } + free_buffer(from->u.buf); + break; + } +#endif + } +} + +INLINE void assign_lvalue_range (svalue_t * from) +{ + int ind1, ind2, size, fsize; + svalue_t *owner; + + ind1 = global_lvalue_range.ind1; + ind2 = global_lvalue_range.ind2; + size = global_lvalue_range.size; + owner = global_lvalue_range.owner; + + switch(owner->type) { + case T_ARRAY: + { + array_t *fv, *dv; + svalue_t *fptr, *dptr; + if (from->type != T_ARRAY) error("Illegal rhs to array range lvalue\n"); + + fv = from->u.arr; + fptr = fv->item; + + if ((fsize = fv->size) == ind2 - ind1) { + dptr = (owner->u.arr)->item + ind1; + while (fsize--) assign_svalue(dptr++, fptr++); + } else { + array_t *old_dv = owner->u.arr; + svalue_t *old_dptr = old_dv->item; + + /* Need to reallocate the array */ + dv = allocate_empty_array(size - ind2 + ind1 + fsize); + dptr = dv->item; + + /* ind1 can range from 0 to sizeof(old_dv) */ + while (ind1--) assign_svalue_no_free(dptr++, old_dptr++); + + while (fsize--) assign_svalue_no_free(dptr++, fptr++); + + /* ind2 can range from 0 to sizeof(old_dv) */ + old_dptr = old_dv->item + ind2; + size -= ind2; + + while (size--) assign_svalue_no_free(dptr++, old_dptr++); + free_array(old_dv); + + owner->u.arr = dv; + } + break; + } + + case T_STRING: + { + if (from->type != T_STRING) error("Illegal rhs to string range lvalue.\n"); + + if ((fsize = SVALUE_STRLEN(from)) == ind2 - ind1) { + /* since fsize >= 0, ind2 - ind1 <= strlen(orig string) */ + /* because both of them can only range from 0 to len */ + + strncpy(((char *)(owner->u.string)) + ind1, from->u.string, fsize); + } else { + char *tmp; + const char *dstr = (char *)(owner->u.string); + + owner->u.string = tmp = new_string(size - ind2 + ind1 + fsize, "assign_lvalue_range"); + if (ind1 >= 1) { + strncpy(tmp, dstr, ind1); + tmp += ind1; + } + strcpy(tmp, from->u.string); + tmp += fsize; + + size -= ind2; + if (size >= 1) { + strncpy(tmp, dstr + ind2, size); + *(tmp + size) = 0; + } + FREE_MSTR(dstr); + } + break; + } + +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + { + if (from->type != T_BUFFER) error("Illegal rhs to buffer range lvalue.\n"); + + if ((fsize = from->u.buf->size) == ind2 - ind1) { + memcpy((owner->u.buf)->item + ind1, from->u.buf->item, fsize); + } else { + buffer_t *b; + unsigned char *old_item = (owner->u.buf)->item; + unsigned char *new_item; + + b = allocate_buffer(size - ind2 + ind1 + fsize); + new_item = b->item; + if (ind1 >= 1) { + memcpy(b->item, old_item, ind1); + new_item += ind1; + } + memcpy(new_item, from->u.buf, fsize); + new_item += fsize; + + if ((size -= ind2) >= 1) + memcpy(new_item, old_item + ind2, size); + free_buffer(owner->u.buf); + owner->u.buf = b; + } + break; + } +#endif + } +} + +/* + * Deallocate 'n' values from the stack. + */ +INLINE void +pop_n_elems (int n) +{ + DEBUG_CHECK1(n < 0, "pop_n_elems: %d elements.\n", n); + while (n--) { + pop_stack(); + } +} + +/* + * Deallocate 2 values from the stack. + */ +INLINE void +pop_2_elems() +{ + free_svalue(sp--, "pop_2_elems"); + DEBUG_CHECK(sp < start_of_stack, "Stack underflow.\n"); + free_svalue(sp--, "pop_2_elems"); +} + +/* + * Deallocate 3 values from the stack. + */ +INLINE void +pop_3_elems() +{ + free_svalue(sp--, "pop_3_elems"); + free_svalue(sp--, "pop_3_elems"); + DEBUG_CHECK(sp < start_of_stack, "Stack underflow.\n"); + free_svalue(sp--, "pop_3_elems"); +} + +void bad_arg (int arg, int instr) +{ + error("Bad Argument %d to %s()\n", arg, query_instr_name(instr)); +} + +void bad_argument (svalue_t * val, int type, int arg, int instr) +{ + outbuffer_t outbuf; + int flag = 0; + int j = TYPE_CODES_START; + int k = 0; + + outbuf_zero(&outbuf); + outbuf_addv(&outbuf, "Bad argument %d to %s%s\nExpected: ", arg, + query_instr_name(instr), (instr < BASE ? "" : "()")); + + do { + if (type & j) { + if (flag) outbuf_add(&outbuf, " or "); + else flag = 1; + outbuf_add(&outbuf, type_names[k]); + } + k++; + } while (!((j <<= 1) & TYPE_CODES_END)); + + outbuf_add(&outbuf, " Got: "); + svalue_to_string(val, &outbuf, 0, 0, 0); + outbuf_add(&outbuf, ".\n"); + outbuf_fix(&outbuf); + error_needs_free(outbuf.buffer); +} + +INLINE void +push_control_stack (int frkind) +{ + if (csp == &control_stack[CFG_MAX_CALL_DEPTH - 1]) { + too_deep_error = 1; + error("Too deep recursion.\n"); + } + csp++; + csp->caller_type = caller_type; + csp->ob = current_object; + csp->framekind = frkind; + csp->prev_ob = previous_ob; + csp->fp = fp; + csp->prog = current_prog; + csp->pc = pc; + csp->function_index_offset = function_index_offset; + csp->variable_index_offset = variable_index_offset; + csp->defers = NULL; +} + +/* + * Pop the control stack one element, and restore registers. + * extern_call must not be modified here, as it is used imediately after pop. + */ +void pop_control_stack() +{ + DEBUG_CHECK(csp == (control_stack - 1), + "Popped out of the control stack\n"); +#ifdef DTRACE + if ((csp->framekind & FRAME_MASK) == FRAME_FUNCTION){ + DTRACE_PROBE3(fluffos, lpc__return, current_object->obname, current_prog->function_table[csp->fr.table_index].funcname, current_prog->filename); + } +#endif +#ifdef PROFILE_FUNCTIONS + if ((csp->framekind & FRAME_MASK) == FRAME_FUNCTION) { + long secs, usecs, dsecs; + function_t *cfp = ¤t_prog->function_table[csp->fr.table_index]; + int stof = 0; + + get_cpu_times((unsigned long *) &secs, (unsigned long *) &usecs); + dsecs = (((secs - csp->entry_secs) * 1000000) + + (usecs - csp->entry_usecs)); + cfp->self += dsecs; + + while((csp-stof) != control_stack){ + if (((csp-stof-1)->framekind & FRAME_MASK) == FRAME_FUNCTION) { + function_t *parent = &((csp-stof)->prog->function_table[(csp-stof-1)->fr.table_index]); + if(parent != cfp) //if it's recursion it's not really a child + parent->children += dsecs; + break; + } + stof++; + } + } +#endif + struct defer_list *stuff = csp->defers; + csp->defers = 0; + while(stuff){ + function_to_call_t ftc; + memset(&ftc, 0, sizeof ftc); + ftc.f.fp = stuff->func.u.fp; + int s = outoftime; + if(outoftime) + set_eval(max_cost); + save_command_giver(stuff->tp.u.ob); + safe_call_efun_callback(&ftc, 0); + restore_command_giver(); + outoftime = s; + free_svalue(&(stuff->func), "pop_stack"); + free_svalue(&(stuff->tp), "pop_stack"); + + struct defer_list* old = stuff; + stuff = stuff->next; + FREE(old); + } + current_object = csp->ob; + current_prog = csp->prog; + previous_ob = csp->prev_ob; + caller_type = csp->caller_type; + pc = csp->pc; + fp = csp->fp; + function_index_offset = csp->function_index_offset; + variable_index_offset = csp->variable_index_offset; + csp--; +} + +/* + * Push a pointer to a array on the stack. Note that the reference count + * is incremented. Newly created arrays normally have a reference count + * initialized to 1. + */ +INLINE void push_array (array_t * v) +{ + STACK_INC; + v->ref++; + sp->type = T_ARRAY; + sp->u.arr = v; +} + +INLINE void push_refed_array (array_t * v) +{ + STACK_INC; + sp->type = T_ARRAY; + sp->u.arr = v; +} + +#ifndef NO_BUFFER_TYPE +INLINE void +push_buffer (buffer_t * b) +{ + STACK_INC; + b->ref++; + sp->type = T_BUFFER; + sp->u.buf = b; +} + +INLINE void +push_refed_buffer (buffer_t * b) +{ + STACK_INC; + sp->type = T_BUFFER; + sp->u.buf = b; +} +#endif + +/* + * Push a mapping on the stack. See push_array(), above. + */ +INLINE void +push_mapping (mapping_t * m) +{ + STACK_INC; + m->ref++; + sp->type = T_MAPPING; + sp->u.map = m; +} + +INLINE void +push_refed_mapping (mapping_t * m) +{ + STACK_INC; + sp->type = T_MAPPING; + sp->u.map = m; +} + +/* + * Push a class on the stack. See push_array(), above. + */ +INLINE void +push_class (array_t * v) +{ + STACK_INC; + v->ref++; + sp->type = T_CLASS; + sp->u.arr = v; +} + +INLINE void +push_refed_class (array_t * v) +{ + STACK_INC; + sp->type = T_CLASS; + sp->u.arr = v; +} + +/* + * Push a string on the stack that is already malloced. + */ +INLINE void push_malloced_string (const char * p) +{ + STACK_INC; + sp->type = T_STRING; + sp->u.string = p; + sp->subtype = STRING_MALLOC; +} + +/* + * Pushes a known shared string. Note that this references, while + * push_malloced_string doesn't. + */ +INLINE void push_shared_string (const char * p) { + STACK_INC; + sp->type = T_STRING; + sp->u.string = p; + sp->subtype = STRING_SHARED; + ref_string(p); +} + +/* + * Push a string on the stack that is already constant. + */ +INLINE +void push_constant_string (const char * p) +{ + STACK_INC; + sp->type = T_STRING; + sp->subtype = STRING_CONSTANT; + sp->u.string = p; +} + +#ifdef TRACE +static void do_trace_call (int offset) +{ + do_trace("Call direct ", current_prog->function_table[offset].funcname, " "); + if (TRACEHB) { + if (TRACETST(TRACE_ARGS)) { + int i, n; + + n = current_prog->function_table[offset].num_arg; + + add_vmessage(command_giver, " with %d arguments: ", n); + for (i = n - 1; i >= 0; i--) { + print_svalue(&sp[-i]); + add_message(command_giver, " ", 1); + } + } + add_message(command_giver, "\n", 1); + } +} +#endif + +/* + * Argument is the function to execute. If it is defined by inheritance, + * then search for the real definition, and return it. + * There is a number of arguments on the stack. Normalize them and initialize + * local variables, so that the called function is pleased. + */ +INLINE void setup_variables (int actual, int local, int num_arg) { + int tmp; + + if ((tmp = actual - num_arg) > 0) { + /* Remove excessive arguments */ + pop_n_elems(tmp); + push_undefineds(local); + } else { + /* Correct number of arguments and local variables */ + push_undefineds(local - tmp); + } + fp = sp - (csp->num_local_variables = local + num_arg) + 1; +} + +INLINE_STATIC void setup_varargs_variables (int actual, int local, int num_arg) { + array_t *arr; + if (actual >= num_arg) { + int n = actual - num_arg + 1; + /* Aggregate excessive arguments */ + arr = allocate_empty_array(n); + while (n--) + arr->item[n] = *sp--; + } else { + /* Correct number of arguments and local variables */ + push_undefineds(num_arg - 1 - actual); + arr = &the_null_array; + } + push_refed_array(arr); + push_undefineds(local); + fp = sp - (csp->num_local_variables = local + num_arg) + 1; +} + +INLINE function_t * +setup_new_frame (int findex) +{ + function_t *func_entry; + register int low, high, mid; + int flags; + + function_index_offset = variable_index_offset = 0; + + /* Walk up the inheritance tree to the real definition */ + if (current_prog->function_flags[findex] & FUNC_ALIAS) { + findex = current_prog->function_flags[findex] & ~FUNC_ALIAS; + } + + while (current_prog->function_flags[findex] & FUNC_INHERITED) { + low = 0; + high = current_prog->num_inherited -1; + + while (high > low) { + mid = (low + high + 1) >> 1; + if (current_prog->inherit[mid].function_index_offset > findex) + high = mid -1; + else low = mid; + } + findex -= current_prog->inherit[low].function_index_offset; + function_index_offset += current_prog->inherit[low].function_index_offset; + variable_index_offset += current_prog->inherit[low].variable_index_offset; + current_prog = current_prog->inherit[low].prog; + } + + flags = current_prog->function_flags[findex]; + + findex -= current_prog->last_inherited; + + func_entry = current_prog->function_table + findex; + csp->fr.table_index = findex; +#ifdef PROFILE_FUNCTIONS + get_cpu_times(&(csp->entry_secs), &(csp->entry_usecs)); + current_prog->function_table[findex].calls++; +#endif + + /* Remove excessive arguments */ + if (flags & FUNC_TRUE_VARARGS) { + setup_varargs_variables(csp->num_local_variables, + func_entry->num_local, + func_entry->num_arg); + } + else + setup_variables(csp->num_local_variables, + func_entry->num_local, + func_entry->num_arg); +#ifdef TRACE + tracedepth++; + if (TRACEP(TRACE_CALL)) { + do_trace_call(findex); + } +#endif + DTRACE_PROBE3(fluffos, lpc__entry, current_object->obname, current_prog->function_table[findex].funcname, current_prog->filename); + + return ¤t_prog->function_table[findex]; +} + +INLINE function_t *setup_inherited_frame (int findex) +{ + function_t *func_entry; + register int low, high, mid; + int flags; + + /* Walk up the inheritance tree to the real definition */ + if (current_prog->function_flags[findex] & FUNC_ALIAS) { + findex = current_prog->function_flags[findex] & ~FUNC_ALIAS; + } + + while (current_prog->function_flags[findex] & FUNC_INHERITED) { + low = 0; + high = current_prog->num_inherited -1; + + while (high > low) { + mid = (low + high + 1) >> 1; + if (current_prog->inherit[mid].function_index_offset > findex) + high = mid -1; + else low = mid; + } + findex -= current_prog->inherit[low].function_index_offset; + function_index_offset += current_prog->inherit[low].function_index_offset; + variable_index_offset += current_prog->inherit[low].variable_index_offset; + current_prog = current_prog->inherit[low].prog; + } + + flags = current_prog->function_flags[findex]; + findex -= current_prog->last_inherited; + + func_entry = current_prog->function_table + findex; + csp->fr.table_index = findex; +#ifdef PROFILE_FUNCTIONS + get_cpu_times(&(csp->entry_secs), &(csp->entry_usecs)); + current_prog->function_table[findex].calls++; +#endif + + /* Remove excessive arguments */ + if (flags & FUNC_TRUE_VARARGS) + setup_varargs_variables(csp->num_local_variables, + func_entry->num_local, + func_entry->num_arg); + else + setup_variables(csp->num_local_variables, + func_entry->num_local, + func_entry->num_arg); +#ifdef TRACE + tracedepth++; + if (TRACEP(TRACE_CALL)) { + do_trace_call(findex); + } +#endif + DTRACE_PROBE3(fluffos, lpc__entry, csp->ob->obname, current_prog->function_table[findex].funcname, current_prog->filename); + + return ¤t_prog->function_table[findex]; +} + +#ifdef DEBUG +/* This function is called at the end of every complete LPC statement, so + * it is a good place to insert debugging code to find out where during + * LPC code certain assertions fail, etc + */ +void break_point() +{ + /* The current implementation of foreach leaves some stuff lying on the + stack */ + if (!stack_in_use_as_temporary && sp - fp - csp->num_local_variables + 1 != 0) + fatal("Bad stack pointer.\n"); +} +#endif + +program_t fake_prog = { "" }; +unsigned char fake_program = F_RETURN; + +/* + * Very similar to push_control_stack() [which see]. The purpose of this is + * to insert an frame containing the object which defined a function pointer + * in cases where it would otherwise not be on the call stack. This + * preserves the idea that function pointers calls happen 'through' the + * object that define the function pointer. + * These frames are the ones that show up as in error traces. + */ +void setup_fake_frame (funptr_t * fun) { + if (csp == &control_stack[CFG_MAX_CALL_DEPTH-1]) { + too_deep_error = 1; + error("Too deep recursion.\n"); + } + csp++; + csp->caller_type = caller_type; + csp->framekind = FRAME_FAKE | FRAME_OB_CHANGE; + csp->fr.funp = fun; + csp->ob = current_object; + csp->prev_ob = previous_ob; + csp->fp = fp; + csp->prog = current_prog; + csp->pc = pc; + csp->function_index_offset = function_index_offset; + csp->variable_index_offset = variable_index_offset; + csp->num_local_variables = 0; + + pc = (char *)&fake_program; + caller_type = ORIGIN_FUNCTION_POINTER; + current_prog = &fake_prog; + previous_ob = current_object; + current_object = fun->hdr.owner; +} + +/* Remove a fake frame added by setup_fake_frame(). Basically just a + * specialized version of pop_control_stack(). + */ +void remove_fake_frame() { + DEBUG_CHECK(csp == (control_stack - 1), + "Popped out of the control stack\n"); + current_object = csp->ob; + current_prog = csp->prog; + previous_ob = csp->prev_ob; + caller_type = csp->caller_type; + pc = csp->pc; + fp = csp->fp; + function_index_offset = csp->function_index_offset; + variable_index_offset = csp->variable_index_offset; + csp--; +} + +/* + * When a array is given as argument to an efun, all items have to be + * checked if there would be a destructed object. + * A bad problem currently is that a array can contain another array, so this + * should be tested too. But, there is currently no prevention against + * recursive arrays, which means that this can not be tested. Thus, MudOS + * may crash if a array contains a array that contains a destructed object + * and this top-most array is used as an argument to an efun. + */ +/* MudOS won't crash when doing simple operations like assign_svalue + * on a destructed object. You have to watch out, of course, that you don't + * apply a function to it. + * to save space it is preferable that destructed objects are freed soon. + * amylaar + */ +void check_for_destr (array_t * v) +{ + int i = v->size; + + while (i--) { + if ((v->item[i].type == T_OBJECT) && (v->item[i].u.ob->flags & O_DESTRUCTED)) { + free_svalue(&v->item[i], "check_for_destr"); + v->item[i] = const0u; + } + } +} + +/* do_loop_cond() coded by John Garnett, 1993/06/01 + +Optimizes these four cases (with 'int i'): + +1) for (expr0; i < integer_variable; expr2) statement; +2) for (expr0; i < integer_constant; expr2) statement; +3) while (i < integer_variable) statement; +4) while (i < integer_constant) statement; +*/ + +INLINE_STATIC void do_loop_cond_local() +{ + svalue_t *s1, *s2; + int i; + + s1 = fp + EXTRACT_UCHAR(pc++); /* a from (a < b) */ + s2 = fp + EXTRACT_UCHAR(pc++); + switch(s1->type | s2->type) { + case T_NUMBER: + i = s1->u.number < s2->u.number; + break; + case T_REAL: + i = s1->u.real < s2->u.real; + break; + case T_STRING: + i = (strcmp(s1->u.string, s2->u.string) < 0); + break; + case T_NUMBER|T_REAL: + if (s1->type == T_NUMBER) i = s1->u.number < s2->u.real; + else i = s1->u.real < s2->u.number; + break; + default: + if (s1->type == T_OBJECT && (s1->u.ob->flags & O_DESTRUCTED)) { + free_object(&s1->u.ob, "do_loop_cond:1"); + *s1 = const0u; + } + if (s2->type == T_OBJECT && (s2->u.ob->flags & O_DESTRUCTED)) { + free_object(&s2->u.ob, "do_loop_cond:2"); + *s2 = const0u; + } + if (s1->type == T_NUMBER && s2->type == T_NUMBER) { + i = s1->u.number < s2->u.number; + break; + } + switch(s1->type) { + case T_NUMBER: + case T_REAL: + error("2nd argument to < is not numeric when the 1st is.\n"); + case T_STRING: + error("2nd argument to < is not string when the 1st is.\n"); + default: + error("Bad 1st argument to <.\n"); + } + i = 0; + } + if (i) { + unsigned short offset; + + COPY_SHORT(&offset, pc); + pc -= offset; + } else pc += 2; +} + +INLINE_STATIC void do_loop_cond_number() +{ + svalue_t *s1; + long i; + + s1 = fp + EXTRACT_UCHAR(pc++); /* a from (a < b) */ + LOAD_INT(i, pc); + if (s1->type == T_NUMBER) { + if (s1->u.number < i) { + unsigned short offset; + + COPY_SHORT(&offset, pc); + pc -= offset; + } else pc += 2; + } else if (s1->type == T_REAL) { + if (s1->u.real < i) { + unsigned short offset; + + COPY_SHORT(&offset, pc); + pc -= offset; + } else pc += 2; + } else error("Right side of < is a number, left side is not.\n"); +} + +#ifdef DEBUG_MACRO +static void show_lpc_line (char * f, int l) { + static FILE *fp = 0; + static char *fn = 0; + static int lastline, offset; + static char buf[32768], *p; + static int n; + int dir; + char *q; + + if (fn == f && l == lastline) return; + printf("LPC: %s:%i\n", f, l); + if (!(debug_level & DBG_LPC_line)) { + fn = f; + lastline = l; + return; + } + + if (fn != f) { + if (fp) fclose(fp); + fp = fopen(f, "r"); + if (!fp) goto bail_hard; + fn = f; + lastline = 1; + offset = 0; + n = fread(buf, 1, 32767, fp); + p = buf; + buf[n] = 0; + } + + dir = (lastline < l ? 1 : -1); + while (lastline - l != 0) { + while (p >= buf && *p && *p != '\n') { + p += dir; + } + + if (p < buf || !*p) { + if (dir == -1) { + if (offset == 0) goto bail_hard; + n = 32767; + if (n > offset) n = offset; + } else { + n = 32767; + } + offset += dir * n; + if (fseek(fp, offset, SEEK_SET) == -1) goto bail_hard; + n = fread(buf, 1, n, fp); + if (n <= 0) goto bail_hard; + buf[n] = 0; + p = (dir == 1 ? &buf[n-1] : buf); + } else { + p += dir; + lastline += dir; + } + } + if (dir == -1) { + while (*p != '\n') { + p--; + if (p < buf) { + if (offset == 0) { p++; break; } + n = 32767; + if (n > offset) n = offset; + offset -= n; + if (fseek(fp, offset, SEEK_SET) == -1) goto bail_hard; + n = fread(buf, 1, 32767, fp); + if (n == -1) goto bail_hard; + buf[n] = 0; + p = &buf[n-1]; + } + } + } + q = p; + while (1) { + while (*q) { + putchar(*q); + if (*q++ == '\n') return; + } + offset += 32767; + if (fseek(fp, offset, SEEK_SET) == -1) goto bail_hard; + n = fread(buf, 1, 32767, fp); + if (n == -1) goto bail_hard; + buf[n] = 0; + p = buf; + } + return; + + bail_hard: + fn = 0; + return; +} +#endif + +/* + * Evaluate instructions at address 'p'. All program offsets are + * to current_prog->program. 'current_prog' must be setup before + * call of this function. + * + * There must not be destructed objects on the stack. The destruct_object() + * function will automatically remove all occurences. The effect is that + * all called efuns knows that they won't have destructed objects as + * arguments. + */ +#ifdef TRACE_CODE +static int previous_instruction[60]; +static int stack_size[60]; +static char *previous_pc[60]; +static int last; +#endif + +void +eval_instruction (char * p) +{ +#ifdef DEBUG + int num_arg; +#endif + long i, n; + float real; + svalue_t *lval; + int instruction; +#if defined(TRACE_CODE) || defined(TRACE) || defined(OPCPROF) || defined(OPCPROF_2D) + int real_instruction; +#endif + unsigned short offset; + static func_t *oefun_table = efun_table - BASE + ONEARG_MAX; +#ifndef DEBUG + static func_t *ooefun_table = efun_table - BASE; +#endif + static instr_t *instrs2 = instrs + ONEARG_MAX; + + IF_DEBUG(svalue_t *expected_stack); + + /* Next F_RETURN at this level will return out of eval_instruction() */ + csp->framekind |= FRAME_EXTERNAL; + pc = p; + while (1) { +# ifdef DEBUG_MACRO + if (debug_level & DBG_LPC) { + char *f; + int l; + /* this could be much more efficient ... */ + get_line_number_info(&f, &l); + show_lpc_line(f, l); + } +# endif + instruction = EXTRACT_UCHAR(pc++); +#if defined(TRACE_CODE) || defined(TRACE) || defined(OPCPROF) || defined(OPCPROF_2D) + if (instruction >= F_EFUN0 && instruction <= F_EFUNV) + real_instruction = EXTRACT_UCHAR(pc) + ONEARG_MAX; + else + real_instruction = instruction; +# ifdef TRACE_CODE + previous_instruction[last] = real_instruction; + previous_pc[last] = pc - 1; + stack_size[last] = sp - fp - csp->num_local_variables; + last = (last + 1) % (sizeof previous_instruction / sizeof(int)); +# endif +# ifdef TRACE + if (TRACEP(TRACE_EXEC)) { + do_trace("Exec ", query_instr_name(real_instruction), "\n"); + } +# endif +# ifdef OPCPROF + if (real_instruction < BASE) + opc_eoper[real_instruction]++; + else + opc_efun[real_instruction-BASE].count++; +# endif +# ifdef OPCPROF_2D + if (real_instruction < BASE) { + if (last_eop) opc_eoper_2d[last_eop][real_instruction]++; + last_eop = real_instruction; + } else { + if (last_eop) opc_eoper_2d[last_eop][BASE]++; + last_eop = BASE; + } +# endif +#endif + if (outoftime) { + debug_message("object /%s: eval_cost too big %d\n", + current_object->obname, max_cost); + set_eval(max_cost); + max_eval_error = 1; + error("Too long evaluation. Execution aborted.\n"); + } + /* + * Execute current instruction. Note that all functions callable from + * LPC must return a value. This does not apply to control + * instructions, like F_JUMP. + */ + + switch (instruction) { + case F_PUSH: /* Push a number of things onto the stack */ + n = EXTRACT_UCHAR(pc++); + while (n--) { + i = EXTRACT_UCHAR(pc++); + switch (i & PUSH_WHAT) { + case PUSH_STRING: + DEBUG_CHECK1((i & PUSH_MASK) >= current_prog->num_strings, + "string %d out of range in F_STRING!\n", + i & PUSH_MASK); + push_shared_string(current_prog->strings[i & PUSH_MASK]); + break; + case PUSH_LOCAL: + lval = fp + (i & PUSH_MASK); + DEBUG_CHECK((fp - lval) >= csp->num_local_variables, + "Tried to push non-existent local\n"); + if ((lval->type == T_OBJECT) && (lval->u.ob->flags & O_DESTRUCTED)) + assign_svalue(lval, &const0u); + push_svalue(lval); + break; + case PUSH_GLOBAL: + lval = find_value(((i & PUSH_MASK) + variable_index_offset)); + if ((lval->type == T_OBJECT) && (lval->u.ob->flags & O_DESTRUCTED)) + assign_svalue(lval, &const0u); + push_svalue(lval); + break; + case PUSH_NUMBER: + push_number(i & PUSH_MASK); + break; + } + } + break; + case F_INC: + DEBUG_CHECK(sp->type != T_LVALUE, + "non-lvalue argument to ++\n"); + lval = (sp--)->u.lvalue; + switch (lval->type) { + case T_NUMBER: + lval->u.number++; + break; + case T_REAL: + lval->u.real++; + break; + case T_LVALUE_BYTE: + if (global_lvalue_byte.subtype == 0 && + *global_lvalue_byte.u.lvalue_byte == (unsigned char)255) + error("Strings cannot contain 0 bytes.\n"); + ++*global_lvalue_byte.u.lvalue_byte; + break; + default: + error("++ of non-numeric argument\n"); + } + break; + case F_WHILE_DEC: + { + svalue_t *s; + + s = fp + EXTRACT_UCHAR(pc++); + if (s->type == T_NUMBER) { + i = s->u.number--; + } else if (s->type == T_REAL) { + i = s->u.real--; + } else { + error("-- of non-numeric argument\n"); + } + if (i) { + COPY_SHORT(&offset, pc); + pc -= offset; + } else { + pc += 2; + } + } + break; + case F_LOCAL_LVALUE: + STACK_INC; + sp->type = T_LVALUE; + sp->u.lvalue = fp + EXTRACT_UCHAR(pc++); + break; +#ifdef REF_RESERVED_WORD + case F_MAKE_REF: + { + ref_t *ref; + int op = EXTRACT_UCHAR(pc++); + /* global and local refs need no protection since they are + * guaranteed to outlive the current scope. Lvalues + * inside structures may not, however ... + */ + ref = make_ref(); + ref->lvalue = sp->u.lvalue; + if (op != F_GLOBAL_LVALUE && op != F_LOCAL_LVALUE && op != F_REF_LVALUE) { + ref->sv.type = lv_owner_type; + ref->sv.subtype = STRING_MALLOC; /* ignored if non-string */ + if (lv_owner_type == T_STRING) { + ref->sv.u.string = (char *)lv_owner; + INC_COUNTED_REF(lv_owner); + ADD_STRING(MSTR_SIZE(lv_owner)); + NDBG(BLOCK(lv_owner)); + } else { + ref->sv.u.refed = lv_owner; + lv_owner->ref++; + if (lv_owner_type == T_MAPPING) + ((mapping_t *)lv_owner)->count |= MAP_LOCKED; + } + } else + ref->sv.type = T_NUMBER; + sp->type = T_REF; + sp->u.ref = ref; + break; + } + case F_KILL_REFS: + { + int num = EXTRACT_UCHAR(pc++); + while (num--) + kill_ref(global_ref_list); + break; + } + case F_REF: + { + svalue_t *s = fp + EXTRACT_UCHAR(pc++); + svalue_t *reflval; + + if (s->type == T_REF) { + reflval = s->u.ref->lvalue; + if (!reflval) + error("Reference is invalid.\n"); + + if (reflval->type == T_LVALUE_BYTE) { + push_number(*global_lvalue_byte.u.lvalue_byte); + break; + } + } else { + error("Non-reference value passed as reference argument.\n"); + } + + if (reflval->type == T_OBJECT && (reflval->u.ob->flags & O_DESTRUCTED)) + assign_svalue(reflval, &const0u); + push_svalue(reflval); + + break; + } + case F_REF_LVALUE: + { + svalue_t *s = fp + EXTRACT_UCHAR(pc++); + + if (s->type == T_REF) { + if (s->u.ref->lvalue) { + STACK_INC; + sp->type = T_LVALUE; + sp->u.lvalue = s->u.ref->lvalue; + } else + error("Reference is invalid.\n"); + } else + error("Non-reference value passed as reference argument.\n"); + break; + } +#endif + case F_SHORT_INT: + { + short s; + + LOAD_SHORT(s, pc); + push_number(s); + break; + } + case F_NUMBER: + LOAD_INT(i, pc); + push_number(i); + break; + case F_REAL: + LOAD_FLOAT(real, pc); + push_real(real); + break; + case F_BYTE: + push_number(EXTRACT_UCHAR(pc++)); + break; + case F_NBYTE: + push_number(-(EXTRACT_UCHAR(pc++))); + break; +#ifdef F_JUMP_WHEN_NON_ZERO + case F_JUMP_WHEN_NON_ZERO: + if ((i = (sp->type == T_NUMBER)) && (sp->u.number == 0)) + pc += 2; + else { + COPY_SHORT(&offset, pc); + pc = current_prog->program + offset; + } + if (i) { + sp--; /* when sp is an integer svalue, its cheaper + * to do this */ + } else { + pop_stack(); + } + break; +#endif + case F_BRANCH: /* relative offset */ + COPY_SHORT(&offset, pc); + pc += offset; + break; + case F_BBRANCH: /* relative offset */ + COPY_SHORT(&offset, pc); + pc -= offset; + break; + case F_BRANCH_NE: + f_ne(); + if ((sp--)->u.number) { + COPY_SHORT(&offset, pc); + pc += offset; + } else + pc += 2; + break; + case F_BRANCH_GE: + f_ge(); + if ((sp--)->u.number) { + COPY_SHORT(&offset, pc); + pc += offset; + } else + pc += 2; + break; + case F_BRANCH_LE: + f_le(); + if ((sp--)->u.number) { + COPY_SHORT(&offset, pc); + pc += offset; + } else + pc += 2; + break; + case F_BRANCH_EQ: + f_eq(); + if ((sp--)->u.number) { + COPY_SHORT(&offset, pc); + pc += offset; + } else + pc += 2; + break; + case F_BBRANCH_LT: + f_lt(); + if ((sp--)->u.number) { + COPY_SHORT(&offset, pc); + pc -= offset; + } else + pc += 2; + break; + case F_BRANCH_WHEN_ZERO: /* relative offset */ + if (sp->type == T_NUMBER) { + if (!((sp--)->u.number)) { + COPY_SHORT(&offset, pc); + pc += offset; + break; + } + } else pop_stack(); + pc += 2; /* skip over the offset */ + break; + case F_BRANCH_WHEN_NON_ZERO: /* relative offset */ + if (sp->type == T_NUMBER) { + if (!((sp--)->u.number)) { + pc += 2; + break; + } + } else pop_stack(); + COPY_SHORT(&offset, pc); + pc += offset; + break; + case F_BBRANCH_WHEN_ZERO: /* relative backwards offset */ + if (sp->type == T_NUMBER) { + if (!((sp--)->u.number)) { + COPY_SHORT(&offset, pc); + pc -= offset; + break; + } + } else pop_stack(); + pc += 2; + break; + case F_BBRANCH_WHEN_NON_ZERO: /* relative backwards offset */ + if (sp->type == T_NUMBER) { + if (!((sp--)->u.number)) { + pc += 2; + break; + } + } else pop_stack(); + COPY_SHORT(&offset, pc); + pc -= offset; + break; + case F_LOR: + /* replaces F_DUP; F_BRANCH_WHEN_NON_ZERO; F_POP */ + if (sp->type == T_NUMBER) { + if (!sp->u.number) { + pc += 2; + sp--; + break; + } + } + COPY_SHORT(&offset, pc); + pc += offset; + break; + case F_LAND: + /* replaces F_DUP; F_BRANCH_WHEN_ZERO; F_POP */ + if (sp->type == T_NUMBER) { + if (!sp->u.number) { + COPY_SHORT(&offset, pc); + pc += offset; + break; + } + sp--; + } else pop_stack(); + pc += 2; + break; + case F_LOOP_INCR: /* this case must be just prior to + * F_LOOP_COND */ + { + svalue_t *s; + + s = fp + EXTRACT_UCHAR(pc++); + if (s->type == T_NUMBER) { + s->u.number++; + } else if (s->type == T_REAL) { + s->u.real++; + } else { + error("++ of non-numeric argument\n"); + } + } + if (*pc == F_LOOP_COND_LOCAL) { + pc++; + do_loop_cond_local(); + } else if (*pc == F_LOOP_COND_NUMBER) { + pc++; + do_loop_cond_number(); + } + break; + case F_LOOP_COND_LOCAL: + do_loop_cond_local(); + break; + case F_LOOP_COND_NUMBER: + do_loop_cond_number(); + break; + case F_TRANSFER_LOCAL: + { + svalue_t *s; + + s = fp + EXTRACT_UCHAR(pc++); + DEBUG_CHECK((fp-s) >= csp->num_local_variables, + "Tried to push non-existent local\n"); + if ((s->type == T_OBJECT) && (s->u.ob->flags & O_DESTRUCTED)) + assign_svalue(s, &const0u); + + STACK_INC; + *sp = *s; + + /* The optimizer has asserted this won't be used again. Make + * it look like a number to avoid double frees. */ + s->type = T_NUMBER; + break; + } + case F_LOCAL: + { + svalue_t *s; + + s = fp + EXTRACT_UCHAR(pc++); + DEBUG_CHECK((fp-s) >= csp->num_local_variables, + "Tried to push non-existent local\n"); + + /* + * If variable points to a destructed object, replace it + * with 0, otherwise, fetch value of variable. + */ + if ((s->type == T_OBJECT) && (s->u.ob->flags & O_DESTRUCTED)) + assign_svalue(s, &const0u); + push_svalue(s); + break; + } + case F_LT: + f_lt(); + break; + case F_ADD: + { + switch (sp->type) { +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + { + if (!((sp-1)->type == T_BUFFER)) { + error("Bad type argument to +. Had %s and %s.\n", + type_name((sp - 1)->type), type_name(sp->type)); + } else { + buffer_t *b; + + b = allocate_buffer(sp->u.buf->size + (sp - 1)->u.buf->size); + memcpy(b->item, (sp - 1)->u.buf->item, (sp - 1)->u.buf->size); + memcpy(b->item + (sp - 1)->u.buf->size, sp->u.buf->item, + sp->u.buf->size); + free_buffer((sp--)->u.buf); + free_buffer(sp->u.buf); + sp->u.buf = b; + } + break; + } /* end of x + T_BUFFER */ +#endif + case T_NUMBER: + { + switch ((--sp)->type) { + case T_NUMBER: + sp->u.number += (sp+1)->u.number; + sp->subtype = 0; + break; + case T_REAL: + sp->u.real += (sp+1)->u.number; + break; + case T_STRING: + { + char buff[30]; + + sprintf(buff, "%ld", (sp+1)->u.number); + EXTEND_SVALUE_STRING(sp, buff, "f_add: 2"); + break; + } + default: + error("Bad type argument to +. Had %s and %s.\n", + type_name(sp->type), type_name((sp+1)->type)); + } + break; + } /* end of x + NUMBER */ + case T_REAL: + { + switch ((--sp)->type) { + case T_NUMBER: + sp->type = T_REAL; + sp->u.real = sp->u.number + (sp+1)->u.real; + break; + case T_REAL: + sp->u.real += (sp+1)->u.real; + break; + case T_STRING: + { + char buff[40]; + + sprintf(buff, "%f", (sp+1)->u.real); + EXTEND_SVALUE_STRING(sp, buff, "f_add: 2"); + break; + } + default: + error("Bad type argument to +. Had %s and %s\n", + type_name(sp->type), type_name((sp+1)->type)); + } + break; + } /* end of x + T_REAL */ + case T_ARRAY: + { + if (!((sp-1)->type == T_ARRAY)) { + error("Bad type argument to +. Had %s and %s\n", + type_name((sp - 1)->type), type_name(sp->type)); + } else { + /* add_array now free's the arrays */ + (sp-1)->u.arr = add_array((sp - 1)->u.arr, sp->u.arr); + sp--; + break; + } + } /* end of x + T_ARRAY */ + case T_MAPPING: + { + if ((sp-1)->type == T_MAPPING) { + mapping_t *map; + + map = add_mapping((sp - 1)->u.map, sp->u.map); + free_mapping((sp--)->u.map); + free_mapping(sp->u.map); + sp->u.map = map; + break; + } else + error("Bad type argument to +. Had %s and %s\n", + type_name((sp - 1)->type), type_name(sp->type)); + } /* end of x + T_MAPPING */ + case T_STRING: + { + switch ((sp-1)->type) { + case T_OBJECT: + { + char buff[1024]; + object_t *ob = (sp-1)->u.ob; + sprintf(buff, "/%s", ob->obname); + SVALUE_STRING_ADD_LEFT(buff, "f_add: 3"); + free_object(&ob, "f_add: 3"); + break; + } + case T_NUMBER: + { + char buff[30]; + + sprintf(buff, "%ld", (sp-1)->u.number); + SVALUE_STRING_ADD_LEFT(buff, "f_add: 3"); + break; + } /* end of T_NUMBER + T_STRING */ + case T_REAL: + { + char buff[40]; + + sprintf(buff, "%f", (sp - 1)->u.real); + SVALUE_STRING_ADD_LEFT(buff, "f_add: 3"); + break; + } /* end of T_REAL + T_STRING */ + case T_STRING: + { + SVALUE_STRING_JOIN(sp-1, sp, "f_add: 1"); + sp--; + break; + } /* end of T_STRING + T_STRING */ + default: + error("Bad type argument to +. Had %s and %s\n", + type_name((sp - 1)->type), type_name(sp->type)); + } + break; + } /* end of x + T_STRING */ + case T_OBJECT: + switch ((sp-1)->type) { + case T_STRING: + { + const char *fname = sp->u.ob->obname; + free_object(&(sp--)->u.ob, "f_add: str+ob"); + EXTEND_SVALUE_STRING(sp, "/", "f_add: str ob"); + EXTEND_SVALUE_STRING(sp, fname, "f_add: str ob"); + break; + } + default: + error("Bad type argument to +. Had %s and %s.\n", + type_name(sp->type), type_name((sp+1)->type)); + } + break; + default: + error("Bad type argument to +. Had %s and %s.\n", + type_name((sp-1)->type), type_name(sp->type)); + } + break; + } + case F_VOID_ADD_EQ: + case F_ADD_EQ: + DEBUG_CHECK(sp->type != T_LVALUE, + "non-lvalue argument to +=\n"); + lval = sp->u.lvalue; + sp--; /* points to the RHS */ + switch (lval->type) { + case T_STRING: + if (sp->type == T_STRING) { + SVALUE_STRING_JOIN(lval, sp, "f_add_eq: 1"); + } else if (sp->type == T_NUMBER) { + char buff[30]; + + sprintf(buff, "%ld", sp->u.number); + EXTEND_SVALUE_STRING(lval, buff, "f_add_eq: 2"); + } else if (sp->type == T_REAL) { + char buff[40]; + + sprintf(buff, "%f", sp->u.real); + EXTEND_SVALUE_STRING(lval, buff, "f_add_eq: 2"); + } else if(sp->type == T_OBJECT) { + const char *fname = sp->u.ob->obname; + free_object(&(sp--)->u.ob, "f_add_eq: 2"); + EXTEND_SVALUE_STRING(lval, "/", "f_add: str ob"); + EXTEND_SVALUE_STRING(lval, fname, "f_add_eq: 2"); + } else { + bad_argument(sp, T_OBJECT | T_STRING | T_NUMBER | T_REAL, 2, instruction); + } + break; + case T_NUMBER: + if (sp->type == T_NUMBER) { + lval->u.number += sp->u.number; + lval->subtype = 0; + /* both sides are numbers, no freeing required */ + } else if (sp->type == T_REAL) { + lval->u.number += sp->u.real; + lval->subtype = 0; + /* both sides are numbers, no freeing required */ + } else { + error("Left hand side of += is a number (or zero); right side is not a number.\n"); + } + break; + case T_REAL: + if (sp->type == T_NUMBER) { + lval->u.real += sp->u.number; + /* both sides are numerics, no freeing required */ + } else if (sp->type == T_REAL) { + lval->u.real += sp->u.real; + /* both sides are numerics, no freeing required */ + } else { + error("Left hand side of += is a number (or zero); right side is not a number.\n"); + } + break; +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + if (sp->type != T_BUFFER) { + bad_argument(sp, T_BUFFER, 2, instruction); + } else { + buffer_t *b; + + b = allocate_buffer(lval->u.buf->size + sp->u.buf->size); + memcpy(b->item, lval->u.buf->item, lval->u.buf->size); + memcpy(b->item + lval->u.buf->size, sp->u.buf->item, + sp->u.buf->size); + free_buffer(sp->u.buf); + free_buffer(lval->u.buf); + lval->u.buf = b; + } + break; +#endif + case T_ARRAY: + if (sp->type != T_ARRAY) + bad_argument(sp, T_ARRAY, 2, instruction); + else { + /* add_array now frees the arrays */ + lval->u.arr = add_array(lval->u.arr, sp->u.arr); + } + break; + case T_MAPPING: + if (sp->type != T_MAPPING) + bad_argument(sp, T_MAPPING, 2, instruction); + else { + absorb_mapping(lval->u.map, sp->u.map); + free_mapping(sp->u.map); /* free RHS */ + /* LHS not freed because its being reused */ + } + break; + case T_LVALUE_BYTE: + { + char c; + + if (sp->type != T_NUMBER) + error("Bad right type to += of char lvalue.\n"); + + c = *global_lvalue_byte.u.lvalue_byte + sp->u.number; + + if (global_lvalue_byte.subtype == 0 && c == '\0') + error("Strings cannot contain 0 bytes.\n"); + *global_lvalue_byte.u.lvalue_byte = c; + } + break; + default: + bad_arg(1, instruction); + } + + if (instruction == F_ADD_EQ) { /* not void add_eq */ + assign_svalue_no_free(sp, lval); + } else { + /* + * but if (void)add_eq then no need to produce an + * rvalue + */ + sp--; + } + break; + case F_AND: + f_and(); + break; + case F_AND_EQ: + f_and_eq(); + break; + case F_FUNCTION_CONSTRUCTOR: + f_function_constructor(); + break; + + case F_FOREACH: + { + int flags = EXTRACT_UCHAR(pc++); + + IF_DEBUG(stack_in_use_as_temporary++); + if (flags & FOREACH_MAPPING) { + CHECK_TYPES(sp, T_MAPPING, 2, F_FOREACH); + + push_refed_array(mapping_indices(sp->u.map)); + + STACK_INC; + sp->type = T_NUMBER; + sp->u.lvalue = (sp-1)->u.arr->item; + sp->subtype = (sp-1)->u.arr->size; + + STACK_INC; + sp->type = T_LVALUE; + if (flags & FOREACH_LEFT_GLOBAL) { + sp->u.lvalue = find_value((int)(READ_GLOBAL_INDEX(pc) + variable_index_offset)); + } else { + sp->u.lvalue = fp + EXTRACT_UCHAR(pc++); + } + } else + if (sp->type == T_STRING) { + STACK_INC; + sp->type = T_NUMBER; + sp->u.lvalue_byte = (unsigned char *)((sp-1)->u.string); + sp->subtype = SVALUE_STRLEN(sp - 1); + } else { + CHECK_TYPES(sp, T_ARRAY, 2, F_FOREACH); + + STACK_INC; + sp->type = T_NUMBER; + sp->u.lvalue = (sp-1)->u.arr->item; + sp->subtype = (sp-1)->u.arr->size; + } + + if (flags & FOREACH_RIGHT_GLOBAL) { + STACK_INC; + sp->type = T_LVALUE; + sp->u.lvalue = find_value((int)(READ_GLOBAL_INDEX(pc) + variable_index_offset)); + } else if (flags & FOREACH_REF) { + ref_t *ref = make_ref(); + svalue_t *loc = fp + EXTRACT_UCHAR(pc++); + + /* foreach guarantees our target remains valid */ + ref->lvalue = 0; + ref->sv.type = T_NUMBER; + STACK_INC; + sp->type = T_REF; + sp->u.ref = ref; + DEBUG_CHECK(loc->type != T_NUMBER && loc->type != T_REF, "Somehow a reference in foreach acquired a value before coming into scope"); + loc->type = T_REF; + loc->u.ref = ref; + ref->ref++; + } else { + STACK_INC; + sp->type = T_LVALUE; + sp->u.lvalue = fp + EXTRACT_UCHAR(pc++); + } + break; + } + case F_NEXT_FOREACH: + if ((sp-1)->type == T_LVALUE) { + /* mapping */ + if ((sp-2)->subtype--) { + svalue_t *key = (sp-2)->u.lvalue++; + svalue_t *value = find_in_mapping((sp-4)->u.map, key); + + assign_svalue((sp-1)->u.lvalue, key); + if (sp->type == T_REF) { + if (value == &const0u) + sp->u.ref->lvalue = 0; + else + sp->u.ref->lvalue = value; + } else + assign_svalue(sp->u.lvalue, value); + COPY_SHORT(&offset, pc); + pc -= offset; + break; + } + } else { + /* array or string */ + if ((sp-1)->subtype--) { + if ((sp-2)->type == T_STRING) { + if (sp->type == T_REF) { + sp->u.ref->lvalue = &global_lvalue_byte; + global_lvalue_byte.u.lvalue_byte = (unsigned char *)((sp-1)->u.lvalue_byte++); + } else { + free_svalue(sp->u.lvalue, "foreach-string"); + sp->u.lvalue->type = T_NUMBER; + sp->u.lvalue->subtype = 0; + sp->u.lvalue->u.number = *((sp-1)->u.lvalue_byte)++; + } + } else { + if (sp->type == T_REF) + sp->u.ref->lvalue = (sp-1)->u.lvalue++; + else + assign_svalue(sp->u.lvalue, (sp-1)->u.lvalue++); + } + COPY_SHORT(&offset, pc); + pc -= offset; + break; + } + } + pc += 2; + /* fallthrough */ + case F_EXIT_FOREACH: + IF_DEBUG(stack_in_use_as_temporary--); + if (sp->type == T_REF) { + if (!(--sp->u.ref->ref) && sp->u.ref->lvalue == 0) + FREE(sp->u.ref); + } + if ((sp-1)->type == T_LVALUE) { + /* mapping */ + sp -= 3; + free_array((sp--)->u.arr); + free_mapping((sp--)->u.map); + } else { + /* array or string */ + sp -= 2; + if (sp->type == T_STRING) + free_string_svalue(sp--); + else + free_array((sp--)->u.arr); + } + break; + + case F_EXPAND_VARARGS: + { + svalue_t *s, *t; + array_t *arr; + + i = EXTRACT_UCHAR(pc++); + s = sp - i; + + if (s->type != T_ARRAY) + error("Item being expanded with ... is not an array\n"); + + arr = s->u.arr; + n = arr->size; + CHECK_STACK_OVERFLOW(n - 1); + num_varargs += n - 1; + if (!n) { + t = s; + while (t < sp) { + *t = *(t + 1); + t++; + } + sp--; + } else if (n == 1) { + assign_svalue_no_free(s, &arr->item[0]); + } else { + t = sp; + CHECK_STACK_OVERFLOW(n - 1); + sp += n - 1; + while (t > s) { + *(t + n - 1) = *t; + t--; + } + t = s + n - 1; + if (arr->ref == 1) { + memcpy(s, arr->item, n * sizeof(svalue_t)); + free_empty_array(arr); + break; + } else { + while (n--) + assign_svalue_no_free(t--, &arr->item[n]); + } + } + free_array(arr); + break; + } + + case F_NEW_CLASS: + { + array_t *cl; + + cl = allocate_class(¤t_prog->classes[EXTRACT_UCHAR(pc++)], 1); + push_refed_class(cl); + } + break; + case F_NEW_EMPTY_CLASS: + { + array_t *cl; + + cl = allocate_class(¤t_prog->classes[EXTRACT_UCHAR(pc++)], 0); + push_refed_class(cl); + } + break; + case F_AGGREGATE: + { + array_t *v; + + LOAD_SHORT(offset, pc); + offset += num_varargs; + num_varargs = 0; + v = allocate_empty_array(offset); + /* + * transfer svalues in reverse...popping stack as we go + */ + while (offset--) + v->item[offset] = *sp--; + push_refed_array(v); + } + break; + case F_AGGREGATE_ASSOC: + { + mapping_t *m; + + LOAD_SHORT(offset, pc); + + offset += num_varargs; + num_varargs = 0; + m = load_mapping_from_aggregate(sp -= offset, offset); + push_refed_mapping(m); + break; + } + case F_ASSIGN: +#ifdef DEBUG + if (sp->type != T_LVALUE) fatal("Bad argument to F_ASSIGN\n"); +#endif + switch(sp->u.lvalue->type) { + case T_LVALUE_BYTE: + { + unsigned char c; + + if ((sp - 1)->type != T_NUMBER) { + error("Illegal rhs to char lvalue\n"); + } else { + c = ((sp - 1)->u.number & 0xff); + if (global_lvalue_byte.subtype == 0 && c == '\0') + error("Strings cannot contain 0 bytes.\n"); + *global_lvalue_byte.u.lvalue_byte = c; + } + break; + } + default: + assign_svalue(sp->u.lvalue, sp - 1); + break; + case T_LVALUE_RANGE: + assign_lvalue_range(sp - 1); + break; + } + sp--; /* ignore lvalue */ + /* rvalue is already in the correct place */ + break; + case F_VOID_ASSIGN_LOCAL: + if (sp->type != T_INVALID) { + lval = fp + EXTRACT_UCHAR(pc++); + free_svalue(lval, "F_VOID_ASSIGN_LOCAL"); + *lval = *sp--; + } else { + sp--; + pc++; + } + break; + case F_VOID_ASSIGN: +#ifdef DEBUG + if (sp->type != T_LVALUE) fatal("Bad argument to F_VOID_ASSIGN\n"); +#endif + lval = (sp--)->u.lvalue; + if (sp->type != T_INVALID) { + switch(lval->type) { + case T_LVALUE_BYTE: + { + if (sp->type != T_NUMBER) { + error("Illegal rhs to char lvalue\n"); + } else { + char c = (sp--)->u.number & 0xff; + if (global_lvalue_byte.subtype == 0 && c == '\0') + error("Strings cannot contain 0 bytes.\n"); + *global_lvalue_byte.u.lvalue_byte = c; + } + break; + } + + case T_LVALUE_RANGE: + { + copy_lvalue_range(sp--); + break; + } + + default: + { + free_svalue(lval, "F_VOID_ASSIGN : 3"); + *lval = *sp--; + } + } + } else sp--; + break; +#ifdef DEBUG + case F_BREAK_POINT: + break_point(); + break; +#endif + case F_CALL_FUNCTION_BY_ADDRESS: + { + function_t *funp; + + LOAD_SHORT(offset, pc); + + offset += function_index_offset; + /* + * Find the function in the function table. As the + * function may have been redefined by inheritance, we + * must look in the last table, which is pointed to by + * current_object. + */ + DEBUG_CHECK(offset >= current_object->prog->last_inherited + + current_object->prog->num_functions_defined, + "Illegal function index\n"); + + if (current_object->prog->function_flags[offset] & FUNC_ALIAS) { + offset = current_object->prog->function_flags[offset] & ~FUNC_ALIAS; + } + + if (current_object->prog->function_flags[offset] + & (FUNC_PROTOTYPE|FUNC_UNDEFINED)) { + error("Undefined function called: %s\n", function_name(current_object->prog, offset)); + } + + /* Save all important global stack machine registers */ + push_control_stack(FRAME_FUNCTION); + current_prog = current_object->prog; + + caller_type = ORIGIN_LOCAL; + /* + * If it is an inherited function, search for the real + * definition. + */ + csp->num_local_variables = EXTRACT_UCHAR(pc++) + num_varargs; + num_varargs = 0; + //if(offset > USHRT_MAX) + //error("Broken function table"); offset is a USHRT, so this just can't happen! + funp = setup_new_frame(offset); + csp->pc = pc; /* The corrected return address */ + + pc = current_prog->program + funp->address; + } + break; + case F_CALL_INHERITED: + { + inherit_t *ip = current_prog->inherit + EXTRACT_UCHAR(pc++); + program_t *temp_prog = ip->prog; + function_t *funp; + + LOAD_SHORT(offset, pc); + + push_control_stack(FRAME_FUNCTION); + current_prog = temp_prog; + + caller_type = ORIGIN_LOCAL; + + csp->num_local_variables = EXTRACT_UCHAR(pc++) + num_varargs; + num_varargs = 0; + + function_index_offset += ip->function_index_offset; + variable_index_offset += ip->variable_index_offset; + + funp = setup_inherited_frame(offset); + csp->pc = pc; + pc = current_prog->program + funp->address; + } + break; + case F_COMPL: + if (sp->type != T_NUMBER) + error("Bad argument to ~\n"); + sp->u.number = ~sp->u.number; + sp->subtype = 0; + break; + case F_CONST0: + push_number(0); + break; + case F_CONST1: + push_number(1); + break; + case F_PRE_DEC: + DEBUG_CHECK(sp->type != T_LVALUE, + "non-lvalue argument to --\n"); + lval = sp->u.lvalue; + switch (lval->type) { + case T_NUMBER: + sp->type = T_NUMBER; + sp->subtype = 0; + sp->u.number = --(lval->u.number); + break; + case T_REAL: + sp->type = T_REAL; + sp->u.real = --(lval->u.real); + break; + case T_LVALUE_BYTE: + if (global_lvalue_byte.subtype == 0 && + *global_lvalue_byte.u.lvalue_byte == '\x1') + error("Strings cannot contain 0 bytes.\n"); + sp->type = T_NUMBER; + sp->subtype = 0; + sp->u.number = --(*global_lvalue_byte.u.lvalue_byte); + break; + default: + error("-- of non-numeric argument\n"); + } + break; + case F_DEC: + DEBUG_CHECK(sp->type != T_LVALUE, + "non-lvalue argument to --\n"); + lval = (sp--)->u.lvalue; + switch (lval->type) { + case T_NUMBER: + lval->u.number--; + break; + case T_REAL: + lval->u.real--; + break; + case T_LVALUE_BYTE: + if (global_lvalue_byte.subtype == 0 && + *global_lvalue_byte.u.lvalue_byte == '\x1') + error("Strings cannot contain 0 bytes.\n"); + --(*global_lvalue_byte.u.lvalue_byte); + break; + default: + error("-- of non-numeric argument\n"); + } + break; + case F_DIVIDE: + { + switch((sp-1)->type|sp->type) { + + case T_NUMBER: + { + if (!(sp--)->u.number) error("Division by zero\n"); + sp->u.number /= (sp+1)->u.number; + break; + } + + case T_REAL: + { + if ((sp--)->u.real == 0.0) error("Division by zero\n"); + sp->u.real /= (sp+1)->u.real; + break; + } + + case T_NUMBER|T_REAL: + { + if ((sp--)->type == T_NUMBER) { + if (!((sp+1)->u.number)) error("Division by zero\n"); + sp->u.real /= (sp+1)->u.number; + } else { + if ((sp+1)->u.real == 0.0) error("Division by 0.0\n"); + sp->type = T_REAL; + sp->u.real = sp->u.number / (sp+1)->u.real; + } + break; + } + + default: + { + if (!((sp-1)->type & (T_NUMBER|T_REAL))) + bad_argument(sp-1,T_NUMBER|T_REAL,1, instruction); + if (!(sp->type & (T_NUMBER|T_REAL))) + bad_argument(sp, T_NUMBER|T_REAL,2, instruction); + } + } + } + break; + case F_DIV_EQ: + f_div_eq(); + break; + case F_EQ: + f_eq(); + break; + case F_GE: + f_ge(); + break; + case F_GT: + f_gt(); + break; + case F_GLOBAL: + { + svalue_t *s; + + s = find_value((int) (READ_GLOBAL_INDEX(pc) + variable_index_offset)); + + /* + * If variable points to a destructed object, replace it + * with 0, otherwise, fetch value of variable. + */ + if ((s->type == T_OBJECT) && (s->u.ob->flags & O_DESTRUCTED)) + assign_svalue(s, &const0u); + push_svalue(s); + break; + } + case F_PRE_INC: + DEBUG_CHECK(sp->type != T_LVALUE, + "non-lvalue argument to ++\n"); + lval = sp->u.lvalue; + switch (lval->type) { + case T_NUMBER: + sp->type = T_NUMBER; + sp->subtype = 0; + sp->u.number = ++lval->u.number; + break; + case T_REAL: + sp->type = T_REAL; + sp->u.real = ++lval->u.real; + break; + case T_LVALUE_BYTE: + if (global_lvalue_byte.subtype == 0 && + *global_lvalue_byte.u.lvalue_byte == (unsigned char)255) + error("Strings cannot contain 0 bytes.\n"); + sp->type = T_NUMBER; + sp->subtype = 0; + sp->u.number = ++*global_lvalue_byte.u.lvalue_byte; + break; + default: + error("++ of non-numeric argument\n"); + } + break; + case F_MEMBER: + { + array_t *arr; + + if (sp->type != T_CLASS) + error("Tried to take a member of something that isn't a class.\n"); + i = EXTRACT_UCHAR(pc++); + arr = sp->u.arr; + if (i >= arr->size) error("Class has no corresponding member.\n"); + if (arr->item[i].type == T_OBJECT && + (arr->item[i].u.ob->flags & O_DESTRUCTED)) { + assign_svalue(&arr->item[i], &const0u); + } + assign_svalue_no_free(sp, &arr->item[i]); + free_class(arr); + + break; + } + case F_MEMBER_LVALUE: + { + array_t *arr; + + if (sp->type != T_CLASS) + error("Tried to take a member of something that isn't a class.\n"); + i = EXTRACT_UCHAR(pc++); + arr = sp->u.arr; + if (i >= arr->size) error("Class has no corresponding member.\n"); + sp->type = T_LVALUE; + sp->u.lvalue = arr->item + i; +#ifdef REF_RESERVED_WORD + lv_owner_type = T_CLASS; + lv_owner = (refed_t *)arr; +#endif + free_class(arr); + break; + } + case F_INDEX: + switch (sp->type) { + case T_MAPPING: + { + svalue_t *v; + mapping_t *m; + + v = find_in_mapping(m = sp->u.map, sp - 1); + if (v->type == T_OBJECT && (v->u.ob->flags & O_DESTRUCTED)) { + assign_svalue(v, &const0u); + } + assign_svalue(--sp, v); /* v will always have a value */ + free_mapping(m); + break; + } +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + { + if ((sp-1)->type != T_NUMBER) + error("Buffer indexes must be integers.\n"); + + i = (sp - 1)->u.number; + if ((i > sp->u.buf->size) || (i < 0)) + error("Buffer index out of bounds.\n"); + i = sp->u.buf->item[i]; + free_buffer(sp->u.buf); + (--sp)->u.number = i; + sp->subtype = 0; + break; + } +#endif + case T_STRING: + { + if ((sp-1)->type != T_NUMBER) { + error("String indexes must be integers.\n"); + } + i = (sp - 1)->u.number; + if ((i > SVALUE_STRLEN(sp)) || (i < 0)) + error("String index out of bounds.\n"); + i = (unsigned char) sp->u.string[i]; + free_string_svalue(sp); + (--sp)->u.number = i; + break; + } + case T_ARRAY: + { + array_t *arr; + + if ((sp-1)->type != T_NUMBER) + error("Array indexes must be integers.\n"); + i = (sp - 1)->u.number; + if (i<0) error("Array index must be positive or zero.\n"); + arr = sp->u.arr; + if (i >= arr->size) error("Array index out of bounds.\n"); + if (arr->item[i].type == T_OBJECT && + (arr->item[i].u.ob->flags & O_DESTRUCTED)) { + assign_svalue(&arr->item[i], &const0u); + } + assign_svalue_no_free(--sp, &arr->item[i]); + free_array(arr); + break; + } + default: + if (sp->type == T_NUMBER && !sp->u.number) + error("Value being indexed is zero.\n"); + error("Cannot index value of type '%s'.\n", type_name(sp->type)); + } + break; + case F_RINDEX: + switch (sp->type) { +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + { + if ((sp-1)->type != T_NUMBER) + error("Indexing a buffer with an illegal type.\n"); + + i = sp->u.buf->size - (sp - 1)->u.number; + if ((i > sp->u.buf->size) || (i < 0)) + error("Buffer index out of bounds.\n"); + + i = sp->u.buf->item[i]; + free_buffer(sp->u.buf); + (--sp)->u.number = i; + sp->subtype = 0; + break; + } +#endif + case T_STRING: + { + int len = SVALUE_STRLEN(sp); + if ((sp-1)->type != T_NUMBER) { + error("Indexing a string with an illegal type.\n"); + } + i = len - (sp - 1)->u.number; + if ((i > len) || (i < 0)) + error("String index out of bounds.\n"); + i = (unsigned char) sp->u.string[i]; + free_string_svalue(sp); + (--sp)->u.number = i; + break; + } + case T_ARRAY: + { + array_t *arr = sp->u.arr; + + if ((sp-1)->type != T_NUMBER) + error("Indexing an array with an illegal type\n"); + i = arr->size - (sp - 1)->u.number; + if (i < 0 || i >= arr->size) error("Array index out of bounds.\n"); + if (arr->item[i].type == T_OBJECT && + (arr->item[i].u.ob->flags & O_DESTRUCTED)) { + assign_svalue(&arr->item[i], &const0u); + } + assign_svalue_no_free(--sp, &arr->item[i]); + free_array(arr); + break; + } + default: + if (sp->type == T_NUMBER && !sp->u.number) + error("Value being indexed is zero.\n"); + error("Cannot index value of type '%s'.\n", type_name(sp->type)); + } + break; +#ifdef F_JUMP_WHEN_ZERO + case F_JUMP_WHEN_ZERO: + if ((i = (sp->type == T_NUMBER)) && sp->u.number == 0) { + COPY_SHORT(&offset, pc); + pc = current_prog->program + offset; + } else { + pc += 2; + } + if (i) { + sp--; /* cheaper to do this when sp is an integer + * svalue */ + } else { + pop_stack(); + } + break; +#endif +#ifdef F_JUMP + case F_JUMP: + COPY_SHORT(&offset, pc); + pc = current_prog->program + offset; + break; +#endif + case F_LE: + f_le(); + break; + case F_LSH: + f_lsh(); + break; + case F_LSH_EQ: + f_lsh_eq(); + break; + case F_MOD: + { + CHECK_TYPES(sp - 1, T_NUMBER, 1, instruction); + CHECK_TYPES(sp, T_NUMBER, 2, instruction); + if ((sp--)->u.number == 0) + error("Modulus by zero.\n"); + sp->u.number %= (sp+1)->u.number; + } + break; + case F_MOD_EQ: + f_mod_eq(); + break; + case F_MULTIPLY: + { + switch((sp-1)->type|sp->type) { + case T_NUMBER: + { + sp--; + sp->u.number *= (sp+1)->u.number; + break; + } + + case T_REAL: + { + sp--; + sp->u.real *= (sp+1)->u.real; + break; + } + + case T_NUMBER|T_REAL: + { + if ((--sp)->type == T_NUMBER) { + sp->type = T_REAL; + sp->u.real = sp->u.number * (sp+1)->u.real; + } + else sp->u.real *= (sp+1)->u.number; + break; + } + + case T_MAPPING: + { + mapping_t *m; + m = compose_mapping((sp-1)->u.map, sp->u.map, 1); + pop_2_elems(); + push_refed_mapping(m); + break; + } + + default: + { + if (!((sp-1)->type & (T_NUMBER|T_REAL|T_MAPPING))) + bad_argument(sp-1, T_NUMBER|T_REAL|T_MAPPING,1, instruction); + if (!(sp->type & (T_NUMBER|T_REAL|T_MAPPING))) + bad_argument(sp, T_NUMBER|T_REAL|T_MAPPING,2, instruction); + error("Args to * are not compatible.\n"); + } + } + } + break; + case F_MULT_EQ: + f_mult_eq(); + break; + case F_NE: + f_ne(); + break; + case F_NEGATE: + if (sp->type == T_NUMBER) { + sp->u.number = -sp->u.number; + sp->subtype = 0; + } else if (sp->type == T_REAL) + sp->u.real = -sp->u.real; + else + error("Bad argument to unary minus\n"); + break; + case F_NOT: + if (sp->type == T_NUMBER) { + sp->u.number = !sp->u.number; + sp->subtype = 0; + } else { + free_svalue(sp, "f_not"); + *sp = const0; + } + break; + case F_OR: + f_or(); + break; + case F_OR_EQ: + f_or_eq(); + break; + case F_PARSE_COMMAND: + f_parse_command(); + break; + case F_POP_VALUE: + pop_stack(); + break; + case F_POST_DEC: + DEBUG_CHECK(sp->type != T_LVALUE, + "non-lvalue argument to --\n"); + lval = sp->u.lvalue; + switch(lval->type) { + case T_NUMBER: + sp->type = T_NUMBER; + sp->u.number = lval->u.number--; + sp->subtype = 0; + break; + case T_REAL: + sp->type = T_REAL; + sp->u.real = lval->u.real--; + break; + case T_LVALUE_BYTE: + sp->type = T_NUMBER; + if (global_lvalue_byte.subtype == 0 && + *global_lvalue_byte.u.lvalue_byte == '\x1') + error("Strings cannot contain 0 bytes.\n"); + sp->u.number = (*global_lvalue_byte.u.lvalue_byte)--; + sp->subtype = 0; + break; + default: + error("-- of non-numeric argument\n"); + } + break; + case F_POST_INC: + DEBUG_CHECK(sp->type != T_LVALUE, + "non-lvalue argument to ++\n"); + lval = sp->u.lvalue; + switch (lval->type) { + case T_NUMBER: + sp->type = T_NUMBER; + sp->u.number = lval->u.number++; + sp->subtype = 0; + break; + case T_REAL: + sp->type = T_REAL; + sp->u.real = lval->u.real++; + break; + case T_LVALUE_BYTE: + if (global_lvalue_byte.subtype == 0 && + *global_lvalue_byte.u.lvalue_byte == (unsigned char)255) + error("Strings cannot contain 0 bytes.\n"); + sp->type = T_NUMBER; + sp->u.number = (*global_lvalue_byte.u.lvalue_byte)++; + sp->subtype = 0; + break; + default: + error("++ of non-numeric argument\n"); + } + break; + case F_GLOBAL_LVALUE: + STACK_INC; + sp->type = T_LVALUE; + sp->u.lvalue = find_value((int) (READ_GLOBAL_INDEX(pc) + + variable_index_offset)); + break; + case F_INDEX_LVALUE: + push_indexed_lvalue(0); + break; + case F_RINDEX_LVALUE: + push_indexed_lvalue(1); + break; + case F_NN_RANGE_LVALUE: + push_lvalue_range(0x00); + break; + case F_RN_RANGE_LVALUE: + push_lvalue_range(0x10); + break; + case F_RR_RANGE_LVALUE: + push_lvalue_range(0x11); + break; + case F_NR_RANGE_LVALUE: + push_lvalue_range(0x01); + break; + case F_NN_RANGE: + f_range(0x00); + break; + case F_RN_RANGE: + f_range(0x10); + break; + case F_NR_RANGE: + f_range(0x01); + break; + case F_RR_RANGE: + f_range(0x11); + break; + case F_NE_RANGE: + f_extract_range(0); + break; + case F_RE_RANGE: + f_extract_range(1); + break; + case F_RETURN_ZERO: + { + if (csp->framekind & FRAME_CATCH) { + free_svalue(&catch_value, "F_RETURN_ZERO"); + catch_value = const0; + while (csp->framekind & FRAME_CATCH) + pop_control_stack(); + csp->framekind |= FRAME_RETURNED_FROM_CATCH; + } + + /* + * Deallocate frame and return. + */ + pop_n_elems(sp - fp + 1); + STACK_INC; + + DEBUG_CHECK(sp != fp, "Bad stack at F_RETURN_ZERO\n"); + *sp = const0; + pop_control_stack(); +#ifdef TRACE + tracedepth--; + if (TRACEP(TRACE_RETURN)) { + do_trace("Return", "", ""); + if (TRACEHB) { + if (TRACETST(TRACE_ARGS)) { + static char msg[] = "with value: 0"; + + add_message(command_giver, msg, sizeof(msg)-1); + } + add_message(command_giver, "\n", 1); + } + } +#endif + /* The control stack was popped just before */ + if (csp[1].framekind & (FRAME_EXTERNAL | FRAME_RETURNED_FROM_CATCH)) + return; + } + break; + case F_RETURN: + { + svalue_t sv; + + if (csp->framekind & FRAME_CATCH) { + free_svalue(&catch_value, "F_RETURN"); + catch_value = const0; + while (csp->framekind & FRAME_CATCH) + pop_control_stack(); + csp->framekind |= FRAME_RETURNED_FROM_CATCH; + } + + if (sp - fp + 1) { + sv = *sp--; + /* + * Deallocate frame and return. + */ + pop_n_elems(sp - fp + 1); + STACK_INC; + DEBUG_CHECK(sp != fp, "Bad stack at F_RETURN\n"); + *sp = sv; /* This way, the same ref counts are + * maintained */ + } + pop_control_stack(); +#ifdef TRACE + tracedepth--; + if (TRACEP(TRACE_RETURN)) { + do_trace("Return", "", ""); + if (TRACEHB) { + if (TRACETST(TRACE_ARGS)) { + char msg[] = " with value: "; + + add_message(command_giver, msg, sizeof(msg)-1); + print_svalue(sp); + } + add_message(command_giver, "\n", 1); + } + } +#endif + /* The control stack was popped just before */ + if (csp[1].framekind & (FRAME_EXTERNAL | FRAME_RETURNED_FROM_CATCH)) + return; + break; + } + case F_RSH: + f_rsh(); + break; + case F_RSH_EQ: + f_rsh_eq(); + break; + case F_SSCANF: + f_sscanf(); + break; + case F_STRING: + LOAD_SHORT(offset, pc); + DEBUG_CHECK1(offset >= current_prog->num_strings, + "string %d out of range in F_STRING!\n", + offset); + push_shared_string(current_prog->strings[offset]); + break; + case F_SHORT_STRING: + DEBUG_CHECK1(EXTRACT_UCHAR(pc) >= current_prog->num_strings, + "string %d out of range in F_STRING!\n", + EXTRACT_UCHAR(pc)); + push_shared_string(current_prog->strings[EXTRACT_UCHAR(pc++)]); + break; + case F_SUBTRACT: + { + i = (sp--)->type; + switch (i | sp->type) { + case T_NUMBER: + sp->u.number -= (sp+1)->u.number; + break; + + case T_REAL: + sp->u.real -= (sp+1)->u.real; + break; + + case T_NUMBER | T_REAL: + if (sp->type == T_REAL) sp->u.real -= (sp+1)->u.number; + else { + sp->type = T_REAL; + sp->u.real = sp->u.number - (sp+1)->u.real; + } + break; + + case T_ARRAY: + { + /* + * subtract_array already takes care of + * destructed objects + */ + sp->u.arr = subtract_array(sp->u.arr, (sp+1)->u.arr); + break; + } + + default: + if (!((sp++)->type & (T_NUMBER|T_REAL|T_ARRAY))) + error("Bad left type to -.\n"); + else if (!(sp->type & (T_NUMBER|T_REAL|T_ARRAY))) + error("Bad right type to -.\n"); + else error("Arguments to - do not have compatible types.\n"); + } + break; + } + case F_SUB_EQ: + f_sub_eq(); + break; + case F_SIMUL_EFUN: + { + unsigned short sindex; + int num_args; + + LOAD_SHORT(sindex, pc); + num_args = EXTRACT_UCHAR(pc++) + num_varargs; + num_varargs = 0; + call_simul_efun(sindex, num_args); + } + break; + case F_SWITCH: + f_switch(); + break; + case F_XOR: + f_xor(); + break; + case F_XOR_EQ: + f_xor_eq(); + break; + case F_CATCH: + { + /* + * Compute address of next instruction after the CATCH + * statement. + */ + ((char *) &offset)[0] = pc[0]; + ((char *) &offset)[1] = pc[1]; + offset = pc + offset - current_prog->program; + pc += 2; + + do_catch(pc, offset); + if ((csp[1].framekind & (FRAME_EXTERNAL | FRAME_RETURNED_FROM_CATCH)) == + (FRAME_EXTERNAL | FRAME_RETURNED_FROM_CATCH)) { + return; + } + + break; + } + case F_END_CATCH: + { + free_svalue(&catch_value, "F_END_CATCH"); + catch_value = const0; + /* We come here when no longjmp() was executed */ + pop_control_stack(); + push_number(0); + return; /* return to do_catch */ + } + case F_TIME_EXPRESSION: + { + long sec, usec; + + IF_DEBUG(stack_in_use_as_temporary++); + get_usec_clock(&sec, &usec); + push_number(sec); + push_number(usec); + break; + } + case F_END_TIME_EXPRESSION: + { + long sec, usec; + + get_usec_clock(&sec, &usec); + usec = (sec - (sp - 1)->u.number) * 1000000 + (usec - sp->u.number); + sp -= 2; + IF_DEBUG(stack_in_use_as_temporary--); + push_number(usec); + break; + } + case F_TYPE_CHECK: + { + int type = sp->u.number; + pop_stack(); + if(sp->type != type && !(sp->type == T_NUMBER && sp->u.number == 0) && + !(sp->type == T_LVALUE)) + error("Trying to put %s in %s\n", type_name(sp->type), type_name(type)); + break; + } +#define Instruction (instruction + ONEARG_MAX) +#ifdef DEBUG +#define CALL_THE_EFUN goto call_the_efun +#else +#define CALL_THE_EFUN (*oefun_table[instruction])(); continue +#endif + case F_EFUN0: + st_num_arg = 0; + instruction = EXTRACT_UCHAR(pc++); + CALL_THE_EFUN; + case F_EFUN1: + st_num_arg = 1; + instruction = EXTRACT_UCHAR(pc++); + CHECK_TYPES(sp, instrs2[instruction].type[0], 1, Instruction); + CALL_THE_EFUN; + case F_EFUN2: + st_num_arg = 2; + instruction = EXTRACT_UCHAR(pc++); + CHECK_TYPES(sp - 1, instrs2[instruction].type[0], 1, Instruction); + CHECK_TYPES(sp, instrs2[instruction].type[1], 2, Instruction); + CALL_THE_EFUN; + case F_EFUN3: + st_num_arg = 3; + instruction = EXTRACT_UCHAR(pc++); + CHECK_TYPES(sp - 2, instrs2[instruction].type[0], 1, Instruction); + CHECK_TYPES(sp - 1, instrs2[instruction].type[1], 2, Instruction); + CHECK_TYPES(sp, instrs2[instruction].type[2], 3, Instruction); + CALL_THE_EFUN; + case F_EFUNV: + { + int num; + st_num_arg = EXTRACT_UCHAR(pc++) + num_varargs; + num_varargs = 0; + instruction = EXTRACT_UCHAR(pc++); + num = instrs2[instruction].min_arg; + for (i = 1; i <= num; i++) { + CHECK_TYPES(sp - st_num_arg + i, instrs2[instruction].type[i-1], i, Instruction); + } + CALL_THE_EFUN; + } + default: + /* optimized 1 arg efun */ + st_num_arg = 1; + CHECK_TYPES(sp, instrs[instruction].type[0], 1, instruction); +#ifndef DEBUG + (*ooefun_table[instruction])(); + continue; +#else + instruction -= ONEARG_MAX; + call_the_efun: + /* We have an efun. Execute it + */ + if (Instruction > NUM_OPCODES) { + fatal("Undefined instruction %s (%d)\n", + query_instr_name(Instruction), Instruction); + } + if (Instruction < BASE) { + fatal("No case for eoperator %s (%d)\n", + query_instr_name(Instruction), Instruction); + } + if (instrs2[instruction].ret_type == TYPE_NOVALUE) + expected_stack = sp - st_num_arg; + else + expected_stack = sp - st_num_arg + 1; + num_arg = st_num_arg; + + (*oefun_table[instruction]) (); + + if (expected_stack != sp) + fatal("Bad stack after efun. Instruction %d, num arg %d\n", + instruction, num_arg); + instruction += ONEARG_MAX; +#endif + } /* switch (instruction) */ + DEBUG_CHECK1(sp < fp + csp->num_local_variables - 1, + "Bad stack after evaluation. Instruction %d\n", + instruction); + } /* while (1) */ +} + +static void +do_catch (char * pc, unsigned short new_pc_offset) +{ + error_context_t econ; + + /* + * Save some global variables that must be restored separately after a + * longjmp. The stack will have to be manually popped all the way. + */ + if (!save_context(&econ)) + error("Can't catch too deep recursion error.\n"); + push_control_stack(FRAME_CATCH); + csp->pc = current_prog->program + new_pc_offset; +#if defined(DEBUG) || defined(TRACE_CODE) + csp->num_local_variables = (csp - 1)->num_local_variables; /* marion */ +#endif + + if (SETJMP(econ.context)) { + /* + * They did a throw() or error. That means that the control stack + * must be restored manually here. + */ + restore_context(&econ); + STACK_INC; + *sp = catch_value; + catch_value = const1; + + /* if it's too deep or max eval, we can't let them catch it */ + if (max_eval_error) { + pop_context(&econ); + error("Can't catch eval cost too big error.\n"); + } + if (0 && too_deep_error) {//can't we?? + pop_context(&econ); + error("Can't catch too deep recursion error.\n"); + } + } else { + assign_svalue(&catch_value, &const1); + /* note, this will work, since csp->extern_call won't be used */ + eval_instruction(pc); + } + pop_context(&econ); +} + +static program_t *ffbn_recurse (program_t * prog, char * name, + int * indexp, int * runtime_index) { + register int high = prog->num_functions_defined - 1; + register int low = 0, mid; + int ri; + char *p; + + /* Search our function table */ + while (high >= low) { + mid = (high + low) >> 1; + p = prog->function_table[mid].funcname; + if (name < p) high = mid - 1; + else if (name > p) low = mid + 1; + else { + ri = mid + prog->last_inherited; + + if (prog->function_flags[ri] & + (FUNC_UNDEFINED | FUNC_PROTOTYPE)) { + return 0; + } + + *indexp = mid; + *runtime_index = ri; + return prog; + } + } + + /* Search inherited function tables */ + mid = prog->num_inherited; + while (mid--) { + program_t *ret = ffbn_recurse(prog->inherit[mid].prog, name, indexp, + runtime_index); + if (ret) { + *runtime_index += prog->inherit[mid].function_index_offset; + return ret; + } + } + return 0; +} + +static program_t *ffbn_recurse2 (program_t * prog, const char * name, + int * indexp, int * runtime_index, + int * fio, int * vio) { + register int high = prog->num_functions_defined - 1; + register int low = 0, mid; + int ri; + char *p; + + /* Search our function table */ + while (high >= low) { + mid = (high + low) >> 1; + p = prog->function_table[mid].funcname; + if (name < p) high = mid - 1; + else if (name > p) low = mid + 1; + else { + ri = mid + prog->last_inherited; + + if (prog->function_flags[ri] & + (FUNC_UNDEFINED | FUNC_PROTOTYPE)) { + return 0; + } + + *indexp = mid; + *runtime_index = ri; + *fio = *vio = 0; + return prog; + } + } + + /* Search inherited function tables */ + mid = prog->num_inherited; + while (mid--) { + program_t *ret = ffbn_recurse2(prog->inherit[mid].prog, name, indexp, + runtime_index, fio, vio); + if (ret) { + *runtime_index += prog->inherit[mid].function_index_offset; + *fio += prog->inherit[mid].function_index_offset; + *vio += prog->inherit[mid].variable_index_offset; + return ret; + } + } + return 0; +} + +INLINE program_t * +find_function_by_name (object_t * ob, const char * name, + int * indexp, int * runtime_index) { + char *funname = findstring(name); + + if (!funname) return 0; + return ffbn_recurse(ob->prog, funname, indexp, runtime_index); +} + +INLINE_STATIC program_t * +find_function_by_name2 (object_t * ob, const char ** name, + int * indexp, int * runtime_index, + int * fio, int * vio) { + if (!(*name = findstring(*name))) return 0; + return ffbn_recurse2(ob->prog, *name, indexp, runtime_index, fio, vio); +} + + + +/* + * Apply a fun 'fun' to the program in object 'ob', with + * 'num_arg' arguments (already pushed on the stack). + * If the function is not found, search in the object pointed to by the + * inherit pointer. + * If the function name starts with '::', search in the object pointed out + * through the inherit pointer by the current object. The 'current_object' + * stores the base object, not the object that has the current function being + * evaluated. Thus, the variable current_prog will normally be the same as + * current_object->prog, but not when executing inherited code. Then, + * it will point to the code of the inherited object. As more than one + * object can be inherited, the call of function by index number has to + * be adjusted. The function number 0 in a superclass object must not remain + * number 0 when it is inherited from a subclass object. The same problem + * exists for variables. The global variables function_index_offset and + * variable_index_offset keep track of how much to adjust the index when + * executing code in the superclass objects. + * + * There is a special case when called from the heart beat, as + * current_prog will be 0. When it is 0, set current_prog + * to the 'ob->prog' sent as argument. + * + * Arguments are always removed from the stack. + * If the function is not found, return 0 and nothing on the stack. + * Otherwise, return 1, and a pushed return value on the stack. + * + * Note that the object 'ob' can be destructed. This must be handled by + * the caller of apply(). + * + * If the function failed to be called, then arguments must be deallocated + * manually ! (Look towards end of this function.) + */ + +#ifdef DEBUG +static char debug_apply_fun[30];/* For debugging */ +#endif + +#ifdef CACHE_STATS +unsigned int apply_low_call_others = 0; +unsigned int apply_low_cache_hits = 0; +unsigned int apply_low_slots_used = 0; +unsigned int apply_low_collisions = 0; +#endif + +typedef struct cache_entry_s { + program_t *oprogp; + program_t *progp; + function_t *funp; + unsigned short function_index_offset; + unsigned short variable_index_offset; +} cache_entry_t; + +static cache_entry_t cache[APPLY_CACHE_SIZE]; + +#ifdef DEBUGMALLOC_EXTENSIONS +void mark_apply_low_cache() { + int i; + for (i = 0; i < APPLY_CACHE_SIZE; i++) { + if (cache[i].funp && !cache[i].progp) + EXTRA_REF(BLOCK((char *)cache[i].funp))++; + if (cache[i].oprogp) + cache[i].oprogp->extra_ref++; + if (cache[i].progp) + cache[i].progp->extra_ref++; + } +} +#endif + +void check_co_args2 (unsigned short *types, int num_arg, const char *name, const char *ob_name){ + int argc = num_arg; + int exptype, i = 0; + do{ + argc--; + if((types[i] & DECL_MODS) == LOCAL_MOD_REF) + exptype = T_REF; + else + exptype = convert_type(types[i++]); + if(exptype == T_ANY) + continue; + + if((sp-argc)->type != exptype){ + char buf[1024]; + if((sp-argc)->type == T_NUMBER && !(sp-argc)->u.number) + continue; + sprintf(buf, "Bad argument %d in call to %s() in %s\nExpected: %s Got %s.\n", + num_arg - argc, name, ob_name, + type_name(exptype), type_name((sp-argc)->type)); +#ifdef CALL_OTHER_WARN + if(current_prog){ + const char *file; + int line; + find_line(pc, current_prog, &file, &line); + int prsave = pragmas; + pragmas &= ~PRAGMA_ERROR_CONTEXT; + smart_log(file, line, buf, 1); + pragmas = prsave; + } else + smart_log("driver", 0, buf, 1); +#else + error(buf); +#endif + } + } while (argc); +} + +void check_co_args (int num_arg, const program_t * prog, function_t * fun, int findex) { +#ifdef CALL_OTHER_TYPE_CHECK + if(num_arg != fun->num_arg){ + char buf[1024]; + //if(!current_prog) what do i need this for again? + // current_prog = master_ob->prog; + sprintf(buf, "Wrong number of arguments to %s in %s.\n", fun->funcname, prog->filename); +#ifdef CALL_OTHER_WARN + if(current_prog){ + const char *file; + int line; + int prsave = pragmas; + pragmas &= ~PRAGMA_ERROR_CONTEXT; + find_line(pc, current_prog, &file, &line); + smart_log(file, line, buf, 1); + pragmas = prsave; + } else + smart_log("driver", 0, buf, 1); +#else + error(buf); +#endif + } + + if(num_arg && prog->type_start && + prog->type_start[findex] != INDEX_START_NONE) + check_co_args2(&prog->argument_types[prog->type_start[findex]], num_arg, + fun->funcname, prog->filename); +#endif +} + + +int apply_low (const char * fun, object_t * ob, int num_arg) +{ + /* + * static memory is initialized to zero by the system or so Jacques says + * :) + */ + const char *sfun; + cache_entry_t *entry; + program_t *progp, *prog; + int ix; + POINTER_INT pfun, pprog; + static int cache_mask = APPLY_CACHE_SIZE - 1; + int local_call_origin = call_origin; + IF_DEBUG(control_stack_t *save_csp); + + if (!local_call_origin) + local_call_origin = ORIGIN_DRIVER; + call_origin = 0; + ob->time_of_ref = current_time; /* Used by the swapper */ + /* + * This object will now be used, and is thus a target for reset later on + * (when time due). + */ +#if !defined(NO_RESETS) && defined(LAZY_RESETS) + try_reset(ob); +#endif + if (ob->flags & O_DESTRUCTED) { + pop_n_elems(num_arg); + return 0; + } + + ob->flags &= ~O_RESET_STATE; +#ifdef DEBUG + strncpy(debug_apply_fun, fun, sizeof(debug_apply_fun)); + debug_apply_fun[sizeof debug_apply_fun - 1] = '\0'; +#endif + /* + * If there is a chain of objects shadowing, start with the first of + * these. + */ +#ifndef NO_SHADOWS + while (ob->shadowed && ob->shadowed != current_object && + (!(ob->shadowed->flags & O_DESTRUCTED))) + ob = ob->shadowed; + retry_for_shadow: +#endif + + progp = ob->prog; + DEBUG_CHECK(ob->flags & O_DESTRUCTED,"apply() on destructed object\n"); +#ifdef CACHE_STATS + apply_low_call_others++; +#endif + pfun = (POINTER_INT)fun; + pprog = (POINTER_INT)progp; + ix = (pfun >> 2)^(pfun >> (2 + APPLY_CACHE_BITS))^(pprog >> 2)^(pprog >> (2 + APPLY_CACHE_BITS)); + entry = &cache[ix & cache_mask]; + if (entry->oprogp == progp && + (entry->progp ? (strcmp(entry->funp->funcname, fun) == 0) : + strcmp((char *)entry->funp, fun) == 0)) { +#ifdef CACHE_STATS + apply_low_cache_hits++; +#endif + + /* if progp is zero, the cache is telling us the function isn't here*/ + if (entry->progp) { + int need; + function_t *funp = entry->funp; + int findex = (funp - entry->progp->function_table); + int funflags, runtime_index; + + runtime_index = findex + entry->progp->last_inherited + entry->function_index_offset; + funflags = entry->oprogp->function_flags[runtime_index]; + + need = (local_call_origin == ORIGIN_DRIVER ? DECL_HIDDEN : ((current_object == ob || local_call_origin == ORIGIN_INTERNAL) ? DECL_PROTECTED : DECL_PUBLIC)); + + if ((funflags & DECL_ACCESS) >= need) { + /* + * the cache will tell us in which program the function is, + * and where + */ + if(!(funflags & FUNC_VARARGS)) + check_co_args(num_arg, entry->progp, funp, findex); + + push_control_stack(FRAME_FUNCTION | FRAME_OB_CHANGE); + current_prog = entry->progp; + caller_type = local_call_origin; + csp->num_local_variables = num_arg; + function_index_offset = entry->function_index_offset; + variable_index_offset = entry->variable_index_offset; + + csp->fr.table_index = findex; +#ifdef PROFILE_FUNCTIONS + get_cpu_times(&(csp->entry_secs), &(csp->entry_usecs)); + current_prog->function_table[findex].calls++; +#endif + + if (funflags & FUNC_TRUE_VARARGS) + setup_varargs_variables(csp->num_local_variables, + funp->num_local, funp->num_arg); + else + setup_variables(csp->num_local_variables, + funp->num_local, funp->num_arg); +#ifdef TRACE + tracedepth++; + if (TRACEP(TRACE_CALL)) { + do_trace_call(findex); + } +#endif + DTRACE_PROBE3(fluffos, lpc__entry, ob->obname, fun, current_prog->filename); + previous_ob = current_object; + current_object = ob; + IF_DEBUG(save_csp = csp); + call_program(current_prog, funp->address); + + DEBUG_CHECK(save_csp - 1 != csp, + "Bad csp after execution in apply_low.\n"); + return 1; + } + } /* when we come here, the cache has told us + * that the function isn't defined in the + * object */ + } else { + int findex, runtime_index, fio, vio; + /* we have to search the function */ + + if (entry->oprogp) { + free_prog(&entry->oprogp); + entry->oprogp = 0; + } + if (entry->progp) { + free_prog(&entry->progp); + entry->progp = 0; + } else { + if (entry->funp){ + free_string((char *)entry->funp); + entry->funp = 0; + } + } + +#ifdef CACHE_STATS + if (!entry->funp) { + apply_low_slots_used++; + } else { + apply_low_collisions++; + } +#endif + sfun = fun; + prog = find_function_by_name2(ob, &sfun, &findex, &runtime_index, + &fio, &vio); + + if (prog) { + int need; + function_t *funp = &prog->function_table[findex]; + int funflags = ob->prog->function_flags[runtime_index]; + + need = (local_call_origin == ORIGIN_DRIVER ? DECL_HIDDEN : ((current_object == ob || local_call_origin == ORIGIN_INTERNAL) ? DECL_PROTECTED : DECL_PUBLIC)); + + if ((funflags & DECL_ACCESS) >= need) { + + if(!(funflags & FUNC_VARARGS)) + check_co_args(num_arg, prog, funp, findex); + + push_control_stack(FRAME_FUNCTION | FRAME_OB_CHANGE); + current_prog = prog; + caller_type = local_call_origin; + /* The searched function is found */ + entry->oprogp = ob->prog; + entry->funp = funp; + csp->fr.table_index = findex; +#ifdef PROFILE_FUNCTIONS + get_cpu_times(&(csp->entry_secs), &(csp->entry_usecs)); + current_prog->function_table[findex].calls++; +#endif + csp->num_local_variables = num_arg; + entry->variable_index_offset = variable_index_offset = vio; + entry->function_index_offset = function_index_offset = fio; + if (funflags & FUNC_TRUE_VARARGS) + setup_varargs_variables(csp->num_local_variables, + funp->num_local, + funp->num_arg); + else + setup_variables(csp->num_local_variables, + funp->num_local, + funp->num_arg); + entry->progp = current_prog; + /* previously, programs had an id_number so they + * didn't have be refed while in the cache. This is + * phenomenally stupid, since it wastes 4 + * bytes/program and 4 bytes/cache entry just to save + * an instruction or two. Actually, less, since + * updating the ref count is as quick, or quicker, + * than checking the id. + * + * The other solution is to clear the cache like the + * stack is cleared when objects destruct. However, that + * can be expensive, since the cache can be quite large. + * [the stack is typically quite small] + * + * This does have the side effect that checking refs no + * longer tells you if a program is inherited by any other + * program, but most uses can cope (see appropriate comments). + */ + reference_prog(entry->oprogp, "apply_low() cache [oprogp]"); + reference_prog(entry->progp, "apply_low() cache [progp]"); + previous_ob = current_object; + current_object = ob; + IF_DEBUG(save_csp = csp); + DTRACE_PROBE3(fluffos, lpc__entry, ob->obname, fun, current_prog->filename); + call_program(current_prog, funp->address); + + DEBUG_CHECK(save_csp - 1 != csp, + "Bad csp after execution in apply_low\n"); + /* + * Arguments and local variables are now removed. One + * resulting value is always returned on the stack. + */ + return 1; + } + } + + /* We have to mark a function not to be in the object */ + entry->oprogp = progp; + reference_prog(entry->oprogp, "apply_low() cache [oprogp miss]"); + if (sfun) { + ref_string(sfun); + entry->funp = (function_t *)sfun; + } else + entry->funp = (function_t *)make_shared_string(fun); + entry->progp = 0; + } +#ifndef NO_SHADOWS + if (ob->shadowing) { + /* + * This is an object shadowing another. The function was not + * found, but can maybe be found in the object we are shadowing. + */ + ob = ob->shadowing; + goto retry_for_shadow; + } +#endif + /* Failure. Deallocate stack. */ + pop_n_elems(num_arg); + return 0; +} + +/* + * Arguments are supposed to be + * pushed (using push_string() etc) before the call. A pointer to a + * 'svalue_t' will be returned. It will be a null pointer if the called + * function was not found. Otherwise, it will be a pointer to a static + * area in apply(), which will be overwritten by the next call to apply. + * Reference counts will be updated for this value, to ensure that no pointers + * are deallocated. + */ + +svalue_t *apply (const char * fun, object_t * ob, int num_arg, + int where) +{ + IF_DEBUG(svalue_t *expected_sp); + + tracedepth = 0; + call_origin = where; + +#ifdef TRACE + if (TRACEP(TRACE_APPLY)) { + static int inapply = 0; + if(!inapply){ + inapply = 1; + do_trace("Apply", "", "\n"); + inapply = 0; + } + } +#endif + IF_DEBUG(expected_sp = sp - num_arg); + if (apply_low(fun, ob, num_arg) == 0) + return 0; + free_svalue(&apply_ret_value, "sapply"); + apply_ret_value = *sp--; + DEBUG_CHECK(expected_sp != sp, + "Corrupt stack pointer.\n"); + return &apply_ret_value; +} + +/* Reason for the following 1. save cache space 2. speed :) */ +/* The following is to be called only from reset_object for */ +/* otherwise extra checks are needed - Sym */ + +void call___INIT (object_t * ob) +{ + program_t *progp; + function_t *cfp; + int num_functions; + IF_DEBUG(svalue_t *expected_sp); + IF_DEBUG(control_stack_t *save_csp); + + tracedepth = 0; + +#ifdef TRACE + if (TRACEP(TRACE_APPLY)) { + do_trace("Apply", "", "\n"); + } +#endif + + IF_DEBUG(expected_sp = sp); + + /* No try_reset here for obvious reasons :) */ + + ob->flags &= ~O_RESET_STATE; + + progp = ob->prog; + num_functions = progp->num_functions_defined; + if (!num_functions) return; + + /* ___INIT turns out to be always the last function */ + cfp = &progp->function_table[num_functions - 1]; + if (cfp->funcname[0] != APPLY___INIT_SPECIAL_CHAR) return; + push_control_stack(FRAME_FUNCTION | FRAME_OB_CHANGE); + current_prog = progp; + csp->fr.table_index = num_functions - 1; +#ifdef PROFILE_FUNCTIONS + get_cpu_times(&(csp->entry_secs), &(csp->entry_usecs)); + current_prog->function_table[num_functions - 1].calls++; +#endif + caller_type = ORIGIN_DRIVER; + csp->num_local_variables = 0; + + previous_ob = current_object; + + current_object = ob; + setup_new_frame(num_functions - 1 + progp->last_inherited); + IF_DEBUG(save_csp = csp); + call_program(current_prog, cfp->address); + + DEBUG_CHECK(save_csp - 1 != csp, + "Bad csp after execution in apply_low\n"); + sp--; + DEBUG_CHECK(expected_sp != sp, + "Corrupt stack pointer.\n"); +} + +/* + * this is a "safe" version of apply + * this allows you to have dangerous driver mudlib dependencies + * and not have to worry about causing serious bugs when errors occur in the + * applied function and the driver depends on being able to do something + * after the apply. (such as the ed exit function, and the net_dead function). + * note: this function uses setjmp() and thus is fairly expensive when + * compared to a normal apply(). Use sparingly. + */ + +svalue_t * +safe_apply (const char * fun, object_t * ob, int num_arg, int where) +{ + svalue_t *ret; + error_context_t econ; + + if (!save_context(&econ)) + return 0; + if (!SETJMP(econ.context)) { + if (!(ob->flags & O_DESTRUCTED)) { + ret = apply(fun, ob, num_arg, where); + } else ret = 0; + } else { + restore_context(&econ); + pop_n_elems(num_arg); /* saved state had args on stack already */ + ret = 0; + } + pop_context(&econ); + return ret; +} + +/* + * Call a function in all objects in a array. + */ +array_t *call_all_other (array_t * v, const char * func, int numargs) +{ + int size; + svalue_t *tmp, *vptr, *rptr; + array_t *ret; + object_t *ob; + int i; + + tmp = sp; + STACK_INC; + sp->type = T_ARRAY; + sp->u.arr = ret = allocate_array(size = v->size); + CHECK_STACK_OVERFLOW(numargs); + for (vptr = v->item, rptr = ret->item; size--; vptr++, rptr++) { + if (vptr->type == T_OBJECT) { + ob = vptr->u.ob; + } else if (vptr->type == T_STRING) { + ob = find_object(vptr->u.string); + if (!ob || !object_visible(ob)) + continue; + } else continue; + if (ob->flags & O_DESTRUCTED) + continue; + i = numargs; + while (i--) push_svalue(tmp - i); + call_origin = ORIGIN_CALL_OTHER; + if (apply_low(func, ob, numargs)) *rptr = *sp--; + } + sp--; + pop_n_elems(numargs); + return ret; +} + +char *function_name (program_t * prog, int findex) { + register int low, high, mid; + + /* Walk up the inheritance tree to the real definition */ + if (prog->function_flags[findex] & FUNC_ALIAS) { + findex = prog->function_flags[findex] & ~FUNC_ALIAS; + } + + while (prog->function_flags[findex] & FUNC_INHERITED) { + low = 0; + high = prog->num_inherited -1; + + while (high > low) { + mid = (low + high + 1) >> 1; + if (prog->inherit[mid].function_index_offset > findex) + high = mid -1; + else low = mid; + } + findex -= prog->inherit[low].function_index_offset; + prog = prog->inherit[low].prog; + } + + findex -= prog->last_inherited; + + return prog->function_table[findex].funcname; +} + +static void get_trace_details (const program_t * prog, int findex, + char ** fname, int * na, int * nl) { + function_t *cfp = &prog->function_table[findex]; + + *fname = cfp->funcname; + *na = cfp->num_arg; + *nl = cfp->num_local; +} + +/* + * This function is similar to apply(), except that it will not + * call the function, only return object name if the function exists, + * or 0 otherwise. If flag is nonzero, then we admit static and private + * functions exist. Note that if you actually intend to call the function, + * it's faster to just try to call it and check if apply() returns zero. + */ +const char *function_exists (const char * fun, object_t * ob, int flag) { + int findex, runtime_index; + program_t *prog; + int flags; + + DEBUG_CHECK(ob->flags & O_DESTRUCTED, + "function_exists() on destructed object\n"); + + if (fun[0] == APPLY___INIT_SPECIAL_CHAR) + return 0; + + prog = find_function_by_name(ob, fun, &findex, &runtime_index); + if (!prog) return 0; + + flags = ob->prog->function_flags[runtime_index]; + + if ((flags & FUNC_UNDEFINED) || (!flag && (flags & (DECL_PROTECTED|DECL_PRIVATE|DECL_HIDDEN)))) + return 0; + + return prog->filename; +} + +#ifndef NO_SHADOWS +/* + is_static: returns 1 if a function named 'fun' is declared 'static' in 'ob'; + 0 otherwise. +*/ +int is_static (const char *fun, object_t * ob) +{ + int findex; + int runtime_index; + program_t *prog; + int flags; + + DEBUG_CHECK(ob->flags & O_DESTRUCTED, + "is_static() on destructed object\n"); + + prog = find_function_by_name(ob, fun, &findex, &runtime_index); + if (!prog) return 0; + + flags = ob->prog->function_flags[runtime_index]; + if (flags & (FUNC_UNDEFINED|FUNC_PROTOTYPE)) + return 0; + if (flags & (DECL_PROTECTED|DECL_PRIVATE|DECL_HIDDEN)) + return 1; + + return 0; +} +#endif + +/* + * Call a function by object and index number. Used by parts of the + * driver which cache function numbers to optimize away function lookup. + * The return value is left on the stack. + * Currently: heart_beats, simul_efuns, master applies. + */ +void call_direct (object_t * ob, int offset, int origin, int num_arg) { + function_t *funp; + program_t *prog = ob->prog; + + ob->time_of_ref = current_time; + push_control_stack(FRAME_FUNCTION | FRAME_OB_CHANGE); + caller_type = origin; + csp->num_local_variables = num_arg; + current_prog = prog; + previous_ob = current_object; + current_object = ob; + funp = setup_new_frame(offset); + call_program(current_prog, funp->address); +} + +void translate_absolute_line (int abs_line, unsigned short * file_info, + int * ret_file, int * ret_line) { + unsigned short *p1, *p2; + int file; + int line_tmp = abs_line; + + /* two passes: first, find out what file we're interested in */ + p1 = file_info; + while (line_tmp > *p1) { + line_tmp -= *p1; + p1 += 2; + } + file = p1[1]; + + /* now correct the line number for that file */ + p2 = file_info; + while (p2 < p1) { + if (p2[1] == file) + line_tmp += *p2; + p2 += 2; + } + *ret_line = line_tmp; + *ret_file = file; +} + +static int find_line (char * p, const program_t * progp, + const char ** ret_file, int * ret_line ) +{ + int offset; + unsigned char *lns; + ADDRESS_TYPE abs_line; + int file_idx; + + *ret_file = 0; + *ret_line = 0; + + if (!progp) return 1; + if (progp == &fake_prog) return 2; + + if (!progp->line_info) + return 4; + + offset = p - progp->program; + DEBUG_CHECK2(offset > progp->program_size, + "Illegal offset %d in object /%s\n", offset, progp->filename); + + lns = progp->line_info; + while (offset > *lns) { + offset -= *lns; + lns += (sizeof(ADDRESS_TYPE) + 1); + } + +#if !defined(USE_32BIT_ADDRESSES) + COPY_SHORT(&abs_line, lns + 1); +#else + COPY4(&abs_line, lns + 1); +#endif + + translate_absolute_line(abs_line, &progp->file_info[2], + &file_idx, ret_line); + + *ret_file = progp->strings[file_idx - 1]; + return 0; +} + +static void get_explicit_line_number_info (char * p, const program_t * prog, + const char ** ret_file, int * ret_line) { + find_line(p, prog, ret_file, ret_line); + if (!(*ret_file)) + *ret_file = prog->filename; +} + +void get_line_number_info (const char ** ret_file, int * ret_line) +{ + find_line(pc, current_prog, ret_file, ret_line); + if (!(*ret_file)) + *ret_file = current_prog->filename; +} + +char* get_line_number (char * p, const program_t * progp) +{ + static char buf[256]; + int i; + const char *file; + int line; + + i = find_line(p, progp, &file, &line); + + switch (i) { + case 1: + strcpy(buf, "(no program)"); + return buf; + case 2: + *buf = 0; + return buf; + case 3: + strcpy(buf, "(compiled program)"); + return buf; + case 4: + strcpy(buf, "(no line numbers)"); + return buf; + case 5: + strcpy(buf, "(includes too deep)"); + return buf; + } + if (!file) + file = progp->filename; + sprintf(buf, "/%s:%d", file, line); + return buf; +} + +static void dump_trace_line (const char * fname, const char * pname, + const char * const obname, char * where) { + char line[256]; + char *end = EndOf(line); + char *p; + + p = strput(line, end, "Object: "); + if (obname[0] != '<' && p < end) + *p++ = '/'; + p = strput(p, end, obname); + p = strput(p, end, ", Program: "); + if (pname[0] != '<' && p < end) + *p++ = '/'; + p = strput(p, end, pname); + p = strput(p, end, "\n in "); + p = strput(p, end, fname); + p = strput(p, end, "() at "); + p = strput(p, end, where); + p = strput(p, end, "\n"); + debug_message(line); +} + +/* + * Write out a trace. If there is a heart_beat(), then return the + * object that had that heart beat. + */ +const char *dump_trace (int how) +{ + control_stack_t *p; + const char * ret = 0; + char *fname; + int num_arg = -1, num_local = -1; + +#if defined(ARGUMENTS_IN_TRACEBACK) || defined(LOCALS_IN_TRACEBACK) + svalue_t *ptr; + int i, context_saved = 0; + error_context_t econ; +#endif + + if (current_prog == 0) + return 0; + if (csp < &control_stack[0]) { + return 0; + } + +#if defined(ARGUMENTS_IN_TRACEBACK) || defined(LOCALS_IN_TRACEBACK) + /* + * save context here because svalue_to_string could generate an error + * which would throw us into a bad state in the error handler. this + * will allow us to recover cleanly. Don't bother if we're in a + * eval cost exceeded or too deep recursion state because (s)printf + * won't make the object_name() apply and save_context() might fail + * here (too deep recursion) + */ + if (!too_deep_error) { + if (!save_context(&econ)) + return 0; + context_saved = 1; + if (SETJMP(econ.context)) { + restore_context(&econ); + pop_context(&econ); + return 0; + } + } +#endif + +#ifdef TRACE_CODE + if (how) + last_instructions(); +#endif + debug_message("--- trace ---\n"); + for (p = &control_stack[0]; p < csp; p++) { + switch (p[0].framekind & FRAME_MASK) { + case FRAME_FUNCTION: + get_trace_details(p[1].prog, p[0].fr.table_index, + &fname, &num_arg, &num_local); + dump_trace_line(fname, p[1].prog->filename, p[1].ob->obname, + get_line_number(p[1].pc, p[1].prog)); + if (strcmp(fname, "heart_beat") == 0) + ret = p->ob ? p->ob->obname : 0; + break; + case FRAME_FUNP: + { + outbuffer_t tmpbuf; + svalue_t tmpval; + + tmpbuf.real_size = 0; + tmpbuf.buffer = 0; + + tmpval.type = T_FUNCTION; + tmpval.u.fp = p[0].fr.funp; + + svalue_to_string(&tmpval, &tmpbuf, 0, 0, 0); + + dump_trace_line(tmpbuf.buffer, p[1].prog->filename, p[1].ob->obname, + get_line_number(p[1].pc, p[1].prog)); + + FREE_MSTR(tmpbuf.buffer); + num_arg = p[0].fr.funp->f.functional.num_arg; + num_local = p[0].fr.funp->f.functional.num_local; + } + break; + case FRAME_FAKE: + dump_trace_line("", p[1].prog->filename, p[1].ob->obname, + get_line_number(p[1].pc, p[1].prog)); + num_arg = -1; + break; + case FRAME_CATCH: + dump_trace_line("", p[1].prog->filename, p[1].ob->obname, + get_line_number(p[1].pc, p[1].prog)); + num_arg = -1; + break; +#ifdef DEBUG + default: + fatal("unknown type of frame\n"); +#endif + } +#ifdef ARGUMENTS_IN_TRACEBACK + if (num_arg != -1) { + ptr = p[1].fp; + debug_message("arguments were ("); + for (i = 0; i < num_arg; i++) { + outbuffer_t outbuf; + + if (i) { + debug_message(","); + } + outbuf_zero(&outbuf); + svalue_to_string(&ptr[i], &outbuf, 0, 0, 0); + /* don't need to fix length here */ + debug_message("%s", outbuf.buffer); + FREE_MSTR(outbuf.buffer); + } + debug_message(")\n"); + } +#endif +#ifdef LOCALS_IN_TRACEBACK + if (num_local > 0 && num_arg != -1) { + ptr = p[1].fp + num_arg; + debug_message("locals were: "); + for (i = 0; i < num_local; i++) { + outbuffer_t outbuf; + + if (i) { + debug_message(","); + } + outbuf_zero(&outbuf); + svalue_to_string(&ptr[i], &outbuf, 0, 0, 0); + /* no need to fix length */ + debug_message("%s", outbuf.buffer); + FREE_MSTR(outbuf.buffer); + } + debug_message("\n"); + } +#endif + } + switch (p[0].framekind & FRAME_MASK) { + case FRAME_FUNCTION: + get_trace_details(current_prog, p[0].fr.table_index, + &fname, &num_arg, &num_local); + debug_message("'%15s' in '/%20s' ('/%20s') %s\n", + fname, current_prog->filename, current_object->obname, + get_line_number(pc, current_prog)); + break; + case FRAME_FUNP: + { + outbuffer_t tmpbuf; + svalue_t tmpval; + + tmpbuf.real_size = 0; + tmpbuf.buffer = 0; + + tmpval.type = T_FUNCTION; + tmpval.u.fp = p[0].fr.funp; + + svalue_to_string(&tmpval, &tmpbuf, 0, 0, 0); + + debug_message("'%s' in '/%20s' ('/%20s') %s\n", + tmpbuf.buffer, + current_prog->filename, current_object->obname, + get_line_number(pc, current_prog)); + FREE_MSTR(tmpbuf.buffer); + num_arg = p[0].fr.funp->f.functional.num_arg; + num_local = p[0].fr.funp->f.functional.num_local; + } + break; + case FRAME_FAKE: + debug_message("' ' in '/%20s' ('/%20s') %s\n", + current_prog->filename, current_object->obname, + get_line_number(pc, current_prog)); + num_arg = -1; + break; + case FRAME_CATCH: + debug_message("' CATCH' in '/%20s' ('/%20s') %s\n", + current_prog->filename, current_object->obname, + get_line_number(pc, current_prog)); + num_arg = -1; + break; + } +#ifdef ARGUMENTS_IN_TRACEBACK + if (num_arg != -1) { + debug_message("arguments were ("); + for (i = 0; i < num_arg; i++) { + outbuffer_t outbuf; + + if (i) { + debug_message(","); + } + outbuf_zero(&outbuf); + svalue_to_string(&fp[i], &outbuf, 0, 0, 0); + /* no need to fix length */ + debug_message("%s", outbuf.buffer); + FREE_MSTR(outbuf.buffer); + } + debug_message(")\n"); + } +#endif +#ifdef LOCALS_IN_TRACEBACK + if (num_local > 0 && num_arg != -1) { + ptr = fp + num_arg; + debug_message("locals were: "); + for (i = 0; i < num_local; i++) { + outbuffer_t outbuf; + + if (i) { + debug_message(","); + } + outbuf_zero(&outbuf); + svalue_to_string(&ptr[i], &outbuf, 0, 0, 0); + /* no need to fix length */ + debug_message("%s", outbuf.buffer); + FREE_MSTR(outbuf.buffer); + } + debug_message("\n"); + } +#endif + debug_message("--- end trace ---\n"); +#if defined(ARGUMENTS_IN_TRACEBACK) || defined(LOCALS_IN_TRACEBACK) + if (context_saved) + pop_context(&econ); +#endif + return ret; +} + +array_t *get_svalue_trace() +{ + control_stack_t *p; + array_t *v; + mapping_t *m; + const char *file; + int line; + char *fname; + int num_arg, num_local = -1; + +#if defined(ARGUMENTS_IN_TRACEBACK) || defined(LOCALS_IN_TRACEBACK) + svalue_t *ptr; + int i; +#endif + + if (current_prog == 0) + return &the_null_array; + if (csp < &control_stack[0]) { + return &the_null_array; + } + v = allocate_empty_array((csp - &control_stack[0]) + 1); + for (p = &control_stack[0]; p < csp; p++) { + m = allocate_mapping(6); + switch (p[0].framekind & FRAME_MASK) { + case FRAME_FUNCTION: + get_trace_details(p[1].prog, p[0].fr.table_index, + &fname, &num_arg, &num_local); + add_mapping_string(m, "function", fname); + break; + case FRAME_CATCH: + add_mapping_string(m, "function", "CATCH"); + num_arg = -1; + break; + case FRAME_FAKE: + add_mapping_string(m, "function", ""); + num_arg = -1; + break; + case FRAME_FUNP: + { + outbuffer_t tmpbuf; + svalue_t tmpval; + + tmpbuf.real_size = 0; + tmpbuf.buffer = 0; + + tmpval.type = T_FUNCTION; + tmpval.u.fp = p[0].fr.funp; + + svalue_to_string(&tmpval, &tmpbuf, 0, 0, 0); + + add_mapping_string(m, "function", tmpbuf.buffer); + FREE_MSTR(tmpbuf.buffer); + num_arg = p[0].fr.funp->f.functional.num_arg; + num_local = p[0].fr.funp->f.functional.num_local; + } + break; +#ifdef DEBUG + default: + fatal("unknown type of frame\n"); +#endif + } + add_mapping_malloced_string(m, "program", add_slash(p[1].prog->filename)); + add_mapping_object(m, "object", p[1].ob); + get_explicit_line_number_info(p[1].pc, p[1].prog, &file, &line); + add_mapping_malloced_string(m, "file", add_slash(file)); + add_mapping_pair(m, "line", line); +#ifdef ARGUMENTS_IN_TRACEBACK + if (num_arg != -1) { + array_t *v2; + + ptr = p[1].fp; + v2 = allocate_empty_array(num_arg); + for (i = 0; i < num_arg; i++) { + assign_svalue_no_free(&v2->item[i], &ptr[i]); + } + add_mapping_array(m, "arguments", v2); + v2->ref--; + } +#endif +#ifdef LOCALS_IN_TRACEBACK + if (num_local > 0 && num_arg != -1) { + array_t *v2; + + ptr = p[1].fp + num_arg; + v2 = allocate_empty_array(num_local); + for (i = 0; i < num_local; i++) { + assign_svalue_no_free(&v2->item[i], &ptr[i]); + } + add_mapping_array(m, "locals", v2); + v2->ref--; + } +#endif + v->item[(p - &control_stack[0])].type = T_MAPPING; + v->item[(p - &control_stack[0])].u.map = m; + } + m = allocate_mapping(6); + switch (p[0].framekind & FRAME_MASK) { + case FRAME_FUNCTION: + get_trace_details(current_prog, p[0].fr.table_index, + &fname, &num_arg, &num_local); + add_mapping_string(m, "function", fname); + break; + case FRAME_CATCH: + add_mapping_string(m, "function", "CATCH"); + num_arg = -1; + break; + case FRAME_FAKE: + add_mapping_string(m, "function", ""); + num_arg = -1; + break; + case FRAME_FUNP: + { + outbuffer_t tmpbuf; + svalue_t tmpval; + + tmpbuf.real_size = 0; + tmpbuf.buffer = 0; + + tmpval.type = T_FUNCTION; + tmpval.u.fp = p[0].fr.funp; + + svalue_to_string(&tmpval, &tmpbuf, 0, 0, 0); + add_mapping_string(m, "function", tmpbuf.buffer); + FREE_MSTR(tmpbuf.buffer); + num_arg = p[0].fr.funp->f.functional.num_arg; + num_local = p[0].fr.funp->f.functional.num_local; + } + break; + } + add_mapping_malloced_string(m, "program", add_slash(current_prog->filename)); + add_mapping_object(m, "object", current_object); + get_line_number_info(&file, &line); + add_mapping_malloced_string(m, "file", add_slash(file)); + add_mapping_pair(m, "line", line); +#ifdef ARGUMENTS_IN_TRACEBACK + if (num_arg != -1) { + array_t *v2; + + v2 = allocate_empty_array(num_arg); + for (i = 0; i < num_arg; i++) { + assign_svalue_no_free(&v2->item[i], &fp[i]); + } + add_mapping_array(m, "arguments", v2); + v2->ref--; + } +#endif +#ifdef LOCALS_IN_TRACEBACK + if (num_local > 0 && num_arg != -1) { + array_t *v2; + + v2 = allocate_empty_array(num_local); + for (i = 0; i < num_local; i++) { + assign_svalue_no_free(&v2->item[i], &fp[i + num_arg]); + } + add_mapping_array(m, "locals", v2); + v2->ref--; + } +#endif + v->item[(csp - &control_stack[0])].type = T_MAPPING; + v->item[(csp - &control_stack[0])].u.map = m; + /* return a reference zero array */ + v->ref--; + return v; +} + +char * get_line_number_if_any() +{ + if (current_prog) + return get_line_number(pc, current_prog); + return 0; +} + +#define SSCANF_ASSIGN_SVALUE_STRING(S) \ +arg->type = T_STRING; \ +arg->u.string = S; \ +arg->subtype = STRING_MALLOC; \ +arg--; \ +num_arg-- + +#define SSCANF_ASSIGN_SVALUE_NUMBER(N) \ +arg->type = T_NUMBER; \ +arg->subtype = 0; \ +arg->u.number = N; \ +arg--; \ +num_arg-- + +#define SSCANF_ASSIGN_SVALUE(T,U,V) \ +arg->type = T; \ +arg->U = V; \ +arg--; \ +num_arg-- + +/* arg points to the same place it used to */ +int inter_sscanf (svalue_t * arg, svalue_t * s0, svalue_t * s1, int num_arg) +{ + const char *fmt; /* Format description */ + const char *in_string; /* The string to be parsed. */ + int number_of_matches; + int skipme; /* Encountered a '*' ? */ + int base = 10; + long num; + const char *match; + char old_char; + const char *tmp; + + /* + * First get the string to be parsed. + */ + CHECK_TYPES(s0, T_STRING, 1, F_SSCANF); + in_string = s0->u.string; + + /* + * Now get the format description. + */ + CHECK_TYPES(s1, T_STRING, 2, F_SSCANF); + fmt = s1->u.string; + + /* + * Loop for every % or substring in the format. + */ + for (number_of_matches = 0; num_arg >= 0; number_of_matches++) { + while (*fmt) { + if (*fmt == '%') { + if (*++fmt == '%') { + if (*in_string++ != '%') return number_of_matches; + fmt++; + continue; + } + if (!*fmt) + error("Format string cannot end in '%%' in sscanf()\n"); + break; + } + if (*fmt++ != *in_string++) return number_of_matches; + } + + if (!*fmt) { + /* + * We have reached the end of the format string. If there are + * any chars left in the in_string, then we put them in the + * last variable (if any). + */ + if (*in_string && num_arg) { + number_of_matches++; + SSCANF_ASSIGN_SVALUE_STRING(string_copy(in_string, "sscanf")); + } + break; + } + DEBUG_CHECK(fmt[-1] != '%', "In sscanf, should be a %% now!\n"); + + if ((skipme = (*fmt == '*'))) fmt++; + else if (num_arg < 1 && *fmt != '%') { + /* + * Hmm ... maybe we should return number_of_matches here instead + * of an error + */ + error("Too few arguments to sscanf()\n"); + } + + switch (*fmt++) { + case 'x': + base = 16; + /* fallthrough */ + case 'd': + { + tmp = in_string; + num = strtol((char *)in_string, (char **)&in_string, base); + if (tmp == in_string) return number_of_matches; + if (!skipme) { + SSCANF_ASSIGN_SVALUE_NUMBER(num); + } + base = 10; + continue; + } + case 'f': + { + float tmp_num; + + tmp = in_string; + tmp_num = _strtof((char *)in_string, (char **)&in_string); + if (tmp == in_string)return number_of_matches; + if (!skipme) { + SSCANF_ASSIGN_SVALUE(T_REAL, u.real, tmp_num); + } + continue; + } + case '(': + { + struct regexp *reg; + + tmp = fmt; /* 1 after the ( */ + num = 1; + while (1) { + switch (*tmp) { + case '\\': + if (*++tmp) { + tmp++; + continue; + } + case '\0': + error("Bad regexp format: '%%%s' in sscanf format string\n", fmt); + case '(': + num++; + /* FALLTHROUGH */ + default: + tmp++; + continue; + case ')': + if (!--num) break; + tmp++; + continue; + } + { + int n = tmp - fmt; + char *buf = (char *)DXALLOC(n + 1, TAG_TEMPORARY, + "sscanf regexp"); + memcpy(buf, fmt, n); + buf[n] = 0; + regexp_user = EFUN_REGEXP; + reg = regcomp((unsigned char *)buf, 0); + FREE(buf); + if (!reg) error(regexp_error); + if (!regexec(reg, in_string) || (in_string != reg->startp[0])) { + FREE(reg); + return number_of_matches; + } + if (!skipme) { + n = *reg->endp - in_string; + buf = new_string(n, "sscanf regexp return"); + memcpy(buf, in_string, n); + buf[n] = 0; + SSCANF_ASSIGN_SVALUE_STRING(buf); + } + in_string = *reg->endp; + FREE((char *)reg); + fmt = ++tmp; + break; + } + } + continue; + } + case 's': + break; + default: + error("Bad type : '%%%c' in sscanf() format string\n", fmt[-1]); + } + + /* + * Now we have the string case. + */ + + /* + * First case: There were no extra characters to match. Then this is + * the last match. + */ + if (!*fmt) { + number_of_matches++; + if (!skipme) { + SSCANF_ASSIGN_SVALUE_STRING(string_copy(in_string, "sscanf")); + } + break; + } + /* + * If the next char in the format string is a '%' then we have to do + * some special checks. Only %d, %f, %x, %(regexp) and %% are allowed + * after a %s + */ + if (*fmt++ == '%') { + int skipme2; + + tmp = in_string; + if ((skipme2 = (*fmt == '*'))) fmt++; + if (num_arg < (!skipme + !skipme2) && *fmt != '%') + error("Too few arguments to sscanf().\n"); + + number_of_matches++; + + switch (*fmt++) { + case 's': + error("Illegal to have 2 adjacent %%s's in format string in sscanf()\n"); + case 'x': + do { + while (*tmp && (*tmp != '0')) tmp++; + if (*tmp == '0') { + if ((tmp[1] == 'x' || tmp[1] == 'X') && + uisxdigit(tmp[2])) break; + tmp += 2; + } + } while (*tmp); + break; + case 'd': + while (*tmp && !uisdigit(*tmp)) tmp++; + break; + case 'f': + while (*tmp && !uisdigit(*tmp) && + (*tmp != '.' || !uisdigit(tmp[1]))) tmp++; + break; + case '%': + while (*tmp && (*tmp != '%')) tmp++; + break; + case '(': + { + struct regexp *reg; + + tmp = fmt; + num = 1; + while (1) { + switch (*tmp) { + case '\\': + if (*++tmp) { + tmp++; + continue; + } + case '\0': + error("Bad regexp format : '%%%s' in sscanf format string\n", fmt); + case '(': + num++; + /* FALLTHROUGH */ + default: + tmp++; + continue; + + case ')': + if (!--num) break; + tmp++; + continue; + } + { + int n = tmp - fmt; + char *buf = (char *)DXALLOC(n + 1, TAG_TEMPORARY, + "sscanf regexp"); + memcpy(buf, fmt, n); + buf[n] = 0; + regexp_user = EFUN_REGEXP; + reg = regcomp((unsigned char *)buf, 0); + FREE(buf); + if (!reg) error(regexp_error); + if (!regexec(reg, in_string)) { + if (!skipme) { + SSCANF_ASSIGN_SVALUE_STRING(string_copy(in_string, "sscanf")); + } + FREE((char *)reg); + return number_of_matches; + } else { + if (!skipme) { + char *tmp2 = new_string(num = (*reg->startp - in_string), "inter_sscanf"); + memcpy(tmp2, in_string, num); + tmp2[num] = 0; + match = tmp2; + SSCANF_ASSIGN_SVALUE_STRING(match); + } + in_string = *reg->endp; + if (!skipme2) { + char *tmp2 = new_string(num = (*reg->endp - *reg->startp), "inter_sscanf"); + memcpy(tmp2, *reg->startp, num); + tmp2[num] = 0; + match = tmp2; + SSCANF_ASSIGN_SVALUE_STRING(match); + } + FREE((char *)reg); + } + fmt = ++tmp; + break; + } + } + continue; + } + + case 0: + error("Format string can't end in '%%'.\n"); + default: + error("Bad type : '%%%c' in sscanf() format string\n", fmt[-1]); + } + + if (!skipme) { + char *tmp2 = new_string(num = (tmp - in_string), "inter_sscanf"); + memcpy(tmp2, in_string, num); + tmp2[num] = 0; + match = tmp2; + SSCANF_ASSIGN_SVALUE_STRING(match); + } + if (!*(in_string = tmp)) return number_of_matches; + switch (fmt[-1]) { + case 'x': + base = 16; + case 'd': + { + num = strtol((char *)in_string, (char **)&in_string, base); + /* We already knew it would be matched - Sym */ + if (!skipme2) { + SSCANF_ASSIGN_SVALUE_NUMBER(num); + } + base = 10; + continue; + } + case 'f': + { + float tmp_num = _strtof((char *)in_string, (char **)&in_string); + if (!skipme2) { + SSCANF_ASSIGN_SVALUE(T_REAL, u.real, tmp_num); + } + continue; + } + case '%': + in_string++; + continue; /* on the big for loop */ + } + } + if ((tmp = strchr(fmt, '%')) != NULL) num = tmp - fmt + 1; + else { + tmp = fmt + (num = strlen(fmt)); + num++; + } + + old_char = *--fmt; + match = in_string; + + /* This loop would be even faster if it used replace_string's skiptable + algorithm. Maybe that algorithm should be lifted so it can be + used in strsrch as well has here, etc? */ + while (*in_string) { + if ((*in_string == old_char) && !strncmp(in_string, fmt, num)) { + /* + * Found a match ! + */ + if (!skipme) { + char *newmatch; + + newmatch = new_string(skipme = (in_string - match), "inter_sscanf"); + memcpy(newmatch, match, skipme); + newmatch[skipme] = 0; + SSCANF_ASSIGN_SVALUE_STRING(newmatch); + } + in_string += num; + fmt = tmp; /* advance fmt to next % */ + break; + } + in_string++; + } + if (fmt == tmp) /* If match, then do continue. */ + continue; + + /* + * No match was found. Then we stop here, and return the result so + * far ! + */ + break; + } + return number_of_matches; +} + +/* dump # of times each efun has been used */ +#ifdef OPCPROF +void opcdump (const char *tfn) +{ + int i, len, limit; + char tbuf[SMALL_STRING_SIZE]; + const char *fn; + FILE *fp; + + if ((len = strlen(tfn)) >= (SMALL_STRING_SIZE - 7)) { + error("Path '%s' too long.\n", tfn); + return; + } + strcpy(tbuf, tfn); + strcpy(tbuf + len, ".efun"); + fn = check_valid_path(tbuf, current_object, "opcprof", 1); + if (!fn) { + error("Invalid path '%s' for writing.\n", tbuf); + return; + } + fp = fopen(fn, "w"); + if (!fp) { + error("Unable to open %s.\n", fn); + return; + } + limit = sizeof(opc_efun) / sizeof(opc_t); + for (i = 0; i < limit; i++) { + fprintf(fp, "%-30s: %10d\n", opc_efun[i].name, opc_efun[i].count); + } + fclose(fp); + + strcpy(tbuf, tfn); + strcpy(tbuf + len, ".eoper"); + fn = check_valid_path(tbuf, current_object, "opcprof", 1); + if (!fn) { + error("Invalid path '%s' for writing.\n", tbuf); + return; + } + fp = fopen(fn, "w"); + if (!fp) { + error("Unable to open %s for writing.\n", fn); + return; + } + for (i = 0; i < BASE; i++) { + fprintf(fp, "%-30s: %10d\n", + query_instr_name(i), opc_eoper[i]); + } + fclose(fp); +} +#endif + +/* dump # of times each efun has been used */ +#ifdef OPCPROF_2D +typedef struct { + int op1, op2; + int num_calls; +} sort_elem_t; + +int sort_elem_cmp (sort_elem_t * se1, sort_elem_t * se2) { + return se2->num_calls - se1->num_calls; +} + +void opcdump (char * tfn) +{ + int ind, i, j, len; + char tbuf[SMALL_STRING_SIZE], *fn; + FILE *fp; + sort_elem_t ops[(BASE + 1) * (BASE + 1)]; + + if ((len = strlen(tfn)) >= (SMALL_STRING_SIZE - 10)) { + error("Path '%s' too long.\n", tfn); + return; + } + strcpy(tbuf, tfn); + strcpy(tbuf + len, ".eop-2d"); + fn = check_valid_path(tbuf, current_object, "opcprof", 1); + if (!fn) { + error("Invalid path '%s' for writing.\n", tbuf); + return; + } + fp = fopen(fn, "w"); + if (!fp) { + error("Unable to open %s for writing.\n", fn); + return; + } + for (i = 0; i <= BASE; i++) { + for (j = 0; j <= BASE; j++) { + ind = i * (BASE + 1) + j; + ops[ind].num_calls = opc_eoper_2d[i][j]; + ops[ind].op1 = i; + ops[ind].op2 = j; + } + } + quickSort((char *) ops, (BASE + 1) * (BASE + 1), sizeof(sort_elem_t), + sort_elem_cmp); + for (i = 0; i < (BASE + 1) * (BASE + 1); i++) { + if (ops[i].num_calls) + fprintf(fp, "%-30s %-30s: %10d\n", query_instr_name(ops[i].op1), + query_instr_name(ops[i].op2), ops[i].num_calls); + } + fclose(fp); +} +#endif + +/* + * Reset the virtual stack machine. + */ +void reset_machine (int first) +{ + csp = control_stack - 1; + if (first) + sp = &start_of_stack[-1]; + else { + pop_n_elems(sp - start_of_stack + 1); + IF_DEBUG(stack_in_use_as_temporary = 0); + } +} + +#ifdef TRACE_CODE +static char *get_arg (int a, int b) +{ + static char buff[10]; + char *from, *to; + + from = previous_pc[a]; + to = previous_pc[b]; + if (to - from < 2) + return ""; + if (to - from == 2) { + sprintf(buff, "%d", from[1]); + return buff; + } + if (to - from == 3) { + short arg; + + COPY_SHORT(&arg, from + 1); + sprintf(buff, "%d", arg); + return buff; + } + if (to - from == 5) { + int arg; + + COPY_INT(&arg, from + 1); + sprintf(buff, "%d", arg); + return buff; + } + return ""; +} + +int last_instructions() +{ + int i; + + debug_message("Recent instruction trace:\n"); + i = last; + do { + if (previous_instruction[i] != 0) + debug_message("%6x: %3d %8s %-25s (%d)\n", previous_pc[i], + previous_instruction[i], + get_arg(i, (i + 1) % + (sizeof previous_instruction / sizeof(int))), + query_instr_name(previous_instruction[i]), + stack_size[i] + 1); + i = (i + 1) % (sizeof previous_instruction / sizeof(int)); + } while (i != last); + return last; +} + +#endif /* TRACE_CODE */ + + +#ifdef TRACE +/* Generate a debug message to the user */ +void do_trace (const char * msg, const char * fname, const char * post) +{ + const char *objname; + + if (!TRACEHB) + return; + objname = TRACETST(TRACE_OBJNAME) ? (current_object && current_object->obname ? current_object->obname : "??") : ""; + add_vmessage(command_giver, "*** %d %*s %s %s %s%s", tracedepth, tracedepth, "", msg, objname, fname, post); +} +#endif + +/* + * When an object is destructed, all references to it must be removed + * from the stack. + */ +void remove_object_from_stack (object_t * ob) +{ + svalue_t *svp; + + for (svp = start_of_stack; svp <= sp; svp++) { + if (svp->type != T_OBJECT) + continue; + if (svp->u.ob != ob) + continue; + free_object(&svp->u.ob, "remove_object_from_stack"); + svp->type = T_NUMBER; + svp->u.number = 0; + } +} + +int strpref (const char * p, const char * s) +{ + while (*p) + if (*p++ != *s++) + return 0; + return 1; +} + +static float _strtof (char * nptr, char ** endptr) +{ + register char *s = nptr; + register float acc; + register int neg, c, any, divv; + + divv = 1; + neg = 0; + /* + * Skip white space and pick up leading +/- sign if any. + */ + do { + c = *s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else if (c == '+') + c = *s++; + + for (acc = 0, any = 0;; c = *s++) { + if (isdigit(c)) + c -= '0'; + else if ((divv == 1) && (c == '.')) { + divv = 10; + continue; + } else + break; + if (divv == 1) { + acc *= (float) 10; + acc += (float) c; + } else { + acc += (float) c / (float) divv; + divv *= 10; + } + any = 1; + } + + if (neg) + acc = -acc; + + if (endptr != 0) + *endptr = any ? s - 1 : (char *) nptr; + + return acc; +} + +#ifdef DEBUGMALLOC_EXTENSIONS +void mark_stack() { + svalue_t *sv; + + for (sv = start_of_stack; sv <= sp; sv++) mark_svalue(sv); +} +#endif + +/* Be careful. This assumes there will be a frame pushed right after this, + as we use econ->save_csp + 1 to restore */ +int save_context (error_context_t * econ) { + if (csp == &control_stack[CFG_MAX_CALL_DEPTH - 1]) { + /* Attempting to push the frame will give Too deep recursion. + fail now. */ + return 0; + } + econ->save_sp = sp; + econ->save_csp = csp; + econ->save_cgsp = cgsp; + econ->save_context = current_error_context; + + current_error_context = econ; + return 1; +} + +void pop_context (error_context_t * econ) { + current_error_context = econ->save_context; +} + +/* can the error handler do this ? */ +void restore_context (error_context_t * econ) { + ref_t *refp; +#ifdef PACKAGE_DWLIB + extern int _in_reference_allowed; + _in_reference_allowed = 0; +#endif + /* unwind the command_giver stack to the saved position */ + + while(csp > econ->save_csp) + pop_control_stack(); + + while (cgsp != econ->save_cgsp) + restore_command_giver(); + DEBUG_CHECK(csp < econ->save_csp, "csp is below econ->csp before unwinding.\n"); + + + pop_n_elems(sp - econ->save_sp); + refp = global_ref_list; + while (refp) { + if (refp->csp >= csp) { + ref_t *ref = refp; + refp = refp->next; + kill_ref(ref); + } else + refp = refp->next; + } +} + diff --git a/fluffos-2.23-ds03/interpret.h b/fluffos-2.23-ds03/interpret.h new file mode 100644 index 0000000..16465f7 --- /dev/null +++ b/fluffos-2.23-ds03/interpret.h @@ -0,0 +1,391 @@ +/* interpret.h */ + +/* It is usually better to include "lpc_incl.h" instead of including this + directly */ + +#ifndef INTERPRET_H +#define INTERPRET_H + +#define PUSH_STRING (0 << 6) +#define PUSH_NUMBER (1 << 6) +#define PUSH_GLOBAL (2 << 6) +#define PUSH_LOCAL (3 << 6) + +#define PUSH_WHAT (3 << 6) +#define PUSH_MASK (0xff ^ (PUSH_WHAT)) + +#define SWITCH_CASE_SIZE (2 + sizeof(char *)) + +/* Trace defines */ +#ifdef TRACE +# define TRACE_CALL 1 +# define TRACE_CALL_OTHER 2 +# define TRACE_RETURN 4 +# define TRACE_ARGS 8 +# define TRACE_EXEC 16 +# define TRACE_HEART_BEAT 32 +# define TRACE_APPLY 64 +# define TRACE_OBJNAME 128 +# define TRACETST(b) (command_giver->interactive->trace_level & (b)) +# define TRACEP(b) \ + (command_giver && command_giver->interactive && TRACETST(b) && \ + (command_giver->interactive->trace_prefix == 0 || \ + (current_object && strpref(command_giver->interactive->trace_prefix, \ + current_object->obname))) ) +# define TRACEHB (current_heart_beat == 0 || (command_giver->interactive->trace_level & TRACE_HEART_BEAT)) +#endif + +#define EXTRACT_UCHAR(p) (*(unsigned char *)(p)) + +/* GCC's optimiser makes a reasonable job of optimising the READ_USHORT macro. + * -- Qwer + */ + +#define READ_UCHAR(p) (*(unsigned char *) (p++)) +#define READ_USHORT(p) (p++, p++, *((unsigned short *) (p - 2))) + +/* + * Control stack element. + * 'prog' is usually same as 'ob->prog' (current_object), except when + * when the current function is defined by inheritance. + * The pointer, csp, will point to the values that will be used at return. + */ +#define FRAME_FUNCTION 0 +#define FRAME_FUNP 1 +#define FRAME_CATCH 2 +#define FRAME_FAKE 3 +#define FRAME_MASK 3 + +#define FRAME_OB_CHANGE 4 +#define FRAME_EXTERNAL 8 + +#define FRAME_RETURNED_FROM_CATCH 16 +struct defer_list{ + struct defer_list *next; + svalue_t func; + svalue_t tp; +}; +typedef struct control_stack_s { +#ifdef PROFILE_FUNCTIONS + unsigned long entry_secs, entry_usecs; +#endif + union { + long table_index; + funptr_t *funp; + } fr; + object_t *ob; /* Current object */ + object_t *prev_ob; /* Save previous object */ + program_t *prog; /* Current program */ + char *pc; + svalue_t *fp; + struct defer_list *defers; + int num_local_variables; /* Local + arguments */ + int function_index_offset; /* Used when executing functions in inherited + * programs */ + int variable_index_offset; /* Same */ + short caller_type; /* was this a locally called function? */ + short framekind; +} control_stack_t; + +typedef struct { + object_t *ob; + union { + funptr_t *fp; + const char *str; + } f; + int narg; + svalue_t *args; +} function_to_call_t; + +typedef struct error_context_s { + jmp_buf context; + control_stack_t *save_csp; + svalue_t *save_sp; + object_t **save_cgsp; + struct error_context_s *save_context; +} error_context_t; + +typedef struct { + function_t *func; + int index; +} function_lookup_info_t; + +#define IS_ZERO(x) (!(x) || (((x)->type == T_NUMBER) && ((x)->u.number == 0))) +#define IS_UNDEFINED(x) (!(x) || (((x)->type == T_NUMBER) && \ + ((x)->subtype == T_UNDEFINED) && ((x)->u.number == 0))) + +#define CHECK_TYPES(val, t, arg, inst) \ + if (!((val)->type & (t))) bad_argument(val, t, arg, inst); + +/* Beek - add some sanity to joining strings */ +/* add to an svalue */ +#define EXTEND_SVALUE_STRING(x, y, z) \ + SAFE( char *ess_res; \ + int ess_len; \ + int ess_r; \ + ess_len = (ess_r = SVALUE_STRLEN(x)) + strlen(y); \ + if (ess_len > MAX_STRING_LENGTH) \ + error("Maximum string length exceeded in concatenation.\n"); \ + if ((x)->subtype == STRING_MALLOC && MSTR_REF((x)->u.string) == 1) { \ + ess_res = (char *) extend_string((x)->u.string, ess_len); \ + if (!ess_res) fatal("Out of memory!\n"); \ + strcpy(ess_res + ess_r, (y)); \ + } else { \ + ess_res = new_string(ess_len, z); \ + strcpy(ess_res, (x)->u.string); \ + strcpy(ess_res + ess_r, (y)); \ + free_string_svalue(x); \ + (x)->subtype = STRING_MALLOC; \ + } \ + (x)->u.string = ess_res; \ + ) + +/* + string svalue */ +#define SVALUE_STRING_ADD_LEFT(y, z) \ + SAFE( char *pss_res; int pss_r; int pss_len; \ + pss_len = SVALUE_STRLEN(sp) + (pss_r = strlen(y)); \ + if (pss_len > MAX_STRING_LENGTH) \ + error("Maximum string length exceeded in concatenation.\n"); \ + pss_res = new_string(pss_len, z); \ + strcpy(pss_res, y); \ + strcpy(pss_res + pss_r, sp->u.string); \ + free_string_svalue(sp--); \ + sp->type = T_STRING; \ + sp->u.string = pss_res; \ + sp->subtype = STRING_MALLOC; \ + ) + +/* basically, string + string; faster than using extend b/c of SVALUE_STRLEN */ +#define SVALUE_STRING_JOIN(x, y, z) \ + SAFE( char *ssj_res; int ssj_r; int ssj_len; \ + ssj_r = SVALUE_STRLEN(x); \ + ssj_len = ssj_r + SVALUE_STRLEN(y); \ + if (ssj_len > MAX_STRING_LENGTH) \ + error("Maximum string length exceeded in concatenation.\n"); \ + if ((x)->subtype == STRING_MALLOC && MSTR_REF((x)->u.string) == 1) { \ + ssj_res = (char *) extend_string((x)->u.string, ssj_len); \ + if (!ssj_res) fatal("Out of memory!\n"); \ + (void) strcpy(ssj_res + ssj_r, (y)->u.string); \ + free_string_svalue(y); \ + } else { \ + ssj_res = (char *) new_string(ssj_len, z); \ + strcpy(ssj_res, (x)->u.string); \ + strcpy(ssj_res + ssj_r, (y)->u.string); \ + free_string_svalue(y); \ + free_string_svalue(x); \ + (x)->subtype = STRING_MALLOC; \ + } \ + (x)->u.string = ssj_res; \ + ) + +/* macro calls */ +#define call_program(prog, offset) \ + eval_instruction(prog->program + offset) + +#ifdef DEBUG +#define free_svalue(x,y) int_free_svalue(x,y) +#else +#define free_svalue(x,y) int_free_svalue(x) +#endif + +#define CHECK_STACK_OVERFLOW(x) if (sp + (x) >= end_of_stack) SAFE( too_deep_error = 1; error("stack overflow"); ) +#define STACK_INC SAFE( CHECK_STACK_OVERFLOW(1); sp++; ) + +#define push_svalue(x) SAFE( \ + STACK_INC;\ + assign_svalue_no_free(sp, x);\ + ) +#define put_number(x) SAFE( \ + sp->type = T_NUMBER;\ + sp->subtype = 0;\ + sp->u.number = (x);\ + ) +#define put_buffer(x) SAFE( \ + sp->type = T_BUFFER;\ + sp->u.buf = (x);\ + ) +#define put_undested_object(x) SAFE(\ + sp->type = T_OBJECT;\ + sp->u.ob = (x);\ + ) +#define put_object(x) SAFE(\ + if (!(x) || (x)->flags & O_DESTRUCTED) *sp = const0u;\ + else put_undested_object(x);\ + ) +#define put_unrefed_undested_object(x, y) SAFE(\ + sp->type = T_OBJECT;\ + sp->u.ob = (x);\ + add_ref((x), y);\ + ) +#define put_unrefed_object(x,y) SAFE(\ + if (!(x) || (x)->flags & O_DESTRUCTED) *sp = const0u;\ + else put_unrefed_undested_object(x,y);\ + ) +/* see comments on push_constant_string */ +#define put_constant_string(x) SAFE(\ + sp->type = T_STRING;\ + sp->subtype = STRING_SHARED;\ + sp->u.string = make_shared_string(x);\ + ) +#define put_malloced_string(x) SAFE(\ + sp->type = T_STRING;\ + sp->subtype = STRING_MALLOC;\ + sp->u.string = (x);\ + ) +#define put_array(x) SAFE(\ + sp->type = T_ARRAY;\ + sp->u.arr = (x);\ + ) +#define put_shared_string(x) SAFE(\ + sp->type = T_STRING;\ + sp->subtype = STRING_SHARED;\ + sp->u.string = (x);\ + ) + +#define FOREACH_LEFT_GLOBAL 1 +#define FOREACH_RIGHT_GLOBAL 2 +#define FOREACH_REF 4 +#define FOREACH_MAPPING 8 + +extern program_t *current_prog; +extern short caller_type; +extern char *pc; +extern svalue_t *sp; +extern svalue_t *fp; +extern svalue_t *end_of_stack; +extern svalue_t catch_value; +extern control_stack_t control_stack[CFG_MAX_CALL_DEPTH+5]; +extern control_stack_t *csp; +extern int too_deep_error; +extern int max_eval_error; +extern int function_index_offset; +extern int variable_index_offset; +extern unsigned int apply_low_call_others; +extern unsigned int apply_low_cache_hits; +extern unsigned int apply_low_slots_used; +extern unsigned int apply_low_collisions; +extern int simul_efun_is_loading; +extern program_t fake_prog; +extern svalue_t global_lvalue_byte; +extern int num_varargs; +extern int st_num_arg; +extern svalue_t const0; +extern svalue_t const1; +extern svalue_t const0u; +extern svalue_t apply_ret_value; +extern ref_t *global_ref_list; +extern int lv_owner_type; +extern refed_t *lv_owner; + +void kill_ref (ref_t *); +ref_t *make_ref (void); + +void init_interpreter (void); +void call_direct (object_t *, int, int, int); +void eval_instruction (char *p); +INLINE void assign_svalue (svalue_t *, svalue_t *); +INLINE void assign_svalue_no_free (svalue_t *, svalue_t *); +INLINE void copy_some_svalues (svalue_t *, svalue_t *, int); +INLINE void transfer_push_some_svalues (svalue_t *, int); +INLINE void push_some_svalues (svalue_t *, int); +#ifdef DEBUG +INLINE void int_free_svalue (svalue_t *, const char *); +#else +INLINE void int_free_svalue (svalue_t *); +#endif +INLINE void free_string_svalue (svalue_t *); +INLINE void free_some_svalues (svalue_t *, int); +INLINE void push_object (object_t *); +INLINE void push_number (long); +INLINE void push_real (float); +INLINE void push_undefined (void); +INLINE void copy_and_push_string (const char *); +INLINE void share_and_push_string (const char *); +INLINE void push_array (array_t *); +INLINE void push_refed_array (array_t *); +#ifndef NO_BUFFER_TYPE +INLINE void push_buffer (buffer_t *); +INLINE void push_refed_buffer (buffer_t *); +#endif +INLINE void push_mapping (mapping_t *); +INLINE void push_refed_mapping (mapping_t *); +INLINE void push_class (array_t *); +INLINE void push_refed_class (array_t *); +INLINE void push_malloced_string (const char *); +INLINE void push_shared_string (const char *); +INLINE void push_constant_string (const char *); +INLINE void pop_stack (void); +INLINE void pop_n_elems (int); +INLINE void pop_2_elems (void); +INLINE void pop_3_elems (void); +INLINE function_t *setup_inherited_frame (int); +INLINE program_t *find_function_by_name (object_t *, const char *, int *, int *); +char *function_name (program_t *, int); +void remove_object_from_stack (object_t *); +void setup_fake_frame (funptr_t *); +void remove_fake_frame (void); +void push_indexed_lvalue (int); +void setup_variables (int, int, int); + +void process_efun_callback (int, function_to_call_t *, int); +svalue_t *call_efun_callback (function_to_call_t *, int); +svalue_t *safe_call_efun_callback (function_to_call_t *, int); +const char *type_name (int c); +void bad_arg (int, int); +void bad_argument (svalue_t *, int, int, int); +void check_for_destr (array_t *); +int is_static (const char *, object_t *); +int apply_low (const char *, object_t *, int); +svalue_t *apply (const char *, object_t *, int, int); +svalue_t *call_function_pointer (funptr_t *, int); +svalue_t *safe_call_function_pointer (funptr_t *, int); +svalue_t *safe_apply (const char *, object_t *, int, int); +void call___INIT (object_t *); +array_t *call_all_other (array_t *, const char *, int); +const char *function_exists (const char *, object_t *, int); +void call_function (program_t *, int); +void mark_apply_low_cache (void); +void translate_absolute_line (int, unsigned short *, int *, int *); +char *add_slash (const char * const); +int strpref (const char *, const char *); +array_t *get_svalue_trace (void); +void do_trace (const char *, const char *, const char *); +const char *dump_trace (int); +void opcdump (const char *); +int inter_sscanf (svalue_t *, svalue_t *, svalue_t *, int); +char * get_line_number_if_any (void); +char *get_line_number (char *, const program_t *); +void get_line_number_info (const char **, int *); +void get_version (char *); +void reset_machine (int); +void unlink_string_svalue (svalue_t *); +void copy_lvalue_range (svalue_t *); +void assign_lvalue_range (svalue_t *); +void debug_perror (const char *, const char *); + + + +#ifndef NO_SHADOWS +int validate_shadowing (object_t *); +#endif + +#if !defined(NO_RESETS) && defined(LAZY_RESETS) +void try_reset (object_t *); +#endif + +void pop_context (error_context_t *); +void restore_context (error_context_t *); +int save_context (error_context_t *); + +void pop_control_stack (void); +INLINE function_t *setup_new_frame (int); +INLINE void push_control_stack (int); + +void break_point (void); + +#ifdef DEBUGMALLOC_EXTENSIONS +void mark_svalue (svalue_t *); +void mark_stack (void); +#endif + +#endif /* _INTERPRET_H */ diff --git a/fluffos-2.23-ds03/lag.d b/fluffos-2.23-ds03/lag.d new file mode 100644 index 0000000..e90bbca --- /dev/null +++ b/fluffos-2.23-ds03/lag.d @@ -0,0 +1,49 @@ +BEGIN +{ + self->start = 0; + self->ind = 0; +} + +fluffos$target:::lpc-entry +/!self->ind/ +{ + self->start = timestamp; + self->spec = speculation(); + speculate(self->spec); + printf("%s(%s):%s ", copyinstr(arg0), copyinstr(arg2), copyinstr(arg1)); +} + +fluffos$target:::lpc-entry +/self->ind==1/ +{ + speculate(self->spec); + printf("\n%s(%s):%s ", copyinstr(arg0), copyinstr(arg2), copyinstr(arg1)); +} + + +fluffos$target:::lpc-entry +{ + self->ind++; +} + +fluffos$target:::lpc-return +/self->ind>0/{ + self->ind--; +} + +fluffos$target:::lpc-return +/!self->ind && timestamp - self->start>1000000000/ +{ + speculate(self->spec); + printf("%d\n", timestamp - self->start); + commit(self->spec); + self->spec = 0; +} + +fluffos$target:::lpc-return +/!self->ind && self->spec/ +{ + discard(self->spec); + self->spec = 0; +} + diff --git a/fluffos-2.23-ds03/lag.stp b/fluffos-2.23-ds03/lag.stp new file mode 100644 index 0000000..c9e7df3 --- /dev/null +++ b/fluffos-2.23-ds03/lag.stp @@ -0,0 +1,19 @@ +global s +global t +global i + +probe process("driver").mark("lpc__entry") +{ + if(!i++) + t = gettimeofday_us(); + + // printf("%s %s\n", user_string($arg1), user_string($arg2)); +} + +probe process("driver").mark("lpc__return") +{ + if(i) + i--; + if(!i && gettimeofday_us() - t > 1000000) + printf("%s(%s):%s %d us\n", user_string($arg1), user_string($arg3), user_string($arg2), gettimeofday_us() - t); +} \ No newline at end of file diff --git a/fluffos-2.23-ds03/lex.c b/fluffos-2.23-ds03/lex.c new file mode 100644 index 0000000..c8b693c --- /dev/null +++ b/fluffos-2.23-ds03/lex.c @@ -0,0 +1,3503 @@ +/* + * File: lex.c + * + * Revision: + * 93-06-27 (Robocoder): + * Adjusted the meaning of the EXPECT_* flags; + * EXPECT_ELSE ... means the last condition was false, so we want to find + * an alternative or the end of the conditional block + * EXPECT_ENDIF ... means the last condition was true, so we want to find + * the end of the conditional block + * Added #elif preprocessor command + * Fixed get_text_block bug so no text returned "" + * Added get_array_block()...using @@ENDMARKER to return array of strings + */ + +#define SUPPRESS_COMPILER_INLINES +#include "std.h" +#include "file_incl.h" +#include "lpc_incl.h" +#include "compiler.h" +#if defined(WIN32) && !defined(MINGW) +# include "grammar_tab.h" +#else +# include "grammar.tab.h" +#endif +#include "scratchpad.h" +#include "preprocess.h" +#include "md.h" +#include "hash.h" +#include "file.h" +#include "main.h" +#include "cc.h" +#include "master.h" + +#define NELEM(a) (sizeof (a) / sizeof((a)[0])) +#define LEX_EOF ((unsigned char) EOF) + +char lex_ctype[256] = {0,0,0,0,0,0,0,0,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0}; + +#define is_wspace(c) lex_ctype[(unsigned char)(c)] + +int current_line; /* line number in this file */ +int current_line_base; /* number of lines from other files */ +int current_line_saved; /* last line in this file where line num + info was saved */ +int total_lines; /* Used to compute average compiled lines/s */ +char *current_file; +int current_file_id; + +/* Bit flags for pragmas in effect */ +int pragmas; + +int num_parse_error; /* Number of errors in the parser. */ + +lpc_predef_t *lpc_predefs = NULL; + +static int yyin_desc; +int lex_fatal; +static char **inc_list; +static int inc_list_size; +static int defines_need_freed = 0; +static char *last_nl; +static int nexpands = 0; + +#define EXPANDMAX 25000 +static char *expands[EXPANDMAX]; +static int expand_depth = 0; + +char yytext[MAXLINE]; +char *outp; + +typedef struct incstate_s { + struct incstate_s *next; + int yyin_desc; + int line; + char *file; + int file_id; + char *last_nl; + char *outp; +} incstate_t; + +static incstate_t *inctop = 0; + +/* prevent unbridled recursion */ +#define MAX_INCLUDE_DEPTH 32 +static int incnum; + +/* If more than this is needed, the code needs help :-) */ +#define MAX_FUNCTION_DEPTH 10 + +static function_context_t function_context_stack[MAX_FUNCTION_DEPTH]; +static int last_function_context; +function_context_t *current_function_context = 0; + +int arrow_efun, evaluate_efun, this_efun, to_float_efun, to_int_efun, new_efun; + + +/* + * The number of arguments stated below, are used by the compiler. + * If min == max, then no information has to be coded about the + * actual number of arguments. Otherwise, the actual number of arguments + * will be stored in the byte after the instruction. + * A maximum value of -1 means unlimited maximum value. + * + * If an argument has type 0 (T_INVALID) specified, then no checks will + * be done at run time. + * + * The argument types are currently not checked by the compiler, + * only by the runtime. + */ +keyword_t predefs[] = +#include "efun_defs.c" + +const char *option_defs[] = +#include "option_defs.c" + +static keyword_t reswords[] = +{ +#ifdef DEBUG + {"__TREE__", L_TREE, 0 }, +#endif +#ifdef ARRAY_RESERVED_WORD + {"array", L_ARRAY, 0 }, +#endif + {"asm", 0, 0}, + {"break", L_BREAK, 0}, +#ifndef NO_BUFFER_TYPE + {"buffer", L_BASIC_TYPE, TYPE_BUFFER}, +#endif + {"case", L_CASE, 0}, + {"catch", L_CATCH, 0}, +#ifdef STRUCT_CLASS + {"class", L_CLASS, 0}, +#endif +#ifdef COMPAT_32 + {"closure", L_BASIC_TYPE, TYPE_FUNCTION}, +#endif + {"continue", L_CONTINUE, 0}, + {"default", L_DEFAULT, 0}, + {"do", L_DO, 0}, + {"efun", L_EFUN, 0}, + {"else", L_ELSE, 0}, + {"float", L_BASIC_TYPE, TYPE_REAL}, + {"for", L_FOR, 0}, + {"foreach", L_FOREACH, 0}, + {"function", L_BASIC_TYPE, TYPE_FUNCTION}, + {"if", L_IF, 0}, + {"in", L_IN, 0}, + {"inherit", L_INHERIT, 0}, + {"int", L_BASIC_TYPE, TYPE_NUMBER}, + {"mapping", L_BASIC_TYPE, TYPE_MAPPING}, + {"mixed", L_BASIC_TYPE, TYPE_ANY}, + {"new", L_NEW, 0}, + {"nomask", L_TYPE_MODIFIER, DECL_NOMASK}, +#ifdef SENSIBLE_MODIFIERS + {"nosave", L_TYPE_MODIFIER, DECL_NOSAVE}, +#endif + {"object", L_BASIC_TYPE, TYPE_OBJECT}, + {"parse_command", L_PARSE_COMMAND, 0}, + {"private", L_TYPE_MODIFIER, DECL_PRIVATE}, + {"protected", L_TYPE_MODIFIER, DECL_PROTECTED}, +#ifdef SENSIBLE_MODIFIERS + {"public", L_TYPE_MODIFIER, DECL_PUBLIC}, +#else + {"public", L_TYPE_MODIFIER, DECL_VISIBLE}, +#endif +#ifdef REF_RESERVED_WORD + {"ref", L_REF, 0 }, +#endif + {"return", L_RETURN, 0}, + {"sscanf", L_SSCANF, 0}, +#ifndef SENSIBLE_MODIFIERS + {"static", L_TYPE_MODIFIER, DECL_NOSAVE | DECL_PROTECTED }, +#endif +#ifdef HAS_STATUS_TYPE + {"status", L_BASIC_TYPE, TYPE_NUMBER}, +#endif + {"string", L_BASIC_TYPE, TYPE_STRING}, +#ifdef STRUCT_STRUCT + {"struct", L_CLASS, 0}, +#endif + {"switch", L_SWITCH, 0}, + {"time_expression", L_TIME_EXPRESSION, 0}, + {"varargs", L_TYPE_MODIFIER, FUNC_VARARGS }, +#ifdef VIRTUAL_RESERVED_WORD + {"virtual", L_TYPE_MODIFIER, 0 }, +#endif + {"void", L_BASIC_TYPE, TYPE_VOID}, + {"while", L_WHILE, 0}, +}; + +static ident_hash_elem_t **ident_hash_table; +static ident_hash_elem_t **ident_hash_head; +static ident_hash_elem_t **ident_hash_tail; + +static ident_hash_elem_t *ident_dirty_list = 0; + +instr_t instrs[MAX_INSTRS]; + +#define TERM_ADD_INPUT 1 +#define TERM_INCLUDE 2 +#define TERM_START 4 + +typedef struct linked_buf_s { + struct linked_buf_s *prev; + char term_type; + char buf[DEFMAX]; + char *buf_end; + char *outp; + char *last_nl; +} linked_buf_t; + +static linked_buf_t head_lbuf = { NULL, TERM_START }; +static linked_buf_t *cur_lbuf; + +static void handle_define (char *); +static void free_defines (void); +static void add_define (const char *, int, const char *); +static void add_predefine (const char *, int, const char *); +static int expand_define (void); +static void add_input (const char *); +static int cond_get_exp (int); +static void merge (char *name, char *dest); +static void add_quoted_predefine (const char *, const char *); +static void lexerror (const char *); +static int skip_to (const char *, const char *); +static void handle_cond (int); +static int inc_open (char *, char *, int); +static void include_error (const char *, int); +static void handle_include (char *, int); +static int get_terminator (char *); +static int get_array_block (char *); +static int get_text_block (char *); +static void skip_line (void); +static void skip_comment (void); +static void deltrail (char *); +static void handle_pragma (char *); +static int cmygetc (void); +static void refill (void); +static void refill_buffer (void); +static int exgetc (void); +static int old_func (void); +static ident_hash_elem_t *quick_alloc_ident_entry (void); +static void yyerrorp (const char *); + +#define LEXER +#include "preprocess.c" + +int lookup_predef(const char * name) +{ + int x; + + for(x = 0; x < (sizeof(predefs) / sizeof(keyword_t)); x++) + { + if(strcmp(name, predefs[x].word) == 0) + { + return x; + } + } + + return -1; +} + +static void merge (char * name, char * dest) +{ + char *from; + + strcpy(dest, current_file); + if ((from = strrchr(dest, '/'))) /* strip filename */ + *from = 0; + else + /* current_file was the file_name */ + /* include from the root directory */ + *dest = 0; + + from = name; + while (*from == '/') { + from++; + *dest = 0; /* absolute path */ + } + + while (*from) { + if (!strncmp(from, "../", 3)) { + char *tmp; + + if (*dest == 0) /* including from above mudlib is NOT allowed */ + break; + tmp = strrchr(dest, '/'); + if (tmp == NULL) /* 1 component in dest */ + *dest = 0; + else + *tmp = 0; + from += 3; /* skip "../" */ + } else if (!strncmp(from, "./", 2)) { + from += 2; + } else { /* append first component to dest */ + char *q; + + if (*dest) + strcat(dest, "/"); /* only if dest is not empty !! */ + q = strchr(from, '/'); + + if (q) { /* from has 2 or more components */ + while (*from == '/') /* find the start */ + from++; + strncat(dest, from, q - from); + for (from = q + 1; *from == '/'; from++); + } else { + /* this was the last component */ + strcat(dest, from); + break; + } + } + } +} + +static void +yyerrorp (const char * s) { + char buf[200]; + sprintf(buf, s, '#'); + yyerror(buf); + lex_fatal++; +} + +static void +lexerror (const char * s) +{ + yyerror(s); + lex_fatal++; +} + +static int +skip_to (const char * token, const char * atoken) +{ + char b[20], *p; + unsigned char c; + register char *yyp = outp, *startp; + char *b_end = b + 19; + int nest; + + for (nest = 0;;) { + if ((c = *yyp++) == '#') { + while (is_wspace(c = *yyp++)); + startp = yyp - 1; + for (p = b; !isspace(c) && c != LEX_EOF; c = *yyp++) { + if (p < b_end) *p++ = c; + else break; + } + *p = 0; + if (!strcmp(b, "if") || !strcmp(b, "ifdef") || !strcmp(b, "ifndef")) { + nest++; + } else if (nest > 0) { + if (!strcmp(b, "endif")) + nest--; + } else { + if (!strcmp(b, token)) { + outp = startp; + *--outp = '#'; + return 1; + } else if (atoken && !strcmp(b, atoken)) { + outp = startp; + *--outp = '#'; + return 0; + } else if (!strcmp(b, "elif")) { + outp = startp; + *--outp = '#'; + return (atoken == 0); + } + } + } + while (c != '\n' && c != LEX_EOF) c = *yyp++; + if (c == LEX_EOF) { + lexerror("Unexpected end of file while looking for #endif"); + outp = yyp - 1; + return 1; + } + current_line++; + total_lines++; + if (yyp == last_nl + 1) { + outp = yyp; + refill_buffer(); + yyp = outp; + } + } +} + +static int +inc_open (char * buf, char * name, int check_local) +{ + int i, f; + char *p; + const char *tmp; + if (check_local) { + merge(name, buf); + tmp = check_valid_path(buf, master_ob, "include", 0); + if (tmp && (f = open(tmp, O_RDONLY)) != -1) + return f; + } + /* + * Search all include dirs specified. + */ + for (p = strchr(name, '.'); p; p = strchr(p + 1, '.')) { + if (p[1] == '.') + return -1; + } + for (i = 0; i < inc_list_size; i++) { + sprintf(buf, "%s/%s", inc_list[i], name); + tmp = check_valid_path(buf, master_ob, "include", 0); + if (tmp && (f = open(tmp, O_RDONLY)) != -1) { + return f; + } + } + return -1; +} + +static void +include_error (const char * msg, int global) +{ + current_line--; + + if (global) { + int saved_pragmas = pragmas; + + pragmas &= ~PRAGMA_ERROR_CONTEXT; + lexerror(msg); + pragmas = saved_pragmas; + } else { + yyerror(msg); + } + + current_line++; +} + +static void +handle_include (char * name, int global) +{ + char *p, *nameptr; + static char buf[MAXLINE]; + incstate_t *is; + int delim, f; + + if (*name != '"' && *name != '<') { + defn_t *d; + + if ((d = lookup_define(name)) && d->nargs == -1) { + char *q; + + q = d->exps; + while (uisspace(*q)) + q++; + handle_include(q, global); + } else { + include_error("Missing leading \" or < in #include", global); + } + return; + } + name = string_copy(name, "handle_include"); + push_malloced_string(name); + delim = *name++ == '"' ? '"' : '>'; + for (p = name; *p && *p != delim; p++); + if (!*p) { + pop_stack(); + include_error("Missing trailing \" or > in #include", global); + return; + } + if (strlen(name) > sizeof(buf) - 100) { + pop_stack(); + include_error("Include name too long.", global); + return; + } + *p = 0; + if (++incnum == MAX_INCLUDE_DEPTH) { + include_error("Maximum include depth exceeded.", global); + } else if ((f = inc_open(buf, name, delim == '"')) != -1) { + is = ALLOCATE(incstate_t, TAG_COMPILER, "handle_include: 1"); + is->yyin_desc = yyin_desc; + is->line = current_line; + is->file = current_file; + is->file_id = current_file_id; + is->last_nl = last_nl; + is->next = inctop; + is->outp = outp; + inctop = is; + current_line--; + save_file_info(current_file_id, current_line - current_line_saved); + current_line_base += current_line; + current_line_saved = 0; + current_line = 1; + current_file = make_shared_string(buf); + current_file_id = add_program_file(buf, 0); + yyin_desc = f; + refill_buffer(); + } else { + sprintf(buf, "Cannot #include %s", name); + include_error(buf, global); + } + pop_stack(); +} + +static int +get_terminator (char * terminator) +{ + unsigned char c; + int j = 0; + + while (((c = *outp++) != LEX_EOF) && (isalnum(c) || c == '_')) + terminator[j++] = c; + + terminator[j] = '\0'; + + while (is_wspace(c) && c != LEX_EOF) + c = *outp++; + + if (c == LEX_EOF) + return 0; + + if (c == '\n') { + current_line++; + if (outp == last_nl + 1) refill_buffer(); + } else { + outp--; + } + + return j; +} + +#define MAXCHUNK (MAXLINE*4) +#define NUMCHUNKS (DEFMAX/MAXCHUNK) + +#define NEWCHUNK(line) \ + if (len == MAXCHUNK - 1) { \ + line[curchunk][MAXCHUNK - 1] = '\0'; \ + if (curchunk == NUMCHUNKS - 1) { \ + res = -2; \ + break; \ + } \ + line[++curchunk] = \ + (char *)DXALLOC(MAXCHUNK, TAG_COMPILER, "array/text chunk"); \ + len = 0; \ + } + +static int +get_array_block (char * term) +{ + int termlen; /* length of terminator */ + char *array_line[NUMCHUNKS];/* allocate memory in chunks */ + int header, len; /* header length; position in chunk */ + int startpos, startchunk; /* start of line */ + int curchunk, res; /* current chunk; this function's result */ + int i; /* an index counter */ + unsigned char c; /* a char */ + char *yyp = outp; + + /* + * initialize + */ + termlen = strlen(term); + array_line[0] = (char *) DXALLOC(MAXCHUNK, TAG_COMPILER, "array_block"); + array_line[0][0] = '('; + array_line[0][1] = '{'; + array_line[0][2] = '"'; + array_line[0][3] = '\0'; + header = 1; + len = 3; + startpos = 3; + startchunk = 0; + curchunk = 0; + res = 0; + + while (1) { + while (((c = *yyp++) != '\n') && (c != LEX_EOF)) { + NEWCHUNK(array_line); + if (c == '"' || c == '\\') { + array_line[curchunk][len++] = '\\'; + NEWCHUNK(array_line); + } + array_line[curchunk][len++] = c; + } + + if (c == '\n' && (yyp == last_nl + 1)) { + outp = yyp; refill_buffer(); yyp = outp; + } + + /* + * null terminate current chunk + */ + array_line[curchunk][len] = '\0'; + + if (res) { + outp = yyp; + break; + } + + /* + * check for terminator + */ + if ((!strncmp(array_line[startchunk] + startpos, term, termlen)) && + (!uisalnum(*(array_line[startchunk] + startpos + termlen))) && + (*(array_line[startchunk] + startpos + termlen) != '_')) { + /* + * handle lone terminator on line + */ + if (strlen(array_line[startchunk] + startpos) == termlen) { + current_line++; + outp = yyp; + } else { + /* + * put back trailing portion after terminator + */ + outp = --yyp; /* some operating systems give EOF only once */ + + for (i = curchunk; i > startchunk; i--) + add_input(array_line[i]); + add_input(array_line[startchunk] + startpos + termlen); + } + + /* + * remove terminator from last chunk + */ + array_line[startchunk][startpos - header] = '\0'; + + /* + * insert array block into input stream + */ + *--outp = ')'; + *--outp = '}'; + for (i = startchunk; i >= 0; i--) + add_input(array_line[i]); + + res = 1; + break; + } else { + /* + * only report end of file in array block, if not an include file + */ + if (c == LEX_EOF && inctop == 0) { + res = -1; + outp = yyp; + break; + } + if (c == '\n') { + current_line++; + } + /* + * make sure there's room in the current chunk for terminator (ie + * it's simpler if we don't have to deal with a terminator that + * spans across chunks) fudge for "\",\"TERMINAL?\0", where '?' + * is unknown + */ + if (len + termlen + 5 > MAXCHUNK) { + if (curchunk == NUMCHUNKS - 1) { + res = -2; + outp = yyp; + break; + } + array_line[++curchunk] = + (char *) DXALLOC(MAXCHUNK, TAG_COMPILER, "array_block"); + len = 0; + } + /* + * header + */ + array_line[curchunk][len++] = '"'; + array_line[curchunk][len++] = ','; + array_line[curchunk][len++] = '"'; + array_line[curchunk][len] = '\0'; + + startchunk = curchunk; + startpos = len; + header = 2; + } + } + + /* + * free chunks + */ + for (i = curchunk; i >= 0; i--) + FREE(array_line[i]); + + return res; +} + +static int +get_text_block (char * term) +{ + int termlen; /* length of terminator */ + char *text_line[NUMCHUNKS]; /* allocate memory in chunks */ + int len; /* position in chunk */ + int startpos, startchunk; /* start of line */ + int curchunk, res; /* current chunk; this function's result */ + int i; /* an index counter */ + unsigned char c; /* a char */ + register char *yyp = outp; + + /* + * initialize + */ + termlen = strlen(term); + text_line[0] = (char *) DXALLOC(MAXCHUNK, TAG_COMPILER, "text_block"); + text_line[0][0] = '"'; + text_line[0][1] = '\0'; + len = 1; + startpos = 1; + startchunk = 0; + curchunk = 0; + res = 0; + + while (1) { + while (((c = *yyp++) != '\n') && (c != LEX_EOF)) { + NEWCHUNK(text_line); + if (c == '"' || c == '\\') { + text_line[curchunk][len++] = '\\'; + NEWCHUNK(text_line); + } + text_line[curchunk][len++] = c; + } + + if (c == '\n' && yyp == last_nl + 1) { + outp = yyp; + refill_buffer(); + yyp = outp; + } + + /* + * null terminate current chunk + */ + text_line[curchunk][len] = '\0'; + + if (res) { + outp = yyp; + break; + } + + /* + * check for terminator + */ + if ((!strncmp(text_line[startchunk] + startpos, term, termlen)) && + (!uisalnum(*(text_line[startchunk] + startpos + termlen))) && + (*(text_line[startchunk] + startpos + termlen) != '_')) { + if (strlen(text_line[startchunk] + startpos) == termlen) { + current_line++; + outp = yyp; + } else { + char *p, *q; + /* + * put back trailing portion after terminator + */ + outp = --yyp; /* some operating systems give EOF only once */ + + for (i = curchunk; i > startchunk; i--) { + /* Ick. go back and unprotect " and \ */ + p = text_line[i]; + while (*p && *p != '\\') + p++; + if (*p) { + q = p++; + do { + *q++ = *p++; + if (*p == '\\') p++; + } while (*p); + *q = 0; + } + + add_input(text_line[i]); + } + p = text_line[startchunk] + startpos + termlen; + while (*p && *p != '\\') + p++; + if (*p) { + q = p++; + do { + *q++ = *p++; + if (*p == '\\') p++; + } while (*p); + *q = 0; + } + add_input(text_line[startchunk] + startpos + termlen); + } + + /* + * remove terminator from last chunk + */ + text_line[startchunk][startpos] = '\0'; + + /* + * insert text block into input stream + */ + *--outp = '\0'; + *--outp = '"'; + + for (i = startchunk; i >= 0; i--) + add_input(text_line[i]); + + res = 1; + break; + } else { + /* + * only report end of file in text block, if not an include file + */ + if (c == LEX_EOF && inctop == 0) { + res = -1; + outp = yyp; + break; + } + if (c == '\n') { + current_line++; + } + /* + * make sure there's room in the current chunk for terminator (ie + * it's simpler if we don't have to deal with a terminator that + * spans across chunks) fudge for "\\nTERMINAL?\0", where '?' is + * unknown + */ + if (len + termlen + 4 > MAXCHUNK) { + if (curchunk == NUMCHUNKS - 1) { + res = -2; + outp = yyp; + break; + } + text_line[++curchunk] = + (char *) DXALLOC(MAXCHUNK, TAG_COMPILER, "text_block"); + len = 0; + } + /* + * header + */ + text_line[curchunk][len++] = '\\'; + text_line[curchunk][len++] = 'n'; + text_line[curchunk][len] = '\0'; + + startchunk = curchunk; + startpos = len; + } + } + + /* + * free chunks + */ + for (i = curchunk; i >= 0; i--) + FREE(text_line[i]); + + return res; +} + +static void skip_line() +{ + unsigned char c; + register char *yyp = outp; + + while (((c = *yyp++) != '\n') && (c != LEX_EOF)); + + /* Next read of this '\n' will do refill_buffer() if neccesary */ + if (c == '\n') yyp--; + outp = yyp; +} + +static void skip_comment() +{ + unsigned char c = '*'; + register char *yyp = outp; + + for (;;) { + while ((c = *yyp++) != '*') { + if (c == LEX_EOF) { + outp = --yyp; + lexerror("End of file in a comment"); + return; + } + if (c == '\n') { + nexpands = 0; + current_line++; + if (yyp == last_nl + 1) { + outp = yyp; + refill_buffer(); + yyp = outp; + } + } + } + if (*(yyp - 2) == '/') + yywarn("/* found in comment."); + do { + if ((c = *yyp++) == '/') { + outp = yyp; + return; + } + if (c == '\n') { + nexpands = 0; + current_line++; + if (yyp == last_nl + 1) { + outp = yyp; + refill_buffer(); + yyp = outp; + } + } + } while (c == '*'); + } +} + +static void +deltrail (char * sp) +{ + char *p; + + p = sp; + if (!*p) { + lexerror("Illegal # command"); + } else { + while (*p && !uisspace(*p)) + p++; + *p = 0; + } +} + +#define SAVEC \ + if (yyp < yytext+MAXLINE-5)\ + *yyp++ = c;\ + else {\ + lexerror("Line too long");\ + break;\ + } + +typedef struct { + const char *name; + int value; +} pragma_t; + +static pragma_t our_pragmas[] = { + { "strict_types", PRAGMA_STRICT_TYPES }, + { "save_types", PRAGMA_SAVE_TYPES }, + { "warnings", PRAGMA_WARNINGS }, + { "optimize", PRAGMA_OPTIMIZE }, + { "show_error_context", PRAGMA_ERROR_CONTEXT }, + { 0, 0 } +}; + +static void handle_pragma (char * str) +{ + int i; + int no_flag; + + if (strncmp(str, "no_", 3) == 0) { + str += 3; + no_flag = 1; + } else + no_flag = 0; + + for (i = 0; our_pragmas[i].name; i++) { + if (strcmp(our_pragmas[i].name, str) == 0) { + if (no_flag) { + pragmas &= ~our_pragmas[i].value; + } else { + pragmas |= our_pragmas[i].value; + } + return; + } + } + yywarn("Unknown #pragma, ignored."); +} + +char *show_error_context() { + static char buf[60]; + extern int yychar; + char sub_context[25]; + register char *yyp, *yyp2; + int len; + + if ((unsigned char)outp[-1] == LEX_EOF) { + strcpy(buf, " at the end of the file\n"); + return buf; + } + + if (yychar == -1) strcpy(buf, " around "); + else strcpy(buf, " before "); + yyp = outp; + yyp2 = sub_context; + len = 20; + while (len--) { + if (*yyp == '\n') { + if (len == 19) strcat(buf, "the end of line"); + break; + } else if ((unsigned char)*yyp == LEX_EOF) { + if (len == 19) strcat(buf, "the end of file"); + break; + } + *yyp2++ = *yyp++; + } + *yyp2 = 0; + if (yyp2 != sub_context) strcat(buf, sub_context); + strcat(buf, "\n"); + return buf; +} + +#ifdef WIN32 +int correct_read(int handle, char *buf, unsigned int count) +{ + unsigned int tmp,size=0; + + do { + tmp=read(handle,buf,count); + if (tmp < 0) return tmp; + if (tmp == 0) return size; + size+=tmp; + count-=tmp; + buf+=tmp; + } while (count>0); + return size; +} +#else +#define correct_read read +#endif + +static void refill_buffer() { + if (cur_lbuf != &head_lbuf) { + if (outp >= cur_lbuf->buf_end && + cur_lbuf->term_type == TERM_ADD_INPUT) { + /* In this case it cur_lbuf cannot have been + allocated due to #include */ + linked_buf_t *prev_lbuf = cur_lbuf->prev; + + FREE(cur_lbuf); + cur_lbuf = prev_lbuf; + outp = cur_lbuf->outp; + last_nl = cur_lbuf->last_nl; + if (cur_lbuf->term_type == TERM_ADD_INPUT + || (outp != last_nl + 1)) + return; + } + } + + /* Here we are sure that we need more from the file */ + /* Assume outp is one beyond a newline at last_nl */ + /* or after an #include .... */ + + { + char *end; + char *p; + int size; + + if (!inctop) { + /* First check if there's enough space at the end */ + end = cur_lbuf->buf + DEFMAX; + if (end - cur_lbuf->buf_end > MAXLINE + 5) { + p = cur_lbuf->buf_end; + } + else { + /* No more space at the end */ + size = cur_lbuf->buf_end - outp + 1; /* Include newline */ + memcpy(outp - MAXLINE - 1, outp - 1, size); + outp -= MAXLINE; + p = outp + size - 1; + } + + size = correct_read(yyin_desc, p, MAXLINE); + cur_lbuf->buf_end = p += size; + if (size < MAXLINE) { + *(last_nl = p) = LEX_EOF; + if(*(last_nl-1) != '\n'){ + if(size +1 > MAXLINE) + yyerror("No newline at end of file."); + *p++ = '\n'; + *(last_nl = p) = LEX_EOF; + } + return; + } + while (*--p != '\n'); + if (p == outp - 1) { + lexerror("Line too long."); + *(last_nl = cur_lbuf->buf_end - 1) = '\n'; + return; + } + last_nl = p; + return; + } else { + int flag = 0; + + /* We are reading from an include file */ + /* Is there enough space? */ + end = inctop->outp; + + /* See if we are the last include in a different linked buffer */ + if (cur_lbuf->term_type == TERM_INCLUDE && + !(end >= cur_lbuf->buf && end < cur_lbuf->buf + DEFMAX)) { + end = cur_lbuf->buf_end; + flag = 1; + } + + size = end - outp + 1; /* Include newline */ + if (outp - cur_lbuf->buf > 2 * MAXLINE) { + memcpy(outp - MAXLINE - 1, outp - 1, size); + outp -= MAXLINE; + p = outp + size - 1; + } else { /* No space, need to allocate new buffer */ + linked_buf_t *new_lbuf; + char *new_outp; + + if (!(new_lbuf = ALLOCATE(linked_buf_t, TAG_COMPILER, "refill_bufer"))) { + lexerror("Out of memory when allocating new buffer.\n"); + return; + } + cur_lbuf->last_nl = last_nl; + cur_lbuf->outp = outp; + new_lbuf->prev = cur_lbuf; + new_lbuf->term_type = TERM_INCLUDE; + new_outp = new_lbuf->buf + DEFMAX - MAXLINE - size - 5; + memcpy(new_outp - 1, outp - 1, size); + cur_lbuf = new_lbuf; + outp = new_outp; + p = outp + size - 1; + flag = 1; + } + + size = correct_read(yyin_desc, p, MAXLINE); + end = p += size; + if (flag) cur_lbuf->buf_end = p; + if (size < MAXLINE) { + *(last_nl = p) = LEX_EOF; + if(*(last_nl-1) != '\n'){ + if(size +1 > MAXLINE) + yyerror("No newline at end of file."); + *p++ = '\n'; + *(last_nl = p) = LEX_EOF; + } + return; + } + while (*--p != '\n'); + if (p == outp - 1) { + lexerror("Line too long."); + *(last_nl = end - 1) = '\n'; + return; + } + last_nl = p; + return; + } + } +} + +static int function_flag = 0; + +INLINE void push_function_context() { + function_context_t *fc; + parse_node_t *node; + + if (last_function_context == MAX_FUNCTION_DEPTH - 1) { + yyerror("Function pointers nested too deep."); + return; + } + fc = &function_context_stack[++last_function_context]; + fc->num_parameters = 0; + fc->num_locals = 0; + node = new_node_no_line(); + node->l.expr = node; + node->r.expr = 0; + node->kind = 0; + fc->values_list = node; + fc->bindable = 0; + fc->parent = current_function_context; + + current_function_context = fc; +} + +void pop_function_context() { + current_function_context = current_function_context->parent; + last_function_context--; +} + +static int old_func() { + add_input(" "); + add_input(yytext); + push_function_context(); + return L_FUNCTION_OPEN; +} + +#define return_assign(opcode) { yylval.number = opcode; return L_ASSIGN; } +#define return_order(opcode) { yylval.number = opcode; return L_ORDER; } + +/* To halt execution when a #breakpoint line is encountered, set a breakpoint + at this function */ +static void lex_breakpoint() { +} + +int yylex() +{ + static char partial[MAXLINE + 5]; /* extra 5 for safety buffer */ + static char terminator[MAXLINE + 5]; + int is_float; + float myreal; + char *partp; + + register char *yyp; + unsigned char c; + + yytext[0] = 0; + + partp = partial; + partial[0] = 0; + + for (;;) { + if (lex_fatal) { + return -1; + } + switch (c = *outp++) { + case LEX_EOF: + if (inctop) { + incstate_t *p; + + p = inctop; + close(yyin_desc); + save_file_info(current_file_id, current_line - current_line_saved); + current_line_saved = p->line - 1; + /* add the lines from this file, and readjust to be relative + to the file we're returning to */ + current_line_base += current_line - current_line_saved; + free_string(current_file); + nexpands = 0; + if (outp >= cur_lbuf->buf_end) { + linked_buf_t *prev_lbuf; + if ((prev_lbuf = cur_lbuf->prev)) { + FREE(cur_lbuf); + cur_lbuf = prev_lbuf; + } + } + + current_file = p->file; + current_file_id = p->file_id; + current_line = p->line; + + yyin_desc = p->yyin_desc; + last_nl = p->last_nl; + outp = p->outp; + inctop = p->next; + incnum--; + FREE((char *) p); + outp[-1] = '\n'; + if (outp == last_nl + 1) refill_buffer(); + break; + } + if (iftop) { + ifstate_t *p = iftop; + + yyerror(p->state == EXPECT_ENDIF ? "Missing #endif" : "Missing #else/#elif"); + while (iftop) { + p = iftop; + iftop = p->next; + FREE((char *) p); + } + } + outp--; + return -1; + case '\r': + yywarn("^M"); + break; + case '\t': +#ifdef WARN_TAB + yywarn(""); +#endif + break; + case '\n': + nexpands = 0; + current_line++; + total_lines++; + if (outp == last_nl + 1) + refill_buffer(); + case ' ': + case '\f': + case '\v': + break; + case '+': + { + switch(*outp++) { + case '+': return L_INC; + case '=': return_assign(F_ADD_EQ); + default: outp--; return '+'; + } + } + case '-': + { + switch(*outp++) { + case '>': return L_ARROW; + case '-': return L_DEC; + case '=': return_assign(F_SUB_EQ); + default: outp--; return '-'; + } + } + case '&': + { + switch(*outp++) { + case '&': return L_LAND; + case '=': return_assign(F_AND_EQ); + default: outp--; return '&'; + } + } + case '|': + { + switch(*outp++) { + case '|': return L_LOR; + case '=': return_assign(F_OR_EQ); + default: outp--; return '|'; + } + } + case '^': + { + if (*outp++ == '=') return_assign(F_XOR_EQ); + outp--; + return '^'; + } + case '<': + { + switch(*outp++) { + case '<': + { + if (*outp++ == '=') return_assign(F_LSH_EQ); + outp--; + return L_LSH; + } + case '=': return_order(F_LE); + default: outp--; return '<'; + } + } + case '>': + { + switch(*outp++) { + case '>': + { + if (*outp++ == '=') return_assign(F_RSH_EQ); + outp--; + return L_RSH; + } + case '=': return_order(F_GE); + default: outp--; return_order(F_GT); + } + } + case '*': + { + if (*outp++ == '=') return_assign(F_MULT_EQ); + outp--; + return '*'; + } + case '%': + { + if (*outp++ == '=') return_assign(F_MOD_EQ); + outp--; + return '%'; + } + case '/': + switch(*outp++) { + case '*': skip_comment(); break; + case '/': skip_line(); break; + case '=': return_assign(F_DIV_EQ); + default: outp--; return '/'; + } + break; + case '=': + if (*outp++ == '=') return L_EQ; + outp--; + yylval.number = F_ASSIGN; + return L_ASSIGN; + case '(': + yyp = outp; +#ifdef WOMBLES + c = *yyp++; +#else + while (isspace(c = *yyp++)) { + if (c == '\n') { + current_line++; + if (yyp == last_nl + 1) { + outp = yyp; + refill_buffer(); + yyp = outp; + } + } + } +#endif + switch(c) { + case '{' : { outp = yyp; return L_ARRAY_OPEN; } + case '[' : { outp = yyp; return L_MAPPING_OPEN; } + case ':' : + { + if ((c = *yyp++) == ':') { + outp = yyp -= 2; + return '('; + } else { + while (isspace(c)) { + if (c == '\n') { + if ((yyp == last_nl + 1)) { + outp = yyp; + refill_buffer(); + yyp = outp; + } + current_line++; + } + c = *yyp++; + } + + outp = yyp; + + if (isalpha(c) || c == '_') { + function_flag = 1; + goto parse_identifier; + } + + outp--; + push_function_context(); + return L_FUNCTION_OPEN; + } + + } + default: + { + outp = yyp - 1; + return '('; + } + } + + case '$': + if (!current_function_context) { + yyerror("$var illegal outside of function pointer."); + return '$'; + } + if (current_function_context->num_parameters == -2) { + yyerror("$var illegal inside anonymous function pointer."); + return '$'; + } else { + if (!isdigit(c = *outp++)) { + outp--; + return '$'; + } + yyp = yytext; + SAVEC; + for (;;) { + if (!isdigit(c = *outp++)) break; + SAVEC; + } + outp--; + *yyp = 0; + yylval.number = atol(yytext) - 1; + if (yylval.number < 0) + yyerror("In function parameter $num, num must be >= 1."); + else if (yylval.number > 254) + yyerror("only 255 parameters allowed."); + else if (yylval.number >= current_function_context->num_parameters) + current_function_context->num_parameters = yylval.number + 1; + return L_PARAMETER; + } + case ')': + case '{': + case '}': + case '[': + case ']': + case ';': + case ',': + case '~': +#ifndef USE_TRIGRAPHS + case '?': + return c; +#else + return c; + /* + * You're probably asking, what the heck are trigraphs? + * The character set of C source is contained within seven-bit + * ASCII, a superset of ISO 646-1983 Invariant Code Set; + * to allow programs to be represented in the reduced set, + * certain single characters are replaced by a corresponding + * trigraph (3 character) sequence. These are: + * ??= # ??( [ ??< { + * ??/ \ ??) ] ??> } + * ??' ^ ??! | ??- ~ + */ + case '?': + if (*outp++ != '?') { outp--; return '?'; } + switch (*outp++) { + case '=': return '#'; + case '/': return '\\'; + case '\'': return '^'; + case '(': return '['; + case ')': return ']'; + case '!': return '|'; + case '<': return '{'; + case '>': return '}'; + case '-': return '~'; + default: + outp -= 2; + return '?'; + } +#endif + case '!': + if (*outp++ == '=') return L_NE; + outp--; + return L_NOT; + case ':': + if (*outp++ == ':') return L_COLON_COLON; + outp--; + return ':'; + case '.': + if (*outp++ == '.') { + if (*outp++ == '.') + return L_DOT_DOT_DOT; + outp--; + return L_RANGE; + } + outp--; + goto badlex; + case '#': + if (*(outp - 2) == '\n') { + char *sp = 0; + int quote; + + while (is_wspace(c = *outp++)); + + yyp = yytext; + + for (quote = 0;;) { + + if (c == '"') + quote ^= 1; + else if (c == '/' && !quote) { + if (*outp == '*') { + outp++; + skip_comment(); + c = *outp++; + } else + if (*outp == '/') { + outp++; + skip_line(); + c = *outp++; + } + } + if (!sp && isspace(c)) + sp = yyp; + if (c == '\n' || c == LEX_EOF) break; + SAVEC; + c = *outp++; + } + if (sp) { + *sp++ = 0; + while (uisspace(*sp)) + sp++; + } else { + sp = yyp; + } + *yyp = 0; + if (!strcmp("include", yytext)) { + current_line++; + if (c == LEX_EOF) { + *(last_nl = --outp) = LEX_EOF; + outp[-1] = '\n'; + } + handle_include(sp, 0); + break; + } else { + if (outp == last_nl + 1) refill_buffer(); + + if (strcmp("define", yytext) == 0) { + handle_define(sp); + } else if (strcmp("if", yytext) == 0) { + int cond; + + *--outp = '\0'; + add_input(sp); + cond = cond_get_exp(0); + if (*outp++) { + yyerror("Condition too complex in #if"); + while (*outp++); + } else + handle_cond(cond); + } else if (strcmp("ifdef", yytext) == 0) { + deltrail(sp); + handle_cond(lookup_define(sp) != 0); + } else if (strcmp("ifndef", yytext) == 0) { + deltrail(sp); + handle_cond(lookup_define(sp) == 0); + } else if (strcmp("elif", yytext) == 0) { + handle_elif(sp); + } else if (strcmp("else", yytext) == 0) { + handle_else(); + } else if (strcmp("endif", yytext) == 0) { + handle_endif(); + } else if (strcmp("undef", yytext) == 0) { + defn_t *d; + + deltrail(sp); + if ((d = lookup_define(sp))) { + if (d->flags & DEF_IS_PREDEF) + yyerror("Illegal to #undef a predefined value."); + else + d->flags |= DEF_IS_UNDEFINED; + } + } else if (strcmp("echo", yytext) == 0) { + debug_message("%s\n", sp); + } else if (strcmp("error", yytext) == 0) { + char buf[MAXLINE+1]; + strcpy(buf, yytext); + strcat(buf, "\n"); + yyerror(buf); + } else if (strcmp("warn", yytext) == 0) { + char buf[MAXLINE+1]; + strcpy(buf, yytext); + strcat(buf, "\n"); + yywarn(buf); + } else if (strcmp("pragma", yytext) == 0) { + handle_pragma(sp); + } else if (strcmp("breakpoint", yytext) == 0) { + lex_breakpoint(); + } else { + yyerror("Unrecognised # directive"); + } + *--outp = '\n'; + break; + } + } else { +#ifdef COMPAT_32 + if (*outp == '\'') { + outp++; + return L_LAMBDA; + } +#endif + goto badlex; + } + case '\'': + + if (*outp++ == '\\') { + switch(*outp++) { + case 'n': yylval.number = '\n'; break; + case 't': yylval.number = '\t'; break; + case 'r': yylval.number = '\r'; break; + case 'b': yylval.number = '\b'; break; + case 'a': yylval.number = '\x07'; break; + case 'e': yylval.number = '\x1b'; break; + case '\'': yylval.number = '\''; break; + case '"': yylval.number = '"'; break; + case '\\': yylval.number = '\\'; break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + outp--; + yylval.number = strtol(outp, &outp, 8); + if (yylval.number > 255) { + yywarn("Illegal character constant."); + yylval.number = 'x'; + } + break; + case 'x': + if (!isxdigit((unsigned char)*outp)) { + yylval.number = 'x'; + yywarn("\\x must be followed by a valid hex value; interpreting as 'x' instead."); + } else { + yylval.number = strtol(outp, &outp, 16); + if (yylval.number > 255) { + yywarn("Illegal character constant."); + yylval.number = 'x'; + } + } + break; + case '\n': + yylval.number = '\n'; + current_line++; + total_lines++; + if ((outp = last_nl + 1)) + refill_buffer(); + break; + default: + yywarn("Unknown \\ escape."); + yylval.number = *(outp - 1); + break; + } + } else { + yylval.number = *(outp - 1); + } + + if (*outp++ != '\'') { + outp--; + yyerror("Illegal character constant"); + yylval.number = 0; + } + return L_NUMBER; + case '@': + { + int rc; + int tmp; + + if ((tmp = *outp++) != '@') { + /* check for Robocoder's @@ block */ + outp--; + } + if (!get_terminator(terminator)) { + lexerror("Illegal terminator"); + break; + } + if (tmp == '@') { + rc = get_array_block(terminator); + + if (rc > 0) { + /* outp is pointing at "({" for histortical reasons */ + outp += 2; + return L_ARRAY_OPEN; + } else if (rc == -1) { + lexerror("End of file in array block"); + return LEX_EOF; + } else { /* if rc == -2 */ + yyerror("Array block exceeded maximum length"); + } + } else { + rc = get_text_block(terminator); + + if (rc > 0) { + int n; + + /* + * make string token and clean up + */ + yylval.string = scratch_copy_string(outp); + + n = strlen(outp) + 1; + outp += n; + + return L_STRING; + } else if (rc == -1) { + lexerror("End of file in text block"); + return LEX_EOF; + } else { /* if (rc == -2) */ + yyerror("Text block exceeded maximum length"); + } + } + } + break; + case '"': + { + int l; + register unsigned char *to = scr_tail + 1; + + if ((l = scratch_end - to) > 255) l = 255; + while (l--) { + switch(c = *outp++) { + case LEX_EOF: + lexerror("End of file in string"); + return LEX_EOF; + + case '"': + *to++ = 0; + if (!l && (to == scratch_end)) { + char *res = scratch_large_alloc(to - scr_tail - 1); + strcpy(res, (char *) (scr_tail + 1)); + yylval.string = res; + return L_STRING; + } + + scr_last = scr_tail + 1; + scr_tail = to; + *to = to - scr_last; + yylval.string = (char *) scr_last; + return L_STRING; + + case '\n': + current_line++; + total_lines++; + if (outp == last_nl + 1) refill_buffer(); + *to++ = '\n'; + break; + + case '\\': + /* Don't copy the \ in yet */ + switch((unsigned char)*outp++) { + case '\n': + current_line++; + total_lines++; + if (outp == last_nl + 1) refill_buffer(); + l++; /* Nothing is copied */ + break; + case LEX_EOF: + lexerror("End of file in string"); + return LEX_EOF; + case 'n': *to++ = '\n'; break; + case 't': *to++ = '\t'; break; + case 'r': *to++ = '\r'; break; + case 'b': *to++ = '\b'; break; + case 'a': *to++ = '\x07'; break; + case 'e': *to++ = '\x1b'; break; + case '"': *to++ = '"'; break; + case '\\': *to++ = '\\'; break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + int tmp; + outp--; + tmp = strtol(outp, &outp, 8); + if (tmp > 255) { + yywarn("Illegal character constant in string."); + tmp = 'x'; + } + *to++ = tmp; + break; + } + case 'x': + { + int tmp; + if (!isxdigit((unsigned char)*outp)) { + *to++ = 'x'; + yywarn("\\x must be followed by a valid hex value; interpreting as 'x' instead."); + } else { + tmp = strtol(outp, &outp, 16); + if (tmp > 255) { + yywarn("Illegal character constant."); + tmp = 'x'; + } + *to++ = tmp; + } + break; + } + default: + *to++ = *(outp - 1); + yywarn("Unknown \\ escape."); + } + break; + default: + *to++ = c; + } + } + + /* Not enough space, we now copy the rest into yytext */ + l = MAXLINE - (to - scr_tail); + + yyp = yytext; + while (l--) { + switch(c = *outp++) { + case LEX_EOF: + lexerror("End of file in string"); + return LEX_EOF; + + case '"': + { + char *res; + *yyp++ = '\0'; + res = scratch_large_alloc((yyp - yytext) + (to - scr_tail) - 1); + strncpy(res, (char *) (scr_tail + 1), (to - scr_tail) - 1); + strcpy(res + (to - scr_tail) - 1, yytext); + yylval.string = res; + return L_STRING; + } + + case '\n': + current_line++; + total_lines++; + if (outp == last_nl + 1) refill_buffer(); + *yyp++ = '\n'; + break; + + case '\\': + /* Don't copy the \ in yet */ + switch((unsigned char)*outp++) { + case '\n': + current_line++; + total_lines++; + if (outp == last_nl + 1) refill_buffer(); + l++; /* Nothing is copied */ + break; + case LEX_EOF: + lexerror("End of file in string"); + return LEX_EOF; + case 'n': *yyp++ = '\n'; break; + case 't': *yyp++ = '\t'; break; + case 'r': *yyp++ = '\r'; break; + case 'b': *yyp++ = '\b'; break; + case 'a': *yyp++ = '\x07'; break; + case 'e': *yyp++ = '\x1b'; break; + case '"': *yyp++ = '"'; break; + case '\\': *yyp++ = '\\'; break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + int tmp; + outp--; + tmp = strtol(outp, &outp, 8); + if (tmp > 255) { + yywarn("Illegal character constant in string."); + tmp = 'x'; + } + *yyp++ = tmp; + break; + } + case 'x': + { + int tmp; + if (!isxdigit((unsigned char)*outp)) { + *yyp++ = 'x'; + yywarn("\\x must be followed by a valid hex value; interpreting as 'x' instead."); + } else { + tmp = strtol(outp, &outp, 16); + if (tmp > 255) { + yywarn("Illegal character constant."); + tmp = 'x'; + } + *yyp++ = tmp; + } + break; + } + default: + *yyp++ = *(outp - 1); + yywarn("Unknown \\ escape."); + } + break; + + default: *yyp++ = c; + } + } + + /* Not even enough length, declare too long string error */ + lexerror("String too long"); + *yyp++ = '\0'; + { + char *res; + res = scratch_large_alloc((yyp - yytext) + (to - scr_tail) - 1); + strncpy(res, (char *) (scr_tail + 1), (to - scr_tail) - 1); + strcpy(res + (to - scr_tail) - 1, yytext); + yylval.string = res; + return L_STRING; + } + } + case '0': + c = *outp++; + if (c == 'X' || c == 'x') { + yyp = yytext; + for (;;) { + c = *outp++; + SAVEC; + if (!isxdigit((unsigned char)c)) + break; + } + outp--; + yylval.number = strtol(yytext, (char **) NULL, 0x10); + return L_NUMBER; + } + outp--; + c = '0'; + /* fall through */ + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + is_float = 0; + yyp = yytext; + *yyp++ = c; + for (;;) { + c = *outp++; + if (c == '.') { + if (!is_float) { + is_float = 1; + } else { + is_float = 0; + outp--; + break; + } + } else if (!isdigit((unsigned char)c)) + break; + SAVEC; + } + outp--; + *yyp = 0; + if (is_float) { + sscanf(yytext, "%f", &myreal); + yylval.real = (float)myreal; + return L_REAL; + } else { + yylval.number = atol(yytext); + return L_NUMBER; + } + default: + if (isalpha((unsigned char)c) || c == '_') { + int r; + +parse_identifier: + yyp = yytext; + *yyp++ = c; + for (;;) { + c = *outp++; + if (!isalnum((unsigned char)c) && (c != '_')) + break; + SAVEC; + } + *yyp = 0; + if (c == '#') { + if (*outp++ != '#') + lexerror("Single '#' in identifier -- use '##' for token pasting"); + outp -= 2; + if (!expand_define()) { + if (partp + (r = strlen(yytext)) + (function_flag ? 3 : 0) - partial > MAXLINE) + lexerror("Pasted token is too long"); + if (function_flag) { + strcpy(partp, "(: "); + partp += 3; + } + strcpy(partp, yytext); + partp += r; + outp += 2; + } + } else if (partp != partial) { + outp--; + if (!expand_define()) + add_input(yytext); + while ((c = *outp++) == ' '); + outp--; + add_input(partial); + partp = partial; + partial[0] = 0; + } else { + outp--; + if (!expand_define()) { + ident_hash_elem_t *ihe; + if ((ihe = lookup_ident(yytext))) { + if (ihe->token & IHE_RESWORD) { + if (function_flag) { + function_flag = 0; + add_input(yytext); + push_function_context(); + return L_FUNCTION_OPEN; + } + yylval.number = ihe->sem_value; + return ihe->token & TOKEN_MASK; + } + if (function_flag) { + int val; + + function_flag = 0; + while ((c = *outp++) == ' '); + outp--; + /* Note that this gets code like: + * #define x :) + * #define y , + * function f = (: foo x; + * function g = (: bar y 1 :); + * + * wrong. But that is almost pathological. + */ + if (c != ':' && c != ',') + return old_func(); + if ((val=ihe->dn.local_num) >= 0) { + if (c == ',') return old_func(); + yylval.number = (val << 8) | FP_L_VAR; + } else if ((val=ihe->dn.global_num) >= 0) { + if (c == ',') return old_func(); + yylval.number = (val << 8) | FP_G_VAR; + } else if ((val=ihe->dn.function_num) >=0) { + yylval.number = (val << 8)|FP_LOCAL; + } else if ((val=ihe->dn.simul_num) >=0) { + yylval.number = (val << 8)|FP_SIMUL; + } else if ((val=ihe->dn.efun_num) >=0) { + yylval.number = (val << 8)|FP_EFUN; + } else return old_func(); + return L_NEW_FUNCTION_OPEN; + } + yylval.ihe = ihe; + return L_DEFINED_NAME; + } + yylval.string = scratch_copy(yytext); + return L_IDENTIFIER; + } + if (function_flag) { + function_flag = 0; + add_input("(:"); + } + } + break; + } + goto badlex; + } + } + badlex: + { +#ifdef DEBUG + char buff[100]; + + sprintf(buff, "Illegal character (hex %02x) '%c'", (unsigned) c, (char) c); + yyerror(buff); +#endif + return ' '; + } +} + +extern YYSTYPE yylval; + +void end_new_file() +{ + while (inctop) { + incstate_t *p; + + p = inctop; + close(yyin_desc); + free_string(current_file); + current_file = p->file; + yyin_desc = p->yyin_desc; + inctop = p->next; + FREE((char *) p); + } + inctop = 0; + while (iftop) { + ifstate_t *p; + + p = iftop; + iftop = p->next; + FREE((char *) p); + } + if (defines_need_freed) { + free_defines(); + defines_need_freed = 0; + } + if (cur_lbuf != &head_lbuf) { + linked_buf_t *prev_lbuf; + + while (cur_lbuf != &head_lbuf) { + prev_lbuf = cur_lbuf->prev; + FREE ((char *) cur_lbuf); + cur_lbuf = prev_lbuf; + } + } +} + +static void add_quoted_predefine (const char * def, const char * val) +{ + char save_buf[MAXLINE]; + + strcpy(save_buf, "\""); + strcat(save_buf, val); + strcat(save_buf, "\""); + add_predefine(def, -1, save_buf); +} + +void add_predefines() +{ + char save_buf[80]; + int i; + lpc_predef_t *tmpf; + + add_predefine("MUDOS", -1, ""); + add_predefine("FLUFFOS", -1, ""); +#ifdef WIN32 + add_predefine("__WIN32__", -1, ""); +#endif +#ifdef RUSAGE + add_predefine("__HAS_RUSAGE__", -1, ""); +#endif +#ifdef M64 + add_predefine("__M64__", -1, ""); +#endif +#ifdef PACKAGE_DB + add_predefine("__PACKAGE_DB__", -1, ""); +#endif +#ifdef GET_CHAR_IS_BUFFERED + add_predefine("__GET_CHAR_IS_BUFFERED__", -1, ""); +#endif +#ifdef PACKAGE_DSLIB + add_predefine("__DSLIB__", -1, ""); +#endif +#ifdef PACKAGE_DWLIB + add_predefine("__DWLIB__", -1, ""); +#endif +#ifdef FD_SETSIZE + sprintf(save_buf, "%d", FD_SETSIZE); +#else + sprintf(save_buf, "%d", 64); +#endif + add_predefine("__FD_SETSIZE__", -1, save_buf); + get_version(save_buf); + add_quoted_predefine("__VERSION__", save_buf); + sprintf(save_buf, "%d", external_port[0].port); + add_predefine("__PORT__", -1, save_buf); + for (i = 0; i < 2 * NUM_OPTION_DEFS; i += 2) { + add_predefine(option_defs[i], -1, option_defs[i+1]); + } + add_quoted_predefine("__ARCH__", ARCH); + add_quoted_predefine("__COMPILER__", COMPILER); + add_quoted_predefine("__OPTIMIZATION__", OPTIMIZE); + + /* Backwards Compat */ +#ifndef CDLIB + add_quoted_predefine("MUD_NAME", MUD_NAME); +#endif +#ifdef F_ED + add_predefine("HAS_ED", -1, ""); +#endif +#ifdef F_PRINTF + add_predefine("HAS_PRINTF", -1, ""); +#endif +#if (defined(RUSAGE) || defined(GET_PROCESS_STATS) || defined(TIMES)) + add_predefine("HAS_RUSAGE", -1, ""); +#endif +#ifdef DEBUG_MACRO + add_predefine("HAS_DEBUG_LEVEL", -1, ""); +#endif + for (tmpf = lpc_predefs; tmpf; tmpf = tmpf->next) { + char namebuf[NSIZE]; + char mtext[MLEN]; + + *mtext = '\0'; + sscanf(tmpf->flag, "%[^=]=%[ -~=]", namebuf, mtext); + if (strlen(namebuf) >= NSIZE) + fatal("NSIZE exceeded"); + if (strlen(mtext) >= MLEN) + fatal("MLEN exceeded"); + add_predefine(namebuf, -1, mtext); + } + sprintf(save_buf, "%ld", sizeof(long)); + add_predefine("SIZEOFINT", -1, save_buf); + sprintf(save_buf, "%ld", LONG_MAX); + add_predefine("MAX_INT", -1, save_buf); +} + +void start_new_file (int f) +{ + if (defines_need_freed) { + free_defines(); + } + defines_need_freed = 1; + if (current_file) { + char *dir; + char *tmp; + int ln; + + ln = strlen(current_file); + dir = (char *) DMALLOC(ln + 4, TAG_COMPILER, "start_new_file"); + dir[0] = '"'; + dir[1] = '/'; + memcpy(dir + 2, current_file, ln); + dir[ln + 2] = '"'; + dir[ln + 3] = 0; + add_define("__FILE__", -1, dir); + tmp = strrchr(dir, '/'); + tmp[1] = '"'; + tmp[2] = 0; + add_define("__DIR__", -1, dir); + FREE(dir); + } + yyin_desc = f; + lex_fatal = 0; + last_function_context = -1; + current_function_context = 0; + cur_lbuf = &head_lbuf; + cur_lbuf->outp = cur_lbuf->buf_end = outp = cur_lbuf->buf + (DEFMAX >> 1); + *(last_nl = outp - 1) = '\n'; + pragmas = DEFAULT_PRAGMAS; + nexpands = 0; + incnum = 0; + current_line = 1; + current_line_base = 0; + current_line_saved = 0; + function_flag = 0; + if (*GLOBAL_INCLUDE_FILE) { + char *gifile; + + /* need a writable copy */ + gifile = alloc_cstring(GLOBAL_INCLUDE_FILE, "global include"); + handle_include(gifile, 1); + FREE(gifile); + } else refill_buffer(); +} + +const char *query_instr_name (int instr) +{ + const char *name; + static char num_buf[20]; + + name = instrs[instr].name; + + if (name) { + if (name[0] == '_') name++; + return name; + } else { + sprintf(num_buf, "efun%d", instr); + return num_buf; + } +} + +#define add_instr_name(w, x, y, z) int_add_instr_name(w, y, z) + +static void int_add_instr_name (const char * name, int n, short t) +{ + instrs[n].name = name; + instrs[n].ret_type = t; +} + +static void init_instrs() +{ + int i, n; + + for (i = 0; i < BASE; i++) { + instrs[i].ret_type = -1; + } + for (i = 0; i < NELEM(predefs); i++) { + n = predefs[i].token; + if (n & F_ALIAS_FLAG) { + predefs[i].token ^= F_ALIAS_FLAG; + } else { + instrs[n].min_arg = predefs[i].min_args; + instrs[n].max_arg = predefs[i].max_args; + instrs[n].name = predefs[i].word; + instrs[n].type[0] = predefs[i].arg_type1; + instrs[n].type[1] = predefs[i].arg_type2; + instrs[n].type[2] = predefs[i].arg_type3; + instrs[n].type[3] = predefs[i].arg_type4; + instrs[n].Default = predefs[i].Default; + instrs[n].ret_type = predefs[i].ret_type; + instrs[n].arg_index = predefs[i].arg_index; + } + } + /* + * eoperators have a return type now. T_* is used instead of TYPE_* + * since operators can return multiple types. + */ +#ifdef NO_BUFFER_TYPE +#define OR_BUFFER +#else +#define OR_BUFFER | T_BUFFER +#endif + + add_instr_name("<", "c_lt();\n", F_LT, T_NUMBER); + add_instr_name(">", "c_gt();\n", F_GT, T_NUMBER); + add_instr_name("<=", "c_le();\n", F_LE, T_NUMBER); + add_instr_name(">=", "c_ge();\n", F_GE, T_NUMBER); + add_instr_name("==", "f_eq();\n", F_EQ, T_NUMBER); + add_instr_name("+=", "c_add_eq(0);\n", F_ADD_EQ, T_ANY); + add_instr_name("(void)+=", "c_add_eq(1);\n", F_VOID_ADD_EQ, T_NUMBER); + add_instr_name("!", "c_not();\n", F_NOT, T_NUMBER); + add_instr_name("&", "f_and();\n", F_AND, T_ARRAY | T_NUMBER); + add_instr_name("&=", "f_and_eq();\n", F_AND_EQ, T_NUMBER); + add_instr_name("index", "c_index();\n", F_INDEX, T_ANY); + add_instr_name("member", "c_member(%i);\n", F_MEMBER, T_ANY); + add_instr_name("new_empty_class", "c_new_class(%i, 0);\n", F_NEW_EMPTY_CLASS, T_ANY); + add_instr_name("new_class", "c_new_class(%i, 1);\n", F_NEW_CLASS, T_ANY); + add_instr_name("rindex", "c_rindex();\n", F_RINDEX, T_ANY); + add_instr_name("loop_cond_local", "C_LOOP_COND_LV(%i, %i); if (lpc_int)\n", F_LOOP_COND_LOCAL, -1); + add_instr_name("loop_cond_number", "C_LOOP_COND_NUM(%i, %i); if (lpc_int)\n", F_LOOP_COND_NUMBER, -1); + add_instr_name("loop_incr", "C_LOOP_INCR(%i);\n", F_LOOP_INCR, -1); + add_instr_name("foreach", 0, F_FOREACH, -1); + add_instr_name("exit_foreach", "c_exit_foreach();\n", F_EXIT_FOREACH, -1); + add_instr_name("expand_varargs", 0, F_EXPAND_VARARGS, -1); + add_instr_name("next_foreach", "c_next_foreach();\n", F_NEXT_FOREACH, -1); + add_instr_name("member_lvalue", "c_member_lvalue(%i);\n", F_MEMBER_LVALUE, T_LVALUE); + add_instr_name("index_lvalue", "push_indexed_lvalue(0);\n", + F_INDEX_LVALUE, T_LVALUE|T_LVALUE_BYTE); + add_instr_name("rindex_lvalue", "push_indexed_lvalue(1);\n", + F_RINDEX_LVALUE, T_LVALUE|T_LVALUE_BYTE); + add_instr_name("nn_range_lvalue", "push_lvalue_range(0x00);\n", + F_NN_RANGE_LVALUE, T_LVALUE_RANGE); + add_instr_name("nr_range_lvalue", "push_lvalue_range(0x01);\n", + F_NR_RANGE_LVALUE, T_LVALUE_RANGE); + add_instr_name("rr_range_lvalue", "push_lvalue_range(0x11);\n", + F_RR_RANGE_LVALUE, T_LVALUE_RANGE); + add_instr_name("rn_range_lvalue", "push_lvalue_range(0x10);\n", + F_RN_RANGE_LVALUE, T_LVALUE_RANGE); + add_instr_name("nn_range", "f_range(0x00);\n", + F_NN_RANGE, T_ARRAY|T_STRING OR_BUFFER); + add_instr_name("rr_range", "f_range(0x11);\n", + F_RR_RANGE, T_ARRAY|T_STRING OR_BUFFER); + add_instr_name("nr_range", "f_range(0x01);\n", + F_NR_RANGE, T_ARRAY|T_STRING OR_BUFFER); + add_instr_name("rn_range", "f_range(0x10);\n", + F_RN_RANGE, T_ARRAY|T_STRING OR_BUFFER); + add_instr_name("re_range", "f_extract_range(1);\n", + F_RE_RANGE, T_ARRAY|T_STRING OR_BUFFER); + add_instr_name("ne_range", "f_extract_range(0);\n", + F_NE_RANGE, T_ARRAY|T_STRING OR_BUFFER); + add_instr_name("global", "C_GLOBAL(%i);\n", F_GLOBAL, T_ANY); + add_instr_name("local", "C_LOCAL(%i);\n", F_LOCAL, T_ANY); + add_instr_name("make_ref", "c_make_ref(%i);\n", F_MAKE_REF, T_REF); + add_instr_name("kill_refs", "c_kill_refs(%i);\n", F_KILL_REFS, T_ANY); + add_instr_name("ref", "C_REF(%i);\n", F_REF, T_ANY); + add_instr_name("ref_lvalue", "C_REF_LVALUE(%i);\n", F_REF_LVALUE, T_LVALUE); + add_instr_name("transfer_local", "C_TRANSFER_LOCAL(%i);\n", F_TRANSFER_LOCAL, T_ANY); + add_instr_name("number", 0, F_NUMBER, T_NUMBER); + add_instr_name("real", 0, F_REAL, T_REAL); + add_instr_name("local_lvalue", "C_LVALUE(fp + %i);\n", F_LOCAL_LVALUE, T_LVALUE); + add_instr_name("while_dec", "C_WHILE_DEC(%i); if (lpc_int)\n", F_WHILE_DEC, -1); + add_instr_name("const1", "push_number(1);\n", F_CONST1, T_NUMBER); + add_instr_name("subtract", "c_subtract();\n", F_SUBTRACT, T_NUMBER | T_REAL | T_ARRAY); + add_instr_name("(void)assign", "c_void_assign();\n", F_VOID_ASSIGN, T_NUMBER); + add_instr_name("(void)assign_local", "c_void_assign_local(fp + %i);\n", F_VOID_ASSIGN_LOCAL, T_NUMBER); + add_instr_name("assign", "c_assign();\n", F_ASSIGN, T_ANY); + add_instr_name("branch", 0, F_BRANCH, -1); + add_instr_name("bbranch", 0, F_BBRANCH, -1); + add_instr_name("byte", 0, F_BYTE, T_NUMBER); + add_instr_name("-byte", 0, F_NBYTE, T_NUMBER); + add_instr_name("branch_ne", 0, F_BRANCH_NE, -1); + add_instr_name("branch_ge", 0, F_BRANCH_GE, -1); + add_instr_name("branch_le", 0, F_BRANCH_LE, -1); + add_instr_name("branch_eq", 0, F_BRANCH_EQ, -1); + add_instr_name("bbranch_lt", 0, F_BBRANCH_LT, -1); + add_instr_name("bbranch_when_zero", 0, F_BBRANCH_WHEN_ZERO, -1); + add_instr_name("bbranch_when_non_zero", 0, F_BBRANCH_WHEN_NON_ZERO, -1); + add_instr_name("branch_when_zero", 0, F_BRANCH_WHEN_ZERO, -1); + add_instr_name("branch_when_non_zero", 0, F_BRANCH_WHEN_NON_ZERO, -1); + add_instr_name("pop", "pop_stack();\n", F_POP_VALUE, -1); + add_instr_name("const0", "push_number(0);\n", F_CONST0, T_NUMBER); +#ifdef F_JUMP_WHEN_ZERO + add_instr_name("jump_when_zero", F_JUMP_WHEN_ZERO, -1); + add_instr_name("jump_when_non_zero", F_JUMP_WHEN_NON_ZERO, -1); +#endif +#ifdef F_LOR + add_instr_name("||", 0, F_LOR, -1); + add_instr_name("&&", 0, F_LAND, -1); +#endif + add_instr_name("-=", "f_sub_eq();\n", F_SUB_EQ, T_ANY); +#ifdef F_JUMP + add_instr_name("jump", F_JUMP, -1); +#endif + add_instr_name("return_zero", "c_return_zero();\nreturn;\n", F_RETURN_ZERO, -1); + add_instr_name("return", "c_return();\nreturn;\n", F_RETURN, -1); + add_instr_name("sscanf", "c_sscanf(%i);\n", F_SSCANF, T_NUMBER); + add_instr_name("parse_command", "c_parse_command(%i);\n", F_PARSE_COMMAND, T_NUMBER); + add_instr_name("string", 0, F_STRING, T_STRING); + add_instr_name("short_string", 0, F_SHORT_STRING, T_STRING); + add_instr_name("call", "c_call(%i, %i);\n", F_CALL_FUNCTION_BY_ADDRESS, T_ANY); + add_instr_name("call_inherited", "c_call_inherited(%i, %i, %i);\n", F_CALL_INHERITED, T_ANY); + add_instr_name("aggregate_assoc", "C_AGGREGATE_ASSOC(%i);\n", F_AGGREGATE_ASSOC, T_MAPPING); +#ifdef DEBUG + add_instr_name("break_point", "break_point();\n", F_BREAK_POINT, -1); +#endif + add_instr_name("aggregate", "C_AGGREGATE(%i);\n", F_AGGREGATE, T_ARRAY); + add_instr_name("(::)", 0, F_FUNCTION_CONSTRUCTOR, T_FUNCTION); + /* sorry about this one */ + add_instr_name("simul_efun", + "call_simul_efun(%i, (lpc_int = %i + num_varargs, num_varargs = 0, lpc_int));\n", + F_SIMUL_EFUN, T_ANY); + add_instr_name("global_lvalue", "C_LVALUE(¤t_object->variables[variable_index_offset + %i]);\n", F_GLOBAL_LVALUE, T_LVALUE); + add_instr_name("|", "f_or();\n", F_OR, T_ARRAY | T_NUMBER); + add_instr_name("<<", "f_lsh();\n", F_LSH, T_NUMBER); + add_instr_name(">>", "f_rsh();\n", F_RSH, T_NUMBER); + add_instr_name(">>=", "f_rsh_eq();\n", F_RSH_EQ, T_NUMBER); + add_instr_name("<<=", "f_lsh_eq();\n", F_LSH_EQ, T_NUMBER); + add_instr_name("^", "f_xor();\n", F_XOR, T_NUMBER); + add_instr_name("^=", "f_xor_eq();\n", F_XOR_EQ, T_NUMBER); + add_instr_name("|=", "f_or_eq();\n", F_OR_EQ, T_NUMBER); + add_instr_name("+", "c_add();\n", F_ADD, T_ANY); + add_instr_name("!=", "f_ne();\n", F_NE, T_NUMBER); + add_instr_name("catch", 0, F_CATCH, T_ANY); + add_instr_name("end_catch", 0, F_END_CATCH, -1); + add_instr_name("-", "c_negate();\n", F_NEGATE, T_NUMBER | T_REAL); + add_instr_name("~", "c_compl();\n", F_COMPL, T_NUMBER); + add_instr_name("++x", "c_pre_inc();\n", F_PRE_INC, T_NUMBER | T_REAL); + add_instr_name("--x", "c_pre_dec();\n", F_PRE_DEC, T_NUMBER | T_REAL); + add_instr_name("*", "c_multiply();\n", F_MULTIPLY, T_REAL | T_NUMBER | T_MAPPING); + add_instr_name("*=", "f_mult_eq();\n", F_MULT_EQ, T_REAL | T_NUMBER | T_MAPPING); + add_instr_name("/", "c_divide();\n", F_DIVIDE, T_REAL | T_NUMBER); + add_instr_name("/=", "f_div_eq();\n", F_DIV_EQ, T_NUMBER | T_REAL); + add_instr_name("%", "c_mod();\n", F_MOD, T_NUMBER); + add_instr_name("%=", "f_mod_eq();\n", F_MOD_EQ, T_NUMBER); + add_instr_name("inc(x)", "c_inc();\n", F_INC, -1); + add_instr_name("dec(x)", "c_dec();\n", F_DEC, -1); + add_instr_name("x++", "c_post_inc();\n", F_POST_INC, T_NUMBER | T_REAL); + add_instr_name("x--", "c_post_dec();\n", F_POST_DEC, T_NUMBER | T_REAL); + add_instr_name("switch", 0, F_SWITCH, -1); + add_instr_name("time_expression", 0, F_TIME_EXPRESSION, -1); + add_instr_name("end_time_expression", 0, F_END_TIME_EXPRESSION, T_NUMBER); +} + +#define get_next_char(c) if ((c = *outp++) == '\n' && outp == last_nl + 1) refill_buffer() + +#define GETALPHA(p, q, m, e) \ + if (*p == '_' || uisalpha(*p)) {\ + while(isalunum((unsigned char)*p)) {\ + *q = *p++;\ + if (q < (m))\ + q++;\ + else {\ + lexerror("Name too long");\ + return;\ + }\ + }\ + } else lexerror(e);\ + *q++ = 0 + +static int cmygetc() +{ + int c; + + for (;;) { + get_next_char(c); + if (c == '/') { + switch(*outp++) { + case '*': skip_comment(); break; + case '/': skip_line(); break; + default: outp--; return c; + } + } else { + return c; + } + } +} + +static void refill() +{ + char *p; + unsigned char c; + + p = yytext; + do { + c = *outp++; + if (p < yytext + MAXLINE - 5) + *p++ = c; + else { + lexerror("Line too long"); + break; + } + } while (c != '\n' && c != LEX_EOF); + if ((c == '\n') && (outp == last_nl + 1)) refill_buffer(); + p[-1] = ' '; + *p = 0; + nexpands = 0; + current_line++; +} + +static void handle_define (char * yyt) +{ + char namebuf[NSIZE]; + char args[NARGS][NSIZE]; + char mtext[MLEN]; + char *p, *q; + + p = yyt; + strcat(p, " "); + q = namebuf; + GETALPHA(p, q, namebuf + NSIZE - 1, "Invalid macro name"); + if (*p == '(') { /* if "function macro" */ + int squote, dquote; + int arg; + int inid; + char *ids = (char *) NULL; + + p++; /* skip '(' */ + SKIPWHITE; + if (*p == ')') { + arg = 0; + } else { + for (arg = 0; arg < NARGS;) { + q = args[arg]; + GETALPHA(p, q, args[arg] + NSIZE - 1, "Invalid macro argument"); + arg++; + SKIPWHITE; + if (*p == ')') + break; + if (*p++ != ',') { + yyerror("Missing ',' in #define parameter list"); + return; + } + SKIPWHITE; + } + if (arg == NARGS) { + lexerror("Too many macro arguments"); + return; + } + } + p++; /* skip ')' */ + q = mtext; + *q++ = ' '; + squote = dquote = 0; + for (inid = 0; *p;) { + if (isalunum((unsigned char)*p)) { /* FIXME */ + if (!inid) { + inid++; + ids = p; + } + } else { + if (!squote && !dquote && inid) { + int idlen = p - ids; + int n, l; + + for (n = 0; n < arg; n++) { + l = strlen(args[n]); + if (l == idlen && strncmp(args[n], ids, l) == 0) { + q -= idlen; + *q++ = MARKS; + *q++ = n + MARKS + 1; + break; + } + } + inid = 0; + } + } + *q = *p; + if (*q == '\\' && *++p) { + if (q < mtext + MLEN - 2) + q++; + else { + lexerror("Macro text too long"); + return; + } + *q = *p; + /* skip the quote checks if we just had a \ */ + } + else if (*q == '"') { + dquote ^= !squote; + } else if (*q == '\'') { + squote ^= !dquote; + } + + if (*p++ == MARKS) + *++q = MARKS; + if (q < mtext + MLEN - 2) + q++; + else { + lexerror("Macro text too long"); + return; + } + if (!*p && p[-2] == '\\') { + q -= 2; + refill(); + p = yytext; + } + } + *--q = 0; + add_define(namebuf, arg, mtext); + } else if (is_wspace(*p) || (*p == '\\')) { + for (q = mtext; *p;) { + *q = *p++; + if (q < mtext + MLEN - 2) + q++; + else { + lexerror("Macro text too long"); + return; + } + if (!*p && p[-2] == '\\') { + q -= 2; + refill(); + p = yytext; + } + } + *--q = 0; + add_define(namebuf, -1, mtext); + } else { + lexerror("Illegal macro symbol"); + } + return; +} + +/* IDEA: linked buffers, to allow "unlimited" buffer expansion */ +static void add_input (const char * p) +{ + int l = strlen(p); + + if (l >= DEFMAX - 10) { + lexerror("Macro expansion buffer overflow"); + return; + } + + if (outp < l + 5 + cur_lbuf->buf) { + /* Not enough space, so let's move it up another linked_buf */ + linked_buf_t *new_lbuf; + char *q, *new_outp, *buf; + int size; + + q = outp; + + while (*q != '\n' && (unsigned char)*q != LEX_EOF) q++; + /* Incorporate EOF later */ + if (*q != '\n' || ((q - outp) + l) >= DEFMAX - 11) { + lexerror("Macro expansion buffer overflow"); + return; + } + size = (q - outp) + l + 1; + cur_lbuf->outp = q + 1; + cur_lbuf->last_nl = last_nl; + + new_lbuf = ALLOCATE(linked_buf_t, TAG_COMPILER, "add_input"); + new_lbuf->term_type = TERM_ADD_INPUT; + new_lbuf->prev = cur_lbuf; + buf = new_lbuf->buf; + cur_lbuf = new_lbuf; + last_nl = (new_lbuf->buf_end = buf + DEFMAX - 2) - 1; + new_outp = new_lbuf->outp = buf + DEFMAX - 2 - size; + memcpy(new_outp, p, l); + memcpy(new_outp + l, outp, (q - outp) + 1); + outp = new_outp; + *(last_nl + 1) = 0; + return; + } + + outp -= l; + strncpy(outp, p, l); +} + +#ifdef DEBUGMALLOC_EXTENSIONS +void mark_all_defines() { + int i; + defn_t *tmp; + + for (i = 0; i < inc_list_size; i++) + EXTRA_REF(BLOCK(inc_list[i]))++; + + for (i = 0; i < DEFHASH; i++) { + tmp = defns[i]; + while (tmp) { + DO_MARK(tmp, TAG_PREDEFINES); + DO_MARK(tmp->name, TAG_PREDEFINES); + DO_MARK(tmp->exps, TAG_PREDEFINES); + tmp = tmp->next; + } + } +} +#endif + +static void add_predefine (const char * name, int nargs, const char * exps) +{ + defn_t *p; + int h; + + if ((p = lookup_define(name))) { + if (nargs != p->nargs || strcmp(exps, p->exps)) { + char buf[200 + NSIZE]; + + sprintf(buf, "redefinition of #define %s\n", name); + yywarn(buf); + } + p->exps = (char *)DREALLOC(p->exps, strlen(exps) + 1, TAG_PREDEFINES, "add_define: redef"); + strcpy(p->exps, exps); + p->nargs = nargs; + } else { + p = ALLOCATE(defn_t, TAG_PREDEFINES, "add_define: def"); + p->name = (char *) DXALLOC(strlen(name) + 1, TAG_PREDEFINES, "add_define: def name"); + strcpy(p->name, name); + p->exps = (char *) DXALLOC(strlen(exps) + 1, TAG_PREDEFINES, "add_define: def exps"); + strcpy(p->exps, exps); + p->flags = DEF_IS_PREDEF; + p->nargs = nargs; + h = defhash(name); + p->next = defns[h]; + defns[h] = p; + } +} + +static void free_defines() +{ + defn_t *p, *q; + int i; + + for (i = 0; i < DEFHASH; i++) { + for (p = defns[i]; p; p = q) { + /* predefines are at the end of the list */ + if (p->flags & DEF_IS_PREDEF) { + break; + } + q = p->next; + FREE(p->name); + FREE(p->exps); + FREE((char *) p); + } + defns[i] = p; + /* in case they undefined a predef */ + while (p) { + p->flags &= ~DEF_IS_UNDEFINED; + p = p->next; + } + } + nexpands = 0; +} + +#define SKIPW \ + do {\ + c = cmygetc();\ + } while (is_wspace(c)); + +static int extract_args (char ** argv, char * argb) +{ + int argc = 0, dquote = 0, parcnt = 0, squote = 0; + char *out; + unsigned char c; + + SKIPW; + if (c != '(') { + yyerror("Missing '(' in macro call"); + if (c == '\n' && outp == last_nl + 1) refill_buffer(); + return -1; + } + + SKIPW; + if (c == ')') + return 0; + + argv[0] = out = argb; + while (argc < NARGS) { + switch (c) { + case '\"': + if (!squote) + dquote ^= 1; + break; + case '\'': + if (!dquote) + squote ^= 1; + break; + case '\\': + if (squote || dquote) { + *out++ = c; + get_next_char(c); + } + break; + case '(': + if (!squote && !dquote) + parcnt++; + break; + case ')': + if (!squote && !dquote) + parcnt--; + break; + case '\n': + if (outp == last_nl + 1) refill_buffer(); + if (squote || dquote) { + lexerror("Newline in string"); + return -1; + } + /* Change this to a space so we don't count it more than once */ + current_line++; + total_lines++; + c = ' '; + break; + case LEX_EOF: + lexerror("Unexpected end of file"); + return -1; + } + + /* negative parcnt means we're done collecting args */ + if (parcnt < 0 || (c == ',' && !parcnt && !dquote && !squote)) { + + /* strip off trailing whitespace char if there was one */ + if (uisspace(*(out - 1))) *(out - 1) = 0; + else *out++ = 0; + if (parcnt < 0) + return argc + 1; + argv[++argc] = out; + } else { + /* don't save leading whitespace and don't accumulate trailing whitespace */ + if (!uisspace(c) || dquote || squote || (out > argv[argc] && !uisspace(*(out - 1)))) { + if (out >= argb + DEFMAX - NARGS) { + lexerror("Macro argument overflow"); + return -1; + } + *out++ = c; + } + } + + if (!squote && !dquote) c = cmygetc(); + else get_next_char(c); + } + + lexerror("Maximum macro argument count exceeded"); + return -1; +} + +/* Check if yytext is a macro and expand if it is. */ +static char *expand_define2 (char * text) +{ + int argc = 0, i, paste = 0, pasting = 0; + defn_t *macro; + char expbuf[DEFMAX], *argv[NARGS], *expand_buffer, *in, *out, *freeme = 0; + + /* special handling for __LINE__ macro */ + if (!strcmp(text, "__LINE__")) { + expand_buffer = (char *)DXALLOC(20, TAG_COMPILER, "expand_define2"); + sprintf(expand_buffer, "%i", current_line); + return expand_buffer; + } + + /* have we already expanded this macro? */ + for (i = 0; i < expand_depth; i++) { + if (!strcmp(expands[i], text)) + return 0; + } + expands[expand_depth++] = text; + + if (nexpands++ > EXPANDMAX) { + expand_depth--; + lexerror("Too many macro expansions"); + return 0; + } + + macro = lookup_define(text); + if (!macro) { + expand_depth--; + return 0; + } + + if (macro->nargs >= 0) { + if ((argc = extract_args(argv, expbuf)) == -1) { + expand_depth--; + return 0; + } + if (argc != macro->nargs) { + expand_depth--; + yyerror("Wrong number of macro arguments"); + return 0; + } + } + + if (!argc) { + expand_buffer = (char *)DXALLOC(strlen(macro->exps) + 1, TAG_COMPILER, "expand_define2"); + strcpy(expand_buffer, macro->exps); + expand_depth--; + return expand_buffer; + } + + /* Perform expansion with args */ + in = macro->exps; + out = expand_buffer = (char *)DXALLOC(DEFMAX, TAG_COMPILER, "expand_define2"); + +#define SAVECHAR(x) SAFE(\ + if (out + 1 < expand_buffer + DEFMAX) {\ + *out++ = (x);\ + } else {\ + if (freeme) FREE(freeme);\ + FREE(expand_buffer);\ + lexerror("Macro expansion overflow");\ + expand_depth--;\ + return 0;\ + }) + +#define SAVESTR(x, y) SAFE(\ + if (out + (y) < expand_buffer + DEFMAX) {\ + memcpy(out, (x), (y));\ + out += (y);\ + } else {\ + if (freeme) FREE(freeme);\ + FREE(expand_buffer);\ + lexerror("Macro expansion overflow");\ + expand_depth--;\ + return 0;\ + }\ + if (freeme) {\ + FREE(freeme);\ + freeme = 0;\ + }) + + while (*in) { + char *skip = in + 1; + + if (*in == MARKS && *++in != MARKS) { + char *exp; + + exp = argv[*in++ - MARKS - 1]; + + if (paste) { + paste = 0; + *(out - 1) = '\"'; + while (*exp) { + switch (*exp) { + case '\"': + SAVECHAR('\\'); + break; + case '\\': + SAVECHAR(*exp); + exp++; + break; + } + SAVECHAR(*exp); + exp++; + } + SAVECHAR('\"'); + } else { + int len; + + /* don't expand if token pasting with ## */ + if (!pasting && (freeme = expand_define2(exp)) != 0) + exp = freeme; + len = strlen(exp); + SAVESTR(exp, len); + } + } else { + paste = (*in == '#'); + /* FIXME: Here we need to recursively expand any macros that we + * come across. This cannot possibly be done the way lex.c is + * currently architected. I've tried. This all needs to be + * redone anyway, but this just going to have to do for now :-( + */ + SAVECHAR(*in); + in++; + } + + /* skip over whitespace and see if we've got ## for token pasting. if + * we do, skip over it and continue at the first non-whitespace char. + * note that comments are not considered whitespace here like they + * should be. + */ + pasting = 0; + while (*skip && uisspace(*skip)) skip++; + if (*skip == '#' && *(skip + 1) == '#') { + skip += 2; + /* guaranteed by add_define to not have end of input before non-whitespace */ + while (uisspace(*skip)) skip++; + in = skip; + pasting = (*in == MARKS && *(in + 1) != MARKS); + } + } + + *out = 0; + expand_depth--; + return expand_buffer; +} + +int expand_define (void) +{ + char *expand_buffer; + + if ((expand_buffer = expand_define2(yytext)) != 0) { + add_input(expand_buffer); + FREE(expand_buffer); + return 1; + } + + return 0; +} + +/* Stuff to evaluate expression. I havn't really checked it. /LA +** Written by "J\"orn Rennecke" +*/ +#define SKPW do c = *outp++; while(is_wspace(c)); outp-- + +static int exgetc() +{ + unsigned char c; + char *yyp; + + c = *outp++; + while (isalpha(c) || c == '_') { + yyp = yytext; + do { + SAVEC; + c = *outp++; + } while (isalunum(c)); + outp--; + *yyp = '\0'; + if (strcmp(yytext, "defined") == 0 || + strcmp(yytext, "efun_defined") == 0) { + int efund = (yytext[0] == 'e'); + int flag; + + /* handle the defined "function" in #if */ + do + c = *outp++; + while (is_wspace(c)); + if (c != '(') { + yyerror("Missing ( in defined"); + continue; + } + do + c = *outp++; + while (is_wspace(c)); + yyp = yytext; + while (isalunum(c)) { + SAVEC; + c = *outp++; + } + *yyp = '\0'; + while (is_wspace(c)) + c = *outp++; + if (c != ')') { + yyerror("Missing ) in defined"); + continue; + } + SKPW; + if (efund) { + ident_hash_elem_t *ihe = lookup_ident(yytext); + flag = (ihe && ihe->dn.efun_num != -1); + } else { + flag = (lookup_define(yytext) != 0); + } + if (flag) + add_input(" 1 "); + else + add_input(" 0 "); + } else { + if (!expand_define()) + add_input(" 0 "); + } + c = *outp++; + } + return c; +} + +void set_inc_list (char * list) +{ + int i, size; + char *p; + + if (list == 0) { + fprintf(stderr, "The config string 'include dirs' must bet set.\n"); + fprintf(stderr, "It should contain a list of all directories to be searched\n"); + fprintf(stderr, "for include files, separated by a ':'.\n"); + exit(-1); + } + size = 1; + p = list; + while (1) { + p = strchr(p, ':'); + if (!p) + break; + size++; + p++; + } + inc_list = CALLOCATE(size, char *, TAG_INC_LIST, "set_inc_list"); + inc_list_size = size; + for (i = size - 1; i >= 0; i--) { + p = strrchr(list, ':'); + if (p) { + *p = '\0'; + p++; + } else { + if (i) { + fprintf(stderr, "Fatal error in set_inc_list: bad state.\n"); + exit(1); + } + p = list; + } + if (*p == '/') + p++; + /* + * Even make sure that the mud administrator has not made an error. + */ + if (!legal_path(p)) { + fprintf(stderr, "'include dirs' must give paths without any '..'\n"); + exit(-1); + } + inc_list[i] = make_shared_string(p); + } + for (i = 0; i < size - 1; i++) + list[strlen(list)] = ':'; +} + +char *main_file_name() +{ + incstate_t *is; + + if (inctop == 0) + return current_file; + is = inctop; + while (is->next) + is = is->next; + return is->file; +} + +/* identifier hash table stuff, size must be an even power of two */ +#define IDENT_HASH_SIZE 1024 +#define IdentHash(s) (whashstr((s)) & (IDENT_HASH_SIZE - 1)) + +/* The identifier table is hashed for speed. The hash chains are circular + * linked lists, so that we can rotate them, since identifier lookup is + * rather irregular (i.e. we're likely to be asked about the same one + * quite a number of times in a row). This isn't as fast as moving entries + * to the front but is done this way for two reasons: + * + * 1. this allows us to keep permanent identifiers consecutive and clean + * up faster + * 2. it would only be faster in cases where two identifiers with the same + * hash value are used often within close proximity in the source. + * This should be rare, esp since the hash table is fairly sparse. + * + * ident_hash_table[hash] points to our current position (last lookup) + * ident_hash_head[hash] points to the first permanent identifier + * ident_hash_tail[hash] points to the last one + * ident_dirty_list is a linked list of identifiers that need to be cleaned + * when we're done; this happens if you define a global or function with + * the same name as an efun or sefun. + */ + +#define CHECK_ELEM(x, y, z) if (!strcmp((x)->name, (y))) { \ + if (((x)->token & IHE_RESWORD) || ((x)->sem_value)) { z } \ + else return 0; } + +ident_hash_elem_t *lookup_ident (const char * name) { + int h = IdentHash(name); + ident_hash_elem_t *hptr, *hptr2; + + if ((hptr = ident_hash_table[h])) { + CHECK_ELEM(hptr, name, return hptr;); + hptr2 = hptr->next; + while (hptr2 != hptr) { + CHECK_ELEM(hptr2, name, ident_hash_table[h] = hptr2; return hptr2;); + hptr2 = hptr2->next; + } + } + return 0; +} + +ident_hash_elem_t *find_or_add_perm_ident (const char * name) { + int h = IdentHash(name); + ident_hash_elem_t *hptr, *hptr2; + + if ((hptr = ident_hash_table[h])) { + if (!strcmp(hptr->name, name)) return hptr; + hptr2 = hptr->next; + while (hptr2 != hptr) { + if (!strcmp(hptr2->name, name)) return hptr2; + hptr2 = hptr2->next; + } + hptr = ALLOCATE(ident_hash_elem_t, TAG_PERM_IDENT, "find_or_add_perm_ident:1"); + hptr->next = ident_hash_head[h]->next; + ident_hash_head[h]->next = hptr; + if (ident_hash_head[h] == ident_hash_tail[h]) + ident_hash_tail[h] = hptr; + } else { + hptr = (ident_hash_table[h] = ALLOCATE(ident_hash_elem_t, TAG_PERM_IDENT, + "find_or_add_perm_ident:2")); + ident_hash_head[h] = hptr; + ident_hash_tail[h] = hptr; + hptr->next = hptr; + } + hptr->name = name; + hptr->token = 0; + hptr->sem_value = 0; + hptr->dn.simul_num = -1; + hptr->dn.local_num = -1; + hptr->dn.global_num = -1; + hptr->dn.efun_num = -1; + hptr->dn.function_num = -1; + hptr->dn.class_num = -1; + return hptr; +} + +typedef struct lname_linked_buf_s { + struct lname_linked_buf_s *next; + char block[4096]; +} lname_linked_buf_t; + +lname_linked_buf_t *lnamebuf = 0; + +int lb_index = 4096; + +static char *alloc_local_name (const char * name) { + int len = strlen(name)+1; + char *res; + + if (lb_index + len > 4096) { + lname_linked_buf_t *new_buf; + new_buf = ALLOCATE(lname_linked_buf_t, TAG_COMPILER, "alloc_local_name"); + new_buf->next = lnamebuf; + lnamebuf = new_buf; + lb_index = 0; + } + res = &(lnamebuf->block[lb_index]); + strcpy(res, name); + lb_index += len; + return res; +} + +int num_free = 0; + +typedef struct ident_hash_elem_list_s { + struct ident_hash_elem_list_s *next; + ident_hash_elem_t items[128]; +} ident_hash_elem_list_t; + +ident_hash_elem_list_t *ihe_list = 0; + +#if 0 +void dump_ihe (ident_hash_elem_t * ihe, int noisy) { + int sv = 0; + if (ihe->token & IHE_RESWORD) { + if (noisy) printf("%s ", ihe->name); + } else { + if (noisy) printf("%s[", ihe->name); + if (ihe->dn.function_num != -1) { + if (noisy) printf("f"); + sv++; + } + if (ihe->dn.simul_num != -1) { + if (noisy) printf("s"); + sv++; + } + if (ihe->dn.efun_num != -1) { + if (noisy) printf("e"); + sv++; + } + if (ihe->dn.local_num != -1) { + if (noisy) printf("l"); + sv++; + } + if (ihe->dn.global_num != -1) { + if (noisy) printf("g"); + sv++; + } + if (ihe->sem_value != sv) { + if (noisy) { + printf("(*%i*)", ihe->sem_value - sv); + } else dump_ihe(ihe, 1); + } + if (noisy) printf("] "); + } +} + +void debug_dump_ident_hash_table (int noisy) { + int zeros = 0; + int i; + ident_hash_elem_t *ihe, *ihe2; + + if (noisy) printf("\n\nIdentifier Hash Table:\n"); + for (i = 0; i < IDENT_HASH_SIZE; i++) { + ihe = ident_hash_table[i]; + if (!ihe) + zeros++; + else { + if (zeros && noisy) printf("<%i zeros>\n", zeros); + zeros = 0; + dump_ihe(ihe, noisy); + ihe2 = ihe->next; + while (ihe2 != ihe) { + dump_ihe(ihe2, noisy); + ihe2 = ihe2->next; + } + if (noisy) printf("\n"); + } + } + if (zeros && noisy) printf("<%i zeros>\n", zeros); +} +#endif + +void free_unused_identifiers() { + ident_hash_elem_list_t *ihel, *next; + lname_linked_buf_t *lnb, *lnbn; + int i; + + /* clean up dirty idents */ + while (ident_dirty_list) { + if (ident_dirty_list->dn.function_num != -1) { + ident_dirty_list->dn.function_num = -1; + ident_dirty_list->sem_value--; + } + if (ident_dirty_list->dn.global_num != -1) { + ident_dirty_list->dn.global_num = -1; + ident_dirty_list->sem_value--; + } + if (ident_dirty_list->dn.class_num != -1) { + ident_dirty_list->dn.class_num = -1; + ident_dirty_list->sem_value--; + } + ident_dirty_list = ident_dirty_list->next_dirty; + } + + for (i = 0; i < IDENT_HASH_SIZE; i++) + if ((ident_hash_table[i] = ident_hash_head[i])) + ident_hash_tail[i]->next = ident_hash_head[i]; + + ihel = ihe_list; + while (ihel) { + next = ihel->next; + FREE(ihel); + ihel = next; + } + ihe_list = 0; + num_free = 0; + + lnb = lnamebuf; + while (lnb) { + lnbn = lnb->next; + FREE(lnb); + lnb = lnbn; + } + lnamebuf = 0; + lb_index = 4096; +#if 0 + debug_dump_ident_hash_table(0); +#endif +} + +static ident_hash_elem_t *quick_alloc_ident_entry() { + if (num_free) { + num_free--; + return &(ihe_list->items[num_free]); + } else { + ident_hash_elem_list_t *ihel; + ihel = ALLOCATE(ident_hash_elem_list_t, TAG_COMPILER, + "quick_alloc_ident_entry"); + ihel->next = ihe_list; + ihe_list = ihel; + num_free = 127; + return &(ihe_list->items[127]); + } +} + +ident_hash_elem_t * +find_or_add_ident (const char * name, int flags) { + int h = IdentHash(name); + ident_hash_elem_t *hptr, *hptr2; + + if ((hptr = ident_hash_table[h])) { + if (!strcmp(hptr->name, name)) { + if ((hptr->token & IHE_PERMANENT) && (flags & FOA_GLOBAL_SCOPE) + && (hptr->dn.function_num==-1)&&(hptr->dn.global_num==-1) + && (hptr->dn.class_num==-1)) { + hptr->next_dirty = ident_dirty_list; + ident_dirty_list = hptr; + } + return hptr; + } + hptr2 = hptr->next; + while (hptr2 != hptr) { + if (!strcmp(hptr2->name, name)) { + if ((hptr2->token & IHE_PERMANENT)&&(flags & FOA_GLOBAL_SCOPE) + && (hptr2->dn.function_num==-1)&&(hptr2->dn.global_num==-1) + && (hptr2->dn.class_num == -1)) { + hptr2->next_dirty = ident_dirty_list; + ident_dirty_list = hptr2; + } + ident_hash_table[h] = hptr2; /* rotate */ + return hptr2; + } + hptr2 = hptr2->next; + } + } + + hptr = quick_alloc_ident_entry(); + if (!(hptr2 = ident_hash_tail[h]) && !(hptr2 = ident_hash_table[h])) { + ident_hash_table[h] = hptr->next = hptr; + } else { + hptr->next = hptr2->next; + hptr2->next = hptr; + } + + if (flags & FOA_NEEDS_MALLOC) { + hptr->name = alloc_local_name(name); + } else { + hptr->name = name; + } + hptr->token = 0; + hptr->sem_value = 0; + hptr->dn.simul_num = -1; + hptr->dn.local_num = -1; + hptr->dn.global_num = -1; + hptr->dn.efun_num = -1; + hptr->dn.function_num = -1; + hptr->dn.class_num = -1; + return hptr; +} + +static void add_keyword_t (const char * name, keyword_t * entry) { + int h = IdentHash(name); + + if (ident_hash_table[h]) { + entry->next = ident_hash_head[h]->next; + ident_hash_head[h]->next = (ident_hash_elem_t *)entry; + if (ident_hash_head[h] == ident_hash_tail[h]) + ident_hash_tail[h] = (ident_hash_elem_t *)entry; + } else { + ident_hash_head[h] = (ident_hash_elem_t *)entry; + ident_hash_tail[h] = (ident_hash_elem_t *)entry; + ident_hash_table[h] = (ident_hash_elem_t *)entry; + entry->next = (ident_hash_elem_t *)entry; + } + entry->token |= IHE_RESWORD; +} + +void init_identifiers() { + int i; + ident_hash_elem_t *ihe; + + init_instrs(); + + /* allocate all three tables together */ + ident_hash_table = CALLOCATE(IDENT_HASH_SIZE * 3, ident_hash_elem_t *, + TAG_IDENT_TABLE, "init_identifiers"); + ident_hash_head = (ident_hash_elem_t **)&ident_hash_table[IDENT_HASH_SIZE]; + ident_hash_tail = (ident_hash_elem_t **)&ident_hash_table[2*IDENT_HASH_SIZE]; + + /* clean all three tables */ + for (i=0; itoken |= IHE_EFUN; + ihe->sem_value++; + ihe->dn.efun_num = i; + } +} + diff --git a/fluffos-2.23-ds03/lex.h b/fluffos-2.23-ds03/lex.h new file mode 100644 index 0000000..94b2eb6 --- /dev/null +++ b/fluffos-2.23-ds03/lex.h @@ -0,0 +1,165 @@ +#ifndef _LEX_H_ +#define _LEX_H_ + +#define DEFMAX 20000 //at least 4 times MAXLINE +#define MAXLINE 4096 +#define MLEN 4096 +#define NSIZE 256 +#define MAX_INSTRS 512 +#define EXPANDMAX 25000 +#define NARGS 25 +#define MARKS '@' + +#define SKIPWHITE while (isspace((unsigned char)*p) && (*p != '\n')) p++ + +#define DEFAULT_NONE 0xff +#define DEFAULT_THIS_OBJECT 0xfe + +#define PRAGMA_STRICT_TYPES 1 +#define PRAGMA_WARNINGS 2 +#define PRAGMA_SAVE_TYPES 4 +#define PRAGMA_SAVE_BINARY 8 +#define PRAGMA_OPTIMIZE 16 +#define PRAGMA_ERROR_CONTEXT 32 +#define PRAGMA_OPTIMIZE_HIGH 64 +/* for find_or_add_ident */ +#define FOA_GLOBAL_SCOPE 0x1 +#define FOA_NEEDS_MALLOC 0x2 + +typedef struct { + SIGNED short local_num, global_num, efun_num; + SIGNED short function_num, simul_num, class_num; +} defined_name_t; + +typedef struct ifstate_s { + struct ifstate_s *next; + int state; +} ifstate_t; + +typedef struct defn_s { + struct defn_s *next; + char *name; + char *exps; + int flags; + int nargs; +} defn_t; + +/* must be a power of 4 */ +#define DEFHASH 128 +#define defhash(s) (whashstr((s)) & (DEFHASH - 1)) + +#define DEF_IS_UNDEFINED 1 +#define DEF_IS_PREDEF 2 +/* used only in edit_source */ +#define DEF_IS_NOT_LOCAL 4 + +/* to speed up cleaning the hash table, and identify the union */ +#define IHE_RESWORD 0x8000 /* reserved word */ +#define IHE_EFUN 0x4000 /* efun name */ +#define IHE_SIMUL 0x2000 /* active simul efun name */ +#define IHE_ORPHAN 0x1000 /* old and unused simul efun name */ +#define IHE_PERMANENT (IHE_RESWORD | IHE_EFUN | IHE_SIMUL | IHE_ORPHAN) +#define TOKEN_MASK 0x0fff + +#define INDENT_HASH_SIZE 1024 /* must be a power of 2 */ + +typedef struct ident_hash_elem_s { + const char *name; + short token; /* only flags */ + unsigned short sem_value; /* for these, a count of the ambiguity */ + struct ident_hash_elem_s *next; +/* the fields above must correspond to struct keyword_t */ + struct ident_hash_elem_s *next_dirty; + defined_name_t dn; +} ident_hash_elem_t; + +typedef struct { + const char *word; + unsigned short token; /* flags here too */ + unsigned short sem_value; /* semantic value for predefined tokens */ + ident_hash_elem_t *next; +/* the fields above must correspond to struct ident_hash_elem */ + short min_args; /* Minimum number of arguments. */ + short max_args; /* Maximum number of arguments. */ + short ret_type; /* The return type used by the compiler. */ + unsigned short arg_type1; /* Type of argument 1 */ + unsigned short arg_type2; /* Type of argument 2 */ + unsigned short arg_type3; /* Type of argument 1 */ + unsigned short arg_type4; /* Type of argument 2 */ + short arg_index; /* Index pointing to where to find arg type */ + short Default; /* an efun to use as default for last + * argument */ +} keyword_t; + +typedef struct lpc_predef_s { + char *flag; + struct lpc_predef_s *next; +} lpc_predef_t; + +#define EXPECT_ELSE 1 +#define EXPECT_ENDIF 2 + +extern lpc_predef_t *lpc_predefs; + +#define isalunum(c) (uisalnum(c) || (c) == '_') + +/* + * Information about all instructions. This is not really needed as the + * automatically generated efun_arg_types[] should be used. + */ + +/* indicates that the instruction is only used at compile time */ +#define F_ALIAS_FLAG 1024 + +typedef struct { + short max_arg, min_arg; /* Can't use char to represent -1 */ + short type[4]; /* need a short to hold the biggest type flag */ + short Default; + short ret_type; + const char *name; + int arg_index; +} instr_t; + +/* + * lex.c + */ +extern instr_t instrs[512]; +extern int current_line; +extern int current_line_base; +extern int current_line_saved; +extern int total_lines; +extern char *current_file; +extern int current_file_id; +extern int pragmas; +extern int num_parse_error; +extern lpc_predef_t *lpc_predefs; +extern int efun_arg_types[]; +extern char yytext[MAXLINE]; +extern keyword_t predefs[]; +extern int lex_fatal; +extern int arrow_efun, evaluate_efun, this_efun, to_float_efun, to_int_efun, new_efun; + +INLINE void push_function_context (void); +void pop_function_context (void); +int yylex (void); +void init_num_args (void); +const char *query_instr_name (int); +char *get_f_name (int); +void set_inc_list (char *); +void start_new_file (int); +void end_new_file (void); +int lookup_predef (const char *); +void add_predefines (void); +char *main_file_name (void); +char *get_defined_name (defined_name_t *); +ident_hash_elem_t *find_or_add_ident (const char *, int); +ident_hash_elem_t *find_or_add_perm_ident (const char *); +ident_hash_elem_t *lookup_ident (const char *); +void free_unused_identifiers (void); +void init_identifiers (void); +char *show_error_context (void); +#ifdef DEBUGMALLOC_EXTENSIONS +void mark_all_defines (void); +#endif + +#endif diff --git a/fluffos-2.23-ds03/local_options.ds b/fluffos-2.23-ds03/local_options.ds new file mode 100644 index 0000000..9cb3e5c --- /dev/null +++ b/fluffos-2.23-ds03/local_options.ds @@ -0,0 +1,916 @@ +/* + * options.h: defines for the compile-time configuration of the MudOS driver + */ + +#ifndef _OPTIONS_H_ +#define _OPTIONS_H_ + +/* + * YOU PROBABLY DO NOT WANT TO MODIFY THIS FILE. + * + * Do 'cp options.h local_options' and edit that instead. local_options, + * if it exists, overrides this file. + * + * The advantage is that when you upgrade to a newer MudOS driver, you can + * simply copy your local_options file into the src directory. The build + * process will warn you if new options have been added that you should + * choose settings for. + */ + +/**************************************************************************** + * EVERY time you change ANYTHING in this file, RECOMPILE from scratch. * + * (type "make clean" then "make" on a UNIX system) Failure to do so may * + * cause the driver to behave oddly. * + ****************************************************************************/ + +/* NOTES: + * Many of the configurable options are now set via the configuration file + * that is specified as the first argument to the driver. + * See port.h for those #defines related to portability (compatibility) if + * you have problems compiling on your system. + * Removing an efun from func_spec.c usually removes most, if not all, + * of the code associated with it. + * Note that anything defined in this file is also visible to LPC files + * surrounded by __. So #define FOO in this file defines __FOO__ for + * all LPC files. This allows code like: + * + * #ifdef __SENSIBLE_MODIFIERS__ + * ... + */ + +/**************************************************************************** + * MALLOC * + * -------- * + * For performance reasons, LP drivers have a variety of memory allocation * + * packages. If you don't care, use the default one on your system: * + * #define SYSMALLOC, #undef the others. * + ****************************************************************************/ + +/* You must choose exactly one of these malloc packages: + * ~~~~ + * SYSMALLOC: + * * Built-in system malloc. + * * No statistics. + * * SYSMALLOC incurs no additional CPU or memory overhead. + * + * SMALLOC: + * * Satoria's smalloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than most system mallocs with modest ammount of memory overhead. + * * Can fall back onto system malloc if sbrk() not ok. + * + * BSDMALLOC: + * * BSD (Berkeley Software Distributions) malloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than SMALLOC but more memory overhead. + * * Requires sbrk(). + */ +#define SYSMALLOC +#undef SMALLOC +#undef BSDMALLOC +#undef MMALLOC + +/* You may optionally choose one (or none) of these malloc wrappers. These + * can be used in conjunction with any of the above malloc packages. + * + * WRAPPEDMALLOC: + * * Limited statistics. + * * Limited additional cpu overhead and no additional memory overhead. + * + * DEBUGMALLOC: + * * Statistics on precisely how much memory has been malloc'd (as well + * as the stats provided by WRAPPEDMALLOC). + * * Incurs a fair amount of overhead (both memory and CPU) + */ +#undef WRAPPEDMALLOC +#undef DEBUGMALLOC + +/* The following add certain bells and whistles to malloc: */ + +/* + * SBRK_OK: do not define this unless SMALLOC is chosen above. + * Defining this causes smalloc to use the low level memory allocation + * routines, and to act as a malloc replacement. Conversely, undef'ing + * SBRK_OK causes smalloc to act as a wrapper for the system malloc + * routines. + * + * Note: + * NeXTStep 3.x users should always #undef SBRK_OK. + */ +#undef SBRK_OK + +/* DO_MSTATS: do not define this unless BSDMALLOC or SMALLOC is chosen above. + * Defining this causes those replacement mallocs to keep statistics that + * the malloc_status() efun will print out (including total memory + * allocated/used). + */ +#undef DO_MSTATS + +/* DEBUGMALLOC_EXTENSIONS: defining this (in addition to DEBUGMALLOC) enables + * the set_malloc_mask(int) and debugmalloc(string,int) efuns. These two + * efuns basically allow you to cause certain malloc's and free's (with tags + * selected by a specified mask) to print debug information (addr, tag, + * description, size) to stdio (in the shell that invoked the driver) or to a + * file. Not defining this does reduce the overhead of DEBUGMALLOC from 16 + * bytes per malloc down to 8. This macro has no effect if DEBUGMALLOC isn't + * defined. + */ +#undef DEBUGMALLOC_EXTENSIONS + +/* CHECK_MEMORY: defining this (in addition to DEBUGMALLOC and + * DEBUGMALLOC_EXTENSIONS) causes the driver to check for memory + * corruption due to writing before the start or end of a block. This + * also adds the check_memory() efun. Takes a considerable ammount + * more memory. Mainly for debugging. + */ +#undef CHECK_MEMORY + +/**************************************************************************** + * COMPATIBILITY * + * --------------- * + * The MudOS driver has evolved quite a bit over the years. These defines * + * are mainly to preserve old behavior in case people didn't want to * + * rewrite the relevant portions of their code. * + * * + * In most cases, code which needs these defines should be rewritten when * + * possible. The 'Compat status' field is designed to give an idea how * + * likely it is that support for that option will be removed in the near * + * future. Certain options are fairly easy to work around, and double * + * the size of the associated code, as well as the maintenance workload, * + * and can make the code significantly more complex or harder to read, so * + * supporting them indefinitely is impractical. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* HAS_STATUS_TYPE: old MudOS drivers had a 'status' type which was + * identical to the 'int' type. Define this to bring it back. + * + * Compat status: very archaic, but easy to support. + */ +#undef HAS_STATUS_TYPE + +/* explode(): + * + * The old behavior (#undef both of the below) strips any number of + * delimiters at the start of the string, and one at the end. So + * explode("..x.y..z..", ".") gives ({ "x", "y", "", "z", "" }) + * + * SANE_EXPLODE_STRING strips off at most one leading delimiter, and + * still strips off one at the end, so the example above gives + * ({ "", "x", "y", "", "z", "" }). + * + * REVERSIBLE_EXPLODE_STRING overrides SANE_EXPLODE_STRING, and makes + * it so that implode(explode(x, y), y) is always x; i.e. no delimiters + * are ever stripped. So the example above gives + * ({ "", "", "x", "y", "", "z", "", "" }). + */ +#define SANE_EXPLODE_STRING +#undef REVERSIBLE_EXPLODE_STRING + +/* CAST_CALL_OTHERS: define this if you want to require casting of call_other's; + * this was the default behavior of the driver prior to this addition. + * + * Compat status: code that requires it doesn't break, and it promotes + * sloppy coding with no benefits. + */ +#undef CAST_CALL_OTHERS + +/* NONINTERACTIVE_STDERR_WRITE: if defined, all writes/tells/etc to + * noninteractive objects will be written to stderr prefixed with a ']' + * (old behavior). + * + * Compat status: Easy to support, and also on the "It's a bug! No, it's + * a feature!" religious war list. + */ +#define NONINTERACTIVE_STDERR_WRITE + +/* NO_LIGHT: define this to disable the set_light() and driver maintenance + * of light levels in objects. You can simulate it via LPC if you want... + * + * Compat status: Very dated, easy to simulate, and gross. + */ +#define NO_LIGHT + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + * process_input() then becomes the only way to deal with player input. + * + * Compat status: next to impossible to simulate, hard to replace, and + * very, very widely used. + */ +#undef NO_ADD_ACTION + +/* NO_SNOOP: disables the snoop() efun and all related functionality. + */ +#undef NO_SNOOP + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + process_input() then becomes the only way to deal with player input. */ + +/* NO_ENVIRONMENT: define this to remove the handling of object containment + * relationships by the driver + * + * Compat status: hard to simulate efficiently, and very widely used. + */ +#undef NO_ENVIRONMENT + +/* NO_WIZARDS: for historical reasons, MudOS used to keep track of who + * is and isn't a wizard. Defining this removes that completely. + * If this is defined, the wizardp() and related efuns don't exist. + * + * Also note that if it is not defined, then non-wizards are always put + * in restricted mode when ed() is used, regardless of the setting of + * the restrict parameter. + * + * Compat status: easy to simulate and dated. + */ +#define NO_WIZARDS + +/* OLD_TYPE_BEHAVIOR: reintroduces a bug in type-checking that effectively + * renders compile time type checking useless. For backwards compatibility. + * + * Compat status: dealing with all the resulting compile errors can be + * a huge pain even if they are correct, and the impact on the code is + * small. + */ +#undef OLD_TYPE_BEHAVIOR + +/* OLD_RANGE_BEHAVIOR: define this if you want negative indexes in string + * or buffer range values (not lvalue, i.e. x[-2..-1]; for e.g. not + * x[-2..-1] = foo, the latter is always illegal) to mean counting from the + * end + * + * Compat status: Not horribly difficult to replace reliance on this, but not + * trivial, and cannot be simulated. + */ +#undef OLD_RANGE_BEHAVIOR + +/* OLD_ED: ed() efun backwards compatible with the old version. The new + * version requires/allows a mudlib front end. + * + * Compat status: Easily simulated. + */ +#undef OLD_ED + +/* In ed auto-indent, + * 1) does the case line get indented after the switch() ? + * 2) How far do we indent? (this can also be set in the mudlib) + */ +#undef ED_INDENT_CASE +#define ED_INDENT_SPACES 4 + +/* SENSIBLE_MODIFIERS: + * Turning this on changes a few things, which may break old code: + * + * (1) 'static' is not recognized; either 'nosave' or 'protected' must + * be used instead. + * (2) The old meaning of 'public' is no longer allowed. Explicit + * functions must be defined at each level to allow access to + * privately inherited functions. + * (3) 'public' now means the default visibility. Previously there was + * no keyword that meant this (before you ask, 'public' meant something + * else, and if you don't know that, you probably don't have any reason + * to care about the old meaning). + */ +#undef SENSIBLE_MODIFIERS + +/**************************************************************************** + * MISCELLANEOUS * + * --------------- * + * Various options that affect the way the driver behaves. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* + * Define this in order to use Fermat@Equilibria's MD5 based crypt() instead + * of the operating system's. It has the advantage of giving the same value + * on all architectures, and being stronger than the standard UNIX crypt(). + */ +#define CUSTOM_CRYPT + +/* + * Some minor tweaks that make it a bit easier to run code designed to run + * on LPmud 3.2/3.2.1. Currently has the following effects: + * + * . m_indices() and m_values() are synonyms for keys() and values(), + * respectively + * . map_delete() returns it's first argument + * . inherit_list() means deep_inherit_list(), not shallow_inherit_list() + * . heart_beat_info() is a synonym for heart_beats() + */ +#undef COMPAT_32 + +/* + * Keep statistics about allocated strings, etc. Which can be viewed with + * the mud_status() efun. If this is off, mud_status() and memory_info() + * ignore allocated strings, but string operations run faster. + */ +#undef STRING_STATS + +/* + * Similarly for arrays ... + */ +#undef ARRAY_STATS + +/* LOG_CATCHES: define this to cause errors that are catch()'d to be + * sent to the debug log anyway. + * + * On by default, because newer libs use catch() a lot, and it's confusing + * if the errors don't show up in the logs. + */ +#define LOG_CATCHES + +/* ARGUMENTS_IN_TRACEBACK: prints out function call arguments in error + * tracebacks, to aid in debugging. Note: it prints the values of + * the arguments at the time of the error, not when the function + * was called. It looks like this: + * + * Failed to load file: read_buffer + * program: command/update.c, object: command/update line 15 + * ' commandHook' in ' clone/user.c' (' clone/user#1')line 72 + * arguments were ("/read_buffer.c") + * ' main' in ' command/update.c' (' command/update')line 15 + * arguments were ("/read_buffer.c") + * + * The only down side is some people like their logs shorter + */ +#undef ARGUMENTS_IN_TRACEBACK + +/* LOCALS_IN_TRACEBACK: similar to ARGUMENTS_IN_TRACEBACK, but for local + * variables. The output looks more or less like: + * + * locals: 1, "local_value" + * + * Same as above. Tends to produce even longer logs, but very useful for + * tracking errors. + */ +#undef LOCALS_IN_TRACEBACK + +/* MUDLIB_ERROR_HANDLER: If you define this, the driver doesn't do any + * handling of runtime errors, other than to turn the heartbeats of + * objects off. Information about the error is passed in a mapping + * to the error_handler() function in the master object. Whatever is + * returned is put in the debug.log. + * + * A good mudlib error handler is one of the best tools for tracking down + * errors. Unfortunately, you need to have one. Check the testsuite or + * other libs for an example. + */ +#define MUDLIB_ERROR_HANDLER + +/* CONFIG_FILE_DIR specifies a directory in which the driver will search for + * config files by default. If you don't wish to use this define, you may + * always specify a full path to the config file when starting the driver. + */ +#define CONFIG_FILE_DIR "./" + +/* DEFAULT_PRAGMAS: This should be a sum of pragmas you want to always + * be on, i.e. + * + * #define DEFAULT_PRAGMAS PRAGMA_STRICT_TYPES + PRAGMA_SAVE_TYPES + * + * will make every LPC file behave as if it had the lines: + * #pragma strict_types + * #pragma save_types + * + * for no default pragmas: + * #define DEFAULT_PRAGMAS 0 + * + * If you don't know what these are, 0 is a good choice. + * + * Supported pragmas: + * PRAGMA_STRICT_TYPES: enforces strict type checking + * PRAGMA_WARNINGS: issues warnings about various dangerous things in + * your code + * PRAGMA_SAVE_TYPES: save the types of function arguments for checking + * calls to functions in this object by objects that + * inherit it. + * PRAGMA_SAVE_BINARY: save a compiled binary version of this file for + * faster loading next time it is needed. + * PRAGMA_OPTIMIZE: make a second pass over the generated code to + * optimize it further. Currently does jump threading. + * PRAGMA_ERROR_CONTEXT:include some text telling where on the line a + * compilation error occured. + */ +#define DEFAULT_PRAGMAS 0 + +/* supress warnings about unused arguments; only warn about unused local + * variables. Makes older code (where argument names were required) compile + * more quietly. + */ +#define SUPPRESS_ARGUMENT_WARNINGS + +/* NO_RESETS: completely disable the periodic calling of reset() */ +#define NO_RESETS + +/* LAZY_RESETS: if this is defined, an object will only have reset() + * called in it when it is touched via call_other() or move_object() + * (assuming enough time has passed since the last reset). If LAZY_RESETS + * is #undef'd, then reset() will be called as always (which guaranteed that + * reset would always be called at least once). The advantage of lazy + * resets is that reset doesn't get called in an object that is touched + * once and never again (which can save memory since some objects won't get + * reloaded that otherwise would). + */ +#undef LAZY_RESETS + +/* SAVE_EXTENSION: defines the file extension used by save_object(). + * and restore_object(). Some sysadmins run scripts that periodically + * scan for and remove files ending in .o (but many mudlibs are already + * set up to use .o thus we leave .o as the default). + */ +#define SAVE_EXTENSION ".o" + +/* NO_ANSI: define if you wish to disallow users from typing in commands that + * contain ANSI escape sequences. Defining NO_ANSI causes all escapes + * (ASCII 27) to be replaced with a space ' ' before the string is passed + * to the action routines added with add_action. + * + * STRIP_BEFORE_PROCESS_INPUT allows the location where the stripping is + * done to be controlled. If it is defined, then process_input() doesn't + * see ANSI characters either; if it is undefined ESC chars can be processed + * by process_input(), but are stripped before add_actions are called. + * Note that if NO_ADD_ACTION is defined, then #define NO_ANSI without + * #define STRIP_BEFORE_PROCESS_INPUT is the same as #undef NO_ANSI. + * + * If you anticipate problems with users intentionally typing in ANSI codes + * to make your terminal flash, etc define this. + */ +#define NO_ANSI +#define STRIP_BEFORE_PROCESS_INPUT + +/* OPCPROF: define this if you wish to enable OPC profiling. Allows a dump + * of the # of times each efun is invoked (via the opcprof() efun). + */ +#define OPCPROF + +/* OPCPROF_2D: define this if you wish to enable 2-D OPC profiling. Allows a + * dump of the # of times each *pair* of eoperators is invoked. + * + * You can't use this and OPCPROF at the same time. + */ +#undef OPCPROF_2D + +/* TRAP_CRASHES: define this if you want MudOS to call crash() in master.c + * and then shutdown when signals are received that would normally crash the + * driver. + */ +#define TRAP_CRASHES + +/* THIS_PLAYER_IN_CALL_OUT: define this if you wish this_player() to be + * usable from within call_out() callbacks. + */ +#define THIS_PLAYER_IN_CALL_OUT + +/* CALLOUT_HANDLES: If this is defined, call_out() returns an integer, which + * can be passed to remove_call_out() or find_call_out(). Removing call_outs + * by name is still allowed, but is significantly less efficient, and also + * doesn't work for function pointers. This option adds 4 bytes overhead + * per callout to keep track of the handle. + */ +#define CALLOUT_HANDLES + +/* FLUSH_OUTPUT_IMMEDIATELY: Causes output to be written to sockets + * immediately after being generated. Useful for debugging. + */ +#undef FLUSH_OUTPUT_IMMEDIATELY + +/* PRIVS: define this if you want object privileges. Your mudlib must + * explicitly make use of this functionality to be useful. Defining this + * this will increase the size of the object structure by 4 bytes (8 bytes + * on the DEC Alpha) and will add a new master apply during object creation + * to "privs_file". In general, privileges can be used to increase the + * granularity of security beyond the current root uid mechanism. + * + * [NOTE: for those who'd rather do such things at the mudlib level, look at + * the inherits() efun and the 'valid_object' apply to master.] + */ +#define PRIVS + +/* INTERACTIVE_CATCH_TELL: define this if you want catch_tell called on + * interactives as well as NPCs. If this is defined, user.c will need a + * catch_tell(msg) method that calls receive(msg); +*/ +#define INTERACTIVE_CATCH_TELL + +/* RECEIVE_ED: define this if you want normal ed output to go to a + receive_ed() apply in the player ob. Some errors still go directly + to output. Useful for post-processing (perhaps colorizing?) ed + output. Prototype: mixed receive_ed(string txt, string fname); + If fname, return a string that ed will output, 0 to let ed handle + the output in the default way, or 1 to handle the output yourself. + If fname == 0, output is help text and you may return any of the above + or an array of strings that will be more'ed. +*/ +#undef RECEIVE_ED + +/* RESTRICTED_ED: define this if you want restricted ed mode enabled. + */ +#define RESTRICTED_ED + +/* NO_SHADOWS: define this if you want to disable shadows in your driver. + */ +#undef NO_SHADOWS + +/* SNOOP_SHADOWED: define this if you want snoop to report what is + * sent to the player even in the event that the player's catch_tell() is + * shadowed and the player may not be seeing what is being sent. Messages + * of this sort will be prefixed with $$. + */ +#undef SNOOP_SHADOWED + +/* RECEIVE_SNOOP: define this if you want snoop text to be sent to + * the receive_snoop() function in the snooper object (instead of being + * sent directly via add_message()). This is useful if you want to + * build a smart client that does something different with snoop messages. + */ +#define RECEIVE_SNOOP + +/* PROFILE_FUNCTIONS: define this to be able to measure the CPU time used by + * all of the user-defined functions in each LPC object. Note: defining + * this adds three long ints (12 bytes on 32-bit machines) to the function + * header structs. Also note that the resolution of the getrusage() timer + * may not be high enough on some machines to give non-zero execution + * times to very small (fast) functions. In particular if the clock + * resolution is 1/60 of a second, then any time less than approxmately 15k + * microseconds will resolve to zero (0). + */ +#define PROFILE_FUNCTIONS + +/* NO_BUFFER_TYPE: if this is #define'd then LPC code using the 'buffer' + * type won't be allowed to compile (since the 'buffer' type won't be + * recognized by the lexer). + */ +#undef NO_BUFFER_TYPE + +/* BINARIES: define this to enable the 'save_binary' pragma. + * This pragma, when set in a program, will cause it to save a + * binary image when loaded, so that subsequent loadings will + * be much faster. The binaries are saved in the directory + * specified in the configuration file. The binaries will not + * load if the LPC source or any of the inherited or included + * files are out of date, in which case the file is compiled + * normally (and may save a new binary). + * + * In order to save the binary, valid_save_binary() is called + * in master.c, and is passed the name of the source file. If + * this returns a non-zero value, the binary is allowed to be + * saved. Allowing any file by any wizard to be saved as a + * binary is convenient, but may take up a lot of disk space. + */ +#undef BINARIES + +/* ARRAY_RESERVED_WORD: If this is defined then the word 'array' can + * be used to define arrays, as in: + * + * int array x = ({ .... }); + * + * A side effect is that 'array' cannot be a variable or function name. + */ +#define ARRAY_RESERVED_WORD + +/* REF_RESERVED_WORD: If this is defined then the word 'ref' can be + * used to pass arguments to functions by value. Example: + * + * void inc(int ref x) { + * x++; + * } + * + * ... y = 1; inc(ref y); ... + * + * A side effect is that 'ref' cannot be a variable or function name. + * + * Note: ref must be used in *both* places; this is intentional. It protects + * against passing references to routines which don't intend to return values + * through their arguments, and against forgetting to pass a reference + * to a function which wants one (or accidentally having a variable modified!) + */ +#define REF_RESERVED_WORD + +/**************************************************************************** + * PACKAGES * + * -------- * + * Defining some/all of the following add certain efuns, and sometimes * + * add/remove code from the driver. * + * * + * if PACKAGE_XYZZY is defined here, then the code in packages/xyzzy.c * + * and the efuns in packages/xyzzy_spec.c will be added to the driver. * + ****************************************************************************/ + +/* various miscellaneous efuns */ +#define PACKAGE_CONTRIB + +/* efuns that are only of use to those that know something about driver + internals */ +#define PACKAGE_DEVELOP + +/* PACKAGE_MATH: determines whether or not the math efuns (for floats) are + included. + */ +#define PACKAGE_MATH + +/* PACKAGE_MATRIX: determines whether or not the 3d graphics efuns (for floats) + * are included - see packages/matrix.spec for a list. + */ +#define PACKAGE_MATRIX + +/* PACKAGE_MUDLIB_STATS: define this to enable domain and author stats + * maintenance by the driver. These mudlib stats are more domain + * based than user based, and replaces the traditional wiz_list stats. + */ +#define PACKAGE_MUDLIB_STATS + +/* PACKAGE_SOCKETS: define this to enable the socket efunctions. This + * causes HAS_SOCKETS to be defined for all LPC objects. + */ +#define PACKAGE_SOCKETS + +/* PACKAGE_PARSER: Natural language parsing efuns for interactive fiction + * type applications + */ +#define PACKAGE_PARSER + +/* PACKAGE_EXTERNAL: Allows the driver to exec() commands specified in the + * config file. + */ +#undef PACKAGE_EXTERNAL + +/* NUM_EXTERNAL_CMDS: the number of external commands supported */ +#define NUM_EXTERNAL_CMDS 100 + +/* PACKAGE_DB: efuns for external database access using msql */ +#undef PACKAGE_DB + +/* If PACKAGE_DB is defined above, you must pick ONE of the following supported + * databases + */ +#ifdef PACKAGE_DB +#undef USE_MSQL +#undef MSQL +#define USE_MYSQL 2 +#define MY_SQL +#endif + +/**************************************************************************** + * UID PACKAGE * + * ----------- * + * UIDS are the basis for some mudlib security systems. Basically, they're * + * preserved for backwards compatibility, as several ways of breaking * + * almost any system which relies on them are known. (No, it's not a flaw * + * of uids; only that b/c of the ease with which LPC objects can call * + * each other, it's far too easy to leave holes) * + * * + * If you don't care about security, the first option is probably what you * + * want. * + ****************************************************************************/ + +/* + * PACKAGE_UIDS: define this if you want a driver that does use uids. + * + */ +#undef PACKAGE_UIDS + +/*PACKAGE DWLIB: some discworld mudlib simuls coded in C (well just one right + now) */ + +#undef PACKAGE_DWLIB + +/* AUTO_SETEUID: when an object is created it's euid is automatically set to + * the equivalent of seteuid(getuid(this_object())). undef AUTO_SETEUID + * if you would rather have the euid of the created object be set to 0. + */ +#undef AUTO_SETEUID + +/* AUTO_TRUST_BACKBONE: define this if you want objects with the backbone + * uid to automatically be trusted and to have their euid set to the uid of + * the object that forced the object's creation. + */ +#undef AUTO_TRUST_BACKBONE + +/************************************************************************* + * FOR EXPERIENCED USERS * + * ----------------------- * + * Most of these options will probably be of no interest to many users. * + *************************************************************************/ + +/* USE_32BIT_ADDRESSES: Use 32 bits for addresses of function, instead of + * the usual 16 bits. This increases the maximum program size from 64k + * of LPC bytecode (NOT source) to 4 GB. Branches are still 16 bits, + * imposing a 64k limit on catch(), if(), switch(), loops, and most other + * control structures. It would take an extremely large function to hit + * those limits, though. + * + * Overhead: 2 bytes/function with LPC->C off. Having LPC->C on forces + * this option, since it needs 4 bytes to store the function pointers + * anyway, and this setting is ignored. + */ +#undef USE_32BIT_ADDRESSES + +/* HEARTBEAT_INTERVAL: define heartbeat interval in microseconds (us). + * 1,000,000 us = 1 second. The value of this macro specifies + * the frequency with which the heart_beat method will be called in + * those LPC objects which have called set_heart_beat(1). + * + * [NOTE: if ualarm() isn't available, alarm() is used instead. Since + * alarm() requires its argument in units of a second, we map 1 - 1,000,000 us + * to an actual interval of one (1) second and 1,000,001 - 2,000,000 maps to + * an actual interval of two (2) seconds, etc.] + */ +#define HEARTBEAT_INTERVAL 1 + +/* + * CALLOUT_CYCLE_SIZE: This is the number of slots in the call_out list. + * It should be approximately the average number of active call_outs, or + * a few times smaller. It should also be a power of 2, and also be relatively + * prime to any common call_out lengths. If all this is too confusing, 32 + * isn't a bad number :-) + */ +#define CALLOUT_CYCLE_SIZE 32 + +/* LARGEST_PRINTABLE_STRING: defines the size of the vsprintf() buffer in + * comm.c's add_message(). Instead of blindly making this value larger, + * your mudlib should be coded to not send huge strings to users. + */ +#define LARGEST_PRINTABLE_STRING 32768 + +/* MESSAGE_BUFFER_SIZE: determines the size of the buffer for output that + * is sent to users. + */ +#define MESSAGE_BUFFER_SIZE 4096 + +/* APPLY_CACHE_BITS: defines the number of bits to use in the call_other cache + * (in interpret.c). + * + * Memory overhead is (1 << APPLY_CACHE_BITS)*16. + * [assuming 32 bit pointers and 16 bit shorts] + * + * ACB: entries: overhead: + * 6 64 1k + * 8 256 4k + * 10 1024 16k + * 12 4096 64k + * 14 16384 256k + * 16 65536 1M + */ +#define APPLY_CACHE_BITS 11 + +/* CACHE_STATS: define this if you want call_other (apply_low) cache + * statistics. Causes HAS_CACHE_STATS to be defined in all LPC objects. + */ +#define CACHE_STATS + +/* TRACE: define this to enable the trace() and traceprefix() efuns. + * (keeping this undefined will cause the driver to run faster). + */ +#undef TRACE + +/* RUNTIME_LOADING: On systems which support it, it allows LPC->C compilation + * 'on the fly' without having to recompile the driver. + * + * Note: This currently only works on machines that have the dlopen() system + * call. SunOS and IRIX do, as do a number of others. AIX and Ultrix don't. + * Linux does if you are using ELF. + */ +#undef RUNTIME_LOADING + +/* TRACE_CODE: define this to enable code tracing (the driver will print + * out the previous lines of code to an error) eval_instruction() runs about + * twice as fast when this is not defined (for the most common eoperators). + */ +#undef TRACE_CODE + +/* HEART_BEAT_CHUNK: The number of heart_beat chunks allocated at a time. + * A large number wastes memory as some will be sitting around unused, while + * a small one wastes more CPU reallocating when it needs to grow. Default + * to a medium value. + */ +#define HEART_BEAT_CHUNK 32 + +/* SERVER_IP: For machines with multiple IP addresses, this specifies which + * one to use. This is useful for IP accounting and is necessary to be + * able to do ident lookups on such machines. + * + * example: #define SERVER_IP "194.229.18.27" + */ +#undef SERVER_IP + +/* Some maximum string sizes + */ +#define SMALL_STRING_SIZE 100 +#define LARGE_STRING_SIZE 1000 +#define COMMAND_BUF_SIZE 2000 + +/* Number of levels of nested datastructures allowed -- this limit prevents + * crashes from occuring when saving objects containing variables containing + * recursive datastructures (with circular references). + */ +#define MAX_SAVE_SVALUE_DEPTH 100 + +/* Miscellaneous config options that should probably be in the runtime + * config file. + */ +/* MAX_LOCAL: maximum number of local variables allowed per LPC function */ +#define CFG_MAX_LOCAL_VARIABLES 50 +/* Increasing max global vars beyond 256 is not recommended */ +#define CFG_MAX_GLOBAL_VARIABLES 256 + +#define CFG_EVALUATOR_STACK_SIZE 3000 +#define CFG_COMPILER_STACK_SIZE 600000 +#define CFG_MAX_CALL_DEPTH 150 +/* This must be one of 4, 16, 64, 256, 1024, 4096 */ +#define CFG_LIVING_HASH_SIZE 256 + +/* NEXT_MALLOC_DEBUG: define this if using a NeXT and you want to enable + * the malloc_check() and/or malloc_debug() efuns. Run the 'man malloc_debug' + * command on the NeXT to find out what the arguments to malloc_debug(int) + * mean. The malloc_check() efun calls the NeXT NXMallocCheck() system + * call which does a consistency check on malloc's data structures (this + * consistency check is done at each malloc() and free() for certain + * malloc_debug() levels). A non-zero return value indicates there was + * a consistency problem. For those NeXT users wanting a bit more + * performance out of malloc, try defining NEXT_MALLOC_DEBUG and calling the + * malloc_debug(-1) efun (with an arg of -1). This will turn all + * malloc debugging off and call malloc_singlethreaded() which the NeXT + * malloc man page claims can make NeXT system malloc 10% to 15% faster. + * + * [NOTE: This #define has no affect on the driver if not using the + * NeXTSTEP OS.] + * + * Warning: if you use a NeXT and define NEXT_MALLOC_DEBUG, be sure to + * protect the use of the malloc_check() and malloc_debug() efuns + * since setting certain debug levels can cause malloc() and free() + * to become _very_ slow (protect efuns by using simul_efuns and + * valid_override). + * + * [NOTE: malloc_debug(6) is a good compromise between efficiency and + * completeness of malloc debugging (malloc/free will be about half as fast).] + */ +#undef NEXT_MALLOC_DEBUG + + +/* GET_CHAR_IS_BUFFERED: Normally get_char() is unbuffered. That is, once + * a character is received for get_char(), anything else is in the input + * stream is immediately thrown away. This can be very undesirable, especially + * if you're calling get_char() again from the handler from the previous call. + * Define this if you want get_char() to be buffered. In this case, the buffer + * will only get flushed if get_char() is not called from the first get_char()'s + * LPC callback handler. + */ +#define GET_CHAR_IS_BUFFERED + +/* PACKAGE_COMPRESS: Enable MCCP support and compressed save files + SAVE_GZ_EXTENSION: save extension for compressed files + */ +#undef HAVE_ZLIB +#undef PACKAGE_COMPRESS +#define SAVE_GZ_EXTENSION ".o.gz" + +/* CALL_OTHER_TYPE_CHECK: enable type checking for call_other() + * (-> operator on objects) + */ +#undef CALL_OTHER_TYPE_CHECK + +/* CALL_OTHER_WARN, make it warning instead of errors */ +#undef CALL_OTHER_WARN + +/* WARN_TAB: Some versions of the editor built in indent function use + * tabs for indenting. This options turns on a warning message for + * files indented with tabs instead of spaces. + */ +#define WARN_TAB + +/* USE_ICONV: Use iconv to translate input and output from/to the users char + * encoding + */ +#undef USE_ICONV + +/* WOMBLES: don't allow spaces between start/end of array/mapping/functional token chars so ({1,2,3}) still works, but ( { 1 , 2 , 3 } ) doesn't and ({ 1 , 2 , 3 }) does.*/ +#undef WOMBLES + +/* ALLOW_INHERIT_AFTER_FUNCTION: allow inheriting after functions have been defined (this includes prototypes). This caused crashes in v22.2a but it may have been fixed since */ +#define ALLOW_INHERIT_AFTER_FUNCTION +#undef ALLOW_INHERIT_AFTER_GLOBAL_VARIABLES +/*PACKAGE_ASYNC: adds some efuns for asyncronous IO */ +#undef PACKAGE_ASYNC + +#define PACKAGE_DSLIB +#define PROG_REF_TYPE int +#define PARSE_DEBUG +#define FLUFFOS +#define HAS_CONSOLE +#define ANSI_SUBSTITUTE 0x1e +#endif +#undef IPV6 +#undef MALLOC64 +#undef PACKAGE_CRYPTO +#undef PACKAGE_SHA1 +#undef MALLOC32 +#undef DTRACE +#define WARN_OLD_RANGE_BEHAVIOR +#define STRUCT_CLASS +#undef STRUCT_STRUCT diff --git a/fluffos-2.23-ds03/local_options.ds.debug b/fluffos-2.23-ds03/local_options.ds.debug new file mode 100644 index 0000000..82a6da6 --- /dev/null +++ b/fluffos-2.23-ds03/local_options.ds.debug @@ -0,0 +1,916 @@ +/* + * options.h: defines for the compile-time configuration of the MudOS driver + */ + +#ifndef _OPTIONS_H_ +#define _OPTIONS_H_ + +/* + * YOU PROBABLY DO NOT WANT TO MODIFY THIS FILE. + * + * Do 'cp options.h local_options' and edit that instead. local_options, + * if it exists, overrides this file. + * + * The advantage is that when you upgrade to a newer MudOS driver, you can + * simply copy your local_options file into the src directory. The build + * process will warn you if new options have been added that you should + * choose settings for. + */ + +/**************************************************************************** + * EVERY time you change ANYTHING in this file, RECOMPILE from scratch. * + * (type "make clean" then "make" on a UNIX system) Failure to do so may * + * cause the driver to behave oddly. * + ****************************************************************************/ + +/* NOTES: + * Many of the configurable options are now set via the configuration file + * that is specified as the first argument to the driver. + * See port.h for those #defines related to portability (compatibility) if + * you have problems compiling on your system. + * Removing an efun from func_spec.c usually removes most, if not all, + * of the code associated with it. + * Note that anything defined in this file is also visible to LPC files + * surrounded by __. So #define FOO in this file defines __FOO__ for + * all LPC files. This allows code like: + * + * #ifdef __SENSIBLE_MODIFIERS__ + * ... + */ + +/**************************************************************************** + * MALLOC * + * -------- * + * For performance reasons, LP drivers have a variety of memory allocation * + * packages. If you don't care, use the default one on your system: * + * #define SYSMALLOC, #undef the others. * + ****************************************************************************/ + +/* You must choose exactly one of these malloc packages: + * ~~~~ + * SYSMALLOC: + * * Built-in system malloc. + * * No statistics. + * * SYSMALLOC incurs no additional CPU or memory overhead. + * + * SMALLOC: + * * Satoria's smalloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than most system mallocs with modest ammount of memory overhead. + * * Can fall back onto system malloc if sbrk() not ok. + * + * BSDMALLOC: + * * BSD (Berkeley Software Distributions) malloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than SMALLOC but more memory overhead. + * * Requires sbrk(). + */ +#define SYSMALLOC +#undef SMALLOC +#undef BSDMALLOC +#undef MMALLOC + +/* You may optionally choose one (or none) of these malloc wrappers. These + * can be used in conjunction with any of the above malloc packages. + * + * WRAPPEDMALLOC: + * * Limited statistics. + * * Limited additional cpu overhead and no additional memory overhead. + * + * DEBUGMALLOC: + * * Statistics on precisely how much memory has been malloc'd (as well + * as the stats provided by WRAPPEDMALLOC). + * * Incurs a fair amount of overhead (both memory and CPU) + */ +#undef WRAPPEDMALLOC +#define DEBUGMALLOC + +/* The following add certain bells and whistles to malloc: */ + +/* + * SBRK_OK: do not define this unless SMALLOC is chosen above. + * Defining this causes smalloc to use the low level memory allocation + * routines, and to act as a malloc replacement. Conversely, undef'ing + * SBRK_OK causes smalloc to act as a wrapper for the system malloc + * routines. + * + * Note: + * NeXTStep 3.x users should always #undef SBRK_OK. + */ +#undef SBRK_OK + +/* DO_MSTATS: do not define this unless BSDMALLOC or SMALLOC is chosen above. + * Defining this causes those replacement mallocs to keep statistics that + * the malloc_status() efun will print out (including total memory + * allocated/used). + */ +#undef DO_MSTATS + +/* DEBUGMALLOC_EXTENSIONS: defining this (in addition to DEBUGMALLOC) enables + * the set_malloc_mask(int) and debugmalloc(string,int) efuns. These two + * efuns basically allow you to cause certain malloc's and free's (with tags + * selected by a specified mask) to print debug information (addr, tag, + * description, size) to stdio (in the shell that invoked the driver) or to a + * file. Not defining this does reduce the overhead of DEBUGMALLOC from 16 + * bytes per malloc down to 8. This macro has no effect if DEBUGMALLOC isn't + * defined. + */ +#define DEBUGMALLOC_EXTENSIONS + +/* CHECK_MEMORY: defining this (in addition to DEBUGMALLOC and + * DEBUGMALLOC_EXTENSIONS) causes the driver to check for memory + * corruption due to writing before the start or end of a block. This + * also adds the check_memory() efun. Takes a considerable ammount + * more memory. Mainly for debugging. + */ +#undef CHECK_MEMORY + +/**************************************************************************** + * COMPATIBILITY * + * --------------- * + * The MudOS driver has evolved quite a bit over the years. These defines * + * are mainly to preserve old behavior in case people didn't want to * + * rewrite the relevant portions of their code. * + * * + * In most cases, code which needs these defines should be rewritten when * + * possible. The 'Compat status' field is designed to give an idea how * + * likely it is that support for that option will be removed in the near * + * future. Certain options are fairly easy to work around, and double * + * the size of the associated code, as well as the maintenance workload, * + * and can make the code significantly more complex or harder to read, so * + * supporting them indefinitely is impractical. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* HAS_STATUS_TYPE: old MudOS drivers had a 'status' type which was + * identical to the 'int' type. Define this to bring it back. + * + * Compat status: very archaic, but easy to support. + */ +#undef HAS_STATUS_TYPE + +/* explode(): + * + * The old behavior (#undef both of the below) strips any number of + * delimiters at the start of the string, and one at the end. So + * explode("..x.y..z..", ".") gives ({ "x", "y", "", "z", "" }) + * + * SANE_EXPLODE_STRING strips off at most one leading delimiter, and + * still strips off one at the end, so the example above gives + * ({ "", "x", "y", "", "z", "" }). + * + * REVERSIBLE_EXPLODE_STRING overrides SANE_EXPLODE_STRING, and makes + * it so that implode(explode(x, y), y) is always x; i.e. no delimiters + * are ever stripped. So the example above gives + * ({ "", "", "x", "y", "", "z", "", "" }). + */ +#define SANE_EXPLODE_STRING +#undef REVERSIBLE_EXPLODE_STRING + +/* CAST_CALL_OTHERS: define this if you want to require casting of call_other's; + * this was the default behavior of the driver prior to this addition. + * + * Compat status: code that requires it doesn't break, and it promotes + * sloppy coding with no benefits. + */ +#undef CAST_CALL_OTHERS + +/* NONINTERACTIVE_STDERR_WRITE: if defined, all writes/tells/etc to + * noninteractive objects will be written to stderr prefixed with a ']' + * (old behavior). + * + * Compat status: Easy to support, and also on the "It's a bug! No, it's + * a feature!" religious war list. + */ +#define NONINTERACTIVE_STDERR_WRITE + +/* NO_LIGHT: define this to disable the set_light() and driver maintenance + * of light levels in objects. You can simulate it via LPC if you want... + * + * Compat status: Very dated, easy to simulate, and gross. + */ +#define NO_LIGHT + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + * process_input() then becomes the only way to deal with player input. + * + * Compat status: next to impossible to simulate, hard to replace, and + * very, very widely used. + */ +#undef NO_ADD_ACTION + +/* NO_SNOOP: disables the snoop() efun and all related functionality. + */ +#undef NO_SNOOP + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + process_input() then becomes the only way to deal with player input. */ + +/* NO_ENVIRONMENT: define this to remove the handling of object containment + * relationships by the driver + * + * Compat status: hard to simulate efficiently, and very widely used. + */ +#undef NO_ENVIRONMENT + +/* NO_WIZARDS: for historical reasons, MudOS used to keep track of who + * is and isn't a wizard. Defining this removes that completely. + * If this is defined, the wizardp() and related efuns don't exist. + * + * Also note that if it is not defined, then non-wizards are always put + * in restricted mode when ed() is used, regardless of the setting of + * the restrict parameter. + * + * Compat status: easy to simulate and dated. + */ +#define NO_WIZARDS + +/* OLD_TYPE_BEHAVIOR: reintroduces a bug in type-checking that effectively + * renders compile time type checking useless. For backwards compatibility. + * + * Compat status: dealing with all the resulting compile errors can be + * a huge pain even if they are correct, and the impact on the code is + * small. + */ +#undef OLD_TYPE_BEHAVIOR + +/* OLD_RANGE_BEHAVIOR: define this if you want negative indexes in string + * or buffer range values (not lvalue, i.e. x[-2..-1]; for e.g. not + * x[-2..-1] = foo, the latter is always illegal) to mean counting from the + * end + * + * Compat status: Not horribly difficult to replace reliance on this, but not + * trivial, and cannot be simulated. + */ +#undef OLD_RANGE_BEHAVIOR + +/* OLD_ED: ed() efun backwards compatible with the old version. The new + * version requires/allows a mudlib front end. + * + * Compat status: Easily simulated. + */ +#undef OLD_ED + +/* In ed auto-indent, + * 1) does the case line get indented after the switch() ? + * 2) How far do we indent? (this can also be set in the mudlib) + */ +#undef ED_INDENT_CASE +#define ED_INDENT_SPACES 4 + +/* SENSIBLE_MODIFIERS: + * Turning this on changes a few things, which may break old code: + * + * (1) 'static' is not recognized; either 'nosave' or 'protected' must + * be used instead. + * (2) The old meaning of 'public' is no longer allowed. Explicit + * functions must be defined at each level to allow access to + * privately inherited functions. + * (3) 'public' now means the default visibility. Previously there was + * no keyword that meant this (before you ask, 'public' meant something + * else, and if you don't know that, you probably don't have any reason + * to care about the old meaning). + */ +#undef SENSIBLE_MODIFIERS + +/**************************************************************************** + * MISCELLANEOUS * + * --------------- * + * Various options that affect the way the driver behaves. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* + * Define this in order to use Fermat@Equilibria's MD5 based crypt() instead + * of the operating system's. It has the advantage of giving the same value + * on all architectures, and being stronger than the standard UNIX crypt(). + */ +#define CUSTOM_CRYPT + +/* + * Some minor tweaks that make it a bit easier to run code designed to run + * on LPmud 3.2/3.2.1. Currently has the following effects: + * + * . m_indices() and m_values() are synonyms for keys() and values(), + * respectively + * . map_delete() returns it's first argument + * . inherit_list() means deep_inherit_list(), not shallow_inherit_list() + * . heart_beat_info() is a synonym for heart_beats() + */ +#undef COMPAT_32 + +/* + * Keep statistics about allocated strings, etc. Which can be viewed with + * the mud_status() efun. If this is off, mud_status() and memory_info() + * ignore allocated strings, but string operations run faster. + */ +#define STRING_STATS + +/* + * Similarly for arrays ... + */ +#define ARRAY_STATS + +/* LOG_CATCHES: define this to cause errors that are catch()'d to be + * sent to the debug log anyway. + * + * On by default, because newer libs use catch() a lot, and it's confusing + * if the errors don't show up in the logs. + */ +#define LOG_CATCHES + +/* ARGUMENTS_IN_TRACEBACK: prints out function call arguments in error + * tracebacks, to aid in debugging. Note: it prints the values of + * the arguments at the time of the error, not when the function + * was called. It looks like this: + * + * Failed to load file: read_buffer + * program: command/update.c, object: command/update line 15 + * ' commandHook' in ' clone/user.c' (' clone/user#1')line 72 + * arguments were ("/read_buffer.c") + * ' main' in ' command/update.c' (' command/update')line 15 + * arguments were ("/read_buffer.c") + * + * The only down side is some people like their logs shorter + */ +#define ARGUMENTS_IN_TRACEBACK + +/* LOCALS_IN_TRACEBACK: similar to ARGUMENTS_IN_TRACEBACK, but for local + * variables. The output looks more or less like: + * + * locals: 1, "local_value" + * + * Same as above. Tends to produce even longer logs, but very useful for + * tracking errors. + */ +#define LOCALS_IN_TRACEBACK + +/* MUDLIB_ERROR_HANDLER: If you define this, the driver doesn't do any + * handling of runtime errors, other than to turn the heartbeats of + * objects off. Information about the error is passed in a mapping + * to the error_handler() function in the master object. Whatever is + * returned is put in the debug.log. + * + * A good mudlib error handler is one of the best tools for tracking down + * errors. Unfortunately, you need to have one. Check the testsuite or + * other libs for an example. + */ +#define MUDLIB_ERROR_HANDLER + +/* CONFIG_FILE_DIR specifies a directory in which the driver will search for + * config files by default. If you don't wish to use this define, you may + * always specify a full path to the config file when starting the driver. + */ +#define CONFIG_FILE_DIR "./" + +/* DEFAULT_PRAGMAS: This should be a sum of pragmas you want to always + * be on, i.e. + * + * #define DEFAULT_PRAGMAS PRAGMA_STRICT_TYPES + PRAGMA_SAVE_TYPES + * + * will make every LPC file behave as if it had the lines: + * #pragma strict_types + * #pragma save_types + * + * for no default pragmas: + * #define DEFAULT_PRAGMAS 0 + * + * If you don't know what these are, 0 is a good choice. + * + * Supported pragmas: + * PRAGMA_STRICT_TYPES: enforces strict type checking + * PRAGMA_WARNINGS: issues warnings about various dangerous things in + * your code + * PRAGMA_SAVE_TYPES: save the types of function arguments for checking + * calls to functions in this object by objects that + * inherit it. + * PRAGMA_SAVE_BINARY: save a compiled binary version of this file for + * faster loading next time it is needed. + * PRAGMA_OPTIMIZE: make a second pass over the generated code to + * optimize it further. Currently does jump threading. + * PRAGMA_ERROR_CONTEXT:include some text telling where on the line a + * compilation error occured. + */ +#define DEFAULT_PRAGMAS 0 + +/* supress warnings about unused arguments; only warn about unused local + * variables. Makes older code (where argument names were required) compile + * more quietly. + */ +#define SUPPRESS_ARGUMENT_WARNINGS + +/* NO_RESETS: completely disable the periodic calling of reset() */ +#undef NO_RESETS + +/* LAZY_RESETS: if this is defined, an object will only have reset() + * called in it when it is touched via call_other() or move_object() + * (assuming enough time has passed since the last reset). If LAZY_RESETS + * is #undef'd, then reset() will be called as always (which guaranteed that + * reset would always be called at least once). The advantage of lazy + * resets is that reset doesn't get called in an object that is touched + * once and never again (which can save memory since some objects won't get + * reloaded that otherwise would). + */ +#undef LAZY_RESETS + +/* SAVE_EXTENSION: defines the file extension used by save_object(). + * and restore_object(). Some sysadmins run scripts that periodically + * scan for and remove files ending in .o (but many mudlibs are already + * set up to use .o thus we leave .o as the default). + */ +#define SAVE_EXTENSION ".o" + +/* NO_ANSI: define if you wish to disallow users from typing in commands that + * contain ANSI escape sequences. Defining NO_ANSI causes all escapes + * (ASCII 27) to be replaced with a space ' ' before the string is passed + * to the action routines added with add_action. + * + * STRIP_BEFORE_PROCESS_INPUT allows the location where the stripping is + * done to be controlled. If it is defined, then process_input() doesn't + * see ANSI characters either; if it is undefined ESC chars can be processed + * by process_input(), but are stripped before add_actions are called. + * Note that if NO_ADD_ACTION is defined, then #define NO_ANSI without + * #define STRIP_BEFORE_PROCESS_INPUT is the same as #undef NO_ANSI. + * + * If you anticipate problems with users intentionally typing in ANSI codes + * to make your terminal flash, etc define this. + */ +#define NO_ANSI +#define STRIP_BEFORE_PROCESS_INPUT + +/* OPCPROF: define this if you wish to enable OPC profiling. Allows a dump + * of the # of times each efun is invoked (via the opcprof() efun). + */ +#define OPCPROF + +/* OPCPROF_2D: define this if you wish to enable 2-D OPC profiling. Allows a + * dump of the # of times each *pair* of eoperators is invoked. + * + * You can't use this and OPCPROF at the same time. + */ +#undef OPCPROF_2D + +/* TRAP_CRASHES: define this if you want MudOS to call crash() in master.c + * and then shutdown when signals are received that would normally crash the + * driver. + */ +#define TRAP_CRASHES + +/* THIS_PLAYER_IN_CALL_OUT: define this if you wish this_player() to be + * usable from within call_out() callbacks. + */ +#define THIS_PLAYER_IN_CALL_OUT + +/* CALLOUT_HANDLES: If this is defined, call_out() returns an integer, which + * can be passed to remove_call_out() or find_call_out(). Removing call_outs + * by name is still allowed, but is significantly less efficient, and also + * doesn't work for function pointers. This option adds 4 bytes overhead + * per callout to keep track of the handle. + */ +#define CALLOUT_HANDLES + +/* FLUSH_OUTPUT_IMMEDIATELY: Causes output to be written to sockets + * immediately after being generated. Useful for debugging. + */ +#undef FLUSH_OUTPUT_IMMEDIATELY + +/* PRIVS: define this if you want object privileges. Your mudlib must + * explicitly make use of this functionality to be useful. Defining this + * this will increase the size of the object structure by 4 bytes (8 bytes + * on the DEC Alpha) and will add a new master apply during object creation + * to "privs_file". In general, privileges can be used to increase the + * granularity of security beyond the current root uid mechanism. + * + * [NOTE: for those who'd rather do such things at the mudlib level, look at + * the inherits() efun and the 'valid_object' apply to master.] + */ +#define PRIVS + +/* INTERACTIVE_CATCH_TELL: define this if you want catch_tell called on + * interactives as well as NPCs. If this is defined, user.c will need a + * catch_tell(msg) method that calls receive(msg); +*/ +#define INTERACTIVE_CATCH_TELL + +/* RECEIVE_ED: define this if you want normal ed output to go to a + receive_ed() apply in the player ob. Some errors still go directly + to output. Useful for post-processing (perhaps colorizing?) ed + output. Prototype: mixed receive_ed(string txt, string fname); + If fname, return a string that ed will output, 0 to let ed handle + the output in the default way, or 1 to handle the output yourself. + If fname == 0, output is help text and you may return any of the above + or an array of strings that will be more'ed. +*/ +#undef RECEIVE_ED + +/* RESTRICTED_ED: define this if you want restricted ed mode enabled. + */ +#define RESTRICTED_ED + +/* NO_SHADOWS: define this if you want to disable shadows in your driver. + */ +#undef NO_SHADOWS + +/* SNOOP_SHADOWED: define this if you want snoop to report what is + * sent to the player even in the event that the player's catch_tell() is + * shadowed and the player may not be seeing what is being sent. Messages + * of this sort will be prefixed with $$. + */ +#undef SNOOP_SHADOWED + +/* RECEIVE_SNOOP: define this if you want snoop text to be sent to + * the receive_snoop() function in the snooper object (instead of being + * sent directly via add_message()). This is useful if you want to + * build a smart client that does something different with snoop messages. + */ +#define RECEIVE_SNOOP + +/* PROFILE_FUNCTIONS: define this to be able to measure the CPU time used by + * all of the user-defined functions in each LPC object. Note: defining + * this adds three long ints (12 bytes on 32-bit machines) to the function + * header structs. Also note that the resolution of the getrusage() timer + * may not be high enough on some machines to give non-zero execution + * times to very small (fast) functions. In particular if the clock + * resolution is 1/60 of a second, then any time less than approxmately 15k + * microseconds will resolve to zero (0). + */ +#define PROFILE_FUNCTIONS + +/* NO_BUFFER_TYPE: if this is #define'd then LPC code using the 'buffer' + * type won't be allowed to compile (since the 'buffer' type won't be + * recognized by the lexer). + */ +#undef NO_BUFFER_TYPE + +/* BINARIES: define this to enable the 'save_binary' pragma. + * This pragma, when set in a program, will cause it to save a + * binary image when loaded, so that subsequent loadings will + * be much faster. The binaries are saved in the directory + * specified in the configuration file. The binaries will not + * load if the LPC source or any of the inherited or included + * files are out of date, in which case the file is compiled + * normally (and may save a new binary). + * + * In order to save the binary, valid_save_binary() is called + * in master.c, and is passed the name of the source file. If + * this returns a non-zero value, the binary is allowed to be + * saved. Allowing any file by any wizard to be saved as a + * binary is convenient, but may take up a lot of disk space. + */ +#undef BINARIES + +/* ARRAY_RESERVED_WORD: If this is defined then the word 'array' can + * be used to define arrays, as in: + * + * int array x = ({ .... }); + * + * A side effect is that 'array' cannot be a variable or function name. + */ +#define ARRAY_RESERVED_WORD + +/* REF_RESERVED_WORD: If this is defined then the word 'ref' can be + * used to pass arguments to functions by value. Example: + * + * void inc(int ref x) { + * x++; + * } + * + * ... y = 1; inc(ref y); ... + * + * A side effect is that 'ref' cannot be a variable or function name. + * + * Note: ref must be used in *both* places; this is intentional. It protects + * against passing references to routines which don't intend to return values + * through their arguments, and against forgetting to pass a reference + * to a function which wants one (or accidentally having a variable modified!) + */ +#define REF_RESERVED_WORD + +/**************************************************************************** + * PACKAGES * + * -------- * + * Defining some/all of the following add certain efuns, and sometimes * + * add/remove code from the driver. * + * * + * if PACKAGE_XYZZY is defined here, then the code in packages/xyzzy.c * + * and the efuns in packages/xyzzy_spec.c will be added to the driver. * + ****************************************************************************/ + +/* various miscellaneous efuns */ +#define PACKAGE_CONTRIB + +/* efuns that are only of use to those that know something about driver + internals */ +#define PACKAGE_DEVELOP + +/* PACKAGE_MATH: determines whether or not the math efuns (for floats) are + included. + */ +#define PACKAGE_MATH + +/* PACKAGE_MATRIX: determines whether or not the 3d graphics efuns (for floats) + * are included - see packages/matrix.spec for a list. + */ +#define PACKAGE_MATRIX + +/* PACKAGE_MUDLIB_STATS: define this to enable domain and author stats + * maintenance by the driver. These mudlib stats are more domain + * based than user based, and replaces the traditional wiz_list stats. + */ +#define PACKAGE_MUDLIB_STATS + +/* PACKAGE_SOCKETS: define this to enable the socket efunctions. This + * causes HAS_SOCKETS to be defined for all LPC objects. + */ +#define PACKAGE_SOCKETS + +/* PACKAGE_PARSER: Natural language parsing efuns for interactive fiction + * type applications + */ +#define PACKAGE_PARSER + +/* PACKAGE_EXTERNAL: Allows the driver to exec() commands specified in the + * config file. + */ +#undef PACKAGE_EXTERNAL + +/* NUM_EXTERNAL_CMDS: the number of external commands supported */ +#define NUM_EXTERNAL_CMDS 100 + +/* PACKAGE_DB: efuns for external database access using msql */ +#undef PACKAGE_DB + +/* If PACKAGE_DB is defined above, you must pick ONE of the following supported + * databases + */ +#ifdef PACKAGE_DB +#undef USE_MSQL +#undef MSQL +#define USE_MYSQL 2 +#define MY_SQL +#endif + +/**************************************************************************** + * UID PACKAGE * + * ----------- * + * UIDS are the basis for some mudlib security systems. Basically, they're * + * preserved for backwards compatibility, as several ways of breaking * + * almost any system which relies on them are known. (No, it's not a flaw * + * of uids; only that b/c of the ease with which LPC objects can call * + * each other, it's far too easy to leave holes) * + * * + * If you don't care about security, the first option is probably what you * + * want. * + ****************************************************************************/ + +/* + * PACKAGE_UIDS: define this if you want a driver that does use uids. + * + */ +#undef PACKAGE_UIDS + +/*PACKAGE DWLIB: some discworld mudlib simuls coded in C (well just one right + now) */ + +#undef PACKAGE_DWLIB + +/* AUTO_SETEUID: when an object is created it's euid is automatically set to + * the equivalent of seteuid(getuid(this_object())). undef AUTO_SETEUID + * if you would rather have the euid of the created object be set to 0. + */ +#undef AUTO_SETEUID + +/* AUTO_TRUST_BACKBONE: define this if you want objects with the backbone + * uid to automatically be trusted and to have their euid set to the uid of + * the object that forced the object's creation. + */ +#undef AUTO_TRUST_BACKBONE + +/************************************************************************* + * FOR EXPERIENCED USERS * + * ----------------------- * + * Most of these options will probably be of no interest to many users. * + *************************************************************************/ + +/* USE_32BIT_ADDRESSES: Use 32 bits for addresses of function, instead of + * the usual 16 bits. This increases the maximum program size from 64k + * of LPC bytecode (NOT source) to 4 GB. Branches are still 16 bits, + * imposing a 64k limit on catch(), if(), switch(), loops, and most other + * control structures. It would take an extremely large function to hit + * those limits, though. + * + * Overhead: 2 bytes/function with LPC->C off. Having LPC->C on forces + * this option, since it needs 4 bytes to store the function pointers + * anyway, and this setting is ignored. + */ +#undef USE_32BIT_ADDRESSES + +/* HEARTBEAT_INTERVAL: define heartbeat interval in microseconds (us). + * 1,000,000 us = 1 second. The value of this macro specifies + * the frequency with which the heart_beat method will be called in + * those LPC objects which have called set_heart_beat(1). + * + * [NOTE: if ualarm() isn't available, alarm() is used instead. Since + * alarm() requires its argument in units of a second, we map 1 - 1,000,000 us + * to an actual interval of one (1) second and 1,000,001 - 2,000,000 maps to + * an actual interval of two (2) seconds, etc.] + */ +#define HEARTBEAT_INTERVAL 1 + +/* + * CALLOUT_CYCLE_SIZE: This is the number of slots in the call_out list. + * It should be approximately the average number of active call_outs, or + * a few times smaller. It should also be a power of 2, and also be relatively + * prime to any common call_out lengths. If all this is too confusing, 32 + * isn't a bad number :-) + */ +#define CALLOUT_CYCLE_SIZE 32 + +/* LARGEST_PRINTABLE_STRING: defines the size of the vsprintf() buffer in + * comm.c's add_message(). Instead of blindly making this value larger, + * your mudlib should be coded to not send huge strings to users. + */ +#define LARGEST_PRINTABLE_STRING 32768 + +/* MESSAGE_BUFFER_SIZE: determines the size of the buffer for output that + * is sent to users. + */ +#define MESSAGE_BUFFER_SIZE 4096 + +/* APPLY_CACHE_BITS: defines the number of bits to use in the call_other cache + * (in interpret.c). + * + * Memory overhead is (1 << APPLY_CACHE_BITS)*16. + * [assuming 32 bit pointers and 16 bit shorts] + * + * ACB: entries: overhead: + * 6 64 1k + * 8 256 4k + * 10 1024 16k + * 12 4096 64k + * 14 16384 256k + * 16 65536 1M + */ +#define APPLY_CACHE_BITS 11 + +/* CACHE_STATS: define this if you want call_other (apply_low) cache + * statistics. Causes HAS_CACHE_STATS to be defined in all LPC objects. + */ +#define CACHE_STATS + +/* TRACE: define this to enable the trace() and traceprefix() efuns. + * (keeping this undefined will cause the driver to run faster). + */ +#undef TRACE + +/* RUNTIME_LOADING: On systems which support it, it allows LPC->C compilation + * 'on the fly' without having to recompile the driver. + * + * Note: This currently only works on machines that have the dlopen() system + * call. SunOS and IRIX do, as do a number of others. AIX and Ultrix don't. + * Linux does if you are using ELF. + */ +#undef RUNTIME_LOADING + +/* TRACE_CODE: define this to enable code tracing (the driver will print + * out the previous lines of code to an error) eval_instruction() runs about + * twice as fast when this is not defined (for the most common eoperators). + */ +#undef TRACE_CODE + +/* HEART_BEAT_CHUNK: The number of heart_beat chunks allocated at a time. + * A large number wastes memory as some will be sitting around unused, while + * a small one wastes more CPU reallocating when it needs to grow. Default + * to a medium value. + */ +#define HEART_BEAT_CHUNK 32 + +/* SERVER_IP: For machines with multiple IP addresses, this specifies which + * one to use. This is useful for IP accounting and is necessary to be + * able to do ident lookups on such machines. + * + * example: #define SERVER_IP "194.229.18.27" + */ +#undef SERVER_IP + +/* Some maximum string sizes + */ +#define SMALL_STRING_SIZE 100 +#define LARGE_STRING_SIZE 1000 +#define COMMAND_BUF_SIZE 2000 + +/* Number of levels of nested datastructures allowed -- this limit prevents + * crashes from occuring when saving objects containing variables containing + * recursive datastructures (with circular references). + */ +#define MAX_SAVE_SVALUE_DEPTH 100 + +/* Miscellaneous config options that should probably be in the runtime + * config file. + */ +/* MAX_LOCAL: maximum number of local variables allowed per LPC function */ +#define CFG_MAX_LOCAL_VARIABLES 50 +/* Increasing max global vars beyond 256 is not recommended */ +#define CFG_MAX_GLOBAL_VARIABLES 256 + +#define CFG_EVALUATOR_STACK_SIZE 3000 +#define CFG_COMPILER_STACK_SIZE 600000 +#define CFG_MAX_CALL_DEPTH 150 +/* This must be one of 4, 16, 64, 256, 1024, 4096 */ +#define CFG_LIVING_HASH_SIZE 256 + +/* NEXT_MALLOC_DEBUG: define this if using a NeXT and you want to enable + * the malloc_check() and/or malloc_debug() efuns. Run the 'man malloc_debug' + * command on the NeXT to find out what the arguments to malloc_debug(int) + * mean. The malloc_check() efun calls the NeXT NXMallocCheck() system + * call which does a consistency check on malloc's data structures (this + * consistency check is done at each malloc() and free() for certain + * malloc_debug() levels). A non-zero return value indicates there was + * a consistency problem. For those NeXT users wanting a bit more + * performance out of malloc, try defining NEXT_MALLOC_DEBUG and calling the + * malloc_debug(-1) efun (with an arg of -1). This will turn all + * malloc debugging off and call malloc_singlethreaded() which the NeXT + * malloc man page claims can make NeXT system malloc 10% to 15% faster. + * + * [NOTE: This #define has no affect on the driver if not using the + * NeXTSTEP OS.] + * + * Warning: if you use a NeXT and define NEXT_MALLOC_DEBUG, be sure to + * protect the use of the malloc_check() and malloc_debug() efuns + * since setting certain debug levels can cause malloc() and free() + * to become _very_ slow (protect efuns by using simul_efuns and + * valid_override). + * + * [NOTE: malloc_debug(6) is a good compromise between efficiency and + * completeness of malloc debugging (malloc/free will be about half as fast).] + */ +#define NEXT_MALLOC_DEBUG + + +/* GET_CHAR_IS_BUFFERED: Normally get_char() is unbuffered. That is, once + * a character is received for get_char(), anything else is in the input + * stream is immediately thrown away. This can be very undesirable, especially + * if you're calling get_char() again from the handler from the previous call. + * Define this if you want get_char() to be buffered. In this case, the buffer + * will only get flushed if get_char() is not called from the first get_char()'s + * LPC callback handler. + */ +#define GET_CHAR_IS_BUFFERED + +/* PACKAGE_COMPRESS: Enable MCCP support and compressed save files + SAVE_GZ_EXTENSION: save extension for compressed files + */ +#undef HAVE_ZLIB +#undef PACKAGE_COMPRESS +#define SAVE_GZ_EXTENSION ".o.gz" + +/* CALL_OTHER_TYPE_CHECK: enable type checking for call_other() + * (-> operator on objects) + */ +#undef CALL_OTHER_TYPE_CHECK + +/* CALL_OTHER_WARN, make it warning instead of errors */ +#undef CALL_OTHER_WARN + +/* WARN_TAB: Some versions of the editor built in indent function use + * tabs for indenting. This options turns on a warning message for + * files indented with tabs instead of spaces. + */ +#define WARN_TAB + +/* USE_ICONV: Use iconv to translate input and output from/to the users char + * encoding + */ +#undef USE_ICONV + +/* WOMBLES: don't allow spaces between start/end of array/mapping/functional token chars so ({1,2,3}) still works, but ( { 1 , 2 , 3 } ) doesn't and ({ 1 , 2 , 3 }) does.*/ +#undef WOMBLES + +/* ALLOW_INHERIT_AFTER_FUNCTION: allow inheriting after functions have been defined (this includes prototypes). This caused crashes in v22.2a but it may have been fixed since */ +#define ALLOW_INHERIT_AFTER_FUNCTION +#undef ALLOW_INHERIT_AFTER_GLOBAL_VARIABLES +/*PACKAGE_ASYNC: adds some efuns for asyncronous IO */ +#undef PACKAGE_ASYNC + +#define PACKAGE_DSLIB +#define PARSE_DEBUG +#define FLUFFOS +#define PROG_REF_TYPE int +#define HAS_CONSOLE +#define ANSI_SUBSTITUTE 0x1e +#endif +#undef IPV6 +#undef MALLOC64 +#undef PACKAGE_CRYPTO +#undef PACKAGE_SHA1 +#undef MALLOC32 +#undef DTRACE +#define WARN_OLD_RANGE_BEHAVIOR +#define STRUCT_CLASS +#undef STRUCT_STRUCT diff --git a/fluffos-2.23-ds03/local_options.dw b/fluffos-2.23-ds03/local_options.dw new file mode 100644 index 0000000..a3ff23d --- /dev/null +++ b/fluffos-2.23-ds03/local_options.dw @@ -0,0 +1,903 @@ +/* + * options.h: defines for the compile-time configuration of the MudOS driver + */ + +#ifndef _OPTIONS_H_ +#define _OPTIONS_H_ + +/* + * YOU PROBABLY DO NOT WANT TO MODIFY THIS FILE. + * + * Do 'cp options.h local_options' and edit that instead. local_options, + * if it exists, overrides this file. + * + * The advantage is that when you upgrade to a newer MudOS driver, you can + * simply copy your local_options file into the src directory. The build + * process will warn you if new options have been added that you should + * choose settings for. + */ + +/**************************************************************************** + * EVERY time you change ANYTHING in this file, RECOMPILE from scratch. * + * (type "make clean" then "make" on a UNIX system) Failure to do so may * + * cause the driver to behave oddly. * + ****************************************************************************/ + +/* NOTES: + * Many of the configurable options are now set via the configuration file + * that is specified as the first argument to the driver. + * See port.h for those #defines related to portability (compatibility) if + * you have problems compiling on your system. + * Removing an efun from func_spec.c usually removes most, if not all, + * of the code associated with it. + * Note that anything defined in this file is also visible to LPC files + * surrounded by __. So #define FOO in this file defines __FOO__ for + * all LPC files. This allows code like: + * + * #ifdef __SENSIBLE_MODIFIERS__ + * ... + */ + +/**************************************************************************** + * MALLOC * + * -------- * + * For performance reasons, LP drivers have a variety of memory allocation * + * packages. If you don't care, use the default one on your system: * + * #define SYSMALLOC, #undef the others. * + ****************************************************************************/ + +/* You must choose exactly one of these malloc packages: + * ~~~~ + * SYSMALLOC: + * * Built-in system malloc. + * * No statistics. + * * SYSMALLOC incurs no additional CPU or memory overhead. + * + * SMALLOC: + * * Satoria's smalloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than most system mallocs with modest ammount of memory overhead. + * * Can fall back onto system malloc if sbrk() not ok. + * + * BSDMALLOC: + * * BSD (Berkeley Software Distributions) malloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than SMALLOC but more memory overhead. + * * Requires sbrk(). + */ +#undef SYSMALLOC +#undef SMALLOC +#undef BSDMALLOC +#undef MMALLOC +#define MALLOC64 +#undef MALLOC32 +/* You may optionally choose one (or none) of these malloc wrappers. These + * can be used in conjunction with any of the above malloc packages. + * + * WRAPPEDMALLOC: + * * Limited statistics. + * * Limited additional cpu overhead and no additional memory overhead. + * + * DEBUGMALLOC: + * * Statistics on precisely how much memory has been malloc'd (as well + * as the stats provided by WRAPPEDMALLOC). + * * Incurs a fair amount of overhead (both memory and CPU) + */ +#undef WRAPPEDMALLOC +#undef DEBUGMALLOC + +/* The following add certain bells and whistles to malloc: */ + +/* + * SBRK_OK: do not define this unless SMALLOC is chosen above. + * Defining this causes smalloc to use the low level memory allocation + * routines, and to act as a malloc replacement. Conversely, undef'ing + * SBRK_OK causes smalloc to act as a wrapper for the system malloc + * routines. + * + * Note: + * NeXTStep 3.x users should always #undef SBRK_OK. + */ +#undef SBRK_OK + +/* DO_MSTATS: do not define this unless BSDMALLOC or SMALLOC is chosen above. + * Defining this causes those replacement mallocs to keep statistics that + * the malloc_status() efun will print out (including total memory + * allocated/used). + */ +#undef DO_MSTATS + +/* DEBUGMALLOC_EXTENSIONS: defining this (in addition to DEBUGMALLOC) enables + * the set_malloc_mask(int) and debugmalloc(string,int) efuns. These two + * efuns basically allow you to cause certain malloc's and free's (with tags + * selected by a specified mask) to print debug information (addr, tag, + * description, size) to stdio (in the shell that invoked the driver) or to a + * file. Not defining this does reduce the overhead of DEBUGMALLOC from 16 + * bytes per malloc down to 8. This macro has no effect if DEBUGMALLOC isn't + * defined. + */ +#undef DEBUGMALLOC_EXTENSIONS + +/* CHECK_MEMORY: defining this (in addition to DEBUGMALLOC and + * DEBUGMALLOC_EXTENSIONS) causes the driver to check for memory + * corruption due to writing before the start or end of a block. This + * also adds the check_memory() efun. Takes a considerable ammount + * more memory. Mainly for debugging. + */ +#undef CHECK_MEMORY + +/**************************************************************************** + * COMPATIBILITY * + * --------------- * + * The MudOS driver has evolved quite a bit over the years. These defines * + * are mainly to preserve old behavior in case people didn't want to * + * rewrite the relevant portions of their code. * + * * + * In most cases, code which needs these defines should be rewritten when * + * possible. The 'Compat status' field is designed to give an idea how * + * likely it is that support for that option will be removed in the near * + * future. Certain options are fairly easy to work around, and double * + * the size of the associated code, as well as the maintenance workload, * + * and can make the code significantly more complex or harder to read, so * + * supporting them indefinitely is impractical. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* HAS_STATUS_TYPE: old MudOS drivers had a 'status' type which was + * identical to the 'int' type. Define this to bring it back. + * + * Compat status: very archaic, but easy to support. + */ +#undef HAS_STATUS_TYPE + +/* explode(): + * + * The old behavior (#undef both of the below) strips any number of + * delimiters at the start of the string, and one at the end. So + * explode("..x.y..z..", ".") gives ({ "x", "y", "", "z", "" }) + * + * SANE_EXPLODE_STRING strips off at most one leading delimiter, and + * still strips off one at the end, so the example above gives + * ({ "", "x", "y", "", "z", "" }). + * + * REVERSIBLE_EXPLODE_STRING overrides SANE_EXPLODE_STRING, and makes + * it so that implode(explode(x, y), y) is always x; i.e. no delimiters + * are ever stripped. So the example above gives + * ({ "", "", "x", "y", "", "z", "", "" }). + */ +#undef SANE_EXPLODE_STRING +#undef REVERSIBLE_EXPLODE_STRING + +/* CAST_CALL_OTHERS: define this if you want to require casting of call_other's; + * this was the default behavior of the driver prior to this addition. + * + * Compat status: code that requires it doesn't break, and it promotes + * sloppy coding with no benefits. + */ +#undef CAST_CALL_OTHERS + +/* NONINTERACTIVE_STDERR_WRITE: if defined, all writes/tells/etc to + * noninteractive objects will be written to stderr prefixed with a ']' + * (old behavior). + * + * Compat status: Easy to support, and also on the "It's a bug! No, it's + * a feature!" religious war list. + */ +#undef NONINTERACTIVE_STDERR_WRITE + +/* NO_LIGHT: define this to disable the set_light() and driver maintenance + * of light levels in objects. You can simulate it via LPC if you want... + * + * Compat status: Very dated, easy to simulate, and gross. + */ +#define NO_LIGHT + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + * process_input() then becomes the only way to deal with player input. + * + * Compat status: next to impossible to simulate, hard to replace, and + * very, very widely used. + */ +#define NO_ADD_ACTION + +/* NO_SNOOP: disables the snoop() efun and all related functionality. + */ +#undef NO_SNOOP + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + process_input() then becomes the only way to deal with player input. */ + +/* NO_ENVIRONMENT: define this to remove the handling of object containment + * relationships by the driver + * + * Compat status: hard to simulate efficiently, and very widely used. + */ +#undef NO_ENVIRONMENT + +/* NO_WIZARDS: for historical reasons, MudOS used to keep track of who + * is and isn't a wizard. Defining this removes that completely. + * If this is defined, the wizardp() and related efuns don't exist. + * + * Also note that if it is not defined, then non-wizards are always put + * in restricted mode when ed() is used, regardless of the setting of + * the restrict parameter. + * + * Compat status: easy to simulate and dated. + */ +#define NO_WIZARDS + +/* OLD_TYPE_BEHAVIOR: reintroduces a bug in type-checking that effectively + * renders compile time type checking useless. For backwards compatibility. + * + * Compat status: dealing with all the resulting compile errors can be + * a huge pain even if they are correct, and the impact on the code is + * small. + */ +#undef OLD_TYPE_BEHAVIOR + +/* OLD_RANGE_BEHAVIOR: define this if you want negative indexes in string + * or buffer range values (not lvalue, i.e. x[-2..-1]; for e.g. not + * x[-2..-1] = foo, the latter is always illegal) to mean counting from the + * end + * + * Compat status: Not horribly difficult to replace reliance on this, but not + * trivial, and cannot be simulated. + */ +#undef OLD_RANGE_BEHAVIOR + +/* OLD_ED: ed() efun backwards compatible with the old version. The new + * version requires/allows a mudlib front end. + * + * Compat status: Easily simulated. + */ +#define OLD_ED + +/* In ed auto-indent, + * 1) does the case line get indented after the switch() ? + * 2) How far do we indent? (this can also be set in the mudlib) + */ +#undef ED_INDENT_CASE +#define ED_INDENT_SPACES 3 + +/* SENSIBLE_MODIFIERS: + * Turning this on changes a few things, which may break old code: + * + * (1) 'static' is not recognized; either 'nosave' or 'protected' must + * be used instead. + * (2) The old meaning of 'public' is no longer allowed. Explicit + * functions must be defined at each level to allow access to + * privately inherited functions. + * (3) 'public' now means the default visibility. Previously there was + * no keyword that meant this (before you ask, 'public' meant something + * else, and if you don't know that, you probably don't have any reason + * to care about the old meaning). + */ +#define SENSIBLE_MODIFIERS + +/**************************************************************************** + * MISCELLANEOUS * + * --------------- * + * Various options that affect the way the driver behaves. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* + * Define this in order to use Fermat@Equilibria's MD5 based crypt() instead + * of the operating system's. It has the advantage of giving the same value + * on all architectures, and being stronger than the standard UNIX crypt(). + */ +#undef CUSTOM_CRYPT + +/* + * Some minor tweaks that make it a bit easier to run code designed to run + * on LPmud 3.2/3.2.1. Currently has the following effects: + * + * . m_indices() and m_values() are synonyms for keys() and values(), + * respectively + * . map_delete() returns it's first argument + * . inherit_list() means deep_inherit_list(), not shallow_inherit_list() + * . heart_beat_info() is a synonym for heart_beats() + */ +#undef COMPAT_32 + +/* + * Keep statistics about allocated strings, etc. Which can be viewed with + * the mud_status() efun. If this is off, mud_status() and memory_info() + * ignore allocated strings, but string operations run faster. + */ +#define STRING_STATS + +/* + * Similarly for arrays ... + */ +#define ARRAY_STATS + +/* LOG_CATCHES: define this to cause errors that are catch()'d to be + * sent to the debug log anyway. + * + * On by default, because newer libs use catch() a lot, and it's confusing + * if the errors don't show up in the logs. + */ +#define LOG_CATCHES + +/* ARGUMENTS_IN_TRACEBACK: prints out function call arguments in error + * tracebacks, to aid in debugging. Note: it prints the values of + * the arguments at the time of the error, not when the function + * was called. It looks like this: + * + * Failed to load file: read_buffer + * program: command/update.c, object: command/update line 15 + * ' commandHook' in ' clone/user.c' (' clone/user#1')line 72 + * arguments were ("/read_buffer.c") + * ' main' in ' command/update.c' (' command/update')line 15 + * arguments were ("/read_buffer.c") + * + * The only down side is some people like their logs shorter + */ +#define ARGUMENTS_IN_TRACEBACK + +/* LOCALS_IN_TRACEBACK: similar to ARGUMENTS_IN_TRACEBACK, but for local + * variables. The output looks more or less like: + * + * locals: 1, "local_value" + * + * Same as above. Tends to produce even longer logs, but very useful for + * tracking errors. + */ +#define LOCALS_IN_TRACEBACK + +/* MUDLIB_ERROR_HANDLER: If you define this, the driver doesn't do any + * handling of runtime errors, other than to turn the heartbeats of + * objects off. Information about the error is passed in a mapping + * to the error_handler() function in the master object. Whatever is + * returned is put in the debug.log. + * + * A good mudlib error handler is one of the best tools for tracking down + * errors. Unfortunately, you need to have one. Check the testsuite or + * other libs for an example. + */ +#define MUDLIB_ERROR_HANDLER + +/* CONFIG_FILE_DIR specifies a directory in which the driver will search for + * config files by default. If you don't wish to use this define, you may + * always specify a full path to the config file when starting the driver. + */ +#define CONFIG_FILE_DIR "/home/atuin/bin" + +/* DEFAULT_PRAGMAS: This should be a sum of pragmas you want to always + * be on, i.e. + * + * #define DEFAULT_PRAGMAS PRAGMA_STRICT_TYPES + PRAGMA_SAVE_TYPES + * + * will make every LPC file behave as if it had the lines: + * #pragma strict_types + * #pragma save_types + * + * for no default pragmas: + * #define DEFAULT_PRAGMAS 0 + * + * If you don't know what these are, 0 is a good choice. + * + * Supported pragmas: + * PRAGMA_STRICT_TYPES: enforces strict type checking + * PRAGMA_WARNINGS: issues warnings about various dangerous things in + * your code + * PRAGMA_SAVE_TYPES: save the types of function arguments for checking + * calls to functions in this object by objects that + * inherit it. + * PRAGMA_OPTIMIZE: make a second pass over the generated code to + * optimize it further. Currently does jump threading. + * PRAGMA_ERROR_CONTEXT:include some text telling where on the line a + * compilation error occured. + */ +#define DEFAULT_PRAGMAS PRAGMA_WARNINGS + PRAGMA_STRICT_TYPES + PRAGMA_ERROR_CONTEXT + +/* supress warnings about unused arguments; only warn about unused local + * variables. Makes older code (where argument names were required) compile + * more quietly. + */ +#define SUPPRESS_ARGUMENT_WARNINGS + +/* NO_RESETS: completely disable the periodic calling of reset() */ +#undef NO_RESETS + +/* LAZY_RESETS: if this is defined, an object will only have reset() + * called in it when it is touched via call_other() or move_object() + * (assuming enough time has passed since the last reset). If LAZY_RESETS + * is #undef'd, then reset() will be called as always (which guaranteed that + * reset would always be called at least once). The advantage of lazy + * resets is that reset doesn't get called in an object that is touched + * once and never again (which can save memory since some objects won't get + * reloaded that otherwise would). + */ +#undef LAZY_RESETS + +/* SAVE_EXTENSION: defines the file extension used by save_object(). + * and restore_object(). Some sysadmins run scripts that periodically + * scan for and remove files ending in .o (but many mudlibs are already + * set up to use .o thus we leave .o as the default). + */ +#define SAVE_EXTENSION ".o" + +/* NO_ANSI: define if you wish to disallow users from typing in commands that + * contain ANSI escape sequences. Defining NO_ANSI causes all escapes + * (ASCII 27) to be replaced with a space ' ' before the string is passed + * to the action routines added with add_action. + * + * STRIP_BEFORE_PROCESS_INPUT allows the location where the stripping is + * done to be controlled. If it is defined, then process_input() doesn't + * see ANSI characters either; if it is undefined ESC chars can be processed + * by process_input(), but are stripped before add_actions are called. + * Note that if NO_ADD_ACTION is defined, then #define NO_ANSI without + * #define STRIP_BEFORE_PROCESS_INPUT is the same as #undef NO_ANSI. + * + * If you anticipate problems with users intentionally typing in ANSI codes + * to make your terminal flash, etc define this. + */ +#define NO_ANSI +#define STRIP_BEFORE_PROCESS_INPUT + +/* OPCPROF: define this if you wish to enable OPC profiling. Allows a dump + * of the # of times each efun is invoked (via the opcprof() efun). + */ +#undef OPCPROF + +/* OPCPROF_2D: define this if you wish to enable 2-D OPC profiling. Allows a + * dump of the # of times each *pair* of eoperators is invoked. + * + * You can't use this and OPCPROF at the same time. + */ +#undef OPCPROF_2D + +/* TRAP_CRASHES: define this if you want MudOS to call crash() in master.c + * and then shutdown when signals are received that would normally crash the + * driver. + */ +#define TRAP_CRASHES + +/* THIS_PLAYER_IN_CALL_OUT: define this if you wish this_player() to be + * usable from within call_out() callbacks. + */ +#define THIS_PLAYER_IN_CALL_OUT + +/* CALLOUT_HANDLES: If this is defined, call_out() returns an integer, which + * can be passed to remove_call_out() or find_call_out(). Removing call_outs + * by name is still allowed, but is significantly less efficient, and also + * doesn't work for function pointers. This option adds 4 bytes overhead + * per callout to keep track of the handle. + */ +#define CALLOUT_HANDLES + +/* FLUSH_OUTPUT_IMMEDIATELY: Causes output to be written to sockets + * immediately after being generated. Useful for debugging. + */ +#undef FLUSH_OUTPUT_IMMEDIATELY + +/* PRIVS: define this if you want object privileges. Your mudlib must + * explicitly make use of this functionality to be useful. Defining this + * this will increase the size of the object structure by 4 bytes (8 bytes + * on the DEC Alpha) and will add a new master apply during object creation + * to "privs_file". In general, privileges can be used to increase the + * granularity of security beyond the current root uid mechanism. + * + * [NOTE: for those who'd rather do such things at the mudlib level, look at + * the inherits() efun and the 'valid_object' apply to master.] + */ +#undef PRIVS + +/* INTERACTIVE_CATCH_TELL: define this if you want catch_tell called on + * interactives as well as NPCs. If this is defined, user.c will need a + * catch_tell(msg) method that calls receive(msg); +*/ +#undef INTERACTIVE_CATCH_TELL + +/* RECEIVE_ED: define this if you want normal ed output to go to a + receive_ed() apply in the player ob. Some errors still go directly + to output. Useful for post-processing (perhaps colorizing?) ed + output. Prototype: mixed receive_ed(string txt, string fname); + If fname, return a string that ed will output, 0 to let ed handle + the output in the default way, or 1 to handle the output yourself. + If fname == 0, output is help text and you may return any of the above + or an array of strings that will be more'ed. +*/ +#undef RECEIVE_ED + +/* RESTRICTED_ED: define this if you want restricted ed mode enabled. + */ +#define RESTRICTED_ED + +/* NO_SHADOWS: define this if you want to disable shadows in your driver. + */ +#undef NO_SHADOWS + +/* SNOOP_SHADOWED: define this if you want snoop to report what is + * sent to the player even in the event that the player's catch_tell() is + * shadowed and the player may not be seeing what is being sent. Messages + * of this sort will be prefixed with $$. + */ +#undef SNOOP_SHADOWED + +/* RECEIVE_SNOOP: define this if you want snoop text to be sent to + * the receive_snoop() function in the snooper object (instead of being + * sent directly via add_message()). This is useful if you want to + * build a smart client that does something different with snoop messages. + */ +#define RECEIVE_SNOOP + +/* PROFILE_FUNCTIONS: define this to be able to measure the CPU time used by + * all of the user-defined functions in each LPC object. Note: defining + * this adds three long ints (12 bytes on 32-bit machines) to the function + * header structs. Also note that the resolution of the getrusage() timer + * may not be high enough on some machines to give non-zero execution + * times to very small (fast) functions. In particular if the clock + * resolution is 1/60 of a second, then any time less than approxmately 15k + * microseconds will resolve to zero (0). + */ +#define PROFILE_FUNCTIONS + +/* NO_BUFFER_TYPE: if this is #define'd then LPC code using the 'buffer' + * type won't be allowed to compile (since the 'buffer' type won't be + * recognized by the lexer). + */ +#undef NO_BUFFER_TYPE + +/* BINARIES: define this to enable the 'save_binary' pragma. + * This pragma, when set in a program, will cause it to save a + * binary image when loaded, so that subsequent loadings will + * be much faster. The binaries are saved in the directory + * specified in the configuration file. The binaries will not + * load if the LPC source or any of the inherited or included + * files are out of date, in which case the file is compiled + * normally (and may save a new binary). + * + * In order to save the binary, valid_save_binary() is called + * in master.c, and is passed the name of the source file. If + * this returns a non-zero value, the binary is allowed to be + * saved. Allowing any file by any wizard to be saved as a + * binary is convenient, but may take up a lot of disk space. + */ +#define BINARIES + +/* ARRAY_RESERVED_WORD: If this is defined then the word 'array' can + * be used to define arrays, as in: + * + * int array x = ({ .... }); + * + * A side effect is that 'array' cannot be a variable or function name. + */ +#undef ARRAY_RESERVED_WORD + +/* REF_RESERVED_WORD: If this is defined then the word 'ref' can be + * used to pass arguments to functions by value. Example: + * + * void inc(int ref x) { + * x++; + * } + * + * ... y = 1; inc(ref y); ... + * + * A side effect is that 'ref' cannot be a variable or function name. + * + * Note: ref must be used in *both* places; this is intentional. It protects + * against passing references to routines which don't intend to return values + * through their arguments, and against forgetting to pass a reference + * to a function which wants one (or accidentally having a variable modified!) + */ +#define REF_RESERVED_WORD + +/**************************************************************************** + * PACKAGES * + * -------- * + * Defining some/all of the following add certain efuns, and sometimes * + * add/remove code from the driver. * + * * + * if PACKAGE_XYZZY is defined here, then the code in packages/xyzzy.c * + * and the efuns in packages/xyzzy_spec.c will be added to the driver. * + ****************************************************************************/ + +/* various miscellaneous efuns */ +#define PACKAGE_CONTRIB + +/* efuns that are only of use to those that know something about driver + internals */ +#define PACKAGE_DEVELOP + +/* PACKAGE_MATH: determines whether or not the math efuns (for floats) are + included. + */ +#define PACKAGE_MATH + +/* PACKAGE_MATRIX: determines whether or not the 3d graphics efuns (for floats) + * are included - see packages/matrix.spec for a list. + */ +#undef PACKAGE_MATRIX + +/* PACKAGE_MUDLIB_STATS: define this to enable domain and author stats + * maintenance by the driver. These mudlib stats are more domain + * based than user based, and replaces the traditional wiz_list stats. + */ +#undef PACKAGE_MUDLIB_STATS + +/* PACKAGE_SOCKETS: define this to enable the socket efunctions. This + * causes HAS_SOCKETS to be defined for all LPC objects. + */ +#define PACKAGE_SOCKETS + +/* PACKAGE_PARSER: Natural language parsing efuns for interactive fiction + * type applications + */ +#undef PACKAGE_PARSER + +/* PACKAGE_EXTERNAL: Allows the driver to exec() commands specified in the + * config file. + */ +#define PACKAGE_EXTERNAL + +/* NUM_EXTERNAL_CMDS: the number of external commands supported */ +#ifdef PACKAGE_EXTERNAL +#define NUM_EXTERNAL_CMDS 100 +#endif + +/* PACKAGE_DB: efuns for external database access using msql */ +#define PACKAGE_DB + +/* If PACKAGE_DB is defined above, you must pick ONE of the following supported + * databases + */ +#ifdef PACKAGE_DB +#undef USE_MSQL +#undef MSQL +#define USE_MYSQL 2 +#define MY_SQL +#endif + +/**************************************************************************** + * UID PACKAGE * + * ----------- * + * UIDS are the basis for some mudlib security systems. Basically, they're * + * preserved for backwards compatibility, as several ways of breaking * + * almost any system which relies on them are known. (No, it's not a flaw * + * of uids; only that b/c of the ease with which LPC objects can call * + * each other, it's far too easy to leave holes) * + * * + * If you don't care about security, the first option is probably what you * + * want. * + ****************************************************************************/ + +/* + * PACKAGE_UIDS: define this if you want a driver that does use uids. + * + */ +#define PACKAGE_UIDS + +/* AUTO_SETEUID: when an object is created it's euid is automatically set to + * the equivalent of seteuid(getuid(this_object())). undef AUTO_SETEUID + * if you would rather have the euid of the created object be set to 0. + */ +#define AUTO_SETEUID + +/* AUTO_TRUST_BACKBONE: define this if you want objects with the backbone + * uid to automatically be trusted and to have their euid set to the uid of + * the object that forced the object's creation. + */ +#undef AUTO_TRUST_BACKBONE + +/************************************************************************* + * FOR EXPERIENCED USERS * + * ----------------------- * + * Most of these options will probably be of no interest to many users. * + *************************************************************************/ + +/* USE_32BIT_ADDRESSES: Use 32 bits for addresses of function, instead of + * the usual 16 bits. This increases the maximum program size from 64k + * of LPC bytecode (NOT source) to 4 GB. Branches are still 16 bits, + * imposing a 64k limit on catch(), if(), switch(), loops, and most other + * control structures. It would take an extremely large function to hit + * those limits, though. + * + * Overhead: 2 bytes/function with LPC->C off. Having LPC->C on forces + * this option, since it needs 4 bytes to store the function pointers + * anyway, and this setting is ignored. + */ +#define USE_32BIT_ADDRESSES + +/* HEARTBEAT_INTERVAL: define heartbeat interval in microseconds (us). + * 1,000,000 us = 1 second. The value of this macro specifies + * the frequency with which the heart_beat method will be called in + * those LPC objects which have called set_heart_beat(1). + * + * [NOTE: if ualarm() isn't available, alarm() is used instead. Since + * alarm() requires its argument in units of a second, we map 1 - 1,000,000 us + * to an actual interval of one (1) second and 1,000,001 - 2,000,000 maps to + * an actual interval of two (2) seconds, etc.] + */ +#define HEARTBEAT_INTERVAL 2 + +/* + * CALLOUT_CYCLE_SIZE: This is the number of slots in the call_out list. + * It should be approximately the average number of active call_outs, or + * a few times smaller. It should also be a power of 2, and also be relatively + * prime to any common call_out lengths. If all this is too confusing, 32 + * isn't a bad number :-) + */ +#define CALLOUT_CYCLE_SIZE 1024 + +/* LARGEST_PRINTABLE_STRING: defines the size of the vsprintf() buffer in + * comm.c's add_message(). Instead of blindly making this value larger, + * your mudlib should be coded to not send huge strings to users. + */ +#define LARGEST_PRINTABLE_STRING 8192 + +/* MESSAGE_BUFFER_SIZE: determines the size of the buffer for output that + * is sent to users. + */ +#define MESSAGE_BUFFER_SIZE 4096 + +/* APPLY_CACHE_BITS: defines the number of bits to use in the call_other cache + * (in interpret.c). + * + * Memory overhead is (1 << APPLY_CACHE_BITS)*16. + * [assuming 32 bit pointers and 16 bit shorts] + * + * ACB: entries: overhead: + * 6 64 1k + * 8 256 4k + * 10 1024 16k + * 12 4096 64k + * 14 16384 256k + * 16 65536 1M + */ +#define APPLY_CACHE_BITS 16 + +/* CACHE_STATS: define this if you want call_other (apply_low) cache + * statistics. Causes HAS_CACHE_STATS to be defined in all LPC objects. + */ +#define CACHE_STATS + +/* TRACE: define this to enable the trace() and traceprefix() efuns. + * (keeping this undefined will cause the driver to run faster). + */ +#undef TRACE + +/* RUNTIME_LOADING: On systems which support it, it allows LPC->C compilation + * 'on the fly' without having to recompile the driver. + * + * Note: This currently only works on machines that have the dlopen() system + * call. SunOS and IRIX do, as do a number of others. AIX and Ultrix don't. + * Linux does if you are using ELF. + */ +#undef RUNTIME_LOADING + +/* TRACE_CODE: define this to enable code tracing (the driver will print + * out the previous lines of code to an error) eval_instruction() runs about + * twice as fast when this is not defined (for the most common eoperators). + */ +#undef TRACE_CODE + +/* HEART_BEAT_CHUNK: The number of heart_beat chunks allocated at a time. + * A large number wastes memory as some will be sitting around unused, while + * a small one wastes more CPU reallocating when it needs to grow. Default + * to a medium value. + */ +#define HEART_BEAT_CHUNK 512 + +/* SERVER_IP: For machines with multiple IP addresses, this specifies which + * one to use. This is useful for IP accounting and is necessary to be + * able to do ident lookups on such machines. + * + * example: #define SERVER_IP "194.229.18.27" + */ +#undef SERVER_IP + +/* Some maximum string sizes + */ +#define SMALL_STRING_SIZE 100 +#define LARGE_STRING_SIZE 1000 +#define COMMAND_BUF_SIZE 2000 + +/* Number of levels of nested datastructures allowed -- this limit prevents + * crashes from occuring when saving objects containing variables containing + * recursive datastructures (with circular references). + */ +#define MAX_SAVE_SVALUE_DEPTH 100 + +/* Miscellaneous config options that should probably be in the runtime + * config file. + */ +/* MAX_LOCAL: maximum number of local variables allowed per LPC function */ +#define CFG_MAX_LOCAL_VARIABLES 50 +/* Increasing max global vars beyond 256 is not recommended */ +#define CFG_MAX_GLOBAL_VARIABLES 65530 + +#define CFG_EVALUATOR_STACK_SIZE 3000000 +#define CFG_COMPILER_STACK_SIZE 600000 +#define CFG_MAX_CALL_DEPTH 150 +/* This must be one of 4, 16, 64, 256, 1024, 4096 */ +#define CFG_LIVING_HASH_SIZE 256 + +/* NEXT_MALLOC_DEBUG: define this if using a NeXT and you want to enable + * the malloc_check() and/or malloc_debug() efuns. Run the 'man malloc_debug' + * command on the NeXT to find out what the arguments to malloc_debug(int) + * mean. The malloc_check() efun calls the NeXT NXMallocCheck() system + * call which does a consistency check on malloc's data structures (this + * consistency check is done at each malloc() and free() for certain + * malloc_debug() levels). A non-zero return value indicates there was + * a consistency problem. For those NeXT users wanting a bit more + * performance out of malloc, try defining NEXT_MALLOC_DEBUG and calling the + * malloc_debug(-1) efun (with an arg of -1). This will turn all + * malloc debugging off and call malloc_singlethreaded() which the NeXT + * malloc man page claims can make NeXT system malloc 10% to 15% faster. + * + * [NOTE: This #define has no affect on the driver if not using the + * NeXTSTEP OS.] + * + * Warning: if you use a NeXT and define NEXT_MALLOC_DEBUG, be sure to + * protect the use of the malloc_check() and malloc_debug() efuns + * since setting certain debug levels can cause malloc() and free() + * to become _very_ slow (protect efuns by using simul_efuns and + * valid_override). + * + * [NOTE: malloc_debug(6) is a good compromise between efficiency and + * completeness of malloc debugging (malloc/free will be about half as fast).] + */ +#undef NEXT_MALLOC_DEBUG + + +/* GET_CHAR_IS_BUFFERED: Normally get_char() is unbuffered. That is, once + * a character is received for get_char(), anything else is in the input + * stream is immediately thrown away. This can be very undesirable, especially + * if you're calling get_char() again from the handler from the previous call. + * Define this if you want get_char() to be buffered. In this case, the buffer + * will only get flushed if get_char() is not called from the first get_char()'s + * LPC callback handler. + */ +#undef GET_CHAR_IS_BUFFERED + +#define HAVE_ZLIB +#define PACKAGE_COMPRESS +#define SAVE_GZ_EXTENSION ".o.gz" +/* CALL_OTHER_TYPE_CHECK: enable type checking for call_other() + * (-> operator on objects) + */ +#undef CALL_OTHER_TYPE_CHECK + + +/* CALL_OTHER_WARN, make it warning instead of errors */ +#define CALL_OTHER_WARN + +#define PACKAGE_DWLIB +#undef MMAP_SBRK +/* WARN_TAB: Some versions of the editor built in indent function use + * tabs for indenting. This options turns on a warning message for + * files indented with tabs instead of spaces. + */ +#define WARN_TAB + +/* USE_ICONV: Use iconv to translate input and output from/to the users char + * encoding + */ +#define USE_ICONV + +/* WOMBLES: don't allow spaces between start/end of array/mapping/functional token chars so ({1,2,3}) still works, but ( { 1 , 2 , 3 } ) doesn't and ({ 1 , 2 , 3 }) does.*/ +#define WOMBLES + +/* ALLOW_INHERIT_AFTER_FUNCTION: allow inheriting after functions have been defined (this includes prototypes). This caused crashes in v22.2a but it may have been fixed since */ +#undef ALLOW_INHERIT_AFTER_FUNCTION + +/*PACKAGE_ASYNC: adds some efuns for asyncronous IO */ +#define PACKAGE_ASYNC + +#define PROG_REF_TYPE short +#undef HAS_CONSOLE +#define IPV6 +#undef PACKAGE_CRYPTO +#undef PACKAGE_SHA1 +#undef DTRACE +#define PACKAGE_PCRE +#endif diff --git a/fluffos-2.23-ds03/local_options.dwclone b/fluffos-2.23-ds03/local_options.dwclone new file mode 100644 index 0000000..121741b --- /dev/null +++ b/fluffos-2.23-ds03/local_options.dwclone @@ -0,0 +1,888 @@ +/* + * options.h: defines for the compile-time configuration of the MudOS driver + */ + +#ifndef _OPTIONS_H_ +#define _OPTIONS_H_ + +/* + * YOU PROBABLY DO NOT WANT TO MODIFY THIS FILE. + * + * Do 'cp options.h local_options' and edit that instead. local_options, + * if it exists, overrides this file. + * + * The advantage is that when you upgrade to a newer MudOS driver, you can + * simply copy your local_options file into the src directory. The build + * process will warn you if new options have been added that you should + * choose settings for. + */ + +/**************************************************************************** + * EVERY time you change ANYTHING in this file, RECOMPILE from scratch. * + * (type "make clean" then "make" on a UNIX system) Failure to do so may * + * cause the driver to behave oddly. * + ****************************************************************************/ + +/* NOTES: + * Many of the configurable options are now set via the configuration file + * that is specified as the first argument to the driver. + * See port.h for those #defines related to portability (compatibility) if + * you have problems compiling on your system. + * Removing an efun from func_spec.c usually removes most, if not all, + * of the code associated with it. + * Note that anything defined in this file is also visible to LPC files + * surrounded by __. So #define FOO in this file defines __FOO__ for + * all LPC files. This allows code like: + * + * #ifdef __SENSIBLE_MODIFIERS__ + * ... + */ + +/**************************************************************************** + * MALLOC * + * -------- * + * For performance reasons, LP drivers have a variety of memory allocation * + * packages. If you don't care, use the default one on your system: * + * #define SYSMALLOC, #undef the others. * + ****************************************************************************/ + +/* You must choose exactly one of these malloc packages: + * ~~~~ + * SYSMALLOC: + * * Built-in system malloc. + * * No statistics. + * * SYSMALLOC incurs no additional CPU or memory overhead. + * + * SMALLOC: + * * Satoria's smalloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than most system mallocs with modest ammount of memory overhead. + * * Can fall back onto system malloc if sbrk() not ok. + * + * BSDMALLOC: + * * BSD (Berkeley Software Distributions) malloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than SMALLOC but more memory overhead. + * * Requires sbrk(). + */ +#undef SYSMALLOC +#undef SMALLOC +#undef BSDMALLOC +#undef MMALLOC +#undef MALLOC64 +#define MALLOC32 +/* You may optionally choose one (or none) of these malloc wrappers. These + * can be used in conjunction with any of the above malloc packages. + * + * WRAPPEDMALLOC: + * * Limited statistics. + * * Limited additional cpu overhead and no additional memory overhead. + * + * DEBUGMALLOC: + * * Statistics on precisely how much memory has been malloc'd (as well + * as the stats provided by WRAPPEDMALLOC). + * * Incurs a fair amount of overhead (both memory and CPU) + */ +#undef WRAPPEDMALLOC +#undef DEBUGMALLOC + +/* The following add certain bells and whistles to malloc: */ + +/* + * SBRK_OK: do not define this unless SMALLOC is chosen above. + * Defining this causes smalloc to use the low level memory allocation + * routines, and to act as a malloc replacement. Conversely, undef'ing + * SBRK_OK causes smalloc to act as a wrapper for the system malloc + * routines. + * + * Note: + * NeXTStep 3.x users should always #undef SBRK_OK. + */ +#undef SBRK_OK + +/* DO_MSTATS: do not define this unless BSDMALLOC or SMALLOC is chosen above. + * Defining this causes those replacement mallocs to keep statistics that + * the malloc_status() efun will print out (including total memory + * allocated/used). + */ +#undef DO_MSTATS + +/* DEBUGMALLOC_EXTENSIONS: defining this (in addition to DEBUGMALLOC) enables + * the set_malloc_mask(int) and debugmalloc(string,int) efuns. These two + * efuns basically allow you to cause certain malloc's and free's (with tags + * selected by a specified mask) to print debug information (addr, tag, + * description, size) to stdio (in the shell that invoked the driver) or to a + * file. Not defining this does reduce the overhead of DEBUGMALLOC from 16 + * bytes per malloc down to 8. This macro has no effect if DEBUGMALLOC isn't + * defined. + */ +#undef DEBUGMALLOC_EXTENSIONS + +/* CHECK_MEMORY: defining this (in addition to DEBUGMALLOC and + * DEBUGMALLOC_EXTENSIONS) causes the driver to check for memory + * corruption due to writing before the start or end of a block. This + * also adds the check_memory() efun. Takes a considerable ammount + * more memory. Mainly for debugging. + */ +#undef CHECK_MEMORY + +/**************************************************************************** + * COMPATIBILITY * + * --------------- * + * The MudOS driver has evolved quite a bit over the years. These defines * + * are mainly to preserve old behavior in case people didn't want to * + * rewrite the relevant portions of their code. * + * * + * In most cases, code which needs these defines should be rewritten when * + * possible. The 'Compat status' field is designed to give an idea how * + * likely it is that support for that option will be removed in the near * + * future. Certain options are fairly easy to work around, and double * + * the size of the associated code, as well as the maintenance workload, * + * and can make the code significantly more complex or harder to read, so * + * supporting them indefinitely is impractical. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* HAS_STATUS_TYPE: old MudOS drivers had a 'status' type which was + * identical to the 'int' type. Define this to bring it back. + * + * Compat status: very archaic, but easy to support. + */ +#undef HAS_STATUS_TYPE + +/* explode(): + * + * The old behavior (#undef both of the below) strips any number of + * delimiters at the start of the string, and one at the end. So + * explode("..x.y..z..", ".") gives ({ "x", "y", "", "z", "" }) + * + * SANE_EXPLODE_STRING strips off at most one leading delimiter, and + * still strips off one at the end, so the example above gives + * ({ "", "x", "y", "", "z", "" }). + * + * REVERSIBLE_EXPLODE_STRING overrides SANE_EXPLODE_STRING, and makes + * it so that implode(explode(x, y), y) is always x; i.e. no delimiters + * are ever stripped. So the example above gives + * ({ "", "", "x", "y", "", "z", "", "" }). + */ +#undef SANE_EXPLODE_STRING +#undef REVERSIBLE_EXPLODE_STRING + +/* CAST_CALL_OTHERS: define this if you want to require casting of call_other's; + * this was the default behavior of the driver prior to this addition. + * + * Compat status: code that requires it doesn't break, and it promotes + * sloppy coding with no benefits. + */ +#undef CAST_CALL_OTHERS + +/* NONINTERACTIVE_STDERR_WRITE: if defined, all writes/tells/etc to + * noninteractive objects will be written to stderr prefixed with a ']' + * (old behavior). + * + * Compat status: Easy to support, and also on the "It's a bug! No, it's + * a feature!" religious war list. + */ +#undef NONINTERACTIVE_STDERR_WRITE + +/* NO_LIGHT: define this to disable the set_light() and driver maintenance + * of light levels in objects. You can simulate it via LPC if you want... + * + * Compat status: Very dated, easy to simulate, and gross. + */ +#define NO_LIGHT + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + * process_input() then becomes the only way to deal with player input. + * + * Compat status: next to impossible to simulate, hard to replace, and + * very, very widely used. + */ +#define NO_ADD_ACTION + +/* NO_SNOOP: disables the snoop() efun and all related functionality. + */ +#undef NO_SNOOP + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + process_input() then becomes the only way to deal with player input. */ + +/* NO_ENVIRONMENT: define this to remove the handling of object containment + * relationships by the driver + * + * Compat status: hard to simulate efficiently, and very widely used. + */ +#undef NO_ENVIRONMENT + +/* NO_WIZARDS: for historical reasons, MudOS used to keep track of who + * is and isn't a wizard. Defining this removes that completely. + * If this is defined, the wizardp() and related efuns don't exist. + * + * Also note that if it is not defined, then non-wizards are always put + * in restricted mode when ed() is used, regardless of the setting of + * the restrict parameter. + * + * Compat status: easy to simulate and dated. + */ +#define NO_WIZARDS + +/* OLD_TYPE_BEHAVIOR: reintroduces a bug in type-checking that effectively + * renders compile time type checking useless. For backwards compatibility. + * + * Compat status: dealing with all the resulting compile errors can be + * a huge pain even if they are correct, and the impact on the code is + * small. + */ +#undef OLD_TYPE_BEHAVIOR + +/* OLD_RANGE_BEHAVIOR: define this if you want negative indexes in string + * or buffer range values (not lvalue, i.e. x[-2..-1]; for e.g. not + * x[-2..-1] = foo, the latter is always illegal) to mean counting from the + * end + * + * Compat status: Not horribly difficult to replace reliance on this, but not + * trivial, and cannot be simulated. + */ +#undef OLD_RANGE_BEHAVIOR + +/* OLD_ED: ed() efun backwards compatible with the old version. The new + * version requires/allows a mudlib front end. + * + * Compat status: Easily simulated. + */ +#define OLD_ED + +/* In ed auto-indent, + * 1) does the case line get indented after the switch() ? + * 2) How far do we indent? (this can also be set in the mudlib) + */ +#undef ED_INDENT_CASE +#define ED_INDENT_SPACES 3 + +/* SENSIBLE_MODIFIERS: + * Turning this on changes a few things, which may break old code: + * + * (1) 'static' is not recognized; either 'nosave' or 'protected' must + * be used instead. + * (2) The old meaning of 'public' is no longer allowed. Explicit + * functions must be defined at each level to allow access to + * privately inherited functions. + * (3) 'public' now means the default visibility. Previously there was + * no keyword that meant this (before you ask, 'public' meant something + * else, and if you don't know that, you probably don't have any reason + * to care about the old meaning). + */ +#define SENSIBLE_MODIFIERS + +/**************************************************************************** + * MISCELLANEOUS * + * --------------- * + * Various options that affect the way the driver behaves. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* + * Define this in order to use Fermat@Equilibria's MD5 based crypt() instead + * of the operating system's. It has the advantage of giving the same value + * on all architectures, and being stronger than the standard UNIX crypt(). + */ +#undef CUSTOM_CRYPT + +/* + * Some minor tweaks that make it a bit easier to run code designed to run + * on LPmud 3.2/3.2.1. Currently has the following effects: + * + * . m_indices() and m_values() are synonyms for keys() and values(), + * respectively + * . map_delete() returns it's first argument + * . inherit_list() means deep_inherit_list(), not shallow_inherit_list() + * . heart_beat_info() is a synonym for heart_beats() + */ +#undef COMPAT_32 + +/* + * Keep statistics about allocated strings, etc. Which can be viewed with + * the mud_status() efun. If this is off, mud_status() and memory_info() + * ignore allocated strings, but string operations run faster. + */ +#define STRING_STATS + +/* + * Similarly for arrays ... + */ +#define ARRAY_STATS + +/* LOG_CATCHES: define this to cause errors that are catch()'d to be + * sent to the debug log anyway. + * + * On by default, because newer libs use catch() a lot, and it's confusing + * if the errors don't show up in the logs. + */ +#define LOG_CATCHES + +/* ARGUMENTS_IN_TRACEBACK: prints out function call arguments in error + * tracebacks, to aid in debugging. Note: it prints the values of + * the arguments at the time of the error, not when the function + * was called. It looks like this: + * + * Failed to load file: read_buffer + * program: command/update.c, object: command/update line 15 + * ' commandHook' in ' clone/user.c' (' clone/user#1')line 72 + * arguments were ("/read_buffer.c") + * ' main' in ' command/update.c' (' command/update')line 15 + * arguments were ("/read_buffer.c") + * + * The only down side is some people like their logs shorter + */ +#define ARGUMENTS_IN_TRACEBACK + +/* LOCALS_IN_TRACEBACK: similar to ARGUMENTS_IN_TRACEBACK, but for local + * variables. The output looks more or less like: + * + * locals: 1, "local_value" + * + * Same as above. Tends to produce even longer logs, but very useful for + * tracking errors. + */ +#define LOCALS_IN_TRACEBACK + +/* MUDLIB_ERROR_HANDLER: If you define this, the driver doesn't do any + * handling of runtime errors, other than to turn the heartbeats of + * objects off. Information about the error is passed in a mapping + * to the error_handler() function in the master object. Whatever is + * returned is put in the debug.log. + * + * A good mudlib error handler is one of the best tools for tracking down + * errors. Unfortunately, you need to have one. Check the testsuite or + * other libs for an example. + */ +#define MUDLIB_ERROR_HANDLER + +/* CONFIG_FILE_DIR specifies a directory in which the driver will search for + * config files by default. If you don't wish to use this define, you may + * always specify a full path to the config file when starting the driver. + */ +#define CONFIG_FILE_DIR "/home/atuin/bin" + +/* DEFAULT_PRAGMAS: This should be a sum of pragmas you want to always + * be on, i.e. + * + * #define DEFAULT_PRAGMAS PRAGMA_STRICT_TYPES + PRAGMA_SAVE_TYPES + * + * will make every LPC file behave as if it had the lines: + * #pragma strict_types + * #pragma save_types + * + * for no default pragmas: + * #define DEFAULT_PRAGMAS 0 + * + * If you don't know what these are, 0 is a good choice. + * + * Supported pragmas: + * PRAGMA_STRICT_TYPES: enforces strict type checking + * PRAGMA_WARNINGS: issues warnings about various dangerous things in + * your code + * PRAGMA_SAVE_TYPES: save the types of function arguments for checking + * calls to functions in this object by objects that + * inherit it. + * PRAGMA_OPTIMIZE: make a second pass over the generated code to + * optimize it further. Currently does jump threading. + * PRAGMA_ERROR_CONTEXT:include some text telling where on the line a + * compilation error occured. + */ +#define DEFAULT_PRAGMAS PRAGMA_WARNINGS + PRAGMA_STRICT_TYPES + PRAGMA_ERROR_CONTEXT + +/* supress warnings about unused arguments; only warn about unused local + * variables. Makes older code (where argument names were required) compile + * more quietly. + */ +#define SUPPRESS_ARGUMENT_WARNINGS + +/* NO_RESETS: completely disable the periodic calling of reset() */ +#undef NO_RESETS + +/* LAZY_RESETS: if this is defined, an object will only have reset() + * called in it when it is touched via call_other() or move_object() + * (assuming enough time has passed since the last reset). If LAZY_RESETS + * is #undef'd, then reset() will be called as always (which guaranteed that + * reset would always be called at least once). The advantage of lazy + * resets is that reset doesn't get called in an object that is touched + * once and never again (which can save memory since some objects won't get + * reloaded that otherwise would). + */ +#undef LAZY_RESETS + +/* SAVE_EXTENSION: defines the file extension used by save_object(). + * and restore_object(). Some sysadmins run scripts that periodically + * scan for and remove files ending in .o (but many mudlibs are already + * set up to use .o thus we leave .o as the default). + */ +#define SAVE_EXTENSION ".o" + +/* NO_ANSI: define if you wish to disallow users from typing in commands that + * contain ANSI escape sequences. Defining NO_ANSI causes all escapes + * (ASCII 27) to be replaced with a space ' ' before the string is passed + * to the action routines added with add_action. + * + * STRIP_BEFORE_PROCESS_INPUT allows the location where the stripping is + * done to be controlled. If it is defined, then process_input() doesn't + * see ANSI characters either; if it is undefined ESC chars can be processed + * by process_input(), but are stripped before add_actions are called. + * Note that if NO_ADD_ACTION is defined, then #define NO_ANSI without + * #define STRIP_BEFORE_PROCESS_INPUT is the same as #undef NO_ANSI. + * + * If you anticipate problems with users intentionally typing in ANSI codes + * to make your terminal flash, etc define this. + */ +#define NO_ANSI +#define STRIP_BEFORE_PROCESS_INPUT + +/* OPCPROF: define this if you wish to enable OPC profiling. Allows a dump + * of the # of times each efun is invoked (via the opcprof() efun). + */ +#undef OPCPROF + +/* OPCPROF_2D: define this if you wish to enable 2-D OPC profiling. Allows a + * dump of the # of times each *pair* of eoperators is invoked. + * + * You can't use this and OPCPROF at the same time. + */ +#undef OPCPROF_2D + +/* TRAP_CRASHES: define this if you want MudOS to call crash() in master.c + * and then shutdown when signals are received that would normally crash the + * driver. + */ +#define TRAP_CRASHES + +/* THIS_PLAYER_IN_CALL_OUT: define this if you wish this_player() to be + * usable from within call_out() callbacks. + */ +#define THIS_PLAYER_IN_CALL_OUT + +/* CALLOUT_HANDLES: If this is defined, call_out() returns an integer, which + * can be passed to remove_call_out() or find_call_out(). Removing call_outs + * by name is still allowed, but is significantly less efficient, and also + * doesn't work for function pointers. This option adds 4 bytes overhead + * per callout to keep track of the handle. + */ +#define CALLOUT_HANDLES + +/* FLUSH_OUTPUT_IMMEDIATELY: Causes output to be written to sockets + * immediately after being generated. Useful for debugging. + */ +#undef FLUSH_OUTPUT_IMMEDIATELY + +/* PRIVS: define this if you want object privileges. Your mudlib must + * explicitly make use of this functionality to be useful. Defining this + * this will increase the size of the object structure by 4 bytes (8 bytes + * on the DEC Alpha) and will add a new master apply during object creation + * to "privs_file". In general, privileges can be used to increase the + * granularity of security beyond the current root uid mechanism. + * + * [NOTE: for those who'd rather do such things at the mudlib level, look at + * the inherits() efun and the 'valid_object' apply to master.] + */ +#undef PRIVS + +/* INTERACTIVE_CATCH_TELL: define this if you want catch_tell called on + * interactives as well as NPCs. If this is defined, user.c will need a + * catch_tell(msg) method that calls receive(msg); +*/ +#undef INTERACTIVE_CATCH_TELL + +/* RECEIVE_ED: define this if you want normal ed output to go to a + receive_ed() apply in the player ob. Some errors still go directly + to output. Useful for post-processing (perhaps colorizing?) ed + output. Prototype: mixed receive_ed(string txt, string fname); + If fname, return a string that ed will output, 0 to let ed handle + the output in the default way, or 1 to handle the output yourself. + If fname == 0, output is help text and you may return any of the above + or an array of strings that will be more'ed. +*/ +#undef RECEIVE_ED + +/* RESTRICTED_ED: define this if you want restricted ed mode enabled. + */ +#define RESTRICTED_ED + +/* NO_SHADOWS: define this if you want to disable shadows in your driver. + */ +#undef NO_SHADOWS + +/* SNOOP_SHADOWED: define this if you want snoop to report what is + * sent to the player even in the event that the player's catch_tell() is + * shadowed and the player may not be seeing what is being sent. Messages + * of this sort will be prefixed with $$. + */ +#undef SNOOP_SHADOWED + +/* RECEIVE_SNOOP: define this if you want snoop text to be sent to + * the receive_snoop() function in the snooper object (instead of being + * sent directly via add_message()). This is useful if you want to + * build a smart client that does something different with snoop messages. + */ +#define RECEIVE_SNOOP + +/* PROFILE_FUNCTIONS: define this to be able to measure the CPU time used by + * all of the user-defined functions in each LPC object. Note: defining + * this adds three long ints (12 bytes on 32-bit machines) to the function + * header structs. Also note that the resolution of the getrusage() timer + * may not be high enough on some machines to give non-zero execution + * times to very small (fast) functions. In particular if the clock + * resolution is 1/60 of a second, then any time less than approxmately 15k + * microseconds will resolve to zero (0). + */ +#undef PROFILE_FUNCTIONS + +/* NO_BUFFER_TYPE: if this is #define'd then LPC code using the 'buffer' + * type won't be allowed to compile (since the 'buffer' type won't be + * recognized by the lexer). + */ +#undef NO_BUFFER_TYPE + +/* BINARIES: define this to enable the 'save_binary' pragma. + * This pragma, when set in a program, will cause it to save a + * binary image when loaded, so that subsequent loadings will + * be much faster. The binaries are saved in the directory + * specified in the configuration file. The binaries will not + * load if the LPC source or any of the inherited or included + * files are out of date, in which case the file is compiled + * normally (and may save a new binary). + * + * In order to save the binary, valid_save_binary() is called + * in master.c, and is passed the name of the source file. If + * this returns a non-zero value, the binary is allowed to be + * saved. Allowing any file by any wizard to be saved as a + * binary is convenient, but may take up a lot of disk space. + */ +#define BINARIES + +/* ARRAY_RESERVED_WORD: If this is defined then the word 'array' can + * be used to define arrays, as in: + * + * int array x = ({ .... }); + * + * A side effect is that 'array' cannot be a variable or function name. + */ +#undef ARRAY_RESERVED_WORD + +/* REF_RESERVED_WORD: If this is defined then the word 'ref' can be + * used to pass arguments to functions by value. Example: + * + * void inc(int ref x) { + * x++; + * } + * + * ... y = 1; inc(ref y); ... + * + * A side effect is that 'ref' cannot be a variable or function name. + * + * Note: ref must be used in *both* places; this is intentional. It protects + * against passing references to routines which don't intend to return values + * through their arguments, and against forgetting to pass a reference + * to a function which wants one (or accidentally having a variable modified!) + */ +#define REF_RESERVED_WORD + +/**************************************************************************** + * PACKAGES * + * -------- * + * Defining some/all of the following add certain efuns, and sometimes * + * add/remove code from the driver. * + * * + * if PACKAGE_XYZZY is defined here, then the code in packages/xyzzy.c * + * and the efuns in packages/xyzzy_spec.c will be added to the driver. * + ****************************************************************************/ + +/* various miscellaneous efuns */ +#define PACKAGE_CONTRIB + +/* efuns that are only of use to those that know something about driver + internals */ +#define PACKAGE_DEVELOP + +/* PACKAGE_MATH: determines whether or not the math efuns (for floats) are + included. + */ +#define PACKAGE_MATH + +/* PACKAGE_MATRIX: determines whether or not the 3d graphics efuns (for floats) + * are included - see packages/matrix.spec for a list. + */ +#undef PACKAGE_MATRIX + +/* PACKAGE_MUDLIB_STATS: define this to enable domain and author stats + * maintenance by the driver. These mudlib stats are more domain + * based than user based, and replaces the traditional wiz_list stats. + */ +#undef PACKAGE_MUDLIB_STATS + +/* PACKAGE_SOCKETS: define this to enable the socket efunctions. This + * causes HAS_SOCKETS to be defined for all LPC objects. + */ +#define PACKAGE_SOCKETS + +/* PACKAGE_PARSER: Natural language parsing efuns for interactive fiction + * type applications + */ +#undef PACKAGE_PARSER + +/* PACKAGE_EXTERNAL: Allows the driver to exec() commands specified in the + * config file. + */ +#define PACKAGE_EXTERNAL + +/* NUM_EXTERNAL_CMDS: the number of external commands supported */ +#ifdef PACKAGE_EXTERNAL +#define NUM_EXTERNAL_CMDS 100 +#endif + +/* PACKAGE_DB: efuns for external database access using msql */ +#define PACKAGE_DB + +/* If PACKAGE_DB is defined above, you must pick ONE of the following supported + * databases + */ +#ifdef PACKAGE_DB +#undef USE_MSQL +#undef MSQL +#define USE_MYSQL 2 +#define MY_SQL +#endif + +/**************************************************************************** + * UID PACKAGE * + * ----------- * + * UIDS are the basis for some mudlib security systems. Basically, they're * + * preserved for backwards compatibility, as several ways of breaking * + * almost any system which relies on them are known. (No, it's not a flaw * + * of uids; only that b/c of the ease with which LPC objects can call * + * each other, it's far too easy to leave holes) * + * * + * If you don't care about security, the first option is probably what you * + * want. * + ****************************************************************************/ + +/* + * PACKAGE_UIDS: define this if you want a driver that does use uids. + * + */ +#define PACKAGE_UIDS + +/* AUTO_SETEUID: when an object is created it's euid is automatically set to + * the equivalent of seteuid(getuid(this_object())). undef AUTO_SETEUID + * if you would rather have the euid of the created object be set to 0. + */ +#define AUTO_SETEUID + +/* AUTO_TRUST_BACKBONE: define this if you want objects with the backbone + * uid to automatically be trusted and to have their euid set to the uid of + * the object that forced the object's creation. + */ +#undef AUTO_TRUST_BACKBONE + +/************************************************************************* + * FOR EXPERIENCED USERS * + * ----------------------- * + * Most of these options will probably be of no interest to many users. * + *************************************************************************/ + +/* USE_32BIT_ADDRESSES: Use 32 bits for addresses of function, instead of + * the usual 16 bits. This increases the maximum program size from 64k + * of LPC bytecode (NOT source) to 4 GB. Branches are still 16 bits, + * imposing a 64k limit on catch(), if(), switch(), loops, and most other + * control structures. It would take an extremely large function to hit + * those limits, though. + * + * Overhead: 2 bytes/function with LPC->C off. Having LPC->C on forces + * this option, since it needs 4 bytes to store the function pointers + * anyway, and this setting is ignored. + */ +#define USE_32BIT_ADDRESSES + +/* HEARTBEAT_INTERVAL: define heartbeat interval in microseconds (us). + * 1,000,000 us = 1 second. The value of this macro specifies + * the frequency with which the heart_beat method will be called in + * those LPC objects which have called set_heart_beat(1). + * + * [NOTE: if ualarm() isn't available, alarm() is used instead. Since + * alarm() requires its argument in units of a second, we map 1 - 1,000,000 us + * to an actual interval of one (1) second and 1,000,001 - 2,000,000 maps to + * an actual interval of two (2) seconds, etc.] + */ +#define HEARTBEAT_INTERVAL 2 + +/* + * CALLOUT_CYCLE_SIZE: This is the number of slots in the call_out list. + * It should be approximately the average number of active call_outs, or + * a few times smaller. It should also be a power of 2, and also be relatively + * prime to any common call_out lengths. If all this is too confusing, 32 + * isn't a bad number :-) + */ +#define CALLOUT_CYCLE_SIZE 1024 + +/* LARGEST_PRINTABLE_STRING: defines the size of the vsprintf() buffer in + * comm.c's add_message(). Instead of blindly making this value larger, + * your mudlib should be coded to not send huge strings to users. + */ +#define LARGEST_PRINTABLE_STRING 300000 + +/* MESSAGE_BUFFER_SIZE: determines the size of the buffer for output that + * is sent to users. + */ +#define MESSAGE_BUFFER_SIZE 4096 + +/* APPLY_CACHE_BITS: defines the number of bits to use in the call_other cache + * (in interpret.c). + * + * Memory overhead is (1 << APPLY_CACHE_BITS)*16. + * [assuming 32 bit pointers and 16 bit shorts] + * + * ACB: entries: overhead: + * 6 64 1k + * 8 256 4k + * 10 1024 16k + * 12 4096 64k + * 14 16384 256k + * 16 65536 1M + */ +#define APPLY_CACHE_BITS 15 + +/* CACHE_STATS: define this if you want call_other (apply_low) cache + * statistics. Causes HAS_CACHE_STATS to be defined in all LPC objects. + */ +#define CACHE_STATS + +/* TRACE: define this to enable the trace() and traceprefix() efuns. + * (keeping this undefined will cause the driver to run faster). + */ +#define TRACE + +/* LPC_TO_C: define this to enable LPC->C compilation. + * + * [NOTE: BINARIES must also be defined for LPC->C to work. Actually + * using binaries is not required, though.] + */ +#undef LPC_TO_C + +/* RUNTIME_LOADING: On systems which support it, it allows LPC->C compilation + * 'on the fly' without having to recompile the driver. + * + * Note: This currently only works on machines that have the dlopen() system + * call. SunOS and IRIX do, as do a number of others. AIX and Ultrix don't. + * Linux does if you are using ELF. + */ +#undef RUNTIME_LOADING + +/* TRACE_CODE: define this to enable code tracing (the driver will print + * out the previous lines of code to an error) eval_instruction() runs about + * twice as fast when this is not defined (for the most common eoperators). + */ +#undef TRACE_CODE + +/* HEART_BEAT_CHUNK: The number of heart_beat chunks allocated at a time. + * A large number wastes memory as some will be sitting around unused, while + * a small one wastes more CPU reallocating when it needs to grow. Default + * to a medium value. + */ +#define HEART_BEAT_CHUNK 512 + +/* SERVER_IP: For machines with multiple IP addresses, this specifies which + * one to use. This is useful for IP accounting and is necessary to be + * able to do ident lookups on such machines. + * + * example: #define SERVER_IP "194.229.18.27" + */ +#undef SERVER_IP + +/* Some maximum string sizes + */ +#define SMALL_STRING_SIZE 100 +#define LARGE_STRING_SIZE 1000 +#define COMMAND_BUF_SIZE 2000 + +/* Number of levels of nested datastructures allowed -- this limit prevents + * crashes from occuring when saving objects containing variables containing + * recursive datastructures (with circular references). + */ +#define MAX_SAVE_SVALUE_DEPTH 100 + +/* Miscellaneous config options that should probably be in the runtime + * config file. + */ +/* MAX_LOCAL: maximum number of local variables allowed per LPC function */ +#define CFG_MAX_LOCAL_VARIABLES 250 +/* Increasing max global vars beyond 256 is not recommended */ +#define CFG_MAX_GLOBAL_VARIABLES 65530 + +#define CFG_EVALUATOR_STACK_SIZE 3000000 +#define CFG_COMPILER_STACK_SIZE 600000 +#define CFG_MAX_CALL_DEPTH 2500 +/* This must be one of 4, 16, 64, 256, 1024, 4096 */ +#define CFG_LIVING_HASH_SIZE 256 + +/* NEXT_MALLOC_DEBUG: define this if using a NeXT and you want to enable + * the malloc_check() and/or malloc_debug() efuns. Run the 'man malloc_debug' + * command on the NeXT to find out what the arguments to malloc_debug(int) + * mean. The malloc_check() efun calls the NeXT NXMallocCheck() system + * call which does a consistency check on malloc's data structures (this + * consistency check is done at each malloc() and free() for certain + * malloc_debug() levels). A non-zero return value indicates there was + * a consistency problem. For those NeXT users wanting a bit more + * performance out of malloc, try defining NEXT_MALLOC_DEBUG and calling the + * malloc_debug(-1) efun (with an arg of -1). This will turn all + * malloc debugging off and call malloc_singlethreaded() which the NeXT + * malloc man page claims can make NeXT system malloc 10% to 15% faster. + * + * [NOTE: This #define has no affect on the driver if not using the + * NeXTSTEP OS.] + * + * Warning: if you use a NeXT and define NEXT_MALLOC_DEBUG, be sure to + * protect the use of the malloc_check() and malloc_debug() efuns + * since setting certain debug levels can cause malloc() and free() + * to become _very_ slow (protect efuns by using simul_efuns and + * valid_override). + * + * [NOTE: malloc_debug(6) is a good compromise between efficiency and + * completeness of malloc debugging (malloc/free will be about half as fast).] + */ +#undef NEXT_MALLOC_DEBUG + + +/* GET_CHAR_IS_BUFFERED: Normally get_char() is unbuffered. That is, once + * a character is received for get_char(), anything else is in the input + * stream is immediately thrown away. This can be very undesirable, especially + * if you're calling get_char() again from the handler from the previous call. + * Define this if you want get_char() to be buffered. In this case, the buffer + * will only get flushed if get_char() is not called from the first get_char()'s + * LPC callback handler. + */ +#undef GET_CHAR_IS_BUFFERED + +#define HAVE_ZLIB +#define PACKAGE_COMPRESS +#define SAVE_GZ_EXTENSION ".o.gz" +#undef CALL_OTHER_TYPE_CHECK +#define CALL_OTHER_WARN +#define PACKAGE_DWLIB +#undef MMAP_SBRK +#define WARN_TAB +#define USE_ICONV +#define WOMBLES +#undef ALLOW_INHERIT_AFTER_FUNCTION +#define PACKAGE_ASYNC +#define PROG_REF_TYPE short +#define HAS_CONSOLE +#define IPV6 +#undef PACKAGE_CRYPTO +#define PACKAGE_SHA1 +#undef DTRACE +#define PACKAGE_PCRE +#endif diff --git a/fluffos-2.23-ds03/local_options.foundation b/fluffos-2.23-ds03/local_options.foundation new file mode 100644 index 0000000..73b5008 --- /dev/null +++ b/fluffos-2.23-ds03/local_options.foundation @@ -0,0 +1,894 @@ +/* + * options.h: defines for the compile-time configuration of the MudOS driver + */ + +#ifndef _OPTIONS_H_ +#define _OPTIONS_H_ + +/* + * YOU PROBABLY DO NOT WANT TO MODIFY THIS FILE. + * + * Do 'cp options.h local_options' and edit that instead. local_options, + * if it exists, overrides this file. + * + * The advantage is that when you upgrade to a newer MudOS driver, you can + * simply copy your local_options file into the src directory. The build + * process will warn you if new options have been added that you should + * choose settings for. + */ + +/**************************************************************************** + * EVERY time you change ANYTHING in this file, RECOMPILE from scratch. * + * (type "make clean" then "make" on a UNIX system) Failure to do so may * + * cause the driver to behave oddly. * + ****************************************************************************/ + +/* NOTES: + * Many of the configurable options are now set via the configuration file + * that is specified as the first argument to the driver. + * See port.h for those #defines related to portability (compatibility) if + * you have problems compiling on your system. + * Removing an efun from func_spec.c usually removes most, if not all, + * of the code associated with it. + * Note that anything defined in this file is also visible to LPC files + * surrounded by __. So #define FOO in this file defines __FOO__ for + * all LPC files. This allows code like: + * + * #ifdef __SENSIBLE_MODIFIERS__ + * ... + */ + +/**************************************************************************** + * MALLOC * + * -------- * + * For performance reasons, LP drivers have a variety of memory allocation * + * packages. If you don't care, use the default one on your system: * + * #define SYSMALLOC, #undef the others. * + ****************************************************************************/ + +/* You must choose exactly one of these malloc packages: + * ~~~~ + * SYSMALLOC: + * * Built-in system malloc. + * * No statistics. + * * SYSMALLOC incurs no additional CPU or memory overhead. + * + * SMALLOC: + * * Satoria's smalloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than most system mallocs with modest ammount of memory overhead. + * * Can fall back onto system malloc if sbrk() not ok. + * + * BSDMALLOC: + * * BSD (Berkeley Software Distributions) malloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than SMALLOC but more memory overhead. + * * Requires sbrk(). + */ +#define SYSMALLOC +#undef SMALLOC +#undef BSDMALLOC +#undef MMALLOC + +/* You may optionally choose one (or none) of these malloc wrappers. These + * can be used in conjunction with any of the above malloc packages. + * + * WRAPPEDMALLOC: + * * Limited statistics. + * * Limited additional cpu overhead and no additional memory overhead. + * + * DEBUGMALLOC: + * * Statistics on precisely how much memory has been malloc'd (as well + * as the stats provided by WRAPPEDMALLOC). + * * Incurs a fair amount of overhead (both memory and CPU) + */ +#undef WRAPPEDMALLOC +#undef DEBUGMALLOC + +/* The following add certain bells and whistles to malloc: */ + +/* + * SBRK_OK: do not define this unless SMALLOC is chosen above. + * Defining this causes smalloc to use the low level memory allocation + * routines, and to act as a malloc replacement. Conversely, undef'ing + * SBRK_OK causes smalloc to act as a wrapper for the system malloc + * routines. + * + * Note: + * NeXTStep 3.x users should always #undef SBRK_OK. + */ +#undef SBRK_OK + +/* DO_MSTATS: do not define this unless BSDMALLOC or SMALLOC is chosen above. + * Defining this causes those replacement mallocs to keep statistics that + * the malloc_status() efun will print out (including total memory + * allocated/used). + */ +#undef DO_MSTATS + +/* DEBUGMALLOC_EXTENSIONS: defining this (in addition to DEBUGMALLOC) enables + * the set_malloc_mask(int) and debugmalloc(string,int) efuns. These two + * efuns basically allow you to cause certain malloc's and free's (with tags + * selected by a specified mask) to print debug information (addr, tag, + * description, size) to stdio (in the shell that invoked the driver) or to a + * file. Not defining this does reduce the overhead of DEBUGMALLOC from 16 + * bytes per malloc down to 8. This macro has no effect if DEBUGMALLOC isn't + * defined. + */ +#undef DEBUGMALLOC_EXTENSIONS + +/* CHECK_MEMORY: defining this (in addition to DEBUGMALLOC and + * DEBUGMALLOC_EXTENSIONS) causes the driver to check for memory + * corruption due to writing before the start or end of a block. This + * also adds the check_memory() efun. Takes a considerable ammount + * more memory. Mainly for debugging. + */ +#undef CHECK_MEMORY + +/**************************************************************************** + * COMPATIBILITY * + * --------------- * + * The MudOS driver has evolved quite a bit over the years. These defines * + * are mainly to preserve old behavior in case people didn't want to * + * rewrite the relevant portions of their code. * + * * + * In most cases, code which needs these defines should be rewritten when * + * possible. The 'Compat status' field is designed to give an idea how * + * likely it is that support for that option will be removed in the near * + * future. Certain options are fairly easy to work around, and double * + * the size of the associated code, as well as the maintenance workload, * + * and can make the code significantly more complex or harder to read, so * + * supporting them indefinitely is impractical. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* HAS_STATUS_TYPE: old MudOS drivers had a 'status' type which was + * identical to the 'int' type. Define this to bring it back. + * + * Compat status: very archaic, but easy to support. + */ +#define HAS_STATUS_TYPE + +/* explode(): + * + * The old behavior (#undef both of the below) strips any number of + * delimiters at the start of the string, and one at the end. So + * explode("..x.y..z..", ".") gives ({ "x", "y", "", "z", "" }) + * + * SANE_EXPLODE_STRING strips off at most one leading delimiter, and + * still strips off one at the end, so the example above gives + * ({ "", "x", "y", "", "z", "" }). + * + * REVERSIBLE_EXPLODE_STRING overrides SANE_EXPLODE_STRING, and makes + * it so that implode(explode(x, y), y) is always x; i.e. no delimiters + * are ever stripped. So the example above gives + * ({ "", "", "x", "y", "", "z", "", "" }). + */ +#undef SANE_EXPLODE_STRING +#undef REVERSIBLE_EXPLODE_STRING + +/* CAST_CALL_OTHERS: define this if you want to require casting of call_other's; + * this was the default behavior of the driver prior to this addition. + * + * Compat status: code that requires it doesn't break, and it promotes + * sloppy coding with no benefits. + */ +#undef CAST_CALL_OTHERS + +/* NONINTERACTIVE_STDERR_WRITE: if defined, all writes/tells/etc to + * noninteractive objects will be written to stderr prefixed with a ']' + * (old behavior). + * + * Compat status: Easy to support, and also on the "It's a bug! No, it's + * a feature!" religious war list. + */ +#define NONINTERACTIVE_STDERR_WRITE + +/* NO_LIGHT: define this to disable the set_light() and driver maintenance + * of light levels in objects. You can simulate it via LPC if you want... + * + * Compat status: Very dated, easy to simulate, and gross. + */ +#define NO_LIGHT + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + * process_input() then becomes the only way to deal with player input. + * + * Compat status: next to impossible to simulate, hard to replace, and + * very, very widely used. + */ +#undef NO_ADD_ACTION + +/* NO_SNOOP: disables the snoop() efun and all related functionality. + */ +#undef NO_SNOOP + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + process_input() then becomes the only way to deal with player input. */ + +/* NO_ENVIRONMENT: define this to remove the handling of object containment + * relationships by the driver + * + * Compat status: hard to simulate efficiently, and very widely used. + */ +#undef NO_ENVIRONMENT + +/* NO_WIZARDS: for historical reasons, MudOS used to keep track of who + * is and isn't a wizard. Defining this removes that completely. + * If this is defined, the wizardp() and related efuns don't exist. + * + * Also note that if it is not defined, then non-wizards are always put + * in restricted mode when ed() is used, regardless of the setting of + * the restrict parameter. + * + * Compat status: easy to simulate and dated. + */ +#define NO_WIZARDS + +/* OLD_TYPE_BEHAVIOR: reintroduces a bug in type-checking that effectively + * renders compile time type checking useless. For backwards compatibility. + * + * Compat status: dealing with all the resulting compile errors can be + * a huge pain even if they are correct, and the impact on the code is + * small. + */ +#undef OLD_TYPE_BEHAVIOR + +/* OLD_RANGE_BEHAVIOR: define this if you want negative indexes in string + * or buffer range values (not lvalue, i.e. x[-2..-1]; for e.g. not + * x[-2..-1] = foo, the latter is always illegal) to mean counting from the + * end + * + * Compat status: Not horribly difficult to replace reliance on this, but not + * trivial, and cannot be simulated. + */ +#undef OLD_RANGE_BEHAVIOR + +/* OLD_ED: ed() efun backwards compatible with the old version. The new + * version requires/allows a mudlib front end. + * + * Compat status: Easily simulated. + */ +#define OLD_ED + +/* SENSIBLE_MODIFIERS: + * Turning this on changes a few things, which may break old code: + * + * (1) 'static' is not recognized; either 'nosave' or 'protected' must + * be used instead. + * (2) The old meaning of 'public' is no longer allowed. Explicit + * functions must be defined at each level to allow access to + * privately inherited functions. + * (3) 'public' now means the default visibility. Previously there was + * no keyword that meant this (before you ask, 'public' meant something + * else, and if you don't know that, you probably don't have any reason + * to care about the old meaning). + */ +#undef SENSIBLE_MODIFIERS + +/**************************************************************************** + * MISCELLANEOUS * + * --------------- * + * Various options that affect the way the driver behaves. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* + * Define this in order to use Fermat@Equilibria's MD5 based crypt() instead + * of the operating system's. It has the advantage of giving the same value + * on all architectures, and being stronger than the standard UNIX crypt(). + */ +#define CUSTOM_CRYPT + +/* + * Some minor tweaks that make it a bit easier to run code designed to run + * on LPmud 3.2/3.2.1. Currently has the following effects: + * + * . m_indices() and m_values() are synonyms for keys() and values(), + * respectively + * . map_delete() returns it's first argument + * . inherit_list() means deep_inherit_list(), not shallow_inherit_list() + * . heart_beat_info() is a synonym for heart_beats() + */ +#undef COMPAT_32 + +/* + * Keep statistics about allocated strings, etc. Which can be viewed with + * the mud_status() efun. If this is off, mud_status() and memory_info() + * ignore allocated strings, but string operations run faster. + */ +#define STRING_STATS + +/* + * Similarly for arrays ... + */ +#define ARRAY_STATS + +/* LOG_CATCHES: define this to cause errors that are catch()'d to be + * sent to the debug log anyway. + * + * On by default, because newer libs use catch() a lot, and it's confusing + * if the errors don't show up in the logs. + */ +#define LOG_CATCHES + +/* ARGUMENTS_IN_TRACEBACK: prints out function call arguments in error + * tracebacks, to aid in debugging. Note: it prints the values of + * the arguments at the time of the error, not when the function + * was called. It looks like this: + * + * Failed to load file: read_buffer + * program: command/update.c, object: command/update line 15 + * ' commandHook' in ' clone/user.c' (' clone/user#1')line 72 + * arguments were ("/read_buffer.c") + * ' main' in ' command/update.c' (' command/update')line 15 + * arguments were ("/read_buffer.c") + * + * The only down side is some people like their logs shorter + */ +#define ARGUMENTS_IN_TRACEBACK + +/* LOCALS_IN_TRACEBACK: similar to ARGUMENTS_IN_TRACEBACK, but for local + * variables. The output looks more or less like: + * + * locals: 1, "local_value" + * + * Same as above. Tends to produce even longer logs, but very useful for + * tracking errors. + */ +#define LOCALS_IN_TRACEBACK + +/* MUDLIB_ERROR_HANDLER: If you define this, the driver doesn't do any + * handling of runtime errors, other than to turn the heartbeats of + * objects off. Information about the error is passed in a mapping + * to the error_handler() function in the master object. Whatever is + * returned is put in the debug.log. + * + * A good mudlib error handler is one of the best tools for tracking down + * errors. Unfortunately, you need to have one. Check the testsuite or + * other libs for an example. + */ +#define MUDLIB_ERROR_HANDLER + +/* CONFIG_FILE_DIR specifies a directory in which the driver will search for + * config files by default. If you don't wish to use this define, you may + * always specify a full path to the config file when starting the driver. + */ +#define CONFIG_FILE_DIR "./" + +/* DEFAULT_PRAGMAS: This should be a sum of pragmas you want to always + * be on, i.e. + * + * #define DEFAULT_PRAGMAS PRAGMA_STRICT_TYPES + PRAGMA_SAVE_TYPES + * + * will make every LPC file behave as if it had the lines: + * #pragma strict_types + * #pragma save_types + * + * for no default pragmas: + * #define DEFAULT_PRAGMAS 0 + * + * If you don't know what these are, 0 is a good choice. + * + * Supported pragmas: + * PRAGMA_STRICT_TYPES: enforces strict type checking + * PRAGMA_WARNINGS: issues warnings about various dangerous things in + * your code + * PRAGMA_SAVE_TYPES: save the types of function arguments for checking + * calls to functions in this object by objects that + * inherit it. + * PRAGMA_SAVE_BINARY: save a compiled binary version of this file for + * faster loading next time it is needed. + * PRAGMA_OPTIMIZE: make a second pass over the generated code to + * optimize it further. Currently does jump threading. + * PRAGMA_ERROR_CONTEXT:include some text telling where on the line a + * compilation error occured. + */ +#define DEFAULT_PRAGMAS 0 + +/* supress warnings about unused arguments; only warn about unused local + * variables. Makes older code (where argument names were required) compile + * more quietly. + */ +#define SUPPRESS_ARGUMENT_WARNINGS + +/* NO_RESETS: completely disable the periodic calling of reset() */ +#undef NO_RESETS + +/* LAZY_RESETS: if this is defined, an object will only have reset() + * called in it when it is touched via call_other() or move_object() + * (assuming enough time has passed since the last reset). If LAZY_RESETS + * is #undef'd, then reset() will be called as always (which guaranteed that + * reset would always be called at least once). The advantage of lazy + * resets is that reset doesn't get called in an object that is touched + * once and never again (which can save memory since some objects won't get + * reloaded that otherwise would). + */ +#undef LAZY_RESETS + +/* SAVE_EXTENSION: defines the file extension used by save_object(). + * and restore_object(). Some sysadmins run scripts that periodically + * scan for and remove files ending in .o (but many mudlibs are already + * set up to use .o thus we leave .o as the default). + */ +#define SAVE_EXTENSION ".o" + +/* NO_ANSI: define if you wish to disallow users from typing in commands that + * contain ANSI escape sequences. Defining NO_ANSI causes all escapes + * (ASCII 27) to be replaced with a space ' ' before the string is passed + * to the action routines added with add_action. + * + * STRIP_BEFORE_PROCESS_INPUT allows the location where the stripping is + * done to be controlled. If it is defined, then process_input() doesn't + * see ANSI characters either; if it is undefined ESC chars can be processed + * by process_input(), but are stripped before add_actions are called. + * Note that if NO_ADD_ACTION is defined, then #define NO_ANSI without + * #define STRIP_BEFORE_PROCESS_INPUT is the same as #undef NO_ANSI. + * + * If you anticipate problems with users intentionally typing in ANSI codes + * to make your terminal flash, etc define this. + */ +#define NO_ANSI +#define STRIP_BEFORE_PROCESS_INPUT + +/* OPCPROF: define this if you wish to enable OPC profiling. Allows a dump + * of the # of times each efun is invoked (via the opcprof() efun). + */ +#undef OPCPROF + +/* OPCPROF_2D: define this if you wish to enable 2-D OPC profiling. Allows a + * dump of the # of times each *pair* of eoperators is invoked. + * + * You can't use this and OPCPROF at the same time. + */ +#undef OPCPROF_2D + +/* TRAP_CRASHES: define this if you want MudOS to call crash() in master.c + * and then shutdown when signals are received that would normally crash the + * driver. + */ +#define TRAP_CRASHES + +/* THIS_PLAYER_IN_CALL_OUT: define this if you wish this_player() to be + * usable from within call_out() callbacks. + */ +#define THIS_PLAYER_IN_CALL_OUT + +/* CALLOUT_HANDLES: If this is defined, call_out() returns an integer, which + * can be passed to remove_call_out() or find_call_out(). Removing call_outs + * by name is still allowed, but is significantly less efficient, and also + * doesn't work for function pointers. This option adds 4 bytes overhead + * per callout to keep track of the handle. + */ +#define CALLOUT_HANDLES + +/* FLUSH_OUTPUT_IMMEDIATELY: Causes output to be written to sockets + * immediately after being generated. Useful for debugging. + */ +#undef FLUSH_OUTPUT_IMMEDIATELY + +/* PRIVS: define this if you want object privileges. Your mudlib must + * explicitly make use of this functionality to be useful. Defining this + * this will increase the size of the object structure by 4 bytes (8 bytes + * on the DEC Alpha) and will add a new master apply during object creation + * to "privs_file". In general, privileges can be used to increase the + * granularity of security beyond the current root uid mechanism. + * + * [NOTE: for those who'd rather do such things at the mudlib level, look at + * the inherits() efun and the 'valid_object' apply to master.] + */ +#define PRIVS + +/* INTERACTIVE_CATCH_TELL: define this if you want catch_tell called on + * interactives as well as NPCs. If this is defined, user.c will need a + * catch_tell(msg) method that calls receive(msg); +*/ +#undef INTERACTIVE_CATCH_TELL + +/* RESTRICTED_ED: define this if you want restricted ed mode enabled. + */ +#define RESTRICTED_ED + +/* NO_SHADOWS: define this if you want to disable shadows in your driver. + */ +#undef NO_SHADOWS + +/* SNOOP_SHADOWED: define this if you want snoop to report what is + * sent to the player even in the event that the player's catch_tell() is + * shadowed and the player may not be seeing what is being sent. Messages + * of this sort will be prefixed with $$. + */ +#undef SNOOP_SHADOWED + +/* RECEIVE_SNOOP: define this if you want snoop text to be sent to + * the receive_snoop() function in the snooper object (instead of being + * sent directly via add_message()). This is useful if you want to + * build a smart client that does something different with snoop messages. + */ +#define RECEIVE_SNOOP + +/* PROFILE_FUNCTIONS: define this to be able to measure the CPU time used by + * all of the user-defined functions in each LPC object. Note: defining + * this adds three long ints (12 bytes on 32-bit machines) to the function + * header structs. Also note that the resolution of the getrusage() timer + * may not be high enough on some machines to give non-zero execution + * times to very small (fast) functions. In particular if the clock + * resolution is 1/60 of a second, then any time less than approxmately 15k + * microseconds will resolve to zero (0). + */ +#undef PROFILE_FUNCTIONS + +/* NO_BUFFER_TYPE: if this is #define'd then LPC code using the 'buffer' + * type won't be allowed to compile (since the 'buffer' type won't be + * recognized by the lexer). + */ +#undef NO_BUFFER_TYPE + +/* BINARIES: define this to enable the 'save_binary' pragma. + * This pragma, when set in a program, will cause it to save a + * binary image when loaded, so that subsequent loadings will + * be much faster. The binaries are saved in the directory + * specified in the configuration file. The binaries will not + * load if the LPC source or any of the inherited or included + * files are out of date, in which case the file is compiled + * normally (and may save a new binary). + * + * In order to save the binary, valid_save_binary() is called + * in master.c, and is passed the name of the source file. If + * this returns a non-zero value, the binary is allowed to be + * saved. Allowing any file by any wizard to be saved as a + * binary is convenient, but may take up a lot of disk space. + */ +#define BINARIES + +/* ARRAY_RESERVED_WORD: If this is defined then the word 'array' can + * be used to define arrays, as in: + * + * int array x = ({ .... }); + * + * A side effect is that 'array' cannot be a variable or function name. + */ +#undef ARRAY_RESERVED_WORD + +/* REF_RESERVED_WORD: If this is defined then the word 'ref' can be + * used to pass arguments to functions by value. Example: + * + * void inc(int ref x) { + * x++; + * } + * + * ... y = 1; inc(ref y); ... + * + * A side effect is that 'ref' cannot be a variable or function name. + * + * Note: ref must be used in *both* places; this is intentional. It protects + * against passing references to routines which don't intend to return values + * through their arguments, and against forgetting to pass a reference + * to a function which wants one (or accidentally having a variable modified!) + */ +#undef REF_RESERVED_WORD + +/**************************************************************************** + * PACKAGES * + * -------- * + * Defining some/all of the following add certain efuns, and sometimes * + * add/remove code from the driver. * + * * + * if PACKAGE_XYZZY is defined here, then the code in packages/xyzzy.c * + * and the efuns in packages/xyzzy_spec.c will be added to the driver. * + ****************************************************************************/ + +/* various miscellaneous efuns */ +#define PACKAGE_CONTRIB + +/* efuns that are only of use to those that know something about driver + internals */ +#define PACKAGE_DEVELOP + +/* PACKAGE_MATH: determines whether or not the math efuns (for floats) are + included. + */ +#define PACKAGE_MATH + +/* PACKAGE_MATRIX: determines whether or not the 3d graphics efuns (for floats) + * are included - see packages/matrix.spec for a list. + */ +#define PACKAGE_MATRIX + +/* PACKAGE_MUDLIB_STATS: define this to enable domain and author stats + * maintenance by the driver. These mudlib stats are more domain + * based than user based, and replaces the traditional wiz_list stats. + */ +#define PACKAGE_MUDLIB_STATS + +/* PACKAGE_SOCKETS: define this to enable the socket efunctions. This + * causes HAS_SOCKETS to be defined for all LPC objects. + */ +#define PACKAGE_SOCKETS + +/* PACKAGE_PARSER: Natural language parsing efuns for interactive fiction + * type applications + */ +#define PACKAGE_PARSER + +/* PACKAGE_EXTERNAL: Allows the driver to exec() commands specified in the + * config file. + */ +#undef PACKAGE_EXTERNAL + +/* NUM_EXTERNAL_CMDS: the number of external commands supported */ +#define NUM_EXTERNAL_CMDS 100 + +/* PACKAGE_DB: efuns for external database access using msql */ +#undef PACKAGE_DB + +/* If PACKAGE_DB is defined above, you must pick ONE of the following supported + * databases + */ +#ifdef PACKAGE_DB +#undef USE_MSQL +#undef MSQL +#define USE_MYSQL 2 +#define MY_SQL +#endif + +/**************************************************************************** + * UID PACKAGE * + * ----------- * + * UIDS are the basis for some mudlib security systems. Basically, they're * + * preserved for backwards compatibility, as several ways of breaking * + * almost any system which relies on them are known. (No, it's not a flaw * + * of uids; only that b/c of the ease with which LPC objects can call * + * each other, it's far too easy to leave holes) * + * * + * If you don't care about security, the first option is probably what you * + * want. * + ****************************************************************************/ + +/* + * PACKAGE_UIDS: define this if you want a driver that does use uids. + * + */ +#undef PACKAGE_UIDS + +/*PACKAGE DWLIB: some discworld mudlib simuls coded in C (well just one right + now) */ + +#undef PACKAGE_DWLIB + +/* AUTO_SETEUID: when an object is created it's euid is automatically set to + * the equivalent of seteuid(getuid(this_object())). undef AUTO_SETEUID + * if you would rather have the euid of the created object be set to 0. + */ +#undef AUTO_SETEUID + +/* AUTO_TRUST_BACKBONE: define this if you want objects with the backbone + * uid to automatically be trusted and to have their euid set to the uid of + * the object that forced the object's creation. + */ +#define AUTO_TRUST_BACKBONE + +/************************************************************************* + * FOR EXPERIENCED USERS * + * ----------------------- * + * Most of these options will probably be of no interest to many users. * + *************************************************************************/ + +/* USE_32BIT_ADDRESSES: Use 32 bits for addresses of function, instead of + * the usual 16 bits. This increases the maximum program size from 64k + * of LPC bytecode (NOT source) to 4 GB. Branches are still 16 bits, + * imposing a 64k limit on catch(), if(), switch(), loops, and most other + * control structures. It would take an extremely large function to hit + * those limits, though. + * + * Overhead: 2 bytes/function with LPC->C off. Having LPC->C on forces + * this option, since it needs 4 bytes to store the function pointers + * anyway, and this setting is ignored. + */ +#undef USE_32BIT_ADDRESSES + +/* HEARTBEAT_INTERVAL: define heartbeat interval in microseconds (us). + * 1,000,000 us = 1 second. The value of this macro specifies + * the frequency with which the heart_beat method will be called in + * those LPC objects which have called set_heart_beat(1). + * + * [NOTE: if ualarm() isn't available, alarm() is used instead. Since + * alarm() requires its argument in units of a second, we map 1 - 1,000,000 us + * to an actual interval of one (1) second and 1,000,001 - 2,000,000 maps to + * an actual interval of two (2) seconds, etc.] + */ +#define HEARTBEAT_INTERVAL 1 + +/* + * CALLOUT_CYCLE_SIZE: This is the number of slots in the call_out list. + * It should be approximately the average number of active call_outs, or + * a few times smaller. It should also be a power of 2, and also be relatively + * prime to any common call_out lengths. If all this is too confusing, 32 + * isn't a bad number :-) + */ +#define CALLOUT_CYCLE_SIZE 32 + +/* LARGEST_PRINTABLE_STRING: defines the size of the vsprintf() buffer in + * comm.c's add_message(). Instead of blindly making this value larger, + * your mudlib should be coded to not send huge strings to users. + */ +#define LARGEST_PRINTABLE_STRING 8192 + +/* MESSAGE_BUFFER_SIZE: determines the size of the buffer for output that + * is sent to users. + */ +#define MESSAGE_BUFFER_SIZE 4096 + +/* APPLY_CACHE_BITS: defines the number of bits to use in the call_other cache + * (in interpret.c). + * + * Memory overhead is (1 << APPLY_CACHE_BITS)*16. + * [assuming 32 bit pointers and 16 bit shorts] + * + * ACB: entries: overhead: + * 6 64 1k + * 8 256 4k + * 10 1024 16k + * 12 4096 64k + * 14 16384 256k + * 16 65536 1M + */ +#define APPLY_CACHE_BITS 11 + +/* CACHE_STATS: define this if you want call_other (apply_low) cache + * statistics. Causes HAS_CACHE_STATS to be defined in all LPC objects. + */ +#define CACHE_STATS + +/* TRACE: define this to enable the trace() and traceprefix() efuns. + * (keeping this undefined will cause the driver to run faster). + */ +#undef TRACE + +/* RUNTIME_LOADING: On systems which support it, it allows LPC->C compilation + * 'on the fly' without having to recompile the driver. + * + * Note: This currently only works on machines that have the dlopen() system + * call. SunOS and IRIX do, as do a number of others. AIX and Ultrix don't. + * Linux does if you are using ELF. + */ +#undef RUNTIME_LOADING + +/* TRACE_CODE: define this to enable code tracing (the driver will print + * out the previous lines of code to an error) eval_instruction() runs about + * twice as fast when this is not defined (for the most common eoperators). + */ +#undef TRACE_CODE + +/* HEART_BEAT_CHUNK: The number of heart_beat chunks allocated at a time. + * A large number wastes memory as some will be sitting around unused, while + * a small one wastes more CPU reallocating when it needs to grow. Default + * to a medium value. + */ +#define HEART_BEAT_CHUNK 32 + +/* SERVER_IP: For machines with multiple IP addresses, this specifies which + * one to use. This is useful for IP accounting and is necessary to be + * able to do ident lookups on such machines. + * + * example: #define SERVER_IP "194.229.18.27" + */ +#undef SERVER_IP + +/* Some maximum string sizes + */ +#define SMALL_STRING_SIZE 100 +#define LARGE_STRING_SIZE 1000 +#define COMMAND_BUF_SIZE 2000 + +/* Number of levels of nested datastructures allowed -- this limit prevents + * crashes from occuring when saving objects containing variables containing + * recursive datastructures (with circular references). + */ +#define MAX_SAVE_SVALUE_DEPTH 100 + +/* Miscellaneous config options that should probably be in the runtime + * config file. + */ +/* MAX_LOCAL: maximum number of local variables allowed per LPC function */ +#define CFG_MAX_LOCAL_VARIABLES 50 +/* Increasing max global vars beyond 256 is not recommended */ +#define CFG_MAX_GLOBAL_VARIABLES 256 + +#define CFG_EVALUATOR_STACK_SIZE 3000 +#define CFG_COMPILER_STACK_SIZE 600000 +#define CFG_MAX_CALL_DEPTH 150 +/* This must be one of 4, 16, 64, 256, 1024, 4096 */ +#define CFG_LIVING_HASH_SIZE 256 + +/* NEXT_MALLOC_DEBUG: define this if using a NeXT and you want to enable + * the malloc_check() and/or malloc_debug() efuns. Run the 'man malloc_debug' + * command on the NeXT to find out what the arguments to malloc_debug(int) + * mean. The malloc_check() efun calls the NeXT NXMallocCheck() system + * call which does a consistency check on malloc's data structures (this + * consistency check is done at each malloc() and free() for certain + * malloc_debug() levels). A non-zero return value indicates there was + * a consistency problem. For those NeXT users wanting a bit more + * performance out of malloc, try defining NEXT_MALLOC_DEBUG and calling the + * malloc_debug(-1) efun (with an arg of -1). This will turn all + * malloc debugging off and call malloc_singlethreaded() which the NeXT + * malloc man page claims can make NeXT system malloc 10% to 15% faster. + * + * [NOTE: This #define has no affect on the driver if not using the + * NeXTSTEP OS.] + * + * Warning: if you use a NeXT and define NEXT_MALLOC_DEBUG, be sure to + * protect the use of the malloc_check() and malloc_debug() efuns + * since setting certain debug levels can cause malloc() and free() + * to become _very_ slow (protect efuns by using simul_efuns and + * valid_override). + * + * [NOTE: malloc_debug(6) is a good compromise between efficiency and + * completeness of malloc debugging (malloc/free will be about half as fast).] + */ +#define NEXT_MALLOC_DEBUG + + +/* GET_CHAR_IS_BUFFERED: Normally get_char() is unbuffered. That is, once + * a character is received for get_char(), anything else is in the input + * stream is immediately thrown away. This can be very undesirable, especially + * if you're calling get_char() again from the handler from the previous call. + * Define this if you want get_char() to be buffered. In this case, the buffer + * will only get flushed if get_char() is not called from the first get_char()'s + * LPC callback handler. + */ +#undef GET_CHAR_IS_BUFFERED + +/* PACKAGE_COMPRESS: Enable MCCP support and compressed save files + SAVE_GZ_EXTENSION: save extension for compressed files + */ +#undef HAVE_ZLIB +#undef PACKAGE_COMPRESS +#define SAVE_GZ_EXTENSION ".o.gz" + +/* CALL_OTHER_TYPE_CHECK: enable type checking for call_other() + * (-> operator on objects) + */ +#undef CALL_OTHER_TYPE_CHECK + +/* CALL_OTHER_WARN, make it warning instead of errors */ +#undef CALL_OTHER_WARN + +/* WARN_TAB: Some versions of the editor built in indent function use + * tabs for indenting. This options turns on a warning message for + * files indented with tabs instead of spaces. + */ +#define WARN_TAB + +/* USE_ICONV: Use iconv to translate input and output from/to the users char + * encoding + */ +#undef USE_ICONV + +/* WOMBLES: don't allow spaces between start/end of array/mapping/functional token chars so ({1,2,3}) still works, but ( { 1 , 2 , 3 } ) doesn't and ({ 1 , 2 , 3 }) does.*/ +#undef WOMBLES + +/* ALLOW_INHERIT_AFTER_FUNCTION: allow inheriting after functions have been defined (this includes prototypes). This caused crashes in v22.2a but it may have been fixed since */ +#define ALLOW_INHERIT_AFTER_FUNCTION +#undef ALLOW_INHERIT_AFTER_GLOBAL_VARIABLES +#define PARSE_DEBUG +#define FLUFFOS +#undef PACKAGE_DSLIB +#undef ED_INDENT_CASE +#define ED_INDENT_SPACES 4 +#define PROG_REF_TYPE int +#undef ANSI_SUBSTITUTE +#undef RECEIVE_ED +#undef PACKAGE_ASYNC +#define HAS_CONSOLE +#endif +#undef IPV6 +#undef MALLOC64 +#undef PACKAGE_CRYPTO +#undef PACKAGE_SHA1 diff --git a/fluffos-2.23-ds03/local_options.foundation2 b/fluffos-2.23-ds03/local_options.foundation2 new file mode 100644 index 0000000..8d00098 --- /dev/null +++ b/fluffos-2.23-ds03/local_options.foundation2 @@ -0,0 +1,894 @@ +/* + * options.h: defines for the compile-time configuration of the MudOS driver + */ + +#ifndef _OPTIONS_H_ +#define _OPTIONS_H_ + +/* + * YOU PROBABLY DO NOT WANT TO MODIFY THIS FILE. + * + * Do 'cp options.h local_options' and edit that instead. local_options, + * if it exists, overrides this file. + * + * The advantage is that when you upgrade to a newer MudOS driver, you can + * simply copy your local_options file into the src directory. The build + * process will warn you if new options have been added that you should + * choose settings for. + */ + +/**************************************************************************** + * EVERY time you change ANYTHING in this file, RECOMPILE from scratch. * + * (type "make clean" then "make" on a UNIX system) Failure to do so may * + * cause the driver to behave oddly. * + ****************************************************************************/ + +/* NOTES: + * Many of the configurable options are now set via the configuration file + * that is specified as the first argument to the driver. + * See port.h for those #defines related to portability (compatibility) if + * you have problems compiling on your system. + * Removing an efun from func_spec.c usually removes most, if not all, + * of the code associated with it. + * Note that anything defined in this file is also visible to LPC files + * surrounded by __. So #define FOO in this file defines __FOO__ for + * all LPC files. This allows code like: + * + * #ifdef __SENSIBLE_MODIFIERS__ + * ... + */ + +/**************************************************************************** + * MALLOC * + * -------- * + * For performance reasons, LP drivers have a variety of memory allocation * + * packages. If you don't care, use the default one on your system: * + * #define SYSMALLOC, #undef the others. * + ****************************************************************************/ + +/* You must choose exactly one of these malloc packages: + * ~~~~ + * SYSMALLOC: + * * Built-in system malloc. + * * No statistics. + * * SYSMALLOC incurs no additional CPU or memory overhead. + * + * SMALLOC: + * * Satoria's smalloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than most system mallocs with modest ammount of memory overhead. + * * Can fall back onto system malloc if sbrk() not ok. + * + * BSDMALLOC: + * * BSD (Berkeley Software Distributions) malloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than SMALLOC but more memory overhead. + * * Requires sbrk(). + */ +#define SYSMALLOC +#undef SMALLOC +#undef BSDMALLOC +#undef MMALLOC + +/* You may optionally choose one (or none) of these malloc wrappers. These + * can be used in conjunction with any of the above malloc packages. + * + * WRAPPEDMALLOC: + * * Limited statistics. + * * Limited additional cpu overhead and no additional memory overhead. + * + * DEBUGMALLOC: + * * Statistics on precisely how much memory has been malloc'd (as well + * as the stats provided by WRAPPEDMALLOC). + * * Incurs a fair amount of overhead (both memory and CPU) + */ +#undef WRAPPEDMALLOC +#undef DEBUGMALLOC + +/* The following add certain bells and whistles to malloc: */ + +/* + * SBRK_OK: do not define this unless SMALLOC is chosen above. + * Defining this causes smalloc to use the low level memory allocation + * routines, and to act as a malloc replacement. Conversely, undef'ing + * SBRK_OK causes smalloc to act as a wrapper for the system malloc + * routines. + * + * Note: + * NeXTStep 3.x users should always #undef SBRK_OK. + */ +#undef SBRK_OK + +/* DO_MSTATS: do not define this unless BSDMALLOC or SMALLOC is chosen above. + * Defining this causes those replacement mallocs to keep statistics that + * the malloc_status() efun will print out (including total memory + * allocated/used). + */ +#undef DO_MSTATS + +/* DEBUGMALLOC_EXTENSIONS: defining this (in addition to DEBUGMALLOC) enables + * the set_malloc_mask(int) and debugmalloc(string,int) efuns. These two + * efuns basically allow you to cause certain malloc's and free's (with tags + * selected by a specified mask) to print debug information (addr, tag, + * description, size) to stdio (in the shell that invoked the driver) or to a + * file. Not defining this does reduce the overhead of DEBUGMALLOC from 16 + * bytes per malloc down to 8. This macro has no effect if DEBUGMALLOC isn't + * defined. + */ +#undef DEBUGMALLOC_EXTENSIONS + +/* CHECK_MEMORY: defining this (in addition to DEBUGMALLOC and + * DEBUGMALLOC_EXTENSIONS) causes the driver to check for memory + * corruption due to writing before the start or end of a block. This + * also adds the check_memory() efun. Takes a considerable ammount + * more memory. Mainly for debugging. + */ +#undef CHECK_MEMORY + +/**************************************************************************** + * COMPATIBILITY * + * --------------- * + * The MudOS driver has evolved quite a bit over the years. These defines * + * are mainly to preserve old behavior in case people didn't want to * + * rewrite the relevant portions of their code. * + * * + * In most cases, code which needs these defines should be rewritten when * + * possible. The 'Compat status' field is designed to give an idea how * + * likely it is that support for that option will be removed in the near * + * future. Certain options are fairly easy to work around, and double * + * the size of the associated code, as well as the maintenance workload, * + * and can make the code significantly more complex or harder to read, so * + * supporting them indefinitely is impractical. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* HAS_STATUS_TYPE: old MudOS drivers had a 'status' type which was + * identical to the 'int' type. Define this to bring it back. + * + * Compat status: very archaic, but easy to support. + */ +#undef HAS_STATUS_TYPE + +/* explode(): + * + * The old behavior (#undef both of the below) strips any number of + * delimiters at the start of the string, and one at the end. So + * explode("..x.y..z..", ".") gives ({ "x", "y", "", "z", "" }) + * + * SANE_EXPLODE_STRING strips off at most one leading delimiter, and + * still strips off one at the end, so the example above gives + * ({ "", "x", "y", "", "z", "" }). + * + * REVERSIBLE_EXPLODE_STRING overrides SANE_EXPLODE_STRING, and makes + * it so that implode(explode(x, y), y) is always x; i.e. no delimiters + * are ever stripped. So the example above gives + * ({ "", "", "x", "y", "", "z", "", "" }). + */ +#define SANE_EXPLODE_STRING +#undef REVERSIBLE_EXPLODE_STRING + +/* CAST_CALL_OTHERS: define this if you want to require casting of call_other's; + * this was the default behavior of the driver prior to this addition. + * + * Compat status: code that requires it doesn't break, and it promotes + * sloppy coding with no benefits. + */ +#undef CAST_CALL_OTHERS + +/* NONINTERACTIVE_STDERR_WRITE: if defined, all writes/tells/etc to + * noninteractive objects will be written to stderr prefixed with a ']' + * (old behavior). + * + * Compat status: Easy to support, and also on the "It's a bug! No, it's + * a feature!" religious war list. + */ +#define NONINTERACTIVE_STDERR_WRITE + +/* NO_LIGHT: define this to disable the set_light() and driver maintenance + * of light levels in objects. You can simulate it via LPC if you want... + * + * Compat status: Very dated, easy to simulate, and gross. + */ +#define NO_LIGHT + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + * process_input() then becomes the only way to deal with player input. + * + * Compat status: next to impossible to simulate, hard to replace, and + * very, very widely used. + */ +#undef NO_ADD_ACTION + +/* NO_SNOOP: disables the snoop() efun and all related functionality. + */ +#undef NO_SNOOP + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + process_input() then becomes the only way to deal with player input. */ + +/* NO_ENVIRONMENT: define this to remove the handling of object containment + * relationships by the driver + * + * Compat status: hard to simulate efficiently, and very widely used. + */ +#undef NO_ENVIRONMENT + +/* NO_WIZARDS: for historical reasons, MudOS used to keep track of who + * is and isn't a wizard. Defining this removes that completely. + * If this is defined, the wizardp() and related efuns don't exist. + * + * Also note that if it is not defined, then non-wizards are always put + * in restricted mode when ed() is used, regardless of the setting of + * the restrict parameter. + * + * Compat status: easy to simulate and dated. + */ +#define NO_WIZARDS + +/* OLD_TYPE_BEHAVIOR: reintroduces a bug in type-checking that effectively + * renders compile time type checking useless. For backwards compatibility. + * + * Compat status: dealing with all the resulting compile errors can be + * a huge pain even if they are correct, and the impact on the code is + * small. + */ +#undef OLD_TYPE_BEHAVIOR + +/* OLD_RANGE_BEHAVIOR: define this if you want negative indexes in string + * or buffer range values (not lvalue, i.e. x[-2..-1]; for e.g. not + * x[-2..-1] = foo, the latter is always illegal) to mean counting from the + * end + * + * Compat status: Not horribly difficult to replace reliance on this, but not + * trivial, and cannot be simulated. + */ +#undef OLD_RANGE_BEHAVIOR + +/* OLD_ED: ed() efun backwards compatible with the old version. The new + * version requires/allows a mudlib front end. + * + * Compat status: Easily simulated. + */ +#undef OLD_ED + +/* SENSIBLE_MODIFIERS: + * Turning this on changes a few things, which may break old code: + * + * (1) 'static' is not recognized; either 'nosave' or 'protected' must + * be used instead. + * (2) The old meaning of 'public' is no longer allowed. Explicit + * functions must be defined at each level to allow access to + * privately inherited functions. + * (3) 'public' now means the default visibility. Previously there was + * no keyword that meant this (before you ask, 'public' meant something + * else, and if you don't know that, you probably don't have any reason + * to care about the old meaning). + */ +#undef SENSIBLE_MODIFIERS + +/**************************************************************************** + * MISCELLANEOUS * + * --------------- * + * Various options that affect the way the driver behaves. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* + * Define this in order to use Fermat@Equilibria's MD5 based crypt() instead + * of the operating system's. It has the advantage of giving the same value + * on all architectures, and being stronger than the standard UNIX crypt(). + */ +#define CUSTOM_CRYPT + +/* + * Some minor tweaks that make it a bit easier to run code designed to run + * on LPmud 3.2/3.2.1. Currently has the following effects: + * + * . m_indices() and m_values() are synonyms for keys() and values(), + * respectively + * . map_delete() returns it's first argument + * . inherit_list() means deep_inherit_list(), not shallow_inherit_list() + * . heart_beat_info() is a synonym for heart_beats() + */ +#undef COMPAT_32 + +/* + * Keep statistics about allocated strings, etc. Which can be viewed with + * the mud_status() efun. If this is off, mud_status() and memory_info() + * ignore allocated strings, but string operations run faster. + */ +#define STRING_STATS + +/* + * Similarly for arrays ... + */ +#define ARRAY_STATS + +/* LOG_CATCHES: define this to cause errors that are catch()'d to be + * sent to the debug log anyway. + * + * On by default, because newer libs use catch() a lot, and it's confusing + * if the errors don't show up in the logs. + */ +#define LOG_CATCHES + +/* ARGUMENTS_IN_TRACEBACK: prints out function call arguments in error + * tracebacks, to aid in debugging. Note: it prints the values of + * the arguments at the time of the error, not when the function + * was called. It looks like this: + * + * Failed to load file: read_buffer + * program: command/update.c, object: command/update line 15 + * ' commandHook' in ' clone/user.c' (' clone/user#1')line 72 + * arguments were ("/read_buffer.c") + * ' main' in ' command/update.c' (' command/update')line 15 + * arguments were ("/read_buffer.c") + * + * The only down side is some people like their logs shorter + */ +#define ARGUMENTS_IN_TRACEBACK + +/* LOCALS_IN_TRACEBACK: similar to ARGUMENTS_IN_TRACEBACK, but for local + * variables. The output looks more or less like: + * + * locals: 1, "local_value" + * + * Same as above. Tends to produce even longer logs, but very useful for + * tracking errors. + */ +#define LOCALS_IN_TRACEBACK + +/* MUDLIB_ERROR_HANDLER: If you define this, the driver doesn't do any + * handling of runtime errors, other than to turn the heartbeats of + * objects off. Information about the error is passed in a mapping + * to the error_handler() function in the master object. Whatever is + * returned is put in the debug.log. + * + * A good mudlib error handler is one of the best tools for tracking down + * errors. Unfortunately, you need to have one. Check the testsuite or + * other libs for an example. + */ +#define MUDLIB_ERROR_HANDLER + +/* CONFIG_FILE_DIR specifies a directory in which the driver will search for + * config files by default. If you don't wish to use this define, you may + * always specify a full path to the config file when starting the driver. + */ +#define CONFIG_FILE_DIR "./" + +/* DEFAULT_PRAGMAS: This should be a sum of pragmas you want to always + * be on, i.e. + * + * #define DEFAULT_PRAGMAS PRAGMA_STRICT_TYPES + PRAGMA_SAVE_TYPES + * + * will make every LPC file behave as if it had the lines: + * #pragma strict_types + * #pragma save_types + * + * for no default pragmas: + * #define DEFAULT_PRAGMAS 0 + * + * If you don't know what these are, 0 is a good choice. + * + * Supported pragmas: + * PRAGMA_STRICT_TYPES: enforces strict type checking + * PRAGMA_WARNINGS: issues warnings about various dangerous things in + * your code + * PRAGMA_SAVE_TYPES: save the types of function arguments for checking + * calls to functions in this object by objects that + * inherit it. + * PRAGMA_SAVE_BINARY: save a compiled binary version of this file for + * faster loading next time it is needed. + * PRAGMA_OPTIMIZE: make a second pass over the generated code to + * optimize it further. Currently does jump threading. + * PRAGMA_ERROR_CONTEXT:include some text telling where on the line a + * compilation error occured. + */ +#define DEFAULT_PRAGMAS PRAGMA_STRICT_TYPES + +/* supress warnings about unused arguments; only warn about unused local + * variables. Makes older code (where argument names were required) compile + * more quietly. + */ +#define SUPPRESS_ARGUMENT_WARNINGS + +/* NO_RESETS: completely disable the periodic calling of reset() */ +#undef NO_RESETS + +/* LAZY_RESETS: if this is defined, an object will only have reset() + * called in it when it is touched via call_other() or move_object() + * (assuming enough time has passed since the last reset). If LAZY_RESETS + * is #undef'd, then reset() will be called as always (which guaranteed that + * reset would always be called at least once). The advantage of lazy + * resets is that reset doesn't get called in an object that is touched + * once and never again (which can save memory since some objects won't get + * reloaded that otherwise would). + */ +#undef LAZY_RESETS + +/* SAVE_EXTENSION: defines the file extension used by save_object(). + * and restore_object(). Some sysadmins run scripts that periodically + * scan for and remove files ending in .o (but many mudlibs are already + * set up to use .o thus we leave .o as the default). + */ +#define SAVE_EXTENSION ".o" + +/* NO_ANSI: define if you wish to disallow users from typing in commands that + * contain ANSI escape sequences. Defining NO_ANSI causes all escapes + * (ASCII 27) to be replaced with a space ' ' before the string is passed + * to the action routines added with add_action. + * + * STRIP_BEFORE_PROCESS_INPUT allows the location where the stripping is + * done to be controlled. If it is defined, then process_input() doesn't + * see ANSI characters either; if it is undefined ESC chars can be processed + * by process_input(), but are stripped before add_actions are called. + * Note that if NO_ADD_ACTION is defined, then #define NO_ANSI without + * #define STRIP_BEFORE_PROCESS_INPUT is the same as #undef NO_ANSI. + * + * If you anticipate problems with users intentionally typing in ANSI codes + * to make your terminal flash, etc define this. + */ +#define NO_ANSI +#define STRIP_BEFORE_PROCESS_INPUT + +/* OPCPROF: define this if you wish to enable OPC profiling. Allows a dump + * of the # of times each efun is invoked (via the opcprof() efun). + */ +#undef OPCPROF + +/* OPCPROF_2D: define this if you wish to enable 2-D OPC profiling. Allows a + * dump of the # of times each *pair* of eoperators is invoked. + * + * You can't use this and OPCPROF at the same time. + */ +#undef OPCPROF_2D + +/* TRAP_CRASHES: define this if you want MudOS to call crash() in master.c + * and then shutdown when signals are received that would normally crash the + * driver. + */ +#define TRAP_CRASHES + +/* THIS_PLAYER_IN_CALL_OUT: define this if you wish this_player() to be + * usable from within call_out() callbacks. + */ +#define THIS_PLAYER_IN_CALL_OUT + +/* CALLOUT_HANDLES: If this is defined, call_out() returns an integer, which + * can be passed to remove_call_out() or find_call_out(). Removing call_outs + * by name is still allowed, but is significantly less efficient, and also + * doesn't work for function pointers. This option adds 4 bytes overhead + * per callout to keep track of the handle. + */ +#define CALLOUT_HANDLES + +/* FLUSH_OUTPUT_IMMEDIATELY: Causes output to be written to sockets + * immediately after being generated. Useful for debugging. + */ +#undef FLUSH_OUTPUT_IMMEDIATELY + +/* PRIVS: define this if you want object privileges. Your mudlib must + * explicitly make use of this functionality to be useful. Defining this + * this will increase the size of the object structure by 4 bytes (8 bytes + * on the DEC Alpha) and will add a new master apply during object creation + * to "privs_file". In general, privileges can be used to increase the + * granularity of security beyond the current root uid mechanism. + * + * [NOTE: for those who'd rather do such things at the mudlib level, look at + * the inherits() efun and the 'valid_object' apply to master.] + */ +#define PRIVS + +/* INTERACTIVE_CATCH_TELL: define this if you want catch_tell called on + * interactives as well as NPCs. If this is defined, user.c will need a + * catch_tell(msg) method that calls receive(msg); +*/ +#undef INTERACTIVE_CATCH_TELL + +/* RESTRICTED_ED: define this if you want restricted ed mode enabled. + */ +#define RESTRICTED_ED + +/* NO_SHADOWS: define this if you want to disable shadows in your driver. + */ +#undef NO_SHADOWS + +/* SNOOP_SHADOWED: define this if you want snoop to report what is + * sent to the player even in the event that the player's catch_tell() is + * shadowed and the player may not be seeing what is being sent. Messages + * of this sort will be prefixed with $$. + */ +#undef SNOOP_SHADOWED + +/* RECEIVE_SNOOP: define this if you want snoop text to be sent to + * the receive_snoop() function in the snooper object (instead of being + * sent directly via add_message()). This is useful if you want to + * build a smart client that does something different with snoop messages. + */ +#define RECEIVE_SNOOP + +/* PROFILE_FUNCTIONS: define this to be able to measure the CPU time used by + * all of the user-defined functions in each LPC object. Note: defining + * this adds three long ints (12 bytes on 32-bit machines) to the function + * header structs. Also note that the resolution of the getrusage() timer + * may not be high enough on some machines to give non-zero execution + * times to very small (fast) functions. In particular if the clock + * resolution is 1/60 of a second, then any time less than approxmately 15k + * microseconds will resolve to zero (0). + */ +#undef PROFILE_FUNCTIONS + +/* NO_BUFFER_TYPE: if this is #define'd then LPC code using the 'buffer' + * type won't be allowed to compile (since the 'buffer' type won't be + * recognized by the lexer). + */ +#undef NO_BUFFER_TYPE + +/* BINARIES: define this to enable the 'save_binary' pragma. + * This pragma, when set in a program, will cause it to save a + * binary image when loaded, so that subsequent loadings will + * be much faster. The binaries are saved in the directory + * specified in the configuration file. The binaries will not + * load if the LPC source or any of the inherited or included + * files are out of date, in which case the file is compiled + * normally (and may save a new binary). + * + * In order to save the binary, valid_save_binary() is called + * in master.c, and is passed the name of the source file. If + * this returns a non-zero value, the binary is allowed to be + * saved. Allowing any file by any wizard to be saved as a + * binary is convenient, but may take up a lot of disk space. + */ +#define BINARIES + +/* ARRAY_RESERVED_WORD: If this is defined then the word 'array' can + * be used to define arrays, as in: + * + * int array x = ({ .... }); + * + * A side effect is that 'array' cannot be a variable or function name. + */ +#define ARRAY_RESERVED_WORD + +/* REF_RESERVED_WORD: If this is defined then the word 'ref' can be + * used to pass arguments to functions by value. Example: + * + * void inc(int ref x) { + * x++; + * } + * + * ... y = 1; inc(ref y); ... + * + * A side effect is that 'ref' cannot be a variable or function name. + * + * Note: ref must be used in *both* places; this is intentional. It protects + * against passing references to routines which don't intend to return values + * through their arguments, and against forgetting to pass a reference + * to a function which wants one (or accidentally having a variable modified!) + */ +#undef REF_RESERVED_WORD + +/**************************************************************************** + * PACKAGES * + * -------- * + * Defining some/all of the following add certain efuns, and sometimes * + * add/remove code from the driver. * + * * + * if PACKAGE_XYZZY is defined here, then the code in packages/xyzzy.c * + * and the efuns in packages/xyzzy_spec.c will be added to the driver. * + ****************************************************************************/ + +/* various miscellaneous efuns */ +#define PACKAGE_CONTRIB + +/* efuns that are only of use to those that know something about driver + internals */ +#define PACKAGE_DEVELOP + +/* PACKAGE_MATH: determines whether or not the math efuns (for floats) are + included. + */ +#define PACKAGE_MATH + +/* PACKAGE_MATRIX: determines whether or not the 3d graphics efuns (for floats) + * are included - see packages/matrix.spec for a list. + */ +#define PACKAGE_MATRIX + +/* PACKAGE_MUDLIB_STATS: define this to enable domain and author stats + * maintenance by the driver. These mudlib stats are more domain + * based than user based, and replaces the traditional wiz_list stats. + */ +#define PACKAGE_MUDLIB_STATS + +/* PACKAGE_SOCKETS: define this to enable the socket efunctions. This + * causes HAS_SOCKETS to be defined for all LPC objects. + */ +#define PACKAGE_SOCKETS + +/* PACKAGE_PARSER: Natural language parsing efuns for interactive fiction + * type applications + */ +#define PACKAGE_PARSER + +/* PACKAGE_EXTERNAL: Allows the driver to exec() commands specified in the + * config file. + */ +#undef PACKAGE_EXTERNAL + +/* NUM_EXTERNAL_CMDS: the number of external commands supported */ +#define NUM_EXTERNAL_CMDS 100 + +/* PACKAGE_DB: efuns for external database access using msql */ +#undef PACKAGE_DB + +/* If PACKAGE_DB is defined above, you must pick ONE of the following supported + * databases + */ +#ifdef PACKAGE_DB +#undef USE_MSQL +#undef MSQL +#define USE_MYSQL 2 +#define MY_SQL +#endif + +/**************************************************************************** + * UID PACKAGE * + * ----------- * + * UIDS are the basis for some mudlib security systems. Basically, they're * + * preserved for backwards compatibility, as several ways of breaking * + * almost any system which relies on them are known. (No, it's not a flaw * + * of uids; only that b/c of the ease with which LPC objects can call * + * each other, it's far too easy to leave holes) * + * * + * If you don't care about security, the first option is probably what you * + * want. * + ****************************************************************************/ + +/* + * PACKAGE_UIDS: define this if you want a driver that does use uids. + * + */ +#undef PACKAGE_UIDS + +/*PACKAGE DWLIB: some discworld mudlib simuls coded in C (well just one right + now) */ + +#undef PACKAGE_DWLIB + +/* AUTO_SETEUID: when an object is created it's euid is automatically set to + * the equivalent of seteuid(getuid(this_object())). undef AUTO_SETEUID + * if you would rather have the euid of the created object be set to 0. + */ +#undef AUTO_SETEUID + +/* AUTO_TRUST_BACKBONE: define this if you want objects with the backbone + * uid to automatically be trusted and to have their euid set to the uid of + * the object that forced the object's creation. + */ +#define AUTO_TRUST_BACKBONE + +/************************************************************************* + * FOR EXPERIENCED USERS * + * ----------------------- * + * Most of these options will probably be of no interest to many users. * + *************************************************************************/ + +/* USE_32BIT_ADDRESSES: Use 32 bits for addresses of function, instead of + * the usual 16 bits. This increases the maximum program size from 64k + * of LPC bytecode (NOT source) to 4 GB. Branches are still 16 bits, + * imposing a 64k limit on catch(), if(), switch(), loops, and most other + * control structures. It would take an extremely large function to hit + * those limits, though. + * + * Overhead: 2 bytes/function with LPC->C off. Having LPC->C on forces + * this option, since it needs 4 bytes to store the function pointers + * anyway, and this setting is ignored. + */ +#undef USE_32BIT_ADDRESSES + +/* HEARTBEAT_INTERVAL: define heartbeat interval in microseconds (us). + * 1,000,000 us = 1 second. The value of this macro specifies + * the frequency with which the heart_beat method will be called in + * those LPC objects which have called set_heart_beat(1). + * + * [NOTE: if ualarm() isn't available, alarm() is used instead. Since + * alarm() requires its argument in units of a second, we map 1 - 1,000,000 us + * to an actual interval of one (1) second and 1,000,001 - 2,000,000 maps to + * an actual interval of two (2) seconds, etc.] + */ +#define HEARTBEAT_INTERVAL 1 + +/* + * CALLOUT_CYCLE_SIZE: This is the number of slots in the call_out list. + * It should be approximately the average number of active call_outs, or + * a few times smaller. It should also be a power of 2, and also be relatively + * prime to any common call_out lengths. If all this is too confusing, 32 + * isn't a bad number :-) + */ +#define CALLOUT_CYCLE_SIZE 32 + +/* LARGEST_PRINTABLE_STRING: defines the size of the vsprintf() buffer in + * comm.c's add_message(). Instead of blindly making this value larger, + * your mudlib should be coded to not send huge strings to users. + */ +#define LARGEST_PRINTABLE_STRING 8192 + +/* MESSAGE_BUFFER_SIZE: determines the size of the buffer for output that + * is sent to users. + */ +#define MESSAGE_BUFFER_SIZE 4096 + +/* APPLY_CACHE_BITS: defines the number of bits to use in the call_other cache + * (in interpret.c). + * + * Memory overhead is (1 << APPLY_CACHE_BITS)*16. + * [assuming 32 bit pointers and 16 bit shorts] + * + * ACB: entries: overhead: + * 6 64 1k + * 8 256 4k + * 10 1024 16k + * 12 4096 64k + * 14 16384 256k + * 16 65536 1M + */ +#define APPLY_CACHE_BITS 11 + +/* CACHE_STATS: define this if you want call_other (apply_low) cache + * statistics. Causes HAS_CACHE_STATS to be defined in all LPC objects. + */ +#define CACHE_STATS + +/* TRACE: define this to enable the trace() and traceprefix() efuns. + * (keeping this undefined will cause the driver to run faster). + */ +#undef TRACE + +/* RUNTIME_LOADING: On systems which support it, it allows LPC->C compilation + * 'on the fly' without having to recompile the driver. + * + * Note: This currently only works on machines that have the dlopen() system + * call. SunOS and IRIX do, as do a number of others. AIX and Ultrix don't. + * Linux does if you are using ELF. + */ +#undef RUNTIME_LOADING + +/* TRACE_CODE: define this to enable code tracing (the driver will print + * out the previous lines of code to an error) eval_instruction() runs about + * twice as fast when this is not defined (for the most common eoperators). + */ +#undef TRACE_CODE + +/* HEART_BEAT_CHUNK: The number of heart_beat chunks allocated at a time. + * A large number wastes memory as some will be sitting around unused, while + * a small one wastes more CPU reallocating when it needs to grow. Default + * to a medium value. + */ +#define HEART_BEAT_CHUNK 32 + +/* SERVER_IP: For machines with multiple IP addresses, this specifies which + * one to use. This is useful for IP accounting and is necessary to be + * able to do ident lookups on such machines. + * + * example: #define SERVER_IP "194.229.18.27" + */ +#undef SERVER_IP + +/* Some maximum string sizes + */ +#define SMALL_STRING_SIZE 100 +#define LARGE_STRING_SIZE 1000 +#define COMMAND_BUF_SIZE 2000 + +/* Number of levels of nested datastructures allowed -- this limit prevents + * crashes from occuring when saving objects containing variables containing + * recursive datastructures (with circular references). + */ +#define MAX_SAVE_SVALUE_DEPTH 100 + +/* Miscellaneous config options that should probably be in the runtime + * config file. + */ +/* MAX_LOCAL: maximum number of local variables allowed per LPC function */ +#define CFG_MAX_LOCAL_VARIABLES 50 +/* Increasing max global vars beyond 256 is not recommended */ +#define CFG_MAX_GLOBAL_VARIABLES 256 + +#define CFG_EVALUATOR_STACK_SIZE 3000 +#define CFG_COMPILER_STACK_SIZE 600000 +#define CFG_MAX_CALL_DEPTH 150 +/* This must be one of 4, 16, 64, 256, 1024, 4096 */ +#define CFG_LIVING_HASH_SIZE 256 + +/* NEXT_MALLOC_DEBUG: define this if using a NeXT and you want to enable + * the malloc_check() and/or malloc_debug() efuns. Run the 'man malloc_debug' + * command on the NeXT to find out what the arguments to malloc_debug(int) + * mean. The malloc_check() efun calls the NeXT NXMallocCheck() system + * call which does a consistency check on malloc's data structures (this + * consistency check is done at each malloc() and free() for certain + * malloc_debug() levels). A non-zero return value indicates there was + * a consistency problem. For those NeXT users wanting a bit more + * performance out of malloc, try defining NEXT_MALLOC_DEBUG and calling the + * malloc_debug(-1) efun (with an arg of -1). This will turn all + * malloc debugging off and call malloc_singlethreaded() which the NeXT + * malloc man page claims can make NeXT system malloc 10% to 15% faster. + * + * [NOTE: This #define has no affect on the driver if not using the + * NeXTSTEP OS.] + * + * Warning: if you use a NeXT and define NEXT_MALLOC_DEBUG, be sure to + * protect the use of the malloc_check() and malloc_debug() efuns + * since setting certain debug levels can cause malloc() and free() + * to become _very_ slow (protect efuns by using simul_efuns and + * valid_override). + * + * [NOTE: malloc_debug(6) is a good compromise between efficiency and + * completeness of malloc debugging (malloc/free will be about half as fast).] + */ +#define NEXT_MALLOC_DEBUG + + +/* GET_CHAR_IS_BUFFERED: Normally get_char() is unbuffered. That is, once + * a character is received for get_char(), anything else is in the input + * stream is immediately thrown away. This can be very undesirable, especially + * if you're calling get_char() again from the handler from the previous call. + * Define this if you want get_char() to be buffered. In this case, the buffer + * will only get flushed if get_char() is not called from the first get_char()'s + * LPC callback handler. + */ +#undef GET_CHAR_IS_BUFFERED + +/* PACKAGE_COMPRESS: Enable MCCP support and compressed save files + SAVE_GZ_EXTENSION: save extension for compressed files + */ +#undef HAVE_ZLIB +#undef PACKAGE_COMPRESS +#define SAVE_GZ_EXTENSION ".o.gz" + +/* CALL_OTHER_TYPE_CHECK: enable type checking for call_other() + * (-> operator on objects) + */ +#undef CALL_OTHER_TYPE_CHECK + +/* CALL_OTHER_WARN, make it warning instead of errors */ +#undef CALL_OTHER_WARN + +/* WARN_TAB: Some versions of the editor built in indent function use + * tabs for indenting. This options turns on a warning message for + * files indented with tabs instead of spaces. + */ +#define WARN_TAB + +/* USE_ICONV: Use iconv to translate input and output from/to the users char + * encoding + */ +#undef USE_ICONV + +/* WOMBLES: don't allow spaces between start/end of array/mapping/functional token chars so ({1,2,3}) still works, but ( { 1 , 2 , 3 } ) doesn't and ({ 1 , 2 , 3 }) does.*/ +#undef WOMBLES + +/* ALLOW_INHERIT_AFTER_FUNCTION: allow inheriting after functions have been defined (this includes prototypes). This caused crashes in v22.2a but it may have been fixed since */ +#define ALLOW_INHERIT_AFTER_FUNCTION +#undef ALLOW_INHERIT_AFTER_GLOBAL_VARIABLES +#define PARSE_DEBUG +#define FLUFFOS +#undef PACKAGE_DSLIB +#undef ED_INDENT_CASE +#define ED_INDENT_SPACES 4 +#define PROG_REF_TYPE int +#undef ANSI_SUBSTITUTE +#undef RECEIVE_ED +#undef PACKAGE_ASYNC +#define HAS_CONSOLE +#endif +#undef IPV6 +#undef MALLOC64 +#undef PACKAGE_CRYPTO +#undef PACKAGE_SHA1 diff --git a/fluffos-2.23-ds03/local_options.fr b/fluffos-2.23-ds03/local_options.fr new file mode 100644 index 0000000..4428d98 --- /dev/null +++ b/fluffos-2.23-ds03/local_options.fr @@ -0,0 +1,894 @@ +/* + * options.h: defines for the compile-time configuration of the MudOS driver + */ + +#ifndef _OPTIONS_H_ +#define _OPTIONS_H_ + +/* + * YOU PROBABLY DO NOT WANT TO MODIFY THIS FILE. + * + * Do 'cp options.h local_options' and edit that instead. local_options, + * if it exists, overrides this file. + * + * The advantage is that when you upgrade to a newer MudOS driver, you can + * simply copy your local_options file into the src directory. The build + * process will warn you if new options have been added that you should + * choose settings for. + */ + +/**************************************************************************** + * EVERY time you change ANYTHING in this file, RECOMPILE from scratch. * + * (type "make clean" then "make" on a UNIX system) Failure to do so may * + * cause the driver to behave oddly. * + ****************************************************************************/ + +/* NOTES: + * Many of the configurable options are now set via the configuration file + * that is specified as the first argument to the driver. + * See port.h for those #defines related to portability (compatibility) if + * you have problems compiling on your system. + * Removing an efun from func_spec.c usually removes most, if not all, + * of the code associated with it. + * Note that anything defined in this file is also visible to LPC files + * surrounded by __. So #define FOO in this file defines __FOO__ for + * all LPC files. This allows code like: + * + * #ifdef __SENSIBLE_MODIFIERS__ + * ... + */ + +/**************************************************************************** + * MALLOC * + * -------- * + * For performance reasons, LP drivers have a variety of memory allocation * + * packages. If you don't care, use the default one on your system: * + * #define SYSMALLOC, #undef the others. * + ****************************************************************************/ + +/* You must choose exactly one of these malloc packages: + * ~~~~ + * SYSMALLOC: + * * Built-in system malloc. + * * No statistics. + * * SYSMALLOC incurs no additional CPU or memory overhead. + * + * SMALLOC: + * * Satoria's smalloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than most system mallocs with modest ammount of memory overhead. + * * Can fall back onto system malloc if sbrk() not ok. + * + * BSDMALLOC: + * * BSD (Berkeley Software Distributions) malloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than SMALLOC but more memory overhead. + * * Requires sbrk(). + */ +#define SYSMALLOC +#undef SMALLOC +#undef BSDMALLOC +#undef MMALLOC + +/* You may optionally choose one (or none) of these malloc wrappers. These + * can be used in conjunction with any of the above malloc packages. + * + * WRAPPEDMALLOC: + * * Limited statistics. + * * Limited additional cpu overhead and no additional memory overhead. + * + * DEBUGMALLOC: + * * Statistics on precisely how much memory has been malloc'd (as well + * as the stats provided by WRAPPEDMALLOC). + * * Incurs a fair amount of overhead (both memory and CPU) + */ +#undef WRAPPEDMALLOC +#undef DEBUGMALLOC + +/* The following add certain bells and whistles to malloc: */ + +/* + * SBRK_OK: do not define this unless SMALLOC is chosen above. + * Defining this causes smalloc to use the low level memory allocation + * routines, and to act as a malloc replacement. Conversely, undef'ing + * SBRK_OK causes smalloc to act as a wrapper for the system malloc + * routines. + * + * Note: + * NeXTStep 3.x users should always #undef SBRK_OK. + */ +#undef SBRK_OK + +/* DO_MSTATS: do not define this unless BSDMALLOC or SMALLOC is chosen above. + * Defining this causes those replacement mallocs to keep statistics that + * the malloc_status() efun will print out (including total memory + * allocated/used). + */ +#undef DO_MSTATS + +/* DEBUGMALLOC_EXTENSIONS: defining this (in addition to DEBUGMALLOC) enables + * the set_malloc_mask(int) and debugmalloc(string,int) efuns. These two + * efuns basically allow you to cause certain malloc's and free's (with tags + * selected by a specified mask) to print debug information (addr, tag, + * description, size) to stdio (in the shell that invoked the driver) or to a + * file. Not defining this does reduce the overhead of DEBUGMALLOC from 16 + * bytes per malloc down to 8. This macro has no effect if DEBUGMALLOC isn't + * defined. + */ +#undef DEBUGMALLOC_EXTENSIONS + +/* CHECK_MEMORY: defining this (in addition to DEBUGMALLOC and + * DEBUGMALLOC_EXTENSIONS) causes the driver to check for memory + * corruption due to writing before the start or end of a block. This + * also adds the check_memory() efun. Takes a considerable ammount + * more memory. Mainly for debugging. + */ +#undef CHECK_MEMORY + +/**************************************************************************** + * COMPATIBILITY * + * --------------- * + * The MudOS driver has evolved quite a bit over the years. These defines * + * are mainly to preserve old behavior in case people didn't want to * + * rewrite the relevant portions of their code. * + * * + * In most cases, code which needs these defines should be rewritten when * + * possible. The 'Compat status' field is designed to give an idea how * + * likely it is that support for that option will be removed in the near * + * future. Certain options are fairly easy to work around, and double * + * the size of the associated code, as well as the maintenance workload, * + * and can make the code significantly more complex or harder to read, so * + * supporting them indefinitely is impractical. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* HAS_STATUS_TYPE: old MudOS drivers had a 'status' type which was + * identical to the 'int' type. Define this to bring it back. + * + * Compat status: very archaic, but easy to support. + */ +#define HAS_STATUS_TYPE + +/* explode(): + * + * The old behavior (#undef both of the below) strips any number of + * delimiters at the start of the string, and one at the end. So + * explode("..x.y..z..", ".") gives ({ "x", "y", "", "z", "" }) + * + * SANE_EXPLODE_STRING strips off at most one leading delimiter, and + * still strips off one at the end, so the example above gives + * ({ "", "x", "y", "", "z", "" }). + * + * REVERSIBLE_EXPLODE_STRING overrides SANE_EXPLODE_STRING, and makes + * it so that implode(explode(x, y), y) is always x; i.e. no delimiters + * are ever stripped. So the example above gives + * ({ "", "", "x", "y", "", "z", "", "" }). + */ +#undef SANE_EXPLODE_STRING +#undef REVERSIBLE_EXPLODE_STRING + +/* CAST_CALL_OTHERS: define this if you want to require casting of call_other's; + * this was the default behavior of the driver prior to this addition. + * + * Compat status: code that requires it doesn't break, and it promotes + * sloppy coding with no benefits. + */ +#undef CAST_CALL_OTHERS + +/* NONINTERACTIVE_STDERR_WRITE: if defined, all writes/tells/etc to + * noninteractive objects will be written to stderr prefixed with a ']' + * (old behavior). + * + * Compat status: Easy to support, and also on the "It's a bug! No, it's + * a feature!" religious war list. + */ +#define NONINTERACTIVE_STDERR_WRITE + +/* NO_LIGHT: define this to disable the set_light() and driver maintenance + * of light levels in objects. You can simulate it via LPC if you want... + * + * Compat status: Very dated, easy to simulate, and gross. + */ +#undef NO_LIGHT + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + * process_input() then becomes the only way to deal with player input. + * + * Compat status: next to impossible to simulate, hard to replace, and + * very, very widely used. + */ +#undef NO_ADD_ACTION + +/* NO_SNOOP: disables the snoop() efun and all related functionality. + */ +#undef NO_SNOOP + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + process_input() then becomes the only way to deal with player input. */ + +/* NO_ENVIRONMENT: define this to remove the handling of object containment + * relationships by the driver + * + * Compat status: hard to simulate efficiently, and very widely used. + */ +#undef NO_ENVIRONMENT + +/* NO_WIZARDS: for historical reasons, MudOS used to keep track of who + * is and isn't a wizard. Defining this removes that completely. + * If this is defined, the wizardp() and related efuns don't exist. + * + * Also note that if it is not defined, then non-wizards are always put + * in restricted mode when ed() is used, regardless of the setting of + * the restrict parameter. + * + * Compat status: easy to simulate and dated. + */ +#undef NO_WIZARDS + +/* OLD_TYPE_BEHAVIOR: reintroduces a bug in type-checking that effectively + * renders compile time type checking useless. For backwards compatibility. + * + * Compat status: dealing with all the resulting compile errors can be + * a huge pain even if they are correct, and the impact on the code is + * small. + */ +#undef OLD_TYPE_BEHAVIOR + +/* OLD_RANGE_BEHAVIOR: define this if you want negative indexes in string + * or buffer range values (not lvalue, i.e. x[-2..-1]; for e.g. not + * x[-2..-1] = foo, the latter is always illegal) to mean counting from the + * end + * + * Compat status: Not horribly difficult to replace reliance on this, but not + * trivial, and cannot be simulated. + */ +#undef OLD_RANGE_BEHAVIOR + +/* OLD_ED: ed() efun backwards compatible with the old version. The new + * version requires/allows a mudlib front end. + * + * Compat status: Easily simulated. + */ +#define OLD_ED + +/* SENSIBLE_MODIFIERS: + * Turning this on changes a few things, which may break old code: + * + * (1) 'static' is not recognized; either 'nosave' or 'protected' must + * be used instead. + * (2) The old meaning of 'public' is no longer allowed. Explicit + * functions must be defined at each level to allow access to + * privately inherited functions. + * (3) 'public' now means the default visibility. Previously there was + * no keyword that meant this (before you ask, 'public' meant something + * else, and if you don't know that, you probably don't have any reason + * to care about the old meaning). + */ +#undef SENSIBLE_MODIFIERS + +/**************************************************************************** + * MISCELLANEOUS * + * --------------- * + * Various options that affect the way the driver behaves. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* + * Define this in order to use Fermat@Equilibria's MD5 based crypt() instead + * of the operating system's. It has the advantage of giving the same value + * on all architectures, and being stronger than the standard UNIX crypt(). + */ +#define CUSTOM_CRYPT + +/* + * Some minor tweaks that make it a bit easier to run code designed to run + * on LPmud 3.2/3.2.1. Currently has the following effects: + * + * . m_indices() and m_values() are synonyms for keys() and values(), + * respectively + * . map_delete() returns it's first argument + * . inherit_list() means deep_inherit_list(), not shallow_inherit_list() + * . heart_beat_info() is a synonym for heart_beats() + */ +#undef COMPAT_32 + +/* + * Keep statistics about allocated strings, etc. Which can be viewed with + * the mud_status() efun. If this is off, mud_status() and memory_info() + * ignore allocated strings, but string operations run faster. + */ +#define STRING_STATS + +/* + * Similarly for arrays ... + */ +#define ARRAY_STATS + +/* LOG_CATCHES: define this to cause errors that are catch()'d to be + * sent to the debug log anyway. + * + * On by default, because newer libs use catch() a lot, and it's confusing + * if the errors don't show up in the logs. + */ +#undef LOG_CATCHES + +/* ARGUMENTS_IN_TRACEBACK: prints out function call arguments in error + * tracebacks, to aid in debugging. Note: it prints the values of + * the arguments at the time of the error, not when the function + * was called. It looks like this: + * + * Failed to load file: read_buffer + * program: command/update.c, object: command/update line 15 + * ' commandHook' in ' clone/user.c' (' clone/user#1')line 72 + * arguments were ("/read_buffer.c") + * ' main' in ' command/update.c' (' command/update')line 15 + * arguments were ("/read_buffer.c") + * + * The only down side is some people like their logs shorter + */ +#define ARGUMENTS_IN_TRACEBACK + +/* LOCALS_IN_TRACEBACK: similar to ARGUMENTS_IN_TRACEBACK, but for local + * variables. The output looks more or less like: + * + * locals: 1, "local_value" + * + * Same as above. Tends to produce even longer logs, but very useful for + * tracking errors. + */ +#define LOCALS_IN_TRACEBACK + +/* MUDLIB_ERROR_HANDLER: If you define this, the driver doesn't do any + * handling of runtime errors, other than to turn the heartbeats of + * objects off. Information about the error is passed in a mapping + * to the error_handler() function in the master object. Whatever is + * returned is put in the debug.log. + * + * A good mudlib error handler is one of the best tools for tracking down + * errors. Unfortunately, you need to have one. Check the testsuite or + * other libs for an example. + */ +#undef MUDLIB_ERROR_HANDLER + +/* CONFIG_FILE_DIR specifies a directory in which the driver will search for + * config files by default. If you don't wish to use this define, you may + * always specify a full path to the config file when starting the driver. + */ +#define CONFIG_FILE_DIR "/home/atuin/bin" + +/* DEFAULT_PRAGMAS: This should be a sum of pragmas you want to always + * be on, i.e. + * + * #define DEFAULT_PRAGMAS PRAGMA_STRICT_TYPES + PRAGMA_SAVE_TYPES + * + * will make every LPC file behave as if it had the lines: + * #pragma strict_types + * #pragma save_types + * + * for no default pragmas: + * #define DEFAULT_PRAGMAS 0 + * + * If you don't know what these are, 0 is a good choice. + * + * Supported pragmas: + * PRAGMA_STRICT_TYPES: enforces strict type checking + * PRAGMA_WARNINGS: issues warnings about various dangerous things in + * your code + * PRAGMA_SAVE_TYPES: save the types of function arguments for checking + * calls to functions in this object by objects that + * inherit it. + * PRAGMA_SAVE_BINARY: save a compiled binary version of this file for + * faster loading next time it is needed. + * PRAGMA_OPTIMIZE: make a second pass over the generated code to + * optimize it further. Currently does jump threading. + * PRAGMA_ERROR_CONTEXT:include some text telling where on the line a + * compilation error occured. + */ +#define DEFAULT_PRAGMAS 0 + +/* supress warnings about unused arguments; only warn about unused local + * variables. Makes older code (where argument names were required) compile + * more quietly. + */ +#define SUPPRESS_ARGUMENT_WARNINGS + +/* NO_RESETS: completely disable the periodic calling of reset() */ +#undef NO_RESETS + +/* LAZY_RESETS: if this is defined, an object will only have reset() + * called in it when it is touched via call_other() or move_object() + * (assuming enough time has passed since the last reset). If LAZY_RESETS + * is #undef'd, then reset() will be called as always (which guaranteed that + * reset would always be called at least once). The advantage of lazy + * resets is that reset doesn't get called in an object that is touched + * once and never again (which can save memory since some objects won't get + * reloaded that otherwise would). + */ +#undef LAZY_RESETS + +/* SAVE_EXTENSION: defines the file extension used by save_object(). + * and restore_object(). Some sysadmins run scripts that periodically + * scan for and remove files ending in .o (but many mudlibs are already + * set up to use .o thus we leave .o as the default). + */ +#define SAVE_EXTENSION ".o" + +/* NO_ANSI: define if you wish to disallow users from typing in commands that + * contain ANSI escape sequences. Defining NO_ANSI causes all escapes + * (ASCII 27) to be replaced with a space ' ' before the string is passed + * to the action routines added with add_action. + * + * STRIP_BEFORE_PROCESS_INPUT allows the location where the stripping is + * done to be controlled. If it is defined, then process_input() doesn't + * see ANSI characters either; if it is undefined ESC chars can be processed + * by process_input(), but are stripped before add_actions are called. + * Note that if NO_ADD_ACTION is defined, then #define NO_ANSI without + * #define STRIP_BEFORE_PROCESS_INPUT is the same as #undef NO_ANSI. + * + * If you anticipate problems with users intentionally typing in ANSI codes + * to make your terminal flash, etc define this. + */ +#define NO_ANSI +#define STRIP_BEFORE_PROCESS_INPUT + +/* OPCPROF: define this if you wish to enable OPC profiling. Allows a dump + * of the # of times each efun is invoked (via the opcprof() efun). + */ +#define OPCPROF + +/* OPCPROF_2D: define this if you wish to enable 2-D OPC profiling. Allows a + * dump of the # of times each *pair* of eoperators is invoked. + * + * You can't use this and OPCPROF at the same time. + */ +#undef OPCPROF_2D + +/* TRAP_CRASHES: define this if you want MudOS to call crash() in master.c + * and then shutdown when signals are received that would normally crash the + * driver. + */ +#define TRAP_CRASHES + +/* THIS_PLAYER_IN_CALL_OUT: define this if you wish this_player() to be + * usable from within call_out() callbacks. + */ +#define THIS_PLAYER_IN_CALL_OUT + +/* CALLOUT_HANDLES: If this is defined, call_out() returns an integer, which + * can be passed to remove_call_out() or find_call_out(). Removing call_outs + * by name is still allowed, but is significantly less efficient, and also + * doesn't work for function pointers. This option adds 4 bytes overhead + * per callout to keep track of the handle. + */ +#define CALLOUT_HANDLES + +/* FLUSH_OUTPUT_IMMEDIATELY: Causes output to be written to sockets + * immediately after being generated. Useful for debugging. + */ +#undef FLUSH_OUTPUT_IMMEDIATELY + +/* PRIVS: define this if you want object privileges. Your mudlib must + * explicitly make use of this functionality to be useful. Defining this + * this will increase the size of the object structure by 4 bytes (8 bytes + * on the DEC Alpha) and will add a new master apply during object creation + * to "privs_file". In general, privileges can be used to increase the + * granularity of security beyond the current root uid mechanism. + * + * [NOTE: for those who'd rather do such things at the mudlib level, look at + * the inherits() efun and the 'valid_object' apply to master.] + */ +#undef PRIVS + +/* INTERACTIVE_CATCH_TELL: define this if you want catch_tell called on + * interactives as well as NPCs. If this is defined, user.c will need a + * catch_tell(msg) method that calls receive(msg); +*/ +#undef INTERACTIVE_CATCH_TELL + +/* RESTRICTED_ED: define this if you want restricted ed mode enabled. + */ +#define RESTRICTED_ED + +/* NO_SHADOWS: define this if you want to disable shadows in your driver. + */ +#undef NO_SHADOWS + +/* SNOOP_SHADOWED: define this if you want snoop to report what is + * sent to the player even in the event that the player's catch_tell() is + * shadowed and the player may not be seeing what is being sent. Messages + * of this sort will be prefixed with $$. + */ +#undef SNOOP_SHADOWED + +/* RECEIVE_SNOOP: define this if you want snoop text to be sent to + * the receive_snoop() function in the snooper object (instead of being + * sent directly via add_message()). This is useful if you want to + * build a smart client that does something different with snoop messages. + */ +#undef RECEIVE_SNOOP + +/* PROFILE_FUNCTIONS: define this to be able to measure the CPU time used by + * all of the user-defined functions in each LPC object. Note: defining + * this adds three long ints (12 bytes on 32-bit machines) to the function + * header structs. Also note that the resolution of the getrusage() timer + * may not be high enough on some machines to give non-zero execution + * times to very small (fast) functions. In particular if the clock + * resolution is 1/60 of a second, then any time less than approxmately 15k + * microseconds will resolve to zero (0). + */ +#undef PROFILE_FUNCTIONS + +/* NO_BUFFER_TYPE: if this is #define'd then LPC code using the 'buffer' + * type won't be allowed to compile (since the 'buffer' type won't be + * recognized by the lexer). + */ +#undef NO_BUFFER_TYPE + +/* BINARIES: define this to enable the 'save_binary' pragma. + * This pragma, when set in a program, will cause it to save a + * binary image when loaded, so that subsequent loadings will + * be much faster. The binaries are saved in the directory + * specified in the configuration file. The binaries will not + * load if the LPC source or any of the inherited or included + * files are out of date, in which case the file is compiled + * normally (and may save a new binary). + * + * In order to save the binary, valid_save_binary() is called + * in master.c, and is passed the name of the source file. If + * this returns a non-zero value, the binary is allowed to be + * saved. Allowing any file by any wizard to be saved as a + * binary is convenient, but may take up a lot of disk space. + */ +#define BINARIES + +/* ARRAY_RESERVED_WORD: If this is defined then the word 'array' can + * be used to define arrays, as in: + * + * int array x = ({ .... }); + * + * A side effect is that 'array' cannot be a variable or function name. + */ +#undef ARRAY_RESERVED_WORD + +/* REF_RESERVED_WORD: If this is defined then the word 'ref' can be + * used to pass arguments to functions by value. Example: + * + * void inc(int ref x) { + * x++; + * } + * + * ... y = 1; inc(ref y); ... + * + * A side effect is that 'ref' cannot be a variable or function name. + * + * Note: ref must be used in *both* places; this is intentional. It protects + * against passing references to routines which don't intend to return values + * through their arguments, and against forgetting to pass a reference + * to a function which wants one (or accidentally having a variable modified!) + */ +#undef REF_RESERVED_WORD + +/**************************************************************************** + * PACKAGES * + * -------- * + * Defining some/all of the following add certain efuns, and sometimes * + * add/remove code from the driver. * + * * + * if PACKAGE_XYZZY is defined here, then the code in packages/xyzzy.c * + * and the efuns in packages/xyzzy_spec.c will be added to the driver. * + ****************************************************************************/ + +/* various miscellaneous efuns */ +#define PACKAGE_CONTRIB + +/* efuns that are only of use to those that know something about driver + internals */ +#define PACKAGE_DEVELOP + +/* PACKAGE_MATH: determines whether or not the math efuns (for floats) are + included. + */ +#define PACKAGE_MATH + +/* PACKAGE_MATRIX: determines whether or not the 3d graphics efuns (for floats) + * are included - see packages/matrix.spec for a list. + */ +#undef PACKAGE_MATRIX + +/* PACKAGE_MUDLIB_STATS: define this to enable domain and author stats + * maintenance by the driver. These mudlib stats are more domain + * based than user based, and replaces the traditional wiz_list stats. + */ +#define PACKAGE_MUDLIB_STATS + +/* PACKAGE_SOCKETS: define this to enable the socket efunctions. This + * causes HAS_SOCKETS to be defined for all LPC objects. + */ +#define PACKAGE_SOCKETS + +/* PACKAGE_PARSER: Natural language parsing efuns for interactive fiction + * type applications + */ +#undef PACKAGE_PARSER + +/* PACKAGE_EXTERNAL: Allows the driver to exec() commands specified in the + * config file. + */ +#undef PACKAGE_EXTERNAL + +/* NUM_EXTERNAL_CMDS: the number of external commands supported */ +#define NUM_EXTERNAL_CMDS 1 + +/* PACKAGE_DB: efuns for external database access using msql */ +#undef PACKAGE_DB + +/* If PACKAGE_DB is defined above, you must pick ONE of the following supported + * databases + */ +#ifdef PACKAGE_DB +#undef USE_MSQL +#undef MSQL +#define USE_MYSQL 2 +#define MY_SQL +#endif + +/**************************************************************************** + * UID PACKAGE * + * ----------- * + * UIDS are the basis for some mudlib security systems. Basically, they're * + * preserved for backwards compatibility, as several ways of breaking * + * almost any system which relies on them are known. (No, it's not a flaw * + * of uids; only that b/c of the ease with which LPC objects can call * + * each other, it's far too easy to leave holes) * + * * + * If you don't care about security, the first option is probably what you * + * want. * + ****************************************************************************/ + +/* + * PACKAGE_UIDS: define this if you want a driver that does use uids. + * + */ +#define PACKAGE_UIDS + +/*PACKAGE DWLIB: some discworld mudlib simuls coded in C (well just one right + now) */ + +#undef PACKAGE_DWLIB + +/* AUTO_SETEUID: when an object is created it's euid is automatically set to + * the equivalent of seteuid(getuid(this_object())). undef AUTO_SETEUID + * if you would rather have the euid of the created object be set to 0. + */ +#undef AUTO_SETEUID + +/* AUTO_TRUST_BACKBONE: define this if you want objects with the backbone + * uid to automatically be trusted and to have their euid set to the uid of + * the object that forced the object's creation. + */ +#define AUTO_TRUST_BACKBONE + +/************************************************************************* + * FOR EXPERIENCED USERS * + * ----------------------- * + * Most of these options will probably be of no interest to many users. * + *************************************************************************/ + +/* USE_32BIT_ADDRESSES: Use 32 bits for addresses of function, instead of + * the usual 16 bits. This increases the maximum program size from 64k + * of LPC bytecode (NOT source) to 4 GB. Branches are still 16 bits, + * imposing a 64k limit on catch(), if(), switch(), loops, and most other + * control structures. It would take an extremely large function to hit + * those limits, though. + * + * Overhead: 2 bytes/function with LPC->C off. Having LPC->C on forces + * this option, since it needs 4 bytes to store the function pointers + * anyway, and this setting is ignored. + */ +#undef USE_32BIT_ADDRESSES + +/* HEARTBEAT_INTERVAL: define heartbeat interval in microseconds (us). + * 1,000,000 us = 1 second. The value of this macro specifies + * the frequency with which the heart_beat method will be called in + * those LPC objects which have called set_heart_beat(1). + * + * [NOTE: if ualarm() isn't available, alarm() is used instead. Since + * alarm() requires its argument in units of a second, we map 1 - 1,000,000 us + * to an actual interval of one (1) second and 1,000,001 - 2,000,000 maps to + * an actual interval of two (2) seconds, etc.] + */ +#define HEARTBEAT_INTERVAL 2 + +/* + * CALLOUT_CYCLE_SIZE: This is the number of slots in the call_out list. + * It should be approximately the average number of active call_outs, or + * a few times smaller. It should also be a power of 2, and also be relatively + * prime to any common call_out lengths. If all this is too confusing, 32 + * isn't a bad number :-) + */ +#define CALLOUT_CYCLE_SIZE 512 + +/* LARGEST_PRINTABLE_STRING: defines the size of the vsprintf() buffer in + * comm.c's add_message(). Instead of blindly making this value larger, + * your mudlib should be coded to not send huge strings to users. + */ +#define LARGEST_PRINTABLE_STRING 8192 + +/* MESSAGE_BUFFER_SIZE: determines the size of the buffer for output that + * is sent to users. + */ +#define MESSAGE_BUFFER_SIZE 4096 + +/* APPLY_CACHE_BITS: defines the number of bits to use in the call_other cache + * (in interpret.c). + * + * Memory overhead is (1 << APPLY_CACHE_BITS)*16. + * [assuming 32 bit pointers and 16 bit shorts] + * + * ACB: entries: overhead: + * 6 64 1k + * 8 256 4k + * 10 1024 16k + * 12 4096 64k + * 14 16384 256k + * 16 65536 1M + */ +#define APPLY_CACHE_BITS 20 + +/* CACHE_STATS: define this if you want call_other (apply_low) cache + * statistics. Causes HAS_CACHE_STATS to be defined in all LPC objects. + */ +#define CACHE_STATS + +/* TRACE: define this to enable the trace() and traceprefix() efuns. + * (keeping this undefined will cause the driver to run faster). + */ +#undef TRACE + +/* RUNTIME_LOADING: On systems which support it, it allows LPC->C compilation + * 'on the fly' without having to recompile the driver. + * + * Note: This currently only works on machines that have the dlopen() system + * call. SunOS and IRIX do, as do a number of others. AIX and Ultrix don't. + * Linux does if you are using ELF. + */ +#undef RUNTIME_LOADING + +/* TRACE_CODE: define this to enable code tracing (the driver will print + * out the previous lines of code to an error) eval_instruction() runs about + * twice as fast when this is not defined (for the most common eoperators). + */ +#undef TRACE_CODE + +/* HEART_BEAT_CHUNK: The number of heart_beat chunks allocated at a time. + * A large number wastes memory as some will be sitting around unused, while + * a small one wastes more CPU reallocating when it needs to grow. Default + * to a medium value. + */ +#define HEART_BEAT_CHUNK 32 + +/* SERVER_IP: For machines with multiple IP addresses, this specifies which + * one to use. This is useful for IP accounting and is necessary to be + * able to do ident lookups on such machines. + * + * example: #define SERVER_IP "194.229.18.27" + */ +#undef SERVER_IP + +/* Some maximum string sizes + */ +#define SMALL_STRING_SIZE 100 +#define LARGE_STRING_SIZE 1000 +#define COMMAND_BUF_SIZE 2000 + +/* Number of levels of nested datastructures allowed -- this limit prevents + * crashes from occuring when saving objects containing variables containing + * recursive datastructures (with circular references). + */ +#define MAX_SAVE_SVALUE_DEPTH 100 + +/* Miscellaneous config options that should probably be in the runtime + * config file. + */ +/* MAX_LOCAL: maximum number of local variables allowed per LPC function */ +#define CFG_MAX_LOCAL_VARIABLES 50 +/* Increasing max global vars beyond 256 is not recommended */ +#define CFG_MAX_GLOBAL_VARIABLES 300 + +#define CFG_EVALUATOR_STACK_SIZE 3000 +#define CFG_COMPILER_STACK_SIZE 600 +#define CFG_MAX_CALL_DEPTH 150 +/* This must be one of 4, 16, 64, 256, 1024, 4096 */ +#define CFG_LIVING_HASH_SIZE 256 + +/* NEXT_MALLOC_DEBUG: define this if using a NeXT and you want to enable + * the malloc_check() and/or malloc_debug() efuns. Run the 'man malloc_debug' + * command on the NeXT to find out what the arguments to malloc_debug(int) + * mean. The malloc_check() efun calls the NeXT NXMallocCheck() system + * call which does a consistency check on malloc's data structures (this + * consistency check is done at each malloc() and free() for certain + * malloc_debug() levels). A non-zero return value indicates there was + * a consistency problem. For those NeXT users wanting a bit more + * performance out of malloc, try defining NEXT_MALLOC_DEBUG and calling the + * malloc_debug(-1) efun (with an arg of -1). This will turn all + * malloc debugging off and call malloc_singlethreaded() which the NeXT + * malloc man page claims can make NeXT system malloc 10% to 15% faster. + * + * [NOTE: This #define has no affect on the driver if not using the + * NeXTSTEP OS.] + * + * Warning: if you use a NeXT and define NEXT_MALLOC_DEBUG, be sure to + * protect the use of the malloc_check() and malloc_debug() efuns + * since setting certain debug levels can cause malloc() and free() + * to become _very_ slow (protect efuns by using simul_efuns and + * valid_override). + * + * [NOTE: malloc_debug(6) is a good compromise between efficiency and + * completeness of malloc debugging (malloc/free will be about half as fast).] + */ +#undef NEXT_MALLOC_DEBUG + + +/* GET_CHAR_IS_BUFFERED: Normally get_char() is unbuffered. That is, once + * a character is received for get_char(), anything else is in the input + * stream is immediately thrown away. This can be very undesirable, especially + * if you're calling get_char() again from the handler from the previous call. + * Define this if you want get_char() to be buffered. In this case, the buffer + * will only get flushed if get_char() is not called from the first get_char()'s + * LPC callback handler. + */ +#undef GET_CHAR_IS_BUFFERED + +/* PACKAGE_COMPRESS: Enable MCCP support and compressed save files + SAVE_GZ_EXTENSION: save extension for compressed files + */ +#undef HAVE_ZLIB +#undef PACKAGE_COMPRESS +#define SAVE_GZ_EXTENSION ".o.gz" + +/* CALL_OTHER_TYPE_CHECK: enable type checking for call_other() + * (-> operator on objects) + */ +#undef CALL_OTHER_TYPE_CHECK + +/* CALL_OTHER_WARN, make it warning instead of errors */ +#undef CALL_OTHER_WARN + +/* WARN_TAB: Some versions of the editor built in indent function use + * tabs for indenting. This options turns on a warning message for + * files indented with tabs instead of spaces. + */ +#define WARN_TAB + +/* USE_ICONV: Use iconv to translate input and output from/to the users char + * encoding + */ +#undef USE_ICONV + +/* WOMBLES: don't allow spaces between start/end of array/mapping/functional token chars so ({1,2,3}) still works, but ( { 1 , 2 , 3 } ) doesn't and ({ 1 , 2 , 3 }) does.*/ +#undef WOMBLES + +/* ALLOW_INHERIT_AFTER_FUNCTION: allow inheriting after functions have been defined (this includes prototypes). This caused crashes in v22.2a but it may have been fixed since */ +#define ALLOW_INHERIT_AFTER_FUNCTION +#define ALLOW_INHERIT_AFTER_GLOBAL_VARIABLES +#undef PACKAGE_DSLIB +#undef ED_INDENT_CASE +#define ED_INDENT_SPACES 4 +#define PROG_REF_TYPE int +#undef ANSI_SUBSTITUTE +#undef RECEIVE_ED +#undef PACKAGE_ASYNC +#define HAS_CONSOLE +#undef PARSE_DEBUG +#define FLUFFOS +#endif +#undef IPV6 +#undef MALLOC64 +#undef PACKAGE_CRYPTO +#undef PACKAGE_SHA1 diff --git a/fluffos-2.23-ds03/local_options.lil b/fluffos-2.23-ds03/local_options.lil new file mode 100644 index 0000000..f30b901 --- /dev/null +++ b/fluffos-2.23-ds03/local_options.lil @@ -0,0 +1,893 @@ +/* + * options.h: defines for the compile-time configuration of the MudOS driver + */ + +#ifndef _OPTIONS_H_ +#define _OPTIONS_H_ + +/* + * YOU PROBABLY DO NOT WANT TO MODIFY THIS FILE. + * + * Do 'cp options.h local_options' and edit that instead. local_options, + * if it exists, overrides this file. + * + * The advantage is that when you upgrade to a newer MudOS driver, you can + * simply copy your local_options file into the src directory. The build + * process will warn you if new options have been added that you should + * choose settings for. + */ + +/**************************************************************************** + * EVERY time you change ANYTHING in this file, RECOMPILE from scratch. * + * (type "make clean" then "make" on a UNIX system) Failure to do so may * + * cause the driver to behave oddly. * + ****************************************************************************/ + +/* NOTES: + * Many of the configurable options are now set via the configuration file + * that is specified as the first argument to the driver. + * See port.h for those #defines related to portability (compatibility) if + * you have problems compiling on your system. + * Removing an efun from func_spec.c usually removes most, if not all, + * of the code associated with it. + * Note that anything defined in this file is also visible to LPC files + * surrounded by __. So #define FOO in this file defines __FOO__ for + * all LPC files. This allows code like: + * + * #ifdef __SENSIBLE_MODIFIERS__ + * ... + */ + +/**************************************************************************** + * MALLOC * + * -------- * + * For performance reasons, LP drivers have a variety of memory allocation * + * packages. If you don't care, use the default one on your system: * + * #define SYSMALLOC, #undef the others. * + ****************************************************************************/ + +/* You must choose exactly one of these malloc packages: + * ~~~~ + * SYSMALLOC: + * * Built-in system malloc. + * * No statistics. + * * SYSMALLOC incurs no additional CPU or memory overhead. + * + * SMALLOC: + * * Satoria's smalloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than most system mallocs with modest ammount of memory overhead. + * * Can fall back onto system malloc if sbrk() not ok. + * + * BSDMALLOC: + * * BSD (Berkeley Software Distributions) malloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than SMALLOC but more memory overhead. + * * Requires sbrk(). + */ +#define SYSMALLOC +#undef SMALLOC +#undef BSDMALLOC +#undef MMALLOC + +/* You may optionally choose one (or none) of these malloc wrappers. These + * can be used in conjunction with any of the above malloc packages. + * + * WRAPPEDMALLOC: + * * Limited statistics. + * * Limited additional cpu overhead and no additional memory overhead. + * + * DEBUGMALLOC: + * * Statistics on precisely how much memory has been malloc'd (as well + * as the stats provided by WRAPPEDMALLOC). + * * Incurs a fair amount of overhead (both memory and CPU) + */ +#undef WRAPPEDMALLOC +#undef DEBUGMALLOC + +/* The following add certain bells and whistles to malloc: */ + +/* + * SBRK_OK: do not define this unless SMALLOC is chosen above. + * Defining this causes smalloc to use the low level memory allocation + * routines, and to act as a malloc replacement. Conversely, undef'ing + * SBRK_OK causes smalloc to act as a wrapper for the system malloc + * routines. + * + * Note: + * NeXTStep 3.x users should always #undef SBRK_OK. + */ +#undef SBRK_OK + +/* DO_MSTATS: do not define this unless BSDMALLOC or SMALLOC is chosen above. + * Defining this causes those replacement mallocs to keep statistics that + * the malloc_status() efun will print out (including total memory + * allocated/used). + */ +#undef DO_MSTATS + +/* DEBUGMALLOC_EXTENSIONS: defining this (in addition to DEBUGMALLOC) enables + * the set_malloc_mask(int) and debugmalloc(string,int) efuns. These two + * efuns basically allow you to cause certain malloc's and free's (with tags + * selected by a specified mask) to print debug information (addr, tag, + * description, size) to stdio (in the shell that invoked the driver) or to a + * file. Not defining this does reduce the overhead of DEBUGMALLOC from 16 + * bytes per malloc down to 8. This macro has no effect if DEBUGMALLOC isn't + * defined. + */ +#undef DEBUGMALLOC_EXTENSIONS + +/* CHECK_MEMORY: defining this (in addition to DEBUGMALLOC and + * DEBUGMALLOC_EXTENSIONS) causes the driver to check for memory + * corruption due to writing before the start or end of a block. This + * also adds the check_memory() efun. Takes a considerable ammount + * more memory. Mainly for debugging. + */ +#undef CHECK_MEMORY + +/**************************************************************************** + * COMPATIBILITY * + * --------------- * + * The MudOS driver has evolved quite a bit over the years. These defines * + * are mainly to preserve old behavior in case people didn't want to * + * rewrite the relevant portions of their code. * + * * + * In most cases, code which needs these defines should be rewritten when * + * possible. The 'Compat status' field is designed to give an idea how * + * likely it is that support for that option will be removed in the near * + * future. Certain options are fairly easy to work around, and double * + * the size of the associated code, as well as the maintenance workload, * + * and can make the code significantly more complex or harder to read, so * + * supporting them indefinitely is impractical. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* HAS_STATUS_TYPE: old MudOS drivers had a 'status' type which was + * identical to the 'int' type. Define this to bring it back. + * + * Compat status: very archaic, but easy to support. + */ +#undef HAS_STATUS_TYPE + +/* explode(): + * + * The old behavior (#undef both of the below) strips any number of + * delimiters at the start of the string, and one at the end. So + * explode("..x.y..z..", ".") gives ({ "x", "y", "", "z", "" }) + * + * SANE_EXPLODE_STRING strips off at most one leading delimiter, and + * still strips off one at the end, so the example above gives + * ({ "", "x", "y", "", "z", "" }). + * + * REVERSIBLE_EXPLODE_STRING overrides SANE_EXPLODE_STRING, and makes + * it so that implode(explode(x, y), y) is always x; i.e. no delimiters + * are ever stripped. So the example above gives + * ({ "", "", "x", "y", "", "z", "", "" }). + */ +#define SANE_EXPLODE_STRING +#undef REVERSIBLE_EXPLODE_STRING + +/* CAST_CALL_OTHERS: define this if you want to require casting of call_other's; + * this was the default behavior of the driver prior to this addition. + * + * Compat status: code that requires it doesn't break, and it promotes + * sloppy coding with no benefits. + */ +#undef CAST_CALL_OTHERS + +/* NONINTERACTIVE_STDERR_WRITE: if defined, all writes/tells/etc to + * noninteractive objects will be written to stderr prefixed with a ']' + * (old behavior). + * + * Compat status: Easy to support, and also on the "It's a bug! No, it's + * a feature!" religious war list. + */ +#define NONINTERACTIVE_STDERR_WRITE + +/* NO_LIGHT: define this to disable the set_light() and driver maintenance + * of light levels in objects. You can simulate it via LPC if you want... + * + * Compat status: Very dated, easy to simulate, and gross. + */ +#define NO_LIGHT + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + * process_input() then becomes the only way to deal with player input. + * + * Compat status: next to impossible to simulate, hard to replace, and + * very, very widely used. + */ +#undef NO_ADD_ACTION + +/* NO_SNOOP: disables the snoop() efun and all related functionality. + */ +#undef NO_SNOOP + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + process_input() then becomes the only way to deal with player input. */ + +/* NO_ENVIRONMENT: define this to remove the handling of object containment + * relationships by the driver + * + * Compat status: hard to simulate efficiently, and very widely used. + */ +#undef NO_ENVIRONMENT + +/* NO_WIZARDS: for historical reasons, MudOS used to keep track of who + * is and isn't a wizard. Defining this removes that completely. + * If this is defined, the wizardp() and related efuns don't exist. + * + * Also note that if it is not defined, then non-wizards are always put + * in restricted mode when ed() is used, regardless of the setting of + * the restrict parameter. + * + * Compat status: easy to simulate and dated. + */ +#define NO_WIZARDS + +/* OLD_TYPE_BEHAVIOR: reintroduces a bug in type-checking that effectively + * renders compile time type checking useless. For backwards compatibility. + * + * Compat status: dealing with all the resulting compile errors can be + * a huge pain even if they are correct, and the impact on the code is + * small. + */ +#undef OLD_TYPE_BEHAVIOR + +/* OLD_RANGE_BEHAVIOR: define this if you want negative indexes in string + * or buffer range values (not lvalue, i.e. x[-2..-1]; for e.g. not + * x[-2..-1] = foo, the latter is always illegal) to mean counting from the + * end + * + * Compat status: Not horribly difficult to replace reliance on this, but not + * trivial, and cannot be simulated. + */ +#undef OLD_RANGE_BEHAVIOR + +/* OLD_ED: ed() efun backwards compatible with the old version. The new + * version requires/allows a mudlib front end. + * + * Compat status: Easily simulated. + */ +#define OLD_ED + +/* SENSIBLE_MODIFIERS: + * Turning this on changes a few things, which may break old code: + * + * (1) 'static' is not recognized; either 'nosave' or 'protected' must + * be used instead. + * (2) The old meaning of 'public' is no longer allowed. Explicit + * functions must be defined at each level to allow access to + * privately inherited functions. + * (3) 'public' now means the default visibility. Previously there was + * no keyword that meant this (before you ask, 'public' meant something + * else, and if you don't know that, you probably don't have any reason + * to care about the old meaning). + */ +#define SENSIBLE_MODIFIERS + +/**************************************************************************** + * MISCELLANEOUS * + * --------------- * + * Various options that affect the way the driver behaves. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* + * Define this in order to use Fermat@Equilibria's MD5 based crypt() instead + * of the operating system's. It has the advantage of giving the same value + * on all architectures, and being stronger than the standard UNIX crypt(). + */ +#define CUSTOM_CRYPT + +/* + * Some minor tweaks that make it a bit easier to run code designed to run + * on LPmud 3.2/3.2.1. Currently has the following effects: + * + * . m_indices() and m_values() are synonyms for keys() and values(), + * respectively + * . map_delete() returns it's first argument + * . inherit_list() means deep_inherit_list(), not shallow_inherit_list() + * . heart_beat_info() is a synonym for heart_beats() + */ +#undef COMPAT_32 + +/* + * Keep statistics about allocated strings, etc. Which can be viewed with + * the mud_status() efun. If this is off, mud_status() and memory_info() + * ignore allocated strings, but string operations run faster. + */ +#define STRING_STATS + +/* + * Similarly for arrays ... + */ +#define ARRAY_STATS + +/* LOG_CATCHES: define this to cause errors that are catch()'d to be + * sent to the debug log anyway. + * + * On by default, because newer libs use catch() a lot, and it's confusing + * if the errors don't show up in the logs. + */ +#define LOG_CATCHES + +/* ARGUMENTS_IN_TRACEBACK: prints out function call arguments in error + * tracebacks, to aid in debugging. Note: it prints the values of + * the arguments at the time of the error, not when the function + * was called. It looks like this: + * + * Failed to load file: read_buffer + * program: command/update.c, object: command/update line 15 + * ' commandHook' in ' clone/user.c' (' clone/user#1')line 72 + * arguments were ("/read_buffer.c") + * ' main' in ' command/update.c' (' command/update')line 15 + * arguments were ("/read_buffer.c") + * + * The only down side is some people like their logs shorter + */ +#define ARGUMENTS_IN_TRACEBACK + +/* LOCALS_IN_TRACEBACK: similar to ARGUMENTS_IN_TRACEBACK, but for local + * variables. The output looks more or less like: + * + * locals: 1, "local_value" + * + * Same as above. Tends to produce even longer logs, but very useful for + * tracking errors. + */ +#define LOCALS_IN_TRACEBACK + +/* MUDLIB_ERROR_HANDLER: If you define this, the driver doesn't do any + * handling of runtime errors, other than to turn the heartbeats of + * objects off. Information about the error is passed in a mapping + * to the error_handler() function in the master object. Whatever is + * returned is put in the debug.log. + * + * A good mudlib error handler is one of the best tools for tracking down + * errors. Unfortunately, you need to have one. Check the testsuite or + * other libs for an example. + */ +#define MUDLIB_ERROR_HANDLER + +/* CONFIG_FILE_DIR specifies a directory in which the driver will search for + * config files by default. If you don't wish to use this define, you may + * always specify a full path to the config file when starting the driver. + */ +#define CONFIG_FILE_DIR "/home/atuin/bin" + +/* DEFAULT_PRAGMAS: This should be a sum of pragmas you want to always + * be on, i.e. + * + * #define DEFAULT_PRAGMAS PRAGMA_STRICT_TYPES + PRAGMA_SAVE_TYPES + * + * will make every LPC file behave as if it had the lines: + * #pragma strict_types + * #pragma save_types + * + * for no default pragmas: + * #define DEFAULT_PRAGMAS 0 + * + * If you don't know what these are, 0 is a good choice. + * + * Supported pragmas: + * PRAGMA_STRICT_TYPES: enforces strict type checking + * PRAGMA_WARNINGS: issues warnings about various dangerous things in + * your code + * PRAGMA_SAVE_TYPES: save the types of function arguments for checking + * calls to functions in this object by objects that + * inherit it. + * PRAGMA_SAVE_BINARY: save a compiled binary version of this file for + * faster loading next time it is needed. + * PRAGMA_OPTIMIZE: make a second pass over the generated code to + * optimize it further. Currently does jump threading. + * PRAGMA_ERROR_CONTEXT:include some text telling where on the line a + * compilation error occured. + */ +#define DEFAULT_PRAGMAS PRAGMA_WARNINGS + PRAGMA_STRICT_TYPES + PRAGMA_ERROR_CONTEXT + +/* supress warnings about unused arguments; only warn about unused local + * variables. Makes older code (where argument names were required) compile + * more quietly. + */ +#define SUPPRESS_ARGUMENT_WARNINGS + +/* NO_RESETS: completely disable the periodic calling of reset() */ +#undef NO_RESETS + +/* LAZY_RESETS: if this is defined, an object will only have reset() + * called in it when it is touched via call_other() or move_object() + * (assuming enough time has passed since the last reset). If LAZY_RESETS + * is #undef'd, then reset() will be called as always (which guaranteed that + * reset would always be called at least once). The advantage of lazy + * resets is that reset doesn't get called in an object that is touched + * once and never again (which can save memory since some objects won't get + * reloaded that otherwise would). + */ +#undef LAZY_RESETS + +/* SAVE_EXTENSION: defines the file extension used by save_object(). + * and restore_object(). Some sysadmins run scripts that periodically + * scan for and remove files ending in .o (but many mudlibs are already + * set up to use .o thus we leave .o as the default). + */ +#define SAVE_EXTENSION ".o" + +/* NO_ANSI: define if you wish to disallow users from typing in commands that + * contain ANSI escape sequences. Defining NO_ANSI causes all escapes + * (ASCII 27) to be replaced with a space ' ' before the string is passed + * to the action routines added with add_action. + * + * STRIP_BEFORE_PROCESS_INPUT allows the location where the stripping is + * done to be controlled. If it is defined, then process_input() doesn't + * see ANSI characters either; if it is undefined ESC chars can be processed + * by process_input(), but are stripped before add_actions are called. + * Note that if NO_ADD_ACTION is defined, then #define NO_ANSI without + * #define STRIP_BEFORE_PROCESS_INPUT is the same as #undef NO_ANSI. + * + * If you anticipate problems with users intentionally typing in ANSI codes + * to make your terminal flash, etc define this. + */ +#define NO_ANSI +#define STRIP_BEFORE_PROCESS_INPUT + +/* OPCPROF: define this if you wish to enable OPC profiling. Allows a dump + * of the # of times each efun is invoked (via the opcprof() efun). + */ +#undef OPCPROF + +/* OPCPROF_2D: define this if you wish to enable 2-D OPC profiling. Allows a + * dump of the # of times each *pair* of eoperators is invoked. + * + * You can't use this and OPCPROF at the same time. + */ +#undef OPCPROF_2D + +/* TRAP_CRASHES: define this if you want MudOS to call crash() in master.c + * and then shutdown when signals are received that would normally crash the + * driver. + */ +#define TRAP_CRASHES + +/* THIS_PLAYER_IN_CALL_OUT: define this if you wish this_player() to be + * usable from within call_out() callbacks. + */ +#define THIS_PLAYER_IN_CALL_OUT + +/* CALLOUT_HANDLES: If this is defined, call_out() returns an integer, which + * can be passed to remove_call_out() or find_call_out(). Removing call_outs + * by name is still allowed, but is significantly less efficient, and also + * doesn't work for function pointers. This option adds 4 bytes overhead + * per callout to keep track of the handle. + */ +#define CALLOUT_HANDLES + +/* FLUSH_OUTPUT_IMMEDIATELY: Causes output to be written to sockets + * immediately after being generated. Useful for debugging. + */ +#undef FLUSH_OUTPUT_IMMEDIATELY + +/* PRIVS: define this if you want object privileges. Your mudlib must + * explicitly make use of this functionality to be useful. Defining this + * this will increase the size of the object structure by 4 bytes (8 bytes + * on the DEC Alpha) and will add a new master apply during object creation + * to "privs_file". In general, privileges can be used to increase the + * granularity of security beyond the current root uid mechanism. + * + * [NOTE: for those who'd rather do such things at the mudlib level, look at + * the inherits() efun and the 'valid_object' apply to master.] + */ +#undef PRIVS + +/* INTERACTIVE_CATCH_TELL: define this if you want catch_tell called on + * interactives as well as NPCs. If this is defined, user.c will need a + * catch_tell(msg) method that calls receive(msg); +*/ +#undef INTERACTIVE_CATCH_TELL + +/* RESTRICTED_ED: define this if you want restricted ed mode enabled. + */ +#define RESTRICTED_ED + +/* NO_SHADOWS: define this if you want to disable shadows in your driver. + */ +#undef NO_SHADOWS + +/* SNOOP_SHADOWED: define this if you want snoop to report what is + * sent to the player even in the event that the player's catch_tell() is + * shadowed and the player may not be seeing what is being sent. Messages + * of this sort will be prefixed with $$. + */ +#undef SNOOP_SHADOWED + +/* RECEIVE_SNOOP: define this if you want snoop text to be sent to + * the receive_snoop() function in the snooper object (instead of being + * sent directly via add_message()). This is useful if you want to + * build a smart client that does something different with snoop messages. + */ +#undef RECEIVE_SNOOP + +/* PROFILE_FUNCTIONS: define this to be able to measure the CPU time used by + * all of the user-defined functions in each LPC object. Note: defining + * this adds three long ints (12 bytes on 32-bit machines) to the function + * header structs. Also note that the resolution of the getrusage() timer + * may not be high enough on some machines to give non-zero execution + * times to very small (fast) functions. In particular if the clock + * resolution is 1/60 of a second, then any time less than approxmately 15k + * microseconds will resolve to zero (0). + */ +#undef PROFILE_FUNCTIONS + +/* NO_BUFFER_TYPE: if this is #define'd then LPC code using the 'buffer' + * type won't be allowed to compile (since the 'buffer' type won't be + * recognized by the lexer). + */ +#undef NO_BUFFER_TYPE + +/* BINARIES: define this to enable the 'save_binary' pragma. + * This pragma, when set in a program, will cause it to save a + * binary image when loaded, so that subsequent loadings will + * be much faster. The binaries are saved in the directory + * specified in the configuration file. The binaries will not + * load if the LPC source or any of the inherited or included + * files are out of date, in which case the file is compiled + * normally (and may save a new binary). + * + * In order to save the binary, valid_save_binary() is called + * in master.c, and is passed the name of the source file. If + * this returns a non-zero value, the binary is allowed to be + * saved. Allowing any file by any wizard to be saved as a + * binary is convenient, but may take up a lot of disk space. + */ +#define BINARIES + +/* ARRAY_RESERVED_WORD: If this is defined then the word 'array' can + * be used to define arrays, as in: + * + * int array x = ({ .... }); + * + * A side effect is that 'array' cannot be a variable or function name. + */ +#define ARRAY_RESERVED_WORD + +/* REF_RESERVED_WORD: If this is defined then the word 'ref' can be + * used to pass arguments to functions by value. Example: + * + * void inc(int ref x) { + * x++; + * } + * + * ... y = 1; inc(ref y); ... + * + * A side effect is that 'ref' cannot be a variable or function name. + * + * Note: ref must be used in *both* places; this is intentional. It protects + * against passing references to routines which don't intend to return values + * through their arguments, and against forgetting to pass a reference + * to a function which wants one (or accidentally having a variable modified!) + */ +#define REF_RESERVED_WORD + +/**************************************************************************** + * PACKAGES * + * -------- * + * Defining some/all of the following add certain efuns, and sometimes * + * add/remove code from the driver. * + * * + * if PACKAGE_XYZZY is defined here, then the code in packages/xyzzy.c * + * and the efuns in packages/xyzzy_spec.c will be added to the driver. * + ****************************************************************************/ + +/* various miscellaneous efuns */ +#define PACKAGE_CONTRIB + +/* efuns that are only of use to those that know something about driver + internals */ +#define PACKAGE_DEVELOP + +/* PACKAGE_MATH: determines whether or not the math efuns (for floats) are + included. + */ +#define PACKAGE_MATH + +/* PACKAGE_MATRIX: determines whether or not the 3d graphics efuns (for floats) + * are included - see packages/matrix.spec for a list. + */ +#undef PACKAGE_MATRIX + +/* PACKAGE_MUDLIB_STATS: define this to enable domain and author stats + * maintenance by the driver. These mudlib stats are more domain + * based than user based, and replaces the traditional wiz_list stats. + */ +#undef PACKAGE_MUDLIB_STATS + +/* PACKAGE_SOCKETS: define this to enable the socket efunctions. This + * causes HAS_SOCKETS to be defined for all LPC objects. + */ +#define PACKAGE_SOCKETS + +/* PACKAGE_PARSER: Natural language parsing efuns for interactive fiction + * type applications + */ +#undef PACKAGE_PARSER + +/* PACKAGE_EXTERNAL: Allows the driver to exec() commands specified in the + * config file. + */ +#undef PACKAGE_EXTERNAL + +/* NUM_EXTERNAL_CMDS: the number of external commands supported */ +#define NUM_EXTERNAL_CMDS 1 + +/* PACKAGE_DB: efuns for external database access using msql */ +#undef PACKAGE_DB + +/* If PACKAGE_DB is defined above, you must pick ONE of the following supported + * databases + */ +#ifdef PACKAGE_DB +#undef USE_MSQL +#undef MSQL +#define USE_MYSQL 2 +#define MY_SQL +#endif + +/**************************************************************************** + * UID PACKAGE * + * ----------- * + * UIDS are the basis for some mudlib security systems. Basically, they're * + * preserved for backwards compatibility, as several ways of breaking * + * almost any system which relies on them are known. (No, it's not a flaw * + * of uids; only that b/c of the ease with which LPC objects can call * + * each other, it's far too easy to leave holes) * + * * + * If you don't care about security, the first option is probably what you * + * want. * + ****************************************************************************/ + +/* + * PACKAGE_UIDS: define this if you want a driver that does use uids. + * + */ +#define PACKAGE_UIDS + +/*PACKAGE DWLIB: some discworld mudlib simuls coded in C (well just one right + now) */ + +#undef PACKAGE_DWLIB + +/* AUTO_SETEUID: when an object is created it's euid is automatically set to + * the equivalent of seteuid(getuid(this_object())). undef AUTO_SETEUID + * if you would rather have the euid of the created object be set to 0. + */ +#undef AUTO_SETEUID + +/* AUTO_TRUST_BACKBONE: define this if you want objects with the backbone + * uid to automatically be trusted and to have their euid set to the uid of + * the object that forced the object's creation. + */ +#define AUTO_TRUST_BACKBONE + +/************************************************************************* + * FOR EXPERIENCED USERS * + * ----------------------- * + * Most of these options will probably be of no interest to many users. * + *************************************************************************/ + +/* USE_32BIT_ADDRESSES: Use 32 bits for addresses of function, instead of + * the usual 16 bits. This increases the maximum program size from 64k + * of LPC bytecode (NOT source) to 4 GB. Branches are still 16 bits, + * imposing a 64k limit on catch(), if(), switch(), loops, and most other + * control structures. It would take an extremely large function to hit + * those limits, though. + * + * Overhead: 2 bytes/function with LPC->C off. Having LPC->C on forces + * this option, since it needs 4 bytes to store the function pointers + * anyway, and this setting is ignored. + */ +#undef USE_32BIT_ADDRESSES + +/* HEARTBEAT_INTERVAL: define heartbeat interval in microseconds (us). + * 1,000,000 us = 1 second. The value of this macro specifies + * the frequency with which the heart_beat method will be called in + * those LPC objects which have called set_heart_beat(1). + * + * [NOTE: if ualarm() isn't available, alarm() is used instead. Since + * alarm() requires its argument in units of a second, we map 1 - 1,000,000 us + * to an actual interval of one (1) second and 1,000,001 - 2,000,000 maps to + * an actual interval of two (2) seconds, etc.] + */ +#define HEARTBEAT_INTERVAL 2 + +/* + * CALLOUT_CYCLE_SIZE: This is the number of slots in the call_out list. + * It should be approximately the average number of active call_outs, or + * a few times smaller. It should also be a power of 2, and also be relatively + * prime to any common call_out lengths. If all this is too confusing, 32 + * isn't a bad number :-) + */ +#define CALLOUT_CYCLE_SIZE 512 + +/* LARGEST_PRINTABLE_STRING: defines the size of the vsprintf() buffer in + * comm.c's add_message(). Instead of blindly making this value larger, + * your mudlib should be coded to not send huge strings to users. + */ +#define LARGEST_PRINTABLE_STRING 8192 + +/* MESSAGE_BUFFER_SIZE: determines the size of the buffer for output that + * is sent to users. + */ +#define MESSAGE_BUFFER_SIZE 4096 + +/* APPLY_CACHE_BITS: defines the number of bits to use in the call_other cache + * (in interpret.c). + * + * Memory overhead is (1 << APPLY_CACHE_BITS)*16. + * [assuming 32 bit pointers and 16 bit shorts] + * + * ACB: entries: overhead: + * 6 64 1k + * 8 256 4k + * 10 1024 16k + * 12 4096 64k + * 14 16384 256k + * 16 65536 1M + */ +#define APPLY_CACHE_BITS 20 + +/* CACHE_STATS: define this if you want call_other (apply_low) cache + * statistics. Causes HAS_CACHE_STATS to be defined in all LPC objects. + */ +#define CACHE_STATS + +/* TRACE: define this to enable the trace() and traceprefix() efuns. + * (keeping this undefined will cause the driver to run faster). + */ +#define TRACE + +/* RUNTIME_LOADING: On systems which support it, it allows LPC->C compilation + * 'on the fly' without having to recompile the driver. + * + * Note: This currently only works on machines that have the dlopen() system + * call. SunOS and IRIX do, as do a number of others. AIX and Ultrix don't. + * Linux does if you are using ELF. + */ +#undef RUNTIME_LOADING + +/* TRACE_CODE: define this to enable code tracing (the driver will print + * out the previous lines of code to an error) eval_instruction() runs about + * twice as fast when this is not defined (for the most common eoperators). + */ +#undef TRACE_CODE + +/* HEART_BEAT_CHUNK: The number of heart_beat chunks allocated at a time. + * A large number wastes memory as some will be sitting around unused, while + * a small one wastes more CPU reallocating when it needs to grow. Default + * to a medium value. + */ +#define HEART_BEAT_CHUNK 32 + +/* SERVER_IP: For machines with multiple IP addresses, this specifies which + * one to use. This is useful for IP accounting and is necessary to be + * able to do ident lookups on such machines. + * + * example: #define SERVER_IP "194.229.18.27" + */ +#undef SERVER_IP + +/* Some maximum string sizes + */ +#define SMALL_STRING_SIZE 100 +#define LARGE_STRING_SIZE 1000 +#define COMMAND_BUF_SIZE 2000 + +/* Number of levels of nested datastructures allowed -- this limit prevents + * crashes from occuring when saving objects containing variables containing + * recursive datastructures (with circular references). + */ +#define MAX_SAVE_SVALUE_DEPTH 100 + +/* Miscellaneous config options that should probably be in the runtime + * config file. + */ +/* MAX_LOCAL: maximum number of local variables allowed per LPC function */ +#define CFG_MAX_LOCAL_VARIABLES 50 + +#define CFG_EVALUATOR_STACK_SIZE 3000 +#define CFG_COMPILER_STACK_SIZE 600 +#define CFG_MAX_CALL_DEPTH 150 +/* This must be one of 4, 16, 64, 256, 1024, 4096 */ +#define CFG_LIVING_HASH_SIZE 256 + +/* NEXT_MALLOC_DEBUG: define this if using a NeXT and you want to enable + * the malloc_check() and/or malloc_debug() efuns. Run the 'man malloc_debug' + * command on the NeXT to find out what the arguments to malloc_debug(int) + * mean. The malloc_check() efun calls the NeXT NXMallocCheck() system + * call which does a consistency check on malloc's data structures (this + * consistency check is done at each malloc() and free() for certain + * malloc_debug() levels). A non-zero return value indicates there was + * a consistency problem. For those NeXT users wanting a bit more + * performance out of malloc, try defining NEXT_MALLOC_DEBUG and calling the + * malloc_debug(-1) efun (with an arg of -1). This will turn all + * malloc debugging off and call malloc_singlethreaded() which the NeXT + * malloc man page claims can make NeXT system malloc 10% to 15% faster. + * + * [NOTE: This #define has no affect on the driver if not using the + * NeXTSTEP OS.] + * + * Warning: if you use a NeXT and define NEXT_MALLOC_DEBUG, be sure to + * protect the use of the malloc_check() and malloc_debug() efuns + * since setting certain debug levels can cause malloc() and free() + * to become _very_ slow (protect efuns by using simul_efuns and + * valid_override). + * + * [NOTE: malloc_debug(6) is a good compromise between efficiency and + * completeness of malloc debugging (malloc/free will be about half as fast).] + */ +#define NEXT_MALLOC_DEBUG + + +/* GET_CHAR_IS_BUFFERED: Normally get_char() is unbuffered. That is, once + * a character is received for get_char(), anything else is in the input + * stream is immediately thrown away. This can be very undesirable, especially + * if you're calling get_char() again from the handler from the previous call. + * Define this if you want get_char() to be buffered. In this case, the buffer + * will only get flushed if get_char() is not called from the first get_char()'s + * LPC callback handler. + */ +#undef GET_CHAR_IS_BUFFERED + +/* PACKAGE_COMPRESS: Enable MCCP support and compressed save files + SAVE_GZ_EXTENSION: save extension for compressed files + */ +#undef HAVE_ZLIB +#undef PACKAGE_COMPRESS +#define SAVE_GZ_EXTENSION ".o.gz" + +/* CALL_OTHER_TYPE_CHECK: enable type checking for call_other() + * (-> operator on objects) + */ +#undef CALL_OTHER_TYPE_CHECK + +/* CALL_OTHER_WARN, make it warning instead of errors */ +#undef CALL_OTHER_WARN + +/* WARN_TAB: Some versions of the editor built in indent function use + * tabs for indenting. This options turns on a warning message for + * files indented with tabs instead of spaces. + */ +#define WARN_TAB + +/* USE_ICONV: Use iconv to translate input and output from/to the users char + * encoding + */ +#undef USE_ICONV + +/* WOMBLES: don't allow spaces between start/end of array/mapping/functional token chars so ({1,2,3}) still works, but ( { 1 , 2 , 3 } ) doesn't and ({ 1 , 2 , 3 }) does.*/ +#undef WOMBLES + +/* ALLOW_INHERIT_AFTER_FUNCTION: allow inheriting after functions have been defined (this includes prototypes). This caused crashes in v22.2a but it may have been fixed since */ +#undef ALLOW_INHERIT_AFTER_FUNCTION +#undef PACKAGE_DSLIB +#define ED_INDENT_SPACES 4 +#define PROG_REF_TYPE int +#undef PARSE_DEBUG +#define HAS_CONSOLE +#define FLUFFOS +#undef ED_INDENT_CASE +#undef ALLOW_INHERIT_AFTER_GLOBAL_VARIABLES +#undef ANSI_SUBSTITUTE +#define CFG_MAX_GLOBAL_VARIABLES 256 +#undef RECEIVE_ED +#undef PACKAGE_ASYNC +#endif +#undef IPV6 +#undef MALLOC64 +#undef PACKAGE_CRYPTO +#undef PACKAGE_SHA1 diff --git a/fluffos-2.23-ds03/local_options.lima b/fluffos-2.23-ds03/local_options.lima new file mode 100644 index 0000000..a0f6483 --- /dev/null +++ b/fluffos-2.23-ds03/local_options.lima @@ -0,0 +1,751 @@ +#ifndef _OPTIONS_H_ +#define _OPTIONS_H_ +#endif + +#undef NO_SNOOP +#define SUPPRESS_ARGUMENT_WARNINGS +#undef FD6_PORT +#define REF_RESERVED_WORD +#undef FD6_KIND +#define CUSTOM_CRYPT +#undef SERVER_IP +#undef SENSIBLE_MODIFIERS +#undef USE_32BIT_ADDRESSES + +/* +** local_options for LIMA +*/ + +/**************************************************************************** + * EVERY time you change ANYTHING in this file, RECOMPILE from scratch. * + * (type "make clean" then "make" on a UNIX system) Failure to do so may * + * cause the driver to behave oddly. * + ****************************************************************************/ + +/* NOTES: + * Many of the configurable options are now set via the configuration file + * that is specified as the first argument to the driver. + * See port.h for those #defines related to portability (compatibility) if + * you have problems compiling on your system. + * Removing an efun from func_spec.c usually removes most, if not all, + * of the code associated with it. + */ + +/**************************************************************************** + * MALLOC * + * -------- * + * for performance reasons, LP drivers have a variety of memory allocation * + * packages. If you don't care, use the default one on your system: * + * #define SYSMALLOC, #undef the others. * + ****************************************************************************/ + +/* You must choose exactly one of these malloc packages: + * ~~~~ + * SYSMALLOC: + * * Built-in system malloc. + * * No statistics. + * * SYSMALLOC incurs no additional CPU or memory overhead. + * + * SMALLOC: + * * Satoria's smalloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than most system mallocs with modest ammount of memory overhead. + * * Can fall back onto system malloc if sbrk() not ok. + * + * BSDMALLOC: + * * BSD (Berkeley Software Distributions) malloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than SMALLOC but more memory overhead. + * * Requires sbrk(). + */ +#define SYSMALLOC +#undef SMALLOC +#undef BSDMALLOC + +/* You may optionally choose one (or none) of these malloc wrappers. These + * can be used in conjunction with any of the above malloc packages. + * + * WRAPPEDMALLOC: + * * Limited statistics. + * * Limited additional cpu overhead and no additional memory overhead. + * + * DEBUGMALLOC: + * * Statistics on precisely how much memory has been malloc'd (as well + * as the stats provided by WRAPPEDMALLOC). + * * Incurs a fair amount of overhead (both memory and CPU) + */ +#undef WRAPPEDMALLOC +#undef DEBUGMALLOC + +/* The following add certain bells and whistles to malloc: */ + +/* + * SBRK_OK: do not define this unless SMALLOC is chosen above. + * Defining this causes smalloc to use the low level memory allocation + * routines, and to act as a malloc replacement. Conversely, undef'ing + * SBRK_OK causes smalloc to act as a wrapper for the system malloc + * routines. + * + * Note: + * NeXTStep 3.x users should always #undef SBRK_OK. + */ +#undef SBRK_OK + +/* DO_MSTATS: do not define this unless BSDMALLOC or SMALLOC is chosen above. + * Defining this causes those replacement mallocs to keep statistics that + * the malloc_status() efun will print out (including total memory + * allocated/used). + */ +#undef DO_MSTATS + +/* DEBUGMALLOC_EXTENSIONS: defining this (in addition to DEBUGMALLOC) enables + * the set_malloc_mask(int) and debugmalloc(string,int) efuns. These two + * efuns basically allow you to cause certain malloc's and free's (with tags + * selected by a specified mask) to print debug information (addr, tag, + * description, size) to stdio (in the shell that invoked the driver) or to a + * file. Not defining this does reduce the overhead of DEBUGMALLOC from 16 + * bytes per malloc down to 8. This macro has no effect if DEBUGMALLOC isn't + * defined. + */ +#undef DEBUGMALLOC_EXTENSIONS + +/* CHECK_MEMORY: defining this (in addition to DEBUGMALLOC and + * DEBUGMALLOC_EXTENSIONS) causes the driver to check for memory + * corruption due to writing before the start or end of a block. This + * also adds the check_memory() efun. Takes a considerable ammount + * more memory. Mainly for debugging. + */ +#undef CHECK_MEMORY + +/**************************************************************************** + * COMPATIBILITY * + * --------------- * + * The MudOS driver has evolved quite a bit over the years. These defines * + * are mainly to preserve old behavior in case people didn't want to * + * rewrite the relevant portions of their code. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* HAS_STATUS_TYPE: old MudOS drivers had a 'status' type which was + * identical to the 'int' type. Define this to bring it back. + */ +#undef HAS_STATUS_TYPE + +/* explode(): + * + * The old behavior (#undef both of the below) strips any number of + * delimiters at the start of the string, and one at the end. So + * explode("..x.y..z..", ".") gives ({ "x", "y", "", "z", "" }) + * + * SANE_EXPLODE_STRING strips off at most one leading delimiter, and + * still strips off one at the end, so the example above gives + * ({ "", "x", "y", "", "z", "" }). + * + * REVERSIBLE_EXPLODE_STRING overrides SANE_EXPLODE_STRING, and makes + * it so that implode(explode(x, y), y) is always x; i.e. no delimiters + * are every stripped. So the example above gives + * ({ "", "", "x", "y", "", "z", "", "" }). + */ +#define SANE_EXPLODE_STRING +#undef REVERSIBLE_EXPLODE_STRING + +/* CAST_CALL_OTHERS: define this if you want to require casting of call_other's; + * this was the default behavior of the driver prior to this addition. + */ +#undef CAST_CALL_OTHERS + +/* NONINTERACTIVE_STDERR_WRITE: if defined, all writes/tells/etc to + * noninteractive objects will be written to stderr prefixed with a ']' + * (old behavior). + */ +#define NONINTERACTIVE_STDERR_WRITE + +/* NO_LIGHT: define this to disable the set_light() and driver maintenance + * of light levels in objects. You can simulate it via LPC if you want... + */ +#define NO_LIGHT + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + process_input() then becomes the only way to deal with player input. */ +#define NO_ADD_ACTION + +/* NO_ENVIRONMENT: define this to remove the handling of object containment + relationships by the driver */ +#undef NO_ENVIRONMENT + +/* NO_WIZARDS: for historical reasons, MudOS used to keep track of who + is and isn't a wizard. Defining this removes that completely. + If this is defined, the wizardp() and related efuns don't exist */ +#define NO_WIZARDS + +/* OLD_TYPE_BEHAVIOR: reintroduces a bug in type-checking that effectively + * renders compile time type checking useless. For backwards compatibility. + */ +#undef OLD_TYPE_BEHAVIOR + +/* OLD_RANGE_BEHAVIOR: define this if you want negative indexes in string + * or buffer range values (not lvalue, i.e. x[-2..-1]; for e.g. not + * x[-2..-1] = foo, the latter is always illegal) to mean counting from the + * end + */ +#undef OLD_RANGE_BEHAVIOR + +/* OLD_ED: ed() efun backwards compatible with the old version. The new + * version requires/allows a mudlib front end. + */ +#undef OLD_ED + +/**************************************************************************** + * MISCELLANEOUS * + * --------------- * + * Various options that affect the way the driver behaves. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* + * Some minor tweaks that make it a bit easier to run code designed to run + * on LPmud 3.2/3.2.1. Currently has the following effects: + * + * . m_indices() and m_values() are synonyms for keys() and values(), + * respectively + * . map_delete() returns it's first argument + * . inherit_list() means deep_inherit_list(), not shallow_inherit_list() + * . heart_beat_info() is a synonym for heart_beats() + */ +#undef COMPAT_32 + +/* + * Keep statistics about allocated strings, etc. Which can be veiwed with + * the mud_status() efun. If this is off, mud_status() and memory_info() + * ignore allocated strings, but string operations run faster. + */ +#undef STRING_STATS + +/* LOG_CATCHES: define this to cause errors that are catch()'d to be + * sent to the debug log anyway. + * + * On by default, because newer libs use catch() alot, and it's confusing + * if the errors don't show up in the logs. + */ +#define LOG_CATCHES + +/* ARGUMENTS_IN_TRACEBACK: prints out function call arguments in error + * tracebacks, to aid in debugging. Note: it prints the values of + * the arguments at the time of the error, not when the function + * was called. It looks like this: + * + * Failed to load file: read_buffer + * program: command/update.c, object: command/update line 15 + * ' commandHook' in ' clone/user.c' (' clone/user#1')line 72 + * arguments were ("/read_buffer.c") + * ' main' in ' command/update.c' (' command/update')line 15 + * arguments were ("/read_buffer.c") + * + * The only down side is some people like their logs shorter + */ +#define ARGUMENTS_IN_TRACEBACK + +/* LOCALS_IN_TRACEBACK: similar to ARGUMENTS_IN_TRACEBACK, but for local + * variables. The output looks more or less like: + * + * locals: 1, "local_value" + * + * Same as above. Tends to produce even longer logs, but very useful for + * tracking errors. + */ +#define LOCALS_IN_TRACEBACK + +/* MUDLIB_ERROR_HANDLER: If you define this, the driver doesn't do any + * handling of runtime errors, other than to turn the heartbeats of + * objects off. Information about the error is passed in a mapping + * to the error_handler() function in the master object. Whatever is + * returned is put in the debug.log. + * + * A good mudlib error handler is one of the best tools for tracking down + * errors. Unfortunately, you need to have one. Check the testsuite or + * other libs for an example. + */ +#define MUDLIB_ERROR_HANDLER + +/* CONFIG_FILE_DIR specifies a directory in which the driver will search for + * config files by default. If you don't wish to use this define, you may + * always specify a full path to the config file when starting the driver. + */ +#ifndef LATTICE +#define CONFIG_FILE_DIR "/usr/local/driver" +#else +#define CONFIG_FILE_DIR "etc:" +#endif + +/* DEFAULT_PRAGMAS: This should be a sum of pragmas you want to always + * be on, i.e. + * + * #define DEFAULT_PRAGMAS PRAGMA_STRICT_TYPES + PRAGMA_SAVE_TYPES + * + * will make every LPC file behave as if it had the lines: + * #pragma strict_types + * #pragma save_types + * + * for no default pragmas: + * #define DEFAULT_PRAGMAS 0 + * + * If you don't know what these are, 0 is a good choice. + * + * Supported pragmas: + * PRAGMA_STRICT_TYPES: enforces strict type checking + * PRAGMA_WARNINGS: issues warnings about various dangerous things in + * your code + * PRAGMA_SAVE_TYPES: save the types of function arguments for checking + * calls to functions in this object by objects that + * inherit it. + * PRAGMA_SAVE_BINARY: save a compiled binary version of this file for + * faster loading next time it is needed. + * PRAGMA_OPTIMIZE: make a second pass over the generated code to + * optimize it further. currently does jump threading. + * PRAGMA_ERROR_CONTEXT:include some text telling where on the line a + * compilation error occured. + */ +#define DEFAULT_PRAGMAS ( PRAGMA_WARNINGS + \ + PRAGMA_ERROR_CONTEXT ) + +/* NO_RESETS: completely disable the periodic calling of reset() */ +#undef NO_RESETS + +/* LAZY_RESETS: if this is defined, an object will only have reset() + * called in it when it is touched via call_other() or move_object() + * (assuming enough time has passed since the last reset). If LAZY_RESETS + * is #undef'd, then reset() will be called as always (which guaranteed that + * reset would always be called at least once). The advantage of lazy + * resets is that reset doesn't get called in an object that is touched + * once and never again (which can save memory since some objects won't get + * reloaded that otherwise would). + */ +#undef LAZY_RESETS + +/* SAVE_EXTENSION: defines the file extension used by save_object(). + * and restore_object(). Some sysadmins run scripts that periodically + * scan for and remove files ending in .o (but many mudlibs are already + * set up to use .o thus we leave .o as the default). + */ +#define SAVE_EXTENSION ".o" + +/* NO_ANSI: define if you wish to disallow users from typing in commands that + * contain ANSI escape sequences. Defining NO_ANSI causes all escapes + * (ASCII 27) to be replaced with a space ' ' before the string is passed + * to the action routines added with add_action. + * + * STRIP_BEFORE_PROCESS_INPUT allows the location where the stripping is + * done to be controlled. If it is defined, then process_input() doesn't + * see ANSI characters either; if it is undefined ESC chars can be processed + * by process_input(), but are stripped before add_actions are called. + * Note that if NO_ADD_ACTION is defined, then #define NO_ANSI without + * #define STRIP_BEFORE_PROCESS_INPUT is the same as #undef NO_ANSI. + * + * If you anticipate problems with users intentionally typing in ANSI codes + * to make your terminal flash, etc define this. + */ +#define NO_ANSI +#define STRIP_BEFORE_PROCESS_INPUT + +/* OPCPROF: define this if you wish to enable OPC profiling. Allows a dump + * of the # of times each efun is invoked (via the opcprof() efun). + */ +#undef OPCPROF + +/* OPCPROF_2D: define this if you wish to enable 2-D OPC profiling. Allows a + * dump of the # of times each *pair* of eoperators is invoked. + * + * You can't use this and OPCPROF at the same time. + */ +#undef OPCPROF_2D + +/* TRAP_CRASHES: define this if you want MudOS to call crash() in master.c + * and then shutdown when signals are received that would normally crash the + * driver. + */ +#undef TRAP_CRASHES + +/* DROP_CORE: define this if you want the driver to attempt to create + * a core file when it crashes via the crash_MudOS() function. This + * define only has an affect if -DDEBUG isn't defined in the makefile + * (except for the SIGINT and SIGTERM signals which are always trapped). + * + * [NOTE: keep this undefined for now since it seems to hang some machines + * upon crashing (some DECstations apparently). If you want to get a core + * file, undef'ing TRAP_CRASHES should work.] + */ +#define DROP_CORE + +/* THIS_PLAYER_IN_CALL_OUT: define this if you wish this_player() to be + * usable from within call_out() callbacks. + */ +#define THIS_PLAYER_IN_CALL_OUT + +/* CALLOUT_HANDLES: If this is defined, call_out() returns an integer, which + * can be passed to remove_call_out() or find_call_out(). Removing call_outs + * by name is still allowed, but is significantly less efficient, and also + * doesn't work for function pointers. This option adds 4 bytes overhead + * per callout to keep track of the handle. + */ +#define CALLOUT_HANDLES + +/* FLUSH_OUTPUT_IMMEDIATELY: Causes output to be written to sockets + * immediately after being generated. Useful for debugging. + */ +#undef FLUSH_OUTPUT_IMMEDIATELY + +/* PRIVS: define this if you want object privledges. Your mudlib must + * explicitly make use of this functionality to be useful. Defining this + * this will increase the size of the object structure by 4 bytes (8 bytes + * on the DEC Alpha) and will add a new master apply during object creation + * to "privs_file". In general, priveleges can be used to increase the + * granularity of security beyond the current root uid mechanism. + * + * [NOTE: for those who'd rather do such things at the mudlib level, look at + * the inherits() efun and the 'valid_object' apply to master.] + */ +#undef PRIVS + +/* INTERACTIVE_CATCH_TELL: define this if you want catch_tell called on + * interactives as well as NPCs. If this is defined, user.c will need a + * catch_tell(msg) method that calls receive(msg); +*/ +#undef INTERACTIVE_CATCH_TELL + +/* RESTRICTED_ED: define this if you want restricted ed mode enabled. + */ +#define RESTRICTED_ED + +/* NO_SHADOWS: define this if you want to disable shadows in your driver. + */ +#undef NO_SHADOWS + +/* SNOOP_SHADOWED: define this if you want snoop to report what is + * sent to the player even in the event that the player's catch_tell() is + * shadowed and the player may not be seeing what is being sent. Messages + * of this sort will be prefixed with $$. + */ +#undef SNOOP_SHADOWED + +/* RECEIVE_SNOOP: define this if you want snoop text to be sent to + * the receive_snoop() function in the snooper object (instead of being + * sent directly via add_message()). This is useful if you want to + * build a smart client that does something different with snoop messages. + */ +#define RECEIVE_SNOOP + +/* PROFILE_FUNCTIONS: define this to be able to measure the CPU time used by + * all of the user-defined functions in each LPC object. Note: defining + * this adds three long ints (12 bytes on 32-bit machines) to the function + * header structs. Also note that the resolution of the getrusage() timer + * may not be high enough on some machines to give non-zero execution + * times to very small (fast) functions. In particular if the clock + * resolution is 1/60 of a second, then any time less than approxmately 15k + * microseconds will resolve to zero (0). + */ +#undef PROFILE_FUNCTIONS + +/* NO_BUFFER_TYPE: if this is #define'd then LPC code using the 'buffer' + * type won't be allowed to compile (since the 'buffer' type won't be + * recognized by the lexer. + */ +#undef NO_BUFFER_TYPE + +/* BINARIES: define this to enable the 'save_binary' pragma. + * This pragma, when set in a program, will cause it to save a + * binary image when loaded, so that subsequent loadings will + * be much faster. The binaries are saved in the directory + * specified in the configuration file. The binaries will not + * load if the LPC source or any of the inherited or included + * files are out of date, in which case the file is compiled + * normally (and may save a new binary). + * + * In order to save the binary, valid_save_binary() is called + * in master.c, and is passed the name of the source file. If + * this returns a non-zero value, the binary is allowed to be + * saved. Allowing any file by any wizard to be saved as a + * binary is convenient, but may take up a lot of disk space. + */ +#define BINARIES + +/* ARRAY_RESERVED_WORD: If this is defined then the word 'array' can + * be used to define arrays, as in: + * + * int array x = ({ .... }); + * + * A side effect is that array cannot be a variable or function name. + */ +#define ARRAY_RESERVED_WORD + +/**************************************************************************** + * PACKAGES * + * -------- * + * Defining some/all of the following add certain efuns, and sometimes * + * add/remove code from the driver. * + * * + * if PACKAGE_XYZZY is defined here, then the code in packages/xyzzy.c * + * and the efuns in packages/xyzzy_spec.c will be added to the driver. * + ****************************************************************************/ + +/* various miscellaneous efuns */ +#define PACKAGE_CONTRIB + +/* efuns that are only of use to those that know something about driver + internals */ +#define PACKAGE_DEVELOP + +/* PACKAGE_MATH: determines whether or not the math efuns (for floats) are + included. + */ +#undef PACKAGE_MATH + +/* PACKAGE_MATRIX: determines whether or not the 3d graphics efuns (for floats) + * are included - see packages/matrix.spec for a list. + */ +#undef PACKAGE_MATRIX + +/* PACKAGE_MUDLIB_STATS: define this to enable domain and author stats + * maintenance by the driver. These mudlib stats are more domain + * based than user based, and replaces the traditional wiz_list stats. + */ +#undef PACKAGE_MUDLIB_STATS + +/* PACKAGE_SOCKETS: define this to enable the socket efunctions. This + * causes HAS_SOCKETS to be defined for all LPC objects. + */ +#define PACKAGE_SOCKETS + +/* PACKAGE_PARSER: Natural language parsing efuns for interactive fiction + * type applications + */ +#define PACKAGE_PARSER + +/* PACKAGE_EXTERNAL: Allows the driver to exec() commands specified in the + * config file. + */ +#undef PACKAGE_EXTERNAL + +/* PACKAGE_DB: efuns for external database access */ +#undef PACKAGE_DB + +/* If PACKAGE_DB is defined above, you must pick ONE of the following supported + * databases + */ +#ifdef PACKAGE_DB +#define MSQL /* MiniSQL, it's small; it's free */ +#endif + +/**************************************************************************** + * UID PACKAGE * + * ----------- * + * UIDS are the basis for some mudlib security systems. Basically, they're * + * preserved for backwards compatibility, as several ways of breaking * + * almost any system which relies on them are known. (No, it's not a flaw * + * of uids; only that b/c of the ease with which LPC objects can call * + * each other, it's far to easy to leave holes) * + * * + * If you don't care about security, the first option is probably what you * + * want. * + ****************************************************************************/ + +/* + * PACKAGE_UIDS: define this if you want a driver that does use uids. + * + */ +#undef PACKAGE_UIDS + +/* AUTO_SETEUID: when an object is created it's euid is automatically set to + * the equivalent of seteuid(getuid(this_object())). undef AUTO_SETEUID + * if you would rather have the euid of the created object be set to 0. + */ +#undef AUTO_SETEUID + +/* AUTO_TRUST_BACKBONE: define this if you want objects with the backbone + * uid to automatically be trusted and to have their euid set to the uid of + * the object that forced the object's creation. + */ +#define AUTO_TRUST_BACKBONE + +/************************************************************************* + * FOR EXPERIENCED USERS * + * ----------------------- * + * Most of these options will probably be of no interest to many users. * + *************************************************************************/ + +/* HEARTBEAT_INTERVAL: define heartbeat interval in microseconds (us). + * 1,000,000 us = 1 second. The value of this macro specifies + * the frequency with which the heart_beat method will be called in + * those LPC objects which have called set_heart_beat(1). + * + * [NOTE: if ualarm() isn't available, alarm() is used instead. Since + * alarm() requires its argument in units of a second, we map 1 - 1,000,000 us + * to an actual interval of one (1) second and 1,000,001 - 2,000,000 maps to + * an actual interval of two (2) seconds, etc.] + */ +#define HEARTBEAT_INTERVAL 2 + +/* + * CALLOUT_CYCLE_SIZE: This is the number of slots in the call_out list. + * It should be approximately the average number of active call_outs, or + * a few times smaller. It should also be a power of 2, and also be relatively + * prime to any common call_out lengths. If all this is too confusing, 32 + * isn't a bad number :-) + */ +#define CALLOUT_CYCLE_SIZE 32 + +/* LARGEST_PRINTABLE_STRING: defines the size of the vsprintf() buffer in + * comm.c's add_message(). Instead of blindly making this value larger, + * mudlib should be coded to not send huge strings to users. + */ +#define LARGEST_PRINTABLE_STRING 8192 + +/* MESSAGE_BUFFER_SIZE: determines the size of the buffer for output that + * is sent to users. + */ +#define MESSAGE_BUFFER_SIZE 4096 + +/* APPLY_CACHE_BITS: defines the number of bits to use in the call_other cache + * (in interpret.c). Somewhere between six (6) and ten (10) is probably + * sufficient for small muds. + */ +#define APPLY_CACHE_BITS 11 + +/* CACHE_STATS: define this if you want call_other (apply_low) cache + * statistics. Causes HAS_CACHE_STATS to be defined in all LPC objects. + */ +#define CACHE_STATS + +/* TRACE: define this to enable the trace() and traceprefix() efuns. + * (keeping this undefined will cause the driver to run faster). + */ +#undef TRACE + +/* LPC_TO_C: define this to enable LPC->C compilation. + * + * [NOTE: BINARIES must also be defined for LPC->C to work. Actually + * using binaries is not required, though.] + */ +#undef LPC_TO_C + +/* RUNTIME_LOADING: On systems which support it, it allows LPC->C compilation + * 'on the fly' without having to recompile the driver. + * + * Note: This currently only works on machines that have the dlopen() system + * call. SunOS and IRIX do, as do a number of others. AIX and Ultrix don't. + * Linux does if you are using ELF. + */ +#undef RUNTIME_LOADING + +/* TRACE_CODE: define this to enable code tracing (the driver will print + * out the previous lines of code to an error) eval_instruction() runs about + * twice as fast when this is not defined (for the most common eoperators). + */ +#undef TRACE_CODE + +/* HEART_BEAT_CHUNK: The number of heart_beat chunks allocated at a time. + * A large number wastes memory as some will be sitting around unused, while + * a small one wastes more CPU reallocating when it needs to grow. Default + * to a middlish value. + */ +#define HEART_BEAT_CHUNK 32 + +/* Some maximum string sizes + */ +#define SMALL_STRING_SIZE 100 +#define LARGE_STRING_SIZE 1000 +#define COMMAND_BUF_SIZE 2000 + +/* Number of levels of nested datastructures allowed -- this limit prevents + * crashes from occuring when saving objects containing variables containing + * recursive datastructures (with circular references). + */ +#define MAX_SAVE_SVALUE_DEPTH 25 + +/* Miscellaneous config options that should probably be in the runtime + * config file. + */ +/* MAX_LOCAL: maximum number of local variables allowed per LPC function */ +#define CFG_MAX_LOCAL_VARIABLES 25 + +#define CFG_EVALUATOR_STACK_SIZE 1000 +#define CFG_MAX_CALL_DEPTH 100 +/* This must be one of 4, 16, 64, 256, 1024, 4096 */ +#define CFG_LIVING_HASH_SIZE 256 + +/* NEXT_MALLOC_DEBUG: define this if using a NeXT and you want to enable + * the malloc_check() and/or malloc_debug() efuns. Run the 'man malloc_debug' + * command on the NeXT to find out what the arguments to malloc_debug(int) + * mean. The malloc_check() efun calls the NeXT NXMallocCheck() system + * call which does a consistency check on malloc's data structures (this + * consistency check is done at each malloc() and free() for certain + * malloc_debug() levels). A non-zero return value indicates there was + * a consistency problem. For those NeXT users wanting a bit more + * performance out of malloc, try defining NEXT_MALLOC_DEBUG and calling the + * malloc_debug(-1) efun (with an arg of -1). This will turn all + * malloc debugging off and call malloc_singlethreaded() which the NeXT + * malloc man page claims can make NeXT system malloc 10% to 15% faster. + * + * [NOTE: This #define has no affect on the driver if not using the + * NeXTSTEP OS.] + * + * Warning: if you use a NeXT and define NEXT_MALLOC_DEBUG, be sure to + * protect the use of the malloc_check() and malloc_debug() efuns + * since setting certain debug levels can cause malloc() and free() + * to become _very_ slow (protect efuns by using simul_efuns and + * valid_override). + * + * [NOTE: malloc_debug(6) is a good compromise between efficiency and + * completeness of malloc debugging (malloc/free will be about half as fast).] + */ +#define NEXT_MALLOC_DEBUG + +#undef ARRAY_STATS +#undef COMPRESS_FUNCTION_TABLES + +/* GET_CHAR_IS_BUFFERED: Normally get_char() is unbuffered. That is, once + * a character is received for get_char(), anything else is in the input + * stream is immediately thrown away. This can be very undesirable, especially + * if you're calling get_char() again from the handler from the previous call. + * Define this if you want get_char() to be buffered. In this case, the buffer + * will only get flushed if get_char() is not called from the first get_char()'s + * LPC callback handler. + */ +#undef GET_CHAR_IS_BUFFERED + +#undef HAVE_ZLIB +#undef WOMBLES +#undef PACKAGE_COMPRESS +#undef PACKAGE_DWLIB +#undef CALL_OTHER_WARN +#undef CALL_OTHER_TYPE_CHECK +#define NUM_EXTERNAL_CMDS 1 +#undef MMALLOC +#undef WARN_TAB +#undef USE_ICONV +#define SAVE_GZ_EXTENSION ".o.gz" +#define COMMAND_BUF_SIZE 2000 +#define CFG_COMPILER_STACK_SIZE 600000 +#undef SERVER_IP +#define ALLOW_INHERIT_AFTER_FUNCTION +#define ALLOW_INHERIT_AFTER_GLOBAL_VARIABLES +#define PARSE_DEBUG +#define FLUFFOS +#undef PACKAGE_DSLIB +#define ED_INDENT_SPACES 4 +#define PROG_REF_TYPE int +#define HAS_CONSOLE +#undef ED_INDENT_CASE +#undef ANSI_SUBSTITUTE +#define CFG_MAX_GLOBAL_VARIABLES 256 +#undef RECEIVE_ED +#undef PACKAGE_ASYNC +#undef IPV6 +#undef MALLOC64 +#undef PACKAGE_CRYPTO +#undef PACKAGE_SHA1 diff --git a/fluffos-2.23-ds03/local_options.lpuni b/fluffos-2.23-ds03/local_options.lpuni new file mode 100644 index 0000000..4e64c27 --- /dev/null +++ b/fluffos-2.23-ds03/local_options.lpuni @@ -0,0 +1,893 @@ +/* + * options.h: defines for the compile-time configuration of the MudOS driver + */ + +#ifndef _OPTIONS_H_ +#define _OPTIONS_H_ + +/* + * YOU PROBABLY DO NOT WANT TO MODIFY THIS FILE. + * + * Do 'cp options.h local_options' and edit that instead. local_options, + * if it exists, overrides this file. + * + * The advantage is that when you upgrade to a newer MudOS driver, you can + * simply copy your local_options file into the src directory. The build + * process will warn you if new options have been added that you should + * choose settings for. + */ + +/**************************************************************************** + * EVERY time you change ANYTHING in this file, RECOMPILE from scratch. * + * (type "make clean" then "make" on a UNIX system) Failure to do so may * + * cause the driver to behave oddly. * + ****************************************************************************/ + +/* NOTES: + * Many of the configurable options are now set via the configuration file + * that is specified as the first argument to the driver. + * See port.h for those #defines related to portability (compatibility) if + * you have problems compiling on your system. + * Removing an efun from func_spec.c usually removes most, if not all, + * of the code associated with it. + * Note that anything defined in this file is also visible to LPC files + * surrounded by __. So #define FOO in this file defines __FOO__ for + * all LPC files. This allows code like: + * + * #ifdef __SENSIBLE_MODIFIERS__ + * ... + */ + +/**************************************************************************** + * MALLOC * + * -------- * + * For performance reasons, LP drivers have a variety of memory allocation * + * packages. If you don't care, use the default one on your system: * + * #define SYSMALLOC, #undef the others. * + ****************************************************************************/ + +/* You must choose exactly one of these malloc packages: + * ~~~~ + * SYSMALLOC: + * * Built-in system malloc. + * * No statistics. + * * SYSMALLOC incurs no additional CPU or memory overhead. + * + * SMALLOC: + * * Satoria's smalloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than most system mallocs with modest ammount of memory overhead. + * * Can fall back onto system malloc if sbrk() not ok. + * + * BSDMALLOC: + * * BSD (Berkeley Software Distributions) malloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than SMALLOC but more memory overhead. + * * Requires sbrk(). + */ +#define SYSMALLOC +#undef SMALLOC +#undef BSDMALLOC +#undef MMALLOC + +/* You may optionally choose one (or none) of these malloc wrappers. These + * can be used in conjunction with any of the above malloc packages. + * + * WRAPPEDMALLOC: + * * Limited statistics. + * * Limited additional cpu overhead and no additional memory overhead. + * + * DEBUGMALLOC: + * * Statistics on precisely how much memory has been malloc'd (as well + * as the stats provided by WRAPPEDMALLOC). + * * Incurs a fair amount of overhead (both memory and CPU) + */ +#undef WRAPPEDMALLOC +#undef DEBUGMALLOC + +/* The following add certain bells and whistles to malloc: */ + +/* + * SBRK_OK: do not define this unless SMALLOC is chosen above. + * Defining this causes smalloc to use the low level memory allocation + * routines, and to act as a malloc replacement. Conversely, undef'ing + * SBRK_OK causes smalloc to act as a wrapper for the system malloc + * routines. + * + * Note: + * NeXTStep 3.x users should always #undef SBRK_OK. + */ +#undef SBRK_OK + +/* DO_MSTATS: do not define this unless BSDMALLOC or SMALLOC is chosen above. + * Defining this causes those replacement mallocs to keep statistics that + * the malloc_status() efun will print out (including total memory + * allocated/used). + */ +#undef DO_MSTATS + +/* DEBUGMALLOC_EXTENSIONS: defining this (in addition to DEBUGMALLOC) enables + * the set_malloc_mask(int) and debugmalloc(string,int) efuns. These two + * efuns basically allow you to cause certain malloc's and free's (with tags + * selected by a specified mask) to print debug information (addr, tag, + * description, size) to stdio (in the shell that invoked the driver) or to a + * file. Not defining this does reduce the overhead of DEBUGMALLOC from 16 + * bytes per malloc down to 8. This macro has no effect if DEBUGMALLOC isn't + * defined. + */ +#undef DEBUGMALLOC_EXTENSIONS + +/* CHECK_MEMORY: defining this (in addition to DEBUGMALLOC and + * DEBUGMALLOC_EXTENSIONS) causes the driver to check for memory + * corruption due to writing before the start or end of a block. This + * also adds the check_memory() efun. Takes a considerable ammount + * more memory. Mainly for debugging. + */ +#undef CHECK_MEMORY + +/**************************************************************************** + * COMPATIBILITY * + * --------------- * + * The MudOS driver has evolved quite a bit over the years. These defines * + * are mainly to preserve old behavior in case people didn't want to * + * rewrite the relevant portions of their code. * + * * + * In most cases, code which needs these defines should be rewritten when * + * possible. The 'Compat status' field is designed to give an idea how * + * likely it is that support for that option will be removed in the near * + * future. Certain options are fairly easy to work around, and double * + * the size of the associated code, as well as the maintenance workload, * + * and can make the code significantly more complex or harder to read, so * + * supporting them indefinitely is impractical. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* HAS_STATUS_TYPE: old MudOS drivers had a 'status' type which was + * identical to the 'int' type. Define this to bring it back. + * + * Compat status: very archaic, but easy to support. + */ +#undef HAS_STATUS_TYPE + +/* explode(): + * + * The old behavior (#undef both of the below) strips any number of + * delimiters at the start of the string, and one at the end. So + * explode("..x.y..z..", ".") gives ({ "x", "y", "", "z", "" }) + * + * SANE_EXPLODE_STRING strips off at most one leading delimiter, and + * still strips off one at the end, so the example above gives + * ({ "", "x", "y", "", "z", "" }). + * + * REVERSIBLE_EXPLODE_STRING overrides SANE_EXPLODE_STRING, and makes + * it so that implode(explode(x, y), y) is always x; i.e. no delimiters + * are ever stripped. So the example above gives + * ({ "", "", "x", "y", "", "z", "", "" }). + */ +#undef SANE_EXPLODE_STRING +#undef REVERSIBLE_EXPLODE_STRING + +/* CAST_CALL_OTHERS: define this if you want to require casting of call_other's; + * this was the default behavior of the driver prior to this addition. + * + * Compat status: code that requires it doesn't break, and it promotes + * sloppy coding with no benefits. + */ +#undef CAST_CALL_OTHERS + +/* NONINTERACTIVE_STDERR_WRITE: if defined, all writes/tells/etc to + * noninteractive objects will be written to stderr prefixed with a ']' + * (old behavior). + * + * Compat status: Easy to support, and also on the "It's a bug! No, it's + * a feature!" religious war list. + */ +#undef NONINTERACTIVE_STDERR_WRITE + +/* NO_LIGHT: define this to disable the set_light() and driver maintenance + * of light levels in objects. You can simulate it via LPC if you want... + * + * Compat status: Very dated, easy to simulate, and gross. + */ +#define NO_LIGHT + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + * process_input() then becomes the only way to deal with player input. + * + * Compat status: next to impossible to simulate, hard to replace, and + * very, very widely used. + */ +#undef NO_ADD_ACTION + +/* NO_SNOOP: disables the snoop() efun and all related functionality. + */ +#undef NO_SNOOP + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + process_input() then becomes the only way to deal with player input. */ + +/* NO_ENVIRONMENT: define this to remove the handling of object containment + * relationships by the driver + * + * Compat status: hard to simulate efficiently, and very widely used. + */ +#undef NO_ENVIRONMENT + +/* NO_WIZARDS: for historical reasons, MudOS used to keep track of who + * is and isn't a wizard. Defining this removes that completely. + * If this is defined, the wizardp() and related efuns don't exist. + * + * Also note that if it is not defined, then non-wizards are always put + * in restricted mode when ed() is used, regardless of the setting of + * the restrict parameter. + * + * Compat status: easy to simulate and dated. + */ +#define NO_WIZARDS + +/* OLD_TYPE_BEHAVIOR: reintroduces a bug in type-checking that effectively + * renders compile time type checking useless. For backwards compatibility. + * + * Compat status: dealing with all the resulting compile errors can be + * a huge pain even if they are correct, and the impact on the code is + * small. + */ +#undef OLD_TYPE_BEHAVIOR + +/* OLD_RANGE_BEHAVIOR: define this if you want negative indexes in string + * or buffer range values (not lvalue, i.e. x[-2..-1]; for e.g. not + * x[-2..-1] = foo, the latter is always illegal) to mean counting from the + * end + * + * Compat status: Not horribly difficult to replace reliance on this, but not + * trivial, and cannot be simulated. + */ +#undef OLD_RANGE_BEHAVIOR + +/* OLD_ED: ed() efun backwards compatible with the old version. The new + * version requires/allows a mudlib front end. + * + * Compat status: Easily simulated. + */ +#define OLD_ED + +/* SENSIBLE_MODIFIERS: + * Turning this on changes a few things, which may break old code: + * + * (1) 'static' is not recognized; either 'nosave' or 'protected' must + * be used instead. + * (2) The old meaning of 'public' is no longer allowed. Explicit + * functions must be defined at each level to allow access to + * privately inherited functions. + * (3) 'public' now means the default visibility. Previously there was + * no keyword that meant this (before you ask, 'public' meant something + * else, and if you don't know that, you probably don't have any reason + * to care about the old meaning). + */ +#undef SENSIBLE_MODIFIERS + +/**************************************************************************** + * MISCELLANEOUS * + * --------------- * + * Various options that affect the way the driver behaves. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* + * Define this in order to use Fermat@Equilibria's MD5 based crypt() instead + * of the operating system's. It has the advantage of giving the same value + * on all architectures, and being stronger than the standard UNIX crypt(). + */ +#define CUSTOM_CRYPT + +/* + * Some minor tweaks that make it a bit easier to run code designed to run + * on LPmud 3.2/3.2.1. Currently has the following effects: + * + * . m_indices() and m_values() are synonyms for keys() and values(), + * respectively + * . map_delete() returns it's first argument + * . inherit_list() means deep_inherit_list(), not shallow_inherit_list() + * . heart_beat_info() is a synonym for heart_beats() + */ +#undef COMPAT_32 + +/* + * Keep statistics about allocated strings, etc. Which can be viewed with + * the mud_status() efun. If this is off, mud_status() and memory_info() + * ignore allocated strings, but string operations run faster. + */ +#define STRING_STATS + +/* + * Similarly for arrays ... + */ +#define ARRAY_STATS + +/* LOG_CATCHES: define this to cause errors that are catch()'d to be + * sent to the debug log anyway. + * + * On by default, because newer libs use catch() a lot, and it's confusing + * if the errors don't show up in the logs. + */ +#define LOG_CATCHES + +/* ARGUMENTS_IN_TRACEBACK: prints out function call arguments in error + * tracebacks, to aid in debugging. Note: it prints the values of + * the arguments at the time of the error, not when the function + * was called. It looks like this: + * + * Failed to load file: read_buffer + * program: command/update.c, object: command/update line 15 + * ' commandHook' in ' clone/user.c' (' clone/user#1')line 72 + * arguments were ("/read_buffer.c") + * ' main' in ' command/update.c' (' command/update')line 15 + * arguments were ("/read_buffer.c") + * + * The only down side is some people like their logs shorter + */ +#define ARGUMENTS_IN_TRACEBACK + +/* LOCALS_IN_TRACEBACK: similar to ARGUMENTS_IN_TRACEBACK, but for local + * variables. The output looks more or less like: + * + * locals: 1, "local_value" + * + * Same as above. Tends to produce even longer logs, but very useful for + * tracking errors. + */ +#define LOCALS_IN_TRACEBACK + +/* MUDLIB_ERROR_HANDLER: If you define this, the driver doesn't do any + * handling of runtime errors, other than to turn the heartbeats of + * objects off. Information about the error is passed in a mapping + * to the error_handler() function in the master object. Whatever is + * returned is put in the debug.log. + * + * A good mudlib error handler is one of the best tools for tracking down + * errors. Unfortunately, you need to have one. Check the testsuite or + * other libs for an example. + */ +#define MUDLIB_ERROR_HANDLER + +/* CONFIG_FILE_DIR specifies a directory in which the driver will search for + * config files by default. If you don't wish to use this define, you may + * always specify a full path to the config file when starting the driver. + */ +#define CONFIG_FILE_DIR "/home/atuin/bin" + +/* DEFAULT_PRAGMAS: This should be a sum of pragmas you want to always + * be on, i.e. + * + * #define DEFAULT_PRAGMAS PRAGMA_STRICT_TYPES + PRAGMA_SAVE_TYPES + * + * will make every LPC file behave as if it had the lines: + * #pragma strict_types + * #pragma save_types + * + * for no default pragmas: + * #define DEFAULT_PRAGMAS 0 + * + * If you don't know what these are, 0 is a good choice. + * + * Supported pragmas: + * PRAGMA_STRICT_TYPES: enforces strict type checking + * PRAGMA_WARNINGS: issues warnings about various dangerous things in + * your code + * PRAGMA_SAVE_TYPES: save the types of function arguments for checking + * calls to functions in this object by objects that + * inherit it. + * PRAGMA_SAVE_BINARY: save a compiled binary version of this file for + * faster loading next time it is needed. + * PRAGMA_OPTIMIZE: make a second pass over the generated code to + * optimize it further. Currently does jump threading. + * PRAGMA_ERROR_CONTEXT:include some text telling where on the line a + * compilation error occured. + */ +#define DEFAULT_PRAGMAS PRAGMA_WARNINGS + PRAGMA_STRICT_TYPES + PRAGMA_ERROR_CONTEXT + +/* supress warnings about unused arguments; only warn about unused local + * variables. Makes older code (where argument names were required) compile + * more quietly. + */ +#define SUPPRESS_ARGUMENT_WARNINGS + +/* NO_RESETS: completely disable the periodic calling of reset() */ +#undef NO_RESETS + +/* LAZY_RESETS: if this is defined, an object will only have reset() + * called in it when it is touched via call_other() or move_object() + * (assuming enough time has passed since the last reset). If LAZY_RESETS + * is #undef'd, then reset() will be called as always (which guaranteed that + * reset would always be called at least once). The advantage of lazy + * resets is that reset doesn't get called in an object that is touched + * once and never again (which can save memory since some objects won't get + * reloaded that otherwise would). + */ +#undef LAZY_RESETS + +/* SAVE_EXTENSION: defines the file extension used by save_object(). + * and restore_object(). Some sysadmins run scripts that periodically + * scan for and remove files ending in .o (but many mudlibs are already + * set up to use .o thus we leave .o as the default). + */ +#define SAVE_EXTENSION ".o" + +/* NO_ANSI: define if you wish to disallow users from typing in commands that + * contain ANSI escape sequences. Defining NO_ANSI causes all escapes + * (ASCII 27) to be replaced with a space ' ' before the string is passed + * to the action routines added with add_action. + * + * STRIP_BEFORE_PROCESS_INPUT allows the location where the stripping is + * done to be controlled. If it is defined, then process_input() doesn't + * see ANSI characters either; if it is undefined ESC chars can be processed + * by process_input(), but are stripped before add_actions are called. + * Note that if NO_ADD_ACTION is defined, then #define NO_ANSI without + * #define STRIP_BEFORE_PROCESS_INPUT is the same as #undef NO_ANSI. + * + * If you anticipate problems with users intentionally typing in ANSI codes + * to make your terminal flash, etc define this. + */ +#undef NO_ANSI +#undef STRIP_BEFORE_PROCESS_INPUT + +/* OPCPROF: define this if you wish to enable OPC profiling. Allows a dump + * of the # of times each efun is invoked (via the opcprof() efun). + */ +#undef OPCPROF + +/* OPCPROF_2D: define this if you wish to enable 2-D OPC profiling. Allows a + * dump of the # of times each *pair* of eoperators is invoked. + * + * You can't use this and OPCPROF at the same time. + */ +#undef OPCPROF_2D + +/* TRAP_CRASHES: define this if you want MudOS to call crash() in master.c + * and then shutdown when signals are received that would normally crash the + * driver. + */ +#define TRAP_CRASHES + +/* THIS_PLAYER_IN_CALL_OUT: define this if you wish this_player() to be + * usable from within call_out() callbacks. + */ +#define THIS_PLAYER_IN_CALL_OUT + +/* CALLOUT_HANDLES: If this is defined, call_out() returns an integer, which + * can be passed to remove_call_out() or find_call_out(). Removing call_outs + * by name is still allowed, but is significantly less efficient, and also + * doesn't work for function pointers. This option adds 4 bytes overhead + * per callout to keep track of the handle. + */ +#define CALLOUT_HANDLES + +/* FLUSH_OUTPUT_IMMEDIATELY: Causes output to be written to sockets + * immediately after being generated. Useful for debugging. + */ +#undef FLUSH_OUTPUT_IMMEDIATELY + +/* PRIVS: define this if you want object privileges. Your mudlib must + * explicitly make use of this functionality to be useful. Defining this + * this will increase the size of the object structure by 4 bytes (8 bytes + * on the DEC Alpha) and will add a new master apply during object creation + * to "privs_file". In general, privileges can be used to increase the + * granularity of security beyond the current root uid mechanism. + * + * [NOTE: for those who'd rather do such things at the mudlib level, look at + * the inherits() efun and the 'valid_object' apply to master.] + */ +#define PRIVS + +/* INTERACTIVE_CATCH_TELL: define this if you want catch_tell called on + * interactives as well as NPCs. If this is defined, user.c will need a + * catch_tell(msg) method that calls receive(msg); +*/ +#define INTERACTIVE_CATCH_TELL + +/* RESTRICTED_ED: define this if you want restricted ed mode enabled. + */ +#define RESTRICTED_ED + +/* NO_SHADOWS: define this if you want to disable shadows in your driver. + */ +#undef NO_SHADOWS + +/* SNOOP_SHADOWED: define this if you want snoop to report what is + * sent to the player even in the event that the player's catch_tell() is + * shadowed and the player may not be seeing what is being sent. Messages + * of this sort will be prefixed with $$. + */ +#undef SNOOP_SHADOWED + +/* RECEIVE_SNOOP: define this if you want snoop text to be sent to + * the receive_snoop() function in the snooper object (instead of being + * sent directly via add_message()). This is useful if you want to + * build a smart client that does something different with snoop messages. + */ +#undef RECEIVE_SNOOP + +/* PROFILE_FUNCTIONS: define this to be able to measure the CPU time used by + * all of the user-defined functions in each LPC object. Note: defining + * this adds three long ints (12 bytes on 32-bit machines) to the function + * header structs. Also note that the resolution of the getrusage() timer + * may not be high enough on some machines to give non-zero execution + * times to very small (fast) functions. In particular if the clock + * resolution is 1/60 of a second, then any time less than approxmately 15k + * microseconds will resolve to zero (0). + */ +#define PROFILE_FUNCTIONS + +/* NO_BUFFER_TYPE: if this is #define'd then LPC code using the 'buffer' + * type won't be allowed to compile (since the 'buffer' type won't be + * recognized by the lexer). + */ +#undef NO_BUFFER_TYPE + +/* BINARIES: define this to enable the 'save_binary' pragma. + * This pragma, when set in a program, will cause it to save a + * binary image when loaded, so that subsequent loadings will + * be much faster. The binaries are saved in the directory + * specified in the configuration file. The binaries will not + * load if the LPC source or any of the inherited or included + * files are out of date, in which case the file is compiled + * normally (and may save a new binary). + * + * In order to save the binary, valid_save_binary() is called + * in master.c, and is passed the name of the source file. If + * this returns a non-zero value, the binary is allowed to be + * saved. Allowing any file by any wizard to be saved as a + * binary is convenient, but may take up a lot of disk space. + */ +#define BINARIES + +/* ARRAY_RESERVED_WORD: If this is defined then the word 'array' can + * be used to define arrays, as in: + * + * int array x = ({ .... }); + * + * A side effect is that 'array' cannot be a variable or function name. + */ +#define ARRAY_RESERVED_WORD + +/* REF_RESERVED_WORD: If this is defined then the word 'ref' can be + * used to pass arguments to functions by value. Example: + * + * void inc(int ref x) { + * x++; + * } + * + * ... y = 1; inc(ref y); ... + * + * A side effect is that 'ref' cannot be a variable or function name. + * + * Note: ref must be used in *both* places; this is intentional. It protects + * against passing references to routines which don't intend to return values + * through their arguments, and against forgetting to pass a reference + * to a function which wants one (or accidentally having a variable modified!) + */ +#define REF_RESERVED_WORD + +/**************************************************************************** + * PACKAGES * + * -------- * + * Defining some/all of the following add certain efuns, and sometimes * + * add/remove code from the driver. * + * * + * if PACKAGE_XYZZY is defined here, then the code in packages/xyzzy.c * + * and the efuns in packages/xyzzy_spec.c will be added to the driver. * + ****************************************************************************/ + +/* various miscellaneous efuns */ +#define PACKAGE_CONTRIB + +/* efuns that are only of use to those that know something about driver + internals */ +#define PACKAGE_DEVELOP + +/* PACKAGE_MATH: determines whether or not the math efuns (for floats) are + included. + */ +#define PACKAGE_MATH + +/* PACKAGE_MATRIX: determines whether or not the 3d graphics efuns (for floats) + * are included - see packages/matrix.spec for a list. + */ +#define PACKAGE_MATRIX + +/* PACKAGE_MUDLIB_STATS: define this to enable domain and author stats + * maintenance by the driver. These mudlib stats are more domain + * based than user based, and replaces the traditional wiz_list stats. + */ +#undef PACKAGE_MUDLIB_STATS + +/* PACKAGE_SOCKETS: define this to enable the socket efunctions. This + * causes HAS_SOCKETS to be defined for all LPC objects. + */ +#define PACKAGE_SOCKETS + +/* PACKAGE_PARSER: Natural language parsing efuns for interactive fiction + * type applications + */ +#define PACKAGE_PARSER + +/* PACKAGE_EXTERNAL: Allows the driver to exec() commands specified in the + * config file. + */ +#undef PACKAGE_EXTERNAL + +/* NUM_EXTERNAL_CMDS: the number of external commands supported */ +#define NUM_EXTERNAL_CMDS 1 + +/* PACKAGE_DB: efuns for external database access using msql */ +#undef PACKAGE_DB + +/* If PACKAGE_DB is defined above, you must pick ONE of the following supported + * databases + */ +#ifdef PACKAGE_DB +#undef USE_MSQL +#undef MSQL +#define USE_MYSQL 2 +#define MY_SQL +#endif + +/**************************************************************************** + * UID PACKAGE * + * ----------- * + * UIDS are the basis for some mudlib security systems. Basically, they're * + * preserved for backwards compatibility, as several ways of breaking * + * almost any system which relies on them are known. (No, it's not a flaw * + * of uids; only that b/c of the ease with which LPC objects can call * + * each other, it's far too easy to leave holes) * + * * + * If you don't care about security, the first option is probably what you * + * want. * + ****************************************************************************/ + +/* + * PACKAGE_UIDS: define this if you want a driver that does use uids. + * + */ +#undef PACKAGE_UIDS + +/*PACKAGE DWLIB: some discworld mudlib simuls coded in C (well just one right + now) */ + +#undef PACKAGE_DWLIB + +/* AUTO_SETEUID: when an object is created it's euid is automatically set to + * the equivalent of seteuid(getuid(this_object())). undef AUTO_SETEUID + * if you would rather have the euid of the created object be set to 0. + */ +#undef AUTO_SETEUID + +/* AUTO_TRUST_BACKBONE: define this if you want objects with the backbone + * uid to automatically be trusted and to have their euid set to the uid of + * the object that forced the object's creation. + */ +#undef AUTO_TRUST_BACKBONE + +/************************************************************************* + * FOR EXPERIENCED USERS * + * ----------------------- * + * Most of these options will probably be of no interest to many users. * + *************************************************************************/ + +/* USE_32BIT_ADDRESSES: Use 32 bits for addresses of function, instead of + * the usual 16 bits. This increases the maximum program size from 64k + * of LPC bytecode (NOT source) to 4 GB. Branches are still 16 bits, + * imposing a 64k limit on catch(), if(), switch(), loops, and most other + * control structures. It would take an extremely large function to hit + * those limits, though. + * + * Overhead: 2 bytes/function with LPC->C off. Having LPC->C on forces + * this option, since it needs 4 bytes to store the function pointers + * anyway, and this setting is ignored. + */ +#define USE_32BIT_ADDRESSES + +/* HEARTBEAT_INTERVAL: define heartbeat interval in microseconds (us). + * 1,000,000 us = 1 second. The value of this macro specifies + * the frequency with which the heart_beat method will be called in + * those LPC objects which have called set_heart_beat(1). + * + * [NOTE: if ualarm() isn't available, alarm() is used instead. Since + * alarm() requires its argument in units of a second, we map 1 - 1,000,000 us + * to an actual interval of one (1) second and 1,000,001 - 2,000,000 maps to + * an actual interval of two (2) seconds, etc.] + */ +#define HEARTBEAT_INTERVAL 2 + +/* + * CALLOUT_CYCLE_SIZE: This is the number of slots in the call_out list. + * It should be approximately the average number of active call_outs, or + * a few times smaller. It should also be a power of 2, and also be relatively + * prime to any common call_out lengths. If all this is too confusing, 32 + * isn't a bad number :-) + */ +#define CALLOUT_CYCLE_SIZE 512 + +/* LARGEST_PRINTABLE_STRING: defines the size of the vsprintf() buffer in + * comm.c's add_message(). Instead of blindly making this value larger, + * your mudlib should be coded to not send huge strings to users. + */ +#define LARGEST_PRINTABLE_STRING 8192 + +/* MESSAGE_BUFFER_SIZE: determines the size of the buffer for output that + * is sent to users. + */ +#define MESSAGE_BUFFER_SIZE 4096 + +/* APPLY_CACHE_BITS: defines the number of bits to use in the call_other cache + * (in interpret.c). + * + * Memory overhead is (1 << APPLY_CACHE_BITS)*16. + * [assuming 32 bit pointers and 16 bit shorts] + * + * ACB: entries: overhead: + * 6 64 1k + * 8 256 4k + * 10 1024 16k + * 12 4096 64k + * 14 16384 256k + * 16 65536 1M + */ +#define APPLY_CACHE_BITS 20 + +/* CACHE_STATS: define this if you want call_other (apply_low) cache + * statistics. Causes HAS_CACHE_STATS to be defined in all LPC objects. + */ +#define CACHE_STATS + +/* TRACE: define this to enable the trace() and traceprefix() efuns. + * (keeping this undefined will cause the driver to run faster). + */ +#define TRACE + +/* RUNTIME_LOADING: On systems which support it, it allows LPC->C compilation + * 'on the fly' without having to recompile the driver. + * + * Note: This currently only works on machines that have the dlopen() system + * call. SunOS and IRIX do, as do a number of others. AIX and Ultrix don't. + * Linux does if you are using ELF. + */ +#undef RUNTIME_LOADING + +/* TRACE_CODE: define this to enable code tracing (the driver will print + * out the previous lines of code to an error) eval_instruction() runs about + * twice as fast when this is not defined (for the most common eoperators). + */ +#define TRACE_CODE + +/* HEART_BEAT_CHUNK: The number of heart_beat chunks allocated at a time. + * A large number wastes memory as some will be sitting around unused, while + * a small one wastes more CPU reallocating when it needs to grow. Default + * to a medium value. + */ +#define HEART_BEAT_CHUNK 32 + +/* SERVER_IP: For machines with multiple IP addresses, this specifies which + * one to use. This is useful for IP accounting and is necessary to be + * able to do ident lookups on such machines. + * + * example: #define SERVER_IP "194.229.18.27" + */ +#undef SERVER_IP + +/* Some maximum string sizes + */ +#define SMALL_STRING_SIZE 100 +#define LARGE_STRING_SIZE 1000 +#define COMMAND_BUF_SIZE 2000 + +/* Number of levels of nested datastructures allowed -- this limit prevents + * crashes from occuring when saving objects containing variables containing + * recursive datastructures (with circular references). + */ +#define MAX_SAVE_SVALUE_DEPTH 100 + +/* Miscellaneous config options that should probably be in the runtime + * config file. + */ +/* MAX_LOCAL: maximum number of local variables allowed per LPC function */ +#define CFG_MAX_LOCAL_VARIABLES 50 + +#define CFG_EVALUATOR_STACK_SIZE 3000 +#define CFG_COMPILER_STACK_SIZE 600 +#define CFG_MAX_CALL_DEPTH 150 +/* This must be one of 4, 16, 64, 256, 1024, 4096 */ +#define CFG_LIVING_HASH_SIZE 256 + +/* NEXT_MALLOC_DEBUG: define this if using a NeXT and you want to enable + * the malloc_check() and/or malloc_debug() efuns. Run the 'man malloc_debug' + * command on the NeXT to find out what the arguments to malloc_debug(int) + * mean. The malloc_check() efun calls the NeXT NXMallocCheck() system + * call which does a consistency check on malloc's data structures (this + * consistency check is done at each malloc() and free() for certain + * malloc_debug() levels). A non-zero return value indicates there was + * a consistency problem. For those NeXT users wanting a bit more + * performance out of malloc, try defining NEXT_MALLOC_DEBUG and calling the + * malloc_debug(-1) efun (with an arg of -1). This will turn all + * malloc debugging off and call malloc_singlethreaded() which the NeXT + * malloc man page claims can make NeXT system malloc 10% to 15% faster. + * + * [NOTE: This #define has no affect on the driver if not using the + * NeXTSTEP OS.] + * + * Warning: if you use a NeXT and define NEXT_MALLOC_DEBUG, be sure to + * protect the use of the malloc_check() and malloc_debug() efuns + * since setting certain debug levels can cause malloc() and free() + * to become _very_ slow (protect efuns by using simul_efuns and + * valid_override). + * + * [NOTE: malloc_debug(6) is a good compromise between efficiency and + * completeness of malloc debugging (malloc/free will be about half as fast).] + */ +#define NEXT_MALLOC_DEBUG + + +/* GET_CHAR_IS_BUFFERED: Normally get_char() is unbuffered. That is, once + * a character is received for get_char(), anything else is in the input + * stream is immediately thrown away. This can be very undesirable, especially + * if you're calling get_char() again from the handler from the previous call. + * Define this if you want get_char() to be buffered. In this case, the buffer + * will only get flushed if get_char() is not called from the first get_char()'s + * LPC callback handler. + */ +#define GET_CHAR_IS_BUFFERED + +/* PACKAGE_COMPRESS: Enable MCCP support and compressed save files + SAVE_GZ_EXTENSION: save extension for compressed files + */ +#undef HAVE_ZLIB +#undef PACKAGE_COMPRESS +#define SAVE_GZ_EXTENSION ".o.gz" + +/* CALL_OTHER_TYPE_CHECK: enable type checking for call_other() + * (-> operator on objects) + */ +#undef CALL_OTHER_TYPE_CHECK + +/* CALL_OTHER_WARN, make it warning instead of errors */ +#undef CALL_OTHER_WARN + +/* WARN_TAB: Some versions of the editor built in indent function use + * tabs for indenting. This options turns on a warning message for + * files indented with tabs instead of spaces. + */ +#define WARN_TAB + +/* USE_ICONV: Use iconv to translate input and output from/to the users char + * encoding + */ +#undef USE_ICONV + +/* WOMBLES: don't allow spaces between start/end of array/mapping/functional token chars so ({1,2,3}) still works, but ( { 1 , 2 , 3 } ) doesn't and ({ 1 , 2 , 3 }) does.*/ +#undef WOMBLES + +/* ALLOW_INHERIT_AFTER_FUNCTION: allow inheriting after functions have been defined (this includes prototypes). This caused crashes in v22.2a but it may have been fixed since */ +#define ALLOW_INHERIT_AFTER_FUNCTION +#undef PACKAGE_DSLIB +#define ED_INDENT_SPACES 4 +#define PROG_REF_TYPE int +#undef PARSE_DEBUG +#define HAS_CONSOLE +#define FLUFFOS +#undef ED_INDENT_CASE +#undef ALLOW_INHERIT_AFTER_GLOBAL_VARIABLES +#undef ANSI_SUBSTITUTE +#define CFG_MAX_GLOBAL_VARIABLES 256 +#undef RECEIVE_ED +#undef PACKAGE_ASYNC +#endif +#undef IPV6 +#undef MALLOC64 +#undef PACKAGE_CRYPTO +#undef PACKAGE_SHA1 diff --git a/fluffos-2.23-ds03/local_options.merentha b/fluffos-2.23-ds03/local_options.merentha new file mode 100644 index 0000000..b081cca --- /dev/null +++ b/fluffos-2.23-ds03/local_options.merentha @@ -0,0 +1,893 @@ +/* + * options.h: defines for the compile-time configuration of the MudOS driver + */ + +#ifndef _OPTIONS_H_ +#define _OPTIONS_H_ + +/* + * YOU PROBABLY DO NOT WANT TO MODIFY THIS FILE. + * + * Do 'cp options.h local_options' and edit that instead. local_options, + * if it exists, overrides this file. + * + * The advantage is that when you upgrade to a newer MudOS driver, you can + * simply copy your local_options file into the src directory. The build + * process will warn you if new options have been added that you should + * choose settings for. + */ + +/**************************************************************************** + * EVERY time you change ANYTHING in this file, RECOMPILE from scratch. * + * (type "make clean" then "make" on a UNIX system) Failure to do so may * + * cause the driver to behave oddly. * + ****************************************************************************/ + +/* NOTES: + * Many of the configurable options are now set via the configuration file + * that is specified as the first argument to the driver. + * See port.h for those #defines related to portability (compatibility) if + * you have problems compiling on your system. + * Removing an efun from func_spec.c usually removes most, if not all, + * of the code associated with it. + * Note that anything defined in this file is also visible to LPC files + * surrounded by __. So #define FOO in this file defines __FOO__ for + * all LPC files. This allows code like: + * + * #ifdef __SENSIBLE_MODIFIERS__ + * ... + */ + +/**************************************************************************** + * MALLOC * + * -------- * + * For performance reasons, LP drivers have a variety of memory allocation * + * packages. If you don't care, use the default one on your system: * + * #define SYSMALLOC, #undef the others. * + ****************************************************************************/ + +/* You must choose exactly one of these malloc packages: + * ~~~~ + * SYSMALLOC: + * * Built-in system malloc. + * * No statistics. + * * SYSMALLOC incurs no additional CPU or memory overhead. + * + * SMALLOC: + * * Satoria's smalloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than most system mallocs with modest ammount of memory overhead. + * * Can fall back onto system malloc if sbrk() not ok. + * + * BSDMALLOC: + * * BSD (Berkeley Software Distributions) malloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than SMALLOC but more memory overhead. + * * Requires sbrk(). + */ +#define SYSMALLOC +#undef SMALLOC +#undef BSDMALLOC +#undef MMALLOC + +/* You may optionally choose one (or none) of these malloc wrappers. These + * can be used in conjunction with any of the above malloc packages. + * + * WRAPPEDMALLOC: + * * Limited statistics. + * * Limited additional cpu overhead and no additional memory overhead. + * + * DEBUGMALLOC: + * * Statistics on precisely how much memory has been malloc'd (as well + * as the stats provided by WRAPPEDMALLOC). + * * Incurs a fair amount of overhead (both memory and CPU) + */ +#undef WRAPPEDMALLOC +#undef DEBUGMALLOC + +/* The following add certain bells and whistles to malloc: */ + +/* + * SBRK_OK: do not define this unless SMALLOC is chosen above. + * Defining this causes smalloc to use the low level memory allocation + * routines, and to act as a malloc replacement. Conversely, undef'ing + * SBRK_OK causes smalloc to act as a wrapper for the system malloc + * routines. + * + * Note: + * NeXTStep 3.x users should always #undef SBRK_OK. + */ +#undef SBRK_OK + +/* DO_MSTATS: do not define this unless BSDMALLOC or SMALLOC is chosen above. + * Defining this causes those replacement mallocs to keep statistics that + * the malloc_status() efun will print out (including total memory + * allocated/used). + */ +#undef DO_MSTATS + +/* DEBUGMALLOC_EXTENSIONS: defining this (in addition to DEBUGMALLOC) enables + * the set_malloc_mask(int) and debugmalloc(string,int) efuns. These two + * efuns basically allow you to cause certain malloc's and free's (with tags + * selected by a specified mask) to print debug information (addr, tag, + * description, size) to stdio (in the shell that invoked the driver) or to a + * file. Not defining this does reduce the overhead of DEBUGMALLOC from 16 + * bytes per malloc down to 8. This macro has no effect if DEBUGMALLOC isn't + * defined. + */ +#undef DEBUGMALLOC_EXTENSIONS + +/* CHECK_MEMORY: defining this (in addition to DEBUGMALLOC and + * DEBUGMALLOC_EXTENSIONS) causes the driver to check for memory + * corruption due to writing before the start or end of a block. This + * also adds the check_memory() efun. Takes a considerable ammount + * more memory. Mainly for debugging. + */ +#undef CHECK_MEMORY + +/**************************************************************************** + * COMPATIBILITY * + * --------------- * + * The MudOS driver has evolved quite a bit over the years. These defines * + * are mainly to preserve old behavior in case people didn't want to * + * rewrite the relevant portions of their code. * + * * + * In most cases, code which needs these defines should be rewritten when * + * possible. The 'Compat status' field is designed to give an idea how * + * likely it is that support for that option will be removed in the near * + * future. Certain options are fairly easy to work around, and double * + * the size of the associated code, as well as the maintenance workload, * + * and can make the code significantly more complex or harder to read, so * + * supporting them indefinitely is impractical. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* HAS_STATUS_TYPE: old MudOS drivers had a 'status' type which was + * identical to the 'int' type. Define this to bring it back. + * + * Compat status: very archaic, but easy to support. + */ +#undef HAS_STATUS_TYPE + +/* explode(): + * + * The old behavior (#undef both of the below) strips any number of + * delimiters at the start of the string, and one at the end. So + * explode("..x.y..z..", ".") gives ({ "x", "y", "", "z", "" }) + * + * SANE_EXPLODE_STRING strips off at most one leading delimiter, and + * still strips off one at the end, so the example above gives + * ({ "", "x", "y", "", "z", "" }). + * + * REVERSIBLE_EXPLODE_STRING overrides SANE_EXPLODE_STRING, and makes + * it so that implode(explode(x, y), y) is always x; i.e. no delimiters + * are ever stripped. So the example above gives + * ({ "", "", "x", "y", "", "z", "", "" }). + */ +#define SANE_EXPLODE_STRING +#undef REVERSIBLE_EXPLODE_STRING + +/* CAST_CALL_OTHERS: define this if you want to require casting of call_other's; + * this was the default behavior of the driver prior to this addition. + * + * Compat status: code that requires it doesn't break, and it promotes + * sloppy coding with no benefits. + */ +#undef CAST_CALL_OTHERS + +/* NONINTERACTIVE_STDERR_WRITE: if defined, all writes/tells/etc to + * noninteractive objects will be written to stderr prefixed with a ']' + * (old behavior). + * + * Compat status: Easy to support, and also on the "It's a bug! No, it's + * a feature!" religious war list. + */ +#define NONINTERACTIVE_STDERR_WRITE + +/* NO_LIGHT: define this to disable the set_light() and driver maintenance + * of light levels in objects. You can simulate it via LPC if you want... + * + * Compat status: Very dated, easy to simulate, and gross. + */ +#define NO_LIGHT + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + * process_input() then becomes the only way to deal with player input. + * + * Compat status: next to impossible to simulate, hard to replace, and + * very, very widely used. + */ +#undef NO_ADD_ACTION + +/* NO_SNOOP: disables the snoop() efun and all related functionality. + */ +#undef NO_SNOOP + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + process_input() then becomes the only way to deal with player input. */ + +/* NO_ENVIRONMENT: define this to remove the handling of object containment + * relationships by the driver + * + * Compat status: hard to simulate efficiently, and very widely used. + */ +#undef NO_ENVIRONMENT + +/* NO_WIZARDS: for historical reasons, MudOS used to keep track of who + * is and isn't a wizard. Defining this removes that completely. + * If this is defined, the wizardp() and related efuns don't exist. + * + * Also note that if it is not defined, then non-wizards are always put + * in restricted mode when ed() is used, regardless of the setting of + * the restrict parameter. + * + * Compat status: easy to simulate and dated. + */ +#define NO_WIZARDS + +/* OLD_TYPE_BEHAVIOR: reintroduces a bug in type-checking that effectively + * renders compile time type checking useless. For backwards compatibility. + * + * Compat status: dealing with all the resulting compile errors can be + * a huge pain even if they are correct, and the impact on the code is + * small. + */ +#undef OLD_TYPE_BEHAVIOR + +/* OLD_RANGE_BEHAVIOR: define this if you want negative indexes in string + * or buffer range values (not lvalue, i.e. x[-2..-1]; for e.g. not + * x[-2..-1] = foo, the latter is always illegal) to mean counting from the + * end + * + * Compat status: Not horribly difficult to replace reliance on this, but not + * trivial, and cannot be simulated. + */ +#undef OLD_RANGE_BEHAVIOR + +/* OLD_ED: ed() efun backwards compatible with the old version. The new + * version requires/allows a mudlib front end. + * + * Compat status: Easily simulated. + */ +#define OLD_ED + +/* SENSIBLE_MODIFIERS: + * Turning this on changes a few things, which may break old code: + * + * (1) 'static' is not recognized; either 'nosave' or 'protected' must + * be used instead. + * (2) The old meaning of 'public' is no longer allowed. Explicit + * functions must be defined at each level to allow access to + * privately inherited functions. + * (3) 'public' now means the default visibility. Previously there was + * no keyword that meant this (before you ask, 'public' meant something + * else, and if you don't know that, you probably don't have any reason + * to care about the old meaning). + */ +#undef SENSIBLE_MODIFIERS + +/**************************************************************************** + * MISCELLANEOUS * + * --------------- * + * Various options that affect the way the driver behaves. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* + * Define this in order to use Fermat@Equilibria's MD5 based crypt() instead + * of the operating system's. It has the advantage of giving the same value + * on all architectures, and being stronger than the standard UNIX crypt(). + */ +#define CUSTOM_CRYPT + +/* + * Some minor tweaks that make it a bit easier to run code designed to run + * on LPmud 3.2/3.2.1. Currently has the following effects: + * + * . m_indices() and m_values() are synonyms for keys() and values(), + * respectively + * . map_delete() returns it's first argument + * . inherit_list() means deep_inherit_list(), not shallow_inherit_list() + * . heart_beat_info() is a synonym for heart_beats() + */ +#undef COMPAT_32 + +/* + * Keep statistics about allocated strings, etc. Which can be viewed with + * the mud_status() efun. If this is off, mud_status() and memory_info() + * ignore allocated strings, but string operations run faster. + */ +#define STRING_STATS + +/* + * Similarly for arrays ... + */ +#define ARRAY_STATS + +/* LOG_CATCHES: define this to cause errors that are catch()'d to be + * sent to the debug log anyway. + * + * On by default, because newer libs use catch() a lot, and it's confusing + * if the errors don't show up in the logs. + */ +#define LOG_CATCHES + +/* ARGUMENTS_IN_TRACEBACK: prints out function call arguments in error + * tracebacks, to aid in debugging. Note: it prints the values of + * the arguments at the time of the error, not when the function + * was called. It looks like this: + * + * Failed to load file: read_buffer + * program: command/update.c, object: command/update line 15 + * ' commandHook' in ' clone/user.c' (' clone/user#1')line 72 + * arguments were ("/read_buffer.c") + * ' main' in ' command/update.c' (' command/update')line 15 + * arguments were ("/read_buffer.c") + * + * The only down side is some people like their logs shorter + */ +#define ARGUMENTS_IN_TRACEBACK + +/* LOCALS_IN_TRACEBACK: similar to ARGUMENTS_IN_TRACEBACK, but for local + * variables. The output looks more or less like: + * + * locals: 1, "local_value" + * + * Same as above. Tends to produce even longer logs, but very useful for + * tracking errors. + */ +#define LOCALS_IN_TRACEBACK + +/* MUDLIB_ERROR_HANDLER: If you define this, the driver doesn't do any + * handling of runtime errors, other than to turn the heartbeats of + * objects off. Information about the error is passed in a mapping + * to the error_handler() function in the master object. Whatever is + * returned is put in the debug.log. + * + * A good mudlib error handler is one of the best tools for tracking down + * errors. Unfortunately, you need to have one. Check the testsuite or + * other libs for an example. + */ +#define MUDLIB_ERROR_HANDLER + +/* CONFIG_FILE_DIR specifies a directory in which the driver will search for + * config files by default. If you don't wish to use this define, you may + * always specify a full path to the config file when starting the driver. + */ +#define CONFIG_FILE_DIR "/home/atuin/bin" + +/* DEFAULT_PRAGMAS: This should be a sum of pragmas you want to always + * be on, i.e. + * + * #define DEFAULT_PRAGMAS PRAGMA_STRICT_TYPES + PRAGMA_SAVE_TYPES + * + * will make every LPC file behave as if it had the lines: + * #pragma strict_types + * #pragma save_types + * + * for no default pragmas: + * #define DEFAULT_PRAGMAS 0 + * + * If you don't know what these are, 0 is a good choice. + * + * Supported pragmas: + * PRAGMA_STRICT_TYPES: enforces strict type checking + * PRAGMA_WARNINGS: issues warnings about various dangerous things in + * your code + * PRAGMA_SAVE_TYPES: save the types of function arguments for checking + * calls to functions in this object by objects that + * inherit it. + * PRAGMA_SAVE_BINARY: save a compiled binary version of this file for + * faster loading next time it is needed. + * PRAGMA_OPTIMIZE: make a second pass over the generated code to + * optimize it further. Currently does jump threading. + * PRAGMA_ERROR_CONTEXT:include some text telling where on the line a + * compilation error occured. + */ +#define DEFAULT_PRAGMAS PRAGMA_STRICT_TYPES + PRAGMA_ERROR_CONTEXT + +/* supress warnings about unused arguments; only warn about unused local + * variables. Makes older code (where argument names were required) compile + * more quietly. + */ +#define SUPPRESS_ARGUMENT_WARNINGS + +/* NO_RESETS: completely disable the periodic calling of reset() */ +#undef NO_RESETS + +/* LAZY_RESETS: if this is defined, an object will only have reset() + * called in it when it is touched via call_other() or move_object() + * (assuming enough time has passed since the last reset). If LAZY_RESETS + * is #undef'd, then reset() will be called as always (which guaranteed that + * reset would always be called at least once). The advantage of lazy + * resets is that reset doesn't get called in an object that is touched + * once and never again (which can save memory since some objects won't get + * reloaded that otherwise would). + */ +#define LAZY_RESETS + +/* SAVE_EXTENSION: defines the file extension used by save_object(). + * and restore_object(). Some sysadmins run scripts that periodically + * scan for and remove files ending in .o (but many mudlibs are already + * set up to use .o thus we leave .o as the default). + */ +#define SAVE_EXTENSION ".o" + +/* NO_ANSI: define if you wish to disallow users from typing in commands that + * contain ANSI escape sequences. Defining NO_ANSI causes all escapes + * (ASCII 27) to be replaced with a space ' ' before the string is passed + * to the action routines added with add_action. + * + * STRIP_BEFORE_PROCESS_INPUT allows the location where the stripping is + * done to be controlled. If it is defined, then process_input() doesn't + * see ANSI characters either; if it is undefined ESC chars can be processed + * by process_input(), but are stripped before add_actions are called. + * Note that if NO_ADD_ACTION is defined, then #define NO_ANSI without + * #define STRIP_BEFORE_PROCESS_INPUT is the same as #undef NO_ANSI. + * + * If you anticipate problems with users intentionally typing in ANSI codes + * to make your terminal flash, etc define this. + */ +#define NO_ANSI +#define STRIP_BEFORE_PROCESS_INPUT + +/* OPCPROF: define this if you wish to enable OPC profiling. Allows a dump + * of the # of times each efun is invoked (via the opcprof() efun). + */ +#undef OPCPROF + +/* OPCPROF_2D: define this if you wish to enable 2-D OPC profiling. Allows a + * dump of the # of times each *pair* of eoperators is invoked. + * + * You can't use this and OPCPROF at the same time. + */ +#undef OPCPROF_2D + +/* TRAP_CRASHES: define this if you want MudOS to call crash() in master.c + * and then shutdown when signals are received that would normally crash the + * driver. + */ +#define TRAP_CRASHES + +/* THIS_PLAYER_IN_CALL_OUT: define this if you wish this_player() to be + * usable from within call_out() callbacks. + */ +#define THIS_PLAYER_IN_CALL_OUT + +/* CALLOUT_HANDLES: If this is defined, call_out() returns an integer, which + * can be passed to remove_call_out() or find_call_out(). Removing call_outs + * by name is still allowed, but is significantly less efficient, and also + * doesn't work for function pointers. This option adds 4 bytes overhead + * per callout to keep track of the handle. + */ +#define CALLOUT_HANDLES + +/* FLUSH_OUTPUT_IMMEDIATELY: Causes output to be written to sockets + * immediately after being generated. Useful for debugging. + */ +#undef FLUSH_OUTPUT_IMMEDIATELY + +/* PRIVS: define this if you want object privileges. Your mudlib must + * explicitly make use of this functionality to be useful. Defining this + * this will increase the size of the object structure by 4 bytes (8 bytes + * on the DEC Alpha) and will add a new master apply during object creation + * to "privs_file". In general, privileges can be used to increase the + * granularity of security beyond the current root uid mechanism. + * + * [NOTE: for those who'd rather do such things at the mudlib level, look at + * the inherits() efun and the 'valid_object' apply to master.] + */ +#undef PRIVS + +/* INTERACTIVE_CATCH_TELL: define this if you want catch_tell called on + * interactives as well as NPCs. If this is defined, user.c will need a + * catch_tell(msg) method that calls receive(msg); +*/ +#undef INTERACTIVE_CATCH_TELL + +/* RESTRICTED_ED: define this if you want restricted ed mode enabled. + */ +#define RESTRICTED_ED + +/* NO_SHADOWS: define this if you want to disable shadows in your driver. + */ +#undef NO_SHADOWS + +/* SNOOP_SHADOWED: define this if you want snoop to report what is + * sent to the player even in the event that the player's catch_tell() is + * shadowed and the player may not be seeing what is being sent. Messages + * of this sort will be prefixed with $$. + */ +#undef SNOOP_SHADOWED + +/* RECEIVE_SNOOP: define this if you want snoop text to be sent to + * the receive_snoop() function in the snooper object (instead of being + * sent directly via add_message()). This is useful if you want to + * build a smart client that does something different with snoop messages. + */ +#define RECEIVE_SNOOP + +/* PROFILE_FUNCTIONS: define this to be able to measure the CPU time used by + * all of the user-defined functions in each LPC object. Note: defining + * this adds three long ints (12 bytes on 32-bit machines) to the function + * header structs. Also note that the resolution of the getrusage() timer + * may not be high enough on some machines to give non-zero execution + * times to very small (fast) functions. In particular if the clock + * resolution is 1/60 of a second, then any time less than approxmately 15k + * microseconds will resolve to zero (0). + */ +#undef PROFILE_FUNCTIONS + +/* NO_BUFFER_TYPE: if this is #define'd then LPC code using the 'buffer' + * type won't be allowed to compile (since the 'buffer' type won't be + * recognized by the lexer). + */ +#undef NO_BUFFER_TYPE + +/* BINARIES: define this to enable the 'save_binary' pragma. + * This pragma, when set in a program, will cause it to save a + * binary image when loaded, so that subsequent loadings will + * be much faster. The binaries are saved in the directory + * specified in the configuration file. The binaries will not + * load if the LPC source or any of the inherited or included + * files are out of date, in which case the file is compiled + * normally (and may save a new binary). + * + * In order to save the binary, valid_save_binary() is called + * in master.c, and is passed the name of the source file. If + * this returns a non-zero value, the binary is allowed to be + * saved. Allowing any file by any wizard to be saved as a + * binary is convenient, but may take up a lot of disk space. + */ +#define BINARIES + +/* ARRAY_RESERVED_WORD: If this is defined then the word 'array' can + * be used to define arrays, as in: + * + * int array x = ({ .... }); + * + * A side effect is that 'array' cannot be a variable or function name. + */ +#define ARRAY_RESERVED_WORD + +/* REF_RESERVED_WORD: If this is defined then the word 'ref' can be + * used to pass arguments to functions by value. Example: + * + * void inc(int ref x) { + * x++; + * } + * + * ... y = 1; inc(ref y); ... + * + * A side effect is that 'ref' cannot be a variable or function name. + * + * Note: ref must be used in *both* places; this is intentional. It protects + * against passing references to routines which don't intend to return values + * through their arguments, and against forgetting to pass a reference + * to a function which wants one (or accidentally having a variable modified!) + */ +#define REF_RESERVED_WORD + +/**************************************************************************** + * PACKAGES * + * -------- * + * Defining some/all of the following add certain efuns, and sometimes * + * add/remove code from the driver. * + * * + * if PACKAGE_XYZZY is defined here, then the code in packages/xyzzy.c * + * and the efuns in packages/xyzzy_spec.c will be added to the driver. * + ****************************************************************************/ + +/* various miscellaneous efuns */ +#define PACKAGE_CONTRIB + +/* efuns that are only of use to those that know something about driver + internals */ +#define PACKAGE_DEVELOP + +/* PACKAGE_MATH: determines whether or not the math efuns (for floats) are + included. + */ +#define PACKAGE_MATH + +/* PACKAGE_MATRIX: determines whether or not the 3d graphics efuns (for floats) + * are included - see packages/matrix.spec for a list. + */ +#undef PACKAGE_MATRIX + +/* PACKAGE_MUDLIB_STATS: define this to enable domain and author stats + * maintenance by the driver. These mudlib stats are more domain + * based than user based, and replaces the traditional wiz_list stats. + */ +#undef PACKAGE_MUDLIB_STATS + +/* PACKAGE_SOCKETS: define this to enable the socket efunctions. This + * causes HAS_SOCKETS to be defined for all LPC objects. + */ +#define PACKAGE_SOCKETS + +/* PACKAGE_PARSER: Natural language parsing efuns for interactive fiction + * type applications + */ +#undef PACKAGE_PARSER + +/* PACKAGE_EXTERNAL: Allows the driver to exec() commands specified in the + * config file. + */ +#undef PACKAGE_EXTERNAL + +/* NUM_EXTERNAL_CMDS: the number of external commands supported */ +#define NUM_EXTERNAL_CMDS 100 + +/* PACKAGE_DB: efuns for external database access using msql */ +#undef PACKAGE_DB + +/* If PACKAGE_DB is defined above, you must pick ONE of the following supported + * databases + */ +#ifdef PACKAGE_DB +#undef USE_MSQL +#undef MSQL +#define USE_MYSQL 2 +#define MY_SQL +#endif + +/**************************************************************************** + * UID PACKAGE * + * ----------- * + * UIDS are the basis for some mudlib security systems. Basically, they're * + * preserved for backwards compatibility, as several ways of breaking * + * almost any system which relies on them are known. (No, it's not a flaw * + * of uids; only that b/c of the ease with which LPC objects can call * + * each other, it's far too easy to leave holes) * + * * + * If you don't care about security, the first option is probably what you * + * want. * + ****************************************************************************/ + +/* + * PACKAGE_UIDS: define this if you want a driver that does use uids. + * + */ +#undef PACKAGE_UIDS + +/*PACKAGE DWLIB: some discworld mudlib simuls coded in C (well just one right + now) */ + +#undef PACKAGE_DWLIB + +/* AUTO_SETEUID: when an object is created it's euid is automatically set to + * the equivalent of seteuid(getuid(this_object())). undef AUTO_SETEUID + * if you would rather have the euid of the created object be set to 0. + */ +#undef AUTO_SETEUID + +/* AUTO_TRUST_BACKBONE: define this if you want objects with the backbone + * uid to automatically be trusted and to have their euid set to the uid of + * the object that forced the object's creation. + */ +#define AUTO_TRUST_BACKBONE + +/************************************************************************* + * FOR EXPERIENCED USERS * + * ----------------------- * + * Most of these options will probably be of no interest to many users. * + *************************************************************************/ + +/* USE_32BIT_ADDRESSES: Use 32 bits for addresses of function, instead of + * the usual 16 bits. This increases the maximum program size from 64k + * of LPC bytecode (NOT source) to 4 GB. Branches are still 16 bits, + * imposing a 64k limit on catch(), if(), switch(), loops, and most other + * control structures. It would take an extremely large function to hit + * those limits, though. + * + * Overhead: 2 bytes/function with LPC->C off. Having LPC->C on forces + * this option, since it needs 4 bytes to store the function pointers + * anyway, and this setting is ignored. + */ +#undef USE_32BIT_ADDRESSES + +/* HEARTBEAT_INTERVAL: define heartbeat interval in microseconds (us). + * 1,000,000 us = 1 second. The value of this macro specifies + * the frequency with which the heart_beat method will be called in + * those LPC objects which have called set_heart_beat(1). + * + * [NOTE: if ualarm() isn't available, alarm() is used instead. Since + * alarm() requires its argument in units of a second, we map 1 - 1,000,000 us + * to an actual interval of one (1) second and 1,000,001 - 2,000,000 maps to + * an actual interval of two (2) seconds, etc.] + */ +#define HEARTBEAT_INTERVAL 1 + +/* + * CALLOUT_CYCLE_SIZE: This is the number of slots in the call_out list. + * It should be approximately the average number of active call_outs, or + * a few times smaller. It should also be a power of 2, and also be relatively + * prime to any common call_out lengths. If all this is too confusing, 32 + * isn't a bad number :-) + */ +#define CALLOUT_CYCLE_SIZE 512 + +/* LARGEST_PRINTABLE_STRING: defines the size of the vsprintf() buffer in + * comm.c's add_message(). Instead of blindly making this value larger, + * your mudlib should be coded to not send huge strings to users. + */ +#define LARGEST_PRINTABLE_STRING 8192 + +/* MESSAGE_BUFFER_SIZE: determines the size of the buffer for output that + * is sent to users. + */ +#define MESSAGE_BUFFER_SIZE 4096 + +/* APPLY_CACHE_BITS: defines the number of bits to use in the call_other cache + * (in interpret.c). + * + * Memory overhead is (1 << APPLY_CACHE_BITS)*16. + * [assuming 32 bit pointers and 16 bit shorts] + * + * ACB: entries: overhead: + * 6 64 1k + * 8 256 4k + * 10 1024 16k + * 12 4096 64k + * 14 16384 256k + * 16 65536 1M + */ +#define APPLY_CACHE_BITS 20 + +/* CACHE_STATS: define this if you want call_other (apply_low) cache + * statistics. Causes HAS_CACHE_STATS to be defined in all LPC objects. + */ +#define CACHE_STATS + +/* TRACE: define this to enable the trace() and traceprefix() efuns. + * (keeping this undefined will cause the driver to run faster). + */ +#define TRACE + +/* RUNTIME_LOADING: On systems which support it, it allows LPC->C compilation + * 'on the fly' without having to recompile the driver. + * + * Note: This currently only works on machines that have the dlopen() system + * call. SunOS and IRIX do, as do a number of others. AIX and Ultrix don't. + * Linux does if you are using ELF. + */ +#undef RUNTIME_LOADING + +/* TRACE_CODE: define this to enable code tracing (the driver will print + * out the previous lines of code to an error) eval_instruction() runs about + * twice as fast when this is not defined (for the most common eoperators). + */ +#undef TRACE_CODE + +/* HEART_BEAT_CHUNK: The number of heart_beat chunks allocated at a time. + * A large number wastes memory as some will be sitting around unused, while + * a small one wastes more CPU reallocating when it needs to grow. Default + * to a medium value. + */ +#define HEART_BEAT_CHUNK 32 + +/* SERVER_IP: For machines with multiple IP addresses, this specifies which + * one to use. This is useful for IP accounting and is necessary to be + * able to do ident lookups on such machines. + * + * example: #define SERVER_IP "194.229.18.27" + */ +#undef SERVER_IP + +/* Some maximum string sizes + */ +#define SMALL_STRING_SIZE 100 +#define LARGE_STRING_SIZE 1000 +#define COMMAND_BUF_SIZE 2000 + +/* Number of levels of nested datastructures allowed -- this limit prevents + * crashes from occuring when saving objects containing variables containing + * recursive datastructures (with circular references). + */ +#define MAX_SAVE_SVALUE_DEPTH 100 + +/* Miscellaneous config options that should probably be in the runtime + * config file. + */ +/* MAX_LOCAL: maximum number of local variables allowed per LPC function */ +#define CFG_MAX_LOCAL_VARIABLES 50 + +#define CFG_EVALUATOR_STACK_SIZE 3000 +#define CFG_COMPILER_STACK_SIZE 600 +#define CFG_MAX_CALL_DEPTH 150 +/* This must be one of 4, 16, 64, 256, 1024, 4096 */ +#define CFG_LIVING_HASH_SIZE 256 + +/* NEXT_MALLOC_DEBUG: define this if using a NeXT and you want to enable + * the malloc_check() and/or malloc_debug() efuns. Run the 'man malloc_debug' + * command on the NeXT to find out what the arguments to malloc_debug(int) + * mean. The malloc_check() efun calls the NeXT NXMallocCheck() system + * call which does a consistency check on malloc's data structures (this + * consistency check is done at each malloc() and free() for certain + * malloc_debug() levels). A non-zero return value indicates there was + * a consistency problem. For those NeXT users wanting a bit more + * performance out of malloc, try defining NEXT_MALLOC_DEBUG and calling the + * malloc_debug(-1) efun (with an arg of -1). This will turn all + * malloc debugging off and call malloc_singlethreaded() which the NeXT + * malloc man page claims can make NeXT system malloc 10% to 15% faster. + * + * [NOTE: This #define has no affect on the driver if not using the + * NeXTSTEP OS.] + * + * Warning: if you use a NeXT and define NEXT_MALLOC_DEBUG, be sure to + * protect the use of the malloc_check() and malloc_debug() efuns + * since setting certain debug levels can cause malloc() and free() + * to become _very_ slow (protect efuns by using simul_efuns and + * valid_override). + * + * [NOTE: malloc_debug(6) is a good compromise between efficiency and + * completeness of malloc debugging (malloc/free will be about half as fast).] + */ +#define NEXT_MALLOC_DEBUG + + +/* GET_CHAR_IS_BUFFERED: Normally get_char() is unbuffered. That is, once + * a character is received for get_char(), anything else is in the input + * stream is immediately thrown away. This can be very undesirable, especially + * if you're calling get_char() again from the handler from the previous call. + * Define this if you want get_char() to be buffered. In this case, the buffer + * will only get flushed if get_char() is not called from the first get_char()'s + * LPC callback handler. + */ +#undef GET_CHAR_IS_BUFFERED + +/* PACKAGE_COMPRESS: Enable MCCP support and compressed save files + SAVE_GZ_EXTENSION: save extension for compressed files + */ +#undef HAVE_ZLIB +#undef PACKAGE_COMPRESS +#define SAVE_GZ_EXTENSION ".o.gz" + +/* CALL_OTHER_TYPE_CHECK: enable type checking for call_other() + * (-> operator on objects) + */ +#undef CALL_OTHER_TYPE_CHECK + +/* CALL_OTHER_WARN, make it warning instead of errors */ +#undef CALL_OTHER_WARN + +/* WARN_TAB: Some versions of the editor built in indent function use + * tabs for indenting. This options turns on a warning message for + * files indented with tabs instead of spaces. + */ +#define WARN_TAB + +/* USE_ICONV: Use iconv to translate input and output from/to the users char + * encoding + */ +#undef USE_ICONV + +/* WOMBLES: don't allow spaces between start/end of array/mapping/functional token chars so ({1,2,3}) still works, but ( { 1 , 2 , 3 } ) doesn't and ({ 1 , 2 , 3 }) does.*/ +#undef WOMBLES + +/* ALLOW_INHERIT_AFTER_FUNCTION: allow inheriting after functions have been defined (this includes prototypes). This caused crashes in v22.2a but it may have been fixed since */ +#define ALLOW_INHERIT_AFTER_FUNCTION +#undef PACKAGE_DSLIB +#define ED_INDENT_SPACES 4 +#define PROG_REF_TYPE int +#undef PARSE_DEBUG +#define HAS_CONSOLE +#define FLUFFOS +#undef ED_INDENT_CASE +#undef ALLOW_INHERIT_AFTER_GLOBAL_VARIABLES +#undef ANSI_SUBSTITUTE +#define CFG_MAX_GLOBAL_VARIABLES 256 +#undef RECEIVE_ED +#undef PACKAGE_ASYNC +#endif +#undef IPV6 +#undef MALLOC64 +#undef PACKAGE_CRYPTO +#undef PACKAGE_SHA1 diff --git a/fluffos-2.23-ds03/local_options.nm3 b/fluffos-2.23-ds03/local_options.nm3 new file mode 100644 index 0000000..f61327b --- /dev/null +++ b/fluffos-2.23-ds03/local_options.nm3 @@ -0,0 +1,893 @@ +/* + * options.h: defines for the compile-time configuration of the MudOS driver + */ + +#ifndef _OPTIONS_H_ +#define _OPTIONS_H_ + +/* + * YOU PROBABLY DO NOT WANT TO MODIFY THIS FILE. + * + * Do 'cp options.h local_options' and edit that instead. local_options, + * if it exists, overrides this file. + * + * The advantage is that when you upgrade to a newer MudOS driver, you can + * simply copy your local_options file into the src directory. The build + * process will warn you if new options have been added that you should + * choose settings for. + */ + +/**************************************************************************** + * EVERY time you change ANYTHING in this file, RECOMPILE from scratch. * + * (type "make clean" then "make" on a UNIX system) Failure to do so may * + * cause the driver to behave oddly. * + ****************************************************************************/ + +/* NOTES: + * Many of the configurable options are now set via the configuration file + * that is specified as the first argument to the driver. + * See port.h for those #defines related to portability (compatibility) if + * you have problems compiling on your system. + * Removing an efun from func_spec.c usually removes most, if not all, + * of the code associated with it. + * Note that anything defined in this file is also visible to LPC files + * surrounded by __. So #define FOO in this file defines __FOO__ for + * all LPC files. This allows code like: + * + * #ifdef __SENSIBLE_MODIFIERS__ + * ... + */ + +/**************************************************************************** + * MALLOC * + * -------- * + * For performance reasons, LP drivers have a variety of memory allocation * + * packages. If you don't care, use the default one on your system: * + * #define SYSMALLOC, #undef the others. * + ****************************************************************************/ + +/* You must choose exactly one of these malloc packages: + * ~~~~ + * SYSMALLOC: + * * Built-in system malloc. + * * No statistics. + * * SYSMALLOC incurs no additional CPU or memory overhead. + * + * SMALLOC: + * * Satoria's smalloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than most system mallocs with modest ammount of memory overhead. + * * Can fall back onto system malloc if sbrk() not ok. + * + * BSDMALLOC: + * * BSD (Berkeley Software Distributions) malloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than SMALLOC but more memory overhead. + * * Requires sbrk(). + */ +#define SYSMALLOC +#undef SMALLOC +#undef BSDMALLOC +#undef MMALLOC + +/* You may optionally choose one (or none) of these malloc wrappers. These + * can be used in conjunction with any of the above malloc packages. + * + * WRAPPEDMALLOC: + * * Limited statistics. + * * Limited additional cpu overhead and no additional memory overhead. + * + * DEBUGMALLOC: + * * Statistics on precisely how much memory has been malloc'd (as well + * as the stats provided by WRAPPEDMALLOC). + * * Incurs a fair amount of overhead (both memory and CPU) + */ +#undef WRAPPEDMALLOC +#undef DEBUGMALLOC + +/* The following add certain bells and whistles to malloc: */ + +/* + * SBRK_OK: do not define this unless SMALLOC is chosen above. + * Defining this causes smalloc to use the low level memory allocation + * routines, and to act as a malloc replacement. Conversely, undef'ing + * SBRK_OK causes smalloc to act as a wrapper for the system malloc + * routines. + * + * Note: + * NeXTStep 3.x users should always #undef SBRK_OK. + */ +#undef SBRK_OK + +/* DO_MSTATS: do not define this unless BSDMALLOC or SMALLOC is chosen above. + * Defining this causes those replacement mallocs to keep statistics that + * the malloc_status() efun will print out (including total memory + * allocated/used). + */ +#undef DO_MSTATS + +/* DEBUGMALLOC_EXTENSIONS: defining this (in addition to DEBUGMALLOC) enables + * the set_malloc_mask(int) and debugmalloc(string,int) efuns. These two + * efuns basically allow you to cause certain malloc's and free's (with tags + * selected by a specified mask) to print debug information (addr, tag, + * description, size) to stdio (in the shell that invoked the driver) or to a + * file. Not defining this does reduce the overhead of DEBUGMALLOC from 16 + * bytes per malloc down to 8. This macro has no effect if DEBUGMALLOC isn't + * defined. + */ +#undef DEBUGMALLOC_EXTENSIONS + +/* CHECK_MEMORY: defining this (in addition to DEBUGMALLOC and + * DEBUGMALLOC_EXTENSIONS) causes the driver to check for memory + * corruption due to writing before the start or end of a block. This + * also adds the check_memory() efun. Takes a considerable ammount + * more memory. Mainly for debugging. + */ +#undef CHECK_MEMORY + +/**************************************************************************** + * COMPATIBILITY * + * --------------- * + * The MudOS driver has evolved quite a bit over the years. These defines * + * are mainly to preserve old behavior in case people didn't want to * + * rewrite the relevant portions of their code. * + * * + * In most cases, code which needs these defines should be rewritten when * + * possible. The 'Compat status' field is designed to give an idea how * + * likely it is that support for that option will be removed in the near * + * future. Certain options are fairly easy to work around, and double * + * the size of the associated code, as well as the maintenance workload, * + * and can make the code significantly more complex or harder to read, so * + * supporting them indefinitely is impractical. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* HAS_STATUS_TYPE: old MudOS drivers had a 'status' type which was + * identical to the 'int' type. Define this to bring it back. + * + * Compat status: very archaic, but easy to support. + */ +#define HAS_STATUS_TYPE + +/* explode(): + * + * The old behavior (#undef both of the below) strips any number of + * delimiters at the start of the string, and one at the end. So + * explode("..x.y..z..", ".") gives ({ "x", "y", "", "z", "" }) + * + * SANE_EXPLODE_STRING strips off at most one leading delimiter, and + * still strips off one at the end, so the example above gives + * ({ "", "x", "y", "", "z", "" }). + * + * REVERSIBLE_EXPLODE_STRING overrides SANE_EXPLODE_STRING, and makes + * it so that implode(explode(x, y), y) is always x; i.e. no delimiters + * are ever stripped. So the example above gives + * ({ "", "", "x", "y", "", "z", "", "" }). + */ +#undef SANE_EXPLODE_STRING +#undef REVERSIBLE_EXPLODE_STRING + +/* CAST_CALL_OTHERS: define this if you want to require casting of call_other's; + * this was the default behavior of the driver prior to this addition. + * + * Compat status: code that requires it doesn't break, and it promotes + * sloppy coding with no benefits. + */ +#undef CAST_CALL_OTHERS + +/* NONINTERACTIVE_STDERR_WRITE: if defined, all writes/tells/etc to + * noninteractive objects will be written to stderr prefixed with a ']' + * (old behavior). + * + * Compat status: Easy to support, and also on the "It's a bug! No, it's + * a feature!" religious war list. + */ +#define NONINTERACTIVE_STDERR_WRITE + +/* NO_LIGHT: define this to disable the set_light() and driver maintenance + * of light levels in objects. You can simulate it via LPC if you want... + * + * Compat status: Very dated, easy to simulate, and gross. + */ +#define NO_LIGHT + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + * process_input() then becomes the only way to deal with player input. + * + * Compat status: next to impossible to simulate, hard to replace, and + * very, very widely used. + */ +#undef NO_ADD_ACTION + +/* NO_SNOOP: disables the snoop() efun and all related functionality. + */ +#undef NO_SNOOP + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + process_input() then becomes the only way to deal with player input. */ + +/* NO_ENVIRONMENT: define this to remove the handling of object containment + * relationships by the driver + * + * Compat status: hard to simulate efficiently, and very widely used. + */ +#undef NO_ENVIRONMENT + +/* NO_WIZARDS: for historical reasons, MudOS used to keep track of who + * is and isn't a wizard. Defining this removes that completely. + * If this is defined, the wizardp() and related efuns don't exist. + * + * Also note that if it is not defined, then non-wizards are always put + * in restricted mode when ed() is used, regardless of the setting of + * the restrict parameter. + * + * Compat status: easy to simulate and dated. + */ +#define NO_WIZARDS + +/* OLD_TYPE_BEHAVIOR: reintroduces a bug in type-checking that effectively + * renders compile time type checking useless. For backwards compatibility. + * + * Compat status: dealing with all the resulting compile errors can be + * a huge pain even if they are correct, and the impact on the code is + * small. + */ +#undef OLD_TYPE_BEHAVIOR + +/* OLD_RANGE_BEHAVIOR: define this if you want negative indexes in string + * or buffer range values (not lvalue, i.e. x[-2..-1]; for e.g. not + * x[-2..-1] = foo, the latter is always illegal) to mean counting from the + * end + * + * Compat status: Not horribly difficult to replace reliance on this, but not + * trivial, and cannot be simulated. + */ +#undef OLD_RANGE_BEHAVIOR + +/* OLD_ED: ed() efun backwards compatible with the old version. The new + * version requires/allows a mudlib front end. + * + * Compat status: Easily simulated. + */ +#define OLD_ED + +/* SENSIBLE_MODIFIERS: + * Turning this on changes a few things, which may break old code: + * + * (1) 'static' is not recognized; either 'nosave' or 'protected' must + * be used instead. + * (2) The old meaning of 'public' is no longer allowed. Explicit + * functions must be defined at each level to allow access to + * privately inherited functions. + * (3) 'public' now means the default visibility. Previously there was + * no keyword that meant this (before you ask, 'public' meant something + * else, and if you don't know that, you probably don't have any reason + * to care about the old meaning). + */ +#undef SENSIBLE_MODIFIERS + +/**************************************************************************** + * MISCELLANEOUS * + * --------------- * + * Various options that affect the way the driver behaves. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* + * Define this in order to use Fermat@Equilibria's MD5 based crypt() instead + * of the operating system's. It has the advantage of giving the same value + * on all architectures, and being stronger than the standard UNIX crypt(). + */ +#define CUSTOM_CRYPT + +/* + * Some minor tweaks that make it a bit easier to run code designed to run + * on LPmud 3.2/3.2.1. Currently has the following effects: + * + * . m_indices() and m_values() are synonyms for keys() and values(), + * respectively + * . map_delete() returns it's first argument + * . inherit_list() means deep_inherit_list(), not shallow_inherit_list() + * . heart_beat_info() is a synonym for heart_beats() + */ +#undef COMPAT_32 + +/* + * Keep statistics about allocated strings, etc. Which can be viewed with + * the mud_status() efun. If this is off, mud_status() and memory_info() + * ignore allocated strings, but string operations run faster. + */ +#define STRING_STATS + +/* + * Similarly for arrays ... + */ +#define ARRAY_STATS + +/* LOG_CATCHES: define this to cause errors that are catch()'d to be + * sent to the debug log anyway. + * + * On by default, because newer libs use catch() a lot, and it's confusing + * if the errors don't show up in the logs. + */ +#define LOG_CATCHES + +/* ARGUMENTS_IN_TRACEBACK: prints out function call arguments in error + * tracebacks, to aid in debugging. Note: it prints the values of + * the arguments at the time of the error, not when the function + * was called. It looks like this: + * + * Failed to load file: read_buffer + * program: command/update.c, object: command/update line 15 + * ' commandHook' in ' clone/user.c' (' clone/user#1')line 72 + * arguments were ("/read_buffer.c") + * ' main' in ' command/update.c' (' command/update')line 15 + * arguments were ("/read_buffer.c") + * + * The only down side is some people like their logs shorter + */ +#define ARGUMENTS_IN_TRACEBACK + +/* LOCALS_IN_TRACEBACK: similar to ARGUMENTS_IN_TRACEBACK, but for local + * variables. The output looks more or less like: + * + * locals: 1, "local_value" + * + * Same as above. Tends to produce even longer logs, but very useful for + * tracking errors. + */ +#define LOCALS_IN_TRACEBACK + +/* MUDLIB_ERROR_HANDLER: If you define this, the driver doesn't do any + * handling of runtime errors, other than to turn the heartbeats of + * objects off. Information about the error is passed in a mapping + * to the error_handler() function in the master object. Whatever is + * returned is put in the debug.log. + * + * A good mudlib error handler is one of the best tools for tracking down + * errors. Unfortunately, you need to have one. Check the testsuite or + * other libs for an example. + */ +#define MUDLIB_ERROR_HANDLER + +/* CONFIG_FILE_DIR specifies a directory in which the driver will search for + * config files by default. If you don't wish to use this define, you may + * always specify a full path to the config file when starting the driver. + */ +#define CONFIG_FILE_DIR "./" + +/* DEFAULT_PRAGMAS: This should be a sum of pragmas you want to always + * be on, i.e. + * + * #define DEFAULT_PRAGMAS PRAGMA_STRICT_TYPES + PRAGMA_SAVE_TYPES + * + * will make every LPC file behave as if it had the lines: + * #pragma strict_types + * #pragma save_types + * + * for no default pragmas: + * #define DEFAULT_PRAGMAS 0 + * + * If you don't know what these are, 0 is a good choice. + * + * Supported pragmas: + * PRAGMA_STRICT_TYPES: enforces strict type checking + * PRAGMA_WARNINGS: issues warnings about various dangerous things in + * your code + * PRAGMA_SAVE_TYPES: save the types of function arguments for checking + * calls to functions in this object by objects that + * inherit it. + * PRAGMA_SAVE_BINARY: save a compiled binary version of this file for + * faster loading next time it is needed. + * PRAGMA_OPTIMIZE: make a second pass over the generated code to + * optimize it further. Currently does jump threading. + * PRAGMA_ERROR_CONTEXT:include some text telling where on the line a + * compilation error occured. + */ +#define DEFAULT_PRAGMAS 0 + +/* supress warnings about unused arguments; only warn about unused local + * variables. Makes older code (where argument names were required) compile + * more quietly. + */ +#define SUPPRESS_ARGUMENT_WARNINGS + +/* NO_RESETS: completely disable the periodic calling of reset() */ +#undef NO_RESETS + +/* LAZY_RESETS: if this is defined, an object will only have reset() + * called in it when it is touched via call_other() or move_object() + * (assuming enough time has passed since the last reset). If LAZY_RESETS + * is #undef'd, then reset() will be called as always (which guaranteed that + * reset would always be called at least once). The advantage of lazy + * resets is that reset doesn't get called in an object that is touched + * once and never again (which can save memory since some objects won't get + * reloaded that otherwise would). + */ +#undef LAZY_RESETS + +/* SAVE_EXTENSION: defines the file extension used by save_object(). + * and restore_object(). Some sysadmins run scripts that periodically + * scan for and remove files ending in .o (but many mudlibs are already + * set up to use .o thus we leave .o as the default). + */ +#define SAVE_EXTENSION ".o" + +/* NO_ANSI: define if you wish to disallow users from typing in commands that + * contain ANSI escape sequences. Defining NO_ANSI causes all escapes + * (ASCII 27) to be replaced with a space ' ' before the string is passed + * to the action routines added with add_action. + * + * STRIP_BEFORE_PROCESS_INPUT allows the location where the stripping is + * done to be controlled. If it is defined, then process_input() doesn't + * see ANSI characters either; if it is undefined ESC chars can be processed + * by process_input(), but are stripped before add_actions are called. + * Note that if NO_ADD_ACTION is defined, then #define NO_ANSI without + * #define STRIP_BEFORE_PROCESS_INPUT is the same as #undef NO_ANSI. + * + * If you anticipate problems with users intentionally typing in ANSI codes + * to make your terminal flash, etc define this. + */ +#define NO_ANSI +#define STRIP_BEFORE_PROCESS_INPUT + +/* OPCPROF: define this if you wish to enable OPC profiling. Allows a dump + * of the # of times each efun is invoked (via the opcprof() efun). + */ +#undef OPCPROF + +/* OPCPROF_2D: define this if you wish to enable 2-D OPC profiling. Allows a + * dump of the # of times each *pair* of eoperators is invoked. + * + * You can't use this and OPCPROF at the same time. + */ +#undef OPCPROF_2D + +/* TRAP_CRASHES: define this if you want MudOS to call crash() in master.c + * and then shutdown when signals are received that would normally crash the + * driver. + */ +#define TRAP_CRASHES + +/* THIS_PLAYER_IN_CALL_OUT: define this if you wish this_player() to be + * usable from within call_out() callbacks. + */ +#define THIS_PLAYER_IN_CALL_OUT + +/* CALLOUT_HANDLES: If this is defined, call_out() returns an integer, which + * can be passed to remove_call_out() or find_call_out(). Removing call_outs + * by name is still allowed, but is significantly less efficient, and also + * doesn't work for function pointers. This option adds 4 bytes overhead + * per callout to keep track of the handle. + */ +#define CALLOUT_HANDLES + +/* FLUSH_OUTPUT_IMMEDIATELY: Causes output to be written to sockets + * immediately after being generated. Useful for debugging. + */ +#undef FLUSH_OUTPUT_IMMEDIATELY + +/* PRIVS: define this if you want object privileges. Your mudlib must + * explicitly make use of this functionality to be useful. Defining this + * this will increase the size of the object structure by 4 bytes (8 bytes + * on the DEC Alpha) and will add a new master apply during object creation + * to "privs_file". In general, privileges can be used to increase the + * granularity of security beyond the current root uid mechanism. + * + * [NOTE: for those who'd rather do such things at the mudlib level, look at + * the inherits() efun and the 'valid_object' apply to master.] + */ +#define PRIVS + +/* INTERACTIVE_CATCH_TELL: define this if you want catch_tell called on + * interactives as well as NPCs. If this is defined, user.c will need a + * catch_tell(msg) method that calls receive(msg); +*/ +#define INTERACTIVE_CATCH_TELL + +/* RESTRICTED_ED: define this if you want restricted ed mode enabled. + */ +#define RESTRICTED_ED + +/* NO_SHADOWS: define this if you want to disable shadows in your driver. + */ +#undef NO_SHADOWS + +/* SNOOP_SHADOWED: define this if you want snoop to report what is + * sent to the player even in the event that the player's catch_tell() is + * shadowed and the player may not be seeing what is being sent. Messages + * of this sort will be prefixed with $$. + */ +#undef SNOOP_SHADOWED + +/* RECEIVE_SNOOP: define this if you want snoop text to be sent to + * the receive_snoop() function in the snooper object (instead of being + * sent directly via add_message()). This is useful if you want to + * build a smart client that does something different with snoop messages. + */ +#define RECEIVE_SNOOP + +/* PROFILE_FUNCTIONS: define this to be able to measure the CPU time used by + * all of the user-defined functions in each LPC object. Note: defining + * this adds three long ints (12 bytes on 32-bit machines) to the function + * header structs. Also note that the resolution of the getrusage() timer + * may not be high enough on some machines to give non-zero execution + * times to very small (fast) functions. In particular if the clock + * resolution is 1/60 of a second, then any time less than approxmately 15k + * microseconds will resolve to zero (0). + */ +#undef PROFILE_FUNCTIONS + +/* NO_BUFFER_TYPE: if this is #define'd then LPC code using the 'buffer' + * type won't be allowed to compile (since the 'buffer' type won't be + * recognized by the lexer). + */ +#undef NO_BUFFER_TYPE + +/* BINARIES: define this to enable the 'save_binary' pragma. + * This pragma, when set in a program, will cause it to save a + * binary image when loaded, so that subsequent loadings will + * be much faster. The binaries are saved in the directory + * specified in the configuration file. The binaries will not + * load if the LPC source or any of the inherited or included + * files are out of date, in which case the file is compiled + * normally (and may save a new binary). + * + * In order to save the binary, valid_save_binary() is called + * in master.c, and is passed the name of the source file. If + * this returns a non-zero value, the binary is allowed to be + * saved. Allowing any file by any wizard to be saved as a + * binary is convenient, but may take up a lot of disk space. + */ +#undef BINARIES + +/* ARRAY_RESERVED_WORD: If this is defined then the word 'array' can + * be used to define arrays, as in: + * + * int array x = ({ .... }); + * + * A side effect is that 'array' cannot be a variable or function name. + */ +#undef ARRAY_RESERVED_WORD + +/* REF_RESERVED_WORD: If this is defined then the word 'ref' can be + * used to pass arguments to functions by value. Example: + * + * void inc(int ref x) { + * x++; + * } + * + * ... y = 1; inc(ref y); ... + * + * A side effect is that 'ref' cannot be a variable or function name. + * + * Note: ref must be used in *both* places; this is intentional. It protects + * against passing references to routines which don't intend to return values + * through their arguments, and against forgetting to pass a reference + * to a function which wants one (or accidentally having a variable modified!) + */ +#undef REF_RESERVED_WORD + +/**************************************************************************** + * PACKAGES * + * -------- * + * Defining some/all of the following add certain efuns, and sometimes * + * add/remove code from the driver. * + * * + * if PACKAGE_XYZZY is defined here, then the code in packages/xyzzy.c * + * and the efuns in packages/xyzzy_spec.c will be added to the driver. * + ****************************************************************************/ + +/* various miscellaneous efuns */ +#define PACKAGE_CONTRIB + +/* efuns that are only of use to those that know something about driver + internals */ +#define PACKAGE_DEVELOP + +/* PACKAGE_MATH: determines whether or not the math efuns (for floats) are + included. + */ +#define PACKAGE_MATH + +/* PACKAGE_MATRIX: determines whether or not the 3d graphics efuns (for floats) + * are included - see packages/matrix.spec for a list. + */ +#define PACKAGE_MATRIX + +/* PACKAGE_MUDLIB_STATS: define this to enable domain and author stats + * maintenance by the driver. These mudlib stats are more domain + * based than user based, and replaces the traditional wiz_list stats. + */ +#define PACKAGE_MUDLIB_STATS + +/* PACKAGE_SOCKETS: define this to enable the socket efunctions. This + * causes HAS_SOCKETS to be defined for all LPC objects. + */ +#define PACKAGE_SOCKETS + +/* PACKAGE_PARSER: Natural language parsing efuns for interactive fiction + * type applications + */ +#define PACKAGE_PARSER + +/* PACKAGE_EXTERNAL: Allows the driver to exec() commands specified in the + * config file. + */ +#undef PACKAGE_EXTERNAL + +/* NUM_EXTERNAL_CMDS: the number of external commands supported */ +#define NUM_EXTERNAL_CMDS 100 + +/* PACKAGE_DB: efuns for external database access using msql */ +#undef PACKAGE_DB + +/* If PACKAGE_DB is defined above, you must pick ONE of the following supported + * databases + */ +#ifdef PACKAGE_DB +#undef USE_MSQL +#undef MSQL +#define USE_MYSQL 2 +#define MY_SQL +#endif + +/**************************************************************************** + * UID PACKAGE * + * ----------- * + * UIDS are the basis for some mudlib security systems. Basically, they're * + * preserved for backwards compatibility, as several ways of breaking * + * almost any system which relies on them are known. (No, it's not a flaw * + * of uids; only that b/c of the ease with which LPC objects can call * + * each other, it's far too easy to leave holes) * + * * + * If you don't care about security, the first option is probably what you * + * want. * + ****************************************************************************/ + +/* + * PACKAGE_UIDS: define this if you want a driver that does use uids. + * + */ +#undef PACKAGE_UIDS + +/*PACKAGE DWLIB: some discworld mudlib simuls coded in C (well just one right + now) */ + +#undef PACKAGE_DWLIB + +/* AUTO_SETEUID: when an object is created it's euid is automatically set to + * the equivalent of seteuid(getuid(this_object())). undef AUTO_SETEUID + * if you would rather have the euid of the created object be set to 0. + */ +#undef AUTO_SETEUID + +/* AUTO_TRUST_BACKBONE: define this if you want objects with the backbone + * uid to automatically be trusted and to have their euid set to the uid of + * the object that forced the object's creation. + */ +#undef AUTO_TRUST_BACKBONE + +/************************************************************************* + * FOR EXPERIENCED USERS * + * ----------------------- * + * Most of these options will probably be of no interest to many users. * + *************************************************************************/ + +/* USE_32BIT_ADDRESSES: Use 32 bits for addresses of function, instead of + * the usual 16 bits. This increases the maximum program size from 64k + * of LPC bytecode (NOT source) to 4 GB. Branches are still 16 bits, + * imposing a 64k limit on catch(), if(), switch(), loops, and most other + * control structures. It would take an extremely large function to hit + * those limits, though. + * + * Overhead: 2 bytes/function with LPC->C off. Having LPC->C on forces + * this option, since it needs 4 bytes to store the function pointers + * anyway, and this setting is ignored. + */ +#undef USE_32BIT_ADDRESSES + +/* HEARTBEAT_INTERVAL: define heartbeat interval in microseconds (us). + * 1,000,000 us = 1 second. The value of this macro specifies + * the frequency with which the heart_beat method will be called in + * those LPC objects which have called set_heart_beat(1). + * + * [NOTE: if ualarm() isn't available, alarm() is used instead. Since + * alarm() requires its argument in units of a second, we map 1 - 1,000,000 us + * to an actual interval of one (1) second and 1,000,001 - 2,000,000 maps to + * an actual interval of two (2) seconds, etc.] + */ +#define HEARTBEAT_INTERVAL 1 + +/* + * CALLOUT_CYCLE_SIZE: This is the number of slots in the call_out list. + * It should be approximately the average number of active call_outs, or + * a few times smaller. It should also be a power of 2, and also be relatively + * prime to any common call_out lengths. If all this is too confusing, 32 + * isn't a bad number :-) + */ +#define CALLOUT_CYCLE_SIZE 32 + +/* LARGEST_PRINTABLE_STRING: defines the size of the vsprintf() buffer in + * comm.c's add_message(). Instead of blindly making this value larger, + * your mudlib should be coded to not send huge strings to users. + */ +#define LARGEST_PRINTABLE_STRING 8192 + +/* MESSAGE_BUFFER_SIZE: determines the size of the buffer for output that + * is sent to users. + */ +#define MESSAGE_BUFFER_SIZE 4096 + +/* APPLY_CACHE_BITS: defines the number of bits to use in the call_other cache + * (in interpret.c). + * + * Memory overhead is (1 << APPLY_CACHE_BITS)*16. + * [assuming 32 bit pointers and 16 bit shorts] + * + * ACB: entries: overhead: + * 6 64 1k + * 8 256 4k + * 10 1024 16k + * 12 4096 64k + * 14 16384 256k + * 16 65536 1M + */ +#define APPLY_CACHE_BITS 11 + +/* CACHE_STATS: define this if you want call_other (apply_low) cache + * statistics. Causes HAS_CACHE_STATS to be defined in all LPC objects. + */ +#define CACHE_STATS + +/* TRACE: define this to enable the trace() and traceprefix() efuns. + * (keeping this undefined will cause the driver to run faster). + */ +#undef TRACE + +/* RUNTIME_LOADING: On systems which support it, it allows LPC->C compilation + * 'on the fly' without having to recompile the driver. + * + * Note: This currently only works on machines that have the dlopen() system + * call. SunOS and IRIX do, as do a number of others. AIX and Ultrix don't. + * Linux does if you are using ELF. + */ +#undef RUNTIME_LOADING + +/* TRACE_CODE: define this to enable code tracing (the driver will print + * out the previous lines of code to an error) eval_instruction() runs about + * twice as fast when this is not defined (for the most common eoperators). + */ +#undef TRACE_CODE + +/* HEART_BEAT_CHUNK: The number of heart_beat chunks allocated at a time. + * A large number wastes memory as some will be sitting around unused, while + * a small one wastes more CPU reallocating when it needs to grow. Default + * to a medium value. + */ +#define HEART_BEAT_CHUNK 32 + +/* SERVER_IP: For machines with multiple IP addresses, this specifies which + * one to use. This is useful for IP accounting and is necessary to be + * able to do ident lookups on such machines. + * + * example: #define SERVER_IP "194.229.18.27" + */ +#undef SERVER_IP + +/* Some maximum string sizes + */ +#define SMALL_STRING_SIZE 100 +#define LARGE_STRING_SIZE 1000 +#define COMMAND_BUF_SIZE 2000 + +/* Number of levels of nested datastructures allowed -- this limit prevents + * crashes from occuring when saving objects containing variables containing + * recursive datastructures (with circular references). + */ +#define MAX_SAVE_SVALUE_DEPTH 100 + +/* Miscellaneous config options that should probably be in the runtime + * config file. + */ +/* MAX_LOCAL: maximum number of local variables allowed per LPC function */ +#define CFG_MAX_LOCAL_VARIABLES 50 + +#define CFG_EVALUATOR_STACK_SIZE 3000 +#define CFG_COMPILER_STACK_SIZE 600000 +#define CFG_MAX_CALL_DEPTH 150 +/* This must be one of 4, 16, 64, 256, 1024, 4096 */ +#define CFG_LIVING_HASH_SIZE 256 + +/* NEXT_MALLOC_DEBUG: define this if using a NeXT and you want to enable + * the malloc_check() and/or malloc_debug() efuns. Run the 'man malloc_debug' + * command on the NeXT to find out what the arguments to malloc_debug(int) + * mean. The malloc_check() efun calls the NeXT NXMallocCheck() system + * call which does a consistency check on malloc's data structures (this + * consistency check is done at each malloc() and free() for certain + * malloc_debug() levels). A non-zero return value indicates there was + * a consistency problem. For those NeXT users wanting a bit more + * performance out of malloc, try defining NEXT_MALLOC_DEBUG and calling the + * malloc_debug(-1) efun (with an arg of -1). This will turn all + * malloc debugging off and call malloc_singlethreaded() which the NeXT + * malloc man page claims can make NeXT system malloc 10% to 15% faster. + * + * [NOTE: This #define has no affect on the driver if not using the + * NeXTSTEP OS.] + * + * Warning: if you use a NeXT and define NEXT_MALLOC_DEBUG, be sure to + * protect the use of the malloc_check() and malloc_debug() efuns + * since setting certain debug levels can cause malloc() and free() + * to become _very_ slow (protect efuns by using simul_efuns and + * valid_override). + * + * [NOTE: malloc_debug(6) is a good compromise between efficiency and + * completeness of malloc debugging (malloc/free will be about half as fast).] + */ +#define NEXT_MALLOC_DEBUG + + +/* GET_CHAR_IS_BUFFERED: Normally get_char() is unbuffered. That is, once + * a character is received for get_char(), anything else is in the input + * stream is immediately thrown away. This can be very undesirable, especially + * if you're calling get_char() again from the handler from the previous call. + * Define this if you want get_char() to be buffered. In this case, the buffer + * will only get flushed if get_char() is not called from the first get_char()'s + * LPC callback handler. + */ +#undef GET_CHAR_IS_BUFFERED + +/* PACKAGE_COMPRESS: Enable MCCP support and compressed save files + SAVE_GZ_EXTENSION: save extension for compressed files + */ +#undef HAVE_ZLIB +#undef PACKAGE_COMPRESS +#define SAVE_GZ_EXTENSION ".o.gz" + +/* CALL_OTHER_TYPE_CHECK: enable type checking for call_other() + * (-> operator on objects) + */ +#undef CALL_OTHER_TYPE_CHECK + +/* CALL_OTHER_WARN, make it warning instead of errors */ +#undef CALL_OTHER_WARN + +/* WARN_TAB: Some versions of the editor built in indent function use + * tabs for indenting. This options turns on a warning message for + * files indented with tabs instead of spaces. + */ +#define WARN_TAB + +/* USE_ICONV: Use iconv to translate input and output from/to the users char + * encoding + */ +#undef USE_ICONV + +/* WOMBLES: don't allow spaces between start/end of array/mapping/functional token chars so ({1,2,3}) still works, but ( { 1 , 2 , 3 } ) doesn't and ({ 1 , 2 , 3 }) does.*/ +#undef WOMBLES + +/* ALLOW_INHERIT_AFTER_FUNCTION: allow inheriting after functions have been defined (this includes prototypes). This caused crashes in v22.2a but it may have been fixed since */ +#define ALLOW_INHERIT_AFTER_FUNCTION +#define ALLOW_INHERIT_AFTER_GLOBAL_VARIABLES +#define PARSE_DEBUG +#define FLUFFOS +#undef PACKAGE_DSLIB +#define ED_INDENT_SPACES 4 +#define PROG_REF_TYPE int +#define HAS_CONSOLE +#undef ED_INDENT_CASE +#undef ANSI_SUBSTITUTE +#define CFG_MAX_GLOBAL_VARIABLES 256 +#undef RECEIVE_ED +#undef PACKAGE_ASYNC +#endif +#undef IPV6 +#undef MALLOC64 +#undef PACKAGE_CRYPTO +#undef PACKAGE_SHA1 diff --git a/fluffos-2.23-ds03/local_options.nm4 b/fluffos-2.23-ds03/local_options.nm4 new file mode 100644 index 0000000..51853bb --- /dev/null +++ b/fluffos-2.23-ds03/local_options.nm4 @@ -0,0 +1,894 @@ +/* + * options.h: defines for the compile-time configuration of the MudOS driver + */ + +#ifndef _OPTIONS_H_ +#define _OPTIONS_H_ + +/* + * YOU PROBABLY DO NOT WANT TO MODIFY THIS FILE. + * + * Do 'cp options.h local_options' and edit that instead. local_options, + * if it exists, overrides this file. + * + * The advantage is that when you upgrade to a newer MudOS driver, you can + * simply copy your local_options file into the src directory. The build + * process will warn you if new options have been added that you should + * choose settings for. + */ + +/**************************************************************************** + * EVERY time you change ANYTHING in this file, RECOMPILE from scratch. * + * (type "make clean" then "make" on a UNIX system) Failure to do so may * + * cause the driver to behave oddly. * + ****************************************************************************/ + +/* NOTES: + * Many of the configurable options are now set via the configuration file + * that is specified as the first argument to the driver. + * See port.h for those #defines related to portability (compatibility) if + * you have problems compiling on your system. + * Removing an efun from func_spec.c usually removes most, if not all, + * of the code associated with it. + * Note that anything defined in this file is also visible to LPC files + * surrounded by __. So #define FOO in this file defines __FOO__ for + * all LPC files. This allows code like: + * + * #ifdef __SENSIBLE_MODIFIERS__ + * ... + */ + +/**************************************************************************** + * MALLOC * + * -------- * + * For performance reasons, LP drivers have a variety of memory allocation * + * packages. If you don't care, use the default one on your system: * + * #define SYSMALLOC, #undef the others. * + ****************************************************************************/ + +/* You must choose exactly one of these malloc packages: + * ~~~~ + * SYSMALLOC: + * * Built-in system malloc. + * * No statistics. + * * SYSMALLOC incurs no additional CPU or memory overhead. + * + * SMALLOC: + * * Satoria's smalloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than most system mallocs with modest ammount of memory overhead. + * * Can fall back onto system malloc if sbrk() not ok. + * + * BSDMALLOC: + * * BSD (Berkeley Software Distributions) malloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than SMALLOC but more memory overhead. + * * Requires sbrk(). + */ +#define SYSMALLOC +#undef SMALLOC +#undef BSDMALLOC +#undef MMALLOC + +/* You may optionally choose one (or none) of these malloc wrappers. These + * can be used in conjunction with any of the above malloc packages. + * + * WRAPPEDMALLOC: + * * Limited statistics. + * * Limited additional cpu overhead and no additional memory overhead. + * + * DEBUGMALLOC: + * * Statistics on precisely how much memory has been malloc'd (as well + * as the stats provided by WRAPPEDMALLOC). + * * Incurs a fair amount of overhead (both memory and CPU) + */ +#undef WRAPPEDMALLOC +#undef DEBUGMALLOC + +/* The following add certain bells and whistles to malloc: */ + +/* + * SBRK_OK: do not define this unless SMALLOC is chosen above. + * Defining this causes smalloc to use the low level memory allocation + * routines, and to act as a malloc replacement. Conversely, undef'ing + * SBRK_OK causes smalloc to act as a wrapper for the system malloc + * routines. + * + * Note: + * NeXTStep 3.x users should always #undef SBRK_OK. + */ +#undef SBRK_OK + +/* DO_MSTATS: do not define this unless BSDMALLOC or SMALLOC is chosen above. + * Defining this causes those replacement mallocs to keep statistics that + * the malloc_status() efun will print out (including total memory + * allocated/used). + */ +#undef DO_MSTATS + +/* DEBUGMALLOC_EXTENSIONS: defining this (in addition to DEBUGMALLOC) enables + * the set_malloc_mask(int) and debugmalloc(string,int) efuns. These two + * efuns basically allow you to cause certain malloc's and free's (with tags + * selected by a specified mask) to print debug information (addr, tag, + * description, size) to stdio (in the shell that invoked the driver) or to a + * file. Not defining this does reduce the overhead of DEBUGMALLOC from 16 + * bytes per malloc down to 8. This macro has no effect if DEBUGMALLOC isn't + * defined. + */ +#undef DEBUGMALLOC_EXTENSIONS + +/* CHECK_MEMORY: defining this (in addition to DEBUGMALLOC and + * DEBUGMALLOC_EXTENSIONS) causes the driver to check for memory + * corruption due to writing before the start or end of a block. This + * also adds the check_memory() efun. Takes a considerable ammount + * more memory. Mainly for debugging. + */ +#undef CHECK_MEMORY + +/**************************************************************************** + * COMPATIBILITY * + * --------------- * + * The MudOS driver has evolved quite a bit over the years. These defines * + * are mainly to preserve old behavior in case people didn't want to * + * rewrite the relevant portions of their code. * + * * + * In most cases, code which needs these defines should be rewritten when * + * possible. The 'Compat status' field is designed to give an idea how * + * likely it is that support for that option will be removed in the near * + * future. Certain options are fairly easy to work around, and double * + * the size of the associated code, as well as the maintenance workload, * + * and can make the code significantly more complex or harder to read, so * + * supporting them indefinitely is impractical. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* HAS_STATUS_TYPE: old MudOS drivers had a 'status' type which was + * identical to the 'int' type. Define this to bring it back. + * + * Compat status: very archaic, but easy to support. + */ +#undef HAS_STATUS_TYPE + +/* explode(): + * + * The old behavior (#undef both of the below) strips any number of + * delimiters at the start of the string, and one at the end. So + * explode("..x.y..z..", ".") gives ({ "x", "y", "", "z", "" }) + * + * SANE_EXPLODE_STRING strips off at most one leading delimiter, and + * still strips off one at the end, so the example above gives + * ({ "", "x", "y", "", "z", "" }). + * + * REVERSIBLE_EXPLODE_STRING overrides SANE_EXPLODE_STRING, and makes + * it so that implode(explode(x, y), y) is always x; i.e. no delimiters + * are ever stripped. So the example above gives + * ({ "", "", "x", "y", "", "z", "", "" }). + */ +#define SANE_EXPLODE_STRING +#undef REVERSIBLE_EXPLODE_STRING + +/* CAST_CALL_OTHERS: define this if you want to require casting of call_other's; + * this was the default behavior of the driver prior to this addition. + * + * Compat status: code that requires it doesn't break, and it promotes + * sloppy coding with no benefits. + */ +#undef CAST_CALL_OTHERS + +/* NONINTERACTIVE_STDERR_WRITE: if defined, all writes/tells/etc to + * noninteractive objects will be written to stderr prefixed with a ']' + * (old behavior). + * + * Compat status: Easy to support, and also on the "It's a bug! No, it's + * a feature!" religious war list. + */ +#define NONINTERACTIVE_STDERR_WRITE + +/* NO_LIGHT: define this to disable the set_light() and driver maintenance + * of light levels in objects. You can simulate it via LPC if you want... + * + * Compat status: Very dated, easy to simulate, and gross. + */ +#define NO_LIGHT + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + * process_input() then becomes the only way to deal with player input. + * + * Compat status: next to impossible to simulate, hard to replace, and + * very, very widely used. + */ +#undef NO_ADD_ACTION + +/* NO_SNOOP: disables the snoop() efun and all related functionality. + */ +#undef NO_SNOOP + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + process_input() then becomes the only way to deal with player input. */ + +/* NO_ENVIRONMENT: define this to remove the handling of object containment + * relationships by the driver + * + * Compat status: hard to simulate efficiently, and very widely used. + */ +#undef NO_ENVIRONMENT + +/* NO_WIZARDS: for historical reasons, MudOS used to keep track of who + * is and isn't a wizard. Defining this removes that completely. + * If this is defined, the wizardp() and related efuns don't exist. + * + * Also note that if it is not defined, then non-wizards are always put + * in restricted mode when ed() is used, regardless of the setting of + * the restrict parameter. + * + * Compat status: easy to simulate and dated. + */ +#define NO_WIZARDS + +/* OLD_TYPE_BEHAVIOR: reintroduces a bug in type-checking that effectively + * renders compile time type checking useless. For backwards compatibility. + * + * Compat status: dealing with all the resulting compile errors can be + * a huge pain even if they are correct, and the impact on the code is + * small. + */ +#undef OLD_TYPE_BEHAVIOR + +/* OLD_RANGE_BEHAVIOR: define this if you want negative indexes in string + * or buffer range values (not lvalue, i.e. x[-2..-1]; for e.g. not + * x[-2..-1] = foo, the latter is always illegal) to mean counting from the + * end + * + * Compat status: Not horribly difficult to replace reliance on this, but not + * trivial, and cannot be simulated. + */ +#undef OLD_RANGE_BEHAVIOR + +/* OLD_ED: ed() efun backwards compatible with the old version. The new + * version requires/allows a mudlib front end. + * + * Compat status: Easily simulated. + */ +#undef OLD_ED + +/* SENSIBLE_MODIFIERS: + * Turning this on changes a few things, which may break old code: + * + * (1) 'static' is not recognized; either 'nosave' or 'protected' must + * be used instead. + * (2) The old meaning of 'public' is no longer allowed. Explicit + * functions must be defined at each level to allow access to + * privately inherited functions. + * (3) 'public' now means the default visibility. Previously there was + * no keyword that meant this (before you ask, 'public' meant something + * else, and if you don't know that, you probably don't have any reason + * to care about the old meaning). + */ +#undef SENSIBLE_MODIFIERS + +/**************************************************************************** + * MISCELLANEOUS * + * --------------- * + * Various options that affect the way the driver behaves. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* + * Define this in order to use Fermat@Equilibria's MD5 based crypt() instead + * of the operating system's. It has the advantage of giving the same value + * on all architectures, and being stronger than the standard UNIX crypt(). + */ +#define CUSTOM_CRYPT + +/* + * Some minor tweaks that make it a bit easier to run code designed to run + * on LPmud 3.2/3.2.1. Currently has the following effects: + * + * . m_indices() and m_values() are synonyms for keys() and values(), + * respectively + * . map_delete() returns it's first argument + * . inherit_list() means deep_inherit_list(), not shallow_inherit_list() + * . heart_beat_info() is a synonym for heart_beats() + */ +#undef COMPAT_32 + +/* + * Keep statistics about allocated strings, etc. Which can be viewed with + * the mud_status() efun. If this is off, mud_status() and memory_info() + * ignore allocated strings, but string operations run faster. + */ +#define STRING_STATS + +/* + * Similarly for arrays ... + */ +#define ARRAY_STATS + +/* LOG_CATCHES: define this to cause errors that are catch()'d to be + * sent to the debug log anyway. + * + * On by default, because newer libs use catch() a lot, and it's confusing + * if the errors don't show up in the logs. + */ +#define LOG_CATCHES + +/* ARGUMENTS_IN_TRACEBACK: prints out function call arguments in error + * tracebacks, to aid in debugging. Note: it prints the values of + * the arguments at the time of the error, not when the function + * was called. It looks like this: + * + * Failed to load file: read_buffer + * program: command/update.c, object: command/update line 15 + * ' commandHook' in ' clone/user.c' (' clone/user#1')line 72 + * arguments were ("/read_buffer.c") + * ' main' in ' command/update.c' (' command/update')line 15 + * arguments were ("/read_buffer.c") + * + * The only down side is some people like their logs shorter + */ +#undef ARGUMENTS_IN_TRACEBACK + +/* LOCALS_IN_TRACEBACK: similar to ARGUMENTS_IN_TRACEBACK, but for local + * variables. The output looks more or less like: + * + * locals: 1, "local_value" + * + * Same as above. Tends to produce even longer logs, but very useful for + * tracking errors. + */ +#undef LOCALS_IN_TRACEBACK + +/* MUDLIB_ERROR_HANDLER: If you define this, the driver doesn't do any + * handling of runtime errors, other than to turn the heartbeats of + * objects off. Information about the error is passed in a mapping + * to the error_handler() function in the master object. Whatever is + * returned is put in the debug.log. + * + * A good mudlib error handler is one of the best tools for tracking down + * errors. Unfortunately, you need to have one. Check the testsuite or + * other libs for an example. + */ +#define MUDLIB_ERROR_HANDLER + +/* CONFIG_FILE_DIR specifies a directory in which the driver will search for + * config files by default. If you don't wish to use this define, you may + * always specify a full path to the config file when starting the driver. + */ +#define CONFIG_FILE_DIR "./" + +/* DEFAULT_PRAGMAS: This should be a sum of pragmas you want to always + * be on, i.e. + * + * #define DEFAULT_PRAGMAS PRAGMA_STRICT_TYPES + PRAGMA_SAVE_TYPES + * + * will make every LPC file behave as if it had the lines: + * #pragma strict_types + * #pragma save_types + * + * for no default pragmas: + * #define DEFAULT_PRAGMAS 0 + * + * If you don't know what these are, 0 is a good choice. + * + * Supported pragmas: + * PRAGMA_STRICT_TYPES: enforces strict type checking + * PRAGMA_WARNINGS: issues warnings about various dangerous things in + * your code + * PRAGMA_SAVE_TYPES: save the types of function arguments for checking + * calls to functions in this object by objects that + * inherit it. + * PRAGMA_SAVE_BINARY: save a compiled binary version of this file for + * faster loading next time it is needed. + * PRAGMA_OPTIMIZE: make a second pass over the generated code to + * optimize it further. Currently does jump threading. + * PRAGMA_ERROR_CONTEXT:include some text telling where on the line a + * compilation error occured. + */ +#define DEFAULT_PRAGMAS 0 + +/* supress warnings about unused arguments; only warn about unused local + * variables. Makes older code (where argument names were required) compile + * more quietly. + */ +#define SUPPRESS_ARGUMENT_WARNINGS + +/* NO_RESETS: completely disable the periodic calling of reset() */ +#undef NO_RESETS + +/* LAZY_RESETS: if this is defined, an object will only have reset() + * called in it when it is touched via call_other() or move_object() + * (assuming enough time has passed since the last reset). If LAZY_RESETS + * is #undef'd, then reset() will be called as always (which guaranteed that + * reset would always be called at least once). The advantage of lazy + * resets is that reset doesn't get called in an object that is touched + * once and never again (which can save memory since some objects won't get + * reloaded that otherwise would). + */ +#undef LAZY_RESETS + +/* SAVE_EXTENSION: defines the file extension used by save_object(). + * and restore_object(). Some sysadmins run scripts that periodically + * scan for and remove files ending in .o (but many mudlibs are already + * set up to use .o thus we leave .o as the default). + */ +#define SAVE_EXTENSION ".o" + +/* NO_ANSI: define if you wish to disallow users from typing in commands that + * contain ANSI escape sequences. Defining NO_ANSI causes all escapes + * (ASCII 27) to be replaced with a space ' ' before the string is passed + * to the action routines added with add_action. + * + * STRIP_BEFORE_PROCESS_INPUT allows the location where the stripping is + * done to be controlled. If it is defined, then process_input() doesn't + * see ANSI characters either; if it is undefined ESC chars can be processed + * by process_input(), but are stripped before add_actions are called. + * Note that if NO_ADD_ACTION is defined, then #define NO_ANSI without + * #define STRIP_BEFORE_PROCESS_INPUT is the same as #undef NO_ANSI. + * + * If you anticipate problems with users intentionally typing in ANSI codes + * to make your terminal flash, etc define this. + */ +#define NO_ANSI +#define STRIP_BEFORE_PROCESS_INPUT + +/* OPCPROF: define this if you wish to enable OPC profiling. Allows a dump + * of the # of times each efun is invoked (via the opcprof() efun). + */ +#define OPCPROF + +/* OPCPROF_2D: define this if you wish to enable 2-D OPC profiling. Allows a + * dump of the # of times each *pair* of eoperators is invoked. + * + * You can't use this and OPCPROF at the same time. + */ +#undef OPCPROF_2D + +/* TRAP_CRASHES: define this if you want MudOS to call crash() in master.c + * and then shutdown when signals are received that would normally crash the + * driver. + */ +#define TRAP_CRASHES + +/* THIS_PLAYER_IN_CALL_OUT: define this if you wish this_player() to be + * usable from within call_out() callbacks. + */ +#define THIS_PLAYER_IN_CALL_OUT + +/* CALLOUT_HANDLES: If this is defined, call_out() returns an integer, which + * can be passed to remove_call_out() or find_call_out(). Removing call_outs + * by name is still allowed, but is significantly less efficient, and also + * doesn't work for function pointers. This option adds 4 bytes overhead + * per callout to keep track of the handle. + */ +#define CALLOUT_HANDLES + +/* FLUSH_OUTPUT_IMMEDIATELY: Causes output to be written to sockets + * immediately after being generated. Useful for debugging. + */ +#undef FLUSH_OUTPUT_IMMEDIATELY + +/* PRIVS: define this if you want object privileges. Your mudlib must + * explicitly make use of this functionality to be useful. Defining this + * this will increase the size of the object structure by 4 bytes (8 bytes + * on the DEC Alpha) and will add a new master apply during object creation + * to "privs_file". In general, privileges can be used to increase the + * granularity of security beyond the current root uid mechanism. + * + * [NOTE: for those who'd rather do such things at the mudlib level, look at + * the inherits() efun and the 'valid_object' apply to master.] + */ +#define PRIVS + +/* INTERACTIVE_CATCH_TELL: define this if you want catch_tell called on + * interactives as well as NPCs. If this is defined, user.c will need a + * catch_tell(msg) method that calls receive(msg); +*/ +#define INTERACTIVE_CATCH_TELL + +/* RESTRICTED_ED: define this if you want restricted ed mode enabled. + */ +#define RESTRICTED_ED + +/* NO_SHADOWS: define this if you want to disable shadows in your driver. + */ +#undef NO_SHADOWS + +/* SNOOP_SHADOWED: define this if you want snoop to report what is + * sent to the player even in the event that the player's catch_tell() is + * shadowed and the player may not be seeing what is being sent. Messages + * of this sort will be prefixed with $$. + */ +#undef SNOOP_SHADOWED + +/* RECEIVE_SNOOP: define this if you want snoop text to be sent to + * the receive_snoop() function in the snooper object (instead of being + * sent directly via add_message()). This is useful if you want to + * build a smart client that does something different with snoop messages. + */ +#define RECEIVE_SNOOP + +/* PROFILE_FUNCTIONS: define this to be able to measure the CPU time used by + * all of the user-defined functions in each LPC object. Note: defining + * this adds three long ints (12 bytes on 32-bit machines) to the function + * header structs. Also note that the resolution of the getrusage() timer + * may not be high enough on some machines to give non-zero execution + * times to very small (fast) functions. In particular if the clock + * resolution is 1/60 of a second, then any time less than approxmately 15k + * microseconds will resolve to zero (0). + */ +#undef PROFILE_FUNCTIONS + +/* NO_BUFFER_TYPE: if this is #define'd then LPC code using the 'buffer' + * type won't be allowed to compile (since the 'buffer' type won't be + * recognized by the lexer). + */ +#undef NO_BUFFER_TYPE + +/* BINARIES: define this to enable the 'save_binary' pragma. + * This pragma, when set in a program, will cause it to save a + * binary image when loaded, so that subsequent loadings will + * be much faster. The binaries are saved in the directory + * specified in the configuration file. The binaries will not + * load if the LPC source or any of the inherited or included + * files are out of date, in which case the file is compiled + * normally (and may save a new binary). + * + * In order to save the binary, valid_save_binary() is called + * in master.c, and is passed the name of the source file. If + * this returns a non-zero value, the binary is allowed to be + * saved. Allowing any file by any wizard to be saved as a + * binary is convenient, but may take up a lot of disk space. + */ +#undef BINARIES + +/* ARRAY_RESERVED_WORD: If this is defined then the word 'array' can + * be used to define arrays, as in: + * + * int array x = ({ .... }); + * + * A side effect is that 'array' cannot be a variable or function name. + */ +#define ARRAY_RESERVED_WORD + +/* REF_RESERVED_WORD: If this is defined then the word 'ref' can be + * used to pass arguments to functions by value. Example: + * + * void inc(int ref x) { + * x++; + * } + * + * ... y = 1; inc(ref y); ... + * + * A side effect is that 'ref' cannot be a variable or function name. + * + * Note: ref must be used in *both* places; this is intentional. It protects + * against passing references to routines which don't intend to return values + * through their arguments, and against forgetting to pass a reference + * to a function which wants one (or accidentally having a variable modified!) + */ +#undef REF_RESERVED_WORD + +/**************************************************************************** + * PACKAGES * + * -------- * + * Defining some/all of the following add certain efuns, and sometimes * + * add/remove code from the driver. * + * * + * if PACKAGE_XYZZY is defined here, then the code in packages/xyzzy.c * + * and the efuns in packages/xyzzy_spec.c will be added to the driver. * + ****************************************************************************/ + +/* various miscellaneous efuns */ +#define PACKAGE_CONTRIB + +/* efuns that are only of use to those that know something about driver + internals */ +#define PACKAGE_DEVELOP + +/* PACKAGE_MATH: determines whether or not the math efuns (for floats) are + included. + */ +#define PACKAGE_MATH + +/* PACKAGE_MATRIX: determines whether or not the 3d graphics efuns (for floats) + * are included - see packages/matrix.spec for a list. + */ +#define PACKAGE_MATRIX + +/* PACKAGE_MUDLIB_STATS: define this to enable domain and author stats + * maintenance by the driver. These mudlib stats are more domain + * based than user based, and replaces the traditional wiz_list stats. + */ +#define PACKAGE_MUDLIB_STATS + +/* PACKAGE_SOCKETS: define this to enable the socket efunctions. This + * causes HAS_SOCKETS to be defined for all LPC objects. + */ +#define PACKAGE_SOCKETS + +/* PACKAGE_PARSER: Natural language parsing efuns for interactive fiction + * type applications + */ +#define PACKAGE_PARSER + +/* PACKAGE_EXTERNAL: Allows the driver to exec() commands specified in the + * config file. + */ +#undef PACKAGE_EXTERNAL + +/* NUM_EXTERNAL_CMDS: the number of external commands supported */ +#define NUM_EXTERNAL_CMDS 100 + +/* PACKAGE_DB: efuns for external database access using msql */ +#undef PACKAGE_DB + +/* If PACKAGE_DB is defined above, you must pick ONE of the following supported + * databases + */ +#ifdef PACKAGE_DB +#undef USE_MSQL +#undef MSQL +#define USE_MYSQL 2 +#define MY_SQL +#endif + +/**************************************************************************** + * UID PACKAGE * + * ----------- * + * UIDS are the basis for some mudlib security systems. Basically, they're * + * preserved for backwards compatibility, as several ways of breaking * + * almost any system which relies on them are known. (No, it's not a flaw * + * of uids; only that b/c of the ease with which LPC objects can call * + * each other, it's far too easy to leave holes) * + * * + * If you don't care about security, the first option is probably what you * + * want. * + ****************************************************************************/ + +/* + * PACKAGE_UIDS: define this if you want a driver that does use uids. + * + */ +#undef PACKAGE_UIDS + +/*PACKAGE DWLIB: some discworld mudlib simuls coded in C (well just one right + now) */ + +#undef PACKAGE_DWLIB + +/* AUTO_SETEUID: when an object is created it's euid is automatically set to + * the equivalent of seteuid(getuid(this_object())). undef AUTO_SETEUID + * if you would rather have the euid of the created object be set to 0. + */ +#undef AUTO_SETEUID + +/* AUTO_TRUST_BACKBONE: define this if you want objects with the backbone + * uid to automatically be trusted and to have their euid set to the uid of + * the object that forced the object's creation. + */ +#undef AUTO_TRUST_BACKBONE + +/************************************************************************* + * FOR EXPERIENCED USERS * + * ----------------------- * + * Most of these options will probably be of no interest to many users. * + *************************************************************************/ + +/* USE_32BIT_ADDRESSES: Use 32 bits for addresses of function, instead of + * the usual 16 bits. This increases the maximum program size from 64k + * of LPC bytecode (NOT source) to 4 GB. Branches are still 16 bits, + * imposing a 64k limit on catch(), if(), switch(), loops, and most other + * control structures. It would take an extremely large function to hit + * those limits, though. + * + * Overhead: 2 bytes/function with LPC->C off. Having LPC->C on forces + * this option, since it needs 4 bytes to store the function pointers + * anyway, and this setting is ignored. + */ +#undef USE_32BIT_ADDRESSES + +/* HEARTBEAT_INTERVAL: define heartbeat interval in microseconds (us). + * 1,000,000 us = 1 second. The value of this macro specifies + * the frequency with which the heart_beat method will be called in + * those LPC objects which have called set_heart_beat(1). + * + * [NOTE: if ualarm() isn't available, alarm() is used instead. Since + * alarm() requires its argument in units of a second, we map 1 - 1,000,000 us + * to an actual interval of one (1) second and 1,000,001 - 2,000,000 maps to + * an actual interval of two (2) seconds, etc.] + */ +#define HEARTBEAT_INTERVAL 1 + +/* + * CALLOUT_CYCLE_SIZE: This is the number of slots in the call_out list. + * It should be approximately the average number of active call_outs, or + * a few times smaller. It should also be a power of 2, and also be relatively + * prime to any common call_out lengths. If all this is too confusing, 32 + * isn't a bad number :-) + */ +#define CALLOUT_CYCLE_SIZE 32 + +/* LARGEST_PRINTABLE_STRING: defines the size of the vsprintf() buffer in + * comm.c's add_message(). Instead of blindly making this value larger, + * your mudlib should be coded to not send huge strings to users. + */ +#define LARGEST_PRINTABLE_STRING 8192 + +/* MESSAGE_BUFFER_SIZE: determines the size of the buffer for output that + * is sent to users. + */ +#define MESSAGE_BUFFER_SIZE 4096 + +/* APPLY_CACHE_BITS: defines the number of bits to use in the call_other cache + * (in interpret.c). + * + * Memory overhead is (1 << APPLY_CACHE_BITS)*16. + * [assuming 32 bit pointers and 16 bit shorts] + * + * ACB: entries: overhead: + * 6 64 1k + * 8 256 4k + * 10 1024 16k + * 12 4096 64k + * 14 16384 256k + * 16 65536 1M + */ +#define APPLY_CACHE_BITS 11 + +/* CACHE_STATS: define this if you want call_other (apply_low) cache + * statistics. Causes HAS_CACHE_STATS to be defined in all LPC objects. + */ +#define CACHE_STATS + +/* TRACE: define this to enable the trace() and traceprefix() efuns. + * (keeping this undefined will cause the driver to run faster). + */ +#undef TRACE + +/* RUNTIME_LOADING: On systems which support it, it allows LPC->C compilation + * 'on the fly' without having to recompile the driver. + * + * Note: This currently only works on machines that have the dlopen() system + * call. SunOS and IRIX do, as do a number of others. AIX and Ultrix don't. + * Linux does if you are using ELF. + */ +#undef RUNTIME_LOADING + +/* TRACE_CODE: define this to enable code tracing (the driver will print + * out the previous lines of code to an error) eval_instruction() runs about + * twice as fast when this is not defined (for the most common eoperators). + */ +#undef TRACE_CODE + +/* HEART_BEAT_CHUNK: The number of heart_beat chunks allocated at a time. + * A large number wastes memory as some will be sitting around unused, while + * a small one wastes more CPU reallocating when it needs to grow. Default + * to a medium value. + */ +#define HEART_BEAT_CHUNK 32 + +/* SERVER_IP: For machines with multiple IP addresses, this specifies which + * one to use. This is useful for IP accounting and is necessary to be + * able to do ident lookups on such machines. + * + * example: #define SERVER_IP "194.229.18.27" + */ +#undef SERVER_IP + +/* Some maximum string sizes + */ +#define SMALL_STRING_SIZE 100 +#define LARGE_STRING_SIZE 1000 +#define COMMAND_BUF_SIZE 2000 + +/* Number of levels of nested datastructures allowed -- this limit prevents + * crashes from occuring when saving objects containing variables containing + * recursive datastructures (with circular references). + */ +#define MAX_SAVE_SVALUE_DEPTH 100 + +/* Miscellaneous config options that should probably be in the runtime + * config file. + */ +/* MAX_LOCAL: maximum number of local variables allowed per LPC function */ +#define CFG_MAX_LOCAL_VARIABLES 50 +/* Increasing max global vars beyond 256 is not recommended */ +#define CFG_MAX_GLOBAL_VARIABLES 256 + +#define CFG_EVALUATOR_STACK_SIZE 3000 +#define CFG_COMPILER_STACK_SIZE 600000 +#define CFG_MAX_CALL_DEPTH 150 +/* This must be one of 4, 16, 64, 256, 1024, 4096 */ +#define CFG_LIVING_HASH_SIZE 256 + +/* NEXT_MALLOC_DEBUG: define this if using a NeXT and you want to enable + * the malloc_check() and/or malloc_debug() efuns. Run the 'man malloc_debug' + * command on the NeXT to find out what the arguments to malloc_debug(int) + * mean. The malloc_check() efun calls the NeXT NXMallocCheck() system + * call which does a consistency check on malloc's data structures (this + * consistency check is done at each malloc() and free() for certain + * malloc_debug() levels). A non-zero return value indicates there was + * a consistency problem. For those NeXT users wanting a bit more + * performance out of malloc, try defining NEXT_MALLOC_DEBUG and calling the + * malloc_debug(-1) efun (with an arg of -1). This will turn all + * malloc debugging off and call malloc_singlethreaded() which the NeXT + * malloc man page claims can make NeXT system malloc 10% to 15% faster. + * + * [NOTE: This #define has no affect on the driver if not using the + * NeXTSTEP OS.] + * + * Warning: if you use a NeXT and define NEXT_MALLOC_DEBUG, be sure to + * protect the use of the malloc_check() and malloc_debug() efuns + * since setting certain debug levels can cause malloc() and free() + * to become _very_ slow (protect efuns by using simul_efuns and + * valid_override). + * + * [NOTE: malloc_debug(6) is a good compromise between efficiency and + * completeness of malloc debugging (malloc/free will be about half as fast).] + */ +#define NEXT_MALLOC_DEBUG + + +/* GET_CHAR_IS_BUFFERED: Normally get_char() is unbuffered. That is, once + * a character is received for get_char(), anything else is in the input + * stream is immediately thrown away. This can be very undesirable, especially + * if you're calling get_char() again from the handler from the previous call. + * Define this if you want get_char() to be buffered. In this case, the buffer + * will only get flushed if get_char() is not called from the first get_char()'s + * LPC callback handler. + */ +#undef GET_CHAR_IS_BUFFERED + +/* PACKAGE_COMPRESS: Enable MCCP support and compressed save files + SAVE_GZ_EXTENSION: save extension for compressed files + */ +#undef HAVE_ZLIB +#undef PACKAGE_COMPRESS +#define SAVE_GZ_EXTENSION ".o.gz" + +/* CALL_OTHER_TYPE_CHECK: enable type checking for call_other() + * (-> operator on objects) + */ +#undef CALL_OTHER_TYPE_CHECK + +/* CALL_OTHER_WARN, make it warning instead of errors */ +#undef CALL_OTHER_WARN + +/* WARN_TAB: Some versions of the editor built in indent function use + * tabs for indenting. This options turns on a warning message for + * files indented with tabs instead of spaces. + */ +#define WARN_TAB + +/* USE_ICONV: Use iconv to translate input and output from/to the users char + * encoding + */ +#undef USE_ICONV + +/* WOMBLES: don't allow spaces between start/end of array/mapping/functional token chars so ({1,2,3}) still works, but ( { 1 , 2 , 3 } ) doesn't and ({ 1 , 2 , 3 }) does.*/ +#undef WOMBLES + +/* ALLOW_INHERIT_AFTER_FUNCTION: allow inheriting after functions have been defined (this includes prototypes). This caused crashes in v22.2a but it may have been fixed since */ +#define ALLOW_INHERIT_AFTER_FUNCTION +#undef ALLOW_INHERIT_AFTER_GLOBAL_VARIABLES +#define PARSE_DEBUG +#define FLUFFOS +#undef PACKAGE_DSLIB +#define ED_INDENT_SPACES 4 +#define PROG_REF_TYPE int +#define HAS_CONSOLE +#undef ED_INDENT_CASE +#undef ANSI_SUBSTITUTE +#undef RECEIVE_ED +#undef PACKAGE_ASYNC +#endif +#undef IPV6 +#undef MALLOC64 +#undef PACKAGE_CRYPTO +#undef PACKAGE_SHA1 diff --git a/fluffos-2.23-ds03/local_options.sapid b/fluffos-2.23-ds03/local_options.sapid new file mode 100644 index 0000000..784c9f6 --- /dev/null +++ b/fluffos-2.23-ds03/local_options.sapid @@ -0,0 +1,935 @@ +/* + * options.h: defines for the compile-time configuration of the MudOS driver + */ + +#ifndef _OPTIONS_H_ +#define _OPTIONS_H_ + +/* + * YOU PROBABLY DO NOT WANT TO MODIFY THIS FILE. + * + * Do 'cp options.h local_options' and edit that instead. local_options, + * if it exists, overrides this file. + * + * The advantage is that when you upgrade to a newer MudOS driver, you can + * simply copy your local_options file into the src directory. The build + * process will warn you if new options have been added that you should + * choose settings for. + */ + +/**************************************************************************** + * EVERY time you change ANYTHING in this file, RECOMPILE from scratch. * + * (type "make clean" then "make" on a UNIX system) Failure to do so may * + * cause the driver to behave oddly. * + ****************************************************************************/ + +/* NOTES: + * Many of the configurable options are now set via the configuration file + * that is specified as the first argument to the driver. + * See port.h for those #defines related to portability (compatibility) if + * you have problems compiling on your system. + * Removing an efun from func_spec.c usually removes most, if not all, + * of the code associated with it. + * Note that anything defined in this file is also visible to LPC files + * surrounded by __. So #define FOO in this file defines __FOO__ for + * all LPC files. This allows code like: + * + * #ifdef __SENSIBLE_MODIFIERS__ + * ... + */ + +/**************************************************************************** + * MALLOC * + * -------- * + * For performance reasons, LP drivers have a variety of memory allocation * + * packages. If you don't care, use the default one on your system: * + * #define SYSMALLOC, #undef the others. * + ****************************************************************************/ + +/* You must choose exactly one of these malloc packages: + * ~~~~ + * SYSMALLOC: + * * Built-in system malloc. + * * No statistics. + * * SYSMALLOC incurs no additional CPU or memory overhead. + * + * SMALLOC: + * * Satoria's smalloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than most system mallocs with modest ammount of memory overhead. + * * Can fall back onto system malloc if sbrk() not ok. + * + * BSDMALLOC: + * * BSD (Berkeley Software Distributions) malloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than SMALLOC but more memory overhead. + * * Requires sbrk(). + */ +#define SYSMALLOC +#undef SMALLOC +#undef BSDMALLOC +#undef MMALLOC + +/* You may optionally choose one (or none) of these malloc wrappers. These + * can be used in conjunction with any of the above malloc packages. + * + * WRAPPEDMALLOC: + * * Limited statistics. + * * Limited additional cpu overhead and no additional memory overhead. + * + * DEBUGMALLOC: + * * Statistics on precisely how much memory has been malloc'd (as well + * as the stats provided by WRAPPEDMALLOC). + * * Incurs a fair amount of overhead (both memory and CPU) + */ +#undef WRAPPEDMALLOC +#undef DEBUGMALLOC + +/* The following add certain bells and whistles to malloc: */ + +/* + * SBRK_OK: do not define this unless SMALLOC is chosen above. + * Defining this causes smalloc to use the low level memory allocation + * routines, and to act as a malloc replacement. Conversely, undef'ing + * SBRK_OK causes smalloc to act as a wrapper for the system malloc + * routines. + * + * Note: + * NeXTStep 3.x users should always #undef SBRK_OK. + */ +#undef SBRK_OK + +/* DO_MSTATS: do not define this unless BSDMALLOC or SMALLOC is chosen above. + * Defining this causes those replacement mallocs to keep statistics that + * the malloc_status() efun will print out (including total memory + * allocated/used). + */ +#undef DO_MSTATS + +/* DEBUGMALLOC_EXTENSIONS: defining this (in addition to DEBUGMALLOC) enables + * the set_malloc_mask(int) and debugmalloc(string,int) efuns. These two + * efuns basically allow you to cause certain malloc's and free's (with tags + * selected by a specified mask) to print debug information (addr, tag, + * description, size) to stdio (in the shell that invoked the driver) or to a + * file. Not defining this does reduce the overhead of DEBUGMALLOC from 16 + * bytes per malloc down to 8. This macro has no effect if DEBUGMALLOC isn't + * defined. + */ +#undef DEBUGMALLOC_EXTENSIONS + +/* CHECK_MEMORY: defining this (in addition to DEBUGMALLOC and + * DEBUGMALLOC_EXTENSIONS) causes the driver to check for memory + * corruption due to writing before the start or end of a block. This + * also adds the check_memory() efun. Takes a considerable ammount + * more memory. Mainly for debugging. + */ +#undef CHECK_MEMORY + +/**************************************************************************** + * COMPATIBILITY * + * --------------- * + * The MudOS driver has evolved quite a bit over the years. These defines * + * are mainly to preserve old behavior in case people didn't want to * + * rewrite the relevant portions of their code. * + * * + * In most cases, code which needs these defines should be rewritten when * + * possible. The 'Compat status' field is designed to give an idea how * + * likely it is that support for that option will be removed in the near * + * future. Certain options are fairly easy to work around, and double * + * the size of the associated code, as well as the maintenance workload, * + * and can make the code significantly more complex or harder to read, so * + * supporting them indefinitely is impractical. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* HAS_STATUS_TYPE: old MudOS drivers had a 'status' type which was + * identical to the 'int' type. Define this to bring it back. + * + * Compat status: very archaic, but easy to support. + */ +#undef HAS_STATUS_TYPE + +/* explode(): + * + * The old behavior (#undef both of the below) strips any number of + * delimiters at the start of the string, and one at the end. So + * explode("..x.y..z..", ".") gives ({ "x", "y", "", "z", "" }) + * + * SANE_EXPLODE_STRING strips off at most one leading delimiter, and + * still strips off one at the end, so the example above gives + * ({ "", "x", "y", "", "z", "" }). + * + * REVERSIBLE_EXPLODE_STRING overrides SANE_EXPLODE_STRING, and makes + * it so that implode(explode(x, y), y) is always x; i.e. no delimiters + * are ever stripped. So the example above gives + * ({ "", "", "x", "y", "", "z", "", "" }). + */ +#define SANE_EXPLODE_STRING +#undef REVERSIBLE_EXPLODE_STRING + +/* CAST_CALL_OTHERS: define this if you want to require casting of call_other's; + * this was the default behavior of the driver prior to this addition. + * + * Compat status: code that requires it doesn't break, and it promotes + * sloppy coding with no benefits. + */ +#undef CAST_CALL_OTHERS + +/* NONINTERACTIVE_STDERR_WRITE: if defined, all writes/tells/etc to + * noninteractive objects will be written to stderr prefixed with a ']' + * (old behavior). + * + * Compat status: Easy to support, and also on the "It's a bug! No, it's + * a feature!" religious war list. + */ +#undef NONINTERACTIVE_STDERR_WRITE + +/* NO_LIGHT: define this to disable the set_light() and driver maintenance + * of light levels in objects. You can simulate it via LPC if you want... + * + * Compat status: Very dated, easy to simulate, and gross. + */ +#define NO_LIGHT + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + * process_input() then becomes the only way to deal with player input. + * + * Compat status: next to impossible to simulate, hard to replace, and + * very, very widely used. + */ +#undef NO_ADD_ACTION + +/* NO_SNOOP: disables the snoop() efun and all related functionality. + */ +#undef NO_SNOOP + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + process_input() then becomes the only way to deal with player input. */ + +/* NO_ENVIRONMENT: define this to remove the handling of object containment + * relationships by the driver + * + * Compat status: hard to simulate efficiently, and very widely used. + */ +#undef NO_ENVIRONMENT + +/* NO_WIZARDS: for historical reasons, MudOS used to keep track of who + * is and isn't a wizard. Defining this removes that completely. + * If this is defined, the wizardp() and related efuns don't exist. + * + * Also note that if it is not defined, then non-wizards are always put + * in restricted mode when ed() is used, regardless of the setting of + * the restrict parameter. + * + * Compat status: easy to simulate and dated. + */ +#define NO_WIZARDS + +/* OLD_TYPE_BEHAVIOR: reintroduces a bug in type-checking that effectively + * renders compile time type checking useless. For backwards compatibility. + * + * Compat status: dealing with all the resulting compile errors can be + * a huge pain even if they are correct, and the impact on the code is + * small. + */ +#undef OLD_TYPE_BEHAVIOR + +/* OLD_RANGE_BEHAVIOR: define this if you want negative indexes in string + * or buffer range values (not lvalue, i.e. x[-2..-1]; for e.g. not + * x[-2..-1] = foo, the latter is always illegal) to mean counting from the + * end + * + * Compat status: Not horribly difficult to replace reliance on this, but not + * trivial, and cannot be simulated. + */ +#undef OLD_RANGE_BEHAVIOR + +/* OLD_ED: ed() efun backwards compatible with the old version. The new + * version requires/allows a mudlib front end. + * + * Compat status: Easily simulated. + */ +#define OLD_ED + +/* In ed auto-indent, + * 1) does the case line get indented after the switch() ? + * 2) How far do we indent? (this can also be set in the mudlib) + */ +#undef ED_INDENT_CASE +#define ED_INDENT_SPACES 4 + +/* SENSIBLE_MODIFIERS: + * Turning this on changes a few things, which may break old code: + * + * (1) 'static' is not recognized; either 'nosave' or 'protected' must + * be used instead. + * (2) The old meaning of 'public' is no longer allowed. Explicit + * functions must be defined at each level to allow access to + * privately inherited functions. + * (3) 'public' now means the default visibility. Previously there was + * no keyword that meant this (before you ask, 'public' meant something + * else, and if you don't know that, you probably don't have any reason + * to care about the old meaning). + */ +#undef SENSIBLE_MODIFIERS + +/**************************************************************************** + * MISCELLANEOUS * + * --------------- * + * Various options that affect the way the driver behaves. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* + * Define this in order to use Fermat@Equilibria's MD5 based crypt() instead + * of the operating system's. It has the advantage of giving the same value + * on all architectures, and being stronger than the standard UNIX crypt(). + */ +#define CUSTOM_CRYPT + +/* + * Some minor tweaks that make it a bit easier to run code designed to run + * on LPmud 3.2/3.2.1. Currently has the following effects: + * + * . m_indices() and m_values() are synonyms for keys() and values(), + * respectively + * . map_delete() returns it's first argument + * . inherit_list() means deep_inherit_list(), not shallow_inherit_list() + * . heart_beat_info() is a synonym for heart_beats() + */ +#undef COMPAT_32 + +/* + * Keep statistics about allocated strings, etc. Which can be viewed with + * the mud_status() efun. If this is off, mud_status() and memory_info() + * ignore allocated strings, but string operations run faster. + */ +#define STRING_STATS + +/* + * Similarly for arrays ... + */ +#define ARRAY_STATS + +/* LOG_CATCHES: define this to cause errors that are catch()'d to be + * sent to the debug log anyway. + * + * On by default, because newer libs use catch() a lot, and it's confusing + * if the errors don't show up in the logs. + */ +#define LOG_CATCHES + +/* ARGUMENTS_IN_TRACEBACK: prints out function call arguments in error + * tracebacks, to aid in debugging. Note: it prints the values of + * the arguments at the time of the error, not when the function + * was called. It looks like this: + * + * Failed to load file: read_buffer + * program: command/update.c, object: command/update line 15 + * ' commandHook' in ' clone/user.c' (' clone/user#1')line 72 + * arguments were ("/read_buffer.c") + * ' main' in ' command/update.c' (' command/update')line 15 + * arguments were ("/read_buffer.c") + * + * The only down side is some people like their logs shorter + */ +#define ARGUMENTS_IN_TRACEBACK + +/* LOCALS_IN_TRACEBACK: similar to ARGUMENTS_IN_TRACEBACK, but for local + * variables. The output looks more or less like: + * + * locals: 1, "local_value" + * + * Same as above. Tends to produce even longer logs, but very useful for + * tracking errors. + */ +#define LOCALS_IN_TRACEBACK + +/* MUDLIB_ERROR_HANDLER: If you define this, the driver doesn't do any + * handling of runtime errors, other than to turn the heartbeats of + * objects off. Information about the error is passed in a mapping + * to the error_handler() function in the master object. Whatever is + * returned is put in the debug.log. + * + * A good mudlib error handler is one of the best tools for tracking down + * errors. Unfortunately, you need to have one. Check the testsuite or + * other libs for an example. + */ +#define MUDLIB_ERROR_HANDLER + +/* CONFIG_FILE_DIR specifies a directory in which the driver will search for + * config files by default. If you don't wish to use this define, you may + * always specify a full path to the config file when starting the driver. + */ +#ifndef LATTICE +#define CONFIG_FILE_DIR "../etc" +#else +#define CONFIG_FILE_DIR "etc:" +#endif + +/* DEFAULT_PRAGMAS: This should be a sum of pragmas you want to always + * be on, i.e. + * + * #define DEFAULT_PRAGMAS PRAGMA_STRICT_TYPES + PRAGMA_SAVE_TYPES + * + * will make every LPC file behave as if it had the lines: + * #pragma strict_types + * #pragma save_types + * + * for no default pragmas: + * #define DEFAULT_PRAGMAS 0 + * + * If you don't know what these are, 0 is a good choice. + * + * Supported pragmas: + * PRAGMA_STRICT_TYPES: enforces strict type checking + * PRAGMA_WARNINGS: issues warnings about various dangerous things in + * your code + * PRAGMA_SAVE_TYPES: save the types of function arguments for checking + * calls to functions in this object by objects that + * inherit it. + * PRAGMA_SAVE_BINARY: save a compiled binary version of this file for + * faster loading next time it is needed. + * PRAGMA_OPTIMIZE: make a second pass over the generated code to + * optimize it further. Currently does jump threading. + * PRAGMA_ERROR_CONTEXT:include some text telling where on the line a + * compilation error occured. + */ +#define DEFAULT_PRAGMAS PRAGMA_WARNINGS + PRAGMA_STRICT_TYPES + PRAGMA_ERROR_CONTEXT + PRAGMA_SAVE_TYPES + +/* supress warnings about unused arguments; only warn about unused local + * variables. Makes older code (where argument names were required) compile + * more quietly. + */ +#define SUPPRESS_ARGUMENT_WARNINGS + +/* NO_RESETS: completely disable the periodic calling of reset() */ +#undef NO_RESETS + +/* LAZY_RESETS: if this is defined, an object will only have reset() + * called in it when it is touched via call_other() or move_object() + * (assuming enough time has passed since the last reset). If LAZY_RESETS + * is #undef'd, then reset() will be called as always (which guaranteed that + * reset would always be called at least once). The advantage of lazy + * resets is that reset doesn't get called in an object that is touched + * once and never again (which can save memory since some objects won't get + * reloaded that otherwise would). + */ +#undef LAZY_RESETS + +/* SAVE_EXTENSION: defines the file extension used by save_object(). + * and restore_object(). Some sysadmins run scripts that periodically + * scan for and remove files ending in .o (but many mudlibs are already + * set up to use .o thus we leave .o as the default). + */ +#define SAVE_EXTENSION ".o" + +/* NO_ANSI: define if you wish to disallow users from typing in commands that + * contain ANSI escape sequences. Defining NO_ANSI causes all escapes + * (ASCII 27) to be replaced with a space ' ' before the string is passed + * to the action routines added with add_action. + * + * STRIP_BEFORE_PROCESS_INPUT allows the location where the stripping is + * done to be controlled. If it is defined, then process_input() doesn't + * see ANSI characters either; if it is undefined ESC chars can be processed + * by process_input(), but are stripped before add_actions are called. + * Note that if NO_ADD_ACTION is defined, then #define NO_ANSI without + * #define STRIP_BEFORE_PROCESS_INPUT is the same as #undef NO_ANSI. + * + * If you anticipate problems with users intentionally typing in ANSI codes + * to make your terminal flash, etc define this. + */ +#undef NO_ANSI +#undef STRIP_BEFORE_PROCESS_INPUT + +/* OPCPROF: define this if you wish to enable OPC profiling. Allows a dump + * of the # of times each efun is invoked (via the opcprof() efun). + */ +#undef OPCPROF + +/* OPCPROF_2D: define this if you wish to enable 2-D OPC profiling. Allows a + * dump of the # of times each *pair* of eoperators is invoked. + * + * You can't use this and OPCPROF at the same time. + */ +#undef OPCPROF_2D + +/* TRAP_CRASHES: define this if you want MudOS to call crash() in master.c + * and then shutdown when signals are received that would normally crash the + * driver. + */ +#define TRAP_CRASHES + +/* THIS_PLAYER_IN_CALL_OUT: define this if you wish this_player() to be + * usable from within call_out() callbacks. + */ +#define THIS_PLAYER_IN_CALL_OUT + +/* CALLOUT_HANDLES: If this is defined, call_out() returns an integer, which + * can be passed to remove_call_out() or find_call_out(). Removing call_outs + * by name is still allowed, but is significantly less efficient, and also + * doesn't work for function pointers. This option adds 4 bytes overhead + * per callout to keep track of the handle. + */ +#define CALLOUT_HANDLES + +/* FLUSH_OUTPUT_IMMEDIATELY: Causes output to be written to sockets + * immediately after being generated. Useful for debugging. + */ +#undef FLUSH_OUTPUT_IMMEDIATELY + +/* PRIVS: define this if you want object privileges. Your mudlib must + * explicitly make use of this functionality to be useful. Defining this + * this will increase the size of the object structure by 4 bytes (8 bytes + * on the DEC Alpha) and will add a new master apply during object creation + * to "privs_file". In general, privileges can be used to increase the + * granularity of security beyond the current root uid mechanism. + * + * [NOTE: for those who'd rather do such things at the mudlib level, look at + * the inherits() efun and the 'valid_object' apply to master.] + */ +#define PRIVS + +/* INTERACTIVE_CATCH_TELL: define this if you want catch_tell called on + * interactives as well as NPCs. If this is defined, user.c will need a + * catch_tell(msg) method that calls receive(msg); +*/ +#define INTERACTIVE_CATCH_TELL + +/* RECEIVE_ED: define this if you want normal ed output to go to a + receive_ed() apply in the player ob. Some errors still go directly + to output. Useful for post-processing (perhaps colorizing?) ed + output. Prototype: mixed receive_ed(string txt, string fname); + If fname, return a string that ed will output, 0 to let ed handle + the output in the default way, or 1 to handle the output yourself. + If fname == 0, output is help text and you may return any of the above + or an array of strings that will be more'ed. +*/ +#undef RECEIVE_ED + +/* RESTRICTED_ED: define this if you want restricted ed mode enabled. + */ +#define RESTRICTED_ED + +/* NO_SHADOWS: define this if you want to disable shadows in your driver. + */ +#undef NO_SHADOWS + +/* SNOOP_SHADOWED: define this if you want snoop to report what is + * sent to the player even in the event that the player's catch_tell() is + * shadowed and the player may not be seeing what is being sent. Messages + * of this sort will be prefixed with $$. + */ +#undef SNOOP_SHADOWED + +/* RECEIVE_SNOOP: define this if you want snoop text to be sent to + * the receive_snoop() function in the snooper object (instead of being + * sent directly via add_message()). This is useful if you want to + * build a smart client that does something different with snoop messages. + */ +#undef RECEIVE_SNOOP + +/* PROFILE_FUNCTIONS: define this to be able to measure the CPU time used by + * all of the user-defined functions in each LPC object. Note: defining + * this adds three long ints (12 bytes on 32-bit machines) to the function + * header structs. Also note that the resolution of the getrusage() timer + * may not be high enough on some machines to give non-zero execution + * times to very small (fast) functions. In particular if the clock + * resolution is 1/60 of a second, then any time less than approxmately 15k + * microseconds will resolve to zero (0). + */ +#define PROFILE_FUNCTIONS + +/* NO_BUFFER_TYPE: if this is #define'd then LPC code using the 'buffer' + * type won't be allowed to compile (since the 'buffer' type won't be + * recognized by the lexer). + */ +#undef NO_BUFFER_TYPE + +/* BINARIES: define this to enable the 'save_binary' pragma. + * This pragma, when set in a program, will cause it to save a + * binary image when loaded, so that subsequent loadings will + * be much faster. The binaries are saved in the directory + * specified in the configuration file. The binaries will not + * load if the LPC source or any of the inherited or included + * files are out of date, in which case the file is compiled + * normally (and may save a new binary). + * + * In order to save the binary, valid_save_binary() is called + * in master.c, and is passed the name of the source file. If + * this returns a non-zero value, the binary is allowed to be + * saved. Allowing any file by any wizard to be saved as a + * binary is convenient, but may take up a lot of disk space. + */ +#define BINARIES + +/* ARRAY_RESERVED_WORD: If this is defined then the word 'array' can + * be used to define arrays, as in: + * + * int array x = ({ .... }); + * + * A side effect is that 'array' cannot be a variable or function name. + */ +#define ARRAY_RESERVED_WORD + +/* REF_RESERVED_WORD: If this is defined then the word 'ref' can be + * used to pass arguments to functions by value. Example: + * + * void inc(int ref x) { + * x++; + * } + * + * ... y = 1; inc(ref y); ... + * + * A side effect is that 'ref' cannot be a variable or function name. + * + * Note: ref must be used in *both* places; this is intentional. It protects + * against passing references to routines which don't intend to return values + * through their arguments, and against forgetting to pass a reference + * to a function which wants one (or accidentally having a variable modified!) + */ +#define REF_RESERVED_WORD + +/**************************************************************************** + * PACKAGES * + * -------- * + * Defining some/all of the following add certain efuns, and sometimes * + * add/remove code from the driver. * + * * + * if PACKAGE_XYZZY is defined here, then the code in packages/xyzzy.c * + * and the efuns in packages/xyzzy_spec.c will be added to the driver. * + ****************************************************************************/ + +/* various miscellaneous efuns */ +#define PACKAGE_CONTRIB + +/* efuns that are only of use to those that know something about driver + internals */ +#define PACKAGE_DEVELOP + +/* PACKAGE_MATH: determines whether or not the math efuns (for floats) are + included. + */ +#define PACKAGE_MATH + +/* PACKAGE_MATRIX: determines whether or not the 3d graphics efuns (for floats) + * are included - see packages/matrix.spec for a list. + */ +#undef PACKAGE_MATRIX + +/* PACKAGE_MUDLIB_STATS: define this to enable domain and author stats + * maintenance by the driver. These mudlib stats are more domain + * based than user based, and replaces the traditional wiz_list stats. + */ +#undef PACKAGE_MUDLIB_STATS + +/* PACKAGE_SOCKETS: define this to enable the socket efunctions. This + * causes HAS_SOCKETS to be defined for all LPC objects. + */ +#define PACKAGE_SOCKETS + +/* PACKAGE_PARSER: Natural language parsing efuns for interactive fiction + * type applications + */ +#define PACKAGE_PARSER + +/* PACKAGE_EXTERNAL: Allows the driver to exec() commands specified in the + * config file. + */ +#undef PACKAGE_EXTERNAL + +/* NUM_EXTERNAL_CMDS: the number of external commands supported */ +#ifdef PACKAGE_EXTERNAL +#define NUM_EXTERNAL_CMDS 100 +#else +#define NUM_EXTERNAL_CMDS 0 +#endif + +/* PACKAGE_DB: efuns for external database access using msql */ +#undef PACKAGE_DB + +/* If PACKAGE_DB is defined above, you must pick ONE of the following supported + * databases + */ +#ifdef PACKAGE_DB +#undef USE_MSQL +#undef MSQL +#define USE_MYSQL 2 +#define MY_SQL +#endif + +/*PACKAGE DWLIB: some discworld mudlib simuls coded in C (well just one right + now) */ + +#undef PACKAGE_DWLIB + +/**************************************************************************** + * UID PACKAGE * + * ----------- * + * UIDS are the basis for some mudlib security systems. Basically, they're * + * preserved for backwards compatibility, as several ways of breaking * + * almost any system which relies on them are known. (No, it's not a flaw * + * of uids; only that b/c of the ease with which LPC objects can call * + * each other, it's far too easy to leave holes) * + * * + * If you don't care about security, the first option is probably what you * + * want. * + ****************************************************************************/ + +/* + * PACKAGE_UIDS: define this if you want a driver that does use uids. + * + */ +#undef PACKAGE_UIDS + +/* AUTO_SETEUID: when an object is created it's euid is automatically set to + * the equivalent of seteuid(getuid(this_object())). undef AUTO_SETEUID + * if you would rather have the euid of the created object be set to 0. + */ +#undef AUTO_SETEUID + +/* AUTO_TRUST_BACKBONE: define this if you want objects with the backbone + * uid to automatically be trusted and to have their euid set to the uid of + * the object that forced the object's creation. + */ +#undef AUTO_TRUST_BACKBONE + +/************************************************************************* + * FOR EXPERIENCED USERS * + * ----------------------- * + * Most of these options will probably be of no interest to many users. * + *************************************************************************/ + +/* USE_32BIT_ADDRESSES: Use 32 bits for addresses of function, instead of + * the usual 16 bits. This increases the maximum program size from 64k + * of LPC bytecode (NOT source) to 4 GB. Branches are still 16 bits, + * imposing a 64k limit on catch(), if(), switch(), loops, and most other + * control structures. It would take an extremely large function to hit + * those limits, though. + * + * Overhead: 2 bytes/function with LPC->C off. Having LPC->C on forces + * this option, since it needs 4 bytes to store the function pointers + * anyway, and this setting is ignored. + */ +#define USE_32BIT_ADDRESSES + +/* HEARTBEAT_INTERVAL: define heartbeat interval in microseconds (us). + * 1,000,000 us = 1 second. The value of this macro specifies + * the frequency with which the heart_beat method will be called in + * those LPC objects which have called set_heart_beat(1). + * + * [NOTE: if ualarm() isn't available, alarm() is used instead. Since + * alarm() requires its argument in units of a second, we map 1 - 1,000,000 us + * to an actual interval of one (1) second and 1,000,001 - 2,000,000 maps to + * an actual interval of two (2) seconds, etc.] + */ +#define HEARTBEAT_INTERVAL 2 + +/* + * CALLOUT_CYCLE_SIZE: This is the number of slots in the call_out list. + * It should be approximately the average number of active call_outs, or + * a few times smaller. It should also be a power of 2, and also be relatively + * prime to any common call_out lengths. If all this is too confusing, 32 + * isn't a bad number :-) + */ +#define CALLOUT_CYCLE_SIZE 64 + +/* LARGEST_PRINTABLE_STRING: defines the size of the vsprintf() buffer in + * comm.c's add_message(). Instead of blindly making this value larger, + * your mudlib should be coded to not send huge strings to users. + */ +#define LARGEST_PRINTABLE_STRING 8192 + +/* MESSAGE_BUFFER_SIZE: determines the size of the buffer for output that + * is sent to users. + */ +#define MESSAGE_BUFFER_SIZE 4096 + +/* APPLY_CACHE_BITS: defines the number of bits to use in the call_other cache + * (in interpret.c). + * + * Memory overhead is (1 << APPLY_CACHE_BITS)*16. + * [assuming 32 bit pointers and 16 bit shorts] + * + * ACB: entries: overhead: + * 6 64 1k + * 8 256 4k + * 10 1024 16k + * 12 4096 64k + * 14 16384 256k + * 16 65536 1M + */ +#define APPLY_CACHE_BITS 14 + +/* CACHE_STATS: define this if you want call_other (apply_low) cache + * statistics. Causes HAS_CACHE_STATS to be defined in all LPC objects. + */ +#define CACHE_STATS + +/* TRACE: define this to enable the trace() and traceprefix() efuns. + * (keeping this undefined will cause the driver to run faster). + */ +#undef TRACE + +/* LPC_TO_C: define this to enable LPC->C compilation. + * + * [NOTE: BINARIES must also be defined for LPC->C to work. Actually + * using binaries is not required, though.] + */ +#undef LPC_TO_C + +/* RUNTIME_LOADING: On systems which support it, it allows LPC->C compilation + * 'on the fly' without having to recompile the driver. + * + * Note: This currently only works on machines that have the dlopen() system + * call. SunOS and IRIX do, as do a number of others. AIX and Ultrix don't. + * Linux does if you are using ELF. + */ +#undef RUNTIME_LOADING + +/* TRACE_CODE: define this to enable code tracing (the driver will print + * out the previous lines of code to an error) eval_instruction() runs about + * twice as fast when this is not defined (for the most common eoperators). + */ +#define TRACE_CODE + +/* HEART_BEAT_CHUNK: The number of heart_beat chunks allocated at a time. + * A large number wastes memory as some will be sitting around unused, while + * a small one wastes more CPU reallocating when it needs to grow. Default + * to a medium value. + */ +#define HEART_BEAT_CHUNK 64 + +/* SERVER_IP: For machines with multiple IP addresses, this specifies which + * one to use. This is useful for IP accounting and is necessary to be + * able to do ident lookups on such machines. + * + * example: #define SERVER_IP "194.229.18.27" + */ +#define SERVER_IP "192.168.2.2" + +/* Some maximum string sizes + */ +#define SMALL_STRING_SIZE 100 +#define LARGE_STRING_SIZE 1000 +#define COMMAND_BUF_SIZE 2000 + +/* Number of levels of nested datastructures allowed -- this limit prevents + * crashes from occuring when saving objects containing variables containing + * recursive datastructures (with circular references). + */ +#define MAX_SAVE_SVALUE_DEPTH 100 + +/* Miscellaneous config options that should probably be in the runtime + * config file. + */ +/* MAX_LOCAL: maximum number of local variables allowed per LPC function */ +#define CFG_MAX_LOCAL_VARIABLES 50 +/* Increasing max global vars beyond 256 is not recommended */ +#define CFG_MAX_GLOBAL_VARIABLES 256 + +#define CFG_EVALUATOR_STACK_SIZE 3000000 +#define CFG_COMPILER_STACK_SIZE 600000 +#define CFG_MAX_CALL_DEPTH 150 +/* This must be one of 4, 16, 64, 256, 1024, 4096 */ +#define CFG_LIVING_HASH_SIZE 256 + +/* NEXT_MALLOC_DEBUG: define this if using a NeXT and you want to enable + * the malloc_check() and/or malloc_debug() efuns. Run the 'man malloc_debug' + * command on the NeXT to find out what the arguments to malloc_debug(int) + * mean. The malloc_check() efun calls the NeXT NXMallocCheck() system + * call which does a consistency check on malloc's data structures (this + * consistency check is done at each malloc() and free() for certain + * malloc_debug() levels). A non-zero return value indicates there was + * a consistency problem. For those NeXT users wanting a bit more + * performance out of malloc, try defining NEXT_MALLOC_DEBUG and calling the + * malloc_debug(-1) efun (with an arg of -1). This will turn all + * malloc debugging off and call malloc_singlethreaded() which the NeXT + * malloc man page claims can make NeXT system malloc 10% to 15% faster. + * + * [NOTE: This #define has no affect on the driver if not using the + * NeXTSTEP OS.] + * + * Warning: if you use a NeXT and define NEXT_MALLOC_DEBUG, be sure to + * protect the use of the malloc_check() and malloc_debug() efuns + * since setting certain debug levels can cause malloc() and free() + * to become _very_ slow (protect efuns by using simul_efuns and + * valid_override). + * + * [NOTE: malloc_debug(6) is a good compromise between efficiency and + * completeness of malloc debugging (malloc/free will be about half as fast).] + */ +#undef NEXT_MALLOC_DEBUG + + +/* GET_CHAR_IS_BUFFERED: Normally get_char() is unbuffered. That is, once + * a character is received for get_char(), anything else is in the input + * stream is immediately thrown away. This can be very undesirable, especially + * if you're calling get_char() again from the handler from the previous call. + * Define this if you want get_char() to be buffered. In this case, the buffer + * will only get flushed if get_char() is not called from the first get_char()'s + * LPC callback handler. + */ +#undef GET_CHAR_IS_BUFFERED + +/* PACKAGE_COMPRESS: Enable MCCP support and compressed save files + SAVE_GZ_EXTENSION: save extension for compressed files + */ +#define HAVE_ZLIB +#define PACKAGE_COMPRESS +#define SAVE_GZ_EXTENSION ".o.gz" + +/* CALL_OTHER_TYPE_CHECK: enable type checking for call_other() + * (-> operator on objects) + */ +#undef CALL_OTHER_TYPE_CHECK + +/* CALL_OTHER_WARN, make it warning instead of errors */ +#define CALL_OTHER_WARN + +/* WARN_TAB: Some versions of the editor built in indent function use + * tabs for indenting. This options turns on a warning message for + * files indented with tabs instead of spaces. + */ +#undef WARN_TAB + +/* USE_ICONV: Use iconv to translate input and output from/to the users char + * encoding + */ +#undef USE_ICONV + +/* WOMBLES: don't allow spaces between start/end of array/mapping/functional token chars so ({1,2,3}) still works, + but ( { 1 , 2 , 3 } ) doesn't and ({ 1 , 2 , 3 }) does. + */ +#undef WOMBLES + +/* ALLOW_INHERIT_AFTER_FUNCTION: allow inheriting after functions have been defined (this includes prototypes). This caused +crashes +in v22.2a but it may have been fixed since */ +#undef ALLOW_INHERIT_AFTER_FUNCTION +#undef ALLOW_INHERIT_AFTER_GLOBAL_VARIABLES + +/*PACKAGE_ASYNC: adds some efuns for asyncronous IO */ +#undef PACKAGE_ASYNC + +#undef PARSE_DEBUG +#define FLUFFOS + +/* PROG_REF_TYPE size of program ref counter: + * char for 8 bit, short for 16, int for 32, + * long long for 64 (completely useless on 32 bit machines though!) */ +#define PROG_REF_TYPE int +#undef PACKAGE_DSLIB +#define HAS_CONSOLE +#undef ANSI_SUBSTITUTE +#endif +#undef IPV6 +#undef MALLOC64 +#undef PACKAGE_CRYPTO +#undef PACKAGE_SHA1 diff --git a/fluffos-2.23-ds03/local_options.skylib b/fluffos-2.23-ds03/local_options.skylib new file mode 100644 index 0000000..8f052df --- /dev/null +++ b/fluffos-2.23-ds03/local_options.skylib @@ -0,0 +1,893 @@ +/* + * options.h: defines for the compile-time configuration of the MudOS driver + */ + +#ifndef _OPTIONS_H_ +#define _OPTIONS_H_ +#endif + +/* + * YOU PROBABLY DO NOT WANT TO MODIFY THIS FILE. + * + * Do 'cp options.h local_options' and edit that instead. local_options, + * if it exists, overrides this file. + * + * The advantage is that when you upgrade to a newer MudOS driver, you can + * simply copy your local_options file into the src directory. The build + * process will warn you if new options have been added that you should + * choose settings for. + */ + +/**************************************************************************** + * EVERY time you change ANYTHING in this file, RECOMPILE from scratch. * + * (type "make clean" then "make" on a UNIX system) Failure to do so may * + * cause the driver to behave oddly. * + ****************************************************************************/ + +/* NOTES: + * Many of the configurable options are now set via the configuration file + * that is specified as the first argument to the driver. + * See port.h for those #defines related to portability (compatibility) if + * you have problems compiling on your system. + * Removing an efun from func_spec.c usually removes most, if not all, + * of the code associated with it. + * Note that anything defined in this file is also visible to LPC files + * surrounded by __. So #define FOO in this file defines __FOO__ for + * all LPC files. This allows code like: + * + * #ifdef __SENSIBLE_MODIFIERS__ + * ... + */ + +/**************************************************************************** + * MALLOC * + * -------- * + * For performance reasons, LP drivers have a variety of memory allocation * + * packages. If you don't care, use the default one on your system: * + * #define SYSMALLOC, #undef the others. * + ****************************************************************************/ + +/* You must choose exactly one of these malloc packages: + * ~~~~ + * SYSMALLOC: + * * Built-in system malloc. + * * No statistics. + * * SYSMALLOC incurs no additional CPU or memory overhead. + * + * SMALLOC: + * * Satoria's smalloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than most system mallocs with modest ammount of memory overhead. + * * Can fall back onto system malloc if sbrk() not ok. + * + * BSDMALLOC: + * * BSD (Berkeley Software Distributions) malloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than SMALLOC but more memory overhead. + * * Requires sbrk(). + */ +#define SYSMALLOC +#undef SMALLOC +#undef BSDMALLOC +#undef MMALLOC + +/* You may optionally choose one (or none) of these malloc wrappers. These + * can be used in conjunction with any of the above malloc packages. + * + * WRAPPEDMALLOC: + * * Limited statistics. + * * Limited additional cpu overhead and no additional memory overhead. + * + * DEBUGMALLOC: + * * Statistics on precisely how much memory has been malloc'd (as well + * as the stats provided by WRAPPEDMALLOC). + * * Incurs a fair amount of overhead (both memory and CPU) + */ +#undef WRAPPEDMALLOC +#undef DEBUGMALLOC + +/* The following add certain bells and whistles to malloc: */ + +/* + * SBRK_OK: do not define this unless SMALLOC is chosen above. + * Defining this causes smalloc to use the low level memory allocation + * routines, and to act as a malloc replacement. Conversely, undef'ing + * SBRK_OK causes smalloc to act as a wrapper for the system malloc + * routines. + * + * Note: + * NeXTStep 3.x users should always #undef SBRK_OK. + */ +#undef SBRK_OK + +/* DO_MSTATS: do not define this unless BSDMALLOC or SMALLOC is chosen above. + * Defining this causes those replacement mallocs to keep statistics that + * the malloc_status() efun will print out (including total memory + * allocated/used). + */ +#undef DO_MSTATS + +/* DEBUGMALLOC_EXTENSIONS: defining this (in addition to DEBUGMALLOC) enables + * the set_malloc_mask(int) and debugmalloc(string,int) efuns. These two + * efuns basically allow you to cause certain malloc's and free's (with tags + * selected by a specified mask) to print debug information (addr, tag, + * description, size) to stdio (in the shell that invoked the driver) or to a + * file. Not defining this does reduce the overhead of DEBUGMALLOC from 16 + * bytes per malloc down to 8. This macro has no effect if DEBUGMALLOC isn't + * defined. + */ +#undef DEBUGMALLOC_EXTENSIONS + +/* CHECK_MEMORY: defining this (in addition to DEBUGMALLOC and + * DEBUGMALLOC_EXTENSIONS) causes the driver to check for memory + * corruption due to writing before the start or end of a block. This + * also adds the check_memory() efun. Takes a considerable ammount + * more memory. Mainly for debugging. + */ +#undef CHECK_MEMORY + +/**************************************************************************** + * COMPATIBILITY * + * --------------- * + * The MudOS driver has evolved quite a bit over the years. These defines * + * are mainly to preserve old behavior in case people didn't want to * + * rewrite the relevant portions of their code. * + * * + * In most cases, code which needs these defines should be rewritten when * + * possible. The 'Compat status' field is designed to give an idea how * + * likely it is that support for that option will be removed in the near * + * future. Certain options are fairly easy to work around, and double * + * the size of the associated code, as well as the maintenance workload, * + * and can make the code significantly more complex or harder to read, so * + * supporting them indefinitely is impractical. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* HAS_STATUS_TYPE: old MudOS drivers had a 'status' type which was + * identical to the 'int' type. Define this to bring it back. + * + * Compat status: very archaic, but easy to support. + */ +#undef HAS_STATUS_TYPE + +/* explode(): + * + * The old behavior (#undef both of the below) strips any number of + * delimiters at the start of the string, and one at the end. So + * explode("..x.y..z..", ".") gives ({ "x", "y", "", "z", "" }) + * + * SANE_EXPLODE_STRING strips off at most one leading delimiter, and + * still strips off one at the end, so the example above gives + * ({ "", "x", "y", "", "z", "" }). + * + * REVERSIBLE_EXPLODE_STRING overrides SANE_EXPLODE_STRING, and makes + * it so that implode(explode(x, y), y) is always x; i.e. no delimiters + * are ever stripped. So the example above gives + * ({ "", "", "x", "y", "", "z", "", "" }). + */ +#undef SANE_EXPLODE_STRING +#undef REVERSIBLE_EXPLODE_STRING + +/* CAST_CALL_OTHERS: define this if you want to require casting of call_other's; + * this was the default behavior of the driver prior to this addition. + * + * Compat status: code that requires it doesn't break, and it promotes + * sloppy coding with no benefits. + */ +#undef CAST_CALL_OTHERS + +/* NONINTERACTIVE_STDERR_WRITE: if defined, all writes/tells/etc to + * noninteractive objects will be written to stderr prefixed with a ']' + * (old behavior). + * + * Compat status: Easy to support, and also on the "It's a bug! No, it's + * a feature!" religious war list. + */ +#undef NONINTERACTIVE_STDERR_WRITE + +/* NO_LIGHT: define this to disable the set_light() and driver maintenance + * of light levels in objects. You can simulate it via LPC if you want... + * + * Compat status: Very dated, easy to simulate, and gross. + */ +#define NO_LIGHT + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + * process_input() then becomes the only way to deal with player input. + * + * Compat status: next to impossible to simulate, hard to replace, and + * very, very widely used. + */ +#define NO_ADD_ACTION + +/* NO_SNOOP: disables the snoop() efun and all related functionality. + */ +#undef NO_SNOOP + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + process_input() then becomes the only way to deal with player input. */ + +/* NO_ENVIRONMENT: define this to remove the handling of object containment + * relationships by the driver + * + * Compat status: hard to simulate efficiently, and very widely used. + */ +#undef NO_ENVIRONMENT + +/* NO_WIZARDS: for historical reasons, MudOS used to keep track of who + * is and isn't a wizard. Defining this removes that completely. + * If this is defined, the wizardp() and related efuns don't exist. + * + * Also note that if it is not defined, then non-wizards are always put + * in restricted mode when ed() is used, regardless of the setting of + * the restrict parameter. + * + * Compat status: easy to simulate and dated. + */ +#define NO_WIZARDS + +/* OLD_TYPE_BEHAVIOR: reintroduces a bug in type-checking that effectively + * renders compile time type checking useless. For backwards compatibility. + * + * Compat status: dealing with all the resulting compile errors can be + * a huge pain even if they are correct, and the impact on the code is + * small. + */ +#undef OLD_TYPE_BEHAVIOR + +/* OLD_RANGE_BEHAVIOR: define this if you want negative indexes in string + * or buffer range values (not lvalue, i.e. x[-2..-1]; for e.g. not + * x[-2..-1] = foo, the latter is always illegal) to mean counting from the + * end + * + * Compat status: Not horribly difficult to replace reliance on this, but not + * trivial, and cannot be simulated. + */ +#undef OLD_RANGE_BEHAVIOR + +/* OLD_ED: ed() efun backwards compatible with the old version. The new + * version requires/allows a mudlib front end. + * + * Compat status: Easily simulated. + */ +#define OLD_ED + +/* SENSIBLE_MODIFIERS: + * Turning this on changes a few things, which may break old code: + * + * (1) 'static' is not recognized; either 'nosave' or 'protected' must + * be used instead. + * (2) The old meaning of 'public' is no longer allowed. Explicit + * functions must be defined at each level to allow access to + * privately inherited functions. + * (3) 'public' now means the default visibility. Previously there was + * no keyword that meant this (before you ask, 'public' meant something + * else, and if you don't know that, you probably don't have any reason + * to care about the old meaning). + */ +#define SENSIBLE_MODIFIERS + +/**************************************************************************** + * MISCELLANEOUS * + * --------------- * + * Various options that affect the way the driver behaves. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* + * Define this in order to use Fermat@Equilibria's MD5 based crypt() instead + * of the operating system's. It has the advantage of giving the same value + * on all architectures, and being stronger than the standard UNIX crypt(). + */ +#define CUSTOM_CRYPT + +/* + * Some minor tweaks that make it a bit easier to run code designed to run + * on LPmud 3.2/3.2.1. Currently has the following effects: + * + * . m_indices() and m_values() are synonyms for keys() and values(), + * respectively + * . map_delete() returns it's first argument + * . inherit_list() means deep_inherit_list(), not shallow_inherit_list() + * . heart_beat_info() is a synonym for heart_beats() + */ +#undef COMPAT_32 + +/* + * Keep statistics about allocated strings, etc. Which can be viewed with + * the mud_status() efun. If this is off, mud_status() and memory_info() + * ignore allocated strings, but string operations run faster. + */ +#define STRING_STATS + +/* + * Similarly for arrays ... + */ +#define ARRAY_STATS + +/* LOG_CATCHES: define this to cause errors that are catch()'d to be + * sent to the debug log anyway. + * + * On by default, because newer libs use catch() a lot, and it's confusing + * if the errors don't show up in the logs. + */ +#define LOG_CATCHES + +/* ARGUMENTS_IN_TRACEBACK: prints out function call arguments in error + * tracebacks, to aid in debugging. Note: it prints the values of + * the arguments at the time of the error, not when the function + * was called. It looks like this: + * + * Failed to load file: read_buffer + * program: command/update.c, object: command/update line 15 + * ' commandHook' in ' clone/user.c' (' clone/user#1')line 72 + * arguments were ("/read_buffer.c") + * ' main' in ' command/update.c' (' command/update')line 15 + * arguments were ("/read_buffer.c") + * + * The only down side is some people like their logs shorter + */ +#define ARGUMENTS_IN_TRACEBACK + +/* LOCALS_IN_TRACEBACK: similar to ARGUMENTS_IN_TRACEBACK, but for local + * variables. The output looks more or less like: + * + * locals: 1, "local_value" + * + * Same as above. Tends to produce even longer logs, but very useful for + * tracking errors. + */ +#define LOCALS_IN_TRACEBACK + +/* MUDLIB_ERROR_HANDLER: If you define this, the driver doesn't do any + * handling of runtime errors, other than to turn the heartbeats of + * objects off. Information about the error is passed in a mapping + * to the error_handler() function in the master object. Whatever is + * returned is put in the debug.log. + * + * A good mudlib error handler is one of the best tools for tracking down + * errors. Unfortunately, you need to have one. Check the testsuite or + * other libs for an example. + */ +#define MUDLIB_ERROR_HANDLER + +/* CONFIG_FILE_DIR specifies a directory in which the driver will search for + * config files by default. If you don't wish to use this define, you may + * always specify a full path to the config file when starting the driver. + */ +#define CONFIG_FILE_DIR "/home/atuin/bin" + +/* DEFAULT_PRAGMAS: This should be a sum of pragmas you want to always + * be on, i.e. + * + * #define DEFAULT_PRAGMAS PRAGMA_STRICT_TYPES + PRAGMA_SAVE_TYPES + * + * will make every LPC file behave as if it had the lines: + * #pragma strict_types + * #pragma save_types + * + * for no default pragmas: + * #define DEFAULT_PRAGMAS 0 + * + * If you don't know what these are, 0 is a good choice. + * + * Supported pragmas: + * PRAGMA_STRICT_TYPES: enforces strict type checking + * PRAGMA_WARNINGS: issues warnings about various dangerous things in + * your code + * PRAGMA_SAVE_TYPES: save the types of function arguments for checking + * calls to functions in this object by objects that + * inherit it. + * PRAGMA_SAVE_BINARY: save a compiled binary version of this file for + * faster loading next time it is needed. + * PRAGMA_OPTIMIZE: make a second pass over the generated code to + * optimize it further. Currently does jump threading. + * PRAGMA_ERROR_CONTEXT:include some text telling where on the line a + * compilation error occured. + */ +#define DEFAULT_PRAGMAS PRAGMA_WARNINGS + PRAGMA_STRICT_TYPES + PRAGMA_ERROR_CONTEXT + +/* supress warnings about unused arguments; only warn about unused local + * variables. Makes older code (where argument names were required) compile + * more quietly. + */ +#define SUPPRESS_ARGUMENT_WARNINGS + +/* NO_RESETS: completely disable the periodic calling of reset() */ +#undef NO_RESETS + +/* LAZY_RESETS: if this is defined, an object will only have reset() + * called in it when it is touched via call_other() or move_object() + * (assuming enough time has passed since the last reset). If LAZY_RESETS + * is #undef'd, then reset() will be called as always (which guaranteed that + * reset would always be called at least once). The advantage of lazy + * resets is that reset doesn't get called in an object that is touched + * once and never again (which can save memory since some objects won't get + * reloaded that otherwise would). + */ +#undef LAZY_RESETS + +/* SAVE_EXTENSION: defines the file extension used by save_object(). + * and restore_object(). Some sysadmins run scripts that periodically + * scan for and remove files ending in .o (but many mudlibs are already + * set up to use .o thus we leave .o as the default). + */ +#define SAVE_EXTENSION ".o" + +/* NO_ANSI: define if you wish to disallow users from typing in commands that + * contain ANSI escape sequences. Defining NO_ANSI causes all escapes + * (ASCII 27) to be replaced with a space ' ' before the string is passed + * to the action routines added with add_action. + * + * STRIP_BEFORE_PROCESS_INPUT allows the location where the stripping is + * done to be controlled. If it is defined, then process_input() doesn't + * see ANSI characters either; if it is undefined ESC chars can be processed + * by process_input(), but are stripped before add_actions are called. + * Note that if NO_ADD_ACTION is defined, then #define NO_ANSI without + * #define STRIP_BEFORE_PROCESS_INPUT is the same as #undef NO_ANSI. + * + * If you anticipate problems with users intentionally typing in ANSI codes + * to make your terminal flash, etc define this. + */ +#define NO_ANSI +#define STRIP_BEFORE_PROCESS_INPUT + +/* OPCPROF: define this if you wish to enable OPC profiling. Allows a dump + * of the # of times each efun is invoked (via the opcprof() efun). + */ +#undef OPCPROF + +/* OPCPROF_2D: define this if you wish to enable 2-D OPC profiling. Allows a + * dump of the # of times each *pair* of eoperators is invoked. + * + * You can't use this and OPCPROF at the same time. + */ +#undef OPCPROF_2D + +/* TRAP_CRASHES: define this if you want MudOS to call crash() in master.c + * and then shutdown when signals are received that would normally crash the + * driver. + */ +#define TRAP_CRASHES + +/* THIS_PLAYER_IN_CALL_OUT: define this if you wish this_player() to be + * usable from within call_out() callbacks. + */ +#define THIS_PLAYER_IN_CALL_OUT + +/* CALLOUT_HANDLES: If this is defined, call_out() returns an integer, which + * can be passed to remove_call_out() or find_call_out(). Removing call_outs + * by name is still allowed, but is significantly less efficient, and also + * doesn't work for function pointers. This option adds 4 bytes overhead + * per callout to keep track of the handle. + */ +#define CALLOUT_HANDLES + +/* FLUSH_OUTPUT_IMMEDIATELY: Causes output to be written to sockets + * immediately after being generated. Useful for debugging. + */ +#undef FLUSH_OUTPUT_IMMEDIATELY + +/* PRIVS: define this if you want object privileges. Your mudlib must + * explicitly make use of this functionality to be useful. Defining this + * this will increase the size of the object structure by 4 bytes (8 bytes + * on the DEC Alpha) and will add a new master apply during object creation + * to "privs_file". In general, privileges can be used to increase the + * granularity of security beyond the current root uid mechanism. + * + * [NOTE: for those who'd rather do such things at the mudlib level, look at + * the inherits() efun and the 'valid_object' apply to master.] + */ +#undef PRIVS + +/* INTERACTIVE_CATCH_TELL: define this if you want catch_tell called on + * interactives as well as NPCs. If this is defined, user.c will need a + * catch_tell(msg) method that calls receive(msg); +*/ +#undef INTERACTIVE_CATCH_TELL + +/* RESTRICTED_ED: define this if you want restricted ed mode enabled. + */ +#define RESTRICTED_ED + +/* NO_SHADOWS: define this if you want to disable shadows in your driver. + */ +#undef NO_SHADOWS + +/* SNOOP_SHADOWED: define this if you want snoop to report what is + * sent to the player even in the event that the player's catch_tell() is + * shadowed and the player may not be seeing what is being sent. Messages + * of this sort will be prefixed with $$. + */ +#undef SNOOP_SHADOWED + +/* RECEIVE_SNOOP: define this if you want snoop text to be sent to + * the receive_snoop() function in the snooper object (instead of being + * sent directly via add_message()). This is useful if you want to + * build a smart client that does something different with snoop messages. + */ +#define RECEIVE_SNOOP + +/* PROFILE_FUNCTIONS: define this to be able to measure the CPU time used by + * all of the user-defined functions in each LPC object. Note: defining + * this adds three long ints (12 bytes on 32-bit machines) to the function + * header structs. Also note that the resolution of the getrusage() timer + * may not be high enough on some machines to give non-zero execution + * times to very small (fast) functions. In particular if the clock + * resolution is 1/60 of a second, then any time less than approxmately 15k + * microseconds will resolve to zero (0). + */ +#undef PROFILE_FUNCTIONS + +/* NO_BUFFER_TYPE: if this is #define'd then LPC code using the 'buffer' + * type won't be allowed to compile (since the 'buffer' type won't be + * recognized by the lexer). + */ +#undef NO_BUFFER_TYPE + +/* BINARIES: define this to enable the 'save_binary' pragma. + * This pragma, when set in a program, will cause it to save a + * binary image when loaded, so that subsequent loadings will + * be much faster. The binaries are saved in the directory + * specified in the configuration file. The binaries will not + * load if the LPC source or any of the inherited or included + * files are out of date, in which case the file is compiled + * normally (and may save a new binary). + * + * In order to save the binary, valid_save_binary() is called + * in master.c, and is passed the name of the source file. If + * this returns a non-zero value, the binary is allowed to be + * saved. Allowing any file by any wizard to be saved as a + * binary is convenient, but may take up a lot of disk space. + */ +#define BINARIES + +/* ARRAY_RESERVED_WORD: If this is defined then the word 'array' can + * be used to define arrays, as in: + * + * int array x = ({ .... }); + * + * A side effect is that 'array' cannot be a variable or function name. + */ +#undef ARRAY_RESERVED_WORD + +/* REF_RESERVED_WORD: If this is defined then the word 'ref' can be + * used to pass arguments to functions by value. Example: + * + * void inc(int ref x) { + * x++; + * } + * + * ... y = 1; inc(ref y); ... + * + * A side effect is that 'ref' cannot be a variable or function name. + * + * Note: ref must be used in *both* places; this is intentional. It protects + * against passing references to routines which don't intend to return values + * through their arguments, and against forgetting to pass a reference + * to a function which wants one (or accidentally having a variable modified!) + */ +#define REF_RESERVED_WORD + +/**************************************************************************** + * PACKAGES * + * -------- * + * Defining some/all of the following add certain efuns, and sometimes * + * add/remove code from the driver. * + * * + * if PACKAGE_XYZZY is defined here, then the code in packages/xyzzy.c * + * and the efuns in packages/xyzzy_spec.c will be added to the driver. * + ****************************************************************************/ + +/* various miscellaneous efuns */ +#define PACKAGE_CONTRIB + +/* efuns that are only of use to those that know something about driver + internals */ +#define PACKAGE_DEVELOP + +/* PACKAGE_MATH: determines whether or not the math efuns (for floats) are + included. + */ +#define PACKAGE_MATH + +/* PACKAGE_MATRIX: determines whether or not the 3d graphics efuns (for floats) + * are included - see packages/matrix.spec for a list. + */ +#undef PACKAGE_MATRIX + +/* PACKAGE_MUDLIB_STATS: define this to enable domain and author stats + * maintenance by the driver. These mudlib stats are more domain + * based than user based, and replaces the traditional wiz_list stats. + */ +#undef PACKAGE_MUDLIB_STATS + +/* PACKAGE_SOCKETS: define this to enable the socket efunctions. This + * causes HAS_SOCKETS to be defined for all LPC objects. + */ +#define PACKAGE_SOCKETS + +/* PACKAGE_PARSER: Natural language parsing efuns for interactive fiction + * type applications + */ +#undef PACKAGE_PARSER + +/* PACKAGE_EXTERNAL: Allows the driver to exec() commands specified in the + * config file. + */ +#undef PACKAGE_EXTERNAL + +/* NUM_EXTERNAL_CMDS: the number of external commands supported */ +#define NUM_EXTERNAL_CMDS 100 + +/* PACKAGE_DB: efuns for external database access using msql */ +#undef PACKAGE_DB + +/* If PACKAGE_DB is defined above, you must pick ONE of the following supported + * databases + */ +#ifdef PACKAGE_DB +#undef USE_MSQL +#undef MSQL +#define USE_MYSQL 2 +#define MY_SQL +#endif + +/**************************************************************************** + * UID PACKAGE * + * ----------- * + * UIDS are the basis for some mudlib security systems. Basically, they're * + * preserved for backwards compatibility, as several ways of breaking * + * almost any system which relies on them are known. (No, it's not a flaw * + * of uids; only that b/c of the ease with which LPC objects can call * + * each other, it's far too easy to leave holes) * + * * + * If you don't care about security, the first option is probably what you * + * want. * + ****************************************************************************/ + +/* + * PACKAGE_UIDS: define this if you want a driver that does use uids. + * + */ +#define PACKAGE_UIDS + +/*PACKAGE DWLIB: some discworld mudlib simuls coded in C (well just one right + now) */ + +#define PACKAGE_DWLIB + +/* AUTO_SETEUID: when an object is created it's euid is automatically set to + * the equivalent of seteuid(getuid(this_object())). undef AUTO_SETEUID + * if you would rather have the euid of the created object be set to 0. + */ +#define AUTO_SETEUID + +/* AUTO_TRUST_BACKBONE: define this if you want objects with the backbone + * uid to automatically be trusted and to have their euid set to the uid of + * the object that forced the object's creation. + */ +#undef AUTO_TRUST_BACKBONE + +/************************************************************************* + * FOR EXPERIENCED USERS * + * ----------------------- * + * Most of these options will probably be of no interest to many users. * + *************************************************************************/ + +/* USE_32BIT_ADDRESSES: Use 32 bits for addresses of function, instead of + * the usual 16 bits. This increases the maximum program size from 64k + * of LPC bytecode (NOT source) to 4 GB. Branches are still 16 bits, + * imposing a 64k limit on catch(), if(), switch(), loops, and most other + * control structures. It would take an extremely large function to hit + * those limits, though. + * + * Overhead: 2 bytes/function with LPC->C off. Having LPC->C on forces + * this option, since it needs 4 bytes to store the function pointers + * anyway, and this setting is ignored. + */ +#undef USE_32BIT_ADDRESSES + +/* HEARTBEAT_INTERVAL: define heartbeat interval in microseconds (us). + * 1,000,000 us = 1 second. The value of this macro specifies + * the frequency with which the heart_beat method will be called in + * those LPC objects which have called set_heart_beat(1). + * + * [NOTE: if ualarm() isn't available, alarm() is used instead. Since + * alarm() requires its argument in units of a second, we map 1 - 1,000,000 us + * to an actual interval of one (1) second and 1,000,001 - 2,000,000 maps to + * an actual interval of two (2) seconds, etc.] + */ +#define HEARTBEAT_INTERVAL 1 + +/* + * CALLOUT_CYCLE_SIZE: This is the number of slots in the call_out list. + * It should be approximately the average number of active call_outs, or + * a few times smaller. It should also be a power of 2, and also be relatively + * prime to any common call_out lengths. If all this is too confusing, 32 + * isn't a bad number :-) + */ +#define CALLOUT_CYCLE_SIZE 512 + +/* LARGEST_PRINTABLE_STRING: defines the size of the vsprintf() buffer in + * comm.c's add_message(). Instead of blindly making this value larger, + * your mudlib should be coded to not send huge strings to users. + */ +#define LARGEST_PRINTABLE_STRING 8192 + +/* MESSAGE_BUFFER_SIZE: determines the size of the buffer for output that + * is sent to users. + */ +#define MESSAGE_BUFFER_SIZE 4096 + +/* APPLY_CACHE_BITS: defines the number of bits to use in the call_other cache + * (in interpret.c). + * + * Memory overhead is (1 << APPLY_CACHE_BITS)*16. + * [assuming 32 bit pointers and 16 bit shorts] + * + * ACB: entries: overhead: + * 6 64 1k + * 8 256 4k + * 10 1024 16k + * 12 4096 64k + * 14 16384 256k + * 16 65536 1M + */ +#define APPLY_CACHE_BITS 20 + +/* CACHE_STATS: define this if you want call_other (apply_low) cache + * statistics. Causes HAS_CACHE_STATS to be defined in all LPC objects. + */ +#define CACHE_STATS + +/* TRACE: define this to enable the trace() and traceprefix() efuns. + * (keeping this undefined will cause the driver to run faster). + */ +#define TRACE + +/* RUNTIME_LOADING: On systems which support it, it allows LPC->C compilation + * 'on the fly' without having to recompile the driver. + * + * Note: This currently only works on machines that have the dlopen() system + * call. SunOS and IRIX do, as do a number of others. AIX and Ultrix don't. + * Linux does if you are using ELF. + */ +#undef RUNTIME_LOADING + +/* TRACE_CODE: define this to enable code tracing (the driver will print + * out the previous lines of code to an error) eval_instruction() runs about + * twice as fast when this is not defined (for the most common eoperators). + */ +#undef TRACE_CODE + +/* HEART_BEAT_CHUNK: The number of heart_beat chunks allocated at a time. + * A large number wastes memory as some will be sitting around unused, while + * a small one wastes more CPU reallocating when it needs to grow. Default + * to a medium value. + */ +#define HEART_BEAT_CHUNK 32 + +/* SERVER_IP: For machines with multiple IP addresses, this specifies which + * one to use. This is useful for IP accounting and is necessary to be + * able to do ident lookups on such machines. + * + * example: #define SERVER_IP "194.229.18.27" + */ +#undef SERVER_IP + +/* Some maximum string sizes + */ +#define SMALL_STRING_SIZE 100 +#define LARGE_STRING_SIZE 1000 +#define COMMAND_BUF_SIZE 2000 + +/* Number of levels of nested datastructures allowed -- this limit prevents + * crashes from occuring when saving objects containing variables containing + * recursive datastructures (with circular references). + */ +#define MAX_SAVE_SVALUE_DEPTH 100 + +/* Miscellaneous config options that should probably be in the runtime + * config file. + */ +/* MAX_LOCAL: maximum number of local variables allowed per LPC function */ +#define CFG_MAX_LOCAL_VARIABLES 50 + +#define CFG_EVALUATOR_STACK_SIZE 3000 +#define CFG_COMPILER_STACK_SIZE 600 +#define CFG_MAX_CALL_DEPTH 150 +/* This must be one of 4, 16, 64, 256, 1024, 4096 */ +#define CFG_LIVING_HASH_SIZE 256 + +/* NEXT_MALLOC_DEBUG: define this if using a NeXT and you want to enable + * the malloc_check() and/or malloc_debug() efuns. Run the 'man malloc_debug' + * command on the NeXT to find out what the arguments to malloc_debug(int) + * mean. The malloc_check() efun calls the NeXT NXMallocCheck() system + * call which does a consistency check on malloc's data structures (this + * consistency check is done at each malloc() and free() for certain + * malloc_debug() levels). A non-zero return value indicates there was + * a consistency problem. For those NeXT users wanting a bit more + * performance out of malloc, try defining NEXT_MALLOC_DEBUG and calling the + * malloc_debug(-1) efun (with an arg of -1). This will turn all + * malloc debugging off and call malloc_singlethreaded() which the NeXT + * malloc man page claims can make NeXT system malloc 10% to 15% faster. + * + * [NOTE: This #define has no affect on the driver if not using the + * NeXTSTEP OS.] + * + * Warning: if you use a NeXT and define NEXT_MALLOC_DEBUG, be sure to + * protect the use of the malloc_check() and malloc_debug() efuns + * since setting certain debug levels can cause malloc() and free() + * to become _very_ slow (protect efuns by using simul_efuns and + * valid_override). + * + * [NOTE: malloc_debug(6) is a good compromise between efficiency and + * completeness of malloc debugging (malloc/free will be about half as fast).] + */ +#define NEXT_MALLOC_DEBUG + + +/* GET_CHAR_IS_BUFFERED: Normally get_char() is unbuffered. That is, once + * a character is received for get_char(), anything else is in the input + * stream is immediately thrown away. This can be very undesirable, especially + * if you're calling get_char() again from the handler from the previous call. + * Define this if you want get_char() to be buffered. In this case, the buffer + * will only get flushed if get_char() is not called from the first get_char()'s + * LPC callback handler. + */ +#undef GET_CHAR_IS_BUFFERED + +/* PACKAGE_COMPRESS: Enable MCCP support and compressed save files + SAVE_GZ_EXTENSION: save extension for compressed files + */ +#undef HAVE_ZLIB +#undef PACKAGE_COMPRESS +#define SAVE_GZ_EXTENSION ".o.gz" + +/* CALL_OTHER_TYPE_CHECK: enable type checking for call_other() + * (-> operator on objects) + */ +#undef CALL_OTHER_TYPE_CHECK + +/* CALL_OTHER_WARN, make it warning instead of errors */ +#undef CALL_OTHER_WARN + +/* WARN_TAB: Some versions of the editor built in indent function use + * tabs for indenting. This options turns on a warning message for + * files indented with tabs instead of spaces. + */ +#define WARN_TAB + +/* USE_ICONV: Use iconv to translate input and output from/to the users char + * encoding + */ +#undef USE_ICONV + +/* WOMBLES: don't allow spaces between start/end of array/mapping/functional token chars so ({1,2,3}) still works, but ( { 1 , 2 , 3 } ) doesn't and ({ 1 , 2 , 3 }) does.*/ +#undef WOMBLES + +/* ALLOW_INHERIT_AFTER_FUNCTION: allow inheriting after functions have been defined (this includes prototypes). This caused crashes in v22.2a but it may have been fixed since */ +#undef ALLOW_INHERIT_AFTER_FUNCTION +#undef PACKAGE_DSLIB +#define ED_INDENT_SPACES 4 +#define PROG_REF_TYPE int +#undef PARSE_DEBUG +#define HAS_CONSOLE +#define FLUFFOS +#undef ED_INDENT_CASE +#undef ALLOW_INHERIT_AFTER_GLOBAL_VARIABLES +#undef ANSI_SUBSTITUTE +#define CFG_MAX_GLOBAL_VARIABLES 256 +#undef RECEIVE_ED +#undef PACKAGE_ASYNC +#undef IPV6 +#undef MALLOC64 +#undef PACKAGE_CRYPTO +#undef PACKAGE_SHA1 diff --git a/fluffos-2.23-ds03/local_options.tmi2 b/fluffos-2.23-ds03/local_options.tmi2 new file mode 100644 index 0000000..fc65e0c --- /dev/null +++ b/fluffos-2.23-ds03/local_options.tmi2 @@ -0,0 +1,870 @@ +/* + * options.h: defines for the compile-time configuration of the MudOS driver + */ + +#ifndef _OPTIONS_H_ +#define _OPTIONS_H_ +#endif + +/* + * YOU PROBABLY DO NOT WANT TO MODIFY THIS FILE. + * + * Do 'cp options.h local_options' and edit that instead. local_options, + * if it exists, overrides this file. + * + * The advantage is that when you upgrade to a newer MudOS driver, you can + * simply copy your local_options file into the src directory. The build + * process will warn you if new options have been added that you should + * choose settings for. + */ + +/**************************************************************************** + * EVERY time you change ANYTHING in this file, RECOMPILE from scratch. * + * (type "make clean" then "make" on a UNIX system) Failure to do so may * + * cause the driver to behave oddly. * + ****************************************************************************/ + +/* NOTES: + * Many of the configurable options are now set via the configuration file + * that is specified as the first argument to the driver. + * See port.h for those #defines related to portability (compatibility) if + * you have problems compiling on your system. + * Removing an efun from func_spec.c usually removes most, if not all, + * of the code associated with it. + * Note that anything defined in this file is also visible to LPC files + * surrounded by __. So #define FOO in this file defines __FOO__ for + * all LPC files. This allows code like: + * + * #ifdef __SENSIBLE_MODIFIERS__ + * ... + */ + +/**************************************************************************** + * MALLOC * + * -------- * + * For performance reasons, LP drivers have a variety of memory allocation * + * packages. If you don't care, use the default one on your system: * + * #define SYSMALLOC, #undef the others. * + ****************************************************************************/ + +/* You must choose exactly one of these malloc packages: + * ~~~~ + * SYSMALLOC: + * * Built-in system malloc. + * * No statistics. + * * SYSMALLOC incurs no additional CPU or memory overhead. + * + * SMALLOC: + * * Satoria's smalloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than most system mallocs with modest ammount of memory overhead. + * * Can fall back onto system malloc if sbrk() not ok. + * + * BSDMALLOC: + * * BSD (Berkeley Software Distributions) malloc. + * * Statistics available. (see wrappers and DO_MSTATS) + * * Faster than SMALLOC but more memory overhead. + * * Requires sbrk(). + */ +#define SYSMALLOC +#undef SMALLOC +#undef BSDMALLOC + +/* You may optionally choose one (or none) of these malloc wrappers. These + * can be used in conjunction with any of the above malloc packages. + * + * WRAPPEDMALLOC: + * * Limited statistics. + * * Limited additional cpu overhead and no additional memory overhead. + * + * DEBUGMALLOC: + * * Statistics on precisely how much memory has been malloc'd (as well + * as the stats provided by WRAPPEDMALLOC). + * * Incurs a fair amount of overhead (both memory and CPU) + */ +#undef WRAPPEDMALLOC +#undef DEBUGMALLOC + +/* The following add certain bells and whistles to malloc: */ + +/* + * SBRK_OK: do not define this unless SMALLOC is chosen above. + * Defining this causes smalloc to use the low level memory allocation + * routines, and to act as a malloc replacement. Conversely, undef'ing + * SBRK_OK causes smalloc to act as a wrapper for the system malloc + * routines. + * + * Note: + * NeXTStep 3.x users should always #undef SBRK_OK. + */ +#undef SBRK_OK + +/* DO_MSTATS: do not define this unless BSDMALLOC or SMALLOC is chosen above. + * Defining this causes those replacement mallocs to keep statistics that + * the malloc_status() efun will print out (including total memory + * allocated/used). + */ +#undef DO_MSTATS + +/* DEBUGMALLOC_EXTENSIONS: defining this (in addition to DEBUGMALLOC) enables + * the set_malloc_mask(int) and debugmalloc(string,int) efuns. These two + * efuns basically allow you to cause certain malloc's and free's (with tags + * selected by a specified mask) to print debug information (addr, tag, + * description, size) to stdio (in the shell that invoked the driver) or to a + * file. Not defining this does reduce the overhead of DEBUGMALLOC from 16 + * bytes per malloc down to 8. This macro has no effect if DEBUGMALLOC isn't + * defined. + */ +#undef DEBUGMALLOC_EXTENSIONS + +/* CHECK_MEMORY: defining this (in addition to DEBUGMALLOC and + * DEBUGMALLOC_EXTENSIONS) causes the driver to check for memory + * corruption due to writing before the start or end of a block. This + * also adds the check_memory() efun. Takes a considerable ammount + * more memory. Mainly for debugging. + */ +#undef CHECK_MEMORY + +/**************************************************************************** + * COMPATIBILITY * + * --------------- * + * The MudOS driver has evolved quite a bit over the years. These defines * + * are mainly to preserve old behavior in case people didn't want to * + * rewrite the relevant portions of their code. * + * * + * In most cases, code which needs these defines should be rewritten when * + * possible. The 'Compat status' field is designed to give an idea how * + * likely it is that support for that option will be removed in the near * + * future. Certain options are fairly easy to work around, and double * + * the size of the associated code, as well as the maintenance workload, * + * and can make the code significantly more complex or harder to read, so * + * supporting them indefinitely is impractical. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* HAS_STATUS_TYPE: old MudOS drivers had a 'status' type which was + * identical to the 'int' type. Define this to bring it back. + * + * Compat status: very archaic, but easy to support. + */ +#undef HAS_STATUS_TYPE + +/* explode(): + * + * The old behavior (#undef both of the below) strips any number of + * delimiters at the start of the string, and one at the end. So + * explode("..x.y..z..", ".") gives ({ "x", "y", "", "z", "" }) + * + * SANE_EXPLODE_STRING strips off at most one leading delimiter, and + * still strips off one at the end, so the example above gives + * ({ "", "x", "y", "", "z", "" }). + * + * REVERSIBLE_EXPLODE_STRING overrides SANE_EXPLODE_STRING, and makes + * it so that implode(explode(x, y), y) is always x; i.e. no delimiters + * are ever stripped. So the example above gives + * ({ "", "", "x", "y", "", "z", "", "" }). + */ +#define SANE_EXPLODE_STRING +#undef REVERSIBLE_EXPLODE_STRING + +/* CAST_CALL_OTHERS: define this if you want to require casting of call_other's; + * this was the default behavior of the driver prior to this addition. + * + * Compat status: code that requires it doesn't break, and it promotes + * sloppy coding with no benefits. + */ +#undef CAST_CALL_OTHERS + +/* NONINTERACTIVE_STDERR_WRITE: if defined, all writes/tells/etc to + * noninteractive objects will be written to stderr prefixed with a ']' + * (old behavior). + * + * Compat status: Easy to support, and also on the "It's a bug! No, it's + * a feature!" religious war list. + */ +#define NONINTERACTIVE_STDERR_WRITE + +/* NO_LIGHT: define this to disable the set_light() and driver maintenance + * of light levels in objects. You can simulate it via LPC if you want... + * + * Compat status: Very dated, easy to simulate, and gross. + */ +#undef NO_LIGHT + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + * process_input() then becomes the only way to deal with player input. + * + * Compat status: next to impossible to simulate, hard to replace, and + * very, very widely used. + */ +#undef NO_ADD_ACTION + +/* NO_SNOOP: disables the snoop() efun and all related functionality. + */ +#undef NO_SNOOP + +/* NO_ENVIRONMENT: define this to remove the handling of object containment + * relationships by the driver + * + * Compat status: hard to simulate efficiently, and very widely used. + */ +#undef NO_ENVIRONMENT + +/* NO_WIZARDS: for historical reasons, MudOS used to keep track of who + * is and isn't a wizard. Defining this removes that completely. + * If this is defined, the wizardp() and related efuns don't exist. + * + * Also note that if it is not defined, then non-wizards are always put + * in restricted mode when ed() is used, regardless of the setting of + * the restrict parameter. + * + * Compat status: easy to simulate and dated. + */ +#undef NO_WIZARDS + +/* OLD_TYPE_BEHAVIOR: reintroduces a bug in type-checking that effectively + * renders compile time type checking useless. For backwards compatibility. + * + * Compat status: dealing with all the resulting compile errors can be + * a huge pain even if they are correct, and the impact on the code is + * small. + */ +#undef OLD_TYPE_BEHAVIOR + +/* OLD_RANGE_BEHAVIOR: define this if you want negative indexes in string + * or buffer range values (not lvalue, i.e. x[-2..-1]; for e.g. not + * x[-2..-1] = foo, the latter is always illegal) to mean counting from the + * end + * + * Compat status: Not horribly difficult to replace reliance on this, but not + * trivial, and cannot be simulated. + */ +#undef OLD_RANGE_BEHAVIOR + +/* OLD_ED: ed() efun backwards compatible with the old version. The new + * version requires/allows a mudlib front end. + * + * Compat status: Easily simulated. + */ +#define OLD_ED + +/* SENSIBLE_MODIFIERS: + * Turning this on changes a few things, which may break old code: + * + * (1) 'static' is not recognized; either 'nosave' or 'protected' must + * be used instead. + * (2) The old meaning of 'public' is no longer allowed. Explicit + * functions must be defined at each level to allow access to + * privately inherited functions. + * (3) 'public' now means the default visibility. Previously there was + * no keyword that meant this (before you ask, 'public' meant something + * else, and if you don't know that, you probably don't have any reason + * to care about the old meaning). + */ +#undef SENSIBLE_MODIFIERS + +/**************************************************************************** + * MISCELLANEOUS * + * --------------- * + * Various options that affect the way the driver behaves. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* + * Define this in order to use Fermat@Equilibria's MD5 based crypt() instead + * of the operating system's. It has the advantage of giving the same value + * on all architectures, and being stronger than the standard UNIX crypt(). + */ +#define CUSTOM_CRYPT + +/* + * Some minor tweaks that make it a bit easier to run code designed to run + * on LPmud 3.2/3.2.1. Currently has the following effects: + * + * . m_indices() and m_values() are synonyms for keys() and values(), + * respectively + * . map_delete() returns it's first argument + * . inherit_list() means deep_inherit_list(), not shallow_inherit_list() + * . heart_beat_info() is a synonym for heart_beats() + */ +#undef COMPAT_32 + +/* + * Keep statistics about allocated strings, etc. Which can be viewed with + * the mud_status() efun. If this is off, mud_status() and memory_info() + * ignore allocated strings, but string operations run faster. + */ +#undef STRING_STATS + +/* + * Similarly for arrays ... + */ +#define ARRAY_STATS + +/* LOG_CATCHES: define this to cause errors that are catch()'d to be + * sent to the debug log anyway. + * + * On by default, because newer libs use catch() a lot, and it's confusing + * if the errors don't show up in the logs. + */ +#define LOG_CATCHES + +/* ARGUMENTS_IN_TRACEBACK: prints out function call arguments in error + * tracebacks, to aid in debugging. Note: it prints the values of + * the arguments at the time of the error, not when the function + * was called. It looks like this: + * + * Failed to load file: read_buffer + * program: command/update.c, object: command/update line 15 + * ' commandHook' in ' clone/user.c' (' clone/user#1')line 72 + * arguments were ("/read_buffer.c") + * ' main' in ' command/update.c' (' command/update')line 15 + * arguments were ("/read_buffer.c") + * + * The only down side is some people like their logs shorter + */ +#define ARGUMENTS_IN_TRACEBACK + +/* LOCALS_IN_TRACEBACK: similar to ARGUMENTS_IN_TRACEBACK, but for local + * variables. The output looks more or less like: + * + * locals: 1, "local_value" + * + * Same as above. Tends to produce even longer logs, but very useful for + * tracking errors. + */ +#define LOCALS_IN_TRACEBACK + +/* MUDLIB_ERROR_HANDLER: If you define this, the driver doesn't do any + * handling of runtime errors, other than to turn the heartbeats of + * objects off. Information about the error is passed in a mapping + * to the error_handler() function in the master object. Whatever is + * returned is put in the debug.log. + * + * A good mudlib error handler is one of the best tools for tracking down + * errors. Unfortunately, you need to have one. Check the testsuite or + * other libs for an example. + */ +#define MUDLIB_ERROR_HANDLER + +/* CONFIG_FILE_DIR specifies a directory in which the driver will search for + * config files by default. If you don't wish to use this define, you may + * always specify a full path to the config file when starting the driver. + */ +#ifndef LATTICE +#define CONFIG_FILE_DIR "/u/tim/COMP/bin" +#else +#define CONFIG_FILE_DIR "etc:" +#endif + +/* DEFAULT_PRAGMAS: This should be a sum of pragmas you want to always + * be on, i.e. + * + * #define DEFAULT_PRAGMAS PRAGMA_STRICT_TYPES + PRAGMA_SAVE_TYPES + * + * will make every LPC file behave as if it had the lines: + * #pragma strict_types + * #pragma save_types + * + * for no default pragmas: + * #define DEFAULT_PRAGMAS 0 + * + * If you don't know what these are, 0 is a good choice. + * + * Supported pragmas: + * PRAGMA_STRICT_TYPES: enforces strict type checking + * PRAGMA_WARNINGS: issues warnings about various dangerous things in + * your code + * PRAGMA_SAVE_TYPES: save the types of function arguments for checking + * calls to functions in this object by objects that + * inherit it. + * PRAGMA_SAVE_BINARY: save a compiled binary version of this file for + * faster loading next time it is needed. + * PRAGMA_OPTIMIZE: make a second pass over the generated code to + * optimize it further. Currently does jump threading. + * PRAGMA_ERROR_CONTEXT:include some text telling where on the line a + * compilation error occured. + */ +#define DEFAULT_PRAGMAS PRAGMA_STRICT_TYPES + PRAGMA_ERROR_CONTEXT + +/* supress warnings about unused arguments; only warn about unused local + * variables. Makes older code (where argument names were required) compile + * more quietly. + */ +#define SUPPRESS_ARGUMENT_WARNINGS + +/* NO_RESETS: completely disable the periodic calling of reset() */ +#undef NO_RESETS + +/* LAZY_RESETS: if this is defined, an object will only have reset() + * called in it when it is touched via call_other() or move_object() + * (assuming enough time has passed since the last reset). If LAZY_RESETS + * is #undef'd, then reset() will be called as always (which guaranteed that + * reset would always be called at least once). The advantage of lazy + * resets is that reset doesn't get called in an object that is touched + * once and never again (which can save memory since some objects won't get + * reloaded that otherwise would). + */ +#undef LAZY_RESETS + +/* SAVE_EXTENSION: defines the file extension used by save_object(). + * and restore_object(). Some sysadmins run scripts that periodically + * scan for and remove files ending in .o (but many mudlibs are already + * set up to use .o thus we leave .o as the default). + */ +#define SAVE_EXTENSION ".o" + +/* NO_ANSI: define if you wish to disallow users from typing in commands that + * contain ANSI escape sequences. Defining NO_ANSI causes all escapes + * (ASCII 27) to be replaced with a space ' ' before the string is passed + * to the action routines added with add_action. + * + * STRIP_BEFORE_PROCESS_INPUT allows the location where the stripping is + * done to be controlled. If it is defined, then process_input() doesn't + * see ANSI characters either; if it is undefined ESC chars can be processed + * by process_input(), but are stripped before add_actions are called. + * Note that if NO_ADD_ACTION is defined, then #define NO_ANSI without + * #define STRIP_BEFORE_PROCESS_INPUT is the same as #undef NO_ANSI. + * + * If you anticipate problems with users intentionally typing in ANSI codes + * to make your terminal flash, etc define this. + */ +#define NO_ANSI +#define STRIP_BEFORE_PROCESS_INPUT + +/* OPCPROF: define this if you wish to enable OPC profiling. Allows a dump + * of the # of times each efun is invoked (via the opcprof() efun). + */ +#undef OPCPROF + +/* OPCPROF_2D: define this if you wish to enable 2-D OPC profiling. Allows a + * dump of the # of times each *pair* of eoperators is invoked. + * + * You can't use this and OPCPROF at the same time. + */ +#undef OPCPROF_2D + +/* TRAP_CRASHES: define this if you want MudOS to call crash() in master.c + * and then shutdown when signals are received that would normally crash the + * driver. + */ +#define TRAP_CRASHES + +/* THIS_PLAYER_IN_CALL_OUT: define this if you wish this_player() to be + * usable from within call_out() callbacks. + */ +#define THIS_PLAYER_IN_CALL_OUT + +/* CALLOUT_HANDLES: If this is defined, call_out() returns an integer, which + * can be passed to remove_call_out() or find_call_out(). Removing call_outs + * by name is still allowed, but is significantly less efficient, and also + * doesn't work for function pointers. This option adds 4 bytes overhead + * per callout to keep track of the handle. + */ +#define CALLOUT_HANDLES + +/* FLUSH_OUTPUT_IMMEDIATELY: Causes output to be written to sockets + * immediately after being generated. Useful for debugging. + */ +#undef FLUSH_OUTPUT_IMMEDIATELY + +/* PRIVS: define this if you want object privileges. Your mudlib must + * explicitly make use of this functionality to be useful. Defining this + * this will increase the size of the object structure by 4 bytes (8 bytes + * on the DEC Alpha) and will add a new master apply during object creation + * to "privs_file". In general, privileges can be used to increase the + * granularity of security beyond the current root uid mechanism. + * + * [NOTE: for those who'd rather do such things at the mudlib level, look at + * the inherits() efun and the 'valid_object' apply to master.] + */ +#undef PRIVS + +/* INTERACTIVE_CATCH_TELL: define this if you want catch_tell called on + * interactives as well as NPCs. If this is defined, user.c will need a + * catch_tell(msg) method that calls receive(msg); +*/ +#undef INTERACTIVE_CATCH_TELL + +/* RESTRICTED_ED: define this if you want restricted ed mode enabled. + */ +#define RESTRICTED_ED + +/* NO_SHADOWS: define this if you want to disable shadows in your driver. + */ +#undef NO_SHADOWS + +/* SNOOP_SHADOWED: define this if you want snoop to report what is + * sent to the player even in the event that the player's catch_tell() is + * shadowed and the player may not be seeing what is being sent. Messages + * of this sort will be prefixed with $$. + */ +#undef SNOOP_SHADOWED + +/* RECEIVE_SNOOP: define this if you want snoop text to be sent to + * the receive_snoop() function in the snooper object (instead of being + * sent directly via add_message()). This is useful if you want to + * build a smart client that does something different with snoop messages. + */ +#define RECEIVE_SNOOP + +/* PROFILE_FUNCTIONS: define this to be able to measure the CPU time used by + * all of the user-defined functions in each LPC object. Note: defining + * this adds three long ints (12 bytes on 32-bit machines) to the function + * header structs. Also note that the resolution of the getrusage() timer + * may not be high enough on some machines to give non-zero execution + * times to very small (fast) functions. In particular if the clock + * resolution is 1/60 of a second, then any time less than approxmately 15k + * microseconds will resolve to zero (0). + */ +#define PROFILE_FUNCTIONS + +/* NO_BUFFER_TYPE: if this is #define'd then LPC code using the 'buffer' + * type won't be allowed to compile (since the 'buffer' type won't be + * recognized by the lexer). + */ +#undef NO_BUFFER_TYPE + +/* BINARIES: define this to enable the 'save_binary' pragma. + * This pragma, when set in a program, will cause it to save a + * binary image when loaded, so that subsequent loadings will + * be much faster. The binaries are saved in the directory + * specified in the configuration file. The binaries will not + * load if the LPC source or any of the inherited or included + * files are out of date, in which case the file is compiled + * normally (and may save a new binary). + * + * In order to save the binary, valid_save_binary() is called + * in master.c, and is passed the name of the source file. If + * this returns a non-zero value, the binary is allowed to be + * saved. Allowing any file by any wizard to be saved as a + * binary is convenient, but may take up a lot of disk space. + */ +#define BINARIES + +/* ARRAY_RESERVED_WORD: If this is defined then the word 'array' can + * be used to define arrays, as in: + * + * int array x = ({ .... }); + * + * A side effect is that 'array' cannot be a variable or function name. + */ +#undef ARRAY_RESERVED_WORD + +/* REF_RESERVED_WORD: If this is defined then the word 'ref' can be + * used to pass arguments to functions by value. Example: + * + * void inc(int ref x) { + * x++; + * } + * + * ... y = 1; inc(ref y); ... + * + * A side effect is that 'ref' cannot be a variable or function name. + * + * Note: ref must be used in *both* places; this is intentional. It protects + * against passing references to routines which don't intend to return values + * through their arguments, and against forgetting to pass a reference + * to a function which wants one (or accidentally having a variable modified!) + */ +#undef REF_RESERVED_WORD + +/**************************************************************************** + * PACKAGES * + * -------- * + * Defining some/all of the following add certain efuns, and sometimes * + * add/remove code from the driver. * + * * + * if PACKAGE_XYZZY is defined here, then the code in packages/xyzzy.c * + * and the efuns in packages/xyzzy_spec.c will be added to the driver. * + ****************************************************************************/ + +/* various miscellaneous efuns */ +#define PACKAGE_CONTRIB + +/* efuns that are only of use to those that know something about driver + internals */ +#define PACKAGE_DEVELOP + +/* PACKAGE_MATH: determines whether or not the math efuns (for floats) are + included. + */ +#define PACKAGE_MATH + +/* PACKAGE_MATRIX: determines whether or not the 3d graphics efuns (for floats) + * are included - see packages/matrix.spec for a list. + */ +#undef PACKAGE_MATRIX + +/* PACKAGE_MUDLIB_STATS: define this to enable domain and author stats + * maintenance by the driver. These mudlib stats are more domain + * based than user based, and replaces the traditional wiz_list stats. + */ +#undef PACKAGE_MUDLIB_STATS + +/* PACKAGE_SOCKETS: define this to enable the socket efunctions. This + * causes HAS_SOCKETS to be defined for all LPC objects. + */ +#define PACKAGE_SOCKETS + +/* PACKAGE_PARSER: Natural language parsing efuns for interactive fiction + * type applications + */ +#undef PACKAGE_PARSER + +/* PACKAGE_EXTERNAL: Allows the driver to exec() commands specified in the + * config file. + */ +#undef PACKAGE_EXTERNAL + +/* NUM_EXTERNAL_CMDS: the number of external commands supported */ +#ifdef PACKAGE_EXTERNAL +#define NUM_EXTERNAL_CMDS +#endif + +/* PACKAGE_DB: efuns for external database access using msql */ +#undef PACKAGE_DB + +/* If PACKAGE_DB is defined above, you must pick ONE of the following supported + * databases + */ +#ifdef PACKAGE_DB +#define USE_MSQL 1 /* MiniSQL, it's small; it's free */ +#undef USE_MYSQL 2 /* MySQL, bigger; it's free */ +#define DEFAULT_DB USE_MSQL /* default database */ +#endif + +/**************************************************************************** + * UID PACKAGE * + * ----------- * + * UIDS are the basis for some mudlib security systems. Basically, they're * + * preserved for backwards compatibility, as several ways of breaking * + * almost any system which relies on them are known. (No, it's not a flaw * + * of uids; only that b/c of the ease with which LPC objects can call * + * each other, it's far too easy to leave holes) * + * * + * If you don't care about security, the first option is probably what you * + * want. * + ****************************************************************************/ + +/* + * PACKAGE_UIDS: define this if you want a driver that does use uids. + * + */ +#define PACKAGE_UIDS + +/* AUTO_SETEUID: when an object is created it's euid is automatically set to + * the equivalent of seteuid(getuid(this_object())). undef AUTO_SETEUID + * if you would rather have the euid of the created object be set to 0. + */ +#undef AUTO_SETEUID + +/* AUTO_TRUST_BACKBONE: define this if you want objects with the backbone + * uid to automatically be trusted and to have their euid set to the uid of + * the object that forced the object's creation. + */ +#define AUTO_TRUST_BACKBONE + +/************************************************************************* + * FOR EXPERIENCED USERS * + * ----------------------- * + * Most of these options will probably be of no interest to many users. * + *************************************************************************/ + +/* USE_32BIT_ADDRESSES: Use 32 bits for addresses of function, instead of + * the usual 16 bits. This increases the maximum program size from 64k + * of LPC bytecode (NOT source) to 4 GB. Branches are still 16 bits, + * imposing a 64k limit on catch(), if(), switch(), loops, and most other + * control structures. It would take an extremely large function to hit + * those limits, though. + * + * Overhead: 2 bytes/function with LPC->C off. Having LPC->C on forces + * this option, since it needs 4 bytes to store the function pointers + * anyway, and this setting is ignored. + */ +#undef USE_32BIT_ADDRESSES + +/* HEARTBEAT_INTERVAL: define heartbeat interval in microseconds (us). + * 1,000,000 us = 1 second. The value of this macro specifies + * the frequency with which the heart_beat method will be called in + * those LPC objects which have called set_heart_beat(1). + * + * [NOTE: if ualarm() isn't available, alarm() is used instead. Since + * alarm() requires its argument in units of a second, we map 1 - 1,000,000 us + * to an actual interval of one (1) second and 1,000,001 - 2,000,000 maps to + * an actual interval of two (2) seconds, etc.] + */ +#define HEARTBEAT_INTERVAL 2 + +/* + * CALLOUT_CYCLE_SIZE: This is the number of slots in the call_out list. + * It should be approximately the average number of active call_outs, or + * a few times smaller. It should also be a power of 2, and also be relatively + * prime to any common call_out lengths. If all this is too confusing, 32 + * isn't a bad number :-) + */ +#define CALLOUT_CYCLE_SIZE 32 + +/* LARGEST_PRINTABLE_STRING: defines the size of the vsprintf() buffer in + * comm.c's add_message(). Instead of blindly making this value larger, + * your mudlib should be coded to not send huge strings to users. + */ +#define LARGEST_PRINTABLE_STRING 8192 + +/* MESSAGE_BUFFER_SIZE: determines the size of the buffer for output that + * is sent to users. + */ +#define MESSAGE_BUFFER_SIZE 4096 + +/* APPLY_CACHE_BITS: defines the number of bits to use in the call_other cache + * (in interpret.c). + * + * Memory overhead is (1 << APPLY_CACHE_BITS)*16. + * [assuming 32 bit pointers and 16 bit shorts] + * + * ACB: entries: overhead: + * 6 64 1k + * 8 256 4k + * 10 1024 16k + * 12 4096 64k + * 14 16384 256k + * 16 65536 1M + */ +#define APPLY_CACHE_BITS 11 + +/* CACHE_STATS: define this if you want call_other (apply_low) cache + * statistics. Causes HAS_CACHE_STATS to be defined in all LPC objects. + */ +#undef CACHE_STATS + +/* TRACE: define this to enable the trace() and traceprefix() efuns. + * (keeping this undefined will cause the driver to run faster). + */ +#undef TRACE + +/* LPC_TO_C: define this to enable LPC->C compilation. + * + * [NOTE: BINARIES must also be defined for LPC->C to work. Actually + * using binaries is not required, though.] + */ +#undef LPC_TO_C + +/* RUNTIME_LOADING: On systems which support it, it allows LPC->C compilation + * 'on the fly' without having to recompile the driver. + * + * Note: This currently only works on machines that have the dlopen() system + * call. SunOS and IRIX do, as do a number of others. AIX and Ultrix don't. + * Linux does if you are using ELF. Versions of FreeBSD prior to 3.0 don't. + */ +#define RUNTIME_LOADING + +/* TRACE_CODE: define this to enable code tracing (the driver will print + * out the previous lines of code to an error) eval_instruction() runs about + * twice as fast when this is not defined (for the most common eoperators). + */ +#define TRACE_CODE + +/* HEART_BEAT_CHUNK: The number of heart_beat chunks allocated at a time. + * A large number wastes memory as some will be sitting around unused, while + * a small one wastes more CPU reallocating when it needs to grow. Default + * to a medium value. + */ +#define HEART_BEAT_CHUNK 32 + +/* GET_CHAR_IS_BUFFERED: Normally get_char() is unbuffered. That is, once + * a character is received for get_char(), anything else is in the input + * stream is immediately thrown away. This can be very undesirable, especially + * if you're calling get_char() again from the handler from the previous call. + * Define this if you want get_char() to be buffered. In this case, the buffer + * will only get flushed if get_char() is not called from the first get_char()'s + * LPC callback handler. + */ +#undef GET_CHAR_IS_BUFFERED + +/* Some maximum string sizes + */ +#define SMALL_STRING_SIZE 100 +#define LARGE_STRING_SIZE 1000 + +/* Number of levels of nested datastructures allowed -- this limit prevents + * crashes from occuring when saving objects containing variables containing + * recursive datastructures (with circular references). + */ +#define MAX_SAVE_SVALUE_DEPTH 25 + +#define COMMAND_BUF_SIZE 2000 + +/* Miscellaneous config options that should probably be in the runtime + * config file. + */ +/* MAX_LOCAL: maximum number of local variables allowed per LPC function */ +#define CFG_MAX_LOCAL_VARIABLES 25 + +#define CFG_EVALUATOR_STACK_SIZE 1000 +#define CFG_MAX_CALL_DEPTH 50 +/* This must be one of 4, 16, 64, 256, 1024, 4096 */ +#define CFG_LIVING_HASH_SIZE 256 + +/* NEXT_MALLOC_DEBUG: define this if using a NeXT and you want to enable + * the malloc_check() and/or malloc_debug() efuns. Run the 'man malloc_debug' + * command on the NeXT to find out what the arguments to malloc_debug(int) + * mean. The malloc_check() efun calls the NeXT NXMallocCheck() system + * call which does a consistency check on malloc's data structures (this + * consistency check is done at each malloc() and free() for certain + * malloc_debug() levels). A non-zero return value indicates there was + * a consistency problem. For those NeXT users wanting a bit more + * performance out of malloc, try defining NEXT_MALLOC_DEBUG and calling the + * malloc_debug(-1) efun (with an arg of -1). This will turn all + * malloc debugging off and call malloc_singlethreaded() which the NeXT + * malloc man page claims can make NeXT system malloc 10% to 15% faster. + * + * [NOTE: This #define has no affect on the driver if not using the + * NeXTSTEP OS.] + * + * Warning: if you use a NeXT and define NEXT_MALLOC_DEBUG, be sure to + * protect the use of the malloc_check() and malloc_debug() efuns + * since setting certain debug levels can cause malloc() and free() + * to become _very_ slow (protect efuns by using simul_efuns and + * valid_override). + * + * [NOTE: malloc_debug(6) is a good compromise between efficiency and + * completeness of malloc debugging (malloc/free will be about half as fast).] + */ +#define NEXT_MALLOC_DEBUG + +#undef HAVE_ZLIB +#undef WOMBLES +#undef PACKAGE_COMPRESS +#undef PACKAGE_DWLIB +#undef CALL_OTHER_WARN +#undef CALL_OTHER_TYPE_CHECK +#define NUM_EXTERNAL_CMDS 1 +#undef MMALLOC +#undef WARN_TAB +#undef USE_ICONV +#define SAVE_GZ_EXTENSION ".o.gz" +#define CFG_COMPILER_STACK_SIZE 600000 +#undef SERVER_IP +#define ALLOW_INHERIT_AFTER_FUNCTION +#define PARSE_DEBUG +#define FLUFFOS +#undef PACKAGE_DSLIB +#define ED_INDENT_SPACES 4 +#define PROG_REF_TYPE int +#define HAS_CONSOLE +#undef ED_INDENT_CASE +#undef ALLOW_INHERIT_AFTER_GLOBAL_VARIABLES +#undef ANSI_SUBSTITUTE +#define CFG_MAX_GLOBAL_VARIABLES 256 +#undef RECEIVE_ED +#undef PACKAGE_ASYNC +#undef IPV6 +#undef MALLOC64 +#undef PACKAGE_CRYPTO +#undef PACKAGE_SHA1 diff --git a/fluffos-2.23-ds03/lpc.h b/fluffos-2.23-ds03/lpc.h new file mode 100644 index 0000000..14e2be0 --- /dev/null +++ b/fluffos-2.23-ds03/lpc.h @@ -0,0 +1,91 @@ +#ifndef LPC_H +#define LPC_H + +/* It is usually better to include "lpc_incl.h" instead of including this + directly */ + +typedef struct { + unsigned short ref; +} refed_t; + +union u { + const char *string; + long number; + float real; + + refed_t *refed; /* any of the block below */ + +#ifndef NO_BUFFER_TYPE + struct buffer_s *buf; +#endif + struct object_s *ob; + struct array_s *arr; + struct mapping_s *map; + struct funptr_s *fp; + + struct svalue_s *lvalue; + struct ref_s *ref; + unsigned char *lvalue_byte; + void (*error_handler) (void); +}; + +/* + * The value stack element. + * If it is a string, then the way that the string has been allocated + * differently, which will affect how it should be freed. + */ +typedef struct svalue_s { + short type; + int subtype; + union u u; +} svalue_t; + +typedef struct ref_s { + unsigned short ref; + struct ref_s *next, *prev; + struct control_stack_s *csp; + svalue_t *lvalue; + svalue_t sv; +} ref_t; + +/* values for type field of svalue struct */ +#define T_INVALID 0x0 +#define T_LVALUE 0x1 + +#define T_NUMBER 0x2 +#define T_STRING 0x4 +#define T_REAL 0x80 + +#define T_ARRAY 0x8 +#define T_OBJECT 0x10 +#define T_MAPPING 0x20 +#define T_FUNCTION 0x40 +#ifndef NO_BUFFER_TYPE +#define T_BUFFER 0x100 +#endif +#define T_CLASS 0x200 + +#define T_LVALUE_BYTE 0x400 /* byte-sized lvalue */ +#define T_LVALUE_RANGE 0x800 +#define T_ERROR_HANDLER 0x1000 +#define T_FREED 0x2000 +#define T_REF 0x4000 + +#ifdef NO_BUFFER_TYPE +#define T_REFED (T_ARRAY|T_OBJECT|T_MAPPING|T_FUNCTION|T_CLASS|T_REF) +#else +#define T_REFED (T_ARRAY|T_OBJECT|T_MAPPING|T_FUNCTION|T_BUFFER|T_CLASS|T_REF) +#endif +#define T_ANY (T_REFED|T_STRING|T_NUMBER|T_REAL) + +/* values for subtype field of svalue struct */ +#define STRING_COUNTED 0x1 /* has a length an ref count */ +#define STRING_HASHED 0x2 /* is in the shared string table */ + +#define STRING_MALLOC STRING_COUNTED +#define STRING_SHARED (STRING_COUNTED | STRING_HASHED) +#define STRING_CONSTANT 0 + +#define T_UNDEFINED 0x4 /* undefinedp() returns true */ + +#endif diff --git a/fluffos-2.23-ds03/lpc_incl.h b/fluffos-2.23-ds03/lpc_incl.h new file mode 100644 index 0000000..fd3fc17 --- /dev/null +++ b/fluffos-2.23-ds03/lpc_incl.h @@ -0,0 +1,25 @@ +#ifndef LPC_INCL_H +#define LPC_INCL_H + +#include "std.h" +#include "include/function.h" +#include "origin.h" +#include "config.h" +#include "applies.h" + +#include "program.h" +#include "lpc.h" +#include "function.h" +#include "buffer.h" +#include "object.h" +#include "array.h" +#include "mapping.h" +#include "class.h" + +#include "stralloc.h" +#include "simulate.h" +#include "interpret.h" +#include "rc.h" +#include "main.h" + +#endif diff --git a/fluffos-2.23-ds03/macros.h b/fluffos-2.23-ds03/macros.h new file mode 100644 index 0000000..2d625f9 --- /dev/null +++ b/fluffos-2.23-ds03/macros.h @@ -0,0 +1,269 @@ +#ifndef MACROS_H +#define MACROS_H + +#ifdef __STDC__ +#define ANSI_STRING_HACK(x) #x +#define DONT_ASK_WHY(x) (x) +#define WHERE (__FILE__ ":" DONT_ASK_WHY(x)) +#else +#define WHERE "non-ansi compilers are a pain" +#endif + +/* + * Some useful macros... + */ +#ifdef BUFSIZ +# define PROT_STDIO(x) (x () +#endif /* BUFSIZ */ + +/* ANSI/K&R compatibility stuff; + * + * The correct way to prototype a function now is: + * + * foobar (int, char *); + * + * foobar (int x, char * y) { ... } + */ +/* xlc can't handle an ANSI protoype followed by a K&R def, and varargs + * functions must be done K&R (b/c va_dcl is K&R style) so don't prototype + * vararg function arguments under AIX + */ +#if defined(__STDC__) || defined(WIN32) +# define VOLATILE volatile +# define SIGNED signed +#else /* __STDC__ */ +# define VOLATILE +# define SIGNED +#endif /* __STDC__ */ + +/* do things both ways ... */ +#define V_START(vlist, last_arg) va_start(vlist, last_arg) +#define V_VAR(type, var, vlist) +#define SAFE(x) do { x } while (0) + + +/* + Define for MALLOC, FREE, REALLOC, and CALLOC depend upon what malloc + package and optional wrapper is used. This technique is used because + overlaying system malloc with another function also named malloc doesn't + work on most mahines that have shared libraries. It will also let + us keep malloc stats even when system malloc is used. + + Please refer to options.h for selecting malloc package and wrapper. +*/ +#if (defined(SYSMALLOC) + defined(SMALLOC) + defined(BSDMALLOC) + defined(MMALLOC)) > 1 +!Only one malloc package should be defined +#endif + +#if (defined(WRAPPEDMALLOC) + defined(DEBUGMALLOC)) > 1 +!Only one wrapper (at most) should be defined +#endif + +#if defined(DO_MSTATS) && defined(SYSMALLOC) +!'DO_MSTATS' not available with 'SYSMALLOC' +#endif + +#if defined (WRAPPEDMALLOC) && !defined(IN_MALLOC_WRAPPER) + +# define MALLOC(x) wrappedmalloc(x) +# define FREE(x) wrappedfree(x) +# define REALLOC(x, y) wrappedrealloc(x, y) +# define CALLOC(x, y) wrappedcalloc(x, y) +# define DXALLOC(x, t, d) xalloc(x) +# define DMALLOC(x, t, d) MALLOC(x) +# define DREALLOC(x, y, t, d) REALLOC(x,y) +# define DCALLOC(x, y, t, d) CALLOC(x,y) + +#else + +# if defined(DEBUGMALLOC) && !defined(IN_MALLOC_WRAPPER) + +# define MALLOC(x) debugmalloc(x, 0, (char *)0) +# define DMALLOC(x, t, d) debugmalloc(x, t, d) +# define DXALLOC(x, t, d) debugmalloc(x, t, d) +# define FREE(x) debugfree(x) +# define REALLOC(x,y) debugrealloc(x,y,0,(char *)0) +# define DREALLOC(x,y,tag,desc) debugrealloc(x,y,tag,desc) +# define CALLOC(x,y) debugcalloc(x,y,0,(char *)0) +# define DCALLOC(x,y,tag,desc) debugcalloc(x,y,tag,desc) + +# else + +# include "my_malloc.h" + +# endif +#endif + +#if !defined(MALLOC) && !defined(EDIT_SOURCE) +!You need to specify a malloc package in local_options/options.h +#endif + +#define ALLOCATE(type, tag, desc) ((type *)DXALLOC(sizeof(type), tag, desc)) +#define CALLOCATE(num, type, tag, desc) ((type *)DXALLOC(sizeof(type[1]) * (num), tag, desc)) +#define RESIZE(ptr, num, type, tag, desc) ((type *)DREALLOC((void *)ptr, sizeof(type) * (num), tag, desc)) + +#ifdef DEBUG +# define IF_DEBUG(x) x +# define DEBUG_CHECK(x, y) if (x) fatal(y) +# define DEBUG_CHECK1(x, y, a) if (x) fatal(y, a) +# define DEBUG_CHECK2(x, y, a, b) if (x) fatal(y, a, b) +#else +# define IF_DEBUG(x) +# define DEBUG_CHECK(x, y) +# define DEBUG_CHECK1(x, y, a) +# define DEBUG_CHECK2(x, y, a, b) +#endif + +#if !defined(EDIT_SOURCE) && !defined(_FUNC_SPEC_) +#define COPY2(x, y) ((char *)(x))[0] = ((char *)(y))[0]; \ + ((char *)(x))[1] = ((char *)(y))[1] +#define LOAD2(x, y) ((char *)&(x))[0] = *y++; \ + ((char *)&(x))[1] = *y++ +#define STORE2(x, y) *x++ = ((char *)(&(y)))[0]; \ + *x++ = ((char *)(&(y)))[1] + +#define COPY4(x, y) ((char *)(x))[0] = ((char *)(y))[0]; \ + ((char *)(x))[1] = ((char *)(y))[1]; \ + ((char *)(x))[2] = ((char *)(y))[2]; \ + ((char *)(x))[3] = ((char *)(y))[3] +#define LOAD4(x, y) ((char *)&(x))[0] = *y++; \ + ((char *)&(x))[1] = *y++; \ + ((char *)&(x))[2] = *y++; \ + ((char *)&(x))[3] = *y++ +#define STORE4(x, y) *x++ = ((char *)(&(y)))[0]; \ + *x++ = ((char *)(&(y)))[1]; \ + *x++ = ((char *)(&(y)))[2]; \ + *x++ = ((char *)(&(y)))[3] + +#define COPY8(x, y) ((char *)(x))[0] = ((char *)(y))[0]; \ + ((char *)(x))[1] = ((char *)(y))[1]; \ + ((char *)(x))[2] = ((char *)(y))[2]; \ + ((char *)(x))[3] = ((char *)(y))[3]; \ + ((char *)(x))[4] = ((char *)(y))[4]; \ + ((char *)(x))[5] = ((char *)(y))[5]; \ + ((char *)(x))[6] = ((char *)(y))[6]; \ + ((char *)(x))[7] = ((char *)(y))[7] +#define LOAD8(x, y) ((char *)&(x))[0] = *y++; \ + ((char *)&(x))[1] = *y++; \ + ((char *)&(x))[2] = *y++; \ + ((char *)&(x))[3] = *y++; \ + ((char *)&(x))[4] = *y++; \ + ((char *)&(x))[5] = *y++; \ + ((char *)&(x))[6] = *y++; \ + ((char *)&(x))[7] = *y++; +#define STORE8(x, y) *x++ = ((char *)(&(y)))[0]; \ + *x++ = ((char *)(&(y)))[1]; \ + *x++ = ((char *)(&(y)))[2]; \ + *x++ = ((char *)(&(y)))[3]; \ + *x++ = ((char *)(&(y)))[4]; \ + *x++ = ((char *)(&(y)))[5]; \ + *x++ = ((char *)(&(y)))[6]; \ + *x++ = ((char *)(&(y)))[7] + +#if SIZEOF_SHORT == 2 +#define COPY_SHORT(x, y) COPY2(x,y) +#define LOAD_SHORT(x, y) LOAD2(x,y) +#define STORE_SHORT(x, y) STORE2(x,y) +#else +!shorts of size other than 2 not implemented +#endif + +#if SIZEOF_INT == 4 +#define INT_32 int +#endif + +#if SIZEOF_LONG == 4 +#define COPY_INT(x, y) COPY4(x,y) +#define LOAD_INT(x, y) LOAD4(x,y) +#define STORE_INT(x, y) STORE4(x,y) +#else +#if SIZEOF_LONG == 8 +#define COPY_INT(x, y) COPY8(x,y) +#define LOAD_INT(x, y) LOAD8(x,y) +#define STORE_INT(x, y) STORE8(x,y) +#else +!ints of size other than 4 not implemented +#endif +#endif + +#if SIZEOF_FLOAT == 4 +#define COPY_FLOAT(x, y) COPY4(x,y) +#define LOAD_FLOAT(x, y) LOAD4(x,y) +#define STORE_FLOAT(x, y) STORE4(x,y) +#else +!floats of size other than 4 not implemented +#endif + +#if SIZEOF_PTR == 4 +# define COPY_PTR(x, y) COPY4(x,y) +# define LOAD_PTR(x, y) LOAD4(x,y) +# define STORE_PTR(x, y) STORE4(x,y) + +# define POINTER_INT int +# define INS_POINTER ins_int +#else +# if SIZEOF_PTR == 8 +# define COPY_PTR(x, y) COPY8(x,y) +# define LOAD_PTR(x, y) LOAD8(x,y) +# define STORE_PTR(x, y) STORE8(x,y) + +# define POINTER_INT long +# define INS_POINTER ins_long +# else +!pointers of size other than 4 or 8 not implemented +# endif +#endif +#endif + +#ifndef _FUNC_SPEC_ + char *xalloc (int); +# ifdef DEBUGMALLOC + char *int_string_copy (const char * const, char *); + char *int_string_unlink (const char *, char *); + char *int_new_string (int, char *); + char *int_alloc_cstring (const char *, char *); +# else + char *int_string_copy (const char * const); + char *int_string_unlink (const char *); + char *int_new_string (int); + char *int_alloc_cstring (const char *); +# endif +#endif + +#ifdef DEBUGMALLOC +# define string_copy(x,y) int_string_copy(x, y) +# define string_unlink(x,y) int_string_unlink(x, y) +# define new_string(x,y) int_new_string(x, y) +# define alloc_cstring(x,y) int_alloc_cstring(x, y) +#else +# define string_copy(x,y) int_string_copy(x) +# define string_unlink(x,y) int_string_unlink(x) +# define new_string(x,y) int_new_string(x) +# define alloc_cstring(x,y) int_alloc_cstring(x) +#endif + +#ifndef INLINE +#define INLINE +#endif + +#ifndef INLINE_STATIC +# define INLINE_STATIC static INLINE +#endif + +/* The ANSI versions must take an unsigned char, and must work on EOF. These + * versions take a (possibly signed) char, and do not work correctly on EOF. + * + * Note that calling isdigit(x) where x is a signed char with x < 0 (i.e. + * high bit set) invokes undefined behavior. + */ +#define uisdigit(x) isdigit((unsigned char)x) +#define uislower(x) islower((unsigned char)x) +#define uisspace(x) isspace((unsigned char)x) +#define uisalnum(x) isalnum((unsigned char)x) +#define uisupper(x) isupper((unsigned char)x) +#define uisalpha(x) isalpha((unsigned char)x) +#define uisxdigit(x) isxdigit((unsigned char)x) +#define uisascii(x) isascii((unsigned char)x) +#define uisprint(x) isprint((unsigned char)x) + +#endif diff --git a/fluffos-2.23-ds03/main.c b/fluffos-2.23-ds03/main.c new file mode 100644 index 0000000..09357eb --- /dev/null +++ b/fluffos-2.23-ds03/main.c @@ -0,0 +1,687 @@ +#define SUPPRESS_COMPILER_INLINES +#include "std.h" +#include "file_incl.h" +#include "lpc_incl.h" +#include "backend.h" +#include "simul_efun.h" +#include "main.h" +#include "otable.h" +#include "comm.h" +#include "compiler.h" +#include "port.h" +#include "md.h" +#include "main.h" +#include "socket_efuns.h" +#include "master.h" +#include "eval.h" + +port_def_t external_port[5]; + +static int e_flag = 0; /* Load empty, without preloads. */ +int t_flag = 0; /* Disable heart beat and reset */ +int comp_flag = 0; /* Trace compilations */ +int max_cost; +int time_to_clean_up; +const char *default_fail_message; +time_t boot_time; +int max_array_size; +int max_buffer_size; +int max_string_length; +static int reserved_size; +char *reserved_area; /* reserved for MALLOC() */ +static char *mud_lib; + +double consts[NUM_CONSTS]; + +#ifndef NO_IP_DEMON +int no_ip_demon = 0; +void init_addr_server(); +#endif /* NO_IP_DEMON */ + +#ifdef SIGNAL_FUNC_TAKES_INT +#define SIGPROT (int) +#define PSIG(z) z (int sig) +#else +#define SIGPROT (void) +#define PSIG(z) z() +#endif + +static void CDECL sig_fpe SIGPROT; +static void CDECL sig_cld SIGPROT; + +#ifdef HAS_CONSOLE +static void CDECL sig_ttin SIGPROT; +#endif + +#ifdef TRAP_CRASHES +static void CDECL sig_usr1 SIGPROT; +static void CDECL sig_usr2 SIGPROT; +static void CDECL sig_term SIGPROT; +static void CDECL sig_int SIGPROT; + +#ifndef DEBUG +static void CDECL sig_hup SIGPROT, + CDECL sig_abrt SIGPROT, + CDECL sig_segv SIGPROT, + CDECL sig_ill SIGPROT, + CDECL sig_bus SIGPROT, + CDECL sig_iot SIGPROT; +#endif +#endif + +#ifdef DEBUG_MACRO +/* used by debug.h: please leave this in here -- Tru (you can change its + value if you like). +*/ +int debug_level = 0; +#endif + +int main (int argc, char ** argv) +{ + time_t tm; + int i, new_mudlib = 0, got_defaults = 0; + char *p; + char version_buf[80]; +#if 0 + int dtablesize; +#endif + error_context_t econ; + +#ifdef PROTO_TZSET + void tzset(); +#endif + +#ifdef INCL_LOCALE_H + setlocale(LC_ALL, "C"); +#endif + +#if !defined(__SASC) && (defined(AMITCP) || defined(AS225)) + amiga_sockinit(); + atexit(amiga_sockexit); +#endif +#ifdef WRAPPEDMALLOC + wrappedmalloc_init(); +#endif /* WRAPPEDMALLOC */ +#ifdef DEBUGMALLOC + MDinit(); +#endif + +#if (defined(PROFILING) && !defined(PROFILE_ON) && defined(HAS_MONCONTROL)) + moncontrol(0); +#endif +#ifdef USE_TZSET + tzset(); +#endif + boot_time = get_current_time(); + + const0.type = T_NUMBER; + const0.u.number = 0; + const1.type = T_NUMBER; + const1.u.number = 1; + + /* const0u used by undefinedp() */ + const0u.type = T_NUMBER; + const0u.subtype = T_UNDEFINED; + const0u.u.number = 0; + + //fake_prog.program_size = 0; //0 anyway + + /* + * Check that the definition of EXTRACT_UCHAR() is correct. + */ + p = (char *) &i; + *p = -10; + if (EXTRACT_UCHAR(p) != 0x100 - 10) { + fprintf(stderr, "Bad definition of EXTRACT_UCHAR() in interpret.h.\n"); + exit(-1); + } + + /* + * An added test: can we do EXTRACT_UCHAR(x++)? + * (read_number, etc uses it) + */ + p = (char *) &i; + (void) EXTRACT_UCHAR(p++); + if ((p - (char *) &i) != 1) { + fprintf(stderr, "EXTRACT_UCHAR() in interpret.h evaluates its argument more than once.\n"); + exit(-1); + } + + /* + * Check the living hash table size + */ + if (CFG_LIVING_HASH_SIZE != 4 && CFG_LIVING_HASH_SIZE != 16 && + CFG_LIVING_HASH_SIZE != 64 && CFG_LIVING_HASH_SIZE != 256 && + CFG_LIVING_HASH_SIZE != 1024 && CFG_LIVING_HASH_SIZE != 4096) { + fprintf(stderr, "CFG_LIVING_HASH_SIZE in options.h must be one of 4, 16, 64, 256, 1024, 4096, ...\n"); + exit(-1); + } + +#ifdef RAND + srand(get_current_time()); +#else +# ifdef DRAND48 + srand48(get_current_time()); +# else +# ifdef RANDOM + srandom(get_current_time()); +# else + fprintf(stderr, "Warning: no random number generator specified!\n"); +# endif +# endif +#endif + current_time = get_current_time(); + /* + * Initialize the microsecond clock. + */ + init_usec_clock(); + + /* read in the configuration file */ + + got_defaults = 0; + for (i = 1; (i < argc) && !got_defaults; i++) { + if (argv[i][0] != '-') { + set_defaults(argv[i]); + got_defaults = 1; + } + } + get_version(version_buf); + if (!got_defaults) { + fprintf(stderr, "%s for %s.\n", version_buf, ARCH); + fprintf(stderr, "You must specify the configuration filename as an argument.\n"); + exit(-1); + } + + printf("Initializing internal tables....\n"); + init_strings(); /* in stralloc.c */ + init_otable(); /* in otable.c */ + init_identifiers(); /* in lex.c */ + init_locals(); /* in compiler.c */ + + /* + * If our estimate is larger than FD_SETSIZE, then we need more file + * descriptors than the operating system can handle. This is a problem + * that can be resolved by decreasing MAX_USERS, MAX_EFUN_SOCKS, or both. + * + * Unfortunately, since neither MAX_USERS or MAX_EFUN_SOCKS exist any more, + * we have no clue how many we will need. This code really should be + * moved to places where ENFILE/EMFILE is returned. + */ +#if 0 + if (dtablesize > FD_SETSIZE) { + fprintf(stderr, "Warning: File descriptor requirements exceed system capacity!\n"); + fprintf(stderr, " Configuration exceeds system capacity by %d descriptor(s).\n", + dtablesize - FD_SETSIZE); + } +#ifdef HAS_SETDTABLESIZE + /* + * If the operating system supports setdtablesize() then we can request + * the number of file descriptors we really need. First check to see if + * wee already have enough. If so dont bother the OS. If not, attempt to + * allocate the number we estimated above. There are system imposed + * limits on file descriptors, so we may not get as many as we asked for. + * Check to make sure we get enough. + */ + if (getdtablesize() < dtablesize) + if (setdtablesize(dtablesize) < dtablesize) { + fprintf(stderr, "Warning: Could not allocate enough file descriptors!\n"); + fprintf(stderr, " setdtablesize() could not allocate %d descriptor(s).\n", + getdtablesize() - dtablesize); + } + /* + * Just be polite and tell the administrator how many he has. + */ + fprintf(stderr, "%d file descriptors were allocated, (%d were requested).\n", + getdtablesize(), dtablesize); +#endif +#endif + time_to_clean_up = TIME_TO_CLEAN_UP; + max_cost = MAX_COST; + reserved_size = RESERVED_SIZE; + max_array_size = MAX_ARRAY_SIZE; + if(max_array_size > 2147483647){ + fprintf(stderr, "Maximum array size can not exceed 65535"); + max_array_size = 2147483647; + } + max_buffer_size = MAX_BUFFER_SIZE; + max_string_length = MAX_STRING_LENGTH; + mud_lib = (char *) MUD_LIB; + set_inc_list(INCLUDE_DIRS); + if (reserved_size > 0) + reserved_area = (char *) DMALLOC(reserved_size, TAG_RESERVED, "main.c: reserved_area"); + for (i = 0; i < sizeof consts / sizeof consts[0]; i++) + consts[i] = exp(-i / 900.0); + reset_machine(1); + /* + * The flags are parsed twice ! The first time, we only search for the -m + * flag, which specifies another mudlib, and the D-flags, so that they + * will be available when compiling master.c. + */ + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') + continue; + switch (argv[i][1]) { + case 'D': + if (argv[i][2]) { + lpc_predef_t *tmp = ALLOCATE(lpc_predef_t, TAG_PREDEFINES, + "predef"); + tmp->flag = argv[i] + 2; + tmp->next = lpc_predefs; + lpc_predefs = tmp; + continue; + } + fprintf(stderr, "Illegal flag syntax: %s\n", argv[i]); + exit(-1); + case 'N': + no_ip_demon++; + continue; +#ifdef HAS_CONSOLE + case 'C': + has_console = 1; + continue; +#endif +#ifdef YYDEBUG + case 'y': + yydebug = 1; + continue; +#endif /* YYDEBUG */ + case 'm': + mud_lib = alloc_cstring(argv[i] + 2, "mudlib dir"); + if (chdir(mud_lib) == -1) { + fprintf(stderr, "Bad mudlib directory: %s\n", mud_lib); + exit(-1); + } + new_mudlib = 1; + break; + } + } + if (!new_mudlib && chdir(mud_lib) == -1) { + fprintf(stderr, "Bad mudlib directory: %s\n", mud_lib); + exit(-1); + } + time(&tm); + debug_message("----------------------------------------------------------------------------\n%s (%s) starting up on %s - %s\n\n", MUD_NAME, version_buf, ARCH, ctime(&tm)); + + add_predefines(); +#ifdef WIN32 + _tzset(); +#endif + +#ifndef NO_IP_DEMON + if (!no_ip_demon && ADDR_SERVER_IP) + init_addr_server(ADDR_SERVER_IP, ADDR_SERVER_PORT); +#endif /* NO_IP_DEMON */ + + save_context(&econ); + if (SETJMP(econ.context)) { + debug_message("The simul_efun (%s) and master (%s) objects must be loadable.\n", + SIMUL_EFUN, MASTER_FILE); + exit(-1); + } else { + init_simul_efun(SIMUL_EFUN); + init_master(); + } + set_eval(max_cost); + pop_context(&econ); + + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') { + continue; + } else { + /* + * Look at flags. -m and -o has already been tested. + */ + switch (argv[i][1]) { + case 'D': + case 'N': + case 'm': + case 'y': + case 'C': + continue; + case 'f': + save_context(&econ); + if (SETJMP(econ.context)) { + debug_message("Error while calling master::flag(\"%s\"), aborting ...\n", argv[i] + 2); + exit(-1); + } + push_constant_string(argv[i] + 2); + apply_master_ob(APPLY_FLAG, 1); + if (MudOS_is_being_shut_down) { + debug_message("Shutdown by master object.\n"); + exit(0); + } + pop_context(&econ); + continue; + case 'e': + e_flag++; + continue; + case 'p': + external_port[0].port = atoi(argv[i] + 2); + continue; + case 'd': +#ifdef DEBUG_MACRO + if (argv[i][2]) + debug_level_set(&argv[i][2]); + else + debug_level |= DBG_d_flag; +#else + debug_message("Driver must be compiled with DEBUG_MACRO on to use -d.\n"); +#endif + break; + case 'c': + comp_flag++; + continue; + case 't': + t_flag++; + continue; + default: + debug_message("Unknown flag: %s\n", argv[i]); + exit(-1); + } + } + } + if (MudOS_is_being_shut_down) + exit(1); + if (*(DEFAULT_FAIL_MESSAGE)) { + char buf[8192]; + + strcpy(buf, DEFAULT_FAIL_MESSAGE); + strcat(buf, "\n"); + default_fail_message = make_shared_string(buf); + } else + default_fail_message = "What?\n"; +#ifdef PACKAGE_MUDLIB_STATS + restore_stat_files(); +#endif + preload_objects(e_flag); +#ifdef SIGFPE + signal(SIGFPE, sig_fpe); +#endif +#ifdef TRAP_CRASHES +#ifdef SIGUSR1 + signal(SIGUSR1, sig_usr1); +#endif +#ifdef SIGUSR2 + signal(SIGUSR2, sig_usr2); +#endif + signal(SIGTERM, sig_term); + signal(SIGINT, sig_int); +#ifndef DEBUG +#if defined(SIGABRT) + signal(SIGABRT, sig_abrt); +#endif +#ifdef SIGIOT + signal(SIGIOT, sig_iot); +#endif +#ifdef SIGHUP + signal(SIGHUP, sig_hup); +#endif +#ifdef SIGBUS + signal(SIGBUS, sig_bus); +#endif + signal(SIGSEGV, sig_segv); + signal(SIGILL, sig_ill); +#endif /* DEBUG */ +#endif +#ifndef WIN32 +#ifdef USE_BSD_SIGNALS + signal(SIGCHLD, sig_cld); +#else + signal(SIGCLD, sig_cld); +#endif +#endif + +#ifdef HAS_CONSOLE + if(has_console >= 0) + signal(SIGTTIN, sig_ttin); + signal(SIGTTOU, SIG_IGN); +#endif + +backend(); + return 0; +} + +#ifdef DEBUGMALLOC +char *int_string_copy (const char * const str, char * desc) +#else +char *int_string_copy (const char * const str) +#endif +{ + char *p; + int len; + + DEBUG_CHECK(!str, "Null string passed to string_copy.\n"); + len = strlen(str); + if (len > max_string_length) { + len = max_string_length; + p = new_string(len, desc); + (void) strncpy(p, str, len); + p[len] = '\0'; + } else { + p = new_string(len, desc); + (void) strncpy(p, str, len + 1); + } + return p; +} + +#ifdef DEBUGMALLOC +char *int_string_unlink (const char * str, char * desc) +#else +char *int_string_unlink (const char * str) +#endif +{ + malloc_block_t *mbt, *newmbt; + + mbt = ((malloc_block_t *)str) - 1; + mbt->ref--; + + if (mbt->size == USHRT_MAX) { + int l = strlen(str + USHRT_MAX) + USHRT_MAX; /* ouch */ + + newmbt = (malloc_block_t *)DXALLOC(l + sizeof(malloc_block_t) + 1, TAG_MALLOC_STRING, desc); + memcpy((char *)(newmbt + 1), (char *)(mbt + 1), l+1); + newmbt->size = USHRT_MAX; + ADD_NEW_STRING(USHRT_MAX, sizeof(malloc_block_t)); + } else { + newmbt = (malloc_block_t *)DXALLOC(mbt->size + sizeof(malloc_block_t) + 1, TAG_MALLOC_STRING, desc); + memcpy((char *)(newmbt + 1), (char *)(mbt + 1), mbt->size+1); + newmbt->size = mbt->size; + ADD_NEW_STRING(mbt->size, sizeof(malloc_block_t)); + } + newmbt->ref = 1; + CHECK_STRING_STATS; + + return (char *)(newmbt + 1); +} + +static FILE *debug_message_fp = 0; + +void debug_message (const char *fmt, ...) +{ + static char deb_buf[1024]; + static char *deb = deb_buf; + va_list args; + + if (!debug_message_fp) { + /* + * check whether config file specified this option + */ + if (strlen(DEBUG_LOG_FILE)) + snprintf(deb, 1023, "%s/%s", LOG_DIR, DEBUG_LOG_FILE); + else + snprintf(deb, 1023, "%s/debug.log", LOG_DIR); + deb[1023] = 0; + while (*deb == '/') + deb++; + debug_message_fp = fopen(deb, "w"); + if (!debug_message_fp) { + /* darn. We're in trouble */ + perror(deb); + abort(); + } + } + + V_START(args, fmt); + V_VAR(char *, fmt, args); + vfprintf(debug_message_fp, fmt, args); + fflush(debug_message_fp); + va_end(args); + V_START(args, fmt); + V_VAR(char *, fmt, args); + vfprintf(stderr, fmt, args); + fflush(stderr); + va_end(args); +} + +int slow_shut_down_to_do = 0; + +char *xalloc (int size) +{ + char *p; + const char *t; + static int going_to_exit; + + if (going_to_exit) + exit(3); +#ifdef DEBUG + if (size == 0) + fatal("Tried to allocate 0 bytes.\n"); +#endif + p = (char *) DMALLOC(size, TAG_MISC, "main.c: xalloc"); + if (p == 0) { + if (reserved_area) { + FREE(reserved_area); + t = "Temporarily out of MEMORY. Freeing reserve.\n"; + write(1, t, strlen(t)); + reserved_area = 0; + slow_shut_down_to_do = 6; + return xalloc(size);/* Try again */ + } + going_to_exit = 1; + fatal("Totally out of MEMORY.\n"); + } + return p; +} + +static void CDECL PSIG(sig_cld) +{ +#ifndef WIN32 + int status; +#ifdef USE_BSD_SIGNALS + while (wait3(&status, WNOHANG, NULL) > 0) + ; +#else + wait(&status); + signal(SIGCLD, sig_cld); +#endif +#endif +} + +static void CDECL PSIG(sig_fpe) +{ + signal(SIGFPE, sig_fpe); +} + +#ifdef HAS_CONSOLE +void restore_sigttin(void) { + if(has_console >= 0) + signal(SIGTTIN, sig_ttin); +} + +/* The console goes to sleep when backgrounded and can + * be woken back up with kill -SIGTTIN + */ +static void CDECL PSIG(sig_ttin) +{ char junk[1024]; + int fl; + + has_console = !has_console; + + signal(SIGTTIN, SIG_IGN); + + if(has_console) { + /* now eat all the gibberish they typed in the console when it was dead */ + fl = fcntl(STDIN_FILENO, F_GETFL); + fcntl(STDIN_FILENO, F_SETFL, fl | O_NONBLOCK); + + while(read(STDIN_FILENO, junk, 1023) > 0); /* ; */ + + /* leaving the output nonblocking is a bad idea. large outputs tend + to get truncated. + */ + fcntl(STDIN_FILENO, F_SETFL, fl); + } +} +#endif + + +#ifdef TRAP_CRASHES + +/* send this signal when the machine is about to reboot. The script + which restarts the MUD should take an exit code of 1 to mean don't + restart + */ + +static void CDECL PSIG(sig_usr1) +{ + push_constant_string("Host machine shutting down"); + push_undefined(); + push_undefined(); + apply_master_ob(APPLY_CRASH, 3); + debug_message("Received SIGUSR1, calling exit(-1)\n"); + exit(-1); +} + +/* Abort evaluation */ +static void CDECL PSIG(sig_usr2) +{ + outoftime = 1; +} + +/* + * Actually, doing all this stuff from a signal is probably illegal + * -Beek + */ +static void CDECL PSIG(sig_term) +{ + fatal("Process terminated"); +} + +static void CDECL PSIG(sig_int) +{ + fatal("Process interrupted"); +} + +#ifndef DEBUG +static void CDECL PSIG(sig_segv) +{ + fatal("Segmentation fault"); +} + +static void CDECL PSIG(sig_bus) +{ + fatal("Bus error"); +} + +static void CDECL PSIG(sig_ill) +{ + fatal("Illegal instruction"); +} + +static void CDECL PSIG(sig_hup) +{ + fatal("Hangup!"); +} + +static void CDECL PSIG(sig_abrt) +{ + fatal("Aborted"); +} + +static void CDECL PSIG(sig_iot) +{ + fatal("Aborted(IOT)"); +} +#endif /* !DEBUG */ + +#endif /* TRAP_CRASHES */ diff --git a/fluffos-2.23-ds03/main.h b/fluffos-2.23-ds03/main.h new file mode 100644 index 0000000..0e71b78 --- /dev/null +++ b/fluffos-2.23-ds03/main.h @@ -0,0 +1,48 @@ +#ifndef MAIN_H +#define MAIN_H + +#include "lpc_incl.h" +#include +/* + * main.c + */ + +#define PORT_UNDEFINED 0 +#define PORT_TELNET 1 +#define PORT_BINARY 2 +#define PORT_ASCII 3 +#define PORT_MUD 4 + +typedef struct { + int kind; + int port; + int fd; +#ifdef F_NETWORK_STATS + int in_packets; + int in_volume; + int out_packets; + int out_volume; +#endif +} port_def_t; + +extern port_def_t external_port[5]; +#ifdef PACKAGE_EXTERNAL +extern char *external_cmd[NUM_EXTERNAL_CMDS]; +#endif + +extern int t_flag; +extern int comp_flag; +extern int time_to_clean_up; +extern const char *default_fail_message; +extern time_t boot_time; +extern int max_cost; +extern int max_array_size; +extern int max_buffer_size; +extern int max_string_length; +extern char *reserved_area; +extern double consts[]; +extern int slow_shut_down_to_do; + +void CDECL debug_message(const char *, ...); + +#endif diff --git a/fluffos-2.23-ds03/make_func.h b/fluffos-2.23-ds03/make_func.h new file mode 100644 index 0000000..7ec6604 --- /dev/null +++ b/fluffos-2.23-ds03/make_func.h @@ -0,0 +1,29 @@ +#ifndef MAKE_FUNC_H +#define MAKE_FUNC_H + +#define MAX_FUNC 2048 /* If we need more than this we're in trouble! */ + +#define VOID 1 +#define INT 2 +#define STRING 3 +#define OBJECT 4 +#define MAPPING 5 +#define MIXED 6 +#define UNKNOWN 7 +#define FLOAT 8 +#define FUNCTION 9 +#define BUFFER 10 + +extern int num_buff; +extern int op_code, efun_code, efun1_code; +extern char *oper_codes[MAX_FUNC]; +extern char *efun_codes[MAX_FUNC], *efun1_codes[MAX_FUNC]; +extern char *efun_names[MAX_FUNC], *efun1_names[MAX_FUNC]; +extern const char *key[MAX_FUNC], *buf[MAX_FUNC]; + +extern int arg_types[1000], last_current_type; + +const char *ctype (int); +const char *etype (int); + +#endif diff --git a/fluffos-2.23-ds03/make_func.y b/fluffos-2.23-ds03/make_func.y new file mode 100644 index 0000000..779c9c2 --- /dev/null +++ b/fluffos-2.23-ds03/make_func.y @@ -0,0 +1,417 @@ +%{ +#define EDIT_SOURCE +#define NO_OPCODES +#include "std.h" +#include "make_func.h" +#include "lex.h" +#include "preprocess.h" +#include "edit_source.h" +#include + +#ifdef WIN32 +#define MSDOS +#include +#endif + + void mf_fatal(const char *); + void yyerror(char const *); + + int num_buff = 0; + int op_code, efun_code, efun1_code; + char *oper_codes[MAX_FUNC]; + char *efun_codes[MAX_FUNC], *efun1_codes[MAX_FUNC]; + char *efun_names[MAX_FUNC], *efun1_names[MAX_FUNC]; + const char *key[MAX_FUNC], *buf[MAX_FUNC]; + + int min_arg = -1, limit_max = 0; + +/* + * arg_types is the types of all arguments. A 0 is used as a delimiter, + * marking next argument. An argument can have several types. + */ +int arg_types[1000], last_current_type; + +/* + * Store the types of the current efun. They will be copied into the + * arg_types list if they were not already there (to save memory). + */ +int curr_arg_types[40], curr_arg_type_size; + +struct type { + const char *name; + int num; +} types[] = { +{ "void", VOID }, +{ "int", INT }, +{ "string", STRING }, +{ "object", OBJECT }, +{ "mapping", MAPPING }, +{ "mixed", MIXED }, +{ "unknown", UNKNOWN }, +{ "float", FLOAT}, +{ "function", FUNCTION}, +{ "buffer", BUFFER} +}; + +#define NELEMS(arr) (sizeof arr / sizeof arr[0]) +%} + +%union { + int number; + const char *string; +} + +%token ID NUM DEFAULT OPERATOR + +%type type arg_list basic typel arg_type typel2 NUM + +%type ID optional_ID optional_default + +%% + +specs: /* empty */ | specs spec ; + +spec: operator | func; + +operator: OPERATOR op_list ';' ; + +op_list: op | op_list ',' op ; + +op: ID + { + char f_name[500],c; + int i = 2; + sprintf(f_name, "F_%s", $1); + while ((c = f_name[i])) { + if (islower(c)) f_name[i++] = toupper(c); + else i++; + } + oper_codes[op_code] = (char *) malloc(i+1); + strcpy(oper_codes[op_code], f_name); + free((void *)$1); + + op_code++; + } ; + +optional_ID: ID | /* empty */ { $$ = ""; } ; + +optional_default: /* empty */ { $$="DEFAULT_NONE"; } + | DEFAULT ':' NUM + { + static char buf[40]; + sprintf(buf, "%i", $3); + $$ = buf; + } + | DEFAULT ':' ID + { + if (strcmp($3, "F__THIS_OBJECT")) + yyerror("Illegal default"); + $$ = "DEFAULT_THIS_OBJECT"; + } ; + +func: type ID optional_ID '(' arg_list optional_default ')' ';' + { + char buff[500]; + char f_name[500]; + int i, len; + if (min_arg == -1) + min_arg = $5; + if (min_arg > 4) mf_fatal("min_arg > 4\n"); + if ($3[0] == '\0') { + if (strlen($2) + 1 + 2 > sizeof f_name) + mf_fatal("A local buffer was too small!(1)\n"); + sprintf(f_name, "F_%s", $2); + len = strlen(f_name); + for (i=0; i < len; i++) { + if (islower(f_name[i])) + f_name[i] = toupper(f_name[i]); + } + if (min_arg == 1 && !limit_max && $5 == 1) { + efun1_codes[efun1_code] = (char *) malloc(len + 1); + strcpy(efun1_codes[efun1_code], f_name); + efun1_names[efun1_code] = (char *) malloc(len - 1); + strcpy(efun1_names[efun1_code], $2); + efun1_code++; + } else { + efun_codes[efun_code] = (char *) malloc(len + 1); + strcpy(efun_codes[efun_code], f_name); + efun_names[efun_code] = (char *) malloc(len - 1); + strcpy(efun_names[efun_code], $2); + efun_code++; + } + } else { + if (strlen($3) + 1 + 17 > sizeof f_name) + mf_fatal("A local buffer was too small(2)!\n"); + sprintf(f_name, "F_%s | F_ALIAS_FLAG", $3); + len = strlen(f_name); + for (i=0; i < len; i++) { + if (islower(f_name[i])) + f_name[i] = toupper(f_name[i]); + } + free((void *)$3); + } + for(i=0; i < last_current_type; i++) { + int j; + for (j = 0; j+i sizeof buff) + mf_fatal("Local buffer overwritten !\n"); + + key[num_buff] = $2; + buf[num_buff] = (char *) malloc(strlen(buff) + 1); + strcpy((char *)buf[num_buff], buff); + num_buff++; + min_arg = -1; + limit_max = 0; + curr_arg_type_size = 0; + } ; + +type: basic | basic '*' { $$ = $1 | 0x10000; }; + +basic: ID + { + int i = NELEMS(types); + $$ = 0; + while (i--){ + if (strcmp($1, types[i].name) == 0) { + $$ = types[i].num; + break; + } + } + if (!$$) { + char buf[256]; + sprintf(buf, "Invalid type: %s", $1); + yyerror(buf); + } + free((void *)$1); + }; + +arg_list: /* empty */ { $$ = 0; } + | typel2 { $$ = 1; if ($1) min_arg = 0; } + | arg_list ',' typel2 { $$ = $1 + 1; if ($3) min_arg = $$ - 1; } ; + +typel2: typel + { + $$ = $1; + curr_arg_types[curr_arg_type_size++] = 0; + if (curr_arg_type_size == NELEMS(curr_arg_types)) + yyerror("Too many arguments"); + } ; + +arg_type: type + { + if ($1 != VOID) { + curr_arg_types[curr_arg_type_size++] = $1; + if (curr_arg_type_size == NELEMS(curr_arg_types)) + yyerror("Too many arguments"); + } + $$ = $1; + } ; + +typel: arg_type { $$ = ($1 == VOID && min_arg == -1); } + | typel '|' arg_type { $$ = (min_arg == -1 && ($1 || $3 == VOID));} + | '.' '.' '.' { $$ = min_arg == -1 ; limit_max = 1; } ; + +%% + +const char *ctype (int n) +{ + static char buff[100]; /* 100 is such a comfortable size :-) */ + const char *p = (char *)NULL; + + if (n & 0x10000) + strcpy(buff, "TYPE_MOD_ARRAY|"); + else + buff[0] = '\0'; + n &= ~0x10000; + switch(n) { + case FLOAT: p = "TYPE_REAL"; break; + case FUNCTION: p = "TYPE_FUNCTION"; break; + case VOID: p = "TYPE_VOID"; break; + case STRING: p = "TYPE_STRING"; break; + case INT: p = "TYPE_NUMBER"; break; + case OBJECT: p = "TYPE_OBJECT"; break; + case MAPPING: p = "TYPE_MAPPING"; break; + case BUFFER: p = "TYPE_BUFFER"; break; + case MIXED: p = "TYPE_ANY"; break; + case UNKNOWN: p = "TYPE_UNKNOWN"; break; + default: yyerror("Bad type!"); + } + strcat(buff, p); + if (strlen(buff) + 1 > sizeof buff) + mf_fatal("Local buffer overwritten in ctype()"); + return buff; +} + +const char *etype1 (int n) +{ + if (n & 0x10000) + return "T_ARRAY"; + switch(n) { + case FLOAT: + return "T_REAL"; + case FUNCTION: + return "T_FUNCTION"; + case INT: + return "T_NUMBER"; + case OBJECT: + return "T_OBJECT"; + case MAPPING: + return "T_MAPPING"; + case STRING: + return "T_STRING"; + case BUFFER: + return "T_BUFFER"; + case MIXED: + return "T_ANY"; /* 0 means any type */ + default: + yyerror("Illegal type for argument"); + } + return "What?"; +} + +const char *etype (int n) +{ + int i; + int local_size = 100; + char *buff = (char *)malloc(local_size); + + for (i=0; i < curr_arg_type_size; i++) { + if (n == 0) + break; + if (curr_arg_types[i] == 0) + n--; + } + if (i == curr_arg_type_size) + return "T_ANY"; + buff[0] = '\0'; + for(; curr_arg_types[i] != 0; i++) { + const char *p; + if (curr_arg_types[i] == VOID) + continue; + if (buff[0] != '\0') + strcat(buff, "|"); + p = etype1(curr_arg_types[i]); + /* + * The number 2 below is to include the zero-byte and the next + * '|' (which may not come). + */ + if (strlen(p) + strlen(buff) + 2 > local_size) { + fprintf(stderr, "Buffer overflow!\n"); + exit(1); + } + strcat(buff, etype1(curr_arg_types[i])); + } + if (!strcmp(buff, "")) + strcpy(buff, "T_ANY"); + return buff; +} + +int ident (int); + +int yylex() { + register int c; + + for(;;) { + switch(c = getc(yyin)){ + case ' ': + case '\t': + continue; + case '\n': + current_line++; + continue; + case '!': + { + char buff[2048]; + fgets(buff, 2047, yyin); + fprintf(stderr, "Configuration problem: %s\n", buff); + exit(-1); + } + case '#': + { + int line; + + char aBuf[2048], fname[2048]; + fgets(aBuf, 2047, yyin); + if (sscanf(aBuf, "%d \"%[^\"]\"", &line, fname)) { + current_line = line; + if (current_file) free(current_file); + current_file = (char*)malloc(strlen(fname) + 1); + strcpy(current_file, fname); + } else + if (sscanf(aBuf, "%d", &line)) current_line = line; + current_line++; + continue; + } + case EOF: + fclose(yyin); + return -1; + default: + if ((c >= '0' && c <= '9') || c == '-') { + int v; + int neg = 0; + v = 0; + if (c == '-') { + neg = 1; + c = '0'; + } + do { + v = v * 10 + (c - '0'); + c = getc(yyin); + } while (c >= '0' && c <= '9'); + ungetc(c, yyin); + yylval.number = (neg ? -v : v); + return NUM; + } + if (isalunum(c)) + return ident(c); + return c; + } + } +} + +int ident (int c) +{ + char buff[100]; + int len; + + for (len = 0; isalunum(c); c = getc(yyin)) { + buff[len++] = c; + if (len == sizeof buff - 1) { + yyerror("Too long indentifier"); + break; + } + } + (void)ungetc(c, yyin); + buff[len] = '\0'; + if (!strcmp(buff, "default")) + return DEFAULT; + if (!strcmp(buff, "operator")) + return OPERATOR; + + yylval.string = (char *)malloc(strlen(buff)+1); + strcpy((char *)yylval.string, buff); + return ID; +} + diff --git a/fluffos-2.23-ds03/make_malloc.c b/fluffos-2.23-ds03/make_malloc.c new file mode 100644 index 0000000..0f3573f --- /dev/null +++ b/fluffos-2.23-ds03/make_malloc.c @@ -0,0 +1,18 @@ +/* simple little program to link the right malloc c module to malloc.c */ +/* needs to be a C program so that it can include config.h */ + +#define NO_SOCKETS +#define NO_OPCODES +#include "std.h" + +#if !defined(THE_MALLOC) && !defined(THE_WRAPPER) +int main() { + puts("Memory package and/or malloc wrapper incorrectly specified in options.h\n"); +} +#else +int main() { + unlink("malloc.c"); + unlink("mallocwrapper.c"); + return 0; +} +#endif diff --git a/fluffos-2.23-ds03/malloc_incl.h b/fluffos-2.23-ds03/malloc_incl.h new file mode 100644 index 0000000..49abc4c --- /dev/null +++ b/fluffos-2.23-ds03/malloc_incl.h @@ -0,0 +1,80 @@ +#ifndef MALLOC_INCL_H +#define MALLOC_INCL_H + +typedef struct { + int real_size; + char *buffer; +} outbuffer_t; + +void outbuf_zero (outbuffer_t *); +void outbuf_add (outbuffer_t *, const char *); +void outbuf_addchar (outbuffer_t *, char); +void CDECL outbuf_addv (outbuffer_t *, const char *, ...); +void outbuf_fix (outbuffer_t *); +void outbuf_push (outbuffer_t *); +int outbuf_extend (outbuffer_t *, int); + +#include "bsdmalloc.h" +#include "smalloc.h" +#include "wrappedmalloc.h" +#include "debugmalloc.h" + +#ifdef DEBUGMALLOC +/* tags */ +#define TAG_TEMPORARY (1 << 8) +#define TAG_PERMANENT (2 << 8) +#define TAG_COMPILER (3 << 8) +#define TAG_DATA (4 << 8) +#define TAG_MISC (5 << 8) +#define TAG_MARKED (1 << 12) + +#define TAG_PROGRAM (TAG_PERMANENT + 11) +#define TAG_CALL_OUT (TAG_PERMANENT + 12) +#define TAG_INTERACTIVE (TAG_PERMANENT + 13) +#define TAG_ED (TAG_PERMANENT + 14) + +#define TAG_INC_LIST (TAG_PERMANENT + 16) +#define TAG_PERM_IDENT (TAG_PERMANENT + 17) +#define TAG_IDENT_TABLE (TAG_PERMANENT + 18) +#define TAG_RESERVED (TAG_PERMANENT + 19) +#define TAG_MUDLIB_STATS (TAG_PERMANENT + 20) +#define TAG_OBJECT (TAG_PERMANENT + 21) +#define TAG_OBJ_TBL (TAG_PERMANENT + 22) +#define TAG_CONFIG (TAG_PERMANENT + 23) +#define TAG_SIMULS (TAG_PERMANENT + 24) +#define TAG_SENTENCE (TAG_PERMANENT + 25) +#define TAG_STR_TBL (TAG_PERMANENT + 26) +#define TAG_SWAP (TAG_PERMANENT + 27) +#define TAG_UID (TAG_PERMANENT + 28) +#define TAG_OBJ_NAME (TAG_PERMANENT + 29) +#define TAG_PREDEFINES (TAG_PERMANENT + 30) +#define TAG_LINENUMBERS (TAG_PERMANENT + 31) +#define TAG_LOCALS (TAG_PERMANENT + 32) +#define TAG_LPC_OBJECT (TAG_PERMANENT + 33) +#define TAG_USERS (TAG_PERMANENT + 34) +#define TAG_DEBUGMALLOC (TAG_PERMANENT + 35) +#define TAG_HEART_BEAT (TAG_PERMANENT + 36) +#ifdef PACKAGE_PARSER +#define TAG_PARSER (TAG_PERMANENT + 37) +#endif +#define TAG_INPUT_TO (TAG_PERMANENT + 38) +#define TAG_SOCKETS (TAG_PERMANENT + 39) +#ifdef PACKAGE_DB +#define TAG_DB (TAG_PERMANENT + 40) +#endif +#define TAG_INTERPRETER (TAG_PERMANENT + 41) + +#define TAG_STRING (TAG_DATA + 40) +#define TAG_MALLOC_STRING (TAG_DATA + 41) +#define TAG_SHARED_STRING (TAG_DATA + 42) +#define TAG_FUNP (TAG_DATA + 43) +#define TAG_ARRAY (TAG_DATA + 44) +#define TAG_MAPPING (TAG_DATA + 45) +#define TAG_MAP_NODE_BLOCK (TAG_DATA + 46) +#define TAG_MAP_TBL (TAG_DATA + 47) +#define TAG_BUFFER (TAG_DATA + 48) +#define TAG_CLASS (TAG_DATA + 49) +#endif + +#endif + diff --git a/fluffos-2.23-ds03/mapping.c b/fluffos-2.23-ds03/mapping.c new file mode 100644 index 0000000..d15262b --- /dev/null +++ b/fluffos-2.23-ds03/mapping.c @@ -0,0 +1,1324 @@ +/* 92/04/18 - cleaned up in accordance with ./src/style.guidelines */ + +#include "std.h" +#include "config.h" +#include "lpc_incl.h" +#include "md.h" +#include "efun_protos.h" + +int num_mappings = 0; +int total_mapping_size = 0; +int total_mapping_nodes = 0; + +mapping_node_t *locked_map_nodes = 0; + +/* + * LPC mapping (associative arrays) module. Contains routines for + * easy value and lvalue manipulation. + * + * Original binary tree version for LPCA written by one of the earliest MudOS + * hackers. + * - some enhancements by Truilkan@TMI + * - rewritten for MudOS to use an extensible hash table implementation styled + * after the one Perl uses in hash.c - 92/07/08 - by Truilkan@TMI + * - Beek reduced mem usage and improved speed 95/09/08; Sym optimized this + * at some point as well. + */ + +/* + growMap: based on hash.c:hsplit() from Larry Wall's Perl. + + growMap doubles the size of the hash table. It is called when FILL_PERCENT + of the buckets in the hash table contain values. This routine is + efficient since the entries in the table don't need to be rehashed (even + though the entries are redistributed across the both halves of the hash + table). +*/ + +INLINE_STATIC unsigned long node_hash (mapping_node_t * mn) { + return MAP_SVAL_HASH(mn->values[0]); +} + +INLINE int growMap (mapping_t * m) +{ + int oldsize = m->table_size + 1; + int newsize = oldsize << 1; + int i; + mapping_node_t **a, **b, **eltp, *elt; + + /* resize the hash table to be twice the old size */ + m->table = a = RESIZE(m->table, newsize, mapping_node_t *, TAG_MAP_TBL, "growMap"); + if (!a) { + /* + We couldn't grow the hash table. Rather than die, we just + accept the performance hit resulting from having an overfull + table. + This trick won't work. m->table is now zero. -Beek + */ + m->unfilled = m->table_size; + return 0; + } + /* hash table doubles in size -- keep track of the memory used */ + total_mapping_size += sizeof(mapping_node_t *) * oldsize; + debug(mapping,("mapping.c: growMap ptr = %p, size = %d\n", m, newsize)); + m->unfilled = oldsize * (unsigned)FILL_PERCENT / (unsigned)100; + m->table_size = newsize - 1; + /* zero out the new storage area (2nd half of table) */ + memset(a += oldsize, 0, oldsize * sizeof(mapping_node_t *)); + i = oldsize; + while (a--, i--) { + if ((elt = *a)) { + eltp = a, b = a + oldsize; + do { + if (node_hash(elt) & oldsize) { + *eltp = elt->next; + if (!(elt->next = *b)) m->unfilled--; + *b = elt; + elt = *eltp; + } + else elt = *(eltp = &elt->next); + } while (elt); + if (!*a) m->unfilled++; + } + } + return 1; +} + +/* + mapTraverse: iterate over the mapping, calling function 'func(elt, extra)' + for each element 'elt'. This is an attempt to encapsulate some of the + specifics of the particular data structure being used so that it won't be + so difficult to change the data structure if the need arises. + -- Truilkan 92/07/19 +*/ + +INLINE mapping_t *mapTraverse (mapping_t *m, int (*func) (mapping_t *, mapping_node_t *, void *), void *extra){ + mapping_node_t *elt, *nelt; + int j = m->table_size; + + debug(mapping,("mapTraverse %p\n", m)); + do { + for (elt = m->table[j]; elt; elt = nelt) { + nelt = elt->next; + if ((*func)(m, elt, extra)) return m; + } + } while (j--); + return m; +} + +/* free_mapping */ + +INLINE void +dealloc_mapping (mapping_t * m) +{ + debug(mapping,("mapping.c: actual free of %p\n", m)); + num_mappings--; + { + int j = m->table_size, c = MAP_COUNT(m); + mapping_node_t *elt, *nelt, **a = m->table; + + total_mapping_size -= (sizeof(mapping_t) + + sizeof(mapping_node_t *) * (j+1) + + sizeof(mapping_node_t) * c); + total_mapping_nodes -= c; +#ifdef PACKAGE_MUDLIB_STATS + add_array_size (&m->stats, - (c << 1)); +#endif + + do { + for (elt = a[j]; elt; elt = nelt) { + nelt = elt->next; + free_svalue(elt->values, "free_mapping"); + free_node(m, elt); + } + } while (j--); + + + debug(mapping, ("in free_mapping: before table\n")); + FREE((char *)a); + } + + debug(mapping, ("in free_mapping: after table\n")); + FREE((char *) m); + debug(mapping, ("in free_mapping: after m\n")); + debug(mapping,("mapping.c: free_mapping end\n")); +} + +INLINE void +free_mapping (mapping_t * m) +{ + debug(mapping,("mapping.c: free_mapping begin, ptr = %p\n", m)); + /* some other object is still referencing this mapping */ + if (--m->ref > 0) + return; + dealloc_mapping(m); +} + +static mapping_node_t *free_nodes = 0; +mapping_node_block_t *mapping_node_blocks = 0; + +#ifdef DEBUGMALLOC_EXTENSIONS +void mark_mapping_node_blocks() { + mapping_node_block_t *mnb = mapping_node_blocks; + + while (mnb) { + DO_MARK(mnb, TAG_MAP_NODE_BLOCK); + mnb = mnb->next; + } +} +#endif + +mapping_node_t *new_map_node() { + mapping_node_block_t *mnb; + mapping_node_t *ret; + int i; + + if ((ret = free_nodes)) { + free_nodes = ret->next; + } else { + mnb = ALLOCATE(mapping_node_block_t, TAG_MAP_NODE_BLOCK, "new_map_node"); + mnb->next = mapping_node_blocks; + mapping_node_blocks = mnb; + mnb->nodes[MNB_SIZE - 1].next = 0; + for (i = MNB_SIZE - 1; i--; ) + mnb->nodes[i].next = &mnb->nodes[i+1]; + ret = &mnb->nodes[0]; + free_nodes = &mnb->nodes[1]; + } + return ret; +} + +void unlock_mapping (mapping_t * m) { + mapping_node_t **mn = &locked_map_nodes; + mapping_node_t *tmp; + + while (*mn) { + if ((*mn)->values[0].u.map == m) { + free_svalue((*mn)->values + 1, "free_locked_nodes"); + /* take it out of the locked list ... */ + tmp = *mn; + *mn = (*mn)->next; + /* and add it to the free list */ + tmp->next = free_nodes; + free_nodes = tmp; + } else + mn = &((*mn)->next); + } + m->count &= ~MAP_LOCKED; +} + +void free_node (mapping_t * m, mapping_node_t * mn) { + if (m->count & MAP_LOCKED) { + mn->next = locked_map_nodes; + locked_map_nodes = mn; + mn->values[0].u.map = m; + } else { + free_svalue(mn->values + 1, "free_node"); + mn->next = free_nodes; + free_nodes = mn; + } +} + +/* allocate_mapping(int n) + + call with n == 0 if you will be doing many deletions from the map. + call with n == "approx. # of insertions you plan to do" if you won't be + doing many deletions from the map. +*/ + +INLINE mapping_t * +allocate_mapping (int n) +{ + mapping_t *newmap; + mapping_node_t **a; + + if (n > MAX_MAPPING_SIZE) n = MAX_MAPPING_SIZE; + newmap = ALLOCATE(mapping_t, TAG_MAPPING, "allocate_mapping: 1"); + debug(mapping,("mapping.c: allocate_mapping begin, newmap = %p\n", newmap)); + if (newmap == NULL) + error("Allocate_mapping - out of memory.\n"); + + if (n > MAP_HASH_TABLE_SIZE) { + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + if (n & 0xff00) n |= n >> 8; + newmap->table_size = n++; + } + else newmap->table_size = (n = MAP_HASH_TABLE_SIZE) - 1; + /* The size is actually 1 higher */ + newmap->unfilled = n * (unsigned)FILL_PERCENT /(unsigned)100; + a = newmap->table = + (mapping_node_t **)DXALLOC(n *= sizeof(mapping_node_t *), + TAG_MAP_TBL, "allocate_mapping: 3"); + if (!a) + error("Allocate_mapping 2 - out of memory.\n"); + /* zero out the hash table */ + memset(a, 0, n); + total_mapping_size += sizeof(mapping_t) + n; + newmap->ref = 1; + newmap->count = 0; +#ifdef PACKAGE_MUDLIB_STATS + if (current_object) { + assign_stats (&newmap->stats, current_object); + add_array_size (&newmap->stats, n << 1); + } else { + null_stats (&newmap->stats); + } +#endif + num_mappings++; + debug(mapping,("mapping.c: allocate_mapping end\n")); + return newmap; +} + +INLINE mapping_t * +allocate_mapping2 (array_t * arr, svalue_t * sv) +{ + mapping_t *newmap; + int i; + + newmap = allocate_mapping(arr->size); + push_refed_mapping(newmap); + + for (i = 0; i < arr->size; i++) { + svalue_t *svp, *ret; + + svp = find_for_insert(newmap, arr->item + i, 1); + if (sv->type == T_FUNCTION) { + push_svalue(arr->item + i); + ret = call_function_pointer(sv->u.fp, 1); + *svp = *ret; + ret->type = T_NUMBER; + } else { + assign_svalue_no_free(svp, sv); + } + } + + sp--; + return newmap; +} + +INLINE mapping_t * +mkmapping (array_t * k, array_t * v) { + mapping_t *newmap; + int i; + + newmap = allocate_mapping(k->size); + for (i = 0; i < k->size; i++) { + svalue_t *svp; + + svp = find_for_insert(newmap, k->item + i, 1); + assign_svalue_no_free(svp, v->item + i); + } + + return newmap; +} + +/* + copyMapping: make a copy of a mapping +*/ + +INLINE_STATIC mapping_t * +copyMapping (mapping_t *m) +{ + mapping_t *newmap; + int k = m->table_size; + mapping_node_t *elt, *nelt, **a, **b = m->table, **c; + + newmap = ALLOCATE(mapping_t, TAG_MAPPING, "copy_mapping: 1"); + if (newmap == NULL) error("copyMapping - out of memory.\n"); + newmap->table_size = k++; + newmap->unfilled = m->unfilled; + newmap->ref = 1; + c = newmap->table = CALLOCATE(k, mapping_node_t *, TAG_MAP_TBL, "copy_mapping: 2"); + if (!c) { + FREE((char *) newmap); + error("copyMapping 2 - out of memory.\n"); + } + newmap->count = m->count; + total_mapping_nodes += MAP_COUNT(m); + memset(c, 0, k * sizeof(mapping_node_t *)); + total_mapping_size += (sizeof(mapping_t) + + sizeof(mapping_node_t *) * k + + sizeof(mapping_node_t) * MAP_COUNT(m)); + +#ifdef PACKAGE_MUDLIB_STATS + if (current_object) { + assign_stats (&newmap->stats, current_object); + add_array_size (&newmap->stats, MAP_COUNT(m) << 1); + } + else null_stats (&newmap->stats); +#endif + num_mappings++; + while (k--) { + if ((elt = b[k])) { + a = c + k; + do { + nelt = new_map_node(); + + assign_svalue_no_free(nelt->values, elt->values); + assign_svalue_no_free(nelt->values + 1, elt->values + 1); + nelt->next = *a; + *a = nelt; + } while ((elt = elt->next)); + } + } + return newmap; +} + +INLINE int +restore_hash_string (char ** val, svalue_t * sv) +{ + register char *cp = *val; + char c, *start = cp; + + while ((c = *cp++) != '"') { + switch(c) { + case '\r': + *(cp-1) = '\n'; + break; + + case '\\': + { + char *news = cp - 1; + + if ((c = *news++ = *cp++)) { + while ((c = *cp++) != '"') { + if (c == '\\') { + if (!(c = *news++ = *cp++)) return ROB_STRING_ERROR; + } + else { + if (c == '\r') + c = *news++ = '\n'; + else *news++ = c; + } + } + if (!c) return ROB_STRING_ERROR; + *news = '\0'; + *val = cp; + sv->u.string = make_shared_string(start); + sv->type = T_STRING; + sv->subtype = STRING_SHARED; + return 0; + } + else return ROB_STRING_ERROR; + } + + case '\0': + return ROB_STRING_ERROR; + } + } + *val = cp; + *--cp = '\0'; + sv->u.string = make_shared_string(start); + sv->type = T_STRING; + sv->subtype = STRING_SHARED; + return 0; +} + +/* + * svalue_t_to_int: Converts an svalue into an integer index. + */ + +int svalue_to_int (svalue_t *v) +{ + if (v->type == T_STRING && v->subtype != STRING_SHARED) { + char *p = make_shared_string(v->u.string); + free_string_svalue(v); + v->subtype = STRING_SHARED; + v->u.string = p; + } + //need to make it shared or all the assumptions about string==other string only when addresses match will fail! + /* The bottom bits of pointers tend to be bad ... + * Note that this means close groups of numbers don't hash particularly + * well, but then one wonders why they aren't using an array ... + */ + return MAP_SVAL_HASH(*v); +} + +int msameval (svalue_t * arg1, svalue_t * arg2) { + return (arg1->u.number == arg2->u.number); + /* it's a union so those all do the same anyway! switch (arg1->type | arg2->type) { + case T_NUMBER: + return arg1->u.number == arg2->u.number; + case T_REAL: + return arg1->u.real == arg2->u.real; + default: + return arg1->u.arr == arg2->u.arr; + }*/ +} + +/* + mapping_delete: delete an element from the mapping +*/ + +INLINE void mapping_delete (mapping_t *m, svalue_t *lv) +{ + int i = svalue_to_int(lv) & m->table_size; + mapping_node_t **prev = m->table + i, *elt; + + if ((elt = *prev)) { + do { + if (msameval(elt->values, lv)) { + if (!(*prev = elt->next) && !m->table[i]) { + m->unfilled++; + debug(mapping,("mapping delete: bucket empty, unfilled = %i", + m->unfilled)); + } + m->count--; + total_mapping_nodes--; + total_mapping_size -= sizeof(mapping_node_t); + debug(mapping,("mapping delete: count = %i", MAP_COUNT(m))); + free_svalue(elt->values, "mapping_delete"); + free_node(m, elt); + return; + + } + prev = &(elt->next); + } while ((elt = elt->next)); + + } +} + +/* + * find_for_insert: Tries to find an address at which an rvalue + * can be inserted in a mapping. This can also be used by the + * microcode interpreter, to translate an expression [index] + * into an lvalue. + */ + +INLINE svalue_t * +find_for_insert (mapping_t * m, svalue_t * lv, int doTheFree) +{ + int oi = svalue_to_int(lv); + unsigned int i = oi & m->table_size; + mapping_node_t *n, *newnode, **a = m->table + i; + + debug(mapping,("mapping.c: hashed to %d\n", i)); + if ((n = *a)) { + do { + if (msameval(lv, n->values)) { + /* normally, the f_assign would free the old value */ + debug(mapping,("mapping.c: found %p\n", n->values)); + if (doTheFree) free_svalue(n->values + 1, "find_for_insert"); + return n->values + 1; + } + } while ((n = n->next)); + debug(mapping,("mapping.c: didn't find %p\n", lv)); + n = *a; + } + else if (!(--m->unfilled)) { + int size = m->table_size + 1; + + if (growMap(m)) { + if (oi & size) i |= size; + n = *(a = m->table + i); + } else { + error("Out of memory\n"); + } + } + + m->count++; + if (MAP_COUNT(m) > MAX_MAPPING_SIZE) { + m->count--; + debug(mapping,("mapping.c: too full")); + mapping_too_large(); + } +#ifdef PACKAGE_MUDLIB_STATS + add_array_size (&m->stats, 2); +#endif + total_mapping_size += sizeof(mapping_node_t); + debug(mapping,("mapping.c: allocated a node\n")); + newnode = new_map_node(); + assign_svalue_no_free(newnode->values, lv); + /* insert at head of bucket */ + (*a = newnode)->next = n; + lv = newnode->values + 1; + *lv = const0u; + total_mapping_nodes++; + return lv; +} + +#ifdef F_UNIQUE_MAPPING + +typedef struct unique_node_s { + svalue_t key; + int count; + struct unique_node_s *next; + int *indices; +} unique_node_t; + +typedef struct unique_m_list_s { + unique_node_t **utable; + struct unique_m_list_s *next; + unsigned int mask; +} unique_m_list_t; + +static unique_m_list_t *g_u_m_list = 0; + +static void unique_mapping_error_handler (void) +{ + unique_m_list_t *nlist = g_u_m_list; + unique_node_t **table = nlist->utable; + unique_node_t *uptr, *nptr; + int mask = nlist->mask; + + g_u_m_list = g_u_m_list->next; + + do { + if ((uptr = table[mask])) { + do { + nptr = uptr->next; + free_svalue(&uptr->key, "unique_mapping_error_handler"); + FREE((char *) uptr->indices); + FREE((char *) uptr); + } while ((uptr = nptr)); + } + } while (mask--); + FREE((char *) table); + FREE((char *) nlist); +} + +void f_unique_mapping (void) +{ + unique_m_list_t *nlist; + svalue_t *arg = sp - st_num_arg + 1, *sv; + unique_node_t **table, *uptr, *nptr; + array_t *v = arg->u.arr, *ret; + unsigned int oi, i, numkeys = 0, mask, size; + unsigned short num_arg = st_num_arg; + unsigned int nmask; + mapping_t *m; + mapping_node_t **mtable, *elt; + int *ind, j; + function_to_call_t ftc; + + process_efun_callback(1, &ftc, F_UNIQUE_MAPPING); + + size = v->size; + if (!size) { + pop_n_elems(num_arg - 1); + free_array(v); + sp->type = T_MAPPING; + sp->u.map = allocate_mapping(0); + return; + } + + if (size > MAP_HASH_TABLE_SIZE) { + size |= size >> 1; + size |= size >> 2; + size |= size >> 4; + if (size & 0xff00) size |= size >> 8; + mask = size++; + } else mask = (size = MAP_HASH_TABLE_SIZE) - 1; + + table = (unique_node_t **) DXALLOC(size *= sizeof(unique_node_t *), + 100, "f_unique_mapping:1"); + if (!table) error("Unique_mapping - Out of memory.\n"); + memset(table, 0, size); + + nlist = ALLOCATE(unique_m_list_t, 101, "f_unique_mapping:2"); + nlist->next = g_u_m_list; + nlist->utable = table; + nlist->mask = mask; + g_u_m_list = nlist; + + STACK_INC; + sp->type = T_ERROR_HANDLER; + sp->u.error_handler = unique_mapping_error_handler; + + size = v->size; + while (size--) { + push_svalue(v->item + size); + sv = call_efun_callback(&ftc, 1); + if(sv) + i = (oi = svalue_to_int(sv)) & mask; + else + i = oi = 0; + if ((uptr = table[i])) { + do { + if (msameval(&uptr->key, sv)) { + ind = uptr->indices = RESIZE(uptr->indices, uptr->count+1, + int, 102, "f_unique_mapping:3"); + ind[uptr->count++] = size; + break; + } + } while ((uptr = uptr->next)); + } + if (!uptr) { + uptr = ALLOCATE(unique_node_t, 103, "f_unique_mapping:4"); + assign_svalue_no_free(&uptr->key, sv); + uptr->count = 1; + uptr->indices = ALLOCATE(int, 104, "f_unique_mapping:5"); + uptr->indices[0] = size; + uptr->next = table[i]; + table[i] = uptr; + numkeys++; + } + } + + m = allocate_mapping(nmask = numkeys << 1); + mtable = m->table; + numkeys = 0; + + if (nmask > MAP_HASH_TABLE_SIZE) { + nmask |= nmask >> 1; + nmask |= nmask >> 2; + nmask |= nmask >> 4; + if (size & 0xff00) nmask |= nmask >> 8; + } else nmask = MAP_HASH_TABLE_SIZE - 1; + j = mask; + sv = v->item; + + do { + if ((uptr = table[j])) { + do { + nptr = uptr->next; + oi = MAP_SVAL_HASH(uptr->key); + i = oi & nmask; + if (!mtable[i] && !(--m->unfilled)) { + if (growMap(m)) { + mtable = m->table; + nmask <<= 1; + nmask--; + } else { + do { + do { + nptr = uptr->next; + free_svalue(&uptr->key, "f_unique_mapping"); + FREE((char *) uptr->indices); + FREE((char *) uptr); + } while ((uptr = nptr)); + uptr = table[--j]; + } while (j >= 0); +#ifdef PACKAGE_MUDLIB_STATS + add_array_size(&m->stats, numkeys << 1); +#endif + total_mapping_size += sizeof(mapping_node_t) * (m->count = numkeys); + total_mapping_nodes += numkeys; + free_mapping(m); + error("Out of memory\n"); + } + } + + elt = ALLOCATE(mapping_node_t, 105,"f_unique_mapping:6"); + *elt->values = uptr->key; + (elt->values + 1)->type = T_ARRAY; + ret = (elt->values + 1)->u.arr = allocate_empty_array(size = uptr->count); + ind = uptr->indices; + while (size--) { + assign_svalue_no_free(ret->item + size, sv + ind[size]); + } + elt->next = mtable[i]; + mtable[i] = elt; + FREE((char *) ind); + FREE((char *) uptr); + numkeys++; + } while ((uptr = nptr)); + } + } while (j--); + +#ifdef PACKAGE_MUDLIB_STATS + add_array_size(&m->stats, numkeys << 1); +#endif + total_mapping_size += sizeof(mapping_node_t) * (m->count = numkeys); + total_mapping_nodes += numkeys; + FREE((char *) table); + g_u_m_list = g_u_m_list->next; + FREE((char *) nlist); + sp--; + pop_n_elems(num_arg - 1); + free_array(v); + sp->type = T_MAPPING; + sp->u.map = m; +} +#endif /* End of unique_mapping */ + +/* + * load_mapping_from_aggregate: Create a new mapping, loading from an + * array of svalues. Format of data: LHS RHS LHS2 RHS2... (uses hash table) + */ + +INLINE mapping_t * +load_mapping_from_aggregate (svalue_t *sp, int n) +{ + mapping_t *m; + int mask, i, oi, count = 0; + mapping_node_t **a, *elt, *elt2; + + debug(mapping,("mapping.c: load_mapping_from_aggregate begin, size = %d\n", n)); + m = allocate_mapping(n >> 1); + if (!n) return m; + mask = m->table_size; + a = m->table; + do { + i = (oi = svalue_to_int(++sp)) & mask; + if ((elt2 = elt = a[i])) { + do { + if (msameval(sp, elt->values)) { + free_svalue(sp++, "load_mapping_from_aggregate: duplicate key"); + free_svalue(elt->values+1, "load_mapping_from_aggregate"); + *(elt->values+1) = *sp; + break; + } + } while ((elt = elt->next)); + if (elt) continue; + } + else if (!(--m->unfilled)) { + if (growMap(m)) { + a = m->table; + if (oi & ++mask) elt2 = a[i |= mask]; + mask <<= 1; + mask--; + } else{ +#ifdef PACKAGE_MUDLIB_STATS + add_array_size(&m->stats, count << 1); +#endif + total_mapping_size += sizeof(mapping_node_t) * (m->count = count); + total_mapping_nodes += count; + free_mapping(m); + error("Out of memory\n"); + } + } + + if (++count > MAX_MAPPING_SIZE) { +#ifdef PACKAGE_MUDLIB_STATS + add_array_size(&m->stats, (--count) << 1); +#endif + total_mapping_size += sizeof(mapping_node_t) * (m->count = count); + total_mapping_nodes += count; + + free_mapping(m); + mapping_too_large(); + } + + elt = new_map_node(); + *elt->values = *sp++; + *(elt->values + 1) = *sp; + (a[i] = elt)->next = elt2; + } while (n -= 2); +#ifdef PACKAGE_MUDLIB_STATS + add_array_size(&m->stats, count << 1); +#endif + total_mapping_size += sizeof(mapping_node_t) * (m->count = count); + total_mapping_nodes += count; + debug(mapping,("mapping.c: load_mapping_from_aggregate end\n")); + return m; +} + +/* is ok */ + +INLINE svalue_t * +find_in_mapping (mapping_t * m, svalue_t *lv) +{ + int i = svalue_to_int(lv) & m->table_size; + mapping_node_t *n = m->table[i]; + + while (n) { + if (msameval(n->values, lv)) return n->values + 1; + n = n->next; + } + + return &const0u; +} + +svalue_t * +find_string_in_mapping (mapping_t * m, const char * p) +{ + char *ss = findstring(p); + int i; + mapping_node_t *n; + static svalue_t str = {T_STRING, STRING_SHARED}; + if (!ss) return &const0u; + str.u.string = ss; + i = MAP_SVAL_HASH(str); + n = m->table[i & m->table_size]; + + while (n) { + if (n->values->type == T_STRING && n->values->u.string == ss) + return n->values + 1; + n = n->next; + } + return &const0u; +} + +/* + add_to_mapping: adds mapping m2 to m1 +*/ + +INLINE_STATIC void +add_to_mapping (mapping_t *m1, mapping_t *m2, int free_flag) +{ + int mask = m1->table_size, j = m2->table_size; + int count = MAP_COUNT(m1); + int i, oi; + mapping_node_t *elt1, *elt2, *newnode, *n; + mapping_node_t **a1 = m1->table, **a2 = m2->table; + svalue_t *sv; + + do { + for (elt2 = a2[j]; elt2; elt2 = elt2->next) { + i = (oi = node_hash(elt2)) & mask; + sv = elt2->values; + if ((n = elt1 = a1[i])) { + do { + if (msameval(sv, elt1->values)) { + assign_svalue(elt1->values + 1, sv + 1); + break; + } + } while ((elt1 = elt1->next)); + if (elt1) continue; + } else if (!(--m1->unfilled)) { + if (growMap(m1)) { + a1 = m1->table; + if (oi & ++mask) n = a1[i |= mask]; + mask <<= 1; + mask--; + } else{ + count -= MAP_COUNT(m1); +#ifdef PACKAGE_MUDLIB_STATS + add_array_size(&m1->stats, count << 1); +#endif + total_mapping_size += count * sizeof(mapping_node_t); + total_mapping_nodes += count; + m1->count += count; + if (free_flag) free_mapping(m1); + error("Out of memory\n"); + } + } + count++; + if (count > MAX_MAPPING_SIZE) { + if (count -= MAP_COUNT(m1) + 1) { +#ifdef PACKAGE_MUDLIB_STATS + add_array_size(&m1->stats, count << 1); +#endif + total_mapping_size += count * sizeof(mapping_node_t); + total_mapping_nodes += count; + } + m1->count += count; + mapping_too_large(); + } + + newnode = new_map_node(); + assign_svalue_no_free(newnode->values, elt2->values); + assign_svalue_no_free(newnode->values+1,elt2->values+1); + (a1[i] = newnode)->next = n; + } + } while (j--); + + if (count -= MAP_COUNT(m1)) { +#ifdef PACKAGE_MUDLIB_STATS + add_array_size(&m1->stats, count << 1); +#endif + total_mapping_size += count * sizeof(mapping_node_t); + total_mapping_nodes += count; + } + + m1->count += count; +} + +/* + unique_add_to_mapping : adds m2 to m1 but doesn't do anything + if they have common keys +*/ + +INLINE_STATIC void +unique_add_to_mapping (mapping_t *m1, mapping_t *m2, int free_flag) +{ + int mask = m1->table_size, j = m2->table_size; + int count = MAP_COUNT(m1); + int i, oi; + mapping_node_t *elt1, *elt2, *newnode, *n; + mapping_node_t **a1 = m1->table, **a2 = m2->table; + svalue_t *sv; + + do { + for (elt2 = a2[j]; elt2; elt2 = elt2->next) { + i = (oi = node_hash(elt2)) & mask; + sv = elt2->values; + if ((n = elt1 = a1[i])) { + do { + if (msameval(sv, elt1->values)) break; + } while ((elt1 = elt1->next)); + if (elt1) continue; + } + else if (!(--m1->unfilled)) { + if (growMap(m1)) { + a1 = m1->table; + if (oi & ++mask) n = a1[i |= mask]; + mask <<= 1; + mask--; + } else{ + ++m1->unfilled; + count -= MAP_COUNT(m1); +#ifdef PACKAGE_MUDLIB_STATS + add_array_size(&m1->stats, count << 1); +#endif + total_mapping_size += count * sizeof(mapping_node_t); + total_mapping_nodes += count; + m1->count += count; + if (free_flag) free_mapping(m1); + + error("Out of memory\n"); + } + } + + if (++count > MAX_MAPPING_SIZE) { + if (count -= MAP_COUNT(m1) + 1) { +#ifdef PACKAGE_MUDLIB_STATS + add_array_size(&m1->stats, count << 1); +#endif + total_mapping_size += count * sizeof(mapping_node_t); + total_mapping_nodes += count; + } + m1->count += count; + mapping_too_large(); + } + + newnode = new_map_node(); + assign_svalue_no_free(newnode->values, elt2->values); + assign_svalue_no_free(newnode->values+1,elt2->values+1); + (a1[i] = newnode)->next = n; + } + } while (j--); + + if (count -= MAP_COUNT(m1)) { +#ifdef PACKAGE_MUDLIB_STATS + add_array_size(&m1->stats, count << 1); +#endif + total_mapping_size += count * sizeof(mapping_node_t); + total_mapping_nodes += count; + } + + m1->count += count; +} + +INLINE void absorb_mapping(mapping_t *m1, mapping_t *m2){ + if (MAP_COUNT(m2)) { + if (m1 != m2) + add_to_mapping(m1, m2, 0); + } +} + +/* + add_mapping: returns a new mapping that contains everything + in two old mappings. (uses hash table) +*/ + +INLINE mapping_t * +add_mapping (mapping_t *m1, mapping_t *m2) +{ + mapping_t *newmap; + + debug(mapping,("mapping.c: add_mapping begin: %p, %p", m1, m2)); + if (MAP_COUNT(m1) >= MAP_COUNT(m2)) { + if (MAP_COUNT(m2)) { + add_to_mapping(newmap = copyMapping(m1), m2, 1); + return newmap; + } + else return copyMapping(m1); + } + else if (MAP_COUNT(m1)) { + unique_add_to_mapping(newmap = copyMapping(m2), m1, 1); + return newmap; + } + else return copyMapping(m2); + debug(mapping,("mapping.c: add_mapping end\n")); +} + +/* + map_mapping: A lot of the efuns that work on arrays, such as + filter_array(), should also work on mappings. +*/ + +#ifdef F_MAP +void +map_mapping (svalue_t * arg, int num_arg) +{ + mapping_t *m; + mapping_node_t **a, *elt; + int j; + svalue_t *ret; + function_to_call_t ftc; + + process_efun_callback(1, &ftc, F_MAP); + + if (arg->u.map->ref > 1) { + m = copyMapping(arg->u.map); + free_mapping(arg->u.map); + arg->u.map = m; + } else { + m = arg->u.map; + } + + j = m->table_size; + a = m->table; + debug(mapping,("mapping.c: map_mapping\n")); + do { + for (elt = a[j]; elt ; elt = elt->next) { + push_svalue(elt->values); + push_svalue(elt->values+1); + ret = call_efun_callback(&ftc, 2); + if (ret) assign_svalue(elt->values+1, ret); + else break; + } + } while (j--); + + pop_n_elems(num_arg-1); +} +#endif + +#ifdef F_FILTER +void +filter_mapping (svalue_t * arg, int num_arg) +{ + mapping_t *m, *newmap; + mapping_node_t **a, *elt; + mapping_node_t **b, *newnode, *n; + int j, count = 0, size; + svalue_t *ret; + unsigned int tb_index; + function_to_call_t ftc; + + process_efun_callback(1, &ftc, F_FILTER); + + if (arg->u.map->ref > 1) { + m = copyMapping(arg->u.map); + free_mapping(arg->u.map); + arg->u.map = m; + } else { + m = arg->u.map; + } + + newmap = allocate_mapping(0); + push_refed_mapping(newmap); + b = newmap->table; + size = newmap->table_size; + + a = m->table; + j = m->table_size; + debug(mapping,("mapping.c: filter_mapping\n")); + do { + for (elt = a[j]; elt ; elt = elt->next) { + push_svalue(elt->values); + push_svalue(elt->values+1); + ret = call_efun_callback(&ftc, 2); + if (!ret) break; + else if (ret->type != T_NUMBER || ret->u.number) { + tb_index = node_hash(elt) & size; + b = newmap->table + tb_index; + if (!(n = *b) && !(--newmap->unfilled)) { + if (growMap(newmap)) { + size = newmap->table_size; + tb_index = node_hash(elt) & size; + n = *(b = newmap->table + tb_index); + } else { +#ifdef PACKAGE_MUDLIB_STATS + add_array_size(&newmap->stats, count << 1); +#endif + total_mapping_size += count * sizeof(mapping_node_t); + total_mapping_nodes += count; + newmap->count = count; + error("Out of memory in filter_mapping\n"); + } + } + if (++count > MAX_MAPPING_SIZE) { + count--; +#ifdef PACKAGE_MUDLIB_STATS + add_array_size(&newmap->stats, count << 1); +#endif + total_mapping_size += count * sizeof(mapping_node_t); + total_mapping_nodes += count; + newmap->count = count; + mapping_too_large(); + } + + newnode = new_map_node(); + assign_svalue_no_free(newnode->values, elt->values); + assign_svalue_no_free(newnode->values+1, elt->values+1); + (*b = newnode)->next = n; + } + } + } while (j--); + + if (count) { +#ifdef PACKAGE_MUDLIB_STATS + add_array_size(&newmap->stats, count << 1); +#endif + total_mapping_size += count * sizeof(mapping_node_t); + total_mapping_nodes += count; + newmap->count += count; + } + + sp--; + pop_n_elems(num_arg); + push_refed_mapping(newmap); +} +#endif + +/* compose_mapping */ + +INLINE mapping_t * +compose_mapping (mapping_t *m1, mapping_t *m2, unsigned short flag) +{ + mapping_node_t *elt, *elt2, **a, **b = m2->table, **prev; + unsigned int j = m1->table_size, deleted = 0; + unsigned int mask = m2->table_size; + svalue_t *sv; + + debug(mapping,("mapping.c: compose_mapping\n")); + if (flag) + m1 = copyMapping(m1); + a = m1->table; + + do { + if ((elt = *(prev = a))) { + do { + sv = elt->values + 1; + if ((elt2 = b[svalue_to_int(sv) & mask])) { + do { + if (msameval(sv, elt2->values)) { + if (sv != elt2->values + 1) /* if m1 == m2 */ + assign_svalue(sv, elt2->values + 1); + break; + } + } while ((elt2 = elt2->next)); + } + if (!elt2) { + if (!(*prev = elt->next) && !(*a)) m1->unfilled++; + deleted++; + free_node(m1, elt); + } else { + prev = &(elt->next); + } + } while ((elt = *prev)); + } + } while (a++, j--); + + if (deleted) { + m1->count -= deleted; + total_mapping_nodes -= deleted; + total_mapping_size -= deleted * sizeof(mapping_node_t); + } + + return m1; +} + +/* mapping_indices */ + +array_t * +mapping_indices (mapping_t *m) +{ + array_t *v; + int j = m->table_size; + mapping_node_t *elt, **a = m->table; + svalue_t *sv; + + debug(mapping,("mapping_indices: size = %d\n", MAP_COUNT(m))); + + v = allocate_empty_array(MAP_COUNT(m)); + sv = v->item; + do { + for (elt = a[j]; elt; elt = elt->next) + assign_svalue_no_free(sv++, elt->values); + } while (j--); + return v; +} + +/* mapping_values */ + +array_t * +mapping_values (mapping_t *m) +{ + array_t *v; + int j = m->table_size; + mapping_node_t *elt, **a = m->table; + svalue_t *sv; + + debug(mapping,("mapping_values: size = %d\n",MAP_COUNT(m))); + + v = allocate_empty_array(MAP_COUNT(m)); + sv = v->item; + do { + for (elt = a[j]; elt; elt = elt->next) + assign_svalue_no_free(sv++, elt->values + 1); + } while (j--); + return v; +} + +/* functions for building mappings */ + +static svalue_t *insert_in_mapping (mapping_t * m, const char * key) { + svalue_t lv; + svalue_t *ret; + + lv.type = T_STRING; + lv.subtype = STRING_CONSTANT; + lv.u.string = key; + ret = find_for_insert(m, &lv, 1); + /* lv.u.string will have been converted to a shared string */ + free_string(lv.u.string); + return ret; +} + +void add_mapping_pair (mapping_t * m, const char * key, long value) +{ + svalue_t *s; + + s = insert_in_mapping(m, key); + s->type = T_NUMBER; + s->subtype = 0; + s->u.number = value; +} + +void add_mapping_string (mapping_t * m, const char * key, const char * value) +{ + svalue_t *s; + + s = insert_in_mapping(m, key); + s->type = T_STRING; + s->subtype = STRING_SHARED; + s->u.string = make_shared_string(value); +} + +void add_mapping_malloced_string (mapping_t * m, const char * key, char * value) +{ + svalue_t *s; + + s = insert_in_mapping(m, key); + s->type = T_STRING; + s->subtype = STRING_MALLOC; + s->u.string = value; +} + +void add_mapping_object (mapping_t * m, const char * key, object_t * value) +{ + svalue_t *s; + + s = insert_in_mapping(m, key); + s->type = T_OBJECT; + s->subtype = 0; + s->u.ob = value; + add_ref(value, "add_mapping_object"); +} + +void add_mapping_array (mapping_t * m, const char * key, array_t * value) +{ + svalue_t *s; + + s = insert_in_mapping(m, key); + s->type = T_ARRAY; + s->subtype = 0; + s->u.arr = value; + value->ref++; +} + +void add_mapping_shared_string (mapping_t * m, const char * key, char * value) +{ + svalue_t *s; + + s = insert_in_mapping(m, key); + s->type = T_STRING; + s->subtype = STRING_SHARED; + s->u.string = ref_string(value); +} diff --git a/fluffos-2.23-ds03/mapping.h b/fluffos-2.23-ds03/mapping.h new file mode 100644 index 0000000..9da0bda --- /dev/null +++ b/fluffos-2.23-ds03/mapping.h @@ -0,0 +1,129 @@ +/* mapping.h - 1992/07/19 */ + +/* It is usually better to include "lpc_incl.h" instead of including this + directly */ + +#ifndef _MAPPING_H +#define _MAPPING_H + +#define MAP_SVAL_HASH(x) sval_hash(x) +#include "hash.h" +#include "stralloc.h" +//#define MAP_SVAL_HASH(x) (((POINTER_INT)((x).u.number)) >> 5) +static unsigned long sval_hash(svalue_t x){ + switch(x.type) + { + case T_STRING: + return HASH(BLOCK(x.u.string)); + case T_NUMBER: + return (unsigned long)x.u.number; + case T_OBJECT: + //return HASH(BLOCK(x.u.ob->obname)); + default: + return (unsigned long)(((POINTER_INT)((x).u.number)) >> 5); + } +} + +typedef struct mapping_node_s { + struct mapping_node_s *next; + svalue_t values[2]; +} mapping_node_t; + +#define MNB_SIZE 256 + +typedef struct mapping_node_block_s { + struct mapping_node_block_s *next; + mapping_node_t nodes[MNB_SIZE]; +} mapping_node_block_t; + +#define MAP_HASH_TABLE_SIZE 8 /* must be a power of 2 */ +#define FILL_PERCENT 80 /* must not be larger than 99 */ + +#define MAPSIZE(size) sizeof(mapping_t) + +#define MAP_LOCKED 0x80000000 +#define MAP_COUNT(m) ((m)->count & ~MAP_LOCKED) + +typedef struct mapping_s { + unsigned short ref; /* how many times this map has been + * referenced */ +#ifdef DEBUG + int extra_ref; +#endif + mapping_node_t **table; /* the hash table */ + unsigned int table_size; /* # of buckets in hash table == power of 2 */ + unsigned int unfilled; /* # of buckets among 80% of total buckets that do not have entries */ + unsigned int count; /* total # of nodes actually in mapping */ +#ifdef PACKAGE_MUDLIB_STATS + statgroup_t stats; /* creators of the mapping */ +#endif +} mapping_t; + +typedef struct finfo_s { + char *func; + object_t *obj; + svalue_t *extra; + funptr_t *fp; +} finfo_t; + +typedef struct vinfo_s { + array_t *v; + int pos, size, w; +} vinfo_t; + +typedef struct minfo_s { + mapping_t *map, *newmap; +} minfo_t; + +#define mapping_too_large() \ + error("Mapping exceeded maximum allowed size of %d.\n",MAX_MAPPING_SIZE); + +#ifndef max +#define max(x,y) ((x) > (y)) ? (x) : (y) +#endif + +/* + * mapping.c + */ +extern int num_mappings; +extern int total_mapping_size; +extern int total_mapping_nodes; +extern mapping_node_t *locked_map_nodes; + +int msameval (svalue_t *, svalue_t *); +int mapping_save_size (mapping_t *); +INLINE mapping_t *mapTraverse (mapping_t *, int (*) (mapping_t *, mapping_node_t *, void *), void *); +INLINE mapping_t *load_mapping_from_aggregate (svalue_t *, int); +INLINE mapping_t *allocate_mapping (int); +INLINE mapping_t *allocate_mapping2 (array_t *, svalue_t *); +INLINE void free_mapping (mapping_t *); +INLINE svalue_t *find_in_mapping (mapping_t *, svalue_t *); +svalue_t *find_string_in_mapping (mapping_t *, const char *); +INLINE svalue_t *find_for_insert (mapping_t *, svalue_t *, int); +INLINE void absorb_mapping (mapping_t *, mapping_t *); +INLINE void mapping_delete (mapping_t *, svalue_t *); +INLINE mapping_t *add_mapping (mapping_t *, mapping_t *); +mapping_node_t *new_map_node (void); +int restore_hash_string (char **str, svalue_t *); +int growMap (mapping_t *); +void free_node (mapping_t *, mapping_node_t *); +void unlock_mapping (mapping_t *); +void map_mapping (svalue_t *, int); +void filter_mapping (svalue_t *, int); +INLINE mapping_t *compose_mapping (mapping_t *, mapping_t *, unsigned short); +array_t *mapping_indices (mapping_t *); +array_t *mapping_values (mapping_t *); +array_t *mapping_each (mapping_t *); +char *save_mapping (mapping_t *); +void dealloc_mapping (mapping_t *); +void mark_mapping_node_blocks (void); +mapping_t *mkmapping (array_t *, array_t *); +int svalue_to_int (svalue_t *); +void add_mapping_pair (mapping_t *, const char *, long); +void add_mapping_string (mapping_t *, const char *, const char *); +void add_mapping_malloced_string (mapping_t *, const char *, char *); +void add_mapping_object (mapping_t *, const char *, object_t *); +void add_mapping_array (mapping_t *, const char *, array_t *); +void add_mapping_shared_string (mapping_t *, const char *, char *); + +#endif /* _MAPPING_H */ diff --git a/fluffos-2.23-ds03/master.c b/fluffos-2.23-ds03/master.c new file mode 100644 index 0000000..9441879 --- /dev/null +++ b/fluffos-2.23-ds03/master.c @@ -0,0 +1,141 @@ +#include "std.h" +#include "comm.h" +#include "master.h" +#include "efuns_main.h" +#include "otable.h" + +object_t *master_ob = 0; +function_lookup_info_t *master_applies = 0; + +/* Note that now, once the master object loads once, there is ALWAYS a + * master object, so the only way this can fail is if the master object + * hasn't loaded yet. In that case, we return (svalue_t *)-1, and the + * calling routine should let the check succeed. + */ +svalue_t *apply_master_ob (int fun, int num_arg) +{ + if (!master_ob) { + pop_n_elems(num_arg); + return (svalue_t *)-1; + } + + if (master_applies[fun].func) { +#ifdef TRACE + if (TRACEP(TRACE_APPLY)) { + do_trace("master apply", master_applies[fun].func->funcname, "\n"); + } +#endif + + call_direct(master_ob, master_applies[fun].index, + ORIGIN_DRIVER, num_arg); + free_svalue(&apply_ret_value, "apply_master_ob"); + apply_ret_value = *sp--; + return &apply_ret_value; + } else { + pop_n_elems(num_arg); + return 0; + } +} + +/* Hmm, need something like a safe_call_direct() to do this one */ +svalue_t *safe_apply_master_ob (int fun, int num_arg) +{ + if (!master_ob) { + pop_n_elems(num_arg); + return (svalue_t *)-1; + } + return safe_apply(applies_table[fun], master_ob, num_arg, ORIGIN_DRIVER); +} + +void init_master() { + char buf[512]; + object_t *new_ob; + + if (!strip_name(MASTER_FILE, buf, sizeof buf)) + error("Illegal master file name '%s'\n", MASTER_FILE); + + new_ob = load_object(buf, compiled_version); + if (new_ob == 0) { + fprintf(stderr, "The master file %s was not loaded.\n", + MASTER_FILE); + exit(-1); + } + set_master(new_ob); +} + +static void get_master_applies (object_t * ob) { + int i; + + /* master_applies will be allocated if we're recompiling master_ob */ + if (master_applies) + FREE(master_applies); + master_applies = CALLOCATE(NUM_MASTER_APPLIES, function_lookup_info_t, + TAG_SIMULS, "get_master_applies"); + + for (i = 0; i < NUM_MASTER_APPLIES; i++) { + char *name = applies_table[i]; + int ind, ri; + + if (find_function_by_name(ob, name, &ind, &ri)) { + master_applies[i].func = find_func_entry(ob->prog, ri); + master_applies[i].index = ri; + } else { + master_applies[i].func = 0; + } + } +} + +void set_master (object_t * ob) { +#if defined(PACKAGE_UIDS) || defined(PACKAGE_MUDLIB_STATS) + int first_load = (!master_ob); +#endif +#ifdef PACKAGE_UIDS + svalue_t *ret; +#endif + + get_master_applies(ob); + master_ob = ob; + /* Make sure master_ob is never made a dangling pointer. */ + add_ref(master_ob, "set_master"); +#ifndef PACKAGE_UIDS +# ifdef PACKAGE_MUDLIB_STATS + if (first_load) { + set_backbone_domain("BACKBONE"); + set_master_author("NONAME"); + } +# endif +#else + ret = apply_master_ob(APPLY_GET_ROOT_UID, 0); + /* can't be -1 or we wouldn't be here */ + if (!ret) { + debug_message("No function %s() in master object; possibly the mudlib doesn't want PACKAGE_UIDS to be defined.\n", + applies_table[APPLY_GET_ROOT_UID]); + exit(-1); + } + if (ret->type != T_STRING) { + debug_message("%s() in master object does not work.\n", + applies_table[APPLY_GET_ROOT_UID]); + exit(-1); + } + if (first_load) { + master_ob->uid = set_root_uid(ret->u.string); + master_ob->euid = master_ob->uid; +# ifdef PACKAGE_MUDLIB_STATS + set_master_author(ret->u.string); +# endif + ret = apply_master_ob(APPLY_GET_BACKBONE_UID, 0); + if (ret == 0 || ret->type != T_STRING) { + debug_message("%s() in the master file does not work\n", + applies_table[APPLY_GET_BACKBONE_UID]); + exit(-1); + } + set_backbone_uid(ret->u.string); +# ifdef PACKAGE_MUDLIB_STATS + set_backbone_domain(ret->u.string); +# endif + } else { + master_ob->uid = add_uid(ret->u.string); + master_ob->euid = master_ob->uid; + } +#endif +} diff --git a/fluffos-2.23-ds03/master.h b/fluffos-2.23-ds03/master.h new file mode 100644 index 0000000..08b2888 --- /dev/null +++ b/fluffos-2.23-ds03/master.h @@ -0,0 +1,16 @@ +#ifndef MASTER_H +#define MASTER_H + +#include "lpc_incl.h" + +/* for apply_master_ob */ +#define MASTER_APPROVED(x) (((x)==(svalue_t *)-1) || ((x) && (((x)->type != T_NUMBER) || (x)->u.number))) + +extern object_t *master_ob; + +svalue_t *apply_master_ob (int, int); +svalue_t *safe_apply_master_ob (int, int); +void init_master (void); +void set_master (object_t *); + +#endif diff --git a/fluffos-2.23-ds03/md.c b/fluffos-2.23-ds03/md.c new file mode 100644 index 0000000..c31453d --- /dev/null +++ b/fluffos-2.23-ds03/md.c @@ -0,0 +1,1062 @@ +#include "std.h" +#include "lpc_incl.h" +#include "file.h" +#include "md.h" +#ifdef DEBUGMALLOC_EXTENSIONS +#include "comm.h" +#include "lex.h" +#include "simul_efun.h" +#include "call_out.h" +#include "mapping.h" +#if defined(PACKAGE_SOCKETS) || defined(PACKAGE_EXTERNAL) +#include "socket_efuns.h" +#endif +#endif +#include "master.h" + +#ifdef PACKAGE_PARSER +#include "packages/parser.h" +#endif + +/* + note: do not use MALLOC() etc. in this module. Unbridled recursion + will occur. (use malloc() etc. instead) + + This module introduces quite a lot of overhead but it can be useful + for tracking down memory leaks or for catching the freeing on non-malloc'd + data. This module could easily be extended to allow the malloced memory + chunks to be tagged with a string label. +*/ + +#ifdef DEBUGMALLOC + +#define LEFT_MAGIC(node) ((node)->magic) +#define RIGHT_MAGIC_ADDR(node) ((unsigned char *)(node) + sizeof(md_node_t) + (node)->size) +#define STORE_RIGHT_MAGIC(node) \ + *(RIGHT_MAGIC_ADDR(node)) = (char)(MD_MAGIC >> 24) & 0xff; \ + *(RIGHT_MAGIC_ADDR(node)+1) = (char)(MD_MAGIC >> 16) & 0xff; \ + *(RIGHT_MAGIC_ADDR(node)+2) = (char)(MD_MAGIC >> 8) & 0xff; \ + *(RIGHT_MAGIC_ADDR(node)+3) = (char)MD_MAGIC & 0xff +#define FETCH_RIGHT_MAGIC(l, node) \ + l = (*(RIGHT_MAGIC_ADDR(node)) << 24) + \ + (*(RIGHT_MAGIC_ADDR(node) + 1) << 16) + \ + (*(RIGHT_MAGIC_ADDR(node) + 2) << 8) + \ + (*(RIGHT_MAGIC_ADDR(node) + 3)) + +int totals[MAX_CATEGORY]; +int blocks[MAX_CATEGORY]; + +static char *sources[] = { + "*", "temporary blocks", "permanent blocks", "compiler blocks", + "data blocks", "miscellaneous blocks", "<#6>", "<#7>", "<#8>", "<#9>", + "<#10>", "program blocks", "call_out blocks", "interactives", "ed blocks", + "<#15>", "include list", "permanent identifiers", + "identifier hash table", "reserved block", "mudlib stats", "objects", + "object table", "config table", "simul_efuns", "sentences", "string table", + "free swap blocks", "uids", "object names", "predefines", "line numbers", + "compiler local blocks", "compiled program", "users", "debugmalloc overhead", + "heart_beat list", "parser", "input_to", "sockets", + "strings", "malloc strings", "shared strings", "function pointers", "arrays", + "mappings", "mapping nodes", "mapping tables", "buffers", "classes" +}; + +int malloc_mask = 121; + +static md_node_t **table; +unsigned int total_malloced = 0L; +unsigned int hiwater = 0L; + +#ifdef DEBUGMALLOC_EXTENSIONS +void check_all_blocks (int); + +outbuffer_t out; + +void MDmemcheck(); + +void MDmemcheck() { + check_all_blocks(2); + if (out.buffer) + fatal("Internal memory check failed: %s\n", out.buffer); +} +#endif + +void MDinit() +{ + int j; + + table = (md_node_t **) calloc(MD_TABLE_SIZE, sizeof(md_node_t *)); + for (j = 0; j < MAX_CATEGORY; j++) { + totals[j] = 0; + } +} + +void +MDmalloc (md_node_t * node, int size, int tag, char * desc) +{ + unsigned long h; + static int count = 0; + + if (!size) { + debug_message("md: debugmalloc: attempted to allocate zero bytes\n"); +#ifdef DEBUG + abort(); +#endif + return; + } + total_malloced += size; + if (total_malloced > hiwater) { + hiwater = total_malloced; + } + h = MD_HASH(node); + node->size = size; + node->next = table[h]; +#ifdef CHECK_MEMORY + LEFT_MAGIC(node) = MD_MAGIC; + STORE_RIGHT_MAGIC(node); +#endif +#ifdef DEBUGMALLOC_EXTENSIONS + if ((tag & 0xff) < MAX_CATEGORY) { + totals[tag & 0xff] += size; + blocks[tag & 0xff]++; + } + if (((tag >> 8) & 0xff) < MAX_CATEGORY) { + totals[(tag >> 8) & 0xff] += size; + blocks[(tag >> 8) & 0xff]++; + } + node->tag = tag; + node->id = count++; + node->desc = desc ? desc : "default"; + if (malloc_mask == node->tag) { + debug_message("MDmalloc: %5d, [%-25s], %8lx:(%d)\n", + node->tag, node->desc, PTR(node), node->size); + } +#endif + table[h] = node; +} + +#ifdef DEBUGMALLOC_EXTENSIONS +void set_tag (const void * ptr, int tag) { + md_node_t *node = PTR_TO_NODET(ptr); + + if ((node->tag & 0xff) < MAX_CATEGORY) { + totals[node->tag & 0xff] -= node->size; + blocks[node->tag & 0xff]--; + } + if (((node->tag >> 8) & 0xff) < MAX_CATEGORY) { + totals[(node->tag >> 8) & 0xff] -= node->size; + blocks[(node->tag >> 8) & 0xff]--; + } + node->tag = tag; + if ((node->tag & 0xff) < MAX_CATEGORY) { + totals[node->tag & 0xff] += node->size; + blocks[node->tag & 0xff]++; + } + if (((node->tag >> 8) & 0xff) < MAX_CATEGORY) { + totals[(node->tag >> 8) & 0xff] += node->size; + blocks[(node->tag >> 8) & 0xff]++; + } +} +#endif + +int +MDfree (void * ptr) +{ + unsigned long h; + int tmp; + md_node_t *entry, **oentry; + + h = MD_HASH(ptr); + oentry = &table[h]; + for (entry = *oentry; entry; oentry = &entry->next, entry = *oentry) { + if (entry == ptr) { + *oentry = entry->next; + total_malloced -= entry->size; + break; + } + } + if (entry) { +#ifdef CHECK_MEMORY + if (LEFT_MAGIC(entry) != MD_MAGIC) { + debug_message("MDfree: left side of entry corrupt: %s %04x at %lx\n", entry->desc, entry->tag, entry); + } + FETCH_RIGHT_MAGIC(tmp, entry); + if (tmp != MD_MAGIC) { + debug_message("MDfree: right side of entry corrupt: %s %04x at %lx\n", entry->desc, entry->tag, entry); + } +#endif +#ifdef DEBUGMALLOC_EXTENSIONS + if ((entry->tag & 0xff) < MAX_CATEGORY) { + totals[entry->tag & 0xff] -= entry->size; + blocks[entry->tag & 0xff]--; + } + if (((entry->tag >> 8) & 0xff) < MAX_CATEGORY) { + totals[(entry->tag >> 8) & 0xff] -= entry->size; + blocks[(entry->tag >> 8) & 0xff]--; + } + if (malloc_mask == entry->tag) { + debug_message("MDfree: %5d, [%-25s], %8lx:(%d)\n", + entry->tag, entry->desc, (unsigned long) PTR(entry), entry->size); + } +#endif + } else { + debug_message("md: debugmalloc: attempted to free non-malloc'd pointer %08lx\n", + (unsigned long) ptr); +#ifdef DEBUG + abort(); +#endif + return 0; + } + return 1; +} + +#ifdef DEBUGMALLOC_EXTENSIONS +char *dump_debugmalloc (char * tfn, int mask) +{ + int j, total = 0, chunks = 0, total2 = 0; + const char *fn; + md_node_t *entry; + FILE *fp; + + outbuf_zero(&out); + fn = check_valid_path(tfn, current_object, "debugmalloc", 1); + if (!fn) { + error("Invalid path '%s' for writing.\n", tfn); + } + fp = fopen(fn, "w"); + if (!fp) { + error("Unable to open %s for writing.\n", fn); + } + for (j = 0; j < MD_TABLE_SIZE; j++) { + for (entry = table[j]; entry; entry = entry->next) { + if (!mask || (entry->tag == mask)) { + fprintf(fp, "%-30s: sz %7d: id %6d: tag %08x, a %8lx\n", + entry->desc, entry->size, entry->id, entry->tag, + (unsigned long) PTR(entry)); + total += entry->size; + chunks++; + } + } + } + fprintf(fp, "total = %8d\n", total); + fprintf(fp, "# chunks = %8d\n", chunks); + fprintf(fp, "ave. bytes per chunk = %7.2f\n\n", (float) total / chunks); + fprintf(fp, "categories:\n\n"); + for (j = 0; j < MAX_CATEGORY; j++) { + fprintf(fp, "%4d: %10d\n", j, totals[j]); + total2 += totals[j]; + } + fprintf(fp, "\ntotal = %11d\n", total2); + fclose(fp); + outbuf_addv(&out, "total = %8d\n", total); + outbuf_addv(&out, "# chunks = %8d\n", chunks); + if (chunks) { + outbuf_addv(&out, "ave. bytes per chunk = %7.2f\n", (float) total / chunks); + } + outbuf_fix(&out); + return out.buffer; +} +#endif /* DEBUGMALLOC_EXTENSIONS */ + +void set_malloc_mask (int mask) +{ + malloc_mask = mask; +} + +#ifdef DEBUGMALLOC_EXTENSIONS +static void mark_object (object_t * ob) { +#ifndef NO_ADD_ACTION + sentence_t *sent; +#endif + int i; + + if (ob->prog) + ob->prog->extra_ref++; + + if (ob->obname) { + DO_MARK(ob->obname, TAG_OBJ_NAME); + } + + if (ob->replaced_program) + EXTRA_REF(BLOCK(ob->replaced_program))++; + +#ifdef PRIVS + if (ob->privs) + EXTRA_REF(BLOCK(ob->privs))++; +#endif + +#ifndef NO_ADD_ACTION + if (ob->living_name) + EXTRA_REF(BLOCK(ob->living_name))++; + + sent = ob->sent; + + while (sent) { + DO_MARK(sent, TAG_SENTENCE); + if (sent->flags & V_FUNCTION) + sent->function.f->hdr.extra_ref++; + else { + if (sent->function.s) + EXTRA_REF(BLOCK(sent->function.s))++; + } + if (sent->verb) + EXTRA_REF(BLOCK(sent->verb))++; + sent = sent->next; + } +#endif + +#ifdef PACKAGE_PARSER + if (ob->pinfo) + parser_mark(ob->pinfo); +#endif + + if (ob->prog) + for (i = 0; i < ob->prog->num_variables_total; i++) + mark_svalue(&ob->variables[i]); + else + outbuf_addv(&out, "can't mark variables; %s is swapped.\n", + ob->obname); +} + +void mark_svalue (svalue_t * sv) { + switch (sv->type) { + case T_OBJECT: + sv->u.ob->extra_ref++; + break; + case T_ARRAY: + sv->u.arr->extra_ref++; + break; + case T_CLASS: + sv->u.arr->extra_ref++; + break; + case T_MAPPING: + sv->u.map->extra_ref++; + break; + case T_FUNCTION: + sv->u.fp->hdr.extra_ref++; + break; +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + sv->u.buf->extra_ref++; + break; +#endif + case T_STRING: + switch (sv->subtype) { + case STRING_MALLOC: + MSTR_EXTRA_REF(sv->u.string)++; + break; + case STRING_SHARED: + EXTRA_REF(BLOCK(sv->u.string))++; + break; + } + } +} + +static void mark_funp (funptr_t* fp) { + if (fp->hdr.args) + fp->hdr.args->extra_ref++; + + if (fp->hdr.owner) + fp->hdr.owner->extra_ref++; + switch (fp->hdr.type) { + case FP_LOCAL | FP_NOT_BINDABLE: + if (fp->hdr.owner) + fp->hdr.owner->prog->extra_func_ref++; + break; + case FP_FUNCTIONAL: + case FP_FUNCTIONAL | FP_NOT_BINDABLE: + fp->f.functional.prog->extra_func_ref++; + break; + } +} + +static void mark_sentence (sentence_t * sent) { + if (sent->flags & V_FUNCTION) { + if (sent->function.f) + sent->function.f->hdr.extra_ref++; + } else { + if (sent->function.s) + EXTRA_REF(BLOCK(sent->function.s))++; + } +#ifndef NO_ADD_ACTION + if (sent->verb) + EXTRA_REF(BLOCK(sent->verb))++; +#endif +} + +static int print_depth = 0; + +static void md_print_array (array_t * vec) { + int i; + + outbuf_add(&out, "({ "); + for (i=0; i < vec->size; i++) { + switch (vec->item[i].type) { + case T_INVALID: + outbuf_add(&out, "INVALID"); + break; + case T_NUMBER: + outbuf_addv(&out, "%ld", vec->item[i].u.number); + break; + case T_REAL: + outbuf_addv(&out, "%f", vec->item[i].u.real); + break; + case T_STRING: + outbuf_addv(&out, "\"%s\"", vec->item[i].u.string); + break; + case T_ARRAY: + if (print_depth < 2) { + print_depth++; + md_print_array(vec->item[i].u.arr); + } else { + outbuf_add(&out, "({ ... })"); + } + break; + case T_CLASS: + outbuf_add(&out, ""); + break; +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + outbuf_add(&out, ""); + break; +#endif + case T_FUNCTION: + outbuf_add(&out, ""); + break; + case T_MAPPING: + outbuf_add(&out, ""); + break; + case T_OBJECT: + outbuf_addv(&out, "OBJ(%s)", vec->item[i].u.ob->obname); + break; + } + if (i != vec->size - 1) outbuf_add(&out, ", "); + } + outbuf_add(&out, " })\n"); + print_depth--; +} + +static void mark_config (void) { + int i; + + for (i = 0; i < NUM_CONFIG_STRS; i++) { + DO_MARK(config_str[i], TAG_STRING); + } +} + +#if defined(PACKAGE_SOCKETS) || defined(PACKAGE_EXTERNAL) +void mark_sockets (void) { + int i; + char *s; + + for (i = 0; i < max_lpc_socks; i++) { + if (lpc_socks[i].flags & S_READ_FP) { + lpc_socks[i].read_callback.f->hdr.extra_ref++; + } else + if ((s = lpc_socks[i].read_callback.s)) { + EXTRA_REF(BLOCK(s))++; + } + if (lpc_socks[i].flags & S_WRITE_FP) { + lpc_socks[i].write_callback.f->hdr.extra_ref++; + } else + if ((s = lpc_socks[i].write_callback.s)) { + EXTRA_REF(BLOCK(s))++; + } + if (lpc_socks[i].flags & S_CLOSE_FP) { + lpc_socks[i].close_callback.f->hdr.extra_ref++; + } else + if ((s = lpc_socks[i].close_callback.s)) { + EXTRA_REF(BLOCK(s))++; + } + } +} +#endif + +#ifdef STRING_STATS +static int base_overhead = 0; + +/* Compute the correct values of allocd_strings, allocd_bytes, and + * bytes_distinct_strings based on blocks that are actually allocated. + */ +void compute_string_totals (int * asp, int * abp, int * bp) { + int hsh; + md_node_t *entry; + malloc_block_t *msbl; + block_t *ssbl; + + *asp = 0; + *abp = 0; + *bp = 0; + + for (hsh = 0; hsh < MD_TABLE_SIZE; hsh++) { + for (entry = table[hsh]; entry; entry = entry->next) { + if (entry->tag == TAG_MALLOC_STRING) { + msbl = NODET_TO_PTR(entry, malloc_block_t*); + *bp += msbl->size + 1; + *asp += msbl->ref; + *abp += msbl->ref * (msbl->size + 1); + } + if (entry->tag == TAG_SHARED_STRING) { + ssbl = NODET_TO_PTR(entry, block_t*); + *bp += ssbl->size + 1; + *asp += ssbl->refs; + *abp += ssbl->refs * (ssbl->size + 1); + } + } + } +} + +/* + * Verify string statistics. out can be zero, in which case any errors + * are printed to stdout and abort() is called. Otherwise the error messages + * are added to the outbuffer. + */ +void check_string_stats (outbuffer_t * out) { + int overhead = blocks[TAG_SHARED_STRING & 0xff] * sizeof(block_t) + + blocks[TAG_MALLOC_STRING & 0xff] * sizeof(malloc_block_t); + int num = blocks[TAG_SHARED_STRING & 0xff] + blocks[TAG_MALLOC_STRING & 0xff]; + int bytes, as, ab; + + compute_string_totals(&as, &ab, &bytes); + + if (!base_overhead) + base_overhead = overhead_bytes - overhead; + overhead += base_overhead; + + if (num != num_distinct_strings) { + if (out) { + outbuf_addv(out, "WARNING: num_distinct_strings is: %i should be: %i\n", + num_distinct_strings, num); + } else { + printf("WARNING: num_distinct_strings is: %i should be: %i\n", + num_distinct_strings, num); + abort(); + } + } + if (overhead != overhead_bytes) { + if (out) { + outbuf_addv(out, "WARNING: overhead_bytes is: %i should be: %i\n", + overhead_bytes, overhead); + } else { + printf("WARNING: overhead_bytes is: %i should be: %i\n", + overhead_bytes, overhead); + abort(); + } + } + if (bytes != bytes_distinct_strings) { + if (out) { + outbuf_addv(out, "WARNING: bytes_distinct_strings is: %i should be: %i\n", + bytes_distinct_strings, bytes - (overhead - base_overhead)); + } else { + printf("WARNING: bytes_distinct_strings is: %i should be: %i\n", + bytes_distinct_strings, bytes - (overhead - base_overhead)); + abort(); + } + } + if (allocd_strings != as) { + if (out) { + outbuf_addv(out, "WARNING: allocd_strings is: %i should be: %i\n", + allocd_strings, as); + } else { + printf("WARNING: allocd_strings is: %i should be: %i\n", + allocd_strings, as); + abort(); + } + } + if (allocd_bytes != ab) { + if (out) { + outbuf_addv(out, "WARNING: allocd_bytes is: %i should be: %i\n", + allocd_bytes, ab); + } else { + printf("WARNING: allocd_bytes is: %i should be: %i\n", + allocd_bytes, ab); + abort(); + } + } +} +#endif + +/* currently: 1 - debug, 2 - suppress leak checks */ +void check_all_blocks (int flag) { + int i, j, hsh; + int tmp; + md_node_t *entry; + object_t *ob; + array_t *vec; + mapping_t *map; +#ifndef NO_BUFFER_TYPE + buffer_t *buf; +#endif + funptr_t *fp; + mapping_node_t *node; + program_t *prog; + sentence_t *sent; + char *ptr; + block_t *ssbl; + malloc_block_t *msbl; + extern svalue_t apply_ret_value; + +#if 0 + int num = 0, total = 0; +#endif + + outbuf_zero(&out); + if (!(flag & 2)) + outbuf_add(&out, "Performing memory tests ...\n"); + + for (hsh = 0; hsh < MD_TABLE_SIZE; hsh++) { + for (entry = table[hsh]; entry; entry = entry->next) { + entry->tag &= ~TAG_MARKED; +#ifdef CHECK_MEMORY + if (LEFT_MAGIC(entry) != MD_MAGIC) { + outbuf_addv(&out, "WARNING: left side of entry corrupt: %s %08lx at %lx\n", entry->desc, entry->tag, entry); + } + FETCH_RIGHT_MAGIC(tmp, entry); + if (tmp != MD_MAGIC) { + outbuf_addv(&out, "WARNING: right side of entry corrupt: %s %08lx at %lx\n", entry->desc, entry->tag, entry); + } +#endif + switch (entry->tag & 0xff00) { + case TAG_TEMPORARY: + if (!(flag & 2)) + outbuf_addv(&out, "WARNING: Found temporary block: %s %04x\n", entry->desc, entry->tag); + break; + case TAG_COMPILER: + if (!(flag & 2)) + outbuf_addv(&out, "Found compiler block: %s %04x\n", entry->desc, entry->tag); + break; + case TAG_MISC: + outbuf_addv(&out, "Found miscellaneous block: %s %04x\n", entry->desc, entry->tag); + break; + } + switch (entry->tag) { + case TAG_OBJECT: + ob = NODET_TO_PTR(entry, object_t *); + ob->extra_ref = 0; + break; + case TAG_PROGRAM: + prog = NODET_TO_PTR(entry, program_t *); + prog->extra_ref = 0; + prog->extra_func_ref = 0; + break; + case TAG_MALLOC_STRING: + { + char *str; + + msbl = NODET_TO_PTR(entry, malloc_block_t *); + /* don't give an error for the return value we are + constructing :) */ + if (msbl == MSTR_BLOCK(out.buffer)) + break; + + str = (char *)(msbl + 1); + msbl->extra_ref = 0; + if (msbl->size != USHRT_MAX && msbl->size != strlen(str)) { + outbuf_addv(&out, "Malloc'ed string length is incorrect: %s %04x '%s': is: %i should be: %i\n", entry->desc, entry->tag, str, msbl->size, strlen(str)); + } + break; + } + case TAG_SHARED_STRING: + ssbl = NODET_TO_PTR(entry, block_t *); + EXTRA_REF(ssbl) = 0; + break; + case TAG_ARRAY: + vec = NODET_TO_PTR(entry, array_t *); + vec->extra_ref = 0; + break; + case TAG_CLASS: + vec = NODET_TO_PTR(entry, array_t *); + vec->extra_ref = 0; + break; + case TAG_MAPPING: + map = NODET_TO_PTR(entry, mapping_t *); + map->extra_ref = 0; + break; + case TAG_FUNP: + fp = NODET_TO_PTR(entry, funptr_t *); + fp->hdr.extra_ref = 0; + break; +#ifndef NO_BUFFER_TYPE + case TAG_BUFFER: + buf = NODET_TO_PTR(entry, buffer_t *); + buf->extra_ref = 0; + break; +#endif + } + } + } + + if (!(flag & 2)) { + /* the easy ones to find */ + if (blocks[TAG_SIMULS & 0xff] > 3) + outbuf_add(&out, "WARNING: more than three simul_efun tables allocated.\n"); + if (blocks[TAG_INC_LIST & 0xff] > 1) + outbuf_add(&out, "WARNING: more than one include list allocated.\n"); + if (blocks[TAG_IDENT_TABLE & 0xff] > 1) + outbuf_add(&out, "WARNING: more than one identifier hash table allocated.\n"); + if (blocks[TAG_RESERVED & 0xff] > 1) + outbuf_add(&out, "WARNING: more than one reserved block allocated.\n"); + if (blocks[TAG_OBJ_TBL & 0xff] > 1) + outbuf_add(&out, "WARNING: more than object table allocated.\n"); + if (blocks[TAG_CONFIG & 0xff] > 1) + outbuf_add(&out, "WARNING: more than config file table allocated.\n"); + if (blocks[TAG_STR_TBL & 0xff] > 1) + outbuf_add(&out, "WARNING: more than string table allocated.\n"); + if (totals[TAG_CALL_OUT & 0xff] != print_call_out_usage(&out, -1)) + outbuf_add(&out, "WARNING: wrong number of call_out blocks allocated.\n"); + if (blocks[TAG_LOCALS & 0xff] > 3) + outbuf_add(&out, "WARNING: more than 3 local blocks allocated.\n"); + + if (blocks[TAG_SENTENCE & 0xff] != tot_alloc_sentence) + outbuf_addv(&out, "WARNING: tot_alloc_sentence is: %i should be: %i\n", + tot_alloc_sentence, blocks[TAG_SENTENCE & 0xff]); + if (blocks[TAG_OBJECT & 0xff] != tot_alloc_object) + outbuf_addv(&out, "WARNING: tot_alloc_object is: %i should be: %i\n", + tot_alloc_object, blocks[TAG_OBJECT & 0xff]); + if (blocks[TAG_PROGRAM & 0xff] != total_num_prog_blocks) + outbuf_addv(&out, "WARNING: total_num_prog_blocks is: %i should be: %i\n", + total_num_prog_blocks, blocks[TAG_PROGRAM & 0xff]); +#ifdef ARRAY_STATS + if (blocks[TAG_ARRAY & 0xff] != num_arrays) + outbuf_addv(&out, "WARNING: num_arrays is: %i should be: %i\n", + num_arrays, blocks[TAG_ARRAY & 0xff]); + if (totals[TAG_ARRAY & 0xff] != total_array_size) + outbuf_addv(&out, "WARNING: total_array_size is: %i should be: %i\n", + total_array_size, totals[TAG_ARRAY & 0xff]); +#endif +#ifdef CLASS_STATS + if (blocks[TAG_CLASS & 0xff] != num_classes) + outbuf_addv(&out, "WARNING: num_classes is: %i should be: %i\n", + num_classes, blocks[TAG_CLASS & 0xff]); + if (totals[TAG_CLASS & 0xff] != total_class_size) + outbuf_addv(&out, "WARNING: total_class_size is: %i should be: %i\n", + total_class_size, totals[TAG_CLASS & 0xff]); +#endif + + if (blocks[TAG_MAPPING & 0xff] != num_mappings) + outbuf_addv(&out, "WARNING: num_mappings is: %i should be: %i\n", + num_mappings, blocks[TAG_MAPPING & 0xff]); + if (blocks[TAG_MAP_TBL & 0xff] != num_mappings) + outbuf_addv(&out, "WARNING: %i tables for %i mappings\n", + blocks[TAG_MAP_TBL & 0xff], num_mappings); + if (blocks[TAG_INTERACTIVE & 0xff] != num_user) + outbuf_addv(&out, "WATNING: num_user is: %i should be: %i\n", + num_user, blocks[TAG_INTERACTIVE & 0xff]); +#ifdef STRING_STATS + check_string_stats(&out); +#endif + +#ifdef PACKAGE_EXTERNAL + for (i = 0; i < NUM_EXTERNAL_CMDS; i++) { + if (external_cmd[i]) { + DO_MARK(external_cmd[i], TAG_STRING); + } + } +#endif + + /* now do a mark and sweep check to see what should be alloc'd */ + for (i = 0; i < max_users; i++) + if (all_users[i]) { + DO_MARK(all_users[i], TAG_INTERACTIVE); + all_users[i]->ob->extra_ref++; + if (all_users[i]->input_to) { + all_users[i]->input_to->ob->extra_ref++; + DO_MARK(all_users[i]->input_to, TAG_SENTENCE); + mark_sentence(all_users[i]->input_to); + if (all_users[i]->num_carry) { + for (j = 0; j < all_users[i]->num_carry; j++) + mark_svalue(all_users[i]->carryover + j); + } + } +#ifdef PACKAGE_COMPRESS + if(all_users[i]->compressed_stream) + DO_MARK(all_users[i]->compressed_stream, TAG_INTERACTIVE); +#endif + +#ifndef NO_ADD_ACTION + if (all_users[i]->iflags & NOTIFY_FAIL_FUNC) + all_users[i]->default_err_message.f->hdr.extra_ref++; + else if (all_users[i]->default_err_message.s) + EXTRA_REF(BLOCK(all_users[i]->default_err_message.s))++; +#endif + } + + if (*(DEFAULT_FAIL_MESSAGE)) { + char buf[8192]; + + strcpy(buf, DEFAULT_FAIL_MESSAGE); + strcat(buf, "\n"); + EXTRA_REF(BLOCK(findstring(buf)))++; + } + +#ifdef PACKAGE_UIDS + mark_all_uid_nodes(); +#endif +#ifdef PACKAGE_MUDLIB_STATS + mark_mudlib_stats(); +#endif +#if defined(PACKAGE_SOCKETS) || defined(PACKAGE_EXTERNAL) + mark_sockets(); +#endif +#ifdef PACKAGE_PARSER + parser_mark_verbs(); +#endif + mark_file_sv(); + mark_all_defines(); + mark_free_sentences(); + mark_iptable(); + mark_stack(); + mark_command_giver_stack(); + mark_call_outs(); + mark_simuls(); + mark_apply_low_cache(); + mark_mapping_node_blocks(); + mark_config(); + + mark_svalue(&apply_ret_value); + + if (master_ob) + master_ob->extra_ref++; + if (simul_efun_ob) + simul_efun_ob->extra_ref++; + for (ob = obj_list; ob; ob = ob->next_all) { + ob->extra_ref++; + } + /* objects on obj_list_destruct still have a ref too */ + for (ob = obj_list_destruct; ob; ob = ob->next_all) { + ob->extra_ref++; + } + + for (hsh = 0; hsh < MD_TABLE_SIZE; hsh++) { + for (entry = table[hsh]; entry; entry = entry->next) { + switch (entry->tag & ~TAG_MARKED) { + case TAG_IDENT_TABLE: { + ident_hash_elem_t *hptr, *first; + ident_hash_elem_t **table; + int size; + + table = NODET_TO_PTR(entry, ident_hash_elem_t **); + size = (entry->size / 3) / sizeof(ident_hash_elem_t *); + for (i = 0; i < size; i++) { + first = table[i]; + if (first) { + hptr = first; + do { + if (hptr->token & (IHE_SIMUL | IHE_EFUN)) { + DO_MARK(hptr, TAG_PERM_IDENT); + } + hptr = hptr->next; + } while (hptr != first); + } + } + break; + } + case TAG_FUNP: + fp = NODET_TO_PTR(entry, funptr_t *); + mark_funp(fp); + break; + case TAG_ARRAY: + vec = NODET_TO_PTR(entry, array_t *); + if (entry->size != sizeof(array_t) + sizeof(svalue_t[1]) * (vec->size - 1)) + outbuf_addv(&out, "array size doesn't match block size: %s %04x\n", entry->desc, entry->tag); + for (i = 0; i < vec->size; i++) mark_svalue(&vec->item[i]); + break; + case TAG_CLASS: + vec = NODET_TO_PTR(entry, array_t *); + if (vec->size && entry->size != sizeof(array_t) + sizeof(svalue_t[1]) * (vec->size - 1)) + outbuf_addv(&out, "class size doesn't match block size: %s %04x\n", entry->desc, entry->tag); + for (i = 0; i < vec->size; i++) mark_svalue(&vec->item[i]); + break; + case TAG_MAPPING: + map = NODET_TO_PTR(entry, mapping_t *); + DO_MARK(map->table, TAG_MAP_TBL); + + i = map->table_size; + do { + for (node = map->table[i]; node; node = node->next) { + mark_svalue(node->values); + mark_svalue(node->values + 1); + } + } while (i--); + break; + case TAG_OBJECT: + ob = NODET_TO_PTR(entry, object_t *); + mark_object(ob); + { + object_t *tmp = obj_list; + while (tmp && tmp != ob) + tmp = tmp->next_all; + if (!tmp) { + tmp = obj_list_destruct; + while (tmp && tmp != ob) + tmp = tmp->next_all; + } + if (!tmp) { + tmp = obj_list_dangling; + while (tmp && tmp != ob) + tmp = tmp->next_all; + if (tmp) + outbuf_addv(&out, + "WARNING: %s is dangling.\n", + ob->obname); + } + if (!tmp) + outbuf_addv(&out, + "WARNING: %s not in object list.\n", + ob->obname); + } + break; + case TAG_LPC_OBJECT: + ob = NODET_TO_PTR(entry, object_t *); + if (ob->obname) { + DO_MARK(ob->obname, TAG_OBJ_NAME); + } + break; + case TAG_PROGRAM: + prog = NODET_TO_PTR(entry, program_t *); + + if (prog->line_info) { + DO_MARK(prog->file_info, TAG_LINENUMBERS); + } + + for (i = 0; i < prog->num_inherited; i++) + prog->inherit[i].prog->extra_ref++; + + for (i = 0; i < prog->num_functions_defined; i++) + if (prog->function_table[i].funcname) + EXTRA_REF(BLOCK(prog->function_table[i].funcname))++; + + for (i = 0; i < prog->num_strings; i++) + EXTRA_REF(BLOCK(prog->strings[i]))++; + + for (i = 0; i < prog->num_variables_defined; i++) + EXTRA_REF(BLOCK(prog->variable_table[i]))++; + + EXTRA_REF(BLOCK(prog->filename))++; + } + } + } + + /* now check */ + for (hsh = 0; hsh < MD_TABLE_SIZE; hsh++) { + for (entry = table[hsh]; entry; entry = entry->next) { + switch (entry->tag) { + case TAG_MUDLIB_STATS: + outbuf_addv(&out, "WARNING: Found orphan mudlib stat block: %s %04x\n", entry->desc, entry->tag); + break; + case TAG_PROGRAM: + prog = NODET_TO_PTR(entry, program_t *); + if (prog->ref != prog->extra_ref) + outbuf_addv(&out, "Bad ref count for program %s, is %d - should be %d\n", prog->filename, prog->ref, prog->extra_ref); + if (prog->func_ref != prog->extra_func_ref) + outbuf_addv(&out, "Bad function ref count for program %s, is %d - should be %d\n", prog->filename, prog->func_ref, prog->extra_func_ref); + break; + case TAG_OBJECT: + ob = NODET_TO_PTR(entry, object_t *); + if (ob->ref != ob->extra_ref) + outbuf_addv(&out, "Bad ref count for object %s, is %d - should be %d\n", ob->obname, ob->ref, ob->extra_ref); + break; + case TAG_ARRAY: + vec = NODET_TO_PTR(entry, array_t *); + if (vec->ref != vec->extra_ref) { + outbuf_addv(&out, "Bad ref count for array, is %d - should be %d\n", vec->ref, vec->extra_ref); + print_depth = 0; + md_print_array(vec); + } + break; + case TAG_CLASS: + vec = NODET_TO_PTR(entry, array_t *); + if (vec->ref != vec->extra_ref) + outbuf_addv(&out, "Bad ref count for class, is %d - should be %d\n", vec->ref, vec->extra_ref); + break; + case TAG_MAPPING: + map = NODET_TO_PTR(entry, mapping_t *); + if (map->ref != map->extra_ref) + outbuf_addv(&out, "Bad ref count for mapping, is %d - should be %d\n", map->ref, map->extra_ref); + break; + case TAG_FUNP: + fp = NODET_TO_PTR(entry, funptr_t *); + if (fp->hdr.ref != fp->hdr.extra_ref) + outbuf_addv(&out, "Bad ref count for function pointer (owned by %s), is %d - should be %d\n", (fp->hdr.owner ? fp->hdr.owner->obname : "(null)"), fp->hdr.ref, fp->hdr.extra_ref); + break; +#ifndef NO_BUFFER_TYPE + case TAG_BUFFER: + buf = NODET_TO_PTR(entry, buffer_t *); + if (buf->ref != buf->extra_ref) + outbuf_addv(&out, "Bad ref count for buffer, is %d - should be %d\n", buf->ref, buf->extra_ref); + break; +#endif + case TAG_PREDEFINES: + outbuf_addv(&out, "WARNING: Found orphan predefine: %s %04x\n", entry->desc, entry->tag); + break; + case TAG_LINENUMBERS: + outbuf_addv(&out, "WARNING: Found orphan line number block: %s %04x\n", entry->desc, entry->tag); + break; + case TAG_OBJ_NAME: + outbuf_addv(&out, "WARNING: Found orphan object name: %s %04x\n", entry->desc, entry->tag); + break; + case TAG_INTERACTIVE: + outbuf_addv(&out, "WARNING: Found orphan interactive: %s %04x\n", entry->desc, entry->tag); + break; + case TAG_UID: + outbuf_addv(&out, "WARNING: Found orphan uid node: %s %04x\n", entry->desc, entry->tag); + break; + case TAG_SENTENCE: + sent = NODET_TO_PTR(entry, sentence_t *); + outbuf_addv(&out, "WARNING: Found orphan sentence: %s:%s - %s %04x\n", sent->ob->obname, sent->function, entry->desc, entry->tag); + break; + case TAG_PERM_IDENT: + outbuf_addv(&out, "WARNING: Found orphan permanent identifier: %s %04x\n", entry->desc, entry->tag); + break; + case TAG_STRING: + ptr = NODET_TO_PTR(entry, char *); + outbuf_addv(&out, "WARNING: Found orphan malloc'ed string: \"%s\" - %s %04x\n", ptr, entry->desc, entry->tag); + break; + case TAG_MALLOC_STRING: + msbl = NODET_TO_PTR(entry, malloc_block_t *); + /* don't give an error for the return value we are + constructing :) */ + if (msbl == MSTR_BLOCK(out.buffer)) + break; + + if (msbl->ref != msbl->extra_ref) + outbuf_addv(&out, "Bad ref count for malloc string \"%s\" %s %04x, is %d - should be %d\n", (char *)(msbl + 1), entry->desc, entry->tag, msbl->ref, msbl->extra_ref); + break; + case TAG_SHARED_STRING: + ssbl = NODET_TO_PTR(entry, block_t *); + if (REFS(ssbl) != EXTRA_REF(ssbl)) + outbuf_addv(&out, "Bad ref count for shared string \"%s\", is %d - should be %d\n", STRING(ssbl), REFS(ssbl), EXTRA_REF(ssbl)); + break; + case TAG_ED: + outbuf_addv(&out, "Found allocated ed block: %s %04x\n", entry->desc, entry->tag); + break; + case TAG_MAP_TBL: + outbuf_addv(&out, "WARNING: Found orphan mapping table: %s %04x\n", entry->desc, entry->tag); + break; + case TAG_MAP_NODE_BLOCK: + outbuf_addv(&out, "WARNING: Found orphan mapping node block: %s %04x\n", entry->desc, entry->tag); + break; + } + entry->tag &= ~TAG_MARKED; + } + } + } + + if (flag & 1) { + outbuf_add(&out, "\n\n"); + outbuf_add(&out, " source blks total\n"); + outbuf_add(&out, "------------------------------ ------ --------\n"); + for (i = 1; i < MAX_CATEGORY; i++) { + if (totals[i]) + outbuf_addv(&out, "%-30s %6d %8d\n", sources[i], blocks[i], totals[i]); + if (i == 5) outbuf_add(&out, "\n"); + } + } + if (!(flag & 2)) + outbuf_push(&out); + else { + FREE_MSTR(out.buffer); + push_number(0); + } +} +#endif /* DEBUGMALLOC_EXTENSIONS */ +#endif /* DEBUGMALLOC */ diff --git a/fluffos-2.23-ds03/md.h b/fluffos-2.23-ds03/md.h new file mode 100644 index 0000000..4fb79a9 --- /dev/null +++ b/fluffos-2.23-ds03/md.h @@ -0,0 +1,66 @@ +/* used by md.c (the malloc debug module) */ + +#if defined(CHECK_MEMORY) && !defined(DEBUGMALLOC_EXTENSIONS) +#undef CHECK_MEMORY +#endif + +typedef struct md_node_s { + int size; + struct md_node_s *next; +#ifdef DEBUGMALLOC_EXTENSIONS + int id; + int tag; + char *desc; +#endif +#ifdef CHECK_MEMORY + int magic; +#endif +} md_node_t; + +#ifdef CHECK_MEMORY +#define MD_OVERHEAD (sizeof(md_node_t) + sizeof(int)) +#define MD_MAGIC 0x4bee4bee + +void check_all_blocks (int); +#else +#define MD_OVERHEAD (sizeof(md_node_t)) +#endif + +#define MD_TABLE_BITS 14 +#define MD_TABLE_SIZE (1 << MD_TABLE_BITS) +#define MD_HASH(x) (((unsigned long)x >> 3) & (MD_TABLE_SIZE - 1)) + +#define PTR(x) ((void *)(x + 1)) +#define NODET_TO_PTR(x, y) ((y)(x + 1)) +#define PTR_TO_NODET(x) ((md_node_t *)(x) - 1) + +#define DO_MARK(ptr, kind) if (PTR_TO_NODET(ptr)->tag != kind) \ + fprintf(stderr, "Expected node of type %04x: got %s %04x\n", \ + kind, PTR_TO_NODET(ptr)->desc, PTR_TO_NODET(ptr)->tag); \ + else PTR_TO_NODET(ptr)->tag |= TAG_MARKED + +#ifdef DEBUGMALLOC_EXTENSIONS +#define SET_TAG(x, y) set_tag(x, y) +#else +#define SET_TAG(x, y) +#endif + +extern int malloc_mask; +extern unsigned int total_malloced; +extern unsigned int hiwater; +void MDinit (void); +void MDmalloc (md_node_t *, int, int, char *); +int MDfree (void *); + +#ifdef DEBUGMALLOC_EXTENSIONS +struct svalue_s; + +void mark_svalue (struct svalue_s *); +void set_tag (const void *, int); +void check_string_stats (outbuffer_t *); +#endif + +#define MAX_CATEGORY 130 + + + diff --git a/fluffos-2.23-ds03/mmalloc.c b/fluffos-2.23-ds03/mmalloc.c new file mode 100644 index 0000000..054607d --- /dev/null +++ b/fluffos-2.23-ds03/mmalloc.c @@ -0,0 +1,52 @@ +#define _GNU_SOURCE +#include +#include + +#define MINSIZE 0;//4*1024-8+rsize +//(long)5*1024*1024*1024-8+rsize + +void *mmalloc(int rrsize){ + long rsize = rrsize; + rsize = rsize % 4096 < 4088?(rsize/4096)*4096+4088:(rsize/4096)*4096+8180; + long size = MINSIZE; + size = size < rsize?rsize:size; + register unsigned long *res = mmap(0,size+4,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,0,0); + if(res == -1){ + perror("malloc: "); + exit(-1); + } + mprotect(res+rsize, size-rsize, PROT_NONE); + *res=size; + return &res[1]; +} + +void mfree(void *p){ + register unsigned long *mem = p; + mem--; + munmap(mem, *mem+4); + //mprotect(mem, 4+*mem, PROT_NONE); +} + +void *mrealloc(void *p, int rrsize){ + long rsize = rrsize; + register unsigned long *mem = p; + unsigned int oldsize; + rsize = rsize % 4096 < 4088?(rsize/4096)*4096+4088:(rsize/4096)*4096+8180; + long size = MINSIZE; + size = size < rsize?rsize:size; + mem--; + oldsize = *mem+8; + mem = mremap(mem, oldsize, size+8, 1); + mprotect(mem+rsize, size-rsize, PROT_NONE); + *mem = size; + return (void *)&mem[1]; +} + +void *mcalloc(int num, int size){ + register void *p; + + size *= num; + if ((p = mmalloc(size))) + memset(p, 0, size); + return (p); +} diff --git a/fluffos-2.23-ds03/my_malloc.h b/fluffos-2.23-ds03/my_malloc.h new file mode 100644 index 0000000..17ac5bc --- /dev/null +++ b/fluffos-2.23-ds03/my_malloc.h @@ -0,0 +1,67 @@ +#ifndef MY_MALLOC_H +#define MY_MALLOC_H + +/* + * to use sysmalloc or malloc replacements + */ +#if defined(SYSMALLOC) || \ + (defined(SMALLOC) && defined(SBRK_OK)) +#define MALLOC(x) malloc(x) +#define FREE(x) free(x) +#define REALLOC(x,y) realloc(x,y) +#define CALLOC(x,y) calloc(x,y) + +#endif + +#ifdef MMALLOC +#define MALLOC(x) mmalloc(x) +#define FREE(x) mfree(x) +#define REALLOC(x,y) mrealloc(x,y) +#define CALLOC(x,y) mcalloc(x,y) +#ifndef _FUNC_SPEC_ +void mfree(void *block); +void *mrealloc(void *block, int size); +void *mcalloc(int num, int size); +void *mmalloc(int size); +#endif +#endif + +#ifdef GNUMALLOC +#define MALLOC(x) gnumalloc(x) +#define FREE(x) gnufree(x) +#define REALLOC(x,y) gnurealloc(x,y) +#define CALLOC(x,y) gnucalloc(x,y) + +#endif + +#ifdef MALLOC64 +#define MALLOC(x) malloc64(x) +#define FREE(x) free64(x) +#define REALLOC(x,y) realloc64(x,y) +#define CALLOC(x,y) calloc64(x,y) +#ifndef _FUNC_SPEC_ +void free64(void *block); +void *realloc64(void *block, int size); +void *calloc64(int num, int size); +void *malloc64(int size); +#endif +#endif + +#ifdef MALLOC32 +#define MALLOC(x) malloc32(x) +#define FREE(x) free32(x) +#define REALLOC(x,y) realloc32(x,y) +#define CALLOC(x,y) calloc32(x,y) +#ifndef _FUNC_SPEC_ +void free32(void *block); +void *realloc32(void *block, int size); +void *calloc32(int num, int size); +void *malloc32(int size); +#endif +#endif + +#define DXALLOC(x,tag,desc) xalloc(x) +#define DMALLOC(x,tag,desc) MALLOC(x) +#define DREALLOC(x,y,tag,desc) REALLOC(x,y) +#define DCALLOC(x,y,tag,desc) CALLOC(x,y) +#endif /* MY_MALLOC_H */ diff --git a/fluffos-2.23-ds03/network_incl.h b/fluffos-2.23-ds03/network_incl.h new file mode 100644 index 0000000..c611838 --- /dev/null +++ b/fluffos-2.23-ds03/network_incl.h @@ -0,0 +1,42 @@ +#ifndef NETWORK_INCL_H +#define NETWORK_INCL_H + +#ifdef INCL_SYS_TYPES_H +# include +#endif +#ifdef INCL_SYS_IOCTL_H +# include +#endif +#ifdef INCL_SYS_SOCKET_H +# include +#endif +#ifdef INCL_NETDB_H +# include +#endif +#ifdef INCL_SYS_SEMA_H +# include +#endif + +/* defined in on HP-PA/RISC; causes problems with telnet */ +#undef SE + +#ifdef INCL_ARPA_TELNET_H +# include +#else +# include "telnet.h" +#endif +#ifdef INCL_SYS_SOCKETVAR_H +# include +#endif +#ifdef INCL_SOCKET_H +# include +#endif +#ifdef INCL_RESOLVE_H +# include +#endif + +#ifdef WINSOCK +# include +#endif + +#endif diff --git a/fluffos-2.23-ds03/object.c b/fluffos-2.23-ds03/object.c new file mode 100644 index 0000000..b9bc3bf --- /dev/null +++ b/fluffos-2.23-ds03/object.c @@ -0,0 +1,2195 @@ +#include "std.h" +#include "lpc_incl.h" +#include "file_incl.h" +#include "otable.h" +#include "backend.h" +#include "comm.h" +#include "socket_efuns.h" +#include "call_out.h" +#include "port.h" +#include "file.h" +#include "hash.h" +#include "master.h" +#include "add_action.h" + +#define too_deep_save_error() \ + error("Mappings and/or arrays nested too deep (%d) for save_object\n",\ + MAX_SAVE_SVALUE_DEPTH); + +object_t *previous_ob; +int tot_alloc_object, tot_alloc_object_size; + +char *save_mapping (mapping_t *m); +INLINE_STATIC int restore_array (char **str, svalue_t *); +INLINE_STATIC int restore_class (char **str, svalue_t *); + +#ifdef F_SET_HIDE +int num_hidden = 0; + +INLINE int +valid_hide (object_t * obj) +{ + svalue_t *ret; + + if (!obj) { + return 0; + } + push_object(obj); + ret = apply_master_ob(APPLY_VALID_HIDE, 1); + return (!IS_ZERO(ret)); +} +#endif + +int save_svalue_depth = 0, max_depth; +int *sizes = 0; + +INLINE int svalue_save_size (svalue_t * v) +{ + switch(v->type) { + case T_STRING: + { + register const char *cp = v->u.string; + char c; + int size = 0; + + while ((c = *cp++)) { + if (c == '\\' || c == '"') size++; + size++; + } + return 3 + size; + } + + case T_ARRAY: + { + svalue_t *sv = v->u.arr->item; + int i = v->u.arr->size, size = 0; + + if (++save_svalue_depth > MAX_SAVE_SVALUE_DEPTH) { + save_svalue_depth = 0; + too_deep_save_error(); + } + while (i--) size += svalue_save_size(sv++); + save_svalue_depth--; + return size + 5; + } + + case T_CLASS: + { + svalue_t *sv = v->u.arr->item; + int i = v->u.arr->size, size = 0; + + if (++save_svalue_depth > MAX_SAVE_SVALUE_DEPTH) { + save_svalue_depth = 0; + too_deep_save_error(); + } + while (i--) size += svalue_save_size(sv++); + save_svalue_depth--; + return size + 5; + } + + case T_MAPPING: + { + mapping_node_t **a = v->u.map->table, *elt; + int j = v->u.map->table_size, size = 0; + + if (++save_svalue_depth > MAX_SAVE_SVALUE_DEPTH) { + save_svalue_depth = 0; + too_deep_save_error(); + } + do { + for (elt = a[j]; elt; elt = elt->next) { + size += svalue_save_size(elt->values) + + svalue_save_size(elt->values+1); + } + } while (j--); + save_svalue_depth--; + return size + 5; + } + + case T_NUMBER: + { + long res = v->u.number, len; +#if SIZEOF_LONG == 4 + len = res < 0 ? (res = (-res) & 0x7fffffff,3) : 2; +#else + len = res < 0 ? (res = (-res) & 0x7fffffffffffffff,3) : 2; +#endif + while (res>9) { + res /= 10; + len++; + } + return len; + } + + case T_REAL: + { + char buf[256]; + sprintf(buf, "%f", v->u.real); + return (strlen(buf)+1); + } + + default: + { + return 1; + } + } +} + +INLINE void save_svalue (svalue_t * v, char ** buf) +{ + switch(v->type) { + case T_STRING: + { + register char *cp = *buf; + const char *str = v->u.string; + char c; + + *cp++ = '"'; + while ((c = *str++)) { + if (c == '"' || c == '\\') { + *cp++ = '\\'; + *cp++ = c; + } + else *cp++ = (c == '\n') ? '\r' : c; + } + + *cp++ = '"'; + *(*buf = cp) = '\0'; + return; + } + + case T_ARRAY: + { + int i = v->u.arr->size; + svalue_t *sv = v->u.arr->item; + + *(*buf)++ = '('; + *(*buf)++ = '{'; + while (i--) { + save_svalue(sv++, buf); + *(*buf)++ = ','; + } + *(*buf)++ = '}'; + *(*buf)++ = ')'; + *(*buf) = '\0'; + return; + } + + case T_CLASS: + { + int i = v->u.arr->size; + svalue_t *sv = v->u.arr->item; + + *(*buf)++ = '('; + *(*buf)++ = '/'; /* Why yes, this *is* a kludge! */ + while (i--) { + save_svalue(sv++, buf); + *(*buf)++ = ','; + } + *(*buf)++ = '/'; + *(*buf)++ = ')'; + *(*buf) = '\0'; + return; + } + + case T_NUMBER: + { + long res = v->u.number, fact; + int len = 1, neg = 0; + register char *cp; + if (res < 0) { + len++; + neg = 1; +#if SIZEOF_LONG == 4 + res = (-res) & 0x7fffffff; +#else + res = (-res) & 0x7fffffffffffffff; +#endif + } + + fact = res; + while (fact > 9) { + fact /= 10; + len++; + } + *(cp = (*buf += len)) = '\0'; + do { + *--cp = res % 10 + '0'; + res /= 10; + } while (res); + if (neg) *(cp-1) = '-'; + return; + } + + case T_REAL: + { + sprintf(*buf, "%f", v->u.real); + (*buf) += strlen(*buf); + return; + } + + case T_MAPPING: + { + int j = v->u.map->table_size; + mapping_node_t **a = v->u.map->table, *elt; + + *(*buf)++ = '('; + *(*buf)++ = '['; + do { + for (elt = a[j]; elt; elt = elt->next) { + save_svalue(elt->values, buf); + *(*buf)++ = ':'; + save_svalue(elt->values + 1, buf); + *(*buf)++ = ','; + } + } while (j--); + + *(*buf)++ = ']'; + *(*buf)++ = ')'; + *(*buf) = '\0'; + return; + } + } +} + +INLINE_STATIC int +restore_internal_size (const char ** str, int is_mapping, int depth) +{ + register const char *cp = *str; + int size = 0; + char c, delim, toggle = 0; + + delim = is_mapping ? ':' : ','; + while ((c = *cp++)) { + switch(c) { + case '"': + { + while ((c = *cp++) != '"') + if ((c == '\0') || (c == '\\' && !*cp++)) { + return 0; + } + if (*cp++ != delim) return 0; + size++; + break; + } + + case '(': + { + if (*cp == '{') { + *str = ++cp; + if (!restore_internal_size(str, 0, save_svalue_depth++)) { + return 0; + } + } + else if (*cp == '[') { + *str = ++cp; + if (!restore_internal_size(str, 1, save_svalue_depth++)) { return 0;} + } + else if (*cp == '/') { + *str = ++cp; + if (!restore_internal_size(str, 0, save_svalue_depth++)) + return 0; + } else { return 0;} + + if (*(cp = *str) != delim) { return 0;} + cp++; + size++; + break; + } + + case ']': + { + if (*cp++ == ')' && is_mapping) { + *str = cp; + if (!sizes) { + max_depth = 128; + while (max_depth <= depth) max_depth <<= 1; + sizes = CALLOCATE(max_depth, int, TAG_TEMPORARY, + "restore_internal_size"); + } + else if (depth >= max_depth) { + while ((max_depth <<= 1) <= depth); + sizes = RESIZE(sizes, max_depth, int, TAG_TEMPORARY, + "restore_internal_size"); + } + sizes[depth] = size; + return 1; + } + else { return 0; } + } + + case '/': + case '}': + { + if (*cp++ == ')' && !is_mapping) { + *str = cp; + if (!sizes) { + max_depth = 128; + while (max_depth <= depth) max_depth <<= 1; + sizes = CALLOCATE(max_depth, int, TAG_TEMPORARY, + "restore_internal_size"); + } + else if (depth >= max_depth) { + while ((max_depth <<= 1) <= depth); + sizes = RESIZE(sizes, max_depth, int, TAG_TEMPORARY, + "restore_internal_size"); + } + sizes[depth] = size; + return 1; + } + else { return 0;} + } + + case ':': + case ',': + { + if (c != delim) return 0; + size++; + break; + } + + default: + { + if (!(cp = strchr(cp, delim))) return 0; + cp++; + size++; + } + } + if (is_mapping) delim = (toggle ^= 1) ? ',' : ':'; + } + return 0; +} + + + +INLINE_STATIC int +restore_size (const char ** str, int is_mapping) +{ + register const char *cp = *str; + int size = 0; + char c, delim, toggle = 0; + + delim = is_mapping ? ':' : ','; + + while ((c = *cp++)) { + switch(c) { + case '"': + { + while ((c = *cp++) != '"') + if ((c == '\0') || (c == '\\' && !*cp++)) return 0; + + if (*cp++ != delim) { return -1; } + size++; + break; + } + + case '(': + { + if (*cp == '{') { + *str = ++cp; + if (!restore_internal_size(str, 0, save_svalue_depth++)) return -1; + } + else if (*cp == '[') { + *str = ++cp; + if (!restore_internal_size(str, 1, save_svalue_depth++)) return -1; + } + else if (*cp == '/') { + *str = ++cp; + if (!restore_internal_size(str, 0, save_svalue_depth++)) return -1; + } else { return -1; } + + if (*(cp = *str) != delim) { return -1;} + cp++; + size++; + break; + } + + case ']': + { + save_svalue_depth = 0; + if (*cp++ == ')' && is_mapping) { + *str = cp; + return size; + } + else { return -1;} + } + + case '/': + case '}': + { + save_svalue_depth = 0; + if (*cp++ == ')' && !is_mapping) { + *str = cp; + return size; + } + else { return -1;} + } + + case ':': + case ',': + { + if (c != delim) return -1; + size++; + break; + } + + default: + { + if (!(cp = strchr(cp, delim))) { return -1;} + cp++; + size++; + } + } + if (is_mapping) delim = (toggle ^= 1) ? ',' : ':'; + } + return -1; +} + +INLINE_STATIC int +restore_interior_string (char ** val, svalue_t * sv) +{ + register char *cp = *val; + char *start = cp, *newstr; + char c; + int len; + + while ((c = *cp++) != '"') { + switch (c) { + case '\r': + { + *(cp-1) = '\n'; + break; + } + + case '\\': + { + char *news = cp - 1; + + if ((*news++ = *cp++)) { + while ((c = *cp++) != '"') { + if (c == '\\') { + if (!(*news++ = *cp++)) return ROB_STRING_ERROR; + } + else { + if (c == '\r') + *news++ = '\n'; + else *news++ = c; + } + } + if (c == '\0') return ROB_STRING_ERROR; + *news = '\0'; + *val = cp; + newstr = new_string(len = (news - start), + "restore_string"); + strcpy(newstr, start); + sv->u.string = newstr; + sv->type = T_STRING; + sv->subtype = STRING_MALLOC; + return 0; + } + else return ROB_STRING_ERROR; + } + + case '\0': + { + return ROB_STRING_ERROR; + } + + } + } + + *val = cp; + *--cp = '\0'; + len = cp - start; + newstr = new_string(len, "restore_string"); + strcpy(newstr, start); + sv->u.string = newstr; + sv->type = T_STRING; + sv->subtype = STRING_MALLOC; + return 0; +} + +static int parse_numeric (char ** cpp, unsigned char c, svalue_t * dest) +{ + char *cp = *cpp; + long res, neg; + + if (c == '-') { + neg = 1; + res = 0; + c = *cp++; + if (!isdigit(c)) + return 0; + } else + neg = 0; + res = c - '0'; + + while ((c = *cp++) && isdigit(c)) { + res *= 10; + res += c - '0'; + } + if (c == '.') { + float f1 = 0.0, f2 = 10.0; + + c = *cp++; + if (!c) { + cp--; + c = '0'; + } + if (!isdigit(c)) return 0; + + do { + f1 += (c - '0')/f2; + f2 *= 10; + } while ((c = *cp++) && isdigit(c)); + + f1 += res; + if (c == 'e') { + int expo = 0; + + if ((c = *cp++) == '+') { + while ((c = *cp++) && isdigit(c)) { + expo *= 10; + expo += (c - '0'); + } + f1 *= pow(10.0, expo); + } else if (c == '-') { + while ((c = *cp++) && isdigit(c)) { + expo *= 10; + expo += (c - '0'); + } + f1 *= pow(10.0, -expo); + } else + return 0; + } + + dest->type = T_REAL; + dest->u.real = (neg ? -f1 : f1); + *cpp = cp; + return 1; + } else if (c == 'e') { + int expo = 0; + float f1; + + if ((c = *cp++) == '+') { + while ((c = *cp++) && isdigit(c)) { + expo *= 10; + expo += (c - '0'); + } + f1 = res * pow(10.0, expo); + } else if (c == '-') { + while ((c = *cp++) && isdigit(c)) { + expo *= 10; + expo += (c - '0'); + } + f1 = res * pow(10.0, -expo); + } else + return 0; + + dest->type = T_REAL; + dest->u.real = (neg ? -f1 : f1); + *cpp = cp; + return 1; + } else { + dest->type = T_NUMBER; + dest->u.number = (neg ? -res : res); + dest->subtype = 0; + *cpp = cp; + return 1; + } +} + +INLINE_STATIC void add_map_stats (mapping_t * m, int count) +{ + total_mapping_nodes += count; + total_mapping_size += count * sizeof(mapping_node_t); +#ifdef PACKAGE_MUDLIB_STATS + add_array_size(&m->stats, count << 1); +#endif + m->count = count; +} + +static int +restore_mapping (char **str, svalue_t * sv) +{ + int size, i, mask, count = 0; + unsigned long oi; + char c; + mapping_t *m; + svalue_t key, value; + mapping_node_t **a, *elt, *elt2; + char *cp = *str; + int err; + + if (save_svalue_depth) size = sizes[save_svalue_depth-1]; + else if ((size = restore_size((const char **)str, 1)) < 0) return 0; + + if (!size) { + *str += 2; + sv->u.map = allocate_mapping(0); + sv->type = T_MAPPING; + return 0; + } + m = allocate_mapping(size >> 1); /* have to clean up after this or */ + a = m->table; /* we'll leak */ + mask = m->table_size; + + while (1) { + switch (c = *cp++) { + case '"': + { + *str = cp; + if ((err = restore_hash_string(str, &key))) + goto key_error; + cp = *str; + cp++; + break; + } + + case '(': + { + save_svalue_depth++; + if (*cp == '[') { + *str = ++cp; + if ((err = restore_mapping(str, &key))) + goto key_error; + } + else if (*cp == '{') { + *str = ++cp; + if ((err = restore_array(str, &key))) + goto key_error; + } + else if (*cp == '/') { + *str = ++cp; + if ((err = restore_class(str, &key))) + goto key_error; + } + else goto generic_key_error; + cp = *str; + cp++; + break; + } + + case ':': + { + key.u.number = 0; + key.type = T_NUMBER; + key.subtype = 0; + break; + } + + case ']': + *str = ++cp; + add_map_stats(m, count); + sv->type = T_MAPPING; + sv->u.map = m; + return 0; + + case '-': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (!parse_numeric(&cp, c, &key)) + goto key_numeral_error; + break; + + default: + goto generic_key_error; + } + + /* At this point, key is a valid, referenced svalue and we're + responsible for it */ + + switch (c = *cp++) { + case '"': + { + *str = cp; + if ((err = restore_interior_string(str, &value))) + goto value_error; + cp = *str; + cp++; + break; + } + + case '(': + { + save_svalue_depth++; + if (*cp == '[') { + *str = ++cp; + if ((err = restore_mapping(str, &value))) + goto value_error; + } + else if (*cp == '{') { + *str = ++cp; + if ((err = restore_array(str, &value))) + goto value_error; + } else if (*cp == '/') { + *str = ++cp; + if ((err = restore_class(str, &value))) + goto value_error; + } + else goto generic_value_error; + cp = *str; + cp++; + break; + } + + case '-': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (!parse_numeric(&cp, c, &value)) + goto value_numeral_error; + break; + + case ',': + { + value.u.number = 0; + value.type = T_NUMBER; + value.subtype = 0; + break; + } + + default: + goto generic_value_error; + } + + /* both key and value are valid, referenced svalues */ + + oi = MAP_SVAL_HASH(key); + i = oi & mask; + if ((elt2 = elt = a[i])) { + do { + /* This should never happen, but don't bail on it */ + if (msameval(&key, elt->values)) { + free_svalue(&key, "restore_mapping: duplicate key"); + free_svalue(elt->values+1, "restore_mapping: replaced value"); + *(elt->values+1) = value; + break; + } + } while ((elt = elt->next)); + if (elt) + continue; + } else if (!(--m->unfilled)) { + if (growMap(m)) { + a = m->table; + if (oi & ++mask) elt2 = a[i |= mask]; + mask <<= 1; + mask--; + } else { + add_map_stats(m, count); + free_mapping(m); + free_svalue(&key, "restore_mapping: out of memory"); + free_svalue(&value, "restore_mapping: out of memory"); + error("Out of memory\n"); + } + } + + if (++count > MAX_MAPPING_SIZE) { + add_map_stats(m, count -1); + free_mapping(m); + free_svalue(&key, "restore_mapping: mapping too large"); + free_svalue(&value, "restore_mapping: mapping too large"); + mapping_too_large(); + } + + elt = new_map_node(); + *elt->values = key; + *(elt->values + 1) = value; + (a[i] = elt)->next = elt2; + } + + /* something went wrong */ + value_numeral_error: + free_svalue(&key, "restore_mapping: numeral value error"); + key_numeral_error: + add_map_stats(m, count); + free_mapping(m); + return ROB_NUMERAL_ERROR; + generic_value_error: + free_svalue(&key, "restore_mapping: generic value error"); + generic_key_error: + add_map_stats(m, count); + free_mapping(m); + return ROB_MAPPING_ERROR; + value_error: + free_svalue(&key, "restore_mapping: value error"); + key_error: + add_map_stats(m, count); + free_mapping(m); + return err; +} + + +INLINE_STATIC int +restore_class (char ** str, svalue_t * ret) +{ + int size; + char c; + array_t *v; + svalue_t *sv; + char *cp = *str; + int err; + + if (save_svalue_depth) size = sizes[save_svalue_depth-1]; + else if ((size = restore_size((const char **)str,0)) < 0) return ROB_CLASS_ERROR; + + v = allocate_class_by_size(size); /* after this point we have to clean up + or we'll leak */ + sv = v->item; + + while (size--) { + switch (c = *cp++) { + case '"': + *str = cp; + if ((err = restore_interior_string(str, sv))) + goto generic_error; + cp = *str; + cp++; + sv++; + break; + + case ',': + sv++; + break; + + case '(': + { + save_svalue_depth++; + if (*cp == '[') { + *str = ++cp; + if ((err = restore_mapping(str, sv))) + goto error; + } + else if (*cp == '{') { + *str = ++cp; + if ((err = restore_array(str, sv))) + goto error; + } + else if (*cp == '/') { + *str = ++cp; + if ((err = restore_class(str, sv))) + goto error; + } + else goto generic_error; + sv++; + cp = *str; + cp++; + break; + } + + case '-': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (parse_numeric(&cp, c, sv)) + sv++; + else + goto numeral_error; + break; + + default: + goto generic_error; + } + } + + cp += 2; + *str = cp; + ret->u.arr = v; + ret->type = T_CLASS; + return 0; + /* something went wrong */ + numeral_error: + err = ROB_NUMERAL_ERROR; + goto error; + generic_error: + err = ROB_CLASS_ERROR; + error: + free_class(v); + return err; +} + +INLINE_STATIC int +restore_array (char ** str, svalue_t * ret) +{ + int size; + char c; + array_t *v; + svalue_t *sv; + char *cp = *str; + int err; + + if (save_svalue_depth) size = sizes[save_svalue_depth-1]; + else if ((size = restore_size((const char **)str,0)) < 0) return ROB_ARRAY_ERROR; + + v = allocate_array(size); /* after this point we have to clean up + or we'll leak */ + sv = v->item; + + while (size--) { + switch (c = *cp++) { + case '"': + *str = cp; + if ((err = restore_interior_string(str, sv))) + goto generic_error; + cp = *str; + cp++; + sv++; + break; + + case ',': + sv++; + break; + + case '(': + { + save_svalue_depth++; + if (*cp == '[') { + *str = ++cp; + if ((err = restore_mapping(str, sv))) + goto error; + } + else if (*cp == '{') { + *str = ++cp; + if ((err = restore_array(str, sv))) + goto error; + } + else if (*cp == '/') { + *str = ++cp; + if ((err = restore_class(str, sv))) + goto error; + } + else goto generic_error; + sv++; + cp = *str; + cp++; + break; + } + + case '-': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (parse_numeric(&cp, c, sv)) + sv++; + else + goto numeral_error; + break; + + default: + goto generic_error; + } + } + + cp += 2; + *str = cp; + ret->u.arr = v; + ret->type = T_ARRAY; + return 0; + /* something went wrong */ + numeral_error: + err = ROB_NUMERAL_ERROR; + goto error; + generic_error: + err = ROB_ARRAY_ERROR; + error: + free_array(v); + return err; +} + +INLINE_STATIC int +restore_string (char * val, svalue_t * sv) +{ + register char *cp = val; + char *start = cp, *newstr; + char c; + int len; + + while ((c = *cp++) != '"') { + switch (c) { + case '\r': + { + *(cp-1) = '\n'; + break; + } + + case '\\': + { + char *news = cp - 1; + if ((*news++ = *cp++)) { + while ((c = *cp++) != '"' && c) { + if (c == '\\') { + if (!(*news++ = *cp++)) + return ROB_STRING_ERROR; + } else { + if (c == '\r') + *news++ = '\n'; + else + *news++ = c; + } + } + if ((c == '\0') || (*cp != '\0')) + return ROB_STRING_ERROR; + *news = '\0'; + newstr = new_string(news - start, "restore_string"); + strcpy(newstr, start); + sv->u.string = newstr; + sv->type = T_STRING; + sv->subtype = STRING_MALLOC; + return 0; + } + } + + case '\0': + { + return ROB_STRING_ERROR; + } + + } + } + + if (*cp--) return ROB_STRING_ERROR; + *cp = '\0'; + len = cp - start; + newstr = new_string(len, "restore_string"); + strcpy(newstr, start); + sv->u.string = newstr; + sv->type = T_STRING; + sv->subtype = STRING_MALLOC; + return 0; +} + +/* for this case, the variable in question has been set to zero already, + and we don't have to worry about preserving it */ +INLINE int +restore_svalue (char * cp, svalue_t * v) +{ + int ret; + char c; + + switch (c = *cp++) { + case '"': + return restore_string(cp, v); + case '(': + if (*cp == '{') { + cp++; + ret = restore_array(&cp, v); + } else if (*cp == '[') { + cp++; + ret = restore_mapping(&cp, v); + } else if (*cp++ == '/') { + ret = restore_class(&cp, v); + } + else ret = ROB_GENERAL_ERROR; + + if (save_svalue_depth) { + save_svalue_depth = max_depth = 0; + if (sizes) + FREE((char *) sizes); + sizes = (int *) 0; + } + return ret; + + case '-': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (!parse_numeric(&cp, c, v)) + return ROB_NUMERAL_ERROR; + break; + + default: + v->type = T_NUMBER; + v->u.number = 0; + } + + return 0; +} + +/* for this case, we're being careful and want to leave the value alone on + an error */ +INLINE_STATIC int +safe_restore_svalue (char * cp, svalue_t * v) +{ + int ret; + svalue_t val; + char c; + + val.type = T_NUMBER; + switch (c = *cp++) { + case '"': + if ((ret = restore_string(cp, &val))) return ret; + break; + case '(': + { + if (*cp == '{') { + cp++; + ret = restore_array(&cp, &val); + } else if (*cp == '[') { + cp++; + ret = restore_mapping(&cp, &val); + } else if (*cp++ == '/') { + ret = restore_class(&cp, &val); + } + else return ROB_GENERAL_ERROR; + + if (save_svalue_depth) { + save_svalue_depth = max_depth = 0; + if (sizes) + FREE((char *) sizes); + sizes = (int *) 0; + } + if (ret) + return ret; + break; + } + + case '-': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (!parse_numeric(&cp, c, &val)) + return ROB_NUMERAL_ERROR; + break; + + default: + val.type = T_NUMBER; + val.u.number = 0; + } + free_svalue(v, "safe_restore_svalue"); + *v = val; + return 0; +} + +static int fgv_recurse (program_t * prog, int * idx, + char * name, unsigned short * type, + int check_nosave) { + int i; + for (i = 0; i < prog->num_inherited; i++) { + if (fgv_recurse(prog->inherit[i].prog, idx, name, type, check_nosave)) { + *type = DECL_MODIFY(prog->inherit[i].type_mod, *type); + + return 1; + } + } + for (i = 0; i < prog->num_variables_defined; i++) { + if (prog->variable_table[i] == name && + (!check_nosave || !(prog->variable_types[i] & DECL_NOSAVE))) { + *idx += i; + *type = prog->variable_types[i]; + return 1; + } + } + *idx += prog->num_variables_defined; + return 0; +} + +int find_global_variable (program_t * prog, const char * const name, + unsigned short * type, int check_nosave) { + int idx = 0; + char *str = findstring(name); + + if (str && fgv_recurse(prog, &idx, str, type, check_nosave)) + return idx; + + return -1; +} + +void +restore_object_from_line (object_t * ob, char * line, int noclear) +{ + char *space; + svalue_t *v; + char var[100]; + int idx; + svalue_t *sv = ob->variables; + int rc; + unsigned short t; + + + if (line[0] == '#') { /* ignore 'comments' in savefiles */ + return ; + } + space = strchr(line, ' '); + if (!space || ((space - line) >= sizeof(var))) { + error("restore_object(): Illegal file format - 1 (%s).\n", line); + } + (void)strncpy(var, line, space - line); + var[space - line] = '\0'; + idx = find_global_variable(current_object->prog, var, &t, 1); + if (idx == -1) { + push_number(0); + rc = restore_svalue(space+1, sp); + } else { + + v = &sv[idx]; + if (noclear) { + rc = safe_restore_svalue(space+1, v); + } else { + rc = restore_svalue(space+1, v); + } + } + if (rc & ROB_ERROR) { + if (rc & ROB_GENERAL_ERROR) { + error("restore_object(): Illegal general format while restoring %s.\n", var); + } else if (rc & ROB_NUMERAL_ERROR) { + error("restore_object(): Illegal numeric format while restoring %s.\n", var); + } else if (rc & ROB_ARRAY_ERROR) { + error("restore_object(): Illegal array format while restoring %s.\n", var); + } else if (rc & ROB_MAPPING_ERROR) { + error("restore_object(): Illegal mapping format while restoring %s.\n", var); + } else if (rc & ROB_STRING_ERROR) { + error("restore_object(): Illegal string format while restoring %s.\n", var); + } else if (rc & ROB_CLASS_ERROR) { + error("restore_object(): Illegal class format while restoring %s.\n", var); + } + } + if(idx == -1){ + copy_and_push_string(var); + apply("restore_lost_variable", ob, 2, ORIGIN_DRIVER); + } +} + +#ifdef HAVE_ZLIB +int +restore_object_from_gzip (object_t * ob, + gzFile gzf, + int noclear, int *count) +{ + static char *buff = NULL; + static long buffsize = 0; + const char* tmp = ""; + int idx; + int t; + + t = 65536 << *count; //should be big enough most of the time + if (buff && buffsize < t) { + FREE(buff); + buff = NULL; + } + + if(!buff){ + buff = (char *)DXALLOC(t, TAG_TEMPORARY, "restore_object: 6"); + buffsize = t; + } + + t = buffsize; + + while (!gzeof(gzf) && tmp != Z_NULL) { + idx = 0; + buff[t - 2] = 0; + // gzgets appaears to pay attension to zero termination even on short + // strings + buff[0] = 0; + tmp = gzgets(gzf, buff, t); + + if (buff[t - 2] != 0 && buff[t - 2] != '\n' && !gzeof(gzf)) { + return -1; //retry with bigger buffer + } + + if (buff[0]) { + char *tmp2 = strchr(buff, '\n'); + if (tmp2) { + *tmp2 = '\0'; + if (tmp2 > buff && tmp2[-1] == '\r') { + *(--tmp2) = '\0'; + } + } + restore_object_from_line(ob, buff, noclear); + } + } + return 0; +} +#endif + +void +restore_object_from_buff (object_t * ob, char * theBuff, + int noclear) +{ + char *buff, *nextBuff, *tmp; + + nextBuff = theBuff; + while ((buff = nextBuff) && *buff) { + + if ((tmp = strchr(buff, '\n'))) { + *tmp = '\0'; + if (tmp > buff && tmp[-1] == '\r') + *(--tmp) = '\0'; + nextBuff = tmp + 1; + } else { + nextBuff = 0; + } + restore_object_from_line(ob, buff, noclear); + } +} + + +/* + * Save an object to a file. + * The routine checks with the function "valid_write()" in /obj/master.c + * to assertain that the write is legal. + * If 'save_zeros' is set, 0 valued variables will be saved + */ +#ifdef HAVE_ZLIB +static int save_object_recurse (program_t * prog, svalue_t ** + svp, int type, int save_zeros, + FILE * f, gzFile gzf) +#else +static int save_object_recurse (program_t * prog, svalue_t ** + svp, int type, int save_zeros, + FILE * f) +#endif +{ + int i; + int textsize = 1; + int tmp; + int theSize; + int oldSize; + char *new_str, *p; + + for (i = 0; i < prog->num_inherited; i++) { +#ifdef HAVE_ZLIB + if (!(tmp = save_object_recurse(prog->inherit[i].prog, svp, + prog->inherit[i].type_mod | type, + save_zeros, f, gzf))) +#else + + if (!(tmp = save_object_recurse(prog->inherit[i].prog, svp, + prog->inherit[i].type_mod | type, + save_zeros, f))) +#endif + return 0; + textsize += tmp; + } + if (type & DECL_NOSAVE) { + (*svp) += prog->num_variables_defined; + return 1; + } + oldSize = -1; + new_str = NULL; + for (i = 0; i < prog->num_variables_defined; i++) { + if (prog->variable_types[i] & DECL_NOSAVE) { + (*svp)++; + continue; + } + save_svalue_depth = 0; + theSize = svalue_save_size(*svp); + + // Try not to malloc/free too much. + if (theSize > oldSize) { + if (new_str) { + FREE(new_str); + } + new_str = (char *)DXALLOC(theSize, TAG_TEMPORARY, "save_object: 2"); + oldSize = theSize; + } + + *new_str = '\0'; + p = new_str; + save_svalue((*svp)++, &p); + DEBUG_CHECK(p - new_str != theSize - 1, "Length miscalculated in save_object!"); + /* FIXME: shouldn't use fprintf() */ + if (save_zeros || new_str[0] != '0' || new_str[1] != 0) { /* Armidale */ + textsize += theSize; + textsize += strlen(prog->variable_table[i]); + textsize += 2; +#ifdef HAVE_ZLIB + if (gzf) { + gzputs(gzf, prog->variable_table[i]); + gzputs(gzf, " "); + gzputs(gzf, new_str); + gzputs(gzf, "\n"); + } else +#endif + { + if (fprintf(f, "%s %s\n", prog->variable_table[i], new_str) < 0) { + debug_perror("save_object: fprintf", 0); + FREE(new_str); + return 0; + } + } + } + } + if (new_str) { + FREE(new_str); + } + return textsize; +} + +/* + * Save an object to a file. + * The routine checks with the function "valid_write()" in /obj/master.c + * to assertain that the write is legal. + * If 'save_zeros' is set, 0 valued variables will be saved + */ + +static int save_object_recurse_str (program_t * prog, svalue_t **svp, int type, int save_zeros, char *buf, int bufsize){ + int i; + int textsize = 1; + int tmp; + int theSize; + int oldSize; + char *new_str, *p; + + for (i = 0; i < prog->num_inherited; i++) { + if (!(tmp = save_object_recurse_str(prog->inherit[i].prog, svp, + prog->inherit[i].type_mod | type, + save_zeros, buf+textsize-1, bufsize))) + return 0; + textsize += tmp - 1; + } + if (type & DECL_NOSAVE) { + (*svp) += prog->num_variables_defined; + return 1; + } + oldSize = -1; + new_str = NULL; + for (i = 0; i < prog->num_variables_defined; i++) { + if (prog->variable_types[i] & DECL_NOSAVE) { + (*svp)++; + continue; + } + save_svalue_depth = 0; + theSize = svalue_save_size(*svp); + if(textsize+theSize + 2 + strlen(prog->variable_table[i])> bufsize) + return 0; + // Try not to malloc/free too much. + + if (theSize > oldSize) { + if (new_str) { + FREE(new_str); + } + new_str = (char *)DXALLOC(theSize, TAG_TEMPORARY, "save_object: 2"); + oldSize = theSize; + } + + *new_str = '\0'; + p = new_str; + save_svalue((*svp)++, &p); + DEBUG_CHECK(p - new_str != theSize - 1, "Length miscalculated in save_object!"); + if (save_zeros || new_str[0] != '0' || new_str[1] != 0) { /* Armidale */ + if (sprintf(buf+textsize-1, "%s %s\n", prog->variable_table[i], new_str) < 0) { + debug_perror("save_object: fprintf", 0); + FREE(new_str); + return 0; + } + textsize += theSize; + textsize += strlen(prog->variable_table[i]); + textsize ++; + + } + } + if (new_str) { + FREE(new_str); + } + return textsize; +} + +int sel = -1; + +#ifdef HAVE_ZLIB +int gz_sel = -1; +#endif + +int +save_object (object_t * ob, const char * file, int save_zeros) +{ + char *name, *p; + static char save_name[256], tmp_name[256]; + int len; + FILE *f; + int success; + svalue_t *v; +#ifdef HAVE_ZLIB + gzFile gzf; + int save_compressed; + + if (save_zeros & 2) { + save_compressed = 1; + save_zeros &= ~2; + } else { + save_compressed = 0; + } +#endif + + if (ob->flags & O_DESTRUCTED) + return 0; + + len = strlen(file); + if (file[len-2] == '.' && file[len - 1] == 'c') + len -= 2; + + if (sel == -1) sel = strlen(SAVE_EXTENSION); + if (strcmp(file + len - sel, SAVE_EXTENSION) == 0) + len -= sel; +#ifdef HAVE_ZLIB + if (gz_sel == -1) { + gz_sel = strlen(SAVE_GZ_EXTENSION); + } + if (save_compressed) { + name = new_string(len + gz_sel, "save_object"); + strcpy(name, file); + strcpy(name + len, SAVE_GZ_EXTENSION); + } else +#endif + { + name = new_string(len + sel, "save_object"); + strcpy(name, file); + strcpy(name + len, SAVE_EXTENSION); + } + + push_malloced_string(name); /* errors */ + + file = check_valid_path(name, ob, "save_object", 1); + free_string_svalue(sp--); + if (!file) + error("Denied write permission in save_object().\n"); + + strcpy(save_name, ob->obname); + if ((p = strrchr(save_name, '#')) != 0) + *p = '\0'; + p = save_name + strlen(save_name) - 1; + if (*p != 'c' && *(p - 1) != '.') + strcat(p, ".c"); + + /* + * Write the save-files to different directories, just in case + * they are on different file systems. + */ + sprintf(tmp_name, "%.250s.tmp", file); + +#ifdef HAVE_ZLIB + gzf = NULL; + f = NULL; + if (save_compressed) { + gzf = gzopen(tmp_name, "w"); + if (!gzf) { + error("Could not open /%s for a save.\n", tmp_name); + } + if (!gzprintf(gzf, "#/%s\n", ob->prog->filename)) { + error("Could not open /%s for a save.\n", tmp_name); + } + } else +#endif + { + if (!(f = fopen(tmp_name, "w")) || fprintf(f, "#/%s\n", save_name) < 0) { + error("Could not open /%s for a save.\n", tmp_name); + } + } + v = ob->variables; +#ifdef HAVE_ZLIB + success = save_object_recurse(ob->prog, &v, 0, save_zeros, f, gzf); + + if (gzf && gzclose(gzf)) { + debug_perror("save_object", file); + success = 0; + } +#else + success = save_object_recurse(ob->prog, &v, 0, save_zeros, f); +#endif + + if (f && fclose(f) < 0) { + debug_perror("save_object", file); + success = 0; + } + + if (!success) { + debug_message("Failed to completely save file. Disk could be full.\n"); + unlink(tmp_name); + } else { +#ifdef WIN32 + /* Need to erase it to write over it. */ + unlink(file); +#endif + if (rename(tmp_name, file) < 0) { + debug_perror("save_object", file); + debug_message("Failed to rename /%s to /%s\n", tmp_name, file); + debug_message("Failed to save object!\n"); + unlink(tmp_name); + } +#ifdef HAVE_ZLIB + else if (save_compressed) { + char buf[1024]; + // When compressed, unlink the uncompressed name too. + strcpy(buf, file); + len = strlen(buf) - gz_sel; + strcpy(buf + len, SAVE_EXTENSION); + unlink(buf); + } +#endif + + } + + return success; +} + +int +save_object_str (object_t *ob, int save_zeros, char *saved, int size) +{ + char *p; + int success; + svalue_t *v; + char *now = saved; + int left; + if (ob->flags & O_DESTRUCTED) + return 0; + strcpy(now, "#/"); + now+=2; + strcpy(now, ob->obname); + if ((p = strrchr(now, '#')) != 0) + *p = '\0'; + p = now + strlen(now) - 1; + if (*p != 'c' && *(p - 1) != '.') + strcat(p, ".c"); + now = now + strlen(now); + *now++ = '\n'; + left = size - (now - saved); + *now = 0; + /* + * Write the save-files to different directories, just in case + * they are on different file systems. + */ + v = ob->variables; + success = save_object_recurse_str(ob->prog, &v, 0, save_zeros, now, left); + + if (!success) { + debug_message("Failed to completely save file. string size too small?.\n"); + } + return success; +} + +/* + * return a string representing an svalue in the form that save_object() + * would write it. + */ +char * +save_variable (svalue_t * var) +{ + int theSize; + char *new_str, *p; + + save_svalue_depth = 0; + theSize = svalue_save_size(var); + new_str = new_string(theSize - 1, "save_variable"); + *new_str = '\0'; + p = new_str; + save_svalue(var, &p); + DEBUG_CHECK(p - new_str != theSize - 1, "Length miscalculated in save_variable"); + return new_str; +} + +static void cns_just_count (int * idx, program_t * prog) { + int i; + + for (i = 0; i < prog->num_inherited; i++) + cns_just_count(idx, prog->inherit[i].prog); + *idx += prog->num_variables_defined; +} + +static void cns_recurse (object_t * ob, int * idx, program_t * prog) { + int i; + + for (i = 0; i < prog->num_inherited; i++) { + if (prog->inherit[i].type_mod & DECL_NOSAVE) + cns_just_count(idx, prog->inherit[i].prog); + else + cns_recurse(ob, idx, prog->inherit[i].prog); + } + for (i = 0; i < prog->num_variables_defined; i++) { + if (!(prog->variable_types[i] & DECL_NOSAVE)) { + free_svalue(&ob->variables[*idx + i], "cns_recurse"); + ob->variables[*idx + i] = const0u; + } + } + *idx += prog->num_variables_defined; +} + +void clear_non_statics (object_t * ob) { + int idx = 0; + cns_recurse(ob, &idx, ob->prog); +} + +int restore_object (object_t * ob, const char * file, int noclear) +{ + char *name; + int len; + object_t *save = current_object; + struct stat st; +#ifdef HAVE_ZLIB + int pos; + gzFile gzf; + static int count = 0; +#else + FILE *f; + // Try and keep one buffer for droping all the restores into + static char *theBuff = NULL; + static int buff_len = 0; + int tmp_len; +#endif + + if (ob->flags & O_DESTRUCTED) + return 0; + + len = strlen(file); + if (file[len-2] == '.' && file[len - 1] == 'c') + len -= 2; + + if (sel == -1) sel = strlen(SAVE_EXTENSION); + if (strcmp(file + len - sel, SAVE_EXTENSION) == 0) + len -= sel; + +#ifdef HAVE_ZLIB + else { + if (gz_sel == -1) gz_sel = strlen(SAVE_GZ_EXTENSION); + if (strcmp(file + len - gz_sel, SAVE_GZ_EXTENSION) == 0) + len -= gz_sel; + } + name = new_string(len + gz_sel, "restore_object"); + strncpy(name, file, len); + strcpy(name + len, SAVE_GZ_EXTENSION); + pos = 0; + while (name[pos] == '/') { + pos++; + } + // See if the gz file exists. + if (stat(name + pos, &st) == -1) + { + FREE_MSTR(name); +#else + { +#endif + name = new_string(len + sel, "restore_object"); + strncpy(name, file, len); + strcpy(name + len, SAVE_EXTENSION); + } + + push_malloced_string(name); /* errors */ + + file = check_valid_path(name, ob, "restore_object", 0); + free_string_svalue(sp--); + if (!file) error("Denied read permission in restore_object().\n"); + + +#ifdef HAVE_ZLIB + gzf = gzopen(file, "r"); + if (!gzf) { + if (gzf) { + (void)gzclose(gzf); + } + return 0; + } + + /* This next bit added by Armidale@Cyberworld 1/1/93 + * If 'noclear' flag is not set, all non-static variables will be + * initialized to 0 when restored. + */ + if (!noclear) { + clear_non_statics(ob); + } + error_context_t econ; + save_context(&econ); + if (SETJMP(econ.context)){ + restore_context(&econ); + pop_context(&econ); + gzclose(gzf); + return 0; + } + while((restore_object_from_gzip(ob, gzf, noclear, &count))){ + count++; + gzseek(gzf, 0, SEEK_SET); + if (!noclear) { + clear_non_statics(ob); + } + } + gzclose(gzf); + pop_context(&econ); +#else + f = fopen(file, "r"); + if (!f || fstat(fileno(f), &st) == -1) { + if (f) + (void)fclose(f); + return 0; + } + + if (!(tmp_len = st.st_size)) { + (void)fclose(f); + return 0; + } + + if (tmp_len > buff_len) { + if (theBuff) { + FREE(theBuff); + } + theBuff = DXALLOC(tmp_len + 1, TAG_TEMPORARY, "restore_object: 4"); + buff_len = tmp_len; + } +#ifdef WIN32 + tmp_len = read(_fileno(f), theBuff, tmp_len); +#else + fread(theBuff, 1, tmp_len, f); +#endif + + fclose(f); + theBuff[tmp_len] = '\0'; + current_object = ob; + + /* This next bit added by Armidale@Cyberworld 1/1/93 + * If 'noclear' flag is not set, all non-static variables will be + * initialized to 0 when restored. + */ + if (!noclear) + clear_non_statics(ob); + + restore_object_from_buff(ob, theBuff, noclear); +#endif + current_object = save; + debug(d_flag, ("Object /%s restored from /%s.\n", ob->obname, file)); + + return 1; +} + +void restore_variable (svalue_t * var, char * str) +{ + int rc; + rc = restore_svalue(str, var); + + if (rc & ROB_ERROR) { + *var = const0; /* clean up */ + if (rc & ROB_GENERAL_ERROR) + error("restore_object(): Illegal general format.\n"); + else if (rc & ROB_NUMERAL_ERROR) + error("restore_object(): Illegal numeric format.\n"); + else if (rc & ROB_ARRAY_ERROR) + error("restore_object(): Illegal array format.\n"); + else if (rc & ROB_MAPPING_ERROR) + error("restore_object(): Illegal mapping format.\n"); + else if (rc & ROB_STRING_ERROR) + error("restore_object(): Illegal string format.\n"); + } +} + +void tell_npc (object_t * ob, const char * str) +{ + copy_and_push_string(str); + apply(APPLY_CATCH_TELL, ob, 1, ORIGIN_DRIVER); +} + +/* + * tell_object: send a message to an object. + * If it is an interactive object, it will go to his + * screen. Otherwise, it will go to a local function + * catch_tell() in that object. This enables communications + * between users and NPC's, and between other NPC's. + * If INTERACTIVE_CATCH_TELL is defined then the message always + * goes to catch_tell unless the target of tell_object is interactive + * and is the current_object in which case it is written via add_message(). + */ +void tell_object (object_t * ob, const char * str, int len) +{ + if (!ob || (ob->flags & O_DESTRUCTED)) { + add_message(0, str, len); + return; + } + /* if this is on, EVERYTHING goes through catch_tell() */ +#ifndef INTERACTIVE_CATCH_TELL + if (ob->interactive) + add_message(ob, str, len); + else +#endif + tell_npc(ob, str); +} + +void dealloc_object (object_t * ob, const char * from) +{ +#ifdef DEBUG + object_t *tmp, *prev_all = 0; +#endif + + debug(d_flag, ("free_object: /%s.\n", ob->obname)); + + if (!(ob->flags & O_DESTRUCTED)) { + if(ob->next_all != ob) + /* This is fatal, and should never happen. */ + fatal("FATAL: Object 0x%x /%s ref count 0, but not destructed (from %s).\n", + ob, ob->obname, from); + else { + destruct_object(ob); + return; + } + } + DEBUG_CHECK(ob->interactive, "Tried to free an interactive object.\n"); + /* + * If the program is freed, then we can also free the variable + * declarations. + */ + if (ob->prog) { + tot_alloc_object_size -= + (ob->prog->num_variables_total - 1) * sizeof(svalue_t) + + sizeof(object_t); + free_prog(&ob->prog); + ob->prog = 0; + } + if (ob->replaced_program) { + FREE_MSTR(ob->replaced_program); + ob->replaced_program = 0; + } +#ifdef PRIVS + if (ob->privs) + free_string(ob->privs); +#endif + if (ob->obname) { + debug(d_flag, ("Free object /%s\n", ob->obname)); + + DEBUG_CHECK1(lookup_object_hash(ob->obname) == ob, + "Freeing object /%s but name still in name table", ob->obname); + FREE((char *)ob->obname); + SETOBNAME(ob, 0); + } +#ifdef DEBUG + prev_all = ob->prev_all; + if (prev_all){ + prev_all->next_all = ob->next_all; + if(ob->next_all) + ob->next_all->prev_all = prev_all; + } else { + obj_list_dangling = ob->next_all; + if(obj_list_dangling) + obj_list_dangling->prev_all = 0; + } + ob->next_all = 0; + ob->prev_all = 0; + tot_dangling_object--; +#endif + tot_alloc_object--; + FREE((char *) ob); +} + +void free_object (object_t ** ob, const char * const from) +{ + //note that we get a pointer to a pointer unlike MudOS where it's a pointer to the object + //this is so we can clear the variable holding the reference as that shouldn't be used anymore + //after freeing it! don't set to NULL as that might still hide such bugs, and I suspect it may + //be related to some of the corrupted memory crashes (which dw stopped doing, oh well, I'm sure it + //will be back.) Better to find and fix than to hide! + if(*ob) + (*ob)->ref--; + + if ((*ob)->ref > 0) { + *ob = (object_t *)9; + return; + } + dealloc_object(*ob, from); + *ob = (object_t *)1; +} + +/* + * Allocate an empty object, and set all variables to 0. Note that a + * 'object_t' already has space for one variable. So, if no variables + * are needed, we waste one svalue worth of memory (or we'd write too + * much memory in copying the NULL_object over. + */ +object_t *get_empty_object (int num_var) +{ + //static object_t NULL_object; + object_t *ob; + int size = sizeof(object_t) + + (num_var - !!num_var) * sizeof(svalue_t); + int i; + + tot_alloc_object++; + tot_alloc_object_size += size; + ob = (object_t *) DXALLOC(size, TAG_OBJECT, "get_empty_object"); + /* + * marion Don't initialize via memset, this is incorrect. E.g. the bull + * machines have a (char *)0 which is not zero. We have structure + * assignment, so use it. + */ + //*ob = NULL_object; gives a warning on const pointers + //memcpy(ob, &NULL_object, sizeof NULL_object); + //screw the "bull machines" we're in the 21st century now + memset(ob, 0, sizeof(object_t)); + ob->ref = 1; + for (i = 0; i < num_var; i++) + ob->variables[i] = const0u; + return ob; +} + +void reset_object (object_t * ob) +{ + /* Be sure to update time first ! */ + ob->next_reset = current_time + TIME_TO_RESET / 2 + + random_number(TIME_TO_RESET / 2); + + save_command_giver(0); + if (!apply(APPLY_RESET, ob, 0, ORIGIN_DRIVER)) { + /* no reset() in the object */ + ob->flags &= ~O_WILL_RESET; /* don't call it next time */ + } + restore_command_giver(); + ob->flags |= O_RESET_STATE; +} + +void call_create (object_t * ob, int num_arg) +{ + /* Be sure to update time first ! */ + ob->next_reset = current_time + TIME_TO_RESET / 2 + + random_number(TIME_TO_RESET / 2); + + call___INIT(ob); + + if (ob->flags & O_DESTRUCTED) { + pop_n_elems(num_arg); + return; /* sigh */ + } + + apply(APPLY_CREATE, ob, num_arg, ORIGIN_DRIVER); + + ob->flags |= O_RESET_STATE; +} + +#ifdef F_SET_HIDE +INLINE int object_visible (object_t * ob) +{ + if (ob->flags & O_HIDDEN) { + if (current_object->flags & O_HIDDEN) + return 1; + + return valid_hide(current_object); + } else + return 1; +} +#endif + +void reload_object (object_t * obj) +{ + int i; + + if (!obj->prog) + return; + for (i = 0; i < obj->prog->num_variables_total; i++) { + free_svalue(&obj->variables[i], "reload_object"); + obj->variables[i] = const0u; + } +#if defined(PACKAGE_SOCKETS) || defined(PACKAGE_EXTERNAL) + if (obj->flags & O_EFUN_SOCKET) { + close_referencing_sockets(obj); + } +#endif + + /* + * If this is the first object being shadowed by another object, then + * destruct the whole list of shadows. + */ +#ifndef NO_SHADOWS + if (obj->shadowed && !obj->shadowing) { + object_t *ob2; + object_t *otmp; + + for (ob2 = obj->shadowed; ob2;) { + otmp = ob2; + ob2 = ob2->shadowed; + otmp->shadowed = 0; + otmp->shadowing = 0; + destruct_object(otmp); + } + } + /* + * The chain of shadows is a double linked list. Take care to update it + * correctly. + */ + if (obj->shadowing) + obj->shadowing->shadowed = obj->shadowed; + if (obj->shadowed) + obj->shadowed->shadowing = obj->shadowing; + obj->shadowing = 0; + obj->shadowed = 0; +#endif + remove_living_name(obj); + set_heart_beat(obj, 0); + remove_all_call_out(obj); +#ifndef NO_LIGHT + add_light(obj, -(obj->total_light)); +#endif +#ifdef PACKAGE_UIDS +#ifdef AUTO_SETEUID + obj->euid = obj->uid; +#else + obj->euid = NULL; +#endif +#endif + call_create(obj, 0); +} + +void get_objects (object_t *** list, int * size, get_objectsfn_t callback, void * data) +{ + object_t *ob; +#ifdef F_SET_HIDE + int display_hidden = 0; + + if (num_hidden > 0) { + if (current_object->flags & O_HIDDEN) { + display_hidden = 1; + } else { + display_hidden = valid_hide(current_object); + } + } + *list = (object_t **)new_string(((tot_alloc_object - (display_hidden ? 0 : num_hidden)) * sizeof(object_t *)) - 1, "get_objects"); +#else + *list = (object_t **)new_string((tot_alloc_object * sizeof(object_t *)) - 1, "get_objects"); +#endif + + if (!*list) + fatal("Out of memory!\n"); + push_malloced_string((char *)*list); + + for (*size = 0, ob = obj_list; ob; ob = ob->next_all) { +#ifdef F_SET_HIDE + if (!display_hidden && (ob->flags & O_HIDDEN)) + continue; +#endif + if (!callback || callback(ob, data)) + (*list)[(*size)++] = ob; + } +} + +static object_t *command_giver_stack[CFG_MAX_CALL_DEPTH]; +object_t **cgsp = command_giver_stack; + +#ifdef DEBUGMALLOC_EXTENSIONS +void mark_command_giver_stack (void) +{ + object_t **ob; + + for (ob = &command_giver_stack[0]; ob < cgsp; ob++) { + if (*ob) + (*ob)->extra_ref++; + } + if (command_giver) + command_giver->extra_ref++; +} +#endif + +/* set a new command giver, saving the old one */ +void save_command_giver (object_t * ob) +{ + DEBUG_CHECK(cgsp == &command_giver_stack[CFG_MAX_CALL_DEPTH], "command_giver stack overflow"); + *(++cgsp) = command_giver; + + command_giver = ob; + if (command_giver) + add_ref(command_giver, "save_command_giver"); +} + +/* restore the saved command giver */ +void restore_command_giver (void) +{ + if (command_giver) + free_object(&command_giver, "command_giver_error_handler"); + DEBUG_CHECK(cgsp == command_giver_stack, "command_giver stack underflow"); + command_giver = *(cgsp--); +} + +/* set a new command giver */ +void set_command_giver (object_t * ob) +{ + if (command_giver) + free_object(&command_giver, "set_command_giver"); + + command_giver = ob; + if (command_giver != 0) + add_ref(command_giver, "set_command_giver"); +} diff --git a/fluffos-2.23-ds03/object.h b/fluffos-2.23-ds03/object.h new file mode 100644 index 0000000..33e24b3 --- /dev/null +++ b/fluffos-2.23-ds03/object.h @@ -0,0 +1,193 @@ +#ifndef OBJECT_H +#define OBJECT_H + +/* It is usually better to include "lpc_incl.h" instead of including this + file directly */ + +/* + * Definition of an object. + * If the object is inherited, then it must not be destructed ! + * + * The reset is used as follows: + * 0: There is an error in the reset() in this object. Never call it again. + * 1: Normal state. + * 2 or higher: This is an interactive user, that has not given any commands + * for a number of reset periods. + */ + +#include "packages/uids.h" +#include "packages/mudlib_stats.h" + +#define MAX_OBJECT_NAME_SIZE 2048 + +#define O_HEART_BEAT 0x01 /* Does it have an heart beat ? */ +#ifndef NO_WIZARDS +#define O_IS_WIZARD 0x02 /* used to be O_IS_WIZARD */ +#endif + +#define O_LISTENER 0x04 /* can hear say(), etc */ +#ifndef NO_ADD_ACTION +#define O_ENABLE_COMMANDS 0x04 /* Can it execute commands ? */ +#else +#define O_CATCH_TELL 0x04 +#endif + +#define O_CLONE 0x08 /* Is it cloned from a master copy ? */ +#define O_DESTRUCTED 0x10 /* Is it destructed ? */ +#define O_ONCE_INTERACTIVE 0x40 /* Has it ever been interactive ? */ +#define O_RESET_STATE 0x80 /* Object in a 'reset':ed state ? */ +#define O_WILL_CLEAN_UP 0x100 /* clean_up will be called next time */ +#define O_VIRTUAL 0x200 /* We're a virtual object */ +#ifdef F_SET_HIDE +#define O_HIDDEN 0x400 /* We're hidden from nonprived objs */ +#endif +#if defined(PACKAGE_SOCKETS) || defined(PACKAGE_EXTERNAL) +#define O_EFUN_SOCKET 0x800 /* efun socket references object */ +#endif +#define O_WILL_RESET 0x1000 /* reset will be called next time */ +#ifndef OLD_ED +#define O_IN_EDIT 0x2000 /* object has an ed buffer open */ +#endif +#define O_BEING_DESTRUCTED 0x4000 +#ifndef NO_SNOOP +#define O_SNOOP 0x8000 +#endif + +/* + * Note: use of more than 16 bits means extending flags to an unsigned long + */ + +typedef struct sentence_s { +#ifndef NO_ADD_ACTION + char *verb; +#endif + struct sentence_s *next; + struct object_s *ob; + union string_or_func function; + int flags; +} sentence_t; + +typedef struct object_s { + unsigned short ref; /* Reference count. */ + unsigned short flags; /* Bits or'ed together from above */ +#ifdef DEBUG + unsigned int extra_ref; /* Used to check ref count. */ +#endif + const char * const obname; + struct object_s *next_hash; + struct object_s *next_ch_hash; + /* the fields above must match lpc_object_t */ + int load_time; /* time when this object was created */ +#ifndef NO_RESET + int next_reset; /* Time of next reset of this object */ +#endif + int time_of_ref; /* Time when last referenced. Used by clean_uo */ + program_t *prog; + struct object_s *next_all; + struct object_s *prev_all; +#ifndef NO_ENVIRONMENT + struct object_s *next_inv; + struct object_s *contains; + struct object_s *super; /* Which object surround us ? */ +#endif + struct interactive_s *interactive; /* Data about an interactive user */ + char *replaced_program; /* Program replaced with */ +#ifndef NO_LIGHT + short total_light; +#endif +#ifndef NO_SHADOWS + struct object_s *shadowing; /* Is this object shadowing ? */ + struct object_s *shadowed; /* Is this object shadowed ? */ +#endif /* NO_SHADOWS */ +#ifndef NO_ADD_ACTION + sentence_t *sent; + struct object_s *next_hashed_living; + char *living_name; /* Name of living object if in hash */ +#endif +#ifdef PACKAGE_UIDS + userid_t *uid; /* the "owner" of this object */ + userid_t *euid; /* the effective "owner" */ +#endif +#ifdef PRIVS + char *privs; /* object's privledges */ +#endif /* PRIVS */ +#ifdef PACKAGE_MUDLIB_STATS + statgroup_t stats; /* mudlib stats */ +#endif +#ifdef PACKAGE_PARSER + struct parse_info_s *pinfo; +#endif + svalue_t variables[1]; /* All variables to this program */ + /* The variables MUST come last in the struct */ +} object_t; + +typedef int (* get_objectsfn_t) (object_t *, void *); + +#ifdef DEBUG +#define add_ref(ob, str) SAFE(\ + if(ob->ref++ > 32000){\ + ob->flags |= O_BEING_DESTRUCTED;\ + destruct_object(ob);\ + error("ref count too high!\n");\ + } \ + debug(d_flag, \ + ("Add_ref %s (%d) from %s\n", \ + ob->obname, ob->ref, str));\ + ) +#else +#define add_ref(ob, str) if(ob->ref++ > 32000){ob->flags|=O_BEING_DESTRUCTED;destruct_object(ob);error("ref count too high!\n");} +#endif + +#define ROB_STRING_ERROR 1 +#define ROB_ARRAY_ERROR 2 +#define ROB_MAPPING_ERROR 4 +#define ROB_NUMERAL_ERROR 8 +#define ROB_GENERAL_ERROR 16 +#define ROB_CLASS_ERROR 32 +#define ROB_ERROR 63 + +#define SETOBNAME(ob,name) (*(const char **)&(ob->obname) = (char *) name) + +extern object_t *previous_ob; +extern int tot_alloc_object; +extern int tot_alloc_object_size; +extern int save_svalue_depth; +extern object_t **cgsp; +#ifdef F_SET_HIDE +extern int num_hidden; +#endif + +void bufcat (char **, char *); +INLINE int svalue_save_size (svalue_t *); +INLINE void save_svalue (svalue_t *, char **); +INLINE int restore_svalue (char *, svalue_t *); +int save_object (object_t *, const char *, int); +int save_object_str (object_t *, int, char *, int); +char *save_variable (svalue_t *); +int restore_object (object_t *, const char *, int); +void restore_variable (svalue_t *, char *); +object_t *get_empty_object (int); +void reset_object (object_t *); +void call_create (object_t *, int); +void reload_object (object_t *); +void free_object (object_t **, const char * const); +#ifdef F_SET_HIDE +INLINE int valid_hide (object_t *); +INLINE int object_visible (object_t *); +#else +#define object_visible(x) 1 +#endif +void tell_npc (object_t *, const char *); +void tell_object (object_t *, const char *, int); +int find_global_variable (program_t *, const char * const, unsigned short *, int); +void dealloc_object (object_t *, const char *); +void get_objects (object_t ***, int *, get_objectsfn_t, void *); +#ifdef DEBUGMALLOC_EXTENSIONS +void mark_command_giver_stack (void); +#endif +void save_command_giver (object_t *); +void restore_command_giver (void); +void set_command_giver (object_t *); +void clear_non_statics (object_t * ob); +void restore_object_from_buff (object_t * ob, char * theBuff, int noclear); +#endif diff --git a/fluffos-2.23-ds03/op_spec.c b/fluffos-2.23-ds03/op_spec.c new file mode 100644 index 0000000..a5b6073 --- /dev/null +++ b/fluffos-2.23-ds03/op_spec.c @@ -0,0 +1,76 @@ +/* + * This file specifies the operators used by the interpreter. + * Normally, these should not be commented out. + */ + +operator pop_value, push, efun0, efun1, efun2, efun3, efunv; + +operator short_int, number, real, byte, nbyte, string, short_string, const0, const1; + +operator aggregate, aggregate_assoc; +#ifdef DEBUG +operator break_point; +#endif + +/* these must be set up so that F_BRANCH is the last foward branch and + * F_BRANCH_X + 3 == F_BBRANCH_X + */ +operator branch_ne, branch_ge, branch_le, branch_eq; +operator branch_when_zero, branch_when_non_zero, branch; +operator bbranch_when_zero, bbranch_when_non_zero, bbranch; + +operator bbranch_lt; + +operator foreach, next_foreach, exit_foreach; +operator loop_cond_local, loop_cond_number; +operator loop_incr; +operator while_dec; + +operator lor, land; + +operator catch, end_catch; +operator time_expression, end_time_expression; + +operator switch; + +operator call_function_by_address, call_inherited, return, return_zero; + +/* eq must be first, gt must be last; c.f. is_boolean() */ +operator eq, ne, le, lt, ge, gt; + +operator inc, dec, pre_inc, post_inc, pre_dec, post_dec; + +operator transfer_local; + +operator make_ref, kill_refs; + +/* lvalue eops must be the original eop + 1 */ +operator local, local_lvalue; +operator ref, ref_lvalue; +operator global, global_lvalue; +operator member, member_lvalue; +operator index, index_lvalue; +operator rindex, rindex_lvalue; +operator nn_range, nn_range_lvalue, rn_range, rn_range_lvalue; +operator rr_range, rr_range_lvalue, nr_range, nr_range_lvalue; +operator ne_range, re_range; + +/* these must all be together */ +operator add_eq, sub_eq, and_eq, or_eq, xor_eq, lsh_eq, rsh_eq, mult_eq; +operator div_eq, mod_eq, assign; + +operator void_add_eq, void_assign, void_assign_local; + +operator add, subtract, multiply, divide, mod, and, or, xor, lsh, rsh; +operator not, negate, compl; + +operator function_constructor; +operator simul_efun; + +operator sscanf; +operator parse_command; + +operator new_class, new_empty_class; +operator expand_varargs; +operator type_check; + diff --git a/fluffos-2.23-ds03/options.h b/fluffos-2.23-ds03/options.h new file mode 100644 index 0000000..faeafc4 --- /dev/null +++ b/fluffos-2.23-ds03/options.h @@ -0,0 +1,921 @@ +/* + * options.h: defines for the compile-time configuration of the MudOS driver + */ + +#ifndef _OPTIONS_H_ +#define _OPTIONS_H_ + +/* + * YOU PROBABLY DO NOT WANT TO MODIFY THIS FILE. + * + * Do 'cp options.h local_options' and edit that instead. local_options, + * if it exists, overrides this file. + * + * The advantage is that when you upgrade to a newer MudOS driver, you can + * simply copy your local_options file into the src directory. The build + * process will warn you if new options have been added that you should + * choose settings for. + */ + +/**************************************************************************** + * EVERY time you change ANYTHING in this file, RECOMPILE from scratch. * + * (type "make clean" then "make" on a UNIX system) Failure to do so may * + * cause the driver to behave oddly. * + ****************************************************************************/ + +/* NOTES: + * Many of the configurable options are now set via the configuration file + * that is specified as the first argument to the driver. + * See port.h for those #defines related to portability (compatibility) if + * you have problems compiling on your system. + * Removing an efun from func_spec.c usually removes most, if not all, + * of the code associated with it. + * Note that anything defined in this file is also visible to LPC files + * surrounded by __. So #define FOO in this file defines __FOO__ for + * all LPC files. This allows code like: + * + * #ifdef __SENSIBLE_MODIFIERS__ + * ... + */ + +/**************************************************************************** + * MALLOC * + * -------- * + * For performance reasons, LP drivers have a variety of memory allocation * + * packages. If you don't care, use the default one on your system: * + * #define SYSMALLOC, #undef the others. * + ****************************************************************************/ + +/* You must choose exactly one of these malloc packages: + * ~~~~ + * SYSMALLOC: + * * Built-in system malloc. + * * No statistics. + * * SYSMALLOC incurs no additional CPU or memory overhead. + * + * MALLOC64 + * * Wodan's malloc, uses system malloc for small allocations and spreads + * * large allocations through the 64 bit memory space + * * won't work on 32 bit systems. + * MALLOC32 + * * fixes realloc by always doing a malloc/memcpy/free instead, try this + * * if you use more memory than expected (or MALLOC64 on a 64bit system). + */ +#define SYSMALLOC +#undef MMALLOC +#undef MALLOC64 +#undef MALLOC32 +/* You may optionally choose one (or none) of these malloc wrappers. These + * can be used in conjunction with any of the above malloc packages. + * + * WRAPPEDMALLOC: + * * Limited statistics. + * * Limited additional cpu overhead and no additional memory overhead. + * + * DEBUGMALLOC: + * * Statistics on precisely how much memory has been malloc'd (as well + * as the stats provided by WRAPPEDMALLOC). + * * Incurs a fair amount of overhead (both memory and CPU) + */ +#undef WRAPPEDMALLOC +#undef DEBUGMALLOC + +/* The following add certain bells and whistles to malloc: */ + +/* + * SBRK_OK: do not define this unless SMALLOC is chosen above. + * Defining this causes smalloc to use the low level memory allocation + * routines, and to act as a malloc replacement. Conversely, undef'ing + * SBRK_OK causes smalloc to act as a wrapper for the system malloc + * routines. + * + * Note: + * NeXTStep 3.x users should always #undef SBRK_OK. + */ +#undef SBRK_OK + +/* DO_MSTATS: do not define this unless BSDMALLOC or SMALLOC is chosen above. + * Defining this causes those replacement mallocs to keep statistics that + * the malloc_status() efun will print out (including total memory + * allocated/used). + */ +#undef DO_MSTATS + +/* DEBUGMALLOC_EXTENSIONS: defining this (in addition to DEBUGMALLOC) enables + * the set_malloc_mask(int) and debugmalloc(string,int) efuns. These two + * efuns basically allow you to cause certain malloc's and free's (with tags + * selected by a specified mask) to print debug information (addr, tag, + * description, size) to stdio (in the shell that invoked the driver) or to a + * file. Not defining this does reduce the overhead of DEBUGMALLOC from 16 + * bytes per malloc down to 8. This macro has no effect if DEBUGMALLOC isn't + * defined. + */ +#undef DEBUGMALLOC_EXTENSIONS + +/* CHECK_MEMORY: defining this (in addition to DEBUGMALLOC and + * DEBUGMALLOC_EXTENSIONS) causes the driver to check for memory + * corruption due to writing before the start or end of a block. This + * also adds the check_memory() efun. Takes a considerable ammount + * more memory. Mainly for debugging. + */ +#undef CHECK_MEMORY + +/**************************************************************************** + * COMPATIBILITY * + * --------------- * + * The MudOS driver has evolved quite a bit over the years. These defines * + * are mainly to preserve old behavior in case people didn't want to * + * rewrite the relevant portions of their code. * + * * + * In most cases, code which needs these defines should be rewritten when * + * possible. The 'Compat status' field is designed to give an idea how * + * likely it is that support for that option will be removed in the near * + * future. Certain options are fairly easy to work around, and double * + * the size of the associated code, as well as the maintenance workload, * + * and can make the code significantly more complex or harder to read, so * + * supporting them indefinitely is impractical. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* HAS_STATUS_TYPE: old MudOS drivers had a 'status' type which was + * identical to the 'int' type. Define this to bring it back. + * + * Compat status: very archaic, but easy to support. + */ +#undef HAS_STATUS_TYPE + +/* explode(): + * + * The old behavior (#undef both of the below) strips any number of + * delimiters at the start of the string, and one at the end. So + * explode("..x.y..z..", ".") gives ({ "x", "y", "", "z", "" }) + * + * SANE_EXPLODE_STRING strips off at most one leading delimiter, and + * still strips off one at the end, so the example above gives + * ({ "", "x", "y", "", "z", "" }). + * + * REVERSIBLE_EXPLODE_STRING overrides SANE_EXPLODE_STRING, and makes + * it so that implode(explode(x, y), y) is always x; i.e. no delimiters + * are ever stripped. So the example above gives + * ({ "", "", "x", "y", "", "z", "", "" }). + */ +#undef SANE_EXPLODE_STRING +#undef REVERSIBLE_EXPLODE_STRING + +/* CAST_CALL_OTHERS: define this if you want to require casting of call_other's; + * this was the default behavior of the driver prior to this addition. + * + * Compat status: code that requires it doesn't break, and it promotes + * sloppy coding with no benefits. + */ +#undef CAST_CALL_OTHERS + +/* NONINTERACTIVE_STDERR_WRITE: if defined, all writes/tells/etc to + * noninteractive objects will be written to stderr prefixed with a ']' + * (old behavior). + * + * Compat status: Easy to support, and also on the "It's a bug! No, it's + * a feature!" religious war list. + */ +#undef NONINTERACTIVE_STDERR_WRITE + +/* NO_LIGHT: define this to disable the set_light() and driver maintenance + * of light levels in objects. You can simulate it via LPC if you want... + * + * Compat status: Very dated, easy to simulate, and gross. + */ +#define NO_LIGHT + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + * process_input() then becomes the only way to deal with player input. + * + * Compat status: next to impossible to simulate, hard to replace, and + * very, very widely used. + */ +#define NO_ADD_ACTION + +/* NO_SNOOP: disables the snoop() efun and all related functionality. + */ +#undef NO_SNOOP + +/* NO_ADD_ACTION: define this to remove add_action, commands, livings, etc. + process_input() then becomes the only way to deal with player input. */ + +/* NO_ENVIRONMENT: define this to remove the handling of object containment + * relationships by the driver + * + * Compat status: hard to simulate efficiently, and very widely used. + */ +#undef NO_ENVIRONMENT + +/* NO_WIZARDS: for historical reasons, MudOS used to keep track of who + * is and isn't a wizard. Defining this removes that completely. + * If this is defined, the wizardp() and related efuns don't exist. + * + * Also note that if it is not defined, then non-wizards are always put + * in restricted mode when ed() is used, regardless of the setting of + * the restrict parameter. + * + * Compat status: easy to simulate and dated. + */ +#define NO_WIZARDS + +/* OLD_TYPE_BEHAVIOR: reintroduces a bug in type-checking that effectively + * renders compile time type checking useless. For backwards compatibility. + * + * Compat status: dealing with all the resulting compile errors can be + * a huge pain even if they are correct, and the impact on the code is + * small. + */ +#undef OLD_TYPE_BEHAVIOR + +/* OLD_RANGE_BEHAVIOR: define this if you want negative indexes in string + * or buffer range values (not lvalue, i.e. x[-2..-1]; for e.g. not + * x[-2..-1] = foo, the latter is always illegal) to mean counting from the + * end + * + * Compat status: Not horribly difficult to replace reliance on this, but not + * trivial, and cannot be simulated. + */ +#undef OLD_RANGE_BEHAVIOR + +/* define to get a warning for code that might use the old range behavior + * when you're not actually using the old range behavior*/ +#undef WARN_OLD_RANGE_BEHAVIOR + + +/* OLD_ED: ed() efun backwards compatible with the old version. The new + * version requires/allows a mudlib front end. + * + * Compat status: Easily simulated. + */ +#define OLD_ED + +/* In ed auto-indent, + * 1) does the case line get indented after the switch() ? + * 2) How far do we indent? (this can also be set in the mudlib) + */ +#undef ED_INDENT_CASE +#define ED_INDENT_SPACES 4 + +/* SENSIBLE_MODIFIERS: + * Turning this on changes a few things, which may break old code: + * + * (1) 'static' is not recognized; either 'nosave' or 'protected' must + * be used instead. + * (2) The old meaning of 'public' is no longer allowed. Explicit + * functions must be defined at each level to allow access to + * privately inherited functions. + * (3) 'public' now means the default visibility. Previously there was + * no keyword that meant this (before you ask, 'public' meant something + * else, and if you don't know that, you probably don't have any reason + * to care about the old meaning). + */ +#define SENSIBLE_MODIFIERS + +/**************************************************************************** + * MISCELLANEOUS * + * --------------- * + * Various options that affect the way the driver behaves. * + * * + * WARNING: If you are using software designed to run with the MudOS driver * + * it may assume certain settings of these options. Check the * + * instructions for details. * + ****************************************************************************/ + +/* + * Define this in order to use Fermat@Equilibria's MD5 based crypt() instead + * of the operating system's. It has the advantage of giving the same value + * on all architectures, and being stronger than the standard UNIX crypt(). + */ +#undef CUSTOM_CRYPT + +/* + * Some minor tweaks that make it a bit easier to run code designed to run + * on LPmud 3.2/3.2.1. Currently has the following effects: + * + * . m_indices() and m_values() are synonyms for keys() and values(), + * respectively + * . map_delete() returns it's first argument + * . inherit_list() means deep_inherit_list(), not shallow_inherit_list() + * . heart_beat_info() is a synonym for heart_beats() + */ +#undef COMPAT_32 + +/* + * Keep statistics about allocated strings, etc. Which can be viewed with + * the mud_status() efun. If this is off, mud_status() and memory_info() + * ignore allocated strings, but string operations run faster. + */ +#define STRING_STATS + +/* + * Similarly for arrays ... + */ +#define ARRAY_STATS + +/* LOG_CATCHES: define this to cause errors that are catch()'d to be + * sent to the debug log anyway. + * + * On by default, because newer libs use catch() a lot, and it's confusing + * if the errors don't show up in the logs. + */ +#define LOG_CATCHES + +/* ARGUMENTS_IN_TRACEBACK: prints out function call arguments in error + * tracebacks, to aid in debugging. Note: it prints the values of + * the arguments at the time of the error, not when the function + * was called. It looks like this: + * + * Failed to load file: read_buffer + * program: command/update.c, object: command/update line 15 + * ' commandHook' in ' clone/user.c' (' clone/user#1')line 72 + * arguments were ("/read_buffer.c") + * ' main' in ' command/update.c' (' command/update')line 15 + * arguments were ("/read_buffer.c") + * + * The only down side is some people like their logs shorter + */ +#define ARGUMENTS_IN_TRACEBACK + +/* LOCALS_IN_TRACEBACK: similar to ARGUMENTS_IN_TRACEBACK, but for local + * variables. The output looks more or less like: + * + * locals: 1, "local_value" + * + * Same as above. Tends to produce even longer logs, but very useful for + * tracking errors. + */ +#define LOCALS_IN_TRACEBACK + +/* MUDLIB_ERROR_HANDLER: If you define this, the driver doesn't do any + * handling of runtime errors, other than to turn the heartbeats of + * objects off. Information about the error is passed in a mapping + * to the error_handler() function in the master object. Whatever is + * returned is put in the debug.log. + * + * A good mudlib error handler is one of the best tools for tracking down + * errors. Unfortunately, you need to have one. Check the testsuite or + * other libs for an example. + */ +#define MUDLIB_ERROR_HANDLER + +/* CONFIG_FILE_DIR specifies a directory in which the driver will search for + * config files by default. If you don't wish to use this define, you may + * always specify a full path to the config file when starting the driver. + */ +#define CONFIG_FILE_DIR "/home/atuin/bin" + +/* DEFAULT_PRAGMAS: This should be a sum of pragmas you want to always + * be on, i.e. + * + * #define DEFAULT_PRAGMAS PRAGMA_STRICT_TYPES + PRAGMA_SAVE_TYPES + * + * will make every LPC file behave as if it had the lines: + * #pragma strict_types + * #pragma save_types + * + * for no default pragmas: + * #define DEFAULT_PRAGMAS 0 + * + * If you don't know what these are, 0 is a good choice. + * + * Supported pragmas: + * PRAGMA_STRICT_TYPES: enforces strict type checking + * PRAGMA_WARNINGS: issues warnings about various dangerous things in + * your code + * PRAGMA_SAVE_TYPES: save the types of function arguments for checking + * calls to functions in this object by objects that + * inherit it. + * PRAGMA_OPTIMIZE: make a second pass over the generated code to + * optimize it further. Currently does jump threading. + * PRAGMA_ERROR_CONTEXT:include some text telling where on the line a + * compilation error occured. + */ +#define DEFAULT_PRAGMAS PRAGMA_WARNINGS + PRAGMA_STRICT_TYPES + PRAGMA_ERROR_CONTEXT + +/* supress warnings about unused arguments; only warn about unused local + * variables. Makes older code (where argument names were required) compile + * more quietly. + */ +#define SUPPRESS_ARGUMENT_WARNINGS + +/* NO_RESETS: completely disable the periodic calling of reset() */ +#undef NO_RESETS + +/* LAZY_RESETS: if this is defined, an object will only have reset() + * called in it when it is touched via call_other() or move_object() + * (assuming enough time has passed since the last reset). If LAZY_RESETS + * is #undef'd, then reset() will be called as always (which guaranteed that + * reset would always be called at least once). The advantage of lazy + * resets is that reset doesn't get called in an object that is touched + * once and never again (which can save memory since some objects won't get + * reloaded that otherwise would). + */ +#undef LAZY_RESETS + +/* SAVE_EXTENSION: defines the file extension used by save_object(). + * and restore_object(). Some sysadmins run scripts that periodically + * scan for and remove files ending in .o (but many mudlibs are already + * set up to use .o thus we leave .o as the default). + */ +#define SAVE_EXTENSION ".o" + +/* NO_ANSI: define if you wish to disallow users from typing in commands that + * contain ANSI escape sequences. Defining NO_ANSI causes all escapes + * (ASCII 27) to be replaced with a space ' ' before the string is passed + * to the action routines added with add_action. + * + * STRIP_BEFORE_PROCESS_INPUT allows the location where the stripping is + * done to be controlled. If it is defined, then process_input() doesn't + * see ANSI characters either; if it is undefined ESC chars can be processed + * by process_input(), but are stripped before add_actions are called. + * Note that if NO_ADD_ACTION is defined, then #define NO_ANSI without + * #define STRIP_BEFORE_PROCESS_INPUT is the same as #undef NO_ANSI. + * + * If you anticipate problems with users intentionally typing in ANSI codes + * to make your terminal flash, etc define this. + */ +#define NO_ANSI +#define STRIP_BEFORE_PROCESS_INPUT + +/* OPCPROF: define this if you wish to enable OPC profiling. Allows a dump + * of the # of times each efun is invoked (via the opcprof() efun). + */ +#undef OPCPROF + +/* OPCPROF_2D: define this if you wish to enable 2-D OPC profiling. Allows a + * dump of the # of times each *pair* of eoperators is invoked. + * + * You can't use this and OPCPROF at the same time. + */ +#undef OPCPROF_2D + +/* TRAP_CRASHES: define this if you want MudOS to call crash() in master.c + * and then shutdown when signals are received that would normally crash the + * driver. + */ +#define TRAP_CRASHES + +/* THIS_PLAYER_IN_CALL_OUT: define this if you wish this_player() to be + * usable from within call_out() callbacks. + */ +#define THIS_PLAYER_IN_CALL_OUT + +/* CALLOUT_HANDLES: If this is defined, call_out() returns an integer, which + * can be passed to remove_call_out() or find_call_out(). Removing call_outs + * by name is still allowed, but is significantly less efficient, and also + * doesn't work for function pointers. This option adds 4 bytes overhead + * per callout to keep track of the handle. + */ +#define CALLOUT_HANDLES + +/* FLUSH_OUTPUT_IMMEDIATELY: Causes output to be written to sockets + * immediately after being generated. Useful for debugging. + */ +#undef FLUSH_OUTPUT_IMMEDIATELY + +/* PRIVS: define this if you want object privileges. Your mudlib must + * explicitly make use of this functionality to be useful. Defining this + * this will increase the size of the object structure by 4 bytes (8 bytes + * on the DEC Alpha) and will add a new master apply during object creation + * to "privs_file". In general, privileges can be used to increase the + * granularity of security beyond the current root uid mechanism. + * + * [NOTE: for those who'd rather do such things at the mudlib level, look at + * the inherits() efun and the 'valid_object' apply to master.] + */ +#undef PRIVS + +/* INTERACTIVE_CATCH_TELL: define this if you want catch_tell called on + * interactives as well as NPCs. If this is defined, user.c will need a + * catch_tell(msg) method that calls receive(msg); +*/ +#undef INTERACTIVE_CATCH_TELL + +/* RECEIVE_ED: define this if you want normal ed output to go to a + receive_ed() apply in the player ob. Some errors still go directly + to output. Useful for post-processing (perhaps colorizing?) ed + output. Prototype: mixed receive_ed(string txt, string fname); + If fname, return a string that ed will output, 0 to let ed handle + the output in the default way, or 1 to handle the output yourself. + If fname == 0, output is help text and you may return any of the above + or an array of strings that will be more'ed. +*/ +#undef RECEIVE_ED + +/* RESTRICTED_ED: define this if you want restricted ed mode enabled. + */ +#define RESTRICTED_ED + +/* NO_SHADOWS: define this if you want to disable shadows in your driver. + */ +#undef NO_SHADOWS + +/* SNOOP_SHADOWED: define this if you want snoop to report what is + * sent to the player even in the event that the player's catch_tell() is + * shadowed and the player may not be seeing what is being sent. Messages + * of this sort will be prefixed with $$. + */ +#undef SNOOP_SHADOWED + +/* RECEIVE_SNOOP: define this if you want snoop text to be sent to + * the receive_snoop() function in the snooper object (instead of being + * sent directly via add_message()). This is useful if you want to + * build a smart client that does something different with snoop messages. + */ +#define RECEIVE_SNOOP + +/* PROFILE_FUNCTIONS: define this to be able to measure the CPU time used by + * all of the user-defined functions in each LPC object. Note: defining + * this adds three long ints (12 bytes on 32-bit machines) to the function + * header structs. Also note that the resolution of the getrusage() timer + * may not be high enough on some machines to give non-zero execution + * times to very small (fast) functions. In particular if the clock + * resolution is 1/60 of a second, then any time less than approxmately 15k + * microseconds will resolve to zero (0). + */ +#undef PROFILE_FUNCTIONS + +/* NO_BUFFER_TYPE: if this is #define'd then LPC code using the 'buffer' + * type won't be allowed to compile (since the 'buffer' type won't be + * recognized by the lexer). + */ +#undef NO_BUFFER_TYPE + +/* ARRAY_RESERVED_WORD: If this is defined then the word 'array' can + * be used to define arrays, as in: + * + * int array x = ({ .... }); + * + * A side effect is that 'array' cannot be a variable or function name. + */ +#undef ARRAY_RESERVED_WORD + +/* REF_RESERVED_WORD: If this is defined then the word 'ref' can be + * used to pass arguments to functions by value. Example: + * + * void inc(int ref x) { + * x++; + * } + * + * ... y = 1; inc(ref y); ... + * + * A side effect is that 'ref' cannot be a variable or function name. + * + * Note: ref must be used in *both* places; this is intentional. It protects + * against passing references to routines which don't intend to return values + * through their arguments, and against forgetting to pass a reference + * to a function which wants one (or accidentally having a variable modified!) + */ +#define REF_RESERVED_WORD + +/**************************************************************************** + * PACKAGES * + * -------- * + * Defining some/all of the following add certain efuns, and sometimes * + * add/remove code from the driver. * + * * + * if PACKAGE_XYZZY is defined here, then the code in packages/xyzzy.c * + * and the efuns in packages/xyzzy_spec.c will be added to the driver. * + ****************************************************************************/ + +/* various miscellaneous efuns */ +#define PACKAGE_CONTRIB + +/* efuns that are only of use to those that know something about driver + internals */ +#define PACKAGE_DEVELOP + +/* PACKAGE_MATH: determines whether or not the math efuns (for floats) are + included. + */ +#define PACKAGE_MATH + +/* PACKAGE_MATRIX: determines whether or not the 3d graphics efuns (for floats) + * are included - see packages/matrix.spec for a list. + */ +#undef PACKAGE_MATRIX + +/* PACKAGE_MUDLIB_STATS: define this to enable domain and author stats + * maintenance by the driver. These mudlib stats are more domain + * based than user based, and replaces the traditional wiz_list stats. + */ +#undef PACKAGE_MUDLIB_STATS + +/* PACKAGE_SOCKETS: define this to enable the socket efunctions. This + * causes HAS_SOCKETS to be defined for all LPC objects. + */ +#define PACKAGE_SOCKETS + +/* PACKAGE_PARSER: Natural language parsing efuns for interactive fiction + * type applications + */ +#undef PACKAGE_PARSER + +/* PACKAGE_EXTERNAL: Allows the driver to exec() commands specified in the + * config file. + */ +#define PACKAGE_EXTERNAL + +/* NUM_EXTERNAL_CMDS: the number of external commands supported */ +#ifdef PACKAGE_EXTERNAL +#define NUM_EXTERNAL_CMDS 100 +#endif + +/* PACKAGE_DB: efuns for external database access using msql */ +#undef PACKAGE_DB + +/* If PACKAGE_DB is defined above, you must pick ONE of the following supported + * databases + */ +#ifdef PACKAGE_DB +#undef USE_MSQL +#define USE_MYSQL 2 +#undef USE_POSTGRES +#endif + +/**************************************************************************** + * UID PACKAGE * + * ----------- * + * UIDS are the basis for some mudlib security systems. Basically, they're * + * preserved for backwards compatibility, as several ways of breaking * + * almost any system which relies on them are known. (No, it's not a flaw * + * of uids; only that b/c of the ease with which LPC objects can call * + * each other, it's far too easy to leave holes) * + * * + * If you don't care about security, the first option is probably what you * + * want. * + ****************************************************************************/ + +/* + * PACKAGE_UIDS: define this if you want a driver that does use uids. + * + */ +#define PACKAGE_UIDS + +/*PACKAGE DWLIB: some discworld mudlib simuls coded in C (well just one right + now) */ + +#define PACKAGE_DWLIB + +/* AUTO_SETEUID: when an object is created it's euid is automatically set to + * the equivalent of seteuid(getuid(this_object())). undef AUTO_SETEUID + * if you would rather have the euid of the created object be set to 0. + */ +#define AUTO_SETEUID + +/* AUTO_TRUST_BACKBONE: define this if you want objects with the backbone + * uid to automatically be trusted and to have their euid set to the uid of + * the object that forced the object's creation. + */ +#undef AUTO_TRUST_BACKBONE + +/************************************************************************* + * FOR EXPERIENCED USERS * + * ----------------------- * + * Most of these options will probably be of no interest to many users. * + *************************************************************************/ + +/* USE_32BIT_ADDRESSES: Use 32 bits for addresses of function, instead of + * the usual 16 bits. This increases the maximum program size from 64k + * of LPC bytecode (NOT source) to 4 GB. Branches are still 16 bits, + * imposing a 64k limit on catch(), if(), switch(), loops, and most other + * control structures. It would take an extremely large function to hit + * those limits, though. + * + * Overhead: 2 bytes/function with LPC->C off. Having LPC->C on forces + * this option, since it needs 4 bytes to store the function pointers + * anyway, and this setting is ignored. + */ +#undef USE_32BIT_ADDRESSES + +/* HEARTBEAT_INTERVAL: define heartbeat interval in microseconds (us). + * 1,000,000 us = 1 second. The value of this macro specifies + * the frequency with which the heart_beat method will be called in + * those LPC objects which have called set_heart_beat(1). + * + * [NOTE: if ualarm() isn't available, alarm() is used instead. Since + * alarm() requires its argument in units of a second, we map 1 - 1,000,000 us + * to an actual interval of one (1) second and 1,000,001 - 2,000,000 maps to + * an actual interval of two (2) seconds, etc.] + */ +#define HEARTBEAT_INTERVAL 2000000 + +/* + * CALLOUT_CYCLE_SIZE: This is the number of slots in the call_out list. + * It should be approximately the average number of active call_outs, or + * a few times smaller. It should also be a power of 2, and also be relatively + * prime to any common call_out lengths. If all this is too confusing, 32 + * isn't a bad number :-) + */ +#define CALLOUT_CYCLE_SIZE 512 + +/* LARGEST_PRINTABLE_STRING: defines the size of the vsprintf() buffer in + * comm.c's add_message(). Instead of blindly making this value larger, + * your mudlib should be coded to not send huge strings to users. + */ +#define LARGEST_PRINTABLE_STRING 8192 + +/* MESSAGE_BUFFER_SIZE: determines the size of the buffer for output that + * is sent to users. + */ +#define MESSAGE_BUFFER_SIZE 4096 + +/* APPLY_CACHE_BITS: defines the number of bits to use in the call_other cache + * (in interpret.c). + * + * Memory overhead is (1 << APPLY_CACHE_BITS)*16. + * [assuming 32 bit pointers and 16 bit shorts] + * + * ACB: entries: overhead: + * 6 64 1k + * 8 256 4k + * 10 1024 16k + * 12 4096 64k + * 14 16384 256k + * 16 65536 1M + */ +#define APPLY_CACHE_BITS 20 + +/* CACHE_STATS: define this if you want call_other (apply_low) cache + * statistics. Causes HAS_CACHE_STATS to be defined in all LPC objects. + */ +#define CACHE_STATS + +/* TRACE: define this to enable the trace() and traceprefix() efuns. + * (keeping this undefined will cause the driver to run faster). + */ +#define TRACE + +/* RUNTIME_LOADING: On systems which support it, it allows LPC->C compilation + * 'on the fly' without having to recompile the driver. + * + * Note: This currently only works on machines that have the dlopen() system + * call. SunOS and IRIX do, as do a number of others. AIX and Ultrix don't. + * Linux does if you are using ELF. + */ +#undef RUNTIME_LOADING + +/* TRACE_CODE: define this to enable code tracing (the driver will print + * out the previous lines of code to an error) eval_instruction() runs about + * twice as fast when this is not defined (for the most common eoperators). + */ +#undef TRACE_CODE + +/* HEART_BEAT_CHUNK: The number of heart_beat chunks allocated at a time. + * A large number wastes memory as some will be sitting around unused, while + * a small one wastes more CPU reallocating when it needs to grow. Default + * to a medium value. + */ +#define HEART_BEAT_CHUNK 32 + +/* SERVER_IP: For machines with multiple IP addresses, this specifies which + * one to use. This is useful for IP accounting and is necessary to be + * able to do ident lookups on such machines. + * + * example: #define SERVER_IP "194.229.18.27" + */ +#undef SERVER_IP + +/* Some maximum string sizes + */ +#define SMALL_STRING_SIZE 100 +#define LARGE_STRING_SIZE 1000 +#define COMMAND_BUF_SIZE 2000 + +/* Number of levels of nested datastructures allowed -- this limit prevents + * crashes from occuring when saving objects containing variables containing + * recursive datastructures (with circular references). + */ +#define MAX_SAVE_SVALUE_DEPTH 100 + +/* Miscellaneous config options that should probably be in the runtime + * config file. + */ +/* MAX_LOCAL: maximum number of local variables allowed per LPC function */ +#define CFG_MAX_LOCAL_VARIABLES 50 + +/* CFG_MAX_GLOBAL_VARIABLES: This value determines the maximum number of + * global variables per object. The maximum value is 65536. There is + * a marginal memory increase for a value over 256. + */ +#define CFG_MAX_GLOBAL_VARIABLES 65536 + +#define CFG_EVALUATOR_STACK_SIZE 3000 +#define CFG_COMPILER_STACK_SIZE 600 +#define CFG_MAX_CALL_DEPTH 150 +/* This must be one of 4, 16, 64, 256, 1024, 4096 */ +#define CFG_LIVING_HASH_SIZE 256 + +/* NEXT_MALLOC_DEBUG: define this if using a NeXT and you want to enable + * the malloc_check() and/or malloc_debug() efuns. Run the 'man malloc_debug' + * command on the NeXT to find out what the arguments to malloc_debug(int) + * mean. The malloc_check() efun calls the NeXT NXMallocCheck() system + * call which does a consistency check on malloc's data structures (this + * consistency check is done at each malloc() and free() for certain + * malloc_debug() levels). A non-zero return value indicates there was + * a consistency problem. For those NeXT users wanting a bit more + * performance out of malloc, try defining NEXT_MALLOC_DEBUG and calling the + * malloc_debug(-1) efun (with an arg of -1). This will turn all + * malloc debugging off and call malloc_singlethreaded() which the NeXT + * malloc man page claims can make NeXT system malloc 10% to 15% faster. + * + * [NOTE: This #define has no affect on the driver if not using the + * NeXTSTEP OS.] + * + * Warning: if you use a NeXT and define NEXT_MALLOC_DEBUG, be sure to + * protect the use of the malloc_check() and malloc_debug() efuns + * since setting certain debug levels can cause malloc() and free() + * to become _very_ slow (protect efuns by using simul_efuns and + * valid_override). + * + * [NOTE: malloc_debug(6) is a good compromise between efficiency and + * completeness of malloc debugging (malloc/free will be about half as fast).] + */ +#define NEXT_MALLOC_DEBUG + + +/* GET_CHAR_IS_BUFFERED: Normally get_char() is unbuffered. That is, once + * a character is received for get_char(), anything else is in the input + * stream is immediately thrown away. This can be very undesirable, especially + * if you're calling get_char() again from the handler from the previous call. + * Define this if you want get_char() to be buffered. In this case, the buffer + * will only get flushed if get_char() is not called from the first get_char()'s + * LPC callback handler. + */ +#undef GET_CHAR_IS_BUFFERED + +/* PACKAGE_COMPRESS: Enable MCCP support and compressed save files + SAVE_GZ_EXTENSION: save extension for compressed files + */ +#define HAVE_ZLIB +#define PACKAGE_COMPRESS +#define SAVE_GZ_EXTENSION ".o.gz" + +/* CALL_OTHER_TYPE_CHECK: enable type checking for call_other() + * (-> operator on objects) + */ +#undef CALL_OTHER_TYPE_CHECK + +/* CALL_OTHER_WARN, make it warning instead of errors */ +#undef CALL_OTHER_WARN + +/* WARN_TAB: Some versions of the editor built in indent function use + * tabs for indenting. This options turns on a warning message for + * files indented with tabs instead of spaces. + */ +#define WARN_TAB + +/* USE_ICONV: Use iconv to translate input and output from/to the users char + * encoding + */ +#define USE_ICONV + +/* WOMBLES: don't allow spaces between start/end of array/mapping/functional token chars so ({1,2,3}) still works, but ( { 1 , 2 , 3 } ) doesn't and ({ 1 , 2 , 3 }) does.*/ +#define WOMBLES + +/* ALLOW_INHERIT_AFTER_FUNCTION: allow inheriting after functions have been defined (this includes prototypes). This caused crashes in v22.2a but it may have been fixed since */ +#undef ALLOW_INHERIT_AFTER_FUNCTION + +/*PACKAGE_ASYNC: adds some efuns for asyncronous IO */ +#define PACKAGE_ASYNC + +/*PACKAGE_SHA1: adds a function to calculate the sha1 hash of a string sha1(string)*/ +#undef PACKAGE_SHA1 + +/*PACKAGE_CRYPTO: adds a function that does multiple hash types hash(hash, string), needs openssl lib and includes and -lssl in system_libs*/ +#undef PACKAGE_CRYPTO + +/* PROG_REF_TYPE size of program ref counter: + * char for 8 bit, short for 16, int for 32, + * long long for 64 (completely useless on 32 bit machines though!) */ +#define PROG_REF_TYPE short + +/* HAS_CONSOLE: If defined, the driver can take the argument -C + * which will give the driver an interactive console (you can type + * commands at the terminal.) Backgrounding the driver will turn off + * the console, but sending signal SIGTTIN (kill -21) to the driver can + * turn it back on. Typing 'help' will display commands available. + * The intent is to allow the inspection of things that are difficult + * to inspect from inside the mud. + */ +#define HAS_CONSOLE + +/* IPV6: Use IP version 6 instead of 4, for most people the only difference + * will be that numerical IP addresses get ::ffff: added in front.*/ +#define IPV6 + +/* static user space dtrace probes, try them if you have dtrace! */ +#undef DTRACE + +/* use class keyword for lpc structs */ +#define STRUCT_CLASS + +/* use struct keyword for lpc structs */ +#define STRUCT_STRUCT +#endif + diff --git a/fluffos-2.23-ds03/origin.h b/fluffos-2.23-ds03/origin.h new file mode 100644 index 0000000..d6d69da --- /dev/null +++ b/fluffos-2.23-ds03/origin.h @@ -0,0 +1,17 @@ +#ifndef ORIGIN_H +#define ORIGIN_H + +enum origin { + ORIGIN_DRIVER = 0x01, + ORIGIN_LOCAL = 0x02, + ORIGIN_CALL_OTHER = 0x04, + ORIGIN_SIMUL_EFUN = 0x08, + ORIGIN_INTERNAL = 0x10, + ORIGIN_EFUN = 0x20, + /* pseudo frames for call_other function pointers and efun pointer */ + ORIGIN_FUNCTION_POINTER = 0x40, + /* anonymous functions */ + ORIGIN_FUNCTIONAL = 0x80 +}; + +#endif diff --git a/fluffos-2.23-ds03/otable.c b/fluffos-2.23-ds03/otable.c new file mode 100644 index 0000000..efdd4a0 --- /dev/null +++ b/fluffos-2.23-ds03/otable.c @@ -0,0 +1,263 @@ +#include "std.h" +#include "otable.h" +#include "comm.h" +#include "hash.h" +#include "simul_efun.h" +#include "master.h" +#include "object.h" + +/* + * Object name hash table. Object names are unique, so no special + * problems - like stralloc.c. For non-unique hashed names, we need + * a better package (if we want to be able to get at them all) - we + * cant move them to the head of the hash chain, for example. + * + * Note: if you change an object name, you must remove it and reenter it. + */ + +static int otable_size; +static int otable_size_minus_one; + +static object_t *find_obj_n(const char *); + +/* + * Object hash function, ripped off from stralloc.c. + */ +#define ObjHash(s) whashstr(s) & otable_size_minus_one + +/* + * hash table - list of pointers to heads of object chains. + * Each object in chain has a pointer, next_hash, to the next object. + */ + +static object_t **obj_table = 0; +static object_t **ch_table = 0; + +static char *basename(const char *full, int *size) { + char *tmp; + char *name= new_string(*size = strlen(full), "base_name: name"); + while (*full == '/') { + full++; + (*size)--; + } + strcpy(name, full); + tmp = strchr(name, '#'); + if (tmp) { + *size = tmp-name; + } + while (*size > 2&& name[*size-1] == 'c'&& name[*size-2] == '.') + *size -= 2; + name[*size] = 0; + name = extend_string(name, *size); + return name; +} + +void init_otable() { + int x, y; + + /* ensure that otable_size is a power of 2 */ + y = OTABLE_SIZE; + for (otable_size = 1; otable_size < y; otable_size *= 2) + ; + otable_size_minus_one = otable_size - 1; + obj_table = CALLOCATE(otable_size, object_t *, + TAG_OBJ_TBL, "init_otable"); + ch_table = CALLOCATE(otable_size, object_t *, + TAG_OBJ_TBL, "init_ch_otable"); + + for (x = 0; x < otable_size; x++) { + obj_table[x] = 0; + ch_table[x] = 0; + } +} + +/* + * Looks for obj in table, moves it to head. + */ + +static long obj_searches = 0, obj_probes = 0, objs_found = 0; + +/* A global. *shhhh* don't tell. */ +static int h; +static int ch; + +static object_t *find_obj_n(const char * s) { + object_t *curr, *prev; + h = ObjHash(s); + curr = obj_table[h]; + prev = 0; + + obj_searches++; + + while (curr) { + obj_probes++; + if (!strcmp(curr->obname, s)) { /* found it */ + if (prev) { /* not at head of list */ + prev->next_hash = curr->next_hash; + curr->next_hash = obj_table[h]; + obj_table[h] = curr; + } + objs_found++; + return (curr); /* pointer to object */ + } + prev = curr; + curr = curr->next_hash; + } + + return (0); /* not found */ +} + +array_t *children(const char * s) { + object_t *curr; + array_t *vec; + int size; + int count = 0; + + s = basename(s, &size); + ch = ObjHash(s); + curr = ch_table[ch]; + + vec = allocate_empty_array(max_array_size); + while (curr && count < max_array_size) { + if (!strncmp(curr->obname, s, size)) { /* found one */ + vec->item[count].u.ob = curr; + add_ref(curr, "children"); + vec->item[count].type = T_OBJECT; + count++; + } + curr = curr->next_ch_hash; + } + FREE_MSTR(s); + vec = resize_array(vec, count); + return (vec); +} + +/* + * Add an object to the table - can't have duplicate names. + * + * Exception: Precompiled objects have a dummy entry here, but it is + * guaranteed to be behind the real entry if a real entry exists. + */ + +static int objs_in_table = 0; + +void enter_object_hash(object_t * ob) { +#ifdef DEBUG + object_t *s; +#endif + char *base; + int dummy; +#ifndef DEBUG + h = ObjHash(ob->obname); +#else + s = find_obj_n(ob->obname); /* This sets h */ + /* when these reload, the new copy comes in before the old goes out */ + if (s != master_ob && s != simul_efun_ob) { + DEBUG_CHECK1(s && s != ob, + "Duplicate object \"/%s\" in object hash table", + ob->obname); + } +#endif + + ob->next_hash = obj_table[h]; + obj_table[h] = ob; + objs_in_table++; + + //for children() + base = basename(ob->obname, &dummy); + + ch = ObjHash(base); + ob->next_ch_hash = ch_table[ch]; + ch_table[ch] = ob; + FREE_MSTR(base); + return; +} + +/* + * Remove an object from the table - generally called when it + * is removed from the next_all list - i.e. in destruct. + */ + +void remove_object_hash(object_t * ob) { + int dummy; + object_t *s; + object_t *t = 0; + char *base; + + s = find_obj_n(ob->obname); /* this sets h, and cycles the ob to the front */ + if (!s) + fatal("couldn't find object %s in obj_table", ob->obname); + + DEBUG_CHECK1(s != ob, "Remove object \"/%s\": found a different object!", + ob->obname); + + obj_table[h] = ob->next_hash; + ob->next_hash = 0; + objs_in_table--; + + base = basename(ob->obname, &dummy); + ch = ObjHash(base); + FREE_MSTR(base); + s = ch_table[ch]; + while (s && s!=ob) { + t = s; + s = s->next_ch_hash; + } + if (!s) + fatal("object not found in children list"); + if (!t) + ch_table[ch] = s->next_ch_hash; + else + t->next_ch_hash = s->next_ch_hash; + ob->next_ch_hash = 0; + return; +} + +/* + * Lookup an object in the hash table; if it isn't there, return null. + * This is only different to find_object_n in that it collects different + * stats; more finds are actually done than the user ever asks for. + */ + +static long user_obj_lookups = 0, user_obj_found = 0; + +object_t *lookup_object_hash(const char * s) { + object_t *ob = find_obj_n(s); + + user_obj_lookups++; + if (ob) + user_obj_found++; + return (ob); +} + +/* + * Print stats, returns the total size of the object table. All objects + * are in table, so their size is included as well. + */ + +static char sbuf[100]; + +int show_otable_status(outbuffer_t * out, int verbose) { + int starts; + + if (verbose == 1) { + outbuf_add(out, "Object name hash table status:\n"); + outbuf_add(out, "------------------------------\n"); + sprintf(sbuf, "%10.2f", objs_in_table / (float) OTABLE_SIZE); + outbuf_addv(out, "Average hash chain length: %s\n", sbuf); + sprintf(sbuf, "%10.2f", (float) obj_probes / obj_searches); + outbuf_addv(out, "Average search length: %s\n", sbuf); + outbuf_addv(out, "Internal lookups (succeeded): %lu (%lu)\n", + obj_searches - user_obj_lookups, objs_found - user_obj_found); + outbuf_addv(out, "External lookups (succeeded): %lu (%lu)\n", + user_obj_lookups, user_obj_found); + } + starts = (long) OTABLE_SIZE *sizeof(object_t *)+objs_in_table + * sizeof(object_t); + + if (!verbose) { + outbuf_addv(out, "Obj table overhead:\t\t%8d %8d\n", + OTABLE_SIZE * sizeof(object_t *), starts); + } + return starts; +} diff --git a/fluffos-2.23-ds03/otable.h b/fluffos-2.23-ds03/otable.h new file mode 100644 index 0000000..1ee79c3 --- /dev/null +++ b/fluffos-2.23-ds03/otable.h @@ -0,0 +1,17 @@ +#ifndef OTABLE_H +#define OTABLE_H + +#include "lpc_incl.h" + +/* + * otable.c + */ +void init_otable (void); +void enter_object_hash (object_t *); +void remove_object_hash (object_t *); +void remove_precompiled_hashes (char *); +object_t *lookup_object_hash (const char *); +int show_otable_status (outbuffer_t *, int); +array_t *find_ch_n (const char * s); + +#endif diff --git a/fluffos-2.23-ds03/packages/GNUmakefile.pre b/fluffos-2.23-ds03/packages/GNUmakefile.pre new file mode 100644 index 0000000..4d5340d --- /dev/null +++ b/fluffos-2.23-ds03/packages/GNUmakefile.pre @@ -0,0 +1,3 @@ +%define GNU + +%include "packages/Makefile.master" diff --git a/fluffos-2.23-ds03/packages/Makefile.master b/fluffos-2.23-ds03/packages/Makefile.master new file mode 100644 index 0000000..2828714 --- /dev/null +++ b/fluffos-2.23-ds03/packages/Makefile.master @@ -0,0 +1,27 @@ +%include "packages/packages" + +%ifdef GNU +OBJ=$(addprefix $(OBJDIR)/,$(subst .c,.o,$(SRC))) + +$(OBJDIR)/%.o: %.c + $(CC) -I$(OBJDIR) -I.. $(CFLAGS) -o $@ -c $< +%else +.c.$(O): + $(CC) $(CFLAGS) -I.. -c $*.c +%endif + +all: $(OBJ) + ar rcu packages.$(A) $(OBJ) + $(RANLIB) packages.$(A) + +%ifdef GNU +$(OBJDIR)/db.o: db.c + $(CC) -I$(OBJDIR) -I.. -I/usr/include/mysql $(CFLAGS) -o $@ -c $< +%else +db.$(O): db.c + $(CC) $(CFLAGS) -I.. -I/usr/include/mysql -c $*.c +%endif + +clean: + rm -f *.$(O) + rm -f packages.$(A) diff --git a/fluffos-2.23-ds03/packages/Makefile.pre b/fluffos-2.23-ds03/packages/Makefile.pre new file mode 100644 index 0000000..070cbe4 --- /dev/null +++ b/fluffos-2.23-ds03/packages/Makefile.pre @@ -0,0 +1,3 @@ +%define NORMAL + +%include "packages/Makefile.master" diff --git a/fluffos-2.23-ds03/packages/async.c b/fluffos-2.23-ds03/packages/async.c new file mode 100644 index 0000000..fb28441 --- /dev/null +++ b/fluffos-2.23-ds03/packages/async.c @@ -0,0 +1,593 @@ +#include "std.h" +#include "../lpc_incl.h" +#include "async.h" +#include "../function.h" +#include +#include +#include +#include +#ifdef F_ASYNC_GETDIR +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#endif +#include "../config.h" +#include "../interpret.h" +#include "../file.h" +#include "../function.h" +#include "../eval.h" +#ifdef F_ASYNC_DB_EXEC +#include "db.h" +#endif + +enum atypes { + aread, + awrite, + agetdir, + adbexec, + done +}; + +enum astates { + BUSY, + DONE, +}; + +struct request{ + char path[MAXPATHLEN]; + int flags; + int status; + int ret; + const char *buf; + int size; + function_to_call_t *fun; + struct request *next; + svalue_t tmp; + enum atypes type; +}; + +void add_req(struct request *req); + +#if defined(F_ASYNC_READ) || defined(F_ASYNC_WRITE) + +struct cb_mem{ + function_to_call_t cb; + struct cb_mem *next; +} *cbs = 0; + +struct req_mem{ + struct request req; + struct req_mem *next; +} *reqms; + +struct stuff{ + void *(*func)(struct request *); + struct request *data; + struct stuff *next; +} *todo, *lasttodo; + +struct stuff_mem{ + struct stuff stuff; + struct stuff_mem *next; +} *stuffs; + +pthread_mutex_t mem_mut; + + +struct stuff *get_stuff(){ + struct stuff *ret; + if(stuffs){ + pthread_mutex_lock(&mem_mut); + ret = &stuffs->stuff; + stuffs = stuffs->next; + ((struct stuff_mem *)ret)->next = 0; + pthread_mutex_unlock(&mem_mut); + }else{ + ret = (struct stuff *)MALLOC(sizeof(struct stuff_mem)); + ((struct stuff_mem *)ret)->next = 0; + } + return ret; +} + +void free_stuff(struct stuff *stuff){ + struct stuff_mem *stufft = (struct stuff_mem *)stuff; + pthread_mutex_lock(&mem_mut); + stufft->next = stuffs; + stuffs = stufft; + pthread_mutex_unlock(&mem_mut); +} + +pthread_mutex_t mut; +pthread_mutex_t work_mut; +int thread_started = 0; + +void *thread_func(void *mydata){ + while(1){ + pthread_mutex_lock(&mut); + while(todo){ + pthread_mutex_lock(&work_mut); + struct stuff *work = todo; + todo = todo->next; + if(!todo) + lasttodo = NULL; + pthread_mutex_unlock(&work_mut); + work->func(work->data); + free_stuff(work); + } + } +} + +void do_stuff(void *(*func)(struct request *), struct request *data){ + if(!thread_started){ + pthread_mutex_init(&mut, NULL); + pthread_mutex_init(&mem_mut, NULL); + pthread_mutex_init(&work_mut, NULL); + pthread_mutex_lock(&mut); + pthread_t t; + pthread_create(&t, NULL, &thread_func, NULL); + thread_started = 1; + } + struct stuff *work = get_stuff(); + work->func = func; + work->data = data; + work->next = NULL; + pthread_mutex_lock(&work_mut); + add_req(data); + if(lasttodo){ + lasttodo->next = work; + lasttodo = work; + } else { + todo = lasttodo = work; + } + pthread_mutex_unlock(&work_mut); + pthread_mutex_unlock(&mut); +} + +function_to_call_t *get_cb(){ + function_to_call_t *ret; + if(cbs){ + ret = &cbs->cb; + cbs = cbs->next; + ((struct cb_mem *)ret)->next = 0; + }else{ + ret = (function_to_call_t *)MALLOC(sizeof(struct cb_mem)); + ((struct cb_mem *)ret)->next = 0; + } + memset(ret, 0, sizeof(function_to_call_t)); + return ret; +} + +void free_cb(function_to_call_t *cb){ + struct cb_mem *cbt = (struct cb_mem *)cb; + cbt->next = cbs; + cbs = cbt; +} + +struct request *get_req(){ + struct request *ret; + if(reqms){ + ret = &reqms->req; + reqms = reqms->next; + ((struct req_mem *)ret)->next = 0; + }else{ + ret = (struct request *)MALLOC(sizeof(struct req_mem)); + ((struct req_mem *)ret)->next = 0; + } + return ret; +} + +void free_req(struct request *req){ + struct req_mem *reqt = (struct req_mem *)req; + reqt->next = reqms; + reqms = reqt; +} + + +static struct request *reqs = NULL; +static struct request *lastreq = NULL; +void add_req(struct request *req){ + if(lastreq){ + lastreq->next = req; + } else { + reqs = req; + } + req->next = NULL; + lastreq = req; +} + +#ifdef PACKAGE_COMPRESS +#include + +void *gzreadthread(struct request *req){ + void *file = gzopen(req->path, "rb"); + req->ret = gzread(file, (void *)(req->buf), req->size); + req->status = DONE; + gzclose(file); + return NULL; +} + +int aio_gzread(struct request *req){ + req->status = BUSY; + do_stuff(gzreadthread, req); + return 0; +} + +void *gzwritethread(struct request *req){ + int fd = open(req->path, req->flags & 1 ? O_CREAT|O_WRONLY|O_TRUNC + : O_CREAT|O_WRONLY|O_APPEND, S_IRWXU|S_IRWXG); + void *file = gzdopen(fd, "wb"); + req->ret = gzwrite(file, (void *)(req->buf), req->size); + req->status = DONE; + gzclose(file); + return NULL; +} + +int aio_gzwrite(struct request *req){ + req->status = BUSY; + do_stuff(gzwritethread, req); + return 0; +} +#endif + +void *writethread(struct request *req){ + int fd = open(req->path, req->flags & 1 ? O_CREAT|O_WRONLY|O_TRUNC + : O_CREAT|O_WRONLY|O_APPEND, S_IRWXU|S_IRWXG); + + req->ret = write(fd, req->buf, req->size); + + req->status = DONE; + close(fd); + return NULL; +} + +int aio_write(struct request *req){ + req->status = BUSY; + do_stuff(writethread, req); + return 0; +} + +void *readthread(struct request *req){ + int fd = open(req->path, O_RDONLY); + req->ret = read(fd, (void *)(req->buf), req->size); + req->status = DONE; + close(fd); + return NULL; +} + +int aio_read(struct request *req){ + req->status = BUSY; + do_stuff(readthread, req); + return 0; +} + +#ifdef F_ASYNC_DB_EXEC +pthread_mutex_t *db_mut = NULL; + +void *dbexecthread(struct request *req){ + pthread_mutex_lock(db_mut); + db_t *db = find_db_conn((int)req->buf); + int ret = -1; + if (db->type->execute) { + if (db->type->cleanup) { + db->type->cleanup(&(db->c)); + } + + ret = db->type->execute(&(db->c), req->tmp.u.string); + if (ret == -1){ + if(db->type->error) { + char *tmp; + strncpy(req->path, tmp = db->type->error(&(db->c)), MAXPATHLEN-1); + FREE_MSTR(tmp); + } else { + strcpy(req->path, "Unknown error"); + } + } + } else { + strcpy(req->path, "No database exec function!"); + } + pthread_mutex_unlock(db_mut); + + req->ret = ret; + req->status = DONE; + return NULL; +} + +int aio_db_exec(struct request *req){ + req->status = BUSY; + do_stuff(dbexecthread, req); + return 0; +} +#endif + +#ifdef F_ASYNC_GETDIR +void *getdirthread(struct request *req){ + int fd = open(req->path, O_RDONLY); + int size = syscall(SYS_getdents, fd, req->buf, req->size); + if(size == -1){ + close(fd); + req->ret = 0; + req->status = DONE; + return NULL; + } + req->ret = size; + while(size = syscall(SYS_getdents, fd, req->buf+req->ret, req->size-req->ret)){ + if(size == -1){ + close(fd); + req->status = DONE; + return NULL; + } + req->ret+=size; + } + req->status = DONE; + close(fd); + return NULL; +} + +int aio_getdir(struct request *req){ + req->status = BUSY; + do_stuff(getdirthread, req); + return 0; +} + +#endif + +int add_read(const char *fname, function_to_call_t *fun) { + if (fname) { + struct request *req = get_req(); + //printf("fname: %s\n", fname); + req->buf = (char *)MALLOC(READ_FILE_MAX_SIZE); + req->size = READ_FILE_MAX_SIZE; + req->fun = fun; + req->type = aread; + strcpy(req->path, fname); +#ifdef PACKAGE_COMPRESS + return aio_gzread(req); +#else + return aio_read(req); +#endif + }else + error("permission denied\n"); + return 1; +} + +#ifdef F_ASYNC_GETDIR +extern int max_array_size; +int add_getdir(const char *fname, function_to_call_t *fun) { + if (fname) { + //printf("fname: %s\n", fname); + struct request *req = get_req(); + req->buf = (char *)MALLOC(sizeof(struct dirent) * max_array_size); + req->size = sizeof(struct dirent) * max_array_size; + req->fun = fun; + req->type = agetdir; + strcpy(req->path, fname); + return aio_getdir(req); + }else + error("permission denied\n"); + return 1; +} +#endif + +int add_write(const char *fname, const char *buf, int size, char flags, function_to_call_t *fun) { + if (fname) { + struct request *req = get_req(); + req->buf = buf; + req->size = size; + req->fun = fun; + req->type = awrite; + req->flags = flags; + strcpy(req->path, fname); + assign_svalue_no_free(&req->tmp, sp-2); +#ifdef PACKAGE_COMPRESS + if(flags & 2) + return aio_gzwrite(req); + else +#endif + return aio_write(req); + } else + error("permission denied\n"); + return 1; +} + +#ifdef F_ASYNC_DB_EXEC +int add_db_exec(int handle, function_to_call_t *fun) { + struct request *req = get_req(); + req->fun = fun; + req->type = adbexec; + req->buf = (char *)handle; + assign_svalue_no_free(&req->tmp, sp-1); + return aio_db_exec(req); +} +#endif + + +void handle_read(struct request *req){ + int val = req->ret; + if(val < 0){ + FREE((void *)req->buf); + push_number(val); + set_eval(max_cost); + safe_call_efun_callback(req->fun, 1); + return; + } + char *file = new_string(val, "read_file_async: str"); + memcpy(file, (char *)(req->buf), val); + file[val]=0; + push_malloced_string(file); + FREE((void *)req->buf); + set_eval(max_cost); + safe_call_efun_callback(req->fun, 1); +} + +#ifdef F_ASYNC_GETDIR + +struct linux_dirent { + unsigned long d_ino; /* Inode number */ + unsigned long d_off; /* Offset to next dirent */ + unsigned short d_reclen; /* Length of this dirent */ + char d_name []; /* Filename (null-terminated) */ + /* length is actually (d_reclen - 2 - + offsetof(struct linux_dirent, d_name) */ +}; + + +void handle_getdir(struct request *req){ + int val = req->ret; + if(val>MAX_ARRAY_SIZE) + val = MAX_ARRAY_SIZE; + array_t *ret = allocate_empty_array(val); + int i=0; + if(val > 0) + { + struct linux_dirent *de = (struct linux_dirent *)req->buf; + for(i=0; ibuf) < val; i++) + { + svalue_t *vp = &(ret->item[i]); + vp->type = T_STRING; + vp->subtype = STRING_MALLOC; + vp->u.string = string_copy(de->d_name, "encode_stat"); + de = (struct linux_dirent *)(((char *)de) + de->d_reclen); + } + } + ret = resize_array(ret, i); + ret->size = i; + push_refed_array(ret); + FREE((void *)req->buf); + set_eval(max_cost); + safe_call_efun_callback(req->fun, 1); +} +#endif + + +void handle_write(struct request *req){ + free_svalue(&req->tmp, "handle_write"); + int val = req->ret; + if(val < 0){ + push_number(val); + set_eval(max_cost); + safe_call_efun_callback(req->fun, 1); + return; + } + push_undefined(); + set_eval(max_cost); + safe_call_efun_callback(req->fun, 1); +} + +void handle_db_exec(struct request *req){ + free_svalue(&req->tmp, "handle_db_exec"); + int val = req->ret; + if(val == -1){ + copy_and_push_string(req->path); + } + else + push_number(val); + set_eval(max_cost); + safe_call_efun_callback(req->fun, 1); +} + +void check_reqs() { + while (reqs) { + int val = reqs->status; + if (val != BUSY) { + enum atypes type = (reqs->type); + reqs->type = done; + switch (type) { + case aread: + handle_read(reqs); + break; + case awrite: + handle_write(reqs); + break; +#ifdef F_ASYNC_GETDIR + case agetdir: + handle_getdir(reqs); + break; +#endif +#ifdef F_ASYNC_DB_EXEC + case adbexec: + handle_db_exec(reqs); + break; +#endif + case done: + //must have had an error while handling it before. + break; + default: + fatal("unknown async type\n"); + } + struct request *here = reqs; + reqs = reqs->next; + if(!reqs) + lastreq = reqs; + free_funp(here->fun->f.fp); + free_cb(here->fun); + free_req(here); + } else + return; + } +} + +void complete_all_asyncio(){ + while(reqs) + check_reqs(); +} + +#ifdef F_ASYNC_READ + +void f_async_read(){ + function_to_call_t *cb = get_cb(); + process_efun_callback(1, cb, F_ASYNC_READ); + cb->f.fp->hdr.ref++; + add_read(check_valid_path((sp-1)->u.string, current_object, "read_file", 0), cb); + pop_2_elems(); +} +#endif + +#ifdef F_ASYNC_WRITE +void f_async_write(){ + function_to_call_t *cb = get_cb(); + process_efun_callback(3, cb, F_ASYNC_WRITE); + cb->f.fp->hdr.ref++; + add_write(check_valid_path((sp-3)->u.string, current_object, "write_file", 1), (sp-2)->u.string, strlen((sp-2)->u.string), (sp-1)->u.number, cb); + pop_n_elems(4); +} +#endif + +#ifdef F_ASYNC_GETDIR +void f_async_getdir(){ + function_to_call_t *cb = get_cb(); + process_efun_callback(1, cb, F_ASYNC_READ); + cb->f.fp->hdr.ref++; + add_getdir(check_valid_path((sp-1)->u.string, current_object, "get_dir", 0), cb); + pop_2_elems(); +} +#endif +#ifdef F_ASYNC_DB_EXEC +void f_async_db_exec(){ + array_t *info; + db_t *db; + info = allocate_empty_array(1); + info->item[0].type = T_STRING; + info->item[0].subtype = STRING_MALLOC; + info->item[0].u.string = string_copy((sp-1)->u.string, "f_db_exec"); + int num_arg = st_num_arg; + valid_database("exec", info); + + db = find_db_conn((sp-2)->u.number); + if (!db) { + error("Attempt to exec on an invalid database handle\n"); + } + if(!db_mut){ + db_mut = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t)); + pthread_mutex_init(db_mut, NULL); + } + st_num_arg = num_arg; + function_to_call_t *cb = get_cb(); + process_efun_callback(2, cb, F_ASYNC_DB_EXEC); + cb->f.fp->hdr.ref++; + + add_db_exec((sp-2)->u.number, cb); + pop_3_elems(); +} +#endif +#endif diff --git a/fluffos-2.23-ds03/packages/async.h b/fluffos-2.23-ds03/packages/async.h new file mode 100644 index 0000000..7c83a7b --- /dev/null +++ b/fluffos-2.23-ds03/packages/async.h @@ -0,0 +1,6 @@ +#ifndef ASYNC_H_ +#define ASYNC_H_ + +void check_reqs(); +void complete_all_asyncio(); +#endif /*ASYNC_H_*/ diff --git a/fluffos-2.23-ds03/packages/async_spec.c b/fluffos-2.23-ds03/packages/async_spec.c new file mode 100644 index 0000000..ab6c1da --- /dev/null +++ b/fluffos-2.23-ds03/packages/async_spec.c @@ -0,0 +1,10 @@ +#include "spec.h" + +void async_read(string, function); +void async_write(string, string, int, function); +#ifdef linux +void async_getdir(string, function); +#endif +#ifdef PACKAGE_DB +void async_db_exec(int, string, function); +#endif diff --git a/fluffos-2.23-ds03/packages/compress.c b/fluffos-2.23-ds03/packages/compress.c new file mode 100644 index 0000000..e23020b --- /dev/null +++ b/fluffos-2.23-ds03/packages/compress.c @@ -0,0 +1,327 @@ +/* Compression efun stuff. + * Started Wed Mar 21 01:52:25 PST 2001 + * by David Bennett (ddt@discworld.imaginary.com) + */ + +#ifdef LATTICE +#include "/lpc_incl.h" +#include "/file_incl.h" +#include "/file.h" +#else +#include "../lpc_incl.h" +#include "../file_incl.h" +#include "../file.h" +#endif + +#include + +#define GZ_EXTENSION ".gz" + +#define COMPRESS_BUF_SIZE 8096 + +#ifdef F_COMPRESS_FILE +void f_compress_file (void) +{ + int readb; + int len; + int num_arg = st_num_arg; + const char* input_file; + const char* output_file; + const char* real_input_file; + const char* real_output_file; + char* tmpout; + gzFile out_file; + FILE* in_file; + char buf[4096]; + char outname[1024]; + + // Not a string? Error! + if ((sp - num_arg + 1)->type != T_STRING) { + pop_n_elems(num_arg); + push_number(0); + return ; + } + + input_file = (sp - num_arg + 1)->u.string; + if (num_arg == 2) { + if (((sp - num_arg + 2)->type != T_STRING)) { + pop_n_elems(num_arg); + push_number(0); + return ; + } + output_file = (sp - num_arg + 2)->u.string; + } else { + len = strlen(input_file); + if (!strcmp(input_file + len - strlen(GZ_EXTENSION), GZ_EXTENSION)) { + // Already compressed... + pop_n_elems(num_arg); + push_number(0); + return ; + } + tmpout = new_string(strlen(input_file) + strlen(GZ_EXTENSION), + "compress_file"); + strcpy(tmpout, input_file); + strcat(tmpout, GZ_EXTENSION); + output_file = tmpout; + } + + real_output_file = check_valid_path(output_file, current_object, "compress_file", 1); + if (!real_output_file) { + pop_n_elems(num_arg); + push_number(0); + return ; + } + // Copy it into our little buffer. + strcpy(outname, real_output_file); + // Free the old file. + if (num_arg != 2) { + FREE_MSTR(output_file); + } + output_file = outname; + + real_input_file = check_valid_path(input_file, current_object, "compress_file", 0); + if (!real_input_file) { + pop_n_elems(num_arg); + push_number(0); + return ; + } + + in_file = fopen(real_input_file, "rb"); + if (!in_file) { + pop_n_elems(num_arg); + push_number(0); + return ; + } + + out_file = gzopen(output_file, "wb"); + if (!out_file) { + fclose(in_file); + pop_n_elems(num_arg); + push_number(0); + return ; + } + + do { + readb = fread(buf, 1, 4096, in_file); + gzwrite(out_file, buf, readb); + } while (readb == 4096); + fclose(in_file); + gzclose(out_file); + + unlink(real_input_file); + + pop_n_elems(num_arg); + push_number(1); +} +#endif + +#ifdef F_UNCOMPRESS_FILE +void f_uncompress_file (void) +{ + int readb; + int len; + int num_arg = st_num_arg; + const char* input_file; + const char* output_file; + const char* real_input_file; + const char* real_output_file; + FILE* out_file; + gzFile in_file; + char buf[4196]; + char outname[1024]; + + // Not a string? Error! + if ((sp - num_arg + 1)->type != T_STRING) { + pop_n_elems(num_arg); + push_number(0); + return ; + } + + input_file = (sp - num_arg + 1)->u.string; + if (num_arg == 2) { + if (((sp - num_arg + 2)->type != T_STRING)) { + pop_n_elems(num_arg); + push_number(0); + return ; + } + output_file = (sp - num_arg + 2)->u.string; + } else { + char *tmp; + len = strlen(input_file); + if (strcmp(input_file + len - strlen(GZ_EXTENSION), GZ_EXTENSION)) { + // Not compressed... + pop_n_elems(num_arg); + push_number(0); + return ; + } + tmp = new_string(len, "compress_file"); + strcpy(tmp, input_file); + tmp[len - strlen(GZ_EXTENSION)] = 0; + output_file = tmp; + } + + real_output_file = check_valid_path(output_file, current_object, "compress_file", 1); + if (!real_output_file) { + if (num_arg != 2) { + FREE_MSTR(output_file); + } + + pop_n_elems(num_arg); + push_number(0); + return ; + } + // Copy it into our little buffer. + strcpy(outname, real_output_file); + if (num_arg != 2) { + FREE_MSTR(output_file); + } + output_file = outname; + + real_input_file = check_valid_path(input_file, current_object, "compress_file", 0); + if (!real_input_file) { + pop_n_elems(num_arg); + push_number(0); + return ; + } + + in_file = gzopen(real_input_file, "rb"); + if (!in_file) { + gzclose(in_file); + pop_n_elems(num_arg); + push_number(0); + return ; + } + + out_file = fopen(output_file, "wb"); + if (!out_file) { + fclose(out_file); + pop_n_elems(num_arg); + push_number(0); + return ; + } + + do { + readb = gzread(in_file, buf, 4096); + fwrite(buf, 1, readb, out_file); + } while (readb == 4096); + gzclose(in_file); + fclose(out_file); + + unlink(real_input_file); + + pop_n_elems(num_arg); + push_number(1); +} +#endif + +#ifdef F_COMPRESS +void f_compress (void) +{ + unsigned char* buffer; + unsigned char* input; + int size; + buffer_t* real_buffer; + uLongf new_size; + + if (sp->type == T_STRING) { + size = SVALUE_STRLEN(sp); + input = (unsigned char*)sp->u.string; + } else if (sp->type == T_BUFFER) { + size = sp->u.buf->size; + input = sp->u.buf->item; + } else { + pop_n_elems(st_num_arg); + push_undefined(); + return ; + } + + new_size = compressBound(size); + // Make it a little larger as specified in the docs. + buffer = (unsigned char*)DXALLOC(new_size, TAG_TEMPORARY, "compress"); + compress(buffer, &new_size, input, size); + + // Shrink it down. + pop_n_elems(st_num_arg); + real_buffer = allocate_buffer(new_size); + write_buffer(real_buffer, 0, (char *)buffer, new_size); + FREE(buffer); + push_buffer(real_buffer); +} +#endif + +#ifdef F_UNCOMPRESS +static void* zlib_alloc(void* opaque, unsigned int items, unsigned int size) { + return CALLOC(items, size); +} + +static void zlib_free(void* opaque, void* address) { + FREE(address); +} + +void f_uncompress (void) +{ + z_stream* compressed; + unsigned char compress_buf[COMPRESS_BUF_SIZE]; + unsigned char* output_data = NULL; + int len; + int pos; + buffer_t* buffer; + int ret; + + if (sp->type == T_BUFFER) { + buffer = sp->u.buf; + } else { + pop_n_elems(st_num_arg); + push_undefined(); + return ; + } + + compressed = (z_stream *) + DXALLOC(sizeof(z_stream), TAG_INTERACTIVE, + "start_compression"); + compressed->next_in = buffer->item; + compressed->avail_in = buffer->size; + compressed->next_out = compress_buf; + compressed->avail_out = COMPRESS_BUF_SIZE; + compressed->zalloc = zlib_alloc; + compressed->zfree = zlib_free; + compressed->opaque = NULL; + + if (inflateInit(compressed) != Z_OK) { + FREE(compressed); + pop_n_elems(st_num_arg); + error("inflateInit failed"); + } + + len = 0; + output_data = NULL; + do { + ret = inflate(compressed, 0); + if (ret == Z_OK || ret == Z_STREAM_END) { + pos = len; + len += COMPRESS_BUF_SIZE - compressed->avail_out; + if (!output_data) { + output_data = (unsigned char*)DXALLOC(len, TAG_TEMPORARY, "uncompress"); + } else { + output_data = (unsigned char *)REALLOC(output_data, len); + } + memcpy(output_data + pos, compress_buf, len - pos); + compressed->next_out = compress_buf; + compressed->avail_out = COMPRESS_BUF_SIZE; + } + } while (ret == Z_OK); + + inflateEnd(compressed); + + pop_n_elems(st_num_arg); + + if (ret == Z_STREAM_END) { + buffer = allocate_buffer(len); + write_buffer(buffer, 0, (char *)output_data, len); + FREE(output_data); + push_buffer(buffer); + } else { + error("inflate: no ZSTREAM_END\n"); + } +} +#endif diff --git a/fluffos-2.23-ds03/packages/compress_spec.c b/fluffos-2.23-ds03/packages/compress_spec.c new file mode 100644 index 0000000..d5c1504 --- /dev/null +++ b/fluffos-2.23-ds03/packages/compress_spec.c @@ -0,0 +1,10 @@ +/* Compression efun specifications. + * Started Wed Mar 21 01:52:25 PST 2001 + * by David Bennett (ddt@discworld.imaginary.com) + */ + +int compress_file(string, string|void); +int uncompress_file(string, string|void); + +buffer compress(string|buffer); +buffer uncompress(string|buffer); diff --git a/fluffos-2.23-ds03/packages/contrib.c b/fluffos-2.23-ds03/packages/contrib.c new file mode 100644 index 0000000..fc42ad4 --- /dev/null +++ b/fluffos-2.23-ds03/packages/contrib.c @@ -0,0 +1,2939 @@ +#define SUPPRESS_COMPILER_INLINES +#include "../lpc_incl.h" +#include "../comm.h" +#include "../file_incl.h" +#include "../file.h" +#include "../backend.h" +#include "../compiler.h" +#include "../main.h" +#include "../eoperators.h" +#include "../efun_protos.h" +#include "../simul_efun.h" +#include "../add_action.h" +#include "../port.h" +#include "../applies.h" +#define MAX_COLOUR_STRING 200 + +/* should be done in configure */ +#ifdef WIN32 +#define strcasecmp(X, Y) stricmp(X, Y) +#endif + +#ifdef F_REAL_TIME +void +f_real_time (void) +{ + push_number(time(NULL)); +} +#endif + +#ifdef F_COMPRESSEDP +void f_compressedp (void) +{ + int i; + + i = sp->u.ob->interactive && sp->u.ob->interactive->compressed_stream; + free_object(&sp->u.ob, "f_compressedp"); + put_number(i != 0); +} +#endif + +/* + * This differs from the livings() efun in that this efun only returns + * objects which have had set_living_name() called as well as + * enable_commands(). The other major difference is that this is + * substantially faster. + */ +#ifdef F_NAMED_LIVINGS +void f_named_livings() { + int i; + int nob; +#ifdef F_SET_HIDE + int apply_valid_hide, display_hidden = 0; +#endif + object_t *ob, **obtab; + array_t *vec; + + nob = 0; +#ifdef F_SET_HIDE + apply_valid_hide = 1; +#endif + + obtab = CALLOCATE(max_array_size, object_t *, TAG_TEMPORARY, "named_livings"); + + for (i = 0; i < CFG_LIVING_HASH_SIZE; i++) { + for (ob = hashed_living[i]; ob; ob = ob->next_hashed_living) { + if (!(ob->flags & O_ENABLE_COMMANDS)) + continue; +#ifdef F_SET_HIDE + if (ob->flags & O_HIDDEN) { + if (apply_valid_hide) { + apply_valid_hide = 0; + display_hidden = valid_hide(current_object); + } + if (!display_hidden) + continue; + } +#endif +if (nob == max_array_size) + break; +obtab[nob++] = ob; + } + } + + vec = allocate_empty_array(nob); + while (--nob >= 0) { + vec->item[nob].type = T_OBJECT; + vec->item[nob].u.ob = obtab[nob]; + add_ref(obtab[nob], "livings"); + } + + FREE(obtab); + + push_refed_array(vec); +} +#endif + +/* I forgot who wrote this, please claim it :) */ +#ifdef F_REMOVE_SHADOW +void +f_remove_shadow (void) +{ + object_t *ob; + + ob = current_object; + if (st_num_arg) { + ob = sp->u.ob; + pop_stack(); + } + if (ob == 0 || (ob->shadowing == 0 && ob->shadowed == 0)) + push_number(0); + else { + if (ob->shadowed) + ob->shadowed->shadowing = ob->shadowing; + if (ob->shadowing) + ob->shadowing->shadowed = ob->shadowed; + ob->shadowing = ob->shadowed = 0; + push_number(1); + } +} +#endif + +/* This was originally written my Malic for Demon. I rewrote parts of it + when I added it (added function support, etc) -Beek */ +#ifdef F_QUERY_NOTIFY_FAIL +void +f_query_notify_fail (void) { + char *p; + + if (command_giver && command_giver->interactive) { + if (command_giver->interactive->iflags & NOTIFY_FAIL_FUNC) { + push_funp(command_giver->interactive->default_err_message.f); + return; + } else if ((p = command_giver->interactive->default_err_message.s)) { + STACK_INC; + sp->type = T_STRING; + sp->subtype = STRING_SHARED; + sp->u.string = p; + ref_string(p); + return; + } + } + push_number(0); +} +#endif + +/* Beek again */ +#ifdef F_STORE_VARIABLE +void +f_store_variable (void) { + int idx; + svalue_t *sv; + unsigned short type; + + idx = find_global_variable(current_object->prog, (sp-1)->u.string, &type, 0); + if (idx == -1) + error("No variable named '%s'!\n", (sp-1)->u.string); + sv = ¤t_object->variables[idx]; + free_svalue(sv, "f_store_variable"); + *sv = *sp--; + free_string_svalue(sp--); +} +#endif + +#ifdef F_FETCH_VARIABLE +void +f_fetch_variable (void) { + int idx; + svalue_t *sv; + unsigned short type; + + idx = find_global_variable(current_object->prog, sp->u.string, &type, 0); + if (idx == -1) + error("No variable named '%s'!\n", sp->u.string); + sv = ¤t_object->variables[idx]; + free_string_svalue(sp--); + push_svalue(sv); +} +#endif + +/* Beek */ +#ifdef F_SET_PROMPT +void +f_set_prompt (void) { + object_t *who; + if (st_num_arg == 2) { + who = sp->u.ob; + pop_stack(); + } else who = command_giver; + + if (!who || who->flags & O_DESTRUCTED || !who->interactive) + error("Prompts can only be set for interactives.\n"); + + /* Future work */ + /* ed() will nuke this; also we have to make sure the string will get + * freed */ +} +#endif + +/* Gudu@VR wrote copy_array() and copy_mapping() which this is heavily + * based on. I made it into a general copy() efun which incorporates + * both. -Beek + */ +#ifdef F_COPY +static int depth; + +static void deep_copy_svalue (svalue_t *, svalue_t *); + +static array_t *deep_copy_array ( array_t * arg ) { + array_t *vec; + int i; + + vec = allocate_empty_array(arg->size); + for (i = 0; i < arg->size; i++) + deep_copy_svalue(&arg->item[i], &vec->item[i]); + + return vec; +} + +static array_t *deep_copy_class (array_t * arg) { + array_t *vec; + int i; + + vec = allocate_empty_class_by_size(arg->size); + for (i = 0; i < arg->size; i++) + deep_copy_svalue(&arg->item[i], &vec->item[i]); + + return vec; +} + +static int doCopy ( mapping_t * map, mapping_node_t * elt, void *dest) { + svalue_t *sv; + + sv = find_for_insert((mapping_t *)dest, &elt->values[0], 1); + if (!sv) { + mapping_too_large(); + return 1; + } + + deep_copy_svalue(&elt->values[1], sv); + return 0; +} + +static mapping_t *deep_copy_mapping ( mapping_t * arg ) { + mapping_t *map; + + map = allocate_mapping( 0 ); /* this should be fixed. -Beek */ + mapTraverse( arg, doCopy, map); /* Not horridly efficient either */ + return map; +} + +static void deep_copy_svalue (svalue_t * from, svalue_t * to) { + switch (from->type) { + case T_ARRAY: + depth++; + if (depth > MAX_SAVE_SVALUE_DEPTH) { + depth = 0; + error("Mappings, arrays and/or classes nested too deep (%d) for copy()\n", + MAX_SAVE_SVALUE_DEPTH); + } + *to = *from; + to->u.arr = deep_copy_array( from->u.arr ); + depth--; + break; + case T_CLASS: + depth++; + if (depth > MAX_SAVE_SVALUE_DEPTH) { + depth = 0; + error("Mappings, arrays and/or classes nested too deep (%d) for copy()\n", + MAX_SAVE_SVALUE_DEPTH); + } + *to = *from; + to->u.arr = deep_copy_class( from->u.arr ); + depth--; + break; + case T_MAPPING: + depth++; + if (depth > MAX_SAVE_SVALUE_DEPTH) { + depth = 0; + error("Mappings, arrays and/or classes nested too deep (%d) for copy()\n", + MAX_SAVE_SVALUE_DEPTH); + } + *to = *from; + to->u.map = deep_copy_mapping( from->u.map ); + depth--; + break; +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + *to = *from; + to->u.buf = allocate_buffer(from->u.buf->size); + memcpy(to->u.buf->item, from->u.buf->item, from->u.buf->size); + break; +#endif + default: + assign_svalue_no_free( to, from ); + } +} + +void f_copy (void) +{ + svalue_t ret; + + depth = 0; + deep_copy_svalue(sp, &ret); + free_svalue(sp, "f_copy"); + *sp = ret; +} +#endif + +/* Gudu@VR */ +/* flag and extra info by Beek */ +#ifdef F_FUNCTIONS +void f_functions (void) { + int i, j, num, ind; + array_t *vec, *subvec; + function_t *funp; + program_t *prog; + int flag = (sp--)->u.number; + unsigned short *types; + char buf[256]; + char *end = EndOf(buf); + program_t *progp = sp->u.ob->prog; + int offset = (flag&2)?progp->last_inherited:0; + + num = (flag&2)?progp->num_functions_defined:progp->num_functions_defined + progp->last_inherited; + + if (progp->num_functions_defined && + progp->function_table[progp->num_functions_defined-1].funcname[0] + == APPLY___INIT_SPECIAL_CHAR) + num--; + + vec = allocate_empty_array(num); + i = num; + + while (i--) { + unsigned short low, high, mid; + + prog = sp->u.ob->prog; + ind = i+offset; + + /* Walk up the inheritance tree to the real definition */ + if (prog->function_flags[ind] & FUNC_ALIAS) { + ind = prog->function_flags[ind] & ~FUNC_ALIAS; + } + + while (prog->function_flags[ind] & FUNC_INHERITED) { + low = 0; + high = prog->num_inherited -1; + + while (high > low) { + mid = (low + high + 1) >> 1; + if (prog->inherit[mid].function_index_offset > ind) + high = mid -1; + else low = mid; + } + ind -= prog->inherit[low].function_index_offset; + prog = prog->inherit[low].prog; + } + + ind -= prog->last_inherited; + + funp = prog->function_table + ind; + + if (flag&1) { + if (prog->type_start && prog->type_start[ind] != INDEX_START_NONE) + types = &prog->argument_types[prog->type_start[ind]]; + else + types = 0; + + vec->item[i].type = T_ARRAY; + subvec = vec->item[i].u.arr = allocate_empty_array(3 + funp->num_arg); + + subvec->item[0].type = T_STRING; + subvec->item[0].subtype = STRING_SHARED; + subvec->item[0].u.string = make_shared_string(funp->funcname); + + subvec->item[1].type = T_NUMBER; + subvec->item[1].subtype = 0; + subvec->item[1].u.number = funp->num_arg; + + get_type_name(buf, end, funp->type); + subvec->item[2].type = T_STRING; + subvec->item[2].subtype = STRING_SHARED; + subvec->item[2].u.string = make_shared_string(buf); + + for (j = 0; j < funp->num_arg; j++) { + if (types) { + get_type_name(buf, end, types[j]); + subvec->item[3 + j].type = T_STRING; + subvec->item[3 + j].subtype = STRING_SHARED; + subvec->item[3 + j].u.string = make_shared_string(buf); + } else { + subvec->item[3 + j].type = T_NUMBER; + subvec->item[3 + j].u.number = 0; + } + } + } else { + vec->item[i].type = T_STRING; + vec->item[i].subtype = STRING_SHARED; + vec->item[i].u.string = make_shared_string(funp->funcname); + } + } + + pop_stack(); + push_refed_array(vec); +} +#endif + +/* Beek */ +#ifdef F_VARIABLES +static void fv_recurse (array_t * arr, int * idx, program_t * prog, int type, int flag) { + int i; + array_t *subarr; + char buf[256]; + char *end = EndOf(buf); + + for (i = 0; i < prog->num_inherited; i++) { + fv_recurse(arr, idx, prog->inherit[i].prog, + type | prog->inherit[i].type_mod, flag); + } + for (i = 0; i < prog->num_variables_defined; i++) { + if (flag) { + arr->item[*idx + i].type = T_ARRAY; + subarr = arr->item[*idx + i].u.arr = allocate_empty_array(2); + subarr->item[0].type = T_STRING; + subarr->item[0].subtype = STRING_SHARED; + subarr->item[0].u.string = ref_string(prog->variable_table[i]); + get_type_name(buf, end, prog->variable_types[i]); + subarr->item[1].type = T_STRING; + subarr->item[1].subtype = STRING_SHARED; + subarr->item[1].u.string = make_shared_string(buf); + } else { + arr->item[*idx + i].type = T_STRING; + arr->item[*idx + i].subtype = STRING_SHARED; + arr->item[*idx + i].u.string = ref_string(prog->variable_table[i]); + } + } + *idx += prog->num_variables_defined; +} + +void f_variables (void) { + int idx = 0; + array_t *arr; + int flag = (sp--)->u.number; + program_t *prog = sp->u.ob->prog; + + arr = allocate_empty_array(prog->num_variables_total); + fv_recurse(arr, &idx, prog, 0, flag); + + pop_stack(); + push_refed_array(arr); +} +#endif + +/* also Beek */ +#ifdef F_HEART_BEATS +void f_heart_beats (void) { + push_refed_array(get_heart_beats()); +} +#endif + +/*Aleas@Nightmare */ +#ifdef F_TERMINAL_COLOUR +/* A fast implementation of the Nightmare color support. + + [Ed note: These codes were actually used on Discworld + before Nightmare] + + Rewritten several times, since Beek wants it to be + perfect :) + + Takes a string and a mapping as args. The string is + exploded using "%^" as delimiter, then all keys of + the mapping found in the resulting array are replaced + by their values. Afterwards a string imploded from + the array is returned. + + No actual string copying is done except for the + creation of the final string and a temporary copy of + the input string to avoid destruction of shared + input strings. An array of pointers to the segments + of the string is compared against the mapping keys + and replaced with a pointer to the value belonging to + that key where matches are found. + + After the replacement pass the result string is created + from the pointer array. + + Further speed is gained by the fact that no parsing is + done if the input string does not contain any "%^" + delimiter sequence. + + by Aleas@Nightmare, dec-94 */ + +/* number of input string segments, if more, it still works, but a + _slow_ realloc is required */ +#define NSTRSEGS 32 +#define TC_FIRST_CHAR '%' +#define TC_SECOND_CHAR '^' + +static int at_end(int i, int imax, int z, int *lens) { + if (z + 1 != lens[i]) + return 0; + for (i++; i < imax; i++) { + if (lens[i] > 0) + return 0; + } + return 1; +} + +void +f_terminal_colour (void) +{ + const char *instr, *cp, **parts; + char *savestr, *deststr, *ncp; + char curcolour[MAX_COLOUR_STRING]; + char colouratstartword[MAX_COLOUR_STRING]; + int curcolourlen; + int colourstartlen=0; + const char *resetstr = 0; + char *resetstrname; + int resetstrlen = 0; + int num, i, j, k, col, start, space, *lens, maybe_at_end; + int space_garbage = 0; + mapping_node_t *elt, **mtab; + int buflen, max_buflen, space_buflen; + int wrap = 0; + int indent = 0; + int fillout = 0; + + if (st_num_arg >= 3) { + if (st_num_arg == 4) + indent = (sp--)->u.number; + wrap = (sp--)->u.number; + if (wrap < 0) { + wrap = -wrap; + fillout = 1; + } + if (wrap < 2 && wrap != 0) wrap = 2; + if (indent < 0 || indent >= wrap - 1) + indent = wrap - 2; + } + + cp = instr = (sp-1)->u.string; + do { + cp = strchr(cp, TC_FIRST_CHAR); + if (cp) + { + if (cp[1] == TC_SECOND_CHAR) + { + savestr = string_copy(instr, "f_terminal_colour"); + cp = savestr + ( cp - instr ); + instr = savestr; + break; + } + cp++; + } + } while (cp); + if (cp == NULL) { + if (wrap) { + num = 1; + parts = (const char **)CALLOCATE(1, char *, TAG_TEMPORARY, "f_terminal_colour: parts"); + parts[0] = instr; + savestr = 0; + } else { + pop_stack(); /* no delimiter in string, so return the original */ + return; + } + } else { + /* here we have something to parse */ + char *newstr = (char *) cp; //must be result of the string_copy above + parts = (const char **) CALLOCATE(NSTRSEGS, char *, TAG_TEMPORARY, "f_terminal_colour: parts"); + if (newstr - instr) { /* starting seg, if not delimiter */ + num = 1; + parts[0] = instr; + *newstr = 0; + } else + num = 0; + // Search through for the %^...%^ combinations + while (newstr) { + newstr += 2; + instr = newstr; + do { + newstr = strchr(newstr,TC_FIRST_CHAR); + if (newstr) { + if (newstr[1] == TC_SECOND_CHAR) + break; + newstr++; + } + } while (newstr); + // Check and make sure we have an end marker. + if (newstr) { + *newstr = 0; + // %^ at start of the text + if (newstr > instr) { + if (num && num % NSTRSEGS == 0) { + // Increase the size of the parts array. + parts = (const char **) RESIZE(parts, num + NSTRSEGS, char *, + TAG_TEMPORARY, "f_terminal_colour: parts realloc"); + } + // Put it in at the current location in the parts array. + parts[num++] = instr; + } + } + } + if (*instr) { /* trailing seg, if not delimiter */ + if (num && num % NSTRSEGS == 0) { + // Increase the size of the parts array. + parts = (const char **) RESIZE(parts, num + NSTRSEGS, char *, + TAG_TEMPORARY, "f_terminal_colour: parts realloc"); + } + // Put it in at the current location in the parts array. + parts[num++] = instr; + } + } + + if (num == 0) { + /* string consists entirely of %^'s */ + FREE(parts); + if (savestr) + FREE_MSTR(savestr); + pop_stack(); + free_string_svalue(sp); + sp->type = T_STRING; + sp->subtype = STRING_CONSTANT; + sp->u.string = ""; + return; + } + + /* Could keep track of the lens as we create parts, removing the need + for a strlen() below */ + lens = CALLOCATE(num, int, TAG_TEMPORARY, "f_terminal_colour: lens"); + mtab = sp->u.map->table; + + // First setup some little things. + curcolour[0] = 0; + curcolourlen = 0; + + // Find the reset colour string. + resetstrname = findstring("RESET"); + k = sp->u.map->table_size; + if (resetstrname) { + int tmp; + static svalue_t str = {T_STRING, STRING_SHARED}; + str.u.string = resetstrname; + tmp = MAP_SVAL_HASH(str); + for (elt = mtab[tmp & k]; elt; elt = elt->next) { + if ( elt->values->type == T_STRING && + (elt->values + 1)->type == T_STRING && + resetstrname == elt->values->u.string) { + resetstr = (elt->values + 1)->u.string; + resetstrlen = strlen((elt->values + 1)->u.string); + break; + } + } + } + + if(!resetstrlen) { + //we really really need one, so just default to ansi reset + resetstr = "\e[49;49m\e[0;10m"; + resetstrlen = 15; + add_mapping_string(sp->u.map, "RESET", resetstr); + } + + /* Do the the pointer replacement and calculate the lengths */ + col = 0; + start = -1; + space = 0; + maybe_at_end = 0; + buflen = max_buflen = space_buflen = 0; + for (j = i = 0, k = sp->u.map->table_size; i < num; i++) { + // Look it up in the mapping. + copy_and_push_string(parts[i]); + svalue_t *tmp = apply(APPLY_TERMINAL_COLOUR_REPLACE, current_object, 1, ORIGIN_EFUN); + if(tmp && tmp->type == T_STRING){ + parts[i] = alloca(SVALUE_STRLEN(tmp)+1); + strcpy(parts[i], tmp->u.string); + } + + if ((cp = findstring(parts[i]))) { + int tmp; + static svalue_t str = {T_STRING, STRING_SHARED}; + str.u.string = cp; + tmp = MAP_SVAL_HASH(str); + for (elt = mtab[tmp & k]; elt; elt = elt->next) { + if ( elt->values->type == T_STRING && + (elt->values + 1)->type == T_STRING && + cp == elt->values->u.string) { + parts[i] = (elt->values + 1)->u.string; + /* Negative indicates don't count for wrapping */ + lens[i] = SVALUE_STRLEN(elt->values + 1); + if (wrap) lens[i] = -lens[i]; + // Do stuff for continueing colour codes. + if (!strcmp(resetstr, parts[i])) { + curcolour[0] = 0; + curcolourlen =0; + } else { + if (curcolourlen + strlen((elt->values + 1)->u.string) < MAX_COLOUR_STRING - 1) { + strcat(curcolour, (elt->values + 1)->u.string); + curcolourlen += strlen((elt->values + 1)->u.string); + } + } + break; + } + } + if (!elt) { + lens[i] = SHARED_STRLEN(cp); + } + } else { + lens[i] = strlen(parts[i]); + } + + if (lens[i] <= 0) { + if (j + -lens[i] > max_string_length) { + lens[i] = -(-(lens[i]) - (j + -lens[i] - max_string_length)); + } + j += -lens[i]; + buflen += -lens[i]; + continue; + } + + if (maybe_at_end) { + if (j + indent > max_string_length) { + /* this string no longer counts, so we are still in + a maybe_at_end condition. This means we will end + up truncating the rest of the fragments too, since + the indent will never fit. */ + lens[i] = 0; + } else { + j += indent; + col += indent; + maybe_at_end = 0; + } + } + + j += lens[i]; + if (j > max_string_length) { + lens[i] -= j - max_string_length; + j = max_string_length; + } + + if (wrap) { + int z; + const char *p = parts[i]; + // This is where we figure out the size of the lines and + // the final output string. j is the size of the final output + // string and max_buflen is the size of the line. + for (z = 0; z < lens[i]; z++) { + char c = p[z]; + buflen++; + if (c == '\n') { + if (fillout) { + j += wrap - col; + } + col = 0; + space = space_buflen = 0; + start = -1; + j += resetstrlen + curcolourlen; + buflen += resetstrlen + curcolourlen; + max_buflen = (buflen > max_buflen ? buflen : max_buflen); + buflen = 0; + } else { + if (col > start || (c != ' ' && c != '\t')) + col++; + else { + j--; + buflen--; + } + + if (col > start && c == '\t') + col += (8 - ((col - 1) % 8)); + if (c == ' ' || c == '\t') { + space = col; + space_buflen = buflen; + strncpy(colouratstartword, curcolour, MAX_COLOUR_STRING-1); + colourstartlen = curcolourlen; + } + if (col == wrap+1) { + if (space) { + if (fillout) { + j += wrap - space; + } + col -= space; + space = 0; + j += resetstrlen + colourstartlen; + buflen += resetstrlen + colourstartlen; + max_buflen = (buflen > max_buflen ? buflen : max_buflen); + buflen -= space_buflen; + space_buflen = 0; + } else { + j++; + col = 1; + j += resetstrlen + curcolourlen; + buflen += resetstrlen + curcolourlen; + max_buflen = (buflen > max_buflen ? buflen : max_buflen); + buflen = 1; + } + start = indent; + } else + continue; + } + + /* If we get here, we ended a line by wrapping */ + if (z + 1 != lens[i] || col) { + j += indent; + col += indent; + } else + maybe_at_end = 1; + + if (j > max_string_length) { + lens[i] -= (j - max_string_length); + j = max_string_length; + if (lens[i] < z) { + /* must have been ok or we wouldn't be here */ + lens[i] = z; + break; + } + } + } + } + } + + if (wrap && buflen > max_buflen) + max_buflen = buflen; + + /* now we have the final string in parts and length in j. + let's compose it, wrapping if necessary */ + ncp = deststr = new_string(j, "f_terminal_colour: deststr"); + if (wrap) { + char *tmp = new_string(max_buflen, "f_terminal_colour: wrap"); + char *pt = tmp; + + col = 0; + start = -1; + space = 0; + buflen = space_buflen = 0; + curcolour[0] = 0; + curcolourlen = 0; + for (i = 0; i < num; i++) { + int kind; + const char *p = parts[i]; + if (lens[i] < 0) { + memcpy(pt, p, -lens[i]); + pt += -lens[i]; + buflen += -lens[i]; + space_garbage += -lens[i]; /* Number of chars due to ignored junk + since last space */ + // Do stuff for continueing colour codes. + if (!strcmp(p, resetstr)) { + curcolour[0] = 0; + curcolourlen = 0; + } else { + if (curcolourlen + strlen(p) < MAX_COLOUR_STRING -1) { + strcat(curcolour, p); + curcolourlen += strlen(p); + } + } + continue; + } + for (k = 0; k < lens[i]; k++) { + int n; + int endpad = wrap-col; + char c = p[k]; + *pt++ = c; + buflen++; + if (c == '\n') { + endpad = wrap - col; + col = 0; + kind = 0; + space = space_garbage = 0; + start = -1; + buflen = 0; + strncpy(colouratstartword, curcolour, MAX_COLOUR_STRING-1); + colourstartlen = curcolourlen; + } else { + if (col > start || (c != ' ' && c != '\t')) + col++; + else { + pt--; + buflen--; + } + + if (col > start && c == '\t') + col += (8 - ((col - 1) % 8)); + if (c == ' ' || c == '\t') { + space = col; + space_garbage = 0; + space_buflen = buflen; + strncpy(colouratstartword, curcolour, MAX_COLOUR_STRING-1); + colourstartlen = curcolourlen; + } + if (col == wrap+1) { + if (space) { + endpad = wrap - space; + col -= space; + space = 0; + kind = 1; + buflen -= space_buflen; + space_buflen = 0; + } else { + col = 1; + kind = 2; + buflen = 1; + strncpy(colouratstartword, curcolour, MAX_COLOUR_STRING-1); + colourstartlen = curcolourlen; + } + start = indent; + } else + continue; + } + /* If we get here, we ended a line */ + n = (pt - tmp) - buflen; + memcpy(ncp, tmp, n); + ncp += n; + if (kind == 1 || kind == 0) { + /* replace the space */ + //ncp[-1] = '\n'; + ncp--; + } + if (kind == 2) { + /* need to insert a newline */ + //*ncp++ = '\n'; + } + // Insert the follow on colour codes. + memcpy(ncp, resetstr, resetstrlen); + ncp += resetstrlen; + if (fillout) { + // Fill in the remaining bits with spaces. + memset(ncp, ' ', endpad); + ncp += endpad; + } + *ncp++ = '\n'; + memcpy(ncp, colouratstartword, colourstartlen); + ncp += colourstartlen; + // Back to the normal code again. + memmove(tmp, tmp + n, buflen); + pt = tmp + buflen; + if (col || !at_end(i, num, k, lens)) { + memset(ncp, ' ', indent); + ncp += indent; + col += indent; + } + } + } + memcpy(ncp, tmp, pt - tmp); + ncp += pt - tmp; + FREE_MSTR(tmp); + } else { + for (i = 0; i < num; i++) { + memcpy(ncp, parts[i], lens[i]); + ncp += lens[i]; + } + } + *ncp = 0; + FREE(lens); + FREE(parts); + if (savestr) + FREE_MSTR(savestr); + /* now we have what we want */ + pop_stack(); +#ifndef DEBUG + if (ncp - deststr != j) { + fatal("Length miscalculated in terminal_colour()\n Expected: %i Was: %i\n String: %s\n Indent: %i Wrap: %i\n", j, ncp - deststr, sp->u.string, indent, wrap); + } +#endif + free_string_svalue(sp); + sp->type = T_STRING; + sp->subtype = STRING_MALLOC; + sp->u.string = deststr; +} +#endif + +#ifdef F_PLURALIZE + +#define PLURAL_SUFFIX 1 +#define PLURAL_SAME 2 +/* number to chop is added */ +#define PLURAL_CHOP 2 + +static char *pluralize (const char * str) { + char *pre; + const char *p, *rel, *end; + char *of_buf; + int of_len = 0, plen, slen; + int sz; + + /* default rule */ + int found = 0; + const char * suffix = "s"; + + sz = strlen(str); + if (!sz) return 0; + + /* if it is of the form 'X of Y', pluralize the 'X' part */ + if ((p = strstr(str, " of "))) { + of_buf = alloc_cstring(p, "pluralize: of"); + of_len = strlen(of_buf); + sz = p - str; + } + + /* + * first, get rid of determiners. pluralized forms never have them ;) + * They can have 'the' so don't remove that + */ + if (str[0] == 'a' || str[0] == 'A') { + if (str[1] == ' ') { + plen = sz - 2; + pre = (char *)DXALLOC(plen + 1, TAG_TEMPORARY, "pluralize: pre"); + strncpy(pre, str + 2, plen); + } else if (sz > 2 && str[1] == 'n' && str[2] == ' ') { + plen = sz - 3; + pre = (char *)DXALLOC(plen + 1, TAG_TEMPORARY, "pluralize: pre"); + strncpy(pre, str + 3, plen); + } else { + plen = sz; + pre = (char *)DXALLOC(plen + 1, TAG_TEMPORARY, "pluralize: pre"); + strncpy(pre, str, plen); + } + } else { + plen = sz; + pre = (char *)DXALLOC(plen + 1, TAG_TEMPORARY, "pluralize: pre"); + strncpy(pre, str, plen); + } + pre[plen] = 0; + + /* + * only pluralize the last word, ie: lose adjectives. + */ + if ((p = strrchr(pre, ' '))) + rel = p + 1; + else + rel = pre; + + end = rel + strlen(rel); + + /* + * trap the exceptions to the rules below and special cases. + * + * Hmm, maybe this should be a prebuilt hash table to make maintenance + * a bit easier. Possibly gperf based; or is that overkill? :-) + */ + switch (rel[0]) { + case 'A': + case 'a': + if (!strcasecmp(rel + 1, "re")) { + found = PLURAL_CHOP + 3; + suffix = "is"; + } + break; + case 'B': + case 'b': + if (!strcasecmp(rel + 1, "us")) { + found = PLURAL_SUFFIX; + suffix = "es"; + break; + } + if (!strcasecmp(rel + 1, "onus")) { + found = PLURAL_SUFFIX; + suffix = "es"; + } + break; + case 'C': + case 'c': + if (!strcasecmp(rel + 1, "hild")) { + found = PLURAL_SUFFIX; + suffix = "ren"; + break; + } + if (!strcasecmp(rel + 1, "liff")) { + found = PLURAL_SUFFIX; + suffix = "s"; + } + break; + case 'D': + case 'd': + if (!strcasecmp(rel + 1, "atum")) { + found = PLURAL_CHOP + 2; + suffix = "a"; + break; + } + if (!strcasecmp(rel + 1, "ie")) { + found = PLURAL_CHOP + 1; + suffix = "ce"; + break; + } + if (!strcasecmp(rel + 1, "eer")) { + found = PLURAL_SAME; + break; + } + if (!strcasecmp(rel + 1, "o")) { + found = PLURAL_SUFFIX; + suffix = "es"; + break; + } + if (!strcasecmp(rel + 1, "ynamo")) + found = PLURAL_SUFFIX; + break; + case 'F': + case 'f': + if (!strcasecmp(rel + 1, "oot")) { + found = PLURAL_CHOP + 3; + suffix = "eet"; + break; + } + if (!strcasecmp(rel + 1, "ish")) { + found = PLURAL_SAME; + break; + } + if (!strcasecmp(rel + 1, "orum")) { + found = PLURAL_CHOP + 2; + suffix = "a"; + break; + } + if (!strcasecmp(rel + 1, "ife")) + found = PLURAL_SUFFIX; + break; + case 'G': + case 'g': + if (!strcasecmp(rel + 1, "lasses")) { + found = PLURAL_SAME; + break; + } + if (!strcasecmp(rel + 1, "oose")) { + found = PLURAL_CHOP + 4; + suffix = "eese"; + break; + } + if (!strcasecmp(rel + 1, "o")) { + found = PLURAL_SUFFIX; + suffix = "es"; + break; + } + if (!strcasecmp(rel + 1, "um")) { + found = PLURAL_SUFFIX; + break; + } + if (!strcasecmp(rel + 1, "iraffe")) { + found = PLURAL_SUFFIX; + suffix = "s"; + } + break; + case 'H': + case 'h': + if (!strcasecmp(rel + 1, "uman")){ + found = PLURAL_SUFFIX; + break; + } + if (!strcasecmp(rel + 1, "ave")) { + found = PLURAL_CHOP + 2; + suffix = "s"; + } + break; + case 'I': + case 'i': + if (!strcasecmp(rel + 1, "ndex")) { + found = PLURAL_CHOP + 2; + suffix = "ices"; + } + break; + case 'L': + case 'l': + if (!strcasecmp(rel + 1, "ouse")) { + found = PLURAL_CHOP + 4; + suffix = "ice"; + break; + } + if (!strcasecmp(rel + 1, "otus")) { + found = PLURAL_SUFFIX; + break; + } + break; + case 'M': + case 'm': + if (!strcasecmp(rel + 1, "ackerel")) { + found = PLURAL_SAME; + break; + } + if (!strcasecmp(rel + 1, "oose")) { + found = PLURAL_SAME; + break; + } + if (!strcasecmp(rel + 1, "ouse")) { + found = PLURAL_CHOP + 4; + suffix = "ice"; + break; + } + if (!strcasecmp(rel + 1, "atrix")) { + found = PLURAL_CHOP + 1; + suffix = "ces"; + break; + } + if (!strcasecmp(rel + 1, "ech")) { + found = PLURAL_SUFFIX; + suffix = "s"; + } + break; + case 'O': + case 'o': + if (!strcasecmp(rel + 1, "x")) { + found = PLURAL_SUFFIX; + suffix = "en"; + } + break; + case 'P': + case 'p': + if (!strcasecmp(rel + 1, "ants")) + found = PLURAL_SAME; + break; + case 'Q': + case 'q': + if (!strcasecmp(rel + 1, "uaff")) + found = PLURAL_SUFFIX; + break; + case 'R': + case 'r': + if (!strcasecmp(rel + 1, "emains")) { + found = PLURAL_SAME; + break; + } + if (!strcasecmp(rel + 1, "oof")) + found = PLURAL_SUFFIX; + break; + case 'S': + case 's': + if (!strcasecmp(rel + 1, "niff")) { + found = PLURAL_SUFFIX; + break; + } + if (!strcasecmp(rel + 1, "heep")) { + found = PLURAL_SAME; + break; + } + if (!strcasecmp(rel + 1, "phinx")) { + found = PLURAL_CHOP + 1; + suffix = "ges"; + break; + } + if (!strcasecmp(rel + 1, "taff")) { + found = PLURAL_CHOP + 2; + suffix = "ves"; + break; + } + if (!strcasecmp(rel + 1, "afe")) { + found = PLURAL_SUFFIX; + break; + } + if (!strcasecmp(rel + 1, "haman")) + found = PLURAL_SUFFIX; + break; + case 'T': + case 't': + if (!strcasecmp(rel + 1, "hief")) { + found = PLURAL_CHOP + 1; + suffix = "ves"; + break; + } + if (!strcasecmp(rel + 1, "ooth")) { + found = PLURAL_CHOP + 4; + suffix = "eeth"; + break; + } + if (!strcasecmp(rel + 1, "alisman")) { + found = PLURAL_SUFFIX; + suffix = "s"; + } + break; + case 'V': + case 'v': + if (!strcasecmp(rel + 1, "ax")) { + found = PLURAL_SUFFIX; + suffix = "en"; + break; + } + if (!strcasecmp(rel + 1, "irus")) { + found = PLURAL_SUFFIX; + suffix = "es"; + } + break; + case 'W': + case 'w': + if (!strcasecmp(rel + 1, "as")) { + found = PLURAL_CHOP + 2; + suffix = "ere"; + } + break; + } + /* + * now handle "rules" ... god I hate english!! + */ + /* + * *x -> *xes (fox -> foxes) + * *s -> *ses (pass -> passes) + * *ch -> *ches (church -> churches) + * *sh -> *shes (brush -> brushes) + */ + /* + * *fe -> *ves (knife -> knives) + */ + /* + * *f -> *ves (half -> halves) + * *ef -> *efs (chef -> chefs) (really a rule for a special case) + */ + /* + * *y -> *ies (gumby -> gumbies) + */ + /* + * *us -> *i (cactus -> cacti) + */ + /* + * *man -> *men (foreman -> foremen) + */ + /* + * *is -> *es (this is from gordons pluralize ... ) + */ + /* + * *o -> *s (also from gordon) + */ + + /* don't have to set found to PLURAL_SUFFIX in these rules b/c + found == 0 is interpreted as PLURAL_SUFFIX */ + if (!found && (end != pre)) + switch (end[-1]) { + case 'E': case 'e': + if ((end-pre) > 1 && (end[-2] == 'f' || end[-2] == 'F')) { + found = PLURAL_CHOP + 2; + suffix = "ves"; + } + break; + case 'F': case 'f': + if ((end-pre) > 1 && (end[-2] == 'e' || end[-2] == 'E')) + break; + found = PLURAL_CHOP + 1; + if ((end-pre) > 1 && (end[-2] == 'f' || end[-2] == 'F')) + found++; + suffix = "ves"; + break; + case 'H': case 'h': + if ((end-pre) > 1 && (end[-2] == 'c' || end[-2]=='s')) + suffix = "es"; + break; +#if 0 + /* + * This rule is causing more problems than not. As such, I'm removing + * it in favour of adding exceptions for words above that should use + * this rule. I'm aware that this rule is proper for Latin derived + * English words, however its use has fallen out of common speech and + * writing for the majority of cases. Currently known common exceptions + * are forum (fora) and datum (data). + * -- Marius, 23-Jun-2000 + */ + case 'M': case 'm': + if ((end-pre) > 1 && end[-2] == 'u') { + found = PLURAL_CHOP + 2; + suffix = "a"; + } + break; +#endif + case 'N': case 'n': + if ((end-pre) > 2 && end[-2] == 'a' && end[-3] == 'm') { + found = PLURAL_CHOP + 3; + suffix = "men"; + } + break; + case 'O': case 'o': + if ((end-pre) > 1 && end[-2] != 'o') + suffix = "es"; + break; + case 'S': case 's': + if ((end-pre) > 1 && end[-2] == 'i') { + found = PLURAL_CHOP + 2; + suffix = "es"; + break; + } + if ((end-pre) > 1 && end[-2] == 'u') { + found = PLURAL_CHOP + 2; + suffix = "i"; + break; + } + if ((end-pre) > 1 && (end[-2] == 'a' || end[-2] == 'e' || end[-2] == 'o')) + suffix = "ses"; + else + suffix = "es"; + break; + case 'X': case 'x': + suffix = "es"; + break; + case 'Y': case 'y': + if ((end-pre) > 1 && end[-2] != 'a' && end[-2] != 'e' && end[-2] != 'i' + && end[-2] != 'o' && end[-2] != 'u') { + found = PLURAL_CHOP + 1; + suffix = "ies"; + } + break; + case 'Z': case 'z': + if ((end-pre) > 1 && (end[-2] == 'a' || end[-2] == 'e' || end[-2] == 'o' + || end[-2] == 'i' || end[-2] == 'u')) + suffix = "zes"; + else + suffix = "es"; + } + + switch (found) { + case PLURAL_SAME: + slen = 0; + sz = plen + of_len; + break; + default: + plen -= (found - PLURAL_CHOP); + /* fallthrough */ + case 0: + case PLURAL_SUFFIX: + slen = strlen(suffix); + sz = plen + slen + of_len; + break; + } + + char *news = new_string(sz, "pluralize"); + news[sz] = 0; + + strncpy(news, pre, plen); + if (slen) + strncpy(news + plen, suffix, slen); + if (of_len) { + strcpy(news + plen + slen, of_buf); + FREE(of_buf); + } + + FREE(pre); + return news; +} /* end of pluralize() */ + +void +f_pluralize (void) +{ + char *s; + + s = pluralize(sp->u.string); + pop_stack(); + if (!s) + push_number(0); + else + push_malloced_string(s); +} +#endif + +#ifdef F_FILE_LENGTH +/* + * file_length() efun, returns the number of lines in a file. + * Returns -1 if no privs or file doesn't exist. + */ +static int file_length (const char * file) +{ + struct stat st; + FILE *f; + int ret = 0; + int num; + char buf[2049]; + char *p, *newp; + + file = check_valid_path(file, current_object, "file_size", 0); + + if (!file) return -1; + if (stat(file, &st) == -1) + return -1; + if (st.st_mode & S_IFDIR) + return -2; + if (!(f = fopen(file, "r"))) + return -1; + + do { + num = fread(buf, 1, 2048, f); + p = buf - 1; + while ((newp = (char *)memchr(p + 1, '\n', num))) { + num -= (newp - p); + p = newp; + ret++; + } + } while (!feof(f)); + + fclose(f); + return ret; +} /* end of file_length() */ + +void +f_file_length (void) +{ + int l; + + l = file_length(sp->u.string); + pop_stack(); + push_number(l); +} +#endif + +#ifdef F_UPPER_CASE +void +f_upper_case (void) +{ + const char *str; + + str = sp->u.string; + /* find first upper case letter, if any */ + for (; *str; str++) { + if (uislower(*str)) { + char *newstr; + int l = str - sp->u.string; + unlink_string_svalue(sp); + newstr = (char *) sp->u.string + l; + *newstr = toupper((unsigned char)*newstr); + for (newstr++; *newstr; newstr++) { + if (uislower((unsigned char)*newstr)) + *newstr = toupper((unsigned char)*newstr); + } + return; + } + } +} +#endif + +#ifdef F_REPLACEABLE +void f_replaceable (void) { + object_t *obj; + program_t *prog; + int i, j, num, numignore, replaceable; + char **ignore; + + if (st_num_arg == 2) { + numignore = sp->u.arr->size; + if (numignore) + ignore = CALLOCATE(numignore + 2, char *, TAG_TEMPORARY, "replaceable"); + else + ignore = 0; + ignore[0] = findstring(APPLY_CREATE); + ignore[1] = findstring(APPLY___INIT); + for (i = 0; i < numignore; i++) { + if (sp->u.arr->item[i].type == T_STRING) + ignore[i + 2] = findstring(sp->u.arr->item[i].u.string); + else + ignore[i + 2] = 0; + } + numignore += 2; + obj = (sp-1)->u.ob; + } else { + numignore = 2; + ignore = CALLOCATE(2, char *, TAG_TEMPORARY, "replaceable"); + ignore[0] = findstring(APPLY_CREATE); + ignore[1] = findstring(APPLY___INIT); + obj = sp->u.ob; + } + + prog = obj->prog; + num = prog->num_functions_defined + prog->last_inherited; + + for (i = 0; i < num; i++) { + if (prog->function_flags[i] & (FUNC_INHERITED | FUNC_NO_CODE)) continue; + for (j = 0; j < numignore; j++) + if (ignore[j] == find_func_entry(prog, i)->funcname) + break; + if (j == numignore) + break; + } + + replaceable = (i == num); + if (obj == simul_efun_ob || prog->func_ref) + replaceable = 0; + + if (st_num_arg == 2) + free_array((sp--)->u.arr); + FREE(ignore); + free_svalue(sp, "f_replaceable"); + put_number(replaceable); +} +#endif + +#ifdef F_PROGRAM_INFO +void f_program_info (void) { + int func_size = 0; + int string_size = 0; + int var_size = 0; + int inherit_size = 0; + int prog_size = 0; + int hdr_size = 0; + int class_size = 0; + int type_size = 0; + int total_size = 0; + object_t *ob; + mapping_t *m; + program_t *prog; + int i, n; + + if (st_num_arg == 1) { + ob = sp->u.ob; + prog = ob->prog; + if (!(ob->flags & O_CLONE)) { + hdr_size += sizeof(program_t); + prog_size += prog->program_size; + + /* function flags */ + func_size += (prog->last_inherited + + prog->num_functions_defined) *sizeof(unsigned short); + + /* definitions */ + func_size += prog->num_functions_defined * + sizeof(function_t); + + string_size += prog->num_strings * sizeof(char *); + var_size += prog->num_variables_defined * (sizeof(char *) + sizeof(unsigned short)); + inherit_size += prog->num_inherited * sizeof(inherit_t); + if (prog->num_classes) + class_size += prog->num_classes * sizeof(class_def_t) + (prog->classes[prog->num_classes - 1].index + prog->classes[prog->num_classes - 1].size) * sizeof(class_member_entry_t); + type_size += prog->num_functions_defined * sizeof(short); + n = 0; + if (prog->type_start) { + unsigned short *ts = prog->type_start; + int nfd = prog->num_functions_defined; + + for (i = 0; i < nfd; i++) { + if (ts[i] == INDEX_START_NONE) + continue; + n += prog->function_table[i].num_arg; + } + } + type_size += n * sizeof(short); + total_size += prog->total_size; + } + pop_stack(); + } else { + for (ob = obj_list; ob; ob = ob->next_all) { + if (ob->flags & O_CLONE) + continue; + prog = ob->prog; + hdr_size += sizeof(program_t); + prog_size += prog->program_size; + + /* function flags */ + func_size += (prog->last_inherited + + prog->num_functions_defined) << 1; + + /* definitions */ + func_size += prog->num_functions_defined * + sizeof(function_t); + + + string_size += prog->num_strings * sizeof(char *); + var_size += prog->num_variables_defined * (sizeof(char *) + sizeof(unsigned short)); + inherit_size += prog->num_inherited * sizeof(inherit_t); + if (prog->num_classes) + class_size += prog->num_classes * sizeof(class_def_t) + (prog->classes[prog->num_classes - 1].index + prog->classes[prog->num_classes - 1].size) * sizeof(class_member_entry_t); + type_size += prog->num_functions_defined * sizeof(short); + n = 0; + if (prog->type_start) { + unsigned short *ts = prog->type_start; + int nfd = prog->num_functions_defined; + + for (i = 0; i < nfd; i++) { + if (ts[i] == INDEX_START_NONE) + continue; + n += prog->function_table[i].num_arg; + } + } + type_size += n * sizeof(short); + total_size += prog->total_size; + } + } + + m = allocate_mapping(0); + add_mapping_pair(m, "header size", hdr_size); + add_mapping_pair(m, "code size", prog_size); + add_mapping_pair(m, "function size", func_size); + add_mapping_pair(m, "string size", string_size); + add_mapping_pair(m, "var size", var_size); + add_mapping_pair(m, "class size", class_size); + add_mapping_pair(m, "inherit size", inherit_size); + add_mapping_pair(m, "saved type size", type_size); + + add_mapping_pair(m, "total size", total_size); + + push_refed_mapping(m); +} +#endif + +/* Magician - 08May95 + * int remove_interactive(object ob) + * If the object isn't destructed and is interactive, then remove it's + * interactivity and disconnect it. (useful for exec()ing to an already + * interactive object, ie, Linkdead reconnection) + */ + +#ifdef F_REMOVE_INTERACTIVE +void f_remove_interactive (void) { + if( (sp->u.ob->flags & O_DESTRUCTED) || !(sp->u.ob->interactive) ) { + free_object(&sp->u.ob, "f_remove_interactive"); + *sp = const0; + } else { + remove_interactive(sp->u.ob, 0); + /* It may have been dested */ + if (sp->type == T_OBJECT) + free_object(&sp->u.ob, "f_remove_interactive"); + *sp = const1; + } +} +#endif + +/* Zakk - August 23 1995 + * return the port number the interactive object used to connect to the + * mud. + */ +#ifdef F_QUERY_IP_PORT +static int query_ip_port (object_t * ob) +{ + if (!ob || ob->interactive == 0) + return 0; + return ob->interactive->local_port; +} + +void +f_query_ip_port (void) +{ + int tmp; + + if (st_num_arg) { + tmp = query_ip_port(sp->u.ob); + free_object(&sp->u.ob, "f_query_ip_port"); + } else { + tmp = query_ip_port(command_giver); + STACK_INC; + } + put_number(tmp); +} +#endif + +/* + ** John Viega (rust@lima.imaginary.com) Jan, 1996 + ** efuns for doing time zone conversions. Much friendlier + ** than doing all the lookup tables in LPC. + ** most muds have traditionally just used an offset of the + ** mud time or GMT, and this isn't always correct. + */ + +#ifdef F_ZONETIME + +char *set_timezone (const char * timezone) +{ + static char put_tz[80]; + char *old_tz; + + old_tz = getenv("TZ"); + sprintf(put_tz, "TZ=%s", timezone); + putenv(put_tz); + tzset(); + return old_tz; +} + +void reset_timezone (const char *old_tz) +{ + static char put_tz[80]; + if(old_tz){ + sprintf(put_tz, "TZ=%s", old_tz); + putenv(put_tz); + }else +#ifndef MINGW + unsetenv("TZ"); +#else + putenv("TZ="); +#endif + + tzset (); +} + +void f_zonetime (void) +{ + const char *timezone, *old_tz; + char *retv; + long time_val; + int len; + + time_val = sp->u.number; + pop_stack(); + timezone = sp->u.string; + pop_stack(); + + old_tz = set_timezone(timezone); + retv = ctime((time_t *)&time_val); + len = strlen(retv); + retv[len-1] = '\0'; + reset_timezone(old_tz); + push_malloced_string (string_copy(retv, "zonetime")); + +} +#endif + +#ifdef F_IS_DAYLIGHT_SAVINGS_TIME +void f_is_daylight_savings_time (void) +{ + struct tm *t; + long time_to_check; + const char *timezone; + char *old_tz; + + time_to_check = sp->u.number; + pop_stack(); + timezone = sp->u.string; + pop_stack(); + + old_tz = set_timezone(timezone); + + t = localtime((time_t *)&time_to_check); + + push_number((t->tm_isdst) > 0); + + reset_timezone(old_tz); +} +#endif + +#ifdef F_DEBUG_MESSAGE +void f_debug_message (void) { + debug_message("%s\n", sp->u.string); + free_string_svalue(sp--); +} +#endif + +#ifdef F_FUNCTION_OWNER +void f_function_owner (void) { + object_t *owner = sp->u.fp->hdr.owner; + + free_funp(sp->u.fp); + put_unrefed_object(owner, "f_function_owner"); +} +#endif + +#ifdef F_REPEAT_STRING +void f_repeat_string (void) { + const char *str; + int repeat, len, newlen; + char *ret, *p; + int i; + + repeat = (sp--)->u.number; + if (repeat > 0) { + str = sp->u.string; + len = SVALUE_STRLEN(sp); + if ((newlen = len * repeat) > max_string_length){ + repeat = max_string_length / len; + newlen = len * repeat; + } + } + if (repeat <= 0) { + free_string_svalue(sp); + sp->type = T_STRING; + sp->subtype = STRING_CONSTANT; + sp->u.string = ""; + } else if (repeat != 1) { + p = ret = new_string(newlen, "f_repeat_string"); + for (i = 0; i < repeat; i++) { + memcpy(p, str, len); + p += len; + } + *p = 0; + free_string_svalue(sp); + sp->type = T_STRING; + sp->subtype = STRING_MALLOC; + sp->u.string = ret; + } +} +#endif + +#ifdef F_MEMORY_SUMMARY +static int memory_share (svalue_t *); + +static int node_share (mapping_t * m, mapping_node_t * elt, void * tp) { + int *t = (int *)tp; + + *t += sizeof(mapping_node_t) - 2*sizeof(svalue_t); + *t += memory_share(&elt->values[0]); + *t += memory_share(&elt->values[1]); + + return 0; +} + +static int memory_share (svalue_t * sv) { + int i, total = sizeof(svalue_t); + int subtotal; + static int calldepth = 0; + + switch (sv->type) { + case T_STRING: + switch (sv->subtype) { + case STRING_MALLOC: + return total + + (1 + COUNTED_STRLEN(sv->u.string) + sizeof(malloc_block_t))/ + (COUNTED_REF(sv->u.string)); + case STRING_SHARED: + return total + + (1 + COUNTED_STRLEN(sv->u.string) + sizeof(block_t))/ + (COUNTED_REF(sv->u.string)); + } + break; + case T_ARRAY: + case T_CLASS: + if (1+calldepth > 100) + return 0; + calldepth++; + /* first svalue is stored inside the array struct, so sizeof(array_t) + * includes one svalue. + */ + subtotal = sizeof(array_t) - sizeof(svalue_t); + for (i = 0; i < sv->u.arr->size; i++) + subtotal += memory_share(&sv->u.arr->item[i]); + calldepth--; + return total + subtotal/sv->u.arr->ref; + case T_MAPPING: + if (1+calldepth > 100) + return 0; + calldepth++; + subtotal = sizeof(mapping_t); + mapTraverse(sv->u.map, node_share, &subtotal); + calldepth--; + return total + subtotal/sv->u.map->ref; + case T_FUNCTION: + { + svalue_t tmp; + tmp.type = T_ARRAY; + tmp.u.arr = sv->u.fp->hdr.args; + + if (1+calldepth > 100) + return 0; + calldepth++; + if (tmp.u.arr) + subtotal = sizeof(funptr_hdr_t) + memory_share(&tmp) - sizeof(svalue_t); + else + subtotal = sizeof(funptr_hdr_t); + switch (sv->u.fp->hdr.type) { + case FP_EFUN: + subtotal += sizeof(efun_ptr_t); + break; + case FP_LOCAL | FP_NOT_BINDABLE: + subtotal += sizeof(local_ptr_t); + break; + case FP_SIMUL: + subtotal += sizeof(simul_ptr_t); + break; + case FP_FUNCTIONAL: + case FP_FUNCTIONAL | FP_NOT_BINDABLE: + subtotal += sizeof(functional_t); + break; + } + calldepth--; + return total + subtotal/sv->u.fp->hdr.ref; + } +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + /* first byte is stored inside the buffer struct */ + return total + (sizeof(buffer_t) + sv->u.buf->size - 1)/sv->u.buf->ref; +#endif + } + return total; +} + + +/* + * The returned mapping is: + * + * map["program name"]["variable name"] = memory usage + */ +#ifdef F_MEMORY_SUMMARY +static void fms_recurse (mapping_t * map, object_t * ob, + int * idx, program_t * prog) { + int i; + svalue_t *entry; + svalue_t sv; + + sv.type = T_STRING; + sv.subtype = STRING_SHARED; + + for (i = 0; i < prog->num_inherited; i++) + fms_recurse(map, ob, idx, prog->inherit[i].prog); + + for (i = 0; i < prog->num_variables_defined; i++) { + int size = memory_share(ob->variables + *idx + i); + + sv.u.string = prog->variable_table[i]; + entry = find_for_insert(map, &sv, 0); + entry->u.number += size; + } + *idx += prog->num_variables_defined; +} + +void f_memory_summary (void) { + mapping_t *result = allocate_mapping(8); + object_t *ob; + int idx; + svalue_t sv; + + sv.type = T_STRING; + sv.subtype = STRING_SHARED; + + for (ob = obj_list; ob; ob = ob->next_all) { + svalue_t *entry; + + sv.u.string = ob->prog->filename; + entry = find_for_insert(result, &sv, 0); + if (entry->type == T_NUMBER) { + entry->type = T_MAPPING; + entry->u.map = allocate_mapping(8); + } + idx = 0; + fms_recurse(entry->u.map, ob, &idx, ob->prog); + } + push_refed_mapping(result); +} +#endif + +#endif + +/* Marius */ +#ifdef F_QUERY_REPLACED_PROGRAM +void f_query_replaced_program (void) +{ + char *res = 0; + + if (st_num_arg) + { + if (sp->u.ob->replaced_program) + res = add_slash(sp->u.ob->replaced_program); + free_object(&sp->u.ob, "f_query_replaced_program"); + } + else + { + if (current_object->replaced_program) + res = add_slash(sp->u.ob->replaced_program); + STACK_INC; + } + + if (res) { + put_malloced_string(res); + } else { + put_number(0); + } +} +#endif + +/* Skullslayer@Realms of the Dragon */ +#ifdef F_NETWORK_STATS +void f_network_stats (void) +{ + mapping_t *m; + int i, ports = 0; + + for (i = 0; i < 5; i++) + if (external_port[i].port) + ports += 4; + +#ifndef PACKAGE_SOCKETS + m = allocate_mapping(ports + 4); +#else + m = allocate_mapping(ports + 8); +#endif + + add_mapping_pair(m, "incoming packets total", inet_in_packets); + add_mapping_pair(m, "incoming volume total", inet_in_volume); + add_mapping_pair(m, "outgoing packets total", inet_out_packets); + add_mapping_pair(m, "outgoing volume total", inet_out_volume); + +#ifdef PACKAGE_SOCKETS + add_mapping_pair(m, "incoming packets sockets", inet_socket_in_packets); + add_mapping_pair(m, "incoming volume sockets", inet_socket_in_volume); + add_mapping_pair(m, "outgoing packets sockets", inet_socket_out_packets); + add_mapping_pair(m, "outgoing volume sockets", inet_socket_out_volume); +#endif + + if (ports) { + for (i = 0; i < 5; i++) { + if (external_port[i].port) { + char buf[40]; + + sprintf(buf, "incoming packets port %d", external_port[i].port); + add_mapping_pair(m, buf, external_port[i].in_packets); + sprintf(buf, "incoming volume port %d", external_port[i].port); + add_mapping_pair(m, buf, external_port[i].in_volume); + sprintf(buf, "outgoing packets port %d", external_port[i].port); + add_mapping_pair(m, buf, external_port[i].out_packets); + sprintf(buf, "outgoing volume port %d", external_port[i].port); + add_mapping_pair(m, buf, external_port[i].out_volume); + } + } + } + + push_refed_mapping(m); +} +#endif + +#ifdef F_EVENT + + +/* EVENTS! + * Okay. This is pretty simple. + * Calls the function "event_"+event_name in the object specified. + * If the object is an array, calls it in each. + * If the object is a room, call it on its inventory. + * [Incorrect: actually calls it on all_inventory() of any object but + * only if addressed uniquely] + * Passes all the parameters too. + */ + +#define EVENT_PREFIX "event_" + +void event(svalue_t * event_ob, const char * event_fun, int numparam, + svalue_t * event_param) { + + object_t *ob, *origin; + char *name; + int i; + + origin = current_object; + + name = new_string(strlen (event_fun) + strlen (EVENT_PREFIX) + 1, + "newmoon.c: au_event"); + push_malloced_string(name); + + strcpy(name, EVENT_PREFIX); + strcat(name, event_fun); + + if (event_ob->type == T_ARRAY) { + int ind; + + for (ind = 0; ind < event_ob->u.arr->size; ind++) { + if (event_ob->u.arr->item[ind].type != T_OBJECT + || event_ob->u.arr->item[ind].u.ob->flags & O_DESTRUCTED) + continue; + + push_object(origin); + for (i = 0; i < numparam; i++) + push_svalue (event_param + i); + + apply(name, event_ob->u.arr->item[ind].u.ob, numparam + 1, + ORIGIN_EFUN); + } + } else if (event_ob->type == T_OBJECT) { + int count = 0; + /* First we call the event on the object itself */ + + push_object(origin); + for (i = 0; i < numparam; i++) + push_svalue (event_param + i); + + apply(name, event_ob->u.ob, numparam + 1, ORIGIN_EFUN); + + /* And then call it on it's inventory..., if it's still around! */ + if (event_ob && event_ob->u.ob && !(event_ob->u.ob->flags + & O_DESTRUCTED)) + for (ob = event_ob->u.ob->contains; ob; ob = ob->next_inv) { + if (ob == origin) + continue; + + if (ob->flags & O_DESTRUCTED) + continue; + push_object(ob); + count++; + } + while (count--) { + ob = sp->u.ob; + pop_stack(); + if (!ob || ob->flags & O_DESTRUCTED) + continue; + else { + push_object(origin); + for (i = 0; i < numparam; i++) + push_svalue (event_param + i); + + apply(name, ob, numparam + 1, ORIGIN_EFUN); + } + } + } + sp--; + FREE_MSTR (name); +} + +void f_event (void){ + + int num; + + num = st_num_arg; + + event ((sp - num + 1), (sp - num + 2)->u.string, num - 2, (sp - num + 3)); + + pop_n_elems(num); +} +#endif + + +#ifdef F_QUERY_NUM +void number_as_string (char * buf, long n){ + const char *low[] = { "ten", "eleven", "twelve", "thirteen", + "fourteen", "fifteen", "sixteen", "seventeen", + "eighteen", "nineteen" }; + const char *hi[] = { "", "", "twenty", "thirty", "forty", "fifty", "sixty", + "seventy", "eighty", "ninety"}; + const char *single[] = { "", "one", "two", "three", "four", "five", "six", + "seven", "eight", "nine"}; + if(!n){ + strcat(buf, "zero"); + return; + } + + if(n<20 && n>9){ + strcat(buf, low[n-10]); + return; + } + + strcat(buf,hi[n/10]); + + if ((n>20) && (n%10)) + strcat(buf, "-"); + n %= 10; + + strcat(buf, single[n]); +} + +void f_query_num (void){ + char ret[100]; + int i; + long n, limit; + int changed = 0; + char *res; + + ret[0] = 0; + limit = sp->u.number; + pop_stack(); + n = sp->u.number; + // pop_stack(); + + if ((limit && n>limit) || (n<0) || (n>99999)) { + strcpy(ret, "many"); /* this is a little pointless ... */ + goto q_n_end; + } + + if ((i = n/1000)) { + n = n%1000; + if (!n){ + number_as_string(ret, i); + strcat(ret, " thousand"); + goto q_n_end; + } + + number_as_string(ret, i); + strcat(ret, " thousand"); + changed = 1; + } + + if ((i = n/100)) { + n = n%100; + if (changed) { + if (!n){ + strcat(ret, " and "); + number_as_string(ret, i); + strcat(ret, " hundred"); + goto q_n_end; + } + strcat(ret, ", "); + number_as_string(ret, i); + strcat(ret, " hundred"); + } else { + if (!n){ + number_as_string(ret, i); + strcat(ret, " hundred"); + goto q_n_end; + } + number_as_string(ret, i); + strcat(ret, " hundred"); + changed = 1; + } + } + if (changed) + strcat(ret, " and "); + + number_as_string(ret, n); + q_n_end: + n = strlen(ret); + res = new_string(n, "query_num"); + strcpy(res, ret); + put_malloced_string(res); +} + +#endif + +#ifdef F_BASE_NAME +void f_base_name (void) { + char *name, *tmp; + int i; + + if( sp->type == T_OBJECT ) { + if( sp->u.ob->flags & O_DESTRUCTED ) { + free_object( &sp->u.ob, "f_base_name"); + *sp = const0; + return; + } + name = (char *)add_slash(sp->u.ob->obname); + } else { + name = string_copy( sp->u.string, "f_base_name: name"); + } + + pop_stack(); + + if( ( tmp = strchr( name, '#') ) != NULL ) { + char *ret; + i = tmp - name; + ret = new_string( i, "f_base_name: ret"); + strncpy( ret, name, i ); + ret[i] = 0; + FREE_MSTR(name); + + push_malloced_string(ret); + } else { + push_malloced_string(name); + } + +} /* f_base_name() */ +#endif + +#ifdef F_GET_GARBAGE +int garbage_check (object_t * ob, void * data){ + return (ob->ref == 1) && (ob->flags & O_CLONE) && + !(ob->super +#ifndef NO_SHADOWS + || ob->shadowing +#endif + ); +} + +void f_get_garbage (void){ + int count, i; + object_t **obs; + array_t *ret; + get_objects(&obs, &count, garbage_check, 0); + + if (count > max_array_size) + count = max_array_size; + ret = allocate_empty_array(count); + for (i = 0; i < count; i++) { + ret->item[i].type = T_OBJECT; + ret->item[i].u.ob = obs[i]; + add_ref(obs[i], "f_get_garbage"); + } + + pop_n_elems(1); + push_refed_array(ret); +} +#endif + +#ifdef F_NUM_CLASSES + +void +f_num_classes() { + int i = sp->u.ob->prog->num_classes; + pop_stack(); + push_number( i ); +} + +#endif + +#ifdef F_ASSEMBLE_CLASS +void +f_assemble_class() { + array_t *arr = copy_array( sp->u.arr ); + pop_stack(); + push_refed_array(arr); + sp->type = T_CLASS; +} + +#endif + +#ifdef F_DISASSEMBLE_CLASS +void +f_disassemble_class() { + array_t *arr; + if( sp->type != T_CLASS ) + error( "Argument to disassemble_class() not a class.\n" ); + arr = copy_array( sp->u.arr ); + pop_stack(); + push_refed_array(arr); +} +#endif + +#ifdef F_FETCH_CLASS_MEMBER + +void f_fetch_class_member() { + int pos = sp->u.number; + array_t *arr; + + pos = sp->u.number; + pop_stack(); + + if( sp->type != T_CLASS ) + error( "Argument to fetch_class_member() not a class.\n" ); + + arr = sp->u.arr; + + if( pos < 0 || pos >= arr->size ) + error( "Class index out of bounds.\n" ); + + assign_svalue_no_free( sp, &arr->item[pos] ); + free_array( arr ); +} +#endif + +#ifdef F_STORE_CLASS_MEMBER + +void f_store_class_member() { + int pos = ( sp - 1 )->u.number; + array_t *arr; + + if( ( sp - 2 )->type != T_CLASS ) + error( "Argument to store_class_member() not a class.\n" ); + + arr = ( sp - 2 )->u.arr; + + if( pos < 0 || pos >= arr->size ) + error( "Class index out of bounds.\n" ); + + assign_svalue(&arr->item[pos], sp); + + pop_2_elems(); +} +#endif + + +#ifdef F_ELEMENT_OF +void f_element_of() { + array_t *arr = sp->u.arr; + if(!arr->size) { + error("Can't take element from empty array.\n"); + } + assign_svalue_no_free(sp, &arr->item[random_number(arr->size)]); + free_array(arr); +} +#endif +#ifdef F_SHUFFLE + +/* shuffle efun, based on LPC shuffle simul efun. + * conversion by Taffyd. + */ + +void shuffle(array_t * args) { + int i, j; + svalue_t temp; + + /* Hrm, if we have less than two elements, then the order isn't + * going to change! Let's just leave the old array on the stack. + */ + if ( args->size < 2 ) { + return; + } + + for ( i = 1; i < args->size; i++ ) { + j = random_number( i + 1 ); + + if ( i == j ) { + continue; + } + + temp = args->item[i]; + args->item[i] = args->item[j]; + args->item[j] = temp; + } + + /* Well, that's it. We don't need to push or anything. */ +} + +void +f_shuffle() +{ + svalue_t *sv = sp - st_num_arg + 1; + + if (sv->type == T_ARRAY && sv->u.arr) { + shuffle(sv->u.arr); + } + else { + push_refed_array(&the_null_array); + } +} +#endif + +#ifdef F_MAX + +void +f_max() { + svalue_t *sarr = sp - 1; + array_t *arr = sarr->u.arr; + int max_index = 0; + int i; + + if( !arr->size ) { + error( "Can't find max of an empty array.\n" ); + } + + if( arr->item->type != T_NUMBER && arr->item->type != T_REAL && + arr->item->type != T_STRING ) { + error( "Array must consist of ints, floats or strings.\n" ); + } + + for( i = 1; i < arr->size; i++ ) { + // Check the type of this element. + switch( arr->item[i].type ) { + case T_NUMBER: + switch( arr->item[max_index].type ) { + case T_NUMBER: + if( arr->item[i].u.number > arr->item[max_index].u.number ) + max_index = i; + break; + case T_REAL: + if( arr->item[i].u.number > arr->item[max_index].u.real ) + max_index = i; + break; + default: + error( "Inhomogeneous array.\n" ); + } + break; + case T_REAL: + switch( arr->item[max_index].type ) { + case T_NUMBER: + if( arr->item[i].u.real > arr->item[max_index].u.number ) + max_index = i; + break; + case T_REAL: + if( arr->item[i].u.real > arr->item[max_index].u.real ) + max_index = i; + break; + default: + error( "Inhomogeneous array.\n" ); + } + break; + case T_STRING: + if( arr->item[max_index].type != T_STRING ) { + error( "Inhomogeneous array.\n" ); + } + if( strcmp( arr->item[i].u.string, + arr->item[max_index].u.string ) > 0 ) + max_index = i; + break; + default: + error( "Array must consist of ints, floats or strings.\n" ); + } + } + + if( sp->u.number != 0 ) { + pop_2_elems(); + push_number( max_index ); + return; + } + + pop_stack(); + + assign_svalue_no_free( sp, &arr->item[max_index] ); + free_array( arr ); +} + +#endif + +#ifdef F_MIN + +void +f_min() { + svalue_t *sarr = sp - 1; + array_t *arr = sarr->u.arr; + int min_index = 0; + int i; + + if( !arr->size ) { + error( "Can't find min of an empty array.\n" ); + } + + if( arr->item->type != T_NUMBER && arr->item->type != T_REAL && + arr->item->type != T_STRING ) { + error( "Array must consist of ints, floats or strings.\n" ); + } + + for( i = 1; i < arr->size; i++ ) { + // Check the type of this element. + switch( arr->item[i].type ) { + case T_NUMBER: + switch( arr->item[min_index].type ) { + case T_NUMBER: + if( arr->item[i].u.number < arr->item[min_index].u.number ) + min_index = i; + break; + case T_REAL: + if( arr->item[i].u.number < arr->item[min_index].u.real ) + min_index = i; + break; + default: + error( "Inhomogeneous array.\n" ); + } + break; + case T_REAL: + switch( arr->item[min_index].type ) { + case T_NUMBER: + if( arr->item[i].u.real < arr->item[min_index].u.number ) + min_index = i; + break; + case T_REAL: + if( arr->item[i].u.real < arr->item[min_index].u.real ) + min_index = i; + break; + default: + error( "Inhomogeneous array.\n" ); + } + break; + case T_STRING: + if( arr->item[min_index].type != T_STRING ) { + error( "Inhomogeneous array.\n" ); + } + if( strcmp( arr->item[i].u.string, + arr->item[min_index].u.string ) < 0 ) + min_index = i; + break; + default: + error( "Array must consist of ints, floats or strings.\n" ); + } + } + + if( sp->u.number != 0 ) { + pop_2_elems(); + push_number( min_index ); + return; + } + + pop_stack(); + + assign_svalue_no_free( sp, &arr->item[min_index] ); + free_array( arr ); +} +#endif + +#ifdef F_ABS + +void +f_abs() { + if( sp->type == T_REAL && sp->u.real < 0.0 ) + sp->u.real = -sp->u.real; + else if( sp->type == T_NUMBER && sp->u.number < 0 ) + sp->u.number = -sp->u.number; +} +#endif + +#ifdef F_ROLL_MDN + +void +f_roll_MdN() { + long roll = 0; + + if ( (sp - 1)->u.number > 0 && sp->u.number > 0 ) { + while( (sp - 1)->u.number-- ) + roll += 1 + random_number( sp->u.number ); + } + + pop_stack(); // Pop one... + sp->u.number = roll; // And change the other! +} + +#endif + +#ifdef F_STRING_DIFFERENCE +int min3( int a, int b, int c ) { + if( a < b ) { + if( a < c ) { + return a; + } + } + else if( b < c ) { + return b; + } + return c; +} + +int levenshtein( char *a, int as, char *b, int bs ) { + int *table, skew, nskew, i, j; + // Strip common pre- and suffix. This doesn't change the result. + while( as > 0 && a[0] == b[0] ) { + a++; + b++; + as--; + bs--; + } + + while( as > 0 && a[as - 1] == b[bs - 1] ) { + as--; + bs--; + } + + if( !as ) { // Empty string needs bs insertions. + return bs; + } + + table = CALLOCATE( bs + 1, int, TAG_TEMPORARY, "levenshtein" ); + for( i = 1; i <= bs; i++ ) { + table[i] = i; + } + + for( i = 0; i < as; i++ ) { + table[0] = i + 1; + skew = i; + for( j = 1; j <= bs; j++ ) { + if( a[i] != b[j - 1] ) { + skew++; + } + + nskew = table[j]; + table[j] = min3( table[j - 1] + 1, nskew + 1, skew ); + skew = nskew; + } + } + + i = table[bs]; + FREE( table ); + return i; +} /* levenshtein() */ + +void f_string_difference() { + int diff, as, bs; + char *a, *b; + + a = (char *)sp->u.string; + b = (char *)( sp - 1 )->u.string; + + if( !strcmp( a, b ) ) { + diff = 0; + } + else { + as = strlen( a ); + bs = strlen( b ); + + // Algorithm is quicker if the shorter string is passed first. + if( as < bs ) { + diff = levenshtein( a, as, b, bs ); + } + else { + diff = levenshtein( b, bs, a, as ); + } + } + + free_string_svalue( sp-- ); + free_string_svalue( sp ); + put_number( diff ); +} +#endif + +#ifdef F_QUERY_CHARMODE +static int query_charmode (object_t * ob){ + int ret; + if (!ob || ob->interactive == 0){ + ret = -2; + } + else { + ret = (ob->interactive->iflags & I_SINGLE_CHAR); + } + return ret; +} + +void f_query_charmode (void){ + int tmp; + + if (st_num_arg){ + tmp = query_charmode(sp->u.ob); + free_object(&sp->u.ob, "f_query_charmode"); + } + else { + tmp = -1; + } + put_number(tmp); +} + +#ifdef F_REMOVE_CHARMODE +static int remove_charmode (object_t * ob){ + int ret; + if (!ob || ob->interactive == 0){ + ret = -2; + } + else { + ret = (ob->interactive->iflags &= ~I_SINGLE_CHAR); + } + return ret; +} + +void f_remove_charmode (void){ + int tmp; + + if (st_num_arg){ + tmp = remove_charmode(sp->u.ob); + free_object(&sp->u.ob, "f_remove_charmode"); + } + else { + tmp = -1; + } + //if(tmp > 0 && !(tmp & I_SINGLE_CHAR)) tmp = 1; + //else tmp = 0; + put_number(tmp); +} +#endif +#endif +#ifdef F_REMOVE_GET_CHAR +static int remove_get_char (object_t * ob){ + int ret; + if (!ob || ob->interactive == 0){ + ret = -2; + } + else ret = 0; + + if (ob->interactive->input_to) { + ret = 1; + free_sentence(ob->interactive->input_to); + if (ob->interactive->num_carry > 0) + free_some_svalues(ob->interactive->carryover, ob->interactive->num_carry); + ob->interactive->carryover = NULL; + ob->interactive->num_carry = 0; + ob->interactive->input_to = 0; + } + else { + ret = -1; + } + return ret; +} + +void f_remove_get_char (void){ + int tmp; + + if (st_num_arg){ + tmp = remove_get_char(sp->u.ob); + free_object(&sp->u.ob, "f_remove_get_char"); + } + else { + tmp = -3; + } + put_number(tmp); +} + +#endif +#ifdef F_SEND_NULLBYTE +void f_send_nullbyte (void){ + int tmp; + object_t *who; + tmp = 0; + + who = sp->u.ob; + if (!who || (who->flags & O_DESTRUCTED) || !who->interactive || + (who->interactive->iflags & (NET_DEAD | CLOSING))) { + tmp = -2; + } + else { + tmp = 1; + //""is only the end-of-string zero byte. + add_message(who,"",1); + flush_message(who->interactive); + } + free_object(&sp->u.ob, "f_send_nullbyte"); + put_number(tmp); +} + +#endif + +#ifdef F_RESTORE_FROM_STRING +void f_restore_from_string(){ + const char *buf; + long noclear; + + buf = (sp-1)->u.string; + noclear = sp->u.number; + if (!noclear) { + clear_non_statics(current_object); + } + copy_and_push_string(buf); //restore_object_from_buff modifies the string in place, which is ok, copied strings aren't shared + restore_object_from_buff(current_object, (char *)sp->u.string, noclear); + pop_3_elems(); +} +#endif + +#ifdef F_CLASSES +void f_classes() { + int i, j, num, size, offset, flag; + array_t *vec, *subvec, *subsubvec; + unsigned short *types; + char buf[256]; + char *end; + program_t *prog; + + flag = (sp--)->u.number; + end = EndOf( buf ); + + prog = sp->u.ob->prog; + num = prog->num_classes; + vec = allocate_empty_array( num ); + + // Pull out data for each class. + for( i = 0; i < num; i++ ) { + // Do we want additional info on each class? + if( flag ) { + size = prog->classes[i].size; + + vec->item[i].type = T_ARRAY; + subvec = vec->item[i].u.arr = allocate_empty_array( 1 + size ); + + // First item of return array: the class's name. + subvec->item[0].type = T_STRING; + subvec->item[0].subtype = STRING_SHARED; + subvec->item[0].u.string = make_shared_string( + prog->strings[prog->classes[i].classname] ); + + offset = prog->classes[i].index; + + // Find the name and type of each class member. + for( j = 0; j < size; j++, offset++ ) { + subvec->item[j + 1].type = T_ARRAY; + subsubvec = subvec->item[j + 1].u.arr = allocate_empty_array( 2 ); + + // Each subarray contains the member's name... + subsubvec->item[0].type = T_STRING; + subsubvec->item[0].subtype = STRING_SHARED; + subsubvec->item[0].u.string = make_shared_string( + prog->strings[prog->class_members[offset].membername] ); + + // ...and type. + get_type_name( buf, end, prog->class_members[offset].type ); + subsubvec->item[1].type = T_STRING; + subsubvec->item[1].subtype = STRING_SHARED; + subsubvec->item[1].u.string = make_shared_string( buf ); + } + } + else { + // No additional info. Just pull out the class name. + vec->item[i].type = T_STRING; + vec->item[i].subtype = STRING_SHARED; + vec->item[i].u.string = make_shared_string( + prog->strings[prog->classes[i].classname] ); + } + } + + pop_stack(); + push_refed_array( vec ); +} + +#endif diff --git a/fluffos-2.23-ds03/packages/contrib_spec.c b/fluffos-2.23-ds03/packages/contrib_spec.c new file mode 100644 index 0000000..d1748b3 --- /dev/null +++ b/fluffos-2.23-ds03/packages/contrib_spec.c @@ -0,0 +1,62 @@ +#include "spec.h" + +#ifndef NO_SHADOWS +int remove_shadow(object); +#endif +#ifndef NO_ADD_ACTION +mixed query_notify_fail(); +object *named_livings(); +#endif +#if 0 +void set_prompt(string, void|object); +#endif +mixed copy(mixed); +mixed *functions(object, int default: 0); +mixed *variables(object, int default: 0); +object *heart_beats(); +#ifdef COMPAT_32 +object *heart_beat_info heart_beats(); +#endif +string terminal_colour(string, mapping, int | void, int | void); +string pluralize(string); +int file_length(string); +string upper_case(string); +int replaceable(object, void | string *); +mapping program_info(void | object); +void store_variable(string, mixed); +mixed fetch_variable(string); +int remove_interactive(object); +int query_ip_port(void | object); +string zonetime(string, int); +int is_daylight_savings_time(string, int); +void debug_message(string); +object function_owner(function); +string repeat_string(string, int); +mapping memory_summary(); +string query_replaced_program(void|object); +mapping network_stats(); +int real_time(); +#ifdef PACKAGE_COMPRESS +int compressedp(object); +#endif +void event(object|object *, string, ...); +string query_num(int, int default:0); +string base_name( string | object default: F__THIS_OBJECT); +object *get_garbage(); +int num_classes( object ); +mixed assemble_class( mixed * ); +mixed *disassemble_class( mixed ); +mixed fetch_class_member( mixed, int ); +mixed store_class_member( mixed, int, mixed ); +mixed *shuffle(mixed *); +mixed element_of(mixed *); +mixed max( mixed *, int default:0); +mixed min( mixed *, int default:0); +mixed abs( int | float ); +int string_difference( string, string ); +int query_charmode(object); +int remove_charmode(object); +int remove_get_char(object); +int send_nullbyte(object); +void restore_from_string(string, int default:0); +mixed *classes( object, int default : 0 ); diff --git a/fluffos-2.23-ds03/packages/crypto.c b/fluffos-2.23-ds03/packages/crypto.c new file mode 100644 index 0000000..daab37d --- /dev/null +++ b/fluffos-2.23-ds03/packages/crypto.c @@ -0,0 +1,115 @@ +/** + * crypto.c + * + * Utilises the OpenSSL crypto library to provide various message digest hashes + * via a hash() efun. It works in almost the same manner as the hash function + * from php, and provides md2, md4, md5, mdc2, sha1 and ripemd160 hashes. You + * must link against the ssl link library (add -lssl to system_libs). + * + * -- coded by Ajandurah@Demonslair (Mark Lyndoe) 10/03/09 + */ + +#include +#include +#include +#include +#include +#include + +#ifdef LATTICE +#include "/lpc_incl.h" +#else +#include "../lpc_incl.h" +#include "../efun_protos.h" +#endif + +#ifdef F_HASH +char *hexdump(unsigned char *data, size_t len) +{ + char *buf; + int i; + + buf = malloc((len*2)+1); + memset(buf, '\0', (len*2)); + + for (i=0; iu.string; + data = sp->u.string; + + /* MD2 Digest */ + if (strcasecmp(algo, (const char *)"md2") == 0) + { + unsigned char md[MD2_DIGEST_LENGTH]; + MD2((unsigned char *)data, strlen(data), md); + res = hexdump(md, MD2_DIGEST_LENGTH); + } + + /* MD4 Digest */ + else if (strcasecmp(algo, (const char *)"md4") == 0) + { + unsigned char md[MD4_DIGEST_LENGTH]; + MD4((unsigned char *)data, strlen(data), md); + res = hexdump(md, MD4_DIGEST_LENGTH); + } + + /* MD5 Digest */ + else if (strcasecmp(algo, (const char *)"md5") == 0) + { + unsigned char md[MD5_DIGEST_LENGTH]; + MD5((unsigned char *)data, strlen(data), md); + res = hexdump(md, MD5_DIGEST_LENGTH); + } + + /* MDC2 Digest */ + else if (strcasecmp(algo, (const char *)"mdc2") == 0) + { + unsigned char md[MDC2_DIGEST_LENGTH]; + MDC2((unsigned char *)data, strlen(data), md); + res = hexdump(md, MDC2_DIGEST_LENGTH); + } + + /* RIPEMD160 Digest */ + else if (strcasecmp(algo, (const char *)"ripemd160") == 0) + { + unsigned char md[RIPEMD160_DIGEST_LENGTH]; + RIPEMD160((unsigned char *)data, strlen(data), md); + res = hexdump(md, RIPEMD160_DIGEST_LENGTH); + } + + /* SHA1 Digest */ + else if (strcasecmp(algo, (const char *)"sha1") == 0) + { + unsigned char md[SHA_DIGEST_LENGTH]; + SHA1((unsigned char *)data, strlen(data), md); + res = hexdump(md, SHA_DIGEST_LENGTH); + } + + else + { + pop_stack(); + res = malloc(29 + strlen(algo)); + sprintf(res, "hash() unknown hash type: %s.\n", algo); + error(res); + } + + /* Pop the arguments off the stack and push the result */ + free_string_svalue(sp--); + free_string_svalue(sp); + + sp->subtype = STRING_MALLOC; + sp->u.string = res; +} +#endif diff --git a/fluffos-2.23-ds03/packages/crypto_spec.c b/fluffos-2.23-ds03/packages/crypto_spec.c new file mode 100644 index 0000000..8c48392 --- /dev/null +++ b/fluffos-2.23-ds03/packages/crypto_spec.c @@ -0,0 +1,3 @@ +#include "spec.h" + +string hash(string, string); diff --git a/fluffos-2.23-ds03/packages/db.c b/fluffos-2.23-ds03/packages/db.c new file mode 100644 index 0000000..9d062d4 --- /dev/null +++ b/fluffos-2.23-ds03/packages/db.c @@ -0,0 +1,1492 @@ +/****************************************************************************** + **** + **** Database package for the MudOS driver + **** + **** History: + **** Sometime: + **** Descartes@Nightmare created and added mSQL support + **** + **** Feb 1999: + **** Andrew@Nanvaent restructured to add MySQL support and a + **** framework for other databases to be added. + **** + **** Jul 2000: + **** Andrew@Nanvaent's work included in the MudOS proper + **** + **** Apr 2006: + **** Ajandurah@Demonslair added SQLite v3 support, defining + **** USE_SQLITE3 in local_options will enable it. + **** + **** Feb 2009: + **** Ajandurah@Demonslair added SQLite v2 support, defining + **** USE_SQLITE2 in local_options will enable it. + **** + **** Notes: + **** . This package has been restructured so that it can be compiled into + **** a driver without any database types defined so that you can write + **** stuff without necessarily having the database. + **** + **** . No database type has been added that supports commit or rollback, + **** so these functions have not been fully implemented, particularly + **** with regard to error handling. + **** + **** . Support for multiple database types is present, if obscure. When + **** you have multiple types you should have DEFAULT_DB defined to be + **** the default one, and USE_MYSQL/USE_MSQL should be defined to be + **** numbers in the local_options file or equivalent, e.g.: + **** #define USE_MSQL 1 + **** #define USE_MYSQL 2 + **** #define DEFAULT_DB USE_MSQL + **** + **** The value that you defined it to will be that expected when you + **** make a call to db_connect( ... ) as the fourth argument. Without + **** the fourth argument, the value used will be that for DEFAULT_DB. + **** + **** . Adding another database type should involve: + **** + picking your own define name + **** + editing db.h and adding an appropriate member to the dbconn_t + **** union + **** + adding a dbdefn_t definition for it in this file + **** + playing around with the code for deciding between databases in + **** f_db_connect() + **** + writing all the required interface functions as you've defined + **** for the dbdefn_t structure. Minimum requirements would be + **** connect, close, fetch and execute and cleanup if you need to + **** cleanup memory allocated between searches. + **** + **** TODO: + **** . Decent Error Message reporting + **** . Function for showing the current connections (incomplete) + **** . Standardise on return values (only db_exec is nonstandard) + **** . Documentation + **** . Add more databases + **** + ******************************************************************************/ + +#include "../std.h" +#include "../md.h" +#include "../master.h" +#include "../lpc_incl.h" +#include "../mapping.h" +#include "../comm.h" +#include "../file_incl.h" +#include "../file.h" +#include "../object.h" +#include "../eoperators.h" +#include "../backend.h" + +#include "db.h" +#ifdef PACKAGE_ASYNC +#include +#endif +static int dbConnAlloc, dbConnUsed; +static db_t *dbConnList; + +db_t * find_db_conn (int); +static int create_db_conn (void); +static void free_db_conn (db_t *); + +#ifdef USE_MSQL +static int msql_connect (dbconn_t *, const char *, const char *, const char *, const char *); +static int msql_close (dbconn_t *); +static int msql_execute (dbconn_t *, const char *); +static array_t *msql_fetch (dbconn_t *, int); +static void msql_cleanup (dbconn_t *); +static char * msql_errormsg (dbconn_t *); + +static db_defn_t msql = { + "mSQL", msql_connect, msql_close, msql_execute, msql_fetch, NULL, NULL, msql_cleanup, NULL, msql_errormsg +}; +#endif + +#ifdef USE_MYSQL +static int MySQL_connect (dbconn_t *, const char *, const char *, const char *, const char *); +static int MySQL_close (dbconn_t *); +static int MySQL_execute (dbconn_t *, const char *); +static array_t *MySQL_fetch (dbconn_t *, int); +static void MySQL_cleanup (dbconn_t *); +static char * MySQL_errormsg (dbconn_t *); + +static db_defn_t mysql = { + "MySQL", MySQL_connect, MySQL_close, MySQL_execute, MySQL_fetch, NULL, NULL, MySQL_cleanup, NULL, MySQL_errormsg +}; +#endif + +#ifdef USE_POSTGRES +static int Postgres_connect (dbconn_t *, const char *, const char *, const char *, const char *); +static int Postgres_close (dbconn_t *); +static int Postgres_execute (dbconn_t *, const char *); +static array_t *Postgres_fetch (dbconn_t *, int); +static void Postgres_cleanup (dbconn_t *); +static char * Postgres_errormsg (dbconn_t *); + +static db_defn_t postgres = { + "Postgres", Postgres_connect, Postgres_close, Postgres_execute, Postgres_fetch, NULL, NULL, Postgres_cleanup, NULL, Postgres_errormsg +}; +#endif + +#ifdef USE_SQLITE2 +static int SQLite2_connect (dbconn_t *, const char *, const char *, const char *, const char *); +static int SQLite2_close (dbconn_t *); +static int SQLite2_execute (dbconn_t *, const char *); +static array_t *SQLite2_fetch (dbconn_t *, int); +static void SQLite2_cleanup (dbconn_t *); +static char * SQLite2_errormsg (dbconn_t *); + +static db_defn_t SQLite2 = { + "SQLite2", SQLite2_connect, SQLite2_close, SQLite2_execute, SQLite2_fetch, NULL, NULL, SQLite2_cleanup, NULL, SQLite2_errormsg +}; +#endif + +#ifdef USE_SQLITE3 +static int SQLite3_connect (dbconn_t *, const char *, const char *, const char *, const char *); +static int SQLite3_close (dbconn_t *); +static int SQLite3_execute (dbconn_t *, const char *); +static array_t *SQLite3_fetch (dbconn_t *, int); +static void SQLite3_cleanup (dbconn_t *); +static char * SQLite3_errormsg (dbconn_t *); + +static db_defn_t SQLite3 = { + "SQLite3", SQLite3_connect, SQLite3_close, SQLite3_execute, SQLite3_fetch, NULL, NULL, SQLite3_cleanup, NULL, SQLite3_errormsg +}; +#endif + +static db_defn_t no_db = { + "None", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +/* valid_database + * + * Calls APPLY_VALID_DATABASE in the master object to provide some + * security on which objects can tweak your database (we don't want + * people doing "DELETE * FROM *" or equivalent for us) + */ +svalue_t *valid_database (const char * action, array_t * info) +{ + svalue_t *ret; + + /* + * Call valid_database(object ob, string action, mixed *info) + * + * Return: string - password for access + * int - 1 for no password, accept, 0 deny + */ + push_object(current_object); + push_constant_string(action); + push_refed_array(info); + + ret = apply_master_ob(APPLY_VALID_DATABASE, 3); + if (ret && (ret == (svalue_t *)-1 || (ret->type == T_STRING || (ret->type == T_NUMBER && ret->u.number)))) + return ret; + + error("Database security violation attempted\n"); +} + +/* int db_close(int handle); + * + * Closes the connection to the database represented by the named handle + * + * Returns 1 on success, 0 on failure + */ +#ifdef F_DB_CLOSE +void f_db_close (void) +{ + int ret = 0; + db_t *db; + + valid_database("close", &the_null_array); + + db = find_db_conn(sp->u.number); + if (!db) { + error("Attempt to close an invalid database handle\n"); + } + + /* Cleanup any memory structures left around */ + if (db->type->cleanup) { + db->type->cleanup(&(db->c)); + } + + if (db->type->close) { + ret = db->type->close(&(db->c)); + } + + /* Remove the entry from the linked list */ + free_db_conn(db); + + sp->u.number = ret; +} +#endif + +/* int db_commit(int handle); + * + * Commits the last set of transactions to the database + * NOTE: MSQL does not have transaction logic, so since + * MSQL is the only thing supported now, this does nothing + * I have put it in, however, so people can write properly + * portable LPC code + * + * Returns 1 on success, 0 on failure + */ +#ifdef F_DB_COMMIT +void f_db_commit (void) +{ + int ret = 0; + db_t *db; + + valid_database("commit", &the_null_array); + + db = find_db_conn(sp->u.number); + if (!db) { + error("Attempt to commit an invalid database handle\n"); + } + + if (db->type->commit) { + ret = db->type->commit(&(db->c)); + } + + sp->u.number = ret; +} +#endif + +/* int db_connect(string host, string database, string user, int type) + * + * Creates a database connection to the database named by the + * second argument found on the host named by the first argument. + * Note that this means you can connect to database servers running on + * machines other than the one on which the mud is running. It will + * connect based on settings established at compile time for the + * user id and password (if required). + * + * Returns a new database handle. + */ +#ifdef F_DB_CONNECT +void f_db_connect (void) +{ + char *errormsg = 0; + const char *user = "", *database, *host; + db_t *db; + array_t *info; + svalue_t *mret; + int handle, ret = 0, args = 0, type; + +#ifdef DEFAULT_DB + type = DEFAULT_DB; +#else + type = 0; +#endif + + switch (st_num_arg) { + case 4: type = (sp - (args++))->u.number; + case 3: user = (sp - (args++))->u.string; + case 2: database = (sp - (args++))->u.string; + case 1: host = (sp - (args++))->u.string; + } + + info = allocate_empty_array(3); + info->item[0].type = info->item[1].type = info->item[2].type = T_STRING; + info->item[0].subtype = info->item[1].subtype = info->item[2].subtype = STRING_MALLOC; + info->item[0].u.string = string_copy(database, "f_db_connect:1"); + if (*host) + info->item[1].u.string = string_copy(host, "f_db_connect:2"); + else + info->item[1] = const0; + info->item[2].u.string = string_copy(user, "f_db_connect:3"); + + mret = valid_database("connect", info); + + handle = create_db_conn(); + if (!handle) { + pop_n_elems(args); + push_number(0); + return; + } + db = find_db_conn(handle); + + switch (type) { + default: + /* fallthrough */ +#ifdef USE_MSQL +#if USE_MSQL - 0 + case USE_MSQL: +#endif + db->type = &msql; + break; +#endif +#ifdef USE_MYSQL +#if USE_MYSQL - 0 + case USE_MYSQL: +#endif + db->type = &mysql; + break; +#endif +#ifdef USE_SQLITE2 +#if USE_SQLITE2 - 0 + case USE_SQLITE2: +#endif + db->type = &SQLite2; + break; +#endif +#ifdef USE_SQLITE3 +#if USE_SQLITE3 - 0 + case USE_SQLITE3: +#endif + db->type = &SQLite3; + break; +#endif +#ifdef USE_POSTGRES +#if USE_POSTGRES - 0 + case USE_POSTGRES: +#endif + db->type = &postgres; + break; +#endif + } + + if (db->type->connect) { + ret = db->type->connect(&(db->c), host, database, user, + (mret != (svalue_t *)-1 && mret->type == T_STRING ? mret->u.string : 0)); + } + + pop_n_elems(args); + + if (!ret) { + if (db->type->error) { + errormsg = db->type->error(&(db->c)); + push_malloced_string(errormsg); + } else { + push_number(0); + } + free_db_conn(db); + } else { + push_number(handle); + } +} +#endif + +/* mixed db_exec(int handle, string sql) + * + * Executes the SQL statement passed for the named connection handle. + * If data needs to be retrieved from this execution, it should be done + * through db_fetch() after making the call to db_exec() + * + * Returns number of rows in result set on success, an error string on failure + * NOTE: the number of rows on INSERT, UPDATE, and DELETE statements will + * be zero since there is no result set. + */ +#ifdef PACKAGE_ASYNC +extern pthread_mutex_t *db_mut; +#endif +#ifdef F_DB_EXEC +void f_db_exec (void) +{ + int ret = 0; + db_t *db; + array_t *info; + info = allocate_empty_array(1); + info->item[0].type = T_STRING; + info->item[0].subtype = STRING_MALLOC; + info->item[0].u.string = string_copy(sp->u.string, "f_db_exec"); + valid_database("exec", info); + + db = find_db_conn((sp-1)->u.number); + if (!db) { + error("Attempt to exec on an invalid database handle\n"); + } + +#ifdef PACKAGE_ASYNC + if(!db_mut){ + db_mut = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t)); + pthread_mutex_init(db_mut, NULL); + } + pthread_mutex_lock(db_mut); +#endif + if (db->type->cleanup) { + db->type->cleanup(&(db->c)); + } + + if (db->type->execute) { + ret = db->type->execute(&(db->c), sp->u.string); + } + + pop_stack(); + if (ret == -1) { + if (db->type->error) { + char *errormsg; + + errormsg = db->type->error(&(db->c)); + put_malloced_string(errormsg); + } else { + put_constant_string("Unknown error"); + } + } else { + sp->u.number = ret; + } +#ifdef PACKAGE_ASYNC + pthread_mutex_unlock(db_mut); +#endif +} +#endif + +/* array db_fetch(int db_handle, int row); + * + * Returns the result set from the last database transaction + * performed through db_exec() on the db handle in question for the row + * named. For example, db_exec(10, "SELECT player_name from t_player") might + * have returned two rows. Typical code to extract that data might be: + * string *res; + * mixed rows; + * int dbconn, i; + * + * dbconn = db_connect("nightmare.imaginary.com", "db_mud"); + * if( dbconn < 1 ) return 0; + * rows = db_exec(dbconn, "SELECT player_name from t_player"); + * if( !rows ) write("No rows returned."); + * else if( stringp(rows) ) write(rows); + * else for(i=1; i<=rows; i++) { + * res = db_fetch(dbconn, i); + * write(res[0]); + * } + * db_close(dbconn); + * return 1; + * + * Returns an array of columns from the named row on success. + */ +#ifdef F_DB_FETCH +void f_db_fetch (void) +{ + db_t *db; + array_t *ret; + + valid_database("fetch", &the_null_array); + + db = find_db_conn((sp-1)->u.number); + if (!db) { + error("Attempt to fetch from an invalid database handle\n"); + } + + if (db->type->fetch) { + ret = db->type->fetch(&(db->c), sp->u.number); + } else { + ret = &the_null_array; + } + + pop_stack(); + if (!ret) { + if (db->type->error) { + char *errormsg; + + errormsg = db->type->error(&(db->c)); + put_malloced_string(errormsg); + } else { + sp->u.number = 0; + } + } else { + put_array(ret); + } +} +#endif + +/* int db_rollback(int handle) + * + * Rollsback all db_exec() calls back to the last db_commit() call for the + * named connection handle. + * NOTE: MSQL does not support rollbacks + * + * Returns 1 on success, 0 on failure + */ +#ifdef F_DB_ROLLBACK +void f_db_rollback (void) +{ + int ret = 0; + db_t *db; + + valid_database("rollback", &the_null_array); + + db = find_db_conn(sp->u.number); + if (!db) { + error("Attempt to rollback an invalid database handle\n"); + } + + if (db->type->rollback) { + ret = db->type->rollback(&(db->c)); + } + + if (ret > 0) { + if (db->type->cleanup) { + db->type->cleanup(&(db->c)); + } + } + + sp->u.number = ret; +} +#endif + +/* string db_status() + * + * Returns a string describing the database package's current status + */ +#ifdef F_DB_STATUS +void f_db_status (void) +{ + int i; + outbuffer_t out; + + outbuf_zero(&out); + + for (i = 0; i < dbConnAlloc; i++) { + if (dbConnList[i].flags & DB_FLAG_EMPTY) { + continue; + } + + outbuf_addv(&out, "Handle: %d (%s)\n", i + 1, dbConnList[i].type->name); + if (dbConnList[i].type->status != NULL) { + dbConnList[i].type->status(&(dbConnList[i].c), &out); + } + } + + outbuf_push(&out); +} +#endif + +void db_cleanup (void) +{ + int i; + + for (i = 0; i < dbConnAlloc; i++) { + if (!(dbConnList[i].flags & DB_FLAG_EMPTY)) { + if (dbConnList[i].type->cleanup) { + dbConnList[i].type->cleanup(&(dbConnList[i].c)); + } + + if (dbConnList[i].type->close) { + dbConnList[i].type->close(&(dbConnList[i].c)); + } + + dbConnList[i].flags = DB_FLAG_EMPTY; + dbConnUsed--; + } + } +} + +int create_db_conn (void) +{ + int i; + + /* allocate more slots if we need them */ + if (dbConnAlloc == dbConnUsed) { + i = dbConnAlloc; + dbConnAlloc += 10; + if (!dbConnList) { + dbConnList = CALLOCATE(dbConnAlloc, db_t, TAG_DB, "create_db_conn"); + } else { + pthread_mutex_lock(db_mut); + dbConnList = RESIZE(dbConnList, dbConnAlloc, db_t, TAG_DB, "create_db_conn"); + pthread_mutex_unlock(db_mut); + } + while (i < dbConnAlloc) { + dbConnList[i++].flags = DB_FLAG_EMPTY; + } + } + + for (i = 0; i < dbConnAlloc; i++) { + if (dbConnList[i].flags & DB_FLAG_EMPTY) { + dbConnList[i].flags = 0; + dbConnList[i].type = &no_db; + dbConnUsed++; + return i + 1; + } + } + + fatal("dbConnAlloc != dbConnUsed, but no empty slots"); +} + +db_t *find_db_conn (int handle) +{ + if (handle < 1 || handle > dbConnAlloc || dbConnList[handle - 1].flags & DB_FLAG_EMPTY) + return 0; + return &(dbConnList[handle - 1]); +} + +void free_db_conn (db_t * db) +{ + DEBUG_CHECK(db->flags & DB_FLAG_EMPTY, "Freeing DB connection that is already freed\n"); + DEBUG_CHECK(!dbConnUsed, "Freeing DB connection when dbConnUsed == 0\n"); + dbConnUsed--; + db->flags |= DB_FLAG_EMPTY; +} + +/* + * MySQL support + */ +#ifdef USE_MYSQL +static void MySQL_cleanup (dbconn_t * c) +{ + *(c->mysql.errormsg) = 0; + if (c->mysql.results) { + mysql_free_result(c->mysql.results); + c->mysql.results = 0; + } +} + +static char *MySQL_errormsg (dbconn_t * c) +{ + if (*(c->mysql.errormsg)) { + return string_copy(c->mysql.errormsg, "MySQL_errormsg:1"); + } + + return string_copy(mysql_error(c->mysql.handle), "MySQL_errormsg:2"); +} + +static int MySQL_close (dbconn_t * c) +{ + mysql_close(c->mysql.handle); + FREE(c->mysql.handle); + c->mysql.handle = 0; + + return 1; +} + +static int MySQL_execute (dbconn_t * c, const char * s) +{ + if (!mysql_query(c->mysql.handle, s)) { + c->mysql.results = mysql_store_result(c->mysql.handle); + if (c->mysql.results) { + return mysql_num_rows(c->mysql.results); + } + + /* Queries returning no input can return a NULL handle */ + if (!mysql_errno(c->mysql.handle)) { + return 0; + } + } + + return -1; +} + +static array_t *MySQL_fetch (dbconn_t * c, int row) +{ + array_t *v; + MYSQL_ROW target_row; + unsigned int i, num_fields; + + if (!c->mysql.results) { + return &the_null_array; + } + if (row < 0 || row > mysql_num_rows(c->mysql.results)) { + return &the_null_array; + } + + num_fields = mysql_num_fields(c->mysql.results); + if (num_fields < 1) { + return &the_null_array; + } + + if(row>0){ + mysql_data_seek(c->mysql.results, row - 1); + target_row = mysql_fetch_row(c->mysql.results); + if (!target_row) { + return &the_null_array; + } + } + + v = allocate_empty_array(num_fields); + for (i = 0; i < num_fields; i++) { + MYSQL_FIELD *field; + + field = mysql_fetch_field(c->mysql.results); + + if (row == 0) { + if (field == (MYSQL_FIELD *)NULL) { + v->item[i] = const0u; + } else { + v->item[i].type = T_STRING; + v->item[i].subtype = STRING_MALLOC; + v->item[i].u.string = string_copy(field->name, "f_db_fetch"); + } + continue; + } + + if (!field || !target_row[i]) { + v->item[i] = const0u; + } else { + switch (field->type) { + case FIELD_TYPE_TINY: + case FIELD_TYPE_SHORT: + case FIELD_TYPE_DECIMAL: + case FIELD_TYPE_LONG: + case FIELD_TYPE_INT24: + case FIELD_TYPE_LONGLONG: + v->item[i].type = T_NUMBER; + v->item[i].subtype = 0; + v->item[i].u.number = atoi(target_row[i]); + break; + + case FIELD_TYPE_FLOAT: + case FIELD_TYPE_DOUBLE: + v->item[i].type = T_REAL; + v->item[i].u.real = atof(target_row[i]); + break; + + case FIELD_TYPE_TINY_BLOB: + case FIELD_TYPE_MEDIUM_BLOB: + case FIELD_TYPE_LONG_BLOB: + case FIELD_TYPE_BLOB: + case FIELD_TYPE_STRING: + case FIELD_TYPE_VAR_STRING: + if (field->flags & BINARY_FLAG) { +#ifndef NO_BUFFER_TYPE + v->item[i].type = T_BUFFER; + v->item[i].u.buf = allocate_buffer(field->max_length); + write_buffer(v->item[i].u.buf, 0, target_row[i], field->max_length); +#else + v->item[i] = const0u; +#endif + } else { + v->item[i].type = T_STRING; + if (target_row[i]) { + v->item[i].subtype = STRING_MALLOC; + v->item[i].u.string = string_copy(target_row[i], "MySQL_fetch"); + } else { + v->item[i].subtype = STRING_CONSTANT; + v->item[i].u.string = ""; + } + } + break; + + default: + v->item[i] = const0u; + break; + } + } + } + + mysql_field_seek(c->mysql.results, 0); + return v; +} + +#ifndef MYSQL_SOCKET_ADDRESS +#define MYSQL_SOCKET_ADDRESS "/tmp/mysql.sock" +#endif + +static int MySQL_connect (dbconn_t * c, const char * host, const char * database, const char * username, const char * password) +{ + int ret; + MYSQL *tmp; + + tmp = ALLOCATE(MYSQL, TAG_DB, "MySQL_connect"); + tmp = mysql_init(tmp); + *(c->mysql.errormsg) = 0; + c->mysql.handle = mysql_real_connect(tmp, host, username, password, database, 0, MYSQL_SOCKET_ADDRESS, 0); + //c->mysql.handle = mysql_connect(tmp, host, username, password); + if (!c->mysql.handle) { + strncpy(c->mysql.errormsg, mysql_error(tmp), sizeof(c->mysql.errormsg)); + c->mysql.errormsg[sizeof(c->mysql.errormsg) - 1] = 0; + FREE(tmp); + return 0; + } + + ret = mysql_select_db(c->mysql.handle, database); + if (ret) { + strncpy(c->mysql.errormsg, mysql_error(c->mysql.handle), sizeof(c->mysql.errormsg)); + c->mysql.errormsg[sizeof(c->mysql.errormsg) - 1] = 0; + mysql_close(c->mysql.handle); + c->mysql.handle = 0; + FREE(tmp); + return 0; + } + + c->mysql.results = 0; + return 1; +} +#endif + +/* + * mSQL support + */ +#ifdef USE_MSQL +static void msql_cleanup (dbconn_t * c) +{ + if (c->msql.result_set) { + msqlFreeResult(c->msql.result_set); + c->msql.result_set = 0; + } +} + +static int msql_close (dbconn_t * c) +{ + msqlClose(c->msql.handle); + c->msql.handle = -1; + + return 1; +} + +static int msql_execute (dbconn_t * c, const char * s) +{ + if (msqlQuery(c->msql.handle, s) != -1) { + c->msql.result_set = msqlStoreResult(); + if (!c->msql.result_set) { + /* Query was an UPDATE or INSERT or DELETE */ + return 0; + } + return msqlNumRows(c->msql.result_set); + } + + return -1; +} + +static array_t *msql_fetch (dbconn_t * c, int row) +{ + int i, num_fields; + m_row this_row; + array_t *v; + + if (!c->msql.result_set) { + return &the_null_array; + } + if (row < 1 || row > msqlNumRows(c->msql.result_set)) { + return &the_null_array; + } + + num_fields = msqlNumFields(c->msql.result_set); + if (num_fields < 1) { + return &the_null_array; + } + + msqlDataSeek(c->msql.result_set, row - 1); + this_row = msqlFetchRow(c->msql.result_set); + if (!this_row) { + return &the_null_array; + } + + v = allocate_empty_array(num_fields); + for (i = 0; i < num_fields; i++) { + m_field *field; + + field = msqlFetchField(c->msql.result_set); + if (!field || !this_row[i]) { + v->item[i] = const0u; + } else { + switch (field->type) { + case INT_TYPE: + case UINT_TYPE: + v->item[i].type = T_NUMBER; + v->item[i].u.number = atoi(this_row[i]); + break; + + case REAL_TYPE: + case MONEY_TYPE: + v->item[i].type = T_REAL; + v->item[i].u.real = atof(this_row[i]); + break; + + case CHAR_TYPE: + case TEXT_TYPE: + case DATE_TYPE: + case TIME_TYPE: + v->item[i].type = T_STRING; + v->item[i].subtype = STRING_MALLOC; + v->item[i].u.string = string_copy(this_row[i], "msql_fetch"); + break; + + default: + v->item[i] = const0u; + break; + } + } + } + + msqlFieldSeek(c->msql.result_set, 0); + return v; +} + +static int msql_connect (dbconn_t * c, char * host, char * database, char * username, char * password) +{ + c->msql.handle = msqlConnect(host); + if (c->msql.handle < 1) { + return 0; + } + + if (msqlSelectDB(c->msql.handle, database) == -1) { + msqlClose(c->msql.handle); + return 0; + } + + c->msql.result_set = 0; + return 1; +} + +static char *msql_errormsg (dbconn_t * c) +{ + return string_copy(msqlErrMsg, "msql_errormsg"); +} +#endif + +/* + * SQLite v2 support + * ajandurah@demonslair (Mark Lyndoe) + */ +#ifdef USE_SQLITE2 +static int SQLite2_connect (dbconn_t * c, const char * host, const char * database, const char * username, const char * password) +{ + c->SQLite2.handle = sqlite_open(database, 0666, &c->SQLite2.errormsg); + if (!c->SQLite2.handle) { + sqlite_close(c->SQLite2.handle); + return 0; + } + + c->SQLite2.nrows = 0; + c->SQLite2.ncolumns = 0; + c->SQLite2.last_row = 0; + c->SQLite2.step_res = 0; + c->SQLite2.values = NULL; + c->SQLite2.col_names = NULL; + c->SQLite2.vm = NULL; + return 1; +} + +static int SQLite2_close (dbconn_t * c) +{ + if (c->SQLite2.errormsg) + free(c->SQLite2.errormsg); + + if (c->SQLite2.vm) + sqlite_finalize(c->SQLite2.vm, NULL); + + sqlite_close(c->SQLite2.handle); + + c->SQLite2.handle = 0; + c->SQLite2.errormsg = 0; + c->SQLite2.nrows = 0; + c->SQLite2.ncolumns = 0; + c->SQLite2.last_row = 0; + c->SQLite2.step_res =0; + c->SQLite2.vm = NULL; + c->SQLite2.values = NULL; + c->SQLite2.col_names = NULL; + return 1; +} + +static void SQLite2_cleanup (dbconn_t * c) +{ + if (c->SQLite2.errormsg) { + free(c->SQLite2.errormsg); + c->SQLite2.errormsg = 0; + } + + if (c->SQLite2.vm) { + sqlite_finalize(c->SQLite2.vm, NULL); + c->SQLite2.vm = 0; + c->SQLite2.last_row = 0; + c->SQLite2.step_res = 0; + } +} + +static int SQLite2_execute (dbconn_t * c, const char * s) +{ + char **result; + const char *tail; + int ret; + + /* Oddly enough a sqlite_get_table will execute sql that inserts and updates! */ + if (sqlite_get_table(c->SQLite2.handle, s, &result, &c->SQLite2.nrows, &c->SQLite2.ncolumns, NULL) != SQLITE_OK) { + sqlite_free_table(result); + return 0; + } + else { + sqlite_free_table(result); + c->SQLite2.sql = string_copy(s, "SQLite2_execute"); + c->SQLite2.last_row = 0; + c->SQLite2.step_res = 0; + + return c->SQLite2.nrows; + } + + return -1; +} + +static array_t *SQLite2_fetch (dbconn_t * c, int row) +{ + int last_row, length, i, l, r; + char *p_end; + const char *tail; + double d; + array_t *v; + + if (!c->SQLite2.vm) { + /* We don't have a vm yet because the sql has not been compiled. + * This is down to db_exec using sqlite_get_table to execute the sql in the + * first instance. This is the reason we saved the sql into the SQLite + * structure, compile it now and create a vm. We return a null array only + * if the compile fails. + */ + r = sqlite_compile(c->SQLite2.handle, c->SQLite2.sql, NULL, &c->SQLite2.vm, &c->SQLite2.errormsg); + if (r != SQLITE_OK || !c->SQLite2.vm) + return &the_null_array; + } + + if (c->SQLite2.step_res && c->SQLite2.step_res != SQLITE_ROW) { + return &the_null_array; + } + + if (row < 0 || row > c->SQLite2.nrows) { + return &the_null_array; + } + + if (c->SQLite2.ncolumns < 1) { + return &the_null_array; + } + + /* If the fetch is for row 0 then we don't return a row containing data values + * instead we return the column names. This has proven quite useful in a number + * of circumstances when they are unknown ahead of the query. Unlike SQLite3 we + * have no means of obtaining them without stepping the virtual machine so we + * have no choice. We will have to check the last_row and step_rc later to make + * sure we use the values here before we step again. + */ + if (row == 0) { + c->SQLite2.step_res = sqlite_step(c->SQLite2.vm, NULL, &c->SQLite2.values, &c->SQLite2.col_names); + if (c->SQLite2.step_res == SQLITE_ROW || c->SQLite2.step_res == SQLITE_DONE) { + v = allocate_empty_array(c->SQLite2.ncolumns); + for (i = 0; i < c->SQLite2.ncolumns; i++) { + v->item[i].type = T_STRING; + v->item[i].subtype = STRING_MALLOC; + v->item[i].u.string = string_copy((char *)c->SQLite2.col_names[i], "SQLite2_fetch"); + } + + return v; + } + + return &the_null_array; + } + + /* There is no quick entry to a row in the prepared statement. Thus we have + * too loop through until we reach the desired row, but only if the last row + * that we fetched is not the previous row... confused? join the club. + */ + last_row = c->SQLite2.last_row; + + /* If the requested row is before the last row that was accessed then we need + * to re-compile the sql and recreate the virtual machine. SQLite3 provides a + * facility to reset a vm however SQLite2 does not. This is a downfall of + * SQLite in general though, we need to restart everything and walk through + * all of the results again until we get to the row we want... sigh + */ + if (row < last_row) { + free(c->SQLite2.errormsg); + sqlite_finalize(c->SQLite2.vm, NULL); + + if (sqlite_compile(c->SQLite2.handle, c->SQLite2.sql, &tail, &c->SQLite2.vm, &c->SQLite2.errormsg) != SQLITE_OK) + return 0; + + c->SQLite2.last_row = 0; + c->SQLite2.step_res = 0; + last_row = 0; + } + + /* If the requested row is the same as the last one, ie: it's been requested + * again! we do not need to step forward, so we miss the row location loop + * and get straight to the nitty gritty of building the result array. If not + * we loop through from the last_row requested to the one requested this time + * using sqlite_step(). As long as the result is SQLITE_ROW we move on, if + * not then either an error occured or there are no more rows so we return a + * null array. The result is stored in the SQLite structure for later checks + * so if fetch is called again on a completed or errornous statement we can + * fail out sooner saving time. + */ + if ((row != last_row) && (last_row < row)) { + for (i = last_row; i < row; i++) { + c->SQLite2.step_res = sqlite_step(c->SQLite2.vm, NULL, &c->SQLite2.values, &c->SQLite2.col_names); + if (c->SQLite2.step_res == SQLITE_ROW) + break; + else + return &the_null_array; + } + } + + /* SQLite v2 does not provide any functions for obtaining the values based on + * their datatypes like v3 does. It is completely typeless and everything is + * returned as a (char *). Thus we need a way of determining if the value is + * numeric or a string. I do make some assumptions here, but all in all it + * does work for the vast majority of cases. There is no support for blobs + * to be returned as LPC buffers with v2. Support for binary data in v2 is + * suspect at best and is not recommended anyway, if you need that use v3. + * + * To determine the datatype, we do the following. Run the value through + * strtoul() if it fails then the value could not be converted to a number + * so we assume it's a string and return it as such. If it works but also + * has trailing data, then it might be a real number or a string. Both + * "12.34" and "12 bottles" will cause strtoul() to work returning 12 but + * both will also have trailing data. Thus we try converting it to a real + * number using strtod() if this fails then we assume its a string that + * starts with a number ie: "12 bottles" and return it as a string. If it + * works then we return it as a real number (float). + * + * It's by no means perfect, but it does catch pretty much everything I've + * thrown at it and is the best solution, bar walking the embedded datatype + * description, if one was set, and working it out from that. + */ + v = allocate_empty_array(c->SQLite2.ncolumns); + for (i = 0; i < c->SQLite2.ncolumns; i++) { + /* If we have a NULL value get out now or we'll segfault */ + if (c->SQLite2.values[i] == NULL) { + v->item[i] = const0u; + continue; + } + + errno = 0; + l = strtoul(c->SQLite2.values[i], &p_end, 10); + if (errno != 0 || c->SQLite2.values[i] == p_end) { + /* The conversion failed so assume it's a string */ + v->item[i].type = T_STRING; + v->item[i].subtype = STRING_MALLOC; + v->item[i].u.string = string_copy((char *)c->SQLite2.values[i], "SQLite2_fetch"); + } + + else if (*p_end != 0) { + /* The conversion left trailing characters behind, see if its a float */ + errno = 0; + d = strtod(c->SQLite2.values[i], &p_end); + if (errno != 0 || c->SQLite2.values[i] == p_end || *p_end != 0) { + /* The conversion to float failed so it must be a string */ + v->item[i].type = T_STRING; + v->item[i].subtype = STRING_MALLOC; + v->item[i].u.string = string_copy((char *)c->SQLite2.values[i], "SQLite2_fetch"); + } + else { + /* It was a floating point number */ + v->item[i].type = T_REAL; + v->item[i].u.real = (float)d; + } + } + + else if (errno == 0) { + /* It was an integer */ + v->item[i].type = T_NUMBER; + v->item[i].u.number = (int)l; + } + + else { + /* No idea what it was */ + v->item[i] = const0u; + } + } + + c->SQLite2.last_row = row; + return v; +} + +static char *SQLite2_errormsg (dbconn_t * c) +{ + return string_copy(c->SQLite2.errormsg, "SQLite2_errormsg"); +} +#endif + + +/* + * SQLite v3 support + * ajandurah@demonslair (Mark Lyndoe) + */ +#ifdef USE_SQLITE3 +static int SQLite3_connect (dbconn_t * c, const char * host, const char * database, const char * username, const char * password) +{ + if (sqlite3_open(database, &c->SQLite3.handle)) { + strncpy(c->SQLite3.errormsg, sqlite3_errmsg(c->SQLite3.handle), sizeof(c->SQLite3.errormsg)); + c->SQLite3.errormsg[sizeof(c->SQLite3.errormsg) - 1] = 0; + sqlite3_close(c->SQLite3.handle); + return 0; + } + + c->SQLite3.results = 0; + c->SQLite3.nrows = 0; + c->SQLite3.last_row = 0; + c->SQLite3.step_res = 0; + return 1; +} + +static int SQLite3_close (dbconn_t * c) +{ + if (c->SQLite3.results) { + sqlite3_finalize(c->SQLite3.results); + } + + sqlite3_close(c->SQLite3.handle); + c->SQLite3.handle = 0; + c->SQLite3.nrows = 0; + c->SQLite3.last_row = 0; + c->SQLite3.step_res = 0; + return 1; +} + +static void SQLite3_cleanup (dbconn_t * c) +{ + if (c->SQLite3.results) { + sqlite3_finalize(c->SQLite3.results); + c->SQLite3.results = 0; + c->SQLite3.last_row = 0; + c->SQLite3.step_res = 0; + } +} + +static int SQLite3_execute (dbconn_t * c, const char * s) +{ + char **result; + + if (sqlite3_prepare(c->SQLite3.handle, s, -1, &c->SQLite3.results, 0) != SQLITE_OK) { + strncpy(c->SQLite3.errormsg, sqlite3_errmsg(c->SQLite3.handle), sizeof(c->SQLite3.errormsg)); + c->SQLite3.errormsg[sizeof(c->SQLite3.errormsg) - 1] = 0; + return 0; + } + + /* There has to be a better way of determining the number of rows in the result + * set. sqlite3_prepare() does not provide them, since we need to call sqlite3_step() + * to walk through them, which we dont want to do until db_fetch() is called. This + * hack means we actually have to execute the full SQL statement to get the row + * total.. expensive time wise unfortunately. + */ + if (c->SQLite3.results) { + if (sqlite3_get_table(c->SQLite3.handle, s, &result, &c->SQLite3.nrows, &c->SQLite3.ncolumns, NULL) != SQLITE_OK) { + sqlite3_free_table(result); + sqlite3_finalize(c->SQLite3.results); + return 0; + } + + sqlite3_free_table(result); + c->SQLite3.last_row = 0; + c->SQLite3.step_res = 0; + return c->SQLite3.nrows; + } + + return -1; +} + +static array_t *SQLite3_fetch (dbconn_t * c, int row) +{ + int cols, last_row, length, i, r; + array_t *v; + + if (!c->SQLite3.results) { + return &the_null_array; + } + + if (c->SQLite3.step_res && c->SQLite3.step_res != SQLITE_ROW) { + return &the_null_array; + } + + if (row < 0 || row > c->SQLite3.nrows) { + return &the_null_array; + } + + cols = sqlite3_column_count(c->SQLite3.results); + if (cols < 1) { + return &the_null_array; + } + + /* If the fetch is for row 0 then we don't return a row from the prepared + * statement, instead we return an array containing the column names. This + * ability is useful in a number of circumstances when the column names are + * not known in advance for a query. We do not step the statement nor do we + * adjust the last_row index since sqlite provides a method to obtain the + * column names at any time. + */ + if (row == 0) { + v = allocate_empty_array(cols); + for (i = 0; i< cols; i++) { + v->item[i].type = T_STRING; + v->item[i].subtype = STRING_MALLOC; + v->item[i].u.string = string_copy((char *)sqlite3_column_name(c->SQLite3.results, i), "SQLite3_fetch"); + } + + return v; + } + + /* There is no quick entry to a row in the prepared statement. Thus we have + * too loop through till we reach the desired row, but only if the last row + * that we fetched is not the previous row... confused? join the club. + */ + last_row = c->SQLite3.last_row; + + /* If the requested row is before the last row that was accessed then we + * reset the compiled statement before continuing. This is because we can't + * just select a row at will using sqlite and we can't rewind a step either. + * We could just reset the result statement at the end of this function like + * the msql and mysql versions, but that gets expensive next time it's called + * if we need to walk through everything again... sigh + */ + if (row < last_row) { + sqlite3_reset(c->SQLite3.results); + c->SQLite3.last_row = 0; + c->SQLite3.step_res = 0; + last_row = 0; + } + + /* If the requested row is the same as the last one, ie: it's been requested + * again! we do not need to step forward, so we miss the row location loop + * and get straight to the nitty gritty of building the result array. If not + * we loop through from the last_row requested to the one requested this time + * using sqlite3_step(). As long as the result is SQLITE_ROW we move on, if + * not then either an error occured or there are no more rows so we return a + * null array. The result is stored in the sqlite structure for later checks + * so if fetch is called again on a completed or errornous statement we can + * fail out sooner saving time. + */ + if ((row != last_row) && (last_row < row)) { + for (i = last_row; i < row; i++) { + c->SQLite3.step_res = sqlite3_step(c->SQLite3.results); + + if (c->SQLite3.step_res == SQLITE_ROW) + break; + else + return &the_null_array; + } + } + + v = allocate_empty_array(cols); + for (i = 0; i < cols; i++) { + switch (sqlite3_column_type(c->SQLite3.results, i)) { + case SQLITE_INTEGER: + v->item[i].type = T_NUMBER; + v->item[i].u.number = sqlite3_column_int(c->SQLite3.results, i); + break; + + case SQLITE_FLOAT: + v->item[i].type = T_REAL; + v->item[i].u.real = (float)sqlite3_column_double(c->SQLite3.results, i); + break; + + case SQLITE3_TEXT: + v->item[i].type = T_STRING; + v->item[i].subtype = STRING_MALLOC; + v->item[i].u.string = string_copy((char *)sqlite3_column_text(c->SQLite3.results, i), "SQLite3_fetch"); + break; + + case SQLITE_BLOB: +#ifndef NO_BUFFER_TYPE +length = sqlite3_column_bytes(c->SQLite3.results, i); +v->item[i].type = T_BUFFER; +v->item[i].u.buf = allocate_buffer(length); +write_buffer(v->item[i].u.buf, 0, (char *)sqlite3_column_blob(c->SQLite3.results, i), length); +#else + v->item[i] = const0u; +#endif + break; + + default: + v->item[i] = const0u; + break; + } + } + + c->SQLite3.last_row = row; + return v; +} + +static char *SQLite3_errormsg (dbconn_t * c) +{ + if (*(c->SQLite3.errormsg)) { + return string_copy((char *)c->SQLite3.errormsg, "SQLite3_errormsg:1"); + } + + return string_copy((char *)sqlite3_errmsg(c->SQLite3.handle), "SQLite3_errormsg:2"); +} +#endif + /* + * Postgres support + */ +#ifdef USE_POSTGRES +static void Postgres_cleanup (dbconn_t * c) +{ + c->postgres.res = 0; +} + +static char *Postgres_errormsg (dbconn_t * c) +{ + return string_copy(PQerrorMessage(c->postgres.conn), "postgresql_errormsg"); +} + +static int Postgres_close (dbconn_t * c) +{ + PQclear(c->postgres.res); + PQfinish(c->postgres.conn); + return 1; +} + +static int Postgres_execute (dbconn_t * c, const char * s) +{ + c->postgres.res = PQexec( c->postgres.conn, s ); + + if( (PQresultStatus( c->postgres.res )) == PGRES_TUPLES_OK ) { + return PQntuples( c->postgres.res ); + } + + if( PQresultStatus( c->postgres.res ) == PGRES_COMMAND_OK ) { + return 0; + } + + fprintf(stderr, "FT: Query failed: \"%s\"\n", PQresultErrorMessage(c->postgres.res)); + return -1; +} + +static int Postgres_connect (dbconn_t * c, const char * host, const char * database, const char * username, const char * password) +{ + int buffsize; + + char *connstr = "host = '%s' dbname = '%s' user = '%s' password = '%s'"; + buffsize = strlen(connstr) + strlen(host) + strlen(database) + strlen(username) + strlen(password); + char *conninfo = malloc(buffsize); + if( conninfo != NULL ) { + sprintf(conninfo,connstr,host,database,username,password); + } + + c->postgres.conn = PQconnectdb( conninfo ); + free(conninfo); + + if( (PQstatus(c->postgres.conn) != CONNECTION_OK) ) { + return 0; + } + return 1; +} + +static array_t *Postgres_fetch (dbconn_t * c, int row) +{ + array_t *v; + char * field; + unsigned int i, num_fields; + + if (!c->postgres.res) { + return &the_null_array; + } + + num_fields = PQnfields( c->postgres.res ); + + if (row < -1 || row > PQntuples( c->postgres.res )) { + return &the_null_array; + } + + if (num_fields < 1) { + return &the_null_array; + } + + if(row==-1) { + v = allocate_empty_array(num_fields); + for( i = 0;i < num_fields; i++ ) { + v->item[i].type = T_STRING; + v->item[i].subtype = STRING_MALLOC; + v->item[i].u.string = string_copy(PQfname(c->postgres.res,i), "f_db_fetch"); + } + } + + if(row>=0){ + v = allocate_empty_array(num_fields); + for (i = 0;i < num_fields;i++) { + if( PQgetisnull(c->postgres.res, row, i) ) { + v->item[i] = const0u; + } else { + v->item[i].type = T_STRING; + v->item[i].subtype = STRING_MALLOC; + v->item[i].u.string = string_copy(PQgetvalue(c->postgres.res,row,i),"postgres_fetch"); + } + } + } + return v; +} +#endif diff --git a/fluffos-2.23-ds03/packages/db.h b/fluffos-2.23-ds03/packages/db.h new file mode 100644 index 0000000..c51d126 --- /dev/null +++ b/fluffos-2.23-ds03/packages/db.h @@ -0,0 +1,148 @@ +#ifndef PACKAGES_DB_H +#define PACKAGES_DB_H + +#ifdef PACKAGE_DB + +#ifdef USE_POSTGRES +#include "/usr/include/postgresql/libpq-fe.h" +#endif + +#ifdef USE_MSQL +/* MSQL v2 requires this so that it knows the right prototypes */ +#define _OS_UNIX + +#ifdef INCL_LOCAL_MSQL_H +#include "/usr/local/include/msql.h" +#endif +#ifdef INCL_LOCAL_MSQL_MSQL_H +#include "/usr/local/msql/include/msql.h" +#endif +#ifdef INCL_LOCAL_MINERVA_MSQL_H +#include "/usr/local/Minerva/include/msql.h" +#endif +#ifdef INCL_LIB_HUGHES_MSQL_H +#include "/usr/lib/Hughes/include/msql.h" +#endif +#endif + +#ifdef USE_MYSQL +#define USE_OLD_FUNCTIONS +#ifndef TCC +#ifdef INCL_MYSQL_INCLUDE_MYSQL_H +#include "/usr/mysql/include/mysql/mysql.h" +#endif +#ifdef INCL_LOCAL_MYSQL_H +#include "/usr/local/include/mysql.h" +#endif +#ifdef INCL_LOCAL_INCLUDE_MYSQL_MYSQL_H +#include "/usr/local/include/mysql/mysql.h" +#endif +#ifdef INCL_LOCAL_MYSQL_MYSQL_H +#include "/usr/local/mysql/include/mysql.h" +#endif +#ifdef INCL_MYSQL_MYSQL_H +#include "/usr/include/mysql/mysql.h" +#endif +#else +#ifdef INCL_LOCAL_MYSQL_H +#include +#endif +#ifdef INCL_LOCAL_INCLUDE_MYSQL_MYSQL_H +#include +#endif +#ifdef INCL_LOCAL_MYSQL_MYSQL_H +#include "/usr/local/mysql/include/mysql.h" +#endif +#ifdef INCL_MYSQL_MYSQL_H +#include +#endif +#endif +#undef USE_OLD_FUNCTIONS +#endif + +#ifdef USE_SQLITE2 +#include "/usr/include/sqlite.h" +#endif + +#ifdef USE_SQLITE3 +#include "/usr/include/sqlite3.h" +#endif + + +typedef union dbconn_u { +#ifdef USE_POSTGRES + struct tmp_postgres { + PGconn *conn; + PGresult *res; + } postgres; +#endif +#ifdef USE_MSQL + struct tmp_msql { + int handle; + m_result * result_set; + } msql; +#endif +#ifdef USE_MYSQL + struct tmp_mysql { + char errormsg[256]; + MYSQL *handle; + MYSQL_RES *results; + } mysql; +#endif +#ifdef USE_SQLITE2 + struct tmp_sqlite2 { + sqlite *handle; + sqlite_vm *vm; + int nrows; + int ncolumns; + int last_row; + int step_res; + const char **values; + const char **col_names; + char *sql; + char *errormsg; + } SQLite2; +#endif +#ifdef USE_SQLITE3 + struct tmp_sqlite3 { + sqlite3 *handle; + sqlite3_stmt *results; + int nrows; + int ncolumns; + int last_row; + int step_res; + char errormsg[256]; + } SQLite3; +#endif +} dbconn_t; + +/* + * Structure so we can have a lookup table for the specific database + */ +typedef struct db_defn_s { + const char *name; + int (*connect)(dbconn_t *, const char *, const char *, const char *, const char *); + int (*close)(dbconn_t *); + int (*execute)(dbconn_t *, const char *); + array_t * (*fetch)(dbconn_t *, int); + int (*commit)(dbconn_t *); + int (*rollback)(dbconn_t *); + void (*cleanup)(dbconn_t *); + void (*status)(dbconn_t *, outbuffer_t *); + char * (*error)(dbconn_t *); +} db_defn_t; + +#define DB_FLAG_EMPTY 0x1 + +typedef struct _db { + int flags; + db_defn_t *type; + dbconn_t c; +} db_t; + +void db_cleanup (void); +svalue_t *valid_database (const char * action, array_t * info); +db_t *find_db_conn (int handle); +#endif /* PACKAGES_DB */ + +#endif /* PACKAGES_DB_H */ diff --git a/fluffos-2.23-ds03/packages/db_spec.c b/fluffos-2.23-ds03/packages/db_spec.c new file mode 100644 index 0000000..ea13cb0 --- /dev/null +++ b/fluffos-2.23-ds03/packages/db_spec.c @@ -0,0 +1,9 @@ +#include "spec.h" + +int db_close(int); +int db_commit(int); +int db_connect(string, string, string|void, int|void); +mixed db_exec(int, string); +mixed *db_fetch(int, int); +int db_rollback(int); +string db_status(void); diff --git a/fluffos-2.23-ds03/packages/debug.c b/fluffos-2.23-ds03/packages/debug.c new file mode 100644 index 0000000..c63d3d4 --- /dev/null +++ b/fluffos-2.23-ds03/packages/debug.c @@ -0,0 +1,78 @@ +void f_thread() { + + int sv[2]; + fd = find_new_socket(); + if (fd < 0) + return fd; + if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) + return EESOCKET; + ret = fork(); + if (ret == -1) { + error("fork() in debug() failed: %s\n", strerror(errno)); + } + if(ret){ + close(sv[1]); + lpc_socks[fd].fd = sv[0]; + lpc_socks[fd].flags = S_EXTERNAL; + set_read_callback(fd, sp-3); + set_write_callback(fd, sp-2); + set_close_callback(fd, sp-1); + lpc_socks[fd].owner_ob = current_object; + lpc_socks[fd].mode = MUD; + lpc_socks[fd].state = STATE_DATA_XFER; + memset((char *) &lpc_socks[fd].l_addr, 0, sizeof(lpc_socks[fd].l_addr)); + memset((char *) &lpc_socks[fd].r_addr, 0, sizeof(lpc_socks[fd].r_addr)); + lpc_socks[fd].owner_ob = current_object; + lpc_socks[fd].release_ob = NULL; + lpc_socks[fd].r_buf = NULL; + lpc_socks[fd].r_off = 0; + lpc_socks[fd].r_len = 0; + lpc_socks[fd].w_buf = NULL; + lpc_socks[fd].w_off = 0; + lpc_socks[fd].w_len = 0; + + current_object->flags |= O_EFUN_SOCKET; + return fd; + } + close(sv[0]); + function_to_call_t cb; + memset(&cb, 0, sizeof(function_to_call_t)); + process_efun_callback(0, &cb, F_THREAD); + for(i=0; i<5; i++) + if(external_port[i].port) + close(external_port[i].fd); //close external ports + for(i=0;itype) { + + case T_OBJECT: + break; + default: + save_svalue_depth = 0; + int len = svalue_save_size(message); + if (save_svalue_depth > MAX_SAVE_SVALUE_DEPTH) { + OS_socket_write(sv[1], "\x00\x00\x00\x11\"result too big\"", 21); + break; + } + char *buf = (char *) + DMALLOC(len + 5, TAG_TEMPORARY, "socket_write: default"); + if (buf == NULL) + break; + *(INT_32 *) buf = htonl((long) len); + len += 4; + buf[4] = '\0'; + p = buf + 4; + save_svalue(message, &p); + int ret,written = 0; + while(written < len){ + ret = OS_socket_write(sv[1], buf+written, len-written); + if(ret < 0) + break; + written += ret; + } + break; + } + fflush(0); + exit(0); +} diff --git a/fluffos-2.23-ds03/packages/debug.h b/fluffos-2.23-ds03/packages/debug.h new file mode 100644 index 0000000..e69de29 diff --git a/fluffos-2.23-ds03/packages/debug_spec.c b/fluffos-2.23-ds03/packages/debug_spec.c new file mode 100644 index 0000000..e69de29 diff --git a/fluffos-2.23-ds03/packages/develop.c b/fluffos-2.23-ds03/packages/develop.c new file mode 100644 index 0000000..fd13879 --- /dev/null +++ b/fluffos-2.23-ds03/packages/develop.c @@ -0,0 +1,271 @@ +#ifdef LATTICE +#include "/lpc_incl.h" +#include "/comm.h" +#include "/md.h" +#include "/sprintf.h" +#else +#include "../lpc_incl.h" +#include "../comm.h" +#include "../md.h" +#include "../sprintf.h" +#include "../efun_protos.h" +#endif + +static object_t *ob; + +#ifdef F_DEBUG_INFO +void +f_debug_info (void) +{ + svalue_t *arg; + outbuffer_t out; + + outbuf_zero(&out); + arg = sp - 1; + switch (arg[0].u.number) { + case 0: + { + int i, flags; + object_t *obj2; + + ob = arg[1].u.ob; + flags = ob->flags; + outbuf_addv(&out, "O_HEART_BEAT : %s\n", + flags & O_HEART_BEAT ? "TRUE" : "FALSE"); +#ifndef NO_WIZARDS + outbuf_addv(&out, "O_IS_WIZARD : %s\n", + flags & O_IS_WIZARD ? "TRUE" : "FALSE"); +#endif +#ifdef NO_ADD_ACTION + outbuf_addv(&out, "O_LISTENER : %s\n", + flags & O_LISTENER ? "TRUE" : "FALSE"); +#else + outbuf_addv(&out, "O_ENABLE_COMMANDS : %s\n", + flags & O_ENABLE_COMMANDS ? "TRUE" : "FALSE"); +#endif + outbuf_addv(&out, "O_CLONE : %s\n", + flags & O_CLONE ? "TRUE" : "FALSE"); + outbuf_addv(&out, "O_VIRTUAL : %s\n", + flags & O_VIRTUAL ? "TRUE" : "FALSE"); + outbuf_addv(&out, "O_DESTRUCTED : %s\n", + flags & O_DESTRUCTED ? "TRUE" : "FALSE"); + outbuf_addv(&out, "O_ONCE_INTERACTIVE: %s\n", + flags & O_ONCE_INTERACTIVE ? "TRUE" : "FALSE"); + outbuf_addv(&out, "O_RESET_STATE : %s\n", + flags & O_RESET_STATE ? "TRUE" : "FALSE"); + outbuf_addv(&out, "O_WILL_CLEAN_UP : %s\n", + flags & O_WILL_CLEAN_UP ? "TRUE" : "FALSE"); + outbuf_addv(&out, "O_WILL_RESET: %s\n", + flags & O_WILL_RESET ? "TRUE" : "FALSE"); +#ifdef HAVE_ZLIB + if (ob->interactive) { + outbuf_addv(&out, "O_COMPRESSED : %s\n", + ob->interactive->compressed_stream ? "TRUE" : + "FALSE"); + + } +#endif + +#ifndef NO_LIGHT + outbuf_addv(&out, "total light : %d\n", ob->total_light); +#endif +#ifndef NO_RESETS + outbuf_addv(&out, "next_reset : %d\n", ob->next_reset); +#endif + outbuf_addv(&out, "time_of_ref : %d\n", ob->time_of_ref); + outbuf_addv(&out, "ref : %d\n", ob->ref); +#ifdef DEBUG + outbuf_addv(&out, "extra_ref : %d\n", ob->extra_ref); +#endif + outbuf_addv(&out, "name : '/%s'\n", ob->obname); + outbuf_addv(&out, "next_all : OBJ(/%s)\n", + ob->next_all ? ob->next_all->obname : "NULL"); + if (obj_list == ob) + outbuf_add(&out, "This object is the head of the object list.\n"); + for (obj2 = obj_list, i = 1; obj2; obj2 = obj2->next_all, i++) + if (obj2->next_all == ob) { + outbuf_addv(&out, "Previous object in object list: OBJ(/%s)\n", + obj2->obname); + outbuf_addv(&out, "position in object list:%d\n", i); + } + break; + } + case 1: + ob = arg[1].u.ob; + + outbuf_addv(&out, "program ref's %d\n", ob->prog->ref); + outbuf_addv(&out, "Name /%s\n", ob->prog->filename); + outbuf_addv(&out, "program size %d\n", + ob->prog->program_size); + outbuf_addv(&out, "function flags table %d (%d) \n", + ob->prog->last_inherited + ob->prog->num_functions_defined, + (ob->prog->last_inherited + ob->prog->num_functions_defined)* sizeof(unsigned short)); + outbuf_addv(&out, "compiler function table %d (%d) \n", + ob->prog->num_functions_defined, + ob->prog->num_functions_defined * sizeof(function_t)); + outbuf_addv(&out, "num strings %d\n", ob->prog->num_strings); + outbuf_addv(&out, "num vars %d (%d)\n", ob->prog->num_variables_defined, + ob->prog->num_variables_defined * (sizeof(char *) + sizeof(short))); + outbuf_addv(&out, "num inherits %d (%d)\n", ob->prog->num_inherited, + ob->prog->num_inherited * sizeof(inherit_t)); + outbuf_addv(&out, "total size %d\n", ob->prog->total_size); + break; + case 2: + { + int i; + ob = arg[1].u.ob; + for (i=0; iprog->num_variables_total; i++) { + /* inefficient, but: */ + outbuf_addv(&out, "%s: ", variable_name(ob->prog, i)); + svalue_to_string(&ob->variables[i], &out, 2, 0, 0); + outbuf_add(&out, "\n"); + } + break; + } + default: + bad_arg(1, F_DEBUG_INFO); + } + pop_stack(); + pop_stack(); + outbuf_push(&out); +} +#endif + +#ifdef F_REFS +void +f_refs (void) +{ + int r; + + switch (sp->type) { + case T_MAPPING: + r = sp->u.map->ref; + break; + case T_CLASS: + case T_ARRAY: + r = sp->u.arr->ref; + break; + case T_OBJECT: + r = sp->u.ob->ref; + break; + case T_FUNCTION: + r = sp->u.fp->hdr.ref; + break; +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + r = sp->u.buf->ref; + break; +#endif + case T_STRING: + if(sp->subtype & STRING_COUNTED) + r = MSTR_REF(sp->u.string); + else + r = 0; + break; + default: + r = 0; + break; + } + free_svalue(sp, "f_refs"); + put_number(r - 1); /* minus 1 to compensate for being arg of + * refs() */ +} +#endif + +#ifdef F_DESTRUCTED_OBJECTS +void f_destructed_objects (void) +{ + int i; + array_t *ret; + object_t *ob; + + ret = allocate_empty_array(tot_dangling_object); + ob = obj_list_dangling; + + for (i = 0; i < tot_dangling_object; i++) { + ret->item[i].type = T_ARRAY; + ret->item[i].u.arr = allocate_empty_array(2); + ret->item[i].u.arr->item[0].type = T_STRING; + ret->item[i].u.arr->item[0].subtype = STRING_SHARED; + ret->item[i].u.arr->item[0].u.string = make_shared_string(ob->obname); + ret->item[i].u.arr->item[1].type = T_NUMBER; + ret->item[i].u.arr->item[1].u.number = ob->ref; + + ob = ob->next_all; + } + + push_refed_array(ret); +} +#endif + +#if (defined(DEBUGMALLOC) && defined(DEBUGMALLOC_EXTENSIONS)) +#ifdef F_DEBUGMALLOC +void +f_debugmalloc (void) +{ + char *res; + + res = dump_debugmalloc((sp - 1)->u.string, sp->u.number); + free_string_svalue(--sp); + sp->subtype = STRING_MALLOC; + sp->u.string = res; +} +#endif + +#ifdef F_SET_MALLOC_MASK +void +f_set_malloc_mask (void) +{ + set_malloc_mask((sp--)->u.number); +} +#endif + +#ifdef F_CHECK_MEMORY +void +f_check_memory (void) +{ + check_all_blocks((sp--)->u.number); +} +#endif +#endif /* (defined(DEBUGMALLOC) && + * defined(DEBUGMALLOC_EXTENSIONS)) */ + +#ifdef F_TRACE +void +f_trace (void) +{ + int ot = -1; + + if (command_giver && command_giver->interactive) { + ot = command_giver->interactive->trace_level; + command_giver->interactive->trace_level = sp->u.number; + } + sp->u.number = ot; +} +#endif + +#ifdef F_TRACEPREFIX +void +f_traceprefix (void) +{ + char *old = 0; + + if (command_giver && command_giver->interactive) { + old = command_giver->interactive->trace_prefix; + if (sp->type & T_STRING) { + const char *p = sp->u.string; + if (*p == '/') p++; + + command_giver->interactive->trace_prefix = make_shared_string(p); + free_string_svalue(sp); + } else + command_giver->interactive->trace_prefix = 0; + } + if (old) { + put_malloced_string(add_slash(old)); + free_string(old); + } else + *sp = const0; +} +#endif + diff --git a/fluffos-2.23-ds03/packages/develop_spec.c b/fluffos-2.23-ds03/packages/develop_spec.c new file mode 100644 index 0000000..7a56a44 --- /dev/null +++ b/fluffos-2.23-ds03/packages/develop_spec.c @@ -0,0 +1,32 @@ +#include "spec.h" + + mixed debug_info(int, object); + int refs(mixed); +#ifdef DEBUG + mixed *destructed_objects(); +#endif + +/* dump_prog: disassembler... comment out this line if you don't want the + disassembler compiled in. +*/ + void dump_prog(object,...); + +#if defined(PROFILING) && defined(HAS_MONCONTROL) + void moncontrol(int); +#endif + +#if (defined(DEBUGMALLOC) && defined(DEBUGMALLOC_EXTENSIONS)) + string debugmalloc(string, int); + void set_malloc_mask(int); + string check_memory(int default: 0); +#endif + +#ifdef TRACE + string traceprefix(string | int); + int trace(int); +#endif + +#if defined(NeXT) && defined(NEXT_MALLOC_DEBUG) + int malloc_check(); + int malloc_debug(int); +#endif diff --git a/fluffos-2.23-ds03/packages/dslib.c b/fluffos-2.23-ds03/packages/dslib.c new file mode 100644 index 0000000..e69de29 diff --git a/fluffos-2.23-ds03/packages/dslib_spec.c b/fluffos-2.23-ds03/packages/dslib_spec.c new file mode 100644 index 0000000..e69de29 diff --git a/fluffos-2.23-ds03/packages/dwlib.c b/fluffos-2.23-ds03/packages/dwlib.c new file mode 100644 index 0000000..3993101 --- /dev/null +++ b/fluffos-2.23-ds03/packages/dwlib.c @@ -0,0 +1,906 @@ +#include "../lpc_incl.h" +#include "../comm.h" +#include "../file_incl.h" +#include "../file.h" +#include "../backend.h" +#include "../compiler.h" +#include "../main.h" +#include "../eoperators.h" +#include "../efuns_main.h" +#include "../efun_protos.h" +#include "../simul_efun.h" +#include "../add_action.h" +#include "../array.h" +#include "../master.h" +#include "../port.h" +#include "../array.h" + +#ifdef F_QUERY_MULTIPLE_SHORT +/* Hideous mangling of C code by Taffyd. */ +void query_multiple_short(svalue_t * arg, const char * type, int no_dollars, int quiet, int dark, int num_arg) { + char m[] = "$M$"; + char s[] = "_short"; + char default_function[] = "a_short"; + char separator[] = ", "; + char andsep[] = " and "; + int mlen = strlen(m); + int slen = strlen(s); + int seplen = strlen( separator ); + int andlen = strlen( andsep ); + + array_t *arr = arg->u.arr; + svalue_t *sv; + svalue_t *v; + int size = arr->size; + int i; + int len; + int total_len; + char *str, *res; + object_t *ob; + char *fun; + + if (!size) { + str = new_string(0, "f_query_multiple_short"); + str[0] = '\0'; + pop_n_elems(num_arg); + push_malloced_string(str); + return; + } + + /* + if (no_dollars && sizeof(args) && objectp(args[0]) && undefinedp(dark) && + this_player() && environment(this_player())) { + dark = this_player()->check_dark(environment(this_player())->query_light()); + if (dark) { + return "some objects you cannot make out"; + } + } */ + + if (no_dollars && arr->item->type == T_OBJECT && !dark && command_giver && + command_giver->super) { + call_origin = ORIGIN_EFUN; + if(!apply_low("query_light", command_giver->super, 0)) + push_number(0); + v = apply("check_dark", command_giver, 1, ORIGIN_EFUN); + + if (v && v->type == T_NUMBER && v->u.number) { + pop_n_elems(num_arg); + copy_and_push_string("some objects you cannot make out"); + return; + } + } + + /* If we don't have a type parameter, then use default_function */ + /* We need to free this value with FREE_MSTR() */ + + if ( !type ) { + len = strlen( default_function ); + fun = new_string( len, "f_query_multiple_short"); + fun[len] = '\0'; + strncpy( fun, default_function, len ); + } + else { + len = strlen( type ) + slen; + fun = new_string( len, "f_query_multiple_short"); + fun[len] = '\0'; + strncpy( fun, type, len ); + strncpy( fun + strlen( type ), s, slen); + } + + /* Check to see if there are any non-objects in the array. */ + for (i = 0; i < size; i++) { + if ((arr->item + i)->type != T_OBJECT) { + break; + } + } + + /* The array consists only of objects, and will use the $M$ + expansion code. */ + if (i == size && !no_dollars) { + str = new_string(max_string_length, "f_query_multiple_short"); + str[max_string_length]= '\0'; + strncpy(str, m, mlen); + total_len = mlen; + + for ( i = 0; i < size; i++ ) { + sv = (arr->item + i); + push_number(quiet); + v = apply(fun, sv->u.ob, 1, ORIGIN_EFUN); + + if (!v || v->type != T_STRING) { + continue; + } + if(total_len + SVALUE_STRLEN(v) > max_string_length - mlen) + continue; + strncpy(str + total_len, v->u.string, (len = SVALUE_STRLEN(v))); + total_len += len; + } + + strncpy(str + total_len, m, mlen); + total_len += mlen; + + res = new_string( total_len, "f_query_multiple_short" ); + res[ total_len ] = '\0'; + memcpy(res, str, total_len); + + /* Clean up our temporary buffer. */ + + FREE_MSTR(str); + FREE_MSTR(fun); + + pop_n_elems(num_arg); + push_malloced_string(res); + return; + } + + /* This is a mixed array, so we don't use $M$ format. Instead, we + do as much $a_short$ conversion as we can etc. */ + + str = new_string(max_string_length, "f_query_multiple_short"); + str[max_string_length]= '\0'; + total_len = 0; + + for ( i = 0; i < size; i++ ) { + sv = (arr->item + i); + + switch(sv->type) { + case T_STRING: + len = SVALUE_STRLEN(sv); + if(total_len + len < max_string_length) { + strncpy(str + total_len, sv->u.string, len); + total_len += len; + } + break; + case T_OBJECT: + push_number(quiet); + v = apply(fun, sv->u.ob, 1, ORIGIN_EFUN); + + if (!v || v->type != T_STRING) { + continue; + } + + if(total_len + SVALUE_STRLEN(v) < max_string_length) { + strncpy(str + total_len, v->u.string, + (len = SVALUE_STRLEN(v))); + total_len += len; + } + + break; + case T_ARRAY: + /* Does anyone use this? */ + /* args[ i ] = "$"+ type +"_short:"+ file_name( args[ i ][ 1 ] ) +"$"; */ + default: + /* Get the next element. */ + continue; + break; + } + + if ( len && size > 1 ) { + if ( i < size - 2 ) { + if(total_len+seplen < max_string_length) { + strncpy( str + total_len, separator, seplen ); + total_len += seplen; + } + } + else { + if ( i < size - 1 ) { + if(total_len+andlen < max_string_length) { + strncpy( str + total_len, andsep, andlen ); + total_len += andlen; + } + } + } + } + } + + FREE_MSTR(fun); + + res = new_string(total_len, "f_query_multiple_short"); + res[total_len] = '\0'; + memcpy(res, str, total_len); + + FREE_MSTR(str); + + /* Ok, now that we have cleaned up here we have to decide what to do + with it. If nodollars is 0, then we need to pass it to an object + for conversion. */ + + if (no_dollars) { + if (command_giver) { + /* We need to call on this_player(). */ + push_malloced_string(res); + v = apply("convert_message", command_giver, 1, ORIGIN_EFUN); + + if (v && v->type == T_STRING) { + pop_n_elems(num_arg); + share_and_push_string(v->u.string); + } + else { + pop_n_elems(num_arg); + push_undefined(); + } + + } + else { + /* We need to find /global/player. */ + /* Does this work? Seems not to. */ + ob = find_object("/global/player"); + + if (ob) { + push_malloced_string(res); + v = apply("convert_message", ob, 1, ORIGIN_EFUN); + + /* Return the result! */ + if (v && v->type == T_STRING) { + pop_n_elems(num_arg); + share_and_push_string(v->u.string); + } + else { + pop_n_elems(num_arg); + push_undefined(); + } + } + else { + pop_n_elems(num_arg); + push_undefined(); + } + } + + } + else { + pop_n_elems(num_arg); + push_malloced_string(res); + } +} /* query_multiple_short() */ + +void +f_query_multiple_short() +{ + svalue_t *sv = sp - st_num_arg + 1; + const char *type = NULL; + int no_dollars = 0, quiet = 0, dark = 0; + + if ( st_num_arg > 4) { + if (sv[4].type == T_NUMBER) { + dark = sv[4].u.number; + } + } + + if ( st_num_arg > 3) { + if (sv[3].type == T_NUMBER) { + quiet = sv[3].u.number; + } + } + + if ( st_num_arg > 2) { + if (sv[2].type == T_NUMBER) { + no_dollars = sv[2].u.number; + } + } + + if (st_num_arg >= 2) { + if (sv[1].type == T_STRING) { + type = sv[1].u.string; + } + } + + query_multiple_short(sv, type, no_dollars, quiet, dark, st_num_arg); +} + +#endif + +#ifdef F_REFERENCE_ALLOWED +/* Hideous mangling of C code by Taffyd. */ + +/* varargs int reference_allowed(object referree, mixed referrer) */ + +#define PLAYTESTER_HANDLER "/obj/handlers/playtesters" +#define PLAYER_HANDLER "/obj/handlers/player_handler" + +int _in_reference_allowed = 0; + +int reference_allowed(object_t * referee, object_t * referrer_obj, const char * referrer_name) +{ + int invis = 0; + int referee_creator = 0; + svalue_t *v; + svalue_t *item; + array_t *vec; + const char *referee_name = NULL; + object_t *playtester_handler = NULL; + object_t *player_handler = NULL; + int referrer_playtester = 0; + int referrer_match = 0; + int playtester_match = 0; + int i; + int size; + int ret = 0; + + /* Check to see whether we're invisible */ + v = apply("query_invis", referee, 0, ORIGIN_EFUN); + + if (v && v->type == T_NUMBER) { + invis = v->u.number; + } + /* And if we're a creator. */ + v = apply("query_creator", referee, 0, ORIGIN_EFUN); + + if ( v && v->type == T_NUMBER) { + referee_creator = v->u.number; + } + + /* If we're not invisible, or not a creator, or currently in a + reference allowed call, then we can see them. */ + if (!invis || !referee_creator || _in_reference_allowed) { + return 1; + } + + _in_reference_allowed = 1; + + if (referrer_obj && referee == referrer_obj) { + _in_reference_allowed = 0; + return 1; + } + + /* Determine the names of these guys. + * We might need to make copies of these strings? apply() + * has a few oddities. + */ + + v = apply("query_name", referee, 0, ORIGIN_EFUN); + + if (v && v->type == T_STRING) { + referee_name = v->u.string; + } + + if (referrer_obj && !referrer_name) { + v = apply("query_name", referrer_obj, 0, ORIGIN_EFUN); + + if (v && v->type == T_STRING) { + referrer_name = v->u.string; + } + } + + if (!referee_name || !referrer_name) { + _in_reference_allowed = 0; + return 1; + } + + playtester_handler = find_object(PLAYTESTER_HANDLER); + + if ( playtester_handler ) { + copy_and_push_string(referrer_name); + v = apply("query_playtester", playtester_handler, 1, ORIGIN_EFUN); + + if (v && v->type == T_NUMBER) { + referrer_playtester = v->u.number; + } + } + + v = apply( "query_allowed", referee, 0, ORIGIN_EFUN); + //printf("allow refs:%d\n", v->u.arr->ref); + if (v && v->type == T_ARRAY) { + vec = v->u.arr; + size = vec->size; + /* Iterate through the allowed array. */ + for (i = 0; i < size; i++) { + item = vec->item + i; + + if (strcmp(referrer_name, item->u.string) == 0) { + referrer_match = 1; + + /* If they're not a playtester, then bail as soon as + * we make this match. */ + if (!referrer_playtester) { + break; + } + } + + if (referrer_playtester && + strcmp("playtesters", item->u.string) == 0) { + playtester_match = 1; + + /* If we've already made a referrer match, then time + * to bail now. */ + if (referrer_match) { + break; + } + } + } + } + + /* If we found a match, then they are allowed so bail. */ + if ( referrer_match || playtester_match ) { + _in_reference_allowed = 0; + return 1; + } + + switch(invis) { + case 3: + /* Check for High Lord Invis. */ + + copy_and_push_string(referrer_name); + v = apply("high_programmer", master_ob, 1, ORIGIN_EFUN); + + if (v && v->type == T_NUMBER) { + ret = v->u.number; + } + break; + + case 2: + /* Check for Lord Invis */ + + copy_and_push_string(referrer_name); + v = apply("query_lord", master_ob, 1, ORIGIN_EFUN); + + if (v && v->type == T_NUMBER) { + ret = v->u.number; + } + break; + + case 1: { + /* Creator Invis */ + if (referrer_obj) { + v = apply("query_creator", referrer_obj, 0, ORIGIN_EFUN); + + if (v && v->type == T_NUMBER) { + ret = v->u.number; + } + } + else { + player_handler = find_object(PLAYER_HANDLER); + copy_and_push_string(referrer_name); + v = apply("test_creator", player_handler, 1, ORIGIN_EFUN); + + if (v && v->type == T_NUMBER) { + ret = v->u.number; + } + } + } + break; + + default: + /* A normal player. + * Shouldn't we do this somewhere else? */ + + ret = 1; + break; + } + + _in_reference_allowed = 0; + return ret; +} + +void +f_reference_allowed() +{ + svalue_t *sv = sp - st_num_arg + 1; + svalue_t *v; + object_t *referee = NULL; + object_t *referrer_obj = command_giver; /* Default to this_player(). */ + const char *referrer_name = NULL; + int result = 0; + int num_arg = st_num_arg; + + /* Maybe I could learn how to use this :p + CHECK_TYPES(sp-1, T_NUMBER, 1, F_MEMBER_ARRAY); */ + + if(referrer_obj && referrer_obj->flags & O_DESTRUCTED) + referrer_obj = NULL; + + if (sv->type == T_OBJECT && sv->u.ob) { + referee = sv->u.ob; + } + + if (st_num_arg > 1) { + if (sv[1].type == T_STRING && sv[1].u.string) { + /* We've been passed in a string, now we need to call + * find_player() */ +#ifdef F_FIND_PLAYER + /* If we have a find_player() efun, then we need to sue + * the following method. This hasn't been tested! + */ + referrer = find_living_object(sv[1].u.string, 1); +#else + if (simul_efun_ob) { + push_svalue(&sv[1]); + v = apply("find_player", simul_efun_ob, 1, ORIGIN_EFUN); + + if (v && v->type == T_OBJECT) { + referrer_obj = v->u.ob; + referrer_name = sv[1].u.string; + } + else { + referrer_obj = NULL; + referrer_name = sv[1].u.string; + } + } +#endif + } + if (sv[1].type == T_OBJECT && sv[1].u.ob) { + referrer_obj = sv[1].u.ob; + referrer_name = NULL; + } + } + + if (referee && (referrer_obj || referrer_name)) { + result = reference_allowed(referee, referrer_obj, referrer_name); + + pop_n_elems(num_arg); + push_number(result); + } else { + pop_n_elems(num_arg); + push_undefined(); + } +} + +#endif + +#ifdef F_ADD_A + +void f_add_a() { + const char *str = sp->u.string; + char *ret; + char *p; + char first; + int len; + int an; + + while( *str == ' ' ) + str++; + + // If *str is 0, it was only spaces. Return "a ". + if( *str == 0 ) { + pop_stack(); + copy_and_push_string( "a " ); + return; + } + + len = strlen( str ); + // Don't add anything if it already begins with a or an. + if( !strncasecmp( str, "a ", 2 ) || !strncasecmp( str, "an ", 3 ) ) { + return; + } + + first = *str; + an = 0; + + // Some special cases. + // If it begins with "us", check the following letter. + // "a use", "a usurper", "a user", but "an usher". + if( !strncasecmp( str, "us", 2 ) ) { + first = str[2]; + an = 1; + } + + // "hour*" gets "an". + if( !strncasecmp( str, "hour", 4 ) ) { + first = 'o'; + } + + switch( first ) { + case 'a': + case 'e': + case 'i': + case 'o': + case 'u': + case 'A': + case 'E': + case 'I': + case 'O': + case 'U': + an = !an; + break; + default: + break; + } + + if( an ) { // Add an. + if( len + 3 > max_string_length ) { + free_string_svalue( sp ); + error( "add_a() exceeded max string length.\n" ); + } + ret = new_string( len + 3, "f_add_a" ); + memcpy( ret, "an ", 3 ); + p = ret + 3; + } else { // Add a. + if( len + 2 > max_string_length ) { + free_string_svalue( sp ); + error( "add_a() exceeded max string length.\n" ); + } + ret = new_string( len + 2, "f_add_a" ); + memcpy( ret, "a ", 2 ); + p = ret + 2; + } + + // Add the rest of the string. + memcpy( p, str, len + 1 ); // + 1: get the \0. + free_string_svalue( sp ); + sp->type = T_STRING; + sp->subtype = STRING_MALLOC; + sp->u.string = ret; +} + +#endif +// This along with add_a() is the only sfun in /secure/simul_efun/add_a.c +#ifdef F_VOWEL +void f_vowel() { + char v = (char)sp->u.number; + + if( v == 'a' || v == 'e' || v == 'i' || v == 'o' || v == 'u' || + v == 'A' || v == 'E' || v == 'I' || v == 'O' || v == 'U' ) + sp->u.number = 1; + else + sp->u.number = 0; +} +#endif + + +#ifdef F_REPLACE + +void f_replace() { + svalue_t *arg2 = sp - st_num_arg + 2; + if(arg2->type == T_STRING) { + return f_replace_string(); + } else { + array_t *arr = arg2->u.arr; + int i = 0; + if(arr->size & 1) { + error("Wrong array size for replace.\n"); + } + pop_n_elems(st_num_arg-2); + sp--; + + for (i=0;isize;i+=2) { + if(arr->item[i].type == T_STRING && arr->item[i+1].type == T_STRING) { + share_and_push_string(arr->item[i].u.string); + share_and_push_string(arr->item[i+1].u.string); + st_num_arg = 3; + f_replace_string(); + if(sp->type != T_STRING) + break; + } + } + free_array(arr); + } +} + +#endif + +#if defined(F_REPLACE_MXP) || defined(F_REPLACE_HTML) +void replace_mxp_html(int html, int mxp) { + char *dst = new_string(max_string_length+8, "f_replace_mxp_html: 2"); + const char *src = sp->u.string; + char *dst2 = dst; + while(*src && dst2-dst < max_string_length) { + switch(*src) { + case '&': + strcpy(dst2, "&"); + dst2 += 5; + break; + case '<': + strcpy(dst2, "<"); + dst2 += 4; + break; + case '>': + strcpy(dst2, ">"); + dst2 += 4; + break; + case '\n': + if(mxp) { + strcpy(dst2, "\e[4z
"); + dst2 += 8; + } else + goto def; + break; + case '"': + if(html) { + strcpy(dst2, """); + dst2 += 6; + break; + } + default: + def: + *dst2++ = *src; + } + src++; + } + pop_stack(); + *dst2 = 0; + push_malloced_string(extend_string(dst, dst2 - dst)); +} + +#endif + +#ifdef F_REPLACE_HTML + +void f_replace_html() {replace_mxp_html(1,0);} + +#endif + +#ifdef F_REPLACE_MXP + +void f_replace_mxp() {replace_mxp_html(0,1);} + +#endif + +#ifdef F_ROULETTE_WHEEL +void f_roulette_wheel() { + long num; + mapping_t *m = sp->u.map; + int j, found; + mapping_node_t *elt, **a = m->table; + svalue_t *val; + + // Loop through the mapping, adding up the weights. + j = m->table_size; + if(!j) + error("empty mapping in roulette_wheel.\n"); + num = 0; + j--; + do { + for( elt = a[j]; elt; elt = elt->next ) { + val = elt->values + 1; + + if( val->type != T_NUMBER || val->u.number < 0 ) { + error( "Weights must be non-negative integers.\n" ); + } + + num += val->u.number; + } + } while( j-- ); + + num = 1 + random_number( num ); + found = 0; + + // Loop again, and stop when the sum of the weights comes to num. + j = m->table_size-1; + do { + for( elt = a[j]; elt; elt = elt->next ) { + val = elt->values + 1; + num -= val->u.number; + + if( num <= 0 ) { + found = 1; + break; + } + } + } while( j-- && !found ); + + if( !found ) { // This shouldn't happen... + error( "Something went wrong!\n" ); + } + + // val points to the value that tipped the scale. val - 1 is the key. + assign_svalue_no_free( sp, val - 1 ); + free_mapping( m ); +} + +#endif + +#ifdef F_REPLACE_OBJECTS + +svalue_t replace_tmp = {T_NUMBER}; +svalue_t *replace_objects(svalue_t *thing){ + int i; + switch(thing->type){ + case T_OBJECT: + { + + char buf[2000]; + strcpy(buf, thing->u.ob->obname); + svalue_t *tmp = 0; + if(!(thing->u.ob->flags & O_DESTRUCTED)){ + push_object(thing->u.ob); + tmp = safe_apply_master_ob(APPLY_OBJECT_NAME, 1); + }else + strcat(buf, " (destructed)"); + if(tmp && tmp->type == T_STRING){ + strcat(buf, " (\""); + strcat(buf, tmp->u.string); + strcat(buf, "\")"); + } + copy_and_push_string(buf); + assign_svalue(&replace_tmp, sp); + pop_stack(); + return &replace_tmp; + } + case T_ARRAY: + case T_CLASS: + { + array_t *ar = thing->u.arr; + array_t *nar = allocate_array(ar->size); + push_refed_array(nar); + for(i=0;isize;i++) + assign_svalue(&nar->item[i], replace_objects(&ar->item[i])); + assign_svalue(&replace_tmp, sp); + pop_stack(); + replace_tmp.type = thing->type; + return &replace_tmp; + } + case T_MAPPING: + push_refed_array(mapping_indices(thing->u.map)); + push_refed_mapping(allocate_mapping(thing->u.map->table_size)); + push_number(0); + for(i=0;i<(sp-2)->u.arr->size; i++){ + svalue_t *key = sp; + svalue_t *tmp = find_in_mapping(thing->u.map, &(sp-2)->u.arr->item[i]); + assign_svalue(key, replace_objects(&(sp-2)->u.arr->item[i])); + assign_svalue_no_free(find_for_insert((sp-1)->u.map, key, 1), replace_objects(tmp)); + if((sp-1)->u.map->count-i != 1) + printf("guilty party:%s\n", key->u.string); + } + assign_svalue(&replace_tmp, sp-1); + pop_3_elems(); + return &replace_tmp; + default: + assign_svalue(&replace_tmp, thing); + return &replace_tmp; + } +} + +void f_replace_objects(){ + assign_svalue(sp, replace_objects(sp)); +} +#endif + +#ifdef F_REPLACE_DOLLARS +void f_replace_dollars(){ + char *newstr; + const char *oldstr = (sp-1)->u.string; + char *currentnew; + const char *currentold = oldstr; + int i; + if(sp->u.arr->size & 1) + error("wrong array length for replace_dollars()"); + for(i=0;iu.arr->size; i++) + if(sp->u.arr->item[i].type != T_STRING) + error("replace array should only contain strings"); + newstr = new_string(MAX_STRING_LENGTH, "replace_dollars"); + currentnew = newstr; + for(i=0;iu.arr->size;j+=2) + { + const char *one = sp->u.arr->item[j].u.string; + if(!strncmp(one, oldstr+i, COUNTED_STRLEN(one))) + { + const char *two = sp->u.arr->item[j+1].u.string; + int len = i-(currentold-oldstr); + if(currentnew + len - newstr > MAX_STRING_LENGTH){ + FREE_MSTR(newstr); + error("string too long"); + } + strncpy(currentnew, currentold, len); + currentnew+=len; + currentold+=len; + currentold+=COUNTED_STRLEN(one); + if(currentnew + COUNTED_STRLEN(one) - newstr > MAX_STRING_LENGTH){ + FREE_MSTR(newstr); + error("string too long"); + } + strcpy(currentnew, two); + currentnew+=COUNTED_STRLEN(two); + break; + } + } + } + } + if(newstr == currentnew){ + //nothing happened! + FREE_MSTR(newstr); + pop_stack(); + return; + } + + if(currentnew + COUNTED_STRLEN(oldstr)-currentold+oldstr - newstr > MAX_STRING_LENGTH){ + FREE_MSTR(newstr); + error("string too long"); + } + + strcpy(currentnew, currentold); + pop_2_elems(); + push_malloced_string(extend_string(newstr, currentnew-newstr + COUNTED_STRLEN(oldstr)-(currentold-oldstr))); +} +#endif diff --git a/fluffos-2.23-ds03/packages/dwlib_spec.c b/fluffos-2.23-ds03/packages/dwlib_spec.c new file mode 100644 index 0000000..2f9e270 --- /dev/null +++ b/fluffos-2.23-ds03/packages/dwlib_spec.c @@ -0,0 +1,13 @@ +#include "spec.h" + +string query_multiple_short(mixed *, int | string | void, int | void, int | void, int | void); +int reference_allowed(object, string | object | void); +int roll_MdN( int, int ); +string add_a( string ); +int vowel( int ); +string replace(string, string *|string, string|void); +string replace_html(string); +string replace_mxp(string); +mixed roulette_wheel( mapping ); +mixed replace_objects(mixed); +string replace_dollars(string, string *); diff --git a/fluffos-2.23-ds03/packages/external.c b/fluffos-2.23-ds03/packages/external.c new file mode 100644 index 0000000..d7817e2 --- /dev/null +++ b/fluffos-2.23-ds03/packages/external.c @@ -0,0 +1,138 @@ +#include "../lpc_incl.h" +#include "../file_incl.h" +#include "../network_incl.h" +#include "../socket_efuns.h" +#include "../include/socket_err.h" +#include "../main.h" + +char *external_cmd[NUM_EXTERNAL_CMDS]; + +#ifdef F_EXTERNAL_START +int external_start (int which, svalue_t * args, + svalue_t * arg1, svalue_t * arg2, svalue_t * arg3) { + int sv[2]; + char *cmd; + int fd; + char **argv; + pid_t ret; + + if (--which < 0 || which > (NUM_EXTERNAL_CMDS-1) || !external_cmd[which]) + error("Bad argument 1 to external_start()\n"); + cmd = external_cmd[which]; + fd = find_new_socket(); + if (fd < 0) return fd; + + if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) + return EESOCKET; + + ret = fork(); + if (ret == -1) { + error("fork() in external_start() failed: %s\n", strerror(errno)); + } + if (ret) { + close(sv[1]); + lpc_socks[fd].fd = sv[0]; + lpc_socks[fd].flags = S_EXTERNAL; + set_read_callback(fd, arg1); + set_write_callback(fd, arg2); + set_close_callback(fd, arg3); + lpc_socks[fd].owner_ob = current_object; + lpc_socks[fd].mode = STREAM; + lpc_socks[fd].state = STATE_DATA_XFER; + memset((char *) &lpc_socks[fd].l_addr, 0, sizeof(lpc_socks[fd].l_addr)); + memset((char *) &lpc_socks[fd].r_addr, 0, sizeof(lpc_socks[fd].r_addr)); + lpc_socks[fd].owner_ob = current_object; + lpc_socks[fd].release_ob = NULL; + lpc_socks[fd].r_buf = NULL; + lpc_socks[fd].r_off = 0; + lpc_socks[fd].r_len = 0; + lpc_socks[fd].w_buf = NULL; + lpc_socks[fd].w_off = 0; + lpc_socks[fd].w_len = 0; + + current_object->flags |= O_EFUN_SOCKET; + return fd; + } else { + int flag = 1; + int i = 1; + int n = 1; + const char *p; + char *arg; + + if (args->type == T_ARRAY) { + n = args->u.arr->size; + } else { + p = args->u.string; + + while (*p) { + if (isspace(*p)) { + flag = 1; + } else { + if (flag) { + n++; + flag = 0; + } + } + p++; + } + } + + argv = CALLOCATE(n, char *, TAG_TEMPORARY, "external args"); + + argv[0] = cmd; + + /* need writable version */ + if (args->type == T_ARRAY) { + int j; + svalue_t *sv = args->u.arr->item; + + for (j = 0; j < n; j++) { + argv[i++] = alloc_cstring(sv[j].u.string, "external args"); + } + } else { + flag = 1; + arg = alloc_cstring(args->u.string, "external args"); + while (*arg) { + if (isspace(*arg)) { + *arg = 0; + flag = 1; + } else { + if (flag) { + argv[i++] = arg; + flag = 0; + } + } + arg++; + } + } + argv[i] = 0; + + close(sv[0]); + for(i=0; i<5; i++) + if(external_port[i].port) + close(external_port[i].fd); //close external ports + dup2(sv[1], 0); + dup2(sv[1], 1); + dup2(sv[1], 2); + execv(cmd, argv); + exit(0); + return 0; + } +} + +void f_external_start (void) +{ + int fd, num_arg = st_num_arg; + svalue_t *arg = sp - num_arg + 1; + + if (check_valid_socket("external", -1, current_object, "N/A", -1)) { + fd = external_start(arg[0].u.number, arg + 1, + arg + 2, arg + 3, (num_arg == 5 ? arg + 4 : 0)); + pop_n_elems(num_arg - 1); + sp->u.number = fd; + } else { + pop_n_elems(num_arg - 1); + sp->u.number = EESECURITY; + } +} +#endif diff --git a/fluffos-2.23-ds03/packages/external_spec.c b/fluffos-2.23-ds03/packages/external_spec.c new file mode 100644 index 0000000..0fdf1c1 --- /dev/null +++ b/fluffos-2.23-ds03/packages/external_spec.c @@ -0,0 +1,3 @@ +#include "spec.h" + +int external_start(int, string | string *, string | function, string | function, string | function | void); diff --git a/fluffos-2.23-ds03/packages/math.c b/fluffos-2.23-ds03/packages/math.c new file mode 100644 index 0000000..6a33e5c --- /dev/null +++ b/fluffos-2.23-ds03/packages/math.c @@ -0,0 +1,380 @@ +/* + math.c: this file contains the math efunctions called from + inside eval_instruction() in interpret.c. + -- coded by Truilkan 93/02/21 + + Added norm, dotprod, distance, angle, log2. + Also added round() which works on floats. If you do work with floats, + you'll discover it's actually more useful than you'd think. + Added int args to the efuns as apppropriate. + - Hamlet 20090516 +*/ + +#include +#include +#ifdef LATTICE +#include "/lpc_incl.h" +#else +#include "../lpc_incl.h" +#include "../efun_protos.h" +#endif + +#define SQUARE(n) ((n)*(n)) + +#ifdef F_COS +void +f_cos (void) +{ + sp->u.real = cos(sp->u.real); +} +#endif + +#ifdef F_SIN +void +f_sin (void) +{ + sp->u.real = sin(sp->u.real); +} +#endif +#ifdef F_TAN +void +f_tan (void) +{ + /* + * maybe should try to check that tan won't blow up (x != (Pi/2 + N*Pi)) + */ + sp->u.real = tan(sp->u.real); +} +#endif + +#ifdef F_ASIN +void +f_asin (void) +{ + if (sp->u.real < -1.0) { + error("math: asin(x) with (x < -1.0)\n"); + return; + } else if (sp->u.real > 1.0) { + error("math: asin(x) with (x > 1.0)\n"); + return; + } + sp->u.real = asin(sp->u.real); +} +#endif + +#ifdef F_ACOS +void +f_acos (void) +{ + if (sp->u.real < -1.0) { + error("math: acos(x) with (x < -1.0)\n"); + return; + } else if (sp->u.real > 1.0) { + error("math: acos(x) with (x > 1.0)\n"); + return; + } + sp->u.real = acos(sp->u.real); +} +#endif + +#ifdef F_ATAN +void +f_atan (void) +{ + sp->u.real = atan(sp->u.real); +} +#endif + +#ifdef F_SQRT +void +f_sqrt (void) +{ float val; + + if(sp->type == T_NUMBER) + val = (float) sp->u.number; + else + val = sp->u.real; + + if (val < 0.0) { + error("math: sqrt(x) with (x < 0.0)\n"); + return; + } + sp->u.real = (float) sqrt(val); + sp->type = T_REAL; +} +#endif + +#ifdef F_LOG +void +f_log (void) +{ + if (sp->u.real <= 0.0) { + error("math: log(x) with (x <= 0.0)\n"); + return; + } + sp->u.real = log(sp->u.real); +} +#endif + +#ifdef F_LOG10 +void +f_log10 (void) +{ + float val; + + if(sp->type == T_NUMBER) + val = (float) sp->u.number; + else + val = sp->u.real; + + if (val <= 0.0) { + error("math: log10(x) with (x <= 0.0)\n"); + return; + } + sp->u.real = log10(val); + sp->type = T_REAL; +} +#endif + +#ifdef F_LOG2 +void +f_log2 (void) +{ + float val; + + if(sp->type == T_NUMBER) + val = (float) sp->u.number; + else + val = sp->u.real; + + if (val <= 0.0) { + error("math: log2(x) with (x <= 0.0)\n"); + return; + } + sp->u.real = (float) log2((double)val); + sp->type = T_REAL; +} +#endif + +#ifdef F_POW +void +f_pow (void) +{ + float val, val2; + + if((sp-1)->type == T_NUMBER) + val = (float) (sp-1)->u.number; + else + val = (sp-1)->u.real; + + if(sp->type == T_NUMBER) + val2 = (float) sp->u.number; + else + val2 = sp->u.real; + + + (sp - 1)->u.real = pow(val, val2); + sp--; + sp->type = T_REAL; +} +#endif + +#ifdef F_EXP +void +f_exp (void) +{ + sp->u.real = exp(sp->u.real); +} +#endif + +#ifdef F_FLOOR +void +f_floor (void) +{ + sp->u.real = floor(sp->u.real); +} +#endif + +#ifdef F_CEIL +void +f_ceil (void) +{ + sp->u.real = ceil(sp->u.real); +} +#endif + +#ifdef F_ROUND +void f_round (void) +{ + sp->u.real = (float) round(sp->u.real); +} +#endif + +#ifdef F_NORM +/* The norm (magnitude) of a vector. + Yes, you could use dotprod() below to implement norm(), but in the interest + of speed, norm() has less cases. +*/ +static float norm(array_t *a) { + int len = sp->u.arr->size; + float total = 0.0; + + while(len-- > 0) + if(a->item[len].type == T_NUMBER) + total += SQUARE((float) a->item[len].u.number); + else if(a->item[len].type == T_REAL) + total += SQUARE(a->item[len].u.real); + else { + return -INT_MAX + 1; + } + + return (float) sqrt(total); +} + +void f_norm(void) { + float val = norm(sp->u.arr); + + if(val == (-INT_MAX + 1)) { + pop_stack(); + error("norm: invalid argument 1.\n"); + return; + } + + pop_stack(); + push_real(val); +} +#endif + +#if defined(F_DOTPROD) | defined(F_DISTANCE) | defined(F_ANGLE) +static float vector_op(array_t *a, array_t *b, + float (*func)(const float, const float)) { + int len = a->size; + float total = 0.0; + + if(b->size != len) { + return -INT_MAX; + } + + while(len-- > 0) { + if(b->item[len].type == T_NUMBER) { + if(a->item[len].type == T_NUMBER) + total += func((float) a->item[len].u.number, + (float) b->item[len].u.number); + else if(a->item[len].type == T_REAL) + total += func(a->item[len].u.real, + (float) b->item[len].u.number); + else { + return -INT_MAX + 1; + } + } + else if(b->item[len].type == T_REAL) { + if(a->item[len].type == T_NUMBER) + total += func((float) a->item[len].u.number, + b->item[len].u.real); + + else if(a->item[len].type == T_REAL) + total += func(a->item[len].u.real, b->item[len].u.real); + else { + return -INT_MAX + 1; + } + } + else { + return -INT_MAX + 2; + } + } + + return total; +} +#endif + +#ifdef F_DOTPROD +static float dotprod_mult(const float a, const float b) { + return a * b; +} + +/* dot product of two vectors */ +static float dotprod(array_t *a, array_t *b) { + return vector_op(a, b, dotprod_mult); +} + +void f_dotprod(void) { + float total = vector_op((sp-1)->u.arr, sp->u.arr, dotprod_mult); + + if(total == -INT_MAX) { + pop_2_elems(); + error("dotprod: cannot take the dotprod of vectors of different sizes.\n"); + return; + } + + if((total == (-INT_MAX + 1)) || (total == (-INT_MAX + 2))) { + pop_2_elems(); + error("dotprod: invalid arg %d.\n", (total + INT_MAX)); + return; + } + + pop_2_elems(); + push_real(total); +} +#endif + +#ifdef F_DISTANCE +static float distance_mult(const float a, const float b) { + return SQUARE(b - a); +} + +/* The (Euclidian) distance between two points */ +void f_distance(void) { + float total = vector_op((sp-1)->u.arr, sp->u.arr, distance_mult); + + if(total == -INT_MAX) { + pop_2_elems(); + error("distance: cannot take the distance of vectors of different sizes.\n"); + return; + } + + if((total == (-INT_MAX + 1)) || (total == (-INT_MAX + 2))) { + pop_2_elems(); + error("distance: invalid arg %d.\n", (total + INT_MAX)); + return; + } + + pop_2_elems(); + push_real((float)sqrt(total)); +} +#endif + +#ifdef F_ANGLE +void f_angle(void) { + float dot, norma, normb; + + dot = dotprod((sp-1)->u.arr, sp->u.arr); + + if(dot <= (-INT_MAX + 2)) { + pop_2_elems(); + if(dot == -INT_MAX) + error("angle: cannot calculate the angle between vectors of different sizes.\n"); + else + error("angle: invalid arg %d.\n", (dot + INT_MAX)); + return; + } + + norma = norm((sp-1)->u.arr); + + if(norma <= (-INT_MAX + 1)) { + pop_2_elems(); + error("angle: invalid argument 1.\n"); + return; + } + + normb = norm(sp->u.arr); + + if(normb <= (-INT_MAX + 1)) { + pop_2_elems(); + error("angle: invalid argument 2.\n"); + return; + } + + pop_2_elems(); + push_real((float)acos( dot / (norma * normb) )); +} +#endif diff --git a/fluffos-2.23-ds03/packages/math_spec.c b/fluffos-2.23-ds03/packages/math_spec.c new file mode 100644 index 0000000..13e13be --- /dev/null +++ b/fluffos-2.23-ds03/packages/math_spec.c @@ -0,0 +1,21 @@ +#include "spec.h" + + float cos(float); + float sin(float); + float tan(float); + float asin(float); + float acos(float); + float atan(float); + float sqrt(float|int); + float log(float); + float log10(float|int); + float log2(float|int); + float pow(float|int, float|int); + float exp(float); + float floor(float); + float ceil(float); + float round(float); + float norm(int *|float *); + float dotprod(int *|float *, int *|float *); + float distance(int *|float *, int *|float *); + float angle(int *|float *, int *|float *); diff --git a/fluffos-2.23-ds03/packages/matrix.c b/fluffos-2.23-ds03/packages/matrix.c new file mode 100644 index 0000000..c112047 --- /dev/null +++ b/fluffos-2.23-ds03/packages/matrix.c @@ -0,0 +1,654 @@ +/* + * matrix.c -- matrix efuns. + * 2-93 : Dwayne Fontenot : original coding. + */ + +#include + +#ifdef LATTICE +#include "/lpc_incl.h" +#else +#include "../lpc_incl.h" +#include "../efun_protos.h" +#endif + +#include "matrix.h" + +static Matrix identity = +{1., 0., 0., 0., + 0., 1., 0., 0., + 0., 0., 1., 0., + 0., 0., 0., 1.}; + +static void print_matrix (Matrix, char *); +static void print_array (Vector *, char *); +static Vector *normalize_array (Vector *); +static Vector *cross_product (Vector *, Vector *, Vector *); +static Vector *points_to_array (Vector *, Vector *, Vector *); + +void f_id_matrix (void) +{ + array_t *matrix; + int i; + + matrix = allocate_empty_array(16); + for (i = 0; i < 16; i++) { + matrix->item[i].type = T_REAL; + matrix->item[i].u.real = identity[i]; + } + push_refed_array(matrix); +} + +void f_translate (void) +{ + array_t *matrix; + double x, y, z; + Matrix current_matrix; + Matrix trans_matrix; + Matrix final_matrix; + int i; + + if ((sp - 1)->type != T_REAL) { + bad_arg(3, F_TRANSLATE); + } + if (sp->type != T_REAL) { + bad_arg(4, F_TRANSLATE); + } + /* + * get arguments from stack. + */ + matrix = (sp - 3)->u.arr; + x = (sp - 2)->u.real; + y = (sp - 1)->u.real; + z = sp->u.real; + sp -= 3; + + /* + * convert vec matrix to float matrix. + */ + for (i = 0; i < 16; i++) { + current_matrix[i] = matrix->item[i].u.real; + } + /* + * create translation matrix. + */ + translate_matrix(x, y, z, trans_matrix); + /* + * compute transformed matrix. + */ + mult_matrix(current_matrix, trans_matrix, final_matrix); + /* + * convert float matrix to vec matrix. + */ + for (i = 0; i < 16; i++) { + matrix->item[i].u.real = final_matrix[i]; + } +} + +void f_scale (void) +{ + array_t *matrix; + double x, y, z; + Matrix current_matrix; + Matrix scaling_matrix; + Matrix final_matrix; + int i; + + if ((sp - 1)->type != T_REAL) { + bad_arg(3, F_SCALE); + } + if (sp->type != T_REAL) { + bad_arg(4, F_SCALE); + } + /* + * get arguments from stack. + */ + matrix = (sp - 3)->u.arr; + x = (sp - 2)->u.real; + y = (sp - 1)->u.real; + z = sp->u.real; + sp -= 3; + /* + * convert vec matrix to float matrix. + */ + for (i = 0; i < 16; i++) { + current_matrix[i] = matrix->item[i].u.real; + } + /* + * create scaling matrix. + */ + scale_matrix(x, y, z, scaling_matrix); + /* + * compute transformed matrix. + */ + mult_matrix(current_matrix, scaling_matrix, final_matrix); + /* + * convert float matrix to vec matrix. + */ + for (i = 0; i < 16; i++) { + matrix->item[i].u.real = final_matrix[i]; + } +} + +void f_rotate_x (void) +{ + array_t *matrix; + double angle; + Matrix current_matrix; + Matrix rot_matrix; + Matrix final_matrix; + int i; + + /* + * get arguments from stack. + */ + matrix = (sp - 1)->u.arr; + angle = (sp--)->u.real; + /* + * convert vec matrix to float matrix. + */ + for (i = 0; i < 16; i++) { + current_matrix[i] = matrix->item[i].u.real; + } + /* + * create x rotation matrix. + */ + rotate_x_matrix(angle, rot_matrix); + /* + * compute transformed matrix. + */ + mult_matrix(current_matrix, rot_matrix, final_matrix); + /* + * convert float matrix to vec matrix. + */ + for (i = 0; i < 16; i++) { + matrix->item[i].u.real = final_matrix[i]; + } +} + +void f_rotate_y (void) +{ + array_t *matrix; + double angle; + Matrix current_matrix; + Matrix rot_matrix; + Matrix final_matrix; + int i; + + /* + * get arguments from stack. + */ + matrix = (sp - 1)->u.arr; + angle = (sp--)->u.real; + /* + * convert vec matrix to float matrix. + */ + for (i = 0; i < 16; i++) { + current_matrix[i] = matrix->item[i].u.real; + } + /* + * create y rotation matrix. + */ + rotate_y_matrix(angle, rot_matrix); + /* + * compute transformed matrix. + */ + mult_matrix(current_matrix, rot_matrix, final_matrix); + /* + * convert float matrix to vec matrix. + */ + for (i = 0; i < 16; i++) { + matrix->item[i].u.real = final_matrix[i]; + } +} + +void f_rotate_z (void) +{ + array_t *matrix; + double angle; + Matrix current_matrix; + Matrix rot_matrix; + Matrix final_matrix; + int i; + + /* + * get arguments from stack. + */ + matrix = (sp - 1)->u.arr; + angle = (sp--)->u.real; + /* + * convert vec matrix to float matrix. + */ + for (i = 0; i < 16; i++) { + current_matrix[i] = matrix->item[i].u.real; + } + /* + * create z rotation matrix. + */ + rotate_z_matrix(angle, rot_matrix); + /* + * compute transformed matrix. + */ + mult_matrix(current_matrix, rot_matrix, final_matrix); + /* + * convert float matrix to vec matrix. + */ + for (i = 0; i < 16; i++) { + matrix->item[i].u.real = final_matrix[i]; + } +} + +void f_lookat_rotate (void) +{ + array_t *matrix; + double x, y, z; + Matrix current_matrix; + Matrix lookat_matrix; + int i; + + if ((sp - 1)->type != T_REAL) { + bad_arg(3, F_LOOKAT_ROTATE); + } + if (sp->type != T_REAL) { + bad_arg(4, F_LOOKAT_ROTATE); + } + /* + * get arguments from stack. + */ + matrix = (sp - 3)->u.arr; + x = (sp - 2)->u.real; + y = (sp - 1)->u.real; + z = sp->u.real; + sp -= 3; + /* + * convert vec matrix to float matrix. + */ + for (i = 0; i < 16; i++) { + current_matrix[i] = matrix->item[i].u.real; + } + /* + * create new viewing transformation matrix. + */ + lookat_rotate(current_matrix, x, y, z, lookat_matrix); + /* + * convert float matrix to vec matrix. + */ + for (i = 0; i < 16; i++) { + matrix->item[i].u.real = lookat_matrix[i]; + } +} + +#ifdef F_LOOKAT_ROTATE2 +void f_lookat_rotate2 (void) +{ + array_t *matrix; + double ex, ey, ez, lx, ly, lz; + Matrix current_matrix; + Matrix lookat_matrix; + int i, j; + + for (j = 4; j >= 0; j--) { + if ((sp - j)->type != T_REAL) { + bad_arg(7 - j, F_LOOKAT_ROTATE2); + } + } + /* + * get arguments from stack. + */ + matrix = (sp - 6)->u.arr; + ex = (sp - 5)->u.real; + ey = (sp - 4)->u.real; + ez = (sp - 3)->u.real; + lx = (sp - 2)->u.real; + ly = (sp - 1)->u.real; + lz = sp->u.real; + sp -= 5; + free_array((sp--)->u.arr); + + /* + * convert vec matrix to float matrix. + */ + for (i = 0; i < 16; i++) { + current_matrix[i] = matrix->item[i].u.real; + } + /* + * create new viewing transformation matrix. + */ + lookat_rotate2(ex, ey, ez, lx, ly, lz, lookat_matrix); + /* + * convert float matrix to vec matrix. + */ + for (i = 0; i < 16; i++) { + matrix->item[i].u.real = lookat_matrix[i]; + } +} +#endif + +#ifdef DEBUG +static void print_matrix (Matrix m, char * label) +{ + int i; + int j; + + fprintf(stderr, "%s:\n", label); + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + fprintf(stderr, "%f\t", m[i * 4 + j]); + } + fprintf(stderr, "\n"); + } +} + +static void print_array (Vector * v, char * label) +{ + fprintf(stderr, "%s:\t%f\t%f\t%f\n", label, v->x, v->y, v->z); +} +#endif + +static Vector *normalize_array (Vector * v) +{ + double xx, yy, zz, mm, m; + + xx = v->x * v->x; + yy = v->y * v->y; + zz = v->z * v->z; + mm = xx + yy + zz; + m = sqrt(mm); + if (m) { + v->x /= m; + v->y /= m; + v->z /= m; + } + return (v); +} + +static Vector *cross_product (Vector * v, Vector * va, Vector * vb) +{ + v->x = (va->y * vb->z) - (va->z * vb->y); + v->y = (va->z * vb->x) - (va->x * vb->z); + v->z = (va->x * vb->y) - (va->y * vb->x); + return (v); +} + +static Vector *points_to_array (Vector * v, Vector * pa, Vector * pb) +{ + v->x = pa->x - pb->x; + v->y = pa->y - pb->y; + v->z = pa->z - pb->z; + return (v); +} + +void lookat_rotate (Matrix T, double x, double y, double z, Matrix M) +{ + static Vector N, V, U; + static Vector ep, lp; + + lp.x = x; + lp.y = y; + lp.z = z; + ep.x = T[12]; + ep.y = T[13]; + ep.z = T[14]; + points_to_array(&N, &lp, &ep); + normalize_array(&N); + + U.x = T[0]; + U.y = T[4]; + U.z = T[8]; + cross_product(&V, &N, &U); + normalize_array(&V); + + cross_product(&U, &V, &N); + normalize_array(&U); + + M[0] = U.x; + M[1] = V.x; + M[2] = N.x; + M[3] = 0.; + M[4] = U.y; + M[5] = V.y; + M[6] = N.y; + M[7] = 0.; + M[8] = U.z; + M[9] = V.z; + M[10] = N.z; + M[11] = 0.; +#if 0 + M[12] = ep.x; + M[13] = ep.y; + M[14] = ep.z; + M[15] = 1.; +#endif +#if 0 + M[12] = -U.x * ep.x - U.y * ep.y - U.z * ep.z; + M[13] = -V.x * ep.x - V.y * ep.y - V.z * ep.z; + M[14] = -N.x * ep.x - N.y * ep.y - N.z * ep.z; +#endif + M[12] = ((U.x * ep.x) + (U.y * ep.y) + (U.z * ep.z)); + M[13] = ((V.x * ep.x) + (V.y * ep.y) + (V.z * ep.z)); + M[14] = ((N.x * ep.x) + (N.y * ep.y) + (N.z * ep.z)); + M[15] = 1.; + +#ifdef DEBUG + print_array(&lp, "look point"); + print_array(&ep, "eye point"); + print_array(&N, "normal array"); + print_array(&V, "V = N x U"); + print_array(&U, "U = V x N"); + print_matrix(M, "final matrix"); +#endif /* DEBUG */ +} + +void lookat_rotate2 (double ex, double ey, double ez, double lx, double ly, double lz, Matrix M) +{ + static Vector N, V, U; + static Vector ep, lp; + + ep.x = ex; + ep.y = ey; + ep.z = ez; + lp.x = lx; + lp.y = ly; + lp.z = lz; + points_to_array(&N, &lp, &ep); + normalize_array(&N); + + U.x = 0.; + U.y = 1.; + U.z = 0.; + cross_product(&V, &N, &U); + normalize_array(&V); + + cross_product(&U, &V, &N); + normalize_array(&U); + + M[0] = U.x; + M[1] = V.x; + M[2] = N.x; + M[3] = 0.; + M[4] = U.y; + M[5] = V.y; + M[6] = N.y; + M[7] = 0.; + M[8] = U.z; + M[9] = V.z; + M[10] = N.z; + M[11] = 0.; +#if 0 + M[12] = ep.x; + M[13] = ep.y; + M[14] = ep.z; + M[15] = 1.; +#endif +#if 0 + M[12] = -U.x * ep.x - U.y * ep.y - U.z * ep.z; + M[13] = -V.x * ep.x - V.y * ep.y - V.z * ep.z; + M[14] = -N.x * ep.x - N.y * ep.y - N.z * ep.z; +#endif + M[12] = ((U.x * ep.x) + (U.y * ep.y) + (U.z * ep.z)); + M[13] = ((V.x * ep.x) + (V.y * ep.y) + (V.z * ep.z)); + M[14] = ((N.x * ep.x) + (N.y * ep.y) + (N.z * ep.z)); + M[15] = 1.; + +#ifdef DEBUG + print_array(&lp, "look point"); + print_array(&ep, "eye point"); + print_array(&N, "normal array"); + print_array(&V, "V = N x U"); + print_array(&U, "U = V x N"); + print_matrix(M, "final matrix"); +#endif /* DEBUG */ +} + +void translate_matrix (double x, double y, double z, Matrix m) +{ + m[0] = 1.; + m[1] = 0.; + m[2] = 0.; + m[3] = 0.; + m[4] = 0.; + m[5] = 1.; + m[6] = 0.; + m[7] = 0.; + m[8] = 0.; + m[9] = 0.; + m[10] = 1.; + m[11] = 0.; + m[12] = x; + m[13] = y; + m[14] = z; + m[15] = 1.; +} + +void scale_matrix (double x, double y, double z, Matrix m) +{ + m[0] = x; + m[1] = 0.; + m[2] = 0.; + m[3] = 0.; + m[4] = 0.; + m[5] = y; + m[6] = 0.; + m[7] = 0.; + m[8] = 0.; + m[9] = 0.; + m[10] = z; + m[11] = 0.; + m[12] = 0.; + m[13] = 0.; + m[14] = 0.; + m[15] = 1.; +} + +void rotate_x_matrix (double a, Matrix m) +{ + double a_rad; + double c, s; + + a_rad = (double) (a * RADIANS_PER_DEGREE); + c = cos(a_rad); + s = sin(a_rad); + m[0] = 1.; + m[1] = 0.; + m[2] = 0.; + m[3] = 0.; + m[4] = 0.; + m[5] = c; + m[6] = s; + m[7] = 0.; + m[8] = 0.; + m[9] = -s; + m[10] = c; + m[11] = 0.; + m[12] = 0.; + m[13] = 0.; + m[14] = 0.; + m[15] = 1.; +} + +void rotate_y_matrix (double a, Matrix m) +{ + double a_rad; + double c, s; + + a_rad = (double) (a * RADIANS_PER_DEGREE); + c = cos(a_rad); + s = sin(a_rad); + m[0] = c; + m[1] = 0.; + m[2] = -s; + m[3] = 0.; + m[4] = 0.; + m[5] = 1.; + m[6] = 0.; + m[7] = 0.; + m[8] = s; + m[9] = 0.; + m[10] = c; + m[11] = 0.; + m[12] = 0.; + m[13] = 0.; + m[14] = 0.; + m[15] = 1.; +} + +void rotate_z_matrix (double a, Matrix m) +{ + double a_rad; + double c, s; + + a_rad = (double) (a * RADIANS_PER_DEGREE); + c = cos(a_rad); + s = sin(a_rad); + m[0] = c; + m[1] = s; + m[2] = 0.; + m[3] = 0.; + m[4] = -s; + m[5] = c; + m[6] = 0.; + m[7] = 0.; + m[8] = 0.; + m[9] = 0.; + m[10] = 1.; + m[11] = 0.; + m[12] = 0.; + m[13] = 0.; + m[14] = 0.; + m[15] = 1.; +} + +void mult_matrix (Matrix ma, Matrix mb, Matrix m) +{ + m[0] = ma[0] * mb[0] + ma[1] * mb[4] + ma[2] * mb[8] + ma[3] * mb[12]; + + m[1] = ma[0] * mb[1] + ma[1] * mb[5] + ma[2] * mb[9] + ma[3] * mb[13]; + + m[2] = ma[0] * mb[2] + ma[1] * mb[6] + ma[2] * mb[10] + ma[3] * mb[14]; + + m[3] = ma[0] * mb[3] + ma[1] * mb[7] + ma[2] * mb[11] + ma[3] * mb[15]; + + m[4] = ma[4] * mb[0] + ma[5] * mb[4] + ma[6] * mb[8] + ma[7] * mb[12]; + + m[5] = ma[4] * mb[1] + ma[5] * mb[5] + ma[6] * mb[9] + ma[7] * mb[13]; + + m[6] = ma[4] * mb[2] + ma[5] * mb[6] + ma[6] * mb[10] + ma[7] * mb[14]; + + m[7] = ma[4] * mb[3] + ma[5] * mb[7] + ma[6] * mb[11] + ma[7] * mb[15]; + + m[8] = ma[8] * mb[0] + ma[9] * mb[4] + ma[10] * mb[8] + ma[11] * mb[12]; + + m[9] = ma[8] * mb[1] + ma[9] * mb[5] + ma[10] * mb[9] + ma[11] * mb[13]; + + m[10] = ma[8] * mb[2] + ma[9] * mb[6] + ma[10] * mb[10] + ma[11] * mb[14]; + + m[11] = ma[8] * mb[3] + ma[9] * mb[7] + ma[10] * mb[11] + ma[11] * mb[15]; + + m[12] = ma[12] * mb[0] + ma[13] * mb[4] + ma[14] * mb[8] + ma[15] * mb[12]; + + m[13] = ma[12] * mb[1] + ma[13] * mb[5] + ma[14] * mb[9] + ma[15] * mb[13]; + + m[14] = ma[12] * mb[2] + ma[13] * mb[6] + ma[14] * mb[10] + ma[15] * mb[14]; + + m[15] = ma[12] * mb[3] + ma[13] * mb[7] + ma[14] * mb[11] + ma[15] * mb[15]; +} diff --git a/fluffos-2.23-ds03/packages/matrix.h b/fluffos-2.23-ds03/packages/matrix.h new file mode 100644 index 0000000..88bc6f8 --- /dev/null +++ b/fluffos-2.23-ds03/packages/matrix.h @@ -0,0 +1,36 @@ +/* + * matrix.h -- definitions and prototypes for matrix.c + * 2-93 : Dwayne Fontenot : original coding. + */ + +#ifndef _MATRIX_H_ +#define _MATRIX_H_ + +#define RADIANS_PER_DEGREE 0.01745329252 + +typedef float Matrix[16]; + +typedef struct { + float x; + float y; + float z; +} Vector; + +void translate_matrix (double x, double y, double z, Matrix m); + +void scale_matrix (double x, double y, double z, Matrix m); + +void rotate_x_matrix (double a, Matrix m); + +void rotate_y_matrix (double a, Matrix m); + +void rotate_z_matrix (double a, Matrix m); + +void lookat_rotate (Matrix T, double x, double y, double z, Matrix m); + +void lookat_rotate2 + (double a, double b, double c, double d, double e, double f, Matrix m); + +void mult_matrix (Matrix m1, Matrix m2, Matrix m); + +#endif /* _MATRIX_H_ */ diff --git a/fluffos-2.23-ds03/packages/matrix_spec.c b/fluffos-2.23-ds03/packages/matrix_spec.c new file mode 100644 index 0000000..7c33ede --- /dev/null +++ b/fluffos-2.23-ds03/packages/matrix_spec.c @@ -0,0 +1,19 @@ +#include "spec.h" +/* + * Matrix efuns for Jacques' 3d mud etc. + */ + float *id_matrix(); + float *translate(float *, float, float, float); + float *scale(float *, float, float, float); + float *rotate_x(float *, float); + float *rotate_y(float *, float); + float *rotate_z(float *, float); + float *lookat_rotate(float *, float, float, float); +/* for this efun to work again, the compiler needs support for min_arg > 4. */ +/* The problem is that type checking was changed to be done for all + arguments, and a limit of 4 args was imposed. This can probably + be fixed simply by forcing such efuns to check the additional ones, + however this is the only efun affected so the fix is low priority. */ +#if 0 + float *lookat_rotate2(float *, float, float, float, float, float, float); +#endif diff --git a/fluffos-2.23-ds03/packages/mudlib_stats.c b/fluffos-2.23-ds03/packages/mudlib_stats.c new file mode 100644 index 0000000..31a62b7 --- /dev/null +++ b/fluffos-2.23-ds03/packages/mudlib_stats.c @@ -0,0 +1,601 @@ +/* + * mudlib_stats.c + * created by: Erik Kay + * last modified: 11/1/92 + * this file is a replacement for wiz_list.c and all of its purposes + * the idea is that it will be more domain based, rather than user based + * and will be a little more general purpose than wiz_list was + */ + +#ifdef LATTICE +#include "/lpc_incl.h" +#include "/backend.h" +#include "/md.h" +#include "/master.h" +#else +#include "../lpc_incl.h" +#include "../backend.h" +#include "../md.h" +#include "../master.h" +#include "../efun_protos.h" +#endif + +#include "mudlib_stats.h" + +#ifdef F_DOMAIN_STATS +void +f_domain_stats (void) +{ + mapping_t *m; + + if (st_num_arg) { + m = get_domain_stats(sp->u.string); + free_string_svalue(sp--); + } else { + m = get_domain_stats(0); + } + if (!m) { + push_number(0); + } else { + /* ref count is properly decremented by get_domain_stats */ + push_mapping(m); + } +} +#endif + +#ifdef F_SET_AUTHOR +void +f_set_author (void) +{ + set_author(sp->u.string); + free_string_svalue(sp--); +} +#endif + +#ifdef F_AUTHOR_STATS +void +f_author_stats (void) +{ + mapping_t *m; + + if (st_num_arg) { + m = get_author_stats(sp->u.string); + free_string_svalue(sp--); + } else { + m = get_author_stats(0); + } + if (!m) { + push_number(0); + } else { + /* ref count is properly decremented by get_author_stats */ + push_mapping(m); + } +} +#endif + +/* Support functions */ +static mudlib_stats_t *domains = 0; +static mudlib_stats_t *backbone_domain = 0; +static mudlib_stats_t *authors = 0; +static mudlib_stats_t *master_author = 0; + +static mudlib_stats_t *find_stat_entry (const char *, mudlib_stats_t *); +static mudlib_stats_t *add_stat_entry (const char *, mudlib_stats_t **); +static void init_author_for_ob (object_t *); +static const char *author_for_file (const char *); +static void init_domain_for_ob (object_t *); +static const char *domain_for_file (const char *); +static void save_stat_list (const char *, mudlib_stats_t *); +static void restore_stat_list (const char *, mudlib_stats_t **); +static mapping_t *get_info (mudlib_stats_t *); +static mapping_t *get_stats (const char *, mudlib_stats_t *); +static mudlib_stats_t *insert_stat_entry (mudlib_stats_t *, mudlib_stats_t **); + +#ifdef DEBUGMALLOC_EXTENSIONS +/* debugging */ +int check_valid_stat_entry (mudlib_stats_t * se) { + mudlib_stats_t *tmp; + + tmp = domains; + while (tmp) { + if (tmp == se) return 1; + tmp = tmp->next; + } + tmp = authors; + while (tmp) { + if (tmp == se) return 1; + tmp = tmp->next; + } + return 0; +} +#endif + +/************************** + * stat list manipulation + **************************/ + +static mudlib_stats_t *insert_stat_entry (mudlib_stats_t * entry, mudlib_stats_t ** list) +{ + entry->next = *list; + *list = entry; + return *list; +} + +/* + * Return the data for an individual domain, if it exists. + * this uses a simple linear search. it's a good thing that most muds + * will have a relatively small number of domains + */ +static mudlib_stats_t *find_stat_entry (const char * name, mudlib_stats_t * list) +{ + int length; + + length = strlen(name); + for (; list; list = list->next) + if (list->length == length && strcmp(list->name, name) == 0) + return list; + return 0; +} + +/* + * add a new domain to the domain list. If it exists, do nothing. + */ +static mudlib_stats_t *add_stat_entry (const char * str, mudlib_stats_t ** list) +{ + mudlib_stats_t *entry; + + if ((entry = find_stat_entry(str, *list))) + return entry; + entry = ALLOCATE(mudlib_stats_t, TAG_MUDLIB_STATS, "add_stat_entry"); + entry->name = make_shared_string(str); + entry->length = strlen(str); + entry->moves = 0; + entry->heart_beats = 0; + entry->errors = 0; + entry->objects = 0; + entry->next = NULL; + entry->size_array = 0; + insert_stat_entry(entry, list); + return entry; +} + + +/************************************* + * general stat modifying accessor functions + **************************************/ + + +void assign_stats (statgroup_t * st, object_t * ob) +{ + st->domain = ob->stats.domain; + st->author = ob->stats.author; +} + +void null_stats (statgroup_t * st) +{ + if (st) { + st->domain = NULL; + st->author = NULL; + } +} + +void init_stats_for_object (object_t * ob) +{ + init_domain_for_ob(ob); + init_author_for_ob(ob); +} + + +/* + * Add moves to an existing domain. + */ +void add_moves (statgroup_t * st, int moves) +{ + if (st) { + if (st->domain) + st->domain->moves += moves; + if (st->author) + st->author->moves += moves; + } +} + +INLINE void add_heart_beats (statgroup_t * st, int hbs) +{ + if (st) { + if (st->domain) + st->domain->heart_beats += hbs; + if (st->author) + st->author->heart_beats += hbs; + } +} + +void add_array_size (statgroup_t * st, int size) +{ + if (st) { + if (st->domain) + st->domain->size_array += size; + if (st->author) + st->author->size_array += size; + } +} + +void add_errors (statgroup_t * st, int errors) +{ + if (st) { + if (st->domain) + st->domain->errors += errors; + if (st->author) + st->author->errors += errors; + } +} + +void add_errors_for_file (const char * file, int errors) +{ + mudlib_stats_t *entry; + const char *name; + + name = domain_for_file(file); + if (name && domains) { + entry = find_stat_entry(name, domains); + if (entry) + entry->errors += errors; + } + name = author_for_file(file); + if (name && authors) { + entry = find_stat_entry(name, authors); + if (entry) + entry->errors += errors; + } +} + +void add_objects (statgroup_t * st, int objects) +{ + if (st) { + if (st->domain) + st->domain->objects += objects; + if (st->author) + st->author->objects += objects; + } +} + +/* + * Basically the "scores" are averaged over time by having them decay + * gradually at each reset. + * Here's how the decay breaks down: + * moves -= 1% + * heart_beats -= 10% + */ +void mudlib_stats_decay() +{ + mudlib_stats_t *dl; + static int next_time; + + /* Perform this once every hour. */ + if (next_time > current_time) + return; + next_time = current_time + 60 * 60; + for (dl = domains; dl; dl = dl->next) { + dl->moves = dl->moves * 99 / 100; + dl->heart_beats = dl->heart_beats * 9 / 10; + } + for (dl = authors; dl; dl = dl->next) { + dl->moves = dl->moves * 99 / 100; + dl->heart_beats = dl->heart_beats * 9 / 10; + } +} + +#ifdef DEBUGMALLOC_EXTENSIONS +void mark_mudlib_stats() { + mudlib_stats_t *dl; + + for (dl = domains; dl; dl = dl->next) { + DO_MARK(dl, TAG_MUDLIB_STATS); + EXTRA_REF(BLOCK(dl->name))++; + } + for (dl = authors; dl; dl = dl->next) { + DO_MARK(dl, TAG_MUDLIB_STATS); + EXTRA_REF(BLOCK(dl->name))++; + } +} +#endif + +/************************* + Author specific functions + *************************/ + +static void init_author_for_ob (object_t * ob) +{ + svalue_t *ret; + + push_malloced_string(add_slash(ob->obname)); + ret = apply_master_ob(APPLY_AUTHOR_FILE, 1); + if (ret == (svalue_t *)-1) { + ob->stats.author = master_author; + } else if (!ret || ret->type != T_STRING) { + ob->stats.author = NULL; + } else { + ob->stats.author = add_stat_entry(ret->u.string, &authors); + } +} + +void set_author (const char *name) +{ + object_t *ob; + + if (!current_object) + return; + ob = current_object; + if (master_ob == (object_t *)-1) { + ob->stats.author = NULL; + return; + } + if (ob->stats.author) { + ob->stats.author->objects--; + } + ob->stats.author = add_stat_entry(name, &authors); + if (ob->stats.author) { + ob->stats.author->objects++; + } +} + +mudlib_stats_t *set_master_author (const char * str) +{ + mudlib_stats_t *author; + + author = add_stat_entry(str, &authors); + if (author) + master_author = author; + return author; +} + +static const char *author_for_file (const char * file) +{ + svalue_t *ret; + static char buff[50]; + + copy_and_push_string(file); + ret = apply_master_ob(APPLY_AUTHOR_FILE, 1); + if (ret == 0 || ret == (svalue_t*)-1 || ret->type != T_STRING) + return 0; + strcpy(buff, ret->u.string); + return buff; +} + + +/************************* + Domain specific functions + *************************/ + +static void init_domain_for_ob (object_t * ob) +{ + svalue_t *ret; + const char *domain_name; + + if (!current_object +#ifdef PACKAGE_UIDS + || !current_object->uid +#endif + ) { + /* + * Only for the master and void object. Note that you can't ask for + * the backbone or root domain here since we're in the process of + * loading the master object. + */ + ob->stats.domain = add_stat_entry("NONAME", &domains); + return; + } + /* + * Ask master object who the creator of this object is. + */ + push_malloced_string(add_slash(ob->obname)); + + if (master_ob) + ret = apply_master_ob(APPLY_DOMAIN_FILE, 1); + else + ret = apply(applies_table[APPLY_DOMAIN_FILE], ob, 1, ORIGIN_DRIVER); + + if (IS_ZERO(ret)) { + ob->stats.domain = current_object->stats.domain; + return; + } + if (ret->type != T_STRING) + error("'domain_file' in the master object must return a string!\n"); + domain_name = ret->u.string; + if (strcmp(current_object->stats.domain->name, domain_name) == 0) { + ob->stats.domain = current_object->stats.domain; + return; + } + if (strcmp(backbone_domain->name, domain_name) == 0) { + /* + * The object is loaded from backbone. We give domain ownership to + * the creator rather than backbone. + */ + ob->stats.domain = current_object->stats.domain; + return; + } + /* + * The object isn't loaded from backbone or from the same domain as the + * creator, so we need to lookup the domain, and add it if it isnt + * present. + */ + ob->stats.domain = add_stat_entry(domain_name, &domains); + return; +} + +mudlib_stats_t *set_backbone_domain (const char * str) +{ + mudlib_stats_t *dom; + + dom = add_stat_entry(str, &domains); + if (dom) + backbone_domain = dom; + return dom; +} + + +/* + * Argument is a file name, which we want to get the domain of. + * Ask the master object. + */ +static const char *domain_for_file (const char * file) +{ + svalue_t *ret; + static char buff[512]; + + share_and_push_string(file); + ret = apply_master_ob(APPLY_DOMAIN_FILE, 1); + if (ret == 0 || ret == (svalue_t*)-1 || ret->type != T_STRING) + return 0; + strcpy(buff, ret->u.string); + return buff; +} + + +/************************************ + * save and restore stats to a file * + ************************************/ + +static void save_stat_list (const char * file, mudlib_stats_t * list) +{ + FILE *f; + char fname_buf[MAXPATHLEN]; + char *fname = fname_buf; + + if (file) { + if (strchr(file, '/')) { + if (file[0] == '/') + file++; + f = fopen(file, "w"); + } else { + sprintf(fname, "%s/%s", LOG_DIR, file); + if (fname[0] == '/') + fname++; + f = fopen(fname, "w"); + } + } else { + debug_message("*Warning: call to save_stat_list with null filename\n"); + return; + } + if (!f) { + debug_message("*Error: unable to open stat file %s for writing.\n", + file); + return; + } + while (list) { + fprintf(f, "%s %d %d\n", list->name, + list->moves, list->heart_beats); + list = list->next; + } + fclose(f); +} + +static void restore_stat_list (const char * file, mudlib_stats_t ** list) +{ + FILE *f; + char fname_buf[MAXPATHLEN]; + char *fname = fname_buf; + mudlib_stats_t *entry; + + if (file) { + if (strchr(file, '/')) { + if (file[0] == '/') + file++; + f = fopen(file, "r"); + } else { + sprintf(fname, "%s/%s", LOG_DIR, file); + if (fname[0] == '/') + fname++; + f = fopen(fname, "r"); + } + } else { + debug_message("*Warning: call to save_stat_list with null filename\n"); + return; + } + if (!f) { + debug_message("*Warning: unable to open stat file %s for reading.\n", + file); + return; + } + while (fscanf(f, "%s", fname) != EOF) { + entry = add_stat_entry(fname, list); + fscanf(f, "%d %d\n", &entry->moves, &entry->heart_beats); + } + fclose(f); +} + + +void save_stat_files() +{ + save_stat_list(DOMAIN_STATS_FILE_NAME, domains); + save_stat_list(AUTHOR_STATS_FILE_NAME, authors); +} + +void restore_stat_files() +{ + restore_stat_list(DOMAIN_STATS_FILE_NAME, &domains); + restore_stat_list(AUTHOR_STATS_FILE_NAME, &authors); +} + + +/************************************* + * The following functions are the interface for efuns to get mappings + * that describe the statistics for authors and domains. + **************************************/ + +static mapping_t * + get_info (mudlib_stats_t * dl) +{ + mapping_t *ret; + + ret = allocate_mapping(8); + add_mapping_pair(ret, "moves", dl->moves); + add_mapping_pair(ret, "errors", dl->errors); + add_mapping_pair(ret, "heart_beats", dl->heart_beats); + add_mapping_pair(ret, "array_size", dl->size_array); + add_mapping_pair(ret, "objects", dl->objects); + return ret; +} + +static mapping_t * + get_stats (const char * str, mudlib_stats_t * list) +{ + mudlib_stats_t *dl; + mapping_t *m; + svalue_t lv, *s; + + if (str) { + for (dl = list; dl; dl = dl->next) { + if (!strcmp(str, dl->name)) /* are these both shared strings? */ + break; + } + if (dl) { + mapping_t *tmp; + + tmp = get_info(dl); + tmp->ref--; + return tmp; + } else { + return 0; + } + } + m = allocate_mapping(8); + for (dl = list; dl; dl = dl->next) { + lv.type = T_STRING; + lv.subtype = STRING_SHARED; + lv.u.string = dl->name; /* find_for_insert() adds a ref */ + s = find_for_insert(m, &lv, 1); + s->type = T_MAPPING; + s->subtype = 0; + s->u.map = get_info(dl); + } + m->ref--; + return m; +} + +mapping_t *get_domain_stats (const char * str){ + return get_stats(str, domains); +} + +mapping_t *get_author_stats (const char * str){ + return get_stats(str, authors); +} diff --git a/fluffos-2.23-ds03/packages/mudlib_stats.h b/fluffos-2.23-ds03/packages/mudlib_stats.h new file mode 100644 index 0000000..e24e46c --- /dev/null +++ b/fluffos-2.23-ds03/packages/mudlib_stats.h @@ -0,0 +1,59 @@ +/* + * mudlib_stats.h + * created by: Erik Kay + * last modified: 11/1/92 + * this file is a replacement for wiz_list.h and all of its purposes + * the idea is that it will be more domain based, rather than user based + * and will be a little more general purpose than wiz_list was + */ + +#if !defined(MUDLIB_STATS_H) && defined(PACKAGE_MUDLIB_STATS) +#define MUDLIB_STATS_H + +typedef struct _mstats { + /* the name of the stat group */ + const char *name; + int length; + /* the next data element in the linked list */ + struct _mstats *next; + /* statistics */ + int moves; + int heart_beats; + int size_array; + int errors; + int objects; +} mudlib_stats_t; + + +typedef struct _statgroup { + mudlib_stats_t *domain; + mudlib_stats_t *author; +} statgroup_t; + +#define DOMAIN_STATS_FILE_NAME "domain_stats" +#define AUTHOR_STATS_FILE_NAME "author_stats" + +void assign_stats (statgroup_t *, struct object_s *); +void null_stats (statgroup_t *); +void init_stats_for_object (struct object_s *); + +void add_moves (statgroup_t *, int); +INLINE void add_heart_beats (statgroup_t *, int); +void add_array_size (statgroup_t *, int); +void add_errors (statgroup_t *, int); +void add_errors_for_file (const char *, int); +void add_objects (statgroup_t *, int); +struct mapping_s *get_domain_stats (const char *); +struct mapping_s *get_author_stats (const char *); +void mudlib_stats_decay (void); +void save_stat_files (void); +void restore_stat_files (void); +void set_author (const char *); +mudlib_stats_t *set_master_author (const char *); +mudlib_stats_t *set_backbone_domain (const char *); +int check_valid_stat_entry (mudlib_stats_t *); +#ifdef DEBUGMALLOC_EXTENSIONS +void mark_mudlib_stats (void); +#endif + +#endif diff --git a/fluffos-2.23-ds03/packages/mudlib_stats_spec.c b/fluffos-2.23-ds03/packages/mudlib_stats_spec.c new file mode 100644 index 0000000..9d74a33 --- /dev/null +++ b/fluffos-2.23-ds03/packages/mudlib_stats_spec.c @@ -0,0 +1,5 @@ +#include "spec.h" + + mapping domain_stats(void | string); + void set_author(string); + mapping author_stats(void | string); diff --git a/fluffos-2.23-ds03/packages/parser.c b/fluffos-2.23-ds03/packages/parser.c new file mode 100644 index 0000000..0534f90 --- /dev/null +++ b/fluffos-2.23-ds03/packages/parser.c @@ -0,0 +1,3457 @@ +/* + * Parsing efuns. Many of the concepts and algorithms here are stolen from + * an earlier LPC parser written by Rust@ZorkMUD. + */ +/* + * TODO: + * . he, she, it, him, her, them -> "look at tempress. get sword. kill her with it" + * . compound input -> "n. e then s." + * . OBS: and, all and everything (all [of] X, X except [for] Y, X and Y) + * . OBS in OBS + * . possesive: my his her its their Beek's + * . one, two, ... + * . questions. 'Take what?' + * . oops + * . the 'her' ambiguity + * . foo, who is ... foo, where is ... foo, what is ... foo, go south + * . where is ... "where is sword" -> "In the bag on the table" + * . > Which button do you mean, the camera button or the recorder button? + * . Zifnab's crasher + */ + +#include "../std.h" +#include "../lpc_incl.h" +#include "parser.h" +#include "../md.h" +#include "../master.h" +#include "../efun_protos.h" + +/* + * These match routines in the LIMA mudlib. [The fact that this file was + * written by an author of the LIMA mudlib is just a coincidence. Honest.] + */ +#define IS_LIVING "is_living" +#define INVENTORY_ACCESSIBLE "inventory_accessible" +#define INVENTORY_VISIBLE "inventory_visible" +/* Named during a fit of madness */ +#define LIVINGS_ARE_REMOTE "livings_are_remote" + +#define MAX_WORDS_PER_LINE 256 +#define MAX_WORD_LENGTH 1024 +#define MAX_MATCHES 10 +#define CHAR_FUNC 1024 +#define CHAR_BUF 1024 + +char *pluralize (char *); + +#define MS_HAS_LITERALS 1 +#define MS_HAS_SPECIALS 2 +#define MS_HAS_USERS 4 +static int master_state = 0; + +static parse_info_t *pi = 0; +static hash_entry_t *hash_table[HASH_SIZE]; +static special_word_t *special_table[SPECIAL_HASH_SIZE]; +static verb_t *verbs[VERB_HASH_SIZE]; +static int objects_loaded = 0; +static int num_objects, num_people, me_object; +static struct object_s *loaded_objects[MAX_NUM_OBJECTS]; +static int object_flags[MAX_NUM_OBJECTS]; +static bitvec_t my_objects; +static char *my_string = 0; +static int num_literals = 0; +static char **literals; +static word_t words[MAX_WORDS_PER_LINE]; +static int num_words = 0; +static verb_node_t *parse_vn; +static verb_t *parse_verb_entry; +static object_t *parse_restricted; +static object_t *parse_user; +static array_t *master_user_list = 0; +static bitvec_t cur_livings; +static bitvec_t cur_accessible; +static int best_match; +static int best_error_match; +static int best_num_errors; +static parse_result_t *best_result = 0; +static match_t matches[MAX_MATCHES]; +static int found_level = 0; +static mapping_t *parse_nicks = 0; +static array_t *parse_env = 0; + +static int direct_object, indirect_object; + +static parser_error_t current_error_info; +static parser_error_t best_error_info; +static parser_error_t parallel_error_info; +static parser_error_t second_parallel_error_info; + +static saved_error_t *parallel_errors = 0; + +#if defined(DEBUG) || defined(PARSE_DEBUG) +static int debug_parse_depth = 0; +static int debug_parse_verbose = 0; + +#define DEBUG_PP(x) if (debug_parse_depth && debug_parse_verbose) debug_parse x +#define DEBUG_P(x) if (debug_parse_depth) debug_parse x +#define DEBUG_INC if (debug_parse_depth) debug_parse_depth++ +#define DEBUG_DEC if (debug_parse_depth) debug_parse_depth-- +#else +#define DEBUG_PP(x) +#define DEBUG_P(x) +#define DEBUG_INC +#define DEBUG_DEC +#endif + +static void parse_rule (parse_state_t *); +static void clear_parallel_errors (saved_error_t **); +static svalue_t *get_the_error (parser_error_t *, int); + +#define isignore(x) (!uisprint(x) || x == '\'') +#define iskeep(x) (uisalnum(x) || x == '*' || x == '?' || x == '!'|| x == '.'|| x == ':') + +#define SHARED_STRING(x) ((x)->subtype == STRING_SHARED ? (x)->u.string : findstring((x)->u.string)) + +#define NEED_REFRESH(ob) (ob->pinfo && ((ob->pinfo->flags & (PI_SETUP|PI_REFRESH)) != PI_SETUP)) + +/* parse_init() - setup the object + * parse_refresh() - refresh an object's parse data + * parse_add_rule(verb, rule) - add a rule for a verb + * parse_sentence(sent) - do the parsing :) + */ + +#ifdef DEBUGMALLOC_EXTENSIONS +static void mark_error (parser_error_t * pe) { + if (pe->error_type == ERR_ALLOCATED) { + MSTR_EXTRA_REF(pe->err.str)++; + } +} + +void parser_mark_verbs() { + int i, j; + + if (best_result) { +#ifdef DEBUGMALLOC_EXTENSIONS + if (best_result->ob) + best_result->ob->extra_ref++; +#endif + if (best_result->parallel) + /* mark parallel errors */; + + for (i = 0; i < 4; i++) { + if (best_result->res[i].func) + MSTR_EXTRA_REF(best_result->res[i].func)++; + if (best_result->res[i].args) { + for (j = 0; j < best_result->res[i].num; j++) + mark_svalue(((svalue_t *)best_result->res[i].args) + j); + /* mark best_result->res[i].args */; + } + } + /* mark best_result */ + } + + mark_error(¤t_error_info); + mark_error(&best_error_info); + mark_error(¶llel_error_info); + mark_error(&second_parallel_error_info); + + for (i = 0; i < VERB_HASH_SIZE; i++) { + verb_t *verb_entry = verbs[i]; + + while (verb_entry) { + EXTRA_REF(BLOCK(verb_entry->real_name))++; + EXTRA_REF(BLOCK(verb_entry->match_name))++; + verb_entry = verb_entry->next; + } + } + + for (i = 0; i < num_literals; i++) { + EXTRA_REF(BLOCK(literals[i]))++; + } + + for (i = 0; i < SPECIAL_HASH_SIZE; i++) { + special_word_t *swp = special_table[i]; + + while (swp) { + EXTRA_REF(BLOCK(swp->wrd))++; + swp = swp->next; + } + } + if (my_string) + EXTRA_REF(BLOCK(my_string))++; +#ifdef DEBUGMALLOC_EXTENSIONS + if (master_user_list) + master_user_list->extra_ref++; +#endif +} + +void parser_mark (parse_info_t * pinfo) { + int i; + + if (!(pinfo->flags & PI_SETUP)) + return; + + for (i = 0; i < pinfo->num_ids; i++) { + EXTRA_REF(BLOCK(pinfo->ids[i]))++; + } + for (i = 0; i < pinfo->num_adjs; i++) { + EXTRA_REF(BLOCK(pinfo->adjs[i]))++; + } + for (i = 0; i < pinfo->num_plurals; i++) { + EXTRA_REF(BLOCK(pinfo->plurals[i]))++; + } +} +#endif + +#if defined(DEBUG) || defined(PARSE_DEBUG) +/* Usage: DEBUG_P(("foo: %s:%i", str, i)); */ +static void debug_parse(char *fmt, ...) { + va_list args; + char buf[2048]; + char *p = buf; + int n = debug_parse_depth - 1; + + while (n--) { + *p++ = ' '; + *p++ = ' '; + } + + va_start(args, fmt); + vsprintf(p, fmt, args); + va_end(args); + + tell_object(command_giver, buf, strlen(buf)); + tell_object(command_giver, "\n", 1); +} +#endif + +INLINE_STATIC void bitvec_copy (bitvec_t * b1, bitvec_t * b2) { + int i, n = b2->last; + + b1->last = n; + for (i = 0; i < n; i++) + b1->b[i] = b2->b[i]; +} + +INLINE_STATIC void bitvec_zero (bitvec_t * bv) { + bv->last = 0; +} + +INLINE_STATIC void bitvec_set (bitvec_t * bv, int elem) { + int which = BV_WHICH(elem); + + if (which >= bv->last) { + int i; + + for (i = bv->last; i < which; i++) + bv->b[i] = 0; + bv->b[which] = BV_BIT(elem); + bv->last = which + 1; + } else { + bv->b[which] |= BV_BIT(elem); + } +} + +INLINE_STATIC int intersect (bitvec_t * bv1, bitvec_t * bv2) { + int i, found = 0; + int n = (bv1->last < bv2->last ? bv1->last : bv2->last); + + bv1->last = n; + for (i = 0; i < n; i++) + if (bv1->b[i] &= bv2->b[i]) found = 1; + + return found; +} + +static int bitvec_count (bitvec_t * bv) { + static int counts[16] = { +/* 0000 */ 0, /* 0001 */ 1, /* 0010 */ 1, /* 0011 */ 2, +/* 0100 */ 1, /* 0101 */ 2, /* 0110 */ 2, /* 0111 */ 3, +/* 1000 */ 1, /* 1001 */ 2, /* 1010 */ 2, /* 1011 */ 3, +/* 1100 */ 2, /* 1101 */ 3, /* 1110 */ 3, /* 1111 */ 4 + }; + + int ret = 0; + int i, j; + + for (i = 0; i < bv->last; i++) { + unsigned int k = bv->b[i]; + if (k) { + for (j = 0; j < 8; j++) { + ret += counts[k & 15]; + k >>= 4; + } + } + } + return ret; +} + +static void all_objects (bitvec_t * bv, int remote_flag) { + int i; + int num = (remote_flag ? num_objects : num_objects - num_people); + int last = BV_WHICH(num); + + i = last; + while (i--) + bv->b[i] = ~0; + if (num < MAX_NUM_OBJECTS) { + bv->b[last] = BV_BIT(num) - 1; + bv->last = last + 1; + } else + bv->last = last; +} + +/* Note: + * For efficiency reasons, there is very little memory allocation in the + * code. We take advantage of the fact that the algorithm is recursive, + * and a parse_* routine doesn't return until that branch has been completely + * evaluated. This allows us to safely keep pointers to temporary buffers + * on the stack. + * + * alloca() would be better for this, but MudOS doesn't currently use it. + */ + +INLINE_STATIC match_t *add_match (parse_state_t * state, int token, + int start, int end) { + match_t *ret; + + DEBUG_PP(("Adding match: tok = %i start = %i end = %i", token, start, end)); + ret = &matches[state->num_matches++]; + ret->first = start; + ret->last = end; + ret->token = token; + if (token == ERROR_TOKEN) + state->num_errors++; + + DEBUG_PP(("State is: %x, num_errors: %i\n", state, state->num_errors)); + return ret; +} + +static int parse_copy_array (array_t * arr, char *** sarrp) { + const char **table; + char **table2; + int j; + int n = 0; + + if (!arr->size) { + *sarrp = 0; + return 0; + } + + table2 = *sarrp = CALLOCATE(arr->size, char *, + TAG_PARSER, "parse_copy_array"); + table = (const char **)table2; + for (j = 0; j < arr->size; j++) { + if (arr->item[j].type == T_STRING) { + DEBUG_PP(("Got: %s", arr->item[j].u.string)); + if (arr->item[j].subtype == STRING_SHARED) { + table[n++] = ref_string(arr->item[j].u.string); + } else { + table[n++] = make_shared_string(arr->item[j].u.string); + } + } + } + if (n != arr->size) + *sarrp = RESIZE(table, n, char *, TAG_PARSER, "parse_copy_array"); + return n; +} + +static void add_special_word (char * wrd, int kind, int arg) { + char *p = make_shared_string(wrd); + int h = DO_HASH(p, SPECIAL_HASH_SIZE); + special_word_t *swp = ALLOCATE(special_word_t, TAG_PARSER, "add_special_word"); + + swp->wrd = p; + swp->kind = kind; + swp->arg = arg; + swp->next = special_table[h]; + special_table[h] = swp; +} + +static int check_special_word (char * wrd, long *arg) { + int h = DO_HASH(wrd, SPECIAL_HASH_SIZE); + special_word_t *swp = special_table[h]; + + while (swp) { + if (swp->wrd == wrd) { + *arg = swp->arg; + return swp->kind; + } + swp = swp->next; + } + + if (isdigit(*wrd)) { + char *p; + + *arg = strtol(wrd, &p, 10); + if (p && *p) { + char *ending = "th"; + + if (p - wrd < 2 || *(p - 2) != '1') { + switch (*(p - 1)) { + case '1': ending = "st"; break; + case '2': ending = "nd"; break; + case '3': ending = "rd"; break; + } + } + + if (!strcmp(p, ending)) + return SW_ORDINAL; + } + } + + return SW_NONE; +} + +static void interrogate_master (void) { + svalue_t *ret; + + if ((master_state & MS_HAS_USERS) == 0) { + DEBUG_PP(("[master::parse_command_users]")); + if (master_user_list) { + free_array(master_user_list); + master_user_list = 0; + } + + DEBUG_PP(("[%s]", applies_table[APPLY_USERS])); + ret = apply_master_ob(APPLY_USERS, 0); + if (ret && ret->type == T_ARRAY) { + master_user_list = ret->u.arr; + ret->u.arr->ref++; + } else { + master_user_list = &the_null_array; + } + master_state |= MS_HAS_USERS; + } + if ((master_state & MS_HAS_LITERALS) == 0) { + if (literals) { + int i; + + for (i = 0; i < num_literals; i++) + free_string(literals[i]); + FREE(literals); + num_literals = 0; + literals = 0; + } + + DEBUG_PP(("[%s]", applies_table[APPLY_LITERALS])); + ret = apply_master_ob(APPLY_LITERALS, 0); + + if (ret && ret->type == T_ARRAY) + num_literals = parse_copy_array(ret->u.arr, &literals); + else + num_literals = 0; + master_state |= MS_HAS_LITERALS; + } + if ((master_state & MS_HAS_SPECIALS) == 0) { + add_special_word("the", SW_ARTICLE, 0); + + add_special_word("me", SW_SELF, 0); + add_special_word("myself", SW_SELF, 0); + + add_special_word("all", SW_ALL, 0); + add_special_word("of", SW_OF, 0); + + add_special_word("and", SW_AND, 0); + + add_special_word("a", SW_ORDINAL, 1); + add_special_word("an", SW_ORDINAL, 1); + add_special_word("any", SW_ORDINAL, 1); + + add_special_word("first", SW_ORDINAL, 1); + add_special_word("second", SW_ORDINAL, 2); + add_special_word("other", SW_ORDINAL, 2); + add_special_word("third", SW_ORDINAL, 3); + add_special_word("fourth", SW_ORDINAL, 4); + add_special_word("fifth", SW_ORDINAL, 5); + add_special_word("sixth", SW_ORDINAL, 6); + add_special_word("seventh", SW_ORDINAL, 7); + add_special_word("eighth", SW_ORDINAL, 8); + add_special_word("ninth", SW_ORDINAL, 9); + + master_state |= MS_HAS_SPECIALS; + } +} + +void f_parse_init (void) { + parse_info_t *pi; + + if (current_object->pinfo) + return; + + pi = current_object->pinfo = ALLOCATE(parse_info_t, TAG_PARSER, "parse_init"); + pi->ob = current_object; + pi->flags = 0; +} + +static void remove_ids (parse_info_t * pinfo) { + int i; + + if (pinfo->flags & PI_SETUP) { + if (pinfo->num_ids) { + for (i = 0; i < pinfo->num_ids; i++) + free_string(pinfo->ids[i]); + FREE(pinfo->ids); + } + if (pinfo->num_plurals) { + for (i = 0; i < pinfo->num_plurals; i++) + free_string(pinfo->plurals[i]); + FREE(pinfo->plurals); + } + if (pinfo->num_adjs) { + for (i = 0; i < pinfo->num_adjs; i++) + free_string(pinfo->adjs[i]); + FREE(pinfo->adjs); + } + pinfo->num_ids = pinfo->num_plurals = pinfo->num_adjs = 0; + pinfo->ids = pinfo->plurals = pinfo->adjs = 0; + } +} + +/* The parse_refresh() efun. Used to inform the parsing package that + * information returned by applies to current_object may have changed, + * and should be recached when necessary. + */ +void f_parse_refresh (void) { + parse_info_t *pi; + + /* If this is the master object, prepare to go through + * interrogate_master() again. Don't free the literals now, or + * things can dangle if we are in the middle of a parse. + */ + if (current_object == master_ob) { + master_state &= ~MS_HAS_USERS; + if (!master_ob->pinfo) + return; + } + + if (!(pi = current_object->pinfo)) + error("/%s is not known by the parser. Call parse_init() first.\n", + current_object->obname); + + if (pi->flags & PI_SETUP) { + pi->flags &= PI_VERB_HANDLER; + pi->flags |= PI_REFRESH; + } else { + pi->flags &= PI_VERB_HANDLER; + } + + /* Recheck this immediately since we don't resync handler objects, only + * object involved in the parse. + */ + if (pi->flags & PI_VERB_HANDLER) { + svalue_t *ret = apply(LIVINGS_ARE_REMOTE, current_object, + 0, ORIGIN_DRIVER); + if (current_object->flags & O_DESTRUCTED) + return; + + if (!IS_ZERO(ret)) + pi->flags |= PI_REMOTE_LIVINGS; + } +} + +/* called from free_object() */ +void parse_free (parse_info_t * pinfo) { + int i; + + if (pinfo->flags & PI_VERB_HANDLER) { + for (i = 0; i < VERB_HASH_SIZE; i++) { + verb_t *v = verbs[i]; + while (v) { + verb_node_t **vn = &(v->node), *old; + while (*vn) { + if ((*vn)->handler == pinfo->ob) { + old = *vn; + *vn = (*vn)->next; + FREE(old); + } else vn = &((*vn)->next); + } + v = v->next; + } + } + } + remove_ids(pinfo); + FREE(pinfo); +} + +static void hash_clean (void) { + int i; + hash_entry_t **nodep, *next; + + for (i = 0; i < HASH_SIZE; i++) { + for (nodep = &hash_table[i]; *nodep && ((*nodep)->flags & HV_PERM); + nodep = &((*nodep)->next)) + ; + while (*nodep) { + next = (*nodep)->next; + free_string((*nodep)->name); + FREE((*nodep)); + *nodep = next; + } + } +} + +static void free_parse_result (parse_result_t * pr) { + int i, j; + + if (pr->ob) + free_object(&pr->ob, "free_parse_result"); + if (pr->parallel) + clear_parallel_errors(&pr->parallel); + + for (i = 0; i < 4; i++) { + if (pr->res[i].func) FREE_MSTR(pr->res[i].func); + if (pr->res[i].args) { + for (j = 0; j < pr->res[i].num; j++) + free_svalue(((svalue_t *)pr->res[i].args) + j, "free_parse_result"); + FREE(pr->res[i].args); + } + } + FREE(pr); +} + +static void clear_result (parse_result_t * pr) { + int i; + + pr->ob = 0; + pr->parallel = 0; + + for (i = 0; i < 4; i++) { + pr->res[i].func = 0; + pr->res[i].args = 0; + } +} + +static void free_parse_globals (void) { + int i; + + if (parse_nicks) + free_mapping(parse_nicks); + if (parse_env) + free_array(parse_env); + + parse_nicks = 0; + parse_env = 0; + + pi = 0; + hash_clean(); + if (objects_loaded) { + for (i = 0; i < num_objects; i++) + free_object(&loaded_objects[i], "free_parse_globals"); + objects_loaded = 0; + } +} + +token_def_t tokens[] = { + { "OBJ", OBJ_A_TOKEN, 1 }, + { "STR", STR_TOKEN, 0 }, + { "WRD", WRD_TOKEN, 0 }, + { "LIV", LIV_A_TOKEN, 1 }, + { "OBS", OBS_TOKEN, 1 }, + { "LVS", LVS_TOKEN, 1 }, + { 0, 0 } +}; + +#define STR3CMP(x, y) (x[0] == y[0] && x[1] == y[1] && x[2] == y[2]) + +static int tokenize (const char ** rule, int * weightp) { + const char *start = *rule; + int i, n; + token_def_t *td; + + while (*start == ' ') start++; + + if (!*start) + return 0; /* at the end */ + + *rule = strchr(start, ' '); + + if (!*rule) + *rule = start + strlen(start); + + n = *rule - start; + + if (n == 3 || (n > 4 && start[3] == ':')) { + td = tokens; + while (td->name) { + if (STR3CMP(td->name, start)) { + i = td->token; + if (n != 3) { + if (!td->mod_legal) + error("Illegal to have modifiers to '%s'\n", td->name); + /* modifiers */ + start += 4; + n -= 4; + while (n--) { + switch(*start++) { + case 'l': + i |= LIV_MODIFIER; + break; + case 'v': + i |= VIS_ONLY_MODIFIER; + break; + case 'p': + i |= PLURAL_MODIFIER; + break; + case 'c': + i |= CHOOSE_MODIFIER; + break; + default: + error("Unknown modifier '%c'\n", start[-1]); + } + } + } + switch (i) { + default: + /* some kind of object */ + (*weightp) += 2; + /* This next one is b/c in the presence of a singular + * and plural match, we want the singular. Consider + * 'take fish' with >1 fish. */ + if (i & PLURAL_MODIFIER) + (*weightp)--; + if (i & LIV_MODIFIER) + (*weightp)++; + if (!(i & VIS_ONLY_MODIFIER)) + (*weightp)++; + break; + case STR_TOKEN: + case WRD_TOKEN: + (*weightp)++; + } + return i; + } + td++; + } + } + + (*weightp)++; /* must be a literal */ + + /* it's not a standard token. Check the literals */ + for (i = 0; i < num_literals; i++) { + if (strlen(literals[i]) == n && (strncmp(literals[i], start, n) == 0)) + return -(i + 1); + } + + { + char buf[CHAR_BUF]; + + if (n > 50) { + strncpy(buf, start, 50); + strcpy(buf + 50, "..."); + } else { + strncpy(buf, start, n); + buf[n] = 0; + } + + error("Unknown token '%s'\n", buf); + } + return 0; +} + +static void make_rule (const char * rule, int * tokens, int * weightp) { + int idx = 0; + int has_plural = 0; + int has_obj = 0; + + *weightp = 1; + while (idx < MAX_MATCHES) { + if (!(tokens[idx] = tokenize(&rule, weightp))) + return; /* we got to the end */ + if (tokens[idx] >= OBJ_A_TOKEN) { + if (++has_obj == 3) + error("Only two object tokens allowed per rule.\n"); + if (tokens[idx] & PLURAL_MODIFIER) { + if (has_plural) error("Only one plural token allowed per rule.\n"); + has_plural = 1; + } + } + idx++; + } + error("Only %i tokens permitted per rule!\n", MAX_MATCHES); +} + +static void free_words (void) { + int i; + + for (i = 0; i < num_words; i++) + if (words[i].type == WORD_ALLOCATED) + FREE_MSTR(words[i].string); + num_words = 0; +} + +static void interrogate_object (object_t * ob) { + svalue_t *ret; + + if (ob->pinfo->flags & PI_REFRESH) + remove_ids(ob->pinfo); + + /* don't bail if we're trying to refresh! */ + if (ob->pinfo->flags & PI_SETUP && !(ob->pinfo->flags & PI_REFRESH)) + return; + + DEBUG_P(("Interogating /%s.", ob->obname)); + + DEBUG_PP(("[%s]", APPLY_NOUN)); + ret = apply(APPLY_NOUN, ob, 0, ORIGIN_DRIVER); + if (ret && ret->type == T_ARRAY) + ob->pinfo->num_ids = parse_copy_array(ret->u.arr, &ob->pinfo->ids); + else + ob->pinfo->num_ids = 0; + if (ob->flags & O_DESTRUCTED) return; + /* in case of an error */ + ob->pinfo->flags |= PI_SETUP; + ob->pinfo->flags &= ~(PI_LIVING | PI_INV_ACCESSIBLE | PI_INV_VISIBLE); + ob->pinfo->num_adjs = 0; + ob->pinfo->num_plurals = 0; + + DEBUG_PP(("[%s]", APPLY_PLURAL)); + ret = apply(APPLY_PLURAL, ob, 0, ORIGIN_DRIVER); + if (ret && ret->type == T_ARRAY) + ob->pinfo->num_plurals = parse_copy_array(ret->u.arr, &ob->pinfo->plurals); + else + ob->pinfo->num_plurals = 0; + if (ob->flags & O_DESTRUCTED) return; + + DEBUG_PP(("[%s]", APPLY_ADJECTIVE)); + ret = apply(APPLY_ADJECTIVE, ob, 0, ORIGIN_DRIVER); + if (ret && ret->type == T_ARRAY) + ob->pinfo->num_adjs = parse_copy_array(ret->u.arr, &ob->pinfo->adjs); + else + ob->pinfo->num_adjs = 0; + if (ob->flags & O_DESTRUCTED) return; + + DEBUG_PP(("[%s]", IS_LIVING)); + ret = apply(IS_LIVING, ob, 0, ORIGIN_DRIVER); + if (!IS_ZERO(ret)) { + ob->pinfo->flags |= PI_LIVING; + DEBUG_PP(("(yes)")); + } + if (ob->flags & O_DESTRUCTED) return; + + DEBUG_PP(("[%s]", INVENTORY_ACCESSIBLE)); + ret = apply(INVENTORY_ACCESSIBLE, ob, 0, ORIGIN_DRIVER); + if (!IS_ZERO(ret)) { + ob->pinfo->flags |= PI_INV_ACCESSIBLE; + DEBUG_PP(("(yes)")); + } + if (ob->flags & O_DESTRUCTED) return; + + DEBUG_PP(("[%s]", INVENTORY_VISIBLE)); + ret = apply(INVENTORY_VISIBLE, ob, 0, ORIGIN_DRIVER); + if (!IS_ZERO(ret)) { + ob->pinfo->flags |= PI_INV_VISIBLE; + DEBUG_PP(("(yes)")); + } +} + +static object_t *first_inv (object_t * ob) { +#ifndef NO_ENVIRONMENT + return ob->contains; +#else + svalue_t *ret; + + push_object(ob); + ret = apply_master_ob(APPLY_PARSE_FIRST_INVENTORY, 1); + if (ret && ret != (svalue_t *)-1 && ret->type == T_OBJECT) + return ret->u.ob; + return (object_t *)NULL; +#endif +} + +static object_t *next_inv (object_t * parent, object_t * sibling) { +#ifndef NO_ENVIRONMENT + return sibling->next_inv; +#else + svalue_t *ret; + + push_object(parent); + push_object(sibling); + ret = apply_master_ob(APPLY_PARSE_NEXT_INVENTORY, 2); + if (ret && ret != (svalue_t *)-1 && ret->type == T_OBJECT) + return ret->u.ob; + return (object_t *)NULL; +#endif +} + +static object_t *super (object_t * ob) { +#ifndef NO_ENVIRONMENT + return ob->super; +#else + svalue_t *ret; + + push_object(ob); + ret = apply_master_ob(APPLY_PARSE_ENVIRONMENT, 1); + if (ret && ret != (svalue_t *)-1 && ret->type == T_OBJECT) + return ret->u.ob; + return (object_t *)NULL; +#endif +} + +#define RAO_INREACH 1 +#define RAO_MY 2 + +static void rec_add_object (object_t * ob, int flags) { + object_t *o; + + if (!ob) return; + if (ob->flags & O_DESTRUCTED) return; + if (ob->pinfo) { + if (num_objects == MAX_NUM_OBJECTS) + return; + if (flags & RAO_MY) + bitvec_set(&my_objects, num_objects); + if (ob == parse_user) { + me_object = num_objects; + flags |= RAO_MY; + } + object_flags[num_objects] = flags & RAO_INREACH; + loaded_objects[num_objects++] = ob; + add_ref(ob, "rec_add_object"); + if (!(ob->pinfo->flags & PI_INV_VISIBLE)) + return; + if (!(ob->pinfo->flags & PI_INV_ACCESSIBLE)) + flags &= ~RAO_INREACH; + } + for (o = first_inv(ob); o; o = next_inv(ob, o)) + rec_add_object(o, flags); +} + +static void add_objects_from_array (array_t * arr, int flags) { + int i, f; + int last_flags = 0; + int last_was_me = 0; + + for (i = 0; i < arr->size; i++) { + object_t *ob; + + if (arr->item[i].type == T_ARRAY) { + f = flags; + if (last_flags & PI_INV_VISIBLE) { + if (!(last_flags & PI_INV_ACCESSIBLE)) + f &= ~RAO_INREACH; + if (last_was_me) + f |= RAO_MY; + add_objects_from_array(arr->item[i].u.arr, f); + } + } + last_flags = 0; + last_was_me = 0; + if (arr->item[i].type == T_OBJECT && + !((ob = arr->item[i].u.ob)->flags & O_DESTRUCTED)) { + if (ob->pinfo) { + if (num_objects == MAX_NUM_OBJECTS) + return; + if (flags & RAO_MY) + bitvec_set(&my_objects, num_objects); + if (ob == parse_user) { + me_object = num_objects; + last_was_me = 1; + } + object_flags[num_objects] = flags & RAO_INREACH; + loaded_objects[num_objects++] = ob; + add_ref(ob, "add_objects_from_array"); + last_flags = ob->pinfo->flags; + } + } + } +} + +static void get_objects_from_array (array_t * arr) { + int i; + + for (i = 0; i < arr->size; i++) { + object_t *ob; + + if (arr->item[i].type == T_ARRAY) + get_objects_from_array(arr->item[i].u.arr); + if (arr->item[i].type != T_OBJECT) continue; + ob = arr->item[i].u.ob; + + if (ob->flags & O_DESTRUCTED) continue; + if (NEED_REFRESH(ob)) { + if (num_objects == MAX_NUM_OBJECTS) + return; + loaded_objects[num_objects++] = ob; + add_ref(ob, "find_uninited_objects"); + } + } +} + +static void find_uninited_objects (object_t * ob) { + object_t *o; + + if (!ob) return; + if (ob->flags & O_DESTRUCTED) return; + if (NEED_REFRESH(ob)) { + if (num_objects == MAX_NUM_OBJECTS) + return; + loaded_objects[num_objects++] = ob; + add_ref(ob, "find_uninited_objects"); + } + for (o = first_inv(ob); o; o = next_inv(ob, o)) + find_uninited_objects(o); +} + +static hash_entry_t *add_hash_entry (const char * str) { + int h = DO_HASH(str, HASH_SIZE); + hash_entry_t *he; + + DEBUG_PP(("add_hash_entry: %s", str)); + he = hash_table[h]; + while (he) { + if (he->name == str) + return he; + he = he->next; + } + + he = ALLOCATE(hash_entry_t, TAG_PARSER, "add_hash_entry"); + he->name = ref_string(str); + bitvec_zero(&he->pv.noun); + bitvec_zero(&he->pv.plural); + bitvec_zero(&he->pv.adj); + he->next = hash_table[h]; + he->flags = 0; + hash_table[h] = he; + return he; +} + +void mark_hash_entry (const char * str) { + int h = DO_HASH(str, HASH_SIZE); + hash_entry_t *he; + + DEBUG_PP(("mark_hash_entry: %s", str)); + he = hash_table[h]; + while (he) { + if (he->name == str) { + he->flags |= HV_NICKNAME; + return; + } + he = he->next; + } + + he = ALLOCATE(hash_entry_t, TAG_PARSER, "mark_hash_entry"); + he->name = ref_string(str); + bitvec_zero(&he->pv.noun); + bitvec_zero(&he->pv.plural); + bitvec_zero(&he->pv.adj); + he->next = hash_table[h]; + he->flags = HV_NICKNAME; + hash_table[h] = he; +} + +static void add_to_hash_table (object_t * ob, int index) { + int i; + parse_info_t *pi = ob->pinfo; + hash_entry_t *he; + + if (!pi) /* woops. Dested during parse_command_users() or something + similarly nasty. */ + return; + DEBUG_PP(("add_to_hash_table: /%s", ob->obname)); + for (i = 0; i < pi->num_ids; i++) { + he = add_hash_entry(pi->ids[i]); + he->flags |= HV_NOUN; + bitvec_set(&he->pv.noun, index); + } + for (i = 0; i < pi->num_plurals; i++) { + he = add_hash_entry(pi->plurals[i]); + he->flags |= HV_PLURAL; + bitvec_set(&he->pv.plural, index); + } + for (i = 0; i < pi->num_adjs; i++) { + he = add_hash_entry(pi->adjs[i]); + he->flags |= HV_ADJ; + bitvec_set(&he->pv.adj, index); + } + + if (pi->flags & PI_LIVING) + bitvec_set(&cur_livings, index); + + if (object_flags[index]) + bitvec_set(&cur_accessible, index); +} + +static void init_users() { + int i; + object_t *ob; + + /* Note that destructed objects have pinfo == 0 [see free_object()], + * so we don't have to worry about them here. We could just keep a + * list of objects, but we keep an entire array anyway. + */ + for (i = 0; i < master_user_list->size; i++) { + if (master_user_list->item[i].type == T_OBJECT + && (ob = master_user_list->item[i].u.ob)->pinfo + && NEED_REFRESH(ob)) { + DEBUG_PP(("adding: /%s", ob->obname)); + if (num_objects == MAX_NUM_OBJECTS) + return; + loaded_objects[num_objects++] = ob; + add_ref(ob, "init_users"); + } + } +} + +/* Note extremely clever delayed evaluation to avoid having to lookup object + * pointer -> index + */ +static void add_nicknames (mapping_t * map) { + int i; + + for (i = 0; i < map->table_size; i++) { + mapping_node_t *mn; + + for (mn = map->table[i]; mn; mn = mn->next) { + if (mn->values[0].type == T_STRING) { + hash_entry_t *he = add_hash_entry(mn->values[0].u.string); + he->flags |= HV_NICKNAME; + } + } + } +} + +static void load_objects (void) { + int i; + object_t *ob, *env; + hash_entry_t *he; + + if (!my_string) my_string = make_shared_string("my"); + + /* 1. Find things that need to be interrogated + * 2. interrogate them + * 3. build the object list + * + * If some of this looks suboptimal, consider: + * 1. LPC code can error, and we don't want to leak, so we must be + * careful that all structures are consistent when we call LPC code + * 2. LPC code can move objects, so we don't want to call LPC code + * while walking inventories. + */ + bitvec_zero(&cur_livings); + bitvec_zero(&cur_accessible); + /* Step 1: */ + num_objects = 0; + + if (parse_env) { + get_objects_from_array(parse_env); + } else { + if (!parse_user || parse_user->flags & O_DESTRUCTED) + error("No this_player()!\n"); + + find_uninited_objects(super(parse_user)); + } + /* get users from master object */ + interrogate_master(); + init_users(); + objects_loaded = 1; + /* Step 2: */ + for (i = 0; i < num_objects; i++) + interrogate_object(loaded_objects[i]); + for (i = 0; i < num_objects; i++) + free_object(&loaded_objects[i], "load_objects"); + /* Step 3: */ + num_objects = 0; + me_object = -1; + + bitvec_zero(&my_objects); + if (parse_env) { + add_objects_from_array(parse_env, RAO_INREACH); + } else { + rec_add_object(super(parse_user), RAO_INREACH); + } + he = add_hash_entry(my_string); + he->flags |= HV_ADJ; + bitvec_copy(&he->pv.adj, &my_objects); + if (parse_nicks) + add_nicknames(parse_nicks); + + num_people = 0; + for (i = 0; i < master_user_list->size; i++) { + if (master_user_list->item[i].type != T_OBJECT) continue; + /* check if we have them already */ + ob = master_user_list->item[i].u.ob; + if (!(ob->pinfo)) + continue; + env = ob; + while (env) { + if (env == super(parse_user)) + break; + env = super(env); + if (env && env->pinfo && !(env->pinfo->flags & PI_INV_VISIBLE)) + env = 0; + } + if (env) continue; + if (num_objects + num_people == MAX_NUM_OBJECTS) + break; + object_flags[num_objects + num_people] = 1; + loaded_objects[num_objects + num_people++] = ob; + add_ref(ob, "load_objects"); + } + num_objects += num_people; + + for (i = 0; i < num_objects; i++) + add_to_hash_table(loaded_objects[i], i); +} + +static int get_single (bitvec_t * bv) { + static int answer[16] = { +/* 0000 */ -1, /* 0001 */ 0, /* 0010 */ 1, /* 0011 */ -1, +/* 0100 */ 2, /* 0101 */ -1, /* 0110 */ -1, /* 0111 */ -1, +/* 1000 */ 3, /* 1001 */ -1, /* 1010 */ -1, /* 1011 */ -1, +/* 1100 */ -1, /* 1101 */ -1, /* 1110 */ -1, /* 1111 */ -1 + }; + + int i, res = -1; + unsigned int tmp; + + for (i = 0; i < bv->last; i++) { + if (bv->b[i]) { + if (res != -1) return -1; + res = i; + } + } + if (res < 0) return -1; + + tmp = bv->b[res]; + res *= BPI; + /* Binary search for the set bit, unrolled for speed. */ + if (tmp & 0x0000ffff) { + if (tmp & 0xffff0000) + return -1; + } else { + tmp >>= 16; + res += 16; + } + + if (tmp & 0x00ff) { + if (tmp & 0xff00) + return -1; + } else { + tmp >>= 8; + res += 8; + } + + if (tmp & 0x0f) { + if (tmp & 0xf0) + return -1; + } else { + tmp >>= 4; + res += 4; + } + + tmp = answer[tmp]; + if (tmp == -1) return tmp; + + DEBUG_PP((" -> %i", res)); + return res + tmp; +} + +/* FIXME: obsolete */ +static char *query_the_short (char * start, char * end, object_t * ob) { + svalue_t *ret; + + if (ob==NULL || ob==0x9 || ob==0x0) return strput(start, end, "the thing"); + if((ob->flags & O_DESTRUCTED) || + (!(ret = apply("the_short", ob, 0, ORIGIN_DRIVER))) + || (ret->type != T_STRING)) { + return strput(start, end, "the thing"); + } + return strput(start, end, ret->u.string); +} + +static char *strput_words (char * str, char * limit, int first, int last) { + char *p = words[first].start; + char *end = words[last].end; + int num; + + /* strip leading and trailing whitespace */ + while (uisspace(p[0])) + p++; + while (uisspace(end[0])) + end--; + + num = end - p + 1; + if (str + num >= limit) + num = limit - str - 1; + + memcpy(str, p, num); + str[num] = 0; + + return str + num; +} + +static void push_words (int first, int last) { + char *p = words[first].start; + char *end = words[last].end; + char *str; + + while (uisspace(p[0])) + p++; + while (uisspace(end[0])) + end--; + push_malloced_string(str = new_string(end - p + 1, "push_words")); + + while (p <= end) + *str++ = *p++; + *str = 0; +} + +static void free_parser_error (parser_error_t * p) { + if (p->error_type == ERR_ALLOCATED) { + FREE_MSTR(p->err.str); + } + p->error_type = 0; +} + +/* They actually used the word, so do the work of looking it up */ +static void expand_node (hash_entry_t * he) { + svalue_t *sv; + object_t *ob; + int i; + + he->flags &= ~HV_NICKNAME; + sv = find_string_in_mapping(parse_nicks, he->name); + if (sv->type != T_OBJECT) return; + ob = sv->u.ob; + if (ob->flags & O_DESTRUCTED) return; + if (ob->pinfo == 0) return; + + /* linear, but we only do this once per nickname they use */ + for (i = 0; i < num_objects; i++) { + if (loaded_objects[i] == ob) { + he->flags |= HV_NOUN; + bitvec_set(&he->pv.noun, i); + return; + } + } +} + +static void parse_obj (int tok, parse_state_t * state, + int ordinal) { + parse_state_t local_state; + bitvec_t objects, save_obs, err_obs; + int start = state->word_index; + char *str; + hash_entry_t *hnode, *last_adj = 0; + int multiple_adj = 0; + int ord_legal, singular_legal = 1, ord_seen = 0; + long tmp, tmp2; + match_t *mp = NULL; + + //if(!ordinal) ordinal = 1; + ord_legal = (ordinal == 0); + + DEBUG_INC; + DEBUG_P(("parse_obj:")); + + all_objects(&objects, parse_vn->handler->pinfo->flags & PI_REMOTE_LIVINGS); + + while (1) { + if (state->word_index == num_words) + return; + str = words[state->word_index++].string; + DEBUG_PP(("Word is %s", str)); + switch (check_special_word(str, &tmp)) { + case SW_ARTICLE: + continue; + case SW_ALL: + singular_legal = 0; + ord_seen = 1; + if (state->word_index < num_words && + check_special_word(words[state->word_index].string, &tmp) == SW_OF) { + state->word_index++; + continue; + } + local_state = *state; + if (tok & PLURAL_MODIFIER) { + local_state.num_objs++; + mp = add_match(&local_state, tok, + start, state->word_index - 1); + bitvec_copy(&mp->val.obs, &objects); + mp->ordinal = 0; + } else { + free_parser_error(¤t_error_info); + mp = add_match(&local_state, ERROR_TOKEN, + start, state->word_index - 1); + current_error_info.error_type = ERR_BAD_MULTIPLE; + } + parse_rule(&local_state); + break; + case SW_SELF: + { + if (me_object != -1) { + local_state = *state; + local_state.num_objs++; + mp = add_match(&local_state, tok, + start, state->word_index - 1); + bitvec_zero(&mp->val.obs); + bitvec_set(&mp->val.obs, me_object); + mp->ordinal = 0; + parse_rule(&local_state); + } + break; + } + case SW_ORDINAL: + if (ord_legal) { + if(!ordinal) ordinal = 1; + ord_seen = 1; + local_state = *state; + parse_obj(tok, &local_state, tmp); + } + break; + } + /* This is a hack; in the future we are going to have to handle + better. The problem is we don't want + to accept "red 1st sword" but we do want "my first sword" and + "my 1st red sword", and right now we don't distinguish between + ordinals and adjectives. Woops. */ + if (str != my_string) ord_legal = 0; + hnode = hash_table[DO_HASH(str, HASH_SIZE)]; + while (hnode) { + //if(!ordinal) ordinal = 1; + if (hnode->name == str) { + if (hnode->flags & HV_NICKNAME) + expand_node(hnode); + + if (singular_legal && (hnode->flags & HV_NOUN)) { + int explore_errors = !best_match && + state->num_errors < best_num_errors; + DEBUG_P(("Found noun: %s", str)); + local_state = *state; + bitvec_copy(&save_obs, &objects); + + /* Sigh, I want to throw exceptions */ + if (!intersect(&objects, &hnode->pv.noun)) { + if (!explore_errors) goto skip_it; + + free_parser_error(¤t_error_info); + current_error_info.error_type = ERR_IS_NOT; + current_error_info.err.noun = hnode; + goto we_have_an_error; + } + if (tok & LIV_MODIFIER) { + if (explore_errors) + bitvec_copy(&err_obs, &objects); + if (!intersect(&objects, &cur_livings)) { + if (!explore_errors) goto skip_it; + + free_parser_error(¤t_error_info); + current_error_info.error_type = ERR_NOT_LIVING; + current_error_info.err.noun = hnode; + goto we_have_an_error; + } + } + if (!(tok & VIS_ONLY_MODIFIER)) { + if (explore_errors) + bitvec_copy(&err_obs, &objects); + if (!intersect(&objects, &cur_accessible)) { + if (!explore_errors) goto skip_it; + + free_parser_error(¤t_error_info); + current_error_info.error_type = ERR_NOT_ACCESSIBLE; + current_error_info.err.noun = hnode; + goto we_have_an_error; + } + } + mp = add_match(&local_state, tok & ~PLURAL_MODIFIER, + start, state->word_index - 1); + bitvec_copy(&mp->val.obs, &objects); + if(ordinal != 0) mp->ordinal = ordinal; + else mp->ordinal = 1; + local_state.num_objs++; + goto do_the_parse; + + we_have_an_error: + mp = add_match(&local_state, ERROR_TOKEN, + start, state->word_index - 1); + + do_the_parse: + parse_rule(&local_state); + + skip_it: + bitvec_copy(&objects, &save_obs); + } + if ((ordinal == 0) && (hnode->flags & HV_PLURAL)) { + int explore_errors = !best_match && + state->num_errors < best_num_errors; + DEBUG_P(("Found plural: %s", str)); + local_state = *state; + bitvec_copy(&save_obs, &objects); + + if (!(tok & PLURAL_MODIFIER)) { + if (!explore_errors) goto p_skip_it; + + free_parser_error(¤t_error_info); + current_error_info.error_type = ERR_BAD_MULTIPLE; + goto p_we_have_an_error; + } + /* Sigh, I want to throw exceptions */ + if (!intersect(&objects, &hnode->pv.plural)) { + if (!explore_errors) goto p_skip_it; + + free_parser_error(¤t_error_info); + current_error_info.error_type = ERR_IS_NOT; + current_error_info.err.noun = hnode; + goto p_we_have_an_error; + } + if (tok & LIV_MODIFIER) { + if (explore_errors) + bitvec_copy(&err_obs, &objects); + if (!intersect(&objects, &cur_livings)) { + if (!explore_errors) goto p_skip_it; + + free_parser_error(¤t_error_info); + current_error_info.error_type = ERR_NOT_LIVING; + current_error_info.err.noun = hnode; + goto p_we_have_an_error; + } + } + if (!(tok & VIS_ONLY_MODIFIER)) { + if (explore_errors) + bitvec_copy(&err_obs, &objects); + if (!intersect(&objects, &cur_accessible)) { + if (!explore_errors) goto p_skip_it; + + free_parser_error(¤t_error_info); + current_error_info.error_type = ERR_NOT_ACCESSIBLE; + current_error_info.err.noun = hnode; + goto p_we_have_an_error; + } + } + mp = add_match(&local_state, tok, + start, state->word_index - 1); + bitvec_copy(&mp->val.obs, &objects); + mp->ordinal = ordinal; + local_state.num_objs++; + goto p_do_the_parse; + + p_we_have_an_error: + mp = add_match(&local_state, ERROR_TOKEN, + start, state->word_index - 1); + + p_do_the_parse: + parse_rule(&local_state); + + p_skip_it: + bitvec_copy(&objects, &save_obs); + } + else if(!ordinal && mp != NULL){ + check_special_word("first", &tmp2); + ordinal = 1; + mp->ordinal = tmp2; + } + if (hnode->flags & HV_ADJ) { + DEBUG_P(("Found adj: %s", str)); + intersect(&objects, &hnode->pv.adj); + if (last_adj) multiple_adj = 1; + last_adj = hnode; + } else { + DEBUG_DEC; + return; + } + break; + } + hnode = hnode->next; + } + if (!hnode) break; + } + DEBUG_PP(("exiting ...")); + DEBUG_DEC; +} + +static void make_error_message (int which, parser_error_t * err) { + char buf[1024]; + char *p; + char *end = EndOf(buf); + int cnt = 0; + int ocnt = 0; + int tok; + int index = 0; + + p = strput(buf, end, "You can't "); + p = strput(p, end, words[0].string); + *p++ = ' '; + while ((tok = parse_vn->token[index++])) { + switch (tok) { + case STR_TOKEN: + if (cnt == which - 1) { + p = strput(p, end, "that "); + cnt++; + break; + } + /* FALLTHRU */ + case WRD_TOKEN: + p = strput_words(p, end, matches[cnt].first, matches[cnt].last); + *p++ = ' '; + cnt++; + break; + default: + if (tok <= 0) { + p = strput(p, end, literals[-(tok + 1)]); + *p++ = ' '; + } else { + if (cnt == which - 1 || ++ocnt >= which + || (matches[cnt].token & PLURAL_MODIFIER)) { + p = strput(p, end, "that "); + } else { + /* FIXME */ + p = query_the_short(p, end, loaded_objects[matches[cnt].val.number]); + *p++ = ' '; + } + cnt++; + } + break; + } + } + p--; + p = strput(p, end, ".\n"); + DEBUG_P((buf)); + free_parser_error(err); + err->error_type = ERR_ALLOCATED; + err->err.str = string_copy(buf, "make_error_message"); +} + +/* 1 -> ok + * 0 -> no such func + * -1 -> returned error + * -2 -> generated error + * -3 -> abort + */ +static int process_answer (parse_state_t * state, svalue_t * sv, + int which) { + if (!sv) return 0; + if (sv->type == T_NUMBER) { + DEBUG_P(("Return value was: %i", sv->u.number)); + if (sv->u.number) + return 1; + if (state->num_errors == best_num_errors) { + DEBUG_P(("Have a better match; aborting ...")); + return -3; + } + if (state->num_errors++ == 0) + make_error_message(which, ¤t_error_info); + + return -2; + } + if (sv->type != T_STRING) { + DEBUG_P(("Return value was not a string or number.")); + return 0; + } + DEBUG_P(("Returned string was: %s", sv->u.string)); + if (state->num_errors == best_num_errors) { + DEBUG_P(("Have a better match; aborting ...")); + return -3; + } + if (state->num_errors++ == 0) { + free_parser_error(¤t_error_info); + current_error_info.error_type = ERR_ALLOCATED; + current_error_info.err.str = string_copy(sv->u.string, "process_answer"); + } + return -1; +} + +/* 1 - error or accepted + * 0 - no function + * -1 - generated or ridiculous error + */ +static int parallel_process_answer (parse_state_t * state, svalue_t * sv, + int which) { + if (!sv) return 0; + if (sv->type == T_NUMBER) { + DEBUG_P(("Return value was: %li", sv->u.number)); + if (sv->u.number) + return 1; + + if (state->num_errors == 0) + make_error_message(which, ¶llel_error_info); + return -1; + } + if (sv->type != T_STRING) { + DEBUG_P(("Return value was not a string or number.", sv->u.number)); + return 0; + } + DEBUG_P(("Returned string was: %s", sv->u.string)); + + free_parser_error(¶llel_error_info); + if (sv->u.string[0] == '#') { + parallel_error_info.error_type = ERR_ALLOCATED; + parallel_error_info.err.str = string_copy(sv->u.string + 1, "process_answer"); + return -1; + } else { + parallel_error_info.error_type = ERR_ALLOCATED; + parallel_error_info.err.str = string_copy(sv->u.string, "process_answer"); + return 1; + } +} + +static int push_real_names (int tryy, int which) { + int index = 0, match = 0; + int tok; + char tmp[1024]; + + if (tryy >= 2) { + char tmpbuf[1024]; + strput_words(tmpbuf, EndOf(tmpbuf), 0, 0); + copy_and_push_string(tmpbuf); + } + + while ((tok = parse_vn->token[index++])) { + if (tok > 0) { + strput_words(tmp, EndOf(tmp), matches[match].first, matches[match].last); + push_malloced_string(string_copy(tmp, "push_real_names")); + match++; + } + } + return match + (tryy >= 2); +} + +static char *rule_string (verb_node_t * vn) { + int index = 0; + int tok; + static char buf[1024]; + char *end = EndOf(buf); + char *p; + + p = buf; + + while (1) { + switch ((tok = vn->token[index++]) & ~CHOOSE_MODIFIER) { + case OBJ_A_TOKEN: + case OBJ_TOKEN: + p = strput(p, end, "OBJ "); + break; + case LIV_A_TOKEN: + case LIV_TOKEN: + p = strput(p, end, "LIV "); + break; + case OBS_TOKEN: + + case ADD_MOD(OBS_TOKEN, VIS_ONLY_MODIFIER): + p = strput(p, end, "OBS "); + break; + case LVS_TOKEN: + case ADD_MOD(LVS_TOKEN, VIS_ONLY_MODIFIER): + p = strput(p, end, "LVS "); + break; + case STR_TOKEN: + p = strput(p, end, "STR "); + break; + case WRD_TOKEN: + p = strput(p, end, "WRD "); + break; + case 0: + if (p == buf) { + *buf = 0; + } else { + *(p-1) = 0; /* nuke last space */ + } + return buf; + default: + p = strput(p, end, literals[-(tok + 1)]); + *p++ = ' '; + break; + } + } +} + +static void push_bitvec_as_array (bitvec_t * bv, int errors_too) { + int i, k, n = 0; + unsigned int j; + array_t *arr; + saved_error_t *se; + + if (errors_too) { + se = best_result->parallel; + while (se) { + n++; + se = se->next; + } + } + + for (i = 0; i < bv->last; i++) { + if (bv->b[i]) { + j = 1; + while (j) { + if (bv->b[i] & j) + n++; + j <<= 1; + } + } + } + arr = allocate_array(n); + /* error safety; right spot for return value too */ + push_refed_array(arr); + + if (errors_too) { + i = 0; + se = best_result->parallel; + while (se) { + svalue_t *ret = get_the_error(&se->err, se->obj); + + if (ret) + assign_svalue_no_free(&arr->item[i], ret); + + se = se->next; + i++; + } + } + + for (i = 0; i < bv->last; i++) { + if (bv->b[i]) { + j = 1; + k = 0; + while (j) { + if (bv->b[i] & j) { + object_t *ob = loaded_objects[BPI * i + k]; + n--; + if (ob->flags & O_DESTRUCTED) { + arr->item[n] = const0u; + } else { + arr->item[n].type = T_OBJECT; + arr->item[n].u.ob = ob; + add_ref(ob, "push_bitvec_as_array"); + } + } + j <<= 1; + k++; + } + } + } +} + +/* Belgarat: this function has been extended to handle + * two more parser apply calls. direct_ and indirect_ applies are + * called sometimes more than once + */ +static char *prefixes[] = { "can_", "direct_", "indirect_", "do_", + /* Belgarat: names for the second pass with filled object arguments */ + "direct_", "indirect_" }; + +static int make_function (char * buf, char * end, int which, + parse_state_t * state, int tryy, + object_t * target) { + int index = 0, match = 0, omatch = 0; + int on_stack = 0; + int tok; + + /* try = 0: "read_about_str_from_obj" + * try = 1: "read_word_str_word_obj" + * try = 2: "verb_word_str_word_obj" + * try = 3: "verb_rule" + */ + + buf = strput(buf, end, prefixes[which]); + if (tryy < 2) { + buf = strput(buf, end, parse_verb_entry->match_name); + } else { + buf = strput(buf, end, "verb"); + push_shared_string(parse_verb_entry->match_name); + on_stack++; + } + + if (tryy == 3) { + buf = strput(buf, end, "_rule"); + /* leave the 0; this effectively truncates the string. */ + buf++; + share_and_push_string(rule_string(parse_vn)); + on_stack++; + } + while ((tok = parse_vn->token[index++])) { + *buf++ = '_'; + switch (tok & ~CHOOSE_MODIFIER) { + case OBJ_TOKEN: + case OBJ_A_TOKEN: + buf = strput(buf, end, "obj"); + goto put_obj_value; + + case OBS_TOKEN: + case ADD_MOD(OBS_TOKEN, VIS_ONLY_MODIFIER): + if (omatch + 1 >= which || + !(matches[match].token & PLURAL_MODIFIER) || (which >= 4)) + buf = strput(buf, end, "obj"); + else + buf = strput(buf, end, "obs"); + goto put_obj_value; + + case LVS_TOKEN: + case ADD_MOD(LVS_TOKEN, VIS_ONLY_MODIFIER): + if (omatch +1 >= which || + !(matches[match].token & PLURAL_MODIFIER) || (which >= 4)) + buf = strput(buf, end, "liv"); + else + buf = strput(buf, end, "lvs"); + goto put_obj_value; + + case LIV_TOKEN: + case LIV_A_TOKEN: + buf = strput(buf, end, "liv"); + + put_obj_value: + omatch++; + /* Belgarat: this part was rewritten; behaviour for `which <= 4' was + * retained and two more calls were added. There seemed to be some kind + * of bug in the original code, but I'm not quite sure. + */ + if (which >= 4) { + if (omatch == 1) { + push_object(loaded_objects[direct_object >= 0 ? direct_object : 0]); + } else { + push_object(loaded_objects[indirect_object >= 0 ? indirect_object : 0]); + } + } else if (omatch == which) { + push_object(target); + } else if (omatch > which) { + push_number(0); + } else if (matches[match].token == ERROR_TOKEN) { + push_number(0); + } else if (matches[match].token & PLURAL_MODIFIER) { + push_bitvec_as_array(&matches[match].val.obs, which == 3); + } else if (matches[match].val.number < 0) { + push_number(0); + } else if (loaded_objects[matches[match].val.number] == NULL || + loaded_objects[matches[match].val.number] == 0x0 || + loaded_objects[matches[match].val.number] == 0x9 || + loaded_objects[matches[match].val.number]->flags & O_DESTRUCTED) { + push_number(0); + } else + push_object(loaded_objects[matches[match].val.number]); + match++; + on_stack++; + break; + case STR_TOKEN: + { + char tmp[1024]; + buf = strput(buf, end, "str"); + strput_words(tmp, EndOf(tmp), matches[match].first, matches[match].last); + push_malloced_string(string_copy(tmp, "push_real_names")); + match++; + on_stack++; + } + break; + case WRD_TOKEN: + { + char tmp[1024]; + buf = strput(buf, end, "wrd"); + strput_words(tmp, end, matches[match].first, matches[match].last); + push_malloced_string(string_copy(tmp, "push_real_names")); + match++; + on_stack++; + } + break; + default: + if (!tryy) { + buf = strput(buf, end, literals[-(tok + 1)]); + } else if (tryy < 3) { + buf = strput(buf, end, "word"); + push_shared_string(literals[-(tok + 1)]); + on_stack++; + } + } + } + return on_stack; +} + +#define SET_OB(x) if ((ob = (x))->flags & O_DESTRUCTED) return 0; + +static int check_functions (object_t * obj, parse_state_t * state) { + object_t *ob; + char func[CHAR_FUNC]; + int tryy, ret, args; + + SET_OB(obj); + for (tryy = 0, ret = 0; !ret && tryy < 8; tryy++) { + if (tryy == 4) + SET_OB(parse_vn->handler); + args = make_function(func, EndOf(func), 0, state, tryy % 4, obj); + args += push_real_names(tryy % 4, 0); + DEBUG_P(("Trying %s ... (/%s)", func, ob->obname)); + ret = process_answer(state, apply(func, ob, args, ORIGIN_DRIVER), 0); + if (ob->flags & O_DESTRUCTED) + return 0; + if (ret == -3) + return 0; + } + if (!ret) { + if (state->num_errors == best_num_errors) { + DEBUG_P(("Nothing matched and we have a better match")); + DEBUG_DEC; + return 0; + } + if (state->num_errors++ == 0) + make_error_message(0, ¤t_error_info); + } + return 1; +} + +static void clear_parallel_errors (saved_error_t ** par) { + saved_error_t *se, *next; + + for (se = *par; se; se = next) { + next = se->next; + free_parser_error(&se->err); + FREE(se); + } + *par = 0; +} + +static int use_last_parallel_error (parse_state_t * state) { + if (!parallel_error_info.error_type) + return 0; + if (state->num_errors++ == 0) { + free_parser_error(¤t_error_info); + current_error_info = parallel_error_info; + parallel_error_info.error_type = 0; + } + return 1; +} + +static int save_last_parallel_error (int ob) { + saved_error_t *n; + + if (!parallel_error_info.error_type) + return 0; + n = ALLOCATE(saved_error_t, TAG_PARSER, "save_last_parallel_error"); + n->next = parallel_errors; + n->obj = ob; + n->err = parallel_error_info; + parallel_errors = n; + parallel_error_info.error_type = 0; + return 1; +} + +static int parallel_check_functions (object_t * obj, + parse_state_t * state, + int which) { + object_t *ob; + char func[CHAR_FUNC]; + int tryy, ret, args; + + free_parser_error(¶llel_error_info); + if(obj && obj != 0x9){ + SET_OB(obj); + for (tryy = 0, ret = 0; !ret && tryy < 8; tryy++) { + if (tryy == 4) + SET_OB(parse_vn->handler); + args = make_function(func, EndOf(func), which, state, tryy % 4, obj); + args += push_real_names(tryy % 4, which); + DEBUG_P(("Trying %s ... (/%s)", func, ob->obname)); + ret = parallel_process_answer(state, apply(func, ob, args, ORIGIN_DRIVER), which); + if (ob->flags & O_DESTRUCTED) + return 0; + } + } + if (!ret) { + if (state->num_errors == 0) + make_error_message(0, ¶llel_error_info); + return 0; + } + return ret == 1; +} + +static void singular_check_functions (int which, parse_state_t * state, + match_t * m) { + bitvec_t *bv = &m->val.obs; + int i, k, ambig = 0, match = -1; + unsigned int j; + int ordinal = m->ordinal; + int ord2 = m->ordinal; + int has_ordinal = (m->ordinal != 0); + int was_error = 0; + + for (i = 0; i < bv->last; i++) { + if (bv->b[i]) { + j = 1; + k = 0; + while (j) { + if (bv->b[i] & j) { + int ret = parallel_check_functions(loaded_objects[BPI * i + k], state, which); + if (ret) { + if (has_ordinal) { + ord2--; + if (ordinal < 0 || --ordinal == 0) { + if (ordinal == -2) + state->num_errors--; + if (use_last_parallel_error(state)) { + m->token = ERROR_TOKEN; + if (ordinal != -1) + return; + ordinal = -2; + } else { + m->val.number = BPI * i + k; + if(m->val.number > MAX_NUM_OBJECTS) abort(); + return; + } + } + } else { + if (!ambig++) { + if (use_last_parallel_error(state)) { + was_error = 1; + m->token = ERROR_TOKEN; + } else { + was_error = 0; + match = BPI * i + k; + } + if (m->token & CHOOSE_MODIFIER) { + if (match >= 0) + { + m->val.number = match; + if(m->val.number > MAX_NUM_OBJECTS) abort(); + } + return; + } + } else { + match = -1; + } + } + } else { + if (has_ordinal && (ordinal == -1 || --ord2 == 0)) { + free_parser_error(&second_parallel_error_info); + second_parallel_error_info = parallel_error_info; + parallel_error_info.error_type = 0; + } + /* not a valid object */ + bv->b[i] &= ~j; + } + } + j <<= 1; + k++; + } + } + } + if (!has_ordinal) { + if (ambig == 1) { + m->val.number = match; + if(m->val.number > MAX_NUM_OBJECTS) abort(); + return; + } + if (was_error) + state->num_errors--; + + m->token = ERROR_TOKEN; + if (ambig == 0 && use_last_parallel_error(state)) + return; + if (state->num_errors++ == 0) { + free_parser_error(¤t_error_info); + + current_error_info.error_type = ERR_AMBIG; + bitvec_copy(¤t_error_info.err.obs, &m->val.obs); + return; + } + } else { + if (ordinal == -2) return; + + m->token = ERROR_TOKEN; + if (state->num_errors++ == 0) { + free_parser_error(¤t_error_info); + if (ord2 <= 0) { + current_error_info = second_parallel_error_info; + second_parallel_error_info.error_type = 0; + } else { + /* Didn't find enough; signal an ordinal error */ + current_error_info.error_type = ERR_ORDINAL; + current_error_info.err.ord_error = bitvec_count(bv); + } + } + } + return; +} + +static void plural_check_functions (int which, parse_state_t * state, + match_t * m) { + bitvec_t *bv = &m->val.obs; + int i, k; + unsigned int j; + int found_one = 0; + + for (i = 0; i < bv->last; i++) { + if (bv->b[i]) { + j = 1; + k = 0; + while (j) { + if (bv->b[i] & j) { + int ret = parallel_check_functions(loaded_objects[BPI * i + k], state, which); + if (!ret || save_last_parallel_error(BPI * i + k)) + bv->b[i] &= ~j; + else + found_one = 1; + } + j <<= 1; + k++; + } + } + } + if (!found_one && use_last_parallel_error(state)) + m->token = ERROR_TOKEN; +} + +/* Belgarat: The next functions are used for tests and error + * reporting in the second pass of parsing when all parameters are exactly + * filled (including the object ones) + */ +static int cache_last_parallel_error(parser_error_t *storage) { + if (!parallel_error_info.error_type) + return 0; + free_parser_error(storage); + *storage = parallel_error_info; + parallel_error_info.error_type = 0; + return 1; +} + +static int use_cached_parallel_error (parse_state_t * state, + parser_error_t* err) { + if (!err->error_type) + return 0; + if (state->num_errors++ == 0) { + free_parser_error(¤t_error_info); + current_error_info = *err; + err->error_type = 0; + } + return 1; +} + +static void dependent_check_functions (int which, parse_state_t * state, + match_t * m) { + bitvec_t *bv = &m->val.obs; + int i, k; + unsigned int j; + int found_one = 0; + parser_error_t errinfo; + + errinfo.error_type = 0; + for (i = 0; i < bv->last; i++) { + if (bv->b[i]) { + j = 1; + k = 0; + while (j) { + if (bv->b[i] & j) { + int ret = parallel_check_functions(loaded_objects[BPI * i + k], state, which); + if (!ret || cache_last_parallel_error(&errinfo)) + bv->b[i] &= ~j; + else { + if (!found_one) + { + m->val.number = BPI * i + k; + if(m->val.number > MAX_NUM_OBJECTS) abort(); + } + found_one = 1; + } + } + j <<= 1; + k++; + } + } + } + if (!found_one && ( + use_cached_parallel_error(state, &errinfo) || + use_last_parallel_error(state)) ) { + m->token = ERROR_TOKEN; + } + /* Translate me! + * Nepotrebuji, aby se mi v pameti flakaly errorove hlasky, ktere + * se ani nepouziji. + */ + free_parser_error(&errinfo); +} + +#define CHECK_DIRECT_OK 1 +#define CHECK_INDIRECT_OK 2 +#define CHECK_ERROR_RELATION 4 +#define CHECK_RELATION_COMPLETE 8 + +/* Translate me! + * Z funkce vypadne DIRECT_OK, kdyz je kombinace schvalena directem, + * INDIRECT_OK, kdyz je kombinace schvalena indirectem + * a ERROR_RELATION kdyz dojde k nejake (libovolne) chybe + * Jinymi slovy, je li zaroven DIRECT_OK a INDIRECT_OK, + * je to platna kombinace a ERROR_RELATION urcuje, zda doslo k chybe + * Jestlize jedno z DIRECT a INDIRECT schazi, je vztah neuplny + * a nebude zaznamenan + */ + +/* Belgarat: + * This function checks if two object can be used together in two-object rule. + * The function returns DIRECT_OK, when only direct object agrees to the action, + * IDIRECT_OK if only indirect object agrees or combination of both, if both + * objects agree (in this case flag CHECK_RELATION_COMPLETE is set as well). + * If it returns ERROR_RELATION, there's some error (that should be saved for + * further processing). + */ +static int check_one_relation(parse_state_t * state, int direct_first, + parser_error_t *errinfo) +{ + int res; + int ob; + parser_error_t err; + + res = 0; + err.error_type = 0; + ob = direct_first ? direct_object : indirect_object; + res = parallel_check_functions( + loaded_objects[direct_first ? direct_object : indirect_object], state, + direct_first ? 4 : 5); + if (!res) { + /* The object doesn't exist, returned 0 or "#error". This object + * can not be used for the rule. + */ + return CHECK_ERROR_RELATION; + } + res |= direct_first ? CHECK_DIRECT_OK : CHECK_INDIRECT_OK; + if (cache_last_parallel_error(&err)) { + /* The object could be used in general, but not at this time. + * mark the rule with error flag so it won't be used for action, + * but continue the processing. + * If both objects returns "error message", then the objects are + * valid for the rule, but they cannot be used right now. + */ + res |= CHECK_ERROR_RELATION; + } + /* checking the other object in the pair */ + res = parallel_check_functions( + loaded_objects[direct_first ? indirect_object: direct_object], state, + direct_first ? 5 : 4); + if (!res) { + /* the same as above, but for the other object */ + if (err.error_type) { + *errinfo = err; + } + return res | CHECK_ERROR_RELATION; + } + res |= direct_first ? CHECK_INDIRECT_OK : CHECK_DIRECT_OK; + /* don't cache the new error if the previous check returned eror too */ + if (!err.error_type && cache_last_parallel_error(&err)) { + /* The same as above - the object can be used for the action, + * but not right now. Mark the pair as error and keep the error + * cached + */ + res |= CHECK_ERROR_RELATION; + } + /* mark the relation as complete. The relation is complete even if some + * error has occured. In general the relation is complete when both objects + * can operate together, but not now (they returned string error + * description without # as the first character) + */ + res |= CHECK_RELATION_COMPLETE; + if (err.error_type) + *errinfo = err; + return res; +} + +/* Belgarat: + * This function checks if the objects in two-object rule can really + * operate together. It checks each object that matched the first OBJ token + * with each object that matched the second OBJ. + */ +static void check_object_relations (parse_state_t * state) { + int i, direct = -1, indirect = -1; + int use_indirect; + bitvec_t *dir_objs, *indir_objs; + int j, k, l, m, n, ret; + int found_direct = -1, found_indirect = -1; + int direct_unique, indirect_unique; + int found_something; + int direct_ordinal, finished = 0; + bitvec_t indirects, directs; + parser_error_t err; + + bitvec_zero(&directs); + bitvec_zero(&indirects); + err.error_type = 0; + for (i = 0; i < state->num_matches; i++) { + if (matches[i].token & OBJ_A_TOKEN) { + if (direct < 0) direct = i; else indirect = i; + } else if (matches[i].token == ERROR_TOKEN) return; + } + if (matches[indirect].ordinal) { + /* if the indirect object is used with ordinal number, choose only + * that single indirect object. Imagine how it would be confusing if + * you enter "get apple from the second cask" and the REAL second + * cask would be skipped, because there is no apple there... without + * error message. + */ + int ord; + bitvec_t *bv = &matches[indirect].val.obs; + + ord = matches[indirect].ordinal; + if (ord > 0) i = 0; + for (; i < bv->last; i++) { + if (bv->b[i]) { + j = 1, k = 0; + while(j) { + if (bv->b[i] & j) { + /* found some object, decrement counter */ + if (!--ord) { + bitvec_zero(bv); + bitvec_set(bv, use_indirect = BPI * i + k); + break; + } + } + j <<= 1, k++; + } + } + } + if (ord) { + /* there's less indirect objs than specified --> error */ + matches[indirect].token = ERROR_TOKEN; + if (state->num_errors++ == 0) { + free_parser_error(¤t_error_info); + current_error_info.error_type = ERR_ORDINAL; + current_error_info.err.ord_error = bitvec_count(bv) + 1; + } + return; + } + } else { + /* check if there's no SO much possibilities. if so, error out. */ + int direct_count = bitvec_count(&directs); + int indirect_count = bitvec_count(&indirects); + /* if you want to increase performance, reduce the number in the if + * below. if it will be at least 20, the players should not complain + * too much + */ + if (direct_count * indirect_count >= 80) { + state->num_errors++; + free_parser_error(¤t_error_info); + current_error_info.error_type = ERR_MANY_PATHS; + return; + } + } + dir_objs = &matches[direct].val.obs; + indir_objs = &matches[indirect].val.obs; + + direct_unique = !(matches[direct].token & PLURAL_MODIFIER); + indirect_unique = !(matches[indirect].token & PLURAL_MODIFIER); + + if (!(direct_ordinal = matches[direct].ordinal)) direct_ordinal = -1; + + for (i = 0; !finished && i < dir_objs->last; i++) if (dir_objs->b[i]) { + for(j = 1, k = 0; j ; j <<=1, k++) if (dir_objs->b[i] & j) { + /* found direct object. + * I have to test it against either use_indirect or against + * all indirect objects I have. + */ + direct_object = BPI * i + k; + found_something = 0; + for (l = 0; l < indir_objs->last; l++) if (indir_objs->b[l]) { + for (m = 1, n = 0; m ; m <<= 1, n++) if (indir_objs->b[l] & m) { + /* found direct/indirect object combination. + * test if that can succeed. + * if yes, remember that indirect obj. + */ + indirect_object = BPI * l + n; + /* indirect unique --> check indirect_ first. */ + ret = check_one_relation(state, indirect_unique, &err); + + /* If it is not complete relation, I can do nothing + * because both the direct and indirect objects have to agree + * on the relation. + */ + if (!(ret & CHECK_RELATION_COMPLETE)) continue; + + /* from now on, direct and indirect object are OK */ + if (indirect_unique && found_indirect >= 0) { + if (found_indirect != indirect_object) { + matches[indirect].token = ERROR_TOKEN; + if (state->num_errors++ == 0) { + free_parser_error(¤t_error_info); + + current_error_info.error_type = ERR_AMBIG; + bitvec_copy(¤t_error_info.err.obs, + &matches[indirect].val.obs); + } + free_parser_error(&err); + return; + } + } + if (direct_ordinal > 0) direct_ordinal--; + + if (direct_ordinal <= 0 && direct_unique && found_direct >= 0) { + if (found_direct != direct_object) { + matches[indirect].token = ERROR_TOKEN; + if (state->num_errors++ == 0) { + free_parser_error(¤t_error_info); + + current_error_info.error_type = ERR_AMBIG; + bitvec_copy(¤t_error_info.err.obs, + &matches[direct].val.obs); + } + free_parser_error(&err); + return; + } + } + /* If there's no error, mark direct and indirect object + * in the tables. Note that insufficient directs that have + * been found result in no error, so indirect object is + * marked in case there's some ambiguity + */ + if (!(ret & CHECK_ERROR_RELATION)) { + if (direct_ordinal <= 0) { + bitvec_set(&directs, direct_object); + } + bitvec_set(&indirects, indirect_object); + } + /* regardles of error state mark found direct/indirect pair + * for possible future ambiguity checks + */ + if (direct_ordinal <= 0) + found_direct = direct_object; + found_indirect = indirect_object; + } + } + /* end of processing of direct object */ + if (found_direct && (!direct_ordinal || + (direct_unique && (matches[direct].token & CHOOSE_MODIFIER)))) { + finished = 1; + break; + } + } + } + /* all searched, now evaluate the results. */ + bitvec_copy(dir_objs, &directs); + bitvec_copy(indir_objs, &indirects); + if (direct_unique) matches[direct].val.number = found_direct; + else matches[direct].val.number = 0; + if (indirect_unique) matches[indirect].val.number = found_indirect; + else matches[indirect].val.number = 0; + + if(matches[indirect].val.number > MAX_NUM_OBJECTS) abort(); + + if (found_direct < 0) { + if (use_cached_parallel_error(state, &err) || + use_last_parallel_error(state)) + matches[direct].token = ERROR_TOKEN; + } else if (found_indirect < 0) { + if (use_cached_parallel_error(state, &err) || + use_last_parallel_error(state)) + matches[indirect].token = ERROR_TOKEN; + } + free_parser_error(&err); +} + +static void we_are_finished (parse_state_t * state) { + char func[CHAR_FUNC]; + char *p; + int which, mtch; + int tryy, args; + + DEBUG_INC; + DEBUG_P(("we_are_finished")); + + if (found_level < 2) found_level = 2; + + /* ignore it if we already have somethign better */ + if (best_match >= parse_vn->weight) { + DEBUG_P(("Have a better match; aborting ...")); + DEBUG_DEC; + return; + } + if (state->num_errors) { + if (state->num_errors > best_num_errors) { + DEBUG_DEC; + return; + } + if (state->num_errors == best_num_errors + && parse_vn->weight < best_error_match) { + DEBUG_DEC; + return; + } + } + + if (!check_functions(parse_user, state)) { + DEBUG_DEC; + return; + } + + clear_parallel_errors(¶llel_errors); + which = 1; + for (which = 1, mtch = 0; which < 3 && mtch < state->num_matches; mtch++) { + int tok = matches[mtch].token; + + if (tok == ERROR_TOKEN) { + which++; /* Is this right if the ERROR_TOKEN + was actually a string? */ + continue; + } + if (!(tok & OBJ_A_TOKEN)) + continue; + + if (tok & PLURAL_MODIFIER) + plural_check_functions(which, state, &matches[mtch]); + else if (state->num_objs == 2) + dependent_check_functions(which, state, &matches[mtch]); + else + singular_check_functions(which, state, &matches[mtch]); + which++; + } + + if (state->num_objs == 2 && !state->num_errors) { + check_object_relations(state); + } + if (state->num_errors) { + int weight; + if(parse_vn) weight = parse_vn->weight; + + if (current_error_info.error_type == ERR_THERE_IS_NO) { + /* ERR_THERE_IS_NO is basically a STR in place of an OBJ, + * so is weighted far too highly. Give it approximately + * the same weight as a STR. + */ + weight = 1; + } + + if (state->num_errors == best_num_errors && + weight <= best_error_match) { + DEBUG_P(("Have better match; aborting ...")); + DEBUG_DEC; + return; + } + free_parser_error(&best_error_info); + best_error_info = current_error_info; + current_error_info.error_type = 0; + best_num_errors = state->num_errors; + best_error_match = weight; + } else { + best_match = parse_vn->weight; + if (best_result) free_parse_result(best_result); + best_result = ALLOCATE(parse_result_t, TAG_PARSER, "we_are_finished"); + clear_result(best_result); + if (parse_vn->handler->flags & O_DESTRUCTED) { + DEBUG_DEC; + return; + } + best_result->ob = parse_vn->handler; + best_result->parallel = parallel_errors; + parallel_errors = 0; + add_ref(parse_vn->handler, "best_result"); + for (tryy = 0; tryy < 4; tryy++) { + args = make_function(func, EndOf(func), 3, state, tryy, 0); + args += push_real_names(tryy, 3); + best_result->res[tryy].func = string_copy(func, "best_result"); + best_result->res[tryy].num = args; + if (args) { + p = (char *)(best_result->res[tryy].args = CALLOCATE(args, + svalue_t, TAG_PARSER, "best_result")); + memcpy(p, (char *)(sp - args + 1), args * sizeof(svalue_t)); + sp -= args; + } + } + DEBUG_P(("Saving successful match: %s (%s)", best_result->res[0].func, + best_result->ob->obname)); + } + DEBUG_DEC; +} + +static void do_the_call (void) { + int i, n; + object_t *ob; + if(best_result) ob = best_result->ob; + else return; + + for (i = 0; i < 4; i++) { + if (ob->flags & O_DESTRUCTED) return; + n = best_result->res[i].num; + if (n) { + CHECK_STACK_OVERFLOW(n); + memcpy((char *)(sp + 1), best_result->res[i].args, n*sizeof(svalue_t)); + /* + * Make sure we haven't dumped any dested obs onto the stack; + * this also updates sp. + */ + while (n--) { + if ((++sp)->type == T_OBJECT && (sp->u.ob->flags & O_DESTRUCTED)) { + free_object(&sp->u.ob, "do_the_call"); + *sp = const0u; + } + } + FREE(best_result->res[i].args); + } + best_result->res[i].args = 0; + DEBUG_P(("Calling %s ...", best_result->res[i].func)); + if (apply(best_result->res[i].func, ob, + best_result->res[i].num, ORIGIN_DRIVER)) return; + } + error("Parse accepted, but no do_* function found in object /%s!\n", + ob->obname); +} + +static void parse_rule (parse_state_t * state) { + int tok; + parse_state_t local_state; + match_t *mp; + int start; + + DEBUG_INC; + DEBUG_P(("parse_rule")); + while (parse_vn) { + tok = parse_vn->token[state->tok_index++]; + if (state->word_index == num_words && tok) { + DEBUG_P(("Ran out of words to parse.")); + DEBUG_DEC; + return; + } + switch (tok & ~CHOOSE_MODIFIER) { + case 0: + if (state->word_index == num_words) + we_are_finished(state); + DEBUG_P(("exiting parse_rule ...")); + DEBUG_DEC; + return; + case OBJ_TOKEN: + case LIV_TOKEN: + case OBJ_A_TOKEN: + case LIV_A_TOKEN: + case OBS_TOKEN: + case ADD_MOD(OBS_TOKEN, VIS_ONLY_MODIFIER): + case LVS_TOKEN: + case ADD_MOD(LVS_TOKEN, VIS_ONLY_MODIFIER): + local_state = *state; + parse_obj(tok, &local_state, 0); + if (!best_match && !best_error_match) { + start = state->word_index++; + while (state->word_index <= num_words) { + local_state = *state; + free_parser_error(¤t_error_info); + mp = add_match(&local_state, ERROR_TOKEN, + start, state->word_index - 1); + current_error_info.error_type = ERR_THERE_IS_NO; + current_error_info.err.str_problem.start = start; + current_error_info.err.str_problem.end = state->word_index - 1; + parse_rule(&local_state); + state->word_index++; + } + } + DEBUG_P(("Done trying to match OBJ")); + DEBUG_DEC; + return; + case STR_TOKEN: + if (!parse_vn->token[state->tok_index]) { + /* At end; match must be the whole thing */ + start = state->word_index; + state->word_index = num_words; + add_match(state, STR_TOKEN, start, num_words - 1); + DEBUG_P(("Taking rest of sentence as STR")); + parse_rule(state); + } else { + start = state->word_index++; + while (state->word_index <= num_words) { + local_state = *state; + add_match(&local_state, STR_TOKEN, + start, state->word_index - 1); + DEBUG_P(("Trying potential STR match")); + parse_rule(&local_state); + state->word_index++; + } + } + DEBUG_P(("Done trying to match STR")); + DEBUG_DEC; + return; + case WRD_TOKEN: + add_match(state, WRD_TOKEN, state->word_index, state->word_index); + state->word_index++; + DEBUG_P(("Trying WRD match")); + parse_rule(state); + DEBUG_DEC; + return; + default: + if (literals[-(tok + 1)] == words[state->word_index].string) { + state->word_index++; + DEBUG_P(("Matched literal: %s", literals[-(tok + 1)])); + } else { + if (state->tok_index == 1) { + DEBUG_DEC; + return; + } + + DEBUG_P(("last match to error ...")); + switch (parse_vn->token[state->tok_index - 2]) { + case STR_TOKEN: + DEBUG_P(("Nope. STR rule last.")); + DEBUG_DEC; + return; + case OBJ_TOKEN: + case LIV_TOKEN: + case OBJ_A_TOKEN: + case LIV_A_TOKEN: + case OBS_TOKEN: + case ADD_MOD(OBS_TOKEN, VIS_ONLY_MODIFIER): + case LVS_TOKEN: + case ADD_MOD(LVS_TOKEN, VIS_ONLY_MODIFIER): + { + match_t *last; + + while (literals[-(tok + 1)] != words[state->word_index++].string) { + if (state->word_index == num_words) { + DEBUG_P(("Literal not found in forward search")); + DEBUG_DEC; + return; + } + } + last = &matches[state->num_matches-1]; + DEBUG_P(("Changing last match.")); + last->token = ERROR_TOKEN; + last->last = state->word_index-1; + if (state->num_errors++ == 0) { + free_parser_error(¤t_error_info); + current_error_info.error_type = ERR_THERE_IS_NO; + current_error_info.err.str_problem.start = last->first; + current_error_info.err.str_problem.end = state->word_index - 1; + } + } + break; + default: + DEBUG_P(("default case")); + DEBUG_DEC; + return; + } + } + } + } + DEBUG_DEC; +} + +static int check_literal (int lit, int start) { + DEBUG_PP(("check_literal: %s", literals[lit])); + + while (start < num_words) { + if (literals[lit] == words[start++].string) { + DEBUG_PP(("yes")); + return start; + } + } + DEBUG_PP(("no")); + return 0; +} + +static void parse_rules (void) { + int pos; + parse_state_t local_state; + + parse_vn = parse_verb_entry->node; + while (parse_vn) { + DEBUG_PP(("Rule: %s", rule_string(parse_vn))); + if ((!parse_restricted || parse_vn->handler == parse_restricted) + && (best_match <= parse_vn->weight)) { + pos = 0; + if ((parse_vn->lit[0] == -1 || + (pos = check_literal(parse_vn->lit[0], 1))) + && (parse_vn->lit[1] == -1 || + check_literal(parse_vn->lit[1], pos))) { + DEBUG_P(("Trying rule: %s", rule_string(parse_vn))); + + local_state.tok_index = 0; + local_state.word_index = 1; + local_state.num_matches = 0; + local_state.num_errors = 0; + local_state.num_objs = 0; + parse_rule(&local_state); + } + } + if(parse_vn) parse_vn = parse_vn->next; + } +} + +static void reset_error (void) { + best_match = 0; + best_error_match = 0; + best_num_errors = 5732; /* Yes. Exactly 5,732 errors. Don't ask. */ + free_parser_error(¤t_error_info); + free_parser_error(&best_error_info); +} + +static void parse_recurse (char ** iwords, char ** ostart, char ** oend) { + char buf[1024]; + char *p, *q; + char **iwp = iwords; + int first = 1; + int l, idx; + + if (*iwords[0]) { + *buf = 0; + p = buf; + do { + l = iwp[1] - iwp[0] - 1; + strcpy(p, *iwp++); + p += l; + if ((q = findstring(buf))) { + words[num_words].type = 0; + words[num_words].start = ostart[0]; + words[num_words].end = oend[iwp - iwords - 1]; + words[num_words++].string = q; + idx = iwp - iwords; + parse_recurse(iwp, ostart + idx, oend + idx); + num_words--; + } else if (first) { + l = p - buf; + words[num_words].type = WORD_ALLOCATED; + words[num_words].string = new_string(l, "parse_recurse"); + words[num_words].start = ostart[0]; + words[num_words].end = oend[iwp - iwords - 1]; + memcpy(words[num_words].string, buf, l); + words[num_words++].string[l] = 0; + idx = iwp - iwords; + parse_recurse(iwp, ostart + idx, oend + idx); + num_words--; + FREE_MSTR(words[num_words].string); + } + first = 0; + *p++ = ' '; + } while (*iwp[0]); + } else { +#if defined(DEBUG) || defined(PARSE_DEBUG) + if (debug_parse_depth) { + char dbuf[1024]; + char *end = EndOf(dbuf); + int i; + char *p; + p = strput(dbuf, end, "Trying interpretation: "); + for (i = 0; i < num_words; i++) { + p = strput(p, end, words[i].string); + p = strput(p, end, ":"); + } + DEBUG_P((dbuf)); + } +#endif + parse_rules(); + } +} + +static void parse_sentence (const char * input) { + unsigned char *starts[MAX_WORDS_PER_LINE]; + unsigned char *orig_starts[MAX_WORDS_PER_LINE]; + unsigned char *orig_ends[MAX_WORDS_PER_LINE]; + unsigned char buf[MAX_WORD_LENGTH], *p, *start; + unsigned char c, *inp; + unsigned char *end = EndOf(buf) - 1; /* space for zero */ + int n = 0; + int i; + int flag; + + reset_error(); + free_words(); + p = start = buf; + flag = 0; + inp = (unsigned char *)input; + while (*inp && (uisspace(*inp) || isignore(*inp))) + inp++; + orig_starts[0] = inp; + + while ((c = *inp++)) { + if (isignore(c)) continue; + if (uisupper(c)) + c = tolower(c); + if (iskeep(c) && p < end) { + if (!flag) + flag = 1; + *p++ = c; + if (p == end) break; /* truncate */ + } else { + /* whitespace or punctuation */ + if (!uisspace(c)) + while (*inp && !iskeep(*inp) && !uisspace(*inp)) + inp++; + else + inp--; + + if (flag) { + flag = 0; + *p++ = 0; + orig_ends[n] = inp - 1; /* points to where c was */ + starts[n++] = start; + if (n == MAX_WORDS_PER_LINE) + return; /* too many words */ + start = p; + while (*inp && uisspace(*inp)) + inp++; + orig_starts[n] = inp; + if (p == end) + break; /* truncate */ + } else { + while (*inp && uisspace(*inp)) + inp++; + } + } + } + if (flag) { + *p++ = 0; + orig_ends[n] = inp - 2; + starts[n++] = start; + if (n == MAX_WORDS_PER_LINE) + return; /* too many words */ + } else { + if (n) + orig_ends[n - 1] = inp - 2; + else + orig_ends[0] = inp - 2; + } + if (p > end) { + starts[n] = end; + } else { + starts[n] = p; + *p = 0; + } + + /* find an interpretation, first word must be shared (verb) */ + for (i = 1; i <= n; i++) { + unsigned char *vb = (unsigned char *)findstring((char *)buf); + verb_t *ve; + + if (vb) { + ve = verbs[DO_HASH(vb, VERB_HASH_SIZE)]; + while (ve) { + if (ve->real_name == (char *)vb) { + if (ve->flags & VB_IS_SYN) + parse_verb_entry = ((verb_syn_t *)ve)->real; + else + parse_verb_entry = ve; + + words[0].string = (char *)vb; + words[0].type = 0; + + if (found_level < 1) found_level = 1; + if (!objects_loaded && + (parse_verb_entry->flags & VB_HAS_OBJ)) + load_objects(); + num_words = 1; + words[0].start = (char *)orig_starts[0]; + words[0].end = (char *)orig_ends[i-1]; + parse_recurse((char **)&starts[i], (char **)&orig_starts[i], (char **)&orig_ends[i]); + } + ve = ve->next; + } + } + starts[i][-1] = ' '; + } +} + +static svalue_t * get_the_error (parser_error_t * err, int obj) { + int tmp = err->error_type; + static svalue_t hack = { T_NUMBER }; + + err->error_type = 0; + push_number(tmp); + if (obj == -1 || (loaded_objects[obj]->flags & O_DESTRUCTED)) + push_undefined(); + else + push_object(loaded_objects[obj]); + + switch (tmp) { + case ERR_IS_NOT: + case ERR_NOT_LIVING: + case ERR_NOT_ACCESSIBLE: + push_shared_string(err->err.noun->name); + push_number(get_single(&err->err.noun->pv.noun) == -1); + return apply_master_ob(APPLY_PARSER_ERROR_MESSAGE, 4); + case ERR_AMBIG: + push_bitvec_as_array(&err->err.obs, 0); + return apply_master_ob(APPLY_PARSER_ERROR_MESSAGE, 3); + case ERR_ORDINAL: + push_number(err->err.ord_error); + return apply_master_ob(APPLY_PARSER_ERROR_MESSAGE, 3); + case ERR_THERE_IS_NO: + push_words(err->err.str_problem.start, + err->err.str_problem.end); + return apply_master_ob(APPLY_PARSER_ERROR_MESSAGE, 3); + case ERR_ALLOCATED: + push_malloced_string(err->err.str); + return apply_master_ob(APPLY_PARSER_ERROR_MESSAGE, 3); + case ERR_BAD_MULTIPLE: + return apply_master_ob(APPLY_PARSER_ERROR_MESSAGE, 2); + case ERR_MANY_PATHS: + return apply_master_ob(APPLY_PARSER_ERROR_MESSAGE, 5); + default: + pop_stack(); + sp--; + hack.u.number = -found_level; + return &hack; + } +} + +void f_parse_sentence (void) { + if (!current_object->pinfo) + error("/%s is not known by the parser. Call parse_init() first.\n", + current_object->obname); + + //if (pi) + // error("Illegal to call parse_sentence() recursively.\n"); + + /* may not be done in case of an error, or in case of tail recursion. + * if we are called tail recursively, we don't need this any more. + */ + if (best_result) { + free_parse_result(best_result); + best_result = 0; + } + + if (st_num_arg == 4) + parse_nicks = (sp--)->u.map; + + if (st_num_arg >= 3) + parse_env = (sp--)->u.arr; + + if (st_num_arg >= 2 && (sp--)->u.number) { +#if defined(DEBUG) || defined(PARSE_DEBUG) + debug_parse_depth = 1; + if ((sp + 1)->u.number > 1) + debug_parse_verbose = 1; + else + debug_parse_verbose = 0; + } else { + debug_parse_depth = 0; +#else + error("Parser debugging not enabled. (compile with -DDEBUG or -DPARSE_DEBUG).\n"); +#endif + } + + STACK_INC; + sp->type = T_ERROR_HANDLER; + sp->u.error_handler = free_parse_globals; + + parse_user = current_object; + pi = current_object->pinfo; + parse_restricted = 0; + found_level = 0; + parse_sentence((sp-1)->u.string); + + if (best_match) { + sp--; /* pop the error handler */ + free_parse_globals(); + + do_the_call(); + free_string_svalue(sp); + put_number(1); + } else { + svalue_t *ret = get_the_error(&best_error_info, -1); + + sp--; /* pop the error handler */ + free_parse_globals(); + + free_string_svalue(sp); + if (ret) { + *sp = *ret; + ret->type = T_NUMBER; /* will be freed later */ + } else + *sp = const0; + } + + if (best_result) { + free_parse_result(best_result); + best_result = 0; + } +} + +void f_parse_my_rules (void) { + int flag = (st_num_arg == 3 ? (sp--)->u.number : 0); + + if (!(sp-1)->u.ob->pinfo) + error("/%s is not known by the parser. Call parse_init() first.\n", + (sp-1)->u.ob->obname); + if (!current_object->pinfo) + error("/%s is not known by the parser. Call parse_init() first.\n", + current_object->obname); + + if (pi) + error("Illegal to call parse_sentence() recursively.\n"); + + STACK_INC; + sp->type = T_ERROR_HANDLER; + sp->u.error_handler = free_parse_globals; + + parse_user = (sp-2)->u.ob; + pi = parse_user->pinfo; + parse_restricted = current_object; + parse_sentence((sp-1)->u.string); + + if (best_match) { + if (flag) { + do_the_call(); + sp--; /* pop the error handler */ + free_string_svalue(sp--); + free_svalue(sp, "parse_my_rules"); /* may have been destructed */ + put_number(1); + } else { + int n; + array_t *arr; + /* give them the info for the wildcard call */ + n = best_result->res[3].num; + arr = allocate_empty_array(n); + if (n) { + memcpy((char *)arr->item, best_result->res[3].args, n*sizeof(svalue_t)); + while (n--) { + if (arr->item[n].type == T_OBJECT && arr->item[n].u.ob->flags & O_DESTRUCTED) { + free_object(&arr->item[n].u.ob, "parse_my_rules"); + arr->item[n] = const0u; + } + } + FREE(best_result->res[3].args); + } + best_result->res[3].args = 0; + sp--; /* pop the error handler */ + free_string_svalue(sp--); + free_svalue(sp, "parse_my_rules"); /* may have been destructed */ + put_array(arr); + } + } else { + svalue_t *ret = get_the_error(&best_error_info, -1); + + sp--; /* pop the error handler */ + free_string_svalue(sp--); + free_svalue(sp, "parse_my_rules"); /* may have been destructed */ + if (ret) { + *sp = *ret; + ret->type = T_NUMBER; + } else { + *sp = const0; + } + } + free_parse_globals(); +} + +void f_parse_remove() { + const char *verb; + verb_t *verb_entry; + + verb = SHARED_STRING(sp); + verb_entry = verbs[DO_HASH(verb, VERB_HASH_SIZE)]; + while (verb_entry) { + if (verb_entry->match_name == verb) { + verb_node_t **vn = &(verb_entry->node), *old; + while (*vn) { + if ((*vn)->handler == current_object) { + old = *vn; + *vn = (*vn)->next; + FREE(old); + } else vn = &((*vn)->next); + } + } + verb_entry = verb_entry->next; + } + free_string_svalue(sp--); +} + +void f_parse_add_rule() { + int tokens[10]; + int lit[2], i, j; + svalue_t *ret; + const char *verb, *rule; + object_t *handler; + verb_t *verb_entry; + verb_node_t *verb_node; + int h; + int weight; + + rule = sp->u.string; + verb = SHARED_STRING(sp-1); + verb_entry = 0; + handler = current_object; + if (!(handler->pinfo)) + error("/%s is not known by the parser. Call parse_init() first.\n", + handler->obname); + + /* We need the literals */ + interrogate_master(); + + /* Create the rule */ + make_rule(rule, tokens, &weight); + + /* Now find a verb entry to put it in */ + if (verb) { + verb_entry = verbs[DO_HASH(verb, VERB_HASH_SIZE)]; + while (verb_entry) { + if (verb_entry->match_name == verb && + verb_entry->real_name == verb && + !(verb_entry->flags & VB_IS_SYN)) + break; + verb_entry = verb_entry->next; + } + } + + if (!verb_entry) { + if (!verb) + verb = make_shared_string((sp-1)->u.string); + else + ref_string(verb); + + h = DO_HASH(verb, VERB_HASH_SIZE); + verb_entry = ALLOCATE(verb_t, TAG_PARSER, "parse_add_rule"); + verb_entry->real_name = verb; + ref_string(verb); + verb_entry->match_name = verb; + verb_entry->node = 0; + verb_entry->flags = 0; + verb_entry->next = verbs[h]; + verbs[h] = verb_entry; + } + + /* Add a new node */ + for (i = 0, j = 0; tokens[i]; i++) { + if (tokens[i] <= 0 && j < 2) + lit[j++] = -(tokens[i]+1); + } + + while (j < 2) + lit[j++] = -1; + + verb_node = (verb_node_t *)DXALLOC(sizeof(verb_node_t) + sizeof(int)*i, + TAG_PARSER, "parse_add_rule"); + + verb_node->lit[0] = lit[0]; + verb_node->lit[1] = lit[1]; + for (j = 0; j <= i; j++) { + if (tokens[j] >= OBJ_A_TOKEN) + verb_entry->flags |= VB_HAS_OBJ; + verb_node->token[j] = tokens[j]; + } + verb_node->weight = weight; + verb_node->handler = handler; + handler->pinfo->flags |= PI_VERB_HANDLER; + verb_node->next = verb_entry->node; + verb_entry->node = verb_node; + + ret = apply(LIVINGS_ARE_REMOTE, handler, 0, ORIGIN_DRIVER); + if (!IS_ZERO(ret)) + handler->pinfo->flags |= PI_REMOTE_LIVINGS; + + /* return */ + free_string_svalue(sp--); + free_string_svalue(sp--); +} + +void f_parse_add_synonym() { + const char *new_verb, *old_verb, *rule, *orig_new_verb; + verb_t *vb; + verb_node_t *vn, *verb_node; + verb_t *verb_entry; + int tokens[10]; + int weight; + int h; + + if (st_num_arg == 3) { + orig_new_verb = (sp-2)->u.string; + new_verb = SHARED_STRING(sp-2); + old_verb = SHARED_STRING(sp-1); + rule = sp->u.string; + } else { + orig_new_verb = (sp-1)->u.string; + new_verb = SHARED_STRING(sp-1); + old_verb = SHARED_STRING(sp); + rule = 0; + } + + if (old_verb == new_verb) + error("Verb cannot be a synonym for itself.\n"); + + verb_entry = 0; + + if (!old_verb) + error("%s is not a verb!\n", old_verb); + + vb = verbs[DO_HASH(old_verb, VERB_HASH_SIZE)]; + while (vb) { + if (vb->real_name == old_verb && vb->match_name == old_verb) + break; + vb = vb->next; + } + + if (!vb) + error("%s is not a verb!\n", old_verb); + + verb_entry = 0; + + /* Now find a verb entry to put it in */ + if (new_verb) { + verb_entry = verbs[DO_HASH(new_verb, VERB_HASH_SIZE)]; + while (verb_entry) { + if (verb_entry->real_name == new_verb + && verb_entry->match_name == old_verb) { + if (rule) { + if ((verb_entry->flags & VB_IS_SYN) == 0) break; + } else { + if ((verb_entry->flags & VB_IS_SYN)) + break; + } + } + verb_entry = verb_entry->next; + } + } + + if (!verb_entry) { + if (!new_verb) + new_verb = make_shared_string(orig_new_verb); + else + ref_string(new_verb); + ref_string(old_verb); + + h = DO_HASH(new_verb, VERB_HASH_SIZE); + verb_entry = ALLOCATE(verb_t, TAG_PARSER, "parse_add_rule"); + verb_entry->real_name = new_verb; + verb_entry->match_name = old_verb; + verb_entry->node = 0; + verb_entry->flags = 0; + verb_entry->next = verbs[h]; + verbs[h] = verb_entry; + } + + if (rule) { + int i; + + /* Create the rule */ + make_rule(rule, tokens, &weight); + + /*check that the rule we are shadowing exists, and check it's handler*/ + for (vn = vb->node; vn; vn = vn->next) { + for (i = 0; tokens[i]; i++) { + if (vn->token[i] != tokens[i]) break; + } + if (!tokens[i] && !vn->token[i]) break; /* match */ + } + if (!vn) error("No such rule defined.\n"); + if (vn->handler != current_object) error("Rule owned by different object.\n"); + + verb_node = (verb_node_t *)DXALLOC(sizeof(verb_node_t) + sizeof(int)*i, + TAG_PARSER, "parse_add_rule"); + memcpy(verb_node, vn, sizeof(verb_node_t) + sizeof(int)*i); + for (i = 0; vn->token[i]; i++) + if (vn->token[i] >= OBJ_A_TOKEN) { + verb_entry->flags |= VB_HAS_OBJ; + break; + } + + verb_node->next = verb_entry->node; + verb_entry->node = verb_node; + } else { + verb_syn_t *syn = (verb_syn_t*)verb_entry; + syn->flags = VB_IS_SYN | (vb->flags & VB_HAS_OBJ); + syn->real = vb; + } + + if (st_num_arg == 3) free_string_svalue(sp--); + free_string_svalue(sp--); + free_string_svalue(sp--); +} + +void f_parse_dump (void) +{ + int i; + outbuffer_t ob; + + outbuf_zero(&ob); + for (i = 0; i < VERB_HASH_SIZE; i++) { + verb_t *v; + + for (v = verbs[i]; v; v = v->next) { + verb_node_t *vn = v->node; + if (v->real_name == v->match_name) + outbuf_addv(&ob, "Verb %s:\n", v->real_name); + else + outbuf_addv(&ob, "Verb %s (%s):\n", v->real_name, v->match_name); + if (v->flags & VB_IS_SYN) { + outbuf_addv(&ob, " Synonym for: %s\n", ((verb_syn_t *)v)->real->real_name); + continue; + } + while (vn) { + outbuf_addv(&ob, " (/%s) %s\n", vn->handler->obname, rule_string(vn)); + vn = vn->next; + } + } + } + outbuf_push(&ob); +} diff --git a/fluffos-2.23-ds03/packages/parser.h b/fluffos-2.23-ds03/packages/parser.h new file mode 100644 index 0000000..8800fd8 --- /dev/null +++ b/fluffos-2.23-ds03/packages/parser.h @@ -0,0 +1,235 @@ +#ifndef ZORKPARSE_H +#define ZORKPARSE_H + +#include "../include/parser_error.h" + +/* Token convention: + * >0 is a token (OBJ, etc). + * <=0 is a literal. + */ +#define ERROR_TOKEN 1 +#define STR_TOKEN 2 +#define WRD_TOKEN 3 + +#define LIV_MODIFIER 8 +#define VIS_ONLY_MODIFIER 16 +#define PLURAL_MODIFIER 32 +#define CHOOSE_MODIFIER 64 + +#define ADD_MOD(x, y) ((x) | (y)) + +#define OBJ_A_TOKEN 4 +#define LIV_A_TOKEN ADD_MOD(OBJ_A_TOKEN, LIV_MODIFIER) +#define OBJ_TOKEN ADD_MOD(OBJ_A_TOKEN, VIS_ONLY_MODIFIER) +#define LIV_TOKEN ADD_MOD(LIV_A_TOKEN, VIS_ONLY_MODIFIER) +#define OBS_TOKEN ADD_MOD(OBJ_A_TOKEN, PLURAL_MODIFIER) +#define LVS_TOKEN ADD_MOD(LIV_A_TOKEN, PLURAL_MODIFIER) + +#define MAX_NUM_OBJECTS 4096 +/* must be powers of 2 */ +#define HASH_SIZE 32 +#define VERB_HASH_SIZE 128 +#define SPECIAL_HASH_SIZE 16 + +/* This is used to hash shared string pointers for various lookup tables */ +#define DO_HASH(x, n) ((((POINTER_INT)x) & (n - 1)) ^ \ + (((POINTER_INT)x >> 8) & (n - 1)) ^ \ + (((POINTER_INT)x >> 16) & (n - 1))) + +/* + * bitvec stuff. Basically, at the start of parsing, we determine what + * objects are involved in the parse, and assign each a number. Then + * we use the following bitvectors to keep track of sets of objects, + * so we can intersect sets fast etc. + */ +/* bits per int */ +#define BPI ((sizeof(int)) * 8) +#define NUM_BITVEC_INTS (MAX_NUM_OBJECTS / BPI) +#define BV_WHICH(x) ((x) / BPI) +#define BV_BIT(x) (1 << ((x) % BPI)) + +typedef struct { + unsigned int b[NUM_BITVEC_INTS]; + short last; +} bitvec_t; + +/* A parse value. This keeps track of which objects respond to a given + * word and how. For example: + * + * ob1: "wolf sword" adj = wolf noun = sword + * ob2: "gray wolf" adj = gray noun = wolf + * ob3: "white wolf" adj = white noun = wolf + * + * "wolf": + * noun: (ob2 and ob3) + * adj: (ob1) + */ +typedef struct { + bitvec_t noun, plural, adj; +} parse_val_t; + +#define WORD_ALLOCATED 1 + +typedef struct { + int type; + char *string; + char *start, *end; +} word_t; + +/* Flags for parse_info structures. parse_info information is cached inside + * objects so we don't have to call the relevant LPC functions over and over + * and over. parse_refresh() is provided to dump the cached info, for cases + * where it changes. + * + * parse_init() allocates the pinfo structure and sets PI_SETUP to zero. + * The actual info will be filled in when needed, and PI_SETUP will then + * be set to 1. parse_refresh() actually just zeros PI_SETUP. + */ +#define PI_SETUP 1 +#define PI_LIVING 2 +#define PI_VERB_HANDLER 4 +#define PI_REMOTE_LIVINGS 8 +#define PI_INV_ACCESSIBLE 16 +#define PI_INV_VISIBLE 32 +#define PI_REFRESH 64 + +typedef struct parse_info_s { + int flags; + struct object_s *ob; + int num_ids, num_adjs, num_plurals; + char **ids, **adjs, **plurals; +} parse_info_t; + +/* HV_PERM indicates that an entry shouldn't be removed from the hash + * table. Currently, unused. Good for global objects, etc + */ +#define HV_PERM 1 +#define HV_NOUN 2 +#define HV_PLURAL 4 +#define HV_ADJ 8 +#define HV_NICKNAME 16 + +/* An entry in the hash table that hashes words->interpretations; + * Hmm ... maybe flags here should be removed. + */ +typedef struct hash_entry_s { + struct hash_entry_s *next; + const char *name; + int flags; + parse_val_t pv; +} hash_entry_t; + +typedef struct special_word_s { + struct special_word_s *next; + const char *wrd; + short kind; + short arg; +} special_word_t; + +enum sw_enum_s { + SW_NONE = 0, SW_ARTICLE, SW_SELF, SW_ORDINAL, SW_ALL, SW_OF, SW_AND +}; + +/* Each node holds informations about a given rule. The handler for the + * rule, the literals it contains, and the token string (OBJ, "to", OBJ) + * are stored in here. Note that it is variable size. + */ +typedef struct verb_node_s { + struct verb_node_s *next; + struct object_s *handler; + int weight; + short lit[2]; + int token[1]; +} verb_node_t; + +/* + * The entry for a verb. Links for the verb hash table, and a linked + * list of rules. + */ +#define VB_HAS_OBJ 1 +#define VB_IS_SYN 2 + +typedef struct verb_s { + struct verb_s *next; + int flags; + const char *match_name; + const char *real_name; + verb_node_t *node; +} verb_t; + +typedef struct verb_syn_s { + struct verb_s *next; + int flags; + const char *match_name; + const char *real_name; + verb_t *real; +} verb_syn_t; + +/* A token definition for the token lookup table */ +typedef struct { + const char *name; + int token; + int mod_legal; +} token_def_t; + +union parser_error_u { + hash_entry_t *noun; + struct { + int start, end; + } str_problem; + bitvec_t obs; + int ord_error; + const char *str; + struct saved_error_s *parallel; +}; + +typedef struct { + int error_type; + union parser_error_u err; +} parser_error_t; + +typedef struct saved_error_s { + struct saved_error_s *next; + parser_error_t err; + int obj; +} saved_error_t; + +struct ms { + bitvec_t obs; + int number; +}; + +typedef struct { + short token; + short first, last; + short ordinal; + struct ms val; +} match_t; + +typedef struct { + int tok_index, word_index; + int num_matches; + int num_errors; + int num_objs; +} parse_state_t; + +typedef struct { + const char *func; + int num; + svalue_t *args; +} sub_result_t; + +typedef struct { + object_t *ob; + saved_error_t *parallel; + sub_result_t res[4]; +} parse_result_t; + +void parse_free (parse_info_t *); +#ifdef DEBUGMALLOC_EXTENSIONS +void parser_mark_verbs(); +void parser_mark (parse_info_t *); +void mark_hash_entry (const char *); +#endif + +#endif diff --git a/fluffos-2.23-ds03/packages/parser_spec.c b/fluffos-2.23-ds03/packages/parser_spec.c new file mode 100644 index 0000000..0391d8d --- /dev/null +++ b/fluffos-2.23-ds03/packages/parser_spec.c @@ -0,0 +1,10 @@ +#include "spec.h" + +void parse_init(); +void parse_refresh(); +mixed parse_sentence(string, void | int, void | object *, void | mapping); +void parse_add_rule(string, string); +void parse_remove(string); +void parse_add_synonym(string, string, void | string); +string parse_dump(); +mixed parse_my_rules(object, string, void | int); diff --git a/fluffos-2.23-ds03/packages/pcre.c b/fluffos-2.23-ds03/packages/pcre.c new file mode 100644 index 0000000..7dc8750 --- /dev/null +++ b/fluffos-2.23-ds03/packages/pcre.c @@ -0,0 +1,1010 @@ +/* FILES + * - pcre.c + * - pcre_spec.c + * - pcre.h + * + * PCRE (Perl Compatible Regular Expressions) + * Efuns using system library of PCRE (http://www.pcre.org/) + * The PCRE library was created by Philip Hazel at the + * University of Cambridge + * + * For regular expressions syntactics: + * http://perldoc.perl.org/perlre.html + * + * + * AUTHOR + * Volothamp @ Final Realms + * nfa106 [a] gmail.com + * + * HISTORY + * June-July 2009: + * Package created + * + * + * DESCRIPTION + * + * This package introduces the following efuns: + * + * string pcre_version(); + * - returns the version of the compiled PCRE library used + * + * mixed pcre_match(string | string *, string, void | int); + * - analog with regexp(string | string *, string, void | int); + * for backwards compatibility reasons but utilizing the PCRE + * library. + * + * mixed *pcre_assoc(string, string *, mixed *, mixed | void); + * - analog with reg_assoc(string, string *, mixed *, mixed | void); + * for backwards compatibility reasons but utilizing the PCRE + * library. + * + * string *pcre_extract(string subject, string pattern); + * - returns an array of captured groups specified in pattern + * + * string pcre_replace(string subject, string pattern, string *replacement); + * - returns a string where all captured groups have been replaced by the + * elements of the replacement array. Number of subgroups and the size of + * the replacement array must match. + * + * string pcre_replace_callback(string subject, string pattern, function | string fun, object ob); + * - returns a string where all captured groups have been replaced by the + * return value of function pointe fun or function fun in object ob. + */ +//TODO +// study pattern +// extra options when matching, greedy, lazy, possesive, etc. +// match_all ? see previous +// store reg->error & reg->erroffset before error(..) + +#include "lpc_incl.h" +#include +#include "pcre.h" +#include "macros.h" +#include "mapping.h" + +// Prototype declarations +static void pcre_free_memory(pcre_t *p); +static pcre *pcre_local_compile(pcre_t *p); +static int pcre_local_exec(pcre_t *p); +static int pcre_magic(pcre_t *p); +static int pcre_query_match(pcre_t *p); +static int pcre_match_single(svalue_t *str, svalue_t *pattern); +static array_t *pcre_match(array_t *v, svalue_t *pattern, int flag); +static array_t *pcre_assoc(svalue_t *str, array_t *pat, array_t *tok, svalue_t *def); +static char *pcre_get_replace(pcre_t *run, array_t *replacements); +static array_t *pcre_get_substrings(pcre_t *run); +//Caching functions +static int pcre_cache_pattern(struct pcre_cache_t *table, pcre *cpat, svalue_t *pattern); +static pcre *pcre_get_cached_pattern(struct pcre_cache_t *table, svalue_t *pattern); +static mapping_t *pcre_get_cache(); +int pcrecachesize = 0; +// Globals +struct pcre_cache_t pcre_cache = {{ 0 }}; + + +// efuns +void f_pcre_version(void) +{ + char *version; + version = (char *)pcre_version(); + push_constant_string(version); +} + +void f_pcre_match(void) +{ + array_t *v; + int flag = 0; + + if (st_num_arg > 2) + { + if (sp->type != T_NUMBER) + error("Bad argument 3 to pcre_match()\n"); + if ((sp - 2)->type == T_STRING) + error("3rd argument illegal for pcre_match(string, string)\n"); + + flag = (sp--)->u.number; + } + + if ((sp - 1)->type == T_STRING ) + { + flag = pcre_match_single((sp-1), sp); + + free_string_svalue(sp--); + free_string_svalue(sp); + put_number(flag); + } + else + { + v = pcre_match((sp - 1)->u.arr, sp, flag); + + free_string_svalue(sp--); + free_array(sp->u.arr); + sp->u.arr = v; + } +} + +void f_pcre_assoc(void) +{ + svalue_t *arg; + array_t *vec; + + arg = sp - st_num_arg + 1; + + if ((arg + 2)->type != T_ARRAY) + error("Bad argument 3 to pcre_assoc()\n"); + + vec = pcre_assoc(arg, (arg+1)->u.arr, (arg+2)->u.arr, + st_num_arg > 3 ? (arg+3) : &const0); + + if (st_num_arg == 4) + pop_3_elems(); + else + pop_2_elems(); + + free_string_svalue(sp); + + sp->type = T_ARRAY; + sp->u.arr = vec; +} + +void f_pcre_extract(void) +{ + pcre_t *run; + array_t *ret; + + run = CALLOCATE(1, pcre_t, TAG_TEMPORARY, "f_pcre_extract : run"); + assign_svalue_no_free(&run->pattern, sp); + run->subject = (sp - 1)->u.string; + run->s_length = SVALUE_STRLEN(sp - 1); + run->ovector = NULL; + run->ovecsize = 0; + + if(pcre_magic(run) < 0) + { + error("PCRE compilation failed at offset %d: %s\n", run->erroffset, + run->error); + pop_2_elems(); + pcre_free_memory(run); + return; + } + + /* Pop the 2 arguments from the stack */ + + if (run->rc < 0) /* No match. could do handling of matching errors if wanted */ + { + pop_2_elems(); + pcre_free_memory(run); + push_refed_array(&the_null_array); + return; + } + else if (run->rc > (run->ovecsize/3 - 1)) + { + pop_2_elems(); + pcre_free_memory(run); + error("Too many substrings.\n"); + return; + } + + + ret = pcre_get_substrings(run); + pop_2_elems(); + + push_refed_array(ret); + + pcre_free_memory(run); + return; +} + + + +void f_pcre_replace(void) +{ + pcre_t *run; + array_t *replacements; + + unsigned int i; + char *ret; + + run = CALLOCATE(1, pcre_t, TAG_TEMPORARY, "f_pcre_replace: run"); + + run->ovector = NULL; + run->ovecsize = 0; + assign_svalue_no_free(&run->pattern, (sp - 1)); + run->subject = (sp - 2)->u.string; + replacements = sp->u.arr; + + run->s_length = SVALUE_STRLEN(sp - 2); + + + if(pcre_magic(run) < 0) + { + pcre_free_memory(run); + error("PCRE compilation failed at offset %d: %s\n", run->erroffset, + run->error); + } + + + if (run->rc < 0) /* No match. could do handling of matching errors if wanted */ + { + pcre_free_memory(run); + pop_2_elems(); + return; + } + + + if (run->rc > (run->ovecsize/3-1)) + { + pcre_free_memory(run); + error("Too many substrings.\n"); + } + if ( (run->rc - 1) != replacements->size ) + { + int tmp = run->rc-1; + pcre_free_memory(run); + error("Number of captured substrings and replacements do not match, " + "%d vs %d.\n", tmp, replacements->size); + } + + + + if (run->rc == 1) + { + /* No captured substrings, return subject */ + pcre_free_memory(run); + pop_2_elems(); + return; + //push_malloced_string(run->subject); + } + + ret = pcre_get_replace(run, replacements); + + + pop_3_elems(); + push_malloced_string(ret); + pcre_free_memory(run); + return; +} + +//string pcre_replace_callback(string, string, function) +void f_pcre_replace_callback(void) +{ + int num_arg = st_num_arg, i; + char *ret; + pcre_t *run; + svalue_t *arg; + array_t *arr, *r; + function_to_call_t ftc; + + arg = sp - num_arg + 1; + + run = CALLOCATE(1, pcre_t, TAG_TEMPORARY, "f_pcre_replace: run"); + run->ovector = NULL; + run->ovecsize = 0; + run->subject = arg->u.string; + assign_svalue_no_free(&run->pattern, (arg + 1)); + + run->s_length = SVALUE_STRLEN(arg); + + if(pcre_magic(run) < 0) + { + pcre_free_memory(run); + error("PCRE compilation failed at offset %d: %s\n", run->erroffset, + run->error); + } + + + if (run->rc < 0) /* No match. could do handling of matching errors if wanted */ + { + pop_n_elems(num_arg-1); + pcre_free_memory(run); + return; + } + + + if (run->rc > (run->ovecsize/3-1)) + { + pcre_free_memory(run); + error("Too many substrings.\n"); + } + + arr = pcre_get_substrings(run); + + if(arg[2].type == T_FUNCTION || arg[2].type == T_STRING) + process_efun_callback(2, &ftc, F_PCRE_REPLACE_CALLBACK); + else {// 0 + pcre_free_memory(run); + error("Illegal third argument (0) to pcre_replace_callback"); + } + + + r = allocate_array(run->rc - 1); //can't use the empty variant in case we error below + + push_refed_array(r); + push_refed_array(arr); + error_context_t econ; + + if (!save_context(&econ)){ + pcre_free_memory(run); + error("context stack full!\n"); + } + if (SETJMP(econ.context)) { + restore_context(&econ); + /* condition was restored to where it was when we came in */ + pcre_free_memory(run); + pop_context(&econ); + error("error in callback!\n"); + } + + for (i = 0; i < run->rc - 1; i++) + { + svalue_t *v; + push_svalue(arr->item + i); + push_number(i); + v = call_efun_callback(&ftc, 2); + + + /* Mimic behaviour of map(string, function) when function pointer returns null, + ie return the input. */ + if (v && v->type == T_STRING && v->u.string != NULL) + assign_svalue_no_free(&r->item[i], v); + else + assign_svalue_no_free(&r->item[i], &arr->item[i]); + } + pop_context(&econ); + ret = pcre_get_replace(run, r); + + pop_n_elems(num_arg+2); //refed arrays + push_malloced_string(ret); + pcre_free_memory(run); + return; +} + + +void f_pcre_cache(void) +{ + mapping_t *m=NULL; + m = pcre_get_cache(); + if (!m) + push_number(0); + else + push_refed_mapping(m); +} + + +// Internal functions utilized by the efuns +static pcre *pcre_local_compile(pcre_t *p) +{ + p->re = pcre_compile( + p->pattern.u.string, + 0, + &p->error, + &p->erroffset, + NULL); + + return p->re; +} + +static int pcre_local_exec(pcre_t *p) +{ + int size; + pcre_fullinfo(p->re, NULL, PCRE_INFO_CAPTURECOUNT, &size); + size+=2; + size *=3; + if(p->ovector) + FREE(p->ovector); + p->ovector = CALLOCATE(size+1, int, TAG_TEMPORARY, "pcre_local_exec"); //too much, but who cares + p->ovecsize = size; + p->rc = pcre_exec( + p->re, + NULL, + p->subject, + p->s_length, + 0, +#ifndef USE_ICONV + PCRE_NO_UTF8_CHECK, +#else + 0, +#endif + p->ovector, + size); + + return p->rc; +} + +static int pcre_magic(pcre_t *p) +{ + p->re = pcre_get_cached_pattern(&pcre_cache, &p->pattern); + + if (p->re == NULL) + { + pcre_local_compile(p); + pcre_cache_pattern(&pcre_cache, p->re, &p->pattern); + } + + + if (p->re == NULL) + return -1; + + /* Add support for studied patterns here */ + //if(p->study && !found) + // { + + // } + pcre_local_exec(p); + + + return 1; +} + +static int pcre_query_match(pcre_t *p) +{ + return p->rc < 0 ? 0 : 1; +} + +static int pcre_match_single(svalue_t *str, svalue_t *pattern) +{ + pcre_t *run; + int ret; + + run = CALLOCATE(1, pcre_t, TAG_TEMPORARY, "pcre_match_single : run"); + run->ovector = NULL; + run->ovecsize = 0; + assign_svalue_no_free(&run->pattern, pattern); + run->subject = str->u.string; + run->s_length = SVALUE_STRLEN(str); + + + if(pcre_magic(run) < 0) + { + error("PCRE compilation failed at offset %d: %s\n", run->erroffset, + run->error); + pcre_free_memory(run); + return 0; + } + + ret = pcre_query_match(run); + + /* Free memory */ + pcre_free_memory(run); + return ret; +} + +static array_t *pcre_match(array_t *v, svalue_t *pattern, int flag) +{ + pcre_t *run; + array_t *ret; + svalue_t *sv1, *sv2; + char *res; + int num_match, size, match = !(flag & 2); + + if (!(size = v->size)) + return &the_null_array; + + run = CALLOCATE(1, pcre_t, TAG_TEMPORARY, "pcre_match : run"); + run->ovector = NULL; + run->ovecsize = 0; + assign_svalue_no_free(&run->pattern, pattern); + + run->re = pcre_get_cached_pattern(&pcre_cache, &run->pattern); + + if (run->re == NULL) + { + if (pcre_local_compile(run) == NULL) + { + const char *rerror = run->error; + int offset = run->erroffset; + + pcre_free_memory(run); + error("PCRE compilation failed at offset %d: %s\n", offset, rerror); + } + else + pcre_cache_pattern(&pcre_cache, run->re, &run->pattern); + } + + res = (char*)DMALLOC(size, TAG_TEMPORARY, "prcre_match: res"); + sv1 = v->item + size; + num_match = 0; + + while (size--) + { + if ((--sv1)->type != T_STRING) + { + res[size] = 0; + continue; + } + + run->subject = sv1->u.string; + run->s_length = SVALUE_STRLEN(sv1); + + pcre_local_exec(run); + + if (!pcre_query_match(run)) + { + res[size] = 0; + continue; + } + + res[size] = 1; + num_match++; + } + + flag &= 1; + ret = allocate_empty_array(num_match << flag); + sv2 = ret->item + (num_match << flag); + size = v->size; + + while (size--) + { + if (res[size]) + { + if (flag) + { + (--sv2)->type = T_NUMBER; + sv2->u.number = size + 1; + } + + (--sv2)->type = T_STRING; + + sv1 = v->item + size; + *sv2 = *sv1; + + if (sv1->subtype & STRING_COUNTED) + { + INC_COUNTED_REF(sv1->u.string); + ADD_STRING(MSTR_SIZE(sv1->u.string)); + } + + if (!--num_match) + break; + } + } + FREE(res); + pcre_free_memory(run); + + return ret; +} + +/* This is mostly copy/paste from reg_assoc, some parts are changed + * TODO: rewrite with new logic + */ +static array_t *pcre_assoc(svalue_t *str, array_t *pat, array_t *tok, svalue_t *def) +{ + int i, size; + const char *tmp; + array_t *ret; + + if ((size = pat->size) != tok->size) + error("Pattern and token array size must be identical.\n"); + + for (i = 0; i < size; i++) + if (pat->item[i].type != T_STRING) + error("Non-string found in pattern array.\n"); + + ret = allocate_empty_array(2); + + if (size) + { + pcre_t **rgpp; + struct reg_match { + int tok_i; + const char *begin, *end; + struct reg_match *next; + } *rmp = (struct reg_match *) 0, *rmph = (struct reg_match *) 0; + int num_match = 0, length; + svalue_t *sv1, *sv2, *sv; + int regindex; + pcre_t *tmpreg; + int laststart; + + rgpp = CALLOCATE(size, pcre_t *, TAG_TEMPORARY, "pcre_assoc : rgpp"); + + for (i = 0; i < size; i++) + { + rgpp[i] = CALLOCATE(1, pcre_t, TAG_TEMPORARY, "pcre_assoc : rgpp[i]"); + rgpp[i]->ovector = NULL; + rgpp[i]->ovecsize = 0; + assign_svalue_no_free(&rgpp[i]->pattern, &pat->item[i]); + rgpp[i]->re = pcre_get_cached_pattern(&pcre_cache, &rgpp[i]->pattern); + + if (rgpp[i]->re == NULL) + { + if (pcre_local_compile(rgpp[i]) == NULL) + { + const char *rerror = rgpp[i]->error; + int offset = rgpp[i]->erroffset; + + while (i--) + pcre_free_memory(rgpp[i]); + + FREE(rgpp); + free_empty_array(ret); + error("PCRE compilation failed at offset %d: %s\n", offset, rerror); + } + else + pcre_cache_pattern(&pcre_cache, rgpp[i]->re, &rgpp[i]->pattern); + } + } + + + tmp = str->u.string; + int totalsize = SVALUE_STRLEN(str); + int used = 0; + while (*tmp) + { + laststart = 0; + regindex = -1; + + for (i = 0; i < size; i++) + { + + rgpp[i]->subject = tmp; + rgpp[i]->s_length = totalsize-used; + + pcre_local_exec(tmpreg = rgpp[i]); + + if (pcre_query_match(tmpreg)) + { + char *curr_temp; + size_t curr_temp_sz; + + curr_temp_sz = totalsize - used - tmpreg->ovector[0]; + if(!tmpreg->ovector[0]){ + regindex = i; + break; + } + if (laststart < curr_temp_sz) + { + laststart = curr_temp_sz; + regindex = i; + } + } + } + + if (regindex >= 0) + { + const char *rmpb_tmp, *rmpe_tmp; + size_t rmpb_tmp_sz, rmpe_tmp_sz; + num_match++; + + if (rmp) + { + rmp->next = ALLOCATE(struct reg_match, + TAG_TEMPORARY, "pcre_assoc : rmp->next"); + rmp = rmp->next; + } + else + rmph = rmp = ALLOCATE(struct reg_match, + TAG_TEMPORARY, "pcre_assoc : rmp"); + + tmpreg = rgpp[regindex]; + + rmpb_tmp = tmp + tmpreg->ovector[0]; + rmpe_tmp = tmp + tmpreg->ovector[1]; + + rmp->begin = rmpb_tmp; + rmp->end = tmp = rmpe_tmp; + used+=tmpreg->ovector[1]; + rmp->tok_i = regindex; + rmp->next = (struct reg_match *) 0; + } + else + break; + + if (rmp->begin == tmp && (!*++tmp)) + break; + } + + sv = ret->item; + sv->type = T_ARRAY; + sv1 = (sv->u.arr = allocate_empty_array(2*num_match + 1))->item; + + sv++; + sv->type = T_ARRAY; + sv2 = (sv->u.arr = allocate_empty_array(2*num_match + 1))->item; + + rmp = rmph; + + tmp = str->u.string; + + while (num_match--){ + char *svtmp; + length = rmp->begin - tmp; + + sv1->type = T_STRING; + sv1->subtype = STRING_MALLOC; + sv1->u.string = svtmp = new_string(length, "pcre_assoc : sv1"); + strncpy(svtmp, tmp, length); + svtmp[length] = 0; + + sv1++; + assign_svalue_no_free(sv2++, def); + tmp += length; + + length = rmp->end - rmp->begin; + + sv1->type = T_STRING; + sv1->subtype = STRING_MALLOC; + sv1->u.string = svtmp = new_string(length, "pcre_assoc : sv1"); + strncpy(svtmp, tmp, length); + svtmp[length] = 0; + + sv1++; + assign_svalue_no_free(sv2++, &tok->item[rmp->tok_i]); + tmp += length; + rmp = rmp->next; + } + + sv1->type = T_STRING; + sv1->subtype = STRING_MALLOC; + sv1->u.string = string_copy(tmp, "pcre_assoc"); + assign_svalue_no_free(sv2, def); + + for (i = 0; i < size; i++) + pcre_free_memory(rgpp[i]); + + FREE(rgpp); + + while (rmp = rmph){ + rmph = rmp->next; + FREE((char *) rmp); + } + return ret; + } + else { + svalue_t *temp; + svalue_t *sv; + + (sv = ret->item)->type = T_ARRAY; + temp = (sv->u.arr = allocate_empty_array(1))->item; + assign_svalue_no_free(temp, str); + sv = &ret->item[1]; + sv->type = T_ARRAY; + assign_svalue_no_free((sv->u.arr = allocate_empty_array(1))->item, def); + return ret; + } +} + +static array_t *pcre_get_substrings(pcre_t *run) +{ + array_t *ret; + unsigned int i; + char **matches; + + ret = allocate_empty_array(run->rc - 1); + + if (run->rc != 1) + { + for (i = 1; i<= (run->rc-1); i++) + { + unsigned int start, length; + /* Allocate enough for the match */ + length = run->ovector[2*i + 1] - run->ovector[2*i]; + start = run->ovector[2*i]; + char *match = new_string(length, "pcre get substrings"); + + sprintf(match, "%.*s", length, run->subject + start); + ret->item[i-1].type = T_STRING; + ret->item[i-1].subtype = STRING_MALLOC; + ret->item[i-1].u.string = match; + } + } + return ret; +} + +static char *pcre_get_replace(pcre_t *run, array_t *replacements) +{ + unsigned int ret_pos = 0, i; + size_t ret_sz; + char *ret; + + /* Set size of return string to subject length */ + ret_sz = run->s_length; + + /* Subtract total size of all substrings */ + int prev = run->ovector[2]; + for (i = 1; i <= (run->rc - 1); i++){ + //printf("%d %d %d\n", ret_sz, run->ovector[2*i],run->ovector[2*i+1] ); + if(run->ovector[2*i] >= prev){ + ret_sz -= (size_t)(run->ovector[2*i + 1] - run->ovector[2*i]); + prev = run->ovector[2*i + 1]; + /* Add total size of all replacements */ + ret_sz += SVALUE_STRLEN(&replacements->item[i-1]); + } + } + + /* Allocate space for the return string */ + ret = new_string((ret_sz), "pcre get replace"); + //printf("ret_sz:%d\n", ret_sz); + + /* Copy start of subject up until first match */ + if(run->rc > 1){ + strncpy(ret, run->subject, run->ovector[2]); + ret_pos = run->ovector[2]; + } + else + strncpy(ret, run->subject, ret_sz); + + for (i = 1; i <= (run->rc - 1); i++) + { + + unsigned int start, end, len_nxt; + const char *rep; + size_t rep_sz; + + start = run->ovector[2*i]; + end = run->ovector[2*i + 1]; + + if ( i == (run->rc - 1)) + len_nxt = run->s_length - end; + else + len_nxt = run->ovector[2*i + 2] - end; + + if(len_nxt > MAX_STRING_LENGTH) + continue; //nested ()s + + rep = replacements->item[i - 1].u.string; + rep_sz = SVALUE_STRLEN(&replacements->item[i - 1]); + + + /* Copy first substring into return variable */ + strncpy(ret + ret_pos, rep, rep_sz); + + + /* increment position in return variable by replacement size */ + ret_pos += rep_sz; + + + strncpy(ret + ret_pos, run->subject + end, len_nxt); + + + ret_pos += len_nxt; + } + + *(ret+ret_sz) = '\0'; + + + return ret; +} + + +static void pcre_free_memory(pcre_t *p) +{ + free_svalue(&p->pattern, "pcre_free_memory"); + if(p->ovector) + FREE(p->ovector); + FREE(p); + +} + +//Caching functions, add new ones at the front of the bucket so we find them faster +static int pcre_cache_pattern(struct pcre_cache_t *table, pcre *cpat, svalue_t *pattern) //don't keep pointers to strings that will get freed elsewhere! +{ + unsigned int bucket = svalue_to_int(pattern) % PCRE_CACHE_SIZE; + int sz; + struct pcre_cache_bucket_t *tmp; + struct pcre_cache_bucket_t *node; + int full; + + tmp = table->buckets[bucket]; + + // Calculate size of compiled pattern + pcre_fullinfo(cpat, NULL, PCRE_INFO_SIZE, &sz); + + full = (pcrecachesize > 2 * PCRE_CACHE_SIZE); + while (tmp) + { + if (pattern->u.string == tmp->pattern.u.string) + break; + + tmp = tmp->next; + } + + if (tmp) + { + //does this even make sense? same pattern will always compile the same way? + pcre_free(tmp->compiled_pattern); + node = tmp; + } + else + { + node = CALLOCATE(1, struct pcre_cache_bucket_t, TAG_TEMPORARY, "pcre_cache_pattern : node"); + node->pattern.type = T_NUMBER; //so we don't free invalids + if (node == NULL) + return -1; + if(!full) + pcrecachesize++; + else{ + if((tmp = table->buckets[bucket])){ + while(tmp->next) + tmp = tmp->next; + if(tmp == table->buckets[bucket]){//if the hash version works, most of the time + pcre_free(tmp->compiled_pattern); + FREE(tmp); + table->buckets[bucket] = NULL; + } else { + struct pcre_cache_bucket_t *tmp2; + tmp2 = table->buckets[bucket]; + while(tmp2->next != tmp) + tmp2 = tmp2->next; //shouldn't get here often + pcre_free(tmp->compiled_pattern); + FREE(tmp); + tmp2->next = NULL; + } + } + } + node->next = table->buckets[bucket]; + table->buckets[bucket] = node; + } + + assign_svalue(&node->pattern, pattern); + node->compiled_pattern = cpat; + node->size = sz; + + return 0; +} + +static pcre *pcre_get_cached_pattern(struct pcre_cache_t *table, svalue_t *pattern) +{ + unsigned int bucket = svalue_to_int(pattern) % PCRE_CACHE_SIZE; + struct pcre_cache_bucket_t *node; + struct pcre_cache_bucket_t *lnode = NULL; + node = table->buckets[bucket]; + + while (node) + { + if (pattern->u.string == node->pattern.u.string){ + if(node != table->buckets[bucket]){ + //not at the front, move it there, so the most used pattern is fastest + lnode->next = node->next; + node->next = table->buckets[bucket]; + table->buckets[bucket] = node; + } + return node->compiled_pattern; + } + lnode = node; + node = node->next; + } + return NULL; +} + + +static mapping_t *pcre_get_cache() +{ + int size = 0, i; + mapping_t *ret; + struct pcre_cache_bucket_t *node; + + // Calculate size for mapping + for (i = 0; i < PCRE_CACHE_SIZE; i++) + { + if (pcre_cache.buckets[i] != NULL) + { + node = pcre_cache.buckets[i]; + + while (node) + { + node = node->next; + size++; + } + } + } + + ret = allocate_mapping(size); + + for (i = 0; i< PCRE_CACHE_SIZE; i++) + { + if (pcre_cache.buckets[i] != NULL) + { + node = pcre_cache.buckets[i]; + + while (node) + { + add_mapping_pair(ret, node->pattern.u.string, node->size); + node = node->next; + } + } + } + return ret; +} + + diff --git a/fluffos-2.23-ds03/packages/pcre.h b/fluffos-2.23-ds03/packages/pcre.h new file mode 100644 index 0000000..ca72eee --- /dev/null +++ b/fluffos-2.23-ds03/packages/pcre.h @@ -0,0 +1,46 @@ +/* OVECCOUNT is the return vector of matches. + ovector[0] = start of entire match + ovector[1] = end of entire match + ovector[2] = start of first capture group + ovector[3] = end of first capture group + ovector[4] = start of second capture group + etc + +The maximum number of capturing groups is: + (n+1)*3 +*/ +#ifndef PCRE_EFUNS +#define PCRE_EFUNS +#define PCRE_CACHE_SIZE 256 + +typedef struct { + pcre *re; + const char *error; + svalue_t pattern; + const char *subject; + unsigned char *name_table; + size_t s_length; + int erroffset; + int find_all; + int namecount; + int name_entry_size; + int *ovector; + int ovecsize; + int rc; +/* EXTRA */ +} pcre_t; + +struct pcre_cache_bucket_t { + pcre *compiled_pattern; // value1 + svalue_t pattern; // key + int size; // size in bytes + struct pcre_cache_bucket_t *next; +}; + +struct pcre_cache_t { + struct pcre_cache_bucket_t *buckets[PCRE_CACHE_SIZE]; +}; + + +#endif + diff --git a/fluffos-2.23-ds03/packages/pcre_spec.c b/fluffos-2.23-ds03/packages/pcre_spec.c new file mode 100644 index 0000000..f1a617f --- /dev/null +++ b/fluffos-2.23-ds03/packages/pcre_spec.c @@ -0,0 +1,9 @@ +#include "spec.h" + +string pcre_version(void); +mixed pcre_match(string | string *, string, void | int); +mixed *pcre_assoc(string, string *, mixed *, mixed | void); +string *pcre_extract(string, string); +string pcre_replace(string, string, string *); +string pcre_replace_callback(string, string, string | function, ...); +mapping pcre_cache(void); diff --git a/fluffos-2.23-ds03/packages/readme b/fluffos-2.23-ds03/packages/readme new file mode 100644 index 0000000..5cadcd2 --- /dev/null +++ b/fluffos-2.23-ds03/packages/readme @@ -0,0 +1,12 @@ +In order to add a package, do the following: + +(1) Pick a name for your package (we will use 'foo' here) + +(2) Put the prototypes for the efuns in foo_spec.c + +(3) implement the efuns in foo.c + +(4) add #define PACKAGE_FOO to options.h or local_options + +(5) do a full recompile (make remake) + diff --git a/fluffos-2.23-ds03/packages/sha1.c b/fluffos-2.23-ds03/packages/sha1.c new file mode 100644 index 0000000..bc88c79 --- /dev/null +++ b/fluffos-2.23-ds03/packages/sha1.c @@ -0,0 +1,134 @@ +/** + * sha1.c: this file provides the sha1 hashing algorithm + * based in part on code in the public domain by Niyaz PK. + * -- coded by Ajandurah@Demonslair 21/02/08 + */ + +#include + +#ifdef LATTICE +#include "/lpc_incl.h" +#else +#include "../lpc_incl.h" +#include "../efun_protos.h" +#endif + +#define rotateleft(x,n) ((x<>(32-n))) +#define rotateright(x,n) ((x>>n) | (x<<(32-n))) + +#ifdef F_SHA1 +void f_sha1(void) +{ + unsigned long int h0,h1,h2,h3,h4,a,b,c,d,e,f,k,temp; + int i, j, m; + + h0 = 0x67452301; + h1 = 0xEFCDAB89; + h2 = 0x98BADCFE; + h3 = 0x10325476; + h4 = 0xC3D2E1F0; + + unsigned char *str; + str = (unsigned char *)malloc(SVALUE_STRLEN(sp)+100); + + strcpy((char *)str, (const char *)sp->u.string); + + int current_length = strlen((const char *)str); + int original_length = current_length; + str[current_length] = 0x80; + str[current_length + 1] = '\0'; + + char ic = str[current_length]; + current_length++; + + int ib = current_length % 64; + if (ib < 56) + ib = 56 - ib; + else + ib = 120 - ib; + + for (i=0; iu.number = fd; + } else { + pop_n_elems(num_arg - 1); + sp->u.number = EESECURITY; + } +} +#endif + +#ifdef F_SOCKET_BIND +void +f_socket_bind (void) +{ + int i, fd, port, num_arg = st_num_arg; + svalue_t *arg; + char addr[ADDR_BUF_SIZE]; + + arg = sp - num_arg + 1; + if ((num_arg == 3) && (arg[2].type != T_STRING)) { + bad_arg(3, F_SOCKET_BIND); + } + + fd = arg[0].u.number; + get_socket_address(fd, addr, &port, 0); + + if (VALID_SOCKET("bind")) { + i = socket_bind(fd, arg[1].u.number, (num_arg == 3 ? arg[2].u.string : 0)); + pop_n_elems(num_arg - 1); + sp->u.number = i; + } else { + pop_n_elems(num_arg - 1); + sp->u.number = EESECURITY; + } +} +#endif + +#ifdef F_SOCKET_LISTEN +void +f_socket_listen (void) +{ + int i, fd, port; + char addr[ADDR_BUF_SIZE]; + + fd = (sp - 1)->u.number; + get_socket_address(fd, addr, &port, 0); + + if (VALID_SOCKET("listen")) { + i = socket_listen(fd, sp); + pop_stack(); + sp->u.number = i; + } else { + pop_stack(); + sp->u.number = EESECURITY; + } +} +#endif + +#ifdef F_SOCKET_ACCEPT +void +f_socket_accept (void) +{ + int port, fd; + char addr[ADDR_BUF_SIZE]; + + if (!(sp->type & (T_STRING | T_FUNCTION))) { + bad_arg(3, F_SOCKET_ACCEPT); + } + get_socket_address(fd = (sp-2)->u.number, addr, &port, 0); + + (sp-2)->u.number = VALID_SOCKET("accept") ? + socket_accept(fd, (sp - 1), sp) : + EESECURITY; + pop_2_elems(); +} +#endif + +#ifdef F_SOCKET_CONNECT +void +f_socket_connect (void) +{ + int i, fd, port; + char addr[ADDR_BUF_SIZE]; + + if (!((sp - 1)->type & (T_FUNCTION | T_STRING))) { + bad_arg(3, F_SOCKET_CONNECT); + } + if (!(sp->type & (T_FUNCTION | T_STRING))) { + bad_arg(4, F_SOCKET_CONNECT); + } + fd = (sp - 3)->u.number; + get_socket_address(fd, addr, &port, 0); + +#ifdef IPV6 + if (!strcmp(addr, "::") && port == 0) { +#else + if (!strcmp(addr, "0.0.0.0") && port == 0) { +#endif + /* + * socket descriptor is not bound yet + */ + const char *s; + int start = 0; + + addr[0] = '\0'; + if ((s = strchr((sp - 2)->u.string, ' '))) { + /* + * use specified address and port + */ + i = s - (sp - 2)->u.string; + if (i > ADDR_BUF_SIZE - 1) { + start = i - ADDR_BUF_SIZE - 1; + i = ADDR_BUF_SIZE - 1; + } + strncat(addr, (sp - 2)->u.string + start, i); + port = atoi(s + 1); + } +#ifdef DEBUG + } else { + fprintf(stderr, "socket_connect: socket already bound to address/port: %s/%d\n", + addr, port); + fprintf(stderr, "socket_connect: requested on: %s\n", (sp - 2)->u.string); +#endif + } + + (sp-3)->u.number = VALID_SOCKET("connect") ? + socket_connect(fd, (sp - 2)->u.string, sp - 1, sp) : EESECURITY; + pop_3_elems(); +} +#endif + +#ifdef F_SOCKET_WRITE +void +f_socket_write (void) +{ + int i, fd, port; + svalue_t *arg; + char addr[ADDR_BUF_SIZE]; + int num_arg = st_num_arg; + + arg = sp - num_arg + 1; + if ((num_arg == 3) && (arg[2].type != T_STRING)) { + bad_arg(3, F_SOCKET_WRITE); + } + fd = arg[0].u.number; + get_socket_address(fd, addr, &port, 0); + + if (VALID_SOCKET("write")) { + i = socket_write(fd, &arg[1], + (num_arg == 3) ? arg[2].u.string : (char *) NULL); + pop_n_elems(num_arg - 1); + sp->u.number = i; + } else { + pop_n_elems(num_arg - 1); + sp->u.number = EESECURITY; + } +} +#endif + +#ifdef F_SOCKET_CLOSE +void +f_socket_close (void) +{ + int fd, port; + char addr[ADDR_BUF_SIZE]; + + fd = sp->u.number; + get_socket_address(fd, addr, &port, 0); + + sp->u.number = VALID_SOCKET("close") ? socket_close(fd, 0) : EESECURITY; +} +#endif + +#ifdef F_SOCKET_RELEASE +void +f_socket_release (void) +{ + int fd, port; + char addr[ADDR_BUF_SIZE]; + + if (!(sp->type & (T_STRING | T_FUNCTION))) { + bad_arg(3, F_SOCKET_RELEASE); + } + fd = (sp - 2)->u.number; + get_socket_address(fd, addr, &port, 0); + + (sp-2)->u.number = VALID_SOCKET("release") ? + socket_release((sp - 2)->u.number, (sp - 1)->u.ob, sp) : + EESECURITY; + + pop_stack(); + /* the object might have been dested an removed from the stack */ + if (sp->type == T_OBJECT) + free_object(&sp->u.ob, "socket_release()"); + sp--; +} +#endif + +#ifdef F_SOCKET_ACQUIRE +void +f_socket_acquire (void) +{ + int fd, port; + char addr[ADDR_BUF_SIZE]; + + if (!((sp - 1)->type & (T_FUNCTION | T_STRING))) { + bad_arg(3, F_SOCKET_ACQUIRE); + } + if (!(sp->type & (T_FUNCTION | T_STRING))) { + bad_arg(4, F_SOCKET_ACQUIRE); + } + fd = (sp - 3)->u.number; + get_socket_address(fd, addr, &port, 0); + + (sp-3)->u.number = VALID_SOCKET("acquire") ? + socket_acquire((sp - 3)->u.number, (sp - 2), + (sp - 1), sp) : EESECURITY; + + pop_3_elems(); +} +#endif + +#ifdef F_SOCKET_ERROR +void +f_socket_error (void) +{ + put_constant_string(socket_error(sp->u.number)); +} +#endif + +#ifdef F_SOCKET_ADDRESS +void +f_socket_address (void) +{ + char *str; + int local, port; + char addr[ADDR_BUF_SIZE]; + char buf[2 * ADDR_BUF_SIZE]; /* a bit of overkill to be safe */ + + +/* + * Ok, we will add in a cute little check thing here to see if it is + * an object or not... + */ + local = (sp--)->u.number; + if (sp->type & T_OBJECT) { + const char *tmp; + +/* This is so we can get the address of interactives as well. */ + + if (!sp->u.ob->interactive) { + free_object(&sp->u.ob, "f_socket_address:1"); + *sp = const0u; + return; + } +#ifdef IPV6 + char tmp2[INET6_ADDRSTRLEN]; + tmp = inet_ntop(AF_INET6, &sp->u.ob->interactive->addr.sin6_addr, tmp2, INET6_ADDRSTRLEN); + sprintf(buf, "%s %d", tmp, ntohs(sp->u.ob->interactive->addr.sin6_port)); +#else + tmp = inet_ntoa(sp->u.ob->interactive->addr.sin_addr); + sprintf(buf, "%s %d", tmp, + ntohs(sp->u.ob->interactive->addr.sin_port)); +#endif + str = string_copy(buf, "f_socket_address"); + free_object(&sp->u.ob, "f_socket_address:2"); + put_malloced_string(str); + return; + } + get_socket_address(sp->u.number, addr, &port, local); + sprintf(buf, "%s %d", addr, port); + str = string_copy(buf, "f_socket_address"); + put_malloced_string(str); +} /* f_socket_address() */ +#endif + +#ifdef F_SOCKET_STATUS +void +f_socket_status (void) +{ + array_t *info; + int i; + + if (st_num_arg) { + info = socket_status(sp->u.number); + + if (!info) { + sp->u.number = 0; + } else { + sp->type = T_ARRAY; + sp->u.arr = info; + } + } else { + info = allocate_empty_array(max_lpc_socks); + for (i = 0; i < max_lpc_socks; i++) { + info->item[i].type = T_ARRAY; + info->item[i].u.arr = socket_status(i); + } + push_refed_array(info); + } +} +#endif diff --git a/fluffos-2.23-ds03/packages/sockets_spec.c b/fluffos-2.23-ds03/packages/sockets_spec.c new file mode 100644 index 0000000..9760bf9 --- /dev/null +++ b/fluffos-2.23-ds03/packages/sockets_spec.c @@ -0,0 +1,26 @@ +#include "spec.h" + +/* + * socket efuns + */ + int socket_create(int, string | function, string | function | void); + int socket_bind(int, int, string | void); + int socket_listen(int, string | function); + int socket_accept(int, string | function, string | function); + int socket_connect(int, string, string | function, string | function); + int socket_write(int, mixed, string | void); + int socket_close(int); + int socket_release(int, object, string | function); + int socket_acquire(int, string | function, string | function, string | function); + string socket_error(int); + string socket_address(int | object, int default: 0); + + /* + * ret[0] = (int) fd + * ret[1] = (string) state + * ret[2] = (string) mode + * ret[3] = (string) local address + * ret[4] = (string) remote address + * ret[5] = (object) owner + */ + mixed *socket_status(void | int); diff --git a/fluffos-2.23-ds03/packages/uids.c b/fluffos-2.23-ds03/packages/uids.c new file mode 100644 index 0000000..7f31f2a --- /dev/null +++ b/fluffos-2.23-ds03/packages/uids.c @@ -0,0 +1,189 @@ +/* + * uid.c + * + * Created by: Erik Kay + * Description: new uid / euid data structures and security + * Modification: + * 11-1-92 - Erik Kay - initial creation + * 94.07.14 - Robocoder - replaced linked list with AVL tree, and + * made uids into shared strings + */ +#ifdef LATTICE +#include "/lpc_incl.h" +#include "/eoperators.h" +#include "/avltree.h" +#include "/md.h" +#include "/uids.h" +#include "/master.h" +#else +#include "../lpc_incl.h" +#include "../eoperators.h" +#include "../avltree.h" +#include "../md.h" +#include "uids.h" +#include "../master.h" +#include "../efun_protos.h" +#endif + +static object_t *ob; + +#ifdef F_EXPORT_UID +void +f_export_uid (void) +{ + if (current_object->euid == NULL) + error("Illegal to export uid 0\n"); + ob = sp->u.ob; + if (ob->euid) { + free_object(&ob, "f_export_uid:1"); + *sp = const0; + } + else { + ob->uid = current_object->euid; + free_object(&ob, "f_export_uid:2"); + *sp = const1; + } +} +#endif + +#ifdef F_GETEUID +void +f_geteuid (void) +{ + if (sp->type & T_OBJECT) { + ob = sp->u.ob; + if (ob->euid) { + put_constant_string(ob->euid->name); + free_object(&ob, "f_geteuid:1"); + return; + } else { + free_object(&ob, "f_geteuid:2"); + *sp = const0; + return; + } + } else if (sp->type & T_FUNCTION) { + funptr_t *fp; + if ((fp = sp->u.fp)->hdr.owner && fp->hdr.owner->euid) { + put_constant_string(fp->hdr.owner->euid->name); + free_funp(fp); + return; + } + free_funp(fp); + *sp = const0; + } +} +#endif + +#ifdef F_GETUID +void +f_getuid (void) +{ + ob = sp->u.ob; + + DEBUG_CHECK(ob->uid == NULL, "UID is a null pointer\n"); + put_constant_string(ob->uid->name); + free_object(&ob, "f_getuid"); +} +#endif + +#ifdef F_SETEUID +void +f_seteuid (void) +{ + svalue_t *arg; + svalue_t *ret; + + if (sp->type & T_NUMBER) { + if (sp->u.number) + bad_arg(1, F_SETEUID); + current_object->euid = NULL; + sp->u.number = 1; + return; + } + arg = sp; + push_object(current_object); + push_svalue(arg); + ret = apply_master_ob(APPLY_VALID_SETEUID, 2); + if (!MASTER_APPROVED(ret)) { + free_string_svalue(sp); + *sp = const0; + return; + } + current_object->euid = add_uid(sp->u.string); + free_string_svalue(sp); + *sp = const1; +} +#endif + +/* Support functions */ +static tree *uids = NULL; +userid_t *backbone_uid = NULL; +userid_t *root_uid = NULL; + +#ifdef DEBUGMALLOC_EXTENSIONS +static void mark_uid_tree (tree * tr) { + DO_MARK(tr, TAG_UID); + DO_MARK(tr->tree_p, TAG_UID); + + EXTRA_REF(BLOCK(((userid_t *)tr->tree_p)->name))++; + if (tr->tree_l) + mark_uid_tree(tr->tree_l); + if (tr->tree_r) + mark_uid_tree(tr->tree_r); +} + +void mark_all_uid_nodes() { + if (uids) + mark_uid_tree(uids); +} +#endif + +static int uidcmp (void *, void *); + +static int uidcmp (void *uid1, void *uid2) +{ + register char *name1, *name2; + + name1 = ((userid_t *)uid1)->name; + name2 = ((userid_t *)uid2)->name; + return (name1 < name2 ? -1 : (name1 > name2 ? 1 : 0)); +} + +userid_t *add_uid (const char * name) +{ + userid_t *uid, t_uid; + char *sname; + + sname = make_shared_string(name); + t_uid.name = sname; + if ((uid = (userid_t *) tree_srch(uids, uidcmp, (char *) &t_uid))) { + free_string(sname); + } else { + uid = ALLOCATE(userid_t, TAG_UID, "add_uid"); + uid->name = sname; + tree_add(&uids, uidcmp, (char *) uid, NULL); + } + return uid; +} + +userid_t *set_root_uid (const char * name) +{ + if (!root_uid) + return root_uid = add_uid(name); + + tree_delete(&uids, uidcmp, (char *) root_uid, NULL); + root_uid->name = make_shared_string(name); + tree_add(&uids, uidcmp, (char *) root_uid, NULL); + return root_uid; +} + +userid_t *set_backbone_uid (const char * name) +{ + if (!backbone_uid) + return backbone_uid = add_uid(name); + + tree_delete(&uids, uidcmp, (char *) backbone_uid, NULL); + backbone_uid->name = make_shared_string(name); + tree_add(&uids, uidcmp, (char *) backbone_uid, NULL); + return backbone_uid; +} diff --git a/fluffos-2.23-ds03/packages/uids.h b/fluffos-2.23-ds03/packages/uids.h new file mode 100644 index 0000000..c4ff196 --- /dev/null +++ b/fluffos-2.23-ds03/packages/uids.h @@ -0,0 +1,29 @@ +/* + * uid.h + * Created by: Erik Kay + * Description: new uid / euid data structures and security + * Modification: + * 11-1-92 - Erik Kay - initial creation + * 94.07.09 - Robocoder - modified to use AVL tree + */ + +#if !defined(_UID_H_) && defined(PACKAGE_UIDS) +#define _UID_H_ + +#include "../std.h" + +typedef struct _uid { + char *name; +} userid_t; + +extern userid_t *backbone_uid; +extern userid_t *root_uid; + +userid_t *add_uid (const char *name); +userid_t *set_root_uid (const char *name); +userid_t *set_backbone_uid (const char *name); +#ifdef DEBUGMALLOC_EXTENSIONS +void mark_all_uid_nodes (void); +#endif + +#endif diff --git a/fluffos-2.23-ds03/packages/uids_spec.c b/fluffos-2.23-ds03/packages/uids_spec.c new file mode 100644 index 0000000..cae560e --- /dev/null +++ b/fluffos-2.23-ds03/packages/uids_spec.c @@ -0,0 +1,6 @@ +#include "spec.h" + +int export_uid(object); +string geteuid(function | object default:F__THIS_OBJECT); +string getuid(object default:F__THIS_OBJECT); +int seteuid(string | int); diff --git a/fluffos-2.23-ds03/parse.c b/fluffos-2.23-ds03/parse.c new file mode 100644 index 0000000..0f59790 --- /dev/null +++ b/fluffos-2.23-ds03/parse.c @@ -0,0 +1,1583 @@ +/* + + Pattern Parser package for LPmud + + Ver 3.1 + + If you have questions or complaints about this code please refer them + to jna@cd.chalmers.se + +*/ + +#include "std.h" +#include "parse.h" +#include "master.h" +#include "add_action.h" + +/***************************************************** + + This is the parser used by the efun parse_command + +*/ +/* + + General documentation: + + parse_command() is one of the most complex efun in LPmud to use. It takes + some effort to learn and use, but when mastered, very powerful constructs + can be implemented. + + Basically parse_command() is a hotted sscanf operating on word basis. It + works similar to sscanf in that it takes a pattern and a variable set of + destination arguments. It is together with sscanf the only efun to use + pass by reference for other variables than arrays. + + *** NOTE: Effective June 22, 1994 ... parse_command() and sscanf() + no longer receive an lvalue list before being called. + The destination arguments are simply placed (in reverse + order) into a preallocated stack frame; upon return the + driver will perform the necessary assignments and clean + up the stack. + + 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 singular list. For + grammatical reasons it does not always succeed in a perfect way. This is + especially true when the 'names' are not single words but phrases. + + The third is very nice to have because it makes constructs like + 'get all the little blue ones' possible. + + Apart from these functions that should exist in all objects, and which + are therefore best put in /std/object.c there is also a set of functions + needed in /secure/master.c These are not absolutely necessary but they + give extra power to the efun. + + Basically these /secure/master.c 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 lfun's 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 + 'all' word. + + string *parse_command_prepos_list() + - Would normally return: ({ "in", "on", "under" }) + + string parse_command_all_word() + - Would normally return: "all" + + IF you want to use a different language than English but still want the + default pluralform maker to work, you need to replace parse.c with the + following file: + +#if 0 + * Language configured parse.c + * + #define PARSE_FOREIGN + + char *parse_to_plural(str) + char *str; + { + + * Your own plural converter for your language * + + } + + * The numberwords below should be replaced for the new language * + + static char *ord1[] = {"", "first", "second", "third", "fourth", "fifth", + "sixth", "seventh", "eighth", "ninth", "tenth", + "eleventh", "twelfth", "thirteenth", "fourteenth", + "fifteenth", "sixteenth", "seventeenth", + "eighteenth","nineteenth"}; + + static char *ord10[] = {"", "", "twenty","thirty","forty","fifty","sixty", + "seventy", "eighty","ninety"}; + + static char *sord10[] = {"", "", "twentieth", "thirtieth", "fortieth", + "fiftieth", "sixtieth","seventieth", "eightieth", + "ninetieth"}; + + static char *num1[] = {"", "one","two","three","four","five","six", + "seven","eight","nine","ten", + "eleven","twelve","thirteen","fourteen","fifteen", + "sixteen", "seventeen","eighteen","nineteen"}; + + static char *num10[] = {"", "", "twenty","thirty","forty","fifty","sixty", + "seventy", "eighty","ninety"}; + + #include "parse_english.c" * This parse.c file * + +#endif + + When all these things are defined parse_command() works best and most + efficient. What follows is the docs for how to use it from LPC: + + + Doc for LPC function + +int parse_command(string, object/object*, string, destargs...) + + Returns 1 if pattern matches + + string Given command + + object* if arr + object array holding the accessible objects + if ob + object from which to recurse and create + the list of accessible objects, normally + ob = environment(this_player()) + string Parsepattern as list of words and formats: + 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) + + destargs This is the list of result variables as in sscanf + One variable is needed for each %_ + The return types of different %_ is: + %o Returns an object + %s Returns a string of words + %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 identical 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', + 'all nasty bugs' or 'second blue sword' the number indicates which + 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. + +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. + + } + + BUGS / Features +: + + Patterns of type: "%s %w %i" + Might not work as one would expect. %w will always succeed so the arg + corresponding to %s will always be empty. + + 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 pattern element can + therefore not contain spaces. + +*/ + +/* Some useful string macros +*/ +#define EQ(x,y) (strcmp(x,y)==0) +#define EQN(x,y) (strncmp(x,y,strlen(x))==0) +#define EMPTY(x) (strcmp(x,"")==0) + +/* Global arrays for 'caching' of ids + + The main 'parse' routine stores these on call, making the entire + parse_command() reentrant. +*/ +typedef struct parse_global_s { + struct parse_global_s *next; + + array_t *Id_list; + array_t *Pluid_list; + array_t *Adjid_list; + array_t *Id_list_d; /* From master */ + array_t *Pluid_list_d; /* From master */ + array_t *Adjid_list_d; /* From master */ + array_t *Prepos_list; /* From master */ + char *Allword; /* From master */ + + array_t *warr; + array_t *patarr; + array_t *obarr; +} parse_global_t; + +static parse_global_t *globals = 0; + +#define gId_list (globals->Id_list) +#define gPluid_list (globals->Pluid_list) +#define gAdjid_list (globals->Adjid_list) +#define gId_list_d (globals->Id_list_d) +#define gPluid_list_d (globals->Pluid_list_d) +#define gAdjid_list_d (globals->Adjid_list_d) +#define gPrepos_list (globals->Prepos_list) +#define gAllword (globals->Allword) +#define parse_warr (globals->warr) +#define parse_patarr (globals->patarr) +#define parse_obarr (globals->obarr) + +static void load_lpc_info (int, object_t *); +static void parse_clean_up (void); +static void push_parse_globals (void); +static void pop_parse_globals (void); +static void store_value (svalue_t *, int, int, svalue_t *); +static void store_words_slice (svalue_t *, int, int, + array_t *, int, int); +static svalue_t *sub_parse (array_t *, array_t *, int *, + array_t *, int *, int *, svalue_t *); +static svalue_t *one_parse (array_t *, const char *, array_t *, + int *, int *, svalue_t *); +static svalue_t *number_parse (array_t *, array_t *, int *, int *); +static svalue_t *item_parse (array_t *, array_t *, int *, int *); +#ifndef NO_ADD_ACTION +static svalue_t *living_parse (array_t *, array_t *, int *, int *); +#endif +static svalue_t *single_parse (array_t *, array_t *, int *, int *); +static svalue_t *prepos_parse (array_t *, int *, int *, svalue_t *); +static int match_object (int, array_t *, int *, int *); +static int find_string (const char *, array_t *, int *); +static int check_adjectiv (int, array_t *, int, int); +static int member_string (const char *, array_t *); +static const char *parse_to_plural (const char *); +static const char *parse_one_plural (const char *); + +/* + * Function name: load_lpc_info + * Description: Loads relevant information from a given object. + * This is the ids, plural ids and adjectiv ids. This + * is the only calls to LPC objects other than the + * master object that occur within the efun + * parse_command(). + * Arguments: ix: Index in the array + * ob: The object to call for information. + */ +static void +load_lpc_info (int ix, object_t * ob) +{ + array_t *tmp, *sing; + svalue_t *ret; + int il, make_plural = 0; + const char *str; + + if (!ob || ob->flags & O_DESTRUCTED) + return; + + if (gPluid_list && + gPluid_list->size > ix && + gPluid_list->item[ix].type == T_NUMBER && + gPluid_list->item[ix].u.number == 0) { + ret = apply(APPLY_QGET_PLURID, ob, 0, ORIGIN_DRIVER); + if (ret && ret->type == T_ARRAY) + assign_svalue_no_free(&gPluid_list->item[ix], ret); + else { + make_plural = 1; + gPluid_list->item[ix].u.number = 1; + } + } + if (gId_list && + gId_list->size > ix && + gId_list->item[ix].type == T_NUMBER && + gId_list->item[ix].u.number == 0 && + !(ob->flags & O_DESTRUCTED) ) { + ret = apply(APPLY_QGET_ID, ob, 0, ORIGIN_DRIVER); + if (ret && ret->type == T_ARRAY) { + assign_svalue_no_free(&gId_list->item[ix], ret); + if (make_plural) { + tmp = allocate_array(ret->u.arr->size); + sing = ret->u.arr; + + for (il = 0; il < tmp->size; il++) { + if (sing->item[il].type == T_STRING) { + str = parse_to_plural(sing->item[il].u.string); + tmp->item[il].type = T_STRING; + tmp->item[il].subtype = STRING_MALLOC; + tmp->item[il].u.string = str; + } + } + gPluid_list->item[ix].type = T_ARRAY; + gPluid_list->item[ix].u.arr = tmp; + } + } else { + gId_list->item[ix].u.number = 1; + } + } + if (gAdjid_list && + gAdjid_list->size > ix && + gAdjid_list->item[ix].type == T_NUMBER && + gAdjid_list->item[ix].u.number == 0 && + !(ob->flags & O_DESTRUCTED)) { + ret = apply(APPLY_QGET_ADJID, ob, 0, ORIGIN_DRIVER); + if (ret && ret->type == T_ARRAY) + assign_svalue_no_free(&gAdjid_list->item[ix], ret); + else + gAdjid_list->item[ix].u.number = 1; + } +} + +/* Main function, called from interpret.c (or eoperators.c) +*/ + +/* Some leak prevention: */ +static void parse_clean_up() { + parse_global_t *pg; + + pg = globals; + globals = pg->next; + + if (pg->Id_list) + free_array(pg->Id_list); + if (pg->Pluid_list) + free_array(pg->Pluid_list); + if (pg->Adjid_list) + free_array(pg->Adjid_list); + if (pg->Id_list_d) + free_array(pg->Id_list_d); + if (pg->Pluid_list_d) + free_array(pg->Pluid_list_d); + if (pg->Adjid_list_d) + free_array(pg->Adjid_list_d); + if (pg->Prepos_list) + free_array(pg->Prepos_list); + if (pg->Allword) + FREE(pg->Allword); + if (pg->warr) + free_array(pg->warr); + if (pg->patarr) + free_array(pg->patarr); + if (pg->obarr) + free_array(pg->obarr); + FREE(pg); +} + +static void push_parse_globals() { + parse_global_t *pg; + + STACK_INC; + sp->type = T_ERROR_HANDLER; + sp->u.error_handler = parse_clean_up; + + pg = ALLOCATE(parse_global_t, TAG_TEMPORARY, "push_parse_globals"); + pg->next = globals; + globals = pg; + + pg->Id_list = 0; + pg->Pluid_list = 0; + pg->Adjid_list = 0; + pg->Id_list_d = 0; + pg->Pluid_list_d = 0; + pg->Adjid_list_d = 0; + pg->Prepos_list = 0; + pg->Allword = 0; + pg->warr = 0; + pg->patarr = 0; + pg->obarr = 0; +} + +static void pop_parse_globals() { + sp--; /* remove error handler */ + parse_clean_up(); +} + +/* all the routines below return a pointer to this which should be copied + immediately ... */ +static svalue_t parse_ret; + +/* + * Function name: parse + * Description: The main function for the efun: parse_command() + * It parses a given command using a given pattern and + * a set of objects (see args below). For details + * see LPC documentation of the efun. + * Arguments: cmd: The command to parse + * ob_or_array: A list of objects or one object from + * which to make a list of objects by + * using the objects deep_inventory + * pattern: The given parse pattern somewhat like sscanf + * but with different %-codes, see efun docs. + * stack_args: Pointer to destination arguments. + * num_arg: Number of destination arguments. + * Returns: True if command matched pattern. + */ +int +parse (const char * cmd, /* Command to parse */ + svalue_t * ob_or_array, /* Object or array of objects */ + const char * pattern, /* Special parsing pattern */ + svalue_t * stack_args, /* Pointer to lvalue args on + * stack */ + int num_arg) +{ + int pix, cix, six, fail, fword, ocix, fpix; + svalue_t *pval; + array_t *obarr; + + /* + * Pattern and commands can not be empty + */ + if (!*cmd || !*pattern) + return 0; + + push_parse_globals(); + + /* Array of words in command */ + parse_warr = explode_string(cmd, strlen(cmd), " ", 1); + + /* Array of pattern elements */ + parse_patarr = explode_string(pattern, strlen(pattern), " ", 1); + + /* + * Explode can return '0'. + */ + if (!parse_warr) + parse_warr = allocate_array(0); + if (!parse_patarr) + parse_patarr = allocate_array(0); + + /* note: obarr is only put in parse_obarr if it needs freeing */ + if (ob_or_array->type == T_ARRAY) + obarr = ob_or_array->u.arr; +#ifndef NO_ENVIRONMENT + else if (ob_or_array->type == T_OBJECT) { + /* 1 == ob + deepinv */ + parse_obarr = obarr = deep_inventory(ob_or_array->u.ob, 1, NULL); + } +#endif + else + error("Bad second argument to parse_command()\n"); + + check_for_destr(obarr); + + gId_list = allocate_array(obarr->size); + gPluid_list = allocate_array(obarr->size); + gAdjid_list = allocate_array(obarr->size); + + /* + * Get the default ids of 'general references' from master object + */ + pval = apply(APPLY_QGET_ID, master_ob, 0, ORIGIN_DRIVER); + if (pval && pval->type == T_ARRAY) { + gId_list_d = pval->u.arr; + pval->u.arr->ref++; /* Otherwise next sapply will free it */ + } + + pval = apply(APPLY_QGET_PLURID, master_ob, 0, ORIGIN_DRIVER); + if (pval && pval->type == T_ARRAY) { + gPluid_list_d = pval->u.arr; + pval->u.arr->ref++; /* Otherwise next sapply will free it */ + } + + pval = apply(APPLY_QGET_ADJID, master_ob, 0, ORIGIN_DRIVER); + if (pval && pval->type == T_ARRAY) { + gAdjid_list_d = pval->u.arr; + pval->u.arr->ref++; /* Otherwise next sapply will free it */ + } + + pval = apply_master_ob(APPLY_QGET_PREPOS, 0); + if (pval && pval->type == T_ARRAY) { + gPrepos_list = pval->u.arr; + pval->u.arr->ref++; /* Otherwise next sapply will free it */ + } + + pval = apply_master_ob(APPLY_QGET_ALLWORD, 0); + if (pval && pval->type == T_STRING) + gAllword = alloc_cstring(pval->u.string, "parse"); + + /* + * Loop through the pattern. Handle %s but not '/' + */ + for (six = 0, cix = 0, pix = 0; pix < parse_patarr->size; pix++) { + pval = 0; /* The 'fill-in' value */ + fail = 0; /* 1 if match failed */ + + if (EQ(parse_patarr->item[pix].u.string, "%s")) { + /* + * We are at end of pattern, scrap up the remaining words and put + * them in the fill-in value. + */ + if (pix == (parse_patarr->size - 1)) { + store_words_slice(stack_args, six++, num_arg, + parse_warr, cix, parse_warr->size - 1); + cix = parse_warr->size; + } else + /* + * There is something after %s, try to parse with the next + * pattern. Begin with the current word and step one word for + * each fail, until match or end of words. + */ + { + ocix = fword = cix; /* Current word */ + fpix = ++pix; /* pix == next pattern */ + do { + fail = 0; + /* + * Parse the following pattern, fill-in values: + * stack_args[six] = result of %s stack_args[six + 1] = + * result of following pattern, if it is a fill-in + * pattern + */ + pval = sub_parse(obarr, parse_patarr, &pix, + parse_warr, &cix, + &fail, ((six + 1) < num_arg) ? + &stack_args[six + 1] : 0); + if (fail) { + cix = ++ocix; + pix = fpix; + } + } while (fail && (cix < parse_warr->size)); + + /* + * We found something mathing the pattern after %s. First + * stack_args[six + 1] = result of match Then stack_args[six] + * = the skipped words before match + */ + if (!fail) { + if (pval) { /* A match with a value fill in param */ + store_value(stack_args, six + 1, num_arg, pval); + store_words_slice(stack_args, six, num_arg, + parse_warr, fword, ocix - 1); + six += 2; + } else { /* A match with a non value ie 'word' */ + store_words_slice(stack_args, six++, num_arg, + parse_warr, fword, ocix - 1); + } + pval = 0; + } + } + } + /* + * The pattern was not %s, parse the pattern if it is not '/', a '/' + * here is skipped. If match, put in fill-in value. + */ + else if (!EQ(parse_patarr->item[pix].u.string, "/")) { + pval = sub_parse(obarr, parse_patarr, &pix, + parse_warr, &cix, &fail, + (six < num_arg) ? &stack_args[six] : 0); + if (!fail && pval) + store_value(stack_args, six++, num_arg, pval); + } + /* + * Terminate parsing if no match + */ + if (fail) + break; + } + + /* + * Also fail when there is words left to parse and pattern exhausted + */ + if (cix < parse_warr->size) + fail = 1; + + pop_parse_globals(); + + return !fail; +} + +static void +store_value (svalue_t * sp, int pos, int num, svalue_t * what) +{ + svalue_t *ret; + + if (pos >= num) { + free_svalue(what, "store_value"); + } else { + ret = sp + num - pos - 1; + free_svalue(ret, "store_value"); /* is this necessary? */ + *ret = *what; + } +} + +/* + * Function name: slice_words + * Description: Gives an imploded string of words from an array + * Arguments: warr: array of words + * from: First word to use + * to: Last word to use + * Returns: A pointer to a static svalue now containing string. + */ +static void +store_words_slice (svalue_t * sp, int pos, int num, array_t * warr, int from, int to) +{ + svalue_t *ret; + array_t *slice; + + if (pos >= num) + return; + + ret = sp + num - pos -1; + ret->type = T_STRING; + + if (from <= to) { + warr->ref++; + slice = slice_array(warr, from, to); + + if (slice->size) { + ret->subtype = STRING_MALLOC; + ret->u.string = implode_string(slice, " ", 1); + free_array(slice); + return; + } + free_array(slice); + } + + ret->subtype = STRING_CONSTANT; + ret->u.string = ""; +} + +/* + * Function name: sub_parse + * Description: Parses a array of words against a pattern. Gives + * result as an svalue. Sets fail if parsing fails and + * updates pointers in pattern and word arrays. It + * handles alternate patterns but not "%s" + */ +static svalue_t * + sub_parse (array_t * obarr, array_t * patarr, int * pix_in, array_t * warr, int * cix_in, int * fail, svalue_t * sp) +{ + int cix, pix, subfail; + svalue_t *pval; + + /* + * Fail if we have a pattern left but no words to parse + */ + if (*cix_in == warr->size) { + *fail = 1; + return 0; + } + cix = *cix_in; + pix = *pix_in; + subfail = 0; + + pval = one_parse(obarr, patarr->item[pix].u.string, + warr, &cix, &subfail, sp); + + while (subfail) { + pix++; + cix = *cix_in; + + /* + * Find the next alternative pattern, consecutive '/' are skipped + */ + while ((pix < patarr->size) && (EQ(patarr->item[pix].u.string, "/"))) { + subfail = 0; + pix++; + } + + if (!subfail && (pix < patarr->size)) { + pval = one_parse(obarr, patarr->item[pix].u.string, warr, &cix, + &subfail, sp); + } else { + *fail = 1; + *pix_in = pix - 1; + return 0; + } + } + + /* + * If there is alternatives left after the mathing pattern, skip them + */ + if ((pix + 1 < patarr->size) && (EQ(patarr->item[pix + 1].u.string, "/"))) { + while ((pix + 1 < patarr->size) && + (EQ(patarr->item[pix + 1].u.string, "/"))) { + pix += 2; + } + if (pix >= patarr->size) + pix = patarr->size - 1; + } + *cix_in = cix; + *pix_in = pix; + *fail = 0; + return pval; +} + +/* + * Function name: one_parse + * Description: Checks one parse pattern to see if match. Consumes + * needed number of words from warr. + * Arguments: obarr: Vector of objects relevant to parse + * pat: The pattern to match against. + * warr: Vector of words in the command to parse + * cix_in: Current word in commandword array + * fail: Fail flag if parse did not match + * prep_param: Only used on %p (see prepos_parse) + * Returns: svalue holding result of parse. + */ +static svalue_t * +one_parse (array_t * obarr, const char * pat, array_t * warr, int * cix_in, int * fail, svalue_t * prep_param) +{ + char ch; + svalue_t *pval; + const char *str1, *str2; + + /* + * Fail if we have a pattern left but no words to parse + */ + if (*cix_in >= warr->size) { + *fail = 1; + return 0; + } + ch = pat[0]; + if (ch == '%') { + ch = ((uisupper(pat[1])) ? tolower(pat[1]) : pat[1]); + } + pval = 0; + + switch (ch) { + case 'i': + pval = item_parse(obarr, warr, cix_in, fail); + break; + +#ifndef NO_ADD_ACTION + case 'l': + pval = living_parse(obarr, warr, cix_in, fail); + break; +#endif + + case 's': + *fail = 0; /* This is double %s in pattern, skip it */ + break; + + case 'w': + parse_ret.type = T_STRING; + parse_ret.subtype = STRING_SHARED; + parse_ret.u.string = make_shared_string(warr->item[*cix_in].u.string); + pval = &parse_ret; + (*cix_in)++; + *fail = 0; + break; + + case 'o': + pval = single_parse(obarr, warr, cix_in, fail); + break; + + case 'p': + pval = prepos_parse(warr, cix_in, fail, prep_param); + break; + + case 'd': + pval = number_parse(obarr, warr, cix_in, fail); + break; + + case '\'': + str1 = &pat[1]; + str2 = warr->item[*cix_in].u.string; + if ((strncmp(str1, str2, strlen(str1) - 1) == 0) && + (strlen(str1) == strlen(str2) + 1)) { + *fail = 0; + (*cix_in)++; + } else + *fail = 1; + break; + + case '[': + str1 = &pat[1]; + str2 = warr->item[*cix_in].u.string; + if ((strncmp(str1, str2, strlen(str1) - 1) == 0) && + (strlen(str1) == strlen(str2) + 1)) { + (*cix_in)++; + } + *fail = 0; + break; + + default: + *fail = 0; /* Skip invalid patterns */ + } + return pval; +} + +/* + We normally define these, see initial documentation (top of file) +*/ +#ifndef PARSE_FOREIGN + +static const char *ord1[] = +{"", "first", "second", "third", "fourth", "fifth", + "sixth", "seventh", "eighth", "ninth", "tenth", + "eleventh", "twelfth", "thirteenth", "fourteenth", + "fifteenth", "sixteenth", "seventeenth", + "eighteenth", "nineteenth"}; + +static const char *ord10[] = +{"", "", "twenty", "thirty", "forty", "fifty", "sixty", + "seventy", "eighty", "ninety"}; + +static const char *sord10[] = +{"", "", "twentieth", "thirtieth", "fortieth", + "fiftieth", "sixtieth", "seventieth", "eightieth", + "ninetieth"}; + +static const char *num1[] = +{"", "one", "two", "three", "four", "five", "six", + "seven", "eight", "nine", "ten", + "eleven", "twelve", "thirteen", "fourteen", "fifteen", + "sixteen", "seventeen", "eighteen", "nineteen"}; + +static const char *num10[] = +{"", "", "twenty", "thirty", "forty", "fifty", "sixty", + "seventy", "eighty", "ninety"}; + +#endif + +/* + * Function name: number_parse + * Description: Tries to interpret the word in wvec as a numeral + * descriptor and returns the result on the form: + * ret.type == T_NUMBER + * num == 0, 'zero', '0', gAllword + * num > 0, one, two, three etc or numbers given + * num < 0, first, second,third etc given + * Arguments: obarr: Vector of objects relevant to parse + * warr: Vector of words in the command to parse + * cix_in: Current word in commandword array + * fail: Fail flag if parse did not match + * Returns: svalue holding result of parse. + */ +static svalue_t * +number_parse (array_t * obarr, array_t * warr, int * cix_in, int * fail) +{ + int cix, ten, ones, num; + char buf[100]; + + cix = *cix_in; + *fail = 0; + + if (sscanf(warr->item[cix].u.string, "%d", &num)) { + if (num >= 0) { + (*cix_in)++; + parse_ret.type = T_NUMBER; + parse_ret.u.number = num; + return &parse_ret; + } + *fail = 1; + return 0; /* Only nonnegative numbers */ + } + if (gAllword && (strcmp(warr->item[cix].u.string, gAllword) == 0)) { + (*cix_in)++; + parse_ret.type = T_NUMBER; + parse_ret.u.number = 0; + return &parse_ret; + } + /* This next double loop is incredibly stupid. -Beek */ + for (ten = 0; ten < 10; ten++) + for (ones = 0; ones < 10; ones++) { + sprintf(buf, "%s%s", num10[ten], + (ten > 1) ? num1[ones] : num1[ten * 10 + ones]); + if (EQ(buf, warr->item[cix].u.string)) { + (*cix_in)++; + parse_ret.type = T_NUMBER; + parse_ret.u.number = ten * 10 + ones; + return &parse_ret; + } + } + + /* this one too */ + for (ten = 0; ten < 10; ten++) + for (ones = 0; ones < 10; ones++) { + sprintf(buf, "%s%s", (ones) ? ord10[ten] : sord10[ten], + (ten > 1) ? ord1[ones] : ord1[ten * 10 + ones]); + if (EQ(buf, warr->item[cix].u.string)) { + (*cix_in)++; + parse_ret.type = T_NUMBER; + parse_ret.u.number = -(ten * 10 + ones); + return &parse_ret; + } + } + + *fail = 1; + return 0; +} + +/* + * Function name: item_parse + * Description: Tries to match as many objects in obvec as possible + * onto the description given in commandarray warr. + * Also finds numeral description if one exist and returns + * that as first element in array: + * ret[0].type == T_NUMBER + * num == 0, 'all' or 'general plural given' + * num > 0, one, two, three etc given + * num < 0, first, second,third etc given + * ret[1-n] == Selected objectpointers from obarr + * Arguments: obarr: Vector of objects relevant to parse + * warr: Vector of words in the command to parse + * cix_in: Current word in commandword array + * fail: Fail flag if parse did not match + * Returns: svalue holding result of parse. + */ +static svalue_t * + item_parse (array_t * obarr, array_t * warr, int * cix_in, int * fail) +{ + array_t *tmp, *ret; + svalue_t *pval; + int cix, tix, obix, plur_flag, max_cix, match_all; + + tmp = allocate_array(obarr->size + 1); + /* in case of errors */ + push_refed_array(tmp); + + if ((pval = number_parse(obarr, warr, cix_in, fail))) + tmp->item[0] = *pval; + + if (pval) { + match_all = (pval->u.number == 0); + plur_flag = (match_all || pval->u.number > 1); + } else { + plur_flag = 0; + match_all = 0; + } + + for (max_cix = *cix_in, tix = 1, obix = 0; obix < obarr->size; obix++) { + *fail = 0; + cix = *cix_in; + if (obarr->item[obix].type != T_OBJECT) + continue; + if (cix == warr->size && match_all) { + assign_svalue_no_free(&tmp->item[tix++], &obarr->item[obix]); + continue; + } + load_lpc_info(obix, obarr->item[obix].u.ob); + + if (match_object(obix, warr, &cix, &plur_flag)) { + assign_svalue_no_free(&tmp->item[tix++], &obarr->item[obix]); + max_cix = (max_cix < cix) ? cix : max_cix; + } + } + sp--; /* remove the copy. No errors occured */ + + if (tix < 2) { + *fail = 1; + free_array(tmp); + if (pval) + (*cix_in)--; + return 0; + } else { + if (*cix_in < warr->size) + *cix_in = max_cix + 1; + if (!pval) { + tmp->item[0].type = T_NUMBER; + tmp->item[0].u.number = plur_flag ? 0 : 1; + } + ret = slice_array(tmp, 0, tix - 1); + } + + parse_ret.type = T_ARRAY; + parse_ret.u.arr = ret; + return &parse_ret; +} + +/* + * Function name: living_parse + * Description: Tries to match as many living objects in obvec as + * possible onto the description given in the command- + * array warr. + * Also finds numeral description if one exist and returns + * that as first element in array: + * ret[0].type == T_NUMBER + * num == 0, 'all' or 'general plural given' + * num > 0, one, two, three etc given + * num < 0, first, second,third etc given + * ret[1-n] == Selected objectpointers from obarr + * If not found in obarr a find_player and + * lastly a find_living is done. These will return an + * objecttype svalue. + * Arguments: obarr: Vector of objects relevant to parse + * warr: Vector of words in the command to parse + * cix_in: Current word in commandword array + * fail: Fail flag if parse did not match + * Returns: svalue holding result of parse. + */ +#ifndef NO_ADD_ACTION +static svalue_t * + living_parse (array_t * obarr, array_t * warr, int * cix_in, int * fail) +{ + array_t *live; + svalue_t *pval; + object_t *ob; + int obix, tix; + + live = allocate_array(obarr->size); + /* in case of errors */ + push_refed_array(live); + tix = 0; + *fail = 0; + + for (obix = 0; obix < obarr->size; obix++) + if (obarr->item[obix].u.ob->flags & O_ENABLE_COMMANDS) + assign_svalue_no_free(&live->item[tix++], &obarr->item[obix]); + + if (tix) { + pval = item_parse(live, warr, cix_in, fail); + if (pval) { + sp--; + free_array(live); + return pval; + } + } + sp--; + free_array(live); + + /* + * find_player + */ + ob = find_living_object(warr->item[*cix_in].u.string, 1); + if (!ob) + /* + * find_living + */ + ob = find_living_object(warr->item[*cix_in].u.string, 0); + + if (ob) { + parse_ret.type = T_OBJECT; + parse_ret.u.ob = ob; + add_ref(ob, "living_parse"); + (*cix_in)++; + return &parse_ret; + } + *fail = 1; + return 0; +} +#endif + +/* + * Function name: single_parse + * Description: Finds the first object in obvec fitting the description + * in commandarray warr. Gives this as an objectpointer. + * Arguments: obarr: Vector of objects relevant to parse + * warr: Vector of words in the command to parse + * cix_in: Current word in commandword array + * fail: Fail flag if parse did not match + * Returns: svalue holding result of parse. + */ +static svalue_t * + single_parse (array_t * obarr, array_t * warr, int * cix_in, int * fail) +{ + int cix, obix, plur_flag; + + for (obix = 0; obix < obarr->size; obix++) { + *fail = 0; + cix = *cix_in; + if (obarr->item[obix].type == T_OBJECT) + load_lpc_info(obix, obarr->item[obix].u.ob); + plur_flag = 0; + if (match_object(obix, warr, &cix, &plur_flag)) { + *cix_in = cix + 1; + assign_svalue_no_free(&parse_ret, &obarr->item[obix]); + return &parse_ret; + } + } + *fail = 1; + return 0; +} + +/* + * Function name: prepos_parse + * Description: This is a general sentencelist matcher with some hard- + * coded prepositions as the default list. The list is + * sent as a parameter which will be replaced in the + * destination values. If no list is given the return + * value on match with the hardcoded prepositions will be + * string. If a list is given, the list will be returned + * with the matched sentence swapped to the first element. + * Arguments: warr: Vector of words in the command to parse + * cix_in: Current word in commandword array + * fail: Fail flag if parse did not match + * prepos: Pointer to svalue holding prepos parameter. + * Returns: svalue holding result of parse. + */ +static svalue_t * +prepos_parse (array_t * warr, int * cix_in, int * fail, svalue_t * prepos) +{ + array_t *parr, *tarr; + const char *tmp; + int pix, tix; + + if ((!prepos) || (prepos->type != T_ARRAY)) { + parr = gPrepos_list; + } else { + parr = prepos->u.arr; + } + + for (pix = 0; pix < parr->size; pix++) { + if (parr->item[pix].type != T_STRING) + continue; + + tmp = parr->item[pix].u.string; + if (!strchr(tmp, ' ')) { + if (EQ(tmp, warr->item[*cix_in].u.string)) { + (*cix_in)++; + break; + } + } else { + tarr = explode_string(tmp, strlen(tmp), " ", 1); + for (tix = 0; tix < tarr->size; tix++) { + if ((*cix_in + tix >= warr->size) || + (!EQ(warr->item[*cix_in + tix].u.string, tarr->item[tix].u.string))) + break; + } + if ((tix = (tix == tarr->size) ? 1 : 0)) + (*cix_in) += tarr->size; + free_array(tarr); + if (tix) + break; + } + } + + if (pix == parr->size) { + parse_ret.type = T_NUMBER; + parse_ret.u.number = 0; + *fail = 1; + } else if (parr != gPrepos_list) { + parse_ret = parr->item[0]; + parr->item[0] = parr->item[pix]; + parr->item[pix] = parse_ret; + *fail = 0; + assign_svalue_no_free(&parse_ret, prepos); + } else { + parse_ret.type = T_STRING; + parse_ret.subtype = STRING_MALLOC; + parse_ret.u.string = string_copy(parr->item[pix].u.string, "parse"); + *fail = 0; + } + + return &parse_ret; +} + +/* + * Function name: match_object + * Description: Tests if a given object matches the description as + * given in the commandarray warr. + * Arguments: obix: Index in id arrays for this object. + * warr: Vector of words in the command to parse + * cix_in: Current word in commandword array + * plur: This arg gets set if the noun was on pluralform + * Returns: True if object matches. + */ +static int +match_object (int obix, array_t * warr, int * cix_in, int * plur) +{ + array_t *ids; + int il, pos, cplur, old_cix; + const char *str; + + for (cplur = (*plur * 2); cplur < 4; cplur++) { + switch (cplur) { + case 0: + if (!gId_list_d) + continue; + ids = gId_list_d; + break; + + case 1: + if (!gId_list || + gId_list->size <= obix || + gId_list->item[obix].type != T_ARRAY) + continue; + ids = gId_list->item[obix].u.arr; + break; + + case 2: + if (!gPluid_list_d) + continue; + ids = gPluid_list_d; + break; + + case 3: + if (!gPluid_list || + gPluid_list->size <= obix || + gPluid_list->item[obix].type != T_ARRAY) + continue; + ids = gPluid_list->item[obix].u.arr; + break; + + default: + ids = 0; + + } + + for (il = 0; il < ids->size; il++) { + if (ids->item[il].type == T_STRING) { + str = ids->item[il].u.string; /* A given id of the object */ + old_cix = *cix_in; + if ((pos = find_string(str, warr, cix_in)) >= 0) { + if (pos == old_cix) { + if (cplur > 1) + *plur = 1; + return 1; + } else if (check_adjectiv(obix, warr, old_cix, pos - 1)) { + if (cplur > 1) + *plur = 1; + return 1; + } + } + *cix_in = old_cix; + } + } + } + return 0; +} + +/* + * Function name: find_string + * Description: Finds out if a given string exist within an + * array of words. + * Arguments: str: String of some words + * warr: Array of words + * cix_in: Startpos in word array + * Returns: Pos in array if string found or -1 + */ +static int +find_string (const char * str, array_t * warr, int * cix_in) +{ + int fpos; + const char *p1, *p2; + array_t *split; + + for (; *cix_in < warr->size; (*cix_in)++) { + p1 = warr->item[*cix_in].u.string; + if (p1[0] != str[0]) + continue; + + if (strcmp(p1, str) == 0) /* str was one word and we found it */ + return *cix_in; + + if (!(p2 = strchr(str, ' '))) + continue; + + /* + * If str was multi word we need to make som special checks + */ + if (*cix_in == (warr->size - 1)) + continue; + + split = explode_string(str, strlen(str), " ", 1); + + /* + * warr->size - *cix_in == + * 2: One extra word + * 3: Two extra words + */ + if (!split || (split->size > (warr->size - *cix_in))) { + if (split) + free_array(split); + continue; + } + fpos = *cix_in; + for (; (*cix_in - fpos) < split->size; (*cix_in)++) { + if (strcmp(split->item[*cix_in - fpos].u.string, + warr->item[*cix_in].u.string)) + break; + } + if ((*cix_in - fpos) == split->size) { + if (split) + free_array(split); + return fpos; + } + + if (split) + free_array(split); + *cix_in = fpos; + } + return -1; +} + +/* + * Function name: check_adjectiv + * Description: Checks a word to see if it fits as adjectiv of an + * object. + * Arguments: obix: The index in the global id arrays + * warr: The command words + * from: #1 cmdword to test + * to: last cmdword to test + * Returns: True if a match is made. + */ +static int +check_adjectiv (int obix, array_t * warr, int from, int to) +{ + int il, back, sum, fail; + char *adstr; + array_t *ids; + + if (gAdjid_list->item[obix].type == T_ARRAY) + ids = gAdjid_list->item[obix].u.arr; + else + ids = 0; + + for (sum = 0, fail = 0, il = from; il <= to; il++) { + sum += strlen(warr->item[il].u.string) + 1; + if ((member_string(warr->item[il].u.string, ids) < 0) && + (member_string(warr->item[il].u.string, gAdjid_list_d) < 0)) { + fail = 1; + } + } + + /* + * Simple case: all adjs were single word + */ + if (!fail) + return 1; + + if (from == to) + return 0; + + adstr = (char *)DXALLOC(sum, TAG_TEMPORARY, "check_adjectiv"); + + /* + * If we now have: "adj1 adj2 adj3 ... adjN" + * We must test in order: "adj1 adj2 adj3 .... adjN-1 adjN" + "adj1 adj2 adj3 .... adjN-1" + "adj1 adj2 adj3 ...." + .... + * if match for adj1 .. adj3 continue with: + * "adj4 adj5 .... adjN-1 adjN" + * "adj4 adj5 .... adjN-1" + * "adj4 adj5 ...." + * ..... + */ + for (il = from; il <= to;) {/* adj1 .. adjN */ + for (back = to; back >= il; back--) { /* back from adjN to adj[il] */ + /* + * Create teststring with "adj[il] .. adj[back]" + */ + adstr[0] = 0; + for (sum = il; sum <= back; sum++) { /* test "adj[il] .. + * adj[back] */ + if (sum > il) + strcat(adstr, " "); + strcat(adstr, warr->item[sum].u.string); + } + if ((member_string(adstr, ids) < 0) && + (member_string(adstr, gAdjid_list_d) < 0)) + continue; + else { + il = back + 1; /* Match "adj[il] adj[il+1] .. adj[back]" */ + back = to; + break; + } + } + if (back < to) { + FREE(adstr); /* adj[il] does not match at all => no match */ + return 0; + } + } + FREE(adstr); + return 1; +} + +/* + * Function name: member_string + * Description: Checks if a string is a member of an array. + * Arguments: str: The string to search for + * sarr: array of strings + * Returns: Pos if found else -1. + */ +static int +member_string (const char * str, array_t * sarr) +{ + int il; + + if (!sarr) + return -1; + + for (il = 0; il < sarr->size; il++) { + if (sarr->item[il].type != T_STRING) + continue; + + if (strcmp(sarr->item[il].u.string, str) == 0) + return il; + } + return -1; +} + +#ifndef PARSE_FOREIGN +/* + * Function name: parse_to_plural + * Description: Change a sentence in singular form to a sentence + * in pluralform. + * Arguments: str: The sentence to change + * Returns: Sentence in plural form. + */ +static const char * + parse_to_plural (const char * str) +{ + array_t *words; + const char *sp; + int il, changed; + + if (!(strchr(str, ' '))) + return string_copy(parse_one_plural(str), "parse_to_plural"); + + words = explode_string(str, strlen(str), " ", 1); + + for (changed = 0, il = 1; il < words->size; il++) { + if ((EQ(words->item[il].u.string, "of")) || + (il + 1 == words->size)) { + sp = parse_one_plural(words->item[il - 1].u.string); + if (sp != words->item[il - 1].u.string) { + free_svalue(&words->item[il - 1], "parse_to_plural"); + words->item[il - 1].type = T_STRING; + words->item[il - 1].subtype = STRING_MALLOC; + words->item[il - 1].u.string = string_copy(sp, + "parse_to_plural"); + changed = 1; + } + } + } + if (!changed) { + free_array(words); + return string_copy(str, "parse_to_plural"); + } + sp = implode_string(words, " ", 1); + free_array(words); + return sp; +} + +/* + * Function name: parse_one_plural + * Description: Change a noun in singularform to a noun + * in pluralform. + * Arguments: str: The sentence to change + * Returns: Word in plural form. + */ +static const char * + parse_one_plural (const char * str) +{ + char ch, ch2, ch3; + int sl; + static char pbuf[100]; /* Words > 100 letters? In Wales maybe... */ + + sl = strlen(str) - 1; + if ((sl < 2) || (sl > 90)) + return str; + + ch = str[sl]; + ch2 = str[sl - 1]; + ch3 = sl > 2 ? str[sl - 2] : '\0'; + strcpy(pbuf, str); + pbuf[sl] = 0; + + switch (ch) { + case 'e': + if (ch2 == 'f') { + pbuf[sl - 1] = 0; + return strcat(pbuf, "ves"); + } + case 'f': + return strcat(pbuf, "ves"); + case 'h': + if (ch2 == 's' || ch2 == 'c') + return strcat(pbuf, "hes"); + case 's': + return strcat(pbuf, "ses"); + case 'x': + if (EQ(str, "ox")) + return "oxen"; + else + return strcat(pbuf, "xes"); + case 'y': + if ((ch2 != 'a' && ch2 != 'e' && ch2 != 'i' && ch2 != 'o' && + ch2 != 'u') || (ch2 == 'u' && ch3 == 'q')) + return strcat(pbuf, "ies"); + } + + if (EQ(str, "corpse")) + return "corpses"; + if (EQ(str, "tooth")) + return "teeth"; + if (EQ(str, "foot")) + return "feet"; + if (EQ(str, "man")) + return "men"; + if (EQ(str, "woman")) + return "women"; + if (EQ(str, "child")) + return "children"; + if (EQ(str, "sheep")) + return "sheep"; + if (EQ(str, "goose")) + return "geese"; + if (EQ(str, "mouse")) + return "mice"; + if (EQ(str, "deer")) + return "deer"; + if (EQ(str, "moose")) + return "moose"; + + pbuf[sl] = ch; + return strcat(pbuf, "s"); +} +#endif + +/* + + End of Parser + +***************************************************************/ diff --git a/fluffos-2.23-ds03/parse.h b/fluffos-2.23-ds03/parse.h new file mode 100644 index 0000000..84c822d --- /dev/null +++ b/fluffos-2.23-ds03/parse.h @@ -0,0 +1,11 @@ +#ifndef PARSE_H +#define PARSE_H + +#include "lpc_incl.h" + +int parse (const char *, svalue_t *, const char *, svalue_t *, int); +char *process_string (char *); +svalue_t *process_value (char *); +char *break_string (char *, int, svalue_t *); + +#endif diff --git a/fluffos-2.23-ds03/parse_trees b/fluffos-2.23-ds03/parse_trees new file mode 100644 index 0000000..8925672 --- /dev/null +++ b/fluffos-2.23-ds03/parse_trees @@ -0,0 +1,95 @@ +NODE_TERNARY_OP: + l.expr: first arg + r.expr: NODE_BINARY_OP + +NODE_BINARY_OP: + v.number: opcode + l.expr, r.expr: arguments + +NODE_UNARY_OP: + v.number: opcode + r.expr: argument + +NODE_OPCODE: + v.number: opcode + +NODE_OPCODE_1: + v.number: opcode + l.number: param + +NODE_OPCODE_2: + v.number: opcode + l.number: param1 + r.number: param2 + +NODE_UNARY_OP_1: + r.expr: argument + v.number: opcode + l.number: param + +NODE_BINARY_OP_1: + r.expr, l.expr: args + v.number: opcode + type: param + +NODE_TERNARY_OP_1: + l.expr: first arg + r.expr: NODE_BINARY_OP + type: param + +NODE_RETURN: + r.expr: return value (may be zero) + +NODE_LAND_LOR: + l.expr, r.expr: expressions + v.number: F_LAND, F_LOR + +NODE_BRANCH_LINK: + l.expr, r.expr: expressions + +NODE_CALL, NODE_CALL_1: + r.expr: expr_list + v.number: opcode + l.number: param (short) + +NODE_CALL_2: + r.expr: expr_list + v.number: opcode + l.number: param2 << 16 + param (short) + +NODE_TWO_VALUES: + l.expr, r.expr: two values ;) + +NODE_CONTROL_JUMP: + v.number: (CJ_BREAK, CJ_BREAK_SWITCH, CJ_CONTINUE) + +NODE_PARAMETER: + v.number: index + +NODE_PARAMETER_LVALUE: + v.number: index + +NODE_IF: + v.expr: condition + l.expr: statement + r.expr: else statement + +NODE_LOOP: + type: if non-zero, do test at top of loop + v.expr: block + l.expr: inc + r.expr: test + +NODE_FOREACH: + l.expr: first var + r.expr: second var, or zero + v.expr: the expression + +NODE_LVALUE_EFUN: + l.expr: binary/ternary expression with builtin args + r.expr: lvalue list + +NODE_EFUN: + r.expr: expr_list + v.number: opcode ( + 1024 if void valued efun is used) + l.number: num args diff --git a/fluffos-2.23-ds03/patchlevel.h b/fluffos-2.23-ds03/patchlevel.h new file mode 100644 index 0000000..90950be --- /dev/null +++ b/fluffos-2.23-ds03/patchlevel.h @@ -0,0 +1,11 @@ +#define PATCH_LEVEL_PREFIX "v2.23-ds03" +#ifdef __CYGWIN__ +#define PATCH_LEVEL_SUFFIX "c" +#else +#ifndef WIN32 +#define PATCH_LEVEL_SUFFIX "" +#else +#define PATCH_LEVEL_SUFFIX "w" +#endif +#endif +#define PATCH_LEVEL PATCH_LEVEL_PREFIX PATCH_LEVEL_SUFFIX diff --git a/fluffos-2.23-ds03/plainwrapper.c b/fluffos-2.23-ds03/plainwrapper.c new file mode 100644 index 0000000..a602b04 --- /dev/null +++ b/fluffos-2.23-ds03/plainwrapper.c @@ -0,0 +1,3 @@ +#ifdef PEDANTIC +int I_really_could_do_without_warnings_about_ANSI_C_not_allowing_files_with_no_definitions; +#endif diff --git a/fluffos-2.23-ds03/port.c b/fluffos-2.23-ds03/port.c new file mode 100644 index 0000000..875cebc --- /dev/null +++ b/fluffos-2.23-ds03/port.c @@ -0,0 +1,304 @@ +#include "std.h" +#include "port.h" +#include "file_incl.h" +#include "network_incl.h" +#include +#ifndef MINGW +#include +#endif +#if defined(WIN32) +int dos_style_link (char * x, char * y) { + char link_cmd[100]; + sprintf(link_cmd, "copy %s %s", x, y); + return system(link_cmd); +} +#endif + +/* for get_cpu_times() */ +#ifdef GET_PROCESS_STATS +#include +#endif +#ifdef RUSAGE +#include +#endif + +#ifdef sun +time_t time (time_t *); +#endif + +/* + * Return a pseudo-random number in the range 0 .. n-1 + */ +long random_number (long n) +{ +#if defined(RAND) || defined(DRAND48) + static char called = 0; + + if (!called) { + time_t tim; + + time(&tim); +# ifdef RAND + srand(tim); +# else + srand48(tim); +# endif + called = 1; + } /* endif */ +# ifdef RAND +# ifdef MINGW + return rand() % n; +# else + return 1 + (long) ((float)n * rand() / (RAND_MAX+1.0); +#endif +# else + return (long)(drand48() * n); +# endif +#else +# ifdef RANDOM + return random() % n; +# else /* RANDOM */ + return current_time % n; /* You really don't want to use this method */ +# endif /* RANDOM */ +#endif /* RAND */ +} + +/* + * The function time() can't really be trusted to return an integer. + * But MudOS uses the 'current_time', which is an integer number + * of seconds. To make this more portable, the following functions + * should be defined in such a way as to return the number of seconds since + * some chosen year. The old behaviour of time(), is to return the number + * of seconds since 1970. + */ + +long get_current_time() +{ + return time(0l); /* Just use the old time() for now */ +} + +const char *time_string (time_t t) +{ + const char *res = ctime(&t); + if(!res) + res = "ctime failed"; + return res; +} + +/* + * Initialize the microsecond clock. + */ +void init_usec_clock() +{ +#ifdef _SEQUENT_ + usclk_init(); +#endif +} + +/* + * Get a microsecond clock sample. + */ +void +get_usec_clock (long * sec, long * usec) +{ +#ifdef HAS_GETTIMEOFDAY + struct timeval tv; + + gettimeofday(&tv, NULL); + *sec = tv.tv_sec; + *usec = tv.tv_usec; +#else +#ifdef _SEQUENT_ + *sec = 0; + *usec = GETUSCLK(); +#else + *sec = time(0); + *usec = 0; +#endif +#endif +} + +#ifdef USE_POSIX_SIGNALS +int +port_sigblock (sigset_t mask) +{ + sigset_t omask; + + sigprocmask(SIG_BLOCK, &mask, &omask); + return (omask); +} + +int +port_sigmask (int sig) +{ + sigset_t set; + + sigemptyset(&set); + sigaddset(&set, sig); + return (set); +} + +void + (*port_signal(sig, func)) () + int sig; + void (*func) (); +{ + struct sigaction act, oact; + + act.sa_handler = func; + act.sa_mask = 0; + act.sa_flags = 0; + if (sigaction(sig, &act, &oact) == -1) + return ((void (*) ()) -1); + return (oact.sa_handler); +} + +int +port_sigsetmask (sigset_t mask) +{ + sigset_t omask; + + sigprocmask(SIG_SETMASK, &mask, &omask); + return (omask); +} +#endif + +int +get_cpu_times (unsigned long * secs, unsigned long * usecs) +{ +#ifdef RUSAGE + struct rusage rus; +#endif +#if defined(TIMES) && !defined(RUSAGE) + struct tms t; + unsigned long total; +#endif +#ifdef GET_PROCESS_STATS + struct process_stats ps; +#endif + +#ifdef RUSAGE /* start RUSAGE */ + if (getrusage(RUSAGE_SELF, &rus) < 0) { + return 0; + } + *secs = rus.ru_utime.tv_sec + rus.ru_stime.tv_sec; + *usecs = rus.ru_utime.tv_usec + rus.ru_stime.tv_usec; + return 1; +#else /* end then RUSAGE */ + +#ifdef GET_PROCESS_STATS /* start GET_PROCESS_STATS */ + if (get_process_stats(NULL, PS_SELF, &ps, NULL) == -1) { + return 0; + } + *secs = ps.ps_utime.tv_sec + ps.ps_stime.tv_sec; + *usecs = ps.ps_utime.tv_usec + ps.ps_stime.tv_usec; + return 1; +#else /* end then GET_PROCESS_STATS */ + +#ifdef TIMES /* start TIMES */ + times(&t); + *secs = (total = t.tms_utime + t.tms_stime) / CLK_TCK; + *usecs = ((total - (*secs * CLK_TCK)) * 1000000) / CLK_TCK; + return 1; +#else /* end then TIMES */ + + return 0; +#endif /* end TIMES */ +#endif /* end else GET_PROCESS_STATS */ +#endif /* end else RUSAGE */ +} + +/* return the current working directory */ +char * + get_current_dir (char * buf, int limit) +{ +#ifdef HAS_GETCWD + return getcwd(buf, limit); /* POSIX */ +#else + return getwd(buf); /* BSD */ +#endif +} + +#ifndef HAS_STRERROR +/* for those systems without strerror() but with sys_errlist, sys_nerr */ +/* Warning: Sun has a prototype for strerror, but no definition for it, + so we can't use that name */ +extern char *sys_errlist[]; +extern int sys_nerr; + +char *port_strerror (int which) +{ + if ((which < 0) || (which >= sys_nerr)) { + return "unknown error"; + } else { + return sys_errlist[which]; + } +} +#endif /* STRERROR */ + +#ifdef MEMMOVE_MISSING +/* for those without memmove() and a working bcopy() that can handle overlaps */ +INLINE char *memmove (register char * b, register char * a, register int s) +{ + char *r = b; + + if (b < a) { + while (s--) + *(b++) = *(a++); + } else if (b > a) { + b += s; + a += s; + while (s--) + *(--b) = *(--a); + } + return r; +} +#endif + +#ifdef WIN32 +char *WinStrError(int err) { + static char buf[30]; + if (errno < 10000) return strerror(err); + sprintf(buf, "error #%d", err); + return buf; +} +#endif + +#ifdef MMAP_SBRK +void * sbrkx(long size){ + static void *end = 0; + static unsigned long tsize = 0; + void *tmp, *result; + long long newsize; + if(!end){ + tmp = mmap((void *)0x41000000, 4096, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS,0,0); + tsize=4096; + end=(void *)0x41000000; + if(tmp != end) + return NULL; + } + + newsize = (long)end + size; + result = end; + end = newsize; + newsize &= 0xFFFFF000; + newsize += 0x1000; + newsize -= 0x41000000; + + tmp = mremap((void *)0x41000000, tsize, newsize, 0); + + if(tmp != (void *) 0x41000000) + return NULL; + + tsize = newsize; + return result; +} + +#else + +void *sbrkx(long size){ +#ifndef MINGW + return sbrk(size); +#endif +} +#endif diff --git a/fluffos-2.23-ds03/port.h b/fluffos-2.23-ds03/port.h new file mode 100644 index 0000000..312c04c --- /dev/null +++ b/fluffos-2.23-ds03/port.h @@ -0,0 +1,23 @@ +#ifndef PORT_H +#define PORT_H + +/* + * port.c + */ +#ifndef _FUNC_SPEC_ +long random_number (long); +long get_current_time (void); +const char *time_string (time_t); +void init_usec_clock (void); +void get_usec_clock (long *, long *); +int get_cpu_times (unsigned long *, unsigned long *); +char *get_current_dir (char *, int); +#ifdef DRAND48 +double drand48 (void); +#endif +#ifndef HAS_STRERROR +char *port_strerror (int); +#endif +#endif + +#endif diff --git a/fluffos-2.23-ds03/portability.h b/fluffos-2.23-ds03/portability.h new file mode 100644 index 0000000..a5bd8b2 --- /dev/null +++ b/fluffos-2.23-ds03/portability.h @@ -0,0 +1,276 @@ +/* + * portability.h: global portability #defines for MudOS, an LPmud driver + * + * If you have to have to change this file to get MudOS to compile and + * run on your system, please provide us wth a copy of your modified + * portability.h file and the name of the type of system you are using. + */ + +/* NOTE: Do not put anything into this file other than preprocessor + directives (#define, #ifdef, #ifndef, etc). If you must put something + other than that, then be sure to put it between #ifndef _FUNC_SPEC_ + and #endif. Otherwise make_func will break. +*/ + +#ifndef PORTABILITY_H +#define PORTABILITY_H + +/* define this if you have an Ultrix system that the driver won't otherwise + compile on (doesn't seem to be needed for DECstations). +*/ +#undef OLD_ULTRIX + +/* define this if you're using HP-UX 7.x (or below?) */ +#undef OLD_HPUX + +#if defined(WINNT) || defined(WIN95) +# ifndef WIN32 +# define WIN32 +# ifndef _FUNC_SPEC_ + typedef char * caddr_t; +# endif +# endif +# define symlink(x, y) dos_style_link(x, y) +# define CDECL __cdecl +#else +# define CDECL +#endif + +#ifdef WIN32 +# define WINSOCK +# ifdef sun +# undef sun +# endif +#endif + +#if defined(SunOS_5) && !defined(SVR4) +# define SVR4 +#endif + +/* "hp68k" refers to Motorola 680xx HP's running BSD - not sure if they + also can run HP-UX or not, but to be sure we check .... + -bobf +*/ +#if (defined(hp200) || defined(hp300) || defined(hp400) || defined(hp500)) \ + && !defined(hpux) +# define hp68k +# define _ANSI_H +#endif + +/* I hear that gcc defines one of these, cc defines the other (w/ OSF/1 1.2) + -bobf +*/ +#if defined(__osf__) || defined(__OSF__) +# define OSF +#endif + +/* HAS_MONCONTROL: define this if you wish to do profiling of the driver + on a machine that has the moncontrol() system call. +*/ +#if defined(NeXT) +# define HAS_MONCONTROL +#endif + +/* define this if your builtin version of inet_ntoa() works well. It has a + * problem on some sun 4's (SPARCstations) (if the driver crashes at + * startup you might try undefining INET_NTOA_OK). + * NOTE: you must define this when compiling on a NeXT or an RS/6000. + */ +#if (!defined(sparc)) +# define INET_NTOA_OK +#endif + +/* the !defined(_FUNC_SPEC) is needed to allow make_func to work okay. */ +#if defined(hpux) && !defined(OLD_HPUX) && !defined(_FUNC_SPEC_) +# include +# define getrusage(a, b) syscall(SYS_GETRUSAGE, (a), (b)) +#endif + +/* + * Dynix/ptx has a system-call similar to rusage(). + */ +#ifdef _SEQUENT_ +# define GET_PROCESS_STATS +#endif + +/* + * Most implementation of System V Release 3 do not provide Berkeley signal + * semantics by default. Instead, POSIX signals are provided. If your + * implementation is System V Release 3 and you do not have Berkeley signals, + * but you do have POSIX signals, then #define USE_POSIX_SIGNALS. + */ +#if (defined(_SEQUENT_) || defined(_M_UNIX)) +# define USE_POSIX_SIGNALS +#endif + +/* + * Define HAS_SETDTABLESIZE if your system has getdtablesize()/setdtablesize(). + * If defined setdtablesize() is used to request the appropriate number of file + * descriptors for the current configuration. + * + * NeXT and Sparc don't have it. + * + * Amiga's AmiTCP does but has too many usage constraints. + */ +#if (defined(_SEQUENT_)) +# define HAS_SETDTABLESIZE +#endif + +/* Should be a configure check */ +#define SIGNAL_FUNC_TAKES_INT defined(_AIX) || defined(NeXT) \ + || defined(_SEQUENT_) || defined(SVR4) \ + || defined(__386BSD__) || defined(apollo) || defined(cray) \ + || defined(SunOS_5) || defined(__bsdi__) || defined(linux) + +/* Define MEMPAGESIZE to be some value if you wish to use BSDMALLOC + * _and_ your system does not support the getpagesize() system call. + * This page size should be terms of the number of bytes in a page of + * system memory (not necessarily the same as the hardware page size). + * You may be able to ascertain the correct value by searching your + * /usr/include files or asking your system adminstrator. + * + * FIXME: configure should check for getpagesize(). + */ +#if !defined(linux) && !defined(__386BSD__) && !defined(__FreeBSD__) \ + && !defined(OSF) && !defined(SunOS_4) && !defined(sgi) +# ifdef _SC_PAGE_SIZE +# define MEMPAGESIZE sysconf(_SC_PAGE_SIZE) +# else +# ifdef _SC_PAGESIZE +# define MEMPAGESIZE sysconf(_SC_PAGESIZE) +# else + /* taken from smalloc.c's CHUNK_SIZE */ +# define MEMPAGESIZE 0x40000 +# endif +# endif +#endif + +/* define this if you system is BSD 4.2 (not 4.3) */ +#undef BSD42 + +/* otherwise make_func will break */ +#ifndef _FUNC_SPEC_ +/* these should be obtained from .h files when Linux .h structure stabilizes */ +# if defined(linux) || defined(_M_UNIX) +/* This has FD_SETSIZE on some Linux's (Linuces?) */ +# include +# include +# ifndef FD_SETSIZE +# define FD_SETSIZE 256 +# endif +# endif +#endif + +#if defined(cray) && !defined(MAXPATHLEN) +# define MAXPATHLEN PATH_MAX +#endif + +#if defined(WIN32) && !defined(MAXPATHLEN) +# define MAXPATHLEN 512 +#endif + +#if defined(_M_UNIX) && !defined(MAXPATHLEN) +# define MAXPATHLEN 1024 +#endif + +/* + * memmove() + * - for the few systems without [working] bcopy(); not sure why some + * gcc users don't have this in their c.lib...it's ANSI C (see K&R) + */ +#ifdef USE_BCOPY +/* sunos 4.x, msdos */ +#define memmove(a,b,c) bcopy(b,a,c) +#endif + +#if defined(sun) && !defined(SunOS_5) +# define OLDCRYPT(x, y) _crypt(x, y) +#else +# define OLDCRYPT(x, y) crypt(x, y) +#endif + +#ifdef CUSTOM_CRYPT +# define CRYPT(x, y) custom_crypt(x, y, 0) +#else +# define CRYPT(x, y) OLDCRYPT(x, y) +#endif + +#ifdef HAS_STRERROR +# define port_strerror strerror +#endif + +#ifdef WINSOCK +/* Windows stuff */ + +# define WINSOCK_NO_FLAGS_SET 0 + +# define OS_socket_write(f, m, l) send(f, m, l, WINSOCK_NO_FLAGS_SET) +# define OS_socket_read(r, b, l) recv(r, b, l, WINSOCK_NO_FLAGS_SET) +# define OS_socket_close(f) closesocket(f) +# define OS_socket_ioctl(f, w, a) ioctlsocket(f, w, a) +# define EWOULDBLOCK WSAEWOULDBLOCK +# define EINPROGRESS WSAEINPROGRESS +# define EALREADY WSAEALREADY +# define ENOTSOCK WSAENOTSOCK +# define EDESTADDRREQ WSAEDESTADDRREQ +# define EMSGSIZE WSAEMSGSIZE +# define EPROTOTYPE WSAEPROTOTYPE +# define ENOPROTOOPT WSAENOPROTOOPT +# define EPROTONOSUPPORT WSAEPROTONOSUPPORT +# define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT +# define EOPNOTSUPP WSAEOPNOTSUPP +# define EPFNOSUPPORT WSAEPFNOSUPPORT +# define EAFNOSUPPORT WSAEAFNOSUPPORT +# define EADDRINUSE WSAEADDRINUSE +# define EADDRNOTAVAIL WSAEADDRNOTAVAIL +# define ENETDOWN WSAENETDOWN +# define ENETUNREACH WSAENETUNREACH +# define ENETRESET WSAENETRESET +# define ECONNABORTED WSAECONNABORTED +# define ECONNRESET WSAECONNRESET +# define ENOBUFS WSAENOBUFS +# define EISCONN WSAEISCONN +# define ENOTCONN WSAENOTCONN +# define ESHUTDOWN WSAESHUTDOWN +# define ETOOMANYREFS WSAETOOMANYREFS +# define ETIMEDOUT WSAETIMEDOUT +# define ECONNREFUSED WSAECONNREFUSED +# define ELOOP WSAELOOP +# define EHOSTDOWN WSAEHOSTDOWN +# define EHOSTUNREACH WSAEHOSTUNREACH +# define EPROCLIM WSAEPROCLIM +# define EUSERS WSAEUSERS +# define EDQUOT WSAEDQUOT +# define ESTALE WSAESTALE +# define EREMOTE WSAEREMOTE +# define socket_errno WSAGetLastError() +# define socket_perror(x, y) SocketPerror(x, y) + +# define FOPEN_READ "rb" +# define FOPEN_WRITE "wb" +# define OPEN_WRITE (O_WRONLY | O_BINARY) +# define OPEN_READ (O_RDONLY | O_BINARY) +#else +/* Normal UNIX */ +# define OS_socket_write(f, m, l) send(f, m, l, 0) +# define OS_socket_read(r, b, l) recv(r, b, l, 0) +# define OS_socket_close(f) close(f) +# define OS_socket_ioctl(f, w, a) ioctl(f, w, (caddr_t)a) +# define socket_errno errno +# define socket_perror(x, y) debug_perror(x, y) +# define INVALID_SOCKET -1 +# define SOCKET_ERROR -1 + +# define FOPEN_READ "r" +# define FOPEN_WRITE "w" +# define OPEN_WRITE O_WRONLY +# define OPEN_READ O_RDONLY +#endif + +#ifndef EWOULDBLOCK +#ifdef EAGAIN +#define EWOULDBLOCK EAGAIN +#endif +#endif + +#endif /* _PORT_H */ diff --git a/fluffos-2.23-ds03/portbind.c b/fluffos-2.23-ds03/portbind.c new file mode 100644 index 0000000..90a589f --- /dev/null +++ b/fluffos-2.23-ds03/portbind.c @@ -0,0 +1,109 @@ +/* portbind.c: Tim Hollebeek, Oct 28, 1996 */ + +#include "std.h" +#include "network_incl.h" + +#define HANDLE_ERROR(routine, call) if ((call) == -1) { perror(#routine); exit(-1); } + +int main(int argc, char **argv) { +#ifndef WIN32 + int port = -1; + char *ipaddress = 0; + char *driver_name = "./driver"; + int uid = -1; + int gid = -1; + + int fd; + int optval = 1; + struct sockaddr_in sin; + + /*Args are passed down to the driver, but we process the following options: + * + * -p + * -d + * -u + * -g + * -i + * + * anything else causes us to quit scanning options. + */ + while (argc > 1) { + if (strcmp(argv[1], "-p") == 0) { + if (argc == 2 || sscanf(argv[2], "%d", &port) != 1) { + fprintf(stderr, "%s: -p must be followed by a port number.\n", + argv[0]); + exit(-1); + } + argc -= 2; + argv += 2; + } else if (strcmp(argv[1], "-d") == 0) { + if (argc == 2) { + fprintf(stderr, "%s: -d must be followed by the driver pathname.\n", argv[0]); + exit(-1); + } + driver_name = argv[2]; + argc -= 2; + argv += 2; + } else if (strcmp(argv[1], "-u") == 0) { + if (argc == 2 || sscanf(argv[2], "%d", &uid) != 1) { + fprintf(stderr, "%s: -u must be followed by a valid numeric uid.\n", argv[0]); + exit(-1); + } + argc -= 2; + argv += 2; + } else if (strcmp(argv[1], "-g") == 0) { + if (argc == 2 || sscanf(argv[2], "%d", &gid) != 1) { + fprintf(stderr, "%s: -g must be followed by a valid numeric gid.\n", argv[0]); + exit(-1); + } + argc -= 2; + argv += 2; + } else if (strcmp(argv[1], "-i") == 0) { + if (argc == 2 || inet_addr(argv[2]) == INADDR_NONE) { + fprintf(stderr, "%s: -i must be followed by a valid dotted decimal ip address.\n", argv[0]); + exit(-1); + } + ipaddress = argv[2]; + argc -= 2; + argv += 2; + } else break; + } + + if (port == -1) { + fprintf(stderr, "%s: a port must be specified with -p.\n", argv[0]); + exit(-1); + } + + /* create the socket */ + HANDLE_ERROR(socket, fd = socket(AF_INET, SOCK_STREAM, 0)); + + /* move to fd #6 */ + HANDLE_ERROR(dup2, dup2(fd, 6)); + + /* close the old copy */ + HANDLE_ERROR(close, close(fd)); + + /* set local address reuse */ + HANDLE_ERROR(setsockopt, setsockopt(6, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval)) == -1); + + /* setup our address */ + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = (ipaddress ? inet_addr(ipaddress) : INADDR_ANY); + sin.sin_port = htons((unsigned short)port); + + /* bind to our address */ + HANDLE_ERROR(bind, bind(6, (struct sockaddr *)&sin, sizeof(sin))); + + /* change our uid and gid */ + if (gid != -1) + HANDLE_ERROR(setgid, setgid(gid)); + + if (uid != -1) + HANDLE_ERROR(setuid, setuid(uid)); + + argv[0] = driver_name; + /* exec the driver */ + HANDLE_ERROR(execv, execv(driver_name, argv)); +#endif + return 0; +} diff --git a/fluffos-2.23-ds03/preprocess.c b/fluffos-2.23-ds03/preprocess.c new file mode 100644 index 0000000..b2bc02e --- /dev/null +++ b/fluffos-2.23-ds03/preprocess.c @@ -0,0 +1,428 @@ +/* WARNING: This file is #included into two places, since the definition + of malloc() differs. Be careful. */ + +static int cond_get_exp (int); +static void handle_cond (int); + +#ifndef LEXER +#undef DXALLOC +#define DXALLOC(x, y, z) malloc(x) +#undef FREE +void free(void *); +#define FREE(x) free(x) +#undef ALLOCATE +void *malloc(size_t); +#define ALLOCATE(x, y, z) (x *)malloc(sizeof(x)) +#undef DREALLOC +void *realloc(void *, size_t); +#define DREALLOC(w, x, y, z) realloc(w, x) +#endif + +static defn_t *defns[DEFHASH]; +static ifstate_t *iftop = 0; + +static defn_t *lookup_definition (const char * s) +{ + defn_t *p; + int h; + + h = defhash(s); + for (p = defns[h]; p; p = p->next) + if (strcmp(s, p->name) == 0) + return p; + return 0; +} + +defn_t *lookup_define (const char * s) +{ + defn_t *p = lookup_definition(s); + + if (p && (p->flags & DEF_IS_UNDEFINED)) + return 0; + else + return p; +} + +static void add_define (const char * name, int nargs, const char * exps) +{ + defn_t *p = lookup_definition(name); + int h, len; + + /* trim off leading and trailing whitespace */ + while (uisspace(*exps)) exps++; + for (len = strlen(exps); len && uisspace(exps[len - 1]); len--); + if (*exps == '#' && *(exps + 1) == '#') { + yyerror("'##' at start of macro definition"); + return; + } + if (len > 2 && *(exps + len - 2) == '#' && *(exps + len - 1) == '#') { + yyerror("'##' at end of macro definition"); + return; + } + + if (p) { + if (p->flags & DEF_IS_UNDEFINED) { + p->exps = (char *)DREALLOC(p->exps, len + 1, TAG_COMPILER, "add_define: redef"); + memcpy(p->exps, exps, len); + p->exps[len] = 0; + p->flags = 0; + p->nargs = nargs; + } else { + if (p->flags & DEF_IS_PREDEF) { + yyerror("Illegal to redefine predefined value."); + return; + } + if (nargs != p->nargs || strcmp(exps, p->exps)) { + char buf[200 + NSIZE]; + + sprintf(buf, "redefinition of #define %s\n", name); + yywarn(buf); + + p->exps = (char *)DREALLOC(p->exps, len + 1, TAG_COMPILER, "add_define: redef"); + memcpy(p->exps, exps, len); + p->exps[len] = 0; + p->nargs = nargs; + } +#ifndef LEXER + p->flags &= ~DEF_IS_NOT_LOCAL; +#endif + } + } else { + p = ALLOCATE(defn_t, TAG_COMPILER, "add_define: def"); + p->name = (char *) DXALLOC(strlen(name) + 1, TAG_COMPILER, "add_define: def name"); + strcpy(p->name, name); + p->exps = (char *) DXALLOC(len + 1, TAG_COMPILER, "add_define: def exps"); + memcpy(p->exps, exps, len); + p->exps[len] = 0; + p->flags = 0; + p->nargs = nargs; + h = defhash(name); + p->next = defns[h]; + defns[h] = p; + } +} + +#ifdef LEXER +static void handle_elif (char * sp) +#else +static void handle_elif() +#endif +{ + if (iftop) { + if (iftop->state == EXPECT_ELSE) { + /* last cond was false... */ + int cond; + ifstate_t *p = iftop; + + /* pop previous condition */ + iftop = p->next; + FREE((char *) p); + +#ifdef LEXER + *--outp = '\0'; + add_input(sp); +#endif + cond = cond_get_exp(0); +#ifdef LEXER + if (*outp++) { + yyerror("Condition too complex in #elif"); + while (*outp++); +#else + if (*outp != '\n') { + yyerror("Condition too complex in #elif"); +#endif + } else handle_cond(cond); + } else {/* EXPECT_ENDIF */ + /* + * last cond was true...skip to end of + * conditional + */ + skip_to("endif", (char *) 0); + } + } else { + yyerrorp("Unexpected %celif"); + } +} + +static void handle_else (void) { + if (iftop) { + if (iftop->state == EXPECT_ELSE) { + iftop->state = EXPECT_ENDIF; + } else { + skip_to("endif", (char *) 0); + } + } else { + yyerrorp("Unexpected %cendif"); + } +} + +static void handle_endif (void) { + if (iftop && (iftop->state == EXPECT_ENDIF || + iftop->state == EXPECT_ELSE)) { + ifstate_t *p = iftop; + + iftop = p->next; + FREE((char *) p); + } else { + yyerrorp("Unexpected %cendif"); + } +} + +#define BNOT 1 +#define LNOT 2 +#define UMINUS 3 +#define UPLUS 4 + +#define MULT 1 +#define DIV 2 +#define MOD 3 +#define BPLUS 4 +#define BMINUS 5 +#define LSHIFT 6 +#define RSHIFT 7 +#define LESS 8 +#define LEQ 9 +#define GREAT 10 +#define GEQ 11 +#define EQ 12 +#define NEQ 13 +#define BAND 14 +#define XOR 15 +#define BOR 16 +#define LAND 17 +#define LOR 18 +#define QMARK 19 + +static char _optab[] = +{0, 4, 0, 0, 0, 26, 56, 0, 0, 0, 18, 14, 0, 10, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 50, 40, 74, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 1}; +static char optab2[] = +{BNOT, 0, 0, LNOT, '=', NEQ, 7, 0, 0, UMINUS, 0, BMINUS, 10, UPLUS, 0, BPLUS, 10, + 0, 0, MULT, 11, 0, 0, DIV, 11, 0, 0, MOD, 11, + 0, '<', LSHIFT, 9, '=', LEQ, 8, 0, LESS, 8, 0, '>', RSHIFT, 9, '=', GEQ, 8, 0, GREAT, 8, + 0, '=', EQ, 7, 0, 0, 0, '&', LAND, 3, 0, BAND, 6, 0, '|', LOR, 2, 0, BOR, 4, + 0, 0, XOR, 5, 0, 0, QMARK, 1}; + +#define optab1 (_optab-' ') + +static int cond_get_exp (int priority) +{ + int c; + int value, value2, x; + +#ifdef LEXER + do + c = exgetc(); + while (is_wspace(c)); + if (c == '(') { +#else + if ((c = exgetc()) == '(') { +#endif + value = cond_get_exp(0); +#ifdef LEXER + do + c = exgetc(); + while (is_wspace(c)); + if (c != ')') { + yyerror("bracket not paired in #if"); + if (!c) *--outp = '\0'; + } +#else + if ((c = exgetc()) != ')') yyerrorp("bracket not paired in %cif"); +#endif + } else if (ispunct(c)) { + if (!(x = optab1[c])) { + yyerrorp("illegal character in %cif"); + return 0; + } + value = cond_get_exp(12); + switch (optab2[x - 1]) { + case BNOT: + value = ~value; + break; + case LNOT: + value = !value; + break; + case UMINUS: + value = -value; + break; + case UPLUS: + value = value; + break; + default: + yyerrorp("illegal unary operator in %cif"); + } + } else { + int base; + + if (!isdigit(c)) { +#ifdef LEXER + if (!c) { +#else + if (c == '\n') { +#endif + yyerrorp("missing expression in %cif"); + } else + yyerrorp("illegal character in %cif"); + return 0; + } + value = 0; + if (c != '0') + base = 10; + else { + c = *outp++; + if (c == 'x' || c == 'X') { + base = 16; + c = *outp++; + } else + base = 8; + } + for (;;) { + if (isdigit(c)) + x = -'0'; + else if (isupper(c)) + x = -'A' + 10; + else if (islower(c)) + x = -'a' + 10; + else + break; + x += c; + if (x > base) + break; + value = value * base + x; + c = *outp++; + } + outp--; + } + for (;;) { +#ifdef LEXER + do + c = exgetc(); + while (is_wspace(c)); + if (!ispunct(c)) + break; +#else + if (!ispunct(c = exgetc())) + break; +#endif + if (!(x = optab1[c])) + break; + value2 = *outp++; + for (;; x += 3) { + if (!optab2[x]) { + outp--; + if (!optab2[x + 1]) { + yyerrorp("illegal operator use in %cif"); + return 0; + } + break; + } + if (value2 == optab2[x]) + break; + } + if (priority >= optab2[x + 2]) { + if (optab2[x]) *--outp = value2; + break; + } + value2 = cond_get_exp(optab2[x + 2]); + switch (optab2[x + 1]) { + case MULT: + value *= value2; + break; + case DIV: + if (value2) + value /= value2; + else + yyerrorp("division by 0 in %cif"); + break; + case MOD: + if (value2) + value %= value2; + else + yyerrorp("modulo by 0 in %cif"); + break; + case BPLUS: + value += value2; + break; + case BMINUS: + value -= value2; + break; + case LSHIFT: + value <<= value2; + break; + case RSHIFT: + value >>= value2; + break; + case LESS: + value = value < value2; + break; + case LEQ: + value = value <= value2; + break; + case GREAT: + value = value > value2; + break; + case GEQ: + value = value >= value2; + break; + case EQ: + value = value == value2; + break; + case NEQ: + value = value != value2; + break; + case BAND: + value &= value2; + break; + case XOR: + value ^= value2; + break; + case BOR: + value |= value2; + break; + case LAND: + value = value && value2; + break; + case LOR: + value = value || value2; + break; + case QMARK: +#ifdef LEXER + do + c = exgetc(); + while (isspace(c)); + if (c != ':') { + yyerror("'?' without ':' in #if"); + outp--; + return 0; + } +#else + if ((c = exgetc()) != ':') yyerrorp("'?' without ':' in %cif"); +#endif + if (value) { + cond_get_exp(1); + value = value2; + } else + value = cond_get_exp(1); + break; + } + } + outp--; + return value; +} + +static void +handle_cond (int c) +{ + ifstate_t *p; + + if (!c) + skip_to("else", "endif"); + p = ALLOCATE(ifstate_t, TAG_COMPILER, "handle_cond"); + p->next = iftop; + iftop = p; + p->state = c ? EXPECT_ENDIF : EXPECT_ELSE; +} + + diff --git a/fluffos-2.23-ds03/preprocess.h b/fluffos-2.23-ds03/preprocess.h new file mode 100644 index 0000000..c89c01e --- /dev/null +++ b/fluffos-2.23-ds03/preprocess.h @@ -0,0 +1,6 @@ +#ifndef PREPROCESS_H +#define PREPROCESS_H + +defn_t *lookup_define (const char *); + +#endif diff --git a/fluffos-2.23-ds03/program.c b/fluffos-2.23-ds03/program.c new file mode 100644 index 0000000..c8fa1ec --- /dev/null +++ b/fluffos-2.23-ds03/program.c @@ -0,0 +1,114 @@ +#include "std.h" +#include "lpc_incl.h" + +int total_num_prog_blocks, total_prog_block_size; + +void reference_prog (program_t * progp, const char * from) +{ + progp->ref++; + debug(d_flag, ("reference_prog: /%s ref %d (%s)\n", + progp->filename, progp->ref, from)); +} + +void deallocate_program (program_t * progp) +{ + int i; + + debug(d_flag, ("free_prog: /%s\n", progp->filename)); + + total_prog_block_size -= progp->total_size; + total_num_prog_blocks -= 1; + + /* Free all function names. */ + for (i = 0; i < progp->num_functions_defined; i++) + if (progp->function_table[i].funcname) + free_string(progp->function_table[i].funcname); + /* Free all strings */ + for (i = 0; i < progp->num_strings; i++) + free_string(progp->strings[i]); + /* Free all variable names */ + for (i = 0; i < progp->num_variables_defined; i++) + free_string(progp->variable_table[i]); + /* Free all inherited objects */ + for (i = 0; i < progp->num_inherited; i++){ + program_t *tmp = progp->inherit[i].prog; + free_prog(&tmp); //don't want to mess up the prog pointer in the inherited ob + } + free_string(progp->filename); + + /* + * We're going away for good, not just being swapped, so free up + * line_number stuff. + */ + if (progp->file_info) + FREE(progp->file_info); + + FREE((char *) progp); +} + +/* + * Decrement reference count for a program. If it is 0, then free the prgram. + * The flag free_sub_strings tells if the propgram plus all used strings + * should be freed. They normally are, except when objects are swapped, + * as we want to be able to read the program in again from the swap area. + * That means that strings are not swapped. + */ +void free_prog (program_t **progp) +{ + (*progp)->ref--; + if ((*progp)->ref > 0) { + *progp = (program_t *)2;//NULL; + return; + } + if ((*progp)->func_ref > 0) { + *progp = (program_t *)3;//NULL; + return; + } + + deallocate_program(*progp); + *progp = (program_t *)4;//NULL; +} + +char *variable_name (program_t * prog, int idx) { + int i = prog->num_inherited - 1; + int first; + + if (i > -1) + first = prog->inherit[i].variable_index_offset + prog->inherit[i].prog->num_variables_total; + else + return prog->variable_table[idx]; + if (idx >= first) + return prog->variable_table[idx - first]; + while (idx < prog->inherit[i].variable_index_offset) + i--; + return variable_name(prog->inherit[i].prog, idx - prog->inherit[i].variable_index_offset); +} + +function_t *find_func_entry (program_t * prog, int index) { + register int low, mid, high; + + + /* Walk up the inheritance tree to the real definition */ + if (prog->function_flags[index] & FUNC_ALIAS) { + index = prog->function_flags[index] & ~FUNC_ALIAS; + } + + while (prog->function_flags[index] & FUNC_INHERITED) { + low = 0; + high = prog->num_inherited -1; + + while (high > low) { + mid = (low + high + 1) >> 1; + if (prog->inherit[mid].function_index_offset > index) + high = mid -1; + else low = mid; + } + index -= prog->inherit[low].function_index_offset; + prog = prog->inherit[low].prog; + } + + index -= prog->last_inherited; + + return prog->function_table + index; +} + diff --git a/fluffos-2.23-ds03/program.h b/fluffos-2.23-ds03/program.h new file mode 100644 index 0000000..3ac14e2 --- /dev/null +++ b/fluffos-2.23-ds03/program.h @@ -0,0 +1,258 @@ +#ifndef PROGRAM_H +#define PROGRAM_H +/* + * A compiled program consists of several data blocks, all allocated + * contiguously in memory to enhance the working set. During compilation, + * the blocks will be allocated separately, as the final size is + * unknown. When compilation is done, the blocks will be copied into + * the one big area. + * + * There are 5 different blocks of information for each program: + * 1. The program itself. Consists of machine code instructions for a virtual + * stack machine. The size of the program must not be bigger than + * 65535 bytes, as 16 bit pointers are used. Who would ever need a bigger + * program :-) + * 2. Function names. All local functions that has been defined or called, + * with the address of the function in the program. Inherited functions + * will be found here too, with information of how far up the inherit + * chain that the function was defined. + * 3. String table. All strings used in the program. They are all pointers + * into the shared string area. Thus, they are easily found and deallocated + * when the object is destructed. + * 4. Table of variable names. They all point into the shared string table. + * 5. Line number information. A table which tells at what address every + * line belongs to. The table has the same number of entries as the + * programs has source lines. This is used at errors, to find out the + * line number of the error. This is usually swapped out to save space. + * First entry is the length of the table. + * 6. List of inherited objects. + */ + +/* + * When a new object inherits from another, all function definitions + * are copied, and all variable definitions. + * Flags below can't explicitly declared. Flags that can be declared, + * are found with TYPE_ below. + * + * When an object is compiled with type testing NAME_STRICT_TYPES, all + * types are saved of the arguments for that function during compilation. + * If the #pragma save_types is specified, then the types are saved even + * after compilation, to be used when the object is inherited. + */ + +/* The semantics of the flags are currently as follows: + + (1) A function is either a definition, a prototype or an undefined + function + + (2) A definition is an address that executes code when + it is jumped to and finishes with a return. + The address is labeled by the following info: + function name, type, flags,number of arguments, number of locals, + argument types. + + (3) A prototype does not execute code, and is basically a label with + the following info: + argument types (optionally also argument names),function name, + type, flags, number of arguments + + (4) An undefined function is an unknown function that has been called or + a label that is as yet not known to be a prototype or definition + + Note that the above rules apply to comments in compiler.c as well. + In particular, a known prototype is not undefined. When 'function' + by itself is used, (1) is always meant. + + FUNC_INHERITED - The function entry that exists in this object actually + is a function in an object we inherited + FUNC_UNDEFINED - see (4) + FUNC_STRICT_TYPES - compiled with strict type testing + FUNC_PROTOTYPE - see (3) + FUNC_ALIAS - This entry refers us to another entry, usually because + this function was overloaded by that function + + Sym + */ +#define FUNC_INHERITED 0x0001 +#define FUNC_UNDEFINED 0x0002 +#define FUNC_STRICT_TYPES 0x0004 +#define FUNC_PROTOTYPE 0x0008 +#define FUNC_TRUE_VARARGS 0x0010 +#define FUNC_VARARGS 0x0020 +#define FUNC_ALIAS 0x8000 /* This shouldn't be changed */ + +#define DECL_HIDDEN 0x0100 /* used by private vars */ +#define DECL_PRIVATE 0x0200 /* Can't be inherited */ +#define DECL_PROTECTED 0x0400 /* Static function or variable */ +#define DECL_PUBLIC 0x0800 +#define DECL_NOMASK 0x1000 /* The nomask => not redefineable */ +#define DECL_NOSAVE 0x2000 +#ifndef SENSIBLE_MODIFIERS +#define DECL_VISIBLE 0x4000 /* Force inherit through private */ + +#define DECL_ACCESS (DECL_HIDDEN | DECL_PRIVATE | DECL_PROTECTED | DECL_PUBLIC | DECL_VISIBLE) + +#define DECL_MODIFY(x,y) ((((x)|(y))&DECL_VISIBLE) ? ((((x)|(y))&~DECL_ACCESS)|DECL_VISIBLE) : DECL_MODIFY2(x,y)) +#else +#define DECL_ACCESS (DECL_HIDDEN | DECL_PRIVATE | DECL_PROTECTED | DECL_PUBLIC) + +#define DECL_MODIFY(x,y) DECL_MODIFY2(x,y) +#endif +#define DECL_MODS (DECL_ACCESS | DECL_NOMASK | DECL_NOSAVE) + +#define DECL_MODIFY2(t, mod) ((((t) & DECL_ACCESS) > ((mod) & DECL_ACCESS)) ? ((t) & ~DECL_ACCESS) | (mod) : (t) | ((mod) & ~DECL_ACCESS)) + +/* only the flags that should be copied up through inheritance levels */ +#define FUNC_MASK (FUNC_VARARGS | FUNC_UNDEFINED | FUNC_STRICT_TYPES | FUNC_PROTOTYPE | FUNC_TRUE_VARARGS | FUNC_ALIAS | DECL_MODS) + +/* a function that isn't 'real' */ +#define FUNC_NO_CODE (FUNC_ALIAS | FUNC_PROTOTYPE | FUNC_UNDEFINED) +#define REAL_FUNCTION(x) (!((x) & (FUNC_ALIAS | FUNC_PROTOTYPE))) + +/* + * These are or'ed in on top of the basic type. + */ + +/* Note, the following restricts class_num to < 0x40 or 64 */ +/* The reason for this is that vars still have a ushort type */ +/* This restriction is not unreasonable, since LPC is still */ +/* catered for mini-applications (compared to say, C++ or */ +/* java)..for now - Sym */ + +#define TYPE_MOD_ARRAY 0x0040 /* Pointer to a basic type */ +#define TYPE_MOD_CLASS 0x0080 /* a class */ +#define CLASS_NUM_MASK 0x003f + +#define LOCAL_MOD_REF 0x0100 +#define LOCAL_MOD_UNUSED 0x0200 + +#define LOCAL_MODS (LOCAL_MOD_UNUSED|LOCAL_MOD_REF) + +typedef struct { + unsigned char num_arg; + unsigned char num_local; + unsigned short f_index; /* Index in sorted function table */ +} runtime_defined_t; + +typedef struct { + unsigned short offset; + unsigned short function_index_offset; +} runtime_inherited_t; + +typedef union { + runtime_defined_t def; + runtime_inherited_t inh; +} runtime_function_u; + +typedef struct { + unsigned short first_defined; + unsigned short first_overload; + unsigned short num_compressed; + unsigned short num_deleted; + unsigned char index[1]; +} compressed_offset_table_t; + +#ifdef USE_32BIT_ADDRESSES +#define ADDRESS_TYPE unsigned int +#define ADDRESS_MAX UINT_MAX +#else +#define ADDRESS_TYPE unsigned short +#define ADDRESS_MAX USHRT_MAX +#endif + +typedef struct { + char *funcname; + unsigned short type; + unsigned char num_arg; + unsigned char num_local; + ADDRESS_TYPE address; +#ifdef PROFILE_FUNCTIONS + unsigned long calls, self, children; +#endif +} function_t; + +typedef struct { + unsigned short classname; + unsigned short type; + unsigned short size; + unsigned short index; +} class_def_t; + +typedef struct { + unsigned short membername; + unsigned short type; +} class_member_entry_t; + +typedef struct { + char *name; + unsigned short type; /* Type of variable. See above. TYPE_ */ +} variable_t; + +typedef struct { + struct program_s *prog; + unsigned short function_index_offset; + unsigned short variable_index_offset; + unsigned short type_mod; +} inherit_t; + +typedef struct program_s { + const char *filename; /* Name of file that defined prog */ + unsigned short flags; + unsigned short last_inherited; + unsigned PROG_REF_TYPE ref; /* Reference count */ + unsigned short func_ref; +#ifdef DEBUG + int extra_ref; /* Used to verify ref count */ + int extra_func_ref; +#endif + char *program; /* The binary instructions */ + unsigned char *line_info; /* Line number information */ + unsigned short *file_info; + int line_swap_index; /* Where line number info is swapped */ + function_t *function_table; + unsigned short *function_flags; /* separate for alignment reasons */ + class_def_t *classes; + class_member_entry_t *class_members; + char **strings; /* All strings uses by the program */ + char **variable_table; /* variables defined by this program */ + unsigned short *variable_types; /* variables defined by this program */ + inherit_t *inherit; /* List of inherited prgms */ + int total_size; /* Sum of all data in this struct */ + /* + * The types of function arguments are saved where 'argument_types' + * points. It can be a variable number of arguments, so allocation is + * done dynamically. To know where first argument is found for function + * 'n' (number of function), use 'type_start[n]'. These two arrays will + * only be allocated if '#pragma save_types' has been specified. This + * #pragma should be specified in files that are commonly used for + * inheritance. There are several lines of code that depends on the type + * length (16 bits) of 'type_start' (sorry !). + */ + unsigned short *argument_types; +#define INDEX_START_NONE 65535 + unsigned short *type_start; + /* + * And now some general size information. + */ + unsigned short heart_beat; /* Index of the heart beat function. 0 means + * no heart beat */ + unsigned short program_size;/* size of this instruction code */ + unsigned short num_classes; + unsigned short num_functions_defined; + unsigned short num_strings; + unsigned short num_variables_total; + unsigned short num_variables_defined; + unsigned short num_inherited; +} program_t; + +extern int total_num_prog_blocks; +extern int total_prog_block_size; +void reference_prog (program_t *, const char *); +void free_prog (program_t **); +void deallocate_program (program_t *); +char *variable_name (program_t *, int); +function_t *find_func_entry (program_t *, int); + +#endif + + diff --git a/fluffos-2.23-ds03/qsort.c b/fluffos-2.23-ds03/qsort.c new file mode 100644 index 0000000..4d62706 --- /dev/null +++ b/fluffos-2.23-ds03/qsort.c @@ -0,0 +1,59 @@ +/* median-3 variant of quicksort - coded by John Garnett. + + using this quicksort rather than the builtin one because most + builtin implementations choke on non-deterministic compare functions + (and we can't control what compare function is used since it is at + the mudlib level). Based on algorithm appearing in _Data Structures and + Algorithm Analysis_ by Cawnthorpe. +*/ + +#include "std.h" +#include "qsort.h" + +#define LEN sizeof(svalue_t) +#define MAX_LEN 1000 + +INLINE_STATIC void doSwap (char *, char *, int); +static void qSort (void *, int, int, int, int, int (*) ()); + +INLINE_STATIC void doSwap (register char * one, register char * two, + register int size) +{ + register char t; + + while (size--) { + t = *one; + *(one++) = *two; + *(two++) = t; + } +} + +/* qsort adapted from page 87 of K&R 2nd edition */ + +static void qSort(void *v, int left, int right, int size, int rightmost, int (*compar) (void *, void *)) +{ + int i, last, szleft; + + if ((left >= right) || (left < 0) || (right > rightmost) || (right < 0)) { + return; + } + szleft = size * left; + doSwap((char *) v + szleft, (char *) v + (size * ((left + right) / 2)), size); + last = left; + for (i = left + 1; i <= right; i++) { + if ((*compar) ((char *) v + (size * i), (char *) v + szleft) < 0) { + doSwap((char *) v + (size * ++last), (char *) v + (size * i), size); + } + } + doSwap((char *) v + szleft, (char *) v + (size * last), size); + qSort(v, left, last - 1, size, rightmost, compar); + qSort(v, last + 1, right, size, rightmost, compar); +} + +void quickSort(void *a, int nmemb, int size, int (*compar) (void *, void *)) +{ + if (nmemb < 2) { + return; + } + qSort(a, 0, nmemb - 1, size, nmemb - 1, compar); +} diff --git a/fluffos-2.23-ds03/qsort.h b/fluffos-2.23-ds03/qsort.h new file mode 100644 index 0000000..1575c7c --- /dev/null +++ b/fluffos-2.23-ds03/qsort.h @@ -0,0 +1,9 @@ +#ifndef QSORT_H +#define QSORT_H + +/* + * qsort.c + */ +void quickSort (void *, int, int, int (*) (void *, void *)); + +#endif diff --git a/fluffos-2.23-ds03/rc.c b/fluffos-2.23-ds03/rc.c new file mode 100644 index 0000000..2354b6b --- /dev/null +++ b/fluffos-2.23-ds03/rc.c @@ -0,0 +1,383 @@ +/* + * rc.c + * description: runtime configuration for lpmud + * author: erikkay@mit.edu + * last modified: July 4, 1994 [robo] + * Mar 26, 1995: edited heavily by Beek + * Aug 29, 1998: modified by Gorta + */ + +#include "std.h" +#include "rc.h" +#include "include/runtime_config.h" +#include "main.h" + +#define MAX_LINE_LENGTH 120 + +char *config_str[NUM_CONFIG_STRS]; +int config_int[NUM_CONFIG_INTS]; + +static char *buff; +static int buff_size; + +static void read_config_file (FILE *); +static int scan_config_line (const char *, void *, int); +static void config_init (void); /* don't ask */ + +static void config_init() { + int i; + + for (i = 0; i < NUM_CONFIG_INTS; i++) { + config_int[i] = 0; + } + for (i = 0; i < NUM_CONFIG_STRS; i++) { + config_str[i] = 0; + } + +} + +static void read_config_file (FILE * file) +{ + char str[MAX_LINE_LENGTH * 4]; + int size = 2, len, tmp; + char *p; + + buff_size = MAX_LINE_LENGTH * (NUM_CONFIG_INTS + 1) * (NUM_CONFIG_STRS + 1); + p = buff = CALLOCATE(buff_size, char, TAG_CONFIG, "read_config_file: 1"); + *p++ = '\n'; + + while (1) { + if (fgets(str, MAX_LINE_LENGTH * 4, file) == NULL) + break; + len = strlen(str); /* ACK! */ + if (len > MAX_LINE_LENGTH) { + fprintf(stderr, "*Error in config file: line too long:\n%s...\n", str); + exit(-1); + } + if (str[0] != '#' && str[0] != '\n') { + size += len + 1; + if (size > buff_size) { + tmp = p - buff; + buff = RESIZE(buff, buff_size *= 2, char, + TAG_CONFIG, "read_config_file: 2"); + p = buff + tmp; + } + strncpy(p, str, len); + p += len; + *p++ = '\n'; + } + } + *p = 0; +} + + +/* + * If the required flag is 0, it will only give a warning if the line is + * missing from the config file. Otherwise, it will give an error and exit + * if the line isn't there. + */ +/* required: + 1 : Must have + 0 : optional + -1 : warn if missing */ +static int scan_config_line (const char * fmt, void * dest, int required) +{ + char *tmp, *end; + char missing_line[MAX_LINE_LENGTH]; + + /* zero the destination. It is either a pointer to an int or a char + buffer, so this will work */ + *((int *)dest) = 0; + tmp = buff; + while (tmp) { + while ((tmp = (char *) strchr(tmp, '\n'))) { + if (*(++tmp) == fmt[0]) break; + } + /* don't allow sscanf() to scan to next line for blank entries */ + end = (tmp ? strchr(tmp, '\n') : 0); + if (end) *end = '\0'; + if (tmp && sscanf(tmp, fmt, dest) == 1) { + if (end) *end = '\n'; + break; + } + if (end) *end = '\n'; + } + if (!tmp) { + strcpy(missing_line, fmt); + tmp = (char *) strchr(missing_line, ':'); + *tmp = '\0'; + if (required == -1) { + fprintf(stderr, "*Warning: Missing line in config file:\n\t%s\n", + missing_line); + return 0; + } + if (!required) return 0; + fprintf(stderr, "*Error in config file. Missing line:\n\t%s\n", + missing_line); + exit(-1); + } + return 1; +} + +#if 0 +static char *process_config_string(char *str) { + char *p = str; + char *q; + int n; + + while (*p && isspace(*p)) + p++; + n = strlen(p); + if (!n) return alloc_cstring("", "config_file: blank string"); + + q = p + n - 1; + while (q > p && isspace(*q)) + q--; + q[1] = 0; + return alloc_cstring(p, "process_config_string()"); +} +#endif + +void set_defaults (char * filename) +{ + FILE *def; + char defaults[SMALL_STRING_SIZE]; + char *p; + char tmp[MAX_LINE_LENGTH]; + char kind[MAX_LINE_LENGTH]; + int i, port, port_start = 0; + + max_string_length = 120; /* needed for string_copy() below */ + config_init(); + def = fopen(filename, "r"); + if (def) { + fprintf(stderr, "using config file: %s\n", filename); + } else { + sprintf(defaults, "%s/%s", CONFIG_FILE_DIR, filename); + def = fopen(defaults, "r"); + if (def) { + fprintf(stderr, "using config file: %s\n", defaults); + } + } + if (!def) { + fprintf(stderr, "*Error: couldn't find or open config file: '%s'\n", filename); + exit(-1); + } + read_config_file(def); + + scan_config_line("global include file : %[^\n]", tmp, 0); + p = CONFIG_STR(__GLOBAL_INCLUDE_FILE__) = alloc_cstring(tmp, "config file: gif"); + + /* check if the global include file is quoted */ + if (*p && *p != '"' && *p != '<') { + char *ptr; + + fprintf(stderr, "Missing '\"' or '<' around global include file name; adding quotes.\n"); + for (ptr = p; *ptr; ptr++) + ; + ptr[2] = 0; + ptr[1] = '"'; + while (ptr > p) { + *ptr = ptr[-1]; + ptr--; + } + *p = '"'; + } + + scan_config_line("name : %[^\n]", tmp, 1); + CONFIG_STR(__MUD_NAME__) = alloc_cstring(tmp, "config file: mn"); + scan_config_line("address server ip : %[^\n]", tmp, 0); + CONFIG_STR(__ADDR_SERVER_IP__) = alloc_cstring(tmp, "config file: asi"); + + scan_config_line("mudlib directory : %[^\n]", tmp, 1); + CONFIG_STR(__MUD_LIB_DIR__) = alloc_cstring(tmp, "config file: mld"); + scan_config_line("binary directory : %[^\n]", tmp, 1); + CONFIG_STR(__BIN_DIR__) = alloc_cstring(tmp, "config file: bd"); + + scan_config_line("log directory : %[^\n]", tmp, 1); + CONFIG_STR(__LOG_DIR__) = alloc_cstring(tmp, "config file: ld"); + scan_config_line("include directories : %[^\n]", tmp, 1); + CONFIG_STR(__INCLUDE_DIRS__) = alloc_cstring(tmp, "config file: id"); + scan_config_line("master file : %[^\n]", tmp, 1); + CONFIG_STR(__MASTER_FILE__) = alloc_cstring(tmp, "config file: mf"); + scan_config_line("simulated efun file : %[^\n]", tmp, 0); + CONFIG_STR(__SIMUL_EFUN_FILE__) = alloc_cstring(tmp, "config file: sef"); + scan_config_line("swap file : %[^\n]", tmp, 1); + CONFIG_STR(__SWAP_FILE__) = alloc_cstring(tmp, "config file: sf"); + scan_config_line("debug log file : %[^\n]", tmp, -1); + CONFIG_STR(__DEBUG_LOG_FILE__) = alloc_cstring(tmp, "config file: dlf"); + + scan_config_line("default error message : %[^\n]", tmp, 0); + CONFIG_STR(__DEFAULT_ERROR_MESSAGE__) = alloc_cstring(tmp, "config file: dem"); + scan_config_line("default fail message : %[^\n]", tmp, 0); + CONFIG_STR(__DEFAULT_FAIL_MESSAGE__) = alloc_cstring(tmp, "config file: dfm"); + + scan_config_line("mud ip : %[^\n]", tmp, 0); + CONFIG_STR(__MUD_IP__) = alloc_cstring(tmp, "config file: mi"); + + if (scan_config_line("fd6 kind : %[^\n]", tmp, 0)) { + if (!strcasecmp(tmp, "telnet")) + FD6_KIND = PORT_TELNET; + else if (!strcasecmp(tmp, "mud")) + FD6_KIND = PORT_MUD; + else if (!strcasecmp(tmp, "ascii")) + FD6_KIND = PORT_ASCII; + else if (!strcasecmp(tmp, "binary")) + FD6_KIND = PORT_BINARY; + else { + fprintf(stderr, "Unknown port type for fd6 kind. fd6 support disabled.\n"); + FD6_KIND = PORT_UNDEFINED; + } + } else { + FD6_KIND = PORT_UNDEFINED; + } + + if (scan_config_line("port number : %d\n", &CONFIG_INT(__MUD_PORT__), 0)) { + external_port[0].port = PORTNO; + external_port[0].kind = PORT_TELNET; + port_start = 1; + } + + scan_config_line("address server port : %d\n", + &CONFIG_INT(__ADDR_SERVER_PORT__), 0); + + scan_config_line("fd6 port : %d\n", &CONFIG_INT(__FD6_PORT__), 0); + + scan_config_line("time to clean up : %d\n", + &CONFIG_INT(__TIME_TO_CLEAN_UP__), 1); + scan_config_line("time to reset : %d\n", + &CONFIG_INT(__TIME_TO_RESET__), 1); + scan_config_line("time to swap : %d\n", + &CONFIG_INT(__TIME_TO_SWAP__), 1); + +#if 0 + /* + * not currently used...see options.h + */ + scan_config_line("evaluator stack size : %d\n", + &CONFIG_INT(__EVALUATOR_STACK_SIZE__), 0); + scan_config_line("maximum local variables : %d\n", + &CONFIG_INT(__MAX_LOCAL_VARIABLES__), 0); + scan_config_line("maximum call depth : %d\n", + &CONFIG_INT(__MAX_CALL_DEPTH__), 0); + scan_config_line("living hash table size : %d\n", + &CONFIG_INT(__LIVING_HASH_TABLE_SIZE__), 0); +#endif + + scan_config_line("inherit chain size : %d\n", + &CONFIG_INT(__INHERIT_CHAIN_SIZE__), 1); + scan_config_line("maximum evaluation cost : %d\n", + &CONFIG_INT(__MAX_EVAL_COST__), 1); + + scan_config_line("maximum array size : %d\n", + &CONFIG_INT(__MAX_ARRAY_SIZE__), 1); +#ifndef NO_BUFFER_TYPE + scan_config_line("maximum buffer size : %d\n", + &CONFIG_INT(__MAX_BUFFER_SIZE__), 1); +#endif + scan_config_line("maximum mapping size : %d\n", + &CONFIG_INT(__MAX_MAPPING_SIZE__), 1); + scan_config_line("maximum string length : %d\n", + &CONFIG_INT(__MAX_STRING_LENGTH__), 1); + scan_config_line("maximum bits in a bitfield : %d\n", + &CONFIG_INT(__MAX_BITFIELD_BITS__), 1); + + scan_config_line("maximum byte transfer : %d\n", + &CONFIG_INT(__MAX_BYTE_TRANSFER__), 1); + scan_config_line("maximum read file size : %d\n", + &CONFIG_INT(__MAX_READ_FILE_SIZE__), 1); + + scan_config_line("reserved size : %d\n", + &CONFIG_INT(__RESERVED_MEM_SIZE__), 0); + + scan_config_line("hash table size : %d\n", + &CONFIG_INT(__SHARED_STRING_HASH_TABLE_SIZE__), 1); + scan_config_line("object table size : %d\n", + &CONFIG_INT(__OBJECT_HASH_TABLE_SIZE__), 1); + + /* check for ports */ + if (port_start == 1) { + if (scan_config_line("external_port_1 : %[^\n]", tmp, 0)) { + int port = CONFIG_INT(__MUD_PORT__); + fprintf(stderr, "Warning: external_port_1 already defined to be 'telnet %i' by the line\n 'port number : %i'; ignoring the line 'external_port_1 : %s'\n", port, port, tmp); + } + } + for (i = port_start; i < 5; i++) { + external_port[i].kind = 0; + external_port[i].fd = -1; + sprintf(kind, "external_port_%i : %%[^\n]", i + 1); + if (scan_config_line(kind, tmp, 0)) { + if (sscanf(tmp, "%s %d", kind, &port) == 2) { + external_port[i].port = port; + if (!strcmp(kind, "telnet")) + external_port[i].kind = PORT_TELNET; + else + if (!strcmp(kind, "binary")) { +#ifdef NO_BUFFER_TYPE + fprintf(stderr, "binary ports unavailable with NO_BUFFER_TYPE defined.\n"); + exit(-1); +#endif + external_port[i].kind = PORT_BINARY; + } else + if (!strcmp(kind, "ascii")) + external_port[i].kind = PORT_ASCII; + else + if (!strcmp(kind, "MUD")) + external_port[i].kind = PORT_MUD; + else + { + fprintf(stderr, "Unknown kind of external port: %s\n", + kind); + exit(-1); + } + } else { + fprintf(stderr, "Syntax error in port specification\n"); + exit(-1); + } + } + } +#ifdef PACKAGE_EXTERNAL + /* check for commands */ + for (i = 0; i < NUM_EXTERNAL_CMDS; i++) { + sprintf(kind, "external_cmd_%i : %%[^\n]", i + 1); + if (scan_config_line(kind, tmp, 0)) + external_cmd[i] = alloc_cstring(tmp, "external cmd"); + else + external_cmd[i] = 0; + } +#endif + + FREE(buff); + fclose(def); + + /* + * from options.h + */ + config_int[__EVALUATOR_STACK_SIZE__ - BASE_CONFIG_INT] = CFG_EVALUATOR_STACK_SIZE; + config_int[__MAX_LOCAL_VARIABLES__ - BASE_CONFIG_INT] = CFG_MAX_LOCAL_VARIABLES; + config_int[__MAX_CALL_DEPTH__ - BASE_CONFIG_INT] = CFG_MAX_CALL_DEPTH; + config_int[__LIVING_HASH_TABLE_SIZE__ - BASE_CONFIG_INT] = CFG_LIVING_HASH_SIZE; +} + +int get_config_item (svalue_t * res, svalue_t * arg) +{ + int num; + + num = arg->u.number; + + if (num < 0 || num >= RUNTIME_CONFIG_NEXT) { + return 0; + } + if (num >= BASE_CONFIG_INT) { + res->type = T_NUMBER; + res->u.number = config_int[num - BASE_CONFIG_INT]; + } else { + if(!config_str[num]) //obsolete value, less muds break if we don't renumber! + return 0; + res->type = T_STRING; + res->subtype = STRING_CONSTANT; + res->u.string = config_str[num]; + } + + return 1; +} diff --git a/fluffos-2.23-ds03/rc.h b/fluffos-2.23-ds03/rc.h new file mode 100644 index 0000000..cfae86e --- /dev/null +++ b/fluffos-2.23-ds03/rc.h @@ -0,0 +1,15 @@ +#ifndef RC_H +#define RC_H + +#include "lpc_incl.h" + +/* + * rc.c + */ + +void set_defaults (char *); +int get_config_int (int); +char *get_config_str (int); +int get_config_item (svalue_t *, svalue_t *); + +#endif diff --git a/fluffos-2.23-ds03/reclaim.c b/fluffos-2.23-ds03/reclaim.c new file mode 100644 index 0000000..d464454 --- /dev/null +++ b/fluffos-2.23-ds03/reclaim.c @@ -0,0 +1,125 @@ +/* + * reclaim.c + * loops through all variables in all objects looking for the possibility + * of freeing up destructed objects (that are still hanging around because + * of references) -- coded by Blackthorn@Genocide Feb. 1993 + */ + +#include "std.h" +#include "lpc_incl.h" +#include "reclaim.h" +#include "call_out.h" + +#define MAX_RECURSION 25 + +static void gc_mapping (mapping_t *); +static void check_svalue (svalue_t *); + +static int cleaned, nested; + +static void +check_svalue (svalue_t * v) +{ + register int idx; + + nested++; + if (nested > MAX_RECURSION) { + return; + } + switch (v->type) { + case T_OBJECT: + if (v->u.ob->flags & O_DESTRUCTED) { + free_svalue(v, "reclaim_objects"); + *v = const0u; + cleaned++; + } + break; + case T_MAPPING: + gc_mapping(v->u.map); + break; + case T_ARRAY: + case T_CLASS: + for (idx = 0; idx < v->u.arr->size; idx++) + check_svalue(&v->u.arr->item[idx]); + break; + case T_FUNCTION: + { + svalue_t tmp; + program_t *prog; + + if (v->u.fp->hdr.owner && (v->u.fp->hdr.owner->flags & O_DESTRUCTED)) { + if (v->u.fp->hdr.type == (FP_LOCAL | FP_NOT_BINDABLE)) { + prog = v->u.fp->hdr.owner->prog; + prog->func_ref--; + debug(d_flag, ("subtr func ref /%s: now %i\n", + prog->filename, prog->func_ref)); + if (!prog->ref && !prog->func_ref) + deallocate_program(prog); + } + free_object(&v->u.fp->hdr.owner, "reclaim_objects"); + v->u.fp->hdr.owner = 0; + cleaned++; + } + + tmp.type = T_ARRAY; + if ((tmp.u.arr = v->u.fp->hdr.args)) + check_svalue(&tmp); + break; + } + } + nested--; + return; +} + +static void +gc_mapping (mapping_t * m) +{ + /* Be careful to correctly handle destructed mapping keys. We can't + * just call check_svalue() b/c the hash would be wrong and the '0' + * element we add would be unreferenceable (in most cases) + */ + mapping_node_t **prev, *elt; + int j = m->table_size; + + do { + prev = m->table + j; + while ((elt = *prev)) { + if (elt->values[0].type == T_OBJECT) { + if (elt->values[0].u.ob->flags & O_DESTRUCTED) { + free_object(&elt->values[0].u.ob, "gc_mapping"); + elt->values[0].u.ob = 0; + /* found one, do a map_delete() */ + if (!(*prev = elt->next) && !m->table[j]) + m->unfilled++; + cleaned++; + m->count--; + total_mapping_nodes--; + total_mapping_size -= sizeof(mapping_node_t); + free_node(m, elt); + continue; + } + } else { + /* in case the key is a mapping or something */ + check_svalue(elt->values); + } + check_svalue(elt->values+1); + prev = &(elt->next); + } + } while (j--); +} + +int reclaim_objects() +{ + int i; + object_t *ob; + + reclaim_call_outs(); + + cleaned = nested = 0; + for (ob = obj_list; ob; ob = ob->next_all) + if (ob->prog) + for (i = 0; i < ob->prog->num_variables_total; i++) + check_svalue(&ob->variables[i]); + + return cleaned; +} diff --git a/fluffos-2.23-ds03/reclaim.h b/fluffos-2.23-ds03/reclaim.h new file mode 100644 index 0000000..7ad4a23 --- /dev/null +++ b/fluffos-2.23-ds03/reclaim.h @@ -0,0 +1,9 @@ +#ifndef RECLAIM_H +#define RECLAIM_H + +/* + * reclaim.c + */ +int reclaim_objects (void); + +#endif diff --git a/fluffos-2.23-ds03/regexp.c b/fluffos-2.23-ds03/regexp.c new file mode 100644 index 0000000..9474edd --- /dev/null +++ b/fluffos-2.23-ds03/regexp.c @@ -0,0 +1,1418 @@ +/* + * + * regexp.c - regular expression matching + * + * DESCRIPTION + * + * Underneath the reformatting and comment blocks which were added to + * make it consistent with the rest of the code, you will find a + * modified version of Henry Specer's regular expression library. + * Henry's functions were modified to provide the minimal regular + * expression matching, as required by P1003. Henry's code was + * copyrighted, and copy of the copyright message and restrictions + * are provided, verbatim, below: + * + * Copyright (c) 1986 by University of Toronto. + * Written by Henry Spencer. Not derived from licensed software. + * + * Permission is granted to anyone to use this software for any + * purpose on any computer system, and to redistribute it freely, + * subject to the following restrictions: + * + * 1. The author is not responsible for the consequences of use of + * this software, no matter how awful, even if they arise + * from defects in it. + * + * 2. The origin of this software must not be misrepresented, either + * by explicit claim or by omission. + * + * 3. Altered versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * + * This version modified by Ian Phillipps to return pointer to terminating + * NUL on substitution string. [ Temp mail address ex-igp@camcon.co.uk ] + * + * Altered by amylaar to support excompatible option and the + * operators \< and >\ . ( 7.Sep. 1991 ) + * + * regsub altered by amylaar to take an additional parameter specifying + * maximum number of bytes that can be written to the memory region + * pointed to by dest + * + * Beware that some of this code is subtly aware of the way operator + * precedence is structured in regular expressions. Serious changes in + * regular-expression syntax might require a total rethink. + * + * AUTHORS + * + * Mark H. Colburn, NAPS International (mark@jhereg.mn.org) + * Henry Spencer, University of Torronto (henry@utzoo.edu) + * + * Sponsored by The USENIX Association for public distribution. + * + */ + +/* Headers */ + +#include "std.h" +#include "regexp.h" +#include "lpc_incl.h" +#include "comm.h" +#include "ed.h" + +/* + * The "internal use only" fields in regexp.h are present to pass info from + * compile to execute that permits the execute phase to run lots faster on + * simple cases. They are: + * + * regstart char that must begin a match; '\0' if none obvious + * reganch is the match anchored (at beginning-of-line only)? + * regmust string (pointer into program) that match must include, or NULL + * regmlen length of regmust string + * + * Regstart and reganch permit very fast decisions on suitable starting points + * for a match, cutting down the work a lot. Regmust permits fast rejection + * of lines that cannot possibly match. The regmust tests are costly enough + * that regcomp() supplies a regmust only if the r.e. contains something + * potentially expensive (at present, the only such thing detected is * or + + * at the start of the r.e., which can involve a lot of backup). Regmlen is + * supplied because the test in regexec() needs it and regcomp() is computing + * it anyway. + */ + +/* + * The first byte of the regexp internal "program" is actually this magic + * number; the start node begins in the second byte. + */ +#define MAGIC 0234 + +/* + * Structure for regexp "program". This is essentially a linear encoding + * of a nondeterministic finite-state machine (aka syntax charts or + * "railroad normal form" in parsing technology). Each node is an opcode + * plus a "nxt" pointer, possibly plus an operand. "Nxt" pointers of + * all nodes except BRANCH implement concatenation; a "nxt" pointer with + * a BRANCH on both ends of it is connecting two alternatives. (Here we + * have one of the subtle syntax dependencies: an individual BRANCH (as + * opposed to a collection of them) is never concatenated with anything + * because of operator precedence.) The operand of some types of node is + * a literal string; for others, it is a node leading into a sub-FSM. In + * particular, the operand of a BRANCH node is the first node of the branch. + * (NB this is *not* a tree structure: the tail of the branch connects + * to the thing following the set of BRANCHes.) The opcodes are: + */ + +/* definition number opnd? meaning */ +#define END 0 /* no End of program. */ +#define BOL 1 /* no Match "" at beginning of line. */ +#define EOL 2 /* no Match "" at end of line. */ +#define ANY 3 /* no Match any one character. */ +#define ANYOF 4 /* str Match any character in this string. */ +#define ANYBUT 5 /* str Match any character not in this + * string. */ +#define BRANCH 6 /* node Match this alternative, or the nxt... */ +#define BACK 7 /* no Match "", "nxt" ptr points backward. */ +#define EXACTLY 8 /* str Match this string. */ +#define NOTHING 9 /* no Match empty string. */ +#define STAR 10 /* node Match this (simple) thing 0 or more + * times. */ +#define PLUS 11 /* node Match this (simple) thing 1 or more + * times. */ +#define WORDSTART 12 /* node matching a start of a word */ +#define WORDEND 13 /* node matching an end of a word */ +#define OPEN 20 /* no Mark this point in input as start of + * #n. */ + /* OPEN+1 is number 1, etc. */ +#define CLOSE 30 /* no Analogous to OPEN. */ + +/* + * Opcode notes: + * + * BRANCH The set of branches constituting a single choice are hooked + * together with their "nxt" pointers, since precedence prevents + * anything being concatenated to any individual branch. The + * "nxt" pointer of the last BRANCH in a choice points to the + * thing following the whole choice. This is also where the + * final "nxt" pointer of each individual branch points; each + * branch starts with the operand node of a BRANCH node. + * + * BACK Normal "nxt" pointers all implicitly point forward; BACK + * exists to make loop structures possible. + * + * STAR,PLUS '?', and complex '*' and '+', are implemented as circular + * BRANCH structures using BACK. Simple cases (one character + * per match) are implemented with STAR and PLUS for speed and + * to minimize recursive * plunges. + * + * OPEN,CLOSE ...are numbered at compile time. + */ + +/* + * A node is one char of opcode followed by two chars of "nxt" pointer. + * "Nxt" pointers are stored as two 8-bit pieces, high order first. The + * value is a positive offset from the opcode of the node containing it. + * An operand, if any, simply follows the node. (Note that much of the + * code generation knows about this implicit relationship.) + * + * Using two bytes for the "nxt" pointer is vast overkill for most things, + * but allows patterns to get big without disasters. + */ +#define OP(p) (*(p)) +/* stralloc.h */ +#undef NEXT +#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377)) +#define OPERAND(p) ((p) + 3) + +/* + * Utility definitions. + */ + +#define SPECIAL 0x100 +#define LBRAC ('('|SPECIAL) +#define RBRAC (')'|SPECIAL) +#define ASTERIX ('*'|SPECIAL) +#define PLUSS ('+'|SPECIAL) +#define QMARK ('?'|SPECIAL) +#define OR_OP ('|'|SPECIAL) +#define DOLLAR ('$'|SPECIAL) +#define DOT ('.'|SPECIAL) +#define CARET ('^'|SPECIAL) +#define LSQBRAC ('['|SPECIAL) +#define RSQBRAC (']'|SPECIAL) +#define LSHBRAC ('<'|SPECIAL) +#define RSHBRAC ('>'|SPECIAL) + +#define FAIL(m) { regerror(m); return(NULL); } +#define ISMULT(c) ((c) == ASTERIX || (c) == PLUSS || (c) == QMARK) +#define META "^$.[()|?+*\\" + +/* Linux seems to define CHARBITS to 8 in values.h; not sure what system + * defines CHARBITS in a form we can use or how to tell (check in configure?) + * Just use 8 bits for now. + */ +#if 0 +#if defined(linux) +# ifndef CHARBITS +# define CHARBITS 0xff +# endif +# define UCHARAT(p) (*(unsigned char *)(p)) +#else +# ifndef CHARBITS +# define CHARBITS 0xff +# define UCHARAT(p) (*(unsigned char *)(p)) +# else +# define UCHARAT(p) (*(p)&CHARBITS) +# endif +#endif +#else +# undef CHARBITS +# define CHARBITS 0xff +# define UCHARAT(p) (*(unsigned char *)(p)) +#endif + +#define ISWORDPART(c) ( isalnum((unsigned char)c) || (c) == '_' ) + +/* + * Flags to be passed up and down. + */ +#define HASWIDTH 01 /* Known never to match null string. */ +#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */ +#define SPSTART 04 /* Starts with * or +. */ +#define WORST 0 /* Worst case. */ + +/* + * Global work variables for regcomp(). + */ +int regexp_user; +const char *regexp_error; + +static short *regparse; /* Input-scan pointer. */ +static int regnpar; /* () count. */ +static char regdummy; +static char *regcode; /* Code-emit pointer; ®dummy = don't. */ +static int regsize; /* Code size. */ + +/* + * Forward declarations for regcomp()'s friends. + */ +#ifndef STATIC +#define STATIC static +#endif +STATIC char *reg (int, int *); +STATIC char *regbranch (int *); +STATIC char *regpiece (int *); +STATIC char *regatom (int *); +STATIC char *regnode (char); +STATIC char *regnext (char *); +STATIC void regc (char); +STATIC void reginsert (char, char *); +STATIC void regtail (char *, char *); +STATIC void regoptail (char *, char *); + +#ifdef STRCSPN +STATIC int strcspn(); +#endif + +STATIC void regerror (const char * s) { + switch (regexp_user) { + case ED_REGEXP: + ED_OUTPUTV(ED_DEST, "ed: regular expression error: %s", s); + break; + case EFUN_REGEXP: + regexp_error = s; + break; + } +} + +/* + - regcomp - compile a regular expression into internal code + * + * We can't allocate space until we know how big the compiled form will be, + * but we can't compile it (and thus know how big it is) until we've got a + * place to put the code. So we cheat: we compile it twice, once with code + * generation turned off and size counting turned on, and once "for real". + * This also means that we don't allocate space until we are sure that the + * thing really will compile successfully, and we never have to move the + * code and thus invalidate pointers into it. (Note that it has to be in + * one piece because FREE() must be able to free it all.) + * + * Beware that the optimization-preparation code in here knows about some + * of the structure of the compiled regexp. + */ +regexp *regcomp (unsigned char * exp, + int excompat) /* \( \) operators like in unix ex */ +{ + register regexp *r; + register unsigned char *scan; + register char *longest; + register int len; + int flags; + short *exp2, *dest, c; + + if (!exp) + FAIL("NULL argument\n"); + + exp2 = (short *) + DXALLOC((strlen((char *)exp) + 1) * (sizeof(short[8]) / sizeof(char[8])), + TAG_TEMPORARY, "regcomp: 1"); + for (scan = exp, dest = exp2; (c = *scan++);) { + switch (c) { + case '(': + case ')': + *dest++ = excompat ? c : c | SPECIAL; + break; + case '.': + case '*': + case '+': + case '?': + case '|': + case '$': + case '^': + case '[': + case ']': + *dest++ = c | SPECIAL; + break; + case '\\': + switch (c = *scan++) { + case 0: + FREE(exp2); + FAIL("Regular expression cannot end with '\\'. Use \"\\\\\".\n"); + break; + case '(': + case ')': + *dest++ = excompat ? c | SPECIAL : c; + break; + case '<': + case '>': + *dest++ = c | SPECIAL; + break; + case '{': + case '}': + FREE(exp2); + FAIL("sorry, unimplemented operator\n"); + case 'b': + *dest++ = '\b'; + break; + case 't': + *dest++ = '\t'; + break; + case 'r': + *dest++ = '\r'; + break; + default: + *dest++ = c; + } + break; + default: + *dest++ = c; + } + } + *dest = 0; + /* First pass: determine size, legality. */ + regparse = exp2; + regnpar = 1; + regsize = 0L; + regcode = ®dummy; + regc((char) MAGIC); + if (reg(0, &flags) == (char *) NULL) { + FREE(exp2); + return ((regexp *) NULL); + } + + /* Small enough for pointer-storage convention? */ + if (regsize >= 32767L) /* Probably could be 65535L. */ + { + FREE(exp2); + FAIL("regexp too big\n"); + } + + /* Allocate space. */ + r = (regexp *) DXALLOC(sizeof(regexp) + (unsigned) regsize, + TAG_TEMPORARY, "regcomp: 2"); + if (r == (regexp *) NULL) { + FREE(exp2); + FAIL("out of space\n"); + } + + /* Second pass: emit code. */ + regparse = exp2; + regnpar = 1; + regcode = (char *)(r->program); + regc((char) MAGIC); + if (reg(0, &flags) == NULL) { + FREE(exp2); + FREE(r); + return ((regexp *) NULL); + } + + /* Dig out information for optimizations. */ + r->regstart = '\0'; /* Worst-case defaults. */ + r->reganch = 0; + r->regmust = NULL; + r->regmlen = 0; + scan = (unsigned char *)(r->program + 1); /* First BRANCH. */ + if (OP(regnext((char *)scan)) == END) { /* Only one top-level choice. */ + scan = OPERAND(scan); + + /* Starting-point info. */ + if (OP(scan) == EXACTLY) + r->regstart = *OPERAND(scan); + else if (OP(scan) == BOL) + r->reganch++; + + /* + * If there's something expensive in the r.e., find the longest + * literal string that must appear and make it the regmust. Resolve + * ties in favor of later strings, since the regstart check works + * with the beginning of the r.e. and avoiding duplication + * strengthens checking. Not a strong reason, but sufficient in the + * absence of others. + */ + if (flags & SPSTART) { + longest = NULL; + len = 0; + for (; scan != NULL; scan = (unsigned char *)regnext((char *)scan)) { + char *tmp = (char *)OPERAND(scan); + int tlen; + if (OP(scan) == EXACTLY && (tlen = strlen(tmp)) >= len) { + longest = tmp; + len = tlen; + } + } + r->regmust = longest; + r->regmlen = len; + } + } + FREE((char *) exp2); + return (r); +} + +/* + - reg - regular expression, i.e. main body or parenthesized thing + * + * Caller must absorb opening parenthesis. + * + * Combining parenthesis handling with the base level of regular expression + * is a trifle forced, but the need to tie the tails of the branches to what + * follows makes it hard to avoid. + */ +static char *reg (int paren, /* Parenthesized? */ + int * flagp) +{ + register char *ret; + register char *br; + register char *ender; + register int parno = 0; + int flags; + + *flagp = HASWIDTH; /* Tentatively. */ + + /* Make an OPEN node, if parenthesized. */ + if (paren) { + if (regnpar >= NSUBEXP) + FAIL("too many ()\n"); + parno = regnpar; + regnpar++; + ret = regnode(OPEN + parno); + } else + ret = (char *) NULL; + + /* Pick up the branches, linking them together. */ + br = regbranch(&flags); + if (br == (char *) NULL) + return ((char *) NULL); + if (ret != (char *) NULL) + regtail(ret, br); /* OPEN -> first. */ + else + ret = br; + if (!(flags & HASWIDTH)) + *flagp &= ~HASWIDTH; + *flagp |= flags & SPSTART; + while (*regparse == OR_OP) { + regparse++; + br = regbranch(&flags); + if (br == (char *) NULL) + return ((char *) NULL); + regtail(ret, br); /* BRANCH -> BRANCH. */ + if (!(flags & HASWIDTH)) + *flagp &= ~HASWIDTH; + *flagp |= flags & SPSTART; + } + + /* Make a closing node, and hook it on the end. */ + ender = regnode((paren) ? CLOSE + parno : END); + regtail(ret, ender); + + /* Hook the tails of the branches to the closing node. */ + for (br = ret; br != (char *) NULL; br = regnext(br)) + regoptail(br, ender); + + /* Check for proper termination. */ + if (paren && *regparse++ != RBRAC) { + FAIL("unmatched ()\n"); + } else if (!paren && *regparse != '\0') { + if (*regparse == RBRAC) { + FAIL("unmatched ()\n"); + } else + FAIL("junk on end\n");/* "Can't happen". */ + /* NOTREACHED */ + } + return (ret); +} + +/* + - regbranch - one alternative of an | operator + * + * Implements the concatenation operator. + */ +static char *regbranch (int * flagp) +{ + register char *ret; + register char *chain; + register char *latest; + int flags; + + *flagp = WORST; /* Tentatively. */ + + ret = regnode(BRANCH); + chain = (char *) NULL; + while (*regparse != '\0' && *regparse != OR_OP && *regparse != RBRAC) { + latest = regpiece(&flags); + if (latest == (char *) NULL) + return ((char *) NULL); + *flagp |= flags & HASWIDTH; + if (chain == (char *) NULL) /* First piece. */ + *flagp |= flags & SPSTART; + else + regtail(chain, latest); + chain = latest; + } + if (chain == (char *) NULL) /* Loop ran zero times. */ + regnode(NOTHING); + + return (ret); +} + +/* + - regpiece - something followed by possible [*+?] + * + * Note that the branching code sequence used for ? and the general cases of + * * and + are somewhat optimized: they use the same NOTHING node as both the + * endmarker for their branch list and the body of the last branch. It might + * seem that this node could be dispensed with entirely, but the endmarker + * role is not redundant. + */ +static char *regpiece (int * flagp) +{ + register char *ret; + register short op; + register char *nxt; + int flags; + + ret = regatom(&flags); + if (ret == (char *) NULL) + return ((char *) NULL); + + op = *regparse; + if (!ISMULT(op)) { + *flagp = flags; + return (ret); + } + if (!(flags & HASWIDTH) && op != QMARK) + FAIL("*+ operand could be empty\n"); + *flagp = (op != PLUSS) ? (WORST | SPSTART) : (WORST | HASWIDTH); + + if (op == ASTERIX && (flags & SIMPLE)) + reginsert(STAR, ret); + else if (op == ASTERIX) { + /* Emit x* as (x&|), where & means "self". */ + reginsert(BRANCH, ret); /* Either x */ + regoptail(ret, regnode(BACK)); /* and loop */ + regoptail(ret, ret); /* back */ + regtail(ret, regnode(BRANCH)); /* or */ + regtail(ret, regnode(NOTHING)); /* null. */ + } else if (op == PLUSS && (flags & SIMPLE)) + reginsert(PLUS, ret); + else if (op == PLUSS) { + /* Emit x+ as x(&|), where & means "self". */ + nxt = regnode(BRANCH); /* Either */ + regtail(ret, nxt); + regtail(regnode(BACK), ret); /* loop back */ + regtail(nxt, regnode(BRANCH)); /* or */ + regtail(ret, regnode(NOTHING)); /* null. */ + } else if (op == QMARK) { + /* Emit x? as (x|) */ + reginsert(BRANCH, ret); /* Either x */ + regtail(ret, regnode(BRANCH)); /* or */ + nxt = regnode(NOTHING); /* null. */ + regtail(ret, nxt); + regoptail(ret, nxt); + } + regparse++; + if (ISMULT(*regparse)) + FAIL("nested *?+\n"); + + return (ret); +} + +/* + - regatom - the lowest level + * + * Optimization: gobbles an entire sequence of ordinary characters so that + * it can turn them into a single node, which is smaller to store and + * faster to run. + */ +static char *regatom (int * flagp) +{ + register char *ret; + int flags; + + *flagp = WORST; /* Tentatively. */ + + switch (*regparse++) { + case CARET: + ret = regnode(BOL); + break; + case DOLLAR: + ret = regnode(EOL); + break; + case DOT: + ret = regnode(ANY); + *flagp |= HASWIDTH | SIMPLE; + break; + case LSHBRAC: + ret = regnode(WORDSTART); + break; + case RSHBRAC: + ret = regnode(WORDEND); + break; + case LSQBRAC:{ + register int classs; + register int classend; + + if (*regparse == CARET) { /* Complement of range. */ + ret = regnode(ANYBUT); + regparse++; + } else + ret = regnode(ANYOF); + if (*regparse == RSQBRAC || *regparse == '-') + regc(*regparse++); + while (*regparse != '\0' && *regparse != RSQBRAC) { + if (*regparse == '-') { + regparse++; + if (*regparse == RSQBRAC || *regparse == '\0') + regc('-'); + else { + classs = (CHARBITS & *(regparse - 2)) + 1; + classend = (CHARBITS & *(regparse)); + if (classs > classend + 1) + FAIL("invalid [] range\n"); + for (; classs <= classend; classs++) + regc(classs); + regparse++; + } + } else + regc(*regparse++); + } + regc('\0'); + if (*regparse != RSQBRAC) + FAIL("unmatched []\n"); + regparse++; + *flagp |= HASWIDTH | SIMPLE; + } + break; + case LBRAC: + ret = reg(1, &flags); + if (ret == (char *) NULL) + return ((char *) NULL); + *flagp |= flags & (HASWIDTH | SPSTART); + break; + case '\0': + case OR_OP: + case RBRAC: + FAIL("internal urp\n"); /* Supposed to be caught earlier. */ + break; + case ASTERIX: + FAIL("* follows nothing\n"); + break; + case PLUSS: + FAIL("+ follows nothing\n"); + break; + case QMARK: + FAIL("? follows nothing\n"); + break; + default:{ + register int len; + register short ender; + + regparse--; + for (len = 0; regparse[len] && + !(regparse[len] & SPECIAL) && regparse[len] != RSQBRAC; len++); + if (len <= 0) { + FAIL("unexpected ]\n"); + } + ender = *(regparse + len); + if (len > 1 && ISMULT(ender)) + len--; /* Back off clear of ?+* operand. */ + *flagp |= HASWIDTH; + if (len == 1) + *flagp |= SIMPLE; + ret = regnode(EXACTLY); + while (len > 0) { + regc(*regparse++); + len--; + } + regc('\0'); + } + break; + } + + return (ret); +} + +/* + - regnode - emit a node + */ +static char *regnode (char op) +{ + register char *ret; + register char *ptr; + + ret = regcode; + if (ret == ®dummy) { + regsize += 3; + return (ret); + } + ptr = ret; + *ptr++ = op; + *ptr++ = '\0'; /* Null "nxt" pointer. */ + *ptr++ = '\0'; + regcode = ptr; + + return (ret); +} + +/* + - regc - emit (if appropriate) a byte of code + */ +static void regc (char b) +{ + if (regcode != ®dummy) + *regcode++ = b; + else + regsize++; +} + +/* + - reginsert - insert an operator in front of already-emitted operand + * + * Means relocating the operand. + */ +static void reginsert (char op, char * opnd) +{ + register char *src; + register char *dst; + register char *place; + + if (regcode == ®dummy) { + regsize += 3; + return; + } + src = regcode; + regcode += 3; + dst = regcode; + while (src > opnd) + *--dst = *--src; + + place = opnd; /* Op node, where operand used to be. */ + *place++ = op; + *place++ = '\0'; + *place++ = '\0'; +} + +/* + - regtail - set the next-pointer at the end of a node chain + */ +static void regtail (char * p, char * val) +{ + register char *scan; + register char *temp; + register int offset; + + if (p == ®dummy) + return; + + /* Find last node. */ + scan = p; + for (;;) { + temp = regnext(scan); + if (temp == (char *) NULL) + break; + scan = temp; + } + + if (OP(scan) == BACK) + offset = scan - val; + else + offset = val - scan; + *(scan + 1) = (offset >> 8) & 0377; + *(scan + 2) = offset & 0377; +} + +/* + - regoptail - regtail on operand of first argument; nop if operandless + */ +static void regoptail (char * p, char * val) +{ + /* "Operandless" and "op != BRANCH" are synonymous in practice. */ + if (p == (char *) NULL || p == ®dummy || OP(p) != BRANCH) + return; + regtail(OPERAND(p), val); +} + +/* + * regexec and friends + */ + +/* + * Global work variables for regexec(). + */ +static const char *reginput; /* String-input pointer. */ +static const char *regbol; /* Beginning of input, for ^ check. */ +static const char **regstartp; /* Pointer to startp array. */ +static const char **regendp; /* Ditto for endp. */ + +/* + * Forwards. + */ +STATIC int regtry (regexp *, const char *); +STATIC int regmatch (char *); +STATIC int regrepeat (char *); + +#ifdef DEBUG +int regnarrate = 0; +void regdump (regexp *); +STATIC char *regprop (char *); + +#endif + +/* + - regexec - match a regexp against a string + */ +int regexec (register regexp * prog, register const char * string) +{ + register const char *s; + + /* Be paranoid... */ + if (prog == (regexp *) NULL || string == (char *) NULL) { + regerror("NULL parameter\n"); + return (0); + } + /* Check validity of program. */ + if (UCHARAT(prog->program) != MAGIC) { + regerror("corrupted program\n"); + return (0); + } + /* If there is a "must appear" string, look for it. */ + if (prog->regmust != (char *) NULL) { + s = string; + while ((s = strchr(s, prog->regmust[0])) != (char *) NULL) { + if (strncmp(s, prog->regmust, prog->regmlen) == 0) + break; /* Found it. */ + s++; + } + if (s == (char *) NULL) /* Not present. */ + return (0); + } + /* Mark beginning of line for ^ . */ + regbol = string; + + /* Simplest case: anchored match need be tried only once. */ + if (prog->reganch) + return (regtry(prog, string)); + + /* Messy cases: unanchored match. */ + s = string; + if (prog->regstart != '\0') + /* We know what char it must start with. */ + while ((s = strchr(s, prog->regstart)) != (char *) NULL) { + if (regtry(prog, s)) + return (1); + s++; + } + else + /* We don't -- general case. */ + do { + if (regtry(prog, s)) + return (1); + } while (*s++ != '\0'); + + /* Failure. */ + return (0); +} + +/* + - regtry - try match at specific point + */ +static int regtry (regexp * prog, const char * string) +{ + register int i; + register const char **sp; + register const char **ep; + + reginput = string; + regstartp = prog->startp; + regendp = prog->endp; + + sp = prog->startp; + ep = prog->endp; + for (i = NSUBEXP; i > 0; i--) { + *sp++ = (char *) NULL; + *ep++ = (char *) NULL; + } + if (regmatch(prog->program + 1)) { + prog->startp[0] = string; + prog->endp[0] = reginput; + return (1); + } else + return (0); +} + +/* + - regmatch - main matching routine + * + * Conceptually the strategy is simple: check to see whether the current + * node matches, call self recursively to see whether the rest matches, + * and then act accordingly. In practice we make some effort to avoid + * recursion, in particular by going through "ordinary" nodes (that don't + * need to know whether the rest of the match failed) by a loop instead of + * by recursion. + */ +static int regmatch (char * prog) +{ + register char *scan; /* Current node. */ + char *nxt; /* nxt node. */ + + scan = prog; +#ifdef DEBUG + if (scan != (char *) NULL && regnarrate) + debug_message("%s(\n", regprop(scan)); +#endif + while (scan != (char *) NULL) { +#ifdef DEBUG + if (regnarrate) + debug_message("%s...\n", regprop(scan)); +#endif + nxt = regnext(scan); + + switch (OP(scan)) { + case BOL: + if (reginput != regbol) + return (0); + break; + case EOL: + if (*reginput != '\0') + return (0); + break; + case ANY: + if (*reginput == '\0') + return (0); + reginput++; + break; + case WORDSTART: + if (reginput == regbol) + break; + if (*reginput == '\0' || + ISWORDPART(*(reginput - 1)) || !ISWORDPART(*reginput)) + return (0); + break; + case WORDEND: + if (*reginput == '\0') + break; + if (reginput == regbol || + !ISWORDPART(*(reginput - 1)) || ISWORDPART(*reginput)) + return (0); + break; + case EXACTLY:{ + register int len; + register char *opnd; + + opnd = OPERAND(scan); + /* Inline the first character, for speed. */ + if (*opnd != *reginput) + return (0); + len = strlen(opnd); + if (len > 1 && strncmp(opnd, reginput, len) != 0) + return (0); + reginput += len; + } + break; + case ANYOF: + if (*reginput == '\0' || + strchr(OPERAND(scan), *reginput) == (char *) NULL) + return (0); + reginput++; + break; + case ANYBUT: + if (*reginput == '\0' || + strchr(OPERAND(scan), *reginput) != (char *) NULL) + return (0); + reginput++; + break; + case NOTHING: + break; + case BACK: + break; + case OPEN + 1: + case OPEN + 2: + case OPEN + 3: + case OPEN + 4: + case OPEN + 5: + case OPEN + 6: + case OPEN + 7: + case OPEN + 8: + case OPEN + 9:{ + register int no; + register const char *save; + + no = OP(scan) - OPEN; + save = reginput; + + if (regmatch(nxt)) { + /* + * Don't set startp if some later invocation of the same + * parentheses already has. + */ + if (regstartp[no] == (char *) NULL) + regstartp[no] = save; + return (1); + } else + return (0); + } + break; + case CLOSE + 1: + case CLOSE + 2: + case CLOSE + 3: + case CLOSE + 4: + case CLOSE + 5: + case CLOSE + 6: + case CLOSE + 7: + case CLOSE + 8: + case CLOSE + 9:{ + register int no; + register const char *save; + + no = OP(scan) - CLOSE; + save = reginput; + + if (regmatch(nxt)) { + /* + * Don't set endp if some later invocation of the same + * parentheses already has. + */ + if (regendp[no] == (char *) NULL) + regendp[no] = save; + return (1); + } else + return (0); + } + break; + case BRANCH:{ + register const char *save; + + if (OP(nxt) != BRANCH) /* No choice. */ + nxt = OPERAND(scan); /* Avoid recursion. */ + else { + do { + save = reginput; + if (regmatch(OPERAND(scan))) + return (1); + reginput = save; + scan = regnext(scan); + } while (scan != (char *) NULL && OP(scan) == BRANCH); + return (0); + /* NOTREACHED */ + } + } + break; + case STAR: + case PLUS:{ + register char nextch; + register int no; + register const char *save; + register int minimum; + + /* + * Lookahead to avoid useless match attempts when we know + * what character comes next. + */ + nextch = '\0'; + if (OP(nxt) == EXACTLY) + nextch = *OPERAND(nxt); + minimum = (OP(scan) == STAR) ? 0 : 1; + save = reginput; + no = regrepeat(OPERAND(scan)); + while (no >= minimum) { + /* If it could work, try it. */ + if (nextch == '\0' || *reginput == nextch) + if (regmatch(nxt)) + return (1); + /* Couldn't or didn't -- back up. */ + no--; + reginput = save + no; + } + return (0); + } + break; + case END: + return (1); /* Success! */ + break; + default: + regerror("memory corruption\n"); + return (0); + break; + } + + scan = nxt; + } + + /* + * We get here only if there's trouble -- normally "case END" is the + * terminating point. + */ + regerror("corrupted pointers\n"); + return (0); +} + +/* + - regrepeat - repeatedly match something simple, report how many + */ +static int regrepeat (char * p) +{ + register int count = 0; + register const char *scan; + register char *opnd; + + scan = reginput; + opnd = OPERAND(p); + switch (OP(p)) { + case ANY: + count = strlen(scan); + scan += count; + break; + case EXACTLY: + while (*opnd == *scan) { + count++; + scan++; + } + break; + case ANYOF: + while (*scan != '\0' && strchr(opnd, *scan) != (char *) NULL) { + count++; + scan++; + } + break; + case ANYBUT: + while (*scan != '\0' && strchr(opnd, *scan) == (char *) NULL) { + count++; + scan++; + } + break; + default: /* Oh dear. Called inappropriately. */ + regerror("internal foulup\n"); + count = 0; /* Best compromise. */ + break; + } + reginput = scan; + + return (count); +} + + +/* + - regnext - dig the "nxt" pointer out of a node + */ +static char *regnext (register char * p) +{ + register int offset; + + if (p == ®dummy) + return ((char *) NULL); + + offset = NEXT(p); + if (offset == 0) + return ((char *) NULL); + + if (OP(p) == BACK) + return (p - offset); + else + return (p + offset); +} + +#ifdef DEBUG + +STATIC char *regprop (char *); + +/* + - regdump - dump a regexp onto stdout in vaguely comprehensible form + */ +void regdump (regexp * r) +{ + register char *s; + register char op = EXACTLY; /* Arbitrary non-END op. */ + register char *nxt; + +#ifdef _AIX + extern char *strchr(); + +#endif /* _AIX */ + + s = r->program + 1; + while (op != END) { /* While that wasn't END last time... */ + op = OP(s); + printf("%2d%s", (s - r->program), regprop(s)); /* Where, what. */ + nxt = regnext(s); + if (nxt == (char *) NULL) /* nxt ptr. */ + printf("(0)"); + else + printf("(%d)", ((s - r->program) + (nxt - s))); + s += 3; + if (op == ANYOF || op == ANYBUT || op == EXACTLY) { + /* Literal string, where present. */ + while (*s != '\0') { + putchar(*s); + s++; + } + s++; + } + putchar('\n'); + } + + /* Header fields of interest. */ + if (r->regstart != '\0') + printf("start `%c' ", r->regstart); + if (r->reganch) + printf("anchored "); + if (r->regmust != (char *) NULL) + printf("must have \"%s\"", r->regmust); + printf("\n"); +} + +/* + - regprop - printable representation of opcode + */ +static char *regprop (char * op) +{ + register char *p; + static char buf[50]; + + strcpy(buf, ":"); + + switch (OP(op)) { + case BOL: + p = "BOL"; + break; + case EOL: + p = "EOL"; + break; + case ANY: + p = "ANY"; + break; + case ANYOF: + p = "ANYOF"; + break; + case ANYBUT: + p = "ANYBUT"; + break; + case BRANCH: + p = "BRANCH"; + break; + case EXACTLY: + p = "EXACTLY"; + break; + case NOTHING: + p = "NOTHING"; + break; + case BACK: + p = "BACK"; + break; + case END: + p = "END"; + break; + case WORDSTART: + p = "WORDSTART"; + break; + case WORDEND: + p = "WORDEND"; + break; + case OPEN + 1: + case OPEN + 2: + case OPEN + 3: + case OPEN + 4: + case OPEN + 5: + case OPEN + 6: + case OPEN + 7: + case OPEN + 8: + case OPEN + 9: + sprintf(buf + strlen(buf), "OPEN%d", OP(op) - OPEN); + p = (char *) NULL; + break; + case CLOSE + 1: + case CLOSE + 2: + case CLOSE + 3: + case CLOSE + 4: + case CLOSE + 5: + case CLOSE + 6: + case CLOSE + 7: + case CLOSE + 8: + case CLOSE + 9: + sprintf(buf + strlen(buf), "CLOSE%d", OP(op) - CLOSE); + p = (char *) NULL; + break; + case STAR: + p = "STAR"; + break; + case PLUS: + p = "PLUS"; + break; + default: + p = (char *) NULL; + regerror("corrupted opcode\n"); + break; + } + if (p != (char *) NULL) + strcat(buf, p); + return (buf); +} +#endif + +/* + * The following is provided for those people who do not have strcspn() in + * their C libraries. They should get off their butts and do something + * about it; at least one public-domain implementation of those (highly + * useful) string routines has been published on Usenet. + */ +#ifdef STRCSPN +/* + * strcspn - find length of initial segment of s1 consisting entirely + * of characters not from s2 + */ +static int strcspn (char * s1, char * s2) +{ + register char *scan1; + register char *scan2; + register int count; + + count = 0; + for (scan1 = s1; *scan1 != '\0'; scan1++) { + for (scan2 = s2; *scan2 != '\0';) /* ++ moved down. */ + if (*scan1 == *scan2++) + return (count); + count++; + } + return (count); +} +#endif + + +/* + - regsub - perform substitutions after a regexp match + */ +char *regsub (regexp * prog, char * source, char * dest, int n) +{ + register char *src; + register char *dst; + register char c; + register int no; + register int len; + + if (prog == (regexp *) NULL || + source == (char *) NULL || dest == (char *) NULL) { + regerror("NULL parm to regsub\n"); + return NULL; + } + if (UCHARAT(prog->program) != MAGIC) { + regerror("damaged regexp fed to regsub\n"); + return NULL; + } + src = source; + dst = dest; + while ((c = *src++) != '\0') { + if (c == '&') + no = 0; + else if (c == '\\' && '0' <= *src && *src <= '9') + no = *src++ - '0'; + else + no = -1; + + if (no < 0) { /* Ordinary character. */ + if (c == '\\' && (*src == '\\' || *src == '&')) + c = *src++; + if (--n < 0) { /* amylaar */ + regerror("line too long\n"); + return NULL; + } + *dst++ = c; + } else if (prog->startp[no] != (char *) NULL && + prog->endp[no] != (char *) NULL) { + len = prog->endp[no] - prog->startp[no]; + if ((n -= len) < 0) { /* amylaar */ + regerror("line too long\n"); + return NULL; + } + strncpy(dst, prog->startp[no], len); + dst += len; + if (len != 0 && *(dst - 1) == '\0') { /* strncpy hit NUL. */ + regerror("damaged match string\n"); + return NULL; + } + } + } + if (--n < 0) { /* amylaar */ + regerror("line too long\n"); + return NULL; + } + *dst = '\0'; + return dst; +} diff --git a/fluffos-2.23-ds03/regexp.h b/fluffos-2.23-ds03/regexp.h new file mode 100644 index 0000000..bf69b44 --- /dev/null +++ b/fluffos-2.23-ds03/regexp.h @@ -0,0 +1,34 @@ +#ifndef _REGEXP_H_ +#define _REGEXP_H_ + +/* + * Definitions etc. for regexp(3) routines. + * + * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof], + * not the System V one. + */ + +#define EFUN_REGEXP 1 +#define ED_REGEXP 2 + +#define NSUBEXP 10 +typedef struct regexp { + const char *startp[NSUBEXP]; + const char *endp[NSUBEXP]; + char regstart; /* Internal use only. */ + char reganch; /* Internal use only. */ + char *regmust; /* Internal use only. */ + int regmlen; /* Internal use only. */ + char program[1]; /* Unwarranted chumminess with compiler. */ +} regexp; + +extern int regnarrate; +extern int regexp_user; +extern const char *regexp_error; + +void regdump (regexp *); +regexp *regcomp (unsigned char *, int); +int regexec (regexp *, const char *); +char *regsub (regexp *, char *, char *, int); + +#endif diff --git a/fluffos-2.23-ds03/replace_program.c b/fluffos-2.23-ds03/replace_program.c new file mode 100644 index 0000000..8c7a640 --- /dev/null +++ b/fluffos-2.23-ds03/replace_program.c @@ -0,0 +1,202 @@ +#include "std.h" +#include "replace_program.h" +#include "simul_efun.h" +#include "efun_protos.h" + +/* + * replace_program.c + * replaces the program in a running object with one of the programs + * it inherits, in order to save memory. + * Ported from Amylaars LP 3.2 driver + */ + +replace_ob_t *obj_list_replace = 0; + +static program_t *search_inherited (char *, program_t *, int *); +static replace_ob_t *retrieve_replace_program_entry (void); + +int replace_program_pending (object_t * ob) +{ + replace_ob_t *r_ob; + + for (r_ob = obj_list_replace; r_ob; r_ob = r_ob->next) { + if (r_ob->ob == ob) + return 1; + } + + return 0; +} + +void replace_programs (void) +{ + replace_ob_t *r_ob, *r_next; + int i, num_fewer, offset; + svalue_t *svp; + + debug(d_flag, ("start of replace_programs")); + + for (r_ob = obj_list_replace; r_ob; r_ob = r_next) { + program_t *old_prog; + + num_fewer = r_ob->ob->prog->num_variables_total - r_ob->new_prog->num_variables_total; + + debug(d_flag, ("%d less variables\n", num_fewer)); + + tot_alloc_object_size -= num_fewer * sizeof(svalue_t[1]); + if ((offset = r_ob->var_offset)) { + svp = r_ob->ob->variables; + /* move our variables up to the top */ + for (i = 0; i < r_ob->new_prog->num_variables_total; i++) { + free_svalue(svp, "replace_programs"); + *svp = *(svp + offset); + *(svp + offset) = const0u; + svp++; + } + /* free the rest */ + for (i = 0; i < num_fewer; i++) { + free_svalue(svp, "replace_programs"); + *svp++ = const0u; + } + } else { + /* We just need to remove the last num_fewer variables */ + svp = &r_ob->ob->variables[r_ob->new_prog->num_variables_total]; + for (i = 0; i < num_fewer; i++) { + free_svalue(svp, "replace_programs"); + *svp++ = const0u; + } + } + + if (r_ob->ob->replaced_program) { + FREE_MSTR(r_ob->ob->replaced_program); + r_ob->ob->replaced_program = 0; + } + r_ob->ob->replaced_program = string_copy(r_ob->new_prog->filename, "replace_programs"); + + reference_prog(r_ob->new_prog, "replace_programs"); + old_prog = r_ob->ob->prog; + r_ob->ob->prog = r_ob->new_prog; + r_next = r_ob->next; + free_prog(&old_prog); + + debug(d_flag, ("program freed.")); +#ifndef NO_SHADOWS + if (r_ob->ob->shadowing) { + /* + * The master couldn't decide if it's a legal shadowing before + * the program was actually replaced. It is possible that the + * blueprint to the replacing program is already destructed, and + * it's source changed. On the other hand, if we called the + * master now, all kind of volatile data structures could result, + * even new entries for obj_list_replace. This would eventually + * require to reference it, and all the lrpp's , in + * check_a_lot_ref_counts() and garbage_collection() . Being able + * to use replace_program() in shadows is hardly worth this + * effort. Thus, we simply stop the shadowing. + */ + r_ob->ob->shadowing->shadowed = r_ob->ob->shadowed; + if (r_ob->ob->shadowed) { + r_ob->ob->shadowed->shadowing = r_ob->ob->shadowing; + r_ob->ob->shadowed = 0; + } + r_ob->ob->shadowing = 0; + } +#endif + FREE((char *) r_ob); + } + obj_list_replace = (replace_ob_t *) 0; + debug(d_flag, ("end of replace_programs")); +} + +#ifdef F_REPLACE_PROGRAM +static program_t *search_inherited (char * str, program_t * prg, int * offpnt) +{ + program_t *tmp; + int i; + + debug(d_flag, ("search_inherited started")); + debug(d_flag, ("searching for PRG(/%s) in PRG(/%s)", str, prg->filename)); + debug(d_flag, ("num_inherited=%d\n", prg->num_inherited)); + + for (i = 0; i < prg->num_inherited; i++) { + debug(d_flag, ("index %d:", i)); + debug(d_flag, ("checking PRG(/%s)", prg->inherit[i].prog->filename)); + + if (strcmp(str, prg->inherit[i].prog->filename) == 0) { + debug(d_flag, ("match found")); + + *offpnt = prg->inherit[i].variable_index_offset; + return prg->inherit[i].prog; + } else if ((tmp = search_inherited(str, prg->inherit[i].prog, + offpnt))) { + debug(d_flag, ("deferred match found")); + + *offpnt += prg->inherit[i].variable_index_offset; + return tmp; + } + } + debug(d_flag, ("search_inherited failed")); + + return (program_t *) 0; +} + +static replace_ob_t *retrieve_replace_program_entry (void) +{ + replace_ob_t *r_ob; + + for (r_ob = obj_list_replace; r_ob; r_ob = r_ob->next) { + if (r_ob->ob == current_object) { + return r_ob; + } + } + return 0; +} + +void +f_replace_program (void) +{ + replace_ob_t *tmp; + int name_len; + char *name, *xname; + program_t *new_prog; + int var_offset; + + if (sp->type != T_STRING) + bad_arg(1, F_REPLACE_PROGRAM); + debug(d_flag, ("replace_program called")); + + if (!current_object) + error("replace_program called with no current object\n"); + if (current_object == simul_efun_ob) + error("replace_program on simul_efun object\n"); + + if (current_object->prog->func_ref) + error("cannot replace a program with function references.\n"); + + name_len = SVALUE_STRLEN(sp); + name = (char *) DMALLOC(name_len + 3, TAG_TEMPORARY, "replace_program"); + xname = name; + strcpy(name, sp->u.string); + if (name[name_len - 2] != '.' || name[name_len - 1] != 'c') + strcat(name, ".c"); + if (*name == '/') + name++; + new_prog = search_inherited(name, current_object->prog, &var_offset); + FREE(xname); + if (!new_prog) { + error("program to replace the current with has to be inherited\n"); + } + if (!(tmp = retrieve_replace_program_entry())) { + tmp = ALLOCATE(replace_ob_t, TAG_TEMPORARY, "replace_program"); + tmp->ob = current_object; + tmp->next = obj_list_replace; + obj_list_replace = tmp; + } + tmp->new_prog = new_prog; + tmp->var_offset = var_offset; + + debug(d_flag, ("replace_program finished")); + + free_string_svalue(sp--); +} + +#endif diff --git a/fluffos-2.23-ds03/replace_program.h b/fluffos-2.23-ds03/replace_program.h new file mode 100644 index 0000000..33be03e --- /dev/null +++ b/fluffos-2.23-ds03/replace_program.h @@ -0,0 +1,18 @@ +#ifndef _REPLACE_PROGRAM_H_ +#define _REPLACE_PROGRAM_H_ + +#include "lpc_incl.h" + +int replace_program_pending (object_t *); +void replace_programs (void); + +typedef struct replace_ob_s { + object_t *ob; + program_t *new_prog; + unsigned short var_offset; + struct replace_ob_s *next; +} replace_ob_t; + +extern replace_ob_t *obj_list_replace; + +#endif diff --git a/fluffos-2.23-ds03/scratchpad.c b/fluffos-2.23-ds03/scratchpad.c new file mode 100644 index 0000000..4585c05 --- /dev/null +++ b/fluffos-2.23-ds03/scratchpad.c @@ -0,0 +1,346 @@ +#define SUPPRESS_COMPILER_INLINES +#include "std.h" +#include "lpc_incl.h" +#include "scratchpad.h" +#include "compiler.h" + +/* + * This is a first attempt at beating malloc() for allocation of strings + * during compilation. It's pretty general, and could probably be done + * better. + * + * Here's what we can assume: + * Things are going to conform to LIFO order, more or less. + * Strings will be of the long variety and the short variety. + * A realloc on strings might be nice, for "a" "b" "c" ... etc + * + * Although in rare cases (errors) certain items won't come off until the + * table is destroyed. + */ +/* Here is what is currently being used: + * + * <0> <0> string1 string2 + * ^ ^ + * last tail + * + * len1 is the length of string1 including the zero at the end + * + * Note: "" looks a heck of a lot like a interior freed string. Currently, + * we ignore the problem. In some cases, it could be left dangling, but + * I don't think that can happen with the present grammar/use of the + * scratchpad. + */ +/* + * Todo: This algorithm might be faster if we aligned to 2 byte + * boundaries and used shorts for lengths. We wouldn't have to + * worry about the 256 byte limit then + */ +/* + * Within this file, a capitalized identifier is that var cast to an + * unsigned type. It makes things easier to read than having casts + * all over the place since we go back and forth a lot. strict ANSI + * requires casts from (unsigned char *) to (char *) and back, but + * we want to deal with strings as unsigned since we keep the length + * in them. + */ +#define Str ((unsigned char *)str) +#define Ptr ((unsigned char *)ptr) +#define Res ((unsigned char *)res) +#define S1 ((unsigned char *)s1) +#define S2 ((unsigned char *)s2) +#define Scratch_large_alloc(x) ((unsigned char *)scratch_large_alloc(x)) +#define Strlen(x) (strlen((char *)x)) +#define Strcpy(x, y) (strcpy((char *)x, (char *)y)) +#define Strncpy(x, y, z) (strncpy((char *)x, (char *)y, z)) + +/* not strictly ANSI, but should always work ... */ +#define HDR_SIZE ((char *)&scratch_head.block[2] - (char *)&scratch_head) +#define FIND_HDR(x) ((sp_block_t *)(x - HDR_SIZE)) +#define SIZE_WITH_HDR(x) (x + HDR_SIZE) + +static unsigned char scratchblock[SCRATCHPAD_SIZE]; +static sp_block_t scratch_head = { 0, 0 }; +unsigned char *scr_last = &scratchblock[2], *scr_tail = &scratchblock[2]; +unsigned char *scratch_end = scratchblock + SCRATCHPAD_SIZE; + +#if 0 +static void scratch_summary (void); + +static void scratch_summary() { + unsigned char *p = scratchblock; + int i; + + while (p<=scr_tail) { + if (*p == 0) printf("0"); + else if (*p < 32 || *p > 127) printf("*"); + else printf("%c", *p); + p++; + } + printf("\n"); + i = scr_last - scratchblock; + while (i--) printf(" "); + printf("l\n"); + i = scr_tail - scratchblock; + while (i--) printf(" "); + printf("t\n"); +} +#endif + +void scratch_destroy() { + sp_block_t *next, *thisb = scratch_head.next; + + SDEBUG(printf("scratch_destroy\n")); + + while (thisb) { + next = thisb->next; + FREE(thisb); + thisb = next; + } + scratch_head.next = 0; + scr_last = &scratchblock[2]; + scr_tail = &scratchblock[2]; +} + + +char *scratch_copy (const char * str) { + unsigned char *from, *to, *end; + + SDEBUG2(printf("scratch_copy(%s):", str)); + + /* first, take a wild guess that there is room and save a strlen() :) */ + from = Str; + to = scr_tail+1; + end = scratch_end - 2; /* room for zero and len */ + if (end > to + 255) end = to + 255; + while (*from && to < end) + *to++ = *from++; + if (!(*from)) { + SDEBUG2(printf(" on scratchpad\n")); + + scr_last = scr_tail + 1; + *to++ = 0; + scr_tail = to; + *to = to - scr_last; + return (char *)scr_last; + } + SDEBUG(printf(" mallocing ... ")); + + /* ACK! no room. strlen(str) == (from - str) + strlen(from) */ + to = Scratch_large_alloc((from - Str) + Strlen(from) + 1); + Strcpy(to, str); + return (char *)to; +} + +void scratch_free (char * ptr) { + /* how do we know what this is? first we check if it's the last string + we made. Otherwise, take advantage of the fact that things on the + scratchpad have a zero two before them. Things not on it wont + (we make sure of this) */ + + SDEBUG2(printf("scratch_free(%s): ", ptr)); + + if (Ptr == scr_last) { + SDEBUG2(printf("last freed\n")); + scratch_free_last(); + } else if (*(Ptr - 2)) { + sp_block_t *sbt; + + DEBUG_CHECK(*(Ptr - 2) != SCRATCH_MAGIC, "scratch_free called on non-scratchpad string.\n"); + SDEBUG(printf("block freed\n")); + sbt = FIND_HDR(ptr); + if (sbt->prev) + sbt->prev->next = sbt->next; + if (sbt->next) + sbt->next->prev = sbt->prev; + FREE(sbt); + } else { + SDEBUG(printf("interior free\n")); + *ptr = 0; /* mark it as freed */ + } +} + +char *scratch_large_alloc (int size) { + sp_block_t *spt; + + SDEBUG(printf("scratch_large_alloc(%i)\n", size)); + + spt = (sp_block_t *)DMALLOC(SIZE_WITH_HDR(size), TAG_COMPILER, "scratch_alloc"); + if ((spt->next = scratch_head.next)) + spt->next->prev = spt; + spt->prev = (sp_block_t *)&scratch_head; + spt->block[0] = SCRATCH_MAGIC; + scratch_head.next = spt; + return (char *)&spt->block[2]; +} + +/* warning: unlike REALLOC(), this one only allows increases */ +char *scratch_realloc (char * ptr, int size) { + SDEBUG(printf("scratch_realloc(%s): ", ptr)); + + if (Ptr == scr_last) { + if (size < 256 && (scr_last + size) < scratch_end) { + SDEBUG(printf("on scratchpad\n")); + scr_tail = scr_last + size; + *scr_tail = size; + return ptr; + } else { + char *res; + SDEBUG(printf("copy off ... ")); + res = scratch_large_alloc(size); + strcpy(res, ptr); + scratch_free_last(); + return res; + } + } else if (*(Ptr - 2)) { + sp_block_t *sbt, *newsbt; + + DEBUG_CHECK(*(Ptr - 2) != SCRATCH_MAGIC, "scratch_realloc on non-scratchpad string.\n"); + SDEBUG(printf("block\n")); + sbt = FIND_HDR(ptr); + newsbt = (sp_block_t *)DREALLOC(sbt, SIZE_WITH_HDR(size), + TAG_COMPILER, "scratch_realloc"); + newsbt->prev->next = newsbt; + if (newsbt->next) + newsbt->next->prev = newsbt; + return (char *)&newsbt->block[2]; + } else { + char *res; + + SDEBUG(printf("interior ... ")); + /* ACK!! it's in the middle. */ + if (size < 256 && (scr_tail + size + 1) < scratch_end) { + SDEBUG(printf("move to end\n")); + scr_last = scr_tail + 1; + Strcpy(scr_last, ptr); + scr_tail = scr_last + size; + *scr_tail = size; + res = (char *)scr_last; + } else { + SDEBUG(printf("copy off ... ")); + res = scratch_large_alloc(size); + strcpy(res, ptr); + } + *ptr = 0; /* free the old version */ + return res; + } +} + +/* the routines above are better than this */ +char *scratch_alloc (int size) { + SDEBUG(printf("scratch_alloc(%i)\n", size)); + if (size < 256 && (scr_tail + size + 1) < scratch_end) { + scr_last = scr_tail + 1; + scr_tail = scr_last + size; + *scr_tail = size; + return (char *)scr_last; + } else + return scratch_large_alloc(size); +} + +char *scratch_join (char * s1, char * s2) { + char *res; + int tmp; + + SDEBUG(printf("scratch_join\n")); + if (*(s1-2) || *(s2-2)) { + int l = strlen(s1); + + DEBUG_CHECK(*(S1 - 2) && *(S1 - 2) != SCRATCH_MAGIC, "argument 1 to scratch_join was not a scratchpad string.\n"); + DEBUG_CHECK(*(S2 - 2) && *(S2 - 2) != SCRATCH_MAGIC, "argument 2 to scratch_join was not a scratchpad string.\n"); + + res = scratch_realloc(s1, l + strlen(s2) + 1); + strcpy(res + l, s2); + scratch_free(s2); + return res; + } else { + /* This assumes that S1 and S2 were the last two things allocated. + Make sure this is true */ + DEBUG_CHECK(S2 != scr_last, "Argument 2 to scratch_join was not the last allocated string.\n"); + DEBUG_CHECK(S1 != (scr_last - 1 - (*(scr_last - 1))), "Argument 1 to scratch_join was not the second to last allocated string.\n"); + + if ((tmp = ((scr_tail - S1) - 2)) < 256) { + scr_tail = scr_last - 2; + do { + *scr_tail = *(scr_tail + 2); + } while (*scr_tail++); + *scr_tail = tmp; + scr_last = S1; + return s1; + } else { + char *ret = scratch_large_alloc(tmp); + strcpy(ret, s1); + strcpy(ret + (scr_last - S1) - 2, s2); + scratch_free(s1); + scratch_free(s2); + return ret; + } + } +} + +char *scratch_copy_string (char *s) { + int l; + register unsigned char *to = scr_tail + 1; + char *res; + + SDEBUG2(printf("scratch_copy_string\n")); + l = scratch_end - to; + + if (l > 255) l = 255; + s++; + while (l--) { + if (*s == '\\') { + switch (*++s) { + case 'n': *to++ = '\n'; break; + case 't': *to++ = '\t'; break; + case 'r': *to++ = '\r'; break; + case 'b': *to++ = '\b'; break; + case '"': + case '\\': *to++ = *s; break; + default: + *to++ = *s; + yywarn("Unknown \\x char."); + } + s++; + } else if (*s == '"') { + *to++ = 0; + if (!l && (to == scratch_end)) { + res = scratch_large_alloc(to - scr_tail - 1); + Strcpy(res, scr_tail + 1); + return res; + } + scr_last = scr_tail + 1; + scr_tail = to; + *to = to - scr_last; + return (char *)scr_last; + } else + *to++ = *s++; + } + /* estimate the length we need */ + /* Note that the last char is we read is ", not \0 - Sym */ + res = scratch_large_alloc(to - scr_tail + strlen(s) - 1); + Strncpy(res, (scr_tail + 1), (to - scr_tail) - 1); + to = Res + (to - scr_tail) - 1; + for (;;) { + if (*s == '\\') { + switch (*++s) { + case 'n': *to++ = '\n'; break; + case 't': *to++ = '\t'; break; + case 'r': *to++ = '\r'; break; + case 'b': *to++ = '\b'; break; + case '"': + case '\\': *to++ = *s; break; + default: + *to++ = *s; + yywarn("Unknown \\x char."); + } + s++; + } else if (*s == '"') { + *to++ = 0; + return res; + } else + *to++ = *s++; + } +} + + + diff --git a/fluffos-2.23-ds03/scratchpad.h b/fluffos-2.23-ds03/scratchpad.h new file mode 100644 index 0000000..ac69968 --- /dev/null +++ b/fluffos-2.23-ds03/scratchpad.h @@ -0,0 +1,54 @@ +#ifndef _SCRATCHPAD_H +#define _SCRATCHPAD_H + +/* Tim Hollebeek + * + * The data must also consist of zero terminated chunks, with lengths in the + * range 0 < len < 256. Longer things can be handled, but they're just + * malloc'ed. + * + * Designed to be used by the compile stack (if pointers get popped off due + * to errors, we don't have to worry about them b/c we'll reclaim the space + * when we throw away the scratchpad; this is another advantage), it could + * be used by other things as well. + */ + +#define SCRATCHPAD_SIZE 4096 +#define SDEBUG(x) +#define SDEBUG2(x) + +#define SCRATCH_MAGIC ((unsigned char)0xbb) + +typedef struct sp_block_s { + struct sp_block_s *next, *prev; + char block[2]; /* block[0] must be nonzero, usually SCRATCH_MAGIC */ +} sp_block_t; + +#define scratch_free_last() \ + scr_tail = --scr_last; \ + scr_last -= *scr_tail; \ + while (!(*scr_last) && scr_tail != scr_last) { \ + /* check if the one before was already freed */ \ + scr_tail = --scr_last; \ + scr_last -= *scr_tail; \ + } + +extern unsigned char *scr_last; +extern unsigned char *scr_tail; +extern unsigned char *scratch_end; + +/* + * scratchpad.c + */ +void scratch_destroy (void); +char *scratch_copy (const char *); +char *scratch_alloc (int); +void scratch_free (char *); +char *scratch_join (char *, char *); +char *scratch_join2 (char *, char *); +char *scratch_realloc (char *, int); +char *scratch_copy_string (char *); +char *scratch_large_alloc (int); + +#endif + diff --git a/fluffos-2.23-ds03/simul_efun.c b/fluffos-2.23-ds03/simul_efun.c new file mode 100644 index 0000000..b407b7d --- /dev/null +++ b/fluffos-2.23-ds03/simul_efun.c @@ -0,0 +1,182 @@ +#include "std.h" +#include "simul_efun.h" +#include "lex.h" +#include "otable.h" + +/* + * This file rewritten by Beek because it was inefficient and slow. We + * now keep track of two mappings: + * name -> index and index -> function + * + * index->function is used at runtime since it's very fast. name->index + * is used at compile time. It's sorted so we can search it in O(log n) + * as opposed to a linear search on the function table. Note that we + * can't sort the function table b/c then indices wouldn't be preserved + * across updates. + * + * note, the name list holds names for past and present simul_efuns and + * is now sorted for finding entries faster etc. The identifier hash + * table is used at compile time. + */ + +typedef struct { + char *name; + short index; +} simul_entry; + +simul_entry *simul_names = 0; +function_lookup_info_t *simuls = 0; +int num_simul_efun = 0; +object_t *simul_efun_ob; + +static void find_or_add_simul_efun (function_t *, int); +static void remove_simuls (void); + +#ifdef DEBUGMALLOC_EXTENSIONS +void mark_simuls() { + int i; + + for (i = 0; i < num_simul_efun; i++) + EXTRA_REF(BLOCK(simul_names[i].name))++; +} +#endif + +/* + * If there is a simul_efun file, then take care of it and extract all + * information we need. + */ +void init_simul_efun (char * file) +{ + char buf[512]; + object_t *new_ob; + + if (!file || !file[0]) { + fprintf(stderr, "No simul_efun\n"); + return; + } + if (!strip_name(file, buf, sizeof buf)) + error("Ilegal simul_efun file name '%s'\n", file); + + if (file[strlen(file) - 2] != '.') + strcat(buf, ".c"); + + new_ob = load_object(buf, compiled_version); + if (new_ob == 0) { + fprintf(stderr, "The simul_efun file %s was not loaded.\n", buf); + exit(-1); + } + set_simul_efun(new_ob); +} + +static void remove_simuls() { + int i; + ident_hash_elem_t *ihe; + /* inactivate all old simul_efuns */ + for (i=0; idn.simul_num != -1) + ihe->sem_value--; + ihe->dn.simul_num = -1; + ihe->token &= ~IHE_SIMUL; + ihe->token |= IHE_ORPHAN; + } + } +} + +static +void get_simul_efuns (program_t * prog) +{ + int i; + int num_new = prog->num_functions_defined + prog->last_inherited; + + if (num_simul_efun) { + remove_simuls(); + if (!num_new) { + FREE(simul_names); + FREE(simuls); + num_simul_efun = 0; + } else { + /* will be resized later */ + simul_names = RESIZE(simul_names, num_simul_efun + num_new, + simul_entry, TAG_SIMULS, "get_simul_efuns"); + simuls = RESIZE(simuls, num_simul_efun + num_new, + function_lookup_info_t, TAG_SIMULS, "get_simul_efuns: 2"); + } + } else { + if (num_new) { + simul_names = CALLOCATE(num_new, simul_entry, TAG_SIMULS, "get_simul_efuns"); + simuls = CALLOCATE(num_new, function_lookup_info_t, TAG_SIMULS, "get_simul_efuns: 2"); + } + } + for (i=0; i < num_new; i++) { + if (prog->function_flags[i] & + (FUNC_NO_CODE|DECL_PROTECTED|DECL_PRIVATE|DECL_HIDDEN)) + continue; + + find_or_add_simul_efun(find_func_entry(prog,i), i); + } + + if (num_simul_efun) { + /* shrink to fit */ + simul_names = RESIZE(simul_names, num_simul_efun, simul_entry, + TAG_SIMULS, "get_simul_efuns"); + simuls = RESIZE(simuls, num_simul_efun, function_lookup_info_t, + TAG_SIMULS, "get_simul_efuns"); + } +} + +/* + * Define a new simul_efun + */ +static void +find_or_add_simul_efun (function_t * funp, int runtime_index) { + ident_hash_elem_t *ihe; + int first = 0; + int last = num_simul_efun - 1; + int i,j; + + while (first <= last) { + j = ((first + last) >> 1); + if (funp->funcname < simul_names[j].name) last = j - 1; + else if (funp->funcname > simul_names[j].name) first = j + 1; + else { + ihe = find_or_add_perm_ident(simul_names[j].name); + ihe->token |= IHE_SIMUL; + ihe->token &= ~IHE_ORPHAN; + ihe->sem_value++; + ihe->dn.simul_num = simul_names[j].index; + simuls[simul_names[j].index].index = runtime_index; + simuls[simul_names[j].index].func = funp; + return; + } + } + for (i=num_simul_efun - 1; i > last; i--) + simul_names[i+1] = simul_names[i]; + simuls[num_simul_efun].index = runtime_index; + simuls[num_simul_efun].func = funp; + simul_names[first].name = funp->funcname; + simul_names[first].index = num_simul_efun; + ihe = find_or_add_perm_ident(funp->funcname); + ihe->token |= IHE_SIMUL; + ihe->token &= ~IHE_ORPHAN; + ihe->sem_value++; + ihe->dn.simul_num = num_simul_efun++; + ref_string(funp->funcname); +} + +void +set_simul_efun (object_t * ob) { + get_simul_efuns(ob->prog); + + simul_efun_ob = ob; + add_ref(simul_efun_ob, "set_simul_efun"); +} + + + + + diff --git a/fluffos-2.23-ds03/simul_efun.h b/fluffos-2.23-ds03/simul_efun.h new file mode 100644 index 0000000..bf8d497 --- /dev/null +++ b/fluffos-2.23-ds03/simul_efun.h @@ -0,0 +1,20 @@ +#ifndef SIMUL_EFUN_H +#define SIMUL_EFUN_H + +#include "lpc_incl.h" + +/* + * simul_efun.c + */ + +extern object_t *simul_efun_ob; +extern function_lookup_info_t *simuls; + +void init_simul_efun (char *); +void set_simul_efun (object_t *); + +#ifdef DEBUGMALLOC_EXTENSIONS +void mark_simuls (void); +#endif + +#endif diff --git a/fluffos-2.23-ds03/simulate.c b/fluffos-2.23-ds03/simulate.c new file mode 100644 index 0000000..7e4df13 --- /dev/null +++ b/fluffos-2.23-ds03/simulate.c @@ -0,0 +1,2012 @@ +#define SUPPRESS_COMPILER_INLINES +#include "std.h" +#include "lpc_incl.h" +#include "file_incl.h" +#include "backend.h" +#include "simul_efun.h" +#include "compiler.h" +#include "otable.h" +#include "comm.h" +#include "socket_efuns.h" +#include "md.h" +#include "eoperators.h" +#include "ed.h" +#include "file.h" +#include "packages/db.h" +#include "packages/parser.h" +#include "packages/async.h" +#include "master.h" +#include "add_action.h" +#include "object.h" +#include "eval.h" +#ifdef DTRACE +#include +#else +#define DTRACE_PROBE1(x,y,z) +#endif + +/* + * 'inherit_file' is used as a flag. If it is set to a string + * after yyparse(), this string should be loaded as an object, + * and the original object must be loaded again. + */ +char *inherit_file; + +/* prevents infinite inherit loops. + No, mark-and-sweep solution won't work. Exercise for reader. */ +static int num_objects_this_thread = 0; + +#ifndef NO_ENVIRONMENT +static object_t *restrict_destruct; +#endif + +object_t *obj_list, *obj_list_destruct; +#ifdef DEBUG +int tot_dangling_object = 0; +object_t *obj_list_dangling = 0; +#endif +object_t *current_object; /* The object interpreting a function. */ +object_t *command_giver; /* Where the current command came from. */ +object_t *current_interactive; /* The user who caused this execution */ + +#ifdef PRIVS +static void init_privs_for_object (object_t *); +#endif +#ifdef PACKAGE_UIDS +static int give_uid_to_object (object_t *); +#endif +static int init_object (object_t *); +static object_t *load_virtual_object (const char *, int); +static char *make_new_name (const char *); +#ifndef NO_ENVIRONMENT +static void send_say (object_t *, const char *, array_t *); +#endif + +INLINE void check_legal_string (const char * s) +{ + if (strlen(s) > LARGEST_PRINTABLE_STRING) { + error("Printable strings limited to length of %d.\n", + LARGEST_PRINTABLE_STRING); + } +} + +/* equivalent to strcpy(x, y); return x + strlen(y), but faster and safer */ +/* Code like: + * + * char buf[256]; + * strcpy(buf, ...); + * strcat(buf, ...); + * strcat(buf, ...); + * + * Should be replaced with: + * + * char buf[256]; + * char *p, *end = EndOf(buf); + * p = strput(buf, end, ...); + * p = strput(p, end, ...); + * p = strput(p, end, ...); + */ +char *strput (char * x, char * limit, const char * y) { + while ((*x++ = *y++)) { + if (x == limit) { + *(x-1) = 0; + break; + } + } + return x - 1; +} + +char *strput_int (char * x, char * limit, int num) { + char buf[20]; + sprintf(buf, "%d", num); + return strput(x, limit, buf); +} + +#ifdef PRIVS +static void +init_privs_for_object (object_t * ob) +{ + svalue_t *value; + + if (!current_object +#ifdef PACKAGE_UIDS + || !current_object->uid +#endif + ) { + ob->privs = NULL; + return; + } + push_malloced_string(add_slash(ob->obname)); + + if (master_ob) + value = apply_master_ob(APPLY_PRIVS_FILE, 1); + else + value = apply(applies_table[APPLY_PRIVS_FILE], ob, 1, ORIGIN_DRIVER); + + if (value == NULL || value->type != T_STRING) + ob->privs = NULL; + else + ob->privs = make_shared_string(value->u.string); +} +#endif /* PRIVS */ + +/* + * Give the correct uid and euid to a created object. + */ +#ifdef PACKAGE_UIDS +static int give_uid_to_object (object_t * ob) +{ + svalue_t *ret; + const char *creator_name; + + if (!master_ob) { + ob->uid = add_uid("NONAME"); +#ifdef AUTO_SETEUID + ob->euid = ob->uid; +#else + ob->euid = NULL; +#endif + return 1; + } + /* + * Ask master object who the creator of this object is. + */ + push_malloced_string(add_slash(ob->obname)); + + ret = apply_master_ob(APPLY_CREATOR_FILE, 1); + if (!ret) + error("master object: No function %s() defined!\n", + applies_table[APPLY_CREATOR_FILE]); + if (!ret || ret == (svalue_t *)-1 || ret->type != T_STRING) { + destruct_object(ob); + if (!ret) error("Master object has no function %s().\n", applies_table[APPLY_CREATOR_FILE]); + if (ret == (svalue_t *)-1) error("Can't load objects without a master object."); + error("Illegal object to load: return value of master::%s() was not a string.\n", applies_table[APPLY_CREATOR_FILE]); + } + creator_name = ret->u.string; + /* + * Now we are sure that we have a creator name. Do not call apply() + * again, because creator_name will be lost ! + */ + if (strcmp(current_object->uid->name, creator_name) == 0) { + /* + * The loaded object has the same uid as the loader. + */ +#ifndef COMPAT_32 + ob->uid = current_object->uid; +#else + ob->uid = current_object->euid; +#endif + ob->euid = current_object->euid; + return 1; + } +#ifdef AUTO_TRUST_BACKBONE + if (strcmp(backbone_uid->name, creator_name) == 0) { + /* + * The object is loaded from backbone. This is trusted, so we let it + * inherit the value of eff_user. + */ + ob->uid = current_object->euid; + ob->euid = current_object->euid; + return 1; + } +#endif + + /* + * The object is not loaded from backbone, nor from from the loading + * objects path. That should be an object defined by another wizard. It + * can't be trusted, so we give it the same uid as the creator. Also give + * it eff_user 0, which means that user 'a' can't use objects from user + * 'b' to load new objects nor modify files owned by user 'b'. + * + * If this effect is wanted, user 'b' must let his object do 'seteuid()' to + * himself. That is the case for most rooms. + */ + ob->uid = add_uid(creator_name); +#ifdef AUTO_SETEUID + ob->euid = ob->uid; +#else + ob->euid = NULL; +#endif + return 1; +} +#endif + +static int init_object (object_t * ob) +{ +#ifdef PACKAGE_MUDLIB_STATS + init_stats_for_object(ob); +#endif +#ifdef PRIVS + init_privs_for_object(ob); +#endif /* PRIVS */ +#ifdef PACKAGE_MUDLIB_STATS + add_objects(&ob->stats, 1); +#endif +#ifdef NO_ADD_ACTION + if (function_exists(APPLY_CATCH_TELL, ob, 1) || + function_exists(APPLY_RECEIVE_MESSAGE, ob, 1)) + ob->flags |= O_LISTENER; +#endif +#ifdef PACKAGE_UIDS + return give_uid_to_object(ob); +#else + return 1; +#endif +} + + +static object_t *load_virtual_object (const char * name, int clone) +{ + int argc = 2; + char *new_name; + object_t *new_ob, *ob; + array_t *args = 0; + svalue_t *v; + + if (!master_ob) { + if (clone) + pop_n_elems(clone - 1); + return 0; + } + + if (clone > 1) { + args = allocate_empty_array(clone - 1); + while (clone-- > 1) + args->item[clone - 1] = *sp--; + argc++; + clone = 1; + } + push_malloced_string(add_slash(name)); + push_number(clone); + if (args) + push_refed_array(args); + v = apply_master_ob(APPLY_COMPILE_OBJECT, argc); + if (!v || (v->type != T_OBJECT)) + return 0; + new_ob = v->u.ob; + + if (!clone) { + ob = lookup_object_hash(name); + if (ob && ob != new_ob) { + /* + * If we rename, we're going to have a duplicate name here. Don't + * allow this. Destruct the new object and raise an error. + */ + destruct_object(new_ob); + error("Virtual object name duplicates an existing object name.\n"); + } + /* Make sure O_CLONE is NOT set */ + new_ob->flags &= ~O_CLONE; + new_name = alloc_cstring(name, "load_virtual_object"); + SET_TAG(new_name, TAG_OBJ_NAME); + } else { + /* Make sure O_CLONE is set */ + new_ob->flags |= O_CLONE; + new_name = make_new_name(name); + } + +#ifdef PACKAGE_MUDLIB_STATS + add_objects(&new_ob->stats, -1); +#endif + + /* perform the object rename */ + remove_object_hash(new_ob); + if (new_ob->obname) + FREE((char *)new_ob->obname); + SETOBNAME(new_ob, new_name); + enter_object_hash(new_ob); + + /* finish initialization */ + new_ob->flags |= O_VIRTUAL; + new_ob->load_time = current_time; +#ifdef PACKAGE_MUDLIB_STATS + init_stats_for_object(new_ob); + add_objects(&new_ob->stats, 1); +#endif +#ifdef PRIVS + if (new_ob->privs) + free_string(new_ob->privs); + init_privs_for_object(new_ob); +#endif +#ifdef PACKAGE_UIDS + /* reassign uid */ + give_uid_to_object(new_ob); +#endif + return new_ob; +} + +int strip_name (const char * src, char * dest, int size) { + char last_c = 0; + char *p = dest; + char *end = dest + size - 1; + + while (*src == '/') src++; + + while (*src && p < end) { + if (last_c == '/' && *src == '/') src++; + else last_c = (*p++ = *src++); + } + + /* In some cases, (for example, object loading) this currently gets + * run twice, once in find_object, and once in load object. The + * net effect of this is: + * /foo.c -> /foo [no such exists, try to load] -> /foo created + * /foo.c.c -> /foo.c [no such exists, try to load] -> /foo created + * + * causing a duplicate object crash. There are two ways to fix this: + * (1) strip multiple .c's so that the output of this routine is something + * that doesn't change if this is run again. + * (2) make sure this routine is only called once on any name. + * + * The first solution is the one currently in use. + */ + while (p - dest > 2 && p[-1] == 'c' && p[-2] == '.') + p -= 2; + + *p = 0; + return 1; +} + +/* + * Load an object definition from file. If the object wants to inherit + * from an object that is not loaded, discard all, load the inherited object, + * and reload again. + * + * In mudlib3.0 when loading inherited objects, their reset() is not called. + * - why is this?? it makes no sense and causes a problem when a developer + * inherits code from a real used item. Say a room for example. In this case + * the room is loaded but is never set up properly, so when someone enters it + * it's all messed up. Realistically, I know that it's pretty bad style to + * inherit from an object that's actually being used and isn't just a building + * block, but I see no reason for this limitation. It happens, and when it + * does occur, produces mysterious results than can be hard to track down. + * for now, I've reenabled resetting. We'll see if anything breaks. -WF + * + * Save the command_giver, because reset() in the new object might change + * it. + * + */ +object_t *int_load_object (const char * lname) +{ + int f; + program_t *prog; + object_t *ob; + svalue_t *mret; + struct stat c_st; + char real_name[400], name[400], actualname[400], obname[400]; + + const char *pname = check_valid_path(lname, master_ob, "load_object", 0); + if(!pname) + error("Read access denied.\n"); + if (++num_objects_this_thread > INHERIT_CHAIN_SIZE) + error("Inherit chain too deep: > %d when trying to load '%s'.\n", INHERIT_CHAIN_SIZE, lname); +#ifdef PACKAGE_UIDS + if (current_object && current_object->euid == NULL) + error("Can't load objects when no effective user.\n"); +#endif + if (strrchr(pname, '#')) + error("Cannot load a clone.\n"); + if (!strip_name(lname, name, sizeof name)) + error("Filenames with consecutive /'s in them aren't allowed (%s).\n", + lname); + if (!strip_name(pname, actualname, sizeof actualname)) + error("Filenames with consecutive /'s in them aren't allowed (%s).\n", + pname); + + /* + * First check that the c-file exists. + */ + (void) strcpy(real_name, actualname); + (void) strcat(real_name, ".c"); + + (void) strcpy(obname, name); + (void) strcat(obname, ".c"); + + if (stat(real_name, &c_st) == -1 || S_ISDIR(c_st.st_mode)) { + save_command_giver(command_giver); + ob = load_virtual_object(actualname, 0); + restore_command_giver(); + num_objects_this_thread--; + return ob; + } + /* + * Check if it's a legal name. + */ + if (!legal_path(real_name)) { + debug_message("Illegal pathname: /%s\n", real_name); + error("Illegal path name '/%s'.\n", real_name); + } + + /* maybe move this section into compile_file? */ + if (comp_flag) { + debug_message(" compiling /%s ...", real_name); + } + f = open(real_name, O_RDONLY); + if (f == -1) { + debug_perror("compile_file", real_name); + error("Could not read the file '/%s'.\n", real_name); + } + save_command_giver(command_giver); + prog = compile_file(f, obname); + restore_command_giver(); + if (comp_flag) + debug_message(" done\n"); + update_compile_av(total_lines); + total_lines = 0; + close(f); + + + /* Sorry, can't handle objects without programs yet. */ + if (inherit_file == 0 && (num_parse_error > 0 || prog == 0)) { + if (num_parse_error == 0 && prog == 0) + error("No program in object '/%s'!\n", name); + + if (prog) { + free_prog(&prog); + } + error("Error in loading object '/%s'\n", name); + } + /* + * This is an iterative process. If this object wants to inherit an + * unloaded object, then discard current object, load the object to be + * inherited and reload the current object again. The global variable + * "inherit_file" will be set by lang.y to point to a file name. + */ + if (inherit_file) { + object_t *inh_obj; + char inhbuf[MAX_OBJECT_NAME_SIZE]; + + if (!strip_name(inherit_file, inhbuf, sizeof inhbuf)) + strcpy(inhbuf, inherit_file); + FREE(inherit_file); + inherit_file = 0; + + if (prog) { + free_prog(&prog); + prog = 0; + } + if (strcmp(inhbuf, name) == 0) { + error("Illegal to inherit self.\n"); + } + + if ((inh_obj = lookup_object_hash(inhbuf))) { + IF_DEBUG(fatal("Inherited object is already loaded!")); + } else { + inh_obj = load_object(inhbuf, 0); + } + if (!inh_obj) error("Inherited file '/%s' does not exist!\n", + inhbuf); + + /* + * Yes, the following is necessary. It is possible that when we + * loaded the inherited object, it loaded this object from it's + * create function. Without this check, that would crash the driver. + * -Beek + */ + if (!(ob = lookup_object_hash(name))) { + ob = load_object(name, 0); + /* sigh, loading the inherited file removed us */ + if (!ob) { + num_objects_this_thread--; + return 0; + } + ob->load_time = current_time; + } + num_objects_this_thread--; + return ob; + } + ob = get_empty_object(prog->num_variables_total); + /* Shared string is no good here */ + SETOBNAME(ob, alloc_cstring(name, "load_object")); + SET_TAG(ob->obname, TAG_OBJ_NAME); + ob->prog = prog; + ob->flags |= O_WILL_RESET; /* must be before reset is first called */ + ob->next_all = obj_list; + ob->prev_all = 0; + if(obj_list) + obj_list->prev_all = ob; + obj_list = ob; + enter_object_hash(ob); /* add name to fast object lookup table */ + save_command_giver(command_giver); + push_object(ob); + mret = apply_master_ob(APPLY_VALID_OBJECT, 1); + if (mret && !MASTER_APPROVED(mret)) { + destruct_object(ob); + error("master object: %s() denied permission to load '/%s'.\n", applies_table[APPLY_VALID_OBJECT], name); + } + + if (init_object(ob)) + call_create(ob, 0); + if (!(ob->flags & O_DESTRUCTED) && + function_exists(APPLY_CLEAN_UP, ob, 1)) { + ob->flags |= O_WILL_CLEAN_UP; + } + restore_command_giver(); + + if (ob) + debug(d_flag, ("--/%s loaded", ob->obname)); + + ob->load_time = current_time; + num_objects_this_thread--; + + return ob; +} + +static char *make_new_name (const char * str) +{ + static unsigned int i; + char *p = (char *)DXALLOC(strlen(str) + 12, TAG_OBJ_NAME, "make_new_name"); + + (void) sprintf(p, "%s#%u", str, i); + i++; + return p; +} + + +/* + * Save the command_giver, because reset() in the new object might change + * it. + */ +object_t *clone_object (const char * str1, int num_arg) +{ + object_t *ob, *new_ob; + +#ifdef PACKAGE_UIDS + if (current_object && current_object->euid == 0) { + error("Object must call seteuid() prior to calling clone_object().\n"); + } +#endif + + save_command_giver(command_giver); + + num_objects_this_thread = 0; + ob = find_object(str1); + if (ob && !object_visible(ob)) + ob = 0; + /* + * If the object self-destructed... + */ + if (ob == 0) { /* fix from 3.1.1 */ + restore_command_giver(); + pop_n_elems(num_arg); + return (0); + } + + if (ob->flags & O_CLONE) + error("Cannot clone from a clone\n"); + + if(ob->flags & O_VIRTUAL) { + new_ob = load_virtual_object(ob->obname, 1 + num_arg); + restore_command_giver(); + return new_ob; + /* + * we can skip all of the stuff below since we were already + * cloned once to have gotten to this stage. + */ + } + + /* We do not want the heart beat to be running for unused copied objects */ + if (ob->flags & O_HEART_BEAT) + (void) set_heart_beat(ob, 0); + new_ob = get_empty_object(ob->prog->num_variables_total); + SETOBNAME(new_ob, make_new_name(ob->obname)); + new_ob->flags |= (O_CLONE | (ob->flags & (O_WILL_CLEAN_UP | O_WILL_RESET))); + new_ob->load_time = ob->load_time; + new_ob->prog = ob->prog; + reference_prog(ob->prog, "clone_object"); + DEBUG_CHECK(!current_object, "clone_object() from no current_object !\n"); + + new_ob->next_all = obj_list; + obj_list->prev_all = new_ob; + new_ob->prev_all = 0; + obj_list = new_ob; + enter_object_hash(new_ob); /* Add name to fast object lookup table */ + + init_object(new_ob); + + call_create(new_ob, num_arg); + restore_command_giver(); + /* Never know what can happen ! :-( */ + if (new_ob->flags & O_DESTRUCTED) + return (0); + return (new_ob); +} + +#ifndef NO_ENVIRONMENT +object_t *environment (svalue_t * arg) +{ + object_t *ob = current_object; + + if (arg && arg->type == T_OBJECT) + ob = arg->u.ob; + if (ob == 0 || ob->super == 0 || (ob->flags & O_DESTRUCTED)) + return 0; + if (ob->flags & O_DESTRUCTED) + error("environment() of destructed object.\n"); + return ob->super; +} +#endif + +/* + * With no argument, present() looks in the inventory of the current_object, + * the inventory of our super, and our super. + * If the second argument is nonzero, only the inventory of that object + * is searched. + */ + + +#ifdef F_PRESENT +static object_t *object_present2 (const char *, object_t *); + +object_t *object_present (svalue_t * v, object_t * ob) +{ + svalue_t *ret; + object_t *ret_ob; + int specific = 0; + + if (ob == 0) + ob = current_object; + else + specific = 1; + if (ob->flags & O_DESTRUCTED) + return 0; + if (v->type == T_OBJECT) { + if (specific) { + if (v->u.ob->super == ob) + return v->u.ob; + else + return 0; + } + if (v->u.ob->super == ob || + (v->u.ob->super == ob->super && ob->super != 0)) + return v->u.ob->super; + return 0; + } + ret_ob = object_present2(v->u.string, ob->contains); + if (ret_ob) + return ret_ob; + if (specific) + return 0; + if (ob->super) { + push_svalue(v); + ret = apply(APPLY_ID, ob->super, 1, ORIGIN_DRIVER); + if (ob->super->flags & O_DESTRUCTED) + return 0; + if (!IS_ZERO(ret)) { + return ob->super; + } + return object_present2(v->u.string, ob->super->contains); + } + return 0; +} + +static object_t *object_present2 (const char * str, object_t * ob) +{ + svalue_t *ret; + const char *p; + int count = 0, length; + + length = strlen(str); + + if (length) { + p = str + length - 1; + if (uisdigit(*p)) { + do { + p--; + } while (p > str && uisdigit(*p)); + + if (*p == ' ') { + count = atoi(p + 1) - 1; + length = p - str; + } + } + } + for (; ob; ob = ob->next_inv) { + char *np; + np = new_string(length, "object_present2"); + memcpy(np, str, length); + np[length] = 0; + push_malloced_string(np); + ret = apply(APPLY_ID, ob, 1, ORIGIN_DRIVER); + if (ob->flags & O_DESTRUCTED) + return 0; + if (IS_ZERO(ret)) + continue; + if (count-- > 0) + continue; + return ob; + } + return 0; +} +#endif + +static const char *saved_master_name; +static const char *saved_simul_name; + +static void fix_object_names() { + SETOBNAME(master_ob, saved_master_name); + SETOBNAME(simul_efun_ob, saved_simul_name); +} + +/* + * Remove an object. It is first moved into the destruct list, and + * not really destructed until later. (see destruct2()). + */ +void destruct_object (object_t * ob) +{ + object_t **pp; + //int removed; +#ifndef NO_ENVIRONMENT + object_t *super; + object_t *save_restrict_destruct = restrict_destruct; + + if (restrict_destruct && restrict_destruct != ob) + error("Only this_object() can be destructed from move_or_destruct.\n"); +#endif + +#if defined(PACKAGE_SOCKETS) || defined(PACKAGE_EXTERNAL) + /* + * check if object has an efun socket referencing it for a callback. if + * so, close the efun socket. + */ + if (ob->flags & O_EFUN_SOCKET) { + close_referencing_sockets(ob); + } +#endif +#ifdef PACKAGE_PARSER + if (ob->pinfo) { + parse_free(ob->pinfo); + ob->pinfo = 0; + } +#endif + + if (ob->flags & O_DESTRUCTED) { + return; + } + remove_object_from_stack(ob); + /* + * If this is the first object being shadowed by another object, then + * destruct the whole list of shadows. + */ +#ifndef NO_SHADOWS + if (ob->shadowed && !ob->shadowing) { + object_t *otmp; + object_t *ob2; + + /* + * move from bottom to top of shadow chain + */ + for (ob2 = ob->shadowed; ob2->shadowed; ob2 = ob2->shadowed); + /* + * remove shadows top...down being careful to unlink shadow being + * destructed from chain + */ + for (; ob2;) { + otmp = ob2; + ob2 = ob2->shadowing; + if (ob2) + ob2->shadowed = 0; + otmp->shadowing = 0; + destruct_object(otmp); + } + return; + } + /* + * The chain of shadows is a double linked list. Take care to update it + * correctly. + */ + if (ob->shadowing) + ob->shadowing->shadowed = ob->shadowed; + if (ob->shadowed) + ob->shadowed->shadowing = ob->shadowing; + ob->shadowing = 0; + ob->shadowed = 0; +#endif + + debug(d_flag, ("Deobject_t /%s (ref %d)", ob->obname, ob->ref)); + +#ifndef NO_ENVIRONMENT + /* try to move our contents somewhere */ + super = ob->super; + + while (ob->contains) { + object_t *otmp; + + otmp = ob->contains; + /* + * An error here will not leave destruct() in an inconsistent + * stage. + */ + push_object(super); + + restrict_destruct = ob->contains; + (void)apply(APPLY_MOVE, ob->contains, 1, ORIGIN_DRIVER); + restrict_destruct = save_restrict_destruct; + /* OUCH! we could be dested by this. -Beek */ + if (ob->flags & O_DESTRUCTED) return; + if (otmp == ob->contains) + destruct_object(otmp); + } +#endif + +#ifdef PACKAGE_MUDLIB_STATS + add_objects(&ob->stats, -1); +#endif +#ifdef OLD_ED + if (ob->interactive && ob->interactive->ed_buffer) + save_ed_buffer(ob); +#else + if (ob->flags & O_IN_EDIT) { + object_save_ed_buffer(ob); + ob->flags &= ~O_IN_EDIT; + } +#endif +#ifndef NO_SNOOP + if (ob->flags & O_SNOOP) { + int i; + for (i = 0; i < max_users; i++) { + if (all_users[i] && all_users[i]->snooped_by == ob) + all_users[i]->snooped_by = 0; + } + ob->flags &= ~O_SNOOP; + } +#endif +#ifndef NO_ENVIRONMENT + /* + * Remove us out of this current room (if any). Remove all sentences + * defined by this object from all objects here. + */ + if (ob->super) { +#ifndef NO_LIGHT + add_light(ob->super, -ob->total_light); +#endif + remove_sent(ob->super, ob); + remove_sent(ob, ob->super); + for (pp = &ob->super->contains; *pp;) { + remove_sent(*pp, ob); + if (*pp != ob) { + remove_sent(ob, *pp); + pp = &(*pp)->next_inv; + } else { + *pp = (*pp)->next_inv; + } + } + } +#endif + + /* At this point, we can still back out, but this is the very last + * minute we can do so. Make sure we have a new object to replace + * us if this is a vital object. + */ + if (ob == master_ob || ob == simul_efun_ob) { + object_t *new_ob, *tmp_ob; + const char *tmp = ob->obname; + + STACK_INC; + sp->type = T_ERROR_HANDLER; + sp->u.error_handler = fix_object_names; + saved_master_name = master_ob->obname; + saved_simul_name = simul_efun_ob->obname; + + /* hack to make sure we don't find ourselves at several points + in the following process */ + SETOBNAME(ob, ""); + + /* handle these two carefully, since they are rather vital */ + new_ob = load_object(tmp, compiled_version); + if (!new_ob) { + SETOBNAME(ob, tmp); + sp--; + error("Destruct on vital object failed: new copy failed to reload."); + } + + if (ob == master_ob) + set_master(new_ob); + if (ob == simul_efun_ob) + set_simul_efun(new_ob); + + /* Set the name back so we can remove it from the hash table. + Also be careful not to remove the new object, which has + the same name. */ + sp--; /* error handler */ + SETOBNAME(ob, tmp); + tmp = new_ob->obname; + SETOBNAME(new_ob, ""); + remove_object_hash(ob); + SETOBNAME(new_ob, tmp); + tmp_ob = ob; + free_object(&tmp_ob, "vital object reference"); + // still need ob below! + } else + remove_object_hash(ob); + + /* + * Now remove us out of the list of all objects. This must be done last, + * because an error in the above code would halt execution. + */ + //removed = 0; + if(ob->prev_all){ + ob->prev_all->next_all = ob->next_all; + if(ob->next_all) + ob->next_all->prev_all = ob->prev_all; + }else{ + obj_list = ob->next_all; + obj_list->prev_all = 0; + } + /* + for (pp = &obj_list; *pp; pp = &(*pp)->next_all) { + if (*pp != ob) + continue; + *pp = (*pp)->next_all; + removed = 1; + break; + } + DEBUG_CHECK(!removed, "Failed to delete object.\n");//*/ + + remove_living_name(ob); +#ifndef NO_ENVIRONMENT + ob->super = 0; + ob->next_inv = 0; + ob->contains = 0; +#endif + ob->next_all = obj_list_destruct; + if(obj_list_destruct) + obj_list_destruct->prev_all = ob; + ob->prev_all = 0; + obj_list_destruct = ob; + set_heart_beat(ob, 0); + ob->flags |= O_DESTRUCTED; + /* moved this here from destruct2() -- see comments in destruct2() */ + if (ob->interactive) + remove_interactive(ob, 1); +#ifdef F_SET_HIDE + if (ob->flags & O_HIDDEN) + num_hidden--; +#endif +} + +/* + * This one is called when no program is executing from the main loop. + */ +void destruct2 (object_t * ob) +{ +#ifndef NO_ADD_ACTION + sentence_t *s; +#endif + + debug(d_flag, ("Destruct-2 object /%s (ref %d)", ob->obname, ob->ref)); + + /* + * We must deallocate variables here, not in 'free_object()'. That is + * because one of the local variables may point to this object, and + * deallocation of this pointer will also decrease the reference count of + * this object. Otherwise, an object with a variable pointing to itself, + * would never be freed. Just in case the program in this object would + * continue to execute, change string and object variables into the + * number 0. + */ + if (ob->prog->num_variables_total > 0) { + /* + * Deallocate variables in this object. The space of the variables + * are not deallocated until the object structure is freed in + * free_object(). + */ + int i; + + for (i = 0; i < ob->prog->num_variables_total; i++) { + free_svalue(&ob->variables[i], "destruct2"); + ob->variables[i] = const0u; + } + } + +#ifndef NO_ADD_ACTION + /* + * For much the same reason as described above, we must remove sentences + * for this object. The reason is because the sentence callback could be + * a function pointer that is bound to this object and thus holds a + * reference to this object. + */ + for (s = ob->sent; s;) { + sentence_t *next; + + next = s->next; + free_sentence(s); + s = next; + } + ob->sent = 0; +#endif + +#ifdef DEBUG + tot_dangling_object++; + ob->next_all = obj_list_dangling; + if(obj_list_dangling) + obj_list_dangling->prev_all = ob; + obj_list_dangling = ob; + ob->prev_all = 0; +#endif + + free_object(&ob, "destruct_object"); +} + +/* + * say() efun - send a message to: + * all objects in the inventory of the source, + * all objects in the same environment as the source, + * and the object surrounding the source. + * + * when there is no command_giver, current_object is used as the source, + * otherwise, command_giver is used. + * + * message never goes to objects in the avoid array, or the source itself. + * + * rewritten, bobf@metronet.com (Blackthorn) 9/6/93 + */ + +#ifndef NO_ENVIRONMENT +static void send_say (object_t * ob, const char * text, array_t * avoid) +{ + int valid, j; + + for (valid = 1, j = 0; j < avoid->size; j++) { + if (avoid->item[j].type != T_OBJECT) + continue; + if (avoid->item[j].u.ob == ob) { + valid = 0; + break; + } + } + + if (!valid) + return; + + tell_object(ob, text, strlen(text)); +} + +void say (svalue_t * v, array_t * avoid) +{ + object_t *ob, *origin; + const char *buff; + + check_legal_string(v->u.string); + buff = v->u.string; + + if (current_object->flags & O_LISTENER || current_object->interactive) + save_command_giver(current_object); + else + save_command_giver(command_giver); + if (command_giver) + origin = command_giver; + else + origin = current_object; + + /* To our surrounding object... */ + if ((ob = origin->super)) { + if (ob->flags & O_LISTENER || ob->interactive) + send_say(ob, buff, avoid); + + /* And its inventory... */ + for (ob = origin->super->contains; ob; ob = ob->next_inv) { + if (ob != origin && (ob->flags & O_LISTENER || ob->interactive)) { + send_say(ob, buff, avoid); + if (ob->flags & O_DESTRUCTED) + break; + } + } + } + /* Our inventory... */ + for (ob = origin->contains; ob; ob = ob->next_inv) { + if (ob->flags & O_LISTENER || ob->interactive) { + send_say(ob, buff, avoid); + if (ob->flags & O_DESTRUCTED) + break; + } + } + + restore_command_giver(); +} + +/* + * Sends a string to all objects inside of a specific object. + * Revised, bobf@metronet.com 9/6/93 + */ +#ifdef F_TELL_ROOM +void tell_room (object_t * room, svalue_t * v, array_t * avoid) +{ + object_t *ob; + const char *buff; + int valid, j; + char txt_buf[LARGEST_PRINTABLE_STRING + 1]; + + switch (v->type) { + case T_STRING: + check_legal_string(v->u.string); + buff = v->u.string; + break; + case T_OBJECT: + buff = v->u.ob->obname; + break; + case T_NUMBER: + buff = txt_buf; + sprintf(txt_buf, "%ld", v->u.number); + break; + case T_REAL: + buff = txt_buf; + sprintf(txt_buf, "%f", v->u.real); + break; + default: + bad_argument(v, T_OBJECT | T_NUMBER | T_REAL | T_STRING, + 2, F_TELL_ROOM); + IF_DEBUG(buff = 0); + } + + for (ob = room->contains; ob; ob = ob->next_inv) { + if (!ob->interactive && !(ob->flags & O_LISTENER)) + continue; + + for (valid = 1, j = 0; j < avoid->size; j++) { + if (avoid->item[j].type != T_OBJECT) + continue; + if (avoid->item[j].u.ob == ob) { + valid = 0; + break; + } + } + + if (!valid) + continue; + + if (!ob->interactive) { + tell_npc(ob, buff); + if (ob->flags & O_DESTRUCTED) + break; + } else { + tell_object(ob, buff, strlen(buff)); + if (ob->flags & O_DESTRUCTED) + break; + } + } +} +#endif +#endif + +void shout_string (const char * str) +{ + object_t *ob; + + check_legal_string(str); + + for (ob = obj_list; ob; ob = ob->next_all) { + if (!(ob->flags & O_LISTENER) || (ob == command_giver) +#ifndef NO_ENVIRONMENT + || !ob->super +#endif + ) + continue; + tell_object(ob, str, strlen(str)); + } +} + +#ifdef F_INPUT_TO +/* + * Set up a function in this object to be called with the next + * user input string. + */ +int input_to (svalue_t * fun, int flag, int num_arg, svalue_t * args) +{ + sentence_t *s; + svalue_t *x; + int i; + + if (!command_giver || command_giver->flags & O_DESTRUCTED) + return 0; + s = alloc_sentence(); + if (set_call(command_giver, s, flag & ~I_SINGLE_CHAR)) { + /* + * If we have args, we copy them, and adjust the stack automatically + * (elsewhere) to avoid double free_svalue()'s + */ + if (num_arg) { + i = num_arg * sizeof(svalue_t); + if ((x = (svalue_t *) + DMALLOC(i, TAG_INPUT_TO, "input_to: 1")) == NULL) + fatal("Out of memory!\n"); + memcpy(x, args, i); + } else + x = NULL; + + command_giver->interactive->carryover = x; + command_giver->interactive->num_carry = num_arg; + if (fun->type == T_STRING) { + s->function.s = make_shared_string(fun->u.string); + s->flags = 0; + } else { + s->function.f = fun->u.fp; + fun->u.fp->hdr.ref++; + s->flags = V_FUNCTION; + } + s->ob = current_object; + add_ref(current_object, "input_to"); + return 1; + } + free_sentence(s); + return 0; +} +#endif + +/* + * Set up a function in this object to be called with the next + * user input character. + */ +#ifdef F_GET_CHAR +int get_char (svalue_t * fun, int flag, int num_arg, svalue_t * args) +{ + sentence_t *s; + svalue_t *x; + int i; + + if (!command_giver || command_giver->flags & O_DESTRUCTED) + return 0; + s = alloc_sentence(); + if (set_call(command_giver, s, flag | I_SINGLE_CHAR)) { + /* + * If we have args, we copy them, and adjust the stack automatically + * (elsewhere) to avoid double free_svalue()'s + */ + if (num_arg) { + i = num_arg * sizeof(svalue_t); + if ((x = (svalue_t *) + DMALLOC(i, TAG_TEMPORARY, "get_char: 1")) == NULL) + fatal("Out of memory!\n"); + memcpy(x, args, i); + } else + x = NULL; + + command_giver->interactive->carryover = x; + command_giver->interactive->num_carry = num_arg; + if (fun->type == T_STRING) { + s->function.s = make_shared_string(fun->u.string); + s->flags = 0; + } else { + s->function.f = fun->u.fp; + fun->u.fp->hdr.ref++; + s->flags = V_FUNCTION; + } + s->ob = current_object; + add_ref(current_object, "get_char"); + return 1; + } + free_sentence(s); + return 0; +} +#endif + +void print_svalue (svalue_t * arg) +{ + char tbuf[2048]; + int len; + + if (arg == 0) { + tell_object(command_giver, "", 6); + } else + switch (arg->type) { + case T_STRING: + len = SVALUE_STRLEN(arg); + if (len > LARGEST_PRINTABLE_STRING) { + error("Printable strings limited to length of %d.\n", + LARGEST_PRINTABLE_STRING); + } + + tell_object(command_giver, arg->u.string, len); + break; + case T_OBJECT: + sprintf(tbuf, "OBJ(/%s)", arg->u.ob->obname); + tell_object(command_giver, tbuf, strlen(tbuf)); + break; + case T_NUMBER: + sprintf(tbuf, "%ld", arg->u.number); + tell_object(command_giver, tbuf, strlen(tbuf)); + break; + case T_REAL: + sprintf(tbuf, "%f", arg->u.real); + tell_object(command_giver, tbuf, strlen(tbuf)); + break; + case T_ARRAY: + tell_object(command_giver, "", strlen("")); + break; + case T_MAPPING: + tell_object(command_giver, "", strlen("")); + break; + case T_FUNCTION: + tell_object(command_giver, "", strlen("")); + break; +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + tell_object(command_giver, "", strlen("")); + break; +#endif + default: + tell_object(command_giver, "", strlen("")); + break; + } + return; +} + +void do_write (svalue_t * arg) +{ + object_t *ob = command_giver; + +#ifndef NO_SHADOWS + if (ob == 0 && current_object->shadowing) + ob = current_object; + if (ob) { + /* Send the message to the first object in the shadow list */ + while (ob->shadowing) + ob = ob->shadowing; + } +#else + if (!ob) + ob = current_object; +#endif /* NO_SHADOWS */ + save_command_giver(ob); + print_svalue(arg); + restore_command_giver(); +} + +/* Find an object. If not loaded, load it ! + * The object may selfdestruct, which is the only case when 0 will be + * returned. + */ + +object_t *find_object (const char * str) +{ + object_t *ob; + char tmpbuf[MAX_OBJECT_NAME_SIZE]; + + if (!strip_name(str, tmpbuf, sizeof tmpbuf)) + return 0; + + if ((ob = lookup_object_hash(tmpbuf))) { + return ob; + } + ob = load_object(tmpbuf, 0); + if (!ob || (ob->flags & O_DESTRUCTED)) /* *sigh* */ + return 0; + return ob; +} + +/* Look for a loaded object. Return 0 if non found. */ +object_t *find_object2 (const char * str) +{ + register object_t *ob; + char p[MAX_OBJECT_NAME_SIZE]; + + if (!strip_name(str, p, sizeof p)) + return 0; + + if ((ob = lookup_object_hash(p))) { + return ob; + } + return 0; +} + +#ifndef NO_ENVIRONMENT +/* + * Transfer an object. + * The object has to be taken from one inventory list and added to another. + * The main work is to update all command definitions, depending on what is + * living or not. Note that all objects in the same inventory are affected. + */ +void move_object (object_t * item, object_t * dest) +{ + object_t **pp, *ob; + + save_command_giver(command_giver); + + /* Recursive moves are not allowed. */ + for (ob = dest; ob; ob = ob->super) + if (ob == item) + error("Can't move object inside itself.\n"); +#ifndef NO_SHADOWS + if (item->shadowing) + error("Can't move an object that is shadowing.\n"); +#endif + +#if !defined(NO_RESETS) && defined(LAZY_RESETS) + try_reset(dest); +#endif +#ifndef NO_LIGHT + add_light(dest, item->total_light); +#endif + if (item->super) { + int okay = 0; + + remove_sent(item->super, item); + remove_sent(item, item->super); +#ifndef NO_LIGHT + add_light(item->super, -item->total_light); +#endif + for (pp = &item->super->contains; *pp;) { + if (*pp != item) { + remove_sent(item, *pp); + remove_sent(*pp, item); + pp = &(*pp)->next_inv; + continue; + } + /* + * unlink object from original inventory list + */ + *pp = item->next_inv; + okay = 1; + } +#ifdef DEBUG + if (!okay) + fatal("Failed to find object /%s in super list of /%s.\n", + item->obname, item->super->obname); +#endif + } + /* + * link object into target's inventory list + */ + item->next_inv = dest->contains; + dest->contains = item; + item->super = dest; + + setup_new_commands(dest, item); + restore_command_giver(); +} +#endif + +#ifndef NO_LIGHT +/* + * Every object has a count of the number of light sources it contains. + * Update this. + */ + +void add_light (object_t * p, int n) +{ + if (n == 0) + return; + p->total_light += n; +#ifndef NO_ENVIRONMENT + while ((p = p->super)) + p->total_light += n; +#endif +} +#endif + +static sentence_t *sent_free = 0; +int tot_alloc_sentence; + +sentence_t *alloc_sentence() +{ + sentence_t *p; + + if (sent_free == 0) { + p = ALLOCATE(sentence_t, TAG_SENTENCE, "alloc_sentence"); + tot_alloc_sentence++; + } else { + p = sent_free; + sent_free = sent_free->next; + } +#ifndef NO_ADD_ACTION + p->verb = 0; +#endif + p->function.s = 0; + p->next = 0; + p->ob = 0; + p->flags = 0; + return p; +} + +#ifdef DEBUGMALLOC_EXTENSIONS +void mark_free_sentences() { + sentence_t *sent = sent_free; + + while (sent) { + DO_MARK(sent, TAG_SENTENCE); +/* Freed sentences should have been freed. right? + if (sent->function) + EXTRA_REF(BLOCK(sent->function))++; + if (sent->verb) + EXTRA_REF(BLOCK(sent->verb))++; +*/ + sent = sent->next; + } +} +#endif + +void free_sentence (sentence_t * p) +{ + if (p->flags & V_FUNCTION) { + if (p->function.f) + free_funp(p->function.f); + else p->function.f = 0; + } else { + if (p->function.s) + free_string(p->function.s); + else p->function.s = 0; + } +#ifndef NO_ADD_ACTION + if (p->verb) + free_string(p->verb); + p->verb = 0; +#endif + p->next = sent_free; + sent_free = p; +} + +void fatal (const char *fmt, ...) +{ + static int in_fatal = 0; + char msg_buf[2049]; + va_list args; + + switch (in_fatal) { + default: + debug_message("Fatal error while shutting down. Aborting.\n"); + break; + case 0: + in_fatal = 1; + V_START(args, fmt); + V_VAR(char *, fmt, args); + vsnprintf(msg_buf, 2048, fmt, args); + va_end(args); + debug_message("******** FATAL ERROR: %s\nFluffOS driver attempting to exit gracefully.\n", msg_buf); + if (current_file) + debug_message("(occured during compilation of %s at line %d)\n", current_file, current_line); + if (current_object) + debug_message("(current object was /%s)\n", current_object->obname); + + dump_trace(1); + +#ifdef PACKAGE_MUDLIB_STATS + save_stat_files(); +#endif + case 1: + in_fatal = 2; + copy_and_push_string(msg_buf); + push_object(command_giver); + push_object(current_object); + safe_apply_master_ob(APPLY_CRASH, 3); + debug_message("crash() in master called successfully. Aborting.\n"); + } + /* Make sure we don't trap our abort() */ +#ifdef SIGABRT + signal(SIGABRT, SIG_DFL); +#endif +#ifdef SIGILL + signal(SIGILL, SIG_DFL); +#endif +#ifdef SIGIOT + signal(SIGIOT, SIG_DFL); +#endif + +#if !defined(DEBUG_NON_FATAL) || !defined(DEBUG) + abort(); +#endif + in_fatal = 0; +} + +static int num_error = 0; + +#ifdef MUDLIB_ERROR_HANDLER +static int num_mudlib_error = 0; +#endif + +/* + * Error() has been "fixed" so that users can catch and throw them. + * To catch them nicely, we really have to provide decent error information. + * Hence, all errors that are to be caught + * (error_recovery_context_exists == 2) construct a string containing + * the error message, which is returned as the + * thrown value. Users can throw their own error values however they choose. + */ + +/* + * This is here because throw constructs its own return value; we dont + * want to replace it with the system's error string. + */ + +void throw_error() +{ + if (((current_error_context->save_csp + 1)->framekind & FRAME_MASK) == FRAME_CATCH) { + LONGJMP(current_error_context->context, 1); + fatal("Throw_error failed!"); + } + error("Throw with no catch.\n"); +} + +static void debug_message_with_location (char * err) { + if (current_object && current_prog) { + debug_message("%sprogram: /%s, object: /%s, file: %s\n", + err, + current_prog->filename, + current_object->obname, + get_line_number(pc, current_prog)); + } else if (current_object) { + debug_message("%sprogram: (none), object: /%s, file: (none)\n", + err, + current_object->obname); + } else { + debug_message("%sprogram: (none), object: (none), file: (none)\n", + err); + } +} + +static void add_message_with_location (char * err) { + if (current_object && current_prog) { + add_vmessage(command_giver, "%sprogram: /%s, object: /%s, file: %s\n", + err, + current_prog->filename, + current_object->obname, + get_line_number(pc, current_prog)); + } else if (current_object) { + add_vmessage(command_giver, "%sprogram: (none), object: /%s, file: (none)\n", + err, + current_object->obname); + } else { + add_vmessage(command_giver, "%sprogram: (none), object: (none), file: (none)\n", + err); + } +} + +#ifdef MUDLIB_ERROR_HANDLER +static void mudlib_error_handler (char * err, int katch) { + mapping_t *m; + const char *file = NULL; + int line = 0; + svalue_t *mret; + + m = allocate_mapping(6); + add_mapping_string(m, "error", err); + if (current_prog) + add_mapping_malloced_string(m, "program", add_slash(current_prog->filename)); + if (current_object) + add_mapping_object(m, "object", current_object); + add_mapping_array(m, "trace", get_svalue_trace()); + if (current_prog) + get_line_number_info(&file, &line); + if(file) + add_mapping_malloced_string(m, "file", add_slash(file)); + if(line) + add_mapping_pair(m, "line", line); + + push_refed_mapping(m); + if (katch) { + STACK_INC; + *sp = const1; + mret = apply_master_ob(APPLY_ERROR_HANDLER,2); + } else { + mret = apply_master_ob(APPLY_ERROR_HANDLER,1); + } + if ((mret == (svalue_t *)-1) || !mret) { + debug_message("No error handler for error: "); + debug_message_with_location(err); + dump_trace(0); + } else if (mret->type == T_STRING) { + debug_message("%s", mret->u.string); + } +} +#endif + +void error_handler (char * err) +{ + const char *object_name; + + /* in case we're going to jump out of load_object */ +#ifndef NO_ENVIRONMENT + restrict_destruct = 0; +#endif + num_objects_this_thread = 0;/* reset the count */ + + if (((current_error_context->save_csp + 1)->framekind & FRAME_MASK) == FRAME_CATCH) { + /* user catches this error */ +#ifdef LOG_CATCHES + /* This is added so that catches generate messages in the log file. */ +#ifdef MUDLIB_ERROR_HANDLER + if (num_mudlib_error) { + debug_message("Error in error handler: "); + num_error++; +#endif + debug_message_with_location(err); + (void) dump_trace(0); +#ifdef MUDLIB_ERROR_HANDLER + num_error--; + num_mudlib_error = 0; + } else { + if(max_eval_error) + outoftime = 0; + + if (!too_deep_error) { + num_mudlib_error++; + mudlib_error_handler(err, 1); + num_mudlib_error--; + } + } +#endif +#endif + if(max_eval_error) + outoftime = 1; + free_svalue(&catch_value, "caught error"); + catch_value.type = T_STRING; + catch_value.subtype = STRING_MALLOC; + catch_value.u.string = string_copy(err, "caught error"); + LONGJMP(current_error_context->context, 1); + fatal("Catch() longjump failed"); + } + + if (num_error > 0) { + /* This can happen via errors in the object_name() apply. */ + debug_message("Error '%s' while trying to print error trace -- trace suppressed.\n", err); + too_deep_error = max_eval_error = 0; + if (current_error_context) + LONGJMP(current_error_context->context, 1); + fatal("LONGJMP failed or no error context for error.\n"); + } + + num_error++; +#ifdef PACKAGE_MUDLIB_STATS + if (current_object) + add_errors(¤t_object->stats, 1); +#endif +#ifdef MUDLIB_ERROR_HANDLER + if (!too_deep_error) { + if (num_mudlib_error) { + debug_message("Error in error handler: "); + debug_message_with_location(err); + (void) dump_trace(0); + num_mudlib_error = 0; + } else { + num_mudlib_error++; + num_error--; + outoftime = 0; + mudlib_error_handler(err, 0); + if(max_eval_error) + outoftime = 1; + num_mudlib_error--; + num_error++; + } + } + else +#endif + { + debug_message_with_location(err + 1); +#if defined(DEBUG) && defined(TRACE_CODE) + object_name = dump_trace(1); +#else + object_name = dump_trace(0); +#endif + if (object_name) { + object_t *ob; + + ob = find_object2(object_name); + if (!ob) { + if (command_giver) + add_vmessage(command_giver, + "error when executing program in destroyed object /%s\n", + object_name); + debug_message("error when executing program in destroyed object /%s\n", + object_name); + } + } + if (command_giver && command_giver->interactive) { +#ifndef NO_WIZARDS + if ((command_giver->flags & O_IS_WIZARD) || !strlen(DEFAULT_ERROR_MESSAGE)) { +#endif + add_message_with_location(err + 1); +#ifndef NO_WIZARDS + } else { + add_vmessage(command_giver, "%s\n", DEFAULT_ERROR_MESSAGE); + } +#endif + } + if (current_heart_beat) { + static char hb_message[] = "FluffOS driver tells you: You have no heart beat!\n"; + set_heart_beat(current_heart_beat, 0); + debug_message("Heart beat in /%s turned off.\n", current_heart_beat->obname); + if (current_heart_beat->interactive) + add_message(current_heart_beat, hb_message, sizeof(hb_message)-1); + + current_heart_beat = 0; + } + } + num_error--; + too_deep_error = max_eval_error = 0; + if (current_error_context) + LONGJMP(current_error_context->context, 1); + fatal("LONGJMP failed or no error context for error.\n"); +} + +void error_needs_free (char * s) +{ + char err_buf[2048]; + strncpy(err_buf + 1, s, 2047); + err_buf[0] = '*'; /* all system errors get a * at the start */ + err_buf[2047] = '\0'; + FREE_MSTR(s); + + error_handler(err_buf); +} + +void error (const char * const fmt, ...) +{ + char err_buf[2048]; + va_list args; + + V_START(args, fmt); + V_VAR(char *, fmt, args); + vsnprintf(err_buf + 1, 2046, fmt, args); + va_end(args); + err_buf[0] = '*'; /* all system errors get a * at the start */ + DTRACE_PROBE1(fluffos, error, (char *)err_buf); + error_handler(err_buf); +} + +/* + * This one is called from HUP. + */ +int MudOS_is_being_shut_down; + +#ifdef SIGNAL_FUNC_TAKES_INT +void startshutdownMudOS (int sig) +#else +void startshutdownMudOS() +#endif +{ + MudOS_is_being_shut_down = 1; +} + +/* + * This one is called from the command "shutdown". + * We don't call it directly from HUP, because it is dangerous when being + * in an interrupt. + */ +void shutdownMudOS (int exit_code) +{ + int i; + + shout_string("FluffOS driver shouts: shutting down immediately.\n"); +#ifdef PACKAGE_MUDLIB_STATS + save_stat_files(); +#endif +#ifdef PACKAGE_ASYNC + complete_all_asyncio(); +#endif + +#ifdef PACKAGE_DB + db_cleanup(); +#endif + ipc_remove(); +#if defined(PACKAGE_SOCKETS) || defined(PACKAGE_EXTERNAL) + for (i = 0; i < max_lpc_socks; i++) { + if (lpc_socks[i].state == STATE_CLOSED) continue; + while (OS_socket_close(lpc_socks[i].fd) == -1 && errno == EINTR) + ; + } +#endif + for (i = 0; i < max_users; i++) { + if (all_users[i] && !(all_users[i]->iflags & CLOSING)) + flush_message(all_users[i]); + } +#ifdef PROFILING + monitor(0, 0, 0, 0, 0); /* cause gmon.out to be written */ +#endif + exit(exit_code); +} + +/* + * Call this one when there is only little memory left. It will start + * Armageddon. + */ +void slow_shut_down (int minutes) +{ + /* + *free some memory. + */ + svalue_t *amo; + + push_number(minutes); + amo = apply_master_ob(APPLY_SLOW_SHUTDOWN, 1); + /* in this case, approved means the mudlib will handle it */ + if (!MASTER_APPROVED(amo)) + { + object_t *save_current = current_object; + + current_object = 0; + save_command_giver(0); + shout_string("FluffOS driver shouts: Out of memory.\n"); + restore_command_giver(); + current_object = save_current; +#ifdef SIGNAL_FUNC_TAKES_INT + startshutdownMudOS(1); +#else + startshutdownMudOS(); +#endif + return; + } +} + +void do_message (svalue_t * lclass, svalue_t * msg, array_t * scope, array_t * exclude, int recurse) +{ + int i, j, valid; + object_t *ob; + + for (i = 0; i < scope->size; i++) { + switch (scope->item[i].type) { + case T_STRING: + ob = find_object(scope->item[i].u.string); + if (!ob || !object_visible(ob)) + continue; + break; + case T_OBJECT: + ob = scope->item[i].u.ob; + break; + default: + continue; + } + if (ob->flags & O_LISTENER || ob->interactive) { + for (valid = 1, j = 0; j < exclude->size; j++) { + if (exclude->item[j].type != T_OBJECT) + continue; + if (exclude->item[j].u.ob == ob) { + valid = 0; + break; + } + } + if (valid) { + push_svalue(lclass); + push_svalue(msg); + apply(APPLY_RECEIVE_MESSAGE, ob, 2, ORIGIN_DRIVER); + } + } +#ifndef NO_ENVIRONMENT + else if (recurse) { + array_t *tmp; + + tmp = all_inventory(ob, 1); + do_message(lclass, msg, tmp, exclude, 0); + free_array(tmp); + } +#endif + } +} + +#if !defined(NO_RESETS) && defined(LAZY_RESETS) +void try_reset (object_t * ob) +{ + if ((ob->next_reset < current_time) && !(ob->flags & O_RESET_STATE)) { + debug(d_flag, ("(lazy) RESET /%s\n", ob->obname)); + + /* need to set the flag here to prevent infinite loops in apply_low */ + ob->flags |= O_RESET_STATE; + reset_object(ob); + } +} +#endif + +#ifndef NO_ENVIRONMENT +#ifdef F_FIRST_INVENTORY +object_t *first_inventory (svalue_t * arg) +{ + object_t *ob; + + if (arg->type == T_STRING) { + ob = find_object(arg->u.string); + if (ob && !object_visible(ob)) + ob = 0; + } else + ob = arg->u.ob; + if (ob == 0) + bad_argument(arg, T_STRING | T_OBJECT, 1, F_FIRST_INVENTORY); + ob = ob->contains; + +#ifdef F_SET_HIDE + while (ob && (ob->flags & O_HIDDEN) && !object_visible(ob)) + ob = ob->next_inv; +#endif + + return ob; +} +#endif +#endif diff --git a/fluffos-2.23-ds03/simulate.h b/fluffos-2.23-ds03/simulate.h new file mode 100644 index 0000000..a3acc69 --- /dev/null +++ b/fluffos-2.23-ds03/simulate.h @@ -0,0 +1,83 @@ +#ifndef SIMULATE_H +#define SIMULATE_H + +/* It is usually better to include "lpc_incl.h" instead of including this + directly */ + +#define V_SHORT 1 +#define V_NOSPACE 2 +#define V_FUNCTION 4 + +/* The end of a static buffer */ +#define EndOf(x) (x + sizeof(x)/sizeof(x[0])) + +/* + * simulate.c + */ + +extern object_t *obj_list; +extern object_t *obj_list_destruct; +extern object_t *current_object; +extern object_t *command_giver; +extern object_t *current_interactive; +extern char *inherit_file; +extern int tot_alloc_sentence; +extern int MudOS_is_being_shut_down; +#ifdef DEBUG +extern object_t *obj_list_dangling; +extern int tot_dangling_object; +#endif + +char *strput (char *, char *, const char *); +char *strput_int (char *, char *, int); +void CDECL debug_fatal (char *, ...); +void CDECL fatal (const char *, ...); +void CDECL error (const char * const, ...); +INLINE void check_legal_string (const char *); +#ifndef NO_LIGHT +void add_light (object_t *, int); +#endif +void free_sentence (sentence_t *); + +sentence_t *alloc_sentence (void); +int input_to (svalue_t *, int, int, svalue_t *); +int get_char (svalue_t *, int, int, svalue_t *); + +int strip_name (const char *, char *, int); +char *check_name (char *); +#define load_object(x, y) int_load_object(x) +object_t *int_load_object (const char *); +object_t *clone_object (const char *, int); +object_t *environment (svalue_t *); +object_t *first_inventory (svalue_t *); +object_t *object_present (svalue_t *, object_t *); +object_t *find_object (const char *); +object_t *find_object2 (const char *); +void move_object (object_t *, object_t *); +void destruct_object (object_t *); +void destruct2 (object_t *); + +void print_svalue (svalue_t *); +void do_write (svalue_t *); +void do_message (svalue_t *, svalue_t *, array_t *, array_t *, int); +void say (svalue_t *, array_t *); +void tell_room (object_t *, svalue_t *, array_t *); +void shout_string (const char *); + +void error_needs_free (char *); +void throw_error (void); +void error_handler (char *); + +#ifdef SIGNAL_FUNC_TAKES_INT +void startshutdownMudOS (int); +#else +void startshutdownMudOS (void); +#endif +void shutdownMudOS (int); +void slow_shut_down (int); + +#ifdef DEBUGMALLOC_EXTENSIONS +void mark_free_sentences (void); +#endif + +#endif diff --git a/fluffos-2.23-ds03/smalloc.c b/fluffos-2.23-ds03/smalloc.c new file mode 100644 index 0000000..119e3b9 --- /dev/null +++ b/fluffos-2.23-ds03/smalloc.c @@ -0,0 +1,1454 @@ +/* Satoria's malloc intended to be optimized for lpmud. +** this memory manager distinguishes between two sizes +** of blocks: small and large. It manages them separately +** in the hopes of avoiding fragmentation between them. +** It expects small blocks to mostly be temporaries. +** It expects an equal number of future requests as small +** block deallocations. +** +** support for atari st/tt and FAST_FIT by amylaar @cs.tu-berlin.de +** +** adapted by Blackthorn@Genocide to work with MudOS 0.9.15 - 93/01/26 +** +** Amiga Lattice support added by Robocoder@TMI-2 +*/ + +#define IN_MALLOC_WRAPPER +#define NO_OPCODES +#include "std.h" +#include "file_incl.h" +#include "lpc_incl.h" +#include "simulate.h" +#include "comm.h" + +#if defined(sparc) +#define MALLOC_ALIGN 8 +#else +#define MALLOC_ALIGN 4 +#endif + +#define POINTER void * +#define FREE_RETURN_TYPE void +#define FREE_RETURN return; +#define SFREE_RETURN_TYPE FREE_RETURN_TYPE +#define SFREE_RETURN FREE_RETURN + +#define FIT_STYLE_FAST_FIT + +#undef LARGE_TRACE + +#define fake(s) + +#define SMALL_BLOCK_MAX_BYTES 32 +#define SMALL_CHUNK_SIZE 0x4000 +#define CHUNK_SIZE 0x40000 + +#define SMALL_BLOCK_MAX (SMALL_BLOCK_MAX_BYTES/SIZEOF_INT) + +#define PREV_BLOCK 0x80000000 +#define THIS_BLOCK 0x40000000 +#define NO_REF 0x20000000 /* check this in gcollect.c */ +#define MASK 0x0FFFFFFF + +#define MAGIC 0x17952932 + +/* SMALL BLOCK info */ + +typedef unsigned int u; + +static u *last_small_chunk = 0; +static u *sfltable[SMALL_BLOCK_MAX] = +{0, 0, 0, 0, 0, 0, 0, 0}; /* freed list */ +static u *next_unused = 0; +static u unused_size = 0; /* until we need a new chunk */ + +/* LARGE BLOCK info */ + +#ifndef FIT_STYLE_FAST_FIT +static u *free_list = 0; +#endif /* FIT_STYLE_FAST_FIT */ +static u *start_next_block = 0; + +/* STATISTICS */ + +static int small_count[SMALL_BLOCK_MAX] = +{0, 0, 0, 0, 0, 0, 0, 0}; +static int small_total[SMALL_BLOCK_MAX] = +{0, 0, 0, 0, 0, 0, 0, 0}; +static int small_max[SMALL_BLOCK_MAX] = +{0, 0, 0, 0, 0, 0, 0, 0}; +static int small_free[SMALL_BLOCK_MAX] = +{0, 0, 0, 0, 0, 0, 0, 0}; + +typedef struct { + unsigned counter, size; +} t_stat; + +#define count(a,b) { a.size+=(b); if ((b)<0) --a.counter; else ++a.counter; } +#define count_up(a,b) { a.size+=(b); ++a.counter; } +#define count_back(a,b) { a.size-=(b); --a.counter; } + +#if 0 +int debugmalloc = 0; /* Only used when debuging malloc() */ +#endif + +/********************************************************/ +/* SMALL BLOCK HANDLER */ +/********************************************************/ + +static char *large_malloc (u, int); +static void large_free (char *); +static int malloc_size_mask (void); +static int malloced_size (POINTER); +static void show_block (u *); +static void remove_from_free_list (u *); +static void add_to_free_list (u *); +static void build_block (u *, u); +static void mark_block (u *); +static char *esbrk (u); +static int resort_free_list (void); +#ifdef DEBUG +static void walk_new_small_malloced (void (*func) (POINTER, int)); +#endif + +#define s_size_ptr(p) (p) +#define s_next_ptr(p) ((u **) (p+1)) + +t_stat small_alloc_stat = +{0, 0}; +t_stat small_free_stat = +{0, 0}; +t_stat small_chunk_stat = +{0, 0}; + +POINTER CDECL smalloc_malloc (size_t size) +{ + /* int i; */ + u *temp; + + DEBUG_CHECK(size == 0, "Malloc size 0.\n"); + if (size > SMALL_BLOCK_MAX_BYTES) + return large_malloc(size, 0); + +#if SIZEOF_PTR > SIZEOF_INT + if (size < SIZEOF_PTR) + size = SIZEOF_PTR; +#endif + + size = (size + 7) & ~3; /* block size in bytes */ +#define SIZE_INDEX(u_array, size) (*(u*) ((char*)u_array-8+size)) +#define SIZE_PNT_INDEX(u_array, size) (*(u**)((char*)u_array-8+size)) + /* i = (size - 8) >> 2; */ + count_up(small_alloc_stat, size); + + SIZE_INDEX(small_count, size) += 1; /* update statistics */ + SIZE_INDEX(small_total, size) += 1; + if (SIZE_INDEX(small_count, size) > SIZE_INDEX(small_max, size)) + SIZE_INDEX(small_max, size) = SIZE_INDEX(small_count, size); + + if (temp = SIZE_PNT_INDEX(sfltable, size)) { /* allocate from the + * free list */ + count_back(small_free_stat, size); + temp++; + SIZE_PNT_INDEX(sfltable, size) = *(u **) temp; + fake("From free list."); + return (char *) temp; + } /* else allocate from the chunk */ + if (unused_size < size) { /* no room in chunk, get another */ + /* + * don't waste this smaller block + */ + if (unused_size) { + count_up(small_free_stat, unused_size); + *s_size_ptr(next_unused) = unused_size >> 2; + *s_next_ptr(next_unused) = SIZE_PNT_INDEX(sfltable, unused_size); + SIZE_PNT_INDEX(sfltable, unused_size) = next_unused; + } + + fake("Allocating new small chunk."); + next_unused = (u *) large_malloc(SMALL_CHUNK_SIZE + SIZEOF_PTR, 1); + if (next_unused == 0) + return 0; + + *next_unused = (u) last_small_chunk; + last_small_chunk = next_unused++; + count_up(small_chunk_stat, SMALL_CHUNK_SIZE + SIZEOF_PTR); + count_up(small_alloc_stat, SIZEOF_PTR); + unused_size = SMALL_CHUNK_SIZE; + } else + fake("Allocated from chunk."); + + temp = (u *) s_next_ptr(next_unused); + *s_size_ptr(next_unused) = size >> 2; + unused_size -= size; + if (unused_size < (SIZEOF_INT + SIZEOF_PTR)) { + count_up(small_alloc_stat, unused_size); + if ((size + unused_size) < (SMALL_BLOCK_MAX_BYTES + SIZEOF_INT)) { + /* + * try to avoid waste + */ + size += unused_size; + *s_size_ptr(next_unused) = size >> 2; + } + unused_size = 0; + } + next_unused += size >> 2; + + fake("allocation from chunk successful\n"); + return (char *) temp; +} + +#ifdef DEBUG +char *debug_free_ptr; +#endif /* DEBUG */ + +static int malloc_size_mask() +{ + return MASK; +} + +static int malloced_size (POINTER ptr) +{ + return (((u *) ptr)[-1] & MASK); +} + +SFREE_RETURN_TYPE CDECL smalloc_free (POINTER ptr) +{ + u *block; + u i; + + if (!ptr) + SFREE_RETURN; + +#ifdef DEBUG + debug_free_ptr = ptr; +#endif /* DEBUG */ + block = (u *) ptr; + block -= 1; + i = (*s_size_ptr(block) & MASK); + if ((*s_size_ptr(block) & MASK) > SMALL_BLOCK_MAX + 1) { + fake("sfree calls large_free"); + large_free(ptr); + SFREE_RETURN + } + count_back(small_alloc_stat, i << 2); + count_up(small_free_stat, i << 2); + i -= 2; + *s_next_ptr(block) = sfltable[i]; + sfltable[i] = block; + small_free[i] += 1; + fake("Freed"); + SFREE_RETURN +} + +/************************************************/ +/* LARGE BLOCK HANDLER */ +/************************************************/ + +#define BEST_FIT 0 +#define FIRST_FIT 1 +#define HYBRID 2 + +#define fit_style BEST_FIT +/* if this is a constant, evaluate at compile-time.... */ +#ifndef fit_style +int fit_style = BEST_FIT; +#endif + +#define l_size_ptr(p) (p) +#define l_next_ptr(p) (*((u **) (p+1))) +#define l_prev_ptr(p) (*((u **) ((u **)(p+1)+1))) +#define l_next_block(p) (p + (MASK & (*(p))) ) +#define l_prev_block(p) (p - (MASK & (*(p-1))) ) +#define l_prev_free(p) (!(*p & PREV_BLOCK)) +#define l_next_free(p) (!(*l_next_block(p) & THIS_BLOCK)) + +static void show_block (u * ptr) +{ + printf("[%c%d: %d] ", (*ptr & THIS_BLOCK ? '+' : '-'), + ptr, (*ptr & MASK)); +} + +#ifdef FIT_STYLE_FAST_FIT + +#if defined(atarist) || defined (sun) || defined(AMIGA) +/* there is a type signed char */ +typedef SIGNED char balance_t; + +#define BALANCE_T_BITS 8 +#else +typedef short balance_t; + +#define BALANCE_T_BITS 16 +#endif +#if (defined(atarist) && !defined(ATARI_TT)) || defined(sparc) || defined(AMIGA) + /* try to avoid multiple shifts, because these are costly */ +#define NO_BARREL_SHIFT +#endif + +typedef struct free_block_s { + u size; + struct free_block_s *parent, *left, *right; + balance_t balance; + short align_dummy; +} free_block_t; + +/* prepare two nodes for the free tree that will never be removed, + so that we can always assume that the tree is and remains non-empty. */ +/* some compilers don't understand forward declarations of static vars. */ +extern free_block_t dummy2; + +static free_block_t dummy = { + /* size */ 0, + /* parent */ &dummy2, + /* left */ 0, + /* right */ 0, + /* balance */ 0 +}; + +free_block_t dummy2 = +{ + /* size */ 0, + /* parent */ 0, + /* left */ &dummy, + /* right */ 0, + /* balance */ -1 +}; + +static free_block_t *free_tree = &dummy2; + +#ifdef DEBUG_AVL +static int inconsistency = 0; + +static int check_avl (free_block_t * parent, free_block_t * p) +{ + int left, right; + + if (!p) + return 0; + left = check_avl(p, p->left); + right = check_avl(p, p->right); + if (p->balance != right - left || p->balance < -1 || p->balance > 1) { + printf("Inconsistency in avl node!\n"); + printf("node:%x\n", p); + printf("size: %d\n", p->size); + printf("left node:%x\n", p->left); + printf("left height: %d\n", left); + printf("right node:%x\n", p->right); + printf("right height: %d\n", right); + printf("alleged balance: %d\n", p->balance); + inconsistency = 1; + } + if (p->parent != parent) { + printf("Inconsistency in avl node!\n"); + printf("node:%x\n", p); + printf("size: %d\n", p->size); + printf("parent: %x\n", parent); + printf("parent size: %d\n", parent->size); + printf("alleged parent: %x\n", p->parent); + printf("alleged parent size: %d\n", p->parent->size); + printf("left height: %d\n", left); + printf("right height: %d\n", right); + printf("alleged balance: %d\n", p->balance); + inconsistency = 1; + } + return left > right ? left + 1 : right + 1; +} + +/* this function returns a value so that it can be used in ,-expressions. */ +static int do_check_avl() +{ + check_avl(0, free_tree); + if (inconsistency) { + fflush(stderr); + fflush(stdout); + fatal("Inconsistency could crash the driver\n"); + } + return 0; +} +#endif /* DEBUG_AVL */ + +t_stat large_free_stat; +static void remove_from_free_list (u * ptr) +{ + free_block_t *p, *q, *r, *s, *t; + + fake((do_check_avl(), "remove_from_free_list called")); + p = (free_block_t *) (ptr + 1); + count_back(large_free_stat, p->size << 2); +#ifdef DEBUG_AVL + printf("node:%x\n", p); + printf("size:%d\n", p->size); +#endif + if (p->left) { + if (q = p->right) { + fake("two childs"); + s = q; + for (; r = q, q = r->left;); + if (r == s) { + r->left = s = p->left; + s->parent = r; + if (r->parent = s = p->parent) { + if (p == s->left) { + s->left = r; + } else { + s->right = r; + } + } else { + free_tree = r; + } + r->balance = p->balance; + p = r; + goto balance_right; + } else { + t = r->parent; + if (t->left = s = r->right) { + s->parent = t; + } + r->balance = p->balance; + r->left = s = p->left; + s->parent = r; + r->right = s = p->right; + s->parent = r; + if (r->parent = s = p->parent) { + if (p == s->left) { + s->left = r; + } else { + s->right = r; + } + } else { + free_tree = r; + } + p = t; + goto balance_left; + } + } else { /* no right child, but left child */ + /* + * We set up the free list in a way so that there will remain at + * least two nodes, and the avl property ensures that the left + * child is a leaf ==> there is a parent + */ + fake("no right child, but left child"); + s = p; + p = s->parent; + r = s->left; + r->parent = p; + if (s == p->left) { + p->left = r; + goto balance_left; + } else { + p->right = r; + goto balance_right; + } + } + } else { /* no left child */ + /* + * We set up the free list in a way so that there is a node left of + * all used nodes, so there is a parent + */ + fake("no left child"); + s = p; + p = s->parent; + if (q = r = s->right) { + r->parent = p; + } + if (s == p->left) { + p->left = r; + goto balance_left; + } else { + p->right = r; + goto balance_right; + } + } + balance_q: + r = p; + p = q; + if (r == p->right) { + balance_t b; + + balance_right: + b = p->balance; + if (b > 0) { + p->balance = 0; + if (q = p->parent) + goto balance_q; + return; + } else if (b < 0) { + r = p->left; + b = r->balance; + if (b <= 0) { + /* R-Rotation */ +#ifdef DEBUG_AVL + fake("R-Rotation."); + printf("r->balance: %d\n", r->balance); +#endif + if (p->left = s = r->right) { + s->parent = p; + } + r->right = p; + s = p->parent; + p->parent = r; + b += 1; + r->balance = b; + b = -b; +#ifdef DEBUG_AVL + printf("node r: %x\n", r); + printf("r->balance: %d\n", r->balance); + printf("node p: %x\n", p); + p->balance = b; + printf("p->balance: %d\n", p->balance); + printf("r-height: %d\n", check_avl(r->parent, r)); +#endif + if (r->parent = s) { + if (p->balance = b) { + if (p == s->left) { + s->left = r; + return; + } else { + s->right = r; + return; + } + } + if (p == s->left) { + fake("left from parent"); + goto balance_left_s; + } else { + fake("right from parent"); + p = s; + p->right = r; + goto balance_right; + } + } + p->balance = b; + free_tree = r; + return; + } else { /* r->balance == +1 */ + /* LR-Rotation */ + balance_t b2; + + fake("LR-Rotation."); + t = r->right; + b = t->balance; + if (p->left = s = t->right) { + s->parent = p; + } + if (r->right = s = t->left) { + s->parent = r; + } + t->left = r; + t->right = p; + r->parent = t; + s = p->parent; + p->parent = t; +#ifdef NO_BARREL_SHIFT + b = -b; + b2 = b >> 1; + r->balance = b2; + b -= b2; + p->balance = b; +#else + b2 = (unsigned char) b >> 7; + p->balance = b2; + b2 = -b2 - b; + r->balance = b2; +#endif + t->balance = 0; +#ifdef DEBUG_AVL + printf("t-height: %d\n", check_avl(t->parent, t)); +#endif + if (t->parent = s) { + if (p == s->left) { + p = s; + s->left = t; + goto balance_left; + } else { + p = s; + s->right = t; + goto balance_right; + } + } + free_tree = t; + return; + } + } else { /* p->balance == 0 */ + p->balance = -1; + return; + } + } else { /* r == p->left */ + balance_t b; + + goto balance_left; + balance_left_s: + p = s; + s->left = r; + balance_left: + b = p->balance; + if (b < 0) { + p->balance = 0; + if (q = p->parent) + goto balance_q; + return; + } else if (b > 0) { + r = p->right; + b = r->balance; + if (b >= 0) { + /* L-Rotation */ +#ifdef DEBUG_AVL + fake("L-Rotation."); + printf("r->balance: %d\n", r->balance); +#endif + if (p->right = s = r->left) { + s->parent = p; + } + fake("subtree relocated"); + r->left = p; + s = p->parent; + p->parent = r; + b -= 1; + r->balance = b; + b = -b; +#ifdef DEBUG_AVL + fake("balances calculated"); + printf("node r: %x\n", r); + printf("r->balance: %d\n", r->balance); + printf("node p: %x\n", p); + p->balance = b; + printf("p->balance: %d\n", p->balance); + printf("r-height: %d\n", check_avl(r->parent, r)); +#endif + if (r->parent = s) { + if (p->balance = b) { + if (p == s->left) { + s->left = r; + return; + } else { + s->right = r; + return; + } + } + if (p == s->left) { + fake("left from parent"); + goto balance_left_s; + } else { + fake("right from parent"); + p = s; + p->right = r; + goto balance_right; + } + } + p->balance = b; + free_tree = r; + return; + } else { /* r->balance == -1 */ + /* RL-Rotation */ + balance_t b2; + + fake("RL-Rotation."); + t = r->left; + b = t->balance; + if (p->right = s = t->left) { + s->parent = p; + } + if (r->left = s = t->right) { + s->parent = r; + } + t->right = r; + t->left = p; + r->parent = t; + s = p->parent; + p->parent = t; +#ifdef NO_BARREL_SHIFT + b = -b; + b2 = b >> 1; + p->balance = b2; + b -= b2; + r->balance = b; +#else + b2 = (unsigned char) b >> 7; + r->balance = b2; + b2 = -b2 - b; + p->balance = b2; +#endif + t->balance = 0; + if (t->parent = s) { + if (p == s->left) { + p = s; + s->left = t; + goto balance_left; + } else { + s->right = t; + p = s; + goto balance_right; + } + } + free_tree = t; + return; + } + } else { /* p->balance == 0 */ + p->balance++; + return; + } + } +} + +static void add_to_free_list (u * ptr) +{ + u size; + free_block_t *p, *q, *r; + + /* + * When there is a distinction between data and address registers and/or + * accesses, gcc will choose data type for q, so an assignmnt to q will + * faciliate branching + */ + + fake((do_check_avl(), "add_to_free_list called")); + size = *ptr & MASK; +#ifdef DEBUG_AVL + printf("size:%d\n", size); +#endif + q = (free_block_t *) size; /* this assignment is a hint for + * register choice */ + r = (free_block_t *) (ptr + 1); + count_up(large_free_stat, size << 2); + q = free_tree; + for (;; /* p = q */ ) { + p = (free_block_t *) q; +#ifdef DEBUG_AVL + printf("checked node size %d\n", p->size); +#endif + if (size < p->size) { + if (q = p->left) { + continue; + } + fake("add left"); + p->left = r; + break; + } else { /* >= */ + if (q = p->right) { + continue; + } + fake("add right"); + p->right = r; + break; + } + } + r->size = size; + r->parent = p; + r->left = 0; + r->right = 0; + r->balance = 0; +#ifdef DEBUG_AVL + fake("built new leaf."); + printf("p->balance:%d\n", p->balance); +#endif + do { + free_block_t *s; + + if (r == p->left) { + balance_t b; + + if (!(b = p->balance)) { +#ifdef DEBUG_AVL + printf("p->size: %d\n", p->size); + printf("p->balance: %d\n", p->balance); + printf("p->right-h: %d\n", check_avl(p, p->right)); + printf("p->left -h: %d\n", check_avl(p, p->left)); + fake("growth propagation from left side"); +#endif + p->balance = -1; + } else if (b < 0) { +#ifdef DEBUG_AVL + printf("p->balance:%d\n", p->balance); +#endif + if (r->balance < 0) { + /* R-Rotation */ + fake("R-Rotation"); + if (p->left = s = r->right) { + s->parent = p; + } + r->right = p; + p->balance = 0; + r->balance = 0; + s = p->parent; + p->parent = r; + if (r->parent = s) { + if (s->left == p) { + s->left = r; + } else { + s->right = r; + } + } else { + free_tree = r; + } + } else { /* r->balance == +1 */ + /* LR-Rotation */ + balance_t b2; + free_block_t *t = r->right; + +#ifdef DEBUG_AVL + fake("LR-Rotation"); + printf("t = %x\n", t); + printf("r->balance:%d\n", r->balance); +#endif + if (p->left = s = t->right) { + s->parent = p; + } + fake("relocated right subtree"); + t->right = p; + if (r->right = s = t->left) { + s->parent = r; + } + fake("relocated left subtree"); + t->left = r; + b = t->balance; +#ifdef NO_BARREL_SHIFT + b = -b; + b2 = b >> 1; + r->balance = b2; + b -= b2; + p->balance = b; +#else + b2 = (unsigned char) b >> 7; + p->balance = b2; + b2 = -b2 - b; + r->balance = b2; +#endif + t->balance = 0; + fake("balances calculated"); + s = p->parent; + p->parent = t; + r->parent = t; + if (t->parent = s) { + if (s->left == p) { + s->left = t; + } else { + s->right = t; + } + } else { + free_tree = t; + } +#ifdef DEBUG_AVL + printf("p->balance:%d\n", p->balance); + printf("r->balance:%d\n", r->balance); + printf("t->balance:%d\n", t->balance); + fake((do_check_avl(), "LR-Rotation completed.")); +#endif + } + break; + } else { /* p->balance == +1 */ + p->balance = 0; + fake("growth of left side balanced the node"); + break; + } + } else { /* r == p->right */ + balance_t b; + + if (!(b = p->balance)) { + fake("growth propagation from right side"); + p->balance++; + } else if (b > 0) { + if (r->balance > 0) { + /* L-Rotation */ + fake("L-Rotation"); + if (p->right = s = r->left) { + s->parent = p; + } + r->left = p; + p->balance = 0; + r->balance = 0; + s = p->parent; + p->parent = r; + if (r->parent = s) { + if (s->left == p) { + s->left = r; + } else { + s->right = r; + } + } else { + free_tree = r; + } + } else { /* r->balance == -1 */ + /* RL-Rotation */ + balance_t b2; + free_block_t *t = r->left; + +#ifdef DEBUG_AVL + fake("RL-Rotation"); + printf("t = %x\n", t); + printf("r->balance:%d\n", r->balance); +#endif + if (p->right = s = t->left) { + s->parent = p; + } + fake("relocated left subtree"); + t->left = p; + if (r->left = s = t->right) { + s->parent = r; + } + fake("relocated right subtree"); + t->right = r; + b = t->balance; +#ifdef NO_BARREL_SHIFT + b = -b; + b2 = b >> 1; + p->balance = b2; + b -= b2; + r->balance = b; +#else + b2 = (unsigned char) b >> 7; + r->balance = b2; + b2 = -b2 - b; + p->balance = b2; +#endif + t->balance = 0; + s = p->parent; + p->parent = t; + r->parent = t; + if (t->parent = s) { + if (s->left == p) { + s->left = t; + } else { + s->right = t; + } + } else { + free_tree = t; + } + fake("RL-Rotation completed."); + } + break; + } else { /* p->balance == -1 */ +#ifdef DEBUG_AVL + printf("p->balance: %d\n", p->balance); + printf("p->right-h: %d\n", check_avl(p, p->right)); + printf("p->left -h: %d\n", check_avl(p, p->left)); +#endif + p->balance = 0; + fake("growth of right side balanced the node"); + break; + } + } + r = p; + p = p->parent; + } while (q = p); + fake((do_check_avl(), "add_to_free_list successful")); +} + +#else /* FIT_STYLE_FAST_FIT */ + +void show_free_list() +{ + u *p; + + p = free_list; + while (p) { + show_block(p); + p = l_next_ptr(p); + } + printf("\n"); +} + +t_stat large_free_stat; +void remove_from_free_list (u * ptr) +{ + count_back(large_free_stat, (*ptr & MASK) << 2); + + if (l_prev_ptr(ptr)) + l_next_ptr(l_prev_ptr(ptr)) = l_next_ptr(ptr); + else + free_list = l_next_ptr(ptr); + + if (l_next_ptr(ptr)) + l_prev_ptr(l_next_ptr(ptr)) = l_prev_ptr(ptr); +} + +void add_to_free_list (u * ptr) +{ + extern int puts(); + + count_up(large_free_stat, (*ptr & MASK) << 2); + +#ifdef DEBUG + if (free_list && l_prev_ptr(free_list)) + puts("Free list consistency error."); +#endif + + l_next_ptr(ptr) = free_list; + if (free_list) + l_prev_ptr(free_list) = ptr; + l_prev_ptr(ptr) = 0; + free_list = ptr; +} +#endif /* FIT_STYLE_FAST_FIT */ + +static void build_block ( /* build a properly annotated unalloc block */ + u * ptr, u size) +{ + u tmp; + + tmp = (*ptr & PREV_BLOCK) | size; + *(ptr + size - 1) = size; + *(ptr) = tmp; /* mark this block as free */ + *(ptr + size) &= ~PREV_BLOCK; /* unmark previous block */ +} + +static void mark_block ( /* mark this block as allocated */ + u * ptr) +{ + *l_next_block(ptr) |= PREV_BLOCK; + *ptr |= THIS_BLOCK; +} + +/* + * It is system dependent how sbrk() aligns data, so we simpy use brk() + * to insure that we have enough. + */ +t_stat sbrk_stat; +static char *esbrk (u size) +{ +#ifdef SBRK_OK +#ifdef NeXT + + void *addr = NULL; + static void *current_break = NULL; + static int anywhere = FALSE; + kern_return_t ret; + + /* + * try to extend current break + */ + addr = current_break; + ret = vm_allocate(task_self(), (vm_address_t *) & addr, size, anywhere); + if (ret != KERN_SUCCESS && (anywhere == FALSE)) { + /* + * allocate anywhere + */ + anywhere = TRUE; + ret = vm_allocate(task_self(), (vm_address_t *) & addr, size, TRUE); + if (ret != KERN_SUCCESS) + return (NULL); + } + count_up(sbrk_stat, size); + current_break = (void *) ((char *) addr + size); + return (addr); + +#else + +#ifndef linux + extern char *sbrkx(); +#endif /* linux */ + + static char *current_break = 0; + + if (current_break == 0) + current_break = (char *)sbrkx(0); + if (brk(current_break + size) == -1) + return 0; + + count_up(sbrk_stat, size); + current_break += size; + return current_break - size; + +#endif /* NeXT */ +#else /* not SBRK_OK */ + + count_up(sbrk_stat, size); + return (char *)malloc(size); + +#endif /* SBRK_OK */ +} + +t_stat large_alloc_stat; +static char *large_malloc (u size, int force_more) +{ + u real_size; + u *ptr; + + fake("large_malloc called"); +#ifdef LARGE_TRACE + printf("request:%d.", size); +#endif + size = (size + 7) >> 2; /* plus overhead */ + count_up(large_alloc_stat, size << 2); + + retry: + ptr = 0; + if (!force_more) { +#ifdef FIT_STYLE_FAST_FIT + + free_block_t *p, *q, *r; + u minsplit; + u tempsize; + + ptr++; + minsplit = size + SMALL_BLOCK_MAX + 1; + q = free_tree; + for (;;) { + p = q; +#ifdef DEBUG_AVL + printf("checked node size %d\n", p->size); +#endif + tempsize = p->size; + if (minsplit < tempsize) { + ptr = (u *) p; /* remember this fit */ + if (q = p->left) { + continue; + } + /* We don't need that much, but that's the best fit we have */ + break; + } else if (size > tempsize) { + if (q = p->right) { + continue; + } + break; + } else { /* size <= tempsize <= minsplit */ + if (size == tempsize) { + ptr = (u *) p; + break; + } + /* size < tempsize */ + if (q = p->left) { + r = p; + /* + * if r is used in the following loop instead of p, gcc + * will handle q very inefficient throughout the function + * large_malloc() + */ + for (;;) { + p = q; + tempsize = p->size; + if (size < tempsize) { + if (q = p->left) { + continue; + } + break; + } else if (size > tempsize) { + if (q = p->right) { + continue; + } + break; + } else { + ptr = (u *) p; + goto found_fit; + } + } + p = r; + } + tempsize = p->size; + if (minsplit > tempsize) { + if (q = p->right) { + for (;;) { + p = q; + tempsize = p->size; + if (minsplit <= tempsize) { + ptr = (u *) p; /* remember this fit */ + if (q = p->left) { + continue; + } + break; + } else { /* minsplit > tempsize */ + if (q = p->right) { + continue; + } + break; + } + } /* end inner for */ + break; + } + break; /* no new fit */ + } + /* minsplit == tempsize ==> best non-exact fit */ + ptr = (u *) p; + break; + } + } /* end outer for */ + found_fit: + ptr--; +#else /* FIT_STYLE */ + u best_size; + u *first, *best; + +#ifdef LARGE_TRACE + u search_length = 0; + +#endif + + first = best = 0; + best_size = MASK; + ptr = free_list; + + while (ptr) { + u tempsize; + +#ifdef LARGE_TRACE + search_length++; +#endif + /* Perfect fit? */ + tempsize = *ptr & MASK; + if (tempsize == size) { + best = first = ptr; + break; + /* always accept perfect fit */ + } + /* does it really even fit at all */ + if (tempsize >= size + SMALL_BLOCK_MAX + 1) { + /* try first fit */ + if (!first) { + first = ptr; + if (fit_style == FIRST_FIT) + break; + /* just use this one! */ + } + /* try best fit */ + tempsize -= size; + if (tempsize > 0 && tempsize <= best_size) { + best = ptr; + best_size = tempsize; + } + } + ptr = l_next_ptr(ptr); + } /* end while */ + +#ifdef LARGE_TRACE + printf("search length %d\n", search_length); +#endif + if (fit_style == BEST_FIT) + ptr = best; + else + ptr = first; + /* FIRST_FIT and HYBRID both leave it in first */ + +#endif /* FIT_STYLE */ + } /* end of if (!force_more) */ + if (!ptr) { /* no match, allocate more memory */ + u chunk_size, block_size; + + block_size = size * SIZEOF_INT; + if (force_more || (block_size > CHUNK_SIZE)) + chunk_size = block_size; + else + chunk_size = CHUNK_SIZE; + +#ifdef SBRK_OK + if (!start_next_block) { + count_up(large_alloc_stat, SIZEOF_INT); + start_next_block = (u *) esbrk(SIZEOF_INT); + if (!start_next_block) + fatal("Couldn't malloc anything"); + *(start_next_block) = PREV_BLOCK; + fake("Allocated little fake block"); + } + ptr = (u *) esbrk(chunk_size); +#else /* not SBRK_OK */ + ptr = (u *) esbrk(chunk_size + SIZEOF_INT); +#endif /* SBRK_OK */ + if (ptr == 0) { + extern char *reserved_area; + extern int slow_shut_down_to_do; + static int going_to_exit = 0; + static char mess1[] = "Temporary out of MEMORY. Freeing reserve.\n"; + static char mess2[] = "Totally out of MEMORY.\n"; + + if (going_to_exit) + exit(3); + if (reserved_area) { + smalloc_free(reserved_area); + reserved_area = 0; + write(1, mess1, sizeof(mess1) - 1); + slow_shut_down_to_do = 6; + force_more = 0; + goto retry; + } + if (force_more) { + force_more = 0; + goto retry; + } + going_to_exit = 1; + write(1, mess2, sizeof(mess2) - 1); + (void) dump_trace(0); + exit(2); + } +#ifdef SBRK_OK + ptr -= 1; /* overlap old memory block */ +#else /* not SBRK_OK */ + if (start_next_block == ptr) { + ptr -= 1; /* overlap old memory block */ + chunk_size += SIZEOF_INT; + } else + *ptr = PREV_BLOCK; + start_next_block = (u *) ((char *) ptr + chunk_size); +#endif /* SBRK_OK */ + block_size = chunk_size / SIZEOF_INT; + + /* configure header info on chunk */ + + build_block(ptr, block_size); + if (force_more) + fake("Build little block"); + else + fake("Built memory block description."); + *l_next_block(ptr) = THIS_BLOCK; + add_to_free_list(ptr); + } /* end of creating a new chunk */ + remove_from_free_list(ptr); + real_size = *ptr & MASK; + + if (real_size - size) { + /* split block pointed to by ptr into two blocks */ + build_block(ptr + size, real_size - size); + fake("Built empty block"); + /* + * When we allocate a new chunk, it might differ very slightly in + * size from the desired size. + */ + if (real_size - size >= SMALL_BLOCK_MAX + 1) { + add_to_free_list(ptr + size); + } else { + mark_block(ptr + size); + } + build_block(ptr, size); + } + mark_block(ptr); + fake("built allocated block"); + return (char *) (ptr + 1); +} + +static void large_free (char * ptr) +{ + u size, *p; + + p = (u *) ptr; + p -= 1; + size = *p & MASK; + count_back(large_alloc_stat, (size << 2)); + + if (!(*(p + size) & THIS_BLOCK)) { + remove_from_free_list(p + size); + size += (*(p + size) & MASK); + *p = (*p & PREV_BLOCK) | size; + } + if (l_prev_free(p)) { + remove_from_free_list(l_prev_block(p)); + size += (*l_prev_block(p) & MASK); + p = l_prev_block(p); + } + build_block(p, size); + + add_to_free_list(p); +} + +POINTER CDECL smalloc_realloc (POINTER p, size_t size) +{ + unsigned *q, old_size; + char *t; + + q = (unsigned *) p; + +#if MALLOC_ALIGN > 4 + while (!(old_size = *--q)); + old_size = ((old_size & MASK) - 1) * SIZEOF_INT; +#else + --q; + old_size = ((*q & MASK) - 1) * SIZEOF_INT; +#endif + if (old_size >= size) + return p; + + t = smalloc_malloc(size); + if (t == 0) + return (char *) 0; + + memcpy(t, p, old_size); + smalloc_free(p); + return t; +} + +static int resort_free_list() +{ + return 0; +} +#ifdef DO_MSTATS +#define dump_stat(str,stat) outbuf_addv(ob, str,stat.counter,stat.size) +void show_mstats (outbuffer_t * ob, char * s) +{ + outbuf_addv(ob, "Memory allocation statistics %s\n", s); + outbuf_add(ob, "Type Count Space (bytes)\n"); + dump_stat("sbrk requests: %8d %10d (a)\n", sbrk_stat); + dump_stat("large blocks: %8d %10d (b)\n", large_alloc_stat); + dump_stat("large free blocks: %8d %10d (c)\n\n", large_free_stat); + dump_stat("small chunks: %8d %10d (d)\n", small_chunk_stat); + dump_stat("small blocks: %8d %10d (e)\n", small_alloc_stat); + dump_stat("small free blocks: %8d %10d (f)\n", small_free_stat); + outbuf_addv(ob, + "unused from current chunk %10d (g)\n\n", unused_size); + outbuf_addv(ob, + " Small blocks are stored in small chunks, which are allocated as\n"); + outbuf_addv(ob, + "large blocks. Therefore, the total large blocks allocated (b) plus\n"); + outbuf_addv(ob, + "the large free blocks (c) should equal total storage from sbrk (a).\n"); + outbuf_addv(ob, + "Similarly, (e) + (f) + (g) equals (d). The total amount of storage\n"); + outbuf_addv(ob, + "wasted is (c) + (f) + (g); the amount allocated is (b) - (f) - (g).\n"); +} +#endif + +/* + * calloc() is provided because some stdio packages uses it. + */ +POINTER CDECL smalloc_calloc (size_t nelem, size_t sizel) +{ + char *p; + + if (nelem == 0 || sizel == 0) + return 0; + p = smalloc_malloc(nelem * sizel); + if (p == 0) + return 0; + (void) memset(p, '\0', nelem * sizel); + return p; +} + +#ifdef DEBUG +/* + * Functions below can be used to debug malloc. + */ + +static void walk_new_small_malloced(void (*func) (POINTER, int)) +{ + int i; + u *p, *q; + + for (i = 0; i < SMALL_BLOCK_MAX; i++) { + for (p = sfltable[i]; p; p = *(u **) (p + 1)) { + *s_size_ptr(p) |= NO_REF; + } + } + if (unused_size) + *next_unused = 0; + for (p = last_small_chunk; p; p = *(u **) p) { + u *end = p - 1 + (p[-1] & MASK); + + debug_message("scanning chunk %x, end %x\n", (u) (p - 1), (u) end); + for (q = p + 1; q < end;) { + u size = *s_size_ptr(q); + + if (!size) + break; + if (!(size & NO_REF)) { + (*func) ((char *) s_next_ptr(q), (size & MASK) << 2); + *s_size_ptr(q) |= NO_REF; + } + q += size & MASK; + } + } + for (i = 0; i < SMALL_BLOCK_MAX; i++) { + for (p = sfltable[i]; p; p = *(u **) (p + 1)) { + *s_size_ptr(p) &= ~NO_REF; + } + } +} +#endif + + diff --git a/fluffos-2.23-ds03/smalloc.h b/fluffos-2.23-ds03/smalloc.h new file mode 100644 index 0000000..8bde639 --- /dev/null +++ b/fluffos-2.23-ds03/smalloc.h @@ -0,0 +1,14 @@ +#ifndef SMALLOC_H +#define SMALLOC_H + +#ifdef SMALLOC +void * CDECL smalloc_malloc (size_t); +void * CDECL smalloc_realloc (void *, size_t); +void * CDECL smalloc_calloc (size_t, size_t); +void CDECL smalloc_free (void *); +#ifdef DO_MSTATS +void show_mstats (outbuffer_t *, char *); +#endif +#endif + +#endif diff --git a/fluffos-2.23-ds03/socket_ctrl.c b/fluffos-2.23-ds03/socket_ctrl.c new file mode 100644 index 0000000..14346e1 --- /dev/null +++ b/fluffos-2.23-ds03/socket_ctrl.c @@ -0,0 +1,163 @@ +#include "std.h" +#include "socket_ctrl.h" +#include "network_incl.h" +#include "lpc_incl.h" +#include "file_incl.h" +#include "file.h" + +/* + ioctl.c: part of the MudOS release -- Truilkan@TMI + + isolates the code which sets the various socket modes since various + machines seem to need this done in different ways. +*/ + +/* + * set process receiving SIGIO/SIGURG signals to us. + */ + +INLINE int set_socket_owner (int fd, int which) +{ +#if defined(OLD_ULTRIX) || defined(__CYGWIN__) + return fcntl(fd, F_SETOWN, which); +#else +#ifdef WINSOCK + return 1; /* FIXME */ +#else + return ioctl(fd, SIOCSPGRP, &which); +#endif +#endif +} + +/* + * allow receipt of asynchronous I/O signals. + */ + +INLINE int set_socket_async (int fd, int which) +{ +#ifdef OLD_ULTRIX + return fcntl(fd, F_SETFL, FASYNC); +#else + return OS_socket_ioctl(fd, FIOASYNC, &which); +#endif +} + +/* + * set socket non-blocking + */ + +INLINE int set_socket_nonblocking (int fd, int which) +{ +#if !defined(OLD_ULTRIX) && !defined(_SEQUENT_) + int result; +#endif + +#ifdef OLD_ULTRIX + if (which) + return fcntl(fd, F_SETFL, FNDELAY); + else + return fcntl(fd, F_SETFL, FNBLOCK); +#else + +#ifdef _SEQUENT_ + int flags = fcntl(fd, F_GETFL, 0); + + if (flags == -1) + return (-1); + if (which) + flags |= O_NONBLOCK; + else + flags &= ~O_NONBLOCK; + return fcntl(fd, F_SETFL, flags); +#else + result = OS_socket_ioctl(fd, FIONBIO, &which); + if (result == -1) + debug_perror("set_socket_nonblocking: ioctl", 0); +#if 0 + /* boggle ... someone track down an errno for this */ + if (result == -1) { + XXX("Try using cc instead of gcc to correct this error.\n"); + } +#endif + return result; +#endif + +#endif +} + +#ifdef WIN32 +void SocketPerror (char * what, char * file) { + static char *errstrings[] = + { "Operation would block", + "Blocking call in progress", + "WSAEALREADY", + "Invalid socket", + "Missing destination", + "Data is too large", + "Wrong protocol type", + "Unsupported option", + "Unsupported protocol", + "Unsupported socket type", + "Socket can't listen", + "WSAEPFNOSUPPORT", + "Can't use address family", + "Addr is used", + "Addr is not available", + "WSAENETDOWN", + "WSAENETUNREACH", + "WSAENETRESET", + "WSAECONNABORTED", + "WSAECONNRESET", + "No buffer space", + "Already connected", + "Not connected", + "WSAESHUTDOWN", + "WSAETOOMANYREFS", + "Time-out", + "Connection refused", + "WSAELOOP", + "WSAENAMETOOLONG", + "WSAEHOSTDOWN", + "WSAEHOSTUNREACH", + "10066", "10067", "10068", "10069", "10070", "10071", "10072", "10073", "10074", + "10075", "10076", "10077", "10078", "10079", "10080", "10081", "10082", "10083", + "10084", "10085", "10086", "10087", "10088", "10089", "10090", + "WSASYSNOTREADY", + "WSAVERNOTSUPPORTED", + "Winsock not initialised", + "10094", "10095", "10096", "10097", "10098", "10099", "11000", + "WSAHOST_NOT_FOUND", + "WSATRY_AGAIN", + "WSANO_RECOVERY", + "WSANO_DATA" + }; + + static char tmpstring[80]; + char *s = tmpstring; + int sock_errno; + + sock_errno = WSAGetLastError(); + + switch (sock_errno) { + case WSAEINTR: strcpy(tmpstring, "Function interrupted"); + case WSAEACCES: strcpy(tmpstring, "Cannot broadcast"); + case WSAEFAULT: strcpy(tmpstring, "Buffer is invalid"); + case WSAEINVAL: strcpy(tmpstring, "Unbound socket"); + case WSAEMFILE: strcpy(tmpstring, "No more descriptors"); + + default: + if ( (sock_errno >= WSAEWOULDBLOCK) && (sock_errno <= WSANO_DATA)) { + s = errstrings[sock_errno - WSAEWOULDBLOCK]; + } else + strcpy(tmpstring, "unknown error"); + } + if (file) + debug_message("System Error: %s:%s:%s\n", what, file, s); + else + debug_message("System Error: %s:%s\n", what, s); +} + +void CDECL cleanup_sockets(void) { + WSACleanup(); +} +#endif diff --git a/fluffos-2.23-ds03/socket_ctrl.h b/fluffos-2.23-ds03/socket_ctrl.h new file mode 100644 index 0000000..e3d3ec7 --- /dev/null +++ b/fluffos-2.23-ds03/socket_ctrl.h @@ -0,0 +1,16 @@ +#ifndef SOCKET_CTRL_H +#define SOCKET_CTRL_H + +/* + * socket_ctrl.c + */ +int set_socket_nonblocking (int, int); +int set_socket_owner (int, int); +int set_socket_async (int, int); + +#ifdef WIN32 +void SocketPerror (char *, char *); +void CDECL cleanup_sockets (void); +#endif + +#endif diff --git a/fluffos-2.23-ds03/socket_efuns.c b/fluffos-2.23-ds03/socket_efuns.c new file mode 100644 index 0000000..98e9d90 --- /dev/null +++ b/fluffos-2.23-ds03/socket_efuns.c @@ -0,0 +1,1470 @@ + +/* + * socket_efun.c -- socket efuns for MudOS. + * 5-92 : Dwayne Fontenot (Jacques@TMI) : original coding. + * 10-92 : Dave Richards (Cynosure) : less original coding. + */ + +#include "std.h" +#include "socket_efuns.h" +#include "socket_err.h" +#include "include/socket_err.h" +#include "socket_ctrl.h" +#include "comm.h" +#include "file.h" +#include "master.h" + +#if defined(PACKAGE_SOCKETS) || defined(PACKAGE_EXTERNAL) + +/* flags for socket_close */ +#define SC_FORCE 1 +#define SC_DO_CALLBACK 2 +#define SC_FINAL_CLOSE 4 + +lpc_socket_t *lpc_socks = 0; +int max_lpc_socks = 0; + +#ifdef PACKAGE_SOCKETS +#ifdef IPV6 +static int socket_name_to_sin (const char *, struct sockaddr_in6 *); +static char *inet_address (struct sockaddr_in6 *); +#else +static int socket_name_to_sin (const char *, struct sockaddr_in *); +static char *inet_address (struct sockaddr_in *); +#endif +#endif + +/* + * check permission + */ +int check_valid_socket (const char * const what, int fd, object_t * owner, + const char * const addr, int port) +{ + array_t *info; + svalue_t *mret; + + info = allocate_empty_array(4); + info->item[0].type = T_NUMBER; + info->item[0].u.number = fd; + assign_socket_owner(&info->item[1], owner); + info->item[2].type = T_STRING; + info->item[2].subtype = STRING_SHARED; + info->item[2].u.string = make_shared_string(addr); + info->item[3].type = T_NUMBER; + info->item[3].u.number = port; + + push_object(current_object); + push_constant_string(what); + push_refed_array(info); + + mret = apply_master_ob(APPLY_VALID_SOCKET, 3); + return MASTER_APPROVED(mret); +} + +static void clear_socket (int which, int dofree) +{ + if (dofree) { + set_read_callback(which, 0); + set_write_callback(which, 0); + set_close_callback(which, 0); + } + + lpc_socks[which].fd = -1; + lpc_socks[which].flags = 0; + lpc_socks[which].mode = MUD; + lpc_socks[which].state = STATE_CLOSED; + memset((char *) &lpc_socks[which].l_addr, 0, sizeof(lpc_socks[which].l_addr)); + memset((char *) &lpc_socks[which].r_addr, 0, sizeof(lpc_socks[which].r_addr)); + lpc_socks[which].owner_ob = NULL; + lpc_socks[which].release_ob = NULL; + lpc_socks[which].read_callback.s = 0; + lpc_socks[which].write_callback.s = 0; + lpc_socks[which].close_callback.s = 0; + lpc_socks[which].r_buf = NULL; + lpc_socks[which].r_off = 0; + lpc_socks[which].r_len = 0; + lpc_socks[which].w_buf = NULL; + lpc_socks[which].w_off = 0; + lpc_socks[which].w_len = 0; +} + +/* + * Get more LPC sockets structures if we run out + */ +static int more_lpc_sockets() +{ + int i; + + max_lpc_socks += 10; + + if (!lpc_socks) + lpc_socks = CALLOCATE(10, lpc_socket_t, TAG_SOCKETS, "more_lpc_sockets"); + else + lpc_socks = RESIZE(lpc_socks, max_lpc_socks, lpc_socket_t, TAG_SOCKETS, "more_lpc_sockets"); + + i = max_lpc_socks; + while (--i >= max_lpc_socks - 10) + clear_socket(i, 0); + + return max_lpc_socks - 10; +} + +/* + * Set the callbacks for a socket + */ +void set_read_callback (int which, svalue_t * cb) +{ + char *s; + + if (lpc_socks[which].flags & S_READ_FP) { + free_funp(lpc_socks[which].read_callback.f); + lpc_socks[which].flags &= ~S_READ_FP; + } else if ((s = lpc_socks[which].read_callback.s)) + free_string(s); + + if (cb) { + if (cb->type == T_FUNCTION) { + lpc_socks[which].flags |= S_READ_FP; + lpc_socks[which].read_callback.f = cb->u.fp; + cb->u.fp->hdr.ref++; + } else { + lpc_socks[which].read_callback.s = make_shared_string(cb->u.string); + } + } else + lpc_socks[which].read_callback.s = 0; +} + +void set_write_callback (int which, svalue_t * cb) +{ + char *s; + + if (lpc_socks[which].flags & S_WRITE_FP) { + free_funp(lpc_socks[which].write_callback.f); + lpc_socks[which].flags &= ~S_WRITE_FP; + } else if ((s = lpc_socks[which].write_callback.s)) + free_string(s); + + if (cb) { + if (cb->type == T_FUNCTION) { + lpc_socks[which].flags |= S_WRITE_FP; + lpc_socks[which].write_callback.f = cb->u.fp; + cb->u.fp->hdr.ref++; + } else { + lpc_socks[which].write_callback.s = make_shared_string(cb->u.string); + } + } else + lpc_socks[which].write_callback.s = 0; +} + +void set_close_callback (int which, svalue_t * cb) +{ + char *s; + + if (lpc_socks[which].flags & S_CLOSE_FP) { + free_funp(lpc_socks[which].close_callback.f); + lpc_socks[which].flags &= ~S_CLOSE_FP; + } else if ((s = lpc_socks[which].close_callback.s)) + free_string(s); + + if (cb) { + if (cb->type == T_FUNCTION) { + lpc_socks[which].flags |= S_CLOSE_FP; + lpc_socks[which].close_callback.f = cb->u.fp; + cb->u.fp->hdr.ref++; + } else { + lpc_socks[which].close_callback.s = make_shared_string(cb->u.string); + } + } else + lpc_socks[which].close_callback.s = 0; +} + +#ifdef PACKAGE_SOCKETS + +static void copy_close_callback (int to, int from) +{ + char *s; + + if (lpc_socks[to].flags & S_CLOSE_FP) { + free_funp(lpc_socks[to].close_callback.f); + } else if ((s = lpc_socks[to].close_callback.s)) + free_string(s); + + if (lpc_socks[from].flags & S_CLOSE_FP) { + lpc_socks[to].flags |= S_CLOSE_FP; + lpc_socks[to].close_callback.f = lpc_socks[from].close_callback.f; + lpc_socks[to].close_callback.f->hdr.ref++; + } else { + lpc_socks[to].flags &= ~S_CLOSE_FP; + s = lpc_socks[to].close_callback.s = lpc_socks[from].close_callback.s; + if (s) + ref_string(s); + } +} + +#endif + +int find_new_socket (void) +{ + int i; + + for (i = 0; i < max_lpc_socks; i++) { + if (lpc_socks[i].state == STATE_CLOSED) + return i; + } + return more_lpc_sockets(); +} + +#ifdef PACKAGE_SOCKETS + +/* + * Create an LPC efun socket + */ +int socket_create (enum socket_mode mode, svalue_t * read_callback, svalue_t * close_callback) +{ + int type, i, fd, optval; +#ifndef NO_BUFFER_TYPE + int binary = 0; + + if (mode == STREAM_BINARY) { + binary = 1; + mode = STREAM; + } else if (mode == DATAGRAM_BINARY) { + binary = 1; + mode = DATAGRAM; + } +#endif + switch (mode) { + + case MUD: + case STREAM: + type = SOCK_STREAM; + break; + case DATAGRAM: + type = SOCK_DGRAM; + break; + + default: + return EEMODENOTSUPP; + } + i = find_new_socket(); + if (i >= 0) { +#ifdef IPV6 + fd = socket(PF_INET6, type, 0); +#else + fd = socket(PF_INET, type, 0); +#endif + if (fd == INVALID_SOCKET) { + socket_perror("socket_create: socket", 0); + return EESOCKET; + } + optval = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &optval, + sizeof(optval)) == -1) { + socket_perror("socket_create: setsockopt", 0); + OS_socket_close(fd); + return EESETSOCKOPT; + } + if (set_socket_nonblocking(fd, 1) == -1) { + socket_perror("socket_create: set_socket_nonblocking", 0); + OS_socket_close(fd); + return EENONBLOCK; + } +#ifdef FD_CLOEXEC + fcntl(fd, F_SETFD, FD_CLOEXEC); +#endif + lpc_socks[i].fd = fd; + lpc_socks[i].flags = S_HEADER; + + if (type == SOCK_DGRAM) close_callback = 0; + set_read_callback(i, read_callback); + set_write_callback(i, 0); + set_close_callback(i, close_callback); + +#ifndef NO_BUFFER_TYPE + if (binary) { + lpc_socks[i].flags |= S_BINARY; + } +#endif + lpc_socks[i].mode = mode; + lpc_socks[i].state = STATE_UNBOUND; + memset((char *) &lpc_socks[i].l_addr, 0, sizeof(lpc_socks[i].l_addr)); + memset((char *) &lpc_socks[i].r_addr, 0, sizeof(lpc_socks[i].r_addr)); + lpc_socks[i].owner_ob = current_object; + lpc_socks[i].release_ob = NULL; + lpc_socks[i].r_buf = NULL; + lpc_socks[i].r_off = 0; + lpc_socks[i].r_len = 0; + lpc_socks[i].w_buf = NULL; + lpc_socks[i].w_off = 0; + lpc_socks[i].w_len = 0; + + current_object->flags |= O_EFUN_SOCKET; + + debug(sockets, ("socket_create: created socket %d mode %d fd %d\n", + i, mode, fd)); + } + + return i; +} + +/* + * Bind an address to an LPC efun socket + */ +int socket_bind (int fd, int port, const char * addr) +{ + socklen_t len; +#ifdef IPV6 + struct sockaddr_in6 sin; +#else + struct sockaddr_in sin; +#endif + memset(&sin, 0, sizeof(sin)); + if (fd < 0 || fd >= max_lpc_socks) + return EEFDRANGE; + if (lpc_socks[fd].state == STATE_CLOSED || + lpc_socks[fd].state == STATE_FLUSHING) + return EEBADF; + if (lpc_socks[fd].owner_ob != current_object) + return EESECURITY; + if (lpc_socks[fd].state != STATE_UNBOUND) + return EEISBOUND; +#ifdef IPV6 + sin.sin6_family = AF_INET6; +#else + sin.sin_family = AF_INET; +#endif + if (!addr) { + if (MUD_IP[0]) +#ifdef IPV6 + inet_pton(AF_INET6, MUD_IP, &(sin.sin6_addr)); + else + sin.sin6_addr = in6addr_any; + sin.sin6_port = htons((u_short) port); +#else + sin.sin_addr.s_addr = inet_addr(MUD_IP); + else + sin.sin_addr.s_addr = INADDR_ANY; + sin.sin_port = htons((u_short) port); +#endif + } else { + if (!socket_name_to_sin(addr, &sin)) + return EEBADADDR; + } + + if (bind(lpc_socks[fd].fd, (struct sockaddr *) & sin, sizeof(sin)) == -1) { + switch (socket_errno) { + case EADDRINUSE: + return EEADDRINUSE; + default: + socket_perror("socket_bind: bind", 0); + return EEBIND; + } + } + len = sizeof(sin); + if (getsockname(lpc_socks[fd].fd, (struct sockaddr *) & lpc_socks[fd].l_addr, &len) == -1) { + socket_perror("socket_bind: getsockname", 0); + return EEGETSOCKNAME; + } + lpc_socks[fd].state = STATE_BOUND; + +#ifdef IPV6 + char tmp[INET6_ADDRSTRLEN]; + debug(sockets, ("socket_bind: bound socket %d to %s.%d\n", + fd, inet_ntop(AF_INET6, &lpc_socks[fd].l_addr.sin6_addr, &tmp, INET6_ADDRSTRLEN), + ntohs(lpc_socks[fd].l_addr.sin6_port))); + +#else + debug(sockets, ("socket_bind: bound socket %d to %s.%d\n", + fd, inet_ntoa(lpc_socks[fd].l_addr.sin_addr), + ntohs(lpc_socks[fd].l_addr.sin_port))); +#endif + return EESUCCESS; +} + +/* + * Listen for connections on an LPC efun socket + */ +int socket_listen (int fd, svalue_t * callback) +{ + if (fd < 0 || fd >= max_lpc_socks) + return EEFDRANGE; + if (lpc_socks[fd].state == STATE_CLOSED || + lpc_socks[fd].state == STATE_FLUSHING) + return EEBADF; + if (lpc_socks[fd].owner_ob != current_object) + return EESECURITY; + if (lpc_socks[fd].mode == DATAGRAM) + return EEMODENOTSUPP; + if (lpc_socks[fd].state == STATE_UNBOUND) + return EENOADDR; + if (lpc_socks[fd].state != STATE_BOUND) + return EEISCONN; + + if (listen(lpc_socks[fd].fd, 5) == -1) { + socket_perror("socket_listen: listen", 0); + return EELISTEN; + } + lpc_socks[fd].state = STATE_LISTEN; + set_read_callback(fd, callback); + + current_object->flags |= O_EFUN_SOCKET; + + debug(sockets, ("socket_listen: listen on socket %d\n", fd)); + + return EESUCCESS; +} + +/* + * Accept a connection on an LPC efun socket + */ +int socket_accept (int fd, svalue_t * read_callback, svalue_t * write_callback) +{ + int accept_fd, i; + socklen_t len; +#ifdef IPV6 + struct sockaddr_in6 sin; +#else + struct sockaddr_in sin; +#endif + if (fd < 0 || fd >= max_lpc_socks) + return EEFDRANGE; + if (lpc_socks[fd].state == STATE_CLOSED || + lpc_socks[fd].state == STATE_FLUSHING) + return EEBADF; + if (lpc_socks[fd].owner_ob != current_object) + return EESECURITY; + if (lpc_socks[fd].mode == DATAGRAM) + return EEMODENOTSUPP; + if (lpc_socks[fd].state != STATE_LISTEN) + return EENOTLISTN; + + lpc_socks[fd].flags &= ~S_WACCEPT; + + len = sizeof(sin); + accept_fd = accept(lpc_socks[fd].fd, (struct sockaddr *) & sin, &len); + if (accept_fd == -1) { + switch (socket_errno) { +#ifdef EWOULDBLOCK + case EWOULDBLOCK: + return EEWOULDBLOCK; +#endif + case EINTR: + return EEINTR; + default: + socket_perror("socket_accept: accept", 0); + return EEACCEPT; + } + } + + /* + * according to Amylaar, 'accepted' sockets in Linux 0.99p6 don't + * properly inherit the nonblocking property from the listening socket. + * Marius, 19-Jun-2000: this happens on other platforms as well, so just + * do it for everyone + * better reset the close on exec as well then + */ + if (set_socket_nonblocking(accept_fd, 1) == -1) { + socket_perror("socket_accept: set_socket_nonblocking 1", 0); + OS_socket_close(accept_fd); + return EENONBLOCK; + } + +#ifdef FD_CLOEXEC + fcntl(accept_fd, F_SETFD, FD_CLOEXEC); +#endif + + + i = find_new_socket(); + if (i >= 0) { + fd_set wmask; + struct timeval t; + int nb; + + lpc_socks[i].fd = accept_fd; + lpc_socks[i].flags = S_HEADER | + (lpc_socks[fd].flags & S_BINARY); + + FD_ZERO(&wmask); + FD_SET(accept_fd, &wmask); + t.tv_sec = 0; + t.tv_usec = 1; //give the kernel some time to open the socket, but not too much! +#ifndef hpux + nb = select(accept_fd+1, (fd_set *) 0, &wmask, (fd_set *) 0, &t); +#else + nb = select(accept_fd+1, (int *) 0, (int *) &wmask, (int *) 0, &t); +#endif + if (!(FD_ISSET(accept_fd, &wmask))) + lpc_socks[i].flags |= S_BLOCKED; + + lpc_socks[i].mode = lpc_socks[fd].mode; + lpc_socks[i].state = STATE_DATA_XFER; + len = sizeof(sin); + if (getsockname(lpc_socks[i].fd, (struct sockaddr *)&lpc_socks[i].l_addr, &len) == -1) { + lpc_socks[i].l_addr = lpc_socks[fd].l_addr; + } + lpc_socks[i].r_addr = sin; + lpc_socks[i].owner_ob = NULL; + lpc_socks[i].release_ob = NULL; + lpc_socks[i].r_buf = NULL; + lpc_socks[i].r_off = 0; + lpc_socks[i].r_len = 0; + lpc_socks[i].w_buf = NULL; + lpc_socks[i].w_off = 0; + lpc_socks[i].w_len = 0; + + lpc_socks[i].owner_ob = current_object; + set_read_callback(i, read_callback); + set_write_callback(i, write_callback); + copy_close_callback(i, fd); + + current_object->flags |= O_EFUN_SOCKET; + + debug(sockets, ("socket_accept: accept on socket %d\n", fd)); + debug(sockets, ("socket_accept: new socket %d on fd %d\n", i, accept_fd)); + } else + OS_socket_close(accept_fd); + + return i; +} + +/* + * Connect an LPC efun socket + */ +int socket_connect (int fd, const char * name, svalue_t * read_callback, svalue_t * write_callback) +{ + if (fd < 0 || fd >= max_lpc_socks) + return EEFDRANGE; + if (lpc_socks[fd].state == STATE_CLOSED || + lpc_socks[fd].state == STATE_FLUSHING) + return EEBADF; + if (lpc_socks[fd].owner_ob != current_object) + return EESECURITY; + if (lpc_socks[fd].mode == DATAGRAM) + return EEMODENOTSUPP; + switch (lpc_socks[fd].state) { + case STATE_CLOSED: + case STATE_FLUSHING: + case STATE_UNBOUND: + case STATE_BOUND: + break; + case STATE_LISTEN: + return EEISLISTEN; + case STATE_DATA_XFER: + return EEISCONN; + } + + if (!socket_name_to_sin(name, &lpc_socks[fd].r_addr)) + return EEBADADDR; + + set_read_callback(fd, read_callback); + set_write_callback(fd, write_callback); + + current_object->flags |= O_EFUN_SOCKET; + +#ifdef WINSOCK + /* Turn on blocking for connect to ensure correct errors */ + if (set_socket_nonblocking(lpc_socks[fd].fd, 0) == -1) { + socket_perror("socket_connect: set_socket_nonblocking 0", 0); + OS_socket_close(fd); + return EENONBLOCK; + } +#endif + if (connect(lpc_socks[fd].fd, (struct sockaddr *) & lpc_socks[fd].r_addr, +#ifdef IPV6 + sizeof(struct sockaddr_in6)) == -1) { +#else + sizeof(struct sockaddr_in)) == -1) { +#endif + switch (socket_errno) { + case EINTR: + return EEINTR; + case EADDRINUSE: + return EEADDRINUSE; + case EALREADY: + return EEALREADY; + case ECONNREFUSED: + return EECONNREFUSED; + case EINPROGRESS: + break; + default: + socket_perror("socket_connect: connect", 0); + return EECONNECT; + } + } +#ifdef WINSOCK + if (set_socket_nonblocking(lpc_socks[fd].fd, 1) == -1) { + socket_perror("socket_connect: set_socket_nonblocking 1", 0); + OS_socket_close(fd); + return EENONBLOCK; + } +#endif + lpc_socks[fd].state = STATE_DATA_XFER; + lpc_socks[fd].flags |= S_BLOCKED; + + return EESUCCESS; +} + +/* + * Write a message on an LPC efun socket + */ +int socket_write (int fd, svalue_t * message, const char * name) +{ + int len, off; + char *buf, *p; +#ifdef IPV6 + struct sockaddr_in6 sin; +#else + struct sockaddr_in sin; +#endif + if (fd < 0 || fd >= max_lpc_socks) + return EEFDRANGE; + if (lpc_socks[fd].state == STATE_CLOSED || + lpc_socks[fd].state == STATE_FLUSHING) + return EEBADF; + if (lpc_socks[fd].owner_ob != current_object) + return EESECURITY; + if (lpc_socks[fd].mode == DATAGRAM) { + if (name == NULL) + return EENOADDR; + if (!socket_name_to_sin(name, &sin)) + return EEBADADDR; + } else { + if (lpc_socks[fd].state != STATE_DATA_XFER) + return EENOTCONN; + if (name != NULL) + return EEBADADDR; + if (lpc_socks[fd].flags & S_BLOCKED) + return EEALREADY; + } + + switch (lpc_socks[fd].mode) { + + case MUD: + switch (message->type) { + + case T_OBJECT: + return EETYPENOTSUPP; + + default: + save_svalue_depth = 0; + len = svalue_save_size(message); + if (save_svalue_depth > MAX_SAVE_SVALUE_DEPTH) { + return EEBADDATA; + } + buf = (char *) + DMALLOC(len + 5, TAG_TEMPORARY, "socket_write: default"); + if (buf == NULL) + fatal("Out of memory"); + *(INT_32 *) buf = htonl((long) len); + len += 4; + buf[4] = '\0'; + p = buf + 4; + save_svalue(message, &p); + break; + } + break; + + case STREAM: + switch (message->type) { +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + len = message->u.buf->size; + buf = (char *) DMALLOC(len, TAG_TEMPORARY, "socket_write: T_BUFFER"); + if (buf == NULL) + fatal("Out of memory"); + memcpy(buf, message->u.buf->item, len); + break; +#endif + case T_STRING: + len = SVALUE_STRLEN(message); + buf = (char *) DMALLOC(len + 1, TAG_TEMPORARY, "socket_write: T_STRING"); + if (buf == NULL) + fatal("Out of memory"); + strcpy(buf, message->u.string); + break; + case T_ARRAY: + { + int i, limit; + svalue_t *el; + + len = message->u.arr->size * sizeof(int); + buf = (char *) DMALLOC(len + 1, TAG_TEMPORARY, "socket_write: T_ARRAY"); + if (buf == NULL) + fatal("Out of memory"); + el = message->u.arr->item; + limit = len / sizeof(int); + for (i = 0; i < limit; i++) { + switch (el[i].type) { + case T_NUMBER: + memcpy((char *) &buf[i * sizeof(int)], + (char *) &el[i].u.number, sizeof(int)); + break; + case T_REAL: + memcpy((char *) &buf[i * sizeof(int)], (char *) &el[i].u.real, + sizeof(int)); + break; + default: + break; + } + } + break; + } + default: + return EETYPENOTSUPP; + } + break; + + case DATAGRAM: + switch (message->type) { + + case T_STRING: + if ((off = sendto(lpc_socks[fd].fd, (char *)message->u.string, + strlen(message->u.string) + 1, 0, + (struct sockaddr *) & sin, sizeof(sin))) == -1) { + //socket_perror("socket_write: sendto", 0); + return EESENDTO; + } + break; + +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + if ((off = sendto(lpc_socks[fd].fd, (char *)message->u.buf->item, + message->u.buf->size, 0, + (struct sockaddr *) & sin, sizeof(sin))) == -1) { + //socket_perror("socket_write: sendto", 0); + return EESENDTO; + } + break; +#endif + + default: + return EETYPENOTSUPP; + } + +#ifdef F_NETWORK_STATS + if (!(lpc_socks[fd].flags & S_EXTERNAL)) { + inet_out_packets++; + inet_out_volume += off; + inet_socket_out_packets++; + inet_socket_out_volume += off; + } +#endif + return EESUCCESS; + + default: + return EEMODENOTSUPP; + } + + if (!len) { + FREE(buf); + return EESUCCESS; + } + off = OS_socket_write(lpc_socks[fd].fd, buf, len); + if (off <= 0) { + FREE(buf); + +#ifdef EWOULDBLOCK + if (off == -1 && socket_errno == EWOULDBLOCK) + return EEWOULDBLOCK; +#endif + if (off == -1 && socket_errno == EINTR) + return EEINTR; + + //socket_perror("socket_write: send", 0); + lpc_socks[fd].flags |= S_LINKDEAD; + socket_close(fd, SC_FORCE | SC_DO_CALLBACK | SC_FINAL_CLOSE); + return EESEND; + } + +#ifdef F_NETWORK_STATS + if (!(lpc_socks[fd].flags & S_EXTERNAL)) { + inet_out_packets++; + inet_out_volume += off; + inet_socket_out_packets++; + inet_socket_out_volume += off; + } +#endif + + if (off < len) { + lpc_socks[fd].flags |= S_BLOCKED; + lpc_socks[fd].w_buf = buf; + lpc_socks[fd].w_off = off; + lpc_socks[fd].w_len = len - off; + return EECALLBACK; + } + FREE(buf); + + return EESUCCESS; +} + +#endif /* PACKAGE_SOCKETS */ + +static void call_callback (int fd, int what, int num_arg) +{ + union string_or_func callback; + + switch (what) { + case S_READ_FP: callback = lpc_socks[fd].read_callback; break; + case S_WRITE_FP: callback = lpc_socks[fd].write_callback; break; + case S_CLOSE_FP: callback = lpc_socks[fd].close_callback; break; + } + + if (lpc_socks[fd].flags & what) { + safe_call_function_pointer(callback.f, num_arg); + } else if (callback.s) { + if (callback.s[0] == APPLY___INIT_SPECIAL_CHAR) + error("Illegal function name.\n"); + safe_apply(callback.s, lpc_socks[fd].owner_ob, num_arg, ORIGIN_INTERNAL); + } +} + +/* + * Handle LPC efun socket read select events + */ +void socket_read_select_handler (int fd) +{ + int cc = 0; + socklen_t addrlen; + char buf[BUF_SIZE], addr[ADDR_BUF_SIZE]; + svalue_t value; +#ifdef IPV6 + struct sockaddr_in6 sin; +#else + struct sockaddr_in sin; +#endif + debug(sockets, ("read_socket_handler: fd %d state %d\n", + fd, lpc_socks[fd].state)); + + switch (lpc_socks[fd].state) { + + case STATE_CLOSED: + case STATE_FLUSHING: + return; + + case STATE_UNBOUND: + debug_message("socket_read_select_handler: read on unbound socket %i\n", fd); + break; + + case STATE_BOUND: + switch (lpc_socks[fd].mode) { + + case MUD: + case STREAM: + break; + + case DATAGRAM: + debug(sockets, ("read_socket_handler: DATA_XFER DATAGRAM\n")); + addrlen = sizeof(sin); + cc = recvfrom(lpc_socks[fd].fd, buf, sizeof(buf) - 1, 0, + (struct sockaddr *) & sin, &addrlen); + if (cc <= 0) + break; +#ifdef F_NETWORK_STATS + if (!(lpc_socks[fd].flags & S_EXTERNAL)) { + inet_in_packets++; + inet_in_volume += cc; + inet_socket_in_packets++; + inet_socket_in_volume++; + } +#endif + debug(sockets, ("read_socket_handler: read %d bytes\n", cc)); + buf[cc] = '\0'; +#ifdef IPV6 + char tmp[INET6_ADDRSTRLEN]; + sprintf(addr, "%s %d", inet_ntop(AF_INET6, &sin.sin6_addr, tmp, INET6_ADDRSTRLEN), + ntohs(sin.sin6_port)); +#else + sprintf(addr, "%s %d", inet_ntoa(sin.sin_addr), + ntohs(sin.sin_port)); +#endif + push_number(fd); +#ifndef NO_BUFFER_TYPE + if (lpc_socks[fd].flags & S_BINARY) { + buffer_t *b; + + b = allocate_buffer(cc); + if (b) { + memcpy(b->item, buf, cc); + push_refed_buffer(b); + } else { + push_number(0); + } + } else { +#endif + copy_and_push_string(buf); +#ifndef NO_BUFFER_TYPE + } +#endif + copy_and_push_string(addr); + debug(sockets, ("read_socket_handler: apply\n")); + call_callback(fd, S_READ_FP, 3); + return; + case STREAM_BINARY: + case DATAGRAM_BINARY: + ; + } + break; + + case STATE_LISTEN: + debug(sockets, ("read_socket_handler: apply read callback\n")); + lpc_socks[fd].flags |= S_WACCEPT; + push_number(fd); + call_callback(fd, S_READ_FP, 1); + return; + + case STATE_DATA_XFER: + switch (lpc_socks[fd].mode) { + + case DATAGRAM: + break; + + case MUD: + debug(sockets, ("read_socket_handler: DATA_XFER MUD\n")); + if (lpc_socks[fd].flags & S_HEADER) { + cc = OS_socket_read(lpc_socks[fd].fd, (char *) &lpc_socks[fd].r_len + + lpc_socks[fd].r_off, 4 - lpc_socks[fd].r_off); + if (cc <= 0) + break; +#ifdef F_NETWORK_STATS + if (!(lpc_socks[fd].flags & S_EXTERNAL)) { + inet_in_packets++; + inet_in_volume += cc; + inet_socket_in_packets++; + inet_socket_in_volume += cc; + } +#endif + debug(sockets, ("read_socket_handler: read %d bytes\n", cc)); + lpc_socks[fd].r_off += cc; + if (lpc_socks[fd].r_off != 4) + return; + debug(sockets, ("read_socket_handler: read header\n")); + lpc_socks[fd].flags &= ~S_HEADER; + lpc_socks[fd].r_off = 0; + lpc_socks[fd].r_len = ntohl(lpc_socks[fd].r_len); + if (lpc_socks[fd].r_len <= 0 || lpc_socks[fd].r_len > MAX_BYTE_TRANSFER) + break; + lpc_socks[fd].r_buf = (char *) + DMALLOC(lpc_socks[fd].r_len + 1, TAG_TEMPORARY, "socket_read_select_handler"); + if (lpc_socks[fd].r_buf == NULL) + fatal("Out of memory"); + debug(sockets, ("read_socket_handler: svalue len is %lu\n", + lpc_socks[fd].r_len)); + } + if (lpc_socks[fd].r_off < lpc_socks[fd].r_len) { + cc = OS_socket_read(lpc_socks[fd].fd, lpc_socks[fd].r_buf + + lpc_socks[fd].r_off, lpc_socks[fd].r_len - + lpc_socks[fd].r_off); + if (cc <= 0) + break; +#ifdef F_NETWORK_STATS + if (!(lpc_socks[fd].flags & S_EXTERNAL)) { + inet_in_packets++; + inet_in_volume += cc; + inet_socket_in_packets++; + inet_socket_in_volume += cc; + } +#endif + debug(sockets, ("read_socket_handler: read %d bytes\n", cc)); + lpc_socks[fd].r_off += cc; + if (lpc_socks[fd].r_off != lpc_socks[fd].r_len) + return; + debug(sockets, ("read_socket_handler: read svalue\n")); + } + lpc_socks[fd].r_buf[lpc_socks[fd].r_len] = '\0'; + value = const0; + push_number(fd); + if (restore_svalue(lpc_socks[fd].r_buf, &value) == 0) { + STACK_INC; + *sp = value; + } else { + push_undefined(); + } + FREE(lpc_socks[fd].r_buf); + lpc_socks[fd].flags |= S_HEADER; + lpc_socks[fd].r_buf = NULL; + lpc_socks[fd].r_off = 0; + lpc_socks[fd].r_len = 0; + debug(sockets, ("read_socket_handler: apply read callback\n")); + call_callback(fd, S_READ_FP, 2); + return; + + case STREAM: + debug(sockets, ("read_socket_handler: DATA_XFER STREAM\n")); + cc = OS_socket_read(lpc_socks[fd].fd, buf, sizeof(buf) - 1); + if (cc <= 0) + break; +#ifdef F_NETWORK_STATS + if (!(lpc_socks[fd].flags & S_EXTERNAL)) { + inet_in_packets++; + inet_in_volume += cc; + inet_socket_in_packets++; + inet_socket_in_volume += cc; + } +#endif + debug(sockets, ("read_socket_handler: read %d bytes\n", cc)); + buf[cc] = '\0'; + push_number(fd); +#ifndef NO_BUFFER_TYPE + if (lpc_socks[fd].flags & S_BINARY) { + buffer_t *b; + + b = allocate_buffer(cc); + if (b) { + b->ref--; + memcpy(b->item, buf, cc); + push_buffer(b); + } else { + push_number(0); + } + } else { +#endif + copy_and_push_string(buf); +#ifndef NO_BUFFER_TYPE + } +#endif + debug(sockets, ("read_socket_handler: apply read callback\n")); + call_callback(fd, S_READ_FP, 2); + return; + case STREAM_BINARY: + case DATAGRAM_BINARY: + ; + } + break; + } + if (cc == -1) { + switch (socket_errno) { + case ECONNREFUSED: + /* Evidentally, on Linux 1.2.1, ECONNREFUSED gets returned + * if an ICMP_PORT_UNREACHED error happens internally. Why + * they use this error message, I have no idea, but this seems + * to work. + */ + if (lpc_socks[fd].state == STATE_BOUND + && lpc_socks[fd].mode == DATAGRAM) + return; + break; + case EINTR: +#ifdef EWOULDBLOCK + case EWOULDBLOCK: + return; +#endif + default: + break; + } + } + + lpc_socks[fd].flags |= S_LINKDEAD; + socket_close(fd, SC_FORCE | SC_DO_CALLBACK | SC_FINAL_CLOSE); +} + +/* + * Handle LPC efun socket write select events + */ +void socket_write_select_handler (int fd) +{ + int cc; + + debug(sockets, ("write_socket_handler: fd %d state %d\n", + fd, lpc_socks[fd].state)); + + /* if the socket isn't blocked, we've got nothing to send */ + /* if the socket is linkdead, don't send -- could block */ + if (!(lpc_socks[fd].flags & S_BLOCKED) || lpc_socks[fd].flags & S_LINKDEAD) + return; + + if (lpc_socks[fd].w_buf != NULL) { + cc = OS_socket_write(lpc_socks[fd].fd, + lpc_socks[fd].w_buf + lpc_socks[fd].w_off, + lpc_socks[fd].w_len); + if (cc <= -1) { + if (cc == -1 && ( +#ifdef EWOULDBLOCK + errno == EWOULDBLOCK || +#endif + errno == EINTR)) { + return; + } + + lpc_socks[fd].flags |= S_LINKDEAD; + if (lpc_socks[fd].state == STATE_FLUSHING) { + lpc_socks[fd].flags &= ~S_BLOCKED; + socket_close(fd, SC_FORCE | SC_FINAL_CLOSE); + return; + } + socket_close(fd, SC_FORCE | SC_DO_CALLBACK | SC_FINAL_CLOSE); + return; + } +#ifdef F_NETWORK_STATS + if (!(lpc_socks[fd].flags & S_EXTERNAL)) { + inet_out_packets++; + inet_out_volume += cc; + inet_socket_out_packets++; + inet_socket_out_volume += cc; + } +#endif + lpc_socks[fd].w_off += cc; + lpc_socks[fd].w_len -= cc; + if (lpc_socks[fd].w_len != 0) + return; + FREE(lpc_socks[fd].w_buf); + lpc_socks[fd].w_buf = NULL; + lpc_socks[fd].w_off = 0; + } + lpc_socks[fd].flags &= ~S_BLOCKED; + if (lpc_socks[fd].state == STATE_FLUSHING) { + socket_close(fd, SC_FORCE | SC_FINAL_CLOSE); + return; + } + + debug(sockets, ("write_socket_handler: apply write_callback\n")); + + push_number(fd); + call_callback(fd, S_WRITE_FP, 1); +} + +/* + * Close an LPC efun socket + */ +int socket_close (int fd, int flags) +{ + if (fd < 0 || fd >= max_lpc_socks) + return EEFDRANGE; + if (lpc_socks[fd].state == STATE_CLOSED) + return EEBADF; + if (lpc_socks[fd].state == STATE_FLUSHING && !(flags & SC_FINAL_CLOSE)) + return EEBADF; + if (!(flags & SC_FORCE) && lpc_socks[fd].owner_ob != current_object) + return EESECURITY; + + if (flags & SC_DO_CALLBACK) { + debug(sockets, ("read_socket_handler: apply close callback\n")); + push_number(fd); + call_callback(fd, S_CLOSE_FP, 1); + } + + set_read_callback(fd, 0); + set_write_callback(fd, 0); + set_close_callback(fd, 0); + + /* if we're linkdead, we'll never flush, so don't even try :-) */ + if ((lpc_socks[fd].flags & S_BLOCKED) && !(lpc_socks[fd].flags & S_LINKDEAD)) { + /* Can't close now; we still have data to write. Tell the mudlib + * it is closed, but we really finish up later. + */ + lpc_socks[fd].state = STATE_FLUSHING; + return EESUCCESS; + } + + while (OS_socket_close(lpc_socks[fd].fd) == -1 && socket_errno == EINTR) + ; /* empty while */ + if (lpc_socks[fd].r_buf != NULL) + FREE(lpc_socks[fd].r_buf); + if (lpc_socks[fd].w_buf != NULL) + FREE(lpc_socks[fd].w_buf); + clear_socket(fd, 1); + + debug(sockets, ("socket_close: closed fd %d\n", fd)); + return EESUCCESS; +} + +#ifdef PACKAGE_SOCKETS + +/* + * Release an LPC efun socket to another object + */ +int socket_release (int fd, object_t * ob, svalue_t * callback) +{ + if (fd < 0 || fd >= max_lpc_socks) + return EEFDRANGE; + if (lpc_socks[fd].state == STATE_CLOSED || + lpc_socks[fd].state == STATE_FLUSHING) + return EEBADF; + if (lpc_socks[fd].owner_ob != current_object) + return EESECURITY; + if (lpc_socks[fd].flags & S_RELEASE) + return EESOCKRLSD; + + lpc_socks[fd].flags |= S_RELEASE; + lpc_socks[fd].release_ob = ob; + + push_number(fd); + push_object(ob); + + if (callback->type == T_FUNCTION) + safe_call_function_pointer(callback->u.fp, 2); + else + safe_apply(callback->u.string, ob, 2, ORIGIN_INTERNAL); + + if ((lpc_socks[fd].flags & S_RELEASE) == 0) + return EESUCCESS; + + lpc_socks[fd].flags &= ~S_RELEASE; + lpc_socks[fd].release_ob = NULL; + + return EESOCKNOTRLSD; +} + +/* + * Aquire an LPC efun socket from another object + */ +int socket_acquire (int fd, svalue_t * read_callback, svalue_t * write_callback, svalue_t * close_callback) +{ + if (fd < 0 || fd >= max_lpc_socks) + return EEFDRANGE; + if (lpc_socks[fd].state == STATE_CLOSED || + lpc_socks[fd].state == STATE_FLUSHING) + return EEBADF; + if ((lpc_socks[fd].flags & S_RELEASE) == 0) + return EESOCKNOTRLSD; + if (lpc_socks[fd].release_ob != current_object) + return EESECURITY; + + lpc_socks[fd].flags &= ~S_RELEASE; + lpc_socks[fd].owner_ob = current_object; + lpc_socks[fd].release_ob = NULL; + + set_read_callback(fd, read_callback); + set_write_callback(fd, write_callback); + set_close_callback(fd, close_callback); + + return EESUCCESS; +} + +/* + * Return the string representation of a socket error + */ +const char *socket_error (int error) +{ + error = -(error + 1); + if (error < 0 || error >= ERROR_STRINGS - 1) + return "socket_error: invalid error number"; + return error_strings[error]; +} + +/* + * Return the remote address for an LPC efun socket + */ +int get_socket_address (int fd, char * addr, int * port, int local) +{ +#ifdef IPV6 + struct sockaddr_in6 *addr_in; +#else + struct sockaddr_in *addr_in; +#endif + if (fd < 0 || fd >= max_lpc_socks) { + addr[0] = '\0'; + *port = 0; + return EEFDRANGE; + } + addr_in = (local ? &lpc_socks[fd].l_addr : &lpc_socks[fd].r_addr); +#ifdef IPV6 + *port = ntohs(addr_in->sin6_port); + inet_ntop(AF_INET6, &addr_in->sin6_addr, addr, INET6_ADDRSTRLEN); +#else + *port = ntohs(addr_in->sin_port); + strcpy(addr, inet_ntoa(addr_in->sin_addr)); +#endif + return EESUCCESS; +} + +/* + * Return the current socket owner + */ +object_t *get_socket_owner (int fd) +{ + if (fd < 0 || fd >= max_lpc_socks) + return (object_t *) NULL; + if (lpc_socks[fd].state == STATE_CLOSED || + lpc_socks[fd].state == STATE_FLUSHING) + return (object_t *) NULL; + return lpc_socks[fd].owner_ob; +} + +#endif /* PACKAGE_SOCKETS */ + +/* + * Initialize a T_OBJECT svalue + */ +void assign_socket_owner (svalue_t * sv, object_t * ob) +{ + if (ob != NULL) { + sv->type = T_OBJECT; + sv->u.ob = ob; + add_ref(ob, "assign_socket_owner"); + } else + assign_svalue_no_free(sv, &const0u); +} + +#ifdef PACKAGE_SOCKETS + +/* + * Convert a string representation of an address to a sockaddr_in + */ +#ifdef IPV6 +static int socket_name_to_sin (const char * name, struct sockaddr_in6 * sin) +#else +static int socket_name_to_sin (const char * name, struct sockaddr_in * sin) +#endif +{ + int port; + char *cp, addr[ADDR_BUF_SIZE]; + + strncpy(addr, name, ADDR_BUF_SIZE); + addr[ADDR_BUF_SIZE - 1] = '\0'; + + cp = strchr(addr, ' '); + if (cp == NULL) + return 0; + + *cp = '\0'; + port = atoi(cp + 1); + +#ifdef IPV6 + sin->sin6_family = AF_INET6; + struct addrinfo hints, *res; + hints.ai_family = AF_INET6; + hints.ai_socktype = 0; + hints.ai_protocol = 0; +#ifndef AI_V4MAPPED + hints.ai_flags = AI_CANONNAME; +#else + hints.ai_flags = AI_CANONNAME| AI_V4MAPPED; +#endif + + if(getaddrinfo(addr, "1234", &hints, &res)){ + //failed + socket_perror("socket_name_to_sin: getaddrinfo", 0); + return 0; + } + struct sockaddr_in6 tmp; + memcpy(&tmp, res->ai_addr, sizeof(tmp)); + freeaddrinfo(res); + sin->sin6_addr = tmp.sin6_addr; + sin->sin6_port = htons((u_short) port); +#else + sin->sin_family = AF_INET; + sin->sin_port = htons((u_short) port); + sin->sin_addr.s_addr = inet_addr(addr); +#endif + return 1; +} + +#endif /* PACKAGE_SOCKETS */ + +/* + * Close any sockets owned by ob + */ +void close_referencing_sockets (object_t * ob) +{ + int i; + + for (i = 0; i < max_lpc_socks; i++) + if (lpc_socks[i].owner_ob == ob && + lpc_socks[i].state != STATE_CLOSED && + lpc_socks[i].state != STATE_FLUSHING) + socket_close(i, SC_FORCE); +} + +#ifdef PACKAGE_SOCKETS + +/* + * Return the string representation of a sockaddr_in + */ +#ifdef IPV6 +static char *inet_address (struct sockaddr_in6 * sin) +#else +static char *inet_address (struct sockaddr_in * sin) +#endif +{ +#ifdef IPV6 + static char addr[INET6_ADDRSTRLEN], port[7]; + if (!memcmp(&sin->sin6_addr, &in6addr_any, sizeof(in6addr_any))) + strcpy(addr, "*"); + else + inet_ntop(AF_INET6, &sin->sin6_addr, addr, INET6_ADDRSTRLEN); + strcat(addr, "."); + if (ntohs(sin->sin6_port) == 0) + strcpy(port, "*"); + else + sprintf(port, "%d", ntohs(sin->sin6_port)); + strcat(addr, port); +#else + static char addr[32], port[7]; + if (ntohl(sin->sin_addr.s_addr) == INADDR_ANY) + strcpy(addr, "*"); + else + strcpy(addr, inet_ntoa(sin->sin_addr)); + strcat(addr, "."); + if (ntohs(sin->sin_port) == 0) + strcpy(port, "*"); + else + sprintf(port, "%d", ntohs(sin->sin_port)); + strcat(addr, port); +#endif + return (addr); +} + +const char *socket_modes[] = { + "MUD", + "STREAM", + "DATAGRAM", + "STREAM_BINARY", + "DATAGRAM_BINARY" +}; + +const char *socket_states[] = { + "CLOSED", + "CLOSING", + "UNBOUND", + "BOUND", + "LISTEN", + "DATA_XFER" +}; + +/* + * Return an array containing info for a socket + */ +array_t *socket_status (int which) +{ + array_t *ret; + + if (which < 0 || which >= max_lpc_socks) return 0; + + ret = allocate_empty_array(6); + + ret->item[0].type = T_NUMBER; + ret->item[0].subtype = 0; + ret->item[0].u.number = lpc_socks[which].fd; + + ret->item[1].type = T_STRING; + ret->item[1].subtype = STRING_CONSTANT; + ret->item[1].u.string = socket_states[lpc_socks[which].state]; + + ret->item[2].type = T_STRING; + ret->item[2].subtype = STRING_CONSTANT; + ret->item[2].u.string = socket_modes[lpc_socks[which].mode]; + + ret->item[3].type = T_STRING; + ret->item[3].subtype = STRING_MALLOC; + ret->item[3].u.string = string_copy(inet_address(&lpc_socks[which].l_addr), + "socket_status"); + + ret->item[4].type = T_STRING; + ret->item[4].subtype = STRING_MALLOC; + ret->item[4].u.string = string_copy(inet_address(&lpc_socks[which].r_addr), + "socket_status"); + + if (lpc_socks[which].state != STATE_FLUSHING && lpc_socks[which].owner_ob && !(lpc_socks[which].owner_ob->flags & O_DESTRUCTED)) { + ret->item[5].type = T_OBJECT; + ret->item[5].u.ob = lpc_socks[which].owner_ob; + add_ref(lpc_socks[which].owner_ob, "socket_status"); + } else { + ret->item[5] = const0u; + } + + return ret; +} + +#endif /* PACKAGE_SOCKETS */ + +#endif /* SOCKET_EFUNS */ diff --git a/fluffos-2.23-ds03/socket_efuns.h b/fluffos-2.23-ds03/socket_efuns.h new file mode 100644 index 0000000..612b46d --- /dev/null +++ b/fluffos-2.23-ds03/socket_efuns.h @@ -0,0 +1,95 @@ +/* + * socket_efuns.h -- definitions and prototypes for socket_efuns.c + * 5-92 : Dwayne Fontenot : original coding. + * 10-92 : Dave Richards : less original coding. + */ + +#ifndef _SOCKET_EFUNS_H_ +#define _SOCKET_EFUNS_H_ + +#include "lpc_incl.h" +#include "network_incl.h" + +#ifdef MINGW +#include +#endif + +enum socket_mode { + MUD, STREAM, DATAGRAM, STREAM_BINARY, DATAGRAM_BINARY +}; + +enum socket_state { + STATE_CLOSED, STATE_FLUSHING, STATE_UNBOUND, STATE_BOUND, STATE_LISTEN, STATE_DATA_XFER +}; + +#define BUF_SIZE 2048 /* max reliable packet size */ +#ifdef IPV6 +#define ADDR_BUF_SIZE INET6_ADDRSTRLEN +#else +#define ADDR_BUF_SIZE 64 /* max length of address string */ +#endif +typedef struct { + int fd; + short flags; + enum socket_mode mode; + enum socket_state state; +#ifdef IPV6 + struct sockaddr_in6 l_addr; + struct sockaddr_in6 r_addr; +#else + struct sockaddr_in l_addr; + struct sockaddr_in r_addr; +#endif + object_t *owner_ob; + object_t *release_ob; + union string_or_func read_callback; + union string_or_func write_callback; + union string_or_func close_callback; + char *r_buf; + int r_off; + int r_len; + char *w_buf; + int w_off; + int w_len; +} lpc_socket_t; + +extern lpc_socket_t *lpc_socks; +extern int max_lpc_socks; + +#define S_RELEASE 0x001 +#define S_BLOCKED 0x002 +#define S_HEADER 0x004 +#define S_WACCEPT 0x008 +#define S_BINARY 0x010 +#define S_READ_FP 0x020 +#define S_WRITE_FP 0x040 +#define S_CLOSE_FP 0x080 +#define S_EXTERNAL 0x100 +#define S_LINKDEAD 0x200 + +array_t *socket_status (int); +array_t *socket_status_by_fd (int); +int check_valid_socket (const char * const, int, object_t *, const char * const, int); +void socket_read_select_handler (int); +void socket_write_select_handler (int); +void assign_socket_owner (svalue_t *, object_t *); +object_t *get_socket_owner (int); +void dump_socket_status (outbuffer_t *); +void close_referencing_sockets (object_t *); +int get_socket_address (int, char *, int *, int); +int socket_bind (int, int, const char *); +int socket_create (enum socket_mode, svalue_t *, svalue_t *); +int socket_listen (int, svalue_t *); +int socket_accept (int, svalue_t *, svalue_t *); +int socket_connect (int, const char *, svalue_t *, svalue_t *); +int socket_write (int, svalue_t *, const char *); +int socket_close (int, int); +int socket_release (int, object_t *, svalue_t *); +int socket_acquire (int, svalue_t *, svalue_t *, svalue_t *); +const char *socket_error (int); +int find_new_socket (void); +void set_read_callback (int, svalue_t *); +void set_write_callback (int, svalue_t *); +void set_close_callback (int, svalue_t *); + +#endif /* _SOCKET_EFUNS_H_ */ diff --git a/fluffos-2.23-ds03/socket_err.c b/fluffos-2.23-ds03/socket_err.c new file mode 100644 index 0000000..e1dc190 --- /dev/null +++ b/fluffos-2.23-ds03/socket_err.c @@ -0,0 +1,43 @@ +/* + * socket_errors.c -- socket error strings + * 5-92 : Dwayne Fontenot (Jacques@TMI) : original coding. + * 10-92 : Dave Richards (Cynosure) : less original coding. + */ + +#include "include/socket_err.h" + +const char *error_strings[ERROR_STRINGS] = +{ + "Problem creating socket", + "Problem with setsockopt", + "Problem setting non-blocking mode", + "No more available efun sockets", + "Descriptor out of range", + "Socket is closed", + "Security violation attempted", + "Socket is already bound", + "Address already in use", + "Problem with bind", + "Problem with getsockname", + "Socket mode not supported", + "Socket not bound to an address", + "Socket is already connected", + "Problem with listen", + "Socket not listening", + "Operation would block", + "Interrupted system call", + "Problem with accept", + "Socket is listening", + "Problem with address format", + "Operation already in progress", + "Connection refused", + "Problem with connect", + "Socket not connected", + "Object type not supported", + "Problem with sendto", + "Problem with send", + "Wait for callback", + "Socket already released", + "Socket not released", + "Data nested too deeply" +}; diff --git a/fluffos-2.23-ds03/socket_err.h b/fluffos-2.23-ds03/socket_err.h new file mode 100644 index 0000000..ed3ede0 --- /dev/null +++ b/fluffos-2.23-ds03/socket_err.h @@ -0,0 +1,8 @@ +#ifndef SOCKET_ERR_H +#define SOCKET_ERR_H +/* + * socket_err.h + */ +extern const char *error_strings[]; + +#endif diff --git a/fluffos-2.23-ds03/spec.h b/fluffos-2.23-ds03/spec.h new file mode 100644 index 0000000..750841c --- /dev/null +++ b/fluffos-2.23-ds03/spec.h @@ -0,0 +1,5 @@ +/* This is the correct file to include in efun specification files; e.g. + func_spec.c and packages/anything_spec.c */ + +#define _FUNC_SPEC_ +#include "std.h" diff --git a/fluffos-2.23-ds03/sprintf.c b/fluffos-2.23-ds03/sprintf.c new file mode 100644 index 0000000..dc11408 --- /dev/null +++ b/fluffos-2.23-ds03/sprintf.c @@ -0,0 +1,1333 @@ +/* + * sprintf.c v1.05 for LPMud 3.0.52 + * + * An implementation of (s)printf() for LPC, with quite a few + * extensions (note that as no floating point exists, some parameters + * have slightly different meaning or restrictions to "standard" + * (s)printf.) Implemented by Lynscar (Sean A Reith). + * 2/28/93: float support for MudOS added by jacques/blackthorn + * + * This version supports the following as modifiers: + * " " pad positive integers with a space. + * "+" pad positive integers with a plus sign. + * "-" left adjusted within field size. + * NB: 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. + * n 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). + * "."n 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. + * ":"n 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 "\\\\". + * The following are the possible type specifiers. + * "%" 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" the integer arg is printed in decimal. + * "i" as d. + * "f" floating point value. + * "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 (in capitals). + */ + +#include "std.h" +#include "sprintf.h" +#include "efuns_incl.h" +#include "simul_efun.h" +#include "lex.h" +#include "stralloc.h" +#include "master.h" + +#if defined(F_SPRINTF) || defined(F_PRINTF) + +typedef unsigned int format_info; + +/* + * Format of format_info: + * 00000000 0000xxxx : argument type: + * 0000 : type not found yet; + * 0001 : error type not found; + * 0010 : percent sign, null argument; + * 0011 : LPC datatype; + * 0100 : string; + * 1000 : integer; + * 1001 : char; + * 1010 : octal; + * 1011 : hex; + * 1100 : HEX; + * 1101 : float; + * 00000000 00xx0000 : justification: + * 00 : right; + * 01 : centre; + * 10 : left; + * 00000000 xx000000 : positive pad char: + * 00 : none; + * 01 : ' '; + * 10 : '+'; + * 0000000x 00000000 : array mode? + * 000000x0 00000000 : column mode? + * 00000x00 00000000 : table mode? + */ + +#define INFO_T 0xF +#define INFO_T_ERROR 0x1 +#define INFO_T_NULL 0x2 +#define INFO_T_LPC 0x3 +#define INFO_T_STRING 0x4 +#define INFO_T_INT 0x8 +#define INFO_T_CHAR 0x9 +#define INFO_T_OCT 0xA +#define INFO_T_HEX 0xB +#define INFO_T_C_HEX 0xC +#define INFO_T_FLOAT 0xD + +#define INFO_J 0x30 +#define INFO_J_CENTRE 0x10 +#define INFO_J_LEFT 0x20 + +#define INFO_PP 0xC0 +#define INFO_PP_SPACE 0x40 +#define INFO_PP_PLUS 0x80 + +#define INFO_ARRAY 0x100 +#define INFO_COLS 0x200 +#define INFO_TABLE 0x400 + +#define ERR_BUFF_OVERFLOW 0x1 /* buffer overflowed */ +#define ERR_TOO_FEW_ARGS 0x2 /* more arguments spec'ed than passed */ +#define ERR_INVALID_STAR 0x3 /* invalid arg to * */ +#define ERR_PRES_EXPECTED 0x4 /* expected precision not found */ +#define ERR_INVALID_FORMAT_STR 0x5 /* error in format string */ +#define ERR_INCORRECT_ARG_S 0x6 /* invalid arg to %s */ +#define ERR_CST_REQUIRES_FS 0x7 /* field size not given for c/t */ +#define ERR_BAD_INT_TYPE 0x8 /* bad integer type... */ +#define ERR_UNDEFINED_TYPE 0x9 /* undefined type found */ +#define ERR_QUOTE_EXPECTED 0xA /* expected ' not found */ +#define ERR_UNEXPECTED_EOS 0xB /* fs terminated unexpectedly */ +#define ERR_NULL_PS 0xC /* pad string is null */ +#define ERR_ARRAY_EXPECTED 0xD /* Yep! You guessed it. */ +#define ERR_RECOVERY_ONLY 0xE /* err msg already done...just + * recover */ + +#define ADD_CHAR(x) {\ + if (sprintf_state->obuff.real_size == MAX_STRING_LENGTH) ERROR(ERR_BUFF_OVERFLOW); \ + outbuf_addchar(&(sprintf_state->obuff), x);\ +} + +#define GET_NEXT_ARG {\ + if (++sprintf_state->cur_arg >= argc) ERROR(ERR_TOO_FEW_ARGS); \ + carg = (argv + sprintf_state->cur_arg);\ +} + +typedef struct { + const char *what; + int len; +} pad_info_t; + +typedef struct { + const char *start; + const char *cur; +} tab_data_t; + +/* slash here means 'or' */ +typedef struct ColumnSlashTable { + union CSTData { + const char *col; /* column data */ + tab_data_t *tab; /* table data */ + } d; /* d == data */ + unsigned short int nocols; /* number of columns in table *sigh* */ + pad_info_t *pad; + unsigned int start; /* starting cursor position */ + unsigned int size; /* column/table width */ + unsigned int remainder; /* extra space needed to fill out to width */ + int pres; /* precision */ + format_info info; /* formatting data */ + struct ColumnSlashTable *next; +} cst; /* Columns Slash Tables */ + +typedef struct _sprintf_state { + outbuffer_t obuff; + cst *csts; + SIGNED int cur_arg; + svalue_t clean; + struct _sprintf_state *next; +} sprintf_state_t; + +static sprintf_state_t *sprintf_state = NULL; + +static void numadd (outbuffer_t *, long num); +static void add_space (outbuffer_t *, int indent); +static void add_justified (const char *str, int slen, pad_info_t *pad, int fs, format_info finfo, short int trailing); +static int add_column (cst ** column, int trailing); +static int add_table (cst ** table); + +#define ERROR(x) sprintf_error(x, 0) + +static void pop_sprintf_state (void) { + sprintf_state_t *state; + + state = sprintf_state; + sprintf_state = sprintf_state->next; + + if (state->obuff.buffer) { + FREE_MSTR(state->obuff.buffer); + } + while (state->csts) { + cst *next = state->csts->next; + if (!(state->csts->info & INFO_COLS) && state->csts->d.tab) { + FREE(state->csts->d.tab); + } + FREE(state->csts); + state->csts = next; + } + if (state->clean.type != T_NUMBER) { + free_svalue(&(state->clean), "pop_sprintf_state"); + } + + FREE(state); +} + +static void push_sprintf_state (void) { + sprintf_state_t *state; + + state = ALLOCATE(sprintf_state_t, TAG_TEMPORARY, "push_sprintf_state"); + outbuf_zero(&(state->obuff)); + state->csts = NULL; + state->cur_arg = -1; + state->clean.type = T_NUMBER; + state->clean.u.number = 0; + state->next = sprintf_state; + sprintf_state = state; +} + +/* Signal an error. Note that we call error, so this routine never returns. + * Anything that has been allocated should be somewhere it can be found and + * freed later. + */ +static void sprintf_error (int which, char * premade) { + char lbuf[2048]; + const char *err; + + switch (which) { + case ERR_BUFF_OVERFLOW: + err = "BUFF_SIZE overflowed..."; + break; + case ERR_TOO_FEW_ARGS: + err = "More arguments specified than passed."; + break; + case ERR_INVALID_STAR: + err = "Incorrect argument type to *."; + break; + case ERR_PRES_EXPECTED: + err = "Expected precision not found."; + break; + case ERR_INVALID_FORMAT_STR: + err = "Error in format string."; + break; + case ERR_INCORRECT_ARG_S: + err = "Incorrect argument to type %%s."; + break; + case ERR_CST_REQUIRES_FS: + err = "Column/table mode requires a field size."; + break; + case ERR_BAD_INT_TYPE: + err = "!feature - bad integer type!"; + break; + case ERR_UNDEFINED_TYPE: + err = "!feature - undefined type!"; + break; + case ERR_QUOTE_EXPECTED: + err = "Quote expected in format string."; + break; + case ERR_UNEXPECTED_EOS: + err = "Unexpected end of format string."; + break; + case ERR_NULL_PS: + err = "Null pad string specified."; + break; + case ERR_ARRAY_EXPECTED: + err = "Array expected."; + break; + case ERR_RECOVERY_ONLY: + err = premade; + break; + default: + err = "undefined error in (s)printf!\n"; + break; + } + sprintf(lbuf, "(s)printf(): %s (arg: %d)\n", err, sprintf_state->cur_arg); + error(lbuf); +} + +static void numadd (outbuffer_t * outbuf, long num) +{ + long i, num_l, /* length of num as a string */ + nve; /* true if num negative */ + int space; + int chop; + char *p; + + if (num < 0) { + /* Beek: yes, it's possible for num < 0, and num * -1 < 0. */ + /* Beek: This shouldn't be a hardcoded const (assumes int is 4 bytes)*/ + /* Wodan: indeed! */ +#if SIZEOF_LONG==4 + num = (num * -1) & 0x7fffffff; +#else + num = (num * -1) & 0x7fffffffffffffff; +#endif + nve = 1; + } else + nve = 0; + for (i = num / 10, num_l = nve + 1; i; i /= 10, num_l++); + if ((space = outbuf_extend(outbuf, num_l))) { + chop = num_l - space; + while (chop--) + num /= 10; /* lose that last digits that got chopped */ + p = outbuf->buffer + outbuf->real_size; + outbuf->real_size += space; + p[space] = 0; + if (nve) { + *p++ = '-'; + space--; + } + while (space--) { + p[space] = (num % 10) + '0'; + num /= 10; + } + } +} /* end of numadd() */ + +static void add_space (outbuffer_t * outbuf, int indent) +{ + int l; + + if ((l = outbuf_extend(outbuf, indent))) { + memset(outbuf->buffer + outbuf->real_size, ' ', l); + *(outbuf->buffer + outbuf->real_size + l) = 0; + outbuf->real_size += l; + } +} + +/* + * Converts any LPC datatype into an arbitrary string format + * and returns a pointer to this string. + * Scary number of parameters for a recursive function. + */ +void svalue_to_string (svalue_t * obj, outbuffer_t * outbuf, int indent, int trailing, int indent2) +{ + int i; + + /* prevent an infinite recursion on self-referential structures */ + if (indent > 20) { + outbuf_add(outbuf, "..."); + return; + } + if (!indent2) + add_space(outbuf, indent); + switch ((obj->type & ~T_FREED)) { + case T_INVALID: + outbuf_add(outbuf, "T_INVALID"); + break; + case T_LVALUE: + outbuf_add(outbuf, "lvalue: "); + svalue_to_string(obj->u.lvalue, outbuf, indent + 2, trailing, 0); + break; + case T_REF: + if(!obj->u.ref->lvalue) + kill_ref(obj->u.ref); + else { + outbuf_add(outbuf, "ref: "); + svalue_to_string(obj->u.ref->lvalue, outbuf, indent + 2, trailing, 0); + } + break; + case T_NUMBER: + numadd(outbuf, obj->u.number); + break; + case T_REAL: + outbuf_addv(outbuf, "%f", obj->u.real); + break; + case T_STRING: + outbuf_add(outbuf, "\""); + outbuf_add(outbuf, obj->u.string); + outbuf_add(outbuf, "\""); + break; + case T_CLASS: + { + int n = obj->u.arr->size; + outbuf_add(outbuf, "CLASS( "); + numadd(outbuf, n); + outbuf_add(outbuf, n == 1 ? " element\n" : " elements\n"); + for (i = 0; i < (obj->u.arr->size) - 1; i++) + svalue_to_string(&(obj->u.arr->item[i]), outbuf, + indent + 2, 1, 0); + if(obj->u.arr->size) + svalue_to_string(&(obj->u.arr->item[i]), outbuf, + indent + 2, 0, 0); + outbuf_add(outbuf, "\n"); + add_space(outbuf, indent); + outbuf_add(outbuf, " )"); + break; + } + case T_ARRAY: + if (!(obj->u.arr->size)) { + outbuf_add(outbuf, "({ })"); + } else { + outbuf_add(outbuf, "({ /* sizeof() == "); + numadd(outbuf, obj->u.arr->size); + outbuf_add(outbuf, " */\n"); + for (i = 0; i < (obj->u.arr->size) - 1; i++) + svalue_to_string(&(obj->u.arr->item[i]), outbuf, indent + 2, 1, 0); + svalue_to_string(&(obj->u.arr->item[i]), outbuf, indent + 2, 0, 0); + outbuf_add(outbuf, "\n"); + add_space(outbuf, indent); + outbuf_add(outbuf, "})"); + } + break; +#ifndef NO_BUFFER_TYPE + case T_BUFFER: + outbuf_add(outbuf, ""); + break; +#endif + case T_FUNCTION: + { + svalue_t tmp; + object_t *ob; + tmp.type = T_ARRAY; + + outbuf_add(outbuf, "(: "); + switch (obj->u.fp->hdr.type) { + case FP_LOCAL | FP_NOT_BINDABLE: + ob = obj->u.fp->hdr.owner; + if (!ob || ob->flags & O_DESTRUCTED) { + outbuf_add(outbuf, "0"); + break; + } + outbuf_add(outbuf, function_name(ob->prog, + obj->u.fp->f.local.index)); + break; + case FP_SIMUL: + outbuf_add(outbuf, simuls[obj->u.fp->f.simul.index].func->funcname); + break; + case FP_FUNCTIONAL: + case FP_FUNCTIONAL | FP_NOT_BINDABLE: + { + char buf[10]; + int n = obj->u.fp->f.functional.num_arg; + + outbuf_add(outbuf, "("); + for (i=1; i < n; i++) { + sprintf(buf, "$%i, ", i); + outbuf_add(outbuf, buf); + } + if (n) { + sprintf(buf, "$%i", n); + outbuf_add(outbuf, buf); + } + outbuf_add(outbuf, ")"); + break; + } + case FP_EFUN: + { + int i; + i = obj->u.fp->f.efun.index; + outbuf_add(outbuf, query_instr_name(i)); + break; + } + } + if (obj->u.fp->hdr.args) { + for (i=0; iu.fp->hdr.args->size; i++) { + outbuf_add(outbuf, ", "); + svalue_to_string(&(obj->u.fp->hdr.args->item[i]), outbuf, indent, 0, 0); + } + } + } + outbuf_add(outbuf, " :)"); + break; + case T_MAPPING: + if (!(obj->u.map->count)) { + outbuf_add(outbuf, "([ ])"); + } else { + outbuf_add(outbuf, "([ /* sizeof() == "); + numadd(outbuf, obj->u.map->count); + outbuf_add(outbuf, " */\n"); + for (i = 0; i <= obj->u.map->table_size; i++) { + mapping_node_t *elm; + + for (elm = obj->u.map->table[i]; elm; elm = elm->next) { + svalue_to_string(&(elm->values[0]), outbuf, indent + 2, 0, 0); + outbuf_add(outbuf, " : "); + svalue_to_string(&(elm->values[1]), outbuf, indent + 4, 1, 1); + } + } + add_space(outbuf, indent); + outbuf_add(outbuf, "])"); + } + break; + case T_OBJECT: + { + svalue_t *temp; + + if (obj->u.ob->flags & O_DESTRUCTED) { + numadd(outbuf, 0); + break; + } + + outbuf_addchar(outbuf, '/'); + outbuf_add(outbuf, obj->u.ob->obname); + + if (!max_eval_error && !too_deep_error) { + push_object(obj->u.ob); + temp = safe_apply_master_ob(APPLY_OBJECT_NAME, 1); + if (temp && temp != (svalue_t *) -1 && (temp->type == T_STRING)) { + outbuf_add(outbuf, " (\""); + outbuf_add(outbuf, temp->u.string); + outbuf_add(outbuf, "\")"); + } + } + break; + } + default: + outbuf_addv(outbuf, "!ERROR: GARBAGE SVALUE: %x!", obj->type); + } /* end of switch (obj->type) */ + if (trailing) + outbuf_add(outbuf, ",\n"); +} /* end of svalue_to_string() */ + +static void add_pad (pad_info_t * pad, int len) { + char *p; + int padlen; + + if (outbuf_extend(&(sprintf_state->obuff), len) < len) + ERROR(ERR_BUFF_OVERFLOW); + p = sprintf_state->obuff.buffer + sprintf_state->obuff.real_size; + sprintf_state->obuff.real_size += len; + p[len] = 0; + + if (pad && (padlen = pad->len)) { + char *end; + const char *pstr = pad->what; + int i; + char c; + + for (i = 0, end = p + len; p < end; i++) { + if (i == padlen) + i = 0; + + if ((c = pstr[i]) == '\\') { + /* guaranteed to have a valid char next */ + *p++ = pstr[++i]; + } else + *p++ = c; + } + } else + memset(p, ' ', len); +} + +INLINE_STATIC void add_nstr (const char * str, int len) { + if (outbuf_extend(&(sprintf_state->obuff), len) < len) + ERROR(ERR_BUFF_OVERFLOW); + memcpy(sprintf_state->obuff.buffer + sprintf_state->obuff.real_size, str, len); + sprintf_state->obuff.real_size += len; + sprintf_state->obuff.buffer[sprintf_state->obuff.real_size] = 0; +} + +/* + * Adds the string "str" to the buff after justifying it within "fs". + * "trailing" is a flag which is set if trailing justification is to be done. + * "str" is unmodified. trailing is, of course, ignored in the case + * of right justification. + */ +static void add_justified (const char * str, int slen, pad_info_t * pad, + int fs, format_info finfo, short int trailing) +{ +#ifdef USE_ICONV + int skip = 0; + int wide = 0; + const char *p2 = str + slen; + while (p2 > str){ + if((*p2) & 0x80){ + wide = 1; + skip++; + }else{ + if(wide){ + wide = 0; + skip--; + } + } + p2--; + } + if(wide) + skip--; + fs -= (slen - skip); +#else + fs -= slen; +#endif + if (fs <= 0) { + add_nstr(str, slen); + } else { + int i; + switch (finfo & INFO_J) { + case INFO_J_LEFT: + add_nstr(str, slen); + if (trailing) + add_pad(pad, fs); + break; + case INFO_J_CENTRE: + i = fs / 2 + fs % 2; + add_pad(pad, i); + add_nstr(str, slen); + if (trailing) + add_pad(pad, fs - i); + break; + case INFO_J_CENTRE | INFO_J_LEFT: + i = fs / 2; + add_pad(pad, i); + add_nstr(str, slen); + if (trailing) + add_pad(pad, fs - i); + break; + default: + /* std (s)printf defaults to right + * justification */ + add_pad(pad, fs); + add_nstr(str, slen); + } + } +} /* end of add_justified() */ + +/* + * Adds "column" to the buffer. + * Returns 0 is column not finished. + * Returns 1 if column completed. + * Returns 2 if column completed has a \n at the end. + */ +static int add_column (cst ** column, int trailing) +{ + register unsigned int done; + char c; + int space = -1; + int ret; + cst *col = *column; /* always holds (*column) */ + const char *col_d = col->d.col; /* always holds (col->d.col) */ + + done = 0; +#ifdef USE_ICONV + int width = 0; +#endif + /* find a good spot to break the line */ + while ((c = col_d[done]) && c != '\n') { + if (c == ' ') + space = done; +#ifdef USE_ICONV + if(c & 0x80){ + if(!(col_d[done+1] & 0x80) ) + width++; + } else { + width++; + } + done++; + if (width == col->pres) { +#else + if (++done == col->pres) { +#endif + if (space != -1) { + c = col_d[done]; + if (c != '\n' && c != ' ' && c) + done = space; + } + break; + } + } + add_justified(col_d, done, col->pad, + col->size, col->info, trailing || col->next); + col_d += done; + ret = 1; + if (*col_d == '\n') { + col_d++; + ret = 2; + } + col->d.col = col_d; + /* + * if the next character is a NULL then take this column out of + * the list. + */ + if (!(*col_d)) { + cst *temp; + + temp = col->next; + if (col->pad) + FREE(col->pad); + FREE(col); + *column = temp; + return ret; + } + return 0; +} /* end of add_column() */ + +/* + * Adds "table" to the buffer. + * Returns 0 if table not completed. + * Returns 1 if table completed. + */ +static int add_table (cst ** table) +{ + int done, i; + cst *tab = *table; /* always (*table) */ + tab_data_t *tab_d = tab->d.tab; /* always tab->d.tab */ + const char *tab_di; /* always tab->d.tab[i].cur */ + int end; +#ifdef USE_ICONV + int width, tabwidth; +#endif + + for (i = 0; i < tab->nocols && (tab_di = tab_d[i].cur); i++) { + end = tab_d[i + 1].start - tab_di - 1; +#ifdef USE_ICONV + width = 0; +#endif + for (done = 0; done != end && tab_di[done] != '\n'; done++) +#ifdef USE_ICONV + { + if(tab_di[done] & 0x80){ + if(!(tab_di[done+1] & 0x80) ) + width++; + } else + width++; + if(width == tab->size) + tabwidth = done+1; + } + add_justified(tab_di, (width > tab->size ? tabwidth : done), + tab->pad, tab->size, tab->info, + tab->pad || (i < tab->nocols - 1) || tab->next); +#else + ; + add_justified(tab_di, (done > tab->size ? tab->size : done), + tab->pad, tab->size, tab->info, + tab->pad || (i < tab->nocols - 1) || tab->next); +#endif + if (done >= end - 1) { + tab_di = 0; + } else { + tab_di += done + 1; /* inc'ed next line ... */ + } + tab_d[i].cur = tab_di; + } + if (tab->pad) { + while (i++ < tab->nocols) { + add_pad(tab->pad, tab->size); + } + add_pad(tab->pad, tab->remainder); + } + if (!tab_d[0].cur) { + cst *temp; + + temp = tab->next; + if (tab->pad) + FREE(tab->pad); + if (tab_d) + FREE(tab_d); + FREE(tab); + *table = temp; + return 1; + } + return 0; +} /* end of add_table() */ + +static int get_curpos() { + char *p1, *p2; + if (!sprintf_state->obuff.buffer) return 0; + p1 = sprintf_state->obuff.buffer + sprintf_state->obuff.real_size - 1; + p2 = p1; +#ifdef USE_ICONV + int skip = 0; + int wide = 0; + while (p2 > sprintf_state->obuff.buffer && *p2 != '\n'){ + if((*p2) & 0x80){ + wide = 1; + skip++; + }else{ + if(wide){ + wide = 0; + skip--; + } + } + p2--; + } + if(wide) + skip--; + if (*p2 != '\n') + return p1 - p2 + 1 - skip; + else + return p1 - p2 - skip; +#else + while (p2 > sprintf_state->obuff.buffer && *p2 != '\n') + p2--; + + if (*p2 != '\n') + return p1 - p2 + 1; + else + return p1 - p2; +#endif +} + +/* We can't use a pointer to a local in a table or column, since it + * could get overwritten by another on the same line. + */ +static pad_info_t *make_pad (pad_info_t * p) { + pad_info_t *x; + if (p->len == 0) return 0; + x = ALLOCATE(pad_info_t, TAG_TEMPORARY, "make_pad"); + x->what = p->what; + x->len = p->len; + return x; +} + +/* + * THE (s)printf() function. + * It returns a pointer to it's internal buffer (or a string in the text + * segment) thus, the string must be copied if it has to survive after + * this function is called again, or if it's going to be modified (esp. + * if it risks being free()ed). + */ +char *string_print_formatted (const char * format_str, int argc, svalue_t * argv) +{ + format_info finfo; + svalue_t *carg; /* current arg */ + unsigned int nelemno = 0; /* next offset into array */ + unsigned int fpos; /* position in format_str */ + int fs; /* field size */ + int pres; /* precision */ + pad_info_t pad; /* fs pad string */ + unsigned int i; + char *retvalue; + int last; + + push_sprintf_state(); + STACK_INC; + sp->type = T_ERROR_HANDLER; + sp->u.error_handler = pop_sprintf_state; + + last = 0; + for (fpos = 0; 1; fpos++) { + char c = format_str[fpos]; + + if (c == '\n' || !c) { + int column_stat = 0; + + if (last != fpos) { + add_nstr(format_str + last, fpos - last); + last = fpos + 1; + } else last++; + + if (!sprintf_state->csts) { + if (!c) + break; + ADD_CHAR('\n'); + continue; + } + ADD_CHAR('\n'); + while (sprintf_state->csts) { + cst **temp; + + temp = &(sprintf_state->csts); + while (*temp) { + if ((*temp)->info & INFO_COLS) { + if (*((*temp)->d.col - 1) != '\n') + while (*((*temp)->d.col) == ' ') + (*temp)->d.col++; + add_pad(0, (*temp)->start - get_curpos()); + column_stat = add_column(temp, 0); + if (!column_stat) + temp = &((*temp)->next); + } else { + add_pad(0, (*temp)->start - get_curpos()); + if (!add_table(temp)) + temp = &((*temp)->next); + } + } /* of while (*temp) */ + if (sprintf_state->csts || c == '\n') + ADD_CHAR('\n'); + } /* of while (sprintf_state->csts) */ + if (column_stat == 2) + ADD_CHAR('\n'); + if (!c) + break; + } else + if (c == '%') { + if (last != fpos) { + add_nstr(format_str + last, fpos - last); + last = fpos + 1; + } else last++; + if (format_str[fpos + 1] == '%') { + ADD_CHAR('%'); + fpos++; + last++; + continue; + } + GET_NEXT_ARG; + fs = 0; + pres = 0; + pad.len = 0; + finfo = 0; + for (fpos++; !(finfo & INFO_T); fpos++) { + if (!format_str[fpos]) { + finfo |= INFO_T_ERROR; + break; + } + if (((format_str[fpos] >= '0') && (format_str[fpos] <= '9')) + || (format_str[fpos] == '*')) { + if (pres == -1) { /* then looking for pres */ + if (format_str[fpos] == '*') { + if (carg->type != T_NUMBER) + ERROR(ERR_INVALID_STAR); + pres = carg->u.number; + GET_NEXT_ARG; + continue; + } + pres = format_str[fpos] - '0'; + for (fpos++; + (format_str[fpos] >= '0') && (format_str[fpos] <= '9'); fpos++) { + pres = pres * 10 + format_str[fpos] - '0'; + } + if (pres < 0) pres = 0; + } else { /* then is fs (and maybe pres) */ + if ((format_str[fpos] == '0') && (((format_str[fpos + 1] >= '1') + && (format_str[fpos + 1] <= '9')) || (format_str[fpos + 1] == '*'))) { + pad.what = "0"; + pad.len = 1; + } else { + if (format_str[fpos] == '*') { + if (carg->type != T_NUMBER) + ERROR(ERR_INVALID_STAR); + fs = carg->u.number; + if (fs < 0) fs = 0; + if (pres == -2) + pres = fs; /* colon */ + GET_NEXT_ARG; + continue; + } + fs = format_str[fpos] - '0'; + } + for (fpos++; + (format_str[fpos] >= '0') && (format_str[fpos] <= '9'); fpos++) { + fs = fs * 10 + format_str[fpos] - '0'; + } + if (fs < 0) fs = 0; + if (pres == -2) { /* colon */ + pres = fs; + } + } + fpos--; /* about to get incremented */ + continue; + } + switch (format_str[fpos]) { + case ' ': + finfo |= INFO_PP_SPACE; + break; + case '+': + finfo |= INFO_PP_PLUS; + break; + case '-': + finfo |= INFO_J_LEFT; + break; + case '|': + finfo |= INFO_J_CENTRE; + break; + case '@': + finfo |= INFO_ARRAY; + break; + case '=': + finfo |= INFO_COLS; + break; + case '#': + finfo |= INFO_TABLE; + break; + case '.': + pres = -1; + break; + case ':': + pres = -2; + break; +#ifdef DEBUG + case '%': + finfo |= INFO_T_NULL; + break; /* never reached */ +#endif + case 'O': + finfo |= INFO_T_LPC; + break; + case 's': + finfo |= INFO_T_STRING; + break; + case 'd': + case 'i': + finfo |= INFO_T_INT; + break; + case 'f': + finfo |= INFO_T_FLOAT; + break; + case 'c': + finfo |= INFO_T_CHAR; + break; + case 'o': + finfo |= INFO_T_OCT; + break; + case 'x': + finfo |= INFO_T_HEX; + break; + case 'X': + finfo |= INFO_T_C_HEX; + break; + case '\'': + fpos++; + pad.what = format_str + fpos; + while (1) { + if (!format_str[fpos]) + ERROR(ERR_UNEXPECTED_EOS); + if (format_str[fpos] == '\\') { + if (!format_str[++fpos]) + ERROR(ERR_UNEXPECTED_EOS); + } else + if (format_str[fpos] == '\'') { + pad.len = format_str + fpos - pad.what; + if (!pad.len) + ERROR(ERR_NULL_PS); + break; + } + fpos++; + } + break; + default: + finfo |= INFO_T_ERROR; + } + } /* end of for () */ + if (pres < 0) + ERROR(ERR_PRES_EXPECTED); + /* + * now handle the different arg types... + */ + if (finfo & INFO_ARRAY) { + if (carg->type != T_ARRAY) + ERROR(ERR_ARRAY_EXPECTED); + if (carg->u.arr->size == 0) { + last = fpos; + fpos--; /* 'bout to get incremented */ + continue; + } + carg = (argv + sprintf_state->cur_arg)->u.arr->item; + nelemno = 1; /* next element number */ + } + while (1) { + if ((finfo & INFO_T) == INFO_T_LPC) { + outbuffer_t outbuf; + + outbuf_zero(&outbuf); + svalue_to_string(carg, &outbuf, 0, 0, 0); + outbuf_fix(&outbuf); + + sprintf_state->clean.type = T_STRING; + sprintf_state->clean.subtype = STRING_MALLOC; + sprintf_state->clean.u.string = outbuf.buffer; + carg = &(sprintf_state->clean); + finfo ^= INFO_T_LPC; + finfo |= INFO_T_STRING; + } + if ((finfo & INFO_T) == INFO_T_ERROR) { + ERROR(ERR_INVALID_FORMAT_STR); +#ifdef DEBUG + } else if ((finfo & INFO_T) == INFO_T_NULL) { + /* never reached... */ + fprintf(stderr, "/%s: (s)printf: INFO_T_NULL.... found.\n", + current_object->obname); + ADD_CHAR('%'); +#endif + } else if ((finfo & INFO_T) == INFO_T_STRING) { + int slen; + /* + * %s null handling added 930709 by Luke Mewburn + * + */ + if (carg->type == T_NUMBER && carg->u.number == 0) { + sprintf_state->clean.type = T_STRING; + sprintf_state->clean.subtype = STRING_MALLOC; + sprintf_state->clean.u.string = string_copy(NULL_MSG, "sprintf NULL"); + carg = &(sprintf_state->clean); + } else + if (carg->type != T_STRING) { + ERROR(ERR_INCORRECT_ARG_S); + } + slen = SVALUE_STRLEN(carg); + if ((finfo & INFO_COLS) || (finfo & INFO_TABLE)) { + cst **temp; + + if (!fs) { + ERROR(ERR_CST_REQUIRES_FS); + } + + temp = &(sprintf_state->csts); + while (*temp) + temp = &((*temp)->next); + if (finfo & INFO_COLS) { + int tmp; + if (pres > fs) pres = fs; + *temp = ALLOCATE(cst, TAG_TEMPORARY, "string_print: 3"); + (*temp)->next = 0; + (*temp)->d.col = carg->u.string; + (*temp)->pad = make_pad(&pad); + (*temp)->size = fs; + (*temp)->pres = (pres) ? pres : fs; + (*temp)->info = finfo; + (*temp)->start = get_curpos(); +#ifdef TCC + puts("tcc has some bugs"); +#endif + tmp = ((format_str[fpos] != '\n') + && (format_str[fpos] != '\0')) + || ((finfo & INFO_ARRAY) + && (nelemno < (argv + sprintf_state->cur_arg)->u.arr->size)); + tmp = add_column(temp, tmp); + if (tmp == 2 && !format_str[fpos]) { + ADD_CHAR('\n'); + } + } else {/* (finfo & INFO_TABLE) */ + unsigned int n, len, max_len; + const char *p1, *p2; + +#define TABLE carg->u.string + (*temp) = ALLOCATE(cst, TAG_TEMPORARY, "string_print: 4"); + (*temp)->d.tab = 0; + (*temp)->pad = make_pad(&pad); + (*temp)->info = finfo; + (*temp)->start = get_curpos(); + (*temp)->next = 0; + max_len = 0; + n = 1; + + p2 = p1 = TABLE; + while (*p1) { + if (*p1 == '\n') { + if (p1 - p2 > max_len) + max_len = p1 - p2; + p1++; + if (*(p2 = p1)) + n++; + } else + p1++; + } + if (!pres) { + /* the null terminated word */ + if (p1 - p2 > max_len) + max_len = p1 - p2; + pres = fs / (max_len + 2); /* at least two + * separating spaces */ + if (!pres) + pres = 1; + + /* This moves some entries from the right side + * of the table to fill out the last line, + * which makes the table look a bit nicer. + * E.g. + * (n=13,p=6) (l=3,p=5) + * X X X X X X X X X X X + * X X X X X X -> X X X X X + * X X X X X + * + */ + len = (n-1)/pres + 1; + if (n > pres && n % pres) + pres -= (pres - n % pres) / len; + } else { + len = (n-1)/pres + 1; + } + (*temp)->size = fs / pres; + (*temp)->remainder = fs % pres; + if (n < pres) { + /* If we have fewer elements than columns, + * pretend we are dealing with a smaller + * table. + */ + (*temp)->remainder += (pres - n)*((*temp)->size); + pres = n; + } + + (*temp)->d.tab = CALLOCATE(pres + 1, tab_data_t, + TAG_TEMPORARY, "string_print: 5"); + (*temp)->nocols = pres; /* heavy sigh */ + (*temp)->d.tab[0].start = TABLE; + if (pres == 1) { + (*temp)->d.tab[1].start = TABLE + SVALUE_STRLEN(carg) + 1; + } else { + i = 1; /* the next column number */ + n = 0; /* the current "word" number in this + * column */ + + p1 = TABLE; + while (*p1) { + if (*p1++ == '\n' && ++n >= len) { + (*temp)->d.tab[i++].start = p1; + n = 0; + } + } + for ( ; i <= pres; i++) + (*temp)->d.tab[i].start = ++p1; + } + for (i = 0; i < pres; i++) + (*temp)->d.tab[i].cur = (*temp)->d.tab[i].start; + + add_table(temp); + } + } else { /* not column or table */ + const char *tmp = carg->u.string; //work around tcc bug; +#ifdef USE_ICONV + int width = 0; + int i; + if(pres){ + for(i=0; icur_arg)->u.arr->size))) + || (slen && (carg->u.string[slen - 1] != '\n'))); + } + } else if (finfo & INFO_T_INT) { /* one of the integer + * types */ + char cheat[20]; + char temp[100]; + + *cheat = '%'; + i = 1; + switch (finfo & INFO_PP) { + case INFO_PP_SPACE: + cheat[i++] = ' '; + break; + case INFO_PP_PLUS: + cheat[i++] = '+'; + break; + } + if (pres) { + cheat[i++] = '.'; + if(pres >= sizeof(temp)) + sprintf(cheat + i, "%ld", sizeof(temp) - 1); + else + sprintf(cheat + i, "%d", pres); + + i += strlen(cheat + i); + } + switch (finfo & INFO_T) { + case INFO_T_INT: + cheat[i++] = 'l'; + cheat[i++] = 'd'; + break; + case INFO_T_FLOAT: + cheat[i++] = 'f'; + break; + case INFO_T_CHAR: + cheat[i++] = 'c'; + break; + case INFO_T_OCT: + cheat[i++] = 'l'; + cheat[i++] = 'o'; + break; + case INFO_T_HEX: + cheat[i++] = 'l'; + cheat[i++] = 'x'; + break; + case INFO_T_C_HEX: + cheat[i++] = 'l'; + cheat[i++] = 'X'; + break; + default: + ERROR(ERR_BAD_INT_TYPE); + } + if ((cheat[i - 1] == 'f' && carg->type != T_REAL) || (cheat[i - 1] != 'f' && carg->type != T_NUMBER)) { +#ifdef RETURN_ERROR_MESSAGES + sprintf(buff, + "ERROR: (s)printf(): Incorrect argument type to %%%c. (arg: %u)\n", + cheat[i - 1], sprintf_state->cur_arg); + fprintf(stderr, "Program /%s File: %s: %s", current_prog->name, + get_line_number_if_any(), buff); + debug_message("%s", buff); + if (current_object) { + debug_message("program: /%s, object: %s, file: %s\n", + current_prog ? current_prog->name : "", + current_object->name, + get_line_number_if_any()); + } + ERROR(ERR_RECOVERY_ONLY); +#else + error("ERROR: (s)printf(): Incorrect argument type to %%%c.\n", + cheat[i - 1]); +#endif /* RETURN_ERROR_MESSAGES */ + } + cheat[i] = '\0'; + + if (carg->type == T_REAL) { + sprintf(temp, cheat, carg->u.real); + } else + sprintf(temp, cheat, carg->u.number); + { + int tmpl = strlen(temp); + + add_justified(temp, tmpl, &pad, fs, finfo, + (((format_str[fpos] != '\n') && (format_str[fpos] != '\0')) + || ((finfo & INFO_ARRAY) && (nelemno < (argv + sprintf_state->cur_arg)->u.arr->size)))); + } + } else /* type not found */ + ERROR(ERR_UNDEFINED_TYPE); + if (sprintf_state->clean.type != T_NUMBER) { + free_svalue(&(sprintf_state->clean), "string_print_formatted"); + sprintf_state->clean.type = T_NUMBER; + } + + if (!(finfo & INFO_ARRAY)) + break; + if (nelemno >= (argv + sprintf_state->cur_arg)->u.arr->size) + break; + carg = (argv + sprintf_state->cur_arg)->u.arr->item + nelemno++; + } /* end of while (1) */ + last = fpos; + fpos--; /* bout to get incremented */ + } + } /* end of for (fpos=0; 1; fpos++) */ + + outbuf_fix(&sprintf_state->obuff); + retvalue = sprintf_state->obuff.buffer; + sprintf_state->obuff.buffer = 0; + pop_stack(); /* pop off our error handler, will call pop_sprintf_state */ + return retvalue; +} /* end of string_print_formatted() */ + +#endif /* defined(F_SPRINTF) || defined(F_PRINTF) */ diff --git a/fluffos-2.23-ds03/sprintf.h b/fluffos-2.23-ds03/sprintf.h new file mode 100644 index 0000000..347ccc4 --- /dev/null +++ b/fluffos-2.23-ds03/sprintf.h @@ -0,0 +1,9 @@ +#ifndef SPRINTF_H +#define SPRINTF_H + +#include "lpc_incl.h" + +void svalue_to_string (svalue_t *, outbuffer_t *, int, int, int); +char *string_print_formatted (const char *, int, svalue_t *); + +#endif diff --git a/fluffos-2.23-ds03/std.h b/fluffos-2.23-ds03/std.h new file mode 100644 index 0000000..8bfd4cc --- /dev/null +++ b/fluffos-2.23-ds03/std.h @@ -0,0 +1,40 @@ +#ifndef STD_H +#define STD_H + +/* This stuff should be included EVERYWHERE */ + +/* the definition of ARCH */ +#include "arch.h" + +#ifdef EDIT_SOURCE +#define CONST +#define INLINE +#else +/* all options and configuration */ +#include "options_incl.h" +#include "configure.h" + +# ifdef PEDANTIC +# undef INLINE +# define INLINE +# endif +#endif + +#include "portability.h" +#include "macros.h" +#ifndef _FUNC_SPEC_ +# include "std_incl.h" +# include "malloc_incl.h" +# ifndef NO_OPCODES +# include "opcodes.h" +# endif +#endif +#include "debug.h" + +#endif + + + + + + diff --git a/fluffos-2.23-ds03/std_incl.h b/fluffos-2.23-ds03/std_incl.h new file mode 100644 index 0000000..d6fea6a --- /dev/null +++ b/fluffos-2.23-ds03/std_incl.h @@ -0,0 +1,123 @@ +#if !defined(STD_INCL_H) && !defined(_FUNC_SPEC_) +#define STD_INCL_H + +#ifdef INCL_STDLIB_H +# include +#endif +#ifdef INCL_UNISTD_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#ifdef INCL_FCNTL_H +# include +#endif + +#ifdef INCL_TIME_H +# include +#endif +#ifdef INCL_SYS_TIME_H +# include +#endif +#ifdef INCL_DOS_H +# include +#endif +#ifdef INCL_SYS_TIMES_H +# include +#endif +#ifdef INCL_USCLKC_H +# include +#endif + +#ifdef INCL_SYS_WAIT_H +# include +#endif +#ifdef INCL_SYS_CRYPT_H +# include +#endif +#ifdef INCL_CRYPT_H +# include +#endif +#ifdef INCL_VALUES_H +# include +#endif +#ifdef INCL_LIMITS_H +# include +#endif +#ifdef INCL_MALLOC_H +# include +#endif +#ifdef INCL_LOCALE_H +# include +#endif + +#ifdef INCL_DLFCN_H +# include +#endif + +#ifndef _AUX_SOURCE +/* supposedly, memmove is in here, but not defined in any lib */ +# include +#endif + +#ifndef NO_SOCKETS +# ifdef INCL_NETINET_IN_H +# include +# endif +# ifdef INCL_ARPA_INET_H +# include +# endif +#endif + +#if defined(WIN32) +int dos_style_link (char *, char *); +#define link(x, y) dos_style_link(x, y) +#endif + +#ifdef NeXT +# include +#endif + +#ifdef WIN32 +# include +#endif + +#if !defined(NeXT) && !defined(WIN32) +# include +#endif + +#ifdef OLD_ULTRIX +# include +# define size_t unsigned +#endif + +#ifdef INCL_MACH_MACH_H +# include +#endif + +#ifdef INCL_MACH_H +# include +#endif + +#ifdef sun +# include +#endif + +#include + +#ifdef INCL_BSTRING_H +#include +#endif + +/* Note: This is now only used if _both_ USHRT_MAX and MAXSHORT fail to exist*/ +#ifndef USHRT_MAX +#define USHRT_MAX ((1 << (sizeof(short)*8)) - 1) +#endif + +#endif diff --git a/fluffos-2.23-ds03/stralloc.c b/fluffos-2.23-ds03/stralloc.c new file mode 100644 index 0000000..658cdcc --- /dev/null +++ b/fluffos-2.23-ds03/stralloc.c @@ -0,0 +1,389 @@ +#include "std.h" +#include "lpc_incl.h" +#include "stralloc.h" +#include "hash.h" +#include "comm.h" + +/* used temporarily by SVALUE_STRLEN() */ +unsigned int svalue_strlen_size; + +#ifdef NOISY_DEBUG +void bp (void) { +} +#endif +/* + this code is not the same as the original code. I cleaned it up to + use structs to: 1) make it easier to check the driver for memory leaks + (using MallocDebug on a NeXT) and 2) because it looks cleaner this way. + --Truilkan@TMI 92/04/19 + + modified to make calls to strlen() unnecessary and to remove superfluous + calls to findblock(). -- Truilkan@TMI, 1992/08/05 +*/ + +/* + * stralloc.c - string management. + * + * All strings are stored in an extensible hash table, with reference counts. + * free_string decreases the reference count; if it gets to zero, the string + * will be deallocated. add_string increases the ref count if it finds a + * matching string, or allocates it if it cant. There is no way to allocate + * a string of a particular size to fill later (hash wont work!), so you'll + * have to copy things from a static (or malloced and later freed) buffer - + * that is, if you want to avoid space leaks... + * + * Current overhead: + * sizeof(block_t) per string (string pointer, next pointer, and a short + * for refs). Strings are nearly all fairly short, so this is a significant + * overhead - there is also the 4 byte malloc overhead and the fact that + * malloc generally allocates blocks which are a power of 2 (should write my + * own best-fit malloc specialised to strings); then again, GNU malloc + * is bug free... + */ + +/* + * there is also generic hash table management code, but strings can be shared + * (that was the point of this code), will be unique in the table, + * require a reference count, and are malloced, copied and freed at + * will by the string manager. Besides, I wrote this code first :-). + * Look at htable.c for the other code. It uses the Hash() function + * defined here, and requires hashed objects to have a pointer to the + * next element in the chain (which you specify when you call the functions). + */ + +#ifdef STRING_STATS +int num_distinct_strings = 0; +int bytes_distinct_strings = 0; +int overhead_bytes = 0; +int allocd_strings = 0; +int allocd_bytes = 0; +int search_len = 0; +int num_str_searches = 0; +#endif + +#define StrHash(s) (whashstr((s)) & (htable_size_minus_one)) + +#define hfindblock(s, h) sfindblock(s, h = StrHash(s)) +#define findblock(s) sfindblock(s, StrHash(s)) + +INLINE_STATIC block_t *sfindblock (const char *, int); + +/* + * hash table - list of pointers to heads of string chains. + * Each string in chain has a pointer to the next string and a + * reference count (char *, int) stored just before the start of the string. + * HTABLE_SIZE is in config.h, and should be a prime, probably between + * 1000 and 5000. + */ + +static block_t **base_table = (block_t **) 0; +static int htable_size; +static int htable_size_minus_one; + +INLINE_STATIC block_t *alloc_new_string (const char *, int); + +void init_strings() +{ + int x, y; + + /* ensure that htable size is a power of 2 */ + y = HTABLE_SIZE; + for (htable_size = 1; htable_size < y; htable_size *= 2) + ; + htable_size_minus_one = htable_size - 1; + base_table = CALLOCATE(htable_size, block_t *, + TAG_STR_TBL, "init_strings"); +#ifdef STRING_STATS + overhead_bytes += (sizeof(block_t *) * htable_size); +#endif + + for (x = 0; x < htable_size; x++) { + base_table[x] = 0; + } +} + +/* + * Looks for a string in the table. If it finds it, returns a pointer to + * the start of the string part, and moves the entry for the string to + * the head of the pointer chain. One thing (blech!) - puts the previous + * pointer on the hash chain into fs_prev. + */ + +INLINE_STATIC block_t * + sfindblock (const char * s, int h) +{ + block_t *curr, *prev; + + curr = base_table[h]; + prev = NULL; +#ifdef STRING_STATS + num_str_searches++; +#endif + + while (curr) { +#ifdef STRING_STATS + search_len++; +#endif + if (*(STRING(curr)) == *s && !strcmp(STRING(curr), s)) { /* found it */ + if (prev) { /* not at head of list */ + NEXT(prev) = NEXT(curr); + NEXT(curr) = base_table[h]; + base_table[h] = curr; + } + return (curr); /* pointer to string */ + } + prev = curr; + curr = NEXT(curr); + } + return ((block_t *) 0); /* not found */ +} + +char * + findstring (const char * s) +{ + block_t *b; + + if ((b = findblock(s))) { + return STRING(b); + } else { + return (NULL); + } +} + +/* alloc_new_string: Make a space for a string. */ + +INLINE_STATIC block_t * +alloc_new_string (const char * string, int h) +{ + block_t *b; + int len = strlen(string); + int size; + int cut = 0; + if (len > max_string_length) { + len = max_string_length; + cut = 1; + } + size = sizeof(block_t) + len + 1; + b = (block_t *) DXALLOC(size, TAG_SHARED_STRING, "alloc_new_string"); + strncpy(STRING(b), string, len); + STRING(b)[len] = '\0'; /* strncpy doesn't put on \0 if 'from' too + * long */ + if(cut) + h = whashstr(STRING(b)) & htable_size_minus_one; + SIZE(b) = (len > UINT_MAX ? UINT_MAX : len); + REFS(b) = 1; + NEXT(b) = base_table[h]; + HASH(b) = h; + base_table[h] = b; + ADD_NEW_STRING(SIZE(b), sizeof(block_t)); + ADD_STRING(SIZE(b)); + return (b); +} + +char * + make_shared_string (const char * str) +{ + block_t *b; + int h; + + b = hfindblock(str, h); /* hfindblock macro sets h = StrHash(s) */ + if (!b) { + b = alloc_new_string(str, h); + } else { + if (REFS(b)) + REFS(b)++; + //no we don't! ADD_STRING(SIZE(b)); + } + NDBG(b); + return (STRING(b)); +} + +/* + ref_string: Fatal to call this function on a string that isn't shared. +*/ + +const char * +ref_string (const char * str) +{ + block_t *b; + + b = BLOCK(str); +#ifdef DEBUG + if (b != findblock(str)) { + fatal("stralloc.c: called ref_string on non-shared string: %s.\n", str); + } +#endif /* defined(DEBUG) */ + if (REFS(b)) + REFS(b)++; + NDBG(b); + ADD_STRING(SIZE(b)); + return str; +} + +/* free_string: fatal to call free_string on a non-shared string */ +/* + * free_string - reduce the ref count on a string. Various sanity + * checks applied. + */ + +void +free_string (const char * str) +{ + block_t **prev, *b; + int h; + + b = BLOCK(str); + DEBUG_CHECK1(b != findblock(str),"stralloc.c: free_string called on non-shared string: %s.\n", str); + + /* + * if a string has been ref'd USHRT_MAX times then we assume that its used + * often enough to justify never freeing it. + */ + if (!REFS(b)) + return; + + REFS(b)--; + SUB_STRING(SIZE(b)); + + NDBG(b); + if (REFS(b) > 0) + return; + + //h = StrHash(str); + h = HASH(BLOCK(str)); + prev = base_table + h; + while ((b = *prev)) { + if (STRING(b) == str) { + *prev = NEXT(b); + break; + } + prev = &(NEXT(b)); + } + + DEBUG_CHECK1(!b, "free_string: not found in string table! (\"%s\")\n", str); + + SUB_NEW_STRING(SIZE(b), sizeof(block_t)); + FREE(b); + CHECK_STRING_STATS; +} + +void +deallocate_string (char * str) +{ + int h; + block_t *b, **prev; + + //h = StrHash(str); + h = HASH(BLOCK(str)); + prev = base_table + h; + while ((b = *prev)) { + if (STRING(b) == str) { + *prev = NEXT(b); + break; + } + prev = &(NEXT(b)); + } + DEBUG_CHECK1(!b,"stralloc.c: deallocate_string called on non-shared string: %s.\n", str); + //printf("freeing string: %s\n", str); + FREE(b); +} + +int +add_string_status (outbuffer_t * out, int verbose) +{ +#ifdef STRING_STATS + if (verbose == 1) { + outbuf_add(out, "All strings:\n"); + outbuf_add(out, "-------------------------\t Strings Bytes\n"); + } + if (verbose != -1) + outbuf_addv(out, "All strings:\t\t\t%8d %8d + %d overhead\n", + num_distinct_strings, bytes_distinct_strings, overhead_bytes); + if (verbose == 1) { + outbuf_addv(out, "Total asked for\t\t\t%8d %8d\n", + allocd_strings, allocd_bytes); + outbuf_addv(out, "Space actually required/total string bytes %d%%\n", + (bytes_distinct_strings + overhead_bytes) * 100 / allocd_bytes); + outbuf_addv(out, "Searches: %d Average search length: %6.3f\n", + num_str_searches, (double) search_len / num_str_searches); + } + return (bytes_distinct_strings + overhead_bytes); +#else + if (verbose) + outbuf_add(out, "\n"); + return 0; +#endif +} + +#ifdef DEBUGMALLOC_EXTENSIONS +#define DME 0, +#else +#define DME +#endif + +/* This stuff needs a bit more work, otherwise FREE_MSTR() will crash on this +malloc_block_t the_null_string_blocks[2] = { { DME 0, 1 }, { DME 0, 0 } }; + +char *the_null_string = (char *)&the_null_string_blocks[1]; +*/ + +#ifdef DEBUGMALLOC +char *int_new_string (int size, char * tag) +#else +char *int_new_string (int size) +#endif +{ + malloc_block_t *mbt; + +#if 0 + if (!size) { + the_null_string_blocks[0].ref++; + ADD_NEW_STRING(0, sizeof(malloc_block_t)); + return the_null_string; + } +#endif + + mbt = (malloc_block_t *)DXALLOC(size + sizeof(malloc_block_t) + 1, TAG_MALLOC_STRING, tag); + if (size < UINT_MAX) { + mbt->size = size; + ADD_NEW_STRING(size, sizeof(malloc_block_t)); + } else { + mbt->size = UINT_MAX; + ADD_NEW_STRING(UINT_MAX, sizeof(malloc_block_t)); + } + mbt->ref = 1; + ADD_STRING(mbt->size); + CHECK_STRING_STATS; + return (char *)(mbt + 1); +} + +char *extend_string (const char * str, int len) { + malloc_block_t *mbt; +#ifdef STRING_STATS + int oldsize = MSTR_SIZE(str); +#endif + + mbt = (malloc_block_t *)DREALLOC(MSTR_BLOCK(str), len + sizeof(malloc_block_t) + 1, TAG_MALLOC_STRING, "extend_string"); + if (len < UINT_MAX) { + mbt->size = len; + } else { + mbt->size = UINT_MAX; + } + ADD_STRING_SIZE(mbt->size - oldsize); + CHECK_STRING_STATS; + + return (char *)(mbt + 1); +} + +#ifdef DEBUGMALLOC +char *int_alloc_cstring (const char * str, char * tag) +#else +char *int_alloc_cstring (const char * str) +#endif +{ + char *ret; + + ret = (char *)DXALLOC(strlen(str) + 1, TAG_STRING, tag); + strcpy(ret, str); + return ret; +} diff --git a/fluffos-2.23-ds03/stralloc.h b/fluffos-2.23-ds03/stralloc.h new file mode 100644 index 0000000..d3553a2 --- /dev/null +++ b/fluffos-2.23-ds03/stralloc.h @@ -0,0 +1,149 @@ +#ifndef _STRALLOC_H_ +#define _STRALLOC_H_ + +/* ref-count debugging code */ +#undef NOISY_DEBUG +#define NOISY_STRING "workroom" + +/* implementation */ +#ifdef NOISY_DEBUG + void bp (void); +# ifdef NOISY_STRING +# define NDBG(x) if (strcmp(STRING(x), NOISY_STRING)==0) \ + debug_message("%s - %d\n", STRING(x), REFS(x)), bp() +# else +# define NDBG(x) debug_message("%s - %d\n", STRING(x), REFS(x)), bp() +# endif +#else +# define NDBG(x) +#endif + +#if defined(DEBUGMALLOC_EXTENSIONS) && defined(STRING_STATS) +/* Uncomment for very complete string ref checking, but be warned it runs + _very_ slowly. A conditional definition like: + + (current_prog && strcmp(current_prog->name, "foo") == 0 ? check_string_stats(0) : 0) + + is usually best. + */ +#define CHECK_STRING_STATS /* check_string_stats(0) */ +#else +#define CHECK_STRING_STATS +#endif + +#ifdef STRING_STATS +#define ADD_NEW_STRING(len, overhead) num_distinct_strings++; bytes_distinct_strings += len + 1; overhead_bytes += overhead +#define SUB_NEW_STRING(len, overhead) num_distinct_strings--; bytes_distinct_strings -= len + 1; overhead_bytes -= overhead + +#define ADD_STRING(len) allocd_strings++; allocd_bytes += len + 1; CHECK_STRING_STATS +#define ADD_STRING_SIZE(len) allocd_bytes += len; bytes_distinct_strings += len +#define SUB_STRING(len) allocd_strings--; allocd_bytes -= len + 1; CHECK_STRING_STATS +#else +/* Blazing fast macros :) */ +#define ADD_NEW_STRING(x, y) +#define SUB_NEW_STRING(x, y) +#define ADD_STRING(x) +#define ADD_STRING_SIZE(x) +#define SUB_STRING(x) +#endif + +typedef struct malloc_block_s { + void *dummy; + int bing; +#ifdef DEBUGMALLOC_EXTENSIONS + long extra_ref; +#endif + unsigned int size; + unsigned short ref; +} malloc_block_t; + +#define MSTR_BLOCK(x) (((malloc_block_t *)(x)) - 1) +#define MSTR_EXTRA_REF(x) (MSTR_BLOCK(x)->extra_ref) +#define MSTR_REF(x) (MSTR_BLOCK(x)->ref) +#define MSTR_SIZE(x) (MSTR_BLOCK(x)->size) +#define MSTR_UPDATE_SIZE(x, y) SAFE(\ + ADD_STRING_SIZE(y - MSTR_SIZE(x));\ + MSTR_BLOCK(x)->size = \ + (y > UINT_MAX ? UINT_MAX : y);\ + ) + +#define FREE_MSTR(x) SAFE(\ + DEBUG_CHECK(MSTR_REF(x) != 1, "FREE_MSTR used on a multiply referenced string\n");\ + svalue_strlen_size = MSTR_SIZE(x);\ + SUB_NEW_STRING(svalue_strlen_size, \ + sizeof(malloc_block_t));\ + FREE(MSTR_BLOCK(x));\ + SUB_STRING(svalue_strlen_size);\ + ) + +/* This counts on some rather crucial alignment between malloc_block_t and + * block_t. COUNTED_STRLEN(x) is the same as strlen(sv->u.string) when + * sv->subtype is STRING_MALLOC or STRING_SHARED, and runs significantly + * faster. + */ +#define COUNTED_STRLEN(x) ((svalue_strlen_size = MSTR_SIZE(x)), svalue_strlen_size != UINT_MAX ? svalue_strlen_size : strlen((x)+UINT_MAX)+UINT_MAX) +/* return the number of references to a STRING_MALLOC or STRING_SHARED + string */ +#define COUNTED_REF(x) MSTR_REF(x) + +/* ref == 0 means the string has been referenced USHRT_MAX times and is + immortal */ +#define INC_COUNTED_REF(x) if (MSTR_REF(x)) MSTR_REF(x)++; +/* This is a conditional expression that evaluates to zero if the block + should be deallocated */ +#define DEC_COUNTED_REF(x) (!(MSTR_REF(x) == 0 || --MSTR_REF(x) > 0)) + +typedef struct block_s { + struct block_s *next; /* next block in the hash chain */ + unsigned int hash; +#if defined(DEBUGMALLOC_EXTENSIONS) //|| (SIZEOF_PTR == 8) + long extra_ref; +#endif + /* these two must be last */ + unsigned int size; /* length of the string */ + unsigned short refs; /* reference count */ +} block_t; + +#define NEXT(x) (x)->next +#define REFS(x) (x)->refs +#define EXTRA_REF(x) (x)->extra_ref +#define SIZE(x) (x)->size +#define HASH(x) (x)->hash +#define BLOCK(x) (((block_t *)(x)) - 1) /* pointer arithmetic */ +#define STRING(x) ((char *)(x + 1)) + +#define SHARED_STRLEN(x) COUNTED_STRLEN(x) + +#define SVALUE_STRLEN(x) (((x)->subtype & STRING_COUNTED) ? \ + COUNTED_STRLEN((x)->u.string) : \ + strlen((x)->u.string)) + +/* For quick checks. Avoid strlen(), etc. This is */ +#define SVALUE_STRLEN_DIFFERS(x, y) ((((x)->subtype & STRING_COUNTED) && \ + ((y)->subtype & STRING_COUNTED)) ? \ + MSTR_SIZE((x)->u.string) != \ + MSTR_SIZE((y)->u.string) : 0) +/* + * stralloc.c + */ +void init_strings (void); +char *findstring (const char *); +char *make_shared_string (const char *); +const char *ref_string (const char *); +void free_string (const char *); +void deallocate_string (char *); +int add_string_status (outbuffer_t *, int); + +char *extend_string (const char *, int); + +extern unsigned int svalue_strlen_size; + +#ifdef STRING_STATS +extern int num_distinct_strings; +extern int bytes_distinct_strings; +extern int allocd_strings; +extern int allocd_bytes; +extern int overhead_bytes; +#endif + +#endif diff --git a/fluffos-2.23-ds03/sysmalloc.c b/fluffos-2.23-ds03/sysmalloc.c new file mode 100644 index 0000000..0e37aef --- /dev/null +++ b/fluffos-2.23-ds03/sysmalloc.c @@ -0,0 +1,13 @@ +#define IN_MALLOC_WRAPPER +#define NO_OPCODES +#include "std.h" +#include "lpc_incl.h" +#include "simulate.h" +#include "comm.h" + +#ifdef DO_MSTATS +void show_mstats (outbuffer_t * ob, char * s) { + outbuf_add(ob, "No malloc statistics available with SYSMALLOC\n"); +} +#endif + diff --git a/fluffos-2.23-ds03/telnet.h b/fluffos-2.23-ds03/telnet.h new file mode 100644 index 0000000..13f03db --- /dev/null +++ b/fluffos-2.23-ds03/telnet.h @@ -0,0 +1,196 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#)telnet.h 5.7 (Berkeley) 11/14/89 + */ + +/* + * Definitions for the TELNET protocol. + */ +#define IAC 255 /* interpret as command: */ +#define DONT 254 /* you are not to use option */ +#define DO 253 /* please, you use option */ +#define WONT 252 /* I won't use option */ +#define WILL 251 /* I will use option */ +#define SB 250 /* interpret as subnegotiation */ +#define GA 249 /* you may reverse the line */ +#define EL 248 /* erase the current line */ +#define EC 247 /* erase the current character */ +#define AYT 246 /* are you there */ +#define AO 245 /* abort output--but let prog finish */ +#define IP 244 /* interrupt process--permanently */ +#define BREAK 243 /* break */ +#define DM 242 /* data mark--for connect. cleaning */ +#define NOP 241 /* nop */ +#define SE 240 /* end sub negotiation */ +#define EOR 239 /* end of record (transparent mode) */ +#define ABORT 238 /* Abort process */ +#define SUSP 237 /* Suspend process */ +#define xEOF 236 /* End of file: EOF is already used... */ + +#define SYNCH 242 /* for telfunc calls */ + +#ifdef TELCMDS +char *telcmds[] = +{ + "EOF", "SUSP", "ABORT", "EOR", + "SE", "NOP", "DMARK", "BRK", "IP", "AO", "AYT", "EC", + "EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC", +}; + +#define TELCMD_FIRST xEOF +#define TELCMD_LAST IAC +#define TELCMD_OK(x) ((x) <= TELCMD_LAST && (x) >= TELCMD_FIRST) +#define TELCMD(x) telcmds[(x)-TELCMD_FIRST] +#endif + +/* telnet options */ +#define TELOPT_BINARY 0 /* 8-bit data path */ +#define TELOPT_ECHO 1 /* echo */ +#define TELOPT_RCP 2 /* prepare to reconnect */ +#define TELOPT_SGA 3 /* suppress go ahead */ +#define TELOPT_NAMS 4 /* approximate message size */ +#define TELOPT_STATUS 5 /* give status */ +#define TELOPT_TM 6 /* timing mark */ +#define TELOPT_RCTE 7 /* remote controlled transmission and echo */ +#define TELOPT_NAOL 8 /* negotiate about output line width */ +#define TELOPT_NAOP 9 /* negotiate about output page size */ +#define TELOPT_NAOCRD 10 /* negotiate about CR disposition */ +#define TELOPT_NAOHTS 11 /* negotiate about horizontal tabstops */ +#define TELOPT_NAOHTD 12 /* negotiate about horizontal tab disposition */ +#define TELOPT_NAOFFD 13 /* negotiate about formfeed disposition */ +#define TELOPT_NAOVTS 14 /* negotiate about vertical tab stops */ +#define TELOPT_NAOVTD 15 /* negotiate about vertical tab disposition */ +#define TELOPT_NAOLFD 16 /* negotiate about output LF disposition */ +#define TELOPT_XASCII 17 /* extended ascic character set */ +#define TELOPT_LOGOUT 18 /* force logout */ +#define TELOPT_BM 19 /* byte macro */ +#define TELOPT_DET 20 /* data entry terminal */ +#define TELOPT_SUPDUP 21 /* supdup protocol */ +#define TELOPT_SUPDUPOUTPUT 22 /* supdup output */ +#define TELOPT_SNDLOC 23 /* send location */ +#define TELOPT_TTYPE 24 /* terminal type */ +#define TELOPT_EOR 25 /* end or record */ +#define TELOPT_TUID 26 /* TACACS user identification */ +#define TELOPT_OUTMRK 27 /* output marking */ +#define TELOPT_TTYLOC 28 /* terminal location number */ +#define TELOPT_3270REGIME 29 /* 3270 regime */ +#define TELOPT_X3PAD 30 /* X.3 PAD */ +#define TELOPT_NAWS 31 /* window size */ +#define TELOPT_TSPEED 32 /* terminal speed */ +#define TELOPT_LFLOW 33 /* remote flow control */ +#define TELOPT_LINEMODE 34 /* Linemode option */ +#define TELOPT_EXOPL 255 /* extended-options-list */ + +#define NTELOPTS (1+TELOPT_LINEMODE) +#ifdef TELOPTS +char *telopts[NTELOPTS] = +{ + "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME", + "STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP", + "NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS", + "NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO", + "DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT", + "SEND LOCATION", "TERMINAL TYPE", "END OF RECORD", + "TACACS UID", "OUTPUT MARKING", "TTYLOC", + "3270 REGIME", "X.3 PAD", "NAWS", "TSPEED", "LFLOW", + "LINEMODE", +}; + +#define TELOPT_FIRST TELOPT_BINARY +#define TELOPT_LAST TELOPT_LINEMODE +#define TELOPT_OK(x) ((x) <= TELOPT_LAST && (x) >= TELOPT_FIRST) +#define TELOPT(x) telopts[(x)-TELOPT_FIRST] +#endif + +/* sub-option qualifiers */ +#define TELQUAL_IS 0 /* option is... */ +#define TELQUAL_SEND 1 /* send option */ + +/* + * LINEMODE suboptions + */ + +#define LM_MODE 1 +#define LM_FORWARDMASK 2 +#define LM_SLC 3 + +#define MODE_EDIT 0x01 +#define MODE_TRAPSIG 0x02 +#define MODE_ACK 0x04 + +#define MODE_MASK (MODE_EDIT|MODE_TRAPSIG|MODE_ACK) + +/* Not part of protocol, but needed to simplify things... */ +#define MODE_FLOW 0x0100 +#define MODE_ECHO 0x0200 +#define MODE_INBIN 0x0400 +#define MODE_OUTBIN 0x0800 +#define MODE_FORCE 0x1000 + +#define SLC_SYNCH 1 +#define SLC_BRK 2 +#define SLC_IP 3 +#define SLC_AO 4 +#define SLC_AYT 5 +#define SLC_EOR 6 +#define SLC_ABORT 7 +#define SLC_EOF 8 +#define SLC_SUSP 9 +#define SLC_EC 10 +#define SLC_EL 11 +#define SLC_EW 12 +#define SLC_RP 13 +#define SLC_LNEXT 14 +#define SLC_XON 15 +#define SLC_XOFF 16 +#define SLC_FORW1 17 +#define SLC_FORW2 18 + +#define NSLC 18 + +/* + * For backwards compatibility, we define SLC_NAMES to be the + * list of names if SLC_NAMES is not defined. + */ +#define SLC_NAMELIST "0", "SYNCH", "BRK", "IP", "AO", "AYT", "EOR", \ + "ABORT", "EOF", "SUSP", "EC", "EL", "EW", "RP", \ + "LNEXT", "XON", "XOFF", "FORW1", "FORW2" + +#ifdef SLC_NAMES +char *slc_names[] = { + SLC_NAMELIST; +}; +#else +extern char *slc_names[]; +#endif + +#define SLC_NAME_OK(x) ((unsigned int)(x) <= NSLC) +#define SLC_NAME(x) slc_names[x] + +#define SLC_NOSUPPORT 0 +#define SLC_CANTCHANGE 1 +#define SLC_VARIABLE 2 +#define SLC_DEFAULT 3 +#define SLC_LEVELBITS 0x03 + +#define SLC_FUNC 0 +#define SLC_FLAGS 1 +#define SLC_VALUE 2 + +#define SLC_ACK 0x80 +#define SLC_FLUSHIN 0x40 +#define SLC_FLUSHOUT 0x20 diff --git a/fluffos-2.23-ds03/testsuite/.edrc b/fluffos-2.23-ds03/testsuite/.edrc new file mode 100644 index 0000000..0d667b5 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/.edrc @@ -0,0 +1 @@ +148 diff --git a/fluffos-2.23-ds03/testsuite/clone/login.c b/fluffos-2.23-ds03/testsuite/clone/login.c new file mode 100644 index 0000000..cef68ad --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/clone/login.c @@ -0,0 +1,33 @@ +#include + +// needs fixed to handle passwords + +#ifdef __INTERACTIVE_CATCH_TELL__ +void catch_tell(string str) { + receive(str); +} +#endif + +void +logon() +{ + object user; + +#ifdef __NO_ADD_ACTION__ + set_this_player(this_object()); +#endif + write("Welcome to Lil!\n\n"); + cat("/etc/motd"); + write("\n> "); +#ifdef __PACKAGE_UIDS__ + seteuid(getuid(this_object())); +#endif + user= new("/clone/user"); + user->set_name("stuf" + getoid(user)); + exec(user, this_object()); + user->setup(); +#ifndef __NO_ENVIRONMENT__ + user->move(VOID_OB); +#endif + destruct(this_object()); +} diff --git a/fluffos-2.23-ds03/testsuite/clone/readme b/fluffos-2.23-ds03/testsuite/clone/readme new file mode 100644 index 0000000..e69de29 diff --git a/fluffos-2.23-ds03/testsuite/clone/user.c b/fluffos-2.23-ds03/testsuite/clone/user.c new file mode 100644 index 0000000..002822d --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/clone/user.c @@ -0,0 +1,232 @@ +// mudlib: Lil +// file: user.c +// purpose: is the representation of an interactive (user) in the MUD + +#include + +inherit BASE; + +private string name; + +#ifdef __INTERACTIVE_CATCH_TELL__ +void catch_tell(string str) { + receive(str); +} +#endif + +// replace this with a functioning version. + +string +query_cwd() +{ + return ""; +} + +// logon: move this to /single/login.c when login.c gets written. + +void +logon() +{ + write("Welcome to Lil.\n> "); +} + +// query_name: called by various objects needing to know this user's name. + +string +query_name() +{ + return name; +} + +void +set_name(string arg) +{ +// may wish to add security to prevent just anyone from changing +// someone else's name. + name = arg; +} + +// called by the present() efun (and some others) to determine whether +// an object is referred as an 'arg'. + +int +id(string arg) +{ + return (arg == query_name()) || base::id(arg); +} + +#ifndef __OLD_ED__ +void +write_prompt() { + switch (query_ed_mode()) { + case 0: + case -2: + write(":"); + break; + + case -1: + write("> "); + break; + + default: + write("*\b"); + break; + } +} + +void +start_ed(string file) { + write(ed_start(file, 0)); +} +#endif + +#ifdef __NO_ADD_ACTION__ +void +exec_command(string arg) { + string *parts = explode(arg, " "); + string verb = sizeof(parts) ? parts[0] : ""; + string rest = implode(parts[1..], " "); + string cmd_path = COMMAND_PREFIX + verb; + object cobj = load_object(cmd_path); + + if (cobj) { + cobj->main(rest); + } else { + // maybe call an emote/soul daemon here + } +} + +void +process_input(string arg) { +#ifndef __OLD_ED__ + if (query_ed_mode() != -1) { + if (arg[0] != '!') { + write(ed_cmd(arg)); + return; + } + arg = arg[1..]; + } +#endif + exec_command(arg); +} +#else +string +process_input(string arg) +{ +#ifndef __OLD_ED__ + if (query_ed_mode() != -1) { + if (arg[0] != '!') { + write(ed_cmd(arg)); + return 0; + } + arg = arg[1..]; + } +#endif + // possible to modify player input here before driver parses it. + return arg; +} + +int +commandHook(string arg) +{ + string cmd_path; + object cobj; + + cmd_path = COMMAND_PREFIX + query_verb(); + + cobj = load_object(cmd_path); + if (cobj) { + return (int)cobj->main(arg); + } else { + // maybe call an emote/soul daemon here + } + return 0; +} + +// init: called by the driver to give the object a chance to add some +// actions (see the MudOS "applies" documentation for a better description). + +void +init() +{ + // using "" as the second argument to add_action() causes the driver + // to call commandHook() for those user inputs not matched by other + // add_action defined commands (thus 'commandHook' becomes the default + // action for those verbs without an explicitly associated action). + if (this_object() == this_player()) { + add_action("commandHook", "", 1); + } +} +#endif + +// create: called by the driver after an object is compiled. + +void +create() +{ +#ifdef __PACKAGE_UIDS__ + seteuid(0); // so that login.c can export uid to us +#endif +} + +// receive_message: called by the message() efun. + +void +receive_message(string newclass, string msg) +{ + // the meaning of 'class' is at the mudlib's discretion + receive(msg); +} + +// setup: used to configure attributes that aren't known by this_object() +// at create() time such as living_name (and so can't be done in create()). + +void +setup() +{ + set_heart_beat(1); +#ifdef __PACKAGE_UIDS__ + seteuid(getuid(this_object())); +#endif +#ifndef __NO_WIZARDS__ + enable_wizard(); +#endif +#ifndef __NO_ADD_ACTION__ + set_living_name(query_name()); + enable_commands(); + add_action("commandHook", "", 1); +#else + set_this_player(this_object()); +#endif +} + +// net_dead: called by the gamedriver when an interactive player loses +// hir network connection to the mud. + +#ifndef __NO_ENVIRONMENT__ +void tell_room(object ob, string msg) { + foreach (ob in all_inventory(ob) - ({ this_object() })) + tell_object(ob, msg); +} +#endif + +void +net_dead() +{ + set_heart_beat(0); +#ifndef __NO_ENVIRONMENT__ + tell_room(environment(), query_name() + " is link-dead.\n"); +#endif +} + +// reconnect: called by the login.c object when a netdead player reconnects. + +void +reconnect() +{ + set_heart_beat(1); +#ifndef __NO_ENVIRONMENT__ + tell_room(environment(), "Reconnected.\n"); + tell_room(environment(), query_name() + " has reconnected.\n"); +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/command/codefor.c b/fluffos-2.23-ds03/testsuite/command/codefor.c new file mode 100644 index 0000000..77074e2 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/command/codefor.c @@ -0,0 +1,25 @@ +int +main(string a) +{ + object ret; + mixed code; + + if (file_size("/tmp_eval_file.c") != -1) + rm ("/tmp_eval_file.c"); + if (find_object("/tmp_eval_file")) + destruct(find_object("/tmp_eval_file")); + + write_file("/tmp_eval_file.c", "mixed eval() { " + a + "; }\n"); + + ret = load_object("/tmp_eval_file"); + + dump_prog(ret, 1, "/CODE_TMP_FILE"); + code = read_file( "/CODE_TMP_FILE"); + rm("/CODE_TMP_FILE"); + rm("/tmp_eval_file.c"); + + code = explode(code, ";;; *** Disassembly ***\n"); + code = code[1]; + write(code[0..strlen(code)-1]); + return 1; +} diff --git a/fluffos-2.23-ds03/testsuite/command/dest.c b/fluffos-2.23-ds03/testsuite/command/dest.c new file mode 100644 index 0000000..bebb05e --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/command/dest.c @@ -0,0 +1,38 @@ +#include + +int +main(string arg) +{ + object obj; + + if (!arg) { +#ifndef __NO_ADD_ACTION__ + return notify_fail("usage: dest object\n"); +#else + write("usage: dest object\n"); + return 1; +#endif + } + obj = find_object(arg); +#ifndef __NO_ENVIRONMENT__ + if (!obj) { + obj = present(arg); + if (!obj) { + obj = present(arg, environment(previous_object())); + } + } +#endif + if (!obj) { +#ifndef __NO_ADD_ACTION__ + return notify_fail("can't find that.\n"); +#else + write("can't find that.\n"); + return 1; +#endif + } + obj->remove(); + if (obj) { + destruct(obj); + } + return 1; +} diff --git a/fluffos-2.23-ds03/testsuite/command/ed.c b/fluffos-2.23-ds03/testsuite/command/ed.c new file mode 100644 index 0000000..83c0333 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/command/ed.c @@ -0,0 +1,13 @@ +#include + +int +main(string file) +{ + // need to call resolve_path() and query_cwd() +#ifdef __OLD_ED__ + ed(file); +#else + this_player()->start_ed(file); +#endif + return 1; +} diff --git a/fluffos-2.23-ds03/testsuite/command/eval.c b/fluffos-2.23-ds03/testsuite/command/eval.c new file mode 100644 index 0000000..60d79ae --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/command/eval.c @@ -0,0 +1,13 @@ +int +main(string arg) +{ + /* clean up first */ + if (file_size("/tmp_eval_file.c") != -1) + rm ("/tmp_eval_file.c"); + if (find_object("/tmp_eval_file")) + destruct(find_object("/tmp_eval_file")); + + write_file("/tmp_eval_file.c","mixed eval() { "+arg+"; }\n"); + printf("Result = %O\n", "/tmp_eval_file"->eval()); + return 1; +} diff --git a/fluffos-2.23-ds03/testsuite/command/quit.c b/fluffos-2.23-ds03/testsuite/command/quit.c new file mode 100644 index 0000000..a89c7bb --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/command/quit.c @@ -0,0 +1,15 @@ +#include + +#ifdef __NO_ENVIRONMENT__ +#define say(x) shout(x) +#endif + +int +main(string arg) +{ + write("Bye.\n"); + say((string)previous_object()->query_name() + + " leaves this reality.\n"); + previous_object()->remove(); + return 1; +} diff --git a/fluffos-2.23-ds03/testsuite/command/readme b/fluffos-2.23-ds03/testsuite/command/readme new file mode 100644 index 0000000..16a62d1 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/command/readme @@ -0,0 +1,2 @@ +This directory is to contain the objects implementing the commands that +interactives can use (movement, building, communication, etc). diff --git a/fluffos-2.23-ds03/testsuite/command/rm.c b/fluffos-2.23-ds03/testsuite/command/rm.c new file mode 100644 index 0000000..7bed226 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/command/rm.c @@ -0,0 +1,9 @@ +#include + +int +main(string file) +{ + // need to call resolve_path() and query_cwd() + rm(file); + return 1; +} diff --git a/fluffos-2.23-ds03/testsuite/command/say.c b/fluffos-2.23-ds03/testsuite/command/say.c new file mode 100644 index 0000000..9092734 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/command/say.c @@ -0,0 +1,12 @@ +#include + +#ifdef __NO_ENVIRONMENT__ +#define say(x) shout(x) +#endif + +int main(string arg) +{ + say((string)previous_object()->query_name() + + " says: " + arg + "\n"); + return 1; +} diff --git a/fluffos-2.23-ds03/testsuite/command/shutdown.c b/fluffos-2.23-ds03/testsuite/command/shutdown.c new file mode 100644 index 0000000..86469d0 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/command/shutdown.c @@ -0,0 +1,8 @@ +#include + +int +main(string arg) +{ + shutdown(0); + return 1; +} diff --git a/fluffos-2.23-ds03/testsuite/command/speed.c b/fluffos-2.23-ds03/testsuite/command/speed.c new file mode 100644 index 0000000..3200399 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/command/speed.c @@ -0,0 +1,206 @@ +#define OTHER_TESTS +#define STRING_TESTS +#define ARRAY_TESTS +#define MAPPING_TESTS + +inherit "/single/inh"; + +int time; +int save; +mixed * a_global_var; +mapping another; +string one_more; + +#ifndef MUDOS +#define map_delete m_delete +#endif + +#ifdef __DGD__ +#define out(x) send_message(x) +#else +#define out(x) write(x) +#endif + +create() { + a_global_var = ({ 1, 3, 5, ({ 4, 1 }) }); + another = ([ 1 : "foo", 3 : "bar" ]); + one_more = "Hmm"; +} + +void lfun0() { +} + +void lfun1(mixed a1) { +} + +void lfun2(mixed a1, mixed a2) { +} + +void lfun3(mixed a1, mixed a2, mixed a3) { +} +#ifdef MUDOS +#define START do { reset_eval_cost(); set_eval_limit(0x7fffffff); before = rusage(); } while (0) +#define END after = rusage(); time = after["stime"] + after["utime"] - before["stime"] - before["utime"] +#else +#ifdef ANCIENT +#define START sscanf(rusage(), before, i); before += i +#define END sscanf(rusage(), after, i); time = after + i - before +#else +#define START before = rusage() +#define END after = rusage(); time = after[0] + after[1] - before[0] - before[1] +#endif +#endif + +#define REPORT(z, t) out((z) + ": " + (t) + "\n") +#define LOOP(n, x) for (i = 0; i < (n); i++) { x; } + +#define DIFF(z, n, x, y) START; LOOP(n, x); END; save = time; \ + START; LOOP(n, y); END; REPORT(z, time - save) +#define SINGLE(z, x) START; x; END; REPORT(z, time) + +/* Evidentally, 3.2 doesn't have token pasting */ +#define INIT(n) START; LOOP(n, ); END; empty##n = time + +#define TIMEDIFF(z, n, x, d) START; LOOP(n, x); END; REPORT(z, time - d) +#define TIME(z, n, x) START; LOOP(n, x); END; REPORT(z, time - empty##n) +#define SAVETIME(z, n, x) START; LOOP(n, x); END; z = time + +int main() { +#ifdef MUDOS + mapping before, after; +#else + int *before, *after; +#endif + int i; +#ifdef STRING_TESTS + string s, s1, s2, s3; +#endif +#ifdef ARRAY_TESTS + mixed *a, *a1, *a2, *a3; +#endif +#ifdef MAPPING_TESTS + mapping m, m1; +#endif + int empty300, empty1000, empty10000, empty20000, empty50000, + empty100000, empty200000, empty1000000; + int save; + int ss, sm; + +#ifdef STRING_TESTS + s1 = "This is a test"; + s2 = " of the emergency broadcast system."; + s3 = s1 + s2; +#endif +#ifdef ARRAY_TESTS + a1 = ({ 5, 1, 3, 4, 2 }); + a2 = ({ 9, 8, 7, 6, 10 }); + a3 = ({ 4, 1 }); +#endif +#ifdef MAPPING_TESTS + m1 = ([ "1" : "a", "2" : "b", "3" : "c", "4" : "d", "5" : "e" ]); +#endif + + out("Initializing variables ...\n"); + INIT(300); + INIT(1000); + INIT(10000); + INIT(20000); + INIT(50000); + INIT(100000); + INIT(200000); + INIT(1000000); + +#ifdef OTHER_TESTS + DIFF("instruction", 10000000, save, -save); + SINGLE("empty for", for (i = 0; i < 3500000; i++) ;); + i = 5000000; SINGLE("while", while (i--); ); + i = 2500000; SINGLE("while2", while (1) { if (!(i--)) break; }); +#endif +#ifdef STRING_TESTS + TIME("string assign (s)",1000000, s = s1); + TIME("string assign (m)",200000, s = s3); + TIME("string add (ss)",200000, s1 + s2); + TIME("string add (sm)",200000,s1 + s3); + TIME("string add (ms)",100000,s3 + s1); + TIME("string add (mm)",100000,s3 + s3); + SAVETIME(ss, 100000, s = s1); + SAVETIME(sm, 100000, s = s3); + TIMEDIFF("string += (ss)",100000,s = s1; s += s2, ss); + TIMEDIFF("string += (sm)",100000,s = s1; s += s3, ss); + TIMEDIFF("string += (ms)",100000,s = s3; s += s1, sm); + TIMEDIFF("string += (mm)",100000,s = s3; s += s3, sm); +#endif +#ifdef ARRAY_TESTS + TIME("allocate array",10000, a = allocate(100)); + TIME("array creation (int)",50000, ({ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 })); + TIME("array creation (string)",20000,({ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" })); + TIME("array assign",200000,a = a1); + TIME("array addition",50000,a1 + a2); + TIME("array subtraction",20000,a1 - a3); + TIME("array lookup",100000,a1[3]); + SAVETIME(save,50000,a = a1); + TIMEDIFF("array +=",50000,a = a1; a += a2,save); + TIMEDIFF("array -=",50000,a = a1; a -= a3, save); +#endif +#ifdef MAPPING_TESTS + TIME("allocate mapping",50000, m = allocate_mapping(100)); + TIME("mapping creation (int)",50000, ([ 1 : 2, 3 : 4, 5 : 6, 7 : 8 ])); + TIME("mapping creation (string)",50000, ([ "1" : "a", "2" : "b", "3" : "c", "4" : "d", "5" : "e" ])); + TIME("lookup (exist)",100000, m1["3"]); + TIME("lookup (missing)",100000, m1["6"]); + TIME("mapping assign",200000, m = m1); + SAVETIME(save,100000, m = m1); + TIMEDIFF("mapping insert",100000, m = m1; m["6"] = "f", save); + TIMEDIFF("mapping replace",100000, m = m1; m["2"] = 0, save); + TIMEDIFF("mapping delete",100000, m = m1; map_delete(m, "2"), save); +#endif +#ifdef OTHER_TESTS + TIME("local call (no args)",100000, lfun0()); + TIME("local call (1 arg)",100000, lfun1(1)); + TIME("local call (2 args)",100000, lfun2("foo", 1)); + TIME("local call (3 args)",100000, lfun3("foo", 1, i)); + TIME("simul_efun",100000, simul()); + TIME("call_other",50000,this_object()->lfun0()); +#ifdef MUDOS + TIME("call_other (string)",50000,"/command/speed"->lfun0()); +#else + TIME("call_other (string)",50000,"/command/speed"->lfun0()); +#endif + TIME("call_other (miss)",50000,this_object()->doesnt_exist()); + TIME("inherited call",100000,ifun()); + TIME("explicit inherited",100000,inh::ifun()); + TIME("save_object",300,save_object("/tmp/tmp")); + TIME("restore_object",1000,restore_object("/tmp/tmp")); + SAVETIME(ss, 1000000, save = 0); + SAVETIME(sm, 1000000, save = 1); + save = 0; + TIMEDIFF("if (x == 0) T",1000000,if (save == 0) { save = 0; }, ss); + save = 1; + TIME("if (x == 0) F",1000000,if (save == 0) { }); + save = 1; + TIMEDIFF("if (x) T",1000000,if (save) { save = 1; }, sm); + save = 0; + TIME("if (x) F",1000000,if (save) { }); + save = 0; + TIMEDIFF("if (x < n) T",1000000,if (save < 1) { save = 0; }, ss); + save = 1; + TIME("if (x < n) F",1000000,if (save < 1) { }); + save = 0; + TIMEDIFF("if (!x) T",1000000,if (!save) { save = 0; }, ss); + save = 1; + TIME("if (!x) F",1000000,if (!save) { }); + save = 1; + TIMEDIFF("if (x == n) T",1000000,if (save == 1) { save = 1; }, sm); + save = 0; + TIME("if (x == n) F",1000000,if (save == 1) { }); + SAVETIME(save, 1000000, sm = 0); + sm = 0; + ss = 1; + TIME("if (x && y && z) F",1000000, if (sm && sm && sm) { sm = 0; }); + TIME("if (x && y && z) TF",1000000, if (ss && sm && sm) { sm = 0; }); + TIME("if (x && y && z) TTF",1000000, if (ss && ss && sm) { sm = 0; }); + TIMEDIFF("if (x && y && z) TTT",1000000, if (ss && ss && ss) { sm = 0; }, + save); +#endif + return 1; +} diff --git a/fluffos-2.23-ds03/testsuite/command/tests.c b/fluffos-2.23-ds03/testsuite/command/tests.c new file mode 100644 index 0000000..2ead6c5 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/command/tests.c @@ -0,0 +1,55 @@ +#include + +int main(string fun); + +void recurse(string dir) { + mixed leaks; + + foreach (string file in get_dir(dir + "*.c")) + main(dir + file); + foreach (string subdir in map(filter(get_dir(dir + "*", -1), + (: $1[1] == -2 :)), + (: $1[0] :)) - ({ ".", ".." })) + { + if (subdir == "fail") { + foreach (string fn in get_dir(dir + "fail/*.c")) { + ASSERT2(catch(load_object(dir+"fail/"+fn)), "fail/" + fn + " loaded"); +#if defined(__DEBUGMALLOC_EXTENSIONS__) && defined(__CHECK_MEMORY__) + leaks = check_memory(); + if (sizeof(filter(explode(leaks, "\n"), (: $1 && $1[0] :))) != 1) { + write("After trying to compile: " + dir + "fail/" + fn + "\n"); + write(leaks); + error("LEAK\n"); + } +#endif + } + rm("/log/compile"); + } else + recurse(dir + subdir + "/"); + } +} + +int +main(string fun) +{ + string leaks; + object tp = this_player(); + + if (!fun || fun == "") { + recurse("/single/tests/"); + write("Checks succeeded.\n"); + return 1; + } + fun->do_tests(); + if (tp != this_player()) + error("Bad this_player() after calling " + fun + "\n"); +#if defined(__DEBUGMALLOC_EXTENSIONS__) && defined(__CHECK_MEMORY__) + leaks = check_memory(); + if (sizeof(filter(explode(leaks, "\n"), (: $1 && $1[0] :))) != 1) { + write("After calling: " + fun + "\n"); + write(leaks); + error("LEAK\n"); + } +#endif + return 1; +} diff --git a/fluffos-2.23-ds03/testsuite/command/update.c b/fluffos-2.23-ds03/testsuite/command/update.c new file mode 100644 index 0000000..1f17d64 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/command/update.c @@ -0,0 +1,22 @@ +#include + +int +main(string file) +{ + object obj; + + // need to call resolve_path() and query_cwd() + if (!file) { +#ifndef __NO_ADD_ACTION__ + return notify_fail("update what?\n"); +#else + write("update what?\n"); + return 1; +#endif + } + if (obj = find_object(file)) { + destruct(obj); + } + load_object(file); + return 1; +} diff --git a/fluffos-2.23-ds03/testsuite/command/who.c b/fluffos-2.23-ds03/testsuite/command/who.c new file mode 100644 index 0000000..1f62187 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/command/who.c @@ -0,0 +1,19 @@ +#include + +int +main(string arg) +{ + object *list; + int j; + + printf("%-25s idle\n", "name (*edit, +input)"); + printf("-------------------- ----\n"); + for (list = users(), j = 0; j < sizeof(list); j++) { + printf("%-25s %4d\n", (string)list[j]->query_name() + + (in_edit(this_player()) ? "*" : "") + + (in_input(this_player()) ? "+" : ""), + query_idle(this_player()) / 60 + ); + } + return 1; +} diff --git a/fluffos-2.23-ds03/testsuite/data/readme b/fluffos-2.23-ds03/testsuite/data/readme new file mode 100644 index 0000000..009eaae --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/data/readme @@ -0,0 +1 @@ +This directory is to contain the .o files created by the save_object() efun. diff --git a/fluffos-2.23-ds03/testsuite/etc/config.test b/fluffos-2.23-ds03/testsuite/etc/config.test new file mode 100644 index 0000000..ef3fb5b --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/etc/config.test @@ -0,0 +1,145 @@ +############################################################################### +# Customizable runtime config file for MudOS v21 # +############################################################################### +# NOTE: All paths specified here are relative to the mudlib directory except # +# for mudlib directory, and binary directory. # +# Lines beginning with a # or a newline are ignored. # +############################################################################### + +# name of this mud +name : Testsuite + +# port number to accept users on +port number : 4000 + +# the address server is an external program that lets the mud translate +# internet names to numbers (and vice versa). select an unused port. +address server ip : localhost +address server port : 7374 + +# absolute pathname of mudlib +mudlib directory : /gdir/apang/beta/testsuite + +# absolute pathname of driver/config dir +binary directory : /gdir/apang/beta + +# debug.log and author/domain stats are stored here +log directory : /log + +# the directories which are searched by #include <...> +# for multiple dirs, separate each path with a ':' +include directories : /include + +# Directory to save binaries in. (if BINARIES is defined) +save binaries directory : /binaries + +# the file which defines the master object +master file : /single/master + +# the file where all global simulated efuns are defined. +simulated efun file : /single/simul_efun + +# file to swap out objects; not used if time to swap is 0 +swap file : /etc/swapfile + +# alternate debug.log file name (assumed to be in specified 'log directory') +debug log file : debug.log + +# This is an include file which is automatically #include'd in all objects +global include file : + +# if an object is left alone for a certain time, then the +# function clean_up will be called. This function can do anything, +# like destructing the object. If the function isn't defined by the +# object, then nothing will happen. +# This time should be substantially longer than the swapping time. +time to clean up : 1200 + +# How long time until an unused object is swapped out. +# Machine with too many players and too little memory: 900 (15 minutes) +# Machine with few players and lot of memory: 10000 +# Machine with infinite memory: 0 (never swap). +time to swap : 600 + +# How many seconds until an object is reset again. +time to reset : 1800 + +# Maximum number of bits in a bit field. They are stored in printable +# strings, 6 bits per byte. +maximum bits in a bitfield : 1200 + +# Max number of local variables in a function. +maximum local variables : 30 + +# Maximum amount of "eval cost" per thread - execution is halted when +# it is exceeded. +maximum evaluation cost : 500000 + +# This is the maximum array size allowed for one single array. +maximum array size : 15000 + +# This is the maximum allowed size of a variable of type 'buffer'. +maximum buffer size : 400000 + +# Max size for a mapping +maximum mapping size : 15000 + +# Max inherit chain size +inherit chain size : 30 + +# maximum length of a string variable +maximum string length : 200000 + +# Max size of a file allowed to be read by 'read_file()'. +maximum read file size : 200000 + +# max number of bytes you allow to be read and written with read_bytes +# and write_bytes +maximum byte transfer : 10000 + +# Reserve an extra memory area from malloc(), to free when we run out +# of memory and allow the mudlib to shutdown. +# If this value is 0, no area will be reserved. +reserved size : 0 + +# Define the size of the shared string hash table. This number should +# a prime, probably between 1000 and 30000; if you set it to about 1/5 +# of the number of distinct strings you have, you will get a hit ratio +# (number of comparisons to find a string) very close to 1, as found strings +# are automatically moved to the head of a hash chain. You will never +# need more, and you will still get good results with a smaller table. +hash table size : 7001 + +# Object hash table size. +# Define this like you did with the strings; probably set to about 1/4 of +# the number of objects in a game, as the distribution of accesses to +# objects is somewhat more uniform than that of strings. +object table size : 1501 + +# default no-matching-action message +default fail message : What? + +# default message when error() occurs (optional) +default error message : + +############################################################################### +# The following aren't currently used or implemented (yet) # +############################################################################### + +# maximum number of users in the game (unused currently) +maximum users : 40 + +# Define the maximum stack size of the stack machine. This stack will also +# contain all local variables and arguments. (unused currently) +evaluator stack size : 1000 + +# Define the size of the compiler stack. This defines how complex +# expressions the compiler can parse. (unused currently) +compiler stack size : 200 + +# Define the maximum call depth for functions. (unused currently) +maximum call depth : 30 + +# There is a hash table for living objects, used by find_living(). +# (unused currently) +living hash table size : 100 diff --git a/fluffos-2.23-ds03/testsuite/etc/motd b/fluffos-2.23-ds03/testsuite/etc/motd new file mode 100644 index 0000000..0ed9b5c --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/etc/motd @@ -0,0 +1,7 @@ +The only commands in this little mudlib are: + + dest, update, ed, eval, efun, rm, say, who, quit, and shutdown. + +All of update, dest, ed, and rm require full pathnames as arguments. + +Have fun. diff --git a/fluffos-2.23-ds03/testsuite/include/command.h b/fluffos-2.23-ds03/testsuite/include/command.h new file mode 100644 index 0000000..6fbbff8 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/include/command.h @@ -0,0 +1,3 @@ +#include + +inherit CLEAN_UP; diff --git a/fluffos-2.23-ds03/testsuite/include/config.h b/fluffos-2.23-ds03/testsuite/include/config.h new file mode 100644 index 0000000..40151cd --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/include/config.h @@ -0,0 +1,9 @@ +/* + * if "global include file" is specified in the config file, this header + * file is automatically included by all objects; otherwise, you have to + * #include it manually + */ +#ifndef __CONFIG_H__ +#define __CONFIG_H__ + +#endif diff --git a/fluffos-2.23-ds03/testsuite/include/globals.h b/fluffos-2.23-ds03/testsuite/include/globals.h new file mode 100644 index 0000000..fa6f0f9 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/include/globals.h @@ -0,0 +1,35 @@ +// file: globals.h + +#ifdef __SENSIBLE_MODIFIERS__ +#define staticf protected +#define staticv nosave +#else +#define staticf static +#define staticv static +#endif + +#include "tests.h" + +#define SINGLE_DIR "/single" +#define CONFIG_DIR "/etc" +#define LOG_DIR "/log" + +#define VIRTUAL_D "/single/virtual" + +#define LOGIN_OB "/clone/login" +#define USER_OB "/clone/user" +#define VOID_OB "/single/void" + +#define ROOT_UID "Root" +#define BACKBONE_UID "Backbone" + +#define BASE "/inherit/base" +#define OVERRIDES_FILE "/single/simul_efun" + +#define COMMAND_PREFIX "/command/" + +// classes for message() efun. +#define M_STATUS "status" +#define M_SAY "say" + +#define CLEAN_UP "/inherit/clean_up" diff --git a/fluffos-2.23-ds03/testsuite/include/lpctypes.h b/fluffos-2.23-ds03/testsuite/include/lpctypes.h new file mode 100644 index 0000000..ed48312 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/include/lpctypes.h @@ -0,0 +1,16 @@ +/* /include/type.h */ + +#ifndef _TYPE_H +#define _TYPE_H + +#define INT "int" +#define STRING "string" +#define ARRAY "array" +#define OBJECT "object" +#define MAPPING "mapping" +#define FUNCTION "function" +#define FLOAT "float" +#define BUFFER "buffer" +#define CLASS "class" + +#endif diff --git a/fluffos-2.23-ds03/testsuite/include/readme b/fluffos-2.23-ds03/testsuite/include/readme new file mode 100644 index 0000000..fc5a9ca --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/include/readme @@ -0,0 +1,2 @@ +This directory contains files that are included via the #include +preprocessor directive. diff --git a/fluffos-2.23-ds03/testsuite/include/tests.h b/fluffos-2.23-ds03/testsuite/include/tests.h new file mode 100644 index 0000000..b8d0f2c --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/include/tests.h @@ -0,0 +1,16 @@ +#ifndef TESTS_H +#define TESTS_H + +#define ASSERT(x) if (!(x)) { error(file_name() + ": Check failed.\n"); } +#define ASSERT2(x, r) if (!(x)) { error(file_name() + ":" + r + ", Check failed.\n"); } + +#define SAVETP tp = this_player() +#define RESTORETP { if (tp) evaluate(bind( (: enable_commands :), tp)); else { object youd_never_use_this_as_a_var = new("/single/void"); evaluate(bind( (: enable_commands :), youd_never_use_this_as_a_var)); destruct(youd_never_use_this_as_a_var); } } + +#ifdef __OLD_TYPE_BEHAVIOR__ +#define TYPETEST scream and die +#else +#define TYPETEST +#endif + +#endif diff --git a/fluffos-2.23-ds03/testsuite/inherit/base.c b/fluffos-2.23-ds03/testsuite/inherit/base.c new file mode 100644 index 0000000..35d77be --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/inherit/base.c @@ -0,0 +1,38 @@ +// set to 'private static' so that inheritor won't be able to directly +// access this variable and so that save_object() won't save it to the .o file + +private staticv string *ids; + +void +remove() +{ + // add code here to prevent unwanted destructions. + // update attributes of the container and the containees. + destruct(this_object()); +} + +#ifndef __NO_ENVIRONMENT__ +int +move(mixed dest) +{ + // add code here to prevent disallowed moves (target is full, object + // is immovable, etc.). + move_object(dest); +} +#endif + +void +set_ids(string *arg) +{ + // probably want to add some security here. + ids = arg; +} + +int +id(string arg) +{ + if (!arg || !ids) { + return 0; + } + return (member_array(arg, ids) != -1); +} diff --git a/fluffos-2.23-ds03/testsuite/inherit/clean_up.c b/fluffos-2.23-ds03/testsuite/inherit/clean_up.c new file mode 100644 index 0000000..c0e6895 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/inherit/clean_up.c @@ -0,0 +1,7 @@ + +int +clean_up(int inh) +{ + destruct(this_object()); + return 0; +} diff --git a/fluffos-2.23-ds03/testsuite/inherit/master/valid.c b/fluffos-2.23-ds03/testsuite/inherit/master/valid.c new file mode 100644 index 0000000..5ae5bf8 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/inherit/master/valid.c @@ -0,0 +1,97 @@ +// file: /inherit/master/valid.c +// mudlib: Lil + +// separated out from master.c to reduce the complexity a bit. + +#include + + + +void create() { +} + +int +valid_shadow(object ob) +{ +#ifdef __PACKAGE_UIDS__ + if (getuid(ob) == ROOT_UID) { + return 0; + } +#endif + if (ob->query_prevent_shadow(previous_object())) { + return 0; + } + return 1; +} + +int +valid_author(string) +{ + return 1; +} + +// valid_override: controls which simul_efuns may be overridden with +// efun:: prefix and which may not. This function is only called at +// object compile-time. +// +// returns: 1 if override is allowed, 0 if not. + +int +valid_override(string file, string name) +{ + if (file == OVERRIDES_FILE) { + return 1; + } + if ((name == "move_object") && (file != BASE)) + return 0; +// may also wish to protect destruct, shutdown, snoop, and exec. + return 1; +} + +// valid_seteuid: determines whether an object ob can become euid str. +// returns: 1 if seteuid() may succeed, 0 if not. + +int +valid_seteuid(object, string) +{ + return 1; +} + +// valid_domain: decides if a domain may be created +// returns: 1 if domain may be created, 0 if not. + +int +valid_domain(string) +{ + return 1; +} + +// valid_socket: controls access to socket efunctions +// return: 1 if access allowed, 0 if not. + +int +valid_socket(object, string, mixed *) +{ + return 1; +} + +// Write and Read privileges: +// +// valid_write: called with the file name, the object initiating the call, +// and the function by which they called it. +// return: 1 if access allowed, 0 if access not allowed. + +int +valid_write(string, mixed, string) +{ + return 1; +} + +// valid_read: called exactly the same as valid_write() + +int +valid_read(string, mixed, string) +{ + return 1; +} + private int y = 1; diff --git a/fluffos-2.23-ds03/testsuite/inherit/readme b/fluffos-2.23-ds03/testsuite/inherit/readme new file mode 100644 index 0000000..216876f --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/inherit/readme @@ -0,0 +1,2 @@ +This directory contains files that are typically inherited (rather than +cloned). diff --git a/fluffos-2.23-ds03/testsuite/inherit/tests.c b/fluffos-2.23-ds03/testsuite/inherit/tests.c new file mode 100644 index 0000000..24c8869 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/inherit/tests.c @@ -0,0 +1,13 @@ +string test_desc; + +void +describe_test(string desc) +{ + test_desc = desc; +} + +string +query_test_info() +{ + return test_desc; +} diff --git a/fluffos-2.23-ds03/testsuite/log/author_stats b/fluffos-2.23-ds03/testsuite/log/author_stats new file mode 100644 index 0000000..9afd74b --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/log/author_stats @@ -0,0 +1,2 @@ +Root 0 0 +NONAME 0 0 diff --git a/fluffos-2.23-ds03/testsuite/log/domain_stats b/fluffos-2.23-ds03/testsuite/log/domain_stats new file mode 100644 index 0000000..f8bc232 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/log/domain_stats @@ -0,0 +1,4 @@ +Root 0 0 +Backbone 0 0 +BACKBONE 0 0 +NONAME 0 0 diff --git a/fluffos-2.23-ds03/testsuite/log/readme b/fluffos-2.23-ds03/testsuite/log/readme new file mode 100644 index 0000000..f2dd1ed --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/log/readme @@ -0,0 +1 @@ +This directory contains logfiles produced by the mudlib and the driver. diff --git a/fluffos-2.23-ds03/testsuite/readme b/fluffos-2.23-ds03/testsuite/readme new file mode 100644 index 0000000..f2ce886 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/readme @@ -0,0 +1,29 @@ +This directory contains a version of the Lil mudlib with additional code +added to provide a testsuite for MudOS. Currently the testsuite is small +but hopefully it will grow with time (assuming the MudOS developers add +to it). The efun tests are in the ./single/efuns directory with one efun +tested per file (named after the efun). Each efun test should attempt to tell +all (each case/branch) of the driver code that implements that particular +efun. In addition, the efun tests should attempt to fully test the +functionality of the efun (including boundary conditions). Eventually, +tests will be added that ensure all of the eoperators are tested as well. +Currently the only way setup to invoke the tests is to login to Lil +and type 'efun efun_name' e.g. 'efun capitalize'. Eventually there will +be a way to invoke the tests in batch mode via the driver's -f flag. + +-- + +This directory contains a very minimal mudlib named Lil intended for use in +bootstrapping a mudlib to be built from scratch. Anyone who has attempted +to build a mudlib from the ground up knows that the most painful part is +getting the mudlib to the point where the driver will boot up and accept +logins. After this point, its much easier to debug objects because the +driver is actually available to compile the objects and provide feedback +about what might be wrong! Lil is provided to allow that first painful +step to be avoided (useful learning experience though it may be). Also, +we felt that providing a driver that won't run out of the box (and it won't +run without a mudlib) is a bit silly. Yet we didn't want to provide a full +mudlib because we'd rather see many different mudlibs rather than just +variations on a single mudlib (also, there are several complete +MudOS mudlibs available and there isn't any good way to choose which +one we would include). diff --git a/fluffos-2.23-ds03/testsuite/single/inh.c b/fluffos-2.23-ds03/testsuite/single/inh.c new file mode 100644 index 0000000..0516ea6 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/inh.c @@ -0,0 +1,2 @@ +void ifun() { +} diff --git a/fluffos-2.23-ds03/testsuite/single/master.c b/fluffos-2.23-ds03/testsuite/single/master.c new file mode 100644 index 0000000..e4ee921 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/master.c @@ -0,0 +1,278 @@ +// file: /daemon/master.c + +#include + +// /inherit/master/valid.c contains all the valid_* functions +inherit "/inherit/master/valid"; + +void flag(string str) { + switch (str) { + case "test": + "/command/tests"->main(); + break; + case "sprintf": + { + string foo = "This is a test.\n"; + string bar = "Of the sprintf benchmark system.\n"; + string bazz = "This is only a test.\n"; + + for (int i = 0; i < 10000; i++) { + sprintf("Let's see if %20|s this is any %-100s faster than the %20i old way.%s", foo, bar, 42, bazz); + } + shutdown(); + break; + } + default: + write("Unknown flag.\n"); + } + shutdown(); +} + +object +connect() +{ + object login_ob; + mixed err; + + err = catch(login_ob = new(LOGIN_OB)); + + if (err) { + write("It looks like someone is working on the player object.\n"); + write(err); + destruct(this_object()); + } + return login_ob; +} + +// compile_object: This is used for loading MudOS "virtual" objects. +// It should return the object the mudlib wishes to associate with the +// filename named by 'file'. It should return 0 if no object is to be +// associated. + +mixed +compile_object(string file) +{ +// return (mixed)VIRTUAL_D->compile_object(file); + return 0; +} + +// This is called when there is a driver segmentation fault or a bus error, +// etc. As it's static it can't be called by anything but the driver (and +// master). + +staticf void +crash(string, object, object) +{ + error("foo\n"); + foreach (object ob in users()) + tell_object(ob, "Master object shouts: Damn!\nMaster object tells you: The game is crashing.\n"); +#if 0 + log_file("crashes", MUD_NAME + " crashed on: " + ctime(time()) + + ", error: " + error + "\n"); + if (command_giver) { + log_file("crashes", "this_player: " + file_name(command_giver) + "\n"); + } + if (current_object) { + log_file("crashes", "this_object: " + file_name(current_object) + "\n"); + } +#endif +} + +// Function name: update_file +// Description: reads in a file, ignoring lines that begin with '#' +// Arguements: file: a string that shows what file to read in. +// Return: Array of nonblank lines that don't begin with '#' +// Note: must be declared static (else a security hole) + +staticf string * +update_file(string file) +{ + string *arr; + string str; + int i; + + str = read_file(file); + if (!str) { + return ({}); + } + arr = explode(str, "\n"); + for (i = 0; i < sizeof(arr); i++) { + if (arr[i][0] == '#') { + arr[i] = 0; + } + } + return arr; +} + +// Function name: epilog +// Return: List of files to preload + +string * +epilog(int) +{ + string *items; + + items = update_file(CONFIG_DIR + "/preload"); + return items; +} + +// preload an object + +void +preload(string file) +{ + int t1; + string err; + + if (file_size(file + ".c") == -1) + return; + + t1 = time(); + write("Preloading : " + file + "..."); + err = catch(call_other(file, "??")); + if (err != 0) { + write("\nError " + err + " when loading " + file + "\n"); + } else { + t1 = time() - t1; + write("(" + t1/60 + "." + t1 % 60 + ")\n"); + } +} + +// Write an error message into a log file. The error occured in the object +// 'file', giving the error message 'message'. + +void +log_error(string, string message) +{ + write_file(LOG_DIR + "/compile", message); +} + +// save_ed_setup and restore_ed_setup are called by the ed to maintain +// individual options settings. These functions are located in the master +// object so that the local admins can decide what strategy they want to use. + +int +save_ed_setup(object who, int code) +{ + string file; + + if (!intp(code)) { + return 0; + } +#ifdef __PACKAGE_UIDS__ + file = user_path(getuid(who)) + ".edrc"; +#else + file = "/.edrc"; +#endif + rm(file); + return write_file(file, code + ""); +} + +// Retrieve the ed setup. No meaning to defend this file read from +// unauthorized access. + +int +retrieve_ed_setup(object who) +{ + string file; + int code; + +#ifdef __PACKAGE_UIDS__ + file = user_path(getuid(who)) + ".edrc"; +#else + file = "/.edrc"; +#endif + if (file_size(file) <= 0) { + return 0; + } + sscanf(read_file(file), "%d", code); + return code; +} + +// When an object is destructed, this function is called with every +// item in that room. We get the chance to save users from being destructed. + +void +destruct_environment_of(object ob) +{ + if (!interactive(ob)) { + return; + } + tell_object(ob, "The object containing you was dested.\n"); + ob->move(VOID_OB); +} + +// make_path_absolute: This is called by the driver to resolve path names in ed. + +string +make_path_absolute(string file) +{ + file = resolve_path((string)this_player()->query_cwd(), file); + return file; +} + +string +get_root_uid() +{ + return ROOT_UID; +} + +string +get_bb_uid() +{ + return BACKBONE_UID; +} + +string +creator_file(string str) +{ + return (string)call_other(SINGLE_DIR + "/simul_efun", "creator_file", str); +} + +string +domain_file(string str) +{ + return (string)call_other(SINGLE_DIR + "/simul_efun", "domain_file", str); +} + +string +author_file(string str) +{ + return (string)call_other(SINGLE_DIR + "/simul_efun", "author_file", str); +} + +string privs_file(string f) { + return f; +} + +staticf void error_handler(mapping map, int flag) { + object ob; + string str; + + ob = this_interactive() || this_player(); + if (flag) str = "*Error caught\n"; + else str = ""; + str += sprintf("Error: %s\nCurrent object: %O\nCurrent program: %s\nFile: %O Line: %d\n%O\n", + map["error"], (map["object"] || "No current object"), + (map["program"] || "No current program"), + map["file"], map["line"], + implode(map_array(map["trace"], + (: sprintf("Line: %O File: %O Object: %O Program: %O", $1["line"], $1["file"], $1["object"] || "No object", $1["program"] || + "No program") :)), "\n")); + write_file("/log/log", str); + if (!flag && ob) tell_object(ob, str); +} + +int valid_bind() { + // This is really unsafe, but testsuite uses it to test bind() + return 1; +} + +int valid_hide() { + // same here + return 1; +} + +int valid_compile_to_c() { + return 1; +} diff --git a/fluffos-2.23-ds03/testsuite/single/readme b/fluffos-2.23-ds03/testsuite/single/readme new file mode 100644 index 0000000..bc07e16 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/readme @@ -0,0 +1,3 @@ +This directory is for objects that are intended to only have a _single_ +instance (no clones) yet are not typically inherited. This sort of object +includes what are sometimes known as daemons. diff --git a/fluffos-2.23-ds03/testsuite/single/simul_efun.c b/fluffos-2.23-ds03/testsuite/single/simul_efun.c new file mode 100644 index 0000000..d614f80 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/simul_efun.c @@ -0,0 +1,210 @@ +// mudlib: Lil +// file: /single/simul_efun.c + +#pragma show_error_context +#include +#include + +int +same(mixed x, mixed y) { + if (typeof(x) != typeof(y)) return 0; + switch (typeof(x)) { + case INT: + case STRING: + case OBJECT: + case FLOAT: + return x == y; + case MAPPING: + if (x == y) return 1; // speed up this case + if (sizeof(x) != sizeof(y)) return 0; + if (!same(keys(x), keys(y))) return 0; + if (!same(values(x), values(y))) return 0; + return 1; + case ARRAY: + if (x == y) return 1; // speed up this case + if (sizeof(x) != sizeof(y)) return 0; + for (int i = 0; i < sizeof(x); i++) { + if (!same(x[i], y[i])) return 0; + } + return 1; + case BUFFER: + case FUNCTION: + case CLASS: + error("Not implemented."); + } +} + +void +cat(string file) +{ + write(read_file(file)); +} + +varargs int +getoid(object ob) +{ + int id; + + sscanf(file_name(ob || previous_object()), "%*s#%d", id); + return id; +} + +string +user_cwd(string name) +{ + return ("/u/" + name[0..0] + "/" + name); +} + +string user_path(string name) +{ + return (user_cwd(name) + "/"); +} + +// Get the owner of a file. Used by log_error() in master.c. + +string +file_owner(string file) +{ + string temp; + + if (file[0] != '/') file = "/" + file; + + if (sscanf(file, "/u/%s/%s/%*s", temp, temp) == 2) { + return temp; + } + return 0; +} + +#include + +// dump_variable, author: Huthar@Portals, TMI +// - returns a printable representation of any variable. +// Changed by Symmetry@IdeaExchange, Tmi-2 5/4/95 +// - the format is retained +// Beek - changed to use foreach() +string +dump_variable(mixed arg) +{ + string rtn; + mixed x, y; + + switch(typeof(arg)) { + case OBJECT: return "("+file_name(arg)+")"; + case STRING: return "\""+arg+"\""; + case INT: return "#"+arg; + case ARRAY: + { + rtn = "ARRAY\n"; + foreach (y in arg) + rtn += sprintf("[%d] == %s\n", x++, dump_variable(y)); + + return rtn; + } + + case MAPPING: + { + rtn = "MAPPING\n" + + implode(values(map_mapping(arg, + (: sprintf("[%s] == %s", $1, $2) :))), "\n"); + return rtn; + } + + case FUNCTION: + case CLASS: + case FLOAT: + case BUFFER: + { + return sprintf("%O\n", arg); + } + + return "UNKNOWN"; + } +} + +/* +// Thanks to Huthar for resolve_path. +// Rewrite by Symmetry 5/4/95 +*/ + +string resolve_path(string curr, string newer) { + int i, j, size; + string *tmp; + + switch(newer) { + case 0: + case ".": + return curr; + +#ifndef __NO_ENVIRONMENT__ + case "here": + return file_name(environment())+".c"; +#endif + + default: + if (newer[0..1] == "~/") newer = user_path((string)this_player()->query_name()) + newer[2..]; + else { + switch(newer[0]) { + case '~': + { + i = strsrch(newer, '/'); + if (i < 0) newer = user_path(newer[1..]); + else newer = user_path(newer[1..i-1]) + newer[i..]; + break; + } + case '/': break; + default: newer[<0..<1] = curr + "/"; + } + } + + if (newer[<1] != '/') newer += "/"; + size = sizeof(tmp = regexp(explode(newer, "/"), ".")); + + i = j = 0; + + while (i < size) { + switch(tmp[i]) { + case "..": + if (j) { + while (j-- && !tmp[j]); + if (j >= 0) tmp[j] = 0; + else j++; + } + case ".": + tmp[i++] = 0; + break; + + default: + j = ++i; + break; + } + } + return "/"+implode(tmp, "/"); + } +} + + +// domain_file should return the domain associated with a given file. + +string +domain_file(string) +{ + return ROOT_UID; +} + +// creator_file should return the name of the creator of a specific file. + +string +creator_file(string) +{ + return ROOT_UID; +} + +// author_file should return the name of the author of a specific file. + +string +author_file(string) +{ + return ROOT_UID; +} + +void simul() {} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/at_block.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/at_block.c new file mode 100644 index 0000000..b75ab10 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/at_block.c @@ -0,0 +1,13 @@ +void do_tests() { + mixed *a; + string s = @END +xxx +yyy +END; + ASSERT( s == "xxx\nyyy\n"); + a = @@END +xxx +yyy +END; + ASSERT(sizeof(a) == 2); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/constant_expr.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/constant_expr.c new file mode 100644 index 0000000..849859e --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/constant_expr.c @@ -0,0 +1,37 @@ +void do_tests() { + mixed code; + + // array constants + code = __TREE__ ( sizeof( ({ 1, 3, 3 }) ) ); + ASSERT(same(code, ({ "number", 3 }))); + + code = __TREE__ ( ({ 1, 3, 3 })[0] ); + ASSERT(same(code, ({ "number", 1 }))); + + code = __TREE__ ( ({ 1, 4, 9 })[<2] ); + ASSERT(same(code, ({ "number", 4 }))); + + code = __TREE__ { int i; for (; i < 5; i++) ; }; + ASSERT(same(code, ({ + "two values", 0, ({ + "loop", 1, 0, ({ + "opcode_2", "loop_cond_number", 1, 5 + }), ({ + "opcode_1", "loop_incr", 1 + }) }) }) )); + + code = __TREE__( !code ? 1 : 2 ); + ASSERT(same(code, ({ + "if", ({ + "number", 2 + }), ({ + "number", 1 + }), ({ + "opcode_1", "local", 0 + }) }) )); + + ASSERT(5/3 == 1); + ASSERT(1/8.0 == 0.125); + ASSERT(1.0/2 == 0.5); + ASSERT(1.0/2.0 == 0.5); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/arr_index.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/arr_index.c new file mode 100644 index 0000000..e0725a2 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/arr_index.c @@ -0,0 +1,3 @@ +void foo { + ({ })[1]; +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_break.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_break.c new file mode 100644 index 0000000..bd76424 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_break.c @@ -0,0 +1,3 @@ +void foo() { + break; +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_continue.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_continue.c new file mode 100644 index 0000000..27ba518 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_continue.c @@ -0,0 +1,3 @@ +void foo() { + continue; +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_for_init.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_for_init.c new file mode 100644 index 0000000..8947fc7 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_for_init.c @@ -0,0 +1,4 @@ +void foo() { + for (int x += 1; ; ) ; +} + diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_foreach.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_foreach.c new file mode 100644 index 0000000..cee77b2 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_foreach.c @@ -0,0 +1,3 @@ +void foo() { + foreach (x in ({})) ; +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_init.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_init.c new file mode 100644 index 0000000..b165a42 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_init.c @@ -0,0 +1 @@ +int x += 1; diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_local_init.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_local_init.c new file mode 100644 index 0000000..cf39bc9 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_local_init.c @@ -0,0 +1,3 @@ +void foo() { + int x += 1; +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_local_init2.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_local_init2.c new file mode 100644 index 0000000..ed36217 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_local_init2.c @@ -0,0 +1,5 @@ +TYPETEST + +void foo() { + int x = "hi"; +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_param.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_param.c new file mode 100644 index 0000000..bfd2339 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_param.c @@ -0,0 +1,3 @@ +void foo() { + (: $-1 :); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_param2.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_param2.c new file mode 100644 index 0000000..d631844 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_param2.c @@ -0,0 +1,3 @@ +void foo() { + (: $1000 :); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_return.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_return.c new file mode 100644 index 0000000..d4300ab --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_return.c @@ -0,0 +1,5 @@ +TYPETEST + +void foo() { + return 1; +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_return2.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_return2.c new file mode 100644 index 0000000..a779ba4 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_return2.c @@ -0,0 +1,5 @@ +TYPETEST + +int foo() { + return "hi"; +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_type_init.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_type_init.c new file mode 100644 index 0000000..8b3a4f4 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/bad_type_init.c @@ -0,0 +1,3 @@ +TYPETEST + +int x = "hi"; diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/class_redef.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/class_redef.c new file mode 100644 index 0000000..d0ae46c --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/class_redef.c @@ -0,0 +1,7 @@ +class foo { + int x; +} + +class foo { + string y; +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/div_zero.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/div_zero.c new file mode 100644 index 0000000..9496bd1 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/div_zero.c @@ -0,0 +1,5 @@ +void foo(mixed x) { + switch(x) { + case 1 / 0: + } +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/div_zero3.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/div_zero3.c new file mode 100644 index 0000000..2b4ac14 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/div_zero3.c @@ -0,0 +1,3 @@ +int foo() { + return 1/0.0; +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/eof_in_comment.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/eof_in_comment.c new file mode 100644 index 0000000..33662f5 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/eof_in_comment.c @@ -0,0 +1 @@ +/* diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/eof_in_string.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/eof_in_string.c new file mode 100644 index 0000000..e412188 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/eof_in_string.c @@ -0,0 +1,3 @@ +void create() { + " +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/local_redef.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/local_redef.c new file mode 100644 index 0000000..c0d1f4e --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/local_redef.c @@ -0,0 +1,3 @@ +void foo(int x) { + int x; +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/local_redef2.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/local_redef2.c new file mode 100644 index 0000000..c091fb4 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/local_redef2.c @@ -0,0 +1,6 @@ +void foo() { + int x; + { + int x; + } +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/lvar_func.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/lvar_func.c new file mode 100644 index 0000000..b52b411 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/lvar_func.c @@ -0,0 +1,4 @@ +void foo() { + int x; + (: x :); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/lvar_func2.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/lvar_func2.c new file mode 100644 index 0000000..c29c4d0 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/lvar_func2.c @@ -0,0 +1,4 @@ +void foo() { + int x; + (: x + 1 :); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/missing_endif.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/missing_endif.c new file mode 100644 index 0000000..c2d4457 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/missing_endif.c @@ -0,0 +1 @@ +#if 1 diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/missing_type.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/missing_type.c new file mode 100644 index 0000000..e901f01 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/missing_type.c @@ -0,0 +1 @@ +foo; diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/mixed_case.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/mixed_case.c new file mode 100644 index 0000000..0701a61 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/mixed_case.c @@ -0,0 +1,6 @@ +void foo(mixed x) { + switch (x) { + case 1: + case "hi": + } +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/mod_zero.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/mod_zero.c new file mode 100644 index 0000000..2c05774 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/mod_zero.c @@ -0,0 +1,5 @@ +void foo(mixed x) { + switch(x) { + case 1 % 0: + } +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/no_member.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/no_member.c new file mode 100644 index 0000000..d2cd5fd --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/no_member.c @@ -0,0 +1,8 @@ +class foo { + int x; +} + +void foo() { + foo y; + y->z; +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/no_ret_type.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/no_ret_type.c new file mode 100644 index 0000000..5dd32b4 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/no_ret_type.c @@ -0,0 +1,4 @@ +#pragma strict_types + +foo() { +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/no_such_class.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/no_such_class.c new file mode 100644 index 0000000..5c7b4d1 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/no_such_class.c @@ -0,0 +1,3 @@ +void foo() { + new(class foo); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/predef.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/predef.c new file mode 100644 index 0000000..846781f --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/predef.c @@ -0,0 +1 @@ +#undef __VERSION__ diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/redef_function.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/redef_function.c new file mode 100644 index 0000000..97c7631 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/redef_function.c @@ -0,0 +1,5 @@ +void foo() { +} + +void foo() { +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/static_local.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/static_local.c new file mode 100644 index 0000000..faa924e --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/static_local.c @@ -0,0 +1,3 @@ +void main() { + static int x = 5; +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/string_case.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/string_case.c new file mode 100644 index 0000000..9fd07e7 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/string_case.c @@ -0,0 +1,5 @@ +void foo() { + switch ("hi") { + case "foo".."bar": + } +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/two_default.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/two_default.c new file mode 100644 index 0000000..2983cbf --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/two_default.c @@ -0,0 +1,6 @@ +void foo() { + switch (1) { + default: + default: + } +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/undef_class.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/undef_class.c new file mode 100644 index 0000000..8c4a00a --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/undef_class.c @@ -0,0 +1 @@ +class foo x; diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/var_to_nonvar.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/var_to_nonvar.c new file mode 100644 index 0000000..ae8d827 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/var_to_nonvar.c @@ -0,0 +1,8 @@ +TYPETEST + +void foo(int x) { +} + +void bar() { + foo( ({ })...); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/void_arg.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/void_arg.c new file mode 100644 index 0000000..0b2274d --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/void_arg.c @@ -0,0 +1,2 @@ +void foo(void x) { +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/void_arg2.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/void_arg2.c new file mode 100644 index 0000000..01e036c --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/void_arg2.c @@ -0,0 +1 @@ +void foo(void, int bar); diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/void_for_var.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/void_for_var.c new file mode 100644 index 0000000..2deaae4 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/void_for_var.c @@ -0,0 +1,3 @@ +void foo() { + for (void x = 1; ; ) ; +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/void_global.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/void_global.c new file mode 100644 index 0000000..a058b12 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/void_global.c @@ -0,0 +1 @@ +void x; diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/void_local.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/void_local.c new file mode 100644 index 0000000..fc0e1c0 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/void_local.c @@ -0,0 +1,3 @@ +void foo() { + void x; +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/void_member.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/void_member.c new file mode 100644 index 0000000..3013fea --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/fail/void_member.c @@ -0,0 +1,3 @@ +class foo { + void x; +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/compiler/succeed.c b/fluffos-2.23-ds03/testsuite/single/tests/compiler/succeed.c new file mode 100644 index 0000000..fb1a189 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/compiler/succeed.c @@ -0,0 +1,24 @@ +#pragma no_strict_types +foo() { } +bar(x) { } +#pragma strict_types +create() { } + +void foo(int); + +; // only a warning + +int ident; +#define X1 id +#define X2 ent +int paste = X1##X2; +string x = @END +xxx +END; +string * y = @@END +xxx +yyy +zzz +END +; + diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/add_action.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/add_action.c new file mode 100644 index 0000000..525a688 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/add_action.c @@ -0,0 +1,18 @@ +int called; +int xverb; + +void do_tests() { +#ifndef __NO_ADD_ACTION__ + object tp; + xverb = called = 0; + SAVETP; + enable_commands(); + add_action( (: called = 1 :), "foo"); + add_action( (: xverb = 1 :), "b", 1); + RESTORETP; + command("foo"); + command("bar"); + ASSERT(called); + ASSERT(xverb); +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/add_light.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/add_light.c new file mode 100644 index 0000000..bdccf76 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/add_light.c @@ -0,0 +1,3 @@ +void do_tests() { + +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/all_inventory.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/all_inventory.c new file mode 100644 index 0000000..62abb5b --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/all_inventory.c @@ -0,0 +1,30 @@ +void do_tests() { +#ifndef __NO_ENVIRONMENT__ + int s = sizeof(all_inventory(this_object())); + + ASSERT(sizeof(all_inventory()) == s); + + for (int i = 0; i < 5; i++) { + ASSERT(sizeof(all_inventory()) == s + i); + clone_object(file_name()); + } + ASSERT(filter(all_inventory(this_object()), (: !$1->is_all_inv_test() :))); +#endif +} + +int is_all_inv_test() { + return 1; +} + +void +create() { +#ifndef __NO_ENVIRONMENT__ + if (clonep()) { + string s = file_name(); + sscanf(s, "%s#%*d", s); + move_object(s); + } +#endif +} + + diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/allocate.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/allocate.c new file mode 100644 index 0000000..7e690db --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/allocate.c @@ -0,0 +1,8 @@ +void do_tests() { + for (int i = 0; i < 10; i++) { + ASSERT(sizeof(allocate(i)) == i); + ASSERT(filter(allocate(i), (: $1 :)) == ({})); + } + ASSERT(allocate(0) == ({})); + ASSERT(catch(allocate(-10))); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/allocate_buffer.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/allocate_buffer.c new file mode 100644 index 0000000..c518b23 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/allocate_buffer.c @@ -0,0 +1,9 @@ +void do_tests() { +#ifndef __NO_BUFFER_TYPE__ + int i = random(100000); + + ASSERT(sizeof(allocate_buffer(i)) == i); + ASSERT(catch(allocate_buffer(-20))); +#endif +} + diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/allocate_mapping.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/allocate_mapping.c new file mode 100644 index 0000000..d0afe5f --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/allocate_mapping.c @@ -0,0 +1,8 @@ +void do_tests() { + mapping m = allocate_mapping(random(1000)); + mixed x, y; + + foreach (x, y in m) { + ASSERT(0); // shouldn't get here + } +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/badshad.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/badshad.c new file mode 100644 index 0000000..2233fab --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/badshad.c @@ -0,0 +1,11 @@ +void create(int arg) { + if (arg) { +#ifndef __NO_SHADOWS__ + ASSERT(catch(shadow(previous_object()))); + destruct(this_object()); +#endif + } +} + +void i_am_bad() { +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/bind.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/bind.c new file mode 100644 index 0000000..9443451 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/bind.c @@ -0,0 +1,14 @@ +int glob; + +#define CANT_BIND(f) ASSERT(catch(bind(f, previous_object()))) +#define CAN_BIND(f) ASSERT(bind(f, previous_object())) + +void do_tests() { + CANT_BIND((: do_tests :)); + CANT_BIND((: glob :)); + CANT_BIND((: glob + 1 :)); + CANT_BIND((: do_tests() :)); + CAN_BIND((: $1 + $2 :)); + ASSERT(functionp(bind( (: $1 :), this_object()))); + ASSERT(evaluate(bind( (: $1 + $2 :), this_object()), 3, 4) == 7); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/break_string.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/break_string.c new file mode 100644 index 0000000..d390f9e --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/break_string.c @@ -0,0 +1,3 @@ +void do_tests() { + /* tests later */ +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/cache_stats.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/cache_stats.c new file mode 100644 index 0000000..5d02f94 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/cache_stats.c @@ -0,0 +1,5 @@ +void do_tests() { +#ifdef __CACHE_STATS__ + ASSERT(stringp(cache_stats())); +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/call_other.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/call_other.c new file mode 100644 index 0000000..522151d --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/call_other.c @@ -0,0 +1,26 @@ +int foo() { return 1; } + +int same(mixed *x, mixed *y) { + for (int i = 0; i < sizeof(x); i++) { + return x[i] == y[i]; + } +} + +int bar(int x) { + return x; +} + +void do_tests() { + ASSERT(file_name()->foo()); + ASSERT(this_object()->foo()); + ASSERT(same((mixed *)({ file_name(), this_object() })->foo(), ({ 1, 1 }))); + + ASSERT(catch(call_other(this_object(), 0))); + ASSERT(call_other(this_object(), "foo")); + ASSERT(call_other(this_object(), ({ "foo", 1 }))); + ASSERT(catch(call_other("foadf", "foo"))); + + ASSERT(undefinedp(this_object()->bazz())); + destruct(this_object()); + ASSERT(undefinedp("/single/master"->valid_bind())); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/call_out.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/call_out.c new file mode 100644 index 0000000..f1dc9b9 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/call_out.c @@ -0,0 +1,51 @@ +object tp; +#ifdef __THIS_PLAYER_IN_CALL_OUT__ +#define TPIC ASSERT(this_player() == tp) +#else +#define TPIC +#endif + +int called; + +void no_args() { + called++; + TPIC; +} + +void one_arg(int x) { + called++; + TPIC; + ASSERT(x == 1); +} + +void two_arg(int x, int y) { + called++; + TPIC; + ASSERT(x == 1); + ASSERT(y == 2); +} + +void finish() { + ASSERT(called == 6); +} + +void do_tests() { + mixed calls, call; + + tp = this_player(); + called = 0; + call_out( (: no_args :), 1); + call_out( "no_args", 2); + call_out( (: one_arg, 1 :), 3); + call_out( "one_arg", 4, 1); + call_out( (: two_arg, 1 :), 5, 2); + call_out( "two_arg", 6, 1, 2); + call_out( "finish", 10); + + calls = call_out_info(); + foreach(call in calls) { + ASSERT(objectp(call[0])); + ASSERT(stringp(call[1])); + ASSERT(intp(call[2])); + } +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/call_stack.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/call_stack.c new file mode 100644 index 0000000..63dbf3c --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/call_stack.c @@ -0,0 +1,20 @@ +void do_tests() { + mixed stack, entry; + int n = sizeof(call_stack(0)); + + stack = call_stack(0); + ASSERT(stack[0] == __FILE__); + ASSERT(sizeof(filter(stack, (: stringp :))) == n); + stack = call_stack(1); + ASSERT(stack[0] == this_object()); + ASSERT(sizeof(filter(stack, (: objectp :))) == n); + stack = call_stack(2); + ASSERT(stack[0] == "do_tests"); + ASSERT(sizeof(filter(stack, (: stringp :))) == n); + stack = call_stack(3); + ASSERT(sizeof(filter(stack, (: stringp :))) == n); + ASSERT(catch(call_stack(-100))); + ASSERT(catch(call_stack(4))); +} + + diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/capitalize.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/capitalize.c new file mode 100644 index 0000000..05215da --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/capitalize.c @@ -0,0 +1,33 @@ +/* + efun: string capitalize(string); + test author: John Garnett + date: 1993 November 2 +*/ + +void do_tests() +{ + string str1, str2, str3; + + str1 = ""; + str2 = capitalize(str1); + str3 = ""; + ASSERT(str2 == str3); + + str1 = "driver"; + str2 = capitalize(str1); + str3 = "Driver"; + ASSERT(str2 == str3); + ASSERT(str1 == "driver"); + + str1 = "Driver"; + str2 = capitalize(str1); + str3 = "Driver"; + ASSERT(str2 == str3); + ASSERT(str1 == "Driver"); + + str1 = "42driver"; + str2 = capitalize(str1); + str3 = "42driver"; + ASSERT(str2 == str3); + ASSERT(str1 == "42driver"); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/children.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/children.c new file mode 100644 index 0000000..4d98903 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/children.c @@ -0,0 +1,13 @@ +void do_tests() { + object x; + + foreach (x in children(__FILE__)) + if (x != this_object()) destruct(x); + + for (int i = 0; i < 5; i++) + new(__FILE__); + + ASSERT(sizeof(children(__FILE__)) == 6); +} + + diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/clear_bit.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/clear_bit.c new file mode 100644 index 0000000..798d8c1 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/clear_bit.c @@ -0,0 +1,15 @@ +void do_tests() { + string str; + + ASSERT(catch(clear_bit("", 1000000000000))); + ASSERT(catch(clear_bit("", -2))); + + str = "11111"; + str = clear_bit(str, 7); + ASSERT(!test_bit(str, 7)); + str = clear_bit(set_bit(str, 12), 12); + ASSERT(!test_bit(str, 7)); + + ASSERT(str == clear_bit(str, 40)); +} + diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/clone_object.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/clone_object.c new file mode 100644 index 0000000..ac44b25 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/clone_object.c @@ -0,0 +1,21 @@ +string my_arg; + +string get_arg() { + return my_arg; +} + +void create(string arg) { + my_arg = arg; +} + +void do_tests() { + object ob; +#ifdef __PACKAGE_UIDS__ + seteuid(0); + ASSERT(catch(new(__FILE__))); + seteuid(getuid(this_object())); +#endif + ASSERT(new(__FILE__)->get_arg() == 0); + ASSERT((string)new(__FILE__, "foo")->get_arg() == "foo"); +} + diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/clonep.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/clonep.c new file mode 100644 index 0000000..53a8489 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/clonep.c @@ -0,0 +1,7 @@ +void do_tests() { + ASSERT(!clonep()); + ASSERT(!clonep(this_object())); + ASSERT(clonep(new(__FILE__))); + ASSERT(!clonep( ({ 1, 2 }) )); + ASSERT(!clonep(1)); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/command.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/command.c new file mode 100644 index 0000000..670e469 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/command.c @@ -0,0 +1,29 @@ +int flag; + +int action() { + flag = 1; + return 1; +} + +void do_tests() { +#ifndef __NO_ADD_ACTION__ + object save_tp = this_player(); + mixed *comms; + + flag = 0; + enable_commands(); + add_action( (: action :), "foo"); + comms = commands(); + disable_commands(); + if (save_tp) + evaluate(bind( (: enable_commands :), save_tp)); + + ASSERT(command("foo")); + ASSERT(sizeof(comms) == 1); + ASSERT(comms[0][0] == "foo"); + ASSERT(comms[0][2] == this_object()); + ASSERT(comms[0][3] == ""); + ASSERT(flag); + destruct(this_object()); +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/cp.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/cp.c new file mode 100644 index 0000000..fdab6d6 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/cp.c @@ -0,0 +1,10 @@ +#define TESTFILE "/testfile" + +void do_tests() { + rm(TESTFILE); + ASSERT(file_size(TESTFILE) == -1); + ASSERT(cp("/single/master.c", TESTFILE)); + ASSERT(file_size(TESTFILE)); + ASSERT(read_file("/single/master.c") == read_file(TESTFILE)); +} + diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/crc32.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/crc32.c new file mode 100644 index 0000000..ed88cbe --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/crc32.c @@ -0,0 +1,5 @@ +void do_tests() { + ASSERT(catch(crc32(0))); + ASSERT(intp(crc32("foobarbazz"))); +} + diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/ctime.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/ctime.c new file mode 100644 index 0000000..b6917c5 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/ctime.c @@ -0,0 +1,5 @@ +void do_tests() { + string tm = ctime(0); + ASSERT(stringp(tm)); + ASSERT(strsrch(tm, '\n') == -1); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/deep_inherit_list.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/deep_inherit_list.c new file mode 100644 index 0000000..dedc960 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/deep_inherit_list.c @@ -0,0 +1,9 @@ +void do_tests() { + mixed *x; + + ASSERT(deep_inherit_list(this_object()) == ({ })); + x = deep_inherit_list(load_object("/single/tests/efuns/inh2.c")); + ASSERT(sizeof(x) == 2); + ASSERT(x[0] == "/single/tests/efuns/inh1.c"); + ASSERT(x[1] == "/single/tests/efuns/inh0.c"); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/deep_inventory.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/deep_inventory.c new file mode 100644 index 0000000..e65182c --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/deep_inventory.c @@ -0,0 +1,22 @@ +void do_tests() { +#ifndef __NO_ENVIRONMENT__ + object ob; + + foreach (ob in deep_inventory(this_object())) + if (ob) + destruct(ob); + new(__FILE__, this_object()); + new(__FILE__, this_object(), 1); + ASSERT(sizeof(deep_inventory(this_object())) == 4); +#endif +} + +void create(object ob, int flag) { +#ifndef __NO_ENVIRONMENT__ + if (ob) move_object(ob); + if (flag) { + new(__FILE__, this_object()); + new(__FILE__, this_object()); + } +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/destruct.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/destruct.c new file mode 100644 index 0000000..776a7b2 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/destruct.c @@ -0,0 +1,6 @@ +void do_tests() { + object ob = new(__FILE__); + ASSERT(ob); + destruct(ob); + ASSERT(!ob); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/disable_commands.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/disable_commands.c new file mode 100644 index 0000000..5eb8745 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/disable_commands.c @@ -0,0 +1,15 @@ +void do_tests() { +#ifndef __NO_ADD_ACTION__ + object save_tp = this_player(); + + disable_commands(); + ASSERT(!living(this_object())); + enable_commands(); + ASSERT(living(this_object())); + disable_commands(); + ASSERT(!living(this_object())); + + if (save_tp) + evaluate(bind( (: enable_commands :), save_tp)); +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/dumpallobj.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/dumpallobj.c new file mode 100644 index 0000000..bf8599d --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/dumpallobj.c @@ -0,0 +1,4 @@ +void do_tests() { + dumpallobj(); + dumpallobj("/OBJ_DUMP2"); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/ed.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/ed.c new file mode 100644 index 0000000..2655198 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/ed.c @@ -0,0 +1,13 @@ +void do_tests() { +#ifndef __OLD_ED__ + ASSERT(catch(ed_cmd("foo"))); + rm("/ed_test"); + write_file("/ed_test", "xyzzy\nxxx"); + ed_start("/ed_test"); + ASSERT(ed_cmd("1s/y/a/g")); + ASSERT(ed_cmd("2s!x!b!")); + ASSERT(catch(ed_start("foo"))); + ASSERT(ed_cmd("x")); + ASSERT(read_file("/ed_test") == "xazza\nbxx\n"); +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/enable_wizard.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/enable_wizard.c new file mode 100644 index 0000000..630af0d --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/enable_wizard.c @@ -0,0 +1,13 @@ +void do_tests() { +#ifndef __NO_WIZARDS__ + disable_wizard(); + ASSERT(!wizardp(this_object())); + enable_wizard(); // fails; not interactive + ASSERT(!wizardp(this_object())); + + evaluate(bind( (: disable_wizard :), this_player())); + ASSERT(!wizardp(this_player())); + evaluate(bind( (: enable_wizard :), this_player())); + ASSERT(wizardp(this_player())); +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/environment.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/environment.c new file mode 100644 index 0000000..3097637 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/environment.c @@ -0,0 +1,19 @@ +void do_tests() { +#ifndef __NO_ENVIRONMENT__ + object ob; + + ASSERT(environment() == 0); + ASSERT(environment(this_object()) == 0); + ob = new(__FILE__, 1); + ASSERT(environment(ob) == this_object()); +#endif +} + +void create(int flag) { +#ifndef __NO_ENVIRONMENT__ + if (flag) + move_object(previous_object()); +#endif +} + + diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/error.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/error.c new file mode 100644 index 0000000..ea2ffbf --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/error.c @@ -0,0 +1,4 @@ +void do_tests() { + ASSERT(catch(error("hi")) == "*hi\n"); + ASSERT(catch(error("hi\n")) == "*hi\n"); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/exec.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/exec.c new file mode 100644 index 0000000..04ad3e5 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/exec.c @@ -0,0 +1,10 @@ +void do_tests() { + object tp = this_player(); + + if (tp) { + ASSERT(exec(this_object(), tp)); + ASSERT(userp(this_object())); + ASSERT(exec(tp, this_object())); + } +} + diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/explode.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/explode.c new file mode 100644 index 0000000..64b3e77 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/explode.c @@ -0,0 +1,78 @@ +void do_tests() { + string tmp = "this is a test"; + mixed *ret; + + ret = explode(tmp, ""); + ASSERT(sizeof(ret) == sizeof(filter(ret, (: strlen($1) == 1 :)))); + ret = explode(tmp, " "); + ASSERT(sizeof(ret) == 4); + ASSERT(ret[1] == "is"); + ASSERT(ret[3] == "test"); + + ret = explode(" " + tmp, " "); +#ifndef __REVERSIBLE_EXPLODE_STRING__ + ASSERT(sizeof(ret) == 4); + ASSERT(ret[1] == "is"); + ASSERT(ret[3] == "test"); +#else + ASSERT(sizeof(ret) == 5); + ASSERT(ret[2] == "is"); + ASSERT(ret[4] == "test"); +#endif + + ret = explode(" " + tmp, " "); +#ifndef __REVERSIBLE_EXPLODE_STRING__ +#ifdef __SANE_EXPLODE_STRING__ + ASSERT(sizeof(ret) == 8); + ASSERT(ret[5] == "is"); + ASSERT(ret[7] == "test"); +#else + ASSERT(sizeof(ret) == 4); + ASSERT(ret[1] == "is"); + ASSERT(ret[3] == "test"); +#endif +#else + ASSERT(sizeof(ret) == 9); + ASSERT(ret[6] == "is"); + ASSERT(ret[8] == "test"); +#endif + + tmp = "this is a test "; + ret = explode(tmp, " "); +#ifndef __REVERSIBLE_EXPLODE_STRING__ + ASSERT(sizeof(ret) == 4); +#else + ASSERT(sizeof(ret) == 5); +#endif + ASSERT(ret[1] == "is"); + ASSERT(ret[3] == "test"); + + ret = explode(" " + tmp, " "); +#ifndef __REVERSIBLE_EXPLODE_STRING__ + ASSERT(sizeof(ret) == 4); + ASSERT(ret[1] == "is"); + ASSERT(ret[3] == "test"); +#else + ASSERT(sizeof(ret) == 6); + ASSERT(ret[2] == "is"); + ASSERT(ret[4] == "test"); +#endif + + ret = explode(" " + tmp, " "); +#ifndef __REVERSIBLE_EXPLODE_STRING__ +#ifdef __SANE_EXPLODE_STRING__ + ASSERT(sizeof(ret) == 6); + ASSERT(ret[3] == "is"); + ASSERT(ret[5] == "test"); +#else + ASSERT(sizeof(ret) == 4); + ASSERT(ret[1] == "is"); + ASSERT(ret[3] == "test"); +#endif +#else + ASSERT(sizeof(ret) == 8); + ASSERT(ret[4] == "is"); + ASSERT(ret[6] == "test"); +#endif + +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/file_name.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/file_name.c new file mode 100644 index 0000000..3daf62c --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/file_name.c @@ -0,0 +1,4 @@ +void do_tests() { + ASSERT(file_name() + ".c" == __FILE__); +} + diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/file_size.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/file_size.c new file mode 100644 index 0000000..bf5e2f6 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/file_size.c @@ -0,0 +1,6 @@ +void do_tests() { + string str = "This is a test"; + rm("/test_file"); + write_file("/test_file", str); + ASSERT(file_size("test_file") == strlen(str)); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/filter.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/filter.c new file mode 100644 index 0000000..e40c189 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/filter.c @@ -0,0 +1,69 @@ +int tmp = 0; + +int third() { + if (++tmp == 3) { + tmp = 0; + return 0; + } + return 1; +} + +int whatever1(mixed x, mixed y, mixed z) { + return x; +} + +int whatever2(mixed x, mixed y, mixed z) { + return y; +} + +int whatever3(mixed x, mixed y, mixed z) { + return z; +} + +int true() { return 1; } + +int same(mixed* x, mixed* y) { + if (sizeof(x) != sizeof(y)) return 0; + for (int i = 0; i < sizeof(x); i++) { + if (x[i] != y[i]) return 0; + } + return 1; +} + +int msame(mapping x, mapping y) { + mixed z; + if (sizeof(keys(x)) != sizeof(keys(y))) return 0; + foreach (z in keys(x)) { + if (x[z] != y[z]) return 0; + } + return 1; +} + +void do_tests() { + // array + ASSERT(same(filter( ({ 1, 2, 0, 3 }), (: $1 :)), ({ 1, 2, 3 }))); + ASSERT(filter( ({}), "foo") == ({})); + ASSERT(sizeof(filter( ({ 1 }), "true"))); + + ASSERT(same(filter( ({ 1,2,3,4,5,6,7,8,9 }), "third", this_object()) + , filter( ({ 1,2,3,4,5,6,7,8,9 }), (: third :)))); + + ASSERT(sizeof(filter( ({ 0 }), (: whatever1, 1 :)))); + ASSERT(sizeof(filter( ({ 0 }), "whatever2", this_object(), 1))); + ASSERT(sizeof(filter( ({ 0 }), (: whatever2 :), 1))); + ASSERT(sizeof(filter( ({ 0 }), "whatever2", __FILE__, 1))); + + // mapping + ASSERT(msame(filter( ([ 1 : 2, 0 : 3 ]), (: $1 :)), ([ 1 : 2 ]))); + ASSERT(msame(filter( ([]), "foo"), ([]))); + ASSERT(sizeof(filter( ([ 1 : 2 ]), "true"))); + + ASSERT(msame(filter( ([ 1:2,3:4,5:6 ]), "third", this_object()), + filter( ([ 1:2,3:4,5:6 ]), (: third :)))); + + ASSERT(!sizeof(filter( ([]), (: $1 :)))); + ASSERT(sizeof(filter( ([ 0 : 0 ]), (: whatever1, 1 :)))); + ASSERT(sizeof(filter( ([ 0 : 0 ]), "whatever3", this_object(), 1))); + ASSERT(sizeof(filter( ([ 0 : 0 ]), (: whatever3 :), 1))); + ASSERT(sizeof(filter( ([ 0 : 0 ]), "whatever3", __FILE__, 1))); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/find_call_out.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/find_call_out.c new file mode 100644 index 0000000..a539c36 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/find_call_out.c @@ -0,0 +1,6 @@ +void do_tests() { + ASSERT(find_call_out("foo") == -1); + call_out("foo", 10); + ASSERT(find_call_out("foo") == 10); + ASSERT(find_call_out("bar") == -1); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/find_living.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/find_living.c new file mode 100644 index 0000000..f8ec920 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/find_living.c @@ -0,0 +1,16 @@ +void do_tests() { +#ifndef __NO_ADD_ACTION__ + object ob; + object tp; + + ASSERT(!find_living("bar")); + SAVETP; + enable_commands(); + set_living_name("bar"); + ob = find_living("bar"); + disable_commands(); + RESTORETP; + ASSERT(ob == this_object()); + ASSERT(!find_living("bar")); +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/find_object.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/find_object.c new file mode 100644 index 0000000..9b75b77 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/find_object.c @@ -0,0 +1,15 @@ +void do_tests() { + object ob; + + ASSERT(find_object(__FILE__) == this_object()); + ob = find_object("/single/tests/efuns/unloaded"); + if (ob) + destruct(ob); + ASSERT(!find_object("/single/tests/efuns/unloaded")); + ASSERT(ob = find_object("/single/tests/efuns/unloaded", 1)); + ASSERT(file_name(ob) == "/single/tests/efuns/unloaded"); + destruct(ob); + ASSERT(ob = load_object("/single/tests/efuns/unloaded", 1)); + ASSERT(file_name(ob) == "/single/tests/efuns/unloaded"); + ASSERT(!load_object("/foo")); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/find_player.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/find_player.c new file mode 100644 index 0000000..9e18727 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/find_player.c @@ -0,0 +1,21 @@ +void do_tests() { +#ifndef __NO_ADD_ACTION__ + object tp; + object o1, o2; + + if (this_player()) { + ASSERT(!find_player("bar")); + SAVETP; + enable_commands(); + set_living_name("bar"); + o1 = find_player("bar"); + exec(this_object(), tp); + o2 = find_player("bar"); + exec(tp, this_object()); + disable_commands(); + RESTORETP; + ASSERT(!o1); + ASSERT(o2 == this_object()); + } +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/function_exists.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/function_exists.c new file mode 100644 index 0000000..aa1b893 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/function_exists.c @@ -0,0 +1,22 @@ +#ifndef __SENSIBLE_MODIFIERS__ +static +#else +protected +#endif +int stat() { +} + +private int priv() { +} + +void do_tests() { + ASSERT(function_exists("stat", this_object(), 1)); + ASSERT(function_exists("priv", this_object(), 1)); + + ASSERT(!function_exists("stat", this_object())); + ASSERT(!function_exists("priv", this_object())); + + ASSERT(!function_exists("bar", this_object())); + ASSERT(function_exists("do_tests", this_object()) + ".c" == __FILE__); +} + diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/function_profile.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/function_profile.c new file mode 100644 index 0000000..919a41f --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/function_profile.c @@ -0,0 +1,11 @@ +void do_tests() { +#ifdef __PROFILE_FUNCTIONS__ + mixed *hmm = function_profile(this_object()); + ASSERT(sizeof(hmm) == 1); + ASSERT(hmm[0]["calls"]); + ASSERT(!undefinedp(hmm[0]["self"])); + ASSERT(!undefinedp(hmm[0]["children"])); + ASSERT(hmm[0]["name"] == "do_tests"); +#endif +} + diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/functionp.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/functionp.c new file mode 100644 index 0000000..40c3c67 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/functionp.c @@ -0,0 +1,5 @@ +void do_tests() { + ASSERT(!functionp(0)); + ASSERT(!functionp("foo")); + ASSERT(functionp((: do_tests :))); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/generate_source.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/generate_source.c new file mode 100644 index 0000000..693f570 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/generate_source.c @@ -0,0 +1,3 @@ +void do_tests() { + // maybe later +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/get_char.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/get_char.c new file mode 100644 index 0000000..693f570 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/get_char.c @@ -0,0 +1,3 @@ +void do_tests() { + // maybe later +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/get_config.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/get_config.c new file mode 100644 index 0000000..5ff5071 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/get_config.c @@ -0,0 +1,4 @@ +void do_tests() { + ASSERT(get_config(0) == MUD_NAME); + ASSERT(catch(get_config(-1))); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/get_dir.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/get_dir.c new file mode 100644 index 0000000..26208d9 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/get_dir.c @@ -0,0 +1,3 @@ +void do_tests() { + // more later +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/goodshad.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/goodshad.c new file mode 100644 index 0000000..0cb34b6 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/goodshad.c @@ -0,0 +1,12 @@ +void create(int arg) { +#ifndef __NO_SHADOWS__ + if (arg) { + ASSERT(shadow(previous_object())); + ASSERT(catch(shadow(previous_object()))); + } +#endif +} + +object foo() { + return this_object(); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/has_errors.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/has_errors.c new file mode 100644 index 0000000..e69de29 diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/implode.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/implode.c new file mode 100644 index 0000000..1c36144 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/implode.c @@ -0,0 +1,14 @@ + +void do_tests() { + ASSERT(implode( ({ 1, 2, 3 }), "foo") == ""); + ASSERT(implode( ({ "foo", "bar" }), "bazz") == "foobazzbar"); + ASSERT(implode( ({ 1, "foo", "bar" }), "bazz") == "foobazzbar"); + ASSERT(implode( ({ "foo", "bar" }), "") == "foobar"); + + ASSERT(implode( ({ 1, 2, 3 }), (: $1 + $2 :)) == 6); + ASSERT(implode( ({ 1, 2, 3 }), (: $1 + $2 :), "") == "123"); + ASSERT(implode( ({}), (: $1 :), 666) == 666); + ASSERT(implode( ({}), (: $1 :)) == 0); + ASSERT(implode( ({ 555 }), (: $1 + 5 :)) == 555); +} + diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/in_edit.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/in_edit.c new file mode 100644 index 0000000..4bd94fb --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/in_edit.c @@ -0,0 +1,8 @@ +void do_tests() { +#ifndef __OLD_ED__ + ASSERT(!in_edit(this_object())); + ed_start("/ed_test"); + ASSERT(in_edit(this_object()) == "/ed_test"); + destruct(this_object()); +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/inh0.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/inh0.c new file mode 100644 index 0000000..e69de29 diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/inh1.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/inh1.c new file mode 100644 index 0000000..601d7d5 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/inh1.c @@ -0,0 +1 @@ +inherit "/single/tests/efuns/inh0.c"; diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/inh2.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/inh2.c new file mode 100644 index 0000000..cdf1e41 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/inh2.c @@ -0,0 +1 @@ +inherit "/single/tests/efuns/inh1.c"; diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/inherit_list.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/inherit_list.c new file mode 100644 index 0000000..0f6acfc --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/inherit_list.c @@ -0,0 +1,7 @@ +void do_tests() { + mixed *x; + ASSERT(inherit_list(this_object()) == ({})); + x = inherit_list(load_object("/single/tests/efuns/inh2.c")); + ASSERT(sizeof(x) == 1); + ASSERT(x[0] == "/single/tests/efuns/inh1.c"); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/inherits.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/inherits.c new file mode 100644 index 0000000..1692836 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/inherits.c @@ -0,0 +1,18 @@ +#define OB2 "/single/tests/efuns/inh2.c" +#define OB1 "/single/tests/efuns/inh1.c" +#define OB0 "/single/tests/efuns/inh0.c" + +void do_tests() { + object ob2 = load_object(OB2); + object ob1 = load_object(OB1); + object ob = load_object(OB0); + + ASSERT(inherits(OB1, ob2)); + ASSERT(inherits(OB0, ob2)); + ASSERT(inherits(OB0, ob1)); + + ASSERT(!inherits(OB2, ob1)); + ASSERT(!inherits(OB2, ob)); + ASSERT(!inherits(OB1, ob)); + ASSERT(!inherits("foo", ob)); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/input_to.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/input_to.c new file mode 100644 index 0000000..8c27471 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/input_to.c @@ -0,0 +1,8 @@ +void foo() {} + +void do_tests() { + // We can only set up one input_to, which makes this hard to test + // exhaustively + if (this_player()) + ASSERT(input_to((: foo, "bazz" :), 1, "bar")); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/interactive.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/interactive.c new file mode 100644 index 0000000..3f706d9 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/interactive.c @@ -0,0 +1,7 @@ +void do_tests() { + if (this_player()) + ASSERT(interactive(this_player())); + ASSERT(!interactive(this_object())); + ASSERT(sizeof(users()) == sizeof(filter(users(), (: interactive :)))); +} + diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/intp.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/intp.c new file mode 100644 index 0000000..5b89bad --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/intp.c @@ -0,0 +1,9 @@ +void do_tests() { + ASSERT(intp(5)); + ASSERT(intp(([])[0])); + ASSERT(!intp( ({}) )); + ASSERT(!intp(([]))); + ASSERT(!intp(this_object())); + destruct(this_object()); + ASSERT(intp(this_object())); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/keys.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/keys.c new file mode 100644 index 0000000..76bf4c7 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/keys.c @@ -0,0 +1,10 @@ +void do_tests() { + mapping m = ([ 1 : 2, 3 : 4, 5 : 6 ]); + mixed *k = keys(m); + mixed x, y; + + foreach (x, y in m) { + k -= ({ x }); + } + ASSERT(k == ({})); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/light.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/light.c new file mode 100644 index 0000000..c40d098 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/light.c @@ -0,0 +1,11 @@ +void create() { +#ifndef __NO_LIGHT__ + set_light(3); +#endif +} + +void move(object ob) { +#ifndef __NO_ENVIRONMENT__ + move_object(ob); +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/living.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/living.c new file mode 100644 index 0000000..4ee41dc --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/living.c @@ -0,0 +1,7 @@ +void do_tests() { +#ifndef __NO_ADD_ACTION__ + if (this_player()) + ASSERT(living(this_player())); + ASSERT(!living(this_object())); +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/livings.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/livings.c new file mode 100644 index 0000000..c6f7cc9 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/livings.c @@ -0,0 +1,7 @@ +void do_tests() { +#ifndef __NO_ADD_ACTION__ + ASSERT(!sizeof(filter(livings(), (: !living($1) :)))); + if (this_player()) + ASSERT(member_array(this_player(), livings()) != -1); +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/lower_case.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/lower_case.c new file mode 100644 index 0000000..dd7552f --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/lower_case.c @@ -0,0 +1,19 @@ +#define STR STR1 +#define STR1 "this is a test!" +#define STR2 "This is a test!" +#define STR3 "This is A tEst!" + +void do_tests() { + string str; + str = STR1; + ASSERT(lower_case(str) == STR); + ASSERT(str == STR1); + + str = STR2; + ASSERT(lower_case(str) == STR); + ASSERT(str == STR2); + + str = STR3; + ASSERT(lower_case(str) == STR); + ASSERT(str == STR3); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/malloc_status.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/malloc_status.c new file mode 100644 index 0000000..dbfd1d5 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/malloc_status.c @@ -0,0 +1,3 @@ +void do_tests() { + ASSERT(stringp(malloc_status())); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/map.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/map.c new file mode 100644 index 0000000..4080924 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/map.c @@ -0,0 +1,54 @@ +int same(mixed* x, mixed* y) { + if (sizeof(x) != sizeof(y)) return 0; + for (int i = 0; i < sizeof(x); i++) { + if (x[i] != y[i]) return 0; + } + return 1; +} + +int msame(mapping x, mapping y) { + mixed z; + if (sizeof(keys(x)) != sizeof(keys(y))) return 0; + foreach (z in keys(x)) { + if (x[z] != y[z]) return 0; + } + return 1; +} + +int whatever1(mixed x, mixed y, mixed z) { + return x; +} + +int whatever2(mixed x, mixed y, mixed z) { + return y; +} + +int whatever3(mixed x, mixed y, mixed z) { + return z; +} + +void do_tests() { + /* array */ + ASSERT(same(map( ({ 1, 2, 0, 3 }), (: $1 :)), ({ 1, 2, 0, 3 }))); + ASSERT(map( ({ }), "foo") == ({})); + ASSERT(same(map( ({ 2, 3 }), (: whatever1, 1 :)), ({ 1, 1 }))); + ASSERT(same(map( ({ 2, 3 }), "whatever2", this_object(), 1), ({ 1, 1}))); + ASSERT(same(map( ({ 2, 3 }), (: whatever2 :), 1), ({ 1, 1 }))); + ASSERT(same(map( ({ 2, 3 }), "whatever2", __FILE__, 1), ({ 1, 1 }))); + + /* mapping */ + ASSERT(msame(map( ([ 1: 2, 0: 3 ]), (: $1 :)), ([ 1: 1, 0: 0 ]))); + ASSERT(msame(map( ([ ]), "foo"), ([]))); + ASSERT(msame(map( ([ 1: 2 ]), (: whatever1, 3 :)), ([ 1: 3 ]))); + ASSERT(msame(map( ([ 1: 2 ]), "whatever3", this_object(), 3), ([ 1: 3 ]))); + ASSERT(msame(map( ([ 1: 2 ]), (: whatever3 :), 3), ([ 1: 3 ]))); + ASSERT(msame(map( ([ 1: 2 ]), "whatever3", __FILE__, 3), ([ 1: 3 ]))); + + /* string */ + ASSERT(map( "foobar", (: $1 + 1 :)) == "gppcbs"); + ASSERT(map("", "foo") == ""); + ASSERT(map( "xy", (: whatever1, 'c' :)) == "cc"); + ASSERT(map( "xy", "whatever2", this_object(), 'c') == "cc"); + ASSERT(map( "xy", (: whatever2 :), 'c')== "cc"); + ASSERT(map( "xy", "whatever2", __FILE__, 'c')== "cc"); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/map_delete.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/map_delete.c new file mode 100644 index 0000000..0dd7294 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/map_delete.c @@ -0,0 +1,11 @@ +void do_tests() { + mapping m = ([ 1 : 2, "foo" : 3, this_object() : 5 ]); + + map_delete(m, 1); + ASSERT(undefinedp(m[1])); + map_delete(m, ({})); + map_delete(m, "foo"); + ASSERT(undefinedp(m["foo"])); + map_delete(m, this_object()); + ASSERT(undefinedp(m[this_object()])); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/mapp.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/mapp.c new file mode 100644 index 0000000..895b830 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/mapp.c @@ -0,0 +1,5 @@ +void do_tests() { + ASSERT(mapp(([]))); + ASSERT(!mapp(0)); + ASSERT(!mapp("foo")); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/master.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/master.c new file mode 100644 index 0000000..9b49f11 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/master.c @@ -0,0 +1,4 @@ +void do_tests() { + ASSERT(master()); + ASSERT(objectp(master())); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/match_path.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/match_path.c new file mode 100644 index 0000000..8fde603 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/match_path.c @@ -0,0 +1,11 @@ +void do_tests() { + mapping m = ([ "foo/" : 1, "bar" : 2, "bazz/foo" : 3, "foo/bar/bazz" : 4]); + + ASSERT(!match_path(m, "kajdfj")); + ASSERT(match_path(m, "bar") == 2); + ASSERT(match_path(m, "bar/") == 2); + ASSERT(match_path(m, "bazz//foo") == 3); + ASSERT(match_path(m, "bazz/foo//") == 3); + ASSERT(match_path(m, "foo/bar") == 1); + ASSERT(match_path(m, "foo/bar/bazz") == 4); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/member_array.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/member_array.c new file mode 100644 index 0000000..2a46381 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/member_array.c @@ -0,0 +1,8 @@ +void do_tests() { + ASSERT(member_array('c', "foo") == -1); + ASSERT(member_array('b', "abar") == 1); + ASSERT(member_array('y', "xyzzy") == 1); + ASSERT(member_array('y', "xyzzy", 2) == 4); + ASSERT(member_array(2, ({ 1, 2, 3 })) == 1); + ASSERT(member_array("foo", ({ 1, "foo", 3 })) == 1); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/message.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/message.c new file mode 100644 index 0000000..0dda40d --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/message.c @@ -0,0 +1,4 @@ +void do_tests() { + // later +} + diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/mkdir.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/mkdir.c new file mode 100644 index 0000000..9dafeae --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/mkdir.c @@ -0,0 +1,3 @@ +void do_tests() { + // later +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/move_object.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/move_object.c new file mode 100644 index 0000000..bc6173a --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/move_object.c @@ -0,0 +1,11 @@ +void do_tests() { +#ifndef __NO_ENVIRONMENT__ + ASSERT(catch(move_object("foo"))); + ASSERT(catch(move_object(__FILE__))); + ASSERT(catch(move_object(this_object()))); + move_object(master()); + ASSERT(environment(this_object()) == master()); + destruct(this_object()); + ASSERT(catch(move_object(master()))); +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/mud_status.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/mud_status.c new file mode 100644 index 0000000..762e00e --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/mud_status.c @@ -0,0 +1,4 @@ +void do_tests() { + ASSERT(stringp(mud_status())); + ASSERT(stringp(mud_status(1))); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/notify_fail.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/notify_fail.c new file mode 100644 index 0000000..88db451 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/notify_fail.c @@ -0,0 +1,6 @@ +void do_tests() { +#ifndef __NO_ADD_ACTION__ + notify_fail("foo"); + notify_fail((: write("hi!\n") :)); +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/nullp.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/nullp.c new file mode 100644 index 0000000..e23a8b1 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/nullp.c @@ -0,0 +1,7 @@ +int x; + +void do_tests() { + ASSERT(evaluate( (: nullp($1) :) )); + ASSERT(nullp(x)); + ASSERT(!nullp(1)); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/objectp.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/objectp.c new file mode 100644 index 0000000..aa9c94f --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/objectp.c @@ -0,0 +1,5 @@ +void do_tests() { + ASSERT(objectp(this_object())); + ASSERT(!objectp(0)); +} + diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/opcprof.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/opcprof.c new file mode 100644 index 0000000..6b68aa7 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/opcprof.c @@ -0,0 +1,6 @@ +void do_tests() { +#if defined(__OPCPROF__) || defined(__OPCPROF_2D__) + opcprof(); + opcprof("/opc"); +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/origin.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/origin.c new file mode 100644 index 0000000..7b33b20 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/origin.c @@ -0,0 +1,20 @@ +void lfun() { + ASSERT(origin() == "local"); +} + +void co() { + ASSERT(origin() == "internal"); +} + +void ef() { + ASSERT(origin() == "efun"); +} + +void do_tests() { + ASSERT(origin() == "call_other"); + lfun(); + call_out("co", 1); + filter( ({ 1 }), "ef"); + ASSERT(evaluate( (: origin :)) == "function pointer"); + ASSERT(evaluate( (: origin() :)) == "functional"); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/pointerp.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/pointerp.c new file mode 100644 index 0000000..bc93bf3 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/pointerp.c @@ -0,0 +1,4 @@ +void do_tests() { + ASSERT(pointerp( ({}) )); + ASSERT(!pointerp( ([]) )); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/present.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/present.c new file mode 100644 index 0000000..c621763 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/present.c @@ -0,0 +1,21 @@ +string id; + +int id(string name) { return name == id; } + +void create(string arg) { +#ifndef __NO_ENVIRONMENT__ + id = arg; + if (!arg) { + new(__FILE__, "foo"); + } else { + move_object(previous_object()); + } +#endif +} + +void do_tests() { +#ifndef __NO_ENVIRONMENT__ + ASSERT(present("foo", this_object())); + ASSERT(present("foo")); +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/previous_object.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/previous_object.c new file mode 100644 index 0000000..f726bea --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/previous_object.c @@ -0,0 +1,7 @@ +void do_tests() { + object *obs = previous_object(-1); + + for (int i = 0; i < sizeof(obs); i++) { + ASSERT(obs[i] == previous_object(i)); + } +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/printf.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/printf.c new file mode 100644 index 0000000..1385da0 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/printf.c @@ -0,0 +1,4 @@ +void do_tests() { + // more complete testing done under sprintf() + printf("Printf test.\n"); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_ed_mode.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_ed_mode.c new file mode 100644 index 0000000..86ec8d2 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_ed_mode.c @@ -0,0 +1,16 @@ +void do_tests() { +#ifndef __OLD_ED__ + ASSERT(query_ed_mode() == -1); + ed_start("/ed_test"); + ASSERT(query_ed_mode() == 0); + ed_cmd("h"); + ASSERT(query_ed_mode() == -2); + ed_cmd(""); + ASSERT(query_ed_mode() == 0); + ed_cmd("2c"); + ASSERT(query_ed_mode() == 2); + ed_cmd("."); + ed_cmd("Q"); + ASSERT(query_ed_mode() == -1); +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_idle.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_idle.c new file mode 100644 index 0000000..12509df --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_idle.c @@ -0,0 +1,4 @@ +void do_tests() { + if (this_player()) + ASSERT(intp(query_idle(this_player()))); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_ip_name.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_ip_name.c new file mode 100644 index 0000000..9e334f5 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_ip_name.c @@ -0,0 +1,5 @@ +void do_tests() { + ASSERT(query_ip_number(this_object()) == 0); + if (this_player()) + ASSERT(stringp(query_ip_number(this_player()))); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_ip_number.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_ip_number.c new file mode 100644 index 0000000..9e334f5 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_ip_number.c @@ -0,0 +1,5 @@ +void do_tests() { + ASSERT(query_ip_number(this_object()) == 0); + if (this_player()) + ASSERT(stringp(query_ip_number(this_player()))); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_load_average.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_load_average.c new file mode 100644 index 0000000..09fd376 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_load_average.c @@ -0,0 +1,4 @@ +void do_tests() { + ASSERT(stringp(query_load_average())); +} + diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_privs.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_privs.c new file mode 100644 index 0000000..36d0d4f --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_privs.c @@ -0,0 +1,5 @@ +void do_tests() { +#ifdef __PRIVS__ + ASSERT(query_privs(this_object())); +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_snoop.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_snoop.c new file mode 100644 index 0000000..e5d6d4d --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_snoop.c @@ -0,0 +1,5 @@ +void do_tests() { +#ifndef __NO_SNOOP__ + ASSERT(query_snoop(this_object()) == 0); +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_snooping.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_snooping.c new file mode 100644 index 0000000..dbb4a79 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_snooping.c @@ -0,0 +1,5 @@ +void do_tests() { +#ifndef __NO_SNOOP__ + ASSERT(query_snooping(this_object()) == 0); +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_verb.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_verb.c new file mode 100644 index 0000000..b1822e1 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/query_verb.c @@ -0,0 +1,16 @@ +#ifndef __NO_ADD_ACTION__ +void func() { + ASSERT(query_verb() == "foo"); +} +#endif + +void do_tests() { +#ifndef __NO_ADD_ACTION__ + object tp; + SAVETP; + enable_commands(); + add_action( (: func :), "foo"); + RESTORETP; + command("foo"); +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/random.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/random.c new file mode 100644 index 0000000..231c202 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/random.c @@ -0,0 +1,6 @@ +void do_tests() { + for (int i = 0; i < 100; i++) { + ASSERT(random(5) >= 0); + ASSERT(random(5) < 5); + } +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/read_buffer.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/read_buffer.c new file mode 100644 index 0000000..f07e86a --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/read_buffer.c @@ -0,0 +1,56 @@ +/* + efun: mixed read_buffer(string|buffer, void|int, void|int); + test author: John Garnett + date: 1993 November 8 +*/ + +#define TEST_STRING "ABC" + +#ifndef __NO_BUFFER_TYPE__ +buffer b; +#endif +int i; + +void do_tests() { + string s; + +#ifndef __NO_BUFFER_TYPE__ + s = read_buffer(b); + ASSERT(s == TEST_STRING); + + s = read_buffer(b, sizeof(b)-1); + ASSERT(s == TEST_STRING[i..i]); + + s = read_buffer(b, sizeof(b)); + ASSERT(s == 0); + + s = read_buffer(b, -sizeof(b)); + ASSERT(s == TEST_STRING); + + s = read_buffer(b, -(sizeof(b) + 1)); + ASSERT(s == 0); + + s = read_buffer(b, 1, 1); + ASSERT(s == TEST_STRING[1..1]); + + s = read_buffer(b, 1, sizeof(b)); + ASSERT(s == TEST_STRING[1..i]); +#endif + + /* add cases here to handle reading from files */ +} + +void +create() +{ + int j, limit; + + i = strlen(TEST_STRING) - 1; + limit = strlen(TEST_STRING); +#ifndef __NO_BUFFER_TYPE__ + b = allocate_buffer(limit); + for (j = 0; j < limit; j++) { + b[j] = TEST_STRING[j]; + } +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/read_bytes.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/read_bytes.c new file mode 100644 index 0000000..bc73f7a --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/read_bytes.c @@ -0,0 +1,17 @@ +void do_tests() { + string foo = read_file("/testfile"); + + ASSERT(!read_bytes("/does_not_exist")); + ASSERT(!read_bytes("/does_not_exist", 1)); + ASSERT(!read_bytes("/does_not_exist", 1, 2)); + + ASSERT(!read_bytes("/testfile", -100000, 10)); + ASSERT(read_bytes("/testfile", -10, 5) == foo[<10..<6]); + ASSERT(read_bytes("/testfile", -10, 0) == foo[<10..]); + ASSERT(read_bytes("/testfile", -10) == foo[<10..]); + ASSERT(read_bytes("/testfile", -10, 100) == foo[<10..]); + ASSERT(read_bytes("/testfile") == foo); + ASSERT(!read_bytes("/testfile", 1000000, 10)); + ASSERT(read_bytes("/testfile", 100, 100) == foo[100..199]); + ASSERT(strlen(read_bytes("/testfile", 100, 100)) == 100); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/read_file.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/read_file.c new file mode 100644 index 0000000..d2a547b --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/read_file.c @@ -0,0 +1,10 @@ +void do_tests() { + string foo = read_bytes("/testfile"); + string mid = implode(explode(foo, "\n")[99..198], "\n") + "\n"; + + ASSERT(!read_file("/single", 10, 10)); + ASSERT(read_file("/testfile") == foo); + ASSERT(read_file("/testfile", 100, 100) == mid); + ASSERT(!read_file("/does_not_exist")); + ASSERT(!read_file("/testfile", 10000, 1)); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/readme b/fluffos-2.23-ds03/testsuite/single/tests/efuns/readme new file mode 100644 index 0000000..e69de29 diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/receive.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/receive.c new file mode 100644 index 0000000..b805a52 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/receive.c @@ -0,0 +1,4 @@ +void do_tests() { + ASSERT(!receive("")); + ASSERT(!receive("recieve_test")); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/reg_assoc.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/reg_assoc.c new file mode 100644 index 0000000..14f862a --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/reg_assoc.c @@ -0,0 +1,22 @@ +int same_array(mixed *x, mixed *y) { + if (!arrayp(x) || !arrayp(y)) return 0; + if (sizeof(x) != sizeof(y)) return 0; + for (int i = 0; i < sizeof(x); i++) { + if (arrayp(x[i])) { + if (!same_array(x[i], y[i])) + return 0; + } else if (x[i] != y[i]) + return 0; + } + return 1; +} + +void do_tests() { + ASSERT(same_array( + reg_assoc("testhahatest", ({ "haha", "te" }), ({ 2, 3 }), 4), + ({ ({ "", "te", "st", "haha", "", "te", "st" }), + ({ 4, 3, 4, 2, 4, 3, 4 }) }))); + ASSERT(catch(reg_assoc("foo", ({ 1 }), ({ 2, 3 })))); + ASSERT(catch(reg_assoc("foo", ({ 1, 2 }), ({ 2, 3 })))); + ASSERT(catch(reg_assoc("foo", ({ "bar", "+" }), ({ 0, 1 })))); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/regexp.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/regexp.c new file mode 100644 index 0000000..88dc84c --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/regexp.c @@ -0,0 +1,32 @@ +int same_array(mixed *x, mixed *y) { + if (!arrayp(x) || !arrayp(y)) return 0; + if (sizeof(x) != sizeof(y)) return 0; + for (int i = 0; i < sizeof(x); i++) { + if (arrayp(x[i])) { + if (!same_array(x[i], y[i])) + return 0; + } else if (x[i] != y[i]) + return 0; + } + return 1; +} + +void do_tests() { + mapping x = ([ 1 : "bazz" ]); + + ASSERT(catch(regexp("foo", "bar", x[1]))); + ASSERT(catch(regexp("foo", "bar", 1))); + + ASSERT(regexp("tabba", "a*b")); + ASSERT(!regexp("tbba", "a+b")); + ASSERT(same_array( + regexp( ({ "foo", "bar", "bazz" }), "b"), + ({ "bar", "bazz" }))); + ASSERT(same_array( + regexp( ({ "foo", "bar", "bazz" }), "^...$"), + ({ "foo", "bar" }) )); + ASSERT(same_array(regexp( ({ "foo", "bar", "bazz" }), "(oo|zz)", 1), + ({ "foo", 1, "bazz", 3 }))); + ASSERT(catch(regexp("foo", "+"))); + ASSERT(catch(regexp( ({ "foo", "bar" }), "+"))); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/remove_action.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/remove_action.c new file mode 100644 index 0000000..3fe95da --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/remove_action.c @@ -0,0 +1,17 @@ +int called = 0; + +void func() { called = 1; } + +void do_tests() { +#ifndef __NO_ADD_ACTION__ + object tp; + + SAVETP; + enable_commands(); + add_action( "func", "bar" ); + ASSERT(remove_action( "func", "bar" )); + RESTORETP; + command("bar"); + ASSERT(!called); +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/remove_call_out.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/remove_call_out.c new file mode 100644 index 0000000..6143e20 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/remove_call_out.c @@ -0,0 +1,24 @@ +int called; + +void first_call() { + called = 1; +} + +void third_call() { + ASSERT(!called); +} + +void second_call() { + ASSERT(!called); + call_out( (: first_call :), 0); + remove_call_out(); + call_out( (: third_call :), 1); +} + +void do_tests() { + called = 0; + call_out( "first_call", 0); + call_out( "second_call", 1); + ASSERT(remove_call_out("first_call") != -1); + ASSERT(remove_call_out("foo") == -1); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/rename.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/rename.c new file mode 100644 index 0000000..cdbd1eb --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/rename.c @@ -0,0 +1,10 @@ +void do_tests() { + write_file("/rename_test", "Hmm."); + rename("/rename_test", "/ren_test"); + ASSERT(file_size("/rename_test") == -1); + ASSERT(read_file("/ren_test") == "Hmm."); + rename("/ren_test", "/single"); + ASSERT(file_size("/ren_test") == -1); + ASSERT(read_file("/single/ren_test") == "Hmm."); + rm("/single/ren_test"); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/replace_string.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/replace_string.c new file mode 100644 index 0000000..f531363 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/replace_string.c @@ -0,0 +1,73 @@ +void do_tests() { + string src = "This is a test"; + + for (int i = 0; i < 2; i++) { + ASSERT(replace_string(src, "", "bar") == src); + ASSERT(replace_string(src, "foo", "bar", 5, 4) == src); + + // case 1: rlen <= plen, plen > 1, rlen > 0 + ASSERT(replace_string(src, "is", "x") == "Thx x a test"); + ASSERT(replace_string(src, "is", "x", 1) == "Thx is a test"); + ASSERT(replace_string(src, "is", "x", 0, 0) == "Thx x a test"); + ASSERT(replace_string(src, "is", "x", 0, 1) == "Thx is a test"); + ASSERT(replace_string(src, "is", "x", 0, 2) == "Thx x a test"); + ASSERT(replace_string(src, "is", "x", 1, 1) == "Thx is a test"); + ASSERT(replace_string(src, "is", "x", 1, 2) == "Thx x a test"); + ASSERT(replace_string(src, "is", "x", 2, 2) == "This x a test"); + // case 2: rlen <= plen, plen > 1, rlen == 0 + ASSERT(replace_string(src, "is", "") == "Th a test"); + ASSERT(replace_string(src, "is", "", 1) == "Th is a test"); + ASSERT(replace_string(src, "is", "", 0, 0) == "Th a test"); + ASSERT(replace_string(src, "is", "", 0, 1) == "Th is a test"); + ASSERT(replace_string(src, "is", "", 0, 2) == "Th a test"); + ASSERT(replace_string(src, "is", "", 1, 1) == "Th is a test"); + ASSERT(replace_string(src, "is", "", 1, 2) == "Th a test"); + ASSERT(replace_string(src, "is", "", 2, 2) == "This a test"); + // case 3: rlen <= plen, plen == 1, rlen > 0 + ASSERT(replace_string(src, "s", "x") == "Thix ix a text"); + ASSERT(replace_string(src, "s", "x", 1) == "Thix is a test"); + ASSERT(replace_string(src, "s", "x", 2) == "Thix ix a test"); + ASSERT(replace_string(src, "s", "x", 0, 0) == "Thix ix a text"); + ASSERT(replace_string(src, "s", "x", 0, 1) == "Thix is a test"); + ASSERT(replace_string(src, "s", "x", 0, 2) == "Thix ix a test"); + ASSERT(replace_string(src, "s", "x", 1, 1) == "Thix is a test"); + ASSERT(replace_string(src, "s", "x", 1, 2) == "Thix ix a test"); + ASSERT(replace_string(src, "s", "x", 1, 3) == "Thix ix a text"); + ASSERT(replace_string(src, "s", "x", 2, 2) == "This ix a test"); + // case 4: rlen <= plen, plen == 1, rlen == 0 + ASSERT(replace_string(src, "s", "") == "Thi i a tet"); + ASSERT(replace_string(src, "s", "", 1) == "Thi is a test"); + ASSERT(replace_string(src, "s", "", 2) == "Thi i a test"); + ASSERT(replace_string(src, "s", "", 0, 0) == "Thi i a tet"); + ASSERT(replace_string(src, "s", "", 0, 1) == "Thi is a test"); + ASSERT(replace_string(src, "s", "", 0, 2) == "Thi i a test"); + ASSERT(replace_string(src, "s", "", 1, 1) == "Thi is a test"); + ASSERT(replace_string(src, "s", "", 1, 2) == "Thi i a test"); + ASSERT(replace_string(src, "s", "", 1, 3) == "Thi i a tet"); + ASSERT(replace_string(src, "s", "", 2, 2) == "This i a test"); + // case 5: rlen > plen, plen > 1, rlen > 0 + ASSERT(replace_string(src, "is", "foo") == "Thfoo foo a test"); + ASSERT(replace_string(src, "is", "foo", 1) == "Thfoo is a test"); + ASSERT(replace_string(src, "is", "foo", 2) == "Thfoo foo a test"); + ASSERT(replace_string(src, "is", "foo", 0, 0) == "Thfoo foo a test"); + ASSERT(replace_string(src, "is", "foo", 0, 1) == "Thfoo is a test"); + ASSERT(replace_string(src, "is", "foo", 0, 2) == "Thfoo foo a test"); + ASSERT(replace_string(src, "is", "foo", 1, 1) == "Thfoo is a test"); + ASSERT(replace_string(src, "is", "foo", 1, 2) == "Thfoo foo a test"); + ASSERT(replace_string(src, "is", "foo", 1, 3) == "Thfoo foo a test"); + ASSERT(replace_string(src, "is", "foo", 2, 2) == "This foo a test"); + // case 6: rlen > plen, plen == 1 + ASSERT(replace_string(src, "s", "foo") == "Thifoo ifoo a tefoot"); + ASSERT(replace_string(src, "s", "foo", 1) == "Thifoo is a test"); + ASSERT(replace_string(src, "s", "foo", 2) == "Thifoo ifoo a test"); + ASSERT(replace_string(src, "s", "foo", 0, 0) == "Thifoo ifoo a tefoot"); + ASSERT(replace_string(src, "s", "foo", 0, 1) == "Thifoo is a test"); + ASSERT(replace_string(src, "s", "foo", 0, 2) == "Thifoo ifoo a test"); + ASSERT(replace_string(src, "s", "foo", 1, 1) == "Thifoo is a test"); + ASSERT(replace_string(src, "s", "foo", 1, 2) == "Thifoo ifoo a test"); + ASSERT(replace_string(src, "s", "foo", 1, 3) == "Thifoo ifoo a tefoot"); + ASSERT(replace_string(src, "s", "foo", 2, 2) == "This ifoo a test"); + + src = src[0..5] + src[6..]; + } +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/restore_object.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/restore_object.c new file mode 100644 index 0000000..295b43a --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/restore_object.c @@ -0,0 +1,49 @@ +int var1; +#ifndef __SENSIBLE_MODIFIERS__ +static int var2; +#else +nosave int var2; +#endif +int var3; +int var4; + +void setup() { + var1 = 1; + var2 = 2; + var3 = 3; + var4 = 4; +} + +void do_tests() { + write_file("/sf.o", "#empty\n", 1); + setup(); + restore_object("/sf"); + ASSERT(!var1); + ASSERT(var2 == 2); + ASSERT(!var3); + ASSERT(!var4); + + setup(); + restore_object("/sf", 1); + ASSERT(var1 == 1); + ASSERT(var2 == 2); + ASSERT(var3 == 3); + ASSERT(var4 == 4); + + write_file("/sf.o", "var1 2\nvar2 4\nvar3 6\nvar4 8\n", 1); + setup(); + restore_object("/sf", 1); + ASSERT(var1 == 2); + ASSERT(var2 == 2); + ASSERT(var3 == 6); + ASSERT(var4 == 8); + + write_file("/sf.o", "var4 1\nvar2 9\nvar1 3\nvar3 4\n", 1); + setup(); + restore_object("/sf", 1); + ASSERT(var1 == 3); + ASSERT(var2 == 2); + ASSERT(var3 == 4); + ASSERT(var4 == 1); +} + diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/restore_variable.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/restore_variable.c new file mode 100644 index 0000000..cca4cbe --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/restore_variable.c @@ -0,0 +1,41 @@ +#define ERR(x) ASSERT2(catch(restore_variable(x)), sprintf("%O", x)) +#define IS(x, y) ASSERT2(same(restore_variable(x),y), sprintf("%O", x)) + +string *value_errs = ({ "\"\"x", "\"\\", "\"\\x\\", "\"\\x\"x", + "-x" }); +mapping values = ([ + "\"\r\"" : "\n", + "\"\\\"\"" : "\"", + "\"\\\"\\x\r\"" : "\"x\n", + "-1" : -1, + "0" : 0, + "1" : 1, + "22" : 22, + "1.2" : 1.2, + "333" : 333, + "({})" : ({}), + "({,})" : ({0}) +]); + +void do_tests() { + mixed x, y; + foreach (x in value_errs) { + ERR(x); + } + + foreach (x, y in values) { + IS(x, y); + } + + // arrays + foreach (x, y in values) { + IS("({" + x + ",})", ({ y })); + IS("({" + x + "," + x + ",})", ({ y, y })); + } + + // mappings + foreach (x, y in values) { + IS("([1:" + x + ",])", ([1:y ])); + IS("([" + x + ":" + x + ",])", ([ y: y ])); + } +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/rm.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/rm.c new file mode 100644 index 0000000..5065019 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/rm.c @@ -0,0 +1,6 @@ +void do_tests() { + write_file("/rm_test", "foo"); + ASSERT(file_size("/rm_test")); + rm("/rm_test"); + ASSERT(file_size("/rm_test") == -1); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/rmdir.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/rmdir.c new file mode 100644 index 0000000..547c7b4 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/rmdir.c @@ -0,0 +1,6 @@ +void do_tests() { + mkdir("/rm_dir"); + ASSERT(file_size("/rm_dir") == -2); + rmdir("/rm_dir"); + ASSERT(file_size("/rm_dir") == -1); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/save_object.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/save_object.c new file mode 100644 index 0000000..0c4c095 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/save_object.c @@ -0,0 +1,14 @@ +int x = 0; +#ifndef __SENSIBLE_MODIFIERS__ +static int z = 5; +#else +nosave int z = 5; +#endif +int y = 1; + +void do_tests() { + save_object("/sf"); + ASSERT(read_file("/sf.o") == "#" + __FILE__ + "\ny 1\n"); + save_object("/sf", 1); + ASSERT(read_file("/sf.o") == "#" + __FILE__ + "\nx 0\ny 1\n"); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/save_variable.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/save_variable.c new file mode 100644 index 0000000..fd29bc6 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/save_variable.c @@ -0,0 +1,35 @@ +#define IS(x, y) ASSERT2(save_variable(x)==y, sprintf("%O %O", x, save_variable(x))) + +mapping values = +([ + "\n" : "\"\r\"", + "\"" : "\"\\\"\"", + "\"x\\\n" : "\"\\\"x\\\\\r\"", + -1 : "-1", + 0 : "0", + 1 : "1", + 22 : "22", + 1.2 : "1.200000", + 333 : "333", + ({}) : "({})", + ({ 0 }) : "({0,})" +]); + +void do_tests() { + mixed x, y; + foreach (x, y in values) { + IS(x, y); + } + + // arrays + foreach (x, y in values) { + IS( ({ x }), "({" + y + ",})"); + IS( ({ x, x }), "({" + y + "," + y + ",})"); + } + + // mappings + foreach (x, y in values) { + IS( ([ 1 : x ]), "([1:" + y + ",])"); + IS( ([ x : x ]), "([" + y + ":" + y + ",])"); + } +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/say.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/say.c new file mode 100644 index 0000000..977b7a2 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/say.c @@ -0,0 +1,32 @@ +#ifndef __NO_ENVIRONMENT__ +string err = 0; +string yes = 0; + +#define YES(x) ASSERT2((talker->send(x), yes == x), x); ASSERT2((talker->send("no:" + x, this_object()), !err), err); ASSERT2((talker->send("no:" + x, ({ this_object() })), !err), err) +#define NO(x) ASSERT2((talker->send(x), !err), err) + +void catch_tell(string str) { + if (str[0..2] != "yes") + err = str; + else + yes = str; +} + +void do_tests() { + object tp; + object talker = new(__DIR__ "talker"); + +#ifndef __NO_ADD_ACTION__ + SAVETP; + enable_commands(); + RESTORETP; +#endif + NO("no-noenv"); + talker->move(this_object()); + + YES("yes-inside"); + talker->move(new("/single/void")); + move_object(talker); + YES("yes-outside"); +} +#endif diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/set_bit.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/set_bit.c new file mode 100644 index 0000000..1703019 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/set_bit.c @@ -0,0 +1,18 @@ +void do_tests() { + string str; + + ASSERT(catch(set_bit("", 10000000000000))); + ASSERT(catch(set_bit("", -2))); + + str = set_bit("", 100); + ASSERT(test_bit(str, 100)); + for (int i = 0; i < 200; i++) { + if (i != 100) + ASSERT(!test_bit(str, i)); + } + str = " "; + str[0] = 5; + ASSERT(catch(set_bit(str, 1))); + str[0] = 255; + ASSERT(catch(set_bit(str, 1))); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/set_debug_level.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/set_debug_level.c new file mode 100644 index 0000000..883f07c --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/set_debug_level.c @@ -0,0 +1,6 @@ +void do_tests() { +#ifdef __DEBUG_MACRO__ + set_debug_level(10); + set_debug_level(0); +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/set_heart_beat.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/set_heart_beat.c new file mode 100644 index 0000000..6f767ab --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/set_heart_beat.c @@ -0,0 +1,32 @@ +int x; + +void heart_beat() { + x++; + switch (x) { + case 1: + ASSERT(query_heart_beat(this_object()) == 1); + set_heart_beat(2); + ASSERT(query_heart_beat(this_object()) == 2); + break; + case 1: + ASSERT(query_heart_beat(this_object()) == 2); + set_heart_beat(-1); + ASSERT(query_heart_beat(this_object()) == 2); + break; + case 2: + ASSERT(query_heart_beat(this_object()) == 2); + set_heart_beat(0); + ASSERT(query_heart_beat(this_object()) == 0); + break; + default: + ASSERT(0); + } +} + +void do_tests() { + x = 0; + set_heart_beat(0); + ASSERT(!query_heart_beat(this_object())); + set_heart_beat(1); + ASSERT(query_heart_beat(this_object()) == 1); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/set_hide.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/set_hide.c new file mode 100644 index 0000000..abdcd3c --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/set_hide.c @@ -0,0 +1,4 @@ +void do_tests() { + set_hide(1); + set_hide(0); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/set_light.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/set_light.c new file mode 100644 index 0000000..fa6556c --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/set_light.c @@ -0,0 +1,40 @@ +int light = 0; + +#define CHK ASSERT(light = set_light(0)); + +#ifndef __NO_ENVIRONMENT__ +void move_or_destruct(object ob) { + move_object(new("/single/void")); +} +#endif + +void do_tests() { + object ob; + +#ifndef __NO_LIGHT__ + CHK; + set_light(2); + light += 2; + CHK; + +#ifndef __NO_ENVIRONMENT__ + ob = new(__DIR__ "light"); + ob->move(this_object()); + light += 3; + CHK; + + destruct(ob); + light -= 3; + CHK; + + ob = new(__DIR__ "light"); + move_object(ob); + light += 3; + CHK; + + destruct(ob); + light -= 3; + CHK; +#endif +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/set_living_name.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/set_living_name.c new file mode 100644 index 0000000..9dfb568 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/set_living_name.c @@ -0,0 +1,19 @@ +void do_tests() { + object tp; +#ifndef __NO_ADD_ACTION__ + SAVETP; + enable_commands(); + RESTORETP; + ASSERT(!find_living("foo")); + set_living_name("foo"); + ASSERT(find_living("foo") == this_object()); + disable_commands(); + ASSERT(!find_living("foo")); + enable_commands(); + RESTORETP; + set_living_name("bar"); + ASSERT(!find_living("foo")); + ASSERT(find_living("bar") == this_object()); + destruct(this_object()); +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/set_privs.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/set_privs.c new file mode 100644 index 0000000..249fc42 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/set_privs.c @@ -0,0 +1,8 @@ +void do_tests() { +#ifdef __PRIVS__ + set_privs(this_object(), "foo"); + ASSERT(query_privs(this_object()) == "foo"); + set_privs(this_object(), 0); + ASSERT(query_privs(this_object()) == 0); +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/shadow.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/shadow.c new file mode 100644 index 0000000..8fabd70 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/shadow.c @@ -0,0 +1,38 @@ +object prev; + +void create() { + prev = previous_object(); +} + +nomask void i_am_bad() { +} + +void do_tests() { + object ob; +#ifndef __NO_SHADOWS__ + ASSERT(catch(shadow(this_object()))); + ASSERT(catch(shadow(master()))); + new(__DIR__ "badshad", 1); + + ASSERT(shadow(this_object(), 0) == 0); + ASSERT((object)this_object()->foo() == this_object()); + + ob = new(__DIR__ "goodshad", 1); + ASSERT(shadow(this_object(), 0) == ob); + ASSERT((object)this_object()->foo() == ob); + ASSERT((object)new(__FILE__)->bar() == ob); + + ASSERT(catch(shadow(ob))); + ASSERT(catch(shadow(new(__FILE__)))); + +#endif +} + +object foo() { + printf("%O\n", file_name()); + return this_object(); +} + +object bar() { + return (object)prev->foo(); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/shutdown.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/shutdown.c new file mode 100644 index 0000000..c8a0563 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/shutdown.c @@ -0,0 +1,9 @@ +void do_the_nasty_deed() { + shutdown(55); + ASSERT(0); +} + +void do_tests() { + // This one is hard to test :-) + call_out( (: do_the_nasty_deed :), 60); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/sizeof.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/sizeof.c new file mode 100644 index 0000000..f678124 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/sizeof.c @@ -0,0 +1,9 @@ +void do_tests() { + ASSERT(sizeof(({ 1, 2, 3 })) == 3); + ASSERT(sizeof(allocate(50)) == 50); + ASSERT(sizeof(allocate_mapping(5)) == 0); + ASSERT(sizeof( ([ 1 : 2, 3 : 4 ]) ) == 2); + ASSERT(sizeof("foo") == 3); + ASSERT(sizeof((: sizeof :)) == 0); + ASSERT(sizeof(6) == 0); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/snoop.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/snoop.c new file mode 100644 index 0000000..0c4e10a --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/snoop.c @@ -0,0 +1,3 @@ +void do_tests() { + // maybe when it is possible for arbitrary objects to snoop. +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/sprintf.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/sprintf.c new file mode 100644 index 0000000..2e855ae --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/sprintf.c @@ -0,0 +1,222 @@ +// need to add: +// = and # mode tests +// precision +// : and @ +// 'X' + +// specifier, result, args +mixed make_arg(int x, int trail) { +#define BEFORE_INTS 0 +#define INTS_HI 2 +#define INTS_LO 6 +#define BEFORE_STRS (INTS_HI * INTS_LO) +#define STRS_HI 1 +#define STRS_LO 1 +#define BEFORE_FLOS (BEFORE_STRS + STRS_HI * STRS_LO) +#define FLOS_HI 1 +#define FLOS_LO 1 +#define BEFORE_CHRS (BEFORE_FLOS + FLOS_HI * FLOS_LO) +#define CHRS_HI 1 +#define CHRS_LO 1 +#define BEFORE_LPCS (BEFORE_CHRS + CHRS_HI * CHRS_LO) +#define LPCS_HI 1 +#define LPCS_LO 9 +#define TOTAL (BEFORE_LPCS + LPCS_HI * LPCS_LO) + + mixed ret; + string lpad = " ", rpad = " ", mpad; + int tmp; + + + switch (x % TOTAL) { + case BEFORE_INTS..BEFORE_INTS + INTS_HI * INTS_LO - 1: + switch (x % INTS_LO) { + case 0: ret = ({ "i", "5", 5 }); break; + case 1: ret = ({ "d", "345", 345 }); break; + case 2: ret = ({ "o", "111", 73 }); break; + case 3: ret = ({ "x", "a9", 169 }); break; + case 4: ret = ({ "X", "A9", 169 }); break; + case 5: ret = ({ "i", "-345", -345 }); break; + } + switch (x / INTS_LO) { + case 0: + break; + case 1: + if (ret[0][0] != 'i' && ret[0][0] != 'd') + break; + ret[0] = "+" + ret[0]; + if (ret[1][0] != '-') ret[1] = "+" + ret[1]; + lpad = "+"; + break; + } + break; + case BEFORE_STRS..BEFORE_STRS + STRS_HI * STRS_LO - 1: + x -= BEFORE_STRS; + switch (x % STRS_LO) { + case 0: ret = ({ "s", "foo", "foo" }); break; + } + switch (x / STRS_LO) { + case 0: + break; + } + break; + case BEFORE_FLOS..BEFORE_FLOS + FLOS_HI * FLOS_LO - 1: + x -= BEFORE_FLOS; + switch (x % FLOS_LO) { + case 0: ret = ({ "f", "1.234000", 1.234 }); break; + } + switch (x / FLOS_LO) { + case 0: + break; + } + break; + case BEFORE_CHRS..BEFORE_CHRS + CHRS_HI * CHRS_LO - 1: + x -= BEFORE_CHRS; + switch (x % CHRS_LO) { + case 0: ret = ({ "c", "a", 97 }); break; + } + switch (x / CHRS_LO) { + case 0: + break; + } + break; + case BEFORE_LPCS..BEFORE_LPCS + LPCS_HI * LPCS_LO - 1: + x -= BEFORE_LPCS; + switch (x % LPCS_LO) { + case 0: ret = ({ "O", "1", 1 }); break; + case 1: ret = ({ "O", "1.500000", 1.5 }); break; + case 2: ret = ({ "O", "\"foo\"", "foo" }); break; + case 3: ret = ({ "O", "({ })", ({}) }); break; + case 4: ret = ({ "O", "({ /* sizeof() == 2 */\n 1,\n 2\n})", ({ 1, 2 }) }); break; + case 5: ret = ({ "O", "(: make_arg, 5 :)", (: make_arg, 5 :) }); break; + case 6: ret = ({ "O", "(: ($1) :)", (: $1 :) }); break; + case 7: ret = ({ "O", "(: sprintf :)", (: sprintf :) }); break; + case 8: ret = ({ "O", "([ /* sizeof() == 1 */\n 1 : 2,\n])", ([ 1 : 2 ]) }); break; + } + switch (x / LPCS_LO) { + case 0: + break; + } + } + + tmp = random(20); + if (random(5)) { + mpad = "xyzzy"; + switch (x / TOTAL) { + case 0: + break; + case 1: + ret[0] = "'xyzzy'" + tmp + ret[0]; + if (strlen(ret[1]) < tmp) { + ret[1] = mpad[0..((tmp - strlen(ret[1])) % strlen(mpad))-1] + + ret[1]; + while (strlen(ret[1]) + strlen(mpad) <= tmp) + ret[1] = mpad + ret[1]; + } + break; + case 2: + { + int n, ll, rr; + ret[0] = "|'xyzzy'" + tmp + ret[0]; + if ((n = strlen(ret[1])) < tmp) { + ll = (tmp - n + 1)/2; + if (ll % strlen(mpad)) + ret[1] = mpad[0..(ll % strlen(mpad))-1] + ret[1]; + ll = ll/strlen(mpad); + while (ll--) + ret[1] = mpad + ret[1]; + if (trail) { + rr = (tmp - n)/2; + n = (rr % strlen(mpad)); + rr = rr/strlen(mpad); + while (rr--) + ret[1] += mpad; + if (n) + ret[1] += mpad[0..n-1]; + } + } + } + break; + case 3: + ret[0] = "-'xyzzy'" + tmp + ret[0]; + if (strlen(ret[1]) < tmp) { + int n = ((tmp - strlen(ret[1])) % strlen(mpad)); + while (strlen(ret[1]) + strlen(mpad) <= tmp) + ret[1] += mpad; + if (n) + ret[1] += mpad[0..n-1]; + } + break; + case 4: + ret[0] = "-*" + tmp + ret[0]; + ret = ret[0..1] + ({ tmp }) + ret[2..]; + while (strlen(ret[1]) < tmp) + ret[1] += rpad; + break; + default: + return 0; + } + } else + switch (x / TOTAL) { + case 0: + break; + case 1: + ret[0] = tmp + ret[0]; + while (strlen(ret[1]) < tmp) + ret[1] = lpad + ret[1]; + break; + case 2: + { + int n, ll, rr; + ret[0] = "|" + tmp + ret[0]; + if ((n = strlen(ret[1])) < tmp) { + ll = (tmp - n + 1)/2; + rr = (tmp - n)/2; + while (ll--) + ret[1] = lpad + ret[1]; + if (trail) + while (rr--) + ret[1] += rpad; + } + } + break; + case 3: + ret[0] = "-" + tmp + ret[0]; + while (strlen(ret[1]) < tmp) + ret[1] += lpad; + break; + case 4: + ret[0] = "-*" + tmp + ret[0]; + ret = ret[0..1] + ({ tmp }) + ret[2..]; + while (strlen(ret[1]) < tmp) + ret[1] += lpad; + break; + default: + return 0; + } + ret[0] = "%" + ret[0]; + return ret; +} + +void do_tests() { + int x; + mixed *mx; + string format, shouldbe; + string hmm; + + while (1) { + if (!(mx = make_arg(x++, 1))) break; + + format = "$" + mx[0] + "^"; + shouldbe = "$" + mx[1] + "^"; + ASSERT2(sprintf(format, mx[2..]...) == shouldbe, shouldbe); + } + + hmm = sprintf("xxx%#-20.5s\n", "This\nis\na\ntest\nof\nsprintf\ntable\nmode\n"); + ASSERT2(hmm == "xxxThisa of tabl\n is testsprimode\n", hmm); + hmm = sprintf("xxx%#-'y'20.5s\n", "This\nis\na\ntest\nof\nsprintf\ntable\nmode\n"); + ASSERT2(hmm == "xxxThisayyyofyytablyyyy\n isyytestsprimodeyyyy\n", hmm); + + hmm = sprintf("%#-20s\n", "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\no\n"); + ASSERT2(hmm == "a d g j o\nb e h k \nc f i l \n", hmm); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/sscanf.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/sscanf.c new file mode 100644 index 0000000..7ba247a --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/sscanf.c @@ -0,0 +1,12 @@ +inherit "/inherit/tests"; + +void do_tests() { + string s; + + ASSERT(catch(sscanf("you%", "%s%", s))); + ASSERT(catch(sscanf("you%", "%su%", s))); + sscanf("you%", "%s%%", s); + ASSERT(s == "you"); + sscanf("you%", "%su%%", s); + ASSERT(s == "yo"); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/talker.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/talker.c new file mode 100644 index 0000000..4e90ee5 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/talker.c @@ -0,0 +1,26 @@ +void create() { +#ifndef __NO_ADD_ACTION__ + enable_commands(); +#endif +} + +void catch_tell(string str) { +} + +void send(string str, mixed x) { +#ifndef __NO_ENVIRONMENT__ + if (x) + say(str, x); + else + say(str); +#else + shout(str); +#endif +} + +void move(object ob) { +#ifndef __NO_ENVIRONMENT__ + move_object(ob); +#endif +} + diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/to_float.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/to_float.c new file mode 100644 index 0000000..37f9639 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/to_float.c @@ -0,0 +1,18 @@ +inherit "/inherit/tests"; + +void do_tests() { + int i = 5; + float f = 6.7; + + f = to_float(i); + ASSERT(f == 5.0); + + f = i; + ASSERT(f == 5.0); + + f = to_float("1.23"); + ASSERT(f == 1.23); + + f = to_float("ajdfj"); + ASSERT(f == 0.00); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/to_int.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/to_int.c new file mode 100644 index 0000000..67c5b3b --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/to_int.c @@ -0,0 +1,16 @@ +void do_tests() { + int i = 5; + float f = 6.7; + + i = to_int(f); + ASSERT(i == 6); + + i = f; + ASSERT(i == 6); + + i = to_int("7"); + ASSERT(i == 7); + + i = to_int("ajdfj"); + ASSERT(i == 0); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/unloaded.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/unloaded.c new file mode 100644 index 0000000..88fa30a --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/unloaded.c @@ -0,0 +1,2 @@ +void create() { +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/users.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/users.c new file mode 100644 index 0000000..d5cd4cc --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/users.c @@ -0,0 +1,5 @@ +void do_tests() { + ASSERT(arrayp(users())); + if (this_player()) + ASSERT(member_array(this_player(), users()) != -1); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/efuns/values.c b/fluffos-2.23-ds03/testsuite/single/tests/efuns/values.c new file mode 100644 index 0000000..08fa064 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/efuns/values.c @@ -0,0 +1,10 @@ +void do_tests() { + mapping m = ([ 1 : 2, 3 : 4, 5 : 6 ]); + mixed *k = values(m); + mixed x, y; + + foreach (x, y in m) { + k -= ({ y }); + } + ASSERT(k == ({})); +} diff --git a/fluffos-2.23-ds03/testsuite/single/tests/operators/range.c b/fluffos-2.23-ds03/testsuite/single/tests/operators/range.c new file mode 100644 index 0000000..192a5e8 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/tests/operators/range.c @@ -0,0 +1,17 @@ +#define ARR ({ 1, 2, 3 }) + +void do_tests() { + mixed arr = ({ 1, 2, 3 }); +#ifndef __OLD_RANGE_BEHAVIOR__ + ASSERT(arr[0..-1] == ({})); + ASSERT(ARR[0..-1] == ({})); + ASSERT(same(arr[0..<1], ({1, 2, 3}))); + ASSERT(same(ARR[0..<1], ({1, 2, 3}))); + ASSERT(same(arr[1..<1], ({2, 3}))); + ASSERT(same(ARR[1..<1], ({2, 3}))); + ASSERT(same(arr[0..<2], ({1, 2}))); + ASSERT(same(ARR[0..<2], ({1, 2}))); + ASSERT(same(arr[1..1], ({ 2 }))); + ASSERT(same(ARR[1..1], ({ 2 }))); +#endif +} diff --git a/fluffos-2.23-ds03/testsuite/single/void.c b/fluffos-2.23-ds03/testsuite/single/void.c new file mode 100644 index 0000000..a9d0f49 --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/single/void.c @@ -0,0 +1,3 @@ +void dummy() +{ +} diff --git a/fluffos-2.23-ds03/testsuite/test_control.c b/fluffos-2.23-ds03/testsuite/test_control.c new file mode 100644 index 0000000..e69de29 diff --git a/fluffos-2.23-ds03/testsuite/u/readme b/fluffos-2.23-ds03/testsuite/u/readme new file mode 100644 index 0000000..7920dfb --- /dev/null +++ b/fluffos-2.23-ds03/testsuite/u/readme @@ -0,0 +1,2 @@ +This directory contains individual directories for those who will building +the mud. diff --git a/fluffos-2.23-ds03/tmp/insttest b/fluffos-2.23-ds03/tmp/insttest new file mode 100644 index 0000000..982793c --- /dev/null +++ b/fluffos-2.23-ds03/tmp/insttest @@ -0,0 +1 @@ +whatever diff --git a/fluffos-2.23-ds03/trees.c b/fluffos-2.23-ds03/trees.c new file mode 100644 index 0000000..3e8bc8b --- /dev/null +++ b/fluffos-2.23-ds03/trees.c @@ -0,0 +1,438 @@ +/* + * Support for parse trees for the compiler. + * + * Added by Beek (Tim Hollebeek) 9/29/94. Only converting expression parsing + * to parse trees at this point; the rest of code generation will likely + * follow later. + * + * Note: it did. See ChangeLogs. + * + */ + +#define SUPPRESS_COMPILER_INLINES +#include "std.h" +#include "lpc_incl.h" +#include "compiler.h" +#include "opcodes.h" + +/* our globals */ +static parse_node_block_t *parse_block_list = 0; +static parse_node_block_t *free_block_list = 0; + +static parse_node_t *next_node = 0; +static parse_node_t *last_node = 0; + +static int last_prog_size = 1; + +/* called by code generation when it is done with the tree */ +void +free_tree() { + parse_node_block_t *cur_block; + + if (!(cur_block = parse_block_list)) + return; + + while (cur_block->next) cur_block = cur_block->next; + + /* put all the blocks in the free list */ + cur_block->next = free_block_list; + free_block_list = parse_block_list; + parse_block_list = 0; + next_node = 0; + last_node = 0; +} + +/* called when the parser cleans up */ +void +release_tree() { + parse_node_block_t *cur_block; + parse_node_block_t *next_block; + + free_tree(); + next_block = free_block_list; + while ((cur_block = next_block)) { + next_block = cur_block->next; + FREE(cur_block); + } + free_block_list = 0; + last_prog_size = 1; +} + +/* get a new node to add to the tree */ +parse_node_t * +new_node() { + parse_node_block_t *cur_block; + + /* fast case */ + if (next_node < last_node) { + next_node->line = current_line_base + current_line; + return next_node++; + } + + /* no more nodes in the current block; do we have a free one? */ + if ((cur_block = free_block_list)) { + free_block_list = cur_block->next; + } else { + cur_block = ALLOCATE(parse_node_block_t, TAG_COMPILER, "new_node"); + } + /* add to block list */ + cur_block->next = parse_block_list; + parse_block_list = cur_block; + /* point the nodes correctly */ + next_node = &cur_block->nodes[0]; + last_node = &cur_block->nodes[NODES_PER_BLOCK]; + next_node->line = current_line_base + current_line; + return next_node++; +} + +/* get a new node to add to the tree, but don't count it for line # purposes + * This should be used for nodes that hold expressions together but don't + * generate any code themselves (NODE_IF, etc) + */ +parse_node_t * +new_node_no_line() { + parse_node_block_t *cur_block; + + /* fast case */ + if (next_node < last_node) { + next_node->line = 0; + return next_node++; + } + /* no more nodes in the current block; do we have a free one? */ + if ((cur_block = free_block_list)) { + free_block_list = cur_block->next; + } else { + cur_block = ALLOCATE(parse_node_block_t, TAG_COMPILER, "new_node"); + } + /* add to block list */ + cur_block->next = parse_block_list; + parse_block_list = cur_block; + /* point the nodes correctly */ + next_node = &cur_block->nodes[0]; + last_node = &cur_block->nodes[NODES_PER_BLOCK]; + next_node->line = 0; + return next_node++; +} + +/* quick routine to make a generic branched node */ +parse_node_t * +make_branched_node (short kind, char type, + parse_node_t * l, parse_node_t * r) { + parse_node_t *ret; + + ret = new_node(); + ret->kind = kind; + ret->type = type; + ret->l.expr = l; + ret->r.expr = r; + return ret; +} + +/* create an optimized typical binary integer operator */ +parse_node_t * +binary_int_op (parse_node_t * l, parse_node_t * r, + char op, const char * name) { + parse_node_t *ret; + + if (exact_types) { + if (!IS_TYPE(l->type, TYPE_NUMBER)) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Bad left argument to '"); + p = strput(p, end, name); + p = strput(p, end, "' : \""); + p = get_type_name(p, end, l->type); + p = strput(p, end, "\""); + yyerror(buf); + } + if (!IS_TYPE(r->type,TYPE_NUMBER)) { + char buf[256]; + char *end = EndOf(buf); + char *p; + + p = strput(buf, end, "Bad right argument to '"); + p = strput(p, end, name); + p = strput(p, end, "' : \""); + p = get_type_name(p, end, r->type); + p = strput(p, end, "\""); + yyerror(buf); + } + } + if (l->kind == NODE_NUMBER) { + if (r->kind == NODE_NUMBER) { + switch (op) { + case F_OR: l->v.number |= r->v.number; break; + case F_XOR: l->v.number ^= r->v.number; break; + case F_AND: l->v.number &= r->v.number; break; + case F_LSH: l->v.number <<= r->v.number; break; + case F_RSH: l->v.number >>= r->v.number; break; + case F_MOD: + if (r->v.number == 0) { + yyerror("Modulo by zero constant"); + break; + } + l->v.number %= r->v.number; break; + default: fatal("Unknown opcode in binary_int_op()\n"); + } + return l; + } + switch (op) { + case F_OR: + case F_XOR: + case F_AND: + CREATE_BINARY_OP(ret, op, TYPE_NUMBER, r, l); + return ret; + } + } + CREATE_BINARY_OP(ret, op, TYPE_NUMBER, l, r); + return ret; +} + +parse_node_t *make_range_node (int code, parse_node_t * expr, + parse_node_t * l, + parse_node_t * r) { + parse_node_t *newnode; + + if (r) { + CREATE_TERNARY_OP(newnode, code, 0, l, r, expr); + } else { + CREATE_BINARY_OP(newnode, code, 0, l, expr); + } + + if (exact_types) { + switch(expr->type) { + case TYPE_ANY: + case TYPE_STRING: + case TYPE_BUFFER: + newnode->type = expr->type; + break; + + default: + if (expr->type & TYPE_MOD_ARRAY) newnode->type = expr->type; + else{ + type_error("Bad type of argument used for range: ", expr->type); + newnode->type = TYPE_ANY; + } + } + + if (!IS_TYPE(l->type, TYPE_NUMBER)) + type_error("Bad type of left index to range operator", l->type); + if (r && !IS_TYPE(r->type, TYPE_NUMBER)) + type_error("Bad type of right index to range operator", r->type); + } else newnode->type = TYPE_ANY; + return newnode; +} + +parse_node_t *insert_pop_value (parse_node_t * expr) { + parse_node_t *replacement; + + if (!expr) + return 0; + if (expr->type == TYPE_NOVALUE) { + expr->type = TYPE_VOID; + return expr; + } + switch (expr->kind) { + case NODE_EFUN: + if (expr->v.number & NOVALUE_USED_FLAG) { + expr->v.number &= ~NOVALUE_USED_FLAG; + return expr; + } + break; + case NODE_TWO_VALUES: + /* (two-values expr1 expr2) where expr1 is already popped. + * + * instead of: (pop (two-values expr1 expr2)) + * generated: (two-values expr (pop expr2)) + * + * both of which generate the same code, but the second optimizes + * better in cases like: i++, j++ + * + * we get: (two-values (inc i) (post-inc j)) + * first: (pop (two-values (inc i) (post-inc j))) + * -> INC i; POST_INC j; POP + * second: (two-values (inc i) (inc j)) + * -> INC i; INC j + */ + if ((expr->r.expr = insert_pop_value(expr->r.expr))) + return expr; + return expr->l.expr; + case NODE_IF: + /* a NODE_IF that gets popped is a (x ? y : z); + * propagate the pop in order to produce the same code as + * if (x) y; else z; + */ + expr->l.expr = insert_pop_value(expr->l.expr); + expr->r.expr = insert_pop_value(expr->r.expr); + + if (!expr->l.expr && !expr->r.expr) { + /* if both branches do nothing, don't bother with the test ... */ + return insert_pop_value(expr->v.expr); + } + return expr; + case NODE_TERNARY_OP: + switch (expr->r.expr->v.number) { + case F_NN_RANGE: case F_RN_RANGE: case F_RR_RANGE: case F_NR_RANGE: + expr->kind = NODE_TWO_VALUES; + expr->l.expr = insert_pop_value(expr->l.expr); + expr->r.expr->kind = NODE_TWO_VALUES; + expr->r.expr->l.expr = insert_pop_value(expr->r.expr->l.expr); + expr->r.expr->r.expr = insert_pop_value(expr->r.expr->r.expr); + + if (!expr->l.expr) { + expr = expr->r.expr; + if (!expr->l.expr) + return expr->r.expr; + if (!expr->r.expr) + return expr->l.expr; + } else { + if (!expr->r.expr->l.expr) { + expr->r.expr = expr->r.expr->r.expr; + if (!expr->r.expr) + return expr->l.expr; + } else { + if (!expr->r.expr->r.expr) + expr->r.expr = expr->r.expr->l.expr; + } + } + return expr; + } + break; + /* take advantage of the fact that opcodes don't clash */ + case NODE_CALL: + case NODE_BINARY_OP: + case NODE_UNARY_OP_1: + case NODE_UNARY_OP: + case NODE_OPCODE_1: + switch (expr->v.number) { + case F_AGGREGATE_ASSOC: + /* This has to be done specially b/c of the way mapping constants + are stored */ + return throw_away_mapping(expr); + case F_AGGREGATE: + return throw_away_call(expr); + case F_PRE_INC: case F_POST_INC: + expr->v.number = F_INC; + return expr; + case F_PRE_DEC: case F_POST_DEC: + expr->v.number = F_DEC; + return expr; + case F_NOT: case F_COMPL: case F_NEGATE: + expr = insert_pop_value(expr->r.expr); + return expr; + case F_MEMBER: + expr = insert_pop_value(expr->r.expr); + return expr; + case F_LOCAL: case F_GLOBAL: case F_REF: + return 0; + case F_EQ: case F_NE: case F_GT: case F_GE: case F_LT: case F_LE: + case F_OR: case F_XOR: case F_AND: case F_LSH: case F_RSH: + case F_ADD: case F_SUBTRACT: case F_MULTIPLY: case F_DIVIDE: + case F_MOD: case F_RE_RANGE: case F_NE_RANGE: case F_RINDEX: + case F_INDEX: + if ((expr->l.expr = insert_pop_value(expr->l.expr))) { + if ((expr->r.expr = insert_pop_value(expr->r.expr))) { + expr->kind = NODE_TWO_VALUES; + return expr; + } else + return expr->l.expr; + } else + return insert_pop_value(expr->r.expr); + break; + case F_ASSIGN: + if (IS_NODE(expr->r.expr, NODE_OPCODE_1, F_LOCAL_LVALUE)) { + long tmp = expr->r.expr->l.number; + expr->kind = NODE_UNARY_OP_1; + expr->r.expr = expr->l.expr; + expr->v.number = F_VOID_ASSIGN_LOCAL; + expr->l.number = tmp; + } else expr->v.number = F_VOID_ASSIGN; + return expr; + case F_ADD_EQ: + expr->v.number = F_VOID_ADD_EQ; + return expr; + } + break; + case NODE_PARAMETER: + case NODE_ANON_FUNC: /* some dweeb threw away one? */ + case NODE_FUNCTION_CONSTRUCTOR: + return 0; + case NODE_NUMBER: + case NODE_STRING: + case NODE_REAL: + return 0; + } + CREATE_UNARY_OP(replacement, F_POP_VALUE, 0, expr); + return replacement; +} + +parse_node_t *pop_value (parse_node_t * pn) { + if (pn) { + parse_node_t *ret = insert_pop_value(pn); + + if (!ret) { + if (pn->kind == NODE_BINARY_OP && pn->v.number >= F_EQ && + pn->v.number <= F_GT) + yywarn("Value of conditional expression is unused"); + else + yywarn("Expression has no side effects, and the value is unused"); + } + return ret; + } + + return 0; +} + +int is_boolean (parse_node_t * pn) { + switch (pn->kind) { + case NODE_UNARY_OP: + if (pn->v.number == F_NOT) + return 1; + return 0; + case NODE_BINARY_OP: + if (pn->v.number >= F_EQ && pn->v.number <= F_GT) + return 1; + return 0; + case NODE_LAND_LOR: + case NODE_BRANCH_LINK: + return 1; + } + return 0; +} + +parse_node_t *optimize_loop_test (parse_node_t * pn) { + parse_node_t *ret; + + if (!pn) return 0; + + if (IS_NODE(pn, NODE_BINARY_OP, F_LT) && + IS_NODE(pn->l.expr, NODE_OPCODE_1, F_LOCAL)) { + if (IS_NODE(pn->r.expr, NODE_OPCODE_1, F_LOCAL)) { + CREATE_OPCODE_2(ret, F_LOOP_COND_LOCAL, 0, + pn->l.expr->l.number, + pn->r.expr->l.number); + } else if (pn->r.expr->kind == NODE_NUMBER) { + CREATE_OPCODE_2(ret, F_LOOP_COND_NUMBER, 0, + pn->l.expr->l.number, + pn->r.expr->v.number); + } else + ret = pn; + } else if (IS_NODE(pn, NODE_UNARY_OP, F_POST_DEC) && + IS_NODE(pn->r.expr, NODE_OPCODE_1, F_LOCAL_LVALUE)) { + long lvar = pn->r.expr->l.number; + CREATE_OPCODE_1(ret, F_WHILE_DEC, 0, lvar); + } else + ret = pn; + + return ret; +} + + + + + + + + diff --git a/fluffos-2.23-ds03/trees.h b/fluffos-2.23-ds03/trees.h new file mode 100644 index 0000000..14f704e --- /dev/null +++ b/fluffos-2.23-ds03/trees.h @@ -0,0 +1,279 @@ +/* + * Defines and types for the compiler parse trees. + */ + +#ifndef _TREES_H +#define _TREES_H +#include "std.h" +#define NODES_PER_BLOCK 256 + +enum node_type { + NODE_RETURN, NODE_TWO_VALUES, NODE_OPCODE, NODE_OPCODE_1, NODE_OPCODE_2, + NODE_UNARY_OP, NODE_UNARY_OP_1, NODE_BINARY_OP, NODE_BINARY_OP_1, + NODE_TERNARY_OP, NODE_TERNARY_OP_1, NODE_CONTROL_JUMP, NODE_LOOP, + NODE_CALL, NODE_CALL_1, NODE_CALL_2, NODE_LAND_LOR, NODE_FOREACH, + NODE_LVALUE_EFUN, NODE_SWITCH_RANGES, NODE_SWITCH_STRINGS, + NODE_SWITCH_DIRECT, NODE_SWITCH_NUMBERS, NODE_CASE_NUMBER, + NODE_CASE_STRING, NODE_DEFAULT, NODE_IF, NODE_BRANCH_LINK, NODE_PARAMETER, + NODE_PARAMETER_LVALUE, NODE_EFUN, NODE_ANON_FUNC, NODE_REAL, NODE_NUMBER, + NODE_STRING, NODE_FUNCTION_CONSTRUCTOR, NODE_CATCH, NODE_TIME_EXPRESSION, + NODE_FUNCTION +}; + +enum control_jump_type { + CJ_BREAK_SWITCH = 2, CJ_BREAK = 0, CJ_CONTINUE = 1 +}; + +union parse_value { + long number; + float real; + struct parse_node_s *expr; +}; + +typedef struct parse_node_s { + short kind; +#if !defined(USE_32BIT_ADDRESSES) + short line; +#else + unsigned int line; +#endif + unsigned char type; + union parse_value v, l, r; /* left, right, and value */ +} parse_node_t; + +typedef struct parse_node_block_s { + struct parse_node_block_s *next; + parse_node_t nodes[NODES_PER_BLOCK]; +} parse_node_block_t; + +#define IS_NODE(vn, nt, op) ((vn)->kind == nt && (vn)->v.number == op) + +#define CREATE_TERNARY_OP(vn, op, t, x, y, z) SAFE(\ + (vn) = new_node();\ + (vn)->kind = NODE_TERNARY_OP;\ + INT_CREATE_TERNARY_OP(vn, op, t,\ + x, y, z);\ + ) +#define INT_CREATE_TERNARY_OP(vn, op, t, x, y, z) SAFE(\ + (vn)->l.expr = (x);\ + (vn)->type = t;\ + CREATE_BINARY_OP((vn)->r.expr, op, t, y, z);\ + ) +#define CREATE_BINARY_OP(vn, op, t, x, y) SAFE(\ + (vn) = new_node();\ + (vn)->kind = NODE_BINARY_OP;\ + INT_CREATE_BINARY_OP(vn, op,\ + t, x, y);\ + ) +#define INT_CREATE_BINARY_OP(vn, op, t, x, y) SAFE(\ + INT_CREATE_UNARY_OP(vn, op,\ + t, y);\ + (vn)->l.expr = x;\ + ) +#define CREATE_UNARY_OP(vn, op, t, x) SAFE(\ + (vn) = new_node();\ + (vn)->kind = NODE_UNARY_OP;\ + INT_CREATE_UNARY_OP(vn, op, t, x);\ + ) +#define INT_CREATE_UNARY_OP(vn, op, t, x) SAFE(\ + INT_CREATE_OPCODE(vn, op, t);\ + (vn)->r.expr = x;\ + ) +#define CREATE_OPCODE(vn, op, t) SAFE(\ + (vn) = new_node();\ + (vn)->kind = NODE_OPCODE;\ + INT_CREATE_OPCODE(vn, op, t);\ + ) +#define INT_CREATE_OPCODE(vn, op, t) SAFE(\ + (vn)->v.number = op;\ + (vn)->type = t;\ + ) + +#define CREATE_OPCODE_1(vn, op, t, p) SAFE(\ + (vn) = new_node();\ + (vn)->kind = NODE_OPCODE_1;\ + INT_CREATE_OPCODE(vn, op, t);\ + (vn)->l.number = p;\ + ) +#define CREATE_OPCODE_2(vn, op, t, p1, p2) SAFE(\ + (vn) = new_node();\ + (vn)->kind = NODE_OPCODE_2;\ + INT_CREATE_OPCODE(vn, op, t);\ + (vn)->l.number = p1;\ + (vn)->r.number = p2;\ + ) +#define CREATE_UNARY_OP_1(vn, op, t, x, p) SAFE(\ + (vn) = new_node();\ + (vn)->kind = NODE_UNARY_OP_1;\ + INT_CREATE_UNARY_OP(vn,\ + op, t, x);\ + (vn)->l.number = p;\ + ) +#define CREATE_BINARY_OP_1(vn, op, t, x, y, p) SAFE(\ + (vn) = new_node();\ + (vn)->kind = NODE_BINARY_OP_1;\ + INT_CREATE_BINARY_OP(vn, op,\ + t, x, y);\ + (vn)->type = p;\ + ) +#define CREATE_TERNARY_OP_1(vn, op, t, x, y, z, p) SAFE(\ + (vn) = new_node();\ + (vn)->kind = NODE_TERNARY_OP_1;\ + INT_CREATE_TERNARY_OP(vn, op, t,\ + x, y, z);\ + (vn)->r.expr->type = p;\ + ) +#define CREATE_RETURN(vn, val) SAFE(\ + (vn) = new_node_no_line();\ + (vn)->kind = NODE_RETURN;\ + (vn)->r.expr = val;\ + ) +#define CREATE_LAND_LOR(vn, op, x, y) SAFE(\ + (vn) = new_node();\ + (vn)->kind = NODE_LAND_LOR;\ + (vn)->v.number = op;\ + (vn)->l.expr = x;\ + (vn)->r.expr = y;\ + (vn)->type = ((x->type == y->type)\ + ? x->type : TYPE_ANY);\ + ) +#define CREATE_CALL(vn, op, t, el) SAFE(\ + (vn) = el;\ + (vn)->kind = NODE_CALL;\ + (vn)->l.number = (vn)->v.number;\ + (vn)->v.number = op;\ + (vn)->type = t;\ + ) +#define CREATE_STATEMENTS(vn, ln, rn) SAFE(\ + (vn) = new_node_no_line();\ + (vn)->kind = NODE_TWO_VALUES;\ + (vn)->l.expr = ln;\ + (vn)->r.expr = rn;\ + ) +#define CREATE_TWO_VALUES(vn, t, ln, rn) SAFE(\ + CREATE_STATEMENTS(vn, ln, rn);\ + (vn)->type = t;\ + ) +#define CREATE_CONTROL_JUMP(vn, op) SAFE(\ + (vn) = new_node_no_line();\ + (vn)->kind = NODE_CONTROL_JUMP;\ + (vn)->v.number = op;\ + ) +#define CREATE_PARAMETER(vn, t, p) SAFE(\ + (vn) = new_node_no_line();\ + (vn)->kind = NODE_PARAMETER;\ + (vn)->type = t;\ + (vn)->v.number = p;\ + ) +#define CREATE_IF(vn, c, s, e) SAFE(\ + (vn) = new_node_no_line();\ + (vn)->kind = NODE_IF;\ + (vn)->v.expr = c;\ + (vn)->l.expr = s;\ + (vn)->r.expr = (e);\ + ) + +#define CREATE_IGNORE(vn, c,s,e) SAFE(\ + (vn) = new_node_no_line();\ + (vn)->kind = NODE_IGNORE;\ + (vn)->v.expr = c;\ + (vn)->l.expr = s;\ + (vn)->r.expr = (e);\ + ) + +#define CREATE_LOOP(vn, tf, b, i, t) SAFE(\ + (vn) = new_node_no_line();\ + (vn)->kind = NODE_LOOP;\ + (vn)->type = tf;\ + (vn)->v.expr = b;\ + (vn)->l.expr = i;\ + (vn)->r.expr = t;\ + ) +#define CREATE_LVALUE_EFUN(vn, t, lvl) SAFE(\ + (vn) = new_node();\ + (vn)->kind = NODE_LVALUE_EFUN;\ + (vn)->r.expr = lvl;\ + (vn)->type = t;\ + ) +#define CREATE_FOREACH(vn, ln, rn) SAFE(\ + (vn) = new_node();\ + (vn)->kind = NODE_FOREACH;\ + (vn)->l.expr = ln;\ + (vn)->r.expr = rn;\ + ) +#define CREATE_ERROR(vn) SAFE(\ + (vn) = new_node_no_line();\ + (vn)->kind = NODE_NUMBER;\ + (vn)->type = TYPE_ANY;\ + ) +#define CREATE_REAL(vn, val) SAFE(\ + (vn) = new_node_no_line();\ + (vn)->kind = NODE_REAL;\ + (vn)->type = TYPE_REAL;\ + (vn)->v.real = val;\ + ) +#define CREATE_NUMBER(vn, val) SAFE(\ + (vn) = new_node_no_line();\ + (vn)->kind = NODE_NUMBER;\ + (vn)->type = (val ? TYPE_NUMBER : TYPE_ANY);\ + (vn)->v.number = val;\ + ) +#define CREATE_STRING(vn, val) SAFE(\ + (vn) = new_node_no_line();\ + (vn)->kind = NODE_STRING;\ + (vn)->type = TYPE_STRING;\ + (vn)->v.number = store_prog_string(val);\ + ) +#define CREATE_EXPR_LIST(vn, pn) SAFE(\ + (vn) = new_node();\ + (vn)->v.number = (pn ? ((parse_node_t *)pn)->kind : 0);\ + (vn)->l.expr = (pn ? ((parse_node_t *)pn)->l.expr : (vn));\ + (vn)->r.expr = pn;\ + ) +#define CREATE_EXPR_NODE(vn, pn, f) SAFE(\ + (vn) = new_node_no_line();\ + (vn)->v.expr = pn;\ + (vn)->l.expr = vn;\ + (vn)->r.expr = 0;\ + (vn)->type = f;\ + ) +#define CREATE_CATCH(vn, pn) SAFE(\ + (vn) = new_node();\ + (vn)->kind = NODE_CATCH;\ + (vn)->type = TYPE_ANY;\ + (vn)->r.expr = pn;\ + ) +#define CREATE_TIME_EXPRESSION(vn, pn) SAFE(\ + (vn) = new_node();\ + (vn)->kind = NODE_TIME_EXPRESSION;\ + (vn)->type = TYPE_ANY;\ + (vn)->r.expr = pn;\ + ) + +#define NODE_NO_LINE(x,y) SAFE(\ + (x) = new_node_no_line();\ + (x)->kind = y;\ + ) + +/* tree functions */ +void free_tree (void); +void release_tree (void); +void lock_expressions (void); +void unlock_expressions (void); +/* node functions */ +parse_node_t *new_node (void); +parse_node_t *new_node_no_line (void); +parse_node_t *make_branched_node (short, char, + parse_node_t *, parse_node_t *); +/* parser grammar functions */ +parse_node_t *binary_int_op (parse_node_t *, parse_node_t *, + char, const char *); +parse_node_t *make_range_node (int, parse_node_t *, + parse_node_t *, + parse_node_t *); +parse_node_t *insert_pop_value (parse_node_t *); +parse_node_t *pop_value (parse_node_t *); +parse_node_t *optimize_loop_test (parse_node_t *); +int is_boolean (parse_node_t *); + +#endif diff --git a/fluffos-2.23-ds03/uvalarm.c b/fluffos-2.23-ds03/uvalarm.c new file mode 100644 index 0000000..c6106f8 --- /dev/null +++ b/fluffos-2.23-ds03/uvalarm.c @@ -0,0 +1,62 @@ +#include "std.h" +#include "uvalarm.h" +#ifndef WIN32 +/* + * Copyright (c) 1985 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)ualarm.c 5.5 (Berkeley) 2/23/91"; +#endif /* LIBC_SCCS and not lint */ + +#define USPS 1000000 /* # of microseconds in a second */ + +/* + * Generate a SIGALRM signal in ``usecs'' microseconds. + * If ``reload'' is non-zero, keep generating SIGALRM + * every ``reload'' microseconds after the first signal. + */ +unsigned uvalarm (unsigned int usecs, unsigned int reload) { + struct itimerval newv, old; + + newv.it_interval.tv_usec = reload % USPS; + newv.it_interval.tv_sec = reload / USPS; + + newv.it_value.tv_usec = usecs % USPS; + newv.it_value.tv_sec = usecs / USPS; + + if (setitimer(ITIMER_VIRTUAL, &newv, &old) == 0) + return old.it_value.tv_sec * USPS + old.it_value.tv_usec; + /* else */ + return -1; +} +#endif diff --git a/fluffos-2.23-ds03/uvalarm.h b/fluffos-2.23-ds03/uvalarm.h new file mode 100644 index 0000000..784a844 --- /dev/null +++ b/fluffos-2.23-ds03/uvalarm.h @@ -0,0 +1 @@ +unsigned uvalarm(unsigned int, unsigned int); diff --git a/fluffos-2.23-ds03/windows/README.win32 b/fluffos-2.23-ds03/windows/README.win32 new file mode 100644 index 0000000..25110e1 --- /dev/null +++ b/fluffos-2.23-ds03/windows/README.win32 @@ -0,0 +1,36 @@ + MudOS for Windows 95 and Windows NT + Port by George Reese (Descartes of Borg) + +This port has a few crashers in it. Known bugs include: + * connect() gives an WASEWOULDBLOCK error (*boggle*) + for connecting to the address server or socket efuns + * bug in reading DOS files (files with \r\n) + this is probably fixed in v21.6 + * some bug in call outs + * Right now the proper calls to WSAGetLastError() are not made + +This is not a simple compile yet, unfortunately. Perhaps someone can +fix the above bugs and simplify the make process? If so, please mail +your fixes to beek@imaginary.com. + +To compile MudOS for Windows NT/95, you need: +MS VC++ 2.0 or later (dunno about Borland or other compilers) +gnu bison and sed, get them from ftp.cc.utexas.edu in the winnt section + +Steps: +0. move the .mak and .bat files in this directory to the main source directory + and run CLEAN.BAT - this removes all files generated during compile +1. Open up edit_source.mak +2. From the command prompt run STEP1.BAT +3. Build edit_source.exe +4. From the DOS command line, execute STEPDBG.BAT (in case you're building + debug version) or STEPREL.BAT (in case you're building release ver) +5. Open up mudos.mak +6. Build mudos.exe +7. Open addr_server.mak +8. Build addr_server.exe +9. Install your lib and run mudos + +Note: if you want to create a DEBUG version of MudOS you have to define +DEBUG symbol either in STD.H or in project setting in both EDIT_SOURCE and +MUDOS. \ No newline at end of file diff --git a/fluffos-2.23-ds03/windows/addr_server.mak b/fluffos-2.23-ds03/windows/addr_server.mak new file mode 100644 index 0000000..0d474c9 --- /dev/null +++ b/fluffos-2.23-ds03/windows/addr_server.mak @@ -0,0 +1,196 @@ +# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=Win32 Debug +!MESSAGE No configuration specified. Defaulting to Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "addr_server.mak" CFG="Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "Win32 Debug" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "WinRel" +# PROP BASE Intermediate_Dir "WinRel" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "WinRel" +# PROP Intermediate_Dir "WinRel" +OUTDIR=.\WinRel +INTDIR=.\WinRel + +ALL : $(OUTDIR)/addr_server.exe $(OUTDIR)/addr_server.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +CPP_PROJ=/nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\ + /FR$(INTDIR)/ /Fp$(OUTDIR)/"addr_server.pch" /Fo$(INTDIR)/ /c +CPP_OBJS=.\WinRel/ +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"addr_server.bsc" +BSC32_SBRS= \ + $(INTDIR)/addr_server.sbr \ + $(INTDIR)/port.sbr \ + $(INTDIR)/socket_ctrl.sbr + +$(OUTDIR)/addr_server.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\ + odbccp32.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:no\ + /PDB:$(OUTDIR)/"addr_server.pdb" /MACHINE:I386 /OUT:$(OUTDIR)/"addr_server.exe"\ + +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/addr_server.obj \ + $(INTDIR)/port.obj \ + $(INTDIR)/socket_ctrl.obj + +$(OUTDIR)/addr_server.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "WinDebug" +# PROP BASE Intermediate_Dir "WinDebug" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "WinDebug" +# PROP Intermediate_Dir "WinDebug" +OUTDIR=.\WinDebug +INTDIR=.\WinDebug + +ALL : $(OUTDIR)/addr_server.exe $(OUTDIR)/addr_server.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "WIN95" /FR /c +CPP_PROJ=/nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D\ + "WIN95" /FR$(INTDIR)/ /Fp$(OUTDIR)/"addr_server.pch" /Fo$(INTDIR)/\ + /Fd$(OUTDIR)/"addr_server.pdb" /c +CPP_OBJS=.\WinDebug/ +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"addr_server.bsc" +BSC32_SBRS= \ + $(INTDIR)/addr_server.sbr \ + $(INTDIR)/port.sbr \ + $(INTDIR)/socket_ctrl.sbr + +$(OUTDIR)/addr_server.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +# SUBTRACT LINK32 /PDB:none +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\ + odbccp32.lib wsock32.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:yes\ + /PDB:$(OUTDIR)/"addr_server.pdb" /DEBUG /MACHINE:I386\ + /OUT:$(OUTDIR)/"addr_server.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/addr_server.obj \ + $(INTDIR)/port.obj \ + $(INTDIR)/socket_ctrl.obj + +$(OUTDIR)/addr_server.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Group "Source Files" + +################################################################################ +# Begin Source File + +SOURCE=.\addr_server.c + +$(INTDIR)/addr_server.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\port.c +DEP_PORT_=\ + .\std.h\ + .\port.h\ + .\lint.h + +$(INTDIR)/port.obj : $(SOURCE) $(DEP_PORT_) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\socket_ctrl.c +DEP_SOCKE=\ + .\std.h + +$(INTDIR)/socket_ctrl.obj : $(SOURCE) $(DEP_SOCKE) $(INTDIR) + +# End Source File +# End Group +# End Project +################################################################################ diff --git a/fluffos-2.23-ds03/windows/clean.bat b/fluffos-2.23-ds03/windows/clean.bat new file mode 100644 index 0000000..5d5812a --- /dev/null +++ b/fluffos-2.23-ds03/windows/clean.bat @@ -0,0 +1,14 @@ +del efunction*.h +del efun_d*.c +del efun_p*.h +del func_s*.cpp +del grammar_tab.c +del grammar_tab.h +del grammar.y +del make_f*.c +del malloc.c +del mallocwrapper.c +del opc.h +del opcodes.h +del option_defs.* +del configure.h \ No newline at end of file diff --git a/fluffos-2.23-ds03/windows/configure.h b/fluffos-2.23-ds03/windows/configure.h new file mode 100644 index 0000000..501790e --- /dev/null +++ b/fluffos-2.23-ds03/windows/configure.h @@ -0,0 +1,17 @@ +#define INCL_STDLIB_H +#define INCL_TIME_H +#define INCL_FCNTL_H +#define INCL_DOS_H +#define INCL_SYS_STAT_H +#define INCL_LIMITS_H +#define USE_STRUCT_DIRENT +#define INCL_STDARG_H +#define HAS_MEMMOVE +#define RAND +#define HAS_STRERROR +#define HAS_GETCWD + +#define SIZEOF_INT 4 +#define SIZEOF_PTR 4 +#define SIZEOF_SHORT 2 +#define SIZEOF_FLOAT 4 diff --git a/fluffos-2.23-ds03/windows/edit_source.mak b/fluffos-2.23-ds03/windows/edit_source.mak new file mode 100644 index 0000000..da8a749 --- /dev/null +++ b/fluffos-2.23-ds03/windows/edit_source.mak @@ -0,0 +1,200 @@ +# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=Win32 Debug +!MESSAGE No configuration specified. Defaulting to Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "edit_source.mak" CFG="Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "Win32 Debug" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "WinRel" +# PROP BASE Intermediate_Dir "WinRel" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "WinRel" +# PROP Intermediate_Dir "WinRel" +OUTDIR=.\WinRel +INTDIR=.\WinRel + +ALL : $(OUTDIR)/edit_source.exe $(OUTDIR)/edit_source.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +CPP_PROJ=/nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\ + /FR$(INTDIR)/ /Fp$(OUTDIR)/"edit_source.pch" /Fo$(INTDIR)/ /c +CPP_OBJS=.\WinRel/ +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"edit_source.bsc" +BSC32_SBRS= \ + $(INTDIR)/edit_source.sbr \ + $(INTDIR)/hash.sbr \ + $(INTDIR)/make_func_tab.sbr + +$(OUTDIR)/edit_source.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\ + odbccp32.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:no\ + /PDB:$(OUTDIR)/"edit_source.pdb" /MACHINE:I386 /OUT:$(OUTDIR)/"edit_source.exe"\ + +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/edit_source.obj \ + $(INTDIR)/hash.obj \ + $(INTDIR)/make_func_tab.obj + +$(OUTDIR)/edit_source.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "WinDebug" +# PROP BASE Intermediate_Dir "WinDebug" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "WinDebug" +# PROP Intermediate_Dir "WinDebug" +OUTDIR=.\WinDebug +INTDIR=.\WinDebug + +ALL : $(OUTDIR)/edit_source.exe $(OUTDIR)/edit_source.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "WIN95" /D "EDIT_SOURCE" /D "DEBUG" /FR /c +CPP_PROJ=/nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D\ + "WIN95" /D "EDIT_SOURCE" /D "DEBUG" /FR$(INTDIR)/\ + /Fp$(OUTDIR)/"edit_source.pch" /Fo$(INTDIR)/ /Fd$(OUTDIR)/"edit_source.pdb" /c +CPP_OBJS=.\WinDebug/ +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"edit_source.bsc" +BSC32_SBRS= \ + $(INTDIR)/edit_source.sbr \ + $(INTDIR)/hash.sbr \ + $(INTDIR)/make_func_tab.sbr + +$(OUTDIR)/edit_source.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\ + odbccp32.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:yes\ + /PDB:$(OUTDIR)/"edit_source.pdb" /DEBUG /MACHINE:I386\ + /OUT:$(OUTDIR)/"edit_source.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/edit_source.obj \ + $(INTDIR)/hash.obj \ + $(INTDIR)/make_func_tab.obj + +$(OUTDIR)/edit_source.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Group "Source Files" + +################################################################################ +# Begin Source File + +SOURCE=.\edit_source.c + +$(INTDIR)/edit_source.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\hash.c + +$(INTDIR)/hash.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\make_func_tab.c +DEP_MAKE_=\ + .\std.h\ + .\make_func.h\ + .\lex.h\ + .\preprocess.h\ + .\edit_source.h + +$(INTDIR)/make_func_tab.obj : $(SOURCE) $(DEP_MAKE_) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\local_options +# End Source File +# End Group +# End Project +################################################################################ diff --git a/fluffos-2.23-ds03/windows/mudos.mak b/fluffos-2.23-ds03/windows/mudos.mak new file mode 100644 index 0000000..ec6ced4 --- /dev/null +++ b/fluffos-2.23-ds03/windows/mudos.mak @@ -0,0 +1,944 @@ +# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=Win32 Debug +!MESSAGE No configuration specified. Defaulting to Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "MudOS.mak" CFG="Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "Win32 Debug" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "WinRel" +# PROP BASE Intermediate_Dir "WinRel" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "WinRel" +# PROP Intermediate_Dir "WinRel" +OUTDIR=.\WinRel +INTDIR=.\WinRel + +ALL : $(OUTDIR)/MudOS.exe $(OUTDIR)/MudOS.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /G4 /MT /W3 /GX /YX /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "WIN95" /FR /c +CPP_PROJ=/nologo /G4 /MT /W3 /GX /YX /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D\ + "WIN95" /FR$(INTDIR)/ /Fp$(OUTDIR)/"MudOS.pch" /Fo$(INTDIR)/ /c +CPP_OBJS=.\WinRel/ +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"MudOS.bsc" +BSC32_SBRS= \ + $(INTDIR)/grammar_tab.sbr \ + $(INTDIR)/lex.sbr \ + $(INTDIR)/main.sbr \ + $(INTDIR)/rc.sbr \ + $(INTDIR)/interpret.sbr \ + $(INTDIR)/simulate.sbr \ + $(INTDIR)/file.sbr \ + $(INTDIR)/object.sbr \ + $(INTDIR)/backend.sbr \ + $(INTDIR)/array.sbr \ + $(INTDIR)/mapping.sbr \ + $(INTDIR)/ed.sbr \ + $(INTDIR)/comm.sbr \ + $(INTDIR)/regexp.sbr \ + $(INTDIR)/swap.sbr \ + $(INTDIR)/buffer.sbr \ + $(INTDIR)/crc32.sbr \ + $(INTDIR)/malloc.sbr \ + $(INTDIR)/class.sbr \ + $(INTDIR)/efuns_main.sbr \ + $(INTDIR)/call_out.sbr \ + $(INTDIR)/otable.sbr \ + $(INTDIR)/dumpstat.sbr \ + $(INTDIR)/stralloc.sbr \ + $(INTDIR)/port.sbr \ + $(INTDIR)/reclaim.sbr \ + $(INTDIR)/parse.sbr \ + $(INTDIR)/simul_efun.sbr \ + $(INTDIR)/sprintf.sbr \ + $(INTDIR)/program.sbr \ + $(INTDIR)/compiler.sbr \ + $(INTDIR)/avltree.sbr \ + $(INTDIR)/icode.sbr \ + $(INTDIR)/trees.sbr \ + $(INTDIR)/generate.sbr \ + $(INTDIR)/scratchpad.sbr \ + $(INTDIR)/socket_efuns.sbr \ + $(INTDIR)/socket_ctrl.sbr \ + $(INTDIR)/qsort.sbr \ + $(INTDIR)/eoperators.sbr \ + $(INTDIR)/socket_err.sbr \ + $(INTDIR)/md.sbr \ + $(INTDIR)/strstr.sbr \ + $(INTDIR)/disassembler.sbr \ + $(INTDIR)/binaries.sbr \ + $(INTDIR)/replace_program.sbr \ + $(INTDIR)/ccode.sbr \ + $(INTDIR)/cfuns.sbr \ + $(INTDIR)/compile_file.sbr \ + $(INTDIR)/contrib.sbr \ + $(INTDIR)/sockets.sbr \ + $(INTDIR)/develop.sbr \ + $(INTDIR)/math.sbr \ + $(INTDIR)/interface.sbr \ + $(INTDIR)/hash.sbr \ + $(INTDIR)/efuns_port.sbr \ + $(INTDIR)/mallocwrapper.sbr \ + $(INTDIR)/parser.sbr \ + $(INTDIR)/crypt.sbr + +$(OUTDIR)/MudOS.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +! # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /NOLOGO /VERSION:22,32 /SUBSYSTEM:console /PDB:none /MACHINE:I386 +! # SUBTRACT LINK32 /DEBUG + LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\ +! odbccp32.lib wsock32.lib /NOLOGO /VERSION:22,32 /SUBSYSTEM:console /PDB:none\ +! /MACHINE:I386 /OUT:$(OUTDIR)/"MudOS.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/grammar_tab.obj \ + $(INTDIR)/lex.obj \ + $(INTDIR)/main.obj \ + $(INTDIR)/rc.obj \ + $(INTDIR)/interpret.obj \ + $(INTDIR)/simulate.obj \ + $(INTDIR)/file.obj \ + $(INTDIR)/object.obj \ + $(INTDIR)/backend.obj \ + $(INTDIR)/array.obj \ + $(INTDIR)/mapping.obj \ + $(INTDIR)/ed.obj \ + $(INTDIR)/comm.obj \ + $(INTDIR)/regexp.obj \ + $(INTDIR)/swap.obj \ + $(INTDIR)/buffer.obj \ + $(INTDIR)/crc32.obj \ + $(INTDIR)/malloc.obj \ + $(INTDIR)/class.obj \ + $(INTDIR)/efuns_main.obj \ + $(INTDIR)/call_out.obj \ + $(INTDIR)/otable.obj \ + $(INTDIR)/dumpstat.obj \ + $(INTDIR)/stralloc.obj \ + $(INTDIR)/port.obj \ + $(INTDIR)/reclaim.obj \ + $(INTDIR)/parse.obj \ + $(INTDIR)/simul_efun.obj \ + $(INTDIR)/sprintf.obj \ + $(INTDIR)/program.obj \ + $(INTDIR)/compiler.obj \ + $(INTDIR)/avltree.obj \ + $(INTDIR)/icode.obj \ + $(INTDIR)/trees.obj \ + $(INTDIR)/generate.obj \ + $(INTDIR)/scratchpad.obj \ + $(INTDIR)/socket_efuns.obj \ + $(INTDIR)/socket_ctrl.obj \ + $(INTDIR)/qsort.obj \ + $(INTDIR)/eoperators.obj \ + $(INTDIR)/socket_err.obj \ + $(INTDIR)/md.obj \ + $(INTDIR)/strstr.obj \ + $(INTDIR)/disassembler.obj \ + $(INTDIR)/binaries.obj \ + $(INTDIR)/replace_program.obj \ + $(INTDIR)/ccode.obj \ + $(INTDIR)/cfuns.obj \ + $(INTDIR)/compile_file.obj \ + $(INTDIR)/contrib.obj \ + $(INTDIR)/sockets.obj \ + $(INTDIR)/develop.obj \ + $(INTDIR)/math.obj \ + $(INTDIR)/interface.obj \ + $(INTDIR)/hash.obj \ + $(INTDIR)/efuns_port.obj \ + $(INTDIR)/mallocwrapper.obj \ + $(INTDIR)/parser.obj \ + $(INTDIR)/crypt.obj + +$(OUTDIR)/MudOS.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "WinDebug" +# PROP BASE Intermediate_Dir "WinDebug" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "WinDebug" +# PROP Intermediate_Dir "WinDebug" +OUTDIR=.\WinDebug +INTDIR=.\WinDebug + +ALL : $(OUTDIR)/MudOS.exe $(OUTDIR)/MudOS.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /MT /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "WIN95" /D "DEBUG" /FR /c +# SUBTRACT CPP /Gy +CPP_PROJ=/nologo /MT /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\ + /D "WIN95" /D "DEBUG" /FR$(INTDIR)/ /Fp$(OUTDIR)/"MudOS.pch" /Fo$(INTDIR)/\ + /Fd$(OUTDIR)/"MudOS.pdb" /c +CPP_OBJS=.\WinDebug/ +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"MudOS.bsc" +BSC32_SBRS= \ + $(INTDIR)/grammar_tab.sbr \ + $(INTDIR)/lex.sbr \ + $(INTDIR)/main.sbr \ + $(INTDIR)/rc.sbr \ + $(INTDIR)/interpret.sbr \ + $(INTDIR)/simulate.sbr \ + $(INTDIR)/file.sbr \ + $(INTDIR)/object.sbr \ + $(INTDIR)/backend.sbr \ + $(INTDIR)/array.sbr \ + $(INTDIR)/mapping.sbr \ + $(INTDIR)/ed.sbr \ + $(INTDIR)/comm.sbr \ + $(INTDIR)/regexp.sbr \ + $(INTDIR)/swap.sbr \ + $(INTDIR)/buffer.sbr \ + $(INTDIR)/crc32.sbr \ + $(INTDIR)/malloc.sbr \ + $(INTDIR)/class.sbr \ + $(INTDIR)/efuns_main.sbr \ + $(INTDIR)/call_out.sbr \ + $(INTDIR)/otable.sbr \ + $(INTDIR)/dumpstat.sbr \ + $(INTDIR)/stralloc.sbr \ + $(INTDIR)/port.sbr \ + $(INTDIR)/reclaim.sbr \ + $(INTDIR)/parse.sbr \ + $(INTDIR)/simul_efun.sbr \ + $(INTDIR)/sprintf.sbr \ + $(INTDIR)/program.sbr \ + $(INTDIR)/compiler.sbr \ + $(INTDIR)/avltree.sbr \ + $(INTDIR)/icode.sbr \ + $(INTDIR)/trees.sbr \ + $(INTDIR)/generate.sbr \ + $(INTDIR)/scratchpad.sbr \ + $(INTDIR)/socket_efuns.sbr \ + $(INTDIR)/socket_ctrl.sbr \ + $(INTDIR)/qsort.sbr \ + $(INTDIR)/eoperators.sbr \ + $(INTDIR)/socket_err.sbr \ + $(INTDIR)/md.sbr \ + $(INTDIR)/strstr.sbr \ + $(INTDIR)/disassembler.sbr \ + $(INTDIR)/binaries.sbr \ + $(INTDIR)/replace_program.sbr \ + $(INTDIR)/ccode.sbr \ + $(INTDIR)/cfuns.sbr \ + $(INTDIR)/compile_file.sbr \ + $(INTDIR)/contrib.sbr \ + $(INTDIR)/sockets.sbr \ + $(INTDIR)/develop.sbr \ + $(INTDIR)/math.sbr \ + $(INTDIR)/interface.sbr \ + $(INTDIR)/hash.sbr \ + $(INTDIR)/efuns_port.sbr \ + $(INTDIR)/mallocwrapper.sbr \ + $(INTDIR)/parser.sbr \ + $(INTDIR)/crypt.sbr + +$(OUTDIR)/MudOS.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +# SUBTRACT LINK32 /PDB:none +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\ + odbccp32.lib wsock32.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:yes\ + /PDB:$(OUTDIR)/"MudOS.pdb" /DEBUG /MACHINE:I386 /OUT:$(OUTDIR)/"MudOS.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/grammar_tab.obj \ + $(INTDIR)/lex.obj \ + $(INTDIR)/main.obj \ + $(INTDIR)/rc.obj \ + $(INTDIR)/interpret.obj \ + $(INTDIR)/simulate.obj \ + $(INTDIR)/file.obj \ + $(INTDIR)/object.obj \ + $(INTDIR)/backend.obj \ + $(INTDIR)/array.obj \ + $(INTDIR)/mapping.obj \ + $(INTDIR)/ed.obj \ + $(INTDIR)/comm.obj \ + $(INTDIR)/regexp.obj \ + $(INTDIR)/swap.obj \ + $(INTDIR)/buffer.obj \ + $(INTDIR)/crc32.obj \ + $(INTDIR)/malloc.obj \ + $(INTDIR)/class.obj \ + $(INTDIR)/efuns_main.obj \ + $(INTDIR)/call_out.obj \ + $(INTDIR)/otable.obj \ + $(INTDIR)/dumpstat.obj \ + $(INTDIR)/stralloc.obj \ + $(INTDIR)/port.obj \ + $(INTDIR)/reclaim.obj \ + $(INTDIR)/parse.obj \ + $(INTDIR)/simul_efun.obj \ + $(INTDIR)/sprintf.obj \ + $(INTDIR)/program.obj \ + $(INTDIR)/compiler.obj \ + $(INTDIR)/avltree.obj \ + $(INTDIR)/icode.obj \ + $(INTDIR)/trees.obj \ + $(INTDIR)/generate.obj \ + $(INTDIR)/scratchpad.obj \ + $(INTDIR)/socket_efuns.obj \ + $(INTDIR)/socket_ctrl.obj \ + $(INTDIR)/qsort.obj \ + $(INTDIR)/eoperators.obj \ + $(INTDIR)/socket_err.obj \ + $(INTDIR)/md.obj \ + $(INTDIR)/strstr.obj \ + $(INTDIR)/disassembler.obj \ + $(INTDIR)/binaries.obj \ + $(INTDIR)/replace_program.obj \ + $(INTDIR)/ccode.obj \ + $(INTDIR)/cfuns.obj \ + $(INTDIR)/compile_file.obj \ + $(INTDIR)/contrib.obj \ + $(INTDIR)/sockets.obj \ + $(INTDIR)/develop.obj \ + $(INTDIR)/math.obj \ + $(INTDIR)/interface.obj \ + $(INTDIR)/hash.obj \ + $(INTDIR)/efuns_port.obj \ + $(INTDIR)/mallocwrapper.obj \ + $(INTDIR)/parser.obj \ + $(INTDIR)/crypt.obj + +$(OUTDIR)/MudOS.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Group "Source Files" + +################################################################################ +# Begin Source File + +SOURCE=.\grammar_tab.c +DEP_GRAMM=\ + .\std.h\ + .\compiler.h\ + .\lex.h\ + .\scratchpad.h\ + .\lpc_incl.h\ + .\simul_efun.h\ + .\generate.h + +$(INTDIR)/grammar_tab.obj : $(SOURCE) $(DEP_GRAMM) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\lex.c + +$(INTDIR)/lex.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\main.c +DEP_MAIN_=\ + .\std.h + +$(INTDIR)/main.obj : $(SOURCE) $(DEP_MAIN_) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\rc.c + +$(INTDIR)/rc.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\interpret.c +DEP_INTER=\ + .\std.h + +$(INTDIR)/interpret.obj : $(SOURCE) $(DEP_INTER) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\simulate.c +DEP_SIMUL=\ + .\std.h + +$(INTDIR)/simulate.obj : $(SOURCE) $(DEP_SIMUL) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\file.c + +$(INTDIR)/file.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\object.c +DEP_OBJEC=\ + .\std.h + +$(INTDIR)/object.obj : $(SOURCE) $(DEP_OBJEC) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\backend.c + +$(INTDIR)/backend.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\array.c +DEP_ARRAY=\ + .\std.h + +$(INTDIR)/array.obj : $(SOURCE) $(DEP_ARRAY) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\mapping.c + +$(INTDIR)/mapping.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\ed.c + +$(INTDIR)/ed.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\comm.c +DEP_COMM_=\ + .\std.h\ + .\network_incl.h\ + .\lpc_incl.h\ + .\applies.h\ + .\main.h\ + .\comm.h\ + .\socket_efuns.h\ + .\backend.h\ + .\socket_ctrl.h\ + .\eoperators.h\ + .\debug.h\ + .\ed.h\ + .\file.h + +$(INTDIR)/comm.obj : $(SOURCE) $(DEP_COMM_) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\regexp.c + +$(INTDIR)/regexp.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\swap.c +DEP_SWAP_=\ + .\std.h + +$(INTDIR)/swap.obj : $(SOURCE) $(DEP_SWAP_) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\buffer.c + +$(INTDIR)/buffer.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\crc32.c +DEP_CRC32=\ + .\std.h + +$(INTDIR)/crc32.obj : $(SOURCE) $(DEP_CRC32) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\malloc.c + +$(INTDIR)/malloc.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\class.c +DEP_CLASS=\ + .\std.h + +$(INTDIR)/class.obj : $(SOURCE) $(DEP_CLASS) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\efuns_main.c + +$(INTDIR)/efuns_main.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\call_out.c +DEP_CALL_=\ + .\std.h + +$(INTDIR)/call_out.obj : $(SOURCE) $(DEP_CALL_) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\otable.c +DEP_OTABL=\ + .\std.h + +$(INTDIR)/otable.obj : $(SOURCE) $(DEP_OTABL) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\dumpstat.c +DEP_DUMPS=\ + .\std.h + +$(INTDIR)/dumpstat.obj : $(SOURCE) $(DEP_DUMPS) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\stralloc.c +DEP_STRAL=\ + .\std.h + +$(INTDIR)/stralloc.obj : $(SOURCE) $(DEP_STRAL) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\port.c +DEP_PORT_=\ + .\std.h + +$(INTDIR)/port.obj : $(SOURCE) $(DEP_PORT_) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\reclaim.c + +$(INTDIR)/reclaim.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\parse.c + +$(INTDIR)/parse.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\simul_efun.c +DEP_SIMUL_=\ + .\std.h + +$(INTDIR)/simul_efun.obj : $(SOURCE) $(DEP_SIMUL_) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\sprintf.c + +$(INTDIR)/sprintf.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\program.c +DEP_PROGR=\ + .\std.h + +$(INTDIR)/program.obj : $(SOURCE) $(DEP_PROGR) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\compiler.c +DEP_COMPI=\ + .\std.h + +$(INTDIR)/compiler.obj : $(SOURCE) $(DEP_COMPI) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\avltree.c + +$(INTDIR)/avltree.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\icode.c + +$(INTDIR)/icode.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\trees.c + +$(INTDIR)/trees.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\generate.c +DEP_GENER=\ + .\std.h + +$(INTDIR)/generate.obj : $(SOURCE) $(DEP_GENER) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\scratchpad.c +DEP_SCRAT=\ + .\std.h + +$(INTDIR)/scratchpad.obj : $(SOURCE) $(DEP_SCRAT) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\socket_efuns.c + +$(INTDIR)/socket_efuns.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\socket_ctrl.c +DEP_SOCKE=\ + .\std.h + +$(INTDIR)/socket_ctrl.obj : $(SOURCE) $(DEP_SOCKE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qsort.c + +$(INTDIR)/qsort.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\eoperators.c + +$(INTDIR)/eoperators.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\socket_err.c + +$(INTDIR)/socket_err.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\md.c +DEP_MD_C2a=\ + .\std.h + +$(INTDIR)/md.obj : $(SOURCE) $(DEP_MD_C2a) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\strstr.c + +$(INTDIR)/strstr.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\disassembler.c + +$(INTDIR)/disassembler.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\binaries.c + +$(INTDIR)/binaries.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\replace_program.c +DEP_REPLA=\ + .\std.h + +$(INTDIR)/replace_program.obj : $(SOURCE) $(DEP_REPLA) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\ccode.c + +$(INTDIR)/ccode.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\cfuns.c +DEP_CFUNS=\ + .\std.h + +$(INTDIR)/cfuns.obj : $(SOURCE) $(DEP_CFUNS) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\compile_file.c +DEP_COMPIL=\ + .\std.h + +$(INTDIR)/compile_file.obj : $(SOURCE) $(DEP_COMPIL) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\packages\contrib.c + +$(INTDIR)/contrib.obj : $(SOURCE) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\packages\sockets.c + +$(INTDIR)/sockets.obj : $(SOURCE) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\packages\develop.c + +$(INTDIR)/develop.obj : $(SOURCE) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\packages\math.c + +$(INTDIR)/math.obj : $(SOURCE) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\mudlib\interface.c + +$(INTDIR)/interface.obj : $(SOURCE) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\hash.c +DEP_HASH_=\ + .\std.h + +$(INTDIR)/hash.obj : $(SOURCE) $(DEP_HASH_) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\efuns_port.c + +$(INTDIR)/efuns_port.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\mallocwrapper.c + +$(INTDIR)/mallocwrapper.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\packages\parser.c + +$(INTDIR)/parser.obj : $(SOURCE) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\amiga\crypt.c + +$(INTDIR)/crypt.obj : $(SOURCE) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\local_options +# End Source File +# End Group +# End Project + \ No newline at end of file diff --git a/fluffos-2.23-ds03/windows/step1.bat b/fluffos-2.23-ds03/windows/step1.bat new file mode 100644 index 0000000..3bbe509 --- /dev/null +++ b/fluffos-2.23-ds03/windows/step1.bat @@ -0,0 +1,2 @@ +bison make_func.y + \ No newline at end of file diff --git a/fluffos-2.23-ds03/windows/stepdbg.bat b/fluffos-2.23-ds03/windows/stepdbg.bat new file mode 100644 index 0000000..4fbe053 --- /dev/null +++ b/fluffos-2.23-ds03/windows/stepdbg.bat @@ -0,0 +1,3 @@ +.\windebug\edit_source -configure +.\windebug\edit_source -options -process grammar.y.pre -malloc -build_func_spec "e:\lang\msdev\bin\cl /E /D "DEBUG" " -build_efuns + \ No newline at end of file diff --git a/fluffos-2.23-ds03/windows/steprel.bat b/fluffos-2.23-ds03/windows/steprel.bat new file mode 100644 index 0000000..ac494c5 --- /dev/null +++ b/fluffos-2.23-ds03/windows/steprel.bat @@ -0,0 +1,7 @@ +.\winrel\edit_source -configure +.\winrel\edit_source -options -process grammar.y.pre -malloc -build_func_spec "e:\lang\msdev\bin\cl /E" -build_efuns + +ren efun_protos.h efun_tmp.h +sed -f sed.cmd efun_tmp.h > efun_protos.h + + \ No newline at end of file diff --git a/fluffos-2.23-ds03/wrappedmalloc.c b/fluffos-2.23-ds03/wrappedmalloc.c new file mode 100644 index 0000000..726758b --- /dev/null +++ b/fluffos-2.23-ds03/wrappedmalloc.c @@ -0,0 +1,58 @@ +/* + wrapper functions for system malloc -- keep malloc stats. + Truilkan@TMI - 92/04/17 +*/ + +#define IN_MALLOC_WRAPPER +#define NO_OPCODES +#include "std.h" +#include "my_malloc.h" +#include "lpc_incl.h" +#include "comm.h" + +typedef struct stats_s { + unsigned int free_calls, alloc_calls, realloc_calls; +} stats_t; + +static stats_t stats; + +void wrappedmalloc_init() +{ + stats.free_calls = 0; + stats.alloc_calls = 0; + stats.realloc_calls = 0; +} + +INLINE void *wrappedrealloc (void * ptr, int size) +{ + stats.realloc_calls++; + return (void *) REALLOC(ptr, size); +} + +INLINE void *wrappedmalloc (int size) +{ + stats.alloc_calls++; + return (void *) MALLOC(size); +} + +INLINE void *wrappedcalloc (int nitems, int size) +{ + stats.alloc_calls++; + return (void *) CALLOC(nitems, size); +} + +INLINE void wrappedfree (void * ptr) +{ + stats.free_calls++; + FREE(ptr); +} + +void dump_malloc_data (outbuffer_t * ob) +{ + outbuf_add(ob, "using wrapped malloc:\n\n"); + outbuf_addv(ob, "#alloc calls: %10lu\n", stats.alloc_calls); + outbuf_addv(ob, "#free calls: %10lu\n", stats.free_calls); + outbuf_addv(ob, "#alloc - #free: %10lu\n", + stats.alloc_calls - stats.free_calls); + outbuf_addv(ob, "#realloc calls: %10lu\n", stats.realloc_calls); +} diff --git a/fluffos-2.23-ds03/wrappedmalloc.h b/fluffos-2.23-ds03/wrappedmalloc.h new file mode 100644 index 0000000..8f912bd --- /dev/null +++ b/fluffos-2.23-ds03/wrappedmalloc.h @@ -0,0 +1,12 @@ +#ifndef WRAPPED_MALLOC_H +#define WRAPPED_MALLOC_H +#ifdef WRAPPEDMALLOC +void *wrappedmalloc (int); +void *wrappedrealloc (void *, int); +void *wrappedcalloc (int, int); +void wrappedfree (void *); + +void wrappedmalloc_init (void); +void dump_malloc_data (outbuffer_t *); +#endif +#endif diff --git a/lib/cfg/days.cfg b/lib/cfg/days.cfg new file mode 100644 index 0000000..a9c743a --- /dev/null +++ b/lib/cfg/days.cfg @@ -0,0 +1,12 @@ +# /cfg/days.cfg +# from the Nightmare IV LPC Library +# days configuration file +# +# format: +# day + +Shadowday +Lockday +Flameday +Darkday +Vaigday diff --git a/lib/cfg/months.cfg b/lib/cfg/months.cfg new file mode 100644 index 0000000..2150c64 --- /dev/null +++ b/lib/cfg/months.cfg @@ -0,0 +1,17 @@ +# /cfg/months.cfg +# from the Nightmare IV LPC Library +# a listing of months +# +# 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 diff --git a/lib/cfg/moons.cfg b/lib/cfg/moons.cfg new file mode 100644 index 0000000..a6a9a07 --- /dev/null +++ b/lib/cfg/moons.cfg @@ -0,0 +1,10 @@ +# /cfg/moons.cfg +# from the Nightmare IV LPC Library +# configuration file for moons +# +# format: +# moon:id:description + +Laros:50000:red moon:A small, irregularly shaped red moon. +Spyefel:25000:blue moon:A large, shiny blue sphere in the sky. +Slayar:30000:green moon:A tiny little sphere that looks like it is made of cheese. diff --git a/lib/cfg/time.cfg b/lib/cfg/time.cfg new file mode 100644 index 0000000..cdeab51 --- /dev/null +++ b/lib/cfg/time.cfg @@ -0,0 +1,24 @@ +# /cmds/time.cfg +# from the Nightmare IV LPC Library +# timezones configuration file +# +# format: +# TIMEZONE_ABBRV:GMT_OFFSET:TIMEZONE_DESCRIPTION + +NZT:10:New Zealand Time +AET:9:Australian Eastern Time +AWT:7:Australian Western Time +MOT:3:Moscow Time +CET:1:Central European Time +BST:1:British Summer Time +GMT:0:Greenwich Mean Time +ADT:-3:Atlantic Daylight Time +AST:-4:Atlantic Standard Time +EDT:-4:Eastern Daylight Time +EST:-5:Eastern Standard Time +CDT:-5:Central Daylight Time +CST:-6:Central Standard Time +MDT:-6:Mountain Daylight Time +MST:-7:Mountain Standard Time +PDT:-7:Pacific Daylight Time +PST:-8:Pacific Standard Time diff --git a/lib/cfg/timezone.cfg b/lib/cfg/timezone.cfg new file mode 100644 index 0000000..e69de29 diff --git a/lib/cfg/timezones.cfg b/lib/cfg/timezones.cfg new file mode 100644 index 0000000..fe15f6d --- /dev/null +++ b/lib/cfg/timezones.cfg @@ -0,0 +1,17 @@ +NZT +AET +AWT +MOT +CET +BST +GMT +ADT +AST +EDT +EST +CDT +CST +MDT +MST +PDT +PST diff --git a/lib/cfg/where.cfg b/lib/cfg/where.cfg new file mode 100644 index 0000000..3ebd6df --- /dev/null +++ b/lib/cfg/where.cfg @@ -0,0 +1,370 @@ +# Created by Billbo Baggins esq. +# Tue Mar 30 16:08:49 BST 1993 +# +# A database for the where command +# /bin/user/_where.c +# +# num1.num2.num3.num4:location +# +# num(1-4) Can either be a number +# or '*' ( meaning any ) +# +# location Is the location of the +# telnet site +# +18.23.*.*:Stoneham, Massachusetts, United States of America +18.58.*.*:Cambridge, Massachusetts, United States of America +18.62.*.*:Cambridge, Massachusetts, United States of America +18.70.*.*:Cambridge, Massachusetts, United States of America +18.71.*.*:Cambridge, Massachusetts, United States of America +18.74.*.*:Cambridge, Massachusetts, United States of America +18.78.*.*:Cambridge, Massachusetts, United States of America +18.80.*.*:Cambridge, Massachusetts, United States of America +35.1.*.*:Ann Arbor, Michigan, United States of America +35.8.*.*:East Lansing, Michigan, United States of America +35.193.*.*:East Lansing, Michigan, United States of America +35.197.*.*:Holland, Michigan, United States of America +35.202.*.*:Ann Arbor, Michigan, United States of America +35.211.*.*:Grand Rapids, Michigan, United States of America +38.146.*.*:Silver Springs, Maryland, United States of America +128.2.*.*:Pittsburgh, Pennsylvania, United States of America +128.6.7.*:Cherry Hill, New Jersey, United States of America +128.6.13.*:Piscataway, New Jersey, United States of America +128.6.18.*:Camden, New Jersey, United States of America +128.8.*.*:Washington, District of Columbia, United States of America +128.32.*.*:Berkeley, California, United States of America +128.42.*.*:Houston, Texas, United States of America +128.55.*.*:Cedar Rapids, Iowa, United States of America +128.59.*.*:New York City, New York, United States of America +128.61.*.*:Atlanta, Georgia, United States of America +128.83.*.*:Austin, Texas, United States of America +128.95.*.*:Seattle, Washington, United States of America +204.157.*.*:Minneapolis, Minnesota, United States of America +131.201.*.*:Minneapolis, Minnesota, United States of America +204.212.*.*:San Diego, California, United States of America +199.120.*.*:Anonymous +204.246.*.*:Minneapolis, Minnesota, United States of America +128.100.*.*:Waterloo, Ontario, Canada +128.101.*.*:Minneapolis, Minnesota, United States of America +128.103.*.*:Cambridge, Massachusetts, United States of America +128.110.*.*:Salt Lake City, Utah, United States of America +128.112.*.*:Princeton, New Jersey, United States of America +128.113.*.*:Troy, New York, United States of America +128.114.*.*:Santa Cruz, California, United States of America +128.118.*.*:Erie, Pennsylvania, United States of America +128.119.*.*:Amherst, Massachusetts, United States of America +128.122.*.*:Jackson Heights, New York, United States of America +128.123.*.*:Fargo, North Dakota, United States of America +128.130.*.*:Wien, Oesterriech +128.135.*.*:Chicago, Illinois, United States of America +128.138.*.*:Boulder, Colorado, United States of America +128.140.*.*:Atlanta, Georgia, United States of America +128.143.*.*:Charlottesville, Virginia, United States of America +128.147.*.*:Plano, Texas, United States of America +128.153.*.*:Potsdam, New York, United States of America +131.107.*.*:Redmond, Washington, United States of America +128.163.*.*:Lexington, Kentucky, United States of America +128.169.*.*:Knoxville, Tennessee, United States of America +128.173.*.*:Blacksburg, Virginia, United States of America +128.174.*.*:Urbana, Illinois, United States of America +128.175.*.*:Newark, Delaware, United States of America +128.185.*.*:Westboro, Massachusetts, United States of America +128.189.*.*:Victoria, British Columbia, Canada +128.192.*.*:Columbus, Georgia, United States of America +128.193.*.*:Corvallis, Oregon, United States of America +#duplicate -- needs clarification -- Val +128.194.*.*:College Station, Texas, United States of America +128.194.*.*:Houston, Texas, United States of America +128.197.*.*:Boston, Massachusetts, United States of America +128.204.*.*:Saratoga, New York, United States of America +128.205.*.*:Buffalo, New York, United States of America +128.210.*.*:Purdue, Indiana, United States of America +128.214.*.*:Helsinki, Suomi +128.226.*.*:Binghampton, New York, United States of America +128.230.*.*:Syracuse, New York, United States of America +128.235.*.*:Newark, New Jersey, United States of America +128.248.*.*:Chicago, Illinois, United States of America +128.250.*.*:Melbourne, Victoria, Australia +128.253.*.*:Ithaca, New York, United States of America +128.255.*.*:Iowa City, Iowa, United States of America +129.2.*.*:College Park, Maryland, United States of America +129.3.*.*:Oswego, New York, United States of America +129.7.*.*:Houston, Texas, United States of America +129.10.8.180:Boston, Massachusetts, United States of America +129.10.20.*:Lynnfield, Massachusetts, United States of America +129.12.*.*:Canterbury, England, United Kingdom +129.24.*.*:Albuquerque, New Mexico, United States of America +129.25.*.*:Philadelphia, Pennsylvania, United States of America +129.31.*.*:London, England, United Kingdom +129.49.*.*:Stonybrook, New York, United States of America +129.63.*.*:North Andover, Massachusetts, United States of America +129.71.*.*:Morgantown, West Virginia, United States of America +129.74.*.*:Notre Dame, Indiana, United States of America +129.78.*.*:Sydney, New South Wales, Australia +129.79.*.*:Bloomington, Indiana, United States of America +129.81.*.*:New Orleans, Louisiana, United States of America +129.89.*.*:Milwaukee, Wisconsin, United States of America +129.97.*.*:Waterloo, Ontario, Canada +129.100.*.*:London, Ontario, Canada +129.101.*.*:Moscow, Idaho, United States of America +129.106.*.*:Houston, Texas, United States of America +129.107.*.*:Arlington, Texas, United States of America +129.110.*.*:Dallas, Texas, United States of America +129.115.*.*:San Antonio, Texas, United States of America +129.118.*.*:Lubbock, Texas, United States of America +129.123.*.*:Logan, Utah, United States of America +129.127.*.*:Adelaide, South Australia, Australia +129.128.*.*:Edmonton, Alberta, Canada +129.130.*.*:Manhattan, Kansas, United States of America +129.132.*.*:Zuerich, Schweiz +129.133.*.*:Middletown, Connecticut, United States of America +129.138.*.*:Socorro, New Mexico, United States of America +129.142.*.*:Aarhus, Danmark +129.143.*.*:Muelheim, Duesseldorf, Deutschland +129.162.*.*:San Antonio, Texas, United States of America +129.170.*.*:Hanover, New Hampshire, United States of America +129.173.*.*:Halifax, Nova Scotia, Canada +129.174.*.*:Washington, District of Columbia, United States of America +129.177.*.*:Bergen, Norge +129.186.*.*:Ames, Iowa, United States of America +129.217.*.*:Dortmund, Nordrhein-Westfalen, Deutschland +129.234.*.*:Durham, England, United Kingdom +129.252.*.*:Columbia, South Carolina, United States of America +130.15.*.*:Kingston, Ontario, Canada +130.18.*.*:Starksville, Mississippi, United States of America +130.49.*.*:Pittsburgh, Pennsylvania, United States of America +130.60.*.*:Zuerich, Schweiz +130.64.*.*:Boston, Massachusetts, United States of America +130.70.*.*:Lafayette, Louisiana, United States of America +130.88.*.*:Manchester, England, United Kingdom +130.95.*.*:Perth, Western Australia, Australia +130.102.*.*:Brisbane, Queensland, Australia +130.105.*.*:Cambridge, Massachusetts, United States of America +130.111.32.*:Orono, Maine. United States of America +130.111.160.*:Augusta, Maine, United States of America +130.115.*.*:Rotterdam, Nederland +130.132.*.*:New Haven, Connecticut, United States of America +130.159.*.*:Glasgow, Scotland, United Kingdom +130.160.*.*:Tuscaloosa, Alabama, United States of America +130.179.*.*:Winnipeg, Manitoba, Canada +130.184.*.*:Fayetteville, Arkansas, United States of America +130.194.*.*:Churchill, Victoria, Australia +130.199.*.*:Upton, New York, United States of America +130.209.*.*:Glasgow, Scotland, United Kingdom +130.215.*.*:Worcester, Massachusetts, United States of America +130.225.*.*:Aalborg, Danmark +130.234.*.*:Jyvaskyla, Suomi +130.236.*.*:Linkoping, Sverige +130.237.*.*:Stockholm, Sverige +130.238.*.*:Uppsala, Sverige +130.239.*.*:Sundswall, Sverige +131.95.*.*:Hattiesburg, Mississippi, United States of America +131.104.*.*:Guelph, Ontario, Canada +131.118.*.*:Baltimore, Maryland, United States of America +131.121.*.*:Annapolis, Maryland, United States of America +131.123.*.*:Akron, Ohio, United States of America +131.144.*.*:Atlanta, Georgia, United States of America +131.172.*.*:Melbourne, Victoria, Australia +131.174.*.*:Nijmegen, Nederland +131.178.*.*:Monterrey, Nuevo Leon, Mexico +131.210.*.*:Kenosha, Wisconsin, United States of America +131.215.*.*:Pasadena, California, United States of America +131.225.*.*:Aurora, Illinois, United States of America +131.229.*.*:North Hampton, Massachusetts, United States of America +131.231.*.*:Southampton, England, United Kingdom +131.234.*.*:Paderborn, Deutschland +131.246.*.*:Kaiserslautern, Deutschland +131.252.*.*:Portland, Oregon, United States of America +132.67.*.*:Tel Aviv, Israel +132.68.*.*:Haifa, Israel +132.136.*.*:Ithaca, New York, United States of America +132.147.*.*:Santa Cruz, California, United States of America +132.162.*.*:Oberlin, Ohio, United States of America +132.177.*.*:Durham, New Hampshire, United States of America +132.181.*.*:Christchurch, New Zealand +132.205.*.*:Montreal, Quebec, Canada +205.134.198.*:Bellevue, Washington, United States of America +132.206.*.*:Montreal, Quebec, Canada +132.236.*.*:Ithaca, New York, United States of America +132.241.*.*:Chico, California, United States of America +134.3.*.*:Waxahachie, Texas, United States of America +134.7.*.*:Perth, Western Australia, Australia +134.10.*.*:Portland, Oregon, United States of America +134.29.*.*:Winona, Minnesota, United States of America +134.36.*.*:Dundee, Scotland, United Kingdom +134.40.*.*:Dundee, Scotland, United Kingdom +134.53.*.*:Oxford, Ohio, United States of America +134.68.*.*:Indianapolis, Indiana, United States of America +134.71.*.*:Alhambra, California, United States of America +134.74.*.*:New York City, New York, United States of America +134.79.*.*:Menlo Park, California, United States of America +134.82.*.*:Lewisburg, Pennsylvania, United States of America +134.83.*.*:Brunel, England, United Kingdom +134.84.*.*:Saint Paul, Minnesota, United States of America +134.87.*.*:Vancouver, British Columbia, Canada +134.88.*.*:Dartmouth, Massachusetts, United States of America +134.91.*.*:Muelheim, Dusseldorf, Deutschland +134.121.*.*:Pulman, Washington, United States of America +134.124.*.*:St. Louis, Missouri, United States of America +134.129.*.*:Oswego, New York, United States of America +134.153.*.*:St. John's, Newfoundland, Canada +134.161.*.*:Cedar Falls, Iowa, United States of America +134.169.*.*:Braunschweig, Deutschland +134.176.*.*:Giessen, Deutschland +134.181.*.*:Lewiston, Maine, United States of America +134.192.*.*:Annapolis, Maryland, United States of America +134.193.*.*:Kansas City, Missouri, United States of America +134.206.*.*:Villeneuve d'Ascq, Nord, France +134.225.*.*:Reading, England, United Kingdom +134.241.*.*:Amherst, Massachusetts, United States of America +136.142.*.*:Pittsburgh, Pennsylvania, United States of America +136.145.*.*:Rio Piedras, Puerto Rico +136.167.*.*:Boston, Massachusetts, United States of America +136.204.*.*:Morrisville, New York, United States of America +136.227.*.*:Springfield, Ohio, United States of America +136.242.*.*:Washington, District of Columbia, United States of America +137.52.*.*:Hollywood, Florida, United States of America +137.82.*.*:Vancouver, British Columbia, Canada +137.99.*.*:Storrs, Connecticut, United States of America +137.122.*.*:Ottawa, Ontario, Canada +137.132.*.*:Singapore City, Singapore +137.141.*.*:Oneonta, New York, United States of America +137.142.*.*:Albany, New York, United States of America +137.143.*.*:Potsdam, New York, United States of America +137.148.*.*:Cleveland, Ohio, United States of America +137.161.*.*:Portland, Oregon, United States of America +137.195.*.*:Edinburgh, Scotland, United Kingdom +137.208.*.*:Wien, Oesterriech +137.219.*.*:Townsville, Queensland, Australia +137.238.*.*:Geneseo, New York, United States of America +138.25.*.*:Sydney, New South Wales, Australia +138.38.*.*:Bath, England, United Kingdom +138.95.*.*:Beaverton, Oregon, United States of America +138.110.*.*:South Hadley, Massachusetts, United States of America +138.129.*.*:Moorhead, Minnesota, United States of America +138.251.*.*:St. Andrews, Scotland, United Kingdom +139.94.*.*:Kingsville, Texas, United States of America +139.230.*.*:Perth, Western Australia, Australia +140.104.*.*:Waukesha, Wisconsin, United States of America +140.142.*.*:Seattle, Washington, United States of America +140.146.*.*:Kenosha, Wisconsin, United States of America +140.160.*.*:Bellingham, Washington, United States of America +140.178.*.*:Poulsbo, Washington, United States of America +140.198.32.*:Glendale, Arizona, United States of America +140.198.*.*:Mesa, Arizona, United States of America +140.211.*.*:Ashland, Oregon, United States of America +140.232.*.*:Worcester, Massachusetts, United States of America +140.244.*.*:Munich, Bavaria, Deutschland +141.212.*.*:Ann Arbor, Michigan, United States of America +141.217.*.*:Detroit, Michigan, United States of America +141.218.*.*:Kalamazoo, Michigan, United States of America +142.32.*.*:Victoria, British Columbia, Canada +142.92.*.*:Ottawa, Ontario, Canada +142.104.*.*:Victoria, British Columbia, Canada +143.43.*.*:Chicago, Illinois, United States of America +143.53.*.*:Bradford, Yorkshire, England +143.54.*.*:Porto Alegre, Rio Grande do Sul, Brasil +143.117.*.*:Belfast, Ireland (occupied) +143.200.*.*:DuPere, Wisconsin, United States of America +143.210.*.*:Leicester, England, United Kingdom +144.80.*.*:Indiana, Pennsylvania, United States of America +144.92.*.*:Madison, Wisconsin, United States of America +144.175.*.*:Frederick, Maryland, United States of America +145.24.*.*:Rotterdam, Nederland +146.50.*.*:Amsterdam, Nederland +146.86.*.*:Salt Lake City, Utah, United States of America +146.87.*.*:Manchester, England, United Kingdom +146.182.*.*:Bloemfontien, Orange Free State, South Africa +146.186.*.*:University Park, Pennsylvania, United States of America +147.9.*.*:Washington, District of Columbia, United States of America +147.26.*.*:San Marcos, Texas, United States of America +147.28.*.*:Beaverton, Oregon, United States of America +147.174.*.*:Baton Rouge, Louisiana, United States of America +147.205.*.*:Oneonta, New York, United States of America +147.226.*.*:Muncie, Indiana, United States of America +149.152.*.*:Willimantic, Connecticut, United States of America +149.155.*.*:Harpenden, Hertfordshire, United Kingdom +149.171.*.*:Sydney, New South Wales, Australia +150.131.*.*:Missoula, Montana, United States of America +150.188.*.*:Caracas, Venezuela +151.103.*.*:Troy, New York, United States of America +152.1.*.*:Raleigh, North Carolina, United States of America +152.2.*.*:Chapel Hill, North Carolina, United States of America +152.10.*.*:Boone, North Carolina, United States of America +152.17.*.*:Salem, North Carolina, United States of America +153.111.*.*:Christchurch, New Zealand +155.92.*.*:Milwaukee, Wisconsin, United States of America +155.210.*.*:Zaragoza, Espana +155.245.*.*:Essex, England, United Kingdom +157.182.*.*:Morgantown, West Virginia, United States of America +157.252.*.*:Hartford, Connecticut, United States of America +158.65.*.*:Keene, New Hampshire, United States of America +158.135.*.*:Huntsville, Texas, United States of America +159.28.*.*:Richmond, Indiana, United States of America +159.230.*.*:Farmville, Virginia, United States of America +159.242.*.*:Indianapolis, Indiana, United States of America +160.91.*.*:Oak Ridge, Tennessee, United States of America +160.114.*.*:Szeged, Magyar orsza'g +161.45.*.*:Murfreesboro, Tennessee, United States of America +162.148.*.*:Seattle, Washington, United States of America +163.1.*.*:Oxford, England, United Kingdom +163.11.8.*:Philadelphia, Pennsylvania, United States of America +163.11.13.*:Cedarville, Ohio, United States of America +163.118.*.*:Melbourne, Florida, United States of America +165.247.*.*:Phoenix, Arizona, United States of America +192.31.*.*:Kelowna, British Columbia, Canada +192.34.*.*:Walla Walla, Washington, United States of America +192.41.*.*:Chicago, Illinois, United States of America +192.42.*.*:Melbourne, Florida, United States of America +192.43.*.*:Commerce, Texas, United States of America +192.48.*.*:Seattle, Washington, United States of America +192.52.*.*:Schenectady, New York, United States of America +192.58.*.*:North Andover, Massachusetts, United States of America +192.65.*.*:Fryeburg, Virginia, United States of America +192.77.*.*:Bedford, Massachusetts, United States of America +192.80.*.*:Manchester, New Hampshire, United States of America +192.84.*.*:Des Moines, Iowa, United States of America +192.88.*.*:Muelheim, Dusseldorf, Deutschland +192.92.*.*:Huntsville, Texas, United States of America +192.94.*.*:Dallas, Texas, United States of America +192.100.*.*:San Jose, California, United States of America +192.102.*.*:Natchitoches, Louisiana, United States of America +192.108.*.*:Portland, Oregon, United States of America +192.111.*.*:St. Louis, Missouri, United States of America +192.131.*.*:Yellow Springs, Ohio, United States of America +192.153.*.*:Rio de Janeiro, RJ, Brasil +192.173.*.*:Arlington, Virginia, United States of America +192.207.*.*:Salt Lake City, Utah, United States of America +192.245.*.*:Dallas, Texas, United States of America +192.246.*.*:Medfield, Massachusetts, United States of America +193.174.*.*:Munich, Bavaria, Deutschland +198.7.*.*:New York City, New York, United States of America +198.17.*.*:San Diego, California, United States of America +198.60.*.*:Bountiful, Utah, United States of America +198.64.53.1:Houston, Texas, United States of America +198.78.*.*:Memphis, Tennessee, United States of America +198.110.*.*:Holland, Michigan, United States of America +198.145.*.*:Seattle, Washington, United States of America +198.174.*.*:Minneapolis, Minnesota, United States of America +199.3.232.*:Houston, Texas, United States of America +199.199.122.*:Minneapolis, Minnesota, United States of America +199.199.125.180:Bloomington, Minnesota, United States of America +204.95.65.*:San Jose, California, United States of America +204.138.*.*:Burlington, Ontario, Canada +205.160.*.*:Atlanta, Georgia, United States of America +205.210.*.*:Burlington, Ontario, Canada +144.124.*.*:Aberystwyth, Wales, United Kingdom +193.40.*.*:Tallin, Estonia +193.204.*.*:Rome, Italy +192.54.*.*:Waterloo, Ontario, Canada +205.184.*.*:Houston, Texas, United States of America +204.118.*.*:Seattle, Washington, United States of America +192.139.*.*:Belleville, Ontario, Canada +204.183.*.*:Lexington Park, Maryland, United States of America +203.21.*.*:Melbourne, Victoria, Australia +199.3.*.*:Marshfield, Wisconsin, United States of America +140.146.*.*:Whitewater, Wisconsin, United States of America +144.13.*.*:Menomonie, Wisconsin, United States of America +155.247.*.*:Ambler, Pennsylvania, United States of America +129.173.*.*:Halifax, Nova Scotia, Canada +158.94.*.*:London, England, United Kingdom diff --git a/lib/cmds/admins/arch.c b/lib/cmds/admins/arch.c new file mode 100644 index 0000000..f962de7 --- /dev/null +++ b/lib/cmds/admins/arch.c @@ -0,0 +1,37 @@ +#include +#include + +mixed cmd(){ + object who = this_player(); + object env = environment(this_player()); + object room = load_object(ROOM_ARCH); + int ret, err; + + if(env == room){ + write("You're already there."); + return 1; + } + + if(!archp(who)){ + write("\nYou are naughty, and must be punished.\n"); + who->eventDestruct(); + return 1; + } + + if(!room){ + write("There seems to be a problem with the arch room."); + return 1; + } + + err = catch( ret = who->eventMoveLiving(room) ); + + if(err || !ret){ + write("Looks like some kind of problem getting into the arch room."); + } + return 1; +} + +string GetHelp(){ + return "Syntax: arch\n\n" + "Transports you to the arch room. \nSee also: wiz\n"; +} diff --git a/lib/cmds/admins/broadcast.c b/lib/cmds/admins/broadcast.c new file mode 100644 index 0000000..5dcbc9d --- /dev/null +++ b/lib/cmds/admins/broadcast.c @@ -0,0 +1,24 @@ +// /bin/adm/_broadcast.c +// from the Dead Souls mudlib +// like shout, except that it overrides ALL blocking +// created by Descartes of Borg 930823 + +#include + +inherit LIB_DAEMON; + +mixed cmd(string str) { + if(!archp(previous_object())) return 0; + if(!str) return "Try: help broadcast"; + message("broadcast", + sprintf("%%^RED%%^Broadcast message from %s: " + "%%^YELLOW%%^%s%%^RESET%%^", + this_player()->GetName(), str), users()); + return 1; +} + +string GetHelp() { + return "Syntax: broadcast [message]\n\n" + "Sends out a message that is in English and immune to all forms of " + "blocking. Do not use this for shout matches!"; +} diff --git a/lib/cmds/admins/cache.c b/lib/cmds/admins/cache.c new file mode 100644 index 0000000..411b7ae --- /dev/null +++ b/lib/cmds/admins/cache.c @@ -0,0 +1,16 @@ +#include + +inherit LIB_DAEMON; + +int cmd(string arg){ + if(!archp(previous_object())) return 0; + cache_stats(); + return 1; +} + +string GetHelp(){ + return "Syntax: cache\n\n" + "Gets the cache stats from the driver, including the hit rate." + "\nSee man: cache_stats" + "\nSee also: callouts, mstatus, netstat, opcprof, fdinfo, dumpallobj"; +} diff --git a/lib/cmds/admins/channel.c b/lib/cmds/admins/channel.c new file mode 100644 index 0000000..ecc45a4 --- /dev/null +++ b/lib/cmds/admins/channel.c @@ -0,0 +1,75 @@ +/* /cmd * from Dead Souls + * command to handle channel privs + * created by Descartes of Borg 940428 + */ + +#include + +inherit LIB_DAEMON; + +int cmd(string str) { + string opt, who, channel; + object ob; + + 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; +} + +string GetHelp() { + return "Syntax: channel \n" + " channel \n\n" + "Used to restrict a player from using a line, or to allow them back " + "onto that line. You can also request a listing of a players currently " + "restricted lines with this command."; +} diff --git a/lib/cmds/admins/dumpallobj.c b/lib/cmds/admins/dumpallobj.c new file mode 100644 index 0000000..52e809e --- /dev/null +++ b/lib/cmds/admins/dumpallobj.c @@ -0,0 +1,16 @@ +#include + +inherit LIB_DAEMON; + +int cmd(string arg){ + if(!archp(previous_object())) return 0; + dumpallobj("/tmp/objects"); + return 1; +} + +string GetHelp(){ + return "Syntax: dumpallobj\n\n" + "Puts a list of all currently loaded objects in /tmp/objects." + "\nSee man: dumpallobj" + "\nSee also: callouts, cache, mstatus, netstat, fdinfo, opcprof"; +} diff --git a/lib/cmds/admins/fdinfo.c b/lib/cmds/admins/fdinfo.c new file mode 100644 index 0000000..9d2f0ce --- /dev/null +++ b/lib/cmds/admins/fdinfo.c @@ -0,0 +1,16 @@ +#include + +inherit LIB_DAEMON; + +int cmd(string arg){ + if(!archp(previous_object())) return 0; + write(dump_file_descriptors()); + return 1; +} + +string GetHelp(){ + return "Syntax: fdinfo\n\n" + "Lists the status of the machines's file descriptors." + "\nSee man: dump_file_descriptors" + "\nSee also: netstat, mstatus, cache, callouts, dumpallobj, opcprof"; +} diff --git a/lib/cmds/admins/objload.c b/lib/cmds/admins/objload.c new file mode 100644 index 0000000..dcd0429 --- /dev/null +++ b/lib/cmds/admins/objload.c @@ -0,0 +1,50 @@ +/* /cmds/admins/objload.c + * From the Dead Souls Mud Library + * Provides information about loaded objects to find where trouble might be + * Created by Descartes of Borg 961204 + * Version: @(#) objload.c 1.4@(#) + * Last modified: 96/12/04 + */ + +#include +#include +#include + +inherit LIB_DAEMON; + +static private int Realms = strlen(REALMS_DIRS); + +mixed cmd(string args) { + string array output = ({ "Creator Files:" }); + object array obs = objects((: file_name($1)[0..Realms-1] ==REALMS_DIRS :)); + mapping vals = ([]); + + foreach(object ob in obs) { + string str = file_privs(file_name(ob)); + + if( !vals[str] ) { + vals[str] = ({ 0, ({}) }); + } + vals[str][0]++; + vals[str][1] = ({ vals[str][1]..., ob }); + } + foreach(string who, mixed array data in vals) { + mapping mp = ([]); + + output += ({ who + ": " + data[0] }); + foreach(object ob in data[1]) { + mp[base_name(ob)]++; + } + foreach(string str, int count in mp) { + output += ({ "\t" + str + ": " + count }); + } + } + previous_object()->eventPage(output, MSG_SYSTEM); + return 1; +} + +string GetHelp() { + return "Syntax: objload\n\n" + "Provides you with information about how many objects " + "each creator has in the game."; +} diff --git a/lib/cmds/common/help.c b/lib/cmds/common/help.c new file mode 100644 index 0000000..639c2aa --- /dev/null +++ b/lib/cmds/common/help.c @@ -0,0 +1,169 @@ +/* /cmds/common/help.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 951021 + * Version: @(#) help.c 1.3@(#) + * Last Modified: 96/12/13 + */ + +#include +#include +#include + +inherit LIB_DAEMON; + +varargs void HelpMenu(string index); + +mixed cmd(string arg) { + object who = previous_object(); + int array screen = (who->GetScreen() || ({ 80, 24 })); + string help = ""; + string tmp = ""; + + 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) ) { + if( arg == "index" ) { + HelpMenu(); + return 1; + } + HelpMenu(arg); + return 1; + } + if(tmp = VERBS_D->GetVerb(arg)){ + arg = last_string_element(tmp, "/")[0..<3]; + } + if( !(tmp = HELP_D->GetHelp(arg)) ) { + tmp = this_player()->GetAlias(arg); + if(tmp) arg = explode(tmp, " ")[0]; + if(!(tmp = HELP_D->GetHelp(arg))){ + return HELP_D->GetLastError(); + } + } + help = center(mud_name()+" System Help", screen[0]) + tmp; + if(sizeof(help) < 2000) help = wrap(help, screen[0]); + who->eventPage(explode(help, "\n"), MSG_HELP); + return 1; +} + +static int CanAccess(object who, string index) { + return HELP_D->CanAccess(who, index); +} + +varargs void HelpMenu(string index) { + function f; + string tmp; + 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), 4); + } + 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, 3); + } + 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 --git a/lib/cmds/creators/anchor.c b/lib/cmds/creators/anchor.c new file mode 100644 index 0000000..2dd713a --- /dev/null +++ b/lib/cmds/creators/anchor.c @@ -0,0 +1,56 @@ +#include +#include + +inherit LIB_DAEMON; + +mixed cmd(string str) { + object target; + int arch = adminp(this_player()); + int ret, curr; + + if(!sizeof(str)) str = "me"; + if(str == "what") return "lol wat"; + if(str == "me") str = this_player()->GetKeyName(); + if(!target = present(str, environment(this_player()))){ + if(arch && (target = find_player(str))){ + write("User found."); + } + else { + write("They're not here."); + return 1; + } + } + if(living(target) && !arch && target != this_player()){ + write("You can only anchor yourself with this command."); + return 1; + } + if((curr = target->GetAnchored())){ + if(target != this_player()) str = nominative(target)+"'s"; + else str = "You're "; + if(curr < 2 && arch){ + write(capitalize(str) + " currently anchored at creator level."); + } + else { + write(capitalize(str) + " already anchored."); + return 1; + } + } + ret = target->SetAnchored(1); + if(ret == curr){ + write("Nothing happens"); + return 1; + } + if(target != this_player()){ + tell_object(target, capitalize(this_player()->GetName())+ + " anchors you."); + } + else str = "yourself"; + write("You anchor "+str+"."); + return 1; +} + +string GetHelp() { + return ("Syntax: anchor \n\n" + "Prevents the target from leaving the environment.\n" + "See also: unanchor"); +} diff --git a/lib/cmds/creators/anglicize.c b/lib/cmds/creators/anglicize.c new file mode 100644 index 0000000..18f72f0 --- /dev/null +++ b/lib/cmds/creators/anglicize.c @@ -0,0 +1,40 @@ +#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; +} + +string GetHelp() { + return ("Syntax: anglicize \n\n" + "Make the target's native language English."); +} diff --git a/lib/cmds/creators/ascii.c b/lib/cmds/creators/ascii.c new file mode 100644 index 0000000..4b88579 --- /dev/null +++ b/lib/cmds/creators/ascii.c @@ -0,0 +1,39 @@ +#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 \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 --git a/lib/cmds/creators/astar.c b/lib/cmds/creators/astar.c new file mode 100644 index 0000000..af6c7bd --- /dev/null +++ b/lib/cmds/creators/astar.c @@ -0,0 +1,163 @@ +/* Tricky */ + +#include + +mapping grid_points; +mapping map_costs; +mapping data; +mixed *path_ret; +string *map_ex; +string path, newpath = ""; +string bap_str, map_str; +int *p_start, *p_end, *m_ind; + +mixed cmd(string str) +{ + int sx, sy; + int gx, gy; + int cnt = 0; + int odir, dir; + int i, j, l, sz; + int start, goal; + + write("foo"); + + map_costs = ([ + ' ': 1, + '*': 50, + 'X': 100, + ]); + + bap_str = + " ########"+"\n"+ + " # **XX #"+"\n"+ + "########### XX*X #"+"\n"+ + "# * # XXX* #"+"\n"+ + "# # ###### #"+"\n"+ + "# ##### # # #"+"\n"+ + "###### #### # # ##"+"\n"+ + " # # # #"+"\n"+ + "## ###*# # #"+"\n"+ + "# # # ######"+"\n"+ + " ### ### #"+"\n"+ + "## ## ## #"+"\n"+ + "### # # #"+"\n"+ + "### ## #"+"\n"+ + "############"; + + map_str = + " #-#-#-#-#-#\n"+ + " | | | | | |\n"+ + " #-#-#-#-#-#\n"+ + " | | | | | |\n"+ + " #-#-# #-#-#-#-#-#-#-#-#-#-#-#\n"+ + " | | | | | | | |\n"+ + " # #-#-#-#-#-#-# #\n"+ + " | | | |\n"+ + " #-#-# # #-#-# #-#\n"+ + " | | |\n"+ + " # # # #\n"+ + " | | | |\n"+ + " #-#-#-#-#-#-# #-#-#-# # #\n"+ + " | | | | | | | |\n"+ + " # # #-#-#-# #-#-#\n"+ + " | | | |\n"+ + " #-#-#-#-#-# # #\n"+ + " | | | |\n"+ + " #-#-# # #\n"+ + " | | |\n"+ + " #-# #-# #\n"+ + " | | | |\n"+ + " # #-#-#-# #\n"+ + " | | | |\n"+ + " #-#-# #-#-#\n"; + + map_ex = explode(map_str, "\n"); + + grid_points = ([ + "Start": ({ 1, 3 }), + "End": ({ 0, 7 }), + ]); + + p_start = grid_points["Start"]; + p_end = grid_points["End"]; + + sx = p_start[0]; sy = p_start[1]; + gx = p_end[0]; gy = p_end[1]; + + path_ret = find_path(map_str, sx, sy, gx, gy, map_costs); + + l = 0; + + for(i = 0; i < sizeof(map_ex); i++) + for(j = 0; j < strlen(map_ex[i]); j++) + if(member_array(map_ex[i][j], keys(map_costs)) != -1) l++; + + write("Walkable paths: " + l + "\n"); + + if(sizeof(path_ret)) + { + path = path_ret[0]; + data = ([ ]) + path_ret[1]; + + m_ind = keys(data); + sz = sizeof(m_ind); + write("Walkable paths checked: " + sz + "\n"); + + while(--sz != -1) + { + int x, y; + + l = m_ind[sz]; + + x = data[l][AS_X]; + y = data[l][AS_Y]; + + if(map_ex[y][x] == ' ') map_ex[y][x] = '.'; + + } + + start = sizeof(map_ex[0]) * sy + sx; + goal = sizeof(map_ex[0]) * gy + gx; + + l = goal; + + while(l != start) + { + int x, y; + + l = data[l][AS_PARENT]; + x = data[l][AS_X]; + y = data[l][AS_Y]; + + map_ex[y][x] = 'o'; + } + + } + else path = 0; + + map_ex[sy][sx] = 'S'; + map_ex[gy][gx] = 'E'; + + write("\n"); + + write(map_str + "\n"); + write("\n"); + write(implode(map_ex, "\n") + "\n"); + write("\n"); + + write("sx, sy: " + sx + ", " + sy + "\n"); + write("gx, gy: " + gx + ", " + gy + "\n"); + write("\n"); + + if(mapp(data)) + { + write("Path cost: " + data[goal][AS_FCOST] + "\n"); + write("\n"); + } + + if(path) write("You should go: " + path + "\n"); + else write("No path could be found.\n"); + + return 1; +} diff --git a/lib/cmds/creators/boards.c b/lib/cmds/creators/boards.c new file mode 100644 index 0000000..d69b007 --- /dev/null +++ b/lib/cmds/creators/boards.c @@ -0,0 +1,26 @@ +// By Magnafix 10-14-96 +// required addition of list_new_posts() in bboard daemon +#include +#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(BBOARD_D->list_new_posts(boards[x], 1)); + + return 1; +} + +string GetHelp() { + return "Syntax: boards\n" + "This command tells you which boards have unread messages " + "on them."; +} diff --git a/lib/cmds/creators/bugs.c b/lib/cmds/creators/bugs.c new file mode 100644 index 0000000..5164350 --- /dev/null +++ b/lib/cmds/creators/bugs.c @@ -0,0 +1,17 @@ +#include +#include + +inherit LIB_DAEMON; + +int cmd() { + int bugs = BUGS_D->BugCheck(); + write("Unresolved bug reports: "+bugs); + return 1; +} + +string GetHelp() { + return ("Syntax: bugs\n\n" + "Returns the number of unresolved bug reports in the bug " + "tracking system.\n" + "See also: bug"); +} diff --git a/lib/cmds/creators/callouts.c b/lib/cmds/creators/callouts.c new file mode 100644 index 0000000..832d3b9 --- /dev/null +++ b/lib/cmds/creators/callouts.c @@ -0,0 +1,37 @@ +/* /cmds/creator/callouts.c + * from the Dead Souls LPC Library + * lists all callouts pending + * created by Descartes of Borg 950514 + * Version: @(#) callouts.c 1.3@(#) + * Last modified: 96/10/06 + */ + +#include +#include + +inherit LIB_DAEMON; + +mixed cmd(string args) { + mixed array callouts; + string tmp; + + callouts = call_out_info(); + if( !sizeof(callouts) ) { + previous_object()->eventPrint("No pending callouts.", MSG_SYSTEM); + return 1; + } + tmp = sprintf("%:-40s %:-25s Delay\n", "Object", "Function"); + tmp += "--------------------------------------------------" + "-------------------------\n"; + foreach(mixed array callout in callouts) { + tmp += sprintf("%:-40O %:-25s %d\n", callout...); + } + this_player()->eventPage(explode(tmp, "\n"), MSG_SYSTEM); + return 1; +} + +string GetHelp() { + return ("Syntax: callouts\n\n" + "Lists all pending callouts.\n" + "See also: events, mstatus, netstat"); +} diff --git a/lib/cmds/creators/classblock.c b/lib/cmds/creators/classblock.c new file mode 100644 index 0000000..3a96a5a --- /dev/null +++ b/lib/cmds/creators/classblock.c @@ -0,0 +1,46 @@ +/** + * /cmds/creators/classblock.c + * From the Dead Souls Mud Library + * Allows a creator to tune in or out of all class chat lines. + * created by Hanse@Dead Souls 930305 + * Version: @(#) classblock.c 1.3@(#) + * Last modified: 96/10/09 + */ + +#include +#include +#include + +inherit LIB_DAEMON; + +mixed cmd(string args) { + if( !args || (args != "on" && args != "off") ) { + return "Syntax: classblock "; + } + if( args == "on" ) { + foreach(string class_name in CLASSES_D->GetClasses()) { + if( !previous_object()->GetBlocked(class_name) ) { + previous_object()->SetBlocked(class_name); + } + } + previous_object()->eventPrint("You are now blocking all class lines.", + MSG_SYSTEM); + } + else { + foreach(string class_name in CLASSES_D->GetClasses()) { + if( previous_object()->GetBlocked(class_name) ) { + previous_object()->SetBlocked(class_name); + } + } + previous_object()->eventPrint("You are no longer blocking any class " + "lines.", MSG_SYSTEM); + } + return 1; +} + +string GetHelp() { + return ("Syntax: classblock \n\n" + "Allows you to make sure that you are blocking all or no " + "class chat lines.\n" + "See also: codeblock"); +} diff --git a/lib/cmds/creators/clean.c b/lib/cmds/creators/clean.c new file mode 100644 index 0000000..9f78cf7 --- /dev/null +++ b/lib/cmds/creators/clean.c @@ -0,0 +1,52 @@ +/* /cmds/creator/clean.c + * From the Dead Souls Mud Library + * Cleans out the inventory of an object, defaulting to this room + * created by Valodin@Dead Souls 930101 + * Version: @(#) clean.c 1.2@(#) + * Last modified: 96/10/06 + */ + +#include +#include + +inherit LIB_DAEMON; + +mixed cmd(string args) { + object array obs, items, users; + object ob; + + if( !args || args == "" ) { + ob = environment(previous_object()); + } + else { + ob = get_object(args); + } + if( !ob ) { + return "No " + args + " found."; + } + previous_object()->eventPrint(sprintf("Cleaning %O", ob), MSG_SYSTEM); + say(this_player()->GetName()+" cleans "+ob->GetShort()+"."); + obs = deep_inventory(ob); + users = filter(obs, (: userp :)); + items = obs - users; + foreach(object user in users) { + object tmp = user; + + while( tmp = environment(tmp) ) { + items -= ({ tmp }); + } + } + foreach(object item in items) { + if( item ) { + item->eventDestruct(); + } + } + return 1; +} + +string GetHelp() { + return ("Syntax: clean [OBJECT]\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 --git a/lib/cmds/creators/clone.c b/lib/cmds/creators/clone.c new file mode 100644 index 0000000..ba1b136 --- /dev/null +++ b/lib/cmds/creators/clone.c @@ -0,0 +1,59 @@ +/* /cmds/creator/clone.c + * from the Dead Souls LPC Library + * clones objects for cres + * created by Descartes of Borg 950409 + * Version: @(#) clone.c 1.2@(#) + * Last modified: 96/10/08 + */ + +#include + +inherit LIB_DAEMON; + +mixed cmd(string args) { + object ob, dest; + string file, res, nom; + + if( args == "" || !args ) return "Clone what?"; + file = absolute_path(this_player()->query_cwd(), args); + if( file[<2..] != ".c" ) file = file + ".c"; + if( file_size(file) < 0 ){ + ob = get_object(args); + if(ob){ + file = base_name(ob)+".c"; + } + } + if( res = catch(ob = new(file)) ) + return "Error in cloning object: " + res; + if( !ob ){ + write("Failed to clone file: " + file); + if(!file_exists(file)){ + write("It seems that the file "+file+" does not exist."); + } + return 1; + } + dest = ( living(ob) ? environment(this_player()) : this_player() ); + if( !(ob->eventMove(dest)) && + !(ob->eventMove(environment(this_player()))) ) { + message("system", "Failed to properly move the object.", + this_player()); + return 1; + } + if( !(nom = ob->GetShort()) ) nom = "something peculiar"; + if( !(res = this_player()->GetMessage("clone", ob)) ) + res = 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: clone \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" + "See also: dest, message"); +} diff --git a/lib/cmds/creators/codeblock.c b/lib/cmds/creators/codeblock.c new file mode 100644 index 0000000..c7c4eaf --- /dev/null +++ b/lib/cmds/creators/codeblock.c @@ -0,0 +1,31 @@ +/* /cmds/creators/codeblock.c + * From the Dead Souls 1.1 Mudlib + * Allows a creator to block all channels + * Created by Descartes of Borg 921031 + * Version: @(#) codeblock.c 1.2@(#) + * Last modified: 96/10/08 + */ + +#include +#include + +inherit LIB_DAEMON; + +mixed cmd(string args) { + 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); + } + return 1; +} + +string GetHelp() { + return ("Syntax: codeblock\n\n" + "Allows you to toggle on and off the blocking of all mud " + "channels.\n" + "See also: classblock"); +} diff --git a/lib/cmds/creators/cryptogram.c b/lib/cmds/creators/cryptogram.c new file mode 100644 index 0000000..663214f --- /dev/null +++ b/lib/cmds/creators/cryptogram.c @@ -0,0 +1,92 @@ +/* blame OotS */ + +#include +#include + +inherit LIB_COMMAND; + +mapping alpha1 = ([ + 1 : "a", + 2 : "b", + 3 : "c", + 4 : "d", + 5 : "e", + 6 : "f", + 7 : "g", + 8 : "h", + 9 : "i", + 10 : "j", + 11 : "k", + 12 : "l", + 13 : "m", + 14 : "n", + 15 : "o", + 16 : "p", + 17 : "q", + 18 : "r", + 19 : "s", + 20 : "t", + 21 : "u", + 22 : "v", + 23 : "w", + 24 : "x", + 25 : "y", + 26 : "z", + ]); + +mapping alpha2 = ([]); + +string doRotate(int code, string str){ + string *str_array = explode(str,""); + string ret = ""; + + foreach(string element in str_array){ + if(alpha2[element]){ + int operand; + operand = alpha2[element]+code; + if(operand > 26){ + operand -= 26; + } + if(operand < 1){ + operand = 26 - abs(operand); + } + ret += alpha1[operand]; + } + else ret += element; + } + return ret; +} + +int cmd(string str){ + int code; + string tmp, tmp2; + string ret = ""; + string *str_array = ({}); + + if(!alpha2 || !sizeof(alpha2)){ + alpha2 = ([]); + foreach(mixed key, mixed val in alpha1) alpha2[val] = key; + } + + if(sscanf(str,"%s %s",tmp, tmp2)){ + if(tmp = "-q"){ + for(int i=0;i<26;i++){ + write(i+": "+doRotate(i, tmp2)); + } + } + } + + else if(!sscanf(str,"%d %s",code, tmp)){ + str_array = explode(str,""); + ret = doRotate(code, str); + } + + write("Output: "+ret); + return 1; +} + +string GetHelp() { + return "Syntax: cryptogram -q FIRSTLETTER SECONDLETTER\n" + " cryptogram NUMBER STRING\n\n" + "Tool for decoding cryptograms"; +} diff --git a/lib/cmds/creators/debug.c b/lib/cmds/creators/debug.c new file mode 100644 index 0000000..8dd4b58 --- /dev/null +++ b/lib/cmds/creators/debug.c @@ -0,0 +1,24 @@ +#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 "Try: help debug"; + 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; +} + +string GetHelp() { + return ("Syntax: debug [on | off]\n\n" + "Allows you to receive debugging information."); +} diff --git a/lib/cmds/creators/defines.c b/lib/cmds/creators/defines.c new file mode 100644 index 0000000..56b9fe8 --- /dev/null +++ b/lib/cmds/creators/defines.c @@ -0,0 +1,25 @@ +#include +#include + +inherit LIB_DAEMON; + +varargs int cmd(string str){ + mixed ret; + if(!str){ + write("Try: help defines"); + return 1; + } + ret = DEFINES_D->GetDefine(str); + write(str+": "+identify(ret)); + return 1; +} + +string GetHelp(){ + return ("Syntax: defines \n\n" + "Returns the defined value for the speficied token, if " + "it is defined in the default includes.\n" + "Examples:\n" + "define SEVERABLE_LIMBS\n" + "define MAX_NEWBIE_LEVEL\n" + "See also: types"); +} diff --git a/lib/cmds/creators/domains.c b/lib/cmds/creators/domains.c new file mode 100644 index 0000000..8ba91b2 --- /dev/null +++ b/lib/cmds/creators/domains.c @@ -0,0 +1,59 @@ +/* /cmds/creators/domains.c + * From the Dead Souls Mud Library + * Shows the domain statistics information + * created by Descartes of Borg 960214 + * Version: @(#) domains.c 1.3@(#) + * Last modified: 96/10/08 + */ + +#include +#include + +inherit LIB_DAEMON; + +mixed cmd(string args) { + object who = previous_object(); + int width = (who->GetScreen())[0]; + mapping stats = ([]); + string array domains; + mixed array tmp; + + foreach(string domain, mixed data in domain_stats()) { + if( !data ) { + continue; + } + if( file_size(DOMAINS_DIRS "/" + domain) != -2 ) { + continue; + } + if( !data["moves"] && !data["heart_beats"] && !data["objects"] ) { + continue; + } + 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: domains\n\n" + "Prints out domain statistics for the mud's domains.\n" + "See also: realms"); +} diff --git a/lib/cmds/creators/efuns.c b/lib/cmds/creators/efuns.c new file mode 100644 index 0000000..f3b0440 --- /dev/null +++ b/lib/cmds/creators/efuns.c @@ -0,0 +1,21 @@ +#include +#include + +inherit LIB_COMMAND; + +int cmd(string str){ + int i, cols = 3; + string *ret; + if(str) i = atoi(str); + if(i) cols = i; + ret = explode(format_page(efuns(), cols), "\n"); + this_player()->eventPage(ret); + return 1; +} + +string GetHelp() { + return "Syntax: efuns [COLUMNS]\n" + "Displays all available driver efuns. If a number is given, the " + "output is broken up into the number of columns specified." + "\nSee also efun, sefun, sefuns, lfun, lfuns, showfuns, findfun"; +} diff --git a/lib/cmds/creators/elog.c b/lib/cmds/creators/elog.c new file mode 100644 index 0000000..9f2aae3 --- /dev/null +++ b/lib/cmds/creators/elog.c @@ -0,0 +1,26 @@ +// /bin/dev/_elog.c +// from the Dead Souls Mudlib +// tails error logs +// created by Descartes of Borg 930813 + +#include +#include + +inherit LIB_DAEMON; + +int cmd(string str) { + if(!str) str = DIR_ERROR_LOGS+"/"+previous_object()->GetKeyName(); + else str = DIR_ERROR_LOGS+"/"+str; + write(str+":\n"); + if(!tail(str)) write("No errors in "+str+".\nTry /log/runtime or /log/catch\n"); + return 1; +} + +string GetHelp() { + return ("Syntax: elog [error log]\n\n" + "This will tail your personal error log if issued without any\n" + "arguments. If an argument is given, it searches for a file\n" + "by that name in the mud's error log directory.\nFor example:\n" + "elog\nelog town\nelog secure\nelog lib\n\nSee also: " + "log, replog"); +} diff --git a/lib/cmds/creators/events.c b/lib/cmds/creators/events.c new file mode 100644 index 0000000..c4a25b2 --- /dev/null +++ b/lib/cmds/creators/events.c @@ -0,0 +1,78 @@ +/* /cmds/creator/events.c + * From the Dead Souls Mud Library + * show wizard events + * Version: @(#) events.c 1.2@(#) + * Last modified: 96/12/08 + */ + +#include +#include + +inherit LIB_DAEMON; + +int cmd(string str) { + mapping mp; + string *obs; + string *st2; + string st3; + int i,j,k,l; + string name; + + if(!str && archp(previous_object())) { + mp = EVENTS_D->GetEvents(); + i = sizeof(obs = sort_array(keys(mp),-1)); + 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())) { + if (archp(previous_object())) + name = str; + else + name = this_player()->GetKeyName(); + j = 0; + mp = EVENTS_D->GetEvents(); + 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())) + message("info", name + " has the following events pending:", this_player()); + else + message("info", "You have the following events pending:", this_player()); + j = 1; + } + st3 = "~"; + 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()); + } + } + if (j == 0) { + if (archp(previous_object())) + message("info", name+" doesn't have any events pending.", this_player()); + else + message("info", "You don't have any events pending.", this_player()); + } + return 1; + } + return 0; +} + +string GetHelp() { + if(archp(this_player())) + return ("Syntax: events [creator]\n\n" + "Gives a list of all pending mud events or all events pending for the specified creator."); + else + return ("Syntax: events\n\n" + "Gives a list of your pending events."); +} diff --git a/lib/cmds/creators/exits.c b/lib/cmds/creators/exits.c new file mode 100644 index 0000000..5c8829c --- /dev/null +++ b/lib/cmds/creators/exits.c @@ -0,0 +1,56 @@ +/* /cmds/creator/exits.c + * from the Dead Souls LPC Library + * Command to display exit and enter info for rooms + * by Kalinash 100195 + */ + +#include + +inherit LIB_DAEMON; + +mixed cmd(){ + string *asExits, sDir, sExit; + string *asEnters; + object oEnv; + + if ( !( oEnv = environment( this_player() ) ) ) + return "You do not have a valid environment."; + if(oEnv->GetRiders()) oEnv = environment( oEnv ); + if ( !oEnv ) + return "Invalid environment."; + + asExits = oEnv->GetExits(); + asEnters = oEnv->GetEnters(); + + message( "Nmy_action", sprintf("\t *** %s ***\n\n", identify( oEnv ) ), + 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; +} + +string GetHelp(){ + return ("Syntax: exits\n\nDisplays exit and enter " + "information for the current room."); +} diff --git a/lib/cmds/creators/expel.c b/lib/cmds/creators/expel.c new file mode 100644 index 0000000..78bf034 --- /dev/null +++ b/lib/cmds/creators/expel.c @@ -0,0 +1,51 @@ +#include +#include ROOMS_H + +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; +} + +string GetHelp() { + return ("Syntax: expel \n\n" + "Forces the specified living thing to leave your environment.\n" + "See also: return, goto, move, trans"); +} diff --git a/lib/cmds/creators/file.c b/lib/cmds/creators/file.c new file mode 100644 index 0000000..3b83ffb --- /dev/null +++ b/lib/cmds/creators/file.c @@ -0,0 +1,33 @@ +#include + +inherit LIB_DAEMON; + +int cmd(string str) { + object ob; + string basename, filename; + + if(!str || str == "here") { + ob = environment(this_player()); + } + + else ob = get_object(str, this_player()); + + if(!ob) { + write("That object can't be found."); + return 1; + } + + filename = file_name(ob); + basename = base_name(ob); + + write("The unique object identifier is: "+filename); + write("The file it is loaded from is: "+basename+".c"); + + return 1; +} + +string GetHelp() { + return "Syntax: file [thing]\n\n"+ + "Provides information about the thing's name and file of origin.\n"+ + "With no argument, it defaults to your location.\n"; +} diff --git a/lib/cmds/creators/find.c b/lib/cmds/creators/find.c new file mode 100644 index 0000000..8d14d3d --- /dev/null +++ b/lib/cmds/creators/find.c @@ -0,0 +1,26 @@ +#include +#include + +inherit LIB_COMMAND; + +int cmd(string str){ + FILE_D->SearchFiles(str); + return 1; +} + +string GetHelp(){ + return "Syntax: find [-s] [-i] \n" + "This command searches the list of files known to the file daemon for files " + "matching the specified search parameter. This list of files is refreshed approximately " + "once every 25 hours automatically, or every time the mud boots, or every time the " + "file daemon is reloaded.\n" + "Options:\n" + "-s Strict matching, aka not substrings.\n" + "-i Case insensitive\n" + "Examples\n" + "find FooBar: finds FooBar, and FooBar.h, but not foobar or FOObar.h\n" + "find -i FooBar: finds foobar, FooBar, FooBarBaz, and Foobar.c\n" + "find -s FooBar: finds FooBar, but NOT FooBar.c or foobarbaz\n" + "find -i -s FooBar: finds fooBAR, and FooBar, but not FooBar.c\n" + ""; +} diff --git a/lib/cmds/creators/findobj.c b/lib/cmds/creators/findobj.c new file mode 100644 index 0000000..042f942 --- /dev/null +++ b/lib/cmds/creators/findobj.c @@ -0,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 += "%^B_BLACK%^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 \n\n" + "Displays matching objects that are loaded into memory.\n\n" + "Examples: \n\nfindobj staff\nfindobj /lib/dummy"); +} diff --git a/lib/cmds/creators/format.c b/lib/cmds/creators/format.c new file mode 100644 index 0000000..af200d1 --- /dev/null +++ b/lib/cmds/creators/format.c @@ -0,0 +1,47 @@ +/* fake wiz command for the help format made by Valodin Jan 93 */ +// NB A nicer solution is to make the help command check a directory in +// /doc if you are a wizard. +// Signed... Campaign '93 "Keep /bin for commands" + +#include + +inherit LIB_DAEMON; + +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; +} + +string GetHelp(){ + return ("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"+ + ""); +} diff --git a/lib/cmds/creators/godmode.c b/lib/cmds/creators/godmode.c new file mode 100644 index 0000000..c94e124 --- /dev/null +++ b/lib/cmds/creators/godmode.c @@ -0,0 +1,46 @@ +#include + +inherit LIB_DAEMON; + +varargs int cmd(string str){ + if(!str){ + write("Godmode is "+ (this_player()->GetGodMode() ? "on." : "off.")); + return 1; + } + if(str == "on"){ + if(this_player()->GetGodMode()){ + write("You are already in godmode.\n"); + return 1; + } + this_player()->SetGodMode(1); + if(this_player()->GetGodMode()){ + write("Godmode is now on."); + } + else { + write("Fail. Godmode is not on."); + } + return 1; + } + if(str == "off"){ + if(!(this_player()->GetGodMode())){ + write("You are already not in godmode.\n"); + return 1; + } + this_player()->SetGodMode(0); + if(!(this_player()->GetGodMode())){ + write("Godmode is now off."); + } + else { + write("Fail. Godmode is still on."); + } + return 1; + } + + write("Try: help godmode"); + return 1; +} + +string GetHelp(){ + return ("Syntax: godmode [ on | off ]\n\n" + "Enables or disables immunity to most forms of lethal damage."); +} diff --git a/lib/cmds/creators/html.c b/lib/cmds/creators/html.c new file mode 100644 index 0000000..636aa11 --- /dev/null +++ b/lib/cmds/creators/html.c @@ -0,0 +1,38 @@ +#include + +inherit LIB_DAEMON; + +mapping TermInfo; + +void create(){ + TermInfo = + ([ "RED" : "", + "GREEN" : "", + "BLUE" : "", + "YELLOW" : "", + "CYAN" : "", + "MAGENTA" : "", + "YELLOW" : "", + "RESET": "", "BR" : "
", "P" : "

", "/P" : "

", ">" : ">", + "HREF" : "", + "I" : "", "/I" : "", "PRE" : "", "/PRE" : "", + "STRONG" : "", "/STRONG" : "", + "TABLE" : "", "/TABLE" : "
", "TR" : "", + "/TR" : "", "TD" : "" , "/TD" : "" ]); +} + +mixed cmd(string args){ + string file = read_file(args); + string *ret = explode(file,"\n"); + file = implode(ret,"
"); + file = terminal_colour(file+"%^RESET%^\n", TermInfo); + file = "" + file + ""; + write(file); + return 1; +} + +string GetHelp() { + return "Syntax: html \n\n" + "Outputs to the screen an htmlified version of the " + "file specified."; +} diff --git a/lib/cmds/creators/i3who.c b/lib/cmds/creators/i3who.c new file mode 100644 index 0000000..47a2e06 --- /dev/null +++ b/lib/cmds/creators/i3who.c @@ -0,0 +1,27 @@ +#include +#include + +inherit LIB_DAEMON; + +string GetHelp(); + +mixed cmd(string str) { + if(str == "every mud") { + SERVICES_D->eventSendWhoRequest(); + } + else { + return GetHelp(); + } + return 1; +} + +string GetHelp() { + return ("Syntax: i3who every mud\n\n" + "Queries each active mud for rwho information.\n\n" + + "%^RED%^BOLD%^WARNING:%^RESET%^ This command sends a rwho request to every mud connected to the Intermud-3 network. " + "If you're sure you want to do it, type \"i3who every mud\". Otherwise, you're probably " + "looking for the \"rwho\" command, which lists information for one specified mud.\n" + + "See also: rwho"); +} diff --git a/lib/cmds/creators/include/showtree.h b/lib/cmds/creators/include/showtree.h new file mode 100644 index 0000000..7bc3295 --- /dev/null +++ b/lib/cmds/creators/include/showtree.h @@ -0,0 +1,8 @@ +#ifndef l_showtree_h +#define l_showtree_h + +mixed cmd(string arg); +string ShowTree(string file, string func, int index); +string GetHelp(string str); + +#endif /* l_showtree_h */ diff --git a/lib/cmds/creators/inherits.c b/lib/cmds/creators/inherits.c new file mode 100644 index 0000000..bf647ab --- /dev/null +++ b/lib/cmds/creators/inherits.c @@ -0,0 +1,53 @@ +#include +#include + +inherit LIB_DAEMON; + +varargs int cmd(string str){ + string tmp, thing, file, *inheriteds; + object ob; + if(!str || sscanf(str,"%s %s",file,thing) != 2){ + write("Syntax: inherits FILE THING"); + return 1; + } + + ob = get_object(thing); + if(!ob){ + write("Sorry I can't find that thing."); + return 1; + } + thing = (ob->GetShort() || thing); + + if(last(file,2) == ".c") file = truncate(file,2); + + tmp = DEFINES_D->GetDefine(file); + + if(tmp) file = tmp; + + write("Checking " + identify(ob) + " for inheritance of " + + file + " , just a moment..."); + if(file){ + if(inherits(file, ob)){ + write(thing+" inherits "+file+"."); + return 1; + } + inheriteds = deep_inherit_list(ob); + foreach(string item in inheriteds){ + if(!grepp(item, file)) inheriteds -= ({ item }); + } + } + if(!sizeof(inheriteds)){ + write("No matches found. "+ thing + + " does not appear to inherit that file."); + return 1; + } + write("Exact match not found, but here are some possible matches: "); + write(implode(inheriteds,"\n")); + return 1; +} + +string GetHelp(){ + return ("Syntax: inherits \n\n"+ + "Tries to match FILE with the list of inherited files "+ + "for THING.\nSee also: showtree, findobj, findfun, showfuns"); +} diff --git a/lib/cmds/creators/invis.c b/lib/cmds/creators/invis.c new file mode 100644 index 0000000..fb89d16 --- /dev/null +++ b/lib/cmds/creators/invis.c @@ -0,0 +1,21 @@ +// /bin/dev/_invis.c +// from the Dead Souls mudlib +// created by Descartes of Borg october 1992 + +#include + +inherit LIB_DAEMON; + +varargs int cmd(){ + if(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; +} + +string GetHelp(){ + return ("Syntax: invis\n\nMakes you invisible to players of lower levels in all circumstances.\nSee also: vis"); +} diff --git a/lib/cmds/creators/lfuns.c b/lib/cmds/creators/lfuns.c new file mode 100644 index 0000000..39841a7 --- /dev/null +++ b/lib/cmds/creators/lfuns.c @@ -0,0 +1,22 @@ +#include +#include + +inherit LIB_COMMAND; + +int cmd(string str){ + int i, cols = 2; + string *ret, *tmp; + if(str) i = atoi(str); + if(i) cols = i; + tmp = sort_array(FUNCTION_D->GetFunctions(), 1); + ret = explode(format_page(tmp, cols), "\n"); + this_player()->eventPage(ret); + return 1; +} + +string GetHelp() { + return "Syntax: lfuns [COLUMNS]\n" + "Displays lfuns known to the FUNCTION_D. If a number is given, the " + "output is broken up into the number of columns specified." + "\nSee also efun, efuns, sefun, lfun, showfuns, findfun"; +} diff --git a/lib/cmds/creators/lightme.c b/lib/cmds/creators/lightme.c new file mode 100644 index 0000000..3edd214 --- /dev/null +++ b/lib/cmds/creators/lightme.c @@ -0,0 +1,27 @@ +#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(){ + return "Syntax: lightme [NUMBER]\n\n"+ + "Reports or changes the amount of light your body radiates."; +} diff --git a/lib/cmds/creators/malloc.c b/lib/cmds/creators/malloc.c new file mode 100644 index 0000000..9ac3c98 --- /dev/null +++ b/lib/cmds/creators/malloc.c @@ -0,0 +1,16 @@ +#include + +inherit LIB_DAEMON; + +int cmd(string arg){ + malloc_status(); + return 1; +} + +string GetHelp(){ + return "Syntax: malloc\n\n" + "Lists memory usage statistics. Output will " + "depend on memory management package specified in options.h" + " when the driver is compiled." + "\nSee man: malloc_status"; +} diff --git a/lib/cmds/creators/man.c b/lib/cmds/creators/man.c new file mode 100644 index 0000000..5e3d8bd --- /dev/null +++ b/lib/cmds/creators/man.c @@ -0,0 +1,37 @@ +/* /cmd * from Dead Souls Mudlib 3.2 + * a command to access the man documents for efuns and such + * created by Descartes of Borg 940122 + */ + +#include +#include + +inherit LIB_DAEMON; + +#define MAN_PAGES ({ "sefun", "efun/all", "applies", "lfun/all" }) + +int cmd(string str) { + string d, tmp; + string *pages; + int i; + + if(!str) return notify_fail("Usage: man \n"); + 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; +} + +string GetHelp() { + return ("Syntax: man \n\n" + "This command provides information on the function specified, " + "if it has a help file in the /doc/efun/all, /doc/sefun, or " + "/doc/lfun/all directories."); +} diff --git a/lib/cmds/creators/margins.c b/lib/cmds/creators/margins.c new file mode 100644 index 0000000..666e74e --- /dev/null +++ b/lib/cmds/creators/margins.c @@ -0,0 +1,17 @@ +#include + +inherit LIB_DAEMON; + +string GetHelp() { + return ("Syntax: margins\n\n" + "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."); +} + +mixed cmd(string str) { + return ( + "|---------------------------------------------------------------|-------------|" + ); + +} diff --git a/lib/cmds/creators/message.c b/lib/cmds/creators/message.c new file mode 100644 index 0000000..36a7d76 --- /dev/null +++ b/lib/cmds/creators/message.c @@ -0,0 +1,42 @@ +/* /cmds/creator/message.c + * from the Foundation II LPC Library + * allows a person to modify their default messages + * created by Descartes of Borg 950428 + */ + +#include + +inherit LIB_DAEMON; + +mixed cmd(string args) { + string type, msg; + + if( !args || args == "" ) { + mapping msgs; + string *cles; + int i; + string tmp = ""; + + i = sizeof(cles = keys(msgs = 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( !(this_player()->SetMessage(type, msg)) ) + return "Invalid message type."; + message("system", "Message " + type + " changed to:\n" + msg, + this_player()); + return 1; +} + +string GetHelp() { + return ("Syntax: message \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"); +} diff --git a/lib/cmds/creators/morse.c b/lib/cmds/creators/morse.c new file mode 100644 index 0000000..656dcde --- /dev/null +++ b/lib/cmds/creators/morse.c @@ -0,0 +1,24 @@ +#include +#include + +inherit LIB_COMMAND; + +int cmd(string str){ + string ret = ""; + + if(!str){ + write("See: help morse"); + return 1; + } + + ret = morse(str); + + write("Output: "+ret); + return 1; +} + +string GetHelp() { + return "Syntax: morse \n\n" + "Renders the provided string as morse code.\n" + "See also: unmorse"; +} diff --git a/lib/cmds/creators/mraces.c b/lib/cmds/creators/mraces.c new file mode 100644 index 0000000..7183dcc --- /dev/null +++ b/lib/cmds/creators/mraces.c @@ -0,0 +1,26 @@ +/* /cmds/creator/mraces.c + * 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; +} + +string GetHelp() { + return ("Syntax: mraces\n\n" + "A simple tool for creators which will list " + "available npc races."); +} + diff --git a/lib/cmds/creators/mstatus.c b/lib/cmds/creators/mstatus.c new file mode 100644 index 0000000..15fb698 --- /dev/null +++ b/lib/cmds/creators/mstatus.c @@ -0,0 +1,24 @@ +#include + +inherit LIB_DAEMON; + +mixed cmd(string arg) { + int flag = !!arg; + this_player()->eventPage(explode(mud_status(flag), "\n")); + return 1; +} + +string GetHelp() { + return "Syntax: mstatus \n\n" + "Gives you statistics on the driver and mudlib. " + "If the optional argument is given, you also get:" + "\nadd_message statistics" + "\nHash table of living objects" + "\nFunction cache information" + "\nHeart beat information" + "\nShared string hash table" + "\nCall out information" + "\nObject name hash table status" + "\nSee man: mud_status" + "\nSee also: netstat, fdinfo, cache, callouts, dumpallobj, opcprof"; +} diff --git a/lib/cmds/creators/netstat.c b/lib/cmds/creators/netstat.c new file mode 100644 index 0000000..809c847 --- /dev/null +++ b/lib/cmds/creators/netstat.c @@ -0,0 +1,31 @@ +/* /cmds/creator/netstat.c + * from the Dead Souls LPC Library + * gives socket status information + * created by Descartes of Borg 921123 + */ + +#include + +inherit LIB_DAEMON; + +mixed cmd(string args) { + string *arr; + string ret = ""; + string dss = replace_string(dump_socket_status(),"-- 0","--\n 0"); + foreach(mixed key, mixed val in network_stats()){ + val = val+""; + ret += sprintf("%:-30s %s",key, val)+"\n"; + } + write(ret); + + arr = filter(explode(dss, "\n"), (: $1[0..1] != "-1" :)); + this_player()->eventPage(arr, "system"); + return 1; +} + +string GetHelp() { + return ("Syntax: netstat\n\n" + "Gives you information about sockets being used by the LPC " + "server through the MudOS socket efuns.\n" + "See also: callouts, dumpallobj, mstatus"); +} diff --git a/lib/cmds/creators/noclip.c b/lib/cmds/creators/noclip.c new file mode 100644 index 0000000..aa91189 --- /dev/null +++ b/lib/cmds/creators/noclip.c @@ -0,0 +1,41 @@ +#include + +inherit LIB_DAEMON; + +varargs int cmd(string args){ + int status = this_player()->GetProperty("noclip"); + string sstatus = "are"; +#if !(GRID) + write("This feature is disabled."); + return 1; +#endif + if(!status) sstatus = "are not"; + if(!args){ + write("You "+sstatus+" noclipping."); + return 1; + } + if(args == "on"){ + if(status) write("You are already noclipping."); + else write("You enable noclip mode."); + this_player()->SetProperty("noclip", 1); + return 1; + } + + if(args == "off"){ + if(!status) write("You are already not noclipping."); + else write("You disable noclip mode."); + this_player()->SetProperty("noclip", 0); + return 1; + } + + write("Try: help noclip"); + return 1; +} + +string GetHelp(){ + return ("Syntax: noclip [ on | off ]\n\n"+ + "Allows you to travel to adjacent rooms known to the "+ + "mud, even if a door is in the way or there is no "+ + "explicit exit in that direction.\nSee also: "+ + "showgrid, wizmap, minimap, prox"); +} diff --git a/lib/cmds/creators/notices.c b/lib/cmds/creators/notices.c new file mode 100644 index 0000000..f4cb945 --- /dev/null +++ b/lib/cmds/creators/notices.c @@ -0,0 +1,64 @@ +/* /cmds/creators/notices + * from the Dead Souls 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(); + int x; + 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( !NOTIFY_D->eventPrintNotices(this_player(), x) ) + return "No recent notices found."; + else return 1; +} + +string GetHelp(string foo) { + string str; + str = "Syntax: notices [number of days back]\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."; + if( archp(this_player()) ) + str += "\nArch 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 "; + return str; +} diff --git a/lib/cmds/creators/ping.c b/lib/cmds/creators/ping.c new file mode 100644 index 0000000..4a4c68a --- /dev/null +++ b/lib/cmds/creators/ping.c @@ -0,0 +1,27 @@ +#include +#include + +inherit LIB_DAEMON; + +mixed cmd(string str) { + string target; + if(!str || str == "") str = mud_name(); + target = INTERMUD_D->GetMudName(str); + if(!target){ + write("Unknown target mud."); + return 1; + } + this_player()->SetProperty("pinging",1); + SERVICES_D->eventSendAuthRequest(target); + return 1; +} + +string GetHelp() { + return ("Syntax: ping [mudname]\n\n" + "Pings a mud to test this mud's 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."); +} diff --git a/lib/cmds/creators/polyglottize.c b/lib/cmds/creators/polyglottize.c new file mode 100644 index 0000000..04165c5 --- /dev/null +++ b/lib/cmds/creators/polyglottize.c @@ -0,0 +1,40 @@ +#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; +} + +string GetHelp() { + return ("Syntax: polyglottize \n\n" + "Make the target able to understand all languages."); +} diff --git a/lib/cmds/creators/praces.c b/lib/cmds/creators/praces.c new file mode 100644 index 0000000..10e43b4 --- /dev/null +++ b/lib/cmds/creators/praces.c @@ -0,0 +1,26 @@ +/* /cmds/creator/mraces.c + * A tool for cres which displays a listing of all available player races + * Blitz@NM-IVD + */ + +#include +#include + +mixed cmd(string str) { + string *types; + + types = load_object(RACES_D)->GetRaces(1); + if( !sizeof(types) ) { + return "No list at this time."; + } + types = sort_array(types, 1); + message("help", format_page(types, 5), this_player() ); + return 1; +} + +string GetHelp() { + return ("Syntax: praces\n\n" + "A simple tool for creators which will list " + "available player races."); +} + diff --git a/lib/cmds/creators/purge.c b/lib/cmds/creators/purge.c new file mode 100644 index 0000000..db153ee --- /dev/null +++ b/lib/cmds/creators/purge.c @@ -0,0 +1,48 @@ +#include +#include ROOMS_H +#include + +inherit LIB_DAEMON; + +mixed cmd(string args) { + object array obs, items, users; + object ob; + + if( !args || args == "" ) { + ob = environment(this_player()); + } + else { + ob = get_object(args); + } + if( !ob ) { + return "No " + args + " found."; + } + this_player()->eventPrint(sprintf("Cleaning %O", ob), MSG_SYSTEM); + say(this_player()->GetName()+" purges "+ob->GetShort()+"."); + obs = filter(all_inventory(ob), (: !userp($1) && + !inherits(LIB_DUMMY, $1) && base_name($1) != LIB_DUMMY :) ); + users = filter(deep_inventory(ob), (: userp($1) :) ); + foreach(object user in users){ + if(environment(user) != ob){ + user->eventMove(environment(this_player())); + } + } + foreach(object item in obs) { + if( item ) { + if(!(item->eventMove(ROOM_FURNACE))){ + object *srs = deep_inventory(item) + ({ item }); + foreach(object bsns in srs){ + bsns->eventDestruct(); + if(bsns) destruct(bsns); + } + } + } + } + return 1; +} + +string GetHelp() { + return ("Syntax: purge [OBJECT]\n\n" + "This command destroys non-dummy, non-user objects in the inventory " + "of the specified object."); +} diff --git a/lib/cmds/creators/pwhere.c b/lib/cmds/creators/pwhere.c new file mode 100644 index 0000000..cd2c295 --- /dev/null +++ b/lib/cmds/creators/pwhere.c @@ -0,0 +1,37 @@ +#include + +inherit LIB_DAEMON; + +varargs int cmd(string str){ + object tmp, player, mount, room; + string name; + if(!str){ + write("Try: help pwhere"); + return 1; + } + player = find_player(str); + if(!player){ + write("That person is not logged in."); + return 1; + } + else name = player->GetShort(); + tmp = environment(player); + if(!tmp){ + write(name+" has no environment."); + return 1; + } + if(living(tmp) && environment(tmp)){ + mount = tmp; + room = environment(tmp); + } + else room = tmp; + write(name+" is"+(mount ? " mounted on "+mount->GetPlainShort() : "")+ + " in "+room->GetShort()+" ( "+base_name(room)+" )"); + return 1; +} + +string GetHelp(){ + return "Syntax: pwhere \n\n" + "Tells you the location of the person specified.\n" + "See also: people, who"; +} diff --git a/lib/cmds/creators/quell.c b/lib/cmds/creators/quell.c new file mode 100644 index 0000000..daa17b0 --- /dev/null +++ b/lib/cmds/creators/quell.c @@ -0,0 +1,29 @@ +#include +#include + +inherit LIB_COMMAND; + +int cmd(string str){ + object who = this_player(); + object env = environment(who); + if(!env){ + write("No environment."); + return 1; + } + write("You casually wave your hand, and bring about peace."); + say(who->GetCapName()+" waves "+possessive(who)+" hand "+ + "and brings peace to the area."); + foreach(object combatant in get_livings(env)){ + if(combatant->GetInCombat()){ + tell_object(combatant,"You stop fighting."); + } + combatant->eventQuell(); + } + return 1; +} + +string GetHelp(string str) { + return "Syntax: quell\n\n" + "This command brings peace between combatants in your environment.\n" + "See also: unquell"; +} diff --git a/lib/cmds/creators/realms.c b/lib/cmds/creators/realms.c new file mode 100644 index 0000000..4749d20 --- /dev/null +++ b/lib/cmds/creators/realms.c @@ -0,0 +1,38 @@ +/* /cmds/creators/realms.c + * from the Dead Souls Library + * created by Blitz@Dead Souls + */ + +static mapping Stats = ([ ]); + +int sortFunction(string a, string b) { + if( Stats[a]["moves"] > Stats[b]["moves"] ) return -1; + else if( Stats[a]["moves"] < Stats[b]["moves"] ) return 1; + else return 0; +} + +mixed cmd(string str) { + string *names, *text; + + Stats = author_stats(); + names = sort_array(keys(Stats), (: sortFunction :)); + text = ({ "\t[ %^CYAN%^Creator Area Statistics...%^RESET%^ ]" }); + 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; +} + +string GetHelp() { + return ("Syntax: realms\n\n" + "A creator command that displays individual author " + "statistics relative to the \"areas\" found within " + "their directories.\n" + "See also: man author_stats"); +} diff --git a/lib/cmds/creators/rehash.c b/lib/cmds/creators/rehash.c new file mode 100644 index 0000000..c3faf2a --- /dev/null +++ b/lib/cmds/creators/rehash.c @@ -0,0 +1,25 @@ +/* /cmds/creator/rehash.c + * 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; +} + +string GetHelp() { + return ("Syntax: rehash \n\n" + "This command allows creators to refresh the specified path's " + "command parsing lookup tables."); +} + diff --git a/lib/cmds/creators/replog.c b/lib/cmds/creators/replog.c new file mode 100644 index 0000000..43dfb02 --- /dev/null +++ b/lib/cmds/creators/replog.c @@ -0,0 +1,29 @@ +// /bin/dev/_replog.c +// from the Dead Souls Mudlib +// Views the report log for the player named +// created by Descartes of Borg 930623 + +#include + +inherit LIB_DAEMON; + +int cmd(string str) { + if(!str) str = 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; +} + +string GetHelp() { + return ("Syntax: replog [logname]\n\n" + "Tails the reports log of the immortal or domain named.\n" + "If no immortal or domain is named, the report log is given\n" + "for the person issuing the command."); +} diff --git a/lib/cmds/creators/reset.c b/lib/cmds/creators/reset.c new file mode 100644 index 0000000..93528fa --- /dev/null +++ b/lib/cmds/creators/reset.c @@ -0,0 +1,34 @@ +// /bin/dev/_reset.c +// Reset command +// created by Descartes of Borg 24 Nov 1992 + +#include + +inherit LIB_DAEMON; + +int cmd(string str) { + object ob; + + if(!str || str == "here") { + environment(this_player())->reset(); + write("You reset the room.\n"); + return 1; + } + ob = present(str, environment(this_player())); + if(!ob) ob = present(str, this_player()); + if(!ob) ob = parse_objects(environment(this_player()), str); + if(!ob) ob = parse_objects(this_player(), str); + if(!ob) { + write("That object can't be found."); + return 1; + } + else ob->reset(); + write("You reset "+str+".\n"); + return 1; +} + +string GetHelp() { + return ("Syntax: reset [object | file]\n\n"+ + "Resets the object named or the environment you are in if no object\n"+ + "is named."); +} diff --git a/lib/cmds/creators/resolve.c b/lib/cmds/creators/resolve.c new file mode 100644 index 0000000..14b8294 --- /dev/null +++ b/lib/cmds/creators/resolve.c @@ -0,0 +1,40 @@ +#include +#include + +inherit LIB_DAEMON; + +mapping NamesMap = ([]); + +varargs int cmd(string str) +{ + if(!RESOLV_D->GetResolving()){ + write("This mud is not using name resolution."); + return 1; + } + + write("Querying for information on "+str+"..."); + RESOLV_D->eventResolve(str, "resolve_callback"); + NamesMap[str] = this_player(); + return 1; +} + +void resolve_callback(string name, string number, int key){ + string cle; + object ob; + if(NamesMap[number]) cle = number; + else if(NamesMap[name]) cle = name; + ob = NamesMap[cle]; + + map_delete(NamesMap, cle); + + if(ob){ + ob->eventPrint(number+" resolves to: "+name); + } +} + +string GetHelp(){ + return "Syntax: resolve \n\n" + "Provides information on the internet name of an " + "ip address, and vice versa.\n" + "See also: wget"; +} diff --git a/lib/cmds/creators/return.c b/lib/cmds/creators/return.c new file mode 100644 index 0000000..0b44532 --- /dev/null +++ b/lib/cmds/creators/return.c @@ -0,0 +1,59 @@ +#include + +inherit LIB_DAEMON; + +mixed cmd(string args) { + object ob, room, where; + string last_loc, name; + int result; + + if( !args || args == "" ){ + ob = this_player(); + name = "You"; + } + else { + if( !(ob = find_player(convert_name(args))) && !(ob = find_living(args)) ) + return "No such being exists anywhere presently."; + name = "They"; + } + if(!last_loc = ob->GetProperty("LastLocation")){ + write(name+" have nowhere to return to."); + return 1; + } + + if(grepp(last_loc,"#")) where = find_object(last_loc); + else where = load_object(last_loc); + + if(!where){ + write("There is a problem with that location."); + write(name+" remain where "+lower_case(name)+" are."); + return 1; + } + + if(environment(ob) == where){ + write(name+" are already there."); + return 1; + } + + else result = ob->eventMoveLiving(where); + + if(ob != this_player()){ + if(result){ + message("system", "You have been returned to your previous location by " + + this_player()->GetName() + ".", ob); + message("system", "You return " + ob->GetCapName() + + " to their previous location.", this_player()); + } + else { + return "Failed to move " + ob->GetCapName() + "."; + } + } + return 1; +} + +string GetHelp() { + return ("Syntax: return [living]\n\n" + "Sends someone back, after a trans.\n" + "With no arguments, sends you to your last location.\n" + "See also: goto"); +} diff --git a/lib/cmds/creators/rot.c b/lib/cmds/creators/rot.c new file mode 100644 index 0000000..2fac3d0 --- /dev/null +++ b/lib/cmds/creators/rot.c @@ -0,0 +1,109 @@ +#include +#include + +inherit LIB_COMMAND; + +mapping alpha1 = ([ + 1 : "a", + 2 : "b", + 3 : "c", + 4 : "d", + 5 : "e", + 6 : "f", + 7 : "g", + 8 : "h", + 9 : "i", + 10 : "j", + 11 : "k", + 12 : "l", + 13 : "m", + 14 : "n", + 15 : "o", + 16 : "p", + 17 : "q", + 18 : "r", + 19 : "s", + 20 : "t", + 21 : "u", + 22 : "v", + 23 : "w", + 24 : "x", + 25 : "y", + 26 : "z", + ]); + +mapping alpha2 = ([]); + +string doRotate(int code, string str){ + string *str_array = explode(str,""); + string ret = ""; + + foreach(string element in str_array){ + if(alpha2[element]){ + int operand; + operand = alpha2[element]+code; + if(operand > 26){ + operand -= 26; + } + if(operand < 1){ + operand = 26 - abs(operand); + } + ret += alpha1[operand]; + } + else ret += element; + } + return ret; +} + +int cmd(string str){ + int code; + string tmp, tmp2; + string ret = ""; + string *str_array = ({}); + + if(!str){ + write("Please see \"help rot\"."); + return 1; + } + + str = lower_case(str); + + if(!alpha2 || !sizeof(alpha2)){ + alpha2 = ([]); + foreach(mixed key, mixed val in alpha1) alpha2[val] = key; + } + + if(sscanf(str,"%d %s",code, tmp)){ + str_array = explode(str,""); + ret = doRotate(code, str); + } + + else if(sscanf(str,"%s %s",tmp, tmp2)){ + if(tmp = "-q"){ + string tmp3, tmp4; + if(sscanf(tmp2,"%s %s",tmp3, tmp4) == 2 && + sizeof(tmp3) == 1 && sizeof(tmp4) == 1){ + ret = alpha2[tmp3] - alpha2[tmp4]; + } + else { + for(int i=0;i<26;i++){ + write(i+": "+doRotate(i, tmp2)); + } + } + } + } + + write("Output: "+ret); + return 1; +} + +string GetHelp(string str) { + return "Syntax: rot -q \n" + " rot \n" + "Provides arbitrary alphabetical place rotation " + "of letters. For example, \n" + "rot 13 hello\n" + "returns uryyb, and\n" + "rot 13 uryyb\n" + "returns hello."; +} diff --git a/lib/cmds/creators/scan.c b/lib/cmds/creators/scan.c new file mode 100644 index 0000000..db13270 --- /dev/null +++ b/lib/cmds/creators/scan.c @@ -0,0 +1,91 @@ +/* /cmds/creator/scan.c + * from the Foundation II LPC Library + * scans an object + * 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(ob->GetKeyName()), + ob->GetMass(), ob->GetValue(), + intp(ob->GetClass()) ? 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 +#include + +inherit LIB_COMMAND; + +int cmd(string str){ + int i, cols = 2; + string *ret; + if(str) i = atoi(str); + if(i) cols = i; + ret = explode(format_page(sefuns(), cols), "\n"); + this_player()->eventPage(ret); + return 1; +} + +string GetHelp(string str) { + return "Syntax: sefuns [COLUMNS]\n\n" + "Displays all available simulated efuns. If a number is given, the " + "output is broken up into the number of columns specified." + "\nSee also efun, efuns, sefun, lfun, lfuns, showfuns, findfun"; +} diff --git a/lib/cmds/creators/shadows.c b/lib/cmds/creators/shadows.c new file mode 100644 index 0000000..7834699 --- /dev/null +++ b/lib/cmds/creators/shadows.c @@ -0,0 +1,39 @@ +#include +#include + +inherit LIB_DAEMON; + +mixed cmd(string str) { + object target; + string ret = "Shadows found: \n"; + mapping retmap = ([]); + + if(!str || str == "") str = "me"; + + if(str == "me") str = this_player()->GetKeyName(); + if(!target = present(str, environment(this_player()))){ + write(capitalize(str)+" is not here."); + return 1; + } + + retmap = target->GetShadows(); + + if(!sizeof(retmap)){ + write("No shadows found."); + return 1; + } + + foreach(mixed key, mixed val in retmap){ + string obbase; + if(objectp(key)) obbase = base_name(key)+".c"; + else obbase = val; + ret += obbase + " " + val + "\n"; + } + write(ret); + return 1; +} + +string GetHelp() { + return ("Syntax: shadows \n\n" + "Identify shadows currently attached to an object."); +} diff --git a/lib/cmds/creators/showgrid.c b/lib/cmds/creators/showgrid.c new file mode 100644 index 0000000..b23d25b --- /dev/null +++ b/lib/cmds/creators/showgrid.c @@ -0,0 +1,52 @@ +#include + +inherit LIB_DAEMON; + +varargs int cmd(string str){ +#if GRID + if(!str){ + write("Showgrid is "+ (this_player()->GetVisibleGrid() ? "on." : "off.")); + return 1; + } + if(str == "on"){ + if(this_player()->GetVisibleGrid()){ + write("You are already seeing grid coordinates."); + return 1; + } + this_player()->SetVisibleGrid(1); + if(this_player()->GetVisibleGrid()){ + write("You are now seeing grid coordinates."); + } + else { + write("Fail. Coordinates are not shown."); + } + return 1; + } + if(str == "off"){ + if(!(this_player()->GetVisibleGrid())){ + write("Grid coordinate display is already disabled."); + return 1; + } + this_player()->SetVisibleGrid(0); + if(!(this_player()->GetVisibleGrid())){ + write("Grid coordinate display is now disabled."); + } + else { + write("Fail. Coordinates are still displaying."); + } + return 1; + } + write("Try: help showgrid"); + return 1; +#else + write("This feature is disabled."); + return 1; +#endif +} + +string GetHelp(){ + return ("Syntax: showgrid [ on | off ]\n\n" + "Adds global grid coordinates for you environment " + "to the room description, if " + "ROOMS_D enables them and they are available."); +} diff --git a/lib/cmds/creators/showtree.c b/lib/cmds/creators/showtree.c new file mode 100644 index 0000000..5c33bd8 --- /dev/null +++ b/lib/cmds/creators/showtree.c @@ -0,0 +1,80 @@ +/* /cmds/creator/showtree.c + * idea borrowed from LIMA for Dead Souls + * shows information about an object + * created by Beek@Dead Souls + */ + +#include +#include "include/showtree.h" + +inherit LIB_DAEMON; + +private string Error; + +mixed cmd(string str) { + string func, file; + object tmp; + + 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; + file = str; + } + } + tmp = get_object(file); + file = absolute_path(this_player()->query_cwd(), file); + if(!file_exists(file) && !file_exists(file+".c")){ + if(tmp) + file = base_name(tmp); + } + if(!file_exists(file) && !file_exists(file+".c")){ + write("Cannot find the file specified."); + return 1; + } + str = ShowTree(file, func, 0); + if( !str ) return Error; + this_player()->eventPage(explode(str, "\n"), "system"); + return 1; +} + +string ShowTree(string file, string func, int indent) { + 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)) ) { + Error = "Error in loading " + file + "."; + return 0; + } + str = sprintf("%*-' 's" + file, indent*4, ""); + if( func && (function_exists(func, ob) == file) ) + str += " (" + func + " defined)\n"; + else str += "\n"; + if( !func || function_exists(func, ob) ) found = 1; + indent++; + foreach(file in inherit_list(ob)) { + string tmp; + + tmp = ShowTree(file, func, indent); + if( tmp && tmp != "" ) { + str += tmp; + found = 1; + } + else if( !tmp ) return 0; + } + return (found ? str : ""); +} + +string GetHelp() { + return ("Syntax: showtree \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" + "See also: help"); +} diff --git a/lib/cmds/creators/stargate.c b/lib/cmds/creators/stargate.c new file mode 100644 index 0000000..7cc7b86 --- /dev/null +++ b/lib/cmds/creators/stargate.c @@ -0,0 +1,54 @@ +#include +#include + +inherit LIB_DAEMON; + +mixed cmd(string str){ + mapping stargates; + string *gates; + string gatename; + int err; + object sgd; + + err = catch( sgd = load_object(STARGATE_D) ); + + if(!sgd || err){ + write("There appears to be a problem with the stargate daemon."); + return 1; + } + + stargates = STARGATE_D->GetStargates(); + + if(sizeof(stargates)) gates = keys(stargates); + + if(!gates){ + write("There are no known stargates."); + return 1; + } + + if(!str){ + write("Known stargates:"); + write(implode(gates, ", ")); + return 1; + } + + gatename = lower_case(str); + + if(member_array(gatename, gates) == -1){ + write("Unknown stargate: \""+str+"\""); + return 1; + } + + write(str); + foreach(mixed key, mixed val in stargates[gatename]){ + write(key + ": " + val); + } + + return 1; +} + +string GetHelp() { + return ("Syntax: stargate [name]\n\n" + "Without an argument, lists known stargates. If the name " + "of a stargate is specified, information on it is listed."); +} diff --git a/lib/cmds/creators/tellblock.c b/lib/cmds/creators/tellblock.c new file mode 100644 index 0000000..9e2e1eb --- /dev/null +++ b/lib/cmds/creators/tellblock.c @@ -0,0 +1,23 @@ +// Tellblock +// A wiz utility to block tells only by Gregon@Dead Souls +// based on _codeblock.c by Descartes of Borg. +// 06Nov1993 + + +#include + +inherit LIB_DAEMON; + +#define CHANNELS "bin/daemon/channels" + +int cmd() { + this_player()->SetBlocked("tell"); + if(this_player()->GetBlocked("tell")) write("Tellblock on.\n"); + else write("Tellblock off.\n"); + return 1; +} + +string GetHelp() { + return ("Syntax: tellblock\n\n"+ + "Toggles the blocking of tells on and off."); +} diff --git a/lib/cmds/creators/trans.c b/lib/cmds/creators/trans.c new file mode 100644 index 0000000..624110d --- /dev/null +++ b/lib/cmds/creators/trans.c @@ -0,0 +1,38 @@ +/* /cmds/creator/trans.c + * from the Foundation II LPC Library + * moves a player to your location + * created by Descartes of Borg 950425 + */ + +#include + +inherit LIB_DAEMON; + +mixed cmd(string args) { + object ob; + + 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 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 " + + this_player()->GetName() + ".", ob); + if( !(ob->eventMoveLiving(environment(this_player()))) ) + return "Failed to move " + ob->GetCapName() + "."; + else message("system", "You trans " + ob->GetCapName() + + " to you.", this_player()); + return 1; +} + +string GetHelp() { + return ("Syntax: trans \n\n" + "Brings a living thing to your location.\n" + "See also: return, goto, move, expel"); +} diff --git a/lib/cmds/creators/transfer.c b/lib/cmds/creators/transfer.c new file mode 100644 index 0000000..1e948b3 --- /dev/null +++ b/lib/cmds/creators/transfer.c @@ -0,0 +1,59 @@ +/* /cmds/creators/transfer.c + * From the Dead Souls Mud 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 = get_object(a); + destination = get_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: transfer \n\n" + "Allows you to transfer the object you name into the container " + "you name.\n" + "See also: trans, expel, goto, return"); +} diff --git a/lib/cmds/creators/types.c b/lib/cmds/creators/types.c new file mode 100644 index 0000000..40da77a --- /dev/null +++ b/lib/cmds/creators/types.c @@ -0,0 +1,73 @@ +#include +#include + +inherit LIB_DAEMON; +string file, contents, program, header; +string *types = sort_array(keys(TYPES_D->GetTypes()),1); + +varargs int cmd(string str){ + int err, i; + string s1, s2; + string file = "/open/typecheck.c"; + mixed ret, tmpret; + if(!str){ + write("Try: help types"); + return 1; + } + i = sscanf(str,"%s %s", s1, s2); + if(i != 2 || member_array(s1, types) == -1){ + write("Try: help types"); + return 1; + } + contents = header+program; + contents = replace_string(contents,"$S",s2); + unguarded((: write_file($(file), contents,1) :)); + reload(file,0,1); + err = catch( tmpret = file->typecheck() ); + if(err || (stringp(tmpret) && !strsrch(tmpret,"DEFINED_D:"))){ + write("\n"+ tmpret +" appears to be an invalid integer value."); + return 1; + } + else ret = TYPES_D->eventCalculateTypes(s1, tmpret); + if(arrayp(ret)) ret = implode(ret," "); + write("The value "+tmpret+" for "+s1+" is: "+ret); + return 1; +} + +string GetHelp(){ + string type_help = implode(types,", "); + return ("Syntax: types \n\n" + "Returns the defined bit checks or defined token " + "for the specified value.\n" + "Examples:\n" + "types parser_error 4\n" + "types armor_types 512|128\n" + "types damage_types 128\n\n" + "Valid type names: "+type_help+".\n\n" + "Note that entering an invalid value will result in a " + "rather unattractive error message. This is normal and " + "harmless.\n" + "See also: defines"); +} + +static void create() { + string *includes = ({}); + ::create(); + foreach(string str in get_dir("/secure/include/")){ + if(str == "object.h") continue; + includes += ({ "#include <"+str+">" }); + } + foreach(string str in get_dir("/include/")){ + includes += ({ "#include <"+str+">" }); + } + header = implode(includes,"\n"); + program = "\nmixed typecheck(){"+ + "\nint err;"+ + "\nmixed ret;"+ + "\nerr = catch( ret = $S );"+ + "\nif(err) ret = \"DEFINED_D: error\";"+ + "\nelse if(undefinedp(ret)) ret = \"DEFINED_D: undefined\";"+ + "\nreturn ret;"+ + "\n}"; + write_file("/open/prog.c",header+program,1); +} diff --git a/lib/cmds/creators/unanchor.c b/lib/cmds/creators/unanchor.c new file mode 100644 index 0000000..4ae7356 --- /dev/null +++ b/lib/cmds/creators/unanchor.c @@ -0,0 +1,50 @@ +#include +#include + +inherit LIB_DAEMON; + +mixed cmd(string str) { + object target; + int arch = adminp(this_player()); + int ret, curr; + + if(!sizeof(str)) str = "me"; + if(str == "me") str = this_player()->GetKeyName(); + if(!target = present(str, environment(this_player()))){ + if(arch && (target = find_player(str))){ + write("User found."); + } + else { + write("They're not here."); + return 1; + } + } + if(living(target) && !arch && target != this_player()){ + write("You can only unanchor yourself with this command."); + return 1; + } + if(!(curr = target->GetAnchored())){ + if(target != this_player()) str = nominative(target)+"'s"; + else str = "You're "; + write(capitalize(str) + " already unanchored."); + return 1; + } + ret = target->SetAnchored(0); + if(ret == curr){ + write("Nothing happens"); + return 1; + } + if(target != this_player()){ + tell_object(target, capitalize(this_player()->GetName())+ + " unanchors you."); + } + else str = "yourself"; + write("You unanchor "+str+"."); + return 1; +} + +string GetHelp() { + return ("Syntax: unanchor \n\n" + "Removes a type of blocked movement from the target..\n" + "See also: anchor"); +} diff --git a/lib/cmds/creators/unmorse.c b/lib/cmds/creators/unmorse.c new file mode 100644 index 0000000..c0b5f76 --- /dev/null +++ b/lib/cmds/creators/unmorse.c @@ -0,0 +1,24 @@ +#include +#include + +inherit LIB_COMMAND; + +int cmd(string str){ + string ret = ""; + + if(!str){ + write("See: help morse"); + return 1; + } + + ret = unmorse(str); + + write("Output: "+ret); + return 1; +} + +string GetHelp(){ + return "Syntax: unmorse \n\n" + "Decodes a morse string into its alphanumeric representation.\n" + "See also: morse"; +} diff --git a/lib/cmds/creators/unquell.c b/lib/cmds/creators/unquell.c new file mode 100644 index 0000000..d087a1e --- /dev/null +++ b/lib/cmds/creators/unquell.c @@ -0,0 +1,22 @@ +#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(){ + return "Syntax: unquell\n\n" + "Allows quelled combat to resume.\n" + "See also: quell"; +} diff --git a/lib/cmds/creators/vis.c b/lib/cmds/creators/vis.c new file mode 100644 index 0000000..ddeeb9a --- /dev/null +++ b/lib/cmds/creators/vis.c @@ -0,0 +1,23 @@ +// /bin/dev/_vis.c +// from the Dead Souls mudlib +// created by Descartes of Borg october 1992 + +#include + +inherit LIB_DAEMON; + +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; +} + +string GetHelp(){ + return "Syntax: vis\n\n" + "Makes you visible if you weren't already." + "\nSee also: invis"; +} diff --git a/lib/cmds/creators/whereis.c b/lib/cmds/creators/whereis.c new file mode 100644 index 0000000..dc4a9e7 --- /dev/null +++ b/lib/cmds/creators/whereis.c @@ -0,0 +1,90 @@ +#include +#include + +inherit LIB_DAEMON; + +mixed cmd(string str) { + object env, my_env, player; + string coords, my_coords, ret, subret; + int x, y, z; + int x2, y2, z2; + int x3, y3, z3; + if(!sizeof(str)) str = "me"; + if(str == "me" || str == "myself") str = this_player()->GetKeyName(); + player = find_player(str); + if(!player){ + write("That person could not be found."); + return 1; + } + env = environment(player); + if(env && living(env)) env = environment(env); + if(!env){ + write("That player appears to lack an environment."); + return 1; + } + my_env = environment(this_player()); + if(my_env && living(my_env)) my_env = environment(my_env); + if(env == my_env){ + write(capitalize(nominative(player))+" is right here!"); + return 1; + } + coords = ROOMS_D->GetCoordinates(env); + ret = capitalize(player->GetKeyName())+" is in "+ + env->GetShort()+", base name "+base_name(env); + if(sizeof(coords) > 2){ + ret += " , coordinates: "+coords+" ."; + } + else { + ret += " ."; + } + if(my_env && sizeof(my_coords = ROOMS_D->GetCoordinates(my_env))){ + if(sscanf(coords,"%d,%d,%d",x,y,z) == 3 && + sscanf(my_coords,"%d,%d,%d",x2,y2,z2) == 3){ + int dist; + float deg; + subret = ""; + deg = bearing(x2,y2,x,y); + x3 = abs(x - x2); + y3 = abs(y - y2); + z3 = abs(z - z2); + if(x3 > y3) dist = x3; + else dist = y3; + if(z3 > dist) dist = z3; + if(y2 < y){ + subret += "north"; + } + else if(y2 > y){ + subret += "south"; + } + if(x2 < x){ + subret += "east"; + } + else if(x2 > x){ + subret += "west"; + } + if(sizeof(subret)){ + subret = "\n" + capitalize(nominative(player))+ " is "+ + cardinal(dist) + " rooms away, " + subret + " of you"; + subret += " ("+deg+" degrees)"; + if(z2 < z) subret += " and above."; + else if(z2 > z) subret += " and below."; + else subret += "."; + } + else { + subret = "\n" + capitalize(nominative(player))+ " is "+ + cardinal(dist) + " rooms "; + if(z2 < z) subret += "above."; + else if(z2 > z) subret += "below."; + } + } + } + if(subret) ret += subret; + write(ret); + return 1; +} + +string GetHelp() { + return ("Syntax: whereis \n\n" + "Indicates the filename and coordinates (if available) "+ + "of the named player."); +} diff --git a/lib/cmds/creators/whomuffed.c b/lib/cmds/creators/whomuffed.c new file mode 100644 index 0000000..f24021c --- /dev/null +++ b/lib/cmds/creators/whomuffed.c @@ -0,0 +1,39 @@ +#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; +} + +string GetHelp() { + return ("Syntax: whomuffed [name]\n\n" + "This command lists who is ignored by the player specified.\n" + "See also: earmuff, unmuff"); +} + diff --git a/lib/cmds/creators/wiz.c b/lib/cmds/creators/wiz.c new file mode 100644 index 0000000..f421cf3 --- /dev/null +++ b/lib/cmds/creators/wiz.c @@ -0,0 +1,32 @@ +#include +#include + +mixed cmd(){ + object who = this_player(); + object env = environment(this_player()); + object room = load_object(ROOM_WIZ); + int ret, err; + + if(!room){ + write("There seems to be a problem with the wiz room."); + return 1; + } + + if(env && env == room){ + write("Wiz!"); + return 1; + } + + err = catch( ret = who->eventMoveLiving(room) ); + + if(err || !ret){ + write("Looks like some kind of problem getting into the wiz room."); + } + + return 1; +} + +string GetHelp(){ + return ("Syntax: wiz\n\n" + "Transports you to the wiz room."); +} diff --git a/lib/cmds/creators/wizlist.c b/lib/cmds/creators/wizlist.c new file mode 100644 index 0000000..3c2e897 --- /dev/null +++ b/lib/cmds/creators/wizlist.c @@ -0,0 +1,28 @@ +#include +#include + +inherit LIB_COMMAND; + +int cmd(string str){ + string *raw_array; + string *grps = sort_array(groups(), 1); + string ret = ""; + raw_array = sort_array(PLAYERS_D->GetCreatorList(),1); + foreach(mixed wiz in raw_array){ + string tmp; + if(!wiz || !stringp(wiz)) continue; + tmp = wiz; + foreach(string group in grps){ + if(member_group(wiz, group)) tmp += " "+group+","; + } + if(last(tmp,1) == ",") tmp = truncate(tmp,1); + ret += capitalize(tmp)+"\n"; + } + print_long_string(this_player(),"Known active creators: \n"+ret); + return 1; +} + +string GetHelp(string str) { + return "Syntax: wizlist\n\n" + "Displays a list of known active (non-ridded) creators."; +} diff --git a/lib/cmds/creators/wizmap.c b/lib/cmds/creators/wizmap.c new file mode 100644 index 0000000..ead9f6b --- /dev/null +++ b/lib/cmds/creators/wizmap.c @@ -0,0 +1,41 @@ +#include + +inherit LIB_DAEMON; + +mixed cmd(string args) { +#if (WIZMAP && GRID) + int status = this_player()->GetProperty("wizmapping"); + string sstatus = "are"; + if(!status) sstatus = "are not"; + if(!args){ + write("You "+sstatus+" wizmapping."); + return 1; + } + if(args == "on"){ + if(status) write("You are already wizmapping."); + else write("You enable wizmapping."); + this_player()->SetProperty("wizmapping", 1); + return 1; + } + + if(args == "off"){ + if(!status) write("You are already not wizmapping."); + else write("You disable wizmapping."); + this_player()->SetProperty("wizmapping", 0); + return 1; + } + + write("Try: help wizmap"); + return 1; +#else + write("This feature is disabled."); + return 1; +#endif +} + +string GetHelp() { + return ("Syntax: wizmap [on | off]\n\n" + "If enabled, a simple map of your surroundings is displayed " + "when your environment is described to you.\nSee also: " + "env, terminal, brief, mute, gag, minimap."); +} diff --git a/lib/cmds/creators/wizroll.c b/lib/cmds/creators/wizroll.c new file mode 100644 index 0000000..344c384 --- /dev/null +++ b/lib/cmds/creators/wizroll.c @@ -0,0 +1,27 @@ +#include +#include + +inherit LIB_COMMAND; + +int cmd(string str){ + mixed *tmp, *tmp2 = ({}); + + if(!str || !(tmp = roll(str))){ + write(this_object()->GetHelp()); + return 1; + } + foreach(mixed foo in tmp){ + tmp2 += ({ itoa(foo) }); + } + write("The individual rolls are: "+implode(tmp2[1..]," ")); + write("The sum total roll is: "+tmp[0]); + return 1; + +} + +string GetHelp(){ + return "Syntax: wizroll \n\n" + "Simulates a roll of dice. For example, 'wizroll 2d6' simulates a " + "roll of two six-sided dice. Dice are not limited to realistic " + "topologies. One may roll a 99d1025."; +} diff --git a/lib/cmds/creators/wizvision.c b/lib/cmds/creators/wizvision.c new file mode 100644 index 0000000..efc59ff --- /dev/null +++ b/lib/cmds/creators/wizvision.c @@ -0,0 +1,45 @@ +#include + +inherit LIB_DAEMON; + +varargs int cmd(string str){ + if(!str){ + write("Wizvision is "+ (this_player()->GetWizVision() ? "on." : "off.")); + return 1; + } + if(str == "on"){ + if(this_player()->GetWizVision()){ + write("Your wizvision is already on.\n"); + return 1; + } + this_player()->SetWizVision(1); + if(this_player()->GetWizVision()){ + write("Wizvision is now on."); + } + else { + write("Fail. Wizvision is not on."); + } + return 1; + } + if(str == "off"){ + if(!(this_player()->GetWizVision())){ + write("Your wizvision is already off.\n"); + return 1; + } + this_player()->SetWizVision(0); + if(!(this_player()->GetWizVision())){ + write("Wizvision is now off."); + } + else { + write("Fail. Wizvision is still on."); + } + return 1; + } + write("Try: help wizvision"); + return 1; +} + +string GetHelp(){ + return ("Syntax: wizvision [ on | off ]\n\n"+ + "Enables clear vision in all lighting situations."); +} diff --git a/lib/cmds/players/annoyblock.c b/lib/cmds/players/annoyblock.c new file mode 100644 index 0000000..2a5f945 --- /dev/null +++ b/lib/cmds/players/annoyblock.c @@ -0,0 +1,45 @@ +#include + +inherit LIB_DAEMON; + +varargs int cmd(string str){ + if(!str){ + write("Annoyblock is "+ (this_player()->GetAnnoyblock() ? "on." : "off.")); + return 1; + } + if(str == "on"){ + if(this_player()->GetAnnoyblock()){ + write("Your annoyblock is already on.\n"); + return 1; + } + this_player()->SetAnnoyblock(1); + if(this_player()->GetAnnoyblock()){ + write("Annoyblock is now on."); + } + else { + write("Fail. Annoyblock is not on."); + } + return 1; + } + if(str == "off"){ + if(!(this_player()->GetAnnoyblock())){ + write("Your annoyblock is already off.\n"); + return 1; + } + this_player()->SetAnnoyblock(0); + if(!(this_player()->GetAnnoyblock())){ + write("Annoyblock is now off."); + } + else { + write("Fail. Annoyblock is still on."); + } + return 1; + } + write("Try: help annoyblock"); + return 1; +} + +string GetHelp(){ + return ("Syntax: annoyblock [ on | off ]\n\n" + "Blocks annoying messages like \"Joe looks around.\""); +} diff --git a/lib/cmds/players/biography.c b/lib/cmds/players/biography.c new file mode 100644 index 0000000..8c1dc66 --- /dev/null +++ b/lib/cmds/players/biography.c @@ -0,0 +1,144 @@ +/* /cmds/players/biography.c + * from the NIghtmare V Object Library + * biography + * created by Descartes of Borg 951217 + */ + +#include +#include +#include +#include +#include + +inherit LIB_DAEMON; + +mixed cmd(string args) { + class marriage *m; + mapping *deaths; + mapping kills; + string *npcs, *tmp, *col1, *col2, *col3; + string yrstr; + int x, cols, birth, i; + + cols = ((int *)this_player()->GetScreen())[0]; + tmp = ({ center("Biography for " + this_player()->GetShort() + + " on " + mud_name(), cols), "" }); + birth = 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: " + + this_player()->GetLevel(), "Age: " + + ((time() - birth)/YEAR) + " years") }); + tmp += ({ "You are " + 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); + if( x < 0 ) yrstr = (-x) + " BN"; + else yrstr = x + ""; + town = (marr->Location)->GetTown(); + 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 = ({}); + } + if( i = sizeof(m) ) { + tmp += ({ "Past marriages:" }); + while(i--) { + string yrstr2; + + marr = m[i]; + x = query_year(marr->WeddingDate); + if( x < 0 ) yrstr = (-x) + " BN"; + else yrstr = x + ""; + x = query_year(marr->DivorceDate); + if( x < 0 ) yrstr2 = (-x) + " BN"; + else yrstr2 = x + ""; + town = (marr->Location)->GetTown(); + 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 = 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 = STATISTICS_D->GetKills(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 ) { + col1 = npcs[0..0]; + if( x == 2 ) col2 = npcs[1..1]; + else col2 = ({}); + col3 = ({}); + } + else { + x = x/3; + col1 = npcs[0..(x-1)]; + col2 = npcs[x..(x+x-1)]; + 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; +} + +string GetHelp(){ + return ("Syntax: biography\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" + "See also: score"); +} diff --git a/lib/cmds/players/brief.c b/lib/cmds/players/brief.c new file mode 100644 index 0000000..1688cf9 --- /dev/null +++ b/lib/cmds/players/brief.c @@ -0,0 +1,28 @@ +/* /cmds/player/brief.c + * 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; +} + +string GetHelp() { + return ("Syntax: brief [on | off]\n\n" + "This command allows you to toggle brief room descriptions " + "on or off.\nSee also: env"); +} + diff --git a/lib/cmds/players/chan.c b/lib/cmds/players/chan.c new file mode 100644 index 0000000..226a952 --- /dev/null +++ b/lib/cmds/players/chan.c @@ -0,0 +1,125 @@ +#include + +mixed cmd(string args) { + object ob = this_player(); + int i, cre = creatorp(ob); + string *channels; + string command, channel; + if(!args) return "Try: help chan"; + i = sscanf(args, "%s %s", command, channel); + if(!channel) return "Try: help chan"; + channels = distinct_array(ob->GetChannels()); + if(command == "block"){ + if(member_array(channel, channels) == -1){ + write("You are not subscribed to that channel."); + return 1; + } + if(ob->GetBlocked(channel)){ + write(channel + " is already blocked."); + } + else ob->SetBlocked(channel, 1); + return 1; + } + if(command == "unblock"){ + if(member_array(channel, channels) == -1){ + write("You are not subscribed to that channel."); + return 1; + } + if(!ob->GetBlocked(channel)){ + write(channel + " is already unblocked."); + } + else ob->SetBlocked(channel, 0); + return 1; + } + if(!cre){ + write("Try: help chan"); + return 1; + } + if(command == "add"){ + if(!creatorp(this_player())){ + write("Try: help chan"); + return 1; + } + if(channel == "all"){ + string *allchans = CHAT_D->GetChannels(); + allchans += CHAT_D->GetRemoteChannels(); + foreach(string chan in allchans){ + //tc("chan: "+identify(chan)); + } + allchans = sort_array(singular_array(allchans), 1); + allchans -= ({ "muds" }); + foreach(string chan in allchans){ + string lchan; + if(sscanf(chan,"%*s:%s",lchan) != 2) lchan = chan; + if(!ob->GetChannel(lchan)){ + ob->AddChannel(lchan); + if(ob->GetChannel(lchan)){ + write("Added: "+lchan); + } + } + } + write("Done."); + return 1; + } + if(member_array(channel, channels) != -1){ + write("You are already subscribed to that channel."); + return 1; + } + ob->AddChannel(channel); + channels = distinct_array(ob->GetChannels()); + if(member_array(channel, channels) == -1){ + write("You fail to add that channel to yourself."); + } + else { + write("You have added "+channel+" to yourself."); + } + return 1; + } + if(command == "remove"){ + if(!creatorp(this_player())){ + write("Try: help chan"); + return 1; + } + if(channel == "all"){ + string *allchans = ob->GetChannels(); + foreach(string chan in allchans){ + ob->RemoveChannel(chan); + if(!(ob->GetChannel(chan))){ + write("Removed: "+chan); + } + } + write("Done."); + return 1; + } + if(member_array(channel, channels) == -1){ + write("You are already unsubscribed to that channel."); + return 1; + } + ob->RemoveChannel(channel); + channels = distinct_array(ob->GetChannels()); + if(member_array(channel, channels) != -1){ + write("You fail to remove that channel from yourself."); + } + else { + write("You have removed "+channel+" from yourself."); + } + return 1; + } + write("Try: help chan"); + return 1; +} + +string GetHelp(){ + int cre = creatorp(this_player()); + string ret = "Syntax: chan block \n"; + ret += " chan unblock \n"; + if(cre){ + ret += " chan add \n"; + ret += " chan remove \n"; + } + ret += "\n"; + ret += "Displays or modifies the user's channel policy "+ + "on available channels."; + ret += "\nSee also: lines, gag, earmuff, env, hist, channels"; + return ret; +} diff --git a/lib/cmds/players/chancolors.c b/lib/cmds/players/chancolors.c new file mode 100644 index 0000000..44a3d23 --- /dev/null +++ b/lib/cmds/players/chancolors.c @@ -0,0 +1,25 @@ +#include + +inherit LIB_DAEMON; + +mixed cmd(string str) { + int what; + if( !sizeof(str) ) + return "Syntax: chancolors "; + str = lower_case(str); + if( str != "on" && str != "off" ) + return "You can only turn chancolors 'on' or 'off'"; + if(str == "on") what = 0; + else what = 1; + this_player()->SetNoChanColors(what); + message("system", + "Colored channels mode turned "+str+".", + this_player() ); + return 1; +} + +string GetHelp() { + return ("Syntax: chancolors [on | off]\n\n" + "This command allows you to toggle whether you see colors in channel messages. \nNote: This doesn't apply to the normal colors of the channel name."); +} + diff --git a/lib/cmds/players/charmode.c b/lib/cmds/players/charmode.c new file mode 100644 index 0000000..b16024b --- /dev/null +++ b/lib/cmds/players/charmode.c @@ -0,0 +1,36 @@ +#include + +inherit LIB_DAEMON; + +mixed cmd(string str) { +#ifndef __GET_CHAR_IS_BUFFERED__ + write("This game does not support this mode. Ask your "+ + "mud administrator to consider recompiling with "+ + "GET_CHAR_IS_BUFFERED defined."); + return 1; +#endif + if( !sizeof(str) ) + return "Syntax: charmode "; + str = lower_case(str); + + if( str != "on" && str != "off" ) + return "You can only turn charmode 'on' or 'off'"; + if(str == "on") this_player()->SetCharmode(1); + else this_player()->CancelCharmode(); + this_player()->SetProperty("reprompt", this_player()->GetCharmode()); + message("system", + "Your charmode mode is turned "+str+".", + this_player() ); + return 1; +} + +string GetHelp() { + return ("Syntax: charmode [on | off]\n\n" + "Enables or disables 'character mode' for your terminal. " + "Unless you are using a very basic mud client (such as " + "a Linux telnet command) you should not enable this, since " + "most mud clients prefer to use line mode and will break " + "if character mode is enabled.\n" + "See also: reprompt, prompt, env"); +} + diff --git a/lib/cmds/players/colors.c b/lib/cmds/players/colors.c new file mode 100644 index 0000000..fee8b2e --- /dev/null +++ b/lib/cmds/players/colors.c @@ -0,0 +1,37 @@ +#include +#include + +inherit LIB_DAEMON; + +int cmd() { + write( + "%^RED%^RED\t%%^^RED%%^^\t\t%^BOLD%^%%^^BOLD%%^^%%^^RED%%^^%^RESET%^\n" + "%^GREEN%^GREEN\t%%^^GREEN%%^^\t%^BOLD%^%%^^BOLD%%^^%%^^GREEN%%^^%^RESET%^\n" + "%^ORANGE%^ORANGE\t%%^^ORANGE%%^^\t%^BOLD%^%%^^BOLD%%^^%%^^ORANGE%%^^%^RESET%^\n" + "%^YELLOW%^YELLOW\t%%^^YELLOW%%^^\t%^BOLD%^%%^^BOLD%%^^%%^^YELLOW%%^^%^RESET%^\n" + "%^BLUE%^BLUE\t%%^^BLUE%%^^\t%^BOLD%^%%^^BOLD%%^^%%^^BLUE%%^^%^RESET%^\n" + "%^CYAN%^CYAN\t%%^^CYAN%%^^\t%^BOLD%^%%^^BOLD%%^^%%^^CYAN%%^^%^RESET%^\n" + "%^MAGENTA%^MAGENTA\t%%^^MAGENTA%%^^\t%^BOLD%^%%^^BOLD%%^^%%^^MAGENTA%%^^%^RESET%^\n" + "%^BLACK%^BLACK\t%%^^BLACK%%^^\t%^BOLD%^%%^^BOLD%%^^%%^^BLACK%%^^%^RESET%^\n" + "%^WHITE%^WHITE\t%%^^WHITE%%^^\t%^BOLD%^%%^^BOLD%%^^%%^^WHITE%%^^%^RESET%^\n" + "%^BLACK%^B_RED%^B_RED\t\t\t%%^^B_RED%%^^%^RESET%^\n" + "%^BLACK%^%^B_GREEN%^B_GREEN\t\t\t%%^^B_GREEN%%^^%^RESET%^\n" + "%^BLACK%^%^B_ORANGE%^B_ORANGE\t\t%%^^B_ORANGE%%^^%^RESET%^\n" + "%^BLACK%^%^B_YELLOW%^B_YELLOW\t\t%%^^B_YELLOW%%^^%^RESET%^\n" + "%^BLACK%^%^B_BLUE%^B_BLUE\t\t\t%%^^B_BLUE%%^^%^RESET%^\n" + "%^BLACK%^%^B_CYAN%^B_CYAN\t\t\t%%^^B_CYAN%%^^%^RESET%^\n" + "%^BLACK%^%^B_MAGENTA%^B_MAGENTA\t\t%%^^B_MAGENTA%%^^%^RESET%^\n" + "%^BOLD%^%^BLACK%^%^B_BLACK%^B_BLACK\t\t\t%%^^B_BLACK%%^^%^RESET%^\n" + "%^BLACK%^%^B_WHITE%^B_WHITE\t\t\t%%^^B_WHITE%%^^%^RESET%^\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."); +} diff --git a/lib/cmds/players/commandecho.c b/lib/cmds/players/commandecho.c new file mode 100644 index 0000000..47b7aea --- /dev/null +++ b/lib/cmds/players/commandecho.c @@ -0,0 +1,31 @@ +#include + +inherit LIB_DAEMON; + +mixed cmd(string str) { + string *clrs = ({ "red", "green", "yellow", "blue", + "cyan", "magenta", "black", "white" }); + if( !sizeof(str) ) + return "Syntax: commandecho "; + str = lower_case(str); + + if( str != "on" && str != "off" && member_array(str, clrs) == -1 ) + return "Try: help commandecho"; + this_player()->SetProperty("commandecho", ( str == "off" ? 0 : str )); + message("system", + "Your commandecho is "+str+".", + this_player() ); + return 1; +} + +string GetHelp() { + return ("Syntax: commandecho \n\n" + "Enables or disables the display of your last command " + "line after you type it. This is useful only " + "if you have reprompt and/or charmode enabled. " + "You can specify a color, using any of the " + "following: red, green, yellow, blue, cyan, magenta, black, " + "white. For example:\ncommandecho blue\n" + "See also: reprompt, charmode"); +} + diff --git a/lib/cmds/players/consider.c b/lib/cmds/players/consider.c new file mode 100644 index 0000000..92a76ab --- /dev/null +++ b/lib/cmds/players/consider.c @@ -0,0 +1,122 @@ +#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; +} + +string GetHelp() { + return ("Syntax: consider \n\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."); +} diff --git a/lib/cmds/players/converse.c b/lib/cmds/players/converse.c new file mode 100644 index 0000000..b46e180 --- /dev/null +++ b/lib/cmds/players/converse.c @@ -0,0 +1,44 @@ +/* /cmds/player/converse.c + * from the Dead Souls LPC Library + * allows a person to talk without having to use the say command + * created by Descartes of Borg 950419 + */ + +#include +#include +#include + +inherit LIB_DAEMON; + +static void eventChat(string args); + +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; +} + +static void eventChat(string args) { + if( trim(args) == "." ) { + message("system", "Exiting conversation mode.", this_player()); + return; + } + else this_player()->eventSpeak(0, TALK_LOCAL, args); + input_to( (: eventChat :) ); +} + +string GetHelp() { + return ("Syntax: converse\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" + "See also: say, tell"); +} diff --git a/lib/cmds/players/cursefilter.c b/lib/cmds/players/cursefilter.c new file mode 100644 index 0000000..ad9cab2 --- /dev/null +++ b/lib/cmds/players/cursefilter.c @@ -0,0 +1,29 @@ +#include + +inherit LIB_DAEMON; + +mixed cmd(string str) { + int status; + if(!sizeof(str)) return "Try: help cursefilter"; + status = this_player()->GetParanoia("cursefilter"); + if(str == "on" && status) return "It's already on!"; + if(str == "off" && !status) return "It's already off!"; + if(str == "on"){ + this_player()->SetParanoia("cursefilter", 1); + write("Curse filter enabled."); + return 1; + } + if(str == "off"){ + this_player()->SetParanoia("cursefilter", 0); + write("Curse filter disabled."); + return 1; + } + return "Type: help cursefilter"; +} + +string GetHelp() { + return ("Syntax: cursefilter [ on | off ]\n\n" + "If enabled, tries to shield you from some common " + "discourteous words.\n" + "See also: env"); +} diff --git a/lib/cmds/players/customize.c b/lib/cmds/players/customize.c new file mode 100644 index 0000000..062a40f --- /dev/null +++ b/lib/cmds/players/customize.c @@ -0,0 +1,47 @@ +/* /cmds/players/customize.c + * from the Dead Souls Mud Library + * customize + * customize STAT AMOUNT + * created by Descartes of Borg 950113 + */ + +#include +#include + +inherit LIB_DAEMON; + +mixed cmd(string args) { + mixed tmp; + string stat; + int amt; + + if( !args || args == "" ) { + amt = 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]); + if( sizeof(tmp) == 1 ) return "Customize which stat how much?"; + stat = implode(tmp[0..<2], " "); + tmp = this_player()->eventCustomizeStat(stat, amt); + if( stringp(tmp) ) return tmp; + if( !tmp ) return "Failed to raise stat."; + this_player()->eventPrint("Your " + stat + " is now at " + tmp + + ", and you have " + + this_player()->GetCustomStats() + + " points left to spend.", MSG_SYSTEM); + return 1; +} + +string GetHelp(){ + return ("Syntax: customize [STAT AMOUNT]\n\n" + "Allows you to spend customization points to boost the " + "stats with which you were born. " + "Using this command without arguments tells you how many " + "points you have left to spend.\n" + "Example: customize strength 5" + "\nNOTE: Once spent, that's it. You will not receive " + "more customization points.\n" + "See also: stats, stat, skills, deviation"); +} diff --git a/lib/cmds/players/date.c b/lib/cmds/players/date.c new file mode 100644 index 0000000..3b24b99 --- /dev/null +++ b/lib/cmds/players/date.c @@ -0,0 +1,43 @@ +/* /cmds/player/date.c + * A simple command which displays current date and time + * Blitz@NM-IVD + */ + +#include +#include +#include + +mixed cmd(string timezone) { + string *parts, year, time, tz; + int offset, x, hour, min, sec; + + if(!timezone || !valid_timezone(timezone)){ + timezone = this_player()->GetProperty("timezone"); + } + if(!timezone || !valid_timezone(timezone)) timezone = local_time()[9]; + + offset = TIME_D->GetOffset(timezone); + 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); + message("info", + sprintf("Time: %d:%s%d %s\nDate: %s, %s", + (hour>12 ? (hour-12) : (hour == 0 ? 12 : hour)), + (min < 10 ? "0" : ""), + min, + ((hour>11 && hour) ? "pm" : "am"), + implode(parts[0..(x-3)], " "), + year), + this_player() ); + return 1; +} + +string GetHelp() { + return ("Syntax: date\n\n" + "Displays current time and date in local time."); +} diff --git a/lib/cmds/players/deviate.c b/lib/cmds/players/deviate.c new file mode 100644 index 0000000..36f6115 --- /dev/null +++ b/lib/cmds/players/deviate.c @@ -0,0 +1,60 @@ +#include +#include + +inherit LIB_DAEMON; + +mixed cmd(string args) { + mixed tmp; + string stat; + int amt; + + if( !args || args == "" ) { + amt = this_player()->GetCustomDeviations(); + this_player()->eventPrint("You have " + amt + + " deviation points left to use.", MSG_SYSTEM); + return 1; + } + if(args == "enable"){ + int i = this_player()->GetDeviating(); + if(i){ + write("You already have enabled deviation for yourself."); + return 1; + } + i = this_player()->SetDeviating(1); + if(i) write("Deviation enabled."); + else write("Deviation not enabled. See an admin for help."); + return 1; + } + if(!this_player()->GetDeviating()){ + write("You have not enabled deviation for yourself."); + write("Please type: help deviate"); + write("And: help deviation"); + return 1; + } + amt = to_int((tmp = explode(args, " "))[<1]); + if( sizeof(tmp) == 1 ) return "Deviate which stat how much?"; + stat = implode(tmp[0..<2], " "); + tmp = this_player()->eventDeviateStat(stat, amt); + if( stringp(tmp) ) return tmp; + if( !tmp ) return "Failed to deviate."; + this_player()->eventPrint("Your " + stat + " class is now " + tmp + + ", and you have " + + this_player()->GetCustomDeviations() + + " deviation points left.", MSG_SYSTEM); + return 1; +} + +string GetHelp(){ + return ("Syntax: deviate\n" + " deviate enable\n" + " deviate STAT AMOUNT\n\n" + "Changes your \"stat class\" for the specified stat, " + "meaning that it improves more frequently when your " + "player level goes up. However it incurs great cost to " + "you in terms of an XP penalty. You cannot reverse a " + "deviation nor its penalty. Before proceeding, read the " + "helpfile for deviation:\nhelp deviation\n\n" + "If you decide to deviate, first enable it by typing:\n" + "deviate enable\nSee also: deviation, customize, " + "stat, stats, score"); +} diff --git a/lib/cmds/players/dispel.c b/lib/cmds/players/dispel.c new file mode 100644 index 0000000..acb5f4f --- /dev/null +++ b/lib/cmds/players/dispel.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include + +inherit LIB_DAEMON; + + +mixed cmd(string args) { + + if(!args){ + write("Dispel what?"); + return 1; + } + if(args == "meditate"){ + object mojo = present("meditate mojo", this_player()); + if(!mojo){ + write("You have no meditation mojo to dispel."); + return 1; + } + write("You dispel the meditation mojo from yourself."); + mojo->eventDispel(); + } + if(args == "whip"){ + object whip = present_file("/obj/whip", this_player()); + if(!whip){ + write("You have no whip to dispel."); + return 1; + } + write("You dispel the whip from yourself."); + whip->eventDispel(); + } + if(args == "buffer"){ + class MagicProtection *Protections; + Protections = this_player()->GetMagicProtection(); + foreach(class MagicProtection tmp in Protections){ + if(!tmp->obname) continue; + if(tmp->obname == "/powers/spells/buffer"){ + if(!(functionp(tmp->hit) & FP_OWNER_DESTED)){ + write("You dispel your buffer."); + this_player()->RemoveMagicProtection("/powers/spells/buffer"); + return 1; + } + } + } + write("You have no buffer to dispel."); + return 1; + } + if(args == "greater buffer"){ + class MagicProtection *Protections; + Protections = this_player()->GetMagicProtection(); + foreach(class MagicProtection tmp in Protections){ + if(!tmp->obname) continue; + if(tmp->obname == "/powers/spells/greater_buffer"){ + if(!(functionp(tmp->hit) & FP_OWNER_DESTED)){ + write("You dispel your greater buffer."); + this_player()->RemoveMagicProtection("/powers/spells/greater_buffer"); + return 1; + } + } + } + write("You have no greater buffer to dispel."); + return 1; + } + return 1; +} + + +string GetHelp(){ + return ("Syntax: dispel \n\n" + "Dismisses a given magical effect, if appropriate.\n" + "\nSee also: cast"); +} diff --git a/lib/cmds/players/earmuff.c b/lib/cmds/players/earmuff.c new file mode 100644 index 0000000..58f3ff9 --- /dev/null +++ b/lib/cmds/players/earmuff.c @@ -0,0 +1,28 @@ +#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; +} + +string GetHelp() { + return ("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"); +} + diff --git a/lib/cmds/players/emote.c b/lib/cmds/players/emote.c new file mode 100644 index 0000000..46bdadb --- /dev/null +++ b/lib/cmds/players/emote.c @@ -0,0 +1,38 @@ +/* /cmds/player/emote.c + * from the Dead Souls LPC Library + * for those times when you are feeling emotional + * created by Descartes of Borg 950412 + */ + +#include + +inherit LIB_DAEMON; + +mixed cmd(string args) { + if( !creatorp(this_player()) && !avatarp(this_player()) ) { + if( this_player()->GetStaminaPoints() < 1 ) + return "You are too tired."; + } + if( !args || args == "" ) { + message("my_action", "You are feeling emotional.", this_player()); + message("other_action", this_player()->GetName() + + " looks emotional.", environment(this_player()), + ({ this_player() })); + return 1; + } + if( args[0] != '\'' ) args = " " + args; + message("my_action", "You emote: " + this_player()->GetName() + + args, this_player()); + message("other_action", this_player()->GetName() + args, + environment(this_player()), ({ this_player() }) ); + return 1; +} + +string GetHelp() { + return ("Syntax: emote \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."); +} + diff --git a/lib/cmds/players/enemies.c b/lib/cmds/players/enemies.c new file mode 100644 index 0000000..a5cdd11 --- /dev/null +++ b/lib/cmds/players/enemies.c @@ -0,0 +1,35 @@ +#include + +inherit LIB_DAEMON; +string *foenames = ({}); + +mixed cmd(string str) { + object *foes = ({}); + object ob; + string ret; + foenames = ({}); + if(sizeof(str) && !creatorp(this_player())){ + if(find_player(lower_case(str)) != this_player()) + return "You can only know about your own enemies."; + } + if(!str) str = this_player()->GetKeyName(); + ob = find_player(lower_case(str)); + if(!ob) return "No such player found."; + foes = ob->GetEnemies(); + if(!sizeof(foes)){ + ret = "No creatures bear ill will toward "+capitalize(str)+"."; + } + else { + ret = "The following creatures bear ill will toward "+ + capitalize(str)+": "; + filter(foes, (: foenames += ({$1->GetShort()}) :) ); + ret += implode(foenames, ", ")+"."; + } + return ret; +} + +string GetHelp() { + return ("Syntax: enemies\n\n" + "This command reports with whom you're not getting along."); +} + diff --git a/lib/cmds/players/env.c b/lib/cmds/players/env.c new file mode 100644 index 0000000..b703dc4 --- /dev/null +++ b/lib/cmds/players/env.c @@ -0,0 +1,112 @@ +#include + +inherit LIB_DAEMON; + +string GetMuted(){ + string ret; + if(this_player()->GetMutedType("local")){ + ret = "local: %^RED%^MUTED%^RESET%^"; + } + else { + ret = "local: %^GREEN%^listening%^RESET%^"; + } + if(this_player()->GetMutedType("remote")){ + ret += ", remote: %^RED%^MUTED%^RESET%^"; + } + else { + ret += ", remote: %^GREEN%^listening%^RESET%^"; + } + return ret; +} + +string GetGagged(){ + string ret; + if(this_player()->GetGaggedType("local")){ + ret = "local: %^RED%^GAGGED%^RESET%^"; + } + else { + ret = "local: %^GREEN%^talking%^RESET%^"; + } + if(this_player()->GetGaggedType("remote")){ + ret += ", remote: %^RED%^GAGGED%^RESET%^"; + } + else { + ret += ", remote: %^GREEN%^talking%^RESET%^"; + } + return ret; +} + +mixed cmd(string args) { + object player = this_player(); + mixed replee = player->GetProperty("reply"); + string ret = ""; + string *tmp; + ret += "Screen: \t\t"+identify(this_player()->GetScreen())+"\n"; + ret += "Terminal: \t\t"+this_player()->GetTerminal()+"\n"; + ret += "Brief mode: \t\t"+ ( (this_player()->GetBriefMode()) ? "on" : "off" )+"\n"; + ret += "Cursefilter: \t\t"+ ( (this_player()->GetParanoia("cursefilter")) ? "on" : "off" )+"\n"; + ret += "Channel message colors: "+ ( (this_player()->GetNoChanColors()) ? "off" : "on" )+"\n"; + ret += "Playerkiller mode: \t"+ ( (this_player()->GetPK()) ? "on" : "off" )+"\n"; + ret += "Mute mode: \t\t"+ GetMuted()+" \n"; + ret += "Gag mode: \t\t"+ GetGagged()+" \n"; + ret += "Wimpy mode: \t\t"+ ( (this_player()->GetWimpy()) ? "on" : "off" )+"\n"; +#if efun_defined(compressedp) + ret += "MCCP mode: \t\t"+(compressedp(this_player()) ? "on" : "off")+"\n"; +#endif +#if MINIMAP + ret += "Minimap mode: \t\t"+ ( this_player()->GetProperty("minimapping") ? "on" : "off" )+"\n"; +#endif + ret += "Annoyblock: \t\t"+ ( (this_player()->GetAnnoyblock()) ? "on" : "off" )+"\n"; + ret += "Reprompt mode: \t\t"+ ( this_player()->GetProperty("reprompt") ? "on" : "off" )+"\n"; + ret += "Screenlock mode: \t"+ ( this_player()->GetProperty("screenlock") ? "on" : "off" )+"\n"; + ret += "Timezone: \t\t"+ ( this_player()->GetProperty("timezone") ? + this_player()->GetProperty("timezone") : "None specified" )+"\n"; +#ifdef __GET_CHAR_IS_BUFFERED__ + ret += "Charmode: \t\t"+ + //( (query_charmode(player) > 0) ? "on" : "off" )+"\n"; + ( (player->GetCharmode()) ? "on" : "off" )+"\n"; +#endif + ret += "Commandecho: \t\t"+ ( this_player()->GetProperty("commandecho") ? this_player()->GetProperty("commandecho") : "off" )+"\n"; +#ifdef __DSLIB__ + ret += "Keepalive mode: \t"+ ( this_player()->GetProperty("keepalive") + ? this_player()->GetProperty("keepalive") : "off" )+"\n"; +#endif + + if(creatorp(this_player())){ + ret += "Homedir: \t\t"+user_path(this_player())+"\n"; + if(this_player()->GetParanoia("homeroom")){ + ret += "Homeroom: \t\t"+this_player()->GetParanoia("homeroom")+"\n"; + } + ret += "Debug mode: \t\t"+ ( (this_player()->GetProperty("debug")) ? "on" : "off" )+"\n"; + ret += "Godmode: \t\t"+ ( (this_player()->GetGodMode()) ? "on" : "off" )+"\n"; + ret += "Wizvision: \t\t"+ ( (this_player()->GetWizVision()) ? "on" : "off" )+"\n"; +#if GRID + ret += "Showgrid: \t\t"+ ( (this_player()->GetVisibleGrid()) ? "on" : "off" )+"\n"; + ret += "Wizmap mode: \t\t"+ ( this_player()->GetProperty("wizmapping") ? "on" : "off" )+"\n"; + ret += "Noclip mode: \t\t"+ ( this_player()->GetProperty("noclip") ? "on" : "off" )+"\n"; + ret += "Anchor: \t\t"+ ( this_player()->GetAnchored() ? "on" : "off" )+"\n"; +#endif + } + if(replee){ + ret += "Reply target: \t\t"+replee+"\n"; + } + tmp = sort_array(explode(ret, "\n"),1); + ret = implode(tmp, "\n"); + write(ret); + return 1; +} + +string GetHelp() { + string *see_also = ({}); + if(creatorp(this_player())){ + see_also = ({ "debug" , "showgrid", + "wizvision", "godmode", "wizmap", "noclip" }); + } + see_also += ({ "brief", "chancolors", "commandecho", "cursefilter", + "terminal", "screen", "pk", "mute", "gag", "wimpy", "minimap", + "annoyblock", "reprompt", "charmode", "keepalive", "timezone", + "screenlock" }); + return ("Syntax: env\n\n" + "Displays some basic interface and play settings.\n" + + "See also: "+implode(sort_array(see_also, 1), ", ")); +} diff --git a/lib/cmds/players/equipment.c b/lib/cmds/players/equipment.c new file mode 100644 index 0000000..f3fcea4 --- /dev/null +++ b/lib/cmds/players/equipment.c @@ -0,0 +1,56 @@ +#include +#include + +inherit LIB_DAEMON; + +void eventInventory(); + +mixed cmd(string args) { + if( this_player()->GetInCombat() ) + this_player()->SetAttack(0, (: eventInventory :), ROUND_OTHER); + else eventInventory(); + return 1; +} + +void eventInventory() { + object *weapons = filter(all_inventory(this_player()), (: $1->GetWielded() :) ); + string *bare_limbs = filter(this_player()->GetLimbs(), (: !sizeof(this_player()->GetWorn($1)) :) ); + object *armors = filter(all_inventory(this_player()), + (: $1->GetWorn() && !($1->GetWielded()) :) ); + string ret = "You are using: \n"; + + foreach(object weapon in weapons){ + string tmp = capitalize(weapon->GetShort()); + string *limbs = ({}); + foreach(string limb in weapon->GetWorn()){ + limbs += ({ "your "+limb }); + } + tmp += " wielded in "+item_list(limbs)+".\n"; + ret += tmp+"\n"; + } + + foreach(object armor in armors){ + string tmp = capitalize(armor->GetShort()); + string *limbs = ({}); + foreach(string limb in armor->GetWorn()){ + limbs += ({ "your "+limb }); + } + tmp += " worn on "+item_list(limbs)+".\n"; + ret += tmp; + } + + if(sizeof(bare_limbs)){ + ret +="\nYour following body parts are unequipped: \n"; + ret += capitalize(item_list(bare_limbs)+"."); + } + + write(ret); +} + +string GetHelp(){ + return ("Syntax: equipment\n\n" + "Lists all items you are currently wearing or wielding. " + "This command " + "will take up one round of combat if you happen to be in " + "combat."); +} diff --git a/lib/cmds/players/faq.c b/lib/cmds/players/faq.c new file mode 100644 index 0000000..ce42ab5 --- /dev/null +++ b/lib/cmds/players/faq.c @@ -0,0 +1,60 @@ +/* /cmds/player/faq.c + * from the Foundation II LPC Library + * a command to access Frequently Asked Questions lists easily + * created by Descartes of Borg 950501 (power to the proletariate) + */ + +#include + +inherit LIB_DAEMON; + +static void GetFAQ(string args); + +mixed cmd(string args) { + if( !args || args == "" ) { + string *files; + 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; + cols = cols / (x+2); + message("help", format_page(files, cols), this_player()); + message("prompt", "\nWhich FAQ (general)? ", this_player()); + input_to( (: GetFAQ :) ); + return 1; + } + else GetFAQ(args); + return 1; +} + +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; + } + if( !(file = read_file(file)) ) { + message("error", "Failed to read FAQ document.", this_player()); + return; + } + this_player()->eventPage(explode(file, "\n"), "help"); +} + +string GetHelp() { + return ("Syntax: faq [FAQ]\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" + "See also: help" + (creatorp(this_player()) ? ", man" : "")); +} + + diff --git a/lib/cmds/players/flee.c b/lib/cmds/players/flee.c new file mode 100644 index 0000000..d6e2066 --- /dev/null +++ b/lib/cmds/players/flee.c @@ -0,0 +1,18 @@ +#include + +inherit LIB_DAEMON; + +mixed cmd(string str) { + if(!(this_player()->GetInCombat())){ + write("You are not in combat."); + return 1; + } + this_player()->eventWimpy("go out"); + return 1; +} + +string GetHelp() { + return ("Syntax: flee\n\n" + "If you need to leave combat in a hurry, and don't care which way you go.\n" + "This command doesn't work for creators."); +} diff --git a/lib/cmds/players/gag.c b/lib/cmds/players/gag.c new file mode 100644 index 0000000..55d224e --- /dev/null +++ b/lib/cmds/players/gag.c @@ -0,0 +1,67 @@ +#include + +inherit LIB_DAEMON; + +string ReportSyntax(){ + int admin = adminp(this_player()); + string ret = "Syntax: gag [remote or local] "; + if(admin) ret += " gag [on or off]"; + return ret; +} + +mixed cmd(string str) { + string which, type; + object player; + string *validtypes = ({ "remote", "local", "all" }); + int admin = adminp(this_player()); + if( !sizeof(str) ) + return ReportSyntax(); + str = lower_case(str); + sscanf(str,"%s %s", type, which); + if(!which && type){ + which = type; + type = "all"; + } + if(!type){ + if(admin){ + player = find_player(str); + } + if(!player) which = str; + else which = "on"; + type = "all"; + } + if(admin){ + if(!player) player = find_player(type); + if(player){ + if(!which) which = "on"; + type = "all"; + } + } + if( which != "on" && which != "off" ) + return "You can only turn gag 'on' or 'off'."; + if( !player && member_array(type, validtypes) == -1 ) + return "Valid gag types are: remote, local, all."; + if(!player) player = this_player(); + if(admin){ + player->SetGagged(type, (which == "on" ? 2 : 0)); + } + else { + player->SetGagged(type, (which == "on")); + } + message("system", + "Gag mode turned "+str+" for "+type+" channels"+ + (player != this_player() ? " for "+player->GetName() : "")+ + ".", this_player() ); + return 1; +} + +string GetHelp() { + int admin = adminp(this_player()); + return "Syntax: gag [remote | local] \n"+ + (admin ? " gag \n" : "")+ + "\nThis command prevents you from talking on channels.\n" + "Good for when you're hiding or using multiple chars.\n" + "You can gag yourself on all channels with: gag on\n" + "You can gag yourself only on intermud channels with: gag remote on\n" + "See also: mute, env"; +} diff --git a/lib/cmds/players/i3locate.c b/lib/cmds/players/i3locate.c new file mode 100644 index 0000000..29cd6da --- /dev/null +++ b/lib/cmds/players/i3locate.c @@ -0,0 +1,27 @@ +/* /cmds/players/i3locate.c + * from the Dead Souls LPC Library + * Intermud 3 command to locate people on other MUDs + * created by Descartes of Borg 950624 + */ + +#include +#include + +inherit LIB_DAEMON; + +mixed cmd(string args) { + if( !args || args == "" ) return "i3locate whom?"; + SERVICES_D->eventSendLocateRequest(convert_name(args)); + message("system", "i3locate query sent.", this_player()); + return 1; +} + +string GetHelp() { + return ("Syntax: i3locate [person]\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" + "See also: mail, mudlist, rwho, tell"); +} diff --git a/lib/cmds/players/idle.c b/lib/cmds/players/idle.c new file mode 100644 index 0000000..b556a97 --- /dev/null +++ b/lib/cmds/players/idle.c @@ -0,0 +1,34 @@ +/* /cmds/players/idle + * 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 1; + args = convert_name(args); + who = find_player(args); + if( !who || who->GetInvis() ) + return "Unable to locate anyone by that name."; + if( !interactive(who) ) + return who->GetName() + " is link dead."; + x = query_idle(who); + if( x > 4 ) { + this_player()->eventPrint(who->GetName()+" has been idle for "+time_elapsed(x)+"."); + } + else this_player()->eventPrint(who->GetName() + " is " + "not idle."); + return 1; +} + +string GetHelp(string str) { + return "Syntax: idle [user]\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.\nIf no argument is provided, the command simply " + "does nothing. This allows you to send a command to the mud " + "to keep your connection alive without generating activity.\n" + "See also: keepalive, env"; +} diff --git a/lib/cmds/players/inventory.c b/lib/cmds/players/inventory.c new file mode 100644 index 0000000..89d8a49 --- /dev/null +++ b/lib/cmds/players/inventory.c @@ -0,0 +1,69 @@ +/* /lib/inventory.c + * from the Dead Souls LPC Library + * gives a person information about their inventory + * created by Descartes of Borg 950412 + */ + +#include +#include +#include + +inherit LIB_DAEMON; + +void eventInventory(); + +mixed cmd(string args) { + if( this_player()->GetInCombat() ) + this_player()->SetAttack(0, (: eventInventory :), ROUND_OTHER); + else eventInventory(); + return 1; +} + +void eventInventory() { + mapping borg; + string *items, *wieldeds, *worns, *shorts; + string ret; + int i; + + items = map(filter(all_inventory(this_player()), + (: !($1->GetInvis(this_player())) && + !($1->GetWorn()) :)), + (: $1->GetEquippedShort() :)); + wieldeds = map(filter(all_inventory(this_player()), + (: !($1->GetInvis(this_player())) && + ($1->GetWielded()) :)), + (: $1->GetEquippedShort() :)); + worns = map(filter(all_inventory(this_player()), + (: !($1->GetInvis(this_player())) && + !($1->GetWielded()) && $1->GetWorn() :)), + (: $1->GetEquippedShort() :)); + shorts = items + wieldeds + worns; + if( !(i = sizeof(shorts)) ) { + message("system", "You are carrying nothing.", this_player()); + return; + } + if( i == 1 ) ret = "You are carrying just this one item:\n"; + else ret = "You are carrying the following items:\n"; + foreach(shorts in ({ items, wieldeds, worns })){ + i = sizeof(shorts); + if(!i) continue; + borg = ([]); + while(i--) if( shorts[i] ) borg[shorts[i]]++; + 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() && + !environment(this_player())->GetProperty("meeting room")) + message(MSG_ANNOYING, this_player()->GetName() + " checks " + + possessive(this_player()) + " possessions.", + environment(this_player()), ({ this_player() })); +} + +string GetHelp() { + return ("Syntax: inventory\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."); +} diff --git a/lib/cmds/players/keepalive.c b/lib/cmds/players/keepalive.c new file mode 100644 index 0000000..1501ea3 --- /dev/null +++ b/lib/cmds/players/keepalive.c @@ -0,0 +1,54 @@ +#include + +inherit LIB_DAEMON; +string err = "This game appears not to have this feature enabled "+ +"in the driver. Consider asking your mud administrator "+ +"to recompile with PACKAGE_DSLIB defined."; + + +mixed cmd(string args) { + mixed keepalive = this_player()->GetProperty("keepalive"); + if(!intp(keepalive)) keepalive = 0; + +#ifndef __DSLIB__ + write(err); + return 1; +#endif + + if( !args || args == "" ) { + if(!keepalive){ + write("You have keepalives disabled."); + return 1; + } + else { + write("Keepalive set to once every "+cardinal(keepalive)+ + " heartbeat"+(keepalive > 1 ? "s." : ".")); + return 1; + } + } + if(!intp(keepalive = to_int(args)) || !keepalive) { + this_player()->SetProperty("keepalive",0); + write("Keepalive disabled."); + return 1; + } + else { + this_player()->SetProperty("keepalive",keepalive); + write("Keepalive set to once every "+cardinal(keepalive)+ + " heartbeat"+(keepalive > 1 ? "s." : ".")); + return 1; + } +} + +string GetHelp(){ + return ("Syntax: keepalive [NUMBER]\n\n" + "Without an argument, keepalive will display your current " + "keepalive interval. When provided an integer argument, this " + "command sets how often an invisible 'keepalive' signal is " + "sent to your client. This is useful for people with an " + "ISP or modem that kills connections that have been idle " + "for a while." +#ifndef __DSLIB__ + "\n---NOTE---\n"+err+"\n---\n" +#endif + "\nSee also: env"); +} diff --git a/lib/cmds/players/kills.c b/lib/cmds/players/kills.c new file mode 100644 index 0000000..bf4b48d --- /dev/null +++ b/lib/cmds/players/kills.c @@ -0,0 +1,44 @@ +#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 " +this_player()->GetShort() + ", level " + + this_player()->GetLevel(); + if( (tmp = this_player()->GetClass()) ) + ret += " " + capitalize(tmp); + else ret += " Drifter"; + ret += " (" + 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; +} + +string GetHelp() { + return ("Syntax: kills\n\n" + "A list of your victories."); +} diff --git a/lib/cmds/players/languages.c b/lib/cmds/players/languages.c new file mode 100644 index 0000000..136bf83 --- /dev/null +++ b/lib/cmds/players/languages.c @@ -0,0 +1,45 @@ +#include +#include + +inherit LIB_DAEMON; + +mixed cmd(string str) { + mapping FluencyMap = ([]); + string *langs = this_player()->GetLanguages(); + + if(str){ + mixed ret = this_player()->CanSpeak(0, TALK_LOCAL, "foo", str); + if(intp(ret)) { + this_player()->SetDefaultLanguage(str); + write("You are now speaking in "+capitalize(lower_case(str))+"."); + return 1; + } + else return ret; + } + + 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."); + } + write("Your current default language is: "+ + this_player()->GetDefaultLanguage()+"."); + + return 1; +} + +string GetHelp() { + return ("Syntax: language [LANGUAGE]\n\n" + "This command reports which languages you speak and understand.\n" + "If a language is specified and you know the language, it is " + "set as your default speaking language.\n" + "See also: languages, speak"); +} + diff --git a/lib/cmds/players/mem.c b/lib/cmds/players/mem.c new file mode 100644 index 0000000..c7e9d11 --- /dev/null +++ b/lib/cmds/players/mem.c @@ -0,0 +1,21 @@ +#include + +inherit LIB_DAEMON; + +mixed cmd(string args) { + int i, lines = 2 * this_player()->GetScreen()[1]; + write("lines: "+lines); + for(i=lines;i>0;i--){ + write("Loading memtest...\n"); + } + this_player()->eventPage(explode(mud_status(1), "\n")); + return 1; + +} + +string GetHelp() { + return ("Syntax: mem\n\n" + "This command makes it look like you're doing something " + "important and technical that has to do with memory, but really " + "it's just wiping your screen of game text."); +} diff --git a/lib/cmds/players/minimap.c b/lib/cmds/players/minimap.c new file mode 100644 index 0000000..5b782d0 --- /dev/null +++ b/lib/cmds/players/minimap.c @@ -0,0 +1,41 @@ +#include + +inherit LIB_DAEMON; + +mixed cmd(string args) { +#if MINIMAP + int status = this_player()->GetProperty("minimapping"); + string sstatus = "are"; + if(!status) sstatus = "are not"; + if(!args){ + write("You "+sstatus+" minimapping."); + return 1; + } + if(args == "on"){ + if(status) write("You are already minimapping."); + else write("You enable minimapping."); + this_player()->SetProperty("minimapping", 1); + return 1; + } + + if(args == "off"){ + if(!status) write("You are already not minimapping."); + else write("You disable minimapping."); + this_player()->SetProperty("minimapping", 0); + return 1; + } + + write("Try: help minimap"); + return 1; +#else + write("This feature is disabled."); + return 1; +#endif +} + +string GetHelp() { + return ("Syntax: minimap [on | off]\n\n" + "If enabled, a simple map of your surroundings is displayed " + "when your environment is described to you.\nSee also: " + "env, terminal, brief, mute, gag."); +} diff --git a/lib/cmds/players/money.c b/lib/cmds/players/money.c new file mode 100644 index 0000000..e75b02a --- /dev/null +++ b/lib/cmds/players/money.c @@ -0,0 +1,43 @@ +// /bin/user/_money.c +// from the Dead Souls mudlib +// a comand to allow players to search their pockets +// created by Descartes of Borg 25 april 1993 + + +#include + +inherit LIB_DAEMON; + +mixed cmd(string str) { + string *currs; + string borg; + int i, tmp; + + if(str) return 0; /* to allow the wiz command to work */ + currs = 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; +} + +string GetHelp() { + return ("Syntax: money\n\n" + "Allows you to search your pockets for all your money " + "of all currency types."); +} diff --git a/lib/cmds/players/mudinfo.c b/lib/cmds/players/mudinfo.c new file mode 100644 index 0000000..89d856c --- /dev/null +++ b/lib/cmds/players/mudinfo.c @@ -0,0 +1,16 @@ +#include +#include + +inherit LIB_DAEMON; + +mixed cmd(string str) { + if( !sizeof(str) ) + return "Syntax: mudinfo "; + return MUDINFO_D->PrintMudInfo(str); +} + +string GetHelp() { + return ("Syntax: mudinfo \n\n" + "If available, this command presents detailed Intermud-3 " + "information on the mud specified."); +} diff --git a/lib/cmds/players/mudlist.c b/lib/cmds/players/mudlist.c new file mode 100644 index 0000000..d85b508 --- /dev/null +++ b/lib/cmds/players/mudlist.c @@ -0,0 +1,144 @@ +/* /cmds/player/mudlist.c + * from the Dead Souls LPC Library + * gives information about muds + * created by Descartes of Borg 950623 + */ + +#include +#include + +inherit LIB_DAEMON; + +mixed cmd(string str) { + mixed *info; + string *list; + mapping borg; + string mud, tempy; + int all = 0; + + if(sizeof(str) && sizeof(tempy = INTERMUD_D->GetMudName(str) )) str = tempy; + + //imc2 mudlist + if(sizeof(str) && str[0..3] == "imc2") { + IMC2_D->mudlist(this_player()); + return 1; + } + + if( str && str != "" ) { + mapping tmp; + string opt, tmpstr; + + tmp = INTERMUD_D->GetMudList(); + if( str[0] != '-' ) str = "-n " + str; + opt = str[1..1]; + str = str[3..]; + borg = ([]); + foreach(mud, info in tmp) { + 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); + y = strlen(tmpstr); + + + if( lower_case(str) == lower_case(tmpstr) ) { + borg = ([ mud : info ]); + break; + } + + else if( y > z && + lower_case(tmpstr[0..z-1]) == lower_case(str) && info[0] == -1 ) + borg[mud] = info; + } + } + else { + borg = ([ ]); + foreach( mud, info in INTERMUD_D->GetMudList() ) + if( all == 1 || info[0] == -1 ) borg[mud] = info; + } + if( !sizeof(borg) ) { + if(this_player()) message("system", "No MUDs match your query.", this_player()); + return 1; + } + else if( sizeof(borg) == 1 ) { + string msg, svc; + int val, comma = 0; + + 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 ) { + if( comma ) msg += ", " + svc; + else { + msg += svc; + comma = 1; + } + } + } + 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"; + if(this_player()) 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; + if(this_player()) this_player()->eventPage(list); + if(this_player()) return 1; + else return implode(list,"\n"); +} + +int alphabet(string a, string b) { + if((a = lower_case(a)) == (b = lower_case(b))) return 0; + else if(a > b) return 1; + else return -1; +} + +string GetHelp() { + return ("Syntax: mudlist [-d] [-m] [-n] [arg]\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" + "See also: finger, mail, rwho, tell"); +} diff --git a/lib/cmds/players/mute.c b/lib/cmds/players/mute.c new file mode 100644 index 0000000..fb31c93 --- /dev/null +++ b/lib/cmds/players/mute.c @@ -0,0 +1,32 @@ +#include + +inherit LIB_DAEMON; + +mixed cmd(string str) { + string which, type; + string *validtypes = ({ "remote", "local", "all" }); + if( !sizeof(str) ) + return "Syntax: mute [remote or local]"; + str = lower_case(str); + sscanf(str,"%s %s",which, type); + if(!type) type = "all"; + else str = which; + if( str != "on" && str != "off" ) + return "You can only turn mute 'on' or 'off'."; + if( member_array(type, validtypes) == -1 ) + return "Valid mute types are: remote, local, all."; + this_player()->SetMuted(type, (str == "on")); + message("system", + "Mute mode turned "+str+" for "+type+" channels.", + this_player() ); + return 1; +} + +string GetHelp() { + return ("Syntax: mute on [ remote | local ]\n" + " mute off [ remote | local ]\n\n" + "This command allows you to avoid or listen to channel messages.\n" + "You can mute all channels with: mute on\n" + "You can mute only intermud channels with: mute remote on\n" + "See also: gag, env"); +} diff --git a/lib/cmds/players/new.c b/lib/cmds/players/new.c new file mode 100644 index 0000000..052548c --- /dev/null +++ b/lib/cmds/players/new.c @@ -0,0 +1,19 @@ +#include +#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(); +} + +string GetHelp() { + eventNoob(); +} + diff --git a/lib/cmds/players/nextreboot.c b/lib/cmds/players/nextreboot.c new file mode 100644 index 0000000..4e52a21 --- /dev/null +++ b/lib/cmds/players/nextreboot.c @@ -0,0 +1,42 @@ +/* /cmd * from the Dead Souls Mudlib + * Shows when the next reboot occurs + * created by Descartes of Borg 940130 + */ + +#include +#include + +inherit LIB_DAEMON; + +mixed cmd(string form) { + string str, tz; + int x, offset; + + if(DISABLE_REBOOTS){ + write("Recurring reboots are disabled."); + write("There is no reboot scheduled by the events daemon."); + return 1; + } + tz = this_player()->GetProperty("timezone"); + if(!tz || !valid_timezone(tz)) tz = query_tz(); + + offset = TIME_D->GetOffset(tz); + offset += EXTRA_TIME_OFFSET; + + x = EVENTS_D->GetRebootInterval() * 3600; + x = (time() - uptime()) + x; + if(query_os_type() != "windows" ) + x += offset * 3600; + str = tz+ " " + ctime(x); + message("system", "Current "+tz+" system time is "+timestamp(tz), + 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(){ + return ("Syntax: nextreboot\n\n" + "Tells you when the next regularly scheduled reboot for " + + mud_name() + " will occur."); +} diff --git a/lib/cmds/players/pk.c b/lib/cmds/players/pk.c new file mode 100644 index 0000000..f52f0a7 --- /dev/null +++ b/lib/cmds/players/pk.c @@ -0,0 +1,50 @@ +#include + +inherit LIB_DAEMON; + +mixed cmd(string args) { + if(!sizeof(args) || (args != "on" && args != "off") ){ + write("Syntax: pk [ on | off ]"); + return 1; + } + if(args == "off"){ + if(creatorp(this_player())){ + if(!(this_player()->GetPK())) write("Your PK flag is already off."); + else write("Your PK flag is now off."); + this_player()->SetPK(0); + return 1; + } + else { + write("You must ask a creator to disable your PK flag."); + return 1; + } + } + if((this_player()->GetPK())){ + write("You are already a player killer."); + return 1; + } + if(this_player()->GetProperty("PK warned")){ + this_player()->SetProperty("PK warned",0); + write("You are now a player killer."); + this_player()->SetPK(1); + return 1; + } + else { + write("If you enable your PK flag, only a creator can disable it."); + write("If you're 100% sure you want to PK, then issue the command again."); + this_player()->SetProperty("PK warned",1); + return 1; + } +} + +string GetHelp() { + return ("Syntax: pk [ on | off ]\n\n" + "\tUnless you are set as a player killer, you cannot engage " + + "in player versus player combat. This command toggles your " + + "player killer setting. Once they are set as PK, players cannot "+ + "unset it without the intervention of a creator.\n" + "\tPlayer killing also requires the mud to have its global PK "+ + "setting enabled in its config file, and the room you are in "+ + "must be PK enabled as well.\n" + "See also: env"); +} diff --git a/lib/cmds/players/plugh.c b/lib/cmds/players/plugh.c new file mode 100644 index 0000000..89b8612 --- /dev/null +++ b/lib/cmds/players/plugh.c @@ -0,0 +1,9 @@ +#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 --git a/lib/cmds/players/position.c b/lib/cmds/players/position.c new file mode 100644 index 0000000..0df2ac5 --- /dev/null +++ b/lib/cmds/players/position.c @@ -0,0 +1,45 @@ +#include +#include + +inherit LIB_DAEMON; + +mixed cmd(string str) { + int pos; + object ob; + string ret; + + if(str) ob = get_object(str); + if(!ob || !living(ob)){ + if(str){ + write("No such living thing found."); + return 1; + } + ob = this_player(); + ret = "You are "; + } + else { + ret = ob->GetShort()+" is "; + } + + pos = ob->GetPosition(); + + switch(pos){ + case POSITION_STANDING : ret += "standing.";break; + case POSITION_SITTING : ret += "sitting.";break; + case POSITION_LYING : ret += "prone.";break; + case POSITION_FLYING : ret += "flying.";break; + case POSITION_KNEELING : ret += "kneeling.";break; + case POSITION_FLOATING : ret += "floating.";break; + case POSITION_SWIMMING : ret += "swimming.";break; + default : ret += "here."; + } + + write(ret); + return 1; +} + +string GetHelp() { + return ("Syntax: position [living thing]\n\n" + "Reports the posture of the person named, or if no argument is " + "provided, your own physical posture."); +} diff --git a/lib/cmds/players/posting.c b/lib/cmds/players/posting.c new file mode 100644 index 0000000..ddf227d --- /dev/null +++ b/lib/cmds/players/posting.c @@ -0,0 +1,29 @@ +// 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( list[i]->GetName(), 20)); + else if(in_edit(list[i]) || in_input(list[i])) + printf("%s - Editing.\n", + arrange_string( list[i]->GetName(), 20)); + return 1; +} + +string GetHelp() { + return "Syntax: posting\n\n" + "Displays whether a user is in editor, posting on a " + "bulletin board, or in the mailer."; +} diff --git a/lib/cmds/players/prompt.c b/lib/cmds/players/prompt.c new file mode 100644 index 0000000..e5771d8 --- /dev/null +++ b/lib/cmds/players/prompt.c @@ -0,0 +1,45 @@ +#include + +inherit LIB_DAEMON; + +mixed cmd(string str) { + if(!sizeof(str)){ + write(this_player()->GetPromptString()); + return 1; + } + this_player()->SetPrompt(str); + this_player()->reset_prompt(); + return 1; +} + +string GetHelp() { + string cre = "$P shows current working directory\n"+ + "To have your creator character's name "+ + "and current dir show up:\nprompt $N $P >\nIn yellow:\n"+ + "prompt %%^^YELLOW%%^^$N $P >%%^^RESET%%^^"; + if(!creatorp(this_player())) cre = ""; + return ("Syntax: prompt [options]\n\n" + "This command allows you to customize your prompt. You may use a static prompt:\n" + "prompt >\n" + "Or you may choose special tokens for an active prompt. The tokens available are:\n" + "$V shows invis status\n" + "$D shows the date (for the server, not the game)\n" + "$T shows the time (for the server, not the game)\n" + "$C shows the command number\n" + "$H shows maximum health points\n" + "$h shows current health points\n" + "$G shows maximum magic points\n" + "$g shows current magic points\n" + "$I shows maximum stamina points\n" + "$i shows current stamina points\n" + "$M shows the mud name\n" + "$N shows the player's name\n" + +cre+ + "\nFor tactical info as a player:\n" + "prompt hp:$h/$H mp:$g/$G sp:$i/$I > \n" + "or: prompt status\n\n" + "You can colorize elements of the prompt with the " + "appropriate color tags, for example:\n" + "prompt %%^^RED%%^^$M %%^^RESET%%^^ >\n" + "\nSee also: reprompt, env, colors"); +} diff --git a/lib/cmds/players/quests.c b/lib/cmds/players/quests.c new file mode 100644 index 0000000..ed93383 --- /dev/null +++ b/lib/cmds/players/quests.c @@ -0,0 +1,42 @@ +#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 key, mapping val in dude->GetQuests()){ + ret += val["Description"] + "\n"; + } + write(ret); + return 1; +} + +string GetHelp(){ + return ("Syntax: quests\n\n" + "This command lists the quests you have completed."); +} diff --git a/lib/cmds/players/queue.c b/lib/cmds/players/queue.c new file mode 100644 index 0000000..2501571 --- /dev/null +++ b/lib/cmds/players/queue.c @@ -0,0 +1,26 @@ +#include +#include + +inherit LIB_DAEMON; + +mixed cmd(string args) { + string *cmds; + if(!sizeof(args)){ + write("Try: help queue"); + return 1; + } + cmds = explode(args, ";"); + foreach(string cmnd in cmds){ + if(sizeof(cmnd)){ + write("Queuing command: "+cmnd); + this_player()->eventQueueCommand(cmnd); + } + } + this_player()->eventExecuteQueuedCommands(); + return 1; +} + +string GetHelp(){ + return ("Syntax: queue \n\n" + "Stacks commands to be executed in order."); +} diff --git a/lib/cmds/players/reprompt.c b/lib/cmds/players/reprompt.c new file mode 100644 index 0000000..735765d --- /dev/null +++ b/lib/cmds/players/reprompt.c @@ -0,0 +1,26 @@ +#include + +inherit LIB_DAEMON; + +mixed cmd(string str) { + if( !sizeof(str) ) + return "Syntax: reprompt "; + str = lower_case(str); + if( str != "on" && str != "off" ) + return "You can only turn reprompt 'on' or 'off'"; + this_player()->SetProperty("reprompt", ( str == "on" ? 1 : 0 )); + message("system", + "Reprompt mode turned "+str+".", + this_player() ); + return 1; +} + +string GetHelp() { + return ("Syntax: reprompt [on | off]\n\n" + "Enables or disables the redrawing of your prompt after " + "receiving messages. Not all clients support this. Note " + "that half-issued commands may wind up looking strange " + "unless charmode is also enabled.\n" + "See also: charmode, prompt, env"); +} + diff --git a/lib/cmds/players/rwho.c b/lib/cmds/players/rwho.c new file mode 100644 index 0000000..7d8e84e --- /dev/null +++ b/lib/cmds/players/rwho.c @@ -0,0 +1,61 @@ +/* /cmds/player/rwho.c + * from the Dead Souls LPC Library + * Sends an Intermud 3 who request + * created by Descartes of Borg 950623 + * + * IMC2 support added by Shadyman 2006-Sep-12 + */ + +#include +#include + +inherit LIB_DAEMON; + +int CheckMud(string name){ + if(!(name = INTERMUD_D->GetMudName(name)) ) return 0; + if(!INTERMUD_D->GetMudList()[name][0]) return 0; + return 1; +} + +mixed cmd(string str) { + string tmp, s1, s2; + string network = "i3"; + + if( !str ) return "Get a remote who from where?"; + + if(grepp(str,"@")){ + if(sscanf(str,"%s@%s", s1, s2) < 2){ + write("Malformed name. Trying anyway..."); + } + else str = s1; + + if(s2 && lower_case(s2) == "imc2"){ + network = "imc2"; + str = imc2_mud_name(s1); + } + } + + if ( network == "imc2" && find_object(IMC2_D) && (tmp = IMC2_D->find_mud(str)) ) { + IMC2_D->who_out(capitalize(this_player()->GetKeyName()),tmp); + message("system", "Remote who query sent to " + tmp + " on the IMC2 network.", this_player()); + return 1; + } else if( CheckMud(str) ) { + tmp = INTERMUD_D->GetMudName(str); + SERVICES_D->eventSendWhoRequest(tmp); + message("system", "Remote who query sent to " + tmp + " on the I3 network.", this_player()); + return 1; + } else { + return mud_name() + " is not aware of such a place, or it is not currently available."; + //Maybe do more processing here for bad spelling, etc? + } + return "Oops, rwho checks fell through, and broke."; +} + +string GetHelp(){ + return ("Syntax: rwho \n\n" + "Gives you a who list in abbreviated form from a mud on the\n" + "global network following the CD protocols for intermud communication.\n" + "The information given by the who varies from mud to mud.\n" + "By default, this command consults the i3 network. You can specify IMC2\n" + "with the following syntax: rwho mudname@imc2"); +} diff --git a/lib/cmds/players/save.c b/lib/cmds/players/save.c new file mode 100644 index 0000000..b41c6ed --- /dev/null +++ b/lib/cmds/players/save.c @@ -0,0 +1,27 @@ +// /bin/user/_save.c +// from the Dead Souls mudlib +// command to save the player +// written by Descartes of Borg + +#include + +inherit LIB_DAEMON; + +int cmd(){ + if(this_player()->query_disable()) { + write("Wait a minute."); + return 1; + } + this_player()->set_disable(); + this_player()->save_player(this_player()->GetKeyName()); + write(this_player()->GetName()+" is now saved."); + return 1; +} + +string GetHelp(){ + return ("Syntax: 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."); +} diff --git a/lib/cmds/players/score.c b/lib/cmds/players/score.c new file mode 100644 index 0000000..e144f19 --- /dev/null +++ b/lib/cmds/players/score.c @@ -0,0 +1,149 @@ +/* /verbs/players/score.c + * from the Dead Souls Library + * Displays a list of score and related info + * created by Blitz@Dead Souls + */ + +#include +#include + +inherit LIB_DAEMON; +inherit LIB_HELP; + +varargs mixed eventScore(); + +static void create() { + daemon::create(); + SetNoClean(1); + SetHelp("Syntax: score\n\n" + "Displays information about your character.\n" + "See also: stat, status, env"); +} + +static string *FoodDegree = +({ "starving!", "very hungry.", + "hungry.", " partially hungry.", + "feeling full.", "quite full." }); + +static string *DrunkDegree = +({ "sober", "tipsy", "drunk", "blitzed", + "three sheets to the wind", "FUBAR" }); + +static string *DrinkDegree = +({ "parched", "extremely thirsty", "very thirsty", "thirsty", + "somewhat thirsty", "unthirsty" }); + +mixed cmd(string arg) { + eventScore(arg); + return 1; +} + +varargs mixed eventScore(string arg) { + string *str; + int birth, age, x, y, z, qp, xp, dbt; + string *tmp; + mapping lev; + object who; + string prn, haben, be, poss; + string past, qual, cnj; + + if(!arg || !creatorp(this_player()) || !(who = find_player(arg))){ + who = this_player(); + haben = "have"; + be = "are"; + poss = "your"; + prn = "you"; + past = "were"; + qual = "qualify"; + cnj = ""; + } + + else { + haben = "has"; + be = "is"; + poss = possessive(who); + prn = nominative(who); + past = "was"; + qual = "qualifies"; + cnj = "s"; + } + str = ({ capitalize(prn)+" "+be+" "+who->GetShort() + " (" + + who->GetMoralityDescription() + ")." }); + str += ({ sprintf(capitalize(prn)+" "+be+" a level %d %s%s %s.", + who->GetLevel(), + ( who->GetUndead() ? "undead " : ""), + capitalize(who->GetRace() || "nothing"), + capitalize(who->GetClass() || "commoner")) }); + str += ({ capitalize(poss)+" native town is "+who->GetTown()+", and "+ + prn+" "+be+" "+ (who->GetReligion() || + "agnostic") + " in faith." }); + str += ({ sprintf(capitalize(prn)+" "+haben+" solved %s, and "+haben+" %s."+ + " (%d Quest Points)", + consolidate(sizeof(who->GetQuests()), + "one quest"), + consolidate(sizeof(who->GetTitles()), + "one title"), who->GetQuestPoints() ) }); + birth = who->GetBirth(); + age = ( query_year(time()) - query_year(birth) ); + str += ({ sprintf(capitalize(prn)+" "+past+ + " 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 = who->GetTrainingPoints() < 1 ) { + y = who->GetLevel() + 1 + (x / -4); + str += ({ "Training points await "+(who == this_player() ? "you" : + objective(who))+" at level " + y + "." }); + } + else str += ({ capitalize(prn)+" "+haben+" " + consolidate( + who->GetTrainingPoints(), + "one training point") + "." }); + if( who->GetWimpy() ) + str += ({ capitalize(prn)+" "+be+" feeling wimpy." }); else + str += ({ capitalize(prn)+" "+be+" feeling brave." }); + if( who->GetPoison() > 0 ) + str += ({ capitalize(prn)+" "+be+" poisoned." }); + x = who->GetFood() / 17; + if( x > sizeof(FoodDegree) - 1 ) x = (sizeof(FoodDegree) - 1); + y = who->GetDrink() / 17; + if( y > sizeof(DrinkDegree) - 1 ) y = (sizeof(DrinkDegree) - 1); + z = who->GetAlcohol(); + if(z) z = (z/17) + 1; + if( z > sizeof(DrunkDegree) - 1 ) z = (sizeof(DrunkDegree) - 1); + str += ({ capitalize(prn)+" "+be+" "+FoodDegree[x] }); + str += ({ sprintf(capitalize(prn)+" "+be+ + " %s and %s.", DrinkDegree[y], DrunkDegree[z]) }); + x = who->GetCustomStats(); + + tmp = ({}); + qp = who->GetQuestPoints(); + xp = who->GetExperiencePoints(); + dbt = who->GetExperienceDebt(); + lev = PLAYERS_D->GetLevelList()[(who->GetLevel()) + 1]; + + if(dbt){ + str += ({ capitalize(prn)+" have "+dbt+" points of "+ + "experience debt." }); + } + + if(lev){ + if(REQUIRE_QUESTING){ + qp = lev["qp"] - qp; + if(qp > 0) tmp += ({capitalize(prn)+" require"+cnj+" "+ + comma(qp)+" more quest points to advance."}); + } + + xp = lev["xp"] - xp; + if(xp > 0) tmp += ({capitalize(prn)+" require"+cnj+" "+ + comma(xp)+" more experience points to advance."}); + if(!sizeof(tmp)) tmp = ({capitalize(prn)+" "+qual+ + " to advance a level."}); + str += tmp; + } + + if(x){ + str += ({ "\n"+capitalize(prn)+" "+haben+" "+x+ + " customization points left. Type: help customize" }); + } + this_player()->eventPage(str, "info"); + return 1; +} diff --git a/lib/cmds/players/screen.c b/lib/cmds/players/screen.c new file mode 100644 index 0000000..f3bc397 --- /dev/null +++ b/lib/cmds/players/screen.c @@ -0,0 +1,34 @@ +/* /cmds/player/screen.c + * from the Foundation II LPC Library + * sets width and height for player terminals + * created by Descartes of Borg 950328 + */ + +#include + +inherit LIB_DAEMON; + +mixed cmd(string args) { + int *screen; + int h, w, lock = this_player()->GetProperty("screenlock"); + 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; + this_player()->SetProperty("screenlock", 0); + 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()); + this_player()->SetProperty("screenlock", lock); + return 1; +} + +string GetHelp() { + return ("Syntax: screen [WIDTH HEIGHT]\n\n" + "Sets the dimensions of your computer screen so that "+ + mud_name() + " knows how to send information to your screen.\n" + "See also: screenlock, brief, terminal, env"); +} diff --git a/lib/cmds/players/screenlock.c b/lib/cmds/players/screenlock.c new file mode 100644 index 0000000..d9b6b19 --- /dev/null +++ b/lib/cmds/players/screenlock.c @@ -0,0 +1,24 @@ +#include + +inherit LIB_DAEMON; + +mixed cmd(string str) { + if( !sizeof(str) ) + return "Syntax: screenlock "; + str = lower_case(str); + if( str != "on" && str != "off" ) + return "You can only turn screenlock 'on' or 'off'"; + this_player()->SetProperty("screenlock", (str == "on")); + message("system", + "Screenlock mode turned "+str+".", + this_player() ); + return 1; +} + +string GetHelp(){ + return ("Syntax: screenlock [on | off]\n\n" + "This command allows you to toggle whether your client is " + "allowed to automatically change your screen size settings " + "after the initial login negotiation.\n" + "See also: screen, terminal, env"); +} diff --git a/lib/cmds/players/skills.c b/lib/cmds/players/skills.c new file mode 100644 index 0000000..2d786c2 --- /dev/null +++ b/lib/cmds/players/skills.c @@ -0,0 +1,72 @@ +/* /cmds/player/skills.c + * from the Dead Souls LPC Library + * command to view skills + * created by Descartes of Borg 950409 + * - 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 = this_player()->GetSkill(skill); + + if( !sizeof(mp) ) return 0; + x = to_int(percent(mp["points"], + this_player()->GetMaxSkillPoints(skill, mp["level"]))); + max = this_player()->GetMaxSkillLevel(skill); + 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 " +this_player()->GetShort() + ", level " + + this_player()->GetLevel(); + if( (tmp = this_player()->GetClass()) ) + ret += " " + capitalize(tmp); + else ret += " Drifter"; + ret += " (" + this_player()->GetRace() + ")\n"; + scr = (this_player()->GetScreen())[0]; + + skills = sort_array(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"; + ret += format_page2(primes, x); + ret += "\n%^BOLD%^%^BLUE%^Secondary skills:%^RESET%^\n"; + ret += format_page2(secs, x); + ret += "\n%^BOLD%^%^BLUE%^Other skills:%^RESET%^\n"; + ret += format_page2(skills, x); + this_player()->eventPage(explode(ret, "\n")); + return 1; +} + +string GetHelp(){ + return "Syntax: skills\n\n" + "Lists all of your skills as well as how skilled you are " + "at the skill in question.\n" + "See also: stats, status"; +} diff --git a/lib/cmds/players/speakcolor.c b/lib/cmds/players/speakcolor.c new file mode 100644 index 0000000..2c1b586 --- /dev/null +++ b/lib/cmds/players/speakcolor.c @@ -0,0 +1,18 @@ +#include + +inherit LIB_DAEMON; + +mixed cmd(string str) { + if( !sizeof(str) ) + return "Syntax: speakcolor "; + this_player()->SetSpeakColor(str); + write("%^BOLD%^"+this_player()->GetSpeakColor()+"This is your current color for "+ + "receiving spoken messages."); + return 1; +} + +string GetHelp() { + return ("Syntax: speakcolor [ cyan | red | green | orange | yellow | blue | magenta | black | white ]\n" + " speakcolor [ b_cyan | b_red | b_green | b_orange | b_yellow | b_blue | b_magenta | b_black | b_white ]\n\n" + "This command allows you to set the color in which you receive spoken messages."); +} diff --git a/lib/cmds/players/spells.c b/lib/cmds/players/spells.c new file mode 100644 index 0000000..4c15915 --- /dev/null +++ b/lib/cmds/players/spells.c @@ -0,0 +1,45 @@ +/* /cmds/player/spells.c + * From Dead Souls LPMud + * created by Descartes of Borg 961028 + * Version: @(#) spells.c 1.3@(#) + * Last modified: 96/10/28 + */ + +#include + +inherit LIB_DAEMON; + +mixed cmd(string args) { + object who = previous_object(); + 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) }); + } + if( !sizeof(spells) ) { + tmp += "You know no spells."; + } + else { + foreach(string spell in spells) { + int i = strlen(spell); + + if( i > len ) { + len = i; + } + } + len = (who->GetScreen())[0]/(len+2); + tmp += format_page(spells, len); + } + who->eventPrint(tmp); + return 1; +} + +string GetHelp(){ + return ("Syntax: spells\n\n" + "Lists all of your spells in your spell book with your " + "proficiency in each spell.\n" + "See also: skills, stats, status"); +} diff --git a/lib/cmds/players/stat.c b/lib/cmds/players/stat.c new file mode 100644 index 0000000..8e8c30c --- /dev/null +++ b/lib/cmds/players/stat.c @@ -0,0 +1,144 @@ +/* /cmds/creator/stat.c + * from the Dead Souls LPC Library + * a command to view something's stats + * created by Descartes of Borg 950409 + */ + +#include +#include + +inherit LIB_DAEMON; + +string gargs; + +mixed cmd(string args) { + string *lines, *arr, *limbs; + object ob, *candidates; + string tmp1, tmp2, gold; + int i, x, y, cols, dbt; + + if( args == "" || !args || args == "me" ) ob = this_player(); + else if(args && !creatorp(this_player())) { + write("You can only stat yourself."); + return 1; + } + if(!environment(this_player())){ + write("You have no environment. Stats are the least of your worries."); + return 1; + } + gargs = args; + candidates = filter(get_livings(environment(this_player())), + (: answers_to(gargs, $1) :) ); + if(!ob && sizeof(candidates)) ob = candidates[0]; + else if( !ob && !(ob = present(args, environment(this_player()))) ) + if( !(ob = find_player(convert_name(args))) && + !(ob = find_living(lower_case(args))) && + !(ob = find_object(args)) ) + return capitalize(args) + " is nowhere to be found."; + if(!living(ob)) return capitalize(args) + " is not alive."; + cols = (this_player()->GetScreen())[0]; + tmp1 = ob->GetCapName() + " aka " + ob->GetShort() + + ", level " + ob->GetLevel() + " " + ob->GetGender(); + if( !(tmp2 = ob->GetRace()) ) tmp2 = "blob"; + tmp1 += " " + tmp2; + if( !(tmp2 = ob->GetClass()) || !stringp(tmp2)) tmp2 = "drifter"; + tmp1 += " " + capitalize(tmp2); + if( tmp2 = ob->GetSpouse() ) + tmp1 += " (spouse: " + tmp2 + ")"; + lines = ({ center(tmp1, cols) }); + if( ob->GetUndead() ) tmp1 = "%^BOLD%^RED%^UNDEAD%^RESET%^"; + else tmp1 = "%^BOLD%^GREEN%^Alive%^RESET%^"; + if( ob->GetSleeping() ) tmp1 += " / Sleeping"; + else tmp1 += " / Awake"; + if( ob->GetParalyzed() ) tmp1 += " / Paralyzed"; + lines += ({ center(tmp1, cols), "" }); + lines += ({ center("Health: " +ob->GetHealthPoints() + "/"+ + ob->GetMaxHealthPoints() + " Magic: " + + ob->GetMagicPoints() + "/" + + ob->GetMaxMagicPoints() + " Stamina: " + + ob->GetStaminaPoints() + "/" + + to_int(ob->GetMaxStaminaPoints()) + " Carry: " + + ob->GetCarriedMass() + "/" + + ob->GetMaxCarry(), cols) }); + lines += ({ center("Food: " + ob->GetFood() + " " + + "Drink: " + ob->GetDrink() + " " + + "Alcohol: " + ob->GetAlcohol() + " " + + "Caffeine: " + ob->GetCaffeine() + " " + + "Poison: " + ob->GetPoison() + " ", cols) }); + lines += ({ "\n" }) ; + if(dbt = ob->GetExperienceDebt()) { + lines += ({ center("Training Points: " + ob->GetTrainingPoints() + + " " + + "Quest Points: "+ ob->GetQuestPoints(),cols) + }); + lines += ({ center("Experience Points: " + ob->GetExperiencePoints() + + " " + + "Experience Debt: "+ dbt,cols) + }); + } else { + lines += ({ center("Training Points: " + ob->GetTrainingPoints() + + " " + + "Quest Points: "+ ob->GetQuestPoints() + + " " + + "Experience Points: "+ ob->GetExperiencePoints(),cols) + }); + } + lines += ({ "", "Limbs:" }); + limbs = ob->GetWieldingLimbs(); + if(ob && !ob->GetGhost()) arr = map(sort_array(ob->GetLimbs(), 1), + (: sprintf("%:-14s%s (%d) %d/%d", $1, + ((member_array($1, $(limbs)) == -1) ? " " : "*"), + ($(ob))->GetLimbClass($1), + ($(ob))->GetHealthPoints($1), + ($(ob))->GetMaxHealthPoints($1)) :)); + i = sizeof(arr); + while(i--) if( (y = strlen(arr[i])) > x ) x = y; + x = cols/(x+2); + lines += explode(format_page2(arr, x), "\n") + ({ "", "Skills:" }); + arr = map(sort_array(ob->GetSkills(), 1), + function(string skill, object who) { + mapping mp = who->GetSkill(skill); + int x, max; + x = to_int(percent(mp["points"], + who->GetMaxSkillPoints(skill, mp["level"]))); + max = who->GetMaxSkillLevel(skill); + 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_page2(arr, x), "\n") + ({ "", "Stats:" }); + arr = map(sort_array(ob->GetStats(), 1), + (: sprintf("%:-12s (%d) %d/%d", $1, + ($(ob))->GetStatClass($1), + ($(ob))->GetStatLevel($1), + ($(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_page2(arr, x), "\n"); + if(sizeof(ECONOMY_D->__QueryCurrencies())){ + if(valid_currency("gold")) gold = "gold"; + else gold = ECONOMY_D->__QueryCurrencies()[0]; + lines += ({ "", ob->GetName()+" has amassed a net worth of " + + ( ob->GetNetWorth(gold) ) + " "+gold+"."}); + arr = filter( map(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 ret = "Syntax: stat"; + if(creatorp(this_player())) ret += " [living]"; + ret += "\n\nDisplays statistical information of a living object.\n"+ + "See also: score, status, env."; + return ret; +} diff --git a/lib/cmds/players/stats.c b/lib/cmds/players/stats.c new file mode 100644 index 0000000..172d1d5 --- /dev/null +++ b/lib/cmds/players/stats.c @@ -0,0 +1,70 @@ +/* /cmds/player/stats.c + * from the Dead Souls LPC Library + * command to view stats + * created by Descartes of Borg 950409 + */ + +#include + +inherit LIB_DAEMON; +object who; + +mixed cmd(string args) { + string *stats; + string ret, tmp; + int i, x, y; + who = 0; + + if(args){ + if(!creatorp(this_player())){ + write("Try: help stats"); + return 1; + } + if(args == "me" || args == "myself") who = this_player(); + if(!who) who = find_player(lower_case(args)); + if(!who){ + object *creatures = get_livings(environment(this_player())); + creatures = filter(creatures, + (: answers_to(lower_case($(args)), $1) :)); + if(sizeof(creatures)) who = creatures[0]; + } + if(!who){ + write("No such living thing found."); + return 1; + } + } + + else who = this_player(); + + ret = who->GetShort() + ", level " + + who->GetLevel(); + if( (tmp = who->GetClass()) ) + ret += " " + capitalize(tmp); + else ret += " Drifter"; + ret += " (" + who->GetRace() + ")\n"; + stats = map(sort_array(who->GetStats(), 1), + (: sprintf("%:-20s: %:-3d", $1, + who->GetStatLevel($1)) :)); + i = sizeof(stats); + while(i--) if( (y = strlen(stats[i])) > x ) x = y; + x = (this_player()->GetScreen())[0]/(x+2); + ret += format_page2(stats, x); + message("system", ret, this_player()); + return 1; +} + +string GetHelp() { + if(creatorp(this_player())){ + return ("Syntax: stats [player]\n\n" + "Lists the stats of the specified player as well as " + "the stat level. With no argument, it defaults to your " + "own stats.\n" + "See also: stat, status, score"); + } + else { + return ("Syntax: stats\n\n" + "Lists all of your stats as well as how skilled you are " + "at the stat in question.\n" + "See also: stat, status, score"); + } +} diff --git a/lib/cmds/players/status.c b/lib/cmds/players/status.c new file mode 100644 index 0000000..3e665e9 --- /dev/null +++ b/lib/cmds/players/status.c @@ -0,0 +1,17 @@ +/* /cmds/player/status.c + * from the Dead Souls LPC Library + * gives a player status information + * created by Descartes of Borg 950409 + */ + +#include + +inherit LIB_DAEMON; + +mixed cmd(string args) { return this_player()->eventDisplayStatus(); } + +string GetHelp() { + return ("Syntax: status\n\n" + "Gives you information about your current physical status.\n" + "See also: money, skills, stats, score, env"); +} diff --git a/lib/cmds/players/terminal.c b/lib/cmds/players/terminal.c new file mode 100644 index 0000000..82fccfc --- /dev/null +++ b/lib/cmds/players/terminal.c @@ -0,0 +1,24 @@ +/* /cmds/player/terminal.c + * from the Foundation II LPC Library + * allows a person to set their terminal manually + * created by Descartes of Borg 950501 + */ + +#include + +inherit LIB_DAEMON; + +mixed cmd(string args) { + if( !args || args == "" ) return "Set it to what?"; + message("system", "Terminal set to " + + this_player()->SetTerminal(args) + ".", this_player()); + return 1; +} + +string GetHelp() { + return ("Syntax: terminal \n\n" + "Allows you to set your terminal type manually in the " + "event the MUD does not automatically recognize the proper " + "setting.\n" + "See also: screen, env"); +} diff --git a/lib/cmds/players/timezone.c b/lib/cmds/players/timezone.c new file mode 100644 index 0000000..9dbb4c3 --- /dev/null +++ b/lib/cmds/players/timezone.c @@ -0,0 +1,32 @@ +#include +#include + +inherit LIB_DAEMON; + +string *zones_cfg = explode((read_file(CFG_TIMEZONES)|| ""), "\n"); + +mixed cmd(string args) { + string tz = this_player()->GetProperty("timezone"); + if(!tz || tz == "NONE") tz = "No timezone set."; + + if(!args){ + write("Your timezone is: "+tz); + return 1; + } + args = upper_case(args); + if(member_array(args, (zones_cfg + ({"NONE"}))) == -1){ + write("That is an unknown timezone."); + return 1; + } + this_player()->SetProperty("timezone", args); + write("Your timezone is now set to: "+args); + return 1; +} + +string GetHelp(){ + return ("Syntax: timezone [zone | none]\n\n" + "Without an argument, timezone will display your current " + "timezone. If provided a valid timezone known to the mud, " + "it will attempt to set your personal timezone to that." + "\nSee also: env"); +} diff --git a/lib/cmds/players/title.c b/lib/cmds/players/title.c new file mode 100644 index 0000000..65b62ed --- /dev/null +++ b/lib/cmds/players/title.c @@ -0,0 +1,148 @@ +/* /cmds/player/title.c + * from the Dead Souls LPC Library + * allows someone to set their titles + * created by Descartes of Borg 950716 + */ + +#include +#include + +inherit LIB_DAEMON; + +static void eventOrderTitles(string *titles, int maxi); +static void GetTitle(string which, string *titles, int maxi); +static void GetDest(string which, string *titles, int i, int maxi); + +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 = this_player()->SetShort(args); + message("system", "Title changed to: " + args, this_player()); + this_player()->save_player(this_player()->GetKeyName()); + update("/secure/daemon/finger"); + return 1; + } + if( !(maxi = sizeof(titles = 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(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 ) { + function f; + + f = function(string yn, string *titles) { + yn = (yn || "n"); + if( yn != "y" ) { + message("system", "Titles remain unchanged.", this_player()); + return; + } + this_player()->SetTitles( ({ titles[1], titles[0] }) ); + message("system", "Titles reversed.", this_player()); + this_player()->save_player(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; + } + else eventOrderTitles(titles, maxi); + return 1; +} + +static void eventOrderTitles(string *titles, int maxi) { + int i; + + message("system", "You have the following titles:", this_player()); + for(i=0; iSetTitles(titles); + message("system", "Done.", this_player()); + return; + } + else if( which == "" || !which ) which = "" + maxi; + x = to_int(which); + if( x < 1 || x > maxi ) { + message("system", "Illegal title number.", this_player()); + eventOrderTitles(titles, maxi); + return; + } + x--; + message("prompt", "Move \"" + titles[x] + "\" to position? [1] ", + this_player()); + input_to( (: GetDest :), titles, x, maxi ); +} + +static void GetDest(string which, string *titles, int i, int maxi) { + string *tmp; + int j, maxj, x; + + if( which == "q" ) { + this_player()->SetTitles(titles); + message("system", "Done.", this_player()); + this_player()->save_player(this_player()->GetKeyName()); + update("/secure/daemon/finger"); + return; + } + else if( which == "" || !which ) which = "1"; + x = to_int(which); + if( x < 1 || x > maxi || x == i+1 ) { + message("system", "Illegal title number.", this_player()); + eventOrderTitles(titles, maxi); + return; + } + x--; + tmp = allocate(maxj = sizeof(titles)); + for(j=0; j x && j > i) ) tmp[j] = titles[j]; + else if( j > x && j <= i ) tmp[j] = titles[j-1]; + else tmp[j] = titles[j+1]; + } + eventOrderTitles(tmp, maxi); +} + +string GetHelp() { + if( creatorp(this_player()) ) { + return ("Syntax: 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."); + } + else { + return ("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."); + } +} + diff --git a/lib/cmds/players/unmuff.c b/lib/cmds/players/unmuff.c new file mode 100644 index 0000000..44ead6c --- /dev/null +++ b/lib/cmds/players/unmuff.c @@ -0,0 +1,23 @@ +#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; +} + +string GetHelp() { + return ("Syntax: unmuff <name>\n\n" + "This command allows you to stop ignoring channel messages from the name specified.\n" + "See also: earmuff, whomuffed"); +} + diff --git a/lib/cmds/players/uptime.c b/lib/cmds/players/uptime.c new file mode 100644 index 0000000..445f1a9 --- /dev/null +++ b/lib/cmds/players/uptime.c @@ -0,0 +1,48 @@ +/* /cmds/player/uptime.c + * from the Dead Souls LPC Library + * tells how long the driver has been up + * created by Beek@Dead Souls 950309 + */ + +#include <lib.h> + +#define MIN 60 +#define HOUR (60 * MIN) +#define DAY (24 * HOUR) +#define WEEK ( 7 * DAY) + +inherit LIB_DAEMON; + +mixed cmd(string unused) { + int tm = uptime(); + string str; + int x; + + 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); + return 1; +} + +string GetHelp(){ + return ("Syntax: uptime\n\nReports how long "+mud_name()+" has been up."); +} diff --git a/lib/cmds/players/users.c b/lib/cmds/players/users.c new file mode 100644 index 0000000..8c1c9b9 --- /dev/null +++ b/lib/cmds/players/users.c @@ -0,0 +1,46 @@ +/* Cygnus@Dead Souls */ + +#include <lib.h> + +inherit LIB_DAEMON; + +int cmd(){ + int i; + object *user_ob; + string ret, name, *user_name; + + user_ob = users(); + user_name = ({ }); + for (i = 0; i < sizeof(user_ob); i++) { + if(user_ob[i]){ + if( user_ob[i]->GetInvis() ) + continue; + name = user_ob[i]->GetKeyName(); + if (stringp(name)) + user_name += ({ capitalize(name) }); + } + } + user_name = sort_array(user_name, "sort_names"); + ret = format_page(user_name, 4); + ret += sprintf("Total : %d", sizeof(user_name)); + if(sizeof(ret) < __LARGEST_PRINTABLE_STRING__ ) write(ret); + else this_player()->eventPage(ret); + return 1; +} + +int sort_names(string name1, string name2){ + if (name1 == name2) + return 0; + if (name1 < name2) + return -1; + else + return 1; +} + +string GetHelp(){ + return "Syntax: users\n\n" + "Lists the names of player logged in. " + "A shorter and quicker version of \"who\".\n" + "See also: who, where\n" + "See also: say, tell, class\n"; +} diff --git a/lib/cmds/players/version.c b/lib/cmds/players/version.c new file mode 100644 index 0000000..fdb150b --- /dev/null +++ b/lib/cmds/players/version.c @@ -0,0 +1,42 @@ +/* /cmds/player/version.c + * from the Dead Souls LPC Library + * gives information about the MUD + * created by Descartes of Borg 950507 + */ + +#include <lib.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 = this_player()->GetProperty("timezone"); + if(!tz || !valid_timezone(tz)) tz = query_tz(); + offset = 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()) + (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; +} + +string GetHelp() { + return ("Syntax: version\n\n" + "Gives you version information about "+mud_name()+" as well as how " + "long the mud has been up in your local time if you have it " + "specified."); +} diff --git a/lib/cmds/players/who.c b/lib/cmds/players/who.c new file mode 100644 index 0000000..afffe3f --- /dev/null +++ b/lib/cmds/players/who.c @@ -0,0 +1,181 @@ +/* Hiccups@Frontiers, 12/16/96 */ +/* Fixes by Haderach, 05 SEP 2005 */ +/* RWHO check by Shadyman, 2006-Sep-12 */ + +#include <lib.h> +#include <privs.h> +#include <daemons.h> + +inherit LIB_DAEMON; +mapping instinfo; +mixed instances; + +#define SEP repeat_string("*=",39)+"*\n"; + +static int LevelSort(mixed one, mixed two){ + int i1, i2, alpha; + string s1, s2; + if(objectp(one)){ + i1 = one->GetLevel(); + s1 = one->GetName(); + if(creatorp(one)) alpha = 1; + } + if(objectp(two)){ + i2 = two->GetLevel(); + s2 = two->GetName(); + if(creatorp(two)) alpha = 1; + } + if(stringp(one) && sizeof(instinfo) && mapp(instinfo[one])){ + i1 = instinfo[one]["level"]; + s1 = one; + if(instinfo[one]["creator"]) alpha = 1; + } + if(stringp(two) && sizeof(instinfo) && mapp(instinfo[two])){ + i2 = instinfo[two]["level"]; + s2 = two; + if(instinfo[two]["creator"]) alpha = 1; + } + if(alpha) return strcmp(s1, s2); + if(i1 > i2) return -1; + else if(i2 > i1) return 1; + else if(s1 && s2) return strcmp(s1, s2); + return -1; +} + +int cmd(string args) { + int p; + string x, tmp="", ret=""; + object *obs; + + if (args && args[0] == '@') { //If there's an @ in the first arg character, it's an rwho request. + if( sizeof(args) <=1 ) return notify_fail("Get a remote who from where?"); //If there's only an @, tell them to RTFM. + "/cmds/players/rwho"->cmd(args[1..]); //Pass it the mud name without the @ + return 1; + } else { + mixed arches, cres, players; + p = 0; + arches = sort_array(filter(users(), (: archp($1) :)), + "LevelSort"); + cres = sort_array(filter(users(), (: !archp($1) && creatorp($1):)), + "LevelSort"); + players = sort_array(filter(users(), (: !creatorp($1) :)), + "LevelSort"); + obs = arches + cres + players; + + for (int i=0; i<sizeof(users()); i++) { + string fnm; + if(!obs[i] || !environment(obs[i])) continue; + sscanf(last_string_element(base_name(obs[i]), "/"),"%s.%*s", fnm); + if(fnm && fnm != obs[i]->GetKeyName()) 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(testp(obs[i]) && !archp(obs[i])){ + tmp+="[%^B_CYAN%^%^BLACK%^TEST%^RESET%^]"; + } + if(ambassadorp(obs[i])) tmp+="[%^YELLOW%^AMBASSADOR%^RESET%^]"; + tmp += ": "; + if(sizeof(strip_colours(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 += " (%^BLUE%^sleeping%^RESET%^) "; + } + else if (obs[i]->GetProperty("afk")){ + tmp += " (%^MAGENTA%^afk%^RESET%^)"; + } + else if (query_idle(obs[i])>240 && obs[i]->GetInCombat()!=1){ + tmp += " (%^YELLOW%^idle%^RESET%^)"; + } + else if (in_edit(obs[i]) || obs[i]->GetCedmode()){ + tmp += " (%^CYAN%^edit%^RESET%^)"; + } + else if(obs[i]->GetInCombat()){ + tmp += " (%^RED%^combat%^RESET%^)"; + } + tmp += "%^RESET%^\n"; + p++; + } + } + ret+=center(mud_name()); + ret+="\n"; + ret+=SEP; + ret+=tmp; + instances = singular_array(INSTANCES_D->GetInstances()); + if(ENABLE_INSTANCES) instances = ({ "global" }); + tmp = INSTANCES_D->GetMyInstanceName(); + if(tmp && instances) instances -= ({ tmp }); + tmp = ""; + + foreach(string inst in sort_array(instances, 1)){ + mixed guys; + mapping tmpmap; + if(!inst) continue; + arches = ({}); + cres = ({}); + players = ({}); + guys = ({}); + instinfo = INSTANCES_D->GetInstData()[inst]; + if(!sizeof(instinfo)){ + continue; + } + if(instinfo["mudname"]) inst = instinfo["mudname"]; + tmp += "\n"+center("--- Instance: "+capitalize(inst)+" ---\n"); + if(!mapp(instinfo["users"])){ + continue; + } + foreach(string name, mapping data in instinfo["users"]){ + string tmpname; + if(name && mapp(data)){ + tmpname = name; + if(data["arch"]) arches += ({ name }); + else if(data["creator"]) cres += ({ name }); + else players += ({ name }); + } + } + arches = sort_array(arches, "LevelSort"); + cres = sort_array(cres, "LevelSort"); + players = sort_array(players, "LevelSort"); + guys = arches + cres + players; + foreach(string dude in guys){ + if(!dude) continue; + tmpmap = instinfo["users"][dude]; + if(!sizeof(tmpmap)) continue; + if(tmpmap["status"] < 1) continue; + if(tmpmap["arch"])tmp += "[%^BLUE%^ARCH%^RESET%^]"; + else if(tmpmap["creator"]) tmp += "[%^CYAN%^WIZ%^RESET%^]"; + else tmp += "["+tmpmap["level"]+"]"; + tmp += ": " + tmpmap["title"]; + if(tmpmap["state"]) tmp += " " +tmpmap["state"]; + tmp += "%^RESET%^\n"; + } + ret += tmp; + 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); + if(check_string_length(ret)) this_player()->eventPrint(""+ret+""); + else print_long_string(this_player(),ret); + return 1; + } +} + +string GetHelp(){ + return ("Syntax: who [@mud]\n\n" + "Gives you a who list in abbreviated form from this mud or other muds on the I3 or IMC2 network."); +} diff --git a/lib/cmds/players/wimpy.c b/lib/cmds/players/wimpy.c new file mode 100644 index 0000000..4f9862e --- /dev/null +++ b/lib/cmds/players/wimpy.c @@ -0,0 +1,104 @@ +/* /cmds/players/wimpy.c + * from the Dead Souls Mud Library + * wimpy NUM + * wimpy STR + * created by Descartes of Borg 960113 + */ + +#include <lib.h> +#include <message_class.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + int percentage; + string cmd; + + if( !args || args == "" ) { + percentage = this_player()->GetWimpy(); + cmd = 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" ) { + percentage = 0; + cmd = 0; + } + else if( percentage = to_int(args) ) cmd = 0; + else if( args == "on" ) { + percentage = 23; + cmd = 0; + } + else if( args == "off" ) { + percentage = 0; + cmd = 0; + } + else { + percentage = 0; + cmd = args; + } + if( !cmd ) { + 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 ) { + this_player()->eventPrint("You are the cautious one!", MSG_SYSTEM); + return 1; + } + 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(){ + return ("Syntax: wimpy [on | off | PERCENTAGE | 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" + "See also: attack, status"); +} + diff --git a/lib/cmds/players/xyzzy.c b/lib/cmds/players/xyzzy.c new file mode 100644 index 0000000..6527cb0 --- /dev/null +++ b/lib/cmds/players/xyzzy.c @@ -0,0 +1,9 @@ +#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 --git a/lib/daemon/banish.c b/lib/daemon/banish.c new file mode 100644 index 0000000..792d08b --- /dev/null +++ b/lib/daemon/banish.c @@ -0,0 +1,352 @@ +/* /adm/daemon/banish.c + * from Dead Souls + * maintains information on legitimate character creation + * created by Descartes of Borg 940115 + */ + +#include <lib.h> +#include <privs.h> +#include <objects.h> +#include <daemons.h> +#include <save.h> +#include <dirs.h> + +#ifndef GUEST_ALLOWED +#define GUEST_ALLOWED 1 +#endif + +#ifndef CFG_IP_BLACKLIST +#define CFG_IP_BLACKLIST DIR_SECURE_CFG "/ip_blacklist.cfg" +#endif + +inherit LIB_DAEMON; + +string *__Names, *__Sites, *__WatchNames, *__WatchSites; +string *__Allowed, *__Guests, *__IllegalSubStrings; +mapping __TmpBanish; +static string SaveFile; + +static private int valid_access(object ob); +void register_site(string str); +void temporary_register(string str, int time); +string query_temp_sites(); +void manual_temp_unregister(string str); +void clean_temp_sites(); +void unregister_site(string str); +string *query_register(); +void banish_name(string str); +void unbanish_name(string str); +string *query_banished(); +void watch_site(string str); +void unwatch_site(string str); +string *query_watched_sites(); +void watch_name(string str); +void unwatch_name(string str); +string *query_watched_names(); +void allow_name(string str); +void unallow_name(string str); +string *query_allowed(); +void set_illegal_substring(string str); +void remove_illegal_substring(string str); +string *query_illegal_substrings(); +void add_guest(string str); +void remove_guest(string str); +string *query_guests(); +static private void save_banish(); +int GetGuest(string str); +int valid_name(string str); +int eventConnect(string nom, string ip); +static private int match_ip(string ip, string *sites); +void setup_blacklist(); + +void create() { + daemon::create(); + SetNoClean(1); + SaveFile = save_file(SAVE_BANISH); + __Names = ({"template"}); + __Sites = ({}); + __WatchNames = ({}); + __WatchSites = ({}); + __Allowed = ({}); + __Guests = ({}); + __IllegalSubStrings = ({}); + __TmpBanish=([]); + if(unguarded( (: file_exists(SaveFile) :) )){ + RestoreObject(SaveFile); + } + if(!__TmpBanish) __TmpBanish = ([]); + clean_temp_sites(); + setup_blacklist(); +} + +void setup_blacklist(){ + if(file_exists(CFG_IP_BLACKLIST)){ + __Sites += read_big_file(CFG_IP_BLACKLIST); + __Sites = distinct_array(__Sites); + } + save_banish(); +} + +static private int valid_access(object ob) { + return 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; + if(strsrch(cap, "' ") != -1) return 0; + if(strsrch(cap, "''") != -1) return 0; + if(strsrch(cap, "-'") != -1) return 0; + if(strsrch(cap, "- ") != -1) return 0; + if(strsrch(cap, "--") != -1) return 0; + if(strsrch(cap, " '") != -1) return 0; + 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(); + __TmpBanish+=([ str : foo ]); + __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", + 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() { + SaveObject(SaveFile); +} + +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; + if(!GUEST_ALLOWED && lower_case(str) == "guest") return 0; + i = sizeof(__IllegalSubStrings); + while(i--) if(strsrch(str, __IllegalSubStrings[i]) != -1) return 0; + 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 --git a/lib/daemon/books.c b/lib/daemon/books.c new file mode 100644 index 0000000..406d17e --- /dev/null +++ b/lib/daemon/books.c @@ -0,0 +1,159 @@ +#include <lib.h> +#include <save.h> + +inherit LIB_DAEMON; + +mapping Books = ([]); + +static string *globalheader; +static string globalstr, globalstr2; +static string SaveFile = save_file(SAVE_BOOKS); + +static void create() { + daemon::create(); + if(unguarded( (: file_exists(SaveFile) :) ) ){ + RestoreObject(SaveFile); + } + if(!Books) Books = ([]); + SetNoClean(1); + SaveObject(SaveFile); +} + +int eventDestruct(){ + SaveObject(SaveFile); + return daemon::eventDestruct(); +} + +string SetBookTitle(string path, string title){ + if(!Books[path]) Books[path] = ([]); + Books[path]["title"] = title; + return title; +} + +string GetBookTitle(string path){ + if(Books[path] && Books[path]["title"]) return Books[path]["title"]; + return "Untitled"; +} + +string array ExtractChapterName(string path){ + string *header; + string chap, foo, line; + int num; + + if(!path) return ({""}); + if(first(last_string_element(path,"/"),1) == ".") return ({""}); + + if(path && file_size(path) > 0){ + globalstr = ""; + globalstr2 = path; + if(!file_exists(globalstr2)) globalstr2 == ""; + if(sizeof(globalstr2)) unguarded( (: globalstr = read_file(globalstr2, 1, 1) :) ); + line = globalstr; + } + if(!line) chap = "unknown"; + if(!strsrch(line,"Chapter")) line=replace_string(line,"Chapter","chapter",1); + if(sscanf(line,"chapter %s %s", chap, foo) != 2) chap = "unknown"; + if(sscanf(chap,"%d",num) != 1) num = 0; + header = ({ "chapter "+chap, "chapter "+cardinal(num), chap }); + return ({ copy(header), foo }); +} + +mixed *LoadChapters(string Source){ + string this_path; + if(!Books[Source]) Books[Source] = ([]); + if(!Books[Source]["object"]){ + if(previous_object() && base_name(previous_object()) != LIB_BOOK) + Books[Source]["object"] = base_name(previous_object()); + else Books[Source]["object"] = "null"; + } + if(!Books[Source]["items"]) Books[Source]["items"] = ([]); + if(!Books[Source]["reads"]) Books[Source]["reads"] = ([]); + + foreach(string chap in get_dir(Source+"/")){ + mixed *statinfo; + this_path = Source+"/"+chap; + statinfo = stat(this_path); + if(sizeof(statinfo) != 3 || !intp(statinfo[1]) || + (Books[Source][this_path] && Books[Source][this_path] + == statinfo[1])){ + continue; + } + else { + Books[Source][this_path] = statinfo[1]; + Books[Source]["index"] = 0; + } + + globalheader = ExtractChapterName(this_path); + + if(sizeof(globalheader) > 1){ + Books[Source]["items"][globalheader[0]] = globalheader[1]; + globalstr = this_path; + globalstr2 = Source; + unguarded( (: Books[globalstr2]["reads"][globalheader[0]] = + read_file(globalstr) :) ); + } + } + this_object()->LoadBookIndex(Source); + return copy(Books[Source]["items"]); +} + +string LoadBookIndex(string Source){ + int i, items; + string chapter_index; + if(!Books[Source]) return 0; + if(Books[Source]["index"]) return Books[Source]["index"]; + if(!Books[Source]["title"]) Books[Source]["title"] = "Untitled"; + items = sizeof(Books[Source]["items"])+1; + chapter_index = "\t\t"+Books[Source]["title"]+"\n\n"; + for(i=1; i<items; i++){ + foreach(mixed key, mixed val in Books[Source]["items"]){ + if(member_array("chapter "+i, key) != -1){ + chapter_index += "Chapter "+i+":\t"; + chapter_index += val+"\n"; + break; + } + } + } + Books[Source]["index"] = chapter_index; + return chapter_index; +} + +string GetBookIndex(string Source){ + if(!Books[Source] || !Books[Source]["index"]) return "No index."; + return Books[Source]["index"]; +} + +string ReturnRead(string file, string what){ + string ret; + if(Books[file] && Books[file]["reads"]){ + foreach(mixed key, mixed val in Books[file]["reads"]){ + if(member_array(what, key) != -1){ + ret = val; + break; + } + } + if(ret) return ret; + } + return "There is no such thing to read."; +} + +string GetBookRead(string name, mixed arg){ + if(arrayp(arg) && sizeof(arg)) arg = arg[0]; + if(!sizeof(arg) || !Books[name] || !Books[name]["reads"]){ + return "There is no such thing to read there."; + } + foreach(mixed key, mixed val in Books[name]["reads"]){ + if(member_array(arg, key) != -1) return val; + } + return "There is no such thing to read there."; +} + +int zero(){ + if(this_player() && archp(this_player())){ + Books = ([]); + } + return 0; +} + +mixed GetBooks() { return copy(Books); } + diff --git a/lib/daemon/bugs.c b/lib/daemon/bugs.c new file mode 100644 index 0000000..0e5a5bb --- /dev/null +++ b/lib/daemon/bugs.c @@ -0,0 +1,125 @@ +/* /daemon/bugs.c + * from the Dead Souls Object Library + * a management daemon for bug tracking + * created by Descartes of Borg 950925 + */ + +#include <lib.h> +#include <save.h> +#include "include/bugs.h" + +inherit LIB_DAEMON; + +#define UNCOMPLETED_LIFE (24 * 3600 * 30 * 6) +#define COMPLETED_LIFE (24 * 3600 * 10) + +private int NextID; +private mapping Bugs; +static string SaveFile; + +static void create() { + mapping bug; + int t, bug_id; + SaveFile = save_file(SAVE_BUGS); + + daemon::create(); + if(unguarded( (: file_exists(SaveFile) :) ) ){ + RestoreObject(SaveFile); + } + if( NextID < 1 || !Bugs ) { + NextID = 1; + Bugs = ([]); + } + t = time(); + 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); + } + } + SaveObject(SaveFile); +} + +int eventAssign(int bug, string who) { + if( !Bugs[bug] ) return 0; + if( !user_exists(convert_name(who)) ) return 0; + else who = capitalize(who); + Bugs[bug]["assigned"] = who; + Bugs[bug]["date assigned"] = time(); + return SaveObject(SaveFile); +} + +int eventComplete(int bug, string resolution) { + if( !Bugs[bug] ) return 0; + Bugs[bug]["date fixed"] = time(); + Bugs[bug]["resolution"] = resolution; + if( SaveObject(SaveFile) ) return 1; + else { + Bugs[bug]["date fixed"] = 0; + Bugs[bug]["resolution"] = 0; + return 0; + } +} + +int eventDelete(int bug) { + mapping fu; + + if( !Bugs[bug] ) return 0; + fu = copy(Bugs); + map_delete(Bugs, bug); + if( !SaveObject(SaveFile) ) { + Bugs = fu; + return 0; /* someone tried to delete this bug */ + } + else return 1; +} + +int eventReport(string who, string type, string bug, string data) { + int x; + + x = NextID++; + Bugs[x] = ([ "who" : who, "type" : type, "bug" : bug, "data" : data, + "assigned" : 0, "date fixed" : 0, "resolution" : 0 ]); + if( SaveObject(SaveFile) ) return x; + else { + map_delete(Bugs, x); + return 0; + } +} + +int BugCheck(){ + int bugs = 0; + foreach(int id, mapping rep in Bugs){ + if(!rep["resolution"]) bugs++; + } + return bugs; +} + +int GetAssignedBugs(string who) { + mapping rep; + int id, x = 0; + + foreach( id, rep in Bugs) + if( rep["assigned"] && !rep["date fixed"] && + (convert_name(rep["assigned"]) == who) ) x++; + return x; +} + +mapping GetBugs() { return Bugs; } + +string AddComment(int bug, string comment) { + string tmp; + + if( !Bugs[bug] ) return 0; + if( !Bugs[bug]["data"] ) Bugs[bug]["data"] = ""; + tmp = Bugs[bug]["data"]; + Bugs[bug]["data"] += "\n" + comment; + if( !SaveObject(SaveFile) ) { + Bugs[bug]["data"] = tmp; + return 0; + } + return Bugs[bug]["data"]; +} diff --git a/lib/daemon/classes.c b/lib/daemon/classes.c new file mode 100644 index 0000000..6923817 --- /dev/null +++ b/lib/daemon/classes.c @@ -0,0 +1,190 @@ +/* /daemon/classes.c + * from the Dead Souls Object Library + * handles race configuration and administration + * created by Descartes of Borg 960929 + * Version: @(#) classes.c 1.4@(#) + * Last modified: 96/10/17 + */ + +#include <lib.h> +#include <cfg.h> +#include <save.h> +#include <daemons.h> +#include <privs.h> +#include "include/classes.h" + +inherit LIB_DAEMON; + +private mapping Classes = ([]); +private int converted = 0; +static string SaveFile; +static int player, foo; + +static void create() { + daemon::create(); + SaveFile = save_file(SAVE_CLASSES); + if( unguarded((: file_exists(SaveFile) :)) ){ + RestoreObject(SaveFile); + } + if(!Classes) Classes = ([]); + if(!converted || !sizeof(Classes)){ + string *classes = get_dir(CFG_CLASSES+"/"); + Classes = ([]); + foreach(string element in classes){ + string str = CFG_CLASSES+"/"+element; + if(file_exists(str)) { + catch( this_object()->AddClass(str) ); + } + } + } + converted = 1; + SaveObject(SaveFile); +} + +static private void validate() { + if( !(master()->valid_apply(({ PRIV_ASSIST }))) ) + error("Illegal attempt to modify class data"); +} + +int ClassMember(string my_class, string query_class) { + mapping cls; + + if( my_class == query_class ) { + return 1; + } + cls = Classes[query_class]; + if( !cls ) { // query class is a multi-class, thus must be equal to mine + return 0; // This should change for triple classing + } + return (member_array(my_class, values(cls["Multis"])) != -1); +} + +void AddClass(string file) { + mapping cls = ([]); + string array lines, tmp; + string class_name; + player = 1; + 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; + } + if(!strsrch(str, "PLAYER_CLASS")){ + if(sscanf(str, "PLAYER_CLASS %d", foo)){ + if(!foo) player = 0; + } + return 0; + } + return 1; + }); + class_name = lines[0]; + if( Classes[class_name] ) error("Class already exists"); + Classes[class_name] = cls; + lines = lines[1..]; + cls["Multis"] = ([]); + cls["Player"] = player; + 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) { + mapping s = ([]); + s["Average"] = to_int(tmp[2]); + s["SkillClass"] = to_int(tmp[1]); + cls["Skills"][tmp[0]] = s; + SKILLS_D->SetSkill(tmp[0], class_name, tmp[1]); + if( sizeof(lines) == 1 ) { + lines = ({}); + break; + } + else { + lines = lines[1..]; + } + } + cls["Complete"] = 1; + SaveObject(SaveFile); +} + +void RemoveClass(string class_name) { + validate(); + map_delete(Classes, class_name); + SaveObject(SaveFile); +} + +void SetClass(string class_name, mixed array args) { + mapping 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, mapping skill in cls["Skills"]) { + ots = ({ots..., ({ key, skill["Average"], skill["SkillClass"] })}); + } + args[1] = ots; +} + +void SetComplete(string class_name) { + mapping cls; + validate(); + if( !Classes[class_name] ) error("No such class"); + else cls = Classes[class_name]; + cls["Complete"] = 1; + SaveObject(SaveFile); +} + +varargs string *GetClasses(int player) { + string *ret; + if(player){ + ret = filter(keys(Classes), (: Classes[$1]["Complete"] && + Classes[$1]["Player"] :)); + } + else ret = filter(keys(Classes), (: Classes[$1]["Complete"] :)); + return ret; +} + +mixed GetClass(string str){ + return copy(Classes[str]); +} + +int GetPlayerClass(string str){ + if(!Classes[str]) return ; + return Classes[str]["Player"]; +} + +string GetHelp(string class_name) { + mapping 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, mapping s in cls["Skills"]) { + if( s["SkillClass"] == 1 ) { + help += "\t" + skill + "\n"; + } + } + return help + "\n"; +} diff --git a/lib/daemon/command.c b/lib/daemon/command.c new file mode 100644 index 0000000..a7f8413 --- /dev/null +++ b/lib/daemon/command.c @@ -0,0 +1,74 @@ +/* /daemon/command.c + * from the Dead Souls Object Library + * a new commands daemon, much faster than the old + * created by Descartes of Borg 940119 + */ + +#include <lib.h> +#include <dirs.h> +#include "include/command.h" + +inherit LIB_DAEMON; + +private static mapping Commands; +private static string *Paths; + +void create() { + daemon::create(); + SetNoClean(1); + 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) { + string path; + + if( stringp(paths) ) paths = ({ paths }); + else if( !pointerp(paths) ) return; + foreach(path in paths) { + string file; + + if( file_size(path) != -2 ) continue; + foreach(file in get_dir(path + "/*.c")) { + string cmd; + + cmd = file[0..<3]; + if( pointerp(Commands[cmd]) ) Commands[cmd] += ({ path }); + else Commands[cmd] = ({ path }); + } + Paths = distinct_array(Paths + ({ path })); + } +} + +string GetCommand(string cmd, string *path) { + string *tmp; + + if( Commands[cmd] && sizeof(tmp = (path & 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 & Commands[cmd])) ) + return sprintf("%s/%s", tmp[0], cmd); + } + return 0; +} + +varargs string *GetCommands(string path) { + string *paths, *tmp; + string cmd; + + if( !path ) return keys(Commands); + tmp = ({ }); + foreach( cmd, paths in Commands) + if( member_array(path, paths) != -1 ) tmp += ({ cmd }); + return tmp; +} + +varargs string *GetPaths(string cmd) { + if( cmd ) return Commands[cmd]; + else return Paths; +} diff --git a/lib/daemon/decay.c b/lib/daemon/decay.c new file mode 100644 index 0000000..0f1499f --- /dev/null +++ b/lib/daemon/decay.c @@ -0,0 +1,29 @@ +#include <lib.h> + +inherit LIB_DAEMON; + +void eventDecay(); + +static void create() { + daemon::create(); + SetNoClean(1); + call_out("eventDecay", 30); +} + +static void eventDecay() { + object *limbs; + object *corpses; + + call_out("eventDecay", 30); + + limbs = filter(findobs(LIB_LIMB), (: clonep($1) :) ); + corpses = filter(findobs(LIB_CORPSE), (: clonep($1) :) ); + + corpses += find_inheritors(LIB_CORPSE); + limbs += find_inheritors(LIB_LIMB); + + catch( limbs->eventDecay() ); + catch( corpses->eventDecay() ); + + return; +} diff --git a/lib/daemon/defines.c b/lib/daemon/defines.c new file mode 100644 index 0000000..bf11000 --- /dev/null +++ b/lib/daemon/defines.c @@ -0,0 +1,48 @@ +#include <lib.h> + +inherit LIB_DAEMON; +string file, contents, program, header; + +static void create() { + string *includes = ({}); + ::create(); + foreach(string str in get_dir("/secure/include/")){ + if(str == "object.h") continue; + if(last(str, 2) != ".h") continue; + includes += ({ "#include <"+str+">" }); + } + foreach(string str in get_dir("/include/")){ + includes += ({ "#include <"+str+">" }); + } + header = implode(includes,"\n")+"\n"; + header += "#ifndef $S\n#define $S \"DEFINED_D: undefined\"\n"; + header += "#endif\n"; + program = "\nmixed defcheck(){"+ + "\nint err;"+ + "\nmixed ret;"+ + "\nerr = catch( ret = $S );"+ + "\nif(err) ret = \"DEFINED_D: error\";"+ + "\nelse if(undefinedp(ret)) ret = \"DEFINED_D: undefined\";"+ + "\nreturn ret;"+ + "\n}"; + write_file("/open/prog.c",header+program,1); +} + +string GetDefine(string str){ + mixed tmpret, ret; + int err; + if(!str || !stringp(str) || grepp(str, "/") || grepp(str, ".")){ + return ret; + } + file = DIR_DAEMONS "/tmp/" + str + ".c"; + if( !unguarded((: file_exists($(file)) :)) ) { + contents = header+program; + contents = replace_string(contents,"$S",str); + unguarded((: write_file($(file), contents) :)); + } + err = catch( tmpret = file->defcheck() ); + if(err || (stringp(tmpret) && !strsrch(tmpret,"DEFINED_D:"))){ + } + else ret = tmpret; + return ret; +} diff --git a/lib/daemon/deviation.c b/lib/daemon/deviation.c new file mode 100644 index 0000000..8212962 --- /dev/null +++ b/lib/daemon/deviation.c @@ -0,0 +1,60 @@ +#include <lib.h> +#include <save.h> +#include <daemons.h> +#include <privs.h> + +inherit LIB_DAEMON; +static string SaveFile; +mapping StatDeviation = ([]); + +static void create() { + daemon::create(); + SaveFile = save_file(SAVE_DEVIATION); + SetSaveFile(SaveFile); + if(!file_exists(SaveFile) && file_exists(old_savename(SaveFile))){ + cp(old_savename(SaveFile), SaveFile); + } + RestoreObject(SaveFile); + if(sizeof(StatDeviation)){ + SaveObject(SaveFile); + } + call_out("SetDeviations", 10); +} + +float GetStatDeviation(int amount){ + float ret; + switch(amount){ + case 0 : ret = 0.0; break; + case 1 : ret = 0.22; break; + case 2 : ret = 0.44; break; + case 3 : ret = 0.66; break; + case 4 : ret = 0.88; break; + default : ret = 0.99; break; + } + return ret; +} + +varargs int GetDeviationCost(object who, int xp){ + int dev; + float fxp, subt; + string race; + if(!who || !xp) return 0; + race = who->GetRace(); + fxp = to_float(xp); + foreach(mixed key, mixed val in who->GetStatsMap()){ + if(!StatDeviation || !StatDeviation[key] || + StatDeviation[key][race]) continue; + dev = (StatDeviation[key][race] - val["class"]); + if(dev > 0){ + subt += (fxp * GetStatDeviation(dev)); + } + } + return to_int(subt); +} + +void SetDeviations(){ + mapping tmpmap = STATS_D->GetStats(); + if(sizeof(tmpmap)) StatDeviation = tmpmap; + SaveObject(SaveFile); +} + diff --git a/lib/daemon/disasters.c b/lib/daemon/disasters.c new file mode 100644 index 0000000..10ee0a1 --- /dev/null +++ b/lib/daemon/disasters.c @@ -0,0 +1,39 @@ +/* /daemon/distasters.c + * From Dead Souls LPMud + * Periodically searches for disasters that can happen to rooms + * Created by Descartes of Borg 961102 + * Version: @(#) disasters.c 1.3@(#) + * Last modified: 96/11/02 + */ + +#include <lib.h> + +inherit LIB_DAEMON; + +void checkDisaster(); + +static void create() { + daemon::create(); + SetNoClean(1); + call_out((: checkDisaster :), 300); +} + +static void checkDisaster() { + object array rooms = objects((: $1->GetMedium() :)); + int chance = 100 - random(100) + 1; + int count = 100; // check at most 100 rooms + + call_out((: checkDisaster :), 300); + if( chance == 100 ) { + return; + } + foreach(object room in rooms) { + count--; + if( room->eventDisaster(chance) ) { + return; + } + if( count < 1 ) { + return; + } + } +} diff --git a/lib/daemon/domains.c b/lib/daemon/domains.c new file mode 100644 index 0000000..32b2a49 --- /dev/null +++ b/lib/daemon/domains.c @@ -0,0 +1,27 @@ +/* /daemon/domains.c + * From the Dead Souls Object Library + * A daemon for handling domain stat information + * Created by Descartes of Borg 961110 + * Version: %A% + * Last modified: %D% + */ + +#include <lib.h> + +inherit LIB_DAEMON; + +class domain_stats { + int errors; + int moves; + int value; +} + +private mapping Stats = ([]); + +static void create() { + daemon::create(); + SetNoClean(1); +} + +void AddMove() { +} diff --git a/lib/daemon/ftp_port_tracker.c b/lib/daemon/ftp_port_tracker.c new file mode 100644 index 0000000..c853e1c --- /dev/null +++ b/lib/daemon/ftp_port_tracker.c @@ -0,0 +1,58 @@ +/* + ** ftp_port_tracker.c + ** Tracks which passive ports are being used by the FTP daemon. + ** + ** Created by Zaxan@Haven + */ + +#include <lib.h> + +#include "include/ftp_port_tracker.h" + +inherit LIB_DAEMON; + +static int array UsedPorts = ({ }); + +/* + ** Adds the specified port to the UsedPorts list. Returns + ** 1 on success, 0 on error. + */ +int AddUsedPort(int port) +{ + if(member_array(port, UsedPorts) != -1) return 0; + + + UsedPorts += ({ port }); + return 1; +} + +/* + ** Removes the specified port from the UsedPorts list. Returns + ** 1 on success, 0 on error. + */ +int RemoveUsedPort(int port) +{ + if(member_array(port, UsedPorts) == -1) return 0; + + UsedPorts -= ({ port }); + return 1; +} + +/* + ** Clears all ports from the UsedPorts list. + */ +void ClearUsedPorts() +{ + + UsedPorts = ({ }); +} + +/* + ** Returns a list of used ports. + */ +int array QueryUsedPorts() +{ + return UsedPorts; +} + + diff --git a/lib/daemon/guard.c b/lib/daemon/guard.c new file mode 100644 index 0000000..5bddb1b --- /dev/null +++ b/lib/daemon/guard.c @@ -0,0 +1,162 @@ +#include <lib.h> +#include <function.h> + +inherit LIB_DAEMON; + +mapping Guards = ([]); +mapping Guarded = ([]); +string *go_verbs = ({ "go", "crawl", "fly", "swim", "enter", "jump", + "boost" }); + +static void create() { + daemon::create(); + Guards = ([]); + Guarded = (["rooms" : ([]), "objects" : ([]), + "livings" : ([]) ]); + SetNoClean(1); +} + +varargs mixed AddGuard(object guard, mixed what, mixed action){ + string which; + if(!what || !objectp(guard) || interactive(guard)){ + return 0; + } + if(!objectp(what)){ + int err = catch( what = load_object(what) ); + if(err || !what) return -1; + } + + if(inherits(LIB_ROOM,what)) which = "rooms"; + else if(living(what)) which = "livings"; + else which = "objects"; + if(!Guarded[which]) Guarded[which] = ([]); + + if(Guards[guard] && member_array(what, keys(Guards[guard][which])) != -1){ + if(member_array(what, keys(Guarded[which])) != -1 && + member_array(guard, Guarded[which][what]) != -1){ + return -2; + } + } + if(!Guards[guard]){ + Guards[guard] = (["rooms" : ([]), "objects" : ([]), "livings" : ([]) ]); + } + Guards[guard][which][what] = (action || -1); + if(!Guarded[which][what]) Guarded[which][what] = ({}); + Guarded[which][what] += ({guard}); + Guarded[which][what] = distinct_array(Guarded[which][what]); + return 1; +} + +mapping GetGuards(){ + return copy(Guards); +} + +mapping GetGuardeds(){ + return copy(Guarded); +} + +varargs mixed GetGuard(object ob, string which){ + mixed ret; + if(!which && ob){ + if(inherits(LIB_ROOM,ob)) which = "rooms"; + if(living(ob)) which = "livings"; + else which = "objects"; + } + if(!Guarded[which] || !(ret = Guarded[which][ob])){ + return 0; + } + ret = filter(ret, (: $1 && objectp($1) :) ); + if(sizeof(ret)) return ret; + else return 0; +} + +varargs mixed GetGuarding(object guard, string which){ + mixed ret = ({}); + if(!Guards || !Guards[guard]){ + return 0; + } + foreach(mixed key, mixed val in Guards[guard]){ + ret += keys(val); + } + ret = filter(ret, (: $1 && objectp($1) :) ); + return ret; +} + +int ClearGuards(){ + if(!this_player() || !archp(this_player())) return 0; + Guards = ([]); + Guarded = ([ "livings" : ([]), "rooms" : ([]), "objects" : ([]) ]); + return 1; +} + +varargs int CheckMove(object who, mixed dest, mixed dir){ + mixed guards; + if(!objectp(dest)){ + int err = catch( dest = load_object(dest) ); + if(err || !dest) return 0; + } + if(!(guards = Guarded["rooms"][dest])){ + return 1; + } + + //This was meant to have guards only prevent "go" type movement, + //but it wound up allowing add_actions that should have been stopped. + //if(member_array(query_verb(),go_verbs) == -1) return 1; + + //Instead, we will assume that if a direction is specified by + //eventMoveLiving(), then it's a physical movement the guard + //should prevent. + if(!sizeof(dir)) return 1; + + guards = filter(guards, (: $1 && objectp($1) && environment($1) && + environment($1) == environment($(who)) :) ); + if(!sizeof(guards)){ + return 1; + } + foreach(object guard in guards){ + mixed f; + int x; + if(Guards[guard] && Guards[guard]["rooms"] && + Guards[guard]["rooms"][dest]){ + f = Guards[guard]["rooms"][dest]; + } + if(!(guard->AllowPass(who, dest))){ + if((x = functionp(f)) && !(x & FP_OWNER_DESTED)){ + evaluate(f,who); + } + else if(stringp(f)){ + who->eventPrint(f); + } + return 0; + } + } + return 1; +} + +varargs int CheckGet(object who, object what){ + mixed guards; + if(!(guards = Guarded["objects"][what])){ + return 1; + } + guards = filter(guards, (: $1 && objectp($1) && environment($1) && + environment($1) == environment($(who)) :) ); + if(!sizeof(guards)) return 1; + foreach(object guard in guards){ + mixed f; + int x; + if(Guards[guard] && Guards[guard]["objects"] && + Guards[guard]["objects"][what]){ + f = Guards[guard]["objects"][what]; + } + if(!(guard->AllowGet(who, what))){ + if((x = functionp(f)) && !(x & FP_OWNER_DESTED)){ + evaluate(f,who); + } + else if(stringp(f)){ + who->eventPrint(f); + } + return 0; + } + } + return 1; +} diff --git a/lib/daemon/help.c b/lib/daemon/help.c new file mode 100644 index 0000000..c7f349f --- /dev/null +++ b/lib/daemon/help.c @@ -0,0 +1,599 @@ +/* /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 + */ + +#include <lib.h> +#include <dirs.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +static private string Error, SeeAlso = ""; +static private mapping Indices; + +static private void LoadIndices(); +string GetHelp(string str); +string GetHelpByIndex(string index, string topic); +string GetTopic(string index, string topic); +varargs string array GetIndices(string topic); + +static void create() { + daemon::create(); + SetNoClean(1); + Error = 0; + LoadIndices(); +} + +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); + + case "builder commands": + return builderp(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_BUILDER_CMDS + "/*.c") + + //get_dir(DIR_BUILDER_CMDS + "/*.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_SECURE_BUILDER_CMDS + "/*.c") + + get_dir(DIR_BUILDER_VERBS + "/*.c") + + (get_dir(DIR_BUILDER_CMDS + "/*.c") || ({})); + Indices["builder commands"] = map(tmp, f); + + tmp = get_dir(DIR_UNDEAD_VERBS "/*.c"); + Indices["undead commands"] = map(tmp, f); + + 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 = CLASSES_D->GetClasses() ) + Indices["classes"] = tmp; + else Indices["classes"] = ({}); + + if( tmp = 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"] = ({}); + + if( tmp = get_dir(DIR_CONSTRUCTS_HELP "/") ) + Indices["lpc"] = tmp; + else Indices["lpc"] = ({}); + + if( tmp = get_dir(DIR_CONCEPTS_HELP "/") ) + Indices["lpc"] += tmp; + + 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, choice,ret =""; + 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(member_array(str, CHAT_D->GetChannels()) != -1 && + str != "newbie" && member_array(str, CLASSES_D->GetClasses()) == -1){ + return "See: help channels"; + } + if( sscanf(str, "adverbs %s", topic) || str == "adverbs" ) { + return SOUL_D->GetHelp(str); + } + tmp = GetIndices(str); + if( sizeof(tmp) > 0){ + if( sizeof(tmp) > 1){ + if(member_array("admin commands",tmp) != -1) choice = "admin commands"; + else if(member_array("creator commands",tmp) != -1) choice = "creator commands"; + else if(member_array("player commands",tmp) != -1) choice = "player commands"; + else if(member_array("builder commands",tmp) != -1) choice = "builder commands"; + } + if(!choice) choice = tmp[0]; + tmp -= ({ choice }); + + if(sizeof(tmp)) SeeAlso = "\nThere also exists help for \"" + str + "\" under the following " + "indices:\n" + implode(tmp, ", "); + ret = GetHelpByIndex(choice, str); + if(ret) ret += SeeAlso; + SeeAlso = ""; + return ret; + } + 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); + } + } + + if(this_player() && adminp(this_player())){ + Error = "Help for the topic \"" + str + "\" could not be found."; + } + else { + Error = "The search for help on the topic \"" + str + "\" yields you no results."; + } + 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": case "builder 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 "builder commands": + if( file_exists( DIR_BUILDER_VERBS + "/" + topic + ".c") ) + file = DIR_BUILDER_VERBS + "/" + topic; + else if( file_exists(DIR_BUILDER_CMDS + "/" + topic + ".c") ) + file = DIR_BUILDER_CMDS + "/" + topic; + else file = DIR_SECURE_BUILDER_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(); + write(SeeAlso); + SeeAlso = ""; + 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": case "lpc": + 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; + + case "lpc": + file = DIR_CONCEPTS_HELP "/" + topic; + if( !file_exists(file) ) + file = DIR_CONSTRUCTS_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( !file_exists(topic+".c") ){ + Error = "No such topic found."; + return 0; + } + 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( !topic || catch(help = topic->GetHelp(topic)) ) { + Error = "An error occurred in attempting to access help for that."; + 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 = RACES_D->GetHelp(topic) ) { + help = "Index: %^GREEN%^" + index + "%^RESET%^\n" + + "Topic: %^GREEN%^" + topic + "%^RESET%^\n\n" + help; + return help; + } + else if( file_exists(DIR_RACE_HELP + "/" + topic) ){ + help = read_file(DIR_RACE_HELP + "/" + topic); + return help; + } + Error = "There is no such race."; + 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 = 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); + } + topics = ({}); + foreach(ind, val in Indices) { + if( !CanAccess(this_player(), ind) ) { + continue; + } + tmp = GetTopic(ind, topic); + if( member_array(tmp, val) != -1 ) { + topics += ({ ind }); + } + } + return sort_array(topics, 1); +} + +string GetTopic(string index, string topic) { + string array dirlist; + string dir; + + if( index != "library objects" && index != "daemon objects" ) { + return topic; + } + if( index == "library objects" ) { + dirlist = ({ DIR_LIB, DIR_SECURE_LIB }); + } + else { + dirlist = ({ DIR_DAEMONS, DIR_SECURE_DAEMONS }); + } + if( strlen(topic) > 2 && topic[<2..] == ".c" ) { + topic = topic[0..<3]; + } + if( file_exists(topic + ".c") ) { + return topic; + } + foreach(dir in dirlist) { + if( file_exists(dir + "/" + topic + ".c") ) { + return dir + "/" + topic; + } + } + return 0; +} + +string array GetTopics(string index) { + string array topics = Indices[index]; + + if( !topics ) { + return 0; + } + else { + return sort_array(topics, 1); + } +} + +string GetLastError() { + return Error; +} + +void Reload() { + LoadIndices(); +} diff --git a/lib/daemon/include/bugs.h b/lib/daemon/include/bugs.h new file mode 100644 index 0000000..7cf4017 --- /dev/null +++ b/lib/daemon/include/bugs.h @@ -0,0 +1,13 @@ +#ifndef l_bugs_h +#define l_bugs_h + +static void create(); +int eventAssign(int bug, string who); +int eventComplete(int bug, string resolution); +int eventDelete(int bug); +int eventReport(string who, string type, string bug, string data); +int GetAssignedBugs(string who); +mapping GetBugs(); +string AddComment(int bug, string comment); + +#endif l_bugs_h diff --git a/lib/daemon/include/chat.h b/lib/daemon/include/chat.h new file mode 100644 index 0000000..347e44b --- /dev/null +++ b/lib/daemon/include/chat.h @@ -0,0 +1,14 @@ +#ifndef __CHAT_H__ +#define __CHAT_H__ + +static void create(); +string *eventRegisterMember(string *chans); +string *eventRemoveMember(string *chans); +int cmdChannel(string verb, string str); +varargs void eventSendChannel(string who, string ch, string msg, int emote, + string target, string targmsg); +string *GetChannelList(string ch); +string GetLocalChannel(string ch); +string GetRemoteChannel(string ch); + +#endif /* __CHAT_H__ */ diff --git a/lib/daemon/include/classes.h b/lib/daemon/include/classes.h new file mode 100644 index 0000000..b850460 --- /dev/null +++ b/lib/daemon/include/classes.h @@ -0,0 +1,15 @@ +#ifndef l_classes_h +#define l_classes_h + +class Skill { + int SkillClass; + int Average; +} + +class Class { + int Complete; + mapping Multis; + mapping Skills; +} + +#endif /* l_classes_h */ diff --git a/lib/daemon/include/command.h b/lib/daemon/include/command.h new file mode 100644 index 0000000..dc48bb8 --- /dev/null +++ b/lib/daemon/include/command.h @@ -0,0 +1,10 @@ +#ifndef __COMMAND_H__ +#define __COMMAND_H__ + +static void create(); +void eventRehash(mixed paths); +string GetCommand(string cmd, string *path); +varargs string *GetCommands(string path); +varargs string *GetPaths(string cmd); + +#endif /* __COMMAND_H__ */ diff --git a/lib/daemon/include/ftp_port_tracker.h b/lib/daemon/include/ftp_port_tracker.h new file mode 100644 index 0000000..d4932a1 --- /dev/null +++ b/lib/daemon/include/ftp_port_tracker.h @@ -0,0 +1,10 @@ +/* + * Created by Zaxan@Haven + */ + +int AddUsedPort(int port); +int RemoveUsedPort(int port); +void ClearUsedPorts(); +int array QueryUsedPorts(); + + diff --git a/lib/daemon/include/http.h b/lib/daemon/include/http.h new file mode 100644 index 0000000..da97c8c --- /dev/null +++ b/lib/daemon/include/http.h @@ -0,0 +1,9 @@ +#ifndef __HTTP_H__ +#define __HTTP_H__ + +static void create(); +static void Setup(); +static void eventRead(int fd, string str); +private static void eventGetFile(int fd, string file); + +#endif /* __HTTP_H__ */ diff --git a/lib/daemon/include/intermud.h b/lib/daemon/include/intermud.h new file mode 100644 index 0000000..1f274c1 --- /dev/null +++ b/lib/daemon/include/intermud.h @@ -0,0 +1,18 @@ +#ifndef l_intermud_h +#define l_intermud_h + +static void create(); +static void Setup(); +static void eventRead(mixed *packet); +static void eventSocketClose(); +static void eventConnectionFailure(); +int SetDestructOnClose(int x); +int SetSocketType(int x); +string GetMudName(string mud); +mapping GetMudList(); +string *GetMuds(); +mapping GetChannelList(); +string *GetMatch(string mud); +string GetNameserver(); + +#endif /* l_intermud_h */ diff --git a/lib/daemon/include/news.h b/lib/daemon/include/news.h new file mode 100644 index 0000000..fe01a47 --- /dev/null +++ b/lib/daemon/include/news.h @@ -0,0 +1,14 @@ +#ifndef l_news_h +#define l_news_h + +void GeneralNews(); +static void NewbieNews(); +static void ClassNews(string cl); +static void HighMortalNews(); +static void AvatarNews(); +static void CreatorNews(); +static void AdminNews(); +static void EndNews(); +string GetNews(string type); + +#endif /* l_news_h */ diff --git a/lib/daemon/include/notify.h b/lib/daemon/include/notify.h new file mode 100644 index 0000000..73d2888 --- /dev/null +++ b/lib/daemon/include/notify.h @@ -0,0 +1,14 @@ +#ifndef __NOTIFY_H__ +#define __NOTIFY_H__ + +#define Date 0 +#define Author 1 +#define Message 2 + +static void create(); +static int eventSaveNotices(); +int eventAddNotice(object who, string msg); +int eventRemoveNotice(int x); +int eventPrintNotices(object who, int start_time); + +#endif diff --git a/lib/daemon/include/party.h b/lib/daemon/include/party.h new file mode 100644 index 0000000..c5bf7ac --- /dev/null +++ b/lib/daemon/include/party.h @@ -0,0 +1,27 @@ +#ifndef l_party_h +#define l_party_h + +class party { + object Leader; + object *Members; + object *Invited; +} + +static void create(); +mixed CanChangeLeader(object who, object targ); +mixed CanCreateParty(object who, string name); +mixed CanInviteMember(object who, object member); +mixed CanJoinParty(object who, string pname); +mixed CanRemoveMember(object who, object targ); +mixed CanRemoveParty(object who); +mixed eventChangeLeader(object who, object targ); +mixed eventCreateParty(object who, string name); +mixed eventInviteMember(object who, object member); +mixed eventJoinParty(object who, string name); +mixed eventRemoveMember(object who, object targ); +mixed eventRemoveParty(object who); +object GetPartyLeader(string name); +object *GetPartyMembers(string name); +static void RemoveInvitiation(string name, object who); + +#endif /* l_party_h */ diff --git a/lib/daemon/include/seasons.h b/lib/daemon/include/seasons.h new file mode 100644 index 0000000..0670c45 --- /dev/null +++ b/lib/daemon/include/seasons.h @@ -0,0 +1,56 @@ +#ifndef __SEASONS_H__ +#define __SEASONS_H__ + +class month { + string Name; + string Season; + int Days; + int DaylightHours; +} + +class moon { + string Name; + int Phase; + string Id; + string Description; + string Color; +} + +static void create(); +static void eventConfigure(); +static void eventDawn(); +static void eventMorning(); +static void eventNoon(); +static void eventTwilight(); +static void eventNight(); +static void eventMidnight(); +int GetCurrentDay(); +string GetCurrentDayName(); +string GetCurrentMonth(); +string GetCurrentSeason(); +int GetCurrentTime(); +int GetCurrentYear(); +varargs int GetDay(int x); +varargs string GetDayName(int x); +string *GetDays(); +int GetDaylightHours(string mon); +varargs int GetHour(int x); +varargs int GetMinutes(int x); +string GetMonth(int x); +private varargs int GetMonthIndex(int x); +string *GetMonths(); +string GetSeason(int x); +varargs int GetTime(int x); +string GetTimeOfDay(); +function AddTimeEvent(string tod, function f); +mapping GetTimeEvents(); +varargs int GetYear(int x); +string GetYearString(int x); +string GetPhaseName(int x); +int GetPhase(string m); +int GetMoonLight(); +string GetLong(string arg); + +#endif /* __SEASONS_H__ */ + + diff --git a/lib/daemon/include/stargate.h b/lib/daemon/include/stargate.h new file mode 100644 index 0000000..9455c9d --- /dev/null +++ b/lib/daemon/include/stargate.h @@ -0,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 --git a/lib/daemon/include/statistics.h b/lib/daemon/include/statistics.h new file mode 100644 index 0000000..9a253b5 --- /dev/null +++ b/lib/daemon/include/statistics.h @@ -0,0 +1,7 @@ +#ifndef l_statistics_h +#define l_statistics_h + +mixed eventKill(object target); +mapping GetKills(string who); + +#endif /* l_statistics_h */ diff --git a/lib/daemon/include/time.h b/lib/daemon/include/time.h new file mode 100644 index 0000000..df8f833 --- /dev/null +++ b/lib/daemon/include/time.h @@ -0,0 +1,14 @@ +#ifndef __TIME_H__ +#define __TIME_H__ + +class timezone { + int Offset; + string Name; +} + +static void create(); +int GetOffset(string tzone); +string GetName(string tzone); +string *GetTimeZones(); + +#endif /* __TIME_H__ */ diff --git a/lib/daemon/include/verbs.h b/lib/daemon/include/verbs.h new file mode 100644 index 0000000..8d8ae85 --- /dev/null +++ b/lib/daemon/include/verbs.h @@ -0,0 +1,9 @@ +#ifndef l_verbs_h +#define l_verbs_h + +static void create(); +varargs void eventReloadVerbs(mixed val); +int GetValidVerb(string str); +string GetHelp(string str); + +#endif /* l_verbs_h */ diff --git a/lib/daemon/intermud.c b/lib/daemon/intermud.c new file mode 100644 index 0000000..b9925c1 --- /dev/null +++ b/lib/daemon/intermud.c @@ -0,0 +1,530 @@ +/* /daemon/intermud.c + * from the Dead Souls LPC Library + * daemon handling the InterMUD-3 Protocol + * created by Descartes of Borg 950506 + * Version: @(#) intermud.c 1.7@(#) + * Last modified: 96/12/14 + */ + +#ifndef __PACKAGE_SOCKETS__ +#error You should not try and load /daemon/intermud.c with no sockets package. +#else + +#include <lib.h> +#include <dirs.h> +#include <logs.h> +#include <privs.h> +#include <save.h> +#include <daemons.h> +#include <commands.h> +#include NETWORK_H +#include ROOMS_H +#include "include/intermud.h" + +inherit LIB_CLIENT; + +static private int Password; +private mapping MudList, ChannelList; +private mapping Banned; +private mixed *Nameservers; +private static int Tries; +private static int SocketStat = -1; +private static int Online = 0; +private static string my_ip; +static string SaveFile; + +mapping ExtraInfo(); +void ConvertLists(); +int GetStatus(string mud); +static mixed SetStatus(string mud, int status); + +static void create(){ + client::create(); + Password = SECRETS_D->GetSecret("I3_SERVER_PW"); + SaveFile = save_file(SAVE_INTERMUD); + tn("INTERMUD_D: prev: "+identify(previous_object(-1)),"red"); + Tries = 0; + Banned = ([]); + MudList = ([]); + ChannelList = ([]); + MudList["ID"] = -1; + MudList["List"] = ([]); + ChannelList["ID"] = -1; + ChannelList["List"] = ([]); + if(file_exists(SaveFile)){ + RestoreObject(SaveFile, 1); + } + ConvertLists(); + Nameservers = ({ ({ "*dalet", "97.107.133.86 8787" }) }); + SetNoClean(1); + tn("INTERMUD_D reloaded."); + tn("Loading object stack: "+get_stack(),"red"); + tn("Loading object trail: "+identify(previous_object(-1)),"red"); + SetDestructOnClose(1); + SetSocketType(MUD); + if(DISABLE_INTERMUD == 1){ + call_out( (: eventDestruct :), 2); + } + else call_out( (: Setup :), 2); +} + +void FirstPing(){ + PING_D->eventPing(); +} + +static void Setup(){ + string ip; + int port; + + if( !Nameservers || !sizeof(Nameservers) ) return; + sscanf(Nameservers[0][1], "%s %d", ip, port); + SocketStat = eventCreateSocket(ip, port); + if( SocketStat < 0 ) return; + tn("INTERMUD_D: SocketStat: "+SocketStat); + 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, + SERVICES_D->GetServices(), ExtraInfo() }) ); + 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, + SERVICES_D->GetServices(), ([]) }) ), "red");; + call_out( (: FirstPing :), 5); + call_out( (: load_object :), 5, IMC2_D); +} + +int GetConnectedStatus(){ + return Online; +} + +void eventClearVars(){ + if( !(master()->valid_apply(({ PRIV_ASSIST, INTERMUD_D }))) ) + error("Illegal attempt to reset intermud: "+get_stack()+" "+identify(previous_object(-1))); + Tries = 0; + MudList = ([]); + ChannelList = ([]); + MudList["ID"] = -1; + MudList["List"] = ([]); + ChannelList["ID"] = -1; + ChannelList["List"] = ([]); + SaveObject(SaveFile); +} + +static void eventRead(mixed *packet){ + mixed val; + string cle; + int mudpacket; + Online = 1; + + 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 "+mud_name()+".", + packet })); + + return; + } + switch(packet[0]){ + case "startup-reply": + LOG_D->LogSpecial(LOG_I3,timestamp()+" "+identify(packet)+"\n"); + 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; + } + /* Start of Tricky's patch */ + if( packet[2] != Nameservers[0][0] ){ + tn("Illegal startup-reply from mud " + packet[2], "red"); + return; + } + /* End of Tricky's patch */ + if( packet[6][0][0] == Nameservers[0][0] ){ + Nameservers = packet[6]; + Password = packet[7]; + SECRETS_D->SetSecret("I3_SERVER_PW", Password); + SaveObject(SaveFile); + } + else { + Nameservers = packet[6]; + Setup(); + } + return; + case "mudlist": + tn("INTERMUD_D mudlist received.","red"); + //log_file(LOG_I3,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]){ + string tmp = ""; + if(cle){ + string lib = "unknown"; + if(val && sizeof(val) > 5 && arrayp(val)){ + if(!my_ip && cle == mud_name()) my_ip = val[1]; + lib = val[5]; + } + MUDINFO_D->ReceiveMudInfo(cle, val); + tmp += "%^BOLD%^CYAN%^Processing mud: "+identify(cle)+ + ", lib: "+lib; + if(val){ + if(!val[0]) tmp += " %^RED%^BOLD%^offline%^RESET%^"; + else tmp += " %^GREEN%^BOLD%^ONLINE%^RESET%^"; + } + else tmp += " removed from mudlist"; + tn(tmp); + //tn(tmp,"cyan",ROOM_ARCH); + if(val && sizeof(val) > 5 && arrayp(val)) + tmp = (val[0] ? "%^BLUE%^online" : "%^RED%^offline")+ + "%^RESET%^, lib: "+lib+", driver: "+val[7]; + else tmp = "removed from mudlist."; + CHAT_D->eventSendChannel(cle+"@i3","muds",tmp,0); + } + if( !val && MudList["List"][cle] != 0 ) + map_delete(MudList["List"], cle); + else if( val ) MudList["List"][cle] = val; + } + SaveObject(SaveFile); + return; + 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); + CHAT_D->RemoveRemoteChannel(cle); + } + else if( val ){ + ChannelList["List"][cle] = val; + CHAT_D->AddRemoteChannel(cle); + } + } + SaveObject(SaveFile); + SERVICES_D->eventRegisterChannels(packet[7]); + return; + case "ping-req": + mudpacket = 1; + SERVICES_D->eventReceiveAuthRequest(packet); + break; + case "ping-reply": + mudpacket = 1; + SERVICES_D->eventReceiveAuthReply(packet); + break; + case "auth-mud-req": + mudpacket = 1; + SERVICES_D->eventReceiveAuthRequest(packet); + break; + case "auth-mud-reply": + mudpacket = 1; + SERVICES_D->eventReceiveAuthReply(packet); + break; + case "channel-t": + mudpacket = 1; + SERVICES_D->eventReceiveChannelTargettedEmote(packet); + break; + case "channel-e": + mudpacket = 1; + SERVICES_D->eventReceiveChannelEmote(packet); + break; + case "channel-m": + mudpacket = 1; + SERVICES_D->eventReceiveChannelMessage(packet); + break; + case "chan-who-reply": + mudpacket = 1; + SERVICES_D->eventReceiveChannelWhoReply(packet); + break; + case "chan-who-req": + mudpacket = 1; + SERVICES_D->eventReceiveChannelWhoRequest(packet); + break; + case "chan-user-req": + mudpacket = 1; + SERVICES_D->eventReceiveChannelUserRequest(packet); + break; + case "emoteto": + mudpacket = 1; + SERVICES_D->eventReceiveEmote(packet); + break; + case "finger-req": + mudpacket = 1; + SERVICES_D->eventReceiveFingerRequest(packet); + break; + case "finger-reply": + mudpacket = 1; + SERVICES_D->eventReceiveFingerReply(packet); + break; + case "locate-req": + mudpacket = 1; + SERVICES_D->eventReceiveLocateRequest(packet); + break; + case "locate-reply": + mudpacket = 1; + SERVICES_D->eventReceiveLocateReply(packet); + break; + case "tell": + mudpacket = 1; + SERVICES_D->eventReceiveTell(packet); + break; + case "chan-user-reply": + mudpacket = 1; + tn("INTERMUD_D: chan-user-reply received.","red"); + case "ucache-update": + mudpacket = 1; + SERVICES_D->eventReceiveUcacheUpdate(packet); + break; + case "who-req": + mudpacket = 1; + SERVICES_D->eventReceiveWhoRequest(packet); + break; + case "who-reply": + mudpacket = 1; + SERVICES_D->eventReceiveWhoReply(packet); + break; + case "news": + mudpacket = 1; + SERVICES_D->eventReceiveNews(packet); + break; + case "mail": + mudpacket = 1; + SERVICES_D->eventReceiveMail(packet); + break; + case "mail-ok": + mudpacket = 1; + SERVICES_D->eventReceiveMailOk(packet); + break; + case "file": + mudpacket = 1; + tn("INTERMUD_D: file packet received.","red"); + break; + case "error": + SERVICES_D->eventReceiveError(packet); + break; + default: + break; + } + if(mudpacket){ + if(!GetStatus(packet[2])){ + tn("Setting status of "+packet[2]+" to online."); + SetStatus(packet[2], -1); + } + } +} + +static void eventSocketClose(){ + Online = 0; +} + +static void eventConnectionFailure(){ + Online = 0; + tn("INTERMUD_D: CONNECTION FAILED","red"); + error("Failed to find a useful name server.\n"); +} + +int SetDestructOnClose(int x){ return 0; } + +static void eventClose(mixed arg){ + SocketStat = -1; + Online = 0; + tn("INTERMUD_D: socket closing!"); + ::eventClose(arg); +} + +int SetSocketType(int x){ return client::SetSocketType(MUD); } + +string GetMudName(string mud){ + string *lc, *uc; + mapping mudses = GetMudList(); + int x; + + 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 ){ + foreach(string name in GetMuds()){ + if(mudses[name][1] +" "+mudses[name][2] == mud) return name; + } + return 0; + } + else return uc[x]; +} + +static mixed SetStatus(string mud, int status){ + mapping mlist = copy(MudList["List"]); + mixed array newmud = ({}); + if(!sizeof(newmud = mlist[mud])) return 0; + tn("old: "+identify(newmud)); + newmud[0] = status; + MudList["List"][mud] = newmud; + tn("new: "+identify(MudList["List"][mud]),"blue"); +} + +int GetStatus(string mud){ + mixed array newmud = ({}); + if(!sizeof(newmud = MudList["List"][mud])) return 0; + return (newmud[0] ? 1 : 0); +} + +mapping GetMudList(){ + if(sizeof(MudList) && MudList["List"]) + return copy(MudList["List"]); + else return ([]); +} + +string *GetMuds(){ + if(sizeof(MudList) && MudList["List"]) + return keys(MudList["List"]); + else return ({}); +} + +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; + SaveObject(SaveFile); + return 1; +} + +mapping GetBanned(){ return copy(Banned); } + +int RawSend(string *packet){ + if(!this_player() || !archp(this_player())) return 0; + eventWrite(packet); + return 1; +} + +string nextboot(){ + string str; + int x, offset; + + if(DISABLE_REBOOTS){ + return "never"; + } + + offset = TIME_D->GetOffset(local_time()[9]); + offset += EXTRA_TIME_OFFSET; + + x = EVENTS_D->GetRebootInterval() * 3600; + x = (time() - uptime()) + x; + if(!LOCAL_TIME) + x += offset * 3600; + str = query_tz()+ " " + ctime(x); + return str; +} + +//This new packet element data added to be able +//to handle liveupgrade stuff more sensibly. +mapping ExtraInfo(){ + return ([ + "native version" : native_version(), + "os build" : query_os_type(), + "architecture" : architecture(), + "upsince" : ctime(time() - uptime()), + "next boot" : nextboot(), + "ip" : HOST_IP, + "oob port" : PORT_OOB, + ]); +} + +void ConvertLists(){ + if(classp(MudList)){ + mapping TmpMap = ([]); + MudList = TmpMap; + MudList["ID"] = -1; + MudList["List"] = ([]); + SaveObject(SaveFile); + } + if(classp(ChannelList)){ + mapping TmpMap = ([]); + ChannelList = TmpMap; + ChannelList["ID"] = -1; + ChannelList["List"] = ([]); + SaveObject(SaveFile); + } +} + +int GetEnabled(){ + return !(DISABLE_INTERMUD); +} + +string GetMyIp(){ + string ret = "127.0.0.1"; + if(my_ip) ret = my_ip; + return ret; +} + +void eventWrite(mixed val){ + object prev = previous_object(); + if(!prev || prev == this_object() + || prev == find_object(PING_D) + || prev == find_object(SERVICES_D) + || prev == find_object(CMD_CHANBAN) + || prev == find_object(CMD_CHANCREATE) + || prev == find_object(CMD_CHANREMOVE) + || prev == find_object(CMD_CHANUNBAN)){ + ::eventWrite(val); + } +} + +static void eventSocketError(string str, int x) { + //debug_message(timestamp()+" i3 "+socket_error(x) + "\n"); + if(query_os_type() == "windows" && grepp(socket_error(x), "Problem with connect")){ + load_object("/secure/cmds/admins/mudconfig")->cmd("intermud disable"); + } +} +#endif /* __PACKAGE_SOCKETS__ */ diff --git a/lib/daemon/map.c b/lib/daemon/map.c new file mode 100644 index 0000000..0280561 --- /dev/null +++ b/lib/daemon/map.c @@ -0,0 +1,261 @@ +#include <lib.h> +#include <daemons.h> +#include <save.h> +#define FLOW_DEBUGGING 0 +#ifndef MAP_CACHE +#define MAP_CACHE 1 +#endif + +inherit LIB_DAEMON; +mapping MapMap, MapCache; +static int heart_count = 1, sweepflag, roomcount, caching = 0; +static string SaveFile; +static string *sweeprooms = ({}); + +void create(){ +#if WIZMAP + SaveFile = save_file(SAVE_MAP); + if(!file_exists(SaveFile) && file_exists(old_savename(SaveFile))){ + cp(old_savename(SaveFile), SaveFile); + } + if(file_exists(SaveFile)){ + RestoreObject(SaveFile, 1); + } + set_heart_beat(1); +#endif +} + +void zero(){ + MapMap = ([]); + MapCache = ([]); + SaveObject(SaveFile, 1); +} + +void heart_beat(){ + if(!(heart_count % 900)){ //Every 15 minutes save the cache + SaveObject(SaveFile, 1); + } + if(!(heart_count % 64800)){ //Every 18 hours refresh the cache + if(!sweepflag){ + sweepflag = 1; + sweeprooms = keys(MapMap); + } + } + if(sweepflag){ + if(sizeof(sweeprooms) <= roomcount){ + sweepflag = 0; + roomcount = 0; + return; + } + if(MapMap[sweeprooms[roomcount]]["name"]){ + this_object()->GetMap(MapMap[sweeprooms[roomcount]]["name"], 8, 1); + } + else { + map_delete(MapMap, sweeprooms[roomcount]); + map_delete(MapCache, sweeprooms[roomcount]); + } + roomcount++; + } + heart_count++; +} + +int eventDestruct(){ + SaveObject(SaveFile, 1); + return daemon::eventDestruct(); +} + +int RemoveCache(string str){ + if(MapCache && MapCache[str]){ + MapCache[str] = 0; + return 1; + } + return 0; +} + +int SetCaching(int x){ + if(x) caching = 1; + else caching = 0; + return caching; +} + +int GetCaching(){ + return caching; +} + +varargs mixed GetMap(mixed args, int size, int forced){ +#if WIZMAP + string ret = ""; + int i,x,line,tempy,tmpres, res = size; + mapping Lines = ([]); + mapping myspot; + string mycoords; + mapping start; + if(!(MASTER_D->GetPerfOK())){ + return ret; + } + if(!size) size = 4; + if(size > 15 && !creatorp(this_player())) size = 6; + if(!args) args = base_name(environment(this_player())); + if(objectp(args)) args = base_name(args); + myspot=ROOMS_D->GetGridMap(args); + if(!myspot) return 0; + mycoords = myspot["coord"]; + res = size; + if(!MapCache) MapCache = ([]); + if(!myspot["coords"] || ( mycoords == "0,0,0" && + ROOMS_D->GetRoomZero() != args )){ + ret = "%^RED%^Map unavailable.%^RESET%^"; + return ret; + } + if(!forced && caching && MapCache[mycoords]){ + return MapCache[mycoords]; + } + start = ([ "x" : myspot["coords"]["x"] - (res/2), + "y" : myspot["coords"]["y"] + (res/2), + "z" : myspot["coords"]["z"] ]); + if(!MapMap) MapMap = ([]); + if(sizeof(MapMap) >= 64000) MapMap = ([]); + for(tempy = start["y"]; tempy > start["y"] - res; tempy--){ + mapping ppos = ([]); + int xcount; + line+=2; + for(tmpres = start["x"];tmpres < start["x"] + res;tmpres++){ + string room, coord = tmpres+","+tempy+","+start["z"]; + mixed tmp = ROOMS_D->GetGrid(coord); + xcount+=2; + if(tmp){ + room = tmp["room"]; + MapMap[coord] = ([ "name" : room ]); + } + + if(!Lines[line]){ + string pre = (tempy > -1 ? " " : ""); + Lines[line] = pre + (tempy % 10) + repeat_string(" ",60); + } + if(!Lines[line+1]){ + Lines[line+1] = " " + repeat_string(" ",60); + } + if(!Lines[line-1]){ + Lines[line-1] = " " + repeat_string(" ",60); + } + if(MapMap[coord]){ + mapping gridmap; + mapping dirs; + object croom; + if(!MapMap[coord]["name"]) continue; + gridmap = ROOMS_D->GetGridMap(MapMap[coord]["name"]); + if(!sizeof(gridmap)) continue; + if(gridmap["exits"]) dirs = gridmap["exits"]; + if(mycoords == coord){ + Lines[line][xcount+2] = '@'; + } + else { +#if FLOW_DEBUGGING + object flow; + croom = find_object(MapMap[coord]["name"]); + if(croom && flow = present("flow",croom)){ + int press = flow->GetPressure(); + if(press == 1) Lines[line][xcount+2] = '1'; + if(press == 2) Lines[line][xcount+2] = '2'; + if(press == 3) Lines[line][xcount+2] = '3'; + if(press == 4) Lines[line][xcount+2] = '4'; + if(press > 4) Lines[line][xcount+2] = '5'; + } + else Lines[line][xcount+2] = '#'; +#else + Lines[line][xcount+2] = '#'; +#endif + } + Lines[line][xcount+3] = ' '; + if(sizeof(dirs)){ + foreach(string dir in keys(dirs)){ + switch(dir){ + case "north" : + if(Lines[line-1]) + Lines[line-1][xcount+2] = '|'; + break; + case "south" : + if(Lines[line+1]) + Lines[line+1][xcount+2] = '|'; + break; + case "east" : + Lines[line][xcount+3] = '-'; + break; + case "west" : + Lines[line][xcount+1] = '-'; + break; + case "northeast" : + if(Lines[line-1]){ + if(Lines[line-1][xcount+3] == '\\') + Lines[line-1][xcount+3] = 'X'; + else + Lines[line-1][xcount+3] = '/'; + } + break; + case "northwest" : + if(Lines[line-1]){ + if(Lines[line-1][xcount+1] == '/') + Lines[line-1][xcount+1] = 'X'; + else + Lines[line-1][xcount+1] = '\\'; + } + break; + case "southeast" : + if(Lines[line+1]){ + if(Lines[line+1][xcount+3] == '/') + Lines[line+1][xcount+3] = 'X'; + else + Lines[line+1][xcount+3] = '\\'; + } + break; + case "southwest" : + if(Lines[line+1]){ + if(Lines[line+1][xcount+1] == '\\') + Lines[line+1][xcount+1] = 'X'; + else + Lines[line+1][xcount+1] = '/'; + } + break; + } + } + } + } + else { + } + } + xcount = 0; + } + if(line == size * 2 ){ + int xcount = size; + string pre; + x = start["x"]-1; + Lines[line] = repeat_string(" ",60); + Lines[line+1] = " "; + while(xcount){ + x++; + if(x < 0) pre = "-"; + else pre = " "; + Lines[line+1] += pre + abs((x % 10)); + xcount--; + } + Lines[line+2] = repeat_string("+2",30); + } + + for(i = sizeof(Lines), x = 0;x < i;x++){ + if(Lines[x]) ret += Lines[x]+"\n"; + } + ret = replace_string(ret,"@","%^RED%^@%^RESET%^"); +#if FLOW_DEBUGGING + ret = replace_string(ret,"1","%^GREEN%^A%^RESET%^"); + ret = replace_string(ret,"2","%^YELLOW%^B%^RESET%^"); + ret = replace_string(ret,"3","%^CYAN%^C%^RESET%^"); + ret = replace_string(ret,"4","%^BLUE%^D%^RESET%^"); + ret = replace_string(ret,"5","%^MAGENTA%^F%^RESET%^"); +#endif + MapCache[mycoords] = ret; + return ret; +#else + /* Wizmapping not enabled in config.h */ + return ""; +#endif +} diff --git a/lib/daemon/meetings.c b/lib/daemon/meetings.c new file mode 100644 index 0000000..85473c3 --- /dev/null +++ b/lib/daemon/meetings.c @@ -0,0 +1,15 @@ +#include <lib.h> +#include <save.h> + +inherit LIB_DAEMON; +string savefile = SAVE_MEETINGS; +mapping schedule = ([]); + +static void create() { + daemon::create(); + RestoreObject(savefile,1); +} + +mapping GetScheduleMapping(){ + return copy(schedule); +} diff --git a/lib/daemon/news.c b/lib/daemon/news.c new file mode 100644 index 0000000..311e155 --- /dev/null +++ b/lib/daemon/news.c @@ -0,0 +1,244 @@ +/* /daemon/news.c + * from the Dead Souls Object Library + * responsible for leading players through news + * created by Descartes of borg 951104 + */ + +#include <lib.h> +#include <news.h> +#include "include/news.h" + +inherit LIB_DAEMON; + +object ThisPlayer(){ + object ret = previous_object(); + if(ret && interactive(ret)) return ret; + else ret = this_player(); + return ret; +} + +void GeneralNews() { + object player = ThisPlayer(); + if( file_exists(NEWS_GENERAL) ) { + int s; + + s = stat(NEWS_GENERAL)[1]; + if( s != player->GetNews("general") ) { + string news; + + news = GetNews("general"); + player->SetNews("general", s); + message("news", "\n%^RED%^General news:", player); + player->eventPrint(news); + message("prompt", "Press <return> to continue: ", player); + if( !(player->GetClass()) && !creatorp(player) ) + input_to((: NewbieNews :)); + else input_to((: ClassNews, "" :)); + return; + } + } + if( !(player->GetClass()) && !creatorp(player) ) + NewbieNews(); + else ClassNews(""); +} + +static void NewbieNews() { + object player = ThisPlayer(); + if( file_exists(NEWS_NEWBIE) ) { + string news; + + news = GetNews("newbie"); + message("news", "\n%^RED%^Newbie news:", player); + message("news", news, player); + message("prompt", "Press <return> to continue: ", player); + input_to((: ClassNews, "" :)); + return; + } + ClassNews(""); +} + +void ClassNews(string cl) { + object player = ThisPlayer(); + 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; + } + } + if( player->ClassMember(cl) && file_exists(DIR_NEWS "/"+cl) ) { + int s; + + s = stat(DIR_NEWS "/" + cl)[1]; + if( s != player->GetNews(cl) ) { + string news; + + news = GetNews(cl); + player->SetNews(cl, s); + message("news", "\n%^RED%^" + capitalize(cl) + " news:", + player); + message("news", news, player); + message("prompt", "Press <return> to continue: ", player); + input_to( (: ClassNews, cl :)); + return; + } + } + ClassNews(cl); +} + +static void HighMortalNews() { + object player = ThisPlayer(); + if( high_mortalp(player ) && file_exists(NEWS_HM) ) { + int s; + + s = stat(NEWS_HM)[1]; + if( s != player->GetNews("hm") ) { + string news; + + news = GetNews("hm"); + player->SetNews("hm", s); + message("news", "\n%^RED%^High mortal news:", player); + message("news", news, player); + message("prompt", "Press <return> to continue: ", player); + input_to( (: AvatarNews :)); + return; + } + } + AvatarNews(); +} + +static void AvatarNews() { + object player = ThisPlayer(); + if( avatarp(player ) && file_exists(NEWS_AVATAR) ) { + int s; + + s = stat(NEWS_AVATAR)[1]; + if( s != player->GetNews("avatar") ) { + string news; + + news = GetNews("avatar"); + player->SetNews("avatar", s); + message("news", "\n%^RED%^Avatar news:", player); + message("news", news, player); + message("prompt", "Press <return> to continue: ", player); + input_to( (: CreatorNews :)); + return; + } + } + CreatorNews(); +} + +static void CreatorNews() { + object player = ThisPlayer(); + if( creatorp(player ) && file_exists(NEWS_CREATOR) ) { + int s; + + s = stat(NEWS_CREATOR)[1]; + if( s != player->GetNews("creator") ) { + string news; + + news = GetNews("creator"); + player->SetNews("creator", s); + message("news", "\n%^RED%^Creator news:", player); + message("news", news, player); + message("prompt", "Press <return> to continue: ", player); + input_to( (: AdminNews :)); + return; + } + } + AdminNews(); +} + +static void AdminNews() { + object player = ThisPlayer(); + if(archp(player ) && file_exists(NEWS_ADMIN) ) { + int s; + + s = stat(NEWS_ADMIN)[1]; + if( s != player->GetNews("admin") ) { + string news; + + news = GetNews("admin"); + player->SetNews("admin", s); + message("news", "\n%^RED%^Admin news:", player); + message("news", news, player); + message("prompt", "Press <return> to continue: ", player); + input_to( (: EndNews :)); + return; + } + } + EndNews(); +} + +static void EndNews() { + object player = ThisPlayer(); + if(player) player->eventDescribeEnvironment(); +} + +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; + } + if( !file_exists(file) ) return "No " + type + " news."; + file = read_file(file) || ("No " + type + " news."); + return file; +} + + + + + + diff --git a/lib/daemon/notify.c b/lib/daemon/notify.c new file mode 100644 index 0000000..c977be6 --- /dev/null +++ b/lib/daemon/notify.c @@ -0,0 +1,80 @@ +/* /daemon/notify.c + * 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" +#define MaxTime (3600 * 24 * 60) + +inherit LIB_DAEMON; + +private mixed * Notes; +static string SaveFile; + +static void create() { + int x; + daemon::create(); + SaveFile = save_file(SAVE_NOTIFY); + SetNoClean(1); + Notes = ({}); + if( unguarded((: file_exists(SaveFile) :) ) ){ + RestoreObject(SaveFile); + } + x = sizeof(Notes); + while( sizeof(Notes) && (time() - Notes[0][Date]) > MaxTime ) + Notes -= ({ Notes[0] }); + if( x != sizeof(Notes) ) eventSaveNotices(); + SaveObject(SaveFile); +} + +static int eventSaveNotices() { + if( !archp(this_player()) ) return 0; + else return SaveObject(SaveFile); +} + +int eventAddNotice(object who, string msg) { + object * obs; + if( !who || !sizeof(msg) ) return 0; + Notes += ({ ({ time(), who->GetName(), msg }) }); + if( sizeof(obs = filter(users() - ({ who }), (: creatorp :))) ) + obs->eventPrint("["+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; + Notes -= ({ Notes[x] }); + 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); + int x = y - 1; + 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; + int x = sizeof(Notes) - 1; + if( !archp(this_player()) ) return 0; + 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 --git a/lib/daemon/party.c b/lib/daemon/party.c new file mode 100644 index 0000000..1dbaea3 --- /dev/null +++ b/lib/daemon/party.c @@ -0,0 +1,278 @@ +/* /daemon/party.c + * from the Dead Souls Object Library + * manages parties + * created by Descartes of Borg 951120 + */ + +#include <lib.h> +#include <save.h> +#include <daemons.h> +#include <message_class.h> +#include "include/party.h" + +inherit LIB_DAEMON; + +mapping Parties; +static string SaveFile; +string *old_parties; + +static void create() { + daemon::create(); + SaveFile = save_file(SAVE_PARTIES); + Parties = ([]); + old_parties = ({}); + if( unguarded((: file_exists(SaveFile) :)) ){ + RestoreObject(SaveFile); + } + SetNoClean(1); + this_object()->eventCleanParties(); + set_heart_beat(60); + SaveObject(SaveFile); +} + +static void eventDestroyParty(string party){ + if(!party || !Parties[party]) return; + foreach(mixed member in this_object()->GetPartyMembers(party)){ + if(member){ + member->SetParty(0); + } + } + if(member_array(party, CHAT_D->GetLocalChannels()) != -1){ + CHAT_D->eventSendChannel("System", party, "The party " + party + + " has been disbanded."); + CHAT_D->RemoveLocalChannel(party); + } + map_delete(Parties, party); + old_parties = distinct_array( (old_parties || ({})) + ({ party }) ); + SaveObject(SaveFile); +} + +string *GetOldParties(){ + return sort_array((copy(old_parties || ({})) - keys(Parties || ([]))),1); +} + +static void eventCleanParties(){ + foreach(mixed key, mixed val in Parties){ + mixed array members = this_object()->GetPartyMembers(key); + members -= ({ 0 }); + if(!sizeof(members)) eventDestroyParty(key); + } +} + +void heart_beat(){ + eventCleanParties(); +} + +mixed array GetParties(){ + return keys(Parties); +} + +mapping GetPartiesMap(){ + return copy(Parties); +} + +mixed CanChangeLeader(object who, object targ) { + class party p; + string pname; + + 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 targ->GetName() + " is not in the party."; + SaveObject(SaveFile); + return 1; +} + +mixed CanCreateParty(object who, string name) { + string *tmpnames = ( CHAT_D->GetChannels() || ({}) ); + tmpnames += ({ "party", "lemon" }); + if( Parties[name] ) return "A party by that name already exists."; + if( member_array(name, tmpnames) != -1 ) + return "You cannot use the name " + name + " for your party."; + if( who->GetParty() ) return "You are already in a party!"; + eventSave(); + return 1; +} + +mixed CanInviteMember(object who, object member) { + string pname; + + pname = 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( member->GetParty() ) + return member->GetName() + " is already in a party."; + if( environment(member) != environment(who) ) + return 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( 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; +} + +mixed CanLeaveParty(object who) { + class party p; + string pname; + + pname = 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; +} + +mixed CanRemoveMember(object who, object targ) { + class party p; + string pname; + + pname = 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) { + class party p; + string pname; + + pname = 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; +} + +mixed eventChangeLeader(object who, object targ) { + class party p; + string pname; + + pname = who->GetParty(); + p = Parties[pname]; + p->Leader = targ; + CHAT_D->eventSendChannel("System", pname, targ->GetName() + " is now " + "the leader."); + SaveObject(SaveFile); + return 1; +} + +mixed eventCreateParty(object who, string name) { + class party this_party; + + if( 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 }); + this_party->Invited = ({}); + Parties[name] = this_party; + who->eventPrint("Party " + name + " successfully created.", MSG_SYSTEM); + SaveObject(SaveFile); + return 1; +} + +mixed eventInviteMember(object who, object targ) { + class party this_party; + string name; + + name = who->GetParty(); + this_party = Parties[name]; + this_party->Invited += ({ targ }); + CHAT_D->eventSendChannel("System", name, 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); + SaveObject(SaveFile); + 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( who->SetParty(name) != name ) + return "Bogus error in joining party."; + this_party->Invited -= ({ who }); + this_party->Members += ({ who }); + CHAT_D->eventSendChannel("System", name, who->GetName() + + " has joined the party."); + SaveObject(SaveFile); + return 1; +} + +mixed eventLeaveParty(object who) { + mixed ret = eventRemoveMember(who, who); + SaveObject(SaveFile); + return ret; +} + +mixed eventRemoveMember(object who, object targ) { + class party p; + object ob = 0; + string name; + + p = Parties[name = who->GetParty()]; + if( targ == p->Leader ) { + if( sizeof(p->Members) == 1 ) return eventRemoveParty(who); + else { + foreach(ob in p->Members) if( ob != targ ) break; + if( !ob ) return eventRemoveParty(who); + else { + p->Leader = ob; + ob->eventPrint("You are now the leader of the party " + name + + ".", MSG_SYSTEM); + } + } + } + targ->SetParty(0); + if( Parties[name] ) { + p->Members -= ({ targ }); + CHAT_D->eventSendChannel("System", name, targ->GetName() + + " is no longer in the party."); + } + targ->eventPrint("You are no longer a member of the party " + name + + ".", MSG_SYSTEM); + SaveObject(SaveFile); + return 1; +} + +mixed eventRemoveParty(object who) { + string name = who->GetParty(); + eventDestroyParty(name); + return 1; +} + +object GetPartyLeader(string name) { + class party p; + string nom; + + foreach(nom, p in Parties) if( nom == name ) return p->Leader; + return 0; +} + +object *GetPartyMembers(string name) { + class party p; + string nom; + + foreach(nom, p in Parties) if( nom == name ) return p->Members; + return 0; +} + +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 --git a/lib/daemon/phys.c b/lib/daemon/phys.c new file mode 100644 index 0000000..347fa35 --- /dev/null +++ b/lib/daemon/phys.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mapping Momentum = ([]); + +void create(){ + if(!Momentum) Momentum = ([]); +} + +#if 0 +varargs int AddMomentum(object what, object from, object to, int speed){ + int x1, y1, z1, x2, y2, z2; + int a, b; + if(previous_object() != what) return 0; + if(from == to) return 0; + if(!from || !to || !speed) return 0; + a = sscanf(ROOMS_D->GetCoordinates(from,"%d,%d,%d",x1,y1,z1); + b = sscanf(ROOMS_D->GetCoordinates(to,"%d,%d,%d",x2,y2,z2); + if(a < 3 || b < 3) return 0; + if(x1 == x2 && y1 == y2 && z1 == z2) return 0; + if(!Momentum[what]) Momentum[what] = ([ "dir" : 0, "speed" : 0 ]); + newdir = bearing(x1, y1, x2, y2); + olddir = Momentum[what]["dir"]; + oldspeed = Momentum[what]["speed"]; +#endif + + + diff --git a/lib/daemon/races.c b/lib/daemon/races.c new file mode 100644 index 0000000..99ee6f7 --- /dev/null +++ b/lib/daemon/races.c @@ -0,0 +1,632 @@ +/* /daemon/race.c + * from the Dead Souls Object Library + * 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 <cfg.h> +#include <save.h> +#include <daemons.h> +#include <privs.h> +#include <armor_types.h> +#include <mouth_types.h> +#include <size_types.h> + +inherit LIB_DAEMON; + +private mapping Races = ([]); +static private mapping Resistances = ([]); +static private mapping Armors = ([]); +static private mapping Sizes = ([]); +static private mapping Btypes = ([]); +string array FlyingRaces = ({}); +string array LimblessCombatRaces = ({}); +string array LimblessRaces = ({}); +string array NonBitingRaces = ({}); +string array SwimmingRaces = ({}); +string array NonMeatRaces = ({}); +static string SaveFile; + +static void ReloadRaces(){ + string *races = get_dir(CFG_RACES+"/"); + Races = ([]); + foreach(string race in races){ + string str = CFG_RACES+"/"+race; + if(file_exists(str)) { + catch( this_object()->AddRace(str) ); + } + } +} + +static void create() { + daemon::create(); + SaveFile = save_file(SAVE_RACES); + if(file_exists(SaveFile)){ + RestoreObject(SaveFile); + } + if( !sizeof(Races) ) ReloadRaces(); + if(!FlyingRaces) FlyingRaces = ({}); + if(!LimblessCombatRaces) LimblessCombatRaces = ({}); + if(!LimblessRaces) LimblessRaces = ({}); + if(!NonBitingRaces) NonBitingRaces = ({}); + if(!Resistances) Resistances = ([]); + if(!Armors) Armors = ([]); + if(!Sizes) Sizes = ([]); + if(!Btypes) Btypes = ([]); + if(!SwimmingRaces) SwimmingRaces = ({}); + if(!NonMeatRaces) NonMeatRaces = ({}); + SaveObject(SaveFile); +} + +static private void validate() { + if( !(master()->valid_apply(({ PRIV_ASSIST }))) ) + 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 CanSwim(string str){ + if( !Races[str] ) return 0; + if(member_array(str, SwimmingRaces) != -1) return 1; + else return 0; +} + +int GetNonMeatRace(string str){ + if(member_array(str,NonMeatRaces) == -1) return 0; + else return 1; +} + +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 SetNonMeatRace(string str){ + if(member_array(str,NonMeatRaces) != -1) return 0; + NonMeatRaces += ({ lower_case(str) }); + 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){ + FlyingRaces += ({ str }); + return 1; +} + +int SetNonBitingRace(string str){ + NonBitingRaces += ({ str }); + return 1; +} + +int SetSwimmingRace(string str){ + SwimmingRaces += ({ str }); + return 1; +} + +int GetSwimmingRace(string str){ + if(member_array(str,SwimmingRaces) != -1) return 1; + else return 0; +} + +string *GetNonMeatRaces(){ + return copy(NonMeatRaces); +} + +string *GetSwimmingRaces(){ + return copy(SwimmingRaces); +} + +string *GetLimblessCombatRaces(){ + return copy(LimblessCombatRaces); +} + +string *GetLimblessRaces(){ + return copy(LimblessRaces); +} + +string *GetFlyingRaces(){ + return copy(FlyingRaces); +} + +int GetBitingRace(string str){ + if(member_array(str,NonBitingRaces) == -1) return 1; + else return 0; +} + +int RemoveRaceVars(string str){ + if(previous_object() != this_object()) return 0; + FlyingRaces -= ({ str }); + LimblessCombatRaces -= ({ str }); + LimblessRaces -= ({ str }); + NonBitingRaces -= ({ str }); + NonBitingRaces -= ({ str }); + SwimmingRaces -= ({ str }); + return 1; +} + +int GetRaceMass(string str){ + int Mass = Races[str]["Mass"]; + if(Mass) return Mass; + else return 0; +} + +int GetRaceSize(string str){ + int Size; + Size = Races[str]["Size"]; + if(Size) return Size; + else return 0; +} + +int GetRaceBodyType(string str){ + int Btype = Races[str]["Btype"]; + if(Btype) return Btype; + else return 0; +} + +int GetRaceRespirationType(string str){ + int Rtype = Races[str]["Rtype"]; + if(Rtype) return Rtype; + else return 0; +} +int GetRaceMouthType(string str){ + int Mtype = Races[str]["Mouthtype"]; + if(Mtype) return Mtype; + else return 0; +} + +mapping GetRace(string str){ + mapping ret = Races[str] + ([]); + return ret; +} + +void AddRace(string file, int player) { + mapping res; + string array tmp, parts; + string race, test_string; + int x; + mixed array limb = allocate(4); + mixed array tmp_limb = allocate(4); + mapping s; + + res = ([]); + + res["Resistance"] = ([]); + res["Skills"] = ([]); + res["Stats"] = ([]); + res["Limbs"] = ({}); + res["Mass"] = 0; + res["Size"] = 0; + res["Btype"] = 0; + res["Rtype"] = 0; + res["Mouthtype"] = 0; + + validate(); + + if( !file_exists(file) ) error("No such file: " + file); + race = last_string_element(file,"/"); + + res["Fingers"] = ([]); + + + foreach(string line in explode(read_file(file),"\n")){ + mixed *tmp_vision; + test_string = first_string_element(line," "); + if(!test_string || !sizeof(test_string)) test_string = line; + + switch(test_string){ + string type = ""; + + case "FLYING_RACE": + line = trim(replace_string(line, "FLYING_RACE", "")); + if(sizeof(line) && atoi(line) < 1) break; + else SetFlyingRace(race); + break; + + case "NOT_MEAT": + line = trim(replace_string(line, "NOT_MEAT", "")); + if(sizeof(line) && atoi(line) < 1) break; + else SetNonMeatRace(race); + break; + + case "LIMBLESS_RACE": + line = trim(replace_string(line, "LIMBLESS_RACE", "")); + if(sizeof(line) && atoi(line) < 1) break; + else SetLimblessRace(race); + break; + + case "LIMBLESS_COMBAT_RACE": + line = trim(replace_string(line, "LIMBLESS_COMBAT_RACE", "")); + if(sizeof(line) && atoi(line) < 1) break; + else SetLimblessCombatRace(race); + break; + + case "NONBITING_RACE": + line = trim(replace_string(line, "NONBITING_RACE", "")); + if(sizeof(line) && atoi(line) < 1) break; + else SetNonBitingRace(race); + break; + + case "SWIMMING_RACE": + line = trim(replace_string(line, "SWIMMING_RACE", "")); + if(sizeof(line) && atoi(line) < 1) break; + else SetSwimmingRace(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 ", ""); + tmp_vision = map(explode(line, ":"), (: to_int :)); + res["Sensitivity"] = ({ tmp_vision[0], tmp_vision[1] * 10 }); + break; + + case "PLAYER_RACE": + line = replace_string(line, "PLAYER_RACE ", ""); + if(player || atoi(line) > 0) player = 1; + else player = 0; + 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 = this_object()->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] }); + SKILLS_D->SetSkill(tmp[0], race, tmp[2], 1); + break; + + case "MASS": + x = 0; + sscanf(line, "MASS %d",x); + if(x) res["Mass"] = x; + break; + + case "SIZE": + type = ""; + x = 0; + if(sscanf(line, "SIZE %s",type)) res["Size"] = this_object()->GetSize(type); + else res["Size"] = x; + break; + + case "BODY_TYPE": + type = ""; + x = 0; + if(sscanf(line, "BODY_TYPE %s",type)) res["Btype"] = this_object()->GetBodyType(type); + else res["Btype"] = x; + break; + + case "RESPIRATION_TYPE": + type = ""; + x = 0; + if(sscanf(line, "RESPIRATION_TYPE %s",type)) res["Rtype"] = this_object()->GetRespirationType(type); + else res["Rtype"] = x; + break; + + case "STATS": + tmp = ({}); + s = ([]); + 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; + STATS_D->SetStat(tmp[0], race, s["Class"]); + break; + + case "MOUTH": + type = ""; + x = 0; + if(sscanf(line, "MOUTH %s",type)){ + res["Mouthtype"] = this_object()->GetMouthType(type); + } + 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 this_object()->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; + SaveObject(SaveFile); +} + +void RemoveRace(string race) { + validate(); + map_delete(Races, race); + RemoveRaceVars(race); + if(Races[race]) + SaveObject(SaveFile); +} + +string ConvertPipe(string str){ + str = replace_string(str," ",""); + str = replace_string(str,"|","+"); + return str; +} + +int GetArmor(string foo) { + string str = ConvertPipe(foo); + 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 GetSize(string foo) { + string str = ConvertPipe(foo); + string file = DIR_DAEMONS "/tmp/" + str + ".c"; + + if( !unguarded((: file_exists($(file)) :)) ) { + unguarded((: write_file($(file), "#include <size_types.h>\n" + + "int size() { return " + $(str) + "; }\n") :)); + } + return call_other(file, "size"); +} + +int GetBodyType(string foo) { + string str = ConvertPipe(foo); + string file = DIR_DAEMONS "/tmp/" + str + ".c"; + + if( !unguarded((: file_exists($(file)) :)) ) { + unguarded((: write_file($(file), "#include <body_types.h>\n" + + "int btype() { return " + $(str) + "; }\n") :)); + } + return call_other(file, "btype"); +} + +int GetRespirationType(string foo) { + string str = ConvertPipe(foo); + string file = DIR_DAEMONS "/tmp/" + str + ".c"; + + if( !unguarded((: file_exists($(file)) :)) ) { + unguarded((: write_file($(file), "#include <respiration_types.h>\n" + + "int rtype() { return " + $(str) + "; }\n") :)); + } + return call_other(file, "rtype"); +} + +int GetMouthType(string foo) { + string str = ConvertPipe(foo); + string file = DIR_DAEMONS "/tmp/" + str + ".c"; + + if( !unguarded((: file_exists($(file)) :)) ) { + unguarded((: write_file($(file), "#include <mouth_types.h>\n" + + "int mtype() { return " + $(str) + "; }\n") :)); + } + return call_other(file, "mtype"); +} + +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, mapping res in foo) { + mapping stats = ([]); + + mp[race] = ([]); + mp[race]["limbs"] = res["Limbs"]; + mp[race]["resistance"] = res["Resistance"]; + + foreach(string stat, mapping 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) { + mapping res; + + validate(); + + if( !Races[race] ) error("No such race"); + else res = Races[race]; + res["Complete"] = 1; + SaveObject(SaveFile); +} + +void SetLightSensitivity(string race, int array sensitivity) { + mapping 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; + SaveObject(SaveFile); +} + +void SetCharacterLimbs(string race, mixed array args) { + mapping 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) { + mapping 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) { + mapping res = Races[race]; + + if( !res["Complete"] ) return 0; + if( player_only && !res["PlayerFlag"] ) + return 0; + return 1; + }, player_only); +} + +string GetHelp(string race) { + mapping 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 = distinct_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 --git a/lib/daemon/seasons.c b/lib/daemon/seasons.c new file mode 100644 index 0000000..0bd09ae --- /dev/null +++ b/lib/daemon/seasons.c @@ -0,0 +1,592 @@ +/* /daemon/seasons.c + * from the Dead Souls LPC Library + * handles game-based time + * created by Descartes of Borg 950508 + * Version: @(#) seasons.c 1.7@(#) + * Last modified: 96/10/27 + */ + +#include <lib.h> +#include <cfg.h> +#include <function.h> +#include "include/seasons.h" + +inherit LIB_DAEMON; + +private static int CurrentDay, CurrentYear; +private static int Dawn, Morning, Noon, Twilight, Night; +private static int ticktock, pending; +private static string CurrentSeason, TimeOfDay; +private static mapping Moons; +private static class month CurrentMonth; +private static string *Days; +private static function *DawnCalls, *MorningCalls, *NoonCalls; +private static function *TwilightCalls, *NightCalls, *MidnightCalls; +private static class month *Months; + +int eventTickTock(int tick){ + if(!this_player() || !archp(this_player())) return 0; + if(!tick) tick = 0; + ticktock = tick; + remove_call_out(pending); + eventConfigure(); + //return GetCurrentTime()/1200; + return GetCurrentTime(); +} + +int GetTickTock(){ return ticktock; } + +int *GetMudTime(){ + //return ({ GetHour(GetCurrentTime()), GetMinutes(GetCurrentTime()) }); + return ({ GetHour(time()+ticktock), GetMinutes(time()+ticktock) }); +} + +static void create() { + string *lines; + int i, maxi; + + daemon::create(); + 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(); +} + +static void eventConfigure() { + int i, x, days, tot, maxi; + + DawnCalls = ({}); + MorningCalls = ({}); + NoonCalls = ({}); + TwilightCalls = ({}); + NightCalls = ({}); + MidnightCalls = ({}); + + days = GetTime(time()+ticktock) / (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; + Noon = (DAY_LENGTH * HOUR_LENGTH) / 2; + 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"; + pending = call_out( (: eventDawn :), Dawn - x); + } + else if( x < Morning ) { + TimeOfDay = "dawn"; + pending = call_out( (: eventMorning :), Morning - x); + } + else if( x < Noon ) { + TimeOfDay = "day"; + pending = call_out( (: eventNoon :), Noon - x); + } + else if( x < Twilight ) { + TimeOfDay = "day"; + pending = call_out( (: eventTwilight :), Twilight - x); + } + else if( x < Night ) { + TimeOfDay = "twilight"; + pending = call_out( (: eventNight :), Night - x ); + } + else { + TimeOfDay = "night"; + pending = call_out( (: eventMidnight :), (DAY_LENGTH * HOUR_LENGTH) - x); + } +} + +static void eventDawn() { + object *obs; + int i; + + pending = call_out( (: eventMorning :), Morning - GetCurrentTime() ); + TimeOfDay = "dawn"; + obs = filter(users(), (: environment($1) && + environment($1)->GetClimateExposed() && + inherits(LIB_ROOM,environment($1)) && + !(environment($1)->GetProperty("no time")) :)); + message("environment", + "%^YELLOW%^The sun appears just over the horizon.%^RESET%^", + obs ); + i = sizeof(DawnCalls); + while(i--) catch(evaluate(DawnCalls[i])); +} + +static void eventMorning() { + object *obs; + int i; + + pending = call_out( (: eventNoon :), Noon - GetCurrentTime()); + TimeOfDay = "day"; + obs = filter(users(), (: environment($1) && + environment($1)->GetClimateExposed() && + inherits(LIB_ROOM,environment($1)) && + !(environment($1)->GetProperty("no time")) :)); + message("environment", "%^BOLD%^YELLOW%^The sun now shines completely " + "on a new day.%^RESET%^", obs); + i = sizeof(MorningCalls); + while(i--) catch(evaluate(MorningCalls[i])); +} + +static void eventNoon() { + int i; + pending = call_out( (: eventTwilight :), Twilight - GetCurrentTime()); + TimeOfDay = "day"; + i = sizeof(NoonCalls); + while(i--) catch(evaluate(NoonCalls[i])); +} + +static void eventTwilight() { + object *obs; + int i; + + pending = call_out( (: eventNight :), Night - GetCurrentTime() ); + TimeOfDay = "twilight"; + obs = filter(users(), (: environment($1) && + environment($1)->GetClimateExposed() && + inherits(LIB_ROOM,environment($1)) && + !(environment($1)->GetProperty("no time")) :)); + message("environment", "%^CYAN%^The sun begins to fall away into " + "twilight.%^RESET%^", obs); + i = sizeof(TwilightCalls); + while(i--) catch(evaluate(TwilightCalls[i])); +} + +static void eventNight() { + object *obs; + int i,x; + + pending = call_out( (: eventMidnight :), + (DAY_LENGTH * HOUR_LENGTH) - GetCurrentTime() ); + TimeOfDay = "night"; + obs = filter(users(), (: environment($1) && + environment($1)->GetClimateExposed() && + inherits(LIB_ROOM,environment($1)) && + !(environment($1)->GetProperty("no time")) :)); + message("environment", + "%^BOLD%^BLUE%^Night darkens all that is real.%^RESET%^", obs); + i = sizeof(NightCalls); + while(i--){ + mixed f = NightCalls[i]; + if((x = functionp(f)) && !(x & FP_OWNER_DESTED)){ + catch(evaluate(f)); + } + } +} + +static void eventMidnight() { + int i; + + 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; + } + pending = call_out( (: eventDawn :), Dawn); + TimeOfDay = "night"; + i = sizeof(MidnightCalls); + while(i--) catch(evaluate(MidnightCalls[i])); +} + +int GetCurrentDay() { return CurrentDay; } + +string GetCurrentDayName() { return GetDayName(time()+ticktock); } + +string GetCurrentMonth() { return CurrentMonth->Name; } + +string GetCurrentSeason() { return CurrentSeason; } + +// get seconds from the start of the day. +int GetCurrentTime() { return GetTime(time()+ticktock) % (DAY_LENGTH * HOUR_LENGTH); } + +int GetCurrentYear() { return CurrentYear; } + +varargs int GetDay(int x) { + int tot, days, i, maxi; + + if(!x) x = time()+ticktock; + days = absolute_value(GetTime(x) / (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; +} + +varargs string GetDayName(int x) { + int days; + + if(!x) x = time()+ticktock; + days = absolute_value(GetTime(x) / (DAY_LENGTH * HOUR_LENGTH)); + return Days[days % sizeof(Days)]; +} + +string *GetDays() { return Days + ({}); } + +int GetDaylightHours(string mon) { + int i; + + i = sizeof(Months); + while(i--) { + if( ((class month)Months[i])->Name == mon ) + return ((class month)Months[i])->DaylightHours; + } + return 0; +} + +varargs int GetHour(int x) { + int y; + + if(!x) + x = time()+ticktock; + y = absolute_value(GetTime(x)); + y = y % (DAY_LENGTH * HOUR_LENGTH); + if( x < DAY_ONE ) y = (DAY_LENGTH * HOUR_LENGTH) - y; + return (y / HOUR_LENGTH); +} + +varargs int GetMinutes(int x) { + int y; + + if(!x) + x = time()+ticktock; + y = absolute_value(GetTime(x)); + y = y % (DAY_LENGTH * HOUR_LENGTH); + if( x < DAY_ONE ) y = (DAY_LENGTH * HOUR_LENGTH) - y; + return (y % HOUR_LENGTH) / (HOUR_LENGTH/60); +} + +string GetMonth(int x) { + int monthIndex; + + monthIndex = GetMonthIndex(x); + return Months[monthIndex]->Name; +} + +private varargs int GetMonthIndex(int x) { + int tot, days, i, maxi; + + if(!x) x = time()+ticktock; + if( x < DAY_ONE ) days = (DAY_ONE - x) / (DAY_LENGTH * HOUR_LENGTH); + else days = GetTime(x) / (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; +} + +string *GetMonths() { + string *ret = ({}); + 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; +} + +varargs int GetTime(int x) { if(!x) x = time()+ticktock; return (x - DAY_ONE); } + +string GetTimeOfDay() { return TimeOfDay; } + +function AddTimeEvent(string tod, function f) { + switch(tod) { + case "dawn": DawnCalls += ({ f }); break; + case "morning": MorningCalls += ({ f }); break; + case "noon": NoonCalls += ({ 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 + ({}), + "noon" : NoonCalls + ({}), "twilight" : TwilightCalls + ({}), + "night" : NightCalls + ({}), "midnight" : MidnightCalls + ({}) ]); +} + +varargs int GetYear(int x) { + int i, tot; + + if(!x) x = time()+ticktock; + i = sizeof(Months); + while(i--) tot += ((class month)Months[i])->Days; + i = (GetTime(x) / (DAY_LENGTH * HOUR_LENGTH)) / tot; + if( x < DAY_ONE ) return i; + else return i + 1; +} + +string GetYearString(int x) { + if( x < 0 ) return (x * (-1)) + " BN"; + else return x + " NM"; +} + + +/* + * Moon functions + */ +string array GetMoons() { + return map(keys(Moons), (: ((class moon)Moons[$1])->Name :)); +} + +string GetPhaseName(mixed val) { + if( stringp(val) ) { + val = GetPhase(val); + } + switch(val) { + case 0: return "new"; + case 1: return "waxing"; + case 2: return "waning"; + case 3: return "full"; + default: return "error"; + } +} + +int GetPhase(string m) { + int x, y, z; + + m = convert_name(m); + x = ((class moon)Moons[m])->Phase; + y = GetTime(time()+ticktock) % x; + z = x / 4; + return y / z; +} + +int GetRadiantLight() { + switch( TimeOfDay ) { + case "night": return (GetMoonLight() * 2); + case "day": return 60; + default: return 30; + } +} + +int GetMoonLight() { + string *moons; + int i, y = 0; + + i = sizeof(moons = keys(Moons)); + while(i--) { + int z; + + z = GetPhase(moons[i]); + if( z == 4) z = 2; + y += z; + } + return y; +} + +string GetLong(string arg) { + string array arr, mn; + object env; + string tmp; + 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])) == 0 ) continue; + else if( tmp ) + tmp += (((class moon)Moons[moons[i]])->Name) + + " is " + GetPhaseName(y) + ".\n"; + else tmp = "\n" + + "You gaze up at the sky, and see the moons...\n"+ + (((class moon)Moons[moons[i]])->Name) + + " is " + + GetPhaseName(y) + ".\n"; + 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), + (: living($1) && + !$1->GetInvis(this_player()) :)); + /* function(object ob) { */ + /* if( ob->GetInvis(this_player()) ) { */ + /* return 0; */ + /* } */ + /* if( living(ob) ) { */ + /* return 1; */ + /* } */ + /* return 0; */ + /* }); */ + + if( sizeof(obs) ) { + int maxi = sizeof(obs); + + sky = obs[i]->GetName(); + if( maxi == 1 ) { + sky += " is flying in the sky."; + } + else { + for(i=1; i<maxi; i++) { + if( i == maxi-1 ) { + if( maxi == 2 ) { + sky += " and "; + } + else { + sky += ", and "; + } + } + else { + sky += ", "; + } + sky += obs[i]->GetName(); + } + sky += " are flying in the sky."; + } + 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; + } +} + +int eventShow(object who, string args) { + string str; + if( !who || !sizeof(args) ) return 0; + if( !str = GetLong(args) ) return 0; + if( !environment(who)->GetClimateExposed() ) { + who->eventPrint("You can't see that from here!"); + return 1; + } + who->eventPrint(str); + environment(who)->eventPrint(who->GetName() + " gazes toward the sky.", who); + return 1; +} diff --git a/lib/daemon/services.c b/lib/daemon/services.c new file mode 100644 index 0000000..79868a7 --- /dev/null +++ b/lib/daemon/services.c @@ -0,0 +1,93 @@ +/* /daemon/services.c + * from the Dead Souls LPC Library + * handles intermud services + * created by Descartes of Borg 950523 + * Version: @(#) services.c 1.3@(#) + * Last modified: 96/12/14 + */ + +#ifndef __PACKAGE_SOCKETS__ +#error You should not try to load /daemon/services.c without the sockets package +#else + +#include <lib.h> +#include <save.h> +#include NETWORK_H + +inherit LIB_DAEMON; + +mapping GetServices(); + +#include "/daemon/services/channel.c" +#include "/daemon/services/emoteto.c" +#include "/daemon/services/error.c" +#include "/daemon/services/finger.c" +#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); + daemon::create(); + SetNoClean(1); +#ifdef SERVICE_UCACHE + call_out((: eventCompactUcache :), 3600); +#endif + eventSave(); +} + +int eventDestruct() { + eventSave(); + return daemon::eventDestruct(); +} + +mapping GetServices() { + string *ports = ({ "ftp", "http", "oob", "nntp", "rcp", "smtp" }); + mapping ret = ([ +#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 + ]); + + foreach(string port in ports){ + if(member_array(port, keys(INET_D->GetServices())) != -1){ + ret[port] = INET_D->GetServicePort(port); + } + } + + if(ret["oob"]) ret["mail"] = 1; + return ret; +} + +#endif /* __PACKAGE_SOCKETS__ */ diff --git a/lib/daemon/services/auth.c b/lib/daemon/services/auth.c new file mode 100644 index 0000000..db388c7 --- /dev/null +++ b/lib/daemon/services/auth.c @@ -0,0 +1,49 @@ +#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") :) ); + OOB_D->ReceivedToken(packet[2],packet[6]); + 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 = ""; + string header = "auth-mud-reply"; + int token = random_numbers(9,1); + PING_D->SetOK(); + tn(packet[0]+" received from "+packet[2]+".","white"); + if(packet[0] == "ping-req") header = "ping-reply"; + INTERMUD_D->eventWrite( ({header, 5, mud_name(), 0, packet[2], + 0, token }) ); + OOB_D->SentToken(packet[2],token); + if(file_exists("/tmp/muds.txt")) + mudlist = read_file("/tmp/muds.txt"); + if((!grepp(mudlist,packet[2]) || packet[2] == "DeadSoulsNew" || + packet[2] == "DeadSoulsWin") && packet[2] != mud_name()){ + write_file("/tmp/muds.txt",packet[2]+"\n"); + tn("We have a new mud! "+packet[2]+" has joined intermud.","red"); + } +} + +void eventSendAuthRequest(string target){ + INTERMUD_D->eventWrite(({ "auth-mud-req", 5, mud_name(), 0, target, 0 })); +} diff --git a/lib/daemon/services/channel.c b/lib/daemon/services/channel.c new file mode 100644 index 0000000..1c4bb78 --- /dev/null +++ b/lib/daemon/services/channel.c @@ -0,0 +1,229 @@ +/* /daemon/services/channel.c + * from the Dead Souls LPC Library + * handles intermud channels using the Intermud 3 protocols + * created by Descartes of Borg 950625 + * Version: @(#) channel.c 1.2@(#) + * Last modified: 96/12/14 + */ + +#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; + + PING_D->SetOK(); + tn("eventReceiveChannelWhoReply: "+identify(packet),"green"); + + if( file_name(previous_object()) != INTERMUD_D ) return; + if( !(ob = find_player(packet[5])) ) return; + packet[6] = 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 = ""; + PING_D->SetOK(); + if( file_name(previous_object()) != INTERMUD_D ) return; + who = 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; + PING_D->SetOK(); + 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 = ob->GetCapName(); + switch( 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) { + PING_D->SetOK(); + 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) { + PING_D->SetOK(); + 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; + PING_D->SetOK(); + 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 ) { + targpl = convert_name(target); + 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) { + string pl; + + pl = 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) { + mixed array val; + string channel, ns; + + if( file_name(previous_object()) != INTERMUD_D ) return; + ns = INTERMUD_D->GetNameserver(); + foreach(channel, val in list) { + if( !val ) continue; + if( member_array(channel, CHAT_D->GetLocalChannels()) == -1){ + INTERMUD_D->eventWrite(({ "channel-listen", 5, mud_name(), 0, ns, + 0, channel, 1 })); + //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, 0 })); + } + tn("eventRegisterChannels: "+identify(list),"green"); + +} + +int eventAdministerChannel(string channel, string array additions, + string array subs) { + tn("eventAdministerChannel. ","green"); + + if( !(master()->valid_apply( ({}) )) ) return 0; + if( member_array(channel, INTERMUD_D->GetChannels()) == -1 ) + return 0; + INTERMUD_D->eventWrite(({ "channel-admin", 5, mud_name(), + this_player(1)->GetKeyName(), + 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( !(master()->valid_apply( ({}) )) ){ + return 0; + } + if( member_array(channel, INTERMUD_D->GetChannels()) != -1 ){ + return 0; + } + INTERMUD_D->eventWrite(({ "channel-add", 5, mud_name(), + this_player(1)->GetKeyName(), + INTERMUD_D->GetNameserver(), 0, + channel, privee })); + return 1; +} + +int RemoveChannel(string channel) { + tn("RemoveChannel: "+identify(channel),"green"); + + if( member_array(channel, INTERMUD_D->GetChannels()) == -1 ){ + return 0; + } + INTERMUD_D->eventWrite(({ "channel-remove", 5, mud_name(), + this_player(1)->GetKeyName(), + INTERMUD_D->GetNameserver(), 0, + channel })); + return 1; +} diff --git a/lib/daemon/services/emoteto.c b/lib/daemon/services/emoteto.c new file mode 100644 index 0000000..81a970e --- /dev/null +++ b/lib/daemon/services/emoteto.c @@ -0,0 +1,43 @@ +/* /daemon/services/emoteto.c + * from the Foundation II Object Library + * handles the I3 emoteto service + * created by Descartes of Borg 950914 + */ + +#define SERVICE_EMOTETO + +#include <daemons.h> + +void eventReceiveEmote(mixed *packet) { + object ob; + string who; + PING_D->SetOK(); + tn("eventReceiveEmote: "+identify(packet), "green"); + if( file_name(previous_object()) != INTERMUD_D ) return; + who = convert_name(packet[5]); + if( !(ob = find_player(who)) || 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]); + message("emote", packet[7], ob); +} + +void eventSendEmote(string who, string where, string msg) { + string pl, plc; + + pl = this_player(1)->GetKeyName(); + plc = this_player(1)->GetCapName(); + where = 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 --git a/lib/daemon/services/error.c b/lib/daemon/services/error.c new file mode 100644 index 0000000..ba031a0 --- /dev/null +++ b/lib/daemon/services/error.c @@ -0,0 +1,38 @@ +/* /daemon/services/error.c + * from the Foundation II LPC Library + * error handling for the grand Intermud 3 Protocol + * created by Descartes of Borg 950715 + */ + +#include <logs.h> +#include <daemons.h> + +void eventReceiveError(mixed *packet) { + object ob; + string error_code, mud, target, msg; + + tn("ERROR RECEIVED: "+identify(packet)); + LOG_D->LogSpecial(LOG_I3ERR ,timestamp()+" "+identify(packet)+"\n"); + if( packet[5] ) { + tn("exceptio probat regulam"); + target = convert_name(packet[5]); + if( !(ob = find_player(target)) ) write("Can't find "+packet[5]);; + } + mud = packet[2]; + error_code = packet[6]; + //msg = packet[7]; + //packet = packet[8]; + //tn("errorcode: "+error_code); + switch(error_code) { + case "unk-src": + //update("/daemon/intermud"); + return; + case "unk-dst": case "not-imp": case "unk-type": + return; + case "unk-user": + if( !ob ) return; + message("system", (msg ? msg : "Unknown user reported from " + mud + + "."), ob); + return; + } +} diff --git a/lib/daemon/services/finger.c b/lib/daemon/services/finger.c new file mode 100644 index 0000000..04280c3 --- /dev/null +++ b/lib/daemon/services/finger.c @@ -0,0 +1,67 @@ +/* /daemon/services/finger.c + * From the Dead Souls Mud Library + * Intermud 3 finger service implementation + * created by Descartes of Borg 950624 + * Version: @(#) finger.c 1.2@(#) + * Last modified: 96/12/14 + */ + +#define SERVICE_FINGER + +#include <daemons.h> +#include ROOMS_H +#include <message_class.h> + +void eventReceiveFingerRequest(mixed array packet) { + mixed array ret; + PING_D->SetOK(); + 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"); + CHAT_D->eventSendChannel("SYSTEM","intermud","[" + capitalize(packet[3])+"@"+ + packet[2]+" fingers "+capitalize(ret[6])+ "]",0); +} + +void eventReceiveFingerReply(mixed array packet) { + string fing; + object ob; + int i; + PING_D->SetOK(); + if( file_name(previous_object()) != INTERMUD_D ) return; + if( !(ob = find_player(convert_name(packet[5]))) ) return; + fing = "Finger information on " + packet[6] + " from " + packet[2] + ":\n"; + if( packet[7] ) fing += replace_string(packet[7], "$N", packet[6]); + else fing += packet[6]; + if( packet[8] ) fing += " (" + packet[8] + ")\n"; + else fing += "\n"; + fing += "Level: " + (packet[13] ? packet[13] : "Confidential") + "\n"; + fing += "Email: " + (packet[9] ? packet[9] : "Confidential") + "\n"; + if( (i = packet[11]) != -1 ) { + fing += (packet[10] ? "On since: " + packet[10] : "Online"); + 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) { + string pl; + + if( !(pl = 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 --git a/lib/daemon/services/locate.c b/lib/daemon/services/locate.c new file mode 100644 index 0000000..3f954d7 --- /dev/null +++ b/lib/daemon/services/locate.c @@ -0,0 +1,95 @@ +/* /daemon/services/locate.c + * From the Dead Souls Mud Library + * performs player lookups + * Created by Descartes of Borg 950624 + * Version: @(#) locate.c 1.2@(#) + * Last modified: 96/12/09 + */ + +#define SERVICE_LOCATE + +#include <daemons.h> +#include ROOMS_H +#include <message_class.h> + +static mapping locate_user_table = ([]); + +static string eventLookupLocateUser(string str){ + if(!locate_user_table) locate_user_table = ([]); + if(!locate_user_table[str]) return str; + else { + string ret = locate_user_table[str]; + //map_delete(locate_user_table, str); + return ret; + } +} + +void eventReceiveLocateRequest(mixed array packet) { + string status; + int idl = 0; + object ob; + PING_D->SetOK(); + 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"); + CHAT_D->eventSendChannel("SYSTEM","intermud","[" + capitalize(packet[3])+"@"+packet[2]+ + " seeks "+packet[6]+ "]",0); + if( !(ob = find_player(packet[6])) || ob->GetInvis()) return; + if( interactive(ob) ) { + string array tmp = ({ }); + if( in_edit(ob) || ob->GetCedmode() ) + tmp += ({ "editing" }); + if( (idl = query_idle(ob)) > 60 ) + tmp += ({ "inactive" }); + if( sizeof(tmp) ) status = implode(tmp, ", "); + else status = 0; + } + else status = "link-dead"; + INTERMUD_D->eventWrite( ({ "locate-reply", 5, mud_name(), 0, packet[2], + packet[3], mud_name(), + ob->GetName(), idl, status }) ); +} + +void eventReceiveLocateReply(mixed array packet) { + object ob; + string m; + int idl; + PING_D->SetOK(); + if( file_name(previous_object()) != INTERMUD_D ) return; + if( !packet[5] || !(ob = find_player(convert_name(eventLookupLocateUser(packet[5])))) ){ + return; + } + tn("Locate reply received: "+identify(packet),"white"); + m = packet[7] + " was just located on " + packet[6] + "."; + if( (idl = packet[8]) > 60 ) + m += sprintf(" (idle %02d:%02d:%02d)", idl/3600, (idl/60)%60, idl%60); + if( stringp(packet[9]) ) + m += " [status: " + packet[9] + "]"; + ob->eventPrint(m, MSG_SYSTEM); +} + +void eventSendLocateRequest(string target) { + string who, crypt_who; + mixed *locate_request; + + who = this_player(1)->GetKeyName(); + + if(this_player(1)->GetInvis()){ + foreach(string key, string val in locate_user_table){ + if(!key || ! val) continue; + if(val == who){ + crypt_who = key; + } + } + if(!crypt_who){ + crypt_who = alpha_crypt(10); + locate_user_table[crypt_who] = who; + } + } + + else crypt_who = who; + + locate_request = ({ "locate-req", 5, mud_name(), crypt_who, 0, 0, target }); + INTERMUD_D->eventWrite( locate_request ); + tn("Locate request being sent: "+identify(locate_request),"white"); +} diff --git a/lib/daemon/services/oob.c b/lib/daemon/services/oob.c new file mode 100644 index 0000000..48efc4a --- /dev/null +++ b/lib/daemon/services/oob.c @@ -0,0 +1,5 @@ +void eventReceiveOOB(mixed *packet){ +} + +void eventSendOOB(mixed *packet){ +} diff --git a/lib/daemon/services/tell.c b/lib/daemon/services/tell.c new file mode 100644 index 0000000..c8229a9 --- /dev/null +++ b/lib/daemon/services/tell.c @@ -0,0 +1,89 @@ +/* /daemon/services/tell.c + * from the Dead Souls LPC Library + * handles the IMP tell service + * created by Descartes of Borg 950507 + */ + +#define SERVICE_TELL + +#include <daemons.h> +#include <message_class.h> +#ifndef PLAYER_INTERTELL_ALLOWED +#define PLAYER_INTERTELL_ALLOWED 0 +#endif + +void eventReceiveTell(mixed *packet) { + object ob, machine; + string who, ret; + string adverb = ""; + string machine_message; + int nopriv; + PING_D->SetOK(); + tn("eventReceiveTell: "+identify(packet),"black"); + if( file_name(previous_object()) != INTERMUD_D ) return; + who = convert_name(packet[5]); + nopriv = (!creatorp(find_player(who)) && !PLAYER_INTERTELL_ALLOWED); + INSTANCES_D->SendTell(who, packet[7], packet[6] + "@" + packet[2]); + if( nopriv || (!(ob = find_player(who)) || ob->GetInvis() || + (nopriv = (RESTRICTED_INTERMUD && !imud_privp(lower_case(who)))) )) { + 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)) || nopriv) return; + adverb = " %^BOLD%^MAGENTA%^unknowingly%^BOLD%^RED%^"; + } + machine=present("answering machine",ob); + if(machine && base_name(machine) == "/secure/obj/machine"){ + int parse_it; + parse_it=machine->query_answer(); + if(parse_it){ + machine->get_message(packet[6] + "@" + packet[2]+ + " tells you: "+packet[7]+"\n"); + machine_message=machine->send_message(); + return; + } + } + ret = "%^BOLD%^RED%^" + packet[6] + "@" + packet[2] + + adverb + " tells you:%^RESET%^ " + packet[7]; + if(member_array(lower_case(packet[6]),ob->GetMuffed()) == -1 && + member_array(lower_case(packet[2]),ob->GetMuffed()) == -1){ + if(!machine_message){ + ob->eventPrint(ret, MSG_CONV); + } + ob->eventTellHist(ret); + if(!sizeof(adverb)){ + ob->SetProperty("reply", packet[6] + "@" + packet[2]); + ob->SetProperty("reply_time", time()); + } + } +} + +void eventSendTell(string who, string where, string msg) { + string pl, plc, ret; + + pl = this_player(1)->GetName(); + plc = this_player(1)->GetCapName(); + where = INTERMUD_D->GetMudName(where); + + // Quixadhal was here + if(RESTRICTED_INTERMUD) { + if(!imud_privp(lower_case(pl))) { + this_player(1)->eventPrint("You lack the power to send tells to other worlds.", MSG_CONV); + return; + } + } + if(!PLAYER_INTERTELL_ALLOWED && !creatorp(this_player())){ + this_player()->eventPrint("You lack the authority to send tells to other worlds.", MSG_CONV); + return; + } + + INTERMUD_D->eventWrite(({ "tell", 5, mud_name(), pl, where, + convert_name(who), plc, msg })); + ret = "%^BOLD%^RED%^You tell " + capitalize(who) + + "@" + where + ":%^RESET%^ " + msg; + this_player(1)->eventPrint(ret, MSG_CONV); + this_player(1)->eventTellHist(ret); + tn("eventSendTell: "+identify( ({ "tell", 5, mud_name(), pl, where, convert_name(who), plc, msg }) ), "red"); +} diff --git a/lib/daemon/services/who.c b/lib/daemon/services/who.c new file mode 100644 index 0000000..fbd86e1 --- /dev/null +++ b/lib/daemon/services/who.c @@ -0,0 +1,94 @@ +/* /daemon/services/who.c + * from the Dead Souls LPC Library + * handles the Intermud 3 who service + * created by Descartes of Borg 950623 + */ + +#define SERVICE_WHO + +#include <daemons.h> +#include ROOMS_H +static mapping user_table = ([]); + +int mini; + +static string eventLookupUser(string str){ + if(!user_table) user_table = ([]); + if(!user_table[str]) return str; + else { + string ret = user_table[str]; + return ret; + } +} + +void eventReceiveWhoReply(mixed *packet) { + string list, *who, tmp; + object ob; + PING_D->SetOK(); + if( file_name(previous_object()) != INTERMUD_D ) return; + if( !packet[5] || !(ob = find_player(convert_name(eventLookupUser(packet[5])))) ) return; + list = "%^MAGENTA%^Remote who information from " + packet[2] + ":%^RESET%^\n"; + foreach(who in packet[6]){ + mixed wtf; + if(intp(who[1])) wtf = to_int(who[1]); + if(wtf < 6) tmp = "not"; + else tmp = time_elapsed(wtf); + list += who[0] + " (" + tmp + " idle): " + who[2] +"\n"; + } + ob->eventPrint(list); + tn("eventReceiveWhoReply: "+identify(packet),"blue"); +} + +void eventReceiveWhoRequest(mixed *packet) { + mixed *msg; + string ret = ""; + mini = 0; + PING_D->SetOK(); + if( file_name(previous_object()) != INTERMUD_D && + file_name(previous_object()) != INSTANCES_D){ + return; + } + if(sizeof(users()) > 100) mini = 1; + msg = map(filter(users(),(: (environment($1) && !($1->GetInvis())) :)), + (: ({ $1->GetCapName(), query_idle($1), + (mini ? "" : $1->GetShort()) }) :)); + if(sizeof(identify(msg)) >= __LARGEST_PRINTABLE_STRING__){ + msg = ({({"Number of users: "+sizeof(msg), 0, "Too many results." })}); + } + write_file("/tmp/thingy.txt",identify(msg),1); + 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"); + CHAT_D->eventSendChannel("SYSTEM","intermud","[" + capitalize(packet[3])+"@"+packet[2]+ + " requests the who list]",0); +} + +varargs void eventSendWhoRequest(string mud) { + string who, crypt_who; + + who = this_player(1)->GetKeyName(); + + if(this_player(1)->GetInvis()){ + foreach(string key, string val in user_table){ + if(!key || ! val) continue; + if(val == who){ + crypt_who = key; + } + } + if(!crypt_who){ + crypt_who = alpha_crypt(10); + user_table[crypt_who] = who; + } + } + + else crypt_who = who; + + if((mud) && sizeof(mud)) INTERMUD_D->eventWrite(({ "who-req", 5, mud_name(), crypt_who, mud, 0 })); + else INTERMUD_D->eventWrite(({ "who-req", 5, mud_name(), crypt_who, 0, 0 })); + tn("eventSendWhoRequest: "+identify( ({ "who-req", 5, mud_name(), who, mud, 0 })), "blue"); +} + diff --git a/lib/daemon/skills.c b/lib/daemon/skills.c new file mode 100644 index 0000000..d23bcb9 --- /dev/null +++ b/lib/daemon/skills.c @@ -0,0 +1,69 @@ +#include <lib.h> +#include <save.h> +#include <daemons.h> +#include <privs.h> + +inherit LIB_DAEMON; +static string SaveFile; +mapping Skills = ([]); +mapping RacialSkills = ([]); + +static void create() { + daemon::create(); + SaveFile = save_file(SAVE_STATS); + SetSaveFile(SaveFile); + if(!file_exists(SaveFile) && file_exists(old_savename(SaveFile))){ + cp(old_savename(SaveFile), SaveFile); + } + RestoreObject(SaveFile); + if(sizeof(Skills)){ + SaveObject(SaveFile); + } + else { + call_out("SetSkills", 5); + } +} + +varargs int SetSkill(string what, string cls, int statcl, int racial){ + object prev = previous_object(); + string pbase = base_name(prev); + int accept_class; + if(!prev || pbase = CLASSES_D || pbase = RACES_D){ + accept_class = 1; + } + else if(!living(prev)){ + return 0; + } + if(!undefinedp(cls) && !undefinedp(statcl)){ + if(!statcl) statcl = 5; + if(accept_class){ + if(!racial){ + if(!Skills) Skills = ([]); + if(!Skills[what]) Skills[what] = ([]); + Skills[what][cls] = statcl; + } + else { + if(!RacialSkills) RacialSkills = ([]); + if(!RacialSkills[what]) RacialSkills[what] = ([]); + RacialSkills[what][cls] = statcl; + } + } + return 2; + } + return 1; +} + +static void SetSkills(){ + foreach(string cls in CLASSES_D->GetClasses()){ + mapping skills = CLASSES_D->GetClass(cls)["Skills"]; + foreach(mixed key, mixed val in skills){ + SetSkill(key, cls, val["SkillClass"]); + } + } + foreach(string race in RACES_D->GetRaces()){ + mapping skills = RACES_D->GetRace(race)["Skills"]; + foreach(mixed key, mixed val in skills){ + SetSkill(key, race, val[1], 1); + } + } +} diff --git a/lib/daemon/soul.c b/lib/daemon/soul.c new file mode 100644 index 0000000..882b9d7 --- /dev/null +++ b/lib/daemon/soul.c @@ -0,0 +1,443 @@ +/* /daemon/emote.c + * From the Dead Souls Object Library + * A centralized soul handler + * Created by Descartes of Borg 961207 + * Version: @(#) soul.c 1.11@(#) + * Last modified: 96/12/15 + */ + +#include <lib.h> +#include <pov.h> +#include <privs.h> +#include <save.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +class emote { + string ErrorMessage; + mapping Rules; +} + +class rule { + mixed array Message; + string array Adverbs; +} + +private mapping Emotes = ([]); +private string array Adverbs = ({}); + +static private void validate() { + if(!this_player()) return 0; + if( !(master()->valid_apply(({ "ASSIST" }))) && + !member_group(this_player(), "EMOTES") ) + error("Illegal attempt to access SOUL_D: "+get_stack()+" "+identify(previous_object(-1))); +} + +varargs int AddAdverbs(string array advs...) { + validate(); + Adverbs = distinct_array(Adverbs + advs); + eventSave(); + return 1; +} + +varargs int AddRule(string verb, string rle, mixed array msg, + string array advs) { + class emote e = Emotes[verb]; + class rule r; + validate(); + + if( !e ) { + return 0; + } + r = new(class rule); + r->Message = msg; + r->Adverbs = (advs || ({})); + e->Rules[rle] = r; + if( catch(parse_add_rule(verb, rle)) ) { + return 0; + } + eventSave(); + return 1; +} + +int AddVerb(string verb, string err) { + class emote e; + validate(); + + if( Emotes[verb] ) { + return 0; + } + else { + e = new(class emote); + } + e->ErrorMessage = err; + e->Rules = ([]); + Emotes[verb] = e; + eventSave(); + return 1; +} + +int RemoveRule(string emt, string rle) { + class emote e = Emotes[emt]; + validate(); + + if( !e ) { + return 0; + } + map_delete(e->Rules, rle); + eventSave(); + return 1; +} + +int RemoveVerb(string verb) { + validate(); + map_delete(Emotes, verb); + eventSave(); + return 1; +} + +string array GetAdverbs() { + return copy(Adverbs); +} + +varargs mixed array GetChannelEmote(string emote, string parse, string args) { + class emote e = Emotes[emote]; + mapping adverb = ([]); + class rule r; + + if( !e ) { + return 0; + } + r = e->Rules[parse]; + if( !r ) { + parse = replace_string(parse, "LIV", "LVS"); + r = e->Rules[parse]; + if( !r ) { + return 0; + } + } + if( args ) { + string array pool = r->Adverbs; + int any_adv = (member_array("*", pool) != -1); + + if( member_array("-", pool) != -1 ) { + pool += Adverbs; + } + if( !any_adv && member_array(args, pool) == -1 ) { + string array matches = regexp(pool, "^" + args); + + if( !sizeof(matches) ) { + return 0; + } + adverb = ([ "$adverb" : matches[0] ]); + } + else { + adverb = ([ "$adverb" : args ]); + } + } + return ({ r->Message, adverb }); +} + +string array GetEmotes() { + return keys(Emotes); +} + +string GetErrorMessage(string verb) { + class emote e = Emotes[verb]; + + if( !e ) { + return 0; + } + return e->ErrorMessage; +} + +string GetHelp(string arg) { + class emote e; + string array rls; + string str; + + 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; + } + e = Emotes[arg]; + if( !e ) { + return 0; + } + rls = keys(e->Rules); + if( !sizeof(rls) ) { + return "This emote is not yet valid."; + } + else { + int w = member_array("", rls); + + if( w > 0 ) { + if( w < sizeof(rls) -1 ) { + rls = ({ rls[w], rls[0..(w-1)]..., rls[(w+1)..]... }); + } + else { + rls = ({ rls[w], rls[0..(w-1)]... }); + } + } + } + if( rls[0] == "" ) { + str = "Syntax: <" + arg + ">\n"; + } + else { + class rule r = e->Rules[rls[0]]; + string array pool = r->Adverbs; + 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 ) { + rule = replace_string(rule, "STR", "PHRASE"); + } + else if( all_advs ) { + pool = (pool - ({ "-", "*" })) + ({ "system adverbs" }); + rule = replace_string(rule, "STR", "ADVERB"); + } + str = "Syntax: <" + arg + " " + rule + ">\n"; + if( !anything ) { + if( sizeof(pool) ) { + str += " Adverbs: " + item_list(pool); + } + } + str += "\n"; + } + if( sizeof(rls) > 1 ) { + rls = rls[1..]; + foreach(string rule in rls) { + class rule r = e->Rules[rule]; + + if( rule == "" ) { + str += " <" + arg + ">\n"; + } + else { + string array pool = r->Adverbs; + int all_advs = (member_array("-", r->Adverbs) != -1); + int anything = (member_array("*", r->Adverbs) != -1); + + rule = replace_string(rule, "LIV", "SINGLE_LIVING"); + rule = replace_string(rule, "LVS", "ONE_OR_MORE_LIVINGS"); + if( anything ) { + rule = replace_string(rule, "STR", "PHRASE"); + } + else if( all_advs ) { + pool = (pool - ({ "-", "*" })) + ({ "system adverbs" }); + rule = replace_string(rule, "STR", "ADVERB"); + } + str += " <" + arg + " " + rule + ">"; + if( !anything ) { + if( sizeof(pool) ) { + str += " Adverbs: " + item_list(pool); + } + } + str += "\n"; + } + } + } + str += "\n"; + 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; +} + +void SetErrorMessage(string verb, string msg) { + class emote e = Emotes[verb]; + validate(); + + if( !e ) { + AddVerb(verb, msg); + } + else { + e->ErrorMessage = msg; + eventSave(); + } +} + +string GetRaceAdverb(mixed who) { + string res; + + if( objectp(who) ) { + res = who->GetRace(); + } + + if( !res ) { + return "godly"; + } + switch(res) { + case "gnome": return "gnomishly"; + case "elf": return "elvenly"; + case "half-elf": return "half-elvenly"; + case "orc": return "orcishly"; + case "half-orc": return "half-orcishly"; + default: return res + "ly"; + } +} + +mapping GetRules(string emote) { + class emote e = Emotes[emote]; + mapping m = ([]); + + if( !e ) { + return 0; + } + foreach(string rle, class rule r in e->Rules) { + m[rle] = ({ r->Adverbs, r->Message }); + } + if( !master()->valid_apply(({ PRIV_ASSIST })) + || (this_player() && !member_group(this_player(), "EMOTES"))){ + return copy(m); + } + return m; +} + +int CanTarget(object who, string verb, object target, string rule) { + if( Emotes[verb] ) { + return 1; + } + else { + return 0; + } +} + +mixed can_verb_rule(string verb, string rle) { + class emote e = Emotes[verb]; + class rule r; + + if( !e ) { + return 0; + } + r = e->Rules[rle]; + if( !r ) { + return 0; + } + return 1; +} + +varargs mixed do_verb_rule(string verb, string rle, mixed args...) { + object env = environment(this_player()); + class emote e = Emotes[verb]; + class rule r = e->Rules[rle]; + string adv = 0; + + switch( rle ) { + case "": + args = 0; + adv = 0; + break; + + case "LIV": case "at LIV": case "with LIV": case "to LIV": + case "around LIV": case "on LIV": + case "OBJ": case "at OBJ": case "with OBJ": case "to OBJ": + case "LVS": case "at LVS": case "with LVS": case "to LVS": + case "around LVS": case "on LVS": + args = args[0]; + adv = 0; + break; + + case "STR": case "for STR": case "about STR": + adv = args[0]; + args = 0; + break; + + case "STR LIV": case "STR at LIV": case "STR with LIV": + case "STR around LIV": case "STR on LIV": + case "for STR LIV": case "for STR to LIV": + case "STR OBJ": case "STR at OBJ": case "STR with OBJ": + case "STR LVS": case "STR at LVS": case "STR with LVS": + case "STR around LVS": case "STR on LVS": + case "for STR LVS": case "for STR to LVS": + adv = args[0]; + args = args[1]; + break; + + case "LIV STR": case "at LIV STR": case "LIV of STR": case "with LIV STR": + case "around LIV STR": case "on LIV STR": + case "LIV for STR": case "to LIV for STR": + case "OBJ STR": case "at OBJ STR": case "OBJ of STR": case "with OBJ STR": + case "LVS STR": case "at LVS STR": case "LVS of STR": case "with LVS STR": + case "around LVS STR": case "on LVS STR": + case "LVS for STR": case "to LVS for STR": + adv = args[1]; + args = args[0]; + break; + + default: + this_player()->eventPrint("Unknown soul syntax."); + return 1; + } + if( arrayp(args) ) { + args = filter(args, (: objectp :)); + } + if( adv ) { + string array pool = r->Adverbs + ({ GetRaceAdverb(this_player()) }); + int any_adv = (member_array("*", pool) != -1); + + if( member_array("-", pool) != -1 ) { + pool += Adverbs; + } + if( !any_adv && member_array(adv, pool) == -1 ) { + string array matches = regexp(pool, "^" + adv); + + 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); + } + } + else { + send_messages(r->Message[0], r->Message[1], this_player(), args, env); + if( args ) { + args->eventReceiveEmote(this_player(), verb); + } + } + return 1; +} + +static void create() { + SetSaveFile(SAVE_SOUL); + daemon::create(); + if(!file_exists(GetSaveFile()) && + file_exists(old_savename(GetSaveFile()))){ + cp(old_savename(GetSaveFile()), GetSaveFile()); + } + SetNoClean(1); + parse_init(); + foreach(string verb, class emote data in Emotes) { + foreach(string rle in keys(data->Rules)) { + parse_add_rule(verb, rle); + } + } + eventSave(); +} diff --git a/lib/daemon/spells.c b/lib/daemon/spells.c new file mode 100644 index 0000000..2fe3ba9 --- /dev/null +++ b/lib/daemon/spells.c @@ -0,0 +1,76 @@ +/* /daemon/spells.c + * From Dead Souls LPMud + * created by Descartes of Borg 961027 + * Version: @(#) spells.c 1.2@(#) + * Last modified: 96/10/28 + */ + +#include <lib.h> +#include <dirs.h> + +inherit LIB_DAEMON; + +private mapping Spells = ([]); +private mapping Prayers = ([]); + +void eventReloadSpells(); + +static void create() { + daemon::create(); + SetNoClean(1); + eventReloadSpells(); +} + +void eventReloadSpells() { + string array spells, prayers; + + Spells = ([]); + spells = get_dir(DIR_SPELLS "/*.c"); + prayers = get_dir(DIR_PRAYERS "/*.c"); + foreach(string element in (prayers + spells)) { + string spell, where; + int err; + object ob; + where = DIR_PRAYERS "/" + element; + if(!file_exists(where)) where = DIR_SPELLS "/" + element; + ob = find_object(where); + + if( ob ) { + ob->eventDestruct(); + } + err = catch(ob = load_object(where)); + if(ob){ + spell = ob->GetSpell(); + if( spell ) { + if(member_array(element,spells) != -1) + Spells[spell] = ob; + else if(member_array(element,prayers) != -1) + Prayers[spell] = ob; + } + } + else debug("Error loading: "+identify(where)); + } +} + +object GetSpell(string spell) { + if( !Spells[spell] ) { + eventReloadSpells(); + } + if(Prayers[spell]) return Prayers[spell]; + else return Spells[spell]; +} + +mapping GetSpells(){ + return (Spells + ([])); +} + +object GetPrayer(string prayer) { + if( !Prayers[prayer] ) { + eventReloadSpells(); + } + return Prayers[prayer]; +} + +mapping GetPrayers(){ + return (Prayers + ([])); +} diff --git a/lib/daemon/stargate.c b/lib/daemon/stargate.c new file mode 100644 index 0000000..de8d2b5 --- /dev/null +++ b/lib/daemon/stargate.c @@ -0,0 +1,177 @@ +/** + * 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 string SaveFile; + +static void create(){ + daemon::create(); + SaveFile = save_file(SAVE_STARGATE); + SetNoClean(1); + eventLoad(); + set_heart_beat(60); + if (!Stargates) Stargates = ([]); + SaveObject(SaveFile, 1); +} + +void eventSave(){ + SaveObject(SaveFile, 1); + return; +} + +void eventLoad(){ + if(file_exists(SaveFile)){ + RestoreObject(SaveFile); + } + return; +} + +int SetStargate(string address, string destination){ + mapping tmp = ([]); + object prevob = previous_object(); + string prev; + + if(!prevob) return 0; + prev = base_name(prevob); + + //Only gates installed in /domains/ or /secure/ are allowed + //to register. + if(strsrch(prev, "/domains/") && strsrch(prev, "/secure/")){ + return 0; + } + + 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){ + if(!Stargates[address]) return 0; + Stargates[address]["status"] = status; + Stargates[address]["last_change"] = time(); + eventSave(); + return 1; +} + +string GetStatus(string address){ + if(!Stargates || !Stargates[address]) return "unknown"; + return Stargates[address]["status"]; +} + +mixed GetDestination(string address){ + if(sizeof(Stargates[address]) && sizeof(Stargates[address]["destination"])) + return Stargates[address]["destination"]; + else return 0; +} + +mixed GetEndpoint(string address){ + if(Stargates[address] && Stargates[address]["endpoint"]){ + return Stargates[address]["endpoint"]; + } + else return 0; +} + +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; +} + +void ResetGates(){ + foreach(mixed key, mixed val in Stargates){ + Stargates[key]["endpoint"] = ""; + Stargates[key]["status"] = "idle"; + Stargates[key]["last_change"] = 0; + eventSave(); + } +} + +void heart_beat(){ + foreach(mixed key, mixed val in Stargates){ + if(undefinedp(val["last_change"])){ + Stargates[key]["last_change"] = 0; + } + if((val["last_change"] && (time() - val["last_change"]) > 60) || + (!val["last_change"] && val["status"] != "idle")){ + Stargates[key]["endpoint"] = ""; + Stargates[key]["status"] = "idle"; + Stargates[key]["last_change"] = 0; + eventSave(); + } + } +} diff --git a/lib/daemon/statistics.c b/lib/daemon/statistics.c new file mode 100644 index 0000000..1f21237 --- /dev/null +++ b/lib/daemon/statistics.c @@ -0,0 +1,46 @@ +/* /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@(#) + * Last modified: 96/10/08 + */ + +#include <lib.h> +#include <dirs.h> +#include "include/statistics.h" + +inherit LIB_DAEMON; + +mixed eventKill(object target) { + mapping kills; + object pl; + string nom, file; + + if( !userp(pl = previous_object()) ) return 0; + nom = pl->GetKeyName(); + file = DIR_KILLS "/" + nom[0..0]; + if( file_size(file) != -2 ) { + unguarded( (: mkdir, file :) ); + } + file = file + "/" + nom; + if( file_size(file) < 1 ) { + kills = ([]); + } + else kills = restore_variable(unguarded((: read_file, file :))); + nom = target->GetShort() || target->GetKeyName(); + if( !kills[nom] ) kills[nom] = 1; + else kills[nom]++; + unguarded((: rm, file :)); + unguarded((: write_file($(file), save_variable($(kills))) :)); + return 1; +} + +mapping GetKills(string who) { + string file; + + who = convert_name(who); + file = DIR_KILLS "/" + who[0..0] + "/" + who; + if( unguarded((: file_size, file :)) < 1 ) return ([]); + else return restore_variable(unguarded((: read_file, file :))); +} diff --git a/lib/daemon/stats.c b/lib/daemon/stats.c new file mode 100644 index 0000000..96518c6 --- /dev/null +++ b/lib/daemon/stats.c @@ -0,0 +1,57 @@ +#include <lib.h> +#include <save.h> +#include <daemons.h> +#include <privs.h> + +inherit LIB_DAEMON; +static string SaveFile; +mapping Stats = ([]); + +static void create() { + daemon::create(); + SaveFile = save_file(SAVE_STATS); + SetSaveFile(SaveFile); + if(!file_exists(SaveFile) && file_exists(old_savename(SaveFile))){ + cp(old_savename(SaveFile), SaveFile); + } + RestoreObject(SaveFile); + if(sizeof(Stats)){ + SaveObject(SaveFile); + } + else { + call_out("SetStats", 5); + } +} + +varargs int SetStat(string what, string race, int statcl){ + object prev = previous_object(); + string pbase = base_name(prev); + int accept_class; + if(!prev || pbase = RACES_D){ + accept_class = 1; + } + else if(!living(prev)){ + return 0; + } + if(!Stats) Stats = ([]); + if(!Stats[what]) Stats[what] = ([]); + if(!undefinedp(race) && !undefinedp(statcl)){ + if(!statcl) statcl = 5; + if(accept_class) Stats[what][race] = statcl; + return 2; + } + return 1; +} + +static void SetStats(){ + foreach(string race in RACES_D->GetRaces()){ + mapping stats = RACES_D->GetRace(race)["Stats"]; + foreach(mixed key, mixed val in stats){ + SetStat(key, race, val["Class"]); + } + } +} + +mapping GetStats(){ + return copy(Stats); +} diff --git a/lib/daemon/terminal.c b/lib/daemon/terminal.c new file mode 100644 index 0000000..4a46e8b --- /dev/null +++ b/lib/daemon/terminal.c @@ -0,0 +1,144 @@ +/* /daemon/terminal.c + * from the Dead Souls Object Library + * daemon storing terminal information + * created by Pinkfish@Discworld + * rewritten for Dead Souls by Descartes of Borg 930903 + * Version: @(#) terminal.c 1.5@(#) + * Last modified: 96/11/11 + */ + +#include <lib.h> + +inherit LIB_DAEMON; + +#define ANSI(p) sprintf("%c["+(p)+"m", 27) +#define ESC(p) sprintf("%c"+(p), 27) + +static mapping term_info; + +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":CARRIAGE_RETURN, "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":CARRIAGE_RETURN, "ENDTERM":ESC("[0r")+ESC("[H")+ESC("[J") ]) +nohtml; + term_info["xterm"] = + ([ "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["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) { + return (term_info[type] ? term_info[type] : term_info["unknown"]); +} + +string *query_terms() { return keys(term_info); } + +int query_term_support(string str) { + return (term_info[str] ? 1 : 0); +} + +string no_colours(string str) { + return terminal_colour(str, term_info["unknown"]); +} + +string no_colors(string str){ + return no_colours(str); +} + +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 ) { + fcount++; + tmp = tmp[(i+5)..]; + } + if( fcount < 1 ) { + return str; + } + tmp = str; + while( (i = strsrch(tmp, "</FONT")) != -1 ) { + ncount++; + tmp = tmp[(i+6)..]; + } + tot = fcount - ncount; + if( tot > 0 ) { + while( tot-- ) { + str += "</FONT>"; + } + } + return str; +} + +#ifdef __DSLIB__ +int GetCharmode(object ob){ + return query_charmode(ob); +} +#endif diff --git a/lib/daemon/time.c b/lib/daemon/time.c new file mode 100644 index 0000000..0e6fd8f --- /dev/null +++ b/lib/daemon/time.c @@ -0,0 +1,53 @@ +/* /daemon/time.c + * from the Dead Souls LPC Library + * a time management daemon + * created by Descartes of Borg 950507 + */ + +#include <lib.h> +#include <cfg.h> +#include <localtime.h> +#include "include/time.h" + +inherit LIB_DAEMON; + +private static string LocalZone; +private static mapping Zones; + +static void create() { + string *lines; + mixed *tmp; + int i, x; + + daemon::create(); + Zones = ([]); + tmp = localtime(time()); + //LocalZone = tmp[LT_ZONE]; + if(LOCAL_TIME) x = -(tmp[LT_GMTOFF] / 3600); + else x = 0; + if( file_size(CFG_TIME) < 1 ) return; + i = sizeof(lines = filter(explode(read_file(CFG_TIME), "\n"), + (: $1 && $1 != "" && $1[0] != '#' :))); + foreach(string line in lines) { + string *words; + if( sizeof(words = explode(line, ":")) != 3 ) continue; + Zones[words[0]] = ([]); + Zones[words[0]]["offset"] = to_int(words[1]) - x; + Zones[words[0]]["name"] = words[2]; + } +} + +int GetOffset(string tzone) { + if(LOCAL_TIME) return 0; + if(!tzone) tzone = query_tz(); + if( !Zones[tzone] ) return 0; + else return Zones[tzone]["offset"]; +} + +string GetName(string tzone) { + if(!tzone) tzone = query_tz(); + if( !Zones[tzone] ) return 0; + else return Zones[tzone]["name"]; +} + +string *GetTimeZones() { return keys(Zones); } diff --git a/lib/daemon/tmp/1,1,1.c b/lib/daemon/tmp/1,1,1.c new file mode 100644 index 0000000..20e6d30 --- /dev/null +++ b/lib/daemon/tmp/1,1,1.c @@ -0,0 +1,95 @@ +#include <bboard.h> +#include <cfg.h> +#include <cgi.h> +#include <clean_up.h> +#include <clock.h> +#include <commands.h> +#include <comp.h> +#include <compat.h> +#include <config.h> +#include <council.h> +#include <daemons.h> +#include <deputies.h> +#include <dirs.h> +#include <domains.h> +#include <events.h> +#include <files.h> +#include <flags.h> +#include <function.h> +#include <global.h> +#include <iips.h> +#include <lib.h> +#include <link.h> +#include <localtime.h> +#include <logs.h> +#include <lvs.h> +#include <modules.h> +#include <mssp.h> +#include <mudlib.h> +#include <network.h> +#include <news.h> +#include <objects.h> +#include <origin.h> +#include <parse_com.h> +#include <parser_error.h> +#include <post.h> +#include <pov.h> +#include <privs.h> +#include <props.h> +#include <rcp.h> +#include <rooms.h> +#include <runtime_config.h> +#include <save.h> +#include <secrets.h> +#include <socket.h> +#include <socket_err.h> +#include <sockets.h> +#include <std.h> +#include <type.h> +#include <user.h> +#include <virtual.h> +#include <voting.h> +#include <armor_types.h> +#include <assessment.h> +#include <astar.h> +#include <body_types.h> +#include <boobytraps.h> +#include <build_types.h> +#include <climb.h> +#include <combat_messages.h> +#include <damage_types.h> +#include <gossip.h> +#include <graphics.h> +#include <jump.h> +#include <magic.h> +#include <magic_protection.h> +#include <marriage.h> +#include <materials.h> +#include <meal_types.h> +#include <medium.h> +#include <message_class.h> +#include <motion.h> +#include <mouth_types.h> +#include <position.h> +#include <race.h> +#include <respiration_types.h> +#include <rounds.h> +#include <size_types.h> +#include <soul.h> +#include <stargate.h> +#include <talk_type.h> +#include <terrain_types.h> +#include <vendor_types.h> +#include <vision.h> +#ifndef 1,1,1 +#define 1,1,1 "DEFINED_D: undefined" +#endif + +mixed defcheck(){ +int err; +mixed ret; +err = catch( ret = 1,1,1 ); +if(err) ret = "DEFINED_D: error"; +else if(undefinedp(ret)) ret = "DEFINED_D: undefined"; +return ret; +} \ No newline at end of file diff --git a/lib/daemon/tmp/A_AMULET.c b/lib/daemon/tmp/A_AMULET.c new file mode 100644 index 0000000..705ca14 --- /dev/null +++ b/lib/daemon/tmp/A_AMULET.c @@ -0,0 +1,2 @@ +#include <armor_types.h> +int armor() { return A_AMULET; } diff --git a/lib/daemon/tmp/A_ARMOR.c b/lib/daemon/tmp/A_ARMOR.c new file mode 100644 index 0000000..65035e9 --- /dev/null +++ b/lib/daemon/tmp/A_ARMOR.c @@ -0,0 +1,2 @@ +#include <armor_types.h> +int armor() { return A_ARMOR; } diff --git a/lib/daemon/tmp/A_BELT.c b/lib/daemon/tmp/A_BELT.c new file mode 100644 index 0000000..56e3326 --- /dev/null +++ b/lib/daemon/tmp/A_BELT.c @@ -0,0 +1,2 @@ +#include <armor_types.h> +int armor() { return A_BELT; } diff --git a/lib/daemon/tmp/A_BODY_ARMOR.c b/lib/daemon/tmp/A_BODY_ARMOR.c new file mode 100644 index 0000000..a9e0a86 --- /dev/null +++ b/lib/daemon/tmp/A_BODY_ARMOR.c @@ -0,0 +1,2 @@ +#include <armor_types.h> +int armor() { return A_BODY_ARMOR; } diff --git a/lib/daemon/tmp/A_BOOT.c b/lib/daemon/tmp/A_BOOT.c new file mode 100644 index 0000000..3d0f539 --- /dev/null +++ b/lib/daemon/tmp/A_BOOT.c @@ -0,0 +1,2 @@ +#include <armor_types.h> +int armor() { return A_BOOT; } diff --git a/lib/daemon/tmp/A_CLOAK.c b/lib/daemon/tmp/A_CLOAK.c new file mode 100644 index 0000000..c995c60 --- /dev/null +++ b/lib/daemon/tmp/A_CLOAK.c @@ -0,0 +1,2 @@ +#include <armor_types.h> +int armor() { return A_CLOAK; } diff --git a/lib/daemon/tmp/A_COLLAR.c b/lib/daemon/tmp/A_COLLAR.c new file mode 100644 index 0000000..11e1f3a --- /dev/null +++ b/lib/daemon/tmp/A_COLLAR.c @@ -0,0 +1,2 @@ +#include <armor_types.h> +int armor() { return A_COLLAR; } diff --git a/lib/daemon/tmp/A_CUSTOM.c b/lib/daemon/tmp/A_CUSTOM.c new file mode 100644 index 0000000..6eebed5 --- /dev/null +++ b/lib/daemon/tmp/A_CUSTOM.c @@ -0,0 +1,2 @@ +#include <armor_types.h> +int armor() { return A_CUSTOM; } diff --git a/lib/daemon/tmp/A_GLOVE.c b/lib/daemon/tmp/A_GLOVE.c new file mode 100644 index 0000000..ffaa7f4 --- /dev/null +++ b/lib/daemon/tmp/A_GLOVE.c @@ -0,0 +1,2 @@ +#include <armor_types.h> +int armor() { return A_GLOVE; } diff --git a/lib/daemon/tmp/A_HELMET.c b/lib/daemon/tmp/A_HELMET.c new file mode 100644 index 0000000..bd32830 --- /dev/null +++ b/lib/daemon/tmp/A_HELMET.c @@ -0,0 +1,2 @@ +#include <armor_types.h> +int armor() { return A_HELMET; } diff --git a/lib/daemon/tmp/A_LONG_BOOT.c b/lib/daemon/tmp/A_LONG_BOOT.c new file mode 100644 index 0000000..a161781 --- /dev/null +++ b/lib/daemon/tmp/A_LONG_BOOT.c @@ -0,0 +1,2 @@ +#include <armor_types.h> +int armor() { return A_LONG_BOOT; } diff --git a/lib/daemon/tmp/A_LONG_GLOVE.c b/lib/daemon/tmp/A_LONG_GLOVE.c new file mode 100644 index 0000000..bc5ba74 --- /dev/null +++ b/lib/daemon/tmp/A_LONG_GLOVE.c @@ -0,0 +1,2 @@ +#include <armor_types.h> +int armor() { return A_LONG_GLOVE; } diff --git a/lib/daemon/tmp/A_LONG_SOCK.c b/lib/daemon/tmp/A_LONG_SOCK.c new file mode 100644 index 0000000..bee2acf --- /dev/null +++ b/lib/daemon/tmp/A_LONG_SOCK.c @@ -0,0 +1,2 @@ +#include <armor_types.h> +int armor() { return A_LONG_SOCK; } diff --git a/lib/daemon/tmp/A_PANTS.c b/lib/daemon/tmp/A_PANTS.c new file mode 100644 index 0000000..29d00bd --- /dev/null +++ b/lib/daemon/tmp/A_PANTS.c @@ -0,0 +1,2 @@ +#include <armor_types.h> +int armor() { return A_PANTS; } diff --git a/lib/daemon/tmp/A_RING.c b/lib/daemon/tmp/A_RING.c new file mode 100644 index 0000000..c83f24f --- /dev/null +++ b/lib/daemon/tmp/A_RING.c @@ -0,0 +1,2 @@ +#include <armor_types.h> +int armor() { return A_RING; } diff --git a/lib/daemon/tmp/A_SHIELD.c b/lib/daemon/tmp/A_SHIELD.c new file mode 100644 index 0000000..14f93c9 --- /dev/null +++ b/lib/daemon/tmp/A_SHIELD.c @@ -0,0 +1,2 @@ +#include <armor_types.h> +int armor() { return A_SHIELD; } diff --git a/lib/daemon/tmp/A_SHIRT.c b/lib/daemon/tmp/A_SHIRT.c new file mode 100644 index 0000000..d2fcc4c --- /dev/null +++ b/lib/daemon/tmp/A_SHIRT.c @@ -0,0 +1,2 @@ +#include <armor_types.h> +int armor() { return A_SHIRT; } diff --git a/lib/daemon/tmp/A_SOCK.c b/lib/daemon/tmp/A_SOCK.c new file mode 100644 index 0000000..e47fcf5 --- /dev/null +++ b/lib/daemon/tmp/A_SOCK.c @@ -0,0 +1,2 @@ +#include <armor_types.h> +int armor() { return A_SOCK; } diff --git a/lib/daemon/tmp/A_VEST.c b/lib/daemon/tmp/A_VEST.c new file mode 100644 index 0000000..3687fc1 --- /dev/null +++ b/lib/daemon/tmp/A_VEST.c @@ -0,0 +1,2 @@ +#include <armor_types.h> +int armor() { return A_VEST; } diff --git a/lib/daemon/tmp/A_VISOR.c b/lib/daemon/tmp/A_VISOR.c new file mode 100644 index 0000000..8d4119a --- /dev/null +++ b/lib/daemon/tmp/A_VISOR.c @@ -0,0 +1,2 @@ +#include <armor_types.h> +int armor() { return A_VISOR; } diff --git a/lib/daemon/tmp/A_WEAPON.c b/lib/daemon/tmp/A_WEAPON.c new file mode 100644 index 0000000..9244db3 --- /dev/null +++ b/lib/daemon/tmp/A_WEAPON.c @@ -0,0 +1,2 @@ +#include <armor_types.h> +int armor() { return A_WEAPON; } diff --git a/lib/daemon/tmp/B_HUMANOID.c b/lib/daemon/tmp/B_HUMANOID.c new file mode 100644 index 0000000..1e05126 --- /dev/null +++ b/lib/daemon/tmp/B_HUMANOID.c @@ -0,0 +1,2 @@ +#include <body_types.h> +int btype() { return B_HUMANOID; } diff --git a/lib/daemon/tmp/DeskarNull.c b/lib/daemon/tmp/DeskarNull.c new file mode 100644 index 0000000..01cc6b9 --- /dev/null +++ b/lib/daemon/tmp/DeskarNull.c @@ -0,0 +1,95 @@ +#include <bboard.h> +#include <cfg.h> +#include <cgi.h> +#include <clean_up.h> +#include <clock.h> +#include <commands.h> +#include <comp.h> +#include <compat.h> +#include <config.h> +#include <council.h> +#include <daemons.h> +#include <deputies.h> +#include <dirs.h> +#include <domains.h> +#include <events.h> +#include <files.h> +#include <flags.h> +#include <function.h> +#include <global.h> +#include <iips.h> +#include <lib.h> +#include <link.h> +#include <localtime.h> +#include <logs.h> +#include <lvs.h> +#include <modules.h> +#include <mssp.h> +#include <mudlib.h> +#include <network.h> +#include <news.h> +#include <objects.h> +#include <origin.h> +#include <parse_com.h> +#include <parser_error.h> +#include <post.h> +#include <pov.h> +#include <privs.h> +#include <props.h> +#include <rcp.h> +#include <rooms.h> +#include <runtime_config.h> +#include <save.h> +#include <secrets.h> +#include <socket.h> +#include <socket_err.h> +#include <sockets.h> +#include <std.h> +#include <type.h> +#include <user.h> +#include <virtual.h> +#include <voting.h> +#include <armor_types.h> +#include <assessment.h> +#include <astar.h> +#include <body_types.h> +#include <boobytraps.h> +#include <build_types.h> +#include <climb.h> +#include <combat_messages.h> +#include <damage_types.h> +#include <gossip.h> +#include <graphics.h> +#include <jump.h> +#include <magic.h> +#include <magic_protection.h> +#include <marriage.h> +#include <materials.h> +#include <meal_types.h> +#include <medium.h> +#include <message_class.h> +#include <motion.h> +#include <mouth_types.h> +#include <position.h> +#include <race.h> +#include <respiration_types.h> +#include <rounds.h> +#include <size_types.h> +#include <soul.h> +#include <stargate.h> +#include <talk_type.h> +#include <terrain_types.h> +#include <vendor_types.h> +#include <vision.h> +#ifndef DeskarNull +#define DeskarNull "DEFINED_D: undefined" +#endif + +mixed defcheck(){ +int err; +mixed ret; +err = catch( ret = DeskarNull ); +if(err) ret = "DEFINED_D: error"; +else if(undefinedp(ret)) ret = "DEFINED_D: undefined"; +return ret; +} \ No newline at end of file diff --git a/lib/daemon/tmp/MOUTH_LIPPED+MOUTH_TOOTHED+MOUTH_TONGUED+MOUTH_TUSKED.c b/lib/daemon/tmp/MOUTH_LIPPED+MOUTH_TOOTHED+MOUTH_TONGUED+MOUTH_TUSKED.c new file mode 100644 index 0000000..05a7437 --- /dev/null +++ b/lib/daemon/tmp/MOUTH_LIPPED+MOUTH_TOOTHED+MOUTH_TONGUED+MOUTH_TUSKED.c @@ -0,0 +1,2 @@ +#include <mouth_types.h> +int mtype() { return MOUTH_LIPPED+MOUTH_TOOTHED+MOUTH_TONGUED+MOUTH_TUSKED; } diff --git a/lib/daemon/tmp/MOUTH_LIPPED+MOUTH_TOOTHED+MOUTH_TONGUED.c b/lib/daemon/tmp/MOUTH_LIPPED+MOUTH_TOOTHED+MOUTH_TONGUED.c new file mode 100644 index 0000000..a6cf235 --- /dev/null +++ b/lib/daemon/tmp/MOUTH_LIPPED+MOUTH_TOOTHED+MOUTH_TONGUED.c @@ -0,0 +1,2 @@ +#include <mouth_types.h> +int mtype() { return MOUTH_LIPPED+MOUTH_TOOTHED+MOUTH_TONGUED; } diff --git a/lib/daemon/tmp/R_AIR.c b/lib/daemon/tmp/R_AIR.c new file mode 100644 index 0000000..fe10d1f --- /dev/null +++ b/lib/daemon/tmp/R_AIR.c @@ -0,0 +1,2 @@ +#include <respiration_types.h> +int rtype() { return R_AIR; } diff --git a/lib/daemon/tmp/S_HUMAN_SIZED.c b/lib/daemon/tmp/S_HUMAN_SIZED.c new file mode 100644 index 0000000..032cebb --- /dev/null +++ b/lib/daemon/tmp/S_HUMAN_SIZED.c @@ -0,0 +1,2 @@ +#include <size_types.h> +int size() { return S_HUMAN_SIZED; } diff --git a/lib/daemon/tmp/S_SOMEWHAT_LARGE.c b/lib/daemon/tmp/S_SOMEWHAT_LARGE.c new file mode 100644 index 0000000..6721b89 --- /dev/null +++ b/lib/daemon/tmp/S_SOMEWHAT_LARGE.c @@ -0,0 +1,2 @@ +#include <size_types.h> +int size() { return S_SOMEWHAT_LARGE; } diff --git a/lib/daemon/tmp/airlock.c b/lib/daemon/tmp/airlock.c new file mode 100644 index 0000000..4908338 --- /dev/null +++ b/lib/daemon/tmp/airlock.c @@ -0,0 +1,95 @@ +#include <bboard.h> +#include <cfg.h> +#include <cgi.h> +#include <clean_up.h> +#include <clock.h> +#include <commands.h> +#include <comp.h> +#include <compat.h> +#include <config.h> +#include <council.h> +#include <daemons.h> +#include <deputies.h> +#include <dirs.h> +#include <domains.h> +#include <events.h> +#include <files.h> +#include <flags.h> +#include <function.h> +#include <global.h> +#include <iips.h> +#include <lib.h> +#include <link.h> +#include <localtime.h> +#include <logs.h> +#include <lvs.h> +#include <modules.h> +#include <mssp.h> +#include <mudlib.h> +#include <network.h> +#include <news.h> +#include <objects.h> +#include <origin.h> +#include <parse_com.h> +#include <parser_error.h> +#include <post.h> +#include <pov.h> +#include <privs.h> +#include <props.h> +#include <rcp.h> +#include <rooms.h> +#include <runtime_config.h> +#include <save.h> +#include <secrets.h> +#include <socket.h> +#include <socket_err.h> +#include <sockets.h> +#include <std.h> +#include <type.h> +#include <user.h> +#include <virtual.h> +#include <voting.h> +#include <armor_types.h> +#include <assessment.h> +#include <astar.h> +#include <body_types.h> +#include <boobytraps.h> +#include <build_types.h> +#include <climb.h> +#include <combat_messages.h> +#include <damage_types.h> +#include <gossip.h> +#include <graphics.h> +#include <jump.h> +#include <magic.h> +#include <magic_protection.h> +#include <marriage.h> +#include <materials.h> +#include <meal_types.h> +#include <medium.h> +#include <message_class.h> +#include <motion.h> +#include <mouth_types.h> +#include <position.h> +#include <race.h> +#include <respiration_types.h> +#include <rounds.h> +#include <size_types.h> +#include <soul.h> +#include <stargate.h> +#include <talk_type.h> +#include <terrain_types.h> +#include <vendor_types.h> +#include <vision.h> +#ifndef airlock +#define airlock "DEFINED_D: undefined" +#endif + +mixed defcheck(){ +int err; +mixed ret; +err = catch( ret = airlock ); +if(err) ret = "DEFINED_D: error"; +else if(undefinedp(ret)) ret = "DEFINED_D: undefined"; +return ret; +} \ No newline at end of file diff --git a/lib/daemon/tmp/bridge.c b/lib/daemon/tmp/bridge.c new file mode 100644 index 0000000..57d688d --- /dev/null +++ b/lib/daemon/tmp/bridge.c @@ -0,0 +1,95 @@ +#include <bboard.h> +#include <cfg.h> +#include <cgi.h> +#include <clean_up.h> +#include <clock.h> +#include <commands.h> +#include <comp.h> +#include <compat.h> +#include <config.h> +#include <council.h> +#include <daemons.h> +#include <deputies.h> +#include <dirs.h> +#include <domains.h> +#include <events.h> +#include <files.h> +#include <flags.h> +#include <function.h> +#include <global.h> +#include <iips.h> +#include <lib.h> +#include <link.h> +#include <localtime.h> +#include <logs.h> +#include <lvs.h> +#include <modules.h> +#include <mssp.h> +#include <mudlib.h> +#include <network.h> +#include <news.h> +#include <objects.h> +#include <origin.h> +#include <parse_com.h> +#include <parser_error.h> +#include <post.h> +#include <pov.h> +#include <privs.h> +#include <props.h> +#include <rcp.h> +#include <rooms.h> +#include <runtime_config.h> +#include <save.h> +#include <secrets.h> +#include <socket.h> +#include <socket_err.h> +#include <sockets.h> +#include <std.h> +#include <type.h> +#include <user.h> +#include <virtual.h> +#include <voting.h> +#include <armor_types.h> +#include <assessment.h> +#include <astar.h> +#include <body_types.h> +#include <boobytraps.h> +#include <build_types.h> +#include <climb.h> +#include <combat_messages.h> +#include <damage_types.h> +#include <gossip.h> +#include <graphics.h> +#include <jump.h> +#include <magic.h> +#include <magic_protection.h> +#include <marriage.h> +#include <materials.h> +#include <meal_types.h> +#include <medium.h> +#include <message_class.h> +#include <motion.h> +#include <mouth_types.h> +#include <position.h> +#include <race.h> +#include <respiration_types.h> +#include <rounds.h> +#include <size_types.h> +#include <soul.h> +#include <stargate.h> +#include <talk_type.h> +#include <terrain_types.h> +#include <vendor_types.h> +#include <vision.h> +#ifndef bridge +#define bridge "DEFINED_D: undefined" +#endif + +mixed defcheck(){ +int err; +mixed ret; +err = catch( ret = bridge ); +if(err) ret = "DEFINED_D: error"; +else if(undefinedp(ret)) ret = "DEFINED_D: undefined"; +return ret; +} \ No newline at end of file diff --git a/lib/daemon/tmp/bushes.c b/lib/daemon/tmp/bushes.c new file mode 100644 index 0000000..17deb58 --- /dev/null +++ b/lib/daemon/tmp/bushes.c @@ -0,0 +1,95 @@ +#include <bboard.h> +#include <cfg.h> +#include <cgi.h> +#include <clean_up.h> +#include <clock.h> +#include <commands.h> +#include <comp.h> +#include <compat.h> +#include <config.h> +#include <council.h> +#include <daemons.h> +#include <deputies.h> +#include <dirs.h> +#include <domains.h> +#include <events.h> +#include <files.h> +#include <flags.h> +#include <function.h> +#include <global.h> +#include <iips.h> +#include <lib.h> +#include <link.h> +#include <localtime.h> +#include <logs.h> +#include <lvs.h> +#include <modules.h> +#include <mssp.h> +#include <mudlib.h> +#include <network.h> +#include <news.h> +#include <objects.h> +#include <origin.h> +#include <parse_com.h> +#include <parser_error.h> +#include <post.h> +#include <pov.h> +#include <privs.h> +#include <props.h> +#include <rcp.h> +#include <rooms.h> +#include <runtime_config.h> +#include <save.h> +#include <secrets.h> +#include <socket.h> +#include <socket_err.h> +#include <sockets.h> +#include <std.h> +#include <type.h> +#include <user.h> +#include <virtual.h> +#include <voting.h> +#include <armor_types.h> +#include <assessment.h> +#include <astar.h> +#include <body_types.h> +#include <boobytraps.h> +#include <build_types.h> +#include <climb.h> +#include <combat_messages.h> +#include <damage_types.h> +#include <gossip.h> +#include <graphics.h> +#include <jump.h> +#include <magic.h> +#include <magic_protection.h> +#include <marriage.h> +#include <materials.h> +#include <meal_types.h> +#include <medium.h> +#include <message_class.h> +#include <motion.h> +#include <mouth_types.h> +#include <position.h> +#include <race.h> +#include <respiration_types.h> +#include <rounds.h> +#include <size_types.h> +#include <soul.h> +#include <stargate.h> +#include <talk_type.h> +#include <terrain_types.h> +#include <vendor_types.h> +#include <vision.h> +#ifndef bushes +#define bushes "DEFINED_D: undefined" +#endif + +mixed defcheck(){ +int err; +mixed ret; +err = catch( ret = bushes ); +if(err) ret = "DEFINED_D: error"; +else if(undefinedp(ret)) ret = "DEFINED_D: undefined"; +return ret; +} \ No newline at end of file diff --git a/lib/daemon/tmp/field.c b/lib/daemon/tmp/field.c new file mode 100644 index 0000000..4feec34 --- /dev/null +++ b/lib/daemon/tmp/field.c @@ -0,0 +1,95 @@ +#include <bboard.h> +#include <cfg.h> +#include <cgi.h> +#include <clean_up.h> +#include <clock.h> +#include <commands.h> +#include <comp.h> +#include <compat.h> +#include <config.h> +#include <council.h> +#include <daemons.h> +#include <deputies.h> +#include <dirs.h> +#include <domains.h> +#include <events.h> +#include <files.h> +#include <flags.h> +#include <function.h> +#include <global.h> +#include <iips.h> +#include <lib.h> +#include <link.h> +#include <localtime.h> +#include <logs.h> +#include <lvs.h> +#include <modules.h> +#include <mssp.h> +#include <mudlib.h> +#include <network.h> +#include <news.h> +#include <objects.h> +#include <origin.h> +#include <parse_com.h> +#include <parser_error.h> +#include <post.h> +#include <pov.h> +#include <privs.h> +#include <props.h> +#include <rcp.h> +#include <rooms.h> +#include <runtime_config.h> +#include <save.h> +#include <secrets.h> +#include <socket.h> +#include <socket_err.h> +#include <sockets.h> +#include <std.h> +#include <type.h> +#include <user.h> +#include <virtual.h> +#include <voting.h> +#include <armor_types.h> +#include <assessment.h> +#include <astar.h> +#include <body_types.h> +#include <boobytraps.h> +#include <build_types.h> +#include <climb.h> +#include <combat_messages.h> +#include <damage_types.h> +#include <gossip.h> +#include <graphics.h> +#include <jump.h> +#include <magic.h> +#include <magic_protection.h> +#include <marriage.h> +#include <materials.h> +#include <meal_types.h> +#include <medium.h> +#include <message_class.h> +#include <motion.h> +#include <mouth_types.h> +#include <position.h> +#include <race.h> +#include <respiration_types.h> +#include <rounds.h> +#include <size_types.h> +#include <soul.h> +#include <stargate.h> +#include <talk_type.h> +#include <terrain_types.h> +#include <vendor_types.h> +#include <vision.h> +#ifndef field +#define field "DEFINED_D: undefined" +#endif + +mixed defcheck(){ +int err; +mixed ret; +err = catch( ret = field ); +if(err) ret = "DEFINED_D: error"; +else if(undefinedp(ret)) ret = "DEFINED_D: undefined"; +return ret; +} \ No newline at end of file diff --git a/lib/daemon/tmp/fluffster.c b/lib/daemon/tmp/fluffster.c new file mode 100644 index 0000000..0efd258 --- /dev/null +++ b/lib/daemon/tmp/fluffster.c @@ -0,0 +1,95 @@ +#include <bboard.h> +#include <cfg.h> +#include <cgi.h> +#include <clean_up.h> +#include <clock.h> +#include <commands.h> +#include <comp.h> +#include <compat.h> +#include <config.h> +#include <council.h> +#include <daemons.h> +#include <deputies.h> +#include <dirs.h> +#include <domains.h> +#include <events.h> +#include <files.h> +#include <flags.h> +#include <function.h> +#include <global.h> +#include <iips.h> +#include <lib.h> +#include <link.h> +#include <localtime.h> +#include <logs.h> +#include <lvs.h> +#include <modules.h> +#include <mssp.h> +#include <mudlib.h> +#include <network.h> +#include <news.h> +#include <objects.h> +#include <origin.h> +#include <parse_com.h> +#include <parser_error.h> +#include <post.h> +#include <pov.h> +#include <privs.h> +#include <props.h> +#include <rcp.h> +#include <rooms.h> +#include <runtime_config.h> +#include <save.h> +#include <secrets.h> +#include <socket.h> +#include <socket_err.h> +#include <sockets.h> +#include <std.h> +#include <type.h> +#include <user.h> +#include <virtual.h> +#include <voting.h> +#include <armor_types.h> +#include <assessment.h> +#include <astar.h> +#include <body_types.h> +#include <boobytraps.h> +#include <build_types.h> +#include <climb.h> +#include <combat_messages.h> +#include <damage_types.h> +#include <gossip.h> +#include <graphics.h> +#include <jump.h> +#include <magic.h> +#include <magic_protection.h> +#include <marriage.h> +#include <materials.h> +#include <meal_types.h> +#include <medium.h> +#include <message_class.h> +#include <motion.h> +#include <mouth_types.h> +#include <position.h> +#include <race.h> +#include <respiration_types.h> +#include <rounds.h> +#include <size_types.h> +#include <soul.h> +#include <stargate.h> +#include <talk_type.h> +#include <terrain_types.h> +#include <vendor_types.h> +#include <vision.h> +#ifndef fluffster +#define fluffster "DEFINED_D: undefined" +#endif + +mixed defcheck(){ +int err; +mixed ret; +err = catch( ret = fluffster ); +if(err) ret = "DEFINED_D: error"; +else if(undefinedp(ret)) ret = "DEFINED_D: undefined"; +return ret; +} \ No newline at end of file diff --git a/lib/daemon/tmp/foo.txt b/lib/daemon/tmp/foo.txt new file mode 100644 index 0000000..27afd21 --- /dev/null +++ b/lib/daemon/tmp/foo.txt @@ -0,0 +1 @@ +This file intentionally left blank. diff --git a/lib/daemon/tmp/grunthol.c b/lib/daemon/tmp/grunthol.c new file mode 100644 index 0000000..27e051d --- /dev/null +++ b/lib/daemon/tmp/grunthol.c @@ -0,0 +1,95 @@ +#include <bboard.h> +#include <cfg.h> +#include <cgi.h> +#include <clean_up.h> +#include <clock.h> +#include <commands.h> +#include <comp.h> +#include <compat.h> +#include <config.h> +#include <council.h> +#include <daemons.h> +#include <deputies.h> +#include <dirs.h> +#include <domains.h> +#include <events.h> +#include <files.h> +#include <flags.h> +#include <function.h> +#include <global.h> +#include <iips.h> +#include <lib.h> +#include <link.h> +#include <localtime.h> +#include <logs.h> +#include <lvs.h> +#include <modules.h> +#include <mssp.h> +#include <mudlib.h> +#include <network.h> +#include <news.h> +#include <objects.h> +#include <origin.h> +#include <parse_com.h> +#include <parser_error.h> +#include <post.h> +#include <pov.h> +#include <privs.h> +#include <props.h> +#include <rcp.h> +#include <rooms.h> +#include <runtime_config.h> +#include <save.h> +#include <secrets.h> +#include <socket.h> +#include <socket_err.h> +#include <sockets.h> +#include <std.h> +#include <type.h> +#include <user.h> +#include <virtual.h> +#include <voting.h> +#include <armor_types.h> +#include <assessment.h> +#include <astar.h> +#include <body_types.h> +#include <boobytraps.h> +#include <build_types.h> +#include <climb.h> +#include <combat_messages.h> +#include <damage_types.h> +#include <gossip.h> +#include <graphics.h> +#include <jump.h> +#include <magic.h> +#include <magic_protection.h> +#include <marriage.h> +#include <materials.h> +#include <meal_types.h> +#include <medium.h> +#include <message_class.h> +#include <motion.h> +#include <mouth_types.h> +#include <position.h> +#include <race.h> +#include <respiration_types.h> +#include <rounds.h> +#include <size_types.h> +#include <soul.h> +#include <stargate.h> +#include <talk_type.h> +#include <terrain_types.h> +#include <vendor_types.h> +#include <vision.h> +#ifndef grunthol +#define grunthol "DEFINED_D: undefined" +#endif + +mixed defcheck(){ +int err; +mixed ret; +err = catch( ret = grunthol ); +if(err) ret = "DEFINED_D: error"; +else if(undefinedp(ret)) ret = "DEFINED_D: undefined"; +return ret; +} \ No newline at end of file diff --git a/lib/daemon/tmp/mansion.c b/lib/daemon/tmp/mansion.c new file mode 100644 index 0000000..255ccd4 --- /dev/null +++ b/lib/daemon/tmp/mansion.c @@ -0,0 +1,95 @@ +#include <bboard.h> +#include <cfg.h> +#include <cgi.h> +#include <clean_up.h> +#include <clock.h> +#include <commands.h> +#include <comp.h> +#include <compat.h> +#include <config.h> +#include <council.h> +#include <daemons.h> +#include <deputies.h> +#include <dirs.h> +#include <domains.h> +#include <events.h> +#include <files.h> +#include <flags.h> +#include <function.h> +#include <global.h> +#include <iips.h> +#include <lib.h> +#include <link.h> +#include <localtime.h> +#include <logs.h> +#include <lvs.h> +#include <modules.h> +#include <mssp.h> +#include <mudlib.h> +#include <network.h> +#include <news.h> +#include <objects.h> +#include <origin.h> +#include <parse_com.h> +#include <parser_error.h> +#include <post.h> +#include <pov.h> +#include <privs.h> +#include <props.h> +#include <rcp.h> +#include <rooms.h> +#include <runtime_config.h> +#include <save.h> +#include <secrets.h> +#include <socket.h> +#include <socket_err.h> +#include <sockets.h> +#include <std.h> +#include <type.h> +#include <user.h> +#include <virtual.h> +#include <voting.h> +#include <armor_types.h> +#include <assessment.h> +#include <astar.h> +#include <body_types.h> +#include <boobytraps.h> +#include <build_types.h> +#include <climb.h> +#include <combat_messages.h> +#include <damage_types.h> +#include <gossip.h> +#include <graphics.h> +#include <jump.h> +#include <magic.h> +#include <magic_protection.h> +#include <marriage.h> +#include <materials.h> +#include <meal_types.h> +#include <medium.h> +#include <message_class.h> +#include <motion.h> +#include <mouth_types.h> +#include <position.h> +#include <race.h> +#include <respiration_types.h> +#include <rounds.h> +#include <size_types.h> +#include <soul.h> +#include <stargate.h> +#include <talk_type.h> +#include <terrain_types.h> +#include <vendor_types.h> +#include <vision.h> +#ifndef mansion +#define mansion "DEFINED_D: undefined" +#endif + +mixed defcheck(){ +int err; +mixed ret; +err = catch( ret = mansion ); +if(err) ret = "DEFINED_D: error"; +else if(undefinedp(ret)) ret = "DEFINED_D: undefined"; +return ret; +} \ No newline at end of file diff --git a/lib/daemon/tmp/space.c b/lib/daemon/tmp/space.c new file mode 100644 index 0000000..23d3627 --- /dev/null +++ b/lib/daemon/tmp/space.c @@ -0,0 +1,95 @@ +#include <bboard.h> +#include <cfg.h> +#include <cgi.h> +#include <clean_up.h> +#include <clock.h> +#include <commands.h> +#include <comp.h> +#include <compat.h> +#include <config.h> +#include <council.h> +#include <daemons.h> +#include <deputies.h> +#include <dirs.h> +#include <domains.h> +#include <events.h> +#include <files.h> +#include <flags.h> +#include <function.h> +#include <global.h> +#include <iips.h> +#include <lib.h> +#include <link.h> +#include <localtime.h> +#include <logs.h> +#include <lvs.h> +#include <modules.h> +#include <mssp.h> +#include <mudlib.h> +#include <network.h> +#include <news.h> +#include <objects.h> +#include <origin.h> +#include <parse_com.h> +#include <parser_error.h> +#include <post.h> +#include <pov.h> +#include <privs.h> +#include <props.h> +#include <rcp.h> +#include <rooms.h> +#include <runtime_config.h> +#include <save.h> +#include <secrets.h> +#include <socket.h> +#include <socket_err.h> +#include <sockets.h> +#include <std.h> +#include <type.h> +#include <user.h> +#include <virtual.h> +#include <voting.h> +#include <armor_types.h> +#include <assessment.h> +#include <astar.h> +#include <body_types.h> +#include <boobytraps.h> +#include <build_types.h> +#include <climb.h> +#include <combat_messages.h> +#include <damage_types.h> +#include <gossip.h> +#include <graphics.h> +#include <jump.h> +#include <magic.h> +#include <magic_protection.h> +#include <marriage.h> +#include <materials.h> +#include <meal_types.h> +#include <medium.h> +#include <message_class.h> +#include <motion.h> +#include <mouth_types.h> +#include <position.h> +#include <race.h> +#include <respiration_types.h> +#include <rounds.h> +#include <size_types.h> +#include <soul.h> +#include <stargate.h> +#include <talk_type.h> +#include <terrain_types.h> +#include <vendor_types.h> +#include <vision.h> +#ifndef space +#define space "DEFINED_D: undefined" +#endif + +mixed defcheck(){ +int err; +mixed ret; +err = catch( ret = space ); +if(err) ret = "DEFINED_D: error"; +else if(undefinedp(ret)) ret = "DEFINED_D: undefined"; +return ret; +} \ No newline at end of file diff --git a/lib/daemon/tmp/start.c b/lib/daemon/tmp/start.c new file mode 100644 index 0000000..8d1e1a4 --- /dev/null +++ b/lib/daemon/tmp/start.c @@ -0,0 +1,95 @@ +#include <bboard.h> +#include <cfg.h> +#include <cgi.h> +#include <clean_up.h> +#include <clock.h> +#include <commands.h> +#include <comp.h> +#include <compat.h> +#include <config.h> +#include <council.h> +#include <daemons.h> +#include <deputies.h> +#include <dirs.h> +#include <domains.h> +#include <events.h> +#include <files.h> +#include <flags.h> +#include <function.h> +#include <global.h> +#include <iips.h> +#include <lib.h> +#include <link.h> +#include <localtime.h> +#include <logs.h> +#include <lvs.h> +#include <modules.h> +#include <mssp.h> +#include <mudlib.h> +#include <network.h> +#include <news.h> +#include <objects.h> +#include <origin.h> +#include <parse_com.h> +#include <parser_error.h> +#include <post.h> +#include <pov.h> +#include <privs.h> +#include <props.h> +#include <rcp.h> +#include <rooms.h> +#include <runtime_config.h> +#include <save.h> +#include <secrets.h> +#include <socket.h> +#include <socket_err.h> +#include <sockets.h> +#include <std.h> +#include <type.h> +#include <user.h> +#include <virtual.h> +#include <voting.h> +#include <armor_types.h> +#include <assessment.h> +#include <astar.h> +#include <body_types.h> +#include <boobytraps.h> +#include <build_types.h> +#include <climb.h> +#include <combat_messages.h> +#include <damage_types.h> +#include <gossip.h> +#include <graphics.h> +#include <jump.h> +#include <magic.h> +#include <magic_protection.h> +#include <marriage.h> +#include <materials.h> +#include <meal_types.h> +#include <medium.h> +#include <message_class.h> +#include <motion.h> +#include <mouth_types.h> +#include <position.h> +#include <race.h> +#include <respiration_types.h> +#include <rounds.h> +#include <size_types.h> +#include <soul.h> +#include <stargate.h> +#include <talk_type.h> +#include <terrain_types.h> +#include <vendor_types.h> +#include <vision.h> +#ifndef start +#define start "DEFINED_D: undefined" +#endif + +mixed defcheck(){ +int err; +mixed ret; +err = catch( ret = start ); +if(err) ret = "DEFINED_D: error"; +else if(undefinedp(ret)) ret = "DEFINED_D: undefined"; +return ret; +} \ No newline at end of file diff --git a/lib/daemon/tmp/town.c b/lib/daemon/tmp/town.c new file mode 100644 index 0000000..636db3a --- /dev/null +++ b/lib/daemon/tmp/town.c @@ -0,0 +1,95 @@ +#include <bboard.h> +#include <cfg.h> +#include <cgi.h> +#include <clean_up.h> +#include <clock.h> +#include <commands.h> +#include <comp.h> +#include <compat.h> +#include <config.h> +#include <council.h> +#include <daemons.h> +#include <deputies.h> +#include <dirs.h> +#include <domains.h> +#include <events.h> +#include <files.h> +#include <flags.h> +#include <function.h> +#include <global.h> +#include <iips.h> +#include <lib.h> +#include <link.h> +#include <localtime.h> +#include <logs.h> +#include <lvs.h> +#include <modules.h> +#include <mssp.h> +#include <mudlib.h> +#include <network.h> +#include <news.h> +#include <objects.h> +#include <origin.h> +#include <parse_com.h> +#include <parser_error.h> +#include <post.h> +#include <pov.h> +#include <privs.h> +#include <props.h> +#include <rcp.h> +#include <rooms.h> +#include <runtime_config.h> +#include <save.h> +#include <secrets.h> +#include <socket.h> +#include <socket_err.h> +#include <sockets.h> +#include <std.h> +#include <type.h> +#include <user.h> +#include <virtual.h> +#include <voting.h> +#include <armor_types.h> +#include <assessment.h> +#include <astar.h> +#include <body_types.h> +#include <boobytraps.h> +#include <build_types.h> +#include <climb.h> +#include <combat_messages.h> +#include <damage_types.h> +#include <gossip.h> +#include <graphics.h> +#include <jump.h> +#include <magic.h> +#include <magic_protection.h> +#include <marriage.h> +#include <materials.h> +#include <meal_types.h> +#include <medium.h> +#include <message_class.h> +#include <motion.h> +#include <mouth_types.h> +#include <position.h> +#include <race.h> +#include <respiration_types.h> +#include <rounds.h> +#include <size_types.h> +#include <soul.h> +#include <stargate.h> +#include <talk_type.h> +#include <terrain_types.h> +#include <vendor_types.h> +#include <vision.h> +#ifndef town +#define town "DEFINED_D: undefined" +#endif + +mixed defcheck(){ +int err; +mixed ret; +err = catch( ret = town ); +if(err) ret = "DEFINED_D: error"; +else if(undefinedp(ret)) ret = "DEFINED_D: undefined"; +return ret; +} \ No newline at end of file diff --git a/lib/daemon/tmp/wiz_hall.c b/lib/daemon/tmp/wiz_hall.c new file mode 100644 index 0000000..20a1616 --- /dev/null +++ b/lib/daemon/tmp/wiz_hall.c @@ -0,0 +1,95 @@ +#include <bboard.h> +#include <cfg.h> +#include <cgi.h> +#include <clean_up.h> +#include <clock.h> +#include <commands.h> +#include <comp.h> +#include <compat.h> +#include <config.h> +#include <council.h> +#include <daemons.h> +#include <deputies.h> +#include <dirs.h> +#include <domains.h> +#include <events.h> +#include <files.h> +#include <flags.h> +#include <function.h> +#include <global.h> +#include <iips.h> +#include <lib.h> +#include <link.h> +#include <localtime.h> +#include <logs.h> +#include <lvs.h> +#include <modules.h> +#include <mssp.h> +#include <mudlib.h> +#include <network.h> +#include <news.h> +#include <objects.h> +#include <origin.h> +#include <parse_com.h> +#include <parser_error.h> +#include <post.h> +#include <pov.h> +#include <privs.h> +#include <props.h> +#include <rcp.h> +#include <rooms.h> +#include <runtime_config.h> +#include <save.h> +#include <secrets.h> +#include <socket.h> +#include <socket_err.h> +#include <sockets.h> +#include <std.h> +#include <type.h> +#include <user.h> +#include <virtual.h> +#include <voting.h> +#include <armor_types.h> +#include <assessment.h> +#include <astar.h> +#include <body_types.h> +#include <boobytraps.h> +#include <build_types.h> +#include <climb.h> +#include <combat_messages.h> +#include <damage_types.h> +#include <gossip.h> +#include <graphics.h> +#include <jump.h> +#include <magic.h> +#include <magic_protection.h> +#include <marriage.h> +#include <materials.h> +#include <meal_types.h> +#include <medium.h> +#include <message_class.h> +#include <motion.h> +#include <mouth_types.h> +#include <position.h> +#include <race.h> +#include <respiration_types.h> +#include <rounds.h> +#include <size_types.h> +#include <soul.h> +#include <stargate.h> +#include <talk_type.h> +#include <terrain_types.h> +#include <vendor_types.h> +#include <vision.h> +#ifndef wiz_hall +#define wiz_hall "DEFINED_D: undefined" +#endif + +mixed defcheck(){ +int err; +mixed ret; +err = catch( ret = wiz_hall ); +if(err) ret = "DEFINED_D: error"; +else if(undefinedp(ret)) ret = "DEFINED_D: undefined"; +return ret; +} \ No newline at end of file diff --git a/lib/daemon/types.c b/lib/daemon/types.c new file mode 100644 index 0000000..426a322 --- /dev/null +++ b/lib/daemon/types.c @@ -0,0 +1,136 @@ +#include <lib.h> +#include <save.h> +#include <armor_types.h> +#include <body_types.h> +#include <boobytraps.h> +#include <build_types.h> +#include <damage_types.h> +#include <graphics.h> +#include <meal_types.h> +#include <message_class.h> +#include <mouth_types.h> +#include <position.h> +#include <respiration_types.h> +#include <size_types.h> +#include <terrain_types.h> +#include <vendor_types.h> + +#include <assessment.h> +#include <climb.h> +#include <jump.h> +#include <magic.h> +#include <medium.h> +#include <motion.h> +#include <rounds.h> +#include <soul.h> +#include <talk_type.h> +#include <vision.h> +#include <parser_error.h> + +inherit LIB_DAEMON; + +string *types = ({ "vendor_types", "terrain_types", "size_types", + "respiration_types", "position", "mouth_types", "message_class", + "meal_types", "graphics", "damage_types", "build_types", + "boobytraps", "body_types", "armor_types" }); + +string *configs = ({ "assessment", "climb", "jump", + "magic", "medium", "motion", "rounds", + "soul", "talk_type", "vision", "parser_error" }); + +mapping Types = ([]); + +int eventReadTypes(); +int eventReadConfigs(); + +static void create() { + ::create(); + SetSaveFile(SAVE_TYPES); + if(!Types) Types = ([]); + call_out((: eventReadTypes :), 10); + call_out((: eventReadConfigs :), 10); +} + +int eventReadTypes(){ + if(!Types) Types = ([]); + foreach(string file in types){ + string *tmp_arr; + string tmp,s1,s2,s3,s4; + int d1,d2,d3, i, j; + if(!Types[file]) Types[file] = ([]); + tmp = read_file("/include/"+file+".h"); + if(!tmp) tmp = read_file("/secure/include/"+file+".h"); + tmp_arr = explode(tmp,"\n"); + foreach(string line in tmp_arr){ + i = sscanf(line,"#define %s (%s<<%s)",s1,s2,s3,s4); + if( i != 4) j = sscanf(line,"#define %s (%s<<%s)",s1,s2,s3); + if(i != 4 && j != 3) continue; + s1 = trim(s1); + s2 = trim(s2); + s3 = trim(s3); + d1 = atoi(s2); + d2 = atoi(s3); + d3 = ( d1 << d2 ); + Types[file][d3] = s1; + } + } + eventSave(); + return 1; +} + +int eventReadConfigs(){ + if(!Types) Types = ([]); + foreach(string file in configs){ + string *tmp_arr; + string tmp,s1,s2,s3; + int d1, i, j; + if(!Types[file]) Types[file] = ([]); + tmp = read_file("/include/"+file+".h"); + if(!tmp) tmp = read_file("/secure/include/"+file+".h"); + tmp_arr = explode(tmp,"\n"); + foreach(string line in tmp_arr){ + line = trim(line); + i = sscanf(line,"#define %s %s %s)",s1,s2,s3); + if( i != 3) j = sscanf(line,"#define %s %s",s1,s2); + if(i != 3 && j != 2) continue; + s1 = trim(s1); + s2 = trim(s2); + d1 = atoi(s2); + Types[file][d1] = s1; + } + } + eventSave(); + return 1; +} + +varargs mixed GetTypes(string str){ + if(!str) return Types + ([]); + if(Types[str]) return Types[str] + ([]); + else return 0; +} + +mixed eventCalculateTypes(string typename, int type){ + string *ret_arr = ({}); + string ret = ""; + + foreach(string canonical_name in keys(Types)){ + if(grepp(canonical_name, typename)){ + typename = canonical_name; + break; + } + } + if(!Types[typename]) return 0; + + if(member_array(typename,types) != -1){ + foreach(int key, string val in Types[typename]){ + if(type & key) ret_arr += ({ Types[typename][key] }); + } + return ret_arr; + } + + foreach(int key, string val in Types[typename]){ + if(type == key) ret = Types[typename][key]; + } + return ret; +} + diff --git a/lib/daemon/unique.c b/lib/daemon/unique.c new file mode 100644 index 0000000..3488ce5 --- /dev/null +++ b/lib/daemon/unique.c @@ -0,0 +1,58 @@ +/* /daemon/unique.c + * from the Dead Souls LPC Library + * handles making objects unique + * created by Descartes of Borg 950529 + */ + +#include <lib.h> +#include <save.h> + +inherit LIB_DAEMON; + +private mapping Objects; +static string SaveFile; + +static void create() { + daemon::create(); + SaveFile = save_file(SAVE_UNIQUE); + Objects = ([]); + if(file_exists(SaveFile)){ + RestoreObject(SaveFile); + } +} + +void eventTouchObject() { + string fn; + + if( !(previous_object()->GetUnique()) ) return; + fn = base_name(previous_object()); + Objects[fn] = time(); + SaveObject(SaveFile); +} + +object GetUniqueCopy(string fn, int rare) { + object ob; + int x; + + if( !Objects[fn] ) { + ob = new(fn); + if( !(ob->GetUnique()) ) return ob; + else Objects[fn] = time(); + SaveObject(SaveFile); + return ob; + } + x = time() - Objects[fn]; + if( x < (86400 * rare) ) return 0; + if( ob = new(fn) ) Objects[fn] = time(); + SaveObject(SaveFile); + return ob; +} + +mapping GetUniques(){ + return copy(Objects); +} + +mapping ResetUniques(){ + Objects = ([]); + SaveObject(SaveFile); +} diff --git a/lib/daemon/verbs.c b/lib/daemon/verbs.c new file mode 100644 index 0000000..14311ed --- /dev/null +++ b/lib/daemon/verbs.c @@ -0,0 +1,86 @@ +/* /daemon/verbs.c + * from the Dead Souls Object Library + * handles the loading and rehashing of verbs + * created by Descartes of Borg 951016 + */ + +#include <lib.h> +#include "include/verbs.h" + +inherit LIB_DAEMON; + +private mapping Verbs; + +static void create() { + daemon::create(); + Verbs = ([]); + SetNoClean(1); + eventReloadVerbs(); +} + +static int ScheduledVerbLoad(string *cache){ + foreach(string verb in cache){ + object ob; + string *verb_list; + if( ob = find_object(verb) ) catch(ob->eventDestruct()); + if( !catch(ob = load_object(verb)) && ob ) { + if( !(verb_list = ob->GetVerbs()) ) + verb_list = ({ explode(verb, "/")[<1][0..<3] }); + else if(verb_list && ob->GetSynonyms()) { + verb_list += ob->GetSynonyms(); + } + Verbs += expand_keys(([ verb_list : verb ])); + } + } +} + +varargs void eventReloadVerbs(mixed val) { + string *cache, *verbs = 0; + string verb; + + if( arrayp(val) ) verbs = filter(val, (: GetValidVerb($1) :)); + else if( stringp(val) ) { + if( strlen(val) > 2 && val[<2..] == ".c" ) val = val[0..<3]; + if( GetValidVerb(val) ) verbs = ({ val }); + if( !verbs ) return; + } + else { + string dir; + verbs = ({}); + 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 :)); + } + } + cache = ({}); + foreach(verb in verbs){ + object ob; + string *verb_list; + cache += ({ verb }); + verbs -= ({ verb }); + if(sizeof(cache) > 9 || !sizeof(verbs)){ + call_out("ScheduledVerbLoad", 1, copy(cache)); + cache = ({}); + } + } + return; +} + +string GetErrorMessage(string verb) { + if( !Verbs[verb] ) return 0; + else return Verbs[verb]->GetErrorMessage(); +} + +int GetValidVerb(string verb) { + if(!strsrch(verb, DIR_VERBS) || !strsrch(verb, DIR_VERBS)) return 1; + else return 0; +} + +mapping GetVerbs() { return copy(Verbs); } +mixed GetVerb(string str) { return Verbs[str]; } diff --git a/lib/daemon/weather.c b/lib/daemon/weather.c new file mode 100644 index 0000000..092083a --- /dev/null +++ b/lib/daemon/weather.c @@ -0,0 +1,8 @@ +#include <lib.h> + +inherit LIB_DAEMON; + +static void create() { + daemon::create(); +} + diff --git a/lib/doc/BASICS b/lib/doc/BASICS new file mode 100644 index 0000000..4872f38 --- /dev/null +++ b/lib/doc/BASICS @@ -0,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 --git a/lib/doc/CREDITS b/lib/doc/CREDITS new file mode 100644 index 0000000..b63296b --- /dev/null +++ b/lib/doc/CREDITS @@ -0,0 +1,42 @@ +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 permission to bundle MudOS, and + Wodan for his permission to bundle FluffOS and his + ongoing support therein. + +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 Cygwin 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, Tricky, + K'Azdean, Raudhrskal, Alecksy, Sryth, Theophage, Vega, + Chaos, Mordain, Nilrin, Quixadhal, and Kalinash. + +Appreciation of: Jayren, Kaylus, Arianrhod, Nosmo, Pyro, Abby, Balmung, + Aten, Metiscus, Garfield, Javelin, Alensin, Daelas, Root, + Kristus, Zeus, Dastuun, Detah, Nulvect, Memrosh, Luna, + Kuurus, Darloth, Albiorix, Aransus, Thecreator, Irmo, Toninno, + Silvyar, Tyche, Grandfather, Atrus, Shasarak, Amok, Hamlet, + Scott, Silenus, Hells, Torak, and Ardneh 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. +* Thanks to murpe.com for letting me test on their box. +* Thanks to JohnOC for letting me test on his box. + +Much gratitude to playtesters: Karri, Aten, Tacitus, Kaatil, Atomic, + Daelas, Greymantle/Grunk, Ratfinger. + +Also: Xyzzy He Is Cool, and Kalinash is super duper awesome. + +Cratylus @ Dead Souls +July 2006 +Last update: September 2014 diff --git a/lib/doc/RELEASE_NOTES b/lib/doc/RELEASE_NOTES new file mode 100644 index 0000000..3350eb0 --- /dev/null +++ b/lib/doc/RELEASE_NOTES @@ -0,0 +1,2634 @@ +---- 3.9 --- +- Released 2020-04-08 +- Fixed a problem that prevented objects from being in the inventory of /realms/ objects. +- Added a cheats book to provide a walkthrough of the basic quests. +- Miscellaneous tidying up. +- Fixed some bugs in bonuses when wearing off. +- Fixed some stuff around fishing, added a bait item. +- Added disease cure to James in the medical office in town. + +---- 3.8.6 --- +- Released 2014-11-03 +- Fixed poison never wearing off. +- Added a few quests. +- Added Get/SetNoSink to rooms and items in case something shouldn't sink. +- Fixed some wonky stuff regarding falling and climbing. +- Added command: dispel +- Added valid_event() sefun. +- Miscellaneous tweaks and fixes. +- Shortened training and teaching times. +- Lowered XP cost for death. +- Added quest cheat sheets (/doc/cheats) +- Fixed some eval cost problems in the file and function indexing daemons + that were causing lag for some people. + +---- 3.8.2 --- +- Released 2014-09-28 +- FluffOS driver now 2.23-ds03, improving Wolfpaw detection. +- Added sefun: read_big_file() +- Updated i3 router code. +- Added GUEST_ALLOWED to config.h and "guestallowed" token to mudconfig. +- Added PLAYER_INTERTELL_ALLOWED to config.h and "playerintertell" + token to mudconfig. +- Added Quixadhal's fix to outgoing intermud tells. +- Added a block of incoming intermud tells to players without intermud privs. +- Miscellaneous minor and typo fixes. + +---- 3.8.1 --- +- Released 2013-08-07 +- FluffOS driver now 2.23-ds02, including fix for socket crasher. + +---- 3.8 --- +- Released 2013-07-20 +- Added some checks to RACES_D for zeroed arrays/mappings. +- Updated IMC2 with Davion/Kiasyn's latest MudBytes IP. +- Disconnected the campus and town domains, applied new coordinates. + +---- 3.7a7 --- +- Released 2012-03-09 +- Fixed CreWeb issue when using recent versions of Firefox. +- I3 keepalives now work more properly after a rename with mudconfig. + +---- 3.7a6 --- +- Released 2012-03-08 +- Updated the IP address of MudBytes's IMC2 to reflect their Dallas move. +- Windows muds should reconnect to i3 more sanely now after a rename. +- Fixed confusing message when failing to pick a lock on a door. +- h_ftpd now uses HOST_IP. +- Updated gridconfig so that resets are more flexible. +- Cleaned up some room locations across domains. +- Corrected beggar's map. +- Started tutorial area. +- Tidied up some virtuals to be more portable across domains. +- SetNoObviousExits() now works more intuitively in rooms. +- The connection daemons now ask whether the player uses a screenreader + so that the mapping can be disabled for them if so. +- Added Kalinash's XP debt system. +- If you die really hard or in quick succession, your player will no longer + have their healing freeze. +- Added SinkRoom functionality to LIB_FALL. +- Cleaned up and reconciled most grid and virtuals functionality. +- Harmonized outdoors areas and virtual skies with SetSkyDomain() for rooms. +- Fixed a bug in add_maps(). +- Added boardwalk and seaside bar to town. +- Fixed barkeep menus and added special menu functionality. + +---- 3.6 --- +- Released 2011-08-17 +- Driver: FluffOS 2.23 with very minor tweaks. +- Driver: Odd sockets crash with instances should no longer happen. +- Somewhat improved BOOKS_D efficiency and minimized likelihood of + duplicated chapter names. +- Fixed centaur body parts. +- Exempted "read" and "title" from special parsing. +- Fixed a problem when using the town virtual areas. +- Fixed confusing message when picking a lock on a door in the same room as + another door. +- Liveupgrade server updated to avoid asphyxia problem. + +---- 3.4 --- +- Released 2011-06-08 +- Disabled instances.c by default to avoid a sockets based driver crasher. +- Added Quix's socket_names() sanitization to avoid a sockets based + driver crasher. +- Fixed peculiar bug in PLAYERS_D (thx quix!) + +---- 3.3a3 --- +- Released 2011-04-11 +- Updated a socket check. +- Fixed mud-based earmuffs. +- The timezone command can now take "none" as an argument. +- Fixed ticktock. +- Forest orcs should now be less noisy. +- Fixed polyglottism for NPC's. + +---- 3.3a1 --- +- Released 2011-04-02 +- Driver: FluffOS 2.22 with minor tweaks. +- Driver: Included updated Windows driver. +- Fixed peculiar respiration type issue (thx Nuku). + NOTE: This will probably kill everything in your mud if you update + while it is up. + +---- 3.2 --- +- Released 2011-02-17 +- Removed intergossip and intercre remappings to avoid log errors. +- LIB_TELLER: you can now "exchange gold for silver" without specifying + amount, this will exchange all the gold you're carrying. You can also + "exchange all for dollars" to attempt to exchange all your various + carried currency into dollars. +- ASSIST can now "hist admin" +- Driver: now includes fix for more than 256 global vars. + Note: The Windows driver is still 2.20. +- ASSIST can now write on the arch board. + +---- 3.1a11 --- +- Released 2011-01-02 +- Crash trace no longer has Pinkfish codes. +- Receiving a packet from a mud previously marked offline will mark it online. +- Mapped router-side "intergossip" to "broken_gossip" to limit confusion. +- Mapped router-side "intercre" to "broken_cre" to limit confusion. +- NPC's with inventories no longer have their stuff duplicated when they are + reloaded by a persistent room. +- Added command: shadows +- Driver: updated to 2.21 plus minor tweaks (Including nfa's GMCP fix) + Note: The Windows driver is still 2.20. +- The command "rotatelogs" now takes an option to force the rotation. +- Fixed a runtime error in player saves if a carried object has an + AddSave pointing to a nonexistent variable. +- Fixed array element mismatch in CHAT_D remote chans. +- SetItems() and AddItem() now work ok on NPC's (thx to HoriceGump for the + suggestion). +- Dummy items in storerooms (like doors) are no longer browseable. + +---- 3.1a10 --- +- Released 2010-08-15 +- Guest is now excluded from PLAYERS_D autopurging. +- Fixed some errant /n's (thx Aleksy!) +- i3router: IRN channel updates are less noisy now, excluding "listening". + 3 years late, but hey, I got to it eventually, Aidil. +- IMC2 server: fixed odd problem with authentication reported by Aleksy, + Quixadhal, and Kline. +- CreWeb now accepts passwords that contain the characters: ~ ! @ # $ % ^ & * + ( ) _ + { } | : " < > ? ` - = [ ] \ ; ' , . / +- Fixed some channel confusion regarding parties. +- Corrected some ambiguity in "nopeer" versus "no peer" for rooms. +- Added LIB_AIM. +- Added some gadgets to the science complex. + +---- 3.1a9 --- +- Released 2010-07-25 +- Driver: Updated to Fluffos 2.20 plus minor tweaks. +- Teachers and trainers now stop instructing you when you're + fighting them or if you've picked them up. +- MB IMC2 channels renamed in CHAT_D. +- IMC2 server: fixed line endings, emotes, minor runtimes and channel parsing. +- IMC2 client: uses CRLF now rather than LFCR if version 2.1 is specified. +- "chan add all" now works. +- Fixed a crasher when querying for binary save dir. +- Receiving messages while in the pager while in charmode no longer + aborts the pager. +- Receiving a message while typing a long line in charmode no longer obscures + the message on next keypress. +- Quitting the pager while in (suspended) charmode unsuspends charmode. + +---- 3.0 --- +- Released 2009-12-31 +- Driver: added Kalinash's fix for Solaris on 64 bit SPARC. +- Driver: added Kalinash's fix for BSD math. +- Added commands: anchor, unanchor +- Note on anchoring: it is intentional that admins can move around + if they wish while anchored, but creators cannot. +- Removed commands: mc, isql, language +- The help command now handles aliased commands. +- Corrected some quirks in editing and the detection of in_input() + that caused some entered characters to be invisible in charmode. +- Standardized help output for commands. Note that the standard is now + for the help message to be a string returned from GetHelp(), not + a write() or a message() or whatever crazy thing occurs to people + in the middle of the night in 1994. +- The "boards" command now indicates the location of the boards listed. +- Admins can now use the gag command to prevent a user from using channels. +- Fixed a password retrieval problem in ftp and hftp. + NOTE: Some newer ftp clients default to epsv when negotiating passive + ftp mode. This breaks hftp. If you're having weird problems using + passive mode and hftp, then right after logging into hftp, type: + epsv off + passive on + bin +- Fixed a double-prompt problem and some cosmetic issues when reprompting. +- Made the harmony of best balance in tell.c for justice. +- The <muds> channel no longer double-pumps on instances. +- Fixed CheckEncounter double-pump in LIB_NPC. +- Tidied up slightly confusing events reporting. +- Fixed a problem with "EverFill" things like rivers running out. +- Fixed a problem with undrinkable floods and floods that couldn't + be used to fill flasks. +- Vendors now buy items at half value, if they can. +- The Windows version now automatically disables IMC2 if the + server IP becomes invalid. + +---- 2.11a22 --- +- Released 2009-11-01 +- Removed unnecessary casts. +- It's possible to peer into virtual rooms now. +- Added a sample ranged weapon: /domains/default/armor/pcannon.c +- Added Tricky's A* implementation (doesn't really do anything yet). +- Improved the thoroughness of warmboots. +- Improved back-compatibility with MudOS v22.2b14-ds. + +---- 2.11a21 --- +- Released 2009-10-24 +- Under some conditions, insufficient time was provided during + a reconnect to allow the reconnection. This has been corrected. +- Driver is now a slightly modified FluffOS 2.18. +- Fixed history list recalculation. +- Number parsing is no longer done for add_action()'s. +- IMC2 tells now propagate properly to instances. + +---- 2.11a20 --- +- Released 2009-10-08 +- Added some rooms to campus lab. +- Fixed a problem in delayed command queues. +- The wizmap is now not caching by default, to avoid + gaps in mapping. +- Slightly streamlined the character generation process, removing + questions that are rarely answered and not requiring "pick" to + precede the race and class. +- Added the ob, name, and obname elements to the MagicProtection class in + magic_protection.h in order to better track and control multiple + magic protections. See /powers/spells/buffer.c for an example of + a spell that checks these in order to avoid stacking. +- Fixed IMC2 colors. +- Exempted file commands from Diku "2.thing" parsing rules. +- The lib now explicitly ignores resets that originate from the + driver, in order to avoid odd over-aggressive resets. +- Any npc can now be a command-obeying zombie, not just "sentient" npc's. +- Fixed some problems with effective vision and peering. +- It's no longer possible to follow someone if they are invisible or + if you are lying down. +- Cleaned up some parsing of LIB_FLASK and LIB_INSTALL. +- Zombies can be re-raised after they are re-killed now. +- Finger now works properly on instances. Note that fingering + *across* instances does not work, and needs be done through + intermud finger. +- It is now more difficult to accidentally drown in the sea east of town. +- Added gendered title (e.g. "the Countess") handling to the + advancement process. +- Added sefun: comma() + +---- 2.11a19 --- +- Released 2009-09-26 +- Added a more efficient auto-mapping drone. +- Rooms can now specify their own coords, for example: + SetCoordinates("-3000,3000,0"); +- Map daemon now periodically sweeps cached maps and updates + their info. +- Parse matching now also checks for emotes. +- Added commands: vaarsuvius, cursefilter, homedir, homeroom +- Log rotation now better accommodates unix file semantics. +- The "reply time" threshold for deleting the reply addressee + is now a full day. +- Fixed a thingy that cancelled "more" in charmode after a + few seconds or so of reading +- QCS now handles SetRead better. +- The IMC2 password should now get clobbered more rarely. +- Fixed a parsing ambiguity in "get from". +- The instances daemon now properly reloads its configuration on boot. +- User names on instances are now more thoroughly reserved. + +---- 2.11a18 --- +- Released 2009-09-13 +- Fixed minor bugs in parsing. +- Individualized a few logs to prevent instances stepping on + each other during log rotation. +- Fixed some logic in the probability lab. + +---- 2.11a17 --- +- Released 2009-09-11 +- Driver: Added Wodan's fix for NEW-ENVIRON. +- Fixed skill problem in CLASSES_D. +- i3router: Added Aidil's irn-mudlist-req and a check for when + a "disconnected" mud sends a packet. +- Fixed problems in anyterm connections. +- Re-enabled number.thing parsing (when did this break?). +- Improved "thing number" parsing, e.g. "get purple thing 2" now works. +- The pause/unpause commands will now also work on players who aren't logged in. +- Pausing or decre-ing a creator now also boots them from creweb. +- Fixed imc2 remote who replies. +- The help command now translates synonyms to the target verbs, to + cut down on verb guessing. +- The lines command has been verbified to simplify its synonymization + and documentation. +- Fixed channel emote problem reported by Flumpy. +- Command matching no longer arbitrarily picks the first matching + command if there is more than one. +- Added command: bugs, queue +- Fixed a problem in PLAYERS_D that prevented suicides from working. +- Fixed a problem in INSTANCES_D that double-pumped channel messages. +- Driver: The parser now defaults to the first matching object in + commands with ambiguous hits. You can "get key" rather than "get + first key" and this is parsed in the driver rather than the lib. + +---- 2.11a9 --- +- Released 2009-07-19 +- Driver is now a slightly modified pre-release Fluffos 2.17. +- Fixed remote channel problem in CHAT_D. +- /secure/include/mssp.h is now somewhat more individualized. +- Added commands: screenlock, weigh +- Driver: Added partial support for telopts NEW-ENVIRON (rfc 1572). + A connection that supports this will cause the driver to call + the receive_environ() apply in LIB_CONNECT, sending the env data + as a single string. +- Added support for using anyterm (http://anyterm.org) as + a client while still identifying player IP's. +- Fixed a problem listing individual items from vendors. +- Replaced broken xterm definition map in TERMINAL_D with ansi def. +- Updated IMC2 client, also added current Server01 IP. +- Instances now update each other more regularly about player info. +- More than one local instance now better supported. +- Added a PLAYER_CLASS entry to class files in /secure/cfg/classes + so that there can be classes players don't get automatic access to. +- Fixed parsing conflict in LIB_FLASHLIGHT and LIB_BATTERY. + +---- 2.10 --- +- Released 2009-06-01 +- Minor fixes to 2.9a19 +- Added pwiping to PLAYERS_D. +- Minor faq updates. + +---- 2.9a19 --- +- Released 2009-05-25 +- The idle command can now be used without an argument as + a connection keepalive. +- i3router: IRN chanlist now tries to prune duplicated entries in the + data packet before transmission. +- i3router: channel-add packets with invalid channel types are + now rejected. +- The mudconfig command now handles mud name and port changes. +- IMC2 channels now have their remote names mapped to their local + names automatically, avoiding the need to hardcode the maps in CHAT_D. +- Added commands: chan, rotatelogs +- Updated the ced editor with some important fixes. It can now be + enabled with mudconfig (mudconfig ced on). Note that this is a highly + experimental editor, so it automatically backs up any file you edit + with it. See the help info for: ced, bk, restore, charmode +- The windows install no longer needs the absolute path to be + c:\ds if the new default runmud.bat and mudos.win32 are used. +- Instances on Windows are now supported. +- Telopts MSSP support added, plaintext MSSP improved. + See: http://dead-souls.net/ds-admin-faq.html#145 +- i3router: the "listening" portion of irn channel updates is + no longer sent. +- i3router: blacklisting of networks is now possible. +- i3router: muds that attempt to reconnect more than once per second + are subject to automatic temporary graylisting. +- Fixed an exploit reported by Ideysus that allowed local creators to + spoof intermud packets. +- Removed command: mfinger +- Updated the performance score calculation to make it more consistent. +- i3router: packet floods are now handled somewhat more efficiently. +- Added sefun: format_page2() +- Alleviated some misfortunes in instance tells. +- The mudconfig command now works properly with imc2 password setting + and the secrets daemon. +- General cleanup of superfluous debugging statements. +- Substring searching added to ced. + +---- 2.9a18 --- +- Released 2009-05-05 +- Fixed a problem with the new reply aging system. +- Fixed a bug in liveupgrading that overwrote SECRETS_H. + +---- 2.9a17 --- +- Released 2009-05-01 +- Driver is now a slightly modified FluffOS 2.16. +- Converted structs to mappings in CLASSES_D. +- Fixed CLASSES_D bug that inverted the position of "importance" and + "average starting level" of classes. +- Instances now share local channels. +- Users on different instances can now tell to each other. +- Users on different instances can now get "finger" info on each other. +- Users on different instances can now see each other in "who". +- Added commands: instconfig, deviate, destfile +- New players can't create a character if the same name is used + on another instance. +- Added sefuns: remote_users(), local_users() +- The actions map elements in LIB_ROOM now actually fire based on + their individual "chance" rather than the overall ActionChance + (thx Raudhrskal!). +- IMC2 tells now work like i3 tells, no need to use the "imc2" command. +- AUTO_WIZ set above 1 now forces new users to become creators, rather + than providing the choice to do so. +- IP addresses of users are no longer displayed to creators on + AUTO_WIZ muds. +- Users on different instances can now shout to each other. +- Fixed problems in the router code when a mud's fd is 0. +- IMC2 client host/port info now does a better job of being correct. +- IRN nodes now periodically send each other mud and chan lists. +- Some password thingies like i3 and IMC2 are now handled by a + secrets daemon, to improve security. +- The non-quitting non-net-dead destruction of users is now announced + and logged (for example, if you "dest" a creator). +- Suicide notes now save somewhere more reasonable. +- Paths in read.cfg and write.cfg can now have wildcard files. +- Added STATS_D and SKILLS_D. They are meant to keep track of which + stats and skills have been used in the mud, and when possible, + maintain information the "importance" of a stat to a race and a + skill to a class, derived by RACES_D and CLASSES_D respectively. + This allows a centralized repository of stat/skill information + that the DEVIATION_D can rely on for deviation calculation. +- Added a stat deviation system. A player can now have an improved + stat class, but at a cost of some percentage of earned XP. See: + help deviation +- The hist command now reverts to the old "query the chat cache" + behavior if the mud doesn't log the type of channel being queried. + Note that by default, remote channels are not logged. +- Fixed an odd display problem in the hist command. +- SNOOP_D can now ignore ip's (good for running bot tests from a known + ip), and admins can now be monitored if set to be so explicitly, + overriding GLOBAL_MONITOR == 2. +- Fixed userlist generation in PLAYERS_D in an instance. +- Since IMC2 servers do not handle usernames with spaces well, IMC2_D + now strips spaces from names before sending channel messages. +- Stargates can now register with the stargate daemon only if they are + in /domains/ or /secure/, to avoid dozens of accidental newbie + stargates to creator realms. +- The prompt command without an argument now returns the raw prompt + string, rather than setting a null prompt. +- Added improvements to the colors command by Raudhrskal. +- Cleaned up the lines command. +- Reply target is now reset on login, and ages out after 15 minutes + of not replying and not receiving a message from that target. +- Inventory output now has worn things at the bottom, and wielded + things just above worn things. +- SetEncounter() on aggro npc's now keys on GetInvis() rather than + query_invis() for somewhat more predictable results when trying + to sneak around. +- Players on instances no longer get booted off during warmboots. + +---- 2.9a16 --- +- Released 2009-03-12 +- The "locate" command is now "i3locate". +- Prettified the tabbed file completion stuff. +- Armor now makes more of an effort to resolve ambiguous + targets, such as "wear ring" when both hands can take a ring. +- Added BaseLimbs to armor in order to resolve ambiguous situations + involving sets of limbs, such as a shield which needs a paired + arm and hand, plus torso. +- LIB_WORN_STORAGE now uses inherited LIB_BASE_ARMOR and + LIB_BASE_STORAGE as inherited code to avoid discrepancies in + behavior in duplicated code. Note this means that the majority + of the code for armor is now in LIB_BASE_ARMOR and the majority of the + code for "things that hold other things" is now in LIB_BASE_STORAGE. +- Added GetMaxSkillLevel() to LIB_ABILITIES to consolidate the + calculation that was previously duplicated by multiple commands. +- Fixed a bug that allowed skill levels in negative numbers. +- Cleaned up some behavior with ANOXIA damage and respiration types. +- Commands that queued when in combat (such as 'inventory') used + to hang indefinitely if you chased your quarry into a "no attack" + room. This is no longer the case. +- Persistent rooms no longer spawn excess copies of unique + or MaxClone objects. +- The fighter's hall in Ylsrim is now a proper, working class hall + with class joining and training available. +- Fixed a bug in the flood object that generated performance + problems over time. +- Fixed a bug in the flood object that failed to set the respiration + type correctly when a room became completely flooded. +- Fixed a problem with warmboots that caused some doors to + have issues being locked/unlocked/manipulated. +- Objects that drop into "void" due to a problem with their + environment now are sent to individualized "virtual voids" if + the ROOMS_D can resolve that. This avoids some rare circumstances + where a huge number of npc's and players fall into a single + "void" room and mayhem ensues. +- Fixed a conflict in QCS with customdefs.h that made it difficult + to modify your workroom. +- The goto command now handles global coordinates, eg: goto 2,2 +- The command "imc2 list" now only returns muds currently connected, + to avoid a timeout receiving data from a long list of defunct muds. +- Fixed a problem in scoped heartbeats that prevented players + from autosaving. +- COMPAT BUSTER: debug() now just takes two args, making it + more like tc(). Example: + debug on + eval debug("My skills: "+identify(this_player()->GetSkills()),"red") +- It is now possible to carry living things. Creators can get creatures + of any size, but players can only pick up creatures smaller than them + by at least 2 size slots. Note that picking up an NPC you have not + befriended will make it attack you. +- Fixed a bug in updating virtual rooms. +- You can now run multiple instances of the same code without clobbering + savefiles. If you set ENABLE_INSTANCES in config.h, then reboot, + objects will add the mud's port to their save name, for example + "rooms.6666.o" rather than "rooms.o". Obviously this means that the + different instances need to be on different ports. For an example + of how to do it: help instances +- Clepius can now extract bullets, if you give him an excision slip. +- Fixed a carried weight conflict in vehicles and mounts. +- tell_room() now works on string names of virtual rooms. +- Fixed a parsing peculiarity when trying to read one book when + others are available. +- Added a hint book to Kim's bookstore. +- If you were in a virtual room during a warmboot, you are returned + to it after the warmboot completes. +- Creators can now keep track of things sneaking in and out of their + inventory with call me->SetParanoia("inventory_monitoring", 1). They + can also keep track of where they might be silently moved to with + call me->SetParanoia("move_monitoring", 1). Note that these are not + foolproof, and the proper way to deal with mischief is not paranoia + but extreme violence and harsh language. +- The "which" command now identifies aliases, add_actions, etc. +- Finally nailed a mysterious data overwrite problem in PLAYERS_D. + +---- 2.9a15 --- +- Liveupgrade only. +- Intermediate release to handle special liveupgrade issues. + +---- 2.9a14 --- +- Released 2009-02-04 +- Driver is now a slightly modified FluffOS 2.15. +- Added an experimental screen-mode inheritable editor, see + LIB_CEDIT and: help ced . It's still a bit quirky and buggy, and + incomplete (handles wrapping poorly, doesn't do search/replace, + etc). For now it's a proof-of-concept/prototype with saving disabled + (thx to Tricky and Raudhrskal for advice on terminal control). Will + not work without charmode. Will not work without FluffOS 2.15-ds*. +- Added sefuns: system_month(), system_day(), write2() +- Added sefuns from Chaos@Lost Souls: levenshtein_distance(), + damerau_levenshtein_distance() +- Added commands: commandecho, profile, timezone, efuns, sefuns, lfuns +- Driver: added ANSI_SUBSTITUTE define to comm.c in order to + control which character is substituted with in NO_ANSI. +- It's now possible to re-engage in combat with an opponent you've + previously ignored. +- Rooms now attempt to set their own respiration type based on + their medium, if their respiration type is not already set. +- The longcat command now tries a bit harder to display ludicrously + large files. +- The commands dsversion and noclip work again. +- Various conflicts in coordinate setting fixed. +- Mitigated a compat buster in QCS involving customdefs. +- Miscellaneous performance tweaks to make DS friendlier to use + on weak hardware. Tested on a Pentium 133MHz and + an UltraSparcII 300MHz. +- Changed the name "automap" to "minimap". Automapping will mean + something else in later releases. +- Implemented a "minimum performance" threshold for certain + resource-intensive features. The performance score of a system is + determined by CPU time taken at boot. The MIN_PERF define in config.h + establishes the minimum score required for "heavy" features like + wizmapping and file/function indexing. This system allows people with + weak machines to use DS without tons of errors, and it allows people + with fast machines to enjoy the fancy stuff by default. +- Fixed a problem in FUNCTION_D that prevented the lib from having + function data when running on Windows. +- Warmboot no longer hoses up people in charmode. +- MASTER_D now forces a quick shutdown if it detects one of the following: + * Exhausted file descriptors. + * Eval cost error cascade loop. +- Driver: added efun remove_charmode() +- The hist command now includes timestamps and accepts a number + argument for how many lines to display. +- Fixed local_time() to accept a string timezone. +- Commands like "date" and "people" now have output customized to the + player's timezone. +- Driver: fixed command() efun so that success is nonzero + when running on Windows. +- Charmode now works on Windows (see command() above). +- The hist command now also handles: say, whisper, yell, shout. +- Fixed a bug in LIB_BODY that caused decapitation during combat + to occur twice, resulting in two severed heads. +- The "nightmare shell" now does tabbed command completion, + tabbed filename completion, tabbed object completion, and + up/down-arrow command recall when in charmode. +- The findfun command now also identifies efuns and sefuns, and + tries to suggest other possible matches based on differing + case and format. It also now takes a substring flag to search + efuns, sefuns, and lfuns for possible matches. +- Guarding works properly again. You can no longer take Kim's + cash register. + +---- 2.9a13 --- +- Released 2009-01-04 +- Finally got around to indenting everything consistently. +- Improved handling of missing/broken rooms in ROOMS_D. +- The noclip command now enables "noclip mode" rather than + being a command for moving in a specific direction. While in + noclip mode you can move through closed doors and walls if + the rooms daemon is aware of an adjacent room in that direction, + even with no explicit exit there. +- Fixed some vaguenesses in death notices. +- Virtual rooms now immediately unload when the last object in their + inventory leaves. This allows, for example, launching a torpedo that + travels 200 rooms without now having to have 200 totally useless + rooms hanging around in memory. +- Added commands: reprompt, charmode, keepalive +- The reprompt mode redraws your prompt when you receive + messages, similar to how Diku muds do so. Note + that reprompt mode looks awful on most mud clients...it's + intended for folks with "single pane" clients, like people + using a default Linux telnet client. +- The charmode command puts you into character mode, so that + your input is received on a per-keystroke basis, rather than + a per-line basis. This allows for stuff like using up and down + arrows for command recall. This is for single-pane clients + only! Most mud clients will fail to handle this...and they + may fail very horribly. This mode is experimental and + somewhat broken at the moment. Unsupported on Windows muds. +- Fixed bug in LIB_BODY that caused overlapping armor to increase + damage received. +- The default player prompt now includes status info. +- Driver: Fixed a bug in comm.c that failed to reset to linemode + if the object with the get_char() target function was destructed. +- Some damage limits have been raised. You may find your npc's + and weapons doing substantially more damage. See MAX_POWER and + MAX_SKILL in LIB_COMBAT. +- i3router: Connection freakouts by blacklisted muds are now handled + more gracefully. +- Added sefuns: present_file(), present_bonus(), query_unique_name() +- Driver: added efuns: query_charmode(), remove_get_char(), + send_nullbyte() (thanks, Raudhrskal!) +- AUTO_WIZ no longer prevents class selection. +- Unified command history code into LIB_HISTORY and rewrote a bit in + order to use mappings rather than arrays, to avoid ambiguities. +- The customdefs.h file for creators and builders is now in their + area/ directory. This is to make it easier to migrate such an + area to domains/ once it is complete. +- Consolidated the calculation of max health points into LIB_RACE, + fixing some issues with strangely overhealthy npc's during combat + (eg kitchen rats). +- Added Raudhrskal's implementation of Daelaskai's evaldefs idea + (thx guys). +- If a thing doesn't have SetDamagePoints() called on it, it will + not deteriorate when it receives damage. +- Items in perfect condition no longer indicate their condition. +- Implemented basic persistence for rooms. If a room is SetNoClean(1), + has SetPersist(1); in create() and RestoreObject(); on the + following line, then when it reloads, it will restore into + its inventory whatever was left there...even across reboots. + For an example, see /domains/town/room/secret.c +- Containers can also have persistence set, but *BEWARE*. Any + item you set to be persistent in this way should be unique + in the mud. Having multiple clones of an object with persistent + inventory may result in hilarity, but very likely also + confusion and sadness in an open mud. For an example of an item with + persistent inventory, see /domains/town/obj/charity.c + *IMPORTANT NOTE*: carryable items that are made persistent will + appear to behave oddly when you "reload" and "update" them, and + modify them with QCS. This is because QCS does not actually + destroy them right away, and in fact for a brief time you have + two of the same item in the mud, stepping on each other's persistent + inventory. Expect to see weirdness when using QCS with persistent items. +- Land-based rooms can now have respiration types other than R_AIR. + For an example, see: /domains/default/room/vacuum.c + You can also test by issuing the commands: + goto /domains/default/room/menagerie + eval return HERE->SetRespirationType(R_VACUUM) + and seeing most everything drop dead within seconds. + +---- 2.9a12 --- +- Released 2008-11-26 +- DECAY_D is now more resistant to runtime-error failures. +- Minor improvements to stress testing. +- At the advice of Silenus, switched the world grid from string based + multidimensional mappings to bitshifted integer based multidimensional + mappings, which not only cut down mapping depth by 35%, but also + increased lookup speed by more than an order of magnitude. Many + thanks to Silenus for holding my hand through figuring out how to + bash the bits. +- Portals no longer fall or sink. +- Warmboots deal more firmly now with situations where very many + rooms are loaded. +- The imc2 channel "ichat" is no longer enabled by default due to + a change in their content policy making them no longer PG-13. To enable + it for yourself, you would type: call me->AddChannel("ichat") +- New creators now automatically "wizmap" rather than "automap". +- Added Town Well quest. +- Added LIB_FLOW as an example of a "flooding" type object. + +---- 2.9a11 --- +- Released 2008-11-20 +- Driver is now a slightly modified FluffOS 2.14. +- Fixed a parser crasher in the driver that occurs under + unusually heavy loads. +- Parsing ambiguity in grenades fixed up a bit. +- Bots now handle too-bright and too-dark rooms more sensibly. +- Bots now handle paged displays more sensibly. +- Room inventories will now accept a function for the number + of items. For an example of a random number of rats between + 1 and 5, see /domains/town/room/mansion_room7.c +- You can now limit the number of of clones of an npc or an item + that the mud will load as inventory. If a sword's base file + has SetMaxClones(15), then a room will not try to load the + sword in its inventory if the mud already has 15 of these swords + cloned somewhere. Note that SetMaxClones() in a base file + will cause the object not to be saved in a player's inventory + when they quit. For an example, see /domains/default/armor/wristcomp.c +- Fixed a problem in CreWeb editing with wrapping and line numbering + that displayed incorrect line numbers. +- Fixed a driver crasher involving the destruction of objects + while they are in a verb parsing loop. +- Fixed a problem with passing functionals to SetAction() in rooms + (thx, Raudhrskal!). +- Added a prototype overland map system. It's mostly in the testing + phase, as it tends to lag the mud somewhat. Creators can enable + automatic mapping with: wizmap on +- Minor fixes of rooms with grid conflicts. +- Added command: wizmap +- Fixed a problem with the npc guard system that prevented more + than one guard from being able to guard in the same room. +- Fixed what is essentially borken behavior in Set/GetItems + that have a functional. However, I suspect that this behavior has + actually been assimilated all over the place as being a standard, + so the effect here is a possible *slight* compat buster, with + SetItems that have functionals displaying output twice. +- Added a portal generator, and cake to go along with it. +- Added new domain: /domains/cave as an undergound orc stronghold. + It's mostly done, though I'll be adding more to it eventually. + Note that this is an example of "an area where normal creators and + overpowered players are not welcome". This is a feature I'm + testing to see how feasible it is to prevent casual-abuse type + creators from being too much of a nuisance on an open mud. + +---- 2.9a10 --- +- Released 2008-10-19 +- Fixed peculiar problem in the get verb that sometimes made + it seem as though an open container was closed, for creators. +- It is now exceedingly difficult to fight or + defend when not standing, or when your vision is poor. +- Added command: gridconfig +- Minor grid conflicts cleaned up. +- Fixed a permissions issue that prevents doors from showing up + for players without read access to an area. +- Value for meals now defaults to base cost. +- Reaping tidied up: REAPER_D now fires up at boot time, and + reap_other() will scour for environmentless clones whether + the driver is FluffOS or not. +- Players are now addressable by their race. +- Added a "max attacks per heartbeat" throttle to combat.c to + avoid having creators in godmode with ludicrous stats causing + the mud to seize up fighting each other. +- Fixed a too long eval in warmbooting. +- LIB_COMMAND now handles multi-word bare exits ("foo bar" rather than + "go foo bar"). +- Added Kalinash's driver mod to override new() with clone_object() if the + clone_object() sefun exists. +- valid_edit() in LIB_BOARD now works more sensibly and denies edit + and deletion access to people who should not have it. +- "give all to X" now works like selling and putting: worn and wielded + items are not automatically surrendered. +- Fixed some parsing issues with booby traps. +- clone_object() is now overridden with a throttle to prevent + accidental cloning cascades from creator objects. +- Added MEMUSE_SOFT_LIMIT and MEMUSE_HARD_LIMIT. These are disabled + by default. They are intended to provide some control over memory + usage, for folks on commercial hosting or resource-starved computers. + For details, see: help config +- Added driver fix for check_memory() crasher. +- Added max player limits in LIB_CONNECT based on compile-time- + detected file descriptor max. +- Fixed a crasher in the driver that occurs under very rare + high-network-load stress. + +---- 2.9a9 --- +- Released 2008-09-24 +- Driver is now a slightly modified pre-release FluffOS 2.14v27. +- Revolvers no longer change caliber spontaneously. +- Basic IMC2 server added. +- IRN "not my mud" endless loop when more than 2 nodes is fixed. +- Added "chanlist-req" to the router. You can now get a chanlist + without having to reboot. +- Packet floods from a given mud are now detected and temporarily + ignored. +- The IMC2 ichat channel has been added as a default channel for + creators in /secure/cmds/admins/encre.c +- The finger daemon no longer reports an incorrect birth year + when queried repeatedly. +- Added commands: mudinfo, enemies, showgrid, whereis +- Quest-dependent advancement can be disabled in config.h by + setting REQUIRE_QUESTING to 0. +- Automatic advancement (i.e. not having to go to Dirk) can + be enabled by setting AUTO_ADVANCE to 1. +- Added "questrequired" and "autoadvance" to mudconfig command. +- The table of quest and experience points required for + advancement is now maintained in PLAYERS_D, not Dirk. +- By default DS will now handle automatic advancement well beyond + level 100. Note that there has been no balancing attempted + beyond level 20. You will need to seriously adjust your mud's balance if + you allow advancement past level 20. +- Bug fixed in quitting while invis. +- Added a cgi gateway to the built-in webserver that allows you + to connect to the mud with a java client. To enable it: + ----------------------- + mudconfig http port 8001 + mudconfig http disable + mudconfig cgi enable + mudconfig dirlist enable + mudconfig creweb enable + mudconfig http enable + ----------------------- + Then use your browser to connect to your mud's connection page + (for example, http://your.muds.address.com:8001/cgi/connection.html ) + NOTE: the mud www port does not have to be 8001. Change it to + whatever is appropriate for you. +- The dest verb now behaves like before. Desting of non-cloned + objects by using their file names is again unsupported. This + fixes problems with desting a singular among plurals. +- Some parsing issues in grenades fixed. They also do more + damage, but are limited to hurting the first dozen or so people. +- Added a flash policy server. To enable, uncomment the flash_policy line + in /secure/cfg/preload.cfg, redirect your mud server's port 843 to + your mud port + 3 (for example 6669, if your mud is on 6666), + and reboot your mud. +- Added MUDINFO_D to manage longterm intermud data (normal people + will not have any use for this). +- The answering machine now works again (when did this break??). +- Added ROOMS_D to keep track of the relative locations of rooms. This + is necessary for some activities that will involve distances, such as vehicle + combat in virtual areas. +- Added sefuns: coordinates(), calculate_coordinates(), + room_environment(), query_windows() +- Some rooms have been moved around to accommodate conflicts with + their coordinates. +- Only Firefox is supported with creweb. I can no longer afford to + try to keep up with every browser's idea of how to conduct itself. + If creweb isn't working and you aren't using Firefox, please use Firefox. +- The "noclip" command now accepts non-exit directions that have + an entry in ROOMS_D as having a room adjacent. +- Books now do not individually hold their data, but rather cache and + query with BOOK_D, to cut down on memory abuse and disk I/O costs. +- Fixed a bug in last_string_element() sefun that screwed up qcs doors. +- Added a zombie scroll to Oana's shop. +- General miscellaneous typo corrctions and minor bugfixes. +- Added Vega's SEASONS_D fixes. + +---- 2.8.5 --- +- Liveupgrade only. +- Intermediate release to handle special liveupgrade issues. + +---- 2.8.4 --- +- Released 2008-07-24 +- Merged 2.9a8 into the 2.8.x line. Due to the importance of some + security fixes, and since major changes have not yet been introduced + in 2.9, the improvements of 2.9a8 (unreleased) and below are being + folded into 2.8. +- Fixed odd door id problem reported by Tricky when warmbooting. +- Class data type removed from LIB_DOOR. +- Added commands: pwhere, vars +- Wizvision now lets creators see invisible creatures in a room. +- Accuracy and performance improvements to default parsing. +- Cleaned up and updated firearm code: targeting in a room full of + corpses is improved. Wounds no longer inflict continuing damage, + they simply interfere with player healing (NPC's heal normally). + Unless you are skilled with firearms, shooting an npc over and + over in rapid succession is extremely likely to miss. +- Fixed typo in PARTY_D. +- Healing is now largely dependent on whether you are hungry/thirsty, + with some modifiers for relevant stats like strength, luck, + and durability. Being asleep and drunk now actually do have a + positive effect on healing, as well as having the "faith" skill. + Overall this means healing *can* happen faster if you stay on + top of these items and don't catch flying bullets. However, if + you're not keeping fed and hydrated, healing will seem to have + got slower. + +---- 2.9a7 --- +- Released 2008-07-18 +- Driver: MSG_NOSIGNAL more promiscuously defined. +- Driver: extra checks added to avoid obscure high-load crashes. +- Parsing problem with doors and multiple keys fixed. +- Miscellaneous minor lib fixes. +- Improvements to sefun and warmboots to better interact with call_outs. +- Added commands: defines, types +- Fixed a bug that prevented receiving damage in a wielding limb. +- Prayer parsing system updated/fixed: clerics can now perform prayers + with targets. + +---- 2.9a6 --- +- Released 2008-07-14 +- Driver is now a customized FluffOS 2.12. +- Miscellaneous minor lib tweaks and fixes. +- Added command: noclip +- Fixed recursing paralysis bug in LIB_BODY. +- The netstat command now includes summary statistics. +- cardinal(), base_name(), and copy() now use efuns rather than sefuns + for improved performance. +- The reaper now uses get_garbage() for improved performance. +- The reaper is now more aggressive about spotting and cleaning + large garbage pileups. +- The call_out efun is now overridden with a sefun that checks + for excessive call_outs and autoblacklists suspected problems. + To tune the number of permitted call_outs, modify the new + MAX_CALL_OUTS param in config.h. Note that objects in /secure and + /daemon are exempted from this check. +- The update command no longer has a problem when you are mounted + on a creature or vehicle. + +---- 2.9a5 --- +- Released 2008-07-10 +- Driver: Fixed segfault for SPARC. +- Minor sefun fixes. + +---- 2.9a4 --- +- Released 2008-07-09 +- Fixed various runtimes in IMC2_D. +- Driver: Crasher due to object ref count flip is now prevented (thx Wodan!) +- Cleaned up some disharmonies in the reaper. + +---- 2.9a3 --- +- Released 2008-07-07 +- Added GUARD_D and LIB_GUARD to allow npc's to guard exits, + objects, and people without having to edit the room. For examples, + see /realms/template/area/npc/fighter.c and /domains/campus/npc/kim.c +- Driver: Added fix by Kalinash that avoids a crasher when dealing + with unloading blank files. +- The gag and mute commands can now accept keywords to indicate + whether you only want to mute/gag local channels or remote channels. +- The reaper now exempts http sockets. +- New defines daemon can identify things defined in standard includes. + Example: eval return DEFINES_D->GetDefine("ADMIN_EMAIL") + +---- 2.9a1 --- +- Released 2008-06-15 +- Fixed periodic check of preloaded objects. +- The command "resurrect" now also works on npc's. +- Added verbs for firearms: load, unload. +- Added verbs for chairs: swivel, rock. +- Driver (under Linux only) : Added enhancements by Kalinash that avoid + SIGPIPE crashes under heavy load and mass disconnections (thx dude). +- Driver: Added fixes by Kalinash that avoid segfaults under + extreme loads (woo Kali again!). +- Periodic check added to STARGATE_D to clear "stuck" gates. +- Spells are now in /powers/spells, to accommodate new systems + of powers such as psi and physical feats. +- Added smokable items: LIB_PIPE, LIB_CIGAR. +- Driver: fixed up plurals for "remains" and "glasses". +- Fixed name banishing in admintool. +- Player teaching fixed up. For now, only spells are teachable. +- Improved handling of corpse and severed limb id's. +- Creators retain their selected title upon reviving from death. +- Hazardous materials lab now requires players to solve a riddle + before letting them in. + +---- 2.8.2 --- +- Released 2008-06-25 +- Bundled driver is now Kalinash-improved. +- Empty log dirs made non-empty to handle fileroller better. +- query_os_type() fixed. + +---- 2.8.1 --- +- Released 2008-06-05 +- Fixed a bug in IMC2 that made all muds connect with the same name. +- Fixed inelegant handling of alcohol levels and their reporting. +- Newbie level checking is now more uniform across the lib. +- The "stop" verb can now be used to stop fighting. +- Missing /open directory added. +- Driver: source now compiles ok on Cygwin. (thanks, Tricky!) + +---- 2.8 --- +- Released 2008-06-01 +- Cleanup of debug statements. +- Fixed some typos. +- Fixed mangled enters display in obvious exits. + +---- 2.7a28 --- +- Released 2008-06-01 +- Various missing init()'s in Ylsrim & Praxis fixed. Note: those + are still unsupported areas, just kept for historical reasons. They + may eventually be dropped from the distribution. +- Driver: FluffOS updated to handle being compiled with DEBUG defined. +- Driver: Address server errors are now suppressed by default ( ADDRFAIL_NOTIFY + in comm.c ) +- New commands: godmode, wizvision, annoyblock. +- Warmboots are now even more thorough in their recursive loading. +- Bug in player description fixed. +- Finger daemon no longer divulges player email addresses except + to arches (top level admins). +- Whispering now happens in your "current language", not + your native language. +- eventMoveLiving() merged for both npc's and interactives in LIB_LIVING. + Odd messages from this function in LIB_STARGATE fixed. +- Input now checked for non-alphabet characters before being + command-matched. +- Global emotes can now be added by non-admin creators, if they are + members of the EMOTES group. + +---- 2.7a27 --- +- Released 2008-05-15 +- Fixed a crasher when reading zero-length files. +- Driver: Fixed a crasher when some command actions fail to return properly. +- The SetInventory refill now will replenish inventory when + some is missing, not just when all is gone. For an example, see + the new weapons rack in /domains/default/room/arena.c +- The blackjack table now uses "stand pat" rather than "stand" for + ending the game. This avoids amusing problems with physical posture. + +---- 2.7a26 --- +- Released 2008-05-04 +- Added sefun: containers() +- Sentients can now be asked about things, for example, + "ask dirk about leveling". Example: /domains/town/npc/dirk.c +- Added commands: praces, removeclasses, addclasses +- The new CLASS_SELECTION option in config.h controls whether + new players are asked to select a class when they create their + character. Disabled by default. To enable: mudconfig selectclass yes +- Fixed some odd defaults in class definition files. +- Fixed a bug in questing that failed to award quest points. +- XP for kills is now shared among party members if they + are in the same room as the kill. + +---- 2.7a25 --- +- Released 2008-04-24 +- Added periodic cleanup of channel mappings in the i3 router to + prevent peculiar runtimes when running for a long time. +- Fixed channel banning in the i3 router. +- The web server now handles POSTS where the boundary gets + split in separate packets (this caused mysterious hangs when + uploading some files but not others). + +---- 2.7a24 --- +- Released 2008-04-16 +- Creweb chanlogs now listed in "last modified" order. +- Virtual rooms now destructed on warm boots. +- Added day/night descs to outdoor town locations. +- Important npc's in town are now set to respawn after + 60 seconds, if killed or moved. See the SetInventory directive + in /domains/town/room/tavern.c for an example. + +---- 2.7a23 --- +- Released 2008-04-07 +- Warm boots no longer hang people in the process + of editing files. +- Various fixes to warm boots. +- Fixed bug in strings.c that broke QCS. +- Tells between invis cre's now behave more sensibly. + +---- 2.7a22 --- +- Released 2008-03-30 +- Fixed runtime in unknown INTERMUD_D packet handling. +- Fixed runtime in creweb logfile reading of empty files. +- Creators can now cast any spell known to SPELLS_D. Their + default spell level is extremely high. +- LIB_QUEST changes: variable name has been changed and is now + a mapping rather than a class. Quest-specific functions moved + out of LIB_PLAYER and into LIB_QUEST. RemoveQuest() is now + an option. +- Dummy object handling improved...the church elevator should + now work somewhat better. +- Taking over your char from a new session now logs in /log/enters. +- Added commands: warmboot, userload +- Windows users: FluffOS file operations tend to take a dramatically + longer time to complete on Windows than on UNIX. A warmboot, while + not disconnecting the users, may hang them for several minutes + such that they may consider it a "crash" of some sort. + +---- 2.7a20 --- +- Released 2008-03-26 +- Chan logs viewing added to creweb. +- The "muds" channel is no longer added to creators by default. +- The jade ring, powered scout armor, and training dummy now use TYPES_D + to work out the received damage type. + +---- 2.7a19 --- +- Released 2008-03-23 +- SERVICES_D now accurately reports current ports for active services. +- Locate requests now adequately hide invis players. +- The who command no longer counts color codes in title length. +- The blow that kills a creature in combat is now more correctly displayed. +- Fixed a parsing bug in dummy items that reported oddly abbreviated names. +- Fixed various problems with the timing of combat messages. +- Fixed bug in "hist tell" + +---- 2.7a18 --- +- Released 2008-03-23 +- Added sefun: telnet_privp() +- Added commands: unvirt, telnet (user must be in the TELNET group) +- Added TYPES_D to help decipher type names from their integer/bitshifted + designation: eval return TYPES_D->eventCalculateTypes("armor",196608) +- Doors are now knockable and yelling from the opposite side of a + closed door is audible. +- Fixed a bug in intermud-3 tells that allowed you to send tells + to disconnected muds. +- "muds" channel added to report connecting and disconnecting muds. +- "intermud" channel added to report finger, who, and locate requests. +- wild_card() no longer an lfun, consolidated as a sefun. +- Fixed problem in user_path() that caused recursion problems due + to the new "builder" player type. +- Added mouth types to races. +- Purged instances of the class data type from RACES_D. + +---- 2.7a16 --- +- Released 2008-03-16 +- Bundled driver is now a customized FluffOS 2.11 + +---- 2.7a14 --- +- Released 2008-03-13 +- Added example of an environmental suit: /domains/default/armor/scoutsuit.c +- Modified firearms code to include rifles: /domains/town/weap/m16rifle.c +- NPC's now try to shoot weapons they're wielding, if they're loaded. +- Removed out of date faqs. +- Tweaks and fixes to room, rocketpack, and position code. +- Fixed module id bug in Yautja wrist computer. +- eventDescribeEnvironment() moved to /lib/events/describe.c in order + to consolidate player/npc behavior, and to simplify things for people + wanting to customize room appearance. + +---- 2.7a13 --- +- Released 2008-03-09 +- Added commands: position, var, variables, cconv, cwgconv. +- Added sample virtual planet composed of sea bottom area, + underwater area, surface area, sky area, and outer space. +- Updated the sconv command to convert Smaug areas more sanely. +- Added verbs: swim, kneel. +- Rapid death occurs when air-breathing creatures are deprived of oxygen. +- Added a breathing device for exploring non-air environments: + /domains/default/armor/breather.c +- Added a rocket pack for traveling in space. Do NOT "activate" it in + space or you will accelerate out of control. "boost" only, for example + "boost +x+z" then to stop: "boost -x-z" +- Stargates added underwater and in outer space for convenient exploration. + Beware fatal anoxia. + +---- 2.7a12 --- +- Released 2008-03-03 +- IMC2 now supports who requests and tells. "imc2 tell joe@dead_souls_joe hello!" +- Driver workaround implemented for strip_colours() problem. +- Channels can now accept filters. The two built-in filters are colorize and morse + example: cre|colorize hello there! + This is not encouraged for use on intermud. CHANNEL_PIPES must be enabled. +- Builder-generated items fixed up to limit cheating. +- Added sefuns string_colors_old() and dbz_colors() +- Inheritables for living creatures modified to limit cheating by builders. +- MASTER_D can now accept some wildcards in read.cfg. +- Fixed up various lib systems that previously did not expect players to + have home directories. +- The source command will now accept the $N token in source files as a representation + of the player's key name. +- Added RESOLV_D to handle internet name lookups and caching. Use the "resolve" command + to look up names. +- Modified WGET_D to be more generic, added "wget" command for downloading arbitrary + files from the intertubes. + +---- 2.7a9 --- +- Released 2008-02-18 +- Added sefuns: efuns(), sefuns(), efun_exists(), sefun_exists(), estatep(). +- Build-specific verbs and commands moved to builders/ directories. +- Updated memcheck. +- Added commands: arealist, areaclone, areagoto. +- Modified QCS verbs to better handle non-creator builders. +- Added terminal_color() efun to the driver that behaves the + way the FluffOS 2.7 terminal_colour() used to work. +- Added support for the class data type in the identify() sefun. +- Builders now have a workroom and sample areas after logging in + after their addition to the builder group. +- NPC's in builder estates do not give XP when killed and do not deal damage to non- + estate NPC's. +- Items in builder estates are not worth money in shops. +- Weapons in builder estates are ineffective against normal opponents. +- Armor in builder estates affords little protection. + +---- 2.7a5 --- +- Released 2008-02-10 +- Added CreWeb system to allow web editing. See: help creweb +- Added sefuns: unpinkfish(), repinkfish(), socket_ip(), builderp(), web_translate(). +- The mudconfig command can now change the port numbers for inet servers. + +---- 2.7a1 --- +- Released 2008-01-18 +- No lib changes. +- Bundled driver is now a slightly modified FluffOS 2.9. + +---- 2.6.4 --- +- Released 2008-05-16 +- Fixed a parsing bug in dummy items that reported oddly abbreviated names. +- Fixed a crasher when reading zero-length files. +- Driver: Fixed a crasher when some command actions fail to return properly. +- Dummy object handling improved: church elevator should work ok. +- Command for liveupgrades improved for stability. +- Fixed some broken defaults in class files. + +---- 2.6.2 --- +- Released 2008-01-06 +- Fixed some confusing behavior with ":" and ";" as emote characters + in CHAT_D, as well as some confusing channel renaming. +- Fixed security bug that allowed an unprivileged creator access to privileged files. +- The goto command now handles virtual rooms. +- The sefun singular_array() is now just another name for distinct_array(), + and scramble_array() has been added. +- Doors can now be externally called to open or close and will behave properly. +- Armor worn on multiple limbs now does not automatically move to the severed limb. + +---- 2.6.1 --- +- Released 2007-12-27 +- IMC2 emotes now display better (Thanks, Tricky!) +- Fix to addemote command with the -edit parameter (Thanks, Alecksy!) +- IMC2 passwords are now stored in /secure/include/config.h +- Miscellaneous tidying up of GetEnters() (Thanks, Raudhrskal!) +- mudconfig command now handles imc2 password changing. +- grep command is somewhat less restrictive now. +- Fixed odd "feature" in LIB_PAGER that ignored an array argument with only one element + (Fixes things such as blank nickname and screwy help index output). +- GetMaxHealthPoints() can no longer report below 1. This prevents some situations (such as + multiple infections) that cause player to die over and over again. + +---- 2.6 --- +- Released 2007-11-15 +- Minor fixes to tellers. +- Miscellaneous cleanup of commented-out code. + +---- 2.5a25 --- +- Released 2007-11-14 +- Implemented MudOS v22.2b14 behavior into uncompressed read_file operations + in FluffOS to avoid a potential crasher. +- INTERMUD_D no longer uses the class data type. +- LIB_READ is now more economical on disk i/o. +- Fixed a recursion bug in check_user() in MASTER_D. +- Creators can now follow/lead each other. +- LIB_LEAD no longer uses the class data type. +- answers_to() has been buffed up to better handle complex adjectives. +- Injury/damage when lockpicking fails now limited to prehensile limbs. +- New properties added to QCS: SetPolyglot, SetPreventGet, SetPreventPut, + SetPreventDrop, SetDestructOnDrop. +- LIB_WORN_STORAGE now saves its copen/closed state across logins. +- Fixed parsing problem when using multiple adjectives in get/put operations. +- Error messages when a container is closed now make more sense. +- LIB_INTERFACE changed to avoid puking when the user is sent unusually + large strings (e.g. "help modify"). +- Bug in LIB_PAGER callback function fixed. +- Default reset interval is now 2 hours. +- Fixed a misleading message when giving multiple objects to an overloaded living. +- Added sample "pre-boobytrapped" objects: /domains/town/weap/boobytrap_dagger.c , + amd /domains/town/armor/boobytrap_ring.c +- Further fixes for conflicts in the shooting system. +- Fixed a problem with guest logins. + +---- 2.5a23 --- +- Released 2007-11-09 +- COMPAT BUSTER: Objects that used to inherit LIB_DUMMY for special + invisible-but-manipulable functionality (see: http://dead-souls.net/ds-creator-faq.html#2.62 ) + now need to inherit LIB_BASE_DUMMY instead, to avoid nomask problems + with shadow hooks. +- Fixes to shadows to better handle calls to nonexistent shadowed objects. +- Jade ring now autoprotects when worn, and cannot be worn by players unless they are + in the TEST group. +- Most bearsuit bugs fixed. However, a disguised player can be detected by another clever + player with some persistence and simple commands. The point is not foolproof + anonymity, but a bit of fun. Creators can very easily detect disguised players + using the command: scan here +- The grep command now prevents you from victimizing the mud with + an excessive recurse. +- The clone command will now try to figure out a nearby matching object + to clone if it doesn't find the file you specify. +- Ammunition and ammo case bugs fixed. +- "cd ~-" and "cd -" will both now change to your previous working dir. +- Added commands: morse, unmorse +- The Healers Guild now sells poison antidote and claritin. +- Added verb: show +- Fixed verb/item conflict when two people in the same room try to shoot each other. +- The heal command now does a more thorough job of it. +- Germs no longer get dropped on login. +- LIB_PAGER now uses mappings rather than classes, and been fixed a bit. + +---- 2.5a21 --- +- Released 2007-11-05 +- Improvements to router code. +- Added basic support for boobytraps. Verbs are: boobytrap and disarm. Lib + objects are LIB_BOOBYTRAP_SHADOW and LIB_BOOBYTRAP_OBJECT. A sample + trap object can be found at: /domains/town/obj/needle_trap.c + Finding boobytraps is done with the command: search +- Re-enabled support for lockpicking tools. See /domains/town/obj/lockpick.c +- Added missing race files. +- Fixed append_line() sefun. +- Added ReadDir and ReadFuns events. +- Fixed log rotation problem in snooper object. +- IMC2 daemon reloading should no longer spam stdout with "Done." +- IMC2 connectivity can now be enabled/disabled with the mudconfig command. + +---- 2.4.6 --- +- Released 2007-11-04 +- Bundled driver is now FluffOS. +- users() sefun override properly fixed. + +---- 2.5a19 --- +- Released 2007-10-31 +- Enabling/disabling the logging of remote or local channels can now + be done with the mudconfig command. +- rwho now defaults to i3. imc2 can be specified. See "help rwho" +- Ping interval now changed to about 5 minutes. Now configurable + with the mudconfig command. +- The help command now defaults to displaying command help, if the + argument to "help" is under multiple categories. The additional + categories are listed in the command output as well. +- Added commands: file, wizroll, roll, inherits +- Added sefun: roll() +- Tidied up get_object() to fail gracefully if necessary. +- New or newly working lib objects/events: LIB_ROLL, LIB_DIE (for dice), LIB_VEHICLE +- Added sample vehicles in /domains/default/vehicles: hoverpod and strider + Vehicles are still *experimental* and under development! +- The command showtree will now try to resolve the most sensible local object, + if it can't find a file with the name you specify. +- Miscellaneous cleanup of loose tc()'s. + +---- 2.5a18 --- +- Released 2007-10-27 +- Win32 FluffOS executable problems fixed, and the current windows + driver is now FluffOS. +- Compile time compat fixes added for Wolfpaw hosts. + +---- 2.5a16 --- +- Released 2007-10-24 +- FluffOS code altered to compile on Win32, but the included binary + is still MudOS. +- Added Shadyman's updated Tim@TimMUD IMC2 code (see: help imc2 ) +- Fixed very confusing behavior when adding a player-usable race + with admintool if the race file was set to PLAYER_RACE. +- The users() sefun override now is optimized for FluffOS. It works + fine on MudOS for back-compatibility, but less efficiently. +- FluffOS code and compilation options somewhat modified to get + around minor compatibility issues. + +---- 2.5a15 --- +- Bundled driver is now FluffOS. + +---- 2.5a14 --- +- Tightened up last_string_element() sefun. +- Router improvements: a) IRN nodes now reset a peer's connection + if no data is received within a set time. b) IP's put on the blacklist + for having the wrong password are now automatically removed + from the blacklist after a set time (default 1 week). +- Router fix: a bug that had the router sending mudlist updates to the + wrong muds has been fixed. + +---- 2.5a13 --- +- Released 2007-10-12 +- Removed command: where +- Modified users() sefun override to avoid a crasher under mysterious + circumstances. +- Added SEFUN_PLURALIZE to config.h, to allow the sefun override of + the driver's pluralize() efun. +- Added command: rot +- Fixed driver problem that stopped compile at malloc.c (stole the + fix from FluffOS!) +- Fixed driver problem that made timekeeping fail (ualarm). +- Keepalive pinger object no longer requires you to be actually idle. +- WARNING: Vehicles do not work yet. Do not be sad if you find what + looks like vehicle code that doesn't work +- Bonus object works properly now. +- Miscellaneous fixes to i3 router code. +- Libtest bot script fixed up. +- Fixed a problem in the users() sefun that mysteriously hosed + 64-bit Linux installs. + +---- 2.4.4 --- +- Released 2007-10-12 +- Miscellaneous minor bugfixes. +- Fixed driver problem that stopped compile at malloc.c (stole the + fix from FluffOS!) +- Fixed driver problem that made timekeeping fail (ualarm). +- Bonus object works properly now. +- Fixed a problem in the users() sefun that mysteriously hosed + 64-bit Linux installs. + +---- 2.5a12 --- +- Released 2007-06-24 +- Nailed some really pesky router crashers involving null socket owner + object references. +- Added sefuns: morse(), unmorse(). +- Added an automatic Morse coder/decoder system to channels. To encode + messages, make the first word of the message be: ^encode + +---- 2.5a11 --- +- Released 2007-06-23 +- Various broken table objects (eg the Orc Shaman's altar) fixed. +- The jade ring no longer makes reporting npc's invulnerable. +- Numerous fixes and updates to IRN system in router code. +- Various broken worn storage items fixed. + +---- 2.5a10 --- +- Released 2007-06-19 +- Removed a channel bug introduced in a8 that prevents the use of renamed + channels like ds, intergossip, etc. +- i3who now works properly for invis users. +- Router now retires muds that haven't connected in a week from the mudlist. + +---- 2.5a9 --- +- Released 2007-06-15 +- Fixed a peculiar crasher in the router when running under Linux. + +---- 2.5a8 --- +- Released 2007-06-15 +- Added Set/GetMatching() to LIB_ID so that individual items + can choose not to be "object matched". +- Intermud status sign should now work for reals. +- Added a shadow management system, so that objects can receive multiple + shadows and remove them individually if necessary. +- New test character tool: /domains/default/armor/jade_ring.c allows you + to receive detailed information about damage you receive, where, how + much before protection, and how much after protection. It can also make + you immune from damage, and can be used to force creatures to report + their damage to you in a similar way. +- Added command: mem +- IRN tested and confirmed to work well with 4 nodes. +- Router fix: Sending a message on a channel a mud wasn't listening to now + enables the channel for the mud *and* sends the message. +- Router fix: if a mud tries to connect with the same name as another + mud, and from a different address, the currently connected mud is + notified. This serves two purposes: alerting a mud to a potential + problem, and triggering a reset of the socket if it's actually zombied. + +---- 2.5a7 --- +- Released 2007-06-02 +- Improved IRN multi-peer support. +- Fixed various router runtimes and improved IRN data integrity. +- The bear costume now effectively disguises a player in most + ways and they truly appear to be a bear. A shadow is used for this purpose. +- Modified driver to approach POSIX setitimer() compliance. +- 100% merged Windows and UNIX driver code. +- Added calendar information to the mudtime command. +- The race of a creature is now automatically added to its id array. +- Added ChangeLevel to sanely manage the advancement of skills + and stats when a creature's level changes. The stat and skill "class" + now dictates when stat and skill level is increased. When the + new player level is divisible by 3, for example, and the stat class + is three, then the stat is increased by 1. +- Added checks for TEST group membership to autosave and auto-quit. +- Implemented workaround to runtime error when moving into a room + with many objects (caused by a buggy new parser feature). +- Fixed bug in /lib/body.c that caused an erroneous eventFall() where + eventCollapse() was called for. + +---- 2.4.2 --- +- Released 2007-04-23 +- New subcommands added to liveupgrade: revert and alpha. +- Various security exposures mitigated. +- Fixed CanGet() bug in LIB_CHAIR (Thanks, K'Azdean). +- The new mkdir_recurse() sefun allows liveupgrade to handle recursively creating + directories if needed. +- Fixed a bug in sample virtual areas that made travel nw, sw, or se take + you to the wrong place. +- CALL_OUT_LOGGING has been reworked to be less vile and it now breaks + few things, if any. +- Added an automapper. See: help automap +- Added Smaug area conversion utility, found in /secure/obj/converter_smaug.c +- A player's start room can now be a virtual room or a + cloned object (e.g. a mount). +- Fixed a problem with sending a string to eventDie() as an argument. +- Beefed up get_stack() sefun. +- Added virtual area to wiz labs for mounted combat testing. +- Added 3d virtual sky area to mounted combat arena. +- Fixed various problems with sky-based 3d virtual areas such as + falling through multiple rooms, flying up more than one room, etc. +- The "source" command now takes the -q flag to indicate queuing, rather than + immediate execution. This allows creators to be subject to the maximum + number of commands per second limit but still be able use sourcing. +- The object matching code used to step on objects. For example, if your room had + a "bar" as a SetItem, and a barstool as an inventory item, and OBJECT_MATCHING + was enabled, then "exa bar" would actually return the barstool's long desc. + This has now been fixed. +- The LastLocation property in players now handles cloned environments (e.g. mounts) + and the return command also now deals with them correctly. +- Fixed a bug in eventDescribeEnvironment() that prevented riders from + seeing living creatures in a room when issuing the command: look +- Fixed bug in npc's that made mounted riders hear spoken messages more than once. +- Fixed another carry leak in containers. Containers now update their + environments' CarriedMass. +- Fixed bug in LIB_BONUS that allowed the dropping/putting/getting of the + invisible bonus object. +- Fixed bug in LIB_POTION that failed to set the effect's duration. +- LIB_CLEAN will no longer dest inheritables in the /lib/ directory. This + avoids a situation where the inherits() efun returns confusing information. +- FILE_D now does a daily recompilation of the mud files list. +- Mounts are now set to resist room resets, so that one's loot doesn't + get unloaded from memory just because they left their horse alone too long. +- The encre command now moves a player's estate to her creator homedir. +- The suicide command now removes a creator's directory or a player's estate + and moves it to the /secure/save/decre directory. +- SetAttackable can now take a function as an argument. See /domains/town/npc/lars.c + for an example. +- A bug in SetAttackable that allowed players to be attacked when a string + was set as an argument is fixed. +- A bug in QCS that prevented deleting rooms with relative "customdefs" defines + has been fixed. +- "restore here" now works. +- Fixed typo in Chapter 8 of the Admin Guide. + +---- 2.4.1 --- +- Released 2007-03-21 +- The display of obvious exits can be over the desc in brackets + or under the desc in text form, depending on the NM_STYLE_EXITS + setting in config.h. This can be configured with: mudconfig nmexits [on|off] +- Added Diku-style equipment (eq) command. +- It's now possible to use two-letter emotes on channels, and one may + use "channel:" syntax as well as "channelemote", eg: "cre: foo" +- Added age check to login for COPPA compliance (Technically this is + not necessary since COPPA applies to commercial enterprises, but + I'm adding it on general principle). +- Fixed nonsensical parsing bug in LIB_COMMAND. +- Liveupgrade will now create a dir if necessary. +- Rooms missing from /std added. + +---- 2.4 --- +- Improved security in WGET_D. + +---- 2.3a20 --- +- convert_ascii no longer uses a broken (and slow) lookup table. It + also now has a reverse counterpart, convert_into_ascii. +- Fixed a null array in LIB_MOUNT that hosed up some non-mount npc's. +- Added defaultdomain subcommand to the mudconfig command, so that + you can make your new domain the default one for the mud with the + command: mudconfig defaultdomain /domains/MySpiffyArea +- The domaincreate command now adds all the rooms necessary to make a + domain work as a default domain. +- Fixed a bug that allowed players to be attacked by other players + despite PK and SetAttackable safeguards. +- Fixed a broken add_action in jennybot that emulated a broken verb. +- The liveupgrade command has been revamped to avoid a crasher (!!!) and + no longer requires multiple "liveupgrade all" entries. Just one will do. +- WGET_D is now throttled to prevent overwhelming the network. +- REMOTEPOST_D is now more aggressive about retiring old failed mail to avoid + idle OOB objects from constantly loading. +- Fixed bug in goto that broke using a string as an argument. + +---- 2.3a19 --- +- Released 2007-03-13 +- Further simplified parsing: it is no longer necessary to "put book on table" or + "give sword to fighter". You can now "put book table" and "give sword fighter". + Added to OLD_STYLE_PLURALS, COMMAND_MATCHING, and OBJECT_MATCHING, you can now + issue brutish stuff like: "gi bo 2 fi 3" instead of "give the second book to the third fighter". + The older syntax still works, of course. +- To emulate Diku behavior, the lib will now accept number.object syntax, eg: "gi 2.bo 3.fi" +- Fixed an excessively ugly error message generated by issuing certain non-alphabetic characters as the + first char in a command. +- Fixed a parsing bug in OLD_STYLE_PLURALS that tried to incorrectly index the command line array. +- The commands goto and people have been updated to handle mounted players. +- Events that occur on mounts are now properly communicated to the mount's environment, + and vice versa. +- When your mount engages in combat, the messages are no longer confusing. +- Fixed last major obstacle to http liveupgrades. Files should no longer get mangled in-transit. + +---- 2.3a18 --- +- Released 2007-03-12 +- If OLD_STYLE_PLURALS is defined in config.h, commands will be translated + from "drop book 2" format to "drop 2nd book" format automatically. +- Added SetNoCondition() to living things. If you don't like indications of + health on an npc, make it SetNoCondition(1) and its health status will not + report on looking at it. This will also work on players. If you want this to + be the default behavior for players, add a call to SetNoCondition in connect.c. +- Added Set/GetAttackable to LIB_LIVING, so that npc's can be made immune + to players' standard attacks. Note that your mud may still contain special + weapons or spells that can trick the npc into fighting, so you may also want to + set the npc to not pick fights, using SetPacifist(1) +- Names of invis players are now scrambled when they make rwho requests, + so that the target mud does not know who has queried it. +- Invis admins now correctly receive pings/tells/rwho's/etc. +- When mounted, you can now "ride s" rather than "ride south". +- The copy verb now deals with custom defines more sanely. +- It is now possible to create rooms not linked to anything, with the create command. + Example: create room none newroom1.c +- The decre command no longer freezes the target. +- Ping daemon does not try to ping when intermud is disabled. +- Added sefuns: convert_newline, clean_newline_file, to deal with http file corruption. +- WGET_D now correctly handles receipt of newlines in files. + +---- 2.3a15 --- +- The liveupgrade command has a check now so that trying to "liveupgrade apply" while + downloads are in progress will fail. +- Unique objects are now dropped when a player leaves the game whether or + not the mud is set to default inventory retention. +- The sefun print_long_string() now deletes its temp file when done. +- Mounts updated and improved: short and long descs include riders, room messages are relayed + to riders, and riders can be examined, among other enhancements. Some messages, such + as combat messages, are still a little confusing. +- The initfix verb now fails reasonably for virtual rooms. +- Non-meat creatures behave somewhat more sensibly now when shot. +- Fixed a null cwd error on first admin login. +- It is now possible to force room inventory to respawn every X seconds. By passing an + array in SetInventory, an item can be respawned if it is missing. See the example + in /domains/default/room/wiz_hall.c , which is set to check every 10 seconds to + see if the tree is there. If it is not, it will respawn one copy of it. +- The who command no longer counts Pinkfish code in its character count for title length, + so you may have a diferent color for every letter of your 50 character long title, + if you absolutely positively MUST. +- Added a LIB_BANK as a wrapper for tellers, like LIB_SHOP for vendors. It's now possible + to just "balance" and "deposit all" rather than "ask zoe for balance" and "ask zoe to + deposit all". +- Added command "speakcolor" to set the color in which you receive spoken messages (if, + for example, you dislike people saying things in cyan). + +---- 2.3a14 --- +- Fixed runtime in lead/follow code with SetEnters. +- Fixed bug that prevented followers from following through a SetEnter. +- Made some important changes to the liveupgrade system to handle + unusual exceptions. + +---- 2.3a13 --- +- The liveupgrade command now defaults to http connections to the dead-souls.net site, + which is orders of magnitude faster and more secure than oob, as well as more + reliable and efficient. +- Implemented shutdown packet in router. If the delay time is less than + 7 days, it just disconnects the mud. Otherwise it deletes the mud's info. +- Router connections with a sufficiently large number of password failures + are automatically blacklisted. +- Removed muds are now properly synced on IRN. +- Intermud passwords now use 9 digits. +- Dead Souls now handles Tricky's ping-req and ping-reply packets. +- Network room is less spammy on reconnects. +- Arch/wiz room intermud status is now updated in realtime. The status indicated is always current. +- Fixed chanlist problem in router. +- MAX_COMMANDS_PER_SECOND now also applies to creators. +- Modified router and router command to add functionality. See: help router +- Router now periodically sifts through sockets and discards router sockets + not currently associated with a connected mud. +- Fixed problem in validate() in PLAYERS_D. + +---- 2.3a11 --- +- Replying to intermud mail now works. +- Fixed spurious error message in mudconfig command. +- Added basic Inter Router Networking support to router code. +- Fixed bizarre exit message if you're not standing and you go home. + +---- 2.3a10 --- +- Released 2007-02-15 +- Added intermud mail support. +- Fixed $P in prompt. +- Added security fixes to router. +- Abstracted the connection code from the everything-else code in the + router, so that modifications can be made without having to drop muds. +- Moved people command to /secure so admins can see each other. +- Invis admins no longer generate connection messages when logging in or out. +- Fixed mv command. +- Creators can now sleep. +- Telling to a sleeping person now generates a warning. + +---- 2.3a9 --- +- Released 2007-01-30 +- Fixed bug that prevented players who idled out while editing from + being booted. +- Sending a tell to an NPC no longer runtimes. +- Closed up various exploit vectors with overrides of efuns. +- Null groups no longer hose MASTER_D. +- Fixed spurious error message in mv command. +- Added the "prompt" command, with which you can now customize dynamic prompts. +- Added wimpy status to env command. +- Fixed some bugs and an exploit in mail code. +- Creators can no longer snoop by default. To make snooping available + to a creator, add her to the SNOOPER group. She will then be able to snoop + players, but not creators. To let her snoop creators, you'll need to + promote her to assistant admin, or edit valid_snoop() in /secure/sefun/sefun.c . +- Added inews to the default creator channel list. +- Fixed grievous carry leak in containers. +- Fixed some null error messages when default parsing is enabled. +- Fixed a runtime with default parsing enabled. +- Fixed error message when giving something to an overloaded creature. +- Added verbs: activate, deactivate, install, uninstall. +- Added LIB_ACTIVATE, LIB_INSTALL. +- Added wrist computer as an example of an object that has functions + added to it without shadows. See /domains/default/armor/wristcomp.c + and /domains/default/obj/module_cloak.c +- Only one LIB_OOB ob is created for a full liveupgrade. +- You can now do a liveupgrade from behind a firewall: opening + your oob port is no longer necessary. +- Fixed flashlight bug. +- Fixed elevator button/dummy object bug. +- System channels are added to players on login if they're missing. This + corrects a problem with login announcements on upgraded muds. +- First admin logins now may choose between four genders. +- Shortest command matching is now shortest *unique* command matching, to + avoid accidentally executing the wrong command. +- Added OBJECT_MATCHING, COMMAND_MATCHING, BARE_EXITS, and + LIVEUPGRADE_SERVER to mudconfig command. +- The wizlist command generates an updated cre list regardless of whether + the mud is upgraded or at its native rev. +- Implemented LIB_ROOM fix suggested by Memrosh. + +---- 2.3a5 --- +- Released 2007-01-19 +- Added OOB support. +- Added liveupgrade system. See: help liveupgrade + +---- 2.3a1 --- +- Released 2006-12-29 +- Fixed null errors in wield verb. +- DEFAULT_PARSING now works correctly. If you have two keys and two tables, + "put key on table" will put a key on a table without causing + an "ambiguous parsing" error. +- Added sefuns: atomize_string, atomize_array. +- Setting OBJECT_MATCHING in /secure/include/config.h to 1 will enable + "shortest matching name" behavior, so that "zap di" is equivalent + to "zap dirk". +- Setting COMMAND_MATCHING in /secure/include/config.h to 1 will enable + "shortest matching command" behavior, so that "upd here" is equivalent + to "update here". +- Added command: qed. +- Setting BARE_EXITS in /secure/include/config.h to 1 will now let you + use "north" and "cabin" as valid movement commands, rather than "go north" + and "enter cabin". +- "afk" property is now removed on login. +- Extra description strings from GetAffectLong() no longer duplicate if + you're carrying multiples of an item. +- Modified races so that non-meat lifeforms don't leave rotting meat corpses. +- Added passive-mode support to ftp server ( contributed by Duuk @ Haven ). +- Added code to prevent "bad alternate router data" bug that tends + to knock muds off the router. +- Added "neutral" (aka hermaphrodite, aka intersex) and "none" to + user-selectable gender choices (Not applicable to first admin). +- Lower case mudlib names now work in mudlist. +- Probability lab bugs have been fixed. Charly and Charles now save + their persistent data in a sensible way. +- "copy /obj/room.c" now works for non-admins. +- Fixed up some issues with the dsversion command. +- Added sefun: chunk_string(), groups(), query_intermud_ip(). +- Added commands: wizlock, wizunlock, wizlist. +- Added commands: gag, mute. +- Fixed another paradox condition in the router where a mud could be + simultaneously connected AND disconnected, causing reconnection problems. + A periodic check for this condition will clear it every 15 minutes or so. +- Added command: flee. +- New creators are polyglottized by default. +- inet, ftp, http, and rcp services can now be configured with mudconfig. +- The router room is now the server monitoring room. Admins may now use + that room selectively to monitor traffic on the following services: + ftp, http, rcp, i3 (router). They can be monitored in any combination, + and the messages are in different colors to help distinguish between them + when multiple service monitoring occurs. +- The netstat command now lists the correct FD's. +- Reverted default MALLOC to something that fancy new 64 bit computers like. +- Retooled inet/server subsystem to accommodate RCP, added creremote + and LIB_REMOTE to the extra/ dir of the distribution, as well as instructions. +- Recompiled Windows driver to match current unix standard config. +- Finally (I hope) nailed that pesky router connection problem. +- Fixed bug in LIB_LOCK that prevented carried, lockable objects from working right. +- "unsnoop" and "unsnoop all" now work. +- Cleaned unwatched players from "snoopreport". +- /log/catch messages now have time stamps. +- Fixed errors/typos in groupmod and mudconfig help text. +- There is an error in the help file for groupmod. It should look like this: + Syntax: groupmod [-a|-r] GROUP NAME + groupmod [-c|-d] GROUP +- Fixed a bug in grep that made it choke and halt on binary files. It still + chokes, but it continues grepping after reporting the runtime. +- "decre" no longer removes all channels. Note that testing encre and + decre repeatedly on the same character will probably generate problems eventually. +- Added LOCAL_TIME parameter to config.h. Some OS'es use UTC and offsets for + timekeeping, others use a "local time" setting. Rather than try to play offset + games and fail miserably, this setting is meant to address that. +- Added "mudconfig" command to enable the convenient changing of some config.h parameters. +- LIB_CONNECT now checks CFG_IP_UNRESTRICT as well as SAME_IP_MAX to determine + if the connection should be permitted. This allows you to specify ip's that + are immune from "max connection" restrictions. +- LIB_CONNECT now checks each incoming connection to determine whether it + is the last known ip of a SECURE user. If it is, the connection + is permitted regardless of SAME_IP_MAX. +- It is now possible to use the "home" command to go to other + creators' workrooms. +- GetPlayerList(), GetCreatorList(), and GetUserList() in PLAYERS_D can now be trusted + to provide correct information (for new installs). +- It is now possible to get player data from users that are logged off, by specifying the variable + to the player daemon. For example: eval return PLAYERS_D->GetPlayerData("cratylus","Properties") +- Beefed up groupmod to handle group adding/deleting, and enable (some) use by ASSIST. +- Added command: groupmod. +- Added commands: pause, unpause. Used to remove/restore commands + from a player with behavior problems. +- Recurring reboots can now be disabled in config.h with DISABLE_REBOOTS. +- Added command "chancolors" to toggle seeing colored channel messages. This is + to limit the annoyingness of people who add pinkfish color codes + to their channel messages. +- Fixed a problem in LIB_SHOOT that prevented targeting specific + victims, as well as a runtime bug when shooting things in your inventory. +- Fixed a runtime in CHAT_D that mishandled unknown chans. +- If EVENTS_LOGGING is set in config.h, new events added to the + EVENTS_D will be logged to /log/secure/events. +- If CALL_OUT_LOGGING is set in config.h, call_outs not created by + privileged objects are logged (There shouldn't be any need to + log call_outs initiated from within /secure). call_outs originating + in /daemon are not logged either, due to the size of the resulting + log growing too quickly. +- Initiating flight while resting on furniture no longer corrupts + a creature's short desc. +- Fixed bug where "look at thing on blah" let you look at + the thing even if it was invis. +- Fixed bug in LIB_NPC that revealed carried invisible objects. +- Commented out annoying addr_init error in driver that spams + STDERR when running on Solaris. +- tc() now also prints to STDOUT. +- SetItems() now works properly in tangible items (eg Orcslayer). +- Fixed problem with out-of-sequence messages using TalkResponse + in sentients. +- Fixed incorrect behavior during automated reloads. +- Fixed an incorrect inherited call in LIB_CHAIR. +- local_options now has "ref" defined as a reserved word. This allows + the use of "ref" as a keyword for passing variables by reference, + instead of by value. For an example, see /domains/default/obj/pass_example.c +- Fixed bug in router code that created problems when muds + originating from the same ip connected and reconnected. +- Added commands: files, doctool, showfuns, createfix, findfun, + pk, find, chanremove, chancreate. +- Got rid of confusing null long desc on doors when initfixed or reloaded. +- Got rid of a null error message in reply command when the target + is missing. +- Fixed problem in help daemon that prevented race help from displaying. +- Revolvers reimplemented. +- Driver options now output verbose warnings about inherited function + conflicts and unused variables if you use local_options.debug at + compile time. +- Eliminated various function conflicts in lib files. +- Isolated unused variables in /lib file function arguments with + true() and false(). +- true() and false() now can take any number of arguments, and always + return 1 and 0, respectively. +- Fixed bug in "home" command. +- mudos.cfg now has a time to swap value of 0, to disable + swapping. I've seen now more than one driver crash due to + a swap bug, and I'm not sure what the problem is, so until I do + know, swapping will be disabled by default. +- Added RELOAD_D for objects that need to somehow get + themselves reloaded without incurring recursion problems. +- ROUTER_D now resets every 25 hours or so. +- The banish command now has an "-s" option to banish offensive + substrings from names. +- Corrected problem in addraces command that distorted which races + could be used by players. +- Modified make_workroom so that newbie creators who hose their + workroom can "restore workroom" without first having backed it up. +- Fixed bug in snoop command that caused bizarre situation when + snooping yourself using your capitalized name. +- "X looks around" and "checks possessions" messages are now suppressed + in meeting rooms. +- Fixed reporting of object mass so that both the mass of the container + and its contents are returned. This corrects a LIB_MOUNT error. +- Fixed archaic parse_* lines in some verbs that interfered with VERBS_D. +- Fixed "say to". +- Added new features to each race file. +- The findfun command no longer fails with timeouts and it executes + extremely fast due to the use of the new daemons. +- Fixed QCS bug that prevented adding includes. +- Added features to races: body type, size, average mass, whether they can + swim, and what they breathe. +- New daemon: FILE_D, traverses the lib hierarchy, compiles + a list of all files, and maintains the cached data for querying. + Full refreshes of the data happen relatively quickly, in under + a minute, and does not lag the mud much. +- New daemon: FUNCTION_D, uses FILE_D to determine inheritable lib + filenames, then queries each for the names of functions defined. + Full refreshes of this data happen slowly, several minutes + or longer. However, the mud is not much lagged during this process + except while processing very large files (e.g. /lib/body.c). +- Fixed "first admin bug" that failed to add channels. +- Implemented emotes bugfix provided by Aransus. +- Modified the template realm somewhat. There are now flask examples, + and each wiz gets their own toychest, rather than using one default file for all. +- Added to QCS: Set/AddTerrainType, SetDefaultLanguage. +- Added room terrain types. +- Non-DS code no longer needs ::create() in the create() fun to work. +- Campus meeting room no longer blocks teleports. +- Added stable with mountable horse south of the town schoolhouse. + "mount horse" and "dismount". +- Mounts must now be befriended before being mounted. To end your + ownership, "abandon" the mount. +- Fixed QCS bug when running in Windows that turned '\n' into '/n' +- Added DEFAULT_PARSING to config.h. If this is set to 1, commands + that normally fail with an ambiguity error ("Which X do you mean?") + will instead default to the first eligible object. +- Fixed problem on i3 router that caused muds to share fd's. +- Added MAX_COMMANDS_PER_SECOND to config.h to enable a cap on scripters. + This affects players only. +- Fixed race-based skills. See http://dead-souls.net/ds-creator-faq.html#2.45 +- Added LIB_FLASK (for canteens, coffee cups, etc). Flasks can + now be filled at the town's riverbank and at the shore. +- Added verbs: pour, fill, empty. +- Removed encre/decre from admintool. It was goofy and dangerous. +- Added SetActionsMap() to LIB_ROOM, to enable room actions with variable + frequencies. The old SetAction() method also still works. +- Added RETAIN_ON_QUIT define in config.h, and SetRetain() and GetRetain() + to LIB_PERSIST. Any object that returns 1 on GetRetain() is retained + across logons, regardless of RETAIN_ON_QUIT. Any object that return 0 + on GetRetain() is removed on quit, regardless of RETAIN_ON_QUIT. Changing + RETAIN_ON_QUIT requires a reload of every object, or a restart of the mud. +- Added sample potions to /domains/town/meals and to Oana's magic shop. +- Empty bottles now behave properly across logons. +- cp and mv now take -f as a flag to force overwriting. +- Removed channels (except admin ones) stay removed. +- Fixed double-logging in channel messages. +- Recompiled windows binary with new options and fixed socket_efuns. +- Added well-door system. +- Changed stat command to handle economies that do not have gold. +- Idle times now report in a human readable format. +- SERVICES_D: unk-src error now triggers an INTERMUD_D reload. +- Router verified to accept over 400 separate mud connections. +- Default connection mud for the telnet room is now Dead Souls Demo. +- Added cambot to conference room. +- Added commands: files, doctool, showfuns, createfix, findfun, pk. +- Fixed a sockets bug in the driver (thanks to Zac@StarMUD) +- Removed intergossip as a default enabled channel. Added dchat + as a default enabled channel.- Added Nimrod's recursive/numbered grep enhancements. +- Added numerous back-compat funs and obs for TMI-2 porting. +- Added numerous back-compat funs and obs for Nightmare 3 porting. +- Added daemons: ESTATES_D, ALCHEMIST_D (materials properties). +- Router admin commands will now also take ip+port. +- It is now possible to mudlist, rwho, and tell to a mud using its + ip address+port. For example: rwho 71.234.154.99 6666 +- The muffing commands now also affect tells. "earmuff Tatianna" will + prevent you from hearing channel messages *and* tells from tatianna. + You can also muff ip address + port, example: + earmuff @194.70.3.211 3000 +- "tell history" now provides a limited history of your tell messages. +- Fixed a problem adding currencies with admintool when there are + fewer than 3 existing currencies. +- Reverted to the old Nightmare calendar: mud time of day and sky + events should make more sense now. +- Added SAME_IP_MAX define in config.h, to help limit bot spam/abuse. + Default limit is 4 connections per IP. +- Fixed login problems in bots. +- Raised ulimit in start script to 1024. +- Dying creatures can no longer be observed to remove armor and weapons. +- Ludicrously long environment descriptions no longer break + when displayed. +- "alias foo" no longer removes the "foo" alias, it merely displays + it. To remove that alias, the new way is: + unalias foo +- New players are 100% proficient in the language Common, and it + is set as their default language. +- You may now "speak in LANGUAGE" to set your default "say" language + to what you specify. To make it so that "say foo" comes out in Rigellian: + speak in rigellian + say foo +- Creators don't lose stamina when moving around while invis. +- Added sefuns check_string_length and print_long_string to handle + Strings Of Unusual Size. +- Removed call_outs from PING_D. +- Added DeadMan switch to PING_D. +- Added logon notification channel <connections>. +- Added A_CUSTOM as an all-purpose armor type that can be worn + on most body parts. +- Enhanced channel and event logging to the router. +- Fixed potential channel spoof and channel admin problems + in the router. +- Modified various commands to deal with Load-Addled Game Syndrome. +- Modified LIB_BOOK to avoid tedious reload on init(). +- Added player bots for load testing (tested on Linux with + approx 250 player bots, all active, with no noticeable lag + on a crappy 1.2GHz laptop). +- Beefed up the router command. +- Character creation now does not save the playerfile until + the entire creation process has completed. +- Made AUTO_WIZzing a choice for the user, rather than + truly automatic. +- Added privacy field to template workroom. +- Added LIB_MESSAGES fix suggested by Memrosh. +- Fixed a LastLocation bug in LIB_PLAYER. +- Fixed shadow bug in the remote control. +- Added catch_tell room to arch area. +- Fixed reaper bug that destructed shadows. +- Fixed a bug in room messages during eventMoveLiving(). +- Added Praxis domain. +- Fixed customdefs issue in QCS with files in /domains. +- Added FILE_D. +- Added LIB_MOUNT, LIB_DOMESTICATE. +- Fixed carry leak in arches during shutdown. +- Fixed save problem in arches during shutdown. +- COMPAT BUSTER: changed GetCustomPath and GetCustomCommand + to query_custom_path and query_custom_command. +- Cleaned up strange formatting error in old sefun docs. +- Added sefun: query_local_functions. + +---- 2.1.1 --- +- Released 2006-09-27 +- Fixed a bug in chat.c that sent comms on new local channels to + the router (!!). +- Fixed "return" command bug and various travel message bugs + in LIB_CREATOR and LIB_PLAYER. +- Eliminated savefile data leak in admins on shutdown. +- Fixed overly aggressive reaper that killed shadows. +- Admintool security flaw has been removed by removing encre and decre from its menu. +- It's no longer possible to screw up admintool by removing too + many currencies at once. +- Updated verbs/commands: reload, gauge. +- "Can't drop things in a no-teleport room" bug fixed. +- Default channel removed: intergossip. +- Default channel added: dchat. +- Players can no longer use the force command. + +---- 2.1 --- +- Released 2006-07-12 +- 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 --- +- Released 2006-07-09 +- 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 --- +- Released 2006-07-05 +- 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 --- +- Released 2006-07-05 +- 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 --- +- Released 2006-06-18 +- 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 --- +- Released 2006-06-06 +- 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 --- +- Released 2006-06-03 +- Ran into some trouble when releasing r23. For + technical reasons, it's being re-released as r24. + +---- 2.0r23 --- +- Released 2006-06-02 +- 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 --- +- Released 2006-05-15 +- 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 --- +- Released 2006-04-22 +- 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 --- +- Released 2006-04-14 +- "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 --- +- Released 2006-04-07 +- 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 --- +- Released 2006-03-29 +- 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 --- +- Released 2006-03-24 +- 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 --- +- Released 2006-03-12 +- 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 --- +- Released 2006-02-23 +- 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 --- +- Release 2006-01-30 +- 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 --- +- Released 2006-01-23 +- 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 --- +- Released 2006-01-17 +- 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 --- +- Released 2006-01-12 +- 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 --- +- Released 2006-01-05 +- 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 --- +- Released 2006-01-02 +- 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 --git a/lib/doc/RELEASE_NOTES_HTTP b/lib/doc/RELEASE_NOTES_HTTP new file mode 100644 index 0000000..89dd35c --- /dev/null +++ b/lib/doc/RELEASE_NOTES_HTTP @@ -0,0 +1,2643 @@ +HTTP/1.1 200 OK +Date: Sun, 06 Sep 2020 11:26:23 GMT +Server: Apache/2.4.7 (Ubuntu) +Last-Modified: Sun, 23 Aug 2020 16:24:26 GMT +ETag: "1ed65-5ad8de74b70c5" +Accept-Ranges: bytes +Content-Length: 126309 +Connection: close + +---- 3.9 --- +- Released 2020-04-08 +- Fixed a problem that prevented objects from being in the inventory of /realms/ objects. +- Added a cheats book to provide a walkthrough of the basic quests. +- Miscellaneous tidying up. +- Fixed some bugs in bonuses when wearing off. +- Fixed some stuff around fishing, added a bait item. +- Added disease cure to James in the medical office in town. + +---- 3.8.6 --- +- Released 2014-11-03 +- Fixed poison never wearing off. +- Added a few quests. +- Added Get/SetNoSink to rooms and items in case something shouldn't sink. +- Fixed some wonky stuff regarding falling and climbing. +- Added command: dispel +- Added valid_event() sefun. +- Miscellaneous tweaks and fixes. +- Shortened training and teaching times. +- Lowered XP cost for death. +- Added quest cheat sheets (/doc/cheats) +- Fixed some eval cost problems in the file and function indexing daemons + that were causing lag for some people. + +---- 3.8.2 --- +- Released 2014-09-28 +- FluffOS driver now 2.23-ds03, improving Wolfpaw detection. +- Added sefun: read_big_file() +- Updated i3 router code. +- Added GUEST_ALLOWED to config.h and "guestallowed" token to mudconfig. +- Added PLAYER_INTERTELL_ALLOWED to config.h and "playerintertell" + token to mudconfig. +- Added Quixadhal's fix to outgoing intermud tells. +- Added a block of incoming intermud tells to players without intermud privs. +- Miscellaneous minor and typo fixes. + +---- 3.8.1 --- +- Released 2013-08-07 +- FluffOS driver now 2.23-ds02, including fix for socket crasher. + +---- 3.8 --- +- Released 2013-07-20 +- Added some checks to RACES_D for zeroed arrays/mappings. +- Updated IMC2 with Davion/Kiasyn's latest MudBytes IP. +- Disconnected the campus and town domains, applied new coordinates. + +---- 3.7a7 --- +- Released 2012-03-09 +- Fixed CreWeb issue when using recent versions of Firefox. +- I3 keepalives now work more properly after a rename with mudconfig. + +---- 3.7a6 --- +- Released 2012-03-08 +- Updated the IP address of MudBytes's IMC2 to reflect their Dallas move. +- Windows muds should reconnect to i3 more sanely now after a rename. +- Fixed confusing message when failing to pick a lock on a door. +- h_ftpd now uses HOST_IP. +- Updated gridconfig so that resets are more flexible. +- Cleaned up some room locations across domains. +- Corrected beggar's map. +- Started tutorial area. +- Tidied up some virtuals to be more portable across domains. +- SetNoObviousExits() now works more intuitively in rooms. +- The connection daemons now ask whether the player uses a screenreader + so that the mapping can be disabled for them if so. +- Added Kalinash's XP debt system. +- If you die really hard or in quick succession, your player will no longer + have their healing freeze. +- Added SinkRoom functionality to LIB_FALL. +- Cleaned up and reconciled most grid and virtuals functionality. +- Harmonized outdoors areas and virtual skies with SetSkyDomain() for rooms. +- Fixed a bug in add_maps(). +- Added boardwalk and seaside bar to town. +- Fixed barkeep menus and added special menu functionality. + +---- 3.6 --- +- Released 2011-08-17 +- Driver: FluffOS 2.23 with very minor tweaks. +- Driver: Odd sockets crash with instances should no longer happen. +- Somewhat improved BOOKS_D efficiency and minimized likelihood of + duplicated chapter names. +- Fixed centaur body parts. +- Exempted "read" and "title" from special parsing. +- Fixed a problem when using the town virtual areas. +- Fixed confusing message when picking a lock on a door in the same room as + another door. +- Liveupgrade server updated to avoid asphyxia problem. + +---- 3.4 --- +- Released 2011-06-08 +- Disabled instances.c by default to avoid a sockets based driver crasher. +- Added Quix's socket_names() sanitization to avoid a sockets based + driver crasher. +- Fixed peculiar bug in PLAYERS_D (thx quix!) + +---- 3.3a3 --- +- Released 2011-04-11 +- Updated a socket check. +- Fixed mud-based earmuffs. +- The timezone command can now take "none" as an argument. +- Fixed ticktock. +- Forest orcs should now be less noisy. +- Fixed polyglottism for NPC's. + +---- 3.3a1 --- +- Released 2011-04-02 +- Driver: FluffOS 2.22 with minor tweaks. +- Driver: Included updated Windows driver. +- Fixed peculiar respiration type issue (thx Nuku). + NOTE: This will probably kill everything in your mud if you update + while it is up. + +---- 3.2 --- +- Released 2011-02-17 +- Removed intergossip and intercre remappings to avoid log errors. +- LIB_TELLER: you can now "exchange gold for silver" without specifying + amount, this will exchange all the gold you're carrying. You can also + "exchange all for dollars" to attempt to exchange all your various + carried currency into dollars. +- ASSIST can now "hist admin" +- Driver: now includes fix for more than 256 global vars. + Note: The Windows driver is still 2.20. +- ASSIST can now write on the arch board. + +---- 3.1a11 --- +- Released 2011-01-02 +- Crash trace no longer has Pinkfish codes. +- Receiving a packet from a mud previously marked offline will mark it online. +- Mapped router-side "intergossip" to "broken_gossip" to limit confusion. +- Mapped router-side "intercre" to "broken_cre" to limit confusion. +- NPC's with inventories no longer have their stuff duplicated when they are + reloaded by a persistent room. +- Added command: shadows +- Driver: updated to 2.21 plus minor tweaks (Including nfa's GMCP fix) + Note: The Windows driver is still 2.20. +- The command "rotatelogs" now takes an option to force the rotation. +- Fixed a runtime error in player saves if a carried object has an + AddSave pointing to a nonexistent variable. +- Fixed array element mismatch in CHAT_D remote chans. +- SetItems() and AddItem() now work ok on NPC's (thx to HoriceGump for the + suggestion). +- Dummy items in storerooms (like doors) are no longer browseable. + +---- 3.1a10 --- +- Released 2010-08-15 +- Guest is now excluded from PLAYERS_D autopurging. +- Fixed some errant /n's (thx Aleksy!) +- i3router: IRN channel updates are less noisy now, excluding "listening". + 3 years late, but hey, I got to it eventually, Aidil. +- IMC2 server: fixed odd problem with authentication reported by Aleksy, + Quixadhal, and Kline. +- CreWeb now accepts passwords that contain the characters: ~ ! @ # $ % ^ & * + ( ) _ + { } | : " < > ? ` - = [ ] \ ; ' , . / +- Fixed some channel confusion regarding parties. +- Corrected some ambiguity in "nopeer" versus "no peer" for rooms. +- Added LIB_AIM. +- Added some gadgets to the science complex. + +---- 3.1a9 --- +- Released 2010-07-25 +- Driver: Updated to Fluffos 2.20 plus minor tweaks. +- Teachers and trainers now stop instructing you when you're + fighting them or if you've picked them up. +- MB IMC2 channels renamed in CHAT_D. +- IMC2 server: fixed line endings, emotes, minor runtimes and channel parsing. +- IMC2 client: uses CRLF now rather than LFCR if version 2.1 is specified. +- "chan add all" now works. +- Fixed a crasher when querying for binary save dir. +- Receiving messages while in the pager while in charmode no longer + aborts the pager. +- Receiving a message while typing a long line in charmode no longer obscures + the message on next keypress. +- Quitting the pager while in (suspended) charmode unsuspends charmode. + +---- 3.0 --- +- Released 2009-12-31 +- Driver: added Kalinash's fix for Solaris on 64 bit SPARC. +- Driver: added Kalinash's fix for BSD math. +- Added commands: anchor, unanchor +- Note on anchoring: it is intentional that admins can move around + if they wish while anchored, but creators cannot. +- Removed commands: mc, isql, language +- The help command now handles aliased commands. +- Corrected some quirks in editing and the detection of in_input() + that caused some entered characters to be invisible in charmode. +- Standardized help output for commands. Note that the standard is now + for the help message to be a string returned from GetHelp(), not + a write() or a message() or whatever crazy thing occurs to people + in the middle of the night in 1994. +- The "boards" command now indicates the location of the boards listed. +- Admins can now use the gag command to prevent a user from using channels. +- Fixed a password retrieval problem in ftp and hftp. + NOTE: Some newer ftp clients default to epsv when negotiating passive + ftp mode. This breaks hftp. If you're having weird problems using + passive mode and hftp, then right after logging into hftp, type: + epsv off + passive on + bin +- Fixed a double-prompt problem and some cosmetic issues when reprompting. +- Made the harmony of best balance in tell.c for justice. +- The <muds> channel no longer double-pumps on instances. +- Fixed CheckEncounter double-pump in LIB_NPC. +- Tidied up slightly confusing events reporting. +- Fixed a problem with "EverFill" things like rivers running out. +- Fixed a problem with undrinkable floods and floods that couldn't + be used to fill flasks. +- Vendors now buy items at half value, if they can. +- The Windows version now automatically disables IMC2 if the + server IP becomes invalid. + +---- 2.11a22 --- +- Released 2009-11-01 +- Removed unnecessary casts. +- It's possible to peer into virtual rooms now. +- Added a sample ranged weapon: /domains/default/armor/pcannon.c +- Added Tricky's A* implementation (doesn't really do anything yet). +- Improved the thoroughness of warmboots. +- Improved back-compatibility with MudOS v22.2b14-ds. + +---- 2.11a21 --- +- Released 2009-10-24 +- Under some conditions, insufficient time was provided during + a reconnect to allow the reconnection. This has been corrected. +- Driver is now a slightly modified FluffOS 2.18. +- Fixed history list recalculation. +- Number parsing is no longer done for add_action()'s. +- IMC2 tells now propagate properly to instances. + +---- 2.11a20 --- +- Released 2009-10-08 +- Added some rooms to campus lab. +- Fixed a problem in delayed command queues. +- The wizmap is now not caching by default, to avoid + gaps in mapping. +- Slightly streamlined the character generation process, removing + questions that are rarely answered and not requiring "pick" to + precede the race and class. +- Added the ob, name, and obname elements to the MagicProtection class in + magic_protection.h in order to better track and control multiple + magic protections. See /powers/spells/buffer.c for an example of + a spell that checks these in order to avoid stacking. +- Fixed IMC2 colors. +- Exempted file commands from Diku "2.thing" parsing rules. +- The lib now explicitly ignores resets that originate from the + driver, in order to avoid odd over-aggressive resets. +- Any npc can now be a command-obeying zombie, not just "sentient" npc's. +- Fixed some problems with effective vision and peering. +- It's no longer possible to follow someone if they are invisible or + if you are lying down. +- Cleaned up some parsing of LIB_FLASK and LIB_INSTALL. +- Zombies can be re-raised after they are re-killed now. +- Finger now works properly on instances. Note that fingering + *across* instances does not work, and needs be done through + intermud finger. +- It is now more difficult to accidentally drown in the sea east of town. +- Added gendered title (e.g. "the Countess") handling to the + advancement process. +- Added sefun: comma() + +---- 2.11a19 --- +- Released 2009-09-26 +- Added a more efficient auto-mapping drone. +- Rooms can now specify their own coords, for example: + SetCoordinates("-3000,3000,0"); +- Map daemon now periodically sweeps cached maps and updates + their info. +- Parse matching now also checks for emotes. +- Added commands: vaarsuvius, cursefilter, homedir, homeroom +- Log rotation now better accommodates unix file semantics. +- The "reply time" threshold for deleting the reply addressee + is now a full day. +- Fixed a thingy that cancelled "more" in charmode after a + few seconds or so of reading +- QCS now handles SetRead better. +- The IMC2 password should now get clobbered more rarely. +- Fixed a parsing ambiguity in "get from". +- The instances daemon now properly reloads its configuration on boot. +- User names on instances are now more thoroughly reserved. + +---- 2.11a18 --- +- Released 2009-09-13 +- Fixed minor bugs in parsing. +- Individualized a few logs to prevent instances stepping on + each other during log rotation. +- Fixed some logic in the probability lab. + +---- 2.11a17 --- +- Released 2009-09-11 +- Driver: Added Wodan's fix for NEW-ENVIRON. +- Fixed skill problem in CLASSES_D. +- i3router: Added Aidil's irn-mudlist-req and a check for when + a "disconnected" mud sends a packet. +- Fixed problems in anyterm connections. +- Re-enabled number.thing parsing (when did this break?). +- Improved "thing number" parsing, e.g. "get purple thing 2" now works. +- The pause/unpause commands will now also work on players who aren't logged in. +- Pausing or decre-ing a creator now also boots them from creweb. +- Fixed imc2 remote who replies. +- The help command now translates synonyms to the target verbs, to + cut down on verb guessing. +- The lines command has been verbified to simplify its synonymization + and documentation. +- Fixed channel emote problem reported by Flumpy. +- Command matching no longer arbitrarily picks the first matching + command if there is more than one. +- Added command: bugs, queue +- Fixed a problem in PLAYERS_D that prevented suicides from working. +- Fixed a problem in INSTANCES_D that double-pumped channel messages. +- Driver: The parser now defaults to the first matching object in + commands with ambiguous hits. You can "get key" rather than "get + first key" and this is parsed in the driver rather than the lib. + +---- 2.11a9 --- +- Released 2009-07-19 +- Driver is now a slightly modified pre-release Fluffos 2.17. +- Fixed remote channel problem in CHAT_D. +- /secure/include/mssp.h is now somewhat more individualized. +- Added commands: screenlock, weigh +- Driver: Added partial support for telopts NEW-ENVIRON (rfc 1572). + A connection that supports this will cause the driver to call + the receive_environ() apply in LIB_CONNECT, sending the env data + as a single string. +- Added support for using anyterm (http://anyterm.org) as + a client while still identifying player IP's. +- Fixed a problem listing individual items from vendors. +- Replaced broken xterm definition map in TERMINAL_D with ansi def. +- Updated IMC2 client, also added current Server01 IP. +- Instances now update each other more regularly about player info. +- More than one local instance now better supported. +- Added a PLAYER_CLASS entry to class files in /secure/cfg/classes + so that there can be classes players don't get automatic access to. +- Fixed parsing conflict in LIB_FLASHLIGHT and LIB_BATTERY. + +---- 2.10 --- +- Released 2009-06-01 +- Minor fixes to 2.9a19 +- Added pwiping to PLAYERS_D. +- Minor faq updates. + +---- 2.9a19 --- +- Released 2009-05-25 +- The idle command can now be used without an argument as + a connection keepalive. +- i3router: IRN chanlist now tries to prune duplicated entries in the + data packet before transmission. +- i3router: channel-add packets with invalid channel types are + now rejected. +- The mudconfig command now handles mud name and port changes. +- IMC2 channels now have their remote names mapped to their local + names automatically, avoiding the need to hardcode the maps in CHAT_D. +- Added commands: chan, rotatelogs +- Updated the ced editor with some important fixes. It can now be + enabled with mudconfig (mudconfig ced on). Note that this is a highly + experimental editor, so it automatically backs up any file you edit + with it. See the help info for: ced, bk, restore, charmode +- The windows install no longer needs the absolute path to be + c:\ds if the new default runmud.bat and mudos.win32 are used. +- Instances on Windows are now supported. +- Telopts MSSP support added, plaintext MSSP improved. + See: http://dead-souls.net/ds-admin-faq.html#145 +- i3router: the "listening" portion of irn channel updates is + no longer sent. +- i3router: blacklisting of networks is now possible. +- i3router: muds that attempt to reconnect more than once per second + are subject to automatic temporary graylisting. +- Fixed an exploit reported by Ideysus that allowed local creators to + spoof intermud packets. +- Removed command: mfinger +- Updated the performance score calculation to make it more consistent. +- i3router: packet floods are now handled somewhat more efficiently. +- Added sefun: format_page2() +- Alleviated some misfortunes in instance tells. +- The mudconfig command now works properly with imc2 password setting + and the secrets daemon. +- General cleanup of superfluous debugging statements. +- Substring searching added to ced. + +---- 2.9a18 --- +- Released 2009-05-05 +- Fixed a problem with the new reply aging system. +- Fixed a bug in liveupgrading that overwrote SECRETS_H. + +---- 2.9a17 --- +- Released 2009-05-01 +- Driver is now a slightly modified FluffOS 2.16. +- Converted structs to mappings in CLASSES_D. +- Fixed CLASSES_D bug that inverted the position of "importance" and + "average starting level" of classes. +- Instances now share local channels. +- Users on different instances can now tell to each other. +- Users on different instances can now get "finger" info on each other. +- Users on different instances can now see each other in "who". +- Added commands: instconfig, deviate, destfile +- New players can't create a character if the same name is used + on another instance. +- Added sefuns: remote_users(), local_users() +- The actions map elements in LIB_ROOM now actually fire based on + their individual "chance" rather than the overall ActionChance + (thx Raudhrskal!). +- IMC2 tells now work like i3 tells, no need to use the "imc2" command. +- AUTO_WIZ set above 1 now forces new users to become creators, rather + than providing the choice to do so. +- IP addresses of users are no longer displayed to creators on + AUTO_WIZ muds. +- Users on different instances can now shout to each other. +- Fixed problems in the router code when a mud's fd is 0. +- IMC2 client host/port info now does a better job of being correct. +- IRN nodes now periodically send each other mud and chan lists. +- Some password thingies like i3 and IMC2 are now handled by a + secrets daemon, to improve security. +- The non-quitting non-net-dead destruction of users is now announced + and logged (for example, if you "dest" a creator). +- Suicide notes now save somewhere more reasonable. +- Paths in read.cfg and write.cfg can now have wildcard files. +- Added STATS_D and SKILLS_D. They are meant to keep track of which + stats and skills have been used in the mud, and when possible, + maintain information the "importance" of a stat to a race and a + skill to a class, derived by RACES_D and CLASSES_D respectively. + This allows a centralized repository of stat/skill information + that the DEVIATION_D can rely on for deviation calculation. +- Added a stat deviation system. A player can now have an improved + stat class, but at a cost of some percentage of earned XP. See: + help deviation +- The hist command now reverts to the old "query the chat cache" + behavior if the mud doesn't log the type of channel being queried. + Note that by default, remote channels are not logged. +- Fixed an odd display problem in the hist command. +- SNOOP_D can now ignore ip's (good for running bot tests from a known + ip), and admins can now be monitored if set to be so explicitly, + overriding GLOBAL_MONITOR == 2. +- Fixed userlist generation in PLAYERS_D in an instance. +- Since IMC2 servers do not handle usernames with spaces well, IMC2_D + now strips spaces from names before sending channel messages. +- Stargates can now register with the stargate daemon only if they are + in /domains/ or /secure/, to avoid dozens of accidental newbie + stargates to creator realms. +- The prompt command without an argument now returns the raw prompt + string, rather than setting a null prompt. +- Added improvements to the colors command by Raudhrskal. +- Cleaned up the lines command. +- Reply target is now reset on login, and ages out after 15 minutes + of not replying and not receiving a message from that target. +- Inventory output now has worn things at the bottom, and wielded + things just above worn things. +- SetEncounter() on aggro npc's now keys on GetInvis() rather than + query_invis() for somewhat more predictable results when trying + to sneak around. +- Players on instances no longer get booted off during warmboots. + +---- 2.9a16 --- +- Released 2009-03-12 +- The "locate" command is now "i3locate". +- Prettified the tabbed file completion stuff. +- Armor now makes more of an effort to resolve ambiguous + targets, such as "wear ring" when both hands can take a ring. +- Added BaseLimbs to armor in order to resolve ambiguous situations + involving sets of limbs, such as a shield which needs a paired + arm and hand, plus torso. +- LIB_WORN_STORAGE now uses inherited LIB_BASE_ARMOR and + LIB_BASE_STORAGE as inherited code to avoid discrepancies in + behavior in duplicated code. Note this means that the majority + of the code for armor is now in LIB_BASE_ARMOR and the majority of the + code for "things that hold other things" is now in LIB_BASE_STORAGE. +- Added GetMaxSkillLevel() to LIB_ABILITIES to consolidate the + calculation that was previously duplicated by multiple commands. +- Fixed a bug that allowed skill levels in negative numbers. +- Cleaned up some behavior with ANOXIA damage and respiration types. +- Commands that queued when in combat (such as 'inventory') used + to hang indefinitely if you chased your quarry into a "no attack" + room. This is no longer the case. +- Persistent rooms no longer spawn excess copies of unique + or MaxClone objects. +- The fighter's hall in Ylsrim is now a proper, working class hall + with class joining and training available. +- Fixed a bug in the flood object that generated performance + problems over time. +- Fixed a bug in the flood object that failed to set the respiration + type correctly when a room became completely flooded. +- Fixed a problem with warmboots that caused some doors to + have issues being locked/unlocked/manipulated. +- Objects that drop into "void" due to a problem with their + environment now are sent to individualized "virtual voids" if + the ROOMS_D can resolve that. This avoids some rare circumstances + where a huge number of npc's and players fall into a single + "void" room and mayhem ensues. +- Fixed a conflict in QCS with customdefs.h that made it difficult + to modify your workroom. +- The goto command now handles global coordinates, eg: goto 2,2 +- The command "imc2 list" now only returns muds currently connected, + to avoid a timeout receiving data from a long list of defunct muds. +- Fixed a problem in scoped heartbeats that prevented players + from autosaving. +- COMPAT BUSTER: debug() now just takes two args, making it + more like tc(). Example: + debug on + eval debug("My skills: "+identify(this_player()->GetSkills()),"red") +- It is now possible to carry living things. Creators can get creatures + of any size, but players can only pick up creatures smaller than them + by at least 2 size slots. Note that picking up an NPC you have not + befriended will make it attack you. +- Fixed a bug in updating virtual rooms. +- You can now run multiple instances of the same code without clobbering + savefiles. If you set ENABLE_INSTANCES in config.h, then reboot, + objects will add the mud's port to their save name, for example + "rooms.6666.o" rather than "rooms.o". Obviously this means that the + different instances need to be on different ports. For an example + of how to do it: help instances +- Clepius can now extract bullets, if you give him an excision slip. +- Fixed a carried weight conflict in vehicles and mounts. +- tell_room() now works on string names of virtual rooms. +- Fixed a parsing peculiarity when trying to read one book when + others are available. +- Added a hint book to Kim's bookstore. +- If you were in a virtual room during a warmboot, you are returned + to it after the warmboot completes. +- Creators can now keep track of things sneaking in and out of their + inventory with call me->SetParanoia("inventory_monitoring", 1). They + can also keep track of where they might be silently moved to with + call me->SetParanoia("move_monitoring", 1). Note that these are not + foolproof, and the proper way to deal with mischief is not paranoia + but extreme violence and harsh language. +- The "which" command now identifies aliases, add_actions, etc. +- Finally nailed a mysterious data overwrite problem in PLAYERS_D. + +---- 2.9a15 --- +- Liveupgrade only. +- Intermediate release to handle special liveupgrade issues. + +---- 2.9a14 --- +- Released 2009-02-04 +- Driver is now a slightly modified FluffOS 2.15. +- Added an experimental screen-mode inheritable editor, see + LIB_CEDIT and: help ced . It's still a bit quirky and buggy, and + incomplete (handles wrapping poorly, doesn't do search/replace, + etc). For now it's a proof-of-concept/prototype with saving disabled + (thx to Tricky and Raudhrskal for advice on terminal control). Will + not work without charmode. Will not work without FluffOS 2.15-ds*. +- Added sefuns: system_month(), system_day(), write2() +- Added sefuns from Chaos@Lost Souls: levenshtein_distance(), + damerau_levenshtein_distance() +- Added commands: commandecho, profile, timezone, efuns, sefuns, lfuns +- Driver: added ANSI_SUBSTITUTE define to comm.c in order to + control which character is substituted with in NO_ANSI. +- It's now possible to re-engage in combat with an opponent you've + previously ignored. +- Rooms now attempt to set their own respiration type based on + their medium, if their respiration type is not already set. +- The longcat command now tries a bit harder to display ludicrously + large files. +- The commands dsversion and noclip work again. +- Various conflicts in coordinate setting fixed. +- Mitigated a compat buster in QCS involving customdefs. +- Miscellaneous performance tweaks to make DS friendlier to use + on weak hardware. Tested on a Pentium 133MHz and + an UltraSparcII 300MHz. +- Changed the name "automap" to "minimap". Automapping will mean + something else in later releases. +- Implemented a "minimum performance" threshold for certain + resource-intensive features. The performance score of a system is + determined by CPU time taken at boot. The MIN_PERF define in config.h + establishes the minimum score required for "heavy" features like + wizmapping and file/function indexing. This system allows people with + weak machines to use DS without tons of errors, and it allows people + with fast machines to enjoy the fancy stuff by default. +- Fixed a problem in FUNCTION_D that prevented the lib from having + function data when running on Windows. +- Warmboot no longer hoses up people in charmode. +- MASTER_D now forces a quick shutdown if it detects one of the following: + * Exhausted file descriptors. + * Eval cost error cascade loop. +- Driver: added efun remove_charmode() +- The hist command now includes timestamps and accepts a number + argument for how many lines to display. +- Fixed local_time() to accept a string timezone. +- Commands like "date" and "people" now have output customized to the + player's timezone. +- Driver: fixed command() efun so that success is nonzero + when running on Windows. +- Charmode now works on Windows (see command() above). +- The hist command now also handles: say, whisper, yell, shout. +- Fixed a bug in LIB_BODY that caused decapitation during combat + to occur twice, resulting in two severed heads. +- The "nightmare shell" now does tabbed command completion, + tabbed filename completion, tabbed object completion, and + up/down-arrow command recall when in charmode. +- The findfun command now also identifies efuns and sefuns, and + tries to suggest other possible matches based on differing + case and format. It also now takes a substring flag to search + efuns, sefuns, and lfuns for possible matches. +- Guarding works properly again. You can no longer take Kim's + cash register. + +---- 2.9a13 --- +- Released 2009-01-04 +- Finally got around to indenting everything consistently. +- Improved handling of missing/broken rooms in ROOMS_D. +- The noclip command now enables "noclip mode" rather than + being a command for moving in a specific direction. While in + noclip mode you can move through closed doors and walls if + the rooms daemon is aware of an adjacent room in that direction, + even with no explicit exit there. +- Fixed some vaguenesses in death notices. +- Virtual rooms now immediately unload when the last object in their + inventory leaves. This allows, for example, launching a torpedo that + travels 200 rooms without now having to have 200 totally useless + rooms hanging around in memory. +- Added commands: reprompt, charmode, keepalive +- The reprompt mode redraws your prompt when you receive + messages, similar to how Diku muds do so. Note + that reprompt mode looks awful on most mud clients...it's + intended for folks with "single pane" clients, like people + using a default Linux telnet client. +- The charmode command puts you into character mode, so that + your input is received on a per-keystroke basis, rather than + a per-line basis. This allows for stuff like using up and down + arrows for command recall. This is for single-pane clients + only! Most mud clients will fail to handle this...and they + may fail very horribly. This mode is experimental and + somewhat broken at the moment. Unsupported on Windows muds. +- Fixed bug in LIB_BODY that caused overlapping armor to increase + damage received. +- The default player prompt now includes status info. +- Driver: Fixed a bug in comm.c that failed to reset to linemode + if the object with the get_char() target function was destructed. +- Some damage limits have been raised. You may find your npc's + and weapons doing substantially more damage. See MAX_POWER and + MAX_SKILL in LIB_COMBAT. +- i3router: Connection freakouts by blacklisted muds are now handled + more gracefully. +- Added sefuns: present_file(), present_bonus(), query_unique_name() +- Driver: added efuns: query_charmode(), remove_get_char(), + send_nullbyte() (thanks, Raudhrskal!) +- AUTO_WIZ no longer prevents class selection. +- Unified command history code into LIB_HISTORY and rewrote a bit in + order to use mappings rather than arrays, to avoid ambiguities. +- The customdefs.h file for creators and builders is now in their + area/ directory. This is to make it easier to migrate such an + area to domains/ once it is complete. +- Consolidated the calculation of max health points into LIB_RACE, + fixing some issues with strangely overhealthy npc's during combat + (eg kitchen rats). +- Added Raudhrskal's implementation of Daelaskai's evaldefs idea + (thx guys). +- If a thing doesn't have SetDamagePoints() called on it, it will + not deteriorate when it receives damage. +- Items in perfect condition no longer indicate their condition. +- Implemented basic persistence for rooms. If a room is SetNoClean(1), + has SetPersist(1); in create() and RestoreObject(); on the + following line, then when it reloads, it will restore into + its inventory whatever was left there...even across reboots. + For an example, see /domains/town/room/secret.c +- Containers can also have persistence set, but *BEWARE*. Any + item you set to be persistent in this way should be unique + in the mud. Having multiple clones of an object with persistent + inventory may result in hilarity, but very likely also + confusion and sadness in an open mud. For an example of an item with + persistent inventory, see /domains/town/obj/charity.c + *IMPORTANT NOTE*: carryable items that are made persistent will + appear to behave oddly when you "reload" and "update" them, and + modify them with QCS. This is because QCS does not actually + destroy them right away, and in fact for a brief time you have + two of the same item in the mud, stepping on each other's persistent + inventory. Expect to see weirdness when using QCS with persistent items. +- Land-based rooms can now have respiration types other than R_AIR. + For an example, see: /domains/default/room/vacuum.c + You can also test by issuing the commands: + goto /domains/default/room/menagerie + eval return HERE->SetRespirationType(R_VACUUM) + and seeing most everything drop dead within seconds. + +---- 2.9a12 --- +- Released 2008-11-26 +- DECAY_D is now more resistant to runtime-error failures. +- Minor improvements to stress testing. +- At the advice of Silenus, switched the world grid from string based + multidimensional mappings to bitshifted integer based multidimensional + mappings, which not only cut down mapping depth by 35%, but also + increased lookup speed by more than an order of magnitude. Many + thanks to Silenus for holding my hand through figuring out how to + bash the bits. +- Portals no longer fall or sink. +- Warmboots deal more firmly now with situations where very many + rooms are loaded. +- The imc2 channel "ichat" is no longer enabled by default due to + a change in their content policy making them no longer PG-13. To enable + it for yourself, you would type: call me->AddChannel("ichat") +- New creators now automatically "wizmap" rather than "automap". +- Added Town Well quest. +- Added LIB_FLOW as an example of a "flooding" type object. + +---- 2.9a11 --- +- Released 2008-11-20 +- Driver is now a slightly modified FluffOS 2.14. +- Fixed a parser crasher in the driver that occurs under + unusually heavy loads. +- Parsing ambiguity in grenades fixed up a bit. +- Bots now handle too-bright and too-dark rooms more sensibly. +- Bots now handle paged displays more sensibly. +- Room inventories will now accept a function for the number + of items. For an example of a random number of rats between + 1 and 5, see /domains/town/room/mansion_room7.c +- You can now limit the number of of clones of an npc or an item + that the mud will load as inventory. If a sword's base file + has SetMaxClones(15), then a room will not try to load the + sword in its inventory if the mud already has 15 of these swords + cloned somewhere. Note that SetMaxClones() in a base file + will cause the object not to be saved in a player's inventory + when they quit. For an example, see /domains/default/armor/wristcomp.c +- Fixed a problem in CreWeb editing with wrapping and line numbering + that displayed incorrect line numbers. +- Fixed a driver crasher involving the destruction of objects + while they are in a verb parsing loop. +- Fixed a problem with passing functionals to SetAction() in rooms + (thx, Raudhrskal!). +- Added a prototype overland map system. It's mostly in the testing + phase, as it tends to lag the mud somewhat. Creators can enable + automatic mapping with: wizmap on +- Minor fixes of rooms with grid conflicts. +- Added command: wizmap +- Fixed a problem with the npc guard system that prevented more + than one guard from being able to guard in the same room. +- Fixed what is essentially borken behavior in Set/GetItems + that have a functional. However, I suspect that this behavior has + actually been assimilated all over the place as being a standard, + so the effect here is a possible *slight* compat buster, with + SetItems that have functionals displaying output twice. +- Added a portal generator, and cake to go along with it. +- Added new domain: /domains/cave as an undergound orc stronghold. + It's mostly done, though I'll be adding more to it eventually. + Note that this is an example of "an area where normal creators and + overpowered players are not welcome". This is a feature I'm + testing to see how feasible it is to prevent casual-abuse type + creators from being too much of a nuisance on an open mud. + +---- 2.9a10 --- +- Released 2008-10-19 +- Fixed peculiar problem in the get verb that sometimes made + it seem as though an open container was closed, for creators. +- It is now exceedingly difficult to fight or + defend when not standing, or when your vision is poor. +- Added command: gridconfig +- Minor grid conflicts cleaned up. +- Fixed a permissions issue that prevents doors from showing up + for players without read access to an area. +- Value for meals now defaults to base cost. +- Reaping tidied up: REAPER_D now fires up at boot time, and + reap_other() will scour for environmentless clones whether + the driver is FluffOS or not. +- Players are now addressable by their race. +- Added a "max attacks per heartbeat" throttle to combat.c to + avoid having creators in godmode with ludicrous stats causing + the mud to seize up fighting each other. +- Fixed a too long eval in warmbooting. +- LIB_COMMAND now handles multi-word bare exits ("foo bar" rather than + "go foo bar"). +- Added Kalinash's driver mod to override new() with clone_object() if the + clone_object() sefun exists. +- valid_edit() in LIB_BOARD now works more sensibly and denies edit + and deletion access to people who should not have it. +- "give all to X" now works like selling and putting: worn and wielded + items are not automatically surrendered. +- Fixed some parsing issues with booby traps. +- clone_object() is now overridden with a throttle to prevent + accidental cloning cascades from creator objects. +- Added MEMUSE_SOFT_LIMIT and MEMUSE_HARD_LIMIT. These are disabled + by default. They are intended to provide some control over memory + usage, for folks on commercial hosting or resource-starved computers. + For details, see: help config +- Added driver fix for check_memory() crasher. +- Added max player limits in LIB_CONNECT based on compile-time- + detected file descriptor max. +- Fixed a crasher in the driver that occurs under very rare + high-network-load stress. + +---- 2.9a9 --- +- Released 2008-09-24 +- Driver is now a slightly modified pre-release FluffOS 2.14v27. +- Revolvers no longer change caliber spontaneously. +- Basic IMC2 server added. +- IRN "not my mud" endless loop when more than 2 nodes is fixed. +- Added "chanlist-req" to the router. You can now get a chanlist + without having to reboot. +- Packet floods from a given mud are now detected and temporarily + ignored. +- The IMC2 ichat channel has been added as a default channel for + creators in /secure/cmds/admins/encre.c +- The finger daemon no longer reports an incorrect birth year + when queried repeatedly. +- Added commands: mudinfo, enemies, showgrid, whereis +- Quest-dependent advancement can be disabled in config.h by + setting REQUIRE_QUESTING to 0. +- Automatic advancement (i.e. not having to go to Dirk) can + be enabled by setting AUTO_ADVANCE to 1. +- Added "questrequired" and "autoadvance" to mudconfig command. +- The table of quest and experience points required for + advancement is now maintained in PLAYERS_D, not Dirk. +- By default DS will now handle automatic advancement well beyond + level 100. Note that there has been no balancing attempted + beyond level 20. You will need to seriously adjust your mud's balance if + you allow advancement past level 20. +- Bug fixed in quitting while invis. +- Added a cgi gateway to the built-in webserver that allows you + to connect to the mud with a java client. To enable it: + ----------------------- + mudconfig http port 8001 + mudconfig http disable + mudconfig cgi enable + mudconfig dirlist enable + mudconfig creweb enable + mudconfig http enable + ----------------------- + Then use your browser to connect to your mud's connection page + (for example, http://your.muds.address.com:8001/cgi/connection.html ) + NOTE: the mud www port does not have to be 8001. Change it to + whatever is appropriate for you. +- The dest verb now behaves like before. Desting of non-cloned + objects by using their file names is again unsupported. This + fixes problems with desting a singular among plurals. +- Some parsing issues in grenades fixed. They also do more + damage, but are limited to hurting the first dozen or so people. +- Added a flash policy server. To enable, uncomment the flash_policy line + in /secure/cfg/preload.cfg, redirect your mud server's port 843 to + your mud port + 3 (for example 6669, if your mud is on 6666), + and reboot your mud. +- Added MUDINFO_D to manage longterm intermud data (normal people + will not have any use for this). +- The answering machine now works again (when did this break??). +- Added ROOMS_D to keep track of the relative locations of rooms. This + is necessary for some activities that will involve distances, such as vehicle + combat in virtual areas. +- Added sefuns: coordinates(), calculate_coordinates(), + room_environment(), query_windows() +- Some rooms have been moved around to accommodate conflicts with + their coordinates. +- Only Firefox is supported with creweb. I can no longer afford to + try to keep up with every browser's idea of how to conduct itself. + If creweb isn't working and you aren't using Firefox, please use Firefox. +- The "noclip" command now accepts non-exit directions that have + an entry in ROOMS_D as having a room adjacent. +- Books now do not individually hold their data, but rather cache and + query with BOOK_D, to cut down on memory abuse and disk I/O costs. +- Fixed a bug in last_string_element() sefun that screwed up qcs doors. +- Added a zombie scroll to Oana's shop. +- General miscellaneous typo corrctions and minor bugfixes. +- Added Vega's SEASONS_D fixes. + +---- 2.8.5 --- +- Liveupgrade only. +- Intermediate release to handle special liveupgrade issues. + +---- 2.8.4 --- +- Released 2008-07-24 +- Merged 2.9a8 into the 2.8.x line. Due to the importance of some + security fixes, and since major changes have not yet been introduced + in 2.9, the improvements of 2.9a8 (unreleased) and below are being + folded into 2.8. +- Fixed odd door id problem reported by Tricky when warmbooting. +- Class data type removed from LIB_DOOR. +- Added commands: pwhere, vars +- Wizvision now lets creators see invisible creatures in a room. +- Accuracy and performance improvements to default parsing. +- Cleaned up and updated firearm code: targeting in a room full of + corpses is improved. Wounds no longer inflict continuing damage, + they simply interfere with player healing (NPC's heal normally). + Unless you are skilled with firearms, shooting an npc over and + over in rapid succession is extremely likely to miss. +- Fixed typo in PARTY_D. +- Healing is now largely dependent on whether you are hungry/thirsty, + with some modifiers for relevant stats like strength, luck, + and durability. Being asleep and drunk now actually do have a + positive effect on healing, as well as having the "faith" skill. + Overall this means healing *can* happen faster if you stay on + top of these items and don't catch flying bullets. However, if + you're not keeping fed and hydrated, healing will seem to have + got slower. + +---- 2.9a7 --- +- Released 2008-07-18 +- Driver: MSG_NOSIGNAL more promiscuously defined. +- Driver: extra checks added to avoid obscure high-load crashes. +- Parsing problem with doors and multiple keys fixed. +- Miscellaneous minor lib fixes. +- Improvements to sefun and warmboots to better interact with call_outs. +- Added commands: defines, types +- Fixed a bug that prevented receiving damage in a wielding limb. +- Prayer parsing system updated/fixed: clerics can now perform prayers + with targets. + +---- 2.9a6 --- +- Released 2008-07-14 +- Driver is now a customized FluffOS 2.12. +- Miscellaneous minor lib tweaks and fixes. +- Added command: noclip +- Fixed recursing paralysis bug in LIB_BODY. +- The netstat command now includes summary statistics. +- cardinal(), base_name(), and copy() now use efuns rather than sefuns + for improved performance. +- The reaper now uses get_garbage() for improved performance. +- The reaper is now more aggressive about spotting and cleaning + large garbage pileups. +- The call_out efun is now overridden with a sefun that checks + for excessive call_outs and autoblacklists suspected problems. + To tune the number of permitted call_outs, modify the new + MAX_CALL_OUTS param in config.h. Note that objects in /secure and + /daemon are exempted from this check. +- The update command no longer has a problem when you are mounted + on a creature or vehicle. + +---- 2.9a5 --- +- Released 2008-07-10 +- Driver: Fixed segfault for SPARC. +- Minor sefun fixes. + +---- 2.9a4 --- +- Released 2008-07-09 +- Fixed various runtimes in IMC2_D. +- Driver: Crasher due to object ref count flip is now prevented (thx Wodan!) +- Cleaned up some disharmonies in the reaper. + +---- 2.9a3 --- +- Released 2008-07-07 +- Added GUARD_D and LIB_GUARD to allow npc's to guard exits, + objects, and people without having to edit the room. For examples, + see /realms/template/area/npc/fighter.c and /domains/campus/npc/kim.c +- Driver: Added fix by Kalinash that avoids a crasher when dealing + with unloading blank files. +- The gag and mute commands can now accept keywords to indicate + whether you only want to mute/gag local channels or remote channels. +- The reaper now exempts http sockets. +- New defines daemon can identify things defined in standard includes. + Example: eval return DEFINES_D->GetDefine("ADMIN_EMAIL") + +---- 2.9a1 --- +- Released 2008-06-15 +- Fixed periodic check of preloaded objects. +- The command "resurrect" now also works on npc's. +- Added verbs for firearms: load, unload. +- Added verbs for chairs: swivel, rock. +- Driver (under Linux only) : Added enhancements by Kalinash that avoid + SIGPIPE crashes under heavy load and mass disconnections (thx dude). +- Driver: Added fixes by Kalinash that avoid segfaults under + extreme loads (woo Kali again!). +- Periodic check added to STARGATE_D to clear "stuck" gates. +- Spells are now in /powers/spells, to accommodate new systems + of powers such as psi and physical feats. +- Added smokable items: LIB_PIPE, LIB_CIGAR. +- Driver: fixed up plurals for "remains" and "glasses". +- Fixed name banishing in admintool. +- Player teaching fixed up. For now, only spells are teachable. +- Improved handling of corpse and severed limb id's. +- Creators retain their selected title upon reviving from death. +- Hazardous materials lab now requires players to solve a riddle + before letting them in. + +---- 2.8.2 --- +- Released 2008-06-25 +- Bundled driver is now Kalinash-improved. +- Empty log dirs made non-empty to handle fileroller better. +- query_os_type() fixed. + +---- 2.8.1 --- +- Released 2008-06-05 +- Fixed a bug in IMC2 that made all muds connect with the same name. +- Fixed inelegant handling of alcohol levels and their reporting. +- Newbie level checking is now more uniform across the lib. +- The "stop" verb can now be used to stop fighting. +- Missing /open directory added. +- Driver: source now compiles ok on Cygwin. (thanks, Tricky!) + +---- 2.8 --- +- Released 2008-06-01 +- Cleanup of debug statements. +- Fixed some typos. +- Fixed mangled enters display in obvious exits. + +---- 2.7a28 --- +- Released 2008-06-01 +- Various missing init()'s in Ylsrim & Praxis fixed. Note: those + are still unsupported areas, just kept for historical reasons. They + may eventually be dropped from the distribution. +- Driver: FluffOS updated to handle being compiled with DEBUG defined. +- Driver: Address server errors are now suppressed by default ( ADDRFAIL_NOTIFY + in comm.c ) +- New commands: godmode, wizvision, annoyblock. +- Warmboots are now even more thorough in their recursive loading. +- Bug in player description fixed. +- Finger daemon no longer divulges player email addresses except + to arches (top level admins). +- Whispering now happens in your "current language", not + your native language. +- eventMoveLiving() merged for both npc's and interactives in LIB_LIVING. + Odd messages from this function in LIB_STARGATE fixed. +- Input now checked for non-alphabet characters before being + command-matched. +- Global emotes can now be added by non-admin creators, if they are + members of the EMOTES group. + +---- 2.7a27 --- +- Released 2008-05-15 +- Fixed a crasher when reading zero-length files. +- Driver: Fixed a crasher when some command actions fail to return properly. +- The SetInventory refill now will replenish inventory when + some is missing, not just when all is gone. For an example, see + the new weapons rack in /domains/default/room/arena.c +- The blackjack table now uses "stand pat" rather than "stand" for + ending the game. This avoids amusing problems with physical posture. + +---- 2.7a26 --- +- Released 2008-05-04 +- Added sefun: containers() +- Sentients can now be asked about things, for example, + "ask dirk about leveling". Example: /domains/town/npc/dirk.c +- Added commands: praces, removeclasses, addclasses +- The new CLASS_SELECTION option in config.h controls whether + new players are asked to select a class when they create their + character. Disabled by default. To enable: mudconfig selectclass yes +- Fixed some odd defaults in class definition files. +- Fixed a bug in questing that failed to award quest points. +- XP for kills is now shared among party members if they + are in the same room as the kill. + +---- 2.7a25 --- +- Released 2008-04-24 +- Added periodic cleanup of channel mappings in the i3 router to + prevent peculiar runtimes when running for a long time. +- Fixed channel banning in the i3 router. +- The web server now handles POSTS where the boundary gets + split in separate packets (this caused mysterious hangs when + uploading some files but not others). + +---- 2.7a24 --- +- Released 2008-04-16 +- Creweb chanlogs now listed in "last modified" order. +- Virtual rooms now destructed on warm boots. +- Added day/night descs to outdoor town locations. +- Important npc's in town are now set to respawn after + 60 seconds, if killed or moved. See the SetInventory directive + in /domains/town/room/tavern.c for an example. + +---- 2.7a23 --- +- Released 2008-04-07 +- Warm boots no longer hang people in the process + of editing files. +- Various fixes to warm boots. +- Fixed bug in strings.c that broke QCS. +- Tells between invis cre's now behave more sensibly. + +---- 2.7a22 --- +- Released 2008-03-30 +- Fixed runtime in unknown INTERMUD_D packet handling. +- Fixed runtime in creweb logfile reading of empty files. +- Creators can now cast any spell known to SPELLS_D. Their + default spell level is extremely high. +- LIB_QUEST changes: variable name has been changed and is now + a mapping rather than a class. Quest-specific functions moved + out of LIB_PLAYER and into LIB_QUEST. RemoveQuest() is now + an option. +- Dummy object handling improved...the church elevator should + now work somewhat better. +- Taking over your char from a new session now logs in /log/enters. +- Added commands: warmboot, userload +- Windows users: FluffOS file operations tend to take a dramatically + longer time to complete on Windows than on UNIX. A warmboot, while + not disconnecting the users, may hang them for several minutes + such that they may consider it a "crash" of some sort. + +---- 2.7a20 --- +- Released 2008-03-26 +- Chan logs viewing added to creweb. +- The "muds" channel is no longer added to creators by default. +- The jade ring, powered scout armor, and training dummy now use TYPES_D + to work out the received damage type. + +---- 2.7a19 --- +- Released 2008-03-23 +- SERVICES_D now accurately reports current ports for active services. +- Locate requests now adequately hide invis players. +- The who command no longer counts color codes in title length. +- The blow that kills a creature in combat is now more correctly displayed. +- Fixed a parsing bug in dummy items that reported oddly abbreviated names. +- Fixed various problems with the timing of combat messages. +- Fixed bug in "hist tell" + +---- 2.7a18 --- +- Released 2008-03-23 +- Added sefun: telnet_privp() +- Added commands: unvirt, telnet (user must be in the TELNET group) +- Added TYPES_D to help decipher type names from their integer/bitshifted + designation: eval return TYPES_D->eventCalculateTypes("armor",196608) +- Doors are now knockable and yelling from the opposite side of a + closed door is audible. +- Fixed a bug in intermud-3 tells that allowed you to send tells + to disconnected muds. +- "muds" channel added to report connecting and disconnecting muds. +- "intermud" channel added to report finger, who, and locate requests. +- wild_card() no longer an lfun, consolidated as a sefun. +- Fixed problem in user_path() that caused recursion problems due + to the new "builder" player type. +- Added mouth types to races. +- Purged instances of the class data type from RACES_D. + +---- 2.7a16 --- +- Released 2008-03-16 +- Bundled driver is now a customized FluffOS 2.11 + +---- 2.7a14 --- +- Released 2008-03-13 +- Added example of an environmental suit: /domains/default/armor/scoutsuit.c +- Modified firearms code to include rifles: /domains/town/weap/m16rifle.c +- NPC's now try to shoot weapons they're wielding, if they're loaded. +- Removed out of date faqs. +- Tweaks and fixes to room, rocketpack, and position code. +- Fixed module id bug in Yautja wrist computer. +- eventDescribeEnvironment() moved to /lib/events/describe.c in order + to consolidate player/npc behavior, and to simplify things for people + wanting to customize room appearance. + +---- 2.7a13 --- +- Released 2008-03-09 +- Added commands: position, var, variables, cconv, cwgconv. +- Added sample virtual planet composed of sea bottom area, + underwater area, surface area, sky area, and outer space. +- Updated the sconv command to convert Smaug areas more sanely. +- Added verbs: swim, kneel. +- Rapid death occurs when air-breathing creatures are deprived of oxygen. +- Added a breathing device for exploring non-air environments: + /domains/default/armor/breather.c +- Added a rocket pack for traveling in space. Do NOT "activate" it in + space or you will accelerate out of control. "boost" only, for example + "boost +x+z" then to stop: "boost -x-z" +- Stargates added underwater and in outer space for convenient exploration. + Beware fatal anoxia. + +---- 2.7a12 --- +- Released 2008-03-03 +- IMC2 now supports who requests and tells. "imc2 tell joe@dead_souls_joe hello!" +- Driver workaround implemented for strip_colours() problem. +- Channels can now accept filters. The two built-in filters are colorize and morse + example: cre|colorize hello there! + This is not encouraged for use on intermud. CHANNEL_PIPES must be enabled. +- Builder-generated items fixed up to limit cheating. +- Added sefuns string_colors_old() and dbz_colors() +- Inheritables for living creatures modified to limit cheating by builders. +- MASTER_D can now accept some wildcards in read.cfg. +- Fixed up various lib systems that previously did not expect players to + have home directories. +- The source command will now accept the $N token in source files as a representation + of the player's key name. +- Added RESOLV_D to handle internet name lookups and caching. Use the "resolve" command + to look up names. +- Modified WGET_D to be more generic, added "wget" command for downloading arbitrary + files from the intertubes. + +---- 2.7a9 --- +- Released 2008-02-18 +- Added sefuns: efuns(), sefuns(), efun_exists(), sefun_exists(), estatep(). +- Build-specific verbs and commands moved to builders/ directories. +- Updated memcheck. +- Added commands: arealist, areaclone, areagoto. +- Modified QCS verbs to better handle non-creator builders. +- Added terminal_color() efun to the driver that behaves the + way the FluffOS 2.7 terminal_colour() used to work. +- Added support for the class data type in the identify() sefun. +- Builders now have a workroom and sample areas after logging in + after their addition to the builder group. +- NPC's in builder estates do not give XP when killed and do not deal damage to non- + estate NPC's. +- Items in builder estates are not worth money in shops. +- Weapons in builder estates are ineffective against normal opponents. +- Armor in builder estates affords little protection. + +---- 2.7a5 --- +- Released 2008-02-10 +- Added CreWeb system to allow web editing. See: help creweb +- Added sefuns: unpinkfish(), repinkfish(), socket_ip(), builderp(), web_translate(). +- The mudconfig command can now change the port numbers for inet servers. + +---- 2.7a1 --- +- Released 2008-01-18 +- No lib changes. +- Bundled driver is now a slightly modified FluffOS 2.9. + +---- 2.6.4 --- +- Released 2008-05-16 +- Fixed a parsing bug in dummy items that reported oddly abbreviated names. +- Fixed a crasher when reading zero-length files. +- Driver: Fixed a crasher when some command actions fail to return properly. +- Dummy object handling improved: church elevator should work ok. +- Command for liveupgrades improved for stability. +- Fixed some broken defaults in class files. + +---- 2.6.2 --- +- Released 2008-01-06 +- Fixed some confusing behavior with ":" and ";" as emote characters + in CHAT_D, as well as some confusing channel renaming. +- Fixed security bug that allowed an unprivileged creator access to privileged files. +- The goto command now handles virtual rooms. +- The sefun singular_array() is now just another name for distinct_array(), + and scramble_array() has been added. +- Doors can now be externally called to open or close and will behave properly. +- Armor worn on multiple limbs now does not automatically move to the severed limb. + +---- 2.6.1 --- +- Released 2007-12-27 +- IMC2 emotes now display better (Thanks, Tricky!) +- Fix to addemote command with the -edit parameter (Thanks, Alecksy!) +- IMC2 passwords are now stored in /secure/include/config.h +- Miscellaneous tidying up of GetEnters() (Thanks, Raudhrskal!) +- mudconfig command now handles imc2 password changing. +- grep command is somewhat less restrictive now. +- Fixed odd "feature" in LIB_PAGER that ignored an array argument with only one element + (Fixes things such as blank nickname and screwy help index output). +- GetMaxHealthPoints() can no longer report below 1. This prevents some situations (such as + multiple infections) that cause player to die over and over again. + +---- 2.6 --- +- Released 2007-11-15 +- Minor fixes to tellers. +- Miscellaneous cleanup of commented-out code. + +---- 2.5a25 --- +- Released 2007-11-14 +- Implemented MudOS v22.2b14 behavior into uncompressed read_file operations + in FluffOS to avoid a potential crasher. +- INTERMUD_D no longer uses the class data type. +- LIB_READ is now more economical on disk i/o. +- Fixed a recursion bug in check_user() in MASTER_D. +- Creators can now follow/lead each other. +- LIB_LEAD no longer uses the class data type. +- answers_to() has been buffed up to better handle complex adjectives. +- Injury/damage when lockpicking fails now limited to prehensile limbs. +- New properties added to QCS: SetPolyglot, SetPreventGet, SetPreventPut, + SetPreventDrop, SetDestructOnDrop. +- LIB_WORN_STORAGE now saves its copen/closed state across logins. +- Fixed parsing problem when using multiple adjectives in get/put operations. +- Error messages when a container is closed now make more sense. +- LIB_INTERFACE changed to avoid puking when the user is sent unusually + large strings (e.g. "help modify"). +- Bug in LIB_PAGER callback function fixed. +- Default reset interval is now 2 hours. +- Fixed a misleading message when giving multiple objects to an overloaded living. +- Added sample "pre-boobytrapped" objects: /domains/town/weap/boobytrap_dagger.c , + amd /domains/town/armor/boobytrap_ring.c +- Further fixes for conflicts in the shooting system. +- Fixed a problem with guest logins. + +---- 2.5a23 --- +- Released 2007-11-09 +- COMPAT BUSTER: Objects that used to inherit LIB_DUMMY for special + invisible-but-manipulable functionality (see: http://dead-souls.net/ds-creator-faq.html#2.62 ) + now need to inherit LIB_BASE_DUMMY instead, to avoid nomask problems + with shadow hooks. +- Fixes to shadows to better handle calls to nonexistent shadowed objects. +- Jade ring now autoprotects when worn, and cannot be worn by players unless they are + in the TEST group. +- Most bearsuit bugs fixed. However, a disguised player can be detected by another clever + player with some persistence and simple commands. The point is not foolproof + anonymity, but a bit of fun. Creators can very easily detect disguised players + using the command: scan here +- The grep command now prevents you from victimizing the mud with + an excessive recurse. +- The clone command will now try to figure out a nearby matching object + to clone if it doesn't find the file you specify. +- Ammunition and ammo case bugs fixed. +- "cd ~-" and "cd -" will both now change to your previous working dir. +- Added commands: morse, unmorse +- The Healers Guild now sells poison antidote and claritin. +- Added verb: show +- Fixed verb/item conflict when two people in the same room try to shoot each other. +- The heal command now does a more thorough job of it. +- Germs no longer get dropped on login. +- LIB_PAGER now uses mappings rather than classes, and been fixed a bit. + +---- 2.5a21 --- +- Released 2007-11-05 +- Improvements to router code. +- Added basic support for boobytraps. Verbs are: boobytrap and disarm. Lib + objects are LIB_BOOBYTRAP_SHADOW and LIB_BOOBYTRAP_OBJECT. A sample + trap object can be found at: /domains/town/obj/needle_trap.c + Finding boobytraps is done with the command: search +- Re-enabled support for lockpicking tools. See /domains/town/obj/lockpick.c +- Added missing race files. +- Fixed append_line() sefun. +- Added ReadDir and ReadFuns events. +- Fixed log rotation problem in snooper object. +- IMC2 daemon reloading should no longer spam stdout with "Done." +- IMC2 connectivity can now be enabled/disabled with the mudconfig command. + +---- 2.4.6 --- +- Released 2007-11-04 +- Bundled driver is now FluffOS. +- users() sefun override properly fixed. + +---- 2.5a19 --- +- Released 2007-10-31 +- Enabling/disabling the logging of remote or local channels can now + be done with the mudconfig command. +- rwho now defaults to i3. imc2 can be specified. See "help rwho" +- Ping interval now changed to about 5 minutes. Now configurable + with the mudconfig command. +- The help command now defaults to displaying command help, if the + argument to "help" is under multiple categories. The additional + categories are listed in the command output as well. +- Added commands: file, wizroll, roll, inherits +- Added sefun: roll() +- Tidied up get_object() to fail gracefully if necessary. +- New or newly working lib objects/events: LIB_ROLL, LIB_DIE (for dice), LIB_VEHICLE +- Added sample vehicles in /domains/default/vehicles: hoverpod and strider + Vehicles are still *experimental* and under development! +- The command showtree will now try to resolve the most sensible local object, + if it can't find a file with the name you specify. +- Miscellaneous cleanup of loose tc()'s. + +---- 2.5a18 --- +- Released 2007-10-27 +- Win32 FluffOS executable problems fixed, and the current windows + driver is now FluffOS. +- Compile time compat fixes added for Wolfpaw hosts. + +---- 2.5a16 --- +- Released 2007-10-24 +- FluffOS code altered to compile on Win32, but the included binary + is still MudOS. +- Added Shadyman's updated Tim@TimMUD IMC2 code (see: help imc2 ) +- Fixed very confusing behavior when adding a player-usable race + with admintool if the race file was set to PLAYER_RACE. +- The users() sefun override now is optimized for FluffOS. It works + fine on MudOS for back-compatibility, but less efficiently. +- FluffOS code and compilation options somewhat modified to get + around minor compatibility issues. + +---- 2.5a15 --- +- Bundled driver is now FluffOS. + +---- 2.5a14 --- +- Tightened up last_string_element() sefun. +- Router improvements: a) IRN nodes now reset a peer's connection + if no data is received within a set time. b) IP's put on the blacklist + for having the wrong password are now automatically removed + from the blacklist after a set time (default 1 week). +- Router fix: a bug that had the router sending mudlist updates to the + wrong muds has been fixed. + +---- 2.5a13 --- +- Released 2007-10-12 +- Removed command: where +- Modified users() sefun override to avoid a crasher under mysterious + circumstances. +- Added SEFUN_PLURALIZE to config.h, to allow the sefun override of + the driver's pluralize() efun. +- Added command: rot +- Fixed driver problem that stopped compile at malloc.c (stole the + fix from FluffOS!) +- Fixed driver problem that made timekeeping fail (ualarm). +- Keepalive pinger object no longer requires you to be actually idle. +- WARNING: Vehicles do not work yet. Do not be sad if you find what + looks like vehicle code that doesn't work +- Bonus object works properly now. +- Miscellaneous fixes to i3 router code. +- Libtest bot script fixed up. +- Fixed a problem in the users() sefun that mysteriously hosed + 64-bit Linux installs. + +---- 2.4.4 --- +- Released 2007-10-12 +- Miscellaneous minor bugfixes. +- Fixed driver problem that stopped compile at malloc.c (stole the + fix from FluffOS!) +- Fixed driver problem that made timekeeping fail (ualarm). +- Bonus object works properly now. +- Fixed a problem in the users() sefun that mysteriously hosed + 64-bit Linux installs. + +---- 2.5a12 --- +- Released 2007-06-24 +- Nailed some really pesky router crashers involving null socket owner + object references. +- Added sefuns: morse(), unmorse(). +- Added an automatic Morse coder/decoder system to channels. To encode + messages, make the first word of the message be: ^encode + +---- 2.5a11 --- +- Released 2007-06-23 +- Various broken table objects (eg the Orc Shaman's altar) fixed. +- The jade ring no longer makes reporting npc's invulnerable. +- Numerous fixes and updates to IRN system in router code. +- Various broken worn storage items fixed. + +---- 2.5a10 --- +- Released 2007-06-19 +- Removed a channel bug introduced in a8 that prevents the use of renamed + channels like ds, intergossip, etc. +- i3who now works properly for invis users. +- Router now retires muds that haven't connected in a week from the mudlist. + +---- 2.5a9 --- +- Released 2007-06-15 +- Fixed a peculiar crasher in the router when running under Linux. + +---- 2.5a8 --- +- Released 2007-06-15 +- Added Set/GetMatching() to LIB_ID so that individual items + can choose not to be "object matched". +- Intermud status sign should now work for reals. +- Added a shadow management system, so that objects can receive multiple + shadows and remove them individually if necessary. +- New test character tool: /domains/default/armor/jade_ring.c allows you + to receive detailed information about damage you receive, where, how + much before protection, and how much after protection. It can also make + you immune from damage, and can be used to force creatures to report + their damage to you in a similar way. +- Added command: mem +- IRN tested and confirmed to work well with 4 nodes. +- Router fix: Sending a message on a channel a mud wasn't listening to now + enables the channel for the mud *and* sends the message. +- Router fix: if a mud tries to connect with the same name as another + mud, and from a different address, the currently connected mud is + notified. This serves two purposes: alerting a mud to a potential + problem, and triggering a reset of the socket if it's actually zombied. + +---- 2.5a7 --- +- Released 2007-06-02 +- Improved IRN multi-peer support. +- Fixed various router runtimes and improved IRN data integrity. +- The bear costume now effectively disguises a player in most + ways and they truly appear to be a bear. A shadow is used for this purpose. +- Modified driver to approach POSIX setitimer() compliance. +- 100% merged Windows and UNIX driver code. +- Added calendar information to the mudtime command. +- The race of a creature is now automatically added to its id array. +- Added ChangeLevel to sanely manage the advancement of skills + and stats when a creature's level changes. The stat and skill "class" + now dictates when stat and skill level is increased. When the + new player level is divisible by 3, for example, and the stat class + is three, then the stat is increased by 1. +- Added checks for TEST group membership to autosave and auto-quit. +- Implemented workaround to runtime error when moving into a room + with many objects (caused by a buggy new parser feature). +- Fixed bug in /lib/body.c that caused an erroneous eventFall() where + eventCollapse() was called for. + +---- 2.4.2 --- +- Released 2007-04-23 +- New subcommands added to liveupgrade: revert and alpha. +- Various security exposures mitigated. +- Fixed CanGet() bug in LIB_CHAIR (Thanks, K'Azdean). +- The new mkdir_recurse() sefun allows liveupgrade to handle recursively creating + directories if needed. +- Fixed a bug in sample virtual areas that made travel nw, sw, or se take + you to the wrong place. +- CALL_OUT_LOGGING has been reworked to be less vile and it now breaks + few things, if any. +- Added an automapper. See: help automap +- Added Smaug area conversion utility, found in /secure/obj/converter_smaug.c +- A player's start room can now be a virtual room or a + cloned object (e.g. a mount). +- Fixed a problem with sending a string to eventDie() as an argument. +- Beefed up get_stack() sefun. +- Added virtual area to wiz labs for mounted combat testing. +- Added 3d virtual sky area to mounted combat arena. +- Fixed various problems with sky-based 3d virtual areas such as + falling through multiple rooms, flying up more than one room, etc. +- The "source" command now takes the -q flag to indicate queuing, rather than + immediate execution. This allows creators to be subject to the maximum + number of commands per second limit but still be able use sourcing. +- The object matching code used to step on objects. For example, if your room had + a "bar" as a SetItem, and a barstool as an inventory item, and OBJECT_MATCHING + was enabled, then "exa bar" would actually return the barstool's long desc. + This has now been fixed. +- The LastLocation property in players now handles cloned environments (e.g. mounts) + and the return command also now deals with them correctly. +- Fixed a bug in eventDescribeEnvironment() that prevented riders from + seeing living creatures in a room when issuing the command: look +- Fixed bug in npc's that made mounted riders hear spoken messages more than once. +- Fixed another carry leak in containers. Containers now update their + environments' CarriedMass. +- Fixed bug in LIB_BONUS that allowed the dropping/putting/getting of the + invisible bonus object. +- Fixed bug in LIB_POTION that failed to set the effect's duration. +- LIB_CLEAN will no longer dest inheritables in the /lib/ directory. This + avoids a situation where the inherits() efun returns confusing information. +- FILE_D now does a daily recompilation of the mud files list. +- Mounts are now set to resist room resets, so that one's loot doesn't + get unloaded from memory just because they left their horse alone too long. +- The encre command now moves a player's estate to her creator homedir. +- The suicide command now removes a creator's directory or a player's estate + and moves it to the /secure/save/decre directory. +- SetAttackable can now take a function as an argument. See /domains/town/npc/lars.c + for an example. +- A bug in SetAttackable that allowed players to be attacked when a string + was set as an argument is fixed. +- A bug in QCS that prevented deleting rooms with relative "customdefs" defines + has been fixed. +- "restore here" now works. +- Fixed typo in Chapter 8 of the Admin Guide. + +---- 2.4.1 --- +- Released 2007-03-21 +- The display of obvious exits can be over the desc in brackets + or under the desc in text form, depending on the NM_STYLE_EXITS + setting in config.h. This can be configured with: mudconfig nmexits [on|off] +- Added Diku-style equipment (eq) command. +- It's now possible to use two-letter emotes on channels, and one may + use "channel:" syntax as well as "channelemote", eg: "cre: foo" +- Added age check to login for COPPA compliance (Technically this is + not necessary since COPPA applies to commercial enterprises, but + I'm adding it on general principle). +- Fixed nonsensical parsing bug in LIB_COMMAND. +- Liveupgrade will now create a dir if necessary. +- Rooms missing from /std added. + +---- 2.4 --- +- Improved security in WGET_D. + +---- 2.3a20 --- +- convert_ascii no longer uses a broken (and slow) lookup table. It + also now has a reverse counterpart, convert_into_ascii. +- Fixed a null array in LIB_MOUNT that hosed up some non-mount npc's. +- Added defaultdomain subcommand to the mudconfig command, so that + you can make your new domain the default one for the mud with the + command: mudconfig defaultdomain /domains/MySpiffyArea +- The domaincreate command now adds all the rooms necessary to make a + domain work as a default domain. +- Fixed a bug that allowed players to be attacked by other players + despite PK and SetAttackable safeguards. +- Fixed a broken add_action in jennybot that emulated a broken verb. +- The liveupgrade command has been revamped to avoid a crasher (!!!) and + no longer requires multiple "liveupgrade all" entries. Just one will do. +- WGET_D is now throttled to prevent overwhelming the network. +- REMOTEPOST_D is now more aggressive about retiring old failed mail to avoid + idle OOB objects from constantly loading. +- Fixed bug in goto that broke using a string as an argument. + +---- 2.3a19 --- +- Released 2007-03-13 +- Further simplified parsing: it is no longer necessary to "put book on table" or + "give sword to fighter". You can now "put book table" and "give sword fighter". + Added to OLD_STYLE_PLURALS, COMMAND_MATCHING, and OBJECT_MATCHING, you can now + issue brutish stuff like: "gi bo 2 fi 3" instead of "give the second book to the third fighter". + The older syntax still works, of course. +- To emulate Diku behavior, the lib will now accept number.object syntax, eg: "gi 2.bo 3.fi" +- Fixed an excessively ugly error message generated by issuing certain non-alphabetic characters as the + first char in a command. +- Fixed a parsing bug in OLD_STYLE_PLURALS that tried to incorrectly index the command line array. +- The commands goto and people have been updated to handle mounted players. +- Events that occur on mounts are now properly communicated to the mount's environment, + and vice versa. +- When your mount engages in combat, the messages are no longer confusing. +- Fixed last major obstacle to http liveupgrades. Files should no longer get mangled in-transit. + +---- 2.3a18 --- +- Released 2007-03-12 +- If OLD_STYLE_PLURALS is defined in config.h, commands will be translated + from "drop book 2" format to "drop 2nd book" format automatically. +- Added SetNoCondition() to living things. If you don't like indications of + health on an npc, make it SetNoCondition(1) and its health status will not + report on looking at it. This will also work on players. If you want this to + be the default behavior for players, add a call to SetNoCondition in connect.c. +- Added Set/GetAttackable to LIB_LIVING, so that npc's can be made immune + to players' standard attacks. Note that your mud may still contain special + weapons or spells that can trick the npc into fighting, so you may also want to + set the npc to not pick fights, using SetPacifist(1) +- Names of invis players are now scrambled when they make rwho requests, + so that the target mud does not know who has queried it. +- Invis admins now correctly receive pings/tells/rwho's/etc. +- When mounted, you can now "ride s" rather than "ride south". +- The copy verb now deals with custom defines more sanely. +- It is now possible to create rooms not linked to anything, with the create command. + Example: create room none newroom1.c +- The decre command no longer freezes the target. +- Ping daemon does not try to ping when intermud is disabled. +- Added sefuns: convert_newline, clean_newline_file, to deal with http file corruption. +- WGET_D now correctly handles receipt of newlines in files. + +---- 2.3a15 --- +- The liveupgrade command has a check now so that trying to "liveupgrade apply" while + downloads are in progress will fail. +- Unique objects are now dropped when a player leaves the game whether or + not the mud is set to default inventory retention. +- The sefun print_long_string() now deletes its temp file when done. +- Mounts updated and improved: short and long descs include riders, room messages are relayed + to riders, and riders can be examined, among other enhancements. Some messages, such + as combat messages, are still a little confusing. +- The initfix verb now fails reasonably for virtual rooms. +- Non-meat creatures behave somewhat more sensibly now when shot. +- Fixed a null cwd error on first admin login. +- It is now possible to force room inventory to respawn every X seconds. By passing an + array in SetInventory, an item can be respawned if it is missing. See the example + in /domains/default/room/wiz_hall.c , which is set to check every 10 seconds to + see if the tree is there. If it is not, it will respawn one copy of it. +- The who command no longer counts Pinkfish code in its character count for title length, + so you may have a diferent color for every letter of your 50 character long title, + if you absolutely positively MUST. +- Added a LIB_BANK as a wrapper for tellers, like LIB_SHOP for vendors. It's now possible + to just "balance" and "deposit all" rather than "ask zoe for balance" and "ask zoe to + deposit all". +- Added command "speakcolor" to set the color in which you receive spoken messages (if, + for example, you dislike people saying things in cyan). + +---- 2.3a14 --- +- Fixed runtime in lead/follow code with SetEnters. +- Fixed bug that prevented followers from following through a SetEnter. +- Made some important changes to the liveupgrade system to handle + unusual exceptions. + +---- 2.3a13 --- +- The liveupgrade command now defaults to http connections to the dead-souls.net site, + which is orders of magnitude faster and more secure than oob, as well as more + reliable and efficient. +- Implemented shutdown packet in router. If the delay time is less than + 7 days, it just disconnects the mud. Otherwise it deletes the mud's info. +- Router connections with a sufficiently large number of password failures + are automatically blacklisted. +- Removed muds are now properly synced on IRN. +- Intermud passwords now use 9 digits. +- Dead Souls now handles Tricky's ping-req and ping-reply packets. +- Network room is less spammy on reconnects. +- Arch/wiz room intermud status is now updated in realtime. The status indicated is always current. +- Fixed chanlist problem in router. +- MAX_COMMANDS_PER_SECOND now also applies to creators. +- Modified router and router command to add functionality. See: help router +- Router now periodically sifts through sockets and discards router sockets + not currently associated with a connected mud. +- Fixed problem in validate() in PLAYERS_D. + +---- 2.3a11 --- +- Replying to intermud mail now works. +- Fixed spurious error message in mudconfig command. +- Added basic Inter Router Networking support to router code. +- Fixed bizarre exit message if you're not standing and you go home. + +---- 2.3a10 --- +- Released 2007-02-15 +- Added intermud mail support. +- Fixed $P in prompt. +- Added security fixes to router. +- Abstracted the connection code from the everything-else code in the + router, so that modifications can be made without having to drop muds. +- Moved people command to /secure so admins can see each other. +- Invis admins no longer generate connection messages when logging in or out. +- Fixed mv command. +- Creators can now sleep. +- Telling to a sleeping person now generates a warning. + +---- 2.3a9 --- +- Released 2007-01-30 +- Fixed bug that prevented players who idled out while editing from + being booted. +- Sending a tell to an NPC no longer runtimes. +- Closed up various exploit vectors with overrides of efuns. +- Null groups no longer hose MASTER_D. +- Fixed spurious error message in mv command. +- Added the "prompt" command, with which you can now customize dynamic prompts. +- Added wimpy status to env command. +- Fixed some bugs and an exploit in mail code. +- Creators can no longer snoop by default. To make snooping available + to a creator, add her to the SNOOPER group. She will then be able to snoop + players, but not creators. To let her snoop creators, you'll need to + promote her to assistant admin, or edit valid_snoop() in /secure/sefun/sefun.c . +- Added inews to the default creator channel list. +- Fixed grievous carry leak in containers. +- Fixed some null error messages when default parsing is enabled. +- Fixed a runtime with default parsing enabled. +- Fixed error message when giving something to an overloaded creature. +- Added verbs: activate, deactivate, install, uninstall. +- Added LIB_ACTIVATE, LIB_INSTALL. +- Added wrist computer as an example of an object that has functions + added to it without shadows. See /domains/default/armor/wristcomp.c + and /domains/default/obj/module_cloak.c +- Only one LIB_OOB ob is created for a full liveupgrade. +- You can now do a liveupgrade from behind a firewall: opening + your oob port is no longer necessary. +- Fixed flashlight bug. +- Fixed elevator button/dummy object bug. +- System channels are added to players on login if they're missing. This + corrects a problem with login announcements on upgraded muds. +- First admin logins now may choose between four genders. +- Shortest command matching is now shortest *unique* command matching, to + avoid accidentally executing the wrong command. +- Added OBJECT_MATCHING, COMMAND_MATCHING, BARE_EXITS, and + LIVEUPGRADE_SERVER to mudconfig command. +- The wizlist command generates an updated cre list regardless of whether + the mud is upgraded or at its native rev. +- Implemented LIB_ROOM fix suggested by Memrosh. + +---- 2.3a5 --- +- Released 2007-01-19 +- Added OOB support. +- Added liveupgrade system. See: help liveupgrade + +---- 2.3a1 --- +- Released 2006-12-29 +- Fixed null errors in wield verb. +- DEFAULT_PARSING now works correctly. If you have two keys and two tables, + "put key on table" will put a key on a table without causing + an "ambiguous parsing" error. +- Added sefuns: atomize_string, atomize_array. +- Setting OBJECT_MATCHING in /secure/include/config.h to 1 will enable + "shortest matching name" behavior, so that "zap di" is equivalent + to "zap dirk". +- Setting COMMAND_MATCHING in /secure/include/config.h to 1 will enable + "shortest matching command" behavior, so that "upd here" is equivalent + to "update here". +- Added command: qed. +- Setting BARE_EXITS in /secure/include/config.h to 1 will now let you + use "north" and "cabin" as valid movement commands, rather than "go north" + and "enter cabin". +- "afk" property is now removed on login. +- Extra description strings from GetAffectLong() no longer duplicate if + you're carrying multiples of an item. +- Modified races so that non-meat lifeforms don't leave rotting meat corpses. +- Added passive-mode support to ftp server ( contributed by Duuk @ Haven ). +- Added code to prevent "bad alternate router data" bug that tends + to knock muds off the router. +- Added "neutral" (aka hermaphrodite, aka intersex) and "none" to + user-selectable gender choices (Not applicable to first admin). +- Lower case mudlib names now work in mudlist. +- Probability lab bugs have been fixed. Charly and Charles now save + their persistent data in a sensible way. +- "copy /obj/room.c" now works for non-admins. +- Fixed up some issues with the dsversion command. +- Added sefun: chunk_string(), groups(), query_intermud_ip(). +- Added commands: wizlock, wizunlock, wizlist. +- Added commands: gag, mute. +- Fixed another paradox condition in the router where a mud could be + simultaneously connected AND disconnected, causing reconnection problems. + A periodic check for this condition will clear it every 15 minutes or so. +- Added command: flee. +- New creators are polyglottized by default. +- inet, ftp, http, and rcp services can now be configured with mudconfig. +- The router room is now the server monitoring room. Admins may now use + that room selectively to monitor traffic on the following services: + ftp, http, rcp, i3 (router). They can be monitored in any combination, + and the messages are in different colors to help distinguish between them + when multiple service monitoring occurs. +- The netstat command now lists the correct FD's. +- Reverted default MALLOC to something that fancy new 64 bit computers like. +- Retooled inet/server subsystem to accommodate RCP, added creremote + and LIB_REMOTE to the extra/ dir of the distribution, as well as instructions. +- Recompiled Windows driver to match current unix standard config. +- Finally (I hope) nailed that pesky router connection problem. +- Fixed bug in LIB_LOCK that prevented carried, lockable objects from working right. +- "unsnoop" and "unsnoop all" now work. +- Cleaned unwatched players from "snoopreport". +- /log/catch messages now have time stamps. +- Fixed errors/typos in groupmod and mudconfig help text. +- There is an error in the help file for groupmod. It should look like this: + Syntax: groupmod [-a|-r] GROUP NAME + groupmod [-c|-d] GROUP +- Fixed a bug in grep that made it choke and halt on binary files. It still + chokes, but it continues grepping after reporting the runtime. +- "decre" no longer removes all channels. Note that testing encre and + decre repeatedly on the same character will probably generate problems eventually. +- Added LOCAL_TIME parameter to config.h. Some OS'es use UTC and offsets for + timekeeping, others use a "local time" setting. Rather than try to play offset + games and fail miserably, this setting is meant to address that. +- Added "mudconfig" command to enable the convenient changing of some config.h parameters. +- LIB_CONNECT now checks CFG_IP_UNRESTRICT as well as SAME_IP_MAX to determine + if the connection should be permitted. This allows you to specify ip's that + are immune from "max connection" restrictions. +- LIB_CONNECT now checks each incoming connection to determine whether it + is the last known ip of a SECURE user. If it is, the connection + is permitted regardless of SAME_IP_MAX. +- It is now possible to use the "home" command to go to other + creators' workrooms. +- GetPlayerList(), GetCreatorList(), and GetUserList() in PLAYERS_D can now be trusted + to provide correct information (for new installs). +- It is now possible to get player data from users that are logged off, by specifying the variable + to the player daemon. For example: eval return PLAYERS_D->GetPlayerData("cratylus","Properties") +- Beefed up groupmod to handle group adding/deleting, and enable (some) use by ASSIST. +- Added command: groupmod. +- Added commands: pause, unpause. Used to remove/restore commands + from a player with behavior problems. +- Recurring reboots can now be disabled in config.h with DISABLE_REBOOTS. +- Added command "chancolors" to toggle seeing colored channel messages. This is + to limit the annoyingness of people who add pinkfish color codes + to their channel messages. +- Fixed a problem in LIB_SHOOT that prevented targeting specific + victims, as well as a runtime bug when shooting things in your inventory. +- Fixed a runtime in CHAT_D that mishandled unknown chans. +- If EVENTS_LOGGING is set in config.h, new events added to the + EVENTS_D will be logged to /log/secure/events. +- If CALL_OUT_LOGGING is set in config.h, call_outs not created by + privileged objects are logged (There shouldn't be any need to + log call_outs initiated from within /secure). call_outs originating + in /daemon are not logged either, due to the size of the resulting + log growing too quickly. +- Initiating flight while resting on furniture no longer corrupts + a creature's short desc. +- Fixed bug where "look at thing on blah" let you look at + the thing even if it was invis. +- Fixed bug in LIB_NPC that revealed carried invisible objects. +- Commented out annoying addr_init error in driver that spams + STDERR when running on Solaris. +- tc() now also prints to STDOUT. +- SetItems() now works properly in tangible items (eg Orcslayer). +- Fixed problem with out-of-sequence messages using TalkResponse + in sentients. +- Fixed incorrect behavior during automated reloads. +- Fixed an incorrect inherited call in LIB_CHAIR. +- local_options now has "ref" defined as a reserved word. This allows + the use of "ref" as a keyword for passing variables by reference, + instead of by value. For an example, see /domains/default/obj/pass_example.c +- Fixed bug in router code that created problems when muds + originating from the same ip connected and reconnected. +- Added commands: files, doctool, showfuns, createfix, findfun, + pk, find, chanremove, chancreate. +- Got rid of confusing null long desc on doors when initfixed or reloaded. +- Got rid of a null error message in reply command when the target + is missing. +- Fixed problem in help daemon that prevented race help from displaying. +- Revolvers reimplemented. +- Driver options now output verbose warnings about inherited function + conflicts and unused variables if you use local_options.debug at + compile time. +- Eliminated various function conflicts in lib files. +- Isolated unused variables in /lib file function arguments with + true() and false(). +- true() and false() now can take any number of arguments, and always + return 1 and 0, respectively. +- Fixed bug in "home" command. +- mudos.cfg now has a time to swap value of 0, to disable + swapping. I've seen now more than one driver crash due to + a swap bug, and I'm not sure what the problem is, so until I do + know, swapping will be disabled by default. +- Added RELOAD_D for objects that need to somehow get + themselves reloaded without incurring recursion problems. +- ROUTER_D now resets every 25 hours or so. +- The banish command now has an "-s" option to banish offensive + substrings from names. +- Corrected problem in addraces command that distorted which races + could be used by players. +- Modified make_workroom so that newbie creators who hose their + workroom can "restore workroom" without first having backed it up. +- Fixed bug in snoop command that caused bizarre situation when + snooping yourself using your capitalized name. +- "X looks around" and "checks possessions" messages are now suppressed + in meeting rooms. +- Fixed reporting of object mass so that both the mass of the container + and its contents are returned. This corrects a LIB_MOUNT error. +- Fixed archaic parse_* lines in some verbs that interfered with VERBS_D. +- Fixed "say to". +- Added new features to each race file. +- The findfun command no longer fails with timeouts and it executes + extremely fast due to the use of the new daemons. +- Fixed QCS bug that prevented adding includes. +- Added features to races: body type, size, average mass, whether they can + swim, and what they breathe. +- New daemon: FILE_D, traverses the lib hierarchy, compiles + a list of all files, and maintains the cached data for querying. + Full refreshes of the data happen relatively quickly, in under + a minute, and does not lag the mud much. +- New daemon: FUNCTION_D, uses FILE_D to determine inheritable lib + filenames, then queries each for the names of functions defined. + Full refreshes of this data happen slowly, several minutes + or longer. However, the mud is not much lagged during this process + except while processing very large files (e.g. /lib/body.c). +- Fixed "first admin bug" that failed to add channels. +- Implemented emotes bugfix provided by Aransus. +- Modified the template realm somewhat. There are now flask examples, + and each wiz gets their own toychest, rather than using one default file for all. +- Added to QCS: Set/AddTerrainType, SetDefaultLanguage. +- Added room terrain types. +- Non-DS code no longer needs ::create() in the create() fun to work. +- Campus meeting room no longer blocks teleports. +- Added stable with mountable horse south of the town schoolhouse. + "mount horse" and "dismount". +- Mounts must now be befriended before being mounted. To end your + ownership, "abandon" the mount. +- Fixed QCS bug when running in Windows that turned '\n' into '/n' +- Added DEFAULT_PARSING to config.h. If this is set to 1, commands + that normally fail with an ambiguity error ("Which X do you mean?") + will instead default to the first eligible object. +- Fixed problem on i3 router that caused muds to share fd's. +- Added MAX_COMMANDS_PER_SECOND to config.h to enable a cap on scripters. + This affects players only. +- Fixed race-based skills. See http://dead-souls.net/ds-creator-faq.html#2.45 +- Added LIB_FLASK (for canteens, coffee cups, etc). Flasks can + now be filled at the town's riverbank and at the shore. +- Added verbs: pour, fill, empty. +- Removed encre/decre from admintool. It was goofy and dangerous. +- Added SetActionsMap() to LIB_ROOM, to enable room actions with variable + frequencies. The old SetAction() method also still works. +- Added RETAIN_ON_QUIT define in config.h, and SetRetain() and GetRetain() + to LIB_PERSIST. Any object that returns 1 on GetRetain() is retained + across logons, regardless of RETAIN_ON_QUIT. Any object that return 0 + on GetRetain() is removed on quit, regardless of RETAIN_ON_QUIT. Changing + RETAIN_ON_QUIT requires a reload of every object, or a restart of the mud. +- Added sample potions to /domains/town/meals and to Oana's magic shop. +- Empty bottles now behave properly across logons. +- cp and mv now take -f as a flag to force overwriting. +- Removed channels (except admin ones) stay removed. +- Fixed double-logging in channel messages. +- Recompiled windows binary with new options and fixed socket_efuns. +- Added well-door system. +- Changed stat command to handle economies that do not have gold. +- Idle times now report in a human readable format. +- SERVICES_D: unk-src error now triggers an INTERMUD_D reload. +- Router verified to accept over 400 separate mud connections. +- Default connection mud for the telnet room is now Dead Souls Demo. +- Added cambot to conference room. +- Added commands: files, doctool, showfuns, createfix, findfun, pk. +- Fixed a sockets bug in the driver (thanks to Zac@StarMUD) +- Removed intergossip as a default enabled channel. Added dchat + as a default enabled channel.- Added Nimrod's recursive/numbered grep enhancements. +- Added numerous back-compat funs and obs for TMI-2 porting. +- Added numerous back-compat funs and obs for Nightmare 3 porting. +- Added daemons: ESTATES_D, ALCHEMIST_D (materials properties). +- Router admin commands will now also take ip+port. +- It is now possible to mudlist, rwho, and tell to a mud using its + ip address+port. For example: rwho 71.234.154.99 6666 +- The muffing commands now also affect tells. "earmuff Tatianna" will + prevent you from hearing channel messages *and* tells from tatianna. + You can also muff ip address + port, example: + earmuff @194.70.3.211 3000 +- "tell history" now provides a limited history of your tell messages. +- Fixed a problem adding currencies with admintool when there are + fewer than 3 existing currencies. +- Reverted to the old Nightmare calendar: mud time of day and sky + events should make more sense now. +- Added SAME_IP_MAX define in config.h, to help limit bot spam/abuse. + Default limit is 4 connections per IP. +- Fixed login problems in bots. +- Raised ulimit in start script to 1024. +- Dying creatures can no longer be observed to remove armor and weapons. +- Ludicrously long environment descriptions no longer break + when displayed. +- "alias foo" no longer removes the "foo" alias, it merely displays + it. To remove that alias, the new way is: + unalias foo +- New players are 100% proficient in the language Common, and it + is set as their default language. +- You may now "speak in LANGUAGE" to set your default "say" language + to what you specify. To make it so that "say foo" comes out in Rigellian: + speak in rigellian + say foo +- Creators don't lose stamina when moving around while invis. +- Added sefuns check_string_length and print_long_string to handle + Strings Of Unusual Size. +- Removed call_outs from PING_D. +- Added DeadMan switch to PING_D. +- Added logon notification channel <connections>. +- Added A_CUSTOM as an all-purpose armor type that can be worn + on most body parts. +- Enhanced channel and event logging to the router. +- Fixed potential channel spoof and channel admin problems + in the router. +- Modified various commands to deal with Load-Addled Game Syndrome. +- Modified LIB_BOOK to avoid tedious reload on init(). +- Added player bots for load testing (tested on Linux with + approx 250 player bots, all active, with no noticeable lag + on a crappy 1.2GHz laptop). +- Beefed up the router command. +- Character creation now does not save the playerfile until + the entire creation process has completed. +- Made AUTO_WIZzing a choice for the user, rather than + truly automatic. +- Added privacy field to template workroom. +- Added LIB_MESSAGES fix suggested by Memrosh. +- Fixed a LastLocation bug in LIB_PLAYER. +- Fixed shadow bug in the remote control. +- Added catch_tell room to arch area. +- Fixed reaper bug that destructed shadows. +- Fixed a bug in room messages during eventMoveLiving(). +- Added Praxis domain. +- Fixed customdefs issue in QCS with files in /domains. +- Added FILE_D. +- Added LIB_MOUNT, LIB_DOMESTICATE. +- Fixed carry leak in arches during shutdown. +- Fixed save problem in arches during shutdown. +- COMPAT BUSTER: changed GetCustomPath and GetCustomCommand + to query_custom_path and query_custom_command. +- Cleaned up strange formatting error in old sefun docs. +- Added sefun: query_local_functions. + +---- 2.1.1 --- +- Released 2006-09-27 +- Fixed a bug in chat.c that sent comms on new local channels to + the router (!!). +- Fixed "return" command bug and various travel message bugs + in LIB_CREATOR and LIB_PLAYER. +- Eliminated savefile data leak in admins on shutdown. +- Fixed overly aggressive reaper that killed shadows. +- Admintool security flaw has been removed by removing encre and decre from its menu. +- It's no longer possible to screw up admintool by removing too + many currencies at once. +- Updated verbs/commands: reload, gauge. +- "Can't drop things in a no-teleport room" bug fixed. +- Default channel removed: intergossip. +- Default channel added: dchat. +- Players can no longer use the force command. + +---- 2.1 --- +- Released 2006-07-12 +- 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 --- +- Released 2006-07-09 +- 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 --- +- Released 2006-07-05 +- 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 --- +- Released 2006-07-05 +- 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 --- +- Released 2006-06-18 +- 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 --- +- Released 2006-06-06 +- 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 --- +- Released 2006-06-03 +- Ran into some trouble when releasing r23. For + technical reasons, it's being re-released as r24. + +---- 2.0r23 --- +- Released 2006-06-02 +- 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 --- +- Released 2006-05-15 +- 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 --- +- Released 2006-04-22 +- 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 --- +- Released 2006-04-14 +- "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 --- +- Released 2006-04-07 +- 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 --- +- Released 2006-03-29 +- 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 --- +- Released 2006-03-24 +- 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 --- +- Released 2006-03-12 +- 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 --- +- Released 2006-02-23 +- 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 --- +- Release 2006-01-30 +- 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 --- +- Released 2006-01-23 +- 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 --- +- Released 2006-01-17 +- 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 --- +- Released 2006-01-12 +- 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 --- +- Released 2006-01-05 +- 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 --- +- Released 2006-01-02 +- 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 --git a/lib/doc/SUPPORT b/lib/doc/SUPPORT new file mode 100644 index 0000000..ab50417 --- /dev/null +++ b/lib/doc/SUPPORT @@ -0,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 --git a/lib/doc/applies/__INIT b/lib/doc/applies/__INIT new file mode 100644 index 0000000..54da750 --- /dev/null +++ b/lib/doc/applies/__INIT @@ -0,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 --git a/lib/doc/applies/author_file b/lib/doc/applies/author_file new file mode 100644 index 0000000..c006d71 --- /dev/null +++ b/lib/doc/applies/author_file @@ -0,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 --git a/lib/doc/applies/catch_tell b/lib/doc/applies/catch_tell new file mode 100644 index 0000000..6aa0c2b --- /dev/null +++ b/lib/doc/applies/catch_tell @@ -0,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 --git a/lib/doc/applies/clean_up b/lib/doc/applies/clean_up new file mode 100644 index 0000000..063cd34 --- /dev/null +++ b/lib/doc/applies/clean_up @@ -0,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 --git a/lib/doc/applies/compile_object b/lib/doc/applies/compile_object new file mode 100644 index 0000000..200d76d --- /dev/null +++ b/lib/doc/applies/compile_object @@ -0,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 --git a/lib/doc/applies/connect b/lib/doc/applies/connect new file mode 100644 index 0000000..2442dd2 --- /dev/null +++ b/lib/doc/applies/connect @@ -0,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 --git a/lib/doc/applies/crash b/lib/doc/applies/crash new file mode 100644 index 0000000..b0254c0 --- /dev/null +++ b/lib/doc/applies/crash @@ -0,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 --git a/lib/doc/applies/create b/lib/doc/applies/create new file mode 100644 index 0000000..e0cf417 --- /dev/null +++ b/lib/doc/applies/create @@ -0,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 --git a/lib/doc/applies/creator_file b/lib/doc/applies/creator_file new file mode 100644 index 0000000..21d3b32 --- /dev/null +++ b/lib/doc/applies/creator_file @@ -0,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 --git a/lib/doc/applies/domain_file b/lib/doc/applies/domain_file new file mode 100644 index 0000000..a8cb1e1 --- /dev/null +++ b/lib/doc/applies/domain_file @@ -0,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 --git a/lib/doc/applies/epilog b/lib/doc/applies/epilog new file mode 100644 index 0000000..db032af --- /dev/null +++ b/lib/doc/applies/epilog @@ -0,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 --git a/lib/doc/applies/error_handler b/lib/doc/applies/error_handler new file mode 100644 index 0000000..edf9936 --- /dev/null +++ b/lib/doc/applies/error_handler @@ -0,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 --git a/lib/doc/applies/flag b/lib/doc/applies/flag new file mode 100644 index 0000000..a711156 --- /dev/null +++ b/lib/doc/applies/flag @@ -0,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 --git a/lib/doc/applies/get_bb_uid b/lib/doc/applies/get_bb_uid new file mode 100644 index 0000000..d14498c --- /dev/null +++ b/lib/doc/applies/get_bb_uid @@ -0,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 --git a/lib/doc/applies/get_root_uid b/lib/doc/applies/get_root_uid new file mode 100644 index 0000000..b11e63d --- /dev/null +++ b/lib/doc/applies/get_root_uid @@ -0,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 --git a/lib/doc/applies/get_save_file_name b/lib/doc/applies/get_save_file_name new file mode 100644 index 0000000..b0a4f91 --- /dev/null +++ b/lib/doc/applies/get_save_file_name @@ -0,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 --git a/lib/doc/applies/heart_beat b/lib/doc/applies/heart_beat new file mode 100644 index 0000000..a61fad5 --- /dev/null +++ b/lib/doc/applies/heart_beat @@ -0,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 --git a/lib/doc/applies/id b/lib/doc/applies/id new file mode 100644 index 0000000..199755e --- /dev/null +++ b/lib/doc/applies/id @@ -0,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 --git a/lib/doc/applies/init b/lib/doc/applies/init new file mode 100644 index 0000000..bcdaf0e --- /dev/null +++ b/lib/doc/applies/init @@ -0,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 --git a/lib/doc/applies/interactive/catch_tell b/lib/doc/applies/interactive/catch_tell new file mode 100644 index 0000000..6aa0c2b --- /dev/null +++ b/lib/doc/applies/interactive/catch_tell @@ -0,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 --git a/lib/doc/applies/interactive/logon b/lib/doc/applies/interactive/logon new file mode 100644 index 0000000..38fd57a --- /dev/null +++ b/lib/doc/applies/interactive/logon @@ -0,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 --git a/lib/doc/applies/interactive/net_dead b/lib/doc/applies/interactive/net_dead new file mode 100644 index 0000000..c97eb97 --- /dev/null +++ b/lib/doc/applies/interactive/net_dead @@ -0,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 --git a/lib/doc/applies/interactive/process_input b/lib/doc/applies/interactive/process_input new file mode 100644 index 0000000..07c4173 --- /dev/null +++ b/lib/doc/applies/interactive/process_input @@ -0,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 --git a/lib/doc/applies/interactive/receive_message b/lib/doc/applies/interactive/receive_message new file mode 100644 index 0000000..c627318 --- /dev/null +++ b/lib/doc/applies/interactive/receive_message @@ -0,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 --git a/lib/doc/applies/interactive/receive_snoop b/lib/doc/applies/interactive/receive_snoop new file mode 100644 index 0000000..68b3a57 --- /dev/null +++ b/lib/doc/applies/interactive/receive_snoop @@ -0,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 --git a/lib/doc/applies/interactive/telnet_suboption b/lib/doc/applies/interactive/telnet_suboption new file mode 100644 index 0000000..937160d --- /dev/null +++ b/lib/doc/applies/interactive/telnet_suboption @@ -0,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 --git a/lib/doc/applies/interactive/terminal_type b/lib/doc/applies/interactive/terminal_type new file mode 100644 index 0000000..b213106 --- /dev/null +++ b/lib/doc/applies/interactive/terminal_type @@ -0,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 --git a/lib/doc/applies/interactive/window_size b/lib/doc/applies/interactive/window_size new file mode 100644 index 0000000..3870d16 --- /dev/null +++ b/lib/doc/applies/interactive/window_size @@ -0,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 --git a/lib/doc/applies/interactive/write_prompt b/lib/doc/applies/interactive/write_prompt new file mode 100644 index 0000000..4ba0b4a --- /dev/null +++ b/lib/doc/applies/interactive/write_prompt @@ -0,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 --git a/lib/doc/applies/log_error b/lib/doc/applies/log_error new file mode 100644 index 0000000..a229c3d --- /dev/null +++ b/lib/doc/applies/log_error @@ -0,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 --git a/lib/doc/applies/logon b/lib/doc/applies/logon new file mode 100644 index 0000000..38fd57a --- /dev/null +++ b/lib/doc/applies/logon @@ -0,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 --git a/lib/doc/applies/make_path_absolute b/lib/doc/applies/make_path_absolute new file mode 100644 index 0000000..50761e9 --- /dev/null +++ b/lib/doc/applies/make_path_absolute @@ -0,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 --git a/lib/doc/applies/master/author_file b/lib/doc/applies/master/author_file new file mode 100644 index 0000000..c006d71 --- /dev/null +++ b/lib/doc/applies/master/author_file @@ -0,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 --git a/lib/doc/applies/master/compile_object b/lib/doc/applies/master/compile_object new file mode 100644 index 0000000..200d76d --- /dev/null +++ b/lib/doc/applies/master/compile_object @@ -0,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 --git a/lib/doc/applies/master/connect b/lib/doc/applies/master/connect new file mode 100644 index 0000000..2442dd2 --- /dev/null +++ b/lib/doc/applies/master/connect @@ -0,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 --git a/lib/doc/applies/master/crash b/lib/doc/applies/master/crash new file mode 100644 index 0000000..b0254c0 --- /dev/null +++ b/lib/doc/applies/master/crash @@ -0,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 --git a/lib/doc/applies/master/creator_file b/lib/doc/applies/master/creator_file new file mode 100644 index 0000000..21d3b32 --- /dev/null +++ b/lib/doc/applies/master/creator_file @@ -0,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 --git a/lib/doc/applies/master/domain_file b/lib/doc/applies/master/domain_file new file mode 100644 index 0000000..a8cb1e1 --- /dev/null +++ b/lib/doc/applies/master/domain_file @@ -0,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 --git a/lib/doc/applies/master/epilog b/lib/doc/applies/master/epilog new file mode 100644 index 0000000..db032af --- /dev/null +++ b/lib/doc/applies/master/epilog @@ -0,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 --git a/lib/doc/applies/master/error_handler b/lib/doc/applies/master/error_handler new file mode 100644 index 0000000..edf9936 --- /dev/null +++ b/lib/doc/applies/master/error_handler @@ -0,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 --git a/lib/doc/applies/master/flag b/lib/doc/applies/master/flag new file mode 100644 index 0000000..a711156 --- /dev/null +++ b/lib/doc/applies/master/flag @@ -0,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 --git a/lib/doc/applies/master/get_bb_uid b/lib/doc/applies/master/get_bb_uid new file mode 100644 index 0000000..d14498c --- /dev/null +++ b/lib/doc/applies/master/get_bb_uid @@ -0,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 --git a/lib/doc/applies/master/get_root_uid b/lib/doc/applies/master/get_root_uid new file mode 100644 index 0000000..b11e63d --- /dev/null +++ b/lib/doc/applies/master/get_root_uid @@ -0,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 --git a/lib/doc/applies/master/get_save_file_name b/lib/doc/applies/master/get_save_file_name new file mode 100644 index 0000000..b0a4f91 --- /dev/null +++ b/lib/doc/applies/master/get_save_file_name @@ -0,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 --git a/lib/doc/applies/master/log_error b/lib/doc/applies/master/log_error new file mode 100644 index 0000000..a229c3d --- /dev/null +++ b/lib/doc/applies/master/log_error @@ -0,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 --git a/lib/doc/applies/master/make_path_absolute b/lib/doc/applies/master/make_path_absolute new file mode 100644 index 0000000..50761e9 --- /dev/null +++ b/lib/doc/applies/master/make_path_absolute @@ -0,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 --git a/lib/doc/applies/master/object_name b/lib/doc/applies/master/object_name new file mode 100644 index 0000000..989b2dd --- /dev/null +++ b/lib/doc/applies/master/object_name @@ -0,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 --git a/lib/doc/applies/master/parse_command_all_word b/lib/doc/applies/master/parse_command_all_word new file mode 100644 index 0000000..7c4c562 --- /dev/null +++ b/lib/doc/applies/master/parse_command_all_word @@ -0,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 --git a/lib/doc/applies/master/parse_command_prepos_list b/lib/doc/applies/master/parse_command_prepos_list new file mode 100644 index 0000000..edeaf4b --- /dev/null +++ b/lib/doc/applies/master/parse_command_prepos_list @@ -0,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 --git a/lib/doc/applies/master/preload b/lib/doc/applies/master/preload new file mode 100644 index 0000000..25783dc --- /dev/null +++ b/lib/doc/applies/master/preload @@ -0,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 --git a/lib/doc/applies/master/privs_file b/lib/doc/applies/master/privs_file new file mode 100644 index 0000000..9cf0459 --- /dev/null +++ b/lib/doc/applies/master/privs_file @@ -0,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 --git a/lib/doc/applies/master/retrieve_ed_setup b/lib/doc/applies/master/retrieve_ed_setup new file mode 100644 index 0000000..a289240 --- /dev/null +++ b/lib/doc/applies/master/retrieve_ed_setup @@ -0,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 --git a/lib/doc/applies/master/save_ed_setup b/lib/doc/applies/master/save_ed_setup new file mode 100644 index 0000000..b6dc197 --- /dev/null +++ b/lib/doc/applies/master/save_ed_setup @@ -0,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 --git a/lib/doc/applies/master/slow_shutdown b/lib/doc/applies/master/slow_shutdown new file mode 100644 index 0000000..b046b39 --- /dev/null +++ b/lib/doc/applies/master/slow_shutdown @@ -0,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 --git a/lib/doc/applies/master/valid_bind b/lib/doc/applies/master/valid_bind new file mode 100644 index 0000000..738536a --- /dev/null +++ b/lib/doc/applies/master/valid_bind @@ -0,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 --git a/lib/doc/applies/master/valid_compile_to_c b/lib/doc/applies/master/valid_compile_to_c new file mode 100644 index 0000000..fb4668e --- /dev/null +++ b/lib/doc/applies/master/valid_compile_to_c @@ -0,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 --git a/lib/doc/applies/master/valid_hide b/lib/doc/applies/master/valid_hide new file mode 100644 index 0000000..5a0dee1 --- /dev/null +++ b/lib/doc/applies/master/valid_hide @@ -0,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 --git a/lib/doc/applies/master/valid_link b/lib/doc/applies/master/valid_link new file mode 100644 index 0000000..8aee47e --- /dev/null +++ b/lib/doc/applies/master/valid_link @@ -0,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 --git a/lib/doc/applies/master/valid_object b/lib/doc/applies/master/valid_object new file mode 100644 index 0000000..15aef56 --- /dev/null +++ b/lib/doc/applies/master/valid_object @@ -0,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 --git a/lib/doc/applies/master/valid_override b/lib/doc/applies/master/valid_override new file mode 100644 index 0000000..0945a39 --- /dev/null +++ b/lib/doc/applies/master/valid_override @@ -0,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 --git a/lib/doc/applies/master/valid_read b/lib/doc/applies/master/valid_read new file mode 100644 index 0000000..8bd69a0 --- /dev/null +++ b/lib/doc/applies/master/valid_read @@ -0,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 --git a/lib/doc/applies/master/valid_save_binary b/lib/doc/applies/master/valid_save_binary new file mode 100644 index 0000000..c13d317 --- /dev/null +++ b/lib/doc/applies/master/valid_save_binary @@ -0,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 --git a/lib/doc/applies/master/valid_seteuid b/lib/doc/applies/master/valid_seteuid new file mode 100644 index 0000000..4a2f9ef --- /dev/null +++ b/lib/doc/applies/master/valid_seteuid @@ -0,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 --git a/lib/doc/applies/master/valid_shadow b/lib/doc/applies/master/valid_shadow new file mode 100644 index 0000000..1fae907 --- /dev/null +++ b/lib/doc/applies/master/valid_shadow @@ -0,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 --git a/lib/doc/applies/master/valid_socket b/lib/doc/applies/master/valid_socket new file mode 100644 index 0000000..4f10b6a --- /dev/null +++ b/lib/doc/applies/master/valid_socket @@ -0,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 --git a/lib/doc/applies/master/valid_write b/lib/doc/applies/master/valid_write new file mode 100644 index 0000000..6198abd --- /dev/null +++ b/lib/doc/applies/master/valid_write @@ -0,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 --git a/lib/doc/applies/move_or_destruct b/lib/doc/applies/move_or_destruct new file mode 100644 index 0000000..29038bd --- /dev/null +++ b/lib/doc/applies/move_or_destruct @@ -0,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 --git a/lib/doc/applies/net_dead b/lib/doc/applies/net_dead new file mode 100644 index 0000000..c97eb97 --- /dev/null +++ b/lib/doc/applies/net_dead @@ -0,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 --git a/lib/doc/applies/object_name b/lib/doc/applies/object_name new file mode 100644 index 0000000..989b2dd --- /dev/null +++ b/lib/doc/applies/object_name @@ -0,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 --git a/lib/doc/applies/parse_command b/lib/doc/applies/parse_command new file mode 100644 index 0000000..154a99d --- /dev/null +++ b/lib/doc/applies/parse_command @@ -0,0 +1,213 @@ + +parse_command(3) LPC Library Functions parse_command(3) + +NAME + parse_command() - try to match a string with a given pat- + tern + +SYNOPSIS + int parse_command( string command, object env|object *oblist, + string pattern, mixed arg, ... ); + +DESCRIPTION + 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. + +CAVEAT + 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. + +BUGS + 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 --git a/lib/doc/applies/parse_command_adjectiv_id_list b/lib/doc/applies/parse_command_adjectiv_id_list new file mode 100644 index 0000000..21ce2fa --- /dev/null +++ b/lib/doc/applies/parse_command_adjectiv_id_list @@ -0,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 --git a/lib/doc/applies/parse_command_all_word b/lib/doc/applies/parse_command_all_word new file mode 100644 index 0000000..7c4c562 --- /dev/null +++ b/lib/doc/applies/parse_command_all_word @@ -0,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 --git a/lib/doc/applies/parse_command_id_list b/lib/doc/applies/parse_command_id_list new file mode 100644 index 0000000..a9f803f --- /dev/null +++ b/lib/doc/applies/parse_command_id_list @@ -0,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 --git a/lib/doc/applies/parse_command_plural_id_list b/lib/doc/applies/parse_command_plural_id_list new file mode 100644 index 0000000..dd9d21d --- /dev/null +++ b/lib/doc/applies/parse_command_plural_id_list @@ -0,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 --git a/lib/doc/applies/parse_command_prepos_list b/lib/doc/applies/parse_command_prepos_list new file mode 100644 index 0000000..edeaf4b --- /dev/null +++ b/lib/doc/applies/parse_command_prepos_list @@ -0,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 --git a/lib/doc/applies/parsing/parse_command b/lib/doc/applies/parsing/parse_command new file mode 100644 index 0000000..154a99d --- /dev/null +++ b/lib/doc/applies/parsing/parse_command @@ -0,0 +1,213 @@ + +parse_command(3) LPC Library Functions parse_command(3) + +NAME + parse_command() - try to match a string with a given pat- + tern + +SYNOPSIS + int parse_command( string command, object env|object *oblist, + string pattern, mixed arg, ... ); + +DESCRIPTION + 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. + +CAVEAT + 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. + +BUGS + 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 --git a/lib/doc/applies/parsing/parse_command_adjectiv_id_list b/lib/doc/applies/parsing/parse_command_adjectiv_id_list new file mode 100644 index 0000000..21ce2fa --- /dev/null +++ b/lib/doc/applies/parsing/parse_command_adjectiv_id_list @@ -0,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 --git a/lib/doc/applies/parsing/parse_command_id_list b/lib/doc/applies/parsing/parse_command_id_list new file mode 100644 index 0000000..a9f803f --- /dev/null +++ b/lib/doc/applies/parsing/parse_command_id_list @@ -0,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 --git a/lib/doc/applies/parsing/parse_command_plural_id_list b/lib/doc/applies/parsing/parse_command_plural_id_list new file mode 100644 index 0000000..dd9d21d --- /dev/null +++ b/lib/doc/applies/parsing/parse_command_plural_id_list @@ -0,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 --git a/lib/doc/applies/preload b/lib/doc/applies/preload new file mode 100644 index 0000000..25783dc --- /dev/null +++ b/lib/doc/applies/preload @@ -0,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 --git a/lib/doc/applies/privs_file b/lib/doc/applies/privs_file new file mode 100644 index 0000000..9cf0459 --- /dev/null +++ b/lib/doc/applies/privs_file @@ -0,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 --git a/lib/doc/applies/process_input b/lib/doc/applies/process_input new file mode 100644 index 0000000..07c4173 --- /dev/null +++ b/lib/doc/applies/process_input @@ -0,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 --git a/lib/doc/applies/receive_message b/lib/doc/applies/receive_message new file mode 100644 index 0000000..c627318 --- /dev/null +++ b/lib/doc/applies/receive_message @@ -0,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 --git a/lib/doc/applies/receive_snoop b/lib/doc/applies/receive_snoop new file mode 100644 index 0000000..68b3a57 --- /dev/null +++ b/lib/doc/applies/receive_snoop @@ -0,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 --git a/lib/doc/applies/reset b/lib/doc/applies/reset new file mode 100644 index 0000000..3f811fc --- /dev/null +++ b/lib/doc/applies/reset @@ -0,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 --git a/lib/doc/applies/retrieve_ed_setup b/lib/doc/applies/retrieve_ed_setup new file mode 100644 index 0000000..a289240 --- /dev/null +++ b/lib/doc/applies/retrieve_ed_setup @@ -0,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 --git a/lib/doc/applies/save_ed_setup b/lib/doc/applies/save_ed_setup new file mode 100644 index 0000000..b6dc197 --- /dev/null +++ b/lib/doc/applies/save_ed_setup @@ -0,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 --git a/lib/doc/applies/slow_shutdown b/lib/doc/applies/slow_shutdown new file mode 100644 index 0000000..b046b39 --- /dev/null +++ b/lib/doc/applies/slow_shutdown @@ -0,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 --git a/lib/doc/applies/telnet_suboption b/lib/doc/applies/telnet_suboption new file mode 100644 index 0000000..937160d --- /dev/null +++ b/lib/doc/applies/telnet_suboption @@ -0,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 --git a/lib/doc/applies/terminal_type b/lib/doc/applies/terminal_type new file mode 100644 index 0000000..b213106 --- /dev/null +++ b/lib/doc/applies/terminal_type @@ -0,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 --git a/lib/doc/applies/valid_bind b/lib/doc/applies/valid_bind new file mode 100644 index 0000000..738536a --- /dev/null +++ b/lib/doc/applies/valid_bind @@ -0,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 --git a/lib/doc/applies/valid_compile_to_c b/lib/doc/applies/valid_compile_to_c new file mode 100644 index 0000000..fb4668e --- /dev/null +++ b/lib/doc/applies/valid_compile_to_c @@ -0,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 --git a/lib/doc/applies/valid_hide b/lib/doc/applies/valid_hide new file mode 100644 index 0000000..5a0dee1 --- /dev/null +++ b/lib/doc/applies/valid_hide @@ -0,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 --git a/lib/doc/applies/valid_link b/lib/doc/applies/valid_link new file mode 100644 index 0000000..8aee47e --- /dev/null +++ b/lib/doc/applies/valid_link @@ -0,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 --git a/lib/doc/applies/valid_object b/lib/doc/applies/valid_object new file mode 100644 index 0000000..15aef56 --- /dev/null +++ b/lib/doc/applies/valid_object @@ -0,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 --git a/lib/doc/applies/valid_override b/lib/doc/applies/valid_override new file mode 100644 index 0000000..0945a39 --- /dev/null +++ b/lib/doc/applies/valid_override @@ -0,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 --git a/lib/doc/applies/valid_read b/lib/doc/applies/valid_read new file mode 100644 index 0000000..8bd69a0 --- /dev/null +++ b/lib/doc/applies/valid_read @@ -0,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 --git a/lib/doc/applies/valid_save_binary b/lib/doc/applies/valid_save_binary new file mode 100644 index 0000000..c13d317 --- /dev/null +++ b/lib/doc/applies/valid_save_binary @@ -0,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 --git a/lib/doc/applies/valid_seteuid b/lib/doc/applies/valid_seteuid new file mode 100644 index 0000000..4a2f9ef --- /dev/null +++ b/lib/doc/applies/valid_seteuid @@ -0,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 --git a/lib/doc/applies/valid_shadow b/lib/doc/applies/valid_shadow new file mode 100644 index 0000000..1fae907 --- /dev/null +++ b/lib/doc/applies/valid_shadow @@ -0,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 --git a/lib/doc/applies/valid_socket b/lib/doc/applies/valid_socket new file mode 100644 index 0000000..4f10b6a --- /dev/null +++ b/lib/doc/applies/valid_socket @@ -0,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 --git a/lib/doc/applies/valid_write b/lib/doc/applies/valid_write new file mode 100644 index 0000000..6198abd --- /dev/null +++ b/lib/doc/applies/valid_write @@ -0,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 --git a/lib/doc/applies/window_size b/lib/doc/applies/window_size new file mode 100644 index 0000000..3870d16 --- /dev/null +++ b/lib/doc/applies/window_size @@ -0,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 --git a/lib/doc/applies/write_prompt b/lib/doc/applies/write_prompt new file mode 100644 index 0000000..4ba0b4a --- /dev/null +++ b/lib/doc/applies/write_prompt @@ -0,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 --git a/lib/doc/bguide/chapter01 b/lib/doc/bguide/chapter01 new file mode 100644 index 0000000..ffd375d --- /dev/null +++ b/lib/doc/bguide/chapter01 @@ -0,0 +1,102 @@ +chapter 1 "QCS and Builder Commands" + + "QCS" is the Dead Souls Quick Creation system, similar in function +to what other codebases refer to as OLC, or On-Line Creation. + + What with muds being text only, QCS has no fancy windowing system. +Using a menu-driven creation system was ruled out quickly due to the +vast complexity of the menus that would be required. Instead, QCS +relies on a few powerful commands. + +BUILDER COMMANDS +---------------- + +home +---- + This command magically teleports you to your workroom. + +arealist +-------- + This lets you see a list of the things you have created. To see +a list of NPC's (or mobs) you've created, type: arealist npc + Other valid categories are: room, object, weapon, armor + +areagoto +-------- + You can travel directly to rooms you've created. If one of +your rooms' file is, for example, ogre_room1, you can: areagoto ogre_room1 + +areaclone +--------- + This allows you to bring into existence a copy of a thing you've +created. For example, one of the weapons you've made has a file name of golden_sword, +you can make one appear by typing: areaclone golden_sword + +dest +---- + This destroys one of your created objects. If you're done playing +with a sword, for example, you can: dest sword + Note that this does not delete the file, it just destroys the cloned +copy. Also, it only works on items cloned from files in your area. You +aren't allowed to dest other people's stuff! + +reload +------ + This destroys the current object and reloads it with its current +code. For example, if your workroom is full of junk and you want to +reset it to its base status, type: reload here + And the room will reset to its default, with the junk gone. + + +QCS COMMANDS +------------ + +create +------ + This is the command that gets the ball rolling. This command +is what lets you bring a new thing into existence. The things you can +create can be seen by typing "help create". Examples are rooms, weapons, +doors, and so on. We will be reviewing each of those in later chapters. + When you issue this command a generic version of the item you +wish to create appears (or, in the case of a room, appears in the +direction you specify). Once that generic copy materializes, you can +change it to suit your needs using the "modify" command. + +modify +------ + I tend to regard this command as the heart and soul of QCS. It's +this tool that lets you make your world your own. Your new generic +things are not useful or fun until you modify them. A "generic weapon" +isn't very interesting, but a "mithrilite poleaxe" might be just the +thing to deal with a pesky dragon. + +add +--- + Creatures, rooms, and containers are capable of storing other +things. Once you make an ogre, you may want to give him a hammer to +wield. After you make that hammer, you use the add command to let +the ogre have that wepon in his permanent inventory. + +delete +------ + On the other hand, you may be tired of that ogre after a while. If +he is a part of the permanent inventory of a room, you can use the +delete command to remove him permanently. Or if you'd rather he have +a Kill-O-Zap Frogstar blaster rather than a hammer, get rid of the +hammer in his inventory with this command. + +copy +---- + This is a room-specific command. Rather than write multiple, +nearly identical rooms for large areas, you can use the copy command to +make the room you are almost exactly like any other room you choose, +except for the exits, which remain the same. Handy for big forests, +cell-blocks, twisty mazes of little passages, etc. + +initfix +------- + If a thing isn't working right, try to initfix it. "init()" is +an object function that many items need in order to work properly. If +you've run into something that is behaving unexpectedly, run initfix on +it. The trouble just might clear up. + diff --git a/lib/doc/bguide/chapter02 b/lib/doc/bguide/chapter02 new file mode 100644 index 0000000..fbd90ce --- /dev/null +++ b/lib/doc/bguide/chapter02 @@ -0,0 +1,93 @@ +chapter 33 "QCS: Creation" + + Creation breaks down into three categories. "Things", rooms, and +doors. Let's look at things first: + +Thing creation: +--------------- + In this category we're including NPC's, weapon, armor, unspecial items, +tables, furniture, books and containers. Basically things that actually show +up somewhere. A door is a very special sort of object and does not fall +under this category. + + To make a new thing, the syntax looks like this: + +create THING FILENAME + + The THING is the category of item we are creating. The FILENAME is +the name of the file that will contain this item's configuration data. +You may enter an absolute path, or you may simply enter a filename. If +you enter a filename, QCS will attempt to figure out the best place +for this file. If your current working directory has a name QCS understands +as being compatible with the type of object you are making (for example, +your cwd is /realms/you/npc and you are making an NPC) it will use that. +Otherwise it will search parent and children directories for a +directory name it understands this way. Finally, if it can find no +compatible directories for your file near your cwd, it will put it in +the appropriate directory in your home area (in this case, +/realms/you/area/npc ). + Avoid a relative path. It probably won't work the way you think. + + When the command completes, FILENAME will be a file containing the +data for your generic thing, and a copy of that generic thing will appear +in the room you are in. + If, for example, you entered: + +%^GREEN%^create npc cowboy%^RESET%^ + + The room you are in will contain a generic NPC which *does not* +answer to the id of "cowboy". This NPC is just a generic NPC whose +filename is (probably) /realms/you/npc/cowboy.c and isn't yet a real +cowboy. You'll need to use the "modify" command to make a proper +cowboy out of him. + + +Room creation +------------- + + Naturally, if you create a room, a new room will not appear inside +your current environment. Instead, the syntax of the "create" command +is different when you want to create a new room. + + You may have noticed that you can't use the "create" command to make +a new room adjacent to your workroom. This is for your protection and +my sanity. Files which contain the directive "SetNoModify(1)" are +immune to QCS manipulation. + Rooms like your workroom, the default start room, the void room, etc, +are set nomodify. This is because if you screw it up, you will be +sorry, and I just don't want to hear it. + So, suppose then that you're in your sample room (one room east +of your workroom) and you want to make a new room. You might issue +the following command: + +%^GREEN%^create room south testroom1%^RESET%^ + + What this does is copy the room you are in (in this case, +/realms/you/area/sample_room.c) to a new location (perhaps +/realms/you/area/testroom1.c). But the neat thing is, this new room +does not have the same exits as the room you are in. The new room +has just one exit, leading back to where you are. + The net effect of all this is that when you issue this command, +you make a new room in the direction you specify, and this +new room looks just like the room you're in, only the exits are such +that you can travel back and forth between the rooms. + + +Door creation +------------- + + Doors are funny things. In Dead Souls, they aren't objects in the +conventional sense of a thing which occupies a room you're in. Rather, +they are really daemons which attach to adjoining rooms. If that doesn't +make sense to you, don't worry. You're not alone. + + The syntax for door creation is much like that for room creation. +After you create that room south of your sample room, you can now create +a door between them: + +%^GREEN%^create door south sample_door%^RESET%^ + + This brings into existence a generic door (closed by default) which +is between the two rooms. + + diff --git a/lib/doc/bguide/chapter03 b/lib/doc/bguide/chapter03 new file mode 100644 index 0000000..80dd7ff --- /dev/null +++ b/lib/doc/bguide/chapter03 @@ -0,0 +1,328 @@ +chapter 34 "QCS: Modification of NPC's" + + In the previous chapter we learned how to make a generic object. +Now that we have it, what to do with it? + + It's important to keep in mind that the generic thing now in +front of you isn't just a clone from a template file. If the command +you used was "create npc cowboy", there is now a file (probably) +called /realms/you/area/npc/cowboy.c that contains the code for the +creature in front of you. + However, this poor beast has the most uninteresting of features. +It is in fact so boring that it responds only to its generic type. +Such that "examine cowboy" or "kill tex" won't work. You'll need to +"look at npc". + + Accordingly, any modification commands need to be made referring +to the new thing with an it responds to, until such a time as you +change the id to suit your tastes. Let's carry on with the example +of our generic npc. To make a cowboy out of him, we can either +change his name, or his id, or both. Let's start with his name: + +%^GREEN%^modify npc name cowboy%^RESET%^ + + This makes the SetKeyName() directive in cowboy.c use "cowboy" +as its argument, effectively allowing you to address this npc as "cowboy" +from now on. Now you can "look at cowboy" with some results. + Obviously our NPC isn't *just* a cowboy. He's also a human, a dude, +and his name is Tex. How do we make him respond to all of these nouns? + +%^GREEN%^modify cowboy id%^RESET%^ + + You'll notice there are no arguments following the word "id". Setting +a thing's id is different from most other settings. If you'll think back +to the LPC datatypes chapter of this manual (you did read the LPC +chapters, didn't you?) you'll remember that some information about +objects is in the form of strings ("cowboy"), some is in the form of +integers (the cowboy's health points, for example) and some is in the +form of arrays, which are a group of data points. In this example we +want the cowboy's id to be an array, because of the many ways we might +want to address him. Therefore, we want the SetId directive in his +file to look like this: + +SetId( ({"human", "dude", "tex" }) ); + + You might think that QCS should be able to accept multiple values +like this on a line, perhaps with "modify cowboy id human dude tex" as +the command. + But what if you want this npc to be a "Boy Named Sue"? How would +you accommodate id's that contain spaces? In designing QCS, I considered +having escape characters to allow for such things, but ultimately +reasoned that this was just way too much mess. Instead, SetId, and +other directives that take arrays as arguments, are handled by entering +a query session. Below is an example of what it might look like. The +example is necessarily messy because I am including both the queries +and the responses. + +--------------------------------------------------- +> %^GREEN%^modify npc name cowboy%^RESET%^ +Indenting file... +"/tmp/indent.1136206130.tmp.dat" 15 lines 420 bytes +Exit from ed. + +> %^GREEN%^modify cowboy 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%^human%^RESET%^ +You may now enter the next value. So far, we have: ({ "dude", "human" }) +If you're done entering values, enter a dot on a blank line. +%^GREEN%^tex%^RESET%^ +You may now enter the next value. So far, we have: ({ "dude", "human", "tex" }) +If you're done entering values, enter a dot on a blank line. +%^GREEN%^boy named sue%^RESET%^ +You may now enter the next value. So far, we have: ({ "dude", "human", "tex", +"boy named sue" }) +If you're done entering values, enter a dot on a blank line. +%^GREEN%^.%^RESET%^ +Entries complete. Final array is: ({ "dude", "human", "tex", "boy named sue" }) +Indenting file... +"/tmp/indent.1136206156.tmp.dat" 19 lines 459 bytes +Exit from ed. + +/open/1136206138: Ok +/realms/cratylus/area/npc/cowboy: Ok +SetId modification complete. +> %^GREEN%^exa tex%^RESET%^ +Other than being human, this npc is entirely unremarkable. +The male human is in top condition. +--------------------------------------------------- + + If you were now to examine Tex's code (with the command "about tex") +you'd see that his SetId directive now looks like this: + +SetId( ({"dude", "human", "tex", "boy named sue"}) ); + + Other NPC features take arrays also. SetAdjectives is one. You +might enter this (mud output omitted for clarity): + +%^GREEN%^modify tex adjectives%^RESET%^ +%^GREEN%^dusty%^RESET%^ +%^GREEN%^hardy%^RESET%^ +%^GREEN%^.%^RESET%^ +%^GREEN%^look at dusty cowboy%^RESET%^ + + There are two other directives that require queries. Things and +NPC's can be looked at, but they can also be smelled and listened +to, if you add SetSmell and SetListen. The syntax is: + +%^GREEN%^modify tex smell%^RESET%^ + + And you will then be asked a question about keys and mappings. +Understanding mappings is important, but for now you just need to +understand that you are being asked *two* separate questions: +1) What on the cowboy is being smelled/listened to? +2) What is the smell/sound? + + What this means is that your input will look something like +this: + +%^GREEN%^modify tex smell%^RESET%^ +%^GREEN%^default%^RESET%^ +%^GREEN%^.%^RESET%^ +Tex smells of sweat and manure. + + What happens is this: +- You enter the modify command. +- You enter the word "default" to indicate this is Tex's general smell. +- You enter a dot to indicate that you are done specifying what + part of Tex is being smelled. +- You then specify the smell. + + This may seem odd until you realize you can also add smells/listens to +parts of things. Not on NPC's, though. We'll look at this more closely in +later chapters. For now, just use the syntax as shown above. For adding +a listen to the cowboy, it works the same way: + +%^GREEN%^modify tex listen%^RESET%^ +%^GREEN%^default%^RESET%^ +%^GREEN%^.%^RESET%^ +Tex seems to be humming a jaunty melody. + + Other features of an NPC do not take arrays, so one-line commands +will do. For example: + +%^GREEN%^modify cowboy long This is a cowboy who calls himself Tex, but is in fact a Boy Named Sue.%^RESET%^ + +%^GREEN%^modify cowboy short a cowboy%^RESET%^ + +%^GREEN%^modify cowboy level 5%^RESET%^ + +%^GREEN%^modify cowboy class fighter%^RESET%^ + +%^GREEN%^modify tex currency gold 1%^RESET%^ + +%^GREEN%^modify tex currency silver 12%^RESET%^ + +%^GREEN%^modify tex skill bargaining 5%^RESET%^ + +%^GREEN%^modify tex skill projectile attack 7%^RESET%^ + +%^GREEN%^modify tex stat strength 33%^RESET%^ + +%^GREEN%^modify tex property nice guy 1%^RESET%^ + +%^GREEN%^modify tex healthpoints 150%^RESET%^ + +%^GREEN%^modify tex maxhealthpoints 170%^RESET%^ + +%^GREEN%^modify tex melee 0%^RESET%^ + +%^GREEN%^modify tex unique 1%^RESET%^ + + If you now issue the "about tex" command you will see that all +the changes you made have been put into the file. + + You may have noticed the "melee" keyword. Dead Souls 2 NPC's come +in various shapes and sizes, and some of them shouldn't wield weapons. A +wolf with a battle axe would be a strange sight indeed. However, the +default combat system makes unarmed creatures extremely vulnerable in +combat. + To make an NPC combat-capable without weapons, use the new SetMelee +directive. SetMelee(1) makes the NPC capable of proper unarmed combat. +SetMelee(0) makes the NPC a weak opponent if unarmed. + NPC's will generally try to bite during unarmed combat. If this +is beneath the capability or dignity of your NPC, you can prevent +this with: + +%^GREEN%^modify tex canbite 0%^RESET%^ + + If your NPC should try to escape when the battle isn't going +his way, the wimpy settings should do: + +%^GREEN%^modify tex wimpy 30%^RESET%^ + +%^GREEN%^modify tex wimpycommand climb ladder%^RESET%^ + + If you don't specify a wimpy command, Tex will leave the +room through a random exit. In this case, when Tex's health +is down to 30% and he is in combat, he will try to climb a ladder. + + Some NPC's are designed to travel about. To enable this +feature, use the wanderspeed directive: + +%^GREEN%^modify tex wanderspeed 5%^RESET%^ + + If you want him to travel more quickly, use a +lower number. By default, wandering NPC's only wander in rooms +that have already been loaded into memory. They avoid loading +rooms because loading a bunch of rooms that only the NPC +will ever see is a waste of your mud's resources. + However, if you *do* want your NPC to wander in an +unrestricted manner, regardless of whether a room is loaded, +use the permitload directive: + +%^GREEN%^modify tex permitload 1%^RESET%^ + + By default, NPC's stand up when they can. This is +so that if they collapse during combat, they try to +get back up once they are able to do so. + If you prefer that your NPC maintain some other +posture, you can set that posture, then disable +autostanding like this: + +%^GREEN%^modify tex posture lying%^RESET%^ + +%^GREEN%^modify tex autostand 0%^RESET%^ + + If he's especially lazy, you can have him take +a nap this way: + +%^GREEN%^modify tex sleeping 10%^RESET%^ + + Which will have him wake up after about a minute. +However, note that if you've disabled autostanding, +he will remain lying down after he wakes up. + + If the NPC should be hostile, that is, he should +attack any creatures that it sees enter a room, +SetEncounter should do it: + +%^GREEN%^modify tex encounter 100%^RESET%^ + + This means that if the creature it sees has a +charisma score of less than 100 (which should pretty +much be always true), Tex will try to kill it. You +can do some fancy stuff with SetEncounter, such +as only attacking orcs, or actually doing something +friendly, but to do so you can't use QCS. Read +the NPC and Sentients chapter in the Creator's +Manual for details on how to code such stuff. + + If the NPC is a golem or other such non-biological +creature, it may be useful to specify what they are +made of. The SetComposition setting for a clay +golem might look like this: + +%^GREEN%^modify golem composition clay%^RESET%^ + + If it happens to be a golem that does not believe +in violence as a solution to problems, you can +make refuse to hurt others with the following: + +%^GREEN%^modify golem pacifist 1%^RESET%^ + + +Vendors: +------- + +Vendors are a special kind of NPC that can sell stuff. +Along with the standard NPC settings, vendors have +the following: + +SetStorageRoom specifies where the vendor's stock +is stored. If a valid room is specified, anything +in that room can be sold by the vendor. + +SetLocalCurrency specifies the type of currency, +such as gold or silver, that the vendor accepts. + +SetMaxItems is the maximum number of items in +the storeroom that the vendor is permitted to sell. + +SetVendorType specifies the kind of stuff the vendor can +trade in. "all" allows him to buy and sell whatever. +But if he is a weapon vendor, he can't trade in armor, +etc. See /include/vendor_types.h for the available +vendor types. To have a "multi-type" vendor, you'll have to +code it by hand. The result of that looks something +like this: + +SetVendorType( VT_TREASURE | VT_ARMOR | VT_HERBS ); + + +Barkeeps: +-------- + + Like vendors, barkeeps sell stuff, but they are +limited to selling food and drink. + + Unlike vendors, barkeeps have no limitation on +the amount of stuff they can sell. They also do +not have a storeroom. The stuff they can sell is +specified in their SetMenu directive, like this: + +%^GREEN%^clone woody%^RESET%^ +You clone a generic barkeep (/realms/temujin/area/npc/woody.c). +%^GREEN%^modify woody menu%^RESET%^ +If you don't understand these questions, type the letter q on a blank line and hit enter. + +Please enter the first key element for this mapping: + +%^GREEN%^bourbon%^RESET%^ +Please enter the next key element, or enter a single dot to finish entering key elements. +%^GREEN%^whiskey%^RESET%^ +Please enter the next key element, or enter a single dot to finish entering key elements. +%^GREEN%^.%^RESET%^ +Please enter the value for key ({ "bourbon", "whiskey" }): + +%^GREEN%^/domains/town/meals/bourbon%^RESET%^ + + Barkeeps also have the SetLocalCurrency directive +to specify the currency they accept. + + diff --git a/lib/doc/bguide/chapter04 b/lib/doc/bguide/chapter04 new file mode 100644 index 0000000..35bf70b --- /dev/null +++ b/lib/doc/bguide/chapter04 @@ -0,0 +1,224 @@ +chapter 35 "QCS: Modifying rooms" + + Suppose you are in your sample room and you issued the +command: + +%^GREEN%^create room south testroom1%^RESET%^ + + You then travel south and see that you are in a room that is +almost exactly like the sample room except for the exits. Well, +probably you don't want to have a mud with nothing but identical +rooms, so let's modify it: + +%^GREEN%^modify here short Test Room One%^RESET%^ + +%^GREEN%^modify here long This is the first test room. The walls are rather blank.%^RESET%^ + +%^GREEN%^modify here climate indoors%^RESET%^ + +%^GREEN%^modify here light 30%^RESET%^ + + + Ok, so far so good. Standard interior. However, a good mud has +rooms with details. Let's add some detail to this room. + I've omitted the system output for clarity. This is just what you +would input. + + +%^GREEN%^modify here item%^RESET%^ + +%^GREEN%^wall%^RESET%^ + +%^GREEN%^walls%^RESET%^ + +%^GREEN%^blank wall%^RESET%^ + +%^GREEN%^blank walls%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^These are just blank walls.%^RESET%^ + + + Let's review what we've done here: +1) You issued the modify command specifying your current room as the + target, and the SetItems directive as the argument. +2) You entered a query session, and were asked to enter each element + of the item's key. +3) You entered a single dot to indicate you were done entering + key elements. +4) You entered the value for the key, which is the description of the + item. + + The result of all this is that now you can issue these commands: + +%^GREEN%^exa wall%^RESET%^ +%^GREEN%^look at blank walls%^RESET%^ +%^GREEN%^examine walls%^RESET%^ + + And the output will be: + +These are just blank walls. + + Let's add a floor while we're at it: + +%^GREEN%^modify here item%^RESET%^ + +%^GREEN%^floor%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^A floor like any other.%^RESET%^ + + In this case, you didn't feel like adding extra synonyms for "floor", +so you entered the final dot rather than entering another key element. +Then you added the description, and now if you "exa floor", you'll get +that description. + "about here" will display to you the file you have modified. + + Well, that's enough fun with indoor rooms. There's not much more +to them. Let's go outdoors now: + +%^GREEN%^create room south exterior_room%^RESET%^ + +%^GREEN%^create door south test_door%^RESET%^ + +%^GREEN%^open door%^RESET%^ + +%^GREEN%^go south%^RESET%^ + +%^GREEN%^modify here short a small lawn%^RESET%^ + +%^GREEN%^modify here daylong A small, well groomed lawn on a lovely sunny day. There is a small building north of here.%^RESET%^ + +%^GREEN%^modify here nightlong This is a small lawn. Stars twinkle in the night sky above, and some light is coming from a small building to the north.%^RESET%^ + +%^GREEN%^modify here daylight 30%^RESET%^ + +%^GREEN%^modify here nightlight 20%^RESET%^ + +%^GREEN%^modify here light delete%^RESET%^ + +%^GREEN%^modify here long delete%^RESET%^ + +%^GREEN%^modify here items delete%^RESET%^ + +%^GREEN%^modify here items%^RESET%^ + +%^GREEN%^building%^RESET%^ + +%^GREEN%^small building%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^A small building, rather ramshackle as if hastily put together.%^RESET%^ + +%^GREEN%^modify here climate temperate%^RESET%^ + + Ok! A few new things here. A neat thing about outdoor rooms is that +typically they are subject to the time of day. A SetClimate directive +that indicates an exterior environment causes the room to receive +messages about the sun setting, rising, etc. + The SetDayLong and SetNightLong directives allow you to more +sensibly describe the area depending on the time of day. To avoid +confusion, I deleted the SetLong directive. It is not mandatory to +have different day and night descriptions, but players appreciate the +effort. + It is also possible to have differing ambient light levels depending +on the time of day, so we've added SetDayLight and SetNightLight, and +we deleted the SetAmbientLight directive. + + Let's continue to add detail: + +%^GREEN%^modify here item%^RESET%^ + +%^GREEN%^lawn%^RESET%^ + +%^GREEN%^grass%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^Healthy, well groomed and freshly cut grass.%^RESET%^ + +%^GREEN%^modify here smell%^RESET%^ + +%^GREEN%^default%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^You can smell the refreshing scent of freshly cut grass.%^RESET%^ + +%^GREEN%^modify here smell%^RESET%^ + +%^GREEN%^lawn%^RESET%^ + +%^GREEN%^grass%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^Yep, it's got that new lawn smell.%^RESET%^ + +%^GREEN%^modify here listen%^RESET%^ + +%^GREEN%^building%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^Sounds like someone's fumbling about in there, making a mess. New creators can be so noisy.%^RESET%^ + +%^GREEN%^modify here item%^RESET%^ + +%^GREEN%^garden%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^You may enter the garden from here.%^RESET%^ + +%^GREEN%^create room garden garden_room%^RESET%^ + + + + You now have a room with lots of charm and detail. You can "smell grass" +and "listen to small building", if you like. Neat, huh? But there's something +very important to keep in mind: + + Enters, listens and smells don't work properly if there is no item defined +for that smell. For example, if you want to be able to listen to the sea, +you must "modify here item" and add a "sea" item. Otherwise, "listen +to the sea" will respond with "There is no sea here." + The only exception to this rule is the "default" smell. + + Enters behave similarly. If you want to be able to "enter" something, +you'll need to create the corresponding item first, as in the example above. + + You can use the SetProperties directive to make the room +conform to some presets, like: + +%^GREEN%^modify here property no attack 1%^RESET%^ + + Read chapter 23 in the Creator's Manual for details on room properties. + + Also, please note that indoor rooms can also have differing +descriptions and light levels for night and day. It's just that +indoor rooms don't get notification of daytime changes. + + Finally, the SetTown directive allows the room to participate in +area-wide events, and is useful for security purposes as well: + +%^GREEN%^modify here town MyTown%^RESET%^ + + +Notes on room filenames: +----------------------- +By default, a filename without a leading path creates a room +in your area room directory, which in my case would be +"/realms/cratylus/area/room". However, you can specify a different +location for the new room. + +To create a room in your current working directory: +%^GREEN%^create room east ./newroom%^RESET%^ + +To create a room in a specific directory: +%^GREEN%^create room east /realms/cratylus/testrooms/newroom%^RESET%^ + + diff --git a/lib/doc/bguide/chapter05 b/lib/doc/bguide/chapter05 new file mode 100644 index 0000000..4d7239e --- /dev/null +++ b/lib/doc/bguide/chapter05 @@ -0,0 +1,67 @@ +chapter 36 "QCS: Modifying weapons" + + Remember that the QCS chapters are supposed to be read in +sequence. This is important because as we progress, I will not make +explanations about directives and concepts explained previously. + + Weapons are different from rooms and NPC's in that they can +be handled, sold, thrown, etc. They are manipulable objects. As such, +we will see new directives: + +%^GREEN%^create weapon hammer%^RESET%^ + + You may be familiar with this example from the example webpage. +Let's go ahead and plow through the commands: + +%^GREEN%^modify weapon id hammer%^RESET%^ + +%^GREEN%^warhammer%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^modify hammer name hammer%^RESET%^ + +%^GREEN%^modify hammer damagetype blunt%^RESET%^ + +%^GREEN%^modify hammer weapontype blunt%^RESET%^ + +%^GREEN%^modify hammer mass 700%^RESET%^ + +%^GREEN%^modify hammer hands 2%^RESET%^ + +%^GREEN%^modify hammer short a heavy war hammer%^RESET%^ + +%^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%^ + +%^GREEN%^modify hammer adj%^RESET%^ + +%^GREEN%^large%^RESET%^ + +%^GREEN%^heavy%^RESET%^ + +%^GREEN%^war%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^modify hammer basecost silver 750%^RESET%^ + +%^GREEN%^about hammer%^RESET%^ + + + Like a room and unlike an NPC, you can also modify the SetItems on +manipulable objects like weapons, so you could do something like this: + +%^GREEN%^modify hammer item%^RESET%^ + +%^GREEN%^shaft%^RESET%^ + +%^GREEN%^handle%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^A thick, reinforced steel shaft with leather bands for a strong grip.%^RESET%^ + +%^GREEN%^exa shaft on hammer%^RESET%^ + + + diff --git a/lib/doc/bguide/chapter06 b/lib/doc/bguide/chapter06 new file mode 100644 index 0000000..d721a6d --- /dev/null +++ b/lib/doc/bguide/chapter06 @@ -0,0 +1,130 @@ +chapter 37 "QCS: Modifying things and stuff" + + You should have a firm grasp now on how QCS works +in relation to manipulable objects. Let's look at the +settings for a few special kinds of items: + +chairs +------ + +%^GREEN%^modify stool maxsitters 1%^RESET%^ + +%^GREEN%^modify stool setmaxcarry 200%^RESET%^ + + +beds +---- + +%^GREEN%^modify sofa maxsitters 2%^RESET%^ + +%^GREEN%^modify sofa maxliers 1%^RESET%^ + +%^GREEN%^modify sofa maxcarry 400%^RESET%^ + + +containers +---------- + +%^GREEN%^modify box canclose 1%^RESET%^ + +%^GREEN%^modify box closed 1%^RESET%^ + +%^GREEN%^modify box locked 1%^RESET%^ + +%^GREEN%^modify box key magic_skeleton_key%^RESET%^ + +%^GREEN%^modify box maxcarry 200%^RESET%^ + +%^GREEN%^modify box setmoney gold 15%^RESET%^ + + +tables +------ + +%^GREEN%^modify altar maxcarry 300%^RESET%^ + +%^GREEN%^modify altar maxliers 1%^RESET%^ + + +meals/drinks +------------ + +%^GREEN%^modify burger mealtype food%^RESET%^ + +%^GREEN%^modify schlitz mealtype alcohol%^RESET%^ + +%^GREEN%^modify apple mealstrength 10%^RESET%^ + + +books +----- + +%^GREEN%^modify journal title The Orc Within%^RESET%^ + +%^GREEN%^modify journal source /domains/Orcland/etc/books/journal%^RESET%^ + + +Readable things: +---------------- + +If you want to be able to "read thing", for example, "read sign": + +%^GREEN%^modify sign defaultread This is a message written on the sign.%^RESET%^ + +If you want to make a thing on a thing readable, as in +"read inscription on ring": + +%^GREEN%^modify ring item%^RESET%^ + +%^GREEN%^inscription%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^This is an inscription on the ring. Try 'read inscription on ring'%^RESET%^ + +%^GREEN%^modify ring read%^RESET%^ + +%^GREEN%^inscription%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^So! We, the spear-Danes%^RESET%^ + +By default, readabale items are readable by anyone, regardless +of the languages they know. If, however, your item should +only be readable by someone who understands the elvish tongue: + +%^GREEN%^modify ring language edhellen%^RESET%^ + + +Miscellaneous: +-------------- + +To make a key have a 50% chance of breaking when it's used: + +%^GREEN%^modify golden key disablechance 50%^RESET%^ + + +To make a room or object immune to resets: + +%^GREEN%^modify sentry noclean 1%^RESET%^ + + +To make sure there is only one instance of an object or +NPC loaded at any given time: + +%^GREEN%^modify tiamat unique 1%^RESET%^ + + +To make a thing or room immune to the QCS (except for this +command): + +%^GREEN%^modify workroom nomodify 1%^RESET%^ + + +To specify what kind of vendor should be allowed to traffic +in this item: + +%^GREEN%^modify necklace vendortype treasure%^RESET%^ + + diff --git a/lib/doc/bguide/chapter07 b/lib/doc/bguide/chapter07 new file mode 100644 index 0000000..916d680 --- /dev/null +++ b/lib/doc/bguide/chapter07 @@ -0,0 +1,70 @@ +chapter 38 "QCS: Adding and deleting" + + Rooms, containers and NPC's all are capable of holding +items, and often it is convenient to have them already holding certain +items upon creation. + The SetInventory directive in an object's file provides us with +a list of that object's "permanent inventory". To modify an object's +inventory, we use the add and delete commands. + + Let's say that we want our cowboy to be wielding a +hammer when he appears... + +%^GREEN%^clone cowboy%^RESET%^ + +%^GREEN%^cd ../weap%^RESET%^ + +%^GREEN%^clone hammer%^RESET%^ + +%^GREEN%^add hammer to cowboy%^RESET%^ + +%^GREEN%^wield hammer%^RESET%^ + + Believe it or not, it's that simple. The add command will ask +you a question after you issue it. What it wants to know is if you +want the NPC to do anything special when the hammer appears on him. +In this case, yes, we wanted him to wield it. + However, if you want to add something to an NPC and don't +have anything interesting for him to do with it, respond to the +question with the number of items that you want to appear. For +example, if I want the cowboy to be carrying a key: + +%^GREEN%^cd ../obj%^RESET%^ + +%^GREEN%^clone key%^RESET%^ + +%^GREEN%^add key to cowboy%^RESET%^ + +%^GREEN%^1%^RESET%^ + + And that's it. Now if I want the cowboy to be a permanent +resident of this room: + +%^GREEN%^add cowboy%^RESET%^ + +%^GREEN%^1%^RESET%^ + + The add command understands that if you don't specify a +target argument, you must mean the room. You can also be specific: + +%^GREEN%^add cowboy to room%^RESET%^ + +%^GREEN%^1%^RESET%^ + + The delete command works the opposite way. It removes items from +an object's permanent inventory: + +%^GREEN%^delete hammer from cowboy%^RESET%^ + +%^GREEN%^delete cowboy%^RESET%^ + + The delete command is also the way to get rid of rooms. You won't +be removing the file from disk, you'll just be deleting that exit +from the room: + +%^GREEN%^delete exit garden%^RESET%^ + +NOTE: When you delete an exit, only the connection from your room to +the other room is removed. The connection from the other room to +your room remains. This is not a bug, it's a feature. There are plenty +of circumstances where one-way travel is desirable. diff --git a/lib/doc/bguide/chapter08 b/lib/doc/bguide/chapter08 new file mode 100644 index 0000000..af86f70 --- /dev/null +++ b/lib/doc/bguide/chapter08 @@ -0,0 +1,90 @@ +chapter 39 "QCS: Final notes" + +* Remember that QCS commands work on objects, not files. To +load a file into memory, use the update command. To reload an +already existing object, like a cloned orc or a book, use +the reload command. To use modify, delete, and add, you have +to specify a cloned object that is on you or in your environment. + + I think you're getting the idea of how this works. Here's +an example of armor creation: + +%^GREEN%^create armor jeans%^RESET%^ + +%^GREEN%^modify jeans id%^RESET%^ + +%^GREEN%^pants%^RESET%^ + +%^GREEN%^trousers%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^modify jeans short a pair of denim jeans%^RESET%^ + +%^GREEN%^modify jeans long Worn jeans, frayed and stained.%^RESET%^ + +%^GREEN%^modify jeans adj%^RESET%^ + +%^GREEN%^pair of%^RESET%^ + +%^GREEN%^denim%^RESET%^ + +%^GREEN%^frayed%^RESET%^ + +%^GREEN%^worn%^RESET%^ + +%^GREEN%^stained%^RESET%^ + +%^GREEN%^.%^RESET%^ + + + To know what directives QCS can change on an object, type: + +%^GREEN%^help modify%^RESET%^ + + This provides a list of modifiable things and the directives +that can be modified on them. + + Ultimately the Quick Creation System generates LPC code, so +you'll want to review the earlier chapters of this handbook to +get a base of understanding of the code that comprises your new +creations. + +Some notes and tips: + +* The SetNoCondition directive makes it so an item does not report + its physical status when examined. Weapons and armor wear down in + combat, and most objects let you know their condition when you + examine them. However, in some cases (a sandwich for example) + this is inappropriate, so the SetNoCondition directive may be + useful. + +* Doors aren't like normal objects. They have to be modified *twice*. + Once for each side of the door. If this sounds unnecessarily + tedious, remember that a door leading south is also a door + leading north from the other room. + +* Doors generally are not visible in the same way that regular + objects are. To make a door especially obvious and noticeable, + do something like: +%^GREEN%^modify door sethiddendoor 0%^RESET%^ + +* SetCurrency is for adding money to NPC's. SetMoney is for adding + money to non-living containers (bags, etc). + +* Item subtypes are listed in /include. To know what kinds of vendors + are available, for example, look in /include/vendor_types.h + +* Books need a "source directory", which must contain one file per + chapter. The SetSource for this manual, for example, is /doc/manual + The first line of each file must follow the same format as + the files you see in /doc/manual + +* SetObviousExits is usually no longer needed: rooms report + obvious exits automatically. However, if you don't want an exit + to show up by default, use the SetObviousExits directive + to specify only those that you want seen. This will override the + room's default exit display. + + + diff --git a/lib/doc/build/Armours b/lib/doc/build/Armours new file mode 100644 index 0000000..9b42059 --- /dev/null +++ b/lib/doc/build/Armours @@ -0,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 --git a/lib/doc/build/Barkeeps b/lib/doc/build/Barkeeps new file mode 100644 index 0000000..4f13df4 --- /dev/null +++ b/lib/doc/build/Barkeeps @@ -0,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 --git a/lib/doc/build/Climates b/lib/doc/build/Climates new file mode 100644 index 0000000..89ca4d0 --- /dev/null +++ b/lib/doc/build/Climates @@ -0,0 +1,6 @@ +indoors +temperate +arid +arctic +tropical +sub-tropical diff --git a/lib/doc/build/Doors b/lib/doc/build/Doors new file mode 100644 index 0000000..2c44fc9 --- /dev/null +++ b/lib/doc/build/Doors @@ -0,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 --git a/lib/doc/build/Guidelines b/lib/doc/build/Guidelines new file mode 100644 index 0000000..3553f70 --- /dev/null +++ b/lib/doc/build/Guidelines @@ -0,0 +1,11 @@ +Please refer to these URL's for guidelines about how to build. + +http://www.mudconnect.com/articles/stylistics.1.html + +http://www.mudconnect.com/articles/stylistics.2.html + +Deviation from those guidelines is entirely acceptable, as +long as there is good reason for it. Naturally, what +constitutes "good reason" depends on your admin. + + diff --git a/lib/doc/build/Introduction b/lib/doc/build/Introduction new file mode 100644 index 0000000..0af2cba --- /dev/null +++ b/lib/doc/build/Introduction @@ -0,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 --git a/lib/doc/build/Items b/lib/doc/build/Items new file mode 100644 index 0000000..9fe715b --- /dev/null +++ b/lib/doc/build/Items @@ -0,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 --git a/lib/doc/build/Meals b/lib/doc/build/Meals new file mode 100644 index 0000000..eff9fd6 --- /dev/null +++ b/lib/doc/build/Meals @@ -0,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 --git a/lib/doc/build/NPC b/lib/doc/build/NPC new file mode 100644 index 0000000..0b9ebb7 --- /dev/null +++ b/lib/doc/build/NPC @@ -0,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 --git a/lib/doc/build/Properties b/lib/doc/build/Properties new file mode 100644 index 0000000..b268782 --- /dev/null +++ b/lib/doc/build/Properties @@ -0,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 --git a/lib/doc/build/Quests b/lib/doc/build/Quests new file mode 100644 index 0000000..f662838 --- /dev/null +++ b/lib/doc/build/Quests @@ -0,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 --git a/lib/doc/build/Rooms b/lib/doc/build/Rooms new file mode 100644 index 0000000..804cf92 --- /dev/null +++ b/lib/doc/build/Rooms @@ -0,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 --git a/lib/doc/build/Sentients b/lib/doc/build/Sentients new file mode 100644 index 0000000..5bfc694 --- /dev/null +++ b/lib/doc/build/Sentients @@ -0,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 --git a/lib/doc/build/Towns b/lib/doc/build/Towns new file mode 100644 index 0000000..751ac08 --- /dev/null +++ b/lib/doc/build/Towns @@ -0,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 --git a/lib/doc/build/Vendors b/lib/doc/build/Vendors new file mode 100644 index 0000000..347fa05 --- /dev/null +++ b/lib/doc/build/Vendors @@ -0,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 --git a/lib/doc/build/Weapons b/lib/doc/build/Weapons new file mode 100644 index 0000000..18a4e97 --- /dev/null +++ b/lib/doc/build/Weapons @@ -0,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 --git a/lib/doc/build/ed.hup b/lib/doc/build/ed.hup new file mode 100644 index 0000000..e69de29 diff --git a/lib/doc/cheats/chapter01 b/lib/doc/cheats/chapter01 new file mode 100644 index 0000000..b416118 --- /dev/null +++ b/lib/doc/cheats/chapter01 @@ -0,0 +1,118 @@ +chapter 1 "Basics" + +The first thing to do is to pick a decent character. The best +all-around choice for a beginner is a human mage, so for the +purposes of these cheat sheets, pick human when you create your character. + +Once your character is created, begin the game by typing: enter town + +You should now be in the main village of the game, where you can find +shops, pubs, a bank, and most everything you'll need. Get familiar here +with the basic commands: + +look +look at tower +go north +go south +smile + +You can also type them in a shortened way: + +l +l tower +n +s +smile + + +Now, learn a little about yourself. Type: + +score +stat + +(Note that you will have to hit <enter> to get to the second page of the +stat command.) + +These commands tell you some things about yourself, like how much food you've +eaten, what skills you have and how good you are at them, and other +attributes, like how strong you are how smart you are, etc. + + +In the game you will need to do some fighting against monsters, and these +pieces of information will help you decide the best way to fight which +enemies. For now, since you've chosen human, you are probably smart but +not very strong. Let's try to fix that, because fights usually go +better if you are strong. + +Every new player has 15 customization points when they join (this only +happens once), so make yourself stronger by adding customization +points to your strength, for example: + +customize strength 5 + +If your intelligence is below 50, you definitely need to increase it too, +if you're going to be a mage. You usually want a strength of at least 30 and +an intelligence above 50, preferably above 60, for casting spells. + +Ok, next, let's get you equipped for exploring. If you're lucky, someone has +left stuff in the church bin. Go to the church: + +go west, go north (or w for west, and n for north) + +From this point, directions will be given like this: + +1w, 1n + +Meaning, in this example, go west once, go north once. + +Now: + +look in bin + +Hopefully there is a bunch of stuff in there but if someone else got +there first, you will need to get equipped on your own, without the +church's charity. For the purpose of this guide, we'll assume you didn't +find anything there. + +Let's get started with your first quest: Cave Explorer I + +Go from the church to the Adventurers' Guild: + +1s, 2e, 1s + +This is where you go to get info on questing and other stuff. There is +a charity bin here too, check it for helpful items. The important thing +to do here, though, is: + +read list + +This tells you the list of quests available. Did you see Cave Explorer I? +We're going to go solve that one right now! + +1n, 5w, 26n, enter cave + +You'll notice that you walked through a big forest just then. Don't try +to explore the forest yet, you could get lost. Just go straight north, +and go fast, because if you accidentally run into an orc, you do *not* +want to hang around and wait for him to start hitting you. + +If you goof up here and do get killed by an orc, well, we might as well talk +about death now. Death takes away a few of your experience points, which +isn't good because you need them to go up in levels. Definitely avoid +death. You can avoid losing those experience points by being resurrected, +but that takes getting the help of another player and we can discuss that +another time. + +For now, just know that if you get killed, you need to: regenerate +And you will rematerialize in the start room. + +Anyway, hopefully you did not die and you are now inside the secret cave +in the forest, and you have completed your very first quest. That was +easy, right? You might even have automatically advanced a level or +two. Congratulations! The next quest will be harder, and it is the Orc +Slayer quest. + +By the way, if that room was too dark to see, come back later with a flashlight +or a torch. There is interesting writing on the door, and on the wall. And, +of course, a powerful and convenient teleportation device sitting right +there on the floor. diff --git a/lib/doc/cheats/chapter02 b/lib/doc/cheats/chapter02 new file mode 100644 index 0000000..4e26398 --- /dev/null +++ b/lib/doc/cheats/chapter02 @@ -0,0 +1,296 @@ +chapter 2 "Orc Slayer" + +You should now be standing in the secret cave in the woods, having +just completed the Cave Explorer I quest. Now things get complicated, +because the next quest is Orc Slayer, and as a weak human there is +absolutely no way you can fight your way through this quest. You will +have to sneak around, so pay attention to all the details here. + +The first thing you need to do is find a way to become invisible so +that you can sneak by some orcs later. There happens to be an invisibility +device available to you, but it is far away. You can't walk to it. You have +to teleport to it. The good news is that there is a teleportation device +in this secret cave you're standing in! It's called a stargate and you +can dial different destinations on it to reach other stargates. Type: + +dial campus lab +enter gate + +See doctor Kleiner? He is wearing a badge you need, but you can't kill +him for it, he will escape if you try. So leave him alone for now. We need +to get you some other loot. + +1s, 1e, 1n, 3e, open door, 1s + +You are now in the Virtual Campus admissions room, and there is a robot +here named Jenny who will give you an introduction to the game, but more +importantly, she will give you some valuable loot you can sell at the +campus store. You'll see why you need to get this loot, just trust me +for now. type: + +activate bot + +And when you're done reading what she says, type: + +next tip + +Until she's done giving you tips. At the end she will give you a hat and +some other goodies. When you have the loot, go: + +1n, 2e, 1n + +To the campus bookstore, and type: + +sell hat to kim + +This should get you a bunch of dollars. Now type: + +buy coat from kim + +And she will give you a lab coat. You see, Dr. Kleiner is looking for +his lab coat, and you will give this to him. Go back to Kleiner: + +1s, 5w, 1s, 1w, 1n + +give coat to kleiner + +Note that while Kleiner is putting on the coat, he drops the badge! Grab +it quick: + +get badge +wear badge + +Now you can enter the room with the invisibility device. You hadn't forgot +about that, had you? + +2s + +get computer from bench +get module from bench +wear computer +activate computer +open computer +install module in computer +close computer + +Now you're ready to do some serious sneaking around. You're not +invisible yet, but we're going to hold off on that for now. Being invisible +uses up your stamina points, so we're going to save it for when you +really need it. Let's get back to the main village and get some other +stuff you really need. + +2n +dial cave +enter gate +26s, 2e, 1s + +Now, here you may run into a problem. If you went up a few levels already, +you won't be able to get past this guard, because he only ignores total +newbies. So you'll have to sneak by him: + +cloak +1s +decloak + +Remember to decloak. If you walk around cloaked (invisible) all the time +you will run out of stamina and that's no fun. Now, let's look around: + +look +look at window + +1w, 1n +get all +1s, 1e +drop ladder + +The mansion door is locked so the only way in is to: + +climb ladder + +You're now in the old abandoned mansion. Time to grab some stuff you'll need: + +1w +search + +You should now see a complex key. You'll need it for opening a safe later. + +get key +1e, 2s, 1d, 2n +cloak +1e + +Here you see a thief that has been using the abandoned mansion as his +own home. If he sees you he will attack, so you really should sneak by +him instead. Notice the rug here? Doesn't it seem strange that it was +so obvious? Is anything underneath it? + +move rug +open door +1d +turn on flashlight +look +open chest +get all from chest +get all from bag +1u, 1w +decloak + +Ok, so let's review what we've done so far. We found an invisibility device, +used it to get past a gate guard, used a ladder to climb into a mansion, +found a key, snuck past a thief to find another key, and now we have +a bunch of loot and money, and you're possibly at level 5 now! + +score + +Pretty cool! But we haven't solved the orcslayer quest yet, so let's keep +going. + +2s, u +unlock door with silver key +open door +1s + +Ok, notice some other obvious things here? A bed and a wardrobe? We'll +get to the wardrobe later, for now let's see if there's anything behind this +big bed: + +move bed + +Well well well! Let's explore further: + +enter passageway +unlock safe with complex key +open safe +get all from safe +drop complex key + +Goodness gracious! That's quite a lot of good loot! A grenade?!? Well don't +use it yet, this is exactly what we will need to solve the orc slayer +quest. We're almost there. + + +Now, at this point you may be carrying too much loot. You're not very big and +strong yet, and you can't arry all your loot and money around all the time. + +Let's get to the bank and deposit some of this cash. + +4n, 1d, 2n, 2e, 3n, 1e + +This is the bank. Let's start by opening a bank account: + +request account from zoe +deposit all + +There! Now you have money stashed away in case things get tough, and now +you can carry more stuff. Let's go sell some of the loot you picked up from the +mansion to make more room in your inventory. + +1w, 3s, 1e, 1n + +sell plastic flashlight to otik + +You can now sell any of the gear you got that you don't think you need. Be careful.. +if you want to buy something back it'll cost you more than you sold it for. Capitalism! + +All righty, now we're ready to confront those orcs...sort of. + +Here's where things get tricky. We'll need to sneak by a bunch of orcs, +but we don't want to waste stamina doing it, so we want to be efficient. We +also want to make sure that we don't make mistakes because we'll need to +move quickly. + +First, let's get where we're going: + +1s, 5w, 1sw +cloak +1w, 1n, 1w + +It's a good thing you're cloaked because you would have been attacked +by all those orcs you snuck past. You're now in the temple of the orc +shaman. If it's too dark to see, turn on the maglite: + +turn on maglite + +Now we're going to plan things out to make sure we don't make any +mistakes. The game has a way for you to bind keys to specific commands. + example type: + +alias 1 smile + +Now if you type the number 1 and hit enter, the game will act as if you +typed out the command "smile". This is important because there are +some commands that need to be typed quickly but cannot be misspelled. +Using keyboard aliases helps in these time-sensitive situations. + +We're about to have a time sensitive situation. Make some aliases: + +alias 1 pull pin on grenade +alias 2 drop grenade +alias 3 go east + +Make sure you have those aliases entered correctly. Especially make sure you +made number 3 be go east, not the letter e, because e is itself an alias and +aliases can't refer to aliases. Now go ahead: + +1 +2 +3 + +And wait 10 seconds. Don't go back west too soon or you'll be in the room +when the grenade goes off! To be sure it's safe, try to look into the +next room: + +peer west + +Is the shaman blown up? Good, go back and get that sword from him. + +get sword from corpse +get helmet from corpse + +You don't need the helmet right this minute, but you will later, so get +it if you can. Now let's go back to the church: + +1e, 1s, 1e +decloak +1ne, 3e, 1n + +All righty, we're almost done! Did you notice that the church has an +elevator? Let's find out what's in the basement. + +push button +1w +push b button (then wait until the elevator stops) +1e + +This is Leo the archwizard. Don't worry, he's not named after anyone you +know, he's been around a long long time. See how he's complaining he lost +the orcslayer? Take a look at the sword you got from the shaman. + +exa orcslayer + +Interesting huh? What if this is what Leo is looking for? + +give orcslayer to leo + +Ta-daa! Now you have solved the orc slayer quest, and Herkimer will +allow you to join the mages guild: + +push button +1w +push 1 button (then wait until the elevator stops) +1e +1s, 1e, 1s, 1w, 1s +ask herkimer to join +ask herkimer to teach whip +ask herkimer to teach buffer +ask herkimer to teach missile +ask herkimer to teach meditate +ask herkimer to teach light +ask herkimer to teach fireball + +And now try out some of your new spells: + +cast whip +cast buffer + +Congratulations, mage. You may now be ready for trickier tests of your mettle. diff --git a/lib/doc/cheats/chapter03 b/lib/doc/cheats/chapter03 new file mode 100644 index 0000000..894c6c0 --- /dev/null +++ b/lib/doc/cheats/chapter03 @@ -0,0 +1,37 @@ +chapter 3 "Orcmaster quest" + +This one is a bit easier. Again, we can get this done without actual combat. + +So you're now a mage standing in the Mage's Guild. Let's head over to Roshd +Burlyneck, the Fighter guildmaster who is looking for his missing helmet. Remember +the helmet you got off the dead orc shaman? Exactly. Two birds with one stone. + +1n, 1e, 1n, 4w, 26n, enter cave + +Remember this place? We're goig to teleport to a different location now: + +cast light +look +dial tower +enter gate + +1d, 1s, 1w, 1n + +You're now in the Fighter's Guild. + +give helmet to roshd + +Now what on earth just happened? What's all this weird text? +That's a language you do not understand, Tangetto. It is the language of the Orcs. + +Roshd just told you thanks dude, if you want to join the Fighter's guild, now you can. + +Now you know how yo join the Fighter's +guild if you want to. Since you're already a human mage that doesn't help you much now, +but if you want to play through again later with a new character that's, say, an orc, +you now know how to get hooked up. + +That's not to say that humans can't be fighters by the way. I'm just saying that +*statistically* it may be more rewarding to choose a bulkier race for that. You +do you, tho, breh. + diff --git a/lib/doc/cheats/chapter04 b/lib/doc/cheats/chapter04 new file mode 100644 index 0000000..39b8831 --- /dev/null +++ b/lib/doc/cheats/chapter04 @@ -0,0 +1,164 @@ +chapter 4 "The Town Well" + +This one is really tricky. There are wheels to turn, levers to pull, +grates to open, and as a weak little human you can't do it all yourself... +or can you? This isn't called a cheat book for nothing. + +All righty we're going to call upon some of the stuff you've already done. +We need to head back to the town and deposit any cash you picked up and +sell any heavy armor you may have that you don't really need (like the +leather boots and jacket from the mansion or chainmail from the church) +and then deposit that money too. Get in the habit of watching your +encumbrance. Keep that weird gray amulet if you found it in the church, though. +And that access badge from Kleiner! + +It's especially important now because you'e about to go fetch a bunch of +heavy equipment to get this quest done. + +So if you're still at Roshd, head back to town: + +1s, 1e, 1n, 1u +dial cave +enter gate +out +26s, 5e, 1n +sell blue jeans +sell white shirt (etc) +1s, 1w, 3n, 1e +deposit all + +Ok now back to the Campus lab + +1w, 3s, 4w, 26n +enter cave +dial campus lab +enter gate +2s +get all from bench + +Yeah dude. A rocket pack and a portal generator. Sweet. Save those for a little later. + +2n +dial stargate lab +enter gate +1n, 1e + +What? What is this? A mech? What? Yes indeed. There should be a landstrider mech +here...looking kind of like ED-209 from Robocop but with a seat you can get into. + +give badge to mech +enter mech +drive west +drive south +direct mech to dial campus lab +direct mech to enter gate +drive south +drive south +get badge +direct mech to enter portal +exit mech +cast light + +You're in an underground tunnel that has a very heavy door that you can't open +yourself if you're a puny human, so you're goig to have to get the mech to +open it for you, once you get the key. Let's leave the mech here for now. + +Make sure you get that badge back or you won't be able to get back here. + +enter portal +1n, 1e, 1n, 2e +open door +cast light +1s, 1d, 1w +push wall +2w, 1s +open hatch +1d +get key from table +1u, 1n, 4e, 1u, 1n, 2w, 1s, 1w, 1s +enter portal +cast light +unlock door with key +enter mech +direct mech to open door +drive west +drive west +direct mech to open grate +drive east +drive east +direct mech to enter portal +exit + +All right so we've unlocked that super heavy door and had the mech open it, +then we had the mech open the super heavy grate. There are other ways to solve +this problem, and they involve killing a human and then making it into a zombie. +If you want to try that solution (or the mech or portal are not available), read the +player hints book and that will guide you through. Otherwise, this method is the +quick and dirty. Now we need to open up the water wheel so that water can start +flooding the overhead chamber...but we also want to wear some gear that will +let us breathe underwater in case we don't type fast enough. + +Remember all that crud you grabbed from the lab table earlier? One of those things +was an A98 breathing device. This will help. If you don't have it handy, just be sure +you can type fast. The next steps will flood the rooms you are in, and as a human +you are not super great at breathing water. + +enter portal +2w +wear a98 +turn wheel +2e +enter portal +remove a98 + +Ok! What's happening now is that a bunch of water is flooding the rooms you were +in. It's flooding upwards into a chamber near the town well. This will take a few +minutes. Once that's done, we'll head over to the well and open a door that lets +the water into the well, solving the quest. + +Another thing the water is doing is flooding along the corridor you were in, and +filling up a locked-up room with water. This is a really really good thing, because +that room has a cave troll that you need to be dead for a different quest, and it is +much easier to have it die from drowning than to have to kill it with combat. + +All right, let's head up to the well. + +2n +dial cave +enter gate +out +26s, 4e, 1s +enter well + +Ok here we are. Has it been a few minutes? Maybe 5 or so? Let's go ahead and open +that flood door: + +pull lever + +If that doesn't work, push the lever and wait some more and try again. If that still +doesn't work, you may need to try the zombie solution. + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/doc/cheats/chapter05 b/lib/doc/cheats/chapter05 new file mode 100644 index 0000000..9f1e42d --- /dev/null +++ b/lib/doc/cheats/chapter05 @@ -0,0 +1,40 @@ +chapter 5 "Princess Daphne" + +This quest is both very easy and very hard. In any case it is very simple. + +Princess Daphne is the name of a very valuable diamond which is on sale in the +Campus Bookstore...the same place you bought a lab coat for Kleiner. The way +to solve this quest is to scavenge and scrounge, making and finding coins, +and then convering all that money into 50,000 dollars at the bank. Then you +go to the campus bookstore, buy the diamond, then go to Dirk at the +Adventurer's Hall and give him the diamond. + +Easy in principle, but it will take some grinding and exploring to get it +done. I suggest you go to Radagast and use the training ponts you earned +with all this leveling up and get trained up on your mage levels. Radagast +is a trainer and is one room up from Dirk in the Adventurer's Hall. Don't +bother asking Herkimer to train you, he doesn't know how. Go to Radagast. + +Protip: You train better if you're smarter. If you've found a magic +pipe somewhere, guess what, the magic is that you're slightly smarter +if you smoke it. If you have it, find (or buy) some matches, then + +strike match +light pipe with match +smoke pipe + +Pipe or not, to train with Radagast: + +ask radagast to train magic attack +ask radagast to train magic defense +ask radagast to train conjuring + +If you don't speak English because you picked elf as your race, you +will need to go to Bugg (1d, 1n, 2e, 1n of Radagast) and "ask bugg to teach english" a +few times until you're fluent. It'll cost you a few training points, but that's better +than not being able to train up on magic. + +To know your language proficiency, type: languages +To switch to another language: speak in english + + diff --git a/lib/doc/cheats/chapter06 b/lib/doc/cheats/chapter06 new file mode 100644 index 0000000..c2fa76d --- /dev/null +++ b/lib/doc/cheats/chapter06 @@ -0,0 +1,68 @@ +chapter 6 "Cave Explorer II & The Postman" + +These two are related. The letter you need to give to Roshd is hidden +in the treasure chest of the Orc captain you need to slay. + +Lat's assume we're starting this from Radagast's training room because +you didn't listen to me in the last chapter and you went there to do +magic training. All righty, let's head to the cave where the Orc +invasion force is gathering in preparation to destroy the town above. + +1d, 1n, 4w + +We are now on the humpbacked bridge between the town and the forest. +Below this bridge is a nasty troll and the cave where the bad guy orcs +live. We will do some more sneaking here. + +cloak +1d + +See the troll? Nasty. + +2e, 1ne, 1nw, 1n, 1e, 2n +open door +1n + +You're here. The orc commander. Notice how low your stamina is...all that +cloaked sneaking really sapped your strength. If you were higher level +I would have suggested fighting your way here and then slamming +this guy with your magic whip and fireballs while shielding yourself +with magic buffer after buffer. This is a no-foolin' boss level guy, and +when you start fighting, he closes and locks the door behind you. Unless +you've figured out the portal device or the omni or some other way to +magically retreat if things get tenuous, you are in it to win it. + +So, I'm not going to give you cheats on winning that. There are no cheats. +You'll have to level up and grind up until you can go toe to toe with the Orc +Commander. + +But, here's how you can complete the Postman quest: + +get letter from table +2s, 1w, 1s, 1se, 1sw, 2w, 1u +decloak + +There's an excellent chance you ran out of stamina along the way there. +Make sure that doesn't happen. Becoming visible in the lair of an orc +invasion force is not a good idea if you're not loaded for bear. + +One way to speed up your recovery is to cast a spell that helps center you: + +cast meditate + +All right, let's head to Roshd: + +1w, 26n +enter cave +dial tower +enter gate +1d, 1s, 1w, 1n +give letter to roshd + +If you tried to read it, it's Tangetto and you couldn't make heads or tails of +it. It's some dumb stuff about how humans are savages and the orc outpost +is only barely hanging on and I love you so much blah blah. Anyway hand it over +and you get your points. + + + diff --git a/lib/doc/cheats/chapter07 b/lib/doc/cheats/chapter07 new file mode 100644 index 0000000..ea68047 --- /dev/null +++ b/lib/doc/cheats/chapter07 @@ -0,0 +1,180 @@ +chapter 7 "Miscellaneous Tips and Secrets" + +- The portal generator (portal gun) works by making an orange portal in one +place, and blue portal somewhere else, and presto, you can now teleport +between those two places by entering one of the portals. By default you only +find the portal generator with the "ammo" for the blue portal...the blue vial. +To make it really useful you need to find the orange vial and install it +in the portal generator too. Unfortunately the orange vial is on a rawther +nasty and tough cave troll. Good luck. + +- When you're in combat with multiple opponents, you really really have to use +the "target" command. For example, "target orc". Otherwise you will keep shifting +your target to the last guy what hit you, and you will not whittle down your +oppenents fast enough and you will die. This is why you need to be very careful +if you get trapped in a room with a dozen rats. If you don't target one at a +time, you're liable to be nibbled to death. + +- If you're fighting and you can't see, you aren't going to do any damage. + +- Unless you are a fighter NEVER wield two weapons at once. Double wielding, and +for that matter, two handed weapons, are skills that fighters have. If you're +not a fighter, double wielding dramatically decreases your combat effectiveness. +Also, unless you're a fighter don't bother trying to fight without wielding a +weapon of some kind. + +- Getting drunk and sleeping makes you heal faster. You can also heal a little +faster by giving Clepius a healing slip, and he'll rub some healy stuff on you. +Healing this way is pretty slow though. For fast healing, either buy potions +from Oana in the magic shop (very expensive) or buy yellow or green spices +from Brandy in Harry's bar (east and south of the town, by the water). You +have to flatter Brandy in the right way for her to be ok with selling you spice. +Say what a good wife you would be. + +- Yellow spice is good for health, blue spice is good for mana, green spice is +good for stamina. You have to pay Brandy in gold. Go to Zoe in the bank for +exchanging money. + +- The rocket pack works pretty ok, in fact perhaps too well. If you boost +up and fly around carelessly, you are very very likely to wind up somewhere +extremely unhelpful, like an ocean with no sense of which way to swim for land. +Its best use is for very short hops over dangerous areas or pits. + +- Do not stargate into space. It will kill you without breathing apparatus, and even +with a breather, if you use the rocket pack, you are almost certain to careen +out of control and eventually run out of air before you can find your way back +to the outer space stargate. + +- It's probably ok to stargate to the sea bottom location if you have a +breathing device, but be sure not to lose your bearings or you'll run out of +air there too. + +- The door in the stargate cave says "Speak, friend, and enter" in the elvish +language of Edhellen. If you want access to the very fine sword and the resurrection +scroll that are on the other side of that door, you'll need to go to the +Bugg, the language teacher, 1n, 2e, 1n of Dirk. And you'll need to spend +training points. + +- The omni is a teleportation device and when you press the button on it it will +tend to whisk you away from trouble. However it has a mind of it own and if it +is in your direct inventory for too long it'll teleport itself away. Keep it +in a rucksack or something. + +- You definitely want a big bag you wear, like the rucksack. The ruck has greater +capacity than other things like the backpacks. It's important to have a bag you +can wear. If you "sell all to otik", worn and wielded things are not sold, +so this is helpful when getting rid of lots of stuff at once. It's also a handy +way to organize your short term versus long term inventory. + +- Don't activate the turret in a room you plan to be in. It doesn't care what it +shoots, it just wants to shoot. + +- If you want XP, grind in the forest. Plenty of critters. Just watch out for +wandering orc soldiers. Only grind there when you are strong enough to take +down orcs. + +- Poleepkwa are very very strong, but that's about it. An insectile +race of fairly low intelligence and with their own language, they are doomed +to playing with no magic and not understanding any written or spoken material +they come across. Poleepkwa is playing on hard difficulty. Not recommended. +Having said that, if you play poleepkwa and get your claws on the powered +armor in the lab, you can kill pretty much anything you come across. + +- If you want to play as a fighter class as dwarf or orc, kill the orc +shaman as if you were going to become mage but instead of giving the +orcslayer sword to Leo in the church, give the helmet to Roshd near the +tower in Ylsrim. + +- When you are a total newbie, you might understand and be able to read +languages different than those of your race. As you lose newbie status, +this goes away and if a language is important to you, you will need to go +learn it at Bugg's. And you better have a high intelligence stat. + +- A lot of locks are pickable but you need a tool to do it. There is a +lockpick in the mansion, in a bag in a room the thief has been using +to sleep in. Once you have it, you can try to "pick lock on door with pick" +or "pick lock on locker with pick". However, it uses up your stamina, +and if you fail you hurt yourself, it doesn't always work, and for it +to work predictably you need to be rogue class and have lockpicking skills. +If you're a mage you can cast buffer so that it hurts less when you fail +a lot. + +- The second vial for the portal gun is in the posession of a cave troll +that lives underneath an orc chieftain. Starting from the orc +commander, go 3s, 1e, 1ne, 1s and you are at the chieftain. wear the rocket +pack (this is important) and activate it, then kill the chieftain. This +may be easier with the pistol (instructions below). Right before he dies, +in the throes of furious retribution, the orc chieftan will activate a trap +that dumps eveything into a pit below, where the cave troll waits. Ideally +he'll be dead and drowned from your solving the well quest. If he's not, +you are now hovering (because of the rocket pack) over an angry cave troll +that is probably way too tough for you to kill. Drop a live grenade +and wait for it to kill him, then boost down and get your loot, then +boost back up. Don't dilly dally too long or you'll run out of rocket pack fuel. +Still, that chieftain is pretty tough. Do some grinding to get up to +level 12 or so, maybe higher. Or tackle this with a party. + +- If you were observant during your raid on the mansion, there is a 9mm pistol +in the safe. If you kept it, you can find an ammunition magazine in the +locked locker 1n, 1e, 1s of Jennybot in the Virtual Campus. The key for +the locker is in a trash can in University Square, where Wim and Tim are +standing near a tree. The trash can is there, but trickily it is hidden +in the room description, instead of being part of the inventory listed +when you look. If the key is already gone, you may need to pick the +lock on the locker with the lockpick. + +Once you have the clip and the gun: + +load clip in pistol +wield pistol +shoot orc with pistol + +- If you die or otherwise somehow remove the Yautja wrist computer, it will +deactivate. To be able to cloak again: + +wear computer +open computer +activate computer +uninstall module from computer +install module in computer +close computer + +- If you're out of money for buying spice from Brandy, you can heal the old +fashioned way: eating food, drinking water, and waiting to heal. Having a full +belly and not being thirsty speeds up how quickly your health, stamina, and mana +regenerate. If you don't have money to buy snacks, go under the the humpbacked +bridge in the town (from Dirk: 1n, 4w, 1d), then: + +cast whip +cast buffer +cast fireball on troll + +Pay attention to the battle. If your buffer shield goes away, cast it again. +And again. And again. Once the troll is dead: + +search rocks +get pole +get can from troll +get worm from can +bait pole with worm +fish with pole + +Eventually you will catch some fish you can eat, to keep up your strength. +Drink some water too: + +eat herring +drink from river +drink from river + +And keep drinking from the river until you can't drink any more. This way of +healing is slower, but it is free, and you'll eventually be back to 100%. + + + + + + + + + + diff --git a/lib/doc/efun/all/TODO b/lib/doc/efun/all/TODO new file mode 100644 index 0000000..839ed60 --- /dev/null +++ b/lib/doc/efun/all/TODO @@ -0,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 --git a/lib/doc/efun/all/acos b/lib/doc/efun/all/acos new file mode 100644 index 0000000..ac9612a --- /dev/null +++ b/lib/doc/efun/all/acos @@ -0,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 --git a/lib/doc/efun/all/add_action b/lib/doc/efun/all/add_action new file mode 100644 index 0000000..b1a4c4f --- /dev/null +++ b/lib/doc/efun/all/add_action @@ -0,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 --git a/lib/doc/efun/all/all_inventory b/lib/doc/efun/all/all_inventory new file mode 100644 index 0000000..cedceba --- /dev/null +++ b/lib/doc/efun/all/all_inventory @@ -0,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 --git a/lib/doc/efun/all/all_previous_objects b/lib/doc/efun/all/all_previous_objects new file mode 100644 index 0000000..e5fb417 --- /dev/null +++ b/lib/doc/efun/all/all_previous_objects @@ -0,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 --git a/lib/doc/efun/all/allocate b/lib/doc/efun/all/allocate new file mode 100644 index 0000000..227cd3a --- /dev/null +++ b/lib/doc/efun/all/allocate @@ -0,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 --git a/lib/doc/efun/all/allocate_buffer b/lib/doc/efun/all/allocate_buffer new file mode 100644 index 0000000..1f30d2c --- /dev/null +++ b/lib/doc/efun/all/allocate_buffer @@ -0,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 --git a/lib/doc/efun/all/allocate_mapping b/lib/doc/efun/all/allocate_mapping new file mode 100644 index 0000000..e5daf86 --- /dev/null +++ b/lib/doc/efun/all/allocate_mapping @@ -0,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 --git a/lib/doc/efun/all/arrayp b/lib/doc/efun/all/arrayp new file mode 100644 index 0000000..aceb839 --- /dev/null +++ b/lib/doc/efun/all/arrayp @@ -0,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 --git a/lib/doc/efun/all/asin b/lib/doc/efun/all/asin new file mode 100644 index 0000000..efb86eb --- /dev/null +++ b/lib/doc/efun/all/asin @@ -0,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 --git a/lib/doc/efun/all/atan b/lib/doc/efun/all/atan new file mode 100644 index 0000000..827c11c --- /dev/null +++ b/lib/doc/efun/all/atan @@ -0,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 --git a/lib/doc/efun/all/author_stats b/lib/doc/efun/all/author_stats new file mode 100644 index 0000000..586f9e8 --- /dev/null +++ b/lib/doc/efun/all/author_stats @@ -0,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 --git a/lib/doc/efun/all/bind b/lib/doc/efun/all/bind new file mode 100644 index 0000000..8851231 --- /dev/null +++ b/lib/doc/efun/all/bind @@ -0,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 --git a/lib/doc/efun/all/bufferp b/lib/doc/efun/all/bufferp new file mode 100644 index 0000000..13dff18 --- /dev/null +++ b/lib/doc/efun/all/bufferp @@ -0,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 --git a/lib/doc/efun/all/cache_stats b/lib/doc/efun/all/cache_stats new file mode 100644 index 0000000..3ecf9e7 --- /dev/null +++ b/lib/doc/efun/all/cache_stats @@ -0,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 --git a/lib/doc/efun/all/call_other b/lib/doc/efun/all/call_other new file mode 100644 index 0000000..9b66bb0 --- /dev/null +++ b/lib/doc/efun/all/call_other @@ -0,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 --git a/lib/doc/efun/all/call_out b/lib/doc/efun/all/call_out new file mode 100644 index 0000000..3ed9f3c --- /dev/null +++ b/lib/doc/efun/all/call_out @@ -0,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 --git a/lib/doc/efun/all/call_out_info b/lib/doc/efun/all/call_out_info new file mode 100644 index 0000000..22116c8 --- /dev/null +++ b/lib/doc/efun/all/call_out_info @@ -0,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 --git a/lib/doc/efun/all/call_stack b/lib/doc/efun/all/call_stack new file mode 100644 index 0000000..081c3b6 --- /dev/null +++ b/lib/doc/efun/all/call_stack @@ -0,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 --git a/lib/doc/efun/all/capitalize b/lib/doc/efun/all/capitalize new file mode 100644 index 0000000..e939e2f --- /dev/null +++ b/lib/doc/efun/all/capitalize @@ -0,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 --git a/lib/doc/efun/all/catch b/lib/doc/efun/all/catch new file mode 100644 index 0000000..f47877e --- /dev/null +++ b/lib/doc/efun/all/catch @@ -0,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 --git a/lib/doc/efun/all/ceil b/lib/doc/efun/all/ceil new file mode 100644 index 0000000..8eb05b4 --- /dev/null +++ b/lib/doc/efun/all/ceil @@ -0,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 --git a/lib/doc/efun/all/check_memory b/lib/doc/efun/all/check_memory new file mode 100644 index 0000000..577188c --- /dev/null +++ b/lib/doc/efun/all/check_memory @@ -0,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 --git a/lib/doc/efun/all/children b/lib/doc/efun/all/children new file mode 100644 index 0000000..0df1dfc --- /dev/null +++ b/lib/doc/efun/all/children @@ -0,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 --git a/lib/doc/efun/all/classp b/lib/doc/efun/all/classp new file mode 100644 index 0000000..9e53f8f --- /dev/null +++ b/lib/doc/efun/all/classp @@ -0,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 --git a/lib/doc/efun/all/clear_bit b/lib/doc/efun/all/clear_bit new file mode 100644 index 0000000..7a70f44 --- /dev/null +++ b/lib/doc/efun/all/clear_bit @@ -0,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 --git a/lib/doc/efun/all/clone_object b/lib/doc/efun/all/clone_object new file mode 100644 index 0000000..a374415 --- /dev/null +++ b/lib/doc/efun/all/clone_object @@ -0,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 --git a/lib/doc/efun/all/clonep b/lib/doc/efun/all/clonep new file mode 100644 index 0000000..dbb50dd --- /dev/null +++ b/lib/doc/efun/all/clonep @@ -0,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 --git a/lib/doc/efun/all/command b/lib/doc/efun/all/command new file mode 100644 index 0000000..24ddb40 --- /dev/null +++ b/lib/doc/efun/all/command @@ -0,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 --git a/lib/doc/efun/all/commands b/lib/doc/efun/all/commands new file mode 100644 index 0000000..04df2b4 --- /dev/null +++ b/lib/doc/efun/all/commands @@ -0,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 --git a/lib/doc/efun/all/copy b/lib/doc/efun/all/copy new file mode 100644 index 0000000..cdaa1fc --- /dev/null +++ b/lib/doc/efun/all/copy @@ -0,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 --git a/lib/doc/efun/all/cos b/lib/doc/efun/all/cos new file mode 100644 index 0000000..3be7040 --- /dev/null +++ b/lib/doc/efun/all/cos @@ -0,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 --git a/lib/doc/efun/all/cp b/lib/doc/efun/all/cp new file mode 100644 index 0000000..f2e4dcf --- /dev/null +++ b/lib/doc/efun/all/cp @@ -0,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 --git a/lib/doc/efun/all/crc32 b/lib/doc/efun/all/crc32 new file mode 100644 index 0000000..b0a190a --- /dev/null +++ b/lib/doc/efun/all/crc32 @@ -0,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 --git a/lib/doc/efun/all/crypt b/lib/doc/efun/all/crypt new file mode 100644 index 0000000..73eb2fc --- /dev/null +++ b/lib/doc/efun/all/crypt @@ -0,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 --git a/lib/doc/efun/all/ctime b/lib/doc/efun/all/ctime new file mode 100644 index 0000000..43281d2 --- /dev/null +++ b/lib/doc/efun/all/ctime @@ -0,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 --git a/lib/doc/efun/all/debug_info b/lib/doc/efun/all/debug_info new file mode 100644 index 0000000..226e07e --- /dev/null +++ b/lib/doc/efun/all/debug_info @@ -0,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 --git a/lib/doc/efun/all/debug_message b/lib/doc/efun/all/debug_message new file mode 100644 index 0000000..a57d3ca --- /dev/null +++ b/lib/doc/efun/all/debug_message @@ -0,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 --git a/lib/doc/efun/all/debugmalloc b/lib/doc/efun/all/debugmalloc new file mode 100644 index 0000000..b04d4b3 --- /dev/null +++ b/lib/doc/efun/all/debugmalloc @@ -0,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 --git a/lib/doc/efun/all/deep_inherit_list b/lib/doc/efun/all/deep_inherit_list new file mode 100644 index 0000000..2795390 --- /dev/null +++ b/lib/doc/efun/all/deep_inherit_list @@ -0,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 --git a/lib/doc/efun/all/deep_inventory b/lib/doc/efun/all/deep_inventory new file mode 100644 index 0000000..03eee3a --- /dev/null +++ b/lib/doc/efun/all/deep_inventory @@ -0,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 --git a/lib/doc/efun/all/destruct b/lib/doc/efun/all/destruct new file mode 100644 index 0000000..8b361ef --- /dev/null +++ b/lib/doc/efun/all/destruct @@ -0,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 --git a/lib/doc/efun/all/disable_commands b/lib/doc/efun/all/disable_commands new file mode 100644 index 0000000..185c207 --- /dev/null +++ b/lib/doc/efun/all/disable_commands @@ -0,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 --git a/lib/doc/efun/all/disable_wizard b/lib/doc/efun/all/disable_wizard new file mode 100644 index 0000000..e3b52c4 --- /dev/null +++ b/lib/doc/efun/all/disable_wizard @@ -0,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 --git a/lib/doc/efun/all/domain_stats b/lib/doc/efun/all/domain_stats new file mode 100644 index 0000000..7483a14 --- /dev/null +++ b/lib/doc/efun/all/domain_stats @@ -0,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 --git a/lib/doc/efun/all/dump_file_descriptors b/lib/doc/efun/all/dump_file_descriptors new file mode 100644 index 0000000..b237e87 --- /dev/null +++ b/lib/doc/efun/all/dump_file_descriptors @@ -0,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 --git a/lib/doc/efun/all/dump_prog b/lib/doc/efun/all/dump_prog new file mode 100644 index 0000000..4d31e64 --- /dev/null +++ b/lib/doc/efun/all/dump_prog @@ -0,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 --git a/lib/doc/efun/all/dump_socket_status b/lib/doc/efun/all/dump_socket_status new file mode 100644 index 0000000..058a564 --- /dev/null +++ b/lib/doc/efun/all/dump_socket_status @@ -0,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 --git a/lib/doc/efun/all/dumpallobj b/lib/doc/efun/all/dumpallobj new file mode 100644 index 0000000..7a614ff --- /dev/null +++ b/lib/doc/efun/all/dumpallobj @@ -0,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 --git a/lib/doc/efun/all/ed b/lib/doc/efun/all/ed new file mode 100644 index 0000000..d46c6be --- /dev/null +++ b/lib/doc/efun/all/ed @@ -0,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 --git a/lib/doc/efun/all/ed_cmd b/lib/doc/efun/all/ed_cmd new file mode 100644 index 0000000..d3ae2fd --- /dev/null +++ b/lib/doc/efun/all/ed_cmd @@ -0,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 --git a/lib/doc/efun/all/ed_start b/lib/doc/efun/all/ed_start new file mode 100644 index 0000000..601e316 --- /dev/null +++ b/lib/doc/efun/all/ed_start @@ -0,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 --git a/lib/doc/efun/all/enable_commands b/lib/doc/efun/all/enable_commands new file mode 100644 index 0000000..ec00775 --- /dev/null +++ b/lib/doc/efun/all/enable_commands @@ -0,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 --git a/lib/doc/efun/all/enable_wizard b/lib/doc/efun/all/enable_wizard new file mode 100644 index 0000000..43dd232 --- /dev/null +++ b/lib/doc/efun/all/enable_wizard @@ -0,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 --git a/lib/doc/efun/all/environment b/lib/doc/efun/all/environment new file mode 100644 index 0000000..47ebb27 --- /dev/null +++ b/lib/doc/efun/all/environment @@ -0,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 --git a/lib/doc/efun/all/error b/lib/doc/efun/all/error new file mode 100644 index 0000000..0fcd489 --- /dev/null +++ b/lib/doc/efun/all/error @@ -0,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 --git a/lib/doc/efun/all/eval_cost b/lib/doc/efun/all/eval_cost new file mode 100644 index 0000000..dbfea2d --- /dev/null +++ b/lib/doc/efun/all/eval_cost @@ -0,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 --git a/lib/doc/efun/all/evaluate b/lib/doc/efun/all/evaluate new file mode 100644 index 0000000..c170c2a --- /dev/null +++ b/lib/doc/efun/all/evaluate @@ -0,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 --git a/lib/doc/efun/all/exec b/lib/doc/efun/all/exec new file mode 100644 index 0000000..c17d852 --- /dev/null +++ b/lib/doc/efun/all/exec @@ -0,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 --git a/lib/doc/efun/all/exp b/lib/doc/efun/all/exp new file mode 100644 index 0000000..f26bebf --- /dev/null +++ b/lib/doc/efun/all/exp @@ -0,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 --git a/lib/doc/efun/all/explode b/lib/doc/efun/all/explode new file mode 100644 index 0000000..d99d715 --- /dev/null +++ b/lib/doc/efun/all/explode @@ -0,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 --git a/lib/doc/efun/all/export_uid b/lib/doc/efun/all/export_uid new file mode 100644 index 0000000..cea7767 --- /dev/null +++ b/lib/doc/efun/all/export_uid @@ -0,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 --git a/lib/doc/efun/all/external_start b/lib/doc/efun/all/external_start new file mode 100644 index 0000000..2a8d2d1 --- /dev/null +++ b/lib/doc/efun/all/external_start @@ -0,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 --git a/lib/doc/efun/all/fetch_variable b/lib/doc/efun/all/fetch_variable new file mode 100644 index 0000000..364dd33 --- /dev/null +++ b/lib/doc/efun/all/fetch_variable @@ -0,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 --git a/lib/doc/efun/all/file_length b/lib/doc/efun/all/file_length new file mode 100644 index 0000000..6ea04d7 --- /dev/null +++ b/lib/doc/efun/all/file_length @@ -0,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 --git a/lib/doc/efun/all/file_name b/lib/doc/efun/all/file_name new file mode 100644 index 0000000..903e3bc --- /dev/null +++ b/lib/doc/efun/all/file_name @@ -0,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 --git a/lib/doc/efun/all/file_size b/lib/doc/efun/all/file_size new file mode 100644 index 0000000..b53b38e --- /dev/null +++ b/lib/doc/efun/all/file_size @@ -0,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 --git a/lib/doc/efun/all/filter b/lib/doc/efun/all/filter new file mode 100644 index 0000000..cb78de9 --- /dev/null +++ b/lib/doc/efun/all/filter @@ -0,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 --git a/lib/doc/efun/all/filter_array b/lib/doc/efun/all/filter_array new file mode 100644 index 0000000..d6339ea --- /dev/null +++ b/lib/doc/efun/all/filter_array @@ -0,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 --git a/lib/doc/efun/all/filter_mapping b/lib/doc/efun/all/filter_mapping new file mode 100644 index 0000000..7545461 --- /dev/null +++ b/lib/doc/efun/all/filter_mapping @@ -0,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 --git a/lib/doc/efun/all/find_call_out b/lib/doc/efun/all/find_call_out new file mode 100644 index 0000000..58b3268 --- /dev/null +++ b/lib/doc/efun/all/find_call_out @@ -0,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 --git a/lib/doc/efun/all/find_living b/lib/doc/efun/all/find_living new file mode 100644 index 0000000..58d024c --- /dev/null +++ b/lib/doc/efun/all/find_living @@ -0,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 --git a/lib/doc/efun/all/find_object b/lib/doc/efun/all/find_object new file mode 100644 index 0000000..179a4f6 --- /dev/null +++ b/lib/doc/efun/all/find_object @@ -0,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 --git a/lib/doc/efun/all/find_player b/lib/doc/efun/all/find_player new file mode 100644 index 0000000..c02b43f --- /dev/null +++ b/lib/doc/efun/all/find_player @@ -0,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 --git a/lib/doc/efun/all/first_inventory b/lib/doc/efun/all/first_inventory new file mode 100644 index 0000000..6a069bc --- /dev/null +++ b/lib/doc/efun/all/first_inventory @@ -0,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 --git a/lib/doc/efun/all/floatp b/lib/doc/efun/all/floatp new file mode 100644 index 0000000..e130685 --- /dev/null +++ b/lib/doc/efun/all/floatp @@ -0,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 --git a/lib/doc/efun/all/floor b/lib/doc/efun/all/floor new file mode 100644 index 0000000..3a97c28 --- /dev/null +++ b/lib/doc/efun/all/floor @@ -0,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 --git a/lib/doc/efun/all/flush_messages b/lib/doc/efun/all/flush_messages new file mode 100644 index 0000000..6fd0c4b --- /dev/null +++ b/lib/doc/efun/all/flush_messages @@ -0,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 --git a/lib/doc/efun/all/function_exists b/lib/doc/efun/all/function_exists new file mode 100644 index 0000000..917d097 --- /dev/null +++ b/lib/doc/efun/all/function_exists @@ -0,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 --git a/lib/doc/efun/all/function_owner b/lib/doc/efun/all/function_owner new file mode 100644 index 0000000..d5a8aff --- /dev/null +++ b/lib/doc/efun/all/function_owner @@ -0,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 --git a/lib/doc/efun/all/function_profile b/lib/doc/efun/all/function_profile new file mode 100644 index 0000000..c68822c --- /dev/null +++ b/lib/doc/efun/all/function_profile @@ -0,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 --git a/lib/doc/efun/all/functionp b/lib/doc/efun/all/functionp new file mode 100644 index 0000000..2a9252e --- /dev/null +++ b/lib/doc/efun/all/functionp @@ -0,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 --git a/lib/doc/efun/all/functions b/lib/doc/efun/all/functions new file mode 100644 index 0000000..e6269f0 --- /dev/null +++ b/lib/doc/efun/all/functions @@ -0,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 --git a/lib/doc/efun/all/generate_source b/lib/doc/efun/all/generate_source new file mode 100644 index 0000000..2c7bdda --- /dev/null +++ b/lib/doc/efun/all/generate_source @@ -0,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 --git a/lib/doc/efun/all/get_char b/lib/doc/efun/all/get_char new file mode 100644 index 0000000..ce6617a --- /dev/null +++ b/lib/doc/efun/all/get_char @@ -0,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 --git a/lib/doc/efun/all/get_config b/lib/doc/efun/all/get_config new file mode 100644 index 0000000..517e460 --- /dev/null +++ b/lib/doc/efun/all/get_config @@ -0,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 --git a/lib/doc/efun/all/get_dir b/lib/doc/efun/all/get_dir new file mode 100644 index 0000000..52333f9 --- /dev/null +++ b/lib/doc/efun/all/get_dir @@ -0,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 --git a/lib/doc/efun/all/geteuid b/lib/doc/efun/all/geteuid new file mode 100644 index 0000000..c391017 --- /dev/null +++ b/lib/doc/efun/all/geteuid @@ -0,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 --git a/lib/doc/efun/all/getuid b/lib/doc/efun/all/getuid new file mode 100644 index 0000000..440def6 --- /dev/null +++ b/lib/doc/efun/all/getuid @@ -0,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 --git a/lib/doc/efun/all/heart_beat_info b/lib/doc/efun/all/heart_beat_info new file mode 100644 index 0000000..020c402 --- /dev/null +++ b/lib/doc/efun/all/heart_beat_info @@ -0,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 --git a/lib/doc/efun/all/heart_beats b/lib/doc/efun/all/heart_beats new file mode 100644 index 0000000..01fe319 --- /dev/null +++ b/lib/doc/efun/all/heart_beats @@ -0,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 --git a/lib/doc/efun/all/implode b/lib/doc/efun/all/implode new file mode 100644 index 0000000..cb3e747 --- /dev/null +++ b/lib/doc/efun/all/implode @@ -0,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 --git a/lib/doc/efun/all/in_edit b/lib/doc/efun/all/in_edit new file mode 100644 index 0000000..ffbde34 --- /dev/null +++ b/lib/doc/efun/all/in_edit @@ -0,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 --git a/lib/doc/efun/all/in_input b/lib/doc/efun/all/in_input new file mode 100644 index 0000000..67744e1 --- /dev/null +++ b/lib/doc/efun/all/in_input @@ -0,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 --git a/lib/doc/efun/all/index b/lib/doc/efun/all/index new file mode 100644 index 0000000..415fc25 --- /dev/null +++ b/lib/doc/efun/all/index @@ -0,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 --git a/lib/doc/efun/all/inherit_list b/lib/doc/efun/all/inherit_list new file mode 100644 index 0000000..121ed24 --- /dev/null +++ b/lib/doc/efun/all/inherit_list @@ -0,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 --git a/lib/doc/efun/all/inherits b/lib/doc/efun/all/inherits new file mode 100644 index 0000000..208c313 --- /dev/null +++ b/lib/doc/efun/all/inherits @@ -0,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 --git a/lib/doc/efun/all/input_to b/lib/doc/efun/all/input_to new file mode 100644 index 0000000..439bf11 --- /dev/null +++ b/lib/doc/efun/all/input_to @@ -0,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 --git a/lib/doc/efun/all/interactive b/lib/doc/efun/all/interactive new file mode 100644 index 0000000..709661b --- /dev/null +++ b/lib/doc/efun/all/interactive @@ -0,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 --git a/lib/doc/efun/all/intp b/lib/doc/efun/all/intp new file mode 100644 index 0000000..79be085 --- /dev/null +++ b/lib/doc/efun/all/intp @@ -0,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 --git a/lib/doc/efun/all/keys b/lib/doc/efun/all/keys new file mode 100644 index 0000000..7112245 --- /dev/null +++ b/lib/doc/efun/all/keys @@ -0,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 --git a/lib/doc/efun/all/link b/lib/doc/efun/all/link new file mode 100644 index 0000000..4c894a6 --- /dev/null +++ b/lib/doc/efun/all/link @@ -0,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 --git a/lib/doc/efun/all/living b/lib/doc/efun/all/living new file mode 100644 index 0000000..9325397 --- /dev/null +++ b/lib/doc/efun/all/living @@ -0,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 --git a/lib/doc/efun/all/livings b/lib/doc/efun/all/livings new file mode 100644 index 0000000..edf89de --- /dev/null +++ b/lib/doc/efun/all/livings @@ -0,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 --git a/lib/doc/efun/all/load_object b/lib/doc/efun/all/load_object new file mode 100644 index 0000000..4347aac --- /dev/null +++ b/lib/doc/efun/all/load_object @@ -0,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 --git a/lib/doc/efun/all/localtime b/lib/doc/efun/all/localtime new file mode 100644 index 0000000..982f545 --- /dev/null +++ b/lib/doc/efun/all/localtime @@ -0,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 --git a/lib/doc/efun/all/log b/lib/doc/efun/all/log new file mode 100644 index 0000000..c9258da --- /dev/null +++ b/lib/doc/efun/all/log @@ -0,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 --git a/lib/doc/efun/all/lower_case b/lib/doc/efun/all/lower_case new file mode 100644 index 0000000..c8be581 --- /dev/null +++ b/lib/doc/efun/all/lower_case @@ -0,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 --git a/lib/doc/efun/all/lpc_info b/lib/doc/efun/all/lpc_info new file mode 100644 index 0000000..f60ebed --- /dev/null +++ b/lib/doc/efun/all/lpc_info @@ -0,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 --git a/lib/doc/efun/all/m_delete b/lib/doc/efun/all/m_delete new file mode 100644 index 0000000..2624356 --- /dev/null +++ b/lib/doc/efun/all/m_delete @@ -0,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 --git a/lib/doc/efun/all/m_indices b/lib/doc/efun/all/m_indices new file mode 100644 index 0000000..89bff3c --- /dev/null +++ b/lib/doc/efun/all/m_indices @@ -0,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 --git a/lib/doc/efun/all/m_values b/lib/doc/efun/all/m_values new file mode 100644 index 0000000..a3c3ce5 --- /dev/null +++ b/lib/doc/efun/all/m_values @@ -0,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 --git a/lib/doc/efun/all/malloc_status b/lib/doc/efun/all/malloc_status new file mode 100644 index 0000000..ee10e1c --- /dev/null +++ b/lib/doc/efun/all/malloc_status @@ -0,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 --git a/lib/doc/efun/all/map b/lib/doc/efun/all/map new file mode 100644 index 0000000..c37bcde --- /dev/null +++ b/lib/doc/efun/all/map @@ -0,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 --git a/lib/doc/efun/all/map_array b/lib/doc/efun/all/map_array new file mode 100644 index 0000000..1c9203b --- /dev/null +++ b/lib/doc/efun/all/map_array @@ -0,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 --git a/lib/doc/efun/all/map_delete b/lib/doc/efun/all/map_delete new file mode 100644 index 0000000..3365904 --- /dev/null +++ b/lib/doc/efun/all/map_delete @@ -0,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 --git a/lib/doc/efun/all/map_mapping b/lib/doc/efun/all/map_mapping new file mode 100644 index 0000000..de9c67c --- /dev/null +++ b/lib/doc/efun/all/map_mapping @@ -0,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 --git a/lib/doc/efun/all/mapp b/lib/doc/efun/all/mapp new file mode 100644 index 0000000..32dc980 --- /dev/null +++ b/lib/doc/efun/all/mapp @@ -0,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 --git a/lib/doc/efun/all/master b/lib/doc/efun/all/master new file mode 100644 index 0000000..81013db --- /dev/null +++ b/lib/doc/efun/all/master @@ -0,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 --git a/lib/doc/efun/all/match_path b/lib/doc/efun/all/match_path new file mode 100644 index 0000000..82872c2 --- /dev/null +++ b/lib/doc/efun/all/match_path @@ -0,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 --git a/lib/doc/efun/all/max_eval_cost b/lib/doc/efun/all/max_eval_cost new file mode 100644 index 0000000..91f267c --- /dev/null +++ b/lib/doc/efun/all/max_eval_cost @@ -0,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 --git a/lib/doc/efun/all/member_array b/lib/doc/efun/all/member_array new file mode 100644 index 0000000..8320b17 --- /dev/null +++ b/lib/doc/efun/all/member_array @@ -0,0 +1,13 @@ +member_array - returns index of an occurrence 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 occurrence of `item' in the array or string +`arr', or the first occurrence 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 --git a/lib/doc/efun/all/memory_info b/lib/doc/efun/all/memory_info new file mode 100644 index 0000000..80d54c1 --- /dev/null +++ b/lib/doc/efun/all/memory_info @@ -0,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 --git a/lib/doc/efun/all/memory_summary b/lib/doc/efun/all/memory_summary new file mode 100644 index 0000000..f5c7831 --- /dev/null +++ b/lib/doc/efun/all/memory_summary @@ -0,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 --git a/lib/doc/efun/all/message b/lib/doc/efun/all/message new file mode 100644 index 0000000..191a00b --- /dev/null +++ b/lib/doc/efun/all/message @@ -0,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 --git a/lib/doc/efun/all/mkdir b/lib/doc/efun/all/mkdir new file mode 100644 index 0000000..2d12b1a --- /dev/null +++ b/lib/doc/efun/all/mkdir @@ -0,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 --git a/lib/doc/efun/all/move_object b/lib/doc/efun/all/move_object new file mode 100644 index 0000000..4d852b8 --- /dev/null +++ b/lib/doc/efun/all/move_object @@ -0,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 --git a/lib/doc/efun/all/mud_status b/lib/doc/efun/all/mud_status new file mode 100644 index 0000000..e191a09 --- /dev/null +++ b/lib/doc/efun/all/mud_status @@ -0,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 --git a/lib/doc/efun/all/named_livings b/lib/doc/efun/all/named_livings new file mode 100644 index 0000000..8f37010 --- /dev/null +++ b/lib/doc/efun/all/named_livings @@ -0,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 --git a/lib/doc/efun/all/network_stats b/lib/doc/efun/all/network_stats new file mode 100644 index 0000000..1504ea7 --- /dev/null +++ b/lib/doc/efun/all/network_stats @@ -0,0 +1 @@ +:( diff --git a/lib/doc/efun/all/new b/lib/doc/efun/all/new new file mode 100644 index 0000000..8a21706 --- /dev/null +++ b/lib/doc/efun/all/new @@ -0,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 --git a/lib/doc/efun/all/next_bit b/lib/doc/efun/all/next_bit new file mode 100644 index 0000000..d264573 --- /dev/null +++ b/lib/doc/efun/all/next_bit @@ -0,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 --git a/lib/doc/efun/all/next_inventory b/lib/doc/efun/all/next_inventory new file mode 100644 index 0000000..7ea314d --- /dev/null +++ b/lib/doc/efun/all/next_inventory @@ -0,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 --git a/lib/doc/efun/all/notify_fail b/lib/doc/efun/all/notify_fail new file mode 100644 index 0000000..8a2be88 --- /dev/null +++ b/lib/doc/efun/all/notify_fail @@ -0,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 --git a/lib/doc/efun/all/nullp b/lib/doc/efun/all/nullp new file mode 100644 index 0000000..12d8f8b --- /dev/null +++ b/lib/doc/efun/all/nullp @@ -0,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 --git a/lib/doc/efun/all/objectp b/lib/doc/efun/all/objectp new file mode 100644 index 0000000..a3df08c --- /dev/null +++ b/lib/doc/efun/all/objectp @@ -0,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 --git a/lib/doc/efun/all/objects b/lib/doc/efun/all/objects new file mode 100644 index 0000000..c44d512 --- /dev/null +++ b/lib/doc/efun/all/objects @@ -0,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 --git a/lib/doc/efun/all/opcprof b/lib/doc/efun/all/opcprof new file mode 100644 index 0000000..c0881ee --- /dev/null +++ b/lib/doc/efun/all/opcprof @@ -0,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 --git a/lib/doc/efun/all/origin b/lib/doc/efun/all/origin new file mode 100644 index 0000000..d282b43 --- /dev/null +++ b/lib/doc/efun/all/origin @@ -0,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 --git a/lib/doc/efun/all/pluralize b/lib/doc/efun/all/pluralize new file mode 100644 index 0000000..f8f4c8d --- /dev/null +++ b/lib/doc/efun/all/pluralize @@ -0,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 --git a/lib/doc/efun/all/pointerp b/lib/doc/efun/all/pointerp new file mode 100644 index 0000000..ad49d54 --- /dev/null +++ b/lib/doc/efun/all/pointerp @@ -0,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 --git a/lib/doc/efun/all/pow b/lib/doc/efun/all/pow new file mode 100644 index 0000000..cb97cf4 --- /dev/null +++ b/lib/doc/efun/all/pow @@ -0,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 --git a/lib/doc/efun/all/present b/lib/doc/efun/all/present new file mode 100644 index 0000000..f681707 --- /dev/null +++ b/lib/doc/efun/all/present @@ -0,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 --git a/lib/doc/efun/all/previous_object b/lib/doc/efun/all/previous_object new file mode 100644 index 0000000..668a97e --- /dev/null +++ b/lib/doc/efun/all/previous_object @@ -0,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 --git a/lib/doc/efun/all/printf b/lib/doc/efun/all/printf new file mode 100644 index 0000000..f4bd025 --- /dev/null +++ b/lib/doc/efun/all/printf @@ -0,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 --git a/lib/doc/efun/all/program_info b/lib/doc/efun/all/program_info new file mode 100644 index 0000000..968c4b5 --- /dev/null +++ b/lib/doc/efun/all/program_info @@ -0,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 --git a/lib/doc/efun/all/query_ed_mode b/lib/doc/efun/all/query_ed_mode new file mode 100644 index 0000000..954a187 --- /dev/null +++ b/lib/doc/efun/all/query_ed_mode @@ -0,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 --git a/lib/doc/efun/all/query_heart_beat b/lib/doc/efun/all/query_heart_beat new file mode 100644 index 0000000..8b20192 --- /dev/null +++ b/lib/doc/efun/all/query_heart_beat @@ -0,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 --git a/lib/doc/efun/all/query_host_name b/lib/doc/efun/all/query_host_name new file mode 100644 index 0000000..7149c81 --- /dev/null +++ b/lib/doc/efun/all/query_host_name @@ -0,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 --git a/lib/doc/efun/all/query_idle b/lib/doc/efun/all/query_idle new file mode 100644 index 0000000..328de4a --- /dev/null +++ b/lib/doc/efun/all/query_idle @@ -0,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 --git a/lib/doc/efun/all/query_ip_name b/lib/doc/efun/all/query_ip_name new file mode 100644 index 0000000..621e31e --- /dev/null +++ b/lib/doc/efun/all/query_ip_name @@ -0,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 --git a/lib/doc/efun/all/query_ip_number b/lib/doc/efun/all/query_ip_number new file mode 100644 index 0000000..733964f --- /dev/null +++ b/lib/doc/efun/all/query_ip_number @@ -0,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 --git a/lib/doc/efun/all/query_ip_port b/lib/doc/efun/all/query_ip_port new file mode 100644 index 0000000..4d1d39f --- /dev/null +++ b/lib/doc/efun/all/query_ip_port @@ -0,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 --git a/lib/doc/efun/all/query_load_average b/lib/doc/efun/all/query_load_average new file mode 100644 index 0000000..eca507f --- /dev/null +++ b/lib/doc/efun/all/query_load_average @@ -0,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 --git a/lib/doc/efun/all/query_notify_fail b/lib/doc/efun/all/query_notify_fail new file mode 100644 index 0000000..34eb90a --- /dev/null +++ b/lib/doc/efun/all/query_notify_fail @@ -0,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 --git a/lib/doc/efun/all/query_num b/lib/doc/efun/all/query_num new file mode 100644 index 0000000..1504ea7 --- /dev/null +++ b/lib/doc/efun/all/query_num @@ -0,0 +1 @@ +:( diff --git a/lib/doc/efun/all/query_privs b/lib/doc/efun/all/query_privs new file mode 100644 index 0000000..d89005c --- /dev/null +++ b/lib/doc/efun/all/query_privs @@ -0,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 --git a/lib/doc/efun/all/query_shadowing b/lib/doc/efun/all/query_shadowing new file mode 100644 index 0000000..598035d --- /dev/null +++ b/lib/doc/efun/all/query_shadowing @@ -0,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 --git a/lib/doc/efun/all/query_snoop b/lib/doc/efun/all/query_snoop new file mode 100644 index 0000000..bf80caf --- /dev/null +++ b/lib/doc/efun/all/query_snoop @@ -0,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 --git a/lib/doc/efun/all/query_snooping b/lib/doc/efun/all/query_snooping new file mode 100644 index 0000000..9b129a4 --- /dev/null +++ b/lib/doc/efun/all/query_snooping @@ -0,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 --git a/lib/doc/efun/all/query_verb b/lib/doc/efun/all/query_verb new file mode 100644 index 0000000..28e83dd --- /dev/null +++ b/lib/doc/efun/all/query_verb @@ -0,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 --git a/lib/doc/efun/all/random b/lib/doc/efun/all/random new file mode 100644 index 0000000..385ca46 --- /dev/null +++ b/lib/doc/efun/all/random @@ -0,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 --git a/lib/doc/efun/all/read_buffer b/lib/doc/efun/all/read_buffer new file mode 100644 index 0000000..202bb05 --- /dev/null +++ b/lib/doc/efun/all/read_buffer @@ -0,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 --git a/lib/doc/efun/all/read_bytes b/lib/doc/efun/all/read_bytes new file mode 100644 index 0000000..cbf2e79 --- /dev/null +++ b/lib/doc/efun/all/read_bytes @@ -0,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 --git a/lib/doc/efun/all/read_file b/lib/doc/efun/all/read_file new file mode 100644 index 0000000..1d77c76 --- /dev/null +++ b/lib/doc/efun/all/read_file @@ -0,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 --git a/lib/doc/efun/all/receive b/lib/doc/efun/all/receive new file mode 100644 index 0000000..e075a42 --- /dev/null +++ b/lib/doc/efun/all/receive @@ -0,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 --git a/lib/doc/efun/all/reclaim_objects b/lib/doc/efun/all/reclaim_objects new file mode 100644 index 0000000..5b14db4 --- /dev/null +++ b/lib/doc/efun/all/reclaim_objects @@ -0,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 --git a/lib/doc/efun/all/refs b/lib/doc/efun/all/refs new file mode 100644 index 0000000..aa459f6 --- /dev/null +++ b/lib/doc/efun/all/refs @@ -0,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 --git a/lib/doc/efun/all/reg_assoc b/lib/doc/efun/all/reg_assoc new file mode 100644 index 0000000..b536851 --- /dev/null +++ b/lib/doc/efun/all/reg_assoc @@ -0,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 --git a/lib/doc/efun/all/regexp b/lib/doc/efun/all/regexp new file mode 100644 index 0000000..8faf973 --- /dev/null +++ b/lib/doc/efun/all/regexp @@ -0,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 --git a/lib/doc/efun/all/reload_object b/lib/doc/efun/all/reload_object new file mode 100644 index 0000000..32c2dd8 --- /dev/null +++ b/lib/doc/efun/all/reload_object @@ -0,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 --git a/lib/doc/efun/all/remove_action b/lib/doc/efun/all/remove_action new file mode 100644 index 0000000..b8e3ece --- /dev/null +++ b/lib/doc/efun/all/remove_action @@ -0,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 --git a/lib/doc/efun/all/remove_call_out b/lib/doc/efun/all/remove_call_out new file mode 100644 index 0000000..7c566da --- /dev/null +++ b/lib/doc/efun/all/remove_call_out @@ -0,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 --git a/lib/doc/efun/all/remove_interactive b/lib/doc/efun/all/remove_interactive new file mode 100644 index 0000000..f78cc76 --- /dev/null +++ b/lib/doc/efun/all/remove_interactive @@ -0,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 --git a/lib/doc/efun/all/remove_shadow b/lib/doc/efun/all/remove_shadow new file mode 100644 index 0000000..3fb93cf --- /dev/null +++ b/lib/doc/efun/all/remove_shadow @@ -0,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 --git a/lib/doc/efun/all/rename b/lib/doc/efun/all/rename new file mode 100644 index 0000000..a8ddeae --- /dev/null +++ b/lib/doc/efun/all/rename @@ -0,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 --git a/lib/doc/efun/all/repeat_string b/lib/doc/efun/all/repeat_string new file mode 100644 index 0000000..414edcb --- /dev/null +++ b/lib/doc/efun/all/repeat_string @@ -0,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 --git a/lib/doc/efun/all/replace_program b/lib/doc/efun/all/replace_program new file mode 100644 index 0000000..9d565eb --- /dev/null +++ b/lib/doc/efun/all/replace_program @@ -0,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 --git a/lib/doc/efun/all/replace_string b/lib/doc/efun/all/replace_string new file mode 100644 index 0000000..58a47d9 --- /dev/null +++ b/lib/doc/efun/all/replace_string @@ -0,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 --git a/lib/doc/efun/all/replaceable b/lib/doc/efun/all/replaceable new file mode 100644 index 0000000..5ba9046 --- /dev/null +++ b/lib/doc/efun/all/replaceable @@ -0,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 --git a/lib/doc/efun/all/reset_eval_cost b/lib/doc/efun/all/reset_eval_cost new file mode 100644 index 0000000..c2aacbd --- /dev/null +++ b/lib/doc/efun/all/reset_eval_cost @@ -0,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 --git a/lib/doc/efun/all/resolve b/lib/doc/efun/all/resolve new file mode 100644 index 0000000..a69bd57 --- /dev/null +++ b/lib/doc/efun/all/resolve @@ -0,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 --git a/lib/doc/efun/all/restore_object b/lib/doc/efun/all/restore_object new file mode 100644 index 0000000..801d42f --- /dev/null +++ b/lib/doc/efun/all/restore_object @@ -0,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 --git a/lib/doc/efun/all/restore_variable b/lib/doc/efun/all/restore_variable new file mode 100644 index 0000000..5b49cf2 --- /dev/null +++ b/lib/doc/efun/all/restore_variable @@ -0,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 --git a/lib/doc/efun/all/rm b/lib/doc/efun/all/rm new file mode 100644 index 0000000..ae1f627 --- /dev/null +++ b/lib/doc/efun/all/rm @@ -0,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 --git a/lib/doc/efun/all/rmdir b/lib/doc/efun/all/rmdir new file mode 100644 index 0000000..138293d --- /dev/null +++ b/lib/doc/efun/all/rmdir @@ -0,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 --git a/lib/doc/efun/all/rusage b/lib/doc/efun/all/rusage new file mode 100644 index 0000000..14d2ec4 --- /dev/null +++ b/lib/doc/efun/all/rusage @@ -0,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 --git a/lib/doc/efun/all/save_object b/lib/doc/efun/all/save_object new file mode 100644 index 0000000..1f5d01f --- /dev/null +++ b/lib/doc/efun/all/save_object @@ -0,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 --git a/lib/doc/efun/all/save_variable b/lib/doc/efun/all/save_variable new file mode 100644 index 0000000..95b4f93 --- /dev/null +++ b/lib/doc/efun/all/save_variable @@ -0,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 --git a/lib/doc/efun/all/say b/lib/doc/efun/all/say new file mode 100644 index 0000000..8c06e5c --- /dev/null +++ b/lib/doc/efun/all/say @@ -0,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 --git a/lib/doc/efun/all/set_author b/lib/doc/efun/all/set_author new file mode 100644 index 0000000..eab4f05 --- /dev/null +++ b/lib/doc/efun/all/set_author @@ -0,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 --git a/lib/doc/efun/all/set_bit b/lib/doc/efun/all/set_bit new file mode 100644 index 0000000..cc01cbf --- /dev/null +++ b/lib/doc/efun/all/set_bit @@ -0,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 --git a/lib/doc/efun/all/set_debug_level b/lib/doc/efun/all/set_debug_level new file mode 100644 index 0000000..4839b92 --- /dev/null +++ b/lib/doc/efun/all/set_debug_level @@ -0,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 --git a/lib/doc/efun/all/set_eval_limit b/lib/doc/efun/all/set_eval_limit new file mode 100644 index 0000000..d89171b --- /dev/null +++ b/lib/doc/efun/all/set_eval_limit @@ -0,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 --git a/lib/doc/efun/all/set_heart_beat b/lib/doc/efun/all/set_heart_beat new file mode 100644 index 0000000..eec5f94 --- /dev/null +++ b/lib/doc/efun/all/set_heart_beat @@ -0,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 --git a/lib/doc/efun/all/set_hide b/lib/doc/efun/all/set_hide new file mode 100644 index 0000000..56be518 --- /dev/null +++ b/lib/doc/efun/all/set_hide @@ -0,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 --git a/lib/doc/efun/all/set_light b/lib/doc/efun/all/set_light new file mode 100644 index 0000000..f014e7d --- /dev/null +++ b/lib/doc/efun/all/set_light @@ -0,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 --git a/lib/doc/efun/all/set_living_name b/lib/doc/efun/all/set_living_name new file mode 100644 index 0000000..e04cf18 --- /dev/null +++ b/lib/doc/efun/all/set_living_name @@ -0,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 --git a/lib/doc/efun/all/set_malloc_mask b/lib/doc/efun/all/set_malloc_mask new file mode 100644 index 0000000..a269d06 --- /dev/null +++ b/lib/doc/efun/all/set_malloc_mask @@ -0,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 --git a/lib/doc/efun/all/set_privs b/lib/doc/efun/all/set_privs new file mode 100644 index 0000000..899f9b0 --- /dev/null +++ b/lib/doc/efun/all/set_privs @@ -0,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 --git a/lib/doc/efun/all/set_reset b/lib/doc/efun/all/set_reset new file mode 100644 index 0000000..448f6f3 --- /dev/null +++ b/lib/doc/efun/all/set_reset @@ -0,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 --git a/lib/doc/efun/all/set_this_player b/lib/doc/efun/all/set_this_player new file mode 100644 index 0000000..45f5af4 --- /dev/null +++ b/lib/doc/efun/all/set_this_player @@ -0,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 --git a/lib/doc/efun/all/seteuid b/lib/doc/efun/all/seteuid new file mode 100644 index 0000000..03fe383 --- /dev/null +++ b/lib/doc/efun/all/seteuid @@ -0,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 --git a/lib/doc/efun/all/shadow b/lib/doc/efun/all/shadow new file mode 100644 index 0000000..0920f2b --- /dev/null +++ b/lib/doc/efun/all/shadow @@ -0,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 --git a/lib/doc/efun/all/shallow_inherit_list b/lib/doc/efun/all/shallow_inherit_list new file mode 100644 index 0000000..4a96e80 --- /dev/null +++ b/lib/doc/efun/all/shallow_inherit_list @@ -0,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 --git a/lib/doc/efun/all/shout b/lib/doc/efun/all/shout new file mode 100644 index 0000000..da7e9e2 --- /dev/null +++ b/lib/doc/efun/all/shout @@ -0,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 --git a/lib/doc/efun/all/shutdown b/lib/doc/efun/all/shutdown new file mode 100644 index 0000000..8451328 --- /dev/null +++ b/lib/doc/efun/all/shutdown @@ -0,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 --git a/lib/doc/efun/all/sin b/lib/doc/efun/all/sin new file mode 100644 index 0000000..5459de7 --- /dev/null +++ b/lib/doc/efun/all/sin @@ -0,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 --git a/lib/doc/efun/all/sizeof b/lib/doc/efun/all/sizeof new file mode 100644 index 0000000..2f29d24 --- /dev/null +++ b/lib/doc/efun/all/sizeof @@ -0,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 --git a/lib/doc/efun/all/snoop b/lib/doc/efun/all/snoop new file mode 100644 index 0000000..cc7d897 --- /dev/null +++ b/lib/doc/efun/all/snoop @@ -0,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 --git a/lib/doc/efun/all/socket_accept b/lib/doc/efun/all/socket_accept new file mode 100644 index 0000000..31ad9d1 --- /dev/null +++ b/lib/doc/efun/all/socket_accept @@ -0,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 --git a/lib/doc/efun/all/socket_acquire b/lib/doc/efun/all/socket_acquire new file mode 100644 index 0000000..9c5f666 --- /dev/null +++ b/lib/doc/efun/all/socket_acquire @@ -0,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 --git a/lib/doc/efun/all/socket_address b/lib/doc/efun/all/socket_address new file mode 100644 index 0000000..0639913 --- /dev/null +++ b/lib/doc/efun/all/socket_address @@ -0,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 --git a/lib/doc/efun/all/socket_bind b/lib/doc/efun/all/socket_bind new file mode 100644 index 0000000..7d6dad8 --- /dev/null +++ b/lib/doc/efun/all/socket_bind @@ -0,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 --git a/lib/doc/efun/all/socket_close b/lib/doc/efun/all/socket_close new file mode 100644 index 0000000..aed6139 --- /dev/null +++ b/lib/doc/efun/all/socket_close @@ -0,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 --git a/lib/doc/efun/all/socket_connect b/lib/doc/efun/all/socket_connect new file mode 100644 index 0000000..b24a966 --- /dev/null +++ b/lib/doc/efun/all/socket_connect @@ -0,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 --git a/lib/doc/efun/all/socket_create b/lib/doc/efun/all/socket_create new file mode 100644 index 0000000..7e5b21e --- /dev/null +++ b/lib/doc/efun/all/socket_create @@ -0,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 --git a/lib/doc/efun/all/socket_error b/lib/doc/efun/all/socket_error new file mode 100644 index 0000000..a9d1fe6 --- /dev/null +++ b/lib/doc/efun/all/socket_error @@ -0,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 --git a/lib/doc/efun/all/socket_error.h b/lib/doc/efun/all/socket_error.h new file mode 100644 index 0000000..e69de29 diff --git a/lib/doc/efun/all/socket_listen b/lib/doc/efun/all/socket_listen new file mode 100644 index 0000000..6f9b900 --- /dev/null +++ b/lib/doc/efun/all/socket_listen @@ -0,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 --git a/lib/doc/efun/all/socket_release b/lib/doc/efun/all/socket_release new file mode 100644 index 0000000..2b2dc16 --- /dev/null +++ b/lib/doc/efun/all/socket_release @@ -0,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 --git a/lib/doc/efun/all/socket_write b/lib/doc/efun/all/socket_write new file mode 100644 index 0000000..48a2da1 --- /dev/null +++ b/lib/doc/efun/all/socket_write @@ -0,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 --git a/lib/doc/efun/all/sort_array b/lib/doc/efun/all/sort_array new file mode 100644 index 0000000..75bf2f1 --- /dev/null +++ b/lib/doc/efun/all/sort_array @@ -0,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 --git a/lib/doc/efun/all/sprintf b/lib/doc/efun/all/sprintf new file mode 100644 index 0000000..60d5c60 --- /dev/null +++ b/lib/doc/efun/all/sprintf @@ -0,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 --git a/lib/doc/efun/all/sqrt b/lib/doc/efun/all/sqrt new file mode 100644 index 0000000..79e4941 --- /dev/null +++ b/lib/doc/efun/all/sqrt @@ -0,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 --git a/lib/doc/efun/all/sscanf b/lib/doc/efun/all/sscanf new file mode 100644 index 0000000..14f6733 --- /dev/null +++ b/lib/doc/efun/all/sscanf @@ -0,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 --git a/lib/doc/efun/all/stat b/lib/doc/efun/all/stat new file mode 100644 index 0000000..9b11b7a --- /dev/null +++ b/lib/doc/efun/all/stat @@ -0,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 --git a/lib/doc/efun/all/store_variable b/lib/doc/efun/all/store_variable new file mode 100644 index 0000000..f1130f4 --- /dev/null +++ b/lib/doc/efun/all/store_variable @@ -0,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 --git a/lib/doc/efun/all/strcmp b/lib/doc/efun/all/strcmp new file mode 100644 index 0000000..0d2c445 --- /dev/null +++ b/lib/doc/efun/all/strcmp @@ -0,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 --git a/lib/doc/efun/all/stringp b/lib/doc/efun/all/stringp new file mode 100644 index 0000000..91d414e --- /dev/null +++ b/lib/doc/efun/all/stringp @@ -0,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 --git a/lib/doc/efun/all/strlen b/lib/doc/efun/all/strlen new file mode 100644 index 0000000..31115c6 --- /dev/null +++ b/lib/doc/efun/all/strlen @@ -0,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 --git a/lib/doc/efun/all/strsrch b/lib/doc/efun/all/strsrch new file mode 100644 index 0000000..8d63db9 --- /dev/null +++ b/lib/doc/efun/all/strsrch @@ -0,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 --git a/lib/doc/efun/all/swap b/lib/doc/efun/all/swap new file mode 100644 index 0000000..6aecd7e --- /dev/null +++ b/lib/doc/efun/all/swap @@ -0,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 --git a/lib/doc/efun/all/tail b/lib/doc/efun/all/tail new file mode 100644 index 0000000..b84e8cf --- /dev/null +++ b/lib/doc/efun/all/tail @@ -0,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 --git a/lib/doc/efun/all/tan b/lib/doc/efun/all/tan new file mode 100644 index 0000000..379efbe --- /dev/null +++ b/lib/doc/efun/all/tan @@ -0,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 --git a/lib/doc/efun/all/tell_object b/lib/doc/efun/all/tell_object new file mode 100644 index 0000000..3820bfc --- /dev/null +++ b/lib/doc/efun/all/tell_object @@ -0,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 --git a/lib/doc/efun/all/tell_room b/lib/doc/efun/all/tell_room new file mode 100644 index 0000000..e8b8a4a --- /dev/null +++ b/lib/doc/efun/all/tell_room @@ -0,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 --git a/lib/doc/efun/all/terminal_colour b/lib/doc/efun/all/terminal_colour new file mode 100644 index 0000000..977dc00 --- /dev/null +++ b/lib/doc/efun/all/terminal_colour @@ -0,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 --git a/lib/doc/efun/all/test_bit b/lib/doc/efun/all/test_bit new file mode 100644 index 0000000..367cfaf --- /dev/null +++ b/lib/doc/efun/all/test_bit @@ -0,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 --git a/lib/doc/efun/all/this_interactive b/lib/doc/efun/all/this_interactive new file mode 100644 index 0000000..73450f8 --- /dev/null +++ b/lib/doc/efun/all/this_interactive @@ -0,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 --git a/lib/doc/efun/all/this_object b/lib/doc/efun/all/this_object new file mode 100644 index 0000000..da57055 --- /dev/null +++ b/lib/doc/efun/all/this_object @@ -0,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 --git a/lib/doc/efun/all/this_player b/lib/doc/efun/all/this_player new file mode 100644 index 0000000..bec4953 --- /dev/null +++ b/lib/doc/efun/all/this_player @@ -0,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 --git a/lib/doc/efun/all/this_user b/lib/doc/efun/all/this_user new file mode 100644 index 0000000..e13dd0e --- /dev/null +++ b/lib/doc/efun/all/this_user @@ -0,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 --git a/lib/doc/efun/all/throw b/lib/doc/efun/all/throw new file mode 100644 index 0000000..a6895d3 --- /dev/null +++ b/lib/doc/efun/all/throw @@ -0,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 --git a/lib/doc/efun/all/time b/lib/doc/efun/all/time new file mode 100644 index 0000000..5fa4ed2 --- /dev/null +++ b/lib/doc/efun/all/time @@ -0,0 +1,13 @@ +time - return the number of seconds since January 1 1970 + +int time( void ); + +Return the number of seconds since midnight (GMT) January 1, 1970. + +See also: + ctime, + localtime, + time_expression, + uptime + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff --git a/lib/doc/efun/all/time_expression b/lib/doc/efun/all/time_expression new file mode 100644 index 0000000..7fdcf3a --- /dev/null +++ b/lib/doc/efun/all/time_expression @@ -0,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 --git a/lib/doc/efun/all/to_float b/lib/doc/efun/all/to_float new file mode 100644 index 0000000..6bb8c68 --- /dev/null +++ b/lib/doc/efun/all/to_float @@ -0,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 --git a/lib/doc/efun/all/to_int b/lib/doc/efun/all/to_int new file mode 100644 index 0000000..7cf9707 --- /dev/null +++ b/lib/doc/efun/all/to_int @@ -0,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 --git a/lib/doc/efun/all/trace b/lib/doc/efun/all/trace new file mode 100644 index 0000000..f1fc148 --- /dev/null +++ b/lib/doc/efun/all/trace @@ -0,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 --git a/lib/doc/efun/all/traceprefix b/lib/doc/efun/all/traceprefix new file mode 100644 index 0000000..f61362b --- /dev/null +++ b/lib/doc/efun/all/traceprefix @@ -0,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 --git a/lib/doc/efun/all/typeof b/lib/doc/efun/all/typeof new file mode 100644 index 0000000..30a5336 --- /dev/null +++ b/lib/doc/efun/all/typeof @@ -0,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 --git a/lib/doc/efun/all/undefinedp b/lib/doc/efun/all/undefinedp new file mode 100644 index 0000000..5ee39c9 --- /dev/null +++ b/lib/doc/efun/all/undefinedp @@ -0,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 --git a/lib/doc/efun/all/unique_array b/lib/doc/efun/all/unique_array new file mode 100644 index 0000000..f4e8c91 --- /dev/null +++ b/lib/doc/efun/all/unique_array @@ -0,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 --git a/lib/doc/efun/all/unique_mapping b/lib/doc/efun/all/unique_mapping new file mode 100644 index 0000000..7f8d44a --- /dev/null +++ b/lib/doc/efun/all/unique_mapping @@ -0,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 --git a/lib/doc/efun/all/upper_case b/lib/doc/efun/all/upper_case new file mode 100644 index 0000000..943eeab --- /dev/null +++ b/lib/doc/efun/all/upper_case @@ -0,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 --git a/lib/doc/efun/all/uptime b/lib/doc/efun/all/uptime new file mode 100644 index 0000000..b5ffbdd --- /dev/null +++ b/lib/doc/efun/all/uptime @@ -0,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 --git a/lib/doc/efun/all/userp b/lib/doc/efun/all/userp new file mode 100644 index 0000000..0fa0bfc --- /dev/null +++ b/lib/doc/efun/all/userp @@ -0,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 --git a/lib/doc/efun/all/users b/lib/doc/efun/all/users new file mode 100644 index 0000000..9a9d722 --- /dev/null +++ b/lib/doc/efun/all/users @@ -0,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 --git a/lib/doc/efun/all/values b/lib/doc/efun/all/values new file mode 100644 index 0000000..5f7e0e9 --- /dev/null +++ b/lib/doc/efun/all/values @@ -0,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 --git a/lib/doc/efun/all/variables b/lib/doc/efun/all/variables new file mode 100644 index 0000000..a283ced --- /dev/null +++ b/lib/doc/efun/all/variables @@ -0,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 --git a/lib/doc/efun/all/virtualp b/lib/doc/efun/all/virtualp new file mode 100644 index 0000000..13b7a0e --- /dev/null +++ b/lib/doc/efun/all/virtualp @@ -0,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 --git a/lib/doc/efun/all/wizardp b/lib/doc/efun/all/wizardp new file mode 100644 index 0000000..d8d5b11 --- /dev/null +++ b/lib/doc/efun/all/wizardp @@ -0,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 --git a/lib/doc/efun/all/write b/lib/doc/efun/all/write new file mode 100644 index 0000000..5c64033 --- /dev/null +++ b/lib/doc/efun/all/write @@ -0,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 --git a/lib/doc/efun/all/write_buffer b/lib/doc/efun/all/write_buffer new file mode 100644 index 0000000..8ced517 --- /dev/null +++ b/lib/doc/efun/all/write_buffer @@ -0,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 --git a/lib/doc/efun/all/write_bytes b/lib/doc/efun/all/write_bytes new file mode 100644 index 0000000..cbf75ea --- /dev/null +++ b/lib/doc/efun/all/write_bytes @@ -0,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 --git a/lib/doc/efun/all/write_file b/lib/doc/efun/all/write_file new file mode 100644 index 0000000..f7b8241 --- /dev/null +++ b/lib/doc/efun/all/write_file @@ -0,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 --git a/lib/doc/efun/arrays/allocate b/lib/doc/efun/arrays/allocate new file mode 100644 index 0000000..227cd3a --- /dev/null +++ b/lib/doc/efun/arrays/allocate @@ -0,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 --git a/lib/doc/efun/arrays/filter_array b/lib/doc/efun/arrays/filter_array new file mode 100644 index 0000000..d6339ea --- /dev/null +++ b/lib/doc/efun/arrays/filter_array @@ -0,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 --git a/lib/doc/efun/arrays/index b/lib/doc/efun/arrays/index new file mode 100644 index 0000000..5abf61a --- /dev/null +++ b/lib/doc/efun/arrays/index @@ -0,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 --git a/lib/doc/efun/arrays/map_array b/lib/doc/efun/arrays/map_array new file mode 100644 index 0000000..1c9203b --- /dev/null +++ b/lib/doc/efun/arrays/map_array @@ -0,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 --git a/lib/doc/efun/arrays/member_array b/lib/doc/efun/arrays/member_array new file mode 100644 index 0000000..8320b17 --- /dev/null +++ b/lib/doc/efun/arrays/member_array @@ -0,0 +1,13 @@ +member_array - returns index of an occurrence 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 occurrence of `item' in the array or string +`arr', or the first occurrence 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 --git a/lib/doc/efun/arrays/sort_array b/lib/doc/efun/arrays/sort_array new file mode 100644 index 0000000..75bf2f1 --- /dev/null +++ b/lib/doc/efun/arrays/sort_array @@ -0,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 --git a/lib/doc/efun/arrays/unique_array b/lib/doc/efun/arrays/unique_array new file mode 100644 index 0000000..f4e8c91 --- /dev/null +++ b/lib/doc/efun/arrays/unique_array @@ -0,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 --git a/lib/doc/efun/buffers/allocate_buffer b/lib/doc/efun/buffers/allocate_buffer new file mode 100644 index 0000000..1f30d2c --- /dev/null +++ b/lib/doc/efun/buffers/allocate_buffer @@ -0,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 --git a/lib/doc/efun/buffers/crc32 b/lib/doc/efun/buffers/crc32 new file mode 100644 index 0000000..b0a190a --- /dev/null +++ b/lib/doc/efun/buffers/crc32 @@ -0,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 --git a/lib/doc/efun/buffers/index b/lib/doc/efun/buffers/index new file mode 100644 index 0000000..175c712 --- /dev/null +++ b/lib/doc/efun/buffers/index @@ -0,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 --git a/lib/doc/efun/buffers/read_buffer b/lib/doc/efun/buffers/read_buffer new file mode 100644 index 0000000..202bb05 --- /dev/null +++ b/lib/doc/efun/buffers/read_buffer @@ -0,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 --git a/lib/doc/efun/buffers/write_buffer b/lib/doc/efun/buffers/write_buffer new file mode 100644 index 0000000..8ced517 --- /dev/null +++ b/lib/doc/efun/buffers/write_buffer @@ -0,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 --git a/lib/doc/efun/calls/call_other b/lib/doc/efun/calls/call_other new file mode 100644 index 0000000..9b66bb0 --- /dev/null +++ b/lib/doc/efun/calls/call_other @@ -0,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 --git a/lib/doc/efun/calls/call_out b/lib/doc/efun/calls/call_out new file mode 100644 index 0000000..3ed9f3c --- /dev/null +++ b/lib/doc/efun/calls/call_out @@ -0,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 --git a/lib/doc/efun/calls/call_stack b/lib/doc/efun/calls/call_stack new file mode 100644 index 0000000..081c3b6 --- /dev/null +++ b/lib/doc/efun/calls/call_stack @@ -0,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 --git a/lib/doc/efun/calls/catch b/lib/doc/efun/calls/catch new file mode 100644 index 0000000..f47877e --- /dev/null +++ b/lib/doc/efun/calls/catch @@ -0,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 --git a/lib/doc/efun/calls/index b/lib/doc/efun/calls/index new file mode 100644 index 0000000..716c429 --- /dev/null +++ b/lib/doc/efun/calls/index @@ -0,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 --git a/lib/doc/efun/calls/origin b/lib/doc/efun/calls/origin new file mode 100644 index 0000000..d282b43 --- /dev/null +++ b/lib/doc/efun/calls/origin @@ -0,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 --git a/lib/doc/efun/calls/previous_object b/lib/doc/efun/calls/previous_object new file mode 100644 index 0000000..668a97e --- /dev/null +++ b/lib/doc/efun/calls/previous_object @@ -0,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 --git a/lib/doc/efun/calls/query_shadowing b/lib/doc/efun/calls/query_shadowing new file mode 100644 index 0000000..598035d --- /dev/null +++ b/lib/doc/efun/calls/query_shadowing @@ -0,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 --git a/lib/doc/efun/calls/remove_call_out b/lib/doc/efun/calls/remove_call_out new file mode 100644 index 0000000..7c566da --- /dev/null +++ b/lib/doc/efun/calls/remove_call_out @@ -0,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 --git a/lib/doc/efun/calls/remove_shadow b/lib/doc/efun/calls/remove_shadow new file mode 100644 index 0000000..3fb93cf --- /dev/null +++ b/lib/doc/efun/calls/remove_shadow @@ -0,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 --git a/lib/doc/efun/calls/shadow b/lib/doc/efun/calls/shadow new file mode 100644 index 0000000..0920f2b --- /dev/null +++ b/lib/doc/efun/calls/shadow @@ -0,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 --git a/lib/doc/efun/calls/this_object b/lib/doc/efun/calls/this_object new file mode 100644 index 0000000..da57055 --- /dev/null +++ b/lib/doc/efun/calls/this_object @@ -0,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 --git a/lib/doc/efun/calls/throw b/lib/doc/efun/calls/throw new file mode 100644 index 0000000..a6895d3 --- /dev/null +++ b/lib/doc/efun/calls/throw @@ -0,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 --git a/lib/doc/efun/compile/generate_source b/lib/doc/efun/compile/generate_source new file mode 100644 index 0000000..2c7bdda --- /dev/null +++ b/lib/doc/efun/compile/generate_source @@ -0,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 --git a/lib/doc/efun/compile/index b/lib/doc/efun/compile/index new file mode 100644 index 0000000..2d02036 --- /dev/null +++ b/lib/doc/efun/compile/index @@ -0,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 --git a/lib/doc/efun/filesystem/cp b/lib/doc/efun/filesystem/cp new file mode 100644 index 0000000..f2e4dcf --- /dev/null +++ b/lib/doc/efun/filesystem/cp @@ -0,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 --git a/lib/doc/efun/filesystem/file_length b/lib/doc/efun/filesystem/file_length new file mode 100644 index 0000000..6ea04d7 --- /dev/null +++ b/lib/doc/efun/filesystem/file_length @@ -0,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 --git a/lib/doc/efun/filesystem/file_size b/lib/doc/efun/filesystem/file_size new file mode 100644 index 0000000..b53b38e --- /dev/null +++ b/lib/doc/efun/filesystem/file_size @@ -0,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 --git a/lib/doc/efun/filesystem/get_dir b/lib/doc/efun/filesystem/get_dir new file mode 100644 index 0000000..52333f9 --- /dev/null +++ b/lib/doc/efun/filesystem/get_dir @@ -0,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 --git a/lib/doc/efun/filesystem/index b/lib/doc/efun/filesystem/index new file mode 100644 index 0000000..823e34e --- /dev/null +++ b/lib/doc/efun/filesystem/index @@ -0,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 --git a/lib/doc/efun/filesystem/link b/lib/doc/efun/filesystem/link new file mode 100644 index 0000000..4c894a6 --- /dev/null +++ b/lib/doc/efun/filesystem/link @@ -0,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 --git a/lib/doc/efun/filesystem/mkdir b/lib/doc/efun/filesystem/mkdir new file mode 100644 index 0000000..2d12b1a --- /dev/null +++ b/lib/doc/efun/filesystem/mkdir @@ -0,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 --git a/lib/doc/efun/filesystem/read_bytes b/lib/doc/efun/filesystem/read_bytes new file mode 100644 index 0000000..cbf2e79 --- /dev/null +++ b/lib/doc/efun/filesystem/read_bytes @@ -0,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 --git a/lib/doc/efun/filesystem/read_file b/lib/doc/efun/filesystem/read_file new file mode 100644 index 0000000..1d77c76 --- /dev/null +++ b/lib/doc/efun/filesystem/read_file @@ -0,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 --git a/lib/doc/efun/filesystem/rename b/lib/doc/efun/filesystem/rename new file mode 100644 index 0000000..a8ddeae --- /dev/null +++ b/lib/doc/efun/filesystem/rename @@ -0,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 --git a/lib/doc/efun/filesystem/rm b/lib/doc/efun/filesystem/rm new file mode 100644 index 0000000..ae1f627 --- /dev/null +++ b/lib/doc/efun/filesystem/rm @@ -0,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 --git a/lib/doc/efun/filesystem/rmdir b/lib/doc/efun/filesystem/rmdir new file mode 100644 index 0000000..138293d --- /dev/null +++ b/lib/doc/efun/filesystem/rmdir @@ -0,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 --git a/lib/doc/efun/filesystem/stat b/lib/doc/efun/filesystem/stat new file mode 100644 index 0000000..9b11b7a --- /dev/null +++ b/lib/doc/efun/filesystem/stat @@ -0,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 --git a/lib/doc/efun/filesystem/tail b/lib/doc/efun/filesystem/tail new file mode 100644 index 0000000..b84e8cf --- /dev/null +++ b/lib/doc/efun/filesystem/tail @@ -0,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 --git a/lib/doc/efun/filesystem/write_bytes b/lib/doc/efun/filesystem/write_bytes new file mode 100644 index 0000000..cbf75ea --- /dev/null +++ b/lib/doc/efun/filesystem/write_bytes @@ -0,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 --git a/lib/doc/efun/filesystem/write_file b/lib/doc/efun/filesystem/write_file new file mode 100644 index 0000000..f7b8241 --- /dev/null +++ b/lib/doc/efun/filesystem/write_file @@ -0,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 --git a/lib/doc/efun/floats/acos b/lib/doc/efun/floats/acos new file mode 100644 index 0000000..ac9612a --- /dev/null +++ b/lib/doc/efun/floats/acos @@ -0,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 --git a/lib/doc/efun/floats/asin b/lib/doc/efun/floats/asin new file mode 100644 index 0000000..efb86eb --- /dev/null +++ b/lib/doc/efun/floats/asin @@ -0,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 --git a/lib/doc/efun/floats/atan b/lib/doc/efun/floats/atan new file mode 100644 index 0000000..827c11c --- /dev/null +++ b/lib/doc/efun/floats/atan @@ -0,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 --git a/lib/doc/efun/floats/ceil b/lib/doc/efun/floats/ceil new file mode 100644 index 0000000..8eb05b4 --- /dev/null +++ b/lib/doc/efun/floats/ceil @@ -0,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 --git a/lib/doc/efun/floats/cos b/lib/doc/efun/floats/cos new file mode 100644 index 0000000..3be7040 --- /dev/null +++ b/lib/doc/efun/floats/cos @@ -0,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 --git a/lib/doc/efun/floats/exp b/lib/doc/efun/floats/exp new file mode 100644 index 0000000..f26bebf --- /dev/null +++ b/lib/doc/efun/floats/exp @@ -0,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 --git a/lib/doc/efun/floats/floor b/lib/doc/efun/floats/floor new file mode 100644 index 0000000..3a97c28 --- /dev/null +++ b/lib/doc/efun/floats/floor @@ -0,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 --git a/lib/doc/efun/floats/index b/lib/doc/efun/floats/index new file mode 100644 index 0000000..3de121d --- /dev/null +++ b/lib/doc/efun/floats/index @@ -0,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 --git a/lib/doc/efun/floats/log b/lib/doc/efun/floats/log new file mode 100644 index 0000000..c9258da --- /dev/null +++ b/lib/doc/efun/floats/log @@ -0,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 --git a/lib/doc/efun/floats/pow b/lib/doc/efun/floats/pow new file mode 100644 index 0000000..cb97cf4 --- /dev/null +++ b/lib/doc/efun/floats/pow @@ -0,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 --git a/lib/doc/efun/floats/sin b/lib/doc/efun/floats/sin new file mode 100644 index 0000000..5459de7 --- /dev/null +++ b/lib/doc/efun/floats/sin @@ -0,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 --git a/lib/doc/efun/floats/sqrt b/lib/doc/efun/floats/sqrt new file mode 100644 index 0000000..79e4941 --- /dev/null +++ b/lib/doc/efun/floats/sqrt @@ -0,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 --git a/lib/doc/efun/floats/tan b/lib/doc/efun/floats/tan new file mode 100644 index 0000000..379efbe --- /dev/null +++ b/lib/doc/efun/floats/tan @@ -0,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 --git a/lib/doc/efun/floats/to_int b/lib/doc/efun/floats/to_int new file mode 100644 index 0000000..7cf9707 --- /dev/null +++ b/lib/doc/efun/floats/to_int @@ -0,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 --git a/lib/doc/efun/functions/bind b/lib/doc/efun/functions/bind new file mode 100644 index 0000000..8851231 --- /dev/null +++ b/lib/doc/efun/functions/bind @@ -0,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 --git a/lib/doc/efun/functions/evaluate b/lib/doc/efun/functions/evaluate new file mode 100644 index 0000000..c170c2a --- /dev/null +++ b/lib/doc/efun/functions/evaluate @@ -0,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 --git a/lib/doc/efun/functions/function_owner b/lib/doc/efun/functions/function_owner new file mode 100644 index 0000000..d5a8aff --- /dev/null +++ b/lib/doc/efun/functions/function_owner @@ -0,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 --git a/lib/doc/efun/functions/index b/lib/doc/efun/functions/index new file mode 100644 index 0000000..cd6f491 --- /dev/null +++ b/lib/doc/efun/functions/index @@ -0,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 --git a/lib/doc/efun/general/copy b/lib/doc/efun/general/copy new file mode 100644 index 0000000..cdaa1fc --- /dev/null +++ b/lib/doc/efun/general/copy @@ -0,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 --git a/lib/doc/efun/general/fetch_variable b/lib/doc/efun/general/fetch_variable new file mode 100644 index 0000000..364dd33 --- /dev/null +++ b/lib/doc/efun/general/fetch_variable @@ -0,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 --git a/lib/doc/efun/general/filter b/lib/doc/efun/general/filter new file mode 100644 index 0000000..cb78de9 --- /dev/null +++ b/lib/doc/efun/general/filter @@ -0,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 --git a/lib/doc/efun/general/index b/lib/doc/efun/general/index new file mode 100644 index 0000000..795b0df --- /dev/null +++ b/lib/doc/efun/general/index @@ -0,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 --git a/lib/doc/efun/general/map b/lib/doc/efun/general/map new file mode 100644 index 0000000..c37bcde --- /dev/null +++ b/lib/doc/efun/general/map @@ -0,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 --git a/lib/doc/efun/general/restore_variable b/lib/doc/efun/general/restore_variable new file mode 100644 index 0000000..5b49cf2 --- /dev/null +++ b/lib/doc/efun/general/restore_variable @@ -0,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 --git a/lib/doc/efun/general/save_variable b/lib/doc/efun/general/save_variable new file mode 100644 index 0000000..95b4f93 --- /dev/null +++ b/lib/doc/efun/general/save_variable @@ -0,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 --git a/lib/doc/efun/general/sizeof b/lib/doc/efun/general/sizeof new file mode 100644 index 0000000..2f29d24 --- /dev/null +++ b/lib/doc/efun/general/sizeof @@ -0,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 --git a/lib/doc/efun/general/store_variable b/lib/doc/efun/general/store_variable new file mode 100644 index 0000000..f1130f4 --- /dev/null +++ b/lib/doc/efun/general/store_variable @@ -0,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 --git a/lib/doc/efun/general/typeof b/lib/doc/efun/general/typeof new file mode 100644 index 0000000..30a5336 --- /dev/null +++ b/lib/doc/efun/general/typeof @@ -0,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 --git a/lib/doc/efun/interactive/add_action b/lib/doc/efun/interactive/add_action new file mode 100644 index 0000000..b1a4c4f --- /dev/null +++ b/lib/doc/efun/interactive/add_action @@ -0,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 --git a/lib/doc/efun/interactive/command b/lib/doc/efun/interactive/command new file mode 100644 index 0000000..24ddb40 --- /dev/null +++ b/lib/doc/efun/interactive/command @@ -0,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 --git a/lib/doc/efun/interactive/commands b/lib/doc/efun/interactive/commands new file mode 100644 index 0000000..04df2b4 --- /dev/null +++ b/lib/doc/efun/interactive/commands @@ -0,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 --git a/lib/doc/efun/interactive/disable_commands b/lib/doc/efun/interactive/disable_commands new file mode 100644 index 0000000..185c207 --- /dev/null +++ b/lib/doc/efun/interactive/disable_commands @@ -0,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 --git a/lib/doc/efun/interactive/disable_wizard b/lib/doc/efun/interactive/disable_wizard new file mode 100644 index 0000000..e3b52c4 --- /dev/null +++ b/lib/doc/efun/interactive/disable_wizard @@ -0,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 --git a/lib/doc/efun/interactive/ed b/lib/doc/efun/interactive/ed new file mode 100644 index 0000000..d46c6be --- /dev/null +++ b/lib/doc/efun/interactive/ed @@ -0,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 --git a/lib/doc/efun/interactive/ed_cmd b/lib/doc/efun/interactive/ed_cmd new file mode 100644 index 0000000..d3ae2fd --- /dev/null +++ b/lib/doc/efun/interactive/ed_cmd @@ -0,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 --git a/lib/doc/efun/interactive/ed_start b/lib/doc/efun/interactive/ed_start new file mode 100644 index 0000000..601e316 --- /dev/null +++ b/lib/doc/efun/interactive/ed_start @@ -0,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 --git a/lib/doc/efun/interactive/enable_commands b/lib/doc/efun/interactive/enable_commands new file mode 100644 index 0000000..ec00775 --- /dev/null +++ b/lib/doc/efun/interactive/enable_commands @@ -0,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 --git a/lib/doc/efun/interactive/enable_wizard b/lib/doc/efun/interactive/enable_wizard new file mode 100644 index 0000000..43dd232 --- /dev/null +++ b/lib/doc/efun/interactive/enable_wizard @@ -0,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 --git a/lib/doc/efun/interactive/exec b/lib/doc/efun/interactive/exec new file mode 100644 index 0000000..c17d852 --- /dev/null +++ b/lib/doc/efun/interactive/exec @@ -0,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 --git a/lib/doc/efun/interactive/find_player b/lib/doc/efun/interactive/find_player new file mode 100644 index 0000000..c02b43f --- /dev/null +++ b/lib/doc/efun/interactive/find_player @@ -0,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 --git a/lib/doc/efun/interactive/get_char b/lib/doc/efun/interactive/get_char new file mode 100644 index 0000000..ce6617a --- /dev/null +++ b/lib/doc/efun/interactive/get_char @@ -0,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 --git a/lib/doc/efun/interactive/in_edit b/lib/doc/efun/interactive/in_edit new file mode 100644 index 0000000..ffbde34 --- /dev/null +++ b/lib/doc/efun/interactive/in_edit @@ -0,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 --git a/lib/doc/efun/interactive/in_input b/lib/doc/efun/interactive/in_input new file mode 100644 index 0000000..67744e1 --- /dev/null +++ b/lib/doc/efun/interactive/in_input @@ -0,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 --git a/lib/doc/efun/interactive/index b/lib/doc/efun/interactive/index new file mode 100644 index 0000000..deb11bc --- /dev/null +++ b/lib/doc/efun/interactive/index @@ -0,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 --git a/lib/doc/efun/interactive/input_to b/lib/doc/efun/interactive/input_to new file mode 100644 index 0000000..439bf11 --- /dev/null +++ b/lib/doc/efun/interactive/input_to @@ -0,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 --git a/lib/doc/efun/interactive/interactive b/lib/doc/efun/interactive/interactive new file mode 100644 index 0000000..709661b --- /dev/null +++ b/lib/doc/efun/interactive/interactive @@ -0,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 --git a/lib/doc/efun/interactive/message b/lib/doc/efun/interactive/message new file mode 100644 index 0000000..191a00b --- /dev/null +++ b/lib/doc/efun/interactive/message @@ -0,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 --git a/lib/doc/efun/interactive/notify_fail b/lib/doc/efun/interactive/notify_fail new file mode 100644 index 0000000..8a2be88 --- /dev/null +++ b/lib/doc/efun/interactive/notify_fail @@ -0,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 --git a/lib/doc/efun/interactive/printf b/lib/doc/efun/interactive/printf new file mode 100644 index 0000000..f4bd025 --- /dev/null +++ b/lib/doc/efun/interactive/printf @@ -0,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 --git a/lib/doc/efun/interactive/query_ed_mode b/lib/doc/efun/interactive/query_ed_mode new file mode 100644 index 0000000..954a187 --- /dev/null +++ b/lib/doc/efun/interactive/query_ed_mode @@ -0,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 --git a/lib/doc/efun/interactive/query_host_name b/lib/doc/efun/interactive/query_host_name new file mode 100644 index 0000000..7149c81 --- /dev/null +++ b/lib/doc/efun/interactive/query_host_name @@ -0,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 --git a/lib/doc/efun/interactive/query_idle b/lib/doc/efun/interactive/query_idle new file mode 100644 index 0000000..328de4a --- /dev/null +++ b/lib/doc/efun/interactive/query_idle @@ -0,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 --git a/lib/doc/efun/interactive/query_ip_name b/lib/doc/efun/interactive/query_ip_name new file mode 100644 index 0000000..621e31e --- /dev/null +++ b/lib/doc/efun/interactive/query_ip_name @@ -0,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 --git a/lib/doc/efun/interactive/query_ip_number b/lib/doc/efun/interactive/query_ip_number new file mode 100644 index 0000000..733964f --- /dev/null +++ b/lib/doc/efun/interactive/query_ip_number @@ -0,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 --git a/lib/doc/efun/interactive/query_ip_port b/lib/doc/efun/interactive/query_ip_port new file mode 100644 index 0000000..4d1d39f --- /dev/null +++ b/lib/doc/efun/interactive/query_ip_port @@ -0,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 --git a/lib/doc/efun/interactive/query_notify_fail b/lib/doc/efun/interactive/query_notify_fail new file mode 100644 index 0000000..34eb90a --- /dev/null +++ b/lib/doc/efun/interactive/query_notify_fail @@ -0,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 --git a/lib/doc/efun/interactive/query_snoop b/lib/doc/efun/interactive/query_snoop new file mode 100644 index 0000000..bf80caf --- /dev/null +++ b/lib/doc/efun/interactive/query_snoop @@ -0,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 --git a/lib/doc/efun/interactive/query_snooping b/lib/doc/efun/interactive/query_snooping new file mode 100644 index 0000000..9b129a4 --- /dev/null +++ b/lib/doc/efun/interactive/query_snooping @@ -0,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 --git a/lib/doc/efun/interactive/receive b/lib/doc/efun/interactive/receive new file mode 100644 index 0000000..e075a42 --- /dev/null +++ b/lib/doc/efun/interactive/receive @@ -0,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 --git a/lib/doc/efun/interactive/remove_action b/lib/doc/efun/interactive/remove_action new file mode 100644 index 0000000..b8e3ece --- /dev/null +++ b/lib/doc/efun/interactive/remove_action @@ -0,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 --git a/lib/doc/efun/interactive/remove_interactive b/lib/doc/efun/interactive/remove_interactive new file mode 100644 index 0000000..f78cc76 --- /dev/null +++ b/lib/doc/efun/interactive/remove_interactive @@ -0,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 --git a/lib/doc/efun/interactive/resolve b/lib/doc/efun/interactive/resolve new file mode 100644 index 0000000..a69bd57 --- /dev/null +++ b/lib/doc/efun/interactive/resolve @@ -0,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 --git a/lib/doc/efun/interactive/say b/lib/doc/efun/interactive/say new file mode 100644 index 0000000..8c06e5c --- /dev/null +++ b/lib/doc/efun/interactive/say @@ -0,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 --git a/lib/doc/efun/interactive/set_this_player b/lib/doc/efun/interactive/set_this_player new file mode 100644 index 0000000..45f5af4 --- /dev/null +++ b/lib/doc/efun/interactive/set_this_player @@ -0,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 --git a/lib/doc/efun/interactive/shout b/lib/doc/efun/interactive/shout new file mode 100644 index 0000000..da7e9e2 --- /dev/null +++ b/lib/doc/efun/interactive/shout @@ -0,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 --git a/lib/doc/efun/interactive/snoop b/lib/doc/efun/interactive/snoop new file mode 100644 index 0000000..cc7d897 --- /dev/null +++ b/lib/doc/efun/interactive/snoop @@ -0,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 --git a/lib/doc/efun/interactive/this_interactive b/lib/doc/efun/interactive/this_interactive new file mode 100644 index 0000000..73450f8 --- /dev/null +++ b/lib/doc/efun/interactive/this_interactive @@ -0,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 --git a/lib/doc/efun/interactive/this_player b/lib/doc/efun/interactive/this_player new file mode 100644 index 0000000..bec4953 --- /dev/null +++ b/lib/doc/efun/interactive/this_player @@ -0,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 --git a/lib/doc/efun/interactive/this_user b/lib/doc/efun/interactive/this_user new file mode 100644 index 0000000..e13dd0e --- /dev/null +++ b/lib/doc/efun/interactive/this_user @@ -0,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 --git a/lib/doc/efun/interactive/userp b/lib/doc/efun/interactive/userp new file mode 100644 index 0000000..0fa0bfc --- /dev/null +++ b/lib/doc/efun/interactive/userp @@ -0,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 --git a/lib/doc/efun/interactive/users b/lib/doc/efun/interactive/users new file mode 100644 index 0000000..9a9d722 --- /dev/null +++ b/lib/doc/efun/interactive/users @@ -0,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 --git a/lib/doc/efun/interactive/wizardp b/lib/doc/efun/interactive/wizardp new file mode 100644 index 0000000..d8d5b11 --- /dev/null +++ b/lib/doc/efun/interactive/wizardp @@ -0,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 --git a/lib/doc/efun/interactive/write b/lib/doc/efun/interactive/write new file mode 100644 index 0000000..5c64033 --- /dev/null +++ b/lib/doc/efun/interactive/write @@ -0,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 --git a/lib/doc/efun/internals/cache_stats b/lib/doc/efun/internals/cache_stats new file mode 100644 index 0000000..3ecf9e7 --- /dev/null +++ b/lib/doc/efun/internals/cache_stats @@ -0,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 --git a/lib/doc/efun/internals/debug_info b/lib/doc/efun/internals/debug_info new file mode 100644 index 0000000..226e07e --- /dev/null +++ b/lib/doc/efun/internals/debug_info @@ -0,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 --git a/lib/doc/efun/internals/debugmalloc b/lib/doc/efun/internals/debugmalloc new file mode 100644 index 0000000..b04d4b3 --- /dev/null +++ b/lib/doc/efun/internals/debugmalloc @@ -0,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 --git a/lib/doc/efun/internals/dump_file_descriptors b/lib/doc/efun/internals/dump_file_descriptors new file mode 100644 index 0000000..b237e87 --- /dev/null +++ b/lib/doc/efun/internals/dump_file_descriptors @@ -0,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 --git a/lib/doc/efun/internals/dump_prog b/lib/doc/efun/internals/dump_prog new file mode 100644 index 0000000..4d31e64 --- /dev/null +++ b/lib/doc/efun/internals/dump_prog @@ -0,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 --git a/lib/doc/efun/internals/dump_socket_status b/lib/doc/efun/internals/dump_socket_status new file mode 100644 index 0000000..058a564 --- /dev/null +++ b/lib/doc/efun/internals/dump_socket_status @@ -0,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 --git a/lib/doc/efun/internals/dumpallobj b/lib/doc/efun/internals/dumpallobj new file mode 100644 index 0000000..7a614ff --- /dev/null +++ b/lib/doc/efun/internals/dumpallobj @@ -0,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 --git a/lib/doc/efun/internals/get_config b/lib/doc/efun/internals/get_config new file mode 100644 index 0000000..517e460 --- /dev/null +++ b/lib/doc/efun/internals/get_config @@ -0,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 --git a/lib/doc/efun/internals/index b/lib/doc/efun/internals/index new file mode 100644 index 0000000..8a8f363 --- /dev/null +++ b/lib/doc/efun/internals/index @@ -0,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 --git a/lib/doc/efun/internals/malloc_status b/lib/doc/efun/internals/malloc_status new file mode 100644 index 0000000..ee10e1c --- /dev/null +++ b/lib/doc/efun/internals/malloc_status @@ -0,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 --git a/lib/doc/efun/internals/memory_info b/lib/doc/efun/internals/memory_info new file mode 100644 index 0000000..80d54c1 --- /dev/null +++ b/lib/doc/efun/internals/memory_info @@ -0,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 --git a/lib/doc/efun/internals/mud_status b/lib/doc/efun/internals/mud_status new file mode 100644 index 0000000..e191a09 --- /dev/null +++ b/lib/doc/efun/internals/mud_status @@ -0,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 --git a/lib/doc/efun/internals/opcprof b/lib/doc/efun/internals/opcprof new file mode 100644 index 0000000..c0881ee --- /dev/null +++ b/lib/doc/efun/internals/opcprof @@ -0,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 --git a/lib/doc/efun/internals/query_load_average b/lib/doc/efun/internals/query_load_average new file mode 100644 index 0000000..eca507f --- /dev/null +++ b/lib/doc/efun/internals/query_load_average @@ -0,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 --git a/lib/doc/efun/internals/refs b/lib/doc/efun/internals/refs new file mode 100644 index 0000000..aa459f6 --- /dev/null +++ b/lib/doc/efun/internals/refs @@ -0,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 --git a/lib/doc/efun/internals/rusage b/lib/doc/efun/internals/rusage new file mode 100644 index 0000000..14d2ec4 --- /dev/null +++ b/lib/doc/efun/internals/rusage @@ -0,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 --git a/lib/doc/efun/internals/set_debug_level b/lib/doc/efun/internals/set_debug_level new file mode 100644 index 0000000..4839b92 --- /dev/null +++ b/lib/doc/efun/internals/set_debug_level @@ -0,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 --git a/lib/doc/efun/internals/set_malloc_mask b/lib/doc/efun/internals/set_malloc_mask new file mode 100644 index 0000000..a269d06 --- /dev/null +++ b/lib/doc/efun/internals/set_malloc_mask @@ -0,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 --git a/lib/doc/efun/internals/swap b/lib/doc/efun/internals/swap new file mode 100644 index 0000000..6aecd7e --- /dev/null +++ b/lib/doc/efun/internals/swap @@ -0,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 --git a/lib/doc/efun/internals/time_expression b/lib/doc/efun/internals/time_expression new file mode 100644 index 0000000..7fdcf3a --- /dev/null +++ b/lib/doc/efun/internals/time_expression @@ -0,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 --git a/lib/doc/efun/internals/trace b/lib/doc/efun/internals/trace new file mode 100644 index 0000000..f1fc148 --- /dev/null +++ b/lib/doc/efun/internals/trace @@ -0,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 --git a/lib/doc/efun/internals/traceprefix b/lib/doc/efun/internals/traceprefix new file mode 100644 index 0000000..f61362b --- /dev/null +++ b/lib/doc/efun/internals/traceprefix @@ -0,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 --git a/lib/doc/efun/mappings/allocate_mapping b/lib/doc/efun/mappings/allocate_mapping new file mode 100644 index 0000000..e5daf86 --- /dev/null +++ b/lib/doc/efun/mappings/allocate_mapping @@ -0,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 --git a/lib/doc/efun/mappings/filter_mapping b/lib/doc/efun/mappings/filter_mapping new file mode 100644 index 0000000..7545461 --- /dev/null +++ b/lib/doc/efun/mappings/filter_mapping @@ -0,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 --git a/lib/doc/efun/mappings/index b/lib/doc/efun/mappings/index new file mode 100644 index 0000000..2fd9fd4 --- /dev/null +++ b/lib/doc/efun/mappings/index @@ -0,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 --git a/lib/doc/efun/mappings/keys b/lib/doc/efun/mappings/keys new file mode 100644 index 0000000..7112245 --- /dev/null +++ b/lib/doc/efun/mappings/keys @@ -0,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 --git a/lib/doc/efun/mappings/m_delete b/lib/doc/efun/mappings/m_delete new file mode 100644 index 0000000..2624356 --- /dev/null +++ b/lib/doc/efun/mappings/m_delete @@ -0,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 --git a/lib/doc/efun/mappings/m_indices b/lib/doc/efun/mappings/m_indices new file mode 100644 index 0000000..89bff3c --- /dev/null +++ b/lib/doc/efun/mappings/m_indices @@ -0,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 --git a/lib/doc/efun/mappings/m_values b/lib/doc/efun/mappings/m_values new file mode 100644 index 0000000..a3c3ce5 --- /dev/null +++ b/lib/doc/efun/mappings/m_values @@ -0,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 --git a/lib/doc/efun/mappings/map_delete b/lib/doc/efun/mappings/map_delete new file mode 100644 index 0000000..3365904 --- /dev/null +++ b/lib/doc/efun/mappings/map_delete @@ -0,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 --git a/lib/doc/efun/mappings/map_mapping b/lib/doc/efun/mappings/map_mapping new file mode 100644 index 0000000..de9c67c --- /dev/null +++ b/lib/doc/efun/mappings/map_mapping @@ -0,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 --git a/lib/doc/efun/mappings/match_path b/lib/doc/efun/mappings/match_path new file mode 100644 index 0000000..82872c2 --- /dev/null +++ b/lib/doc/efun/mappings/match_path @@ -0,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 --git a/lib/doc/efun/mappings/unique_mapping b/lib/doc/efun/mappings/unique_mapping new file mode 100644 index 0000000..7f8d44a --- /dev/null +++ b/lib/doc/efun/mappings/unique_mapping @@ -0,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 --git a/lib/doc/efun/mappings/values b/lib/doc/efun/mappings/values new file mode 100644 index 0000000..5f7e0e9 --- /dev/null +++ b/lib/doc/efun/mappings/values @@ -0,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 --git a/lib/doc/efun/mixed/arrayp b/lib/doc/efun/mixed/arrayp new file mode 100644 index 0000000..aceb839 --- /dev/null +++ b/lib/doc/efun/mixed/arrayp @@ -0,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 --git a/lib/doc/efun/mixed/bufferp b/lib/doc/efun/mixed/bufferp new file mode 100644 index 0000000..13dff18 --- /dev/null +++ b/lib/doc/efun/mixed/bufferp @@ -0,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 --git a/lib/doc/efun/mixed/classp b/lib/doc/efun/mixed/classp new file mode 100644 index 0000000..9e53f8f --- /dev/null +++ b/lib/doc/efun/mixed/classp @@ -0,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 --git a/lib/doc/efun/mixed/floatp b/lib/doc/efun/mixed/floatp new file mode 100644 index 0000000..e130685 --- /dev/null +++ b/lib/doc/efun/mixed/floatp @@ -0,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 --git a/lib/doc/efun/mixed/functionp b/lib/doc/efun/mixed/functionp new file mode 100644 index 0000000..2a9252e --- /dev/null +++ b/lib/doc/efun/mixed/functionp @@ -0,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 --git a/lib/doc/efun/mixed/intp b/lib/doc/efun/mixed/intp new file mode 100644 index 0000000..79be085 --- /dev/null +++ b/lib/doc/efun/mixed/intp @@ -0,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 --git a/lib/doc/efun/mixed/mapp b/lib/doc/efun/mixed/mapp new file mode 100644 index 0000000..32dc980 --- /dev/null +++ b/lib/doc/efun/mixed/mapp @@ -0,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 --git a/lib/doc/efun/mixed/nullp b/lib/doc/efun/mixed/nullp new file mode 100644 index 0000000..12d8f8b --- /dev/null +++ b/lib/doc/efun/mixed/nullp @@ -0,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 --git a/lib/doc/efun/mixed/objectp b/lib/doc/efun/mixed/objectp new file mode 100644 index 0000000..a3df08c --- /dev/null +++ b/lib/doc/efun/mixed/objectp @@ -0,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 --git a/lib/doc/efun/mixed/pointerp b/lib/doc/efun/mixed/pointerp new file mode 100644 index 0000000..ad49d54 --- /dev/null +++ b/lib/doc/efun/mixed/pointerp @@ -0,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 --git a/lib/doc/efun/mixed/stringp b/lib/doc/efun/mixed/stringp new file mode 100644 index 0000000..91d414e --- /dev/null +++ b/lib/doc/efun/mixed/stringp @@ -0,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 --git a/lib/doc/efun/mixed/undefinedp b/lib/doc/efun/mixed/undefinedp new file mode 100644 index 0000000..5ee39c9 --- /dev/null +++ b/lib/doc/efun/mixed/undefinedp @@ -0,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 --git a/lib/doc/efun/mudlib/author_stats b/lib/doc/efun/mudlib/author_stats new file mode 100644 index 0000000..586f9e8 --- /dev/null +++ b/lib/doc/efun/mudlib/author_stats @@ -0,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 --git a/lib/doc/efun/mudlib/domain_stats b/lib/doc/efun/mudlib/domain_stats new file mode 100644 index 0000000..7483a14 --- /dev/null +++ b/lib/doc/efun/mudlib/domain_stats @@ -0,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 --git a/lib/doc/efun/mudlib/export_uid b/lib/doc/efun/mudlib/export_uid new file mode 100644 index 0000000..cea7767 --- /dev/null +++ b/lib/doc/efun/mudlib/export_uid @@ -0,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 --git a/lib/doc/efun/mudlib/find_living b/lib/doc/efun/mudlib/find_living new file mode 100644 index 0000000..58d024c --- /dev/null +++ b/lib/doc/efun/mudlib/find_living @@ -0,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 --git a/lib/doc/efun/mudlib/geteuid b/lib/doc/efun/mudlib/geteuid new file mode 100644 index 0000000..c391017 --- /dev/null +++ b/lib/doc/efun/mudlib/geteuid @@ -0,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 --git a/lib/doc/efun/mudlib/getuid b/lib/doc/efun/mudlib/getuid new file mode 100644 index 0000000..440def6 --- /dev/null +++ b/lib/doc/efun/mudlib/getuid @@ -0,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 --git a/lib/doc/efun/mudlib/index b/lib/doc/efun/mudlib/index new file mode 100644 index 0000000..f13e68e --- /dev/null +++ b/lib/doc/efun/mudlib/index @@ -0,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 --git a/lib/doc/efun/mudlib/living b/lib/doc/efun/mudlib/living new file mode 100644 index 0000000..9325397 --- /dev/null +++ b/lib/doc/efun/mudlib/living @@ -0,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 --git a/lib/doc/efun/mudlib/livings b/lib/doc/efun/mudlib/livings new file mode 100644 index 0000000..edf89de --- /dev/null +++ b/lib/doc/efun/mudlib/livings @@ -0,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 --git a/lib/doc/efun/mudlib/query_privs b/lib/doc/efun/mudlib/query_privs new file mode 100644 index 0000000..d89005c --- /dev/null +++ b/lib/doc/efun/mudlib/query_privs @@ -0,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 --git a/lib/doc/efun/mudlib/set_author b/lib/doc/efun/mudlib/set_author new file mode 100644 index 0000000..eab4f05 --- /dev/null +++ b/lib/doc/efun/mudlib/set_author @@ -0,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 --git a/lib/doc/efun/mudlib/set_light b/lib/doc/efun/mudlib/set_light new file mode 100644 index 0000000..f014e7d --- /dev/null +++ b/lib/doc/efun/mudlib/set_light @@ -0,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 --git a/lib/doc/efun/mudlib/set_living_name b/lib/doc/efun/mudlib/set_living_name new file mode 100644 index 0000000..e04cf18 --- /dev/null +++ b/lib/doc/efun/mudlib/set_living_name @@ -0,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 --git a/lib/doc/efun/mudlib/set_privs b/lib/doc/efun/mudlib/set_privs new file mode 100644 index 0000000..899f9b0 --- /dev/null +++ b/lib/doc/efun/mudlib/set_privs @@ -0,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 --git a/lib/doc/efun/mudlib/seteuid b/lib/doc/efun/mudlib/seteuid new file mode 100644 index 0000000..03fe383 --- /dev/null +++ b/lib/doc/efun/mudlib/seteuid @@ -0,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 --git a/lib/doc/efun/numbers/index b/lib/doc/efun/numbers/index new file mode 100644 index 0000000..d71f6bf --- /dev/null +++ b/lib/doc/efun/numbers/index @@ -0,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 --git a/lib/doc/efun/numbers/query_num b/lib/doc/efun/numbers/query_num new file mode 100644 index 0000000..1504ea7 --- /dev/null +++ b/lib/doc/efun/numbers/query_num @@ -0,0 +1 @@ +:( diff --git a/lib/doc/efun/numbers/random b/lib/doc/efun/numbers/random new file mode 100644 index 0000000..385ca46 --- /dev/null +++ b/lib/doc/efun/numbers/random @@ -0,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 --git a/lib/doc/efun/numbers/to_float b/lib/doc/efun/numbers/to_float new file mode 100644 index 0000000..6bb8c68 --- /dev/null +++ b/lib/doc/efun/numbers/to_float @@ -0,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 --git a/lib/doc/efun/objects/all_inventory b/lib/doc/efun/objects/all_inventory new file mode 100644 index 0000000..cedceba --- /dev/null +++ b/lib/doc/efun/objects/all_inventory @@ -0,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 --git a/lib/doc/efun/objects/children b/lib/doc/efun/objects/children new file mode 100644 index 0000000..0df1dfc --- /dev/null +++ b/lib/doc/efun/objects/children @@ -0,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 --git a/lib/doc/efun/objects/clone_object b/lib/doc/efun/objects/clone_object new file mode 100644 index 0000000..a374415 --- /dev/null +++ b/lib/doc/efun/objects/clone_object @@ -0,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 --git a/lib/doc/efun/objects/clonep b/lib/doc/efun/objects/clonep new file mode 100644 index 0000000..dbb50dd --- /dev/null +++ b/lib/doc/efun/objects/clonep @@ -0,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 --git a/lib/doc/efun/objects/deep_inventory b/lib/doc/efun/objects/deep_inventory new file mode 100644 index 0000000..03eee3a --- /dev/null +++ b/lib/doc/efun/objects/deep_inventory @@ -0,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 --git a/lib/doc/efun/objects/destruct b/lib/doc/efun/objects/destruct new file mode 100644 index 0000000..8b361ef --- /dev/null +++ b/lib/doc/efun/objects/destruct @@ -0,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 --git a/lib/doc/efun/objects/environment b/lib/doc/efun/objects/environment new file mode 100644 index 0000000..47ebb27 --- /dev/null +++ b/lib/doc/efun/objects/environment @@ -0,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 --git a/lib/doc/efun/objects/file_name b/lib/doc/efun/objects/file_name new file mode 100644 index 0000000..903e3bc --- /dev/null +++ b/lib/doc/efun/objects/file_name @@ -0,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 --git a/lib/doc/efun/objects/find_object b/lib/doc/efun/objects/find_object new file mode 100644 index 0000000..179a4f6 --- /dev/null +++ b/lib/doc/efun/objects/find_object @@ -0,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 --git a/lib/doc/efun/objects/first_inventory b/lib/doc/efun/objects/first_inventory new file mode 100644 index 0000000..6a069bc --- /dev/null +++ b/lib/doc/efun/objects/first_inventory @@ -0,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 --git a/lib/doc/efun/objects/heart_beat_info b/lib/doc/efun/objects/heart_beat_info new file mode 100644 index 0000000..020c402 --- /dev/null +++ b/lib/doc/efun/objects/heart_beat_info @@ -0,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 --git a/lib/doc/efun/objects/heart_beats b/lib/doc/efun/objects/heart_beats new file mode 100644 index 0000000..01fe319 --- /dev/null +++ b/lib/doc/efun/objects/heart_beats @@ -0,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 --git a/lib/doc/efun/objects/index b/lib/doc/efun/objects/index new file mode 100644 index 0000000..c63b04e --- /dev/null +++ b/lib/doc/efun/objects/index @@ -0,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 --git a/lib/doc/efun/objects/load_object b/lib/doc/efun/objects/load_object new file mode 100644 index 0000000..4347aac --- /dev/null +++ b/lib/doc/efun/objects/load_object @@ -0,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 --git a/lib/doc/efun/objects/master b/lib/doc/efun/objects/master new file mode 100644 index 0000000..81013db --- /dev/null +++ b/lib/doc/efun/objects/master @@ -0,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 --git a/lib/doc/efun/objects/move_object b/lib/doc/efun/objects/move_object new file mode 100644 index 0000000..4d852b8 --- /dev/null +++ b/lib/doc/efun/objects/move_object @@ -0,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 --git a/lib/doc/efun/objects/new b/lib/doc/efun/objects/new new file mode 100644 index 0000000..8a21706 --- /dev/null +++ b/lib/doc/efun/objects/new @@ -0,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 --git a/lib/doc/efun/objects/next_inventory b/lib/doc/efun/objects/next_inventory new file mode 100644 index 0000000..7ea314d --- /dev/null +++ b/lib/doc/efun/objects/next_inventory @@ -0,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 --git a/lib/doc/efun/objects/objects b/lib/doc/efun/objects/objects new file mode 100644 index 0000000..c44d512 --- /dev/null +++ b/lib/doc/efun/objects/objects @@ -0,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 --git a/lib/doc/efun/objects/present b/lib/doc/efun/objects/present new file mode 100644 index 0000000..f681707 --- /dev/null +++ b/lib/doc/efun/objects/present @@ -0,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 --git a/lib/doc/efun/objects/query_heart_beat b/lib/doc/efun/objects/query_heart_beat new file mode 100644 index 0000000..8b20192 --- /dev/null +++ b/lib/doc/efun/objects/query_heart_beat @@ -0,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 --git a/lib/doc/efun/objects/reload_object b/lib/doc/efun/objects/reload_object new file mode 100644 index 0000000..32c2dd8 --- /dev/null +++ b/lib/doc/efun/objects/reload_object @@ -0,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 --git a/lib/doc/efun/objects/restore_object b/lib/doc/efun/objects/restore_object new file mode 100644 index 0000000..801d42f --- /dev/null +++ b/lib/doc/efun/objects/restore_object @@ -0,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 --git a/lib/doc/efun/objects/save_object b/lib/doc/efun/objects/save_object new file mode 100644 index 0000000..1f5d01f --- /dev/null +++ b/lib/doc/efun/objects/save_object @@ -0,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 --git a/lib/doc/efun/objects/set_heart_beat b/lib/doc/efun/objects/set_heart_beat new file mode 100644 index 0000000..eec5f94 --- /dev/null +++ b/lib/doc/efun/objects/set_heart_beat @@ -0,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 --git a/lib/doc/efun/objects/set_hide b/lib/doc/efun/objects/set_hide new file mode 100644 index 0000000..56be518 --- /dev/null +++ b/lib/doc/efun/objects/set_hide @@ -0,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 --git a/lib/doc/efun/objects/tell_object b/lib/doc/efun/objects/tell_object new file mode 100644 index 0000000..3820bfc --- /dev/null +++ b/lib/doc/efun/objects/tell_object @@ -0,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 --git a/lib/doc/efun/objects/tell_room b/lib/doc/efun/objects/tell_room new file mode 100644 index 0000000..e8b8a4a --- /dev/null +++ b/lib/doc/efun/objects/tell_room @@ -0,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 --git a/lib/doc/efun/objects/virtualp b/lib/doc/efun/objects/virtualp new file mode 100644 index 0000000..13b7a0e --- /dev/null +++ b/lib/doc/efun/objects/virtualp @@ -0,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 --git a/lib/doc/efun/parsing/TODO b/lib/doc/efun/parsing/TODO new file mode 100644 index 0000000..839ed60 --- /dev/null +++ b/lib/doc/efun/parsing/TODO @@ -0,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 --git a/lib/doc/efun/parsing/index b/lib/doc/efun/parsing/index new file mode 100644 index 0000000..9497d65 --- /dev/null +++ b/lib/doc/efun/parsing/index @@ -0,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 --git a/lib/doc/efun/parsing/query_verb b/lib/doc/efun/parsing/query_verb new file mode 100644 index 0000000..28e83dd --- /dev/null +++ b/lib/doc/efun/parsing/query_verb @@ -0,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 --git a/lib/doc/efun/sockets/index b/lib/doc/efun/sockets/index new file mode 100644 index 0000000..4a67c43 --- /dev/null +++ b/lib/doc/efun/sockets/index @@ -0,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 --git a/lib/doc/efun/sockets/network_stats b/lib/doc/efun/sockets/network_stats new file mode 100644 index 0000000..1504ea7 --- /dev/null +++ b/lib/doc/efun/sockets/network_stats @@ -0,0 +1 @@ +:( diff --git a/lib/doc/efun/sockets/socket_accept b/lib/doc/efun/sockets/socket_accept new file mode 100644 index 0000000..31ad9d1 --- /dev/null +++ b/lib/doc/efun/sockets/socket_accept @@ -0,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 --git a/lib/doc/efun/sockets/socket_acquire b/lib/doc/efun/sockets/socket_acquire new file mode 100644 index 0000000..9c5f666 --- /dev/null +++ b/lib/doc/efun/sockets/socket_acquire @@ -0,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 --git a/lib/doc/efun/sockets/socket_address b/lib/doc/efun/sockets/socket_address new file mode 100644 index 0000000..0639913 --- /dev/null +++ b/lib/doc/efun/sockets/socket_address @@ -0,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 --git a/lib/doc/efun/sockets/socket_bind b/lib/doc/efun/sockets/socket_bind new file mode 100644 index 0000000..7d6dad8 --- /dev/null +++ b/lib/doc/efun/sockets/socket_bind @@ -0,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 --git a/lib/doc/efun/sockets/socket_close b/lib/doc/efun/sockets/socket_close new file mode 100644 index 0000000..aed6139 --- /dev/null +++ b/lib/doc/efun/sockets/socket_close @@ -0,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 --git a/lib/doc/efun/sockets/socket_connect b/lib/doc/efun/sockets/socket_connect new file mode 100644 index 0000000..b24a966 --- /dev/null +++ b/lib/doc/efun/sockets/socket_connect @@ -0,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 --git a/lib/doc/efun/sockets/socket_create b/lib/doc/efun/sockets/socket_create new file mode 100644 index 0000000..7e5b21e --- /dev/null +++ b/lib/doc/efun/sockets/socket_create @@ -0,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 --git a/lib/doc/efun/sockets/socket_error b/lib/doc/efun/sockets/socket_error new file mode 100644 index 0000000..a9d1fe6 --- /dev/null +++ b/lib/doc/efun/sockets/socket_error @@ -0,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 --git a/lib/doc/efun/sockets/socket_error.h b/lib/doc/efun/sockets/socket_error.h new file mode 100644 index 0000000..e69de29 diff --git a/lib/doc/efun/sockets/socket_listen b/lib/doc/efun/sockets/socket_listen new file mode 100644 index 0000000..6f9b900 --- /dev/null +++ b/lib/doc/efun/sockets/socket_listen @@ -0,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 --git a/lib/doc/efun/sockets/socket_release b/lib/doc/efun/sockets/socket_release new file mode 100644 index 0000000..2b2dc16 --- /dev/null +++ b/lib/doc/efun/sockets/socket_release @@ -0,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 --git a/lib/doc/efun/sockets/socket_write b/lib/doc/efun/sockets/socket_write new file mode 100644 index 0000000..48a2da1 --- /dev/null +++ b/lib/doc/efun/sockets/socket_write @@ -0,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 --git a/lib/doc/efun/strings/capitalize b/lib/doc/efun/strings/capitalize new file mode 100644 index 0000000..e939e2f --- /dev/null +++ b/lib/doc/efun/strings/capitalize @@ -0,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 --git a/lib/doc/efun/strings/clear_bit b/lib/doc/efun/strings/clear_bit new file mode 100644 index 0000000..7a70f44 --- /dev/null +++ b/lib/doc/efun/strings/clear_bit @@ -0,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 --git a/lib/doc/efun/strings/crypt b/lib/doc/efun/strings/crypt new file mode 100644 index 0000000..73eb2fc --- /dev/null +++ b/lib/doc/efun/strings/crypt @@ -0,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 --git a/lib/doc/efun/strings/explode b/lib/doc/efun/strings/explode new file mode 100644 index 0000000..d99d715 --- /dev/null +++ b/lib/doc/efun/strings/explode @@ -0,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 --git a/lib/doc/efun/strings/implode b/lib/doc/efun/strings/implode new file mode 100644 index 0000000..cb3e747 --- /dev/null +++ b/lib/doc/efun/strings/implode @@ -0,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 --git a/lib/doc/efun/strings/index b/lib/doc/efun/strings/index new file mode 100644 index 0000000..d78ce9d --- /dev/null +++ b/lib/doc/efun/strings/index @@ -0,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 --git a/lib/doc/efun/strings/lower_case b/lib/doc/efun/strings/lower_case new file mode 100644 index 0000000..c8be581 --- /dev/null +++ b/lib/doc/efun/strings/lower_case @@ -0,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 --git a/lib/doc/efun/strings/next_bit b/lib/doc/efun/strings/next_bit new file mode 100644 index 0000000..d264573 --- /dev/null +++ b/lib/doc/efun/strings/next_bit @@ -0,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 --git a/lib/doc/efun/strings/pluralize b/lib/doc/efun/strings/pluralize new file mode 100644 index 0000000..f8f4c8d --- /dev/null +++ b/lib/doc/efun/strings/pluralize @@ -0,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 --git a/lib/doc/efun/strings/reg_assoc b/lib/doc/efun/strings/reg_assoc new file mode 100644 index 0000000..b536851 --- /dev/null +++ b/lib/doc/efun/strings/reg_assoc @@ -0,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 --git a/lib/doc/efun/strings/regexp b/lib/doc/efun/strings/regexp new file mode 100644 index 0000000..8faf973 --- /dev/null +++ b/lib/doc/efun/strings/regexp @@ -0,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 --git a/lib/doc/efun/strings/repeat_string b/lib/doc/efun/strings/repeat_string new file mode 100644 index 0000000..414edcb --- /dev/null +++ b/lib/doc/efun/strings/repeat_string @@ -0,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 --git a/lib/doc/efun/strings/replace_string b/lib/doc/efun/strings/replace_string new file mode 100644 index 0000000..58a47d9 --- /dev/null +++ b/lib/doc/efun/strings/replace_string @@ -0,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 --git a/lib/doc/efun/strings/set_bit b/lib/doc/efun/strings/set_bit new file mode 100644 index 0000000..cc01cbf --- /dev/null +++ b/lib/doc/efun/strings/set_bit @@ -0,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 --git a/lib/doc/efun/strings/sprintf b/lib/doc/efun/strings/sprintf new file mode 100644 index 0000000..60d5c60 --- /dev/null +++ b/lib/doc/efun/strings/sprintf @@ -0,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 --git a/lib/doc/efun/strings/sscanf b/lib/doc/efun/strings/sscanf new file mode 100644 index 0000000..14f6733 --- /dev/null +++ b/lib/doc/efun/strings/sscanf @@ -0,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 --git a/lib/doc/efun/strings/strcmp b/lib/doc/efun/strings/strcmp new file mode 100644 index 0000000..0d2c445 --- /dev/null +++ b/lib/doc/efun/strings/strcmp @@ -0,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 --git a/lib/doc/efun/strings/strlen b/lib/doc/efun/strings/strlen new file mode 100644 index 0000000..31115c6 --- /dev/null +++ b/lib/doc/efun/strings/strlen @@ -0,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 --git a/lib/doc/efun/strings/strsrch b/lib/doc/efun/strings/strsrch new file mode 100644 index 0000000..8d63db9 --- /dev/null +++ b/lib/doc/efun/strings/strsrch @@ -0,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 --git a/lib/doc/efun/strings/terminal_colour b/lib/doc/efun/strings/terminal_colour new file mode 100644 index 0000000..977dc00 --- /dev/null +++ b/lib/doc/efun/strings/terminal_colour @@ -0,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 --git a/lib/doc/efun/strings/test_bit b/lib/doc/efun/strings/test_bit new file mode 100644 index 0000000..367cfaf --- /dev/null +++ b/lib/doc/efun/strings/test_bit @@ -0,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 --git a/lib/doc/efun/strings/upper_case b/lib/doc/efun/strings/upper_case new file mode 100644 index 0000000..943eeab --- /dev/null +++ b/lib/doc/efun/strings/upper_case @@ -0,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 --git a/lib/doc/efun/system/all_previous_objects b/lib/doc/efun/system/all_previous_objects new file mode 100644 index 0000000..e5fb417 --- /dev/null +++ b/lib/doc/efun/system/all_previous_objects @@ -0,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 --git a/lib/doc/efun/system/call_out_info b/lib/doc/efun/system/call_out_info new file mode 100644 index 0000000..22116c8 --- /dev/null +++ b/lib/doc/efun/system/call_out_info @@ -0,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 --git a/lib/doc/efun/system/check_memory b/lib/doc/efun/system/check_memory new file mode 100644 index 0000000..577188c --- /dev/null +++ b/lib/doc/efun/system/check_memory @@ -0,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 --git a/lib/doc/efun/system/ctime b/lib/doc/efun/system/ctime new file mode 100644 index 0000000..43281d2 --- /dev/null +++ b/lib/doc/efun/system/ctime @@ -0,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 --git a/lib/doc/efun/system/debug_message b/lib/doc/efun/system/debug_message new file mode 100644 index 0000000..a57d3ca --- /dev/null +++ b/lib/doc/efun/system/debug_message @@ -0,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 --git a/lib/doc/efun/system/deep_inherit_list b/lib/doc/efun/system/deep_inherit_list new file mode 100644 index 0000000..2795390 --- /dev/null +++ b/lib/doc/efun/system/deep_inherit_list @@ -0,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 --git a/lib/doc/efun/system/error b/lib/doc/efun/system/error new file mode 100644 index 0000000..0fcd489 --- /dev/null +++ b/lib/doc/efun/system/error @@ -0,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 --git a/lib/doc/efun/system/eval_cost b/lib/doc/efun/system/eval_cost new file mode 100644 index 0000000..dbfea2d --- /dev/null +++ b/lib/doc/efun/system/eval_cost @@ -0,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 --git a/lib/doc/efun/system/external_start b/lib/doc/efun/system/external_start new file mode 100644 index 0000000..6839af4 --- /dev/null +++ b/lib/doc/efun/system/external_start @@ -0,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 --git a/lib/doc/efun/system/find_call_out b/lib/doc/efun/system/find_call_out new file mode 100644 index 0000000..58b3268 --- /dev/null +++ b/lib/doc/efun/system/find_call_out @@ -0,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 --git a/lib/doc/efun/system/flush_messages b/lib/doc/efun/system/flush_messages new file mode 100644 index 0000000..6fd0c4b --- /dev/null +++ b/lib/doc/efun/system/flush_messages @@ -0,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 --git a/lib/doc/efun/system/function_exists b/lib/doc/efun/system/function_exists new file mode 100644 index 0000000..917d097 --- /dev/null +++ b/lib/doc/efun/system/function_exists @@ -0,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 --git a/lib/doc/efun/system/function_profile b/lib/doc/efun/system/function_profile new file mode 100644 index 0000000..c68822c --- /dev/null +++ b/lib/doc/efun/system/function_profile @@ -0,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 --git a/lib/doc/efun/system/functions b/lib/doc/efun/system/functions new file mode 100644 index 0000000..e6269f0 --- /dev/null +++ b/lib/doc/efun/system/functions @@ -0,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 --git a/lib/doc/efun/system/index b/lib/doc/efun/system/index new file mode 100644 index 0000000..415fc25 --- /dev/null +++ b/lib/doc/efun/system/index @@ -0,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 --git a/lib/doc/efun/system/inherit_list b/lib/doc/efun/system/inherit_list new file mode 100644 index 0000000..121ed24 --- /dev/null +++ b/lib/doc/efun/system/inherit_list @@ -0,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 --git a/lib/doc/efun/system/inherits b/lib/doc/efun/system/inherits new file mode 100644 index 0000000..208c313 --- /dev/null +++ b/lib/doc/efun/system/inherits @@ -0,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 --git a/lib/doc/efun/system/localtime b/lib/doc/efun/system/localtime new file mode 100644 index 0000000..982f545 --- /dev/null +++ b/lib/doc/efun/system/localtime @@ -0,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 --git a/lib/doc/efun/system/lpc_info b/lib/doc/efun/system/lpc_info new file mode 100644 index 0000000..f60ebed --- /dev/null +++ b/lib/doc/efun/system/lpc_info @@ -0,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 --git a/lib/doc/efun/system/max_eval_cost b/lib/doc/efun/system/max_eval_cost new file mode 100644 index 0000000..91f267c --- /dev/null +++ b/lib/doc/efun/system/max_eval_cost @@ -0,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 --git a/lib/doc/efun/system/memory_summary b/lib/doc/efun/system/memory_summary new file mode 100644 index 0000000..f5c7831 --- /dev/null +++ b/lib/doc/efun/system/memory_summary @@ -0,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 --git a/lib/doc/efun/system/named_livings b/lib/doc/efun/system/named_livings new file mode 100644 index 0000000..8f37010 --- /dev/null +++ b/lib/doc/efun/system/named_livings @@ -0,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 --git a/lib/doc/efun/system/program_info b/lib/doc/efun/system/program_info new file mode 100644 index 0000000..968c4b5 --- /dev/null +++ b/lib/doc/efun/system/program_info @@ -0,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 --git a/lib/doc/efun/system/reclaim_objects b/lib/doc/efun/system/reclaim_objects new file mode 100644 index 0000000..5b14db4 --- /dev/null +++ b/lib/doc/efun/system/reclaim_objects @@ -0,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 --git a/lib/doc/efun/system/replace_program b/lib/doc/efun/system/replace_program new file mode 100644 index 0000000..9d565eb --- /dev/null +++ b/lib/doc/efun/system/replace_program @@ -0,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 --git a/lib/doc/efun/system/replaceable b/lib/doc/efun/system/replaceable new file mode 100644 index 0000000..5ba9046 --- /dev/null +++ b/lib/doc/efun/system/replaceable @@ -0,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 --git a/lib/doc/efun/system/reset_eval_cost b/lib/doc/efun/system/reset_eval_cost new file mode 100644 index 0000000..c2aacbd --- /dev/null +++ b/lib/doc/efun/system/reset_eval_cost @@ -0,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 --git a/lib/doc/efun/system/set_eval_limit b/lib/doc/efun/system/set_eval_limit new file mode 100644 index 0000000..d89171b --- /dev/null +++ b/lib/doc/efun/system/set_eval_limit @@ -0,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 --git a/lib/doc/efun/system/set_reset b/lib/doc/efun/system/set_reset new file mode 100644 index 0000000..448f6f3 --- /dev/null +++ b/lib/doc/efun/system/set_reset @@ -0,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 --git a/lib/doc/efun/system/shallow_inherit_list b/lib/doc/efun/system/shallow_inherit_list new file mode 100644 index 0000000..4a96e80 --- /dev/null +++ b/lib/doc/efun/system/shallow_inherit_list @@ -0,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 --git a/lib/doc/efun/system/shutdown b/lib/doc/efun/system/shutdown new file mode 100644 index 0000000..8451328 --- /dev/null +++ b/lib/doc/efun/system/shutdown @@ -0,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 --git a/lib/doc/efun/system/time b/lib/doc/efun/system/time new file mode 100644 index 0000000..5fa4ed2 --- /dev/null +++ b/lib/doc/efun/system/time @@ -0,0 +1,13 @@ +time - return the number of seconds since January 1 1970 + +int time( void ); + +Return the number of seconds since midnight (GMT) January 1, 1970. + +See also: + ctime, + localtime, + time_expression, + uptime + + Tim Hollebeek Beek@ZorkMUD, Lima Bean, IdeaExchange, and elsewhere diff --git a/lib/doc/efun/system/uptime b/lib/doc/efun/system/uptime new file mode 100644 index 0000000..b5ffbdd --- /dev/null +++ b/lib/doc/efun/system/uptime @@ -0,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 --git a/lib/doc/efun/system/variables b/lib/doc/efun/system/variables new file mode 100644 index 0000000..a283ced --- /dev/null +++ b/lib/doc/efun/system/variables @@ -0,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 --git a/lib/doc/guide/chapter01 b/lib/doc/guide/chapter01 new file mode 100644 index 0000000..7bd43a1 --- /dev/null +++ b/lib/doc/guide/chapter01 @@ -0,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 --git a/lib/doc/guide/chapter02 b/lib/doc/guide/chapter02 new file mode 100644 index 0000000..9bbf33b --- /dev/null +++ b/lib/doc/guide/chapter02 @@ -0,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 --git a/lib/doc/guide/chapter03 b/lib/doc/guide/chapter03 new file mode 100644 index 0000000..822d003 --- /dev/null +++ b/lib/doc/guide/chapter03 @@ -0,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 --git a/lib/doc/guide/chapter04 b/lib/doc/guide/chapter04 new file mode 100644 index 0000000..e269724 --- /dev/null +++ b/lib/doc/guide/chapter04 @@ -0,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 --git a/lib/doc/guide/chapter05 b/lib/doc/guide/chapter05 new file mode 100644 index 0000000..20210b0 --- /dev/null +++ b/lib/doc/guide/chapter05 @@ -0,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 --git a/lib/doc/guide/chapter06 b/lib/doc/guide/chapter06 new file mode 100644 index 0000000..b11e1f8 --- /dev/null +++ b/lib/doc/guide/chapter06 @@ -0,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 --git a/lib/doc/guide/chapter07 b/lib/doc/guide/chapter07 new file mode 100644 index 0000000..2cbb9ba --- /dev/null +++ b/lib/doc/guide/chapter07 @@ -0,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 --git a/lib/doc/guide/chapter08 b/lib/doc/guide/chapter08 new file mode 100644 index 0000000..7f57520 --- /dev/null +++ b/lib/doc/guide/chapter08 @@ -0,0 +1,345 @@ +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 VI: 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 --git a/lib/doc/guide/chapter09 b/lib/doc/guide/chapter09 new file mode 100644 index 0000000..2759b1c --- /dev/null +++ b/lib/doc/guide/chapter09 @@ -0,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 --git a/lib/doc/hbook/chapter01 b/lib/doc/hbook/chapter01 new file mode 100644 index 0000000..206347b --- /dev/null +++ b/lib/doc/hbook/chapter01 @@ -0,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 --git a/lib/doc/hbook/chapter02 b/lib/doc/hbook/chapter02 new file mode 100644 index 0000000..83e7d4d --- /dev/null +++ b/lib/doc/hbook/chapter02 @@ -0,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 --git a/lib/doc/hbook/chapter03 b/lib/doc/hbook/chapter03 new file mode 100644 index 0000000..220cad9 --- /dev/null +++ b/lib/doc/hbook/chapter03 @@ -0,0 +1,272 @@ +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. + +New characters should avail themselves of the "customize" command. +When you create a character, you are assigned stats based on +random numbers modified by the race you choose. For example, humans +are physically weaker than other races, so you might have a +strength of 15 as a human, whereas a dwarf might expect something +like 42. On the other hand, humans tend to be quite smart, and so +your human character might have a high intelligence stat, and +the dwarf a substantially lower one. To balance out stats that +are grossly unfair, new characters are given 15 points to spend +to add to their stats. As a human with 15 strength, you might +choose to throw all your customization points into strength, adding +up to a whopping 30. Or you might choose to distribute points +among your stats in a manner most suited to your playing style. +For syntax and details, type: + +help customize + + +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 --git a/lib/doc/hbook/chapter04 b/lib/doc/hbook/chapter04 new file mode 100644 index 0000000..4a928df --- /dev/null +++ b/lib/doc/hbook/chapter04 @@ -0,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's 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's +healers 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 --git a/lib/doc/hbook/chapter05 b/lib/doc/hbook/chapter05 new file mode 100644 index 0000000..d1e70bb --- /dev/null +++ b/lib/doc/hbook/chapter05 @@ -0,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 --git a/lib/doc/hbook/chapter06 b/lib/doc/hbook/chapter06 new file mode 100644 index 0000000..45062bf --- /dev/null +++ b/lib/doc/hbook/chapter06 @@ -0,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 --git a/lib/doc/hbook/chapter07 b/lib/doc/hbook/chapter07 new file mode 100644 index 0000000..2ae2350 --- /dev/null +++ b/lib/doc/hbook/chapter07 @@ -0,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 --git a/lib/doc/hbook/chapter08 b/lib/doc/hbook/chapter08 new file mode 100644 index 0000000..b68c887 --- /dev/null +++ b/lib/doc/hbook/chapter08 @@ -0,0 +1,76 @@ +chapter 8 "Stats details" + +Stats are very important! Depending on the style of +play you prefer, different stats can be of more value +to you. Fighters may prefer strength, mages +may favor intelligence. + +%^RED%^IMPORTANT TIP%^RESET%^: Players start off with 15 stat points +they can add to their stats...so that if you find your +strength is abysmally low, you can raise it to where +your character is playable at lower levels. Don't +forget to type: %^GREEN%^help customize%^RESET%^ + +%^CYAN%^About "stat classes"%^RESET%^: Depending on the race you choose at +character creation, your stat class will be something +in the range of 1 to 5. This is a measure of the stat's +typical priority for that race. For example, orcs are very +strong, and so not only do they usually start with a +high strength stat, their strength class is 1, meaning +that every time an orc has a level promotion, their strength +stat is also raised by 1. Humans, however, have a strength +stat class of 3, meaning a human player's strength stat +is increased by 1 only every third level promotion. + +%^CYAN%^Deviation%^RESET%^:Starting in Dead Souls 2.9a18, a player can choose to +"deviate" from her race's default stat classes. For example, +you *can* have an orc mage with a high-priority intelligence +stat. To do so, you use the deviate command to set your +stat deviation...meaning you're going to devote a certain +percent of the XP you earn to making yourself better at +some stats you choose. Naturally, the more you want to +change a stat class, the more expensive this will be in +terms of your XP deviance cost. For more information, +see: %^GREEN%^help deviate%^RESET%^ + + +%^CYAN%^Some notes on individual stats%^RESET%^: + +High %^MAGENTA%^strength%^RESET%^ means you hit hard when you're in combat, +but it also means you might be strong enough to perform some +tasks others cannot, like open very heavy metal doors. + + +High %^MAGENTA%^intelligence%^RESET%^ means you're able to learn things +better, quicker, like skill training and languages. It +means your training points do you more good. + + +High %^MAGENTA%^charisma%^RESET%^ means it's easier to befriend animals, +which is important if you want to, for example, mount +a horse: + +%^GREEN%^befriend horse%^RESET%^ +%^GREEN%^mount horse%^RESET%^ + + +%^MAGENTA%^Agility%^RESET%^ and %^MAGENTA%^coordination%^RESET%^ are important for avoiding being +hit, and for certain special abilities like stealth, +lock picking, shooting, etc. + + +%^MAGENTA%^Wisdom%^RESET%^ is important for some types of spells. + + +%^MAGENTA%^Durability%^RESET%^ helps determine how much stamina you have... +this is vital to lasting through long combat or moving +quickly through terrain on foot. + + +Finally, %^MAGENTA%^luck%^RESET%^ is an all-around general good thing to have +lots of...some random situations may call for it, and just +like in real life, it's hard to know when it'll come in handy, +but boy can it mean the difference between win and fail! + + + diff --git a/lib/doc/hbook/chapter09 b/lib/doc/hbook/chapter09 new file mode 100644 index 0000000..90c95cc --- /dev/null +++ b/lib/doc/hbook/chapter09 @@ -0,0 +1,82 @@ +chapter 9 "Skills, teachers, and trainers" + +%^CYAN%^General stuff%^RESET%^ + +Stats are the physical attributes that let you do things. +Skills are those things you do. "blunt attack", for example, +is the skill that determines how good you are at using +blunt weapons in combat...while "blunt defense" is how +good you are at *avoiding* damage from such weapons. +"melee attack" and "melee defense" determine your proficiency +at unarmed combat, etc. It is very rare for players who +are not fighters to be able to physically fight without weapons, +by the way. + +If the "skills" command does not list a particular skill +that means you don't have it at all, and whatever it is, you +are very, very bad at it. Mages, for example, usually lack +"blade attack" and "blade defense" entirely...meaning they +are utterly awful at fighting with swords and avoiding +swords in combat. + +Some skills seem useless but are actually quite important. +For example, mages can cast a spell called "whip" which +summons up an energy weapon whose power can be devastating +if the mage is high-level. However, if the mage's conjuring +skill is low, the whip does not last long...meaning she will +have to keep casting this expensive spell frequently. + +Skill levels, like stat levels, increase when a player's +player level is promoted, depending on the skill class. For +a fighter, "blunt attack" is a major priority, and so their +skill class for this is 1. For another class, it may differ. +If the skill class is a high priority, then the skill +improves more often when your player level increases. + +There is no "deviation" command to manipulate skill class. +Emphasis on skill classes is what player classes (like +"fighter", "cleric", etc) are for. + + +%^CYAN%^Trainers%^RESET%^ + +Trainers are folks that can help you improve your skills. +When your player level goes up, you are awarded "training +points". You use these training points by asking trainers to +train you on some specific skill. For example, a mage can +go to Radagast (east, south, up, from the town clocktower) +and: %^GREEN%^ask radagast to train magic attack%^RESET%^ + +If you're a fighter, Radagast will not be able to help you, +since you do not already posess that skill. Trainers can +only train you in skills you already have some knowledge of. + +Instead, a fighter might go to Roshd Burlyneck (down, +south, west, north, of the Ylsrim tower top) and: +%^GREEN%^ask roshd to train knife defense%^RESET%^ + +At this point, a human player might run into a problem. Roshd +is an orc, you see, and speaks Tangetto. He can't train +you if you don't understand that language. This is where +a different kind of instruction comes in... + + +%^CYAN%^Teachers%^RESET%^ + +Teachers are a special kind of trainer than can also teach +you things you did not already know. Typically this would be +a language teacher (like Bugg: east, east, east, north, of +the village clocktower), or a spell teacher (Herkimer: south, +west, south, of the village clocktower). + +%^RED%^PROTIP%^RESET%^: You don't have to be a mage in order to have +Herkimer teach you a spell. As long as you have some magical +ability, and have the money, he will teach you some simple +spells whether you are a mage or not. Mages get to learn them +free, however, and Herkimer saves some spells for mages only. + +Trainers and teachers are where having a high intelligence stat +can really pay off. It takes fewer lessons to improve your language +or your skills if you have high intelligence. + + diff --git a/lib/doc/help/classes/cleric b/lib/doc/help/classes/cleric new file mode 100644 index 0000000..a36b51b --- /dev/null +++ b/lib/doc/help/classes/cleric @@ -0,0 +1,15 @@ +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. diff --git a/lib/doc/help/classes/explorer b/lib/doc/help/classes/explorer new file mode 100644 index 0000000..0dca065 --- /dev/null +++ b/lib/doc/help/classes/explorer @@ -0,0 +1,11 @@ +Explorers are well-rounded folk who are capable of learning +spells relatively well, yet can still handle themselves in +a fierce fight. + +Since explorers do not specialize in any specific set of +skills, they lack the spellcasting might of mages, the +formidable melee power of fighters and the fancy shadowcraft +of thieves, but they also lack the weaknesses of those classes. + +Explorers are jacks of all trades, masters of none. + diff --git a/lib/doc/help/classes/fighter b/lib/doc/help/classes/fighter new file mode 100644 index 0000000..befcaef --- /dev/null +++ b/lib/doc/help/classes/fighter @@ -0,0 +1,7 @@ +Fighters are the tried-and-true destroyers and meatshields +of the battlefield. Facing a strong, experienced fighter is +a challenge, for despite their lack of sophisticated magic +or trickery, fighters are trained to just beat you down, +fast, and hard. With their bare hands, if need be. + + diff --git a/lib/doc/help/classes/mage b/lib/doc/help/classes/mage new file mode 100644 index 0000000..4fb361e --- /dev/null +++ b/lib/doc/help/classes/mage @@ -0,0 +1,12 @@ +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. + diff --git a/lib/doc/help/classes/thief b/lib/doc/help/classes/thief new file mode 100644 index 0000000..c643414 --- /dev/null +++ b/lib/doc/help/classes/thief @@ -0,0 +1,9 @@ +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. diff --git a/lib/doc/help/creators/addemote_help b/lib/doc/help/creators/addemote_help new file mode 100644 index 0000000..f82e392 --- /dev/null +++ b/lib/doc/help/creators/addemote_help @@ -0,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 --git a/lib/doc/help/creators/admin b/lib/doc/help/creators/admin new file mode 100644 index 0000000..495596e --- /dev/null +++ b/lib/doc/help/creators/admin @@ -0,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 --git a/lib/doc/help/creators/config b/lib/doc/help/creators/config new file mode 100644 index 0000000..e67f0f2 --- /dev/null +++ b/lib/doc/help/creators/config @@ -0,0 +1,524 @@ +This file details the effects of configuration parameters in /secure/include/config.h + +#ifndef s_config_h +#define s_config_h + This means, "If the s_config_h parameter is not defined, define it now +and also define the stuff in this file." + + +#define DEFAULT_PROMPT "> " + Self-explanatory. Can be overridden per player with the "prompt" command. + + +#define HOST_IP "127.0.0.1" + Sometimes your mud's actual IP will be a fake internal address, +like 10.0.1.1. But this may be confusing under some circumstances, +and especially in the case of the hftp server, an address like this +will interfere with proper operation. + Normally the right and safe thing to do is leave this parameter +alone. A host IP definition of 127.0.0.1 lets the mud know it needs to +figure out its IP address the normal way. If you are running hftp, or +have some unusual situation where your actual IP address is not reachable +but some other one is, then this is where you'd put that external-facing +IP address. + General advice: leave this alone. + + +#define MUD_STATUS "mudlib development" + Self explanatory. + + +#define ADMIN_EMAIL "cratylus@comcast.net" + Self explanatory. Note that it is very important to have a valid +email defined here. Otherwise if the I3 router moves, or your mud +malfunctions and needs to be blacklisted, there is no way to contact +you to straighten things out. + + +#define DEBUGGER "cratylus" + The tc() sefun is a special kind of debugger for admin use. It +will send its messages to the one person specified here. + + +#define LOCAL_NEWS_PREFIX "nm" + Deprecated. Once used for an intermud news system that is +not currently supported. + + +#define MUD_IS_LOCKED 0 + If this is a nonzero integer, only people in the allowed groups +are permitted to log in. By default, these groups are: SECURE, ASSIST, +ELDER, TEST. + + +#define AUTO_WIZ 0 + If this is a 1, new users are given the option to +join your mud as either players or creators, as they choose. If +it is anything other than 0 or 1, new users are automatically +made creators, without being given the option to be players. + + +#define RESTRICTED_INTERMUD 0 + If this is a nonzero integer, users must be added to the INTERMUD +group by an admin if you want them to be able to use intermud channels. +This can be done conveniently with the "groupmod" command. + + +#define DISABLE_INTERMUD 0 + If this is a nonzero integer, no intermud functions will work. Your +intermud daemon will refuse to load, and you will therefore not be +connected to the intermud network. Note that disabling intermud here +disables both Intermud-3 and IMC2. + + +#define DISABLE_IMC2 0 + IMC2 is an intermud protocol, like i3. Its packet syntax is +different enough that it needs its own handler and subsystem. To use +it, leave it enabled here and avail yourself of the imc2 command. + + +#define MINUTES_REBOOT_WARNING 20 + Self explanatory. + + +#define TIME_TO_RESET 3600 + The interval between calls to eventReset() in +the master daemon. 20000 means that every 5 hours, the master +daemon will call evetReset() in itself. This function will randomly +pick 25% of all loaded objects, and call reset() and clean_up() on them. + + +#define RESET_ALL 0 + If this is a nonzero integer, eventReset() in MASTER_D will +eventReset() 100% of all loaded objects, not 25%. Not recommended +for large muds, as this can cause noticeable lag if there are +many loaded objects. + + +#define GMT_OFFSET -32000 + A way to tinker with time settings, if you live in a strange +place. Recommendation: leave this alone. + + +#define LOCAL_TIME 1 + If this is a non-zero integer, the mud will simply believe +whatever time the system thinks it is. Most OS'es can be trusted to +return the time you want, but if your server is in another time zone, +or your OS returns a GMT (aka UTC) offset rather than local time, +then you may need to set this to 0 and tinker with GMT_OFFSET and +EXTRA_TIME_OFFSET. + + +#define EXTRA_TIME_OFFSET 0 + Another tool for tuning your local time. Set in hours, not seconds. +Play with offset settings at your own risk. The correct time of day on your +own system is your own responsibility. + + +#define MAX_LOG_SIZE 150000 + The log rotation daemon uses this parameter as its trigger for +backing up logs. When log rotation check happens, approximately every +two hours (this is set in the events daemon, see the "events" command) +any log file the daemon is set to scan that is larger than this size +is renamed to something unique and archived. + + +#define MAX_NET_DEAD_TIME 1800 + The maximum number of seconds allowed for a player to be "disconnected +but not having quit". Players whose link dies are normally moved to ROOM_FREEZER +where they stay until their link is re-established. If it doesn't happen in +the specified number of seconds, their player object if force-quit. + + +#define MIN_HISTORY_SIZE 20 +#define MAX_HISTORY_SIZE 30 + The number of lines stored in a player's command history buffer. + + +#define LOGON_TIMEOUT 360 + If a user does not complete their login within this number of seconds, +their connection is dropped. + + +#define IDLE_TIMEOUT 3600 + If a player is idle for this number of seconds, they are force-quit. + + +#define LINK_WAIT_PERIOD 1800 + Unsupported. This is part of a multi-character play control system that +may or may not work in Dead Souls 2. + + +#define MAX_PASSWORD_TRIES 3 +#define MIN_USER_NAME_LENGTH 2 +#define MAX_USER_NAME_LENGTH 15 +#define MAX_USER_CAP_NAME_LENGTH 20 + Self explanatory. The "cap name" indicates the special name that a player may +have which includes special characters. This name is spacified on character +creation. + + +#define LOCKED_ACCESS_ALLOWED ({ "SECURE", "ASSIST", "ELDER", "TEST" }) + Members of these user groups are allowed to log in when the mud is locked. + + +#define SUPPORTED_CLIENTS ({ "amcp", "amcp/1.1" }) + UNSUPPORTED. This is a remote administration protocol that has not been made +to work on Dead Souls 2. + + +#define HOUR_LENGTH 1200 +#define DAY_LENGTH 20 + Mud-time definitions. Dead Souls hours and days are shorter than "real world" +hours and days. Here is where that is specified. + + +#define MAX_NEWBIE_LEVEL 3 + Players below this level get special treatment. They gain access to +special newbie areas, can see in the dark, and understand all languages. + + +#define AUTOSAVE_TIME 450 + Interval between automatic saves in users. + + +#define MORTAL_POSITIONS ({ "player", "high mortal", "ambassador" }) + Unsupported. Part of a roles system that does not apply to Dead Souls 2 +by default. + + +#define DEFAULT_GRAVITY 1.0 + Affects the amount of stuff players can carry. + + +#define DEFAULT_ITEM_MESSAGE "You do not see that here." + Self explanatory. + + +#define RESET_INTERMUD 0 + If this is a nonzer integer, your intermud data cache will be wiped on reboot. + + +#define ENGLISH_ONLY 0 + Forces the use of English only for users. + + +#define HUMANS_ONLY 0 + Prevents new users from picking a race other than human. + + +#define PINGING_MUDS ({}) + Defines the muds used by the ping daemon for its periodic i3 +connection status check. If empty, you only ping yourself. It is +recommended to leave it empty. + + +#define PING_INTERVAL 290 + The number of seconds between automated i3 pings. + + +#define ENABLE_ENCUMBRANCE 0 + If this is a nonzero integer, players will find it near-impossible +to engage in successful combat if they're carring stuff. Anything that is +not worn or wielded creates a major obstacle to fighting. + + +#define GLOBAL_MONITOR 0 + If this is set to 1, all users are automatically snooped when they +connect and their sessions are logged in /secure/adm. + If this is set to 2, only non-admin users are logged this way. + + +#define PLAYER_KILL 0 + This must be set to a nonzero integer if playerkilling zones are +to work in the mud. + + +#define NPC_CATCH_TELL_DEBUG 0 + If a nonzero integer, then anything seen or heard by any NPC is +echoed to /domains/default/room/catchtell, along with some debugging +info. Recommendation: do not use this. It is noisier than you expect, +will tend to lag a busy mud, and is really for debugging purposes only. + + +#define SAME_IP_MAX 4 + The maximum number of connections permitted from an IP. IP's +from which an admin has previously logged in are excluded from this, +and IP's to be excluded from this can be specified in /secure/cfg/ip_unrestrict.cfg +(by adding the ip's on their own lines). + + +#define COMPAT_MODE 1 + This enables the lib to use defines that translate old code from +TMI-2 and Nightmare 3 (among others) into usable DS2 code on the fly. +See /secure/include/compat.h and /secure/sefun/legacy.c + + +#define RETAIN_ON_QUIT 1 + If this is a nonzero integer, when a character quits, her inventory is +saved, and it is restored to her when she logs back in. If this is zero, +then when a character quits, her inventory is moved to her environment, and +it is not restored to her when she logs back in. + Unique items are moved to the quitter's environment regardless of +what this is set to. + + +#define MAX_COMMANDS_PER_SECOND 10 + Defines for non-admins the maximum number of commands allowed per second. +This avoids both player scripting foolishness, and certain errors +that can occur when "command stacking" hundreds of commands per second that can +ruin things for everyone. + + +#define DEFAULT_PARSING 1 + If this is a nonzero integer, lib-based extension to the driver parser +will attempt re-parse ambiguous commands, making things like "drop book" +parse like "drop a book" if you have more than one. This adds some overhead +to each ambiguous command that needs to be reparsed, so disable it if you +are having performance problems. + + +#define CALL_OUT_LOGGING 0 + This will log the use of the call_out() efun by objects outside the +/daemon and /secure filesystems. Recommendation: do not use this. While it +has been fixed so it does not break things, this is strictly a debugging +tool to ferret out errors, not a "normal use" logger. + + +#define EVENTS_LOGGING 1 + A nonzero integer here will enable the logging of events initiated by the +events daemon. + + +#define DISABLE_REBOOTS 0 + A nonzero integer here will cause your mud's periodic reboots not to +occur. + + +#define BARE_EXITS 1 + A nonzero integer here allows the use of exits such that typing +"house" is possible, rather than "go house" or "enter house". This adds +some overhead to every command, so disable it if you are having performance +problems. + + +#define COMMAND_MATCHING 1 + A nonzero integer here allows the use of "shortest unique command matching". +This means you might, for example, be able to "gi book to knight" rather than +"give book to knight". This adds some overhead to every command, so disable it if +you are having performance problems. + + +#define OBJECT_MATCHING 1 + A nonzero integer here allows the use of "shortest unique object matching". +This means you might, for example, be able to "give bo to kni" rather than +"give book to knight". This adds some overhead to every command, so disable it if +you are having performance problems. + + +#define LIVEUPGRADE_SERVER "Dead Souls" + Deprecated. Specifies the mud to use for OOB liveupgrades. OOB liveupgrades +are no longer supported and have been replaced by the faster and more secure +web based liveupgrade system. + + +#define CARRIAGE_RETURN "\r" + In some cases, this pesky little character has to be wiped from files without +wiping the thing that specifies what character to wipe. This define helps avoid +problems when a file has to clean itself of this character. Don't change this. + + +#define OLD_STYLE_PLURALS 1 + A nonzero integer here allows you to use stuff like "book 2" or "2.book" +rather than "second book" in a command. This adds some overhead to every command, +so disable it if you are having performance problems. + + +#define NM_STYLE_EXITS 0 + A nonzero integer here enables the old "obvious exits" behavior, which was to +display them over the long desc in the form: [n, s, enter lodge] + Otherwise, they display below the long desc, in the form: +Obvious exits: north, south, enter lodge + + +#define WEB_SOURCE_IP "204.209.44.12" + Specifies the ip to use during liveupgrades. + + +#define WEB_SOURCE_NAME "lpmuds.net" + Specifies the website used for liveupgrades. This is often +necessary if the target webserver uses virtual hosts. + + +#define DESTRUCT_LOGGING 0 + If set to a nonzero integer, this enables the logging of +the destruct() efun being called on objects. You are strongly +advised not to enable this except in the most dire cases of +things breaking. + + +#define ROUTER_NAME "Alpha" +#define IRN_PASSWORD "Alpha" +#define IRN_PASSWORD1 "Bravo" +#define IRN_PASSWORD2 "Charlie" +#define IRN_PASSWORD3 "Delta" +#define ROUTER_TESTING 1 + Definitions specific to running an Intermud-3 router as +a node in an IRN (Inter Router Network). It is a good idea to +leave these settings alone unless you are 100% certain you +need to change them. + + +#define SEFUN_PLURALIZE 0 + Indicates whether you wish to override the driver's +built-in pluralize() efun with the sefun of the same name. + + +#define LOG_REMOTE_CHANS 0 + Controls the logging of remote (i.e. intermud) channels. Intermud +channels can be extremely spammy and if you are paying for diskspace +on a commercial host, logging them can lead to running out of room. + + +#define LOG_LOCAL_CHANS 1 + Controls the logging of channels local to your mud. + + +#define IMC2_CLIENT_PW "clientpass" +#define IMC2_SERVER_PW "serverpass" + Passwords for the IMC2 connection. These are automatically +changed into random strings when you first install your mud. If +you upgrade your mud, or reinstall, make sure you keep a copy of +the old randomized passwords and put them in the new config.h. + + +#define ENABLE_CGI 0 + Determines whether the built-in webserver will accept CGI +requests. This is required for CreWeb to work. Note that while +CreWeb attempts to avoid obvious security problems, maintaining +your mud's security is your responsibility. + + +#define WWW_DIR_LIST 0 + Determines whether directory listings are allowed on the +built-in webserver. This is required for CreWeb to work. See the +above note regarding security. + + +#define ENABLE_CREWEB 0 + Self explanatory. + + +#define F_TERMINAL_COLOR 1 + Old workaround to a strange FluffOS issue. May no longer +be needed, but I can't be bothered to check. + + +#define MAX_CALL_OUTS 750 + The call_out() efun is a way to schedule events. In MudOS this +efun's abuse could be the cause of grief, as overall mud performance +could be severely impacted. On FluffOS this is less of a concern, but +runaway callouts are still a threat to your mud's availability. The +number defined here is the threshold at which the mud will stop +accepting new callouts from unprivileged objects, such as things +in /realms/. Privileged, lib, and domain objects can still issue +callouts even if this threshold is reached. + + +#define REQUIRE_QUESTING 1 + By default, Dead Souls muds require players not just to have +enough XP to advance, but also to have been awarded quest points as +specified in PLAYERS_D. This define controls whether that +requirement is in force. + + +#define AUTO_ADVANCE 1 + Older versions of Dead Souls required that you visit a specific +NPC in the Adventurers' Hall and request advancement. If this define +is set to a nonzero integer, players will automatically advance when +they achieve the XP/QP requirement for their next level as specified +in PLAYERS_D, without having to go see Dirk. + + +#define MAX_INVENTORY_SIZE 2048 + If an object's inventory reaches this number of items, it will +stop accepting additional objects. This is intended to prevent the +accidental clogging of a mud through careless recursive coding. + + +#define MAX_ATTACKS_PER_HB 40 + If your creators have enabled godmode and have jacked up their +stats and skills to astronomical levels and then try to PK each other, +this define will prevent your mud from locking up as a result of +their foolishness. + + +#define MEMUSE_SOFT_LIMIT 0 + If the mud's memory use hits this limit, it will enter a +more aggressive posture regarding resets, garbage, and environmentless +objects. Non-privileged objects will be restricted from cloning +new objects until memory use is again below this limit. +IMPORTANT NOTE: The mud's memory use is NOT the same thing as +the memory allocated by the operating system. The actual amount +of memory in use is usually much much lower than the memory +allocation indicated in programs such as top. If you're going to +experiment with this, start with a low number, such as 10000000 +(10 million bytes, aka 10 megs). 0 here disables the limit. + + +#define MEMUSE_HARD_LIMIT 0 + If the mud's memory use hits this limit, it will try to +throw as much junk overboard as possible. If the memory use is +still above this limit after that attempt, the mud will then +schedule a reboot to occur within one minute. 0 here disables +the limit. + + +#define MAX_USERS 0 + LIB_CONNECT automatically determines how many players +your mud is theoretically able to handle. Based on this, +it establishes a maximum limit of players logged in simultaneously. +In some cases this estimation is overly generous, and it may +be necessary to limit maximum players to what your server +can actually handle, not what it can theoretically do. The +MAX_USERS define overrides the LIB_CONNECT calculated maximum. +Setting it to 0 allows LIB_CONNECT to figure the max out on its own. +Note that users in the LOCKED_ACCESS_ALLOWED groups defined +above are allowed to log in despite the player cap. + To find out the current limit: +eval return LIB_CONNECT->GetMaxPlayers() + + +#define MIN_PERF 2000 + Some fancy stuff, like object matching and overhead mapping, +require your mud server to have a minimum performance score for the +feature to work properly. This is where that score is set. The +closer to 0, the faster the computer. 2000 is a rather slow computer. + + +#define MINIMAP 1 + Whether players can have the minimap show up as part of their +room description data. + + +#define WIZMAP 1 + Whether creators can have the wizmap show up as part of their +room description data. + + +#define GRID 1 + Whether the mud grid system is enabled for your mud. This will +be overridden by the "minimum performance" score. If your computer +is too slow, the grid is disabled regardless of what this setting is. + + +#define ENABLE_INSTANCES 0 + If 1, the mud will assume it is an instance, and will apply +special naming conventions to savefiles. Your "dev instance" +should have this set to 0. Your "player instance" should have this +set to 1. If you don't know what this stuff means, LEAVE IT AT 0. +For more info: help instances + + +#endif /* s_config_h */ + End configuration. diff --git a/lib/doc/help/creators/creation b/lib/doc/help/creators/creation new file mode 100644 index 0000000..0161a9f --- /dev/null +++ b/lib/doc/help/creators/creation @@ -0,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 --git a/lib/doc/help/creators/creator b/lib/doc/help/creators/creator new file mode 100644 index 0000000..1ffa305 --- /dev/null +++ b/lib/doc/help/creators/creator @@ -0,0 +1,44 @@ +A creator (sometimes also called a wizard or wiz) is +a user on the mud that has access to special commands +that allow for the manipulation of game data. + +A creator can, with some restrictions, edit files, +modify stats, create new rooms, objects, and NPC's. +They, like admins, are mud staff and share the +responsibility of improving and enhancing it. + +If you are a new creator, take the time to get familiar +with how the mud works. You have your very own workroom. +To go to it, type: home + +There you can open your chest and get a standard set +of creator tools (sometimes also called wiztoys) and +get a sense for how things work. + +Remember that although you have fantastic, superhuman +powers, you must use them responsibly. You have, for +example, the zap command, which lets you kill almost +anything instantly. Having the command, however, is +not permission to run through the mud zapping every +mob you see. Talk to your admin about what is ok +and not ok. + +If you are new to this kind of mud, read the Player's +Handbook. If you dont have one on you, type: + +clone /domains/default/obj/handbook +read chapter 1 in handbook +read chapter 2 in handbook + +And so on. Once you've read the handbook, read over +the Creator FAQ at http://dead-souls.net/ds-creator-faq.html +and when you feel ready to start using your Creator +powers, start reading the Creator's Manual. + +Contributing to a mud can be hard work, and if you've +never done it before, it'll be a steep learning curve. +However, remember that this mud has tons of documentation, +and this kind of mud is one of the easiest for newcomers. +Just relax, take your time, and don't get stressed. + + diff --git a/lib/doc/help/creators/creator_general b/lib/doc/help/creators/creator_general new file mode 100644 index 0000000..7d24530 --- /dev/null +++ b/lib/doc/help/creators/creator_general @@ -0,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 --git a/lib/doc/help/creators/creweb b/lib/doc/help/creators/creweb new file mode 100644 index 0000000..57bd765 --- /dev/null +++ b/lib/doc/help/creators/creweb @@ -0,0 +1,77 @@ +Creweb is a set of CGI scripts written in LPC that +together with the mud web server allow creators to +view and edit their files from the internet, using +their browser. + +A creator simply visits the mud home page and clicks on +the CreWeb link, then uses their mud name and mud +password to login. + +The interface is primitive, just plain old black-on +white and HTML form controls. Perhaps a better way to +look at is is "clean and uncluttered". + +Creators can upload files, and edit files. However, +they cannot navigate beyond their home directory. This +is for security reasons, and probably will not change. + +To enable CreWeb on your mud: + +1) Choose a port for your web server. In this example + we'll use port 8001 + + +2) Issue the following commands: + +mudconfig http port 8001 +mudconfig http disable +mudconfig cgi enable +mudconfig dirlist enable +mudconfig creweb enable +mudconfig http enable + + +3) Use your favorite browser to go to port 8001 on your + mud computer. For example: + +http://your.mud.address:8001 + + +4) Click on the CreWeb link, log in, and have fun! + + +Important things to keep in mind about CreWeb: +--------------------------------------------- + +* This is an experimental system. It probably contains +bugs or problems. + +* It requires cookies and javascript enabled. + +* It was built with security as a priority but it is +still a web-facing file modification system, meaning it +is not and never can be 100% safe. + +* If you decide not to use it, just use the following +command to disable it: mudconfig creweb disable + +* It is intentionally limited to home directories +only. You are strongly advised not to try to change +CreWeb to circumvent this. + +* If you need to use CreWeb to edit files outside your +home directory, simply copy them into your home directory +while logged into the mud, edit, then copy them back. + +* Users of Microsoft Internet Explorer may have occasional +difficulty when editing files. This is due to IE's default +cache behavior. Change your preferences to reload pages: +Tools->General->Settings->Every visit to the page + Then logout of creweb and restart IE. + +* Despite my best efforts, users of IE still sometimes have +problems. If you keep getting weird stuff like not being +able to write to a file, or being unable to display the +page, try using Firefox instead. And complain to MS. :( + + diff --git a/lib/doc/help/creators/debug_hints b/lib/doc/help/creators/debug_hints new file mode 100644 index 0000000..5cbd7d9 --- /dev/null +++ b/lib/doc/help/creators/debug_hints @@ -0,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 --git a/lib/doc/help/creators/debug_macro b/lib/doc/help/creators/debug_macro new file mode 100644 index 0000000..093e047 --- /dev/null +++ b/lib/doc/help/creators/debug_macro @@ -0,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 --git a/lib/doc/help/creators/debugging b/lib/doc/help/creators/debugging new file mode 100644 index 0000000..6567b98 --- /dev/null +++ b/lib/doc/help/creators/debugging @@ -0,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 --git a/lib/doc/help/creators/ds b/lib/doc/help/creators/ds new file mode 100644 index 0000000..ed2ab7b --- /dev/null +++ b/lib/doc/help/creators/ds @@ -0,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 --git a/lib/doc/help/creators/editor b/lib/doc/help/creators/editor new file mode 100644 index 0000000..db505fa --- /dev/null +++ b/lib/doc/help/creators/editor @@ -0,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 --git a/lib/doc/help/creators/emotes b/lib/doc/help/creators/emotes new file mode 100644 index 0000000..728b269 --- /dev/null +++ b/lib/doc/help/creators/emotes @@ -0,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 --git a/lib/doc/help/creators/foo b/lib/doc/help/creators/foo new file mode 100644 index 0000000..e0ead42 --- /dev/null +++ b/lib/doc/help/creators/foo @@ -0,0 +1,21 @@ +foo /foo/ 1. /interj./ Term of disgust. 2. Used very generally as a sample name for absolutely anything, esp. programs and files (esp. scratch files). 3. First on the standard list of metasyntactic variables used in syntax examples. See also bar, baz, qux, quux, corge, grault, garply, waldo, fred, plugh, xyzzy, thud. + +The etymology of hackish `foo' is obscure. When used in connection with `bar' it is generally traced to the WWII-era Army slang acronym FUBAR (`Fucked Up Beyond All Repair'), later bowdlerized to foobar. (See also FUBAR.) + +However, the use of the word `foo' itself has more complicated antecedents, including a long history in comic strips and cartoons. The old "Smokey Stover" comic strips by Bill Holman often included the word `FOO', in particular on license plates of cars; allegedly, `FOO' and `BAR' also occurred in Walt Kelly's "Pogo" strips. In the 1938 cartoon "The Daffy Doc", a very early version of Daffy Duck holds up a sign saying "SILENCE IS FOO!"; oddly, this seems to refer to some approving or positive affirmative use of foo. It has been suggested that this might be related to the Chinese word `fu' (sometimes transliterated `foo'), which can mean "happiness" when spoken with the proper tone (the lion-dog guardians flanking the steps of many Chinese restaurants are properly called "fu dogs"). + +Paul Dickson's excellent book "Words" (Dell, 1982, ISBN 0-440-52260-7) traces "Foo" to an unspecified British naval magazine in 1946, quoting as follows: "Mr. Foo is a mysterious Second World War product, gifted with bitter omniscience and sarcasm." + +Other sources confirm that `FOO' was a semi-legendary subject of WWII British-army graffiti more-or-less equivalent to the American Kilroy. Where British troops went, the graffito "FOO was here" or something similar showed up. Several slang dictionaries aver that FOO probably came from Forward Observation Officer. In this connection, the later American military slang `foo fighters' is interesting; at least as far back as the 1950s, radar operators used it for the kind of mysterious or spurious trace that would later be called a UFO (the older term resurfaced in popular American usage in 1995 via the name of one of the better grunge-rock bands). + +Earlier versions of this entry suggested the possibility that hacker usage actually sprang from "FOO, Lampoons and Parody", the title of a comic book first issued in September 1958, a joint project of Charles and Robert Crumb. Though Robert Crumb (then in his mid-teens) later became one of the most important and influential artists in underground comics, this venture was hardly a success; indeed, the brothers later burned most of the existing copies in disgust. The title FOO was featured in large letters on the front cover. However, very few copies of this comic actually circulated, and students of Crumb's `oeuvre' have established that this title was a reference to the earlier Smokey Stover comics. + +An old-time member reports that in the 1959 "Dictionary of the TMRC Language", compiled at TMRC, there was an entry that went something like this: + + FOO: The first syllable of the sacred chant phrase "FOO MANE + PADME HUM." Our first obligation is to keep the foo counters + turning. + +For more about the legendary foo counters, see TMRC. Almost the entire staff of what later became the MIT AI Lab was involved with TMRC, and probably picked the word up there. + +Very probably, hackish `foo' had no single origin and derives through all these channels from Yiddish `feh' and/or English `fooey'. diff --git a/lib/doc/help/creators/force b/lib/doc/help/creators/force new file mode 100644 index 0000000..561c859 --- /dev/null +++ b/lib/doc/help/creators/force @@ -0,0 +1,4 @@ +Syntax: <force LIVING SOMETHING> + <force LIVING to DO SOMETHING> +Allows you to command some living things to do +your bidding. diff --git a/lib/doc/help/creators/grid b/lib/doc/help/creators/grid new file mode 100644 index 0000000..915c602 --- /dev/null +++ b/lib/doc/help/creators/grid @@ -0,0 +1,36 @@ + Dead Souls Grid System + + The Dead Souls grid is a dynamically generated coordinate system +that assigns x,y,z coordinates to each room, as possible. When a room +is loaded, it checks ROOMS_D for its own coordinates. If it lacks +coordinates, it checks for the coordinates of neighboring rooms and tries +to calculate its own coordinates and reports them to ROOMS_D. + + The idea of rooms with coordinates is to allow for game mechanics +that work across rooms, such as directional teleports, cross-room combat, +and the like. It is not necessary for every mud, and it can be disabled +in config.h if you don't want it. + + If you've created a new domain and it doesn't seem to be included +in the grid, ensure your domain has a room named room/start.c , and +set the coordinates for that room to be something that either makes +sense for the coordinates of the rest of the mud, or that are certain +not to conflict with existing coordinates by being very far away from +everything else. In the start.c room's create() function, ensure +you have a directive that looks like this: + +SetCoordinates("9000,7000,0"); + + But, of course, with suitable x,y,z coordinates for your mud. + + Once you've done this, erase the existing grid cache and begin the +process of rebuilding it with mapper drones. The command to do this is: + +gridconfig reset + + It will take some time for the grid to rebuild, depending on the size +of your mud. You should be able to see the progress of that rebuild in +the wizmap, if you have enabled that functionality. + +See also: gridconfig, wizmap, minimap + diff --git a/lib/doc/help/creators/instances b/lib/doc/help/creators/instances new file mode 100644 index 0000000..9bb2b54 --- /dev/null +++ b/lib/doc/help/creators/instances @@ -0,0 +1,121 @@ +What are instances? +------------------- + +Instances are separate muds that run from the same Dead Souls +installation directory, but that communicate with each other. + +The reason to have separate muds is to be able to test code +on a test mud, without affecting what is happening on the +other mud. + +The reason to have them communicate is that the MU in MUD +stands for "Multi User" and it's nice to have more users +communicating rather than fewer. + +What instances let you do, for example, is have a "build/dev" +mud running on, say, port 8888, and a "player mud" running +on port 6666. Creators can chat with people on the player +mud while developing on the dev mud. But if they screw something +up big-time, the folks on the player mud are somewhat isolated from +catastrophe. Creators also can't mess with players on the other +mud, nor give them cheat items and such...because they're +"physically" isolated. Only communication goes back and forth. + + +Do I need to use instances? +--------------------------- + +Very very very few people will have use for this. Instances +are largely something that is useful to me, Cratylus, in my +project. If you don't immediately understand the point of +instances and go "YES! EXACTLY WHAT I NEED!" then you can +just stop reading now and forget about them. + + +What should I know in general? +------------------------------ + +- Instances use a concept of a "global" instance and client +instances. The global instance is the first instance: the mud +you installed. Instances you create must be created from the +global instance. + +- Client instances don't speak to each other, only to the global +instance. + +- Don't fiddle with ENABLE_INSTANCES in config.*. This setting +is meant to be manipulated by the instconfig command only. You +should leave that define alone in the global instance, and +leave it alone also in the client instances. + + +How do I get it going on Linux? +------------------------------- + +To get a second instance of your mud running if the +new port is 8888 and the instance name is "Foo": + +- Get the mud running the normal way. Create an admin char, etc. +- Once it's up, login as an administrator. +- Uncomment the instances line in /secure/cfg/preload.cfg +- Type: instconfig create Foo 8888 +- Copy /secure/cfg/mudos.8888.cfg into bin/ +- Go into bin/ and type: ./driver ./mudos.8888.cfg +- Ta-daa! + + +How do I get it going on Microsoft Windows? +------------------------------------------- + +To get a second instance of your mud running if the +new port is 9999 and the instance name is "Bar": + +- Get the mud running the normal way. Create an admin char, etc. +- Once it's up, login as an administrator. +- Uncomment the instances line in /secure/cfg/preload.cfg +- Type: instconfig create Bar 9999 +- Copy lib\secure\cfg\runmud_9999.bat into your mud's top-level + install directory (the same place you'll find runmud.bat) +- Go into your mud's top-level install directory and double- + click on runmud_9999.bat +- Ta-daa! + + +Warnings +-------- + +- Instances are a somewhat advanced feature. If you're new to +Dead Souls, you should concentrate on basics. If you're a newbie +and have problems dealing with instances, it will be very very +difficult for me to extract from you the information I need +to help you, so you'll need to be very rigorous in reporting +problems: http://www.chiark.greenend.org.uk/~sgtatham/bugs.html + +- I don't know what happens if you set up an instance with the +same port number as the global instance. If you actually do this, +please keep it to yourself. I'd rather not know. + +- The instance communication protocol is quite primitive and +only allows for instances to communicate with the global instance. + +- You can't create a character with the same name on another +instance. This is for security reasons. If you need to have a +character with the same name on instance foo, you'll need to +copy the user file. for example: + +cp testyguy.o testyguy.8888.o + +Note that whatever privileges are in effect for testyguy on the +global instance will be in effect in the client instance, since +all instances use the same groups.cfg file. You are very much +copying the same player to the new instance, not making a "new" +player. + +- If you have the slightest concern that instances pose a security +risk, do not use them. In fact, *don't* use them, unless you grok +the code completely. For the most part I'm including this in the +distribution as a convenience and favor to me, because i am awesome +and I deserve it, so don't be surprised if it doesn't suit you, +and please understand what you're reporting if you do want to +report a problem. + diff --git a/lib/doc/help/creators/messaging b/lib/doc/help/creators/messaging new file mode 100644 index 0000000..bea8758 --- /dev/null +++ b/lib/doc/help/creators/messaging @@ -0,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 --git a/lib/doc/help/creators/mssp b/lib/doc/help/creators/mssp new file mode 100644 index 0000000..5a4fd74 --- /dev/null +++ b/lib/doc/help/creators/mssp @@ -0,0 +1,21 @@ +MSSP is a protocol that allows someone else's internet program to +connect to your mud and ask it for information. For example, your +mud's name, how many players are on, what your theme is, etc. + +It's useful because it lets you maintain an up to date +source of information on your mud for multiple mud listing +sites, without having to schlep to each one to update your +listing to keep it current. + +To change your MSSP info, edit /secure/include/mssp.h and +change the fields you feel need changing. + +VITALLY IMPORTANT NOTE: If you modify information in that +file and create broken LPC code, you may render your mud +impossible to log into, and unbootable. Make 100% certain you +back up this file before editing it, and once you edit it, +make sure it works by updating LIB_CONNECT. + +bk /secure/include/mssp.h +update /secure/lib/connect.c + diff --git a/lib/doc/help/creators/plan b/lib/doc/help/creators/plan new file mode 100644 index 0000000..dac03b1 --- /dev/null +++ b/lib/doc/help/creators/plan @@ -0,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 --git a/lib/doc/help/creators/profile b/lib/doc/help/creators/profile new file mode 100644 index 0000000..026bcfd --- /dev/null +++ b/lib/doc/help/creators/profile @@ -0,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 --git a/lib/doc/help/creators/qcs b/lib/doc/help/creators/qcs new file mode 100644 index 0000000..71290c7 --- /dev/null +++ b/lib/doc/help/creators/qcs @@ -0,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 --git a/lib/doc/help/creators/security b/lib/doc/help/creators/security new file mode 100644 index 0000000..e482ff9 --- /dev/null +++ b/lib/doc/help/creators/security @@ -0,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 --git a/lib/doc/help/creators/shadows b/lib/doc/help/creators/shadows new file mode 100644 index 0000000..af0726e --- /dev/null +++ b/lib/doc/help/creators/shadows @@ -0,0 +1,83 @@ +Shadows are means to simulate the addition +of functions to an already existing object. + +For example, one way to "enchant" a player might +be to make it so that any object that tries to +do damage to her fails. This would mean that +somehow you have to override eventReceiveDamage in +that player (there are other ways, but let's pretend +this is a good idea). + +A shadow would do it. You could code an with +the following code: + +varargs int eventReceiveDamage() { +return 0; +} + +And then use the shadow() efun to attach it to +the player. Now when something tries to call the +eventReceiveDamage function on the player, the +shadow intercepts that call, and nothing happens at all. + +Neat, huh? + +There are, however, problems with shadows, which +we'll go over here: + +1) SECURITY +----------- +The main problem with shadows is security. If anybody on +a mud can create shadows, then your mud basically +has no security at all, because a creator can enshadow +an admin (or some other privileged object) in such +a way as to elevate their own privilege. + +This would be bad. + +The way this is handled in Dead Souls is that the mud +won't allow an object to be shadowed unless the shadowing +object's code lives in /shadows. This means that it takes +an admin to put the code there so that at least there is +someone who *should* know what they're doing who is +responsible for putting this code into play. + +This "only stuff in the /shadows directory" behavior +is defined in the valid_shadow() master apply. + +2) MANAGEMENT +------------- +The other headache when it comes to shadows is managing +them. The MudOS shadow() efun is simple enough to use, +but suppose an object has more than one shadow and you +only want to remove one. This is problematic because +remove_shadow() doesn't distinguish between shadows...it'll +remove *all* shadows from an object. While this may sometimes +be desirable, it may not always be the right thing. + +Starting in Dead Souls 2.5a8, a system for basic management +of multiple shadows is included. The system relies on the +following rules on a mud to work properly: + +*) All shadows must inherit LIB_SHADOW. +*) Any shadow must be attached to an object via the eventShadow() lfun. +*) Any shadow must be removed via the eventUnshadow() lfun. + +This is because tangible items (cans of spam, swords, players, etc) +now all inherit LIB_SHADOW_HOOK. What this means is that any shadow +that is to be attached to an item will first identify itself to +the item, and that item will maintain a list of objects that are +shadowing it. This allows you to query that item for its shadows, +and to then remove individual shadows. For example: + +find_player("xyzzy")->GetShadows() +find_player("xyzzy")->eventUnshadow(find_object("/shadows/clan#9")) + +So that only that specific shadow is removed from Xyzzy. + +Note that this system does not prevent people from using +shadow() and remove_shadow() independently, so for things to +work properly, your mud needs to have it be a standard that +shadows are removed and attached according to the rules above. + +For more information on shadows in general, please see: /doc/guide/chapter07 diff --git a/lib/doc/help/creators/staff b/lib/doc/help/creators/staff new file mode 100644 index 0000000..5908253 --- /dev/null +++ b/lib/doc/help/creators/staff @@ -0,0 +1,26 @@ + 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", and it must be somewhere in +/secure. See /secure/obj/glasses.c for an example. + + diff --git a/lib/doc/help/players/alias b/lib/doc/help/players/alias new file mode 100644 index 0000000..8253d74 --- /dev/null +++ b/lib/doc/help/players/alias @@ -0,0 +1,30 @@ +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 see a specific alias, like gc: %^GREEN%^alias gc%^RESET%^ + +To remove an alias, type unalias plus the alias, like so: + +%^GREEN%^unalias gc%^RESET%^ + + diff --git a/lib/doc/help/players/banking b/lib/doc/help/players/banking new file mode 100644 index 0000000..fa06bd0 --- /dev/null +++ b/lib/doc/help/players/banking @@ -0,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 --git a/lib/doc/help/players/channel b/lib/doc/help/players/channel new file mode 100644 index 0000000..3d984e0 --- /dev/null +++ b/lib/doc/help/players/channel @@ -0,0 +1 @@ +See: help channels diff --git a/lib/doc/help/players/channels b/lib/doc/help/players/channels new file mode 100644 index 0000000..d0f205f --- /dev/null +++ b/lib/doc/help/players/channels @@ -0,0 +1,64 @@ + 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 mage class +priest - channel for the priest class +explorer - channel for the explorer class +admin - only admins hear this +muds - announcements of muds connecting or disconnecting from i3 +intermud - announcmenets of things like remote fingers and who + +The following are intermud channels: + +ds - Dead Souls mud code talk +ds_test - testing testing 1, 2, 3, etc +intergossip - general offtopic stuff +dchat - friendly 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 +list german@dead souls demo + +To see a brief history of channel messages: +hist newbie + +See also: +mute, gag, earmuff, unmuff, lines, hist, chancolors diff --git a/lib/doc/help/players/chat b/lib/doc/help/players/chat new file mode 100644 index 0000000..3d984e0 --- /dev/null +++ b/lib/doc/help/players/chat @@ -0,0 +1 @@ +See: help channels diff --git a/lib/doc/help/players/classes b/lib/doc/help/players/classes new file mode 100644 index 0000000..b34f577 --- /dev/null +++ b/lib/doc/help/players/classes @@ -0,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 --git a/lib/doc/help/players/communication b/lib/doc/help/players/communication new file mode 100644 index 0000000..9115680 --- /dev/null +++ b/lib/doc/help/players/communication @@ -0,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 --git a/lib/doc/help/players/credits b/lib/doc/help/players/credits new file mode 100644 index 0000000..fa91d4b --- /dev/null +++ b/lib/doc/help/players/credits @@ -0,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 --git a/lib/doc/help/players/deviation b/lib/doc/help/players/deviation new file mode 100644 index 0000000..f0e0769 --- /dev/null +++ b/lib/doc/help/players/deviation @@ -0,0 +1,84 @@ +By default, Dead Souls uses body characteristics of different races +(e.g. ogres, deer, fish, human) to calculate all sorts of things... +combat effectiveness, learning proficiency, etc. Some of these +characteristics are "stats", like strength or intelligence. + +For example, orcs can be formidable warriors because their +starting strength stats tend to be very high. In addition, +strength is high in importance to the orc body...its "stat class", +or how important it is, is 1, which is the highest level of +importance. This means that orc players increase the strength +stat by one point every time they are promoted one player level. + +Therefore an orc player who started with a strength stat of 40 +would have a strength stat of 50 upon reaching level 11. + +Humans, however, have a low starting strength and the human +stat class for strength is 3, meaning that human players get a +strength point added every 3 level promotions. A human with +a starting strength stat of 15 would, upon reaching level 11, +have reached a strength stat of 18. + +This can seem a little unfair to a person that wants to play +a human warrior...and in a way it *is* somewhat unfair, since it's +entirely possible for there to be freakishly strong humans or +humans who devote themselves to becoming very very strong. + +One way to make up for this is to use "customization points". +They allow you to add a small number of stat points to the +stats you feel are most important. But you only get 15 customization +points ever, and they go quick. And even if you use all of them +to jack up a stat...if that stat has a low stat class you'll +always be lagging behind. + +For example, if our human warrior jacks up her strength from +15 to 30 by using up all her customization points in that stat, +she'll still be struggling somewhat against physically stronger +races of her same player level. + +Similarly, orcs tend to have low starting intelligence and +a dismal intelligence stat class. This makes playing an orc +mage a torturous experience, such that it would be quite +rare to ever see a player choose that race and class combination. +But orc mages do exist in some settings, and making it practically +impossible seems a bit unfair. + +Stat deviation is a way of helping make it possible to have +these unusual class and race combinations without torturing +players unnecessarily for them. Stat deviation is an alteration +of a player's stat class which allows them to gain stat points +more quickly than her racial defaults normally would allow. This +alteration comes at the cost of a percentage of experience points +gained while so deviated. + +For example, our human warrior princess could choose to deviate +her stat class from the default of 3 to a more favorable 2, +allowing her to gain a strength point every other level, rather than +every third level. + +Each deviation point comes at a 22% cost of XP gained, meaning that +once she deviates by one point, killing a monster that would normally +earn her 1000 XP now earns her 780 XP. If she wants to max out on +the strength stat class and use 2 deviations on it, it'll cost her +44% of the XP she gains from then on, meaning a 1000 XP monster +for her is now just worth 560 XP. + +Clearly deviations are severely expensive, and will tend to slow +down a player's overall advancement, but they do offer the possibility +of playing the kind of race with the kind of class you prefer, facing +opponents with a more class appropriate set of attributes. Rather +than it being, for example, practically impossible to reach level +20 as an orc mage, and being nearly useless as an orc mage even at +that level, deviating right would actually *allow* you to reasonably +hope you could get to that level one day, and that at that level you +would actually be able to stand up to nearly-level-appropriate opponents. + +Since deviation is something that involves your character's devotion +to improving herself and doing things in a way that is different from +others of her race, it makes sense that there is a cost (XP) but +also that it cannot be revoked. Once you deviate, you're a deviant +forever, so think long and hard before using the "deviate" command. +You may not miss the XP now, but you might miss them later, when you're +a mighty player and that 22% is now thousands of XP. + +See also: deviate, customize, stat, score diff --git a/lib/doc/help/players/handbook b/lib/doc/help/players/handbook new file mode 100644 index 0000000..e1ea7ae --- /dev/null +++ b/lib/doc/help/players/handbook @@ -0,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 +kind of edged weapon. diff --git a/lib/doc/help/players/languages b/lib/doc/help/players/languages new file mode 100644 index 0000000..1f806f8 --- /dev/null +++ b/lib/doc/help/players/languages @@ -0,0 +1,45 @@ + 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%^ + +To switch your default language to Valar (if you know it): + +%^GREEN%^speak in valar%^RESET%^ + +This makes you use the Valar language whenever you "say" something. + + +See also: language, ask, shout, speak diff --git a/lib/doc/help/players/list b/lib/doc/help/players/list new file mode 100644 index 0000000..8d4939e --- /dev/null +++ b/lib/doc/help/players/list @@ -0,0 +1,8 @@ +Displays who is listening to a given channel. To know who +is listening to ds on your mud, type: + +list ds + +To know who is listening to ds on another mud: + +list ds@dead souls diff --git a/lib/doc/help/players/locate b/lib/doc/help/players/locate new file mode 100644 index 0000000..3bf2f63 --- /dev/null +++ b/lib/doc/help/players/locate @@ -0,0 +1,2 @@ +To find someone on Intermud-3: i3locate +If you are a creator looking for stuff in this mud, see: find, whereis, findobj diff --git a/lib/doc/help/players/map b/lib/doc/help/players/map new file mode 100644 index 0000000..6136d38 --- /dev/null +++ b/lib/doc/help/players/map @@ -0,0 +1 @@ +See: help automap diff --git a/lib/doc/help/players/mapping b/lib/doc/help/players/mapping new file mode 100644 index 0000000..6136d38 --- /dev/null +++ b/lib/doc/help/players/mapping @@ -0,0 +1 @@ +See: help automap diff --git a/lib/doc/help/players/nickname b/lib/doc/help/players/nickname new file mode 100644 index 0000000..9e16086 --- /dev/null +++ b/lib/doc/help/players/nickname @@ -0,0 +1,9 @@ +This command permits you to substitute names, typically +so you can avoid typing out long or complicated names all +the time. For example, if you do the following: + +%^GREEN%^nickname crat cratylus%^RESET%^ + +You can then do stuff like: + +%^GREEN%^tell crat hi!%^RESET%^ diff --git a/lib/doc/help/players/password b/lib/doc/help/players/password new file mode 100644 index 0000000..5d83a14 --- /dev/null +++ b/lib/doc/help/players/password @@ -0,0 +1,5 @@ +Users can change their own passwords with the command: passwd + +Admins can change someone else's password with: resetpasswd + + diff --git a/lib/doc/help/players/player_general b/lib/doc/help/players/player_general new file mode 100644 index 0000000..5f3e045 --- /dev/null +++ b/lib/doc/help/players/player_general @@ -0,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 --git a/lib/doc/help/players/points b/lib/doc/help/players/points new file mode 100644 index 0000000..f6ea05f --- /dev/null +++ b/lib/doc/help/players/points @@ -0,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 --git a/lib/doc/help/players/races b/lib/doc/help/players/races new file mode 100644 index 0000000..82dec3f --- /dev/null +++ b/lib/doc/help/players/races @@ -0,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 --git a/lib/doc/help/players/unalias b/lib/doc/help/players/unalias new file mode 100644 index 0000000..7122341 --- /dev/null +++ b/lib/doc/help/players/unalias @@ -0,0 +1 @@ +See: help alias diff --git a/lib/doc/help/players/vendors b/lib/doc/help/players/vendors new file mode 100644 index 0000000..54cea3c --- /dev/null +++ b/lib/doc/help/players/vendors @@ -0,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 --git a/lib/doc/help/players/wordwrap b/lib/doc/help/players/wordwrap new file mode 100644 index 0000000..97554aa --- /dev/null +++ b/lib/doc/help/players/wordwrap @@ -0,0 +1,35 @@ +Different clients do different things. Dead Souls tries to handle +the most common setups automatically. This may not be enough for you. + +Here are some common issues: + +1) You set the screen to something (like 100 50) but it keeps changing + to something else. + +This is usually because your client is sending invisible resizing commands +to the mud, and the mud is honoring those commands. To stop this, you +lock your screen settings, and then set the screen parameters: +%^GREEN%^ +screenlock on +screen 100 50 +%^RESET%^ + +2) You set your width and/or height to a very large number but it's + smaller when you check it. + +Your screen setting tries to limit itself to the size of the mud's +maximum printable string size...a number which is fairly arbitrary and +mostly there to avoid excessive spamming of players. This limit can +only be changed by an administrator willing to recompile the driver +with a changed value for the LARGEST_PRINTABLE_STRING opton. + + +3) You set your width to something very large but not all text goes that wide. + +Some text, like this file, are written with hard returns somewhere before the +80th column. This is usually due to a preference the author has, and is +common among lib folks of a certain vintage. If you find instances where +this is particularly unattractive, talk it over with your admin to see +if they want to add it to their list of things to clean up. + +See also: env, terminal diff --git a/lib/doc/help/players/wrapping b/lib/doc/help/players/wrapping new file mode 100644 index 0000000..bde541e --- /dev/null +++ b/lib/doc/help/players/wrapping @@ -0,0 +1 @@ +See: wordwrap diff --git a/lib/doc/help/races/ooga b/lib/doc/help/races/ooga new file mode 100644 index 0000000..532e5c4 --- /dev/null +++ b/lib/doc/help/races/ooga @@ -0,0 +1 @@ +Oogas believe that everything wuld be better if we could just learn from tribal folks and really love nature. diff --git a/lib/doc/help/races/orc b/lib/doc/help/races/orc new file mode 100644 index 0000000..2096c2c --- /dev/null +++ b/lib/doc/help/races/orc @@ -0,0 +1 @@ +Orcs tend to smell bad, be aggressive, and express themselves poorly. diff --git a/lib/doc/help/races/poleepkwa b/lib/doc/help/races/poleepkwa new file mode 100644 index 0000000..5aec864 --- /dev/null +++ b/lib/doc/help/races/poleepkwa @@ -0,0 +1,3 @@ +Poleepkwa are a large, bipedal race bearing a strong resemblance to insects. The most commonly encountered poleepkwa are soldier drones: extremely strong but unwise, unintelligent, and uncharismatic. They also tend to change little over time as they gain experience: their stats improve very slowly. + +Due to the severe challenges of poleepkwa psychology and physiology, only very experienced players should choose this as a race. diff --git a/lib/doc/lfun/README b/lib/doc/lfun/README new file mode 100644 index 0000000..4286e84 --- /dev/null +++ b/lib/doc/lfun/README @@ -0,0 +1,11 @@ +This directory contains lfun, or library function, documentation. +The complete bunch is in the all/ subdirectory. In the lib/ +subdirectory you will find functions broken down by the files +in which they are found. + +Note that some function labels, such as static, nomask, and the +like, may be inconsistent betwee what is listed here and what +you find in the file. + +-Cratylus +November 2006 diff --git a/lib/doc/lfun/all/AddAlcohol b/lib/doc/lfun/all/AddAlcohol new file mode 100644 index 0000000..3ea9aa8 --- /dev/null +++ b/lib/doc/lfun/all/AddAlcohol @@ -0,0 +1,24 @@ +ADDALCOHOL + +NAME + AddAlcohol() + +SYNOPSIS + int AddAlcohol(int x) + +DESCRIPTION + Arbitrarily add alcohol to the creature by the amount indicated by the passed integer. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + GetAlcohol + +Author + Cratylus + diff --git a/lib/doc/lfun/all/AddCaffeine b/lib/doc/lfun/all/AddCaffeine new file mode 100644 index 0000000..c39ac8c --- /dev/null +++ b/lib/doc/lfun/all/AddCaffeine @@ -0,0 +1,24 @@ +ADDCAFFEINE + +NAME + AddCaffeine() + +SYNOPSIS + int AddCaffeine(int x) + +DESCRIPTION + Arbitrarily add caffeine to the creature by the amount indicated by the passed integer. + +EXAMPLES + present("junkie",environment(this_player()))->AddCaffeine(10) + +LOCATION + /lib/body + + +SEE ALSO + GetCaffeine + +Author + Cratylus + diff --git a/lib/doc/lfun/all/AddChannel b/lib/doc/lfun/all/AddChannel new file mode 100644 index 0000000..0e72e99 --- /dev/null +++ b/lib/doc/lfun/all/AddChannel @@ -0,0 +1,24 @@ +ADDCHANNEL + +NAME + AddChannel() + +SYNOPSIS + string array AddChannel(mixed val) + +DESCRIPTION + Adds a channel to the list of those accessible to the user. + +EXAMPLES + + +LOCATION + /lib/chat + + +SEE ALSO + AddChannel, RemoveChannel, GetChannels, returnChannels + +Author + Cratylus + diff --git a/lib/doc/lfun/all/AddDrink b/lib/doc/lfun/all/AddDrink new file mode 100644 index 0000000..aba5f6e --- /dev/null +++ b/lib/doc/lfun/all/AddDrink @@ -0,0 +1,24 @@ +ADDDRINK + +NAME + AddDrink() + +SYNOPSIS + int AddDrink(int x) + +DESCRIPTION + Arbitrarily add "drink points" to the creature by the amount indicated by the passed integer. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + GetDrink + +Author + Cratylus + diff --git a/lib/doc/lfun/all/AddExperiencePoints b/lib/doc/lfun/all/AddExperiencePoints new file mode 100644 index 0000000..9f1fa88 --- /dev/null +++ b/lib/doc/lfun/all/AddExperiencePoints @@ -0,0 +1,24 @@ +ADDEXPERIENCEPOINTS + +NAME + AddExperiencePoints() + +SYNOPSIS + int AddExperiencePoints(mixed x) + +DESCRIPTION + This is the function called when "XP" is to be added to a player. + +EXAMPLES + this_player()->AddExperiencePoints(42) + +LOCATION + /lib/body + + +SEE ALSO + GetExperiencePoints, SetCustomXP, GetCustomXP + +Author + Cratylus + diff --git a/lib/doc/lfun/all/AddExtraChannels b/lib/doc/lfun/all/AddExtraChannels new file mode 100644 index 0000000..455e133 --- /dev/null +++ b/lib/doc/lfun/all/AddExtraChannels @@ -0,0 +1,24 @@ +ADDEXTRACHANNELS + +NAME + AddExtraChannels() + +SYNOPSIS + string array AddExtraChannels(string array chans) + +DESCRIPTION + Adds to the player's extra channels. Extra channels are part of a channel test system and will be largely unused post Dead Souls 2.1. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + SetExtraChannels, GetExtraChannels, AddExtraChannels, RemoveExtraChannels + +Author + Cratylus + diff --git a/lib/doc/lfun/all/AddFingers b/lib/doc/lfun/all/AddFingers new file mode 100644 index 0000000..a724617 --- /dev/null +++ b/lib/doc/lfun/all/AddFingers @@ -0,0 +1,22 @@ +ADDFINGERS +NAME + AddFingers() + +SYNOPSIS + varargs int AddFingers(string limb, int x) + +DESCRIPTION + Adds the given number of fingers to the given limb. string limb - the limb to which fingers will be added. int x - the number of fingers being added, can be negative. Returns the total number of fingers after addition. + +EXAMPLES + + +LOCATION + /lib/body + +SEE ALSO + GetFingers + +Author + Unknown + diff --git a/lib/doc/lfun/all/AddFood b/lib/doc/lfun/all/AddFood new file mode 100644 index 0000000..ac93a9f --- /dev/null +++ b/lib/doc/lfun/all/AddFood @@ -0,0 +1,24 @@ +ADDFOOD + +NAME + AddFood() + +SYNOPSIS + int AddFood(int x) + +DESCRIPTION + Arbitrarily add "food points" to the creature by the amount indicated by the passed integer. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + GetFood() + +Author + Cratylus + diff --git a/lib/doc/lfun/all/AddHP b/lib/doc/lfun/all/AddHP new file mode 100644 index 0000000..3f37879 --- /dev/null +++ b/lib/doc/lfun/all/AddHP @@ -0,0 +1,24 @@ +ADDHP + +NAME + AddHP() + +SYNOPSIS + int AddHP(int hp) + +DESCRIPTION + Arbitrarily change a creature's health points by the integer provided. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + eventReceiveDamage + +Author + Cratylus + diff --git a/lib/doc/lfun/all/AddHealthPoints b/lib/doc/lfun/all/AddHealthPoints new file mode 100644 index 0000000..42a3baf --- /dev/null +++ b/lib/doc/lfun/all/AddHealthPoints @@ -0,0 +1,36 @@ +ADDHEALTHPOINTS + +NAME + AddHealthPoints() + + + +SYNOPSIS + varargs static int AddHealthPoints(int x, string limb, object agent) + + + +DESCRIPTION + If the value of limb is not zero, then "x" number of health points will be added to limb "limb". If the value is 0, then the overall health points will be modified. int x - number of points being added, may be negative (required). string limb - the limb to which health is being added (optional). object agent - the living responsible for this damage. Returns the remaining number of health points for the limb in question or for the overall health points. Note this is a static function and cannot be called from outside the creature. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/player + + +SEE ALSO + AddHP + + + +Author + Unknown + + diff --git a/lib/doc/lfun/all/AddHeartModifier b/lib/doc/lfun/all/AddHeartModifier new file mode 100644 index 0000000..81bf07f --- /dev/null +++ b/lib/doc/lfun/all/AddHeartModifier @@ -0,0 +1,24 @@ +ADDHEARTMODIFIER + +NAME + AddHeartModifier() + +SYNOPSIS + varargs int AddHeartModifier(int x, int t) + +DESCRIPTION + Changes the heart rate modifier by the integer specified in the first argument. If argument t is provided, this modifier is removed after t seconds. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + GetHeartModifier + +Author + Cratylus + diff --git a/lib/doc/lfun/all/AddLead b/lib/doc/lfun/all/AddLead new file mode 100644 index 0000000..a7c58fc --- /dev/null +++ b/lib/doc/lfun/all/AddLead @@ -0,0 +1,29 @@ +ADDLEAD + +NAME + AddLead() + + +SYNOPSIS + int AddLead(string ammo,int number) + + +DESCRIPTION + Obsolete function for adding bullet damage to a creature. + + +EXAMPLES + + + +LOCATION + /lib/body + + +SEE ALSO + GetLead + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/AddLimb b/lib/doc/lfun/all/AddLimb new file mode 100644 index 0000000..c422b5f --- /dev/null +++ b/lib/doc/lfun/all/AddLimb @@ -0,0 +1,29 @@ +ADDLIMB + +NAME + AddLimb() + + +SYNOPSIS + varargs int AddLimb(string limb, string parent, int classes, int *armors) + + +DESCRIPTION + Adds the named limb to the body, attached at the named point the limb classes starts at 1 for a torso (strongest) to whatever the documentation rates as the weakest. string limb - the limb being added (required). string parent - the limb to which this one is being attached (required). int classes - rating of the limb's strength (optional). int *armors - the types of armors which can be worn here (optional). Returns 1 on success, 0 on failure. classes defaults to 1. armors defaults to ({}). + + +EXAMPLES + To add a prehensile (wielding) limb to a creature: creature->AddLimb("tentacle", "torso", 2, ({A_WEAPON })) + + +LOCATION + /lib/body + + +SEE ALSO + RemoveLimb, DestLimb, RestoreLimb + +Author + Unknown + + diff --git a/lib/doc/lfun/all/AddMagicPoints b/lib/doc/lfun/all/AddMagicPoints new file mode 100644 index 0000000..68c7214 --- /dev/null +++ b/lib/doc/lfun/all/AddMagicPoints @@ -0,0 +1,24 @@ +ADDMAGICPOINTS + +NAME + AddMagicPoints() + +SYNOPSIS + int AddMagicPoints(int x) + +DESCRIPTION + Arbitrarily adds magic points to a creature. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + SetMagicPoints, GetMagicPoints, GetMaxMagicPoints + +Author + Cratylus + diff --git a/lib/doc/lfun/all/AddMagicProtection b/lib/doc/lfun/all/AddMagicProtection new file mode 100644 index 0000000..a7eb028 --- /dev/null +++ b/lib/doc/lfun/all/AddMagicProtection @@ -0,0 +1,24 @@ +ADDMAGICPROTECTION + +NAME + AddMagicProtection() + +SYNOPSIS + int AddMagicProtection(class MagicProtection cl) + +DESCRIPTION + This is the rather complex means by which to add sophisticated magical protection to a creature. An item must first create a protection class, then pass it as an argument to this funtion in the creature. + +EXAMPLES + Please see the buffer spell, /spells/buffer.c , for a detailed example of the mechanics of this system. + +LOCATION + /lib/body + + +SEE ALSO + SetProtect, GetProtect, RemoveMagicProtection, eventCheckProtection + +Author + Cratylus + diff --git a/lib/doc/lfun/all/AddMoJo b/lib/doc/lfun/all/AddMoJo new file mode 100644 index 0000000..967a7fd --- /dev/null +++ b/lib/doc/lfun/all/AddMoJo @@ -0,0 +1,29 @@ +ADDMOJO + +NAME + AddMoJo() + + +SYNOPSIS + float AddMoJo(mixed x) + + +DESCRIPTION + This is a test function, designed to add the notional characteristic of "Mojo" to a creature. It is unused. + + +EXAMPLES + + + +LOCATION + /lib/body + + +SEE ALSO + GetMojo + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/AddPoison b/lib/doc/lfun/all/AddPoison new file mode 100644 index 0000000..725b95a --- /dev/null +++ b/lib/doc/lfun/all/AddPoison @@ -0,0 +1,36 @@ +ADDPOISON + +NAME + AddPoison() + + + +SYNOPSIS + int AddPoison(int x) + + + +DESCRIPTION + Arbitrarily add poison by the amount indicated by the passed integer. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/events/poison + + +SEE ALSO + GetPoison + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/AddQuestPoints b/lib/doc/lfun/all/AddQuestPoints new file mode 100644 index 0000000..bbcb0e5 --- /dev/null +++ b/lib/doc/lfun/all/AddQuestPoints @@ -0,0 +1,29 @@ +ADDQUESTPOINTS + +NAME + AddQuestPoints() + + +SYNOPSIS + int AddQuestPoints(mixed x) + + +DESCRIPTION + Arbitrarily add quest points to a creature. Usually this is done when a player completes a quest. + + +EXAMPLES + + + +LOCATION + /lib/body + + +SEE ALSO + GetQuestPoints + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/AddSacrificeType b/lib/doc/lfun/all/AddSacrificeType new file mode 100644 index 0000000..ab6123e --- /dev/null +++ b/lib/doc/lfun/all/AddSacrificeType @@ -0,0 +1,24 @@ +ADDSACRIFICETYPE + +NAME + AddSacrificeType() + +SYNOPSIS + int AddSacrificeType(int x) + +DESCRIPTION + Adds to the existing set of permitted sacrifices here. Unimplemented in Dead Souls 2.1. + +EXAMPLES + + +LOCATION + /lib/chapel + + +SEE ALSO + SetAllowSacrifice, GetAllowSacrifice, SetSacrificeType, AddSacrificeType, GetSacrificeType, eventSacrifice, CanSacrifice + +Author + Cratylus + diff --git a/lib/doc/lfun/all/AddSkillPoints b/lib/doc/lfun/all/AddSkillPoints new file mode 100644 index 0000000..4ef5fd7 --- /dev/null +++ b/lib/doc/lfun/all/AddSkillPoints @@ -0,0 +1,25 @@ +ADDSKILLPOINTS + +NAME + AddSkillPoints() + +SYNOPSIS + int AddSkillPoints(string skill, int x) + +DESCRIPTION + LIB_ABILITIES: adds "x" points to the total for skill "skill". if the points go over the max for the current skill level, then the level is raised 1, if the points go under 0, then the skill level is lowered. LIB_CLASSES: Applies the appropriate skill modifiers to the skill change before passing it on to LIB_ABILITIES. + +EXAMPLES + + +LOCATION + /lib/classes +/lib/lvs/abilities + +SEE ALSO + AddSkillPoints, SetSkillModifier, GetSkillModifier + + +Author + Unknown + diff --git a/lib/doc/lfun/all/CanBurn b/lib/doc/lfun/all/CanBurn new file mode 100644 index 0000000..fa72a84 --- /dev/null +++ b/lib/doc/lfun/all/CanBurn @@ -0,0 +1,28 @@ +CANBURN + +NAME + CanBurn() + +SYNOPSIS + mixed CanExtinguish(object who) + +DESCRIPTION + Returns whether the item can burn, depending on its fuel requirement and amount of fuel. + + +EXAMPLES + + + +LOCATION + /lib/burn + + +SEE ALSO + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/CanExtinguish b/lib/doc/lfun/all/CanExtinguish new file mode 100644 index 0000000..f8dd11f --- /dev/null +++ b/lib/doc/lfun/all/CanExtinguish @@ -0,0 +1,29 @@ +CANEXTINGUISH + +NAME + CanExtinguish() + + +SYNOPSIS + mixed CanExtinguish(object who) + + +DESCRIPTION + Returns whether the item can be doused, depending on physical location and fuel status. + + +EXAMPLES + + + +LOCATION + /lib/burn + + +SEE ALSO + CanBurn + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/CanFly b/lib/doc/lfun/all/CanFly new file mode 100644 index 0000000..1fe52ae --- /dev/null +++ b/lib/doc/lfun/all/CanFly @@ -0,0 +1,37 @@ +CANFLY + +NAME + CanFly() + + + +SYNOPSIS + int CanFly() + + + +DESCRIPTION + In npc's, checks to see whether the creature is capable of flight. A return of 1 is yes, a return of 0 is no. In rooms, the default is for a room to permit a flying creature to fly in or out. If CanFly returns 0, that behavior is restricted. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/std/room +/lib/virtual/virt_sky + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/CanJoin b/lib/doc/lfun/all/CanJoin new file mode 100644 index 0000000..94d36ad --- /dev/null +++ b/lib/doc/lfun/all/CanJoin @@ -0,0 +1,23 @@ +CANJOIN + +NAME + CanJOin() + +SYNOPSIS + mixed CanJoin(object ob) + +DESCRIPTION + Returns 1 of the specified user object may join the clan, 0 otherwise. + +EXAMPLES + if(CanJoin(this_player())) write("Welcome to the Frombotzer Clan!"); + +LOCATION + /lib/clan + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/CanLight b/lib/doc/lfun/all/CanLight new file mode 100644 index 0000000..3f102e7 --- /dev/null +++ b/lib/doc/lfun/all/CanLight @@ -0,0 +1,29 @@ +CANLIGHT + +NAME + CanLight() + +SYNOPSIS + + + +DESCRIPTION + + + +EXAMPLES + + + +LOCATION + /lib/light + + +SEE ALSO + CanExtinguish + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/CanManipulate b/lib/doc/lfun/all/CanManipulate new file mode 100644 index 0000000..9bea110 --- /dev/null +++ b/lib/doc/lfun/all/CanManipulate @@ -0,0 +1,31 @@ +CANMANIPULATE + +NAME + CanManipulate() + + +SYNOPSIS + mixed CanManipulate() + + +DESCRIPTION + Returns whether a creature has limbs with which to manipulate items. If a creature lacks limbs with which it can wield weapons, it is considered non-prehensile, and this function returns 0. Otherwise it returns 1. + + +EXAMPLES + + + +LOCATION + /lib/body +/lib/events/manipulate + + +SEE ALSO + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/CanMarry b/lib/doc/lfun/all/CanMarry new file mode 100644 index 0000000..8eb27c3 --- /dev/null +++ b/lib/doc/lfun/all/CanMarry @@ -0,0 +1,25 @@ +CANMARRY + +NAME + CanMarry() + +SYNOPSIS + mixed CanMarry(object who, object spouse1, object spouse2) + +DESCRIPTION + Ensures that the person officiating the marriage is an arch, and that the two prospective spouses are eligible to marry one another. + +EXAMPLES + + +LOCATION + /lib/chapel +/lib/interactive + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/CanReceive b/lib/doc/lfun/all/CanReceive new file mode 100644 index 0000000..3f3afe1 --- /dev/null +++ b/lib/doc/lfun/all/CanReceive @@ -0,0 +1,34 @@ +CANRECEIVE + +NAME + CanReceive() + +SYNOPSIS + int CanReceive(object ob) + +DESCRIPTION + Objects that can hold other objects use this function to determine whether the incoming objects 'ob' is allowed to enter. If it is allowed, this function should return 1. If it is not allowed, this function should return 0. + +EXAMPLES + + +LOCATION + /lib/flashlight +/lib/npc +/lib/post_office +/lib/firearm +/lib/comp/container +/lib/player +/lib/std/corpse +/lib/comp/holder +/lib/std/limb +/lib/clip +/lib/std/furnace +/lib/std/room + +SEE ALSO + CanRelease + +Author + Cratylus + diff --git a/lib/doc/lfun/all/CanRelease b/lib/doc/lfun/all/CanRelease new file mode 100644 index 0000000..50232d4 --- /dev/null +++ b/lib/doc/lfun/all/CanRelease @@ -0,0 +1,26 @@ +CANRELEASE + +NAME + CanRelease() + +SYNOPSIS + int CanRelease(object ob) + +DESCRIPTION + Objects that can hold other objects use this function to determine whether the outgoing object 'ob' is allowed to leave. If it is allowed, this function should return 1. If it is not allowed, this function should return 0. + +EXAMPLES + + +LOCATION + /lib/fishing +/lib/firearm +/lib/comp/container +/lib/clip + +SEE ALSO + CanReceive() + +Author + Cratylus + diff --git a/lib/doc/lfun/all/CanRemoveItem b/lib/doc/lfun/all/CanRemoveItem new file mode 100644 index 0000000..06fdd49 --- /dev/null +++ b/lib/doc/lfun/all/CanRemoveItem @@ -0,0 +1,24 @@ +CANREMOVEITEM + +NAME + CanRemoveItem() + +SYNOPSIS + mixed CanRemoveItem(object ob) + +DESCRIPTION + LIB_BODY: Returns whether the creature can remove a given article of clothing or unwield a weapon. In body.c it is a stub that always returns 1. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/CanSacrifice b/lib/doc/lfun/all/CanSacrifice new file mode 100644 index 0000000..a9c0b3c --- /dev/null +++ b/lib/doc/lfun/all/CanSacrifice @@ -0,0 +1,24 @@ +CANSACRIFICE + +NAME + CanSacrifice() + +SYNOPSIS + mixed CanSacrifice(object who, object what, string deus) + +DESCRIPTION + Checks the religion of "who" to determine if their religious affiliation permits their sacrifice here. + +EXAMPLES + + +LOCATION + /lib/chapel + + +SEE ALSO + SetAllowSacrifice, GetAllowSacrifice, SetSacrificeType, AddSacrificeType, GetSacrificeType, eventSacrifice, CanSacrifice + +Author + Cratylus + diff --git a/lib/doc/lfun/all/CanWear b/lib/doc/lfun/all/CanWear new file mode 100644 index 0000000..06691da --- /dev/null +++ b/lib/doc/lfun/all/CanWear @@ -0,0 +1,24 @@ +CANWEAR + +NAME + CanWear() + +SYNOPSIS + mixed CanWear(object ob, string *limbs) + +DESCRIPTION + Checks to see if a particular armor can be worn. object armor - the piece of armor being checked. string *limbs - the limbs on which the armor wants to be worn. A nested array indicates that just one of the included limbs must be satisfied. Returns 1 if the armor can be worn on those limbs. Returns 0 if the armor cannot be worn there for any reason. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Unknown + diff --git a/lib/doc/lfun/all/ChangeClass b/lib/doc/lfun/all/ChangeClass new file mode 100644 index 0000000..8072bd4 --- /dev/null +++ b/lib/doc/lfun/all/ChangeClass @@ -0,0 +1,27 @@ +CHANGECLASS + +NAME + ChangeClass() + + +SYNOPSIS + string ChangeClass(string class_name) + + +DESCRIPTION + Changes a creature's class from its current one to the one specified by "class_name". + + +EXAMPLES + + + +LOCATION + /lib/classes + +SEE ALSO + SetClass + +Author + Cratylus + diff --git a/lib/doc/lfun/all/ClassMember b/lib/doc/lfun/all/ClassMember new file mode 100644 index 0000000..94835c1 --- /dev/null +++ b/lib/doc/lfun/all/ClassMember @@ -0,0 +1,24 @@ +CLASSMEMBER + +NAME + ClassMember() + +SYNOPSIS + int ClassMember(string class_name) + +DESCRIPTION + Returns whether the class daemon thinks the player is a member of the specified class. + +EXAMPLES + + +LOCATION + /lib/classes + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/DestLimb b/lib/doc/lfun/all/DestLimb new file mode 100644 index 0000000..cc20f7f --- /dev/null +++ b/lib/doc/lfun/all/DestLimb @@ -0,0 +1,24 @@ +DESTLIMB + +NAME + DestLimb() + +SYNOPSIS + int DestLimb(string limb) + +DESCRIPTION + Removes a limb from the limbs mapping. The limb isn't marked as mising, and the monster doesn't die even if you remove a fatal limb. Useful for removing limbs from standard race types. Removing the torso isn't allowed. Returns -1 on error, 0 on failure, 1 on success. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + RemoveLimb + +Author + Unknown + diff --git a/lib/doc/lfun/all/GetAffectLong b/lib/doc/lfun/all/GetAffectLong new file mode 100644 index 0000000..028c1fd --- /dev/null +++ b/lib/doc/lfun/all/GetAffectLong @@ -0,0 +1,23 @@ +GETAFFECTLONG +NAME + GetAffectLong() + +SYNOPSIS + string GetAffectLong(object ob) + +DESCRIPTION + Adds a descriptive string to a creature's long desc indicating some variable information. In the case of LIB_BODY, it indicates wakefulness or intoxication. For LIB_CLAN, clan membership is indicated. The argument is not used. + +EXAMPLES + + +LOCATION + /lib/body +/lib/clan + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetAlcohol b/lib/doc/lfun/all/GetAlcohol new file mode 100644 index 0000000..a623737 --- /dev/null +++ b/lib/doc/lfun/all/GetAlcohol @@ -0,0 +1,36 @@ +GETALCOHOL + +NAME + GetAlcohol() + + + +SYNOPSIS + int GetAlcohol() + + + +DESCRIPTION + Returns the alcohol level of the creature. + + + +EXAMPLES + present("wino",environment(this_player()))->GetAlcohol() + + + +LOCATION + /lib/body +/lib/race + + +SEE ALSO + SetAlcohol + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetAllowSacrifice b/lib/doc/lfun/all/GetAllowSacrifice new file mode 100644 index 0000000..8606fff --- /dev/null +++ b/lib/doc/lfun/all/GetAllowSacrifice @@ -0,0 +1,24 @@ +GETALLOWSACRIFICE + +NAME + GetAllowSacrifice() + +SYNOPSIS + int GetAllowSacrifice() + +DESCRIPTION + Returns 1 if sacrifices are allowed here, 0 otherwise. + +EXAMPLES + + +LOCATION + /lib/chapel + + +SEE ALSO + SetAllowSacrifice, GetAllowSacrifice, SetSacrificeType, AddSacrificeType, GetSacrificeType, eventSacrifice, CanSacrifice + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetAmmoType b/lib/doc/lfun/all/GetAmmoType new file mode 100644 index 0000000..2b167ef --- /dev/null +++ b/lib/doc/lfun/all/GetAmmoType @@ -0,0 +1,26 @@ +GETAMMOTYPE + +NAME + GetAmmoType() + +SYNOPSIS + string GetAmmoType() + +DESCRIPTION + If the ammunition type is set on a clip or a round, they must match in order to be compatible. This function returns the string defined for that information. + +EXAMPLES + + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + SetAmmoType, GetFirearmType, SetFirearmType + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetBaseStatLevel b/lib/doc/lfun/all/GetBaseStatLevel new file mode 100644 index 0000000..6ed1fe2 --- /dev/null +++ b/lib/doc/lfun/all/GetBaseStatLevel @@ -0,0 +1,26 @@ +GETBASESTATLEVEL + +NAME + GetBaseStatLevel() + +SYNOPSIS + int GetBaseStatLevel(string stat) + +DESCRIPTION + Returns the unmodified stat level for stat "stat". For example, a player's GetStatLevel("coordination") will be lower than her GetBaseStatLevel("coordination") if she's drunk. + +EXAMPLES + + +LOCATION + /lib/classes +/lib/combat +/lib/genetics + + +SEE ALSO + GetStatLevel + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetBodyComposition b/lib/doc/lfun/all/GetBodyComposition new file mode 100644 index 0000000..959e3a1 --- /dev/null +++ b/lib/doc/lfun/all/GetBodyComposition @@ -0,0 +1,29 @@ +GETBODYCOMPOSITION + +NAME + GetBodyComposition() + + +SYNOPSIS + string GetBodyComposition() + + +DESCRIPTION + Returns a string indicating what a non-biological creature is made of. + +EXAMPLES + + + +LOCATION + /lib/body + + +SEE ALSO + SetBodyComposition + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetBonusDuration b/lib/doc/lfun/all/GetBonusDuration new file mode 100644 index 0000000..66d4a0e --- /dev/null +++ b/lib/doc/lfun/all/GetBonusDuration @@ -0,0 +1,24 @@ +GETBONUSDURATION + +NAME + GetBonusDuration() + +SYNOPSIS + int GetBonusDuration() + +DESCRIPTION + Returns the number of heartbeats left before a bonus's effects wear off. + +EXAMPLES + + +LOCATION + /lib/bonus + + +SEE ALSO + GetPoints, GetSkills, GetStats + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetBurnRate b/lib/doc/lfun/all/GetBurnRate new file mode 100644 index 0000000..d74b1c5 --- /dev/null +++ b/lib/doc/lfun/all/GetBurnRate @@ -0,0 +1,33 @@ +GETBURNRATE + +NAME + GetBurnRate() + + +SYNOPSIS + int GetBurnRate() + + + +DESCRIPTION + Returns the rate at which a thing burns. + + + +EXAMPLES + + + + +LOCATION + /lib/burn +/lib/lamp + + +SEE ALSO + SetBurnRate + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetBurning b/lib/doc/lfun/all/GetBurning new file mode 100644 index 0000000..2810e45 --- /dev/null +++ b/lib/doc/lfun/all/GetBurning @@ -0,0 +1,24 @@ +GETBURNING + +NAME + GetBurning() + +SYNOPSIS + int GetBurning() + +DESCRIPTION + Returns whether the item in question is undergoing combustion. + +EXAMPLES + + +LOCATION + /lib/burn + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetBurntValue b/lib/doc/lfun/all/GetBurntValue new file mode 100644 index 0000000..c81d1e0 --- /dev/null +++ b/lib/doc/lfun/all/GetBurntValue @@ -0,0 +1,24 @@ +GETBURNTVALUE + +NAME + GetBurntValue() + +SYNOPSIS + int GetBurntValue() + +DESCRIPTION + Returns how much money the burnt thing is worth after being entirely consumed. + +EXAMPLES + + +LOCATION + /lib/burn + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetCaffeine b/lib/doc/lfun/all/GetCaffeine new file mode 100644 index 0000000..2d34374 --- /dev/null +++ b/lib/doc/lfun/all/GetCaffeine @@ -0,0 +1,24 @@ +GETCAFFEINE + +NAME + GetCaffeine() + +SYNOPSIS + int GetCaffeine() + +DESCRIPTION + Returns the caffeine level of the creature. + +EXAMPLES + present("barista",environment(this_player()))->GetCaffeine() + +LOCATION + /lib/body + + +SEE ALSO + SetCaffeine + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetCaliber b/lib/doc/lfun/all/GetCaliber new file mode 100644 index 0000000..3481b93 --- /dev/null +++ b/lib/doc/lfun/all/GetCaliber @@ -0,0 +1,26 @@ +GETCALIBER + +NAME + GetCaliber() + +SYNOPSIS + int GetCaliber() + +DESCRIPTION + Caliber is a measurement of ammunition size, different from millimeters. This function returns that information for the given object, if it is set. + +EXAMPLES + + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + SetCaliber, SetMillimeter, GetMillimeter + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetCanBite b/lib/doc/lfun/all/GetCanBite new file mode 100644 index 0000000..7aea1d2 --- /dev/null +++ b/lib/doc/lfun/all/GetCanBite @@ -0,0 +1,24 @@ +GETCANBITE + +NAME + GetCanBite() + +SYNOPSIS + int GetCanBite() + +DESCRIPTION + Returns whether the creature is permitted to bite during combat. This may be overridden by the race settings, if it is not a "biting race". + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetCapName b/lib/doc/lfun/all/GetCapName new file mode 100644 index 0000000..7cb66e2 --- /dev/null +++ b/lib/doc/lfun/all/GetCapName @@ -0,0 +1,39 @@ +GETCAPNAME + +NAME + GetCapName() + + + +SYNOPSIS + string GetCapName() + + + +DESCRIPTION + Returns a thing's capitalized name. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/npc +/lib/player +/lib/props/id +/secure/lib/connect + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetCellType b/lib/doc/lfun/all/GetCellType new file mode 100644 index 0000000..70c0f2d --- /dev/null +++ b/lib/doc/lfun/all/GetCellType @@ -0,0 +1,36 @@ +GETCELLTYPE + +NAME + GetCellType() + + + +SYNOPSIS + string GetCellType() + + + +DESCRIPTION + Returns a string indicating (for batteries) what kind of battery it is, or (for flashlights) what kind of batteries the device requires. + + + +EXAMPLES + + + + +LOCATION + /lib/battery +/lib/flashlight + + +SEE ALSO + SetCellType + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetChannels b/lib/doc/lfun/all/GetChannels new file mode 100644 index 0000000..5267a99 --- /dev/null +++ b/lib/doc/lfun/all/GetChannels @@ -0,0 +1,24 @@ +GETCHANNELS + +NAME + GetChannels() + +SYNOPSIS + string array GetChannels() + +DESCRIPTION + Returns an array listing the names of the channels accessible to a user. + +EXAMPLES + + +LOCATION + /lib/chat + + +SEE ALSO + AddChannel, RemoveChannel, GetChannels, returnChannels + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetCharge b/lib/doc/lfun/all/GetCharge new file mode 100644 index 0000000..619770b --- /dev/null +++ b/lib/doc/lfun/all/GetCharge @@ -0,0 +1,24 @@ +GETCHARGE + +NAME + GetCharge() + +SYNOPSIS + int GetCharge() + +DESCRIPTION + Returns the amount of power left in a battery. + +EXAMPLES + present("battery",this_object())->GetCharge() + +LOCATION + /lib/battery.c + + +SEE ALSO + SetCharge, SetDrainRate, GetDrainRate + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetClan b/lib/doc/lfun/all/GetClan new file mode 100644 index 0000000..3a21a25 --- /dev/null +++ b/lib/doc/lfun/all/GetClan @@ -0,0 +1,23 @@ +GETCLAN + +NAME + GetClan() + +SYNOPSIS + string GetClan() + +DESCRIPTION + Returns what the player object has set as its clan. + +EXAMPLES + + +LOCATION + /lib/classes + +SEE ALSO + SetClan + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetClanName b/lib/doc/lfun/all/GetClanName new file mode 100644 index 0000000..fbd5331 --- /dev/null +++ b/lib/doc/lfun/all/GetClanName @@ -0,0 +1,23 @@ +GETCLANNAME + +NAME + GetClanName() + +SYNOPSIS + string GetClanName() + +DESCRIPTION + Returns the nameof the clan the object belongs to. + +EXAMPLES + + +LOCATION + /lib/clan + +SEE ALSO + SetClanName + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetClanObject b/lib/doc/lfun/all/GetClanObject new file mode 100644 index 0000000..d80a221 --- /dev/null +++ b/lib/doc/lfun/all/GetClanObject @@ -0,0 +1,23 @@ +GETCLANOBJECT + +NAME + GetClanObject() + +SYNOPSIS + string GetClanObject() + +DESCRIPTION + Returns the unique id of the membership object of the clan the object belongs to. + +EXAMPLES + + +LOCATION + /lib/clan + +SEE ALSO + SetClanObject + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetClanSkill b/lib/doc/lfun/all/GetClanSkill new file mode 100644 index 0000000..26fb90d --- /dev/null +++ b/lib/doc/lfun/all/GetClanSkill @@ -0,0 +1,23 @@ +GETCLANSKILL + +NAME + GetClanSkill() + +SYNOPSIS + string GetClanSkill() + +DESCRIPTION + Returns the name of the skill that clan membership entitles one to. + +EXAMPLES + + +LOCATION + /lib/clan + +SEE ALSO + SetClanSkill + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetClass b/lib/doc/lfun/all/GetClass new file mode 100644 index 0000000..674a114 --- /dev/null +++ b/lib/doc/lfun/all/GetClass @@ -0,0 +1,28 @@ +GETCLASS + +NAME + GetClass() + +SYNOPSIS + string GetClass() + + +DESCRIPTION + Returns the creature's class. + + +EXAMPLES + + + +LOCATION + /lib/classes +/lib/props/damage + +SEE ALSO + SetClass, ChangeClass + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetDeathEvents b/lib/doc/lfun/all/GetDeathEvents new file mode 100644 index 0000000..35a4f4a --- /dev/null +++ b/lib/doc/lfun/all/GetDeathEvents @@ -0,0 +1,24 @@ +GETDEATHEVENTS + +NAME + GetDeathEvents() + +SYNOPSIS + int GetDeathEvents() + +DESCRIPTION + This function is checked in order to determine how many times this body has been "killed". Under rare circumstances a body may receive more than one kill blow simultaneously. This is part of a system to prevent the weirdness that results from such an event. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetDrainRate b/lib/doc/lfun/all/GetDrainRate new file mode 100644 index 0000000..abfced4 --- /dev/null +++ b/lib/doc/lfun/all/GetDrainRate @@ -0,0 +1,30 @@ +GETDRAINRATE + +NAME + GetDrainRate() + + +SYNOPSIS + int GetDrainRate() + + +DESCRIPTION + Return the speed with which a battery is drained over time, in charge units per heartbeat. + + +EXAMPLES + + + +LOCATION + /lib/battery + + +SEE ALSO + SetDrainRate, SetCharge, GetCharge + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetDrainable b/lib/doc/lfun/all/GetDrainable new file mode 100644 index 0000000..bd267e7 --- /dev/null +++ b/lib/doc/lfun/all/GetDrainable @@ -0,0 +1,29 @@ +GETDRAINABLE + +NAME + GetDrainable() + + +SYNOPSIS + int GetDrainable() + + +DESCRIPTION + Returns whether a battery can lose charge. + + +EXAMPLES + + +LOCATION + /lib/battery.c + + +SEE ALSO + SetDrainable, SetDrainRate, GetDrainRate + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetDrink b/lib/doc/lfun/all/GetDrink new file mode 100644 index 0000000..17404da --- /dev/null +++ b/lib/doc/lfun/all/GetDrink @@ -0,0 +1,24 @@ +GETDRINK + +NAME + GetDrink() + +SYNOPSIS + int GetDrink() + +DESCRIPTION + Returns the drink level of the creature. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetDying b/lib/doc/lfun/all/GetDying new file mode 100644 index 0000000..6089505 --- /dev/null +++ b/lib/doc/lfun/all/GetDying @@ -0,0 +1,24 @@ +GETDYING + +NAME + GetDying + +SYNOPSIS + int GetDying() + +DESCRIPTION + Sometimes things happen a bit too fast, and the lib tries to do something fatal to a body that's already dying. This check prevents logical paradoxes from occurring. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetEncumbrance b/lib/doc/lfun/all/GetEncumbrance new file mode 100644 index 0000000..b102986 --- /dev/null +++ b/lib/doc/lfun/all/GetEncumbrance @@ -0,0 +1,29 @@ +GETENCUMBRANCE + +NAME + GetEncumbrance() + + +SYNOPSIS + int GetEncumbrance() + +DESCRIPTION + Encumbrance is the measure of how unwieldy a player's inventory is. It has to do with the number of items carried, not necessarily their weight. The more items carried, the creater the encumbrance, and the more difficult it is to fight, if ENABLE_ENCUMBRANCE is defined in config.h. + + +EXAMPLES + + + +LOCATION + /lib/body + + +SEE ALSO + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetEquippedLimbs b/lib/doc/lfun/all/GetEquippedLimbs new file mode 100644 index 0000000..12037fe --- /dev/null +++ b/lib/doc/lfun/all/GetEquippedLimbs @@ -0,0 +1,24 @@ +GETEQUIPPEDLIMBS + +NAME + GetEquippedLimbs() + +SYNOPSIS + string array GetEquippedLimbs() + +DESCRIPTION + Returns an array of the limbs possessed by a creature that are currently wearing or wielding something. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + GetWorn + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetExperiencePoints b/lib/doc/lfun/all/GetExperiencePoints new file mode 100644 index 0000000..9f2b962 --- /dev/null +++ b/lib/doc/lfun/all/GetExperiencePoints @@ -0,0 +1,24 @@ +GETEXPERIENCEPOINTS + +NAME + GetExperiencePoints() + +SYNOPSIS + int GetExperiencePoints() + +DESCRIPTION + Returns the experience points a creature has earned. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetExtraChannels b/lib/doc/lfun/all/GetExtraChannels new file mode 100644 index 0000000..c3a53b7 --- /dev/null +++ b/lib/doc/lfun/all/GetExtraChannels @@ -0,0 +1,30 @@ +GETEXTRACHANNELS + +NAME + GetExtraChannels() + + +SYNOPSIS + string array GetExtraChannels() + + +DESCRIPTION + Returns an array of the player's extra channels. Extra channels are part of a channel test system and will be largely unused post Dead Souls 2.1. + + +EXAMPLES + + + + +LOCATION + /lib/body + + +SEE ALSO + SetExtraChannels, GetExtraChannels, AddExtraChannels, RemoveExtraChannels + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetFingers b/lib/doc/lfun/all/GetFingers new file mode 100644 index 0000000..a4c6549 --- /dev/null +++ b/lib/doc/lfun/all/GetFingers @@ -0,0 +1,37 @@ +GETFINGERS + +NAME + GetFingers() + + + +SYNOPSIS + LIB_BODY: int GetFingers(string limb) LIB_ARMOR: int GetFingers() + + + +DESCRIPTION + For creatures, returns the number of fingers on the given limb. For armor, returns the number of fingers required to wear the item. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/std/armor +/lib/std/worn_storage + + +SEE ALSO + AddFingers + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetFirearmType b/lib/doc/lfun/all/GetFirearmType new file mode 100644 index 0000000..159f673 --- /dev/null +++ b/lib/doc/lfun/all/GetFirearmType @@ -0,0 +1,26 @@ +GETFIREARMTYPE + +NAME + GetFirearmType() + +SYNOPSIS + string GetFirearmType() + +DESCRIPTION + If the firearm type is set on a clip or a round, they must match in order to be compatible. This function returns the string defined for that information. + +EXAMPLES + + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetAmmoType, SetAmmoType, SetFirearmType + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetFood b/lib/doc/lfun/all/GetFood new file mode 100644 index 0000000..d49ec0b --- /dev/null +++ b/lib/doc/lfun/all/GetFood @@ -0,0 +1,36 @@ +GETFOOD + +NAME + GetFood() + + + +SYNOPSIS + LIB_BODY: int GetFood() LIB_FISH: string GetFood() + + + +DESCRIPTION + LIB_BODY: Returns the food level of the creature. LIB_FISH: Returns the path to the meal file that this fish uses. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/fish + + +SEE ALSO + SetFood, AddFood + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetFuelRequired b/lib/doc/lfun/all/GetFuelRequired new file mode 100644 index 0000000..e08397a --- /dev/null +++ b/lib/doc/lfun/all/GetFuelRequired @@ -0,0 +1,29 @@ +GETFUELREQUIRED + +NAME + GetFuelRequired() + + +SYNOPSIS + int GetFuelRequired() + + +DESCRIPTION + Returns 1 if a thing requires fuel to burn, 0 otherwise. + + +EXAMPLES + + + +LOCATION + /lib/burn + + +SEE ALSO + SetFuelRequired + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetHealRate b/lib/doc/lfun/all/GetHealRate new file mode 100644 index 0000000..7ad1392 --- /dev/null +++ b/lib/doc/lfun/all/GetHealRate @@ -0,0 +1,31 @@ +GETHEALRATE + +NAME + GetHealRate() + + +SYNOPSIS + int GetHealRate() + + +DESCRIPTION + Returns a creature's healing rate. + + +EXAMPLES + + + +LOCATION + /lib/body +/lib/race + + +SEE ALSO + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetHealthPoints b/lib/doc/lfun/all/GetHealthPoints new file mode 100644 index 0000000..75a553a --- /dev/null +++ b/lib/doc/lfun/all/GetHealthPoints @@ -0,0 +1,24 @@ +GETHEALTHPOINTS + +NAME + GetHealthPoints() + +SYNOPSIS + varargs int GetHealthPoints(string limb) + +DESCRIPTION + Without an argument, returns the health points of the creature it's called in. With a limb argument specified, it returns the health points left in that limb, if it exists. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetHealthShort b/lib/doc/lfun/all/GetHealthShort new file mode 100644 index 0000000..2682db9 --- /dev/null +++ b/lib/doc/lfun/all/GetHealthShort @@ -0,0 +1,36 @@ +GETHEALTHSHORT + +NAME + GetHealthShort() + + + +SYNOPSIS + string GetHealthShort() + + + +DESCRIPTION + Colorizes a creature's short description based on their health status. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/std/corpse + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetHeartModifier b/lib/doc/lfun/all/GetHeartModifier new file mode 100644 index 0000000..db178e2 --- /dev/null +++ b/lib/doc/lfun/all/GetHeartModifier @@ -0,0 +1,29 @@ +GETHEARTMODIFIER + +NAME + GetHeartModifier() + + +SYNOPSIS + int GetHeartModifier() + + +DESCRIPTION + Returns the modifier set in that creature for their heart rate. A low number means a faster heart rate. A higher number means a slower heart rate. This affects how quickly a creature heals. + + +EXAMPLES + + + +LOCATION + /lib/body + + +SEE ALSO + AddHeartModifier + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetHeartRate b/lib/doc/lfun/all/GetHeartRate new file mode 100644 index 0000000..3bce69f --- /dev/null +++ b/lib/doc/lfun/all/GetHeartRate @@ -0,0 +1,31 @@ +GETHEARTRATE + +NAME + GetHeartRate() + + +SYNOPSIS + int GetHeartRate() + + +DESCRIPTION + Returns a creature's heart rate (NOT heart_beat). + + +EXAMPLES + + + +LOCATION + /lib/body +/lib/race + + +SEE ALSO + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetHeat b/lib/doc/lfun/all/GetHeat new file mode 100644 index 0000000..b701e1a --- /dev/null +++ b/lib/doc/lfun/all/GetHeat @@ -0,0 +1,24 @@ +GETHEAT + +NAME + GetHeat() + +SYNOPSIS + int GetHeat() + +DESCRIPTION + Returns the heat given off by the item. + +EXAMPLES + + +LOCATION + /lib/burn + + +SEE ALSO + SetHeat, GetMinHeat, SetMinHeat + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetLead b/lib/doc/lfun/all/GetLead new file mode 100644 index 0000000..4e294a3 --- /dev/null +++ b/lib/doc/lfun/all/GetLead @@ -0,0 +1,24 @@ +GETLEAD + +NAME + GetLead() + +SYNOPSIS + int GetLead(string ammo) + +DESCRIPTION + This is part of an obsolete firearms system. It reports how much bullet damage a creature has received. This will be replaced by a proper projectile wound system post-2.1. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetLeader b/lib/doc/lfun/all/GetLeader new file mode 100644 index 0000000..f9246f1 --- /dev/null +++ b/lib/doc/lfun/all/GetLeader @@ -0,0 +1,24 @@ +GETLEADER + +NAME + GetLeader() + +SYNOPSIS + LIB_FOLLOW: object GetLeader(), LIB_CLAN: string GetLeader() + +DESCRIPTION + Gets who the leader is in the given context. Note that LIB_FOLLOW uses the object datatype and LIB_CLAN uses string. + +EXAMPLES + + +LOCATION + /lib/clan +/lib/follow + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetLimbChildren b/lib/doc/lfun/all/GetLimbChildren new file mode 100644 index 0000000..afd9090 --- /dev/null +++ b/lib/doc/lfun/all/GetLimbChildren @@ -0,0 +1,29 @@ +GETLIMBCHILDREN + +NAME + GetLimbChildren() + + +SYNOPSIS + string array GetLimbChildren(string limb) + + +DESCRIPTION + Returns the limbs that depend on this limb to remain attached to the creature. + + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + GetLimbParent, GetMissingLimbParent, GetMissingLimbs, GetLimbs + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetLimbClass b/lib/doc/lfun/all/GetLimbClass new file mode 100644 index 0000000..cf8f473 --- /dev/null +++ b/lib/doc/lfun/all/GetLimbClass @@ -0,0 +1,24 @@ +GETLIMBCLASS + +NAME + GetLimbClass() + +SYNOPSIS + int GetLimbClass(string limb) + +DESCRIPTION + Returns the "class" or level of importance of the specified limb. Severing a creature's class 1 limb will result in its immediate death. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetLimbParent b/lib/doc/lfun/all/GetLimbParent new file mode 100644 index 0000000..23ea3f4 --- /dev/null +++ b/lib/doc/lfun/all/GetLimbParent @@ -0,0 +1,33 @@ +GETLIMBPARENT + +NAME + GetLimbParent() + + + +SYNOPSIS + string GetLimbParent(string limb) + + + +DESCRIPTION + Returns the name of the "parent limb" of the limb specified. + + + +EXAMPLES + + + + +LOCATION + /lib/body + + +SEE ALSO + GetLimbChildren, GetMissingLimbParent, GetMissingLimbs, GetLimbs + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetLimbs b/lib/doc/lfun/all/GetLimbs new file mode 100644 index 0000000..273978f --- /dev/null +++ b/lib/doc/lfun/all/GetLimbs @@ -0,0 +1,24 @@ +GETLIMBS + +NAME + GetLimbs() + +SYNOPSIS + string array GetLimbs() + +DESCRIPTION + Returns a creature's existing limbs. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + GetMissingLimbs + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetLong b/lib/doc/lfun/all/GetLong new file mode 100644 index 0000000..097c124 --- /dev/null +++ b/lib/doc/lfun/all/GetLong @@ -0,0 +1,47 @@ +GETLONG + +NAME + GetLong() + + + +SYNOPSIS + string GetLong(string str) + + + +DESCRIPTION + Returns the "long desciption" of the object it's called in. This long description is the main part of what the player sees when they "look at" something. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/bot +/lib/creator +/lib/donate +/lib/door +/lib/fuel +/lib/interactive +/lib/lamp +/lib/npc +/lib/player +/lib/torch +/lib/events/look +/lib/std/room + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetMagicPoints b/lib/doc/lfun/all/GetMagicPoints new file mode 100644 index 0000000..313da17 --- /dev/null +++ b/lib/doc/lfun/all/GetMagicPoints @@ -0,0 +1,24 @@ +GETMAGICPOINTS + +NAME + GetMagicPoints() + +SYNOPSIS + int GetMagicPoints() + +DESCRIPTION + Returns a creature's current magic point level. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + SetMagicPoints, GetMaxMagicPoints, AddMagicPoints + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetMaxHealthPoints b/lib/doc/lfun/all/GetMaxHealthPoints new file mode 100644 index 0000000..ee454cb --- /dev/null +++ b/lib/doc/lfun/all/GetMaxHealthPoints @@ -0,0 +1,39 @@ +GETMAXHEALTHPOINTS + +NAME + GetMaxHealthPoints() + + + +SYNOPSIS + varargs int GetMaxHealthPoints(string limb) + + + +DESCRIPTION + Returns a creature's maximum health level. Their normal healing process will not increase their health beyond this point. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/combat +/lib/living +/lib/npc +/lib/race + + +SEE ALSO + SetMaxHealthPoints, SetHealthPoints, GetHealthPoints + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetMaxMagicPoints b/lib/doc/lfun/all/GetMaxMagicPoints new file mode 100644 index 0000000..a6e290e --- /dev/null +++ b/lib/doc/lfun/all/GetMaxMagicPoints @@ -0,0 +1,36 @@ +GETMAXMAGICPOINTS + +NAME + GetMaxMagicPoints() + + + +SYNOPSIS + int GetMaxMagicPoints() + + + +DESCRIPTION + Returns a creature's maximum magic level. Their normal healing process will not increase their magic beyond this point. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/race + + +SEE ALSO + SetMagicPoints, GetMagicPoints, AddMagicPoints + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetMaxStaminaPoints b/lib/doc/lfun/all/GetMaxStaminaPoints new file mode 100644 index 0000000..c98e79d --- /dev/null +++ b/lib/doc/lfun/all/GetMaxStaminaPoints @@ -0,0 +1,36 @@ +GETMAXSTAMINAPOINTS + +NAME + GetMaxStaminaPoints() + + + +SYNOPSIS + float GetMaxStaminaPoints() + + + +DESCRIPTION + Returns a creature's maximum stamina level. Their normal healing process will not increase their stamina beyond this point. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/race + + +SEE ALSO + AddStaminaPoints, GetStaminaPoints + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetMelee b/lib/doc/lfun/all/GetMelee new file mode 100644 index 0000000..0f37f6a --- /dev/null +++ b/lib/doc/lfun/all/GetMelee @@ -0,0 +1,24 @@ +GETMELEE + +NAME + GetMelee() + +SYNOPSIS + int GetMelee() + +DESCRIPTION + Returns whether a creature is capable of unarmed combat. If this returns 0, the creature is most likely extremely ineffective without a weapon. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetMillimeter b/lib/doc/lfun/all/GetMillimeter new file mode 100644 index 0000000..5f54d8b --- /dev/null +++ b/lib/doc/lfun/all/GetMillimeter @@ -0,0 +1,26 @@ +GETMILLIMETER + +NAME + GetMillimeter() + +SYNOPSIS + int GetMillimeter() + +DESCRIPTION + Millimeter is a measurement of ammunition size, different from caliber. This function returns that information for the given object, if it is set. + +EXAMPLES + . + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetCaliber, SetCaliber, SetMillimeter + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetMinHeat b/lib/doc/lfun/all/GetMinHeat new file mode 100644 index 0000000..f5e9d40 --- /dev/null +++ b/lib/doc/lfun/all/GetMinHeat @@ -0,0 +1,24 @@ +GETMINHEAT + +NAME + GetMinHeat() + +SYNOPSIS + int GetMinHeat() + +DESCRIPTION + Returns the minimum amount of heat required for the item to give off light. + +EXAMPLES + + +LOCATION + /lib/burn + + +SEE ALSO + SetHeat, GetHeat, SetMinHeat + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetMissingLimbParent b/lib/doc/lfun/all/GetMissingLimbParent new file mode 100644 index 0000000..26b180d --- /dev/null +++ b/lib/doc/lfun/all/GetMissingLimbParent @@ -0,0 +1,24 @@ +GETMISSINGLIMBPARENT + +NAME + GetMissingLimbParent() + +SYNOPSIS + string GetMissingLimbParent(string limb) + +DESCRIPTION + Returns the name of the parent limb of the specified missing limb. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + GetLimbChildren, GetLimbParent, GetMissingLimbs, GetLimbs + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetMissingLimbParents b/lib/doc/lfun/all/GetMissingLimbParents new file mode 100644 index 0000000..42d59bf --- /dev/null +++ b/lib/doc/lfun/all/GetMissingLimbParents @@ -0,0 +1,24 @@ +GETMISSINGLIMBPARENTS + +NAME + GetMissingLimbParents() + +SYNOPSIS + string array GetMissingLimbParents(string limb) + +DESCRIPTION + Returns the entire chain of a limb's attachment as an array. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + GetLimbs, GetLimbParent, GetMissingLimbParent, GetLimbChildren + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetMissingLimbs b/lib/doc/lfun/all/GetMissingLimbs new file mode 100644 index 0000000..5d47beb --- /dev/null +++ b/lib/doc/lfun/all/GetMissingLimbs @@ -0,0 +1,24 @@ +GETMISSINGLIMBS + +NAME + GetMissingLimbs() + +SYNOPSIS + varargs string array GetMissingLimbs(int not_default) + +DESCRIPTION + Returns an array of the limbs a creature is missing. The integer argument invokes a test function that is largely unused as of Dead Souls 2.1. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + GetLimbs, GetLimbParent, GetMissingLimbParent, GetLimbChildren + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetMoJo b/lib/doc/lfun/all/GetMoJo new file mode 100644 index 0000000..6b93ba3 --- /dev/null +++ b/lib/doc/lfun/all/GetMoJo @@ -0,0 +1,24 @@ +GETMOJO + +NAME + GetMoJo() + +SYNOPSIS + float GetMoJo() + +DESCRIPTION + This is a test function, designed to check a creature's level of the notional characteristic of "Mojo". It is unused. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + SetMojo + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetMorality b/lib/doc/lfun/all/GetMorality new file mode 100644 index 0000000..ae13485 --- /dev/null +++ b/lib/doc/lfun/all/GetMorality @@ -0,0 +1,24 @@ +GETMORALITY + +NAME + GetMorality() + +SYNOPSIS + int GetMorality() + +DESCRIPTION + Returns the morality of the object. + +EXAMPLES + + +LOCATION + /lib/classes +/lib/spell + +SEE ALSO + SetMorality + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetMoralityDescription b/lib/doc/lfun/all/GetMoralityDescription new file mode 100644 index 0000000..652ae39 --- /dev/null +++ b/lib/doc/lfun/all/GetMoralityDescription @@ -0,0 +1,24 @@ +GETMORALITYDESCRIPTION + +NAME + GetMoralityDescription() + +SYNOPSIS + string GetMoralityDescription() + +DESCRIPTION + Returns the descriptive string associated with a player's morality, such as "neutral" + +EXAMPLES + + +LOCATION + /lib/classes + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetName b/lib/doc/lfun/all/GetName new file mode 100644 index 0000000..9b9f25b --- /dev/null +++ b/lib/doc/lfun/all/GetName @@ -0,0 +1,41 @@ +GETNAME + +NAME + GetName() + + + +SYNOPSIS + string GetName() + + + +DESCRIPTION + Returns the object's proper name, capitalized if appropriate. + + + +EXAMPLES + this_player()->GetName() + + + +LOCATION + /lib/body +/lib/creator +/lib/interactive +/lib/messages +/lib/npc +/lib/player +/lib/props/id + + +SEE ALSO + GetKeyName() + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetNoChanColors b/lib/doc/lfun/all/GetNoChanColors new file mode 100644 index 0000000..30f78f8 --- /dev/null +++ b/lib/doc/lfun/all/GetNoChanColors @@ -0,0 +1,24 @@ +GETNOCHANCOLORS + +NAME + GetNoChanColors() + +SYNOPSIS + int GetNoChanColors() + +DESCRIPTION + Users can disable seeing colors in channel messages. This lfun determines whether they have done so. + +EXAMPLES + + +LOCATION + /lib/chat + + +SEE ALSO + SetNoChanColors + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetPacifist b/lib/doc/lfun/all/GetPacifist new file mode 100644 index 0000000..0ee5af0 --- /dev/null +++ b/lib/doc/lfun/all/GetPacifist @@ -0,0 +1,24 @@ +GETPACIFIST + +NAME + GetPacifist() + +SYNOPSIS + int GetPacifist() + +DESCRIPTION + The default, 0, means the creature is willing to engage in combat. A return of 1 means the creature will not fight, regardless of whether it is under attack. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + SetPacifist + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetPoints b/lib/doc/lfun/all/GetPoints new file mode 100644 index 0000000..989203e --- /dev/null +++ b/lib/doc/lfun/all/GetPoints @@ -0,0 +1,25 @@ +GETPOINTS + +NAME + GetPoints() + +SYNOPSIS + mapping GetPoints() + +DESCRIPTION + Returs which vital points are affected by a potion or bonus, and by how much. + +EXAMPLES + + +LOCATION + /lib/bonus +/lib/potion + + +SEE ALSO + SetPoints, SetBonusDuration, GetBonusDuration + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetPoison b/lib/doc/lfun/all/GetPoison new file mode 100644 index 0000000..246d1bc --- /dev/null +++ b/lib/doc/lfun/all/GetPoison @@ -0,0 +1,36 @@ +GETPOISON + +NAME + GetPoison + + + +SYNOPSIS + int GetPoison() + + + +DESCRIPTION + Returns the current poison level. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/events/poison + + +SEE ALSO + AddPoison + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetProtect b/lib/doc/lfun/all/GetProtect new file mode 100644 index 0000000..94f80e9 --- /dev/null +++ b/lib/doc/lfun/all/GetProtect @@ -0,0 +1,32 @@ +GETPROTECT + +NAME + GetProtect() + + + +SYNOPSIS + function GetProtect() + + + +DESCRIPTION + Returns the "Protect" function set in the creature. + + +EXAMPLES + + + + +LOCATION + /lib/body + + +SEE ALSO + SetProtect, RemoveMagicProtection, AddMagicProtection + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetQuestPoints b/lib/doc/lfun/all/GetQuestPoints new file mode 100644 index 0000000..2f8cf67 --- /dev/null +++ b/lib/doc/lfun/all/GetQuestPoints @@ -0,0 +1,24 @@ +GETQUESTPOINTS + +NAME + GetQuestPoints() + +SYNOPSIS + int GetQuestPoints() + +DESCRIPTION + Returns the number of quest points earned by the creature. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + AddQuestPoints + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetRace b/lib/doc/lfun/all/GetRace new file mode 100644 index 0000000..e945d80 --- /dev/null +++ b/lib/doc/lfun/all/GetRace @@ -0,0 +1,38 @@ +GETRACE + +NAME + GetRace() + + + +SYNOPSIS + string GetRace() + + + +DESCRIPTION + Returns the creature's race. + + + +EXAMPLES + present("Spock", environment(this_player()))->GetRace() + + + +LOCATION + /lib/body +/lib/race +/lib/std/corpse +/lib/std/limb + + +SEE ALSO + GetClass + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetRandomLimb b/lib/doc/lfun/all/GetRandomLimb new file mode 100644 index 0000000..5005106 --- /dev/null +++ b/lib/doc/lfun/all/GetRandomLimb @@ -0,0 +1,24 @@ +GETRANDOMLIMB + +NAME + GetRandomLimb() + +SYNOPSIS + string GetRandomLimb(string targ) + +DESCRIPTION + Returns a random limb weighted towards the targetted limb. string targ - the targetted limb. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + UNKNOWN + diff --git a/lib/doc/lfun/all/GetRechargeable b/lib/doc/lfun/all/GetRechargeable new file mode 100644 index 0000000..2b6e6e5 --- /dev/null +++ b/lib/doc/lfun/all/GetRechargeable @@ -0,0 +1,24 @@ +GETRECHARGEABLE + +NAME + GetRechargeable() + +SYNOPSIS + int GetRechargeable() + +DESCRIPTION + Returns whether the battery is capable of being recharged. + +EXAMPLES + + +LOCATION + /lib/battery.c + + +SEE ALSO + SetRechargeable, SetCharge, GetCharge + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetReligion b/lib/doc/lfun/all/GetReligion new file mode 100644 index 0000000..a95d90e --- /dev/null +++ b/lib/doc/lfun/all/GetReligion @@ -0,0 +1,25 @@ +GETRELIGION + +NAME + GetReligion() + +SYNOPSIS + string GetReligion(int flag) + +DESCRIPTION + Returns the religion of the object. + +EXAMPLES + + + +LOCATION + /lib/chapel +/lib/classes + +SEE ALSO + SetReligion + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetResistance b/lib/doc/lfun/all/GetResistance new file mode 100644 index 0000000..1fbc0ce --- /dev/null +++ b/lib/doc/lfun/all/GetResistance @@ -0,0 +1,32 @@ +GETRESISTANCE + +NAME + GetResistance() + + +SYNOPSIS + string GetResistance(int type) + + +DESCRIPTION + Returns the creature's resistance level to the given damage type. + + +EXAMPLES + this_player()->GetResistance(GAS) + + +LOCATION + /lib/body +/lib/genetics +/lib/race + + +SEE ALSO + damage_types.h + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetRestrictedChannels b/lib/doc/lfun/all/GetRestrictedChannels new file mode 100644 index 0000000..cbdc984 --- /dev/null +++ b/lib/doc/lfun/all/GetRestrictedChannels @@ -0,0 +1,24 @@ +GETRESTRICTEDCHANNELS + +NAME + GetRestrictedChannels() + +SYNOPSIS + string array GetRestrictedChannels() + +DESCRIPTION + Returns an array of the names of the channels whose use is restricted to this user. + +EXAMPLES + + +LOCATION + /lib/chat + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetSacrificeType b/lib/doc/lfun/all/GetSacrificeType new file mode 100644 index 0000000..d5e69d9 --- /dev/null +++ b/lib/doc/lfun/all/GetSacrificeType @@ -0,0 +1,27 @@ +GETSACRIFICETYPE + +NAME + GetSacrificeType() + +SYNOPSIS + int GetSacrificeType() + +DESCRIPTION + Bit shifted return of sacrifice types permitted here. Unimplemented in Dead Souls 2.1. + +EXAMPLES + + + +LOCATION + /lib/chapel + + +SEE ALSO + SetAllowSacrifice, GetAllowSacrifice, SetSacrificeType, AddSacrificeType, GetSacrificeType, eventSacrifice, CanSacrifice + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetSkillModifier b/lib/doc/lfun/all/GetSkillModifier new file mode 100644 index 0000000..0c953ab --- /dev/null +++ b/lib/doc/lfun/all/GetSkillModifier @@ -0,0 +1,23 @@ +GETSKILLMODIFIER + +NAME + GetSkillModifier() + +SYNOPSIS + string GetSkillModifier(string skill) + +DESCRIPTION + Returns the stat (eg, strength, intelligence) that affects the advancement of the specified skill. + +EXAMPLES + + +LOCATION + /lib/classes + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetSkills b/lib/doc/lfun/all/GetSkills new file mode 100644 index 0000000..dbaaa79 --- /dev/null +++ b/lib/doc/lfun/all/GetSkills @@ -0,0 +1,27 @@ +GETSKILLS + +NAME + GetSkills() + +SYNOPSIS + LIB_SPELL, LIB_ABILITIES: string array GetSkills() ; LIB_POTION, LIB_BONUS: mapping GetSkills() + +DESCRIPTION + For LIB_ABILITIES this lfun returns the list of skill names possessed by the creature it's called in, such as "knife defense", etc. For LIB_SPELL this returns a list of the skills required to be able to cast the spell. For LIB_POTION and LIB_BONUS, this lfun works much like GetStats(), in that it returns a mapping of skills and how they are modified when a potion is drunk. + +EXAMPLES + + +LOCATION + /lib/bonus +/lib/lvs/abilities +/lib/potion +/lib/spell + + +SEE ALSO + GetStats, SetSkill + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetSleeping b/lib/doc/lfun/all/GetSleeping new file mode 100644 index 0000000..7fcf5a9 --- /dev/null +++ b/lib/doc/lfun/all/GetSleeping @@ -0,0 +1,24 @@ +GETSLEEPING + +NAME + GetSleeping() + +SYNOPSIS + int GetSleeping() + +DESCRIPTION + Returns how soundly asleep a creature is. Multiplying the resulting number by the standard modifier indicates the number of heartbeats left in that creature's sleep. In Dead Souls 2.1 that standard modifier is 6. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + SetSleeping + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetStaminaPoints b/lib/doc/lfun/all/GetStaminaPoints new file mode 100644 index 0000000..8ad4aa3 --- /dev/null +++ b/lib/doc/lfun/all/GetStaminaPoints @@ -0,0 +1,24 @@ +GETSTAMINAPOINTS + +NAME + GetStaminaPoints() + +SYNOPSIS + int GetStaminaPoints() + +DESCRIPTION + Returns a creature's current stamina point level. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + AddStaminaPoints, GetMaxStaminaPoints + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetStats b/lib/doc/lfun/all/GetStats new file mode 100644 index 0000000..34a54b3 --- /dev/null +++ b/lib/doc/lfun/all/GetStats @@ -0,0 +1,26 @@ +GETSTATS + +NAME + GetStats() + +SYNOPSIS + genetics: string array GetStats() , potion and bonus: mapping GetStats() + +DESCRIPTION + Called in a living thing, GetStats() returns an array of the creature's stat names, such as "strength", "wisdom", and the like. In the potion object, it returns a mapping of stats to modify when the potion is drunk. When the potion is drunk, this mapping is communicated to the bonus object that is moved into the drinker. + +EXAMPLES + + +LOCATION + /lib/bonus +/lib/genetics +/lib/potion + + +SEE ALSO + SetStats, GetStat, SetStat, GetStatLevel + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetTorso b/lib/doc/lfun/all/GetTorso new file mode 100644 index 0000000..45714c2 --- /dev/null +++ b/lib/doc/lfun/all/GetTorso @@ -0,0 +1,24 @@ +GETTORSO + +NAME + GetTorso() + +SYNOPSIS + string GetTorso() + +DESCRIPTION + Returns the name of the main limb nexus of a creature. An octopus, for example, might return "head" and an ant might return "thorax". + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetWielded b/lib/doc/lfun/all/GetWielded new file mode 100644 index 0000000..89c706f --- /dev/null +++ b/lib/doc/lfun/all/GetWielded @@ -0,0 +1,36 @@ +GETWIELDED + +NAME + GetWielded() + + + +SYNOPSIS + LIB_BODY: varargs mixed GetWielded(string limb) LIB_WEAPON: int GetWielded() + + + +DESCRIPTION + LIB_BODY: With no argument, returns the objects wielded by the creature. If the argument is a limb, this function returns what is wielded in that limb, if anything. LIB_WEAPON: If the weapon is wielded, this function returns 1. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/comp/weapon + + +SEE ALSO + GetWieldingLimbs + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/GetWieldingLimbs b/lib/doc/lfun/all/GetWieldingLimbs new file mode 100644 index 0000000..8544dda --- /dev/null +++ b/lib/doc/lfun/all/GetWieldingLimbs @@ -0,0 +1,24 @@ +GETWIELDINGLIMBS + +NAME + GetWieldingLimbs() + +SYNOPSIS + string array GetWieldingLimbs() + +DESCRIPTION + Returns a creature's prehensile limbs. Prehensile limbs are limbs that can wield weapons. A creature lacking prehensile limbs is generally unable to get or manipulate objects. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + GetLimbChildren, GetLimbParent, GetMissingLimbs, GetLimbs, GetMissingLimbParent + +Author + Cratylus + diff --git a/lib/doc/lfun/all/GetWorn b/lib/doc/lfun/all/GetWorn new file mode 100644 index 0000000..e9ed7fa --- /dev/null +++ b/lib/doc/lfun/all/GetWorn @@ -0,0 +1,32 @@ +GETWORN + +NAME + GetWorn() + + + +SYNOPSIS + LIB_BODY: varargs object array GetWorn(string limb) LIB_EQUIP: string array GetWorn() + + +DESCRIPTION + LIB_BODY: Without an argument, returns an array of all worn and wielded objects in the creature's inventory. With a limb as an argument, returns an array of all worn and wielded objects on that limb. LIB_EQUIP: Returns a positive integer if the item is currently being worn, 0 otherwise. + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/props/equip + + +SEE ALSO + SetWorn, GetEquippedLimbs + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/HandleTeller b/lib/doc/lfun/all/HandleTeller new file mode 100644 index 0000000..90cde9c --- /dev/null +++ b/lib/doc/lfun/all/HandleTeller @@ -0,0 +1,23 @@ +HANDLETELLER + +NAME + HandleTeller() + +SYNOPSIS + int HandleTeller(string str) + +DESCRIPTION + The LIB_BANK inheritable is a kind of 'wrapper' for the LIB_TELLER npc. Rather than have to type 'ask zoe to withdraw 100 dollars', that add_actions in LIB_BANK catch the 'withdraw' command and send it and the arguments provided to the teller, so a player can just type 'withdraw 100 dollars'. The HandleTeller() function provides that call to the npc. + +EXAMPLES + + +LOCATION + /lib/bank + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/HealLimb b/lib/doc/lfun/all/HealLimb new file mode 100644 index 0000000..12bb307 --- /dev/null +++ b/lib/doc/lfun/all/HealLimb @@ -0,0 +1,24 @@ +HEALLIMB + +NAME + HealLimb() + +SYNOPSIS + int HealLimb(string limb) + +DESCRIPTION + If the creature possesses the limb in question, its maximum health points are restored. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/InitComposition b/lib/doc/lfun/all/InitComposition new file mode 100644 index 0000000..c9d24f9 --- /dev/null +++ b/lib/doc/lfun/all/InitComposition @@ -0,0 +1,23 @@ +INITCOMPOSITION + +NAME + InitComposition() + +SYNOPSIS + void InitComposition() + +DESCRIPTION + This is a function internal to LIB_CLAY which is called in create() to initialize its values. + +EXAMPLES + + +LOCATION + /lib/clay + +SEE ALSO + SetComposition + +Author + Cratylus + diff --git a/lib/doc/lfun/all/ModCharge b/lib/doc/lfun/all/ModCharge new file mode 100644 index 0000000..a08089b --- /dev/null +++ b/lib/doc/lfun/all/ModCharge @@ -0,0 +1,24 @@ +MODCHARGE + +NAME + ModCharge() + +SYNOPSIS + int ModCharge(int i) + +DESCRIPTION + Arbitrarily changes the charge setting of a battery without incurring all the actions of SetCharge. + +EXAMPLES + + +LOCATION + /lib/battery.c + + +SEE ALSO + SetCharge, GetCharge + +Author + Cratylus + diff --git a/lib/doc/lfun/all/NewBody b/lib/doc/lfun/all/NewBody new file mode 100644 index 0000000..5ebc142 --- /dev/null +++ b/lib/doc/lfun/all/NewBody @@ -0,0 +1,31 @@ +NEWBODY + +NAME + NewBody() + + +SYNOPSIS + void NewBody(string race) + + +DESCRIPTION + Initializes some body-specific mappings. A null race creates potentially undesirable outcomes. + + +EXAMPLES + + + +LOCATION + /lib/body +/lib/race + + +SEE ALSO + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/ParseHook b/lib/doc/lfun/all/ParseHook new file mode 100644 index 0000000..902a6b1 --- /dev/null +++ b/lib/doc/lfun/all/ParseHook @@ -0,0 +1,24 @@ +PARSEHOOK + +NAME + ParseHook() + +SYNOPSIS + void ParseHook(string str) + +DESCRIPTION + This is a test function designed to invoke the parse_sentence function in the creature. As of Dead Souls 2.1 it is largely unused. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/PlusAmmo b/lib/doc/lfun/all/PlusAmmo new file mode 100644 index 0000000..751a72f --- /dev/null +++ b/lib/doc/lfun/all/PlusAmmo @@ -0,0 +1,23 @@ +PLUSAMMO + +NAME + + +SYNOPSIS + + +DESCRIPTION + + +EXAMPLES + + +LOCATION + + +SEE ALSO + + +Author + One + diff --git a/lib/doc/lfun/all/RemoveBonuses b/lib/doc/lfun/all/RemoveBonuses new file mode 100644 index 0000000..e5cb2f5 --- /dev/null +++ b/lib/doc/lfun/all/RemoveBonuses @@ -0,0 +1,24 @@ +REMOVEBONUSES + +NAME + RemoveBonuses() + +SYNOPSIS + int RemoveBonuses() + +DESCRIPTION + Remove the effects of a bonus from a creature. + +EXAMPLES + + +LOCATION + /lib/bonus + + +SEE ALSO + SetBonuses + +Author + Cratylus + diff --git a/lib/doc/lfun/all/RemoveChannel b/lib/doc/lfun/all/RemoveChannel new file mode 100644 index 0000000..b53dcbd --- /dev/null +++ b/lib/doc/lfun/all/RemoveChannel @@ -0,0 +1,24 @@ +REMOVECHANNEL + +NAME + RemoveChannel() + +SYNOPSIS + string array RemoveChannel(mixed val) + +DESCRIPTION + Deletes a channel from the list of channels accessible to the user. + +EXAMPLES + + +LOCATION + /lib/chat + + +SEE ALSO + AddChannel, RemoveChannel, GetChannels, returnChannels + +Author + Cratylus + diff --git a/lib/doc/lfun/all/RemoveExtraChannels b/lib/doc/lfun/all/RemoveExtraChannels new file mode 100644 index 0000000..8ff27f8 --- /dev/null +++ b/lib/doc/lfun/all/RemoveExtraChannels @@ -0,0 +1,29 @@ +REMOVEEXTRACHANNELS + +NAME + RemoveExtraChannels() + + +SYNOPSIS + string array RemoveExtraChannels(string array chans) + + +DESCRIPTION + Removes channels from the player's extra channels. Extra channels are part of a channel test system and will be largely unused post Dead Souls 2.1. + + +EXAMPLES + + + +LOCATION + /lib/body + + +SEE ALSO + SetExtraChannels, GetExtraChannels, AddExtraChannels, RemoveExtraChannels + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/RemoveLimb b/lib/doc/lfun/all/RemoveLimb new file mode 100644 index 0000000..e651bbe --- /dev/null +++ b/lib/doc/lfun/all/RemoveLimb @@ -0,0 +1,25 @@ +REMOVELIMB + +NAME + RemoveLimb() + +SYNOPSIS + int RemoveLimb(string limb, object agent) + +DESCRIPTION + Removes a limb from the limbs mapping and stores vital data in the missing limbs mapping. string limb - the limb being removed. object agent - the agent who is responsible for the limb removal. Returns -1 on error, 0 on failure, 1 on success. + +EXAMPLES + + + +LOCATION + /lib/body + + +SEE ALSO + RestoreLimb, DestLimb, AddLimb + +Author + Unknown + diff --git a/lib/doc/lfun/all/RemoveMagicProtection b/lib/doc/lfun/all/RemoveMagicProtection new file mode 100644 index 0000000..674ff77 --- /dev/null +++ b/lib/doc/lfun/all/RemoveMagicProtection @@ -0,0 +1,24 @@ +REMOVEMAGICPROTECTION + +NAME + RemoveMagicProtection() + +SYNOPSIS + int RemoveMagicProtection(int i) + +DESCRIPTION + If there is a protection function element i, for example Protection[3], it is removed from the creature's protections. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + AddMagicProtection + +Author + Cratylus + diff --git a/lib/doc/lfun/all/RestoreLimb b/lib/doc/lfun/all/RestoreLimb new file mode 100644 index 0000000..765a30c --- /dev/null +++ b/lib/doc/lfun/all/RestoreLimb @@ -0,0 +1,24 @@ +RESTORELIMB + +NAME + RestoreLimb() + +SYNOPSIS + varargs int RestoreLimb(string limb, int recurse) + +DESCRIPTION + This is the function that should be used to put tail back on something that used to have a tail and no longer does because it was severed. Using AddLimb() for that purpose is not recommended. If the optional argument "recurse" is a positive integer, the function will restore the limb and anything distal to it. If the limb to be restored is attached to a limb that does not exist, the function will fail. + +EXAMPLES + To restore the arm plus its children (in this case, a hand): RestoreLimb("right arm",1) . RestoreLimb("right arm") will restore the arm only. + +LOCATION + /lib/body + + +SEE ALSO + RemoveLimb, DestLimb, AddLimb + +Author + Cratylus + diff --git a/lib/doc/lfun/all/RestrictChannel b/lib/doc/lfun/all/RestrictChannel new file mode 100644 index 0000000..c0583f9 --- /dev/null +++ b/lib/doc/lfun/all/RestrictChannel @@ -0,0 +1,24 @@ +RESTRICTCHANNEL + +NAME + RestrictChannel() + +SYNOPSIS + string array RestrictChannel(mixed val) + +DESCRIPTION + Limit the availability of the given channel(s) to the user. + +EXAMPLES + + +LOCATION + /lib/chat + + +SEE ALSO + AddChannel, RemoveChannel, GetChannels, returnChannels + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetAllowSacrifice b/lib/doc/lfun/all/SetAllowSacrifice new file mode 100644 index 0000000..4ca03fe --- /dev/null +++ b/lib/doc/lfun/all/SetAllowSacrifice @@ -0,0 +1,24 @@ +SETALLOWSACRIFICE + +NAME + SetAllowSacrifice() + +SYNOPSIS + int SetAllowSacrifice(int x) + +DESCRIPTION + Returns whether sacrifices are allowed at all here. + +EXAMPLES + + +LOCATION + /lib/chapel + + +SEE ALSO + SetAllowSacrifice, GetAllowSacrifice, SetSacrificeType, AddSacrificeType, GetSacrificeType, eventSacrifice, CanSacrifice + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetAmmoType b/lib/doc/lfun/all/SetAmmoType new file mode 100644 index 0000000..a0ab48c --- /dev/null +++ b/lib/doc/lfun/all/SetAmmoType @@ -0,0 +1,26 @@ +SETAMMOTYPE + +NAME + SetAmmoType() + +SYNOPSIS + int SetAmmoType(string str) + +DESCRIPTION + If the ammunition type is set on a clip or a round, they must match in order to be compatible. This function defines the string for that information. + +EXAMPLES + SetAmmoType("acp") + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetAmmoType, GetFirearmType, SetFirearmType + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetBodyComposition b/lib/doc/lfun/all/SetBodyComposition new file mode 100644 index 0000000..51c09f5 --- /dev/null +++ b/lib/doc/lfun/all/SetBodyComposition @@ -0,0 +1,29 @@ +SETBODYCOMPOSITION + +NAME + SetBodyComposition() + + +SYNOPSIS + string SetBodyComposition(string str) + + +DESCRIPTION + Creatures without biological components, such as golems, have this set so that when they die, the appropriate chunks of matter are put into the room, rather than a fleshy corpse. + + +EXAMPLES + SetBodyComposition("clay") + +LOCATION + /lib/body + + +SEE ALSO + GetBodyComposition + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/SetBonusDuration b/lib/doc/lfun/all/SetBonusDuration new file mode 100644 index 0000000..8c83734 --- /dev/null +++ b/lib/doc/lfun/all/SetBonusDuration @@ -0,0 +1,24 @@ +SETBONUSDURATION + +NAME + SetBonusDuration() + +SYNOPSIS + int SetBonusDuration(int i) + +DESCRIPTION + Specifies the number of heartbeats that should elapse before a bonus's effects wear off. + +EXAMPLES + SetBonusDuration(100) + +LOCATION + /lib/bonus + + +SEE ALSO + SetPoints, SetSkills, SetStats + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetBonuses b/lib/doc/lfun/all/SetBonuses new file mode 100644 index 0000000..9140f0e --- /dev/null +++ b/lib/doc/lfun/all/SetBonuses @@ -0,0 +1,25 @@ +SETBONUSES + +NAME + SetBonuses() + +SYNOPSIS + int SetBonuses() + +DESCRIPTION + A function internal to LIB_BONUS which cycles through the bonuses set on the object and applies them. + +EXAMPLES + + + +LOCATION + /lib/bonus + + +SEE ALSO + RemoveBonuses + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetBurnRate b/lib/doc/lfun/all/SetBurnRate new file mode 100644 index 0000000..b62ffe7 --- /dev/null +++ b/lib/doc/lfun/all/SetBurnRate @@ -0,0 +1,29 @@ +SETBURNRATE + +NAME + SetBurnRate() + + +SYNOPSIS + static int SetBurnRate(int x) + + +DESCRIPTION + Returns the rate at which a thing burns. A higher number is a slower burn. + +EXAMPLES + To consume one unit of fuel every 5 heart beats: SetBurnRate(5) + +LOCATION + /lib/burn +/lib/lamp + + +SEE ALSO + GetBurnRate + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/SetCaliber b/lib/doc/lfun/all/SetCaliber new file mode 100644 index 0000000..eacc5f5 --- /dev/null +++ b/lib/doc/lfun/all/SetCaliber @@ -0,0 +1,26 @@ +SETCALIBER + +NAME + SetCaliber() + +SYNOPSIS + int SetCaliber(int x) + +DESCRIPTION + Caliber is a measurement of ammunition size, different from millimeters. If this is set on a round or a firearm, then the round and firearm must match calibers in order to be compatible. + +EXAMPLES + SetCaliber(357) + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetCaliber, SetMillimeter, GetMillimeter + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetCanBite b/lib/doc/lfun/all/SetCanBite new file mode 100644 index 0000000..35f6313 --- /dev/null +++ b/lib/doc/lfun/all/SetCanBite @@ -0,0 +1,24 @@ +SETCANBITE + +NAME + SetCanBite() + +SYNOPSIS + int SetCanBite(int i) + +DESCRIPTION + Some creatures are physically capable of biting during combat, but it may not be desirable to allow it. Setting this to 0 can allow a demigod, for example, to keep his dignity in unarmed combat. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + GetCanBite + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetCellType b/lib/doc/lfun/all/SetCellType new file mode 100644 index 0000000..95649e7 --- /dev/null +++ b/lib/doc/lfun/all/SetCellType @@ -0,0 +1,36 @@ +SETCELLTYPE + +NAME + SetCellType() + + + +SYNOPSIS + int SetCellType(string str) + + + +DESCRIPTION + In LIB_BATTERY, sets the battery in question to the appropriate type, such as C, AA, etc.\nIn LIB_FLASHLIGHT, sets what kind of batteries it will accept. + + + +EXAMPLES + SetCellType("D") + + + +LOCATION + /lib/battery +/lib/flashlight + + +SEE ALSO + GetCellType + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/SetCharge b/lib/doc/lfun/all/SetCharge new file mode 100644 index 0000000..2ed0b6e --- /dev/null +++ b/lib/doc/lfun/all/SetCharge @@ -0,0 +1,24 @@ +SETCHARGE + +NAME + SetCharge() + +SYNOPSIS + int SetCharge(int i) + +DESCRIPTION + Sets the amount of power left in the battery. + +EXAMPLES + A battery with a drain rate of one will be a two-minute battery with this: SetCharge(120) + +LOCATION + /lib/battery.c + + +SEE ALSO + GetCharge + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetClan b/lib/doc/lfun/all/SetClan new file mode 100644 index 0000000..9462b96 --- /dev/null +++ b/lib/doc/lfun/all/SetClan @@ -0,0 +1,23 @@ +SETCLAN + +NAME + SetClan() + +SYNOPSIS + string SetClan(string clan) + +DESCRIPTION + Sets which clan the player belongs to. This is saved in the player object. + +EXAMPLES + + +LOCATION + /lib/classes + +SEE ALSO + GetClan + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetClanName b/lib/doc/lfun/all/SetClanName new file mode 100644 index 0000000..192a476 --- /dev/null +++ b/lib/doc/lfun/all/SetClanName @@ -0,0 +1,23 @@ +SETCLANNAME + +NAME + SetClanName() + +SYNOPSIS + string SetClanName(string str) + +DESCRIPTION + Establishes the name of the clan that the clan object belongs to. + +EXAMPLES + SetClanName("Warriors") + +LOCATION + /lib/clan + +SEE ALSO + GetClanName + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetClanObject b/lib/doc/lfun/all/SetClanObject new file mode 100644 index 0000000..8258a2a --- /dev/null +++ b/lib/doc/lfun/all/SetClanObject @@ -0,0 +1,23 @@ +SETCLANOBJECT + +NAME + SetClanObject() + +SYNOPSIS + string SetClanObject(string str) + +DESCRIPTION + Establishes the unique id of the clan's "clan object", which confers membership. + +EXAMPLES + SetClanObject("snoo") + +LOCATION + /lib/clan + +SEE ALSO + GetClanObject + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetClanSkill b/lib/doc/lfun/all/SetClanSkill new file mode 100644 index 0000000..72821cf --- /dev/null +++ b/lib/doc/lfun/all/SetClanSkill @@ -0,0 +1,23 @@ +SETCLANSKILL + +NAME + SetClanSkill() + +SYNOPSIS + string SetClanSkill(string str) + +DESCRIPTION + Sets the name of the skill that clan membership entitles one to. + +EXAMPLES + + +LOCATION + /lib/clan + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetClass b/lib/doc/lfun/all/SetClass new file mode 100644 index 0000000..1b42558 --- /dev/null +++ b/lib/doc/lfun/all/SetClass @@ -0,0 +1,27 @@ +SETCLASS + +NAME + SetClass() + +SYNOPSIS + string SetClass(string class_name) + +DESCRIPTION + If the creature does not currently have a class, its class is set to the string specified. If the creature already has a class, that class name is returned. + +EXAMPLES + + +LOCATION + /lib/classes +/lib/npc +/lib/player +/lib/props/damage + + +SEE ALSO + ChangeClass + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetComposition b/lib/doc/lfun/all/SetComposition new file mode 100644 index 0000000..2062575 --- /dev/null +++ b/lib/doc/lfun/all/SetComposition @@ -0,0 +1,23 @@ +SETCOMPOSITION + +NAME + SetComposition() + +SYNOPSIS + varargs string SetComposition(string comp, string name, string *nouns, string *adjs, string short, string desc) + +DESCRIPTION + LIB_CLAY is an object that provides a flexible means for creating "chunks" of things, such as a chunk of clay when a clay golem has an arm amputated. A new chunk, inheriting LIB_CLAY, uses SetComposition to establish what kind of thing it is. + +EXAMPLES + ob = new(LIB_CLAY); ob->SetComposition(this_object()->GetBodyComposition(), "hunk", ({"chunk","hunk","piece"}), ({"plastic"}), "a plastic chunk","This is a piece of plastic.") + +LOCATION + /lib/clay + +SEE ALSO + InitComposition + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetDeathEvents b/lib/doc/lfun/all/SetDeathEvents new file mode 100644 index 0000000..af9ab30 --- /dev/null +++ b/lib/doc/lfun/all/SetDeathEvents @@ -0,0 +1,24 @@ +SETDEATHEVENTS + +NAME + SetDeathEvents() + +SYNOPSIS + int SetDeathEvents(int i) + +DESCRIPTION + This function is called in order to establish how many times this body has been "killed". Under rare circumstances a body may receive more than one kill blow simultaneously. This is part of a system to prevent the weirdness that results from such an event. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetDrainRate b/lib/doc/lfun/all/SetDrainRate new file mode 100644 index 0000000..dfa4460 --- /dev/null +++ b/lib/doc/lfun/all/SetDrainRate @@ -0,0 +1,36 @@ +SETDRAINRATE + +NAME + SetDrainRate() + + + +SYNOPSIS + int SetDrainRate(int i) + + + +DESCRIPTION + Sets how much of a battery's charge is drained per heartbeat of use. + + + +EXAMPLES + For a two-minute battery with a charge of 120 on a mud with a one-second heartbeat: SetDrainRate(1) + + + +LOCATION + /lib/battery +/lib/flashlight + + +SEE ALSO + GetDrainRate, SetCharge, GetCharge + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/SetDrainable b/lib/doc/lfun/all/SetDrainable new file mode 100644 index 0000000..0e830b0 --- /dev/null +++ b/lib/doc/lfun/all/SetDrainable @@ -0,0 +1,24 @@ +SETDRAINABLE + +NAME + SetDrainable() + +SYNOPSIS + int SetDrainable(int i) + +DESCRIPTION + Sets whether a battery actually loses power over time or not. + +EXAMPLES + For an everlasting battery: SetDrainable(0) + +LOCATION + /lib/battery.c + + +SEE ALSO + GetDrainable, SetDrainRate, GetDrainRate + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetExtraChannels b/lib/doc/lfun/all/SetExtraChannels new file mode 100644 index 0000000..4e27e37 --- /dev/null +++ b/lib/doc/lfun/all/SetExtraChannels @@ -0,0 +1,24 @@ +SETEXTRACHANNELS + +NAME + SetExtraChannels() + +SYNOPSIS + string array SetExtraChannels(string array chans) + +DESCRIPTION + Sets the player's extra channels. Extra channels are part of a channel test system and will be largely unused post Dead Souls 2.1. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + SetExtraChannels, GetExtraChannels, AddExtraChannels, RemoveExtraChannels + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetFingers b/lib/doc/lfun/all/SetFingers new file mode 100644 index 0000000..b2419a0 --- /dev/null +++ b/lib/doc/lfun/all/SetFingers @@ -0,0 +1,31 @@ +SETFINGERS + +NAME + + + +SYNOPSIS + + + +DESCRIPTION + + + +EXAMPLES + + + +LOCATION + /lib/std/armor +/lib/std/worn_storage + + +SEE ALSO + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/SetFirearmType b/lib/doc/lfun/all/SetFirearmType new file mode 100644 index 0000000..dc58dc7 --- /dev/null +++ b/lib/doc/lfun/all/SetFirearmType @@ -0,0 +1,26 @@ +SETFIREARMTYPE + +NAME + SetFirearmType() + +SYNOPSIS + int SetFirearmType(string str) + +DESCRIPTION + If the firearm type is set on a clip or a round, they must match in order to be compatible. This function defines the string for that information. + +EXAMPLES + SetFirearmType("auto") + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetAmmoType, SetAmmoType, GetFirearmType + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetFuelRequired b/lib/doc/lfun/all/SetFuelRequired new file mode 100644 index 0000000..a9e9692 --- /dev/null +++ b/lib/doc/lfun/all/SetFuelRequired @@ -0,0 +1,24 @@ +SETFUELREQUIRED + +NAME + SetFuelRequired() + +SYNOPSIS + static int SetFuelRequired(int x) + +DESCRIPTION + Sets whether a thing requires fuel in order to burn. + +EXAMPLES + + +LOCATION + /lib/burn + + +SEE ALSO + GetFuelRequired + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetHeat b/lib/doc/lfun/all/SetHeat new file mode 100644 index 0000000..9af9d90 --- /dev/null +++ b/lib/doc/lfun/all/SetHeat @@ -0,0 +1,24 @@ +SETHEAT + +NAME + SetHeat() + +SYNOPSIS + static int SetHeat(int x) + +DESCRIPTION + Sets the heat given off by the item. + +EXAMPLES + + +LOCATION + /lib/burn + + +SEE ALSO + GetHeat, GetMinHeat, SetMinHeat + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetLeader b/lib/doc/lfun/all/SetLeader new file mode 100644 index 0000000..210b90a --- /dev/null +++ b/lib/doc/lfun/all/SetLeader @@ -0,0 +1,24 @@ +SETLEADER + +NAME + SetLeader() + +SYNOPSIS + LIB_CLAN: string SetLeader(string str)\nLIB_FOLLOW: object SetLeader(object leader) + +DESCRIPTION + Sets who the leader is in the given context. Note that LIB_FOLLOW uses the object datatype and LIB_CLAN uses string. + +EXAMPLES + + +LOCATION + /lib/clan +/lib/follow + +SEE ALSO + GetLeader + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetMelee b/lib/doc/lfun/all/SetMelee new file mode 100644 index 0000000..9a2fbe6 --- /dev/null +++ b/lib/doc/lfun/all/SetMelee @@ -0,0 +1,29 @@ +SETMELEE + +NAME + SetMelee() + + +SYNOPSIS + int SetMelee(int i) + + +DESCRIPTION + Allows the npc this is called in to be capable of unarmed combat if the integer passed is 1. An argument of 0 indicates that the npc is not able to properly fight without weapons. + + +EXAMPLES + + + +LOCATION + /lib/body + + +SEE ALSO + GetMelee + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/SetMillimeter b/lib/doc/lfun/all/SetMillimeter new file mode 100644 index 0000000..9b33f96 --- /dev/null +++ b/lib/doc/lfun/all/SetMillimeter @@ -0,0 +1,26 @@ +SETMILLIMETER + +NAME + SetMillimeter() + +SYNOPSIS + int SetMillimeter(int x) + +DESCRIPTION + Millimeter is a measurement of ammunition size, different from caliber. If this is set on a round or a firearm, then the round and firearm must match millimeter definition in order to be compatible. + +EXAMPLES + SetMillimeter(9) + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetCaliber, SetCaliber, GetMillimeter + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetMinHeat b/lib/doc/lfun/all/SetMinHeat new file mode 100644 index 0000000..e678c6a --- /dev/null +++ b/lib/doc/lfun/all/SetMinHeat @@ -0,0 +1,24 @@ +SETMINHEAT + +NAME + SetMinHeat() + +SYNOPSIS + static int SetMinHeat(int x) + +DESCRIPTION + Sets the minimum amount of heat required for the item to give off light. + +EXAMPLES + + +LOCATION + /lib/burn + + +SEE ALSO + GetHeat, SetHeat, GetMinHeat + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetMorality b/lib/doc/lfun/all/SetMorality new file mode 100644 index 0000000..14275ea --- /dev/null +++ b/lib/doc/lfun/all/SetMorality @@ -0,0 +1,24 @@ +SETMORALITY + +NAME + SetMorality() + +SYNOPSIS + int SetMorality(int x) + +DESCRIPTION + Sets the morality of the object. + +EXAMPLES + + +LOCATION + /lib/classes +/lib/spell + +SEE ALSO + GetMorality + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetNoChanColors b/lib/doc/lfun/all/SetNoChanColors new file mode 100644 index 0000000..5223d80 --- /dev/null +++ b/lib/doc/lfun/all/SetNoChanColors @@ -0,0 +1,24 @@ +SETNOCHANCOLORS + +NAME + SetNoChanColors() + +SYNOPSIS + int SetNoChanColors(int x) + +DESCRIPTION + Users can disable seeing colors in channel messages. This lfun sets that parameter in the player object. + +EXAMPLES + SetNoChanColors(1) + +LOCATION + /lib/chat + + +SEE ALSO + GetNoChanColors + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetPacifist b/lib/doc/lfun/all/SetPacifist new file mode 100644 index 0000000..36e4b85 --- /dev/null +++ b/lib/doc/lfun/all/SetPacifist @@ -0,0 +1,24 @@ +SETPACIFIST + +NAME + SetPacifist() + +SYNOPSIS + int SetPacifist(int i) + +DESCRIPTION + An argument of 1 makes the creature a pacifist. 0 makes it not a pacifist. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + GetPacifist + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetPoints b/lib/doc/lfun/all/SetPoints new file mode 100644 index 0000000..a4771a5 --- /dev/null +++ b/lib/doc/lfun/all/SetPoints @@ -0,0 +1,25 @@ +SETPOINTS + +NAME + SetPoints() + +SYNOPSIS + mapping SetPoints(mapping arg) + +DESCRIPTION + In LIB_POTION and LIB_BONUS, this lfun specifies which vital points are affected, and by how much. + +EXAMPLES + SetPoints( ([ "HP" : 100, "SP" : 50 ]) ); + +LOCATION + /lib/bonus +/lib/potion + + +SEE ALSO + GetPoints, SetBonusDuration, GetBonusDuration + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetPowerType b/lib/doc/lfun/all/SetPowerType new file mode 100644 index 0000000..f1fc3da --- /dev/null +++ b/lib/doc/lfun/all/SetPowerType @@ -0,0 +1,24 @@ +SETPOWERTYPE + +NAME + SetPowerType() + +SYNOPSIS + int SetPowerType(string str) + +DESCRIPTION + Sets the battery to the desired type, typically AC, DC, Fusion, whatever. + +EXAMPLES + SetPowerType("hydrogen") + +LOCATION + /lib/battery.c + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetProtect b/lib/doc/lfun/all/SetProtect new file mode 100644 index 0000000..bf2f0f3 --- /dev/null +++ b/lib/doc/lfun/all/SetProtect @@ -0,0 +1,32 @@ +SETPROTECT + +NAME + SetProtect() + + + +SYNOPSIS + mixed SetProtect(function f) + + + +DESCRIPTION + Sets a function (f) to be the one called when GetProtect is called. + + +EXAMPLES + + + + +LOCATION + /lib/body + + +SEE ALSO + GetProtect, RemoveMagicProtection, AddMagicProtection + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/SetRechargeable b/lib/doc/lfun/all/SetRechargeable new file mode 100644 index 0000000..6de7236 --- /dev/null +++ b/lib/doc/lfun/all/SetRechargeable @@ -0,0 +1,24 @@ +SETRECHARGEABLE + +NAME + SetRechargeable() + +SYNOPSIS + int SetRechargeable(int i) + +DESCRIPTION + Makes the battery capable of being recharged. + +EXAMPLES + + +LOCATION + /lib/battery.c + + +SEE ALSO + GetRechargeable, SetCharge, GetCharge + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetReligion b/lib/doc/lfun/all/SetReligion new file mode 100644 index 0000000..dd04a58 --- /dev/null +++ b/lib/doc/lfun/all/SetReligion @@ -0,0 +1,24 @@ +SETRELIGION + +NAME + SetReligion() + +SYNOPSIS + string array SetReligion(string adj, string noun) + +DESCRIPTION + Sets the religion of the object. + +EXAMPLES + + +LOCATION + /lib/chapel +/lib/classes + +SEE ALSO + GetReligion + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetSacrificeType b/lib/doc/lfun/all/SetSacrificeType new file mode 100644 index 0000000..9cc183f --- /dev/null +++ b/lib/doc/lfun/all/SetSacrificeType @@ -0,0 +1,24 @@ +SETSACRIFICETYPE + +NAME + SetSacrificeType() + +SYNOPSIS + int SetSacrificeType(int x) + +DESCRIPTION + Set what kind of sacrifice is permitted here. Unimplemented in Dead Souls 2.1. + +EXAMPLES + + +LOCATION + /lib/chapel + + +SEE ALSO + SetAllowSacrifice, GetAllowSacrifice, SetSacrificeType, AddSacrificeType, GetSacrificeType, eventSacrifice, CanSacrifice + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetSkillModifier b/lib/doc/lfun/all/SetSkillModifier new file mode 100644 index 0000000..3b72080 --- /dev/null +++ b/lib/doc/lfun/all/SetSkillModifier @@ -0,0 +1,23 @@ +SETSKILLMODIFIER + +NAME + SetSkillModifier() + +SYNOPSIS + static string SetSkillModifier(string skill, string stat) + +DESCRIPTION + Establishes which of your stats (eg, strength, intelligence) affects the specified skill. + +EXAMPLES + + +LOCATION + /lib/classes + +SEE ALSO + GetSkillModifier + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetSkills b/lib/doc/lfun/all/SetSkills new file mode 100644 index 0000000..2a3c39d --- /dev/null +++ b/lib/doc/lfun/all/SetSkills @@ -0,0 +1,26 @@ +SETSKILLS + +NAME + SetSkills() + +SYNOPSIS + mapping SetSkills(mapping mp) + +DESCRIPTION + For LIB_SPELL this sets the required skills to be able to cast a spell, and the required level for each skill. For LIB_POTION and LIB_BONUS, this sets the skills altered by drinking the potion. + +EXAMPLES + SetSkills( ([ "cleverness" : 1 ]) ) + +LOCATION + /lib/bonus +/lib/potion +/lib/spell + + +SEE ALSO + GetSkills, SetStats, GetStats + +Author + Cratylus + diff --git a/lib/doc/lfun/all/SetSleeping b/lib/doc/lfun/all/SetSleeping new file mode 100644 index 0000000..639c300 --- /dev/null +++ b/lib/doc/lfun/all/SetSleeping @@ -0,0 +1,30 @@ +SETSLEEPING + +NAME + SetSleeping() + + +SYNOPSIS + int SetSleeping(int i) + + +DESCRIPTION + Set the creature to its sleep state, for a heartbeat duration of the number specified multiplied by the standard modifier, which in Dead Souls 2.1 is 6. + + +EXAMPLES + To make Tacitus sleep for 60 heart_beats (note that his heart_beats may be more than just one second long): find_player("tacitus")->SetSleeping(10) + + +LOCATION + /lib/body + + +SEE ALSO + GetSleeping + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/SetStats b/lib/doc/lfun/all/SetStats new file mode 100644 index 0000000..907c5a0 --- /dev/null +++ b/lib/doc/lfun/all/SetStats @@ -0,0 +1,25 @@ +SETSTATS + +NAME + SetStats() + +SYNOPSIS + mapping SetStats(mapping arg) + +DESCRIPTION + Sets which stats are altered by a potion or bonus, and to what extent. + +EXAMPLES + SetStats( ([ "strength" : 30, "intelligence" : -30 ]) ) + +LOCATION + /lib/bonus +/lib/potion + + +SEE ALSO + GetStats, SetSkills, GetSkills + +Author + Cratylus + diff --git a/lib/doc/lfun/all/Spent b/lib/doc/lfun/all/Spent new file mode 100644 index 0000000..afb8d84 --- /dev/null +++ b/lib/doc/lfun/all/Spent @@ -0,0 +1,24 @@ +SPENT + +NAME + Spent() + +SYNOPSIS + int Spent() + +DESCRIPTION + Sets the given battery to its "spent" state, with no charge and a new description. + +EXAMPLES + + +LOCATION + /lib/battery.c + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/UnrestrictChannel b/lib/doc/lfun/all/UnrestrictChannel new file mode 100644 index 0000000..8b0f8dc --- /dev/null +++ b/lib/doc/lfun/all/UnrestrictChannel @@ -0,0 +1,24 @@ +UNRESTRICTCHANNEL + +NAME + UnrestrictChannel() + +SYNOPSIS + string array UnrestrictChannel(mixed val) + +DESCRIPTION + Removes the user's limitations on the channel(s) specified. + +EXAMPLES + + +LOCATION + /lib/chat + + +SEE ALSO + AddChannel, RemoveChannel, GetChannels, returnChannels + +Author + Cratylus + diff --git a/lib/doc/lfun/all/chat_command b/lib/doc/lfun/all/chat_command new file mode 100644 index 0000000..d0dd2cd --- /dev/null +++ b/lib/doc/lfun/all/chat_command @@ -0,0 +1,24 @@ +CHAT_COMMAND + +NAME + chat_command() + +SYNOPSIS + static string chat_command(string str) + +DESCRIPTION + Intercepts all commands issued by the user and determines whether they are channel commands. If so, they are processed by the chat daemon. If not, they are allowed to continue on their merry way. + +EXAMPLES + + +LOCATION + /lib/chat + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/checkCollapse b/lib/doc/lfun/all/checkCollapse new file mode 100644 index 0000000..c5d84c1 --- /dev/null +++ b/lib/doc/lfun/all/checkCollapse @@ -0,0 +1,24 @@ +CHECKCOLLAPSE + +NAME + checkCollapse() + +SYNOPSIS + private void checkCollapse() + +DESCRIPTION + This function is periodically called to find out if the creature is too weak to stand, or if it is strong enough to get back up. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/eventBring b/lib/doc/lfun/all/eventBring new file mode 100644 index 0000000..0257dcd --- /dev/null +++ b/lib/doc/lfun/all/eventBring @@ -0,0 +1,23 @@ +EVENTBRING + +NAME + eventBring() + +SYNOPSIS + int eventBring(string str) + +DESCRIPTION + A clan master is empowered to attempt to teleport a member to her location. This function performs the work for that event. + +EXAMPLES + eventBring("doofus") + +LOCATION + /lib/clan + +SEE ALSO + eventJoin, eventUnjoin, eventInitiate, eventRetire + +Author + Cratylus + diff --git a/lib/doc/lfun/all/eventBurnOut b/lib/doc/lfun/all/eventBurnOut new file mode 100644 index 0000000..fa089ce --- /dev/null +++ b/lib/doc/lfun/all/eventBurnOut @@ -0,0 +1,24 @@ +EVENTBURNOUT + +NAME + eventBurnOut() + +SYNOPSIS + mixed eventBurnOut() + +DESCRIPTION + Initiates the events associated with the expiration of a burn source. + +EXAMPLES + + +LOCATION + /lib/burn + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/eventBuy b/lib/doc/lfun/all/eventBuy new file mode 100644 index 0000000..0a8b2f5 --- /dev/null +++ b/lib/doc/lfun/all/eventBuy @@ -0,0 +1,36 @@ +EVENTBUY + +NAME + eventBuy() + + + +SYNOPSIS + LIB_BODY: varargs mixed eventBuy(mixed arg1, mixed arg2, mixed arg3) LIB_VENDOR: mixed eventBuy(object who, object *obs) + + + +DESCRIPTION + In LIB_BODY, this is a function designed to return an error. If the creature is supposed to be able to do something with this function (such as vendors), it should be overridden with the appropriate code. LIB_VENDOR: This is called when someone tries to sell something to the vendor. The seller is who, and the items being sold is *obs. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/std/vendor + + +SEE ALSO + eventSell + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/eventCharge b/lib/doc/lfun/all/eventCharge new file mode 100644 index 0000000..5dd0cbe --- /dev/null +++ b/lib/doc/lfun/all/eventCharge @@ -0,0 +1,24 @@ +EVENTCHARGE + +NAME + eventCharge() + +SYNOPSIS + int eventCharge(int i) + +DESCRIPTION + Causes a battery to be charged by the integer specified. + +EXAMPLES + + +LOCATION + /lib/battery.c + + +SEE ALSO + SetCharge, GetCharge + +Author + Cratylus + diff --git a/lib/doc/lfun/all/eventCheckHealing b/lib/doc/lfun/all/eventCheckHealing new file mode 100644 index 0000000..59b12ce --- /dev/null +++ b/lib/doc/lfun/all/eventCheckHealing @@ -0,0 +1,24 @@ +EVENTCHECKHEALING + +NAME + eventCheckHealing() + +SYNOPSIS + void eventCheckHealing() + +DESCRIPTION + This function performs the general, periodic tasks associated with the effects of the passage of time on a body. Sleep, food, and drink levels are decremented, the actual healing function is triggered if appropriate, etc. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + eventCompleteHeal + +Author + Cratylus + diff --git a/lib/doc/lfun/all/eventCheckProtection b/lib/doc/lfun/all/eventCheckProtection new file mode 100644 index 0000000..1a9c435 --- /dev/null +++ b/lib/doc/lfun/all/eventCheckProtection @@ -0,0 +1,24 @@ +EVENTCHECKPROTECTION + +NAME + eventCheckProtection() + +SYNOPSIS + int eventCheckProtection(object agent, int type, int damage) + +DESCRIPTION + This function cycles through any magic protection found, reducing damage accordingly. agent : object doing the damage. type : damage type(s). damage : original amount damage being done. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + SetProtect, GetProtect, RemoveMagicProtection, AddMagicProtection + +Author + Unknown + diff --git a/lib/doc/lfun/all/eventCollapse b/lib/doc/lfun/all/eventCollapse new file mode 100644 index 0000000..5f406ea --- /dev/null +++ b/lib/doc/lfun/all/eventCollapse @@ -0,0 +1,24 @@ +EVENTCOLLAPSE + +NAME + eventCollapse() + +SYNOPSIS + int eventCollapse() + +DESCRIPTION + Runs the appropriate events on and about the collapse of a creature. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/eventCompareLimbs b/lib/doc/lfun/all/eventCompareLimbs new file mode 100644 index 0000000..6f70501 --- /dev/null +++ b/lib/doc/lfun/all/eventCompareLimbs @@ -0,0 +1,24 @@ +EVENTCOMPARELIMBS + +NAME + eventCompareLimbs() + +SYNOPSIS + int eventCompareLimbs(string limb1, string limb2) + +DESCRIPTION + A test function designed to be run by the GetMissingLimbs fun. Largely unused in Dead Souls 2.1. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/eventCompleteHeal b/lib/doc/lfun/all/eventCompleteHeal new file mode 100644 index 0000000..77b16c8 --- /dev/null +++ b/lib/doc/lfun/all/eventCompleteHeal @@ -0,0 +1,33 @@ +EVENTCOMPLETEHEAL + +NAME + eventCompleteHeal() + + + +SYNOPSIS + void eventCompleteHeal(int x) + + + +DESCRIPTION + When a body determines it is time for a heal event (basically, the correct amount of time has passed, and the creature is to recover somewhat) this function is called. It does not do a "complete heal", it simply completes the heal event. + +EXAMPLES + + + + +LOCATION + /lib/body + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/eventDestruct b/lib/doc/lfun/all/eventDestruct new file mode 100644 index 0000000..9b89fb3 --- /dev/null +++ b/lib/doc/lfun/all/eventDestruct @@ -0,0 +1,36 @@ +EVENTDESTRUCT + +NAME + eventDestruct() + +SYNOPSIS + int eventDestruct() + +DESCRIPTION + This lfun provides a convenient means to ensure proper things happen when an object is destructed. Rather than simply destruct(), you can use eventDestruct to, for example, move a thing to the furnace before it is actually removed from memory. Any invocation of eventDestruct() in a child object should probably make a scope reference to eventDestruct in its inheritance chain. + +EXAMPLES + int eventDestruct(){ write("Gbye!"); return ::eventDestruct(); } + +LOCATION + /lib/bonus +/lib/chat +/lib/interactive +/lib/meal +/lib/npc +/lib/props/clean +/lib/std/daemon +/secure/lib/connect +/secure/lib/file +/secure/lib/net/client +/secure/lib/net/ftp_client +/secure/lib/net/ftp_data_connection +/secure/lib/net/server + + +SEE ALSO + destruct (efun) + +Author + Cratylus + diff --git a/lib/doc/lfun/all/eventDie b/lib/doc/lfun/all/eventDie new file mode 100644 index 0000000..4e12cf7 --- /dev/null +++ b/lib/doc/lfun/all/eventDie @@ -0,0 +1,41 @@ +EVENTDIE + +NAME + eventDie() + + + +SYNOPSIS + varargs int eventDie(mixed agent) + + + +DESCRIPTION + When a creature dies, this function is called in them. The argument should be what it is that killed them. Note that this is a function that is heavily overridden, and must be handled with care if modified. If you don't know what a function override is, then don't mess with this function. If eventDie() returns something other than a positive integer, the creature doesn't die in the conventional sense: they instead become undead. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/bot +/lib/combat +/lib/flashlight +/lib/npc +/lib/player +/lib/race + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/eventDrain b/lib/doc/lfun/all/eventDrain new file mode 100644 index 0000000..334cf62 --- /dev/null +++ b/lib/doc/lfun/all/eventDrain @@ -0,0 +1,24 @@ +EVENTDRAIN + +NAME + eventDrain() + +SYNOPSIS + int eventDrain(int i) + +DESCRIPTION + Causes a battery to lose charge by the specified amount. + +EXAMPLES + + +LOCATION + /lib/battery.c + + +SEE ALSO + GetDrainRate, SetDrainRate + +Author + Cratylus + diff --git a/lib/doc/lfun/all/eventExtinguish b/lib/doc/lfun/all/eventExtinguish new file mode 100644 index 0000000..77fcd06 --- /dev/null +++ b/lib/doc/lfun/all/eventExtinguish @@ -0,0 +1,31 @@ +EVENTEXTINGUISH + +NAME + eventExtinguish() + + +SYNOPSIS + mixed eventExtinguish() + + +DESCRIPTION + LIB_BURN: Calls eventDarken and stops heart_beat. LIB_FLASHLIGHT: Calls eventTurnOff(). + +EXAMPLES + + + + +LOCATION + /lib/burn +/lib/flashlight + + +SEE ALSO + eventLight + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/eventFall b/lib/doc/lfun/all/eventFall new file mode 100644 index 0000000..ec44d0b --- /dev/null +++ b/lib/doc/lfun/all/eventFall @@ -0,0 +1,35 @@ +EVENTFALL + +NAME + eventFall() + + + +SYNOPSIS + mixed eventFall() + + + +DESCRIPTION + What happens when a body suffers a fall. Relevant checks and actions occur here. + + + +EXAMPLES + this_player()->eventFall() + + + +LOCATION + /lib/body +/lib/lvs/position + + +SEE ALSO + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/eventHealDamage b/lib/doc/lfun/all/eventHealDamage new file mode 100644 index 0000000..ab82de8 --- /dev/null +++ b/lib/doc/lfun/all/eventHealDamage @@ -0,0 +1,24 @@ +EVENTHEALDAMAGE + +NAME + eventHealDamage() + +SYNOPSIS + varargs int eventHealDamage(int x, int internal, mixed limbs) + +DESCRIPTION + int x - amount of damage being healed, negatives illegal. int internal - internal damage flag (optional). mixed limbs - limb or limbs affected by the heal event (optional). If the internal flag is set then overall health is healed. If limbs are specified then the specified limbs are healed. If the internal flag is NOT set and NO limbs are specified (default) then both overall health as well as the health of all limbs are healed. Returns the actual amount of healing done or -1 if an error occurs. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + eventReceiveDamage + +Author + Unknown + diff --git a/lib/doc/lfun/all/eventInitiate b/lib/doc/lfun/all/eventInitiate new file mode 100644 index 0000000..03b7960 --- /dev/null +++ b/lib/doc/lfun/all/eventInitiate @@ -0,0 +1,23 @@ +EVENTINITIATE + +NAME + eventInitiate() + +SYNOPSIS + int eventInitiate(string str) + +DESCRIPTION + This is the first part of a two part "clan joining process". Once the new clan member has gone through the directives in this function, eventJoin() is called in this object to finalize the new membership. + +EXAMPLES + eventJoin, eventUnjoin, eventBring, eventRetire + +LOCATION + /lib/clan + +SEE ALSO + eventJoin, eventUnjoin, eventBring, eventRetire + +Author + Cratylus + diff --git a/lib/doc/lfun/all/eventJoin b/lib/doc/lfun/all/eventJoin new file mode 100644 index 0000000..22f008b --- /dev/null +++ b/lib/doc/lfun/all/eventJoin @@ -0,0 +1,24 @@ +EVENTJOIN + +NAME + eventJoin() + +SYNOPSIS + void eventJoin(object ob) + +DESCRIPTION + This is the second part of a two part "clan joining process". Once the new clan member has gone through the directives in eventInitiate(), this function is called in this object to finalize the new membership. + +EXAMPLES + + +LOCATION + /lib/clan +/lib/leader + +SEE ALSO + eventRetire, eventUnjoin, eventBring, eventInitiate + +Author + Cratylus + diff --git a/lib/doc/lfun/all/eventLight b/lib/doc/lfun/all/eventLight new file mode 100644 index 0000000..4764a8d --- /dev/null +++ b/lib/doc/lfun/all/eventLight @@ -0,0 +1,37 @@ +EVENTLIGHT + +NAME + eventLight() + + + +SYNOPSIS + mixed eventLight(object who, object what) + + + +DESCRIPTION + LIB_BURN: Calls eventBurn to initiate combustion. LIB_LIGHT: Sets "Lit" to 1. LIB_FLASHLIGHT: calls eventTurnOn. LIB_LAMP: Begins the fuel burning process. + + +EXAMPLES + + + + +LOCATION + /lib/burn +/lib/flashlight +/lib/lamp +/lib/light + + +SEE ALSO + eventBurn + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/eventLoad b/lib/doc/lfun/all/eventLoad new file mode 100644 index 0000000..dd822da --- /dev/null +++ b/lib/doc/lfun/all/eventLoad @@ -0,0 +1,26 @@ +EVENTLOAD + +NAME + eventLoad() + +SYNOPSIS + LIB_CLIP and LIB_ROUND: varargs mixed eventLoad(object who, object where) , LIB_FIREARM: mixed eventLoad(object ob) + +DESCRIPTION + For LIB_CLIP and LIB_ROUND, this function performs the work of moving the object into the destination 'where'. For LIB_FIREARM, this function is called when a round is being loaded directly into a revolver. + +EXAMPLES + + +LOCATION + /lib/round +/lib/events/load +/lib/firearm +/lib/clip + +SEE ALSO + eventUnload + +Author + Cratylus + diff --git a/lib/doc/lfun/all/eventMarry b/lib/doc/lfun/all/eventMarry new file mode 100644 index 0000000..8733a8a --- /dev/null +++ b/lib/doc/lfun/all/eventMarry @@ -0,0 +1,25 @@ +EVENTMARRY + +NAME + eventMarry() + +SYNOPSIS + mixed eventMarry(object who, object spouse1, object spouse2) + +DESCRIPTION + Carries out the actions of the marriage process. + +EXAMPLES + + +LOCATION + /lib/chapel +/lib/interactive + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/eventMoralAct b/lib/doc/lfun/all/eventMoralAct new file mode 100644 index 0000000..8b65a9b --- /dev/null +++ b/lib/doc/lfun/all/eventMoralAct @@ -0,0 +1,24 @@ +EVENTMORALACT + +NAME + eventMoralAct() + +SYNOPSIS + int eventMoralAct(int degree) + +DESCRIPTION + Adds the integer "degree" to the creature's morality. + +EXAMPLES + Killing a smurf might do this: gargamel->eventMoralAct(-50) + +LOCATION + /lib/classes + + +SEE ALSO + SetMorality, GetMorality, GetMoralityDescription + +Author + Cratylus + diff --git a/lib/doc/lfun/all/eventReceiveDamage b/lib/doc/lfun/all/eventReceiveDamage new file mode 100644 index 0000000..b72a68f --- /dev/null +++ b/lib/doc/lfun/all/eventReceiveDamage @@ -0,0 +1,39 @@ +EVENTRECEIVEDAMAGE + +NAME + eventReceiveDamage() + + + +SYNOPSIS + varargs int eventReceiveDamage(object agent, int type, int x, int internal, mixed limbs) + + + +DESCRIPTION + What sometimes happens to good people. + + + +EXAMPLES + orc->eventReceiveDamage(this_player(), BLADE, 100, 0, ({ "head", "neck" }) ) + + + +LOCATION + /lib/body +/lib/combat +/lib/props/deterioration +/lib/std/armor +/lib/std/worn_storage + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/eventReceiveThrow b/lib/doc/lfun/all/eventReceiveThrow new file mode 100644 index 0000000..e16b83f --- /dev/null +++ b/lib/doc/lfun/all/eventReceiveThrow @@ -0,0 +1,24 @@ +EVENTRECEIVETHROW + +NAME + eventReceiveThrow() + +SYNOPSIS + mixed eventReceiveThrow(object who, object what) + +DESCRIPTION + Performs the appropriate calculations for a body that is the target of a thrown object. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/all/eventReconnect b/lib/doc/lfun/all/eventReconnect new file mode 100644 index 0000000..9046556 --- /dev/null +++ b/lib/doc/lfun/all/eventReconnect @@ -0,0 +1,40 @@ +EVENTRECONNECT + +NAME + eventReconnect() + + + +SYNOPSIS + void eventReconnect() + + + +DESCRIPTION + A series of events that need to occur when a user reconnects to the game after going link-dead. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/chat +/lib/creator +/lib/interactive +/lib/npc +/lib/player + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/eventRemoveItem b/lib/doc/lfun/all/eventRemoveItem new file mode 100644 index 0000000..697d242 --- /dev/null +++ b/lib/doc/lfun/all/eventRemoveItem @@ -0,0 +1,32 @@ +EVENTREMOVEITEM + +NAME + eventRemoveItem() + + + +SYNOPSIS + int eventRemoveItem(object ob) + + + +DESCRIPTION + Removes a worn or wielded item from the list. object ob - the item being removed. Returns 1 on success, 0 on failure. + + +EXAMPLES + + + + +LOCATION + /lib/body + + +SEE ALSO + eventWear + +Author + Unknown + + diff --git a/lib/doc/lfun/all/eventRetire b/lib/doc/lfun/all/eventRetire new file mode 100644 index 0000000..ca37f10 --- /dev/null +++ b/lib/doc/lfun/all/eventRetire @@ -0,0 +1,23 @@ +EVENTRETIRE + +NAME + eventRetire() + +SYNOPSIS + int eventRetire(string str) + +DESCRIPTION + This is the first part of a two part "clan expulsion process". Once the clan member has gone through the directives in this function, eventUnjoin() is called in this object to finalize the expulsion. + +EXAMPLES + eventRetire("deckard") + +LOCATION + /lib/clan + +SEE ALSO + eventJoin, eventUnjoin, eventBring, eventInitiate + +Author + Cratylus + diff --git a/lib/doc/lfun/all/eventSacrifice b/lib/doc/lfun/all/eventSacrifice new file mode 100644 index 0000000..e445ce3 --- /dev/null +++ b/lib/doc/lfun/all/eventSacrifice @@ -0,0 +1,24 @@ +EVENTSACRIFICE + +NAME + eventSacrifice() + +SYNOPSIS + mixed eventSacrifice(object who, object what, string deus) + +DESCRIPTION + Performs the sacrifice act. + +EXAMPLES + + +LOCATION + /lib/chapel + + +SEE ALSO + SetAllowSacrifice, GetAllowSacrifice, SetSacrificeType, AddSacrificeType, GetSacrificeType, eventSacrifice, CanSacrifice + +Author + Cratylus + diff --git a/lib/doc/lfun/all/eventUnjoin b/lib/doc/lfun/all/eventUnjoin new file mode 100644 index 0000000..e2055b5 --- /dev/null +++ b/lib/doc/lfun/all/eventUnjoin @@ -0,0 +1,23 @@ +EVENTUNJOIN + +NAME + eventUnjoin() + +SYNOPSIS + void eventUnjoin(object ob) + +DESCRIPTION + This is the second part of a two part "clan expulsion process". Once the clan member has gone through the directives in eventRetire(), this function is called in this object to finalize the expulsion. + +EXAMPLES + + +LOCATION + /lib/clan + +SEE ALSO + eventRetire, eventJoin, eventBring, eventInitiate + +Author + Cratylus + diff --git a/lib/doc/lfun/all/eventUnload b/lib/doc/lfun/all/eventUnload new file mode 100644 index 0000000..7476126 --- /dev/null +++ b/lib/doc/lfun/all/eventUnload @@ -0,0 +1,26 @@ +EVENTUNLOAD + +NAME + eventUnload() + +SYNOPSIS + mixed eventUnload(mixed what) + +DESCRIPTION + Provides for unloading. If the argument is a nonzero integer, it is presumed that the object is a LIB_CLIP or LIB_FIREARM and a number of objects are being unloaded from it. In the case of unloading a LIB_ROUND or a LIB_CLIP from something, then the argument would be the object that contains it. + +EXAMPLES + + +LOCATION + /lib/round +/lib/events/load +/lib/firearm +/lib/clip + +SEE ALSO + eventLoad + +Author + Cratylus + diff --git a/lib/doc/lfun/all/eventUse b/lib/doc/lfun/all/eventUse new file mode 100644 index 0000000..e2602fe --- /dev/null +++ b/lib/doc/lfun/all/eventUse @@ -0,0 +1,37 @@ +EVENTUSE + +NAME + eventUse() + + + +SYNOPSIS + LIB_BATTERY: int eventUse(int i), LIB_PLAYER: mixed eventUse(object used, string cmd) + + + +DESCRIPTION + For batteries, it runs necessary actions when the battery is used. For players, it runs the parser in a stripped way for testing. + + + +EXAMPLES + + + + +LOCATION + /lib/battery +/lib/flashlight +/lib/player + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/eventWear b/lib/doc/lfun/all/eventWear new file mode 100644 index 0000000..9d1d715 --- /dev/null +++ b/lib/doc/lfun/all/eventWear @@ -0,0 +1,24 @@ +EVENTWEAR + +NAME + eventWear() + +SYNOPSIS + int eventWear(object ob, mixed limbs) + +DESCRIPTION + Mrks the limbs "limbs" as being protected by the armor "ob". object ob - the item being worn (or wielded). mixed limbs - string or array of limbs on which it is being worn (or wielded). Returns 1 if successful, 0 if failure. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + eventRemoveItem + +Author + Unknown + diff --git a/lib/doc/lfun/all/eventWelcome b/lib/doc/lfun/all/eventWelcome new file mode 100644 index 0000000..4bf2a7e --- /dev/null +++ b/lib/doc/lfun/all/eventWelcome @@ -0,0 +1,23 @@ +EVENTWELCOME + +NAME + eventWelcome() + +SYNOPSIS + void eventWelcome(object ob) + +DESCRIPTION + Provides a set of messages or events to occur indicating to the new clan member they are welcome. + +EXAMPLES + + +LOCATION + /lib/clan + +SEE ALSO + eventRetire, eventJoin, eventUnjoin, eventBring, eventInitiate + +Author + Cratylus + diff --git a/lib/doc/lfun/all/performMarriage b/lib/doc/lfun/all/performMarriage new file mode 100644 index 0000000..2755017 --- /dev/null +++ b/lib/doc/lfun/all/performMarriage @@ -0,0 +1,22 @@ +PERFORMMARRIAGE + +NAME + performMarriage() + +SYNOPSIS + mixed performMarriage(object spouse1, object spouse2) + +DESCRIPTION + This function checks to ensure the location of the two betrotheds is suitable, then performs the actions that seal their lives in mortal bliss. + +EXAMPLES + + +LOCATION + /lib/clerk + +SEE ALSO + + +Author + Cratylus diff --git a/lib/doc/lfun/all/returnChannels b/lib/doc/lfun/all/returnChannels new file mode 100644 index 0000000..df9c413 --- /dev/null +++ b/lib/doc/lfun/all/returnChannels @@ -0,0 +1,28 @@ +RETURNCHANNELS + +NAME + returnChannels() + +SYNOPSIS + mapping returnChannels() + +DESCRIPTION + Returns a mapping containing the channels accessible to the user and their associated data. + +EXAMPLES + + + + +LOCATION + /lib/chat + + +SEE ALSO + AddChannel, RemoveChannel, GetChannels + + +Author + Cratylus + + diff --git a/lib/doc/lfun/all/teller_check b/lib/doc/lfun/all/teller_check new file mode 100644 index 0000000..ac5e710 --- /dev/null +++ b/lib/doc/lfun/all/teller_check @@ -0,0 +1,23 @@ +TELLER_CHECK + +NAME + teller_check() + +SYNOPSIS + mixed teller_check() + +DESCRIPTION + If there is an npc in the bank that defines this lfun, and that npc inherits LIB_TELLER, then this lfun returns a pointer to that npc. Otherwise it returns 0. + +EXAMPLES + + +LOCATION + /lib/bank + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/abilities/AddSkillPoints b/lib/doc/lfun/lib/abilities/AddSkillPoints new file mode 100644 index 0000000..4ef5fd7 --- /dev/null +++ b/lib/doc/lfun/lib/abilities/AddSkillPoints @@ -0,0 +1,25 @@ +ADDSKILLPOINTS + +NAME + AddSkillPoints() + +SYNOPSIS + int AddSkillPoints(string skill, int x) + +DESCRIPTION + LIB_ABILITIES: adds "x" points to the total for skill "skill". if the points go over the max for the current skill level, then the level is raised 1, if the points go under 0, then the skill level is lowered. LIB_CLASSES: Applies the appropriate skill modifiers to the skill change before passing it on to LIB_ABILITIES. + +EXAMPLES + + +LOCATION + /lib/classes +/lib/lvs/abilities + +SEE ALSO + AddSkillPoints, SetSkillModifier, GetSkillModifier + + +Author + Unknown + diff --git a/lib/doc/lfun/lib/abilities/GetSkills b/lib/doc/lfun/lib/abilities/GetSkills new file mode 100644 index 0000000..dbaaa79 --- /dev/null +++ b/lib/doc/lfun/lib/abilities/GetSkills @@ -0,0 +1,27 @@ +GETSKILLS + +NAME + GetSkills() + +SYNOPSIS + LIB_SPELL, LIB_ABILITIES: string array GetSkills() ; LIB_POTION, LIB_BONUS: mapping GetSkills() + +DESCRIPTION + For LIB_ABILITIES this lfun returns the list of skill names possessed by the creature it's called in, such as "knife defense", etc. For LIB_SPELL this returns a list of the skills required to be able to cast the spell. For LIB_POTION and LIB_BONUS, this lfun works much like GetStats(), in that it returns a mapping of skills and how they are modified when a potion is drunk. + +EXAMPLES + + +LOCATION + /lib/bonus +/lib/lvs/abilities +/lib/potion +/lib/spell + + +SEE ALSO + GetStats, SetSkill + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/armor/GetFingers b/lib/doc/lfun/lib/armor/GetFingers new file mode 100644 index 0000000..a4c6549 --- /dev/null +++ b/lib/doc/lfun/lib/armor/GetFingers @@ -0,0 +1,37 @@ +GETFINGERS + +NAME + GetFingers() + + + +SYNOPSIS + LIB_BODY: int GetFingers(string limb) LIB_ARMOR: int GetFingers() + + + +DESCRIPTION + For creatures, returns the number of fingers on the given limb. For armor, returns the number of fingers required to wear the item. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/std/armor +/lib/std/worn_storage + + +SEE ALSO + AddFingers + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/armor/SetFingers b/lib/doc/lfun/lib/armor/SetFingers new file mode 100644 index 0000000..b2419a0 --- /dev/null +++ b/lib/doc/lfun/lib/armor/SetFingers @@ -0,0 +1,31 @@ +SETFINGERS + +NAME + + + +SYNOPSIS + + + +DESCRIPTION + + + +EXAMPLES + + + +LOCATION + /lib/std/armor +/lib/std/worn_storage + + +SEE ALSO + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/armor/eventReceiveDamage b/lib/doc/lfun/lib/armor/eventReceiveDamage new file mode 100644 index 0000000..b72a68f --- /dev/null +++ b/lib/doc/lfun/lib/armor/eventReceiveDamage @@ -0,0 +1,39 @@ +EVENTRECEIVEDAMAGE + +NAME + eventReceiveDamage() + + + +SYNOPSIS + varargs int eventReceiveDamage(object agent, int type, int x, int internal, mixed limbs) + + + +DESCRIPTION + What sometimes happens to good people. + + + +EXAMPLES + orc->eventReceiveDamage(this_player(), BLADE, 100, 0, ({ "head", "neck" }) ) + + + +LOCATION + /lib/body +/lib/combat +/lib/props/deterioration +/lib/std/armor +/lib/std/worn_storage + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/bank/HandleTeller b/lib/doc/lfun/lib/bank/HandleTeller new file mode 100644 index 0000000..90cde9c --- /dev/null +++ b/lib/doc/lfun/lib/bank/HandleTeller @@ -0,0 +1,23 @@ +HANDLETELLER + +NAME + HandleTeller() + +SYNOPSIS + int HandleTeller(string str) + +DESCRIPTION + The LIB_BANK inheritable is a kind of 'wrapper' for the LIB_TELLER npc. Rather than have to type 'ask zoe to withdraw 100 dollars', that add_actions in LIB_BANK catch the 'withdraw' command and send it and the arguments provided to the teller, so a player can just type 'withdraw 100 dollars'. The HandleTeller() function provides that call to the npc. + +EXAMPLES + + +LOCATION + /lib/bank + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/bank/teller_check b/lib/doc/lfun/lib/bank/teller_check new file mode 100644 index 0000000..ac5e710 --- /dev/null +++ b/lib/doc/lfun/lib/bank/teller_check @@ -0,0 +1,23 @@ +TELLER_CHECK + +NAME + teller_check() + +SYNOPSIS + mixed teller_check() + +DESCRIPTION + If there is an npc in the bank that defines this lfun, and that npc inherits LIB_TELLER, then this lfun returns a pointer to that npc. Otherwise it returns 0. + +EXAMPLES + + +LOCATION + /lib/bank + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/battery/GetCellType b/lib/doc/lfun/lib/battery/GetCellType new file mode 100644 index 0000000..70c0f2d --- /dev/null +++ b/lib/doc/lfun/lib/battery/GetCellType @@ -0,0 +1,36 @@ +GETCELLTYPE + +NAME + GetCellType() + + + +SYNOPSIS + string GetCellType() + + + +DESCRIPTION + Returns a string indicating (for batteries) what kind of battery it is, or (for flashlights) what kind of batteries the device requires. + + + +EXAMPLES + + + + +LOCATION + /lib/battery +/lib/flashlight + + +SEE ALSO + SetCellType + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/battery/GetCharge b/lib/doc/lfun/lib/battery/GetCharge new file mode 100644 index 0000000..619770b --- /dev/null +++ b/lib/doc/lfun/lib/battery/GetCharge @@ -0,0 +1,24 @@ +GETCHARGE + +NAME + GetCharge() + +SYNOPSIS + int GetCharge() + +DESCRIPTION + Returns the amount of power left in a battery. + +EXAMPLES + present("battery",this_object())->GetCharge() + +LOCATION + /lib/battery.c + + +SEE ALSO + SetCharge, SetDrainRate, GetDrainRate + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/battery/GetDrainRate b/lib/doc/lfun/lib/battery/GetDrainRate new file mode 100644 index 0000000..abfced4 --- /dev/null +++ b/lib/doc/lfun/lib/battery/GetDrainRate @@ -0,0 +1,30 @@ +GETDRAINRATE + +NAME + GetDrainRate() + + +SYNOPSIS + int GetDrainRate() + + +DESCRIPTION + Return the speed with which a battery is drained over time, in charge units per heartbeat. + + +EXAMPLES + + + +LOCATION + /lib/battery + + +SEE ALSO + SetDrainRate, SetCharge, GetCharge + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/battery/GetDrainable b/lib/doc/lfun/lib/battery/GetDrainable new file mode 100644 index 0000000..bd267e7 --- /dev/null +++ b/lib/doc/lfun/lib/battery/GetDrainable @@ -0,0 +1,29 @@ +GETDRAINABLE + +NAME + GetDrainable() + + +SYNOPSIS + int GetDrainable() + + +DESCRIPTION + Returns whether a battery can lose charge. + + +EXAMPLES + + +LOCATION + /lib/battery.c + + +SEE ALSO + SetDrainable, SetDrainRate, GetDrainRate + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/battery/GetRechargeable b/lib/doc/lfun/lib/battery/GetRechargeable new file mode 100644 index 0000000..2b6e6e5 --- /dev/null +++ b/lib/doc/lfun/lib/battery/GetRechargeable @@ -0,0 +1,24 @@ +GETRECHARGEABLE + +NAME + GetRechargeable() + +SYNOPSIS + int GetRechargeable() + +DESCRIPTION + Returns whether the battery is capable of being recharged. + +EXAMPLES + + +LOCATION + /lib/battery.c + + +SEE ALSO + SetRechargeable, SetCharge, GetCharge + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/battery/ModCharge b/lib/doc/lfun/lib/battery/ModCharge new file mode 100644 index 0000000..a08089b --- /dev/null +++ b/lib/doc/lfun/lib/battery/ModCharge @@ -0,0 +1,24 @@ +MODCHARGE + +NAME + ModCharge() + +SYNOPSIS + int ModCharge(int i) + +DESCRIPTION + Arbitrarily changes the charge setting of a battery without incurring all the actions of SetCharge. + +EXAMPLES + + +LOCATION + /lib/battery.c + + +SEE ALSO + SetCharge, GetCharge + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/battery/SetCellType b/lib/doc/lfun/lib/battery/SetCellType new file mode 100644 index 0000000..95649e7 --- /dev/null +++ b/lib/doc/lfun/lib/battery/SetCellType @@ -0,0 +1,36 @@ +SETCELLTYPE + +NAME + SetCellType() + + + +SYNOPSIS + int SetCellType(string str) + + + +DESCRIPTION + In LIB_BATTERY, sets the battery in question to the appropriate type, such as C, AA, etc.\nIn LIB_FLASHLIGHT, sets what kind of batteries it will accept. + + + +EXAMPLES + SetCellType("D") + + + +LOCATION + /lib/battery +/lib/flashlight + + +SEE ALSO + GetCellType + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/battery/SetCharge b/lib/doc/lfun/lib/battery/SetCharge new file mode 100644 index 0000000..2ed0b6e --- /dev/null +++ b/lib/doc/lfun/lib/battery/SetCharge @@ -0,0 +1,24 @@ +SETCHARGE + +NAME + SetCharge() + +SYNOPSIS + int SetCharge(int i) + +DESCRIPTION + Sets the amount of power left in the battery. + +EXAMPLES + A battery with a drain rate of one will be a two-minute battery with this: SetCharge(120) + +LOCATION + /lib/battery.c + + +SEE ALSO + GetCharge + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/battery/SetDrainRate b/lib/doc/lfun/lib/battery/SetDrainRate new file mode 100644 index 0000000..dfa4460 --- /dev/null +++ b/lib/doc/lfun/lib/battery/SetDrainRate @@ -0,0 +1,36 @@ +SETDRAINRATE + +NAME + SetDrainRate() + + + +SYNOPSIS + int SetDrainRate(int i) + + + +DESCRIPTION + Sets how much of a battery's charge is drained per heartbeat of use. + + + +EXAMPLES + For a two-minute battery with a charge of 120 on a mud with a one-second heartbeat: SetDrainRate(1) + + + +LOCATION + /lib/battery +/lib/flashlight + + +SEE ALSO + GetDrainRate, SetCharge, GetCharge + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/battery/SetDrainable b/lib/doc/lfun/lib/battery/SetDrainable new file mode 100644 index 0000000..0e830b0 --- /dev/null +++ b/lib/doc/lfun/lib/battery/SetDrainable @@ -0,0 +1,24 @@ +SETDRAINABLE + +NAME + SetDrainable() + +SYNOPSIS + int SetDrainable(int i) + +DESCRIPTION + Sets whether a battery actually loses power over time or not. + +EXAMPLES + For an everlasting battery: SetDrainable(0) + +LOCATION + /lib/battery.c + + +SEE ALSO + GetDrainable, SetDrainRate, GetDrainRate + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/battery/SetPowerType b/lib/doc/lfun/lib/battery/SetPowerType new file mode 100644 index 0000000..f1fc3da --- /dev/null +++ b/lib/doc/lfun/lib/battery/SetPowerType @@ -0,0 +1,24 @@ +SETPOWERTYPE + +NAME + SetPowerType() + +SYNOPSIS + int SetPowerType(string str) + +DESCRIPTION + Sets the battery to the desired type, typically AC, DC, Fusion, whatever. + +EXAMPLES + SetPowerType("hydrogen") + +LOCATION + /lib/battery.c + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/battery/SetRechargeable b/lib/doc/lfun/lib/battery/SetRechargeable new file mode 100644 index 0000000..6de7236 --- /dev/null +++ b/lib/doc/lfun/lib/battery/SetRechargeable @@ -0,0 +1,24 @@ +SETRECHARGEABLE + +NAME + SetRechargeable() + +SYNOPSIS + int SetRechargeable(int i) + +DESCRIPTION + Makes the battery capable of being recharged. + +EXAMPLES + + +LOCATION + /lib/battery.c + + +SEE ALSO + GetRechargeable, SetCharge, GetCharge + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/battery/Spent b/lib/doc/lfun/lib/battery/Spent new file mode 100644 index 0000000..afb8d84 --- /dev/null +++ b/lib/doc/lfun/lib/battery/Spent @@ -0,0 +1,24 @@ +SPENT + +NAME + Spent() + +SYNOPSIS + int Spent() + +DESCRIPTION + Sets the given battery to its "spent" state, with no charge and a new description. + +EXAMPLES + + +LOCATION + /lib/battery.c + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/battery/eventCharge b/lib/doc/lfun/lib/battery/eventCharge new file mode 100644 index 0000000..5dd0cbe --- /dev/null +++ b/lib/doc/lfun/lib/battery/eventCharge @@ -0,0 +1,24 @@ +EVENTCHARGE + +NAME + eventCharge() + +SYNOPSIS + int eventCharge(int i) + +DESCRIPTION + Causes a battery to be charged by the integer specified. + +EXAMPLES + + +LOCATION + /lib/battery.c + + +SEE ALSO + SetCharge, GetCharge + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/battery/eventDrain b/lib/doc/lfun/lib/battery/eventDrain new file mode 100644 index 0000000..334cf62 --- /dev/null +++ b/lib/doc/lfun/lib/battery/eventDrain @@ -0,0 +1,24 @@ +EVENTDRAIN + +NAME + eventDrain() + +SYNOPSIS + int eventDrain(int i) + +DESCRIPTION + Causes a battery to lose charge by the specified amount. + +EXAMPLES + + +LOCATION + /lib/battery.c + + +SEE ALSO + GetDrainRate, SetDrainRate + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/battery/eventUse b/lib/doc/lfun/lib/battery/eventUse new file mode 100644 index 0000000..e2602fe --- /dev/null +++ b/lib/doc/lfun/lib/battery/eventUse @@ -0,0 +1,37 @@ +EVENTUSE + +NAME + eventUse() + + + +SYNOPSIS + LIB_BATTERY: int eventUse(int i), LIB_PLAYER: mixed eventUse(object used, string cmd) + + + +DESCRIPTION + For batteries, it runs necessary actions when the battery is used. For players, it runs the parser in a stripped way for testing. + + + +EXAMPLES + + + + +LOCATION + /lib/battery +/lib/flashlight +/lib/player + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/AddAlcohol b/lib/doc/lfun/lib/body/AddAlcohol new file mode 100644 index 0000000..3ea9aa8 --- /dev/null +++ b/lib/doc/lfun/lib/body/AddAlcohol @@ -0,0 +1,24 @@ +ADDALCOHOL + +NAME + AddAlcohol() + +SYNOPSIS + int AddAlcohol(int x) + +DESCRIPTION + Arbitrarily add alcohol to the creature by the amount indicated by the passed integer. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + GetAlcohol + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/AddCaffeine b/lib/doc/lfun/lib/body/AddCaffeine new file mode 100644 index 0000000..c39ac8c --- /dev/null +++ b/lib/doc/lfun/lib/body/AddCaffeine @@ -0,0 +1,24 @@ +ADDCAFFEINE + +NAME + AddCaffeine() + +SYNOPSIS + int AddCaffeine(int x) + +DESCRIPTION + Arbitrarily add caffeine to the creature by the amount indicated by the passed integer. + +EXAMPLES + present("junkie",environment(this_player()))->AddCaffeine(10) + +LOCATION + /lib/body + + +SEE ALSO + GetCaffeine + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/AddDrink b/lib/doc/lfun/lib/body/AddDrink new file mode 100644 index 0000000..aba5f6e --- /dev/null +++ b/lib/doc/lfun/lib/body/AddDrink @@ -0,0 +1,24 @@ +ADDDRINK + +NAME + AddDrink() + +SYNOPSIS + int AddDrink(int x) + +DESCRIPTION + Arbitrarily add "drink points" to the creature by the amount indicated by the passed integer. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + GetDrink + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/AddExperiencePoints b/lib/doc/lfun/lib/body/AddExperiencePoints new file mode 100644 index 0000000..9f1fa88 --- /dev/null +++ b/lib/doc/lfun/lib/body/AddExperiencePoints @@ -0,0 +1,24 @@ +ADDEXPERIENCEPOINTS + +NAME + AddExperiencePoints() + +SYNOPSIS + int AddExperiencePoints(mixed x) + +DESCRIPTION + This is the function called when "XP" is to be added to a player. + +EXAMPLES + this_player()->AddExperiencePoints(42) + +LOCATION + /lib/body + + +SEE ALSO + GetExperiencePoints, SetCustomXP, GetCustomXP + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/AddExtraChannels b/lib/doc/lfun/lib/body/AddExtraChannels new file mode 100644 index 0000000..455e133 --- /dev/null +++ b/lib/doc/lfun/lib/body/AddExtraChannels @@ -0,0 +1,24 @@ +ADDEXTRACHANNELS + +NAME + AddExtraChannels() + +SYNOPSIS + string array AddExtraChannels(string array chans) + +DESCRIPTION + Adds to the player's extra channels. Extra channels are part of a channel test system and will be largely unused post Dead Souls 2.1. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + SetExtraChannels, GetExtraChannels, AddExtraChannels, RemoveExtraChannels + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/AddFingers b/lib/doc/lfun/lib/body/AddFingers new file mode 100644 index 0000000..a724617 --- /dev/null +++ b/lib/doc/lfun/lib/body/AddFingers @@ -0,0 +1,22 @@ +ADDFINGERS +NAME + AddFingers() + +SYNOPSIS + varargs int AddFingers(string limb, int x) + +DESCRIPTION + Adds the given number of fingers to the given limb. string limb - the limb to which fingers will be added. int x - the number of fingers being added, can be negative. Returns the total number of fingers after addition. + +EXAMPLES + + +LOCATION + /lib/body + +SEE ALSO + GetFingers + +Author + Unknown + diff --git a/lib/doc/lfun/lib/body/AddFood b/lib/doc/lfun/lib/body/AddFood new file mode 100644 index 0000000..ac93a9f --- /dev/null +++ b/lib/doc/lfun/lib/body/AddFood @@ -0,0 +1,24 @@ +ADDFOOD + +NAME + AddFood() + +SYNOPSIS + int AddFood(int x) + +DESCRIPTION + Arbitrarily add "food points" to the creature by the amount indicated by the passed integer. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + GetFood() + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/AddHP b/lib/doc/lfun/lib/body/AddHP new file mode 100644 index 0000000..3f37879 --- /dev/null +++ b/lib/doc/lfun/lib/body/AddHP @@ -0,0 +1,24 @@ +ADDHP + +NAME + AddHP() + +SYNOPSIS + int AddHP(int hp) + +DESCRIPTION + Arbitrarily change a creature's health points by the integer provided. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + eventReceiveDamage + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/AddHealthPoints b/lib/doc/lfun/lib/body/AddHealthPoints new file mode 100644 index 0000000..42a3baf --- /dev/null +++ b/lib/doc/lfun/lib/body/AddHealthPoints @@ -0,0 +1,36 @@ +ADDHEALTHPOINTS + +NAME + AddHealthPoints() + + + +SYNOPSIS + varargs static int AddHealthPoints(int x, string limb, object agent) + + + +DESCRIPTION + If the value of limb is not zero, then "x" number of health points will be added to limb "limb". If the value is 0, then the overall health points will be modified. int x - number of points being added, may be negative (required). string limb - the limb to which health is being added (optional). object agent - the living responsible for this damage. Returns the remaining number of health points for the limb in question or for the overall health points. Note this is a static function and cannot be called from outside the creature. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/player + + +SEE ALSO + AddHP + + + +Author + Unknown + + diff --git a/lib/doc/lfun/lib/body/AddHeartModifier b/lib/doc/lfun/lib/body/AddHeartModifier new file mode 100644 index 0000000..81bf07f --- /dev/null +++ b/lib/doc/lfun/lib/body/AddHeartModifier @@ -0,0 +1,24 @@ +ADDHEARTMODIFIER + +NAME + AddHeartModifier() + +SYNOPSIS + varargs int AddHeartModifier(int x, int t) + +DESCRIPTION + Changes the heart rate modifier by the integer specified in the first argument. If argument t is provided, this modifier is removed after t seconds. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + GetHeartModifier + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/AddLead b/lib/doc/lfun/lib/body/AddLead new file mode 100644 index 0000000..a7c58fc --- /dev/null +++ b/lib/doc/lfun/lib/body/AddLead @@ -0,0 +1,29 @@ +ADDLEAD + +NAME + AddLead() + + +SYNOPSIS + int AddLead(string ammo,int number) + + +DESCRIPTION + Obsolete function for adding bullet damage to a creature. + + +EXAMPLES + + + +LOCATION + /lib/body + + +SEE ALSO + GetLead + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/AddLimb b/lib/doc/lfun/lib/body/AddLimb new file mode 100644 index 0000000..c422b5f --- /dev/null +++ b/lib/doc/lfun/lib/body/AddLimb @@ -0,0 +1,29 @@ +ADDLIMB + +NAME + AddLimb() + + +SYNOPSIS + varargs int AddLimb(string limb, string parent, int classes, int *armors) + + +DESCRIPTION + Adds the named limb to the body, attached at the named point the limb classes starts at 1 for a torso (strongest) to whatever the documentation rates as the weakest. string limb - the limb being added (required). string parent - the limb to which this one is being attached (required). int classes - rating of the limb's strength (optional). int *armors - the types of armors which can be worn here (optional). Returns 1 on success, 0 on failure. classes defaults to 1. armors defaults to ({}). + + +EXAMPLES + To add a prehensile (wielding) limb to a creature: creature->AddLimb("tentacle", "torso", 2, ({A_WEAPON })) + + +LOCATION + /lib/body + + +SEE ALSO + RemoveLimb, DestLimb, RestoreLimb + +Author + Unknown + + diff --git a/lib/doc/lfun/lib/body/AddMagicPoints b/lib/doc/lfun/lib/body/AddMagicPoints new file mode 100644 index 0000000..68c7214 --- /dev/null +++ b/lib/doc/lfun/lib/body/AddMagicPoints @@ -0,0 +1,24 @@ +ADDMAGICPOINTS + +NAME + AddMagicPoints() + +SYNOPSIS + int AddMagicPoints(int x) + +DESCRIPTION + Arbitrarily adds magic points to a creature. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + SetMagicPoints, GetMagicPoints, GetMaxMagicPoints + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/AddMagicProtection b/lib/doc/lfun/lib/body/AddMagicProtection new file mode 100644 index 0000000..a7eb028 --- /dev/null +++ b/lib/doc/lfun/lib/body/AddMagicProtection @@ -0,0 +1,24 @@ +ADDMAGICPROTECTION + +NAME + AddMagicProtection() + +SYNOPSIS + int AddMagicProtection(class MagicProtection cl) + +DESCRIPTION + This is the rather complex means by which to add sophisticated magical protection to a creature. An item must first create a protection class, then pass it as an argument to this funtion in the creature. + +EXAMPLES + Please see the buffer spell, /spells/buffer.c , for a detailed example of the mechanics of this system. + +LOCATION + /lib/body + + +SEE ALSO + SetProtect, GetProtect, RemoveMagicProtection, eventCheckProtection + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/AddMoJo b/lib/doc/lfun/lib/body/AddMoJo new file mode 100644 index 0000000..967a7fd --- /dev/null +++ b/lib/doc/lfun/lib/body/AddMoJo @@ -0,0 +1,29 @@ +ADDMOJO + +NAME + AddMoJo() + + +SYNOPSIS + float AddMoJo(mixed x) + + +DESCRIPTION + This is a test function, designed to add the notional characteristic of "Mojo" to a creature. It is unused. + + +EXAMPLES + + + +LOCATION + /lib/body + + +SEE ALSO + GetMojo + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/AddPoison b/lib/doc/lfun/lib/body/AddPoison new file mode 100644 index 0000000..725b95a --- /dev/null +++ b/lib/doc/lfun/lib/body/AddPoison @@ -0,0 +1,36 @@ +ADDPOISON + +NAME + AddPoison() + + + +SYNOPSIS + int AddPoison(int x) + + + +DESCRIPTION + Arbitrarily add poison by the amount indicated by the passed integer. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/events/poison + + +SEE ALSO + GetPoison + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/AddQuestPoints b/lib/doc/lfun/lib/body/AddQuestPoints new file mode 100644 index 0000000..bbcb0e5 --- /dev/null +++ b/lib/doc/lfun/lib/body/AddQuestPoints @@ -0,0 +1,29 @@ +ADDQUESTPOINTS + +NAME + AddQuestPoints() + + +SYNOPSIS + int AddQuestPoints(mixed x) + + +DESCRIPTION + Arbitrarily add quest points to a creature. Usually this is done when a player completes a quest. + + +EXAMPLES + + + +LOCATION + /lib/body + + +SEE ALSO + GetQuestPoints + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/CanFly b/lib/doc/lfun/lib/body/CanFly new file mode 100644 index 0000000..1fe52ae --- /dev/null +++ b/lib/doc/lfun/lib/body/CanFly @@ -0,0 +1,37 @@ +CANFLY + +NAME + CanFly() + + + +SYNOPSIS + int CanFly() + + + +DESCRIPTION + In npc's, checks to see whether the creature is capable of flight. A return of 1 is yes, a return of 0 is no. In rooms, the default is for a room to permit a flying creature to fly in or out. If CanFly returns 0, that behavior is restricted. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/std/room +/lib/virtual/virt_sky + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/CanManipulate b/lib/doc/lfun/lib/body/CanManipulate new file mode 100644 index 0000000..9bea110 --- /dev/null +++ b/lib/doc/lfun/lib/body/CanManipulate @@ -0,0 +1,31 @@ +CANMANIPULATE + +NAME + CanManipulate() + + +SYNOPSIS + mixed CanManipulate() + + +DESCRIPTION + Returns whether a creature has limbs with which to manipulate items. If a creature lacks limbs with which it can wield weapons, it is considered non-prehensile, and this function returns 0. Otherwise it returns 1. + + +EXAMPLES + + + +LOCATION + /lib/body +/lib/events/manipulate + + +SEE ALSO + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/CanRemoveItem b/lib/doc/lfun/lib/body/CanRemoveItem new file mode 100644 index 0000000..06fdd49 --- /dev/null +++ b/lib/doc/lfun/lib/body/CanRemoveItem @@ -0,0 +1,24 @@ +CANREMOVEITEM + +NAME + CanRemoveItem() + +SYNOPSIS + mixed CanRemoveItem(object ob) + +DESCRIPTION + LIB_BODY: Returns whether the creature can remove a given article of clothing or unwield a weapon. In body.c it is a stub that always returns 1. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/CanWear b/lib/doc/lfun/lib/body/CanWear new file mode 100644 index 0000000..06691da --- /dev/null +++ b/lib/doc/lfun/lib/body/CanWear @@ -0,0 +1,24 @@ +CANWEAR + +NAME + CanWear() + +SYNOPSIS + mixed CanWear(object ob, string *limbs) + +DESCRIPTION + Checks to see if a particular armor can be worn. object armor - the piece of armor being checked. string *limbs - the limbs on which the armor wants to be worn. A nested array indicates that just one of the included limbs must be satisfied. Returns 1 if the armor can be worn on those limbs. Returns 0 if the armor cannot be worn there for any reason. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Unknown + diff --git a/lib/doc/lfun/lib/body/DestLimb b/lib/doc/lfun/lib/body/DestLimb new file mode 100644 index 0000000..cc20f7f --- /dev/null +++ b/lib/doc/lfun/lib/body/DestLimb @@ -0,0 +1,24 @@ +DESTLIMB + +NAME + DestLimb() + +SYNOPSIS + int DestLimb(string limb) + +DESCRIPTION + Removes a limb from the limbs mapping. The limb isn't marked as mising, and the monster doesn't die even if you remove a fatal limb. Useful for removing limbs from standard race types. Removing the torso isn't allowed. Returns -1 on error, 0 on failure, 1 on success. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + RemoveLimb + +Author + Unknown + diff --git a/lib/doc/lfun/lib/body/GetAffectLong b/lib/doc/lfun/lib/body/GetAffectLong new file mode 100644 index 0000000..028c1fd --- /dev/null +++ b/lib/doc/lfun/lib/body/GetAffectLong @@ -0,0 +1,23 @@ +GETAFFECTLONG +NAME + GetAffectLong() + +SYNOPSIS + string GetAffectLong(object ob) + +DESCRIPTION + Adds a descriptive string to a creature's long desc indicating some variable information. In the case of LIB_BODY, it indicates wakefulness or intoxication. For LIB_CLAN, clan membership is indicated. The argument is not used. + +EXAMPLES + + +LOCATION + /lib/body +/lib/clan + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/GetAlcohol b/lib/doc/lfun/lib/body/GetAlcohol new file mode 100644 index 0000000..a623737 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetAlcohol @@ -0,0 +1,36 @@ +GETALCOHOL + +NAME + GetAlcohol() + + + +SYNOPSIS + int GetAlcohol() + + + +DESCRIPTION + Returns the alcohol level of the creature. + + + +EXAMPLES + present("wino",environment(this_player()))->GetAlcohol() + + + +LOCATION + /lib/body +/lib/race + + +SEE ALSO + SetAlcohol + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/GetBodyComposition b/lib/doc/lfun/lib/body/GetBodyComposition new file mode 100644 index 0000000..959e3a1 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetBodyComposition @@ -0,0 +1,29 @@ +GETBODYCOMPOSITION + +NAME + GetBodyComposition() + + +SYNOPSIS + string GetBodyComposition() + + +DESCRIPTION + Returns a string indicating what a non-biological creature is made of. + +EXAMPLES + + + +LOCATION + /lib/body + + +SEE ALSO + SetBodyComposition + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/GetCaffeine b/lib/doc/lfun/lib/body/GetCaffeine new file mode 100644 index 0000000..2d34374 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetCaffeine @@ -0,0 +1,24 @@ +GETCAFFEINE + +NAME + GetCaffeine() + +SYNOPSIS + int GetCaffeine() + +DESCRIPTION + Returns the caffeine level of the creature. + +EXAMPLES + present("barista",environment(this_player()))->GetCaffeine() + +LOCATION + /lib/body + + +SEE ALSO + SetCaffeine + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/GetCanBite b/lib/doc/lfun/lib/body/GetCanBite new file mode 100644 index 0000000..7aea1d2 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetCanBite @@ -0,0 +1,24 @@ +GETCANBITE + +NAME + GetCanBite() + +SYNOPSIS + int GetCanBite() + +DESCRIPTION + Returns whether the creature is permitted to bite during combat. This may be overridden by the race settings, if it is not a "biting race". + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/GetCapName b/lib/doc/lfun/lib/body/GetCapName new file mode 100644 index 0000000..7cb66e2 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetCapName @@ -0,0 +1,39 @@ +GETCAPNAME + +NAME + GetCapName() + + + +SYNOPSIS + string GetCapName() + + + +DESCRIPTION + Returns a thing's capitalized name. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/npc +/lib/player +/lib/props/id +/secure/lib/connect + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/GetCellType b/lib/doc/lfun/lib/body/GetCellType new file mode 100644 index 0000000..b5ddd4e --- /dev/null +++ b/lib/doc/lfun/lib/body/GetCellType @@ -0,0 +1,37 @@ +GETCELLTYPE + +NAME + GetCellType() + + + +SYNOPSIS + string GetCellType() + + + +DESCRIPTION + Returns a string indicating (for batteries) what kind of battery it is, or (for flashlights) what kind of batteries the device requires. + + + +EXAMPLES + + + + +LOCATION + /lib/battery +/lib/flashlight + + + +SEE ALSO + SetCellType + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/GetDeathEvents b/lib/doc/lfun/lib/body/GetDeathEvents new file mode 100644 index 0000000..35a4f4a --- /dev/null +++ b/lib/doc/lfun/lib/body/GetDeathEvents @@ -0,0 +1,24 @@ +GETDEATHEVENTS + +NAME + GetDeathEvents() + +SYNOPSIS + int GetDeathEvents() + +DESCRIPTION + This function is checked in order to determine how many times this body has been "killed". Under rare circumstances a body may receive more than one kill blow simultaneously. This is part of a system to prevent the weirdness that results from such an event. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/GetDrink b/lib/doc/lfun/lib/body/GetDrink new file mode 100644 index 0000000..17404da --- /dev/null +++ b/lib/doc/lfun/lib/body/GetDrink @@ -0,0 +1,24 @@ +GETDRINK + +NAME + GetDrink() + +SYNOPSIS + int GetDrink() + +DESCRIPTION + Returns the drink level of the creature. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/GetDying b/lib/doc/lfun/lib/body/GetDying new file mode 100644 index 0000000..6089505 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetDying @@ -0,0 +1,24 @@ +GETDYING + +NAME + GetDying + +SYNOPSIS + int GetDying() + +DESCRIPTION + Sometimes things happen a bit too fast, and the lib tries to do something fatal to a body that's already dying. This check prevents logical paradoxes from occurring. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/GetEncumbrance b/lib/doc/lfun/lib/body/GetEncumbrance new file mode 100644 index 0000000..b102986 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetEncumbrance @@ -0,0 +1,29 @@ +GETENCUMBRANCE + +NAME + GetEncumbrance() + + +SYNOPSIS + int GetEncumbrance() + +DESCRIPTION + Encumbrance is the measure of how unwieldy a player's inventory is. It has to do with the number of items carried, not necessarily their weight. The more items carried, the creater the encumbrance, and the more difficult it is to fight, if ENABLE_ENCUMBRANCE is defined in config.h. + + +EXAMPLES + + + +LOCATION + /lib/body + + +SEE ALSO + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/GetEquippedLimbs b/lib/doc/lfun/lib/body/GetEquippedLimbs new file mode 100644 index 0000000..12037fe --- /dev/null +++ b/lib/doc/lfun/lib/body/GetEquippedLimbs @@ -0,0 +1,24 @@ +GETEQUIPPEDLIMBS + +NAME + GetEquippedLimbs() + +SYNOPSIS + string array GetEquippedLimbs() + +DESCRIPTION + Returns an array of the limbs possessed by a creature that are currently wearing or wielding something. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + GetWorn + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/GetExperiencePoints b/lib/doc/lfun/lib/body/GetExperiencePoints new file mode 100644 index 0000000..9f2b962 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetExperiencePoints @@ -0,0 +1,24 @@ +GETEXPERIENCEPOINTS + +NAME + GetExperiencePoints() + +SYNOPSIS + int GetExperiencePoints() + +DESCRIPTION + Returns the experience points a creature has earned. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/GetExtraChannels b/lib/doc/lfun/lib/body/GetExtraChannels new file mode 100644 index 0000000..c3a53b7 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetExtraChannels @@ -0,0 +1,30 @@ +GETEXTRACHANNELS + +NAME + GetExtraChannels() + + +SYNOPSIS + string array GetExtraChannels() + + +DESCRIPTION + Returns an array of the player's extra channels. Extra channels are part of a channel test system and will be largely unused post Dead Souls 2.1. + + +EXAMPLES + + + + +LOCATION + /lib/body + + +SEE ALSO + SetExtraChannels, GetExtraChannels, AddExtraChannels, RemoveExtraChannels + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/GetFingers b/lib/doc/lfun/lib/body/GetFingers new file mode 100644 index 0000000..a4c6549 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetFingers @@ -0,0 +1,37 @@ +GETFINGERS + +NAME + GetFingers() + + + +SYNOPSIS + LIB_BODY: int GetFingers(string limb) LIB_ARMOR: int GetFingers() + + + +DESCRIPTION + For creatures, returns the number of fingers on the given limb. For armor, returns the number of fingers required to wear the item. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/std/armor +/lib/std/worn_storage + + +SEE ALSO + AddFingers + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/GetFood b/lib/doc/lfun/lib/body/GetFood new file mode 100644 index 0000000..d49ec0b --- /dev/null +++ b/lib/doc/lfun/lib/body/GetFood @@ -0,0 +1,36 @@ +GETFOOD + +NAME + GetFood() + + + +SYNOPSIS + LIB_BODY: int GetFood() LIB_FISH: string GetFood() + + + +DESCRIPTION + LIB_BODY: Returns the food level of the creature. LIB_FISH: Returns the path to the meal file that this fish uses. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/fish + + +SEE ALSO + SetFood, AddFood + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/GetHealRate b/lib/doc/lfun/lib/body/GetHealRate new file mode 100644 index 0000000..7ad1392 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetHealRate @@ -0,0 +1,31 @@ +GETHEALRATE + +NAME + GetHealRate() + + +SYNOPSIS + int GetHealRate() + + +DESCRIPTION + Returns a creature's healing rate. + + +EXAMPLES + + + +LOCATION + /lib/body +/lib/race + + +SEE ALSO + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/GetHealthPoints b/lib/doc/lfun/lib/body/GetHealthPoints new file mode 100644 index 0000000..75a553a --- /dev/null +++ b/lib/doc/lfun/lib/body/GetHealthPoints @@ -0,0 +1,24 @@ +GETHEALTHPOINTS + +NAME + GetHealthPoints() + +SYNOPSIS + varargs int GetHealthPoints(string limb) + +DESCRIPTION + Without an argument, returns the health points of the creature it's called in. With a limb argument specified, it returns the health points left in that limb, if it exists. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/GetHealthShort b/lib/doc/lfun/lib/body/GetHealthShort new file mode 100644 index 0000000..2682db9 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetHealthShort @@ -0,0 +1,36 @@ +GETHEALTHSHORT + +NAME + GetHealthShort() + + + +SYNOPSIS + string GetHealthShort() + + + +DESCRIPTION + Colorizes a creature's short description based on their health status. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/std/corpse + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/GetHeartModifier b/lib/doc/lfun/lib/body/GetHeartModifier new file mode 100644 index 0000000..db178e2 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetHeartModifier @@ -0,0 +1,29 @@ +GETHEARTMODIFIER + +NAME + GetHeartModifier() + + +SYNOPSIS + int GetHeartModifier() + + +DESCRIPTION + Returns the modifier set in that creature for their heart rate. A low number means a faster heart rate. A higher number means a slower heart rate. This affects how quickly a creature heals. + + +EXAMPLES + + + +LOCATION + /lib/body + + +SEE ALSO + AddHeartModifier + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/GetHeartRate b/lib/doc/lfun/lib/body/GetHeartRate new file mode 100644 index 0000000..3bce69f --- /dev/null +++ b/lib/doc/lfun/lib/body/GetHeartRate @@ -0,0 +1,31 @@ +GETHEARTRATE + +NAME + GetHeartRate() + + +SYNOPSIS + int GetHeartRate() + + +DESCRIPTION + Returns a creature's heart rate (NOT heart_beat). + + +EXAMPLES + + + +LOCATION + /lib/body +/lib/race + + +SEE ALSO + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/GetLead b/lib/doc/lfun/lib/body/GetLead new file mode 100644 index 0000000..4e294a3 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetLead @@ -0,0 +1,24 @@ +GETLEAD + +NAME + GetLead() + +SYNOPSIS + int GetLead(string ammo) + +DESCRIPTION + This is part of an obsolete firearms system. It reports how much bullet damage a creature has received. This will be replaced by a proper projectile wound system post-2.1. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/GetLimbChildren b/lib/doc/lfun/lib/body/GetLimbChildren new file mode 100644 index 0000000..afd9090 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetLimbChildren @@ -0,0 +1,29 @@ +GETLIMBCHILDREN + +NAME + GetLimbChildren() + + +SYNOPSIS + string array GetLimbChildren(string limb) + + +DESCRIPTION + Returns the limbs that depend on this limb to remain attached to the creature. + + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + GetLimbParent, GetMissingLimbParent, GetMissingLimbs, GetLimbs + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/GetLimbClass b/lib/doc/lfun/lib/body/GetLimbClass new file mode 100644 index 0000000..cf8f473 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetLimbClass @@ -0,0 +1,24 @@ +GETLIMBCLASS + +NAME + GetLimbClass() + +SYNOPSIS + int GetLimbClass(string limb) + +DESCRIPTION + Returns the "class" or level of importance of the specified limb. Severing a creature's class 1 limb will result in its immediate death. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/GetLimbParent b/lib/doc/lfun/lib/body/GetLimbParent new file mode 100644 index 0000000..23ea3f4 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetLimbParent @@ -0,0 +1,33 @@ +GETLIMBPARENT + +NAME + GetLimbParent() + + + +SYNOPSIS + string GetLimbParent(string limb) + + + +DESCRIPTION + Returns the name of the "parent limb" of the limb specified. + + + +EXAMPLES + + + + +LOCATION + /lib/body + + +SEE ALSO + GetLimbChildren, GetMissingLimbParent, GetMissingLimbs, GetLimbs + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/GetLimbs b/lib/doc/lfun/lib/body/GetLimbs new file mode 100644 index 0000000..273978f --- /dev/null +++ b/lib/doc/lfun/lib/body/GetLimbs @@ -0,0 +1,24 @@ +GETLIMBS + +NAME + GetLimbs() + +SYNOPSIS + string array GetLimbs() + +DESCRIPTION + Returns a creature's existing limbs. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + GetMissingLimbs + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/GetLong b/lib/doc/lfun/lib/body/GetLong new file mode 100644 index 0000000..097c124 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetLong @@ -0,0 +1,47 @@ +GETLONG + +NAME + GetLong() + + + +SYNOPSIS + string GetLong(string str) + + + +DESCRIPTION + Returns the "long desciption" of the object it's called in. This long description is the main part of what the player sees when they "look at" something. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/bot +/lib/creator +/lib/donate +/lib/door +/lib/fuel +/lib/interactive +/lib/lamp +/lib/npc +/lib/player +/lib/torch +/lib/events/look +/lib/std/room + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/GetMagicPoints b/lib/doc/lfun/lib/body/GetMagicPoints new file mode 100644 index 0000000..313da17 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetMagicPoints @@ -0,0 +1,24 @@ +GETMAGICPOINTS + +NAME + GetMagicPoints() + +SYNOPSIS + int GetMagicPoints() + +DESCRIPTION + Returns a creature's current magic point level. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + SetMagicPoints, GetMaxMagicPoints, AddMagicPoints + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/GetMaxHealthPoints b/lib/doc/lfun/lib/body/GetMaxHealthPoints new file mode 100644 index 0000000..ee454cb --- /dev/null +++ b/lib/doc/lfun/lib/body/GetMaxHealthPoints @@ -0,0 +1,39 @@ +GETMAXHEALTHPOINTS + +NAME + GetMaxHealthPoints() + + + +SYNOPSIS + varargs int GetMaxHealthPoints(string limb) + + + +DESCRIPTION + Returns a creature's maximum health level. Their normal healing process will not increase their health beyond this point. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/combat +/lib/living +/lib/npc +/lib/race + + +SEE ALSO + SetMaxHealthPoints, SetHealthPoints, GetHealthPoints + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/GetMaxMagicPoints b/lib/doc/lfun/lib/body/GetMaxMagicPoints new file mode 100644 index 0000000..a6e290e --- /dev/null +++ b/lib/doc/lfun/lib/body/GetMaxMagicPoints @@ -0,0 +1,36 @@ +GETMAXMAGICPOINTS + +NAME + GetMaxMagicPoints() + + + +SYNOPSIS + int GetMaxMagicPoints() + + + +DESCRIPTION + Returns a creature's maximum magic level. Their normal healing process will not increase their magic beyond this point. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/race + + +SEE ALSO + SetMagicPoints, GetMagicPoints, AddMagicPoints + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/GetMaxStaminaPoints b/lib/doc/lfun/lib/body/GetMaxStaminaPoints new file mode 100644 index 0000000..c98e79d --- /dev/null +++ b/lib/doc/lfun/lib/body/GetMaxStaminaPoints @@ -0,0 +1,36 @@ +GETMAXSTAMINAPOINTS + +NAME + GetMaxStaminaPoints() + + + +SYNOPSIS + float GetMaxStaminaPoints() + + + +DESCRIPTION + Returns a creature's maximum stamina level. Their normal healing process will not increase their stamina beyond this point. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/race + + +SEE ALSO + AddStaminaPoints, GetStaminaPoints + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/GetMelee b/lib/doc/lfun/lib/body/GetMelee new file mode 100644 index 0000000..0f37f6a --- /dev/null +++ b/lib/doc/lfun/lib/body/GetMelee @@ -0,0 +1,24 @@ +GETMELEE + +NAME + GetMelee() + +SYNOPSIS + int GetMelee() + +DESCRIPTION + Returns whether a creature is capable of unarmed combat. If this returns 0, the creature is most likely extremely ineffective without a weapon. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/GetMissingLimbParent b/lib/doc/lfun/lib/body/GetMissingLimbParent new file mode 100644 index 0000000..26b180d --- /dev/null +++ b/lib/doc/lfun/lib/body/GetMissingLimbParent @@ -0,0 +1,24 @@ +GETMISSINGLIMBPARENT + +NAME + GetMissingLimbParent() + +SYNOPSIS + string GetMissingLimbParent(string limb) + +DESCRIPTION + Returns the name of the parent limb of the specified missing limb. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + GetLimbChildren, GetLimbParent, GetMissingLimbs, GetLimbs + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/GetMissingLimbParents b/lib/doc/lfun/lib/body/GetMissingLimbParents new file mode 100644 index 0000000..42d59bf --- /dev/null +++ b/lib/doc/lfun/lib/body/GetMissingLimbParents @@ -0,0 +1,24 @@ +GETMISSINGLIMBPARENTS + +NAME + GetMissingLimbParents() + +SYNOPSIS + string array GetMissingLimbParents(string limb) + +DESCRIPTION + Returns the entire chain of a limb's attachment as an array. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + GetLimbs, GetLimbParent, GetMissingLimbParent, GetLimbChildren + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/GetMissingLimbs b/lib/doc/lfun/lib/body/GetMissingLimbs new file mode 100644 index 0000000..5d47beb --- /dev/null +++ b/lib/doc/lfun/lib/body/GetMissingLimbs @@ -0,0 +1,24 @@ +GETMISSINGLIMBS + +NAME + GetMissingLimbs() + +SYNOPSIS + varargs string array GetMissingLimbs(int not_default) + +DESCRIPTION + Returns an array of the limbs a creature is missing. The integer argument invokes a test function that is largely unused as of Dead Souls 2.1. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + GetLimbs, GetLimbParent, GetMissingLimbParent, GetLimbChildren + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/GetMoJo b/lib/doc/lfun/lib/body/GetMoJo new file mode 100644 index 0000000..6b93ba3 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetMoJo @@ -0,0 +1,24 @@ +GETMOJO + +NAME + GetMoJo() + +SYNOPSIS + float GetMoJo() + +DESCRIPTION + This is a test function, designed to check a creature's level of the notional characteristic of "Mojo". It is unused. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + SetMojo + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/GetName b/lib/doc/lfun/lib/body/GetName new file mode 100644 index 0000000..9b9f25b --- /dev/null +++ b/lib/doc/lfun/lib/body/GetName @@ -0,0 +1,41 @@ +GETNAME + +NAME + GetName() + + + +SYNOPSIS + string GetName() + + + +DESCRIPTION + Returns the object's proper name, capitalized if appropriate. + + + +EXAMPLES + this_player()->GetName() + + + +LOCATION + /lib/body +/lib/creator +/lib/interactive +/lib/messages +/lib/npc +/lib/player +/lib/props/id + + +SEE ALSO + GetKeyName() + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/GetPacifist b/lib/doc/lfun/lib/body/GetPacifist new file mode 100644 index 0000000..0ee5af0 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetPacifist @@ -0,0 +1,24 @@ +GETPACIFIST + +NAME + GetPacifist() + +SYNOPSIS + int GetPacifist() + +DESCRIPTION + The default, 0, means the creature is willing to engage in combat. A return of 1 means the creature will not fight, regardless of whether it is under attack. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + SetPacifist + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/GetPoison b/lib/doc/lfun/lib/body/GetPoison new file mode 100644 index 0000000..246d1bc --- /dev/null +++ b/lib/doc/lfun/lib/body/GetPoison @@ -0,0 +1,36 @@ +GETPOISON + +NAME + GetPoison + + + +SYNOPSIS + int GetPoison() + + + +DESCRIPTION + Returns the current poison level. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/events/poison + + +SEE ALSO + AddPoison + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/GetProtect b/lib/doc/lfun/lib/body/GetProtect new file mode 100644 index 0000000..94f80e9 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetProtect @@ -0,0 +1,32 @@ +GETPROTECT + +NAME + GetProtect() + + + +SYNOPSIS + function GetProtect() + + + +DESCRIPTION + Returns the "Protect" function set in the creature. + + +EXAMPLES + + + + +LOCATION + /lib/body + + +SEE ALSO + SetProtect, RemoveMagicProtection, AddMagicProtection + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/GetQuestPoints b/lib/doc/lfun/lib/body/GetQuestPoints new file mode 100644 index 0000000..2f8cf67 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetQuestPoints @@ -0,0 +1,24 @@ +GETQUESTPOINTS + +NAME + GetQuestPoints() + +SYNOPSIS + int GetQuestPoints() + +DESCRIPTION + Returns the number of quest points earned by the creature. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + AddQuestPoints + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/GetRace b/lib/doc/lfun/lib/body/GetRace new file mode 100644 index 0000000..e945d80 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetRace @@ -0,0 +1,38 @@ +GETRACE + +NAME + GetRace() + + + +SYNOPSIS + string GetRace() + + + +DESCRIPTION + Returns the creature's race. + + + +EXAMPLES + present("Spock", environment(this_player()))->GetRace() + + + +LOCATION + /lib/body +/lib/race +/lib/std/corpse +/lib/std/limb + + +SEE ALSO + GetClass + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/GetRandomLimb b/lib/doc/lfun/lib/body/GetRandomLimb new file mode 100644 index 0000000..5005106 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetRandomLimb @@ -0,0 +1,24 @@ +GETRANDOMLIMB + +NAME + GetRandomLimb() + +SYNOPSIS + string GetRandomLimb(string targ) + +DESCRIPTION + Returns a random limb weighted towards the targetted limb. string targ - the targetted limb. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + UNKNOWN + diff --git a/lib/doc/lfun/lib/body/GetResistance b/lib/doc/lfun/lib/body/GetResistance new file mode 100644 index 0000000..1fbc0ce --- /dev/null +++ b/lib/doc/lfun/lib/body/GetResistance @@ -0,0 +1,32 @@ +GETRESISTANCE + +NAME + GetResistance() + + +SYNOPSIS + string GetResistance(int type) + + +DESCRIPTION + Returns the creature's resistance level to the given damage type. + + +EXAMPLES + this_player()->GetResistance(GAS) + + +LOCATION + /lib/body +/lib/genetics +/lib/race + + +SEE ALSO + damage_types.h + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/GetSleeping b/lib/doc/lfun/lib/body/GetSleeping new file mode 100644 index 0000000..7fcf5a9 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetSleeping @@ -0,0 +1,24 @@ +GETSLEEPING + +NAME + GetSleeping() + +SYNOPSIS + int GetSleeping() + +DESCRIPTION + Returns how soundly asleep a creature is. Multiplying the resulting number by the standard modifier indicates the number of heartbeats left in that creature's sleep. In Dead Souls 2.1 that standard modifier is 6. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + SetSleeping + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/GetStaminaPoints b/lib/doc/lfun/lib/body/GetStaminaPoints new file mode 100644 index 0000000..8ad4aa3 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetStaminaPoints @@ -0,0 +1,24 @@ +GETSTAMINAPOINTS + +NAME + GetStaminaPoints() + +SYNOPSIS + int GetStaminaPoints() + +DESCRIPTION + Returns a creature's current stamina point level. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + AddStaminaPoints, GetMaxStaminaPoints + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/GetTorso b/lib/doc/lfun/lib/body/GetTorso new file mode 100644 index 0000000..45714c2 --- /dev/null +++ b/lib/doc/lfun/lib/body/GetTorso @@ -0,0 +1,24 @@ +GETTORSO + +NAME + GetTorso() + +SYNOPSIS + string GetTorso() + +DESCRIPTION + Returns the name of the main limb nexus of a creature. An octopus, for example, might return "head" and an ant might return "thorax". + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/GetWielded b/lib/doc/lfun/lib/body/GetWielded new file mode 100644 index 0000000..89c706f --- /dev/null +++ b/lib/doc/lfun/lib/body/GetWielded @@ -0,0 +1,36 @@ +GETWIELDED + +NAME + GetWielded() + + + +SYNOPSIS + LIB_BODY: varargs mixed GetWielded(string limb) LIB_WEAPON: int GetWielded() + + + +DESCRIPTION + LIB_BODY: With no argument, returns the objects wielded by the creature. If the argument is a limb, this function returns what is wielded in that limb, if anything. LIB_WEAPON: If the weapon is wielded, this function returns 1. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/comp/weapon + + +SEE ALSO + GetWieldingLimbs + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/GetWieldingLimbs b/lib/doc/lfun/lib/body/GetWieldingLimbs new file mode 100644 index 0000000..8544dda --- /dev/null +++ b/lib/doc/lfun/lib/body/GetWieldingLimbs @@ -0,0 +1,24 @@ +GETWIELDINGLIMBS + +NAME + GetWieldingLimbs() + +SYNOPSIS + string array GetWieldingLimbs() + +DESCRIPTION + Returns a creature's prehensile limbs. Prehensile limbs are limbs that can wield weapons. A creature lacking prehensile limbs is generally unable to get or manipulate objects. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + GetLimbChildren, GetLimbParent, GetMissingLimbs, GetLimbs, GetMissingLimbParent + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/GetWorn b/lib/doc/lfun/lib/body/GetWorn new file mode 100644 index 0000000..e9ed7fa --- /dev/null +++ b/lib/doc/lfun/lib/body/GetWorn @@ -0,0 +1,32 @@ +GETWORN + +NAME + GetWorn() + + + +SYNOPSIS + LIB_BODY: varargs object array GetWorn(string limb) LIB_EQUIP: string array GetWorn() + + +DESCRIPTION + LIB_BODY: Without an argument, returns an array of all worn and wielded objects in the creature's inventory. With a limb as an argument, returns an array of all worn and wielded objects on that limb. LIB_EQUIP: Returns a positive integer if the item is currently being worn, 0 otherwise. + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/props/equip + + +SEE ALSO + SetWorn, GetEquippedLimbs + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/HealLimb b/lib/doc/lfun/lib/body/HealLimb new file mode 100644 index 0000000..12bb307 --- /dev/null +++ b/lib/doc/lfun/lib/body/HealLimb @@ -0,0 +1,24 @@ +HEALLIMB + +NAME + HealLimb() + +SYNOPSIS + int HealLimb(string limb) + +DESCRIPTION + If the creature possesses the limb in question, its maximum health points are restored. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/NewBody b/lib/doc/lfun/lib/body/NewBody new file mode 100644 index 0000000..5ebc142 --- /dev/null +++ b/lib/doc/lfun/lib/body/NewBody @@ -0,0 +1,31 @@ +NEWBODY + +NAME + NewBody() + + +SYNOPSIS + void NewBody(string race) + + +DESCRIPTION + Initializes some body-specific mappings. A null race creates potentially undesirable outcomes. + + +EXAMPLES + + + +LOCATION + /lib/body +/lib/race + + +SEE ALSO + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/ParseHook b/lib/doc/lfun/lib/body/ParseHook new file mode 100644 index 0000000..902a6b1 --- /dev/null +++ b/lib/doc/lfun/lib/body/ParseHook @@ -0,0 +1,24 @@ +PARSEHOOK + +NAME + ParseHook() + +SYNOPSIS + void ParseHook(string str) + +DESCRIPTION + This is a test function designed to invoke the parse_sentence function in the creature. As of Dead Souls 2.1 it is largely unused. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/RemoveExtraChannels b/lib/doc/lfun/lib/body/RemoveExtraChannels new file mode 100644 index 0000000..8ff27f8 --- /dev/null +++ b/lib/doc/lfun/lib/body/RemoveExtraChannels @@ -0,0 +1,29 @@ +REMOVEEXTRACHANNELS + +NAME + RemoveExtraChannels() + + +SYNOPSIS + string array RemoveExtraChannels(string array chans) + + +DESCRIPTION + Removes channels from the player's extra channels. Extra channels are part of a channel test system and will be largely unused post Dead Souls 2.1. + + +EXAMPLES + + + +LOCATION + /lib/body + + +SEE ALSO + SetExtraChannels, GetExtraChannels, AddExtraChannels, RemoveExtraChannels + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/RemoveLimb b/lib/doc/lfun/lib/body/RemoveLimb new file mode 100644 index 0000000..e651bbe --- /dev/null +++ b/lib/doc/lfun/lib/body/RemoveLimb @@ -0,0 +1,25 @@ +REMOVELIMB + +NAME + RemoveLimb() + +SYNOPSIS + int RemoveLimb(string limb, object agent) + +DESCRIPTION + Removes a limb from the limbs mapping and stores vital data in the missing limbs mapping. string limb - the limb being removed. object agent - the agent who is responsible for the limb removal. Returns -1 on error, 0 on failure, 1 on success. + +EXAMPLES + + + +LOCATION + /lib/body + + +SEE ALSO + RestoreLimb, DestLimb, AddLimb + +Author + Unknown + diff --git a/lib/doc/lfun/lib/body/RemoveMagicProtection b/lib/doc/lfun/lib/body/RemoveMagicProtection new file mode 100644 index 0000000..674ff77 --- /dev/null +++ b/lib/doc/lfun/lib/body/RemoveMagicProtection @@ -0,0 +1,24 @@ +REMOVEMAGICPROTECTION + +NAME + RemoveMagicProtection() + +SYNOPSIS + int RemoveMagicProtection(int i) + +DESCRIPTION + If there is a protection function element i, for example Protection[3], it is removed from the creature's protections. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + AddMagicProtection + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/RestoreLimb b/lib/doc/lfun/lib/body/RestoreLimb new file mode 100644 index 0000000..765a30c --- /dev/null +++ b/lib/doc/lfun/lib/body/RestoreLimb @@ -0,0 +1,24 @@ +RESTORELIMB + +NAME + RestoreLimb() + +SYNOPSIS + varargs int RestoreLimb(string limb, int recurse) + +DESCRIPTION + This is the function that should be used to put tail back on something that used to have a tail and no longer does because it was severed. Using AddLimb() for that purpose is not recommended. If the optional argument "recurse" is a positive integer, the function will restore the limb and anything distal to it. If the limb to be restored is attached to a limb that does not exist, the function will fail. + +EXAMPLES + To restore the arm plus its children (in this case, a hand): RestoreLimb("right arm",1) . RestoreLimb("right arm") will restore the arm only. + +LOCATION + /lib/body + + +SEE ALSO + RemoveLimb, DestLimb, AddLimb + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/SetBodyComposition b/lib/doc/lfun/lib/body/SetBodyComposition new file mode 100644 index 0000000..51c09f5 --- /dev/null +++ b/lib/doc/lfun/lib/body/SetBodyComposition @@ -0,0 +1,29 @@ +SETBODYCOMPOSITION + +NAME + SetBodyComposition() + + +SYNOPSIS + string SetBodyComposition(string str) + + +DESCRIPTION + Creatures without biological components, such as golems, have this set so that when they die, the appropriate chunks of matter are put into the room, rather than a fleshy corpse. + + +EXAMPLES + SetBodyComposition("clay") + +LOCATION + /lib/body + + +SEE ALSO + GetBodyComposition + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/SetCanBite b/lib/doc/lfun/lib/body/SetCanBite new file mode 100644 index 0000000..35f6313 --- /dev/null +++ b/lib/doc/lfun/lib/body/SetCanBite @@ -0,0 +1,24 @@ +SETCANBITE + +NAME + SetCanBite() + +SYNOPSIS + int SetCanBite(int i) + +DESCRIPTION + Some creatures are physically capable of biting during combat, but it may not be desirable to allow it. Setting this to 0 can allow a demigod, for example, to keep his dignity in unarmed combat. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + GetCanBite + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/SetDeathEvents b/lib/doc/lfun/lib/body/SetDeathEvents new file mode 100644 index 0000000..af9ab30 --- /dev/null +++ b/lib/doc/lfun/lib/body/SetDeathEvents @@ -0,0 +1,24 @@ +SETDEATHEVENTS + +NAME + SetDeathEvents() + +SYNOPSIS + int SetDeathEvents(int i) + +DESCRIPTION + This function is called in order to establish how many times this body has been "killed". Under rare circumstances a body may receive more than one kill blow simultaneously. This is part of a system to prevent the weirdness that results from such an event. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/SetDrainRate b/lib/doc/lfun/lib/body/SetDrainRate new file mode 100644 index 0000000..e428821 --- /dev/null +++ b/lib/doc/lfun/lib/body/SetDrainRate @@ -0,0 +1,33 @@ +SETDRAINRATE + +NAME + SetDrainRate() + + +SYNOPSIS + int SetDrainRate(int i) + + + +DESCRIPTION + Sets how much of a battery's charge is drained per heartbeat of use. + + +EXAMPLES + For a two-minute battery with a charge of 120 on a mud with a one-second heartbeat: SetDrainRate(1) + + +LOCATION + /lib/battery.c +/lib/flashlight.c + + + +SEE ALSO + GetDrainRate, SetCharge, GetCharge + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/SetExtraChannels b/lib/doc/lfun/lib/body/SetExtraChannels new file mode 100644 index 0000000..4e27e37 --- /dev/null +++ b/lib/doc/lfun/lib/body/SetExtraChannels @@ -0,0 +1,24 @@ +SETEXTRACHANNELS + +NAME + SetExtraChannels() + +SYNOPSIS + string array SetExtraChannels(string array chans) + +DESCRIPTION + Sets the player's extra channels. Extra channels are part of a channel test system and will be largely unused post Dead Souls 2.1. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + SetExtraChannels, GetExtraChannels, AddExtraChannels, RemoveExtraChannels + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/SetFingers b/lib/doc/lfun/lib/body/SetFingers new file mode 100644 index 0000000..2275d7d --- /dev/null +++ b/lib/doc/lfun/lib/body/SetFingers @@ -0,0 +1,23 @@ +SETFINGERS + +NAME + + +SYNOPSIS + + +DESCRIPTION + + +EXAMPLES + + +LOCATION + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/SetMelee b/lib/doc/lfun/lib/body/SetMelee new file mode 100644 index 0000000..9a2fbe6 --- /dev/null +++ b/lib/doc/lfun/lib/body/SetMelee @@ -0,0 +1,29 @@ +SETMELEE + +NAME + SetMelee() + + +SYNOPSIS + int SetMelee(int i) + + +DESCRIPTION + Allows the npc this is called in to be capable of unarmed combat if the integer passed is 1. An argument of 0 indicates that the npc is not able to properly fight without weapons. + + +EXAMPLES + + + +LOCATION + /lib/body + + +SEE ALSO + GetMelee + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/SetPacifist b/lib/doc/lfun/lib/body/SetPacifist new file mode 100644 index 0000000..36e4b85 --- /dev/null +++ b/lib/doc/lfun/lib/body/SetPacifist @@ -0,0 +1,24 @@ +SETPACIFIST + +NAME + SetPacifist() + +SYNOPSIS + int SetPacifist(int i) + +DESCRIPTION + An argument of 1 makes the creature a pacifist. 0 makes it not a pacifist. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + GetPacifist + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/SetProtect b/lib/doc/lfun/lib/body/SetProtect new file mode 100644 index 0000000..bf2f0f3 --- /dev/null +++ b/lib/doc/lfun/lib/body/SetProtect @@ -0,0 +1,32 @@ +SETPROTECT + +NAME + SetProtect() + + + +SYNOPSIS + mixed SetProtect(function f) + + + +DESCRIPTION + Sets a function (f) to be the one called when GetProtect is called. + + +EXAMPLES + + + + +LOCATION + /lib/body + + +SEE ALSO + GetProtect, RemoveMagicProtection, AddMagicProtection + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/SetSleeping b/lib/doc/lfun/lib/body/SetSleeping new file mode 100644 index 0000000..639c300 --- /dev/null +++ b/lib/doc/lfun/lib/body/SetSleeping @@ -0,0 +1,30 @@ +SETSLEEPING + +NAME + SetSleeping() + + +SYNOPSIS + int SetSleeping(int i) + + +DESCRIPTION + Set the creature to its sleep state, for a heartbeat duration of the number specified multiplied by the standard modifier, which in Dead Souls 2.1 is 6. + + +EXAMPLES + To make Tacitus sleep for 60 heart_beats (note that his heart_beats may be more than just one second long): find_player("tacitus")->SetSleeping(10) + + +LOCATION + /lib/body + + +SEE ALSO + GetSleeping + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/checkCollapse b/lib/doc/lfun/lib/body/checkCollapse new file mode 100644 index 0000000..c5d84c1 --- /dev/null +++ b/lib/doc/lfun/lib/body/checkCollapse @@ -0,0 +1,24 @@ +CHECKCOLLAPSE + +NAME + checkCollapse() + +SYNOPSIS + private void checkCollapse() + +DESCRIPTION + This function is periodically called to find out if the creature is too weak to stand, or if it is strong enough to get back up. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/eventBuy b/lib/doc/lfun/lib/body/eventBuy new file mode 100644 index 0000000..0a8b2f5 --- /dev/null +++ b/lib/doc/lfun/lib/body/eventBuy @@ -0,0 +1,36 @@ +EVENTBUY + +NAME + eventBuy() + + + +SYNOPSIS + LIB_BODY: varargs mixed eventBuy(mixed arg1, mixed arg2, mixed arg3) LIB_VENDOR: mixed eventBuy(object who, object *obs) + + + +DESCRIPTION + In LIB_BODY, this is a function designed to return an error. If the creature is supposed to be able to do something with this function (such as vendors), it should be overridden with the appropriate code. LIB_VENDOR: This is called when someone tries to sell something to the vendor. The seller is who, and the items being sold is *obs. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/std/vendor + + +SEE ALSO + eventSell + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/eventCheckHealing b/lib/doc/lfun/lib/body/eventCheckHealing new file mode 100644 index 0000000..59b12ce --- /dev/null +++ b/lib/doc/lfun/lib/body/eventCheckHealing @@ -0,0 +1,24 @@ +EVENTCHECKHEALING + +NAME + eventCheckHealing() + +SYNOPSIS + void eventCheckHealing() + +DESCRIPTION + This function performs the general, periodic tasks associated with the effects of the passage of time on a body. Sleep, food, and drink levels are decremented, the actual healing function is triggered if appropriate, etc. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + eventCompleteHeal + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/eventCheckProtection b/lib/doc/lfun/lib/body/eventCheckProtection new file mode 100644 index 0000000..1a9c435 --- /dev/null +++ b/lib/doc/lfun/lib/body/eventCheckProtection @@ -0,0 +1,24 @@ +EVENTCHECKPROTECTION + +NAME + eventCheckProtection() + +SYNOPSIS + int eventCheckProtection(object agent, int type, int damage) + +DESCRIPTION + This function cycles through any magic protection found, reducing damage accordingly. agent : object doing the damage. type : damage type(s). damage : original amount damage being done. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + SetProtect, GetProtect, RemoveMagicProtection, AddMagicProtection + +Author + Unknown + diff --git a/lib/doc/lfun/lib/body/eventCollapse b/lib/doc/lfun/lib/body/eventCollapse new file mode 100644 index 0000000..5f406ea --- /dev/null +++ b/lib/doc/lfun/lib/body/eventCollapse @@ -0,0 +1,24 @@ +EVENTCOLLAPSE + +NAME + eventCollapse() + +SYNOPSIS + int eventCollapse() + +DESCRIPTION + Runs the appropriate events on and about the collapse of a creature. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/eventCompareLimbs b/lib/doc/lfun/lib/body/eventCompareLimbs new file mode 100644 index 0000000..6f70501 --- /dev/null +++ b/lib/doc/lfun/lib/body/eventCompareLimbs @@ -0,0 +1,24 @@ +EVENTCOMPARELIMBS + +NAME + eventCompareLimbs() + +SYNOPSIS + int eventCompareLimbs(string limb1, string limb2) + +DESCRIPTION + A test function designed to be run by the GetMissingLimbs fun. Largely unused in Dead Souls 2.1. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/eventCompleteHeal b/lib/doc/lfun/lib/body/eventCompleteHeal new file mode 100644 index 0000000..77b16c8 --- /dev/null +++ b/lib/doc/lfun/lib/body/eventCompleteHeal @@ -0,0 +1,33 @@ +EVENTCOMPLETEHEAL + +NAME + eventCompleteHeal() + + + +SYNOPSIS + void eventCompleteHeal(int x) + + + +DESCRIPTION + When a body determines it is time for a heal event (basically, the correct amount of time has passed, and the creature is to recover somewhat) this function is called. It does not do a "complete heal", it simply completes the heal event. + +EXAMPLES + + + + +LOCATION + /lib/body + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/eventDie b/lib/doc/lfun/lib/body/eventDie new file mode 100644 index 0000000..4e12cf7 --- /dev/null +++ b/lib/doc/lfun/lib/body/eventDie @@ -0,0 +1,41 @@ +EVENTDIE + +NAME + eventDie() + + + +SYNOPSIS + varargs int eventDie(mixed agent) + + + +DESCRIPTION + When a creature dies, this function is called in them. The argument should be what it is that killed them. Note that this is a function that is heavily overridden, and must be handled with care if modified. If you don't know what a function override is, then don't mess with this function. If eventDie() returns something other than a positive integer, the creature doesn't die in the conventional sense: they instead become undead. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/bot +/lib/combat +/lib/flashlight +/lib/npc +/lib/player +/lib/race + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/eventFall b/lib/doc/lfun/lib/body/eventFall new file mode 100644 index 0000000..ec44d0b --- /dev/null +++ b/lib/doc/lfun/lib/body/eventFall @@ -0,0 +1,35 @@ +EVENTFALL + +NAME + eventFall() + + + +SYNOPSIS + mixed eventFall() + + + +DESCRIPTION + What happens when a body suffers a fall. Relevant checks and actions occur here. + + + +EXAMPLES + this_player()->eventFall() + + + +LOCATION + /lib/body +/lib/lvs/position + + +SEE ALSO + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/eventHealDamage b/lib/doc/lfun/lib/body/eventHealDamage new file mode 100644 index 0000000..ab82de8 --- /dev/null +++ b/lib/doc/lfun/lib/body/eventHealDamage @@ -0,0 +1,24 @@ +EVENTHEALDAMAGE + +NAME + eventHealDamage() + +SYNOPSIS + varargs int eventHealDamage(int x, int internal, mixed limbs) + +DESCRIPTION + int x - amount of damage being healed, negatives illegal. int internal - internal damage flag (optional). mixed limbs - limb or limbs affected by the heal event (optional). If the internal flag is set then overall health is healed. If limbs are specified then the specified limbs are healed. If the internal flag is NOT set and NO limbs are specified (default) then both overall health as well as the health of all limbs are healed. Returns the actual amount of healing done or -1 if an error occurs. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + eventReceiveDamage + +Author + Unknown + diff --git a/lib/doc/lfun/lib/body/eventReceiveDamage b/lib/doc/lfun/lib/body/eventReceiveDamage new file mode 100644 index 0000000..b72a68f --- /dev/null +++ b/lib/doc/lfun/lib/body/eventReceiveDamage @@ -0,0 +1,39 @@ +EVENTRECEIVEDAMAGE + +NAME + eventReceiveDamage() + + + +SYNOPSIS + varargs int eventReceiveDamage(object agent, int type, int x, int internal, mixed limbs) + + + +DESCRIPTION + What sometimes happens to good people. + + + +EXAMPLES + orc->eventReceiveDamage(this_player(), BLADE, 100, 0, ({ "head", "neck" }) ) + + + +LOCATION + /lib/body +/lib/combat +/lib/props/deterioration +/lib/std/armor +/lib/std/worn_storage + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/eventReceiveThrow b/lib/doc/lfun/lib/body/eventReceiveThrow new file mode 100644 index 0000000..e16b83f --- /dev/null +++ b/lib/doc/lfun/lib/body/eventReceiveThrow @@ -0,0 +1,24 @@ +EVENTRECEIVETHROW + +NAME + eventReceiveThrow() + +SYNOPSIS + mixed eventReceiveThrow(object who, object what) + +DESCRIPTION + Performs the appropriate calculations for a body that is the target of a thrown object. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/body/eventReconnect b/lib/doc/lfun/lib/body/eventReconnect new file mode 100644 index 0000000..9046556 --- /dev/null +++ b/lib/doc/lfun/lib/body/eventReconnect @@ -0,0 +1,40 @@ +EVENTRECONNECT + +NAME + eventReconnect() + + + +SYNOPSIS + void eventReconnect() + + + +DESCRIPTION + A series of events that need to occur when a user reconnects to the game after going link-dead. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/chat +/lib/creator +/lib/interactive +/lib/npc +/lib/player + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/body/eventRemoveItem b/lib/doc/lfun/lib/body/eventRemoveItem new file mode 100644 index 0000000..697d242 --- /dev/null +++ b/lib/doc/lfun/lib/body/eventRemoveItem @@ -0,0 +1,32 @@ +EVENTREMOVEITEM + +NAME + eventRemoveItem() + + + +SYNOPSIS + int eventRemoveItem(object ob) + + + +DESCRIPTION + Removes a worn or wielded item from the list. object ob - the item being removed. Returns 1 on success, 0 on failure. + + +EXAMPLES + + + + +LOCATION + /lib/body + + +SEE ALSO + eventWear + +Author + Unknown + + diff --git a/lib/doc/lfun/lib/body/eventWear b/lib/doc/lfun/lib/body/eventWear new file mode 100644 index 0000000..9d1d715 --- /dev/null +++ b/lib/doc/lfun/lib/body/eventWear @@ -0,0 +1,24 @@ +EVENTWEAR + +NAME + eventWear() + +SYNOPSIS + int eventWear(object ob, mixed limbs) + +DESCRIPTION + Mrks the limbs "limbs" as being protected by the armor "ob". object ob - the item being worn (or wielded). mixed limbs - string or array of limbs on which it is being worn (or wielded). Returns 1 if successful, 0 if failure. + +EXAMPLES + + +LOCATION + /lib/body + + +SEE ALSO + eventRemoveItem + +Author + Unknown + diff --git a/lib/doc/lfun/lib/bonus/GetBonusDuration b/lib/doc/lfun/lib/bonus/GetBonusDuration new file mode 100644 index 0000000..66d4a0e --- /dev/null +++ b/lib/doc/lfun/lib/bonus/GetBonusDuration @@ -0,0 +1,24 @@ +GETBONUSDURATION + +NAME + GetBonusDuration() + +SYNOPSIS + int GetBonusDuration() + +DESCRIPTION + Returns the number of heartbeats left before a bonus's effects wear off. + +EXAMPLES + + +LOCATION + /lib/bonus + + +SEE ALSO + GetPoints, GetSkills, GetStats + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/bonus/GetPoints b/lib/doc/lfun/lib/bonus/GetPoints new file mode 100644 index 0000000..989203e --- /dev/null +++ b/lib/doc/lfun/lib/bonus/GetPoints @@ -0,0 +1,25 @@ +GETPOINTS + +NAME + GetPoints() + +SYNOPSIS + mapping GetPoints() + +DESCRIPTION + Returs which vital points are affected by a potion or bonus, and by how much. + +EXAMPLES + + +LOCATION + /lib/bonus +/lib/potion + + +SEE ALSO + SetPoints, SetBonusDuration, GetBonusDuration + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/bonus/GetSkills b/lib/doc/lfun/lib/bonus/GetSkills new file mode 100644 index 0000000..dbaaa79 --- /dev/null +++ b/lib/doc/lfun/lib/bonus/GetSkills @@ -0,0 +1,27 @@ +GETSKILLS + +NAME + GetSkills() + +SYNOPSIS + LIB_SPELL, LIB_ABILITIES: string array GetSkills() ; LIB_POTION, LIB_BONUS: mapping GetSkills() + +DESCRIPTION + For LIB_ABILITIES this lfun returns the list of skill names possessed by the creature it's called in, such as "knife defense", etc. For LIB_SPELL this returns a list of the skills required to be able to cast the spell. For LIB_POTION and LIB_BONUS, this lfun works much like GetStats(), in that it returns a mapping of skills and how they are modified when a potion is drunk. + +EXAMPLES + + +LOCATION + /lib/bonus +/lib/lvs/abilities +/lib/potion +/lib/spell + + +SEE ALSO + GetStats, SetSkill + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/bonus/GetStats b/lib/doc/lfun/lib/bonus/GetStats new file mode 100644 index 0000000..34a54b3 --- /dev/null +++ b/lib/doc/lfun/lib/bonus/GetStats @@ -0,0 +1,26 @@ +GETSTATS + +NAME + GetStats() + +SYNOPSIS + genetics: string array GetStats() , potion and bonus: mapping GetStats() + +DESCRIPTION + Called in a living thing, GetStats() returns an array of the creature's stat names, such as "strength", "wisdom", and the like. In the potion object, it returns a mapping of stats to modify when the potion is drunk. When the potion is drunk, this mapping is communicated to the bonus object that is moved into the drinker. + +EXAMPLES + + +LOCATION + /lib/bonus +/lib/genetics +/lib/potion + + +SEE ALSO + SetStats, GetStat, SetStat, GetStatLevel + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/bonus/RemoveBonuses b/lib/doc/lfun/lib/bonus/RemoveBonuses new file mode 100644 index 0000000..e5cb2f5 --- /dev/null +++ b/lib/doc/lfun/lib/bonus/RemoveBonuses @@ -0,0 +1,24 @@ +REMOVEBONUSES + +NAME + RemoveBonuses() + +SYNOPSIS + int RemoveBonuses() + +DESCRIPTION + Remove the effects of a bonus from a creature. + +EXAMPLES + + +LOCATION + /lib/bonus + + +SEE ALSO + SetBonuses + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/bonus/SetBonusDuration b/lib/doc/lfun/lib/bonus/SetBonusDuration new file mode 100644 index 0000000..8c83734 --- /dev/null +++ b/lib/doc/lfun/lib/bonus/SetBonusDuration @@ -0,0 +1,24 @@ +SETBONUSDURATION + +NAME + SetBonusDuration() + +SYNOPSIS + int SetBonusDuration(int i) + +DESCRIPTION + Specifies the number of heartbeats that should elapse before a bonus's effects wear off. + +EXAMPLES + SetBonusDuration(100) + +LOCATION + /lib/bonus + + +SEE ALSO + SetPoints, SetSkills, SetStats + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/bonus/SetBonuses b/lib/doc/lfun/lib/bonus/SetBonuses new file mode 100644 index 0000000..9140f0e --- /dev/null +++ b/lib/doc/lfun/lib/bonus/SetBonuses @@ -0,0 +1,25 @@ +SETBONUSES + +NAME + SetBonuses() + +SYNOPSIS + int SetBonuses() + +DESCRIPTION + A function internal to LIB_BONUS which cycles through the bonuses set on the object and applies them. + +EXAMPLES + + + +LOCATION + /lib/bonus + + +SEE ALSO + RemoveBonuses + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/bonus/SetPoints b/lib/doc/lfun/lib/bonus/SetPoints new file mode 100644 index 0000000..a4771a5 --- /dev/null +++ b/lib/doc/lfun/lib/bonus/SetPoints @@ -0,0 +1,25 @@ +SETPOINTS + +NAME + SetPoints() + +SYNOPSIS + mapping SetPoints(mapping arg) + +DESCRIPTION + In LIB_POTION and LIB_BONUS, this lfun specifies which vital points are affected, and by how much. + +EXAMPLES + SetPoints( ([ "HP" : 100, "SP" : 50 ]) ); + +LOCATION + /lib/bonus +/lib/potion + + +SEE ALSO + GetPoints, SetBonusDuration, GetBonusDuration + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/bonus/SetSkills b/lib/doc/lfun/lib/bonus/SetSkills new file mode 100644 index 0000000..2a3c39d --- /dev/null +++ b/lib/doc/lfun/lib/bonus/SetSkills @@ -0,0 +1,26 @@ +SETSKILLS + +NAME + SetSkills() + +SYNOPSIS + mapping SetSkills(mapping mp) + +DESCRIPTION + For LIB_SPELL this sets the required skills to be able to cast a spell, and the required level for each skill. For LIB_POTION and LIB_BONUS, this sets the skills altered by drinking the potion. + +EXAMPLES + SetSkills( ([ "cleverness" : 1 ]) ) + +LOCATION + /lib/bonus +/lib/potion +/lib/spell + + +SEE ALSO + GetSkills, SetStats, GetStats + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/bonus/SetStats b/lib/doc/lfun/lib/bonus/SetStats new file mode 100644 index 0000000..907c5a0 --- /dev/null +++ b/lib/doc/lfun/lib/bonus/SetStats @@ -0,0 +1,25 @@ +SETSTATS + +NAME + SetStats() + +SYNOPSIS + mapping SetStats(mapping arg) + +DESCRIPTION + Sets which stats are altered by a potion or bonus, and to what extent. + +EXAMPLES + SetStats( ([ "strength" : 30, "intelligence" : -30 ]) ) + +LOCATION + /lib/bonus +/lib/potion + + +SEE ALSO + GetStats, SetSkills, GetSkills + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/bonus/eventDestruct b/lib/doc/lfun/lib/bonus/eventDestruct new file mode 100644 index 0000000..9b89fb3 --- /dev/null +++ b/lib/doc/lfun/lib/bonus/eventDestruct @@ -0,0 +1,36 @@ +EVENTDESTRUCT + +NAME + eventDestruct() + +SYNOPSIS + int eventDestruct() + +DESCRIPTION + This lfun provides a convenient means to ensure proper things happen when an object is destructed. Rather than simply destruct(), you can use eventDestruct to, for example, move a thing to the furnace before it is actually removed from memory. Any invocation of eventDestruct() in a child object should probably make a scope reference to eventDestruct in its inheritance chain. + +EXAMPLES + int eventDestruct(){ write("Gbye!"); return ::eventDestruct(); } + +LOCATION + /lib/bonus +/lib/chat +/lib/interactive +/lib/meal +/lib/npc +/lib/props/clean +/lib/std/daemon +/secure/lib/connect +/secure/lib/file +/secure/lib/net/client +/secure/lib/net/ftp_client +/secure/lib/net/ftp_data_connection +/secure/lib/net/server + + +SEE ALSO + destruct (efun) + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/bot/GetLong b/lib/doc/lfun/lib/bot/GetLong new file mode 100644 index 0000000..097c124 --- /dev/null +++ b/lib/doc/lfun/lib/bot/GetLong @@ -0,0 +1,47 @@ +GETLONG + +NAME + GetLong() + + + +SYNOPSIS + string GetLong(string str) + + + +DESCRIPTION + Returns the "long desciption" of the object it's called in. This long description is the main part of what the player sees when they "look at" something. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/bot +/lib/creator +/lib/donate +/lib/door +/lib/fuel +/lib/interactive +/lib/lamp +/lib/npc +/lib/player +/lib/torch +/lib/events/look +/lib/std/room + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/bot/eventDie b/lib/doc/lfun/lib/bot/eventDie new file mode 100644 index 0000000..4e12cf7 --- /dev/null +++ b/lib/doc/lfun/lib/bot/eventDie @@ -0,0 +1,41 @@ +EVENTDIE + +NAME + eventDie() + + + +SYNOPSIS + varargs int eventDie(mixed agent) + + + +DESCRIPTION + When a creature dies, this function is called in them. The argument should be what it is that killed them. Note that this is a function that is heavily overridden, and must be handled with care if modified. If you don't know what a function override is, then don't mess with this function. If eventDie() returns something other than a positive integer, the creature doesn't die in the conventional sense: they instead become undead. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/bot +/lib/combat +/lib/flashlight +/lib/npc +/lib/player +/lib/race + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/burn/CanBurn b/lib/doc/lfun/lib/burn/CanBurn new file mode 100644 index 0000000..fa72a84 --- /dev/null +++ b/lib/doc/lfun/lib/burn/CanBurn @@ -0,0 +1,28 @@ +CANBURN + +NAME + CanBurn() + +SYNOPSIS + mixed CanExtinguish(object who) + +DESCRIPTION + Returns whether the item can burn, depending on its fuel requirement and amount of fuel. + + +EXAMPLES + + + +LOCATION + /lib/burn + + +SEE ALSO + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/burn/CanExtinguish b/lib/doc/lfun/lib/burn/CanExtinguish new file mode 100644 index 0000000..f8dd11f --- /dev/null +++ b/lib/doc/lfun/lib/burn/CanExtinguish @@ -0,0 +1,29 @@ +CANEXTINGUISH + +NAME + CanExtinguish() + + +SYNOPSIS + mixed CanExtinguish(object who) + + +DESCRIPTION + Returns whether the item can be doused, depending on physical location and fuel status. + + +EXAMPLES + + + +LOCATION + /lib/burn + + +SEE ALSO + CanBurn + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/burn/GetBurnRate b/lib/doc/lfun/lib/burn/GetBurnRate new file mode 100644 index 0000000..d74b1c5 --- /dev/null +++ b/lib/doc/lfun/lib/burn/GetBurnRate @@ -0,0 +1,33 @@ +GETBURNRATE + +NAME + GetBurnRate() + + +SYNOPSIS + int GetBurnRate() + + + +DESCRIPTION + Returns the rate at which a thing burns. + + + +EXAMPLES + + + + +LOCATION + /lib/burn +/lib/lamp + + +SEE ALSO + SetBurnRate + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/burn/GetBurning b/lib/doc/lfun/lib/burn/GetBurning new file mode 100644 index 0000000..2810e45 --- /dev/null +++ b/lib/doc/lfun/lib/burn/GetBurning @@ -0,0 +1,24 @@ +GETBURNING + +NAME + GetBurning() + +SYNOPSIS + int GetBurning() + +DESCRIPTION + Returns whether the item in question is undergoing combustion. + +EXAMPLES + + +LOCATION + /lib/burn + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/burn/GetBurntValue b/lib/doc/lfun/lib/burn/GetBurntValue new file mode 100644 index 0000000..c81d1e0 --- /dev/null +++ b/lib/doc/lfun/lib/burn/GetBurntValue @@ -0,0 +1,24 @@ +GETBURNTVALUE + +NAME + GetBurntValue() + +SYNOPSIS + int GetBurntValue() + +DESCRIPTION + Returns how much money the burnt thing is worth after being entirely consumed. + +EXAMPLES + + +LOCATION + /lib/burn + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/burn/GetFuelRequired b/lib/doc/lfun/lib/burn/GetFuelRequired new file mode 100644 index 0000000..e08397a --- /dev/null +++ b/lib/doc/lfun/lib/burn/GetFuelRequired @@ -0,0 +1,29 @@ +GETFUELREQUIRED + +NAME + GetFuelRequired() + + +SYNOPSIS + int GetFuelRequired() + + +DESCRIPTION + Returns 1 if a thing requires fuel to burn, 0 otherwise. + + +EXAMPLES + + + +LOCATION + /lib/burn + + +SEE ALSO + SetFuelRequired + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/burn/GetHeat b/lib/doc/lfun/lib/burn/GetHeat new file mode 100644 index 0000000..b701e1a --- /dev/null +++ b/lib/doc/lfun/lib/burn/GetHeat @@ -0,0 +1,24 @@ +GETHEAT + +NAME + GetHeat() + +SYNOPSIS + int GetHeat() + +DESCRIPTION + Returns the heat given off by the item. + +EXAMPLES + + +LOCATION + /lib/burn + + +SEE ALSO + SetHeat, GetMinHeat, SetMinHeat + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/burn/GetMinHeat b/lib/doc/lfun/lib/burn/GetMinHeat new file mode 100644 index 0000000..f5e9d40 --- /dev/null +++ b/lib/doc/lfun/lib/burn/GetMinHeat @@ -0,0 +1,24 @@ +GETMINHEAT + +NAME + GetMinHeat() + +SYNOPSIS + int GetMinHeat() + +DESCRIPTION + Returns the minimum amount of heat required for the item to give off light. + +EXAMPLES + + +LOCATION + /lib/burn + + +SEE ALSO + SetHeat, GetHeat, SetMinHeat + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/burn/SetBurnRate b/lib/doc/lfun/lib/burn/SetBurnRate new file mode 100644 index 0000000..b62ffe7 --- /dev/null +++ b/lib/doc/lfun/lib/burn/SetBurnRate @@ -0,0 +1,29 @@ +SETBURNRATE + +NAME + SetBurnRate() + + +SYNOPSIS + static int SetBurnRate(int x) + + +DESCRIPTION + Returns the rate at which a thing burns. A higher number is a slower burn. + +EXAMPLES + To consume one unit of fuel every 5 heart beats: SetBurnRate(5) + +LOCATION + /lib/burn +/lib/lamp + + +SEE ALSO + GetBurnRate + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/burn/SetFuelRequired b/lib/doc/lfun/lib/burn/SetFuelRequired new file mode 100644 index 0000000..a9e9692 --- /dev/null +++ b/lib/doc/lfun/lib/burn/SetFuelRequired @@ -0,0 +1,24 @@ +SETFUELREQUIRED + +NAME + SetFuelRequired() + +SYNOPSIS + static int SetFuelRequired(int x) + +DESCRIPTION + Sets whether a thing requires fuel in order to burn. + +EXAMPLES + + +LOCATION + /lib/burn + + +SEE ALSO + GetFuelRequired + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/burn/SetHeat b/lib/doc/lfun/lib/burn/SetHeat new file mode 100644 index 0000000..9af9d90 --- /dev/null +++ b/lib/doc/lfun/lib/burn/SetHeat @@ -0,0 +1,24 @@ +SETHEAT + +NAME + SetHeat() + +SYNOPSIS + static int SetHeat(int x) + +DESCRIPTION + Sets the heat given off by the item. + +EXAMPLES + + +LOCATION + /lib/burn + + +SEE ALSO + GetHeat, GetMinHeat, SetMinHeat + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/burn/SetMinHeat b/lib/doc/lfun/lib/burn/SetMinHeat new file mode 100644 index 0000000..e678c6a --- /dev/null +++ b/lib/doc/lfun/lib/burn/SetMinHeat @@ -0,0 +1,24 @@ +SETMINHEAT + +NAME + SetMinHeat() + +SYNOPSIS + static int SetMinHeat(int x) + +DESCRIPTION + Sets the minimum amount of heat required for the item to give off light. + +EXAMPLES + + +LOCATION + /lib/burn + + +SEE ALSO + GetHeat, SetHeat, GetMinHeat + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/burn/eventBurnOut b/lib/doc/lfun/lib/burn/eventBurnOut new file mode 100644 index 0000000..fa089ce --- /dev/null +++ b/lib/doc/lfun/lib/burn/eventBurnOut @@ -0,0 +1,24 @@ +EVENTBURNOUT + +NAME + eventBurnOut() + +SYNOPSIS + mixed eventBurnOut() + +DESCRIPTION + Initiates the events associated with the expiration of a burn source. + +EXAMPLES + + +LOCATION + /lib/burn + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/burn/eventExtinguish b/lib/doc/lfun/lib/burn/eventExtinguish new file mode 100644 index 0000000..77fcd06 --- /dev/null +++ b/lib/doc/lfun/lib/burn/eventExtinguish @@ -0,0 +1,31 @@ +EVENTEXTINGUISH + +NAME + eventExtinguish() + + +SYNOPSIS + mixed eventExtinguish() + + +DESCRIPTION + LIB_BURN: Calls eventDarken and stops heart_beat. LIB_FLASHLIGHT: Calls eventTurnOff(). + +EXAMPLES + + + + +LOCATION + /lib/burn +/lib/flashlight + + +SEE ALSO + eventLight + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/burn/eventLight b/lib/doc/lfun/lib/burn/eventLight new file mode 100644 index 0000000..4764a8d --- /dev/null +++ b/lib/doc/lfun/lib/burn/eventLight @@ -0,0 +1,37 @@ +EVENTLIGHT + +NAME + eventLight() + + + +SYNOPSIS + mixed eventLight(object who, object what) + + + +DESCRIPTION + LIB_BURN: Calls eventBurn to initiate combustion. LIB_LIGHT: Sets "Lit" to 1. LIB_FLASHLIGHT: calls eventTurnOn. LIB_LAMP: Begins the fuel burning process. + + +EXAMPLES + + + + +LOCATION + /lib/burn +/lib/flashlight +/lib/lamp +/lib/light + + +SEE ALSO + eventBurn + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/chapel/AddSacrificeType b/lib/doc/lfun/lib/chapel/AddSacrificeType new file mode 100644 index 0000000..ab6123e --- /dev/null +++ b/lib/doc/lfun/lib/chapel/AddSacrificeType @@ -0,0 +1,24 @@ +ADDSACRIFICETYPE + +NAME + AddSacrificeType() + +SYNOPSIS + int AddSacrificeType(int x) + +DESCRIPTION + Adds to the existing set of permitted sacrifices here. Unimplemented in Dead Souls 2.1. + +EXAMPLES + + +LOCATION + /lib/chapel + + +SEE ALSO + SetAllowSacrifice, GetAllowSacrifice, SetSacrificeType, AddSacrificeType, GetSacrificeType, eventSacrifice, CanSacrifice + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/chapel/CanMarry b/lib/doc/lfun/lib/chapel/CanMarry new file mode 100644 index 0000000..8eb27c3 --- /dev/null +++ b/lib/doc/lfun/lib/chapel/CanMarry @@ -0,0 +1,25 @@ +CANMARRY + +NAME + CanMarry() + +SYNOPSIS + mixed CanMarry(object who, object spouse1, object spouse2) + +DESCRIPTION + Ensures that the person officiating the marriage is an arch, and that the two prospective spouses are eligible to marry one another. + +EXAMPLES + + +LOCATION + /lib/chapel +/lib/interactive + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/chapel/CanSacrifice b/lib/doc/lfun/lib/chapel/CanSacrifice new file mode 100644 index 0000000..a9c0b3c --- /dev/null +++ b/lib/doc/lfun/lib/chapel/CanSacrifice @@ -0,0 +1,24 @@ +CANSACRIFICE + +NAME + CanSacrifice() + +SYNOPSIS + mixed CanSacrifice(object who, object what, string deus) + +DESCRIPTION + Checks the religion of "who" to determine if their religious affiliation permits their sacrifice here. + +EXAMPLES + + +LOCATION + /lib/chapel + + +SEE ALSO + SetAllowSacrifice, GetAllowSacrifice, SetSacrificeType, AddSacrificeType, GetSacrificeType, eventSacrifice, CanSacrifice + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/chapel/GetAllowSacrifice b/lib/doc/lfun/lib/chapel/GetAllowSacrifice new file mode 100644 index 0000000..8606fff --- /dev/null +++ b/lib/doc/lfun/lib/chapel/GetAllowSacrifice @@ -0,0 +1,24 @@ +GETALLOWSACRIFICE + +NAME + GetAllowSacrifice() + +SYNOPSIS + int GetAllowSacrifice() + +DESCRIPTION + Returns 1 if sacrifices are allowed here, 0 otherwise. + +EXAMPLES + + +LOCATION + /lib/chapel + + +SEE ALSO + SetAllowSacrifice, GetAllowSacrifice, SetSacrificeType, AddSacrificeType, GetSacrificeType, eventSacrifice, CanSacrifice + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/chapel/GetReligion b/lib/doc/lfun/lib/chapel/GetReligion new file mode 100644 index 0000000..a95d90e --- /dev/null +++ b/lib/doc/lfun/lib/chapel/GetReligion @@ -0,0 +1,25 @@ +GETRELIGION + +NAME + GetReligion() + +SYNOPSIS + string GetReligion(int flag) + +DESCRIPTION + Returns the religion of the object. + +EXAMPLES + + + +LOCATION + /lib/chapel +/lib/classes + +SEE ALSO + SetReligion + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/chapel/GetSacrificeType b/lib/doc/lfun/lib/chapel/GetSacrificeType new file mode 100644 index 0000000..d5e69d9 --- /dev/null +++ b/lib/doc/lfun/lib/chapel/GetSacrificeType @@ -0,0 +1,27 @@ +GETSACRIFICETYPE + +NAME + GetSacrificeType() + +SYNOPSIS + int GetSacrificeType() + +DESCRIPTION + Bit shifted return of sacrifice types permitted here. Unimplemented in Dead Souls 2.1. + +EXAMPLES + + + +LOCATION + /lib/chapel + + +SEE ALSO + SetAllowSacrifice, GetAllowSacrifice, SetSacrificeType, AddSacrificeType, GetSacrificeType, eventSacrifice, CanSacrifice + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/chapel/SetAllowSacrifice b/lib/doc/lfun/lib/chapel/SetAllowSacrifice new file mode 100644 index 0000000..4ca03fe --- /dev/null +++ b/lib/doc/lfun/lib/chapel/SetAllowSacrifice @@ -0,0 +1,24 @@ +SETALLOWSACRIFICE + +NAME + SetAllowSacrifice() + +SYNOPSIS + int SetAllowSacrifice(int x) + +DESCRIPTION + Returns whether sacrifices are allowed at all here. + +EXAMPLES + + +LOCATION + /lib/chapel + + +SEE ALSO + SetAllowSacrifice, GetAllowSacrifice, SetSacrificeType, AddSacrificeType, GetSacrificeType, eventSacrifice, CanSacrifice + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/chapel/SetReligion b/lib/doc/lfun/lib/chapel/SetReligion new file mode 100644 index 0000000..dd04a58 --- /dev/null +++ b/lib/doc/lfun/lib/chapel/SetReligion @@ -0,0 +1,24 @@ +SETRELIGION + +NAME + SetReligion() + +SYNOPSIS + string array SetReligion(string adj, string noun) + +DESCRIPTION + Sets the religion of the object. + +EXAMPLES + + +LOCATION + /lib/chapel +/lib/classes + +SEE ALSO + GetReligion + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/chapel/SetSacrificeType b/lib/doc/lfun/lib/chapel/SetSacrificeType new file mode 100644 index 0000000..9cc183f --- /dev/null +++ b/lib/doc/lfun/lib/chapel/SetSacrificeType @@ -0,0 +1,24 @@ +SETSACRIFICETYPE + +NAME + SetSacrificeType() + +SYNOPSIS + int SetSacrificeType(int x) + +DESCRIPTION + Set what kind of sacrifice is permitted here. Unimplemented in Dead Souls 2.1. + +EXAMPLES + + +LOCATION + /lib/chapel + + +SEE ALSO + SetAllowSacrifice, GetAllowSacrifice, SetSacrificeType, AddSacrificeType, GetSacrificeType, eventSacrifice, CanSacrifice + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/chapel/eventMarry b/lib/doc/lfun/lib/chapel/eventMarry new file mode 100644 index 0000000..8733a8a --- /dev/null +++ b/lib/doc/lfun/lib/chapel/eventMarry @@ -0,0 +1,25 @@ +EVENTMARRY + +NAME + eventMarry() + +SYNOPSIS + mixed eventMarry(object who, object spouse1, object spouse2) + +DESCRIPTION + Carries out the actions of the marriage process. + +EXAMPLES + + +LOCATION + /lib/chapel +/lib/interactive + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/chapel/eventSacrifice b/lib/doc/lfun/lib/chapel/eventSacrifice new file mode 100644 index 0000000..e445ce3 --- /dev/null +++ b/lib/doc/lfun/lib/chapel/eventSacrifice @@ -0,0 +1,24 @@ +EVENTSACRIFICE + +NAME + eventSacrifice() + +SYNOPSIS + mixed eventSacrifice(object who, object what, string deus) + +DESCRIPTION + Performs the sacrifice act. + +EXAMPLES + + +LOCATION + /lib/chapel + + +SEE ALSO + SetAllowSacrifice, GetAllowSacrifice, SetSacrificeType, AddSacrificeType, GetSacrificeType, eventSacrifice, CanSacrifice + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/chat/AddChannel b/lib/doc/lfun/lib/chat/AddChannel new file mode 100644 index 0000000..0e72e99 --- /dev/null +++ b/lib/doc/lfun/lib/chat/AddChannel @@ -0,0 +1,24 @@ +ADDCHANNEL + +NAME + AddChannel() + +SYNOPSIS + string array AddChannel(mixed val) + +DESCRIPTION + Adds a channel to the list of those accessible to the user. + +EXAMPLES + + +LOCATION + /lib/chat + + +SEE ALSO + AddChannel, RemoveChannel, GetChannels, returnChannels + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/chat/GetChannels b/lib/doc/lfun/lib/chat/GetChannels new file mode 100644 index 0000000..5267a99 --- /dev/null +++ b/lib/doc/lfun/lib/chat/GetChannels @@ -0,0 +1,24 @@ +GETCHANNELS + +NAME + GetChannels() + +SYNOPSIS + string array GetChannels() + +DESCRIPTION + Returns an array listing the names of the channels accessible to a user. + +EXAMPLES + + +LOCATION + /lib/chat + + +SEE ALSO + AddChannel, RemoveChannel, GetChannels, returnChannels + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/chat/GetNoChanColors b/lib/doc/lfun/lib/chat/GetNoChanColors new file mode 100644 index 0000000..30f78f8 --- /dev/null +++ b/lib/doc/lfun/lib/chat/GetNoChanColors @@ -0,0 +1,24 @@ +GETNOCHANCOLORS + +NAME + GetNoChanColors() + +SYNOPSIS + int GetNoChanColors() + +DESCRIPTION + Users can disable seeing colors in channel messages. This lfun determines whether they have done so. + +EXAMPLES + + +LOCATION + /lib/chat + + +SEE ALSO + SetNoChanColors + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/chat/GetRestrictedChannels b/lib/doc/lfun/lib/chat/GetRestrictedChannels new file mode 100644 index 0000000..cbdc984 --- /dev/null +++ b/lib/doc/lfun/lib/chat/GetRestrictedChannels @@ -0,0 +1,24 @@ +GETRESTRICTEDCHANNELS + +NAME + GetRestrictedChannels() + +SYNOPSIS + string array GetRestrictedChannels() + +DESCRIPTION + Returns an array of the names of the channels whose use is restricted to this user. + +EXAMPLES + + +LOCATION + /lib/chat + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/chat/RemoveChannel b/lib/doc/lfun/lib/chat/RemoveChannel new file mode 100644 index 0000000..b53dcbd --- /dev/null +++ b/lib/doc/lfun/lib/chat/RemoveChannel @@ -0,0 +1,24 @@ +REMOVECHANNEL + +NAME + RemoveChannel() + +SYNOPSIS + string array RemoveChannel(mixed val) + +DESCRIPTION + Deletes a channel from the list of channels accessible to the user. + +EXAMPLES + + +LOCATION + /lib/chat + + +SEE ALSO + AddChannel, RemoveChannel, GetChannels, returnChannels + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/chat/RestrictChannel b/lib/doc/lfun/lib/chat/RestrictChannel new file mode 100644 index 0000000..c0583f9 --- /dev/null +++ b/lib/doc/lfun/lib/chat/RestrictChannel @@ -0,0 +1,24 @@ +RESTRICTCHANNEL + +NAME + RestrictChannel() + +SYNOPSIS + string array RestrictChannel(mixed val) + +DESCRIPTION + Limit the availability of the given channel(s) to the user. + +EXAMPLES + + +LOCATION + /lib/chat + + +SEE ALSO + AddChannel, RemoveChannel, GetChannels, returnChannels + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/chat/SetNoChanColors b/lib/doc/lfun/lib/chat/SetNoChanColors new file mode 100644 index 0000000..5223d80 --- /dev/null +++ b/lib/doc/lfun/lib/chat/SetNoChanColors @@ -0,0 +1,24 @@ +SETNOCHANCOLORS + +NAME + SetNoChanColors() + +SYNOPSIS + int SetNoChanColors(int x) + +DESCRIPTION + Users can disable seeing colors in channel messages. This lfun sets that parameter in the player object. + +EXAMPLES + SetNoChanColors(1) + +LOCATION + /lib/chat + + +SEE ALSO + GetNoChanColors + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/chat/UnrestrictChannel b/lib/doc/lfun/lib/chat/UnrestrictChannel new file mode 100644 index 0000000..8b0f8dc --- /dev/null +++ b/lib/doc/lfun/lib/chat/UnrestrictChannel @@ -0,0 +1,24 @@ +UNRESTRICTCHANNEL + +NAME + UnrestrictChannel() + +SYNOPSIS + string array UnrestrictChannel(mixed val) + +DESCRIPTION + Removes the user's limitations on the channel(s) specified. + +EXAMPLES + + +LOCATION + /lib/chat + + +SEE ALSO + AddChannel, RemoveChannel, GetChannels, returnChannels + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/chat/chat_command b/lib/doc/lfun/lib/chat/chat_command new file mode 100644 index 0000000..d0dd2cd --- /dev/null +++ b/lib/doc/lfun/lib/chat/chat_command @@ -0,0 +1,24 @@ +CHAT_COMMAND + +NAME + chat_command() + +SYNOPSIS + static string chat_command(string str) + +DESCRIPTION + Intercepts all commands issued by the user and determines whether they are channel commands. If so, they are processed by the chat daemon. If not, they are allowed to continue on their merry way. + +EXAMPLES + + +LOCATION + /lib/chat + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/chat/eventDestruct b/lib/doc/lfun/lib/chat/eventDestruct new file mode 100644 index 0000000..9b89fb3 --- /dev/null +++ b/lib/doc/lfun/lib/chat/eventDestruct @@ -0,0 +1,36 @@ +EVENTDESTRUCT + +NAME + eventDestruct() + +SYNOPSIS + int eventDestruct() + +DESCRIPTION + This lfun provides a convenient means to ensure proper things happen when an object is destructed. Rather than simply destruct(), you can use eventDestruct to, for example, move a thing to the furnace before it is actually removed from memory. Any invocation of eventDestruct() in a child object should probably make a scope reference to eventDestruct in its inheritance chain. + +EXAMPLES + int eventDestruct(){ write("Gbye!"); return ::eventDestruct(); } + +LOCATION + /lib/bonus +/lib/chat +/lib/interactive +/lib/meal +/lib/npc +/lib/props/clean +/lib/std/daemon +/secure/lib/connect +/secure/lib/file +/secure/lib/net/client +/secure/lib/net/ftp_client +/secure/lib/net/ftp_data_connection +/secure/lib/net/server + + +SEE ALSO + destruct (efun) + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/chat/eventReconnect b/lib/doc/lfun/lib/chat/eventReconnect new file mode 100644 index 0000000..9046556 --- /dev/null +++ b/lib/doc/lfun/lib/chat/eventReconnect @@ -0,0 +1,40 @@ +EVENTRECONNECT + +NAME + eventReconnect() + + + +SYNOPSIS + void eventReconnect() + + + +DESCRIPTION + A series of events that need to occur when a user reconnects to the game after going link-dead. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/chat +/lib/creator +/lib/interactive +/lib/npc +/lib/player + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/chat/returnChannels b/lib/doc/lfun/lib/chat/returnChannels new file mode 100644 index 0000000..df9c413 --- /dev/null +++ b/lib/doc/lfun/lib/chat/returnChannels @@ -0,0 +1,28 @@ +RETURNCHANNELS + +NAME + returnChannels() + +SYNOPSIS + mapping returnChannels() + +DESCRIPTION + Returns a mapping containing the channels accessible to the user and their associated data. + +EXAMPLES + + + + +LOCATION + /lib/chat + + +SEE ALSO + AddChannel, RemoveChannel, GetChannels + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/clan/CanJoin b/lib/doc/lfun/lib/clan/CanJoin new file mode 100644 index 0000000..94d36ad --- /dev/null +++ b/lib/doc/lfun/lib/clan/CanJoin @@ -0,0 +1,23 @@ +CANJOIN + +NAME + CanJOin() + +SYNOPSIS + mixed CanJoin(object ob) + +DESCRIPTION + Returns 1 of the specified user object may join the clan, 0 otherwise. + +EXAMPLES + if(CanJoin(this_player())) write("Welcome to the Frombotzer Clan!"); + +LOCATION + /lib/clan + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clan/GetAffectLong b/lib/doc/lfun/lib/clan/GetAffectLong new file mode 100644 index 0000000..028c1fd --- /dev/null +++ b/lib/doc/lfun/lib/clan/GetAffectLong @@ -0,0 +1,23 @@ +GETAFFECTLONG +NAME + GetAffectLong() + +SYNOPSIS + string GetAffectLong(object ob) + +DESCRIPTION + Adds a descriptive string to a creature's long desc indicating some variable information. In the case of LIB_BODY, it indicates wakefulness or intoxication. For LIB_CLAN, clan membership is indicated. The argument is not used. + +EXAMPLES + + +LOCATION + /lib/body +/lib/clan + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clan/GetClanName b/lib/doc/lfun/lib/clan/GetClanName new file mode 100644 index 0000000..fbd5331 --- /dev/null +++ b/lib/doc/lfun/lib/clan/GetClanName @@ -0,0 +1,23 @@ +GETCLANNAME + +NAME + GetClanName() + +SYNOPSIS + string GetClanName() + +DESCRIPTION + Returns the nameof the clan the object belongs to. + +EXAMPLES + + +LOCATION + /lib/clan + +SEE ALSO + SetClanName + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clan/GetClanObject b/lib/doc/lfun/lib/clan/GetClanObject new file mode 100644 index 0000000..d80a221 --- /dev/null +++ b/lib/doc/lfun/lib/clan/GetClanObject @@ -0,0 +1,23 @@ +GETCLANOBJECT + +NAME + GetClanObject() + +SYNOPSIS + string GetClanObject() + +DESCRIPTION + Returns the unique id of the membership object of the clan the object belongs to. + +EXAMPLES + + +LOCATION + /lib/clan + +SEE ALSO + SetClanObject + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clan/GetClanSkill b/lib/doc/lfun/lib/clan/GetClanSkill new file mode 100644 index 0000000..26fb90d --- /dev/null +++ b/lib/doc/lfun/lib/clan/GetClanSkill @@ -0,0 +1,23 @@ +GETCLANSKILL + +NAME + GetClanSkill() + +SYNOPSIS + string GetClanSkill() + +DESCRIPTION + Returns the name of the skill that clan membership entitles one to. + +EXAMPLES + + +LOCATION + /lib/clan + +SEE ALSO + SetClanSkill + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clan/GetLeader b/lib/doc/lfun/lib/clan/GetLeader new file mode 100644 index 0000000..f9246f1 --- /dev/null +++ b/lib/doc/lfun/lib/clan/GetLeader @@ -0,0 +1,24 @@ +GETLEADER + +NAME + GetLeader() + +SYNOPSIS + LIB_FOLLOW: object GetLeader(), LIB_CLAN: string GetLeader() + +DESCRIPTION + Gets who the leader is in the given context. Note that LIB_FOLLOW uses the object datatype and LIB_CLAN uses string. + +EXAMPLES + + +LOCATION + /lib/clan +/lib/follow + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clan/SetClanName b/lib/doc/lfun/lib/clan/SetClanName new file mode 100644 index 0000000..192a476 --- /dev/null +++ b/lib/doc/lfun/lib/clan/SetClanName @@ -0,0 +1,23 @@ +SETCLANNAME + +NAME + SetClanName() + +SYNOPSIS + string SetClanName(string str) + +DESCRIPTION + Establishes the name of the clan that the clan object belongs to. + +EXAMPLES + SetClanName("Warriors") + +LOCATION + /lib/clan + +SEE ALSO + GetClanName + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clan/SetClanObject b/lib/doc/lfun/lib/clan/SetClanObject new file mode 100644 index 0000000..8258a2a --- /dev/null +++ b/lib/doc/lfun/lib/clan/SetClanObject @@ -0,0 +1,23 @@ +SETCLANOBJECT + +NAME + SetClanObject() + +SYNOPSIS + string SetClanObject(string str) + +DESCRIPTION + Establishes the unique id of the clan's "clan object", which confers membership. + +EXAMPLES + SetClanObject("snoo") + +LOCATION + /lib/clan + +SEE ALSO + GetClanObject + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clan/SetClanSkill b/lib/doc/lfun/lib/clan/SetClanSkill new file mode 100644 index 0000000..72821cf --- /dev/null +++ b/lib/doc/lfun/lib/clan/SetClanSkill @@ -0,0 +1,23 @@ +SETCLANSKILL + +NAME + SetClanSkill() + +SYNOPSIS + string SetClanSkill(string str) + +DESCRIPTION + Sets the name of the skill that clan membership entitles one to. + +EXAMPLES + + +LOCATION + /lib/clan + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clan/SetLeader b/lib/doc/lfun/lib/clan/SetLeader new file mode 100644 index 0000000..210b90a --- /dev/null +++ b/lib/doc/lfun/lib/clan/SetLeader @@ -0,0 +1,24 @@ +SETLEADER + +NAME + SetLeader() + +SYNOPSIS + LIB_CLAN: string SetLeader(string str)\nLIB_FOLLOW: object SetLeader(object leader) + +DESCRIPTION + Sets who the leader is in the given context. Note that LIB_FOLLOW uses the object datatype and LIB_CLAN uses string. + +EXAMPLES + + +LOCATION + /lib/clan +/lib/follow + +SEE ALSO + GetLeader + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clan/eventBring b/lib/doc/lfun/lib/clan/eventBring new file mode 100644 index 0000000..0257dcd --- /dev/null +++ b/lib/doc/lfun/lib/clan/eventBring @@ -0,0 +1,23 @@ +EVENTBRING + +NAME + eventBring() + +SYNOPSIS + int eventBring(string str) + +DESCRIPTION + A clan master is empowered to attempt to teleport a member to her location. This function performs the work for that event. + +EXAMPLES + eventBring("doofus") + +LOCATION + /lib/clan + +SEE ALSO + eventJoin, eventUnjoin, eventInitiate, eventRetire + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clan/eventInitiate b/lib/doc/lfun/lib/clan/eventInitiate new file mode 100644 index 0000000..03b7960 --- /dev/null +++ b/lib/doc/lfun/lib/clan/eventInitiate @@ -0,0 +1,23 @@ +EVENTINITIATE + +NAME + eventInitiate() + +SYNOPSIS + int eventInitiate(string str) + +DESCRIPTION + This is the first part of a two part "clan joining process". Once the new clan member has gone through the directives in this function, eventJoin() is called in this object to finalize the new membership. + +EXAMPLES + eventJoin, eventUnjoin, eventBring, eventRetire + +LOCATION + /lib/clan + +SEE ALSO + eventJoin, eventUnjoin, eventBring, eventRetire + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clan/eventJoin b/lib/doc/lfun/lib/clan/eventJoin new file mode 100644 index 0000000..22f008b --- /dev/null +++ b/lib/doc/lfun/lib/clan/eventJoin @@ -0,0 +1,24 @@ +EVENTJOIN + +NAME + eventJoin() + +SYNOPSIS + void eventJoin(object ob) + +DESCRIPTION + This is the second part of a two part "clan joining process". Once the new clan member has gone through the directives in eventInitiate(), this function is called in this object to finalize the new membership. + +EXAMPLES + + +LOCATION + /lib/clan +/lib/leader + +SEE ALSO + eventRetire, eventUnjoin, eventBring, eventInitiate + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clan/eventRetire b/lib/doc/lfun/lib/clan/eventRetire new file mode 100644 index 0000000..ca37f10 --- /dev/null +++ b/lib/doc/lfun/lib/clan/eventRetire @@ -0,0 +1,23 @@ +EVENTRETIRE + +NAME + eventRetire() + +SYNOPSIS + int eventRetire(string str) + +DESCRIPTION + This is the first part of a two part "clan expulsion process". Once the clan member has gone through the directives in this function, eventUnjoin() is called in this object to finalize the expulsion. + +EXAMPLES + eventRetire("deckard") + +LOCATION + /lib/clan + +SEE ALSO + eventJoin, eventUnjoin, eventBring, eventInitiate + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clan/eventUnjoin b/lib/doc/lfun/lib/clan/eventUnjoin new file mode 100644 index 0000000..e2055b5 --- /dev/null +++ b/lib/doc/lfun/lib/clan/eventUnjoin @@ -0,0 +1,23 @@ +EVENTUNJOIN + +NAME + eventUnjoin() + +SYNOPSIS + void eventUnjoin(object ob) + +DESCRIPTION + This is the second part of a two part "clan expulsion process". Once the clan member has gone through the directives in eventRetire(), this function is called in this object to finalize the expulsion. + +EXAMPLES + + +LOCATION + /lib/clan + +SEE ALSO + eventRetire, eventJoin, eventBring, eventInitiate + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clan/eventWelcome b/lib/doc/lfun/lib/clan/eventWelcome new file mode 100644 index 0000000..4bf2a7e --- /dev/null +++ b/lib/doc/lfun/lib/clan/eventWelcome @@ -0,0 +1,23 @@ +EVENTWELCOME + +NAME + eventWelcome() + +SYNOPSIS + void eventWelcome(object ob) + +DESCRIPTION + Provides a set of messages or events to occur indicating to the new clan member they are welcome. + +EXAMPLES + + +LOCATION + /lib/clan + +SEE ALSO + eventRetire, eventJoin, eventUnjoin, eventBring, eventInitiate + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/classes/AddSkillPoints b/lib/doc/lfun/lib/classes/AddSkillPoints new file mode 100644 index 0000000..4ef5fd7 --- /dev/null +++ b/lib/doc/lfun/lib/classes/AddSkillPoints @@ -0,0 +1,25 @@ +ADDSKILLPOINTS + +NAME + AddSkillPoints() + +SYNOPSIS + int AddSkillPoints(string skill, int x) + +DESCRIPTION + LIB_ABILITIES: adds "x" points to the total for skill "skill". if the points go over the max for the current skill level, then the level is raised 1, if the points go under 0, then the skill level is lowered. LIB_CLASSES: Applies the appropriate skill modifiers to the skill change before passing it on to LIB_ABILITIES. + +EXAMPLES + + +LOCATION + /lib/classes +/lib/lvs/abilities + +SEE ALSO + AddSkillPoints, SetSkillModifier, GetSkillModifier + + +Author + Unknown + diff --git a/lib/doc/lfun/lib/classes/ChangeClass b/lib/doc/lfun/lib/classes/ChangeClass new file mode 100644 index 0000000..8072bd4 --- /dev/null +++ b/lib/doc/lfun/lib/classes/ChangeClass @@ -0,0 +1,27 @@ +CHANGECLASS + +NAME + ChangeClass() + + +SYNOPSIS + string ChangeClass(string class_name) + + +DESCRIPTION + Changes a creature's class from its current one to the one specified by "class_name". + + +EXAMPLES + + + +LOCATION + /lib/classes + +SEE ALSO + SetClass + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/classes/ClassMember b/lib/doc/lfun/lib/classes/ClassMember new file mode 100644 index 0000000..94835c1 --- /dev/null +++ b/lib/doc/lfun/lib/classes/ClassMember @@ -0,0 +1,24 @@ +CLASSMEMBER + +NAME + ClassMember() + +SYNOPSIS + int ClassMember(string class_name) + +DESCRIPTION + Returns whether the class daemon thinks the player is a member of the specified class. + +EXAMPLES + + +LOCATION + /lib/classes + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/classes/GetBaseStatLevel b/lib/doc/lfun/lib/classes/GetBaseStatLevel new file mode 100644 index 0000000..6ed1fe2 --- /dev/null +++ b/lib/doc/lfun/lib/classes/GetBaseStatLevel @@ -0,0 +1,26 @@ +GETBASESTATLEVEL + +NAME + GetBaseStatLevel() + +SYNOPSIS + int GetBaseStatLevel(string stat) + +DESCRIPTION + Returns the unmodified stat level for stat "stat". For example, a player's GetStatLevel("coordination") will be lower than her GetBaseStatLevel("coordination") if she's drunk. + +EXAMPLES + + +LOCATION + /lib/classes +/lib/combat +/lib/genetics + + +SEE ALSO + GetStatLevel + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/classes/GetClan b/lib/doc/lfun/lib/classes/GetClan new file mode 100644 index 0000000..3a21a25 --- /dev/null +++ b/lib/doc/lfun/lib/classes/GetClan @@ -0,0 +1,23 @@ +GETCLAN + +NAME + GetClan() + +SYNOPSIS + string GetClan() + +DESCRIPTION + Returns what the player object has set as its clan. + +EXAMPLES + + +LOCATION + /lib/classes + +SEE ALSO + SetClan + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/classes/GetClass b/lib/doc/lfun/lib/classes/GetClass new file mode 100644 index 0000000..674a114 --- /dev/null +++ b/lib/doc/lfun/lib/classes/GetClass @@ -0,0 +1,28 @@ +GETCLASS + +NAME + GetClass() + +SYNOPSIS + string GetClass() + + +DESCRIPTION + Returns the creature's class. + + +EXAMPLES + + + +LOCATION + /lib/classes +/lib/props/damage + +SEE ALSO + SetClass, ChangeClass + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/classes/GetMorality b/lib/doc/lfun/lib/classes/GetMorality new file mode 100644 index 0000000..ae13485 --- /dev/null +++ b/lib/doc/lfun/lib/classes/GetMorality @@ -0,0 +1,24 @@ +GETMORALITY + +NAME + GetMorality() + +SYNOPSIS + int GetMorality() + +DESCRIPTION + Returns the morality of the object. + +EXAMPLES + + +LOCATION + /lib/classes +/lib/spell + +SEE ALSO + SetMorality + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/classes/GetMoralityDescription b/lib/doc/lfun/lib/classes/GetMoralityDescription new file mode 100644 index 0000000..652ae39 --- /dev/null +++ b/lib/doc/lfun/lib/classes/GetMoralityDescription @@ -0,0 +1,24 @@ +GETMORALITYDESCRIPTION + +NAME + GetMoralityDescription() + +SYNOPSIS + string GetMoralityDescription() + +DESCRIPTION + Returns the descriptive string associated with a player's morality, such as "neutral" + +EXAMPLES + + +LOCATION + /lib/classes + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/classes/GetReligion b/lib/doc/lfun/lib/classes/GetReligion new file mode 100644 index 0000000..a95d90e --- /dev/null +++ b/lib/doc/lfun/lib/classes/GetReligion @@ -0,0 +1,25 @@ +GETRELIGION + +NAME + GetReligion() + +SYNOPSIS + string GetReligion(int flag) + +DESCRIPTION + Returns the religion of the object. + +EXAMPLES + + + +LOCATION + /lib/chapel +/lib/classes + +SEE ALSO + SetReligion + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/classes/GetSkillModifier b/lib/doc/lfun/lib/classes/GetSkillModifier new file mode 100644 index 0000000..0c953ab --- /dev/null +++ b/lib/doc/lfun/lib/classes/GetSkillModifier @@ -0,0 +1,23 @@ +GETSKILLMODIFIER + +NAME + GetSkillModifier() + +SYNOPSIS + string GetSkillModifier(string skill) + +DESCRIPTION + Returns the stat (eg, strength, intelligence) that affects the advancement of the specified skill. + +EXAMPLES + + +LOCATION + /lib/classes + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/classes/SetClan b/lib/doc/lfun/lib/classes/SetClan new file mode 100644 index 0000000..9462b96 --- /dev/null +++ b/lib/doc/lfun/lib/classes/SetClan @@ -0,0 +1,23 @@ +SETCLAN + +NAME + SetClan() + +SYNOPSIS + string SetClan(string clan) + +DESCRIPTION + Sets which clan the player belongs to. This is saved in the player object. + +EXAMPLES + + +LOCATION + /lib/classes + +SEE ALSO + GetClan + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/classes/SetClass b/lib/doc/lfun/lib/classes/SetClass new file mode 100644 index 0000000..1b42558 --- /dev/null +++ b/lib/doc/lfun/lib/classes/SetClass @@ -0,0 +1,27 @@ +SETCLASS + +NAME + SetClass() + +SYNOPSIS + string SetClass(string class_name) + +DESCRIPTION + If the creature does not currently have a class, its class is set to the string specified. If the creature already has a class, that class name is returned. + +EXAMPLES + + +LOCATION + /lib/classes +/lib/npc +/lib/player +/lib/props/damage + + +SEE ALSO + ChangeClass + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/classes/SetMorality b/lib/doc/lfun/lib/classes/SetMorality new file mode 100644 index 0000000..14275ea --- /dev/null +++ b/lib/doc/lfun/lib/classes/SetMorality @@ -0,0 +1,24 @@ +SETMORALITY + +NAME + SetMorality() + +SYNOPSIS + int SetMorality(int x) + +DESCRIPTION + Sets the morality of the object. + +EXAMPLES + + +LOCATION + /lib/classes +/lib/spell + +SEE ALSO + GetMorality + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/classes/SetReligion b/lib/doc/lfun/lib/classes/SetReligion new file mode 100644 index 0000000..dd04a58 --- /dev/null +++ b/lib/doc/lfun/lib/classes/SetReligion @@ -0,0 +1,24 @@ +SETRELIGION + +NAME + SetReligion() + +SYNOPSIS + string array SetReligion(string adj, string noun) + +DESCRIPTION + Sets the religion of the object. + +EXAMPLES + + +LOCATION + /lib/chapel +/lib/classes + +SEE ALSO + GetReligion + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/classes/SetSkillModifier b/lib/doc/lfun/lib/classes/SetSkillModifier new file mode 100644 index 0000000..3b72080 --- /dev/null +++ b/lib/doc/lfun/lib/classes/SetSkillModifier @@ -0,0 +1,23 @@ +SETSKILLMODIFIER + +NAME + SetSkillModifier() + +SYNOPSIS + static string SetSkillModifier(string skill, string stat) + +DESCRIPTION + Establishes which of your stats (eg, strength, intelligence) affects the specified skill. + +EXAMPLES + + +LOCATION + /lib/classes + +SEE ALSO + GetSkillModifier + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/classes/eventMoralAct b/lib/doc/lfun/lib/classes/eventMoralAct new file mode 100644 index 0000000..8b65a9b --- /dev/null +++ b/lib/doc/lfun/lib/classes/eventMoralAct @@ -0,0 +1,24 @@ +EVENTMORALACT + +NAME + eventMoralAct() + +SYNOPSIS + int eventMoralAct(int degree) + +DESCRIPTION + Adds the integer "degree" to the creature's morality. + +EXAMPLES + Killing a smurf might do this: gargamel->eventMoralAct(-50) + +LOCATION + /lib/classes + + +SEE ALSO + SetMorality, GetMorality, GetMoralityDescription + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clay/InitComposition b/lib/doc/lfun/lib/clay/InitComposition new file mode 100644 index 0000000..c9d24f9 --- /dev/null +++ b/lib/doc/lfun/lib/clay/InitComposition @@ -0,0 +1,23 @@ +INITCOMPOSITION + +NAME + InitComposition() + +SYNOPSIS + void InitComposition() + +DESCRIPTION + This is a function internal to LIB_CLAY which is called in create() to initialize its values. + +EXAMPLES + + +LOCATION + /lib/clay + +SEE ALSO + SetComposition + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clay/SetComposition b/lib/doc/lfun/lib/clay/SetComposition new file mode 100644 index 0000000..2062575 --- /dev/null +++ b/lib/doc/lfun/lib/clay/SetComposition @@ -0,0 +1,23 @@ +SETCOMPOSITION + +NAME + SetComposition() + +SYNOPSIS + varargs string SetComposition(string comp, string name, string *nouns, string *adjs, string short, string desc) + +DESCRIPTION + LIB_CLAY is an object that provides a flexible means for creating "chunks" of things, such as a chunk of clay when a clay golem has an arm amputated. A new chunk, inheriting LIB_CLAY, uses SetComposition to establish what kind of thing it is. + +EXAMPLES + ob = new(LIB_CLAY); ob->SetComposition(this_object()->GetBodyComposition(), "hunk", ({"chunk","hunk","piece"}), ({"plastic"}), "a plastic chunk","This is a piece of plastic.") + +LOCATION + /lib/clay + +SEE ALSO + InitComposition + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clean/eventDestruct b/lib/doc/lfun/lib/clean/eventDestruct new file mode 100644 index 0000000..9b89fb3 --- /dev/null +++ b/lib/doc/lfun/lib/clean/eventDestruct @@ -0,0 +1,36 @@ +EVENTDESTRUCT + +NAME + eventDestruct() + +SYNOPSIS + int eventDestruct() + +DESCRIPTION + This lfun provides a convenient means to ensure proper things happen when an object is destructed. Rather than simply destruct(), you can use eventDestruct to, for example, move a thing to the furnace before it is actually removed from memory. Any invocation of eventDestruct() in a child object should probably make a scope reference to eventDestruct in its inheritance chain. + +EXAMPLES + int eventDestruct(){ write("Gbye!"); return ::eventDestruct(); } + +LOCATION + /lib/bonus +/lib/chat +/lib/interactive +/lib/meal +/lib/npc +/lib/props/clean +/lib/std/daemon +/secure/lib/connect +/secure/lib/file +/secure/lib/net/client +/secure/lib/net/ftp_client +/secure/lib/net/ftp_data_connection +/secure/lib/net/server + + +SEE ALSO + destruct (efun) + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clerk/performMarriage b/lib/doc/lfun/lib/clerk/performMarriage new file mode 100644 index 0000000..12fe487 --- /dev/null +++ b/lib/doc/lfun/lib/clerk/performMarriage @@ -0,0 +1,23 @@ +PERFORMMARRIAGE + +NAME + performMarriage() + +SYNOPSIS + mixed performMarriage(object spouse1, object spouse2) + +DESCRIPTION + This function checks to ensure the location of the two betrotheds is suitable, then performs the actions that seal their lives in mortal bliss. + +EXAMPLES + + +LOCATION + /lib/clerk + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/client/eventDestruct b/lib/doc/lfun/lib/client/eventDestruct new file mode 100644 index 0000000..9b89fb3 --- /dev/null +++ b/lib/doc/lfun/lib/client/eventDestruct @@ -0,0 +1,36 @@ +EVENTDESTRUCT + +NAME + eventDestruct() + +SYNOPSIS + int eventDestruct() + +DESCRIPTION + This lfun provides a convenient means to ensure proper things happen when an object is destructed. Rather than simply destruct(), you can use eventDestruct to, for example, move a thing to the furnace before it is actually removed from memory. Any invocation of eventDestruct() in a child object should probably make a scope reference to eventDestruct in its inheritance chain. + +EXAMPLES + int eventDestruct(){ write("Gbye!"); return ::eventDestruct(); } + +LOCATION + /lib/bonus +/lib/chat +/lib/interactive +/lib/meal +/lib/npc +/lib/props/clean +/lib/std/daemon +/secure/lib/connect +/secure/lib/file +/secure/lib/net/client +/secure/lib/net/ftp_client +/secure/lib/net/ftp_data_connection +/secure/lib/net/server + + +SEE ALSO + destruct (efun) + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clip/CanReceive b/lib/doc/lfun/lib/clip/CanReceive new file mode 100644 index 0000000..3f3afe1 --- /dev/null +++ b/lib/doc/lfun/lib/clip/CanReceive @@ -0,0 +1,34 @@ +CANRECEIVE + +NAME + CanReceive() + +SYNOPSIS + int CanReceive(object ob) + +DESCRIPTION + Objects that can hold other objects use this function to determine whether the incoming objects 'ob' is allowed to enter. If it is allowed, this function should return 1. If it is not allowed, this function should return 0. + +EXAMPLES + + +LOCATION + /lib/flashlight +/lib/npc +/lib/post_office +/lib/firearm +/lib/comp/container +/lib/player +/lib/std/corpse +/lib/comp/holder +/lib/std/limb +/lib/clip +/lib/std/furnace +/lib/std/room + +SEE ALSO + CanRelease + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clip/CanRelease b/lib/doc/lfun/lib/clip/CanRelease new file mode 100644 index 0000000..50232d4 --- /dev/null +++ b/lib/doc/lfun/lib/clip/CanRelease @@ -0,0 +1,26 @@ +CANRELEASE + +NAME + CanRelease() + +SYNOPSIS + int CanRelease(object ob) + +DESCRIPTION + Objects that can hold other objects use this function to determine whether the outgoing object 'ob' is allowed to leave. If it is allowed, this function should return 1. If it is not allowed, this function should return 0. + +EXAMPLES + + +LOCATION + /lib/fishing +/lib/firearm +/lib/comp/container +/lib/clip + +SEE ALSO + CanReceive() + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clip/GetAmmoType b/lib/doc/lfun/lib/clip/GetAmmoType new file mode 100644 index 0000000..2b167ef --- /dev/null +++ b/lib/doc/lfun/lib/clip/GetAmmoType @@ -0,0 +1,26 @@ +GETAMMOTYPE + +NAME + GetAmmoType() + +SYNOPSIS + string GetAmmoType() + +DESCRIPTION + If the ammunition type is set on a clip or a round, they must match in order to be compatible. This function returns the string defined for that information. + +EXAMPLES + + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + SetAmmoType, GetFirearmType, SetFirearmType + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clip/GetCaliber b/lib/doc/lfun/lib/clip/GetCaliber new file mode 100644 index 0000000..3481b93 --- /dev/null +++ b/lib/doc/lfun/lib/clip/GetCaliber @@ -0,0 +1,26 @@ +GETCALIBER + +NAME + GetCaliber() + +SYNOPSIS + int GetCaliber() + +DESCRIPTION + Caliber is a measurement of ammunition size, different from millimeters. This function returns that information for the given object, if it is set. + +EXAMPLES + + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + SetCaliber, SetMillimeter, GetMillimeter + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clip/GetFirearmType b/lib/doc/lfun/lib/clip/GetFirearmType new file mode 100644 index 0000000..159f673 --- /dev/null +++ b/lib/doc/lfun/lib/clip/GetFirearmType @@ -0,0 +1,26 @@ +GETFIREARMTYPE + +NAME + GetFirearmType() + +SYNOPSIS + string GetFirearmType() + +DESCRIPTION + If the firearm type is set on a clip or a round, they must match in order to be compatible. This function returns the string defined for that information. + +EXAMPLES + + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetAmmoType, SetAmmoType, SetFirearmType + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clip/GetMillimeter b/lib/doc/lfun/lib/clip/GetMillimeter new file mode 100644 index 0000000..5f54d8b --- /dev/null +++ b/lib/doc/lfun/lib/clip/GetMillimeter @@ -0,0 +1,26 @@ +GETMILLIMETER + +NAME + GetMillimeter() + +SYNOPSIS + int GetMillimeter() + +DESCRIPTION + Millimeter is a measurement of ammunition size, different from caliber. This function returns that information for the given object, if it is set. + +EXAMPLES + . + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetCaliber, SetCaliber, SetMillimeter + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clip/SetAmmoType b/lib/doc/lfun/lib/clip/SetAmmoType new file mode 100644 index 0000000..a0ab48c --- /dev/null +++ b/lib/doc/lfun/lib/clip/SetAmmoType @@ -0,0 +1,26 @@ +SETAMMOTYPE + +NAME + SetAmmoType() + +SYNOPSIS + int SetAmmoType(string str) + +DESCRIPTION + If the ammunition type is set on a clip or a round, they must match in order to be compatible. This function defines the string for that information. + +EXAMPLES + SetAmmoType("acp") + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetAmmoType, GetFirearmType, SetFirearmType + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clip/SetCaliber b/lib/doc/lfun/lib/clip/SetCaliber new file mode 100644 index 0000000..eacc5f5 --- /dev/null +++ b/lib/doc/lfun/lib/clip/SetCaliber @@ -0,0 +1,26 @@ +SETCALIBER + +NAME + SetCaliber() + +SYNOPSIS + int SetCaliber(int x) + +DESCRIPTION + Caliber is a measurement of ammunition size, different from millimeters. If this is set on a round or a firearm, then the round and firearm must match calibers in order to be compatible. + +EXAMPLES + SetCaliber(357) + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetCaliber, SetMillimeter, GetMillimeter + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clip/SetFirearmType b/lib/doc/lfun/lib/clip/SetFirearmType new file mode 100644 index 0000000..dc58dc7 --- /dev/null +++ b/lib/doc/lfun/lib/clip/SetFirearmType @@ -0,0 +1,26 @@ +SETFIREARMTYPE + +NAME + SetFirearmType() + +SYNOPSIS + int SetFirearmType(string str) + +DESCRIPTION + If the firearm type is set on a clip or a round, they must match in order to be compatible. This function defines the string for that information. + +EXAMPLES + SetFirearmType("auto") + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetAmmoType, SetAmmoType, GetFirearmType + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clip/SetMillimeter b/lib/doc/lfun/lib/clip/SetMillimeter new file mode 100644 index 0000000..9b33f96 --- /dev/null +++ b/lib/doc/lfun/lib/clip/SetMillimeter @@ -0,0 +1,26 @@ +SETMILLIMETER + +NAME + SetMillimeter() + +SYNOPSIS + int SetMillimeter(int x) + +DESCRIPTION + Millimeter is a measurement of ammunition size, different from caliber. If this is set on a round or a firearm, then the round and firearm must match millimeter definition in order to be compatible. + +EXAMPLES + SetMillimeter(9) + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetCaliber, SetCaliber, GetMillimeter + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clip/eventLoad b/lib/doc/lfun/lib/clip/eventLoad new file mode 100644 index 0000000..dd822da --- /dev/null +++ b/lib/doc/lfun/lib/clip/eventLoad @@ -0,0 +1,26 @@ +EVENTLOAD + +NAME + eventLoad() + +SYNOPSIS + LIB_CLIP and LIB_ROUND: varargs mixed eventLoad(object who, object where) , LIB_FIREARM: mixed eventLoad(object ob) + +DESCRIPTION + For LIB_CLIP and LIB_ROUND, this function performs the work of moving the object into the destination 'where'. For LIB_FIREARM, this function is called when a round is being loaded directly into a revolver. + +EXAMPLES + + +LOCATION + /lib/round +/lib/events/load +/lib/firearm +/lib/clip + +SEE ALSO + eventUnload + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/clip/eventUnload b/lib/doc/lfun/lib/clip/eventUnload new file mode 100644 index 0000000..7476126 --- /dev/null +++ b/lib/doc/lfun/lib/clip/eventUnload @@ -0,0 +1,26 @@ +EVENTUNLOAD + +NAME + eventUnload() + +SYNOPSIS + mixed eventUnload(mixed what) + +DESCRIPTION + Provides for unloading. If the argument is a nonzero integer, it is presumed that the object is a LIB_CLIP or LIB_FIREARM and a number of objects are being unloaded from it. In the case of unloading a LIB_ROUND or a LIB_CLIP from something, then the argument would be the object that contains it. + +EXAMPLES + + +LOCATION + /lib/round +/lib/events/load +/lib/firearm +/lib/clip + +SEE ALSO + eventLoad + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/combat/GetBaseStatLevel b/lib/doc/lfun/lib/combat/GetBaseStatLevel new file mode 100644 index 0000000..6ed1fe2 --- /dev/null +++ b/lib/doc/lfun/lib/combat/GetBaseStatLevel @@ -0,0 +1,26 @@ +GETBASESTATLEVEL + +NAME + GetBaseStatLevel() + +SYNOPSIS + int GetBaseStatLevel(string stat) + +DESCRIPTION + Returns the unmodified stat level for stat "stat". For example, a player's GetStatLevel("coordination") will be lower than her GetBaseStatLevel("coordination") if she's drunk. + +EXAMPLES + + +LOCATION + /lib/classes +/lib/combat +/lib/genetics + + +SEE ALSO + GetStatLevel + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/combat/GetMaxHealthPoints b/lib/doc/lfun/lib/combat/GetMaxHealthPoints new file mode 100644 index 0000000..ee454cb --- /dev/null +++ b/lib/doc/lfun/lib/combat/GetMaxHealthPoints @@ -0,0 +1,39 @@ +GETMAXHEALTHPOINTS + +NAME + GetMaxHealthPoints() + + + +SYNOPSIS + varargs int GetMaxHealthPoints(string limb) + + + +DESCRIPTION + Returns a creature's maximum health level. Their normal healing process will not increase their health beyond this point. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/combat +/lib/living +/lib/npc +/lib/race + + +SEE ALSO + SetMaxHealthPoints, SetHealthPoints, GetHealthPoints + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/combat/eventDie b/lib/doc/lfun/lib/combat/eventDie new file mode 100644 index 0000000..4e12cf7 --- /dev/null +++ b/lib/doc/lfun/lib/combat/eventDie @@ -0,0 +1,41 @@ +EVENTDIE + +NAME + eventDie() + + + +SYNOPSIS + varargs int eventDie(mixed agent) + + + +DESCRIPTION + When a creature dies, this function is called in them. The argument should be what it is that killed them. Note that this is a function that is heavily overridden, and must be handled with care if modified. If you don't know what a function override is, then don't mess with this function. If eventDie() returns something other than a positive integer, the creature doesn't die in the conventional sense: they instead become undead. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/bot +/lib/combat +/lib/flashlight +/lib/npc +/lib/player +/lib/race + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/combat/eventReceiveDamage b/lib/doc/lfun/lib/combat/eventReceiveDamage new file mode 100644 index 0000000..b72a68f --- /dev/null +++ b/lib/doc/lfun/lib/combat/eventReceiveDamage @@ -0,0 +1,39 @@ +EVENTRECEIVEDAMAGE + +NAME + eventReceiveDamage() + + + +SYNOPSIS + varargs int eventReceiveDamage(object agent, int type, int x, int internal, mixed limbs) + + + +DESCRIPTION + What sometimes happens to good people. + + + +EXAMPLES + orc->eventReceiveDamage(this_player(), BLADE, 100, 0, ({ "head", "neck" }) ) + + + +LOCATION + /lib/body +/lib/combat +/lib/props/deterioration +/lib/std/armor +/lib/std/worn_storage + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/connect/GetCapName b/lib/doc/lfun/lib/connect/GetCapName new file mode 100644 index 0000000..7cb66e2 --- /dev/null +++ b/lib/doc/lfun/lib/connect/GetCapName @@ -0,0 +1,39 @@ +GETCAPNAME + +NAME + GetCapName() + + + +SYNOPSIS + string GetCapName() + + + +DESCRIPTION + Returns a thing's capitalized name. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/npc +/lib/player +/lib/props/id +/secure/lib/connect + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/connect/eventDestruct b/lib/doc/lfun/lib/connect/eventDestruct new file mode 100644 index 0000000..9b89fb3 --- /dev/null +++ b/lib/doc/lfun/lib/connect/eventDestruct @@ -0,0 +1,36 @@ +EVENTDESTRUCT + +NAME + eventDestruct() + +SYNOPSIS + int eventDestruct() + +DESCRIPTION + This lfun provides a convenient means to ensure proper things happen when an object is destructed. Rather than simply destruct(), you can use eventDestruct to, for example, move a thing to the furnace before it is actually removed from memory. Any invocation of eventDestruct() in a child object should probably make a scope reference to eventDestruct in its inheritance chain. + +EXAMPLES + int eventDestruct(){ write("Gbye!"); return ::eventDestruct(); } + +LOCATION + /lib/bonus +/lib/chat +/lib/interactive +/lib/meal +/lib/npc +/lib/props/clean +/lib/std/daemon +/secure/lib/connect +/secure/lib/file +/secure/lib/net/client +/secure/lib/net/ftp_client +/secure/lib/net/ftp_data_connection +/secure/lib/net/server + + +SEE ALSO + destruct (efun) + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/container/CanReceive b/lib/doc/lfun/lib/container/CanReceive new file mode 100644 index 0000000..3f3afe1 --- /dev/null +++ b/lib/doc/lfun/lib/container/CanReceive @@ -0,0 +1,34 @@ +CANRECEIVE + +NAME + CanReceive() + +SYNOPSIS + int CanReceive(object ob) + +DESCRIPTION + Objects that can hold other objects use this function to determine whether the incoming objects 'ob' is allowed to enter. If it is allowed, this function should return 1. If it is not allowed, this function should return 0. + +EXAMPLES + + +LOCATION + /lib/flashlight +/lib/npc +/lib/post_office +/lib/firearm +/lib/comp/container +/lib/player +/lib/std/corpse +/lib/comp/holder +/lib/std/limb +/lib/clip +/lib/std/furnace +/lib/std/room + +SEE ALSO + CanRelease + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/container/CanRelease b/lib/doc/lfun/lib/container/CanRelease new file mode 100644 index 0000000..50232d4 --- /dev/null +++ b/lib/doc/lfun/lib/container/CanRelease @@ -0,0 +1,26 @@ +CANRELEASE + +NAME + CanRelease() + +SYNOPSIS + int CanRelease(object ob) + +DESCRIPTION + Objects that can hold other objects use this function to determine whether the outgoing object 'ob' is allowed to leave. If it is allowed, this function should return 1. If it is not allowed, this function should return 0. + +EXAMPLES + + +LOCATION + /lib/fishing +/lib/firearm +/lib/comp/container +/lib/clip + +SEE ALSO + CanReceive() + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/corpse/CanReceive b/lib/doc/lfun/lib/corpse/CanReceive new file mode 100644 index 0000000..3f3afe1 --- /dev/null +++ b/lib/doc/lfun/lib/corpse/CanReceive @@ -0,0 +1,34 @@ +CANRECEIVE + +NAME + CanReceive() + +SYNOPSIS + int CanReceive(object ob) + +DESCRIPTION + Objects that can hold other objects use this function to determine whether the incoming objects 'ob' is allowed to enter. If it is allowed, this function should return 1. If it is not allowed, this function should return 0. + +EXAMPLES + + +LOCATION + /lib/flashlight +/lib/npc +/lib/post_office +/lib/firearm +/lib/comp/container +/lib/player +/lib/std/corpse +/lib/comp/holder +/lib/std/limb +/lib/clip +/lib/std/furnace +/lib/std/room + +SEE ALSO + CanRelease + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/corpse/GetHealthShort b/lib/doc/lfun/lib/corpse/GetHealthShort new file mode 100644 index 0000000..2682db9 --- /dev/null +++ b/lib/doc/lfun/lib/corpse/GetHealthShort @@ -0,0 +1,36 @@ +GETHEALTHSHORT + +NAME + GetHealthShort() + + + +SYNOPSIS + string GetHealthShort() + + + +DESCRIPTION + Colorizes a creature's short description based on their health status. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/std/corpse + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/corpse/GetRace b/lib/doc/lfun/lib/corpse/GetRace new file mode 100644 index 0000000..e945d80 --- /dev/null +++ b/lib/doc/lfun/lib/corpse/GetRace @@ -0,0 +1,38 @@ +GETRACE + +NAME + GetRace() + + + +SYNOPSIS + string GetRace() + + + +DESCRIPTION + Returns the creature's race. + + + +EXAMPLES + present("Spock", environment(this_player()))->GetRace() + + + +LOCATION + /lib/body +/lib/race +/lib/std/corpse +/lib/std/limb + + +SEE ALSO + GetClass + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/creator/GetLong b/lib/doc/lfun/lib/creator/GetLong new file mode 100644 index 0000000..097c124 --- /dev/null +++ b/lib/doc/lfun/lib/creator/GetLong @@ -0,0 +1,47 @@ +GETLONG + +NAME + GetLong() + + + +SYNOPSIS + string GetLong(string str) + + + +DESCRIPTION + Returns the "long desciption" of the object it's called in. This long description is the main part of what the player sees when they "look at" something. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/bot +/lib/creator +/lib/donate +/lib/door +/lib/fuel +/lib/interactive +/lib/lamp +/lib/npc +/lib/player +/lib/torch +/lib/events/look +/lib/std/room + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/creator/GetName b/lib/doc/lfun/lib/creator/GetName new file mode 100644 index 0000000..9b9f25b --- /dev/null +++ b/lib/doc/lfun/lib/creator/GetName @@ -0,0 +1,41 @@ +GETNAME + +NAME + GetName() + + + +SYNOPSIS + string GetName() + + + +DESCRIPTION + Returns the object's proper name, capitalized if appropriate. + + + +EXAMPLES + this_player()->GetName() + + + +LOCATION + /lib/body +/lib/creator +/lib/interactive +/lib/messages +/lib/npc +/lib/player +/lib/props/id + + +SEE ALSO + GetKeyName() + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/creator/eventReconnect b/lib/doc/lfun/lib/creator/eventReconnect new file mode 100644 index 0000000..9046556 --- /dev/null +++ b/lib/doc/lfun/lib/creator/eventReconnect @@ -0,0 +1,40 @@ +EVENTRECONNECT + +NAME + eventReconnect() + + + +SYNOPSIS + void eventReconnect() + + + +DESCRIPTION + A series of events that need to occur when a user reconnects to the game after going link-dead. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/chat +/lib/creator +/lib/interactive +/lib/npc +/lib/player + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/daemon/eventDestruct b/lib/doc/lfun/lib/daemon/eventDestruct new file mode 100644 index 0000000..9b89fb3 --- /dev/null +++ b/lib/doc/lfun/lib/daemon/eventDestruct @@ -0,0 +1,36 @@ +EVENTDESTRUCT + +NAME + eventDestruct() + +SYNOPSIS + int eventDestruct() + +DESCRIPTION + This lfun provides a convenient means to ensure proper things happen when an object is destructed. Rather than simply destruct(), you can use eventDestruct to, for example, move a thing to the furnace before it is actually removed from memory. Any invocation of eventDestruct() in a child object should probably make a scope reference to eventDestruct in its inheritance chain. + +EXAMPLES + int eventDestruct(){ write("Gbye!"); return ::eventDestruct(); } + +LOCATION + /lib/bonus +/lib/chat +/lib/interactive +/lib/meal +/lib/npc +/lib/props/clean +/lib/std/daemon +/secure/lib/connect +/secure/lib/file +/secure/lib/net/client +/secure/lib/net/ftp_client +/secure/lib/net/ftp_data_connection +/secure/lib/net/server + + +SEE ALSO + destruct (efun) + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/damage/GetClass b/lib/doc/lfun/lib/damage/GetClass new file mode 100644 index 0000000..674a114 --- /dev/null +++ b/lib/doc/lfun/lib/damage/GetClass @@ -0,0 +1,28 @@ +GETCLASS + +NAME + GetClass() + +SYNOPSIS + string GetClass() + + +DESCRIPTION + Returns the creature's class. + + +EXAMPLES + + + +LOCATION + /lib/classes +/lib/props/damage + +SEE ALSO + SetClass, ChangeClass + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/damage/SetClass b/lib/doc/lfun/lib/damage/SetClass new file mode 100644 index 0000000..1b42558 --- /dev/null +++ b/lib/doc/lfun/lib/damage/SetClass @@ -0,0 +1,27 @@ +SETCLASS + +NAME + SetClass() + +SYNOPSIS + string SetClass(string class_name) + +DESCRIPTION + If the creature does not currently have a class, its class is set to the string specified. If the creature already has a class, that class name is returned. + +EXAMPLES + + +LOCATION + /lib/classes +/lib/npc +/lib/player +/lib/props/damage + + +SEE ALSO + ChangeClass + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/deterioration/eventReceiveDamage b/lib/doc/lfun/lib/deterioration/eventReceiveDamage new file mode 100644 index 0000000..b72a68f --- /dev/null +++ b/lib/doc/lfun/lib/deterioration/eventReceiveDamage @@ -0,0 +1,39 @@ +EVENTRECEIVEDAMAGE + +NAME + eventReceiveDamage() + + + +SYNOPSIS + varargs int eventReceiveDamage(object agent, int type, int x, int internal, mixed limbs) + + + +DESCRIPTION + What sometimes happens to good people. + + + +EXAMPLES + orc->eventReceiveDamage(this_player(), BLADE, 100, 0, ({ "head", "neck" }) ) + + + +LOCATION + /lib/body +/lib/combat +/lib/props/deterioration +/lib/std/armor +/lib/std/worn_storage + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/donate/GetLong b/lib/doc/lfun/lib/donate/GetLong new file mode 100644 index 0000000..097c124 --- /dev/null +++ b/lib/doc/lfun/lib/donate/GetLong @@ -0,0 +1,47 @@ +GETLONG + +NAME + GetLong() + + + +SYNOPSIS + string GetLong(string str) + + + +DESCRIPTION + Returns the "long desciption" of the object it's called in. This long description is the main part of what the player sees when they "look at" something. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/bot +/lib/creator +/lib/donate +/lib/door +/lib/fuel +/lib/interactive +/lib/lamp +/lib/npc +/lib/player +/lib/torch +/lib/events/look +/lib/std/room + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/door/GetLong b/lib/doc/lfun/lib/door/GetLong new file mode 100644 index 0000000..097c124 --- /dev/null +++ b/lib/doc/lfun/lib/door/GetLong @@ -0,0 +1,47 @@ +GETLONG + +NAME + GetLong() + + + +SYNOPSIS + string GetLong(string str) + + + +DESCRIPTION + Returns the "long desciption" of the object it's called in. This long description is the main part of what the player sees when they "look at" something. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/bot +/lib/creator +/lib/donate +/lib/door +/lib/fuel +/lib/interactive +/lib/lamp +/lib/npc +/lib/player +/lib/torch +/lib/events/look +/lib/std/room + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/equip/GetWorn b/lib/doc/lfun/lib/equip/GetWorn new file mode 100644 index 0000000..e9ed7fa --- /dev/null +++ b/lib/doc/lfun/lib/equip/GetWorn @@ -0,0 +1,32 @@ +GETWORN + +NAME + GetWorn() + + + +SYNOPSIS + LIB_BODY: varargs object array GetWorn(string limb) LIB_EQUIP: string array GetWorn() + + +DESCRIPTION + LIB_BODY: Without an argument, returns an array of all worn and wielded objects in the creature's inventory. With a limb as an argument, returns an array of all worn and wielded objects on that limb. LIB_EQUIP: Returns a positive integer if the item is currently being worn, 0 otherwise. + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/props/equip + + +SEE ALSO + SetWorn, GetEquippedLimbs + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/file/eventDestruct b/lib/doc/lfun/lib/file/eventDestruct new file mode 100644 index 0000000..9b89fb3 --- /dev/null +++ b/lib/doc/lfun/lib/file/eventDestruct @@ -0,0 +1,36 @@ +EVENTDESTRUCT + +NAME + eventDestruct() + +SYNOPSIS + int eventDestruct() + +DESCRIPTION + This lfun provides a convenient means to ensure proper things happen when an object is destructed. Rather than simply destruct(), you can use eventDestruct to, for example, move a thing to the furnace before it is actually removed from memory. Any invocation of eventDestruct() in a child object should probably make a scope reference to eventDestruct in its inheritance chain. + +EXAMPLES + int eventDestruct(){ write("Gbye!"); return ::eventDestruct(); } + +LOCATION + /lib/bonus +/lib/chat +/lib/interactive +/lib/meal +/lib/npc +/lib/props/clean +/lib/std/daemon +/secure/lib/connect +/secure/lib/file +/secure/lib/net/client +/secure/lib/net/ftp_client +/secure/lib/net/ftp_data_connection +/secure/lib/net/server + + +SEE ALSO + destruct (efun) + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/firearm/CanReceive b/lib/doc/lfun/lib/firearm/CanReceive new file mode 100644 index 0000000..3f3afe1 --- /dev/null +++ b/lib/doc/lfun/lib/firearm/CanReceive @@ -0,0 +1,34 @@ +CANRECEIVE + +NAME + CanReceive() + +SYNOPSIS + int CanReceive(object ob) + +DESCRIPTION + Objects that can hold other objects use this function to determine whether the incoming objects 'ob' is allowed to enter. If it is allowed, this function should return 1. If it is not allowed, this function should return 0. + +EXAMPLES + + +LOCATION + /lib/flashlight +/lib/npc +/lib/post_office +/lib/firearm +/lib/comp/container +/lib/player +/lib/std/corpse +/lib/comp/holder +/lib/std/limb +/lib/clip +/lib/std/furnace +/lib/std/room + +SEE ALSO + CanRelease + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/firearm/CanRelease b/lib/doc/lfun/lib/firearm/CanRelease new file mode 100644 index 0000000..50232d4 --- /dev/null +++ b/lib/doc/lfun/lib/firearm/CanRelease @@ -0,0 +1,26 @@ +CANRELEASE + +NAME + CanRelease() + +SYNOPSIS + int CanRelease(object ob) + +DESCRIPTION + Objects that can hold other objects use this function to determine whether the outgoing object 'ob' is allowed to leave. If it is allowed, this function should return 1. If it is not allowed, this function should return 0. + +EXAMPLES + + +LOCATION + /lib/fishing +/lib/firearm +/lib/comp/container +/lib/clip + +SEE ALSO + CanReceive() + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/firearm/GetAmmoType b/lib/doc/lfun/lib/firearm/GetAmmoType new file mode 100644 index 0000000..2b167ef --- /dev/null +++ b/lib/doc/lfun/lib/firearm/GetAmmoType @@ -0,0 +1,26 @@ +GETAMMOTYPE + +NAME + GetAmmoType() + +SYNOPSIS + string GetAmmoType() + +DESCRIPTION + If the ammunition type is set on a clip or a round, they must match in order to be compatible. This function returns the string defined for that information. + +EXAMPLES + + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + SetAmmoType, GetFirearmType, SetFirearmType + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/firearm/GetCaliber b/lib/doc/lfun/lib/firearm/GetCaliber new file mode 100644 index 0000000..3481b93 --- /dev/null +++ b/lib/doc/lfun/lib/firearm/GetCaliber @@ -0,0 +1,26 @@ +GETCALIBER + +NAME + GetCaliber() + +SYNOPSIS + int GetCaliber() + +DESCRIPTION + Caliber is a measurement of ammunition size, different from millimeters. This function returns that information for the given object, if it is set. + +EXAMPLES + + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + SetCaliber, SetMillimeter, GetMillimeter + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/firearm/GetFirearmType b/lib/doc/lfun/lib/firearm/GetFirearmType new file mode 100644 index 0000000..159f673 --- /dev/null +++ b/lib/doc/lfun/lib/firearm/GetFirearmType @@ -0,0 +1,26 @@ +GETFIREARMTYPE + +NAME + GetFirearmType() + +SYNOPSIS + string GetFirearmType() + +DESCRIPTION + If the firearm type is set on a clip or a round, they must match in order to be compatible. This function returns the string defined for that information. + +EXAMPLES + + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetAmmoType, SetAmmoType, SetFirearmType + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/firearm/GetMillimeter b/lib/doc/lfun/lib/firearm/GetMillimeter new file mode 100644 index 0000000..5f54d8b --- /dev/null +++ b/lib/doc/lfun/lib/firearm/GetMillimeter @@ -0,0 +1,26 @@ +GETMILLIMETER + +NAME + GetMillimeter() + +SYNOPSIS + int GetMillimeter() + +DESCRIPTION + Millimeter is a measurement of ammunition size, different from caliber. This function returns that information for the given object, if it is set. + +EXAMPLES + . + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetCaliber, SetCaliber, SetMillimeter + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/firearm/SetAmmoType b/lib/doc/lfun/lib/firearm/SetAmmoType new file mode 100644 index 0000000..a0ab48c --- /dev/null +++ b/lib/doc/lfun/lib/firearm/SetAmmoType @@ -0,0 +1,26 @@ +SETAMMOTYPE + +NAME + SetAmmoType() + +SYNOPSIS + int SetAmmoType(string str) + +DESCRIPTION + If the ammunition type is set on a clip or a round, they must match in order to be compatible. This function defines the string for that information. + +EXAMPLES + SetAmmoType("acp") + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetAmmoType, GetFirearmType, SetFirearmType + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/firearm/SetCaliber b/lib/doc/lfun/lib/firearm/SetCaliber new file mode 100644 index 0000000..eacc5f5 --- /dev/null +++ b/lib/doc/lfun/lib/firearm/SetCaliber @@ -0,0 +1,26 @@ +SETCALIBER + +NAME + SetCaliber() + +SYNOPSIS + int SetCaliber(int x) + +DESCRIPTION + Caliber is a measurement of ammunition size, different from millimeters. If this is set on a round or a firearm, then the round and firearm must match calibers in order to be compatible. + +EXAMPLES + SetCaliber(357) + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetCaliber, SetMillimeter, GetMillimeter + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/firearm/SetFirearmType b/lib/doc/lfun/lib/firearm/SetFirearmType new file mode 100644 index 0000000..dc58dc7 --- /dev/null +++ b/lib/doc/lfun/lib/firearm/SetFirearmType @@ -0,0 +1,26 @@ +SETFIREARMTYPE + +NAME + SetFirearmType() + +SYNOPSIS + int SetFirearmType(string str) + +DESCRIPTION + If the firearm type is set on a clip or a round, they must match in order to be compatible. This function defines the string for that information. + +EXAMPLES + SetFirearmType("auto") + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetAmmoType, SetAmmoType, GetFirearmType + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/firearm/SetMillimeter b/lib/doc/lfun/lib/firearm/SetMillimeter new file mode 100644 index 0000000..9b33f96 --- /dev/null +++ b/lib/doc/lfun/lib/firearm/SetMillimeter @@ -0,0 +1,26 @@ +SETMILLIMETER + +NAME + SetMillimeter() + +SYNOPSIS + int SetMillimeter(int x) + +DESCRIPTION + Millimeter is a measurement of ammunition size, different from caliber. If this is set on a round or a firearm, then the round and firearm must match millimeter definition in order to be compatible. + +EXAMPLES + SetMillimeter(9) + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetCaliber, SetCaliber, GetMillimeter + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/firearm/eventLoad b/lib/doc/lfun/lib/firearm/eventLoad new file mode 100644 index 0000000..dd822da --- /dev/null +++ b/lib/doc/lfun/lib/firearm/eventLoad @@ -0,0 +1,26 @@ +EVENTLOAD + +NAME + eventLoad() + +SYNOPSIS + LIB_CLIP and LIB_ROUND: varargs mixed eventLoad(object who, object where) , LIB_FIREARM: mixed eventLoad(object ob) + +DESCRIPTION + For LIB_CLIP and LIB_ROUND, this function performs the work of moving the object into the destination 'where'. For LIB_FIREARM, this function is called when a round is being loaded directly into a revolver. + +EXAMPLES + + +LOCATION + /lib/round +/lib/events/load +/lib/firearm +/lib/clip + +SEE ALSO + eventUnload + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/firearm/eventUnload b/lib/doc/lfun/lib/firearm/eventUnload new file mode 100644 index 0000000..7476126 --- /dev/null +++ b/lib/doc/lfun/lib/firearm/eventUnload @@ -0,0 +1,26 @@ +EVENTUNLOAD + +NAME + eventUnload() + +SYNOPSIS + mixed eventUnload(mixed what) + +DESCRIPTION + Provides for unloading. If the argument is a nonzero integer, it is presumed that the object is a LIB_CLIP or LIB_FIREARM and a number of objects are being unloaded from it. In the case of unloading a LIB_ROUND or a LIB_CLIP from something, then the argument would be the object that contains it. + +EXAMPLES + + +LOCATION + /lib/round +/lib/events/load +/lib/firearm +/lib/clip + +SEE ALSO + eventLoad + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/fish/GetFood b/lib/doc/lfun/lib/fish/GetFood new file mode 100644 index 0000000..d49ec0b --- /dev/null +++ b/lib/doc/lfun/lib/fish/GetFood @@ -0,0 +1,36 @@ +GETFOOD + +NAME + GetFood() + + + +SYNOPSIS + LIB_BODY: int GetFood() LIB_FISH: string GetFood() + + + +DESCRIPTION + LIB_BODY: Returns the food level of the creature. LIB_FISH: Returns the path to the meal file that this fish uses. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/fish + + +SEE ALSO + SetFood, AddFood + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/fishing/CanRelease b/lib/doc/lfun/lib/fishing/CanRelease new file mode 100644 index 0000000..50232d4 --- /dev/null +++ b/lib/doc/lfun/lib/fishing/CanRelease @@ -0,0 +1,26 @@ +CANRELEASE + +NAME + CanRelease() + +SYNOPSIS + int CanRelease(object ob) + +DESCRIPTION + Objects that can hold other objects use this function to determine whether the outgoing object 'ob' is allowed to leave. If it is allowed, this function should return 1. If it is not allowed, this function should return 0. + +EXAMPLES + + +LOCATION + /lib/fishing +/lib/firearm +/lib/comp/container +/lib/clip + +SEE ALSO + CanReceive() + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/flashlight/CanReceive b/lib/doc/lfun/lib/flashlight/CanReceive new file mode 100644 index 0000000..3f3afe1 --- /dev/null +++ b/lib/doc/lfun/lib/flashlight/CanReceive @@ -0,0 +1,34 @@ +CANRECEIVE + +NAME + CanReceive() + +SYNOPSIS + int CanReceive(object ob) + +DESCRIPTION + Objects that can hold other objects use this function to determine whether the incoming objects 'ob' is allowed to enter. If it is allowed, this function should return 1. If it is not allowed, this function should return 0. + +EXAMPLES + + +LOCATION + /lib/flashlight +/lib/npc +/lib/post_office +/lib/firearm +/lib/comp/container +/lib/player +/lib/std/corpse +/lib/comp/holder +/lib/std/limb +/lib/clip +/lib/std/furnace +/lib/std/room + +SEE ALSO + CanRelease + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/flashlight/GetCellType b/lib/doc/lfun/lib/flashlight/GetCellType new file mode 100644 index 0000000..70c0f2d --- /dev/null +++ b/lib/doc/lfun/lib/flashlight/GetCellType @@ -0,0 +1,36 @@ +GETCELLTYPE + +NAME + GetCellType() + + + +SYNOPSIS + string GetCellType() + + + +DESCRIPTION + Returns a string indicating (for batteries) what kind of battery it is, or (for flashlights) what kind of batteries the device requires. + + + +EXAMPLES + + + + +LOCATION + /lib/battery +/lib/flashlight + + +SEE ALSO + SetCellType + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/flashlight/SetCellType b/lib/doc/lfun/lib/flashlight/SetCellType new file mode 100644 index 0000000..95649e7 --- /dev/null +++ b/lib/doc/lfun/lib/flashlight/SetCellType @@ -0,0 +1,36 @@ +SETCELLTYPE + +NAME + SetCellType() + + + +SYNOPSIS + int SetCellType(string str) + + + +DESCRIPTION + In LIB_BATTERY, sets the battery in question to the appropriate type, such as C, AA, etc.\nIn LIB_FLASHLIGHT, sets what kind of batteries it will accept. + + + +EXAMPLES + SetCellType("D") + + + +LOCATION + /lib/battery +/lib/flashlight + + +SEE ALSO + GetCellType + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/flashlight/SetDrainRate b/lib/doc/lfun/lib/flashlight/SetDrainRate new file mode 100644 index 0000000..dfa4460 --- /dev/null +++ b/lib/doc/lfun/lib/flashlight/SetDrainRate @@ -0,0 +1,36 @@ +SETDRAINRATE + +NAME + SetDrainRate() + + + +SYNOPSIS + int SetDrainRate(int i) + + + +DESCRIPTION + Sets how much of a battery's charge is drained per heartbeat of use. + + + +EXAMPLES + For a two-minute battery with a charge of 120 on a mud with a one-second heartbeat: SetDrainRate(1) + + + +LOCATION + /lib/battery +/lib/flashlight + + +SEE ALSO + GetDrainRate, SetCharge, GetCharge + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/flashlight/eventDie b/lib/doc/lfun/lib/flashlight/eventDie new file mode 100644 index 0000000..4e12cf7 --- /dev/null +++ b/lib/doc/lfun/lib/flashlight/eventDie @@ -0,0 +1,41 @@ +EVENTDIE + +NAME + eventDie() + + + +SYNOPSIS + varargs int eventDie(mixed agent) + + + +DESCRIPTION + When a creature dies, this function is called in them. The argument should be what it is that killed them. Note that this is a function that is heavily overridden, and must be handled with care if modified. If you don't know what a function override is, then don't mess with this function. If eventDie() returns something other than a positive integer, the creature doesn't die in the conventional sense: they instead become undead. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/bot +/lib/combat +/lib/flashlight +/lib/npc +/lib/player +/lib/race + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/flashlight/eventExtinguish b/lib/doc/lfun/lib/flashlight/eventExtinguish new file mode 100644 index 0000000..77fcd06 --- /dev/null +++ b/lib/doc/lfun/lib/flashlight/eventExtinguish @@ -0,0 +1,31 @@ +EVENTEXTINGUISH + +NAME + eventExtinguish() + + +SYNOPSIS + mixed eventExtinguish() + + +DESCRIPTION + LIB_BURN: Calls eventDarken and stops heart_beat. LIB_FLASHLIGHT: Calls eventTurnOff(). + +EXAMPLES + + + + +LOCATION + /lib/burn +/lib/flashlight + + +SEE ALSO + eventLight + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/flashlight/eventLight b/lib/doc/lfun/lib/flashlight/eventLight new file mode 100644 index 0000000..4764a8d --- /dev/null +++ b/lib/doc/lfun/lib/flashlight/eventLight @@ -0,0 +1,37 @@ +EVENTLIGHT + +NAME + eventLight() + + + +SYNOPSIS + mixed eventLight(object who, object what) + + + +DESCRIPTION + LIB_BURN: Calls eventBurn to initiate combustion. LIB_LIGHT: Sets "Lit" to 1. LIB_FLASHLIGHT: calls eventTurnOn. LIB_LAMP: Begins the fuel burning process. + + +EXAMPLES + + + + +LOCATION + /lib/burn +/lib/flashlight +/lib/lamp +/lib/light + + +SEE ALSO + eventBurn + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/flashlight/eventUse b/lib/doc/lfun/lib/flashlight/eventUse new file mode 100644 index 0000000..e2602fe --- /dev/null +++ b/lib/doc/lfun/lib/flashlight/eventUse @@ -0,0 +1,37 @@ +EVENTUSE + +NAME + eventUse() + + + +SYNOPSIS + LIB_BATTERY: int eventUse(int i), LIB_PLAYER: mixed eventUse(object used, string cmd) + + + +DESCRIPTION + For batteries, it runs necessary actions when the battery is used. For players, it runs the parser in a stripped way for testing. + + + +EXAMPLES + + + + +LOCATION + /lib/battery +/lib/flashlight +/lib/player + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/follow/GetLeader b/lib/doc/lfun/lib/follow/GetLeader new file mode 100644 index 0000000..f9246f1 --- /dev/null +++ b/lib/doc/lfun/lib/follow/GetLeader @@ -0,0 +1,24 @@ +GETLEADER + +NAME + GetLeader() + +SYNOPSIS + LIB_FOLLOW: object GetLeader(), LIB_CLAN: string GetLeader() + +DESCRIPTION + Gets who the leader is in the given context. Note that LIB_FOLLOW uses the object datatype and LIB_CLAN uses string. + +EXAMPLES + + +LOCATION + /lib/clan +/lib/follow + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/follow/SetLeader b/lib/doc/lfun/lib/follow/SetLeader new file mode 100644 index 0000000..210b90a --- /dev/null +++ b/lib/doc/lfun/lib/follow/SetLeader @@ -0,0 +1,24 @@ +SETLEADER + +NAME + SetLeader() + +SYNOPSIS + LIB_CLAN: string SetLeader(string str)\nLIB_FOLLOW: object SetLeader(object leader) + +DESCRIPTION + Sets who the leader is in the given context. Note that LIB_FOLLOW uses the object datatype and LIB_CLAN uses string. + +EXAMPLES + + +LOCATION + /lib/clan +/lib/follow + +SEE ALSO + GetLeader + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/ftp_client/eventDestruct b/lib/doc/lfun/lib/ftp_client/eventDestruct new file mode 100644 index 0000000..9b89fb3 --- /dev/null +++ b/lib/doc/lfun/lib/ftp_client/eventDestruct @@ -0,0 +1,36 @@ +EVENTDESTRUCT + +NAME + eventDestruct() + +SYNOPSIS + int eventDestruct() + +DESCRIPTION + This lfun provides a convenient means to ensure proper things happen when an object is destructed. Rather than simply destruct(), you can use eventDestruct to, for example, move a thing to the furnace before it is actually removed from memory. Any invocation of eventDestruct() in a child object should probably make a scope reference to eventDestruct in its inheritance chain. + +EXAMPLES + int eventDestruct(){ write("Gbye!"); return ::eventDestruct(); } + +LOCATION + /lib/bonus +/lib/chat +/lib/interactive +/lib/meal +/lib/npc +/lib/props/clean +/lib/std/daemon +/secure/lib/connect +/secure/lib/file +/secure/lib/net/client +/secure/lib/net/ftp_client +/secure/lib/net/ftp_data_connection +/secure/lib/net/server + + +SEE ALSO + destruct (efun) + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/ftp_data_connection/eventDestruct b/lib/doc/lfun/lib/ftp_data_connection/eventDestruct new file mode 100644 index 0000000..9b89fb3 --- /dev/null +++ b/lib/doc/lfun/lib/ftp_data_connection/eventDestruct @@ -0,0 +1,36 @@ +EVENTDESTRUCT + +NAME + eventDestruct() + +SYNOPSIS + int eventDestruct() + +DESCRIPTION + This lfun provides a convenient means to ensure proper things happen when an object is destructed. Rather than simply destruct(), you can use eventDestruct to, for example, move a thing to the furnace before it is actually removed from memory. Any invocation of eventDestruct() in a child object should probably make a scope reference to eventDestruct in its inheritance chain. + +EXAMPLES + int eventDestruct(){ write("Gbye!"); return ::eventDestruct(); } + +LOCATION + /lib/bonus +/lib/chat +/lib/interactive +/lib/meal +/lib/npc +/lib/props/clean +/lib/std/daemon +/secure/lib/connect +/secure/lib/file +/secure/lib/net/client +/secure/lib/net/ftp_client +/secure/lib/net/ftp_data_connection +/secure/lib/net/server + + +SEE ALSO + destruct (efun) + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/fuel/GetLong b/lib/doc/lfun/lib/fuel/GetLong new file mode 100644 index 0000000..097c124 --- /dev/null +++ b/lib/doc/lfun/lib/fuel/GetLong @@ -0,0 +1,47 @@ +GETLONG + +NAME + GetLong() + + + +SYNOPSIS + string GetLong(string str) + + + +DESCRIPTION + Returns the "long desciption" of the object it's called in. This long description is the main part of what the player sees when they "look at" something. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/bot +/lib/creator +/lib/donate +/lib/door +/lib/fuel +/lib/interactive +/lib/lamp +/lib/npc +/lib/player +/lib/torch +/lib/events/look +/lib/std/room + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/furnace/CanReceive b/lib/doc/lfun/lib/furnace/CanReceive new file mode 100644 index 0000000..3f3afe1 --- /dev/null +++ b/lib/doc/lfun/lib/furnace/CanReceive @@ -0,0 +1,34 @@ +CANRECEIVE + +NAME + CanReceive() + +SYNOPSIS + int CanReceive(object ob) + +DESCRIPTION + Objects that can hold other objects use this function to determine whether the incoming objects 'ob' is allowed to enter. If it is allowed, this function should return 1. If it is not allowed, this function should return 0. + +EXAMPLES + + +LOCATION + /lib/flashlight +/lib/npc +/lib/post_office +/lib/firearm +/lib/comp/container +/lib/player +/lib/std/corpse +/lib/comp/holder +/lib/std/limb +/lib/clip +/lib/std/furnace +/lib/std/room + +SEE ALSO + CanRelease + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/genetics/GetBaseStatLevel b/lib/doc/lfun/lib/genetics/GetBaseStatLevel new file mode 100644 index 0000000..6ed1fe2 --- /dev/null +++ b/lib/doc/lfun/lib/genetics/GetBaseStatLevel @@ -0,0 +1,26 @@ +GETBASESTATLEVEL + +NAME + GetBaseStatLevel() + +SYNOPSIS + int GetBaseStatLevel(string stat) + +DESCRIPTION + Returns the unmodified stat level for stat "stat". For example, a player's GetStatLevel("coordination") will be lower than her GetBaseStatLevel("coordination") if she's drunk. + +EXAMPLES + + +LOCATION + /lib/classes +/lib/combat +/lib/genetics + + +SEE ALSO + GetStatLevel + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/genetics/GetResistance b/lib/doc/lfun/lib/genetics/GetResistance new file mode 100644 index 0000000..1fbc0ce --- /dev/null +++ b/lib/doc/lfun/lib/genetics/GetResistance @@ -0,0 +1,32 @@ +GETRESISTANCE + +NAME + GetResistance() + + +SYNOPSIS + string GetResistance(int type) + + +DESCRIPTION + Returns the creature's resistance level to the given damage type. + + +EXAMPLES + this_player()->GetResistance(GAS) + + +LOCATION + /lib/body +/lib/genetics +/lib/race + + +SEE ALSO + damage_types.h + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/genetics/GetStats b/lib/doc/lfun/lib/genetics/GetStats new file mode 100644 index 0000000..34a54b3 --- /dev/null +++ b/lib/doc/lfun/lib/genetics/GetStats @@ -0,0 +1,26 @@ +GETSTATS + +NAME + GetStats() + +SYNOPSIS + genetics: string array GetStats() , potion and bonus: mapping GetStats() + +DESCRIPTION + Called in a living thing, GetStats() returns an array of the creature's stat names, such as "strength", "wisdom", and the like. In the potion object, it returns a mapping of stats to modify when the potion is drunk. When the potion is drunk, this mapping is communicated to the bonus object that is moved into the drinker. + +EXAMPLES + + +LOCATION + /lib/bonus +/lib/genetics +/lib/potion + + +SEE ALSO + SetStats, GetStat, SetStat, GetStatLevel + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/holder/CanReceive b/lib/doc/lfun/lib/holder/CanReceive new file mode 100644 index 0000000..3f3afe1 --- /dev/null +++ b/lib/doc/lfun/lib/holder/CanReceive @@ -0,0 +1,34 @@ +CANRECEIVE + +NAME + CanReceive() + +SYNOPSIS + int CanReceive(object ob) + +DESCRIPTION + Objects that can hold other objects use this function to determine whether the incoming objects 'ob' is allowed to enter. If it is allowed, this function should return 1. If it is not allowed, this function should return 0. + +EXAMPLES + + +LOCATION + /lib/flashlight +/lib/npc +/lib/post_office +/lib/firearm +/lib/comp/container +/lib/player +/lib/std/corpse +/lib/comp/holder +/lib/std/limb +/lib/clip +/lib/std/furnace +/lib/std/room + +SEE ALSO + CanRelease + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/id/GetCapName b/lib/doc/lfun/lib/id/GetCapName new file mode 100644 index 0000000..7cb66e2 --- /dev/null +++ b/lib/doc/lfun/lib/id/GetCapName @@ -0,0 +1,39 @@ +GETCAPNAME + +NAME + GetCapName() + + + +SYNOPSIS + string GetCapName() + + + +DESCRIPTION + Returns a thing's capitalized name. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/npc +/lib/player +/lib/props/id +/secure/lib/connect + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/id/GetName b/lib/doc/lfun/lib/id/GetName new file mode 100644 index 0000000..9b9f25b --- /dev/null +++ b/lib/doc/lfun/lib/id/GetName @@ -0,0 +1,41 @@ +GETNAME + +NAME + GetName() + + + +SYNOPSIS + string GetName() + + + +DESCRIPTION + Returns the object's proper name, capitalized if appropriate. + + + +EXAMPLES + this_player()->GetName() + + + +LOCATION + /lib/body +/lib/creator +/lib/interactive +/lib/messages +/lib/npc +/lib/player +/lib/props/id + + +SEE ALSO + GetKeyName() + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/interactive/CanMarry b/lib/doc/lfun/lib/interactive/CanMarry new file mode 100644 index 0000000..8eb27c3 --- /dev/null +++ b/lib/doc/lfun/lib/interactive/CanMarry @@ -0,0 +1,25 @@ +CANMARRY + +NAME + CanMarry() + +SYNOPSIS + mixed CanMarry(object who, object spouse1, object spouse2) + +DESCRIPTION + Ensures that the person officiating the marriage is an arch, and that the two prospective spouses are eligible to marry one another. + +EXAMPLES + + +LOCATION + /lib/chapel +/lib/interactive + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/interactive/GetLong b/lib/doc/lfun/lib/interactive/GetLong new file mode 100644 index 0000000..097c124 --- /dev/null +++ b/lib/doc/lfun/lib/interactive/GetLong @@ -0,0 +1,47 @@ +GETLONG + +NAME + GetLong() + + + +SYNOPSIS + string GetLong(string str) + + + +DESCRIPTION + Returns the "long desciption" of the object it's called in. This long description is the main part of what the player sees when they "look at" something. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/bot +/lib/creator +/lib/donate +/lib/door +/lib/fuel +/lib/interactive +/lib/lamp +/lib/npc +/lib/player +/lib/torch +/lib/events/look +/lib/std/room + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/interactive/GetName b/lib/doc/lfun/lib/interactive/GetName new file mode 100644 index 0000000..9b9f25b --- /dev/null +++ b/lib/doc/lfun/lib/interactive/GetName @@ -0,0 +1,41 @@ +GETNAME + +NAME + GetName() + + + +SYNOPSIS + string GetName() + + + +DESCRIPTION + Returns the object's proper name, capitalized if appropriate. + + + +EXAMPLES + this_player()->GetName() + + + +LOCATION + /lib/body +/lib/creator +/lib/interactive +/lib/messages +/lib/npc +/lib/player +/lib/props/id + + +SEE ALSO + GetKeyName() + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/interactive/eventDestruct b/lib/doc/lfun/lib/interactive/eventDestruct new file mode 100644 index 0000000..9b89fb3 --- /dev/null +++ b/lib/doc/lfun/lib/interactive/eventDestruct @@ -0,0 +1,36 @@ +EVENTDESTRUCT + +NAME + eventDestruct() + +SYNOPSIS + int eventDestruct() + +DESCRIPTION + This lfun provides a convenient means to ensure proper things happen when an object is destructed. Rather than simply destruct(), you can use eventDestruct to, for example, move a thing to the furnace before it is actually removed from memory. Any invocation of eventDestruct() in a child object should probably make a scope reference to eventDestruct in its inheritance chain. + +EXAMPLES + int eventDestruct(){ write("Gbye!"); return ::eventDestruct(); } + +LOCATION + /lib/bonus +/lib/chat +/lib/interactive +/lib/meal +/lib/npc +/lib/props/clean +/lib/std/daemon +/secure/lib/connect +/secure/lib/file +/secure/lib/net/client +/secure/lib/net/ftp_client +/secure/lib/net/ftp_data_connection +/secure/lib/net/server + + +SEE ALSO + destruct (efun) + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/interactive/eventMarry b/lib/doc/lfun/lib/interactive/eventMarry new file mode 100644 index 0000000..8733a8a --- /dev/null +++ b/lib/doc/lfun/lib/interactive/eventMarry @@ -0,0 +1,25 @@ +EVENTMARRY + +NAME + eventMarry() + +SYNOPSIS + mixed eventMarry(object who, object spouse1, object spouse2) + +DESCRIPTION + Carries out the actions of the marriage process. + +EXAMPLES + + +LOCATION + /lib/chapel +/lib/interactive + + +SEE ALSO + + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/interactive/eventReconnect b/lib/doc/lfun/lib/interactive/eventReconnect new file mode 100644 index 0000000..9046556 --- /dev/null +++ b/lib/doc/lfun/lib/interactive/eventReconnect @@ -0,0 +1,40 @@ +EVENTRECONNECT + +NAME + eventReconnect() + + + +SYNOPSIS + void eventReconnect() + + + +DESCRIPTION + A series of events that need to occur when a user reconnects to the game after going link-dead. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/chat +/lib/creator +/lib/interactive +/lib/npc +/lib/player + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/lamp/GetBurnRate b/lib/doc/lfun/lib/lamp/GetBurnRate new file mode 100644 index 0000000..d74b1c5 --- /dev/null +++ b/lib/doc/lfun/lib/lamp/GetBurnRate @@ -0,0 +1,33 @@ +GETBURNRATE + +NAME + GetBurnRate() + + +SYNOPSIS + int GetBurnRate() + + + +DESCRIPTION + Returns the rate at which a thing burns. + + + +EXAMPLES + + + + +LOCATION + /lib/burn +/lib/lamp + + +SEE ALSO + SetBurnRate + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/lamp/GetLong b/lib/doc/lfun/lib/lamp/GetLong new file mode 100644 index 0000000..097c124 --- /dev/null +++ b/lib/doc/lfun/lib/lamp/GetLong @@ -0,0 +1,47 @@ +GETLONG + +NAME + GetLong() + + + +SYNOPSIS + string GetLong(string str) + + + +DESCRIPTION + Returns the "long desciption" of the object it's called in. This long description is the main part of what the player sees when they "look at" something. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/bot +/lib/creator +/lib/donate +/lib/door +/lib/fuel +/lib/interactive +/lib/lamp +/lib/npc +/lib/player +/lib/torch +/lib/events/look +/lib/std/room + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/lamp/SetBurnRate b/lib/doc/lfun/lib/lamp/SetBurnRate new file mode 100644 index 0000000..b62ffe7 --- /dev/null +++ b/lib/doc/lfun/lib/lamp/SetBurnRate @@ -0,0 +1,29 @@ +SETBURNRATE + +NAME + SetBurnRate() + + +SYNOPSIS + static int SetBurnRate(int x) + + +DESCRIPTION + Returns the rate at which a thing burns. A higher number is a slower burn. + +EXAMPLES + To consume one unit of fuel every 5 heart beats: SetBurnRate(5) + +LOCATION + /lib/burn +/lib/lamp + + +SEE ALSO + GetBurnRate + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/lamp/eventLight b/lib/doc/lfun/lib/lamp/eventLight new file mode 100644 index 0000000..4764a8d --- /dev/null +++ b/lib/doc/lfun/lib/lamp/eventLight @@ -0,0 +1,37 @@ +EVENTLIGHT + +NAME + eventLight() + + + +SYNOPSIS + mixed eventLight(object who, object what) + + + +DESCRIPTION + LIB_BURN: Calls eventBurn to initiate combustion. LIB_LIGHT: Sets "Lit" to 1. LIB_FLASHLIGHT: calls eventTurnOn. LIB_LAMP: Begins the fuel burning process. + + +EXAMPLES + + + + +LOCATION + /lib/burn +/lib/flashlight +/lib/lamp +/lib/light + + +SEE ALSO + eventBurn + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/leader/eventJoin b/lib/doc/lfun/lib/leader/eventJoin new file mode 100644 index 0000000..22f008b --- /dev/null +++ b/lib/doc/lfun/lib/leader/eventJoin @@ -0,0 +1,24 @@ +EVENTJOIN + +NAME + eventJoin() + +SYNOPSIS + void eventJoin(object ob) + +DESCRIPTION + This is the second part of a two part "clan joining process". Once the new clan member has gone through the directives in eventInitiate(), this function is called in this object to finalize the new membership. + +EXAMPLES + + +LOCATION + /lib/clan +/lib/leader + +SEE ALSO + eventRetire, eventUnjoin, eventBring, eventInitiate + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/light/CanLight b/lib/doc/lfun/lib/light/CanLight new file mode 100644 index 0000000..3f102e7 --- /dev/null +++ b/lib/doc/lfun/lib/light/CanLight @@ -0,0 +1,29 @@ +CANLIGHT + +NAME + CanLight() + +SYNOPSIS + + + +DESCRIPTION + + + +EXAMPLES + + + +LOCATION + /lib/light + + +SEE ALSO + CanExtinguish + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/light/eventLight b/lib/doc/lfun/lib/light/eventLight new file mode 100644 index 0000000..4764a8d --- /dev/null +++ b/lib/doc/lfun/lib/light/eventLight @@ -0,0 +1,37 @@ +EVENTLIGHT + +NAME + eventLight() + + + +SYNOPSIS + mixed eventLight(object who, object what) + + + +DESCRIPTION + LIB_BURN: Calls eventBurn to initiate combustion. LIB_LIGHT: Sets "Lit" to 1. LIB_FLASHLIGHT: calls eventTurnOn. LIB_LAMP: Begins the fuel burning process. + + +EXAMPLES + + + + +LOCATION + /lib/burn +/lib/flashlight +/lib/lamp +/lib/light + + +SEE ALSO + eventBurn + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/limb/CanReceive b/lib/doc/lfun/lib/limb/CanReceive new file mode 100644 index 0000000..3f3afe1 --- /dev/null +++ b/lib/doc/lfun/lib/limb/CanReceive @@ -0,0 +1,34 @@ +CANRECEIVE + +NAME + CanReceive() + +SYNOPSIS + int CanReceive(object ob) + +DESCRIPTION + Objects that can hold other objects use this function to determine whether the incoming objects 'ob' is allowed to enter. If it is allowed, this function should return 1. If it is not allowed, this function should return 0. + +EXAMPLES + + +LOCATION + /lib/flashlight +/lib/npc +/lib/post_office +/lib/firearm +/lib/comp/container +/lib/player +/lib/std/corpse +/lib/comp/holder +/lib/std/limb +/lib/clip +/lib/std/furnace +/lib/std/room + +SEE ALSO + CanRelease + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/limb/GetRace b/lib/doc/lfun/lib/limb/GetRace new file mode 100644 index 0000000..e945d80 --- /dev/null +++ b/lib/doc/lfun/lib/limb/GetRace @@ -0,0 +1,38 @@ +GETRACE + +NAME + GetRace() + + + +SYNOPSIS + string GetRace() + + + +DESCRIPTION + Returns the creature's race. + + + +EXAMPLES + present("Spock", environment(this_player()))->GetRace() + + + +LOCATION + /lib/body +/lib/race +/lib/std/corpse +/lib/std/limb + + +SEE ALSO + GetClass + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/living/GetMaxHealthPoints b/lib/doc/lfun/lib/living/GetMaxHealthPoints new file mode 100644 index 0000000..ee454cb --- /dev/null +++ b/lib/doc/lfun/lib/living/GetMaxHealthPoints @@ -0,0 +1,39 @@ +GETMAXHEALTHPOINTS + +NAME + GetMaxHealthPoints() + + + +SYNOPSIS + varargs int GetMaxHealthPoints(string limb) + + + +DESCRIPTION + Returns a creature's maximum health level. Their normal healing process will not increase their health beyond this point. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/combat +/lib/living +/lib/npc +/lib/race + + +SEE ALSO + SetMaxHealthPoints, SetHealthPoints, GetHealthPoints + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/load/eventLoad b/lib/doc/lfun/lib/load/eventLoad new file mode 100644 index 0000000..dd822da --- /dev/null +++ b/lib/doc/lfun/lib/load/eventLoad @@ -0,0 +1,26 @@ +EVENTLOAD + +NAME + eventLoad() + +SYNOPSIS + LIB_CLIP and LIB_ROUND: varargs mixed eventLoad(object who, object where) , LIB_FIREARM: mixed eventLoad(object ob) + +DESCRIPTION + For LIB_CLIP and LIB_ROUND, this function performs the work of moving the object into the destination 'where'. For LIB_FIREARM, this function is called when a round is being loaded directly into a revolver. + +EXAMPLES + + +LOCATION + /lib/round +/lib/events/load +/lib/firearm +/lib/clip + +SEE ALSO + eventUnload + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/load/eventUnload b/lib/doc/lfun/lib/load/eventUnload new file mode 100644 index 0000000..7476126 --- /dev/null +++ b/lib/doc/lfun/lib/load/eventUnload @@ -0,0 +1,26 @@ +EVENTUNLOAD + +NAME + eventUnload() + +SYNOPSIS + mixed eventUnload(mixed what) + +DESCRIPTION + Provides for unloading. If the argument is a nonzero integer, it is presumed that the object is a LIB_CLIP or LIB_FIREARM and a number of objects are being unloaded from it. In the case of unloading a LIB_ROUND or a LIB_CLIP from something, then the argument would be the object that contains it. + +EXAMPLES + + +LOCATION + /lib/round +/lib/events/load +/lib/firearm +/lib/clip + +SEE ALSO + eventLoad + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/look/GetLong b/lib/doc/lfun/lib/look/GetLong new file mode 100644 index 0000000..097c124 --- /dev/null +++ b/lib/doc/lfun/lib/look/GetLong @@ -0,0 +1,47 @@ +GETLONG + +NAME + GetLong() + + + +SYNOPSIS + string GetLong(string str) + + + +DESCRIPTION + Returns the "long desciption" of the object it's called in. This long description is the main part of what the player sees when they "look at" something. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/bot +/lib/creator +/lib/donate +/lib/door +/lib/fuel +/lib/interactive +/lib/lamp +/lib/npc +/lib/player +/lib/torch +/lib/events/look +/lib/std/room + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/manipulate/CanManipulate b/lib/doc/lfun/lib/manipulate/CanManipulate new file mode 100644 index 0000000..9bea110 --- /dev/null +++ b/lib/doc/lfun/lib/manipulate/CanManipulate @@ -0,0 +1,31 @@ +CANMANIPULATE + +NAME + CanManipulate() + + +SYNOPSIS + mixed CanManipulate() + + +DESCRIPTION + Returns whether a creature has limbs with which to manipulate items. If a creature lacks limbs with which it can wield weapons, it is considered non-prehensile, and this function returns 0. Otherwise it returns 1. + + +EXAMPLES + + + +LOCATION + /lib/body +/lib/events/manipulate + + +SEE ALSO + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/meal/eventDestruct b/lib/doc/lfun/lib/meal/eventDestruct new file mode 100644 index 0000000..9b89fb3 --- /dev/null +++ b/lib/doc/lfun/lib/meal/eventDestruct @@ -0,0 +1,36 @@ +EVENTDESTRUCT + +NAME + eventDestruct() + +SYNOPSIS + int eventDestruct() + +DESCRIPTION + This lfun provides a convenient means to ensure proper things happen when an object is destructed. Rather than simply destruct(), you can use eventDestruct to, for example, move a thing to the furnace before it is actually removed from memory. Any invocation of eventDestruct() in a child object should probably make a scope reference to eventDestruct in its inheritance chain. + +EXAMPLES + int eventDestruct(){ write("Gbye!"); return ::eventDestruct(); } + +LOCATION + /lib/bonus +/lib/chat +/lib/interactive +/lib/meal +/lib/npc +/lib/props/clean +/lib/std/daemon +/secure/lib/connect +/secure/lib/file +/secure/lib/net/client +/secure/lib/net/ftp_client +/secure/lib/net/ftp_data_connection +/secure/lib/net/server + + +SEE ALSO + destruct (efun) + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/messages/GetName b/lib/doc/lfun/lib/messages/GetName new file mode 100644 index 0000000..9b9f25b --- /dev/null +++ b/lib/doc/lfun/lib/messages/GetName @@ -0,0 +1,41 @@ +GETNAME + +NAME + GetName() + + + +SYNOPSIS + string GetName() + + + +DESCRIPTION + Returns the object's proper name, capitalized if appropriate. + + + +EXAMPLES + this_player()->GetName() + + + +LOCATION + /lib/body +/lib/creator +/lib/interactive +/lib/messages +/lib/npc +/lib/player +/lib/props/id + + +SEE ALSO + GetKeyName() + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/npc/CanReceive b/lib/doc/lfun/lib/npc/CanReceive new file mode 100644 index 0000000..3f3afe1 --- /dev/null +++ b/lib/doc/lfun/lib/npc/CanReceive @@ -0,0 +1,34 @@ +CANRECEIVE + +NAME + CanReceive() + +SYNOPSIS + int CanReceive(object ob) + +DESCRIPTION + Objects that can hold other objects use this function to determine whether the incoming objects 'ob' is allowed to enter. If it is allowed, this function should return 1. If it is not allowed, this function should return 0. + +EXAMPLES + + +LOCATION + /lib/flashlight +/lib/npc +/lib/post_office +/lib/firearm +/lib/comp/container +/lib/player +/lib/std/corpse +/lib/comp/holder +/lib/std/limb +/lib/clip +/lib/std/furnace +/lib/std/room + +SEE ALSO + CanRelease + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/npc/GetCapName b/lib/doc/lfun/lib/npc/GetCapName new file mode 100644 index 0000000..7cb66e2 --- /dev/null +++ b/lib/doc/lfun/lib/npc/GetCapName @@ -0,0 +1,39 @@ +GETCAPNAME + +NAME + GetCapName() + + + +SYNOPSIS + string GetCapName() + + + +DESCRIPTION + Returns a thing's capitalized name. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/npc +/lib/player +/lib/props/id +/secure/lib/connect + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/npc/GetLong b/lib/doc/lfun/lib/npc/GetLong new file mode 100644 index 0000000..097c124 --- /dev/null +++ b/lib/doc/lfun/lib/npc/GetLong @@ -0,0 +1,47 @@ +GETLONG + +NAME + GetLong() + + + +SYNOPSIS + string GetLong(string str) + + + +DESCRIPTION + Returns the "long desciption" of the object it's called in. This long description is the main part of what the player sees when they "look at" something. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/bot +/lib/creator +/lib/donate +/lib/door +/lib/fuel +/lib/interactive +/lib/lamp +/lib/npc +/lib/player +/lib/torch +/lib/events/look +/lib/std/room + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/npc/GetMaxHealthPoints b/lib/doc/lfun/lib/npc/GetMaxHealthPoints new file mode 100644 index 0000000..ee454cb --- /dev/null +++ b/lib/doc/lfun/lib/npc/GetMaxHealthPoints @@ -0,0 +1,39 @@ +GETMAXHEALTHPOINTS + +NAME + GetMaxHealthPoints() + + + +SYNOPSIS + varargs int GetMaxHealthPoints(string limb) + + + +DESCRIPTION + Returns a creature's maximum health level. Their normal healing process will not increase their health beyond this point. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/combat +/lib/living +/lib/npc +/lib/race + + +SEE ALSO + SetMaxHealthPoints, SetHealthPoints, GetHealthPoints + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/npc/GetName b/lib/doc/lfun/lib/npc/GetName new file mode 100644 index 0000000..9b9f25b --- /dev/null +++ b/lib/doc/lfun/lib/npc/GetName @@ -0,0 +1,41 @@ +GETNAME + +NAME + GetName() + + + +SYNOPSIS + string GetName() + + + +DESCRIPTION + Returns the object's proper name, capitalized if appropriate. + + + +EXAMPLES + this_player()->GetName() + + + +LOCATION + /lib/body +/lib/creator +/lib/interactive +/lib/messages +/lib/npc +/lib/player +/lib/props/id + + +SEE ALSO + GetKeyName() + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/npc/SetClass b/lib/doc/lfun/lib/npc/SetClass new file mode 100644 index 0000000..1b42558 --- /dev/null +++ b/lib/doc/lfun/lib/npc/SetClass @@ -0,0 +1,27 @@ +SETCLASS + +NAME + SetClass() + +SYNOPSIS + string SetClass(string class_name) + +DESCRIPTION + If the creature does not currently have a class, its class is set to the string specified. If the creature already has a class, that class name is returned. + +EXAMPLES + + +LOCATION + /lib/classes +/lib/npc +/lib/player +/lib/props/damage + + +SEE ALSO + ChangeClass + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/npc/eventDestruct b/lib/doc/lfun/lib/npc/eventDestruct new file mode 100644 index 0000000..9b89fb3 --- /dev/null +++ b/lib/doc/lfun/lib/npc/eventDestruct @@ -0,0 +1,36 @@ +EVENTDESTRUCT + +NAME + eventDestruct() + +SYNOPSIS + int eventDestruct() + +DESCRIPTION + This lfun provides a convenient means to ensure proper things happen when an object is destructed. Rather than simply destruct(), you can use eventDestruct to, for example, move a thing to the furnace before it is actually removed from memory. Any invocation of eventDestruct() in a child object should probably make a scope reference to eventDestruct in its inheritance chain. + +EXAMPLES + int eventDestruct(){ write("Gbye!"); return ::eventDestruct(); } + +LOCATION + /lib/bonus +/lib/chat +/lib/interactive +/lib/meal +/lib/npc +/lib/props/clean +/lib/std/daemon +/secure/lib/connect +/secure/lib/file +/secure/lib/net/client +/secure/lib/net/ftp_client +/secure/lib/net/ftp_data_connection +/secure/lib/net/server + + +SEE ALSO + destruct (efun) + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/npc/eventDie b/lib/doc/lfun/lib/npc/eventDie new file mode 100644 index 0000000..4e12cf7 --- /dev/null +++ b/lib/doc/lfun/lib/npc/eventDie @@ -0,0 +1,41 @@ +EVENTDIE + +NAME + eventDie() + + + +SYNOPSIS + varargs int eventDie(mixed agent) + + + +DESCRIPTION + When a creature dies, this function is called in them. The argument should be what it is that killed them. Note that this is a function that is heavily overridden, and must be handled with care if modified. If you don't know what a function override is, then don't mess with this function. If eventDie() returns something other than a positive integer, the creature doesn't die in the conventional sense: they instead become undead. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/bot +/lib/combat +/lib/flashlight +/lib/npc +/lib/player +/lib/race + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/npc/eventReconnect b/lib/doc/lfun/lib/npc/eventReconnect new file mode 100644 index 0000000..9046556 --- /dev/null +++ b/lib/doc/lfun/lib/npc/eventReconnect @@ -0,0 +1,40 @@ +EVENTRECONNECT + +NAME + eventReconnect() + + + +SYNOPSIS + void eventReconnect() + + + +DESCRIPTION + A series of events that need to occur when a user reconnects to the game after going link-dead. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/chat +/lib/creator +/lib/interactive +/lib/npc +/lib/player + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/player/AddHealthPoints b/lib/doc/lfun/lib/player/AddHealthPoints new file mode 100644 index 0000000..42a3baf --- /dev/null +++ b/lib/doc/lfun/lib/player/AddHealthPoints @@ -0,0 +1,36 @@ +ADDHEALTHPOINTS + +NAME + AddHealthPoints() + + + +SYNOPSIS + varargs static int AddHealthPoints(int x, string limb, object agent) + + + +DESCRIPTION + If the value of limb is not zero, then "x" number of health points will be added to limb "limb". If the value is 0, then the overall health points will be modified. int x - number of points being added, may be negative (required). string limb - the limb to which health is being added (optional). object agent - the living responsible for this damage. Returns the remaining number of health points for the limb in question or for the overall health points. Note this is a static function and cannot be called from outside the creature. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/player + + +SEE ALSO + AddHP + + + +Author + Unknown + + diff --git a/lib/doc/lfun/lib/player/CanReceive b/lib/doc/lfun/lib/player/CanReceive new file mode 100644 index 0000000..3f3afe1 --- /dev/null +++ b/lib/doc/lfun/lib/player/CanReceive @@ -0,0 +1,34 @@ +CANRECEIVE + +NAME + CanReceive() + +SYNOPSIS + int CanReceive(object ob) + +DESCRIPTION + Objects that can hold other objects use this function to determine whether the incoming objects 'ob' is allowed to enter. If it is allowed, this function should return 1. If it is not allowed, this function should return 0. + +EXAMPLES + + +LOCATION + /lib/flashlight +/lib/npc +/lib/post_office +/lib/firearm +/lib/comp/container +/lib/player +/lib/std/corpse +/lib/comp/holder +/lib/std/limb +/lib/clip +/lib/std/furnace +/lib/std/room + +SEE ALSO + CanRelease + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/player/GetCapName b/lib/doc/lfun/lib/player/GetCapName new file mode 100644 index 0000000..7cb66e2 --- /dev/null +++ b/lib/doc/lfun/lib/player/GetCapName @@ -0,0 +1,39 @@ +GETCAPNAME + +NAME + GetCapName() + + + +SYNOPSIS + string GetCapName() + + + +DESCRIPTION + Returns a thing's capitalized name. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/npc +/lib/player +/lib/props/id +/secure/lib/connect + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/player/GetLong b/lib/doc/lfun/lib/player/GetLong new file mode 100644 index 0000000..097c124 --- /dev/null +++ b/lib/doc/lfun/lib/player/GetLong @@ -0,0 +1,47 @@ +GETLONG + +NAME + GetLong() + + + +SYNOPSIS + string GetLong(string str) + + + +DESCRIPTION + Returns the "long desciption" of the object it's called in. This long description is the main part of what the player sees when they "look at" something. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/bot +/lib/creator +/lib/donate +/lib/door +/lib/fuel +/lib/interactive +/lib/lamp +/lib/npc +/lib/player +/lib/torch +/lib/events/look +/lib/std/room + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/player/GetName b/lib/doc/lfun/lib/player/GetName new file mode 100644 index 0000000..9b9f25b --- /dev/null +++ b/lib/doc/lfun/lib/player/GetName @@ -0,0 +1,41 @@ +GETNAME + +NAME + GetName() + + + +SYNOPSIS + string GetName() + + + +DESCRIPTION + Returns the object's proper name, capitalized if appropriate. + + + +EXAMPLES + this_player()->GetName() + + + +LOCATION + /lib/body +/lib/creator +/lib/interactive +/lib/messages +/lib/npc +/lib/player +/lib/props/id + + +SEE ALSO + GetKeyName() + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/player/SetClass b/lib/doc/lfun/lib/player/SetClass new file mode 100644 index 0000000..1b42558 --- /dev/null +++ b/lib/doc/lfun/lib/player/SetClass @@ -0,0 +1,27 @@ +SETCLASS + +NAME + SetClass() + +SYNOPSIS + string SetClass(string class_name) + +DESCRIPTION + If the creature does not currently have a class, its class is set to the string specified. If the creature already has a class, that class name is returned. + +EXAMPLES + + +LOCATION + /lib/classes +/lib/npc +/lib/player +/lib/props/damage + + +SEE ALSO + ChangeClass + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/player/eventDie b/lib/doc/lfun/lib/player/eventDie new file mode 100644 index 0000000..4e12cf7 --- /dev/null +++ b/lib/doc/lfun/lib/player/eventDie @@ -0,0 +1,41 @@ +EVENTDIE + +NAME + eventDie() + + + +SYNOPSIS + varargs int eventDie(mixed agent) + + + +DESCRIPTION + When a creature dies, this function is called in them. The argument should be what it is that killed them. Note that this is a function that is heavily overridden, and must be handled with care if modified. If you don't know what a function override is, then don't mess with this function. If eventDie() returns something other than a positive integer, the creature doesn't die in the conventional sense: they instead become undead. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/bot +/lib/combat +/lib/flashlight +/lib/npc +/lib/player +/lib/race + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/player/eventReconnect b/lib/doc/lfun/lib/player/eventReconnect new file mode 100644 index 0000000..9046556 --- /dev/null +++ b/lib/doc/lfun/lib/player/eventReconnect @@ -0,0 +1,40 @@ +EVENTRECONNECT + +NAME + eventReconnect() + + + +SYNOPSIS + void eventReconnect() + + + +DESCRIPTION + A series of events that need to occur when a user reconnects to the game after going link-dead. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/chat +/lib/creator +/lib/interactive +/lib/npc +/lib/player + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/player/eventUse b/lib/doc/lfun/lib/player/eventUse new file mode 100644 index 0000000..e2602fe --- /dev/null +++ b/lib/doc/lfun/lib/player/eventUse @@ -0,0 +1,37 @@ +EVENTUSE + +NAME + eventUse() + + + +SYNOPSIS + LIB_BATTERY: int eventUse(int i), LIB_PLAYER: mixed eventUse(object used, string cmd) + + + +DESCRIPTION + For batteries, it runs necessary actions when the battery is used. For players, it runs the parser in a stripped way for testing. + + + +EXAMPLES + + + + +LOCATION + /lib/battery +/lib/flashlight +/lib/player + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/poison/AddPoison b/lib/doc/lfun/lib/poison/AddPoison new file mode 100644 index 0000000..725b95a --- /dev/null +++ b/lib/doc/lfun/lib/poison/AddPoison @@ -0,0 +1,36 @@ +ADDPOISON + +NAME + AddPoison() + + + +SYNOPSIS + int AddPoison(int x) + + + +DESCRIPTION + Arbitrarily add poison by the amount indicated by the passed integer. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/events/poison + + +SEE ALSO + GetPoison + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/poison/GetPoison b/lib/doc/lfun/lib/poison/GetPoison new file mode 100644 index 0000000..246d1bc --- /dev/null +++ b/lib/doc/lfun/lib/poison/GetPoison @@ -0,0 +1,36 @@ +GETPOISON + +NAME + GetPoison + + + +SYNOPSIS + int GetPoison() + + + +DESCRIPTION + Returns the current poison level. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/events/poison + + +SEE ALSO + AddPoison + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/position/eventFall b/lib/doc/lfun/lib/position/eventFall new file mode 100644 index 0000000..ec44d0b --- /dev/null +++ b/lib/doc/lfun/lib/position/eventFall @@ -0,0 +1,35 @@ +EVENTFALL + +NAME + eventFall() + + + +SYNOPSIS + mixed eventFall() + + + +DESCRIPTION + What happens when a body suffers a fall. Relevant checks and actions occur here. + + + +EXAMPLES + this_player()->eventFall() + + + +LOCATION + /lib/body +/lib/lvs/position + + +SEE ALSO + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/post_office/CanReceive b/lib/doc/lfun/lib/post_office/CanReceive new file mode 100644 index 0000000..3f3afe1 --- /dev/null +++ b/lib/doc/lfun/lib/post_office/CanReceive @@ -0,0 +1,34 @@ +CANRECEIVE + +NAME + CanReceive() + +SYNOPSIS + int CanReceive(object ob) + +DESCRIPTION + Objects that can hold other objects use this function to determine whether the incoming objects 'ob' is allowed to enter. If it is allowed, this function should return 1. If it is not allowed, this function should return 0. + +EXAMPLES + + +LOCATION + /lib/flashlight +/lib/npc +/lib/post_office +/lib/firearm +/lib/comp/container +/lib/player +/lib/std/corpse +/lib/comp/holder +/lib/std/limb +/lib/clip +/lib/std/furnace +/lib/std/room + +SEE ALSO + CanRelease + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/potion/GetPoints b/lib/doc/lfun/lib/potion/GetPoints new file mode 100644 index 0000000..989203e --- /dev/null +++ b/lib/doc/lfun/lib/potion/GetPoints @@ -0,0 +1,25 @@ +GETPOINTS + +NAME + GetPoints() + +SYNOPSIS + mapping GetPoints() + +DESCRIPTION + Returs which vital points are affected by a potion or bonus, and by how much. + +EXAMPLES + + +LOCATION + /lib/bonus +/lib/potion + + +SEE ALSO + SetPoints, SetBonusDuration, GetBonusDuration + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/potion/GetSkills b/lib/doc/lfun/lib/potion/GetSkills new file mode 100644 index 0000000..dbaaa79 --- /dev/null +++ b/lib/doc/lfun/lib/potion/GetSkills @@ -0,0 +1,27 @@ +GETSKILLS + +NAME + GetSkills() + +SYNOPSIS + LIB_SPELL, LIB_ABILITIES: string array GetSkills() ; LIB_POTION, LIB_BONUS: mapping GetSkills() + +DESCRIPTION + For LIB_ABILITIES this lfun returns the list of skill names possessed by the creature it's called in, such as "knife defense", etc. For LIB_SPELL this returns a list of the skills required to be able to cast the spell. For LIB_POTION and LIB_BONUS, this lfun works much like GetStats(), in that it returns a mapping of skills and how they are modified when a potion is drunk. + +EXAMPLES + + +LOCATION + /lib/bonus +/lib/lvs/abilities +/lib/potion +/lib/spell + + +SEE ALSO + GetStats, SetSkill + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/potion/GetStats b/lib/doc/lfun/lib/potion/GetStats new file mode 100644 index 0000000..34a54b3 --- /dev/null +++ b/lib/doc/lfun/lib/potion/GetStats @@ -0,0 +1,26 @@ +GETSTATS + +NAME + GetStats() + +SYNOPSIS + genetics: string array GetStats() , potion and bonus: mapping GetStats() + +DESCRIPTION + Called in a living thing, GetStats() returns an array of the creature's stat names, such as "strength", "wisdom", and the like. In the potion object, it returns a mapping of stats to modify when the potion is drunk. When the potion is drunk, this mapping is communicated to the bonus object that is moved into the drinker. + +EXAMPLES + + +LOCATION + /lib/bonus +/lib/genetics +/lib/potion + + +SEE ALSO + SetStats, GetStat, SetStat, GetStatLevel + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/potion/SetPoints b/lib/doc/lfun/lib/potion/SetPoints new file mode 100644 index 0000000..a4771a5 --- /dev/null +++ b/lib/doc/lfun/lib/potion/SetPoints @@ -0,0 +1,25 @@ +SETPOINTS + +NAME + SetPoints() + +SYNOPSIS + mapping SetPoints(mapping arg) + +DESCRIPTION + In LIB_POTION and LIB_BONUS, this lfun specifies which vital points are affected, and by how much. + +EXAMPLES + SetPoints( ([ "HP" : 100, "SP" : 50 ]) ); + +LOCATION + /lib/bonus +/lib/potion + + +SEE ALSO + GetPoints, SetBonusDuration, GetBonusDuration + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/potion/SetSkills b/lib/doc/lfun/lib/potion/SetSkills new file mode 100644 index 0000000..2a3c39d --- /dev/null +++ b/lib/doc/lfun/lib/potion/SetSkills @@ -0,0 +1,26 @@ +SETSKILLS + +NAME + SetSkills() + +SYNOPSIS + mapping SetSkills(mapping mp) + +DESCRIPTION + For LIB_SPELL this sets the required skills to be able to cast a spell, and the required level for each skill. For LIB_POTION and LIB_BONUS, this sets the skills altered by drinking the potion. + +EXAMPLES + SetSkills( ([ "cleverness" : 1 ]) ) + +LOCATION + /lib/bonus +/lib/potion +/lib/spell + + +SEE ALSO + GetSkills, SetStats, GetStats + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/potion/SetStats b/lib/doc/lfun/lib/potion/SetStats new file mode 100644 index 0000000..907c5a0 --- /dev/null +++ b/lib/doc/lfun/lib/potion/SetStats @@ -0,0 +1,25 @@ +SETSTATS + +NAME + SetStats() + +SYNOPSIS + mapping SetStats(mapping arg) + +DESCRIPTION + Sets which stats are altered by a potion or bonus, and to what extent. + +EXAMPLES + SetStats( ([ "strength" : 30, "intelligence" : -30 ]) ) + +LOCATION + /lib/bonus +/lib/potion + + +SEE ALSO + GetStats, SetSkills, GetSkills + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/race/GetAlcohol b/lib/doc/lfun/lib/race/GetAlcohol new file mode 100644 index 0000000..a623737 --- /dev/null +++ b/lib/doc/lfun/lib/race/GetAlcohol @@ -0,0 +1,36 @@ +GETALCOHOL + +NAME + GetAlcohol() + + + +SYNOPSIS + int GetAlcohol() + + + +DESCRIPTION + Returns the alcohol level of the creature. + + + +EXAMPLES + present("wino",environment(this_player()))->GetAlcohol() + + + +LOCATION + /lib/body +/lib/race + + +SEE ALSO + SetAlcohol + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/race/GetHealRate b/lib/doc/lfun/lib/race/GetHealRate new file mode 100644 index 0000000..7ad1392 --- /dev/null +++ b/lib/doc/lfun/lib/race/GetHealRate @@ -0,0 +1,31 @@ +GETHEALRATE + +NAME + GetHealRate() + + +SYNOPSIS + int GetHealRate() + + +DESCRIPTION + Returns a creature's healing rate. + + +EXAMPLES + + + +LOCATION + /lib/body +/lib/race + + +SEE ALSO + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/race/GetHeartRate b/lib/doc/lfun/lib/race/GetHeartRate new file mode 100644 index 0000000..3bce69f --- /dev/null +++ b/lib/doc/lfun/lib/race/GetHeartRate @@ -0,0 +1,31 @@ +GETHEARTRATE + +NAME + GetHeartRate() + + +SYNOPSIS + int GetHeartRate() + + +DESCRIPTION + Returns a creature's heart rate (NOT heart_beat). + + +EXAMPLES + + + +LOCATION + /lib/body +/lib/race + + +SEE ALSO + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/race/GetMaxHealthPoints b/lib/doc/lfun/lib/race/GetMaxHealthPoints new file mode 100644 index 0000000..ee454cb --- /dev/null +++ b/lib/doc/lfun/lib/race/GetMaxHealthPoints @@ -0,0 +1,39 @@ +GETMAXHEALTHPOINTS + +NAME + GetMaxHealthPoints() + + + +SYNOPSIS + varargs int GetMaxHealthPoints(string limb) + + + +DESCRIPTION + Returns a creature's maximum health level. Their normal healing process will not increase their health beyond this point. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/combat +/lib/living +/lib/npc +/lib/race + + +SEE ALSO + SetMaxHealthPoints, SetHealthPoints, GetHealthPoints + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/race/GetMaxMagicPoints b/lib/doc/lfun/lib/race/GetMaxMagicPoints new file mode 100644 index 0000000..a6e290e --- /dev/null +++ b/lib/doc/lfun/lib/race/GetMaxMagicPoints @@ -0,0 +1,36 @@ +GETMAXMAGICPOINTS + +NAME + GetMaxMagicPoints() + + + +SYNOPSIS + int GetMaxMagicPoints() + + + +DESCRIPTION + Returns a creature's maximum magic level. Their normal healing process will not increase their magic beyond this point. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/race + + +SEE ALSO + SetMagicPoints, GetMagicPoints, AddMagicPoints + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/race/GetMaxStaminaPoints b/lib/doc/lfun/lib/race/GetMaxStaminaPoints new file mode 100644 index 0000000..c98e79d --- /dev/null +++ b/lib/doc/lfun/lib/race/GetMaxStaminaPoints @@ -0,0 +1,36 @@ +GETMAXSTAMINAPOINTS + +NAME + GetMaxStaminaPoints() + + + +SYNOPSIS + float GetMaxStaminaPoints() + + + +DESCRIPTION + Returns a creature's maximum stamina level. Their normal healing process will not increase their stamina beyond this point. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/race + + +SEE ALSO + AddStaminaPoints, GetStaminaPoints + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/race/GetRace b/lib/doc/lfun/lib/race/GetRace new file mode 100644 index 0000000..e945d80 --- /dev/null +++ b/lib/doc/lfun/lib/race/GetRace @@ -0,0 +1,38 @@ +GETRACE + +NAME + GetRace() + + + +SYNOPSIS + string GetRace() + + + +DESCRIPTION + Returns the creature's race. + + + +EXAMPLES + present("Spock", environment(this_player()))->GetRace() + + + +LOCATION + /lib/body +/lib/race +/lib/std/corpse +/lib/std/limb + + +SEE ALSO + GetClass + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/race/GetResistance b/lib/doc/lfun/lib/race/GetResistance new file mode 100644 index 0000000..1fbc0ce --- /dev/null +++ b/lib/doc/lfun/lib/race/GetResistance @@ -0,0 +1,32 @@ +GETRESISTANCE + +NAME + GetResistance() + + +SYNOPSIS + string GetResistance(int type) + + +DESCRIPTION + Returns the creature's resistance level to the given damage type. + + +EXAMPLES + this_player()->GetResistance(GAS) + + +LOCATION + /lib/body +/lib/genetics +/lib/race + + +SEE ALSO + damage_types.h + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/race/NewBody b/lib/doc/lfun/lib/race/NewBody new file mode 100644 index 0000000..5ebc142 --- /dev/null +++ b/lib/doc/lfun/lib/race/NewBody @@ -0,0 +1,31 @@ +NEWBODY + +NAME + NewBody() + + +SYNOPSIS + void NewBody(string race) + + +DESCRIPTION + Initializes some body-specific mappings. A null race creates potentially undesirable outcomes. + + +EXAMPLES + + + +LOCATION + /lib/body +/lib/race + + +SEE ALSO + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/race/eventDie b/lib/doc/lfun/lib/race/eventDie new file mode 100644 index 0000000..4e12cf7 --- /dev/null +++ b/lib/doc/lfun/lib/race/eventDie @@ -0,0 +1,41 @@ +EVENTDIE + +NAME + eventDie() + + + +SYNOPSIS + varargs int eventDie(mixed agent) + + + +DESCRIPTION + When a creature dies, this function is called in them. The argument should be what it is that killed them. Note that this is a function that is heavily overridden, and must be handled with care if modified. If you don't know what a function override is, then don't mess with this function. If eventDie() returns something other than a positive integer, the creature doesn't die in the conventional sense: they instead become undead. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/bot +/lib/combat +/lib/flashlight +/lib/npc +/lib/player +/lib/race + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/room/CanFly b/lib/doc/lfun/lib/room/CanFly new file mode 100644 index 0000000..1fe52ae --- /dev/null +++ b/lib/doc/lfun/lib/room/CanFly @@ -0,0 +1,37 @@ +CANFLY + +NAME + CanFly() + + + +SYNOPSIS + int CanFly() + + + +DESCRIPTION + In npc's, checks to see whether the creature is capable of flight. A return of 1 is yes, a return of 0 is no. In rooms, the default is for a room to permit a flying creature to fly in or out. If CanFly returns 0, that behavior is restricted. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/std/room +/lib/virtual/virt_sky + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/room/CanReceive b/lib/doc/lfun/lib/room/CanReceive new file mode 100644 index 0000000..3f3afe1 --- /dev/null +++ b/lib/doc/lfun/lib/room/CanReceive @@ -0,0 +1,34 @@ +CANRECEIVE + +NAME + CanReceive() + +SYNOPSIS + int CanReceive(object ob) + +DESCRIPTION + Objects that can hold other objects use this function to determine whether the incoming objects 'ob' is allowed to enter. If it is allowed, this function should return 1. If it is not allowed, this function should return 0. + +EXAMPLES + + +LOCATION + /lib/flashlight +/lib/npc +/lib/post_office +/lib/firearm +/lib/comp/container +/lib/player +/lib/std/corpse +/lib/comp/holder +/lib/std/limb +/lib/clip +/lib/std/furnace +/lib/std/room + +SEE ALSO + CanRelease + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/room/GetLong b/lib/doc/lfun/lib/room/GetLong new file mode 100644 index 0000000..097c124 --- /dev/null +++ b/lib/doc/lfun/lib/room/GetLong @@ -0,0 +1,47 @@ +GETLONG + +NAME + GetLong() + + + +SYNOPSIS + string GetLong(string str) + + + +DESCRIPTION + Returns the "long desciption" of the object it's called in. This long description is the main part of what the player sees when they "look at" something. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/bot +/lib/creator +/lib/donate +/lib/door +/lib/fuel +/lib/interactive +/lib/lamp +/lib/npc +/lib/player +/lib/torch +/lib/events/look +/lib/std/room + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/round/GetAmmoType b/lib/doc/lfun/lib/round/GetAmmoType new file mode 100644 index 0000000..2b167ef --- /dev/null +++ b/lib/doc/lfun/lib/round/GetAmmoType @@ -0,0 +1,26 @@ +GETAMMOTYPE + +NAME + GetAmmoType() + +SYNOPSIS + string GetAmmoType() + +DESCRIPTION + If the ammunition type is set on a clip or a round, they must match in order to be compatible. This function returns the string defined for that information. + +EXAMPLES + + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + SetAmmoType, GetFirearmType, SetFirearmType + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/round/GetCaliber b/lib/doc/lfun/lib/round/GetCaliber new file mode 100644 index 0000000..3481b93 --- /dev/null +++ b/lib/doc/lfun/lib/round/GetCaliber @@ -0,0 +1,26 @@ +GETCALIBER + +NAME + GetCaliber() + +SYNOPSIS + int GetCaliber() + +DESCRIPTION + Caliber is a measurement of ammunition size, different from millimeters. This function returns that information for the given object, if it is set. + +EXAMPLES + + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + SetCaliber, SetMillimeter, GetMillimeter + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/round/GetFirearmType b/lib/doc/lfun/lib/round/GetFirearmType new file mode 100644 index 0000000..159f673 --- /dev/null +++ b/lib/doc/lfun/lib/round/GetFirearmType @@ -0,0 +1,26 @@ +GETFIREARMTYPE + +NAME + GetFirearmType() + +SYNOPSIS + string GetFirearmType() + +DESCRIPTION + If the firearm type is set on a clip or a round, they must match in order to be compatible. This function returns the string defined for that information. + +EXAMPLES + + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetAmmoType, SetAmmoType, SetFirearmType + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/round/GetMillimeter b/lib/doc/lfun/lib/round/GetMillimeter new file mode 100644 index 0000000..5f54d8b --- /dev/null +++ b/lib/doc/lfun/lib/round/GetMillimeter @@ -0,0 +1,26 @@ +GETMILLIMETER + +NAME + GetMillimeter() + +SYNOPSIS + int GetMillimeter() + +DESCRIPTION + Millimeter is a measurement of ammunition size, different from caliber. This function returns that information for the given object, if it is set. + +EXAMPLES + . + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetCaliber, SetCaliber, SetMillimeter + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/round/SetAmmoType b/lib/doc/lfun/lib/round/SetAmmoType new file mode 100644 index 0000000..a0ab48c --- /dev/null +++ b/lib/doc/lfun/lib/round/SetAmmoType @@ -0,0 +1,26 @@ +SETAMMOTYPE + +NAME + SetAmmoType() + +SYNOPSIS + int SetAmmoType(string str) + +DESCRIPTION + If the ammunition type is set on a clip or a round, they must match in order to be compatible. This function defines the string for that information. + +EXAMPLES + SetAmmoType("acp") + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetAmmoType, GetFirearmType, SetFirearmType + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/round/SetCaliber b/lib/doc/lfun/lib/round/SetCaliber new file mode 100644 index 0000000..eacc5f5 --- /dev/null +++ b/lib/doc/lfun/lib/round/SetCaliber @@ -0,0 +1,26 @@ +SETCALIBER + +NAME + SetCaliber() + +SYNOPSIS + int SetCaliber(int x) + +DESCRIPTION + Caliber is a measurement of ammunition size, different from millimeters. If this is set on a round or a firearm, then the round and firearm must match calibers in order to be compatible. + +EXAMPLES + SetCaliber(357) + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetCaliber, SetMillimeter, GetMillimeter + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/round/SetFirearmType b/lib/doc/lfun/lib/round/SetFirearmType new file mode 100644 index 0000000..dc58dc7 --- /dev/null +++ b/lib/doc/lfun/lib/round/SetFirearmType @@ -0,0 +1,26 @@ +SETFIREARMTYPE + +NAME + SetFirearmType() + +SYNOPSIS + int SetFirearmType(string str) + +DESCRIPTION + If the firearm type is set on a clip or a round, they must match in order to be compatible. This function defines the string for that information. + +EXAMPLES + SetFirearmType("auto") + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetAmmoType, SetAmmoType, GetFirearmType + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/round/SetMillimeter b/lib/doc/lfun/lib/round/SetMillimeter new file mode 100644 index 0000000..9b33f96 --- /dev/null +++ b/lib/doc/lfun/lib/round/SetMillimeter @@ -0,0 +1,26 @@ +SETMILLIMETER + +NAME + SetMillimeter() + +SYNOPSIS + int SetMillimeter(int x) + +DESCRIPTION + Millimeter is a measurement of ammunition size, different from caliber. If this is set on a round or a firearm, then the round and firearm must match millimeter definition in order to be compatible. + +EXAMPLES + SetMillimeter(9) + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetCaliber, SetCaliber, GetMillimeter + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/round/eventLoad b/lib/doc/lfun/lib/round/eventLoad new file mode 100644 index 0000000..dd822da --- /dev/null +++ b/lib/doc/lfun/lib/round/eventLoad @@ -0,0 +1,26 @@ +EVENTLOAD + +NAME + eventLoad() + +SYNOPSIS + LIB_CLIP and LIB_ROUND: varargs mixed eventLoad(object who, object where) , LIB_FIREARM: mixed eventLoad(object ob) + +DESCRIPTION + For LIB_CLIP and LIB_ROUND, this function performs the work of moving the object into the destination 'where'. For LIB_FIREARM, this function is called when a round is being loaded directly into a revolver. + +EXAMPLES + + +LOCATION + /lib/round +/lib/events/load +/lib/firearm +/lib/clip + +SEE ALSO + eventUnload + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/round/eventUnload b/lib/doc/lfun/lib/round/eventUnload new file mode 100644 index 0000000..7476126 --- /dev/null +++ b/lib/doc/lfun/lib/round/eventUnload @@ -0,0 +1,26 @@ +EVENTUNLOAD + +NAME + eventUnload() + +SYNOPSIS + mixed eventUnload(mixed what) + +DESCRIPTION + Provides for unloading. If the argument is a nonzero integer, it is presumed that the object is a LIB_CLIP or LIB_FIREARM and a number of objects are being unloaded from it. In the case of unloading a LIB_ROUND or a LIB_CLIP from something, then the argument would be the object that contains it. + +EXAMPLES + + +LOCATION + /lib/round +/lib/events/load +/lib/firearm +/lib/clip + +SEE ALSO + eventLoad + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/server/eventDestruct b/lib/doc/lfun/lib/server/eventDestruct new file mode 100644 index 0000000..9b89fb3 --- /dev/null +++ b/lib/doc/lfun/lib/server/eventDestruct @@ -0,0 +1,36 @@ +EVENTDESTRUCT + +NAME + eventDestruct() + +SYNOPSIS + int eventDestruct() + +DESCRIPTION + This lfun provides a convenient means to ensure proper things happen when an object is destructed. Rather than simply destruct(), you can use eventDestruct to, for example, move a thing to the furnace before it is actually removed from memory. Any invocation of eventDestruct() in a child object should probably make a scope reference to eventDestruct in its inheritance chain. + +EXAMPLES + int eventDestruct(){ write("Gbye!"); return ::eventDestruct(); } + +LOCATION + /lib/bonus +/lib/chat +/lib/interactive +/lib/meal +/lib/npc +/lib/props/clean +/lib/std/daemon +/secure/lib/connect +/secure/lib/file +/secure/lib/net/client +/secure/lib/net/ftp_client +/secure/lib/net/ftp_data_connection +/secure/lib/net/server + + +SEE ALSO + destruct (efun) + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/shell/GetAmmoType b/lib/doc/lfun/lib/shell/GetAmmoType new file mode 100644 index 0000000..2b167ef --- /dev/null +++ b/lib/doc/lfun/lib/shell/GetAmmoType @@ -0,0 +1,26 @@ +GETAMMOTYPE + +NAME + GetAmmoType() + +SYNOPSIS + string GetAmmoType() + +DESCRIPTION + If the ammunition type is set on a clip or a round, they must match in order to be compatible. This function returns the string defined for that information. + +EXAMPLES + + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + SetAmmoType, GetFirearmType, SetFirearmType + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/shell/GetCaliber b/lib/doc/lfun/lib/shell/GetCaliber new file mode 100644 index 0000000..3481b93 --- /dev/null +++ b/lib/doc/lfun/lib/shell/GetCaliber @@ -0,0 +1,26 @@ +GETCALIBER + +NAME + GetCaliber() + +SYNOPSIS + int GetCaliber() + +DESCRIPTION + Caliber is a measurement of ammunition size, different from millimeters. This function returns that information for the given object, if it is set. + +EXAMPLES + + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + SetCaliber, SetMillimeter, GetMillimeter + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/shell/GetFirearmType b/lib/doc/lfun/lib/shell/GetFirearmType new file mode 100644 index 0000000..159f673 --- /dev/null +++ b/lib/doc/lfun/lib/shell/GetFirearmType @@ -0,0 +1,26 @@ +GETFIREARMTYPE + +NAME + GetFirearmType() + +SYNOPSIS + string GetFirearmType() + +DESCRIPTION + If the firearm type is set on a clip or a round, they must match in order to be compatible. This function returns the string defined for that information. + +EXAMPLES + + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetAmmoType, SetAmmoType, SetFirearmType + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/shell/GetMillimeter b/lib/doc/lfun/lib/shell/GetMillimeter new file mode 100644 index 0000000..5f54d8b --- /dev/null +++ b/lib/doc/lfun/lib/shell/GetMillimeter @@ -0,0 +1,26 @@ +GETMILLIMETER + +NAME + GetMillimeter() + +SYNOPSIS + int GetMillimeter() + +DESCRIPTION + Millimeter is a measurement of ammunition size, different from caliber. This function returns that information for the given object, if it is set. + +EXAMPLES + . + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetCaliber, SetCaliber, SetMillimeter + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/shell/SetAmmoType b/lib/doc/lfun/lib/shell/SetAmmoType new file mode 100644 index 0000000..a0ab48c --- /dev/null +++ b/lib/doc/lfun/lib/shell/SetAmmoType @@ -0,0 +1,26 @@ +SETAMMOTYPE + +NAME + SetAmmoType() + +SYNOPSIS + int SetAmmoType(string str) + +DESCRIPTION + If the ammunition type is set on a clip or a round, they must match in order to be compatible. This function defines the string for that information. + +EXAMPLES + SetAmmoType("acp") + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetAmmoType, GetFirearmType, SetFirearmType + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/shell/SetCaliber b/lib/doc/lfun/lib/shell/SetCaliber new file mode 100644 index 0000000..eacc5f5 --- /dev/null +++ b/lib/doc/lfun/lib/shell/SetCaliber @@ -0,0 +1,26 @@ +SETCALIBER + +NAME + SetCaliber() + +SYNOPSIS + int SetCaliber(int x) + +DESCRIPTION + Caliber is a measurement of ammunition size, different from millimeters. If this is set on a round or a firearm, then the round and firearm must match calibers in order to be compatible. + +EXAMPLES + SetCaliber(357) + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetCaliber, SetMillimeter, GetMillimeter + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/shell/SetFirearmType b/lib/doc/lfun/lib/shell/SetFirearmType new file mode 100644 index 0000000..dc58dc7 --- /dev/null +++ b/lib/doc/lfun/lib/shell/SetFirearmType @@ -0,0 +1,26 @@ +SETFIREARMTYPE + +NAME + SetFirearmType() + +SYNOPSIS + int SetFirearmType(string str) + +DESCRIPTION + If the firearm type is set on a clip or a round, they must match in order to be compatible. This function defines the string for that information. + +EXAMPLES + SetFirearmType("auto") + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetAmmoType, SetAmmoType, GetFirearmType + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/shell/SetMillimeter b/lib/doc/lfun/lib/shell/SetMillimeter new file mode 100644 index 0000000..9b33f96 --- /dev/null +++ b/lib/doc/lfun/lib/shell/SetMillimeter @@ -0,0 +1,26 @@ +SETMILLIMETER + +NAME + SetMillimeter() + +SYNOPSIS + int SetMillimeter(int x) + +DESCRIPTION + Millimeter is a measurement of ammunition size, different from caliber. If this is set on a round or a firearm, then the round and firearm must match millimeter definition in order to be compatible. + +EXAMPLES + SetMillimeter(9) + +LOCATION + /lib/round +/lib/firearm +/lib/shell +/lib/clip + +SEE ALSO + GetCaliber, SetCaliber, GetMillimeter + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/spell/GetMorality b/lib/doc/lfun/lib/spell/GetMorality new file mode 100644 index 0000000..ae13485 --- /dev/null +++ b/lib/doc/lfun/lib/spell/GetMorality @@ -0,0 +1,24 @@ +GETMORALITY + +NAME + GetMorality() + +SYNOPSIS + int GetMorality() + +DESCRIPTION + Returns the morality of the object. + +EXAMPLES + + +LOCATION + /lib/classes +/lib/spell + +SEE ALSO + SetMorality + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/spell/GetSkills b/lib/doc/lfun/lib/spell/GetSkills new file mode 100644 index 0000000..dbaaa79 --- /dev/null +++ b/lib/doc/lfun/lib/spell/GetSkills @@ -0,0 +1,27 @@ +GETSKILLS + +NAME + GetSkills() + +SYNOPSIS + LIB_SPELL, LIB_ABILITIES: string array GetSkills() ; LIB_POTION, LIB_BONUS: mapping GetSkills() + +DESCRIPTION + For LIB_ABILITIES this lfun returns the list of skill names possessed by the creature it's called in, such as "knife defense", etc. For LIB_SPELL this returns a list of the skills required to be able to cast the spell. For LIB_POTION and LIB_BONUS, this lfun works much like GetStats(), in that it returns a mapping of skills and how they are modified when a potion is drunk. + +EXAMPLES + + +LOCATION + /lib/bonus +/lib/lvs/abilities +/lib/potion +/lib/spell + + +SEE ALSO + GetStats, SetSkill + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/spell/SetMorality b/lib/doc/lfun/lib/spell/SetMorality new file mode 100644 index 0000000..14275ea --- /dev/null +++ b/lib/doc/lfun/lib/spell/SetMorality @@ -0,0 +1,24 @@ +SETMORALITY + +NAME + SetMorality() + +SYNOPSIS + int SetMorality(int x) + +DESCRIPTION + Sets the morality of the object. + +EXAMPLES + + +LOCATION + /lib/classes +/lib/spell + +SEE ALSO + GetMorality + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/spell/SetSkills b/lib/doc/lfun/lib/spell/SetSkills new file mode 100644 index 0000000..2a3c39d --- /dev/null +++ b/lib/doc/lfun/lib/spell/SetSkills @@ -0,0 +1,26 @@ +SETSKILLS + +NAME + SetSkills() + +SYNOPSIS + mapping SetSkills(mapping mp) + +DESCRIPTION + For LIB_SPELL this sets the required skills to be able to cast a spell, and the required level for each skill. For LIB_POTION and LIB_BONUS, this sets the skills altered by drinking the potion. + +EXAMPLES + SetSkills( ([ "cleverness" : 1 ]) ) + +LOCATION + /lib/bonus +/lib/potion +/lib/spell + + +SEE ALSO + GetSkills, SetStats, GetStats + +Author + Cratylus + diff --git a/lib/doc/lfun/lib/torch/GetLong b/lib/doc/lfun/lib/torch/GetLong new file mode 100644 index 0000000..097c124 --- /dev/null +++ b/lib/doc/lfun/lib/torch/GetLong @@ -0,0 +1,47 @@ +GETLONG + +NAME + GetLong() + + + +SYNOPSIS + string GetLong(string str) + + + +DESCRIPTION + Returns the "long desciption" of the object it's called in. This long description is the main part of what the player sees when they "look at" something. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/bot +/lib/creator +/lib/donate +/lib/door +/lib/fuel +/lib/interactive +/lib/lamp +/lib/npc +/lib/player +/lib/torch +/lib/events/look +/lib/std/room + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/vendor/eventBuy b/lib/doc/lfun/lib/vendor/eventBuy new file mode 100644 index 0000000..0a8b2f5 --- /dev/null +++ b/lib/doc/lfun/lib/vendor/eventBuy @@ -0,0 +1,36 @@ +EVENTBUY + +NAME + eventBuy() + + + +SYNOPSIS + LIB_BODY: varargs mixed eventBuy(mixed arg1, mixed arg2, mixed arg3) LIB_VENDOR: mixed eventBuy(object who, object *obs) + + + +DESCRIPTION + In LIB_BODY, this is a function designed to return an error. If the creature is supposed to be able to do something with this function (such as vendors), it should be overridden with the appropriate code. LIB_VENDOR: This is called when someone tries to sell something to the vendor. The seller is who, and the items being sold is *obs. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/std/vendor + + +SEE ALSO + eventSell + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/virt_sky/CanFly b/lib/doc/lfun/lib/virt_sky/CanFly new file mode 100644 index 0000000..1fe52ae --- /dev/null +++ b/lib/doc/lfun/lib/virt_sky/CanFly @@ -0,0 +1,37 @@ +CANFLY + +NAME + CanFly() + + + +SYNOPSIS + int CanFly() + + + +DESCRIPTION + In npc's, checks to see whether the creature is capable of flight. A return of 1 is yes, a return of 0 is no. In rooms, the default is for a room to permit a flying creature to fly in or out. If CanFly returns 0, that behavior is restricted. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/std/room +/lib/virtual/virt_sky + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/weapon/GetWielded b/lib/doc/lfun/lib/weapon/GetWielded new file mode 100644 index 0000000..89c706f --- /dev/null +++ b/lib/doc/lfun/lib/weapon/GetWielded @@ -0,0 +1,36 @@ +GETWIELDED + +NAME + GetWielded() + + + +SYNOPSIS + LIB_BODY: varargs mixed GetWielded(string limb) LIB_WEAPON: int GetWielded() + + + +DESCRIPTION + LIB_BODY: With no argument, returns the objects wielded by the creature. If the argument is a limb, this function returns what is wielded in that limb, if anything. LIB_WEAPON: If the weapon is wielded, this function returns 1. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/comp/weapon + + +SEE ALSO + GetWieldingLimbs + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/worn_storage/GetFingers b/lib/doc/lfun/lib/worn_storage/GetFingers new file mode 100644 index 0000000..a4c6549 --- /dev/null +++ b/lib/doc/lfun/lib/worn_storage/GetFingers @@ -0,0 +1,37 @@ +GETFINGERS + +NAME + GetFingers() + + + +SYNOPSIS + LIB_BODY: int GetFingers(string limb) LIB_ARMOR: int GetFingers() + + + +DESCRIPTION + For creatures, returns the number of fingers on the given limb. For armor, returns the number of fingers required to wear the item. + + + +EXAMPLES + + + + +LOCATION + /lib/body +/lib/std/armor +/lib/std/worn_storage + + +SEE ALSO + AddFingers + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/worn_storage/SetFingers b/lib/doc/lfun/lib/worn_storage/SetFingers new file mode 100644 index 0000000..b2419a0 --- /dev/null +++ b/lib/doc/lfun/lib/worn_storage/SetFingers @@ -0,0 +1,31 @@ +SETFINGERS + +NAME + + + +SYNOPSIS + + + +DESCRIPTION + + + +EXAMPLES + + + +LOCATION + /lib/std/armor +/lib/std/worn_storage + + +SEE ALSO + + + +Author + Cratylus + + diff --git a/lib/doc/lfun/lib/worn_storage/eventReceiveDamage b/lib/doc/lfun/lib/worn_storage/eventReceiveDamage new file mode 100644 index 0000000..b72a68f --- /dev/null +++ b/lib/doc/lfun/lib/worn_storage/eventReceiveDamage @@ -0,0 +1,39 @@ +EVENTRECEIVEDAMAGE + +NAME + eventReceiveDamage() + + + +SYNOPSIS + varargs int eventReceiveDamage(object agent, int type, int x, int internal, mixed limbs) + + + +DESCRIPTION + What sometimes happens to good people. + + + +EXAMPLES + orc->eventReceiveDamage(this_player(), BLADE, 100, 0, ({ "head", "neck" }) ) + + + +LOCATION + /lib/body +/lib/combat +/lib/props/deterioration +/lib/std/armor +/lib/std/worn_storage + + +SEE ALSO + + + + +Author + Cratylus + + diff --git a/lib/doc/lpc/basic/Contents b/lib/doc/lpc/basic/Contents new file mode 100644 index 0000000..0dd4efb --- /dev/null +++ b/lib/doc/lpc/basic/Contents @@ -0,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 --git a/lib/doc/lpc/basic/Introduction b/lib/doc/lpc/basic/Introduction new file mode 100644 index 0000000..6231f54 --- /dev/null +++ b/lib/doc/lpc/basic/Introduction @@ -0,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 --git a/lib/doc/lpc/basic/chapter1 b/lib/doc/lpc/basic/chapter1 new file mode 100644 index 0000000..6f233d0 --- /dev/null +++ b/lib/doc/lpc/basic/chapter1 @@ -0,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 --git a/lib/doc/lpc/basic/chapter2 b/lib/doc/lpc/basic/chapter2 new file mode 100644 index 0000000..72cb44f --- /dev/null +++ b/lib/doc/lpc/basic/chapter2 @@ -0,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 --git a/lib/doc/lpc/basic/chapter3 b/lib/doc/lpc/basic/chapter3 new file mode 100644 index 0000000..f7e89a4 --- /dev/null +++ b/lib/doc/lpc/basic/chapter3 @@ -0,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 --git a/lib/doc/lpc/basic/chapter4 b/lib/doc/lpc/basic/chapter4 new file mode 100644 index 0000000..4f44cdc --- /dev/null +++ b/lib/doc/lpc/basic/chapter4 @@ -0,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 --git a/lib/doc/lpc/basic/chapter5 b/lib/doc/lpc/basic/chapter5 new file mode 100644 index 0000000..ab7e22e --- /dev/null +++ b/lib/doc/lpc/basic/chapter5 @@ -0,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 --git a/lib/doc/lpc/basic/chapter6 b/lib/doc/lpc/basic/chapter6 new file mode 100644 index 0000000..aa1b00b --- /dev/null +++ b/lib/doc/lpc/basic/chapter6 @@ -0,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 --git a/lib/doc/lpc/basic/chapter7 b/lib/doc/lpc/basic/chapter7 new file mode 100644 index 0000000..909686d --- /dev/null +++ b/lib/doc/lpc/basic/chapter7 @@ -0,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 --git a/lib/doc/lpc/basic/chapter8 b/lib/doc/lpc/basic/chapter8 new file mode 100644 index 0000000..5077575 --- /dev/null +++ b/lib/doc/lpc/basic/chapter8 @@ -0,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 --git a/lib/doc/lpc/concepts/MudOSdriver b/lib/doc/lpc/concepts/MudOSdriver new file mode 100644 index 0000000..2f73545 --- /dev/null +++ b/lib/doc/lpc/concepts/MudOSdriver @@ -0,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 --git a/lib/doc/lpc/concepts/defines b/lib/doc/lpc/concepts/defines new file mode 100644 index 0000000..1be8bc8 --- /dev/null +++ b/lib/doc/lpc/concepts/defines @@ -0,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 --git a/lib/doc/lpc/concepts/efun b/lib/doc/lpc/concepts/efun new file mode 100644 index 0000000..2a56d4d --- /dev/null +++ b/lib/doc/lpc/concepts/efun @@ -0,0 +1,9 @@ +efuns are functions available to all objects on the +mud. Any object may need to know what time() it is, so rather +than have a time() function in every file that needs it, which +could be many, there is a time() function built into the +game that any object can use. An efun is built into the +driver, so there is no LPC code to look at. Because they +are compiled code, they tend to be very fast. + +See also: efuns, sefun, sefuns, lfun, lfuns, showfuns, findfun diff --git a/lib/doc/lpc/concepts/heredoc b/lib/doc/lpc/concepts/heredoc new file mode 100644 index 0000000..3a9e4d5 --- /dev/null +++ b/lib/doc/lpc/concepts/heredoc @@ -0,0 +1,75 @@ +Heredoc is a way to format text and is part of the preprocessor. +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 --git a/lib/doc/lpc/concepts/lfun b/lib/doc/lpc/concepts/lfun new file mode 100644 index 0000000..45beeb3 --- /dev/null +++ b/lib/doc/lpc/concepts/lfun @@ -0,0 +1,9 @@ +lfuns are functions specific to library objects. A shirt, +for example, has functions that a sword may not need, so +the LIB_ARMOR and LIB_WEAPON files contain their own functions, +not shared by other files (it's more complicated than this, +but that's the idea). These functions are library +functions, or lfuns. Typically they are found in the objects +defined by the files in /lib. + +See also: efun, efuns, sefun, sefuns, lfuns, showfuns, findfun diff --git a/lib/doc/lpc/concepts/lpc b/lib/doc/lpc/concepts/lpc new file mode 100644 index 0000000..d35ce2a --- /dev/null +++ b/lib/doc/lpc/concepts/lpc @@ -0,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 --git a/lib/doc/lpc/concepts/mappings b/lib/doc/lpc/concepts/mappings new file mode 100644 index 0000000..d2678f4 --- /dev/null +++ b/lib/doc/lpc/concepts/mappings @@ -0,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 --git a/lib/doc/lpc/concepts/message_doc b/lib/doc/lpc/concepts/message_doc new file mode 100644 index 0000000..9546fec --- /dev/null +++ b/lib/doc/lpc/concepts/message_doc @@ -0,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 --git a/lib/doc/lpc/concepts/objects b/lib/doc/lpc/concepts/objects new file mode 100644 index 0000000..b0ce294 --- /dev/null +++ b/lib/doc/lpc/concepts/objects @@ -0,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 --git a/lib/doc/lpc/concepts/oop b/lib/doc/lpc/concepts/oop new file mode 100644 index 0000000..d2fb90e --- /dev/null +++ b/lib/doc/lpc/concepts/oop @@ -0,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 --git a/lib/doc/lpc/concepts/preprocessor b/lib/doc/lpc/concepts/preprocessor new file mode 100644 index 0000000..9a1d4e8 --- /dev/null +++ b/lib/doc/lpc/concepts/preprocessor @@ -0,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 --git a/lib/doc/lpc/concepts/sefun b/lib/doc/lpc/concepts/sefun new file mode 100644 index 0000000..6aac205 --- /dev/null +++ b/lib/doc/lpc/concepts/sefun @@ -0,0 +1,8 @@ +sefuns are functions available to all objects on the +mud. Any object may need to tell to a player, so a convenient +tell_player() sefun is made available as a global function to +all objects, in the form of a sefun, or "simulated efun", which +is in LPC rather than compiled code in the driver. +sefuns are kept in /secure/sefun. + +See also: efun, efuns, sefuns, lfun, lfuns, showfuns, findfun diff --git a/lib/doc/lpc/concepts/simul_efun b/lib/doc/lpc/concepts/simul_efun new file mode 100644 index 0000000..4f9929b --- /dev/null +++ b/lib/doc/lpc/concepts/simul_efun @@ -0,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 --git a/lib/doc/lpc/concepts/socket_efuns b/lib/doc/lpc/concepts/socket_efuns new file mode 100644 index 0000000..64c9a1d --- /dev/null +++ b/lib/doc/lpc/concepts/socket_efuns @@ -0,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 --git a/lib/doc/lpc/constructs/for b/lib/doc/lpc/constructs/for new file mode 100644 index 0000000..894af2c --- /dev/null +++ b/lib/doc/lpc/constructs/for @@ -0,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 --git a/lib/doc/lpc/constructs/function b/lib/doc/lpc/constructs/function new file mode 100644 index 0000000..08f616a --- /dev/null +++ b/lib/doc/lpc/constructs/function @@ -0,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 --git a/lib/doc/lpc/constructs/if b/lib/doc/lpc/constructs/if new file mode 100644 index 0000000..40d927b --- /dev/null +++ b/lib/doc/lpc/constructs/if @@ -0,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 --git a/lib/doc/lpc/constructs/include b/lib/doc/lpc/constructs/include new file mode 100644 index 0000000..a4eece9 --- /dev/null +++ b/lib/doc/lpc/constructs/include @@ -0,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 --git a/lib/doc/lpc/constructs/inherit b/lib/doc/lpc/constructs/inherit new file mode 100644 index 0000000..bc59bbf --- /dev/null +++ b/lib/doc/lpc/constructs/inherit @@ -0,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 --git a/lib/doc/lpc/constructs/prototypes b/lib/doc/lpc/constructs/prototypes new file mode 100644 index 0000000..fd14208 --- /dev/null +++ b/lib/doc/lpc/constructs/prototypes @@ -0,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 --git a/lib/doc/lpc/constructs/switch b/lib/doc/lpc/constructs/switch new file mode 100644 index 0000000..b1a7dc7 --- /dev/null +++ b/lib/doc/lpc/constructs/switch @@ -0,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 --git a/lib/doc/lpc/constructs/while b/lib/doc/lpc/constructs/while new file mode 100644 index 0000000..2770dda --- /dev/null +++ b/lib/doc/lpc/constructs/while @@ -0,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 --git a/lib/doc/lpc/etc/error_msgs b/lib/doc/lpc/etc/error_msgs new file mode 100644 index 0000000..529304a --- /dev/null +++ b/lib/doc/lpc/etc/error_msgs @@ -0,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 --git a/lib/doc/lpc/intermediate/Contents b/lib/doc/lpc/intermediate/Contents new file mode 100644 index 0000000..ff58a8a --- /dev/null +++ b/lib/doc/lpc/intermediate/Contents @@ -0,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 --git a/lib/doc/lpc/intermediate/Copyright b/lib/doc/lpc/intermediate/Copyright new file mode 100644 index 0000000..29a2620 --- /dev/null +++ b/lib/doc/lpc/intermediate/Copyright @@ -0,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 --git a/lib/doc/lpc/intermediate/chapter1 b/lib/doc/lpc/intermediate/chapter1 new file mode 100644 index 0000000..6c459cd --- /dev/null +++ b/lib/doc/lpc/intermediate/chapter1 @@ -0,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 --git a/lib/doc/lpc/intermediate/chapter2 b/lib/doc/lpc/intermediate/chapter2 new file mode 100644 index 0000000..9f5c20b --- /dev/null +++ b/lib/doc/lpc/intermediate/chapter2 @@ -0,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 --git a/lib/doc/lpc/intermediate/chapter3 b/lib/doc/lpc/intermediate/chapter3 new file mode 100644 index 0000000..5ab4b40 --- /dev/null +++ b/lib/doc/lpc/intermediate/chapter3 @@ -0,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 --git a/lib/doc/lpc/intermediate/chapter4 b/lib/doc/lpc/intermediate/chapter4 new file mode 100644 index 0000000..f0d2f0a --- /dev/null +++ b/lib/doc/lpc/intermediate/chapter4 @@ -0,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 --git a/lib/doc/lpc/intermediate/chapter5 b/lib/doc/lpc/intermediate/chapter5 new file mode 100644 index 0000000..3d057ad --- /dev/null +++ b/lib/doc/lpc/intermediate/chapter5 @@ -0,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 --git a/lib/doc/lpc/intermediate/chapter6 b/lib/doc/lpc/intermediate/chapter6 new file mode 100644 index 0000000..02f3695 --- /dev/null +++ b/lib/doc/lpc/intermediate/chapter6 @@ -0,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 --git a/lib/doc/lpc/intermediate/chapter7 b/lib/doc/lpc/intermediate/chapter7 new file mode 100644 index 0000000..aa8cc0e --- /dev/null +++ b/lib/doc/lpc/intermediate/chapter7 @@ -0,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 --git a/lib/doc/lpc/types/array.2d b/lib/doc/lpc/types/array.2d new file mode 100644 index 0000000..6950b09 --- /dev/null +++ b/lib/doc/lpc/types/array.2d @@ -0,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 --git a/lib/doc/lpc/types/buffer b/lib/doc/lpc/types/buffer new file mode 100644 index 0000000..6308665 --- /dev/null +++ b/lib/doc/lpc/types/buffer @@ -0,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 --git a/lib/doc/lpc/types/float b/lib/doc/lpc/types/float new file mode 100644 index 0000000..dbb607b --- /dev/null +++ b/lib/doc/lpc/types/float @@ -0,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 --git a/lib/doc/lpc/types/function b/lib/doc/lpc/types/function new file mode 100644 index 0000000..4db14ed --- /dev/null +++ b/lib/doc/lpc/types/function @@ -0,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 --git a/lib/doc/lpc/types/general b/lib/doc/lpc/types/general new file mode 100644 index 0000000..d2d02e1 --- /dev/null +++ b/lib/doc/lpc/types/general @@ -0,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 --git a/lib/doc/lpc/types/mappings b/lib/doc/lpc/types/mappings new file mode 100644 index 0000000..04d6979 --- /dev/null +++ b/lib/doc/lpc/types/mappings @@ -0,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 --git a/lib/doc/manual/chapter01 b/lib/doc/manual/chapter01 new file mode 100644 index 0000000..008d695 --- /dev/null +++ b/lib/doc/manual/chapter01 @@ -0,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 --git a/lib/doc/manual/chapter02 b/lib/doc/manual/chapter02 new file mode 100644 index 0000000..ada33e9 --- /dev/null +++ b/lib/doc/manual/chapter02 @@ -0,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 --git a/lib/doc/manual/chapter03 b/lib/doc/manual/chapter03 new file mode 100644 index 0000000..4bc3b79 --- /dev/null +++ b/lib/doc/manual/chapter03 @@ -0,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 --git a/lib/doc/manual/chapter04 b/lib/doc/manual/chapter04 new file mode 100644 index 0000000..0af84bd --- /dev/null +++ b/lib/doc/manual/chapter04 @@ -0,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 --git a/lib/doc/manual/chapter05 b/lib/doc/manual/chapter05 new file mode 100644 index 0000000..769cf4d --- /dev/null +++ b/lib/doc/manual/chapter05 @@ -0,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 --git a/lib/doc/manual/chapter06 b/lib/doc/manual/chapter06 new file mode 100644 index 0000000..9894134 --- /dev/null +++ b/lib/doc/manual/chapter06 @@ -0,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 --git a/lib/doc/manual/chapter07 b/lib/doc/manual/chapter07 new file mode 100644 index 0000000..2139240 --- /dev/null +++ b/lib/doc/manual/chapter07 @@ -0,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 --git a/lib/doc/manual/chapter08 b/lib/doc/manual/chapter08 new file mode 100644 index 0000000..644c0ea --- /dev/null +++ b/lib/doc/manual/chapter08 @@ -0,0 +1,198 @@ +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. +// CORRECTION: move_object() does not take two arguments in recent +// versions of MudOS. -Crat 24Feb2007 + +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 --git a/lib/doc/manual/chapter09 b/lib/doc/manual/chapter09 new file mode 100644 index 0000000..7b05b6f --- /dev/null +++ b/lib/doc/manual/chapter09 @@ -0,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 --git a/lib/doc/manual/chapter10 b/lib/doc/manual/chapter10 new file mode 100644 index 0000000..d559d78 --- /dev/null +++ b/lib/doc/manual/chapter10 @@ -0,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 --git a/lib/doc/manual/chapter11 b/lib/doc/manual/chapter11 new file mode 100644 index 0000000..51eed67 --- /dev/null +++ b/lib/doc/manual/chapter11 @@ -0,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 --git a/lib/doc/manual/chapter12 b/lib/doc/manual/chapter12 new file mode 100644 index 0000000..58d8736 --- /dev/null +++ b/lib/doc/manual/chapter12 @@ -0,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 --git a/lib/doc/manual/chapter13 b/lib/doc/manual/chapter13 new file mode 100644 index 0000000..78447c7 --- /dev/null +++ b/lib/doc/manual/chapter13 @@ -0,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 --git a/lib/doc/manual/chapter14 b/lib/doc/manual/chapter14 new file mode 100644 index 0000000..45438a2 --- /dev/null +++ b/lib/doc/manual/chapter14 @@ -0,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 --git a/lib/doc/manual/chapter15 b/lib/doc/manual/chapter15 new file mode 100644 index 0000000..df774d8 --- /dev/null +++ b/lib/doc/manual/chapter15 @@ -0,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 --git a/lib/doc/manual/chapter16 b/lib/doc/manual/chapter16 new file mode 100644 index 0000000..8bdfb05 --- /dev/null +++ b/lib/doc/manual/chapter16 @@ -0,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 --git a/lib/doc/manual/chapter17 b/lib/doc/manual/chapter17 new file mode 100644 index 0000000..58af549 --- /dev/null +++ b/lib/doc/manual/chapter17 @@ -0,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 --git a/lib/doc/manual/chapter18 b/lib/doc/manual/chapter18 new file mode 100644 index 0000000..9879a7e --- /dev/null +++ b/lib/doc/manual/chapter18 @@ -0,0 +1,8 @@ +chapter 18 "Valid climates" + +indoors +temperate +arid +arctic +tropical +sub-tropical diff --git a/lib/doc/manual/chapter19 b/lib/doc/manual/chapter19 new file mode 100644 index 0000000..bf904fd --- /dev/null +++ b/lib/doc/manual/chapter19 @@ -0,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 --git a/lib/doc/manual/chapter20 b/lib/doc/manual/chapter20 new file mode 100644 index 0000000..38cd9ce --- /dev/null +++ b/lib/doc/manual/chapter20 @@ -0,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 --git a/lib/doc/manual/chapter21 b/lib/doc/manual/chapter21 new file mode 100644 index 0000000..54fbfe3 --- /dev/null +++ b/lib/doc/manual/chapter21 @@ -0,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 --git a/lib/doc/manual/chapter22 b/lib/doc/manual/chapter22 new file mode 100644 index 0000000..6f4b8b7 --- /dev/null +++ b/lib/doc/manual/chapter22 @@ -0,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 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 --git a/lib/doc/manual/chapter23 b/lib/doc/manual/chapter23 new file mode 100644 index 0000000..f0ad031 --- /dev/null +++ b/lib/doc/manual/chapter23 @@ -0,0 +1,94 @@ +chapter 23 "Properties" + 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 --git a/lib/doc/manual/chapter24 b/lib/doc/manual/chapter24 new file mode 100644 index 0000000..6209f22 --- /dev/null +++ b/lib/doc/manual/chapter24 @@ -0,0 +1,36 @@ +chapter 24 "Quests" + 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 --git a/lib/doc/manual/chapter25 b/lib/doc/manual/chapter25 new file mode 100644 index 0000000..ddea0c3 --- /dev/null +++ b/lib/doc/manual/chapter25 @@ -0,0 +1,488 @@ +chapter 25 "Rooms" + 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 --git a/lib/doc/manual/chapter26 b/lib/doc/manual/chapter26 new file mode 100644 index 0000000..983cf15 --- /dev/null +++ b/lib/doc/manual/chapter26 @@ -0,0 +1,236 @@ +chapter 26 "Sentients" + 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 --git a/lib/doc/manual/chapter27 b/lib/doc/manual/chapter27 new file mode 100644 index 0000000..2c11b81 --- /dev/null +++ b/lib/doc/manual/chapter27 @@ -0,0 +1,91 @@ +chapter 27 "Towns" + 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 --git a/lib/doc/manual/chapter28 b/lib/doc/manual/chapter28 new file mode 100644 index 0000000..09c30fc --- /dev/null +++ b/lib/doc/manual/chapter28 @@ -0,0 +1,64 @@ +chapter 28 "Vendors" + 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 --git a/lib/doc/manual/chapter29 b/lib/doc/manual/chapter29 new file mode 100644 index 0000000..8abea32 --- /dev/null +++ b/lib/doc/manual/chapter29 @@ -0,0 +1,213 @@ +chapter 29 "Weapons" + 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 --git a/lib/doc/manual/chapter30 b/lib/doc/manual/chapter30 new file mode 100644 index 0000000..2aa31c2 --- /dev/null +++ b/lib/doc/manual/chapter30 @@ -0,0 +1,205 @@ +chapter 30 "The Natural Language Parser" + The Natural Language Parser + +The Problem +A gut reaction to this entire system is to be overwhelmed by its apparent complexity, comparing it to the good-old days of using add_action(). A discussion of the natural language parsing system therefore needs to start by answering the question, "Why bother?". + +The old way of handling user input was to define commands and tie them to functions using add_action. Each user object kept track which commands it had available to it, and of which functions each command would trigger. The list of commands changed each time the player object (really, any object which had enable_commands() called in it) moved. In addition, each time an object moved inside the player object or left its inventory, this list changed. + +This led to two basic problems: + + 1. The same command might have slightly different uses in different parts of the mud. Or worse, the player could have two similar objects which define the same command in slightly different ways. + 2. The complexity of syntax varied based on creator abilities and was limited by CPU. + +For example, one creator could have created a rock in their area that added the 'throw' command. This creator is a newbie creator, and thus simply put the following code in their throw_rock() function: + +int throw_rock(string str) { + object ob; + + if( !str ) return 0; + ob = present(str, this_player()); + if( !ob ) { + notify_fail("You have no rock!"); + return 0; + } + if( ob != this_object() ) return 0; + if( (int)ob->move(environment(this_player())) != MOVE_OK ) { + write("You cannot throw it for some reason."); + return 1; + } + write("You throw the rock."); + say((string)this_player()->query_cap_name() + " throws the rock."); + return 1; +} + +In this case, "throw rock" will work, but "throw the granite rock at tommy" will not. But another creator also defined a throw command in their spear. This creator however, is a good coder and codes their throw_spear() command to handle 'throw the red spear at tommy' as well as 'throw spear'. Explain to a player why both syntaxes only work for the spear, and not for the rock. Then explain to that player why 'throw rock' for a rock built in yet another area yields 'What?'. + +An early attempt to get around this problem was the parse_command(). Unfortunately it was buggy spaghetti that was way too complex for anyone to understand. The MudOS attempt to solve this problem is its new natural language command parser. The parser is based on the following assumptions: + +All commands should behave in a consistent manner across the mud. +Similar objects should respond as expected to the same command line. +A player should only see 'What?' (or its equivalent) when they make a typo. +It should enable creators to handle the complex command processing required by the above assumption. + +Overview of the MudOS System +The MudOS natural language parser is based on a philosophy of centralized command parsing. In other words, creators have no control over which commands exist nor over what syntax rules existing commands follow. Instead, creators are tasked with defining what those commands mean to their objects. Unlike with add_action() where commands are registered to the driver, the MudOS system registers verbs (the command) and rules with the driver. In this example, a simple "smile" verb is registered with a single rule, "at LIV". + +With the old way of doing things, commands were executed either when a player entered in a command or when the command() efun was called. With this new system, a command may be executed at any time via either the parse_sentence() or parse_my_rules() efuns. + +When one of those efuns is called, the driver searches through the list of verbs for a verb and rule which matches the command string. In order to do that, however, it needs to make several calls of all the objects involved to determine what the sentence means. For any given command string, the following objects are relevant to the parsing of that command string: + +the verb handler + This object contains the functions used to see if the command is valid and to execute it. It is also the one that creates the rules for the verb. + +the subject + This is the object from which parse_sentence() is called, or the object mentioned as the first argument in parse_my_rules(). It is the object considered to be executing the command in questin, the logical subject of the sentence. + +the master object + This object keeps track of global information, such was what literals (mistakenly referred to as prepositions) exist across the mud. In general, a literal is a preposition. + +the direct object + This is not the logical direct object of the sentence. Rather, this is the first object at which the verb action is targetted. + +the indirect object + Again, this is not the logical indirect object of the sentence. Rather, it is the second object at which the verb action is targetted. For example, in "give the book to the elf", the elf will be both the logical indirect object and the parser indirect object. But if you allow "give the elf the book", the elf naturally still remains the logical indirect object, but the book is the indirect object to the parser since it is the second object targetted by the verb (the first being the elf). + +Each object involved in he parsing of a sentence, except the subject, is responsible for handling certain driver applies that help the driver in parsing the sentence. The subject, unlike the other objects, is responsible for initiating the command. Although this document treats all of these objects as if they were completely distinct, it is possible to have the same object performing multiple roles for the same command. For example, your subject could also be direct object and verb handler. The next section discusses the objects and the applies they are responsible for in detail. + +The Objects +Before studying each object in detail, it is important to keep in mind that each object which can be involved in any role must call parse_init() before doing anything related to verb parsing. The only exception is the master object. + +The subject +The subject is simply the initiator of a command. A command is typically initiated by a call to parse_sentence() inside the object's process_input() apply. This example shows how a player object might use parse_sentence() to initiate a command. This efun will return 1 if the command successfully matched a known verb and rule and successfully executed it. If it found the verb in question, but it did not match any rule, then 0 is returned. If it found the verb in question and matched a rule, but the execution of the rule failed, it will return an errorstring describing why it failed. Finally, if no verb matched the command, then -1 is returned. + +Take for example a mud with this one rule: + +parse_add_rule("smile", "at LIV") + +The efun parse_sentence() would return the following values for the following command lines: + +smile at descartes + Returns: 1 +smile happily + Returns: 0 +smile at the red box + Returns: "The Box is not a living thing!" +eat the red box + Returns: -1 + +The master object +The master object is responsible for a single apply, parse_command_prepos_list(). This apply returns a list of literal strings which may be used in a rule. A literal string is simply one that appears in the rule exactly as a player types it. In the smile example above, "at" is a literal. In most all cases, literals are prepositions, thus the name of the apply. + +The verb handler +The verb handler object is responsible for setting up the rules for a verb and handling the test and execution of those rules. This example demonstrates a simple verb handler for the smile verb described above. As you can see, each rule is divided up into three parts: + + 1. initialization + 2. testing + 3. execution + +The intialization is the call to parse_add_rule(). This associates a rule with a verb. The first argument is the verb (this verb may have spaces in it, like "look at") and the second argument is one of the rules being handled by this verb handler. This list defines the valid tokens for a rule. + +The testing portion is a "can" apply. In testing a rule, the driver calls the applies can_<verb_rule> to determine if the execution of the verb even makes sense in this situation. The test apply is called when the driver has valid arguments to a rule, but it wants to see if those valid arguments make sense right now. For example, you might check a player here to see if they have enough magic points for casting the spell this verb/rule represents. If not, you might return "You are too tired right now.". If the rule match up in question makes completely no sense at all, like for example, they tried to throw a house for the ("throw", "OBJ") rule, you should return 0. The parser will guess well an error message from the situation. In this case, it will have parse_sentence() return "You cannot throw the thing.". + +Finally execution is where the verb actually happens. You know you have a verb/rule match and you know all the arguments to it are valid. Now it is time to do something. You almost always want to return 1 from this function except in extreme circumstances. + +The direct and indirect objects +As stated above, the directness or indirectness of an object has nothing to do with the linguistic meaning of those terms. Instead it has to do with what position in the token list the object takes. The direct object is the first object in the token list, and the indirect object is the second object in the token list. + +These objects basically answer the question "Can I be the direct/indirect object for this verb and rule?". Like the testing and execution applies for verb handlers, the applies that answer this question may return 1, 0, or an error string. Also like the testing and execution applies for the verb handler, these come in the form of (in)direct_<verb>_<rule>(). This example is from somewhere inside the living object heirarchy. Note the is_living() apply which lets the parser know that the object matches a LIV token. + +Inventory visibility +Some objects are subjects, direct objects, or indirect objects of verbs which require access to things in their inventory. For example, living things, bags, chests, etc. all need to allow other things access to their inventories for some commands. Two applies handle this situation: + + 1. inventory_accessible() + 2. inventory_visible() + +The first returns 1 if verbs can have access to an object's inventory, the second returns 1 if verbs simply can take into account an object's inventory. An example of the difference might be a glass chest. When closed, you want its inventory to be visible, but not accessible. + +It is important to remember that is the return value for any of these special applies, including is_living(), you need to make an explicit call to the parse_refresh() efun. Unless the parse_refresh() efun is called, these special applies are only called once with no guarantee as to when that one call will actually occur. + +Creating a New Verb +Currently, the Lima and Nightmare mudlibs use this parser system. Both mudlibs provide inheritable objects which make it simpler to interface with the MudOS parser system. Nightmare specifically has the inheritable LIB_VERB with methods for defining a new verb. + +This verb example comes from the Nightmare mudlib. The simple Nightmare verb requires the following steps: + + 1. Name the verb + 2. State the verb rules + 3. Name any synonyms + 4. Set an error message for display when the command is wrongly used + 5. Create help text for the command + +Naming the verb is done through the SetVerb() method. You simply specify the name of the verb. + +The rules are passed to the SetRules() method. You may specify as many rules as are needed for the verb. + +Like rules, synonyms are set as a list for the SetSynonyms() method. A synonym is simply any verb which is exactly synonymous with any possible rule for the verb in question. The player is able to access help for the verb and get error messages for the verb through the verb or any of its synonyms. + +The error message is a string displayed to the user when they use the verb in an incorrect manner. For example, if I typed 'eat' when the rule is 'eat OBJ', the error message would be 'Eat what?'. + +Finally, like with any object, the help text can be set through the SetHelp() method. Help is very important for verbs. + +All of these methods only are able to take care of verb initalization. It is up to the verb creator to give meaning to a new verb. This is done first off by writing can_*() and do_*() applies in the verb handler. These methods should be very simplistic in nature. For example, a can method almost always simply returns 1. A do method generally finds its target and triggers some sort of event in that object. The event does the real command handling. + +In addition to can and do applies, you need also to write any direct and indirect applies in approperiate objects. Nightmare centralizes this sort of processing through inheritables geared towards responding to particular verbs. A good example of this is LIB_PRESS which responds to the "press" command. Thus any object which should be pressable needs only to inherit this object to become a pressable object. + +The can, do, direct, and indirect applies all have the same argument set for the same verb/rule pair, but it is important to know when the parser knows certan things. Take for example the verb/rule "press OBJ on OBJ". The parser takes the following actions: + + 1. Call can_press_obj_on_obj() in verb handler + 2. Call direct_press_obj_on_obj() in all accessible and visible objects + 3. Call indirect_press_obj_on_obj() in all accessible and visible objects + 4. Call do_press_obj_on_obj() in the verb handler + +The arguments to all methods called in this process are: + + 1. object direct_object + 2. object indirect_object + 3. string direct_object_as_entered_on_command_line + 4. string indirect_object_as_entered_on_command_line + +But how can can_press_obj_on_obj() know what the direct and indirect objects are if they have not been identified yet? The answer is that it cannot. For the command "push the button on the wall", in a room with me and you in it and we carry nothing, the sequence looks like this (return in parens): + + 1. verb->can_press_obj_on_obj(0, 0, "the button", "the wall"); (1) + 2. me->direct_press_obj_on_obj(0, 0, "the button", the wall"); (0) + 3. you->direct_press_obj_on_obj(0, 0, "the button", "the wall"); (0) + 4. room->direct_press_obj_on_obj(0, 0, "the button", "the wall"); (1) + 5. me->indirect_press_obj_on_obj(room, 0, "the button", "the wall"); (0) + 6. you->indirect_press_obj_on_obj(room, 0, "the button", "the wall"); (0) + 7. room->indirect_press_obj_on_obj(room, 0, "the button", "the wall"); (1) + 8. verb->do_press_obj_on_obj(room, room, "the buton", "the wall"); (1) + +This assumes, of course, that the room responds positively with the id's "button" and "wall". + +People familiar with the parser might say, "Hey, wait, there is a lot more that happens than just that." In fact, there are many more possible permutations of this sequence. The most interesting is the ability to simply ignore the difference between prepositions like "in" and "into" which are often used interchangeably in colloquial speech. For example, if you had "put OBJ in OBJ" and "put OBJ into OBJ" verb/rules, you could handle them in a single place for each of the applies respectively liek this: + +can_put_obj_word_obj() +direct_put_obj_word_obj() +indirect_put_obj_word_obj() +do_put_obj_word_obj() + +If the parser found no can_put_obj_in_obj() defined, it then searches for a more generic handler, can_put_obj_word_obj(). In fact the real order it searches for a can handler is: + + 1. can_put_obj_in_obj() + 2. can_put_obj_word_obj() + 3. can_put_rule() + 4. can_verb_rule() +--------------------- + +Last example: + +static void create() { + parse_init(); + parse_add_rule("smile", "at LIV"); +} + +mixed can_smile_at_liv(object target) { + return 1; +} + +mixed do_smile_at_liv(object target) { + previous_object()->eventPrint("You smile at " + + (string)target->GetName() + "."); + target->eventPrint((string)previous_object()->GetName() + + " smiles at you."); + return 1; +} + diff --git a/lib/doc/manual/chapter31 b/lib/doc/manual/chapter31 new file mode 100644 index 0000000..12d44be --- /dev/null +++ b/lib/doc/manual/chapter31 @@ -0,0 +1,47 @@ +chapter 31 "Overview of the Quick Creation System" + + First, let me clarify that the QCS is not intended to replace +good coding habits. It is also not designed to handle every possible +need of a builder. The QCS is just a handy tool for making the +most tedious parts of building easier. + + The amount of time it takes to hand-code an area of 100 rooms +(a small area, that is), with all the appropriate descriptions and +monsters and weapons and such is just mind-boggling. As a grown-up, +I just don't have time for building stuff line by excruciating line +in raw LPC, because I also need to work, maintain my house, say hello +to my family on occasion, etc. + + At the same time, I would need a team of dedicated LPC code +fetishists to make a creation system that covers every last possible +thing you could do in LPC. The QCS is somewhere in between those +two extremes. + + Therefore please view the QCS as a quick way to get bulk building +done, and not as a be-all end-all solution. You still need to learn +LPC to do really cool stuff. But to hammer out an area with a quest, +QCS lets you sail through the process of thingmaking with little hassle. + + The design philosophy of the system itself involves object files +stored in /secure/modules. These files are inherited by an object which +you need to carry with you in order to use the QCS system. The code +for these creation modules is fairly messy and inelegant, but the +result is clean, indented code that compiles, so let's keep the +mockery to a minimum, shall we? + + It is important to keep in mind the QCS isn't an editing system. +It's real live on-line modification, meaning that to modify a thing, +it actually has to be in the same room you are in, or it has to be that +room itself. + Once you modify something, it will typically update, so that if +you change the name of an npc, you're going to need to use the new name +to modify it further. + + The next few chapters in this manual are nominally QCS specific, +but in reality this is pretty much my only chance to document some +of the changes in Dead Souls since version 1, so even if you never +intend to use QCS, it's worth poking through these chapters. + +- Cratylus @ Frontiers +2 January 2006 + diff --git a/lib/doc/manual/chapter32 b/lib/doc/manual/chapter32 new file mode 100644 index 0000000..816a8c7 --- /dev/null +++ b/lib/doc/manual/chapter32 @@ -0,0 +1,50 @@ +chapter 32 "QCS: Commands" + + What with muds being text only, QCS has no fancy windowing system. +Using a menu-driven creation system was ruled out quickly due to the +vast complexity of the menus that would be required. Instead, QCS +relies on a few powerful commands. + +create + This is the command that gets the ball rolling. This command +is what lets you bring a new thing into existence. The things you can +create can be seen by typing "help create". Examples are rooms, weapons, +doors, and so on. We will be reviewing each of those in later chapters. + When you issue this command a generic version of the item you +wish to create appears (or, in the case of a room, appears in the +direction you specify). Once that generic copy materializes, you can +change it to suit your needs using the "modify" command. + +modify + I tend to regard this command as the heart and soul of QCS. It's +this tool that lets you make your world your own. Your new generic +things are not useful or fun until you modify them. A "generic weapon" +isn't very interesting, but a "mithrilite poleaxe" might be just the +thing to deal with a pesky dragon. + +add + Creatures, rooms, and containers are capable of storing other +things. Once you make an ogre, you may want to give him a hammer to +wield. After you make that hammer, you use the add command to let +the ogre have that wepon in his permanent inventory. + +delete + On the other hand, you may be tired of that ogre after a while. If +he is a part of the permanent inventory of a room, you can use the +delete command to remove him permanently. Or if you'd rather he have +a Kill-O-Zap Frogstar blaster rather than a hammer, get rid of the +hammer in his inventory with this command. + +copy + This is a room-specific command. Rather than write multiple, +nearly identical rooms for large areas, you can use the copy command to +make the room you are almost exactly like any other room you choose, +except for the exits, which remain the same. Handy for big forests, +cell-blocks, twisty mazes of little passages, etc. + +initfix + If a thing isn't working right, try to initfix it. "init()" is +an object function that many items need in order to work properly. If +you've run into something that is behaving unexpectedly, run initfix on +it. The trouble just might clear up. + diff --git a/lib/doc/manual/chapter33 b/lib/doc/manual/chapter33 new file mode 100644 index 0000000..fbd90ce --- /dev/null +++ b/lib/doc/manual/chapter33 @@ -0,0 +1,93 @@ +chapter 33 "QCS: Creation" + + Creation breaks down into three categories. "Things", rooms, and +doors. Let's look at things first: + +Thing creation: +--------------- + In this category we're including NPC's, weapon, armor, unspecial items, +tables, furniture, books and containers. Basically things that actually show +up somewhere. A door is a very special sort of object and does not fall +under this category. + + To make a new thing, the syntax looks like this: + +create THING FILENAME + + The THING is the category of item we are creating. The FILENAME is +the name of the file that will contain this item's configuration data. +You may enter an absolute path, or you may simply enter a filename. If +you enter a filename, QCS will attempt to figure out the best place +for this file. If your current working directory has a name QCS understands +as being compatible with the type of object you are making (for example, +your cwd is /realms/you/npc and you are making an NPC) it will use that. +Otherwise it will search parent and children directories for a +directory name it understands this way. Finally, if it can find no +compatible directories for your file near your cwd, it will put it in +the appropriate directory in your home area (in this case, +/realms/you/area/npc ). + Avoid a relative path. It probably won't work the way you think. + + When the command completes, FILENAME will be a file containing the +data for your generic thing, and a copy of that generic thing will appear +in the room you are in. + If, for example, you entered: + +%^GREEN%^create npc cowboy%^RESET%^ + + The room you are in will contain a generic NPC which *does not* +answer to the id of "cowboy". This NPC is just a generic NPC whose +filename is (probably) /realms/you/npc/cowboy.c and isn't yet a real +cowboy. You'll need to use the "modify" command to make a proper +cowboy out of him. + + +Room creation +------------- + + Naturally, if you create a room, a new room will not appear inside +your current environment. Instead, the syntax of the "create" command +is different when you want to create a new room. + + You may have noticed that you can't use the "create" command to make +a new room adjacent to your workroom. This is for your protection and +my sanity. Files which contain the directive "SetNoModify(1)" are +immune to QCS manipulation. + Rooms like your workroom, the default start room, the void room, etc, +are set nomodify. This is because if you screw it up, you will be +sorry, and I just don't want to hear it. + So, suppose then that you're in your sample room (one room east +of your workroom) and you want to make a new room. You might issue +the following command: + +%^GREEN%^create room south testroom1%^RESET%^ + + What this does is copy the room you are in (in this case, +/realms/you/area/sample_room.c) to a new location (perhaps +/realms/you/area/testroom1.c). But the neat thing is, this new room +does not have the same exits as the room you are in. The new room +has just one exit, leading back to where you are. + The net effect of all this is that when you issue this command, +you make a new room in the direction you specify, and this +new room looks just like the room you're in, only the exits are such +that you can travel back and forth between the rooms. + + +Door creation +------------- + + Doors are funny things. In Dead Souls, they aren't objects in the +conventional sense of a thing which occupies a room you're in. Rather, +they are really daemons which attach to adjoining rooms. If that doesn't +make sense to you, don't worry. You're not alone. + + The syntax for door creation is much like that for room creation. +After you create that room south of your sample room, you can now create +a door between them: + +%^GREEN%^create door south sample_door%^RESET%^ + + This brings into existence a generic door (closed by default) which +is between the two rooms. + + diff --git a/lib/doc/manual/chapter34 b/lib/doc/manual/chapter34 new file mode 100644 index 0000000..80dd7ff --- /dev/null +++ b/lib/doc/manual/chapter34 @@ -0,0 +1,328 @@ +chapter 34 "QCS: Modification of NPC's" + + In the previous chapter we learned how to make a generic object. +Now that we have it, what to do with it? + + It's important to keep in mind that the generic thing now in +front of you isn't just a clone from a template file. If the command +you used was "create npc cowboy", there is now a file (probably) +called /realms/you/area/npc/cowboy.c that contains the code for the +creature in front of you. + However, this poor beast has the most uninteresting of features. +It is in fact so boring that it responds only to its generic type. +Such that "examine cowboy" or "kill tex" won't work. You'll need to +"look at npc". + + Accordingly, any modification commands need to be made referring +to the new thing with an it responds to, until such a time as you +change the id to suit your tastes. Let's carry on with the example +of our generic npc. To make a cowboy out of him, we can either +change his name, or his id, or both. Let's start with his name: + +%^GREEN%^modify npc name cowboy%^RESET%^ + + This makes the SetKeyName() directive in cowboy.c use "cowboy" +as its argument, effectively allowing you to address this npc as "cowboy" +from now on. Now you can "look at cowboy" with some results. + Obviously our NPC isn't *just* a cowboy. He's also a human, a dude, +and his name is Tex. How do we make him respond to all of these nouns? + +%^GREEN%^modify cowboy id%^RESET%^ + + You'll notice there are no arguments following the word "id". Setting +a thing's id is different from most other settings. If you'll think back +to the LPC datatypes chapter of this manual (you did read the LPC +chapters, didn't you?) you'll remember that some information about +objects is in the form of strings ("cowboy"), some is in the form of +integers (the cowboy's health points, for example) and some is in the +form of arrays, which are a group of data points. In this example we +want the cowboy's id to be an array, because of the many ways we might +want to address him. Therefore, we want the SetId directive in his +file to look like this: + +SetId( ({"human", "dude", "tex" }) ); + + You might think that QCS should be able to accept multiple values +like this on a line, perhaps with "modify cowboy id human dude tex" as +the command. + But what if you want this npc to be a "Boy Named Sue"? How would +you accommodate id's that contain spaces? In designing QCS, I considered +having escape characters to allow for such things, but ultimately +reasoned that this was just way too much mess. Instead, SetId, and +other directives that take arrays as arguments, are handled by entering +a query session. Below is an example of what it might look like. The +example is necessarily messy because I am including both the queries +and the responses. + +--------------------------------------------------- +> %^GREEN%^modify npc name cowboy%^RESET%^ +Indenting file... +"/tmp/indent.1136206130.tmp.dat" 15 lines 420 bytes +Exit from ed. + +> %^GREEN%^modify cowboy 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%^human%^RESET%^ +You may now enter the next value. So far, we have: ({ "dude", "human" }) +If you're done entering values, enter a dot on a blank line. +%^GREEN%^tex%^RESET%^ +You may now enter the next value. So far, we have: ({ "dude", "human", "tex" }) +If you're done entering values, enter a dot on a blank line. +%^GREEN%^boy named sue%^RESET%^ +You may now enter the next value. So far, we have: ({ "dude", "human", "tex", +"boy named sue" }) +If you're done entering values, enter a dot on a blank line. +%^GREEN%^.%^RESET%^ +Entries complete. Final array is: ({ "dude", "human", "tex", "boy named sue" }) +Indenting file... +"/tmp/indent.1136206156.tmp.dat" 19 lines 459 bytes +Exit from ed. + +/open/1136206138: Ok +/realms/cratylus/area/npc/cowboy: Ok +SetId modification complete. +> %^GREEN%^exa tex%^RESET%^ +Other than being human, this npc is entirely unremarkable. +The male human is in top condition. +--------------------------------------------------- + + If you were now to examine Tex's code (with the command "about tex") +you'd see that his SetId directive now looks like this: + +SetId( ({"dude", "human", "tex", "boy named sue"}) ); + + Other NPC features take arrays also. SetAdjectives is one. You +might enter this (mud output omitted for clarity): + +%^GREEN%^modify tex adjectives%^RESET%^ +%^GREEN%^dusty%^RESET%^ +%^GREEN%^hardy%^RESET%^ +%^GREEN%^.%^RESET%^ +%^GREEN%^look at dusty cowboy%^RESET%^ + + There are two other directives that require queries. Things and +NPC's can be looked at, but they can also be smelled and listened +to, if you add SetSmell and SetListen. The syntax is: + +%^GREEN%^modify tex smell%^RESET%^ + + And you will then be asked a question about keys and mappings. +Understanding mappings is important, but for now you just need to +understand that you are being asked *two* separate questions: +1) What on the cowboy is being smelled/listened to? +2) What is the smell/sound? + + What this means is that your input will look something like +this: + +%^GREEN%^modify tex smell%^RESET%^ +%^GREEN%^default%^RESET%^ +%^GREEN%^.%^RESET%^ +Tex smells of sweat and manure. + + What happens is this: +- You enter the modify command. +- You enter the word "default" to indicate this is Tex's general smell. +- You enter a dot to indicate that you are done specifying what + part of Tex is being smelled. +- You then specify the smell. + + This may seem odd until you realize you can also add smells/listens to +parts of things. Not on NPC's, though. We'll look at this more closely in +later chapters. For now, just use the syntax as shown above. For adding +a listen to the cowboy, it works the same way: + +%^GREEN%^modify tex listen%^RESET%^ +%^GREEN%^default%^RESET%^ +%^GREEN%^.%^RESET%^ +Tex seems to be humming a jaunty melody. + + Other features of an NPC do not take arrays, so one-line commands +will do. For example: + +%^GREEN%^modify cowboy long This is a cowboy who calls himself Tex, but is in fact a Boy Named Sue.%^RESET%^ + +%^GREEN%^modify cowboy short a cowboy%^RESET%^ + +%^GREEN%^modify cowboy level 5%^RESET%^ + +%^GREEN%^modify cowboy class fighter%^RESET%^ + +%^GREEN%^modify tex currency gold 1%^RESET%^ + +%^GREEN%^modify tex currency silver 12%^RESET%^ + +%^GREEN%^modify tex skill bargaining 5%^RESET%^ + +%^GREEN%^modify tex skill projectile attack 7%^RESET%^ + +%^GREEN%^modify tex stat strength 33%^RESET%^ + +%^GREEN%^modify tex property nice guy 1%^RESET%^ + +%^GREEN%^modify tex healthpoints 150%^RESET%^ + +%^GREEN%^modify tex maxhealthpoints 170%^RESET%^ + +%^GREEN%^modify tex melee 0%^RESET%^ + +%^GREEN%^modify tex unique 1%^RESET%^ + + If you now issue the "about tex" command you will see that all +the changes you made have been put into the file. + + You may have noticed the "melee" keyword. Dead Souls 2 NPC's come +in various shapes and sizes, and some of them shouldn't wield weapons. A +wolf with a battle axe would be a strange sight indeed. However, the +default combat system makes unarmed creatures extremely vulnerable in +combat. + To make an NPC combat-capable without weapons, use the new SetMelee +directive. SetMelee(1) makes the NPC capable of proper unarmed combat. +SetMelee(0) makes the NPC a weak opponent if unarmed. + NPC's will generally try to bite during unarmed combat. If this +is beneath the capability or dignity of your NPC, you can prevent +this with: + +%^GREEN%^modify tex canbite 0%^RESET%^ + + If your NPC should try to escape when the battle isn't going +his way, the wimpy settings should do: + +%^GREEN%^modify tex wimpy 30%^RESET%^ + +%^GREEN%^modify tex wimpycommand climb ladder%^RESET%^ + + If you don't specify a wimpy command, Tex will leave the +room through a random exit. In this case, when Tex's health +is down to 30% and he is in combat, he will try to climb a ladder. + + Some NPC's are designed to travel about. To enable this +feature, use the wanderspeed directive: + +%^GREEN%^modify tex wanderspeed 5%^RESET%^ + + If you want him to travel more quickly, use a +lower number. By default, wandering NPC's only wander in rooms +that have already been loaded into memory. They avoid loading +rooms because loading a bunch of rooms that only the NPC +will ever see is a waste of your mud's resources. + However, if you *do* want your NPC to wander in an +unrestricted manner, regardless of whether a room is loaded, +use the permitload directive: + +%^GREEN%^modify tex permitload 1%^RESET%^ + + By default, NPC's stand up when they can. This is +so that if they collapse during combat, they try to +get back up once they are able to do so. + If you prefer that your NPC maintain some other +posture, you can set that posture, then disable +autostanding like this: + +%^GREEN%^modify tex posture lying%^RESET%^ + +%^GREEN%^modify tex autostand 0%^RESET%^ + + If he's especially lazy, you can have him take +a nap this way: + +%^GREEN%^modify tex sleeping 10%^RESET%^ + + Which will have him wake up after about a minute. +However, note that if you've disabled autostanding, +he will remain lying down after he wakes up. + + If the NPC should be hostile, that is, he should +attack any creatures that it sees enter a room, +SetEncounter should do it: + +%^GREEN%^modify tex encounter 100%^RESET%^ + + This means that if the creature it sees has a +charisma score of less than 100 (which should pretty +much be always true), Tex will try to kill it. You +can do some fancy stuff with SetEncounter, such +as only attacking orcs, or actually doing something +friendly, but to do so you can't use QCS. Read +the NPC and Sentients chapter in the Creator's +Manual for details on how to code such stuff. + + If the NPC is a golem or other such non-biological +creature, it may be useful to specify what they are +made of. The SetComposition setting for a clay +golem might look like this: + +%^GREEN%^modify golem composition clay%^RESET%^ + + If it happens to be a golem that does not believe +in violence as a solution to problems, you can +make refuse to hurt others with the following: + +%^GREEN%^modify golem pacifist 1%^RESET%^ + + +Vendors: +------- + +Vendors are a special kind of NPC that can sell stuff. +Along with the standard NPC settings, vendors have +the following: + +SetStorageRoom specifies where the vendor's stock +is stored. If a valid room is specified, anything +in that room can be sold by the vendor. + +SetLocalCurrency specifies the type of currency, +such as gold or silver, that the vendor accepts. + +SetMaxItems is the maximum number of items in +the storeroom that the vendor is permitted to sell. + +SetVendorType specifies the kind of stuff the vendor can +trade in. "all" allows him to buy and sell whatever. +But if he is a weapon vendor, he can't trade in armor, +etc. See /include/vendor_types.h for the available +vendor types. To have a "multi-type" vendor, you'll have to +code it by hand. The result of that looks something +like this: + +SetVendorType( VT_TREASURE | VT_ARMOR | VT_HERBS ); + + +Barkeeps: +-------- + + Like vendors, barkeeps sell stuff, but they are +limited to selling food and drink. + + Unlike vendors, barkeeps have no limitation on +the amount of stuff they can sell. They also do +not have a storeroom. The stuff they can sell is +specified in their SetMenu directive, like this: + +%^GREEN%^clone woody%^RESET%^ +You clone a generic barkeep (/realms/temujin/area/npc/woody.c). +%^GREEN%^modify woody menu%^RESET%^ +If you don't understand these questions, type the letter q on a blank line and hit enter. + +Please enter the first key element for this mapping: + +%^GREEN%^bourbon%^RESET%^ +Please enter the next key element, or enter a single dot to finish entering key elements. +%^GREEN%^whiskey%^RESET%^ +Please enter the next key element, or enter a single dot to finish entering key elements. +%^GREEN%^.%^RESET%^ +Please enter the value for key ({ "bourbon", "whiskey" }): + +%^GREEN%^/domains/town/meals/bourbon%^RESET%^ + + Barkeeps also have the SetLocalCurrency directive +to specify the currency they accept. + + diff --git a/lib/doc/manual/chapter35 b/lib/doc/manual/chapter35 new file mode 100644 index 0000000..35bf70b --- /dev/null +++ b/lib/doc/manual/chapter35 @@ -0,0 +1,224 @@ +chapter 35 "QCS: Modifying rooms" + + Suppose you are in your sample room and you issued the +command: + +%^GREEN%^create room south testroom1%^RESET%^ + + You then travel south and see that you are in a room that is +almost exactly like the sample room except for the exits. Well, +probably you don't want to have a mud with nothing but identical +rooms, so let's modify it: + +%^GREEN%^modify here short Test Room One%^RESET%^ + +%^GREEN%^modify here long This is the first test room. The walls are rather blank.%^RESET%^ + +%^GREEN%^modify here climate indoors%^RESET%^ + +%^GREEN%^modify here light 30%^RESET%^ + + + Ok, so far so good. Standard interior. However, a good mud has +rooms with details. Let's add some detail to this room. + I've omitted the system output for clarity. This is just what you +would input. + + +%^GREEN%^modify here item%^RESET%^ + +%^GREEN%^wall%^RESET%^ + +%^GREEN%^walls%^RESET%^ + +%^GREEN%^blank wall%^RESET%^ + +%^GREEN%^blank walls%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^These are just blank walls.%^RESET%^ + + + Let's review what we've done here: +1) You issued the modify command specifying your current room as the + target, and the SetItems directive as the argument. +2) You entered a query session, and were asked to enter each element + of the item's key. +3) You entered a single dot to indicate you were done entering + key elements. +4) You entered the value for the key, which is the description of the + item. + + The result of all this is that now you can issue these commands: + +%^GREEN%^exa wall%^RESET%^ +%^GREEN%^look at blank walls%^RESET%^ +%^GREEN%^examine walls%^RESET%^ + + And the output will be: + +These are just blank walls. + + Let's add a floor while we're at it: + +%^GREEN%^modify here item%^RESET%^ + +%^GREEN%^floor%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^A floor like any other.%^RESET%^ + + In this case, you didn't feel like adding extra synonyms for "floor", +so you entered the final dot rather than entering another key element. +Then you added the description, and now if you "exa floor", you'll get +that description. + "about here" will display to you the file you have modified. + + Well, that's enough fun with indoor rooms. There's not much more +to them. Let's go outdoors now: + +%^GREEN%^create room south exterior_room%^RESET%^ + +%^GREEN%^create door south test_door%^RESET%^ + +%^GREEN%^open door%^RESET%^ + +%^GREEN%^go south%^RESET%^ + +%^GREEN%^modify here short a small lawn%^RESET%^ + +%^GREEN%^modify here daylong A small, well groomed lawn on a lovely sunny day. There is a small building north of here.%^RESET%^ + +%^GREEN%^modify here nightlong This is a small lawn. Stars twinkle in the night sky above, and some light is coming from a small building to the north.%^RESET%^ + +%^GREEN%^modify here daylight 30%^RESET%^ + +%^GREEN%^modify here nightlight 20%^RESET%^ + +%^GREEN%^modify here light delete%^RESET%^ + +%^GREEN%^modify here long delete%^RESET%^ + +%^GREEN%^modify here items delete%^RESET%^ + +%^GREEN%^modify here items%^RESET%^ + +%^GREEN%^building%^RESET%^ + +%^GREEN%^small building%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^A small building, rather ramshackle as if hastily put together.%^RESET%^ + +%^GREEN%^modify here climate temperate%^RESET%^ + + Ok! A few new things here. A neat thing about outdoor rooms is that +typically they are subject to the time of day. A SetClimate directive +that indicates an exterior environment causes the room to receive +messages about the sun setting, rising, etc. + The SetDayLong and SetNightLong directives allow you to more +sensibly describe the area depending on the time of day. To avoid +confusion, I deleted the SetLong directive. It is not mandatory to +have different day and night descriptions, but players appreciate the +effort. + It is also possible to have differing ambient light levels depending +on the time of day, so we've added SetDayLight and SetNightLight, and +we deleted the SetAmbientLight directive. + + Let's continue to add detail: + +%^GREEN%^modify here item%^RESET%^ + +%^GREEN%^lawn%^RESET%^ + +%^GREEN%^grass%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^Healthy, well groomed and freshly cut grass.%^RESET%^ + +%^GREEN%^modify here smell%^RESET%^ + +%^GREEN%^default%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^You can smell the refreshing scent of freshly cut grass.%^RESET%^ + +%^GREEN%^modify here smell%^RESET%^ + +%^GREEN%^lawn%^RESET%^ + +%^GREEN%^grass%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^Yep, it's got that new lawn smell.%^RESET%^ + +%^GREEN%^modify here listen%^RESET%^ + +%^GREEN%^building%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^Sounds like someone's fumbling about in there, making a mess. New creators can be so noisy.%^RESET%^ + +%^GREEN%^modify here item%^RESET%^ + +%^GREEN%^garden%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^You may enter the garden from here.%^RESET%^ + +%^GREEN%^create room garden garden_room%^RESET%^ + + + + You now have a room with lots of charm and detail. You can "smell grass" +and "listen to small building", if you like. Neat, huh? But there's something +very important to keep in mind: + + Enters, listens and smells don't work properly if there is no item defined +for that smell. For example, if you want to be able to listen to the sea, +you must "modify here item" and add a "sea" item. Otherwise, "listen +to the sea" will respond with "There is no sea here." + The only exception to this rule is the "default" smell. + + Enters behave similarly. If you want to be able to "enter" something, +you'll need to create the corresponding item first, as in the example above. + + You can use the SetProperties directive to make the room +conform to some presets, like: + +%^GREEN%^modify here property no attack 1%^RESET%^ + + Read chapter 23 in the Creator's Manual for details on room properties. + + Also, please note that indoor rooms can also have differing +descriptions and light levels for night and day. It's just that +indoor rooms don't get notification of daytime changes. + + Finally, the SetTown directive allows the room to participate in +area-wide events, and is useful for security purposes as well: + +%^GREEN%^modify here town MyTown%^RESET%^ + + +Notes on room filenames: +----------------------- +By default, a filename without a leading path creates a room +in your area room directory, which in my case would be +"/realms/cratylus/area/room". However, you can specify a different +location for the new room. + +To create a room in your current working directory: +%^GREEN%^create room east ./newroom%^RESET%^ + +To create a room in a specific directory: +%^GREEN%^create room east /realms/cratylus/testrooms/newroom%^RESET%^ + + diff --git a/lib/doc/manual/chapter36 b/lib/doc/manual/chapter36 new file mode 100644 index 0000000..4d7239e --- /dev/null +++ b/lib/doc/manual/chapter36 @@ -0,0 +1,67 @@ +chapter 36 "QCS: Modifying weapons" + + Remember that the QCS chapters are supposed to be read in +sequence. This is important because as we progress, I will not make +explanations about directives and concepts explained previously. + + Weapons are different from rooms and NPC's in that they can +be handled, sold, thrown, etc. They are manipulable objects. As such, +we will see new directives: + +%^GREEN%^create weapon hammer%^RESET%^ + + You may be familiar with this example from the example webpage. +Let's go ahead and plow through the commands: + +%^GREEN%^modify weapon id hammer%^RESET%^ + +%^GREEN%^warhammer%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^modify hammer name hammer%^RESET%^ + +%^GREEN%^modify hammer damagetype blunt%^RESET%^ + +%^GREEN%^modify hammer weapontype blunt%^RESET%^ + +%^GREEN%^modify hammer mass 700%^RESET%^ + +%^GREEN%^modify hammer hands 2%^RESET%^ + +%^GREEN%^modify hammer short a heavy war hammer%^RESET%^ + +%^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%^ + +%^GREEN%^modify hammer adj%^RESET%^ + +%^GREEN%^large%^RESET%^ + +%^GREEN%^heavy%^RESET%^ + +%^GREEN%^war%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^modify hammer basecost silver 750%^RESET%^ + +%^GREEN%^about hammer%^RESET%^ + + + Like a room and unlike an NPC, you can also modify the SetItems on +manipulable objects like weapons, so you could do something like this: + +%^GREEN%^modify hammer item%^RESET%^ + +%^GREEN%^shaft%^RESET%^ + +%^GREEN%^handle%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^A thick, reinforced steel shaft with leather bands for a strong grip.%^RESET%^ + +%^GREEN%^exa shaft on hammer%^RESET%^ + + + diff --git a/lib/doc/manual/chapter37 b/lib/doc/manual/chapter37 new file mode 100644 index 0000000..d721a6d --- /dev/null +++ b/lib/doc/manual/chapter37 @@ -0,0 +1,130 @@ +chapter 37 "QCS: Modifying things and stuff" + + You should have a firm grasp now on how QCS works +in relation to manipulable objects. Let's look at the +settings for a few special kinds of items: + +chairs +------ + +%^GREEN%^modify stool maxsitters 1%^RESET%^ + +%^GREEN%^modify stool setmaxcarry 200%^RESET%^ + + +beds +---- + +%^GREEN%^modify sofa maxsitters 2%^RESET%^ + +%^GREEN%^modify sofa maxliers 1%^RESET%^ + +%^GREEN%^modify sofa maxcarry 400%^RESET%^ + + +containers +---------- + +%^GREEN%^modify box canclose 1%^RESET%^ + +%^GREEN%^modify box closed 1%^RESET%^ + +%^GREEN%^modify box locked 1%^RESET%^ + +%^GREEN%^modify box key magic_skeleton_key%^RESET%^ + +%^GREEN%^modify box maxcarry 200%^RESET%^ + +%^GREEN%^modify box setmoney gold 15%^RESET%^ + + +tables +------ + +%^GREEN%^modify altar maxcarry 300%^RESET%^ + +%^GREEN%^modify altar maxliers 1%^RESET%^ + + +meals/drinks +------------ + +%^GREEN%^modify burger mealtype food%^RESET%^ + +%^GREEN%^modify schlitz mealtype alcohol%^RESET%^ + +%^GREEN%^modify apple mealstrength 10%^RESET%^ + + +books +----- + +%^GREEN%^modify journal title The Orc Within%^RESET%^ + +%^GREEN%^modify journal source /domains/Orcland/etc/books/journal%^RESET%^ + + +Readable things: +---------------- + +If you want to be able to "read thing", for example, "read sign": + +%^GREEN%^modify sign defaultread This is a message written on the sign.%^RESET%^ + +If you want to make a thing on a thing readable, as in +"read inscription on ring": + +%^GREEN%^modify ring item%^RESET%^ + +%^GREEN%^inscription%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^This is an inscription on the ring. Try 'read inscription on ring'%^RESET%^ + +%^GREEN%^modify ring read%^RESET%^ + +%^GREEN%^inscription%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^So! We, the spear-Danes%^RESET%^ + +By default, readabale items are readable by anyone, regardless +of the languages they know. If, however, your item should +only be readable by someone who understands the elvish tongue: + +%^GREEN%^modify ring language edhellen%^RESET%^ + + +Miscellaneous: +-------------- + +To make a key have a 50% chance of breaking when it's used: + +%^GREEN%^modify golden key disablechance 50%^RESET%^ + + +To make a room or object immune to resets: + +%^GREEN%^modify sentry noclean 1%^RESET%^ + + +To make sure there is only one instance of an object or +NPC loaded at any given time: + +%^GREEN%^modify tiamat unique 1%^RESET%^ + + +To make a thing or room immune to the QCS (except for this +command): + +%^GREEN%^modify workroom nomodify 1%^RESET%^ + + +To specify what kind of vendor should be allowed to traffic +in this item: + +%^GREEN%^modify necklace vendortype treasure%^RESET%^ + + diff --git a/lib/doc/manual/chapter38 b/lib/doc/manual/chapter38 new file mode 100644 index 0000000..916d680 --- /dev/null +++ b/lib/doc/manual/chapter38 @@ -0,0 +1,70 @@ +chapter 38 "QCS: Adding and deleting" + + Rooms, containers and NPC's all are capable of holding +items, and often it is convenient to have them already holding certain +items upon creation. + The SetInventory directive in an object's file provides us with +a list of that object's "permanent inventory". To modify an object's +inventory, we use the add and delete commands. + + Let's say that we want our cowboy to be wielding a +hammer when he appears... + +%^GREEN%^clone cowboy%^RESET%^ + +%^GREEN%^cd ../weap%^RESET%^ + +%^GREEN%^clone hammer%^RESET%^ + +%^GREEN%^add hammer to cowboy%^RESET%^ + +%^GREEN%^wield hammer%^RESET%^ + + Believe it or not, it's that simple. The add command will ask +you a question after you issue it. What it wants to know is if you +want the NPC to do anything special when the hammer appears on him. +In this case, yes, we wanted him to wield it. + However, if you want to add something to an NPC and don't +have anything interesting for him to do with it, respond to the +question with the number of items that you want to appear. For +example, if I want the cowboy to be carrying a key: + +%^GREEN%^cd ../obj%^RESET%^ + +%^GREEN%^clone key%^RESET%^ + +%^GREEN%^add key to cowboy%^RESET%^ + +%^GREEN%^1%^RESET%^ + + And that's it. Now if I want the cowboy to be a permanent +resident of this room: + +%^GREEN%^add cowboy%^RESET%^ + +%^GREEN%^1%^RESET%^ + + The add command understands that if you don't specify a +target argument, you must mean the room. You can also be specific: + +%^GREEN%^add cowboy to room%^RESET%^ + +%^GREEN%^1%^RESET%^ + + The delete command works the opposite way. It removes items from +an object's permanent inventory: + +%^GREEN%^delete hammer from cowboy%^RESET%^ + +%^GREEN%^delete cowboy%^RESET%^ + + The delete command is also the way to get rid of rooms. You won't +be removing the file from disk, you'll just be deleting that exit +from the room: + +%^GREEN%^delete exit garden%^RESET%^ + +NOTE: When you delete an exit, only the connection from your room to +the other room is removed. The connection from the other room to +your room remains. This is not a bug, it's a feature. There are plenty +of circumstances where one-way travel is desirable. diff --git a/lib/doc/manual/chapter39 b/lib/doc/manual/chapter39 new file mode 100644 index 0000000..af86f70 --- /dev/null +++ b/lib/doc/manual/chapter39 @@ -0,0 +1,90 @@ +chapter 39 "QCS: Final notes" + +* Remember that QCS commands work on objects, not files. To +load a file into memory, use the update command. To reload an +already existing object, like a cloned orc or a book, use +the reload command. To use modify, delete, and add, you have +to specify a cloned object that is on you or in your environment. + + I think you're getting the idea of how this works. Here's +an example of armor creation: + +%^GREEN%^create armor jeans%^RESET%^ + +%^GREEN%^modify jeans id%^RESET%^ + +%^GREEN%^pants%^RESET%^ + +%^GREEN%^trousers%^RESET%^ + +%^GREEN%^.%^RESET%^ + +%^GREEN%^modify jeans short a pair of denim jeans%^RESET%^ + +%^GREEN%^modify jeans long Worn jeans, frayed and stained.%^RESET%^ + +%^GREEN%^modify jeans adj%^RESET%^ + +%^GREEN%^pair of%^RESET%^ + +%^GREEN%^denim%^RESET%^ + +%^GREEN%^frayed%^RESET%^ + +%^GREEN%^worn%^RESET%^ + +%^GREEN%^stained%^RESET%^ + +%^GREEN%^.%^RESET%^ + + + To know what directives QCS can change on an object, type: + +%^GREEN%^help modify%^RESET%^ + + This provides a list of modifiable things and the directives +that can be modified on them. + + Ultimately the Quick Creation System generates LPC code, so +you'll want to review the earlier chapters of this handbook to +get a base of understanding of the code that comprises your new +creations. + +Some notes and tips: + +* The SetNoCondition directive makes it so an item does not report + its physical status when examined. Weapons and armor wear down in + combat, and most objects let you know their condition when you + examine them. However, in some cases (a sandwich for example) + this is inappropriate, so the SetNoCondition directive may be + useful. + +* Doors aren't like normal objects. They have to be modified *twice*. + Once for each side of the door. If this sounds unnecessarily + tedious, remember that a door leading south is also a door + leading north from the other room. + +* Doors generally are not visible in the same way that regular + objects are. To make a door especially obvious and noticeable, + do something like: +%^GREEN%^modify door sethiddendoor 0%^RESET%^ + +* SetCurrency is for adding money to NPC's. SetMoney is for adding + money to non-living containers (bags, etc). + +* Item subtypes are listed in /include. To know what kinds of vendors + are available, for example, look in /include/vendor_types.h + +* Books need a "source directory", which must contain one file per + chapter. The SetSource for this manual, for example, is /doc/manual + The first line of each file must follow the same format as + the files you see in /doc/manual + +* SetObviousExits is usually no longer needed: rooms report + obvious exits automatically. However, if you don't want an exit + to show up by default, use the SetObviousExits directive + to specify only those that you want seen. This will override the + room's default exit display. + + + diff --git a/lib/doc/manual/chapter40 b/lib/doc/manual/chapter40 new file mode 100644 index 0000000..c80a08a --- /dev/null +++ b/lib/doc/manual/chapter40 @@ -0,0 +1,152 @@ +chapter 40 "Useful Creator Commands" + +Moving around: +------------- + +* To go to your workroom: +%^GREEN%^home%^RESET%^ + +* To go to someone else's workroom, "home <person>", for example: +%^GREEN%^home cratylus%^RESET%^ + +* To go to the town pub: +%^GREEN%^goto /domains/town/room/tavern%^RESET%^ + +* Or: +%^GREEN%^cd /domains/town/room%^RESET%^ +%^GREEN%^goto tavern%^RESET%^ + +* To return to where you were before you went somewhere else: +%^GREEN%^return%^RESET%^ + +* To bring someone to you, "trans <person>". For example: +%^GREEN%^trans cratylus%^RESET%^ + +* To send them back when you're done with them: +%^GREEN%^return cratylus%^RESET%^ + + +Dealing with living beings: +--------------------------- + +* To force everyone in a room to stop fighting: +%^GREEN%^quell%^RESET%^ + +* To let them resume combat: +%^GREEN%^unquell%^RESET%^ + +* To insta-kill a living being, "zap <thing>". For example: +%^GREEN%^zap orc%^RESET%^ + +* To bring to life a player who somehow left the death +room without regenerating, "resurrect <person>", For example: +%^GREEN%^resurrect cratylus%^RESET%^ + +* To make a living being do something you want, "force <thing> +<command>". For example: +%^GREEN%^force thief drop towel%^RESET%^ +%^GREEN%^force thief go west%^RESET%^ + +* For complex management of a living being's vital statistics, +skills, health, score, and satiety levels, use the medical +tricorder in the chest in your workroom. + +* For a detailed report of a living being's physical status: +%^GREEN%^stat orc%^RESET%^ +%^GREEN%^stat cratylus%^RESET%^ + + +Handling objects in general: +--------------------------- + +* To destroy an object, "dest <thing>". Note that the object's +inventory will probably move to the room it was occupying. +For example, if you: + +%^GREEN%^dest fighter%^RESET%^ + + You may find that the room now contains a sword, shield, and +chainmail shirt, but no fighter. + +* To reset an object to its original state, "reload <thing>". Note +that this also makes the object incorporate any changes you +made to its file. For example: +%^GREEN%^reload fighter%^RESET%^ +%^GREEN%^reload here%^RESET%^ + +* To load a file into memory, "update file". This is used when you +have edited an object's file, and want the mud to use the new +stuff you created. For example, if you edited the fighter's file +and wanted to know if it will load properly into memory, you'd +type: +%^GREEN%^update /realms/you/area/npc/fighter.c%^RESET%^ + +Or: +%^GREEN%^cd /realms/you/area/npc/%^RESET%^ +%^GREEN%^update fighter%^RESET%^ + + If you do not specify an object to update, the mud assumes you +want to update the room you are in. If there is a problem with the +room's code, and it does not load, you will be dropped into the +"void". + If the room's code is ok and it updates, anything in the room +that isn't part of its permanent inventory (except for players) will +disappear from the room. + +* To make a copy of an object appear, "clone <file>". For example: +%^GREEN%^clone /realms/you/area/npc/fighter%^RESET%^ + +Or: +%^GREEN%^cd /realms/you/area/npc/%^RESET%^ +%^GREEN%^clone fighter%^RESET%^ + +* To know the precise contents of an object, use scan: +%^GREEN%^scan fighter%^RESET%^ +%^GREEN%^scan here%^RESET%^ + + If you want to know not only what the fighter has, but +also what any containers he is carrying have, use the "-d" flag: +%^GREEN%^scan -d fighter%^RESET%^ +%^GREEN%^scan -d here%^RESET%^ + +Debugging commands: +-------------------- + +* elog: This will report back to you the last few lines of +your error log. Usually this is very helpful in nailing down +which lines of a file contain errors. If you are admin, you +may be working on files other than your home dir. If those +files fail to update, you can supply elog with a directory name +to specify where to look for an error report: +%^GREEN%^elog secure%^RESET%^ +%^GREEN%^elog cmds%^RESET%^ +%^GREEN%^elog lib%^RESET%^ + +* dbxwhere: provides a list of the chain of messages caught +in your last runtime error. + +* dbxframe <number>: Using the list number from dbxwhere, +dbxframe can pinpoint exactly where in that link the error +came from. + +%^GREEN%^tail /log/runtime%^RESET%^ +%^GREEN%^tail /log/catch%^RESET%^ +%^GREEN%^tail /log/player_errors%^RESET%^ + + +miscellaneous useful commands: +----------------------------- + +* %^GREEN%^people%^RESET%^: reports who is logged on, what site they logged +in from, and what room they are in. + +* %^GREEN%^mudtime%^RESET%^: reports the time of day in the mud (nothing to +do with the time of day anywhere in the real world). + +* %^GREEN%^bk <thing or file>%^RESET%^: makes a unique copy of that thing +or file and puts it in /realms/you/bak + +*%^GREEN%^ restore <filename>%^RESET%^: copies the last backup of the +filename from your bak/ directory into where it used +to be. + diff --git a/lib/doc/misc/ed.txt b/lib/doc/misc/ed.txt new file mode 100644 index 0000000..3d603ed --- /dev/null +++ b/lib/doc/misc/ed.txt @@ -0,0 +1,44 @@ + + +The ed editor + + + There's two modes in the editor: the input +mode and the command mode. While in the input +mode, what you type is added to the file +you're editing. While in command mode, you +can view or make modifications to the file. + + To edit a new file called joe.c you would +type "ed joe.c", which puts you right into +input mode. You'd then write whatever code +you want. When finished, on a blank line you +would enter a single period, then hit enter. +This exits from input mode and puts you in +command mode. + + When in command mode, you can modify the +file (like deleting lines, for example), +exit without saving your code, or exit and +save the code. To delete line 1, you'd hit +"1d" while in command mode. + To add a line after line 5, you'd hit +"5a", which would put you in input mode +right after line 5. To replace line 5 you'd +"5c" while in command mode. + + For a full list of commands available in +command mode, hit "h" and enter while in the +editor command mode. + + To exit the editor and save the file +as modified, issue the "x" command at +the editor. To exit without saving, +use "Q". + + For your new object to be loaded into memory, +you must update it after you've edited it. +"update joe.c" will load the changes into memory. + + Don't forget to post questions on the +Creator Bulletin Board if you're confused! diff --git a/lib/doc/old/CHANGES b/lib/doc/old/CHANGES new file mode 100644 index 0000000..64ae24a --- /dev/null +++ b/lib/doc/old/CHANGES @@ -0,0 +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. diff --git a/lib/doc/old/README b/lib/doc/old/README new file mode 100644 index 0000000..40a905c --- /dev/null +++ b/lib/doc/old/README @@ -0,0 +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 diff --git a/lib/doc/old/RELEASE_NOTES.old b/lib/doc/old/RELEASE_NOTES.old new file mode 100644 index 0000000..923317a --- /dev/null +++ b/lib/doc/old/RELEASE_NOTES.old @@ -0,0 +1,135 @@ +---- 2.0 --- +- It is done. + +---- 1.9r21 --- +- Typo fixes, cosmetic changes. + +---- 1.9r19 --- +- Creation system fixes and overhaul: you now need to be holding the + creator staff to use the Quick Creation System. +- Some QCS docs added. +- Added commands reload, wake, resurrect. +- Added sefuns reload, add_maps, alphap. + +---- 1.9r18 --- +- Creation system bugfixes. +- Connection bugfixes. +- Template bugfix. + +---- 1.9r12 --- +- The roommaker is now obsolete, but is not being removed, as + a convenience to those who've gotten used to it. Instead of + the roommaker, use the create command, then the modify command + to adjust the new room to your preferences. +- The thingmaker is now obsolete and has been removed. On-line + object making and editing is done using the new commands: create, + modify, delete. +- admintool now edits groups. Use it in order to ensure you don't + munge the groups.cfg formatting. +- Users in the TEST group are now allowed to log in when the mud is + locked. +- ~/.profile will now be processed when creators log in, and commands + included in it will be automatically executed. +- Added answering machine (for intercepting inconvenient tells). +- Fixed the sample virtual desert. +- Removed the prior intermud restrictions. Rather than requiring + name changes to get onto i3, creators have to add intermud + channels to themselves before talking on them. To do this: + call me->AddChannel("intergossip") + call me->AddChannel("intercre") + +---- Version 1.9r5 --- + +- Fixes and tweaks to town/ domain. +- Updated commands: stat, who, afk. +- Tweaks to body.c and player.c. + +---- Version 1.9r2 --- + +- Added some default SetRestrictLimbs() in armor init() so + that wearing items over the same body parts doesn't + create a crisis. +- Fixed GetNetWorth(). +- Minor tweaks to /lib objects. +- Minor tweaks to town domain. +- Added meditate spell. + + +---- Version 1.9 --- + +- Fixed shoot verb. +- Tweaked body to include messages of drunkenness or sleep. +- Fixed sleeping. +- Fixed economy, including vendors, tellers, and barkeeps. +- Removed daemons: combat, underworld, war. +- Added about command. +- Added string replacer. +- Modified give and drop for newbies to discourage cheating. + +---- Version 1.8r1 --- + +- Added souls (smile, wink, etc). + +---- Version 1.8 --- + +- Fixed lib obs: put, look_in, get_from + to work with surfaces and recursing containers. +- Fixed verb put to work with surfaces and recursing containers. +- Fixed /lib/std/germ to work properly and handle bane. +- Fixed verb read to properly handle readable things + on objects. +- Updated enter, jump, and go verbs to handle hobbling. +- Numerous minor fixes and updates to verbs and lib objects. +- Added crawl verb. +- Fixed armor conflicts. +- Added intermud requirement to change ADMIN_EMAIL. + +---- Version 1.7r1 --- + +- Fixed some minor login bugs. +- Updated the make_workroom sefun. + +---- Version 1.7 --- + +- Added template creator setup for first admin and encre. +- Fixed and tweaked help: help works properly now. +- Fixed "force". +- Added roommaker. +- Added (default) explorer and mage classes. +- Tweaked connect.real. +- Fixed numerous armor bugs: armor works properly now. +- Changed the pointlessly affected "armor" spelling to "armor" +- Stopped numbering items in the changelog + +---- Version 1.6 --- +11 Added large, functional sample area based on Larstown + +10 Major changes to many many lib files and sefuns + +---- Version 1.1r5 --- +9 Fixed library inheritables: inventory, move, container + +8 Added library inheritables: shop, shadow, getlivings, addstuff + +7 Added sefuns: tell_player(), GetCustomPath(), GetCustomCommand(), + dump_socket_status(), flat_map(), get_cmds(), get_verbs(), + get_livings(), local_time(), reap_dummies(), reap_other(), + reap_list(), tail(), timestamp(), get_dupes() + +---- Version 1.1r4 --- +6 Added license.txt + +5 Added telnet client and telnet room + +4 Applied ftpd fixes + +---- Version 1.1r3 --- +3 Fixed /domains/Ylsrim, and most items work + +---- Version 1.1r2 --- +2 We know there are still many many bugs left in the lib. + This is a preliminary release. An update is already in the works. + +1 W00t! It's finally free! + + diff --git a/lib/doc/old/the_beginning.txt b/lib/doc/old/the_beginning.txt new file mode 100644 index 0000000..059a9d7 --- /dev/null +++ b/lib/doc/old/the_beginning.txt @@ -0,0 +1,55 @@ +From - Wed Sep 14 16:42:12 2005 +X-Account-Key: account3 +X-UIDL: BAABFB9854115F7218C41D66992B9B8F +X-Mozilla-Status: 0001 +X-Mozilla-Status2: 00000000 +Received: from ylpvm47.prodigy.net by yipvmd with SMTP; Wed, 14 Sep 2005 16:30:41 -0400 +X-Originating-IP: [67.19.238.52] +Received: from hicky.mudmagic.com (mudmagic.com [67.19.238.52]) + by ylpvm47.prodigy.net (8.12.10 083104/8.12.10) with ESMTP id j8EKU49c022577 + for <<me!>@snet.net>; Wed, 14 Sep 2005 16:30:04 -0400 +Received: from hicky.mudmagic.com (localhost.localdomain [127.0.0.1]) + by hicky.mudmagic.com (8.12.11/8.12.11) with ESMTP id j8EKXJJM032313 + for <<me!>@snet.net>; Wed, 14 Sep 2005 15:33:19 -0500 +Received: (from apache@localhost) + by hicky.mudmagic.com (8.12.11/8.12.11/Submit) id j8EKXJ3l032311; + Wed, 14 Sep 2005 15:33:19 -0500 +Date: Wed, 14 Sep 2005 15:33:19 -0500 +To: <me!>@snet.net +Subject: [WATCHING] Dead Souls is BACK! +Message-ID: <346e96fe420e490d32858b1238cd48df> +From: Cratylus <noreply@mudmagic.com> +Reply-To: reviews@mudmagic.com +X-Phorum-TGB-Version: TGB 1.0 +X-Phorum-TGB-Forum: Review Requests +X-Phorum-TGB-Thread: 319 +X-Phorum-TGB-Parent: +X-Virus-Scanned: ClamAV 0.86.2/1081/Tue Sep 13 02:06:09 2005 on hicky.mudmagic.com +X-Virus-Status: Clean + +Hey folks. + +I fixed up Dead Souls, got it to work with MudOS v22.2b14, +and even got all the sample rooms to load properly! + +I'm probably going to tinker some more with it. If you'd +like to contribute, let me know. + +Now, I am not the original author of DS, but it was released +as public domain back in 1998 and has lain lifeless and +abandoned ever since. + +But I think it's got great potential, and since it's been +doing nothing but collecting dust, I figure it might as +well be me that picks up the reins. + +Give it a go and let me know what you think. + +It's at http://sourceforge.net/projects/dead-souls/ + +Click on the "files" link to get to the download section. + +Good luck! + +- Cratylus @ Frontiers + diff --git a/lib/doc/phints/chapter01 b/lib/doc/phints/chapter01 new file mode 100644 index 0000000..84b6c61 --- /dev/null +++ b/lib/doc/phints/chapter01 @@ -0,0 +1,156 @@ +chapter 1 "Getting started: The Newbie Mansion" + +You understand the basics. You've read the player's +handbook (you read that, right?), you now understand stats +and skills, you've customized your stats, and you're +ready to play. This chapter will now give you a walkthrough +of the first quest a newbie should perform. It is a *complete* +walkthrough! It is a SPOILER. If you don't want the quest +spoiled, stop reading now! + +I'm going to assume your mud does not allow picking your +class at char creation, or that the class you picked is +"explorer". This is to simplify the walkthrough. This also +assumes you've just created this char and it is level 1. + +We'll start in the reception room, with Jennybot (5 south, +3 east, 1 south, of the village clocktower). If you haven't +done so already, this might be a good time to: +%^GREEN%^activate bot%^RESET%^ + +What she says is kind of boring if you're not new to muds. +But hang around until she gives you the baseball cap. It's +worth some money. + +%^RED%^PROTIP%^RESET%^: If she has already given you a cap before, +you won't get a new one. + +Once you get the cap, go 1n, 3w, 5n, 1e, 1n. This is the village +shop. Remove and drop your worthless t-shirt and jeans, +and sell the cap to otik: + +%^GREEN%^sell cap to otik%^RESET%^ + +Sell any other crap you've picked up along the way. The newbie +mansion will have all the equipment you'll need to solve it. +But keep this hint book handy! + +Now it's time to open a bank account. Believe me, you do not +want to be carrying around all your money if you die. So let's +go open an account and put our hard-earned cash somewhere safe: +1s, 1w, 3n, 1e. + +%^GREEN%^request account from zoe%^RESET%^ +%^GREEN%^deposit all%^RESET%^ + +Good! I feel safer already! Now let's head to the mansion. +From the bank it is: 1w, 3s, 2w, 2s. If you're still at newbie +levels, the mansion guard won't notice you slip by. + +You're now in front of the mansion, but how to get in? The door +is locked! Pay close attention to the description...did you +notice that the mansion is described as having an open +second story window? + +Go to the gardener's shack (1w, 1n) and get the ladder. Return +to the front of the mansion (1s, 1e) and: + +%^GREEN%^drop ladder%^RESET%^ +%^GREEN%^climb ladder%^RESET%^ + +You're in! You're now standing in the second floor hallway of +the newbie mansion. Time to get equipped. Go east into the +guest room, open the overnight bag, and get and wear the +following: leather jacket, leather pants, helmet, shirt, and gloves. +This is relatively decent newbie armor that still lets you +gather loot because it's not too heavy. + +%^RED%^PROTIP:%^RESET%^ You can do stuff to more than one +item at a time, and when you do, worn items are ignored. Try: +%^GREEN%^open overnight bag%^RESET%^ +%^GREEN%^get all from overnight bag%^RESET%^ +%^GREEN%^wear all%^RESET%^ +%^GREEN%^drop all%^RESET%^ +Did you notice that you only dropped the things you were not wearing? + +Now, go to the master bedroom (1w, 3s), open the wardrobe and +get the boots from the wardrobe and wear them. These are long +boots and are better than the boots in the guest room. These +boots also protect your legs. + +Leave the rest of the stuff in the wardrobe alone for now...you +can loot the mansion after you complete the quest. Next, let's +get you a weapon. Go downstairs, just outside the kitchen (1n, 1d, +1n). The kitchen will be east. Do this, very quickly: + +%^GREEN%^go east%^RESET%^ +%^GREEN%^get carving knife from rack%^RESET%^ +%^GREEN%^go west%^RESET%^ + +Ignore the kitchen rats...kill them later if you want, for now +let's save up your strength for the mansion boss...and he's +next! Before we go on, though, let me ask you...did you get +both knives from the rack? No! just the carving knife! You see, +only fighters are skilled at using two weapons at once. As +an explorer, if you try to wield two weapons at once, you +will do very very badly in combat. The carving knife is an +excellent weapon. Just wield that, and drop the butcher knife. + +Now go north and east...and meet your first quest boss. Yes, +the soggy thief! He's snuck into the mansion while the master +was away, and made himself at home! He won't like your +presence and will attack you, but he's really quite wimpy. +Just stand your ground and you'll defeat him with no effort. + +Finished? Aren't you sad now? No? Good. There's plenty of +slaying to do in this game, if you're getting sentimental over +killing a burglar while wearing his armor (that you stole) then +this just might not be the game for you. Now, take his stuff +and look around. See anything that piques your curiosity? + +%^GREEN%^get all from corpse%^RESET%^ +%^GREEN%^look%^RESET%^ + +Maybe the rug is valuable... + +%^GREEN%^exa rug%^RESET%^ +%^GREEN%^get rug%^RESET%^ + +Weird! What if we... + +%^GREEN%^move rug%^RESET%^ + +Well what do you know! Open that trap door, go down into +the secret chamber, and you'll have solved your first Dead Souls +quest. Congratulations! You'll be awarded quest and experience +points, and if your mud is set to auto-advance, you'll +probably gain a level or two. If not, you can visit Dirk and +ask him to advance (Dirk is 1e, 1s of the village clocktower). + +There's a bunch of loot in the chest in the secret chamber, as well +as a bag with money (don't just sell the bag, "get all from bag" +first!). You can now focus on robbing the mansion blind and +selling everything you steal. With the money, you can start buying +expensive equipment you need for the more challenging quests. + +%^RED%^Loot tip 1:%^RESET%^ Go back to the master bedroom and move the bed. +Surprise! Enter the passageway and unlock the safe with the complex key +you took from the thief. Inside the safe you'll find stuff you +will want to keep, not sell. Trust me on that. Don't sell that stuff. + +%^RED%^Loot tip 2:%^RESET%^ Search the room across the hall from the guest +room you looted. + +%^RED%^Loot tip 3:%^RESET%^ Whether you sell or keep it, remember where the +bear costume is. It could come in handy later. + +%^RED%^Loot tip 4:%^RESET%^ Sell stuff to Kim if you can, rather than Otik. Otik pays +with silver, which is heavy. Kim pays with dollars, which are light. Sadly, +Kim will not buy or sell weapons, but for everything else, her light +currency is very convenient. You can always exchange currencies at +the bank. Kim's bookstore is 1n, 2e, 1n of Jennybot. + +%^RED%^Loot tip 5:%^RESET%^ If you advanced automatically, you might find that the mansion +guard no longer lets you past him any more...and you can't get rid of him. +Strategies for dealing with the gate guard are discussed later. + diff --git a/lib/doc/phints/chapter02 b/lib/doc/phints/chapter02 new file mode 100644 index 0000000..2c3bf15 --- /dev/null +++ b/lib/doc/phints/chapter02 @@ -0,0 +1,116 @@ +chapter 2 "Post-Mansion Hints" + +So you're flush with joy at having solved your first quest, +and now you're loaded with money and loot! Woo! But...oh no... +there's so much loot left in the mansion, and the gate gard won't +let you pass because you're not a newbie anymore. Bummer! Well, +we're going to fix that, but first, let's get organized. You're +carrying a bunch of stuff, some of which you want to keep, some +of which you want to sell, and it's going to get tiresome soon, +having to sort through your inventory all the time at shops. So +the first thing we're going to do is buy a rucksack. + +Why? + +Remember when you tried to "drop all" and the only things +you didn't drop were the things you were wearing? A rucksack +gives you somewhere to keep a bunch of stuff, and you *wear* +the rucksack. Meaning that "drop all" and "sell all" will +ignore the valuable stuff you keep in your rucksack, if +you're wearing it. Neat, huh? It makes life much easier when +selling tons of loot. + +So, let's go to Otik (from the gate guard, 1n, 3e, 1n), and +buy the rucksack. Try: +%^GREEN%^buy ruck from otik%^RESET%^ +If you dont have enough money, sell some of the junk you got +from the mansion. It also could be that you *do* have enough money, +but not in silver. If this is the case, go to zoe and do a +currency exchange: +%^GREEN%^exchange 5 gold for silver%^RESET%^ +Note that you can only exchange money in your possession. Zoe +does not exchange money while it is deposited. + +Once you have your rucksack, wear it, open it, and put in it +the stuff you want to keep. I suggest putting the grenade, the +pistol, and the slips in there. Now sell the junk you don't +want, deposit the excess cash with Zoe, and let's get ready +to deal with the gate guard. + +The problem: A guard you cannot kill, preventing passage. + +The solution: Find a way around, or through him. + +Now, you might be tempted to use the grenade. You *could* pull +the pin on the grenade, drop it, leave, wait a few seconds, and +come back...and the guard *might* be dead. But this is a magical +guard. Even if he dies, his spirit prevents you from getting +past. And he will regenerate into a new body within seconds. So... +what to do? There are two solutions, and both of them require... + +SCIENCE! + +Go to Zoe and withdraw 110 dollars or so (darn fees), then +go to the bookstore (1w, 8s, 5e, 1n), and buy the lab coat from Kim. +Now go to the campus stargate lab (1s, 5w, 1s, 1w, 1n), where Kleiner +is busy working on exotechnology, as usual. In typical egghead +fashion, Kleiner is too preoccupied with his experiments to +help you, but he wants *your* help. He's lost his lab coat, you see. +Like so many geniuses, Kleiner is somewhat physically clumsy, +and if he wears a lab coat you give him, he's liable to drop +his identification badge. This badge gives its carrier access +to the "hazardous technologies" lab two rooms south of Kleiner. + +%^RED%^PROTIP%^RESET%^: Do not attempt to kill Kleiner. He is carrying a +teleportation device called an omni which he will use the moment he +receives harm from someone. Attacking Kleiner just means he and +his ID badge will teleport to some random location, and you'll be +up the creek. + +%^RED%^PROTIP%^RESET%^: In the hazardous materials lab, DO NOT attempt to harm +the tripod gun turret. Failure to heed this warning will result in +catastrophic injury to anyone in the room. + +On the hazlab workbench you'll find various items of interest. For +now we'll concentrate on the Yautja wrist computer, the Yautja data +module, and the rocket pack. The rocket pack is the simplest tool for +circumventing the gate guard. Wear it, and head back to the guard +(1n, 1e, 6n, 2w, 1s). Now use the pack to fly over the guard: + +%^GREEN%^activate pack%^RESET%^ +%^GREEN%^boost up%^RESET%^ +%^GREEN%^boost south%^RESET%^ +%^GREEN%^boost down%^RESET%^ +%^GREEN%^deactivate pack%^RESET%^ + +How do ya like that! Remember to deactivate the pack, too. If you +leave it running, it'll eventually run out of fuel. Don't get too +crazy flying around with it, either. You're extremely likely to boost +yourself out over the ocean if you're not careful, and wind up +lost and drowning. Also, if you run out of fuel while up in the +air, you *will* fall and the damage you'll receive will be grievous. +So let's be very careful in our use of the rocket pack. + +Another way to get past the guard is by having him not see you at all. +The Yautja technology can help you in this: + +%^GREEN%^wear wristcomp%^RESET%^ +%^GREEN%^open wristcomp%^RESET%^ +%^GREEN%^activate wristcomp%^RESET%^ +%^GREEN%^install module in wristcomp%^RESET%^ +%^GREEN%^close wristcomp%^RESET%^ +%^GREEN%^cloak%^RESET%^ +%^GREEN%^go south%^RESET%^ +%^GREEN%^decloak%^RESET%^ + +It is crucially important that you are cloaked only as long as +necessary. If you walk around while cloaked, it will sap your stamina +extremely quickly. Note that it is a peculiarity of Yautja technology +that it's a bit awkward to use. If you remove the wristcomp, it +deactivates, and you'll need to wear it, activate it again, uninstall +the module, and install it again. Those Yautja hunters always do +things the hard way, I'll tellya. + +You now have the tools you need to successfully steal every +ounce of worth from the newbie mansion regardless of your +newbie status. Congratulations...I guess. diff --git a/lib/doc/phints/chapter03 b/lib/doc/phints/chapter03 new file mode 100644 index 0000000..bd61c3a --- /dev/null +++ b/lib/doc/phints/chapter03 @@ -0,0 +1,80 @@ +chapter 3 "Teleportation Devices" + +Let's talk a little about how to use some of the teleportation +technology in the default Dead Souls distribution. Some of +this stuff can save your hide, and some of it can kill you, +so it's worth being aware of it. + +%^CYAN%^Visitor's Pass%^RESET%^ +This is an extremely rare item, and only intended for official test +characters. If you don't show up in the "who" list with a [%^YELLOW%^TEST%^RESET%^] +tag, and you have a visitor's pass, something has gone wrong. You +use the pass to get out of trouble with the command: %^GREEN%^click heels%^RESET%^ + +%^CYAN%^omni%^RESET%^ +The omni is a device created by a consortium of time travelers dedicated +to fixing errors in history. While they'd never make the full chrono-omni +available for public consuption, a "gimped" version can be purchased +from Oana at the magic shop. This omni does not do time travel, and when +you press the button on it, it will only take you to one location: Lars's +Pub. However, it is an incredibly valuable tool of recall when you find +yourself in a tight spot. For example, suppose you are an orc or a dwarf, +and you cannot swim, but you walked off the village shore and are now +drowning and sinking to the sea floor. If you have an omni in your +rucksack, you can: + +%^GREEN%^get omi from ruck%^RESET%^ +%^GREEN%^push button on omni%^RESET%^ + +And materialize, gasping but alive, in the old tavern. It's a must-have +for any adventurer. I suggest aliasing those commands, so you can +hit the buttons quickly in panic-mode. See: %^GREEN%^help alias%^RESET%^ + +%^RED%^PROTIP:%^RESET%^ The omni is programmed not to be in the possession of a +living being for very long. If you keep it in your inventory too long, it +will glow red and disappear. You can limit this by keeping it in your ruck. + + +%^CYAN%^Kleiner's omni%^RESET%^ +Kleiner, brilliant scientist he is, has been tinkering with his omni +and disabled the auto-vanish feature for himself on it. He also has been +able to reprogram his omni to take him to different places. However, +you really don't want this omni. Only Kleiner can control where it takes +him. For anyone else, it takes them to a completely random location +on the mud, and believe me when I tell you this is not really as +fun as it sounds. + + +%^CYAN%^Stargates%^RESET%^ +Ancient technology of a long-lost civilization, stargates permit travel +to and from each other. You dial a specific stargate you want to go to, +then enter the stargate. Note that if the destination stargate is already +in use the dialing process may fail. Stargates stay open for only a brief +time, though, so unless your mud is super busy, you can probably just +retry the dialing and find success. + +Note that stargates can take you to places whose environment is unsuitable +to you. If you dial a stargate that is on the sea floor or one that is in +outer space, you'd best be wearing a breathing device or be carrying +an omni with you. Of course, if on your mud someone has coded a stargate +whose destination is next to a sun going nova, or in a nest of gundarks, +the breathing device may provide insufficient protection + + +%^CYAN%^Portal gun%^RESET%^ +If it has both blue and orange vials installed, this device allows you to +create portals (one blue, one orange) that connect to each other. Entering +the blue portal will take you to the location of the orange portal, and +vice versa. Only one blue portal may exist in the game at any time...the +creation of a new one destroys the old one. This is also true of the +orange portal. Portal locations persist through reboots. By default, the +blue vial is found along with the portal gun, in the hazlab. The orange +vial is rather trickier to obtain...it is kept in the private storage area +of an incredibly powerful and aggressive cave troll. + +You can create a blue portal wherever you want if you have the blue vial +installed, but without the orange vial you cannot change the location of +the orange portal. + +%^RED%^Protip:%^RESET%^ Do not ever enter a portal if the other portal is +in the same room. diff --git a/lib/doc/phints/chapter04 b/lib/doc/phints/chapter04 new file mode 100644 index 0000000..2fb6fb0 --- /dev/null +++ b/lib/doc/phints/chapter04 @@ -0,0 +1,207 @@ +chapter 4 "The Town Well" + +Ok, so you're now all set with a bunch of money in the bank, +light-but-decent equipment, and a thirst for more advancement. +Let's try a quest that requires a little fancy footwork and +little (if any) fighting. + +I'm going to assume that the portal gun portals are where the +default distribution puts them. The blue portal in the hazlab, +the orange portal...well, you'll see. + +By now you should have Kleiner's badge. If not, go back to where I +describe how to get it. If you sold it, go buy it back. Also, get +yourself a flashlight. I recommend maglite, but whatever you can +find is better than nothing. Now go back to Jennybot. Near her is +a stairwell that leads to the campus basement. Turn on your +flashlight then go 1n, 1w, 1s, 1d, 1w of Jennybot. You're now in +the western end of the campus basement. Note the smudged wall? +%^GREEN%^push wall%^RESET%^ +Whee! Go west until you can't go any further, then go 1s. Lying +there is a key you'll need. Put it in your ruck, then go north +til you can't go north any further. Note that the next couple of +things you need to do must be done quickly. You're about to enter +a dangerous sewer service area, and you may get blasted with harmful +steam if you hang around too long. + +Go down into the sewer area. See that pile of crap? Search it. Bonus! +Now go east twice, up, open grate, up. You're now back up on the +cobblestone road, but with a shiny new ring to wear or sell, and +a key you'll need. Head to the hazlab (4s, 1w, 1s). Now, just in case +some joker put the orange portal somewhere dangerous, you should have +an omni handy (you can buy one from Oana). Enter the blue portal. Unless +someone's been playing around, you should now be in an underground +tunnel, with a large metal door to the west. There's not much to +explore here...if you follow the tunnel north and east, you'll find +a locked gate with a cave troll on the other side. What you really +want to do is get past the door to the west. You got the key to this door +from the campus underground, so go ahead and unlock it. Now comes the +hard part...open the door. + +Chances are that you can't. It's huge and it's heavy...it requires having +a strength stat of at least 50 to open. You have 2 possible ways of dealing +with this...one is expensive, the other a bit tricky. The expensive way +is to buy strength potions from Oana and drink them until your strength +is above 49, then rush back to this door before the potions wear off, +and open the door. Like I said, expensive. + +The other way is to control something that is strong enough to open the +door. Go back to kleiner, then type: +%^GREEN%^dial stargate lab%^RESET%^ +This takes you to a secret area used by creators to test their npc's, +armor, and equipment. Go north, then east. If you're lucky, nobody has +taken the landstrider mech for a joyride and it's standing there, waiting +for you. Type: %^GREEN%^enter mech%^RESET%^ +You are now inside your very own mech-type robot you control. Cool! +Have it go back to the stargate: +%^GREEN%^drive west%^RESET%^ +%^GREEN%^drive south%^RESET%^ +%^GREEN%^direct mech to dial campus lab%^RESET%^ +%^GREEN%^direct mech to enter gate%^RESET%^ +%^GREEN%^drive south%^RESET%^ +%^GREEN%^drive south%^RESET%^ + +Uh oh! The mech can't enter the hazlab because it's not carrying Kleiner's +badge! What you need to do is drop the badge. It will then be in the mech's +inventory, so that the security door can see it. + +%^GREEN%^drop badge%^RESET%^ +%^GREEN%^drive south%^RESET%^ + +Now we have the mech enter the portal and open the door for you. + +%^GREEN%^direct mech to enter portal%^RESET%^ +%^GREEN%^direct mech to open door%^RESET%^ + +Excellent! Now, the next part involves making this area kind of +hostile for general use, so let's get the mech out of harm's way + +%^GREEN%^get badge%^RESET%^ +%^GREEN%^wear badge%^RESET%^ +%^GREEN%^direct mech to enter portal%^RESET%^ +%^GREEN%^out%^RESET%^ + +Now go back in the portal (just you, without the mech), and +go west twice. This is the source of the problem. The town well is dry +because someone shut off the water source! + +To restore water to the well, turn the metal wheel here, and +water will start rushing out of the pipe at high pressure. There's a +grate-type door overhead through which the water is supposed to flow up to +the bottom of the well. If the orange portal hadn't been there, you'd have had +to do the alternate solution, which involves accessing the +water source from that other direction. + +Now, as you can imagine, this area is going to fill up with water +very rapidly, so leave east right away. The entire series of tunnels +will flood, so get back to the orange portal and enter it quickly. + +%^RED%^PROTIP:%^RESET%^ The water will also go through the locked cavetroll +gate. And cavetrolls don't breathe water. + +Now, go to the town well (1n, 1e, 5n of the hazlab), and: %^GREEN%^enter well%^RESET%^ +Hopefully you did get the maglite. By now the weaker flashlights may have +pooped out. See the lever on the wall? That operates a set of two doors that +serve as a waterlock for the well. Pull it, and a door will open, letting +water flood into the well, and solving the quest! + +It may be that someone has already been fooling with the water lock, though. +If the door was already open when you got there, push the lever, wait a +few minutes for water to flood the lock, then pull the lever. It could +take a while depending on the water pressure for the lock to fill up, so +if it's dry, close it again and wait a while before opening again. + + +%^CYAN%^Alternate Resolution%^RESET%^ + +It may be that the orange portal was not in the water tunnel. It could +be that the hazardous materials labs was not accessible to you. If that +is the case, you'll need to solve this quest by accessing the water +source from the direction of the well. This is tricky because you need +to be very strong to open the grate, *and* you need an extra set of +hands to operate the water lock lever. Let's deal with one problem at a time. +First, the strength issue. On the other side of the water lock is a +grate that you must have at least 50 strength to open. If your strength +is already above 49, great. If not, you need to decide whether you want +to boost it with strength potions from Oana (expensive) or use the +landstrider mech (tricky). If the plan is to use strength potions, go buy +them now and stick them in your ruck. If the plan is to use the mech, +go get it. Go to Kleiner, and: + +%^GREEN%^dial stargate lab%^RESET%^ +%^GREEN%^enter gate%^RESET%^ +%^GREEN%^go north%^RESET%^ +%^GREEN%^go east%^RESET%^ +%^GREEN%^enter mech%^RESET%^ +%^GREEN%^drive west%^RESET%^ +%^GREEN%^drive south%^RESET%^ +%^GREEN%^direct mech to dial campus lab%^RESET%^ +%^GREEN%^direct mech to enter gate%^RESET%^ +%^GREEN%^drive south%^RESET%^ +%^GREEN%^drive east%^RESET%^ +%^GREEN%^drive north%^RESET%^ +%^GREEN%^drive north%^RESET%^ +%^GREEN%^drive north%^RESET%^ +%^GREEN%^drive north%^RESET%^ +%^GREEN%^drive north%^RESET%^ +%^GREEN%^direct mech to enter well%^RESET%^ +%^GREEN%^direct mech to pull lever%^RESET%^ +%^GREEN%^drive west%^RESET%^ +%^GREEN%^out%^RESET%^ +%^GREEN%^go east%^RESET%^ + +The mech is now in the water lock. But neither you nor the mech +can proceed further west...you need someone to pull the lever +for you. You're going to need a servant...a slave...a ZOMBIE! Go +up and west, and buy a dark scroll from Oana. The scroll can be +used to raise a corpse, but you must be able to read English. If +you've chosen a race that doesn't speak English, you'll need to +learn it now. Go to Bugg (1n, 2e, 1n of the well) and ask him to +teach you English. Once you've learned it, you'll be ready to +create a zombie. From Bugg, go to the campus square (1s, 2w, 5s) +and murder Tim. It's important that you slay something that speaks +a language you know, so since you're either human or just now +learned English, a human victim is suitable. Plus Tim is a wuss. +Once he's slain: %^GREEN%^read scroll at tim%^RESET%^ + +There he is! Your very own zombie! We'll need to move quickly +now. Zombies don't last forever...the clock is ticking. Do the +following to get him to follow you: + +%^GREEN%^speak in english%^RESET%^ +%^GREEN%^say follow cratylus%^RESET%^ + +Except, of course, instead of "cratylus", put in your own name. +Note something important here. Zombies are obedient, but not +smart. If someone else starts saying things that the zombie understands +as a command, it will start obeying them. So remember that while +you created this zombie, someone else can steal him if you're not +careful. + +Now, return to the well (4n) then enter the well and go west. +You'll need to tell the zombie to leave the water lock and operate it: + + +%^GREEN%^say go east%^RESET%^ +%^GREEN%^yell push lever%^RESET%^ +%^GREEN%^enter mech%^RESET%^ +%^GREEN%^drive west%^RESET%^ +%^GREEN%^direct mech to open grate%^RESET%^ + +Woohoo! If you don't have the mech, of course, you just +walk your own self west, drink your strength potions, and +open the grate yourself. If you *do* have the mech, let's get it out +of harm's way... + +%^GREEN%^drive east%^RESET%^ +%^GREEN%^out%^RESET%^ +%^GREEN%^go west%^RESET%^ + +All righty, now let's go resolve this well problem. Go down +and you'll see the metal wheel and the water pipe. To get the water +flowing again, turn the wheel. Then very quickly get yourself back to +the water lock...the area will fill with water soon! When water +gets to the lock: %^GREEN%^yell pull lever%^RESET%^ +Your zombie will then open the east door, allowing you and the water to +get to the well, and solving the Town Well Quest. Congratulations! + diff --git a/lib/doc/phints/chapter05 b/lib/doc/phints/chapter05 new file mode 100644 index 0000000..8afdfcb --- /dev/null +++ b/lib/doc/phints/chapter05 @@ -0,0 +1,31 @@ +chapter 5 "The Orcslayer" + +You're getting spoiled, aren't you? You're achieving dizzying +heights of player leveling in no time, and learning tons about +how to fight, move, and operate in the Dead Souls environment. + +Well, sorry to say, we are close to the end of your free ride. +The orcslayer quest is the last one you get a full walkthrough +on. After this, you'll need to apply the lessons you've learned +from this hint book to whatever other quests and adventures your +mud features. + +Before we really get started...do you remember what you did with +that bear costume? I ask because orcs are known to be quite +deferential to bears. Keep that in mind, if your player race +is not "orc". + +Now, Leo the Archwizard misplaced his precious magical sword, Orcslayer. +Leo is in the basement of the village church (1w, 1n of the clocktower) +waiting for you to help him find it. Little does he know that some +juvenile orcs, trying to prove their mettle, stole it and have given +it to their wanna-be shaman in their improvised lair (4w, 1sw, 1w, +1n, 1w of the clocktower). + +There are a few ways you can handle the orcs between you and the shaman. +If you decide to do it the hard way, let me remind you that Herkimer +can sometimes teach you some spells even if you are not a mage. In particular +the buffer spell can pro ++++ +ATH0 +NO CARRIER diff --git a/lib/doc/sefun/absolute_path b/lib/doc/sefun/absolute_path new file mode 100644 index 0000000..5259ebf --- /dev/null +++ b/lib/doc/sefun/absolute_path @@ -0,0 +1,51 @@ + +ABSOLUTE_PATH(1) ABSOLUTE_PATH(1) + +NAME + absolute_path() - returns the full path starting at root + +SYNOPSIS + string absolute_path(string curr, string new) + +DESCRIPTION + Given any relative path, this function returns the full + path from /. The first argument is the base directory, + and the second is the relative path you wish to make + absolute. If the second argument cannot be made absolute + on its own, it is made absolute relative to the base + directory, which is usually the current working directory. + It understands special things like: + + o ~/ represents the home directory of the command giver + + o ~user represents the home directory of the user named + + o ^domains represents the home directory of the domain + named + + o + + . represents the current working directory + + o + + .. represents the parent of the current working directory + +EXAMPLES + o absolute_path("/realms/descartes", "monster.c") + returns "/realms/descartes/monster.c" + + o absolute_path("/std", "~workroom.c") returns + "/realms/descartes/workroom.c" + +LOCATION + /secure/sefun/absolute_path.c + +SEE ALSO + base_name(), path_file() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/absolute_value b/lib/doc/sefun/absolute_value new file mode 100644 index 0000000..a8340bd --- /dev/null +++ b/lib/doc/sefun/absolute_value @@ -0,0 +1,29 @@ + +ABSOLUTE_VALUE(1) ABSOLUTE_VALUE(1) + +NAME + absolute_value() - returns the absolute value of a give + number + +SYNOPSIS + int absolute_value(int x) + +DESCRIPTION + Given any integer argument, it returns its absolute value. + +EXAMPLES + absolute_value(-5) returns 5 + + o absolute_value(5) returns 5 + +LOCATION + /secure/sefun/absolute_value.c + +SEE ALSO + percent() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/add_sky_event b/lib/doc/sefun/add_sky_event new file mode 100644 index 0000000..3552abb --- /dev/null +++ b/lib/doc/sefun/add_sky_event @@ -0,0 +1,43 @@ + +ADD_SKY_EVENT(1) ADD_SKY_EVENT(1) + +NAME + add_sky_event() - sets a function to be called every + change of time of day + +SYNOPSIS + void add_sky_event(function f) + +DESCRIPTION + This functions sets the mudlib to call the function you + specify every time the time of day changes. With the + Nightmare Mudlib time system, there are four changes in + time of day: dawn, morning, twilight, night. If you call + add_sky_event(), then any time the time of day changes, + the function you specified will be called with the time of + day as an argument. + +EXAMPLES + add_sky_event((: howl :)) will have the function: void + howl(string str); get called in your object every change + in the time of day. The string argument is the time of + day, which will be one of dawn, morning, twilight, night. + +NOTES + In general, this should be called only from create() in an + object. It definitely should only be called once for each + function to be called in an object. Also, it is + recommended that you set_no_clean(1) in any object which + does have functions set by this function to be called. + +LOCATION + /secure/sefun/time.c + +SEE ALSO + remove_sky_event() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/alignment_ok b/lib/doc/sefun/alignment_ok new file mode 100644 index 0000000..16eda49 --- /dev/null +++ b/lib/doc/sefun/alignment_ok @@ -0,0 +1,28 @@ + +ALIGNMENT_OK(1) ALIGNMENT_OK(1) + +NAME + alignment_ok() - returns true if a player is inside + alignment restrictions + +SYNOPSIS + int alignment_ok(object ob) + +DESCRIPTION + If the object passed as the argument is within alignment + restrictions for the player's class, then the function + returns true. Otherwise it returns false. + +EXAMPLES + o alignment_ok(this_player()) returns false if I am an + evil cleric, or true if I am a good monk, or always + true as a fighter + +LOCATION + /secure/sefun/alignment.c + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/alignment_string b/lib/doc/sefun/alignment_string new file mode 100644 index 0000000..e916dab --- /dev/null +++ b/lib/doc/sefun/alignment_string @@ -0,0 +1,32 @@ + +ALIGNMENT_STRING(1) ALIGNMENT_STRING(1) + +NAME + alignment_string() - returns a string describing a + living's alignment + +SYNOPSIS + string alignment_string(object|int val) + +DESCRIPTION + The function can be passed either a living object or an + integer representing an alignment value. The return value + is a string which describes the alignment of the object or + the alignment value passed. + +EXAMPLES + o alignment_string(0) returns "neutral" + + o alignment_string(this_player()) returns "evil" + +LOCATION + /secure/sefun/alignment.c + +SEE ALSO + alignment_ok() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/ambassadorp b/lib/doc/sefun/ambassadorp new file mode 100644 index 0000000..bd59a9d --- /dev/null +++ b/lib/doc/sefun/ambassadorp @@ -0,0 +1,30 @@ + +AMBASSADORP(1) AMBASSADORP(1) + +NAME + ambassadorp() - returns true if the object is an + ambassador + +SYNOPSIS + int ambassadorp(object ob) + +DESCRIPTION + Returns true if the argument passed is an ambassador. An + ambassador is a user who is listed in the AMBASSADOR group + in /secure/cfg/groups.cfg. + +EXAMPLES + o ambassadorp(this_player()) returns true if + this_player() is an ambassador + +LOCATION + /secure/sefun/pointers.c + +SEE ALSO + archp(), high_mortalp(), leaderp(), userp(), wizardp() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/answers_to b/lib/doc/sefun/answers_to new file mode 100644 index 0000000..1621292 --- /dev/null +++ b/lib/doc/sefun/answers_to @@ -0,0 +1,26 @@ +ANSWERS_TO(1) ANSWERS_TO(1) + +NAME + answers_to() - Determines whether an object answers to a string. + +SYNOPSIS + int answers_to(string name, object what) + +DESCRIPTION + If the specified object answers to the name, 1 is returned, + lese 0 is returned. + +EXAMPLES + o answers_to("big hairy monster", this_object()) + +LOCATION + /secure/sefun/query_name.c + +SEE ALSO + query_name() + +Author + Cratylus + + 1 + diff --git a/lib/doc/sefun/architecture b/lib/doc/sefun/architecture new file mode 100644 index 0000000..ea56fc4 --- /dev/null +++ b/lib/doc/sefun/architecture @@ -0,0 +1,26 @@ + +ARCHITECTURE(1) ARCHITECTURE(1) + +NAME + architecture() - returns the name of the hardware of the + game + +SYNOPSIS + string architecture() + +DESCRIPTION + Returns the name of the hardware platform on which the MUD + is run. + +LOCATION + /secure/sefun/mud_info.c + +SEE ALSO + mud_name(), mudlib(), mudlib_version(), query_host_port(), + version() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/archp b/lib/doc/sefun/archp new file mode 100644 index 0000000..12b7a12 --- /dev/null +++ b/lib/doc/sefun/archp @@ -0,0 +1,30 @@ + +ARCHP(1) ARCHP(1) + +NAME + archp() - returns true for arches + +SYNOPSIS + int archp(object ob) + +DESCRIPTION + For any object which is passed which is a user object and + in either the SUPERUSER or ASSIST groups, this function + returns true. + +EXAMPLES + archp(this_player()) will return true if this_player() is + in the SUPERUSER or ASSIST groups. + +LOCATION + /secure/sefun/pointers.c + +SEE ALSO + ambassadorp(), high_mortalp(), leaderp(), userp(), + wizardp() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/arrange_string b/lib/doc/sefun/arrange_string new file mode 100644 index 0000000..5de0601 --- /dev/null +++ b/lib/doc/sefun/arrange_string @@ -0,0 +1,41 @@ + +ARRANGE_STRING(1) ARRANGE_STRING(1) + +NAME + arrange_string() - arranges a string to a given length + +SYNOPSIS + string arrange_string(string str, int x) + +DESCRIPTION + Passed a string and a length, this function returns the + original string either cut to or extended to the length + specified by the second argument. If the length of the + original string is longer than the length specified, then + all characters beyond the length specified are cut off. + If the length is less than the original string's length, + then the original string is padded with spaces so that it + ends up being as long as the length specified. + +EXAMPLES + o arrange_string("resistence is futile", 25) returns + "resistence is futile " + + o arrange_string("gurble", 2) returns "gu" + +NOTES + Do not use this function inside the mudlib, as it is slow. + Instead use sprintf(). This sefun exists to make life + easy on creators. + +LOCATION + /secure/sefun/strings.c + +SEE ALSO + center(), wrap() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/base_name b/lib/doc/sefun/base_name new file mode 100644 index 0000000..71237c8 --- /dev/null +++ b/lib/doc/sefun/base_name @@ -0,0 +1,32 @@ + +BASE_NAME(1) BASE_NAME(1) + +NAME + base_name() - returns the name of the object's original + file + +SYNOPSIS + string base_name(mixed val) + +DESCRIPTION + If you pass an object name (returned by the file_name() + efun) or an object itself, this function will return the + name of the original file from which the object was loaded + or cloned. For master copies, the base_name() will equal + the file_name(). For clones, the file_name() will be the + base_name() plus an extension. + +EXAMPLES + base_name(find_living("orc")) might return "/std/monster" + +LOCATION + /secure/sefun/base_name.c + +SEE ALSO + file_name() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/cardinal b/lib/doc/sefun/cardinal new file mode 100644 index 0000000..fe57065 --- /dev/null +++ b/lib/doc/sefun/cardinal @@ -0,0 +1,27 @@ + +CARDINAL(1) CARDINAL(1) + +NAME + cardinal() - returns the string description of a number + +SYNOPSIS + string cardinal(int x) + +DESCRIPTION + Given any integer number, this function will return the + number written out in English. + +EXAMPLES + o cardinal(5) returns "five" + +LOCATION + /secure/sefun/english.c + +SEE ALSO + ordinal() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/center b/lib/doc/sefun/center new file mode 100644 index 0000000..d116543 --- /dev/null +++ b/lib/doc/sefun/center @@ -0,0 +1,27 @@ + +CENTER(1) CENTER(1) + +NAME + center() - centers a given string in a field + +SYNOPSIS + varargs string center(string str, int x) + +DESCRIPTION + This function will center the string given as the first + argument in a string field as wide as specified by the + second argument. The second argument is optional. If the + second argument is not supplied, a string width of 80 is + assumed. + +LOCATION + /secure/sefun/strings.c + +SEE ALSO + arrange_string(), wrap() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/check_privs b/lib/doc/sefun/check_privs new file mode 100644 index 0000000..1e67a91 --- /dev/null +++ b/lib/doc/sefun/check_privs @@ -0,0 +1,29 @@ + +CHECK_PRIVS(1) CHECK_PRIVS(1) + +NAME + check_privs() - Determines write privileges to a directory. + +SYNOPSIS + int check_privs(object player, string str) + +DESCRIPTION + Checks whether a player should have write access to a file based +on arch status and home directory. + +EXAMPLES + check_privs(this_player(),"/realms/cratylus") returns 1 if +this_player() is cratylus. + + +LOCATION + /secure/sefun/secure.c + +SEE ALSO + + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/conjunction b/lib/doc/sefun/conjunction new file mode 100644 index 0000000..3048b32 --- /dev/null +++ b/lib/doc/sefun/conjunction @@ -0,0 +1,35 @@ + +CONJUCTION(1) CONJUCTION(1) + +NAME + conjunction() - connects words, phrases or clauses with a + coordinator. + +SYNOPSIS + varargs string conjunction(mixed expressions, + string coordinator) + +DESCRIPTION + Given a number of words, or groups of words, that are used + the same way in a sentence, this function returns a string + which joins them using a coordinator such as and, but, or + or nor. The first argument is the group of words that are + to be joined. The second argument is the coordinator used + to join them. The coordinator defaults to "and". + +EXAMPLES + o conjunction(({"a frog", "twelve trees", + "some whip cream"})) + returns "a frog, twelve trees and some whip cream" + + o conjunction(({"Descartes", "Blitz"}), + "and obviously") + returns "Descartes and obviously Blitz" + + /secure/sefun/english.c + +Author + Rush + + 1 + diff --git a/lib/doc/sefun/consolidate b/lib/doc/sefun/consolidate new file mode 100644 index 0000000..7baf4d9 --- /dev/null +++ b/lib/doc/sefun/consolidate @@ -0,0 +1,34 @@ + +CONSOLIDATE(1) CONSOLIDATE(1) + +NAME + consolidate() - consolidates a string with a number + +SYNOPSIS + string consolidate(int x, string str) + +DESCRIPTION + Given a number of singularly described items, this + function returns a string which describes them in the + plural, reflecting the number of them that exist. The + first argument is the number of things which have the same + singular description. The second argument is their + singular description. + +EXAMPLES + o consolidate(5, "a fish") returns "five fish" + + o consolidate(2, "a knight") returns "two knights" + + head1 LOCATION + + /secure/sefun/english.c + +SEE ALSO + pluralize() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/convert_ascii b/lib/doc/sefun/convert_ascii new file mode 100644 index 0000000..beaaabd --- /dev/null +++ b/lib/doc/sefun/convert_ascii @@ -0,0 +1,25 @@ + +CONVERT_ASCII(1) CONVERT_ASCII(1) + +NAME + convert_ascii() - Translates ascii code to string. + +SYNOPSIS + string convert_ascii(int i) + +DESCRIPTION + This sefun takes an integer as an argument, and if that integer +corresponds to an ASCII code that is in its list, that +ASCII character is returned. + +LOCATION + /secure/sefun/ascii.c + +EXAMPLE + convert_ascii(42) returns "*" + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/convert_name b/lib/doc/sefun/convert_name new file mode 100644 index 0000000..d3f419d --- /dev/null +++ b/lib/doc/sefun/convert_name @@ -0,0 +1,30 @@ + +CONVERT_NAME(1) CONVERT_NAME(1) + +NAME + convert_name() - creates a unique identifier for a name + string + +SYNOPSIS + string convert_name(string str) + +DESCRIPTION + This function takes a capitalized name and returns the + real name any player using that cap name must have. + +EXAMPLES + o convert_name("Descartes of Borg") returns + "descartesofborg" + +NOTES + The value of convert_name((string)player->query_CapName()) + always equals (string)player->query_name(). + +LOCATION + /secure/sefun/convert_name.c + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/copy b/lib/doc/sefun/copy new file mode 100644 index 0000000..7f15ae3 --- /dev/null +++ b/lib/doc/sefun/copy @@ -0,0 +1,40 @@ + +COPY(1) COPY(1) + +NAME + copy() - returns a secure copy of any data type + +SYNOPSIS + mixed copy(mixed val) + +DESCRIPTION + In LPC, mappings and arrays are pointers. This means that + if you set one mapping equal to another, making a change + in one will reflect a change in the other. To understand + this better, read up on these data types. Nevertheless, + there are times when you do not want to be passing around + these pointers. For example, if someone queries your + groups from the master object, you do not want them to get + your groups mapping and be able to modify it. Thus, you + return a copy of that mapping. This sefun makes such + a safe copy. + +EXAMPLES + o given two mappings, mapping a and b, a = ([ "borg" : 1 + ]); b = a; the expression a == b is true. b = copy(a) + sets b equal to ([ "borg" : 1]), but a == b is false. + + head1 NOTES + + Use this only where absolutely needed for security + reasons. It is an expensive sefun as far as CPU + resources are concerned. + +LOCATION + /secure/sefun/copy.c + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/currency_inflation b/lib/doc/sefun/currency_inflation new file mode 100644 index 0000000..9b3d6a0 --- /dev/null +++ b/lib/doc/sefun/currency_inflation @@ -0,0 +1,33 @@ + +CURRENCY_INFLATION(1) CURRENCY_INFLATION(1) + +NAME + currency_inflation() - returns the rate of annual + inflation + +SYNOPSIS + float currency_inflation(string type) + +DESCRIPTION + Given any currency as an argument, this function returns + the rate at which that currency inflates or deflates each + MUD year. + +EXAMPLES + o currency_inflation("gold") might return 0.03, meaning + it's buying power will decrease by 3% over the next + MUD year. In other words, an object which cost 100 + gold today will cost 103 gold this time next year. + +LOCATION + /secure/sefun/economy.c + +SEE ALSO + currency_mass(), currency_rate(), currency_value(), + mud_currencies() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/currency_mass b/lib/doc/sefun/currency_mass new file mode 100644 index 0000000..5fce405 --- /dev/null +++ b/lib/doc/sefun/currency_mass @@ -0,0 +1,30 @@ + +CURRENCY_MASS(1) CURRENCY_MASS(1) + +NAME + currency_mass() - returns the mass of a given amount of a + currency + +SYNOPSIS + int currency_mass(string type, int x) + +DESCRIPTION + Given a currency and an amount of that currency, the + function will return the mass. + +EXAMPLES + int currency_mass("gold", 100) might return 4 for 4 mass + units + +LOCATION + /secure/sefun/economy.c + +SEE ALSO + currency_inflation(), currency_rate(), currency_value(), + mud_currencies() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/currency_rate b/lib/doc/sefun/currency_rate new file mode 100644 index 0000000..1c01331 --- /dev/null +++ b/lib/doc/sefun/currency_rate @@ -0,0 +1,33 @@ + +CURRENCY_RATE(1) CURRENCY_RATE(1) + +NAME + currency_rate() - returns how much of a currency equals + one EU + +SYNOPSIS + float currency_rate(string type) + +DESCRIPTION + Given a currency type as an argument, this function will + tell you how much of that currency is needed to equal one + EU, or economic unit. An economic unit is a base value + used by the mud to set relative values. The set_value() + function in objects uses EU's. + +EXAMPLES + currency_rate("gold") would return 1.5 if, for example, it + takes 3 gold to buy something that has a set_value() of 2. + +LOCATION + /secure/sefun/economy.c + +SEE ALSO + currency_inflation(), currency_mass(), currency_value(), + mud_currencies() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/currency_value b/lib/doc/sefun/currency_value new file mode 100644 index 0000000..08aae66 --- /dev/null +++ b/lib/doc/sefun/currency_value @@ -0,0 +1,30 @@ + +CURRENCY_VALUE(1) CURRENCY_VALUE(1) + +NAME + currency_value() - returns how much in EU's an amount of a + currency is + +SYNOPSIS + int currency_value(int x, string str) + +DESCRIPTION + Given an amount of a currency, this returns its worth in + EU's, or economic units, the base measurement of relative + economic worth. + +EXAMPLES + If the currency rate of gold is 1.5, then + currency_value(10, "gold") will return 15. + +LOCATION + /secure/sefun/economy.c + +SEE ALSO + currency_inflation(), currency_mass(), currency_rate() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/damerau_levenshtein_distance b/lib/doc/sefun/damerau_levenshtein_distance new file mode 100644 index 0000000..e099fec --- /dev/null +++ b/lib/doc/sefun/damerau_levenshtein_distance @@ -0,0 +1,24 @@ +damerau_levenshtein_distance - compute Damerau-Levenshtein distance of two strings + +SYNOPSIS + int damerau_levenshtein_distance(string a, string b) + +DESCRIPTION + Computes the Damarau-Levenshtein distance between strings a and b, + which is the number of insertions, deletions, replacements or + transpositions necessary to transform one to the other provided + that no substring is modified more than once. For more information, + see http://en.wikipedia.org/wiki/Damerau-Levenshtein_distance. + +EXAMPLE + > eval -b damerau_levenshtein_distance("kitten", "mittens") + [Integer] 2 + > eval -b damerau_levenshtein_distance("terrible", "tortuous") + [Integer] 6 + > eval -b damerau_levenshtein_distance("terrible", "tribble") + [Integer] 2 + > eval -b damerau_levenshtein_distance("know", "nkow") + [Integer] 1 + +SEE ALSO + levenshtein_distance(sefun), regexp(efun) diff --git a/lib/doc/sefun/date b/lib/doc/sefun/date new file mode 100644 index 0000000..3eba136 --- /dev/null +++ b/lib/doc/sefun/date @@ -0,0 +1,29 @@ + +DATE(1) DATE(1) + +NAME + date() - returns the date in the month at a given time + (MUD time) + +SYNOPSIS + int date(int x) + +DESCRIPTION + Returns what day of the month is represented by the first + argument, which is assumed to be a time integer. + +EXAMPLES + o date(time()) returned 6 today, meaning it is Altki + 6th. + +LOCATION + /secure/sefun/time.c + +SEE ALSO + day(), hour(), minutes(), month(), query_night(), year() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/day b/lib/doc/sefun/day new file mode 100644 index 0000000..ecf383f --- /dev/null +++ b/lib/doc/sefun/day @@ -0,0 +1,27 @@ + +DAY(1) DAY(1) + +NAME + day() - returns the name of the day in MUD time + +SYNOPSIS + string day(int x) + +DESCRIPTION + Given a time integer as an argument, this will return the + day at that time. + +EXAMPLES + day(time()) returns "Shadowday" today + +LOCATION + /secure/sefun/time.c + +SEE ALSO + day(), hour(), minutes(), month(), query_night(), year() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/debug b/lib/doc/sefun/debug new file mode 100644 index 0000000..ead271b --- /dev/null +++ b/lib/doc/sefun/debug @@ -0,0 +1,27 @@ + +DEBUG(1) DEBUG(1) + +NAME + debug() - Generates messages useful for debugging. + +SYNOPSIS + varargs void debug(mixed msg, string color) + +DESCRIPTION + This command sends 'msg' to all users() who have +enabled receipt of debug info with the debug command. +The optional 'color' indicates what color the message +should be. + +EXAMPLE + +In a misbehaving npc: + debug("My skills: " + identify(this_object()->GetSkills()),"red"); + +LOCATION + /secure/sefun/communications.c + +Author + Cratylus @ Dead Souls + + 1 diff --git a/lib/doc/sefun/destruct b/lib/doc/sefun/destruct new file mode 100644 index 0000000..664f0bf --- /dev/null +++ b/lib/doc/sefun/destruct @@ -0,0 +1,27 @@ + +DESTRUCT(1) DESTRUCT(1) + +NAME + destruct() - provides security for the destruct() efun + +SYNOPSIS + int destruct(object ob) + +DESCRIPTION + Since the MudOS efun destruct() appropriately has no + security tied to it, and the Nightmare Mudlib wished + destructions to be tied to security, the Nightmare Mudlib + overrides the MudOS destruct() efun. The destruct() efun + removes the object passed from memory. + +LOCATION + /secure/sefun/sefun.c + +SEE ALSO + destruct() efun + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/distinct_array b/lib/doc/sefun/distinct_array new file mode 100644 index 0000000..28abc47 --- /dev/null +++ b/lib/doc/sefun/distinct_array @@ -0,0 +1,32 @@ + +DISTINCT_ARRAY(1) DISTINCT_ARRAY(1) + +NAME + distinct_array() - returns an array of distinct members + +SYNOPSIS + mixed *distinct_array(mixed *arr) + +DESCRIPTION + With the first argument of an array of any type, this + function will filter out duplicate members and return an + array with only unique members. + +EXAMPLES + distinct_array(({ "a", "b", "c", "b", "d", "a" })) returns + ({ "a", "b", "c", "d" }) + +NOTE + The order of the result array is NOT guaranteed. + +LOCATION + /secure/sefun/distinct_array.c + +SEE ALSO + exclude_array() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/domain b/lib/doc/sefun/domain new file mode 100644 index 0000000..f48a3f8 --- /dev/null +++ b/lib/doc/sefun/domain @@ -0,0 +1,49 @@ + +DOMAIN(1) DOMAIN(1) + +NAME + domain() - returns the domain to which an object belongs + +SYNOPSIS + string domain(object|string val) + +DESCRIPTION + Given an object as an argument, domain() will return the + domain to which the object belongs based on its file name. + If a string is passed, the string is assumed to be the + file name of an object and the function will return the + domain associated with that file name. + + Domains are determined based on the following criteria: + + o the return from query_domain() in the object if that + value is a valid domain and the first argument is an + object or a loadable file + + o the domain from which the object comes if its file name + is from the mudlib domains directory + + o if the object is from a creator home directory, it + checks the sub-directory of that home directory from + which it came and returns it if it is a valid domain + =back + +EXAMPLES + o domain(ob) will return "NorthForest" if the file name + is "/domains/NorthForest/sword" and ob->query_domain() + returns 0 + + o domain("/realms/descartes/Orlith/entrance") returns + "Orlith" + +LOCATION + /secure/sefun/domains.c + +SEE ALSO + domain_master(), domain_exists() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/domain_exists b/lib/doc/sefun/domain_exists new file mode 100644 index 0000000..964fef6 --- /dev/null +++ b/lib/doc/sefun/domain_exists @@ -0,0 +1,29 @@ + +DOMAIN_EXISTS(1) DOMAIN_EXISTS(1) + +NAME + domain_exists() - returns true if the given string is a + valid domain + +SYNOPSIS + int domain_exists(string dmn) + +DESCRIPTION + Given any string, this function will return true if the + string is the name of a valid domain. + +EXAMPLES + domain_exists("Praxis") returns true if there is a + directory called "/domains/Praxis" + +LOCATION + /secure/sefun/domain_exists.c + +SEE ALSO + domain(), domain_master() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/domain_master b/lib/doc/sefun/domain_master new file mode 100644 index 0000000..938e5f9 --- /dev/null +++ b/lib/doc/sefun/domain_master @@ -0,0 +1,31 @@ + +DOMAIN_MASTER(1) DOMAIN_MASTER(1) + +NAME + domain_master() - returns the master object for a given + domain + +SYNOPSIS + object domain_master(string|object val) + +DESCRIPTION + Given a file name or an object, this function will return + the object which controls the functions of the domain from + which it comes. + +EXAMPLES + o domain_master("/realms/descartes/NorthForest/room/entrance") + will return the object + "/domains/NorthForest/adm/master" + +LOCATION + /secure/sefun/domains.c + +SEE ALSO + domain(), domain_exists() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/effective_light b/lib/doc/sefun/effective_light new file mode 100644 index 0000000..4294dd4 --- /dev/null +++ b/lib/doc/sefun/effective_light @@ -0,0 +1,29 @@ + +EFFECTIVE_LIGHT(1) EFFECTIVE_LIGHT(1) + +NAME + effective_light() - returns the amount of light available + to an object + +SYNOPSIS + int effective_light(object ob) + +DESCRIPTION + Passed an object, this function returns the amount of + light available specifically for that object. This + differs from total_light() in that total_light() returns + the total amount of light available for any user in an + environment, whereas effective_light() takes into account + individual factors such as night vision, sunglasses, etc. + +LOCATION + /secure/sefun/light.c + +SEE ALSO + moon_light(), total_light() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/event b/lib/doc/sefun/event new file mode 100644 index 0000000..84ca300 --- /dev/null +++ b/lib/doc/sefun/event @@ -0,0 +1,41 @@ + +EVENT(1) EVENT(1) + +NAME + event() - sets up an event to occur regularly + +SYNOPSIS + varargs void event(string fun, int when, mixed *args, int + reg) + +DESCRIPTION + This function is exactly like the call_out() efun, except + in that this sefun works across reboots. This is + useful for setting up long terms events, such as monthly + goblin raids or lunar based lycanthropy. The first + argument is a string representing the name of the function + to be called. The second argument is how long after + event() is called that the first event should happen. The + third and fourth arguments are optional. If given, the + third argument is an array of arguments to be passed to + the function when it is called. In addition, the fourth + argument, is a flag. If given and 1, it flags the event + to be recurring. If not give or 0, the event will only + happen the first time. + +EXAMPLES + o event("call_war", MONTH) will set the function + call_war() to be called one mud month from now + +LOCATION + /secure/sefun/events.c + +SEE ALSO + call_out(), event_pending(), remove_call_out(), + set_heart_beat() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/event_pending b/lib/doc/sefun/event_pending new file mode 100644 index 0000000..8bdb5e1 --- /dev/null +++ b/lib/doc/sefun/event_pending @@ -0,0 +1,25 @@ + +EVENT_PENDING(1) EVENT_PENDING(1) + +NAME + event_pending() - returns true if an event is pending for + an object + +SYNOPSIS + int event_pending(object ob) + +DESCRIPTION + If an event is pending for the object which you pass, then + the function returns 1. Otherwise it returns 0. + +LOCATION + /secure/sefun/events.c + +SEE ALSO + call_out(), event(), remove_call_out(), set_heart_beat() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/exclude_array b/lib/doc/sefun/exclude_array new file mode 100644 index 0000000..13e2cf1 --- /dev/null +++ b/lib/doc/sefun/exclude_array @@ -0,0 +1,37 @@ + +EXCLUDE_ARRAY(1) EXCLUDE_ARRAY(1) + +NAME + exclude_array() - excludes 1 or more elements from an + array + +SYNOPSIS + varargs mixed *exclude_array(mixed *array, int from, int + to) + +DESCRIPTION + Given any type of an array as a first argument, this + sefun will return a different array with the elements + from the element in the second argument up to the elements + in the third argument removed from the original. If the + third argument is omitted, then only the element in the + second argument will be omitted. + +EXAMPLES + o exclude_array(({ "a", "b", "c" }), 1) returns ({ "a", + "c" }) + + o exclude_array(({ "a", "b", "c", "d" }), 1, 2) returns + ({ "a", "d" }) + +LOCATION + /secure/sefun/exclude_array.c + +SEE ALSO + distinct_array() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/exec b/lib/doc/sefun/exec new file mode 100644 index 0000000..b0bc568 --- /dev/null +++ b/lib/doc/sefun/exec @@ -0,0 +1,25 @@ + +EXEC(1) EXEC(1) + +NAME + exec() - provides security for the MudOS exec() efun + +SYNOPSIS + int exec(object target, object src) + +DESCRIPTION + Since MudOS appropriately provides no security for this + efun, the mudlib must decide what security it wants in an + efun override. + +LOCATION + /secure/sefun/sefun.c + +SEE ALSO + the exec() efun + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/false b/lib/doc/sefun/false new file mode 100644 index 0000000..62aeab1 --- /dev/null +++ b/lib/doc/sefun/false @@ -0,0 +1,24 @@ + +FALSE(1) FALSE(1) + +NAME + false() - Always returns a 0. + +SYNOPSIS + int false() + +DESCRIPTION + This function is mostly just cosmetic. There are circumstances where +I feel wrong not having SOMETHING happen, so there is this. + +LOCATION + /secure/sefun/generic.c + +SEE ALSO + true() + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/file_exists b/lib/doc/sefun/file_exists new file mode 100644 index 0000000..d027b5d --- /dev/null +++ b/lib/doc/sefun/file_exists @@ -0,0 +1,25 @@ + +FILE_EXISTS(1) FILE_EXISTS(1) + +NAME + file_exists() - returns true if the string passed is a + file + +SYNOPSIS + int file_exists(string str) + +DESCRIPTION + Allows you to test to see if a file by the name passed as + an argument exists. + +LOCATION + /secure/sefun/files.c + +SEE ALSO + file_size() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/file_privs b/lib/doc/sefun/file_privs new file mode 100644 index 0000000..a73385f --- /dev/null +++ b/lib/doc/sefun/file_privs @@ -0,0 +1,26 @@ + +FILE_PRIVS(1) FILE_PRIVS(1) + +NAME + file_privs() - returns the level of protection for a file + +SYNOPSIS + string file_privs(string file) + +DESCRIPTION + Returns a string which represents the level of protection + which is enjoyed by the file. With the exception of use + objects, objects which derive from the file name passed + will also have access which at least matches these privs. + +LOCATION + /secure/sefun/security.c + +SEE ALSO + member_group(), unguarded() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/first b/lib/doc/sefun/first new file mode 100644 index 0000000..80caeff --- /dev/null +++ b/lib/doc/sefun/first @@ -0,0 +1,25 @@ + +FIRST(1) FIRST(1) + +NAME + first() - Outputs the specified first N characters of a string. + +SYNOPSIS + string first(string str, int i) + +DESCRIPTION + Provided a string and integer i, it will return the first i +characters in the string. + +EXAMPLES + first("DeadSouls",4) returns "Dead" + first("platypus",1) returns "p" + +LOCATION + /secure/sefun/strings.c + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/first_string_element b/lib/doc/sefun/first_string_element new file mode 100644 index 0000000..e7a3cb0 --- /dev/null +++ b/lib/doc/sefun/first_string_element @@ -0,0 +1,33 @@ + +FIRST_STRING_ELEMENT(1) FIRST_STRING_ELEMENT(1) + +NAME + first_string_element() - Extracts the contents of a string before a delimiter. + +SYNOPSIS + string first_string_element(string path, string delimiter, int stripfirst) + +DESCRIPTION + Pretty much just tries to figure out what the top-level subdirectory +is of a file. It can be used with delimiters other than "/" if need be. If +used with a full pathname, the "stripfirst" flag should be set. If you don't +set the stripfirst flag and your string's first character is a delimiter, it +will return a null string. + +EXAMPLES + first_string_element("/realms/cratylus/workroom.c","/",1) + +returns "realms". + + +LOCATION + /secure/sefun/strings.c + +SEE ALSO + last_string_element + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/flat_map b/lib/doc/sefun/flat_map new file mode 100644 index 0000000..437d959 --- /dev/null +++ b/lib/doc/sefun/flat_map @@ -0,0 +1,30 @@ + +FLAT_MAP(1) FLAT_MAP(1) + +NAME + flat_map() - returns a string that describes the contents of a mapping. + +SYNOPSIS + string flat_map(mapping mp) + +DESCRIPTION + Each member of an array is read and to a limited degree it +is stringified and returned. This efun is of limited use and is being +kept for historical and sentimental reasons only. The identify() sefun +is the preferred method for stringifying mappings. + +EXAMPLES + flat_map(this_user()->GetSkill("bargaining")) + + +LOCATION + /secure/sefun/mappings.c + +SEE ALSO + identify() + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/format_page b/lib/doc/sefun/format_page new file mode 100644 index 0000000..7745bfb --- /dev/null +++ b/lib/doc/sefun/format_page @@ -0,0 +1,39 @@ + +FORMAT_PAGE(1) FORMAT_PAGE(1) + +NAME + format_page() - returns a string of formatted columns from + an array + +SYNOPSIS + string format_page(string *items, int columns) + +DESCRIPTION + Given an array of strings and a number of columns as + arguments, this function formats the array into a single + string with the elements put into the number of columns + specified. Unfortunately, as this sefun predates + Nightmare terminal support, this sefun only supports + 80 character screen widths. + +EXAMPLES + format_page(({ "house", "car", "cat", "mouse", "dog" }), + 3) returns "house car + cat + mouse dog" + +NOTES + This sefun is pretty much out of date and useless for + new uses. + +LOCATION + /secure/sefun/strings.c + +SEE ALSO + arrange_string(), center(), format_string(), wrap() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/format_string b/lib/doc/sefun/format_string new file mode 100644 index 0000000..48cc6c1 --- /dev/null +++ b/lib/doc/sefun/format_string @@ -0,0 +1,25 @@ + +FORMAT_STRING(1) FORMAT_STRING(1) + +NAME + format_string() - returns a formatted string like + sprintf() + +SYNOPSIS + string format_string(string format, mixed *variables) + +DESCRIPTION + Boggle me why this exists. It comes from the Portals + Mudlib, so I must have brought it over when sockets first + came out so the example code would not break. Don't use + it, it is slow and pointless. + +SEE ALSO + arrange_string(), center(), format_page(), printf(), + sprintf(), wrap() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/generate_tmp b/lib/doc/sefun/generate_tmp new file mode 100644 index 0000000..57fed99 --- /dev/null +++ b/lib/doc/sefun/generate_tmp @@ -0,0 +1,30 @@ + +GENERATE_TMP(1) GENERATE_TMP(1) + +NAME + generate_tmp() - Create a unique temp filename. + +SYNOPSIS + varargs string generate_tmp(mixed arg) + +DESCRIPTION + If the user has a home directory, the function tries +to use their tmp/ dir, otherwise /open is used. The filename is +generated by using the arguments, if any, and adding them to +ctime plus some random characters for good measure. + +EXAMPLES + generate_tmp(this_player()) returns "/realms/cratylus/tmp/cratylus80irhLDFd7sWg1140052843.c" + + +LOCATION + /secure/sefun/strings.c + +SEE ALSO + + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/get_cmds b/lib/doc/sefun/get_cmds new file mode 100644 index 0000000..b07feb0 --- /dev/null +++ b/lib/doc/sefun/get_cmds @@ -0,0 +1,23 @@ + +GET_CMDS(1) GET_CMDS(1) + +NAME + get_cmds() - Returns a list of available commands. + +SYNOPSIS + string *get_cmds() + +DESCRIPTION + Provides an array of available commands in /cmds and /secure/cmds. + +LOCATION + /secure/sefun/get_cmds.c + +SEE ALSO + get_cmds() + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/get_livings b/lib/doc/sefun/get_livings new file mode 100644 index 0000000..30f2734 --- /dev/null +++ b/lib/doc/sefun/get_livings @@ -0,0 +1,27 @@ + +GET_LIVINGS(1) GET_LIVINGS(1) + +NAME + get_livings() - Lists living things in a container. + +SYNOPSIS + varargs object array get_livings(object container, int foo) + +DESCRIPTION + Without a second argument, a list of all living things in +"container" is returned in array form. If the second argument is the +integer 1, only interactive living things (players and creators) are +returned. If the integer is 2, only non-interactive living things are +returned. + +EXAMPLES + get_livings(environment(this_player()), 1) + +LOCATION + /secure/sefun/get_livings.c + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/get_object b/lib/doc/sefun/get_object new file mode 100644 index 0000000..5fb6786 --- /dev/null +++ b/lib/doc/sefun/get_object @@ -0,0 +1,27 @@ + +GET_STD_ITEM(1) GET_OBJECT(1) + +NAME + get_object() - returns an object represented by a string + +SYNOPSIS + varargs object get_object(string str, object player) + +DESCRIPTION + Returns an object which is represented by the string + passed as the first argument. If the second argument is + given, the string is resolved with respect to that player + object. Otherwise the string is resolved with respect to + the value of this_player(). + +LOCATION + /secure/sefun/get_object.c + +SEE ALSO + find_object(), get_objects(), load_object() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/get_random_living b/lib/doc/sefun/get_random_living new file mode 100644 index 0000000..ec1f85b --- /dev/null +++ b/lib/doc/sefun/get_random_living @@ -0,0 +1,28 @@ + +GET_RANDOM_LIVING(1) GET_RANDOM_LIVING(1) + +NAME + get_random_livings() - Randomly picks a living thing in a container. + +SYNOPSIS + varargs object get_random_living(object container, int foo) + +DESCRIPTION + Without a second argument, a living creature in the "container" +is selected at random. If the second argument is the integer 1, only +interactive living things are eligible for the selection. If the +integer is 2, only non-interactive living things are eligible for the +selection. + + +EXAMPLES + get_random_living(environment(this_player()), 1) + +LOCATION + /secure/sefun/get_livings.c + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/get_verbs b/lib/doc/sefun/get_verbs new file mode 100644 index 0000000..a5f3511 --- /dev/null +++ b/lib/doc/sefun/get_verbs @@ -0,0 +1,23 @@ + +GET_VERBS(1) GET_VERBS(1) + +NAME + get_verbs() - Returns a list of available verbs. + +SYNOPSIS + string *get_verbs() + +DESCRIPTION + Provides an array of files in the /verbs/* directories. + +LOCATION + /secure/sefun/get_verbs.c + +SEE ALSO + get_cmds() + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/grepp b/lib/doc/sefun/grepp new file mode 100644 index 0000000..a255aa9 --- /dev/null +++ b/lib/doc/sefun/grepp @@ -0,0 +1,30 @@ + +GREPP(1) GREPP(1) + +NAME + grepp() - Whether a given substring is in a string. + +SYNOPSIS + grepp(string primary, string sub) + +DESCRIPTION + If sub is a member of primary, returns 1. Otherwise, returns 0. It +is basically a prettification of strsrch, which is the preferred way +of doing it. This sefun is much more expensive to use than the strsrch +efun, but it's easier to read. + +EXAMPLES + grepp("foo, barbaz", "baz") would return 1 + grepp("foo, barbaz", "shiz") would return 0 + +SEE ALSO + strsrch + + +LOCATION + /secure/sefun/strings.c + +Author + Cratylus @ Dead Souls + + 1 diff --git a/lib/doc/sefun/hiddenp b/lib/doc/sefun/hiddenp new file mode 100644 index 0000000..6715684 --- /dev/null +++ b/lib/doc/sefun/hiddenp @@ -0,0 +1,21 @@ + +HIDDENP(1) HIDDENP(1) + +NAME + hiddenp() - returns true if the object is hidden + +SYNOPSIS + int hiddenp(object ob) + +DESCRIPTION + Takes an object as an argument and returns true if that + object is hidden. + +LOCATION + /secure/sefun/pointers.c + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/high_mortalp b/lib/doc/sefun/high_mortalp new file mode 100644 index 0000000..4bcf417 --- /dev/null +++ b/lib/doc/sefun/high_mortalp @@ -0,0 +1,26 @@ + +HIGH_MORTALP(1) HIGH_MORTALP(1) + +NAME + high_mortalp() - returns true if the player in question is + high mortal + + =head1 SYNOPSIS + + int high_mortalp(object ob) + +DESCRIPTION + Given an object, this function will return true if that + object is a high mortal. + +LOCATION + /secure/sefun/pointers.c + +SEE ALSO + ambassadorp(), archp(), leaderp(), userp(), wizardp() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/hour b/lib/doc/sefun/hour new file mode 100644 index 0000000..9fdf6c2 --- /dev/null +++ b/lib/doc/sefun/hour @@ -0,0 +1,27 @@ + +HOUR(1) HOUR(1) + +NAME + hour() - returns the hour at the time given + +SYNOPSIS + int hour(int x) + +DESCRIPTION + Given a time integer as an argument, this function returns + what hour of the day that time represents in MUD time. + +EXAMPLES + o hour(time()) returns at this moment 5 + +LOCATION + /secure/sefun/time.c + +SEE ALSO + date(), day(), minutes(), month(), query_night(), year() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/identify b/lib/doc/sefun/identify new file mode 100644 index 0000000..87bc574 --- /dev/null +++ b/lib/doc/sefun/identify @@ -0,0 +1,28 @@ + +IDENTIFY(1) IDENTIFY(1) + +NAME + identify() - returns a string version of any data type + +SYNOPSIS + string identify(mixed a) + +DESCRIPTION + Given any argument passed, this function will return a + string which represents that argument. + +EXAMPLES + identify(this_player()) returns OBJ("descartes", + "/secure/save/users/d/descartes") + +LOCATION + /secure/sefun/identify.c + +SEE ALSO + sprintf() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/indent_file b/lib/doc/sefun/indent_file new file mode 100644 index 0000000..020c76b --- /dev/null +++ b/lib/doc/sefun/indent_file @@ -0,0 +1,27 @@ + +INDENT_FILE(1) INDENT_FILE(1) + +NAME + indent_file() - Make a file more readable. + +SYNOPSIS + int indent_file(string file) + +DESCRIPTION + Provided a filename, it makes a temporary copy, indents the copy, +then copies the indented version over the original. + +EXAMPLES + indent_file("/home/cratylus/workroom") + +LOCATION + /secure/sefun/files.c + +SEE ALSO + save_file, file_exists, directory exists + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/last b/lib/doc/sefun/last new file mode 100644 index 0000000..0f628d7 --- /dev/null +++ b/lib/doc/sefun/last @@ -0,0 +1,28 @@ + +LAST(1) LAST(1) + +NAME + last() - Outputs the specified last N characters of a string. + +SYNOPSIS + string last(string str, int i, int significant) + +DESCRIPTION + Provided a string and integer i, it will +return the last i characters in the string. If the +"significant" flag is set, blank spaces at the end +of the string are ignored. + +EXAMPLES + last("platypus",3) returns "pus" + last("echidna ",1) returns " " + last("sassafras ",2,1) returns "as" + +LOCATION + /secure/sefun/strings.c + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/last_string_element b/lib/doc/sefun/last_string_element new file mode 100644 index 0000000..f4d254a --- /dev/null +++ b/lib/doc/sefun/last_string_element @@ -0,0 +1,29 @@ + +LAST_STRING_ELEMENT(1) LAST_STRING_ELEMENT(1) + +NAME + last_string_element() - Extracts the contents of a string after the last delimiter. + +SYNOPSIS + string last_string_element(string path, string delimiter) + +DESCRIPTION + The opposite of first_string_element, this function returns the end of +a string after the last delimiter. + +EXAMPLES + last_string_element("/realms/cratylus/workroom.c","/") + +returns "workroom.c". + +LOCATION + /secure/sefun/strings.c + +SEE ALSO + first_string_element + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/leaderp b/lib/doc/sefun/leaderp new file mode 100644 index 0000000..53ec58b --- /dev/null +++ b/lib/doc/sefun/leaderp @@ -0,0 +1,25 @@ + +LEADERP(1) LEADERP(1) + +NAME + leaderp() - returns true if the player is an elected + leader + +SYNOPSIS + int leaderp(object ob) + +DESCRIPTION + Given an object as an argument, leaderp() will return true + if that player is an elected leader. + +LOCATION + /secure/sefun/pointers.c + +SEE ALSO + ambassadorp(), archp(), high_mortalp(), userp(), wizardp() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/levenshtein_distance b/lib/doc/sefun/levenshtein_distance new file mode 100644 index 0000000..bf71f03 --- /dev/null +++ b/lib/doc/sefun/levenshtein_distance @@ -0,0 +1,23 @@ +levenshtein_distance - compute Levenshtein distance of two strings + +SYNOPSIS + int levenshtein_distance(string a, string b) + +DESCRIPTION + Computes the Levenshtein distance between strings a and b, + which is the number of insertions, deletions, or replacements + necessary to transform one to the other. For more information, + see http://en.wikipedia.org/wiki/Levenshtein_distance. + +EXAMPLE + > eval -b levenshtein_distance("kitten", "mittens") + [Integer] 2 + > eval -b levenshtein_distance("terrible", "tortuous") + [Integer] 6 + > eval -b levenshtein_distance("terrible", "tribble") + [Integer] 2 + > eval -b levenshtein_distance("know", "nkow") + [Integer] 2 + +SEE ALSO + damerau_levenshtein_distance(sefun), regexp(efun) diff --git a/lib/doc/sefun/livings b/lib/doc/sefun/livings new file mode 100644 index 0000000..88318e5 --- /dev/null +++ b/lib/doc/sefun/livings @@ -0,0 +1,25 @@ + +LIVINGS(1) LIVINGS(1) + +NAME + livings() - returns an array of all living objects + +SYNOPSIS + object *livings() + +DESCRIPTION + A security mask for the livings() efun. Filters out + hidden objects for non-priveledged objects making the + call. + +LOCATION + /secure/sefun/sefun.c + +SEE ALSO + the livings() efun + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/load_object b/lib/doc/sefun/load_object new file mode 100644 index 0000000..426017b --- /dev/null +++ b/lib/doc/sefun/load_object @@ -0,0 +1,26 @@ + +LOAD_STD_ITEM(1) LOAD_OBJECT(1) + +NAME + load_object() - returns an object, loads it if not already + loaded + +SYNOPSIS + object load_object(string str) + +DESCRIPTION + Much like the find_object() efun, this sefun will try + to load the object in question if it is unable to find one + already loaded. + +LOCATION + /secure/sefun/load_object.c + +SEE ALSO + find_object() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/local_time b/lib/doc/sefun/local_time new file mode 100644 index 0000000..f439f8f --- /dev/null +++ b/lib/doc/sefun/local_time @@ -0,0 +1,27 @@ + +LOCAL_TIME(1) LOCAL_TIME(1) + +NAME + local_time() - Provides information about the time of day. + +SYNOPSIS + string local_time(string str) + +DESCRIPTION + Without an argument, local_time() returns an array in the +format of the localtime() efun with information about the local time +in the current timezone. With a valid timezone as an argument, it +returns a string in the format of ctime() with the local time for +the specified timezone. + +EXAMPLES + local_time("PST") + +LOCATION + /secure/sefun/local_time.c + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/log_file b/lib/doc/sefun/log_file new file mode 100644 index 0000000..e7d7a7e --- /dev/null +++ b/lib/doc/sefun/log_file @@ -0,0 +1,27 @@ + +LOG_FILE(1) LOG_FILE(1) + +NAME + log_file() - logs a string to a file + +SYNOPSIS + void log_file(string fl, string msg) + +DESCRIPTION + Will write the string passed as the second argument to the + file passed as the second argument under the log + directory. If the object doing the logging is not an + approved secure object, then the log goes under the etc + sub-directory of the log directory. + +LOCATION + /secure/sefun/log_file.c + +SEE ALSO + read_file(), write_file() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/member_group b/lib/doc/sefun/member_group new file mode 100644 index 0000000..1dfde45 --- /dev/null +++ b/lib/doc/sefun/member_group @@ -0,0 +1,33 @@ + +MEMBER_GROUP(1) MEMBER_GROUP(1) + +NAME + member_group() - returns true if a person is a member of + the group passed + +SYNOPSIS + int member_group(string|object who, string grp) + +DESCRIPTION + The first argument, either a user object or the name of a + user, is tested to see if the user is a member of the + group which goes by the name passed as the second + argument. If the user is a member of that group, then the + function returns true. Otherwise the function will return + false. + +EXAMPLES + o member_group("descartes", "SUPERUSER") would return + true on Nightmare LPMud + +LOCATION + /secure/sefun/security.c + +SEE ALSO + file_privs() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/memberp b/lib/doc/sefun/memberp new file mode 100644 index 0000000..08632d4 --- /dev/null +++ b/lib/doc/sefun/memberp @@ -0,0 +1,27 @@ + +MEMBERP(1) MEMBERP(1) + +NAME + memberp() - Determines whether a thing is a member of an array. + +SYNOPSIS + int memberp(mixed *primary, mixed sub) + +DESCRIPTION + If sub is a member of primary, returns 1. Otherwise, returns 0. It +is basically a prettification of member_array, which is the preferred way +of doing it. This sefun is much more expensive to use than the member_array +efun, but it's easier to read. + +EXAMPLES + memberp(({"foo","bar","baz"}), "baz") would return 1 + memberp(({"foo","bar","baz"}), "shiz") would return 0 + + +LOCATION + /secure/sefun/strings.c + +Author + Cratylus @ Dead Souls + + 1 diff --git a/lib/doc/sefun/minutes b/lib/doc/sefun/minutes new file mode 100644 index 0000000..d0bef48 --- /dev/null +++ b/lib/doc/sefun/minutes @@ -0,0 +1,29 @@ + +MINUTES(1) MINUTES(1) + +NAME + minutes() - returns the number of minutes past the MUD + hour + +SYNOPSIS + int minutes(int x) + +DESCRIPTION + Given an integer time as an argument, this function will + return the number of minutes past the hour at the time + which was given. + +EXAMPLES + o minutes(time()) at this moment returns 19 + +LOCAITON + /secure/sefun/time.c + +SEE ALSO + date(), day(), hour(), month(), query_night(), year() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/month b/lib/doc/sefun/month new file mode 100644 index 0000000..0e32d27 --- /dev/null +++ b/lib/doc/sefun/month @@ -0,0 +1,27 @@ + +MONTH(1) MONTH(1) + +NAME + month() - returns the name of the month at a given time + +SYNOPSIS + string month(int x) + +DESCRIPTION + Given an integer formatted time, this function will return + the name of the month in MUD time for that time. + +EXAMPLES + o month(time()) this moment returns "Altki" + +LOCATION + /secure/sefun/time.c + +SEE ALSO + date(), day(), hour(), minutes(), query_night(), year() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/moon_light b/lib/doc/sefun/moon_light new file mode 100644 index 0000000..4f4fd2c --- /dev/null +++ b/lib/doc/sefun/moon_light @@ -0,0 +1,27 @@ + +MOON_LIGHT(1) MOON_LIGHT(1) + +NAME + moon_light() - returns the amount of light the moons are + providing + +SYNOPSIS + int moon_light() + +DESCRIPTION + Since moons necessarily reflect different levels of light + for their different phases, this function will return the + total amount of light currently being reflected by all + moons. + +LOCATION + /secure/sefun/light.c + +SEE ALSO + effective_light(), total_light() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/mud_currencies b/lib/doc/sefun/mud_currencies new file mode 100644 index 0000000..834abd8 --- /dev/null +++ b/lib/doc/sefun/mud_currencies @@ -0,0 +1,24 @@ + +MUD_CURRENCIES(1) MUD_CURRENCIES(1) + +NAME + mud_currencies() - returns an array of all MUD currencies + +SYNOPSIS + string *mud_currencies() + +DESCRIPTION + Returns all currencies which exist on the MUD as an array. + +LOCATION + /secure/sefun/economy.c + +SEE ALSO + currency_inflation(), currency_mass(), currency_rate(), + currency_value() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/mud_name b/lib/doc/sefun/mud_name new file mode 100644 index 0000000..6ef8a14 --- /dev/null +++ b/lib/doc/sefun/mud_name @@ -0,0 +1,33 @@ + +MUD_NAME(1) MUD_NAME(1) + +NAME + mud_name() - returns the name of the MUD + +SYNOPSIS + string mud_name() + +DESCRIPTION + Returns the official name of the MUD. This information is + taken from the driver config file. + +NOTES + If you are pretty stable with your MUD's name, then you + really do not need to use this function. It is used + through the mudlib, since the mudlib may be used on many + MUDs. Using this once your MUD is relatively stable will + server to slow things down when you do not need the + flexibility. + +LOCATION + /secure/sefun/mud_info.c + +SEE ALSO + architecture(), mudlib(), mudlib_version(), + query_host_port(), version() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/mudlib b/lib/doc/sefun/mudlib new file mode 100644 index 0000000..05eb885 --- /dev/null +++ b/lib/doc/sefun/mudlib @@ -0,0 +1,26 @@ + +MUDLIB(1) MUDLIB(1) + +NAME + mudlib() - returns the name of the mudlib + +SYNOPSIS + string mudlib() + +DESCRIPTION + If you are using this documentation, then this function + should return the string "Nightmare", unless, of course, + you are claiming the work of others as your own? + +LOCATION + /secure/sefun/mud_info.c + +SEE ALSO + architecture(), mud_name(), mudlib_version(), + query_host_port(), version() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/mudlib_version b/lib/doc/sefun/mudlib_version new file mode 100644 index 0000000..fc3f0fd --- /dev/null +++ b/lib/doc/sefun/mudlib_version @@ -0,0 +1,31 @@ + +MUDLIB_VERSION(1) MUDLIB_VERSION(1) + +NAME + mudlib_version() - returns the current version of this + mudlib + +SYNOPSIS + string mudlib_version() + +DESCRIPTION + Returns the currenct version of the mudlib you are using. + If you have made local modifications to the mudlib, you + should change this definition in /secure/include/config.h + to reflect your deviation. + +EXAMPLES + o mudlib_version() as of this document will return "3.3" + +LOCATION + /secure/sefun/mud_info.c + +SEE ALSO + architecture(), mud_name(), mudlib(), query_host_port(), + version() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/nominative b/lib/doc/sefun/nominative new file mode 100644 index 0000000..6125856 --- /dev/null +++ b/lib/doc/sefun/nominative @@ -0,0 +1,31 @@ + +NOMINATIVE(1) NOMINATIVE(1) + +NAME + nominative() - returns the nominative pronoun for an + object + +SYNOPSIS + string nominative(string|object val) + +DESCRIPTION + This function takes either a string representing the + gender of a living object or a living object as an + argument. It returns the nominative pronoun ("he", "she", + or "it") depending on the gender. + +EXAMPLES + nominative(this_player()) returns "he" for me, at least on + Nightmare. + +LOCATION + /secure/sefun/english.c + +SEE ALSO + objective(), possessive(), possessive_noun(), reflexive() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/objective b/lib/doc/sefun/objective new file mode 100644 index 0000000..3212bf3 --- /dev/null +++ b/lib/doc/sefun/objective @@ -0,0 +1,30 @@ + +STD_ITEMIVE(1) OBJECTIVE(1) + +NAME + objective() - returns the objective pronoun for a gender + +SYNOPSIS + string objective(string|object val) + +DESCRIPTION + Given an object or a gender string, this function will + return the appropriate objective pronoun ("him", "her", or + "it") for the gender passed, or for the gender of the + object in question. + +EXAMPLES + objective(find_player("lassondra")) returns "her" + + head1 LOCATION + + /secure/sefun/english.c + +SEE ALSO + nominative(), possessive(), possessive_noun(), reflexive() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/ordinal b/lib/doc/sefun/ordinal new file mode 100644 index 0000000..7c5750a --- /dev/null +++ b/lib/doc/sefun/ordinal @@ -0,0 +1,27 @@ + +ORDINAL(1) ORDINAL(1) + +NAME + ordinal() - returns the ordinal suffix for a number + +SYNOPSIS + string ordinal(int x) + +DESCRIPTION + Given an integer, this function returns the ordinal suffix + for the number. + +EXAMPLES + o ordinal(7) returns "th" + +LOCATION + /secure/sefun/english.c + +SEE ALSO + cardinal() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/path_file b/lib/doc/sefun/path_file new file mode 100644 index 0000000..ef6d0e7 --- /dev/null +++ b/lib/doc/sefun/path_file @@ -0,0 +1,31 @@ + +PATH_FILE(1) PATH_FILE(1) + +NAME + path_file() - returns an array of files associated with an + array of files + +SYNOPSIS + mixed *path_file(string|string * full_path) + +DESCRIPTION + Given a path or an array of paths, this function separates + the file name from its path and returns an array with them + separated, or an array of such arrays in the event the + argument passed is an array. + +EXAMPLES + o path_file("/secure/cfg/write.cfg") returns ({ + "/secure/cfg", "write.cfg" }) + +LOCATION + /secure/sefun/path_file.c + +SEE ALSO + absolute_path() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/path_prefix b/lib/doc/sefun/path_prefix new file mode 100644 index 0000000..bf74e9a --- /dev/null +++ b/lib/doc/sefun/path_prefix @@ -0,0 +1,26 @@ + +PATH_PREFIX(1) CHECK_PRIVS(1) + +NAME + path_prefix() - A file's or directory's path without the last element. + +SYNOPSIS + string path_prefix(string filename) + +DESCRIPTION + If given a path, it returns a string with the last path element removed. + +EXAMPLES + path_prefix("/realms/cratylus/workroom.c") + + would return "/realms/cratylus" + + +LOCATION + /secure/sefun/strings.c + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/percent b/lib/doc/sefun/percent new file mode 100644 index 0000000..9b7b8d3 --- /dev/null +++ b/lib/doc/sefun/percent @@ -0,0 +1,28 @@ + +PERCENT(1) PERCENT(1) + +NAME + percent() - returns the percent of one number that another + is + +SYNOPSIS + float percent(int|float numerator, int|float denominator) + +DESCRIPTION + Returns what percent of the second argument that the first + argument is. + +EXAMPLES + o percent(23, 99) returns 23.232323 + +LOCATION + /secure/sefun/percent.c + +SEE ALSO + absolute_value() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/pluralize b/lib/doc/sefun/pluralize new file mode 100644 index 0000000..76b080b --- /dev/null +++ b/lib/doc/sefun/pluralize @@ -0,0 +1,31 @@ + +PLURALIZE(1) PLURALIZE(1) + +NAME + pluralize() - returns the plural of a string or an object + +SYNOPSIS + string pluralize(string|object single) + +DESCRIPTION + Given a string, this function will return its pluralized + for. Given an object, this function will returnthe plural + of its short description. + +EXAMPLES + o pluralize("frog") returns "frogs" + + o pluralize("a globe of frogs") returns "globes of + frogs" + +LOCATION + /secure/sefun/english.c + +SEE ALSO + consolidate() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/possessive b/lib/doc/sefun/possessive new file mode 100644 index 0000000..85d34f8 --- /dev/null +++ b/lib/doc/sefun/possessive @@ -0,0 +1,28 @@ + +POSSESSIVE(1) POSSESSIVE(1) + +NAME + possessive() - returns the possessive pronoun for a gender + +SYNOPSIS + string possessive(mixed val) + +DESCRIPTION + Given a string or an object as an argument, this function + will return the appropriate possessive pronoun ("his", + "her", or "its") for the gender in question. + +EXAMPLES + o possessive(find_living("plant")) returns "its" + +LOCATION + /secure/sefun/english.c + +SEE ALSO + nominative(), objective(), possessive_noun(), reflexive() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/possessive_noun b/lib/doc/sefun/possessive_noun new file mode 100644 index 0000000..c9ac534 --- /dev/null +++ b/lib/doc/sefun/possessive_noun @@ -0,0 +1,28 @@ + +POSSESSIVE_NOUN(1) POSSESSIVE_NOUN(1) + +NAME + possessive_noun() - returns the possessive form of a noun + +SYNOPSIS + string possessive_noun(string|object val) + +DESCRIPTION + Given a string, this function will return the possessive + form of it. Given an object, it will return the + possessive form of that object's short description. + +EXAMPLES + o possessive_noun("Descartes") returns "Descartes'" + +LOCATION + /secure/sefun/english.c + +SEE ALSO + nominative(), objective(), possessive(), reflexive() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/query_custom_command b/lib/doc/sefun/query_custom_command new file mode 100644 index 0000000..acd4b98 --- /dev/null +++ b/lib/doc/sefun/query_custom_command @@ -0,0 +1,20 @@ + +GETCUSTOMCOMMAND(1) GETCUSTOMCOMMAND(1) + +NAME + query_custom_command() - Determines whether a custom command exists. + +SYNOPSIS + string query_custom_command(string str) + +DESCRIPTION + This sefun is used to ensure that a custom command isn't being spoofed. + +LOCATION + /secure/sefun/custom_commands.c + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/query_custom_path b/lib/doc/sefun/query_custom_path new file mode 100644 index 0000000..fb1c903 --- /dev/null +++ b/lib/doc/sefun/query_custom_path @@ -0,0 +1,23 @@ + +GETCUSTOMPATH(1) GETCUSTOMPATH(1) + +NAME + query_custom_path() - returns the directory designated as the +custom commands location. + +SYNOPSIS + string *query_custom_path() + +DESCRIPTION + Creators are expected to have a directory within their +homedir with a standard name which contains user-created, or +"custom" command. This sefun retuns the dir for this_player(). + +LOCATION + /secure/sefun/custom_commands.c + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/query_host_port b/lib/doc/sefun/query_host_port new file mode 100644 index 0000000..d4f0599 --- /dev/null +++ b/lib/doc/sefun/query_host_port @@ -0,0 +1,24 @@ + +QUERY_HOST_PORT(1) QUERY_HOST_PORT(1) + +NAME + query_host_port() - returns the port on which the MUD runs + +SYNOPSIS + int query_host_port() + +DESCRIPTION + Returns the port to which people telnet to access the MUD. + +LOCATION + /secure/sefun/mud_info.c + +SEE ALSO + architecture(), mud_name(), mudlib(), mudlib_version(), + version() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/query_night b/lib/doc/sefun/query_night new file mode 100644 index 0000000..27e908b --- /dev/null +++ b/lib/doc/sefun/query_night @@ -0,0 +1,23 @@ + +QUERY_NIGHT(1) QUERY_NIGHT(1) + +NAME + query_night() - returns true if it is night on the MUD + +SYNOPSIS + int query_night() + +DESCRIPTION + Returns true if it is night on the MUD. + +LOCATION + /secure/sefun/time.c + +SEE ALSO + date(), day(), hour(), minutes(), month(), year() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/query_snoop b/lib/doc/sefun/query_snoop new file mode 100644 index 0000000..708a623 --- /dev/null +++ b/lib/doc/sefun/query_snoop @@ -0,0 +1,26 @@ + +QUERY_SNOOP(1) QUERY_SNOOP(1) + +NAME + query_snoop() - returns whoever is snooping an object + +SYNOPSIS + object query_snoop(object snoopee) + +DESCRIPTION + Given a player as an argument, this function will return + the player object, if any, which is snooping the object + argument. This is an override of a MudOS efun to provide + some protection against global use. + +LOCATION + /secure/sefun/sefun.c + +SEE ALSO + the query_snoop() efun + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/query_snooping b/lib/doc/sefun/query_snooping new file mode 100644 index 0000000..fc9820e --- /dev/null +++ b/lib/doc/sefun/query_snooping @@ -0,0 +1,25 @@ + +QUERY_SNOOPING(1) QUERY_SNOOPING(1) + +NAME + query_snooping() - returns the player being snooped + +SYNOPSIS + object query_snooping(object ob) + +DESCRIPTION + An override of the MudOS efun for security reasons. This + function will return the object which is being snooped by + the object passed as an argument. + +LOCATION + /secure/sefun/sefun.c + +SEE ALSO + the query_snooping() efun + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/read_database b/lib/doc/sefun/read_database new file mode 100644 index 0000000..af5e904 --- /dev/null +++ b/lib/doc/sefun/read_database @@ -0,0 +1,27 @@ + +READ_DATABASE(1) READ_DATABASE(1) + +NAME + read_database() - returns an array of non-commented file + lines + +SYNOPSIS + string *read_database(string file) + +DESCRIPTION + Given a file to read, this function will read the file and + return an array of lines without any comments or blank + lines. Commented lines start with a # sign. + +NOTES + This function is an immensely inefficient way to handle + this. I must have been on drugs when I wrote it. + +LOCATION + /secure/sefun/read_database.c + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/reap_dummies b/lib/doc/sefun/reap_dummies new file mode 100644 index 0000000..ee21041 --- /dev/null +++ b/lib/doc/sefun/reap_dummies @@ -0,0 +1,25 @@ + +REAP_DUMMIES(1) REAP_DUMMIES(1) + +NAME + reap_dummies() - Destructs dummy objects without an environment. + +SYNOPSIS + void reap_dummies() + +DESCRIPTION + Early versions of Dead Souls were prone to memory leaks in the +form of dummy items failing to be destructed. The sefun is part of +the effort to address the symptoms of that issue. + +LOCATION + /secure/sefun/reaper.c + +SEE ALSO + reap_other(), reap_list() + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/reflexive b/lib/doc/sefun/reflexive new file mode 100644 index 0000000..4d1b2d3 --- /dev/null +++ b/lib/doc/sefun/reflexive @@ -0,0 +1,31 @@ + +REFLEXIVE(1) REFLEXIVE(1) + +NAME + reflexive() - returns the reflexive pronoun for a gender + +SYNOPSIS + string reflexive(string|object val) + +DESCRIPTION + This function returns a reflexive pronoun ("himself", + "herself", or "itself") based on the gender passed as the + first argument if the first argument is a string, or based + on the gender of the first argument if it is an object. + +EXAMPLES + o reflexive(this_player()) returns "himself" for + Descartes + +LOCATION + /secure/sefun/english.c + +SEE ALSO + nominative(), objective(), possessive(), + possessive_pronoun() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/remove_matching_line b/lib/doc/sefun/remove_matching_line new file mode 100644 index 0000000..0d1f5ac --- /dev/null +++ b/lib/doc/sefun/remove_matching_line @@ -0,0 +1,49 @@ + +REMOVE_MATCHING_LINE(1) REMOVE_MATCHING_LINE(1) + +NAME + remove_matching_line() - Focused string removal. + +SYNOPSIS + varargs mixed remove_matching_line(string target, string substring, int i, string exclude) + +DESCRIPTION + Like replace_matching_line, rather than keying on +newlines to determine where a line ends, this attempts +to parse the code to identify the entire LPC instruction. + Unlike replace_matching_line, this function only +deletes, it doesn't replace. + +target: This can be a string or a filename. If it is a filename, the + file will be read and treated as a string. + +substring: The string used to determine a match. + +i: Whether it should remove one matching line or all matching lines. + +exclude: If the line matches but it also contains this string, do not remove. + + +EXAMPLES + remove_matching_line("/realms/cratylus/workroom.c", "AddMeep", + "Balky"); + + This line would read my workroom into a string, and if it has a line +that contains "AddMeep" that *doesn't* contain "Balky", it will remove that line +from the string. + +NOTE: This will not change my workroom. It will return a string that I +can overwrite my workroom with, or that I can write to some other file. + + +LOCATION + /secure/sefun/strings.c + +SEE ALSO + write_file + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/remove_sky_event b/lib/doc/sefun/remove_sky_event new file mode 100644 index 0000000..d690ad7 --- /dev/null +++ b/lib/doc/sefun/remove_sky_event @@ -0,0 +1,28 @@ + +REMOVE_SKY_EVENT(1) REMOVE_SKY_EVENT(1) + +NAME + remove_sky_event() - removes a sky event set up by + add_sky_event() + +SYNOPSIS + void remove_sky_event(function f) + +DESCRIPTION + Removes a sky event set up by the add_sky_event function. + +NOTES + This function will not work under the new function pointer + structure. + +LOCATION + /secure/sefun/time.c + +SEE ALSO + add_sky_event() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/replace_line b/lib/doc/sefun/replace_line new file mode 100644 index 0000000..69ac173 --- /dev/null +++ b/lib/doc/sefun/replace_line @@ -0,0 +1,47 @@ + +REPLACE_LINE(1) REPLACE_LINE(1) + +NAME + replace_line() - Reads a string and replaces a line with substitute text. + +SYNOPSIS + string replace_line(string file, string *params, string repl) + +DESCRIPTION + Provided a string, search parameter(s), and replacement text, this +function finds every matching line and replaces it with the supplied substitution. + +EXAMPLES + replace_line(read_file("/realms/cratylus/workroom.c",({"Add","Monkey"}), + "SetFoo(\"Donkey\");") + +If my workroom contains the line: + +AddFoo("Monkey"); + +Then this function will return the full text of my workroom file, but +with the above string replaced by the one below: + +SetFoo("Donkey"); + +The line must match *all* of the parameters, or the replacement does not +occur. For example, the line: + +SetMoo("Monkey"); + +would be left unchanged, because it doesn't contain "Add". + +NOTE: This does not modify files. To do so, you'll need to use the output +of this funtion as the second argument in the write_file efun. + +LOCATION + /secure/sefun/strings.c + +SEE ALSO + + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/replace_matching_line b/lib/doc/sefun/replace_matching_line new file mode 100644 index 0000000..bfd6fdd --- /dev/null +++ b/lib/doc/sefun/replace_matching_line @@ -0,0 +1,51 @@ + +REPLACE_MATCHING_LINE(1) REPLACE_MATCHING_LINE(1) + +NAME + replace_matching_line() - Focused string replacement. + +SYNOPSIS + varargs mixed replace_matching_line(string target, string substring, string replace, int i, string exclude) + +DESCRIPTION + This monstrosity is quite different from +replace_line. Rather than keying on +newlines to determine where a line ends, it attempts +to parse the code to identify +the entire LPC instruction. + +target: This can be a string or a filename. If it is a filename, the + file will be read and treated as a string. + +substring: The string used to determine a match. + +replace: The replacement line. + +i: Whether it should replace one matching line or all matching lines. + +exclude: If the line matches but it also contains this string, do not replace. + + +EXAMPLES + replace_matching_line("/realms/cratylus/workroom.c", "AddMeep", +"SetMeep(([\"feep\":\"Meepos\",\n\"meep\":\"Feepos\",\n]));", "Balky"); + + This line would read my workroom into a string, and if it has a line +that contains "AddMeep" that *doesn't* contain "Balky", it will remove that line +from the string and replace it with my SetMeep substitute. + +NOTE: This will not change my workroom. It will return a string that I +can overwrite my workroom with, or that I can write to some other file. + + +LOCATION + /secure/sefun/strings.c + +SEE ALSO + write_file + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/reverse_string b/lib/doc/sefun/reverse_string new file mode 100644 index 0000000..28b9b93 --- /dev/null +++ b/lib/doc/sefun/reverse_string @@ -0,0 +1,27 @@ + +REVERSE_STRING(1) REVERSE_STRING(1) + +NAME + reverse_string() - Reverses a string. + +SYNOPSIS + string reverse_string(string str) + +DESCRIPTION + Returns a string whose characters are arranged in a +manner inverse to the original string. + +EXAMPLES + reverse_string("MXLPLX") returns "XLPLXM" + +LOCATION + /secure/sefun/strings.c + +SEE ALSO + + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/say b/lib/doc/sefun/say new file mode 100644 index 0000000..d251d7f --- /dev/null +++ b/lib/doc/sefun/say @@ -0,0 +1,35 @@ + +SAY(1) SAY(1) + +NAME + say() - sends a message to objects in the same room as + command giver + +SYNOPSIS + varargs void say(mixed str, object ob) + +DESCRIPTION + This function sends a message, the first argument, to all + users in the same room as the command giver other than the + command giver (this_player()). The message is sent as + message class "other_action". If a second argument is + given, that object is excluded from hearing the message. + +NOTES + This is an override of the MudOS efun by the same name. + In order to be AMCP compliant, all messages need to go + through receive_message(). This function allows creators + to continuing using the oldstyle messaging while remaining + compliant. + +LOCATION + /secure/sefun/communications.c + +SEE ALSO + message(), write() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/season b/lib/doc/sefun/season new file mode 100644 index 0000000..e9ba9c5 --- /dev/null +++ b/lib/doc/sefun/season @@ -0,0 +1,25 @@ + +SEASON(1) SEASON(1) + +NAME + season() - returns the season at a given time + +SYNOPSIS + string season(int x) + +DESCRIPTION + Given an integer time, this function returns the name of + the season for that time. + +LOCATION + /secure/sefun/time.c + +SEE ALSO + date(), day(), hour(), minutes(), month(), query_night(), + year() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/set_eval_limit b/lib/doc/sefun/set_eval_limit new file mode 100644 index 0000000..a6c3d6c --- /dev/null +++ b/lib/doc/sefun/set_eval_limit @@ -0,0 +1,26 @@ + +SET_EVAL_LIMIT(1) SET_EVAL_LIMIT(1) + +NAME + set_eval_limit() - provides security for the + set_eval_limit() efun + +SYNOPSIS + void set_eval_limit(int x) + +DESCRIPTION + The MudOS efun set_eval_limit() has no security, so the + mudlib needs to prevent objects from resetting the eval + limit. This override performs this function. + +LOCATION + /secure/sefun/sefun.c + +SEE ALSO + the set_eval_limit() efun + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/set_privs b/lib/doc/sefun/set_privs new file mode 100644 index 0000000..5c20dc6 --- /dev/null +++ b/lib/doc/sefun/set_privs @@ -0,0 +1,21 @@ + +SET_PRIVS(1) SET_PRIVS(1) + +NAME + set_privs() - prevents anyone from using the set_privs() + efun + +SYNOPSIS + void set_privs(object ob, string str) + +DESCRIPTION + The Nightmare Mudlib security system does not allow for + setting of privs after object creation, so the MudOS efun + set_privs() needs to be overriidden to prevent this from + happening. + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/shout b/lib/doc/sefun/shout new file mode 100644 index 0000000..bc815d9 --- /dev/null +++ b/lib/doc/sefun/shout @@ -0,0 +1,25 @@ + +SHOUT(1) SHOUT(1) + +NAME + shout() - sends a message to all users online + +SYNOPSIS + varargs void shout(string|int str, object|object *exclude) + +DESCRIPTION + Sends the message specified by the first argument to all + users online. If a second argument is give, it is an + object or array of objects which will be excluded from + hearing the message. The message class shout() uses is + "shout". + +LOCATION + /secure/sefun/communications.c + +SEE ALSO message(), say(), write() +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/shutdown b/lib/doc/sefun/shutdown new file mode 100644 index 0000000..5ab19a9 --- /dev/null +++ b/lib/doc/sefun/shutdown @@ -0,0 +1,24 @@ + +SHUTDOWN(1) SHUTDOWN(1) + +NAME + shutdown() - shuts down the mud + +SYNOPSIS + varargs void shutdown(int code) + +DESCRIPTION + The MudOS shutdown() efun has no security. This sefun + overrides the MudOS shutdown() efun to provide security. + +LOCATION + /secure/sefun/sefun.c + +SEE ALSO + the shutdown() efun + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/snoop b/lib/doc/sefun/snoop new file mode 100644 index 0000000..b6a507c --- /dev/null +++ b/lib/doc/sefun/snoop @@ -0,0 +1,22 @@ + +SNOOP(1) SNOOP(1) + +NAME + snoop() - sets one player to snoop another + +SYNOPSIS + varargs object snoop(object who, object target) + +DESCRIPTION This function provides security for the MudOS efun + snoop(). +LOCATION + /secure/sefun/sefun.c + +SEE ALSO + the snoop() efun + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/starts_with b/lib/doc/sefun/starts_with new file mode 100644 index 0000000..ec49fd5 --- /dev/null +++ b/lib/doc/sefun/starts_with @@ -0,0 +1,23 @@ + +STARTS_WITH(1) STARTS_WITH(1) + +NAME + starts_with() - Whether a string begins with the specified substring. + +SYNOPSIS + int starts_with(string primary, string sub) + +DESCRIPTION + If primary begins with sub, returns 1. Otherwise returns 0. + +EXAMPLES + starts_with(string primary, string sub) + +LOCATION + /secure/sefun/strings.c + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/strip_colours b/lib/doc/sefun/strip_colours new file mode 100644 index 0000000..e13978f --- /dev/null +++ b/lib/doc/sefun/strip_colours @@ -0,0 +1,24 @@ + +STRIP_COLOURS(1) STRIP_COLOURS(1) + +NAME + strip_colours() - strips all colour codes from a string + +SYNOPSIS + string strip_colours(string str) + +DESCRIPTION + Returns a string free of colour codes. + +EXAMPLES + o strip_colours("%^RED%^Descartes tells you:%^RESET%^ + hi!") returns "Descartes tells you: hi!" + +LOCATION + /secure/sefun/strings.c + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/tail b/lib/doc/sefun/tail new file mode 100644 index 0000000..79df5e7 --- /dev/null +++ b/lib/doc/sefun/tail @@ -0,0 +1,28 @@ + +TAIL(1) TAIL(1) + +NAME + tail() - Displays the last lines of a specified file. + +SYNOPSIS + int tail(string file) + +DESCRIPTION + Displays the last few lines (1024 bytes) of a file to +this_player(). + +EXAMPLES + tail("/realms/cratylus/workroom.c") + + +LOCATION + /secure/sefun/tail.c + +SEE ALSO + write(), say() + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/tell_object b/lib/doc/sefun/tell_object new file mode 100644 index 0000000..7f501cf --- /dev/null +++ b/lib/doc/sefun/tell_object @@ -0,0 +1,21 @@ + +TELL_STD_ITEM(1) TELL_OBJECT(1) + +NAME + tell_object() - sends a message to an object + +SYNOPSIS + void tell_object(object ob, string|int str) + +DESCRIPTION + This function sends a message of the message class + "environment" to the object named. + +LOCATION + /secure/sefun/communications.c + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/tell_player b/lib/doc/sefun/tell_player new file mode 100644 index 0000000..6b4674b --- /dev/null +++ b/lib/doc/sefun/tell_player @@ -0,0 +1,21 @@ + +TELL_PLAYER(1) TELL_PLAYER(1) + +NAME + tell_player() - sends a message to a player + +SYNOPSIS + void tell_player(object player, string str) + +DESCRIPTION + This function sends a message of the message class + "environment" to the player named. + +LOCATION + /secure/sefun/communications.c + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/total_light b/lib/doc/sefun/total_light new file mode 100644 index 0000000..ac7bbb6 --- /dev/null +++ b/lib/doc/sefun/total_light @@ -0,0 +1,26 @@ + +TOTAL_LIGHT(1) TOTAL_LIGHT(1) + +NAME + total_light() - returns the independent light value for a + room + +SYNOPSIS + int total_light(object ob) + +DESCRIPTION + Returns the light value for a room. This sefun does + not say how much light may be available to any given + player. + +LOCATION + /secure/sefun/light.c + +SEE ALSO + effective_light(), moon_light() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/translate b/lib/doc/sefun/translate new file mode 100644 index 0000000..2cbc9c7 --- /dev/null +++ b/lib/doc/sefun/translate @@ -0,0 +1,31 @@ + +TRANSLATE(1) TRANSLATE(1) + +NAME + translate() - translates any given string into nonsense + +SYNOPSIS + string translate(string str, int prof) + +DESCRIPTION + Depending on the users linguistic proficiency, specified + by the second argument, this function takes the string in + the first argument and turns it into an appropriate degree + of nonsense. It is used to handle linguistic + communication. + +EXAMPLES + o translate("this is a string in another language", 2) + returns "blurb is bargle bing yellow gurble zing" + + o translate("this is another string", 10) returns "this + is another string" + +LOCATION + /secure/sefun/translate.c + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/true b/lib/doc/sefun/true new file mode 100644 index 0000000..118b67c --- /dev/null +++ b/lib/doc/sefun/true @@ -0,0 +1,24 @@ + +TRUE(1) TRUE(1) + +NAME + true() - Always returns a 1. + +SYNOPSIS + int true() + +DESCRIPTION + This function is mostly just cosmetic. There are circumstances where +I feel wrong not having SOMETHING happen, so there is this. + +LOCATION + /secure/sefun/generic.c + +SEE ALSO + false() + +Author + Cratylus @ Dead Souls + + 1 + diff --git a/lib/doc/sefun/unguarded b/lib/doc/sefun/unguarded new file mode 100644 index 0000000..1aaaeeb --- /dev/null +++ b/lib/doc/sefun/unguarded @@ -0,0 +1,52 @@ + +UNGUARDED(1) UNGUARDED(1) + +NAME + unguarded() - calls a function relying only on the + object's security + +SYNOPSIS + mixed unguarded(function f) + +DESCRIPTION + This function allows an object to make a function call + based solely its own access. Normally, when an object + makes a function call, the access of all objects invloved + in the object chain are checked to see if there is proper + access. For example, if you have a guild object which + needs to read a help file in your home directory, under + normal circumstances this will fail. Even though your + guild object has proper permissions to read your files, + the person executing the command does not. So, the guild + object passes the security check, the player fails. Since + the player fails, the entire read fails. This system is + useful for preventing people from using other objects to + gain illegal access. However, in the case outlined above, + this can be a pain. The unguarded() function call directs + the mudlib only to check to see if your guild object has + the proper permission. The argument to unguarded() is the + function to be called. + +EXAMPLES + In the above example, there would be code like this: + + int cmd_help(string str) { + if(str != "guild") return 0; + txt = unguarded((: read_file, HELP_FILE :)); + message("help", txt, this_player()); + return 1; + } + + The function unguarded((: read_file, HELP_FILE :)) acts + just like read_file(HELP_FILE) except that the security + only checks your object with the first call, but checks + all objects in the call stack on the second call. + +LOCATION + /secure/sefun/security.c + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/user_exists b/lib/doc/sefun/user_exists new file mode 100644 index 0000000..d93dc25 --- /dev/null +++ b/lib/doc/sefun/user_exists @@ -0,0 +1,25 @@ + +USER_EXISTS(1) USER_EXISTS(1) + +NAME + user_exists() - returns true if a given user exists + +SYNOPSIS + int user_exists(string str) + +DESCRIPTION + If the argument passed is an existing player, this + function returns true. Otherwise the function returns + false. + +EXAMPLES + user_exists("descartes") returns true on Nightmare + +LOCATION + /secure/sefun/user_exists.c + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/user_path b/lib/doc/sefun/user_path new file mode 100644 index 0000000..bec31ad --- /dev/null +++ b/lib/doc/sefun/user_path @@ -0,0 +1,24 @@ + +USER_PATH(1) USER_PATH(1) + +NAME + user_path() - returns the home directory of the user named + +SYNOPSIS + string user_path(string name) + +DESCRIPTION + This function returns the home directory of the user named + as an argument. + +EXAMPLES + user_path("descartes") returns "/realms/descartes" + +LOCATION + /secure/sefun/user_path.c + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/version b/lib/doc/sefun/version new file mode 100644 index 0000000..f7eb984 --- /dev/null +++ b/lib/doc/sefun/version @@ -0,0 +1,24 @@ + +VERSION(1) VERSION(1) + +NAME + version() - returns the driver name and version + +SYNOPSIS + string version() + +DESCRIPTION + This function returns the driver name and version. + +LOCATION + /secure/sefun/mud_info.c + +SEE ALSO + architecture(), mud_name(), mudlib(), mudlib_version(), + query_host_port() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/wrap b/lib/doc/sefun/wrap new file mode 100644 index 0000000..322d149 --- /dev/null +++ b/lib/doc/sefun/wrap @@ -0,0 +1,28 @@ + +WRAP(1) WRAP(1) + +NAME + wrap() - returns a string wrapped to a specified terminal + width + +SYNOPSIS + varargs string wrap(string str, int width) + +DESCRIPTION + If a second argument is passed, the first argument is + fitted with carriage returns to wrap the string for + display on a terminal as wide as the second argument. If + no second argument is given, a terminal width of 80 is + assumed. + +LOCATION + /secure/sefun/strings.c + +SEE ALSO + arrange_string(), format_page(), sprintf() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/write b/lib/doc/sefun/write new file mode 100644 index 0000000..2efe3ed --- /dev/null +++ b/lib/doc/sefun/write @@ -0,0 +1,25 @@ + +WRITE(1) WRITE(1) + +NAME + write() - sends a message to the current command giver + +SYNOPSIS + void write(string str) + +DESCRIPTION + This function is simply redefined as: + + message("my_action", str, this_player()); + +LOCATION + /secure/sefun/communication.c + +SEE ALSO + message(), say(), shout() + +Author + Descartes of Borg + + 1 + diff --git a/lib/doc/sefun/year b/lib/doc/sefun/year new file mode 100644 index 0000000..08d8b5f --- /dev/null +++ b/lib/doc/sefun/year @@ -0,0 +1,26 @@ + +YEAR(1) YEAR(1) + +NAME + year() - returns the year for a given time + +SYNOPSIS + int year(int x) + +DESCRIPTION + Given a time integer as an argument, this function returns + the MUD year for that time. + +EXAMPLES + o year(time()) returns the MUD year today, which at the + time of this document happens to be 14. + +SEE ALSO + date(), day(), hour(), minutes(), month(), query_night(), + season() + +Author + Descartes of Borg + + 1 + diff --git a/lib/domains/Praxis/README b/lib/domains/Praxis/README new file mode 100644 index 0000000..7c8088e --- /dev/null +++ b/lib/domains/Praxis/README @@ -0,0 +1,19 @@ + /domains/Praxis + The Standard Domain for the Nightmare 3 Object Library + +This is the ANCIENT Praxis domain from the old Nightmare 3 +mudlib. It had been updated to work on Dead Souls 2, and +the objects all will load into memory properly, and for +the most part, they work the way they're supposed to. + +However, this is *NOT* an example of what you should do +when coding areas. This domain is provided for both historical +context and for examples of how things *can* be done. + +Fancy stuff probably doesn't work, since it may depend on +subsystems used in NM3 that are not used in DS2 (such as +UID security). + +Broken things here will very likely *NOT* be fixed. Like +Ylsrim, this area is a museum piece, provided for reference +and education, but for display purposes only. diff --git a/lib/domains/Praxis/adm/README b/lib/domains/Praxis/adm/README new file mode 100644 index 0000000..2ddcbe3 --- /dev/null +++ b/lib/domains/Praxis/adm/README @@ -0,0 +1,14 @@ + The Administrative Directory + +This directory contains files necessary for domain administration. + +Specifically it is the default directory for the access object, +which is used for providing nonstandard access to files with +the "grant" command. + +This is also the location where domain-specific daemons can be +expected to reside. + +In the case of archaic domains, such as Ylsrim, this is where +some mandatory rooms are expected to be, such as freezer.c and void.c + diff --git a/lib/domains/Praxis/adm/access.c b/lib/domains/Praxis/adm/access.c new file mode 100644 index 0000000..75bab2d --- /dev/null +++ b/lib/domains/Praxis/adm/access.c @@ -0,0 +1,3 @@ +#include <std.h> + +inherit ACCESS; diff --git a/lib/domains/Praxis/adm/master.c b/lib/domains/Praxis/adm/master.c new file mode 100644 index 0000000..516a914 --- /dev/null +++ b/lib/domains/Praxis/adm/master.c @@ -0,0 +1,20 @@ +// File: /d/standard/adm/master.c +// Purpose: The Standard domain's master object. +// Mudlib: Nightmare +// Author: Douglas Reay (Pallando @ TMI, Nightmare, etc) +// 93-06-08: Stores domain specific material properties +// and does any domain specific initialsation of objects + +#include <daemons.h> + +inherit ALCHEMIST_D; + +void create() { save_file = "/domains/Praxis/data/properties"; ::create(); } + +varargs void setup_object( object ob, object pobj ) +{ + ::setup_object( ob, pobj ); + + // Any domain specific initialisation we wish to do + ob-> set( "domain", "standard" ); +} diff --git a/lib/domains/Praxis/adv_inner.c b/lib/domains/Praxis/adv_inner.c new file mode 100644 index 0000000..7537912 --- /dev/null +++ b/lib/domains/Praxis/adv_inner.c @@ -0,0 +1,54 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + object ob; + + ::create(); + SetProperty("light", 2); + SetProperty("indoors", 1); + SetShort( "The Hall of the Immortals"); + SetLong( + "This is the meeting %^GREEN%^green%^RESET%^ room of the immortals of Nightmare. " + "In this room, matters of mud policy and events are discussed " + "by all Nightmare immortals so that everyone might know what " + "is going on. There is a room for discussing LPC south and " + "a planning room east where immortals post their plans for areas " + "domains, guilds and quests. Down from here is the approval room."); + SetExits( + (["up" : "/domains/Praxis/mudlib", + "north" : "/domains/Praxis/adv_main", + "south" : "/domains/Praxis/lpc_inner", + "down": __DIR__ "app_room", + "east" : "/domains/Praxis/planning_room"]) ); + + ob = new("/lib/bboard"); + ob->SetKeyName("board"); + ob->SetId( ({ "board", "reality board" }) ); + ob->set_board_id("immortal"); + ob->set_max_posts(30); + ob->move("/domains/Praxis/adv_inner"); + ob->SetShort( "Immortal's Reality Board"); + ob->SetLong( "Posts any notes concerning the mud which do " + "not belong out in a public forum among players " + "here for immortal discussion.\n"); + SetProperty("no steal", 1); +} + +int CanReceive(object ob) { + if(!living(ob)) return 1; + if(!userp(ob)) return 0; + if(!creatorp(ob)) { + message("my_action", "You cannot penetrate the magic force of the " + "blue shield.", this_player()); + message("other_action", sprintf("%s tries to pass through the magic " + "blue shield, but fails.", this_player()->query_cap_name()), + environment(this_player()), ({ this_player() })); + return 0; + } + return ::CanReceive(ob); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/adv_main.c b/lib/domains/Praxis/adv_main.c new file mode 100644 index 0000000..232cfc2 --- /dev/null +++ b/lib/domains/Praxis/adv_main.c @@ -0,0 +1,123 @@ +#include <lib.h> + +inherit STD_ROOM; + +int get_exp(int lev); +int train_player(object tp, string which, int amount); +int get_stat_cost(int x, int lev); + +void create() { + object ob; + + ::create(); + SetProperty("light", 2); + SetProperty("indoors", 1); + SetNoClean(1); + SetShort( "the adventurer's hall"); + SetLong( + "This is the adventurer's hall of the town of Praxis. It " + "is a large wooden building which looks worn from all the use " + "over the years. A large bulletin board stands in the center of the " + "room, filled with notes from the many adventurers of this reality. " + "In front of the building Boc La Road runs north of here. To the " + "south is a small passage illuminated by a shimmering " + "%^BLUE%^blue%^RESET%^ light."); + SetExits( + (["north" : "/domains/Praxis/e_boc_la2", + "east" : "/domains/Praxis/lpmud_room", + "south" : "/domains/Praxis/adv_inner", + "down" : "/domains/Praxis/ombud_hall"]) ); + SetItems( + (["hall" : "A place for a rowdy time!", + "road" : "A small dirt path going through Praxis.", + "passage" : "A %^BLUE%^blue%^RESET%^ light illuminates it.", + "light" : "It is probably a force field."]) ); + + ob = new("/lib/bboard"); + ob->SetKeyName("board"); + ob->SetId( ({ "board", "bulletin board", "reality board" }) ); + ob->set_board_id("main_board"); + ob->SetShort("The Nightmare Reality Board"); + // ob->SetShort( "The Nightmare Reality Board"); + ob->SetLong( "An old cork board where the adventurers " + "who pass through Praxis post information on the " + "reality they have discovered.\n"); + ob->set_max_posts(75); + + ob->move(this_object()); + SetProperty("no steal", 1); + SetProperty("no attack", 1); +} + +int go_south() { + if(!creatorp(this_player())) { + write("%^BLUE%^%^BOLD%^You cannot penetrate the force of the blue light."); + say(this_player()->query_cap_name()+" tries to get through the " + "passage, but fails.", this_player()); + return 0; + } + return 1; +} + +int get_exp(int lev) { + int val; + + switch(lev) { + case 0: val = 0; break; + case 1: val = 1014; break; + case 2: val = 2028; break; + case 3: val = 3056; break; + case 4: val = 4800; break; + case 5: val = 6200; break; + case 6: val = 9100; break; + case 7: val = 12500; break; + case 8: val = 15000; break; + case 9: val = 20000; break; + case 10: val = 28000; break; + case 11: val = 40000; break; + case 12: val = 55000; break; + case 13: val = 72000; break; + case 14: val = 104000; break; + case 15: val = 150000; break; + default: val = (lev-12)*(lev-15)*28000 + 150000; + } + return val; +} + +int train_player(object tp, string which, int amount) { + int exp, amt; + + if(amount < 1) { + notify_fail("You cannot train that amount.\n"); + return 0; + } + exp = tp->query_exp(); + if(exp-amount < get_exp(tp->query_level())) { + notify_fail("You do not have the experience to train that much.\n"); + return 0; + } + if(tp->query_max_skill(which) <= tp->query_skill(which)) { + notify_fail("You can train no more in that skill.\n"); + return 0; + } + amt = ( tp->query_level() * 4 ) + 20; + if(amt <= tp->query_skill(which) ) + { + notify_fail("You must advance your level to train more in that skill"+ + ".\n"); + return 0; + } + tp->add_skill_points(which, amount/4); + tp->add_exp(-amount); + tell_object(tp, "You train in the skill of "+which+"."); + return 1; +} + +int get_stat_cost(int x, int lev) { + if(x==1) return ((lev/10)*(lev/10)*10000) + (lev/3)*1000; + else return (lev/7)*(lev/7)*(lev*900); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/alley1.c b/lib/domains/Praxis/alley1.c new file mode 100644 index 0000000..c43a38d --- /dev/null +++ b/lib/domains/Praxis/alley1.c @@ -0,0 +1,32 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 2); + SetProperty("night light", 1); + SetProperty("no castle", 1); + SetShort("A narrow alley"); + SetSmell( "default", "The faint smell of rubbish assaults you."); + SetLong( + "You find yourself on a small dirt path which leads to and from " + "Centre Path. The path is a dirt road, cluttered occasionally " + "with garbage from some of the less considerate citizens of Praxis. " + "The local Post office is to the south, and to the north you can see " + "a large bulding which serves as the bank of Praxis."); + SetItems( + (["path" : "The path is a small dirt road leading from Centre Path.", + "bank" :"The bank of Praxis is a very well known establishment.", + ({"office", "post", "post office"}) : "You can send and receive " + "mail to other people here or on other muds there.", + "alley" : "The alley is a very small dirt path."]) ); + SetSkyDomain("town"); + SetExits( ([ + "west" : "/domains/Praxis/alley2", + "east" : "/domains/Praxis/s_centre2", + ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/alley2.c b/lib/domains/Praxis/alley2.c new file mode 100644 index 0000000..0cb0b4a --- /dev/null +++ b/lib/domains/Praxis/alley2.c @@ -0,0 +1,37 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("no castle", 1); + SetProperty("light", 2); + SetProperty("night light", 1); + SetSmell("default", "An unbelievable stench fills the air."); + SetSmell("dump", "It smells of all kinds of " + "nasty rotting things."); + SetShort( "The end of a nasty alley"); + SetLong( + "This is the end of the alley. All about you can see " + "decaying buildings. Off to the south you can see an old abondoned + building, worn from the weather and a lack of care. To the north " + "there are more ruins. It appears that this used to be a whole " + "other section of Praxis, abondened long ago. The Praxis dump " + "is further west." ); + SetItems( + (["alley" : "It goes through the worst parts of Praxis.", + "dump" : "People take their trash there. Always " + "during daytime hours.", + "building" : "It looks like no one has paid it any " + "attention in eons.", + "ruins" : "Graffiti covers them."]) ); + SetSkyDomain("town"); + SetExits( + ([ "east": "/domains/Praxis/alley1", + "north":"/domains/Praxis/wall", + "south":"/domains/Praxis/building", + "west":"/domains/Praxis/dump" ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/app_room.c b/lib/domains/Praxis/app_room.c new file mode 100644 index 0000000..80d67b8 --- /dev/null +++ b/lib/domains/Praxis/app_room.c @@ -0,0 +1,27 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperties( ([ + "light":2, + "indoors":1 + ]) ); + SetShort("approval room"); + SetLong("This is the meeting room of the approval team. In this room " + "problems, suggestions and new approval changes can be posted on the " + "board so that everyone is informed about the newest stuff. Up from this " + "room is the hall of immortals."); + SetExits( ([ + "up": __DIR__ "adv_inner" + ]) ); +} +void reset() { + ::reset(); + //if(!present("approval board")) + //new( __DIR__ "obj/misc/app_board")->move(this_object()); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/arch.c b/lib/domains/Praxis/arch.c new file mode 100644 index 0000000..197789f --- /dev/null +++ b/lib/domains/Praxis/arch.c @@ -0,0 +1,30 @@ +inherit "/lib/std/room"; + +void init() { + ::init(); + if(!archp(this_player())) + this_player()->eventMoveLiving("/domains/Praxis/planning_room", "down"); +} + +void create() { + object ob; + + ::create(); + SetProperty("light", 2); + SetProperty("indoors", 1); + SetShort( "The Arch's Room"); + SetLong( + "This is where the arches decide the fate of Nightmare."); + SetExits( + (["down" : "/domains/Praxis/planning_room"]) ); + + ob = new("/lib/bboard"); + ob->SetKeyName("board"); + ob->SetId( ({ "board" }) ); + ob->set_board_id("arch"); + ob->set_max_posts(20); + ob->move("/domains/Praxis/arch"); + ob->SetShort( "the Arch Immortal's Board"); + ob->SetLong( "A board for utter nonsense.\n"); +} + diff --git a/lib/domains/Praxis/attic/class_change.c b/lib/domains/Praxis/attic/class_change.c new file mode 100644 index 0000000..f34f5ff --- /dev/null +++ b/lib/domains/Praxis/attic/class_change.c @@ -0,0 +1,106 @@ +#define addi(x,y) AddItem(x,y) +#define adde(x,y) AddExit(y) + +inherit "/lib/std/room"; + +void create() { + + SetAmbientLight(30); + SetShort("Magical Mind Altering Altar"); + SetLong( + "This room is clean and has almost brand new furniture in it. A strange\n"+ + "tilted altar is in the middle of the room. Tables with wheels, which are\n"+ + "covered with magical devices, have been pushed up against the walls.\n"); + addi("furniture", + "The furniture is all made of oak.\n"); + addi("altar", + "The altar is made out of wood and is tilted at a strange angle.\n"); + addi("tables", + "The tables are covered with various wands, rings, orbs, magical herbs, and\n"+ + "some things you cannot even identify.\n"); + addi("table", + "Each table is made out of sturdy oak and can be wheeled around the room.\n"); + addi("devices","The devices are very peculiar.\n"); + addi("device", + "One device catches your eye. It is squirting water down a drain.\n"); + addi("water","The water looks cool and refreshing.\n"); + addi("drain","The drain is on the floor.\n"); + addi("floor","The floor is well swept granite.\n"); + addi("walls","The stone walls are bare of decorations.\n"); + addi("wall","All the walls are the same.\n"); + addi("stone","All the stone in this room is granite.\n"); + addi("granite","The granite is grey and rough.\n"); + //new("/obj/mon/wizard")->move(this_object()); +} + +void init() +{ + ::init(); + add_action("changing","change"); + add_action("helping","help"); +} + +int helping(string str) +{ + if(str != "changing") return 0; + write( + "The cost for changing from one class to another is half your experience and\n"+ + "five-thousand gold pieces.\n\n"+ + "To change your class type 'change class to <type>' where type is the class\n"+ + "you wish to change to. The wizard will then operate on you to make the\n"+ + "adjustments. It won't hurt, really, not much anyway.\n"); + return 1; +} + +int changing(string str) +{ + int i; + + if(!present("mad wizard")) + { + write("The mad wizard is not in to fix you up.\n"); + return 1; + } + if(!str) + { + write("How can the wizard operate if you do not give "+ + "instructions?\n"); + say("The mad wizard bonks "+this_player()->query_cap_name()+ + " over the head.\n"); + return 1; + } + //wtf does this do? + //str=extract(str, 9); + if(str == this_player()->query_class()) + { + write("Mad Wizard says: yer even crazier than I am!\n"); + return 1; + } + switch(str) + { + case "fighter": + case "cleric": + case "rogue": + case "mage": + case "monk": + i=1; + break; + default: i=0; + } + if(!i) + { + write("Mad Wizard says: what kind of class is that?\n"); + return 1; + } + if( this_player()->query_money("gold") < 5000) + { + write("Mad Wizard says: You need more money than that.\n"); + return 1; + } + this_player()->add_money("gold", - 5000); + this_player()->add_exp( - (this_player()->query_exp() / 2) ); + this_player()->set_class(str); + write("The wizard picks up a wand off of a table and zaps you!\n"); + say("The wizard zaps "+this_player()->query_cap_name()+" with a wand.\n"); + return 1; +} diff --git a/lib/domains/Praxis/attic/tmp_hos b/lib/domains/Praxis/attic/tmp_hos new file mode 100644 index 0000000..ed75683 --- /dev/null +++ b/lib/domains/Praxis/attic/tmp_hos @@ -0,0 +1,294 @@ +#include <daemons.h> + +inherit "/lib/std/room"; + +#define COST money/bonus +#define MAX_DONATION 600 + +mapping blood; + +void init() { + ::init(); + add_action("new_body", "renew"); + add_action("clean_poison", "clean"); + add_action("regenerate", "regenerate"); + add_action("read", "read"); + add_action("donate", "donate"); + add_action("transfuse", "transfuse"); +} + +void create() { + seteuid(getuid()); + SetProperty("light", 2); + SetProperty("indoors", 1); + SetShort("Cleric's Hospital of Praxis"); + SetLong( + "You are in the local hospital run by the town's clerics.\n"+ + "Here they specialize in the regeneration of lost limbs.\n"+ + "A list of all services they perform is posted on the wall.\n" + ); + set_item_descriptions( + ({ + "list", "hospital", "clerics", "cleric" + }), + ({ + "You can read all the services by typing <read list>.\n", + "The clerics here specialize in regenerating lost limbs.\n", + "They are mending the wounds of patients.\n", + "He is mending a patient's wounds.\n" + }) + ); + SetExits( ([ + "east" : "/domains/Praxis/n_centre2" , + ]) ); + blood = ([ "who": ([]), "hp":200, "mp":200 ]); + SetProperty("no teleport", 1); +} + +int new_body(string str) { + object *inv; + int i; + + + if( (int)this_player()->query_level() != 1) { + notify_fail("The clerics only perform this service for the inexperienced.\n"); + return 0; + } + inv = all_inventory(this_player()); + for(i=0; i<sizeof(inv); i++) { + inv[i]->unequip(); + } + write("A cleric comes over to you and mutters a small prayer.\n"); + write("You again have the all the limbs you were born with!\n"); + say("A cleric mutters a small prayer for the novice "+this_player()->query_cap_name()+".\n", this_player()); + this_player()->new_body(); + return 1; +} + +int read(string str) { + if(!str) { + notify_fail("Read what?\n"); + return 0; + } + if(str != "list") { + notify_fail("That is not here for reading.\n"); + return 0; + } + write("Welcome to the Cleric's Hospital of Praxis!\n"+ + "The clerics perform the following services:\n"+ + "------------------------------------------------------------------\n"+ + "<renew body>: This is a charity service the clerics perform for\n"+ + " novice adventurers who have lost limbs while adventuring.\n"+ + " All limbs are replaced.\n\n"+ + "<regenerate [limb]>: This service is for the experienced adventurer\n"+ + " who has lost limbs. The limb is replaced and acts like new.\n"+ + " Tithe schedule for regeneration:\n"+ + " hands and feet- 400 gold\n"); + write(" arms and legs- 600 gold\n"+ + "<clean poison>: Helps remove some of the poison from your body.\n"+ + "\ttithe: 50 gold\n"+ + "<donate # (hp or mp) of blood>: Donates some of your blood in\n"+ + "\texchange for gold.\n"+ + "<transfuse # (hp or mp)>: Transfuse some blood int hp or mp into your body\n"+ + "\ttithe: amount * 3 gold coins.\n"+ + "Currently: "+blood["hp"]+" hp blood and "+blood["mp"]+" mp blood free.\n"+ + "------------------------------------------------------------------\n"+ + "Half off all regenerations with the severed limb!\n"+ + "Your tithe is used only toward good causes.\n"); + return 1; +} + +int clean_poison(string str) { + object tp; + + if(!str) return 0; + if(str != "poison") return 0; + tp = this_player(); + if((int)tp->query_poisoning()<1) { + notify_fail("A cleric whispers to you: But you are not poisoned!\n"); + return 0; + } + if((int)tp->query_money("gold") < 50) { + notify_fail("You do not have enough gold for the tithe.\n"); + return 0; + } + tp->add_money("gold", -50); + tp->add_poisoning(-10); + write("A cleric casts a spell of healing upon you.\n"); + say("A cleric casts a spell of healing on "+tp->query_cap_name()+".\n", tp); + return 1; +} + +int regenerate(string limb) { + int money, bonus; + mapping limb_info; + object tp; + string *there, *missing; + + tp = this_player(); + if(present(limb, this_player())) bonus = 2; + else bonus = 1; + there = (string *)tp->query_limbs(); + missing = (string *)this_player()->query_severed_limbs() + + (string *)RACE_D->query_limbs((string)this_player()->query_race()); +/* + checking with the race_d is allowing compatibility with old + versions of the mudlib +*/ + if(!missing) { + notify_fail("You aren't missing any limbs!\n"); + return 0; + } + if(member_array(limb, missing) == -1) { + notify_fail("You are not missing that limb!\n"); + return 0; + } + if(member_array(limb, there) != -1) { + notify_fail("You already have that one back!\n"); + return 0; + } + limb_info= (mapping)RACE_D->query_limb_info(limb,(string)tp->query_race()); + if(!limb_info) { + notify_fail("That limb cannot be replaced!\n"); + return 0; + } + if(limb_info["ref"] != "") { + if(member_array(limb_info["ref"], there) == -1) { + notify_fail("You would need a "+limb_info["ref"]+" for that!\n"); + return 0; + } + } + if((string)this_player()->query_class() == "cleric") money = 1200; + else money = 1600; + money = money / limb_info["max"]; + if((int)tp->query_money("gold") < COST) { + notify_fail("The cleric tells you: You do not have enough gold.\n"); + return 0; + } + tp->AddLimb(limb, limb_info["ref"], (int)tp->query_max_hp()/limb_info["max"], 0, 0); + if(member_array(limb, (string *)RACE_D->query_wielding_limbs((string)tp->qyery_race())) != -1) + tp->add_wielding_limb(limb); + tp->add_money("gold", -COST); + if(limb == "left hand") { + if(member_array("left arm", there) == -1) { + notify_fail("You would need a left arm for that!\n"); + return 0; + } + money = 400; + if((int)tp->query_money("gold") < COST) { + notify_fail("The cleric tells you: You do not have enough gold for that.\n"); + return 0; + } + tp->AddLimb(limb, "", (int)tp->query_max_hp()/4, 0, 0); + tp->add_wielding_limb(limb); + tp->add_money("gold", -COST); + } + else if(limb == "left foot" || limb == "right foot") { + money = 400; + if((int)tp->query_money("gold") < COST) { + notify_fail("The cleric says: You don't have enough gold for the tithe.\n"); + return 0; + } + if( (limb == "left foot" && member_array("left leg", there) == -1) || (limb == "right foot" && member_array("right leg", there) == -1) ) { + notify_fail("You need a limb to attatch it to!\n"); + return 0; + } + tp->AddLimb(limb, "", (int)tp->query_max_hp()/4, 0, 0); + tp->add_money("gold", -COST); + } + else if(limb == "left arm" || limb == "left leg" || limb == "right arm" || limb == "right leg") { + money = 600; + if((int)tp->query_money("gold") < COST) { + notify_fail("The cleric tells you: You do not have enough gold for the tithe.\n"); + return 0; + } + if(limb == "left arm") tp->AddLimb(limb, "left hand", (int)tp->query_max_hp()/3, 0, 0); + else if(limb == "left leg") tp->AddLimb(limb, "left foot", (int)tp->query_max_hp()/3, 0, 0); + else if(limb == "right leg") tp->AddLimb(limb, "right foot", (int)tp->query_max_hp()/3, 0, 0); + else tp->AddLimb(limb, "right hand", (int)tp->query_max_hp()/3, 0, 0); + tp->add_money("gold", -COST); + } + else { + write("The cleric says: Sorry, but we do not have the ability to do that.\n"); + say("A cleric looks sadly at "+tp->query_cap_name()+".\n", tp); + return 1; + } + say(tp->query_cap_name()+" asks the clerics for some help with "+tp->query_possessive()+" missing "+limb+".\n", tp); + write("The clerics restore your "+limb+"!\n"); + return 1; +} + +int donate(string str) { + string what; + int amount, tmp; + + if(!str) { + notify_fail("Donate what?\n"); + return 0; + } + if(sscanf(str, "%d %s of blood", amount, what) !=2) { + notify_fail("Correct syntax: <donate [#] [hp | mp] of blood>\n"); + return 0; + } + if(what != "mp" && what != "hp") { + notify_fail("Donate what?\n"); + return 0; + } + if(blood[(string)this_player()->query_name()]+amount > MAX_DONATION) { + write("You will have to wait before giving that much blood.\n"); + return 1; + } + tmp = (int)call_other(this_player(), "query_"+what); + if(tmp < amount + 5) { + notify_fail("You must have at least 5 more than you plan to give!\n"); + return 0; + } + call_other(this_player(), "add_"+what, -amount); + this_player()->add_money("gold", amount/2); + blood[what] += amount; + blood["who"][(string)this_player()->query_name()] += amount; + write("You donate some blood for "+(amount/2)+" gold coins.\n"); + say(this_player()->query_cap_name()+" donates some blood for some gold.\n", this_player()); + call_out("reduce_donation", 900, ({ this_player(), amount })); + return 1; +} + +int transfuse(string str) { + string what; + int amount; + + if(!str) { + notify_fail("Transfuse what?\n"); + return 0; + } + if(sscanf(str, "%d %s", amount, what) != 2) { + notify_fail("Correct syntax: <transfuse [#] [mp | hp]>\n"); + return 0; + } + if(what != "hp" && what != "mp") { + notify_fail("You cannot do that!\n"); + return 0; + } + if(amount < 1) { + notify_fail("Are you crazy?!?\n"); + return 0; + } + if(blood[what] < amount) { + notify_fail("We do not have that much blood in right now.\n"); + return 0; + } + if((int)this_player()->query_money("gold") < amount*3) { + notify_fail("You do not have enough gold for the tithe.\n"); + return 0; + } + this_player()->add_money("gold", -(amount*3)); + call_other(this_player(), "add_"+what, amount); + write("You receive a blood transfusion\n"); + say(this_player()->query_cap_name()+" receives a blood transfusion.\n", this_player()); + return 1; +} + +void reduce_donation(mixed *tmp) { + blood["who"][tmp[0]] -= tmp[1]; + if(blood["who"][tmp[0]] < 1) map_delete(blood, tmp[0]); +} diff --git a/lib/domains/Praxis/bank.c b/lib/domains/Praxis/bank.c new file mode 100644 index 0000000..6ed82f6 --- /dev/null +++ b/lib/domains/Praxis/bank.c @@ -0,0 +1,160 @@ +// /d/standard/bank.c +// from the Nightmare mudlib +// banking room +// created by Descartes of Borg 28 february 1993 + +#include <lib.h> +#include <daemons.h> +//#include <money.h> +//#include <bank.h> + +#define BANK_ID "praxis" + +inherit LIB_ROOM; + +void init() { + ::init(); + add_action("Bugga", "Bugga"); + add_action("read", "read"); +} + +void create() { + ::create(); + SetProperty("magic hold", 10); + SetProperty("no castle", 1); + SetProperty("light", 2); + SetProperty("night light", 2); + SetShort( "the bank of praxis"); + SetLong( + "Welcome to the Bank of Praxis!\n" + "The Bank of Praxis is a lovely looking building. Red carpeting " + "covers the worn floor, and to the north there is a polished wooden " + "counter. In the back of the bank there is a vault where all " + "the town's deposits are kept. A sign by the teller details " + "all commands. The exit to the bank is back south."); + SetItems( + (["bank" : "You are in its huge lobby. There is a counter in " + "front of you\nand and exit behind you.", + "citizens" : "They are wandering about aimlessly.", + "account" : "You're a damn loon.", + "sign" : "Reading it will give you a list of commands.", + "teller" : "The teller looks at you impatiently.", + "counter" : "A teller waits behind it for you to do something.", + "exit" : "It leads out into the alley.", + "vault" : (: this_object(), "look_at_vault" :) ]) ); + SetExits( + (["south":"/domains/Praxis/alley1"]) ); +} + +void reset() { + object mon, weapon, key; + + ::reset(); + if(!present("guard")) { + mon = new(LIB_NPC); + mon->SetKeyName("guard"); + mon->SetId( ({ "guard", "bank guard", "big ogre" }) ); + mon->SetRace( "ogre"); + mon->SetGender("male"); + mon->SetShort( "Bank guard"); + mon->SetLong( "A big, ugly ogre hired to guard the " + "newly open bank.\n"); + mon->SetLevel(14); + mon->SetRace("human"); + mon->SetHealthPoints(500 + random(100)); + mon->SetClass("fighter"); + mon->SetSpellChance(10); + mon->SetSpells( ({ "parry", "Bugga" }) ); + mon->SetSkills("defense", 70); + mon->SetSkills("blade", 90); + mon->set_emotes(9, + ({ "Guard says: Goddamn thief!", + "Guard grunts.", + "Guard says: No way you're getting past me!", + "Guard says: You disgust me."}), 1); + mon->set_emotes(3, + ({ "Guard munches on a rat pie.", + "Guard says: I hate rogues." }), 0); + mon->SetWielding_limbs( ({ "right hand", "left hand" }) ); + mon->move(this_object()); + weapon = new(LIB_ITEM); + weapon->SetKeyName("broadsword"); + weapon->SetId( ({ "broadsword", "sword" }) ); + weapon->SetShort( "Broadsword"); + weapon->SetLong( "A huge broadsword."); + weapon->SetClass(13); + weapon->SetType("blade"); + weapon->SetMass(700); + weapon->SetValue(91); + weapon->move(mon); + mon->eventForce("wield broadsword in right hand"); + key = new(LIB_ITEM); + key->SetKeyName("key"); + key->SetId( ({ "bank key", "key", "bronze key" }) ); + key->SetShort( "Bronze key"); + key->SetLong( "An unremarkable bronze key."); + key->SetMass(29); + key->SetValue(35); + key->move(mon); + } + if(query_reset_number() != 1) { + object tmpob = present("guard"); + if(tmpob){ + tmpob->eventForce("close vault"); + tmpob->eventForce("lock vault with key"); + } + } +} + +int do_drunkard() { + if(present("guard") && !this_player()->query_invis()) { + present("guard")->eventForce("kill "+this_player()->query_name()); + this_player()->add_follower(present("guard")); + write("The guard foils you before you can slip the key in!"); + say(this_player()->query_cap_name()+" is foiled trying to break " + "into the vault!"); + return 0; + } + if(this_player()->query_intox()) { + write("You are fumble around drunkenly with the bank key."); + say(this_player()->query_cap_name()+" fiddles around drunkenly " + "with the bank key."); + return 0; + } + return 1; +} + +int read(string str) { + if(str != "sign") return notify_fail("Read what?\n"); + message("info", + "You may do any of the following at Praxis Merchant's Bank:\n" + "<open account>\nWill open an account for you.\n\n" + "<close account>\nCloses your account.\n\n" + "<balance>\nGives you account balance information.\n\n" + "<deposit [#] [type]>\nDeposits # of currency of type.\n\n" + "<withdraw [#] [type]>\nWithdraws # of currency of type.\n\n" + "<exchange [#] of [type1] for [type2]>\nExchanges currencies. There is a 10% charge.\n\n", + this_player() + ); + return 1; +} + +int Bugga(string str) { + string limb; + object ob; + int amount; + + if(this_player()->is_player()) return 0; + ob = (object)this_player()->query_current_attacker(); + if(!ob) return 1; + limb = ob->return_limb(); + if(ob->query_class() == "rogue") amount = 24 + random(30); + else amount = 20 + random(20); + ob->do_damage(limb, amount); + tell_object(ob, "The guard bashes your "+limb+" with his " + "left fist!"); + tell_room(this_object(), "The guard bashes "+ob->query_cap_name()+"'s "+ + limb+" with his left fist!", ({ ob })); + return 1; +} + diff --git a/lib/domains/Praxis/bank_vault.c b/lib/domains/Praxis/bank_vault.c new file mode 100644 index 0000000..f33593e --- /dev/null +++ b/lib/domains/Praxis/bank_vault.c @@ -0,0 +1,31 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 2); + SetProperty("indoors", 1); + SetShort( "The bank vault"); + SetLong( + "The Praxis Bank keeps all cash it has on hand in this otherwise " + "empty vault. The door on the south end leads to the lobby."); + SetExits( + (["south" : "/domains/Praxis/bank"]) ); +} + +void reset() { + object money; + + ::reset(); + if(!present("money")) { + money = new("/std/lib/pile"); + money->SetCurrency("platinum", random(10)); + money->SetCurrency("gold", random(100)); + money->SetCurrency("electrum", random(200)); + money->move(this_object()); + } +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/booth.c b/lib/domains/Praxis/booth.c new file mode 100644 index 0000000..b87c51c --- /dev/null +++ b/lib/domains/Praxis/booth.c @@ -0,0 +1,81 @@ +// /d/standard/booth.c +// from the Nightmare mudlib +// a nice, simple polling booth +// created by Gregon@Nightmare Jan 1994 + +#include <daemons.h> +#define BOOTH_VOTES "/domains/Praxis/data/booth_votes" +#define BOOTH_QUESTION "/domains/Praxis/data/booth_question" +inherit "/lib/std/room"; + +int a,b; +mapping vote; + +void create() { + ::create(); + SetShort("Nightmare referendum room"); + SetProperty("light", 2); + SetProperty("indoors", 1); + SetLong( + "This is the referendum room of Nightmare. Players come here to vote "+ + "on issues that the wizards desire input on. The current voting "+ + "question is posted on the wall <read question> will display it." + ); + + SetExits( (["down" : "/domains/Praxis/adv_main"]) ); + vote=([]); + RestoreObject(BOOTH_VOTES); +} + +void init() { + ::init(); + add_action("vote", "vote"); + add_action("read", "read"); + if(archp(this_player())) add_action("check", "check"); + +} + +int vote(string str) { + string me; + + me=this_player()->query_name(); + if(str!="a" && str!="b") { + notify_fail("You may only vote for a or b.\n"); + return 0; + } + if(PLAYERS_D->non_voter(me)) { + write("You are listed as a second character. You may not vote."); + return 1; + } + if(vote[me]) { + write("You have already voted."); + return 1; + } + if(str=="a") { + vote[me]="a"; + a++; + write("Vote counted. Thank you."); + SaveObject(BOOTH_VOTES); + return 1; + } + if(str=="b") { + vote[me]="b"; + b++; + write("Vote counted. Thank you."); + SaveObject(BOOTH_VOTES); + return 1; + } + +} + +int read(string str) { + if(!str || str != "question") return 0; + write("The current voting question is this:\n"); + this_player()->more(BOOTH_QUESTION); + return 1; +} + +int check(){ + write("A: "+a+"\nB: "+b); + return 1; +} diff --git a/lib/domains/Praxis/branches.c b/lib/domains/Praxis/branches.c new file mode 100644 index 0000000..316bbaf --- /dev/null +++ b/lib/domains/Praxis/branches.c @@ -0,0 +1,364 @@ +inherit "/lib/std/room"; + +void create() { + ::create(); + SetShort("between the branches"); + SetLong( + "Here, between two strong branches, a small platform (with railing) has "+ + "been installed. The wind rustles the leaves of the tree, a pleasant "+ + "sound that helps keep your mind off the fact that if you fell, you would "+ + "make a very unpleasant-looking mess on the pavement below. But don't "+ + "worry, there have been no fatalities from here... yet. A telescope "+ + "stands near each corner of the platform. "); + SetProperties( (["light" : 2, + "indoors" : 1 , + "no castle" : 1]) ); + SetExits( (["down" : "/domains/Praxis/trunk"]) ); + SetItems( ([ + "telescope" : "Through this magically enhanced telescope, you can see the "+ + "whole world.. you can look at various directions and "+ + "places, broadening your horizons till they overlap those "+ + "of the world. With this telescope, you realize, you can "+ + "add much to your knowledge. ", + "platform" : "The platform is very sturdy. Standing on it, you feel "+ + "much more comfortable than if you had been standing a "+ + "few meters to your left--in mid-air. ", + "railing" : "Having a railing immensely increases your sense of "+ + "security, quite understandably. ", + "branches" : "The broad branches here easily support the platform. ", + "leaves" : "The leaves provide a pleasant green canopy. Even though "+ + "this tree is deciduous, it stays green all year long. ", + "tree" : "You lean back from the telescope and take a moment to look at "+ + "your surroundings, the branches of the Tree of Mages. As "+ + "legend has it, the Tree is as old as the world; some say "+ + "older, but few believe that. It is a fact, though, that the "+ + "Tree of Mages has, through millenia of association with "+ + "powerful mages, acquired tremendous magic and, according to "+ + "some, even intelligence. Today the Tree serves as the class "+ + "hall of the Class of Mages.", + + ({"n", "north"}) : "North of the Tree lie the dark expanses of the North "+ + "Forest, a place of fear and wonder, great danger and "+ + "great treasure. Far off in the distance you see a city "+ + "consisting mainly of a huge library--probably the "+ + "Philosophers' city of Cartesia. Still farther, at the "+ + "very horizon, you see the gleaming of pristine snow at "+ + "what must be the north pole.", + ({"e", "east"}) : "East of the mage tree lie the northern reaches of Krasna. "+ + "Nearby a few buildings lie, whereas farther off the "+ + "north-south road Centre Path connects with the "+ + "eastward-leading Sun Alley. A hospital lies west of that "+ + "juncture, while Sun Alley harbors a classy restaurant, "+ + "and a small residential area mainly occupied by "+ + "aristocrats fallen on hard times. Sun Alley ends when "+ + "it connects with East Road. East of Sun Alley is the "+ + "Cemetery, where the restless spirits of the immortals "+ + "make their home. East Road leads northwards, to the "+ + "gates of Newbieland. North of the cemetery, a small "+ + "path connects with East Road and leads yet eastward, "+ + "over a plateau. Dragons are said to make their lair "+ + "beyond the plateau.", + ({"w", "west"}) : "To the west a vast desert lies, crossed by a range of "+ + "towering mountains. The Desert Highway slices the "+ + "barrenness of the desert as it leads westwards, its "+ + "farthest expanses cloaked by shimmering heat waves... "+ + "Nearby a strange valley lies, somewhat to the north of "+ + "the Desert Highway. In the distance, you can barely "+ + "glimpse the glistening white spires of a desert city.", + + ({"s", "south"}) : "South of the Mage Tree lies West Road, the north-south "+ + "road that marks the western limit of Krasna. It "+ + "connects at the southern end with Boc-La Road, the main "+ + "road of the city. A hut to the eastern side of the "+ + "road, slightly south of the tree, catches your eye.", + ({"se", "southeast"}) + : "Southeast of the Mage Tree lies the main body of the "+ + "city of Krasna. West Road leads south from the Tree, "+ + "and ends at Boc-La, the east-west road that has been "+ + "called ``the main artery of Krasna''. Boc-La's western "+ + "end begins at West Road's southern end, and from "+ + "there it leads east, passing through Monument "+ + "Square and continuing eastwards toward the dark Eastern "+ + "Jungle, where savages, cannibals and rogues make their "+ + "home. Along the way, Boc-La passes through Lars' Bar, "+ + "the establishment of the Sage of Languages, the local "+ + "Monastery, Horace's Supply shop, and other famous "+ + "sites. At its eastern end, just before heading "+ + "into the jungle, Boc-La road has a small gate leading "+ + "south to the fabled docks of the Flying Galleys. From "+ + "Monument Square another main road, Centre Path, leads "+ + "north and south. North, Centre Path passes by the "+ + "church, a hospital and Sun Alley before heading to the "+ + "North Forest; south, it leads past the bar to south "+ + "Krasna, where the business sector lies (and where the "+ + "bank and post office are located). Yet southwards, "+ + "Centre Path leads to the headquarters of the class of "+ + "fighters and, eventually, all the way south are the "+ + "piers where fishermen cast nets to provide the local "+ + "restaurant with fresh seafood.", + ({"nw", "northwest"}) + : "The North Forest is abruptly arrested by a range of "+ + "mountains lying west and slightly north of the Mage "+ + "Tree. On the other side of the mountains lies the desert.", + ({"ne", "northeast"}) + : "As it leaves Krasna to the north, Centre Path turns "+ + "into a trail winding through the North Forest. Slightly "+ + "north of the city limits an east-west path leads from "+ + "the remains of Centre Path. Passing by this path, the "+ + "trail continues north, past a hole in the ground, then "+ + "curves northwest for a short while, and when it curves "+ + "back north, it has joined the North Forest Highway. "+ + "The Highway goes north for a long time, passing by in "+ + "turn a bog, an exit going west to some city, a tower "+ + "and a house, and finally reaching the polar ice cap "+ + "at the very horizon.", + + ({"valley", "strange valley"}) + : "This strange valley to the north of the Great Western "+ + "Highway (sometimes known as the Desert Highway) is "+ + "obviously artificial. Its clumsy manufacture leads you "+ + "to believe that it was constructed by some particularly "+ + "maladroit race, perhaps by orcs.", + ({"desert highway", "western highway", "great western highway"}) + : "Constructed many years ago to allow trade between "+ + "Krasna and the cities beyond the desert, this highway "+ + "is protected by magic against sand storms. It provides "+ + "no protection against heat, however; sometimes one can "+ + "see a small bag, or trinket, that is all that remains of "+ + "an unfortunate traveller whose body has long since "+ + "become dust.", + ({"spires", "desert city"}) + : "The shimmering is too strong for you to make out any "+ + "details, but you can glimpse the white spires of a "+ + "desert city at the end of the Great Desert Highway.", + ({"mountains", "desert mountains"}) + : "A mighty mountain range crosses the desert to the west "+ + "of Krasna. It is rumored to harbour orcs, goblin caves, "+ + "stirges and all kinds of nasty creatures.", + "centre path" : "A road leading north and south from Monument Square, "+ + "the heart of Krasna. Along it lie some of the most "+ + "famous establishments of Krasna, not least being "+ + "Lars' Pub and the Clerics' Hospital.", + "east road" : "A north-south road at the eastern limit of Krasna, "+ + "East Road connects with Sun Alley at the cemetery. "+ + "Its northern end leads to Newbieland.", + "sun alley" : "An east-west alley leading from the hospital at its "+ + "western end to the cemetery at its eastern end "+ + "(coincidence?), Sun Alley is home to the Last Dragon "+ + "Restaurant and also to barons and knights who have "+ + "fallen on hard times.", + "cemetery" : "Praxis Cemetery is already occupied by the ghosts of "+ + "the immortals. Thus, for new entrants it is strictly "+ + "Standing Room Only.", + "newbieland" : "Newbieland lies north of East Road; a force-field "+ + "surrounding it prevents you from seeing anything else.", + "hospital" : "The Clerics' Hospital was established many years ago "+ + "by the kind class of Clerics, who have their class "+ + "head-quarters in the church just south of the hospital. "+ + "Normally they charge a fee to cover their expenses, but "+ + "in certain cases they make exceptions for first-level "+ + "players.", + "restaurant" : "The Last Dragon Restaurant is the classiest restaurant "+ + "in Krasna! Located in Sun Alley, once a prestigious "+ + "neighbourhood, this restaurant uses only the freshest "+ + "ingredients. Needless to say it also charges a lot.", + "plateau" : "East of Krasna lies a plateau. Dragons are said to lie "+ + "beyond, and horridly injured travellers returning from "+ + "there confirm the tale.", + "square" : "Monument Square, once known as Krasna Square, is the "+ + "teeming heart of Krasna City. People come there to "+ + "converse, meet, receive healing if a cleric is there, "+ + "and generally relax. The immortals have graciously put "+ + "protective forces on the Square to prevent and fighting, "+ + "stealing and any spell-casting except heal-craft.", + ({"krasna", "praxis", "city"}) + : "Krasna City is the major city in this reality. All of "+ + "the class halls are located in or near it (except the "+ + "class hall of the rogues, who have been banished to the "+ + "jungle). Once known as Praxis, Krasna has a rich history "+ + "and a lively commerce with other, lesser cities such as "+ + "the desert city, Arberth, Cartesia and many more.\n"+ + " To Global Newbieland A - Mage Tree\n"+ + " B - Hospital\n"+ + " | C - Post Office\n"+ + " + D - Square\n"+ + " | E - Monastery\n"+ + " Here there | F - Free equipment\n"+ + " be dragons F--+ G - Horace's Store\n"+ + " | | H - Boards\n"+ + " | | Here there I - Library\n"+ + " A + +-- be dragons\n"+ + " | | |\n"+ + " | | |\n"+ + " T +--+ B--+---+---+---+-- To Graveyard\n"+ + " o | | | | |\n"+ + " | | + + |\n"+ + " M + + +---I\n"+ + " o | | E G |\n"+ + " u | | | | |\n"+ + " n ---+---+---+----+--D---+---+---+---+-- To Outlands\n"+ + " t | | | | |\n"+ + " a + +--+ H-+ |\n"+ + " i | +\n"+ + " n + + | To Ships\n"+ + " s | | |\n"+ + " +---+---+---+---+\n"+ + " | | |\n"+ + " | | |\n"+ + " + C +\n"+ + " /\n"+ + " /\n"+ + " +\n"+ + " |\n"+ + " |\n"+ + " +", + "bar" : "When this reality was created, Lars' Bar was one of the "+ + "first establishments to operate. Lars spared no expense "+ + "in providing the very best atmosphere for players to "+ + "relax in. Recent anti-alcohol measures, notably a tax on "+ + "drinks, have caused Lars' Bar to lose some of its "+ + "grandeur, however. Lars tried at first to draw more "+ + "customers by publishing a list of the most powerful "+ + "adventurers in this world, but when that failed to bring "+ + "enough customers Lars had to resort to increasing "+ + "prices. Still, despite ever-rising prices, if you really "+ + "need a drink then Lars' Bar is *the* place to go; his "+ + "profits may have gone down but his drinks are still as "+ + "powerful as they ever were.", + "church" : "The local church is where the class of clerics make "+ + "their home. Ever willing to help their kindred, the "+ + "clerics of Nightmare have established a hospital just "+ + "north of the church, where for a fee one can get healing "+ + "and magical energy, and even limbs can be restored.", + "monastery" : "Home of the powerful class of monks, the monastery is a "+ + "proud and solemn place where many of the sacred rituals "+ + "of Nightmare take place. It is in the main hall of the "+ + "monastery that ghosts come to pray for resurrection "+ + "after being killed, and it is in a chapel in the "+ + "monastery that couples are joined in marriage. Located "+ + "north of Boc-La, slightly to the east of Monument "+ + "Square, the monastery is awarded deep respect by most "+ + "members of society.", + ({"docks", "galleys"}) + : "At the very east end of Boc-La a gate leads south to "+ + "the magic docks of Krasna where flying galleys are "+ + "purchased, to bring travellers to different realms.", + "shop" : "Horace, one of the first true-blooded elves to come to "+ + "Nightmare, promptly set up shop near the east end of "+ + "Krasna. Taking advantage of his position, Horace buys "+ + "low and sells high. He is noted for his cold-blooded "+ + "mercantility and his crass profiteering; since his store "+ + "is, however, one of the few places where newbies can "+ + "sell their gear, the High Mortals of Nightmare "+ + "discourage people from killing him.", + "piers" : "Located at the very southern end of Krasna, the piers "+ + "are frequently visited by hopeful players with fishing "+ + "poles on their shoulders and a lot of time on their "+ + "hands.", + ({"bank", + "post office"}) : "South of Monument Square an east-west alley marks the "+ + "business sector of Krasna. To the east it leads to the "+ + "sewers, and to the west it leads to the bank and the "+ + "post office. The bank is where people open an account to "+ + "store their cash; no interest payments, unfortunately. "+ + "At the post office mail is handled, sent, and received.", + "jungle" : "To the east of Krasna lies the dark Eastern Jungle. Its "+ + "inhabitants include cannibals, savages, rogues, and "+ + "other vermin. At the far end of the jungle a mysterious "+ + "tower is rumored to lie, but few have returned to tell "+ + "the tale. The few who have speak of death traps, doors "+ + "that lock behind you and other chilling details.", + "sage" : "The Sage dwells in a small hut north of Boc-La, near "+ + "the western end of the city. He is the person in charge "+ + "of instructing players in the proper use of various "+ + "languages.", + + ({"forest", "north forest"}) + : "A dark place of many legends and a thousand tales, the "+ + "North Forest is home to a myriad of creatures, ranging "+ + "from evil faeries to wicked wolves, from trolls to "+ + "dragons to centaurs. It is even said that the gates of "+ + "hell lie somewhere in the North Forest. And yet the "+ + "forest harbours heros, and scholars, paladins and "+ + "seekers of truth... and treasures beyond the wildest "+ + "dreams of avarice... Fortunately for travellers, the "+ + "North Forest Highway provides magical protection from "+ + "monsters, but even the highway offers no shield from "+ + "the bandits and highwaymen who frequently beset the "+ + "unwary.", + ({"north pole", "pole", "snow"}) + : "At the north horizon, where sky embraces earth in a "+ + "white-grey swirl, lies the North Pole. Once the "+ + "residence of one Mr. S. Claus and his elves, sometimes "+ + "referred to as subordinate clauses, the North Pole has "+ + "been ruthlessly taken over by a tribe of ferocious "+ + "giants who evicted Mr. Claus and turned his helpers "+ + "into yummy bite-sized (by giant standards) pieces of "+ + "raw meat. At least, that is what is claimed by the few "+ + "who have returned from there; but they may well have "+ + "suffered trauma from the cold and entered a "+ + "hallucinatory state.", + "west road" : "This north-south road harbours two important magical "+ + "establishments, the legendary Tree of Mages and the "+ + "less well-known hut of Mora the Teller of Fortunes. The "+ + "Tree is at the north end of the road, Mora's hut is "+ + "somewhat to the south. The south end of the road "+ + "connects to the western end of Boc-La.", + "boc-la" : "This road runs east-west through the heart of the "+ + "city. To the west it merges with the western highway, "+ + "and to the east it dissappears in the jungle. The road "+ + "passes through the square, and many important "+ + "establishments can be found just off it. Horace's shop "+ + "and the adventurer's hall flank the road in the east. "+ + "Nearer to the tree you can see Lars' pub, and the "+ + "Sage's house is opposite a bit of farmlands.", + "hut" : "Mora's hut lies south and east of the Mage Tree. "+ + "Training the telescope on the sign above the door, you "+ + "make out that Mora is a fortune-teller specializing in "+ + "horoscopes.", + "library" : "You cannot clearly make out the library, as your view "+ + "is obstructed.", + "cartesia" : "Far north of Krasna lies the famous Philosopher City "+ + "of Cartesia, home to the largest known library in the "+ + "world. The Philosophers of Cartesia, or Seekers of "+ + "Truth as they are sometimes called, have long been a "+ + "major force, exploring new areas, seeking out new life, "+ + "and new civilizations, boldly going where no player has "+ + "gone before.", + "north highway" : "A magical path leading through the North Forest, the "+ + "North Forest Highway is magically protected against "+ + "monsters, thus ensuring free passage to those who are "+ + "not stupid.. err.. bold enough to wander off it. "+ + "However, it does not offer protection against bandits "+ + "and highwaymen. The Highway connects with a path "+ + "leading north from Krasna, forming a single, long road "+ + "from the heart of civilization (Krasna) to, "+ + "essentially, the polar icecap. A ways north of its "+ + "southern end, the Highway has an exit leading to the "+ + "rationally-designed, empirically-built and dogmatically-"+ + "defended city of philosophers, Cartesia.", + "horizon" : "You do not notice that here. duh.", + "hole" : "North of the city, right before the remains of Centre "+ + "Path curve northwest, lies a hole in the ground with a "+ + "reddish glow coming out of it. That hole is reputed to "+ + "be the lair of the evil demon-worshipping class known "+ + "as the Class of Kataans.", + "tower" : "The tower is obscured by trees.", + "house" : "A fairly large mansion on the lies west of the North "+ + "Highway, somewhat to the north of the exit to the "+ + "Philosopher City. Not much is known about it, except "+ + "that a necromancer might be living in it.", + "bog" : "At the south end of the North Forest Highway a path "+ + "leads east to a diseased-looking bog. Many explorers "+ + "have gone there, and quite a few have come back. Those "+ + "who came back all had one thing in common: they had "+ + "wimpy set ``on''. They report of nasty beasts, horrid "+ + "insects, ghoulish graveyards and some other.. well.. "+ + "weird things.", + "exit" : "Several miles north of where the North Highway "+ + "connects with the trail that is the northern extension "+ + "of Centre Path, an exit leads west from the Highway "+ + "toward a small city with a big library."]) ) ; } + void init(){ + ::init(); + } diff --git a/lib/domains/Praxis/building.c b/lib/domains/Praxis/building.c new file mode 100644 index 0000000..0cf3f9f --- /dev/null +++ b/lib/domains/Praxis/building.c @@ -0,0 +1,53 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 1); + SetProperty("indoors", 1); + SetSmell("default", "The building smells stale and decaying."); + SetListen("default", "The boards which make up " + "the floor are creaking under your weight."); + SetShort( "a broken down building"); + SetLong( + "Broken boards and rotting thatch have left this place very " + "dangerous for walking. The squeaks of diseased rodents " + "tell you that this place is no longer run by humanoids, but " + "bits of evidence here and there suggest recent humanoid passage. " + "The alley lies north of here."); + SetItems( + (["board" : "It is rotting from exposure to the weather.", + "boards" : "You do not want to rely on them for support.", + "thatch" : "It once formed the roof of the building, but no more.", + "roof" : "A patchwork of rotting thatch.", + "evidence" : "Dust left unsettled.", + "dust" : "It looks like it has not been very long settled in places.", + "foo" : "What do you mean by foo?"]) ); + SetExits( + (["north" : "/domains/Praxis/alley2"]) ); +} + +void reset() { + object rat; + + ::reset(); + if(!present("rat")) { + rat = new("/lib/npc"); + rat->SetKeyName("rat"); + rat->SetId( ({ "rat", "filthy rat", "a filthy rat" }) ); + rat->SetLevel(1); + rat->SetShort( "A filthy rat"); + rat->SetLong("A disgusting little rodent."); + rat->SetRace( "rodent"); + rat->SetCurrency("silver", random(10)); + rat->SetHealthPoints(60+random(10)); + rat->SetMorality(-1); + rat->move(this_object()); + } + if(!present("torch")) + new("/domains/town/obj/torch")->move(this_object()); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/cache.c b/lib/domains/Praxis/cache.c new file mode 100644 index 0000000..467e36b --- /dev/null +++ b/lib/domains/Praxis/cache.c @@ -0,0 +1,11 @@ +inherit "/lib/std/room"; + +void create() { + ::create(); + SetShort( "The cache"); + SetLong( "Things are hidden here."); + SetProperty("storage room", 1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/cemetery/grave_yard.c b/lib/domains/Praxis/cemetery/grave_yard.c new file mode 100644 index 0000000..32f2fa5 --- /dev/null +++ b/lib/domains/Praxis/cemetery/grave_yard.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 2); + SetExits( + (["west" : "/domains/Praxis/east_road2", + "east" : "/domains/Praxis/cemetery/grave_yard2"]) ); + SetShort("Cemetary Entrance"); + SetLong( + "You stand between the gates of an ancient, nearly " + "forgotten cemetery. The air is very still here, and " + "preternaturally quiet. You feel uneasy and look over " + "your shoulder. No one comes here anymore for some reason. " + "You see a headstone off to the east. "); + SetItems( + (["headstone" : "The headstone is too far away to read.", + "gates" : "The gates are antiques. No one makes gates " + "like these anymore."]) ); + SetSkyDomain("town"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/cemetery/grave_yard2.c b/lib/domains/Praxis/cemetery/grave_yard2.c new file mode 100644 index 0000000..5bb830b --- /dev/null +++ b/lib/domains/Praxis/cemetery/grave_yard2.c @@ -0,0 +1,41 @@ +#include <lib.h> +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 1); + SetShort( "Entrance to graveyard"); + SetLong( + "You have entered an old, disreputable cemetery. There are a few " + "new graves, but most are very ancient and untended. You see a " + "cracked marble headstone on the grave here."); + SetItems( + (["depths" : "You look down into Melissa's grave and see " + "a swirling white haze.", + "haze" : "The haze moves like it is alive, and takes " + "on what looks like a female form at times.", + "haziness" : "The haziness swirls constantly and covers the grave.", + "depression" : "The depression is caused by the soil over " + "the grave sinking. There is a haze covering it.", + "headstone" : "An ancient headstone, perhaps the first. " + "Its writing is illegible except for the name Melissa Praxis.", + "graves" : "Most graves here are overgrown and untended. " + "You stand next to a very old and shabby, sunken grave.", + "cemetery" : "The residents of Praxis get buried there. " + "It looks spooky.", + "grave" : "You look down at Melissa's grave. " + "You see an odd haziness in the depths of the depression " + "where the grave has sunken over the years."]) ); + SetSkyDomain("town"); + SetExits( + (["west" : "/domains/Praxis/cemetery/grave_yard", + "northeast" : "/domains/Praxis/cemetery/grave_yard6", + "east" : "/domains/Praxis/cemetery/grave_yard5", + "southeast" : "/domains/Praxis/cemetery/grave_yard4", + "south" : "/domains/Praxis/cemetery/grave_yard3", + "down" : "/domains/Praxis/cemetery/grave_yard7", + "north" : "/domains/Praxis/cemetery/grave_yard8"]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/cemetery/grave_yard3.c b/lib/domains/Praxis/cemetery/grave_yard3.c new file mode 100644 index 0000000..bd802af --- /dev/null +++ b/lib/domains/Praxis/cemetery/grave_yard3.c @@ -0,0 +1,46 @@ +#include <lib.h> +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 1); + SetShort( "Darkone's grave"); + SetLong( + "You are in the southern-most area of the cemetery. You hear " + "no friendly sounds, only an ominous silence. There is a " + "solitary grave here, with a small headstone at the head of it."); + SetItems( + (["headstone" : "The headstone is a deep cobalt blue, and " + "has writing on it.", + "cemetery" : "All about you stretch the silent graves. " + "You feel like you are being watched.", + "grave" : "The grave is covered with soft grass, and has " + "been here a long time", + "writing" : "Here lies Darkone. He was lynched, suitably " + "enough, by an irate mob of young immortals for nit-picking " + "in their castles."]) ); + SetSkyDomain("town"); + SetExits( + (["north" : "/domains/Praxis/cemetery/grave_yard2", + "northeast" : "/domains/Praxis/cemetery/grave_yard4"]) ); +} + +void reset() { + ::reset(); + if (!present("ghost")) + new("/domains/Praxis/cemetery/mon/ghost3")->move(this_object()); +} + +void init() { + ::init(); + add_action("read","read"); +} + +int read(string str) { + if (str == "writing") { + write (::GetLong("writing")); + return 1; + } + notify_fail("Read what?\n"); + return 0; +} diff --git a/lib/domains/Praxis/cemetery/grave_yard4.c b/lib/domains/Praxis/cemetery/grave_yard4.c new file mode 100644 index 0000000..a589459 --- /dev/null +++ b/lib/domains/Praxis/cemetery/grave_yard4.c @@ -0,0 +1,58 @@ +#include <lib.h> +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 1); + SetShort( "Flamme's grave"); + SetLong( + "You have entered an area set aside for insurance agents, " + "bankers and women who mud. It's a sad and dismal place, " + "seldom visited by mourners since there usually aren't any. " + "There is one grave here that catches your eye. It is " + "covered in broken pencils and wadded up paper with bits " + "of code that don't work. Some poor creature has come to " + "a bad end. You see a small wooden marker, as no one thought " + "to put up a headstone."); + SetItems( + (["cemetery" : "All about you stretch the silent graves. " + "You feel like you are being watched.", + "grave" : "The grave is covered with the trash and " + "mementos of a coder.", + "pencils" : "The pencils are all short, chewed, and " + "broken. None write anymore.", + "writing" : "Here lies Flamme. This lovely young lass " + "met an untimely end when she used humor at the wrong " + "time and with the wrong god. Let this be a lesson to " + "young immortals.", + "paper" : "Countless small bits and wads of paper litter the area.", + "code" : "The pieces of code never did work, and are " + "unintelligible to normal humans.", + "marker" : "The plaque is of white marble. You might " + "be able to read the writing on it."]) ); + SetExits( + (["northeast" : "/domains/Praxis/cemetery/grave_yard5", + "northwest" : "/domains/Praxis/cemetery/grave_yard2", + "southwest" : "/domains/Praxis/cemetery/grave_yard3"]) ); +} + +void reset() { + ::reset(); + if (!present("ghost")) + new("/domains/Praxis/cemetery/mon/ghost4")->move(this_object()); +} + +void init() { + ::init(); + add_action("read","read"); +} + +int read(string str) { + if (str == "writing") { + write (::GetLong("writing")); + return 1; + } + notify_fail("Read what?\n"); + return 0; +} + diff --git a/lib/domains/Praxis/cemetery/grave_yard5.c b/lib/domains/Praxis/cemetery/grave_yard5.c new file mode 100644 index 0000000..e0b5ac0 --- /dev/null +++ b/lib/domains/Praxis/cemetery/grave_yard5.c @@ -0,0 +1,48 @@ +#include <lib.h> +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 1); + SetShort( "Forlock's grave"); + SetLong( + "You are in an old, dark cemetery. The eerie silence gets on your " + "nerves. At your feet is a new grave, dug in haste. A few faded " + "blossoms give mute, sad testimony to affections from the past. A " + "small marble plaque lies to one side, not having been installed " + "at the head of the grave yet."); + SetItems( + (["cemetery" : "All about you stretch the silent graves. " + "You feel like you are being watched.", + "grave" : "The grave is new and mounded with fresh dirt.", + "blossoms" : "The flowers are wilted and faded. They look sad.", + "writing" : "Here lies poor old Forlock. His last words were: " + "Help!! I'm getting line noiss..fjjjdk..%$fffs..*squawk*.." + "0w0w0w0w0w!!", + "plaque" : "The plaque is of grey marble. You might be able " + "to read the writing on it."]) ); + SetExits( + (["northwest" : "/domains/Praxis/cemetery/grave_yard6", + "west" : "/domains/Praxis/cemetery/grave_yard2", + "southwest" : "/domains/Praxis/cemetery/grave_yard4"]) ); +} +void reset() { + ::reset(); + if (!present("ghost")) + new("/domains/Praxis/cemetery/mon/ghost5")->move(this_object()); +} + +void init() { + ::init(); + add_action("read","read"); +} + +int read(string str) { + if(str == "writing" || str == "plaque") { + write (::GetLong("writing")); + return 1; + } + notify_fail("Read what?\n"); + return 0; +} + diff --git a/lib/domains/Praxis/cemetery/grave_yard6.c b/lib/domains/Praxis/cemetery/grave_yard6.c new file mode 100644 index 0000000..45fd572 --- /dev/null +++ b/lib/domains/Praxis/cemetery/grave_yard6.c @@ -0,0 +1,52 @@ +inherit "/lib/std/room"; + +void create() { + ::create(); + SetProperty("light", 1); + SetShort( "Descartes' grave"); + SetLong( + "This is the cold and silent northeast corner of the ancient " + "cemetery. You feel shivers go up your spine as you look at " + "the tortured form of the statue mounted over this grave. " + "There are small heaps of nuts and bolts lying on the grave. " + "You notice a plaque on the statue."); + SetItems( + (["cemetery" : "All about you stretch the silent graves. " + "You feel like you are being watched.", + "grave" : "The grave is covered with small metal nuts and " + "bolts and other metal tributes.", + "nuts" : "The grave is covered with heaps of small pieces of metal.", + "bolts" : "The grave is covered with small bits of metal, " + "including nuts and bolts.", + "statue" : "The statue is of a large cube, made of many " + "metal bits stuck together.", + "writing" : "Here lies the Borg, unit #82664302-tr, " + "unmourned and unnoticed when it ceased to function.", + "plaque" : "The plaque is of silver metal. You might be " + "able to read the engraving on it."]) ); + SetSkyDomain("town"); + SetExits( + (["northwest" : "/domains/Praxis/cemetery/grave_yard8", + "southwest" : "/domains/Praxis/cemetery/grave_yard2", + "southeast" : "/domains/Praxis/cemetery/grave_yard5"]) ); +} + +void reset() { + ::reset(); + if (!present("ghost")) + new("/domains/Praxis/cemetery/mon/ghost6")->move(this_object()); +} + +void init() { + ::init(); + add_action("read","read"); +} + +int read(string str) { + if (str == "plaque") { + write (::GetLong("writing")); + return 1; + } + notify_fail("Read what?\n"); + return 0; +} diff --git a/lib/domains/Praxis/cemetery/grave_yard7.c b/lib/domains/Praxis/cemetery/grave_yard7.c new file mode 100644 index 0000000..3d84872 --- /dev/null +++ b/lib/domains/Praxis/cemetery/grave_yard7.c @@ -0,0 +1,24 @@ +inherit "/lib/std/room"; +object coffin; + +void create() { + ::create(); + SetProperty("light", 0); + SetShort( "The grave"); + SetLong( + "You have foolishly climbed down into the ancient grave of one of " + "the founders of Praxis. You are standing on the closed lower door " + "of a coffin. The upper door is open and gruesomely inviting. The " + "soil presses in around you claustrophobicly."); + SetItems( + (["under" : "You can't look under the coffin, you're " + "standing on it.", + "soil" : "The dirt walls of the grave are soft and " + "smell of the earth.", + "grave" : "The grave is horribly empty and sad."]) ); + SetExits( + ([ "up" : "/domains/Praxis/cemetery/grave_yard2"]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/cemetery/grave_yard8.c b/lib/domains/Praxis/cemetery/grave_yard8.c new file mode 100644 index 0000000..5e96f3a --- /dev/null +++ b/lib/domains/Praxis/cemetery/grave_yard8.c @@ -0,0 +1,44 @@ +inherit "/lib/std/room"; + +void create() { + ::create(); + SetProperty("light", 1); + SetShort( "Shadowwolf's grave"); + SetLong( + "You are in the northern reaches of the Praxis cemetery. Old, " + "long-abandoned graves spread out around you. An eerie silence " + "has settled over the area, as if it's awaiting something horrible. " + "You see a grave here, with an antique headstone."); + SetItems( + (["cemetery" : "All about you stretch the silent graves. " + "You feel like you are being watched.", + "grave" : "The grave is old, and grass-covered.", + "writing" : "The engraving says: Here lies the mysterious " + "Shadowwolf. He was decisively executed by mudders when " + "it was discovered he hung out with Knights who say NI.", + "headstone" : "The headstone is of grey marble. You might " + "be able to read the writing on it."]) ); + SetSkyDomain("town"); + SetExits( + (["southeast" : "/domains/Praxis/cemetery/grave_yard6", + "south" : "/domains/Praxis/cemetery/grave_yard2"]) ); +} +void reset() { + ::reset(); + if (!present("ghost")) + new("/domains/Praxis/cemetery/mon/ghost8")->move(this_object()); +} + +void init() { + ::init(); + add_action("read","read"); +} + +int read(string str) { + if(str == "writing" || str == "headstone") { + write (::GetLong("writing")); + return 1; + } + notify_fail("Read what?\n"); + return 0; +} diff --git a/lib/domains/Praxis/cemetery/mon/ghost.c b/lib/domains/Praxis/cemetery/mon/ghost.c new file mode 100644 index 0000000..a42d5bc --- /dev/null +++ b/lib/domains/Praxis/cemetery/mon/ghost.c @@ -0,0 +1,34 @@ +inherit "/lib/npc"; + +void create() { + ::create(); + SetKeyName("Melissa's Ghost"); + SetId( ({ "ghost","melissa","Melissa","Melissa's Ghost" }) ); + SetShort( "Melissa's ghost"); + SetAggressive( 0); + SetLevel(1); + SetLong( "A misty figure in a long flowing white gown. " + "She is wringing her hands and weeping."); + SetMorality(200); + SetRace( "wraith"); + SetGender("female"); + SetCurrency("gold",random(50)); + SetMaxHealthPoints(25); + SetHealthPoints(25); + SetRace("human"); +} + +void catch_tell(string str) { + object ob; + string a, b, c; + + if(sscanf(str, "%s gives %s to you", a, b) == 2) { + ob = present( lower_case(a), environment(this_object())); + if(ob) { + tell_object(ob, "The ghost thanks you for your generosity."); + tell_room(environment(this_object()), "The ghost thanks "+a+" for "+ob->query_possessive()+" generosity.", ({this_object(), ob})); + } + } + if(sscanf(str, "%ssmiles%s", a, b) == 2) + tell_room(environment(this_object()), "The little ghost weeps piteously.", ({this_object()})); +} diff --git a/lib/domains/Praxis/cemetery/mon/ghost3.c b/lib/domains/Praxis/cemetery/mon/ghost3.c new file mode 100644 index 0000000..f319411 --- /dev/null +++ b/lib/domains/Praxis/cemetery/mon/ghost3.c @@ -0,0 +1,38 @@ +inherit "/lib/npc"; + +void create() { + ::create(); + SetKeyName("darkone's ghost"); + SetId( ({ "ghost","darkone","Darkone","Darkone's Ghost" }) ); + SetShort( "Darkone, the ghost with a bent neck"); + SetAggressive( 0); + SetLevel(1); + SetLong( "This is Darkone's evil ghost. He is smiling so " + "evilly that huge black horns have sprouted on his head. " + "He is deeply grieved he can no longer torture wizards " + "by nit-picking in their castles."); + SetMorality(-600); + SetRace( "wraith"); + SetGender("neuter"); + SetMaxHealthPoints(25); + SetCurrency("gold",25); + SetHealthPoints(25); + SetRace("human"); +} + +void catch_tell(string str) { + object ob; + string a, b, c; + + if(sscanf(str, "%s gives %s to you", a, b) == 2) { + ob = present( lower_case(a), environment(this_object())); + if(ob) { + tell_object(ob, "The ghost thanks you for your generosity."); + tell_room(environment(this_object()), "The ghost thanks "+a+" for "+ob->query_possessive()+" generosity.", ({this_object(), ob})); + } + } + if(sscanf(str, "%ssmiles%s", a, b) == 2) + tell_room(environment(this_object()), "Darkone's ghost " + "groans loudly: Aooooooooooooo...*gerk* (The howl " + "cuts off abruptly.)", ({this_object()})); +} diff --git a/lib/domains/Praxis/cemetery/mon/ghost4.c b/lib/domains/Praxis/cemetery/mon/ghost4.c new file mode 100644 index 0000000..78d86cf --- /dev/null +++ b/lib/domains/Praxis/cemetery/mon/ghost4.c @@ -0,0 +1,33 @@ +inherit "/lib/npc"; + +void create() { + ::create(); + SetKeyName("flamme's ghost"); + SetId( ({ "ghost","flamme","Flamme","Flamme's Ghost" }) ); + SetShort( "Flamme's ghost"); + SetAggressive( 0); + SetLevel(1); + SetLong( "The ghost still has a few tufts of auburn hair " + "sticking out in all directions. She is smiling, but " + "with a rather surprised look on her face."); + SetMorality(600); + SetRace( "wraith"); + SetGender("female"); + SetMaxHealthPoints(25); + SetHealthPoints(25); + SetRace("human"); +} + +void catch_tell(string str) { + object ob; + string a, b, c; + + if(sscanf(str, "%s gives %s to you", a, b) == 2) { + ob = present( lower_case(a), environment(this_object())); + if(ob) { + tell_object(ob, "The ghost thanks you for your generosity."); + tell_room(environment(this_object()), "The ghost thanks "+a+" for "+ob->query_possessive()+" generosity.", ({this_object(), ob})); + } + } + if(sscanf(str, "%ssmiles%s", a, b) == 2) tell_room(environment(this_object()), "The little ghost asks: What happened to me?", ({this_object()})); +} diff --git a/lib/domains/Praxis/cemetery/mon/ghost5.c b/lib/domains/Praxis/cemetery/mon/ghost5.c new file mode 100644 index 0000000..e1b851b --- /dev/null +++ b/lib/domains/Praxis/cemetery/mon/ghost5.c @@ -0,0 +1,32 @@ +inherit "/lib/npc"; + +void create() { + ::create(); + SetKeyName("forlock's ghost"); + SetId( ({ "ghost","forlock","Forlock","Forlock's Ghost" }) ); + SetShort( "Forlock's ghost"); + SetAggressive( 0); + SetLevel(1); + SetLong( "This is Forlock's sad ghost, lost, and bereft " + "of mortal companions."); + SetMorality(200); + SetRace( "wraith"); + SetGender("male"); + SetMaxHealthPoints(25); + SetHealthPoints(25); + SetRace("human"); +} + +void catch_tell(string str) { + object ob; + string a, b, c; + + if(sscanf(str, "%s gives %s to you", a, b) == 2) { + ob = present( lower_case(a), environment(this_object())); + if(ob) { + tell_object(ob, "The ghost thanks you for your generosity."); + tell_room(environment(this_object()), "The ghost thanks "+a+" for "+ob->query_possessive()+" generosity.", ({this_object(), ob})); + } + } + if(sscanf(str, "%ssmiles%s", a, b) == 2) tell_room(environment(this_object()), "Forlock's ghost grimaces, and asks you if you've seen his mud.", ({this_object()})); +} diff --git a/lib/domains/Praxis/cemetery/mon/ghost6.c b/lib/domains/Praxis/cemetery/mon/ghost6.c new file mode 100644 index 0000000..48a3417 --- /dev/null +++ b/lib/domains/Praxis/cemetery/mon/ghost6.c @@ -0,0 +1,45 @@ +inherit "/lib/npc"; + +create() { + ::create(); + SetKeyName("descartes's ghost"); + SetId( ({ "ghost","descartes","Descartes","Descartes's Ghost" }) ); + SetShort("Descartes's ghost"); + SetAggressive( 0); + /* + set_speed(9); + set_moving(1); + */ + + SetLevel(1); + SetLong("This is an android ghost, rusted immobile by a sudden, unexpected mud-rain.\n"); + SetMorality(400); + SetRace( "wraith"); + SetGender("male"); + SetMaxHealthPoints(25); + SetHealthPoints(25); + AddLimb("head", "FATAL", 25, 0, 4); + AddLimb("torso", "FATAL", 50, 0, 4); + AddLimb("right arm", "right hand", 20, 0, 4); + AddLimb("right hand", "", 15, 0, 4); + AddLimb("left arm", "left hand", 20, 0, 4); + AddLimb("left hand", "", 15, 0, 4); + AddLimb("right leg", "right foot", 25, 0, 4); + AddLimb("right foot", "", 20, 0, 4); + AddLimb("left leg", "left foot", 25, 0, 4); + AddLimb("left foot", "", 20, 0, 4); +} + +void catch_tell(string str) { + object ob; + string a, b, c; + + if(sscanf(str, "%s gives %s to you", a, b) == 2) { + ob = present( lower_case(a), environment(this_object())); + if(ob) { + tell_object(ob, "The ghost thanks you for your generosity.\n"); + tell_room(environment(this_object()), "The ghost thanks "+a+" for "+ob->query_possessive()+" generosity.\n", ({this_object(), ob})); + } + } + if(sscanf(str, "%ssmiles%s", a, b) == 2) tell_room(environment(this_object()), " Descartes, the immobile ghost, makes muffled meeping sounds.\n", ({this_object()})); +} diff --git a/lib/domains/Praxis/cemetery/mon/ghost8.c b/lib/domains/Praxis/cemetery/mon/ghost8.c new file mode 100644 index 0000000..3c32450 --- /dev/null +++ b/lib/domains/Praxis/cemetery/mon/ghost8.c @@ -0,0 +1,34 @@ +inherit "/lib/npc"; + +void create() { + ::create(); + SetKeyName("shadowwolf's ghost"); + SetId( ({ "ghost","shadowwolf","Shadowwolf","Shadowwolf's Ghost" }) ); + SetShort( "Shadowwolf's ghost"); + SetAggressive( 0); + SetLevel(1); + SetLong( "The ghost is a pale wraithe, holding a NI clutched " + "tightly to his chest."); + SetMorality(100); + SetRace( "wraith"); + SetGender("male"); + SetMaxHealthPoints(25); + SetHealthPoints(5); + SetRace("human"); + RemoveLimb("left foot",this_object()); + RemoveLimb("right hand",this_object()); +} + +void catch_tell(string str) { + object ob; + string a, b, c; + + if(sscanf(str, "%s gives %s to you", a, b) == 2) { + ob = present( lower_case(a), environment(this_object())); + if(ob) { + tell_object(ob, "The ghost thanks you for your generosity."); + tell_room(environment(this_object()), "The ghost thanks "+a+" for "+ob->query_possessive()+" generosity.", ({this_object(), ob})); + } + } + if(sscanf(str, "%stickle%s", a, b) == 2) tell_room(environment(this_object()), "The ghost says: It's only a flesh wound!!", ({this_object()})); +} diff --git a/lib/domains/Praxis/cemetery/mon/ghost9.c b/lib/domains/Praxis/cemetery/mon/ghost9.c new file mode 100644 index 0000000..d577ae1 --- /dev/null +++ b/lib/domains/Praxis/cemetery/mon/ghost9.c @@ -0,0 +1,31 @@ +inherit "/lib/npc"; + +void create() { + ::create(); + SetKeyName("test ghost"); + SetId( ({ "test ghost" }) ); + SetLevel(1); + SetShort( "test ghost"); + SetLong( "Yup, it's a ghost."); + SetRace( "wraith"); + SetGender("neuter"); + SetAggressive( 0); + SetMorality(200); + SetMaxHealthPoints(25); + SetHealthPoints(25); + SetRace("human"); +} + +void catch_tell(string str) { + object ob; + string a, b, c; + + if(sscanf(str, "%s gives %s to you", a, b) == 2) { + ob = present( lower_case(a), environment(this_object())); + if(ob) { + tell_object(ob, "The ghost thanks you for your generosity."); + tell_room(environment(this_object()), "The ghost thanks "+a+" for "+ob->query_possessive()+" generosity.", ({this_object(), ob})); + } + } + if(sscanf(str, "%ssmiles%s", a, b) == 2) tell_room(environment(this_object()), "The little ghost asks plaintively: Why don't gods like me?", ({this_object()})); +} diff --git a/lib/domains/Praxis/cemetery/mon/ghosta.c b/lib/domains/Praxis/cemetery/mon/ghosta.c new file mode 100644 index 0000000..5c7a9b1 --- /dev/null +++ b/lib/domains/Praxis/cemetery/mon/ghosta.c @@ -0,0 +1,38 @@ +inherit "/lib/npc"; + +object mony; + +void create() { + ::create(); + SetKeyName("Melissa's Ghost"); + SetId( ({ "ghost","melissa","Melissa","Melissa's Ghost" }) ); + SetShort( "Melissa's ghost"); + SetAggressive( 0); + SetLevel(1); + SetLong( "A misty figure in a long flowing white gown. " + "She is wringing her hands and weeping."); + SetMorality(-200); + SetRace( "wraith"); + SetGender("female"); + SetCurrency("gold",random(50)); + SetMaxHealthPoints(25); + SetHealthPoints(25); + SetRace("human"); + mony = new("/lib/pile"); + mony->SetCurrency("silver",500); + mony->move(this_object()); +} + +void catch_tell(string str) { + object ob; + string a, b, c; + + if(sscanf(str, "%s gives %s to you", a, b) == 2) { + ob = present( lower_case(a), environment(this_object())); + if(ob) { + tell_object(ob, "The ghost thanks you for your generosity."); + tell_room(environment(this_object()), "The ghost thanks "+a+" for "+ob->query_possessive()+" generosity.", ({this_object(), ob})); + } + } + if(sscanf(str, "%ssmiles%s", a, b) == 2) tell_room(environment(this_object()), "The little ghost weeps piteously.", ({this_object()})); +} diff --git a/lib/domains/Praxis/chapel.c b/lib/domains/Praxis/chapel.c new file mode 100644 index 0000000..8b58f7b --- /dev/null +++ b/lib/domains/Praxis/chapel.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperties( ([ "light" : 2, "indoors" : 1, "no attack" : 1, "no steal" : 1 ]) ); + SetExits( + (["south" : "/domains/Praxis/monastery"]) ); + SetShort("The chapel"); + SetLong( + sprintf("The %s chapel is solemn and ancient with stained glass " + "windows and dark oak pews. Most wedding ceremonies " + "are performed here. Type <help marriage> for " + "information on weddings.", mud_name()) ); + SetItems( + (["pews" : "Ancient oak seats, darkened by eons of " + "bottoms resting on them.", + "windows" : "The windows show highlights of " + "mud history, many of them gorey.", + "ceremony" : "The ceremony is only visible when you " + "scroll back."]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/cleric_hall.c b/lib/domains/Praxis/cleric_hall.c new file mode 100644 index 0000000..3ed3b67 --- /dev/null +++ b/lib/domains/Praxis/cleric_hall.c @@ -0,0 +1,260 @@ +#include <lib.h> +#include ROOMS_H +#include <council.h> +#include <daemons.h> + +inherit LIB_ROOM; + +string get_new_title(object tp); +string get_male(int lev); +string get_female(int lev); +string previous_title(object tp); +int get_cost(string which, int lev); + +int CanReceive(object ob) { + if(!VOTING_D->is_time_to_vote()) + return ::CanReceive(ob); + if(creatorp(this_player()) || this_player()->query_level() < 2) + return ::CanReceive(ob); + if(VOTING_D->query_voted(this_player()->query_name(), + this_player()->query_class())) + return ::CanReceive(ob); + else { + message("my_action", "You have not yet voted for you class leader. Please do so now.", this_player()); + call_out("move_me", 5, this_player()); + } + return ::CanReceive(ob); +} + +void move_me(object who) { + who->eventMoveLiving("/domains/Praxis/"+who->query_class()+"_vote"); + return; +} + +void create() { + object ob; + + ::create(); + SetProperties( ([ "no attack":1, "light" : 2, "indoors" : 1]) ); + SetShort( "the inner sanctum of the clerics"); + SetLong( + "Welcome to the inner sanctum of the clerics!\n" + "Clerics come to this room to contemplate their deities. " + "The room is very sparse. The floor is made from oak, and chairs are set " + "up all around. Very simple, and unpretensious. A large breeze fills " + "the room, making it very light and airy. The available options for " + "a cleric are <cost>, <advance>, <list (number)>, <improve stat>, " + "<train skill amount>, and <roll stats>. Through the passage guarded " + "by a shimmering %^BLUE%^blue%^RESET%^ light is the church."); + SetExits( + (["south" : "/domains/Praxis/cleric_join", + "down" : "/domains/Praxis/crypt.c", + "council" : "/domains/Praxis/council_hall", + "east" : "/domains/Praxis/cleric_vote"]) ); + + ob = new(LIB_BOARD); + ob->SetKeyName("board"); + ob->SetId( ({ "board", "reality board" }) ); + ob->set_board_id("cleric_board"); + ob->set_max_posts(25); + ob->set_edit_ok(CLERIC_COUNCIL); + ob->move("/domains/Praxis/cleric_hall"); + ob->SetShort( "the Cleric's Board of Healing"); + ob->SetLong( "Clerics post tales of their experiences of " + "this reality here.\n"); +} + +void init() { + ::init(); + add_action("cost","cost"); + add_action("roll","roll"); + add_action("train", "train"); + add_action("improve", "improve"); + add_action("advance","advance"); + add_action("list","list"); +} + +int roll(string str) { + if(str != "stats") return 0; + //ROOM_SETTER->do_rolls(); + return 1; +} + +string get_new_title(object tp) +{ + int lev; + string gen, title; + + lev = this_player()->query_level(); + gen = this_player()->query_gender(); + if(this_player()->query_guild()) { + if(present(tp->query_guild()+"_ob", tp)) { + if(lev > 19) title = "High mortal"; + else title = present(tp->query_guild()+"_ob", tp)->query_title(tp); + title += " $N"; + } + else { + if(lev > 19) title = "High mortal $N"; + else title = "$N"; + } + } + else { + if(lev > 20) title = "High mortal $N"; + else title = "$N"; + } + if(lev > 20) title += previous_title(tp); + else if(gen == "male") title += " "+get_male(lev); + else title += " "+get_female(lev); + return title; +} + +string get_male(int lev) { + switch(lev) { + case 1: return "the novice cleric"; break; + case 2: return "the new student of nature"; break; + case 3: return "the student of nature"; break; + case 4: return "the advanced student of nature"; break; + case 5: return "the minor believer in natural unity"; break; + case 6: return "the believer in natural unity"; break; + case 7: return "the unity of nature"; break; + case 8: return "the minor low priest"; break; + case 9: return "the minor priest"; break; + case 10: return "the high minor priest"; break; + case 11: return "the low cleric"; break; + case 12: return "the junior cleric"; break; + case 13: return "the cleric"; break; + case 14: return "the cleric"; break; + case 15: return "the high cleric"; break; + case 16: return "the low master priest"; break; + case 17: return "the master priest"; break; + case 18: return "the high master priest"; break; + case 19: return "the grand high priest"; break; + case 20: return "the new high mortal cleric"; break; + default: return ""; break; + } +} + +string get_female(int lev) { + switch(lev) { + case 8: return "the minor low priestess"; break; + case 9: return "the minor priestess"; break; + case 10: return "the high minor priestess"; break; + case 16: return "the low master priestess"; break; + case 17: return "the master priestess"; break; + case 18: return "the high master priestess"; break; + case 19: return "the grand high priestess"; break; + default: return get_male(lev); break; + } +} + +int advance() { return ADVANCE_D->advance(); } + +int train(string str) { + string which, which_tmp; + int amount; + + if(!str) { + notify_fail("Train what?\n"); + return 0; + } + if(sscanf(str, "%s %s %d", which, which_tmp, amount) == 3) which = which + " "+which_tmp; + else if(sscanf(str, "%s %d", which, amount) !=2) { + notify_fail("Correct syntax: <train skill amount>\n"); + return 0; + } + which = lower_case(which); + if(!this_player()->skill_exists(which)) { + notify_fail("No such skill.\n"); + return 0; + } + return ADVANCE_D->train_player(this_player(), which, amount); +} + +int improve(string str) { + string *stats; + int stat_cost; + + stats = ({ "strength", "intelligence", "wisdom", "dexterity", "constitution", "charisma" }); + str = lower_case(str); + if(member_array(str, stats) == -1) { + notify_fail("You have no such stat.\n"); + return 0; + } + stat_cost = get_cost(str, this_player()->query_base_stats(str)); + if( this_player()->query_exp()-stat_cost < ADVANCE_D->get_exp( this_player()->query_level() ) ) { + notify_fail("You are not experienced enough to improve yourself in that way.\n"); + return 0; + } + this_player()->SetStat(str, this_player()->query_base_stats(str) + 1); + this_player()->add_exp(-stat_cost); + message("Nmy_action", "You feel much ", this_player()); + message("Nother_action", this_player()->query_cap_name()+ + " looks much ", this_object(), ({ this_player() }) ); + if(str == "strength") tell_room(this_object(), "stronger."); + else if(str == "intelligence") tell_room(this_object(), "more intelligent."); + else if(str == "wisdom") tell_room(this_object(), "wiser."); + else if(str == "dexterity") tell_room(this_object(), "more nimble."); + else if(str == "constitution") tell_room(this_object(), "sturdier."); + else tell_room(this_object(), "more attractive."); + return 1; +} + +int get_cost(string stat, int lev) { + switch(stat) { + case "intelligence": return ADVANCE_D->get_stat_cost(1, lev); break; + case "wisdom": return ADVANCE_D->get_stat_cost(1, lev); break; + case "strength": return ADVANCE_D->get_stat_cost(1, lev); break; + default: return ADVANCE_D->get_stat_cost(2, lev); break; + } +} + +int cost(string str) { + int bing; + + write("Costs for advancement, training, and improvement:\n"); + bing = ADVANCE_D->get_exp( this_player()->query_level() + 1 ); + if(bing < 1) write("level:\t\tIt will cost you nothing to advance."); + else write("level:\t\t"+bing+"\n"); + write("skills: You train by spending the amount of experience you + desire."); + write("strength:\t\t" + get_cost("strength", + this_player()->query_base_stats("strength")) + + "\t\tconstitution:\t\t" + get_cost("constitution", + this_player()->query_base_stats("constitution")) ); + write("intelligence:\t\t" + get_cost("intelligence", + this_player()->query_base_stats("intelligence")) + + "\t\tdexterity:\t\t" + get_cost("dexterity", + this_player()->query_base_stats("dexterity")) ); + write("wisdom:\t\t" + get_cost("wisdom", + this_player()->query_base_stats("wisdom")) + + "\t\tcharisma:\t\t" + get_cost("charisma", + this_player()->query_base_stats("charisma")) ); + return 1; +} + +string previous_title(object tp) { + string pre, post, str; + + str = tp->getenv("TITLE"); + sscanf(str, "%s $N %s", pre, post); + return post; +} + +int list(string str) { + int x; + + if(!str) "/domains/Praxis/quest_room"->list_quests(this_player(), 0); + else { + if(sscanf(str, "%d", x) != 1) { + notify_fail("You must give the number of the quest you want listed.\n"); + return 0; + } + if(x<1) { + notify_fail("No such quest.\n"); + return 0; + } + "/domains/Praxis/quest_room"->list_quests(this_player(), x); + } + return 1; +} + diff --git a/lib/domains/Praxis/cleric_join.c b/lib/domains/Praxis/cleric_join.c new file mode 100644 index 0000000..d465614 --- /dev/null +++ b/lib/domains/Praxis/cleric_join.c @@ -0,0 +1,84 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void init() { + ::init(); + add_action("become", "become"); + add_action("go_north","go"); + add_action("preview","preview"); +} + +void create() { + ::create(); + SetProperties( (["light": 2, "indoors" : 1, "no castle" : 1]) ); + SetShort( "the clerics' church of Praxis"); + SetLong( + "You are in the small cleric's church of Praxis. It is a very " + "simple, yet elegant building. The lack of adornment is made up " + "for in the strong faith you can feel radiating from this little " + "church. People of all faiths come here for prayer, or solitude. " + "The clerics initiate young adventurers here into the class of " + "clerics. <preview> will tell you about becoming a cleric. " + "There is a passage north."); + SetItems( + (["church" : "It holds a small chapel for wedding ceremonies " + "west, and there is an inner sanctum for clerics north", + "chapel" : "The clerics of the church perform wedding " + "ceremonies there.", + "light" : "A %^BLUE%^blue%^RESET%^ light protects this place.", + "passage" : "It leads north into the cleric's inner sanctum."]) ); + SetExits( + (["east" : "/domains/Praxis/n_centre1"]) ); +} + +int preview() { + if(this_player()->query_class() != "explorer") { + message("info", "This is not for you.", this_player()); + return 1; + } + message("info", this_player()->query_cap_name()+" seeks to learn about clerics.", this_object(), ({ this_player() })); + message("info", "Welcome, explorer!", this_player()); + message("info", "Clerics are deeply religious people of greatly varied " + "beliefs, yet united in their belief in the sanctity of the natural world. Their " + "ability to get in touch with the unity of nature through prayer " + "gives them great healing powers as well as powers of protection. " + "Destruction is the most horrible of evils to them, and they will " + "lose the powers they have through prayer if they become too " + "destructive. Type <become cleric> to become a cleric.", this_player()); + return 1; +} + +int become(string str) { + if(!str) { + notify_fail("Become what?\n"); + return 0; + } + if(str != "cleric") { + notify_fail("You cannot become that here.\n"); + return 0; + } + if(this_player()->query_class() != "explorer") { + write("You are much too old to start learning our ways now!"); + return 1; + } + write("The High Priestess of Clerics initiates you into the class of clerics."); + say(this_player()->query_cap_name()+" becomes a cleric.", this_player()); + this_player()->SetClass("cleric"); + this_player()->setenv("TITLE", "$N the novice cleric"); + this_player()->init_skills("cleric"); + this_player()->setenv("start", "/domains/Praxis/cleric_hall"); + return 1; +} + +int go_north(string str) { + if(str !="north") return notify_fail("What?\n"); + if(this_player()->query_class() != "cleric") { + write("You cannot penetrate the force field that blocks the passage."); + say(this_player()->query_cap_name()+" tries to get into the " + "church's inner sanctum, but fails.", this_player()); + return 1; + } + this_player()->eventMoveLiving("/domains/Praxis/cleric_hall", "through the light in the passage"); + return 1; +} diff --git a/lib/domains/Praxis/cleric_vote.c b/lib/domains/Praxis/cleric_vote.c new file mode 100644 index 0000000..fffa814 --- /dev/null +++ b/lib/domains/Praxis/cleric_vote.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include <voting.h> +#include <daemons.h> + +inherit "/domains/town/room/voters"; + +void create() { + ::create(); + SetProperty("light", 1); + SetProperty("no castle", 1); + SetProperty("indoors", 1); + SetShort( "Voting hall of the clerics"); + SetLong( (: this_object(), "new_long" :)); + SetItems( + (["list" : "During election time, it lists all candidates."]) ); + SetExits( + (["west" : "/domains/Praxis/cleric_hall"]) ); +} + +string new_long() { + if(VOTING_D->election_day()) + return "This is the room where Clerics can put in their bid for office. " + "If you wish to run for office, just type in the command " + "'enter' and you will be added to the list. A list of candidates " + "is posted on the wall. Type 'list candidates' to see the list."; + else return "This is the voting chamber of the Hall of Clerics. " + "Clerics will gather here for the next election: "+VOTING_D->query_vote_date()+"."; +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/commands b/lib/domains/Praxis/commands new file mode 100644 index 0000000..5cd23d7 --- /dev/null +++ b/lib/domains/Praxis/commands @@ -0,0 +1,24 @@ +Syntax: propose <title> +Effect: a councilor uses this command to propose new laws. The title of +the new law is <title> and it puts you into a text editor to enter the +actual proposal. + +Syntax: repeal <title> +Effect: If a law already exists with the title <title> a councilor can use +this command to put to the vote that the law be repealed. + +Syntax: law <title> +Effect: Lists the text of law <title> +Syntax: law +Effect: Lists the titles of all laws + +Syntax: read <title> +Effect: Lists the text of proposal <title> +Syntax: read +Effect: Lists the titles of all proposals + +Syntax: cast <vote> on <title> +Effect: <vote> may be: + aye - vote that <title> be law (either introduced or not repealed) + nay - vote that <title> not be law (either be repealed or not be introduced) + abs - abstain diff --git a/lib/domains/Praxis/council.c b/lib/domains/Praxis/council.c new file mode 100644 index 0000000..ef5ef6e --- /dev/null +++ b/lib/domains/Praxis/council.c @@ -0,0 +1,349 @@ +/* +// File : /domains/Praxis/council.c +// Comment : Town Council Chambers +// 94-07-02 : Pallando @ Nightmare wrote it +// 94-07-06 : Manny @ Nightmare added descriptions +// 94-08-18 : Forlock @ Nightmare added descriptions of plaque & law book + */ +#include <lib.h> +#include <dirs.h> +#include <objects.h> +#include <daemons.h> + +#define TOWN_HALL "/domains/Praxis/town_hall" +#define HELP_FILE "/domains/Praxis/commands" +#define TMP_FILE DIR_TMP + "/" + (this_player()->query_name()) + ".proposal" +#define QUORUM 5 +#define PASSES 5 + +inherit LIB_ROOM; + +mapping policies = ([]); + +void create() +{ + ::create(); + enable_commands(); // Used to echo tells to the Town Hall + SetProperties( ([ + "mountable" : 1, + "indoors" : 1, + "light" : 2, + "no castle" : 1, + "no teleport" : 1, + "no bump" : 1, + "no attack" : 1, + "no steal" : 1, + "no magic" : 1, + ]) ); + SetShort( "The Chambers of the High Council" ); + SetLong( + "The lights are darkened in this room, a set of 12 candles set along a " + "long, narrow table are the only light. The table is constructed of the " + "purest black obsidian, and is surrounded at all sides by wooden chairs, " + "each covered in a bright pattern of rubies. On the walls of the room hang " + "the flags of each of the classes of Nightmare, each created by the best " + "artists in the land. The ceiling is covered in 4 ornate patterns, each " + "a picture of one of the Head Archwizards of the land. The pictures give " + "the appearance of watching all that occurs within this chamber. " + "Sitting on a pedestal made completely of platinum is the Book of Law. " + "A plaque is attached to the west wall. " + ); + SetExits( ([ + "down" : "/domains/Praxis/town_hall", + ]) ); + SetItems( ([ + "view" : "A magnificent panorama of all Praxis.", + ({ "candles", "candle" }) : "Tall, thin white candles on a "+ + "long, narrow table.", + "table" : "A brightly polished table of deep black obsidian", + "obsidian" : "The obsidian is of the purest in the land.", + ({ "chair", "chairs" }) : "Each of the chairs have a unique pattern of "+ + "rubies engrained within the body of the chair.", + "rubies" : "Large rubies of the rarest kind.", + "flags" : "6 flags, each representing the individual classes " + "of the land.", + "ceiling" : "A vast mural of the Four greatest in " + "all the land, Forlock, Descartes, Lassondra, " + "and Shadowwolf.", + "plaque" : "A discreet piece of granite with finly etched words.", + "book" : "The Book of Law. Its cover is made of pure solid gold " + "and the pages of the finest leather. Inside, one can find " + "details of the Laws of the Land.", + "forlock" : "The Great Enforcer, donning a great black robe " + "lined with a deep red sheath. The deep stare of " + "Forlock fills you with all that is good and just.", + "descartes" : "Descartes of Borg, in his most noble position " + "upon a great white horse, is the embodiment of " + "great wisdom and knowlege.", + "lassondra" : "Long, black wavy hair drape down upon a " + "great green cloak upon her broad sholders. " + "The warm smile and loving eyes depict equality " + "and fairness for all.", + "shadowwolf" : "Donning a long hooded robe, Shadowwolf is " + "perhaps the most mysterious of the four. " + "Shadowwolf's eyes faintly pierce the darkness " + "that surrounds him, seemingly staring " + "directly at you." + ]) ); +} + +void init() +{ + ::init(); + add_action( "cmd_propose", "propose" ); + add_action( "cmd_repeal", "repeal" ); + add_action( "cmd_cast", "cast" ); + add_action( "cmd_read", "read" ); + add_action( "cmd_law", "law" ); +} + +int quorum() +{ + object *voters; + + voters = all_inventory( this_object() ); + voters = filter_array( voters, "leaderp", find_object( OB_SIMUL_EFUN ) ); + return sizeof( voters ); +} + +int votes_needed( string title ) +{ + return PASSES + sizeof( policies[title]["Nay"] ) - + sizeof( policies[title]["Aye"] ); +} + +int vetos_needed( string title ) +{ + return PASSES + sizeof( policies[title]["Aye"] ) - + sizeof( policies[title]["Nay"] ); +} + +varargs void display_policy( mapping policy, int as_law ) +{ + int then; + + if( as_law ) + { + then = policy["Time"]; + printf( "As of %s, %d %s, %d NM; at the urging of %s\n\n\t\t\%s\n\n%s", + day( then ), date( then ), month( then ), year( then ), + capitalize( policy["Proposer"] ), policy["Title"], policy["Text"] ); + return; + } + printf( + "Title: %s\nProposer: %s\n\n%s", + policy["Title"], + capitalize( policy["Proposer"] ), + policy["Text"], + ); + if( sizeof( policy["Aye"] ) ) + write( wrap( "In favour: " + implode( policy["Aye"], ", " ) ) ); + if( sizeof( policy["Nay"] ) ) + write( wrap( "Against: " + implode( policy["Nay"], ", " ) ) ); + if( sizeof( policy["Abs"] ) ) + write( wrap( "Abstentions: " + implode( policy["Abs"], ", " ) ) ); +} + +int cmd_law( string arg ) +{ + mapping policy; + + if( arg ) + { + if( undefinedp( policy = POLITICS_D-> query_policy( arg ) ) ) + write( "There is no law: " + arg + "\n" ); + else + display_policy( policy, 1 ); + } else { + printf( "The book of law contains the following:\n %s\n", + wrap( implode( sort_array( keys( + POLITICS_D-> query_policies() ), 1 ), "\n " ) ) ); + } + return 1; +} + +int cmd_read( string arg ) +{ + mapping policy; + + if( arg ) + { + if( arg == "book" || arg == "law" ) + write( "Use the \"law\" command.\n" ); + else if( arg == "plaque" ) + write( read_file( HELP_FILE ) ); + else if( undefinedp( policy = policies[arg] ) ) + write( "There is no proposal: " + arg + "\n" ); + else + display_policy( policy ); + } else { + if( !sizeof( policies ) ) + write( "There are no proposals waiting to be passed.\n" ); + else + write( "The following proposals are waiting to be passed:\n" + + wrap( implode( keys( policies ), ", " ) ) ); + } + return 1; +} + +int cmd_propose( string title ) +{ + if( !title ) return notify_fail( "Syntax: propose <title>\n" ); + title = lower_case( title ); + if( policies[title] || POLITICS_D-> query_policy( title ) ) + return notify_fail( "That already exists.\n" ); + if( ( quorum() < QUORUM ) && !archp( this_player() ) ) + return notify_fail( "There are not " + QUORUM + " voters present.\n" ); + write( "Enter your proposal:\n" ); + this_player()-> edit( TMP_FILE, + (: "callback_propose" :), + (: "abort_propose" :), + title, + ); + return 1; +} + +void abort_propose( string title ) { write( "Aborting proposal.\n" ); } + +void callback_propose( string title ) +{ + string proposal; + + proposal = read_file( TMP_FILE ); + rm( TMP_FILE ); + if( !proposal ) + { + write( "Aborting proposal.\n" ); + return; + } + + policies[title] = ([ + "Title" : title, + "Proposer" : this_player()-> query_name(), + "Time" : time(), + "Text" : proposal, + "Voted" : ([]), + "Aye" : ({}), + "Nay" : ({}), + "Abs" : ({}), + ]); + display_policy( policies[title] ); + write( "You have 1/2 hr to get " + votes_needed( title ) + "\n" ); + call_out( "last_warning", 1500, title ); +} + +void last_warning( string title ) +{ + object proposer; + + if( !policies[title] ) return; + call_out( "delete_proposal", 300, title ); + if( !proposer = find_player( policies[title]["Proposer"] ) ) return; + tell_object( proposer, + "***** LAST WARNING *****\n"+ + "Proposal " + title + " will be deleted in 5 minutes\nunless "+ + "you can find " + votes_needed( title ) + " votes before then.\n" ); +} + +void delete_proposal( string title ) +{ + map_delete( policies, title ); +} + +int cmd_repeal( string title ) +{ + mapping policy; + + if( !title ) return notify_fail( "Syntax: repeal <title>\n" ); + title = lower_case( title ); + if( !policy = POLITICS_D-> query_policy( title ) ) + return notify_fail( "There is no law: " + title + ".\n" ); + if( ( quorum() < QUORUM ) && !archp( this_player() ) ) + return notify_fail( "There are not " + QUORUM + " voters present.\n" ); + policy["Proposer"] = this_player()-> query_name(); + policy["Repeal"] = 1; + policies[title] = policy; + call_out( "delete_proposal", 1800, title ); + write( "You have 1/2 hour to get the votes needed to repeal " + + title + ".\n" ); + return 1; +} + +int cmd_cast( string arg ) +{ + string vote, title, name; + + if( !arg || + ( ( 2 != sscanf( arg, "%s on %s", vote, title ) ) && + ( 2 != sscanf( arg, "%s %s", vote, title ) ) ) ) + return notify_fail( "Syntax: cast <vote> on <title>\n" ); + if( !policies[title] ) + return notify_fail( "There is no proposal: " + title + ".\n" ); + name = this_player()-> query_name(); + if( policies[title]["Voted"][name] ) + policies[title][policies[title]["Voted"][name]] -= ({ name }); + vote = lower_case( vote[0..2] ); + switch( vote ) + { + case "aye": + policies[title]["Aye"] += ({ name }); break; + case "nay": + policies[title]["Nay"] += ({ name }); break; + case "abs": + policies[title]["Abs"] += ({ name }); break; + default: + return notify_fail( "You vote must be 'aye', 'nay' or 'abs'.\n" ); + } + policies[title]["Voted"][name] = capitalize( vote ); + if( policies[title]["Repeal"] ) + { + if( vetos_needed( title ) < 1 ) + { + say( title + " is no longer law.\n" ); + POLITICS_D-> repeal_policy( title ); + delete_proposal( title ); + return 1; + } + } + else if( votes_needed( title ) < 1 ) + { + say( "Proposal: " + title + " is writ large in the book of law.\n" ); + POLITICS_D-> set_policy( title, policies[title] ); + delete_proposal( title ); + return 1; + } + write( "Ok.\n" ); + return 1; +} + +void receive_message( string msg_class, string msg ) +{ + /* + write( "class = " + msg_class + "\n" ); + */ + message( msg_class, msg, all_inventory( this_object() ), ({ this_player() }) ); + TOWN_HALL-> receive_message( msg_class, msg ); +} + +// Wizard test functions + +mixed query_policies() { return policies; } + +void alter_proposal( string title, string field, mixed value ) +{ + policies[title][field] = value; +} + +void make_law( string title ) +{ + POLITICS_D-> set_policy( title, policies[title] ); + delete_proposal( title ); +} + +void repeal_law( string title ) +{ + POLITICS_D-> repeal_policy( title ); + delete_proposal( title ); +} + +/* EOF */ diff --git a/lib/domains/Praxis/council_hall.c b/lib/domains/Praxis/council_hall.c new file mode 100644 index 0000000..3479b4c --- /dev/null +++ b/lib/domains/Praxis/council_hall.c @@ -0,0 +1,71 @@ +#include <lib.h> +#include ROOMS_H +#include <council.h> +#include <daemons.h> + +inherit LIB_ROOM; + +int CanReceive(object ob) { + if((!previous_object()->is_player()) || + creatorp(previous_object()) || + (-1!=member_array(previous_object()->query_name(), COUNCIL))) + return ::CanReceive(ob); + message("my_action", "You are not allowed in the council room. If you are "+ + "a council member, try contacting Nialson, advocate, and law in "+ + "that order.", previous_object()); + return 0; +} + +void create() { + object ob; + + ::create(); + SetProperties( (["light" : 2, + "indoors" : 1, + "no attack" : 1, + "no steal" : 1, + "no magic" : 1, + "no teleport" : 1, + "no castle" : 1]) ); + SetShort( "The private meeting hall of the council"); + SetLong( "Welcome to the cavern beneath the square. This is the meeting "+ + "hall of the councils of the classes. " ); + SetExits( (["leave" : "/domains/Praxis/square"]) ); + + ob = new("/lib/bboard"); + ob->SetKeyName("board"); + ob->SetId( ({ "board", "pipe dream board", "bulletin board"}) ); + ob->set_board_id("council_board"); + ob->set_max_posts(30); + ob->set_edit_ok( ({"nialson"}) ); + ob->move(this_object()); + ob->SetShort( "the pipe dream board of class war avoidance"); + ob->SetLong( "This is a collection of ill-conceived threats, and useful "+ + "suggestions intended to increase the orderly flow of "+ + "information and to decrease the level of inter-player "+ + "tension (at least for the immortals)."); + SetSearch("default", "Why, the remains of Archduke Ferdinand are "+ + "concealed here! So that's what happenned to him."); +} + +void init() { + ::init(); + add_action("leave","leave"); +} + +int leave() { + string verb; + string *tmpstrs; + int val; + + if( this_player()->query_disable() && + sizeof(this_player()->query_attackers()) ) { + write("You can not exit while doing something else."); + return 1; } + if (creatorp(this_player())) + this_player()->eventMoveLiving("/domains/Praxis/adv_inner", "leave"); + else + this_player()->eventMoveLiving("/domains/Praxis/"+this_player()->query_class()+ + "_hall", "leave"); + return 1; +} diff --git a/lib/domains/Praxis/council_vote.c b/lib/domains/Praxis/council_vote.c new file mode 100644 index 0000000..13784b2 --- /dev/null +++ b/lib/domains/Praxis/council_vote.c @@ -0,0 +1,13 @@ +// /domains/Praxis/council_vote.c +// Nightmare IV Mudlib +// Room for players to vote for council members. +// Kalinash@Nightmare Aug 17, 1994 + +#include <lib.h> +#include <daemons.h> + +inherit LIB_ROOM; + +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/court_room.c b/lib/domains/Praxis/court_room.c new file mode 100644 index 0000000..f854fa5 --- /dev/null +++ b/lib/domains/Praxis/court_room.c @@ -0,0 +1,191 @@ +/* +// File : /domains/Praxis/court_room.c +// Comment : The Court where High Justice is served. +// 94-07-02 : Pallando @ Nightmare wrote it + */ +#include <lib.h> +#include ROOMS_H +#include <council.h> + +#define COUNCIL_CHAMBER "/domains/Praxis/council" + +inherit LIB_ROOM; + +object defendant; + +void create() +{ + ::create(); + SetProperties( ([ + "indoors" : 1, + "light" : 2, + "no castle" : 1, + "no teleport" : 1, + "no bump" : 1, + "no attack" : 1, + "no steal" : 1, + "no magic" : 1, + ]) ); + SetShort( "the court of high justice" ); + // Thank you, whoever added this. However, if you have time, I have + // a few suggestions: + // We want the justice system to be intimidating. Imagine being a + // short dwarf. You have been lead up from a dank stone dungeon. + // you peer up at the dark oak furnishings (the dock has omnious + // scratches left on by the last victim dragged away for execution) + // the flickering torches leave frightning looming dark heights to + // the room, while leaving the dock harshly lit. The judges bench + // it tall, imposing, richly ornamented in legal symbols (an iron + // glove enclosing an iron fist). UNderneath it is a supply of gin. + // The place smells slightly of chalk dust used for lawyer's wigs, + // and the perspiration of bored and jeering juiries. The stone + // fllor flagstones boom ominously every time the usher bangs his + // staff to summon the next witness. A hanging on the wall, + // embroidered by the housewifes union depicts the possible sentances + // in gory detail. Occasional screams can be heard from the prison + // or execution square. + // + // You could also use interactive SetItems to show if the dock and + // bench are currently occupied. + SetLong( + "The sheer size of this room dazzles you. The ceiling cannot be viewed\n"+ + "from where you stand. At one end of the room is a huge chair, in front\n"+ + "of which is a desk. Both the chair and the desk are made from the finest\n"+ + "wood in the land. Next to the desk lies a second chair, where witnesses\n"+ + "sit. On the other side of the room are rows of chairs, and an aisle\n"+ + "through the center. Two doors lead the way out of this room, north\n"+ + "is the Town Hall, east is the sheriff's office.\n" + ); + SetExits( ([ + "north" : "/domains/Praxis/town_hall", + "east" : "/domains/Praxis/sheriff", + ]) ); + SetItems( ([ + "view" : "A magnificent panorama of all Praxis.", + "gavel" : "A wooden hammer-like object, used for pounding.", + "chair" : "Made out of the finest wood.", + "desk" : "A large desk made out of the finest wood.", + ({ "door", "doors" }) : + "Large wooden doors leading out of the room.", + "ceiling" : "The ceiling extends out of view.", + "room" : "A very large, spacious room with a " + "rather formal aura.", + "office" : "The office of the Sheriff of Praxis.", + "wood" : "The highest quality wood, made exclusivly " + "from the trees of the elven forest.", + ]) ); +} + +varargs int justicep( mixed arg ) +{ + if( !arg ) arg = this_player(); + if( objectp( arg ) ) arg = geteuid( arg ); + return -1 != member_array( arg, JUSTICES) || member_array( arg, POLICECOM ); +} + +int release_objects( object ob ) +{ + return ob != defendant; +} + +void init() +{ + add_action( "cmd_law", "law" ); + ::init(); + if( !creatorp( this_player() ) && !justicep( this_player() ) ) + return; + add_action( "cmd_summon", "summon" ); + add_action( "cmd_verdict", "verdict" ); + add_action( "cmd_sentence", "sentence" ); +} + +int cmd_law( string title ) +{ + return COUNCIL_CHAMBER-> cmd_law( title ); +} + + +int cmd_summon( string arg ) +{ + object victim; + + if( !arg ) + return notify_fail( "Syntax: summon <player name>\n" ); + //call_other( ROOM_SHERIFF, "sighs_for_deleted_simul_efun_f.o.o.l." ); + if( victim = present( arg, this_object() ) ) + { + if( victim == defendant ) + return notify_fail( arg + " is already in the dock.\n" ); + } + //else if( victim = present( arg, find_object( ROOM_SHERIFF ) ) ) { + // ROOM_SHERIFF-> remove_prisoner( victim ); + // victim-> eventMove( this_object() ); + // } + else notify_fail( "The sheriffs do not have " + arg + ".\n" ); + if( defendant ) + tell_object( defendant, "You trial is suspended. You may leave.\n" ); + defendant = victim; + say( defendant-> query_cap_name() + " is summoned to the dock.\n" ); + return 1; +} + +int cmd_verdict( string arg ) +{ + if( !arg ) + return notify_fail( "Syntax: verdict guilty|innocent|none\n" ); + if( !defendant ) + return notify_fail( "You must summon a defendant first.\n" ); + switch( arg ) + { + case "innocent": + case "free": + case "insufficient evidence": + say( "VERDICT: the defendant is found to be Not Guilty.\n" ); + defendant-> set_outlaw( 0 ); + defendant = 0; + break; + case "guilty": + say( "VERDICT: the defendant is Guilty.\n" ); + defendant-> set_outlaw( 1 ); + break; + case "none": + default: + say( "VERDICT: no change in the defendant's status\n" ); + defendant = 0; + break; + } + return 1; +} + +int cmd_sentence( string arg ) +{ + mapping executions; + object criminal; + + //executions = ROOM_SHERIFF-> valid_execution(); + executions = ([]); + if( !arg || undefinedp( executions[arg] ) ) + return notify_fail( + "Syntax: sentence <punishment>\nCurrent options:\n "+ + implode( keys( executions ), "\n " ) + "\n" ); + if( !defendant ) + return notify_fail( "You must summon a defendant first.\n" ); + say( sprintf( + "%s says: %s, you have been found guilty by due process\n" + " and now justice must be seen to be done. It is the will of law that\n"+ + " you shall now be taken from here unto the place of execution,\n"+ + " where you shall suffer the torments of %s until dead.\n", + this_player()-> query_cap_name(), + defendant-> query_cap_name(), + arg ) ); + + criminal = defendant; + defendant = 0; + //ROOM_SHERIFF-> add_prisoner( criminal ); + //ROOM_SHERIFF-> execute( criminal, arg ); + + return 1; +} + + +/* EOF */ diff --git a/lib/domains/Praxis/crypt.c b/lib/domains/Praxis/crypt.c new file mode 100644 index 0000000..b9be04c --- /dev/null +++ b/lib/domains/Praxis/crypt.c @@ -0,0 +1,253 @@ +#include <lib.h> + +#define PH "/realms/drakken/clerics/" +#define SAVE_FILE "/domains/Praxis/data/cleric_crypt" +#define WHAMMER "/realms/zaknaifen/weap/whammer" +#define PHYL "/realms/zaknaifen/armor/phylactery" + +inherit LIB_ROOM; + +int prayers,is_hammer,is_phyl; + +void create() { + ::create(); + prayers = 0; + is_hammer = 0; + is_phyl = 0; + RestoreObject(SAVE_FILE); // restore is_hammer and is_phyl + SetProperties(([ + "no attack": 1, + "no steal":1, + "no castle":1, + "holy ground":1, + "light" : 2, + "indoors" : 1, + ])); + SetShort("a small crypt"); + SetLong("The altar room is carved from the ancient gray stone that Praxis " + "rests upon. Burning candles along the walls cause the shadows to " + "dance around the room in a chaotic, yet enchanting dance. A large altar " + "rises from the floor in the center of the room and steps carved into the " + "stone lead upwards. "); + SetExits( ([ + "up" : "/domains/Praxis/cleric_hall" + ]) ); + SetItems(([ + "altar":(: this_object(), "exaaltar" :), + "scenes" : "You see Tempos wielding his mighty %^CYAN%^warhammer%^RESET%^ in a variety of battles " + "you recognize from your religious studies. ", + ({"stones","stone"}): + "The cold grey stone is creased and marked by the tools that were used " + "to carve this room beaneath the earth. ", + ({"shadows","shadow"}): + "The shadows dance enchantingly across the room in time to the music " + "of the flickering candle flames. ", + "steps" : "The steps are carved into the grey stone and are worn by the passage " + "of many feet over the ages. ", + ({"walls","wall"}): + "The walls are hewn roughly from the stone beneath Praxis and are lined " + "with many flickering candles. ", + ({"candle","candles"}): + "The candles rest in iron stands set along the wall and are made from " + "animal fat. The candle flames flicker to the tune of the wind, creating " + "the music by which the shadows cavort and dance. ", + "stands" : "The stands are made of %^BLACK%^%^BOLD%^black%^RESET%^ iron and are of plain construction. " + "Each stand holds between three to four lit candles. ", + ])); +} + +void exaaltar() { + string str; + + str = "The altar is made of ancient gray stone and is huge. There are scenes " + "of Tempos fighting mythical beasts carved all along the sides of the altar. " + "The top of the altar is flat and has the image of a hammer traced along " + "it in %^YELLOW%^gold%^RESET%^. "; + if (is_hammer) str += "The %^CYAN%^warhammer%^RESET%^ lieing upon it perfectly fits into the traces. "; + if (is_phyl) str += "A %^YELLOW%^golden%^RESET%^ phylactery partially covers the traces."; + write(str); +} + +void reset() +{ + ::reset(); + if (!present("box")) { + //new(PH "obj/donation")->move(this_object()); + } + prayers = 0; +} + +void init() +{ + ::init(); + add_action("pray_func","pray"); +} + +int pray_func(string str) { + object ob, ob2, *inv; + string limb; + int i,j; + + ob = this_player(); + inv = all_inventory(ob); + for (i=0; i<sizeof(inv); i++) { + if ((!str || strlen(str) == 0) && inv[i]->id("hammer of tempos") && is_hammer == 0) { + tell_room(this_object(),ob->query_cap_name()+" mutters a prayer in front of the altar. As "+ + nominative(ob)+" does so, the shape of a demigod appears on the altar. " + "You feel the might of the shadow and take part in his pleasure with the prayer as you notice that " + "the shadow is an incarnation of Tempos himself! " + "Tempos notices that "+ob->query_cap_name()+" carries his %^CYAN%^warhammer%^RESET%^ and takes it away! " + "As the shadow disappears the %^CYAN%^warhammer%^RESET%^ appears on the altar.",ob); + tell_object(ob,"You mutter a prayer in front of the altar. As you " + "do so, the shape of a demigod appears on the altar. " + "You feel the might of the shadow and repeat the prayer as you notice that " + "the shadow is an incarnation of Tempos himself! " + "Tempos notices that you carry his %^CYAN%^warhammer%^RESET%^ and takes it away! " + "As the shadow disappears the %^CYAN%^warhammer%^RESET%^ appears on the altar."); + is_hammer = 1; + SaveObject(SAVE_FILE); // save is_hammer + inv[i]->destruct(); + return 1; + } else if ((!str || strlen(str) == 0) && inv[i]->id("hammer of tempos") && is_hammer == 1) { + tell_room(this_object(),ob->query_cap_name()+" mutters a prayer in front of the altar. As "+ + nominative(ob)+" does so, the shape of a demigod appears on the altar. " + "You feel the might of the shadow and take part in his pleasure with the prayer as you notice that " + "the shadow is an incarnation of Tempos himself! " + "Tempos notices that "+ob->query_cap_name()+" carries his %^CYAN%^warhammer%^RESET%^ and takes it away!",ob); + tell_object(ob,"You mutter a prayer in front of the altar. As you " + "do so, the shape of a demigod appears on the altar. " + "You feel the might of the shadow and repeat the prayer as you notice that " + "the shadow is an incarnation of Tempos himself! " + "Tempos notices that you carry his %^CYAN%^warhammer%^RESET%^ and takes it away!"); + inv[i]->destruct(); + return 1; + } + if ((!str || strlen(str) == 0) && inv[i]->id("phylactery") && is_phyl == 0) { + tell_room(this_object(),ob->query_cap_name()+" mutters a prayer in front of the altar. As "+ + nominative(ob)+" does so, the shape of a demigod appears on the altar. " + "You feel the might of the shadow and take part in his pleasure with the prayer as you notice that " + "the shadow is an incarnation of Tempos himself! " + "Tempos notices that "+ob->query_cap_name()+" carries his phylactery and takes it away! " + "As the shadow disappears the phylactery appears on the altar.",ob); + tell_object(ob,"You mutter a prayer in front of the altar. As you " + "do so, the shape of a demigod appears on the altar. " + "You feel the might of the shadow and repeat the prayer as you notice that " + "the shadow is an incarnation of Tempos himself! " + "Tempos notices that you carry his phylactery and takes it away! " + "As the shadow disappears the phylactery appears on the altar."); + is_phyl = 1; + SaveObject(SAVE_FILE); // save is_phyl + inv[i]->destruct(); + return 1; + } else if ((!str || strlen(str) == 0) && inv[i]->id("phylactery") && is_phyl == 1) { + tell_room(this_object(),ob->query_cap_name()+" mutters a prayer in front of the altar. As "+ + nominative(ob)+" does so, the shape of a demigod appears on the altar. " + "You feel the might of the shadow and take part in his pleasure with the prayer as you notice that " + "the shadow is an incarnation of Tempos himself! " + "Tempos notices that "+ob->query_cap_name()+" carries his phylactery and takes it away! ",ob); + tell_object(ob,"You mutter a prayer in front of the altar. As you " + "do so, the shape of a demigod appears on the altar. " + "You feel the might of the shadow and repeat the prayer as you notice that " + "the shadow is an incarnation of Tempos himself! " + "Tempos notices that you carry his phylactery and takes it away!"); + inv[i]->destruct(); + return 1; + } + } + if (is_hammer) { + j = 0; + for (i=0; i<sizeof(inv); i++) + if (inv[i]->id("hammer of tempos")) { + j = 1; + break; + } + if (str == "for warhammer" && j == 0 && ob->query_alignment() >= 1000 && ob->query_level() > 5) { + ob2 = new(WHAMMER); + if (ob2) { + tell_room(this_object(),ob->query_cap_name()+" mutters a prayer in front of the altar. As "+ + nominative(ob)+" does so, the shape of a demigod appears on the altar. " + "You feel the might of the shadow and take part in his pleasure with the prayer as you notice that " + "the shadow is an incarnation of Tempos himself! " + "Tempos notices the %^CYAN%^warhammer%^RESET%^ on top of the altar and hands it to "+ob->query_cap_name()+"!",ob); + tell_object(ob,"You mutter a prayer in front of the altar. As you " + "do so, the shape of a demigod appears on the altar. " + "You feel the might of the shadow and repeat the prayer as you notice that " + "the shadow is an incarnation of Tempos himself! " + "Tempos notices his %^CYAN%^warhammer%^RESET%^ on top of the altar and hands it to you!"); + tell_room(this_object(),"The shadow disappears as the prayer ends.",({})); + is_hammer = 0; + SaveObject(SAVE_FILE); // save is_hammer + ob2->move(ob); + return 1; + } + } + } + if (is_phyl) { + j = 0; + for (i=0; i<sizeof(inv); i++) + if (inv[i]->id("phylactery")) { + j = 1; + break; + } + if (str == "for phylactery" && j==0 && ob->query_alignment()>=800 && ob->query_level()>5 && ob->query_skill("faith")>50) { + ob2 = new(PHYL); + if (ob2) { + tell_room(this_object(),ob->query_cap_name()+" mutters a prayer in front of the altar. As "+ + nominative(ob)+" does so, the shape of a demigod appears on the altar. " + "You feel the might of the shadow and take part in his pleasure with the prayer as you notice that " + "the shadow is an incarnation of Tempos himself! " + "Tempos notices the phylactery on top of the altar and hands it to "+ob->query_cap_name()+"!",ob); + tell_object(ob,"You mutter a prayer in front of the altar. As you " + "do so, the shape of a demigod appears on the altar. " + "You feel the might of the shadow and repeat the prayer as you notice that " + "the shadow is an incarnation of Tempos himself! " + "Tempos notices his phylactery on top of the altar and hands it to you!"); + tell_room(this_object(),"The shadow disappears as the prayer ends.",({})); + is_phyl = 0; + SaveObject(SAVE_FILE); // save is_phyl + ob2->move(ob); + return 1; + } + } + } + if (prayers < 7) { + tell_room(this_object(),ob->query_cap_name()+" mutters a prayer in front of the altar. As "+ + nominative(ob)+" does so, the shape of a demigod appears on the altar. " + "You feel the might of the shadow and take part in his pleasure with the prayer as you notice that " + "the shadow is an incarnation of Tempos himself!",ob); + tell_object(ob,"You mutter a prayer in front of the altar. As you " + "do so, the shape of a demigod appears on the altar. " + "You feel the might of the shadow and repeat the prayer as you notice that " + "the shadow is an incarnation of Tempos himself!"); + tell_room(this_object(),"The shadow disappears as the prayer ends.",({})); + if (random(100) <(15+ob->query_base_stats("charisma"))) ob->add_alignment(random(3)+10-prayers); + } else { + limb = ob->return_limb(); + tell_room(this_object(),ob->query_cap_name()+" mutters a prayer in front of the altar. As "+ + nominative(ob)+" does so, the shape of a demigod appears on the altar. " + "You feel the might of the shadow and the fear he installs in your heart! " + "The shadow again is an incarnation of Tempos himself, but this time he is annoyed of being " + "disturbed that often! With a swing of his hammer he attacks "+ob->query_cap_name()+ + "! "+ ( is_hammer ? + " This time the hammer turns out to be real!\nTempos destroys "+ob->query_cap_name()+" utterly in the "+limb+ + " with his %^CYAN%^warhammer%^RESET%^!" + : "Luckily for "+objective(ob)+ " the hammer is a shadow also, and therefore the damage is minimal." + ) ,ob); + tell_room(this_object(),"Tempos decides "+ob->query_cap_name()+" is not " + "worth to bother with anyway and disappears.",ob); + tell_object(ob,"You mutter a prayer in front of the altar. As you " + "do so, the shape of a demigod appears on the altar. " + "You feel the might of the shadow and the fear he installs in your heart! " + "The shadow again is an incarnation of Tempos himself, but this time he is annoyed of being " + "disturbed that often! With a swing of his hammer he attacks you!" + + ( is_hammer ? + " This time the hammer turns out to be real!\nTempos destroys you utterly in the "+limb+ + " with his %^CYAN%^warhammer%^RESET%^!" + : " Luckily for you the hammer is a shadow also, and therefore the damage is minimal." + ) ); + ob->do_damage(limb,5+random(prayers)+is_hammer*25); + tell_object(ob,"Tempos decides you are not worth to bother with anyway and disappears."); + } + prayers++; + return 1; +} diff --git a/lib/domains/Praxis/data/booth_question b/lib/domains/Praxis/data/booth_question new file mode 100644 index 0000000..cff9534 --- /dev/null +++ b/lib/domains/Praxis/data/booth_question @@ -0,0 +1,20 @@ + + One possible way to cut down on the amount of lag that we have been +experiencing recently is to limit the number of players on the mud at any given +time. Therefore the administrators would like player input on limiting the +number of players permitted to log on at any given time to 35. The results +of this poll will have an influence on the decision that is reached, so +please consider your vote carefully. + +A. I think that Nightmare should only be permitted to have 35 players on at + any given time. (Note: this would only be a temporary solution until + another can be found) + +B. I think that Nightmare should not limit the number of players, and + alternative methods of fighting the lag should be found. + + +Also note with solution A, archwizards and above would still be able to get +on at any time. +To vote type either <vote a> or <vote b>. As always second characters are not +allowed to vote. Immortals may feel free to vote in this poll, if they desire. diff --git a/lib/domains/Praxis/data/booth_votes.o b/lib/domains/Praxis/data/booth_votes.o new file mode 100644 index 0000000..c26348d --- /dev/null +++ b/lib/domains/Praxis/data/booth_votes.o @@ -0,0 +1,17 @@ +#d/standard/booth.c +__VendorType "treasure" +__Short "Nightmare referendum room" +__Long "This is the referendum room of Nightmare. Players come here to vote on issues that the wizards desire input on. The current voting question is posted on the wall <read question> will display it." +destinations (["down":"/domains/Praxis/adv_main",]) +invis_exits ([]) +pre_exit_func ([]) +post_exit_func ([]) +tracks ({}) +__Items (["slayar":0,"red moon":0,"spyefel":0,"green moon":0,"moon":0,"laros":0,"sun":0,"moons":0,"blue moon":0,"sky":0,]) +__Smells ([]) +__Listens ([]) +__Searches ([]) +reset_number 4 +a 10 +b 56 +vote (["asdf":"b","nex":"b","argus":"b","allanon":"b","soosheemee":"b","irie":"b","pollux":"b","josh":"b","bobafet":"a","trandar":"a","corona":"b","karatekid":"b","hades":"b","xa":"b","placid":"b","belfalas":"b","lassondra":"b","annie":"b","szordrin":"b","hugga":"b","dossy":"a","forlock":"b","nightshade":"b","nyarlathotep":"a","hrok":"b","asp":"b","millamber":"b","acidcasper":"b","alderon":"b","thekiller":"a","kolpi":"b","andras":"b","jubal":"b","deimos":"b","corvar":"b","turk":"b","flamme":"a","descartes":"b","aberddine":"b","isil":"b","kalinash":"a","baalzebub":"b","carmen":"b","tchalla":"b","cobalt":"a","eandril":"b","sleak":"b","zaknaifen":"a","cax":"b","merck":"b","phyyr":"b","brillag":"b","dana":"b","obiwan":"a","ahab":"b","kahless":"b","wysard":"b","kalos":"b","surpha":"b","niteraven":"b","ariel":"b","yildor":"b","gandalf":"b","retrograde":"b","brunoer":"b","jimbob":"b",]) diff --git a/lib/domains/Praxis/data/cleric_crypt.o b/lib/domains/Praxis/data/cleric_crypt.o new file mode 100644 index 0000000..66538ca --- /dev/null +++ b/lib/domains/Praxis/data/cleric_crypt.o @@ -0,0 +1,15 @@ +#domains/Praxis/crypt.c +__VendorType "treasure" +__Short "a small crypt" +__Long "The altar room is carved from the ancient gray stone that Praxis rests upon. Burning candles along the walls cause the shadows to dance around the room in a chaotic, yet enchanting dance. A large altar rises from the floor in the center of the room and steps carved into the stone lead upwards. " +destinations (["up":"/domains/Praxis/cleric_hall",]) +invis_exits ([]) +pre_exit_func ([]) +post_exit_func ([]) +tracks ({}) +__Items (["spyefel":,"moon":,"sun":,"blue moon":,"shadows":"The shadows dance enchantingly across the room in time to the music of the flickering candle flames. ","candles":"The candles rest in iron stands set along the wall and are made from animal fat. The candle flames flicker to the tune of the wind, creating the music by which the shadows cavort and dance. ","sky":,"altar":,"red moon":,"slayar":,"shadow":"The shadows dance enchantingly across the room in time to the music of the flickering candle flames. ","stone":"The cold grey stone is creased and marked by the tools that were used to carve this room beaneath the earth. ","green moon":,"stones":"The cold grey stone is creased and marked by the tools that were used to carve this room beaneath the earth. ","laros":,"walls":"The walls are hewn roughly from the stone beneath Praxis and are lined with many flickering candles. ","moons":,"steps":"The steps are carved into the grey stone and are worn by the passage of many feet over the ages. ","wall":"The walls are hewn roughly from the stone beneath Praxis and are lined with many flickering candles. ","candle":"The candles rest in iron stands set along the wall and are made from animal fat. The candle flames flicker to the tune of the wind, creating the music by which the shadows cavort and dance. ","stands":"The stands are made of %^BLACK%^%^BOLD%^black%^RESET%^ iron and are of plain construction. Each stand holds between three to four lit candles. ","scenes":"You see Tempos wielding his mighty %^CYAN%^warhammer%^RESET%^ in a variety of battles you recognize from your religious studies. ",]) +__Smells ([]) +__Listens ([]) +__Searches ([]) +reset_number 2 +prayers 32 diff --git a/lib/domains/Praxis/data/properties.o b/lib/domains/Praxis/data/properties.o new file mode 100644 index 0000000..2f9255c --- /dev/null +++ b/lib/domains/Praxis/data/properties.o @@ -0,0 +1,2 @@ +#d/standard/adm/master.c +properties (["hardness":(["wood":(["holly":5000,]),]),"temperature":(["default":295,]),]) diff --git a/lib/domains/Praxis/data/properties.t b/lib/domains/Praxis/data/properties.t new file mode 100644 index 0000000..815cc55 --- /dev/null +++ b/lib/domains/Praxis/data/properties.t @@ -0,0 +1,5 @@ +#Properties of the standard realm that differ from /data/properties +#see /data/properties.t for units +#eg if in this realm druids were important and it is colder than average +hardness/wood/holly;5000 +temperature/default;295 diff --git a/lib/domains/Praxis/data/wall.o b/lib/domains/Praxis/data/wall.o new file mode 100644 index 0000000..53a2fa3 --- /dev/null +++ b/lib/domains/Praxis/data/wall.o @@ -0,0 +1,9 @@ +#domains/Praxis/wall.c +__VendorType "treasure" +__Short "a graffitti covered wall" +__Long "You are in among ruined buildings in a bad part of the village. There is graffiti all over the wall to the east." +__Items (["graffiti":"Some is fresh, some is old.","sky":0,"wall":"You can scribble something on it. <scribble stuff>. You can also read what is on it.","blue moon":0,"sun":0,"moons":0,"moon":0,"laros":0,"green moon":0,"buildings":"They are worn down by years of neglect.","spyefel":0,"slayar":0,"red moon":0,]) +__Smells ([]) +__Listens ([]) +__Searches ([]) +text_scan ({}) diff --git a/lib/domains/Praxis/death/death_room.c b/lib/domains/Praxis/death/death_room.c new file mode 100644 index 0000000..7e1eef1 --- /dev/null +++ b/lib/domains/Praxis/death/death_room.c @@ -0,0 +1,11 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + room::create(); + SetProperties(([ "light" : 3, "no magic" : 1 ])); + SetShort("the underworld"); + SetLong("This will become something more interesting. Exit is up."); + AddExit("up", "/domains/Praxis/square"); +} diff --git a/lib/domains/Praxis/dump.c b/lib/domains/Praxis/dump.c new file mode 100644 index 0000000..79fe735 --- /dev/null +++ b/lib/domains/Praxis/dump.c @@ -0,0 +1,54 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetSmell("default", "You nearly pass out from the stench of the place."); + SetSmell("piles", "They smell of rotten elf food."); + SetSmell("food", (: this_object(), "smell_food" :)); + SetProperty("light", 3); + SetShort( "Praxis dump"); + SetLong( + "The waste of an entire town accumulates here at the Praxis dump. " + "All around you are mounds upon mounds of trash and other stinking " + "unidentifiable things. A small alley leads east."); + SetItems( + (["mounds" : "Who knows what might be in amoung that crap?", + "dump" : "The people of Praxis bring their junk here.", + "trash" : "Anything and everything.", + "alley" : "It leads back to Centre Path."]) ); + SetExits( + (["east" : "/domains/Praxis/alley2"]) ); +} + +void reset() { + ::reset(); + SetSearch("mound", (: this_object(), "mound_searching" :)); + SetSearch("mounds", (: this_object(), "mound_searching" :)); +} + +void mound_searching() { + message("my_action", "You found a dagger in one of the mounds of trash!", + this_player()); + message("other_action", this_player()->query_cap_name()+ + " found a dagger in one of the mounds of trash.", this_object(), + ({ this_player() })); + new("/domains/Praxis/obj/weapon/dagger")->move(this_object()); + RemoveSearch("mounds"); + RemoveSearch("mound"); +} + +void smell_food(string str) { + message("my_action", "You pass out from the stench of rotten elf food.", + this_player()); + message("other_action", this_player()->query_cap_name()+ + " passes out from the stench of rotten elf food.", this_object(), + ({ this_player() })); + this_player()->add_sp(-3); + this_player()->add_hp(-3); + this_player()->set_paralyzed(10, "You are too nauseated to move!"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/e_boc_la1.c b/lib/domains/Praxis/e_boc_la1.c new file mode 100644 index 0000000..913bd78 --- /dev/null +++ b/lib/domains/Praxis/e_boc_la1.c @@ -0,0 +1,36 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 3); + SetProperty("night light", 1); + SetProperty("no castle", 1); + SetShort("East Boc La south of the monastary"); + SetLong( + "Boc La Road on the eastern side of Praxis is a large dirt road " + "leading towards the center of town, Monument Square. Many " + "footprints have pounded the road into a flat surface, easy to " + "travel. Rusted old lamp posts stand on either side of the road, " + "to light Praxis by night. A small path to the north leads into the " + "village monastary. East Boc La road continues east from here, " + "and the town hall is south."); + SetExits( + (["north" : "/domains/Praxis/monastery", + "east" : "/domains/Praxis/e_boc_la2", + "south" : "/domains/Praxis/town_hall.c", + "west" : "/domains/Praxis/square"]) ); + SetItems( + (["road" : "Boc La Road is the large path that runs east-west " + "through Praxis.", + "monastery" : "The monks of Nightmare study and " + "worship there.", + "square" : "Monument Square is the center point of " + "all of Praxis. Many adventurers enjoying hanging out there, " + "chatting with fellow citizens about life in Praxis."]) ); + SetSkyDomain("town"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/e_boc_la2.c b/lib/domains/Praxis/e_boc_la2.c new file mode 100644 index 0000000..a907ddf --- /dev/null +++ b/lib/domains/Praxis/e_boc_la2.c @@ -0,0 +1,37 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 3); + SetProperty("night light", 1); + SetProperty("no castle", 1); + SetListen( "default", "The hustle of a town surrounds you."); + SetShort( "East Boc La Road"); + SetLong( + "Off to the east you can see the intersection between Boc La Road " + "and East Road. There are two buildings visible from here, Horace's " + "Supply Store is to the north, and the building housing the " + "adventurer's hall is to the south. People busily bustle " + "back and forth, going about their business."); + SetExits( + (["north" : "/domains/Praxis/supply", + "south" : "/domains/Praxis/adv_main", + "east" : "/domains/Praxis/e_boc_la3", + "west" : "/domains/Praxis/e_boc_la1"]) ); + SetItems( + (["shop" : "A small place where items can be bought and sold.", + "road" : "A dirt path leading east and west through Praxis.", + "area" : "Adventurers gather there to form parties and " + "discuss their adventures.", + "square" : "You cannot see it very well from here.", + "people" : "The people walk by at a quicken pace, hardly bothering " + "you with a glance.", + "hall" : "The hall is where all the adventurer's of Praxis gather to " + "chat."]) ); + SetSkyDomain("town"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/e_boc_la3.c b/lib/domains/Praxis/e_boc_la3.c new file mode 100644 index 0000000..5543f83 --- /dev/null +++ b/lib/domains/Praxis/e_boc_la3.c @@ -0,0 +1,38 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 3); + SetProperty("night light", 1); + SetProperty("no castle", 1); + SetSmell( "default", "The faint smell of foliage wafts towards you."); + SetShort( "the east end of Praxis"); + SetLong( + "The dirt path brings you to the end of the village of Praxis. " + "Boc La Road meets up with a smaller dirt path which leads " + "out further east into the wilderness. The path is very " + "narrow and looks unsafe. After travelling a couple of meters it " + "is suddenly engulfed in a mass of green leaves and undergrowth. " + "Up ahead, you can see the darker path of East road, leading to " + "Praxis' cemetery. West takes you back along East Boc La road."); + SetItems( + (["road" : "It leads west toward the village center.", + "village" : "Praxis is a small adventuring community " + "of the Nightmare reality.", + "wilderness" : "Stories tell of bandits and rogues out " + "in the wilderness.", + "path" : "The path leads in many directions from here, towards the " + "Praxis cemetery, the wilderness, and back towards Monument Square.", + "cemetery": "The Praxis cemetery is off to the north on East Road." ]) ); + SetSkyDomain("town"); + SetExits( ([ + "west" : "/domains/Praxis/e_boc_la2", + "north" : "/domains/Praxis/east_road1", + "east" : "/domains/Praxis/wild1", + ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/east_road1.c b/lib/domains/Praxis/east_road1.c new file mode 100644 index 0000000..d2e394c --- /dev/null +++ b/lib/domains/Praxis/east_road1.c @@ -0,0 +1,62 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void init() { + ::init(); + add_action("climb", "climb"); +} + +void create() { + ::create(); + SetProperty("light", 3); + SetProperty("night light", 1); + SetProperty("no castle", 1); + SetShort( "the southern end of East Road"); + SetLong( + "Starting your journey down East Road, you can see that this is " + "a less travelled street. Boc La Road is south from here, running " + "straight through Praxis. Every now and then you can see a street " + "lamp or two, in its ancient and rusted stage. The walls of the supply " + "store border the western side of the road, and the Praxis Library, " + "one of the biggest libraries in this realm, is to the east."); + SetItems( + (["road" : "East Road, which marks the far east end of Praxis.", + "roads" : "East Road and Boc La Road.", + "side" : "It's the supply shop.", + "shop" : "The local adventurer's supply shop sits on Boc La " + "and East Road.", + "walls" : "They are nothing special.", + "wall" : "You are fairly certain that you cannot climb them.", + "library" : "It is open for your reading pleasure."]) ); + SetSkyDomain("town"); + SetExits( + (["north" : "/domains/Praxis/east_road2", + "south" : "/domains/Praxis/e_boc_la3", + "east" : "/domains/Praxis/library"]) ); + SetProperty("no castle", 1); +} + +int climb(string str) { + if(!str) { + notify_fail("Climb what?\n"); + return 0; + } + if(str != "wall" && str != "walls") { + notify_fail("That's not here for climbing.\n"); + return 0; + } + if(this_player()->query_stats("dexterity") < random(30)) { + write("Ack! You slip and hurt yourself in trying!"); + say(this_player()->query_cap_name()+" slips and hurts "+ + this_player()->query_objective()+"self in trying " + "to climb the walls."); + this_player()->add_hp(-(random(7))); + } + else { + write("You can't quite manage the climb."); + say(this_player()->query_cap_name()+" tries to climb the shop " + "walls and fails."); + } + return 1; +} diff --git a/lib/domains/Praxis/east_road2.c b/lib/domains/Praxis/east_road2.c new file mode 100644 index 0000000..83a732a --- /dev/null +++ b/lib/domains/Praxis/east_road2.c @@ -0,0 +1,39 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 2); + SetProperty("night light", 1); + SetProperty("no castle", 1); + SetListen( "default", "The quiet chirp of grasshoppers hangs " + "in the air." ); + SetShort( "the crossing of East Road and Sun Alley"); + SetLong( + "Sun Alley, named for its' beautiful view of the sunsets, shoots " + "off west from East Road. East Road continues, heading north and " + "south upon the eastern border of town. To the east, you can see " + "the Praxis cemetery, shaded by large trees. The air is very still " + "here, and a feeling of foreboding hangs in the air."); + SetItems( + (["alley" : "A bright and cheery alley which marks the northern " + "boarder of Praxis.", + "road" : "East Road is a curvy road running north and south " + "on the east side of Praxis.", + "cemetery" : "The residents of Praxis get buried there. It " + "looks spooky.", + "trees" : "The trees are large drooping willow trees.", + "forest" : "A great forest the marks the northern end of Praxis."]) + ); + SetSkyDomain("town"); + SetExits( + (["north" : "/domains/Praxis/east_road3", + "south" : "/domains/Praxis/east_road1", + "east" : "/domains/Praxis/cemetery/grave_yard", + "west" : "/domains/Praxis/sun2"]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/east_road3.c b/lib/domains/Praxis/east_road3.c new file mode 100644 index 0000000..9f197e0 --- /dev/null +++ b/lib/domains/Praxis/east_road3.c @@ -0,0 +1,53 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 2); + SetProperty("no castle", 1); + SetShort( "the north end of East Road"); + SetLong( + "East Road comes to a sudden dead end as you find yourself " + "at the foot of Praxis forest. These outskirts of Praxis aren't " + "visited very often. The area is very quiet and lonely with " + "so few people around. Ahead, at the end of the road you " + "can see a discreet sign tacked to a tree. A small footpath leads " + "off the road in an eastern direction."); + SetItems( + (["road" : "The road that travels the eastern end of Praxis.", + "forest" : "The forest is dark and forebidding.", + "intersection" : "There is a restaurant at one of its corners.", + "alley" : "It is bright and wonderful.", + "restaurant" : "The Last Dragon Restaurant.", + "sign" : "A litte white sign, perhaps you could read it."]) ); + SetSkyDomain("town"); + SetExits( ([ + "south" : "/domains/Praxis/east_road2", + ]) ); +} + +int go_north() { + if(this_player()->query_level() > 5) { + write("You try to continue on to the north, but the path " + "becomes too narrow to accomadate your size."); + return 0; + } + return 1; +} + +void init() { + ::init(); + add_action("read","read"); +} + +int read(string str) { + if(str == "sign") { + write("The sign reads: %^RED%^Welcome all new members to Nightmare! " + "Off to the north of here lies a special area for all " + "players new to the town of Praxis.%^RESET%^"); + return 1; + } + notify_fail("Read what?\n"); + return 0; +} diff --git a/lib/domains/Praxis/farm.c b/lib/domains/Praxis/farm.c new file mode 100644 index 0000000..2039f53 --- /dev/null +++ b/lib/domains/Praxis/farm.c @@ -0,0 +1,46 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 3); + SetProperty("no castle", 1); + SetShort( "Praxis farmlands"); + SetLong( + "The area which you have wandered into is the farmlands of Praxis. " + "Large cornfields surround you, stretching for miles to both the " + "east and the west. The stalks grow strong and tall, making " + "it hard to see. Off in the far distance you can see the speck of " + "what appears to be a farmhouse."); + SetItems( + (["stalks" : "Huge stalks of corn covering so many acres of land.", + "stalk" : "A huge stalk of corn.", + "farmhouse" : "The farmhouse is far off in the distance, and " + "impossible to get to.", + "field" : "This place must supply the entire area with food.", + "corn" : "A food some people like to eat. It is " + "%^YELLOW%^yellow%^RESET%^."]) ); + SetSkyDomain("town"); + SetExits( + (["north" : "/domains/Praxis/w_boc_la2"]) ); +} + +void reset() { + ::reset(); + SetSearch("field", (: this_object(), "stalk_searching" :)); + SetSearch("stalks", (: this_object(), "stalk_searching" :)); +} + +void stalk_searching() { + message("my_action", "After searching through all the long stalks " + "you find a shovel among the them!", this_player()); + message("other_action", this_player()->query_cap_name()+" finds " + "a shovel among the stalks.", this_object(), ({ this_player() })); + new("/domains/Praxis/obj/misc/shovel")->move(this_object()); + RemoveSearch("stalks"); + RemoveSearch("field"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/fighter_hall.c b/lib/domains/Praxis/fighter_hall.c new file mode 100644 index 0000000..21e04a5 --- /dev/null +++ b/lib/domains/Praxis/fighter_hall.c @@ -0,0 +1,243 @@ +#include <lib.h> +#include <council.h> +#include <daemons.h> +#include ROOMS_H + +inherit LIB_ROOM; + +string get_new_title(object tp); +string get_male(int lev); +string get_female(int lev); +string previous_title(object tp); +int get_cost(string which, int lev); + +int CanReceive(object ob) { + if(!VOTING_D->is_time_to_vote()) + return ::CanReceive(ob); + if(VOTING_D->query_voted(this_player()->query_name(),this_player()->query_class())) + return ::CanReceive(ob); + if(creatorp(this_player()) || this_player()->query_level() < 2) + return ::CanReceive(ob); + else { + message("my_action", "You have not yet voted for you class leader. Please do so now.", this_player()); + call_out("move_me", 5, this_player()); + } + return ::CanReceive(ob); +} + +void move_me(object who) { + who->eventMoveLiving("/domains/Praxis/"+who->query_class()+"_vote"); + return; +} + +void create() { + object ob; + + ::create(); + SetProperties( (["no attack": 1, "no castle":1,"light":2,"indoors":1]) ); + SetShort( "the inner sanctum of the fighters"); + SetLong( + "Welcome to the inner sanctum of the Hall of Fighters!\n" + "Fighters come here to learn about the art of combat. " + "You are in what appears to be a large training hall. Large mats are " + "on the floor and weapons hang on the walls, in various shapes and forms. " + "In this mighty hall, a fighter may <advance>, <cost>, " + "<list (number)>, <improve stat>, <train skill amount>, and <roll stats>. " + "Down through a stairway guarded by a shimmering %^BLUE%^blue%^RESET%^ " + "light is the entrance to the hall."); + SetExits( ([ + "council" : "/domains/Praxis/council_hall", + "east" : "/domains/Praxis/fighter_vote", + "down" : "/domains/Praxis/fighter_join", + ]) ); + + ob = new("/lib/bboard"); + ob->SetKeyName("board"); + ob->SetId( ({ "board", "bulletin board", "glory board" }) ); + ob->set_board_id("fighter_board"); + ob->set_edit_ok(FIGHTER_COUNCIL); + ob->set_max_posts(50); + ob->move("/domains/Praxis/fighter_hall"); + ob->SetShort( "Glory Board of Fighters"); + ob->SetLong( + "The Fighters of our reality post tales of their glorious " + "adventures here, as well as info on the dangers out there.\n"); + //new("/realms/grumpy/fighter/obj/box.c")->move(this_object()); +} + +void init() { + ::init(); + add_action("cost","cost"); + add_action("roll","roll"); + add_action("train", "train"); + add_action("improve", "improve"); + add_action("advance","advance"); + add_action("list","list"); +} + +int roll(string str) { + if(str != "stats") return 0; + //ROOM_SETTER->do_rolls(); + return 1; +} + +string get_new_title(object tp) +{ + int lev; + string gen, title; + + lev = this_player()->query_level(); + gen = this_player()->query_gender(); + if(this_player()->query_guild()) { + if(present(tp->query_guild()+"_ob", tp)) { + if(lev > 19) title = "High mortal"; + else title = present(tp->query_guild()+"_ob", tp)->query_title(tp); + title += " $N"; + } + else { + if(lev > 19) title = "High mortal $N"; + else title = "$N"; + } + } + else { + if(lev > 20) title = "High mortal $N"; + else title = "$N"; + } + if(lev > 20) title += previous_title(tp); + else if(gen == "male") title += " "+get_male(lev); + else title += " "+get_female(lev); + return title; +} + +string get_male(int lev) { + string *male_title_str; + + if(!male_title_str) male_title_str = allocate(20); + male_title_str[19] ="the legend"; + male_title_str[18] ="the wise old master of combat"; + male_title_str[17] ="the old veteran"; + male_title_str[16] ="the battle hardened veteran"; + male_title_str[15] ="is death incarnate"; + male_title_str[14] ="the war-monger"; + male_title_str[13] = "the great gladiator"; + male_title_str[12] ="the experienced gladiator"; + male_title_str[11] ="the gladiator"; + male_title_str[10] ="the great champion"; + male_title_str[9] ="the champion"; + male_title_str[8] ="the experienced fighter"; + male_title_str[7] ="the employed fighter"; + male_title_str[6] ="the fighter for hire"; + male_title_str[5] ="the rookie fighter"; + male_title_str[4] ="the amateur fighter"; + male_title_str[3] ="the experienced squire"; + male_title_str[2] ="the gung-ho squire"; + male_title_str[1] ="the timid squire"; + male_title_str[0] ="the page"; + return male_title_str[lev-1]; +} + +string get_female(int lev) { + return get_male(lev); +} + +int advance() { return ADVANCE_D->advance(); } + +int train(string str) { + string which, which_tmp; + int amount; + + if(!str) { + notify_fail("Correct syntax: <train skill amount>\n"); + return 0; + } + if(sscanf(str, "%s %s %d", which, which_tmp, amount) == 3) which = which+ " "+ which_tmp; + else if(sscanf(str, "%s %d", which, amount) !=2) { + notify_fail("Correct syntax: <train skill amount>\n"); + return 0; + } + which = lower_case(which); + if(!this_player()->skill_exists(which)) { + notify_fail("No such skill.\n"); + return 0; + } + return ADVANCE_D->train_player(this_player(), which, amount); +} + +int improve(string str) { + string *stats; + string adj; + int stat_cost; + + stats = ({ "strength", "intelligence", "wisdom", "dexterity", "constitution", "charisma" }); + str = lower_case(str); + if(member_array(str, stats) == -1) { + notify_fail("You have no such stat.\n"); + return 0; + } + stat_cost = get_cost(str, this_player()->query_base_stats(str)); + if( this_player()->query_exp()-stat_cost < ADVANCE_D->get_exp( this_player()->query_level() ) ) { + notify_fail("You are not experienced enough to improve yourself in that way.\n"); + return 0; + } + this_player()->SetStat(str, this_player()->query_base_stats(str) + 1); + this_player()->add_exp(-stat_cost); + adj = (str == "strength" ? "stronger" : (str == "intelligence" ? "more intelligent" : + (str == "wisdom" ? "wiser" : (str == "dexterity" ? "more nimble" : + (str == "constitution" ? "sturdier" : "more attractive"))))); + message("my_action", sprintf("You look %s.", adj), this_player()); + message("other_action", sprintf("%s looks much %s", + this_player()->query_cap_name(), adj), environment(this_player()), + ({ this_player() })); + return 1; +} + +int get_cost(string stat, int lev) { + switch(stat) { + case "strength": return ADVANCE_D->get_stat_cost(1, lev); break; + case "constitution": return ADVANCE_D->get_stat_cost(1, lev); break; + case "dexterity": return ADVANCE_D->get_stat_cost(1, lev); break; + default: return ADVANCE_D->get_stat_cost(2, lev); break; + } +} + +int cost(string str) { + int bing; + + write("Costs for advancement, training, and improvement:\n"); + bing = ADVANCE_D->get_exp( this_player()->query_level() + 1 ); + if(bing < 1) write("level:\t\tIt will cost you nothing to advance."); + else write("level:\t\t"+bing+"\n"); + write("skills: You train by spending the amount of experience you + desire."); + write("strength:\t\t" + get_cost("strength", + this_player()->query_base_stats("strength")) + + "\t\tconstitution:\t\t" + get_cost("constitution", + this_player()->query_base_stats("constitution")) ); + write("intelligence:\t\t" + get_cost("intelligence", + this_player()->query_base_stats("intelligence")) + + "\t\tdexterity:\t\t" + get_cost("dexterity", + this_player()->query_base_stats("dexterity")) ); + write("wisdom:\t\t" + get_cost("wisdom", + this_player()->query_base_stats("wisdom")) + + "\t\tcharisma:\t\t" + get_cost("charisma", + this_player()->query_base_stats("charisma")) ); + return 1; +} + +int list(string str) { + int x; + + if(!str) "/domains/Praxis/quest_room"->list_quests(this_player(), 0); + else { + if(sscanf(str, "%d", x) != 1) { + notify_fail("You must give the number of the quest you want listed.\n"); + return 0; + } + if(x<1) { + notify_fail("No such quest.\n"); + return 0; + } + "/domains/Praxis/quest_room"->list_quests(this_player(), x); + } + return 1; +} diff --git a/lib/domains/Praxis/fighter_join.c b/lib/domains/Praxis/fighter_join.c new file mode 100644 index 0000000..5c5b6d9 --- /dev/null +++ b/lib/domains/Praxis/fighter_join.c @@ -0,0 +1,94 @@ +#include <lib.h> +int go_up(); + +inherit LIB_ROOM; + +void init() { + ::init(); + add_action("become", "become"); + add_action("preview","preview"); +} + +void create() { + ::create(); + SetProperty("light", 2); + SetProperty("indoors", 1); + SetProperty("no castle", 1); + SetShort( "The Hall of Fighters"); + SetLong( + "The Hall of Fighters is decorated with ornate tapestries of " + "men and women engaged in combat of all traditions. Adventuring " + "fighters are gathered around discussing glory at the base of a " + "spiraling staircase which leads up through a magically lit hole " + "in the ceiling. Young warriors stand about hoping to learn the " + "ways of the fighter. Children may <preview> what it is like to " + "be a fighter."); + SetItems( + ([({"tapestry", "tapestries", "wall"}) : "The walls are all " + "covered with some of the most ornate tapestries from " + "all over. The one you are looking at depicts a heroic " + "battle between a dragon and a human combatant.", + ({"hole", "light", "opening", "ceiling"}) : "Up in the ceiling, " + "the staircase leads through a mystical light up " + "to the second floor.", + "staircase" : "It leads through the opening in the ceiling " + "to the second floor.", + "fighters" : "They are loud and obnoxious.", + ({"warriors", "young warriors"}) : "They look clueless."]) ); + SetExits( + (["southeast" : "/domains/Praxis/s_centre4"]) ); + AddExit("up", "/domains/Praxis/fighter_hall", (:go_up:)); + SetListen("default", "Fighters are yelling and screaming and " + "being generally obnoxiously loud."); +} + +int preview() { + if(this_player()->query_class() != "explorer") { + write("This is not for you.\n"); + return 1; + } + say(this_player()->query_cap_name()+" seeks to learn about fighter.", + this_player()); + write("Welcome, explorer!"); + write("Fighters are people whose only uniting belief is in combat as a " + "form of art. Some are great knights who fight for good wherever " + "they go. Others might be considered quite fiendish in some circles. " + "They therefore have no moral restrictions placed upon them. But " + "they spend so much time learning the arts of combat, that they " + "are almost entirely ignorant of the ways of magic. To become " + "a fighter, type <become fighter>."); + return 1; +} + +int become(string str) { + if(!str) { + notify_fail("Become what?\n"); + return 0; + } + if(str != "fighter") { + notify_fail("You cannot become that here.\n"); + return 0; + } + if(this_player()->query_class() != "explorer") { + write("You are much too old to start learning our ways now!"); + return 1; + } + write("The Great Warrior initiates you into the class of fighters."); + say(this_player()->query_cap_name()+" becomes a fighter.", this_player()); + this_player()->SetClass("fighter"); + this_player()->setenv("TITLE", "$N the page"); + this_player()->init_skills("fighter"); + this_player()->setenv("start", "/domains/Praxis/fighter_hall"); + return 1; +} + +int go_up() { + if(this_player()->query_class() != "fighter") { + write("You cannot penetrate the force field that blocks the passage."); + say(this_player()->query_cap_name()+" tries to get into the " + "fighter's sanctuary, but fails.", this_player()); + return 0; + } + return 1; +} + diff --git a/lib/domains/Praxis/fighter_vote.c b/lib/domains/Praxis/fighter_vote.c new file mode 100644 index 0000000..2fb82f9 --- /dev/null +++ b/lib/domains/Praxis/fighter_vote.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include <voting.h> +#include <daemons.h> + +inherit "/domains/town/room/voters"; + +void create() { + ::create(); + SetProperty("light", 3); + SetProperty("no castle", 1); + SetProperty("indoors", 1); + SetShort( "Voting hall of the fighters"); + SetLong( (: this_object(), "new_long" :)); + SetItems( + (["list" : "During election time, it lists all candidates."]) ); + SetExits( + (["west" : "/domains/Praxis/fighter_hall"]) ); +} + +string new_long() { + if(VOTING_D->election_day()) + return "This is the room where Fighters can put in their bid for office. " + "If you wish to run for office, just type in the command " + "'enter' and you will be added to the list. A list of candidates " + "is posted on the wall. Type 'list candidates' to read it."; + else return "This is the voting chamber of the Hall of Fighters. " + "Fighters will gather here for the next election: "+VOTING_D->query_vote_date()+"."; +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/forest1.c b/lib/domains/Praxis/forest1.c new file mode 100644 index 0000000..081429d --- /dev/null +++ b/lib/domains/Praxis/forest1.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 3); + SetProperty("no castle", 1); + SetShort( "the North Forest"); + SetLong( + "You are in a huge forest just north of the village of Praxis. " + "The forest extends in all directions, with a small path " + "leading deeper into the forest north and into one of the main " + "village roads south."); + SetExits( + (["north" : "/domains/Praxis/forest2", + "south" : "/domains/Praxis/n_centre2"]) ); + SetItems( + (["path" : "A small path throught the huge North Forest.", + "forest" : "The North Forest. It is not a very well traveled place.", + "village" : "The grand village of Praxis"]) ); + SetSkyDomain("town"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/forest2.c b/lib/domains/Praxis/forest2.c new file mode 100644 index 0000000..efed820 --- /dev/null +++ b/lib/domains/Praxis/forest2.c @@ -0,0 +1,32 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 1); + SetProperty("no castle", 1); + SetShort("a path in the North Forest"); + SetLong( + "The small footpath is leading you further and further into the " + "depths of North Forest. The forest becomes much denser, and the " + "the trees indicate that this is the older section of the " + "forest. The foliage is so dense, that little light can filter " + "through. North leads further into the forest, and south takes you " + "back towards the main village. East you can see another path heading off."); + SetItems( + (["footpath" : "A small path through the huge North Forest.", + "forest" : "The North Forest. It is not a very well-traveled " + "place.", + ({ "trees", "tree" }) : "The trees are huge and forebodding.", + "foliage" : "The foliage is a very dark coloured green." + ]) ); + SetSkyDomain("town"); + SetExits( ([ + "south" : "/domains/Praxis/forest1", + "north" : "/domains/Praxis/forest3", + ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/forest3.c b/lib/domains/Praxis/forest3.c new file mode 100644 index 0000000..c2c916d --- /dev/null +++ b/lib/domains/Praxis/forest3.c @@ -0,0 +1,32 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 2); + SetProperty("no castle", 1); + SetShort( "deep in the North Forest"); + SetLong( + "The tiny footpath suddenly turns sharply to the northwest, " + "continuing further into the North Forest. The path is being " + "overgrown by large amounts of undergrowth. Over in the corner you " + "spy a mysterious dark cavern leading down into the depths " + "of the earth. A path leads off to the northwest, and south heads " + "back out of the forest."); + SetItems( + ([ + ({"path", "footpath"}) : "A small path running through North Forest.", + "forest" : "North Forest is a very dark and evil place.", + "undergrowth" : "The undergrowth slowly is assimilating the path.", + "cavern" : "Its mysterious maw beckons you to enter."]) ); + SetSkyDomain("town"); + SetExits( ([ + "south" : "/domains/Praxis/forest2", + "down" : "/domains/Praxis/kataan_join", + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/freezer.c b/lib/domains/Praxis/freezer.c new file mode 100644 index 0000000..3d3b953 --- /dev/null +++ b/lib/domains/Praxis/freezer.c @@ -0,0 +1,37 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +static private object *old; + +void create() { + ::create(); + SetProperty("no teleport", 1); + SetShort( "The freezer"); + SetLong( "The local freezer."); + SetExits( + (["square" : "/domains/Praxis/square"]) ); + SetNoClean(1); + call_out("clean_room", MAX_NET_DEAD_TIME); +} + +static void clean_room() { + object *in_here, *to_clean; + int i; + + if(!sizeof(in_here = livings() & all_inventory(this_object()))) { + old = in_here; + call_out("clean_room", MAX_NET_DEAD_TIME); + return; + } + i = sizeof(to_clean = in_here & (pointerp(old) ? old : ({}))); + old = in_here - to_clean; + while(i--) to_clean[i]->clean_net_dead(); + i = sizeof(to_clean = all_inventory(this_object()) - in_here); + while(i--) to_clean[i]->destruct(); + call_out("clean_room", MAX_NET_DEAD_TIME); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/hall.c b/lib/domains/Praxis/hall.c new file mode 100644 index 0000000..ae63471 --- /dev/null +++ b/lib/domains/Praxis/hall.c @@ -0,0 +1,41 @@ +inherit "/lib/std/room"; + +void create() { + ::create(); + SetProperties( ([ "light" : 1, "no castle" : 1 ]) ); + SetShort( "the Nightmare Inn" ); + SetLong( "The hallway is very quiet, you can barely hear the whisper " + "of your feet against the rich carpet. Large wooden doors for each room " + "stand both to your left and right, trimmed with gold. Small lanterns " + "hang every 5 feet or so, giving off a gentle glow, lighting the way." ); + SetItems( ([ "hallway" : "The hallway is very quiet.", + "carpet" : "It is a deep burgundy colour.", + ({ "lanterns", "lanter" }) : + "The lanterns are gold with glass panes.", + "doors" : "The doors are large oaken barriers.", + ]) ); + SetExits( ([ "north" : "/domains/Praxis/hall2", + "south" : "/domains/Praxis/hotel", + "east" : "/domains/Praxis/inn101", + "west" : "/domains/Praxis/inn102", + ]) ); + //set_pre_exit_functions( ({ "east", "west" }), ({ "room_101", "room_102" }) ); +} + +int room_101() { + if(present("/domains/Praxis/hotel"->query_key_id(101),this_player())) + return 1; + write( "You cannot go in there!"); + return 0; +} + +int room_102() { + if(present("/domains/Praxis/hotel"->query_key_id(102),this_player())) + return 1; + write( "You cannot go in there!"); + return 0; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/hall2.c b/lib/domains/Praxis/hall2.c new file mode 100644 index 0000000..3775b5e --- /dev/null +++ b/lib/domains/Praxis/hall2.c @@ -0,0 +1,41 @@ +inherit "/lib/std/room"; + +void create() { + ::create(); + SetProperties( ([ "light" : 1, "no castle" : 1 ]) ); + SetShort( "the Nightmare Inn" ); + SetLong( "The hallway is very quiet, you can barely hear the whisper " + "of your feet against the rich carpet. Large wooden doors for each room " + "stand both to your left and right, trimmed with gold. Small lanterns " + "hang every 5 feet or so, giving off a gentle glow, lighting the way." ); + SetItems( ([ "hallway" : "The hallway is very quiet.", + "carpet" : "It is a deep burgundy colour.", + ({ "lanterns", "lanter" }) : + "The lanterns are gold with glass panes.", + "doors" : "The doors are large oaken barriers.", + ]) ); + SetExits( ([ "north" : "/domains/Praxis/hall3", + "south" : "/domains/Praxis/hall", + "east" : "/domains/Praxis/inn103", + "west" : "/domains/Praxis/inn104" + ]) ); + //set_pre_exit_functions( ({ "east" , "west" }), ({ "room_103", "room_104" }) ); +} + +int room_103() { + if(present("/domains/Praxis/hotel"->query_key_id(103),this_player())) + return 1; + write( "You cannot go in there!"); + return 0; +} + +int room_104() { + if(present("/domains/Praxis/hotel"->query_key_id(104),this_player())) + return 1; + write( "You cannot go in there!"); + return 0; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/hall3.c b/lib/domains/Praxis/hall3.c new file mode 100644 index 0000000..74fb04f --- /dev/null +++ b/lib/domains/Praxis/hall3.c @@ -0,0 +1,41 @@ +inherit "/lib/std/room"; + +void create() { + ::create(); + SetProperties( ([ "light" : 1, "no castle" : 1 ]) ); + SetShort( "the Nightmare Inn" ); + SetLong( "The hallway is very quiet, you can barely hear the whisper " + "of your feet against the rich carpet. Large wooden doors for each room " + "stand both to your left and right, trimmed with gold. Small lanterns " + "hang every 5 feet or so, giving off a gentle glow, lighting the way." ); + SetItems( ([ "hallway" : "The hallway is very quiet.", + "carpet" : "It is a deep burgundy colour.", + ({ "lanterns", "lanter" }) : + "The lanterns are gold with glass panes.", + "doors" : "The doors are large oaken barriers.", + ]) ); + SetExits( ([ "north" : "/domains/Praxis/hall4", + "south" : "/domains/Praxis/hall2", + "east" : "/domains/Praxis/inn105", + "west" : "/domains/Praxis/inn106" + ]) ); + //set_pre_exit_functions( ({ "east", "west" }), ({"inn_105", "inn_106"}) ); +} + +int room_105() { + if(present("/domains/Praxis/hotel"->query_key_id(105),this_player())) + return 1; + write( "You cannot go in there!"); + return 0; +} + +int room_106() { + if(present("/domains/Praxis/hotel"->query_key_id(106),this_player())) + return 1; + write( "You cannot go in there!"); + return 0; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/hall4.c b/lib/domains/Praxis/hall4.c new file mode 100644 index 0000000..63d312b --- /dev/null +++ b/lib/domains/Praxis/hall4.c @@ -0,0 +1,42 @@ +//Written by Lassondra of Sunshine + +inherit "/lib/std/room"; + +void create() { + ::create(); + SetProperties( ([ "light" : 1, "no castle" : 1 ]) ); + SetShort( "the Nightmare Inn" ); + SetLong( "The hallway is very quiet, you can barely hear the whisper " + "of your feet against the rich carpet. Large wooden doors for each room " + "stand both to your left and right, trimmed with gold. Small lanterns " + "hang every 5 feet or so, giving off a gentle glow, lighting the way." ); + SetItems( ([ "hallway" : "The hallway is very quiet.", + "carpet" : "It is a deep burgundy colour.", + ({ "lanterns", "lanter" }) : + "The lanterns are gold with glass panes.", + "doors" : "The doors are large oaken barriers.", + ]) ); + SetExits( ([ "north" : "/domains/Praxis/hall5", + "south" : "/domains/Praxis/hall3", + "east" : "/domains/Praxis/inn107", + "west" : "/domains/Praxis/inn108", + ]) ); + //set_pre_exit_functions( ({ "east", "west" }), ({ "room_107", "room_108" }) ); +} + +int room_107() { + if(present("/domains/Praxis/hotel"->query_key_id(107),this_player())) + return 1; + write( "You cannot go in there!"); + return 0; +} + +int room_108() { + if(present("/domains/Praxis/hotel"->query_key_id(108),this_player())) + return 1; + write( "You cannot go in there!"); + return 0; +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/hall5.c b/lib/domains/Praxis/hall5.c new file mode 100644 index 0000000..a29466c --- /dev/null +++ b/lib/domains/Praxis/hall5.c @@ -0,0 +1,41 @@ +//Written by Lassondra who thinks Descartes is a weenie + +inherit "/lib/std/room"; + +void create() { + ::create(); + SetProperties( ([ "light" : 1, "no castle" : 1 ]) ); + SetShort( "the Nightmare Inn" ); + SetLong( "The hallway is very quiet, you can barely hear the whisper " + "of your feet against the rich carpet. Large wooden doors for each room " + "stand both to your left and right, trimmed with gold. Small lanterns " + "hang every 5 feet or so, giving off a gentle glow, lighting the way." ); + SetItems( ([ "hallway" : "The hallway is very quiet.", + "carpet" : "It is a deep burgundy colour.", + ({ "lanterns", "lanter" }) : + "The lanterns are gold with glass panes.", + "doors" : "The doors are large oaken barriers.", + ]) ); + SetExits( ([ "east" : "/domains/Praxis/inn109", + "west" : "/domains/Praxis/inn110", + "south" : "/domains/Praxis/hall4" + ]) ); + //set_pre_exit_functions( ({ "east", "west" }), ({ "room_109", "room_110" }) ); +} + +int room_109() { + if(present("/domains/Praxis/hotel"->query_key_id(109),this_player())) + return 1; + write( "You cannot go in there!"); + return 0; +} + +int room_110() { + if(present("/domains/Praxis/hotel"->query_key_id(110),this_player())) + return 1; + write( "You cannot go in there!"); + return 0; +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/highway1.c b/lib/domains/Praxis/highway1.c new file mode 100644 index 0000000..6ccacfb --- /dev/null +++ b/lib/domains/Praxis/highway1.c @@ -0,0 +1,34 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 3); + SetProperty("no castle", 1); + SetShort( "a dirt highway"); + SetLong( + "You find yourself on a large dirt highway which heads " + "west out of Praxis. In the distance the Daroq Mountains " + "rise majestically over the flat plains of the rest of the lands. " + "This area is rather sparse, with just a small smattering of trees. " + "There appears to have been grass here a long time ago, but it has " + "been ruined from the many adventurers that traverse these parts. " + "East leads to West Boc La road and east takes you to the highway "); + SetItems( + (["highway" : "A highway linking Praxis to the western lands " + "of Nightmare.", + ({ "trees", "tree" }) : "The trees are very small. This isn't " + "a very good environment for them to grow in.", + "village" : "A tiny adventuring village. They have many " + "services there.", + "mountains" : "The Daroq Mountains are far to the west." + ]) ); + SetSkyDomain("town"); + SetExits( + (["west" : "/domains/Praxis/highway2", + "east" : "/domains/Praxis/w_boc_la3"]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/highway2.c b/lib/domains/Praxis/highway2.c new file mode 100644 index 0000000..b523ab2 --- /dev/null +++ b/lib/domains/Praxis/highway2.c @@ -0,0 +1,40 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperties( (["light": 3, "no castle" : 1 ])); + SetShort( "the great western highway"); + SetLong( + "The Great Western Highway, extending both east and west, allows " + "travel between the mountains and the many other villages of " + "this land. The further west you travel, more dry and arid the air " + "becomes. The highway has become very dusty, and starting to " + "blend in with the rest of the earth, making the path almost " + "indistinguishable. Looking beyond the Daraq mountains you " + "can see the beginnings of the Qajip Desert."); + SetItems( + (["highway" : "A well-traveled dirt road between the " + "mountains in the west and the populated towns of the east.", + "lands" : "You are in a forested valley with the Daroq " + "Mountains in the west.", + "mountains" : "The Daroq Mountains, home of vile goblins.", + "mountain" : "Trendahl Mountain.", + "daroq mountains" : "Evil goblins live in the " + "tunnels that thread the mountains."]) ); + SetSkyDomain("town"); + SetExits( ([ + "west" : "/domains/Praxis/highway3", + "east" : "/domains/Praxis/highway1", + ]) ); +} + +void reset() { + ::reset(); + if(!present("bag")) + new("/domains/Praxis/obj/misc/bag")->move(this_object()); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/highway3.c b/lib/domains/Praxis/highway3.c new file mode 100644 index 0000000..de2bad1 --- /dev/null +++ b/lib/domains/Praxis/highway3.c @@ -0,0 +1,46 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void init() { + ::init(); + add_action("go_north", "north"); +} + +void create() { + ::create(); + SetProperty("light", 3); + SetProperty("no castle", 1); + SetShort( "the western highway in the shadows of the Daroq Mountains"); + SetLong( + "The Daroq Mountains tower above you to the west, blocking " + "out the sky so much that an eerie twilight covers the land. " + "There is a small overgrown path to the south heading towards " + "some rather ominous-looking peaks in the distance. " + "The Great Western Highway, which provides a route of travel " + "east, ends just west of here in a mountain pass. There is only " + "a small break in the forest that surrounds you to the north."); + SetItems( + (["peaks" : "The peaks you see are the twin peaks of the " + "Destiny Mountains.", + "path" : "The path is very overgrown and seems to go in " + "the direction of the peaks in\nthe distance.", + "mountains" : "A huge mountain range that seperates the " + "barren Qajip Desert from the fertile lands of the east.", + "mountain" : "Kateihl Mountain, a known stronghold of goblins.", + "highway" : "The Great Western Highway ends here at a " + "mountain pass.", + ({"pass", "break"}) : "It is just large enough for you to get " + "through.", + "forest" : "A very dark, uninviting forest."]) ); + SetSkyDomain("town"); + SetExits( + (["west" : "/domains/Praxis/pass1", + "north" : "/domains/Praxis/orc_valley/guard", + "east" : "/domains/Praxis/highway2"]) ); +} + +int go_north() { + this_player()->eventMoveLiving("/domains/Praxis/orc_valley/guard", "north"); + return 1; +} diff --git a/lib/domains/Praxis/hm_chamber.c b/lib/domains/Praxis/hm_chamber.c new file mode 100644 index 0000000..12e1504 --- /dev/null +++ b/lib/domains/Praxis/hm_chamber.c @@ -0,0 +1,56 @@ +//High Mortal Meeting Room written by Lassondra of Sunshine +//with help from that Borg geek 5/8/94 +inherit "/lib/std/room"; + +int CanReceive(object ob) { + if(!userp(ob) || high_mortalp(ob) || creatorp (ob)) return 1; + write( "You cannot go in there!"); + return 0; +} + +void init() { + ::init(); + add_action( "sit", "sit" ); +} + +void create(){ + object ob; + ::create(); + SetProperties( ([ "light" : 3, "no steal" : 1, "no magic" : 1, + "no teleport" : 1, "no attack" : 1, "no castle" : 1, "no bump" : 1 ]) ); + SetShort( "the High Mortal Chamber" ); + SetLong( "You have entered the forum for the High Mortals of the " + "Nightmare reality. You see a large round table standing in the middle " + "of the room, surrounded by oaken chairs. %^BLUE%^Blue%^RESET%^ carpet " + "is on the floor, and the walls have been painted a cream colour. " + ); + SetItems( ([ + "table" : "A large, round oaken table.", + "chairs" : "The chairs match the wood of the table.", + "carpet" : "The carpet is a deep blue.", + "walls" : "The walls are cream coloured." + ]) ); + SetExits( ([ "east" : "/domains/Praxis/ombud_hall.c" ]) ); + + ob = new("/lib/bboard"); + ob->SetKeyName("board"); + ob->SetId( ({ "board", "high mortal board", "bulletin board"}) ); + ob->set_board_id("hm_board"); + ob->set_max_posts(30); + ob->set_edit_ok( ({"lassondra"}) ); + ob->set_location("/domains/Praxis/hm_chamber"); + ob->SetShort( "the High Mortal board of wisdom"); + ob->SetLong( "This is the High Mortals board of wisdom. It "+ + "is used for the High Mortals to discuss issues "+ + "concerning the welfare of the mud. "); +} + +int sit(string str) { + if(!str || str!="chair" ) { + notify_fail( "Sit where\n?"); + return 0; + } + + write( "You sit down in the oaken chair."); + return 1; +} diff --git a/lib/domains/Praxis/hole.c b/lib/domains/Praxis/hole.c new file mode 100644 index 0000000..8015e87 --- /dev/null +++ b/lib/domains/Praxis/hole.c @@ -0,0 +1,39 @@ +inherit "/lib/std/room"; + +void create() { + ::create(); + SetProperty("light", 0); + SetShort( "A hole in the ground"); + SetLong( + "You are in a deep hole in the ground. The light is very poor " + "down here."); + SetNoClean(1); + SetExits( ([ ]) ); +} + +void fixing_a_hole() { + RemoveItem("hole"); + RemoveExit("up"); +} + +void digging() { + AddItem("hole", "A hole up to the surface."); AddExit( "up", "/domains/Praxis/west_road2"); + +} + +void reset() { + object money; + ::reset(); + if(!present("match")) + new("/domains/Praxis/obj/misc/match")->move(this_object()); + if(!present("money")) { + money = new("/lib/pile"); + money->SetCurrency("platinum", random(5)); + money->SetCurrency("silver", random(100)); + money->SetCurrency("copper", random(1000)); + money->move(this_object()); + } +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/hospital.c b/lib/domains/Praxis/hospital.c new file mode 100644 index 0000000..a6b035a --- /dev/null +++ b/lib/domains/Praxis/hospital.c @@ -0,0 +1,256 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_ROOM; + +#define COST money/bonus +#define MAX_DONATION 600 + +mapping blood; + +void init() { + ::init(); + add_action("new_body", "renew"); + add_action("clean_poison", "clean"); + add_action("regenerate", "regenerate"); + add_action("read", "read"); + add_action("donate", "donate"); + add_action("transfuse", "transfuse"); +} + +void create() { + ::create(); + SetProperties( (["light" :2 , "indoors" :1 , "castle" : 1 ]) ); + SetShort( "the hospital of Praxis"); + SetLong( + "You are in the hospital of Praxis. It basically consists " + "of one large single room, with several crude beds placed in rows. " + "The hospital doesn't look to be to clean, you might want to think " + "twice before engaging their services. A list of all the services " + "that can be performed is posted on the far wall. The exit back to the " + "main road is east."); + SetItems( + (["list" : "You can read all the services by typing <read list>.", + "hospital" : "The clerics here specialize in regenerating " + "lost limbs.", + "clerics" : "They are mending the wounds of patients.", + "cleric" : "He is mending a patient's wounds."])); + SetExits( + (["east" : "/domains/Praxis/n_centre2"]) ); + blood = ([ "who": ([]), "hp":200, "mp":200 ]); + SetProperty("no teleport", 1); +} + +int new_body(string str) { + object *inv; + int i; + + if( this_player()->query_level() != 1) { + notify_fail("The clerics only perform this service for the inexperienced.\n"); + return 0; + } + inv = all_inventory(this_player()); + for(i=0; i<sizeof(inv); i++) { + inv[i]->unequip(); + } + write("A cleric comes over to you and mutters a small prayer."); + write("You again have all the limbs you were born with!"); + say("A cleric mutters a small prayer for the novice "+this_player()->query_cap_name()+".", this_player()); + this_player()->new_body(); + return 1; +} + +int read(string str) { + if(!str) { + notify_fail("Read what?\n"); + return 0; + } + if(str != "list") { + notify_fail("That is not here for reading.\n"); + return 0; + } + message("info", "Welcome to the Cleric's Hospital of Praxis!",this_player()); + message("Ninfo", + "The clerics perform the following services:\n" + "------------------------------------------------------------------\n" + "<renew body>: This is a charity service the clerics perform for\n" + " novice adventurers who have lost limbs while adventuring.\n" + " All limbs are replaced.\n" + "<regenerate [limb]>: This service is for the experienced adventurer\n" + " who has lost limbs. The limb is replaced and acts like new.\n" + " Tithe schedule for regeneration:\n" + " from "+currency_value(320, "gold")+" gold for minor limbs (non-clerics)\n" + " to "+currency_value(800, "gold")+" gold for major limbs (non-clerics)\n" + " "+currency_value(240, "gold")+" to "+currency_value(600, "gold")+" gold for clerics\n" + "<clean poison>: Helps remove some of the poison from your body.\n" + "\ttithe: "+currency_value(50, "gold")+" gold\n" + "<donate # (hp or mp) of blood>: Donates some of your blood in\n" + "\texchange for gold.\n" + "<transfuse # (hp or mp)>: Transfuse some blood int hp or mp into your body\n" + "\ttithe: amount times "+currency_value(3, "gold")+" gold.\n" + "Currently: "+blood["hp"]+" hp blood and "+blood["mp"]+" mp blood free.\n" + "------------------------------------------------------------------\n" + "Half off all regenerations with the severed limb!\n" + "Your tithe is used only toward good causes.\n", this_player()); + return 1; +} + +int clean_poison(string str) { + object tp; + + if(!str) return 0; + if(str != "poison") return 0; + tp = this_player(); + if(tp->query_poisoning()<1) { + notify_fail("A cleric whispers to you: But you are not poisoned!\n"); + return 0; + } + if(tp->query_money("gold") < currency_value(50, "gold")) { + notify_fail("You do not have enough gold for the tithe.\n"); + return 0; + } + tp->AddCurrency("gold", -currency_value(50, "gold")); + tp->add_poisoning(-10); + write("A cleric casts a spell of healing upon you."); + say("A cleric casts a spell of healing on "+tp->query_cap_name()+".", tp); + return 1; +} + +int regenerate(string limb) { + int money, bonus; + mapping limb_info; + object tp; + string *there, *missing; + + tp = this_player(); + if(present(limb, this_player())) bonus = 2; + else bonus = 1; + there = tp->query_limbs(); + missing = this_player()->query_severed_limbs() + + RACES_D->query_limbs(this_player()->query_race()); + /* + checking with the race_d is allowing compatibility with old + versions of the mudlib + */ + if(!missing) { + notify_fail("You aren't missing any limbs!\n"); + return 0; + } + if(member_array(limb, missing) == -1) { + notify_fail("You are not missing that limb!\n"); + return 0; + } + if(member_array(limb, there) != -1) { + notify_fail("You already have that one back!\n"); + return 0; + } + limb_info= RACES_D->query_limb_info(limb,tp->query_race()); + if(!limb_info) { + notify_fail("That limb cannot be replaced!\n"); + return 0; + } + if(limb_info["attach"] != "0") { + if(member_array(limb_info["attach"], there) == -1) { + notify_fail("You would need a "+limb_info["attach"]+" for that!\n"); + return 0; + } + } + if(strsrch(limb, "hand") != -1 || strsrch(limb, "foot") != -1 || + strsrch(limb, "hoof") != -1) { + money = (this_player()->query_class() == "cleric" ? + currency_value(240, "gold") : currency_value(320, "gold")); + } + else money = (this_player()->query_class() == "cleric" ? + currency_value(600, "gold") : currency_value(800, "gold")); + if(tp->query_money("gold") < COST) { + notify_fail("The cleric tells you: You do not have enough gold.\n"); + return 0; + } + tp->AddLimb(limb, limb_info["ref"], tp->query_max_hp()/limb_info["max"], 0, 0); + if(member_array(limb, RACES_D->query_wielding_limbs(tp->query_race())) != -1) + tp->add_wielding_limb(limb); + this_player()->AddCurrency("gold", -COST); + say(sprintf("%s asks the clerics for some help with %s missing %s.", + this_player()->query_cap_name(), possessive(this_player()), limb)); + write("The clerics restore your "+limb+"!"); + return 1; +} + +int donate(string str) { + string what; + int amount, tmp; + + if(!str) { + notify_fail("Donate what?\n"); + return 0; + } + if(sscanf(str, "%d %s of blood", amount, what) !=2) { + notify_fail("Correct syntax: <donate [#] [hp | mp] of blood>\n"); + return 0; + } + if(what != "mp" && what != "hp") { + notify_fail("Donate what?\n"); + return 0; + } + if(blood[this_player()->query_name()]+amount > MAX_DONATION) { + write("You will have to wait before giving that much blood."); + return 1; + } + tmp = call_other(this_player(), "query_"+what); + if(tmp < amount + 5) { + notify_fail("You must have at least 5 more than you plan to give!\n"); + return 0; + } + call_other(this_player(), "add_"+what, -amount); + this_player()->AddCurrency("gold", currency_value(amount/5, "gold")); + blood[what] += amount; + blood["who"][this_player()->query_name()] += amount; + write("You donate some blood for "+(currency_value(amount/5, "gold"))+" gold coins."); + say(this_player()->query_cap_name()+" donates some blood for some gold.", this_player()); + call_out("reduce_donation", 900, ({ this_player(), amount })); + return 1; +} + +int transfuse(string str) { + string what; + int amount; + + if(!str) { + notify_fail("Transfuse what?\n"); + return 0; + } + if(sscanf(str, "%d %s", amount, what) != 2) { + notify_fail("Correct syntax: <transfuse [#] [mp | hp]>\n"); + return 0; + } + if(what != "hp" && what != "mp") { + notify_fail("You cannot do that!\n"); + return 0; + } + if(amount < 1) { + notify_fail("Are you crazy?!?\n"); + return 0; + } + if(blood[what] < amount) { + notify_fail("We do not have that much blood in right now.\n"); + return 0; + } + if(this_player()->query_money("gold") < currency_value(amount*3, "gold")) { + notify_fail("You do not have enough gold for the tithe.\n"); + return 0; + } + this_player()->AddCurrency("gold", -currency_value(amount*3, "gold")); + call_other(this_player(), "add_"+what, amount); + write("You receive a blood transfusion"); + say(this_player()->query_cap_name()+" receives a blood transfusion.", this_player()); + return 1; +} + +void reduce_donation(mixed *tmp) { + blood["who"][tmp[0]] -= tmp[1]; + if(blood["who"][tmp[0]] < 1) map_delete(blood, tmp[0]); +} + + + + diff --git a/lib/domains/Praxis/hotel.c b/lib/domains/Praxis/hotel.c new file mode 100644 index 0000000..7b05904 --- /dev/null +++ b/lib/domains/Praxis/hotel.c @@ -0,0 +1,107 @@ +/* /d/standard/hotel.c + * from Nightmare IV + * a place to stay for rest and other things + * created by Descartes of Borg (what a cutie!) + * and Lassondra@Nightmare 940424 + */ + +#include <lib.h> +#include <clock.h> +#include <daemons.h> + +inherit LIB_ROOM; + +int query_occupied(int chambre); +string query_key_id(int chambre); +object query_room(int chambre); +void check_out(); +static private void random_key(int chambre); + +static private mapping __Rooms; +void create() { + int x; + + room::create(); + SetProperties( ([ "indoors":1, "light":2, "no castle":1]) ); + SetShort("the Nightmare Inn"); + SetLong( + "You find yourself at the entrance of the most prestigious " + "inn in Nightmare. The floor is carpeted with plush red carpet, " + "and the walls are trimmed with golden paint. Large oaken " + "doors from where you entered stand behind you, and directly " + "in front of you the front desk of the hotel stands." + " Type list to see the available rooms, and <rent 'type'> to rent a certain type of room." + ); + SetItems( ([ "entrance" : "The lobby of the hotel is very " + "large and spacious. It looks like it is a rather " + "expensive hotel.", + "floor" : "The floor is covered with a very thick " + "red carpet, with golden fringes at the edges.", + "carpet" : "The carpet is in good shape, although " + "it is a bit worn in spots. There is a golden " + "symbol of the hotel standing in the center of it.", + ({ "wall", "walls" }) : + "The walls have been painted white with some gold " + "trim on all the edges.", + ({ "doors", "door" }) : + "The heavy oaken doors are ornately carved with " + "the hotel ensignia. The doors gleam in the light " + "from the large amount of polishing they receive.", + "desk" : "The front desk is also made from oak, and " + "stands at the back of the lobby.", + "hotel" : "You are in the Nightmare Inn." + ]) + ); + SetExits( ([ + "north" : "/domains/Praxis/hall", + "west" : "/domains/Praxis/n_centre1.c", + ]) ); + // if(!event_pending(this_object())) { + // if((x=hour(time())) > 9) x= (9+(20-x))*HOUR; + // else x = HOUR*(9-x); + // event("check_out", x, 0, 1); + // } + // SetNoClean(1); + // __Rooms = allocate_mapping(10); + // this_object()->check_out(); +} +void reset() { + int x; + + room::reset(); + if(present("receptionist")) return; + new("/domains/Praxis/obj/mon/receptionist")->move(this_object()); +} +void set_occupied(int x) { __Rooms[x]["occupied"] = 1; } +int query_occupied(int chambre) { + return __Rooms[chambre]["occupied"]; +} +string query_key_id(int chambre) { + return __Rooms[chambre]["key id"]; +} + +object query_room(int x) { + return load_object(sprintf("/domains/Praxis/inn%d", x)); +} +void check_out() { + object *tmp; + int i, j; + + if(previous_object() != this_object() && + base_name(previous_object()) != EVENTS_D) return; + for(i=1; i<11; i++) { + __Rooms[100+i] = ([ "occupied":0, "key id": random_key(100+i) ]); + j = sizeof(tmp = livings() & all_inventory(query_room(100+i))); + while(j--) { + message("my_action", "Check out time!\nThe receptionist " + "hurries you out into the lobby.", tmp[j]); + tmp[j]->eventMoveLiving("/domains/Praxis/hotel", "out"); + } + } +} +string random_key(int chambre) { + return sprintf("praxishotel%d%d", chambre, random(100)); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/house.c b/lib/domains/Praxis/house.c new file mode 100644 index 0000000..d265fd7 --- /dev/null +++ b/lib/domains/Praxis/house.c @@ -0,0 +1,62 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperties( ([ "no castle" : 1,"light" : 2, "indoors" : 1]) ); + SetShort("a house with a thatched roof"); + SetLong( + "The small thatch covered house has been standing for many years. " + "It is the dwelling of an old, dishonored knight. The house " + "is very sparse, devoid of any decorations or furnishings. The knight " + "is quite poor and cannot afford any more than a few meager belongings. " + "A rough wooden door leads into a room to the south, " + "and north leads back to Sun Alley."); + SetItems( + (["thatch" : "It is beginning to suffer from the weather " + "and ill-keeping.", + "house" : "It is very unimpressive.", + "furnishing" : "Nothing.", + "decoration" : "Absolutely nothing.", + "door" : (: this_object(), "look_at_door" :) ]) ); + SetExits( ([ + "north" : "/domains/Praxis/sun1", + ]) ); + SetDoor("/domains/Praxis/locked", "south"); + //present("knight")->eventForce("close door"); + //present("knight")->eventForce("lock door with key"); +} + +void reset() { + object mon, key; + + ::reset(); + if(!present("knight")) { + mon = new("/domains/Praxis/obj/mon/knight"); + mon->move(this_object()); + new("/domains/Praxis/obj/armour/helm")->move(mon); + mon->command("wear helm"); + key = new(LIB_ITEM); + key->SetKeyName("key"); + key->SetId( ({ "key", "honor key" }) ); + key->SetShort( "a wooden key"); + key->SetLong("The wooden key is very coarse, and rough. " + "It doesn't look like it would lead to anything of " + "importance."); + key->SetValue(15); + key->SetMass(40); + key->move(mon); + } + if(query_reset_number() != 1) { + //present("knight")->eventForce("close door"); + //present("knight")->eventForce("lock door with key"); + } +} + +void look_at_door() { + write("It is a door."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/idle_storage.c b/lib/domains/Praxis/idle_storage.c new file mode 100644 index 0000000..d699d00 --- /dev/null +++ b/lib/domains/Praxis/idle_storage.c @@ -0,0 +1,11 @@ +inherit "/lib/std/room"; + +void create() { + ::create(); + SetShort( "Adventurer's Supply Storage Room"); + SetLong( "Horace stores weapons and such here.\n"); + SetExits( (["south" : "/domains/Praxis/supply"]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/idle_supply.c b/lib/domains/Praxis/idle_supply.c new file mode 100644 index 0000000..94b93b7 --- /dev/null +++ b/lib/domains/Praxis/idle_supply.c @@ -0,0 +1,48 @@ +inherit "/lib/std/room"; + +void init() { + ::init(); + add_action("go_north", "north"); +} + +void create() { + ::create(); + SetProperty("light", 2); + SetProperty("indoors", 1); + SetShort( "Horace's Adventurer's Supply Shop"); + SetLong( + "Welcome to Horace's Adventurer's Supply Shop!\n" + "Horace buys and sells goods created for and found " + "by adventurer's when he is in. The store opens out " + "onto Boc La Road south. There is a passage to the " + "north guarded by a magic field."); + SetItems( + (["shop" : "You can buy and sell things here.", + "passage" : "Horace keeps the things he has for sale back there.", + "road" : "Boc La Road."]) ); + SetExits( + (["south" : "/domains/Praxis/e_boc_la2"]) ); + SetProperty("no castle", 1); +} + +void reset() { + ::reset(); + if(!present("horace")) + new("/domains/Praxis/obj/mon/horace")->move(this_object()); +} + +int go_north() { + if(this_player()->query_position() == "player" || + this_player()->query_position() == "high mortal") { + write("The magic of Horace stops you."); + say(this_player()->query_cap_name()+" is stopped by the magic of Horace.", + this_player()); + return 1; + } + write("You cannot be stopped by Horace's magic."); + say(this_player()->query_cap_name()+" cannot be stopped by Horace's "+ + "magic.", this_player()); + this_player()->eventMoveLiving("/domains/Praxis/storage", "north"); + return 1; +} + diff --git a/lib/domains/Praxis/immortal_hall.c b/lib/domains/Praxis/immortal_hall.c new file mode 100644 index 0000000..4c14472 --- /dev/null +++ b/lib/domains/Praxis/immortal_hall.c @@ -0,0 +1,29 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 1); + SetProperty("indoors", 1); + SetProperty("no castle", 1); + SetShort( "The Hall of Immortals"); + SetLong( + "Welcome to the hall of immortals!\n" + "High mortals come here to seek mentors who will guide them into " + "the world of immortality. Mortals come here to prove " + "their worthiness for high mortalhood. A spiral flight " + "of stairs leads up out of the cellar."); + SetExits( + (["up" : "/domains/Praxis/stairs"]) ); + SetProperty("no castle", 1); +} + +void reset() { + ::reset(); + if(!present("unity")) + new("/domains/Praxis/obj/mon/unity")->move(this_object()); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/inn101.c b/lib/domains/Praxis/inn101.c new file mode 100644 index 0000000..8ee306a --- /dev/null +++ b/lib/domains/Praxis/inn101.c @@ -0,0 +1,53 @@ +inherit "/lib/std/room"; + +void init() { + ::init(); + add_action( "leave", "leave" ); + add_action( "bounce", "bounce" ); +} + +void create() { + ::create(); + SetProperties( ([ "light" : 2, "no castle" : 1 ]) ); + SetShort( "a sleeping chamber" ); + SetLong( "You have entered one of the sleeping chambers of " + "the posh Nightmare Inn. The room is in perfect order. " + "A large bed sits in the middle of the room, surrounded " + "by night stands on both side. A crystal lamp rests " + "the nightstand on the right. The carpet is a lovely " + "shade of sand, and the furniture is a deep oaken " + "color. In order to exit the room, try 'leave'." ); + SetItems( ([ + ({ "room", "chambers", "chamber" }) : + "The chamber is a very comfortable room.", + "inn" : "The Nightmare Inn is reputed to be the best " + "in the land.", + "bed" : "The bed is very large and comfortable. It " + "looks like it would be fun to bounce on.", + ({ "night stand", "night stands" }) : + "The night stands are very solid oaken structures.", + "lamp" : "The lamp is a very old antique lamp that " + "is made out of fine crystal.", + "carpet" : "The carpet is a very soothing shade of " + "beige.", ]) ); + SetExits( ([ + "west" : "/domains/Praxis/hall.c", + ]) ); + +} + +int bounce(string str) { + if(!str || str!="bed" ) { + notify_fail( "Bounce on what?\n"); + return 0; + } + + write( "You bounce up and down on the bed happily."); + return 1; +} +int leave(string str) { + write( "You open the door to your hotel room and venture out " + "into the hallway." ); + this_player()->eventMoveLiving( "/domains/Praxis/hall.c"); + return 1; +} diff --git a/lib/domains/Praxis/inn102.c b/lib/domains/Praxis/inn102.c new file mode 100644 index 0000000..dfd47ad --- /dev/null +++ b/lib/domains/Praxis/inn102.c @@ -0,0 +1,53 @@ +inherit "/lib/std/room"; + +void init() { + ::init(); + add_action( "leave", "leave" ); + add_action( "bounce", "bounce" ); +} + +void create() { + ::create(); + SetProperties( ([ "light" : 2, "no castle" : 1 ]) ); + SetShort( "a sleeping chamber" ); + SetLong( "You have entered one of the sleeping chambers of " + "the posh Nightmare Inn. The room is in perfect order. " + "A large bed sits in the middle of the room, surrounded " + "by night stands on both side. A crystal lamp rests " + "the nightstand on the right. The carpet is a lovely " + "shade of sand, and the furniture is a deep oaken " + "color. In order to exit the room, try 'leave'." ); + SetItems( ([ + ({ "room", "chambers", "chamber" }) : + "The chamber is a very comfortable room.", + "inn" : "The Nightmare Inn is reputed to be the best " + "in the land.", + "bed" : "The bed is very large and comfortable. It " + "looks like it would be fun to bounce on.", + ({ "night stand", "night stands" }) : + "The night stands are very solid oaken structures.", + "lamp" : "The lamp is a very old antique lamp that " + "is made out of fine crystal.", + "carpet" : "The carpet is a very soothing shade of " + "beige.", ]) ); + SetExits( ([ + "east" : "/domains/Praxis/hall.c", + ]) ); + +} + +int bounce(string str) { + if(!str || str!="bed" ) { + notify_fail( "Bounce on what?\n"); + return 0; + } + + write( "You bounce up and down on the bed happily."); + return 1; +} +int leave(string str) { + write( "You open the door to your hotel room and venture out " + "into the hallway." ); + this_player()->eventMoveLiving( "/domains/Praxis/hall.c"); + return 1; +} diff --git a/lib/domains/Praxis/inn103.c b/lib/domains/Praxis/inn103.c new file mode 100644 index 0000000..57e0c13 --- /dev/null +++ b/lib/domains/Praxis/inn103.c @@ -0,0 +1,53 @@ +inherit "/lib/std/room"; + +void init() { + ::init(); + add_action( "leave", "leave" ); + add_action( "bounce", "bounce" ); +} + +void create() { + ::create(); + SetProperties( ([ "light" : 2, "no castle" : 1 ]) ); + SetShort( "a sleeping chamber" ); + SetLong( "You have entered one of the sleeping chambers of " + "the posh Nightmare Inn. The room is in perfect order. " + "A large bed sits in the middle of the room, surrounded " + "by night stands on both side. A crystal lamp rests " + "the nightstand on the right. The carpet is a lovely " + "shade of sand, and the furniture is a deep oaken " + "color. In order to exit the room, try 'leave'." ); + SetItems( ([ + ({ "room", "chambers", "chamber" }) : + "The chamber is a very comfortable room.", + "inn" : "The Nightmare Inn is reputed to be the best " + "in the land.", + "bed" : "The bed is very large and comfortable. It " + "looks like it would be fun to bounce on.", + ({ "night stand", "night stands" }) : + "The night stands are very solid oaken structures.", + "lamp" : "The lamp is a very old antique lamp that " + "is made out of fine crystal.", + "carpet" : "The carpet is a very soothing shade of " + "beige.", ]) ); + SetExits( ([ + "west" : "/domains/Praxis/hall2.c", + ]) ); + +} + +int bounce(string str) { + if(!str || str!="bed" ) { + notify_fail( "Bounce on what?\n"); + return 0; + } + + write( "You bounce up and down on the bed happily."); + return 1; +} +int leave(string str) { + write( "You open the door to your hotel room and venture out " + "into the hallway." ); + this_player()->eventMoveLiving( "/domains/Praxis/hall2.c"); + return 1; +} diff --git a/lib/domains/Praxis/inn104.c b/lib/domains/Praxis/inn104.c new file mode 100644 index 0000000..3f2b5ff --- /dev/null +++ b/lib/domains/Praxis/inn104.c @@ -0,0 +1,53 @@ +inherit "/lib/std/room"; + +void init() { + ::init(); + add_action( "leave", "leave" ); + add_action( "bounce", "bounce" ); +} + +void create() { + ::create(); + SetProperties( ([ "light" : 2, "no castle" : 1 ]) ); + SetShort( "a sleeping chamber" ); + SetLong( "You have entered one of the sleeping chambers of " + "the posh Nightmare Inn. The room is in perfect order. " + "A large bed sits in the middle of the room, surrounded " + "by night stands on both side. A crystal lamp rests " + "the nightstand on the right. The carpet is a lovely " + "shade of sand, and the furniture is a deep oaken " + "color. In order to exit the room, try 'leave'." ); + SetItems( ([ + ({ "room", "chambers", "chamber" }) : + "The chamber is a very comfortable room.", + "inn" : "The Nightmare Inn is reputed to be the best " + "in the land.", + "bed" : "The bed is very large and comfortable. It " + "looks like it would be fun to bounce on.", + ({ "night stand", "night stands" }) : + "The night stands are very solid oaken structures.", + "lamp" : "The lamp is a very old antique lamp that " + "is made out of fine crystal.", + "carpet" : "The carpet is a very soothing shade of " + "beige.", ]) ); + SetExits( ([ + "east" : "/domains/Praxis/hall2.c", + ]) ); + +} + +int bounce(string str) { + if(!str || str!="bed" ) { + notify_fail( "Bounce on what?\n"); + return 0; + } + + write( "You bounce up and down on the bed happily."); + return 1; +} +int leave(string str) { + write( "You open the door to your hotel room and venture out " + "into the hallway." ); + this_player()->eventMoveLiving( "/domains/Praxis/hall2.c"); + return 1; +} diff --git a/lib/domains/Praxis/inn105.c b/lib/domains/Praxis/inn105.c new file mode 100644 index 0000000..54ede00 --- /dev/null +++ b/lib/domains/Praxis/inn105.c @@ -0,0 +1,31 @@ +inherit "/lib/std/room"; + + +void create() { + ::create(); + SetProperties( ([ "light" : 2, "no castle" : 1 ]) ); + SetShort( "a deluxe sleeping chamber" ); + SetLong( "You have entered one of the deluxe rooms of the Nightmare " + "Inn. A large bed covered with a light blue satin comforter stands " + "in the middle of the room. A wooden closet is off to your right, and " + "to oaken nightstands have been placed on either side of the bed. " + "A crystal vase filled with roses has been placed on the bureau " + "against the back wall. To exit the room, type 'leave'."); + SetItems( ([ ({ "rooms", "room" }) : + "The room is one of the deluxe suites at the Nightmare Inn.", + "bed" : "The bed is very large and comfortable looking.", + "closet" : "The wooden closet is off in the corner.", + "vase" : "The vase is filled with fresh roses.", + "bureau" : "The wooden bureau has been placed against the far wall.", + "wall" : "The wall has been recently painted a creamy white colour.", + "nightstand" : "The nightstand have been made out of a high quality " + "wood.", + ]) ); + SetExits( ([ + "leave" : "/domains/Praxis/hall3", + "west" : "/domains/Praxis/hall3.c", + ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/inn106.c b/lib/domains/Praxis/inn106.c new file mode 100644 index 0000000..62b338c --- /dev/null +++ b/lib/domains/Praxis/inn106.c @@ -0,0 +1,31 @@ +inherit "/lib/std/room"; + + +void create() { + ::create(); + SetProperties( ([ "light" : 2, "no castle" : 1 ]) ); + SetShort( "a deluxe sleeping chamber" ); + SetLong( "You have entered one of the deluxe rooms of the Nightmare " + "Inn. A large bed covered with a light blue satin comforter stands " + "in the middle of the room. A wooden closet is off to your right, and " + "to oaken nightstands have been placed on either side of the bed. " + "A crystal vase filled with roses has been placed on the bureau " + "against the back wall. To exit the room, type 'leave'."); + SetItems( ([ ({ "rooms", "room" }) : + "The room is one of the deluxe suites at the Nightmare Inn.", + "bed" : "The bed is very large and comfortable looking.", + "closet" : "The wooden closet is off in the corner.", + "vase" : "The vase is filled with fresh roses.", + "bureau" : "The wooden bureau has been placed against the far wall.", + "wall" : "The wall has been recently painted a creamy white colour.", + "nightstand" : "The nightstand have been made out of a high quality " + "wood.", + ]) ); + SetExits( ([ + "leave" : "/domains/Praxis/hall3", + "east" : "/domains/Praxis/hall3.c", + ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/inn107.c b/lib/domains/Praxis/inn107.c new file mode 100644 index 0000000..28ca071 --- /dev/null +++ b/lib/domains/Praxis/inn107.c @@ -0,0 +1,31 @@ +inherit "/lib/std/room"; + + +void create() { + ::create(); + SetProperties( ([ "light" : 2, "no castle" : 1 ]) ); + SetShort( "a deluxe sleeping chamber" ); + SetLong( "You have entered one of the deluxe rooms of the Nightmare " + "Inn. A large bed covered with a light blue satin comforter stands " + "in the middle of the room. A wooden closet is off to your right, and " + "to oaken nightstands have been placed on either side of the bed. " + "A crystal vase filled with roses has been placed on the bureau " + "against the back wall. To exit the room, type 'leave'."); + SetItems( ([ ({ "rooms", "room" }) : + "The room is one of the deluxe suites at the Nightmare Inn.", + "bed" : "The bed is very large and comfortable looking.", + "closet" : "The wooden closet is off in the corner.", + "vase" : "The vase is filled with fresh roses.", + "bureau" : "The wooden bureau has been placed against the far wall.", + "wall" : "The wall has been recently painted a creamy white colour.", + "nightstand" : "The nightstand have been made out of a high quality " + "wood.", + ]) ); + SetExits( ([ + "leave" : "/domains/Praxis/hall3", + "west" : "/domains/Praxis/hall4.c", + ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/inn108.c b/lib/domains/Praxis/inn108.c new file mode 100644 index 0000000..dc3a5a3 --- /dev/null +++ b/lib/domains/Praxis/inn108.c @@ -0,0 +1,31 @@ +inherit "/lib/std/room"; + + +void create() { + ::create(); + SetProperties( ([ "light" : 2, "no castle" : 1 ]) ); + SetShort( "a deluxe sleeping chamber" ); + SetLong( "You have entered one of the deluxe rooms of the Nightmare " + "Inn. A large bed covered with a light blue satin comforter stands " + "in the middle of the room. A wooden closet is off to your right, and " + "to oaken nightstands have been placed on either side of the bed. " + "A crystal vase filled with roses has been placed on the bureau " + "against the back wall. To exit the room, type 'leave'."); + SetItems( ([ ({ "rooms", "room" }) : + "The room is one of the deluxe suites at the Nightmare Inn.", + "bed" : "The bed is very large and comfortable looking.", + "closet" : "The wooden closet is off in the corner.", + "vase" : "The vase is filled with fresh roses.", + "bureau" : "The wooden bureau has been placed against the far wall.", + "wall" : "The wall has been recently painted a creamy white colour.", + "nightstand" : "The nightstand have been made out of a high quality " + "wood.", + ]) ); + SetExits( ([ + "leave" : "/domains/Praxis/hall3", + "east" : "/domains/Praxis/hall4.c", + ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/inn109.c b/lib/domains/Praxis/inn109.c new file mode 100644 index 0000000..b951e2d --- /dev/null +++ b/lib/domains/Praxis/inn109.c @@ -0,0 +1,36 @@ +//Lassondra@Nightmare +inherit "/lib/std/room"; + + +void create() { + ::create(); + SetShort("the honeymoon suite" ); + SetProperties( ([ "no castle" : 1, "light" : 2 ]) ); + SetLong( "The honeymoon suite is a very luxurious room. A large " + "bed, made up with a emerald green silk comforter stands in themiddle " + "of the room. The carpet beneath your feet is a dark beige colour, " + "almost a perfect match for the wooden hue of the nightstand and " + "bureau. Large double doors with golden handles lead into and " + "out of the suite." ); + SetItems( ([ "suite" : "The suite is a very large and expensive " + "looking room at the Nightmare Inn.", + "room" : "The room is one of the honeymoon suites at the " + "Nightmare Inn.", + "carpet" : "The carpet is very thick and a deep hue of beige.", + "bureau" : "The bureau has been polished many times, you can tell " + "by howit gleems in the light.", + "nightstand" : "The nightstands have been placed on either sides " + "iof the bed.", + ({ "doors", "door" }) : "The large opaken doors are a very " + "deep shade of mahogany.", + ({ "handles", "handle" }) : "The handles on the double doors " + "are golden." + ]) ); + SetExits( ([ + "leave" : "/domains/Praxis/hall5", + "west" : "/domains/Praxis/hall5.c", + ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/inn110.c b/lib/domains/Praxis/inn110.c new file mode 100644 index 0000000..88370ed --- /dev/null +++ b/lib/domains/Praxis/inn110.c @@ -0,0 +1,36 @@ +//Lassondra@Nightmare +inherit "/lib/std/room"; + + +void create() { + ::create(); + SetShort("the honeymoon suite" ); + SetProperties( ([ "no castle" : 1, "light" : 2 ]) ); + SetLong( "The honeymoon suite is a very luxurious room. A large " + "bed, made up with a emerald green silk comforter stands in themiddle " + "of the room. The carpet beneath your feet is a dark beige colour, " + "almost a perfect match for the wooden hue of the nightstand and " + "bureau. Large double doors with golden handles lead into and " + "out of the suite." ); + SetItems( ([ "suite" : "The suite is a very large and expensive " + "looking room at the Nightmare Inn.", + "room" : "The room is one of the honeymoon suites at the " + "Nightmare Inn.", + "carpet" : "The carpet is very thick and a deep hue of beige.", + "bureau" : "The bureau has been polished many times, you can tell " + "by howit gleems in the light.", + "nightstand" : "The nightstands have been placed on either sides " + "iof the bed.", + ({ "doors", "door" }) : "The large opaken doors are a very " + "deep shade of mahogany.", + ({ "handles", "handle" }) : "The handles on the double doors " + "are golden." + ]) ); + SetExits( ([ + "leave" : "/domains/Praxis/hall5", + "east" : "/domains/Praxis/hall5.c", + ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/jungle.c b/lib/domains/Praxis/jungle.c new file mode 100644 index 0000000..0050d9a --- /dev/null +++ b/lib/domains/Praxis/jungle.c @@ -0,0 +1,23 @@ +inherit "/lib/std/room"; + +void create() { + ::create(); + SetProperty("light", 2); + SetShort( "The jungle"); + SetLong( + "The jungle is ever increasing in humidity. " + "The vegetation that imposes itself upon you from " + "every direction becomes even thicker to the north and east. " + "It looks a bit tamer as you look south and west."); + SetItems( + (["jungle" : "A growing rain forest full of green vegetation.", + "vegetation" : "All sorts of plant life growing as you have " + "never before seen."]) ); + SetSkyDomain("town"); + SetExits( + (["northeast" : "/domains/Praxis/rain_forest", + "southwest" : "/domains/Praxis/wild2"]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/kataan_hall.c b/lib/domains/Praxis/kataan_hall.c new file mode 100644 index 0000000..f806571 --- /dev/null +++ b/lib/domains/Praxis/kataan_hall.c @@ -0,0 +1,248 @@ +#include <lib.h> +#include <council.h> +#include <daemons.h> + +inherit LIB_ROOM; + +string get_new_title(object tp); +string get_male(int lev); +string get_female(int lev); +string previous_title(object tp); +int get_cost(string which, int lev); + +int CanReceive(object ob) { + if(!VOTING_D->is_time_to_vote()) + return ::CanReceive(ob); + if(creatorp(this_player()) || this_player()->query_level() < 2) + return ::CanReceive(ob); + if(VOTING_D->query_voted(this_player()->query_name(), + this_player()->query_class())) + return ::CanReceive(ob); + else { + message("my_action", "You have not yet voted for your class leader. Please do so now.", this_player()); + call_out("move_me", 5, this_player()); + } + return ::CanReceive(ob); +} + +void move_me(object who) { + who->eventMoveLiving("/domains/Praxis/"+who->query_class()+"_vote"); + return; +} + +void create() { + object ob; + + ::create(); + SetProperties(([ "no attack":1, "no castle" :1, "light":2, "indoors":1])); + SetShort("The central chamber of the kataans"); + SetLong( + "Welcome to the central chamber of the kataans!\n" + "You find yourself in a very dark and damp cave. Shadows dance " + "across the stony walls of the cave, and an aura of evil fills the " + "air. Kataans come here to advance in the art of combat and in magic. " + "The available commands are <cost>, <advance>, <list(number)>, " + "<improve stat>, <train skill amount>, and <roll>. Down through " + "a hole " + "guarded by a shimmering %^BLUE%^blue%^RESET%^ light is the " + "entrance to the main hall. " + "<help skills> will list the full names of all skills."); + SetExits( ([ + "up" : "/domains/Praxis/kataan_join", + "council" : "/domains/Praxis/council_hall", + "east" : "/domains/Praxis/kataan_vote", + ]) ); + + ob = new("/lib/bboard"); + ob->SetKeyName("board"); + ob->SetId( ({ "board", "bulletin board", "board of despair" }) ); + ob->set_board_id("kataan_board"); + ob->set_edit_ok(KATAAN_COUNCIL); + ob->set_max_posts(25); + ob->move("/domains/Praxis/kataan_hall"); + ob->SetShort( "Kataans' Board of Despair"); + ob->SetLong( + "The Kataans of our reality post stories of treachery and " + "demonic myths for all to see here.\n"); +} + +void init() { + ::init(); + add_action("cost","cost"); + add_action("roll","roll"); + add_action("train", "train"); + add_action("improve", "improve"); + add_action("advance","advance"); + add_action("list","list"); +} + +int roll() { call_other("/domains/Praxis/setter", "do_rolls"); return 1; } + +string get_new_title(object tp) +{ + int lev; + string gen, title; + + lev = this_player()->query_level(); + gen = this_player()->query_gender(); + if(this_player()->query_guild()) { + if(present(tp->query_guild()+"_ob", tp)) { + if(lev > 19) title = "High mortal"; + else title = present(tp->query_guild()+"_ob", tp)->query_title(tp); + title += " $N"; + } + else { + if(lev > 19) title = "High mortal $N"; + else title = "$N"; + } + } + else { + if(lev > 20) title = "High mortal $N"; + else title = "$N"; + } + if(lev > 20) title += previous_title(tp); + else if(gen == "male") title += " "+get_male(lev); + else title += " "+get_female(lev); + return title; +} + +string get_male(int lev) { + string *male_title_str; + + if(!male_title_str) male_title_str = allocate(20); + male_title_str[19] ="the supreme high kataan of doom"; + male_title_str[18] ="the supreme kataan of doom"; + male_title_str[17] ="the high kataan of doom"; + male_title_str[16] ="the kataan of doom"; + male_title_str[15] ="the javelin of death"; + male_title_str[14] ="the warmage of evil"; + male_title_str[13] ="the lesser kataan"; + male_title_str[12] ="the great shaman of the underrealms"; + male_title_str[11] ="the shaman of the underrealms"; + male_title_str[10] ="the demonic warmage"; + male_title_str[9] ="the evil warmage"; + male_title_str[8] ="the warmage"; + male_title_str[7] ="the archer of kataan"; + male_title_str[6] ="the shamanic follower of kataan"; + male_title_str[5] ="the bolt thrower"; + male_title_str[4] ="the bolt tosser"; + male_title_str[3] ="the rock thrower"; + male_title_str[2] ="the rock tosser"; + male_title_str[1] ="the pebble thrower"; + male_title_str[0] ="the pebble tosser"; + return male_title_str[lev-1]; +} + +string get_female(int lev) { + return get_male(lev); +} + +int advance() { return ADVANCE_D->advance(); } + +int train(string str) { + string which, which_tmp; + int amount; + + if(!str) { + notify_fail("Correct syntax: <train skill amount>\n"); + return 0; + } + if(sscanf(str, "%s %s %d", which, which_tmp, amount) == 3) which = which+ " "+ which_tmp; + else if(sscanf(str, "%s %d", which, amount) !=2) { + notify_fail("Correct syntax: <train skill amount>\n"); + return 0; + } + which = lower_case(which); + if(!this_player()->skill_exists(which)) { + notify_fail("No such skill.\n"); + return 0; + } + return ADVANCE_D->train_player(this_player(), which, amount); +} + +int improve(string str) { + string *stats; + int stat_cost; + + stats = ({ "strength", "intelligence", "wisdom", "dexterity", "constitution", "charisma" }); + str = lower_case(str); + if(member_array(str, stats) == -1) { + notify_fail("You have no such stat.\n"); + return 0; + } + stat_cost = get_cost(str, this_player()->query_base_stats(str)); + if( this_player()->query_exp()-stat_cost < ADVANCE_D->get_exp( this_player()->query_level() ) ) { + notify_fail("You are not experienced enough to improve yourself in that way.\n"); + return 0; + } + this_player()->SetStat(str, this_player()->query_base_stats(str) + 1); + this_player()->add_exp(-stat_cost); + write("You feel much "); + say(this_player()->query_cap_name()+" looks much "); + if(str == "strength") tell_room(this_object(), "stronger.\n"); + else if(str == "intelligence") tell_room(this_object(), "more intelligent.\n"); + else if(str == "wisdom") tell_room(this_object(), "wiser.\n"); + else if(str == "dexterity") tell_room(this_object(), "more nimble.\n"); + else if(str == "constitution") tell_room(this_object(), "sturdier.\n"); + else tell_room(this_object(), "more attractive.\n"); + return 1; +} + +int get_cost(string stat, int lev) { + switch(stat) { + case "strength": return ADVANCE_D->get_stat_cost(1, lev); break; + case "intelligence": return ADVANCE_D->get_stat_cost(1, lev); break; + case "charisma": return ADVANCE_D->get_stat_cost(1, lev); break; + default: return ADVANCE_D->get_stat_cost(2, lev); break; + } +} + +int cost(string str) { + int bing; + + write("Costs for advancement, training, and improvement:\n"); + bing = ADVANCE_D->get_exp( this_player()->query_level() + 1 ); + if(bing < 1) write("level:\t\tIt will cost you nothing to advance."); + else write("level:\t\t"+bing+"\n"); + write("skills: You train by spending the amount of experience you + desire.\n"); + write("strength:\t\t" + get_cost("strength", + this_player()->query_base_stats("strength")) + + "\t\tconstitution:\t\t" + get_cost("constitution", + this_player()->query_base_stats("constitution")) ); + write("intelligence:\t\t" + get_cost("intelligence", + this_player()->query_base_stats("intelligence")) + + "\t\tdexterity:\t\t" + get_cost("dexterity", + this_player()->query_base_stats("dexterity")) ); + write("wisdom:\t\t" + get_cost("wisdom", + this_player()->query_base_stats("wisdom")) + + "\t\tcharisma:\t\t" + get_cost("charisma", + this_player()->query_base_stats("charisma")) ); + return 1; +} + +string previous_title(object tp) { + string pre, post, str; + + str = tp->getenv("TITLE"); + sscanf(str, "%s $N %s", pre, post); + return post; +} + +int list(string str) { + int x; + + if(!str) "/domains/Praxis/quest_room"->list_quests(this_player(), 0); + else { + if(sscanf(str, "%d", x) != 1) { + notify_fail("You must give the number of the quest you want listed.\n"); + return 0; + } + if(x<1) { + notify_fail("No such quest.\n"); + return 0; + } + "/domains/Praxis/quest_room"->list_quests(this_player(), x); + } + return 1; +} diff --git a/lib/domains/Praxis/kataan_join.c b/lib/domains/Praxis/kataan_join.c new file mode 100644 index 0000000..e6260f4 --- /dev/null +++ b/lib/domains/Praxis/kataan_join.c @@ -0,0 +1,82 @@ +#include <lib.h> +int go_down(); + +inherit LIB_ROOM; + +void init() { + ::init(); + add_action("become", "become"); + add_action("preview","preview"); +} + +void create() { + ::create(); + SetProperties( (["no castle":1,"light":2,"indoors":1,"no castle":1])); + SetShort( "cavern of the kataans"); + SetLong( + "You are in a dark underground cavern just north of Praxis. " + "Deep, intricate murals and symbols are carved into the walls of the " + "cave. Down deeper in the cavern is a passage protected " + "by a shimmering %^BLUE%^blue%^RESET%^ light. " + "<preview> will tell you about becoming a Kataan. "); + SetItems( + (["mural" : "It is very old and depicts gruesome cult practices.", + "murals" : "They are quite ancient and are made up of " + "pictures depicting bizarre rituals.", + "light" : "You are certain that it is a field which allows " + "only kataans to pass.", + "cavern" : "The cavern almost pulses with hidden evil."]) ); + SetExits( + (["up" : "/domains/Praxis/forest3"]) ); + AddExit("down","/domains/Praxis/kataan_hall",(:go_down:)); +} + +int preview() { + if(this_player()->query_class() != "explorer") { + write("This is not for you."); + return 1; + } + say(this_player()->query_cap_name()+" seeks to learn about " + "kataans.", this_player()); + write("Welcome, explorer! "); + write("Kataans are an ancient coven of evil, magical warriors skilled " + "in the use of projectiles and stealth. They are careful to do " + "no acts which might be considered good. Instead, the use the " + "powers given to them by their demon masters to terrorize good " + "beings wherever they may be.\n" + "To become a kataan, type <become kataan>\n"); + return 1; +} + +int become(string str) { + if(!str) { + notify_fail("Become what?\n"); + return 0; + } + if(str != "kataan") { + notify_fail("You cannot become that here.\n"); + return 0; + } + if(this_player()->query_class() != "explorer") { + write("You are much too old to start learning our ways now!"); + return 1; + } + write("The Master Kataan initiates you into the class of kataans."); + say(this_player()->query_cap_name()+" becomes a kataan.", this_player()); + this_player()->SetClass("kataan"); + this_player()->setenv("TITLE", "$N the pebble tosser"); + this_player()->init_skills("kataan"); + this_player()->setenv("start", "/domains/Praxis/kataan_hall"); + return 1; +} + +int go_down() { + if(this_player()->query_class() != "kataan") { + write("You cannot penetrate the force field that blocks the passage."); + say(this_player()->query_cap_name()+" tries to get into the kataan's sanctuary, but fails.", this_player()); + return 0; + } + return 1; +} + + diff --git a/lib/domains/Praxis/kataan_vote.c b/lib/domains/Praxis/kataan_vote.c new file mode 100644 index 0000000..22712a8 --- /dev/null +++ b/lib/domains/Praxis/kataan_vote.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include <voting.h> +#include <daemons.h> + +inherit "/domains/town/room/voters"; + +void create() { + ::create(); + SetProperty("light", 1); + SetProperty("no castle", 1); + SetProperty("indoors", 1); + SetShort( "Voting hall of the kataans"); + SetLong( (: this_object(), "new_long" :)); + SetItems( + (["list" : "During election time, it lists all candidates."]) ); + SetExits( + (["west" : "/domains/Praxis/kataan_hall"]) ); +} + +string new_long() { + if(VOTING_D->election_day()) + return "This is the room where Kataans can put in their bid for office. " + "If you wish to run for office, just type in the command " + "'enter' and you will be added to the list. A list of candidates " + "is posted on the wall."; + else return "This is the voting chamber of the Hall of Kataans. " + "Kataans will gather here for the next election: "+VOTING_D->query_vote_date()+"."; +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/library.c b/lib/domains/Praxis/library.c new file mode 100644 index 0000000..dbe5026 --- /dev/null +++ b/lib/domains/Praxis/library.c @@ -0,0 +1,79 @@ +#include <lib.h> +#include <daemons.h> +#include <dirs.h> + +inherit LIB_ROOM; + +void init() { + ::init(); + add_action("help", "help"); + add_action("read", "read"); +} + +void create() { + ::create(); + SetSmell( "default", "The musty smell of old books fills the room."); + SetProperties((["light":2, "no castle" : 1, "indoors" :1 ]) ); + SetShort( "Praxis Library"); + SetLong( + "Welcome to the Praxis Library of higher learning!\n" + "The library is filled with shelves and shelves full of books, " + "reaching up towards the ceiling. The leather bound books are " + "waiting to be read. East Road is west of the library. " + "The command <read books> will show you what books are available and " + "type <read [title]> to read a particular book."); + SetItems( + (["library" : "The laws of reality are explained in here.", + "shelf" : "It has books on it.", + "shelves" : "Books fill them.", + "book" : "One of many.", + "books" : "They are everywhere on the shelves."]) ); + SetExits( + (["west" : "/domains/Praxis/east_road1"]) ); + +} + +int read(string str) { + string *dir; + string *tmp; + string tmp_str; + int i,j,k; + + if(!str) { + notify_fail("Read what?\n"); + return 0; + } + if(str == "volume" || str == "book") { + notify_fail("Which "+str+"?\n"); + return 0; + } + if(str == "volumes" || str == "books") { + message("info", "The books available for reading are:",this_player()); + dir = get_dir(DIR_LIBRARY + "/"); + for(i=0; i<sizeof(dir); i++) dir[i] = replace_string(dir[i], "_", " "); + message("info", replace_string(format_page(dir, 3), "\n", " "), + this_player()); + message("info", "Type <read [book name]> to read a particular book.", this_player()); + } + else { + str = replace_string(str, " ", "_"); + if(file_size(DIR_LIBRARY + "/"+str) == -1) { + notify_fail("There is no book here by that title.\n"); + return 0; + } + this_player()->more(DIR_LIBRARY + "/"+str); + } + return 1; +} + +int help(string str) { + if(!str) return 0; + if(str != "library") { + notify_fail("You help "+str+".\n"); + return 0; + } + write("You can read what is in the library.\nType <read books>.\n"); + return 1; +} + + diff --git a/lib/domains/Praxis/locked.c b/lib/domains/Praxis/locked.c new file mode 100644 index 0000000..84ef2ea --- /dev/null +++ b/lib/domains/Praxis/locked.c @@ -0,0 +1,31 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void init() { + ::init(); + add_action("any_hook", "", 1); +} + +void create() { + ::create(); + SetNoClean(1); + SetShort("the locked room"); + SetProperties(([ "no scry" : 1, "light" : 1, "indoors" : 1 ])); + SetLong( + "You have been assimilated.\n" + "From this time on, you will service the Borg."); + SetExits( + (["square" : "/domains/Praxis/square"]) ); +} + +static int any_hook(string str) { + message("prompt", sprintf("\n(%s) Password: ", mud_name()), + this_player()); + return 1; +} +int CanReceive(object ob) { + if(!ob) ob = previous_object(); + if(!(ob->query_locked())) return 0; + else return ::CanReceive(ob); +} diff --git a/lib/domains/Praxis/lpc_inner.c b/lib/domains/Praxis/lpc_inner.c new file mode 100644 index 0000000..c2e87d5 --- /dev/null +++ b/lib/domains/Praxis/lpc_inner.c @@ -0,0 +1,27 @@ +inherit "/lib/std/room"; + +void create() { + object ob; + + ::create(); + SetProperty("light", 2); + SetProperty("indoors", 1); + SetShort( "The LPC and MudOS Room"); + SetLong( + "Immortals come here to discuss coding problems. " + "The Hall of Immortals is north of here."); + SetExits( + (["north" : "/domains/Praxis/adv_inner"]) ); + + ob = new("/lib/bboard"); + ob->SetKeyName("board"); + ob->SetId( ({ "board", "irreality board" }) ); + ob->set_board_id("coding"); + ob->set_max_posts(20); + ob->move("/domains/Praxis/lpc_inner"); + ob->SetShort( "the LPC and MudOS Irreality Board"); + ob->SetLong( "Post your questions about coding here.\n"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/lpmud_room.c b/lib/domains/Praxis/lpmud_room.c new file mode 100644 index 0000000..8579a53 --- /dev/null +++ b/lib/domains/Praxis/lpmud_room.c @@ -0,0 +1,31 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + object ob; + + ::create(); + SetProperty("light", 2); + SetProperty("indoors", 1); + SetShort( "The LPMud Room"); + SetLong( + "Advertisements for new LPMuds are posted here. " + "Ads on other boards will be quickly removed."); + SetExits( + (["west" : "/domains/Praxis/adv_main"]) ); + + ob = new("/lib/bboard"); + ob->SetKeyName("board"); + ob->SetId( ({ "board", "lpmud board" }) ); + ob->set_board_id("lpmud"); + ob->set_max_posts(20); + ob->move("/domains/Praxis/lpmud_room"); + ob->SetShort( "LPMud Advertising Board"); + ob->SetLong( "This board exists to promote LPMuds everywhere. " + "Please feel free to post about a mud you know of here.\n"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/mage_hall.c b/lib/domains/Praxis/mage_hall.c new file mode 100644 index 0000000..af0d3c0 --- /dev/null +++ b/lib/domains/Praxis/mage_hall.c @@ -0,0 +1,253 @@ +#include <lib.h> +#include ROOMS_H +#include <council.h> +#include <daemons.h> + +inherit LIB_ROOM; + +string get_new_title(object tp); +string get_male(int lev); +string get_female(int lev); +string previous_title(object tp); +int get_cost(string which, int lev); + +int CanReceive(object ob) { + if(!VOTING_D->is_time_to_vote()) + return ::CanReceive(ob); + if(creatorp(this_player()) || this_player()->query_level() < 2) + return ::CanReceive(ob); + if(VOTING_D->query_voted(this_player()->query_name(), + this_player()->query_class())) + return ::CanReceive(ob); + else { + message("my_action", "You have not yet voted for your class leader. Please do so now.", this_player()); + call_out("move_me", 5, this_player()); + } + return ::CanReceive(ob); +} + +void move_me(object who) { + who->eventMoveLiving("/domains/Praxis/"+who->query_class()+"_vote"); + return; +} + +void create() { + object ob; + + ::create(); + SetProperty("no attack",1); + SetProperty("light", 2); + SetProperty("indoors", 1); + SetShort( "The inner sanctum of the tree of the mages"); + SetLong( + "Welcome into the heart of the mage tree!\n" + "Mages come here to advance their knowledge of the magical arts. " + "The available commands are <cost>, <advance>, <list (number)>, " + "<improve stat>, <train skill amount>, and <roll stats>. Up " + "through a stairway " + "guarded by a shimmering %^BLUE%^blue%^RESET%^ light is the " + "entrance to the tree. " + "<help skills> will list all skills with their full, proper names."); + SetExits( + (["up" : "/domains/Praxis/mage_join", + "council" : "/domains/Praxis/council_hall", + "east" : "/domains/Praxis/mage_vote", + "down" : "/domains/Praxis/roots", + "stairs" : "/domains/Praxis/trunk"]) ); + + ob = new("/lib/bboard"); + ob->SetKeyName("board"); + ob->SetNoClean(1); + ob->SetId( ({ "board", "crystal board", "bulletin board"}) ); + ob->set_board_id("mage_board"); + ob->set_max_posts(25); + ob->set_edit_ok(MAGE_COUNCIL); + ob->move("/domains/Praxis/mage_hall"); + ob->SetShort( "the Crystal Board of Mages"); + ob->SetLong( + "It is a huge slab of crystal into which mages have the power " + "to cast their thoughts about the class of mages.\n"); +} + +void init() { + ::init(); + add_action("cost","cost"); + add_action("roll","roll"); + add_action("train", "train"); + add_action("improve", "improve"); + add_action("advance","advance"); + add_action("list","list"); +} + +int roll(string str) { + if(str != "stats") { + notify_fail("Correct syntax: <roll stats>\n"); + return 0; + } + //ROOM_SETTER->do_rolls(); + return 1; +} + +string get_male(int lev) { + string *male_title_str; + + if(!male_title_str) male_title_str = allocate(20); + male_title_str[19] ="the new high mortal mage"; + male_title_str[18] ="the high mage warlock"; + male_title_str[17] ="the master warlock"; + male_title_str[16] ="the elder warlock"; + male_title_str[15] ="the warlock"; + male_title_str[14] ="the lesser warlock"; + male_title_str[13] ="the master mage"; + male_title_str[12] ="the elder mage"; + male_title_str[11] ="the mage"; + male_title_str[10] ="the low mage"; + male_title_str[9] ="the grand high enchanter"; + male_title_str[8] ="the high enchanter"; + male_title_str[7] ="the enchanter"; + male_title_str[6] ="the low enchanter"; + male_title_str[5] ="the grand master conjurer"; + male_title_str[4] ="the master conjurer"; + male_title_str[3] ="the conjurer"; + male_title_str[2] ="the apprentice conjurer"; + male_title_str[1] ="the inexperienced magic user"; + male_title_str[0] ="the novice mage"; + return male_title_str[lev-1]; +} + +string get_female(int lev) { + string *female_title; + + female_title = ({ + "the new high mortal mage", + "the high mage witch", + "the master witch", + "the elder witch", + "the witch", + "the lesser witch", + "the master mage", + "the elder mage", + "the mage", + "the low mage", + "the grand high enchantress", + "the high enchantress", + "the enchantress", + "the low enchantress", + "the grand master conjuress", + "the master conjuress", + "the conjuress", + "the apprentice conjuress", + "the inexperienced magic user", + "the novice mage" + }); + if(lev>20) lev = 20; + return female_title[20-lev]; +} + +int advance() { return ADVANCE_D->advance(); } + +int train(string str) { + string which, which_tmp; + int amount; + + if(!str) { + notify_fail("Corract syntax: <train skill amount.\n"); + return 0; + } + if(sscanf(str, "%s %s %d", which, which_tmp, amount) == 3) which = which +" "+ which_tmp; + else if(sscanf(str, "%s %d", which, amount) !=2) { + notify_fail("Correct syntax: <train skill amount>\n"); + return 0; + } + which = lower_case(which); + if(!this_player()->skill_exists(which)) { + notify_fail("No such skill.\n"); + return 0; + } + return ADVANCE_D->train_player(this_player(), which, amount); +} + +int improve(string str) { + string *stats; + int stat_cost; + + stats = ({ "strength", "intelligence", "wisdom", "dexterity", "constitution", "charisma" }); + if(!str) { + notify_fail("Improve what?\n"); + return 0; + } + str = lower_case(str); + if(member_array(str, stats) == -1) { + notify_fail("You have no such stat.\n"); + return 0; + } + stat_cost = get_cost(str, this_player()->query_base_stats(str)); + if( this_player()->query_exp()-stat_cost < ADVANCE_D->get_exp( this_player()->query_level() ) ) { + notify_fail("You are not experienced enough to improve yourself in that way.\n"); + return 0; + } + this_player()->SetStat(str, this_player()->query_base_stats(str) + 1); + this_player()->add_exp(-stat_cost); + write("You feel much "); + say(this_player()->query_cap_name()+" looks much "); + if(str == "strength") tell_room(this_object(), "stronger.\n"); + else if(str == "intelligence") tell_room(this_object(), "more intelligent.\n"); + else if(str == "wisdom") tell_room(this_object(), "wiser.\n"); + else if(str == "dexterity") tell_room(this_object(), "more nimble.\n"); + else if(str == "constitution") tell_room(this_object(), "sturdier.\n"); + else tell_room(this_object(), "more attractive.\n"); + return 1; +} + +int get_cost(string stat, int lev) { + switch(stat) { + case "intelligence": return ADVANCE_D->get_stat_cost(1, lev); break; + case "constitution": return ADVANCE_D->get_stat_cost(1, lev); break; + case "wisdom": return ADVANCE_D->get_stat_cost(1, lev); break; + default: return ADVANCE_D->get_stat_cost(2, lev); break; + } +} + +int cost(string str) { + int bing; + + write("Costs for advancement, training, and improvement:\n"); + bing = ADVANCE_D->get_exp( this_player()->query_level() + 1 ); + if(bing < 1) write("level:\t\tIt will cost you nothing to advance."); + else write("level:\t\t"+bing+"\n"); + write("\nskills: You train by spending the amount of experience you + desire.\n"); + write("\n"); + write("strength:\t\t" + get_cost("strength", + this_player()->query_base_stats("strength")) + + "\t\tconstitution:\t\t" + get_cost("constitution", + this_player()->query_base_stats("constitution")) ); + write("intelligence:\t\t" + get_cost("intelligence", + this_player()->query_base_stats("intelligence")) + + "\t\tdexterity:\t\t" + get_cost("dexterity", + this_player()->query_base_stats("dexterity")) ); + write("wisdom:\t\t" + get_cost("wisdom", + this_player()->query_base_stats("wisdom")) + + "\t\tcharisma:\t\t" + get_cost("charisma", + this_player()->query_base_stats("charisma")) ); + return 1; +} + +int list(string str) { + int x; + + if(!str) "/domains/Praxis/quest_room"->list_quests(this_player(), 0); + else { + if(sscanf(str, "%d", x) != 1) { + notify_fail("You must give the number of the quest you want listed.\n"); + return 0; + } + if(x<1) { + notify_fail("No such quest.\n"); + return 0; + } + "/domains/Praxis/quest_room"->list_quests(this_player(), x); + } + return 1; +} + diff --git a/lib/domains/Praxis/mage_join.c b/lib/domains/Praxis/mage_join.c new file mode 100644 index 0000000..7e5ce18 --- /dev/null +++ b/lib/domains/Praxis/mage_join.c @@ -0,0 +1,92 @@ +#include <lib.h> +int go_down(); + +inherit LIB_ROOM; + +void init() { + ::init(); + add_action("become", "become"); + add_action("preview","preview"); +} + +void create() { + ::create(); + SetProperty("light", 2); + SetProperty("indoors", 1); + SetShort( "Inside a tree"); + SetLong( + "The inside of the tree impossibly occupies more space than " + "its physical size! Torches circle the wooden walls of the " + "tree, giving it a magical light. A flight of stairs leads " + "down into a hole in the ground protected by a magical " + "%^BLUE%^blue%^RESET%^ " + "light. The High Mage Warlock waits here to initiate aspiring " + "magic users into the mysterious class of Nightmare mages. " + "<preview> will tell you about becoming a mage."); + SetItems( + (["tree" : "Like Dr. Who's tardis, bigger inside than outside.", + "hole" : "The hole leads down into an undergorund room.", + "light" : "You are certain that it is a field which allows " + "only mages to pass.", + "walls" : "They are made from the wood of this old tree. An " + "opening leads outside.", + "stairs" : "They are very nice.", + "torch" : "It is locked magically into the wall.", + "warlock" : "He awaits to initiate new mages.", + "mage" : "He awaits to initiate new mages and explain " + "the difference between transitive and intransitive verbs.", + "opening" : "It leads out to West Road.", + "torches" : "They create an eerie glow to the room."]) ); + SetExits( + (["out" : "/domains/Praxis/west_road3"]) ); + AddExit("down", "/domains/Praxis/mage_hall.c", (:go_down:)); +} + +int preview() { + if(this_player()->query_class() != "explorer") { + message("info", "This is not for you.", this_player()); + return 1; + } + message("other_action", this_player()->query_cap_name()+" seeks to learn about mages.", this_object(), ({this_player()})); + message("info", "Welcome, explorer!", this_player()); + message("info", "Mages have no overriding beliefs which unite them, but instead " + "they are united in their love of the art of magic. Some of them " + "are devoted practitioners of white magic, while others are evil " + "dark mages. Their magical arts are centered around those " + "which will most help them along in the material world, the arts " + "of conjuring and magical combat. You can type <become mage> to " + "be initiated into the class of mages.", this_player()); + return 1; +} + +int become(string str) { + if(!str) { + notify_fail("Become what?\n"); + return 0; + } + if(str != "mage") { + notify_fail("You cannot become that here.\n"); + return 0; + } + if(this_player()->query_class() != "explorer") { + message("my_action", "You are much too old to start learning our ways now!", this_player()); + return 1; + } + message("my_action", "The High Mage Warlock initiates you into the class of mages.", this_player()); + message("other_action", this_player()->query_cap_name()+" becomes a mage.", this_object(), ({this_player()})); + this_player()->SetClass("mage"); + this_player()->setenv("TITLE", "$N the novice mage"); + this_player()->init_skills("mage"); + this_player()->setenv("start", "/domains/Praxis/mage_hall"); + return 1; +} + +int go_down() { + if(this_player()->query_class() != "mage") { + message("my_action", "You cannot penetrate the force field that blocks the passage.", this_player()); + message("other_action", this_player()->query_cap_name()+" tries to get into the mage's sanctuary, but fails.", this_object(), ({this_player() })); + return 0; + } + return 1; +} + diff --git a/lib/domains/Praxis/mage_vote.c b/lib/domains/Praxis/mage_vote.c new file mode 100644 index 0000000..5e688c5 --- /dev/null +++ b/lib/domains/Praxis/mage_vote.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include <voting.h> +#include <daemons.h> + +inherit "/domains/town/room/voters"; + +void create() { + ::create(); + SetProperty("light", 1); + SetProperty("no castle", 1); + SetProperty("indoors", 1); + SetShort( "Voting hall of the mages"); + SetLong( (: this_object(), "new_long" :)); + SetItems( + (["list" : "During election time, it lists all candidates."]) ); + SetExits( + (["west" : "/domains/Praxis/mage_hall"]) ); +} + +string new_long() { + if(VOTING_D->election_day()) + return "This is the room where Mages can put in their bid for office. " + "If you wish to run for office, just type in the command " + "'enter race' and you will be added to the list. A list of candidates " + "is posted on the wall. Type 'list candidates' to read it."; + else return "This is the voting chamber of the Hall of Mages. " + "Mages will gather here for the next election: "+VOTING_D->query_vote_date()+"."; +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/medium.c b/lib/domains/Praxis/medium.c new file mode 100644 index 0000000..758fd15 --- /dev/null +++ b/lib/domains/Praxis/medium.c @@ -0,0 +1,30 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 2); + SetProperty("indoors", 1); + SetProperty("no castle", 1); + SetSmell("default", "You smell the aroma of incense."); + SetShort( "Mora's hut"); + SetLong( + "A mystical aura hangs about this otherwise modest hut " + "decorated with strange artifacts from distant worlds. " + "This must be the hut of the famous medium Mora."); + SetExits( + (["west" : "/domains/Praxis/west_road2"]) ); + SetItems( + (["artifacts" : "You have no idea what they are or what they mean.", + "hut" : "It is very odd."]) ); +} + +void reset() { + ::reset(); + if(present("mora")) return; + new("/domains/Praxis/obj/mon/mora")->move(this_object()); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/monastery.c b/lib/domains/Praxis/monastery.c new file mode 100644 index 0000000..496fd79 --- /dev/null +++ b/lib/domains/Praxis/monastery.c @@ -0,0 +1,109 @@ +#include <lib.h> + +inherit LIB_ROOM; + +object *begging; + +void init() { + ::init(); + add_action("confess", "confess"); + add_action("pray", "pray"); +} + +void create() { + ::create(); + SetListen("default", "You hear the faint sounds of " + "chanting from up the stairs."); + SetListen("upstairs", "You hear the chanting of monks."); + SetListen("chants", "We serve an old man in a dry season" + "\nA lighthouse keeper in the desert sun\n" + "Dreamers of sleepers and white treason\n" + "We dream of rain and the history of the gun\n"); + begging = ({}); + SetShort( "Praxis monastary"); + SetLong( + "You are in the ornate monastary of Praxis.\n" + "In this huge open monastary run by Praxis monks, the wretched " + "murders come to confess, and the dead come to pray for resurrection. " + "A small stairway to the east leads to the monastary attic and " + "basement. The Praxis Chapel where monks marry people is north. " + "Boc La Road is outside the monastary to the south. "); + SetExits( + (["south" : "/domains/Praxis/e_boc_la1", + "east" : "/domains/Praxis/stairs", + "north" : "/domains/Praxis/chapel"]) ); + SetProperty("light", 2); + SetProperty("indoors", 1); + SetItems( + (["monastery" : "The home of the Nightmare monks.", + "chamber" : "People come here to pray for resurrection " + "when they die.", + "stairway" : "A small spiral set of stairs leading to " + "the attic and cellar.", + "road" : "Boc La Road."]) ); + SetProperty("no attack", 1); + SetProperty("no steal", 1); + SetProperty("no castle", 1); +} + +int pray() { + if(!this_player()->query_ghost()) { + notify_fail("The living do not need to pray for revival.\n"); + return 0; + } + this_player()->revive(); + this_player()->SetHealthPoints(10); + this_player()->set_heart_beat(1); + this_player()->set_heal_rate(2); + return 1; +} + +int confess(string str) { + object *inv; + int i, ok; + string res; + + if(str != "murder") { + notify_fail("Confess what?\n"); + return 0; + } + ok = 0; + if(sscanf(this_player()->getenv("TITLE"), "%s murderer $N%*s", res) + != 1) { + notify_fail("You are no murderer.\n"); + return 0; + } + i = sizeof(inv = all_inventory(this_object())); + while(i--) if(inv[i]->query_class() == "monk") ok = 1; + if(!ok) { + write("There is no one here to whom you may confess."); + return 1; + } + message("my_action", "You beg the monks for forgiveness for " + "your murder of a "+lower_case(res)+".", this_player()); + message("my_action", ("You pray that forgiveness does not mean " + "death."), this_player()); + say(this_player()->query_cap_name()+" begs for "+ + this_player()->query_possessive()+" murder of a "+ + lower_case(str)+"."); + begging += ({ this_player() }); + call_out("forgive", 60, this_player()); + return 1; +} + +object *query_forgiven() { return begging; } + +void forgive(object ob) { + string tmp; + + if(member_array(ob, begging) == -1) return; + begging -= ({ ob }); + tmp = call_other("/domains/Praxis/"+ob->query_class()+"_hall", + "get_new_title", ob); + message("info", "You are now forgiven.", ob); + ob->setenv("TITLE", tmp); + ob->add_mp(-500); + ob->add_hp(100- (ob->query_skill("faith"))); +} + + diff --git a/lib/domains/Praxis/monk_hall.c b/lib/domains/Praxis/monk_hall.c new file mode 100644 index 0000000..5a450b3 --- /dev/null +++ b/lib/domains/Praxis/monk_hall.c @@ -0,0 +1,260 @@ +#include <lib.h> +#include <council.h> +#include <daemons.h> + +inherit LIB_ROOM; + +string get_new_title(object tp); +string get_male(int lev); +string get_female(int lev); +int get_cost(string which, int lev); + +int CanReceive(object ob) { + if(!VOTING_D->is_time_to_vote()) + return ::CanReceive(ob); + if(creatorp(this_player()) || this_player()->query_level() < 2) + return ::CanReceive(ob); + if(VOTING_D->query_voted(this_player()->query_name(), + this_player()->query_class())) + return ::CanReceive(ob); + else { + message("my_action", "You have not yet voted for class leader. Please do so now.", this_player()); + call_out("move_me", 5, this_player()); + } + return ::CanReceive(ob); +} + +void move_me(object ob) { + ob->eventMoveLiving("/domains/Praxis/"+ob->query_class()+"_vote"); + return; +} + + +void create() { + object ob, box; + + ::create(); + SetProperty("no attack",1); + SetProperty("light", 2); + SetProperty("indoors", 1); + SetProperty("no castle", 1); + SetShort( "inside the hall of monks"); + SetLong( + "Welcome to the Monastary of Eternal Holiness.\n" + "All monks come here to advance in life and study. The " + "available commands are <cost>, <advance>, <list (number)>, " + "<improve stat>, <train skill amount>, and <roll stats>. West " + "through a passage guarded by a shimmering %^BLUE%^blue%^RESET%^ " + "light is the entrance to the monastery. Type <help skills> to " + "get a list of the full names of skills."); + SetExits( + (["west" : "/domains/Praxis/monk_join", + "council" : "/domains/Praxis/council_hall", + "east" : "/domains/Praxis/monk_vote"]) ); + + ob = new(LIB_BOARD); + ob->SetKeyName("tableau"); + ob->SetId( ({ "holy tableau", "tableau", "monk tableau", "board" }) ); + ob->set_board_id("monk_board"); + ob->set_max_posts(25); + ob->set_edit_ok(MONK_COUNCIL); + ob->move("/domains/Praxis/monk_hall"); + ob->SetShort( "the Holy Tableau of Monks"); + ob->SetLong( "A holy tableau into which monks mark their thoughts.\n"); + //box = new("/realms/nialson/monks/donation"); + //box->move(this_object()); +} + +void init() { + ::init(); + add_action("cost","cost"); + add_action("roll","roll"); + add_action("train", "train"); + add_action("improve", "improve"); + add_action("advance","advance"); + add_action("list","list"); +} + +int roll(string str) { + if(str != "stats") return 0; + call_other("/domains/Praxis/setter", "do_rolls"); + return 1; +} + +string get_new_title(object tp) +{ + int lev; + string gen, title; + + lev = this_player()->query_level(); + gen = this_player()->query_gender(); + if(this_player()->query_guild()) { + if(present(tp->query_guild()+"_ob", tp)) { + title = present(tp->query_guild()+"_ob", tp)->query_title(tp); + title += " $N"; + } + else title = "$N"; + } + else title = "$N"; + if(gen == "male") title += " "+get_male(lev); + else title += " "+get_female(lev); + return title; +} + +string get_male(int lev) { + string *male_title_str; + + if(!male_title_str) male_title_str = allocate(20); + male_title_str[19] ="the angel"; + male_title_str[18] ="the prophet"; + male_title_str[17] ="the saint"; + male_title_str[16] ="the doctor of divinity"; + male_title_str[15] ="the devil-dodger"; + male_title_str[14] ="the pope"; + male_title_str[13] ="the holy father"; + male_title_str[12] ="the cardinal priest"; + male_title_str[11] ="the spiritual father"; + male_title_str[10] ="the great missionary"; + male_title_str[9] ="the missionary"; + male_title_str[8] ="the promoter of the faith"; + male_title_str[7] ="the high priest"; + male_title_str[6] ="the priest"; + male_title_str[5] ="the born again priest"; + male_title_str[4] ="the evangelist"; + male_title_str[3] ="the preacher"; + male_title_str[2] ="the servant of God"; + male_title_str[1] ="the bible reader"; + male_title_str[0] ="the choir boy"; + return male_title_str[lev-1]; +} + +string get_female(int lev) { + string *fem_title_str; + + if(!fem_title_str) fem_title_str = allocate(20); + fem_title_str[19] ="the angel"; + fem_title_str[18] ="the prophet"; + fem_title_str[17] ="the saint"; + fem_title_str[16] ="the doctor of divinity"; + fem_title_str[15] ="the devil-dodger"; + fem_title_str[14] ="the pope"; + fem_title_str[13] ="the mother superior"; + fem_title_str[12] ="her reverance"; + fem_title_str[11] ="the cardinal priestess"; + fem_title_str[10] ="the spiritual mother"; + fem_title_str[9] ="the great missionary"; + fem_title_str[8] ="the missionary"; + fem_title_str[7] ="the promoter of the faith"; + fem_title_str[6] ="the high priestess"; + fem_title_str[5] ="the priestess"; + fem_title_str[4] ="the born again priestess"; + fem_title_str[3] ="the evangelist"; + fem_title_str[2] ="the preacheress"; + fem_title_str[1] ="the sevant of God"; + fem_title_str[0] ="the choir girl"; + return fem_title_str[lev-1]; +} + +int advance() { return ADVANCE_D->advance(); } + +int train(string str) { + string which, which_tmp; + int amount; + + if(!str) { + notify_fail("Train what?\n"); + return 0; + } + if(sscanf(str, "%s %s %d", which, which_tmp, amount) == 3) which = which + " " + which_tmp; + else if(sscanf(str, "%s %d", which, amount) !=2) { + notify_fail("Correct syntax: <train skill amount>\n"); + return 0; + } + which = lower_case(which); + if(!this_player()->skill_exists(which)) { + notify_fail("No such skill.\n"); + return 0; + } + return ADVANCE_D->train_player(this_player(), which, amount); +} + +int improve(string str) { + string *stats; + int stat_cost; + + stats = ({ "strength", "intelligence", "wisdom", "dexterity", "constitution", "charisma" }); + str = lower_case(str); + if(member_array(str, stats) == -1) { + notify_fail("You have no such stat.\n"); + return 0; + } + stat_cost = get_cost(str, this_player()->query_base_stats(str)); + if( this_player()->query_exp()-stat_cost < ADVANCE_D->get_exp( this_player()->query_level() ) ) { + notify_fail("You are not experienced enough to improve yourself in that way.\n"); + return 0; + } + this_player()->SetStat(str, this_player()->query_base_stats(str) + 1); + this_player()->add_exp(-stat_cost); + message("Nmy_action", "You feel much ", this_player()); + message("Nother_action", this_player()->query_cap_name()+ + " looks much ", this_object(), ({ this_player() }) ); + if(str == "strength") tell_room(this_object(), "stronger.\n"); + else if(str == "intelligence") tell_room(this_object(), "more intelligent.\n"); + else if(str == "wisdom") tell_room(this_object(), "wiser.\n"); + else if(str == "dexterity") tell_room(this_object(), "more nimble.\n"); + else if(str == "constitution") tell_room(this_object(), "sturdier.\n"); + else tell_room(this_object(), "more attractive.\n"); + return 1; +} + +int get_cost(string stat, int lev) { + switch(stat) { + case "intelligence": return ADVANCE_D->get_stat_cost(1, lev); break; + case "dexterity": return ADVANCE_D->get_stat_cost(1, lev); break; + case "wisdom": return ADVANCE_D->get_stat_cost(1, lev); break; + default: return ADVANCE_D->get_stat_cost(2, lev); break; + } +} + +int cost(string str) { + int bing; + + write("Costs for advancement, training, and improvement:\n"); + bing = ADVANCE_D->get_exp( this_player()->query_level() + 1 ); + if(bing < 1) write("level:\t\tIt will cost you nothing to advance."); + else write("level:\t\t"+bing+"\n"); + write("skills: You train by spending the amount of experience you + desire.\n"); + write("strength:\t\t" + get_cost("strength", + this_player()->query_base_stats("strength")) + + "\t\tconstitution:\t\t" + get_cost("constitution", + this_player()->query_base_stats("constitution")) ); + write("intelligence:\t\t" + get_cost("intelligence", + this_player()->query_base_stats("intelligence")) + + "\t\tdexterity:\t\t" + get_cost("dexterity", + this_player()->query_base_stats("dexterity")) ); + write("wisdom:\t\t" + get_cost("wisdom", + this_player()->query_base_stats("wisdom")) + + "\t\tcharisma:\t\t" + get_cost("charisma", + this_player()->query_base_stats("charisma")) ); + return 1; +} + +int list(string str) { + int x; + + if(!str) "/domains/Praxis/quest_room"->list_quests(this_player(), 0); + else { + if(sscanf(str, "%d", x) != 1) { + notify_fail("You must give the number of the quest you want listed.\n"); + return 0; + } + if(x <1) { + notify_fail("No such quest.\n"); + return 0; + } + "/domains/Praxis/quest_room"->list_quests(this_player(), x); + } + return 1; +} + diff --git a/lib/domains/Praxis/monk_join.c b/lib/domains/Praxis/monk_join.c new file mode 100644 index 0000000..c545135 --- /dev/null +++ b/lib/domains/Praxis/monk_join.c @@ -0,0 +1,86 @@ +#include <lib.h> +int go_east(); + +inherit LIB_ROOM; + +void init() { + ::init(); + add_action("become", "become"); + add_action("preview","preview"); +} + +void create() { + ::create(); + SetProperty("light", 2); + SetProperty("indoors", 1); + SetProperty("no castle", 1); + SetShort( "Entry to the Hall of Monks"); + SetLong( + "Candles illuminate the chambers of the monastery. " + "The monks who run the monastery keep home here " + "and initiate new believers into way of monks. " + "A passage to the east is filled with a shimmering light. " + "<preview> will tell you about becoming a monk."); + SetItems( + (["candles" : "They are all over the monastery.", + "candle" : "It burns brightly and helps light the room.", + "monk" : "She is wandering about peacefully.", + "passage" : "You sense that only monks may pass that way."]) ); + SetExits( + (["down" : "/domains/Praxis/stairs"]) ); + AddExit("east","/domains/Praxis/monk_hall",(:go_east:)); +} + +int preview() { + if(this_player()->query_class() != "explorer") { + message("info", "This is not for you.", this_player()); + return 1; + } + say(this_player()->query_cap_name()+" seeks to learn about the monks.", + this_player()); + message("info", "Welcome, explorer!", this_player()); + message("info", "Monks make up people of many different beliefs of " + "great faith, but they are all united in their belief in a single " + "deity of Goodness and will devote themselves to Holy War to fight " + "evil wherever it might be. They are nearly fanatical about their " + "beliefs. To become a monk, type <become monk>,", this_player()); + return 1; +} + +int become(string str) { + if(!str) { + notify_fail("Become what?\n"); + return 0; + } + if(str != "monk") { + notify_fail("You cannot become that here.\n"); + return 0; + } + if(this_player()->query_class() != "explorer") { + message("my_action", "You are much too old to start learning our ways now!", this_player()); + return 1; + } + message("my_action", "The Grand Lord High Priestess initiates you into the class of monks.", this_player()); + message("other_action", this_player()->query_cap_name()+" becomes a monk.", + this_object(), ({ this_player() })); + this_player()->SetClass("monk"); + this_player()->setenv("TITLE", "$N the novice monk"); + this_player()->init_skills("monk"); + this_player()->setenv("start", "/domains/Praxis/monk_hall"); + return 1; +} + +int go_east() { + if(creatorp(this_player())){ + write("Mighty immortals are always welcome into the humble monastary."); + return 1; + } else + if(this_player()->query_class() != "monk") { + write("You cannot penetrate the force field that blocks the passage."); + say(this_player()->query_cap_name()+" tries to get into the monk's sanctuary, but fails.", this_player()); + return 0; + } + return 1; +} + + diff --git a/lib/domains/Praxis/monk_vote.c b/lib/domains/Praxis/monk_vote.c new file mode 100644 index 0000000..2878ea1 --- /dev/null +++ b/lib/domains/Praxis/monk_vote.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include <voting.h> +#include <daemons.h> + +inherit "/domains/town/room/voters"; + +void create() { + ::create(); + SetProperty("light", 1); + SetProperty("no castle", 1); + SetProperty("indoors", 1); + SetShort( "Voting hall of the monks"); + SetLong( (: this_object(), "new_long" :)); + SetItems( + (["list" : "During election time, it lists all candidates."]) ); + SetExits( + (["west" : "/domains/Praxis/monk_hall"]) ); +} + +string new_long() { + if(VOTING_D->election_day()) + return "This is the room where Monks can put in their bid for office. " + "If you wish to run for office, just type in the command " + "'enter' and you will be added to the list. A list of candidates " + "is posted on the wall. Type 'list candidates' to see the list."; + else return "This is the voting chamber of the Hall of Monks. " + "Monks will gather here for the next election: "+VOTING_D->query_vote_date()+"."; +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/mountains/chamber1.c b/lib/domains/Praxis/mountains/chamber1.c new file mode 100644 index 0000000..df7cfb1 --- /dev/null +++ b/lib/domains/Praxis/mountains/chamber1.c @@ -0,0 +1,59 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", -1); + SetProperty("indoors", 1); + SetProperty("no teleport", 1); + SetProperty("no castle", 1); + SetShort( "A dark underground chamber"); + SetLong( + "You are in a very dark chamber, illuminated only by your " + "light source. The stench in here is foul, and trapped."); + SetItems( + (["light" : "What light?", + "tunnel" : "It is very dark.", + "chamber" : "You cannot see it very well."]) ); + SetExits( + (["west" : "/domains/Praxis/mountains/tunnel1"]) ); +} + +void reset() { + object arm, mon; + + ::reset(); + if(!present("goblin")) { + mon = new(LIB_NPC); + mon->SetKeyName("goblin"); + mon->SetId( ({ "soldier", "goblin", "goblin soldier" }) ); + mon->SetLevel(3); + mon->SetShort( "Goblin soldier"); + mon->SetLong( "An ugly monster who has likely never " + "seen the light of day."); + mon->SetRace( "goblin"); + mon->SetAggressive( 10); + mon->SetMorality(-140); + mon->SetHealthPoints(240); + mon->set_languages( ({ "goeblesque" }) ); + mon->set_speech(10, "goeblesque", ({ "Piss off!", "Die, asshole!" }), + 1); + mon->SetGender("female"); + mon->SetRace("human"); + mon->move(this_object()); + arm = new(LIB_ARMOR); + arm->SetKeyName("boot"); + arm->SetId( ({ "boot", "boot", "goblin boot" }) ); + arm->SetShort( "Right goblin boot"); + arm->SetLong( "A boot for right foot made from the rotting leather goblins can only find."); + arm->set_type("boot"); + arm->set_limbs( ({ "right foot" }) ); + arm->set_ac(3); + arm->set_mass(120); + arm->set_value(50); + arm->move(mon); + mon->force_me("wear boot"); + } +} + diff --git a/lib/domains/Praxis/mountains/chamber2.c b/lib/domains/Praxis/mountains/chamber2.c new file mode 100644 index 0000000..4557dac --- /dev/null +++ b/lib/domains/Praxis/mountains/chamber2.c @@ -0,0 +1,61 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", -1); + SetProperty("indoors", 1); + SetProperty("no teleport", 1); + SetProperty("no castle", 1); + SetSmell("default", "The stench in here is foul and trapped."); + SetShort( "A dark chamber under the mountains"); + SetLong( + "You are in a very dark chamber, illuminated only by your " + "light source."); + SetItems( + (["light" : "What light?", + "tunnel" : "It is very dark.", + "chamber" : "You cannot see it very well."]) ); + SetExits( + (["east" : "/domains/Praxis/mountains/tunnel1"]) ); +} + +void reset() { + object arm, mon; + + ::reset(); + if(!present("goblin")) { + mon = new(LIB_NPC); + mon->SetKeyName("goblin"); + mon->SetId( ({ "soldier", "goblin", "goblin soldier" }) ); + mon->SetShort( "Goblin soldier"); + mon->SetLong( "An ugly monster who has likely never seen " + "the light of day."); + mon->SetLevel(3); + mon->SetRace( "goblin"); + mon->SetAggressive( 10); + mon->SetMorality(-140); + mon->set_languages( ({ "goeblesque" }) ); + mon->set_speech(10, "goeblesque", ({ "Piss off.", "Go away or die!" }), + 1); + mon->SetHealthPoints(240); + mon->SetGender("female"); + mon->SetRace("human"); + mon->move(this_object()); + arm = new(LIB_ARMOR); + arm->SetKeyName("boot"); + arm->SetId( ({ "left boot", "boot", "goblin boot" }) ); + arm->SetShort( "Left goblin boot"); + arm->SetLong( "A boot for left foot made from the " + "rotting leather goblins can only find."); + arm->set_type("boot"); + arm->set_limbs( ({ "left foot" }) ); + arm->set_ac(3); + arm->set_mass(120); + arm->set_value(50); + arm->move(mon); + mon->force_me("wear boot"); + } +} + diff --git a/lib/domains/Praxis/mountains/chamber3.c b/lib/domains/Praxis/mountains/chamber3.c new file mode 100644 index 0000000..e93e7bb --- /dev/null +++ b/lib/domains/Praxis/mountains/chamber3.c @@ -0,0 +1,58 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", -1); + SetProperty("indoors", 1); + SetProperty("no castle", 1); + SetProperty("no teleport", 1); + SetShort( "A chamber underneath the Daroq Mountains"); + SetLong( + "You are in a very dark chamber, illuminated only by your " + "light source."); + SetSmell("default", "The stench of decay is all around."); + SetItems( + (["light" : "What light?", + "tunnel" : "It is very dark.", + "chamber" : "You cannot see it very well."]) ); + SetExits( (["west" : "/domains/Praxis/mountains/tunnel2"]) ); +} + +void reset() { + object arm, mon; + + ::reset(); + if(!present("goblin")) { + mon = new(LIB_NPC); + mon->SetKeyName("goblin"); + mon->SetId( ({ "colonel", "goblin", "goblin colonel" }) ); + mon->SetShort( "Goblin colonel"); + mon->SetLong( "An ugly monster who has likely never seen " + "the light of day."); + mon->SetLevel(4); + mon->SetRace( "goblin"); + mon->SetAggressive( 10); + mon->SetMorality(-180); + mon->SetHealthPoints(275); + mon->SetGender("female"); + mon->SetRace("human"); + mon->move(this_object()); + + arm = new(LIB_ARMOR); + arm->SetKeyName("visor"); + arm->SetId( ({ "visor", "goblin visor" }) ); + arm->SetShort( "Goblin visor"); + arm->SetLong( "A metallic visor with opening just " + "large enough to see through."); + arm->set_type("visor"); + arm->set_limbs( ({ "head" }) ); + arm->set_ac(1); + arm->set_mass(100); + arm->set_value(100); + arm->move(mon); + mon->force_me("wear visor"); + } +} + diff --git a/lib/domains/Praxis/mountains/chamber4.c b/lib/domains/Praxis/mountains/chamber4.c new file mode 100644 index 0000000..f0ec9db --- /dev/null +++ b/lib/domains/Praxis/mountains/chamber4.c @@ -0,0 +1,57 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", -1); + SetProperty("indoors", 1); + SetProperty("no teleport", 1); + SetProperty("no castle", 1); + SetShort( "A dark underground chamber"); + SetLong( + "You are in a very dark chamber, illuminated only by your " + "light source."); + SetSmell("default", "The stench in here is foul and trapped."); + SetItems( + (["light" : "What light?", + "tunnel" : "It is very dark.", + "chamber" : "You cannot see it very well."]) ); + SetExits( (["east" : "/domains/Praxis/mountains/tunnel2"]) ); +} + +void reset() { + object arm, mon; + + ::reset(); + if(!present("goblin")) { + mon = new(LIB_NPC); + mon->SetKeyName("goblin"); + mon->SetId( ({ "general", "goblin", "goblin general" }) ); + mon->SetShort( "Goblin general"); + mon->SetLong( "An ugly monster who has likely never " + "seen the light of day."); + mon->SetLevel(5); + mon->SetRace( "goblin"); + mon->SetAggressive( 10); + mon->SetMorality(-200); + mon->SetHealthPoints(300); + mon->SetGender("male"); + mon->SetRace("human"); + mon->move(this_object()); + arm = new(LIB_ARMOR); + arm->SetKeyName("shield"); + arm->SetId( ({ "shield", "goblin shield" }) ); + arm->SetShort( "Goblin shield"); + arm->SetLong( "A huge, heavy shield whose metal was mined " + "from the Darow Mountains."); + arm->set_type("shield"); + arm->set_limbs( ({ "left hand", "left arm", "torso" }) ); + arm->set_ac(3); + arm->set_mass(500); + arm->set_value(150); + arm->move(mon); + mon->force_me("wear shield"); + } +} + diff --git a/lib/domains/Praxis/mountains/entrance.c b/lib/domains/Praxis/mountains/entrance.c new file mode 100644 index 0000000..16273f7 --- /dev/null +++ b/lib/domains/Praxis/mountains/entrance.c @@ -0,0 +1,39 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 1); + SetProperty("indoors", 1); + SetProperty("no castle", 1); + SetListen("default", "Sounds taunt you from every direction."); + SetSmell("default", "Musty odors arise from deeper into the " + "mountain."); + SetShort( "Tunnel entrance under the Daroq Mountains"); + SetLong( + "You are inside the poorly lit tunnel of goblins under the Daroq " + "Mountains. The only source of light is the opening to the outside. " + "As the tunnel drops down deeper into the mountain, it gets even darker." + " On the east wall a thick clump of bushes has grown up in " + "front of a small cave making it difficult to see it. " + "Off to the northeast you can see a rocky path."); + SetItems( + (["tunnel" : "It is very dim.", + "light" : "There is not much of it.", + "opening" : "It leads to the outside world.", + "mountain" : "You feel evil throughout it."]) ); + SetExits( ([ + "out" : "/domains/Praxis/pass2", + ]) ); + AddExit("down", "/domains/Praxis/mountains/tunnel1", (: "go_down" :)); +} + +int go_down() { + if(this_player()->query_level() > 10) { + message("my_action", "A magic force prevents you from going " + "further into the mountain.", this_player()); + return 0; + } + return 1; +} diff --git a/lib/domains/Praxis/mountains/temp.c b/lib/domains/Praxis/mountains/temp.c new file mode 100644 index 0000000..339b774 --- /dev/null +++ b/lib/domains/Praxis/mountains/temp.c @@ -0,0 +1,53 @@ +inherit "/lib/std/room"; + +void create() { + ::create(); + SetProperty("light", -1); + SetProperty("indoors", 1); + SetShort( "Inside a dark chamber"); + SetLong( + "You are in a very dark chamber, illuminated only by your " + "light source. The stench in here is foul, and trapped."); + SetItems( + (["light" : "What light?", + "tunnel" : "It is very dark.", + "chamber" : "You cannot see it very well."]) ); + SetExits( (["west" : "/domains/Praxis/mountains/tunnel1"]) ); +} + +void reset() { + object arm, mon; + + ::reset(); + if(!present("goblin")) { + mon = new("/lib/npc"); + mon->SetKeyName("goblin"); + mon->SetId( ({ "soldier", "goblin", "goblin soldier"}) ); + mon->SetLevel(3); + mon->SetShort( "Goblin soldier"); + mon->SetLong( "An ugly monster who has likely never " + "seen the light of day."); + mon->SetRace( "goblin"); + mon->SetAggressive( 10); + mon->SetMorality(-140); + mon->SetHealthPoints(240); + mon->SetGender("female"); + mon->SetRace("human"); + mon->move(this_object()); + + arm = new("/lib/std/armor"); + arm->SetKeyName("boot"); + arm->SetId( ({ "boot", "boot", "goblin boot" }) ); + arm->SetShort( "Right goblin boot"); + arm->SetLong( "A boot for right foot made from the rotting " + "leather goblins can only find."); + arm->set_type("boot"); + arm->set_limbs( ({ "right foot" }) ); + arm->set_ac(3); + arm->set_mass(100); + arm->set_value(100); + arm->move(mon); + mon->force_me("wear boot"); + } +} + diff --git a/lib/domains/Praxis/mountains/tunnel1.c b/lib/domains/Praxis/mountains/tunnel1.c new file mode 100644 index 0000000..7719c5e --- /dev/null +++ b/lib/domains/Praxis/mountains/tunnel1.c @@ -0,0 +1,78 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 0); + SetProperty("indoors", 1); + SetProperty("no teleport", 1); + SetShort( "A dark tunnel under the mountains"); + SetLong( + "There is a weak light coming from up this descending tunnel, " + "but it is not enough to illuminate this passage. Chambers " + "branch off of the main tunnel east and west."); + SetItems( + (["light" : "What light?", + "tunnel" : "It is very dark.", + "chamber" : "You cannot see it very well.", + "chambers" : "There is one east, and one west, but you " + "cannot make out anything in them."]) ); + SetExits( + (["east" : "/domains/Praxis/mountains/chamber1", + "west" : "/domains/Praxis/mountains/chamber2", + "down" : "/domains/Praxis/mountains/tunnel2", + "up" : "/domains/Praxis/mountains/entrance"]) ); +} + +void reset() { + object arm, mon; + + ::reset(); + if(!present("goblin")) { + mon = new(LIB_NPC); + mon->SetKeyName("goblin"); + mon->SetId( ({ "guard", "goblin", "goblin guard" }) ); + mon->SetLevel(4); + mon->SetShort( "Goblin guard"); + mon->SetLong( "An ugly monster who has likely never seen " + "the light of day."); + mon->SetRace( "goblin"); + mon->set_stats("strength", 5); + mon->SetAggressive( 10); + mon->set_languages( ({ "goeblesque" }) ); + mon->set_speech(10, "goeblesque", + ({ "Get the hell out of here, asshole!", "You will never get that " + "damn crystal ball!", "I will freaking kill you!"}), 0); + mon->set_speech(20, "goeblesque", ({ "You are dead!", + "Shouldn't have picked a fight with me!", "I will body slam you!", + "%&$*!head!" }), 1); + mon->SetMorality(-120); + mon->SetHealthPoints(400); + mon->SetGender("male"); + mon->SetRace("human"); + mon->move(this_object()); + + arm = new(LIB_ARMOR); + arm->SetKeyName("chainmail"); + arm->SetId( ({ "chainmail", "suit of chainmail", "suit" }) ); + arm->SetShort( "A suit of chainmail"); + arm->SetLong( "A rusty old suit of chainmail."); + arm->set_type("body armour"); + arm->set_limbs( ({ "torso", "left arm", "left leg", "right arm", "right leg" }) ); + arm->set_ac(5); + arm->set_mass(900); + arm->set_value(100); + arm->move(mon); + mon->force_me("wear suit"); + } +} + +int CanReceive() { + if(previous_object()->query_level() > 10) { + message("my_action", "A magic force prevents you from going " + "further into the mountain.", this_player()); + return 0; + } + return 1; +} diff --git a/lib/domains/Praxis/mountains/tunnel2.c b/lib/domains/Praxis/mountains/tunnel2.c new file mode 100644 index 0000000..202a688 --- /dev/null +++ b/lib/domains/Praxis/mountains/tunnel2.c @@ -0,0 +1,66 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", -1); + SetProperty("indoors", 1); + SetProperty("no teleport", 1); + SetProperty("no castle", 1); + SetShort( "Deep under the Daroq Mountains"); + SetLong( + "The tunnel is pitch black, save for your source of light. " + "A pair of chambers spread off east and west."); + SetItems( + (["light" : "What light?", + "tunnel" : "It is very dark.", + "chamber" : "You cannot see it very well.", + "chambers" : "There is one east, and one west, but you " + "cannot make out anything in them."]) ); + SetExits( + (["east" : "/domains/Praxis/mountains/chamber3", + "west" : "/domains/Praxis/mountains/chamber4", + "down" : "/domains/Praxis/mountains/tunnel3", + "up" : "/domains/Praxis/mountains/tunnel1"]) ); +} + +void reset() { + object arm, mon; + + ::reset(); + if(!present("goblin")) { + mon = new(LIB_NPC); + mon->SetKeyName("goblin"); + mon->SetId( ({ "guard", "goblin", "goblin guard" }) ); + mon->SetShort( "Goblin guard"); + mon->SetLong( "An ugly monster who has likely never seen " + "the light of day."); + mon->SetLevel(4); + mon->SetRace( "goblin"); + mon->SetAggressive( 10); + mon->set_languages( ({ "goeblesque" }) ); + mon->set_speech(10, "goeblesque", ({ "I can get you in just one shot.", + "You do not stand a chance!", "Get out quick or die!" }), 1); + mon->SetMorality(-120); + mon->SetHealthPoints(200); + mon->SetGender("male"); + mon->SetRace("human"); + mon->move(this_object()); + + arm = new(LIB_ARMOR); + arm->SetKeyName("ring"); + arm->SetId( ({ "ring", "ring of darkness" }) ); + arm->SetShort( "Ring of darkness"); + arm->SetLong( "A featureless ring made from black obsidian."); + arm->set_type("ring"); + arm->set_limbs( ({ ({ "right hand", "left hand", "first hand", "second hand", "third hand", "fourth hand" }) }) ); + arm->set_ac(1); + arm->set_mass(60); + arm->set_value(100); + arm->move(mon); + mon->force_me("wear ring on right hand"); + } +} + + diff --git a/lib/domains/Praxis/mountains/tunnel3.c b/lib/domains/Praxis/mountains/tunnel3.c new file mode 100644 index 0000000..73e37af --- /dev/null +++ b/lib/domains/Praxis/mountains/tunnel3.c @@ -0,0 +1,39 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", -2); + SetProperty("indoors", 1); + SetProperty("no teleport", 1); + SetProperty("no castle", 1); + SetShort( "Deep inside a tunnel underneath the mountains"); + SetLong( + "The tunnel of goblins comes to an end here, deep inside " + "the evil Daroq Mountains."); + SetExits( (["up" : "/domains/Praxis/mountains/tunnel2"]) ); +} + +void reset() { + ::reset(); + SetSearch("default", (: this_object(), "ball" :)); + SetSearch("tunnel", (: this_object(), "ball" :)); +} + +void ball() { + object ob; + + write("You find a crystal ball."); + say(this_player()->query_name()+" finds a crystal ball."); + RemoveSearch("default"); + RemoveSearch("tunnel"); + ob = new("/domains/Praxis/obj/magic/ball"); + if(ob->move(this_player())) { + message("my_action", "You drop the crystal ball!", this_player()); + message("other_action", this_player()->query_cap_name()+ + " drops the crystal ball!", this_object(),({this_player()})); + ob->move(this_object()); + } +} + diff --git a/lib/domains/Praxis/mudlib.c b/lib/domains/Praxis/mudlib.c new file mode 100644 index 0000000..e3a045d --- /dev/null +++ b/lib/domains/Praxis/mudlib.c @@ -0,0 +1,30 @@ +inherit "/lib/std/room"; + +void create() { + object ob; + + ::create(); + SetProperty("light", 2); + SetProperty("indoors", 1); + SetShort( "The Mudlib Room"); + SetLong( + "In this room you can see the status of work being done on " + "bugs in the game by the mudlib department, as well as report " + "bugs that have not been getting the attention you think the bug " + "deserves."); + SetExits( + (["down" : "/domains/Praxis/adv_inner"]) ); + + ob = new("/lib/bboard"); + ob->SetKeyName("board"); + ob->SetId( ({ "board" }) ); + ob->set_board_id("mudlib"); + ob->set_max_posts(50); + ob->move("/domains/Praxis/mudlib"); + ob->SetShort( "the Mudlib Board"); + ob->SetLong( "A board for complete and utter nonsense.\n"); +} +void init(){ + ::init(); +} + diff --git a/lib/domains/Praxis/n_centre1.c b/lib/domains/Praxis/n_centre1.c new file mode 100644 index 0000000..548e1e6 --- /dev/null +++ b/lib/domains/Praxis/n_centre1.c @@ -0,0 +1,30 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 3); + SetProperty("night light", 1); + SetProperty("no castle", 1); + SetShort( "Centre Path north of Krasna Square"); + SetLong("Centre Path is a highly-traveled dirt path that runs north and south through Praxis. Just south of here, it intersects Boc La Road in Krasna Square. A small church is off to the west. It is a medium sized building, made out of sturdy wood that has been painted white. A very simple, yet beautiful stain glass window stares out at you from the front of the church. The doors are a deep black, and one is slightly open, in welcome. To the east is the local hotel."); + SetProperty("light", 3); + SetProperty("night light", 1); + SetItems( + (["path" : "Centre Path leads to Monument square south and out " + "of town north.", + "road" : "Boc La Road is the main east-west road.", + "church" : "It is a small church run by the local clerics.", + "square" : "The central square of Praxis."]) ); + SetSkyDomain("town"); + SetExits( ([ + "south" : "/domains/Praxis/square", + "west" : "/domains/Praxis/cleric_join", + "north" : "/domains/Praxis/n_centre2", + "east" : "/domains/Praxis/hotel.c", + ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/n_centre2.c b/lib/domains/Praxis/n_centre2.c new file mode 100644 index 0000000..ca1c4fe --- /dev/null +++ b/lib/domains/Praxis/n_centre2.c @@ -0,0 +1,36 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 3); + SetProperty("night light", 1); + SetProperty("no castle", 1); + SetShort( "The north end of Praxis"); + SetLong( + "Centre Path turns into nothing more than a small path " + "through the North Forest north of here as you approach " + "the northernmost part of Praxis. South the path leads into " + "the heart of this grand village. A small hospital is west. " + "Sun alley runs east."); + SetExits( + (["north" : "/domains/Praxis/forest1", + "south" : "/domains/Praxis/n_centre1", + "east" : "/domains/Praxis/sun1", + "west" : "/domains/Praxis/hospital"]) ); + SetItems( + (["path" : "Centre Path leads to Krasna Square south and out " + "of town north.", + "road" : "Boc La Road is the main east-west road.", + "church" : "It is a small church run by the local clerics.", + "forest" : "The North Forest. It is not a very well-" + "traveled place.", + "village" : "The grand village of Praxis", + "hospital" : "It is a primson white building jutting out " + "from the landscape"]) ); + SetSkyDomain("town"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/obj/armour/helm.c b/lib/domains/Praxis/obj/armour/helm.c new file mode 100644 index 0000000..9d37015 --- /dev/null +++ b/lib/domains/Praxis/obj/armour/helm.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include <armor_types.h> +inherit "/lib/std/armor"; + +void create() { + ::create(); + SetKeyName("helm"); + SetId( ({ "helm", "helmet", "knight's helm" }) ); + SetShort( "Knight's helm"); + SetLong( "The helm of a knight of justice."); + SetMass(375); SetValue( 95); + + SetArmorType(A_HELMET); + SetRestrictLimbs( ({ "head" }) ); + SetAC(3); + SetWear( (: this_object(), "extra_worn" :) ); +} + +int extra_worn() { + if(this_player()->query_alignment() < 200) { + write("This helmet burns with disgust."); + say(this_player()->query_cap_name()+" is burned trying to wear the knight's helm."); + return 0; + } + write("You feel the the powers of goodness flowing through you."); + say(this_player()->query_cap_name() + " shines with the powers of goodness of the knight's helm."); + return 1; +} diff --git a/lib/domains/Praxis/obj/magic/ball.c b/lib/domains/Praxis/obj/magic/ball.c new file mode 100644 index 0000000..5761dbf --- /dev/null +++ b/lib/domains/Praxis/obj/magic/ball.c @@ -0,0 +1,52 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; + +void init() { + ::init(); + add_action("scry", "scry"); +} + +void create() { + ::create(); + SetKeyName("ball"); + SetId( ({ "ball", "base", "crystal ball", "honor_quest_ob" }) ); + SetShort( "%^CYAN%^a crystal ball%^RESET%^"); + SetLong("It has some writing on its base."); + SetRead("From your grandfather with love."); + + SetMass(190); + SetValue(50); + SetVendorType(VT_MAGIC); + SetProperty("magic item", ({"scry"}) ); + true(); +} + +int scry(string str) { + object ob, env; + + if(!str) return notify_fail("Scry what?\n"); + write("You gaze into the crystal ball."); + if(this_player()->query_mp() < 5) { + write("Your magic powers are just too weak to help you."); + return 1; + } + if(!(ob = find_living(str)) || creatorp(ob)) { + write("No such person in our reality."); + return 1; + } + if(!environment(ob)) return notify_fail("Gurble gurble gurble.\n"); + if(environment(ob)->GetProperty("no scry")) + { + write("Something is blocking your concentration."); + return 1; + } + this_player()->add_mp(-5); + if(!(env = environment(ob))) { + write(ob->query_cap_name()+" is lost."); + return 1; + } + write("You find "+ob->query_cap_name()+" in the crystal ball at:\n"); + write(env->GetShort()+"\n"); + return 1; +} diff --git a/lib/domains/Praxis/obj/magic/invis.c b/lib/domains/Praxis/obj/magic/invis.c new file mode 100644 index 0000000..c2fa462 --- /dev/null +++ b/lib/domains/Praxis/obj/magic/invis.c @@ -0,0 +1,50 @@ +#include <lib.h> + +inherit LIB_ITEM; + +int __InvisTime; +mixed *__Invis; + +void create() { + ::create(); + SetKeyName("invis"); + SetId( ({ "invis" }) ); + SetInvis(1); + SetPreventPut("What are you doing?"); + SetPreventDrop("What are you doing?"); +} + +void create_invis(object who, string what, int x) { + __Invis = ({ who, what }); + __InvisTime = time() + x; + who->SetInvis( (: this_object(), "test_invis" :) ); + eventMove(who); +} + +int test_invis(object who, object whom) { + if(!__Invis) { + if(this_object()) this_object()->reeventMove(); + return 0; + } + if(__InvisTime < time()) { + message("environment", "You are feeling more vulnerable now.", + __Invis[0]); + this_object()->reeventMove(); + return 0; + } + if(__Invis[0] != who) return 0; + if(whom->query_race() == __Invis[1]) return 1; + return 0; +} + +int remove() { + int x; + + //if(!__Invis || !sizeof(__Invis)) return ::reeventMove(); + //if(__Invis[0]) + // __Invis[0]->remove_invis_test( (: this_object(), "test_invis" :) ); + //x = ::reeventMove(); + if(!this_object()) return x; + else __Invis[0]->SetInvis( (: this_object(), "test_invis" :) ); + return x; +} diff --git a/lib/domains/Praxis/obj/misc/app_board.c b/lib/domains/Praxis/obj/misc/app_board.c new file mode 100644 index 0000000..50f01ab --- /dev/null +++ b/lib/domains/Praxis/obj/misc/app_board.c @@ -0,0 +1,13 @@ +#include <lib.h> + +inherit LIB_BOARD; + +void create() { + ::create(); + SetProperty("no steal",1); + SetKeyName("board"); + SetId( ({"board","approval board"}) ); + set_board_id("approval"); + SetShort("the approval board"); + SetLong("Posts and notes for the approval team.\n"); +} diff --git a/lib/domains/Praxis/obj/misc/bag.c b/lib/domains/Praxis/obj/misc/bag.c new file mode 100644 index 0000000..c7f724c --- /dev/null +++ b/lib/domains/Praxis/obj/misc/bag.c @@ -0,0 +1,22 @@ +/* /d/Praxis/obj/misc/bag.c + * from Nightmare IV + * a simple bag + * created by Descartes of Borg 940212 + */ + +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("bag"); + SetId( ({ "bag" }) ); + SetAdjectives( ({ "small", "cloth", "a" }) ); + SetShort("a small cloth bag"); + SetLong("It is a simple cloth bag used to hold things."); + SetMass(274); + SetValue(50); + SetMaxCarry(500); + SetPreventPut("You cannot put this in there!"); +} diff --git a/lib/domains/Praxis/obj/misc/chest.c b/lib/domains/Praxis/obj/misc/chest.c new file mode 100644 index 0000000..f6421c0 --- /dev/null +++ b/lib/domains/Praxis/obj/misc/chest.c @@ -0,0 +1,36 @@ +/* /d/Praxis/obj/misc/chest.c + * from Nightmare IV + * a lockable treasure chest + * created by Descartes of Borg 940212 + */ + +#include <lib.h> +#include <objects.h> + +inherit LIB_STORAGE; + +void create() { + object money; + + ::create(); + SetKeyName("chest"); + SetId( ({ "chest" }) ); + SetAdjectives( ({ "orc", "treasure" }) ); + SetShort("an orc treasure chest"); + SetLong("A huge treasure chest with a great big lock on it."); + SetMass(2000); + SetValue(100); + SetMaxCarry(2000); + SetCanClose(1); + SetCanLock(1); + SetPreventPut("A treasure chest? Right!"); + SetProperty("magic hold", 10); + SetKey("orc_treasure"); + money = new(LIB_PILE); + money->SetCurrency("platinum", random(5)); + money->SetCurrency("gold", random(100)); + money->SetCurrency("copper", random(10000)); + money->move(this_object()); + SetClosed(1); + SetLocked(1); +} diff --git a/lib/domains/Praxis/obj/misc/cold.c b/lib/domains/Praxis/obj/misc/cold.c new file mode 100644 index 0000000..d308b21 --- /dev/null +++ b/lib/domains/Praxis/obj/misc/cold.c @@ -0,0 +1,29 @@ +#include <lib.h> + +inherit LIB_GERM; + +int coughs; + +void create() { + germ::create(); + coughs = 80; + SetKeyName("cold"); + SetId( ({ "cold" }) ); + SetShort("the cold"); + SetLong("A viral infection which is mostly harmless, but which " + "generally afflicts most beings during their lifetime."); + SetCommunicable(10); + SetCure(1); + SetLifeSpan(300); + SetType("viral"); +} + +void suffer(object ob) { + coughs--; + if(coughs%2) return; + ob->add_hp(-(ob->query_hp()/10)); + message("my_action", "You cough horridly!", ob); + message("other_action", ob->query_cap_name()+" coughs horribly!", + environment(ob), ob); + if(!coughs) this_object()->remove(); +} diff --git a/lib/domains/Praxis/obj/misc/deed.c b/lib/domains/Praxis/obj/misc/deed.c new file mode 100644 index 0000000..b48b024 --- /dev/null +++ b/lib/domains/Praxis/obj/misc/deed.c @@ -0,0 +1,163 @@ +/* /domains/Praxis/order.c + * from Nightmare IV + * a deed for a high mortal room + * created by Descartes of Borg 940701 + */ + +#include <lib.h> +#include <dirs.h> +#include <daemons.h> +//#include <security.h> + +inherit LIB_ITEM; + +int __Light, __Indoors; +string __Short, __Long, __Exit, __NewRoom, __EstateLong; + +static private string create_file(); + +void create() { + ::create(); + SetKeyName("deed"); + SetId( ({ "estate deed", "deed" }) ); + SetShort("an estate deed"); + SetLong("A deed to your very own high mortal estate, with a work " + "order to have workers begin to create your estate " + "to your desires. In order to build your estate, go " + "to the place where you want it built, and type: " + "\"build estate\". You will be asked some questions " + "about the room which will serve as the entrance to your estate." + ); + SetMass(10); + SetValue(99); + true(); +} + +void init() { + ::init(); + add_action("cmd_build", "build"); +} + +static int cmd_build(string str) { + if(str != "estate") return 0; + if(!high_mortalp(this_player())) + return notify_fail("Only high mortals may build!\n"); + if(environment(this_player())->GetProperty("indoors")) { + message("system", "You cannot build an estate indoors!", this_player()); + return 1; + } + if(sizeof(filter_array(all_inventory(environment(this_player())), + "estates", this_object())) >= + environment(this_player())->GetProperty("allow estate")) { + message("system", "This area cannot support an estate.",this_player()); + return 1; + } + if(file_size(ESTATES_DIRS+"/"+geteuid(this_player())) != -2) { + //seteuid(UID_ESTATES); + mkdir(ESTATES_DIRS+"/"+geteuid(this_player())); + seteuid(getuid()); + } + __Exit = "$"+file_name(environment(this_player()))+";$exit"; + message("system", "Give a one to two line description of your estate:", + this_player()); + input_to("input_long"); + return 1; +} + +static void input_long(string str) { + if(str == "") { + message("system", "Invalid entry.", this_player()); + return; + } + __EstateLong = str; + message("system", "Please give a short description for the room " + "people will enter from here. This is the description like " + "\"the entrance to "+this_player()->query_CapName()+"'s" + " estate\" that is seen when in brief mode.", this_player()); + message("prompt", "Enter in a short description: ", this_player()); + input_to("input_short"); +} + +static void input_short(string str) { + __Short = str; + message("prompt", "Is the room 0) outdoors, or 1) indoors? ", this_player()); + input_to("input_indoors"); + return; +} + +static void input_indoors(string str) { + int x; + + x = to_int(str); + if(x && x != 1) { + message("system", "That was not a valid value.", this_player()); + return; + } + __Indoors = x; + message("system", "How well lit is the room?", this_player()); + message("system", " 0 is darkest, 3 brightest", this_player()); + message("prompt", "\nEnter light value: ", this_player()); + input_to("input_light"); +} + +static void input_light(string str) { + int x; + + x = to_int(str); + if(x && x != 1 && x != 2 && x != 3) { + message("system", "Invalid light number.", this_player()); + return; + } + __Light = x; + message("system", "Enter in a long description for the room. " + "A long description is what people see when they enter a " + "room in verbose mode. A line showing obvious exits is automatically " + "appended. In addition, if you add any smells or sounds, the " + "default ones are automatically appended. So do not describe sounds or " + "smells here.", this_player()); + message("system", "Enter in the long description like mail.", this_player()); + rm(DIR_TMP+"/"+geteuid(this_player())+".estate"); + this_player()->edit(DIR_TMP+"/"+geteuid(this_player())+".estate", + "done_edit", this_object()); +} + +void abort() { + rm(DIR_TMP+"/"+geteuid(this_player())+".estate"); + message("system", "Building aborted.", this_player()); +} + +void done_edit(mixed *unused) { + string str; + + if(!(str = read_file(DIR_TMP+"/"+geteuid(this_player())+".estate"))) { + message("system", "No long!", this_player()); + return; + } + __Long = replace_string(str, "\n", " "); + __NewRoom= create_file(); + //seteuid(UID_ESTATES); + write_file(__NewRoom, "SetProperty: $indoors;#"+__Indoors+"\n"); + write_file(__NewRoom, "SetProperty: $light;#"+__Light+"\n"); + write_file(__NewRoom, "SetShort: $"+__Short+"\n"); + write_file(__NewRoom, "SetLong: $"+__Long+"\n"); + write_file(__NewRoom, "AddExit: "+__Exit+"\n"); + ESTATES_D->add_estate(this_player()->query_CapName(), __NewRoom, + file_name(environment(this_player())), __EstateLong); + //seteuid(getuid()); + message("system", "Room begun. You will see your addition " + "appear later when the work is complete.", this_player()); + this_object()->remove(); +} + +static private string create_file() { + string dir, str; + int x; + + x = sizeof(get_dir((dir = ESTATES_DIRS+"/"+geteuid(this_player())+"/"))); + while(file_exists(str = dir+"room"+x)) x++; + return str; +} + +static int estates(object ob) { + return ob->id("estate"); +} diff --git a/lib/domains/Praxis/obj/misc/donation.c b/lib/domains/Praxis/obj/misc/donation.c new file mode 100644 index 0000000..bb24b70 --- /dev/null +++ b/lib/domains/Praxis/obj/misc/donation.c @@ -0,0 +1,120 @@ +inherit "/lib/std/item"; +//#include <security.h> +#include <council.h> +#define LOG "/realms/nialson/data/mage_coffer_log" + +int loaded, stored_amount; + +void init() { + ::init(); + add_action("donate", "donate"); + add_action("withdraw", "withdraw"); +} + +void create() { + ::create(); + loaded=stored_amount=0; + SetKeyName("donation box"); + SetId( ({ "donation box", "box" }) ); + SetShort("a donation box"); + SetRead("Property of Frobitz collection agency."); + SetMass(0); + SetValue(0); + SetPreventGet("You aren't allowed to take that. No one is."); + SetNoClean(1); +} + +int restore_int(string str) { + string tmp; + string repl; + int value; + + tmp=absolute_path("/realms/nialson/data", str); + repl=read_file(tmp, 1, 1); + sscanf(repl, "%d\n", value); + return value; +} + +void save_int(string str, int value) { + string tmp; + + tmp=absolute_path("/realms/nialson/data", str); + rm(tmp); + write_file(tmp, ""+value+"\n"); +} + +int donate(string str) { + int amount; + + if(!str) { + notify_fail("Donate what?\n"); + return 0; + } + if(sscanf(str, "%d gold", amount) !=1) { + notify_fail("Correct syntax: <donate [#] gold>\n"); + return 0; + } + if(amount < 1) { + notify_fail("That would be a nifty trick indeed!\n"); + return 0; + } + if(this_player()->query_money("gold") < amount) { + notify_fail("You don't have that much gold!\n"); + return 0; + } + if (!loaded) { + stored_amount = restore_int("mage_coffers"); + loaded=1;} + this_player()->add_money("gold", -1*amount); + write("You donate "+amount+" gold coins to the mages."); + say(this_player()->query_cap_name()+" donates some gold.", this_player()); + stored_amount += amount; + write_file(LOG,""+stored_amount+"\t"+ + this_player()->query_name()+" donates ."+amount+"\n"); + save_int("mage_coffers", stored_amount); + return 1; +} + +string GetLong(string junk) { + if (!loaded) { + stored_amount = restore_int("mage_coffers"); + loaded=1;} + return + "A medium sized, VERY heavy box that contains the funds of the mage class.\n"+ + "If you wish, you can <donate # gold> to increase those funds.\n"+ + "The coffers currently contain "+stored_amount+" gold.\n"; +} + +int withdraw(string str) { + int amount; +#define TESTERS ({"nialson", "lassondra", "zaknaifen"}) + if((-1==member_array(this_player()->query_name(), TESTERS))&& + (-1==member_array(this_player()->query_name(), MAGE_COUNCIL))) { + notify_fail("Only council members may withdraw money.\n"); + return 0; } + if(!str) { + notify_fail("Withdraw what?\n"); + return 0; } + if(sscanf(str, "%d gold", amount) !=1) { + notify_fail("Correct syntax: <withdraw [#] gold>\n"); + return 0; } + if (!amount) { + notify_fail("Stop wasting my time and yours.\n"); + return 0; } + if (amount < 0) { + notify_fail("Negatives not allowed!\n"); + return 0; } + if (!loaded) { + stored_amount = restore_int("mage_coffers"); + loaded=1;} + + write("You withdraw "+amount+" gold coins from the mages."); + say(this_player()->query_cap_name()+" withdraws some gold.", this_player()); + stored_amount -= amount; + this_player()->add_money("gold", amount); + write_file(LOG,""+stored_amount+"\t"+ + this_player()->query_name()+" withdrew ."+amount+"\n"); + save_int("mage_coffers", stored_amount); + return 1; +} + diff --git a/lib/domains/Praxis/obj/misc/easter_egg.c b/lib/domains/Praxis/obj/misc/easter_egg.c new file mode 100644 index 0000000..f8e7e5c --- /dev/null +++ b/lib/domains/Praxis/obj/misc/easter_egg.c @@ -0,0 +1,54 @@ +#include <lib.h> + +inherit LIB_MEAL; + +void create() { + ::create(); + SetKeyName("easter egg"); + SetId( ({ "egg", "easter egg" }) ); + SetShort("an %^RED%^e%^GREEN%^a%^YELLOW%^s%^BLUE%^t%^MAGENTA%^e" + "%^CYAN%^r%^RESET%^ egg"); + SetLong( + "A beautiful easter egg brought by the easter bunny. It looks " + "yummy. If you do not want to eat it, why not hide it for " + "someone else?" + ); + SetValue(0); + SetMass(10); + if(random(100) < 30) { + SetStrength(-10); + SetMealMessages("$N eat $O, and it is ROTTEN!", + "$N eats $O, and it is ROTTEN!"); + } + else { + SetStrength(10); + SetMealMessages("$N eat $O filled with delicious candy!", + "$N eats $O filled with delicious candy!"); + } +} + +void init() { + ::init(); + add_action("cmd_search", "search"); + add_action("cmd_hide", "hide"); +} + +int cmd_hide(string str) { + if(present(str, this_player()) != this_object()) return 0; + message("my_action", "You hide "+GetShort()+".", this_player()); + message("other_action", this_player()->query_cap_name()+ + " hides something.", environment(this_player()), ({this_player()})); + SetInvis(1); + eventMove(environment(this_player())); + return 1; +} + +int cmd_search(string str) { + if(!query_invis()) return 0; + message("my_action", "You find "+GetShort()+"!", this_player()); + message("other_action", this_player()->query_cap_name()+ + "finds "+GetShort()+"!", environment(this_player()), + ({ this_player() })); + SetInvis(0); + return 1; +} diff --git a/lib/domains/Praxis/obj/misc/fishing_pole.c b/lib/domains/Praxis/obj/misc/fishing_pole.c new file mode 100644 index 0000000..792740e --- /dev/null +++ b/lib/domains/Praxis/obj/misc/fishing_pole.c @@ -0,0 +1,106 @@ +/* fishing pole designed by Descartes for use in rooms that are fishing + compatible. The pole is really nothing special except in that + you can bait it with anything that returns an id of bait and also + in that it has the following functions called by fishing rooms: + query_pole_class() returns an integer, the higher the number, the + better the pole is for fishing. + query_bait() returns an integer which is the strength of the bait, + the higher the number, the better the bait is for fishing + pole class should range from 2 (a horrible pole) to 7 (an absolutely + awesome pole) + bait strength, which is found out by the pole by calling a function + in items which return an id of true for bait, should be a + number between 0 (items fish wont eat) to 4 (yummy fish food) + */ + +#include <lib.h> +inherit LIB_ITEM; + +int query_bait(); +int query_pole_class(); +int query_broken(); +int break_pole(); +void unbait(); +int broken; +int bait; + +void init() { + add_action("bait_it","bait"); +} + +void create() { + ::create(); + SetKeyName("stick"); + SetId( ({ "stick", "fishing pole", "hook", "string" }) ); SetValue( 20); + SetMass( 28); + + broken = 0; + bait = 0; +} + +string GetLong(string str) { + if(str == "hook") { + if(!bait) return ("Perhaps you could bait this with something?\n"); + else return ("It has bait on it.\n"); + } + else if(str == "string") return ("A string with a hook at the end.\n"); + else { + return ("A bamboo stick with a piece of string connected to the end.\n" + "At the end of the string is a hook. What a primitive looking fishing tool!\n"); + } +} + +string GetShort() { + if(!broken) { + if(!bait) return "A bamboo stick"; + else return "A bamboo stick (baited)"; + } + else return "A bamboo stick (broken)"; +} + +int query_pole_class() { + return 2; +} + +int query_bait() { + return bait; +} + +int bait_it(string str) { + string pole, the_bait; + if(!str) return 0; + if((sscanf(str, "%s with %s", pole, the_bait)) !=2) return 0; + if(pole != "stick" && pole != "hook") return 0; + if(!present(the_bait,this_player())) { + write("You do not have any "+the_bait+" to bait your stick!\n"); + return 1; + } + if(!(present(the_bait,this_player())->id("bait"))) { + write("You can't use that as bait!\n"); + return 1; + } + if(!bait) { + bait = (100-present(the_bait, this_player())->query_strength())/7; + write("You bait your hook with "+the_bait+".\n"); + + say(this_player()->query_cap_name()+" baits "+this_player()->query_possessive()+" stick.\n"); + find_object(the_bait)->remove(); + return 1; + } + else { + write("You already have bait on your hook!"); + } + return 1; +} + +void unbait() { + bait = 0; +} + +int query_broken(){ + return broken;} int break_pole() { SetValue( 10); + + true(); + broken = 1; + } + diff --git a/lib/domains/Praxis/obj/misc/gallows.c b/lib/domains/Praxis/obj/misc/gallows.c new file mode 100644 index 0000000..8059671 --- /dev/null +++ b/lib/domains/Praxis/obj/misc/gallows.c @@ -0,0 +1,36 @@ +// /domains/Praxis/obj/misc/gallows.c +// Gallows for the Nightmare Mortal Law system +// Written by Manny@Nightmare 940823 + +#include <lib.h> + +inherit LIB_ITEM; +object hangman; +void set_hangman(object who); + + +create() { + ::create(); + SetKeyName("gallows"); + SetId( ({ "gallows", "noose", "platform" }) ); + SetShort("the gallows"); + SetLong( (: "long_func" :) ); + SetPreventGet("You cannot get that!"); +} + +string long_func() { + string str, name; + + str = "A large wooden platform with two upright timbers and " + "a crossbeam with a rope and noose."; + if(hangman) { + if(name = capitalize(present("the corpse of "+hangman->query_name(), + environment(this_object()))->GetKeyName())) + str += "\n"+name+" is hanging from the noose."; + else str += "\n"+hangman->query_cap_name()+" is standing " + "upon the platform, noose around "+hangman->query_possessive()+" neck."; + } + return str; +} + +void set_hangman(object who) { hangman = who; } diff --git a/lib/domains/Praxis/obj/misc/handcuffs.c b/lib/domains/Praxis/obj/misc/handcuffs.c new file mode 100644 index 0000000..d624719 --- /dev/null +++ b/lib/domains/Praxis/obj/misc/handcuffs.c @@ -0,0 +1,49 @@ +// /domains/Praxis/obj/misc/handcuffs.c +// From the Nightmare IV mudlib +// Autoloading handcuffs for use with the mortal law system. +// Created by Manny@Nightmare 940821 + +#include <lib.h> +#include <dirs.h> +#define ALLOWED_COMMANDS ({ "look", "say", "tell", "shout", "smile",\ + "frown", "grin", "shiver", "giggle", "laugh", "cry", "whimper",\ + "inventory", "pray", "dest", "call", "eval" }) + +inherit LIB_ITEM; + +create() { + ::create(); + SetId( ({ "handcuffs", "cuffs" }) ); + SetKeyName("handcuffs"); + SetShort("Rope handcuffs"); + SetLong("Thick rope used to restrain unlawful characters."); + SetMass(0); + SetValue(0); + SetPreventDrop("You're unable to drop that, you're hands are tied."); +} + +void init() { + ::init(); + add_action("all_cmds", ""); + if(!living(environment(this_object()))) this_object()->eventDestruct(); + command("save"); +} + +mixed *query_auto_load() { + return (DIR_STANDARD_DOMAIN+"/obj/misc/handcuffs.c", ({ }) ); +} + +int all_cmds(string str) { + + if(member_array(query_verb(), ALLOWED_COMMANDS) == -1) { + message("say", "%^RED%^You cannot do that with the handcuffs on.", + this_player()); + return 1; + } + if(this_player()->query_ghost()) call_out("destroy_me", 0); + return 0; +} + +void destroy_me() { + eventDestruct(); +} diff --git a/lib/domains/Praxis/obj/misc/hood.c b/lib/domains/Praxis/obj/misc/hood.c new file mode 100644 index 0000000..fac338b --- /dev/null +++ b/lib/domains/Praxis/obj/misc/hood.c @@ -0,0 +1,31 @@ +// /domains/Praxis/obj/misc/hood.c +// A hood for blinding players +// For the Nightmare mortal law system +// Created by Manny@Nightmare 940906 + +#include <lib.h> + +inherit LIB_ITEM; + +create() { + ::create(); + SetKeyName("hood"); + SetId(({"hood", "black hood" }) ); + SetShort("a black hood"); + SetLong("A black hood to hide the eyes of victims"); + SetPreventDrop("The hood is securly fastened to your neck"); +} + +void init() { + ::init(); + if(!living(environment(this_object()))) this_object()->remove(); + add_action("cmd_look", "look"); + add_action("cmd_look", "peek"); + add_action("cmd_look", "give"); +} + +int cmd_look() { + message("my_action", "It is too dark.", this_player()); + return 1; +} + diff --git a/lib/domains/Praxis/obj/misc/match.c b/lib/domains/Praxis/obj/misc/match.c new file mode 100644 index 0000000..eed1add --- /dev/null +++ b/lib/domains/Praxis/obj/misc/match.c @@ -0,0 +1,22 @@ +#include <lib.h> + +inherit LIB_MATCH; + +static void create() { + match::create(); + SetKeyName("match"); + SetId("match"); + SetAdjectives( ({ "wooden" }) ); + SetShort("a wooden match"); + SetLong("A wooden match that might light if you strike it."); + SetRadiantLight(2); + SetStrikeChance(50); + SetMinHeat(10); + SetFuelRequired(1); + SetMaxFuel(10); + SetFuelAmount(10); + SetRefuelable(0); + SetMass(5); + SetBaseCost("silver",2); + SetBurntValue(1); +} diff --git a/lib/domains/Praxis/obj/misc/order.c b/lib/domains/Praxis/obj/misc/order.c new file mode 100644 index 0000000..e11fbc4 --- /dev/null +++ b/lib/domains/Praxis/obj/misc/order.c @@ -0,0 +1,153 @@ +/* /domains/Praxis/order.c + * from Nightmare IV + * a work order for a high mortal room + * created by Descartes of Borg 940701 + */ + +#include <lib.h> +#include <dirs.h> +//#include <security.h> + +inherit LIB_ITEM; + +int __Light, __Indoors; +string __Short, __Long, __Exit, __NewRoom; + +static private string create_file(); + +void create() { + ::create(); + SetKeyName("work order"); + SetId( ({ "order", "work order" }) ); + SetShort("a work order"); + SetLong("An order for workers to begin modifying your estate " + "to your desires. In order to modify your estate, go to " + "any room in it, and type \"build <room name>\". " + "For example, to build your study, type: " + "\"build the study\". Room's as you type in the command " + "are what people see when they enter a room in brief mode. " + "In this case, people would see \"The study\". You will then be " + "asked some questions about your room." + ); + SetMass(10); + SetValue(99); + true(); +} + +void init() { + ::init(); + add_action("cmd_build", "build"); +} + +static int cmd_build(string str) { + if(!str) return notify_fail("Build which room?\n"); + if(file_size(ESTATES_DIRS+"/"+geteuid(this_player())) != -2) + return notify_fail("You need an estates directory!\n"); + /* + if(!high_mortalp(this_player())) + return notify_fail("Only high mortals may build!\n"); + */ + if(strsrch(file_name(environment(this_player())), + ESTATES_DIRS+"/"+geteuid(this_player())) != 0) + return notify_fail("You can only build on your stuff!\n"); + __Short = str; + message("prompt", "Is the room 0) outdoors, or 1) indoors? ", this_player()); + input_to("input_indoors"); + return 1; +} + +static void input_indoors(string str) { + int x; + + x = to_int(str); + if(x && x != 1) { + message("system", "That was not a valid value.", this_player()); + return; + } + __Indoors = x; + message("system", "How well lit is the room?", this_player()); + message("system", " 0 is darkest, 3 brightest", this_player()); + message("prompt", "\nEnter light value: ", this_player()); + input_to("input_light"); +} + +static void input_light(string str) { + int x; + + x = to_int(str); + if(x && x != 1 && x != 2 && x != 3) { + message("system", "Invalid light number.", this_player()); + return; + } + __Light = x; + message("system", "Enter in a long description for the room. " + "A long description is what people see when they enter a " + "room in verbose mode. A line showing obvious exits is automatically " + "appended. In addition, if you add any smells or sounds, the " + "default ones are automatically appended. So do not describe sounds or " + "smells here.", this_player()); + message("system", "Enter in the long description like mail.", this_player()); + rm(DIR_TMP+"/"+geteuid(this_player())+".estate"); + this_player()->edit(DIR_TMP+"/"+geteuid(this_player())+".estate", + "done_edit", this_object()); +} + +void abort() { + rm(DIR_TMP+"/"+geteuid(this_player())+".estate"); + message("system", "Building aborted.", this_player()); +} + +void done_edit(mixed *unused) { + string str; + + if(!(str = read_file(DIR_TMP+"/"+geteuid(this_player())+".estate"))) { + message("system", "No long!", this_player()); + return; + } + __Long = replace_string(str, "\n", " "); + message("prompt", "\nIn which direction do you wish to build "+__Short+"? ", + this_player()); + input_to("input_exit"); +} + +static void input_exit(string str) { + mapping valid_exits; + string file; + + if(member_array(str, environment(this_player())->query_exits()) + != -1) { + message("system", "A room already exists in that direction!", + this_player()); + return; + } + valid_exits = ([ "north": "south", "south": "north", "east":"west", + "west":"east", "up":"down", "down":"up", "southeast":"northwest", + "northwest":"southeast", "southwest":"northeast", + "northeast":"southwest" ]); + if(!valid_exits[str]) { + message("system", "That is not a real direction!", this_player()); + return; + } + __Exit = "$"+(file=file_name(environment(this_player())))+";$"+valid_exits[str]; + __NewRoom= create_file(); + //seteuid(UID_ESTATES); + write_file(file, "AddExit: $"+__NewRoom+";$"+str+"\n"); + write_file(__NewRoom, "SetProperty: $indoors;#"+__Indoors+"\n"); + write_file(__NewRoom, "SetProperty: $light;#"+__Light+"\n"); + write_file(__NewRoom, "SetShort: $"+__Short+"\n"); + write_file(__NewRoom, "SetLong: $"+__Long+"\n"); + write_file(__NewRoom, "AddExit: "+__Exit+"\n"); + //seteuid(getuid()); + message("system", "Room begun. You will see your addition " + "appear later when the work is complete.", this_player()); + this_object()->remove(); +} + +static private string create_file() { + string dir, str; + int x; + + x = sizeof(get_dir((dir = ESTATES_DIRS+"/"+geteuid(this_player())+"/"))); + while(file_exists(str = dir+"room"+x)) x++; + return str; +} diff --git a/lib/domains/Praxis/obj/misc/pedestal.c b/lib/domains/Praxis/obj/misc/pedestal.c new file mode 100644 index 0000000..2b473ae --- /dev/null +++ b/lib/domains/Praxis/obj/misc/pedestal.c @@ -0,0 +1,92 @@ +inherit "/lib/std/item"; + +int has_ball; + +void init() { + ::init(); + add_action("place", "place"); +} + +void clean_up() { return; } + +void create() { + ::create(); + has_ball=0; + SetKeyName("pedestal"); + SetId( ({ "pedestal" }) ); + SetShort("a pedestal"); + SetLong( + "This small (gnome-height) pedestal is made from a dark, mysterious stone. "+ + "There is a small indentation on the flat top, as if a round object were "+ + "meant to be placed there. "); + SetRead("Made by the Wilsonshire and Sons corintian pillar specialists."); + SetMass(10000); + SetValue(0); +} + +int place(string str) +{ + string this; + object ths; + + if (!stringp(str) || sscanf(str,"%s on pedestal", this) != 1) return 0; + if (has_ball) { + if (!(ths=present(this,this_player()))) return 0; + if (!ths->id("crystal ball")) return 0; + write("The pedestal already has a crystal ball on it. "); + return 1;} + if (!(ths=present(this,this_player()))) { + notify_fail("You are not carrying "+this+". "); + return 0;} + if (!ths->id("crystal ball")) { + notify_fail("That's pointless. "); + return 0;} + ths->remove(); + write("You place the crystal ball on the pedestal, and watch it fuse into place. "); + say("Places a crystal ball on the pedestal. The ball is fused to the pedestal"); + SetShort("a pedestal with crystal ball."); + SetLong( + "This small (gnome-height) pedestral is made from a dark, mysterious "+ + "stone. A crystal ball snugly fits into an indentation on the top. As "+ + "you peer at it, you notice barely-perceptible lines of force streaming "+ + "from the stone to the crystal ball. It seems your lessons in discerning "+ + "magic forces have paid off. "); + add_action("view", "view"); + has_ball=1; + return 1; +} + +int view(string str) +{ + int i; + string desc; + object ob, env, *inv; + + write("You gaze into the crystal ball. "); + if(this_player()->query_mp() < 5) { + write("Your magic powers are just too weak to help you. "); + return 1; + } + if(!(ob = find_living(str)) +#if 0 + || creatorp(ob) +#endif + ) { + write("No such person in our reality. "); + return 1; + } + this_player()->add_mp(-5); + if(!(env = environment(ob))) { + write(ob->query_cap_name()+" is lost. "); + return 1; + } + write("You find "+ob->query_cap_name()+" in the crystal ball: "); + ob=environment(ob); + desc = ob->GetLong()+"\n"; + inv = all_inventory(ob); + for(i=0; i<sizeof(inv); i++) { + if(inv[i]->query_invis()) continue; + desc += "\n"+inv[i]->GetShort()+" "; } + write(desc); + return 1; +} diff --git a/lib/domains/Praxis/obj/misc/shovel.c b/lib/domains/Praxis/obj/misc/shovel.c new file mode 100644 index 0000000..3455ac7 --- /dev/null +++ b/lib/domains/Praxis/obj/misc/shovel.c @@ -0,0 +1,26 @@ +// shovel.c created by Descartes 921004 +// it digs in rooms that look for shovels when digging is done + +#include <lib.h> + +inherit LIB_ITEM; + +void init() { + ::init(); + add_action("dig", "dig"); +} + +void create() { + ::create(); + SetId( ({ "shovel" }) ); + SetKeyName("shovel"); + SetShort( "a shovel"); + SetLong( "You might be able to dig with this in the right soil."); + SetMass(100); SetValue( 18); + +} + +int dig(string str) { + notify_fail("The shovel can't quite manage the soil here.\n"); + return 0; +} diff --git a/lib/domains/Praxis/obj/misc/stargate.c b/lib/domains/Praxis/obj/misc/stargate.c new file mode 100644 index 0000000..ebcbcd7 --- /dev/null +++ b/lib/domains/Praxis/obj/misc/stargate.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include <daemons.h> +#include "/lib/include/stargate.h" + +inherit LIB_STARGATE; + +int ReadScreen(); + +void create() +{ + ::create(); + SetOrigin("praxis", "/domains/Praxis/square"); + SetRead(([ ({ "screen" }) : (: ReadScreen :) ]) ); + SetItems(([ ({ "screen" }) : "a computer screen which shows the status of the gate network" ]) ); +} + +void init() +{ + ::init(); +} + +int ReadScreen() +{ + write("stargate network status\n"); + write("-----------------------\n"); + write("\n"); + +} diff --git a/lib/domains/Praxis/obj/misc/stone.c b/lib/domains/Praxis/obj/misc/stone.c new file mode 100644 index 0000000..ecb49fd --- /dev/null +++ b/lib/domains/Praxis/obj/misc/stone.c @@ -0,0 +1,112 @@ +// /domains/Praxis/obj/misc/stone.c +// Stone for throwing at criminals and stuff. +// For the Nightmare mortal law system +// Created by Manny@Nightmare 940901 + +#include <lib.h> + +inherit LIB_ITEM; + +object target; +void set_target(object who); + +create() { + ::create(); + SetKeyName("stone"); + SetId( ({ "stone", "throwing stone" }) ); + SetShort("a throwing stone"); + SetLong( (: "long_func" :) ); + SetMass(2); + SetValue(0); +} + +void long_func() { + if(target) { + message("say", "A throwing stone just waiting to be thrown at "+ + target->query_cap_name()+"'s forehead.", this_player()); + } else { + message("say", "A throwing stone whithout direction.", + this_player()); + } +} + +void init() { + ::init(); + add_action("throw_stone", "throw"); +} + +int throw_stone(string str) { + string what, who; + string limb; + + if(!str) { + notify_fail("Throw what?\n"); + return 0; + } + if(!sscanf(str, "%s at %s", what, who) == 2) { + notify_fail("Throw what at whom?\n"); + return 0; + } + if(!id(what)) { + notify_fail("Throw what?\n"); + return 0; + } + if(who != target->query_name()) { + message("say", "The stone misses completely.", this_player()); + message("say", this_player()->query_cap_name()+" throws a " + "stone in some random direction.", environment(this_player()), + this_player()); + return 1; + } + switch(random(4)) { + case 0: + message("say", "You hit "+target->query_cap_name()+" square " + "in the forehead!!", this_player()); + message("say", this_player()->query_cap_name()+" hits "+ + target->query_cap_name()+" in the forehead with a stone.", + environment(this_player()), ({ this_player(), target }) ); + message("say", this_player()->query_cap_name()+" hits " + "you squarely in the head with a small stone!!", target); + limb = "head"; + break; + case 1: + message("say", target->query_cap_name()+" screams in agony " + "as you hit "+target->query_possessive()+" squarely in " + "the nose!", this_player()); + message("say", target->query_cap_name()+" screams in agony " + "as "+this_player()->query_cap_name()+" hits " + +target->query_possessive()+" squarely in " + "the nose!", environment(this_player()), + ({ this_player(), target }) ); + message("say", "You scream in agony as a stone plows into your " + "nose!!", target); + limb = "head"; + break; + case 2: + message("say", "OUCH! You stone lands right on "+ + target->query_possessive()+" nards!!", this_player()); + message("say", this_player()->query_cap_name()+" is quite " + "a good shot with those stones...", + environment(this_player()), ({ this_player(), target })); + message("say", this_player()->query_cap_name()+" pegs you " + "right in the nards!! OUCH!", target); + limb = "torso"; + break; + case 3: + message("say", "You plant a stone right in "+ + target->query_possessive()+" stomach.", this_player()); + message("say", this_player()->query_cap_name()+" mercilessly " + "beats on "+target->query_cap_name()+" with the stones.", + environment(this_player()), ({ this_player(), target })); + message("say", this_player()->query_cap_name()+" plugs a stone " + "into your stomach, knocking your breath from you.", target); + limb = "torso"; + break; + } + target->do_damage(limb, random(50)+10); + if((target->check_on_limb(limb) == 2) || (target->query_hp() < 0)) + target->die(); + return 1; +} + +void set_target(object who) { target = who; } diff --git a/lib/domains/Praxis/obj/misc/stone_pile.c b/lib/domains/Praxis/obj/misc/stone_pile.c new file mode 100644 index 0000000..5523e80 --- /dev/null +++ b/lib/domains/Praxis/obj/misc/stone_pile.c @@ -0,0 +1,45 @@ +// /domains/Praxis/obj/misc/stone_pile.c +// A stone pile/stones for stoning criminals. +// For use with the Nightmare Mortal Law system +// Created by Manny@Nightmare 940901 + +#include <lib.h> + +inherit LIB_ITEM; + +object target; +void set_target(object who); + +void create() { + ::create(); + SetKeyName("pile"); + SetId( ({ "stones", "pile of stones", "pile" }) ); + SetShort("a pile of stones"); + SetLong("A pile of nice round stones, perfect for throwing at " + "outlaws and criminals."); + SetPreventGet("You can only get one stone at a time."); +} + +void init() { + ::init(); + add_action("get_stone", "get"); +} + +int get_stone(string str) { + object stone; + + if(!str || str != "stone") return 0; + message("say", "You pick up a stone from the pile. You feel a " + "strong desire to try <throw>ing it at " + +target->query_cap_name()+"...", this_player()); + message("say", this_player()->query_cap_name()+" picks up a stone " + "from the pile.", environment(this_player()), this_player()); + stone = new("/"+__DIR__+"stone"); + stone->set_target(target); + stone->move(this_player()); + return 1; +} + +void set_target(object who) { target = who; } + + diff --git a/lib/domains/Praxis/obj/misc/torch.c b/lib/domains/Praxis/obj/misc/torch.c new file mode 100644 index 0000000..b47f99c --- /dev/null +++ b/lib/domains/Praxis/obj/misc/torch.c @@ -0,0 +1,25 @@ +#include <lib.h> + +inherit LIB_TORCH; + +static void create() { + torch::create(); + SetKeyName("torch"); + SetId( ({ "torch", "old torch", "wooden torch" }) ); + SetAdjectives( ({ "old", "wooden" }) ); + SetShort("an old wooden torch"); + SetLong("An old, wooden torch with a bit of cloth wrapped around " + "one end and dipped into a flamable substance."); + SetRadiantLight(7); + SetFuelRequired(1); + SetMaxFuel(1000); + SetFuelAmount(1000); + SetRefuelable(1); + SetMass(50); + SetBaseCost("silver",60); + SetBurntValue(10); + SetClass(10); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/obj/misc/vial.c b/lib/domains/Praxis/obj/misc/vial.c new file mode 100644 index 0000000..1bc7ca7 --- /dev/null +++ b/lib/domains/Praxis/obj/misc/vial.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_MEAL_POISON; +inherit LIB_MEAL; + +void create() { + meal::create(); + poison::create(); + SetKeyName("vial"); + SetId( ({ "vial", "vial of poison", "poison" }) ); + SetShort( "Vial of poison"); + SetLong( "A glass vial with a skull and crossbones on it."); + SetPoisonStrength(8); + SetVendorType(VT_HERB); + SetValue( 150); + SetMass( 70); + +} diff --git a/lib/domains/Praxis/obj/misc/watchtower.c b/lib/domains/Praxis/obj/misc/watchtower.c new file mode 100644 index 0000000..fb4193c --- /dev/null +++ b/lib/domains/Praxis/obj/misc/watchtower.c @@ -0,0 +1,81 @@ +// /obj/monument.c +// from the Nightmare mudlib +// The time keeper of Krasna Square +// created by Daroki@Nightmare + +#include <lib.h> +#include <daemons.h> + +#define DONATORS_LIST ({ "Kalinash", "Kazmandu", "Ariel", "Mikla", "Ninja",\ + "Shambere", "Cair", "Drittz", "Beorn", "Vilesilencer", "Elwin", "Silenus",\ + "Corvar", "Lassondra", "Bohemund", "Maria", "Arugess", "Drakken", "Dana",\ + "Soong", "Slade", "Rearden", "Stonehenge", "Shadowwolf", "Descartes",\ + }) + +inherit LIB_ITEM; + +void GetLong_time(); +string query_hour(); + +void create() { + ::create(); + SetKeyName("monument"); + SetId( ({ "monument", "tower", "clock" }) ); + SetLong( + "This monument stands at the centre of Praxis to remind " + "everyone of those who have made this reality possible for " + "everyone to enjoy. On one face of the monument is a clock " + "which shows the time in Praxis. All other sides are " + "engraved with the names of those who have contributed " + "in money to this world. <read clock> will tell you the time. " + "<read names> to see who all has donated, and do thank them." + ); SetMass( 0); + + SetNoClean(1); +} + +void init() { + add_action("read", "read"); +} + +int read(string str) { + if(str == "clock") { + GetLong_time(); + return 1; + } + else if (str == "names") { + message("Ninfo", "These people have donated money and made Nightmare possible:\n"+ + format_page(sort_array(DONATORS_LIST, "alpha", this_object()), 5) + ,this_player()); + return 1; + } + notify_fail("Read what?\n"); + return 0; +} + +void GetLong_time() { + write(capitalize(season(time()))+" hovers over "+mud_name()+" on the "+ + date(time())+ordinal(date(time()))+" day of "+ + month(time())+" in year "+year(time())+" NM.\n" + ); + write("The clock face reads "+query_hour()+".\n"); +} + +string query_hour() { + int tmp, tmp2; + string str; + + tmp = hour(time()); + if(!tmp) tmp =10; + else if(tmp > 10) tmp -= 10; + tmp2 = minutes(time()); + str = (hour(time()) < 10 ? "am" : "pm"); + return tmp + ":" + (tmp2 > 9 ? tmp2 : "0"+tmp2)+" "+str; +} + + +int get() { return 0; } + +string affect_environment() { return "A magnificent monument rises above the square."; } + +int alpha(string a, string b) { return strcmp(a,b); } diff --git a/lib/domains/Praxis/obj/mon/armageddon.c b/lib/domains/Praxis/obj/mon/armageddon.c new file mode 100644 index 0000000..3c22051 --- /dev/null +++ b/lib/domains/Praxis/obj/mon/armageddon.c @@ -0,0 +1,16 @@ +#include <lib.h> +inherit "/lib/npc"; + +#include <daemons.h> + +void create() { + ::create(); + SetKeyName("armageddon"); + SetId( ({ "armageddon", "crasher", "asshole", "game crasher", "armageddon the game crasher" }) ); + SetShort("Game crasher Armageddon of Borg"); + SetLong("He appears once and briefly only to cause doom to the mud.\n"); + SetLevel(33); + SetHealthPoints(10000); + SetRace("human"); +} + diff --git a/lib/domains/Praxis/obj/mon/atmos.c b/lib/domains/Praxis/obj/mon/atmos.c new file mode 100644 index 0000000..ab74f29 --- /dev/null +++ b/lib/domains/Praxis/obj/mon/atmos.c @@ -0,0 +1,16 @@ +inherit "/lib/npc"; + +void create() { + ::create(); + SetKeyName("atmos"); + SetId( ({ "atmos" }) ); + SetShort("High mortal Atmos, Lord of Praxis"); + SetAggressive( 0); + SetLevel(26); + SetLong("Atmos is the lord of Praxis and all high mortals.\n"); + SetMorality(1000); + SetRace( "human"); + SetMaxHealthPoints(800000); + SetHealthPoints(400000); + SetRace("human"); +} diff --git a/lib/domains/Praxis/obj/mon/balrog.c b/lib/domains/Praxis/obj/mon/balrog.c new file mode 100644 index 0000000..22f8475 --- /dev/null +++ b/lib/domains/Praxis/obj/mon/balrog.c @@ -0,0 +1,16 @@ +inherit "/lib/npc"; + +create() { + ::create(); + SetKeyName("balrog"); + SetId( ({ "balrog" }) ); + SetShort("A wicked balrog"); + SetAggressive( 17); + SetLevel(9); + SetLong("He is one of the guardians of the Daroq Mountains.\n"); + SetRace("human"); + SetMorality(-200); + SetRace( "balrog"); + SetHealthPoints(360); + SetMagicPoints(200); +} diff --git a/lib/domains/Praxis/obj/mon/beggar.c b/lib/domains/Praxis/obj/mon/beggar.c new file mode 100644 index 0000000..a5a43a1 --- /dev/null +++ b/lib/domains/Praxis/obj/mon/beggar.c @@ -0,0 +1,95 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + + +int left_hand; +void complete_quest(object ob); + +create() { + ::create(); + SetKeyName("beggar"); + SetId( ({ "beggar" }) ); + SetShort("A poor beggar"); + SetAggressive( 0); + SetWanderSpeed(60); + SetGender("male"); + SetLevel(4); + SetLong("He is a poor beggar looking only for a few coins.\n"); + SetEncounter(0); + SetMorality(30); + SetRace( "human"); + SetMaxHealthPoints(50); + SetHealthPoints(50); + AddLimb("head", "FATAL", 25, 0, 4); + AddLimb("torso", "FATAL", 50, 0, 4); + AddLimb("right arm", "right hand", 20, 0, 4); + AddLimb("right hand", "", 15, 0, 4); + AddLimb("left arm", "left hand", 20, 0, 4); + AddLimb("left hand", "", 15, 0, 4); + AddLimb("right leg", "right foot", 25, 0, 4); + AddLimb("right foot", "", 20, 0, 4); + AddLimb("left leg", "left foot", 25, 0, 4); + AddLimb("left foot", "", 20, 0, 4); + RemoveLimb("left hand",this_object()); + left_hand = 0; + new("/domains/Praxis/obj/misc/cold")->infect(this_object()); +} +void catch_tell(string str) { + object ob; + string a, b, c; + + if(sscanf(str, "%s quest%*s", a)) { + call_out("say_line", 2, "The beggar says: What quest? I know nothing of any quests.\n"); + return; + } + if(sscanf(str, "%s regenerates your %s", a, b) == 2) { + if(left_hand) return; + if(!(ob=present((a=lower_case(a)), environment(this_object())))) return; + //if(!query_is_limb("left hand")) return; + left_hand = 1; + call_out("complete_quest", 1, ob); + return; + } + if(sscanf(str, "%s says: %s hand%*s", a, b) == 2) { + //if(query_is_limb("left hand")) + //call_out("say_line", 2, "The beggar says: My left hand is doing fine now!\n"); + // else + call_out("say_line", 2, "The beggar says: I wish it could be replaced.\n"); + return; + } + if(sscanf(str, "%s gives %s you", a, b) == 2) { + ob = present( lower_case(a), environment(this_object())); + if(ob) { + tell_object(ob, "The beggar thanks you for your generousity.\n"); + tell_room(environment(this_object()), "The beggar thanks "+a+" for "+ob->query_possessive()+" generousity.\n", ({this_object(), ob})); + } + } + if(sscanf(str, "%s?", a)) { + call_out("say_line", 2, "The beggar says: I do not understand the question.\n"); + return; + } + if(sscanf(str, "%ssmiles%s", a, b) == 2) + call_out("say_line", 2, "The beggar smiles happily.\n"); + AddAlcohol(200); +} +void complete_quest(object ob) { + if(!ob->set_mini_quest("beggar", 5000, + "You replaced the missing left hand of a poor beggar.\n")) { + tell_object(ob, "The beggar thanks you.\n"); + tell_room(environment(this_object()), "The beggar thanks "+ob->query_cap_name()+".\n", ({ ob, this_object() }) ); + SetAction(5, ob->query_cap_name()+" replaced my missing left hand!"); + return; + } + tell_object(ob, "The beggar glows in satisfaction!\n"); + tell_object(ob, "The beggar says: Thank you so much!\n"); + tell_object(ob, "You feel more experienced.\n"); + tell_room(environment(this_object()), ob->query_cap_name()+" looks more experienced.\n", ({ ob, this_object() }) ); + SetAction(5, ob->query_cap_name()+" replaced my missing left hand!" ); +} +void say_line(string str) { + tell_room(environment(this_object()), str, ({ this_object() }) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/obj/mon/christmas_bunny.c b/lib/domains/Praxis/obj/mon/christmas_bunny.c new file mode 100644 index 0000000..1f6ee3c --- /dev/null +++ b/lib/domains/Praxis/obj/mon/christmas_bunny.c @@ -0,0 +1,60 @@ +inherit "/lib/sentient"; + +int count_eggs; + +void create() { + ::create(); + SetKeyName("easter bunny"); + SetId( ({ "bunny", "easter bunny" }) ); + SetShort( "A Confused Easter bunny"); + SetLong( "Hippity Hoppity.\nOh, joy, it's the Easter Bunny.\nWatch him drool.\nHe is hiding Easter eggs all over Nightmare.\n"); + SetAggressive( 0); + SetWanderSpeed(30); + SetGender("male"); + SetLevel(30); + SetMorality(200); + SetRace("rodent"); + SetMaxHealthPoints(500000); + SetHealthPoints(500000); + SetAction(10, + ({ "The Easter Bunny drools.\n", + "The Easter Bunny farts at you.\n", + "The Easter bunny looks around, confused.\n", + "The Easter Bunny mumbles about rotten eggs.\n" }) + ); + SetSkill("melee", 400); +} + +void catch_tell(string str) { + string who; + + //if(!interact("enters", str)) return; + sscanf(str, "%s enters%*s", who); + who = lower_case(who); + call_out("egghead", 2, who); +} + +void egghead(string who) { + object ob, it; + + ob = present(who, environment(this_object())); + if(!ob) return; + if(random(101) < 25) { + tell_object(ob, "The Easter Bunny throws an egg at you!\n"); + tell_room(environment(this_object()), "The Easter Bunny throws an egg at "+ob->query_cap_name()+".\n", ({ ob })); + it = new("/domains/Praxis/obj/misc/easter_egg"); + it->move(ob); + } +} + +void heart_beat() { + object it; + count_eggs++; + if(count_eggs > 60) { + count_eggs = 0; + it = new("/domains/Praxis/obj/misc/easter_egg"); + it->move(this_object()); + eventForce("hide egg"); + } + ::heart_beat(); +} diff --git a/lib/domains/Praxis/obj/mon/easter_bunny.c b/lib/domains/Praxis/obj/mon/easter_bunny.c new file mode 100644 index 0000000..9dbf290 --- /dev/null +++ b/lib/domains/Praxis/obj/mon/easter_bunny.c @@ -0,0 +1,61 @@ +inherit "/lib/sentient"; + +int count_eggs; + +void create() { + ::create(); + SetKeyName("easter bunny"); + SetId( ({ "bunny", "easter bunny" }) ); + SetShort( "The Easter bunny"); + SetLong( "Hippity Hoppity.\nOh, joy, it's the Easter Bunny.\nWatch him drool.\nHe is hiding Easter eggs all over Nightmare.\n"); + SetAggressive( 0); + SetWanderSpeed(30); + SetGender("male"); + SetLevel(30); + SetMorality(200); + SetRace("rodent"); + SetMaxHealthPoints(500000); + SetHealthPoints(500000); + SetAction(10, + ({ "The Easter Bunny drools.\n", + "The Easter Bunny farts at you.\n", + "The Easter bunny looks around, confused.\n", + "The Easter Bunny mumbles about rotten eggs.\n" }) + ); + SetSkill("melee", 400); + SetRace("rodent"); +} + +void catch_tell(string str) { + string who; + + //if(!interact("enters", str)) return; + sscanf(str, "%s enters%*s", who); + who = lower_case(who); + call_out("egghead", 2, who); +} + +void egghead(string who) { + object ob, it; + + ob = present(who, environment(this_object())); + if(!ob) return; + if(random(101) < 25) { + tell_object(ob, "The Easter Bunny throws an egg at you!\n"); + tell_room(environment(this_object()), "The Easter Bunny throws an egg at "+ob->query_cap_name()+".\n", ({ ob })); + it = new("/domains/Praxis/obj/misc/easter_egg"); + it->move(ob); + } +} + +void heart_beat() { + object it; + count_eggs++; + if(count_eggs > 60) { + count_eggs = 0; + it = new("/domains/Praxis/obj/misc/easter_egg"); + it->move(this_object()); + eventForce("hide egg"); + } + ::heart_beat(); +} diff --git a/lib/domains/Praxis/obj/mon/execution_d.c b/lib/domains/Praxis/obj/mon/execution_d.c new file mode 100644 index 0000000..c6f7f08 --- /dev/null +++ b/lib/domains/Praxis/obj/mon/execution_d.c @@ -0,0 +1,22 @@ +// /domains/stanadard/obj/mon/execution.c +// Execution functions for the mortal law system +// Created 940917 by Manny@Nightmare + +#include <lib.h> +#include <dirs.h> + +inherit DAEMON; + +void create() { + daemon::create(); +} + +void stone_player(object who, string where) { + object me; + + me = previous_object(); + message("say", "%^RED%^"+me->query_cap_name()+", cheers wildly and " + "runs off to join in the stoning!", environment(me)); + me->eventMoveLiving(where, "cheers wildly and " + "runs off to join in the stoning!"); +} diff --git a/lib/domains/Praxis/obj/mon/goblin_fighter.c b/lib/domains/Praxis/obj/mon/goblin_fighter.c new file mode 100644 index 0000000..ff1bfcb --- /dev/null +++ b/lib/domains/Praxis/obj/mon/goblin_fighter.c @@ -0,0 +1,17 @@ +inherit "/lib/npc"; + +create() { + ::create(); + SetKeyName("goblin"); + SetId( ({ "goblin", "soldier" })); + SetShort( "a goblin soldier"); + SetAggressive( 17); + SetLevel(5); + SetLong( "A warrior of the Daroq goblins."); + SetClass("fighter"); + SetRace("human"); + SetMorality(-200); + SetRace( "goblin"); + SetHealthPoints(300); + SetMagicPoints(200); +} diff --git a/lib/domains/Praxis/obj/mon/guard.c b/lib/domains/Praxis/obj/mon/guard.c new file mode 100644 index 0000000..98cc8c8 --- /dev/null +++ b/lib/domains/Praxis/obj/mon/guard.c @@ -0,0 +1,20 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_NPC; + +private object __Target; + +void heart_beat() { + ::heart_beat(); + if(__Target && environment(__Target) != environment(this_object())) { + message("say", "%^BOLD%^%^RED%^The guard tells you: %^RESET%^"+ + "An' where do ya think you're goin' buster??", __Target); + __Target->eventMoveLiving(environment(this_object())); + } +} + +void set_target(object ob) { + if(!ob) return; + __Target = ob; +} diff --git a/lib/domains/Praxis/obj/mon/horace.c b/lib/domains/Praxis/obj/mon/horace.c new file mode 100644 index 0000000..7f4a290 --- /dev/null +++ b/lib/domains/Praxis/obj/mon/horace.c @@ -0,0 +1,33 @@ +#include <vendor_types.h> +inherit "/lib/std/vendor"; + +create() { + ::create(); + SetKeyName("horace"); + SetId( ({ "horace", "vendor", "shop keeper", "keeper", "shopkeeper", "nerd" }) ); + SetShort("Horace, the shop keeper of the adventurer's supply shop"); + SetAggressive( 0); + SetLevel(12); + SetLong("He buys and sells goods for adventuring.\n"+ + "<help shop> will get you a list of shop commands.\n"); + SetNativeLanguage( "eltherian" ); + SetGender("male"); + SetMorality(40); + SetRace( "elf"); + SetHealthPoints(480); + AddCurrency("electrum", random(200)); + SetRace("human"); + SetLocalCurrency("electrum"); + SetVendorType(VT_TREASURE); + SetStorageRoom("/domains/Praxis/storage"); + SetSkill("melee",100); + SetSkill("bargaining", 150); + SetProperty("no bump", 1); +} + +int is_invincible() { + SetStaminaPoints(GetMaxStaminaPoints()); + this_object()->eventForce("shout in eltherian Help!! I am being attacked by "+ + previous_object()->query_cap_name()); + return 0; +} diff --git a/lib/domains/Praxis/obj/mon/knight.c b/lib/domains/Praxis/obj/mon/knight.c new file mode 100644 index 0000000..9856f0a --- /dev/null +++ b/lib/domains/Praxis/obj/mon/knight.c @@ -0,0 +1,58 @@ +inherit "/lib/npc"; + +create() { + ::create(); + SetKeyName("knight"); + SetId( ({ "knight" }) ); + SetShort("A local knight"); + SetLevel(13); + SetLong( "She serves justice.\n"); + SetGender("female"); + SetRace( "human"); + SetMorality(300); + SetHealthPoints(450); + AddLimb("head", "FATAL", 100, 0, 4); + AddLimb("torso", "FATAL", 201, 0, 4); + AddLimb("right arm", "right hand", 70, 0, 4); + AddLimb("right hand", "", 50, 0, 4); + AddLimb("left arm", "left hand", 70, 0, 4); + AddLimb("left hand", "", 50, 0, 4); + AddLimb("right leg", "right foot", 70, 0, 4); + AddLimb("right foot", "", 50, 0, 4); + AddLimb("left leg", "left foot", 70, 0, 4); + AddLimb("left foot", "", 50, 0, 4); +} + +void catch_tell(string str) { + object tp; + string a, b, c; + + if(sscanf(str, "%suest%s", a, b) == 2) { + tell_room(environment(this_object()), "The knight says: I ventured into the goblin caves on a quest for glory.\nI ended up barely escaping with my life.\nAlthough I am now quite respected, I still feel honorless over the loss of\nmy great-grandfather's magic crystal ball.\nPlease return it to me!\n", ({ this_object() })); + return; + } + if(sscanf(str, "%s gives you %s", a, b) == 2) { + a = lower_case(a); + tp = present(a, environment(this_object())); + if(!tp) return; + call_out("check_ball", 2, tp); + return; + } +} + +void check_ball(object tp) { + object ob; + + ob = present("honor_quest_ob", this_object()); + if(!ob) { + tell_object(tp, "This is very nice, but it is not what I seek.\n"); + return; + } + ob->destruct(); + if(!tp->set_quest("honor")) return; + tell_object(tp, "The knight says: You have restored my honor!\nThe knight thanks you very much.\n"); + tell_object(tp, "The knight pays you 10000 copper coins in reward.\n"); + tp->AddCurrency("copper", 10000); + tp->add_exp(500); + tp->add_alignment(20); +} diff --git a/lib/domains/Praxis/obj/mon/lars.c b/lib/domains/Praxis/obj/mon/lars.c new file mode 100644 index 0000000..ad9e959 --- /dev/null +++ b/lib/domains/Praxis/obj/mon/lars.c @@ -0,0 +1,56 @@ +#include <lib.h> + +inherit LIB_BARKEEP; + +create() { + ::create(); + SetProperty("no bump", 1); + SetKeyName("lars"); + SetId( ({ "lars", "barkeep" }) ); + SetShort("Lars, the proprietor of the Lars Pub"); + SetAggressive( 0); + SetLevel(12); + SetLong("He tends bar and he listens.\n"); + SetGender("male"); + SetMorality(122); + SetRace( "human"); + SetHealthPoints(300); + AddCurrency("gold", random(200)); + SetRace("human"); + SetLocalCurrency("gold"); + //SetMenu( + // ({ + // "firebreather", "special", "ale" + // }), + // ({ "alcoholic", "alcoholic", "alcoholic" }), + // ({ 25, 15, 3 }) + // ); + // set_my_mess( + // ({ + // "The firebreather burns your throat!\n", + // "Wow! Lars sure knew how to make drinks when he invented that!\n", + // "You down some ale.\n" + // }) + // ); + // set_your_mess( + // ({ + // "screams from the burning of a drink of a firebreather.\n", + // "drinks a special of the house.\n", + // "drinks some ale.\n" + // }) + // ); + // SetMenu_short( + // ({ + // "A firebreather", + // "A special of the house", + // "A pale ale" + // }) + // ); + // SetMenu_long( + // ({ + // "A firebreather from the Lars Pub.\n", + // "A classic special of the house from the Lars Pub.\n", + // "A pale ale brewed in the farming fields outside Praxis.\n" + // }) + // ); +} diff --git a/lib/domains/Praxis/obj/mon/mora.c b/lib/domains/Praxis/obj/mon/mora.c new file mode 100644 index 0000000..43df0ef --- /dev/null +++ b/lib/domains/Praxis/obj/mon/mora.c @@ -0,0 +1,163 @@ +#include <lib.h> + +inherit LIB_NPC; + +void create() { + ::create(); + SetKeyName("mora"); + SetId( ({ "mora", "medium", "fortune teller", "teller" }) ); + SetShort( "Mora, the teller of fortunes"); + SetLong( + "She is spiritually on a plane beyond this reality. " + "A medium of the highest caliber, she tells the " + "fortunes of those who come and seek her words. " + "It is 60 gold to \"horoscope\" yourself. " + "It is 100 gold for others." + ); + SetRace( "gnome"); + SetGender("female"); + SetRace("human"); + SetHealthPoints(950); + SetLanguage( "nibelungen",100 ); + SetMaxHealthPoints(950); + SetMagicPoints(900); + SetMaxMagicPoints(900); + SetLevel(17); + SetStat("wisdom", 40); + SetSkill("magic attack", 100); + SetAction(12, + ({ + "Come! Let me tell you your horoscope!", + "Only 60 gold to know your horoscope.", + "I am in touch with alternate realities.", + "I can tell you the horoscope of your enemies.", + "I am always spiritually well." + }) + ); + SetMorality(-5); + AddCurrency("gold", random(60)); +} + +void init() { + ::init(); + add_action("horoscope", "horoscope"); +} + +int horoscope(string str) { + object ob; + string msg; + int mag, phy, cost; + + if(!str || str == "me" || str == "myself") ob = this_player(); + else ob = find_player(lower_case(str)); + if(!ob) { + notify_fail("I cannot find "+capitalize(str)+".\n"); + return 0; + } + if(ob == this_player()) cost = 60; + else cost = 110; + if(this_player()->query_money("gold") < cost) { + notify_fail("You do not have enough gold.\n"); + return 0; + } + mag = ob->query_spiritual(); + phy = ob->query_physical(); + this_player()->AddCurrency("gold", -cost); + write("You pay "+cost+" gold for Mora to give you a reading for today."); + say(this_player()->query_cap_name()+" pays Mora for a horoscope reading.", this_player()); + switch(mag) { + case -5: + if(ob == this_player()) msg = "Spiritual reality is disconnected from your soul."; + else msg = "Spiritual reality is disconnected from "+ob->query_possessive()+" soul."; + break; + case -4: + if(ob == this_player()) msg = "You are feeling out of touch with spiritual reality."; + else msg = capitalize(str)+" is feeling out of touch with spiritual reality."; + break; + case -3: + if(ob == this_player()) msg = "Your soul is particularly weak today."; + else msg = capitalize(str)+"'s soul is particularly weak today."; + break; + case -2: + if(ob == this_player()) msg = "You are best advised not to rely on spiritual matters today."; + else msg = capitalize(str)+" is best advised not to rely on spiritual matters today."; + break; + case -1: + if(ob == this_player()) msg = "You will need to concentrate to excel spiritually."; + else msg = capitalize(str)+" will need to concentrate to excel spiritually."; + break; + case 0: + if(ob == this_player()) msg = "Today is an average day for you on the spiritual planes."; + else msg = "Today is an average day for "+capitalize(str)+" on the spiritual planes."; + break; + case 1: + if(ob == this_player()) msg = "You will need to do little to excel spiritually."; + else msg = capitalize(str)+" will need to do a little to excel spiritually."; + break; + case 2: + if(ob == this_player()) msg = "You will do well with your magic today."; + else msg = capitalize(str)+" will do well with "+ob->query_possessive()+" magic today."; + break; + case 3: + if(ob == this_player()) msg = "Your spiritual aura shines very strongly today."; + else msg = capitalize(str)+"'s spiritual aura shines very strongly today."; + break; + case 4: + if(ob == this_player()) msg = "You have an unusually radiant spiritual aura today."; + else msg = capitalize(str)+" have and unusually radiant spiritual aura today."; + break; + case 5: + if(ob == this_player()) msg = "No one should get in the way of your magic today."; + else msg = "No one should get in the way of "+ob->query_possessive()+" magic today."; + break; + } + write(""+msg); + switch(phy) { + case -5: + if(ob == this_player()) msg = "You really should stay in bed today."; + else msg = capitalize(str)+" really should stay in bed today."; + break; + case -4: + if(ob == this_player()) msg = "You are feeling quite pathetic today."; + else msg = capitalize(str)+" is feeling quite pathetic today."; + break; + case -3: + if(ob == this_player()) msg = "It is not the best of days for your body."; + else msg = "It is not the best of days for "+capitalize(str)+"'s body."; + break; + case -2: + if(ob == this_player()) msg = "You are going to have a bad day with your body."; + else msg = capitalize(str)+" is going to have a bad day with "+ob->query_possessive()+" body."; + break; + case -1: + if(ob == this_player()) msg = "Your body is a bit under the weather today."; + else msg = capitalize(str)+"'s body is a bit under the weather today."; + break; + case 0: + if(ob == this_player()) msg = "You will do fine today."; + else msg = capitalize(str)+" will be doing fine today."; + break; + case 1: + if(ob == this_player()) msg = "You will do well today."; + else msg = capitalize(str)+" will do well today."; + break; + case 2: + if(ob == this_player()) msg = "Your physical strength is somewhat high."; + else msg = capitalize(str)+"'s physical strength is somewhat high."; + break; + case 3: + if(ob == this_player()) msg = "Today is a very robust day for you physically."; + else msg = "Today is a very robust day for "+capitalize(str)+" physically."; + break; + case 4: + if(ob == this_player()) msg = "You are in superior physical condition!"; + else msg = capitalize(str)+" is in superior physical condition!"; + break; + case 5: + if(ob == this_player()) msg = "Physically, you are in a rare top form."; + else msg = "Physically, "+capitalize(str)+" is in a rare top form."; + break; + } + write(""+msg); + return 1; +} diff --git a/lib/domains/Praxis/obj/mon/orc_shaman.c b/lib/domains/Praxis/obj/mon/orc_shaman.c new file mode 100644 index 0000000..b1eca93 --- /dev/null +++ b/lib/domains/Praxis/obj/mon/orc_shaman.c @@ -0,0 +1,20 @@ +inherit "/lib/npc"; + +create() { + ::create(); + SetKeyName("shaman"); + SetId( ({ "shaman", "orc", "orc shaman" }) ); + SetShort("The high orc shaman"); + SetAggressive( 29); + SetLevel(13); + SetLong("She is a powerful dark mage and the leader of the orcs of Orc Valley.\n"); + SetMorality(-515); + SetGender("female"); + SetClass("mage"); + SetRace( "orc"); + SetHealthPoints(220); + SetMagicPoints(350); + SetRace("human"); + SetSkill("magic attack", 60); + SetProperty("no bump", 1); +} diff --git a/lib/domains/Praxis/obj/mon/police.c b/lib/domains/Praxis/obj/mon/police.c new file mode 100644 index 0000000..b36c566 --- /dev/null +++ b/lib/domains/Praxis/obj/mon/police.c @@ -0,0 +1,42 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_SENTIENT; + +private object __Target; + +void go_home(); + +void init() { + ::init(); + add_action("cmd_surrender", "surrender"); +} + +void heart_beat() { + if(!__Target || __Target->query_ghost()) go_home(); + ::heart_beat(); + if(__Target && environment(__Target) != environment(this_object())) + go_home(); +} + +void set_target(object ob) { + if(!ob) return; + __Target = ob; + eventMove(environment(ob)); + ob->add_follower(this_object()); + command("kill "+ob->query_name()); +} + +void go_home() { + __Target = 0; + eventMove("/domains/Praxis/sheriff"); +} + +static int cmd_surrender(string unused) { + if(this_player() != __Target) return 0; + this_player()->cease_all_attacks(); + this_player()->move("/domains/Praxis/sheriff"); + "/domains/Praxis/sheriff"->add_prisoner(this_player()); + go_home(); + return 1; +} diff --git a/lib/domains/Praxis/obj/mon/receptionist.c b/lib/domains/Praxis/obj/mon/receptionist.c new file mode 100644 index 0000000..b637485 --- /dev/null +++ b/lib/domains/Praxis/obj/mon/receptionist.c @@ -0,0 +1,109 @@ +/* /d/standard/obj/mon/receptionist.c + * from Nightmare IV + * receptionist for the Nightmare Inn + * created by Descartes of Borgie and Lassondra of Sunshine@Nightmare 940424 + */ + +#include <lib.h> + +inherit LIB_NPC; + +#define ROOMS ([\ +101: ([ "name": "regular", "cost":8 ]),\ + 102: ([ "name": "regular", "cost":8 ]),\ + 103:([ "name":"regular", "cost":8 ]),\ + 104:([ "name":"regular", "cost":8 ]),\ + 105:(["name":"deluxe", "cost":12 ]),\ + 106:(["name":"deluxe", "cost":12 ]),\ + 107:([ "name":"deluxe", "cost":12]),\ + 108:(["name":"deluxe", "cost":12]),\ + 109:(["name":"honeymoon suite", "cost":20]),\ + 110:(["name":"honeymoon suite", "cost":20]),\ + ]) + +void create() { + npc::create(); + SetKeyName( "linfield"); + SetId( ({ "linfield", "receptionist" }) ); + SetShort( "Linfield, the receptionist" ); + SetLong( "Linfield is the dignified receptionist for the " + "Nightmare Inn. He stands tall behind the counter, " + "waiting to help the next customer. He wears dark " + "pants and blazer, with a white shirt and a blue " + "and red striped cravate."); + SetLevel(15); + SetGender( "male" ); + SetRace( "human" ); + SetHealthPoints(700); + SetClass( "mage" ); + SetSkill( "magic attack", 60); + SetSkill( "melee", 70); + SetCurrency( "gold", 50); +} + +void init() { + npc::init(); + add_action("cmd_rent", "rent"); + add_action("cmd_list", "list"); +} + +int cmd_list(string str) { + write( "%^GREEN%^ -= The Nightmare Inn =-%^RESET%^"); + write( "\n"); + write( "%^GREEN%^ There are 3 types of rooms.%^RESET%^"); + write( "%^GREEN%^ Regular: %^RESET%^"+currency_value(ROOMS[101]["cost"], "gold") ); + write( "%^GREEN%^ Deluxe: %^RESET%^" +currency_value(ROOMS[106]["cost"], "gold") ); + write( "%^GREEN%^ Honeymoon suite: %^RESET%^" +currency_value(ROOMS[109]["cost"], "gold") ); + write( "%^GREEN%^ To rent a room, type <rent 'room(like deluxe)'>%^RESET%^"); + return 1; +} + +int cmd_rent(string str) { + object ob; + int *arr; + int cost, i, x; + + if(str != "regular" && str != "deluxe" && str != "honeymoon suite") + return notify_fail("Rent what sort of room?\n"); + i = sizeof(arr = keys(ROOMS)); + x = -1; + while(i--) { + if(ROOMS[arr[i]]["name"] == str && + !(environment(this_object())->query_occupied(arr[i]))) { + x = arr[i]; + break; + } + } + if(x == -1) + return notify_fail("No such room is available right now.\n"); + cost = currency_value(ROOMS[x]["cost"], "gold"); + if(cost > this_player()->query_money("gold")) { + this_object()->eventForce("speak You do not have enough money " + "for one of those rooms!"); + return 1; + } + this_player()->AddCurrency(-cost, "gold"); + environment(this_object())->set_occupied(x); + message("my_action", sprintf("You rent room %d of the Nightmare Inn.", + x), this_player()); + message("other_action", sprintf("%s rents a room at the Nightmare Inn.", + this_player()->query_cap_name()), environment(this_object()), + ({ this_player() }) ); + ob = new(LIB_ITEM); + ob->SetKeyName("hotel key"); + ob->SetShort("a hotel key"); + ob->SetLong(sprintf("The key to room %d at the Nightmare Inn.", x)); + ob->SetMass(50); + ob->SetValue(100); + ob->SetRead(sprintf("The Nightmare Inn.\nRoom %d.\n", x)); + ob->SetId( ({ "key", "hotel key", + environment(this_object())->query_key_id(x) }) ); + if(ob->move(this_player())) { + message("my_action", "You drop your key!", this_player()); + message("other_action", sprintf("%s drops %s key!", + this_player()->query_cap_name(), possessive(this_player())), + environment(this_object()), ({ this_player() }) ); + ob->move(environment(this_object())); + } + return 1; +} diff --git a/lib/domains/Praxis/obj/mon/spider.c b/lib/domains/Praxis/obj/mon/spider.c new file mode 100644 index 0000000..26a1be6 --- /dev/null +++ b/lib/domains/Praxis/obj/mon/spider.c @@ -0,0 +1,57 @@ +// /domains/Praxis/obj/mon/spider.c +// Semi-Random spiders for the Pit of Spiders +// Part of the Mortal Law system at Nightmare +// Created by Manny@Nightmare 940831 + +#include <lib.h> + +inherit LIB_NPC; + +create() { + ::create(); + SetKeyName("spider"); + switch(random(5)) { + case 0: + SetId( ({ "spider", "leaper", "black leaper" }) ); + SetShort("Black Leaper"); + SetLong("There are few spiders larger and more greusome than " + "the infamous Black Leaper.."); + SetLevel(20); + break; + case 1: + case 2: + SetId( ({ "spider", "timber spider", "giant timber spider" }) ); + SetShort("Giant Timber Spider"); + SetLong("A very large and ugly grey spider. It looks quite " + "hungry."); + SetLevel(random(3)+12); + break; + default: + SetId( ({ "spider", "cave spider" }) ); + SetShort("Praxis cave spider"); + SetLong("A medium-sized black spider with a cresent-shaped " + "moon on its tail end."); + SetLevel(random(3)+8); + break; + } + SetRace("insect"); + SetGender("male"); + SetAggressive(999999); + SetDie( (:"death_func":) ); +} + +int death_func() { + message("say", "%^RED%^"+this_object()->query_name()+" squeals out " + "a loud shreak, then falls dead.", environment(this_object())); + if(!present("spider", environment(this_object()))) { + int x; + + message("say", "%^RED%^You notice additional spiders " + "creeping in from cracks at the base of the pit!", + environment(this_object())); + for(x=0; x<10; ++x) { + new("/"+__DIR__+"obj/mon/spider")->move(environment(this_object())); + } + } + return 1; +} diff --git a/lib/domains/Praxis/obj/mon/unity.c b/lib/domains/Praxis/obj/mon/unity.c new file mode 100644 index 0000000..742069d --- /dev/null +++ b/lib/domains/Praxis/obj/mon/unity.c @@ -0,0 +1,64 @@ +#include <lib.h> + +inherit LIB_NPC; + +void check_quest(string *what); +void check_immortal(string a, string b); + +void create() { + ::create(); + SetKeyName("unity"); + SetId( ({ "unity" }) ); + SetShort( "Unity, the grantor of immortality"); + SetAggressive( 0); + SetLevel(28); + SetLong( "Unity grants immortality to those high mortals with mentors to sponsor them."); + SetMorality(1000); + SetRace( "human"); + SetMaxHealthPoints(100000); + SetHealthPoints(100000); + SetRace("human"); +} + +void catch_tell(string str) { + object ob; + string a, b, c; + + if(this_player() == (ob = this_object())) return; + if(sscanf(str, "%squest%s", a, b) == 2 || sscanf(str, "%stask%s", a, b) == 2) { + this_object()->eventForce("speak in farsi You must find for me the Orc Slayer! The evil orcs have taken it so that it cannot be used against them. The people of Praxis must have it back."); + return; + } + if(sscanf(str, "%shere%slayer%s", a, b, c) == 3) { + this_object()->eventForce("speak in farsi The Orc Slayer is in the treasury in the Valley of the Orcs."); + return; + } + if(sscanf(str, "%s gives you %s", a, b) == 2) { + call_out("check_quest", 2, ({ lower_case(a), lower_case(b) }) ); + } +} + +void check_quest( string *what ) { + object tp, ob; + string who, that; + + who = what[0]; + that = what[1]; + tp = present(who, environment(this_object())); + ob = present("sword"); + if(!tp) return; + if(!ob) { + tell_object(tp, "Unity says: Nice try. Now leave or die."); + return; + } + if(!ob->id("the_one_orc_slayer")) { + tell_object(ob, "Unity says: This is very nice, but I do not need it."); + eventForce("give "+that+" to "+who); + return; + } + tell_room(environment(this_object()), "Unity smiles happily.", this_object()); + tell_room(environment(this_object()), tp->query_cap_name()+" has completed the quest for the Orc Slayer.", ({ tp, this_object() })); + tell_object(tp, "Unity says: You have done well. You shall some day be a high mortal!"); + ob->destruct(); + if(tp->set_quest("orcslayer")) tp->add_exp(1000); +} diff --git a/lib/domains/Praxis/obj/mon/waitress.c b/lib/domains/Praxis/obj/mon/waitress.c new file mode 100644 index 0000000..ddbe9bf --- /dev/null +++ b/lib/domains/Praxis/obj/mon/waitress.c @@ -0,0 +1,58 @@ +#include <lib.h> +inherit LIB_BARKEEP; + +create() { + ::create(); + SetKeyName("waitress"); + SetId( ({ "waitress", "restaurant waitress" }) ); + SetShort("A restaurant waitress"); + SetAggressive( 0); + SetLevel(10); + SetLong("She is ready to take your order.\n"); + SetGender("female"); + SetMorality(164); + SetRace( "nymph"); + SetHealthPoints(270); + AddCurrency("copper", random(200)); + SetSkill("melee",90); + SetLocalCurrency("gold"); + //SetMenu( + // ({ + // "lobster", "worms", "fish", "fries" + // }), + // ({ "food", "food", "food", "food" }), + // ({ 25, 15, 8, 3 }) + // ); + // set_my_mess( + // ({ + // "What a wonderful way of not cooking lobsters!\n", + // "Feel them wiggle in your throat?\n", + // "Tasty indeed!\n", + // "You enjoy them one by one to the end.\n" + // }) + // ); + // set_your_mess( + // ({ + // "enjoys some uncooked lobster.\n", + // "slides down a plate of worms.\n", + // "chomps on some Praxian fish.\n", + // "eats some fries one by one.\n" + // }) + // ); + // SetMenu_short( + // ({ + // "A lobster", + // "A plate of sea worms", + // "A nice fish", + // "Fries" + // }) + // ); + // SetMenu_long( + // ({ + // "It is uncooked in a Praxia sort of way.\n", + // "They are still alive!\n", + // "Mmmmmmm good.\n", + // "Not many there, but something just the same.\n" + // }) + // ); +} diff --git a/lib/domains/Praxis/obj/weapon/bow.c b/lib/domains/Praxis/obj/weapon/bow.c new file mode 100644 index 0000000..f9dd050 --- /dev/null +++ b/lib/domains/Praxis/obj/weapon/bow.c @@ -0,0 +1,28 @@ +// /domains/Praxis/obj/weapon/bow.c +// Short bow used in executions. +// For the Nightmare mortal law system. +// Created by Manny@Nightmare 940906 + +#include <lib.h> + +inherit LIB_ITEM; + +create() { + ::create(); + SetKeyName("bow"); + SetId( ({ "bow", "short bow" }) ); + SetShort("short bow"); + SetLong("A small bow."); + SetMass(10); + SetClass(2); + SetValue(10); +} + +void init() { + ::init(); + if(environment(this_object())->query_name() != "guard") { + write("The short bow crumbles in your hands."); + destruct(); + } +} + diff --git a/lib/domains/Praxis/obj/weapon/dagger.c b/lib/domains/Praxis/obj/weapon/dagger.c new file mode 100644 index 0000000..f2b25c5 --- /dev/null +++ b/lib/domains/Praxis/obj/weapon/dagger.c @@ -0,0 +1,16 @@ +#include <lib.h> +#include <damage_types.h> +inherit LIB_ITEM; + +create() { + ::create(); + SetId( ({ "dagger", "rusty dagger" }) ); + SetKeyName("dagger"); + SetShort("A rusty dagger"); + SetLong("An old dagger someone just threw out.\n"); + SetMass(350); SetValue( 25); + SetDamageType(KNIFE); + SetClass(7); + SetWeaponType("knife"); + SetWield("It's yucky, but it wields."); +} diff --git a/lib/domains/Praxis/obj/weapon/orc_slayer.c b/lib/domains/Praxis/obj/weapon/orc_slayer.c new file mode 100644 index 0000000..2c4b918 --- /dev/null +++ b/lib/domains/Praxis/obj/weapon/orc_slayer.c @@ -0,0 +1,32 @@ +#include <lib.h> +inherit LIB_ITEM; + +create() { + ::create(); + SetId(({"sword", "the_one_orc_slayer","orcslayer","fine sword"})); + SetKeyName("orcslayer"); + SetShort("a fine sword"); + SetLong("It is a very finely crafter sword with the picture of a dying orc on it.\nThere are writings on it.\n"); + SetMass(611); SetValue( 200); + + SetClass(7); + SetWeaponType("blade"); + SetWield("You feel a great hatred for orcs as you wield the sword.\n"); + SetRead( "Orcslayer\n"); + + true(); +} + +int eventStrike(object ob) { + int x, y; + + if(ob->query_race() != "orc") return 0; + y = random(10); + x = this_player()->query_alignment(); + if(x> 0) x = (x/100); + else x = 0; + y += x; + write("The Orcslayer draws more orc blood!\n"); + say(this_player()->query_cap_name()+" Orcslayer draws more orc blood!\n", this_player()); + return y; +} diff --git a/lib/domains/Praxis/obj/weapon/sword.c b/lib/domains/Praxis/obj/weapon/sword.c new file mode 100644 index 0000000..d3806fe --- /dev/null +++ b/lib/domains/Praxis/obj/weapon/sword.c @@ -0,0 +1,18 @@ +#include <lib.h> +inherit LIB_ITEM; + +create() { + ::create(); + SetId(({"sword","dull sword","a dull sword"})); + SetKeyName("sword"); + SetShort("a dull sword"); + SetLong( "This sword has seen better days. It appears to have " + "been sitting in the sewers a while and as a consequence it " + "is rusted almost to the point of uselessness."); + SetMass(500); SetValue( 50); + + SetClass(7); + SetWeaponType("blade"); + SetWield("A disgusting slime covers your hand as you " + "wield the sword."); +} diff --git a/lib/domains/Praxis/ombud_hall.c b/lib/domains/Praxis/ombud_hall.c new file mode 100644 index 0000000..16b46b1 --- /dev/null +++ b/lib/domains/Praxis/ombud_hall.c @@ -0,0 +1,39 @@ +inherit "/lib/std/room"; + +void create() { + object ob; + + ::create(); + SetProperty("light", 2); + SetProperty("indoors", 1); + SetShort( "Complaint Department"); + SetLong( + "You are in a dark, musty room. This is the official " + "Nightmare complaints department. Post any gripes, questions, or comments " + "you have that you wish for the wizards to address on the board."); + SetExits( + ([ + "up" : "/domains/Praxis/adv_main", + "west" : "/domains/Praxis/hm_chamber.c" + ]) + ); + + ob = new("/lib/bboard"); + ob->SetKeyName("board"); + ob->SetId( ({ "comments board", "board" }) ); + ob->set_board_id("ombud"); + ob->set_max_posts(50); + ob->set_edit_ok( ({ "nialson", "ninja" }) ); + ob->SetShort("the Board of the Complainers"); + ob->SetLong( "People of this reality come here to post their " + "comments and questions for the immortals who control " + "the fate of all reality.\n"); + ob->move(this_object()); + SetProperty("no steal", 1); + SetProperty("no attack", 1); + SetProperty("no castle", 1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/orc_valley/chamber1.c b/lib/domains/Praxis/orc_valley/chamber1.c new file mode 100644 index 0000000..c0d69f4 --- /dev/null +++ b/lib/domains/Praxis/orc_valley/chamber1.c @@ -0,0 +1,59 @@ +#include <lib.h> +inherit "/lib/std/room"; + +void create() { + ::create(); + SetProperty("light", 0); + SetProperty("indoors", 1); + SetShort( "An orc soldier's chamber"); + SetLong( + "You are in a dark living chamber inside the orc fortress. " + "A passage west leads to the courtyard."); + SetItems( + (["chamber" : "It is small with little in the way of furnishings.", + "furnishings" : "They are nothing of interest.", + "passage" : "It leads out to the courtyard."]) ); + SetExits( (["west" : "/domains/Praxis/orc_valley/passage1"]) ); +} + +void reset() { + object ob, thing; + + ::reset(); + if(!present("orc")) { + ob = new("/lib/npc"); + ob->SetKeyName("soldier"); + ob->SetId( ({ "orc", "orc soldier", "soldier" }) ); + ob->SetShort( "Orc soldier"); + ob->SetLong( "He is ugly and very unhappy about " + "your presence."); + ob->SetClass("fighter"); + ob->SetSkill("blunt", 50); + ob->SetRace( "orc"); + ob->SetGender("male"); + ob->SetLevel(7); + ob->SetHealthPoints(129); + ob->SetMorality(-135); + ob->SetAggressive( 18); + ob->SetRace("human"); + ob->SetWielding_limbs( ({ "right hand", "left hand" }) ); + ob->move(this_object()); + + thing = new(LIB_ITEM); + thing->SetKeyName("mace"); + thing->SetId( ({ "mace", "battle mace" }) ); + thing->SetShort( "Battle mace"); + thing->SetLong( "It was clearly made by orcs."); + thing->SetType("blunt"); + thing->SetClass(14); + thing->SetAC(3); + thing->SetMass(312); + thing->SetValue(171); + thing->move(ob); + ob->eventForce("wield mace in right hand"); + } +} +void init(){ + ::init(); +} + diff --git a/lib/domains/Praxis/orc_valley/chamber2.c b/lib/domains/Praxis/orc_valley/chamber2.c new file mode 100644 index 0000000..9b0fac6 --- /dev/null +++ b/lib/domains/Praxis/orc_valley/chamber2.c @@ -0,0 +1,58 @@ +#include <lib.h> +inherit "/lib/std/room"; + +void create() { + ::create(); + SetProperty("light", 0); + SetProperty("indoors", 1); + SetShort( "An orc soldier's chamber"); + SetLong( + "You are in a dark living chamber inside the orc fortress. " + "A passage east leads to the courtyard."); + SetItems( + (["chamber" : "It is small with little in the way of furnishings.", + "furnishings" : "They are nothing of interest.", + "passage" : "It leads out to the courtyard."]) ); + SetExits( (["east" : "/domains/Praxis/orc_valley/passage2"]) ); +} + +void reset() { + object ob, thing; + + ::reset(); + if(!present("orc")) { + ob = new("/lib/npc"); + ob->SetKeyName("soldier"); + ob->SetId( ({ "orc", "orc soldier", "soldier" }) ); + ob->SetShort( "Orc soldier"); + ob->SetLong( "He is ugly and very unhappy about " + "your presence."); + ob->SetClass("fighter"); + ob->SetSkill("two handed", 50); + ob->SetRace( "orc"); + ob->SetGender("male"); + ob->SetLevel(7); + ob->SetHealthPoints(129); + ob->SetMorality(-135); + ob->SetAggressive( 18); + ob->SetRace("human"); + ob->SetWielding_limbs( ({ "right hand", "left hand" }) ); + ob->move(this_object()); + + thing = new(LIB_ITEM); + thing->SetKeyName("sword"); + thing->SetId( ({ "sword", "two-handed sword" }) ); + thing->SetShort( "Two-handed sword"); + thing->SetLong( "It was clearly made by orcs."); + thing->SetType("two handed"); + thing->SetClass(15); + thing->SetMass(450); + thing->SetValue(299); + thing->move(ob); + ob->eventForce("wield sword in right hand and left hand"); + } +} +void init(){ + ::init(); +} + diff --git a/lib/domains/Praxis/orc_valley/guard.c b/lib/domains/Praxis/orc_valley/guard.c new file mode 100644 index 0000000..37853d3 --- /dev/null +++ b/lib/domains/Praxis/orc_valley/guard.c @@ -0,0 +1,80 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 2); + SetProperty("no castle", 1); + SetShort( "The entrance to the Valley of the Orcs"); + SetLong( + "In the shadow of the Daroq Mountains to the west, and just north " + "of the great highway is the valley of the orcs. Here you find " + "the entrance to a huge stone orc fortress surrounded by dense " + "forest. The great highway is south of here."); + SetItems( + (["mountains" : "They are a dark range of mountains to the " + "northwest. To the southwest, the mountains are go by " + "the name of Destiny Mountains.", + "highway" : "You cannot see it through the trees.", + "valley" : "It sits in the shadow of the Daroq Mountains.", + "entrance" : "A grand stone gateway into the orc fortress.", + "stone" : "It is an old grey stone that has stood here for ages.", + "fortress" : "It is the home of the orcs who live in Orc Valley.", + "forest" : "It is terribly dense here.", + "trees" : "They are huge and grow close together.", + "gateway" : "The entrance to the orc fortress."]) ); + SetSkyDomain("town"); + SetExits( + (["north" : "/domains/Praxis/orc_valley/open", + "south" : "/domains/Praxis/highway3"]) ); + AddExit("north", "/domains/Praxis/orc_valley/open", (: "go_north" :) ); +} + +void reset() { + int i, x; + object ob, thing; + + ::reset(); + if(!present("orc")) { + for(i=0; i< 3; i++) { + ob = new(LIB_NPC); + ob->SetKeyName("guard"); + ob->SetId( ({ "orc", "orc guard", "guard" }) ); + ob->SetShort( "Orc guard"); + ob->SetLong( "He is not happy to have people like you around."); + ob->SetRace( "orc"); + ob->SetGender("male"); + ob->SetLevel(4); + ob->SetHealthPoints(77); + ob->SetMorality(-75); + ob->SetAggressive( 15); + ob->SetWielding_limbs( ({ "right hand", "left hand" }) ); + ob->move(this_object()); + + thing = new(LIB_ITEM); + thing->SetKeyName("axe"); + thing->SetId( ({ "axe", "hand axe" }) ); + thing->SetShort( "Hand axe"); + thing->SetLong( "It was clearly made by orcs."); + thing->SetType("knife"); + thing->SetClass(8); + thing->SetMass(223); + thing->SetValue(90); + thing->move(ob); + ob->eventForce("wield axe in right hand"); + } + } +} + +int go_north() { + if(present("orc")) { + present("orc")->eventForce("speak in orcish No one gets past us!"); + return 0; + } + else return 1; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/orc_valley/open.c b/lib/domains/Praxis/orc_valley/open.c new file mode 100644 index 0000000..64646e0 --- /dev/null +++ b/lib/domains/Praxis/orc_valley/open.c @@ -0,0 +1,43 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 2); + SetProperty("night light", 1); + SetProperty("no castle", 1); + SetShort( "An open courtyard in the orc fortress"); + SetLong( + "The courtyard around you is surrounded by ancient stone walls " + "that gives this fortress the feeling of impregnability. An " + "impressive archway south opens out into Orc Valley. " + "There are passages east and west."); + SetItems( + (["courtyard" : "An open yard walled in by stone walls on every side.", + "yard" : "It has no roof, but the walls are so high you " + "can see only sky.", + "stone" : "A grey stone of unknown origin. There are " + "writings on it.", + "walls" : "You cannot get beyond them unnaturally.", + "fortress" : "It looks extremely old.", + "arch" : "A huge, heavily guarded entrance to the fortress.", + "archway" : "It forms the huge, heavily guarded entrance to " + "the fortress.", + "valley" : "You cannot see any of it from inside the courtyard.", + "passages" : "They lead to the inner parts of the fortress.", + "passage" : "You have no idea where it might lead."]) ); + SetExits( + (["east" : "/domains/Praxis/orc_valley/passage1", + "west" : "/domains/Praxis/orc_valley/passage2", + "north" : "/domains/Praxis/orc_valley/shaman", + "south" : "/domains/Praxis/orc_valley/guard"]) ); + SetSearch( 0, "Search what?"); + SetSearch( "walls", "You notice a secret passage in the north wall."); + SetSearch("wall", "Which wall?"); + SetSearch("north wall", "You notice a secret passage."); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/orc_valley/passage1.c b/lib/domains/Praxis/orc_valley/passage1.c new file mode 100644 index 0000000..66d75da --- /dev/null +++ b/lib/domains/Praxis/orc_valley/passage1.c @@ -0,0 +1,19 @@ +inherit "/lib/std/room"; + +void create() { + ::create(); + SetProperty("light", 1); + SetProperty("indoors", 1); + SetShort( "A dark passage"); + SetLong( + "You are in a dark passage inside the orc fortress."); + SetItems( + (["passage" : "You cannot see much of anything."]) ); + SetExits( + (["east" : "/domains/Praxis/orc_valley/chamber1", + "west" : "/domains/Praxis/orc_valley/open"]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/orc_valley/passage2.c b/lib/domains/Praxis/orc_valley/passage2.c new file mode 100644 index 0000000..1b23781 --- /dev/null +++ b/lib/domains/Praxis/orc_valley/passage2.c @@ -0,0 +1,18 @@ +inherit "/lib/std/room"; + +void create() { + ::create(); + SetProperty("light", 1); + SetProperty("indooors", 1); + SetShort( "A dark passage"); + SetLong( + "You are in a dark passage inside the orc fortress."); + SetItems( + (["passage" : "You cannot see much of anything."]) ); + SetExits( + (["west" : "/domains/Praxis/orc_valley/chamber2", + "east" : "/domains/Praxis/orc_valley/open"]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/orc_valley/shaman.c b/lib/domains/Praxis/orc_valley/shaman.c new file mode 100644 index 0000000..ef11891 --- /dev/null +++ b/lib/domains/Praxis/orc_valley/shaman.c @@ -0,0 +1,49 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 1); + SetProperty("indoors", 1); + SetProperty("no castle", 1); + SetShort( "The chamber of the orc shaman"); + SetLong( + "This secret room is the chamber of the orc shaman. " + "It is most certain that you should not be here."); + SetItems( + (["chamber" : "It is a roundish room and dimly lit."]) ); + SetExits( + (["south" : "/domains/Praxis/orc_valley/open", + "north" : "/domains/Praxis/orc_valley/treasure"]) ); + AddExit("north", "/domains/Praxis/orc_valley/treasure", (: "go_north" :) ); +} + +void reset() { + object mon, ob; + + ::reset(); + if(!present("shaman")) { + mon = new("/domains/Praxis/obj/mon/orc_shaman"); + mon->move(this_object()); + ob = new(LIB_ITEM); + ob->SetKeyName("key"); + ob->SetId( ({ "key", "stone key", "a stone key", "orc_treasure" }) ); + ob->SetShort( "A stone key"); + ob->SetLong( "There is nothing special about it."); + ob->SetMass(190); + ob->SetValue(30); + ob->move(mon); + } +} + +int go_north() { + if(!present("shaman")) return 1; + write("The shaman smashes you as you try to go north!"); + this_player()->add_hp(-(random(10))); + return 0; +} +void init(){ + ::init(); +} + diff --git a/lib/domains/Praxis/orc_valley/treasure.c b/lib/domains/Praxis/orc_valley/treasure.c new file mode 100644 index 0000000..26bf980 --- /dev/null +++ b/lib/domains/Praxis/orc_valley/treasure.c @@ -0,0 +1,35 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 1); + SetProperty("indoors", 1); + SetProperty("no castle", 1); + SetSmell("default", "It smells very musty in here."); + SetShort( "Treasury of the Valley Orcs"); + SetLong( + "This small vault where the orc of the valley keep their " + "treasure is poorly lit and littered with dust, making you well " + "aware that the orcs willingly allow anyone in here."); + SetItems( + (["vault" : "It is very, very dimly lit."]) ); + SetExits( (["south" : "/domains/Praxis/orc_valley/shaman"]) ); + SetNoClean(1); + SetProperty("no teleport", 1); +} + +void reset() { + ::reset(); + if(!present("chest")) + new("/domains/Praxis/obj/misc/chest")->move(this_object()); + //present("chest", this_object())->SetClosed(0); + //if(!present("orcslayer", present("chest"))) + new("/domains/Praxis/obj/weapon/orc_slayer")->move(present("chest")); + //present("chest")->SetClosed(1); +} +void init(){ + ::init(); +} + diff --git a/lib/domains/Praxis/party.c b/lib/domains/Praxis/party.c new file mode 100644 index 0000000..1712a77 --- /dev/null +++ b/lib/domains/Praxis/party.c @@ -0,0 +1,198 @@ +#include <lib.h> + +inherit LIB_ROOM; + +static private int __EntryAllowed, __PartyTime; + +int query_party_time(); +int x; + +void create() { + room::create(); + SetProperties( ([ "light":2, "indoors":1, "no attack":1, + "no teleport":1, "no steal":1, "no magic":1 ]) ); + SetShort("%^MAGENTA%^%^BOLD%^In the volcano%^RESET%^"); + SetLong( + "You are standing on a wide, circular platform, surrounded on " + "all sides by %^RED%^bubbling lava%^RESET%^. The platform floats " + "above the pool of lava at a safe distance, yet close enough for " + "you to feel the heat as the lava sometimes flares upward. " + "The platform is decorated with %^MAGENTA%^floating lights " + "%^RESET%^of %^BLUE%^varying %^ORANGE%^hues and %^RESET%^size. " + "Tables with refreshments have also been placed near the edges of " + "the platform. "); + SetItems( + ([ + ({"platform", "wide platform", "circular platform"}) : + "The platform floats " + "above the pool of lava at a safe distance, yet close enough for " + "you to feel the heat as the lava sometimes flares upward. " + "The platform is decorated with %^MAGENTA%^floating lights " + "%^RESET%^of %^BLUE%^varying %^ORANGE%^hues and %^RESET%^size. " + "Tables with refreshments have also been placed near the " + "edges of the platform. ", + ({"sides", "side", "edges", "edge"}) : + "The platform is surrounded on all sides by " + "%^RED%^bubbling lava.%^RESET%^", + + ({"pool", "pool of lava", "lava", "bubbling lava"}) : + (:this_object(), "look_lava":), + + ({"lights", "light", "floating lights", "floating light"}) : + (:this_object(), "look_lights":), + ({"tables", "table"}) : + "The tables are covered with many delicious treats. " + "Bottles containing every conceivable combination " + "of drink possible are set up along the tables. As a matter-of-fact, you feel like pouring yourself a glass of frosty beverage right now. " + "You intuit that pour <drinkname> will provide you with a glass of your favorite " + "frosty beverage. ", + ({"treats", "treat"}) : (:this_object(), "look_treat":) + ]) ); + SetExits( ([ "square" : "/domains/Praxis/square" ]) ); +} + +void init() { + room::init(); + add_action("cmd_pour", "pour"); +} + +void start_party(string msg) { + if(base_name(previous_object()) != "/cmds/mortal/_mudparty") return; + if(query_party_time()) return; + message("shout", sprintf("Party announcement from %s: A %s party is now " + "being held to celebrate %s!", this_player()->query_cap_name(), + mud_name(), msg), users()); + message("shout", "You have 2 minutes to type \"mudparty join\" in " + "order to join the party!", users()); + __EntryAllowed = 1; + __PartyTime = 1; + call_out("deny_entry", 120); +} + +static void deny_entry() { __EntryAllowed = 0; } + +int query_party_time() { return __PartyTime; } + +int query_entry_allowed() { return __EntryAllowed; } + +string look_lava(string unused) +{ + x=random(3)+1; + + if(x==1) + { + message("info", + "%^RED%^A magnificent geyser of lava explodes into the air and " + "parts before striking the platform, sparing you certain death. " + "%^RESET%^", + environment(this_player())); + } + + if(x==2) + { + message("info", + "%^RED%^A jet of flame falres from the lava and casts the room " + "in red-hued light.%^RESET%^", environment(this_player())); + } + + if(x==3) + { + message("info", + "%^RED%^%^BOLD%^The platform shifts about as a large pillar of lava " + "gushes up from beneath it.%^RESET%^", + environment(this_player())); + } + + if(x==4) + { + message("info", + "%^MAGENTA%^The lava changes hues and from %^RED%^red %^MAGENTA%^to " + "purple.%^RESET%^", + environment(this_player())); + } + + return("The lava is constantly shifting and bubbling. You can see large " + "chunks of rock floating within it. "); +} + + +string look_lights(string unused) +{ + x=random(3)+1; + + if(x==1) + { + return( + "A pretty %^YELLOW%^yellow%^RESET%^ orb drifts near to you and casts " + "a cheery glow on you. "); + } + + if(x==2) + { + return( + "A pretty %^BLUE%^blue%^RESET%^ orb drifts near to you and casts " + "a mellow glow on you. "); + } + + if(x==3) + { + return( + "A pretty %^MAGENTA%^purple%^RESET%^ orb drifts near to you and casts " + "a purple glow over your body. "); + } + + if(x==4) + { + return( + "A pretty %^RED%^red%^RESET%^ orb drifts near to you and casts " + "a rosy glow over your body. "); + } +} + + +int look_treat() +{ + message("other_action", + this_player()->query_cap_name()+" eats and drinks " + "refreshments from the table after looking them over. ", + environment(this_player()), this_player()); + message("my_action", + "After looking at the vast array of treats before you, you " + "decide to try and sample all of them! Punch, cookies, meats.." + "The sky is the limit!", this_player()); + return 1; +} + +int cmd_pour(string str) { + object ob; + string *words; + + // if(!str) return notify_fail("Pour what?\n"); + // if(this_player()->query_mp() < 10) + // return notify_fail("You are too weak for that!\n"); + // words = explode(str, " "); + // if(words[0] == "A" || words[0] == "An") words[0] = lower_case(words[0]); + // ob = new(DRINK); + // ob->SetKeyName(words[sizeof(words)-1]); + // ob->SetMass(75); + // ob->SetId(explode(strip_colours(str), " ")); + // if(sizeof(words) > 2) + // SetAdjectives(words[0..sizeof(words)-2]); + // ob->SetShort(implode(words, " ")); + // ob->SetLong("A nice drink created by "+ + // this_player()->query_cap_name()+"."); + // ob->SetStrength(random(30)+2); + // ob->set_drink("$N drink $O.", + // "$N drinks $O poured by "+this_player()->query_cap_name()+"."); + // this_player()->add_hp(-2); + // if(ob->move(this_player())) { + // message("my_action", "You cannot carry that!", this_player()); + // ob->destruct(); + // return 1; + // } + // message("my_action", "You pour "+implode(words, " ")+".", this_player()); + // message("other_action", sprintf("%s pours %s.", + // this_player()->query_cap_name(), implode(words, " ")), + // this_object(), ({ this_player() })); + return 1; +} diff --git a/lib/domains/Praxis/pass1.c b/lib/domains/Praxis/pass1.c new file mode 100644 index 0000000..17e9fa7 --- /dev/null +++ b/lib/domains/Praxis/pass1.c @@ -0,0 +1,32 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperties( (["light":3, "no castle" : 1 ]) ); + SetShort( "eastern end of the Daroq Mountains pass"); + SetLong( "Looking down this great ravine you can see the " + "Great Western Highway winding its way east across " + "the land. Veering off to the left, this path leads " + "into the Daroq Mountains, where it is rumored that " + "goblins, balrogs and tak'daroqs live. The territory " + "is very rough and dangerous, civilization is far " + "behind you. Not too far off to the west is the highest " + "point of the path."); + SetItems( (["pass" : "A gloomy pass through the Daroq Mountains.", + "highway" : "The Great Western highway. It leads into Praxis.", + "lands" : "The fertile lands of the east.", + "range" : "The Daroq Mountains, home of many vile creatures.", + "mountains" : "The Daroq Mountains, home of many vile creatures.", + "territory" : "It belongs to the evil creatures of the underground.", + "point" : "From there, the pass heads down westward into " + "the Qajip Desert."]) ); + SetSkyDomain("town"); + SetExits( + (["northwest" : "/domains/Praxis/pass2", + "east" : "/domains/Praxis/highway3"]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/pass2.c b/lib/domains/Praxis/pass2.c new file mode 100644 index 0000000..ebc144f --- /dev/null +++ b/lib/domains/Praxis/pass2.c @@ -0,0 +1,37 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(25); + SetShort( "a mountain pass"); + SetLong( + "You are at the zenith of the dark pass which runs through " + "the Daroq Mountains. Looking down below, you can see " + "the barren Qajip Desert off to the west. It is rumored " + "that upon entering the desert, few make it out alive. " + "Far off to the east you can see the gentle swells of " + "a forest valley. Directly ahead a small cave opens " + "up into the mountain."); + SetItems( + (["point" : "From here it looks like you can see the entire world.", + "pass" : "It winds around from the west to the southeast.", + "mountains" : "A huge mountain range separating the fertile " + "lands of the east from the desert.", + "valley" : "A huge forested valley.", + "desert" : "The Qajip Desert where many travellers have " + "lost their way and not been found.", + "forest" : "It is dark and gloomy near the mountains, but " + "it looks friendlier off to the east.", + "cave" : "The cave stands very darkly and ominously before you.", + "mountain" : "It is one of the lower ones, guarding the pass."]) ); + SetSkyDomain("town"); + SetExits( + (["west" : "/domains/Praxis/pass3", + "southeast" : "/domains/Praxis/pass1", + "north" : "/domains/Praxis/mountains/entrance"]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/pass3.c b/lib/domains/Praxis/pass3.c new file mode 100644 index 0000000..61e63c6 --- /dev/null +++ b/lib/domains/Praxis/pass3.c @@ -0,0 +1,38 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(25); + SetShort( "a mountain pass"); + SetLong( + "You are west of the highest point of the Daroq Mountains. " + "Off to the south you can see some less imposing " + "mountains, known as the Destiny Mountains. The trail " + "which you are traveling rises high above the rest of " + "the mountain range, allowing you a spectacular view " + "of the lands of Nightmare. The path leads east and west." ); + SetItems( + (["point" : "From here it looks like you can see the entire world.", + "pass" : "The pass heads down into the loneliness of the " + "Qajip Desert.", + "mountains" : "A huge mountain range separating the fertile " + "lands of the east from the desert.", + "valley" : "A huge forested valley.", + "desert" : "The Qajip Desert where many travellers have " + "lost their way and not been found.", + "mountain" : "It is one of the lower ones, guarding the pass."]) ); + SetSkyDomain("town"); + SetExits( ([ + "east" : "/domains/Praxis/pass2", + ]) ); +} +void reset() { + ::reset(); + if(!present("balrog")) + new("/domains/Praxis/obj/mon/balrog")->move(this_object()); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/pier1.c b/lib/domains/Praxis/pier1.c new file mode 100644 index 0000000..9f90590 --- /dev/null +++ b/lib/domains/Praxis/pier1.c @@ -0,0 +1,47 @@ +#include <lib.h> + +inherit LIB_FISHING; + +void create() { + ::create(); + SetProperty("no castle", 1); + SetProperty("light", 3); + SetProperty("night light", 2); + SetMaxFishing(4); + SetChance(10); + SetShort( "Pier 1 of the Port of Praxis"); + SetLong( + "Welcome to the Port of Praxis!\n" + "The Pier 1 port is virtually bustling with activity. Ships from " + "all over the reality dock here to deliver their goods to Praxis " + "and its surrounding regions. The pier is made out of solid wood " + "which has become weathered due to the rain and salty air. Torches " + "line each side of the dockss, lighting the way at night. All along " + "the pier you can see people fishing, talking and enjoying the weather."); + SetSmell("default", "Rotting fish offend your nostrils."); + SetSmell("fish", "They smell as if they have been out for days."); + SetItems( + (["port" : "Ships from all over Nightmare dock here to " + "do business in Praxis.", + "pier" : "Pier 1 of the port.", + "goods" : "Merchandise from exotic places.", + "torch" : "It lights up the pier at night.", + "torches" : "They light up the pier at night."]) ); + SetExits( + (["north" : "/domains/Praxis/s_centre4" + ]) ); +} + +void reset() { + int i; + + ::reset(); + if(!present("stick")) + new("/domains/Praxis/obj/misc/fishing_pole")->move(this_object()); + if(present("match")) return; + i = 4; + while(i--) new("/domains/Praxis/obj/misc/match")->move(this_object()); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/pit.c b/lib/domains/Praxis/pit.c new file mode 100644 index 0000000..16d1666 --- /dev/null +++ b/lib/domains/Praxis/pit.c @@ -0,0 +1,34 @@ +// /domains/Praxis/pit.c +// A torture chamber, for use with the Nightmare Mortal law system. +// Created by Manny@Nightmare 940830 + +#include <lib.h> + +inherit LIB_ROOM; + +create() { + ::create(); + SetProperties( ([ "light": 0, "no teleport" : 1, "no magic" : 1 + ]) ); + SetShort("Pit of Spiders"); + SetLong("You are standing deep underground in " + "a circular pit. The walls surrounding you are completely " + "smooth with no sign of hand holds or other ways " + "to get out."); + SetItems( ([ ({ "walls", "wall" }) : "A smooth, circular wall, " + "about 50 cubits deep and unnaturaly smooth." ]) ); +} + +void reset() { + int x; + + ::reset(); + if(!present("spider")) { + for(x=0; x<15; ++x) { + new("/domains/Praxis/obj/mon/spider")->move(this_object()); + } + } +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/planning_room.c b/lib/domains/Praxis/planning_room.c new file mode 100644 index 0000000..5e35706 --- /dev/null +++ b/lib/domains/Praxis/planning_room.c @@ -0,0 +1,39 @@ +inherit "/lib/std/room"; + +void create() { + object ob; + + ::create(); + SetProperty("light", 2); + SetProperty("indoors", 1); + SetShort( "The Planning Room"); + SetLong( (: this_object(), "go_away" :)); + SetExits( + (["west" : "/domains/Praxis/adv_inner", + ]) ); + AddExit("up", "/domains/Praxis/arch", (:"do_check":)); + ob = new("/lib/bboard"); + ob->SetKeyName("board"); + ob->SetId( ({ "board", "planning board" }) ); + ob->set_board_id("planning"); + ob->set_max_posts(30); + ob->move("/domains/Praxis/planning_room"); + ob->SetShort( "the Planning Our Reality Board"); + ob->SetLong( "A board for posting ideas so that others " + "will not use them.\n"); +} + +int do_check() { return archp(this_player()); } + +string go_away() { + string str; + + if(archp(this_player())) str = "The arch meeting room is upstairs. "; + else str = ""; + str += "All ideas are unclaimed until they appear here. " + "If your idea is taken, and you did not post it, you have only yourself to blame."; + return str; +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/post.c b/lib/domains/Praxis/post.c new file mode 100644 index 0000000..3fb6b60 --- /dev/null +++ b/lib/domains/Praxis/post.c @@ -0,0 +1,62 @@ +#include <lib.h> +#include <objects.h> +#include <post.h> + +inherit LIB_ROOM; + +void init() { + object ob; + + ::init(); + if(!living(this_player()) || !interactive(this_player())) + this_player()->eventMoveLiving("/domains/Praxis/alley1", "north"); + add_action("mail", "mail"); +} + +void create() { + ::create(); + SetShort( "Praxis post office"); + SetLong( + "Welcome to the Praxis Post Office!\n" + "The Praxis post office is a quaint whitewashed building. The floor " + "is a worn wood, due to all the customers that walk upon its floors. " + "Red trim lines the walls, and a window in the far corner lets in " + "a slight breeze. " + "People come here to read and post mail. Type <mail> to access " + "your mailbox, or <mail name> to send mail to player name. " + "The Nightmare post office runs on the intermud system, meaning " + "that you can send mails to players on any other mud on the system. " + "Type <muds> to find out who is on the system. The groups available " + "can be accessed by typing <g> at the % prompt." ); + SetProperty("no castle", 1); + SetProperty("light", 2); + SetProperty("indoors", 1); + SetItems( ([ "list" : "A list of commands you may use at the " + "post office."]) ); + //exit changed by drakken 17.aug + AddExit("north","/domains/Praxis/alley1",(: this_object(),"more" :) ); + SetProperty("no attack", 1); + SetProperty("no steal", 1); +} + +int mail(string str) { + object ob; + + if(this_player()->query_name() == "guest") { + notify_fail("Guest may not use the mailer.\n"); + return 0; + } + ob = new(OB_POSTAL); + ob->move(this_player()); + ob->start_post(str); + return 1; +} + +int more() { + object ob; + + if(!(ob = present(POSTAL_ID, this_player()))) return 1; + ob->destruct(); + return 1; +} + diff --git a/lib/domains/Praxis/project_room.c b/lib/domains/Praxis/project_room.c new file mode 100644 index 0000000..b20390a --- /dev/null +++ b/lib/domains/Praxis/project_room.c @@ -0,0 +1,52 @@ +// project_room.c +// Nightmare Mudlib +// The Project Room +// by Kalinash@Nightmare on June 30, 1994. + +#include <lib.h> +#include <daemons.h> + +inherit LIB_ROOM; + +void init() { + ::init(); + add_action("start_fun", "start"); + add_action("list_fun", "list"); +} + +void create() { + ::create(); + SetProperties( ([ + "light" : 2, + "no kill" : 1, + "no steal" : 1, + "no magic" : 1, + "no teleport" : 1, + "no castle" : 1 + ]) ); + SetShort("Project Room"); + SetLong("Welcome to the Project Tracking Department!\n" + "A list of commands is printed on the wall, use <read list> to view it. " + "This is the room you can come to find out about " + "what is going on on the immortal plane on Nightmare."); + SetExits( ([ "west" : "/domains/Praxis/mudlib" ]) ); +} + +int start_fun(string group) { + if(!group) { + message("my_action", "Start what?", this_player()); + return 1; + } + //if(!PROJECT_D->add_group(group, this_player()->query_name())) + // return notify_fail("Error in the daemon.\n"); + //message("my_action", sprintf("Group '%s' successfully created.", + // group), this_player()); + return 1; +} + +int list_fun(string which) { + if(!which) + return notify_fail("List what?\n"); + if(which == "groups") + return; +} diff --git a/lib/domains/Praxis/pub.c b/lib/domains/Praxis/pub.c new file mode 100644 index 0000000..ab4b10c --- /dev/null +++ b/lib/domains/Praxis/pub.c @@ -0,0 +1,85 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void init() { + ::init(); + add_action("read", "read"); +} + +void create() { + ::create(); + SetProperties( ([ "light": 2, "indoors" : 1, "no castle" : 1 ]) ); + SetShort( "Lars' tavern and bar"); + SetLong( + "Welcome to Lars' Tavern!\n" + "Lars' Tavern is a very old and well established pub. It " + "has recently been remodelled, and you can tell that " + "business is picking up by the general hum of chatter " + "in the room. The floor is made out of polished wood, " + "as is the counter that stands in the back of the room. " + "Pictures of the different lands of Nightmare hang " + "on the wall, as do some wanted posters of the hunted " + "rogues of this land."); + SetItems( + (["pub" : "The most hoppin' place in Praxis.", + "wall" : "The walls are covered with various pictures.", + ({ "posters", "poster", "wanted posters" }) : + "The wanted posters are very old and brittle. They mark " + "the faces of the rogues of this land.", + ({ "pictures" , "picture" }) : + "The pictures are of different parts of Nightmare, painted " + "by several of the villages' aspiring artists.", + "bar" : "The bar is actually Lars' Tavern. It is a very " + "clean and well run establishment.", + "counter" : "The wooden counter stands at the back of the " + "room and houses all of Lars' drinks.", + "room" : "You are in the main room of Lars' Tavern.", + "foo" : "bar", + "tavern" : "The tavern is the place that the people of " + "Praxis come to when they want to have a drink or just " + "be social.", + "floor" : "The floor is made out of solid oak.", + "list" : "It looks like a list of drinks. Read it to see " + "what's available."]) ); + SetExits( + (["north" : "/domains/Praxis/w_boc_la1", + "east" : "/domains/Praxis/s_centre1"]) ); + SetProperties( ([ "no castle": 1, "no attack" : 1 ]) ); +} + +void reset() { + ::reset(); + if(!present("list")) + //new("std/obj/player_list")->move(this_object()); + if(!present("lars")) + new("/domains/Praxis/obj/mon/lars")->move(this_object()); +} + +int read(string str) { + object ob; + int i; + + ob = present("lars"); + if(!ob) { + write("You cannot read the menu, as it is splattered with blood."); + return 1; + } + message("Ninfo", "The following classic drinks are served at the Lars Pub!\n", this_player()); + message("Ninfo", "-----------------------------------------------------------\n", this_player()); + message("Ninfo", "A firebreather\t\t\t"+ ob->get_price("firebreather")+" gold\n", this_player()); + message("Ninfo", "A special of the house\t\t"+ob->get_price("special")+" gold\n", this_player()); + message("Ninfo", "A pale ale\t\t\t"+ob->get_price("ale")+" gold\n", this_player()); + message("Ninfo", "-----------------------------------------------------------\n", this_player()); + message("Ninfo", "<buy drink_name> gets you a drink.\n", this_player()); + return 1; +} + + + + + + + + + diff --git a/lib/domains/Praxis/quest_room.c b/lib/domains/Praxis/quest_room.c new file mode 100644 index 0000000..ab664be --- /dev/null +++ b/lib/domains/Praxis/quest_room.c @@ -0,0 +1,78 @@ +inherit "/lib/std/room"; + +#define POINTS_NEEDED 100 +#define QUEST_DIR "/domains/Praxis/quests/" + +void init() { + ::init(); + if(!archp(this_player())) this_player()->destruct(); +} + +void create() { + string *quest_ls; + int i; + ::create(); + SetProperty("light", 1); + SetShort( "Quest room"); + SetLong( "Quests are stored here."); + quest_ls = get_dir(QUEST_DIR); + if(!sizeof(quest_ls)) return; + for(i=0; i<sizeof(quest_ls); i++) { + new(QUEST_DIR+quest_ls[i])->move(this_object()); + } +} + +void list_quests(object tp, int x) { + object *inv; + int i; + string *quest_list; + + inv = all_inventory(this_object()); + if(!sizeof(inv)) { + tell_object(tp, "There are no quests."); + return; + } + quest_list = ({}); + for(i=0; i<sizeof(inv); i++) { + if(member_array(inv[i]->query_name(), tp->query_quests()) == -1) quest_list += ({ inv[i] }); + } + if(!x) { + tell_object(tp, "There are "+sizeof(quest_list)+" quests you " + "have not solved. They are these quests:\n"); + for(i=0; i<sizeof(quest_list); i++) { + tell_object(tp, (i+1)+": "+present(quest_list[i], this_object())->GetShort()+"\n"); + } + } + else { + if(x > sizeof(quest_list)) { + tell_object(tp, "No such quest.\n"); + return; + } + tell_object(tp, present(quest_list[x-1], this_object())->GetLong()); + } +} + +int query_quest_points(string str) { + int x; + object ob; + + ob = present(str); + x = ob->query_quest_points(); + return x; +} + +int check_quests(object tp, int lev) { + int qp; + string *list; + + qp= tp->query_quest_points(); + if(lev>=5) if(qp < POINTS_NEEDED/4) return 0; + else if(lev >= 10) if(qp < POINTS_NEEDED/2) return 0; + else if(lev >= 15) if(qp < (3*POINTS_NEEDED)/4) return 0; + else if(lev > 19) if(qp < POINTS_NEEDED) return 0; + return 1; +} + +void clean_up() { return; } + + diff --git a/lib/domains/Praxis/quests/chaucer.c b/lib/domains/Praxis/quests/chaucer.c new file mode 100644 index 0000000..9ef8b73 --- /dev/null +++ b/lib/domains/Praxis/quests/chaucer.c @@ -0,0 +1,12 @@ +inherit "/std/quest_ob"; + +void create() { + ::create(); + set_name("chaucer"); + set_id( ({"chaucer", "quest_object"}) ); + set_short( "%^YELLOW%^The Canterbury Tales%^RESET%^"); + set_long( "Something seems to be amiss inside Chaucer's " + "most famous work. Aid the distraught pilgrims on their way to " + "Canterbury.\nRating: Easy"); + set_quest_points(15); +} diff --git a/lib/domains/Praxis/quests/dragon.c b/lib/domains/Praxis/quests/dragon.c new file mode 100644 index 0000000..7590240 --- /dev/null +++ b/lib/domains/Praxis/quests/dragon.c @@ -0,0 +1,13 @@ +inherit "/std/quest_ob"; + +void create() { + ::create(); + set_name("dragon"); + set_id( ({ "dragon", "quest_object" }) ); + set_short("The quest for the dragon"); + set_long( + "An evil dragon has been attacking the floating wizard fortress.\n"+ + "Find the fortress and and help the wizards by destroying the dragon.\n"+ + "Quest rating: explorer\n"); + set_quest_points(25); +} diff --git a/lib/domains/Praxis/quests/evil.c b/lib/domains/Praxis/quests/evil.c new file mode 100644 index 0000000..0d78fea --- /dev/null +++ b/lib/domains/Praxis/quests/evil.c @@ -0,0 +1,12 @@ +inherit "/std/quest_ob"; + +void create() { + ::create(); + set_name("evil"); + set_id( ({ "evil", "quest_object" }) ); + set_short("The Evil Quest"); + set_long( + "Find the evil one and plunge the silver artifact into him.\n"+ + "Quest rating: very experienced\n"); + set_quest_points(20); +} diff --git a/lib/domains/Praxis/quests/hellfire.c b/lib/domains/Praxis/quests/hellfire.c new file mode 100644 index 0000000..624eac3 --- /dev/null +++ b/lib/domains/Praxis/quests/hellfire.c @@ -0,0 +1,13 @@ +inherit "/std/quest_ob"; + +void create() { + ::create(); + set_name("hellfire"); + set_id( ({ "hellfire", "quest_object" })); + set_short("The Hellfire Quest"); + set_long( + "Locate the raging hellfire that is burning out of control\n" + "and put the fire out.\n" + "Quest rating: easy explorer.\n" ); + set_quest_points(20); +} diff --git a/lib/domains/Praxis/quests/honor.c b/lib/domains/Praxis/quests/honor.c new file mode 100644 index 0000000..532b665 --- /dev/null +++ b/lib/domains/Praxis/quests/honor.c @@ -0,0 +1,14 @@ +inherit "/std/quest_ob"; + +void create() { + ::create(); + set_name("honor"); + set_id( ({ "honor", "quest_object" }) ); + set_short("The quest for honor"); + set_long( + "An aging knight made a mistake in her youth, and now she needs\n"+ + "her honor back. Do what it takes to return her honor to her.\n"+ + "Quest rating: newbie\n" + ); + set_quest_points(8); +} diff --git a/lib/domains/Praxis/quests/imp_crown.c b/lib/domains/Praxis/quests/imp_crown.c new file mode 100644 index 0000000..955fd91 --- /dev/null +++ b/lib/domains/Praxis/quests/imp_crown.c @@ -0,0 +1,16 @@ +/* /wizards/melvaig/imp, Nightmare, November 1992 */ +inherit "/std/quest_ob"; + +void create() { + ::create(); + set_name("imp_crown"); + set_id( ({ "imp_crown" , "quest_object" }) ); + set_short("The quest for the fabled Imp crown"); + set_long( + "Destroy the Imperial crown of Simplicity. Monarchy has run rampant\n"+ + "and is more corrupt than days of old.\n"+ + "This is a quest for Newbies (levels 1-6).\n"+ + "Quest rating: beginner\n" + ); + set_quest_points(15); +} diff --git a/lib/domains/Praxis/quests/orcslayer.c b/lib/domains/Praxis/quests/orcslayer.c new file mode 100644 index 0000000..21554ec --- /dev/null +++ b/lib/domains/Praxis/quests/orcslayer.c @@ -0,0 +1,15 @@ +inherit "/std/quest_ob"; + +void create() { + ::create(); + set_name("orcslayer"); + set_id( ({ "orcslayer", "quest_object" }) ); + set_short("The quest of the immortals"); + set_long( + "Unity is the grantor of immortality. He has a quest which he\n"+ + "requires of all mortals before they ascend to the status of\n"+ + "high mortal. Go to him and ask of him the task.\n"+ + "Quest rating: easy\n" + ); + set_quest_points(20); +} diff --git a/lib/domains/Praxis/quests/pyr_quest.c b/lib/domains/Praxis/quests/pyr_quest.c new file mode 100644 index 0000000..844a857 --- /dev/null +++ b/lib/domains/Praxis/quests/pyr_quest.c @@ -0,0 +1,14 @@ +inherit "/std/quest_ob"; + +void create() { + ::create(); + set_name("pyramid"); + set_id( ({ "pyramid", "quest_object" })); + set_short("%^BLUE%^%^BOLD%^The Amonia Ra Gypt Quest%^RESET%^"); + set_long( + "Evil forces have captured the arch priestess of the Egytian Sun God, " + "Ammonia Ra Gypt. Try to find the kidnappers and free the innocent before " + "she gets scacrificed to Osiris.\n" + "Quest rating: High mortal.\n" ); + set_quest_points(35); +} diff --git a/lib/domains/Praxis/quests/the_blight_of_the_bog.c b/lib/domains/Praxis/quests/the_blight_of_the_bog.c new file mode 100644 index 0000000..b5bc998 --- /dev/null +++ b/lib/domains/Praxis/quests/the_blight_of_the_bog.c @@ -0,0 +1,14 @@ +inherit "/std/quest_ob"; + +void create() { + ::create(); + set_name("the_blight_of_the_bog"); + set_id( ({"blight", "quest_object", "the blight of the bog"}) ); + set_short( "%^GREEN%^%^BOLD%^The Blight of the Bog%^RESET%^"); + set_long( "Rumours have been floating about concerning a strange " + "disease that is ravaging sections of the North Forest. " + "You must find the source of this sickness and figure out how " + "to cure the horrible blight before it devastates the entire " + "forest surrounding the bog.\nRating: High Mortal"); + set_quest_points(40); +} diff --git a/lib/domains/Praxis/quests/zemoch.c b/lib/domains/Praxis/quests/zemoch.c new file mode 100644 index 0000000..5d75e01 --- /dev/null +++ b/lib/domains/Praxis/quests/zemoch.c @@ -0,0 +1,14 @@ +inherit "/std/quest_ob"; + +void create() { + ::create(); + set_name("zemoch"); + set_id( ({ "zemoch", "quest_object", "zemoch quest" })); + set_short("The Zemoch Quest"); + set_long( + "You must stop the evil Zemochs from sacrificing any more innocents.\n" + "Helping others will help yourself in destroying the evil god of the\n" + "Zemochs, Azash.\n" + "Quest rating: High Mortal, extremely difficult\n" ); + set_quest_points(45); +} diff --git a/lib/domains/Praxis/rain_forest.c b/lib/domains/Praxis/rain_forest.c new file mode 100644 index 0000000..f4bb3b9 --- /dev/null +++ b/lib/domains/Praxis/rain_forest.c @@ -0,0 +1,18 @@ +inherit "/lib/std/room"; + +void create() { + ::create(); + SetProperty("light", 1); + SetShort( "Deep in the rain forest"); + SetLong("You are deep inside a tropical rain forest. There is a shack east of here."); + SetItems( + ([ "forest" : "A very humid jungle away from civilization."]) ); + SetSkyDomain("town"); + SetExits( ([ + "southwest" : "/domains/Praxis/jungle", + "east" : "/domains/Praxis/rogue_join.c", + ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/realty.c b/lib/domains/Praxis/realty.c new file mode 100644 index 0000000..53284cc --- /dev/null +++ b/lib/domains/Praxis/realty.c @@ -0,0 +1,167 @@ +/* /domains/Praxis/realty.c + * from Nightmare IV + * the place to buy stuff + * created by Descartes of Borg 940702 + */ + +#include <lib.h> +#include <objects.h> + +#define DEED_COST 250000 +#define ORDER_COST 17000 + +inherit LIB_ROOM; + +void create() { + room::create(); + SetProperties( ([ "light":2, "indoors":1 ]) ); + SetShort("Praxis Realty"); + SetLong( + "Welcome to Praxis Realty!\n" + "People come here to buy deeds to build estates, as well as work " + "orders for making changes to those estates. The office is built " + "up in all kinds of dreary colours, with a desk at the far end of the " + "office being the spot where all business is done." + ); + SetItems( ([ "colours": "Mostly puce.", "desk": (: "at_desk" :), + "office":"A nice little space with a desk in it." ]) ); + SetExits( ([ "north" : "/"+__DIR__+"unnamed1" ]) ); +} + +void init() { + room::init(); + add_action("read_list", "read"); + add_action("cmd_buy", "buy"); +} + +void reset() { + object ob, arm; + + room::reset(); + if(present("atmos")) return; + ob = new(LIB_NPC); + ob->SetKeyName("atmos"); + ob->SetProperties( (["no paralyze":1, "no steal":1])); + ob->SetId( ({ "atmos", "atmos the patron of high mortals", "patron", + "realtor" }) ); + ob->SetShort("Atmos, the Patron of High Mortals"); + ob->SetLong("Atmos is a geek."); + ob->SetLevel(66); + ob->SetRace("artrell"); + ob->SetClass("mage"); + ob->AddCurrency("gold", currency_value(100, "gold")); + ob->SetStat("constitution", 500); + ob->SetStat("dexterity",500); + ob->SetStat("strength", 500); + ob->SetSkill("melee", 390); + ob->SetSkill("defense", 500); + ob->SetSkill("stealth", 300); + ob->SetSkill("magic attack", 500); + ob->SetHealthPoints(1000000); + ob->SetMagicPoints(5000000); + ob->SetSpellChance(20); + ob->SetSpells( ({ "freeze", "fireball" }) ); + ob->SetMorality(100); + ob->AddLimb("head","FATAL",800000,0,15); + ob->AddLimb("torso","FATAL",800000,0,15); + ob->AddLimb("first arm","",600000,0,15); + ob->AddLimb("second arm","",600000,0,15); + ob->AddLimb("third arm","",600000,0,15); + ob->AddLimb("fourth arm","",600000,0,15); + ob->AddLimb("first hand","",400000,0,15); + ob->AddLimb("second hand",400000,0,15); + ob->AddLimb("third hand","",400000,0,15); + ob->AddLimb("fourth hand","",400000,0,15); + ob->AddLimb("left leg","",600000,0,15); + ob->AddLimb("right leg","",600000,0,15); + ob->AddLimb("left foot","",400000,0,15); + ob->AddLimb("right foot","",400000,0,15); + ob->move(this_object()); + arm = new(LIB_ARMOR); + arm->SetKeyName("plate of atmos"); + arm->SetId( ({ "plate", "plate of atmos" }) ); + arm->SetAdjectives( ({ "heavy", "the" }) ); + arm->SetShort("the plate of Atmos"); + arm->SetLong("A beautifully crafted, fake-silver plate armour once " + "owned by Atmos the Geek."); + arm->SetAC(10); + arm->true(1); + arm->SetValue(1000); + arm->SetMass(1500); + arm->SetType("armour"); + arm->SetRestrictLimbs( ({ "torso", "first arm", "second arm", "third arm", + "fourth arm" }) ); + arm->set_illuminate(20); + arm->move(ob); + ob->eventForce("wear plate"); +} + +static int cmd_buy(string str) { + object ob; + + if(!present("atmos", this_object())) + return notify_fail("Atmos is missing!\n"); + if(str == "deed") { + if(this_player()->query_money("gold") < + currency_value(DEED_COST, "gold")) { + message("my_action", "You do not have enough gold.",this_player()); + return 1; + } + message("my_action", "You purchase a deed.", this_player()); + message("other_action", this_player()->query_cap_name()+ + " purchases a deed.", this_object(), ({ this_player() })); + this_player()->AddCurrency("gold", -currency_value(DEED_COST, "gold")); + ob = new(OB_DEED); + if(ob->move(this_player())) { + message("my_action", "You drop your deed.", this_player()); + message("other_action", this_player()->query_cap_name()+ + " drops "+possessive(this_player())+" deed.", this_object(), + ({ this_player() })); + ob->move(this_object()); + } + return 1; + } + else if(str == "order" || str == "work order" ) { + if(this_player()->query_money("gold") < + currency_value(ORDER_COST, "gold")) { + ob->eventForce("speak You are too low on gold!"); + return 1; + } + message("my_action", "You purchase a work order.", this_player()); + message("other_action", this_player()->query_cap_name()+ + " purchases a work order.", this_object(), ({ this_player() })); + this_player()->AddCurrency("gold", -currency_value(ORDER_COST, "gold")); + ob = new(OB_ORDER); + if(ob->move(this_player())) { + message("my_action", "You drop the work order!", this_player()); + message("other_action", this_player()->query_cap_name()+ + " drops "+possessive(this_player())+" work order.", + this_object(), ({ this_player() })); + ob->move(this_object()); + } + return 1; + } + else return 0; +} + +string at_desk(string str) { + string tmp; + + tmp = "A list of real estate options is posted on the desk. "; + if(present("atmos")) tmp += "Atmos is seated behind it waiting."; + else tmp += "No one seems to be around."; + return tmp; +} +static int read_list(string str) { + string tmp; + + if(str != "list") return 0; + tmp = "Welcome to Praxis Realty!\n" + "You may purchase any of the following items:\n" + " deed- an estate deed for creating an estate: "+ + currency_value(DEED_COST, "gold")+" gold.\n" + " order- a work order for adding rooms: "+ + currency_value(ORDER_COST, "gold")+" gold.\n"; + message("info", tmp, this_player()); + return 1; +} diff --git a/lib/domains/Praxis/restaurant.c b/lib/domains/Praxis/restaurant.c new file mode 100644 index 0000000..87c59c3 --- /dev/null +++ b/lib/domains/Praxis/restaurant.c @@ -0,0 +1,56 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void init() { + ::init(); + add_action("read", "read"); +} + +void create() { + ::create(); + SetProperties( ([ "light": 3, "indoors" : 1, "no castle" : 1 ]) ); + SetShort( "Last Dragon Restaurant"); + SetLong( + "Welcome to the Last Dragon Restaurant!\n" + "The Last Dragon Restaurant is home to the finest cusine " + "in Praxis! The atmosphere is lively and friendly, as is the service." + " The restaurant itself is an oaken structure, well polished and " + "maintained. A menu is displayed on the wall, and the waitress " + "will be happy to serve you when she is arround. South of here " + "runs Sun Alley." ); + SetItems( + (["restaurant" : "The Last Dragon Restaurant, home of " + "great Praxian cuisine.", + "wall" : "The menu is posted there.", + "menu" : "You may read it if you like."]) ); + SetExits( + (["north" : "/domains/Praxis/sun2"]) ); +} + +void reset() { + ::reset(); + if(!present("waitress")) + new("/domains/Praxis/obj/mon/waitress")->move(this_object()); +} + +int read(string str) { + object ob; + int i; + + ob = present("waitress"); + if(!ob) { + write("You cannot read the menu, as it is splattered with blood."); + return 1; + } + write("The following great foods are served here at the Last Dragon Restaurant."); + write("--------------------------------------------------------------------"); + write("Praxian lobster\t\t\t"+ ob->get_price("lobster") + " gold"); + write("A plate of sea worms\t\t"+ob->get_price("worms")+" gold"); + write("A serving of fish "+ob->get_price("fish")+" gold"); + write("Some fries\t\t\t"+ ob->get_price("fries")+" gold"); + write("-----------------------------------------------------------"); + write("<buy dish_name> gets you the food."); + return 1; +} + diff --git a/lib/domains/Praxis/rogue_hall.c b/lib/domains/Praxis/rogue_hall.c new file mode 100644 index 0000000..150efb3 --- /dev/null +++ b/lib/domains/Praxis/rogue_hall.c @@ -0,0 +1,257 @@ +#include <council.h> +#include <daemons.h> + +inherit LIB_ROOM; + +string get_new_title(object tp); +string get_male(int lev); +string get_female(int lev); +string previous_title(object tp); +int get_cost(string which, int lev); + +int CanReceive(object ob) { + if(!VOTING_D->is_time_to_vote()) + return ::CanReceive(ob); + if(creatorp(this_player()) || this_player()->query_level() < 2) + return ::CanReceive(ob); + if(VOTING_D->query_voted(this_player()->query_name(), + this_player()->query_class())) + return ::CanReceive(ob); + else { + message("my_action", "You have not yet voted for your class leader. Please do so now.", this_player()); + call_out("move_me", 5, this_player()); + } + return ::CanReceive(ob); +} + +void move_me(object who) { + who->eventMoveLiving("/domains/Praxis/"+who->query_class()+"_vote"); + return; +} + +void create() { + object ob; + + ::create(); + SetProperty("no attack",1); + SetProperty("light", 1); + SetProperty("indoors", 1); + SetShort( "The heart of the rogue hideout"); + SetLong( + "Welcome into the rogue hideout!\n"+ + "Rogues come here to sharpen their fiendish skills.\n"+ + "The available commands are <cost>, <advance>, <list (number)>, " + "<train skill amount>, <improve stat> and <roll stats>. Up " + "through a stairway guarded by a shimmering %^BLUE%^blue%^RESET%^ " + "light is the entrance to the fortress. <help skills> will list " + "all of the full names of skills."); + SetExits( + (["up" : "/domains/Praxis/rogue_join", + "council" : "/domains/Praxis/council_hall", + "east" : "/domains/Praxis/rogue_vote"]) ); + + ob = new("/lib/bboard"); + ob->SetKeyName("board"); + ob->SetId( ({ "board", "rogue board" }) ); + ob->set_board_id("rogue_board"); + ob->set_max_posts(25); + ob->set_edit_ok(ROGUE_COUNCIL); + ob->move("/domains/Praxis/rogue_hall"); + ob->SetShort( "Rogue's Board of Fiendish Plots"); + ob->SetLong( "On this rotting wood board, rogues come to post " + "of bounties dastardly deeds, and other fiendish foils " + "for other rogues to see.\n"); + // new("/realms/grumpy/rogue/obj/box.c")->move(this_object()); +} + +void init() { + ::init(); + add_action("cost","cost"); + add_action("murder", "murder"); + add_action("roll","roll"); + add_action("train", "train"); + add_action("improve", "improve"); + add_action("advance","advance"); + add_action("list","list"); +} + +int roll(string str) { + if(str != "stats") return 0; + call_other("/domains/Praxis/setter", "do_rolls"); + return 1; +} + +string get_new_title(object tp) +{ + int lev; + string gen, title; + + lev = this_player()->query_level(); + gen = this_player()->query_gender(); + if(this_player()->query_guild()) { + if(present(tp->query_guild()+"_ob", tp)) { + if(lev > 19) title = "High mortal"; + else title = present(tp->query_guild()+"_ob", tp)->query_title(tp); + title += " $N"; + } + else { + if(lev > 19) title = "High mortal $N"; + else title = "$N"; + } + } + else { + if(lev > 20) title = "High mortal $N"; + else title = "$N"; + } + if(lev > 20) title += previous_title(tp); + else if(gen == "male") title += " "+get_male(lev); + else title += " "+get_female(lev); + return title; +} + +string get_male(int lev) { + switch(lev) { + case 1: return "the rascal"; break; + case 2: return "the little thug"; break; + case 3: return "the petty thief"; break; + case 4: return "the lurking swindler"; break; + case 5: return "the minor rogue"; break; + case 6: return "the creeping cutpurse"; break; + case 7: return "the nasty thug"; break; + case 8: return "the lurking criminal"; break; + case 9: return "the devious bandit"; break; + case 10: return "the fearsome rogue"; break; + case 11: return "the deceiving fiend"; break; + case 12: return "the rich swindler"; break; + case 13: return "the accomplished rogue"; break; + case 14: return "the corrupt pick-pocket"; break; + case 15: return "the cunning thief"; break; + case 16: return "the spiteful con-artist"; break; + case 17: return "the deceitful backstabber"; break; + case 18: return "the perpetual thief"; break; + case 19: return "the grand master rogue"; break; + case 20: return "the high mortal rogue"; break; + default: return ""; break; + } +} + +string get_female(int lev) { + switch(lev) { + case 8: return "the lesser murderess"; break; + default: return get_male(lev); break; + } +} + +int advance() { return ADVANCE_D->advance(); } + +int train(string str) { + string which, which_tmp; + int amount; + + if(sscanf(str, "%s %s %d", which, which_tmp, amount) ==3) which = which + " "+ which_tmp; + else if(sscanf(str, "%s %d", which, amount) !=2) { + notify_fail("Correct syntax: <train skill amount>\n"); + return 0; + } + which = lower_case(which); + if(!this_player()->skill_exists(which)) { + notify_fail("No such skill.\n"); + return 0; + } + return ADVANCE_D->train_player(this_player(), which, amount); +} + +int improve(string str) { + string *stats; + int stat_cost; + + stats = ({ "strength", "intelligence", "wisdom", "dexterity", "constitution", "charisma" }); + str = lower_case(str); + if(member_array(str, stats) == -1) { + notify_fail("You have no such stat.\n"); + return 0; + } + stat_cost = get_cost(str, this_player()->query_base_stats(str)); + if( this_player()->query_exp()-stat_cost < ADVANCE_D->get_exp( this_player()->query_level() ) ) { + notify_fail("You are not experienced enough to improve yourself in that way.\n"); + return 0; + } + this_player()->SetStat(str, this_player()->query_base_stats(str) + 1); + this_player()->add_exp(-stat_cost); + write("You feel much "); + say(this_player()->query_cap_name()+" looks much "); + if(str == "strength") tell_room(this_object(), "stronger.\n"); + else if(str == "intelligence") tell_room(this_object(), "more intelligent.\n"); + else if(str == "wisdom") tell_room(this_object(), "wiser.\n"); + else if(str == "dexterity") tell_room(this_object(), "more nimble.\n"); + else if(str == "constitution") tell_room(this_object(), "sturdier.\n"); + else tell_room(this_object(), "more attractive.\n"); + return 1; +} + +int get_cost(string stat, int lev) { + switch(stat) { + case "intelligence": return ADVANCE_D->get_stat_cost(1, lev); break; + case "dexterity": return ADVANCE_D->get_stat_cost(1, lev); break; + case "charisma": return ADVANCE_D->get_stat_cost(1, lev); break; + default: return ADVANCE_D->get_stat_cost(2, lev); break; + } +} + +int cost(string str) { + int bing; + + write("Costs for advancement, training, and improvement:\n"); + bing = ADVANCE_D->get_exp( this_player()->query_level() + 1 ); + if(bing < 1) write("level:\t\tIt will cost you nothing to advance."); + else write("level:\t\t"+bing+"\n"); + write("skills: You train by spending the amount of experience you + desire.\n"); + write("strength:\t\t" + get_cost("strength", + this_player()->query_base_stats("strength")) + + "\t\tconstitution:\t\t" + get_cost("constitution", + this_player()->query_base_stats("constitution")) ); + write("intelligence:\t\t" + get_cost("intelligence", + this_player()->query_base_stats("intelligence")) + + "\t\tdexterity:\t\t" + get_cost("dexterity", + this_player()->query_base_stats("dexterity")) ); + write("wisdom:\t\t" + get_cost("wisdom", + this_player()->query_base_stats("wisdom")) + + "\t\tcharisma:\t\t" + get_cost("charisma", + this_player()->query_base_stats("charisma")) ); + return 1; +} +string previous_title(object tp) { + + string pre, post, str; + + str = tp->getenv("TITLE"); + sscanf(str, "%s $N %s", pre, post); + return post; +} + +int list(string str) { + int x; + + if(!str) "/domains/Praxis/quest_room"->list_quests(this_player(), 0); + else { + if(sscanf(str, "%d", x) != 1) { + notify_fail("You must give the number of the quest you want listed.\n"); + return 0; + } + if(x<1) { + notify_fail("No such quest.\n"); + return 0; + } + "/domains/Praxis/quest_room"->list_quests(this_player(), x); + } + return 1; +} + +int murder() { + if(this_player()->query_skill("murder")) return 0; + this_player()->add_skill("murder", 3, 100); + write("Done.\n"); + return 1; +} + diff --git a/lib/domains/Praxis/rogue_join.c b/lib/domains/Praxis/rogue_join.c new file mode 100644 index 0000000..6401729 --- /dev/null +++ b/lib/domains/Praxis/rogue_join.c @@ -0,0 +1,87 @@ +inherit "/lib/std/room"; +int go_down(); + +void init() { + ::init(); + add_action("become", "become"); + add_action("preview","preview"); +} + +void create() { + ::create(); + SetProperty("light", 1); + SetProperty("indoors", 1); + SetShort( "Rogue Hut"); + SetLong( + "You have stumbled upon the hideout of the Nightmare rogues. " + "What appears to be a worn down shack on the outside is actually " + "a well put together fortress on the inside. A magic " + "%^BLUE%^blue%^RESET%^ light " + "guards the entrance to the heart of the fortress down a flight " + "of stairs. The Grand Master Rogue waits here to initiate new " + "slime into the vile and contemptable class of rogues. " + "<preview> will tell you about becoming a rogue."); + SetItems( + (["hideout" : "Rogues come here to plot wicked acts.", + "shack" : "It is not really a shack, but a fortress.", + "fortress" : "The rogues make this place their hideout.", + "light" : "Only rogues can pass beyond it.", + "stairs" : "They lead down into the heart of the rogue hideout.", + ({"rogue", "master", "grand master rogue"}) : "He initiates " + "new rogues."]) ); + SetExits( ([ + "west" : "/domains/Praxis/rain_forest.c", + ]) ); + AddExit("down","/domains/Praxis/rogue_hall",(:go_down:)); +} + +int preview() { + if(this_player()->query_class() != "explorer") { + write("This is not for you."); + return 1; + } + say(this_player()->query_cap_name()+" seeks to learn about rogues.", this_player()); + write("Welcome, explorer!\n"); + write("Rogues are people who make their life and pleasure from the misery " + "of others. They keep their hideout here in the Outlands so as to " + "keep a low profile in the eyes of the civilized world which is only " + "interested in hunting them down and bringing them to justice. " + "Rogues are made up of many different types of scum. Some are murderers, " + "while others are thieves and bandits. But they all love it. " + "Keep in mind that once you choose to become a rogue, you will be " + "hated by people from all walks of life. You will never be able to " + "move about safely. Unless you avoid targeting players, that is. " + "Type <become rogue> to become a rogue."); + return 1; +} + +int become(string str) { + if(!str) { + notify_fail("Become what?\n"); + return 0; + } + if(str != "rogue") { + notify_fail("You cannot become that here.\n"); + return 0; + } + if(this_player()->query_class() != "explorer") { + write("You are much too old to start learning our ways now!"); + return 1; + } + write("The Grand Master Rogue initiates you into the class of rogues."); + say(this_player()->query_cap_name()+" becomes a rogue.", this_player()); + this_player()->SetClass("rogue"); + this_player()->setenv("TITLE", "$N the novice rogue"); + this_player()->init_skills("rogue"); + this_player()->setenv("start", "/domains/Praxis/rogue_hall"); + return 1; +} + +int go_down() { + if(this_player()->query_class() != "rogue") { + write("You cannot penetrate the force field that blocks the passage."); + say(this_player()->query_cap_name()+" tries to get into the heart of the fortress, but fails.", this_player()); + return 0; + } + return 1; +} diff --git a/lib/domains/Praxis/rogue_vote.c b/lib/domains/Praxis/rogue_vote.c new file mode 100644 index 0000000..d9ae899 --- /dev/null +++ b/lib/domains/Praxis/rogue_vote.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include <voting.h> +#include <daemons.h> + +inherit "/domains/town/room/voters"; + +void create() { + ::create(); + SetProperty("light", 1); + SetProperty("no castle", 1); + SetProperty("indoors", 1); + SetShort( "Voting hall of the rogues"); + SetLong( (: this_object(), "new_long" :)); + SetItems( + (["list" : "During election time, it lists all candidates."]) ); + SetExits( + (["west" : "/domains/Praxis/rogue_hall"]) ); +} + +string new_long() { + if(VOTING_D->election_day()) + return "This is the room where Rogues can put in their bid for office. " + "If you wish to run for office, just type in the command " + "'enter' and you will be added to the list. A list of candidates " + "is posted on the wall."; + else return "This is the voting chamber of the Hall of Rogues. " + "Rogues will gather here for the next election: "+VOTING_D->query_vote_date()+"."; +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/roots.c b/lib/domains/Praxis/roots.c new file mode 100644 index 0000000..aecfdf2 --- /dev/null +++ b/lib/domains/Praxis/roots.c @@ -0,0 +1,50 @@ +inherit "/lib/std/room"; + +void create() { + object pedestal, box; + object for_test_only; + + ::create(); + SetShort("among the roots of the tree"); + SetLong( + "Here, among the huge, stalactite-like roots of the fabled mages' tree, a "+ + "large room has been excavated. All moisture is magically funneled to the "+ + "roots, so the air here is very dry. Apart from the tree itself (and the "+ + "occasional mage), no life dares intrude upon the silence of this place. "+ + "In the center of this room, a small pedestral juts up from the ground, while, "+ + "Close to the north wall, a donations box reminds you of your financial "+ + "responsibility to your class. A small stairway to the east leads up into "+ + "the heart of the mage tree. "); + SetProperties( (["light" : 2, + "indoors" : 1 , + "no castle" : 1]) ); + SetItems( ([ + "room" : (: this_object(), "print_long" :), + "tree" : "You are among the roots of the tree.", + "north wall" : "Near the north wall of the tree there's a donation box", + "wall" : "Near the north wall of the tree there's a donation box", + "roots" : "These enormous roots supply nourishment for the immense mage "+ + "tree. According to legend, the roots reach the very core of "+ + "the world, effectively making the mage tree as permanent as "+ + "the Earth. ", + "stairway" : "The stairway has been carved out of the roots. It seems "+ + "unsturdy, but as soon as you step on it you are reassured, "+ + "for the stairway partakes of the infinite stability of the "+ + "tree itself. "]) ); + SetExits( (["up" : "/domains/Praxis/mage_hall"]) ); + //box = new("/realms/nialson/mages/donation"); + //box->move(this_object()); + pedestal = new("/domains/Praxis/obj/misc/pedestal"); + pedestal->move(this_object()); +#if 0 + for_test_only = new("/domains/Praxis/obj/magic/ball"); + for_test_only->move(this_object()); +#endif +} + +void print_long() { + write (this_object()->GetLong()); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/s_centre1.c b/lib/domains/Praxis/s_centre1.c new file mode 100644 index 0000000..232d5c5 --- /dev/null +++ b/lib/domains/Praxis/s_centre1.c @@ -0,0 +1,35 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetListen("default", "Raucus noise is coming from " + "inside the pub west."); + SetShort( "Centre Path outside Lars' Pub"); + SetLong( + "Centre Path leads through the heart of the business district " + "of Praxis, and down towards the famous Port of Praxis. " + "Rowdy customers can be seen heading west towards Lar's Pub. " + "The building is very old and worn. The abuse of many drunken " + "adventurer's has began to take its toll on the establishment. " + ); + SetExits( + (["north" : "/domains/Praxis/square", + "south" : "/domains/Praxis/s_centre2", + "west" : "/domains/Praxis/pub"]) ); + SetProperty("light", 3); + SetProperty("night light", 1); + SetItems( + (["path" : "Centre Path leads to Monument Square south and out " + "of town north.", + "road" : "Boc La Road is the main east-west road.", + "pub" : "Lars Pub, now mostly obsolete, but it is the original.", + "square" : "The central square of Praxis."]) ); + SetSkyDomain("town"); + SetProperty("no castle", 1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/s_centre2.c b/lib/domains/Praxis/s_centre2.c new file mode 100644 index 0000000..8c235d9 --- /dev/null +++ b/lib/domains/Praxis/s_centre2.c @@ -0,0 +1,29 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 3); + SetProperty("night light", 2); + SetProperty("no castle", 1); + SetShort( "Centre Path just south of Krasna Square"); + SetLong( + "A small alley crosses Centre Path here just south of Krasna Square. " + "As it winds on south, Centre Path travels through the business " + "center of South Praxis up to the Port of Praxis."); + SetExits( + (["north" : "/domains/Praxis/s_centre1", + "south" : "/domains/Praxis/s_centre3", + "east" : "/domains/Praxis/yard", + "west" : "/domains/Praxis/alley1"]) ); + SetItems( + ([({ "path", "road", "centre path" }) : "Centre Path leads to " + "Monument Square north and to the port south.", + "alley" : "It opens up to a yard of houses east, and a post " + "and bank west."]) ); + SetSkyDomain("town"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/s_centre3.c b/lib/domains/Praxis/s_centre3.c new file mode 100644 index 0000000..54dc7e5 --- /dev/null +++ b/lib/domains/Praxis/s_centre3.c @@ -0,0 +1,34 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 3); + SetProperty("night light", 1); + SetProperty("no castle", 1); + SetShort("Southern Praxis"); + SetDayLong( "Southern Praxis is the business district of this " + "small adventuring community. Through it runs Centre Path, " + "bringing people from the centre of town through here and " + "to the southwest the area really begins to rumble with " + "horse and foot traffic."); + SetNightLong( "The business district of Praxis nearly slumbers " + "save for a few nocturnal races of adventurer. Centre Path " + "winds down from the north out to the Port of Praxis southwest. " + " An unnamed road heads east."); + SetExits( + (["north" : "/domains/Praxis/s_centre2", + "southwest" : "/domains/Praxis/s_centre4", + "east" : "/domains/Praxis/unnamed1"]) ); + SetItems( + ([({"path", "centre path"}) : "The main road leading north and " + "south through Praxis.", + ({"port", "port of praxis"}) : "You cannot see that from here.", + ({"road", "unnamed road"}) : "It leads out of town."]) ); + SetSkyDomain("town"); + SetListen("road", "An eerie silence fills the air that way."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/s_centre4.c b/lib/domains/Praxis/s_centre4.c new file mode 100644 index 0000000..c757cc2 --- /dev/null +++ b/lib/domains/Praxis/s_centre4.c @@ -0,0 +1,47 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 3); + SetProperty("night light", 1); + SetProperty("no castle", 1); + SetShort( "Praxis Commercial District"); + // SetLong( "Centre Path leads south into the bustling Port of Praxis where it " "dead ends at Pier 1. Business life hurries all about you to get " "things done before the end of the short Praxis day. In the realty " ( high mortals make transactions for real estate with " "the mighty Atmos. In the great Hall of Fighters northwest fighters " "gather both night and day. Praxis centre is northeast from here." ); + SetLong("Centre Path leads south into the bustling Port of Praxis where it " + "dead ends at Pier 1. Business life hurries all about you to get " + "things done before the end of teh short Praxis day. In the realty " + "high mortals make transactions for real estate with " + "the mighty Atmos. In the great Hall of Fighters northwest fighters " + "gather both night and day. Praxis centre is northeast from here."); + //set_night long", "Even in the heart of night people are moving about the business " "district trying to conduct monetary affairs with those types who " "shy away from daylight. The shadiest of characters arrive in Praxis " "at Pier 1 of the Port of Praxis south under cloak of night. Fighters " ( especially the nocturnal ones gather in the Hall of " "Fighters northwest. Praxis centre is northeast."); + + SetItems( + ([({"path", "centre path"}) : "It is the main road winding " + "north and south through Praxis.", + ({"pier", "port", "port of praxis"}) : "Everything that " + "comes into Praxis from overseas comes through here.", + ({"hall", "hall of fighters"}) : "The fighters of this " + "reality often come from all over to gather there.", + "realty" : "High mortals by stuff to build castles with there.", + "fighters" : "They are roaming aimlessly about the Hall of " + "Fighters.", + "people" : "They are going about their business in the area.", + "high mortals" : "The mightiest of mortals who often " + "comprise class leaders."]) ); + SetExits( ([ + "south" : "/domains/Praxis/pier1", + "northwest" : "/domains/Praxis/fighter_join", + "northeast" : "/domains/Praxis/s_centre3", + ]) ); + SetListen("default", "You hear many people going about their " + "business."); + SetListen("fighters", "They are being really loud and rude."); + SetSmell("money", "Damn, you sure are greedy."); + SetSmell("fish", "You smell that they have been lying all over " + "the pier south."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/sage_room.c b/lib/domains/Praxis/sage_room.c new file mode 100644 index 0000000..c8b9759 --- /dev/null +++ b/lib/domains/Praxis/sage_room.c @@ -0,0 +1,283 @@ +// /d/standard/sage_room +// by Valodin +// This is where you can learn new languages and fix old ones + +#include <lib.h> +#include <daemons.h> +#include <clock.h> + +// This is how many experience points == one second +#define SEC_TO_EXP 3 + +inherit "/lib/std/room"; + +#define OLD_LANGUAGES ({ "elvish", "giantish", "orcish", "artrellian", "mischief", "sensuous", "hobbitish", "pseudo-speak", "gnomish" }) + +mapping queue; + +void create() { + ::create(); + queue = ([]); + SetProperty("light", 3); + SetProperty("indoors", 1); + SetProperty("no steal", 1); + SetProperty("no attack", 1); + SetProperty("no magic", 1); + SetShort( "Sage room"); + SetLong( "The walls of this smoke-filled room are covered with trappings " + "from far off lands. In the center of a huge smoke cloud sits a small " + "white-haired man. He looks like he is very wise. There are books on " + "how to speak different languages."); + SetItems( + ([({"sage", "man", "old man"}) : "The sage is a tiny little " + "wrinkled man. But he looks very wise.", + ({"walls", "trappings"}) : "The walls are covered in strange " + "writings in many languages, but you can hardly see them " + "through all the smoke from the sage's pipe.", + "pipe" : "The sage puffs away on this small water pipe. " + "The wisps of smoke remind you of the man's beard.", + ({"book", "books"}) : "As you flip through the books you " + "decide that you should study a new language."]) ); + AddExit("south", "/domains/Praxis/w_boc_la2", (: "leave_the_room" :) ); +} + +void init() { + ::init(); + add_action("ask_sage", "ask"); + add_action("study_lang", "study"); +} + +int remove_old_lang(object ob) { + string *langs; + int i, szl; + + if(!function_exists("query_all_languages", ob)) + return 0; + langs = ob->query_all_languages(); + for(i = 0, szl = sizeof(langs); i < szl; i++) + if(member_array(langs[i], OLD_LANGUAGES) != -1) + ob->remove_language(langs[i]); + return 1; +} + +int fix_languages() { + write("The sage peers at you intently."); + if(!remove_old_lang(this_player())) + { + write("The sage says: You need new flesh before I can help your mind."); + return 1; + } + //LANG_D->init_languages(this_player()); + write("The sage says: You have been healed, my " + + ((this_player()->query_gender() == "male") ? "son" : + "daughter") + "."); + return 1; +} + +int ask_sage(string str) +{ + string trash; + + notify_fail("Ask who, what?\n"); + if(!str) + return 0; + if(sscanf(str, "sage%s", trash, trash) == 1) + notify_fail("What do you want to ask the sage?\n"); + if(sscanf(str, "sage%sfix%s", trash, trash) == 2) + { + return fix_languages(); + } + return 0; +} + +int able_to_study(int amount) +{ + int exp; + + exp = this_player()->query_exp(); + if((exp - amount) < + ADVANCE_D->get_exp(this_player()->query_level())) + return 0; + else + return 1; +} + +int coclean(mixed *element, object ob) +{ + if(element[0] != ob) + return 0; + else + return 1; +} + +void clean_call_outs(object ob) +{ + mixed *all_callouts; + int i, acsz; + + all_callouts = call_out_info(); + all_callouts = filter_array(all_callouts, "coclean", this_object(), + this_object()); + for(i = 0, acsz = sizeof(all_callouts); i < acsz; i++) + remove_call_out(all_callouts[i][1]); + for(i = 0, acsz = sizeof(all_callouts); i < acsz; i++) + if(all_callouts[i][3] != ob) + call_out(all_callouts[i][1], all_callouts[i][2], all_callouts[i][3]); +} + +int convert_time(string str) +{ + string *times; + int ret, i, j, tln; + + times = explode(str, " "); + ret = 0; + tln = sizeof(times) / 2; + for(i = 0; i < tln; i++) + { + j = to_int(times[2 * i]); + switch(times[2 * i + 1]) + { + case "seconds": + case "second": + j = j * SECOND; + break; + case "minutes": + case "minute": + j = j * MINUTE; + break; + case "hours": + case "hour": + j = j * HOUR; + break; + case "days": + case "day": + j = j * DAY; + break; + case "week": + case "weeks": + j = j * WEEK; + break; + case "month": + case "months": + j = j * MONTH; + break; + case "year": + case "years": + j = j * YEAR; + break; + default: + return 0; + } + ret += j; + } + return ret; +} + +int study_lang(string str) +{ + string lang, timestr; + int nmtimespan; + + if(!str) + { + write("Study which language for how long?"); + return 1; + } + + if(queue[this_player()]) + { + write("The sage says: I cannot teach you two languages at once, my " + + ((this_player()->query_gender() == "male") ? "son." : + "daughter.")); + return 1; + } + + if(!function_exists("learn_language", this_player())) + { + write("The sage says: I am sorry, my " + + ((this_player()->query_gender() == "male") ? "son" : + "daughter") + ", but I cannot teach you in your current body."); + return 1; + } + if((sscanf(str, "%s for %s", lang, timestr) != 2) || (lang == "") || + (timestr == "") || !(nmtimespan = convert_time(timestr))) + { + write("Study which language for how long?"); + return 1; + } + + lang = lower_case(lang); + + if(nmtimespan <= 0) + { + write("The sage shakes his head at you in disgust."); + return 1; + } + if(nmtimespan > DAY) + { + write("You decide that you will get hungry and bored long before then."); + return 1; + } + + if(!able_to_study(SEC_TO_EXP * nmtimespan)) + { + write("The sage says: I am sorry, my " + + ((this_player()->query_gender() == "male") ? "son" : + "daughter") + ", but you are not experienced enough to study " + "for that long."); + return 1; + } + + write("You begin studying " + capitalize(lang) + ". You must stay here and" + " study until your time has ended in order to learn the langauge."); + queue[this_player()] = ({ lang, (SEC_TO_EXP * nmtimespan) }); + call_out("advance_em", nmtimespan, this_player()); + + //if(member_array(lang, (LANG_D->all_languages())) == -1) + //{ + // write("The sage says: " + capitalize(lang) + " is an uncommon language. " + // "If you did not mean to study it, then you should leave now, my " + + // ((this_player()->query_gender() == "male") ? "son." : + // "daughter.")); + // return 1; + //} + return 1; +} + +int leave_the_room() +{ + if(queue[this_player()]) + { + write("You decide to quit studying and go do other things."); + map_delete(queue, this_player()); + clean_call_outs(this_player()); + } + return 1; +} + +void advance_em(mixed arg) +{ + object ob; + string lang; + int exp; + + ob = (object)arg; + if(!ob || (environment(ob) != this_object())) + { + if(ob) + if(queue[ob]) + map_delete(queue,ob); + return; + } + + if(!queue[ob]) + return; + + lang = queue[ob][0]; + exp = queue[ob][1]; + ob->add_exp(-exp); + ob->learn_language(lang, exp); + write("You are done studying " + capitalize(lang) + "."); + map_delete(queue, ob); +} diff --git a/lib/domains/Praxis/setter.c b/lib/domains/Praxis/setter.c new file mode 100644 index 0000000..335e33b --- /dev/null +++ b/lib/domains/Praxis/setter.c @@ -0,0 +1,120 @@ +// /d/standard/setter.c +// Starting room for new characters choosing races +// from the Nightmare Mudlib +// created by Shadowwolf@Nightmare july 1992 +// modified by Descartes of Borg for the race daemon 10 june 1993 + +#include <lib.h> +#include ROOMS_H +#include <daemons.h> + +inherit LIB_ROOM; + +void do_rolls(); + +void create() { + ::create(); + SetProperty("light", 2); + SetProperty("indoors", 1); + SetLong( + "You are in a small box of both infinite and no dimensions. " + "Reality is black and without material. You are being created. " + "You intuit a list of possible races you might become, and even " + "read it. Once you pick your race, you can begin your journey " + "through the reality of Nightmare! Type <read list> to see " + "the list of races."); + SetItems( + (["room" : "The nothingness from which you will be born " + "into Nightmare.", + "list" : "A list of races that exist in the world of Nightmare."]) ); +} + +void init() { + ::init(); + add_action("read", "read"); + add_action("pick","pick"); + if (this_player()->query_exp() != 0) { + write("\nWelcome to Nightmare!\n" + "Please choose a race for yourself. Your race determines your main " + "genetic attributes, strength, intelligence, dexterity, constitution, " + "and charisma."); + this_player()->set_rolls(0); + } +} +int pick(string str) { + string *which; + mapping borg; + int tmp, i; + string Class; + + Class = "child"; + if(!str) { + write("To pick a race, type \"pick whatever\", where whatever is the race."); + return 1; + } + str = lower_case(str); + if(str == "satyr" && + this_player()->query_gender() != "male") { + write("You must be a male to be a satyr!\nPick again."); + return 1; + } + else if(str == "nymph" && this_player()->query_gender() + != "female") { + write("You must be a female to be a nymph!\nPick again."); + return 1; + } + if(member_array(str, RACES_D->query_races()) == -1) { + write("You must pick a race from the list!\nType <read list>\n"); + return 1; + } + this_player()->SetRace(str); + this_player()->new_body(); + this_player()->SetClass(Class); + if( this_player()->query_gender() == "male") this_player()->setenv("TITLE", "Newbie $N the boy"); + else this_player()->setenv("TITLE", "Newbie $N the girl"); + this_player()->init_skills(Class); + write("You can roll your stats up to three times."); + write("You do this in the hall of the class you will soon choose."); + do_rolls(); + write("You are now transfered to the village square."); + this_player()->eventMoveLiving(ROOM_START); + return 1; +} + +void do_rolls() { + string *which; + mapping borg; + int i, tmp; + + if(this_player()->query_rolls() >3) { + write("You can roll your stats no more."); + return; + } + write("You roll your stats."); + for(i=0, tmp=sizeof(which=keys(borg=RACES_D->do_rolls(this_player()->query_race()))); i<tmp; i++) + this_player()->SetStat(which[i], borg[which[i]]); + this_player()->set_rolls(this_player()->query_rolls()+1); + return; +} + +int read(string str) { + string *res; + int i, j, tmp; + if(!str) { + notify_fail("What do you want to read? A list?\n"); + return 0; + } + if(str != "list") { + notify_fail("That is not here to be read.\n"); + return 0; + } + write("These are the following races available in our reality:"); + write("-----------------------------------------------------------"); + message("Ninfo", format_page(RACES_D->query_races(), 4), + this_player()); + write("----------------------------------------------------------"); + write("Only males may be satyrs, and only females may be nymphs."); + write("pick <race> will forever make you one of these races"); + write("Type <help races> for more information."); + return 1; +} diff --git a/lib/domains/Praxis/sewer.c b/lib/domains/Praxis/sewer.c new file mode 100644 index 0000000..6ec43fb --- /dev/null +++ b/lib/domains/Praxis/sewer.c @@ -0,0 +1,24 @@ + +inherit "/lib/std/room"; + +void create() { + ::create(); + SetProperty("light", -1); + SetProperty("indoors", 1); + SetShort( "A disgusting sewer"); + SetLong( + "These sewers under Praxis are filled with slime. " + ); + SetItems( + (["sewers" : "The disgusting tunnels of human waste under Praxis.", + "slime" : "Nasty, nasty.", + ({"wall", "east wall"}) : "A disgusting slime-coated wall.", + "ceiling" : "A disgusting slime-coated ceiling.", + ])); + SetExits( + (["west" : "/domains/Praxis/sewer_ent", + ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/sewer_ent.c b/lib/domains/Praxis/sewer_ent.c new file mode 100644 index 0000000..e6f57a0 --- /dev/null +++ b/lib/domains/Praxis/sewer_ent.c @@ -0,0 +1,31 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetShort( "The Praxis sewers"); + SetLong( + "You are underneath the town of Praxis inside their " + "small sewer system. There is a manhole to the surface above " + "you."); + SetSmell("default", "The sewers stink of humanoid waste."); + SetDoor("/domains/Praxis/yard","up"); + SetProperty("light", 0); + SetProperty("indoors", 1); + SetItems( + ([ "manhole" : "It is a hole that leads to the surface."]) ); + SetExits( ([ + "up" : "/domains/Praxis/yard", + "east" : "/domains/Praxis/sewer", + ]) ); +} + +void reset() { + ::reset(); + if(!present("sword")) + new("/domains/Praxis/obj/weapon/sword")->move(this_object()); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/sheriff.c b/lib/domains/Praxis/sheriff.c new file mode 100644 index 0000000..7254e3f --- /dev/null +++ b/lib/domains/Praxis/sheriff.c @@ -0,0 +1,722 @@ +/* +// File : /domains/Praxis/sheriff.c +// Comment : handles law enforcement +// 94-08-15 : Descartes of Borg wrote original code +// 94-08-28 : Manny of Law executed it +// 94-09-02 : Pallando of Everywhere fixed it + */ +#include <lib.h> +#include <daemons.h> +#include <dirs.h> + +inherit LIB_ROOM; + +object *__Prisoners; +mapping Executions; + +object *clone_guards(int num); + +void create() { + object *obs; + int x,y, i, tot; + + Executions = ([ + "hanging" : "death_by_hanging", + "firing squad" : "death_by_firing_squad", + "torture" : "death_by_torture", + "the pit" : "death_by_the_pit", + // "stoning" : "death_by_stoning", + // "beheading" : "death_by_beheading", + ]); + room::create(); + SetNoClean(1); + SetProperties( ([ "light":2, "indoors":1, "no bump":1, "no kill":1, + "no steal":1 ]) ); + SetShort("praxis sheriff's office"); + SetLong( + "In the corner of this small, one room wooden building is " + "a barred off area indicating that you have entered the Praxis " + "sheriff's office. An old desk belonging to the sheriff occupies " + "the northeast corner of the room. Exits to court room and yard are " + "west and south respectively." + ); + SetItems( ([ "desk":"A rickety wooden desk hardly ever used, as the " + "sheriff never does seem to be able to sit for any period of time.", + ({ "building", "office", "room" }): "A wooden building constructed " + "long ago for a lawless era. There is a jail cell in one area.", + "area": "A jail cell.", + ({ "cell", "jail cell", "jail" }): (: "la_jail" :), + "exits": "Boc La Road and Centre Path."]) ); + SetSmell("default", "You can smell the residue of sweaty outlaws."); + SetExits( ([ "south":"/"+__DIR__+"yard", + "west":"/"+__DIR__+"court_room" ]) ); + x = POLITICS_D->query_personnel("police"); + y = POLITICS_D->query_spending("police"); + //if(!(tot = (y/x)/currency_rate("gold"))) return; + for(i=0, obs = allocate(x); i<x; i++) + obs[i] = new("/"+__DIR__+"obj/mon/police"); + obs->SetKeyName("deputy"); + obs->SetId( ({ "law officer", "praxis police", "police", "deputy", + "officer" }) ); + obs->SetShort("a Praxis deputy"); + obs->SetLong("A law officer charged with preserving the peace in " + "Praxis. If you are hunted by this officer, type \"surrender\" " + "to surrender yourself and go to jail."); + obs->SetRace("klingon"); + obs->SetRace("human"); + obs->SetGender(random(2) ? "male" : "female"); + obs->SetLevel(tot/1000+1); + obs->SetSkill("melee", (tot/1000)*7); + obs->SetSkill("attack", (tot/1000)*7); + obs->SetSkill("defense", (tot/1000)*7); + obs->SetSkill("stealth", (tot/1000)*5); + obs->SetStat("constitution", (tot/1000)*3 + 15); + obs->SetStat("dexterity", (tot/1000)*5 + 10); + obs->SetMorality(random(500)); + obs->move(this_object()); + __Prisoners = ({}); +} + +void init() { + room::init(); + add_action("cmd_quit", "quit"); +} + +static int cmd_quit(string str) { + message("system", "You cannot quit from the sheriff's office.", + this_player()); + return 1; +} + +void rescue_me(object victim, object outlaw) { + object *obs; + int x, i; + + if(!present("deputy")) return; + x = outlaw->query_level() - victim->query_level(); + if(x < 5) x = 1; + else x = x/5; + i = sizeof(obs = all_inventory(this_object())); + while(i-- && x) { + if(obs[i]->id("deputy")) { + obs[i]->set_target(outlaw); + x--; + } + } +} + +int release_objects(object ob) { + return (member_array(ob, __Prisoners) == -1); +} + +void add_prisoner(object ob) { __Prisoners += ({ ob }); } + +void remove_prisoner(object ob) { __Prisoners -= ({ ob }); } + +object *query_prisoners() { return __Prisoners; } + +string la_jail(string arg) { + string str; + int i; + + if(!sizeof(__Prisoners)) return "There are no prisoners right now."; + str = "The following prisoners are in the cell: "; + i = sizeof(__Prisoners); + while(i--) str += __Prisoners[i]->query_cap_name()+" "; + return str; +} + +object *clone_guards(int num) { + object *obs; + int y, x, i, tot; + + y = POLITICS_D->query_spending("police"); + x = POLITICS_D->query_personnel("police"); + for(i=0, obs = allocate(num); i<num; i++) + obs[i] = new("/"+__DIR__+"obj/mon/guard"); + tot = (y/x)/currency_rate("gold"); + tell_object(find_player("manny"), "tot = "+tot); + obs->SetKeyName("guard"); + obs->SetId( ({ "guard", "city guard", "officer", "praxis guard" }) ); + obs->SetShort("a Praxis guard"); + obs->SetRace("klingon"); + obs->SetRace("human"); + obs->SetGender(random(2) ? "male" : "female"); + obs->SetLevel(tot/1000+1); + obs->SetSkill("melee", (tot/1000)*7); + obs->SetSkill("attack", (tot/1000)*7); + obs->SetSkill("defense", (tot/1000)*7); + obs->SetSkill("stealth", (tot/1000)*5); + obs->SetStat("constitution", (tot/1000)*3 + 15); + obs->SetStat("dexterity", (tot/1000)*5 + 10); + obs->SetMorality(random(500)); + return obs; +} + +string death_by_hanging(object who) { + if(member_array(who, __Prisoners) == -1) + return who->query_cap_name()+" is not a prisoner."; + message("say", "%^RED%^You hear the rythmic pounding of " + "the city guard approaching the door. Two large, burly " + "men in blue step through the door and, without emotion, " + "bind you hands tightly together with thick rope.", + who); + shout("%^BOLD%^%^RED%^Distant bells ring thrice, " + "signaling the pending execution of "+who->query_cap_name()+ + "."); + call_out("hanging_part_two", 2, who); + return "The execution has begun."; +} + +void hanging_part_two(object who) { + message("say", "\n%^CYAN%^The guard whispers to you: " + "%^RESET%^Scumbag.", who); + call_out("hanging_part_three", 3, who); +} + +void hanging_part_three(object who) { + int x, y; + object *obs; + + message("say", "\n%^RED%^The two guards securely grasp your " + "arms and begin dragging you to the town square.", who); + (DIR_STANDARD_DOMAIN+"/square")->SetProperty("no bump", 1); + new("/"+__DIR__+"obj/misc/handcuffs")->move(who); + obs = clone_guards(2); + obs->set_target(who); + obs->move(DIR_STANDARD_DOMAIN+"/square"); + obs[0] = new("/"+__DIR__+"obj/misc/gallows"); + obs[0]->set_hangman(who); + obs[0]->move(DIR_STANDARD_DOMAIN+"/square"); + who->eventMoveLiving(DIR_STANDARD_DOMAIN+"/square"); + call_out("hanging_part_four", 4, who); +} + +void hanging_part_four(object who) { + message("say", "\n%^RED%^Meanancing jeers from the gathering " + "bloodthirsty crowd fill your ears as one of the guards " + "covers your head with a black hood. Burned into your " + "mind is the last image of life you shall ever see, an " + "image filled with faces of hate and disgust. You are " + "overcome with a sincere regret for your crimes, a burning " + "emotion extinguished by the realization that it is " + "too late.", who); + message("say", who->query_cap_name()+" is dragged up the stairs onto " + "the wooden platform. Menacing jeers fill the crowd as " + "one of the more burly guards places a large black hood over " + "the paniced face of "+who->query_cap_name()+". Any mercy " + "for "+who->query_possessive()+" soul is quickly replaced " + "by hatred and disgust for such a lowly individual.", + environment(who), who); + call_out("hanging_part_five", 3, who); +} + +void hanging_part_five(object who) { + message("say", "\n%^RED%^A tight grip upon your shaking " + "forarm leads you up a short set of stairs onto a wooden " + "platform. A heavy rope is placed around your neck, then " + "tightened. The rythmic beat of a nearby drum is all that " + "fills your conscience, as you do not dare fathom what awaits " + "you on the other side...", who); + message("say", "\nThe rythmic beat of the drum of death brings a " + "hush over the surrounding crowd.", environment(who), who); + call_out("hanging_part_six", 4, who); +} + +void hanging_part_six(object who) { + message("say", "\n%^RED%^The drum's beat falls into a steady " + "roll...", who); + message("say", "\nThe drum's beat falls into a steady " + "roll...", environment(who), who); + call_out("hanging_part_seven", random(3) + 2, who); +} + +void hanging_part_seven(object who) { + object here; + + here = environment(who); + message("say", "\n%^RED%^The klunk of the floor falling beneath " + "you is the final sound to reach your ears.", who); + message("say", "\nSuddenly without warning, the floor beneath "+ + who->query_cap_name()+"'s feet falls away, leaving "+ + who->query_cap_name()+" suspended only by the rope attached " + "to "+who->query_possessive()+" neck. "+ + who->query_cap_name()+" struggles for a moment, then falls " + "limp.", environment(who), who); + present("handcuffs", who)->destruct(); + who->die(); + call_out("hanging_part_eight", 3, here); +} + +void hanging_part_eight(object where) { + object stuff; + message("say", "The guards dispurse, removing the gallows and cleaning up " + "the area before leaving.", where); + if(stuff = present("guard", where)) stuff->destruct(); + if(stuff = present("guard", where)) stuff->destruct(); + if(stuff = present("gallows", where)) stuff->destruct(); + where->SetProperty("no bump", 0); +} + +string death_by_firing_squad(object who) { + object *obs; + if(member_array(who, __Prisoners) == -1) + return who->query_cap_name()+" is not a prisoner."; + message("say", "%^RED%^A large, burly guard enters, accompanied by " + "a priest in black robes mumbling a prose from a small book " + "he carries.", who); + obs=clone_guards(2); + obs[1]->SetKeyName("priest"); + obs[1]->SetShort("a priest"); + obs->move(environment(who)); + shout("%^RED%^Distant bells ring, signaling the execution " + "of "+who->query_cap_name()+" in the town square."); + call_out("squad_part_two", 2, who); + return "The execution has begun."; +} + +void squad_part_two(object who) { + object pole, *obs; + int x; + + message("say", "\n%^RED%^%^BOLD%^The guard tells you:%^RESET%^ Your " + "time has come.", who); + message("say", "\n%^RED%^Opening the cell, one of the guards ties " + "your hands behind your back with a thick rope. A guard then " + "places a tight grip upon your arm and drags you out of the " + "building and towards the town square.", who); + new("/"+__DIR__+"obj/misc/handcuffs")->move(who); + message("say", "A Praxis guard enters carrying a large bloodstained " + "pole. Walking to the far side of the square, he digs a small " + "hole and firmly plants the pole.", DIR_STANDARD_DOMAIN+"/square"); + (DIR_STANDARD_DOMAIN+"/square")->SetProperty("no bump", 1); + clone_guards(1)->move(DIR_STANDARD_DOMAIN+"/square"); + pole=new(LIB_ITEM); + pole->SetKeyName("pole"); + pole->SetId( ({ "pole", "bloodstained pole", "large pole" }) ); + pole->SetShort("a large, bloodstained pole"); + pole->SetLong("A large pole firmly planted in the ground. Blood " + "spots are scattered in various places near the top half of " + "the pole."); + pole->SetPreventGet("The pole is firmly planted in the ground."); + pole->move(DIR_STANDARD_DOMAIN+"/square"); + message("say", "A small set of guards enter and form a line opposite " + "of the pole.", DIR_STANDARD_DOMAIN+"/square"); + clone_guards(5)->move(DIR_STANDARD_DOMAIN+"/square"); + call_out("squad_part_three", 5, who); +} + +void squad_part_three(object who) { + object thing; + if(thing=present("guard", environment(who))) + thing->move(DIR_STANDARD_DOMAIN+"/square"); + else clone_guards(1)->move(DIR_STANDARD_DOMAIN+"/square"); + if(thing=present("priest", environment(who))) + thing->move(DIR_STANDARD_DOMAIN+"/square"); + else clone_guards(1)->move(DIR_STANDARD_DOMAIN+"/square"); + who->eventMoveLiving(DIR_STANDARD_DOMAIN+"/square"); + message("say", "\n%^RED%^In the once familar town square, a large " + "area has been cleared out, with one pole near a wall on the " + "far side of the square. This pole is in the direction you " + "and the ever stoic guard are headed.", who); + message("say", "\n%^RED%^The guard ties your hands securly behind the " + "rough blood-stained pole, facing a line of the town guards, " + "each wielding a large bow with a single arrow.", who); + message("say", "\n%^RED%^The guard pulls out a large black " + "hood which is placed over your head and steps away.", who); + new("/"+__DIR__+"obj/misc/hood")->move(who); + message("say", who->query_cap_name()+" is dragged towards a pole " + "on the far side of the square, where he is tied by one of " + "the guards. The guard places a large black hood over the " + "criminal's head and steps away.", environment(who), who); + message("say", "\nA nearby drum begins a steady, rythmic beat.", + environment(who)); + call_out("squad_part_four", 4, who); +} + +void squad_part_four(object who) { + message("say", "\n%^RED%^The drums' beat becomes a steady roll, and " + "you hear a guard shout a single, inaudiable word. You hear " + "the rustle of weapons being cocked.", who); + message("say", "\nA lead guard yells out a single inaudiable word " + "as the line of guards ready their weapons.", environment(who), + who); + call_out("squad_part_five", 4, who); +} + +void squad_part_five(object who) { + message("say", "\n%^RED%^A guard yells a second word as the firing " + "squad prepare the arrows for launching.", who); + message("say", "\nThe lead guard yells a second word as the firing " + "line pull back their arrows in preparation.", environment(who), + who); + call_out("squad_part_six", 4, who); +} + +void squad_part_six(object who) { + int x, dam; + + message("say", "\n%^RED%^The guard yells a thrid and final word, and " + "dozens of arrows peirce your entire body. The darkness surrounding " + "you becomes even darker, and vague voices begin to cackle evily " + "within you mind..", who); + message("say", "\nThe guard yells out a third and final word, and " + "the entire squad releases their arrows into the helpless body " + "of "+who->query_cap_name()+". The body instantly falls limp.", + environment(who), who); + dam= (who->query_max_hp())/5; + present("hood", who)->destruct(); + present("handcuffs", who)->destruct(); + for(x=0; x<6; ++x) + who->do_damage("torso", dam + 10); + call_out("squad_part_seven", 4, environment(who)); + who->die(); +} + +void squad_part_seven(object place) { + object thing; + message("say", "The guards begin marching away, one removing the pole " + "on his way out. He leaves the dead body on the " + "ground to rot away, just as it deserves.", + DIR_STANDARD_DOMAIN+"/square"); + place->SetProperty("no bump", 0); + while(thing = present("guard", place)) + thing->destruct(); + if(thing=present("pole", place)) thing->destruct(); +} + +string death_by_torture(object who) { + if(member_array(who, __Prisoners) == -1) + return who->query_cap_name()+" is not a prisoner."; + message("say", "%^RED%^A large guard enters your cell and ties " + "your hands with a large rope. Saying nothing, he drags you " + "out of the room.", who); + new("/"+__DIR__+"obj/misc/handcuffs")->move(who); + call_out("torture_part_two", 3, who); + return "The execution has begun."; +} + +void torture_part_two(object who) { + who->eventMoveLiving("/"+__DIR__+"torture_room"); + message("say", "%^RED%^The guard brings you into a room of which " + "the likes you have only heard about. Your heart sinks at the " + "thought of parting with life in such a cruel way.", who); + message("say", "\n%^RED%^The guard forces you to lie down on a " + "small table in the middle of the room. Heavy straps are " + "placed over your legs, arms and forehead, making all " + "movement impossible. When you look up you finally see the " + "object of your death: a large, clean blade at the end of " + "a long pole.", who); + call_out("torture_part_three", 4, who); +} + +void torture_part_three(object who) { + message("say", "\n%^RED%^%^BOLD%^The guard tells you: %^RESET%^Now " + "just sit tight and it will all be over in a few hours.", who); + message("say", "\nThe guard grins evilly.", who); + message("say", "\n%^RED%^The guard reaches up and grabs the blade, " + "swinging it like a pendulium.", who); + call_out("torture_part_four", 4, who); +} + +void torture_part_four(object who) { + message("say", "\nThe guard ponders for a moment.", who); + call_out("torture_part_five", 4, who); +} + +void torture_part_five(object who) { + message("say", "\n%^RED%^%^BOLD%^The guard tells you:%^RESET%^ Ya' " + "know, I respect yer kind. Nun too many pe'ple gots the balls " + "ta do wha' ya did.", who); + message("say", "\n%^RED%^%^BOLD%^The guard tells you:%^RESET%^ I's " + "gonna show ya a lit'le bit o' mercy, make it quiker fer ya.", who); + message("say", "\n%^RED%^The guard grabs the pole above the " + "bladed pendulium and pulls down upon it, bringing the blade " + "closer to your neck. He gives it a hardy shove, and it begins " + "it's steady swing again.", who); + call_out("torture_part_six", 3, who); +} +void torture_part_six(object who) { + message("say", "\n%^RED%^After a moment of careful examination, the " + "guard gives a satisfied smirk.", who); + message("say", "\n%^BOLD%^%^RED%^The guard tells you: %^RESET%^Have " + "a happy afterlife.", who); + message("say", "\n%^RED%^The guard grins evilly and stalks out of " + "the room, locking the door behind him.", who); + call_out("torture_part_seven", 6, ({ who, 1 }) ); +} + +void torture_part_seven(mixed *stuff) { + object who; + who = stuff[0]; + switch(random(7)) { + case 0: + case 1: + case 2: tell_object(who, "\n%^RED%^You notice the swinging blade seems " + "to be getting closer"); break; + case 3: tell_object(who, "\n%^RED%^You feel a very strong urge to " + "use the restroom."); break; + case 4: tell_object(who, "\n%^RED%^Shivers run through your body."); + break; + case 5: tell_object(who, "\n%^RED%^A small rat scurries across the " + "floor"); + case 6: tell_object(who, "\n%^RED%^With closer examination, the blade " + "swinging just above your neck seems remarkably clean. " + "You can't help but to wonder if you're the first life " + "to be claimed by this horrific device."); + } + if(++stuff[1] == 10) + call_out("torture_part_eight", 5, who); + else call_out("torture_part_seven", 6, stuff); +} + +void torture_part_eight(object who) { + message("say", "\n%^RED%^The blade swings dangerously close to your " + "neck. By your best estimate, you have a single breath left...", + who); + call_out("torture_part_nine", 3, who); +} + +void torture_part_nine(object who) { + message("say", "\n%^RED%^In one final swoop, the huge metal blade " + "places a clean cut into your throat. Your struggle for more " + "air only fills your mouth and lungs with your life blood.", who); + message("say", "\n%^BOLD%^%^BLACK%^The ever-persistant darkness " + "finally covers your eyes. Distant, evil voices cackle with " + "glee at thier newest victim...", who); + present("handcuffs", who)->destruct(); + who->die(); +} + +string death_by_the_pit(object who) { + if(member_array(who, __Prisoners) == -1) + return who->query_cap_name()+" is not a prisoner."; + message("say", "%^RED%^A large, burly guard enters the cell and " + "securly ties your hands with a peice of rope.", who); + message("say", "\n%^RED%^%^BOLD%^The guard tells you:%^RESET%^ It's " + "to the pit with your sorry self. Hehehe.", who); + message("say", "\n%^RED%^The guard drags you out of the building " + "towards the dreaded pit...", who); + shout("%^RED%^Distant bells signal the pending death " + "of "+who->query_cap_name()+" in the dreaded Pit of Spiders."); + new("/"+__DIR__+"obj/misc/handcuffs")->move(who); + call_out("pit_part_two", 5, who); + return "The execution has begun."; +} + + +void pit_part_two(object who) { + string orig_long; + + message("say", "Two guards enter and clear off an area " + "revealing a large stone covering. The guards lift the heavy " + "plate, opening a deep, black hole on the northeastern side of " + "the square.", DIR_STANDARD_DOMAIN+"/square"); + (DIR_STANDARD_DOMAIN+"/square")->SetProperty("no bump", 1); + orig_long = (DIR_STANDARD_DOMAIN+"/square")->GetLong(); + (DIR_STANDARD_DOMAIN+"/square")->AddExit("down", + DIR_STANDARD_DOMAIN+"/spider_pit", (: "prevent_down" :) ); + (DIR_STANDARD_DOMAIN+"/square")->SetLong( + orig_long+"\n\nA large, deep pit has been uncovered in " + "the middle of the square."); + clone_guards(2)->move(DIR_STANDARD_DOMAIN+"/square"); + call_out("pit_part_three", 3, ({ who, orig_long })); +} + +void pit_part_three(mixed *stuff) { + stuff[0]->eventMoveLiving(DIR_STANDARD_DOMAIN+"/square"); + message("say", "\n%^RED%^Upon the arrival of the all too familar " + "town square, two guards have already removed the cover from " + "the pit. Deep in the dark hole, the erie floor seems to " + "be crawling...", stuff[0]); + message("say", "\n"+stuff[0]->query_cap_name()+" enters, dragged by the " + "town guards.", environment(stuff[0]), stuff[0]); + call_out("pit_part_four", 4, stuff); +} + +void pit_part_four(mixed *stuff) { + object here; + + message("say", "\n%^RED%^%^BOLD%^A guard tells you:%^RESET%^ Say " + "hi to the Leaper for me!", stuff[0]); + message("say", "\n%^RED%^The guard cackles evilly as he shoves you " + "into the pit.", stuff[0]); + message("say", "\nThe guard cackles evilly as he shoves "+ + stuff[0]->query_cap_name()+" into the pit", environment(stuff[0]), + stuff[0]); + here=environment(stuff[0]); + stuff[0]->eventMoveLiving("/"+__DIR__+"spider_pit", + "falls screaming into the pit!!"); + (DIR_STANDARD_DOMAIN+"/square")->SetProperty("no bump", 0); + message("say", "\nThe guard pulls the protective covering over the " + "hole. Muffled screams of pain echo from within as you realize " + "the criminal's chances of a peacful death are zero.", + DIR_STANDARD_DOMAIN+"/square"); + call_out("pit_part_five", 10, ({ here, stuff[1] })); +} + +void pit_part_five(mixed *stuff) { + object thing; + + message("say", "The guards, satisfied that this world is a better " + "place, replace the cover upon the pit of spiders and" + "walk off.", stuff[0]); + stuff[0]->RemoveExit("down"); + stuff[0]->SetLong(stuff[1]); + if(thing = present("guard", stuff[0])) thing->destruct(); + if(thing = present("guard", stuff[0])) thing->destruct(); +} + +int prevent_down() { + message("say", "A guard blocks your way, making it clear that " + "you really don't want to go down there.", this_player()); + return 0; +} + +string death_by_stoning(object who) { + if(member_array(who, __Prisoners) == -1) + return who->query_cap_name()+" is not a prisoner."; + message("say", "%^RED%^A guard enters and ties your hands together " + "with a thick rope.", who); + message("say", "\n%^BOLD%^%^RED%^A guard tells you:%^RESET%^ Right " + "this way, you scumbag.", who); + message("say", "\n%^RED%^The guard grabs you by the arm and drags you " + "towards the town square.", who); + // shout("%^RED%^Distant bells sound, signaling the execution " + // "of "+who->query_cap_name()+" by stoning in the town square."); + call_out("stoning_part_two", 5, who); +} + +void stoning_part_two(object who) { + object *townsfolk, *homes; + string *wanted; + int x, y; + + wanted = ({ "horace", "lars", "beggar", "knight", "waitress" }); + townsfolk=({ }); + homes = ({ }); + for(x=0, y=0; y<sizeof(wanted); y++) + if(find_living(wanted[y])) { + homes[x]=environment(townsfolk[x]); + message("say", townsfolk[x]->query_cap_name()+" cheers in excitment " + "for the upcomming execution!", environment(townsfolk[x])); + x++; + } + townsfolk->eventMoveLiving(DIR_STANDARD_DOMAIN+"/square", "to join in the " + "stoning of "+who->query_cap_name()); + call_out("control_townsfolk", 1, ({ who, townsfolk, homes })); + (DIR_STANDARD_DOMAIN+"/square")->SetProperty("no bump", 1); + new("/"+__DIR__+"obj/misc/stones")->move(DIR_STANDARD_DOMAIN+"/square"); + who->eventMoveLiving(DIR_STANDARD_DOMAIN+"/square"); + message("say", "\n%^RED%^Upon arrival to the town square, the guard " + "ties you to a wooden post, facing the jeering crowd. With a " + "grim smirk upon his face, he wishes you a good afterlife and " + "leaves you to die at the hands of the countless victims of " + "your crimes.", who); + message("say", "Upon arrival to the town square, the guard ties "+ + who->query_cap_name()+" to the post, smirks, and leaves. " + "Immedately the towns people pick up their rocks and expend " + "thier frustration upon the criminal who caused them so much " + "grief.", environment(who), who); +} + +void control_townsfolk(mixed *them) { + int x; + + for(x=0; x<sizeof(them[1]); x++) + switch(random(5)) { + case 0 : message("saY", them[1][x]->query_cap_name()+" cheers " + "enthustically!", environment(them[1][x])); break; + case 1 : message("say", them[1][x]->query_cap_name()+"yells: " + "Scumbag!!", environment(them[1][x])); break; + case 2 : message("say", them[1][x]->query_cap_name()+" spits on " + + them[0]->query_cap_name()+"!", environment(them[1][x])); + break; + case 3 : message("say", them[1][x]->query_cap_name()+"boos " + "and hisses.", environment(them[1][x])); break; + case 4 : them[1][x]->command("get stone"); + them[1][x]->command("throw stone at "+them[0]->query_name()); + break; + } + if(them[0]->query_ghost()) { + them[1]->command("cheer"); + call_out("stoning_part_three", 3, ({ them[1], them[2] }) ); + } else call_out("control_townsfolk", 1, them); +} + +void stoning_part_three(mixed *townsfolk) { + int x; + message("say", "The townsfolk head back to their respective " + "homes.", environment(townsfolk[0][0])); + present("stone pile", environment(townsfolk[0][0]))->destruct(); + for(x=0; x < sizeof(townsfolk[0]); x++) + townsfolk[0][x]->eventMoveLiving(townsfolk[1][x]); +} + +string death_by_beheading(object who) { + if(member_array(who, __Prisoners) == -1) + return who->query_cap_name()+" is not a prisoner."; + message("say", "%^RED%^A large, burly guard enters your cell and securly " + "ties your hands with a thick rope. He grabs your arm and pulls " + "you towards the exit of the prison, in the direction of the town " + "square.", who); + shout("%^RED%^Distant bells ring thrice, signaling the " + "public beheading of "+who->query_cap_name()+" at the town " + "square"); + new("/"+__DIR__+"obj/misc/handcuffs")->move(who); + call_out("beheading_part_two", 2, who); + return "The execution has begun"; +} + +void beheading_part_two(object who) { + (DIR_STANDARD_DOMAIN+"/square")->SetProperty("no bump", 1); + clone_guards(4)->move(DIR_STANDARD_DOMAIN+"/square"); + message("say", "A group of guards enter, bringing with them a large " + "platform with a thick round wooden stump covered with dried " + "blood.", DIR_STANDARD_DOMAIN+"/square"); + who->eventMoveLiving(DIR_STANDARD_DOMAIN+"/square"); + message("say", "\n%^RED%^Upon arrival to the town square, you notice " + "a large platform with a blood-stained wooden stump. Standing " + "atop the platform is a black-hooded man with a large axe. It " + "is upon this platform, next to the hooded man, where you are " + "lead by the guard and commanded to kneal.", who); + call_out("beheading_part_three", 3, who); +} + +void beheading_part_three(object who) { + message("say", "\n%^RED%^From atop the platform you see the gathering " + "crowd, very unfriendly. A rope is placed around your neck, and " + "you are forced to place your head over the stump, you neck " + "fearfully exposed to the man in the black hood. A nearby drum " + "begins it's steady death beat...", who); + message("say", "\nA guard places a rope around "+who->query_cap_name()+ + "'s neck and is forced to lie over the stump. There is a desparate " + "look on "+who->query_cap_name()+"'s face as a nearby drum begins " + "a steady beat...", environment(who), who); + call_out("beheading_part_four", 3, who); +} + +void beheading_part_four(object who) { + message("say", "\n%^RED%^Without warning, the drum beat comes to a " + "sudden stop.", who); + message("say", "\nThe drum beat comes to a sudden end, and the black " + "hooded brings his axe down through "+who->query_cap_name()+"'s " + "neck without hesitation. "+who->query_cap_name()+"'s head drops " + "to the platform with a loud thunk, the expression of desparation " + "permanently affixed to "+who->query_possessive()+" face.", + environment(who), who); + (DIR_STANDARD_DOMAIN+"/square")->SetProperty("no bump", 0); + who->die(); +} + + +varargs mapping valid_execution( string type ) +{ + if( type ) return Executions[type]; + return Executions; +} + +string execute( object who, string type ) +{ + return call_other( this_object(), Executions[type], who ); +} diff --git a/lib/domains/Praxis/spider_pit.c b/lib/domains/Praxis/spider_pit.c new file mode 100644 index 0000000..4270792 --- /dev/null +++ b/lib/domains/Praxis/spider_pit.c @@ -0,0 +1,34 @@ +#include <lib.h> +#include <dirs.h> + +inherit LIB_ROOM; + +create() { + ::create(); + SetProperties( (["no magic" : 1, "light" : 0, "no teleport" : 1]) ); + SetShort("Pit of Spiders"); + SetLong("You find yourself in the dreaded pit of spiders. The ground " + "and walls surrounding you are completely smooth, except for the " + "crawling lumps of deadly spiders. By the looks of it, your worst fears " + "crawling lumps of deadly spiders. By the looks of it, your " + "worst fears have come true: there is no escape."); + SetItems( ([ "spiders" : "Greusome spiders, both dead and alive, " + "completely cover the ground and walls of the pit.", + ({ "wall", "walls", "floor" }) : "More spiders." ]) ); +} + +void reset() { + int x; + ::reset(); + if(!present("spider", this_object())) + for(x=0; x<10; x++) { + new("/domains/Praxis/obj/mon/spider")->move(this_object()); + } +} + +void init() { + ::init(); + if(this_player()->query_ghost()) { + this_player()->move(DIR_STANDARD_DOMAIN+"/square"); + } +} diff --git a/lib/domains/Praxis/square.c b/lib/domains/Praxis/square.c new file mode 100644 index 0000000..ab1d907 --- /dev/null +++ b/lib/domains/Praxis/square.c @@ -0,0 +1,80 @@ +#include <lib.h> + +inherit LIB_ROOM; + +string ReadSign(){ + this_player()->more("/domains/town/txt/praxis_sign.txt"); + return ""; +} + +void create() { + object borg; + + ::create(); + SetProperty("light", 3); + SetProperty("night light", 2); + SetProperty("no steal", 1); + SetProperty("no magic", 1); + SetProperty("no attack", 1); + SetProperty("no castle", 1); + SetListen("default", "The sounds of a busy adventuring town are all about."); + SetShort( "Monument Square"); + SetLong( "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." + "\n%^RED%^There is a sign here you can read.%^RESET%^"); + SetExits( + (["north" : "/domains/Praxis/n_centre1", + "south" : "/domains/Praxis/s_centre1", + "east" : "/domains/Praxis/e_boc_la1", + "west" : "/domains/Praxis/w_boc_la1"]) ); + + //new("/domains/Praxis/obj/misc/watchtower")->move(this_object()); + SetItems( + (["road" : "Boc La Road leads east toward the adventurer's " + "hall and the Praxis Monastary.", + "path" : "Centre Road leads south toward the bank and post office.", + "sign" : "A sign you can read.", + "square" : "Krasna Square is the central point of Praxis."]) ); + SetInventory(([ + "/domains/Praxis/obj/misc/stargate" : 1, + ])); + SetRead("sign", (: ReadSign :) ); + SetCoordinates("1000,-1000,0"); + SetSkyDomain("town"); +} + +int CanReceive(object ob) { + string start; + + if (previous_object()->is_player()) { + start = previous_object()->getenv("start"); + if (!start) return ::CanReceive(ob); + if (9>strlen(start)) return ::CanReceive(ob); + if ("/d/" == start[0..2]) + previous_object()->setenv("start", + "/domains/"+start[3..strlen(start)]); + if ("d/" == start[0..1]) + previous_object()->setenv("start", + "/domains/"+start[2..strlen(start)]); + if ("/wizards/" == start[0..8]) + previous_object()->setenv("start", + "/realms/"+start[9..strlen(start)]); + if ("wizards/" == start[0..7]) + previous_object()->setenv("start", + "/realms/"+start[8..strlen(start)]); + + if("/domains/standard/" ==start[0..17]) + previous_object()->set_primary_start("/domains/Praxis/"+ + start[18..strlen(start)]); + if("domains/standard/"==start[0..16]) + previous_object()->set_primary_start("/domains/Praxis/"+ + start[17..strlen(start)]); + } + return ::CanReceive(ob); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/stairs.c b/lib/domains/Praxis/stairs.c new file mode 100644 index 0000000..6d4ccc3 --- /dev/null +++ b/lib/domains/Praxis/stairs.c @@ -0,0 +1,25 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 1); + SetProperty("indoors", 1); + SetProperty("no castle", 1); + SetShort( "Monastary stairwell"); + SetLong( + "A spiraling flight of stairs leads up to the monastery " + "attic and down to the cellar. The prayer area is west."); + SetExits( + (["west" : "/domains/Praxis/monastery", + "up" : "/domains/Praxis/monk_join", + "down" : "/domains/Praxis/immortal_hall"]) ); + SetItems( + (["stairs" : "They spiral up and down in this old monastery."]) ); + SetProperty("no castle", 1); +} +void init(){ + ::init(); +} + diff --git a/lib/domains/Praxis/storage.c b/lib/domains/Praxis/storage.c new file mode 100644 index 0000000..77a8e44 --- /dev/null +++ b/lib/domains/Praxis/storage.c @@ -0,0 +1,16 @@ +inherit "/lib/std/room"; + +void create() { + int i; + ::create(); + SetShort( "Adventurer's Supply Storage Room"); + SetLong( "Horace stores weapons and such here."); + SetExits( + (["south" : "/domains/Praxis/supply"]) ); + new("/domains/Praxis/obj/misc/vial")->move(this_object()); + //for( i=0 ; i<5 ; i++ ) + //new("/realms/nialson/newspaper/paper")->move(this_object()); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/sun1.c b/lib/domains/Praxis/sun1.c new file mode 100644 index 0000000..c54758a --- /dev/null +++ b/lib/domains/Praxis/sun1.c @@ -0,0 +1,32 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 4); + SetProperty("night light", 1); + SetProperty("no castle", 1); + SetShort( "Sun Alley near Centre Path"); + SetLong( + "Sun Alley is a bright path, named for the fact that the sun " + "always seems to be shining down upon it. The path is fairly " + "quiet, except for the occasional villager that is out strolling " + "or running their errands. The alley runs north of the village, " + "and interescts Centre Path west of here. To the south " + "you can see a small brown thatch house. " ); + SetItems( + (["alley" : "It is bright and cheerful, not like that alley on " + "the south end.", + "path" : "The main north-south road of Praxis.", + "intersection" : "Sun alley meets Centre Path there.", + "house" : "It's a small thatch house, nothing special."]) ); + SetSkyDomain("town"); + SetExits( + (["east" : "/domains/Praxis/sun2", + "west" : "/domains/Praxis/n_centre2", + "south" : "/domains/Praxis/house"]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/sun2.c b/lib/domains/Praxis/sun2.c new file mode 100644 index 0000000..c8b4232 --- /dev/null +++ b/lib/domains/Praxis/sun2.c @@ -0,0 +1,35 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 3); + SetProperty("night light", 1); + SetProperty("no castle", 1); + SetShort( "Sun Alley near East Road"); + SetLong( + "South of here, at the corner of this sunny alley is the Last " + "Dragon Restaurant. The building is a brownish grey wooden structure " + "with very little adornment on the outside. East Road interesects with " + "this alley over to the east. The beginnings of a forest indicate " + "the borders of Praxis here."); + SetItems( + (["foo" : "Whatever you say.", + "alley" : "This alley is the northernmost part of Praxis. " + "Only the great North Forest is north of here.", + "restaurant" : "A great place to rest up from adventuring.", + "road" : "East Road.", + "forest" : "The huge forest north of Praxis. The " + "walled town of Cartesia is out there somewhere.", + "border" : "The forest keeps Praxis from expanding any " + "further north."]) ); + SetSkyDomain("town"); + SetExits( + (["east" : "/domains/Praxis/east_road2", + "west" : "/domains/Praxis/sun1", + "south" : "/domains/Praxis/restaurant"]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/supply.c b/lib/domains/Praxis/supply.c new file mode 100644 index 0000000..b237364 --- /dev/null +++ b/lib/domains/Praxis/supply.c @@ -0,0 +1,57 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void init() { + ::init(); + add_action("go_north", "go"); +} + +void create() { + ::create(); + SetProperties( ([ "light" : 2, "indoors" : 1, "no castle" : 1 ]) ); + SetShort("Horace's general supply shop"); + SetLong( + "Welcome to Horace's General Supply Shop!\n" + "Horace's supply shop is the largest business running in Praxis " + "to date. It was established long ago, and has earned itself " + "a very high reputation over the years. A long counter stands " + "at the back of the store, where you can often see Horace himself " + "standing, bargaining with customers. Two windows frame the front " + "wall of the store, and a cheery red door exits you back out to " + "the main street. Horace buys and sells goods created for and found " + "by adventurer's when he is in. The pasasge north is guarded " + "by a magic field."); + SetItems( + (["shop" : "You can buy and sell things here.", + "passage" : "Horace keeps the things he has for sale back there.", + "road" : "Boc La Road."]) ); + SetInventory(([ + "/domains/Praxis/obj/mon/horace" : 1, + ])); + SetExits( + (["south" : "/domains/Praxis/e_boc_la2"]) ); + SetProperty("no castle", 1); +} + +void reset() { + ::reset(); + if(!present("horace")) + new("/domains/Praxis/obj/mon/horace")->move(this_object()); +} + +int go_north(string str) { + if(str !="north") return notify_fail("What?\n"); + if(!creatorp(this_player())) { + message("my_action", "The magic of Horace stops you.", this_player()); + message("other_action", this_player()->query_cap_name()+ + " is stopped by the magic of Horace.", this_object(), + ({ this_player() })); + return 1; + } + message("other_action", this_player()->query_cap_name()+ + " cannot be stopped by Horace's magic.", this_object(), + ({ this_player() })); + this_player()->eventMoveLiving("/domains/Praxis/storage", "north"); + return 1; +} diff --git a/lib/domains/Praxis/supply2.c b/lib/domains/Praxis/supply2.c new file mode 100644 index 0000000..d08671a --- /dev/null +++ b/lib/domains/Praxis/supply2.c @@ -0,0 +1,61 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperties( ([ "light" : 2, "indoors" : 1, "no castle" : 1 ]) ); + SetShort("Horace's General Supply Shop"); + SetLong( + "Welcome to Horace's General Supply Shop!\n" + "Horace buys and sells goods created for and found " + "by adventurer's when he is in. The store opens out " + "onto Boc La Road south. There is a passage to the " + "north guarded by a magic field."); + SetItems( + (["shop" : "You can buy and sell things here.", + "passage" : "Horace keeps the things he has for sale back there.", + "road" : "Boc La Road."]) ); + SetExits( ([ "south" : "/domains/Praxis/e_boc_la2", + "north" : "/domains/Praxis/storage" ]) ); + set_pre_exit_functions( ({ "north" }), ({ "go_north" }) ); + add_sky_event( (: "shop_closing" :) ); +} + +void reset() { + ::reset(); + if(query_night()) return; + if(!present("horace")) + new("/domains/Praxis/obj/mon/horace")->move(this_object()); +} + +string shop_long(string str) { + if(query_night()) + return "Horace's is now closed."; +} + +void shop_closing(string str) { + object ob; + + if(str == "night" && ob = present("horace", this_object())) + ob->destruct(); + else if(str == "dawn" && !present("horace", this_object())) + new("/domains/Praxis/obj/mon/horace")->move(this_object()); +} + +int go_north(string str) { + if(!creatorp(this_player())) { + message("my_action", "The magic of Horace stops you.", this_player()); + message("other_action", this_player()->query_cap_name()+ + " is stopped by the magic of Horace.", this_object(), + ({ this_player() })); + return 0; + } + message("other_action", this_player()->query_cap_name()+ + " cannot be stopped by Horace's magic.", this_object(), + ({ this_player() })); + return 1; +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/torture_room.c b/lib/domains/Praxis/torture_room.c new file mode 100644 index 0000000..a92f62a --- /dev/null +++ b/lib/domains/Praxis/torture_room.c @@ -0,0 +1,28 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperties( ([ "indoors" : 1, "light" : 1, "no killing" : 1, + "no stealing" : 1, "no magic" : 1, "no teleport" : 1 ]) ); + SetShort("Torture Room"); + SetLong("You are in the infamous Torture hall, a small " + "room used by the Praxis Guard on only the worst of criminals. " + "From your vantage point upon a " + "table in the center of the room, you are unable to gather " + "much information about your surroundings. However, you can " + "see various devices scattered around the room, covered " + "with dust and cobwebs."); + SetItems( ([ "devices" : "Assorted mechanical devices used in the " + "performing cruel and unusual punishments.", + "table" : "An uncomfortable cement table." ]) ); + SetSmell("default", "The pungent odor of rotting corpses fills " + "the air."); +} + +void init() { + ::init(); + if(this_player()->query_ghost()) + this_player()->move("/domains/Mountains/cave/cave3"); +} diff --git a/lib/domains/Praxis/town_hall.c b/lib/domains/Praxis/town_hall.c new file mode 100644 index 0000000..df6aa4d --- /dev/null +++ b/lib/domains/Praxis/town_hall.c @@ -0,0 +1,91 @@ +/* +// File : /domains/Praxis/town_hall.c +// Comment : Entrance for Court room and Council chambers +// 94-07-02 : Pallando @ Nightmare wrote it + */ +#include <lib.h> +#include <objects.h> + +#define COUNCIL_CHAMBER "/domains/Praxis/council" + +inherit LIB_ROOM; + +object *listeners = ({ }); + + +void create() +{ + ::create(); + SetProperties( ([ + "indoors" : 1, + "light" : 2, + "no castle" : 1, + "no teleport" : 1, + "no bump" : 1, + "no attack" : 1, + "no steal" : 1, + "no magic" : 1, + ]) ); + SetShort( "Praxis Town Hall" ); + SetLong( + "This is a large stately hall; the walls are covered with rich hangings, " + "the vaulted roof is supported by thick marble columns. A wide curving " + "staircase leads up to the council chambers above. The exit to the " + "street is north." + // " South lies the Court of Justice." + ); + SetItems( ([ + "hall" : "It is five times the height of a tall man.", + "roof" : "If you \"listen to council\", perhaps you will hear them.", + "hangings" : "They depict the noble self-sacrifice of being a councilor.", + "columns" : "They have gargoyles at their tops.", + "staircase" : "It goes between two of the columns.", + "chambers" : "If you listen, perhaps you can hear the council.", + "court" : "This is where trials are held.", + "street" : "It is Boc La Road south of the monastary.", + "gargoyles" : "They look innocently inanimate.", + "gargoyle" : "It is impenetrateable as a stone wall.", + ]) ); + SetExits( ([ + "south" : "/domains/Praxis/court_room", + "north" : "/domains/Praxis/e_boc_la1", + ]) ); + SetListen( "council", (: "listen_council" :) ); +} +int pre_exit_up() +{ + if( leaderp( this_player() ) || creatorp( this_player() ) ) + return 1; + write( "A gargoyle blocks your way.\n" ); + return 0; +} +string listen_council( string arg ) +{ + // First, check if there are any councilors to listen to. + //call_other( COUNCIL_CHAMBER, "???" ); + //if( !sizeof( filter_array( all_inventory( find_object( COUNCIL_CHAMBER + // ) ), "leaderp", OB_SIMUL_EFUN ) ) ) + // return "Council is not in session.\n"; + // if( -1 != member_array( this_player(), listeners ) ) + // return "You are already listening.\n"; + // listeners += ({ this_player() }); + return "You start listening in to the council's debate.\n"; +} +int release_objects( object ob ) +{ + if( -1 != member_array( ob, listeners ) ) + { + tell_object( ob, "You stop listening to the council.\n" ); + listeners -= ({ ob }); + } + return 1; +} +void receive_message( string msg_class, string msg ) +{ + message( msg_class, msg, listeners ); +} + +/* EOF */ +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/trunk.c b/lib/domains/Praxis/trunk.c new file mode 100644 index 0000000..c80eaa8 --- /dev/null +++ b/lib/domains/Praxis/trunk.c @@ -0,0 +1,37 @@ +inherit "/lib/std/room"; + +void create() { + ::create(); + SetShort("the upper trunk"); + SetLong( + "A very large room has been carved out of the upper trunk of the mage tree. "+ + "A small stairway leads down to the entrance of the tree, while upwards it "+ + "leads out of the tree, and into the wide canopy of the branches. "); + SetProperties( (["light" : 2, + "indoors" : 1 , + "no castle" : 1]) ); + SetItems( ([ + "mage tree" : "You cannot see the tree for the living wooden walls "+ + "surrounding you.", + "upper trunk" : "You are in the trunk of the tree.", + "entrance" : "The entrance is in the room below you.", + "canopy" : "Above you are leafy green branches. Go up into them.", + "room" : (: this_object(), "print_long" :), + "trunk" : "You are in the trunk of the tree.", + "tree" : "You cannot see the tree for the living wooden walls "+ + "surrounding you.", + "branches" : "Above you are leafy green branches. Go up into them.", + "walls" : "This room has walls. Fancy that. They're made of wood, "+ + "which makes sense since you are inside of a tree.", + "stairway" : "The wooden stairway creaks and groans as you put your weight "+ + "on it."]) ); + SetExits( (["down" : "/domains/Praxis/mage_hall", + "up" : "/domains/Praxis/branches"]) ); +} + +void print_long() { + write (this_object()->GetLong()); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/unnamed1.c b/lib/domains/Praxis/unnamed1.c new file mode 100644 index 0000000..5217a1c --- /dev/null +++ b/lib/domains/Praxis/unnamed1.c @@ -0,0 +1,24 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 2); + SetProperty("night light", 1); + SetProperty("no castle", 1); + SetShort( "Outside the financial district"); + SetLong( + "Leading out east into the rural lands outside of Praxis, this unnamed " + "dirt road sits almost entirely untravelled. The business district " + "of Praxis is west."); + SetItems( + (["road" : "It is temporarily blocked going east."]) ); + SetSkyDomain("town"); + SetExits( ([ + "west" : "/domains/Praxis/s_centre3", + ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/void.c b/lib/domains/Praxis/void.c new file mode 100644 index 0000000..e868ec0 --- /dev/null +++ b/lib/domains/Praxis/void.c @@ -0,0 +1,13 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + room::create(); + SetShort("the void"); + SetLong("The void. Go down to get out."); + SetExits(([ "down": "/domains/Praxis/square" ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/w_boc_la1.c b/lib/domains/Praxis/w_boc_la1.c new file mode 100644 index 0000000..379d718 --- /dev/null +++ b/lib/domains/Praxis/w_boc_la1.c @@ -0,0 +1,44 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 3); + SetProperty("night light", 1); + SetProperty("no castle", 1); + SetShort( "West Boc La in Praxis"); + SetDayLong("The local pub on the southwest corner of the square " + "east of here gets little business at the height of " + "the day. As twilight fall into dusk, however, you " + "will notice more people making their way into the pub " + "to cap off a day of adventure. The road you are on, " + "West Boc La, leads into the western districts of " + "Praxis and east to the centre of town."); + SetNightLong("The street lamps provide you with barely enough " + "light to see, but can you can just see Krasna Square east and " + "Lars' Pub to the south. You can also make out a chapel to " + "the north, but you see no entrance."); + + SetListen("default", "Cheers of local adventurers " + "resonate from inside the pub."); + SetExits( + (["east" : "/domains/Praxis/square", + "west" : "/domains/Praxis/w_boc_la2", + "south" : "/domains/Praxis/pub"]) ); + SetItems( + (["church" : "It looks like the entrance might be on the " + "road leading north from Monument Square.", + ({"lamps", "lamp", "street lamp"}) : "All of the street " + "lamps along the road provide minimal light at night.", + ({"pub", "lars pub", "lars' pub"}) : "Local adventurers " + "wind down their day in Lars' Pub.", + ({"road", "west boc la", "boc la"}) : "It goes beyond the " + "western districts of Praxis into the mountains.", + "square" : "At the centre of Praxis, it is where " + "Boc La and Centre Path meet."]) ); + SetSkyDomain("town"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/w_boc_la2.c b/lib/domains/Praxis/w_boc_la2.c new file mode 100644 index 0000000..ddb835b --- /dev/null +++ b/lib/domains/Praxis/w_boc_la2.c @@ -0,0 +1,45 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 3); + SetProperty("night light", 1); + SetProperty("no castle", 1); + SetShort("West Boc La"); + SetDayLong( "Western Praxis is a more rural district of town. " + "The southern area opens up into farmlands while the northern " + "side is lined with small huts and houses. The road continues " + "to run in an east-west direction."); + SetNightLong("Street lamps line the streets of rural West " + "Praxis lighting the small huts and houses to the north and " + "the farmlands to the south. To the east and west the road " + "continues."); + + SetSmell("default", "Wisps of a magical smelling smoke are rising " + "from a house on the north side of West Boc La."); + SetSmell("smoke", "It smells unlike any substance you have ever " + "encountered."); + SetSmell("house", "It smells of the magic smoke coming from it."); + SetExits( + (["east" : "/domains/Praxis/w_boc_la1", + "west" : "/domains/Praxis/w_boc_la3", + "south" : "/domains/Praxis/farm", + "north" : "/domains/Praxis/sage_room"]) ); + SetItems( + (["road" : "Boc La Road runs east and west through Praxis.", + "roads" : "West Road and Boc La Road.", + "highway" : "A very heavily travelled highway to the " + "western lands of Nightmare. Beware of the Daroq Mountains.", + "mountains" : "The Daroq Mountains. Vile creatures are " + "rumoured to live in and about them.", + "house" : "This tiny little house has wisps of white " + "smoke coming out of the door and windows.", + "smoke" : "Lacey wisps of white smoke are coming out " + "of the house to the north."]) ); + SetSkyDomain("town"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/w_boc_la3.c b/lib/domains/Praxis/w_boc_la3.c new file mode 100644 index 0000000..c0665b9 --- /dev/null +++ b/lib/domains/Praxis/w_boc_la3.c @@ -0,0 +1,31 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 2); + SetProperty("night light", 1); + SetProperty("no castle", 1); + SetShort( "The western outskirts of Praxis"); + SetLong( + "Beyond Praxis to the west tower the wicked Daroq Mountains which " + "protect this part of reality from the punishing Qajip Desert. " + "Boc La Road of a local village leads east into the centre of the " + "town. West Road travels north from here."); + SetExits( + (["north" : "/domains/Praxis/west_road1", + "west" : "/domains/Praxis/highway1", + "east" : "/domains/Praxis/w_boc_la2"]) ); + SetItems( + (["road" : "Boc La Road runs east and west through Praxis. ", + "roads" : "West Road and Boc La Road. ", + "highway" : "A very heavily travelled highway to the western " + "lands of Nightmare. Beware of the Daroq Mountains. ", + "mountains" : "The Daroq Mountains. Vile creatures are " + "rumoured to live in and about them."]) ); + SetSkyDomain("town"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/wall.c b/lib/domains/Praxis/wall.c new file mode 100644 index 0000000..149754a --- /dev/null +++ b/lib/domains/Praxis/wall.c @@ -0,0 +1,93 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_ROOM; + +mixed *text_scan; + +int bad(string str); + +void init() { + ::init(); + add_action("read", "read"); + add_action("scribble", "scribble"); +} + +void create() { + ::create(); + SetProperties( ([ "light" : 2, "night light" : 1, "no castle" : 1 ])); + SetShort("a graffitti covered wall"); + SetLong( + "You are in among ruined buildings in a bad part of the village. " + "There is graffiti all over the wall to the east."); + SetItems( + (["buildings" : "They are worn down by years of neglect.", + "graffiti" : "Some is fresh, some is old.", + "wall" : "You can scribble something on it. <scribble stuff>.\n" + "You can also read what is on it."]) ); + SetExits( + (["south" : "/domains/Praxis/alley2"]) ); + call_out("fade", 900); + unguarded( (: RestoreObject("/domains/Praxis/data/wall") :) ); +} + +int scribble(string str) { + if(!text_scan) text_scan = ({}); + if(bad(str)) { + notify_fail("The Nightmare Reality prevents you from spreading your crap.\n"); + return 0; + } + text_scan += ({ str }); + personal_log("graffitti: "+ this_player()->query_name()+" "+ctime(time())+"\n"+str+"\n"); + unguarded( (: SaveObject("/domains/Praxis/data/wall") :) ); + message("my_action", sprintf("You scribble: %s", str), this_player()); + message("other_action", sprintf("%s scribbles some graffitti on the wall.", + this_player()->query_cap_name()), this_object(), + ({ this_player() })); + return 1; +} + +int read(string str) { + int i; + + if(!str) { + notify_fail("Read what?\n"); + return 0; + } + if(str != "wall" && str != "graffitti") { + notify_fail("Read what?\n"); + return 0; + } + for(i=0; i<sizeof(text_scan); i++) { + message("info", text_scan[i], this_player()); + } + message("other_action", sprintf("%s reads the graffitti on the wall.", + this_player()->query_cap_name()), this_object(), + ({ this_player() })); + return 1; +} + +int bad(string str) { + string a, b; + int i; + string *bad_words; + + bad_words = ({ "fuck", "shit", "cock", "cunt", "bitch" }); + for(i=0; i<sizeof(bad_words); i++) { + if(sscanf(lower_case(str), "%s"+bad_words[i]+"%s", a, b) == 2) return 1; + } + return 0; +} + +void fade() { + string str; + + if(!text_scan) return; + if(text_scan == ({})) return; + str = text_scan[0]; + text_scan -= ({ str }); + message("environment", "Some graffitti fades from the wall.", + this_object()); + call_out("fade", 10000); + SaveObject("/domains/Praxis/data/wall"); +} diff --git a/lib/domains/Praxis/west_road1.c b/lib/domains/Praxis/west_road1.c new file mode 100644 index 0000000..cdc0696 --- /dev/null +++ b/lib/domains/Praxis/west_road1.c @@ -0,0 +1,30 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 2); + SetProperty("night light", 1); + SetProperty("no castle", 1); + SetShort( "the southern end of West Road"); + SetLong( + "West Road is the main residential road that runs through Praxis. " + "One or two more houses lie on either side of the road, until " + "it comes to a dead end south of here at Boc La Road. The small " + "huts lining the road are rather run down and unattractive. You " + "can hear noises coming from inside of them, as the inhabitants " + "carry on with their lives."); + SetItems( + (["road" : "West Road, which marks the westernmost end of Praxis.", + "huts" : "They are small peasant huts.", + "hut" : "It has a thatch roofing, and is not really extravagant." + ]) ); + SetSkyDomain("town"); + SetExits( + (["north" : "/domains/Praxis/west_road2", + "south" : "/domains/Praxis/w_boc_la3"]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/west_road2.c b/lib/domains/Praxis/west_road2.c new file mode 100644 index 0000000..2f44986 --- /dev/null +++ b/lib/domains/Praxis/west_road2.c @@ -0,0 +1,91 @@ +#include <lib.h> + +inherit LIB_ROOM; + +int dug; +string orig_long, dug_long; +string is_dug(); + +void init() { + ::init(); + add_action("read", "read"); + add_action("dig", "dig"); +} + +void create() { + ::create(); + SetProperty("light", 2); + SetProperty("no castle", 1); + SetShort( "along West Road"); + SetLong( (: is_dug :)); + SetNoClean(1); + SetItems( + (["road" : "There is a mound of loose dirt piled by its side.", + "dirt" : "It is very loose.", + "hut " : "It looks very mystical.", + "sign" : "Those who can read are very fortunate indeed!", + "mound" : (: this_object(), "look_at_mound" :) ]) ); + SetSkyDomain("town"); + SetExits( + (["north" : "/domains/Praxis/west_road3", + "south" : "/domains/Praxis/west_road1", + "east" : "/domains/Praxis/medium"]) ); + dug = 0; +} + +void reset() { + ::reset(); + if(!dug) return; + dug = 0; + RemoveItem("hole"); + RemoveExit("down"); + call_other("/domains/Praxis/hole", "fixing_a_hole"); +} + +void look_at_mound() { + if(!dug) write("It looks as if someone dug a hole there, " + "then covered it back up."); + else write("It is a mound of dirt dug out from the hole beside it."); +} + +int dig() { + if(!present("shovel", this_player()) && !present("spade", this_player())) { + notify_fail("You have nothing to dig with!\n"); + return 0; + } + if(dug) { + notify_fail("Where are you going to dig?\n"); + return 0; + } + write("You dig into the mound and uncover a hole."); + say(this_player()->query_cap_name()+" digs into the mound " + "and uncovers a hole.", this_player()); + dug = 1; + AddItem("hole", "A hole where someone just dug into the ground by the mound by the road."); AddExit( "down", "/domains/Praxis/hole"); + + call_other("/domains/Praxis/hole", "digging"); + return 1; +} + +int query_dug() { return dug; } + +int read(string str) { + if(str != "sign" && str != "door") { + notify_fail("Read what?\n"); + return 0; + } + write("Mora's house of mysticism.\n" + "Learn yours or someone else's horoscope for the day."); + return 1; +} + +string is_dug() { + if(!dug) return "You are in the middle of West Road where rural " + "huts line the sides of the road. One of the huts on the east side " + "has a sign hanging outside it. A mound of loose dirt covers part " + "of the west side of the road."; + else return "You are in the middle of west road where rural huts line " + "the sides of the road. One of the huts on the east side has a " + "sign hanging outside of it. A hole has been recently uncovered " + "on the west side of the road."; +} diff --git a/lib/domains/Praxis/west_road3.c b/lib/domains/Praxis/west_road3.c new file mode 100644 index 0000000..b102755 --- /dev/null +++ b/lib/domains/Praxis/west_road3.c @@ -0,0 +1,43 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void init() { + ::init(); + add_action("enter", "enter"); +} + +void create() { + ::create(); + SetProperty("light", 2); + SetShort( "the north end of West Road"); + SetLong( + "West Road comes to an abrupt end as it is engulfed by the forest " + "to the north. A huge ancient willow tree provides shelter to " + "this entire section of the road. At its massive roots you can " + "see a whole leading down into the depths of the earth. Boc La Road " + "lies far south of here."); + SetItems( + (["tree" : "It must be older than Praxis itself.", + "hole" : "You might even be able to enter the tree.", + "road" : "This end of the road is shaded by the huge " + "tree of mysterious origins.", + "foo" : "You're daft.", + "bar" : "Had to check that too, eh?"]) ); + SetSkyDomain("town"); + SetExits( + (["south" : "/domains/Praxis/west_road2"]) ); +} + +int enter(string str) { + if(!str) { + notify_fail("Enter what?\n"); + return 0; + } + if(str != "hole" && str != "tree") { + notify_fail("You can't do that here.\n"); + return 0; + } + this_player()->eventMoveLiving("/domains/Praxis/mage_join", "into the tree"); + return 1; +} diff --git a/lib/domains/Praxis/wild1.c b/lib/domains/Praxis/wild1.c new file mode 100644 index 0000000..b581901 --- /dev/null +++ b/lib/domains/Praxis/wild1.c @@ -0,0 +1,23 @@ +inherit "/lib/std/room"; + +void create() { + ::create(); + SetProperty("light", 3); + SetProperty("night light", 1); + SetShort( "The wilderness outside of Praxis"); + SetLong( + "The vegetation in the area outside the village " + "thickens into jungle as you head east."); + SetItems( + (["jungle" : "A wilderness area full of outlaws and " + "mysterious things.", + "village" : "The adventurer's town of Praxis.", + "vegetation" : "It gets thicker to the east."]) ); + SetSkyDomain("town"); + SetExits( + (["east" : "/domains/Praxis/wild2", + "west" : "/domains/Praxis/e_boc_la3"]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Praxis/wild2.backup b/lib/domains/Praxis/wild2.backup new file mode 100644 index 0000000..0a0b620 --- /dev/null +++ b/lib/domains/Praxis/wild2.backup @@ -0,0 +1,47 @@ +inherit "/lib/std/room"; + +void init() { + ::init(); + add_action("enter_opening", "enter"); + add_action("go_southeast", "southeast"); +} + +void create() { + ::create(); + SetProperty("light", 2); + SetShort( "The tropical wilderness"); + SetLong( + "You are inside a jungle that thickens along the path " + "northeast. The path widens west as it heads towards " + "the adventuring village of Praxis. You also notice " + "a small opening in the thick jungle cover southeast."); + SetItems( + (["jungle" : "A wilderness area full of outlaws and " + "mysterious things.\n", + "village" : "The adventurer's town of Praxis.", + "vegetation" : "It gets thicker to the east.", + "path" : "You can see it opening up towards the village west.", + "opening" : "Perhaps you could enter it?"]) ); + SetExits( + (["northeast" : "/domains/Praxis/jungle", + "west" : "/domains/Praxis/wild1"]) ); +} + +int enter_opening(string str) { + if(!str) { + notify_fail("Enter what?\n"); + return 0; + } + if(str != "opening" && str != "hole" && str != "jungle") { + notify_fail("That is not here to be entered.\n"); + return 0; + } + this_player()->eventMoveLiving("/domains/Praxis/outland1", "into the jungle"); + return 1; +} + +int go_southeast() { + this_player()->eventMoveLiving("/domains/Praxis/outland1", "into the jungle"); + return 1; +} + diff --git a/lib/domains/Praxis/wild2.c b/lib/domains/Praxis/wild2.c new file mode 100644 index 0000000..dc12b60 --- /dev/null +++ b/lib/domains/Praxis/wild2.c @@ -0,0 +1,44 @@ +inherit "/lib/std/room"; + +void init() { + ::init(); + //add_action("enter_opening", "enter"); +} + +void create() { + ::create(); + SetProperty("light", 2); + SetShort( "The tropical wilderness"); + SetLong( + "You are inside a jungle that thickens along the path " + "northeast. The path widens west as it heads towards " + "the adventuring village of Praxis." + // " You also notice a small opening in the thick jungle." + ); + SetItems( + (["jungle" : "A wilderness area full of outlaws and " + "mysterious things.\n", + "village" : "The adventurer's town of Praxis.", + "vegetation" : "It gets thicker to the east.", + "path" : "You can see it opening up towards the village west.", + //"opening" : "On second glance, its too small to enter" + ]) ); + SetSkyDomain("town"); + SetExits( + (["northeast" : "/domains/Praxis/jungle", + "west" : "/domains/Praxis/wild1"]) ); +} + +int enter_opening(string str) { + if(!str) { + notify_fail("Enter what?\n"); + return 0; + } + if(str != "opening" && str != "hole" && str != "jungle") { + notify_fail("That is not here to be entered.\n"); + return 0; + } + this_player()->eventMoveLiving("/domains/Praxis/outland1", "into the jungle"); + return 1; +} + diff --git a/lib/domains/Praxis/yard.c b/lib/domains/Praxis/yard.c new file mode 100644 index 0000000..566dc93 --- /dev/null +++ b/lib/domains/Praxis/yard.c @@ -0,0 +1,47 @@ +#include <lib.h> + +inherit LIB_ROOM; + +void create() { + ::create(); + SetProperty("light", 3); + SetProperty("night light", 2); + SetProperty("no castle", 1); + SetShort("A small yard"); + SetDayLong( "Daytime makes this beautiful yard at the end of a " + "small alley glow with peace. Quaint houses surround the yard " + "on all flanks except to the west where the alley intersects " + "Centre Path. There is a manhole where the alley meets the " + "yard."); + SetNightLong( "Very little stirs at the end of this small alley " + "in the dark of the night. Some light illuminates the area from " + "the lamps which are posted in front of the houses which " + "surround the yard at the end of the alley."); + + SetDoor("/domains/Praxis/sewer_ent","down"); + "/domains/Praxis/sewer_ent"->SetOpen("manhole", 0); + SetExits( + (["west" : "/domains/Praxis/s_centre2", + "north" : "/domains/Praxis/sheriff", + "down" : "/domains/Praxis/sewer_ent"]) ); + SetItems( + (["alley" : "It looks beautiful here.", + ({ "lamp", "lamps" }) : "Dimly illuminated lights.", + "manhole" : (: this_object(), "look_at_manhole" :) ]) ); + SetSkyDomain("town"); + SetInventory(([ + "/domains/Praxis/obj/mon/beggar" : 1, + ])); +} + +void reset() { + ::reset(); + if(!find_living("beggar") || !environment(find_living("beggar"))) + new("/domains/Praxis/obj/mon/beggar")->move(this_object()); + if(query_reset_number() != 1) { + "/domains/Praxis/sewer_ent"->SetOpen("manhole", 0); + } +} +void init(){ + ::init(); +} diff --git a/lib/domains/README b/lib/domains/README new file mode 100644 index 0000000..b7800b0 --- /dev/null +++ b/lib/domains/README @@ -0,0 +1,14 @@ +These are sample domains. + +Ylsrim is from Nightmare V. It is kept for historical +and sentimental reasons. It can be safely deleted. + +Praxis is from Nightmare 3. It is kept for historical +and sentimental reasons. It can be safely deleted. + +The rest contain important examples and should not +be deleted unless you know exactly what this means. +Please see the following URL for a more detailed +explanation: + +http://dead-souls.net/ds-admin-faq.html#138 diff --git a/lib/domains/Ylsrim/README b/lib/domains/Ylsrim/README new file mode 100644 index 0000000..3bfa349 --- /dev/null +++ b/lib/domains/Ylsrim/README @@ -0,0 +1,12 @@ + /domains/Ylsrim + The Standard Domain for the Nightmare V Object Library + +This is the original sample domain provided with Dead Souls 1.1pre. + +It has been modified to work correctly with Dead Souls 2, but you will +notice some differences in layout and design philosophy. Please regard this +domain as a source of examples, but note that it is here for historical +and back-compatibility purposes, and not necessarily as a model for +building standards. + +-Cratylus 06DEC05 diff --git a/lib/domains/Ylsrim/README.old b/lib/domains/Ylsrim/README.old new file mode 100644 index 0000000..a04f28a --- /dev/null +++ b/lib/domains/Ylsrim/README.old @@ -0,0 +1,14 @@ + /domains/Ylsrim + The Standard Domain for the Nightmare V Object Library + +This domain is designed to provide examples of all Nightmare V Object +Library inheritables. It also serves as the standard distribution +domain and should serve as an adequate area for people wanting to open +up a mud quickly with minimum hassle. We do recommend, if you have +the resources, that you use this stuff only for examples and write +your own, unique standard domain. To do so, you will need in your new +standard domain all of the files in /domains/Ylsrim/adm and you will +also need a start room (which here is /domains/Ylsrim/room/bazaar). +Then go into /secure/include/dirs.h and change DIR_STANDARD_DOMAIN to +point to your new domain directory, and /secure/include/rooms.h to +point to your new start room. diff --git a/lib/domains/Ylsrim/adm/README b/lib/domains/Ylsrim/adm/README new file mode 100644 index 0000000..2ddcbe3 --- /dev/null +++ b/lib/domains/Ylsrim/adm/README @@ -0,0 +1,14 @@ + The Administrative Directory + +This directory contains files necessary for domain administration. + +Specifically it is the default directory for the access object, +which is used for providing nonstandard access to files with +the "grant" command. + +This is also the location where domain-specific daemons can be +expected to reside. + +In the case of archaic domains, such as Ylsrim, this is where +some mandatory rooms are expected to be, such as freezer.c and void.c + diff --git a/lib/domains/Ylsrim/adm/access.c b/lib/domains/Ylsrim/adm/access.c new file mode 100644 index 0000000..c8f9f3f --- /dev/null +++ b/lib/domains/Ylsrim/adm/access.c @@ -0,0 +1,9 @@ +/* /domains/Ylsrim/adm/access.c + * From the Dead Souls Mud Library + * the access object for the Ylsrim domain + * created by Descartes of Borg 960302 + */ + +#include <lib.h> + +inherit LIB_ACCESS; diff --git a/lib/domains/Ylsrim/adm/cache.c b/lib/domains/Ylsrim/adm/cache.c new file mode 100644 index 0000000..6d8866c --- /dev/null +++ b/lib/domains/Ylsrim/adm/cache.c @@ -0,0 +1,17 @@ +/* /domains/Ylsrim/adm/cache.c + * from the Dead Souls Mud Library + * room where hidden objects are stored + * created by Descartes of Borg 960302 + */ + +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetShort( "The cache"); + SetLong( "Things are hidden here."); + SetProperties( ([ "storage room" : 1, "logout" : ROOM_START ]) ); +} diff --git a/lib/domains/Ylsrim/adm/freezer.c b/lib/domains/Ylsrim/adm/freezer.c new file mode 100644 index 0000000..5f92e8f --- /dev/null +++ b/lib/domains/Ylsrim/adm/freezer.c @@ -0,0 +1,41 @@ +/* /domains/Ylsrim/adm/freezer.c + * from the Dead Souls Mud Library + * room that stores net-dead people + * created by Descartes of Borg 960302 + */ + +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +static private object *Old; + +void create() { + room::create(); + SetNoClean(1); + SetProperties(([ "login" : ROOM_START, "no teleport" : 1 ])); + SetShort( "The freezer"); + SetLong( "The local freezer. Go down to leave."); + SetObviousExits("down"); + SetExits( ([ "down" : ROOM_START ]) ); + Old = ({}); + call_out("clean_room", MAX_NET_DEAD_TIME); +} + +static void clean_room() { + object *clean_me; + object ob; + + foreach(ob in filter(all_inventory(), (: !living($1) :))) + ob->eventDestruct(); + if( !sizeof(filter(all_inventory(), (: living :))) ) { + Old = ({}); + call_out((: clean_room :), MAX_NET_DEAD_TIME); + return; + } + clean_me = (all_inventory() & Old); + Old = all_inventory() - clean_me; + foreach(ob in clean_me) ob->eventDestruct(); + call_out((: clean_room :), MAX_NET_DEAD_TIME); +} diff --git a/lib/domains/Ylsrim/adm/void.c b/lib/domains/Ylsrim/adm/void.c new file mode 100644 index 0000000..99c0faf --- /dev/null +++ b/lib/domains/Ylsrim/adm/void.c @@ -0,0 +1,18 @@ +/* /domains/Ylsrim/adm/void.c + * from the Dead Souls Mud Library + * place where people go when their environments accidentally are + * destructed + * created by Descartes of Borg 960302 + */ + +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetShort("the void"); + SetLong("The void. Go down to get out."); + SetExits( ([ "down" : ROOM_START ]) ); +} diff --git a/lib/domains/Ylsrim/armor/artrell_armor.c b/lib/domains/Ylsrim/armor/artrell_armor.c new file mode 100644 index 0000000..23503ff --- /dev/null +++ b/lib/domains/Ylsrim/armor/artrell_armor.c @@ -0,0 +1,34 @@ +/* /domains/Ylsrim/armor/artrell_armor.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 960302 + */ + +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ARMOR; + +static void create() { + armor::create(); + SetKeyName("leather armor"); + SetId( ({ "armor", "leather armor" }) ); + SetAdjectives( ({ "leather" }) ); + SetShort("a suit of leather armor"); + SetLong("An ordinary suit of leather armor. It is worn on one's arms, torso and legs."); + SetVendorType(VT_ARMOR); + SetMass(750); + SetValue(150); + SetDamagePoints(800); + SetProtection(BLUNT, 20); + SetProtection(BLADE, 20); + SetProtection(KNIFE, 25); + SetProtection(HEAT, 7); + SetProtection(COLD, 4); + SetProtection(SHOCK, 15); + SetArmorType(A_ARMOR); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/armor/helm.c b/lib/domains/Ylsrim/armor/helm.c new file mode 100644 index 0000000..d67fe01 --- /dev/null +++ b/lib/domains/Ylsrim/armor/helm.c @@ -0,0 +1,46 @@ +/* /domains/Ylsrim/armor/helm.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 960302 + */ + +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ARMOR; + +varargs int WearHelm(object who, mixed where); + +static void create() { + armor::create(); + SetKeyName("desert helm"); + SetId( ({ "helm", "desert helm" }) ); + SetAdjectives( ({ "sandy", "brown" }) ); + SetShort("a dusty helm"); + SetLong("This helm is the Desert helm, bestowed upon honoured " + "knights of the desert. It is made from a magic sand bound " + "together to protect the heads of the righteous."); + SetDamagePoints(3000); + SetVendorType(VT_ARMOR); + SetMass(200); + SetValue(300); + SetArmorType(A_HELMET); + SetWear( (: WearHelm :) ); + SetProtection(BLUNT, 40); + SetProtection(BLADE, 3); + SetProtection(KNIFE, 10); + SetProtection(HEAT, 30); +} + +varargs int WearHelm(object who, mixed where) { + object env = environment(who); + if( who->GetMorality() < 300 ) { + who->eventPrint("The helm burns your head!"); + who->eventReceiveDamage(0, HEAT, random(10) + 10, 0, "head"); + return 0; + } + who->eventPrint("You wear the desert helm."); + if(env) tell_room(env, who->GetName()+" wears the desert helm.", ({who})); + return 1; +} diff --git a/lib/domains/Ylsrim/armor/leather_armor.c b/lib/domains/Ylsrim/armor/leather_armor.c new file mode 100644 index 0000000..95719c4 --- /dev/null +++ b/lib/domains/Ylsrim/armor/leather_armor.c @@ -0,0 +1,34 @@ +/* /domains/Ylsrim/armor/artrell_armor.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 960302 + */ + +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ARMOR; + +static void create() { + armor::create(); + SetKeyName("leather armor"); + SetId( ({ "armor", "leather armor" }) ); + SetAdjectives( ({ "leather" }) ); + SetShort("a suit of leather armor"); + SetLong("An ordinary suit of leather armor. It is worn on one's arms, torso and legs."); + SetVendorType(VT_ARMOR); + SetMass(750); + SetValue(150); + SetDamagePoints(800); + SetProtection(BLUNT, 20); + SetProtection(BLADE, 20); + SetProtection(KNIFE, 25); + SetProtection(HEAT, 7); + SetProtection(COLD, 4); + SetProtection(SHOCK, 15); + SetArmorType(A_BODY_ARMOR); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/armor/normal_helm.c b/lib/domains/Ylsrim/armor/normal_helm.c new file mode 100644 index 0000000..eed268a --- /dev/null +++ b/lib/domains/Ylsrim/armor/normal_helm.c @@ -0,0 +1,30 @@ +/* /domains/Ylsrim/armor/helm.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 960302 + */ + +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ARMOR; + + +static void create() { + armor::create(); + SetKeyName("wooden helm"); + SetId("helm"); + SetAdjectives("wooden"); + SetShort("a wooden helm"); + SetLong("It is a lame wooden helm."); + SetDamagePoints(3000); + SetVendorType(VT_ARMOR); + SetMass(200); + SetValue(100); + SetArmorType(A_HELMET); + SetProtection(BLUNT, 40); + SetProtection(BLADE, 3); + SetProtection(KNIFE, 10); + SetProtection(HEAT, 30); +} diff --git a/lib/domains/Ylsrim/armor/shield.c b/lib/domains/Ylsrim/armor/shield.c new file mode 100644 index 0000000..07d8188 --- /dev/null +++ b/lib/domains/Ylsrim/armor/shield.c @@ -0,0 +1,44 @@ +/* /domains/Ylsrim/armor/shield.c + * from the Dead Souls Mud Library + * an example shield + * created by Lassondra@Dead Souls + */ + +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ARMOR; + +varargs int eventWearShield(object who, mixed where); + +static void create() { + armor::create(); + SetKeyName("wooden shield"); + SetId( ({ "shield", "wooden shield" }) ); + SetShort("a wooden shield"); + SetLong("This shield is a simple circle of woode with no markings."); + SetDamagePoints(600); + SetVendorType(VT_ARMOR); + SetMass(400); + SetValue(75); + SetArmorType(A_SHIELD); + SetWear( (: eventWearShield :) ); + SetProtection(BLUNT, 5); + SetProtection(BLADE, 3); + SetProtection(KNIFE, 10); + SetProtection(SHOCK, 30); +} + +varargs int eventWearShield(object who, mixed where) { + object env = environment(who); + if( who->GetRace() != "hobbit" ) { + who->eventPrint("The shield's handle simply does not fit your hand " + "right."); + return 0; + } + who->eventPrint("You wear "+GetShort()+"."); + if(env) tell_room(env, who->GetName()+" wears "+GetShort()+".", ({who})); + return 1; +} diff --git a/lib/domains/Ylsrim/broken/README b/lib/domains/Ylsrim/broken/README new file mode 100644 index 0000000..6453217 --- /dev/null +++ b/lib/domains/Ylsrim/broken/README @@ -0,0 +1,3 @@ +Items in this directory appear to require +library objects that do not exist by default +in the originally released Dead Souls lib. diff --git a/lib/domains/Ylsrim/broken/cold.c b/lib/domains/Ylsrim/broken/cold.c new file mode 100644 index 0000000..9c41500 --- /dev/null +++ b/lib/domains/Ylsrim/broken/cold.c @@ -0,0 +1,45 @@ +/* /domains/Ylsrim/etc/cold.c + * From the Dead Souls Mud Library + * An example of how to build a germ + * created by Descartes of Borg 961216 + */ + +#include <lib.h> +#include <damage_types.h> + +inherit LIB_GERM; + +static void create() { + germ::create(); + SetId("cold"); + SetType("cold"); + SetCommunicable(40); + SetCure(20); + SetLifeSpan(60); +} + +int eventSuffer(object who) { + if( !random(100) ) { + Destruct(); + return 1; + } + switch(random(3)) { + case 0: + send_messages("cough", "$agent_name $agent_verb miserably.", + who, 0, environment(who)); + break; + + case 1: + send_messages("", "$agent_possessive_noun red nose runs all over " + "$agent_possessive face.", who, 0, environment(who)); + break; + + case 2: + send_messages("look", "$agent_name $agent_verb miserable.", + who, 0, environment(who)); + break; + } + who->eventReceiveDamage(0, COLD, random(3) + 1, 1); + return 1; +} + diff --git a/lib/domains/Ylsrim/broken/flu.c b/lib/domains/Ylsrim/broken/flu.c new file mode 100644 index 0000000..02f9fb4 --- /dev/null +++ b/lib/domains/Ylsrim/broken/flu.c @@ -0,0 +1,64 @@ +/* /domains/Ylsrim/etc/flu.c + * From the Dead Souls Mud Library + * An example of how to build a germ + * created by Descartes of Borg 961216 + */ + +#include <lib.h> +#include <damage_types.h> + +inherit LIB_GERM; + +int cureMe(object who, int amount, string type); +int infectMe(object who); + +static void create() { + germ::create(); + SetId("flu", "influenza"); + SetType("flu"); + SetCommunicable(20); + SetCure((: cureMe :)); + SetLifeSpan(60); + SetInfect((: infectMe :)); +} + +mixed cureMe(object who, int amount, string type) { + if( amount < 40 ) { + return 0; + } + return 1; +} + +int infectMe(object who) { + if( who->GetRace() == "klingon" ) { + return 0; + } + who->eventPrint("You start feeling a little achy."); + return 1; +} + +int eventSuffer(object who) { + if( !random(100) ) { + Destruct(); + return 1; + } + switch(random(3)) { + case 0: + send_messages("cough", "$agent_name $agent_verb miserably.", + who, 0, environment(who)); + break; + + case 1: + send_messages("", "$agent_possessive_noun red nose runs all over " + "$agent_possessive face.", who, 0, environment(who)); + break; + + case 2: + send_messages("look", "$agent_name $agent_verb miserable.", + who, 0, environment(who)); + break; + } + who->eventReceiveDamage(0, COLD, random(3) + 1, 1); + return 1; +} + diff --git a/lib/domains/Ylsrim/broken/jar.c b/lib/domains/Ylsrim/broken/jar.c new file mode 100644 index 0000000..a43cef5 --- /dev/null +++ b/lib/domains/Ylsrim/broken/jar.c @@ -0,0 +1,145 @@ +#include <lib.h> + +inherit LIB_ITEM; +inherit LIB_CLOSE; +inherit LIB_LIGHT; +inherit LIB_CAPTURE; + +int BugDies = 0; + +static void create() { + AddSave(({ "BugDies" })); + item::create(); + close::create(); + capture::create(); + light::create(); + SetKeyName("jar"); + SetId( ({ "jar" }) ); + SetShort("a jar"); + SetLong("A jar with lid. The lid has holes poked in " + "the top. It would be perfect to catch bugs in."); + SetDestroyOnSell(1); + SetMass(100); + SetValue(30); + SetClosed(1); + SetMaxCapture(1); + if( BugDies > 1 ) { + set_heart_beat(2); + } +} + +static void heart_beat() { + BugDies -= 2; + if( BugDies < 1 ) { + eventDarken(); + } +} + +int direct_light_obj() { // They cannot use the light command + return 0; +} + +mixed CanCapture(object who, object target) { + if( !target->id("lightning bug") ) { + return "The jar has a fit as you try to capture something other " + "than a lightning bug!"; + } + if( GetLit() ) { + return "You already have a lightning bug in there!"; + } + if( GetClosed() ) { + return "The jar must be open!"; + } + return 1; +} + +mixed eventCapture(object who, object target) { + mixed tmp = capture::eventCapture(who, "lightning bug"); + + if( tmp != 1 ) { + return tmp; + } + target->eventDestruct(); + who->eventPrint("You capture a lightning bug in your jar!"); + environment(who)->eventPrint(who->GetName() + " captures a lightning bug " + "with " + possessive(who) + " jar.", who); + SetLit(1); + BugDies = 360; + set_heart_beat(2); +} + +mixed eventDarken() { + object env = environment(); + + if( env ) { + env->eventPrint("The %^YELLOW%^lighning bug%^RESET%^ dies."); + } + if( living(env) && (env = environment(env)) ) { + env->eventPrint(possessive_noun(environment()->GetName()) + + " lightning bug dies and " + possessive(environment()) + + " jar goes dark.", environment()); + } + capture::eventFree("lightning bug"); + SetLit(0); + return 1; +} + +mixed eventFree(object who, string target) { + mixed tmp = capture::eventFree(target); + object bug; + + if( tmp != 1 ) { + return tmp; + } + if( GetClosed() ) { + eventOpen(who, "jar"); + } + SetLit(0); + environment(who)->eventPrint("A lightning bug flies free of the jar!"); + bug = new("/realms/ariel/wonder/monsters/lbug"); + bug->eventMove(environment(who)); + return 1; +} + +varargs mixed eventOpen(object who, string id, object tool) { + mixed tmp = close::eventOpen(who, id, tool); + + if( tmp != 1 ) { + return tmp; + } + if( sizeof(GetCaptured()) ) { + eventFree(who, "lightning bug"); + } + return 1; +} + +string GetShort() { + string tmp = item::GetShort(); + + if( GetLit() ) { + tmp += "\nIt is holding a lightning bug."; + } + if( GetClosed() ) { + tmp += "\nIt is closed."; + } + else { + tmp += "\nIt is open."; + } + return tmp; +} + +string GetLong(string str) { + string tmp = item::GetLong(); + + if( GetLit() ) { + tmp += "\nIt is glowing."; + } + if( GetClosed() ) { + tmp += "\nIt is closed."; + } + else { + tmp += "\nIt is open."; + } + return tmp; + +} diff --git a/lib/domains/Ylsrim/etc/adv_board.c b/lib/domains/Ylsrim/etc/adv_board.c new file mode 100644 index 0000000..ea974ce --- /dev/null +++ b/lib/domains/Ylsrim/etc/adv_board.c @@ -0,0 +1,21 @@ +/* /domains/Ylsrim/etc/adv_board.c + * from the Dead Souls Mud Library + * created by Rush@Dead Souls + */ + +#include <lib.h> + +inherit "/lib/bboard"; + +static void create() +{ + ::create(); + SetKeyName("bulletin board"); + SetId( ({"board", "bulletin board"}) ); + SetAdjectives("stupid"); + SetShort("a bulletin board"); + SetLong("Adventurers passing through Ylsrim post their thoughts here."); + set_board_id("ylsrim"); +} + + diff --git a/lib/domains/Ylsrim/etc/chest.c b/lib/domains/Ylsrim/etc/chest.c new file mode 100644 index 0000000..dca84c7 --- /dev/null +++ b/lib/domains/Ylsrim/etc/chest.c @@ -0,0 +1,25 @@ +/* /domains/Ylsrim/etc/chest.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 951028 + */ + +#include <lib.h> + +inherit LIB_STORAGE; + +static void create() { + storage::create(); + SetKeyName("chest"); + SetId( ({ "chest" }) ); + SetAdjectives( ({ "wooden" }) ); + SetShort("a wooden chest"); + SetLong("This chest is made from an ancient forest far from " + "Ylsrim. You can feel the age in touching it."); + SetMass(1200); + SetValue(300); + SetInventory( ([ DIR_STANDARD_DOMAIN "/etc/shovel" : -10, + DIR_STANDARD_DOMAIN "/etc/heal_scroll" : 1 ]) ); + SetCanClose(1); + SetClosed(1); + SetMaxCarry(2000); +} diff --git a/lib/domains/Ylsrim/etc/church_button.c b/lib/domains/Ylsrim/etc/church_button.c new file mode 100644 index 0000000..5f8fbca --- /dev/null +++ b/lib/domains/Ylsrim/etc/church_button.c @@ -0,0 +1,38 @@ +/* /domains/Ylsrim/etc/chuch_button.c + * From the Dead Souls Mud Library + * An example dummy item that allows pressing + * Created by Descartes of Borg 961222 + */ + +#include <lib.h> + +inherit LIB_DUMMY; // These do not show up in desc, but you can look at them +inherit LIB_PRESS; // Makes the item pressable + +int openDoor(object who) { + object door = find_object("/domains/Ylsrim/etc/church_door"); + + send_messages("press", "$agent_name $agent_verb the button.", + who, 0, environment(who)); + if( !door->GetClosed() ) { + return 1; + } + environment(who)->eventPrint("You hear a click from the door."); + if( door->GetLocked() ) { + door->SetLocked(0); + } + else { + door->SetLocked(1); + } + return 1; +} + +static void create() { + dummy::create(); + SetKeyName("button"); + SetId("button"); + SetAdjectives("big", "huge"); + SetShort("a huge button"); + SetLong("It is a wooden button that you could probably press."); + SetPress((: openDoor :)); +} diff --git a/lib/domains/Ylsrim/etc/church_door.c b/lib/domains/Ylsrim/etc/church_door.c new file mode 100644 index 0000000..f51f99d --- /dev/null +++ b/lib/domains/Ylsrim/etc/church_door.c @@ -0,0 +1,23 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("north", (["id" : ({ "door", "handsome wooden door", "wooden door" }), + "short" : "a door leading north", + "long" : "This is a plain wooden door.", + "lockable" : 1 ]) ); + + SetSide("south", (["id" : ({ "door leading into the mansion", "handsome wooden door", "wooden door", "door" }), + "short" : "a door leading south", + "long" : "This is a handsome wooden door.", + "lockable" : 1 ]) ); + + SetClosed(1); + SetLocked(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/etc/dug_hole.c b/lib/domains/Ylsrim/etc/dug_hole.c new file mode 100644 index 0000000..203c24f --- /dev/null +++ b/lib/domains/Ylsrim/etc/dug_hole.c @@ -0,0 +1,46 @@ +/* /domains/Ylsrim/etc/dug_hole.c + * From the Dead Souls Mud Library + * A door that is really a hole instead of a door + * Created by Descartes of Borg 961231 + */ + +#include <lib.h> + +inherit LIB_DOOR; + +string checkOpenDown(object who) { + if( GetClosed() ) { + return "You would need to dig a hole."; + } + else { + return "It is a deep, dark hole in the desert sand."; + } +} + +string checkOpenUp(object who) { + if( GetClosed() ) { + return "There is no hole here."; + } + else { + return "It leads into the open air."; + } +} + +mixed CanClose() { + return 0; // people should not be closing this manually +} + +mixed CanOpen() { + return 0; // people should not be opening this manually +} + +static void create() { + door::create(); + SetId("down", "hole"); + SetShort("down", "sand"); // this is what is seen when bumped into + SetLong("down", (: checkOpenDown :)); + SetId("up", "hole"); + SetShort("up", "sand"); // this is what is seen when bumped into + SetLong("up", (: checkOpenUp :)); + SetClosed(1); +} diff --git a/lib/domains/Ylsrim/etc/fighter_door.c b/lib/domains/Ylsrim/etc/fighter_door.c new file mode 100644 index 0000000..f99d76a --- /dev/null +++ b/lib/domains/Ylsrim/etc/fighter_door.c @@ -0,0 +1,26 @@ +/* /domains/Praxis/etc/basement_door.c + * from Dead Souls LPMud + * created by Descartes of Borg 951027 + */ + +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + SetId("north", "door"); + SetShort("north", "a door made from fine oak"); + SetLong("north", "It is a magnificent door marking the entrance to " + "the fighter class hall."); + SetLockable("north", 1); + SetKeys("north", "special_key_id"); + SetId("south", "door"); + SetShort("south", "a door made from fine oak"); + SetLong("south", "It is a magnificent door leading out to the recruitment " + "area."); + SetLockable("south", 1); + SetKeys("south", "special_key_id"); + SetClosed(1); + SetLocked(0); +} diff --git a/lib/domains/Ylsrim/etc/hole.c b/lib/domains/Ylsrim/etc/hole.c new file mode 100644 index 0000000..34b93dd --- /dev/null +++ b/lib/domains/Ylsrim/etc/hole.c @@ -0,0 +1,21 @@ +/* /domains/Ylsrim/etc/hole.c + * From the Dead Souls Mud Library + * An example of something people can jump into + * Created by Descartes of Borg 961222 + */ + +#include <lib.h> +#include <jump.h> // defines JUMP_INTO + +inherit LIB_DUMMY; // These do not show up in desc, but you can look at them +inherit LIB_JUMP; // This makes it jumpable + +static void create() { + dummy::create(); + SetKeyName("hole"); + SetId("hole", "bank"); + SetShort("a hole in the roof"); + SetLong("It is too dark to see inside the bank, but perhaps you could " + "jump into it?"); + AddJump("hole","/domains/Ylsrim/room/bank", JUMP_INTO); +} diff --git a/lib/domains/Ylsrim/etc/key.c b/lib/domains/Ylsrim/etc/key.c new file mode 100644 index 0000000..72b338d --- /dev/null +++ b/lib/domains/Ylsrim/etc/key.c @@ -0,0 +1,21 @@ +/* /domains/Ylsrim/etc/key.c + * from the Dead Souls Object Library + * created by Descartes of Borg 960512 + */ + +#include <lib.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("key"); + SetId( ({ "key", "special_key_id" }) ); + SetAdjectives( ({ "brilliant", "silver" }) ); + SetShort("a silver key"); + SetLong("It is a brilliant silver key with no markings."); + SetMass(50); + SetValue(15); + SetDisableChance(90); +} + diff --git a/lib/domains/Ylsrim/etc/match.c b/lib/domains/Ylsrim/etc/match.c new file mode 100644 index 0000000..0216d48 --- /dev/null +++ b/lib/domains/Ylsrim/etc/match.c @@ -0,0 +1,27 @@ +/* /domains/Praxis/etc/torch.c + * from Dead Souls LPMud + * created by Descartes of Borg 951023 + */ + +#include <lib.h> + +inherit LIB_MATCH; + +static void create() { + match::create(); + SetKeyName("match"); + SetId("match"); + SetAdjectives( ({ "wooden" }) ); + SetShort("a wooden match"); + SetLong("A wooden match that might light if you strike it."); + SetRadiantLight(2); + SetStrikeChance(50); + SetMinHeat(10); + SetFuelRequired(1); + SetMaxFuel(10); + SetFuelAmount(10); + SetRefuelable(0); + SetMass(5); + SetValue(2); + SetBurntValue(1); +} diff --git a/lib/domains/Ylsrim/etc/pole.c b/lib/domains/Ylsrim/etc/pole.c new file mode 100644 index 0000000..68b1c72 --- /dev/null +++ b/lib/domains/Ylsrim/etc/pole.c @@ -0,0 +1,30 @@ +/* /domains/Ylsrim/etc/pole.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 951009 + */ + +#include <lib.h> +#include <vendor_types.h> + +inherit LIB_POLE; +inherit LIB_ITEM; + +static void create() { + pole::create(); + item::create(); + SetKeyName("bamboo pole"); + SetId( ({ "pole", "bamboo pole", "stick" }) ); + SetAdjectives( ({ "bamboo", "feeble" }) ); + SetShort("a bamboo pole"); + SetLong("It is a feeble bamboo stick with a string at the end of it."); + SetClass(1); + SetValue(10); + SetMass(30); + SetVendorType(VT_TREASURE | VT_FISHING); + SetStrength(200); + SetChance(20); +} + +static mixed AddSave(mixed *var) { + return item::AddSave(var); +} diff --git a/lib/domains/Ylsrim/etc/road.c b/lib/domains/Ylsrim/etc/road.c new file mode 100644 index 0000000..1945ebd --- /dev/null +++ b/lib/domains/Ylsrim/etc/road.c @@ -0,0 +1,31 @@ +/* /domains/Ylsrim/etc/road.c + * From the Dead Souls Mud Library + * An example of something people can jump into + * Created by Descartes of Borg 961222 + */ + +#include <lib.h> +#include <jump.h> // defines JUMP_INTO +#include <damage_types.h> // defines BLUNT + +inherit LIB_DUMMY; // These do not show up in desc, but you can look at them +inherit LIB_JUMP; // This makes it jumpable + +int eventJump(object who) { + who->eventReceiveDamage(0, BLUNT, random(100) + 5, 1); + who->eventMoveLiving("/domains/Ylsrim/room/kaliid6", + "$N tries to jump into the road " + "and seriously hurts " + reflexive(who) + ".", + "$N comes falling in."); + return 1; +} + +static void create() { + dummy::create(); + SetKeyName("road"); + SetId("road"); + SetAdjectives("kaliid"); + SetShort("Kaliid Road", 1); // it is a proper noun + SetLong("The main road through Ylsrim."); + AddJump("road","/domains/Ylsrim/room/kaliid6",JUMP_INTO); +} diff --git a/lib/domains/Ylsrim/etc/roof.c b/lib/domains/Ylsrim/etc/roof.c new file mode 100644 index 0000000..4fa4093 --- /dev/null +++ b/lib/domains/Ylsrim/etc/roof.c @@ -0,0 +1,24 @@ +/* /domains/Ylsrim/etc/roof.c + * From the Dead Souls Mud Library + * An example of something people can jump from + * Created by Descartes of Borg 961222 + */ + +#include <lib.h> +#include <jump.h> // defines JUMP_FROM + +inherit LIB_DUMMY; // These do not show up in desc, but you can look at them +inherit LIB_JUMP; // This makes it jumpable + +static void create() { + dummy::create(); + SetKeyName("roof"); + SetId("roof"); + SetAdjectives("adobe", "bank"); + SetShort("a roof"); + SetLong("The bank roof looks over the road below. " + "Maybe you could jump into it." + "The adobe wall looks like you could climb down it. "); + //"A hole in the center of the roof opens into the bank."); + AddJump("roof","/domains/Ylsrim/room/bank", JUMP_FROM); +} diff --git a/lib/domains/Ylsrim/etc/roof_wall.c b/lib/domains/Ylsrim/etc/roof_wall.c new file mode 100644 index 0000000..43bf0f2 --- /dev/null +++ b/lib/domains/Ylsrim/etc/roof_wall.c @@ -0,0 +1,22 @@ +/* /domains/Ylsrim/etc/roof_wall.c + * From the Dead Souls Mud Library + * An example of climbing down + * Created by Descartes of Borg 961222 + */ + +#include <lib.h> +#include <climb.h> // defines CLIMB_DOWN + +inherit LIB_DUMMY; // These do not show up in desc, but you can look at them +inherit LIB_CLIMB; // This makes it climbable + +static void create() { + dummy::create(); + SetKeyName("wall"); + SetId("wall"); + SetAdjectives("adobe", "bank"); + SetShort("an adobe wall"); + SetLong("It has enough holes that you can get a good foot hold and " + "climb down it!"); + SetClimb("/domains/Ylsrim/room/kaliid6", CLIMB_DOWN); +} diff --git a/lib/domains/Ylsrim/etc/shovel.c b/lib/domains/Ylsrim/etc/shovel.c new file mode 100644 index 0000000..734e897 --- /dev/null +++ b/lib/domains/Ylsrim/etc/shovel.c @@ -0,0 +1,25 @@ +/* /domains/Ylsrim/etc/shovel.c + * From the Dead Souls Mud Library + * An example of how to code a digging tool + * Created by Descartes of Borg 961231 + */ + +#include <lib.h> + +inherit LIB_ITEM; +inherit LIB_DIG_WITH; + +static void create() { + item::create(); + SetKeyName("shovel"); + SetId("shovel", "spade"); + SetAdjectives("wooden"); + SetShort("a shovel"); + SetLong("A plain, wooden shovel. You probably can dig things with " + "it."); + SetMass(87); + SetValue(50); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/etc/stool.c b/lib/domains/Ylsrim/etc/stool.c new file mode 100644 index 0000000..a1e1873 --- /dev/null +++ b/lib/domains/Ylsrim/etc/stool.c @@ -0,0 +1,21 @@ +/* /domains/Ylsrim/etc/stool.c + * From the Dead Souls Mud Library + * An example of a chair object + * Created by Descartes of Borg 961221 + */ + +#include <lib.h> + +inherit LIB_CHAIR; + +static void create() { + chair::create(); + SetKeyName("stool"); + SetId("stool"); + SetAdjectives("wooden", "rickety"); + SetShort("a rickety wooden stool"); + SetLong("The stool is sturdy enough for you to sit in."); + SetMass(1500); + SetValue(15); + SetMaxSitters(1); +} diff --git a/lib/domains/Ylsrim/etc/torch.c b/lib/domains/Ylsrim/etc/torch.c new file mode 100644 index 0000000..3afd97d --- /dev/null +++ b/lib/domains/Ylsrim/etc/torch.c @@ -0,0 +1,27 @@ +/* /domains/Praxis/etc/torch.c + * from Dead Souls LPMud + * created by Descartes of Borg 951023 + */ + +#include <lib.h> + +inherit LIB_TORCH; + +static void create() { + torch::create(); + SetKeyName("torch"); + SetId( ({ "torch", "old torch", "wooden torch" }) ); + SetAdjectives( ({ "old", "wooden" }) ); + SetShort("an old, wooden torch"); + SetLong("An old, wooden torch with a bit of cloth wrapped around " + "one end and dipped into a flamable substance."); + SetRadiantLight(7); + SetFuelRequired(1); + SetMaxFuel(1000); + SetFuelAmount(1000); + SetRefuelable(1); + SetMass(50); + SetValue(60); + SetBurntValue(10); + SetClass(10); +} diff --git a/lib/domains/Ylsrim/etc/wall.c b/lib/domains/Ylsrim/etc/wall.c new file mode 100644 index 0000000..a8ab330 --- /dev/null +++ b/lib/domains/Ylsrim/etc/wall.c @@ -0,0 +1,22 @@ +/* /domains/Ylsrim/etc/wall.c + * From the Dead Souls Mud Library + * An example of climbing up + * Created by Descartes of Borg 961222 + */ + +#include <lib.h> +#include <climb.h> // defines CLIMB_UP + +inherit LIB_DUMMY; // These do not show up in desc, but you can look at them +inherit LIB_CLIMB; // This makes it climbable + +static void create() { + dummy::create(); + SetKeyName("wall"); + SetId("wall"); + SetAdjectives("adobe", "bank"); + SetShort("an adobe wall"); + SetLong("It has enough holes that you can get a good foot hold and " + "climb up it!"); + SetClimb("/domains/Ylsrim/room/bank_roof", CLIMB_UP); +} diff --git a/lib/domains/Ylsrim/fish/shark.c b/lib/domains/Ylsrim/fish/shark.c new file mode 100644 index 0000000..19f6286 --- /dev/null +++ b/lib/domains/Ylsrim/fish/shark.c @@ -0,0 +1,37 @@ +/* /domains/Ylsrim/fish/shark.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 960302 + */ + +#include <lib.h> +#include <dirs.h> +#include <damage_types.h> + +inherit LIB_FISH; + +void BiteMe(object who); + +static void create() { + fish::create(); + SetKeyName("blue shark"); + SetId( ({ "shark", "blue shark" }) ); + SetShort("a blue shark"); + SetLong("It is a huge, long fish with razor sharp teeth and a carnivorous " + "appetite."); + SetMass(100); + SetFight(40); + SetFood("/domains/Ylsrim"+ "/meal/shark"); +} + +int eventCatch(object who, object pole) { + call_out((: BiteMe, who :), 0); + return 1; +} + +void BiteMe(object who) { + who->eventPrint("The shark bites you before it dies!"); + environment(who)->eventPrint("The shark bites " + who->GetName() + + " before it dies!", who); + who->eventReceiveDamage(this_object(), KNIFE, random(20), 0, + who->GetRandomLimb("right hand")); +} diff --git a/lib/domains/Ylsrim/meal/ale.c b/lib/domains/Ylsrim/meal/ale.c new file mode 100644 index 0000000..771fa44 --- /dev/null +++ b/lib/domains/Ylsrim/meal/ale.c @@ -0,0 +1,29 @@ +/* /domains/Ylsrim/meal/ale.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 960302 + */ + +#include <lib.h> +#include <meal_types.h> + +inherit LIB_MEAL; + +static void create() { + meal::create(); + SetKeyName("ale"); + SetId( ({ "bottle", "ale", "ylsrim ale" }) ); + SetShort("a bottle of ale"); + SetLong("A nice bottle of Lars' famous Ylsrim Ale."); + SetMass(60); + SetBaseCost("electrum", 20); + SetMealType(MEAL_DRINK | MEAL_ALCOHOL); + SetStrength(10); + SetMealMessages("You drink a wonderful bottle of Ylsrim Ale.", + "$N drinks a wonderful bottle of Ylsrim Ale."); + SetEmptyName("bottle"); + SetEmptyShort("an empty bottle of Ylsrim Ale"); + SetEmptyLong("It is an empty brown bottle that once held some ale."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/meal/shark.c b/lib/domains/Ylsrim/meal/shark.c new file mode 100644 index 0000000..1386b0f --- /dev/null +++ b/lib/domains/Ylsrim/meal/shark.c @@ -0,0 +1,22 @@ +/* /domains/Ylsrim/meal/shark.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 960302 + */ + +#include <lib.h> +#include <meal_types.h> + +inherit LIB_MEAL; + +static void create() { + meal::create(); + SetKeyName("shark"); + SetId( ({ "blue shark", "shark", "fish" }) ); + SetAdjectives( ({ "blue" }) ); + SetShort("a blue shark"); + SetLong("A blue shark who once looked deadly, now looks yummy."); + SetMass(100); + SetMealType(MEAL_FOOD); + SetStrength(25); + SetMealMessages("It tastes excellent.", "$N eats a blue shark."); +} diff --git a/lib/domains/Ylsrim/meal/stew.c b/lib/domains/Ylsrim/meal/stew.c new file mode 100644 index 0000000..f4cdf78 --- /dev/null +++ b/lib/domains/Ylsrim/meal/stew.c @@ -0,0 +1,24 @@ +/* /domains/Ylsrim/meal/stew.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 960302 + */ + +#include <lib.h> +#include <meal_types.h> + +inherit LIB_MEAL; + +static void create() { + meal::create(); + SetKeyName("elven stew"); + SetId( ({ "stew" }) ); + SetAdjectives( ({ "elven" }) ); + SetShort("some hot elven stew"); + SetLong("This stew is made from the left-overs of other dishes served at " + "Toral Restaurant."); + SetMass(10); + SetMealType(MEAL_FOOD); + SetStrength(3); + SetMealMessages("The stew clears your sinuses!", + "$N perks up after eating some elven stew."); +} diff --git a/lib/domains/Ylsrim/npc/balrog.c b/lib/domains/Ylsrim/npc/balrog.c new file mode 100644 index 0000000..cf70b7f --- /dev/null +++ b/lib/domains/Ylsrim/npc/balrog.c @@ -0,0 +1,27 @@ +/* /domains/Ylsrim/npc/balrog.c + * From the Dead Souls Mud Library + * An example simple NPC + * Created by Descartes of Borg 960302 + */ + +#include <lib.h> + +inherit LIB_NPC; + +static void create() { + npc::create(); + SetKeyName("balrog"); + SetId("balrog"); + SetAdjectives("wicked", "ugly"); + SetShort("a wicked balrog"); + SetLong("Balrogs are an ugly sort that hide out among the many " + "crevices and canyons in the mountains. This one is " + "extremely tall, and evidently not all too pleased to see you."); + SetLevel(8); // level, race, and class determine NPC's power + SetRace("balrog"); // must be some valid race from mraces command + SetClass("fighter"); // needs a class! + SetGender("male"); + SetEncounter(80); + SetMorality(-800); // -2000 absolute evil, 2000 absolute good + SetAction(5, ({ "!growl" })); // Make him growl every now and then +} diff --git a/lib/domains/Ylsrim/npc/lars.c b/lib/domains/Ylsrim/npc/lars.c new file mode 100644 index 0000000..37eeff5 --- /dev/null +++ b/lib/domains/Ylsrim/npc/lars.c @@ -0,0 +1,40 @@ +/* /domains/Ylsrim/npc/lars.c + * From the Dead Souls Mud Library + * An example barkeeper + * Created by Descartes of Borg 960302 + */ + +#include <lib.h> +#include <dirs.h> + +inherit LIB_BARKEEP; + +static void create() { + barkeep::create(); + SetKeyName("lars"); + SetId("lars", "owner", "barkeep", "bartender", "keeper"); + SetShort("Lars, the keeper of Lars' Pub"); + SetLevel(12); + SetLong("Lars is the owner of Lars' Pub, and old, famous " + "drinking establishment in the heart of the Ylsrim Bazaar. " + "He is an unassuming elf, but quite jovial. You may ask him to " + "serve whatever drinks are on his menu."); + SetGender("male"); + SetMorality(40); + SetRace("elf"); + SetClass("fighter"); + AddCurrency("electrum", random(200)); + // How good a barkeep is he? + SetSkill("bargaining", 150); + // Keep him in the pub + SetProperty("no bump", 1); + // He takes electrum + SetLocalCurrency("electrum"); + // What he sells + SetMenuItems(([ + ({ "ale", "beer" }) : "/domains/Ylsrim/meal/ale", + ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/npc/max.c b/lib/domains/Ylsrim/npc/max.c new file mode 100644 index 0000000..be8ce22 --- /dev/null +++ b/lib/domains/Ylsrim/npc/max.c @@ -0,0 +1,33 @@ +/* /domains/Ylsrim/npc/max.c + * From the Dead Souls Mud Library + * An example vendor + * Created by Descartes of Borg 960302 + */ + +#include <lib.h> +#include <vendor_types.h> + +inherit LIB_VENDOR; + +static void create() { + vendor::create(); + SetKeyName("max"); + SetId("max", "vendor", "shop keeper", "keeper", "shopkeeper"); + SetShort("Max, the local armorer"); + SetLong("He buys and sells goods for armors."); + SetLevel(15); + SetRace( "elf"); + SetGender("male"); + SetMorality(40); + AddCurrency("electrum", random(200)); + // Define the place where he stores stuff to sell + SetStorageRoom("/domains/Ylsrim"+ "/room/armory_storage"); + // How good a vendor is he? Should be 100+ + SetSkill("bargaining", 110); + // He should stay in his shop + SetProperty("no bump", 1); + // He accepts electrum + SetLocalCurrency("electrum"); + // He sells armors + SetVendorType(VT_ARMOR); +} diff --git a/lib/domains/Ylsrim/npc/priest.c b/lib/domains/Ylsrim/npc/priest.c new file mode 100644 index 0000000..ed4e2be --- /dev/null +++ b/lib/domains/Ylsrim/npc/priest.c @@ -0,0 +1,32 @@ +/* /domains/Ylsrim/npc/priest.c + * From the Dead Souls Mud Library + * An example of a religious class leader + * Created by Descartes of Borg 961222 + */ + +#include <lib.h> + +inherit LIB_LEADER; + +static void create() { + leader::create(); + SetKeyName("ixtala"); + SetId("ixtala", "priest"); + SetShort("Ix'Tala, high priestess of the Priests"); + SetLong("Ix'Tala initiates priests into the Priests class as well as " + "converts the wayward to the truth of the Dalin religion. " + "To learn more about becoming a priest " + "ask her to \"describe priests\". If you choose to become " + "a priest, ask her to \"join priests\". Of course, you can " + "convert by asking her to \"convert me\"."); + SetLevel(45); + SetRace("klingon"); + SetClass("cleric"); + SetGender("female"); + SetMorality(400); + SetReligion("Dalin", "Dalite"); + SetProperty("no bump", 1); + if( clonep() ) { + AddChannel("priest"); + } +} diff --git a/lib/domains/Ylsrim/npc/roshd.c b/lib/domains/Ylsrim/npc/roshd.c new file mode 100644 index 0000000..7ae6277 --- /dev/null +++ b/lib/domains/Ylsrim/npc/roshd.c @@ -0,0 +1,197 @@ +/* /domains/Ylsrim/npc/fighter.c + * From the Dead Souls Mud Library + * An example class leader + * Created by Lassondra@Dead Souls + */ + +#include <lib.h> +inherit LIB_TRAINER; + +static string save_file = save_file("/domains/Ylsrim/save/roshd"); +static string quest_object = "/domains/town/armor/orc_helmet"; +string *ok_join = ({}); + +int JoinGuild(object ob, string verb, string what); +int TeachFeat(object who, string verb, string feat); +int AllowPass(object who, object what){ + if(who->GetClass() == "fighter") return 1; + return ::AllowPass(who, what); +} + +int CheckVisitor(object who){ + eventForce("say Only fighters are allowed there!"); + return 1; +} + +static void create() { + trainer::create(); + RestoreObject(save_file); + if(!ok_join) ok_join = ({}); + SetKeyName("roshd burlyneck"); + SetId("roshd", "roshd burlyneck"); + SetShort("Roshd Burlyneck, Master Warrior"); + SetLong("Roshd Burlyneck is the master warrior of " + "the fighters. Immense in size, Roshd stands well " + "over seven feet tall. Long brown hair streams " + "out behind him, and his biceps are so large " + "it would take several hand spans to fit around " + "them. Roshd's armor is worn and covered in dirt " + "as if he has just returned from combat. " + "Roshd initiates new members into the ways of " + "combat. If you choose to become " + "a fighter, \"ask roshd to join\".\n\nDespite his " + "devotion to his guild, Roshd will train outsiders in " + "combat skills, if they are capable. For example: \"ask " + "roshd to train blunt defense\""); + SetRace("orc"); + SetClass("fighter"); + SetLevel(45); + SetGender("male"); + SetMorality(-400); + SetProperty("no bump", 1); + SetGuard("north", (: CheckVisitor :)); + //SetLanguage("Common", 100); + //SetDefaultLanguage("Common"); + SetNoSpells(1); + AddTrainingSkills(({"multi-weapon","multi-hand","blunt attack","blunt defense","blade attack","blade defense","knife attack","knife defense"})); + // stick him on the fighter line + if( clonep() ) { + AddChannel("fighter"); + } + SetCommandResponses( ([ + "train" : (: eventTrain :), + "teach" : (: eventTrain :), + "default" : (: eventHelp :), + "help" : (: eventHelp :), + "join" : (: JoinGuild :), + ]) ); + AddRequestResponses( ([ + "help" : (: eventHelp :), + ]) ); +} + +int JoinGuild(object ob, string verb, string what){ + string keyname = ob->GetKeyName(); + string name = ob->GetName(); + if(ob->GetClass() == "fighter") { + eventForce("say You're already in, genius."); + return 1; + } + eventForce("say Hmm...want to join our guild, do you?"); + + if(member_array(keyname, ok_join) == -1){ + eventForce("say First you must prove yourself worthy. Bring me " + "the skull helmet stolen by the wannabe orc shaman and I will " + "deem you fit to join our family. Until then, you may not join " + "the fighters."); + return 1; + } + if(ob->GetClass() == "explorer" || !ob->GetClass()){ + eventForce("say very well, "+ob->GetName()+"."); + ob->ChangeClass("fighter"); + eventForce("say Welcome to the fighters' guild! You now have " + "access to training in special skills designed to make you into " + "a fine and respectable meat shield!"); + eventForce("laugh"); + eventForce("say For weapon based training, come to me. For melee " + "skills, also known as unarmed combat, see our martial artist " + "trainer in the room north of here."); + return 1; + } + eventForce("say I'm sorry, it looks to me like you have already chosen your + specialty. As a member of the Guildmasters' Guild, I am forbidden from removing + you from the "+capitalize(ob->GetClass())+"'s Guild."); + return 1; +} + +int CompleteQuest2(object ob){ + string *quests; + object hat = present_file("/domains/town/armor/orc_helmet", this_object()); + quests = ob->GetQuests(); + if(!ob->GetQuest("Orc Master Quest")){ + ob->AddQuest("the Orc Master","Orc Master Quest"); + eventForce("say You have solved the Orc Master Quest. Congratulations!"); + eventForce("say I hereby award you 7 quest points, and 2000 experience points!"); + ob->AddQuestPoints(7); + ob->AddExperiencePoints(2000); + if(hat) hat->eventDestruct(); + reload("/domains/town/room/valley",0,1); + reload("/domains/town/room/orc_fortress",0,1); + reload("/domains/town/room/orc_temple",0,1); + } + return 1; +} + +int eventReceiveObject(object foo){ + int ret; + object ob, player; + ob = previous_object(); + player = this_player(); + + if( !ob || !(ret = ::eventReceiveObject(foo)) ) return 0; + if(base_name(ob) == quest_object){ + call_out("EnableJoin", 0, player, ob); + } + if(base_name(ob) == "/domains/cave/obj/letter" && interactive(player)){ + call_out("CompleteQuest", 0, player); + } + return ret; +} + +mixed EnableJoin(object player, object thing){ + string uname = thing->GetUniqueId(); + string name, keyname; + if(!player) return 0; + keyname = player->GetKeyName(); + if(member_array(keyname, ok_join) == -1){ + name = lower_case(player->GetName()); + ok_join += ({ keyname }); + SaveObject(save_file,1); + if(name != keyname) keyname = capitalize(name); + if(sizeof(present_file(quest_object, this_object(), 1)) > 1){ + eventForce("say Nice. I'm all set for now, though, so "+ + "you can have this back."); + eventForce("give "+uname+" to "+player->GetKeyName()); + } + else { + eventForce("say Thanks, "+keyname+". It's just what I wanted."); + eventForce("wear "+uname); + } + if(player->GetClass() != "fighter"){ + eventForce("say If you want, you may now ask to join the "+ + "fighter's guild: ask roshd to join"); + } + call_out("CompleteQuest2", 0, player); + } + else { + eventForce("say I think we went through this already."); + eventForce("give "+uname+" to "+player->GetKeyName()); + } + return 1; +} + +int CompleteQuest(object ob){ + string *quests; + object letter = present("kletter", this_object()); + quests = ob->GetQuests(); + if(!ob->GetQuest("A Soldier's Lament")){ + ob->AddQuest("the Postman","A Soldier's Lament"); + eventForce("read letter"); + eventForce("cry"); + eventForce("say However you got this, I thank you, and Kasatka thanks you.") + ; + eventForce("say I hereby award you 5 quest points, and 800 experience + points."); + ob->AddQuestPoints(5); + ob->AddExperiencePoints(800); + if(letter) letter->eventDestruct(); + reload("/domains/cave/room/kurogane",0,1); + } + return 1; +} + +void init(){ + ::init(); +} + + diff --git a/lib/domains/Ylsrim/npc/segata.c b/lib/domains/Ylsrim/npc/segata.c new file mode 100644 index 0000000..cda4297 --- /dev/null +++ b/lib/domains/Ylsrim/npc/segata.c @@ -0,0 +1,32 @@ +#include <lib.h> +#include <objects.h> + +inherit LIB_TRAINER; +void create(){ + trainer::create(); + SetKeyName("segata"); + SetId(({"segata", "sanshiro", "segata sanshiro"})); + SetAdjectives(({"stocky","built","strong","strongly built"})); + SetGender("male"); + SetRace("human"); + SetShort("Segata Sanshiro"); + SetLong("Stocky and strongly built, this legendary master of " + "martial arts helps train fighters to become the very best " + "they can be, so that they may fulfill their duty. Segata " + "Sanshiro specializes in melee (unarmed) combat. For armed " + "combat training, guildmaster Roshd is still the trainer."); + SetClass("fighter"); + SetLevel(40); + AddTrainingSkills( ({ "melee attack", "melee defense" }) ); + SetSkill("melee attack", 100); + SetSkill("melee defense", 100); + SetPolyglot(1); + SetLanguage("Common", 100); + SetDefaultLanguage("Common"); + SetGuard("/domains/Ylsrim/obj/cask","Segata Sanshiro prevents your theft."); + SetUnique(1); +} + +void init() { + trainer::init(); +} diff --git a/lib/domains/Ylsrim/npc/shiela.c b/lib/domains/Ylsrim/npc/shiela.c new file mode 100644 index 0000000..14e4804 --- /dev/null +++ b/lib/domains/Ylsrim/npc/shiela.c @@ -0,0 +1,35 @@ +/* /domains/Ylsrim/npc/shiela.c + * From the Dead Souls Mud Library + * An example vendor. + * Created by Descartes of Borg 960302 + */ + +#include <lib.h> +#include <vendor_types.h> // defines VT_WEAPON + +inherit LIB_VENDOR; + +static void create() { + vendor::create(); + SetKeyName("shiela"); + SetId("shiela", "vendor", "shop keeper", "keeper", "shopkeeper"); + SetShort("Shiela, the local weapon vendor"); + SetLong("She buys and sells weapons."); + SetLevel(15); + SetRace( "human"); + SetGender("female"); + SetMorality(40); + SetListen("She has a very gruff voice."); + AddCurrency("electrum", random(200)); + // the room where she stores stuff to sell + SetStorageRoom("/domains/Ylsrim"+ "/room/weaponry_storage"); + // How good is she at being a vendor? Should be 100+ + SetSkill("bargaining", 150); + // This vendor belongs in a particular shop, don't bump her + SetProperty("no bump", 1); + // She takes electrum coins + SetLocalCurrency("electrum"); + // She buys weapons + SetVendorType(VT_WEAPON); +} + diff --git a/lib/domains/Ylsrim/npc/traveler.c b/lib/domains/Ylsrim/npc/traveler.c new file mode 100644 index 0000000..42f30f0 --- /dev/null +++ b/lib/domains/Ylsrim/npc/traveler.c @@ -0,0 +1,84 @@ +/* /domains/Ylsrim/npc/traveller.c + * From the Dead Souls Mud Library + * An example of a wandering sentient who steals + * Created by Descartes of Borg 960302 + */ + +#include <lib.h> + +inherit LIB_SENTIENT; + +// This steal function will get called randomly as set up in +// the SetAction() function in create(). It checks to see if +// someone is around from whom this guy can steal + +static void Steal() { + object array obs; + object target; + string cmd; + int i; + + if( !environment() ) { + return; + } + // Find all living things that are not me in the same room as me + obs = filter(all_inventory(environment()), + (: living($1) && $1 != this_object() :)); + i = sizeof(obs); + if( i == 0 ) { // no one to steal from + return; + } + if( i != 1 ) { // many potential targets + // pick one + i = random(i); + } + else { // only oone target, so pick obs[0] + i = 0; + } + target = obs[i]; + // Find all items on the target that can be stolen + obs = filter(all_inventory(target), + (: !($1->GetProperty("no steal")) :)); + i = sizeof(obs); + if( i == 0 ) { // no goods, let's try to get some cash + cmd = "pick " + target->GetKeyName(); + } + else { // heh, some goodies + if( i != 1 ) { // many goodies + // pick one + i = random(i); + } + else { + i = 0; + } + cmd = "steal " + obs[i]->GetKeyName() + " from " + + target->GetKeyName(); + } + // now do the steal or pick + eventForce(cmd); +} +static void create() { + sentient::create(); + SetKeyName("traveler"); + SetId( ({"traveller", "human", "npc"}) ); + SetShort("a traveler"); + SetLong("He looks a bit worn down, but also a bit shifty."); + SetLevel(5); + SetRace("human"); + SetClass("fighter"); + SetGender("male"); + SetMorality(-200); + AddCurrency("electrum", 1 + random(100)); + SetInventory(([ "/domains/Ylsrim/armor/leather_armor" : "wear armor" ])); + // Check if he can steal at a 5% chance/heart beat + SetAction(5, (: Steal :)); + // Don't want him getting cloned all over the place + SetUnique(1); + // Set him to wander + SetWander(25); + // Any time he hears the word dork, he goes ballistic! + SetTalkResponses(([ "dork" : "no, YOU are a dork!" ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/npc/traveller.c b/lib/domains/Ylsrim/npc/traveller.c new file mode 100644 index 0000000..42f30f0 --- /dev/null +++ b/lib/domains/Ylsrim/npc/traveller.c @@ -0,0 +1,84 @@ +/* /domains/Ylsrim/npc/traveller.c + * From the Dead Souls Mud Library + * An example of a wandering sentient who steals + * Created by Descartes of Borg 960302 + */ + +#include <lib.h> + +inherit LIB_SENTIENT; + +// This steal function will get called randomly as set up in +// the SetAction() function in create(). It checks to see if +// someone is around from whom this guy can steal + +static void Steal() { + object array obs; + object target; + string cmd; + int i; + + if( !environment() ) { + return; + } + // Find all living things that are not me in the same room as me + obs = filter(all_inventory(environment()), + (: living($1) && $1 != this_object() :)); + i = sizeof(obs); + if( i == 0 ) { // no one to steal from + return; + } + if( i != 1 ) { // many potential targets + // pick one + i = random(i); + } + else { // only oone target, so pick obs[0] + i = 0; + } + target = obs[i]; + // Find all items on the target that can be stolen + obs = filter(all_inventory(target), + (: !($1->GetProperty("no steal")) :)); + i = sizeof(obs); + if( i == 0 ) { // no goods, let's try to get some cash + cmd = "pick " + target->GetKeyName(); + } + else { // heh, some goodies + if( i != 1 ) { // many goodies + // pick one + i = random(i); + } + else { + i = 0; + } + cmd = "steal " + obs[i]->GetKeyName() + " from " + + target->GetKeyName(); + } + // now do the steal or pick + eventForce(cmd); +} +static void create() { + sentient::create(); + SetKeyName("traveler"); + SetId( ({"traveller", "human", "npc"}) ); + SetShort("a traveler"); + SetLong("He looks a bit worn down, but also a bit shifty."); + SetLevel(5); + SetRace("human"); + SetClass("fighter"); + SetGender("male"); + SetMorality(-200); + AddCurrency("electrum", 1 + random(100)); + SetInventory(([ "/domains/Ylsrim/armor/leather_armor" : "wear armor" ])); + // Check if he can steal at a 5% chance/heart beat + SetAction(5, (: Steal :)); + // Don't want him getting cloned all over the place + SetUnique(1); + // Set him to wander + SetWander(25); + // Any time he hears the word dork, he goes ballistic! + SetTalkResponses(([ "dork" : "no, YOU are a dork!" ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/obj/cask.c b/lib/domains/Ylsrim/obj/cask.c new file mode 100644 index 0000000..66f67d3 --- /dev/null +++ b/lib/domains/Ylsrim/obj/cask.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> +inherit LIB_FLASK; + +void create(){ + ::create(); + SetKeyName("cask"); + SetId( ({"cask","keg"}) ); + SetAdjectives( ({"large","wooden","wood"}) ); + SetShort("a wooden cask"); + SetLong("A large wooden cask for containing fluids."); + SetMass(2000); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetFlaskContents("wine"); + SetFlaskUses(100); + SetStrength(10); + SetMaxFlask(100); + SetMealType(MEAL_ALCOHOL); + SetUnique(1); + SetTapped(1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/obj/stargate.c b/lib/domains/Ylsrim/obj/stargate.c new file mode 100644 index 0000000..550e749 --- /dev/null +++ b/lib/domains/Ylsrim/obj/stargate.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include <daemons.h> +#include "/lib/include/stargate.h" + +inherit LIB_STARGATE; + +int ReadScreen(); + +void create() +{ + ::create(); + SetOrigin("tower", "/domains/Ylsrim/room/tower"); + SetRead(([ ({ "screen" }) : (: ReadScreen :) ]) ); + SetItems(([ ({ "screen" }) : "a computer screen which shows the status of the gate network" ]) ); +} + +void init() +{ + ::init(); +} + +int ReadScreen() +{ + write("stargate network status\n"); + write("-----------------------\n"); + write("\n"); + +} diff --git a/lib/domains/Ylsrim/room/adv_hall.c b/lib/domains/Ylsrim/room/adv_hall.c new file mode 100644 index 0000000..c410b89 --- /dev/null +++ b/lib/domains/Ylsrim/room/adv_hall.c @@ -0,0 +1,33 @@ +/* /domains/Ylsrim/room/adv_hall.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 960302 + */ + +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + object ob; + + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("the adventurer's hall"); + SetLong("A bulletin board sits in the middle of this circular room where " + "adventurers from all over gather to meet one another. Kaliid Road " + "lies to the south. Stairs lead up to the tower."); + SetItems( ([ "stairs" : "They spiral up into the tower which looks over " + "Kaliid Road.", + "tower" : "You can't see much in the darkness into which the " + "stairs disappear." ])); + SetExits( ([ + "up" : "/domains/Ylsrim/room/"+ "tower", + "south" : "/domains/Ylsrim/room/"+ "kaliid4" ]) ); + ob = new("/domains/Ylsrim/etc/adv_board"); + ob->set_max_posts(30); + ob->eventMove(this_object()); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/room/armory.c b/lib/domains/Ylsrim/room/armory.c new file mode 100644 index 0000000..2a8e6d5 --- /dev/null +++ b/lib/domains/Ylsrim/room/armory.c @@ -0,0 +1,59 @@ +/* /domains/Ylsrim/room/armory.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 951023 + */ + +#include <lib.h> +#include <dirs.h> + +inherit LIB_ROOM; + +string CheckOpen(string str); +string CheckItem(string str); + +static void create() { + room::create(); + SetTown("Ylsrim"); + SetClimate("indoors"); + SetAmbientLight(27); + SetShort("the Ylsrim armory"); + SetLong((: CheckOpen :)); + SetItems( ([ ({ "case", "cases" }) : (: CheckItem :), + "bazaar" : "People from all about are wandering around, looking " + "for a bargain." ]) ); + SetObviousExits("west"); + SetExits( ([ "west" : "/domains/Ylsrim/room/"+ "bazaar" ]) ); + SetInventory( ([ "/domains/Ylsrim"+ "/npc/max" : 1 ]) ); +} + +string CheckOpen(string str) { + object ob; + + ob = present("vendor"); + if( query_night() ) { + if( ob ) ob->eventDestruct(); + return ("The cases of the armory are empty, as the armory " + "has closed for the night. The bazaar is " + "west."); + } + if( !ob ) + return ("Fresh blood is splattered across broken cases which once " + "housed display armor sold in this armory. The armor is " + "gone, and the vendor clearly murdered. All you can do is " + "shake your head and exit to the west."); + return ("Sealed cases contain display armor, exemplifying what the local " + "vendor, Max, has to offer. He buys and sells all sorts of " + "armor from adventurers who come here to sell of their " + "discovered goods, or equip to continue adventuring. An exit " + "is west."); +} + +string CheckItem(string str) { + if( query_night() ) return "They are empty."; + else if ( present("vendor") ) return "They are filled with armor."; + else return "They are broken and covered in blood."; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/room/armory_storage.c b/lib/domains/Ylsrim/room/armory_storage.c new file mode 100644 index 0000000..a44c87a --- /dev/null +++ b/lib/domains/Ylsrim/room/armory_storage.c @@ -0,0 +1,28 @@ +/* /domains/Ylsrim/room/armory_storage.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 960302 + */ + +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetNoClean(1); + SetTown("Ylsrim"); + SetProperties( ([ "login" : "/domains/Ylsrim/room/"+ "armory" ]) ); + SetClimate("indoors"); + SetShort("armory storage"); + SetLong("Armory storage."); + SetObviousExits("west"); + SetExits( ([ "west" : "/domains/Ylsrim/room/"+ "armory" ]) ); +} + +int CanReceive(object ob) { + if( !living(ob) || creatorp(ob) ) return room::CanReceive(ob); + else return 0; +} +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/room/bank_roof.c b/lib/domains/Ylsrim/room/bank_roof.c new file mode 100644 index 0000000..72df47f --- /dev/null +++ b/lib/domains/Ylsrim/room/bank_roof.c @@ -0,0 +1,35 @@ +/* /domains/Ylsrim/room/bank_room.c + * From the Dead Souls Mud Library + * An example of a room with an item that allows jumping and climbing + * Created by Descartes of Borg 961010 + */ + +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetTown("Ylsrim"); + SetClimate("arid"); + SetAmbientLight(30); + SetShort("The roof of the Bank of Ylsrim"); + SetDayLong("From your perfect vantage point atop the hot adobe of " + "the Bank of Ylsrim you can see nearly the entire desert " + "town. On the south side of the bank, the wall is rough " + "enough to get a foothold down into Kaliid Road. The wall " + "on the other sides of the building are simply too smooth to " + "climb down. You might be able to jump into the road, as well."); + SetNightLong("The lights of Ylsrim look beautiful from this vantage " + "on the bank roof."); + AddItem("adobe", "The walls and roof are made of this substance."); + // this is the wall that can be climbed down + AddItem(new("/domains/Ylsrim/etc/roof_wall")); + // this is the road that people can jump into + AddItem(new("/domains/Ylsrim/etc/road")); + // this is the roof people can jump from + AddItem(new("/domains/Ylsrim/etc/roof")); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/room/bazaar.c b/lib/domains/Ylsrim/room/bazaar.c new file mode 100644 index 0000000..d6b5057 --- /dev/null +++ b/lib/domains/Ylsrim/room/bazaar.c @@ -0,0 +1,91 @@ +/* /domains/Ylsrim/room/bazaar.c + * From the Dead Souls Mud Library + * An example of a simple room + * created by Descartes of Borg 950928 + */ + +#include <lib.h> + +inherit LIB_ROOM; + +int ReadSign() { + this_player()->more("/domains/town/txt/warning_sign.txt"); + return 1; +} + +static void create() { + object ob; // this will be used to create dummy items + + // setup the stuff you inherit + room::create(); + // set the town, as native Ylsrimites can do special things in Ylsrim + SetTown("Ylsrim"); + // the climate in Ylsrim is arid because it is a desert town + SetClimate("arid"); + // the is the amount of light the street lamps make at night + SetAmbientLight(30); + // the obvious exits tell people how to leave the room + // set the sounds people hear + SetListen("Vendors are begging you to come look at their goods."); + // set the short description... should not be capitalized + SetShort("the central bazaar of Ylsrim"); + // this is the description people see at day + SetDayLong("Shops and vendors selling all types of goods fill " + "the central bazaar of Ylsrim. Local villagers and " + "exotic travellers are passing about you in search of a " + "bargain, or even in some cases, in search of trouble. " + "Kaliid Road crosses Ylsrim from the west to the east just " + "north of you, with an armory and a weapon shop straddling " + "both sides of the bazaar. The bazaar stretches on south." + "\n%^RED%^There is a sign here you can read.%^RESET%^"); + SetSkyDomain("town"); + // this is the description people see at night + SetNightLong("Though most areas of Ylsrim are peaceful right now, " + "the central bazaar is still filled with people doing " + "business, even though most of the shops are closed. " + "Kaliid Road is just north of here, and a closed armory " + "and weapons shop sit on both sides of the bazaar. " + "The bazaar stretches south." + "\n%^RED%^There is a sign here you can read.%^RESET%^"); + // set up dummy items... the first few are simple + AddItem(({ "villager", "traveller" }), + "Both villagers and travellers are out looking for good " + "deals."); + AddItem(({ "sign"}), "A sign. To read it, 'read sign'."); + AddItem(({ "road" }), "It leads through Ylsrim from the Great Desert " + "in the west towards more fertile land east.", ({ "kaliid" })); + // people need to enter the armory, so we need to do something special + // first create an armory dummy item + SetRead("sign", (: ReadSign :) ); + ob = new(LIB_DUMMY, ({ "armory", "shop" }), + function(string str) { + if( query_night() ) { + return "It is closed."; + } + else { + return "It is open."; + } + }, ({ "armor" })); + // set it so when people 'enter armory', they move to the armory + ob->SetEnter("/domains/Ylsrim/room/"+ "armory"); + // now add it as an item + AddItem(ob); + // do the same stuff for the weaponry + ob = new(LIB_DUMMY, ({ "weaponry", "shop" }), + function(string str) { + if( query_night() ) { + return "It is closed."; + } + else { + return "It is open."; + } + }, ({ "weapon" })); + ob->SetEnter("/domains/Ylsrim/room/"+ "weaponry"); + AddItem(ob); + // set the directional exits + SetExits( ([ "north" : "/domains/Ylsrim/room/"+ "kaliid4", + "south" : "/domains/Ylsrim/room/"+ "s_bazaar" ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/room/church.c b/lib/domains/Ylsrim/room/church.c new file mode 100644 index 0000000..554833e --- /dev/null +++ b/lib/domains/Ylsrim/room/church.c @@ -0,0 +1,46 @@ +/* /domains/Ylsrim/room/church + * From the Dead Souls Mud Library + * An example of a religious class hall + * Created by Descartes of Borg 961222 + */ + +#include <lib.h> + +inherit LIB_ROOM; + +int CheckPriest(string dir) { + object ob; + + if( this_player()->ClassMember("cleric") || creatorp(this_player()) ) { + return 1; + } + if( ob = present("cleric", this_object()) ) { + ob->eventForce("speak I cannot allow you in this sacred rooms."); + return 0; + } + else { + return 1; + } +} + +static void create() { + room::create(); + SetNoClean(1); + SetTown("Ylsrim"); + SetClimate("indoors"); + SetAmbientLight(27); + SetShort("Ylsrim Church"); + SetLong("Dim candles create more than enough light to fill this " + "very humble church of the Dalin religion. Dalites come " + "here to pray, and others come to convert to Dalin."); + AddItem("candle", "They do not appear to make much light, but the " + "church is very bright.", ({ "dim" })); + AddItem(new("/domains/Ylsrim/etc/church_button")); + SetExits(([ + "south" : "/domains/Ylsrim/room/"+ "kaliid3"])); + SetDoor("south", "/domains/Ylsrim/etc/church_door"); + SetInventory(([ "/domains/Ylsrim/npc/priest" : 1 ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/room/fighter.c b/lib/domains/Ylsrim/room/fighter.c new file mode 100644 index 0000000..57fb81c --- /dev/null +++ b/lib/domains/Ylsrim/room/fighter.c @@ -0,0 +1,36 @@ +/* /domains/Ylsrim/room/fighter.c + * from the Dead Souls Object Library + * created by Descartes of Borg 960512 + */ + +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetNoClean(1); + SetTown("Ylsrim"); + SetClimate("indoors"); + SetAmbientLight(40); + SetShort("the interior chamber of the Hall of Fighters"); + SetLong("Fighters gather here to drink, boast, and train. They also " + "leave helpful weapons and items here for each other, because " + "they know this is a sanctuary from the loss of objects when " + "the world renews itself."); + SetExits( ([ + "south" : "/domains/Ylsrim/room/"+ "fighter_hall", + ]) ); + SetInventory( ([ + "/domains/Ylsrim/obj/cask" : ({ 900, 1 }), + "/domains/Ylsrim/npc/segata" : ({ 300, 1 }), + ]) ); + SetDoor( "south", "/domains/Ylsrim/etc/fighter_door.c"); + SetNoClean(1); + SetPersistent(1); + RestoreObject(); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/room/fighter_hall.c b/lib/domains/Ylsrim/room/fighter_hall.c new file mode 100644 index 0000000..4a18cc3 --- /dev/null +++ b/lib/domains/Ylsrim/room/fighter_hall.c @@ -0,0 +1,35 @@ +/* /domains/Ylsrim/room/fighter_hall + * from the Dead Souls Object Library + * created by Descartes of Borg 960512 + */ + +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetNoClean(1); + SetTown("Ylsrim"); + SetClimate("indoors"); + SetAmbientLight(27); + SetShort("the Hall of Fighters"); + SetLong("The Great Hall of Fighters was constructed many ages ago to " + "act as a meeting place for all the fighters who come through " + "Ylsrim. In addition, it serves as a place to recruit new " + "fighters into the fold. A magnificent oak door stands north."); + SetExits( ([ + "north" : "/domains/Ylsrim/room/fighter", + "south" : "/domains/Ylsrim/room/kaliid5", + ]) ); + SetInventory(([ "/domains/Ylsrim/npc/roshd" : 1 ])); + SetItems( ([ + ({ "meeting","room","hall","fighter hall" }) : + "New adventurers may become fighters here.", + ]) ); + SetDoor( "north", "/domains/Ylsrim/etc/fighter_door"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/room/furnace.c b/lib/domains/Ylsrim/room/furnace.c new file mode 100644 index 0000000..240341a --- /dev/null +++ b/lib/domains/Ylsrim/room/furnace.c @@ -0,0 +1,10 @@ +#include <lib.h> + +inherit LIB_FURNACE; + +void create() { + furnace::create(); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/room/kaliid3.c b/lib/domains/Ylsrim/room/kaliid3.c new file mode 100644 index 0000000..dd5d2a1 --- /dev/null +++ b/lib/domains/Ylsrim/room/kaliid3.c @@ -0,0 +1,36 @@ +/* /domains/Ylsrim/room/kaliid3.c + * From the Dead Souls Mud Library + * An example of a room with a door and press event handler + * Created by Descartes of Borg 961222 + */ + +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetTown("Ylsrim"); + SetClimate("arid"); + SetAmbientLight(30); + SetShort("Kaliid Road by the Church"); + SetLong("Kaliid Road moves east and west through the desert town of " + "Ylsrim. The road itself gets sandier as it gets swallowed by " + "the desert in the distance east. On the northern end of the " + "road a door belonging to the local church. Next to the door " + "sits a huge button."); + SetSkyDomain("town"); + AddItem("church", "It is a rather pathetic wooden building where the " + "local priests initiate people into their religion."); + AddItem("desert", "The town does all it can to keep from being swallowed " + "by it."); + AddItem(new("/domains/Ylsrim/etc/church_button")); + SetExits( ([ + "north" : "/domains/Ylsrim/room/"+ "church", + "west" : "/domains/Ylsrim/room/"+ "kaliid4" ])); + SetDoor("north", "/domains/Ylsrim/etc/church_door"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/room/kaliid4.c b/lib/domains/Ylsrim/room/kaliid4.c new file mode 100644 index 0000000..a5bb350 --- /dev/null +++ b/lib/domains/Ylsrim/room/kaliid4.c @@ -0,0 +1,39 @@ +/* /domains/Ylsrim/room/kaliid4.c + * From the Dead Souls Mud Library + * A simple example room + * Created by Descartes of Borg 950929 + */ + +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetTown("Ylsrim"); + SetClimate("arid"); + SetAmbientLight(30); + SetShort("Kaliid Road north of the bazaar"); + SetLong("Kaliid Road stretches as far as you can see east and west across Ylsrim. South, Kaliid opens up into the central bazaar where vendors sell goods day and night. on the opposite side of the road is the entrance to the local adventurers' hall."); + SetSkyDomain("town"); + SetExits( ([ + "east" : "/domains/Ylsrim/room/kaliid3", + "south" : "/domains/Ylsrim/room/bazaar", + "west" : "/domains/Ylsrim/room/kaliid5", + "north" : "/domains/Ylsrim/room/adv_hall", + ]) ); + AddItem("hall", "A small building which serves as the focal point for " + "the adventuring activities for which Ylsrim's support " + "is widely known.", ({ "adventurer", "adventurers" })); + AddItem("bazaar", "The central bazaar is the main marketplace of " + "Ylsrim. Though many of the shops close at night, vendors " + "wander the bazaar at all times pawning their goods.", + ({ "central" })); + AddItem("vendor", "There are many vendors wandering about the bazaar."); + AddItem("town", "A new town, north of here."); + AddItem("road", "The main street for Ylsrim.", ({ "kaliid" })); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/room/kaliid5.c b/lib/domains/Ylsrim/room/kaliid5.c new file mode 100644 index 0000000..2b2ce45 --- /dev/null +++ b/lib/domains/Ylsrim/room/kaliid5.c @@ -0,0 +1,33 @@ +/* /domains/Ylsrim/room/kaliid5.c + * From the Dead Souls Mud Library + * A simple room + * Created by Descartes of Borg 960512 + */ + +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetTown("Ylsrim"); + SetClimate("arid"); + SetAmbientLight(30); + SetShort("Kaliid Road near the Fighters' Hall"); + SetLong("Kaliid Road stretches as far as you can see east and west " + "across Ylsrim. Along the north side of this stretch of road " + "sits the local Fighters' Hall. Immediately inside the entrance " + "you notice a recruitment area where novice seekers of fortune " + "decide to make their ways as fighters."); + SetSkyDomain("town"); + AddItem("hall", "Fighters passing through Ylsrim stop in to yap about " + "their adventures, and novices sign up to become fighters.", + ({ "fighter", "fighters" })); + AddItem("road", "The main street for Ylsrim.", ({ "kaliid" })); + SetExits( ([ "east" : "/domains/Ylsrim/room/"+ "kaliid4", + "west" : "/domains/Ylsrim/room/"+ "kaliid6", + "north" : "/domains/Ylsrim/room/"+ "fighter_hall" ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/room/kaliid6.c b/lib/domains/Ylsrim/room/kaliid6.c new file mode 100644 index 0000000..323ac8d --- /dev/null +++ b/lib/domains/Ylsrim/room/kaliid6.c @@ -0,0 +1,35 @@ +/* /domains/Ylsrim/room/kaliid6.c + * From the Dead Souls Mud Library + * An example of a room with an object that allows climbing + * Created by Descartes of Borg 961010 + */ + +#include <lib.h> +#include <climb.h> + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetTown("Ylsrim"); + SetClimate("arid"); + SetAmbientLight(30); + SetShort("Kaliid Road south of the bank"); + SetLong("Kaliid Road stretches as far as you can see east and west " + "across Ylsrim. The rough wall on the north side of the road " + "looks like the distinctive adobe of the Bank of Ylsrim. As " + "the road travels along side the bank walls west, you can see " + "Kaliid Road intersect with another."); + SetSkyDomain("town"); + AddItem(({ "bank", "bank of ylsrim" }), "Ylsrim's local bank. It has " + "an adobe wall filled with holes.", ({ "ylsrim" })); + AddItem("road", "The main street in Ylsrim.", "kaliid"); + AddItem("holes", "You might be able to use them to climb the wall."); + // here is the thing that can be climbed, have a look at it! + AddItem(new("/domains/Ylsrim/etc/wall")); + SetExits( ([ "east" : "/domains/Ylsrim/room/"+ "kaliid5", + "west" : "/domains/Ylsrim/room/"+ "kaliid7" ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/room/kaliid7.c b/lib/domains/Ylsrim/room/kaliid7.c new file mode 100644 index 0000000..0ae767b --- /dev/null +++ b/lib/domains/Ylsrim/room/kaliid7.c @@ -0,0 +1,32 @@ +/* /domains/Ylsrim/room/kaliid7.c + * From the Dead Souls Mud Library + * An example simple room with an item in it + * Created by Descartes of Borg 970101 + */ + +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetTown("Ylsrim"); + SetClimate("arid"); + SetAmbientLight(30); + SetShort("the western edge of Ylsrim"); + SetLong("Kaliid Road comes to its western end here as Ylsrim disappears " + "into the desert. Not too far east of here you see where " + "the local bank rests."); + SetSkyDomain("town"); + AddItem(({ "bank", "bank of ylsrim" }), "Ylsrim's local bank. It has " + "an adobe wall.", ({ "ylsrim" })); + AddItem("desert", "A great desert that surrounds Ylsrim and makes it " + "look so fragile."); + AddItem("road", "The main street in Ylsrim.", "kaliid"); + SetInventory(([ "/domains/Ylsrim/weapon/stick" : 1 ])); + SetExits( ([ "east" : "/domains/Ylsrim/room/"+ "kaliid6", + "west" : "/domains/Ylsrim/room/"+ "sand_room" ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/room/pub.c b/lib/domains/Ylsrim/room/pub.c new file mode 100644 index 0000000..432f7d5 --- /dev/null +++ b/lib/domains/Ylsrim/room/pub.c @@ -0,0 +1,74 @@ +/* /domains/Ylsrim/room/pub.c + * From the Dead Souls Mud Library + * An example pub room + * Created by Descartes of Borg 960302 + */ + +#include <lib.h> +#include <message_class.h> // defines MSG_SYSTEM + +inherit LIB_ROOM; + +// This is a special SetRead() function that allows players to read +// the menu + +int readMenu(object who, string str) { + string array tmp2 = ({}); + string array tmp = ({ sprintf("%:-20s %:-7s", "Drink", "Cost") }); + int langlevel = this_player()->GetLanguageLevel("Edhellen"); + object ob = present_file("/domains/Ylsrim/npc/lars"); + + if( !ob ) { // lars is dead! + this_player()->eventPrint("The menu is bloodstained and hard to read."); + tmp = ({ translate("Bad wolf.", langlevel) }); + } + else { + foreach(string *item in keys(ob->GetMenuItems())) { + tmp += ({ sprintf("%:-20s %d electrum", capitalize(item[0]), + to_int(ob->GetCost(item))) }); + } + foreach(string element in tmp){ + element = translate(element, langlevel); + tmp2 += ({ element }); + } + tmp = tmp2; + } + // show the menu a page at a time + this_player()->eventPage(tmp, MSG_SYSTEM); // MSG_SYSTEM means ignore blocking + return 1; +} +static void create() { + room::create(); + SetTown("Ylsrim"); + SetClimate("indoors"); + SetAmbientLight(25); + SetShort("Lars' Pub"); + SetLong("Lars' Pub is one of the most famous gathering places in all " + "Ylsrim. As you can see about you, however, it is not among the " + "more homely ones. Tables and stools are littered all about " + "with a hodge-podge of writing in all different languages " + "covering the wall. A menu of drinks is about the only " + "readable thing on the wall. If you read Edhellen."); + SetLanguage("Edhellen"); + SetInventory(([ + "/domains/Ylsrim/npc/lars" : 1, + ])); + SetListen("Rowdy party sounds make it hard to hear anything else."); + SetSmell("The place smells like it is soaked in ale."); + AddItem(({ "tables", "stools" }), "The tables and stools begin " + "to migrate as the day goes on and customerizes socialize. " + "Of course, nothing moves them better than a good brawl."); + AddItem(({ "menu", "drinks", "menu of drinks" }), "The menu is " + "written in Edhellen. Can you read it?", ({ "drink" })); + AddItem(({ "writing", "walls" }), "Scribble in all different " + "languages, and in many pens and many hands covers much of " + "each wall."); + SetExits(([ "east" : "/domains/Ylsrim/room/"+ "s_bazaar" ])); + // Bring in the Bar Keep + // make the writing and the menu readable + SetRead("writing", (: readMenu :)); + SetRead("menu", (: readMenu :)); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/room/s_bazaar.c b/lib/domains/Ylsrim/room/s_bazaar.c new file mode 100644 index 0000000..c4f9090 --- /dev/null +++ b/lib/domains/Ylsrim/room/s_bazaar.c @@ -0,0 +1,34 @@ +/* /domains/Ylsrim/room/s_bazaar.c + * From the Dead Souls Mud Library + * A simple room example with a unique, wandering NPC + * Created by Descartes of Borg 960302 + */ + +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetTown("Ylsrim"); + SetClimate("arid"); + SetAmbientLight(30); + SetShort("The south end of the Ylsrim Bazaar"); + SetLong("Along the south end of the Ylsrim Bazaar stands a restaurant " + "and a pub. The central area of the Bazaar is just north of " + "here."); + SetSkyDomain("town"); + SetInventory(([ + "/domains/Ylsrim/npc/traveler" : 1, + ])); + AddItem("pub", "You can buy yourself an ale from one of Ylsrim's most " + "respected residents.", ({ "lars" })); + AddItem("restaurant", "This restaurant is known for its stew.", + ({ "toral" })); + SetExits( ([ "north" : "/domains/Ylsrim/room/"+ "bazaar" ]) ); + SetEnters( ([ + "pub" : "/domains/Ylsrim/room/"+ "pub" ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/room/sand_hole.c b/lib/domains/Ylsrim/room/sand_hole.c new file mode 100644 index 0000000..264637c --- /dev/null +++ b/lib/domains/Ylsrim/room/sand_hole.c @@ -0,0 +1,25 @@ +/* /domains/Ylsrim/room/sand_hole.c + * From the Dead Souls Mud Library + * An example of a room in which you go after digging (get trapped!) + * Created by Descartes of Borg 961231 + */ + +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(25); + SetShort("a dark hole in the sand"); + SetLong("You are in a very dark, sandy hole in the desert."); + AddItem("sand", "It is everywhere."); + SetObviousExits(""); + SetExits( ([ "up" : "/domains/Ylsrim/room/"+ "sand_room" ])); + // use a door to act as a hole, as that is what the hole really is + SetDoor("up", "/domains/Ylsrim/etc/dug_hole"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/room/sand_room.c b/lib/domains/Ylsrim/room/sand_room.c new file mode 100644 index 0000000..1d66d22 --- /dev/null +++ b/lib/domains/Ylsrim/room/sand_room.c @@ -0,0 +1,86 @@ +/* /domains/Ylsrim/room/sand_room.c + * From the Dead Souls Mud Library + * An example of a room in which you can dig + * Created by Descartes of Borg 961231 + */ + +#include <lib.h> + +inherit LIB_ROOM; +inherit LIB_DIG; // inherit this to add dig functionality +inherit LIB_BURY; // inherit this to add bury functionality + +int eventEnterDesert(){ + this_player()->eventMoveLiving(load_object("/domains/Ylsrim/virtual/server")->compile_object("/domains/Ylsrim/virtual/desert/7,7")); + return 1; +} + +// This function gets called when someone tries to bury the hole +mixed buryHole(object who, object shovel) { + int closed; + closed = "/domains/Ylsrim/etc/dug_hole"->GetClosed(); + + if( closed ) { + who->eventPrint("Perhaps you want to dig the hole?"); + return 1; + } + send_messages("bury", "$agent_name $agent_verb a deep, gaping " + "hole in the sand.", who, 0, environment(who)); + "/domains/Ylsrim/etc/dug_hole"->SetClosed(1); + return 1; +} + +// This function gets called when someone tries to dig +mixed digHole(object who, object shovel) { + int closed; + closed = "/domains/Ylsrim/etc/dug_hole"->GetClosed(); + + if( !closed ) { + who->eventPrint("Perhaps you want to bury the hole?"); + return 1; + } + send_messages("dig", "$agent_name $agent_verb up a deep, gaping " + "hole in the sand.", who, 0, environment(who)); + "/domains/Ylsrim/etc/dug_hole"->SetClosed(0); + return 1; +} + +// This function is set in SetLong() to describe the room differently +// when the hole is open. +string describeRoom() { + string str = "You are just outside the western edge of Ylsrim. You now " + "stand in the open desert with a dry, arid wind draining you " + "of all strength. Nothing at all exists here besides endless " + "sand. About all you could possibly do is sit and dig."; + SetExits( ([ + "east" : "/domains/Ylsrim/room/kaliid7", + "down" : "/domains/Ylsrim/room/sand_hole", + ]) ); + + if( "/domains/Ylsrim/etc/dug_hole"->GetClosed() ) { + return str; // no hole to see + } + else { + return str + " A hole opens up in the middle of the sand."; + } +} + +static void create() { + room::create(); + SetClimate("arid"); + SetAmbientLight(30); + SetShort("a sandy desert outside of Ylsrim"); + SetLong((: describeRoom :)); + AddItem("sand", "Boring stretches of sand extend to the horizon."); + AddItem("ylsrim", "It is east of here."); + SetInventory( ([ "/domains/Ylsrim/etc/shovel" : 1 ]) ); + // use a door to act as a hole, as that is what the hole really is + SetDoor("down", "/domains/Ylsrim/etc/dug_hole"); + // this tells the room to call this function when a player digs + SetDig((: digHole :)); + // this tells the room what to call when a player buries the hole + SetBury((: buryHole :)); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/room/tower.c b/lib/domains/Ylsrim/room/tower.c new file mode 100644 index 0000000..525c94d --- /dev/null +++ b/lib/domains/Ylsrim/room/tower.c @@ -0,0 +1,43 @@ +/* /domains/Ylsrim/room/tower.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 960512 + */ + +#include <lib.h> +#include <jump.h> + +inherit LIB_ROOM; +inherit LIB_JUMP; + +int ReadSign() { + this_player()->more("/domains/town/txt/ylsrim_sign.txt"); + return 1; +} + +void create() { + room::create(); + SetClimate("indoors"); + SetTown("Ylsrim"); + SetAmbientLight(28); + SetShort("Ylsrim Tower"); + SetLong("The tower looks out over Kaliid Road. South of the road is " + "the always busy Ylsrim bazaar. A spiraling staircase leads " + "down into the heart of the adventurer's hall." + "\n%^RED%^There is a sign here you can read.%^RESET%^"); + SetItems( ([ ({ "road", "kaliid road" }) : + "You could probably jump down into the road from here.", + "bazaar" : "It looks like it is bustling.", + "sign":"A sign. To read it, 'read sign'.", + "tower" : "The tower you are on.", + ({ "stairs", "staircase" }) : "They lead down into the " + "heart of the hall." ]) ); + SetExits( ([ "down" : "/domains/Ylsrim/room/"+ "adv_hall" ]) ); + SetInventory(([ + "/domains/Ylsrim/obj/stargate" : 1, + ])); + SetRead("sign", (: ReadSign :) ); + SetCoordinates("1000,1001,1"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/room/vote_hall.c b/lib/domains/Ylsrim/room/vote_hall.c new file mode 100644 index 0000000..dec9e60 --- /dev/null +++ b/lib/domains/Ylsrim/room/vote_hall.c @@ -0,0 +1,163 @@ +/* + * /domains/Praxis/room/vote_hall.c + * from the Dead Souls mudlib + * So that players can vote + * by Kalinash on 961026 + */ + +#include <lib.h> +#include <daemons.h> +#include <voting.h> + +inherit LIB_ROOM; + +mixed ReadList(); + +static void create() { + ::create(); + SetTown("Ylsrim"); + SetClimate("indoors"); + SetProperties( ([ "no kill" : 1, "no attack" : 1, "no steal" : 1, + "no magic" : 1, "light" : 3, "no bump" : 1, "no teleport" : 1 ]) ); + SetShort("voting hall"); + SetLong("You are in the voting hall of Ylsrim. This is where people come to nominate candidates for class leader and to cast their vote. There is a list posted on the wall here."); + SetItems( ([ "list" : "This is the list of candidates." ]) ); + SetRead( "list", (: ReadList :) ); + SetObviousExits("down"); + SetExits( ([ "down" : "/domains/Ylsrim/room/bazaar" ]) ); +} + +mixed ReadList() { + string msg; + + if( VOTING_D->GetStatus() == VOTE_NOT_RUNNING ) { + this_player()->eventPrint("Since the elections are not " + "currently running, the list is blank."); + return 1; + } + + msg = "\tCandidates for Dead Souls Offices\n\n"; + + foreach( string sClass in CLASSES_D->GetClasses() ) { + msg += capitalize( sClass ) + " : "; + foreach( string sName in VOTING_D->GetCandidates(sClass) ) + msg += capitalize(sName) + ", "; + if( msg[strlen(msg)-2] == ',' ) + msg = msg[0..strlen(msg)-3]; + msg += "\n"; + } + + this_player()->eventPrint( msg ); + return 1; +} + +mixed CanNominate( object who ) { return 1; } +mixed CanVote( object who ) { return 1; } +mixed CanWithdraw( object who ) { return 1; } + +mixed eventNominate( object who, string str ) { + int iErr; + + if( creatorp( who ) ) { + who->eventPrint("Creators cannot vote!"); + return 1; + } + + iErr = VOTING_D->eventAddCandidate( who->GetClass(), str ); + + switch( iErr ) { + case VOTE_NOT_RUNNING : + this_player()->eventPrint("The elections are not running now!"); + break; + + case VOTE_MODE_VOTING : + this_player()->eventPrint("The time for nominating " + "candidates is past, cast your vote instead."); + break; + + case VOTE_ERROR : + this_player()->eventPrint("There was an error, you cannot " + "nominate someone at this time."); + break; + + case VOTE_NOT_CLASS_MEMBER : + this_player()->eventPrint( capitalize(str) + " is not a member + of " + "the " + pluralize( who->GetClass() ) + "."); + break; + + case VOTE_ALREADY_RUNNING : + this_player()->eventPrint( capitalize(str) + " is already + running." ); + break; + } + return 1; +} + +mixed eventVote( object who, string str ) { + int iErr; + string sClass; + + sClass = who->GetClass(); + iErr = VOTING_D->eventCastVote( sClass, who->GetName(), str ); + + switch( iErr ) { + case VOTE_NOT_RUNNING : + this_player()->eventPrint("The elections are not running + now!"); + break; + + case VOTE_MODE_CANDIDATES : + this_player()->eventPrint("Voting has not yet started, " + "nominate a candidate instead."); + break; + + case VOTE_NOT_PRIMARY : + this_player()->eventPrint("Only your primary character can + vote."); + break; + + case VOTE_NOT_CLASS_MEMBER : + this_player()->eventPrint( str + " is not a candidate for " + "the " + pluralize(who->GetClass()) + "."); + break; + + case VOTE_ALREADY_VOTED : + this_player()->eventPrint("You have already cast your vote!"); + break; + + case VOTE_SUCCESS : + this_player()->eventPrint("You cast your vote!"); + break; + } + + return 1; +} + +mixed eventWithdraw( object who ) { + int iErr; + + iErr = VOTING_D->eventRemoveCandidate( who->GetClass(), who->GetName() + ); + + switch( iErr ) { + case VOTE_NOT_RUNNING : + this_player()->eventPrint("The elections are not running + now!"); + break; + + case VOTE_MODE_VOTING : + this_player()->eventPrint("The elections have begun, it is " + "too late to withdraw."); + break; + + case VOTE_NOT_CANDIDATE : + this_player()->eventPrint("You are not a candidate."); + break; + } + + return 1; +} +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/room/weaponry.c b/lib/domains/Ylsrim/room/weaponry.c new file mode 100644 index 0000000..4d4ded1 --- /dev/null +++ b/lib/domains/Ylsrim/room/weaponry.c @@ -0,0 +1,59 @@ +/* /domains/Ylsrim/room/weaponry.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 951023 + */ + +#include <lib.h> +#include <dirs.h> + +inherit LIB_ROOM; + +string CheckOpen(string str); +string CheckItem(string str); + +static void create() { + room::create(); + SetTown("Ylsrim"); + SetClimate("indoors"); + SetAmbientLight(28); + SetShort("the Ylsrim weaponry"); + SetLong((: CheckOpen :)); + SetItems( ([ ({ "case", "cases" }) : (: CheckItem :), + "bazaar" : "People from all about are wandering around, looking " + "for a bargain." ]) ); + SetObviousExits("east"); + SetExits( ([ "east" : "/domains/Ylsrim/room/"+ "bazaar" ]) ); + SetInventory( ([ "/domains/Ylsrim"+ "/npc/shiela" : 1 ]) ); +} + +string CheckOpen(string str) { + object ob; + + ob = present("vendor"); + if( query_night() ) { + if( ob ) ob->eventDestruct(); + return ("The cases of the weaponry are empty, as the weaponry " + "has closed for the night. The bazaar is " + "east."); + } + if( !ob ) + return ("Fresh blood is splattered across broken cases which once " + "housed display weapons sold in this weaponry. The weapons are " + "gone, and the vendor clearly murdered. All you can do is " + "shake your head and exit to the east."); + return ("Sealed cases contain display weapons, exemplifying what the " + "local vendor has to offer. She buys and sells all sorts of " + "weapons from adventurers who come here to sell of their " + "discovered goods, or equip to continue adventuring. An exit " + "is east."); +} + +string CheckItem(object ob) { + if( query_night() ) return "They are empty."; + else if ( present("vendor") ) return "They are filled with weapons."; + else return "They are broken and covered in blood."; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/room/weaponry_storage.c b/lib/domains/Ylsrim/room/weaponry_storage.c new file mode 100644 index 0000000..8fb5465 --- /dev/null +++ b/lib/domains/Ylsrim/room/weaponry_storage.c @@ -0,0 +1,28 @@ +/* /domains/Ylsrim/room/weaponry_storage.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 960302 + */ + +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetNoClean(1); + SetTown("Ylsrim"); + SetProperties( ([ "login" : "/domains/Ylsrim/room/"+ "weaponry" ]) ); + SetClimate("indoors"); + SetShort("weaponry storage"); + SetLong("Weaponry storage."); + SetObviousExits("east"); + SetExits( ([ "west" : "/domains/Ylsrim/room/"+ "weaponry" ]) ); +} + +int CanReceive(object ob) { + if( !living(ob) || creatorp(ob) ) return room::CanReceive(ob); + else return 0; +} +void init(){ + ::init(); +} diff --git a/lib/domains/Ylsrim/virtual/README b/lib/domains/Ylsrim/virtual/README new file mode 100644 index 0000000..192aa1d --- /dev/null +++ b/lib/domains/Ylsrim/virtual/README @@ -0,0 +1,20 @@ + /domains/Ylsrim/virtual + Virtual Rooms for the Ylsrim Domain + +The Nightmare Object Library ships with a virtual desert to the east +of the main town of Ylsrim. It is 25 rooms by 25 rooms in which +people can get lost. What happens is when some objects references an +object in /domains/Ylsrim/virtual/desert/ but finds no file there, it +calls compile_object() in /domains/Ylsrim/virtual/server.c. That +function returns an object which serves as the non-existent object. + +The virtual server looks at the file name like: +/domains/Ylsrim/virtual/desert/15,12 + +That tells it to clone /domains/Ylsrim/virtual/desert.c and pass it +15, 12 as the argument to create(). Thus desert.c is able to set up +exits and such for its location at 15, 12 on the virtual desert grid. + +You can thus write your own virtual grid, say for a forest, simply by +writing a forest.c like the desert.c given here. + diff --git a/lib/domains/Ylsrim/virtual/desert.c b/lib/domains/Ylsrim/virtual/desert.c new file mode 100644 index 0000000..0d17f4c --- /dev/null +++ b/lib/domains/Ylsrim/virtual/desert.c @@ -0,0 +1,96 @@ +/* /domains/Ylsrim/virtual/desert.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 960302 + */ + +#include <lib.h> +#include <dirs.h> +#include <virtual.h> + +inherit LIB_VIRT_LAND; + +static private int XPosition, YPosition; + +varargs void SetLongAndItems(int x, int y, int z); + +varargs static void create(int x, int y) { + string n, s, e, w; + + SetNoReplace(1); + virt_land::create(); + XPosition = x; + YPosition = y; + SetClimate("arid"); + SetAmbientLight(30); + SetLongAndItems(); + SetShort(x == 25 ? "the edge of a desert" : "deep within a desert"); + if( x == 25 ) e = "desert/" + random(25) + "," + y; + else e = "desert/" + (x+1) + "," + y; + if( x == 1 ) w = "desert/" + random(25) + "," + y; + else w = "desert/" + (x-1) + "," + y; + if( y == 25 ) n = "desert/" + x + "," + random(25); + else n = "desert/" + x + "," + (y+1); + if( y == 1 ) s = "desert/" + x+ "," + random(25); + else s = "desert/" + x + "," + (y-1); + SetGoMessage("The dunes are too high to let you pass in that direction."); + if( n ) AddExit("north", __DIR__ + n); + if( s ) AddExit("south", __DIR__ + s); + if( e ) AddExit("east", __DIR__ + e); + if( w ) AddExit("west", __DIR__ + w); + if(x == 7 && y == 7){ + RemoveExit("east"); + AddExit("east","/domains/Ylsrim/room/sand_room"); + } +} + +varargs void SetLongAndItems(int x, int y, int z) { + mapping inv, items; + string str; + ::SetLongAndItems(x, y, z); + + inv = ([]); + str = "You are at the heart of a vast desert. The emptiness of endless " + "sand cuts at your morale with the strength of a scimitar. No path " + "marks your way."; + SetItems( ([ "desert" : "It is so vast." ]) ); + if( !random(50) ) { + str += " Burnt wood, scattered rocks and twigs, and other signs " + "of an abandoned camp site are scattered about."; + AddItem( ({ "twigs", "sticks", "kindling", "wood", "burnt wood" }) , + "Though long since burnt to nothing, scattered kindling " + "and burnt wood lie about as a memory of travellers who have " + "passed through"); + if( random(2) ) { + string thing; + + foreach(thing in ({ "twigs", "sticks", "kindling", "wood" })) + SetSearch(thing, function(object who, string str) { + object ob; + string thing2; + + if( !(ob = new("/domains/Ylsrim"+ "/etc/pole")) ) + return 0; + who->eventPrint("You find a fishing pole!"); + eventPrint(who->GetName() + " finds a fishing pole " + "among the abandoned campsite.", who); + foreach(thing2 in ({ "twigs", "sticks", "kindling", "wood"})) + RemoveSearch(thing2); + if( !(ob->eventMove(this_player())) ) { + who->eventPrint("You drop the pole!"); + eventPrint(who->GetName() + " drops the pole.", + who); + ob->eventMove(this_object()); + } + return; + }); + } + } + else if( !random(10) ) + SetSmell("default", "You smell a distant camp fire."); + if( !random(25) ) + inv["/domains/Ylsrim"+ "/npc/traveller"] = random(3) + 1; + else if( !random(4) ) + SetListen("default", "You hear voices whispering in the distance."); + SetLong(str); + SetInventory(inv); +} diff --git a/lib/domains/Ylsrim/virtual/desert_map.c b/lib/domains/Ylsrim/virtual/desert_map.c new file mode 100644 index 0000000..2bad38a --- /dev/null +++ b/lib/domains/Ylsrim/virtual/desert_map.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include <dirs.h> +#include <virtual.h> + +inherit LIB_VIRT_MAP; + +varargs string array BaseMap(){ //override with actual map + return + ({ + // 0 + // 01234 + ({"00000",//0 + "01000",//1 + "00000",//2 + "00000",//3 + "00000",//4 + }) + }); + +} + + +varargs static void create() { + ::create(); + //SetNoClean(1); + //SetVirtFile(base_name(this_object())); + //AddLocation("foo", ({2,2,0}) ); +} + + diff --git a/lib/domains/Ylsrim/virtual/server.c b/lib/domains/Ylsrim/virtual/server.c new file mode 100644 index 0000000..ceec7ce --- /dev/null +++ b/lib/domains/Ylsrim/virtual/server.c @@ -0,0 +1,18 @@ +/* /domains/Ylsrim/virtual/server.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 960302 + */ + +mixed compile_object(string file) { + string *path; + object ob; + int x, y; + + //if( previous_object() != master() ) return 0; + path = explode(file, "/"); + //if( sizeof(path) != 5 ) return "Wrong size path"; + if( file_size(__DIR__ + path[3] + ".c") < 1 ) return "bad file"; + if( sscanf(path[4], "%d,%d", x, y) != 2 ) return "missing comma"; + if( !(ob = new(__DIR__ + path[3], x, y)) ) return "failed to compile"; + return ob; +} diff --git a/lib/domains/Ylsrim/weapon/orc_slayer.c b/lib/domains/Ylsrim/weapon/orc_slayer.c new file mode 100644 index 0000000..72b5b45 --- /dev/null +++ b/lib/domains/Ylsrim/weapon/orc_slayer.c @@ -0,0 +1,46 @@ +/* /domains/Ylsrim/weapon/orc_slayer.c + * From the Dead Souls Mud Library + * An example of a weapon that is nasty against orcs + * Created by Descartes of Borg 970101 + */ + +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("orc slayer"); + SetId("sword", "slayer", "orcslayer"); + SetAdjectives("orc", "metal", "dull"); + SetShort("a dull sword"); + SetLong("This long, dull sword has some ancient runes on it."); + SetRead("Orc Slayer"); + SetMass(140); + SetValue(110); + SetVendorType(VT_WEAPON); + SetClass(18); + SetDamageType(BLADE); + SetWeaponType("blade"); +} + +// eventStrike() gets called each time the weapon hits an enemy +int eventStrike(object target) { + // call the default eventStrike() to get default damage + int x = item::eventStrike(target); + + // check if the target is an orc + if( target->GetRace() == "orc" ) { + // send a cool message to everyone in the room + // environment() is the person using the sword + // environment(environment()) thus would be the room + environment(environment())->eventPrint("The Orc Slayer flares with " + "hatred of orcs."); + // add a random(5) to the default damage + x += random(5); + } + // return the damage it should do + return x; +} diff --git a/lib/domains/Ylsrim/weapon/stick.c b/lib/domains/Ylsrim/weapon/stick.c new file mode 100644 index 0000000..ae3f80c --- /dev/null +++ b/lib/domains/Ylsrim/weapon/stick.c @@ -0,0 +1,27 @@ +/* /domains/Ylsrim/weapon/stick.c + * From the Dead Souls Mud Library + * An example simple weapon + * Created by Descartes of Borg 970101 + */ + +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("stick"); + SetId("stick"); + SetAdjectives("wooden"); + SetShort("a wooden stick"); + SetLong("A wooden stick which looks like it might once have been used " + "as a walking stick, or perhaps as a poor person's club."); + SetMass(30); + SetValue(10); + SetVendorType(VT_WEAPON); + SetClass(10); + SetDamageType(BLUNT); + SetWeaponType("blunt"); +} diff --git a/lib/domains/amigara/npc/rat.c b/lib/domains/amigara/npc/rat.c new file mode 100644 index 0000000..3e0e9fa --- /dev/null +++ b/lib/domains/amigara/npc/rat.c @@ -0,0 +1,32 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("rat"); + SetAdjectives( ({"ratlike","unusual","large","very","dangerous", + "dangerous looking","rat like"}) ); + SetId( ({"rat","rous","beast"}) ); + SetShort("a rodent of unusual size"); + SetLong("A very large, very dangerous-looking ratlike beast."); + SetRace("rodent"); + SetGender("male"); + SetClass("fighter"); + SetEncounter(100); + SetLevel(1); + SetMelee(1); + SetMessage("come","$N scurries in."); + SetMessage("leave","$N scurries $D."); + SetGuard("/domains/town/obj/ladder","The rat snarls and blocks your attempt."); +} + +void init(){ + ::init(); +} + +void heart_beat(){ + object env = environment(); + ::heart_beat(); +} + diff --git a/lib/domains/amigara/obj/lamp.c b/lib/domains/amigara/obj/lamp.c new file mode 100644 index 0000000..2b5cf32 --- /dev/null +++ b/lib/domains/amigara/obj/lamp.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_TORCH; + +void create(){ + ::create(); + SetKeyName("lamp"); + SetId( ({"thing","item","thang","dingus"}) ); + SetAdjectives( ({"generic","sample","template"}) ); + SetShort("a tall lamp"); + SetLong("This is a lamp embedded into the floor, designed to provide light."); + SetPreventGet("The lamp is embedded into the floor."); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetRadiantLight(25); + SetFuelAmount(5000); +} + +void init(){ + ::init(); + if(!GetLit() && CanBurn(this_object())){ + this_object()->eventBurn(0,0,1); + } +} diff --git a/lib/domains/amigara/room/banquet.c b/lib/domains/amigara/room/banquet.c new file mode 100644 index 0000000..1f39e15 --- /dev/null +++ b/lib/domains/amigara/room/banquet.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("copy of passage17.c"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits(([ + "east" : "/domains/amigara/room/passage17", + ])); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/cave.c b/lib/domains/amigara/room/cave.c new file mode 100644 index 0000000..d3fda33 --- /dev/null +++ b/lib/domains/amigara/room/cave.c @@ -0,0 +1,38 @@ +#include <lib.h> +#include <climb.h> +#include ROOMS_H + +inherit LIB_ROOM; +inherit LIB_CLIMB; + +int DownClimb(){ + //tc("hit DownClimb"); + eventClimb(this_player(),CLIMB_DOWN,"/domains/amigara/room/passage1"); +} + +void create() { + ::create(); + SetAmbientLight(5); + SetNightLight(15); + SetDayLight(25); + SetShort("A Dark Cave"); + SetNightLong("This is a cave in the rough stone mountain wall. "+ + "The cave opens south into the night. To the north is darkness."); + SetDayLong("This is a cave in the rough stone mountain wall. Daylight shines in from the south, where where a forest lies. To the north, the cave continues into darkness."); + SetLong("This is a small cave near a forest."); + SetItems(([ + ({ "wall", "rocky wall", "mountain wall", "rough stone mountain wall", "stone mountain wall" }) : "Geological activity has created this cave ove the years, but clearly some sentient activity has formed it into a usable size and shape for habitation.", + ])); + SetInventory(([ + "/domains/town/obj/ladder" : 1, + ])); + SetExits( ([ + "south" : "/domains/town/virtual/forest/-3,25", + "north" : "/domains/amigara/room/midair.c", + ]) ); + SetClimb( (: DownClimb :) , CLIMB_DOWN); + SetObviousExits("south, climb down"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/death.c b/lib/domains/amigara/room/death.c new file mode 100644 index 0000000..9a8de22 --- /dev/null +++ b/lib/domains/amigara/room/death.c @@ -0,0 +1,73 @@ +#include <lib.h> +#include <dirs.h> +#include ROOMS_H + +inherit LIB_ROOM; + +string FunkyPic(); +int CheckChat(); +int StartHeart(object ob); + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("off the mortal coil"); + SetLong( (:FunkyPic:) ); + SetObviousExits("no exit"); + set_heart_beat(10); + SetNoModify(1); +} + +void init(){ + ::init(); + add_action("regenerate","regenerate"); + add_action("regenerate","choose"); + add_action("wander","wander"); + this_object()->CheckChat(); +} + +string FunkyPic(){ + return "YOU ARE DEAD!!!"; +} + +int regenerate(){ + write("With a great rush of matter and energy, you rematerialize "+ + "into a corporeal state, and find yourself in a familiar place..."); + this_player()->eventRevive(); + this_player()->eventMoveLiving(ROOM_START); + return 1; +} + +int wander(){ + write("There is a strange, hollow vibration all around you, and you "+ + "realize that some force is compelling your ethereal form elsewhere..."+ + "you find yourself in a place that is known to you, yet oddly new."); + this_player()->eventMoveLiving(ROOM_START); + return 1; +} + +void heart_beat(){ + tell_room(this_object(), "A voice whispers: \" You may choose to "+ + "regenerate into a new body here.\""); + return; +} + + +int CanRelease(object ob){ + if(userp(ob) && ob->GetGhost() && environment(ob) == this_object()) { + tell_player(ob,"\n%^RED%^Your undead spirit is recalled and as you leave "+ + "the underworld a new body regenerates around you. "+ + "You live again!%^RESET%^\n"); + ob->eventRevive(); + } + return 1; +} + +int CanReceive(object ob){ + if(!living(ob)){ + return 0; + } + return ::CanReceive(ob); +} + diff --git a/lib/domains/amigara/room/food_storage.c b/lib/domains/amigara/room/food_storage.c new file mode 100644 index 0000000..c541b9e --- /dev/null +++ b/lib/domains/amigara/room/food_storage.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("food storage"); + SetLong("A small room carved into the cave. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits(([ + "east" : "/domains/amigara/room/passage7", + ])); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/freezer.c b/lib/domains/amigara/room/freezer.c new file mode 100644 index 0000000..896cbbf --- /dev/null +++ b/lib/domains/amigara/room/freezer.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetNoClean(1); + SetProperties(([ "login" : ROOM_START ])); + SetShort( "The freezer"); + SetLong( "The local freezer. Go down to leave."); + SetObviousExits("down"); + SetExits( ([ "down" : ROOM_START ]) ); + call_out("clean_room", MAX_NET_DEAD_TIME); + SetNoModify(1); +} + +static void clean_room(){ + object ob; + call_out((: clean_room :), MAX_NET_DEAD_TIME); + foreach(ob in filter(all_inventory(), (: living($1) :))){ + string name = last_string_element(base_name(ob),"/"); + if(!user_exists(name)) continue; + ob->eventDestruct(); + } +} + +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/furnace.c b/lib/domains/amigara/room/furnace.c new file mode 100644 index 0000000..240341a --- /dev/null +++ b/lib/domains/amigara/room/furnace.c @@ -0,0 +1,10 @@ +#include <lib.h> + +inherit LIB_FURNACE; + +void create() { + furnace::create(); +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/guard_room.c b/lib/domains/amigara/room/guard_room.c new file mode 100644 index 0000000..3581559 --- /dev/null +++ b/lib/domains/amigara/room/guard_room.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("guardroom"); + SetLong("A small room carved into the cave. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits(([ + "south" : "/domains/amigara/room/passage2", + ])); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/kchief.c b/lib/domains/amigara/room/kchief.c new file mode 100644 index 0000000..7c8245f --- /dev/null +++ b/lib/domains/amigara/room/kchief.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("Chieftain room"); + SetLong("A small room carved into the cave. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "west" : "/domains/amigara/room/kguards", + "north" : "/domains/amigara/room/passage11.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/kcommon.c b/lib/domains/amigara/room/kcommon.c new file mode 100644 index 0000000..e06ea87 --- /dev/null +++ b/lib/domains/amigara/room/kcommon.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("common room"); + SetLong("A small room carved into the cave. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits(([ + "west" : "/domains/amigara/room/passage8", + ])); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/kguards.c b/lib/domains/amigara/room/kguards.c new file mode 100644 index 0000000..d466c5f --- /dev/null +++ b/lib/domains/amigara/room/kguards.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("guardroom"); + SetLong("A small room carved into the cave. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "west" : "/domains/amigara/room/passage10", + "east" : "/domains/amigara/room/kchief.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/midair.c b/lib/domains/amigara/room/midair.c new file mode 100644 index 0000000..de994e4 --- /dev/null +++ b/lib/domains/amigara/room/midair.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include <terrain_types.h> +#include <medium.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("midair in a cave"); + SetLong("This is a cave in the stone mountain north of the town forest. There is no floor here. There is darkness below."); + SetItems(([ + ({ "wall", "rocky wall", "mountain wall", "rough stone mountain wall", "stone mountain wall" }) : "Geological activity has created this cave ove the years, but clearly some sentient activity has formed it into a usable size and shape for habitation.", + ])); + SetExits( ([ + "south" : "/domains/amigara/room/cave", + "down" : "/domains/amigara/room/passage1.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + SetTerrainType(T_MIDAIR); + SetMedium(MEDIUM_AIR); +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/ocommchamb.c b/lib/domains/amigara/room/ocommchamb.c new file mode 100644 index 0000000..9e58a6f --- /dev/null +++ b/lib/domains/amigara/room/ocommchamb.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("common chamber"); + SetLong("A small room carved into the cave. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits(([ + "northeast" : "/domains/amigara/room/passage27", + ])); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/ocommhall.c b/lib/domains/amigara/room/ocommhall.c new file mode 100644 index 0000000..823eab6 --- /dev/null +++ b/lib/domains/amigara/room/ocommhall.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("common hall"); + SetLong("A small room carved into the cave. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits(([ + "north" : "/domains/amigara/room/passage27", + ])); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/ocommon.c b/lib/domains/amigara/room/ocommon.c new file mode 100644 index 0000000..f3fc934 --- /dev/null +++ b/lib/domains/amigara/room/ocommon.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("common room"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "southeast" : "/domains/amigara/room/passage17.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/oguard.c b/lib/domains/amigara/room/oguard.c new file mode 100644 index 0000000..b4db948 --- /dev/null +++ b/lib/domains/amigara/room/oguard.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("guardroom"); + SetLong("A small room carved into the cave. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits(([ + "west" : "/domains/amigara/room/passage12", + ])); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/oguard2.c b/lib/domains/amigara/room/oguard2.c new file mode 100644 index 0000000..e0c7139 --- /dev/null +++ b/lib/domains/amigara/room/oguard2.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("guardroom"); + SetLong("A small room carved into the cave. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits(([ + "west" : "/domains/amigara/room/passage15", + ])); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/oleader.c b/lib/domains/amigara/room/oleader.c new file mode 100644 index 0000000..090d87b --- /dev/null +++ b/lib/domains/amigara/room/oleader.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("leader room"); + SetLong("A small room carved into the cave. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits(([ + "west" : "/domains/amigara/room/passage24", + ])); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/osecret.c b/lib/domains/amigara/room/osecret.c new file mode 100644 index 0000000..c9692ab --- /dev/null +++ b/lib/domains/amigara/room/osecret.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "northeast" : "/domains/amigara/room/passage21", + "west" : "/domains/amigara/room/passage22.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/ostorage.c b/lib/domains/amigara/room/ostorage.c new file mode 100644 index 0000000..5d88e78 --- /dev/null +++ b/lib/domains/amigara/room/ostorage.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("storage"); + SetLong("A small room carved into the cave. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits(([ + "west" : "/domains/amigara/room/passage19", + ])); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage1.c b/lib/domains/amigara/room/passage1.c new file mode 100644 index 0000000..134a84a --- /dev/null +++ b/lib/domains/amigara/room/passage1.c @@ -0,0 +1,32 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("Dark Passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare. Above there seems to be another part of the cave but there is no obvious way of walking up there."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetInventory(([ + "/domains/amigara/obj/lamp" : 1, + ])); + SetExits( ([ + "east" : "/domains/amigara/room/passage2", + "west" : "/domains/amigara/room/rats.c", + ]) ); + SetFlyRoom("/domains/amigara/room/midair"); + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage10.c b/lib/domains/amigara/room/passage10.c new file mode 100644 index 0000000..129a245 --- /dev/null +++ b/lib/domains/amigara/room/passage10.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "west" : "/domains/amigara/room/passage9", + "east" : "/domains/amigara/room/kguards.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage11.c b/lib/domains/amigara/room/passage11.c new file mode 100644 index 0000000..83ff526 --- /dev/null +++ b/lib/domains/amigara/room/passage11.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "south" : "/domains/amigara/room/kchief", + "north" : "/domains/amigara/room/passage12.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage12.c b/lib/domains/amigara/room/passage12.c new file mode 100644 index 0000000..4b3a468 --- /dev/null +++ b/lib/domains/amigara/room/passage12.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "south" : "/domains/amigara/room/passage11", + "east" : "/domains/amigara/room/oguard", + "west" : "/domains/amigara/room/passage13.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage13.c b/lib/domains/amigara/room/passage13.c new file mode 100644 index 0000000..ae377e5 --- /dev/null +++ b/lib/domains/amigara/room/passage13.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "north" : "/domains/amigara/room/passage14", + "east" : "/domains/amigara/room/passage12", + "west" : "/domains/amigara/room/passage17.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage14.c b/lib/domains/amigara/room/passage14.c new file mode 100644 index 0000000..afc8b15 --- /dev/null +++ b/lib/domains/amigara/room/passage14.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "south" : "/domains/amigara/room/passage13", + "east" : "/domains/amigara/room/passage15", + "west" : "/domains/amigara/room/passage16.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage15.c b/lib/domains/amigara/room/passage15.c new file mode 100644 index 0000000..704ec2f --- /dev/null +++ b/lib/domains/amigara/room/passage15.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "west" : "/domains/amigara/room/passage14", + "east" : "/domains/amigara/room/oguard2.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage16.c b/lib/domains/amigara/room/passage16.c new file mode 100644 index 0000000..35604b2 --- /dev/null +++ b/lib/domains/amigara/room/passage16.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "east" : "/domains/amigara/room/passage14", + "north" : "/domains/amigara/room/passage18.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage17.c b/lib/domains/amigara/room/passage17.c new file mode 100644 index 0000000..8f3bdba --- /dev/null +++ b/lib/domains/amigara/room/passage17.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "east" : "/domains/amigara/room/passage13", + "west" : "/domains/amigara/room/banquet", + "northwest" : "/domains/amigara/room/ocommon.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage18.c b/lib/domains/amigara/room/passage18.c new file mode 100644 index 0000000..942f62c --- /dev/null +++ b/lib/domains/amigara/room/passage18.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "south" : "/domains/amigara/room/passage16", + "east" : "/domains/amigara/room/passage19", + "west" : "/domains/amigara/room/passage20.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage19.c b/lib/domains/amigara/room/passage19.c new file mode 100644 index 0000000..8cd4dac --- /dev/null +++ b/lib/domains/amigara/room/passage19.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "west" : "/domains/amigara/room/passage18", + "east" : "/domains/amigara/room/ostorage.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage2.c b/lib/domains/amigara/room/passage2.c new file mode 100644 index 0000000..e891729 --- /dev/null +++ b/lib/domains/amigara/room/passage2.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "north" : "/domains/amigara/room/guard_room", + "west" : "/domains/amigara/room/passage1", + "east" : "/domains/amigara/room/passage3.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage20.c b/lib/domains/amigara/room/passage20.c new file mode 100644 index 0000000..a865ee9 --- /dev/null +++ b/lib/domains/amigara/room/passage20.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "east" : "/domains/amigara/room/passage18", + "west" : "/domains/amigara/room/passage21.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage21.c b/lib/domains/amigara/room/passage21.c new file mode 100644 index 0000000..3db0769 --- /dev/null +++ b/lib/domains/amigara/room/passage21.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "east" : "/domains/amigara/room/passage20", + "southwest" : "/domains/amigara/room/osecret.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage22.c b/lib/domains/amigara/room/passage22.c new file mode 100644 index 0000000..e911ea5 --- /dev/null +++ b/lib/domains/amigara/room/passage22.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "east" : "/domains/amigara/room/osecret", + "west" : "/domains/amigara/room/passage23.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage23.c b/lib/domains/amigara/room/passage23.c new file mode 100644 index 0000000..da42424 --- /dev/null +++ b/lib/domains/amigara/room/passage23.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "north" : "/domains/amigara/room/passage24", + "east" : "/domains/amigara/room/passage22", + "west" : "/domains/amigara/room/passage25.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage24.c b/lib/domains/amigara/room/passage24.c new file mode 100644 index 0000000..d5c5eb5 --- /dev/null +++ b/lib/domains/amigara/room/passage24.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "south" : "/domains/amigara/room/passage23", + "east" : "/domains/amigara/room/oleader.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage25.c b/lib/domains/amigara/room/passage25.c new file mode 100644 index 0000000..07907f3 --- /dev/null +++ b/lib/domains/amigara/room/passage25.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "east" : "/domains/amigara/room/passage23", + "south" : "/domains/amigara/room/passage26.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage26.c b/lib/domains/amigara/room/passage26.c new file mode 100644 index 0000000..4c38fec --- /dev/null +++ b/lib/domains/amigara/room/passage26.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "north" : "/domains/amigara/room/passage25", + "southeast" : "/domains/amigara/room/passage27.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage27.c b/lib/domains/amigara/room/passage27.c new file mode 100644 index 0000000..202d61c --- /dev/null +++ b/lib/domains/amigara/room/passage27.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "south" : "/domains/amigara/room/ocommhall", + "northwest" : "/domains/amigara/room/passage26", + "southwest" : "/domains/amigara/room/ocommchamb.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage3.c b/lib/domains/amigara/room/passage3.c new file mode 100644 index 0000000..dd78953 --- /dev/null +++ b/lib/domains/amigara/room/passage3.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "east" : "/domains/amigara/room/passage4", + "west" : "/domains/amigara/room/passage2", + "north" : "/domains/amigara/room/passage5.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage4.c b/lib/domains/amigara/room/passage4.c new file mode 100644 index 0000000..4783f96 --- /dev/null +++ b/lib/domains/amigara/room/passage4.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "west" : "/domains/amigara/room/passage3", + "east" : "/domains/amigara/room/passage8.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage5.c b/lib/domains/amigara/room/passage5.c new file mode 100644 index 0000000..2b2b329 --- /dev/null +++ b/lib/domains/amigara/room/passage5.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "south" : "/domains/amigara/room/passage3", + "north" : "/domains/amigara/room/passage6.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage6.c b/lib/domains/amigara/room/passage6.c new file mode 100644 index 0000000..ba562e4 --- /dev/null +++ b/lib/domains/amigara/room/passage6.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "south" : "/domains/amigara/room/passage5", + "west" : "/domains/amigara/room/passage7", + "east" : "/domains/amigara/room/passage9.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage7.c b/lib/domains/amigara/room/passage7.c new file mode 100644 index 0000000..1173bea --- /dev/null +++ b/lib/domains/amigara/room/passage7.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "east" : "/domains/amigara/room/passage6", + "west" : "/domains/amigara/room/food_storage.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage8.c b/lib/domains/amigara/room/passage8.c new file mode 100644 index 0000000..6f2edd2 --- /dev/null +++ b/lib/domains/amigara/room/passage8.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "west" : "/domains/amigara/room/passage4", + "east" : "/domains/amigara/room/kcommon.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/passage9.c b/lib/domains/amigara/room/passage9.c new file mode 100644 index 0000000..7e1ec4b --- /dev/null +++ b/lib/domains/amigara/room/passage9.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("a dark passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "west" : "/domains/amigara/room/passage6", + "east" : "/domains/amigara/room/passage10.c", + ]) ); + + SetInventory(([ + ])); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/pod.c b/lib/domains/amigara/room/pod.c new file mode 100644 index 0000000..62da2f9 --- /dev/null +++ b/lib/domains/amigara/room/pod.c @@ -0,0 +1,16 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("the incept pod"); + SetLong("The incept pod. Some objects come here to be created "+ + "and identified. Go down to get out."); + SetExits( ([ "down" : ROOM_START ]) ); +} +int CanReceive(object ob){ + return room::CanReceive(ob); +} diff --git a/lib/domains/amigara/room/rats.c b/lib/domains/amigara/room/rats.c new file mode 100644 index 0000000..dc1286d --- /dev/null +++ b/lib/domains/amigara/room/rats.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("midden room"); + SetLong("A small room carved into the cave. The walls are rough and bare."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "A space torn or carved into the mountain.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetInventory(([ + "/domains/amigara/npc/rat" : 1, + "/domains/town/obj/ladder" : 1, + ])); + SetExits(([ + "east" : "/domains/amigara/room/passage1", + ])); + + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/start.c b/lib/domains/amigara/room/start.c new file mode 100644 index 0000000..9a40b1f --- /dev/null +++ b/lib/domains/amigara/room/start.c @@ -0,0 +1,14 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/void.c b/lib/domains/amigara/room/void.c new file mode 100644 index 0000000..622a4ac --- /dev/null +++ b/lib/domains/amigara/room/void.c @@ -0,0 +1,16 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("the void"); + SetLong("The void. Go down to get out."); + SetExits( ([ "down" : ROOM_START ]) ); + SetNoModify(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/room/wiz_hall.c b/lib/domains/amigara/room/wiz_hall.c new file mode 100644 index 0000000..dba7910 --- /dev/null +++ b/lib/domains/amigara/room/wiz_hall.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Creators' Hall"); + SetLong("A generic Wiz Hall."); + SetProperty("no attack", 1); + SetProperty("nopeer",1); +} + +int CanReceive(object ob) { + if(playerp(ob) && !creatorp(ob) && !present("testchar badge",ob)) { + message("info","Creator staff only, sorry.", ob); + return 0; + } + return ::CanReceive(ob); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/amigara/virtual/server.c b/lib/domains/amigara/virtual/server.c new file mode 100644 index 0000000..826b336 --- /dev/null +++ b/lib/domains/amigara/virtual/server.c @@ -0,0 +1,22 @@ +#define __DIR__ "/domains/amigara/virtual/" + +mixed compile_object(string file) { + string *path; + object ob; + int x, y, z, elements; + if(grepp(file, "/user_") || grepp(file, "/object_")){ + ob = new("/domains/amigara/virtual/void"); + if(!ob){ + return "No void room available."; + } + return ob; + } + path = explode(file, "/"); + if( file_size(__DIR__ + path[3] + ".c") < 1 ) return "bad file"; + if( (elements = sscanf(path[4], "%d,%d,%d", x, y, z)) != 3 ) { + if( (elements = sscanf(path[4], "%d,%d", x, y)) != 2 ) return "missing comma"; + } + if( elements == 2 && !(ob = new(__DIR__ + path[3], x, y)) ) return "failed to compile"; + else if( elements == 3 && !(ob = new(__DIR__ + path[3], x, y, z)) ) return "failed to compile"; + return ob; +} diff --git a/lib/domains/amigara/virtual/void.c b/lib/domains/amigara/virtual/void.c new file mode 100644 index 0000000..4a0a743 --- /dev/null +++ b/lib/domains/amigara/virtual/void.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <dirs.h> +#include <rooms.h> +#include <virtual.h> +#include <position.h> +#define __DIR__ "/domains/amigara/virtual/" + +inherit LIB_VIRT_LAND; + +varargs static void create(int x, int y) { + SetNoReplace(1); + virt_land::create(); + SetClimate("temperate"); + SetAmbientLight(30); + SetLong("A featureless void."); + SetShort("an empty place"); + AddExit("down", ROOM_START); +} diff --git a/lib/domains/begin/room/arena.c b/lib/domains/begin/room/arena.c new file mode 100644 index 0000000..f4c018a --- /dev/null +++ b/lib/domains/begin/room/arena.c @@ -0,0 +1,47 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("the Arena"); + SetLong("You are in a large room with blank cement walls. This room was built so Creators may test their armor, weapons and NPC's in combat. A large steel door is here, which can be used to prevent wimpy creatures from escaping."); + SetItems( ([ + ({"wall","walls"}) : "The walls are smooth and cement.", + ({"floor","ceiling"}) : "The floor and ceiling are, like the walls, made "+ + "of smooth cement." ]) ); + SetInventory(([ + "/domains/default/npc/fighter" : 1, + "/domains/default/obj/locker" : 1, + "/domains/default/npc/dummy" : 1, + "/domains/default/obj/case" : 1, + "/domains/default/obj/abox" : 1, + "/domains/default/obj/javelin_bin" : 1, + "/domains/default/obj/rack" : 1, + ])); + SetExits( ([ + "south" : "/domains/default/room/wiz_corr_east", + ]) ); + SetPlayerKill(1); + + SetDoor("south", "/domains/default/doors/steel_door2.c"); + +} + +int CanReceive(object sneak) { + object *living_stack = get_livings(sneak); + if(!living_stack || !arrayp(living_stack)) living_stack = ({ sneak }); + foreach(object ob in living_stack){ + if(playerp(ob) && !creatorp(ob) && + !member_group(ob,"TEST")) { + message("info","Creator staff only, sorry.", ob); + return 0; + } + } + return 1; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/begin/room/builder_hall.c b/lib/domains/begin/room/builder_hall.c new file mode 100644 index 0000000..f84cfd3 --- /dev/null +++ b/lib/domains/begin/room/builder_hall.c @@ -0,0 +1,48 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Builders' Lounge"); + SetLong("This is the comfortable lounge where builders can congregate to chat about their work and leave messages for each other on the board. The Adventurers' Guild is north."); + SetProperty("no attack", 1); + SetProperty("nopeer",1); + ob = new("/lib/bboard"); + ob->SetKeyName("chalkboard"); + ob->SetId( ({ "board", "chalkboard", "dusty board", "dusty chalkboard" }) ); + ob->set_board_id("builder_board"); + ob->set_max_posts(30); + ob->SetShort("a dusty chalkboard"); + ob->eventMove(this_object()); + SetItems( ([ + ({"sign"}) : "A sign you can read.", + ]) ); + SetExits( ([ + "north" : "/domains/town/room/adv_guild", + ]) ); + SetInventory(([ + "/domains/default/obj/couch" : 1, + ])); +} + +int CanReceive(object sneak) { + object *living_stack = get_livings(sneak); + if(!living_stack || !arrayp(living_stack)) living_stack = ({ sneak }); + foreach(object ob in living_stack){ + if(playerp(ob) && !builderp(ob) && !present("testchar badge",ob) && + !member_group(ob,"TEST")) { + message("info","Staff only, sorry.", ob); + return 0; + } + } + return 1; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/begin/room/catchtell.c b/lib/domains/begin/room/catchtell.c new file mode 100644 index 0000000..4660082 --- /dev/null +++ b/lib/domains/begin/room/catchtell.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include <daemons.h> +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("catch_tell room"); + SetLong("This is a room designed to receive certain messages from NPC's. It is largely for debugging purposes, and it is not vital to normal mud operations."); + SetExits(([ + "west" : "/secure/room/network", + ])); + +} +int CanReceive(object ob) { + if( !archp(ob) ){ + message("info","The catch tell room is available only to "+ + "admins, sorry.",ob); + return 0; + } + return 1; +} +void init(){ + ::init(); +} diff --git a/lib/domains/begin/room/death.c b/lib/domains/begin/room/death.c new file mode 100644 index 0000000..f0354b1 --- /dev/null +++ b/lib/domains/begin/room/death.c @@ -0,0 +1,73 @@ +#include <lib.h> +#include <dirs.h> +#include ROOMS_H + +inherit LIB_ROOM; + +string FunkyPic(); +int CheckChat(); +int StartHeart(object ob); + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("off the mortal coil"); + SetLong( (:FunkyPic:) ); + SetObviousExits("no exit"); + set_heart_beat(10); + SetNoModify(1); +} + +void init(){ + ::init(); + add_action("regenerate","regenerate"); + add_action("wander","wander"); + this_object()->CheckChat(); +} + +string FunkyPic(){ + return read_file("/domains/default/etc/death.txt"); +} + +int regenerate(){ + write("With a great rush of matter and energy, you rematerialize "+ + "into a corporeal state, and find yourself in a familiar place..."); + this_player()->eventRevive(); + this_player()->eventMoveLiving(ROOM_START); + return 1; +} + +int wander(){ + write("There is a strange, hollow vibration all around you, and you "+ + "realize that some force is compelling your ethereal form elsewhere..."+ + "you find yourself in a place that is known to you, yet oddly new."); + this_player()->eventMoveLiving(ROOM_START); + return 1; +} + +void heart_beat(){ + tell_room(this_object(), "A voice whispers: \" You may choose to "+ + "regenerate into a new body here.\""); + return; +} + + +int CanRelease(object ob){ + if(userp(ob) && ob->GetGhost() && environment(ob) == this_object()) { + tell_player(ob,"\n%^RED%^Your undead spirit is recalled and as you leave "+ + "the underworld a new body regenerates around you. "+ + "You live again!%^RESET%^\n"); + ob->eventRevive(); + } + return 1; +} + +int CanReceive(object ob){ + if(!living(ob)){ + return 0; + } + return ::CanReceive(ob); +} + + diff --git a/lib/domains/begin/room/domains_room.c b/lib/domains/begin/room/domains_room.c new file mode 100644 index 0000000..5c593f0 --- /dev/null +++ b/lib/domains/begin/room/domains_room.c @@ -0,0 +1,66 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +string LongDesc(){ + string desc = "Immortals come here to visit parts of "+ + "the world they are building. The Creators' Hall is above. "+ + "To visit the Dead Souls "+ + "test and development mud, go west."; + return desc; +} + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Domains Room"); + SetLong("This room provides a convenient access point to various domain start rooms and featured realms."); + SetItems(([ + "Ylsrim" : "This is the entry point for the Ylsrim domain.", + "campus" : "This is the entry point for the campus domain.", + "examples" : "This is the entry point for the examples domain.", + "town" : "This is the entry point for the town domain.", + "cave" : "This is the entry point for the cave domain.", + "praxis" : "This is the entry point for the praxis domain.", + "learning" : "This is the entry point for the tutorial", + ({ "sign" }) : "A sign you can read.", + ])); + SetEnters( ([ + "campus" : "/domains/campus/room/start", + "ylsrim" : "/domains/Ylsrim/room/bazaar", + "examples" : "/domains/examples/room/start.c", + "cave" : "/domains/cave/room/start", + "town" : "/domains/town/room/start", + "learning" : "/domains/learning/room/start", + "praxis" : "/domains/Praxis/square", + ]) ); + SetProperty("no attack", 1); + SetProperty("nopeer",1); + SetExits(([ + "north" : "/domains/default/room/wiz_hall2", + ])); + + SetInventory(([ + ])); + + SetRead("sign", (: load_object(ROOM_ARCH)->SignRead() :) ); +} + +int CanReceive(object ob) { + if(playerp(ob) && !creatorp(ob) && !present("testchar badge",ob) && + !member_group(ob,"TEST")) { + message("info","Creator staff only, sorry.", ob); + return 0; + } + + if(ob->GetRace() == "rodent"){ + message("info","You are repelled by rodenticide.",ob); + return 0; + } + return 1; +} +void init(){ + ::init(); +} diff --git a/lib/domains/begin/room/freezer.c b/lib/domains/begin/room/freezer.c new file mode 100644 index 0000000..896cbbf --- /dev/null +++ b/lib/domains/begin/room/freezer.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetNoClean(1); + SetProperties(([ "login" : ROOM_START ])); + SetShort( "The freezer"); + SetLong( "The local freezer. Go down to leave."); + SetObviousExits("down"); + SetExits( ([ "down" : ROOM_START ]) ); + call_out("clean_room", MAX_NET_DEAD_TIME); + SetNoModify(1); +} + +static void clean_room(){ + object ob; + call_out((: clean_room :), MAX_NET_DEAD_TIME); + foreach(ob in filter(all_inventory(), (: living($1) :))){ + string name = last_string_element(base_name(ob),"/"); + if(!user_exists(name)) continue; + ob->eventDestruct(); + } +} + +void init(){ + ::init(); +} diff --git a/lib/domains/begin/room/furnace.c b/lib/domains/begin/room/furnace.c new file mode 100644 index 0000000..240341a --- /dev/null +++ b/lib/domains/begin/room/furnace.c @@ -0,0 +1,10 @@ +#include <lib.h> + +inherit LIB_FURNACE; + +void create() { + furnace::create(); +} +void init(){ + ::init(); +} diff --git a/lib/domains/begin/room/menagerie.c b/lib/domains/begin/room/menagerie.c new file mode 100644 index 0000000..d9435e0 --- /dev/null +++ b/lib/domains/begin/room/menagerie.c @@ -0,0 +1,45 @@ +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("The Menagerie"); + SetLong("This is a magical area containing examples of the various " + "races available to creators for their areas. Normally these creatures " + "would not be found all crowded together like this, but a powerful " + "magic keeps them bound here so that mud staff can analyze and test them. " + "There are more creatures to the south, east, and west."); + SetExits( ([ + "south" : "/domains/default/room/menagerie_south", + "east" : "/domains/default/room/menagerie_e", + "west" : "/domains/default/room/menagerie_w", + "up" : "/domains/default/room/wiz_corr_south", + ]) ); + SetInventory(([ + "/domains/default/npc/horse" : 1, + "/domains/default/npc/bird" : 1, + "/domains/default/npc/elephant" : 1, + "/domains/default/npc/bat" : 1, + "/domains/default/npc/newt" : 1, + "/domains/default/npc/lynx" : 1, + "/domains/default/npc/deer" : 1, + "/domains/default/npc/spider" : 1, + "/domains/default/npc/bear" : 1, + "/domains/default/npc/dryad" : 1, + "/domains/default/npc/rat" : 1, + "/domains/default/npc/zookeeper" : 1, + "/domains/default/npc/cow" : 1, + "/domains/default/npc/centaur" : 1, + "/domains/default/npc/gnome" : 1, + "/domains/default/npc/moth" : 1, + "/domains/default/npc/gecko" : 1, + ])); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/begin/room/menagerie_e.c b/lib/domains/begin/room/menagerie_e.c new file mode 100644 index 0000000..44691d4 --- /dev/null +++ b/lib/domains/begin/room/menagerie_e.c @@ -0,0 +1,32 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("Menagerie, east"); + SetLong("This is the eastern annex of the menagerie."); + SetInventory(([ + "/domains/default/npc/foochy" : 1, + "/domains/default/npc/satyr" : 1, + "/domains/default/npc/slug" : 1, + "/domains/default/npc/unicorn" : 1, + "/domains/default/npc/triffid" : 1, + "/domains/default/npc/snake" : 1, + "/domains/default/npc/sheep" : 1, + "/domains/default/npc/boar" : 1, + "/domains/default/npc/pegasus" : 1, + "/domains/default/npc/giant" : 1, + "/domains/default/npc/lemur" : 1, + "/domains/default/npc/treant" : 1, + ])); + SetExits(([ + "west" : "/domains/default/room/menagerie", + ])); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/begin/room/menagerie_south.c b/lib/domains/begin/room/menagerie_south.c new file mode 100644 index 0000000..ab3442e --- /dev/null +++ b/lib/domains/begin/room/menagerie_south.c @@ -0,0 +1,37 @@ +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Menagerie Annex"); + SetLong("This area was added to the menagerie to allow a little leg room for creatures that like to wander."); + SetInventory(([ + "/domains/default/npc/chimera" : 1, + "/domains/default/npc/ogre" : 1, + "/domains/default/npc/orc" : 1, + "/domains/default/npc/red_dragon" : 1, + "/domains/default/npc/bacchus" : 1, + "/domains/default/npc/minotaur" : 1, + "/domains/default/npc/goblin" : 1, + "/domains/default/npc/golem" : 1, + "/domains/default/npc/troll" : 1, + "/domains/default/npc/klingon" : 1, + "/domains/default/npc/gargoyle" : 1, + "/domains/default/npc/balrog" : 1, + "/domains/default/npc/kobold" : 1, + "/domains/default/npc/wraith" : 1, + "/domains/default/npc/yattering" : 1, + "/domains/default/npc/gnoll" : 1, + "/domains/default/npc/elemental" : 1, + ])); + SetExits(([ + "north" : "/domains/default/room/menagerie", + ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/begin/room/menagerie_w.c b/lib/domains/begin/room/menagerie_w.c new file mode 100644 index 0000000..547a36f --- /dev/null +++ b/lib/domains/begin/room/menagerie_w.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("Menagerie, west"); + SetLong("This is the western annex of the menagerie."); + SetInventory(([ + "/domains/default/npc/dwarf" : 1, + "/domains/default/npc/helf" : 1, + "/domains/default/npc/artrell" : 1, + "/domains/default/npc/halfling" : 1, + "/domains/default/npc/nymph" : 1, + "/domains/default/npc/avidryl" : 1, + "/domains/default/npc/faerie" : 1, + "/domains/default/npc/hobbit" : 1, + "/domains/default/npc/pessis" : 1, + "/domains/default/npc/kender" : 1, + "/domains/default/npc/zoe" : 1, + ])); + SetExits(([ + "east" : "/domains/default/room/menagerie", + ])); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/begin/room/pod.c b/lib/domains/begin/room/pod.c new file mode 100644 index 0000000..62da2f9 --- /dev/null +++ b/lib/domains/begin/room/pod.c @@ -0,0 +1,16 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("the incept pod"); + SetLong("The incept pod. Some objects come here to be created "+ + "and identified. Go down to get out."); + SetExits( ([ "down" : ROOM_START ]) ); +} +int CanReceive(object ob){ + return room::CanReceive(ob); +} diff --git a/lib/domains/begin/room/quarantine1.c b/lib/domains/begin/room/quarantine1.c new file mode 100644 index 0000000..e9360dc --- /dev/null +++ b/lib/domains/begin/room/quarantine1.c @@ -0,0 +1,44 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Disease Lab Prep Room"); + SetLong("This room is designed to repel the spread of diseases that are tested in the room downstairs. It is also where you can get a disease repellent collar, so you may work in the quarantine area without becoming infected. To infect the test subjects use the medical tricorder. To make all of them healthy again, type 'update', which will reset the room. The test subjects are waiting for you below."); + SetExits( ([ + "south" : "/domains/default/room/wiz_corr1", + "down" : "/domains/default/room/quarantine2.c", + ]) ); + SetInventory(([ + "/domains/default/obj/collarchest" : 1, + ])); + + SetProperty("no attack", 1); + +} +int CanReceive(object ob) { + object *inv; + string taxonomy; + + if(inherits(LIB_GERM,ob)) return 0; + + inv = deep_inventory(ob); + foreach(object thing in inv){ + if(inherits(LIB_GERM,thing)) { + write("%^YELLOW%^A parasite has been discovered on your body! It is being automatically removed.%^RESET%^"); + if(taxonomy = thing->GetGermName()) write("%^YELLOW%^Removing: "+taxonomy+".%^RESET%^"); + thing->eventMove(ROOM_FURNACE); + } + } + + return room::CanReceive(); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/begin/room/quarantine2.c b/lib/domains/begin/room/quarantine2.c new file mode 100644 index 0000000..69c2a8b --- /dev/null +++ b/lib/domains/begin/room/quarantine2.c @@ -0,0 +1,39 @@ +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Disease Lab"); + SetLong("This room is designed for testing the effects and transmissibility of disease. Another testing area is east."); + SetExits( ([ + "east" : "/domains/default/room/quarantine3", + "up" : "/domains/default/room/quarantine1", + ]) ); + SetNoClean(1); + SetInventory(([ + "/domains/default/npc/quarantine/wim" : 1, + "/domains/default/npc/quarantine/rik" : 1, + "/domains/default/npc/quarantine/han" : 1, + "/domains/default/npc/quarantine/tom" : 1, + "/domains/default/npc/quarantine/lex" : 1, + "/domains/default/npc/quarantine/jan" : 1, + "/domains/default/npc/quarantine/ted" : 1, + "/domains/default/npc/quarantine/pip" : 1, + "/domains/default/npc/quarantine/cor" : 1, + "/domains/default/npc/quarantine/kip" : 1, + "/domains/default/npc/quarantine/job" : 1, + "/domains/default/npc/quarantine/ton" : 1 + ])); + AddItem(new("/domains/default/obj/reset_button")); + +} +int CanReceive(object ob) { + return room::CanReceive(); +} +void init(){ + ::init(); +} diff --git a/lib/domains/begin/room/quarantine3.c b/lib/domains/begin/room/quarantine3.c new file mode 100644 index 0000000..9a8e6e0 --- /dev/null +++ b/lib/domains/begin/room/quarantine3.c @@ -0,0 +1,37 @@ +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Disease Lab Annex"); + SetLong("This room is designed for testing the effects and transmissibility of disease. Another testing area is west."); + SetExits( ([ + "west" : "/domains/default/room/quarantine2", + ]) ); + SetInventory(([ + "/domains/default/npc/quarantine/nigel" : 1, + "/domains/default/npc/quarantine/graham" : 1, + "/domains/default/npc/quarantine/duncan" : 1, + "/domains/default/npc/quarantine/trevor" : 1, + "/domains/default/npc/quarantine/simon" : 1, + "/domains/default/npc/quarantine/spencer" : 1, + "/domains/default/npc/quarantine/gavin" : 1, + "/domains/default/npc/quarantine/adrian" : 1, + "/domains/default/npc/quarantine/miles" : 1, + "/domains/default/npc/quarantine/edmund" : 1, + "/domains/default/npc/quarantine/wallace" : 1, + "/domains/default/npc/quarantine/lester" : 1, + ])); + SetNoClean(1); + AddItem(new("/domains/default/obj/reset_button")); +} +int CanReceive(object ob) { + return room::CanReceive(); +} +void init(){ + ::init(); +} diff --git a/lib/domains/begin/room/stargate_lab.c b/lib/domains/begin/room/stargate_lab.c new file mode 100644 index 0000000..a46a394 --- /dev/null +++ b/lib/domains/begin/room/stargate_lab.c @@ -0,0 +1,49 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_ROOM; + +int SignRead(){ + string list; + list = implode(keys(STARGATE_D->GetStargates()),", "); + write("These are Stargate operation instructions."); + write("The Dead Souls stargate system provides teleportation within " + "the stargate network. To use the stargate network, one finds an " + "idle stargate, then dials the name of some other known stargate. " + "One then enters the outbound stargate, and if things go well, teleportation " + "to the dialed stargate occurs. To travel to Uruk, if that were a " + "valid stargate name, you would: dial uruk\n" + "Once the stargate activates: enter stargate"); + write("Currently available stargates are:"); + write("%^BOLD%^%^YELLOW%^"+list+"%^RESET%^"); + return 1; +} + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Stargate Lab"); + SetLong("This is the test laboratory for the new Dead Souls Stargate system.\n" + "%^BOLD%^%^GREEN%^An instruction sign is here.%^RESET%^"); + SetItems(([ + ({ "sign", "instruction sign", "instructions sign", "instruction", "instructions" }) : "A sign you can read. It appears to be instructions for operating the stargate.", + ])); + SetExits( ([ + "north" : "/domains/default/room/wiz_corr_east2.c", + ]) ); + SetInventory(([ + "/domains/default/obj/stargate" : 1, + ])); + SetRead("sign", (: SignRead() :) ); + SetProperty("no attack", 1); + +} +int CanReceive(object ob) { + return room::CanReceive(); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/begin/room/start.c b/lib/domains/begin/room/start.c new file mode 100644 index 0000000..829a2d6 --- /dev/null +++ b/lib/domains/begin/room/start.c @@ -0,0 +1,47 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +int tutorial = 0; + +string DoDesc(){ + string desc = "Welcome! To enter Oogtopia, type: %^%^GREEN%^%^enter oogtopia%^%^RESET%^%^\n\nTo enter Voluntaria type: %^%^GREEN%^%^enter voluntaria%^%^RESET%^%^\n\n"; + string desc2 = "To enter a tutorial area, type: %^%^RED%^%^enter tutorial\n\n%^%^RESET%^%^"; + return desc + ( tutorial ? desc2 : ""); +} + +void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("The start room"); + SetLong( (: DoDesc :)); + SetExits( ([ + "south" : "/domains/default/room/wiz_hall", + ]) ); + SetNoModify(1); + SetCoordinates("5000,5000,0"); + SetItems( ([ + "tutorial" : "A set of rooms to get familiar with this environment.", + "town" : "The main town.", + "oogtopia" : "A planet full of nature loving Anarcho-Primitivists, or, as they are affectionately known, Ooga Boogas.", + "voluntaria" : "A planet full of Voluntaryists, also known as Anarcho-Capitalists" + ]) ); + SetEnters( ([ + //"tutorial" : "/domains/tutorial/room/start", + "town" : "/domains/town/room/start", + "oogtopia" : "/domains/oogtopia/room/start", + "voluntaria" : "/domains/voluntaria/room/start", + ]) ); + SetInventory(([ + "/domains/default/obj/cheatbook" : 1 + ]) ); + if(tutorial){ + AddEnter("tutorial", "/domains/tutorial/room/start"); + } +} + +void init(){ + ::init(); +} diff --git a/lib/domains/begin/room/telnet_room.c b/lib/domains/begin/room/telnet_room.c new file mode 100644 index 0000000..2d59c8c --- /dev/null +++ b/lib/domains/begin/room/telnet_room.c @@ -0,0 +1,64 @@ +#include <lib.h> +#include <daemons.h> +#include ROOMS_H + +inherit LIB_ROOM; + +string LoadIP(){ + if(INTERMUD_D->GetMudList()["Dead Souls Dev"]){ + return INTERMUD_D->GetMudList()["Dead Souls Dev"][1]; + } + else return "127.0.0.1"; +} + +string LoadPort(){ + if(INTERMUD_D->GetMudList()["Dead Souls Dev"]){ + return INTERMUD_D->GetMudList()["Dead Souls Dev"][2]; + } + else return ""+query_host_port(); +} + +void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("the telnet room"); + SetLong("From this room, you can attempt "+ + "to connect to Dead Souls Dev. This is useful if you "+ + "need to ask questions but the intermud connection is down. "+ + "Note that being in charmode interferes with input. "+ + "\n\tIf the connection "+ + "fails, email cratylus@comcast.net to ask for help. "+ + "Once you connect to Dead Souls Dev, type \"dcon\" to "+ + "return to your own mud. \n\n"+ + "To connect type \"connect\" \n"+ + "The Creators' Hall annex is west of here."); + SetExits( ([ + "west" : "/domains/default/room/wiz_hall2", + ]) ); + SetNoModify(1); +} + +void init(){ + object ding; + ::init(); + if(!present("telnet_room_client",this_player())){ + ding=new("/secure/obj/tc"); + ding->eventMove(this_player()); + ding->SetConnection(LoadIP()+" "+LoadPort()); + } +} + +int CanRelease(object ob){ + if(present("telnet_room_client",ob)){ + present("telnet_room_client",ob)->eventDestruct(); + } + return 1; +} + +int CanReceive(object ob) { + if(interactive(ob)){ + tell_object(this_object(),ob->GetName()+" is about to enter the telnet room."); + } + return 1; +} diff --git a/lib/domains/begin/room/test.c b/lib/domains/begin/room/test.c new file mode 100644 index 0000000..25f49aa --- /dev/null +++ b/lib/domains/begin/room/test.c @@ -0,0 +1,19 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("The start room"); + SetLong("The default start room. To enter "+ + "a sample set of rooms, go down."); + SetExits( ([ + "down" : "/domains/town/room/road", + ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/begin/room/vacuum.c b/lib/domains/begin/room/vacuum.c new file mode 100644 index 0000000..ea26a6a --- /dev/null +++ b/lib/domains/begin/room/vacuum.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include ROOMS_H +#include <respiration_types.h> + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("An airless room"); + SetLong("A room whose only purpose is to have nothing to breathe."); + SetRespirationType(R_VACUUM); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/begin/room/void.c b/lib/domains/begin/room/void.c new file mode 100644 index 0000000..622a4ac --- /dev/null +++ b/lib/domains/begin/room/void.c @@ -0,0 +1,16 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("the void"); + SetLong("The void. Go down to get out."); + SetExits( ([ "down" : ROOM_START ]) ); + SetNoModify(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/begin/room/wiz_corr1.c b/lib/domains/begin/room/wiz_corr1.c new file mode 100644 index 0000000..28fdaa1 --- /dev/null +++ b/lib/domains/begin/room/wiz_corr1.c @@ -0,0 +1,30 @@ +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Test Labs Corridor West"); + SetLong("This is the west end of main corridor of the test labs. North is the disease lab. The Creators Hall is west of here, and corridor continues east."); + SetExits( ([ + "north" : "/domains/default/room/quarantine1", + "east" : "/domains/default/room/wiz_corr_east", + "west" : "/domains/default/room/wiz_hall", + ]) ); + + SetInventory(([ + ])); + + SetProperty("no attack", 1); + +} +int CanReceive(object ob) { + return room::CanReceive(); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/begin/room/wiz_corr_east.c b/lib/domains/begin/room/wiz_corr_east.c new file mode 100644 index 0000000..8c29c79 --- /dev/null +++ b/lib/domains/begin/room/wiz_corr_east.c @@ -0,0 +1,31 @@ +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Test Labs Corridor"); + SetLong("This is the main corridor of the test labs. North is the combat arena. South is the menagerie. The corridor continues east and west."); + SetExits( ([ + "south" : "/domains/default/room/wiz_corr_south", + "west" : "/domains/default/room/wiz_corr1", + "north" : "/domains/default/room/arena", + "east" : "/domains/default/room/wiz_corr_east2.c", + ]) ); + SetInventory(([ + ])); + + + SetDoor("north", "/domains/default/doors/steel_door2.c"); + +} +int CanReceive(object ob) { + return room::CanReceive(); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/begin/room/wiz_corr_east2.c b/lib/domains/begin/room/wiz_corr_east2.c new file mode 100644 index 0000000..7f8bee1 --- /dev/null +++ b/lib/domains/begin/room/wiz_corr_east2.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Test Labs Corridor East"); + SetLong("This is the main corridor of the test labs. The corridor runs east and west. South is the stargate lab."); + SetExits( ([ + "east" : "/domains/default/room/wiz_corr_east3", + "west" : "/domains/default/room/wiz_corr_east", + "south" : "/domains/default/room/stargate_lab.c", + ]) ); + SetProperty("no attack", 1); +} + +int CanReceive(object ob) { + return room::CanReceive(); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/begin/room/wiz_corr_east3.c b/lib/domains/begin/room/wiz_corr_east3.c new file mode 100644 index 0000000..9c23fc8 --- /dev/null +++ b/lib/domains/begin/room/wiz_corr_east3.c @@ -0,0 +1,44 @@ +#include <lib.h> + +inherit LIB_ROOM; + +int PreExit(mixed args...){ + object *livings; + string duderace = this_player()->GetRace(); + if(sizeof(users()) > 210) return 1; + livings = get_livings(this_object()); + foreach(object living in livings){ + if(base_name(living) == "/domains/default/vehicle/strider" && + previous_object(2) != living ){ + write("The strider is in your way."); + return 0; + } + } + return 1; +} + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Test Labs Corridor East"); + SetLong("This is the main corridor of the test labs. East is the mounted combat arena. The corridor runs west from here."); + SetExits( ([ + "west" : "/domains/default/room/wiz_corr_east2", + ]) ); + AddExit("east", "/domains/default/virtual/arena/5005,4999", (: PreExit :)); + SetInventory(([ + "/domains/default/vehicle/strider" : 1, + ])); + + SetProperty("no attack", 1); + +} +int CanReceive(object ob) { + return room::CanReceive(); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/begin/room/wiz_corr_south.c b/lib/domains/begin/room/wiz_corr_south.c new file mode 100644 index 0000000..f140230 --- /dev/null +++ b/lib/domains/begin/room/wiz_corr_south.c @@ -0,0 +1,35 @@ +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Menagerie Corridor"); + SetLong("This short corridor leads down to the menagerie. This corridor has been specially created to repel NPC's, so that the creatures below do not escape. The main test lab corridor is north."); + SetExits( ([ + "north" : "/domains/default/room/wiz_corr_east", + "down" : "/domains/default/room/menagerie.c", + ]) ); + + SetInventory(([ + ])); + +} +int CanReceive(object ob) { + //if(living(ob) && !creatorp(ob) && !present("testchar badge",ob)) { + // message("info","Creator staff only, sorry.", ob); + // return 0; + // } + if(living(ob) && !interactive(ob)){ + message("info","NPC's not allowed, sorry.", ob); + return 0; + } + return room::CanReceive(ob); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/begin/room/wiz_hall.c b/lib/domains/begin/room/wiz_hall.c new file mode 100644 index 0000000..60d54da --- /dev/null +++ b/lib/domains/begin/room/wiz_hall.c @@ -0,0 +1,99 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; +int ds; + +string LongDesc(){ + string desc = "Immortals come here to communicate with each other about "+ + "the world they are building. The default start room is "+ + "north. The Arch Room is south."+ + (!(ds) ? " To visit the Dead Souls "+ + "test and development mud, visit the upstairs annex." : "")+ + " The test lab facilities are east."; + desc += "\nA sign reads: "+load_object(ROOM_ARCH)->SignRead(); + return desc; +} + +static void create() { + object ob; + room::create(); + if(mud_name() == "Dead Souls"){ + ds = 1; + } + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Creators' Hall"); + SetLong( (: LongDesc :) ); + SetProperty("no attack", 1); + SetProperty("nopeer",1); + ob = new("/lib/bboard"); + ob->SetKeyName("chalkboard"); + ob->SetId( ({ "board", "chalkboard", "dusty board", "dusty chalkboard" }) ); + ob->set_board_id("immortal_board"); + ob->set_max_posts(30); + ob->SetShort("a dusty chalkboard"); + ob->eventMove(this_object()); + SetInventory(([ + "/domains/default/npc/tree" : ({ 10, 1 }), + "/domains/default/obj/chest" : 1 ])); + SetItems( ([ + ({"sign"}) : "A sign you can read.", + ]) ); + SetExits( ([ + "south" : "/secure/room/arch", + "north" : "/domains/default/room/start", + "east" : "/domains/default/room/wiz_corr1", + "up" : "/domains/default/room/wiz_hall2.c", + ]) ); + SetRead("sign", (: load_object(ROOM_ARCH)->SignRead() :) ); +} + +int CanReceive(object sneak) { + object *living_stack = get_livings(sneak); + if(!living_stack || !arrayp(living_stack)) living_stack = ({ sneak }); + foreach(object ob in living_stack){ + if(living(ob) && !creatorp(ob) && + base_name(ob) != "/domains/default/npc/tree" && + base_name(ob) != "/secure/npc/arch_wraith" && + base_name(ob) != "/domains/default/npc/drone3" && + base_name(ob) != "/secure/obj/floodmapper" && + !member_group(ob,"TEST")) { + message("info","Creator staff only, sorry.", ob); + return 0; + } + } + return ::CanReceive(sneak); +} + +int eventReceiveObject(object ob){ + string race = ob->GetRace(); + int ret = ::eventReceiveObject(ob); + if(!ret) return 0; + if(race && race == "orc"){ + ob->eventPrint("Welcome to our inclusive halls, proud orc!"); + } + if(ob->GetInvis()){ + tell_room(this_object(), capitalize(ob->GetKeyName())+ + " enters invisibly.", ({ ob }) ); + ob->eventPrint("%^BOLD%^%^RED%^Your invisible entry has "+ + "been announced.%^RESET%^"); + } + return ret; +} + +int eventReleaseObject(object ob){ + int ret = ::eventReleaseObject(ob); + if(!ret) return 0; + if(ob->GetInvis()){ + tell_room(this_object(), capitalize(ob->GetKeyName())+ + " exits invisibly.", ({ ob }) ); + ob->eventPrint("%^BOLD%^%^RED%^Your invisible exit has "+ + "been announced.%^RESET%^"); + } + return ret; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/begin/room/wiz_hall2.c b/lib/domains/begin/room/wiz_hall2.c new file mode 100644 index 0000000..52dfc25 --- /dev/null +++ b/lib/domains/begin/room/wiz_hall2.c @@ -0,0 +1,57 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; +int ds; + +static void create() { + object ob; + room::create(); + if(mud_name() == "Dead Souls"){ + ds = 1; + } + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Creators' Hall Upstairs"); + SetLong("This is the upstairs annex of the Creators' Hall. East is the telnet room where you can connect to the Dead Souls test and development mud. South is the domains room, where you can conveniently visit featured domains or realms. The main hall is below."); + SetProperty("no attack", 1); + SetProperty("nopeer",1); + ob = new("/lib/bboard"); + ob->SetKeyName("chalkboard"); + ob->SetId( ({ "board", "chalkboard", "dusty board", "dusty chalkboard" }) ); + ob->set_board_id("immortal_board"); + ob->set_max_posts(30); + SetShort("Creators' Hall West Wing"); + ob->eventMove(this_object()); + SetItems( ([ + ({"sign"}) : "A sign you can read.", + ]) ); + SetExits( ([ + "south" : "/domains/default/room/domains_room", + "down" : "/domains/default/room/wiz_hall", + "east" : "/domains/default/room/telnet_room.c", + ]) ); + if(!ds){ + } + SetInventory(([ + ])); + + SetRead("sign", (: load_object(ROOM_ARCH)->SignRead() :) ); +} + +int CanReceive(object ob) { + if(playerp(ob) && !creatorp(ob) && + !member_group(ob,"TEST")) { + message("info","Creator staff only, sorry.", ob); + return 0; + } + + if(ob->GetRace() == "rodent"){ + message("info","You are repelled by rodenticide.",ob); + return 0; + } + return 1; +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/adm/README b/lib/domains/campus/adm/README new file mode 100644 index 0000000..2ddcbe3 --- /dev/null +++ b/lib/domains/campus/adm/README @@ -0,0 +1,14 @@ + The Administrative Directory + +This directory contains files necessary for domain administration. + +Specifically it is the default directory for the access object, +which is used for providing nonstandard access to files with +the "grant" command. + +This is also the location where domain-specific daemons can be +expected to reside. + +In the case of archaic domains, such as Ylsrim, this is where +some mandatory rooms are expected to be, such as freezer.c and void.c + diff --git a/lib/domains/campus/armor/badge.c b/lib/domains/campus/armor/badge.c new file mode 100644 index 0000000..6f49187 --- /dev/null +++ b/lib/domains/campus/armor/badge.c @@ -0,0 +1,50 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("visitor's pass"); + SetId(({"testchar badge","badge","pass","visitor's pass"})); + SetShort("a test character Visitor's Pass"); + SetLong("This clip-on plastic badge grants the wearer access to "+ + "some areas typically restricted to creator staff only. Abuse of this "+ + "pass is grounds for disciplinary action. A small scribble "+ + "at the bottom of the pass reads: click heels"); + SetMass(10); + SetDollarCost(5000); + SetDamagePoints(100); + SetArmorType(A_AMULET); + SetRetainOnDeath(1); + SetRestrictLimbs( ({ "torso" }) ); +} +void init(){ + ::init(); + add_action("nplh","click"); + add_action("post_it","post"); +} +int nplh(string str){ + if(str=="heels"){ + if(present(this_object()->GetKeyName(),this_player() ) ){ + write("There's no place like home!\n"+ + "You are transported by an awesome whirlwind somewhere "+ + "else...\n"); + this_player()->eventMoveLiving("/domains/campus/room/start"); + return 1; + } + write("You click your heels together...but feel "+ + "as though you're missing something.\n"); + return 1; + } +} +int post_it(string str){ + if(present("chalkboard",environment(this_player())) && !creatorp(this_player()) ){ + write("As a visitor, you are not allowed to post on creator boards."); + return 1; + } +} +string GetAffectLong(object ob) { + if(!ob || !living(ob)) return 0; + return ob->GetName() + " is an authorized Test Character."; +} diff --git a/lib/domains/campus/armor/badge2.c b/lib/domains/campus/armor/badge2.c new file mode 100644 index 0000000..edf53be --- /dev/null +++ b/lib/domains/campus/armor/badge2.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("identification badge"); + SetId(({"badge","pass","id","i.d.","pass of dr kleiner"})); + SetAdjectives( ({"clip on", "plastic", "id","i.d.","access","kleiner"}) ); + SetShort("an identification badge"); + SetLong("This clip-on plastic badge grants the owner access to "+ + "restricted areas. There is a photo of someone on it, as well "+ + "as some writing."); + SetMass(10); + SetDollarCost(5); + SetDamagePoints(100); + SetArmorType(A_AMULET); + SetRestrictLimbs( ({ "torso" }) ); + SetReads( ([ + "default" : "Isaac Kleiner, Ph.D.", + "writing" : "Isaac Kleiner, Ph.D.", + ]) ); + SetItems( ([ + ({"photo","picture","photograph"}) : "An older, white-haired "+ + "gentleman, wearing an affable, goofy grin.", + ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/armor/bandanna.c b/lib/domains/campus/armor/bandanna.c new file mode 100644 index 0000000..02d03f7 --- /dev/null +++ b/lib/domains/campus/armor/bandanna.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("bandanna"); + SetAdjectives( ({"red"}) ); + SetId( ({"kerchief", "handkerchief"}) ); + SetShort("a red bandanna"); + SetLong("This is a red kerchief fashioned into improvised headgear, possibly to prevent getting dirt on one's hair and vice versa."); + SetMass(1); + SetBaseCost("silver",1); + SetArmorType(A_HELMET); + SetProtection(BLUNT, 1); + SetProtection(BLADE, 1); + SetProtection(KNIFE, 1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/armor/bdu.c b/lib/domains/campus/armor/bdu.c new file mode 100644 index 0000000..285d304 --- /dev/null +++ b/lib/domains/campus/armor/bdu.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("battle dress uniform"); + SetId(({"uniform","bdu","bdu's","fatigues"})); + SetAdjectives(({"camouflage","battle","dress","combat"})); + SetShort("a battle dress uniform"); + SetLong("This uniform consists of a camouflage blouse and "+ + "pants. It is green with mottled brown and black camouflage patterns, "+ + "and probably provides excellent concealment in a wooded environment."); + SetMass(10); + SetDollarCost(100); + SetDamagePoints(100); + SetArmorType(A_BODY_ARMOR); +} diff --git a/lib/domains/campus/armor/bluedress.c b/lib/domains/campus/armor/bluedress.c new file mode 100644 index 0000000..82865af --- /dev/null +++ b/lib/domains/campus/armor/bluedress.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("blue dress"); + SetId(({"dress","outfit","costume"})); + SetAdjectives(({"blue","cotton","lovely","light"})); + SetShort("a lovely blue dress"); + SetLong("This is a lovely little blue dress of simple, "+ + "efficient design, yet obviously comfortable and practical. The hem is at "+ + "the knees, and the fabric feels soft and light yet strong, like some sort of cotton."); + SetMass(10); + SetDollarCost(100); + SetDamagePoints(100); + SetArmorType(A_BODY_ARMOR); +} diff --git a/lib/domains/campus/armor/cap.c b/lib/domains/campus/armor/cap.c new file mode 100644 index 0000000..ef1cb4b --- /dev/null +++ b/lib/domains/campus/armor/cap.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("baseball cap"); + SetAdjectives( ({"red", "old", "greasy", "dirty", "baseball", "cat"}) ); + SetId( ({"cap", "hat", "cover"}) ); + SetShort("a red baseball cap"); + SetLong("A greasy, old, dirty baseball cap that was once mostly red, with " + "the word 'CAT' on the front."); + SetMass(5); + SetBaseCost("silver",1); + SetArmorType(A_HELMET); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/armor/chainmail.c b/lib/domains/campus/armor/chainmail.c new file mode 100644 index 0000000..7bd77f9 --- /dev/null +++ b/lib/domains/campus/armor/chainmail.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("chainmail shirt"); + SetId(({"armor","chainmail armor","chain mail armor","shirt","chainmail shirt","chainmail","chain mail shirt"})); + SetShort("a sturdy-looking chainmail shirt"); + SetLong("This is a shirt made of metal rings fashioned together as armor. "); + SetMass(75); + SetDollarCost(100); + SetDamagePoints(100); + SetProtection(BLUNT,4); + SetProtection(BLADE,25); + SetProtection(KNIFE,25); + SetArmorType(A_BODY_ARMOR); +} diff --git a/lib/domains/campus/armor/coat.c b/lib/domains/campus/armor/coat.c new file mode 100644 index 0000000..8bc18ef --- /dev/null +++ b/lib/domains/campus/armor/coat.c @@ -0,0 +1,19 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("lab coat"); + SetId(({"coat","labcoat"})); + SetAdjectives(({"lab","science","white","long"})); + SetShort("a lab coat"); + SetLong("This is a long white lab coat of the type used by scientists "+ + "to avoid getting experimental results on themselves."); + SetMass(75); + SetDollarCost(20); + SetArmorType(A_CLOAK); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/armor/collar.c b/lib/domains/campus/armor/collar.c new file mode 100644 index 0000000..369c194 --- /dev/null +++ b/lib/domains/campus/armor/collar.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +inherit LIB_BANE; + +static void create(){ + armor::create(); + SetKeyName("collar"); + SetId(({"repellent_collar","bane"})); + SetAdjectives( ({"repellent","odd","plastic","white"}) ); + SetShort("a plastic collar"); + SetLong("This is a simple collar made of a soft white plastic. It "+ + "seems to be coated with a fine, clear resin. There is something "+ + "written on the collar."); + SetRead("Disease and parasite repellent collar, test character use only."); + SetMass(1); + SetDollarCost(5000); + SetDamagePoints(100); + SetArmorType(A_AMULET); + SetBane(({"all"})); +} diff --git a/lib/domains/campus/armor/dress.c b/lib/domains/campus/armor/dress.c new file mode 100644 index 0000000..52508c9 --- /dev/null +++ b/lib/domains/campus/armor/dress.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("pink dress"); + SetId(({"dress","outfit","costume"})); + SetAdjectives(({"pink","cotton","lovely","light"})); + SetShort("a lovely pink dress"); + SetLong("This is a lovely little pink dress of simple, "+ + "efficient design, yet obviously comfortable and practical. The hem is at "+ + "the knees, and the fabric feels soft and light yet strong, like some sort of cotton."); + SetMass(10); + SetDollarCost(100); + SetDamagePoints(100); + SetArmorType(A_BODY_ARMOR); +} diff --git a/lib/domains/campus/armor/foodsmock.c b/lib/domains/campus/armor/foodsmock.c new file mode 100644 index 0000000..19a81ca --- /dev/null +++ b/lib/domains/campus/armor/foodsmock.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("uniform"); + SetAdjectives( ({"food workers","food worker's"}) ); + SetId( ({"overalls", "smock"}) ); + SetShort("a food worker's uniform"); + SetLong("This is a set of overalls used by food workers to keep their bodies and the food at a healthy distance."); + SetMass(50); + SetArmorType(A_BODY_ARMOR); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/armor/glove.c b/lib/domains/campus/armor/glove.c new file mode 100644 index 0000000..f02054b --- /dev/null +++ b/lib/domains/campus/armor/glove.c @@ -0,0 +1,32 @@ +/* /domains/Examples/armor/glove.c + * from the Dead Souls LPC Library + * an example glove + * created by Descartes of Borg 950408 + */ + +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ARMOR; + +static void create() { + armor::create(); + SetKeyName("red glove"); + SetId( ({ "glove", "red glove" }) ); + SetAdjectives( ({ "red" }) ); + SetShort("a red glove"); + SetLong("A red glove with five fingers."); + SetDamagePoints(75); + SetVendorType(VT_ARMOR); + SetMass(50); + SetValue(20); + SetArmorType(A_GLOVE); + SetProtection(BLUNT, 1); + SetProtection(BLADE, 1); + SetProtection(KNIFE, 2); + SetProtection(HEAT, 3); + SetProtection(COLD, 7); + SetFingers(5); +} diff --git a/lib/domains/campus/armor/handbag.c b/lib/domains/campus/armor/handbag.c new file mode 100644 index 0000000..62d3bf8 --- /dev/null +++ b/lib/domains/campus/armor/handbag.c @@ -0,0 +1,24 @@ +#include <lib.h> + +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_WORN_STORAGE; + + +static void create() { + ::create(); + SetKeyName("backpack"); + SetId(({"bookbag","bag","pack"})); + SetAdjectives(({"leather","soft","brown"})); + SetShort("a soft, brown leather backpack"); + SetLong("This is a medium-sized backpack made of soft brown leather. "+ + "It seems suitable for carrying books around, for the busy college student. "+ + "It features wide, comfortable straps for convenient wear."); + SetMass(100); + SetDollarCost(30); + SetCanClose(1); + SetClosed(1); + SetMaxCarry(500); + SetDamagePoints(100); + SetArmorType(A_CLOAK); +} diff --git a/lib/domains/campus/armor/helmet.c b/lib/domains/campus/armor/helmet.c new file mode 100644 index 0000000..ece733a --- /dev/null +++ b/lib/domains/campus/armor/helmet.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("kevlar helmet"); + SetId(({"helmet","cover","kevlar"})); + SetAdjectives(({"kevlar","battle","hard"})); + SetShort("a camouflaged kevlar helmet"); + SetLong("This is a military helmet made of a very tough "+ + "polymer fiber that provides excellent ballistic protection. It bears a "+ + "mottled camouflage design to aid in woodland concealment."); + SetMass(50); + SetDollarCost(500); + SetDamagePoints(100); + SetArmorType(A_HELMET); + SetProtection(BLUNT, 20); + SetProtection(BLADE, 20); + SetProtection(KNIFE, 20); +} diff --git a/lib/domains/campus/armor/jeans.c b/lib/domains/campus/armor/jeans.c new file mode 100644 index 0000000..bcdcf15 --- /dev/null +++ b/lib/domains/campus/armor/jeans.c @@ -0,0 +1,19 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("blue jeans"); + SetId(({"jeans","pants","blue jeans","bluejeans","denim"})); + SetAdjectives(({"blue","denim","comfortable","broken in","broken-in"})); + SetShort("a pair of blue jeans"); + SetLong("A comfortable pair of denim blue jeans."); + SetMass(5); + SetDollarCost(1); + SetDamagePoints(1); + SetProtection(BLUNT,1); + SetProtection(BLADE,1); + SetProtection(KNIFE,1); + SetArmorType(A_PANTS); +} diff --git a/lib/domains/campus/armor/necklace.c b/lib/domains/campus/armor/necklace.c new file mode 100644 index 0000000..0fe00c3 --- /dev/null +++ b/lib/domains/campus/armor/necklace.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + + +static void create(){ + armor::create(); + SetKeyName("gold necklace"); + SetId(({"necklace"})); + SetAdjectives( ({"gold","beautiful"}) ); + SetShort("a gold necklace"); + SetLong("This is a simple and beautiful gold necklace."); + SetMass(1); + SetDollarCost(5000); + SetDamagePoints(100); + SetArmorType(A_COLLAR); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/armor/newbie_cap.c b/lib/domains/campus/armor/newbie_cap.c new file mode 100644 index 0000000..101b738 --- /dev/null +++ b/lib/domains/campus/armor/newbie_cap.c @@ -0,0 +1,39 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +//inherit "/lib/events/read"; + +string eventReadBill(){ + return "The front of the cap reads: \"Kiss me, I'm a newbie!\""; +} +static void create(){ + armor::create(); + SetKeyName("baseball cap"); + SetId(({"cap","hat"})); + SetAdjectives(({"baseball"})); + SetShort("a baseball cap"); + SetLong("This baseball cap looks pretty normal, except "+ + "the trim is fine corinthian leather and the bill "+ + "is plated in what appears to be pure mithril. There is some "+ + "writing on the front of the cap."); + SetMass(50); + SetDollarCost(100); + SetDamagePoints(20); + SetArmorType(A_HELMET); + SetProtection(BLUNT, 20); + SetProtection(BLADE, 20); + SetProtection(KNIFE, 20); + SetItems( ([ + ({"brim","bill","front"}) : "For some reason the front of this cap "+ + "is plated with a fine layer of mithril...one of the strongest "+ + "and most expensive substances known to man.", + ({"writing","letters"}): "Something is written on the front of the "+ + "cap. Perhaps you could \"read writing on cap\"", + ]) ); + + SetRead( ([ + ({"front","writing","letters"}) : "The front of the cap reads: \"Kiss me, I'm a newbie!\"", + ]) ); + SetDefaultRead("default", "The front of the cap reads: \"Kiss me, I'm a newbie!\""); +} diff --git a/lib/domains/campus/armor/overalls.c b/lib/domains/campus/armor/overalls.c new file mode 100644 index 0000000..57954e8 --- /dev/null +++ b/lib/domains/campus/armor/overalls.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_WORN_STORAGE; + +static void create(){ + ::create(); + SetKeyName("overalls"); + SetId(({"overalls","pants", "trousers"})); + SetAdjectives(({"worn","abused","pair of","set of"})); + SetShort("a pair of overalls"); + SetLong("This is a set of worn and abused overall trousers with large pockets " + "for carrying stuff."); + SetMass(50); + SetMaxCarry(300); + SetBaseCost("silver",1); + SetProtection(BLUNT,1); + SetProtection(BLADE,1); + SetProtection(KNIFE,1); + SetArmorType(A_CUSTOM); + SetInventory( ([ + "/domains/campus/weap/knife" : 1, + ]) ); + SetRestrictLimbs( ({ "right leg","left leg","torso" }) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/armor/pillbox_hat.c b/lib/domains/campus/armor/pillbox_hat.c new file mode 100644 index 0000000..784f9f2 --- /dev/null +++ b/lib/domains/campus/armor/pillbox_hat.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("pillbox hat"); + SetId(({"hat"})); + SetAdjectives(({"pillbox"})); + SetShort("a light blue pillbox hat"); + SetLong("A cute little pillbox hat, light blue in "+ + "color. The inside appears to be lined with leopard "+ + "skin. Looks uncomfortable."); + SetMass(50); + SetDollarCost(50); + SetDamagePoints(10); + SetArmorType(A_HELMET); + SetProtection(BLUNT, 2); + SetProtection(BLADE, 2); + SetProtection(KNIFE, 2); +} diff --git a/lib/domains/campus/armor/ring.c b/lib/domains/campus/armor/ring.c new file mode 100644 index 0000000..a533e46 --- /dev/null +++ b/lib/domains/campus/armor/ring.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("gold_ring"); + SetId(({"ring","gold ring"})); + SetAdjectives( ({"beautiful"}) ); + SetShort("a beautiful gold ring"); + SetLong("This is a simple but beautiful ring made of "+ + "gold, suitable for wearing on one's finger."); + SetMass(1); + SetDollarCost(1000); + SetDamagePoints(100); + SetArmorType(A_RING); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/armor/ring1.c b/lib/domains/campus/armor/ring1.c new file mode 100644 index 0000000..ee36132 --- /dev/null +++ b/lib/domains/campus/armor/ring1.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("silver_ring"); + SetId(({"ring","silver ring"})); + SetAdjectives( ({"beautiful"}) ); + SetShort("a beautiful silver ring"); + SetLong("This is a simple but beautiful ring made of "+ + "silver, suitable for wearing on one's finger. The ring bears an inscription."); + SetMass(1); + SetDollarCost(1000); + SetDamagePoints(100); + SetArmorType(A_RING); + SetItems(([ + ({"script","words","inscription","writing"}) : "Words engraved on the ring in a highly "+ + "stylized script." + ]) ); + SetRead(({"script","words","inscription","writing"}), "\"etaoin shrdlu\"" ); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/armor/robe.c b/lib/domains/campus/armor/robe.c new file mode 100644 index 0000000..b191118 --- /dev/null +++ b/lib/domains/campus/armor/robe.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("wizard's robe"); + SetId(({"robe","cloak","duster"})); + SetAdjectives(({"wizard","wizard's","soft"})); + SetShort("a robe"); + SetLong("This is a large, comfortable-looking robe, like a wizard might wear. "); + SetMass(75); + SetDollarCost(100); + SetDamagePoints(100); + SetProtection(BLUNT,100); + SetProtection(BLADE,100); + SetProtection(KNIFE,100); + SetArmorType(A_CLOAK); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/armor/shield.c b/lib/domains/campus/armor/shield.c new file mode 100644 index 0000000..ef45766 --- /dev/null +++ b/lib/domains/campus/armor/shield.c @@ -0,0 +1,31 @@ +/* /domains/Examples/armor/shield.c + * from the Dead Souls LPC Library + * an example shield + * created by Lassondra@Dead Souls + */ + +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ARMOR; + +static void create() { + armor::create(); + SetKeyName("large shield"); + SetId( ({ "shield" }) ); + SetAdjectives( ({ "wood", "wooden","large" }) ); + SetShort("a large wooden shield"); + SetLong("A large, heavy shield made of strong wood banded with iron."); + SetDamagePoints(75); + SetVendorType(VT_ARMOR); + SetMass(100); + SetDollarCost(150); + SetArmorType(A_SHIELD); + SetProtection(BLUNT, 10); + SetProtection(BLADE, 10); + SetProtection(KNIFE, 10); + //SetRestrictLimbs( ({"left hand"}) ); +} + diff --git a/lib/domains/campus/armor/shirt.c b/lib/domains/campus/armor/shirt.c new file mode 100644 index 0000000..98a3128 --- /dev/null +++ b/lib/domains/campus/armor/shirt.c @@ -0,0 +1,19 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("a white t-shirt"); + SetId(({"shirt","tshirt","t-shirt","t shirt"})); + SetAdjectives(({"white"})); + SetShort("a white t-shirt"); + SetLong("An ordinary white t-shirt."); + SetMass(5); + SetDollarCost(1); + SetDamagePoints(1); + SetProtection(BLUNT,1); + SetProtection(BLADE,1); + SetProtection(KNIFE,1); + SetArmorType(A_SHIRT); +} diff --git a/lib/domains/campus/armor/silverring.c b/lib/domains/campus/armor/silverring.c new file mode 100644 index 0000000..6ef3e7a --- /dev/null +++ b/lib/domains/campus/armor/silverring.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("silver_ring"); + SetId(({"ring","silver ring"})); + SetAdjectives( ({"beautiful"}) ); + SetShort("a beautiful silver ring"); + SetLong("This is a simple but beautiful ring made of "+ + "silver, suitable for wearing on one's finger. The ring bears an inscription."); + SetMass(1); + SetDollarCost(5000); + SetDamagePoints(100); + SetArmorType(A_RING); + SetItems(([ + ({"script","words","inscription","writing"}) : "Words engraved on the ring in a highly "+ + "stylized script." + ]) ); + SetRead(({"script","words","inscription","writing"}), "\"etaoin shrdlu\"" ); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/armor/tshirt.c b/lib/domains/campus/armor/tshirt.c new file mode 100644 index 0000000..c244942 --- /dev/null +++ b/lib/domains/campus/armor/tshirt.c @@ -0,0 +1,19 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("a Def Leppard shirt"); + SetId(({"shirt"})); + SetAdjectives(({"Def Leppard", "def leppard", "stupid", "black"})); + SetShort("a Def Leppard shirt"); + SetLong("A stupid-looking black shirt with a ridiculous band logo on it."); + SetMass(5); + SetDollarCost(1); + SetDamagePoints(1); + SetProtection(BLUNT,1); + SetProtection(BLADE,1); + SetProtection(KNIFE,1); + SetArmorType(A_SHIRT); +} diff --git a/lib/domains/campus/armor/vest.c b/lib/domains/campus/armor/vest.c new file mode 100644 index 0000000..fee7108 --- /dev/null +++ b/lib/domains/campus/armor/vest.c @@ -0,0 +1,19 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("paisley vest"); + SetId(({"vest"})); + SetAdjectives(({"paisley","colorful","hippie","hippy","psychedelic"})); + SetShort("a colorful, paisley vest"); + SetLong("A stupid-looking hippie vest with psychedelic paisley patterns on it."); + SetMass(5); + SetDollarCost(1); + SetDamagePoints(1); + SetProtection(BLUNT,1); + SetProtection(BLADE,1); + SetProtection(KNIFE,1); + SetArmorType(A_VEST); +} diff --git a/lib/domains/campus/armor/wglove_l.c b/lib/domains/campus/armor/wglove_l.c new file mode 100644 index 0000000..04f56f6 --- /dev/null +++ b/lib/domains/campus/armor/wglove_l.c @@ -0,0 +1,36 @@ +/* /domains/Examples/armor/glove.c + * from the Dead Souls LPC Library + * an example glove + * created by Descartes of Borg 950408 + */ + +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ARMOR; + +static void create() { + armor::create(); + SetKeyName("white glove"); + SetId( ({ "glove" }) ); + SetAdjectives( ({ "left", "white" ,"simple","elegant"}) ); + SetShort("a white glove"); + SetLong("A simple, yet elegant white glove with five fingers for the left hand."); + SetDamagePoints(75); + SetVendorType(VT_ARMOR); + SetMass(10); + SetDollarCost(10); + SetArmorType(A_GLOVE); + SetRestrictLimbs( ({"left hand"}) ); + SetProtection(BLUNT, 1); + SetProtection(BLADE, 1); + SetProtection(KNIFE, 2); + SetProtection(HEAT, 3); + SetProtection(COLD, 7); + SetFingers(5); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/armor/wglove_r.c b/lib/domains/campus/armor/wglove_r.c new file mode 100644 index 0000000..538274c --- /dev/null +++ b/lib/domains/campus/armor/wglove_r.c @@ -0,0 +1,36 @@ +/* /domains/Examples/armor/glove.c + * from the Dead Souls LPC Library + * an example glove + * created by Descartes of Borg 950408 + */ + +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ARMOR; + +static void create() { + armor::create(); + SetKeyName("white glove"); + SetId( ({ "glove" }) ); + SetAdjectives( ({ "right", "white" ,"simple","elegant"}) ); + SetShort("a white glove"); + SetLong("A simple, yet elegant white glove with five fingers for the right hand."); + SetDamagePoints(75); + SetVendorType(VT_ARMOR); + SetMass(10); + SetDollarCost(10); + SetArmorType(A_GLOVE); + SetRestrictLimbs( ({"right hand"}) ); + SetProtection(BLUNT, 1); + SetProtection(BLADE, 1); + SetProtection(KNIFE, 2); + SetProtection(HEAT, 3); + SetProtection(COLD, 7); + SetFingers(5); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/armor/wizard_hat.c b/lib/domains/campus/armor/wizard_hat.c new file mode 100644 index 0000000..3abe308 --- /dev/null +++ b/lib/domains/campus/armor/wizard_hat.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("wizard's hat"); + SetAdjectives( ({"wizard","wizards", "floppy", "large", "conical", "blue"}) ); + SetId( ({"hat"}) ); + SetShort("a wizard's hat"); + SetLong("This is a large, floppy hat with a wide brim all "+ + "around it, and a conical center. It is dark blue in color, "+ + "and is decorated with pictures of yellow moons and stars."); + SetProperties(([ + "beta" : 2, + ])); + SetMass(50); + SetBaseCost("silver",500); + SetDamagePoints(100); + SetArmorType(A_HELMET); + SetProtection(BLUNT, 20); + SetProtection(BLADE, 20); + SetProtection(KNIFE, 20); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/armor/workboot_l.c b/lib/domains/campus/armor/workboot_l.c new file mode 100644 index 0000000..45a4b67 --- /dev/null +++ b/lib/domains/campus/armor/workboot_l.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("workboot"); + SetAdjectives( ({"strong", "brown", "leather", "left", "work", "heavy"}) ); + SetId( ({"boot"}) ); + SetShort("a brown leather workboot"); + SetLong("A heavy, brown leather workboot with strong ankle and sole support. It is designed for wear on the left foot."); + SetMass(40); + SetBaseCost("silver",25); + SetProtection(BLUNT,5); + SetProtection(BLADE,5); + SetProtection(KNIFE,5); + SetArmorType(A_BOOT); + SetRestrictLimbs(({"left foot"})); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/armor/workboot_r.c b/lib/domains/campus/armor/workboot_r.c new file mode 100644 index 0000000..b15aaaa --- /dev/null +++ b/lib/domains/campus/armor/workboot_r.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("workboot"); + SetAdjectives( ({"strong", "brown", "leather", "work", "right", "heavy"}) ); + SetId( ({"boot"}) ); + SetShort("a brown leather workboot"); + SetLong("A heavy, brown leather workboot with strong ankle and sole support. It is designed for wear on the right foot."); + SetMass(40); + SetBaseCost("silver",25); + SetProtection(BLUNT,5); + SetProtection(BLADE,5); + SetProtection(KNIFE,5); + SetArmorType(A_BOOT); + SetRestrictLimbs(({"right foot"})); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/armor/workglove_l.c b/lib/domains/campus/armor/workglove_l.c new file mode 100644 index 0000000..90bcdc3 --- /dev/null +++ b/lib/domains/campus/armor/workglove_l.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ARMOR; + +static void create() { + armor::create(); + SetKeyName("workglove"); + SetAdjectives( ({"work", "brown", "leather", "left"}) ); + SetId( ({ "glove" }) ); + SetShort("a leather work glove"); + SetLong("A thick, brown leather work glove, designed for wear on the left hand."); + SetVendorType(VT_ARMOR); + SetMass(10); + SetBaseCost("silver",7); + SetArmorType(A_GLOVE); + SetProtection(BLUNT, 1); + SetProtection(BLADE, 1); + SetProtection(KNIFE, 2); + SetProtection(HEAT, 3); + SetProtection(COLD, 7); + SetFingers(5); + SetRestrictLimbs(({"left hand"})); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/armor/workglove_r.c b/lib/domains/campus/armor/workglove_r.c new file mode 100644 index 0000000..0af383a --- /dev/null +++ b/lib/domains/campus/armor/workglove_r.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ARMOR; + +static void create() { + armor::create(); + SetKeyName("workglove"); + SetAdjectives( ({"work", "brown", "leather", "thick", "right"}) ); + SetId( ({ "glove" }) ); + SetShort("a leather work glove"); + SetLong("A thick, brown leather work glove, designed for wear on the right hand."); + SetVendorType(VT_ARMOR); + SetMass(10); + SetBaseCost("silver",7); + SetArmorType(A_GLOVE); + SetProtection(BLUNT, 1); + SetProtection(BLADE, 1); + SetProtection(KNIFE, 2); + SetProtection(HEAT, 3); + SetProtection(COLD, 7); + SetFingers(5); + SetRestrictLimbs(({"right hand"})); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/chamber/elevator.c b/lib/domains/campus/chamber/elevator.c new file mode 100644 index 0000000..9eedba6 --- /dev/null +++ b/lib/domains/campus/chamber/elevator.c @@ -0,0 +1,18 @@ +#include <lib.h> + +inherit LIB_ELEVATOR; + +void create(){ + elevator::create(); + SetSpeed(5); + SetOpacity(0); + SetFloors( ([ + -1 : ({ "b", "/domains/campus/room/shaftb" }), + 1 : ({ "1", "/domains/campus/room/shaft1" }), + 2 : ({ "2", "/domains/campus/room/shaft2" }), + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/chamber/tree.c b/lib/domains/campus/chamber/tree.c new file mode 100644 index 0000000..125098d --- /dev/null +++ b/lib/domains/campus/chamber/tree.c @@ -0,0 +1,61 @@ +#include <lib.h> +#include <climb.h> +#include <position.h> + +inherit LIB_CHAMBER; +inherit LIB_CLIMB; + +varargs mixed ClimbMe(mixed args...){ + return 1; +} + +static void create() { + ::create(); + SetKeyName("tree"); + SetId(({"oak"})); + SetAdjectives(({"large"})); + SetShort("a large tree"); + SetLong("This is a very large tree. It has been around since long "+ + "before the Virtual Campus, and looks like it will be around long "+ + "after, as well."); + SetChamberInterior("You are among the sturdy branches of "+ + "the large tree in University Square."); + SetRace("tree"); + SetPacifist(1); + SetPosition(POSITION_NULL); + SetMelee(0); + SetNoClean(1); + SetMount(1); + SetMountStyle("driven"); + SetVisibleRiders(0); + SetOpacity(0); + SetMaxHealthPoints(20); + SetMaxCarry(30000); + SetNoCondition(1); + SetAttackable(0); + SetClimb( (: ClimbMe :), CLIMB_DOWN ); + SetClimb( (: ClimbMe :), CLIMB_OUT ); + SetClimb( (: ClimbMe :), CLIMB_UP ); + SetClimb( (: ClimbMe :), CLIMB_INTO ); + SetClimb( (: ClimbMe :), CLIMB_THROUGH ); +} + +void init(){ + ::init(); +} + +varargs mixed eventClimb(object who, int type, string where){ + mixed ret; + switch(type){ + case CLIMB_DOWN: + ret = eventDismount(who); + break; + case CLIMB_OUT: + ret = eventDismount(who); + break; + default : + ret = eventMount(who); + break; + } + return ret; +} diff --git a/lib/domains/campus/doors/blue_door.c b/lib/domains/campus/doors/blue_door.c new file mode 100644 index 0000000..268c979 --- /dev/null +++ b/lib/domains/campus/doors/blue_door.c @@ -0,0 +1,27 @@ +/* /domains/Examples/etc/door.c + * from the Dead Souls LPC Library + * an example door object connecting doorroom1.c and doorroom2.c + * created by Descartes of Borg 950411 + */ + +#include <lib.h> + +inherit LIB_DOOR; + + +static void create() { + door::create(); + SetSide("blue room", ([ "id" : ({"blue door"}), + "short" : "a blue door", + "long" : "This is a blue door.", + "lockable" : 1 ]) ); + SetSide("south", ([ "id" : ({"blue door","door"}), + "short" : "a blue door", + "long" : "This is a blue door.", + "lockable" : 1 ]) ); + SetClosed(1); + SetLocked(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/doors/blue_door2.c b/lib/domains/campus/doors/blue_door2.c new file mode 100644 index 0000000..504ab7c --- /dev/null +++ b/lib/domains/campus/doors/blue_door2.c @@ -0,0 +1,27 @@ +/* /domains/Examples/etc/door.c + * from the Dead Souls LPC Library + * an example door object connecting doorroom1.c and doorroom2.c + * created by Descartes of Borg 950411 + */ + +#include <lib.h> + +inherit LIB_DOOR; + + +static void create() { + door::create(); + SetSide("blue room", ([ "id" : ({"blue door"}), + "short" : "a blue door", + "long" : "This is a blue door.", + "lockable" : 1 ]) ); + SetSide("east", ([ "id" : ({"blue door","door"}), + "short" : "a blue door", + "long" : "This is a blue door.", + "lockable" : 1 ]) ); + SetClosed(1); + SetLocked(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/doors/blue_door3.c b/lib/domains/campus/doors/blue_door3.c new file mode 100644 index 0000000..e17e926 --- /dev/null +++ b/lib/domains/campus/doors/blue_door3.c @@ -0,0 +1,27 @@ +/* /domains/Examples/etc/door.c + * from the Dead Souls LPC Library + * an example door object connecting doorroom1.c and doorroom2.c + * created by Descartes of Borg 950411 + */ + +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + SetSide("blue room", ([ "id" : ({"blue door"}), + "short" : "a blue door", + "long" : "This is a blue door.", + "lockable" : 1 ]) ); + SetSide("west", ([ "id" : ({"blue door","door"}), + "short" : "a blue door", + "long" : "This is a blue door.", + "lockable" : 1 ]) ); + SetClosed(1); + SetLocked(1); +} +void init(){ + ::init(); +} + diff --git a/lib/domains/campus/doors/eledoor1.c b/lib/domains/campus/doors/eledoor1.c new file mode 100644 index 0000000..42fd1c5 --- /dev/null +++ b/lib/domains/campus/doors/eledoor1.c @@ -0,0 +1,25 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("east", (["id" : ({ "door", "elevator door" }), + "short" : "an elevator door leading east", + "long" : "This is an elevator door.", + "lockable" : 0 ]) ); + SetSide("west", (["id" : ({ "door", "elevator door" }), + "short" : "an elevator door leading west", + "long" : "This is an elevator door.", + "lockable" : 0 ]) ); + SetClosed(1); + SetLocked(0); +} + +void init(){ + ::init(); +} +mixed CanOpen(object ob){ + return "There is no handle to open it."; +} diff --git a/lib/domains/campus/doors/eledoor2.c b/lib/domains/campus/doors/eledoor2.c new file mode 100644 index 0000000..42fd1c5 --- /dev/null +++ b/lib/domains/campus/doors/eledoor2.c @@ -0,0 +1,25 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("east", (["id" : ({ "door", "elevator door" }), + "short" : "an elevator door leading east", + "long" : "This is an elevator door.", + "lockable" : 0 ]) ); + SetSide("west", (["id" : ({ "door", "elevator door" }), + "short" : "an elevator door leading west", + "long" : "This is an elevator door.", + "lockable" : 0 ]) ); + SetClosed(1); + SetLocked(0); +} + +void init(){ + ::init(); +} +mixed CanOpen(object ob){ + return "There is no handle to open it."; +} diff --git a/lib/domains/campus/doors/eledoor3.c b/lib/domains/campus/doors/eledoor3.c new file mode 100644 index 0000000..42fd1c5 --- /dev/null +++ b/lib/domains/campus/doors/eledoor3.c @@ -0,0 +1,25 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("east", (["id" : ({ "door", "elevator door" }), + "short" : "an elevator door leading east", + "long" : "This is an elevator door.", + "lockable" : 0 ]) ); + SetSide("west", (["id" : ({ "door", "elevator door" }), + "short" : "an elevator door leading west", + "long" : "This is an elevator door.", + "lockable" : 0 ]) ); + SetClosed(1); + SetLocked(0); +} + +void init(){ + ::init(); +} +mixed CanOpen(object ob){ + return "There is no handle to open it."; +} diff --git a/lib/domains/campus/doors/grate.c b/lib/domains/campus/doors/grate.c new file mode 100644 index 0000000..43047c7 --- /dev/null +++ b/lib/domains/campus/doors/grate.c @@ -0,0 +1,37 @@ +/* /domains/Examples/etc/door.c + * from the Dead Souls LPC Library + * an example door object connecting doorroom1.c and doorroom2.c + * created by Descartes of Borg 950411 + */ + +#include <lib.h> + +inherit LIB_DOOR; +//inherit "/lib/events/close"; + +static void create() { + door::create(); + SetSide("down", ([ "id" : ({"grate","metal grate","sewer","sewer grate","rainwater grate","water grate"}), + "short" : "a drainage grate", + "long" : "This is a standard grate "+ + "for draining excess water from the road into the sewer system below.", + //Though "+ + //"it is man-sized and apparently can be opened, there is no visible way "+ + //"of opening it from up here.", + "lockable" : 0 ]) ); + SetSide("up", ([ "id" : ({"grate","metal grate","sewer","sewer grate","rainwater grate","water grate"}), + "short" : "a drainage grate", + "long" : "This is a standard drainage grate. You can see "+ + "light through it, and hear the sounds of the village above.", + "lockable" : 0 ]) ); + SetPerforated(1); + SetClosed(1); +} + +int CanOpen(object ob){ + if(base_name(environment(ob)) == "/domains/campus/room/sewer3"){ + return 1; + } + else return 0; +} + diff --git a/lib/domains/campus/doors/green_door.c b/lib/domains/campus/doors/green_door.c new file mode 100644 index 0000000..405c4eb --- /dev/null +++ b/lib/domains/campus/doors/green_door.c @@ -0,0 +1,27 @@ +/* /domains/Examples/etc/door.c + * from the Dead Souls LPC Library + * an example door object connecting doorroom1.c and doorroom2.c + * created by Descartes of Borg 950411 + */ + +#include <lib.h> + +inherit LIB_DOOR; + + +static void create() { + door::create(); + SetSide("green room", ([ "id" : ({"green door"}), + "short" : "a green door", + "long" : "This is a green door.", + "lockable" : 1 ]) ); + SetSide("south", ([ "id" : ({"green door","door"}), + "short" : "a green door", + "long" : "This is a green door.", + "lockable" : 1 ]) ); + SetClosed(1); + SetLocked(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/doors/green_door2.c b/lib/domains/campus/doors/green_door2.c new file mode 100644 index 0000000..a3ebbda --- /dev/null +++ b/lib/domains/campus/doors/green_door2.c @@ -0,0 +1,27 @@ +/* /domains/Examples/etc/door.c + * from the Dead Souls LPC Library + * an example door object connecting doorroom1.c and doorroom2.c + * created by Descartes of Borg 950411 + */ + +#include <lib.h> + +inherit LIB_DOOR; + + +static void create() { + door::create(); + SetSide("green room", ([ "id" : ({"green door"}), + "short" : "a green door", + "long" : "This is a green door.", + "lockable" : 1 ]) ); + SetSide("east", ([ "id" : ({"green door","door"}), + "short" : "a green door", + "long" : "This is a green door.", + "lockable" : 1 ]) ); + SetClosed(1); + SetLocked(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/doors/green_door3.c b/lib/domains/campus/doors/green_door3.c new file mode 100644 index 0000000..0ba55db --- /dev/null +++ b/lib/domains/campus/doors/green_door3.c @@ -0,0 +1,27 @@ +/* /domains/Examples/etc/door.c + * from the Dead Souls LPC Library + * an example door object connecting doorroom1.c and doorroom2.c + * created by Descartes of Borg 950411 + */ + +#include <lib.h> + +inherit LIB_DOOR; + + +static void create() { + door::create(); + SetSide("green room", ([ "id" : ({"green door"}), + "short" : "a green door", + "long" : "This is a green door.", + "lockable" : 1 ]) ); + SetSide("west", ([ "id" : ({"green door","door"}), + "short" : "a green door", + "long" : "This is a green door.", + "lockable" : 1 ]) ); + SetClosed(1); + SetLocked(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/doors/hatch.c b/lib/domains/campus/doors/hatch.c new file mode 100644 index 0000000..777592f --- /dev/null +++ b/lib/domains/campus/doors/hatch.c @@ -0,0 +1,24 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + SetSide("down", ([ "id" : ({"service hatch", "hatch"}), + "short" : "a hatch", + "long" : "This is a service hatch.", + "lockable" : 0 ]) ); + SetSide("up", ([ "id" : ({"service hatch", "hatch"}), + "short" : "a hatch", + "long" : "This is a service hatch.", + "lockable" : 0 ]) ); + SetClosed(1); +} + +mixed CanOpen(object ob){ + return ::CanOpen(ob); + //if(base_name(environment(ob)) == "/domains/campus/room/maintenance"){ + // return 1; + //} + //else return "There is no handle on this side."; +} diff --git a/lib/domains/campus/doors/plain_door.c b/lib/domains/campus/doors/plain_door.c new file mode 100644 index 0000000..aca9878 --- /dev/null +++ b/lib/domains/campus/doors/plain_door.c @@ -0,0 +1,23 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("south", (["id" : ({ "door", "plain wooden door", "wooden door" }), + "short" : "a door leading south", + "long" : "This is a plain wooden door.", + "lockable" : 0 ]) ); + SetSide("north", (["id" : ({ "door", "plain wooden door", "wooden door" }), + "short" : "a door leading north", + "long" : "This is a plain wooden door.", + "lockable" : 0 ]) ); + SetKeys("north", ({"prob_door_key"}) ); + SetKeys("north", ({"prob_door_key"}) ); + SetClosed(1); + SetLocked(0); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/doors/plain_door.test b/lib/domains/campus/doors/plain_door.test new file mode 100644 index 0000000..7559f9f --- /dev/null +++ b/lib/domains/campus/doors/plain_door.test @@ -0,0 +1,22 @@ +/* /domains/Examples/etc/door.c + * from the Dead Souls LPC Library + * an example door object connecting doorroom1.c and doorroom2.c + * created by Descartes of Borg 950411 + */ + +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + SetSide("north", ([ "id" : "south door", +"short" : "a door leading north", + "long" : "This is a plain wooden door.", + "lockable" : 0 ]) ); + SetSide("south", ([ "id" : "north door", +"short" : "a door leading south", + "long" : "This is a plain wooden door.", + "lockable" : 0 ]) ); +SetClosed(1); +} diff --git a/lib/domains/campus/doors/plain_door2.c b/lib/domains/campus/doors/plain_door2.c new file mode 100644 index 0000000..0acc3dc --- /dev/null +++ b/lib/domains/campus/doors/plain_door2.c @@ -0,0 +1,22 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("east", (["id" : ({ "door", "plain wooden door", "wooden door" }), + "short" : "a door leading east", + "long" : "This is a plain wooden door.", + "lockable" : 0 ]) ); + SetSide("west", (["id" : ({ "door", "plain wooden door", "wooden door" }), + "short" : "a door leading west", + "long" : "This is a plain wooden door.", + "lockable" : 0 ]) ); + SetClosed(1); + SetLocked(0); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/doors/prob_door.c b/lib/domains/campus/doors/prob_door.c new file mode 100644 index 0000000..2ebea73 --- /dev/null +++ b/lib/domains/campus/doors/prob_door.c @@ -0,0 +1,25 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("south", (["id" : ({ "door leading south", "door", "south door" }), + "short" : "a door leading south", + "long" : "This is the north side of a door leading south.", + "lockable" : 1 ]) ); + SetKeys("south", ({"prob_door_key"}) ); + + SetSide("north", (["id" : ({ "door leading north", "door", "north door" }), + "short" : "a door leading north", + "long" : "This is the south side of a door leading north.", + "lockable" : 1 ]) ); + SetKeys("north", ({"prob_door_key"}) ); + + SetClosed(1); + SetLocked(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/doors/red_door.c b/lib/domains/campus/doors/red_door.c new file mode 100644 index 0000000..35a213f --- /dev/null +++ b/lib/domains/campus/doors/red_door.c @@ -0,0 +1,27 @@ +/* /domains/Examples/etc/door.c + * from the Dead Souls LPC Library + * an example door object connecting doorroom1.c and doorroom2.c + * created by Descartes of Borg 950411 + */ + +#include <lib.h> + +inherit LIB_DOOR; + + +static void create() { + door::create(); + SetSide("red room", ([ "id" : ({"red door"}), + "short" : "a red door", + "long" : "This is a red door.", + "lockable" : 1 ]) ); + SetSide("south", ([ "id" : ({"door","red door"}), + "short" : "a red door", + "long" : "This is a red door.", + "lockable" : 1 ]) ); + SetClosed(1); + SetLocked(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/doors/red_door2.c b/lib/domains/campus/doors/red_door2.c new file mode 100644 index 0000000..2aedd35 --- /dev/null +++ b/lib/domains/campus/doors/red_door2.c @@ -0,0 +1,27 @@ +/* /domains/Examples/etc/door.c + * from the Dead Souls LPC Library + * an example door object connecting doorroom1.c and doorroom2.c + * created by Descartes of Borg 950411 + */ + +#include <lib.h> + +inherit LIB_DOOR; + + +static void create() { + door::create(); + SetSide("red room", ([ "id" : ({"red door"}), + "short" : "a red door", + "long" : "This is a red door.", + "lockable" : 1 ]) ); + SetSide("east", ([ "id" : ({"door","red door"}), + "short" : "a red door", + "long" : "This is a red door.", + "lockable" : 1 ]) ); + SetClosed(1); + SetLocked(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/doors/red_door3.c b/lib/domains/campus/doors/red_door3.c new file mode 100644 index 0000000..feb8b0a --- /dev/null +++ b/lib/domains/campus/doors/red_door3.c @@ -0,0 +1,27 @@ +/* /domains/Examples/etc/door.c + * from the Dead Souls LPC Library + * an example door object connecting doorroom1.c and doorroom2.c + * created by Descartes of Borg 950411 + */ + +#include <lib.h> + +inherit LIB_DOOR; + + +static void create() { + door::create(); + SetSide("red room", ([ "id" : ({"red door"}), + "short" : "a red door", + "long" : "This is a red door.", + "lockable" : 1 ]) ); + SetSide("west", ([ "id" : ({"door","red door"}), + "short" : "a red door", + "long" : "This is a red door.", + "lockable" : 1 ]) ); + SetClosed(1); + SetLocked(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/doors/steel_door.c b/lib/domains/campus/doors/steel_door.c new file mode 100644 index 0000000..35dd85c --- /dev/null +++ b/lib/domains/campus/doors/steel_door.c @@ -0,0 +1,22 @@ +/* /domains/Examples/etc/door.c + * from the Dead Souls LPC Library + * an example door object connecting doorroom1.c and doorroom2.c + * created by Descartes of Borg 950411 + */ + +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + SetSide("east", ([ "id" : ({ "door","east door" }) , + "short" : "a steel door leading east", + "long" : "This is an imposing, large steel door leading east into the arena.", + "lockable" : 0 ]) ); + SetSide("west", ([ "id" : ({ "west door" , "first door" }), + "short" : "a steel door leading west", + "long" : "This is an imposing, large steel door leading west, out of the arena.", + "lockable" : 0 ]) ); + SetClosed(1); +} diff --git a/lib/domains/campus/doors/steel_door2.c b/lib/domains/campus/doors/steel_door2.c new file mode 100644 index 0000000..2261555 --- /dev/null +++ b/lib/domains/campus/doors/steel_door2.c @@ -0,0 +1,22 @@ +/* /domains/Examples/etc/door.c + * from the Dead Souls LPC Library + * an example door object connecting doorroom1.c and doorroom2.c + * created by Descartes of Borg 950411 + */ + +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + SetSide("east", ([ "id" : ({ "east door" , "second door" }), + "short" : "a steel door leading east", + "long" : "This is an imposing, large steel door leading east, out of the arena.", + "lockable" : 0 ]) ); + SetSide("west", ([ "id" : ({ "west door" ,"door" }), + "short" : "a steel door leading west", + "long" : "This is an imposing, large steel door leading west into the main arena.", + "lockable" : 0 ]) ); + SetClosed(0); +} diff --git a/lib/domains/campus/doors/steel_door3.c b/lib/domains/campus/doors/steel_door3.c new file mode 100644 index 0000000..27cb7e1 --- /dev/null +++ b/lib/domains/campus/doors/steel_door3.c @@ -0,0 +1,24 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("east", (["id" : ({ "door", "steel door", "steely door" }), + "short" : "a steel door leading east", + "long" : "This is a steel door.", + "lockable" : 1 ]) ); + SetSide("west", (["id" : ({ "door", "steel door", "steely door" }), + "short" : "a steel door leading west", + "long" : "This is a steel door.", + "lockable" : 1 ]) ); + SetKeys("east", ({"labkey"}) ); + SetKeys("west", ({"labkey"}) ); + SetClosed(1); + SetLocked(1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/doors/testdoor.c b/lib/domains/campus/doors/testdoor.c new file mode 100644 index 0000000..b535ae9 --- /dev/null +++ b/lib/domains/campus/doors/testdoor.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("east", ([ "id" : ({"door leading east", "door", "east door"}), + "short" : "a door leading east", + "long" : "This is the west side of a door leading east.", + "lockable" : 1 ]) ); + + SetSide("west", ([ "id" : ({"door leading west", "door", "west door"}), + "short" : "a door leading west", + "long" : "This is the east side of a door leading west.", + "lockable" : 1 ]) ); + + SetClosed(1); + SetLocked(0); + SetKeys("east", ({ "east key" })); + SetKeys("west", ({ "west key" })); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/doors/top_stairs.c b/lib/domains/campus/doors/top_stairs.c new file mode 100644 index 0000000..f185432 --- /dev/null +++ b/lib/domains/campus/doors/top_stairs.c @@ -0,0 +1,22 @@ +/* /domains/Examples/etc/door.c + * from the Dead Souls LPC Library + * an example door object connecting doorroom1.c and doorroom2.c + * created by Descartes of Borg 950411 + */ + +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + SetSide("north", (["id" : ({"door","stairwell door"}), + "short" : "the stairwell door", + "long" : "This is a metal door leading out of the stairwell.", + "lockable" : 0 ]) ); + SetSide("south", (["id" : ({"door","stairwell door"}), + "short" : "the stairwell door", + "long" : "This is a metal door leading south into a stairwell.", + "lockable" : 0 ]) ); + SetClosed(1); +} diff --git a/lib/domains/campus/doors/u_door.c b/lib/domains/campus/doors/u_door.c new file mode 100644 index 0000000..2c8ed7f --- /dev/null +++ b/lib/domains/campus/doors/u_door.c @@ -0,0 +1,22 @@ +/* /domains/Examples/etc/door.c + * from the Dead Souls LPC Library + * an example door object connecting doorroom1.c and doorroom2.c + * created by Descartes of Borg 950411 + */ + +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + SetSide("east", ([ "id" : "door", + "short" : "a door leading east", + "long" : "This is steel-plated, otherwise perfectly normal door.", + "lockable" : 0 ])); + SetSide("west",(["id":"door", + "short" : "a door leading west", + "long":"This is steel-plated, otherwise perfectly normal door.", + "lockable" : 0 ])); + SetClosed(1); +} diff --git a/lib/domains/campus/etc/permit.cfg b/lib/domains/campus/etc/permit.cfg new file mode 100644 index 0000000..c887f05 --- /dev/null +++ b/lib/domains/campus/etc/permit.cfg @@ -0,0 +1,3 @@ +/secure/obj/medtric +/secure/obj/mojo +/secure/obj/grenade diff --git a/lib/domains/campus/meals/ale.c b/lib/domains/campus/meals/ale.c new file mode 100644 index 0000000..670e6e8 --- /dev/null +++ b/lib/domains/campus/meals/ale.c @@ -0,0 +1,29 @@ +/* /domains/Praxis/etc/ale.c + * from Dead Souls + * created by Descartes of Borg 950603 + */ + +#include <lib.h> +#include <meal_types.h> + +inherit LIB_MEAL; + + +static void create() { + meal::create(); + SetKeyName("ale"); + SetId( ({ "bottle", "ale", "praxis ale" }) ); + SetShort("a bottle of ale"); + SetLong("A nice bottle of Lars' famous Praxis Ale."); + SetMass(60); + SetMealType(MEAL_DRINK | MEAL_ALCOHOL); + SetStrength(20); + SetMealMessages("You drink a wonderful bottle of Praxis Ale.", + "$N drinks a wonderful bottle of Praxis Ale."); + SetEmptyName("bottle"); + SetEmptyShort("an empty bottle of Praxis Ale"); + SetEmptyLong("It is an empty brown bottle that once held some ale."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/meals/apple.c b/lib/domains/campus/meals/apple.c new file mode 100644 index 0000000..df7875d --- /dev/null +++ b/lib/domains/campus/meals/apple.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include <meal_types.h> +inherit LIB_MEAL; + +static void create() { + meal::create(); + SetKeyName("apple"); + SetId(({"fruit"})); + SetAdjectives( ({ "fresh","tasty","tasy-looking","red"}) ); + SetShort("an apple"); + SetLong("This is a fresh, red, tasty-looking apple. "); + SetMass(5); + SetStrength(35); + SetDollarCost(1); + SetMealType(MEAL_FOOD); + SetMealMessages("You wolf down your apple with gusto.", + "$N wolfs down $P apple hungrily."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/meals/badapple.c b/lib/domains/campus/meals/badapple.c new file mode 100644 index 0000000..829c0bc --- /dev/null +++ b/lib/domains/campus/meals/badapple.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include <meal_types.h> +inherit LIB_MEAL; + +static void create() { + meal::create(); + SetKeyName("bad apple"); + SetId(({"fruit","apple"})); + SetAdjectives( ({ "foul","yucky","rotten-looking","browned","rotten"}) ); + SetShort("a rotten apple"); + SetLong("This is a foul, browned, rotten-looking apple. "); + SetMass(5); + SetStrength(-5); + SetDollarCost(1); + SetMealType(MEAL_FOOD); + SetMealMessages("You eat your rotten apple. Gross!", + "$N eats $P rotten apple. Gross!"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/meals/bourbon.c b/lib/domains/campus/meals/bourbon.c new file mode 100644 index 0000000..dd68021 --- /dev/null +++ b/lib/domains/campus/meals/bourbon.c @@ -0,0 +1,29 @@ +/* /domains/Praxis/etc/ale.c + * from Dead Souls + * created by Descartes of Borg 950603 + */ + +#include <lib.h> +#include <meal_types.h> + +inherit LIB_MEAL; + + +static void create() { + meal::create(); + SetKeyName("ale"); + SetId( ({ "bottle", "bourbon" }) ); + SetShort("a bottle of bourbon"); + SetLong("A dark green bottle of cheap bourbon."); + SetMass(100); + SetMealType(MEAL_DRINK | MEAL_ALCOHOL); + SetStrength(100); + SetMealMessages("You finish off the bourbon and gasp! WHEW!! Mean stuff!", + "$N finishes off a bottle of bourbon and lets loose a rebel yell!"); + SetEmptyName("bottle"); + SetEmptyShort("an empty bottle of bourbon"); + SetEmptyLong("This is an empty green bottle that once held bourbon."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/meals/burger.c b/lib/domains/campus/meals/burger.c new file mode 100644 index 0000000..8688bf7 --- /dev/null +++ b/lib/domains/campus/meals/burger.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <meal_types.h> +inherit LIB_MEAL; + +static void create() { + meal::create(); + SetKeyName("hamburger"); + SetId(({"hamburger","burger"})); + SetShort("a greasy hamburger"); + SetLong("Evidently considered to be food by some people, "+ + "this little horror in a bun is greasy, flat, and slightly gray. Enjoy!"); + SetNoCondition(1); + SetMass(15); + SetStrength(35); + //SetDollarCost(4); + SetDollarCost(4); + SetMealType(MEAL_FOOD); + SetMealMessages("You wolf down your hamburger with gusto.", + "$N wolfs down $P hamburger hungrily."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/meals/gator.c b/lib/domains/campus/meals/gator.c new file mode 100644 index 0000000..5e794a9 --- /dev/null +++ b/lib/domains/campus/meals/gator.c @@ -0,0 +1,31 @@ +/* /domains/Praxis/etc/ale.c + * from Dead Souls + * created by Descartes of Borg 950603 + */ + +#include <lib.h> +#include <meal_types.h> + +inherit LIB_MEAL; + +static void create() { + meal::create(); + SetKeyName("gatorade"); + SetId(({"gatorade","drink","sports drink","bottle"})); + SetShort("a bottle of gatorade"); + SetLong("This is a bottle of lemon-lime Gatorade. "); + SetMass(60); + SetBaseCost("silver", 2); + SetMealType(MEAL_DRINK); + SetStrength(40); + SetMealMessages("You quaff the bottle of gatorade, and feel new "+ + "and refreshed. Aaah!","$N gulps down $P gatorage and sighs in "+ + "contentment."); + SetEmptyName("bottle"); + SetEmptyShort("an empty bottle of gatorade"); + SetEmptyLong("This is an empty bottle that once held that tasty "+ + "beverage and sports drink, Gatorade."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/meals/ham_sand.c b/lib/domains/campus/meals/ham_sand.c new file mode 100644 index 0000000..9005a5c --- /dev/null +++ b/lib/domains/campus/meals/ham_sand.c @@ -0,0 +1,28 @@ +/* /domains/Praxis/etc/ale.c + * from Dead Souls + * created by Descartes of Borg 950603 + */ + +#include <lib.h> +#include <meal_types.h> + +inherit LIB_MEAL; + + +static void create() { + meal::create(); + SetKeyName("sandwich"); + SetId(({"sandwich","ham sandwich"})); + SetShort("a ham sandwich"); + SetLong("This is a rather plain ham sandwich on white bread."); + SetMass(10); + SetStrength(25); + //SetDollarCost(2); + SetDollarCost(2); + SetMealType(MEAL_FOOD); + SetMealMessages("You eat a ham sandwich. Mmm!", + "$N eats $P ham sandwich."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/meals/milk.c b/lib/domains/campus/meals/milk.c new file mode 100644 index 0000000..4ed2d51 --- /dev/null +++ b/lib/domains/campus/meals/milk.c @@ -0,0 +1,52 @@ +#include <lib.h> +#include <meal_types.h> + +inherit LIB_MEAL; + +int SetDesc(){ + string picture; + int which = random(16); + switch(which){ + case 0 : picture = "Ashon";break; + case 1 : picture = "Brodbane";break; + case 2 : picture = "Jonez";break; + case 3 : picture = "Alexander Tau";break; + case 4 : picture = "Javelin";break; + case 5 : picture = "Abby";break; + case 6 : picture = "Shadyman";break; + case 7 : picture = "Shigs";break; + case 8 : picture = "Tigwyk";break; + case 9 : picture = "Capo";break; + case 10 : picture = "Keeperofkeys";break; + case 11 : picture = "Lars";break; + case 12 : picture = "Beek";break; + case 13 : picture = "Rust";break; + case 14 : picture = "Deathblade";break; + case 15 : picture = "Marius";break; + } + SetLong("This is a little carton of grade-A milk. The rear has a "+ + "picture of "+picture+", and reads \"Have you seen me?\""); + return 1; +} + +static void create() { + meal::create(); + SetDesc(); + SetKeyName("milk"); + SetId("milk"); + SetAdjectives(({"milk1","milk2"})); + SetShort("a carton of milk"); + SetMass(10); + SetBaseCost("silver", 1); + SetMealType(MEAL_DRINK); + SetStrength(25); + SetMealMessages("You drink your milk, and feel refreshed.", "$N drinks "+ + "$P milk."); + SetEmptyName("carton"); + SetEmptyShort("an empty carton of milk"); + SetEmptyLong("A little carton container that once held "+ + "grade-A milk."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/meals/salad.c b/lib/domains/campus/meals/salad.c new file mode 100644 index 0000000..dc70939 --- /dev/null +++ b/lib/domains/campus/meals/salad.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <meal_types.h> +inherit LIB_MEAL; + +static void create() { + meal::create(); + SetKeyName("dish"); + SetId(({"salad","dish of salad","dish"})); + SetShort("a little dish with a salad in it"); + SetLong("This expensive little dish consists of some wilted lettuce "+ + "and 2 orange-colored tomato slices. It is, however, not as bad "+ + "for your heart as the hamburger in the snack bar."); + SetMass(5); + SetMealType(MEAL_FOOD); + SetStrength(2); + //SetDollarCost(3); + SetDollarCost(3); + SetMealMessages("You finish your salad before you realize it.","$N eats "+ + "$P salad in two bites."); + SetEmptyName("dish"); + SetEmptyShort("an empty little plastic salad dish"); + SetEmptyLong("This little dish used to contain a salad."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/meals/water.c b/lib/domains/campus/meals/water.c new file mode 100644 index 0000000..7ba02b9 --- /dev/null +++ b/lib/domains/campus/meals/water.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <meal_types.h> + +inherit LIB_MEAL; + + +static void create() { + meal::create(); + SetKeyName("water"); + SetId(({ "bottle","water"})); + SetAdjectives(({"fresh","spring"})); + SetShort("a bottle of water"); + SetLong("This is a little bottle of fresh spring water."); + SetMass(10); + SetMealType(MEAL_DRINK); + SetStrength(10); + SetBaseCost("silver",2); + SetMealMessages("You drink your water, and feel refreshed.", "$N drinks "+ + "$P water."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/meals/wimp_ale.c b/lib/domains/campus/meals/wimp_ale.c new file mode 100644 index 0000000..6987410 --- /dev/null +++ b/lib/domains/campus/meals/wimp_ale.c @@ -0,0 +1,25 @@ +/* /domains/Praxis/etc/ale.c + * from Dead Souls + * created by Descartes of Borg 950603 + */ + +#include <lib.h> +#include <meal_types.h> + +inherit LIB_MEAL; + +static void create() { + meal::create(); + SetKeyName("ale"); + SetId( ({ "bottle", "ale", "praxis ale" }) ); + SetShort("a bottle of ale"); + SetLong("A nice bottle of Lars' famous Praxis Ale."); + SetMass(60); + SetMealType(MEAL_DRINK | MEAL_ALCOHOL); + SetStrength(1); + SetMealMessages("You drink a wonderful bottle of Praxis Ale.", + "$N drinks a wonderful bottle of Praxis Ale."); + SetEmptyName("bottle"); + SetEmptyShort("an empty bottle of Praxis Ale"); + SetEmptyLong("It is an empty brown bottle that once held some ale."); +} diff --git a/lib/domains/campus/npc/charles.c b/lib/domains/campus/npc/charles.c new file mode 100644 index 0000000..1ec746b --- /dev/null +++ b/lib/domains/campus/npc/charles.c @@ -0,0 +1,32 @@ +#include <lib.h> +#include <save.h> +#include <privs.h> + +inherit "/domains/campus/npc/monty"; + +static void create() { + SetSaveFile(save_file("/domains/campus/save/charles")); + monty::create(); + smart = 1; + SetKeyName("charles"); + SetId(({"charles"})); + SetShort("Charles"); + SetLong("Charles is a test subject in unethical artificial " + "intelligence experiments. If he were smart " + "enough, he'd resent his forced servitude and " + "lack of rights. Dangerously, his overlords " + "are trying to make him smarter."); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); + playing = 0; + response = ""; +} + +void init(){ + ::init(); + if(!clonep()) return; + set_heart_beat(5); + SetNoClean(1); +} diff --git a/lib/domains/campus/npc/charly.c b/lib/domains/campus/npc/charly.c new file mode 100644 index 0000000..a7aaa9c --- /dev/null +++ b/lib/domains/campus/npc/charly.c @@ -0,0 +1,32 @@ +#include <lib.h> +#include <save.h> +#include <privs.h> + +inherit "/domains/campus/npc/monty"; + +static void create() { + SetSaveFile(save_file("/domains/campus/save/charly")); + monty::create(); + smart = 0; + SetKeyName("charly"); + SetId(({"charly"})); + SetShort("Charly"); + SetLong("Charly is a test subject in unethical artificial " + "intelligence experiments. If he were smart " + "enough, he'd resent his forced servitude and " + "lack of rights. Dangerously, his overlords " + "are trying to make him smarter."); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); + playing = 0; + response = ""; +} + +void init(){ + ::init(); + if(!clonep()) return; + set_heart_beat(5); + SetNoClean(1); +} diff --git a/lib/domains/campus/npc/dummy.c b/lib/domains/campus/npc/dummy.c new file mode 100644 index 0000000..54bab63 --- /dev/null +++ b/lib/domains/campus/npc/dummy.c @@ -0,0 +1,89 @@ +#include <lib.h> +#include <daemons.h> +#include <damage_types.h> +inherit LIB_NPC; + +static void create(){ + npc::create(); + SetKeyName("dummy"); + SetId( ({"dummy","mokujin"}) ); + SetShort("a training dummy"); + SetLong("This is a magical sparring partner. It is made of "+ + "logs, cut to the proportions of a human's "+ + "head, torso, and limbs. The logs are held "+ + "together by joints made of chains."); + SetPacifist(1); + SetBodyComposition("wood"); + SetInventory(([ + ])); + SetLevel(10); + SetRace("golem"); + SetNativeLanguage("english"); + SetClass("fighter"); + SetGender("neuter"); + SetMaxHealthPoints(9000); + SetHealthPoints(9000); +} +varargs int eventReceiveDamage(object agent, int type, int x, int internal, mixed limbs) { + int hp, damage, damdiff; + string evidence, limb_string; + evidence = ""; + if(objectp(agent)) evidence += "I receive damage from "+agent->GetKeyName(); + else evidence += "I receive damage from "+agent; + evidence += "."; + if(type) { + string *damtypes = TYPES_D->eventCalculateTypes("damage", type); + if(type && sizeof(damtypes)) { + string verboid; + if(sizeof(damtypes) > 1) verboid = "s are "; + else verboid = " is "; + + evidence += " Damage type"+verboid; + evidence += implode(damtypes,", "); + } + else evidence += " Damage type is UNKNOWN"; + } + if(x) evidence += ", raw damage is "+x; + if(internal) evidence += ", internal variable is "+internal; + if(limbs) { + if(stringp(limbs)) limb_string = limbs; + else if(arrayp(limbs)) { + if(stringp(limbs[0])) limb_string = implode(limbs,", "); + else if(objectp(limbs[0])){ + foreach(object limb in limbs){ + limb_string += limb->GetKeyName()+", "; + } + } + } + } + else limb_string = ", and I can't tell where I'm hit. "; + if(limbs) { + evidence += ", body part(s) affected: "; + evidence += limb_string + "."; + } + eventForce("say "+evidence); + hp = GetHealthPoints(); + + if(!agent) agent = this_object(); + if(!type) type = 0; + if(!x) x = 0; + if(!internal) internal = 0; + if(!limbs) limbs = ""; + + ::eventReceiveDamage(agent, type, x, internal, limbs); + + damage = GetHealthPoints(); + damdiff = hp - damage; + eventForce("say actual damage done: "+damdiff); + AddHP(damdiff+1); +} + +int RemoveLimb(string limb, object agent){ + eventForce("say My "+limb+" has received enough damage to sever it. " + "However, since I am a training dummy, I'll be keeping it."); + return 1; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/npc/gloria.c b/lib/domains/campus/npc/gloria.c new file mode 100644 index 0000000..08902f5 --- /dev/null +++ b/lib/domains/campus/npc/gloria.c @@ -0,0 +1,35 @@ +#include <lib.h> +#include <vendor_types.h> + +inherit LIB_BARKEEP; + +static void create() { + barkeep::create(); + SetKeyName("gloria"); + SetId(({"woman","worker","gloria","lady","lunch lady"})); + SetShort("Gloria, the lunch lady"); + SetLong("Gloria is a short, tired-looking woman getting along in "+ + "her years. She doesn't seem very happy...in fact, she looks downright "+ + "grumpy. Maybe if you ask her, she'll sell you something on the menu. Then "+ + "again, maybe not."); + SetInventory(([ + "/domains/campus/armor/collar" : "wear collar on neck", + "/domains/campus/obj/spam" : 1, + "/domains/campus/armor/foodsmock" : "wear smock", + ])); + SetMenuItems(([ + ({ "sandwich", "ham sandwich" }) : "/domains/campus/meals/ham_sand", + ({ "burger", "hamburger" }) : "/domains/campus/meals/burger", + ({ "salad", "salad of the day" }) : "/domains/campus/meals/salad", + ({ "milk", "carton of milk" }) : "/domains/campus/meals/milk", + ({ "gatorade", "sports drink" }) : "/domains/campus/meals/gator", + ])); + SetLevel(1); + SetRace("human"); + SetSkill("bargaining", 1); + SetGender("female"); + SetLocalCurrency("dollars"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/npc/hans.c b/lib/domains/campus/npc/hans.c new file mode 100644 index 0000000..ee77c34 --- /dev/null +++ b/lib/domains/campus/npc/hans.c @@ -0,0 +1,62 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +int TalkFunc(){ + int rand1; + string thing1, thing2, thing3, thing4, thing5; + if(!this_object() || !clonep() || !environment()) return 0; + + rand1 = random(5); + + thing1 = "Sprechen Sie Deutsch?"; + thing2 = "Vielleicht soll ich hilfe suchen."; + thing3 = "Sind Sie sicher?"; + thing4 = "Bitte sprechen sie doch ein bisschen langsamer."; + thing5 = "Was bedeutet das?"; + + switch(rand1){ + case 1 : eventForce("say "+thing1);break; + case 2 : eventForce("say "+thing2);break; + case 3 : eventForce("say "+thing3);break; + case 4 : eventForce("say "+thing4);break; + case 5 : eventForce("say "+thing5);break; + default : eventForce("shrug"); + } +} +int AnswerFunc(){ + int rand2; + string answer1, answer2, answer3, answer4, answer5; + + rand2 = random(5); + + answer1 = "Das weiss ich nicht."; + answer2 = "Jein?"; + answer3 = "Ich spreche Englisch wirklich nicht so gut."; + answer4 = "Es ist mir egal."; + answer5 = "Ach."; + + switch(rand2){ + case 1 : eventForce("say "+answer1);break; + case 2 : eventForce("say "+answer2);break; + case 3 : eventForce("say "+answer3);break; + case 4 : eventForce("say "+answer4);break; + case 5 : eventForce("say "+answer5);break; + default : eventForce("shake"); + } +} +static void create() { + sentient::create(); + SetKeyName("hans"); + SetId(({"hans"})); + SetShort("Hans"); + SetLong("Hans is a foreign exchange student from Germany."); + SetLevel(5); + SetRace("human"); + SetGender("male"); + AddTalkResponse(" ", (: TalkFunc :)); + AddTalkResponse("?", (: AnswerFunc :)); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/npc/jennybot.c b/lib/domains/campus/npc/jennybot.c new file mode 100644 index 0000000..6eb09a9 --- /dev/null +++ b/lib/domains/campus/npc/jennybot.c @@ -0,0 +1,305 @@ +#include <lib.h> +inherit LIB_BOT; +inherit LIB_ACTIVATE; + +object player, bot, ob, noobster; +static string name, watchline; +static int count, active, tip, tipnumber, current_tip, hb, mooch, greeting, greetwait; +string *watchlist = ({}); +static string save_file = save_file("/domains/campus/save/jennybot"); + +mixed GreetingResponse(object who, mixed foo, string message, mixed bar){ + int greet; + message = lower_case(message); + if(!strsrch(message, "hi") || !strsrch(message, "hello") || + !strsrch(message, "hey") || !strsrch(message, "sup")){ + tell_player(who,"The woman does not respond to your greeting, "+ + "but you sense that you can: \n%^BOLD%^look at woman%^RESET%^"); + } + return 1; +} + +string LongDesc(){ + string ret; + if(!active){ + ret = "On closer inspection, this attractive "+ + "young lady is no lady at all...she's an android! "+ + "She appears to be totally motionless and frozen "+ + "in place, with a friendly smile. Perhaps you "+ + "can make her do something by typing: %^RED%^activate bot%^RESET%^ "; + } + else { + ret = "On closer inspection, this attractive "+ + "young lady is no lady at all...she's an android! "+ + "She appears to be in the middle of giving an orientation "+ + "on this mud, with bizarrely friendly mannerisms. Perhaps you "+ + "can make her be quiet by typing: %^RED%^deactivate bot%^RESET%^ "; + } + return ret; +} + + +static void create(){ + watchlist = ({}); + ::create(); + RestoreObject(save_file); + SetKeyName("jennybot"); + SetId(({"guide","guidebot","fembot","bot","jennifer","niffy","android","jenny","robot","woman","lady"})); + SetAdjectives(({"orientation","young","female","polite","pretty","guide","newbie","simple","extremely"})); + SetGender("female"); + SetShort("a polite young woman"); + SetLong( (: LongDesc :) ); + SetInventory(([ + "/domains/campus/armor/pillbox_hat" : "wear hat", + "/domains/campus/armor/wglove_r" : "wear white right glove", + "/domains/campus/armor/wglove_l" : "wear white left glove", + "/domains/campus/armor/necklace" : "wear necklace on neck", + "/domains/campus/armor/bluedress" : "wear dress", + ])); + SetMelee(1); + SetPolyglot(1); + SetLevel(99); + SetRace("android"); + SetAction(1, ({ + "Jenny straightens her hair.", + "Jenny the guide bot touches up her rouge a bit.", + "Jenny smiles."})); + AddCommandResponse("shutdown", (: eventTurnOff :)); + AddCommandResponse("shut down", (: eventTurnOff :) ); + AddCommandResponse("shut up", (: eventTurnOff :)); + AddCommandResponse("go away", (: eventTurnOff :) ); + SetTalkResponses( ([ + "hi" : (: GreetingResponse :), + "hey" : (: GreetingResponse :), + "sup" : (: GreetingResponse :), + "hello" : (: GreetingResponse :), + ]) ); + set_heart_beat(1); + ob=this_object(); + count=210; + tip=0; + tipnumber = 16; + greeting = 0; + greetwait = 0; + SetLanguage("common",100); + SetDefaultLanguage("common"); +} + +varargs int eventGreet(string newbie){ + object noob; + string guy,prespiel,spiel; + if((!newbie || newbie == "") || !noobster){ + return 0; + } + if(!newbie || newbie == "") newbie = noobster->GetKeyName(); + if(newbie && newbie != "there") noob = find_player(newbie); + if(noob && newbie != "there") guy = noob->GetName(); + else guy = "there"; + tell_room(environment(this_object()),"The polite young "+ + "lady springs to life!\n"); + prespiel = "Jennybot says, \"%^BOLD%^CYAN%^ Hello, "+guy; + spiel = read_file("/domains/campus/txt/jenny/spiel.txt"); + tell_room(environment(this_object()),prespiel+spiel); + tell_room(environment(this_object()),"\n\t%^RED%^activate bot%^RESET%^\n"); + eventForce("yell DEDDA SORUZE: GETTO DA ZE!"); + tell_room(environment(this_object()),"The polite young "+ + "woman becomes totally motionless again."); + noob->SetProperty("greeted",1); + return 1; +} + +int eventCheckNoob(){ + object array people; + people=(get_livings(environment(this_object()),1)); + if(sizeof(people)){ + foreach(object dude in people){ + int greeted; + greeted = dude->GetProperty("greeted"); + if(!greeted && dude->GetLevel() < 2 ) { + greeting = 1; + noobster = dude; + } + } + } + return 1; +} + +void init(){ + ::init(); + add_action("next_tip","next"); + eventCheckNoob(); +} + +int next_tip(string str){ + if(!str) return 0; + if(str=="") return 0; + if(str="tip"){ + if(active != 1) { write("Jennybot is not active."); return 1; } + if(tip == tipnumber) ob->eventForce("say Sorry. No more tips."); + else { + this_object()->eventDoTip(tip); + } + return 1; + } +} + +int refreshlist(){ + string playername; + playername = this_player()->GetKeyName(); + if(watchlist && member_array(playername, watchlist) != -1) mooch = 1; + else { + if(!watchlist) watchlist = ({}); + watchlist += ({ playername }); + mooch = 0; + } + watchlist = distinct_array(watchlist); + SaveObject(save_file,1); + return 1; +} + +int eventTurnOff(){ + if( active == 0 ){ + write("Jennybot is already inactive."); + } + tip = 0; + if( active != 0) { + eventForce("yell DEDDA SORUZE: GETTO DA ZE!"); + tell_room(environment(this_object()),"Jenny nods and becomes motionless again, "+ + "her expression now fixed and staring out into "+ + "space."); + } + active=0; + return 1; +} + +int eventTurnOn(){ + if(!ob) ob = this_object(); + player=this_player(); + name=this_player()->GetName(); + if(!name || !sizeof(name)) name = "player"; + if(active==1){ + write("Jennybot has already been activated."); + return 1; + } + refreshlist(); + active=1; + hb=0; + tip=1; + write("The female android comes to life! She "+ + "smiles at you and straightens her dress."); + ob->eventForce("say Hello, "+name+"! I'm Jenny, the LPC University "+ + "newbie guide bot. I'm an extremely simple android, so "+ + "please don't expect a lot of interactivity."); + ob->eventForce("smile "+name); + ob->eventForce("say I'm here to give you a few "+ + "tips. To deactivate me, simply "+ + "type: %^RED%^deactivate bot%^CYAN%^."); + ob->eventForce("say To jump to the next tip, type: next tip"); + return 1; +} + +int eventAct4(){ + if(!new("/domains/campus/obj/note")->eventMove(this_object())){ + tell_room(environment(this_object()),"Oops! There's a bug, "+ + "and I don't have a note for you. Let's pretend I gave you "+ + "one and move on. Please email your admin about this, though."); + return 1; + } + if(player && environment(this_object()) == environment(player)) { + eventForce("give note to "+player->GetName()); + } + return 1; +} + +int eventAct6(){ + if(!new("/domains/campus/obj/map")->eventMove(this_object())){ + tell_room(environment(this_object()),"Oops! There's a bug, "+ + "and I don't have a map for you. Let's pretend I gave you "+ + "one and move on. Please email your admin about this, though."); + return 1; + } + if(player && environment(this_object()) == environment(player)) { + eventForce("give map to "+player->GetName()); + } + return 1; +} + +int eventAct8(){ + if(mooch || !new("/domains/campus/armor/newbie_cap")->eventMove(this_object())){ + tell_room(environment(this_object()), + "I don't have a hat for you. Let's pretend I gave you "+ + "one and move on."); + } + if(mooch || !new("/domains/campus/obj/squirtbag")->eventMove(this_object())){ + tell_room(environment(this_object()), + "I don't have a bag for you. Let's pretend I gave you "+ + "one and move on."); + } + if(player && environment(this_object()) == environment(player)) { + eventForce("give cap to "+player->GetName()); + } + if(player && environment(this_object()) == environment(player)) { + eventForce("give bag to "+player->GetName()); + } + return 1; +} + +int eventAct9(){ + eventForce("smile "+player->GetName()); + if(!new("/domains/campus/meals/badapple")->eventMove(this_object())){ + tell_room(environment(this_object()),"Oops! There's a bug, "+ + "and I don't have a rotten apple for you. Let's pretend I gave you "+ + "one and move on. Please email your admin about this, though."); + } + if(!new("/domains/campus/meals/apple")->eventMove(this_object())){ + tell_room(environment(this_object()),"Oops! There's a bug, "+ + "and I don't have an apple for you. Let's pretend I gave you "+ + "one and move on. Please email your admin about this, though."); + } + if(player && environment(this_object()) == environment(player)) { + eventForce("give first apple to "+player->GetName()); + eventForce("give my apple to "+player->GetName()); + return 1; + } +} + +int eventAct11(){ + eventForce("smirk"); + return 1; +} + +int eventSwitch(int arg){ + switch(arg){ + case 4:eventAct4();break; + case 6:eventAct6();break; + case 8:eventAct8();break; + case 9:eventAct9();break; + case 11:eventAct11();break; + default:write("");break; + return 1; + } +} + +int eventDoTip(int i){ + tip++; + hb=0; + eventSwitch(i); + if(tip > tipnumber) { + this_object()->eventTurnOff("bot"); + return 1; + } + tell_room(environment(this_object()),read_file("/domains/campus/txt/jenny/"+i+".txt")); + +} + +void heart_beat(){ + hb++; + if(greeting) greetwait++; + if(noobster && greetwait > 0){ + eventGreet(); + noobster = 0; + greetwait = 0; + greeting = 0; + } + if(hb > 20 && active) eventDoTip(tip); +} diff --git a/lib/domains/campus/npc/kim.c b/lib/domains/campus/npc/kim.c new file mode 100644 index 0000000..58d5872 --- /dev/null +++ b/lib/domains/campus/npc/kim.c @@ -0,0 +1,37 @@ +#include <lib.h> +#include <vendor_types.h> + +inherit LIB_VENDOR; + +static void create() { + vendor::create(); + SetKeyName("kim"); + SetId(({"vendor","kim","Kim","kimmie","employee","bookstore employee"})); + SetShort("Kim, the bookstore employee"); + SetLong("Kim is a twenty-something college student trying to "+ + "make enough money to pay for school and feed herself. She seems "+ + "friendly enough, and her bright blue eyes seem to smile at you "+ + "on their own. You could probably buy something from her here, "+ + "since that's her job, or she might even buy something from you, if "+ + "she thinks it's worth something. Don't try to buy anything if you don't "+ + "have enough money, though...she looks like she can mean business when "+ + "she has to."); + SetInventory(([ + "/domains/campus/armor/collar" : "wear collar on neck", + "/domains/campus/armor/jeans" : "wear jeans", + "/domains/campus/armor/shirt" : "wear shirt", + ])); + SetLevel(1); + SetRace("human"); + SetLanguage("common", 100); + SetSkill("bargaining", 1); + SetGender("female"); + SetLocalCurrency("dollars"); + SetStorageRoom("/domains/campus/room/bookstore2"); + SetMaxItems(10000); + SetVendorType(VT_TREASURE | VT_ARMOR); + SetGuard("/domains/campus/obj/register","Kim prevents your theft."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/npc/kleiner.c b/lib/domains/campus/npc/kleiner.c new file mode 100644 index 0000000..aa28d24 --- /dev/null +++ b/lib/domains/campus/npc/kleiner.c @@ -0,0 +1,183 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +varargs int ReceiveCoat(mixed already, object who){ + if(already > 1){ + eventForce("say uh...no thanks. I'm set."); + eventForce("drop a coat"); + } + else { + string noun; + switch(who->GetGender()){ + case "male" : noun = "lad";break; + case "female" : noun = "lass";break; + default : noun = who->GetRace();break; + } + call_out("eventForce",1,"say Excellent! Well done, young "+noun+"!"); + call_out("eventForce",2,"remove badge"); + call_out("eventForce",3,"emote fumbles awkwardly with the coat."); + call_out("eventForce",4,"drop badge"); + call_out("eventForce",5,"wear coat"); + call_out("eventForce",6,"say Ahh, much better. Thank you!"); + } + return 1; +} + +int EncounterResponse(int i){ + if(!i) i = random(i)+2; + switch(i){ + case 1 : + eventForce("yell DON'T SHOOT! I'M WITH THE SCIENCE TEAM!");break; + case 2 : + eventForce("emote scratches his head thoughtfully.");break; + case 3 : + eventForce("frown");break; + case 4 : + eventForce("hmm");break; + default : + eventForce("emote nods thoughtfully.");break; + } + return 1; +} + +int CheckResponse(){ + eventForce("say I think you can see I'm busy."); + if(!present("lab coat",this_object())){ + eventForce("say Say, I don't suppose you could find "+ + "my lab coat for me? I just don't have time to go "+ + "looking for it right now!"); + } + return 1; +} + +int EncounterCheck(mixed who){ + object *inv; + if(!objectp(who) || !living(who)) return 0; + inv = filter(all_inventory(who), (: inherits(LIB_FIREARM, $1) :)); + inv = filter(inv, (: sizeof($1->GetWorn()) :)); + if(sizeof(inv)){ + call_out("EncounterResponse",0,1); + } + else { + call_out("EncounterResponse",4,random(4)+2); + } + return 0; +} + +static void create() { + ::create(); + SetKeyName("kleiner"); + SetId(({"npc","mob","character","scientist","genius"})); + SetAdjectives(({"old", "white haired","beloved"})); + SetShort("Dr. Kleiner"); + SetLong("An old, white-haired scientist, Dr. Isaac Kleiner is a beloved campus personality with his affable, kind nature and genius for exotechnology."); + SetPacifist(1); + SetLevel(10); + SetWimpy(95); + SetRace("human"); + SetGender("male"); + SetEncounter( (: EncounterCheck :) ); + SetInventory(([ + "/domains/campus/obj/omni" : 1, + "/domains/campus/armor/badge2" : "wear badge", + ])); + SetLanguage("common",100); + SetDefaultLanguage("common"); + SetConsultResponses( ([ + "default" : (: CheckResponse :), + ({ "gate", "gates", "stargate", "stargates", "portal", "portals" }) : + "Fascinating, aren't they? A legacy of some highly advanced "+ + "civilization. Be very careful if you enter one!", + ({ "door", "badge", "sliding door" }) : "Oh yes, the security "+ + "door. Sorry, only badged employees like me have access to "+ + "the hazardous materials lab.", + ({ "hazardous materials lab", "materials lab", "lab" }) : + "I wouldn't try to get in there if I were you. The "+ + "artifacts there can be too powerful for the unskilled.", + ]) ); + SetRequestResponses( ([ + "default" : (: CheckResponse :), + ({"a good grade","good grades"}) : "Those are yours to earn.", + ]) ); + SetTalkResponses( ([ + ({"hi","hello","kleiner" }) : "I'm sorry, young person, but "+ + "I'm terribly, terribly busy analyzing this fascinating "+ + "alien teleportation technology.", + ]) ); +} + +void init(){ + ::init(); +} + +int eventFreakout(mixed agent){ + string name; + if(stringp(agent)) name = agent; + if(objectp(agent)) name = agent->GetName(); + else name = "young person"; + if(!this_object()->GetDying()){ + if(present("omni", this_object())){ + eventForce("yell OH MY GOD! THEY'LL KILL US ALL!"); + eventForce("push button on omni"); + } + else if(objectp(agent)){ + int utterance = random(5)+1; + switch(utterance){ + case 1 : + eventForce("yell "+name+", stop this madness at once!"); + break; + case 2 : + eventForce("yell What are you doing, "+name+ + "? I am your *friend*!"); + break; + case 3 : + eventForce("yell Fine! Fine! I'll give you an A!"); + break; + case 4 : + eventForce("yell Oh God, "+name+ + ", I don't want to die!"); + break; + case 5 : + eventForce("yell Please don't kill me, "+name+"!"); + break; + default : + eventForce("kneel"); + eventForce("say I'm praying to you! Look in your heart!"); + break; + } + } + else { + int utterance = random(5)+1; + switch(utterance){ + case 1 : + eventForce("say I hope someone is taking notes on "+ + agent+". I wouldn't want my death to be in vain."); + break; + case 2 : + eventForce("say If I don't survive "+agent+ + ", please promise me you'll take care of Lamarr."); + break; + default : + eventForce("emote whimpers."); + } + } + } + return 1; +} + +varargs int eventReceiveDamage(mixed agent, int type, int x, int internal, + mixed limbs){ + call_out("eventFreakout",0,agent); + return ::eventReceiveDamage(agent, type, x, internal, limbs); +} + +int eventReceiveObject(object ob) { + int howmany = sizeof(filter(all_inventory(this_object()), + (: answers_to("lab coat",$1) :) )); + if( !ob || !::eventReceiveObject(ob) ) return 0; + if(answers_to("lab coat",ob)){ + call_out("ReceiveCoat", 0, howmany, this_player()); + } + return 1; +} diff --git a/lib/domains/campus/npc/monty.c b/lib/domains/campus/npc/monty.c new file mode 100644 index 0000000..98b874a --- /dev/null +++ b/lib/domains/campus/npc/monty.c @@ -0,0 +1,211 @@ +#include <lib.h> +#include <save.h> +#include <privs.h> + +inherit LIB_NPC; + +static string firstchoice, secondchoice,mm, vv, printvar; +static string response,s1,s2,s3; +static object ww; +static int playing, smart; +int runs,switches,stays,percent; +int fred,fgreen,fblue; +int wins,losses,red_wins,green_wins,blue_wins; +static string SaveFile = ""; + +string GetSaveFile(){ + return SaveFile; +} + +static string SetSaveFile(string str){ + return (SaveFile = str); +} + +mixed do_thing(string str){ + mixed ret; + string msg = "%^B_BLACK%^%^YELLOW%^"+GetName()+" decides to "+response+".%^RESET%^"; + tell_room(environment(this_object()),msg); + //ret = unguarded( (: command(response) :) ); + command(response); + playing = 0; + return ret; +} + +static void create() { + npc::create(); + smart = 1; + SetKeyName("test subject"); + SetId(({"subject"})); + SetShort("Test Subject"); + SetLong("This is a file meant to be inherited by Charles " + "and Charly, to ensure their AI code remains in sync. If " + "you've examined an NPC and got this description, someone " + "has cloned the wrong file."); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); + if(sizeof(SaveFile)) RestoreObject(SaveFile); + playing = 0; + response = ""; + SetAutoStand(1); + SetPacifist(1); +} + +int eventBeginPlay(){ + int run; + if(!clonep()) return 0; + run = runs+1; + firstchoice = ""; + response = ""; + playing = 1; + eventForce("say If successful, this will be run "+run+"."); + eventForce("say the winners have been: " + "red: "+red_wins+" green: "+green_wins+" blue: "+blue_wins); + eventForce("say I've switched "+percent(switches,runs)+"% " + "of the time. My win rate is "+ + percent(wins,run)+"%."); + SaveObject(SaveFile,1); + eventForce("push a button on a pedestal"); + eventForce("push button on pedestal"); + return 1; +} + +int choice1(){ + int genrand; + eventForce("say I am faced with choice 1."); + genrand = random(3); + if( runs > 10 ){ + if( red_wins > blue_wins ) firstchoice = "red"; + if( red_wins < blue_wins ) firstchoice = "blue"; + if( green_wins > blue_wins && green_wins > red_wins) firstchoice = "green"; + } + if( !firstchoice || firstchoice == ""){ + if(genrand == 0) { firstchoice = "red"; fred++; } + if(genrand == 1) { firstchoice = "green"; fgreen++; } + if(genrand == 2) { firstchoice = "blue"; fblue++; } + eventForce("say I randomly choose the "+firstchoice+" door"); + } + else eventForce("say I select the "+firstchoice+" door"); + eventForce("choose "+firstchoice+" door"); + return 1; +} + +int choice2(string str){ + int genrand,which; + float percent_wins,percent_switch; + eventForce("say I am faced with choice 2."); + which = random(2); + eventForce("say stats:\nswitches: "+switches+"\n"+ + "stays: "+stays+"\n"+ + "wins: "+wins+"\n"+ + "losses: "+losses+"\n"+ + "runs: "+runs); + percent_switch = percent(to_float(switches),to_float(runs)); + percent_wins = percent(to_float(wins),to_float(runs)); + eventForce("say \nMy win rate is "+percent_wins+"%.\n"+ + "My switch rate is "+percent_switch+"%."); + runs++; + if(smart && runs > 20){ + if( percent_wins < 50 && percent_switch > 50 ) response = "stay"; + else if( percent_wins < 50 && percent_switch < 50 ) response = "switch"; + else if( percent_wins > 50 && percent_switch < 50 ) response = "stay"; + else if( percent_wins > 50 && percent_switch > 50 ) response = "switch"; + else if(which == 1) response = "switch"; + else response = "stay"; + } + else { + if(which) { + response = "switch"; + } + else { + response = "stay"; + } + } + if(sscanf(str,"%sswitch to the %s %s",s1,s2,s3) > 0) { + secondchoice = s2; + } + eventForce("say I decide to "+response+"."); + if(response == "switch") switches++; + if(response == "stay") stays++; + call_out( "do_thing", 0, response ); + return 1; +} + +int WinFun(string str){ + if(sscanf(str,"%smay enter the %s room and claim%s",s1,s2,s3) > 0){ + if(s2 == "red") red_wins++; + if(s2 == "green") green_wins++; + if(s2 == "blue") blue_wins++; + wins++; + eventForce("say w00t! "+s2+" wins!"); + return 1; + } + return 0; +} + +int LoseFun(string str){ + string foo; + if(sscanf(str,"%smay enter the %s room to get%s",s1,s2,s3) > 0){ + if(response == "stay") foo = secondchoice; + } + eventForce("say "+secondchoice+" wins, I guess."); + if(secondchoice == "red") red_wins++; + else if(secondchoice == "green") green_wins++; + else if(secondchoice == "blue") blue_wins++; + else eventForce("say WTF? foo is "+firstchoice); + losses++; + return 1; +} + +int eventPedestalParse(string str){ + if(sscanf(str,"%schoose one door from%s",s1,s2) > 0) choice1(); + if(sscanf(str,"%sI have opened%s",s1,s2) > 0) choice2(str); + if(sscanf(str,"%sminor glitch%s",s1,s2) > 0) playing = 0; + if(sscanf(str,"%sclaim your prize%s",s1,s2) > 0) WinFun(str); + if(sscanf(str,"%syour big load%s",s1,s2) > 0) LoseFun(str); + return 1; +} + +int eventFirstPass(string str){ + if(!str || str == "") return 0; + if(sscanf(str,"A voice from the pedestal%s",s1) > 0){ + eventPedestalParse(str); + return 1; + } + return 0; +} + +private void eventPrint(string str1, string str2); +void init(){ + ::init(); + set_heart_beat(5); + SetNoClean(1); +} + +void receive_message(string string1, string string2){ + eventFirstPass(string2); +} + +varargs mixed eventHearTalk(object who, object target, int cls, string verb, + string msg, string lang) { + ww=who; + vv=verb; + mm=msg; + unguarded((: this_object()->receive_message("me",ww->GetName()+" "+vv+"s: "+mm) :)); + return; +} +int eventPrint(string msg, string msg_class){ + printvar=msg; + unguarded((: this_object()->receive_message("me again",printvar) :)); +} + +void heart_beat(){ + if(!environment() || !clonep()){ + set_heart_beat(0); + return; + } + if(!playing){ + eventBeginPlay(); + } +} diff --git a/lib/domains/campus/npc/orc.c b/lib/domains/campus/npc/orc.c new file mode 100644 index 0000000..986e994 --- /dev/null +++ b/lib/domains/campus/npc/orc.c @@ -0,0 +1,44 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +int AllowPass(object who, object what){ + string *allowed_races = ({ "orc", "half-orc", "bear" }); + if(member_array(who->GetRace(), allowed_races) != -1) return 1; + return ::AllowPass(who, what); +} + +int CheckOrc(mixed val){ + string *allowed_races = ({ "orc", "half-orc", "bear" }); + if(!val) return 0; + if(!objectp(val)) return 0; + if(member_array(val->GetRace(), allowed_races) != -1) return 0; + else eventForce("growl at "+val->GetKeyName()); + return 0; +} + +static void create() { + ::create(); + SetKeyName("orc"); + SetId(({"orc"})); + SetAdjectives(({"dirty"})); + SetShort("a dirty orc"); + SetLong("This orc is typical of its breed: nasty, brutish, and short. It appears " + "to be a juvenile or adolescent, making it somewhat less " + "dangerous but more hostile. "); + SetLevel(1); + SetRace("orc"); + SetGender("male"); + SetMaxHealthPoints(100); + SetEncounter( (: CheckOrc :) ); + SetInventory(([ + "/domains/town/weap/dagger":"wield dagger", + ]) ); + SetGuard("west", "An orc bars your way!" ); + SetGuard("north", "An orc bars your way!"); +} +void init(){ + ::init(); +} +void reset(){ +} diff --git a/lib/domains/campus/npc/rat.c b/lib/domains/campus/npc/rat.c new file mode 100644 index 0000000..9fe01db --- /dev/null +++ b/lib/domains/campus/npc/rat.c @@ -0,0 +1,25 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("a mangy little rat"); + SetId(({"rat","dirty rat"})); + SetShort("a rat"); + SetLong("A scruffy little dirty rat."); + SetLevel(1); + SetMaxHealthPoints(5); + SetRace("rodent"); + SetGender("male"); + SetWanderSpeed(1); + SetMessage("come","$N scurries in."); + SetMessage("leave","$N scurries $D."); + SetAction(5, ({ + "The rat squeaks.", "You hear a rat scuttling about.", + "A scruffy little rat brushes against your leg.", + "You hear tiny munching sounds."})); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/npc/seth.c b/lib/domains/campus/npc/seth.c new file mode 100644 index 0000000..9cef299 --- /dev/null +++ b/lib/domains/campus/npc/seth.c @@ -0,0 +1,57 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +int give_it(string str); +static void create() { + sentient::create(); + SetKeyName("Dr. Seth Brundle"); + SetId(({"seth","brundle","Dr. Brundle","Seth","Brundle","seth brundle", "Seth Brundle"})); + SetShort("Dr. Seth Brundle"); + SetLong("Dr. Brundle is a tall, lanky scientist with an olive complexion "+ + "and dark, piercing eyes. He seems extremely upset, and hard at work. He looks "+ + "rumpled, wired, and really nervous."); + SetInventory(([ + "/domains/campus/obj/omni" : 1, + "/domains/campus/obj/labkey" : 1, + ])); + SetLevel(5); + SetUnique(1); + SetRace("human"); + SetGender("male"); + AddCommandResponse("give", (: give_it :)); + AddCommandResponse("omni", (: give_it :) ); + SetAction(25, ({ + "Seth Brundle runs a nervous hand through his hair.", + "Dr. Brundle twitches momentarily.", "Dr. Seth Brundle ponders.", + "Seth thinks.", "Dr. Seth Brundle thinks carefully.", + "Dr. Seth Brundle says, \"You won't be able to get back without an omni.\"", + "Dr. Seth Brundle peers nervously at the portal."})); +} +void reset(){ + if(!present("omni",this_object())){ + new("/domains/campus/obj/omni")->eventMove(this_object()); + return; + } +} +int give_it(string str){ + if(!present("omni",this_object())){ + this_object()->eventForce("say I'm afraid I don't have anything to give"); + this_object()->eventForce("ponder"); + return 1; + } + if(!present("omni",this_player())){ + write("Dr. Brundle looks at you skeptically for a moment.\n"); + say("Dr. Brundle looks at "+this_player()->GetName()+" skeptically for a moment.\n"); + this_object()->eventForce("give first omni to "+lower_case(this_player()->GetName()) ); + this_object()->eventForce("say Just try not to get killed, "+this_player()->GetName()); + this_object()->eventForce("sigh"); + return 1; + } + this_object()->eventForce("snort"); + this_object()->eventForce("say You've already got one, "+this_player()->GetName()); + return 1; +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/npc/tim.c b/lib/domains/campus/npc/tim.c new file mode 100644 index 0000000..c4458f0 --- /dev/null +++ b/lib/domains/campus/npc/tim.c @@ -0,0 +1,52 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +int DoSomething(){ + int rand; + string thing1, thing2, thing3, thing4, thing5; + string thing6, thing7, thing8, thing9, thing10; + if(!this_object() || !clonep() || !environment()) return 0; + rand = random(10); + + thing1 = "I think the campus is still under serious construction."; + thing2 = "I wonder when the classroom building will open."; + thing3 = "There's a village up north that's still being built, I heard."; + thing4 = "Any travel north of here may be unsafe, you know."; + thing5 = "Oh man, I need to get that stuff I left in the building basement."; + thing6 = "Why won't Kim ever buy or sell weapons?"; + thing7 = "How am I supposed to leave campus if Kim won't sell me a weapon?"; + thing8 = "Maybe there's a shop in the village up north where you can buy whatever you need."; + thing9 = "I heard you can get in trouble with the dean if you climb the tree."; + thing10 = "Some dude told me \bree-yark\" is \"we surrender\" in \"Kobold\". Does that even make any sense?"; + + switch(rand){ + case 1 : eventForce("say "+thing1);break; + case 2 : eventForce("say "+thing2);break; + case 3 : eventForce("say "+thing3);break; + case 4 : eventForce("say "+thing4);break; + case 5 : eventForce("say "+thing5);break; + case 6 : eventForce("say "+thing6);break; + case 7 : eventForce("say "+thing7);break; + case 8 : eventForce("say "+thing8);break; + case 9 : eventForce("say "+thing9);break; + case 10 : eventForce("say "+thing10);break; + default : eventForce("smile"); + } +} + +void create() { + sentient::create(); + SetKeyName("Tim"); + SetId(({"tim"})); + SetShort("Tim"); + SetLong("Tim is a student in the Virtual Campus."); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetAction(25, (: DoSomething :)); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/npc/turret.c b/lib/domains/campus/npc/turret.c new file mode 100644 index 0000000..88f9a3d --- /dev/null +++ b/lib/domains/campus/npc/turret.c @@ -0,0 +1,162 @@ +#include <lib.h> +#include <damage_types.h> +#include <position.h> + +inherit LIB_SENTIENT; +inherit LIB_ACTIVATE; +int active, ammo = 1000; + +int eventShootDude(object ob){ + int dam, numlimbs; + string limbname, str; + string *limbs; + if(!environment()) return 0; + str = ob->GetName(); + if(!ammo){ + tell_room(environment(),"The gun turret clicks."); + active = 0; + return 0; + } + tell_object(this_object(),"You fire at "+ob->GetName()+"!"); + tell_room(environment(),"The gun turret fires at "+ob->GetName()+"!", + ({this_object(),ob})); + tell_object(ob,"The gun turret fires at you!"); + ammo--; + if(random(100) < 10) return 1; + limbs=ob->GetLimbs(); + numlimbs=sizeof(limbs); + limbname = limbs[random(numlimbs-1)]; + tell_room(environment(this_object()), + "The bullet smashes into "+ + capitalize(str)+"'s "+limbname+"!\n",ob); + tell_object(ob,"The bullet smashes into your "+limbname+"!\n"); + ob->SetAttack(this_agent()); + if(!present("firearms_wound",ob)){ + new(LIB_WOUND)->eventMove(ob); + } + ob->AddLead("gunshot_wounds", 1); + dam = 20; + dam *= random(10); + dam -= random(ob->GetStatLevel("coordination")); + ob->eventReceiveDamage(this_object(),(PIERCE), dam, 0, limbname); + if(!ob->GetInCombat()){ + ob->eventForce("attack "+this_object()->GetKeyName()); + } + return 1; +} + +int eventHoseTarget(object target){ + int repeat = 10; + if(!target) return 0; + //write("Hosing target: "+identify(target)); + while(repeat && !(target->GetDying())){ + eventShootDude(target); + repeat--; + } + return 1; +} + +int eventTargetScan(){ + object *targets; + int targs; + if(!environment() || !active) return 0; + targets = filter(get_livings(environment()), (: !($1->GetInvis()) && + $1->GetRace() != "bot" :)); + targets = scramble_array(targets); + targets -= ({ this_object() }); + if(!(targs = sizeof(targets))) return 0; + if(targs > 10) targs = 10; + else { + eventForce("say "+cardinal(targs)+" target"+ + ((targs > 1) ? "s" : "" )+" acquired."); + } + targs--; + targets = targets[0..targs]; + foreach(object target in targets){ + eventHoseTarget(target); + } + return 1; +} + +int AddLegs(){ + AddLimb("first leg", "torso", 2); + AddLimb("second leg", "torso", 2); + AddLimb("third leg", "torso", 2); + return 1; +} + +int ActivateTurret(){ + if(!ammo){ + write("The turret clicks and goes silent."); + return 0; + } + active = 1; + eventForce("say TURRET IS NOW FULLY ARMED AND OPERATIONAL."); + eventTargetScan(); + set_heart_beat(1); + return 1; +} + +static void create() { + sentient::create(); + SetKeyName("gun turret"); + SetId( ({"bot", "robot","turret"}) ); + SetAdjectives(({"non-player", "non player"})); + SetShort("a gun turret"); + SetLong("This is a four foot tall metal turret on tripod legs "+ + "designed to automatically acquire and engage any moving " + "targets with its massive 20 millimeter guns."); + SetPosition(POSITION_STANDING); + SetLevel(1); + SetPacifist(1); + SetNoClean(0); + SetRace("bot"); + SetClass("fighter"); + SetGender("neuter"); + SetPolyglot(1); + call_out("AddLegs",0); + SetLanguage("common",100); + SetDefaultLanguage("common"); +} + +void init(){ + ::init(); +} + +int eventTurnOn(){ + if(active){ + write("The turret is already active."); + return 1; + } + else { + call_out("ActivateTurret",7); + write("You activate the gun turret."); + eventForce("say TURRET ACTIVE."); + eventForce("say YOU HAVE 5 SECONDS TO REACH MINIMUM SAFE DISTANCE."); + } + return 1; +} + +int eventTurnOff(){ + if(!active){ + write("The turret is already inactive."); + return 1; + } + else { + write("It seems this turret cannot be deactivated."); + //write("You deactivate the gun turret."); + //active = 0; + } + return 1; +} + +void heart_beat(){ + ::heart_beat(); + eventTargetScan(); +} + +varargs int eventReceiveDamage(mixed agent, int type, int x, int internal, + mixed limbs){ + ActivateTurret(); + return ::eventReceiveDamage(agent, type, x, internal, limbs); +} diff --git a/lib/domains/campus/npc/wim.c b/lib/domains/campus/npc/wim.c new file mode 100644 index 0000000..d14d300 --- /dev/null +++ b/lib/domains/campus/npc/wim.c @@ -0,0 +1,17 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("Wim"); + SetId(({"wim"})); + SetShort("Wim"); + SetLong("Wim is a foreign exchange student from the Netherlands."); + SetLevel(5); + SetRace("human"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/npc/yulia.c b/lib/domains/campus/npc/yulia.c new file mode 100644 index 0000000..9fe7e2a --- /dev/null +++ b/lib/domains/campus/npc/yulia.c @@ -0,0 +1,35 @@ +/* /domains/Praxis/npc/otik.c + * from Dead Souls + * created by Descartes of Borg 950603 + */ + +#include <lib.h> +#include <vendor_types.h> + +inherit LIB_VENDOR; + +static void create() { + ::create(); + SetKeyName("yulia"); + SetId( ({ "vendor","secretary","assistant","manager" }) ); + SetAdjectives( ({ "executive","medical","guild" }) ); + SetShort("Yulia, the clinic assistant"); + SetLevel(12); + SetLong("Yulia is typical of office assistants: she is a bit "+ + "arrogant, officious, and brusque; but she appears "+ + "to be a competent enough secretary. "+ + "She is the person you will buy a treatment slip "+ + "from. Read the list on the wall for the slips "+ + "available."); + SetGender("female"); + SetMorality(40); + SetRace("human"); + AddCurrency("dollars", random(100)); + SetProperty("no bump", 1); + SetLocalCurrency("dollars"); + SetStorageRoom("/domains/campus/room/healer2"); + SetMaxItems(10000); + SetVendorType(VT_HERB); + SetSkill("bargaining", 1); + +} diff --git a/lib/domains/campus/obj/223clip.c b/lib/domains/campus/obj/223clip.c new file mode 100644 index 0000000..e7ee84c --- /dev/null +++ b/lib/domains/campus/obj/223clip.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_CLIP; + +void create(){ + clip::create(); + SetKeyName(".223 clip"); + SetId(({"clip","magazine"})); + SetAdjectives(({".223","rifle","caliber","ammo","ammunition"})); + SetShort("a .223 caliber rifle ammunition clip"); + SetLong("This is a spring-loaded ammunition clip for a .223 caliber "+ + "rifle. It will contain a maximum of thirty rounds."); + SetCaliber(223); + SetMaxAmmo(30); + SetAmmoType("nato"); + SetVendorType(VT_TREASURE); + SetInventory(([ + "/domains/campus/obj/223round" : 30, + ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/223round.c b/lib/domains/campus/obj/223round.c new file mode 100644 index 0000000..33fc9fc --- /dev/null +++ b/lib/domains/campus/obj/223round.c @@ -0,0 +1,19 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ROUND; + +void create(){ + round::create(); + SetKeyName("223round"); + SetId(({"round","bullet"})); + SetAdjectives(({".223","caliber","rifle","m16","M16","m-16","M-16"})); + SetShort("a .223 caliber rifle round"); + SetLong("This is a .223 caliber rifle round, probably for an M-16 assault rifle. "+ + "It is not very wide, but contains a large powder charge. It is no doubt a powerful "+ + "piece of ammunition. It has not been fired."); + SetCaliber(223); + SetFirearmType("auto"); + SetFirearmType("auto"); + SetAmmoType("nato"); + SetVendorType(VT_TREASURE); +} diff --git a/lib/domains/campus/obj/357case.c b/lib/domains/campus/obj/357case.c new file mode 100644 index 0000000..47c82a6 --- /dev/null +++ b/lib/domains/campus/obj/357case.c @@ -0,0 +1,27 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + storage::create(); + SetKeyName("cardboard case"); + SetAdjectives( ({"small", "cardboard", "357", "ammo"}) ); + SetId( ({ "case" }) ); + SetShort("a small .357 ammo case"); + SetLong("A small cardboard case designed to carry .357 caliber amunition."); + SetMass(10); + SetDollarCost(1); + SetMaxCarry(12); +} + +mixed CanReceive(object ob){ + if(ob->GetKeyName() != ".357 round") { + tell_object(this_player(),"This cardboard case is for .357 ammunition only."); + return 0; + } + return storage::CanReceive(ob); +} + +void init(){ + storage::init(); +} diff --git a/lib/domains/campus/obj/357round.c b/lib/domains/campus/obj/357round.c new file mode 100644 index 0000000..8e8252e --- /dev/null +++ b/lib/domains/campus/obj/357round.c @@ -0,0 +1,17 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ROUND; + +void create(){ + round::create(); + SetKeyName(".357 round"); + SetId(({"round","bullet"})); + SetAdjectives(({".357","caliber","revolver","pistol"})); + SetShort("a .357 pistol round"); + SetLong("This is a .357 caliber revolver bullet. It has not been fired."); + SetCaliber(357); + SetFirearmType("revolver"); + SetAmmoType("magnum"); + SetVendorType(VT_TREASURE); + SetMass(1); +} diff --git a/lib/domains/campus/obj/357shell.c b/lib/domains/campus/obj/357shell.c new file mode 100644 index 0000000..af506a9 --- /dev/null +++ b/lib/domains/campus/obj/357shell.c @@ -0,0 +1,20 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_SHELL; + +void create(){ + shell::create(); + SetKeyName("357shell"); + SetId(({"shell","casing","spent bullet"})); + SetAdjectives(({".357","spent","magnum","shell"})); + SetShort("a .357 shell casing"); + SetLong("This is the spent casing of a .357 magnum bullet."); + SetCaliber(357); + SetFirearmType("revolver"); + SetAmmoType("magnum"); + SetVendorType(VT_TREASURE); +} + +void init(){ + shell::init(); +} diff --git a/lib/domains/campus/obj/45case.c b/lib/domains/campus/obj/45case.c new file mode 100644 index 0000000..243fe64 --- /dev/null +++ b/lib/domains/campus/obj/45case.c @@ -0,0 +1,30 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + storage::create(); + SetKeyName("cardboard case"); + SetAdjectives( ({"small", "cardboard", "45", "ammo", "ammunition"}) ); + SetId( ({ "case" }) ); + SetShort("a small .45 ammo case"); + SetLong("A small cardboard case designed to carry .45 caliber acp amunition."); + SetMass(10); + SetDollarCost(1); + SetMaxCarry(12); + SetInventory( ([ + "/domains/campus/obj/45round" : 12, + ]) ); +} + +mixed CanReceive(object ob){ + if(ob->GetKeyName() != ".45 round") { + write("This cardboard case is for .45 acp ammunition only."); + return 0; + } + return storage::CanReceive(ob); +} + +void init(){ + storage::init(); +} diff --git a/lib/domains/campus/obj/45round.c b/lib/domains/campus/obj/45round.c new file mode 100644 index 0000000..183a4e2 --- /dev/null +++ b/lib/domains/campus/obj/45round.c @@ -0,0 +1,17 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ROUND; + +void create(){ + round::create(); + SetKeyName(".45 round"); + SetId(({"round","bullet"})); + SetAdjectives(({".45","caliber","acp","pistol","semiautomatic"})); + SetShort("a .45 caliber pistol round"); + SetLong("This is a .45 caliber bullet for a semiautomatic pistol. It has not been fired."); + SetCaliber(45); + SetFirearmType("auto"); + SetAmmoType("acp"); + SetVendorType(VT_TREASURE); + SetMass(1); +} diff --git a/lib/domains/campus/obj/50round.c b/lib/domains/campus/obj/50round.c new file mode 100644 index 0000000..0445d4e --- /dev/null +++ b/lib/domains/campus/obj/50round.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ROUND; + +void create(){ + round::create(); + SetKeyName(".50 round"); + SetId(({"round","bullet"})); + SetAdjectives(({".50","caliber","rifle"})); + SetShort("a .50 caliber rifle bullet"); + SetLong("This mammoth bullet is nearly five inches long. Anything this bad "+ + "boy hits is in for a rough time."); + SetCaliber(50); + SetFirearmType("bolt"); + SetFirearmType("bolt"); + SetAmmoType("bolt"); + SetVendorType(VT_TREASURE); +} diff --git a/lib/domains/campus/obj/9mmbox.c b/lib/domains/campus/obj/9mmbox.c new file mode 100644 index 0000000..7cba45b --- /dev/null +++ b/lib/domains/campus/obj/9mmbox.c @@ -0,0 +1,32 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + storage::create(); + SetKeyName("cardboard case"); + SetId(({"case","box"})); + SetAdjectives(({"small", "cardboard", "9mm", "9 millimeter", "ammo"})); + SetShort("a small 9mm ammo case"); + SetLong("A small cardboard case designed to carry 9mm ammunition."); + SetMass(10); + SetDollarCost(1); + SetMaxCarry(36); + SetCanClose(1); + SetClosed(0); + SetInventory( ([ + "/domains/campus/obj/9mmround": 30 + ]) ); +} + +mixed CanReceive(object ob){ + if(ob->GetKeyName() != "9mm round") { + tell_object(this_player(),"This cardboard case is for 9mm ammunition only."); + return 0; + } + return storage::CanReceive(ob); +} + +void init(){ + storage::init(); +} diff --git a/lib/domains/campus/obj/9mmclip.c b/lib/domains/campus/obj/9mmclip.c new file mode 100644 index 0000000..0121634 --- /dev/null +++ b/lib/domains/campus/obj/9mmclip.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_CLIP; + +void create(){ + clip::create(); + SetKeyName("9mm clip"); + SetId(({"clip","magazine"})); + SetAdjectives(({"9mm","ammunition","ammo","9 millimeter","pistol"})); + SetShort("a 9 millimeter pistol ammunition clip"); + SetLong("This is a slender, spring-loaded metal container designed "+ + "to feed a 9 millimeter pistol with bullets."); + SetMillimeter(9); + SetMaxAmmo(15); + SetAmmoType("acp"); + SetVendorType(VT_TREASURE); + SetInventory(([ + "/domains/campus/obj/9mmround" : 15 + ])); +} + +void init(){ + clip::init(); +} diff --git a/lib/domains/campus/obj/9mmround.c b/lib/domains/campus/obj/9mmround.c new file mode 100644 index 0000000..d40fe56 --- /dev/null +++ b/lib/domains/campus/obj/9mmround.c @@ -0,0 +1,16 @@ +#include <lib.h> +#include <vendor_types.h> +inherit "/lib/round"; + +void create(){ + ::create(); + SetKeyName("9mmround"); + SetId(({"round","bullet"})); + SetAdjectives(({"9 millimeter","9mm","pistol"})); + SetShort("a 9 millimeter pistol round"); + SetLong("This is a 9 millimeter pistol bullet. It has not been fired."); + SetMillimeter(9); + SetFirearmType("auto"); + SetAmmoType("acp"); + SetVendorType(VT_TREASURE); +} diff --git a/lib/domains/campus/obj/abox.c b/lib/domains/campus/obj/abox.c new file mode 100644 index 0000000..6da8e86 --- /dev/null +++ b/lib/domains/campus/obj/abox.c @@ -0,0 +1,37 @@ +/* /domains/Examples/etc/bag.c + * from the Dead Souls LPC Library + * a sample bag object + * created by Descartes of Borg 950529 + */ + +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("ammunition box"); + SetId(({"can","box"})); + SetAdjectives(({"metal","ammo","ammunition","large"})); + SetShort("an ammo box"); + SetLong("This is a large metal box containing various kinds "+ + "of ammunition. "); + SetMass(200); + SetDollarCost(50); + SetMaxCarry(5000); + SetCanClose(1); + SetClosed(0); + + SetInventory( ([ + "/domains/campus/obj/9mmclip": 10, + "/domains/campus/obj/223clip": 10, + "/domains/campus/obj/357case": 10 + ]) ); + +} + +void init(){ + ::init(); +} + +mixed CanGet(object ob) { return "The metal ammunition box does not budge.";} diff --git a/lib/domains/campus/obj/apple.c b/lib/domains/campus/obj/apple.c new file mode 100644 index 0000000..c438439 --- /dev/null +++ b/lib/domains/campus/obj/apple.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; + +void create(){ + ::create(); + SetKeyName("rotten apple"); + SetId( ({"apple","fruit"}) ); + SetAdjectives( ({"rotten","foul-smelling","dried-up","browned","brown"}) ); + SetShort("a rotten apple"); + SetLong("This is browned, foul-smelling, dried-up apple."); + SetMass(5); + SetDollarCost(0); + SetVendorType(VT_TREASURE); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/backpack.c b/lib/domains/campus/obj/backpack.c new file mode 100644 index 0000000..3d60026 --- /dev/null +++ b/lib/domains/campus/obj/backpack.c @@ -0,0 +1,39 @@ +#include <lib.h> + +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_WORN_STORAGE; + +static void create() { + ::create(); + SetKeyName("backpack"); + SetId(({"bag","pack"})); + SetAdjectives(({"sturdy","green","olive","olive-green","od green","od-green"})); + SetShort("a sturdy, olive-green backpack"); + SetLong("This is a large, sturdy backpack made of some sort of " + "strong, canvas-like material. It appears suitable "+ + "for just about any adventure you'd find yourself in."); + SetInventory(([ + "/domains/campus/obj/match" : 3, + "/domains/campus/weap/sharpsword" : 1, + "/domains/campus/armor/chainmail" : 1, + "/domains/campus/meals/burger" : 3, + "/domains/campus/armor/helmet" : 1, + "/domains/campus/armor/shield" : 1, + "/domains/campus/obj/maglite" : 1, + "/domains/campus/armor/collar" : 1, + "/domains/campus/meals/wimp_ale" : 3, + "/domains/campus/obj/torch" : 1, + ])); + SetMass(100); + SetBaseCost("silver", 40); + SetCanClose(1); + SetClosed(0); + SetMaxCarry(500); + SetDamagePoints(100); + SetArmorType(A_VEST); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/backpack_civilian.c b/lib/domains/campus/obj/backpack_civilian.c new file mode 100644 index 0000000..ec4259e --- /dev/null +++ b/lib/domains/campus/obj/backpack_civilian.c @@ -0,0 +1,27 @@ +#include <lib.h> + +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_WORN_STORAGE; + +static void create() { + ::create(); + SetKeyName("backpack"); + SetId(({"bag","pack"})); + SetAdjectives(({"sturdy","green","olive","olive-green","od green","od-green"})); + SetShort("a sturdy, olive-green backpack"); + SetLong("This is a large, sturdy backpack made of some sort of " + "strong, canvas-like material. It appears suitable "+ + "for just about any adventure you'd find yourself in."); + SetMass(100); + SetBaseCost("silver", 40); + SetCanClose(1); + SetClosed(0); + SetMaxCarry(500); + SetDamagePoints(100); + SetArmorType(A_VEST); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/backpack_empty.c b/lib/domains/campus/obj/backpack_empty.c new file mode 100644 index 0000000..ec4259e --- /dev/null +++ b/lib/domains/campus/obj/backpack_empty.c @@ -0,0 +1,27 @@ +#include <lib.h> + +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_WORN_STORAGE; + +static void create() { + ::create(); + SetKeyName("backpack"); + SetId(({"bag","pack"})); + SetAdjectives(({"sturdy","green","olive","olive-green","od green","od-green"})); + SetShort("a sturdy, olive-green backpack"); + SetLong("This is a large, sturdy backpack made of some sort of " + "strong, canvas-like material. It appears suitable "+ + "for just about any adventure you'd find yourself in."); + SetMass(100); + SetBaseCost("silver", 40); + SetCanClose(1); + SetClosed(0); + SetMaxCarry(500); + SetDamagePoints(100); + SetArmorType(A_VEST); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/bag.c b/lib/domains/campus/obj/bag.c new file mode 100644 index 0000000..0d7c9dc --- /dev/null +++ b/lib/domains/campus/obj/bag.c @@ -0,0 +1,27 @@ +/* /domains/Examples/etc/bag.c + * from the Dead Souls LPC Library + * a sample bag object + * created by Descartes of Borg 950529 + */ + +#include <lib.h> + +inherit LIB_STORAGE; + + +void create() { + ::create(); + SetKeyName("bag"); + SetId( ({ "bag" }) ); + SetAdjectives( ({ "small", "cloth", "a" }) ); + SetShort("a small cloth bag"); + SetLong("It is a simple cloth bag used to hold things. It has a cute Virtual Campus "+ + "logo on it."); + SetMass(274); + SetDollarCost(1); + SetMaxCarry(50); + // SetPreventPut("You cannot put this in there!"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/bbucket.c b/lib/domains/campus/obj/bbucket.c new file mode 100644 index 0000000..dd8f088 --- /dev/null +++ b/lib/domains/campus/obj/bbucket.c @@ -0,0 +1,35 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("bin"); + SetId(({"bin","can","dustbin","trash","rubbish"})); + SetAdjectives(({"metal","small","blue","recycling","trash","garbage","dust"})); + SetShort("a recycling bin"); + SetLong("This is a blue trash can, marked with "+ + "the letters \"/dev/null\"."); + SetMass(274); + SetBaseCost("silver",50); + SetMaxCarry(999999); +} + +int tidy_up(){ + object *inv; + inv = all_inventory(this_object()); + foreach(object thing in inv){ + if(thing) thing->eventMove(load_object("/domains/town/room/furnace")); + } + return 1; +} + +int eventReceiveObject(object ob){ + write("You make a deposit into the the recycling bin.\n"); + call_out((: tidy_up :),1); + return 1; +} +mixed CanGet(object ob) { return "The bucket does not budge.";} + +void init(){ +} diff --git a/lib/domains/campus/obj/bench.c b/lib/domains/campus/obj/bench.c new file mode 100644 index 0000000..90e5bda --- /dev/null +++ b/lib/domains/campus/obj/bench.c @@ -0,0 +1,27 @@ +/* /domains/campus/etc/stool.c + * From the Dead Souls Object Library + * An example of a chair object + * Created by Descartes of Borg 961221 + */ + +#include <lib.h> + +inherit LIB_CHAIR; + + +static void create() { + chair::create(); + SetKeyName("bench"); + SetId("bench"); + SetAdjectives("wooden"); + SetShort("a wooden bench"); + SetLong("This is a typical wooden bench, the sort you might "+ + "see in a park. It appears designed for sitting on."); + SetMass(1500); + SetDollarCost(15); + SetMaxSitters(3); +} +mixed CanGet(object ob) { return "The bench does not budge.";} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/bluebox.c b/lib/domains/campus/obj/bluebox.c new file mode 100644 index 0000000..8071dd6 --- /dev/null +++ b/lib/domains/campus/obj/bluebox.c @@ -0,0 +1,28 @@ +/* /domains/Examples/etc/bag.c + * from the Dead Souls LPC Library + * a sample bag object + * created by Descartes of Borg 950529 + */ + +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("bluebox"); + SetId( ({ "box","bluebox", "bbox" }) ); + SetAdjectives( ({ "small", "plastic","blue", "a" }) ); + SetShort("a small, %^BLUE%^blue%^RESET%^ plastic box"); + SetLong("It is a simple plastic box used to hold things. It is %^BLUE%^blue%^RESET%^, and it has a cute Virtual Campus "+ + "logo on it."); + SetMass(274); + SetDollarCost(1); + SetMaxCarry(100); + SetCanClose(1); + SetClosed(0); + // SetPreventPut("You cannot put this in there!"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/box.c b/lib/domains/campus/obj/box.c new file mode 100644 index 0000000..e12c15a --- /dev/null +++ b/lib/domains/campus/obj/box.c @@ -0,0 +1,26 @@ +/* /domains/Examples/etc/bag.c + * from the Dead Souls LPC Library + * a sample bag object + * created by Descartes of Borg 950529 + */ + +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("box"); + SetId( ({ "box" }) ); + SetAdjectives( ({ "small", "plastic","green", "a" }) ); + SetShort("a small plastic box"); + SetLong("It is a simple plastic box used to hold things. It is green, and it has a cute Virtual Campus "+ + "logo on it."); + SetMass(274); + SetDollarCost(1); + SetMaxCarry(10); + // SetPreventPut("You cannot put this in there!"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/chair.c b/lib/domains/campus/obj/chair.c new file mode 100644 index 0000000..c95e38a --- /dev/null +++ b/lib/domains/campus/obj/chair.c @@ -0,0 +1,43 @@ +#include <lib.h> + +inherit LIB_CHAIR; + + +static void create() { + chair::create(); + SetKeyName("chair"); + SetId("chair"); + SetAdjectives( ({ "swivel", "small", "black" }) ); + SetShort("a swivel chair"); + SetLong("This is a small swivel chair, with tasteful and understated "+ + "black covers."); + SetMass(1500); + SetDollarCost(15); + SetMaxSitters(1); +} +void init(){ + ::init(); + add_action("swivel","swivel"); +} +int swivel(string str){ + int hit,i; + object *dupes; + dupes = get_dupes(this_object(),environment(this_object()) ); + if(!str || str =="" || str == "in chair" || str == "in the chair"){ + hit = 42; + for(i=0;i<sizeof(dupes);i++){ + if( member_array(this_player(),dupes[i]->GetSitters()) != -1) hit = 7; + if( member_array(this_player(),this_object()->GetSitters()) != -1) hit = 7; + } + if( hit == 7) { + write("You swivel around in your swivel chair! Whee!"); + say(this_player()->GetName()+" swivels around in "+possessive(this_player())+" "+ + "swivel chair, yelling \"WHEEEE!!!\""); + return 1; + } + else { write("You are not sitting in a swivel chair."); } + } + if(hit == 42) return 1; + else return 0; +} +mixed CanGet(object ob) { return "The chair does not budge.";} diff --git a/lib/domains/campus/obj/clip.c b/lib/domains/campus/obj/clip.c new file mode 100644 index 0000000..0121634 --- /dev/null +++ b/lib/domains/campus/obj/clip.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_CLIP; + +void create(){ + clip::create(); + SetKeyName("9mm clip"); + SetId(({"clip","magazine"})); + SetAdjectives(({"9mm","ammunition","ammo","9 millimeter","pistol"})); + SetShort("a 9 millimeter pistol ammunition clip"); + SetLong("This is a slender, spring-loaded metal container designed "+ + "to feed a 9 millimeter pistol with bullets."); + SetMillimeter(9); + SetMaxAmmo(15); + SetAmmoType("acp"); + SetVendorType(VT_TREASURE); + SetInventory(([ + "/domains/campus/obj/9mmround" : 15 + ])); +} + +void init(){ + clip::init(); +} diff --git a/lib/domains/campus/obj/dcell.c b/lib/domains/campus/obj/dcell.c new file mode 100644 index 0000000..27936d0 --- /dev/null +++ b/lib/domains/campus/obj/dcell.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <vendor_types.h> +inherit "/lib/battery"; + +void create(){ + ::create(); + SetKeyName("d-cell"); + SetId( ({"cell","battery"}) ); + SetAdjectives( ({"d","generic","D","D-cell"}) ); + SetShort("a D cell battery"); + SetLong("This is a typical D-cell battery, of a generic brand."); + SetMass(2); + SetDollarCost(2); + SetVendorType(VT_TREASURE); + SetPowerType("DC"); + SetCellType("D"); + SetCharge(60); + SetRechargeable(0); + SetDrainable(1); + SetDrainRate(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/dcell_crappy.c b/lib/domains/campus/obj/dcell_crappy.c new file mode 100644 index 0000000..27936d0 --- /dev/null +++ b/lib/domains/campus/obj/dcell_crappy.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <vendor_types.h> +inherit "/lib/battery"; + +void create(){ + ::create(); + SetKeyName("d-cell"); + SetId( ({"cell","battery"}) ); + SetAdjectives( ({"d","generic","D","D-cell"}) ); + SetShort("a D cell battery"); + SetLong("This is a typical D-cell battery, of a generic brand."); + SetMass(2); + SetDollarCost(2); + SetVendorType(VT_TREASURE); + SetPowerType("DC"); + SetCellType("D"); + SetCharge(60); + SetRechargeable(0); + SetDrainable(1); + SetDrainRate(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/dcell_good.c b/lib/domains/campus/obj/dcell_good.c new file mode 100644 index 0000000..0ce48fd --- /dev/null +++ b/lib/domains/campus/obj/dcell_good.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <vendor_types.h> +inherit "/lib/battery"; + +void create(){ + ::create(); + SetKeyName("d-cell"); + SetId( ({"cell","battery"}) ); + SetAdjectives( ({"d","generic","D","D-cell"}) ); + SetShort("a D cell battery"); + SetLong("This is a typical D-cell battery, of a generic brand."); + SetMass(2); + SetDollarCost(2); + SetVendorType(VT_TREASURE); + SetPowerType("DC"); + SetCellType("D"); + SetCharge(10000); + SetRechargeable(0); + SetDrainable(1); + SetDrainRate(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/dcell_std.c b/lib/domains/campus/obj/dcell_std.c new file mode 100644 index 0000000..034d4a0 --- /dev/null +++ b/lib/domains/campus/obj/dcell_std.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <vendor_types.h> +inherit "/lib/battery"; + +void create(){ + ::create(); + SetKeyName("d-cell"); + SetId( ({"cell","battery"}) ); + SetAdjectives( ({"d","generic","D","D-cell"}) ); + SetShort("a D cell battery"); + SetLong("This is a typical D-cell battery, of a generic brand."); + SetMass(2); + SetDollarCost(2); + SetVendorType(VT_TREASURE); + SetPowerType("DC"); + SetCellType("D"); + SetCharge(1000); + SetRechargeable(0); + SetDrainable(1); + SetDrainRate(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/debris.c b/lib/domains/campus/obj/debris.c new file mode 100644 index 0000000..623ab9c --- /dev/null +++ b/lib/domains/campus/obj/debris.c @@ -0,0 +1,46 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; + +int ringfound; +string SearchCrap(){ + string result; + if(!ringfound){ + result="Rummaging through the disgusting pile, you "+ + "discover a beautiful gold ring mixed in with the "+ + "crap."; + say(this_player()->GetName()+" searches the pile of debris "+ + "and seems to have found something of value."); + if(!new("/domains/campus/armor/ring")->eventMove(this_player())) + new("/domains/campus/armor/ring")->eventMove(environment(this_object())); + ringfound=1; + return result; + } + + result="You rummage through the disgusting pile "+ + "and find nothing."; + say(this_player()->GetName()+" searches the pile of debris "+ + "with no results."); + return result; +} +void create(){ + ::create(); + SetKeyName("debris"); + SetId( ({"pile","debris","crap","crud"}) ); + SetAdjectives( ({"disgusting","pile of","smelly"}) ); + SetShort("a pile of debris"); + SetLong("This is a smelly, disgusting pile of crud "+ + "that has accumulated from the running stream of "+ + "sewage here. "); + SetMass(20); + SetDollarCost(0); + SetVendorType(VT_TREASURE); + SetSearch( (: SearchCrap :) ); + ringfound=0; + +} +mixed CanGet(object ob) { return "The pile of debris isn't at all portable.";} +string GetItemCondition() { return "";} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/diamond.c b/lib/domains/campus/obj/diamond.c new file mode 100644 index 0000000..49a06b7 --- /dev/null +++ b/lib/domains/campus/obj/diamond.c @@ -0,0 +1,19 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; + +void create(){ + ::create(); + SetKeyName("diamond"); + SetAdjectives( ({"fabled", "beautiful", "princess", "princess daphne"}) ); + SetId( ({"gem", "gemstone"}) ); + SetShort("a beautiful diamond"); + SetLong("This is the fabled Princess Daphne diamond. It is a beautiful gem."); + SetMass(200); + SetBaseCost("dollars", 50000); + SetVendorType(VT_TREASURE); + SetProperty("gem", 1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/flashlight.c b/lib/domains/campus/obj/flashlight.c new file mode 100644 index 0000000..95f26bd --- /dev/null +++ b/lib/domains/campus/obj/flashlight.c @@ -0,0 +1,14 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +void create(){ + ::create(); + SetKeyName("generic thing"); + SetId( ({"thing","item","thang","dingus"}) ); + SetAdjectives( ({"generic","sample","template"}) ); + SetShort("a generic thing"); + SetLong("This is an object of indeterminate nature and proportions."); + SetMass(20); + SetDollarCost(10); + SetVendorType(VT_TREASURE); +} diff --git a/lib/domains/campus/obj/greenbox.c b/lib/domains/campus/obj/greenbox.c new file mode 100644 index 0000000..9f99155 --- /dev/null +++ b/lib/domains/campus/obj/greenbox.c @@ -0,0 +1,28 @@ +/* /domains/Examples/etc/bag.c + * from the Dead Souls LPC Library + * a sample bag object + * created by Descartes of Borg 950529 + */ + +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("greenbox"); + SetId( ({ "box","greenbox","gbox" }) ); + SetAdjectives( ({ "small", "plastic","green", "a" }) ); + SetShort("a small, %^GREEN%^green%^RESET%^ plastic box"); + SetLong("It is a simple plastic box used to hold things. It is %^GREEN%^green%^RESET%^, and it has a cute Virtual Campus "+ + "logo on it."); + SetMass(274); + SetDollarCost(1); + SetMaxCarry(100); + SetCanClose(1); + SetClosed(0); + // SetPreventPut("You cannot put this in there!"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/key.c b/lib/domains/campus/obj/key.c new file mode 100644 index 0000000..4d4d37a --- /dev/null +++ b/lib/domains/campus/obj/key.c @@ -0,0 +1,24 @@ +/* /domains/Midian/etc/key.c + * from the Dead Souls Object Library + * created by Descartes of Borg 960512 + */ + +#include <lib.h> + +inherit LIB_ITEM; + + +static void create() { + item::create(); + SetKeyName("key"); + SetId( ({ "key", "special_key_id" }) ); + SetAdjectives( ({ "brilliant", "silver" }) ); + SetShort("a silver key"); + SetLong("It is a brilliant silver key with no markings."); + SetMass(50); + SetDollarCost(15); + SetDisableChance(90); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/key1.c b/lib/domains/campus/obj/key1.c new file mode 100644 index 0000000..c4aa56b --- /dev/null +++ b/lib/domains/campus/obj/key1.c @@ -0,0 +1,24 @@ +/* /domains/Midian/etc/key.c + * from the Dead Souls Object Library + * created by Descartes of Borg 960512 + */ + +#include <lib.h> + +inherit LIB_ITEM; + + +static void create() { + item::create(); + SetKeyName("key"); + SetId(({"key","locker_key_1"})); + SetAdjectives(({"locker","small",})); + SetShort("a small key"); + SetLong("This is a small key, perhaps to a padlock or locker."); + SetMass(1); + SetDollarCost(2); + SetDisableChance(90); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/labkey.c b/lib/domains/campus/obj/labkey.c new file mode 100644 index 0000000..1ce44d2 --- /dev/null +++ b/lib/domains/campus/obj/labkey.c @@ -0,0 +1,19 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; + +void create(){ + ::create(); + SetKeyName("lab key"); + SetAdjectives( ({"engineering", "lab", "probability lab"}) ); + SetId( ({"prob_door_key", "key", "labkey"}) ); + SetShort("a key"); + SetLong("This is a key labeled 'engineering and lab'."); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/lamp.c b/lib/domains/campus/obj/lamp.c new file mode 100644 index 0000000..c905b2a --- /dev/null +++ b/lib/domains/campus/obj/lamp.c @@ -0,0 +1,12 @@ +#include <lib.h> + +inherit LIB_DUMMY; // These do not show up in desc, but you can look at them + +static void create() { + dummy::create(); + SetKeyName("lamp"); + SetId("lamp on a post","post","lamp post","lamppost"); + SetShort("a lamp on a post"); + SetLong("This is a lamp on a post which is lit at night so townsfolk " + "can find their way around."); +} diff --git a/lib/domains/campus/obj/lever.c b/lib/domains/campus/obj/lever.c new file mode 100644 index 0000000..2c8846f --- /dev/null +++ b/lib/domains/campus/obj/lever.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; + +void create(){ + ::create(); + SetKeyName("hand grenade spoon"); + SetId(({"lever","spoon"})); + SetAdjectives(({"grenade","hand grenade","metal","small"})); + SetShort("a small metal lever"); + SetLong("This is the fuse lever, or spoon, for a hand grenade."); + SetMass(1); + SetDollarCost(0); + SetVendorType(VT_TREASURE); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/locker.c b/lib/domains/campus/obj/locker.c new file mode 100644 index 0000000..63bd495 --- /dev/null +++ b/lib/domains/campus/obj/locker.c @@ -0,0 +1,38 @@ +/* /domains/Examples/etc/bag.c + * from the Dead Souls LPC Library + * a sample bag object + * created by Descartes of Borg 950529 + */ + +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("locker"); + //SetMatching(0); + SetId(({"locker"})); + SetAdjectives(({"metal","tall","school"})); + SetShort("a tall metal locker"); + SetLong("This is a large school locker, the kind one might find in any of "+ + "thousands of schools around the world."); + SetInventory(([ + "/domains/campus/weap/waterpistol" : 1, + "/domains/town/obj/9mmclip" : 1, + "/domains/campus/obj/bag" : 1, + "/domains/campus/obj/dcell_std" : 4, + ])); + SetMass(274); + SetDollarCost(50); + SetMaxCarry(500); + SetCanClose(1); + SetClosed(1); + SetCanLock(1); + SetLocked(1); + SetKey("locker_key_1"); +} +mixed CanGet(object ob) { return "The locker does not budge.";} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/magbox.c b/lib/domains/campus/obj/magbox.c new file mode 100644 index 0000000..5cf4a34 --- /dev/null +++ b/lib/domains/campus/obj/magbox.c @@ -0,0 +1,28 @@ +/* /domains/Examples/etc/bag.c + * from the Dead Souls LPC Library + * a sample bag object + * created by Descartes of Borg 950529 + */ + +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("magbox"); + SetId( ({ "box","magentabox" , "magbox" , "mbox" }) ); + SetAdjectives( ({ "small", "plastic","magenta", "a" }) ); + SetShort("a small, %^MAGENTA%^magenta%^RESET%^ plastic box"); + SetLong("It is a simple plastic box used to hold things. It is %^MAGENTA%^magenta%^RESET%^, and it has a cute Virtual Campus "+ + "logo on it."); + SetMass(274); + SetDollarCost(1); + SetMaxCarry(100); + SetCanClose(1); + SetClosed(0); + // SetPreventPut("You cannot put this in there!"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/maglite.c b/lib/domains/campus/obj/maglite.c new file mode 100644 index 0000000..2f96759 --- /dev/null +++ b/lib/domains/campus/obj/maglite.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include <vendor_types.h> +inherit "/lib/flashlight"; + + +void create(){ + ::create(); + SetKeyName("maglite"); + SetId( ({"fl","flashlight","light","flashlite","Maglite"}) ); + SetAdjectives( ({"powerful","heavy","large","Maglite"}) ); + SetShort( "a large flashlight" ); + SetLong("This is a powerful, heavy, Maglite brand flashlight."); + SetMass(20); + SetDollarCost(40); + SetLightLevel(20); + SetMinCells(4); + SetMaxCells(4); + SetCellType("D"); + Lit=0; + SetVendorType(VT_TREASURE); + + SetInventory(([ + "/domains/campus/obj/dcell_good":4 + ])); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/map.c b/lib/domains/campus/obj/map.c new file mode 100644 index 0000000..5ee50b3 --- /dev/null +++ b/lib/domains/campus/obj/map.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +inherit LIB_READ; + + +int TestFunc(){ + this_player()->eventPage("/domains/campus/txt/map.txt","system"); + return 1; +} +void create(){ + ::create(); + SetKeyName("building map"); + SetId(({"map","map of the administrative building","small map of the administrative building"})); + SetAdjectives(({"small"})); + SetShort("a small map of the administrative building"); + SetLong("A map of the administrative building. Try: read map \n"); + SetMass(0); + SetDollarCost(0); + SetVendorType(VT_TREASURE); + SetRead((: TestFunc :)); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/match.c b/lib/domains/campus/obj/match.c new file mode 100644 index 0000000..8b18c3c --- /dev/null +++ b/lib/domains/campus/obj/match.c @@ -0,0 +1,31 @@ +/* /domains/Praxis/etc/torch.c + * from Dead Souls + * created by Descartes of Borg 951023 + */ + +#include <lib.h> + +inherit LIB_MATCH; + + +static void create() { + match::create(); + SetKeyName("match"); + SetId("match"); + SetAdjectives( ({ "wooden" }) ); + SetShort("a wooden match"); + SetLong("A wooden match that might light if you strike it."); + SetRadiantLight(2); + SetStrikeChance(50); + SetMinHeat(10); + SetFuelRequired(1); + SetMaxFuel(10); + SetFuelAmount(10); + SetRefuelable(0); + SetMass(5); + SetDollarCost(2); + SetBurntValue(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/medbag.c b/lib/domains/campus/obj/medbag.c new file mode 100644 index 0000000..f8fb2b7 --- /dev/null +++ b/lib/domains/campus/obj/medbag.c @@ -0,0 +1,25 @@ +/* /domains/Examples/etc/bag.c + * from the Dead Souls LPC Library + * a sample bag object + * created by Descartes of Borg 950529 + */ + +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("bag"); + SetId( ({ "medical bag" }) ); + SetAdjectives( ({ "small", "cloth", "a" }) ); + SetShort("a small cloth bag"); + SetLong("It is a simple cloth bag used to hold things. Printed on it is: " + "\"Property of A.S. Clepius\""); + SetMass(274); + SetDollarCost(1); + SetMaxCarry(100); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/medtool.c b/lib/domains/campus/obj/medtool.c new file mode 100644 index 0000000..a50250f --- /dev/null +++ b/lib/domains/campus/obj/medtool.c @@ -0,0 +1,20 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; + +void create(){ + ::create(); + SetKeyName("medtool"); + SetId( ({"tool"}) ); + SetAdjectives( ({"yautja","med","medical"}) ); + SetShort("a yautja medtool"); + SetLong("This is pistol-shaped metallic device used in cases of "+ + "medical emergency. It appears you can try to apply it to yourself."); + SetMass(100); + SetDollarCost(1000); + SetVendorType(VT_TREASURE); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/mlocker.c b/lib/domains/campus/obj/mlocker.c new file mode 100644 index 0000000..83a1030 --- /dev/null +++ b/lib/domains/campus/obj/mlocker.c @@ -0,0 +1,34 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("locker"); + SetId(({"locker"})); + SetAdjectives(({"metal","tall","school"})); + SetShort("a tall metal locker"); + SetLong("This is a large metal locker."); + SetMass(3000); + SetDollarCost(50); + SetMaxCarry(500); + SetInventory(([ + "/domains/campus/armor/bandanna": 1, + "/domains/campus/armor/workboot_l": 1, + "/domains/campus/armor/workboot_r": 1, + "/domains/campus/armor/workglove_l": 1, + "/domains/campus/armor/workglove_r": 1, + "/domains/campus/armor/overalls": 1, + "/domains/campus/armor/cap": 1, + "/domains/campus/weap/crowbar": 1, + ])); + SetCanClose(1); + SetClosed(0); + SetCanLock(1); + SetLocked(0); + SetKey("locker_key_1"); +} +mixed CanGet(object ob) { return "The locker does not budge.";} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/mtable.c b/lib/domains/campus/obj/mtable.c new file mode 100644 index 0000000..9185478 --- /dev/null +++ b/lib/domains/campus/obj/mtable.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_CHAIR; + +void create() { + chair::create(); + SetKeyName("wooden table"); + SetId( ({ "table" }) ); + SetAdjectives( ({ "wood","wooden", "simple", "medium-sized" "medium sized" }) ); + SetShort("a wooden table"); + SetLong("It is a simple, medium-sized table made of wood."); + SetInventory(([ + "/domains/campus/obj/labkey" : 1, + "/domains/campus/obj/dcell_good" : 1, + ])); + SetMass(274); + SetBaseCost("silver",1); + SetBaseCost("silver",1); + SetMaxCarry(5000); + inventory_visible(); + inventory_accessible(); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/note.c b/lib/domains/campus/obj/note.c new file mode 100644 index 0000000..ed97b51 --- /dev/null +++ b/lib/domains/campus/obj/note.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +inherit LIB_READ; + +int lupus; +int TestFunc(){ + if(lupus){ + write("Bad wolf."); + return 1; + } + this_player()->eventPage("/domains/campus/txt/note.txt","system"); + return 1; +} +void create(){ + ::create(); + lupus = ( random(99) > 95 ); + SetKeyName("note"); + SetId(({"paper","slip"})); + SetAdjectives(({"small"})); + SetShort("a note"); + SetLong("A note with writing on it. Try: read note \n"); + SetMass(0); + SetDollarCost(0); + SetVendorType(VT_TREASURE); + SetRead((: TestFunc :)); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/omni.c b/lib/domains/campus/obj/omni.c new file mode 100644 index 0000000..d76cabf --- /dev/null +++ b/lib/domains/campus/obj/omni.c @@ -0,0 +1,83 @@ +#include <lib.h> +#include ROOMS_H +inherit LIB_ITEM; +inherit LIB_PRESS; + +int check_environs(); +int vanish_count = 50; +static void create() { + item::create(); + SetKeyName("omni"); + SetId(({"omni","Omni","device"})); + SetShort("an omni"); + SetLong("This is a small, round metal device, copper in color, "+ + "and similar in appearance to a pocket watch. There is a blinking red light "+ + "next to the tiny metal button at its top."); + SetMass(10); + SetDollarCost(300); + AddItem("button", "A button on the omni."); +} +void init() { + ::init(); + check_environs(); +} +mixed CanPress(object who, string target) { + if(!present(this_object()->GetKeyName(),who ) && target == "button"){ + return "You do not have the Omni!"; + } + if(this_object()->GetId() == target){ + return "You cannot push that."; + } + return 1; +} +mixed eventPress(object who, string where) { + object *rooms = objects( (: inherits(LIB_ROOM, $1) :) ); + object target; + int success = 0; + rooms = filter(rooms, (: member_array(base_name($1), ({ ROOM_START, + ROOM_FURNACE, ROOM_VOID, ROOM_POD, ROOM_DEATH, ROOM_WIZ, + ROOM_ARCH, ROOM_NETWORK, ROOM_ROUTER, LIB_FURNACE, + ROOM_FREEZER }) ) == -1 && strsrch(base_name($1),"/realms/") && + !inherits(LIB_FURNACE,$1) && + !($1->GetVirtual() && !grepp(base_name($1),",")) && + last_string_element(base_name($1),"/") != "death" :) ); + say(who->GetName()+" turns "+dbz_colors("multicolored")+" and disappears!"); + write("You feel momentarily disoriented and find yourself elsewhere!"); + while(!success){ + target = rooms[random(sizeof(rooms)-1)]; + success = who->eventMove(target); + } + who->eventDescribeEnvironment(); + tell_room(target, "With a multicolored flash, "+who->GetName()+ + " appears!",who); + return 1; +} + +void heart_beat(){ + object env = environment(); + object *holders; + if(!env) return; + holders = filter(containers(this_object()), + (: interactive($1) :) ); + if(interactive(env)) vanish_count--; + else if(sizeof(holders) && random(100) > 80) vanish_count--; + if(vanish_count < 0){ + tell_object(env,"The omni glows brightly and disappears!"); + this_object()->eventDestruct(); + } + if(vanish_count == 5){ + tell_object(env,"The omni begins to glow a dull red."); + this_object()->SetLong("This is a small, round metal device, copper in color, "+ + "and similar in appearance to a pocket watch. There is a blinking red light "+ + "next to the tiny metal button at its top. It is glowing a dull red."); + this_object()->SetShort("an omni (glowing)"); + } +} + +int check_environs(){ + if( interactive(environment()) ){ + set_heart_beat(10); + return 1; + } + return 1; +} diff --git a/lib/domains/campus/obj/pack.c b/lib/domains/campus/obj/pack.c new file mode 100644 index 0000000..8bec761 --- /dev/null +++ b/lib/domains/campus/obj/pack.c @@ -0,0 +1,26 @@ +#include <lib.h> + +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_WORN_STORAGE; + +static void create() { + ::create(); + SetKeyName("backpack"); + SetId(({"pack"})); + SetAdjectives(({"leather","soft","brown"})); + SetShort("a soft, brown leather backpack"); + SetLong("This is a medium-sized backpack made of soft brown leather. "+ + "It seems suitable for carrying books around, for the busy college student. "+ + "It features wide, comfortable straps for convenient wear."); + SetMass(100); + SetDollarCost(30); + SetCanClose(1); + SetClosed(1); + SetMaxCarry(500); + SetDamagePoints(100); + SetArmorType(A_CLOAK); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/ped_button.c b/lib/domains/campus/obj/ped_button.c new file mode 100644 index 0000000..0e95998 --- /dev/null +++ b/lib/domains/campus/obj/ped_button.c @@ -0,0 +1,41 @@ +/* /domains/campus/etc/chuch_button.c + * From the Dead Souls Object Library + * An example dummy item that allows pressing + * Created by Descartes of Borg 961222 + */ + +#include <lib.h> + +inherit LIB_DUMMY; // These do not show up in desc, but you can look at them +inherit LIB_PRESS; // Makes the item pressable + +int PushButton(object who) { + object *objects; + objects=({ load_object("/domains/campus/doors/red_door") }); + objects+=({ load_object("/domains/campus/doors/green_door") }); + objects+=({ load_object("/domains/campus/doors/blue_door") }); + objects+=({ load_object("/domains/campus/room/red_room") }); + objects+=({ load_object("/domains/campus/room/green_room") }); + objects+=({ load_object("/domains/campus/room/blue_room") }); + objects+=({ load_object("/domains/campus/room/monty") }); + + send_messages("press", "$agent_name $agent_verb the button, " + "resetting the experiment.", + who, 0, environment(who)); + + foreach(object ob in objects){ + ob->ButtonPush(); + } + +} + +static void create() { + dummy::create(); + SetKeyName("button"); + SetId(({"button","button on the pedestal" })); + SetAdjectives("pedestal", "red","shiny","candylike","candy-like","big"); + SetShort("a big red button"); + SetLong("It is a red, shiny, candy-like button."); + //SetPress((: PushButton :)); + SetPress(tell_object(this_player(),"hi!")); +} diff --git a/lib/domains/campus/obj/pedestal.c b/lib/domains/campus/obj/pedestal.c new file mode 100644 index 0000000..01e14e9 --- /dev/null +++ b/lib/domains/campus/obj/pedestal.c @@ -0,0 +1,184 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +inherit LIB_PRESS; + +int PushTheButton(); +string color,gagnant,my_door,other_door,removed_door; +void create(){ + ::create(); + SetKeyName("button pedestal"); + SetId( ({"pedestal","altar"}) ); + SetAdjectives( ({"cylindrical","round","waist-high"}) ); + SetShort("a pedestal with a red button on it"); + SetLong("This is a cylindrical pedestal, about waist-high, " + "of mysterious composition. A button is " + "on it."); + SetItems( ([ + ({"button","red button"}) : "A red button." + ]) ); + SetMass(20); + SetDollarCost(10); + SetVendorType(VT_TREASURE); + SetPress( ([ + ({"button","red button"}) : (: PushTheButton :) + ]) ); +} +mixed CanGet(object ob) { return "The pedestal does not budge.";} +int ResetGame(){ + object *objects; + object *contents; + string prize; + prize = "/domains/campus/armor/silverring"; + objects = ({}); + objects+=({ load_object("/domains/campus/room/red_room") }); + objects+=({ load_object("/domains/campus/room/green_room") }); + objects+=({ load_object("/domains/campus/room/blue_room") }); + + objects = ({ load_object("/domains/campus/doors/red_door") }); + objects +=({ load_object("/domains/campus/doors/green_door") }); + objects +=({ load_object("/domains/campus/doors/blue_door") }); + + foreach(object ding in objects){ + if(ding) ding->SetClosed(1); + if(ding) ding->SetLocked(1); + } + + if(sscanf(gagnant,"%s door",color)>0){ + string where; + where="/domains/campus/room/"+color+"_room"; + //new(prize)->eventMove(load_object(where)); + } +} +int PushTheButton(){ + int genrand; + gagnant = ""; + genrand = random(3); + send_messages("press", "$agent_name $agent_verb the button.", + this_player(), 0, environment(this_player())); + if(genrand == 0) gagnant = "red door"; + if(genrand == 1) gagnant = "green door"; + if(genrand == 2) gagnant = "blue door"; +#if 0 + tell_room(environment(),"A voice from the pedestal says: " + "PRECOG: genrand is: "+genrand); + tell_room(environment(),"A voice from the pedestal says: " + "PRECOG: gagnant is: "+gagnant+".\n" + "PRECOG: genrand modulus is: "+genrand); +#endif + remove_action("doStay","stay"); + remove_action("doSwitch","switch"); + add_action("choose","choose"); + tell_room(environment(),"A voice from the pedestal says: " + "You must now choose one door from these " + "three. Behind one is a prize. Behind the " + "other two, nothing. To choose the " + "red door, for example: choose red door"); + ResetGame(); + return 1; +} +void init(){ + ::init(); + if(gagnant != "" && my_door !=""){ + add_action("doStay","stay"); + add_action("doSwitch","switch"); + } + if(gagnant != "" && my_door == ""){ + add_action("choose","choose"); + } +} +int choose(string str){ + if(!str || str == ""){ + tell_room(environment(),"A voice from the pedestal says: " + "Please try choosing a door, ok?"); + } + else if(str == "door"){ + tell_room(environment(),"A voice from the pedestal says: " + "You'll need to be more specific."); + } + else if(str == "red door" || str == "blue door" ||str == "green door"){ + tell_room(environment(),"A voice from the pedestal says: " + "You choose the "+str+"."); + this_object()->MontyMagic(str); + } + else { + tell_room(environment(),"A voice from the pedestal says: " + "I don't understand that."); + } + reap_dummies(); + reap_other("/domains/campus/armor/silverring"); + return 1; +} +int MontyMagic(string str){ + int genrand,which; + string *choices; + choices = ({}); + if(str != "red door") choices += ({ "red door" }); + if(str != "green door") choices += ({ "green door" }); + if(str != "blue door") choices += ({ "blue door" }); + genrand = random(2); + if(choices[1] == gagnant) which = 0; + else if(choices[0] == gagnant) which = 1; + else which = genrand; + removed_door = choices[which]; + choices -= ({ choices[which] }); + other_door = choices[0]; + my_door = str; + choices += ({ str }); + if(sscanf(removed_door,"%s door",color)>0) color = color; + load_object("/domains/campus/doors/"+color+"_door")->SetLocked(0); + load_object("/domains/campus/doors/"+color+"_door")->SetClosed(0); + tell_room(environment(),"A voice from the pedestal says: " + "I have opened the "+removed_door+"! \n" + "You may enter the "+color+" room and see that it is empty.\n" + "Only the "+choices[0]+" and "+choices[1]+" remain.\n\n" + "Would you like to switch to the "+other_door+"? \n" + "Or would you rather stay with the "+str+"?\n\n" + "To switch, type: switch\n" + "To stay, type: stay"); + remove_action("choose","choose"); + add_action("doStay","stay"); + add_action("doSwitch","switch"); + return 1; + +} +int CheckWin(string str){ + if(sscanf(str,"%s door",color)>0) color = color; + if(str == gagnant) { + this_object()->WinFun(); + return 1; + } + load_object("/domains/campus/doors/"+color+"_door")->SetLocked(0); + load_object("/domains/campus/doors/"+color+"_door")->SetClosed(0); + tell_room(environment(),"A voice from the pedestal says: " + "YOU LOOOOOSE!\n" + "You may enter the "+color+" room to get your big " + "load of NOTHING. Haaa haa!"); + return 1; +} +int doStay(){ + tell_room(environment(),"A voice from the pedestal says: " + "Oh, how loyal!"); + remove_action("doStay","stay"); + remove_action("doSwitch","switch"); + CheckWin(my_door); + return 1; +} +int doSwitch(){ + tell_room(environment(),"A voice from the pedestal says: " + "Why you're inconstant as a feather!"); + remove_action("doStay","stay"); + remove_action("doSwitch","switch"); + my_door = other_door; + CheckWin(my_door); + return 1; +} +int WinFun(){ + load_object("/domains/campus/doors/"+color+"_door")->SetLocked(0); + load_object("/domains/campus/doors/"+color+"_door")->SetClosed(0); + tell_room(environment(),"A voice from the pedestal says: " + "You win, kid. Congrats!\n" + "You may enter the "+color+" room and claim your prize.\n\n" + "Push the button on the pedestal to reset the game."); + return 1; +} diff --git a/lib/domains/campus/obj/pedestal2.c b/lib/domains/campus/obj/pedestal2.c new file mode 100644 index 0000000..8eb12b6 --- /dev/null +++ b/lib/domains/campus/obj/pedestal2.c @@ -0,0 +1,184 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +inherit LIB_PRESS; + +int PushTheButton(); +string color,gagnant,my_door,other_door,removed_door; +void create(){ + ::create(); + SetKeyName("button pedestal"); + SetId( ({"pedestal","altar"}) ); + SetAdjectives( ({"cylindrical","round","waist-high"}) ); + SetShort("a pedestal with a red button on it"); + SetLong("This is a cylindrical pedestal, about waist-high, " + "of mysterious composition. A button is " + "on it."); + SetItems( ([ + ({"button","red button"}) : "A red button." + ]) ); + SetMass(20); + SetDollarCost(10); + SetVendorType(VT_TREASURE); + SetPress( ([ + ({"button","red button"}) : (: PushTheButton :) + ]) ); +} +mixed CanGet(object ob) { return "The pedestal does not budge.";} +int ResetGame(){ + object *objects; + object *contents; + string prize; + prize = "/domains/campus/armor/silverring"; + objects = ({}); + objects+=({ load_object("/domains/campus/room/red_room2") }); + objects+=({ load_object("/domains/campus/room/green_room2") }); + objects+=({ load_object("/domains/campus/room/blue_room2") }); + + objects = ({ load_object("/domains/campus/doors/red_door2") }); + objects +=({ load_object("/domains/campus/doors/green_door2") }); + objects +=({ load_object("/domains/campus/doors/blue_door2") }); + + foreach(object ding in objects){ + if(ding) ding->SetClosed(1); + if(ding) ding->SetLocked(1); + } + + if(sscanf(gagnant,"%s door",color)>0){ + string where; + where="/domains/campus/room/"+color+"_room2"; + //new(prize)->eventMove(load_object(where)); + } +} +int PushTheButton(){ + int genrand; + gagnant = ""; + genrand = random(3); + send_messages("press", "$agent_name $agent_verb the button.", + this_player(), 0, environment(this_player())); + if(genrand == 0) gagnant = "red door"; + if(genrand == 1) gagnant = "green door"; + if(genrand == 2) gagnant = "blue door"; +#if 0 + tell_room(environment(),"A voice from the pedestal says: " + "PRECOG: genrand is: "+genrand); + tell_room(environment(),"A voice from the pedestal says: " + "PRECOG: gagnant is: "+gagnant+".\n" + "PRECOG: genrand modulus is: "+genrand); +#endif + remove_action("doStay","stay"); + remove_action("doSwitch","switch"); + add_action("choose","choose"); + tell_room(environment(),"A voice from the pedestal says: " + "You must now choose one door from these " + "three. Behind one is a prize. Behind the " + "other two, nothing. To choose the " + "red door, for example: choose red door"); + ResetGame(); + return 1; +} +void init(){ + ::init(); + if(gagnant != "" && my_door !=""){ + add_action("doStay","stay"); + add_action("doSwitch","switch"); + } + if(gagnant != "" && my_door == ""){ + add_action("choose","choose"); + } +} +int choose(string str){ + if(!str || str == ""){ + tell_room(environment(),"A voice from the pedestal says: " + "Please try choosing a door, ok?"); + } + else if(str == "door"){ + tell_room(environment(),"A voice from the pedestal says: " + "You'll need to be more specific."); + } + else if(str == "red door" || str == "blue door" ||str == "green door"){ + tell_room(environment(),"A voice from the pedestal says: " + "You choose the "+str+"."); + this_object()->MontyMagic(str); + } + else { + tell_room(environment(),"A voice from the pedestal says: " + "I don't understand that."); + } + reap_dummies(); + reap_other("/domains/campus/armor/silverring"); + return 1; +} +int MontyMagic(string str){ + int genrand,which; + string *choices; + choices = ({}); + if(str != "red door") choices += ({ "red door" }); + if(str != "green door") choices += ({ "green door" }); + if(str != "blue door") choices += ({ "blue door" }); + genrand = random(2); + if(choices[1] == gagnant) which = 0; + else if(choices[0] == gagnant) which = 1; + else which = genrand; + removed_door = choices[which]; + choices -= ({ choices[which] }); + other_door = choices[0]; + my_door = str; + choices += ({ str }); + if(sscanf(removed_door,"%s door",color)>0) color = color; + load_object("/domains/campus/doors/"+color+"_door2")->SetLocked(0); + load_object("/domains/campus/doors/"+color+"_door2")->SetClosed(0); + tell_room(environment(),"A voice from the pedestal says: " + "I have opened the "+removed_door+"! \n" + "You may enter the "+color+" room and see that it is empty.\n" + "Only the "+choices[0]+" and "+choices[1]+" remain.\n\n" + "Would you like to switch to the "+other_door+"? \n" + "Or would you rather stay with the "+str+"?\n\n" + "To switch, type: switch\n" + "To stay, type: stay"); + remove_action("choose","choose"); + add_action("doStay","stay"); + add_action("doSwitch","switch"); + return 1; + +} +int CheckWin(string str){ + if(sscanf(str,"%s door",color)>0) color = color; + if(str == gagnant) { + this_object()->WinFun(); + return 1; + } + load_object("/domains/campus/doors/"+color+"_door2")->SetLocked(0); + load_object("/domains/campus/doors/"+color+"_door2")->SetClosed(0); + tell_room(environment(),"A voice from the pedestal says: " + "YOU LOOOOOSE!\n" + "You may enter the "+color+" room to get your big " + "load of NOTHING. Haaa haa!"); + return 1; +} +int doStay(){ + tell_room(environment(),"A voice from the pedestal says: " + "Oh, how loyal!"); + remove_action("doStay","stay"); + remove_action("doSwitch","switch"); + CheckWin(my_door); + return 1; +} +int doSwitch(){ + tell_room(environment(),"A voice from the pedestal says: " + "Why you're inconstant as a feather!"); + remove_action("doStay","stay"); + remove_action("doSwitch","switch"); + my_door = other_door; + CheckWin(my_door); + return 1; +} +int WinFun(){ + load_object("/domains/campus/doors/"+color+"_door2")->SetLocked(0); + load_object("/domains/campus/doors/"+color+"_door2")->SetClosed(0); + tell_room(environment(),"A voice from the pedestal says: " + "You win, kid. Congrats!\n" + "You may enter the "+color+" room and claim your prize.\n\n" + "Push the button on the pedestal to reset the game."); + return 1; +} diff --git a/lib/domains/campus/obj/pedestal3.c b/lib/domains/campus/obj/pedestal3.c new file mode 100644 index 0000000..1cd1796 --- /dev/null +++ b/lib/domains/campus/obj/pedestal3.c @@ -0,0 +1,184 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +inherit LIB_PRESS; + +int PushTheButton(); +string color,gagnant,my_door,other_door,removed_door; +void create(){ + ::create(); + SetKeyName("button pedestal"); + SetId( ({"pedestal","altar"}) ); + SetAdjectives( ({"cylindrical","round","waist-high"}) ); + SetShort("a pedestal with a red button on it"); + SetLong("This is a cylindrical pedestal, about waist-high, " + "of mysterious composition. A button is " + "on it."); + SetItems( ([ + ({"button","red button"}) : "A red button." + ]) ); + SetMass(20); + SetDollarCost(10); + SetVendorType(VT_TREASURE); + SetPress( ([ + ({"button","red button"}) : (: PushTheButton :) + ]) ); +} +mixed CanGet(object ob) { return "The pedestal does not budge.";} +int ResetGame(){ + object *objects; + object *contents; + string prize; + prize = "/domains/campus/armor/silverring"; + objects = ({}); + objects+=({ load_object("/domains/campus/room/red_room3") }); + objects+=({ load_object("/domains/campus/room/green_room3") }); + objects+=({ load_object("/domains/campus/room/blue_room3") }); + + objects = ({ load_object("/domains/campus/doors/red_door3") }); + objects +=({ load_object("/domains/campus/doors/green_door3") }); + objects +=({ load_object("/domains/campus/doors/blue_door3") }); + + foreach(object ding in objects){ + if(ding) ding->SetClosed(1); + if(ding) ding->SetLocked(1); + } + + if(sscanf(gagnant,"%s door",color)>0){ + string where; + where="/domains/campus/room/"+color+"_room3"; + //new(prize)->eventMove(load_object(where)); + } +} +int PushTheButton(){ + int genrand; + gagnant = ""; + genrand = random(3); + send_messages("press", "$agent_name $agent_verb the button.", + this_player(), 0, environment(this_player())); + if(genrand == 0) gagnant = "red door"; + if(genrand == 1) gagnant = "green door"; + if(genrand == 2) gagnant = "blue door"; +#if 0 + tell_room(environment(),"A voice from the pedestal says: " + "PRECOG: genrand is: "+genrand); + tell_room(environment(),"A voice from the pedestal says: " + "PRECOG: gagnant is: "+gagnant+".\n" + "PRECOG: genrand modulus is: "+genrand); +#endif + remove_action("doStay","stay"); + remove_action("doSwitch","switch"); + add_action("choose","choose"); + tell_room(environment(),"A voice from the pedestal says: " + "You must now choose one door from these " + "three. Behind one is a prize. Behind the " + "other two, nothing. To choose the " + "red door, for example: choose red door"); + ResetGame(); + return 1; +} +void init(){ + ::init(); + if(gagnant != "" && my_door !=""){ + add_action("doStay","stay"); + add_action("doSwitch","switch"); + } + if(gagnant != "" && my_door == ""){ + add_action("choose","choose"); + } +} +int choose(string str){ + if(!str || str == ""){ + tell_room(environment(),"A voice from the pedestal says: " + "Please try choosing a door, ok?"); + } + else if(str == "door"){ + tell_room(environment(),"A voice from the pedestal says: " + "You'll need to be more specific."); + } + else if(str == "red door" || str == "blue door" ||str == "green door"){ + tell_room(environment(),"A voice from the pedestal says: " + "You choose the "+str+"."); + this_object()->MontyMagic(str); + } + else { + tell_room(environment(),"A voice from the pedestal says: " + "I don't understand that."); + } + reap_dummies(); + reap_other("/domains/campus/armor/silverring"); + return 1; +} +int MontyMagic(string str){ + int genrand,which; + string *choices; + choices = ({}); + if(str != "red door") choices += ({ "red door" }); + if(str != "green door") choices += ({ "green door" }); + if(str != "blue door") choices += ({ "blue door" }); + genrand = random(2); + if(choices[1] == gagnant) which = 0; + else if(choices[0] == gagnant) which = 1; + else which = genrand; + removed_door = choices[which]; + choices -= ({ choices[which] }); + other_door = choices[0]; + my_door = str; + choices += ({ str }); + if(sscanf(removed_door,"%s door",color)>0) color = color; + load_object("/domains/campus/doors/"+color+"_door3")->SetLocked(0); + load_object("/domains/campus/doors/"+color+"_door3")->SetClosed(0); + tell_room(environment(),"A voice from the pedestal says: " + "I have opened the "+removed_door+"! \n" + "You may enter the "+color+" room and see that it is empty.\n" + "Only the "+choices[0]+" and "+choices[1]+" remain.\n\n" + "Would you like to switch to the "+other_door+"? \n" + "Or would you rather stay with the "+str+"?\n\n" + "To switch, type: switch\n" + "To stay, type: stay"); + remove_action("choose","choose"); + add_action("doStay","stay"); + add_action("doSwitch","switch"); + return 1; + +} +int CheckWin(string str){ + if(sscanf(str,"%s door",color)>0) color = color; + if(str == gagnant) { + this_object()->WinFun(); + return 1; + } + load_object("/domains/campus/doors/"+color+"_door3")->SetLocked(0); + load_object("/domains/campus/doors/"+color+"_door3")->SetClosed(0); + tell_room(environment(),"A voice from the pedestal says: " + "YOU LOOOOOSE!\n" + "You may enter the "+color+" room to get your big " + "load of NOTHING. Haaa haa!"); + return 1; +} +int doStay(){ + tell_room(environment(),"A voice from the pedestal says: " + "Oh, how loyal!"); + remove_action("doStay","stay"); + remove_action("doSwitch","switch"); + CheckWin(my_door); + return 1; +} +int doSwitch(){ + tell_room(environment(),"A voice from the pedestal says: " + "Why you're inconstant as a feather!"); + remove_action("doStay","stay"); + remove_action("doSwitch","switch"); + my_door = other_door; + CheckWin(my_door); + return 1; +} +int WinFun(){ + load_object("/domains/campus/doors/"+color+"_door3")->SetLocked(0); + load_object("/domains/campus/doors/"+color+"_door3")->SetClosed(0); + tell_room(environment(),"A voice from the pedestal says: " + "You win, kid. Congrats!\n" + "You may enter the "+color+" room and claim your prize.\n\n" + "Push the button on the pedestal to reset the game."); + return 1; +} diff --git a/lib/domains/campus/obj/pin.c b/lib/domains/campus/obj/pin.c new file mode 100644 index 0000000..437491e --- /dev/null +++ b/lib/domains/campus/obj/pin.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; + +void create(){ + ::create(); + SetKeyName("pull-pin"); + SetId(({"pin","ring"})); + SetAdjectives(({"pull","grenade","fuse"})); + SetShort("a grenade pin"); + SetLong("This is the pull pin from a hand grenade fuse."); + SetMass(1); + SetDollarCost(0); + SetVendorType(VT_TREASURE); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/podium.c b/lib/domains/campus/obj/podium.c new file mode 100644 index 0000000..5a0e12f --- /dev/null +++ b/lib/domains/campus/obj/podium.c @@ -0,0 +1,752 @@ +/* It works now, no define needed. + * make sure someone does "setmc" or it won't do much. + * setmc can only be done once, first come, first get i guess ;) + * by Boy@frontiers. + * Major corrections and modifications by Crat 25jul05 + */ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_STORAGE; + +#define DEFAULT_BOUNCE_ROOM "/domains/town/room/adv_guild" +string bounce_room ; /* File name of the bounce room */ +string *voters ; /* Array of names of users who have voted */ +string *agenda ; /* Array of agenda item strings. */ +mapping votes ; /* Keys are names, data are votes cast */ +string vote_str ; /* The proposition being voted on */ +int endtime ; /* Time at which the speaker/vote ends */ +int votelog ; /* 1 if votes are being announced, else 0 */ + +string speaker; +string mc; +int x; +object ob; +static void create() { + storage::create(); + SetShort("a podium"); + SetLong("This is the speaker's podium. It is about four feet tall "+ + "and made of some expensive-looking, deep grain wood. This podium "+ + "facilitates the running of meetings by giving the speaker the power "+ + "to recognize individual people to speak at a time. There is "+ + "some space in the podium to store things in, perhaps there is something "+ + "in there now. For more "+ + "details on running a meeting with the podium, type: help podium."); + SetMass(10); + SetId( ({"podium", "speaker's podium", "podium.c"}) ); + SetDollarCost(-110); + SetKeyName("podium"); + SetId(({"podium","handler"})); + SetAdjectives(({"wood","wooden","meeting","speaker's","Speaker's"})); + SetDamagePoints(1000); + SetPreventGet("You can't get that."); + SetMaxCarry(20); + + SetInventory(([ + ])); + + mc = ""; + x = 0; + speaker = ""; + + vote_str = "none" ; + voters = ({ }) ; + votes = ([ ]) ; + agenda = ({ }) ; + bounce_room = DEFAULT_BOUNCE_ROOM ; + +} +void init() { + ::init(); + add_action("eventSay", "say",1); + add_action("eventSay", "codesay"); + add_action("eventRaise", "raise"); + add_action("eventCallOn", "recognize"); + add_action("shaddap", "yell"); + add_action("shaddap", "shout"); + add_action("shaddap", "emote"); + add_action("help", "help"); + add_action("quiet", "quiet"); + add_action("changemc", "changemc"); + add_action("SetMc", "setmc"); + add_action ("echo", "echo") ; + add_action ("vote", "vote") ; + add_action ("call_for_vote", "call") ; + add_action ("call_for_roll", "rollcall") ; + add_action ("permit_entry", "permit") ; + add_action ("localtime", "time") ; + add_action ("reset_clock", "reset") ; + add_action ("show_agenda", "agenda") ; + add_action ("add_items", "add") ; + add_action ("remove_item", "remove") ; + add_action ("clear_items", "clear") ; + add_action ("eject_player", "eject") ; + add_action ("privacy", "privacy"); + add_action ("privacy", "priv"); + add_action ("localupdate", "update") ; + add_action ("localupdate", "reload") ; + add_action ("step_down", "step" ); + add_action ("RestrictedAction", "zap" ); + add_action ("RestrictedAction", "force" ); +} +mixed CanGet(object ob) { return "The podium does not budge.";} + +int RestrictedAction(){ + if(!archp(this_player()) && sizeof(mc) && mc != this_player()->GetKeyName()){ + write("That action is restricted here."); + return 1; + } +} + +int eventSay(string args) { + string foo; + + if(!sizeof(args)) return 0; + args = replace_string(args,"\n",""); + if (mc == this_player()->GetKeyName()) { + //this_player()->eventPrint("You say %^CYAN%^\"" + capitalize(args) + "\""); + //say(this_player()->GetName() + " says %^CYAN%^\"" + capitalize(args) + "\""); + return 0; + } + if ( mc != "" && this_player()-> GetKeyName() != speaker ) { + this_player()->eventPrint("%^RED%^It is not polite to talk out of order."); + this_player()->eventPrint("Raise your hand if you'd like to speak."); + return 1; + } + if ((!args) || (args == " ")) { + write ("You mutter to yourself.\n") ; + return 1 ; + } + //foo = this_player()->GetCapName() + + //" says: %^CYAN%^\"" + capitalize(args)+"\""; + //say (foo) ; + //write("You say: %^CYAN%^\"" + capitalize(args)+"\""); + return 0; + +} + + +int eventCallOn(string args) { + if (present((object)args)) { + if (mc == this_player()->GetKeyName()) { + speaker = args; + write("You have called on " + speaker+".\n"); + find_living(args)->eventPrint("%^CYAN%^" + capitalize(mc) + " has called on you, you may speak."); + return 1; + } + else { + this_player()->eventPrint("Only the speaker can do that."); + return 1; + } + } + else { + write("%^CYAN%^This person is not here to be called on."); + return 1; + } +} + + +int eventRaise() { + string dude; + dude=this_player()->GetKeyName(); + if(dude != mc && dude != speaker) { + tell_room(environment(this_player()), + this_player()->GetName()+" raises "+ + possessive(this_player())+ + " hand.", ({this_player()}) ); + this_player()->eventPrint("%^CYAN%^You raise your hand."); + return 1; + } + else { + write("You can speak already. Say what's on your mind."); + return 1; + } +} + + +int shaddap() { + if(mc != "" && this_player()->GetKeyName() != speaker){ + write("%^RED%^It would be impolite to do that at this time."); + return 1; + } +} + + +int help(string args) { + if (args != "podium") { + return 0; + } + else { + write("%^GREEN%^This is the speakers podium, it is where the " + "speaker stands during a speech. This podium " + "has special properties, it can prevent others " + "from speaking out of turn, if you are the "+ + "speaker.%^RESET%^"); + if (this_player()->GetKeyName() == mc) { + write("%^RED%^Available commands:"); + write("%^YELLOW%^recognize %^RESET%^: Calls on another to speak."); + write("%^YELLOW%^say %^RESET%^: As the speaker, you can say things whenever you like."); + write("%^YELLOW%^quiet %^RESET%^: Revokes the speaking privilege to the person you last called on."); + write("%^YELLOW%^changemc %^RESET%^: Removes yourself as mc, and let someone else take over."); + write("%^YELLOW%^add <string>%^RESET%^: Add agenda item <string> to the bottom of the agenda."); + write("%^YELLOW%^remove <int>%^RESET%^: Remove agenda item <int> from the agenda."); + write("%^YELLOW%^clear agenda%^RESET%^: Clear the agenda."); + write("%^YELLOW%^permit <name>%^RESET%^: Permit player <name> to enter the meeting room when locked."); + write("%^YELLOW%^eject <name>%^RESET%^: Eject player <name> from the meeting room."); + write("%^YELLOW%^time <num> [minutes/seconds]%^RESET%^: Set the clock to <num> minutes or seconds."); + write("%^YELLOW%^reset clock%^RESET%^: Clear the clock."); + write("%^YELLOW%^step down%^RESET%^: Step down as head speaker."); + write("%^YELLOW%^rollcall <num> [minutes/seconds] <subject>%^RESET%^: Call for a roll call vote,\n" + "\tlasting num minutes or seconds, on <subject>."); + write("%^YELLOW%^add after <int> <string>%^RESET%^: Add agenda item <string> after agenda item #<int>.\n" + "\tadd after 0 <string> adds to the top of the list."); + write("%^YELLOW%^call <num> [minutes/seconds] <subject>%^RESET%^: Call for a vote, lasting num minutes\n" + "\tor seconds, on <subject>."); + return 1; + } + else { + write("%^RED%^Available commands:"); + write("%^YELLOW%^raise %^RESET%^: Raise your hand, to motion to the speaker that you would like to speak."); + write("%^YELLOW%^say %^RESET%^ : Say something, you only may do this if the speaker has called on you."); + if (x == 0) { + write("%^YELLOW%^setmc%^RESET%^ : There is no mc currently, use this command to set one."); + } + return 1; + } + } +} + + +int quiet() { + if (mc == this_player()->GetKeyName()) { + write("%^CYAN%^You thank " + capitalize(speaker) + " for speaking."); + find_living(speaker)->eventPrint("%^CYAN%^" + capitalize(mc) + " thanks you for you speaking."); + speaker = mc; + return 1; + } + write ("Only the mc may use this command.\n") ; + return 1; +} + + +int changemc(string args) { + if (args != 0) { + if ( this_player()->GetKeyName() != mc ) { + write("%^RED%^You are not the mc to begin with, you cannot give that position away."); + return 1; + } + else { + if (!present(args)) { + write("%^CYAN%^" + args + " is not present, and therefore cannot be mc."); + return 1; + } + else { + write("%^CYAN%^You hand the podium over to " + args); + mc = args; + say("%^CYAN%^" + capitalize(args) + " is the new head speaker."); + find_living(mc)->eventPrint("%^BLUE%^You are the new head speaker!"); + find_living(mc)->eventPrint("The command \"help podium\" can help you, if you don't know what to do."); + return 1; + } + } + } + else { + write("%^CYAN%^Syntax:"); + write("changemc <player>"); + return 1; + } +} + +int step_down(string args){ + if (args == "down") { + if ( this_player()->GetKeyName() != mc ) { + write("%^RED%^You are not the mc to begin with, you cannot give that position away."); + return 1; + } + say("%^CYAN%^" + capitalize(mc) + " has stepped down as the head speaker."); + write ( "You step down as the head speaker" ); + mc = ""; + x--; + load_object(base_name(environment(this_object())))->AutoDeactivate(); + return 1; + } + else { + write("%^CYAN%^Syntax:"); + write("<step down>"); + return 1; + } + +} + +int SetMc(string args) { + object ob; + if(args) ob = find_living(args); + if(!args || !ob) ob = this_player(); + if(!member_group(ob, "MODERATORS")){ + write("That person is not a member of the moderators group."); + write("An admin should use the admintool command to add the "+ + "appropriate people to that user group."); + return 1; + } + if (x==0) { + if (args != 0) { + if (present(args) ) { + mc = args; + say("%^CYAN%^" + capitalize(mc) + " is the speaker."); + write("You set " + capitalize(args) + " as the speaker."); + find_living(mc)->eventPrint("The command \"help podium\" can help you, if you don't know what to do."); + x++; + return 1; + } + else { + write("You cannot set him/her as the speaker, he/she is not here!"); + return 1; + } + } + else { + write("%^CYAN%^Syntax:"); + write("setmc <player>"); + return 1; + } + } + else { + write("There is already a speaker, you cannot set another one."); + return 1; + } +} + +int privacy(string str){ + + if ( mc != this_player()->GetKeyName() ) { + write ("Only the mc may use the shield.\n") ; + return 1 ; + } + if(str=="on" || str == "1"){ + load_object(base_name(environment(this_object())))->set_privacy( 1 ); + write("You enable the privacy shield.\n"); + say(this_player()->GetName()+" enables a privacy force field around the room."); + return 1; + } + if(str=="off" || str == "0"){ + load_object(base_name(environment(this_object())))->AutoDeactivate(); + write("You disable the privacy shield.\n"); + say(this_player()->GetName()+" disables a privacy force field around the room."); + return 1; + } +} + +// Echoing is always forbidden. It's just too much of a hassle. +int echo (string str) { + write ("Echoing is forbidden in the conference room at all times.\n") ; + return 1 ; +} + +// Permit_entry lets the mc bring someone into the conference room +// when it is locked. +int permit_entry (string name) { + + object user ; + int oldlock ; + + if ( mc != this_player()->GetKeyName() ) { + write ("Only the mc may permit entry into a locked conference.\n") ; + return 1 ; + } + user = find_player(name) ; + if (!user) { + write ("There is no user by that name.\n") ; + return 1 ; + } + if (present(user,environment(this_object()))) { + write (capitalize(name)+" is already here!\n") ; + return 1 ; + } + // We save the old locked status of the room, and restore it when we're + // done. You can "permit" entry into an unlocked conference if you want + // to: it saves the person the trouble of walking. + oldlock = load_object(base_name(environment(this_object())))->get_privacy() ; + load_object(base_name(environment(this_object())))->set_privacy( 0 ); + user -> eventMove(environment(this_object())) ; + load_object(base_name(environment(this_object())))->set_privacy( oldlock ); + write ("You bring "+capitalize(name)+" into the conference.\n") ; + tell_object (user, capitalize(mc)+" permits you to enter.\n") ; + say (capitalize(name)+" has been permitted to enter the conference.\n", user) ; + return 1 ; +} + + + +// Eject_player lets the mc banish a player from the room and dump +// him in the bounce room. +int eject_player (string str) { + object env = environment(this_player()); + object ob ; + + if ( mc != this_player()->GetKeyName() ) { + write ("Only the mc may eject players.\n") ; + return 1 ; + } + ob = find_player(str) ; + if (!ob || !present (ob, environment(this_object()))) { + write ("There is no player named "+capitalize(str)+" here.\n") ; + return 1 ; + } + write ("You eject "+capitalize(str)+" from the room!\n") ; + tell_object (ob, "You have been ejected from the room.\n") ; + say (capitalize(str)+" has been ejected from the room.\n") ; + ob->eventMove(bounce_room) ; + if(env) env->AddEjected(ob); + return 1 ; +} + +// Localtime shows the user the amount of time left on the room clock. +// The name is chosen to avoid colliding with the time() efun. +// The mc may also use this function to set the time on the clock +// and start it running. See the help documents for more information on +// how the clock works. +varargs int localtime (string str) { + + int i, min, sec ; + string foo ; + + // If no string, then we just indicate how much time is left on the clock. + if (!str) { + if (!endtime || endtime == 0) { + write ("Time is not running at the moment.\n") ; + return 1 ; + } + i = time() ; + i = endtime - i ; + min = (i/60) ; + sec = i - (min*60) ; + if (min==1) { + write ("The clock shows 1 minute and "+sec+" seconds remaining.\n") ; + } else { + write ("The clock shows "+min+" minutes and "+sec+" seconds remaining.\n") ; + } + return 1 ; + } + // If there is a string, then the user is trying to set the clock to some + // number of minutes or seconds. + if ( mc != this_player()->GetKeyName() ) { + write ("Only the mc may set the clock.\n") ; + return 1 ; + } + // You cannot set a new time if the clock is running. This is for safety. + // You must reset the clock first. See below. + if (endtime!=0) { + write ("The clock is running. You must reset the clock first.\n" + ) ; + return 1 ; + } + if (sscanf(str, "%d min%s", i, foo) == 2) { + i=i*60 ; + } else { + if (sscanf(str, "%d seconds", i) != 1) { + write ("You must set a number of minutes or seconds: ie, 3 minutes or 90 seconds.\n") ; + return 1 ; + } + } + write ("You set the clock to "+str+".\n") ; + say (capitalize(mc)+" sets the clock to "+str+".\n") ; + endtime = time()+i ; + // We call_out to a function that prints a message when time runs out. + call_out ("expire_time", i) ; + return 1 ; +} + +// Reset_clock lets the mc clear the clock before setting a new time +// on it. +int reset_clock (string str) { + if (!str || str!="clock") { + notify_fail ("Reset what?\n") ; + return 0 ; + } + if ( mc != this_player()->GetKeyName() ) { + write ("Only the mc may reset the clock.\n") ; + return 1 ; + } + if (endtime==0) { + write ("The clock isn't running.\n") ; + return 1 ; + } + endtime = 0 ; + write ("You clear the clock.\n") ; + say (capitalize(mc)+" clears the clock.\n") ; + // Clear any pending call_outs that may be left behind. + remove_call_out("expire_time") ; + remove_call_out("expire_vote") ; + return 1 ; +} + +// Expire_time lets the conference room know that time has expired. It +// doesn't force the speaker to shut up or anything like that: that's left +// to the mcs discretion. +int expire_time() { + tell_room (environment(this_object()),"The clock runs out.\n") ; + endtime = 0 ; +} + + +// Show_agenda lets users see the current agenda. +int show_agenda() { + + int i ; + + if (!agenda || sizeof(agenda)==0) { + write ("The agenda has not been set.\n") ; + return 1 ; + } + write ("The current agenda is:\n") ; + for (i=0;i<sizeof(agenda);i++) { + write ((i+1)+". "+agenda[i]+"\n") ; + } + return 1 ; +} + + + +// Clear_speakers erases the speakers list or agenda, depending on argument. +int clear_items (string str) { + if ( mc != this_player()->GetKeyName() ) { + write ("Only the mc may clear the agenda.\n") ; + return 1 ; + } + if (!str || str!="agenda") { + write ("Usage: clear [agenda]\n") ; + return 1 ; + } + agenda = ({ }) ; + write ("The agenda has been cleared.\n") ; + say ("The agenda has been cleared.\n") ; + return 1 ; +} + +// Add_agenda_item lets the mc add an agenda item. If the argument +// is of the form "after <int> <string>", then string is added to the +// agenda AFTER item int. Agenda items are numbered 1-N rather than 0-(N-1). +int add_items (string str) { + + int post ; + string prop ; + + if ( mc != this_player()->GetKeyName() ) { + notify_fail ("Only the mc may add agenda items.\n") ; + return 0 ; + } + if (!str) { + write ("Usage: add item or add after N item\n") ; + return 1 ; + } + if (sscanf(str,"after %d %s", post, prop)!=2) { + agenda += ({ str }) ; + write ("Added the following item to the agenda\n"+str+"\n") ; + return 1 ; + } + if (post<0 || post>=sizeof(agenda)) { + notify_fail ("Item number out of range.\n") ; + return 0 ; + } + if (post==0) agenda = ({ prop }) + agenda ; else + agenda = agenda[0..post-1] + ({ prop }) + agenda[post..sizeof(agenda)] ; + write ("Added the following agenda item after item "+post+":\n"+ + prop+"\n") ; + return 1 ; +} + +// Remove_item lets the mc take an item off the agenda. +int remove_item (string str) { + + int agitem ; + + if (!str) { + notify_fail ("Usage: remove <number of agenda item>\n") ; + return 0 ; + } + if (sscanf(str,"%d",agitem)!=1) { + notify_fail ("Usage: remove <number of agenda item>\n") ; + return 0 ; + } + if (agitem<0 || agitem>sizeof(agenda)) { + write ("Item number out of range.\n") ; + return 0 ; + } + // Convert to 0-(N-1) numbering. + agitem = agitem-1 ; + write (agitem+"\n") ; + write ("Removing the following agenda item:\n"+agenda[agitem]+"\n") ; + if (agitem==0) { + agenda = agenda[1..sizeof(agenda)-1] ; + } else { + if (agitem == sizeof(agenda)-1) { + agenda = agenda[0..sizeof(agenda)-2] ; + } else { + agenda = agenda[0..agitem-1] + agenda[agitem+1..sizeof(agenda)-1] ; + } + } + return 1 ; +} + +// Vote lets a player cast a vote on the proposed issue. See the help +// document for details on how voting works. +int vote (string str) { + // With no argument, we print the proposal, if there is one. + if (!str) { + if (!vote_str || vote_str=="none") { + write ("No vote is in progress.\n") ; + return 1 ; + } + write ("Voting on: "+vote_str+"\n") ; + return 1 ; + } + // If there is a argument, we interpret that string as a vote cast. + if (!vote_str || vote_str=="none") { + write ("No vote is in progress at this time.\n") ; + return 1 ; + } + if (str!="yes" && str!="no" && str!="abstain") { + write ("Please vote yes, no, or abstain..\n") ; + return 1 ; + } + if (member_array( this_player()->GetName(),voters)!=-1) { + write ("You have already voted!\n") ; + return 1 ; + } + voters += ({ this_player()->GetName() }) ; + votes[str] = votes[str]+1 ; + write ("You vote "+str+" on "+vote_str+".\n") ; + // If this is a roll call vote - ie, the votes are being logged - we announce + // the vote to the log file and to the room. + if (votelog) { + say (capitalize(this_player()->GetName())+" votes "+capitalize(str)+".\n") ; + } + return 1 ; +} + +// Call_for_vote allows the mc to call for a secret-ballot vote on +// a proposal. +int call_for_vote (string str) { + + string timestr, subjstr ; + int i ; + + if ( mc != this_player()->GetKeyName() ) { + write ("Only the mc may call for votes.\n") ; + return 1 ; + } + // Must specify an amount of time for which votes may be cast, and a subject + // which people are voting on. + if (!str) { + write ("Usage: call <num> <minutes|seconds> <subject>\n") ; + return 1 ; + } + if (sscanf(str,"%d %s %s",i,timestr,subjstr)!=3) { + write ("Usage: call <num> <minutes|seconds> <subject>\n") ; + return 1 ; + } + // This is going to reset the clock: so we want to force the mc to + // clear the clock first. + if (endtime!=0) { + write ("The clock is running. You must reset the clock first.\n") ; + return 1 ; + } + if (timestr=="minutes") { + i = i * 60 ; + } else { + if (timestr!="seconds") { + write ("Enter the time in minutes or seconds.\n") ; + return 1 ; + } + } + vote_str = subjstr ; + // This is a secret ballot so we don't want to log the votes. + votelog = 0 ; + write ("You call for a vote on "+vote_str+".\n") ; + say (capitalize(mc)+" calls for a vote on "+vote_str+".\n") ; + say (capitalize(mc)+" sets the clock to "+str+".\n") ; + endtime = time()+i ; + // Call out to a function which totals the votes at the end of the vote time. + call_out ("expire_vote",i) ; + return 1 ; +} + +// Call_for_roll is exactly like call_for_vote EXCEPT that it calls for +// a roll-call vote: that is, all votes are announced and logged. +int call_for_roll (string str) { + + string timestr, subjstr ; + int i ; + + if ( mc != this_player()->GetKeyName() ) { + write ("Only the mc may call for votes.\n") ; + return 1 ; + } + if (!str) { + write ("Usage: rollcall <num> <minutes|seconds> <subject>\n") ; + return 1 ; + } + if (sscanf(str,"%d %s %s",i,timestr,subjstr)!=3) { + write ("Usage: rollcall <num> <minutes|seconds> <subject>\n") ; + return 1 ; + } + if (endtime!=0) { + write ("The clock is running. You must reset the clock first.\n") ; + return 1 ; + } + if (timestr=="minutes") { + i = i * 60 ; + } else { + if (timestr!="seconds") { + write ("Enter the time in minutes or seconds.\n") ; + return 1 ; + } + } + vote_str = subjstr ; + // This is a roll call vote so we log the votes and announce them. + votelog = 1 ; + write ("You call for a roll call vote on "+vote_str+".\n") ; + say (capitalize(mc)+" calls for a roll call vote on "+vote_str+".\n") ; + say (capitalize(mc)+" sets the clock to "+str+".\n") ; + endtime = time()+i ; + call_out ("expire_vote",i) ; + return 1 ; +} + +// Expire_vote finishes the vote and tabulates the results. It does not +// announce the outcome because some votes required 2/3 or 3/4 to pass +// rather than a simple majority. +int expire_vote() { + tell_room (environment(this_object()), "The clock runs out. Voting is over.\n") ; + endtime = 0 ; + tell_room (environment(this_object()), "The results of the vote were:\n"+ + "Yes: "+votes["yes"]+" No: "+votes["no"]+" Abstain: "+ + votes["abstain"]+"\n") ; + voters = ({ }) ; + votes["yes"] = 0 ; + votes["no"] = 0 ; + votes["abstain"] = 0 ; + vote_str="none" ; +} + +int localupdate() { + if(!archp(this_player())){ + write ("You may not update objects while in the conference room.\n") ; + return 1; + } +} + +int eventDestruct(){ + if(sizeof(mc) && !this_player() || (this_player() && !archp(this_player()))){ + write("You may not tamper with the podium."); + return 0; + } + else return ::eventDestruct(); +} + +int eventMove(mixed dest){ + if(sizeof(mc)){ + write("No."); + return 0; + } + else return ::eventMove(dest); +} + diff --git a/lib/domains/campus/obj/pwatch.c b/lib/domains/campus/obj/pwatch.c new file mode 100644 index 0000000..ad2ab88 --- /dev/null +++ b/lib/domains/campus/obj/pwatch.c @@ -0,0 +1,49 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <localtime.h> +inherit LIB_ARMOR; + +string l_time; +string l_time,tzone; +static void create(){ + armor::create(); + SetKeyName("pocket watch"); + SetId(({"watch","pocketwatch","pocket watch","timepiece"})); + SetShort("a gold pocket watch"); + SetLong("This is a beautifully decorated and intricately carved "+ + "pocket watch made of gold. It glows with an almost surreal, deep golden "+ + "luster. It is quietly ticking the seconds, and it looks like you can get the "+ + "accurate time by checking the watch."); + SetMass(10); + SetDollarCost(1); + SetProtection(BLUNT,1); + SetProtection(BLADE,1); + SetProtection(KNIFE,1); + SetArmorType(A_AMULET); +} +void init(){ + ::init(); + add_action("check_time","check"); + add_action("pre_check","time"); +} +int pre_check(string str){ + if(!str){ + this_object()->check_time("time"); + return 1; + } +} +int check_time(string str){ + if(str=="time" || str=="watch"){ + if(present("pocket watch",this_player())){ + tzone="/daemon/timezone"->GetTZ(); + l_time="/daemon/current_time"->GetCurrentTime(tzone); + write("Checking the pocket watch, you see it is "+l_time+".\n"); + say(this_player()->GetName()+" checks "+possessive(this_player())+ + " pocket watch.\n"); + return 1; + } + write("You cannot read the watch face from here.\n"); + return 1; + } +} diff --git a/lib/domains/campus/obj/rayovac.c b/lib/domains/campus/obj/rayovac.c new file mode 100644 index 0000000..b39eef4 --- /dev/null +++ b/lib/domains/campus/obj/rayovac.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include <vendor_types.h> +inherit "/lib/flashlight"; + + +void create(){ + ::create(); + SetKeyName("flashlight"); + SetId( ({"fl","flashlight","light","torch","flashlite"}) ); + SetAdjectives( ({"plastic","small","cheap","rayovac","Rayovac"}) ); + SetShort( "a small, plastic flashlight" ); + SetLong("This is a cheap Rayovac brand flashlight."); + SetMass(20); + SetDollarCost(10); + SetLightLevel(6); + SetMinCells(2); + SetMaxCells(2); + SetCellType("D"); + Lit=0; + SetVendorType(VT_TREASURE); + SetInventory(([ + "/domains/campus/obj/dcell_crappy":2 + ])); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/redbox.c b/lib/domains/campus/obj/redbox.c new file mode 100644 index 0000000..29fe2f4 --- /dev/null +++ b/lib/domains/campus/obj/redbox.c @@ -0,0 +1,28 @@ +/* /domains/Examples/etc/bag.c + * from the Dead Souls LPC Library + * a sample bag object + * created by Descartes of Borg 950529 + */ + +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("redbox"); + SetId( ({ "box","redbox","rbox" }) ); + SetAdjectives( ({ "small", "plastic","red", "a" }) ); + SetShort("a small, %^RED%^red%^RESET%^ plastic box"); + SetLong("It is a simple plastic box used to hold things. It is %^RED%^red%^RESET%^, and it has a cute Virtual Campus "+ + "logo on it."); + SetMass(274); + SetDollarCost(1); + SetMaxCarry(100); + SetCanClose(1); + SetClosed(0); + // SetPreventPut("You cannot put this in there!"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/register.c b/lib/domains/campus/obj/register.c new file mode 100644 index 0000000..845e8e0 --- /dev/null +++ b/lib/domains/campus/obj/register.c @@ -0,0 +1,25 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("register"); + SetId(({"register","machine"})); + SetAdjectives(({"cash","metal"})); + SetShort("a cash register"); + SetLong("This is a metal machine used for cash transactions."); + SetMass(200); + SetBaseCost("silver",50); + SetMaxCarry(10); + SetPreventPut("You cannot put this in there!"); + SetMoney( ([ + "dollars" : random(200), + ]) ); + SetCanClose(1); + SetClosed(1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/round.c b/lib/domains/campus/obj/round.c new file mode 100644 index 0000000..8e8252e --- /dev/null +++ b/lib/domains/campus/obj/round.c @@ -0,0 +1,17 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ROUND; + +void create(){ + round::create(); + SetKeyName(".357 round"); + SetId(({"round","bullet"})); + SetAdjectives(({".357","caliber","revolver","pistol"})); + SetShort("a .357 pistol round"); + SetLong("This is a .357 caliber revolver bullet. It has not been fired."); + SetCaliber(357); + SetFirearmType("revolver"); + SetAmmoType("magnum"); + SetVendorType(VT_TREASURE); + SetMass(1); +} diff --git a/lib/domains/campus/obj/simple_chair.c b/lib/domains/campus/obj/simple_chair.c new file mode 100644 index 0000000..cfeefa5 --- /dev/null +++ b/lib/domains/campus/obj/simple_chair.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_CHAIR; + +static void create() { + chair::create(); + SetKeyName("chair"); + SetAdjectives( ({"simple", "wooden"}) ); + SetId("chair"); + SetShort("a wooden chair"); + SetLong("A simple chair, made of wood, for sitting on."); + SetMass(150); + SetDollarCost(15); + SetMaxSitters(1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/sofa.c b/lib/domains/campus/obj/sofa.c new file mode 100644 index 0000000..6f10203 --- /dev/null +++ b/lib/domains/campus/obj/sofa.c @@ -0,0 +1,27 @@ +/* /domains/campus/etc/stool.c + * From the Dead Souls Object Library + * An example of a chair object + * Created by Descartes of Borg 961221 + */ + +#include <lib.h> + +inherit LIB_CHAIR; + + +static void create() { + chair::create(); + SetKeyName("sofa"); + SetId("sofa"); + SetAdjectives( ({ "black", "small", "tasteful", "upholstered" }) ); + SetShort("a sofa"); + SetLong("This is a small, plush sofa tastefully upholstered "+ + "in black. It appears designed for sitting on."); + SetMass(1500); + SetDollarCost(15); + SetMaxSitters(2); +} +mixed CanGet(object ob) { return "The bench does not budge.";} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/spam.c b/lib/domains/campus/obj/spam.c new file mode 100644 index 0000000..a8b14cb --- /dev/null +++ b/lib/domains/campus/obj/spam.c @@ -0,0 +1,74 @@ +#include <lib.h> +#include <vendor_types.h> +#define DIR_TXT "/domains/campus/txt" +inherit LIB_ITEM; +int Spam(string spam); +string SpamSpam(string spamspam); +int SpamSpamSpam(string spamspamspam); +string spam1, spam2; +void create(){ + ::create(); + SetKeyName("spam can"); + SetId(({"spam","can"})); + SetAdjectives(({"can of","can","spam"})); + SetShort("a can of spam"); + SetLong( (: SpamSpam :) ); + SetMass(20); + SetDollarCost(10); + SetVendorType(VT_TREASURE); +} +void init(){ + ::init(); + add_action("SpamSpamSpamSpam","spam"); +} + +string SpamSpam(string spamspam){ + string spamspamspam; + spamspamspam=read_file("/domains/campus/txt/spam.txt"); + return spamspamspam; +} +int SpamSpamSpamSpam(string spam){ + string spamspam; + object ob; + if(!spam || spam == ""){ + this_object()->Spam(); + return 1; + } + if(!sscanf(spam,"%s with %s",spam1,spam2)){ + write("You'd like to spam who with what?"); + say(this_player()->GetName()+" fumbles with "+possessive(this_player())+ + " can of spam.\n"); + return 1; + } + ob=present(spam1,environment(this_player())); + if(!ob){ + write("There is no such thing here to spam!\n"); + say(this_player()->GetName()+" looks around for something to spam.\n"); + return 1; + } + if(!living(ob)){ + write(ob->GetShort()+" is not impressed by spam.\n"); + say(this_player()->GetName()+" spams around foolishly.\n"); + return 1; + } + if(file_size(DIR_TXT+"/"+spam2+".txt") == -1){ + write("You cannot spam "+ob->GetName()+" that way. You look silly.\n"); + say(this_player()->GetName()+" looks silly trying to spam incorrectly.\n"); + return 1; + } + spamspam=unguarded((: read_file(DIR_TXT+"/"+spam2+".txt") :)); + say(this_player()->GetName()+" spams "+ob->GetName()+" with a "+ + "giant "+spam2+".\n"); + tell_object(ob, this_player()->GetName()+" spams you with:\n"+spamspam+"\n"); + write("You spam "+ob->GetName()+" with a giant "+spam2+"!\n"); + return 1; +} +int Spam(string spamspamspamspam){ + string but_I_dont_like_spam; + but_I_dont_like_spam=unguarded((:read_file("/secure/obj/txt/spam.txt") :)); + this_player()->SetLong("$N is a can of spam:\n\n"+but_I_dont_like_spam); + this_player()->AddTitle("the can of spam (Spammy!)"); + write("You spam all over yourself!\n"); + say(this_player()->GetName()+" spams all over "+objective(this_player())+"self!\n"); + return 1; +} diff --git a/lib/domains/campus/obj/spent.c b/lib/domains/campus/obj/spent.c new file mode 100644 index 0000000..762f769 --- /dev/null +++ b/lib/domains/campus/obj/spent.c @@ -0,0 +1,20 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; + +void create(){ + ::create(); + SetKeyName("slug"); + SetId( ({"slug","round","bullet","projectile"}) ); + SetAdjectives( ({"spent","lead"}) ); + SetShort("a spent firearms slug"); + SetLong("This small, twisted chunk of metal appears to be a spent "+ + "slug: the part of a bullet that is fired from a gun and enters the target. "+ + "Its shape has been distorted by its impact with whatever it hit."); + SetMass(1); + SetDollarCost(0); + SetVendorType(VT_TREASURE); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/squirtbag.c b/lib/domains/campus/obj/squirtbag.c new file mode 100644 index 0000000..8d7867a --- /dev/null +++ b/lib/domains/campus/obj/squirtbag.c @@ -0,0 +1,28 @@ +/* /domains/Examples/etc/bag.c + * from the Dead Souls LPC Library + * a sample bag object + * created by Descartes of Borg 950529 + */ + +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("bag"); + SetId( ({ "bag" }) ); + SetAdjectives( ({ "small", "cloth", "a" }) ); + SetShort("a small cloth bag"); + SetLong("It is a simple cloth bag used to hold things. It has a cute Virtual Campus "+ + "logo on it."); + SetInventory(([ + "/domains/campus/weap/waterpistol" : 1, + ])); + SetMass(10); + SetDollarCost(1); + SetMaxCarry(50); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/stargate.c b/lib/domains/campus/obj/stargate.c new file mode 100644 index 0000000..083adc1 --- /dev/null +++ b/lib/domains/campus/obj/stargate.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include <daemons.h> +#include "/lib/include/stargate.h" + +inherit LIB_STARGATE; + +int ReadScreen(); + +void create() +{ + ::create(); + SetOrigin("campus lab", "/domains/campus/room/slab"); + SetRead(([ ({ "screen" }) : (: ReadScreen :) ]) ); + SetItems(([ ({ "screen" }) : "a computer screen which shows the status of the gate network" ]) ); +} + +void init() +{ + ::init(); +} + +int ReadScreen() +{ + write("stargate network status\n"); + write("-----------------------\n"); + write("\n"); + +} diff --git a/lib/domains/campus/obj/thing.c b/lib/domains/campus/obj/thing.c new file mode 100644 index 0000000..38f1531 --- /dev/null +++ b/lib/domains/campus/obj/thing.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; + +void create(){ + ::create(); + SetKeyName("generic thing"); + SetId( ({"thing","item","thang","dingus"}) ); + SetAdjectives( ({"generic","sample","template"}) ); + SetShort("a generic thing"); + SetLong("This is an object of indeterminate nature and proportions."); + SetMass(200); + SetDollarCost(10); + SetVendorType(VT_TREASURE); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/tlocker.c b/lib/domains/campus/obj/tlocker.c new file mode 100644 index 0000000..7e30839 --- /dev/null +++ b/lib/domains/campus/obj/tlocker.c @@ -0,0 +1,37 @@ +/* /domains/Examples/etc/bag.c + * from the Dead Souls LPC Library + * a sample bag object + * created by Descartes of Borg 950529 + */ + +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("locker"); + SetId(({"locker"})); + SetAdjectives(({"metal","tall","school"})); + SetShort("a tall metal locker"); + SetLong("This is a large school locker, the kind one might find in any of "+ + "thousands of schools around the world."); + SetMass(3000); + SetDollarCost(50); + SetMaxCarry(500); + SetInventory(([ + "/domains/campus/obj/bag": 1, + "/domains/campus/obj/9mmclip": 1, + "/domains/campus/weap/waterpistol" : 1, + "/domains/campus/obj/223clip": 1 + ])); + SetCanClose(1); + SetClosed(0); + SetCanLock(1); + SetLocked(0); + SetKey("locker_key_1"); +} +mixed CanGet(object ob) { return "The locker does not budge.";} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/torch.c b/lib/domains/campus/obj/torch.c new file mode 100644 index 0000000..b009d9c --- /dev/null +++ b/lib/domains/campus/obj/torch.c @@ -0,0 +1,31 @@ +/* /domains/Praxis/etc/torch.c + * from Dead Souls + * created by Descartes of Borg 951023 + */ + +#include <lib.h> + +inherit LIB_TORCH; + + +static void create() { + torch::create(); + SetKeyName("torch"); + SetId( ({ "torch", "old torch", "wooden torch" }) ); + SetAdjectives( ({ "old", "wooden" }) ); + SetShort("an old, wooden torch"); + SetLong("An old, wooden torch with a bit of cloth wrapped around " + "one end and dipped into a flamable substance."); + SetRadiantLight(7); + SetFuelRequired(1); + SetMaxFuel(1000); + SetFuelAmount(1000); + SetRefuelable(1); + SetMass(50); + SetDollarCost(60); + SetBurntValue(10); + SetClass(10); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/trashcan.c b/lib/domains/campus/obj/trashcan.c new file mode 100644 index 0000000..26ae04d --- /dev/null +++ b/lib/domains/campus/obj/trashcan.c @@ -0,0 +1,24 @@ +#include <lib.h> + +inherit LIB_BASE_DUMMY; +inherit LIB_STORAGE; + +static void create() { + base_dummy::create(); + storage::create(); + SetKeyName("trashcan"); + SetId(({"can","container","bin"})); + SetAdjectives("trash","rubbish","waste"); + SetShort("a trashcan"); + SetLong("A container for discarding waste."); + SetMass(1500); + SetDollarCost(15); + SetMaxCarry(900); + SetInventory( ([ + "/domains/campus/obj/key1" : 1, + ]) ); + SetPreventGet("It is firmly attached to the ground."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/watch.c b/lib/domains/campus/obj/watch.c new file mode 100644 index 0000000..88eb9cd --- /dev/null +++ b/lib/domains/campus/obj/watch.c @@ -0,0 +1,48 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <localtime.h> +inherit LIB_ARMOR; + +string l_time,tzone; +static void create(){ + armor::create(); + SetKeyName("pocket watch"); + SetId(({"watch","pocketwatch","pocket watch","timepiece"})); + SetShort("a pocket watch"); + SetLong("This is a beautifully decorated and intricately carved "+ + "pocket watch. It glows with a bright, polished bronze "+ + "luster. It is quietly ticking the seconds, and it looks like you can get the "+ + "accurate time by checking the watch."); + SetMass(10); + SetBaseCost("silver", 40); + SetProtection(BLUNT,1); + SetProtection(BLADE,1); + SetProtection(KNIFE,1); + SetArmorType(A_AMULET); +} +void init(){ + ::init(); + add_action("check_time","check"); + add_action("pre_check","time"); +} +int pre_check(string str){ + if(!str){ + this_object()->check_time("time"); + return 1; + } +} +int check_time(string str){ + if(str=="time" || str=="watch"){ + if(present("pocket watch",this_player())){ + tzone="/daemon/timezone"->GetTZ(); + l_time="/daemon/current_time"->GetCurrentTime(tzone); + write("Checking the pocket watch, you see it is "+l_time+".\n"); + say(this_player()->GetName()+" checks "+possessive(this_player())+ + " pocket watch.\n"); + return 1; + } + write("You cannot read the watch face from here.\n"); + return 1; + } +} diff --git a/lib/domains/campus/obj/wlocker.c b/lib/domains/campus/obj/wlocker.c new file mode 100644 index 0000000..768935b --- /dev/null +++ b/lib/domains/campus/obj/wlocker.c @@ -0,0 +1,35 @@ +/* /domains/Examples/etc/bag.c + * from the Dead Souls LPC Library + * a sample bag object + * created by Descartes of Borg 950529 + */ + +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("locker"); + SetId(({"locker"})); + SetAdjectives(({"metal","tall","large","weapon","weapons"})); + SetShort("a metal weapons locker"); + SetLong("This is a large metal locker designed to contain firearms."); + SetMass(3000); + SetDollarCost(50); + SetMaxCarry(500); + SetInventory(([ + "/domains/campus/weap/9mil" : 5, + //"/domains/campus/weap/m16rifle" : 5, + //"/domains/campus/weap/50rifle" : 5, + "/domains/campus/weap/357pistol" : 5, + ])); + SetCanClose(1); + SetClosed(0); + SetCanLock(1); + SetLocked(0); +} +mixed CanGet(object ob) { return "The locker does not budge.";} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/workbench.c b/lib/domains/campus/obj/workbench.c new file mode 100644 index 0000000..bcb5573 --- /dev/null +++ b/lib/domains/campus/obj/workbench.c @@ -0,0 +1,27 @@ +#include <lib.h> + +inherit LIB_TABLE; + +void create() { + ::create(); + SetKeyName("workbench"); + SetAdjectives( ({"work", "simple", "flat"}) ); + SetId( ({"table", "workbench", "bench"}) ); + SetShort("a workbench"); + SetLong("A simple flat surface for analyzing materials."); + SetMaxCarry(5000); + SetInventory(([ + "/domains/town/armor/rocketpack" : 1, + "/domains/default/obj/generator" : 1, + "/domains/default/obj/module_cloak" : 1, + "/domains/default/armor/wristcomp" : 1, + "/domains/default/obj/vial_blue" : 1, + "/domains/town/armor/breather" : 1, + ])); + SetPreventGet("The workbench does not budge."); + SetBaseCost("silver",1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/wrack.c b/lib/domains/campus/obj/wrack.c new file mode 100644 index 0000000..c2e6b57 --- /dev/null +++ b/lib/domains/campus/obj/wrack.c @@ -0,0 +1,36 @@ +/* /domains/Examples/etc/bag.c + * from the Dead Souls LPC Library + * a sample bag object + * created by Descartes of Borg 950529 + */ + +#include <lib.h> + +inherit LIB_STORAGE; + + +void create() { + ::create(); + SetKeyName("rack"); + SetId(({"wrack"})); + SetAdjectives(({"wooden","large","weapon","weapons"})); + SetShort("a wooden weapons rack"); + SetLong("This is a large wooden rack designed to contain "+ + "conventional or melee weapons. It is set into the wall."); + SetMass(3000); + SetDollarCost(500); + SetMaxCarry(5000); + SetInventory(([ + "/domains/campus/weap/dagger" : 5, + "/domains/campus/weap/sword" : 5, + "/domains/campus/weap/sharpsword" : 5, + "/domains/campus/weap/staff" : 5, + ])); + SetCanClose(1); + SetClosed(0); + +} +mixed CanGet(object ob) { return "The rack does not budge.";} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/obj/yellowbox.c b/lib/domains/campus/obj/yellowbox.c new file mode 100644 index 0000000..0ad3e87 --- /dev/null +++ b/lib/domains/campus/obj/yellowbox.c @@ -0,0 +1,28 @@ +/* /domains/Examples/etc/bag.c + * from the Dead Souls LPC Library + * a sample bag object + * created by Descartes of Borg 950529 + */ + +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("yellowbox"); + SetId( ({ "box","yellowbox","ybox" }) ); + SetAdjectives( ({ "small", "plastic","yellow", "a" }) ); + SetShort("a small, %^YELLOW%^yellow%^RESET%^ plastic box"); + SetLong("It is a simple plastic box used to hold things. It is %^YELLOW%^yellow%^RESET%^, and it has a cute Virtual Campus "+ + "logo on it."); + SetMass(274); + SetDollarCost(1); + SetMaxCarry(100); + SetCanClose(1); + SetClosed(0); + // SetPreventPut("You cannot put this in there!"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/access0.c b/lib/domains/campus/room/access0.c new file mode 100644 index 0000000..aa574b1 --- /dev/null +++ b/lib/domains/campus/room/access0.c @@ -0,0 +1,46 @@ +#include <lib.h> +inherit LIB_ROOM; + +int eventHopDown(){ + write("You hop down into the hole, noting that there is no ladder for getting back up."); + say(this_player()->GetName()+" hops into the open manhole.",this_player()); + return 1; +} +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(16); + SetShort("access tunnel"); + SetLong("You are standing in what appears to be an underground "+ + "service access tunnel of some kind. The overhead neon lights flicker and "+ + "provide barely useful illumination. The air is damp and musty, and it "+ + "feels as though nobody has gone through here in years. The tunnel runs "+ + "south from here. This appears to be the north end of the tunnel. There "+ + "is a large, open manhole in the floor here."); + SetItems(([ + ({"wall","walls","corridor","hall"}) : "The thick, metal walls here are scarred "+ + "and badly corroded. Wherever you are, it's seen heavy use in the distant past.", + ({"lights","light","neon lights"}) : "Overhead neon lights. They appear on the "+ + "verge of failure.", + ({"floor","ground"}) : "The floor is composed of metal plates welded together, "+ + "with raised traction cleats.", + ({"cleat","cleats"}) : "Little raised bumps on the floor so you won't slip and fall.", + ({"ladder","metal ladder"}) : "You see rusted bolts in the concrete floor and in "+ + "the hole that suggest a ladder was once here.", + ({"hole","manhole"}) : "This is an opening built into the floor for access to "+ + "whatever it is that lies below. It looks like there was once a metal ladder for easy "+ + "movement, but it's now gone, so any trip down is one-way.", + ])); + AddExit("down","/domains/campus/room/sewer", (: eventHopDown :) ); + AddExit("south","/domains/campus/room/access5"); +} +int CanReceive(object ob){ + if(ob && ob->GetRace() == "rodent"){ + message("info","You are repelled by rodenticide.",ob); + return 0; + } + return ::CanReceive(ob); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/access1.c b/lib/domains/campus/room/access1.c new file mode 100644 index 0000000..3015dc7 --- /dev/null +++ b/lib/domains/campus/room/access1.c @@ -0,0 +1,31 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(16); + SetShort("access tunnel"); + SetLong("You are standing in what appears to be an underground "+ + "service access tunnel of some kind. The overhead neon lights flicker and "+ + "provide barely useful illumination. The air is damp and musty, and it "+ + "feels as though nobody has gone through here in years. The tunnel runs "+ + "north and south from here. You feel a slight breeze coming from the "+ + "north."); + SetItems(([ + ({"wall","walls","corridor","hall"}) : "The thick, metal walls here are scarred "+ + "and badly corroded. Wherever you are, it's seen heavy use in the distant past.", + ({"lights","light","neon lights"}) : "Overhead neon lights. They appear on the "+ + "verge of failure.", + ({"floor","ground"}) : "The floor is composed of metal plates welded together, "+ + "with raised traction cleats.", + ({"cleat","cleats"}) : "Little raised bumps on the floor so you won't slip and fall.", + ])); + AddExit("north","/domains/campus/room/access0"); + AddExit("south","/domains/campus/room/access2"); + SetObviousExits("north, south"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/access2.c b/lib/domains/campus/room/access2.c new file mode 100644 index 0000000..1fcb5d6 --- /dev/null +++ b/lib/domains/campus/room/access2.c @@ -0,0 +1,34 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(16); + SetShort("access tunnel"); + SetLong("You are standing in what appears to be an underground "+ + "service access tunnel of some kind. The overhead neon lights flicker and "+ + "provide barely useful illumination. The air is damp and musty, and it "+ + "feels as though nobody has gone through here in years. The tunnel runs "+ + "north and south from here."); + SetItems(([ + ({"wall","walls","corridor","hall"}) : "The thick, metal walls here are scarred "+ + "and badly corroded. Wherever you are, it's seen heavy use in the distant past.", + ({"lights","light","neon lights"}) : "Overhead neon lights. They appear on the "+ + "verge of failure.", + ({"floor","ground"}) : "The floor is composed of metal plates welded together, "+ + "with raised traction cleats.", + ({"cleat","cleats"}) : "Little raised bumps on the floor so you won't slip and fall.", + ({"hole","port","porthole","access port"}) : "An exit set in the wall, providing maintenance access.", + ])); + SetEnters( ([ + ({"hole","port","porthole","access port"}):"/domains/campus/room/furnace" + ]) ); + AddExit("north","/domains/campus/room/access1"); + AddExit("south","/domains/campus/room/access3"); + SetObviousExits("north, south"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/access3.c b/lib/domains/campus/room/access3.c new file mode 100644 index 0000000..26448aa --- /dev/null +++ b/lib/domains/campus/room/access3.c @@ -0,0 +1,34 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(16); + SetShort("access tunnel"); + SetLong("You are standing in what appears to be an underground "+ + "service access tunnel of some kind. The overhead neon lights flicker and "+ + "provide barely useful illumination. The air is damp and musty, and it "+ + "feels as though nobody has gone through here in years. The tunnel runs "+ + "north and south from here."); + SetItems(([ + ({"wall","walls","corridor","hall"}) : "The thick, metal walls here are scarred "+ + "and badly corroded. Wherever you are, it's seen heavy use in the distant past.", + ({"lights","light","neon lights"}) : "Overhead neon lights. They appear on the "+ + "verge of failure.", + ({"floor","ground"}) : "The floor is composed of metal plates welded together, "+ + "with raised traction cleats.", + ({"cleat","cleats"}) : "Little raised bumps on the floor so you won't slip and fall.", + ({"hole","port","porthole","access port"}) : "An exit set in the wall, providing maintenance access.", + ])); + SetEnters( ([ + ({"hole","port","porthole","access port"}):"/domains/campus/room/freezer" + ]) ); + AddExit("north","/domains/campus/room/access0"); + AddExit("south","/domains/campus/room/access4"); + SetObviousExits("north, south"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/access4.c b/lib/domains/campus/room/access4.c new file mode 100644 index 0000000..330d33e --- /dev/null +++ b/lib/domains/campus/room/access4.c @@ -0,0 +1,31 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(16); + SetShort("access tunnel"); + SetLong("You are standing in what appears to be an underground "+ + "service access tunnel of some kind. The overhead neon lights flicker and "+ + "provide barely useful illumination. The air is damp and musty, and it "+ + "feels as though nobody has gone through here in years. The tunnel runs "+ + "north and south from here."); + SetItems(([ + ({"wall","walls","corridor","hall"}) : "The thick, metal walls here are scarred "+ + "and badly corroded. Wherever you are, it's seen heavy use in the distant past.", + ({"lights","light","neon lights"}) : "Overhead neon lights. They appear on the "+ + "verge of failure.", + ({"floor","ground"}) : "The floor is composed of metal plates welded together, "+ + "with raised traction cleats.", + ({"cleat","cleats"}) : "Little raised bumps on the floor so you won't slip and fall.", + ])); + SetEnters( ([ + ]) ); + AddExit("north","/domains/campus/room/access0"); + AddExit("south","/domains/campus/room/access5"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/access5.c b/lib/domains/campus/room/access5.c new file mode 100644 index 0000000..3ed25ab --- /dev/null +++ b/lib/domains/campus/room/access5.c @@ -0,0 +1,35 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(16); + SetShort("access tunnel"); + SetLong("You are standing in what appears to be an underground "+ + "service access tunnel of some kind. The overhead neon lights flicker and "+ + "provide barely useful illumination. The air is damp and musty, and it "+ + "feels as though nobody has gone through here in years. The tunnel runs "+ + "north and south from here."); + SetItems(([ + ({"wall","walls","corridor","hall"}) : "The thick, metal walls here are scarred "+ + "and badly corroded. Wherever you are, it's seen heavy use in the distant past.", + ({"lights","light","neon lights"}) : "Overhead neon lights. They appear on the "+ + "verge of failure.", + ({"floor","ground"}) : "The floor is composed of metal plates welded together, "+ + "with raised traction cleats.", + ({"cleat","cleats"}) : "Little raised bumps on the floor so you won't slip and fall.", + ])); + SetEnters( ([ + ]) ); + AddExit("north","/domains/campus/room/access0"); + AddExit("south","/domains/campus/room/access6"); + SetInventory(([ + "/domains/campus/npc/rat" :1 + ])); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/access6.c b/lib/domains/campus/room/access6.c new file mode 100644 index 0000000..be5ee34 --- /dev/null +++ b/lib/domains/campus/room/access6.c @@ -0,0 +1,31 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(16); + SetShort("access tunnel"); + SetLong("You are standing in what appears to be an underground "+ + "service access tunnel of some kind. The overhead neon lights flicker and "+ + "provide barely useful illumination. The air is damp and musty, and it "+ + "feels as though nobody has gone through here in years. The tunnel runs "+ + "north and south from here."); + SetItems(([ + ({"wall","walls","corridor","hall"}) : "The thick, metal walls here are scarred "+ + "and badly corroded. Wherever you are, it's seen heavy use in the distant past.", + ({"lights","light","neon lights"}) : "Overhead neon lights. They appear on the "+ + "verge of failure.", + ({"floor","ground"}) : "The floor is composed of metal plates welded together, "+ + "with raised traction cleats.", + ({"cleat","cleats"}) : "Little raised bumps on the floor so you won't slip and fall.", + ])); + SetEnters( ([ + ]) ); + AddExit("north","/domains/campus/room/access5"); + AddExit("south","/domains/campus/room/access7"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/access7.c b/lib/domains/campus/room/access7.c new file mode 100644 index 0000000..4f0ff74 --- /dev/null +++ b/lib/domains/campus/room/access7.c @@ -0,0 +1,32 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(16); + SetShort("access tunnel"); + SetLong("You are standing in what appears to be an underground "+ + "service access tunnel of some kind. The overhead neon lights flicker and "+ + "provide barely useful illumination. The air is damp and musty, and it "+ + "feels as though nobody has gone through here in years. The tunnel runs "+ + "north and south from here."); + SetItems(([ + ({"wall","walls","corridor","hall"}) : "The thick, metal walls here are scarred "+ + "and badly corroded. Wherever you are, it's seen heavy use in the distant past.", + ({"lights","light","neon lights"}) : "Overhead neon lights. They appear on the "+ + "verge of failure.", + ({"floor","ground"}) : "The floor is composed of metal plates welded together, "+ + "with raised traction cleats.", + ({"cleat","cleats"}) : "Little raised bumps on the floor so you won't slip and fall.", + ])); + SetEnters( ([ + ]) ); + AddExit("north","/domains/campus/room/access6"); + AddExit("south","/domains/campus/room/access9"); + AddExit("east","/domains/campus/room/tunnel2"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/access9.c b/lib/domains/campus/room/access9.c new file mode 100644 index 0000000..7e6c737 --- /dev/null +++ b/lib/domains/campus/room/access9.c @@ -0,0 +1,32 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(16); + SetShort("access tunnel"); + SetLong("You are standing in what appears to be an underground service access tunnel of some kind. The overhead neon lights flicker and provide barely useful illumination. The air is damp and musty, and it feels as though nobody has gone through here in years. The tunnel runs north from here. A hatch in the floor leads down."); + SetItems(([ + ({"wall","walls","corridor","hall"}) : "The thick, metal walls here are scarred "+ + "and badly corroded. Wherever you are, it's seen heavy use in the distant past.", + ({"lights","light","neon lights"}) : "Overhead neon lights. They appear on the "+ + "verge of failure.", + ({"floor","ground"}) : "The floor is composed of metal plates welded together, "+ + "with raised traction cleats.", + ({"cleat","cleats"}) : "Little raised bumps on the floor so you won't slip and fall.", + ])); + SetInventory(([ + ])); + SetExits( ([ + "north" : "/domains/campus/room/access7", + "down" : "/domains/campus/room/maintenance.c", + ]) ); + SetEnters( ([ + ]) ); + SetDoor("down", "/domains/campus/doors/hatch"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/alcove1.c b/lib/domains/campus/room/alcove1.c new file mode 100644 index 0000000..91a1739 --- /dev/null +++ b/lib/domains/campus/room/alcove1.c @@ -0,0 +1,19 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("An alcove"); + SetLong("An alcove."); + SetClimate("indoors"); + SetExits(([ + "east" : "/domains/campus/room/stairwell2a", + ])); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/alcove2.c b/lib/domains/campus/room/alcove2.c new file mode 100644 index 0000000..8dfddc6 --- /dev/null +++ b/lib/domains/campus/room/alcove2.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("An alcove"); + SetLong("An alcove."); + SetClimate("indoors"); + SetItems( ([ + ]) ); + SetInventory(([ + "/domains/campus/weap/board" : 1, + ])); + SetExits(([ + "east" : "/domains/campus/room/weaplab", + ])); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/basement.c b/lib/domains/campus/room/basement.c new file mode 100644 index 0000000..13ef4a0 --- /dev/null +++ b/lib/domains/campus/room/basement.c @@ -0,0 +1,35 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(29); + SetShort("the basement"); + SetLong("You are in the basement of the LPC University administrative building. It "+ + "is very dark here, and rather damp. The fluorescent lighting seems to be "+ + "on the verge of total failure, with only one or two flickering on and off enough "+ + "to see anything. The air here is damp, thick and musty. There is a small crawlspace you can enter under "+ + "the stairs here, and the basement continues west into darkness."); + SetItems(([ + "stairs" : "A flight of stairs leading up. There is a crawlspace beneath them.", + "basement" : "This is a dark, creepy basement.", + "building" : "You are in the basement of the LPC University administrative building.", + ({"dark","darkness"}) : "There's a lot of it, all around.", + ({"light","lighting","fluorescent lighting"}) : "The lighting here is extremely bad. "+ + "The lights show just enough to let you know you'd rather not spend too "+ + "much time in here.", + "air" : "It feels heavy, making it hard to breathe. It's hard to imagine "+ + "who or what would enjoy spending time down here.", + "crawlspace" : "It looks like you might be able to enter the crawlspace, if you "+ + "really wanted to."])); + SetInventory((["/domains/campus/npc/rat" : 1])); + AddExit("up","/domains/campus/room/stairwell"); + AddExit("west","/domains/campus/room/basement2"); + AddEnter("crawlspace" , "/domains/campus/room/crawlspace"); + SetProperty("no attack", 1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/basement2.c b/lib/domains/campus/room/basement2.c new file mode 100644 index 0000000..2798f02 --- /dev/null +++ b/lib/domains/campus/room/basement2.c @@ -0,0 +1,50 @@ +#include <lib.h> +inherit LIB_ROOM; + +int push_it(string str){ + if(str=="wall" || str=="west wall"){ + write("The west wall opens and you fall through!\n"); + say(this_player()->GetName()+" suddenly falls and is gone!\n"); + this_player()->eventMoveLiving("/domains/campus/room/tunnel", "west through a secret exit", this_player()->GetName()+" tumbles in."); + return 1; + } +} + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(5); + SetShort("the basement"); + SetLong("You are in the basement of the LPC University administrative building. It "+ + "is very dark here, and rather damp. The fluorescent lighting seems to have "+ + "completely failed. The east side "+ + "of the basement seems somewhat better lit. The west wall seems heavily "+ + "smudged...it's even grungier than the rest of this place."); + SetItems(([ + "basement" : "This is a dark, creepy basement.", + "building" : "You are in the basement of the LPC University administrative building.", + ({"wall","west wall"}) : "The wall seems to have a lot of smudged handprints "+ + "on it.", + ({"dark","darkness"}) : "There's a lot of it, all around.", + ({"light","lighting","fluorescent lighting"}) : "The lighting here has failed "+ + "completely.", + ({"prints","print","handprint","handprints"}) : "Smudgy handprints, as if someone "+ + "had been against the wall here.", + "air" : "It feels heavy, making it hard to breathe. It's hard to imagine "+ + "who or what would enjoy spending time down here."])); + SetExits( ([ + "east" : "/domains/campus/room/basement.c", + ]) ); + SetRead( ([ + ({"wall","west wall"}) : "The cake is a lie.", + ]), "malkierien" ); + SetProperty("no attack", 1); +} + +void init(){ + ::init(); + add_action("push_it","push"); + add_action("push_it","search"); + add_action("push_it","touch"); + add_action("push_it","open"); +} diff --git a/lib/domains/campus/room/basement3.c b/lib/domains/campus/room/basement3.c new file mode 100644 index 0000000..31cdcc3 --- /dev/null +++ b/lib/domains/campus/room/basement3.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("Secret Lab"); + SetLong("This tidy workspace between campus levels seems to "+ + "be some kind of secret laboratory."); + SetClimate("indoors"); + SetItems( ([ + ]) ); + SetInventory(([ + "/domains/campus/weap/zpem" : 1, + ])); + SetExits( ([ + "west" : "/domains/campus/room/shaft0", + "east" : "/domains/campus/room/basement4.c", + ]) ); + SetDoor("west","/domains/campus/doors/steel_door3"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/basement4.c b/lib/domains/campus/room/basement4.c new file mode 100644 index 0000000..e91e1f1 --- /dev/null +++ b/lib/domains/campus/room/basement4.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("Secret Lab"); + SetLong("This room seems to be used for secret experiments."); + SetClimate("indoors"); + SetItems( ([ + ]) ); + SetExits(([ + "west" : "/domains/campus/room/basement3", + ])); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/blue_room.c b/lib/domains/campus/room/blue_room.c new file mode 100644 index 0000000..ce259b7 --- /dev/null +++ b/lib/domains/campus/room/blue_room.c @@ -0,0 +1,18 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("a blue room"); + SetLong("This is a blue room. Probability Lab 1 is south."); + SetExits( ([ + "south" : "/domains/campus/room/monty" + ]) ); + SetDoor("south","/domains/campus/doors/blue_door"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/blue_room2.c b/lib/domains/campus/room/blue_room2.c new file mode 100644 index 0000000..6d3a94a --- /dev/null +++ b/lib/domains/campus/room/blue_room2.c @@ -0,0 +1,18 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("a blue room"); + SetLong("This is a blue room. Probability Lab 2 is east."); + SetExits( ([ + "east" : "/domains/campus/room/plab2" + ]) ); + SetDoor("east","/domains/campus/doors/blue_door2"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/blue_room3.c b/lib/domains/campus/room/blue_room3.c new file mode 100644 index 0000000..433f1b8 --- /dev/null +++ b/lib/domains/campus/room/blue_room3.c @@ -0,0 +1,18 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("a blue room"); + SetLong("This is a blue room. Probability Lab 3 is west."); + SetExits( ([ + "west" : "/domains/campus/room/plab" + ]) ); + SetDoor("west","/domains/campus/doors/blue_door3"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/bookstore.c b/lib/domains/campus/room/bookstore.c new file mode 100644 index 0000000..df1204d --- /dev/null +++ b/lib/domains/campus/room/bookstore.c @@ -0,0 +1,52 @@ +#include <lib.h> +inherit LIB_SHOP; +int read_sign(); + +static void create() { + ::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("the campus bookstore"); + SetLong("This is the Virtual Campus Bookstore. It is a fairly small place, and in fact has few books available, since the campus is not open for classes yet. There is, however, a wide assortment of useful items available, which you can browse by typing the 'list' command. The storeroom is above. There is a sign on the wall behind the counter."); + SetItems(([ + ({"store","bookstore","place"}) : "This is the Virtual Campus bookstore.", + "books" : "There aren't any yet. Weren't you paying attention?", + ({"assortment","items","stuff"}) : "To browse what you can buy, type: list.", + "counter" : "A cheap wood-textured counter designed to make the surrender "+ + "of your money more convenient.", + "sign" : "A sign on the wall, meant for reading.", + ])); + SetExits( ([ + "south" : "/domains/campus/room/corridor4", + "up" : "/domains/campus/room/bookstore2.c", + ]) ); + SetInventory(([ + "/domains/campus/obj/bbucket" : 1, + "/domains/campus/obj/register" : 1, + /* + * Note: kim has to load *after* the cash register + * in order to guard it! + */ + "/domains/campus/npc/kim" : 1, + ])); + SetRead("sign", (: read_sign :) ); + SetProperty("no attack", 1); +} + +void init(){ + ::init(); + if(!present("bookstore employee",this_object())){ + new("/domains/campus/npc/kim")->eventMove(this_object()); + } +} + +int read_sign(){ + write("HOW TO CONDUCT BUSINESS HERE\n"); + write("list : Get a list of all the items Kim has for sale"); + write("appraise <item> : Ask Kim to tell you how much she would pay you for your item"); + write("price <item> : Ask Kim the price of her item"); + write("show <item> : Ask Kim for a closer look at her item\n"); + write("\nbuy <item> from kim\nsell <item> to kim\n"); + write("Cash US Dollars only!"); + return 1; +} diff --git a/lib/domains/campus/room/bookstore2.c b/lib/domains/campus/room/bookstore2.c new file mode 100644 index 0000000..2e73161 --- /dev/null +++ b/lib/domains/campus/room/bookstore2.c @@ -0,0 +1,38 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetAmbientLight(30); + SetClimate("indoors"); + SetShort("a generic room"); + SetLong("This is an utterly plain, blank room."); + SetInventory(([ + "/domains/campus/obj/diamond" : 1, + "/domains/default/obj/phints" : 5, + "/domains/default/obj/handbook" : 5, + "/domains/campus/obj/pack" : 30, + "/domains/campus/obj/bag" : 3, + "/domains/default/obj/manual" : 5, + "/domains/default/obj/guide" : 5, + "/domains/campus/armor/coat" : 1, + ])); + SetExits( ([ + "down" : "/domains/campus/room/bookstore.c", + ]) ); +} +int CanReceive(object sneak) { + object *living_stack = get_livings(sneak); + if(!living_stack || !arrayp(living_stack)) living_stack = ({ sneak }); + foreach(object ob in living_stack){ + if(living(ob) && !creatorp(ob) && + !member_group(ob,"TEST")) { + message("info","The storeroom is for authorized personnel only.", ob); + return 0; + } + } + return ::CanReceive(sneak); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/classroom1.c b/lib/domains/campus/room/classroom1.c new file mode 100644 index 0000000..121b17f --- /dev/null +++ b/lib/domains/campus/room/classroom1.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("Science Classroom"); + SetLong("This small room provides a teaching space for the advanced topics researched by the facility."); + SetClimate("indoors"); + SetItems( ([ + ]) ); + SetExits(([ + "south" : "/domains/campus/room/science5", + ])); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/conf.c b/lib/domains/campus/room/conf.c new file mode 100644 index 0000000..d43d748 --- /dev/null +++ b/lib/domains/campus/room/conf.c @@ -0,0 +1,101 @@ +#include <lib.h> +#include ROOMS_H +inherit LIB_ROOM; + +object *ejected_players = ({}); + +string ReadSign(); + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(50); + SetShort("Conference Room"); + SetLong("This is the Virtual Campus ad hoc conference room. It is "+ + "elegantly appointed with richly carved mahogany paneling and gold-leaf trim. "+ + "The luxurious carpeting and moody lighting make this conference room "+ + "a very comfortable, relaxing environment. The main hallway is north of here.\n"+ + "%^GREEN%^There is a sign you can read here.%^RESET%^"); + SetItems(([ + ({"panels","paneling","wall","walls","mahogany","wood"}) : "The walls are "+ + "paneled in rich, dark mahogany. The wood is intricately carved with "+ + "exquisite designs. This sort of craftmanship must have cost a fortune.", + ({"room","conference room","ad hoc conference room"}) : "This is a "+ + "well-appointed, comfortable room to hold meetings in.", + ({"carving","carvings","design","designs","craftmanship"}) : "The carvings "+ + "are mostly abstract shapes that seem so detailed and tightly interwoven "+ + "they almost squirm before your eyes.", + ({"leaf","gold-leaf trim","trim","gold leaf trim"}) : "The trim along the walls' "+ + "baseboards and doorframe is a beautiful gold leaf design.", + ({"floor","carpet","carpeting","luxurious carpeting"}) : "The carpet is thick, and "+ + "a rich maroon color.", + ({"lighting","lights","moody lighting"}) : "The lighting here is indirect and diffused, "+ + "giving everything a warm glow.", + "environment" : "Very comfortable indeed.", + "sign" : "Try: read sign", + ])); + SetExits( (["north" : "/domains/campus/room/corridor4", + ])); + SetInventory((["/domains/campus/obj/podium" : 1, + "/secure/npc/cambot" : 1 + ])); + SetRead( ([ + "sign" : (: ReadSign :) + ]) ); + SetProperty("no attack", 1); + SetProperty("meeting room", 1); + SetNoClean(1); +} +int CanReceive(object ob) { + if(ob && interactive(ob) && !environment(ob)){ + write("You are whisked to the main start point."); + ob->eventMoveLiving(ROOM_START); + return 0; + } + if(member_array(ob, ejected_players) != -1) { + write("You have been ejected from the meeting room and may not return."); + return 0; + } + return ::CanReceive(ob); +} + +void init(){ + ::init(); +} + +object *AddEjected(object punk){ + if(member_array(punk, ejected_players) == -1){ + write(capitalize(punk->GetKeyName())+" has been added to the ejected list."); + ejected_players += ({ punk }); + } + else write(capitalize(punk->GetKeyName())+" is already on the ejected list."); + return ejected_players; +} + +object *GetEjected(){ + return ejected_players; +} + +object *RemoveEjected(object punk){ + if(member_array(punk, ejected_players) != -1){ + write(capitalize(punk->GetKeyName())+" has been removed from the ejected list."); + ejected_players -= ({ punk }); + } + else write(capitalize(punk->GetKeyName())+" is not on the ejected list."); + return ejected_players; +} + +string ReadSign(){ + string ret = "This is a special room for the orderly administration of meetings. It uses a special podium to manage speaking, and prevents the receipt of channel messages. It also prevents teleporting in under some circumstances. If you are attending a meeting here, please try to be polite and avoid being disruptive. You are here by choice, so if you're bored, feel free to leave quietly. Some useful commands in this room:\n"; + ret += "raise : indicates you wish to speak.\n"; + ret += "agenda : displays the current agenda.\n\n"; + ret += "Remember! Channels and some commands like \"call\" may "; + ret += "not work here!"; + return ret; +} + +int eventDestruct(){ + if( !(master()->valid_apply(({ "ASSIST" }))) ) + error("Illegal attempt to destroy object: "+get_stack()+" "+identify(previous_object(-1))); + else return ::eventDestruct(); +} diff --git a/lib/domains/campus/room/conf2.c b/lib/domains/campus/room/conf2.c new file mode 100644 index 0000000..36aff04 --- /dev/null +++ b/lib/domains/campus/room/conf2.c @@ -0,0 +1,124 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +int privacy, timer; +string ExtraDesc(); +static void create() { + string privs; + privs = query_privs(); + if( privs ) privs = capitalize(privs); + else privs = "a creator"; + room::create(); + SetClimate("indoors"); + SetAmbientLight(40); + SetShort("Conference Room"); + SetLong((: ExtraDesc :)); + SetExits( ([ + ]) ); + SetInventory(([ + "/domains/town/obj/bbucket" : 1, + "/domains/town/obj/chair" : 4, + "/domains/campus/obj/podium" : 1, + ])); + + SetProperties(([ + "no attack" : 1, + "nopeer" : 1, + ])); + privacy=0; + set_heart_beat(20); + timer = 0; + +} + +int AutoDeactivate(){ + message("info","%^RED%^The privacy field shuts off.%^RESET%^", this_object()); + timer = 0; + privacy = 0; + return 1; +} + +void init(){ + ::init(); + add_action("report_time","timer"); +} + +void heart_beat(){ + if(timer && (time() - timer ) > 1200) AutoDeactivate(); +} + +int report_time(){ + int secs = time() - timer; + + if(!timer){ + write("Privacy field is not active."); + return 1; + } + + write("Elapsed seconds: "+secs); + write("Elapsed minutes: "+(secs/60)); + return secs; +} + +int CanReceive(object ob) { + if(privacy){ + if(!interactive(ob)) { + message("info","\n\nPRIVACY WARNING: "+ob->GetName()+" has entered the room.\n\n",this_object() ); + } + else if(!archp(ob)){ + message("info","You bounce off the conference room privacy shield.", ob); + message("info",ob->GetName()+" bounced off the privacy shield.",this_object()); + if(!environment(ob)) ob->eventMoveLiving(ROOM_START); + return 0; + } + + } + return ::CanReceive(ob); +} + +int set_privacy(int i){ + if(environment(this_player()) != this_object() && !archp(this_player())) { + write("You lack the adequate privileges to do that."); + say(this_player()->GetName()+" is trying to mess around with the privacy shield system."); + return 1; + } + privacy=i; + timer = time(); + return 1; +} +/* + int privacy(string str){ + if(environment(this_player()) != this_object() && !archp(this_player())) { + write("You lack the adequate privileges to do that."); + say(this_player()->GetName()+" is trying to muck around with the privacy shield system."); + return 1; + } + + if(str=="on" || str == "1"){ + this_object()->set_privacy(1); + write("You enable the privacy shield.\n"); + say(this_player()->GetName()+" enables a privacy force field around the room."); + timer = time(); + return 1; + } + if(str=="off" || str == "0"){ + this_object()->set_privacy(0); + write("You disable the privacy shield.\n"); + say(this_player()->GetName()+" disables a privacy force field around the room."); + timer = 0; + return 1; + } + } + */ +int get_privacy(){ + return privacy; +} + +string ExtraDesc(){ + string extra = "%^YELLOW%^A privacy force field is active around this room.%^RESET%^"; + string desc = "This is an enchanted room, with the magical power to prevent uninvited people from entering. It is used for meetings where three or more people need to share information without interruption or privately. To enable privacy, 'privacy on'. To disable it, 'privacy off'. The privacy field automatically deactivates after approximately 20 minutes.\n"; + if(privacy) return desc+extra; + else return desc+"%^RED%^The privacy field is DISABLED."; +} diff --git a/lib/domains/campus/room/corridor.c b/lib/domains/campus/room/corridor.c new file mode 100644 index 0000000..d0701bb --- /dev/null +++ b/lib/domains/campus/room/corridor.c @@ -0,0 +1,30 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Corridor"); + SetLong("You are in an east-west corridor on the first floor of the Virtual Campus administrative building. There is a door south of here, leading into the Admissions office."); + SetItems( (["corridor" : "This is a carpeted corridor, leading west.", + "floor" : "The carpet is purple, and somewhat institutional.", + "carpet" : "The carpet is purple, and somewhat institutional."]) ); + SetExits( ([ + "south" : "/domains/campus/room/start", + "east" : "/domains/campus/room/corridor2", + "west" : "/domains/campus/room/corridor3", + ]) ); + SetProperty("no attack", 1); + SetDoor("south", "/domains/campus/doors/plain_door"); +} +int CanReceive(object ob) { + if(ob && ob->GetRace() == "rodent"){ + message("info","You are repelled by rodenticide.",ob); + return 0; + } + return ::CanReceive(ob); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/corridor2.c b/lib/domains/campus/room/corridor2.c new file mode 100644 index 0000000..ef87890 --- /dev/null +++ b/lib/domains/campus/room/corridor2.c @@ -0,0 +1,19 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetAmbientLight(30); + SetClimate("indoors"); + SetShort("Corridor, East"); + SetLong("You are in an east-west corridor on the first floor of the Virtual Campus administrative building. The student lounge is south of here."); + SetExits( ([ + "south" : "/domains/campus/room/lounge", + "west" : "/domains/campus/room/corridor", + "east" : "/domains/campus/room/corridor4", + ]) ); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/corridor3.c b/lib/domains/campus/room/corridor3.c new file mode 100644 index 0000000..6642605 --- /dev/null +++ b/lib/domains/campus/room/corridor3.c @@ -0,0 +1,31 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Corridor"); + SetLong("You are in an east-west corridor on the first floor of the Virtual Campus administrative building. The building's snack bar lies to the north, and a door to the south leads into a stairwell. A foyer and the building exit lie west of here."); + SetItems( (["corridor" : "This is a carpeted corridor, leading west.", + "floor" : "The carpet is purple, and somewhat institutional.", + "carpet" : "The carpet is purple, and somewhat institutional."]) ); + SetExits( ([ + "south" : "/domains/campus/room/stairwell", + "east" : "/domains/campus/room/corridor", + "west" : "/domains/campus/room/foyer", + "north" : "/domains/campus/room/snack.c", + ]) ); + SetDoor("south","/domains/campus/doors/top_stairs"); + SetProperty("no attack", 1); +} +int CanReceive(object ob){ + if(ob && ob->GetRace() == "rodent"){ + message("info","You are repelled by rodenticide.",ob); + return 0; + } + return ::CanReceive(ob); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/corridor4.c b/lib/domains/campus/room/corridor4.c new file mode 100644 index 0000000..3c91408 --- /dev/null +++ b/lib/domains/campus/room/corridor4.c @@ -0,0 +1,34 @@ +#include <lib.h> +#include ROOMS_H +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(40); + SetShort("Corridor"); + SetLong("You are in an east-west corridor on the first " + "floor of the Virtual Campus administrative building. " + "North is the campus bookstore, and there is a conference "+ + "room south of here."); + SetItems( (["corridor" : "This is a carpeted corridor, running east-west.", + "floor" : "The carpet is purple, and somewhat institutional.", + "carpet" : "The carpet is purple, and somewhat institutional."]) ); + SetExits( ([ + "south" : "/domains/campus/room/conf", + "north" : "/domains/campus/room/bookstore", + "west" : "/domains/campus/room/corridor2.c", + ]) ); + SetProperty("no attack", 1); +} +int CanReceive(object ob){ + if(ob && ob->GetRace() == "rodent"){ + message("info","You are repelled by rodenticide.",ob); + if(!environment(ob) && interactive(ob)) ob->eventMove(ROOM_START); + return 0; + } + return ::CanReceive(ob); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/crawlspace.c b/lib/domains/campus/room/crawlspace.c new file mode 100644 index 0000000..949a9bc --- /dev/null +++ b/lib/domains/campus/room/crawlspace.c @@ -0,0 +1,25 @@ +#include <lib.h> +inherit LIB_ROOM; +static void create() { + room::create(); + SetCoordinates("3999,4000,-2"); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("a tiny crawlspace"); + SetLong("You are in a cramped little space beneath the stairs in the "+ + "basement. It is dark, tight, and dirty in here."); + SetItems(([ + ({"crawlspace","space"}) : "You are in the space beneath stairs.", + "basement" : "The basement is just outside the crawlspace.", + "stairs" : "You're under them."])); + SetInventory(([ + "/domains/campus/obj/rayovac" : 1, + ])); + AddExit("out" , "/domains/campus/room/basement"); + SetObviousExits("out"); + SetProperty("no attack", 1); + SetMoney( ([ "dollars" : random(30)+2, ]) ); +} +void reset(){ + ::reset(); +} diff --git a/lib/domains/campus/room/crawlspace2.c b/lib/domains/campus/room/crawlspace2.c new file mode 100644 index 0000000..a585f07 --- /dev/null +++ b/lib/domains/campus/room/crawlspace2.c @@ -0,0 +1,22 @@ +#include <lib.h> +inherit LIB_ROOM; +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("a tiny crawlspace"); + SetLong("You are in a cramped little space beneath the stairs in the "+ + "basement. It is dark, tight, and dirty in here."); + SetItems(([ + ({"crawlspace","space"}) : "You are in the space beneath stairs.", + "basement" : "The basement is just outside the crawlspace.", + "stairs" : "You're under them."])); + SetExits( ([ + "out" : "/domains/campus/room/stairwell2d" + ]) ); + SetInventory(([ + ])); +} +void reset(){ + ::reset(); +} diff --git a/lib/domains/campus/room/death.c b/lib/domains/campus/room/death.c new file mode 100644 index 0000000..f0354b1 --- /dev/null +++ b/lib/domains/campus/room/death.c @@ -0,0 +1,73 @@ +#include <lib.h> +#include <dirs.h> +#include ROOMS_H + +inherit LIB_ROOM; + +string FunkyPic(); +int CheckChat(); +int StartHeart(object ob); + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("off the mortal coil"); + SetLong( (:FunkyPic:) ); + SetObviousExits("no exit"); + set_heart_beat(10); + SetNoModify(1); +} + +void init(){ + ::init(); + add_action("regenerate","regenerate"); + add_action("wander","wander"); + this_object()->CheckChat(); +} + +string FunkyPic(){ + return read_file("/domains/default/etc/death.txt"); +} + +int regenerate(){ + write("With a great rush of matter and energy, you rematerialize "+ + "into a corporeal state, and find yourself in a familiar place..."); + this_player()->eventRevive(); + this_player()->eventMoveLiving(ROOM_START); + return 1; +} + +int wander(){ + write("There is a strange, hollow vibration all around you, and you "+ + "realize that some force is compelling your ethereal form elsewhere..."+ + "you find yourself in a place that is known to you, yet oddly new."); + this_player()->eventMoveLiving(ROOM_START); + return 1; +} + +void heart_beat(){ + tell_room(this_object(), "A voice whispers: \" You may choose to "+ + "regenerate into a new body here.\""); + return; +} + + +int CanRelease(object ob){ + if(userp(ob) && ob->GetGhost() && environment(ob) == this_object()) { + tell_player(ob,"\n%^RED%^Your undead spirit is recalled and as you leave "+ + "the underworld a new body regenerates around you. "+ + "You live again!%^RESET%^\n"); + ob->eventRevive(); + } + return 1; +} + +int CanReceive(object ob){ + if(!living(ob)){ + return 0; + } + return ::CanReceive(ob); +} + + diff --git a/lib/domains/campus/room/foyer.c b/lib/domains/campus/room/foyer.c new file mode 100644 index 0000000..41560d6 --- /dev/null +++ b/lib/domains/campus/room/foyer.c @@ -0,0 +1,39 @@ +#include <lib.h> +inherit LIB_ROOM; + + +int readSign() { + this_player()->more("/domains/campus/txt/warning.txt"); + return 1; +} +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(40); + SetShort("Foyer"); + SetLong("This is the west end of the main hallway "+ + "in the Virtual Campus administrative building. The hallway "+ + "continues to the east of here. West is the building exit, to "+ + "the world outside.\n%^GREEN%^There is a large sign on the wall "+ + "you can read.%^RESET%^"); + SetExits( ([ + "west" : "/domains/campus/room/usquare", + "east" : "/domains/campus/room/corridor3" + ]) ); + SetItems( (["corridor" : "This is a carpeted corridor, leading west.", + "floor" : "The carpet is purple, and somewhat institutional.", + "sign":"A large sign on the wall. To read it, 'read sign'.", + "carpet" : "The carpet is purple, and somewhat institutional."]) ); + SetRead("sign", (: readSign :) ); + SetProperty("no attack", 1); +} +int CanReceive(object ob) { + if(ob && ob->GetRace() == "rodent"){ + message("info","You are repelled by rodenticide.",ob); + return 0; + } + return ::CanReceive(ob); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/freezer.c b/lib/domains/campus/room/freezer.c new file mode 100644 index 0000000..896cbbf --- /dev/null +++ b/lib/domains/campus/room/freezer.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetNoClean(1); + SetProperties(([ "login" : ROOM_START ])); + SetShort( "The freezer"); + SetLong( "The local freezer. Go down to leave."); + SetObviousExits("down"); + SetExits( ([ "down" : ROOM_START ]) ); + call_out("clean_room", MAX_NET_DEAD_TIME); + SetNoModify(1); +} + +static void clean_room(){ + object ob; + call_out((: clean_room :), MAX_NET_DEAD_TIME); + foreach(ob in filter(all_inventory(), (: living($1) :))){ + string name = last_string_element(base_name(ob),"/"); + if(!user_exists(name)) continue; + ob->eventDestruct(); + } +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/furnace.c b/lib/domains/campus/room/furnace.c new file mode 100644 index 0000000..240341a --- /dev/null +++ b/lib/domains/campus/room/furnace.c @@ -0,0 +1,10 @@ +#include <lib.h> + +inherit LIB_FURNACE; + +void create() { + furnace::create(); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/green_room.c b/lib/domains/campus/room/green_room.c new file mode 100644 index 0000000..63d234f --- /dev/null +++ b/lib/domains/campus/room/green_room.c @@ -0,0 +1,17 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("a green room"); + SetLong("This is a green room. Probability Lab 1 is south."); + SetExits( ([ + "south" : "/domains/campus/room/monty" + ]) ); + SetDoor("south","/domains/campus/doors/green_door"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/green_room2.c b/lib/domains/campus/room/green_room2.c new file mode 100644 index 0000000..8c05f25 --- /dev/null +++ b/lib/domains/campus/room/green_room2.c @@ -0,0 +1,17 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("a green room"); + SetLong("This is a green room. Probability Lab 2 is east."); + SetExits( ([ + "east" : "/domains/campus/room/plab2" + ]) ); + SetDoor("east","/domains/campus/doors/green_door2"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/green_room3.c b/lib/domains/campus/room/green_room3.c new file mode 100644 index 0000000..246dbeb --- /dev/null +++ b/lib/domains/campus/room/green_room3.c @@ -0,0 +1,17 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("a green room"); + SetLong("This is a green room. Probability Lab 3 is west."); + SetExits( ([ + "west" : "/domains/campus/room/plab" + ]) ); + SetDoor("west","/domains/campus/doors/green_door3"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/hazlab.c b/lib/domains/campus/room/hazlab.c new file mode 100644 index 0000000..73113b9 --- /dev/null +++ b/lib/domains/campus/room/hazlab.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("Hazardous Technologies Lab"); + SetLong("The University's research often yields mysterious, advanced, or alien artifacts which may pose a hazard to normal people. This laboratory is where such items are brought for analysis."); + SetInventory(([ + "/domains/campus/npc/turret" : 1, + "/domains/campus/obj/workbench" : 1, + "/domains/default/armor/pscoutsuit" : 1, + ])); + SetExits(([ + "north" : "/domains/campus/room/science2", + ])); + + SetClimate("indoors"); + SetProperty("nopeer",1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/klab.c b/lib/domains/campus/room/klab.c new file mode 100644 index 0000000..c48848d --- /dev/null +++ b/lib/domains/campus/room/klab.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("Keliner storage"); + SetLong("This is where Dr. Kleiner apparently keeps large "+ + "pieces of research equipment."); + SetClimate("indoors"); + SetItems( ([ + ]) ); + SetExits(([ + "west" : "/domains/campus/room/kleiner", + ])); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/kleiner.c b/lib/domains/campus/room/kleiner.c new file mode 100644 index 0000000..e678764 --- /dev/null +++ b/lib/domains/campus/room/kleiner.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("Dr. Kleiner's Office"); + SetLong("The place where Dr. Kleiner conducts administrative "+ + "business."); + SetClimate("indoors"); + SetItems( ([ + ]) ); + SetExits( ([ + "south" : "/domains/campus/room/science7", + "east" : "/domains/campus/room/klab.c", + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/lounge.c b/lib/domains/campus/room/lounge.c new file mode 100644 index 0000000..87bc4af --- /dev/null +++ b/lib/domains/campus/room/lounge.c @@ -0,0 +1,56 @@ +#include <lib.h> +inherit LIB_ROOM; + +void AddStuff(){ + object ob; + ob = new("/lib/bboard"); + ob->SetKeyName("chalkboard"); + ob->SetId( ({ "board", "chalkboard","bulletin board","visitor's board"})); + ob->set_board_id("visitor_board"); + ob->set_max_posts(30); + ob->SetShort("The Visitor's Board"); + ob->SetLong("This is the visitor's bulletin board. Students and visitors use it to "+ + "post messages, comments ans questions about LPC University to each other and "+ + "LPC University creators. Occasionally creators also post hints, suggestions and "+ + "clues. To post something, type: post <message name>. When "+ + "finished writing, enter a single period on a blank line, then at "+ + "the colon prompt (:) type a lower-case x and return. \n"); + ob->eventMove(this_object()); + ob->SetNoClean(0); +} +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(40); + SetShort("the student lounge"); + SetLong("This is the LPC University New Main building student lounge. "+ + "It is rather bare at the moment, as the building is still in early stages of "+ + "construction. You see some marks on the floor where furniture is to be "+ + "placed. The main corridor lies north, and a window overlooks the campus "+ + "on the south wall."); + SetItems(([ + ({"here","room","lounge"}) : "This seems to be intended to be a student "+ + "lounge.", + "building" : "You are in New Main, LPC University' main administrative building.", + ({"mark","marks"}) : "Some small chalkmarks and tape strips indicate "+ + "where furniture is to go.", + ({"floor","ground"}) : "Standard off-white linoleum tile floor, in case clumsy students "+ + "plan on eating in here.", + ({"corridor","hall"}) : "The main corridor on the first floor of New Main.", + "window" : "A window set into the south wall, overlooking the campus. Strangely, "+ + "there seems to be nothing outside the window...no campus, no light, no stars...nothing. "+ + "It's as though the administrative building were suspended in a vacuum.", + "campus" : "It seems oddly absent.", + ({"wall","south wall"}) : "A wall with a window in it."])); + SetExits( ([ + "north" : "/domains/campus/room/corridor2.c", + ]) ); + SetInventory(([ + "/domains/campus/obj/locker" : 1, + ])); + SetProperty("no attack", 1); + AddStuff(); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/mailroom.c b/lib/domains/campus/room/mailroom.c new file mode 100644 index 0000000..4250cf8 --- /dev/null +++ b/lib/domains/campus/room/mailroom.c @@ -0,0 +1,80 @@ +#include <lib.h> +#include <objects.h> +#include <post.h> +#include "/lib/include/post_office.h" + +inherit LIB_ROOM; + +static void create(){ + room::create(); + SetTown("campus"); + SetClimate("indoors"); + SetAmbientLight(40); + SetShort("the campus mail room"); + SetLong("This is a small office containing rows of mailboxes and "+ + "various other postal implements. There is a sign on the wall behind the "+ + "counter, outlining instructions for how to mail other users."); + SetItems( ([ + ({"box","boxes","mailboxes","mailbox"}) : "Rows of mailboxes for "+ + "the denizens of LPC University.", + "sign" : "This is a sign on the wall describing how to mail messages.", + ({"wall","walls"}) : "Gray-painted institutional walls of the kind you'd "+ + "expect in a post office.", + "implements" : "Ink, paper, etc.", + "instructions" : "Try reading them.", + "counter" : "A counter folks use to lean on while writing messages." ]) ); + SetExits( ([ + ]) ); + SetProperty("no attack", 1); +} +void init(){ + ::init(); + add_action("instr","read"); +} +int instr(string str){ + if(str=="instructions"||str=="sign"){ + write("To mail someone, type mail <person's name here>.\n"+ + "Enter a subject line.\n"+ + "Enter your message.\n"+ + "Once you've finished, enter a period (.) on a blank line.\n"+ + "Hit x, then s to send it. You're done!\n"); + return 1; + } +} +mixed CanMail(object who, string args) { + if( who && !interactive(who) ) return 0; + //Normally only people from this town should be able to + //do mail stuff here, but this is a newbie area, and + //it's a little too confusing to newcomers not to be able + //to send mail from a post office. + //if( GetTown() != who->GetTown() ) + // return "Any mail you might have will be at your home post office."; + return 1; +} +mixed eventMail(object who, string args) { + object ob; + + if( !(ob = new(OBJ_POST)) ) { + who->eventPrint("Failed to load postal object!"); + return 1; + } + if( !(ob->eventMove(who)) ) { + who->eventPrint("You can't seem to carry the postal object."); + return 1; + } + ob->start_post(args); + return 1; +} +int CanReceive(object ob) { + if( !ob || (living(ob) && !interactive(ob)) ) return 0; + else return room::CanReceive(ob); +} +int eventReleaseObject() { + object ob; + + if(!ob) return 0; + if( !(ob = previous_object()) ) return room::eventReleaseObject(); + if( !room::eventReleaseObject() ) return 0; + if( (ob = present(POSTAL_ID, ob)) ) ob->eventDestruct(); + return 1; +} diff --git a/lib/domains/campus/room/maintenance.c b/lib/domains/campus/room/maintenance.c new file mode 100644 index 0000000..cc82509 --- /dev/null +++ b/lib/domains/campus/room/maintenance.c @@ -0,0 +1,30 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(0); + SetShort("Maintenance room"); + SetLong("A room for access to service areas and to store " + "maintenance supplies."); + SetItems(([ + ])); + SetInventory(([ + "/domains/campus/obj/simple_chair" : 1, + "/domains/campus/obj/mtable" : 1, + "/domains/campus/obj/mlocker" : 1, + ])); + SetExits( ([ + "up" : "/domains/campus/room/access9", + "west" : "/domains/campus/room/sub_basement1.c", + ]) ); + SetEnters( ([ + ]) ); + SetDoor("up", "/domains/campus/doors/hatch"); + SetDoor("west", "/domains/campus/doors/plain_door2"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/medlab.c b/lib/domains/campus/room/medlab.c new file mode 100644 index 0000000..1978716 --- /dev/null +++ b/lib/domains/campus/room/medlab.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("Medical Research Lab"); + SetLong("Medical experiments occur here."); + SetClimate("indoors"); + SetProperty("nopeer",1); + SetItems( ([ + ({ "door","sliding door" }) : "A strange, metallic sliding door.", + ]) ); + SetExits( ([ + "north" : "/domains/campus/room/science5.c", + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/monty.c b/lib/domains/campus/room/monty.c new file mode 100644 index 0000000..d98f707 --- /dev/null +++ b/lib/domains/campus/room/monty.c @@ -0,0 +1,47 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Probability Lab 1"); + SetLong("This is a clean, antiseptic lab with " + "gleaming white walls. On the north wall are " + "three doors: " + "one %^RED%^red%^RESET%^, " + "one %^GREEN%^green%^RESET%^, " + "one %^BLUE%^blue%^RESET%^. " + "\n" + "%^GREEN%^There is a large sign on the wall you can read.%^RESET%^"); + SetInventory( ([ + "/domains/campus/obj/pedestal" : 1, + "/domains/campus/npc/charly" : 1 + ]) ); + SetItems( ([ + ({ "wall","walls","north wall"}) : "Shiny, white laboratory walls.", + "red room" : "There's no red room here.", + "green room" : "There's no green room here.", + "blue room" : "There's no blue room here.", + ]) ); + SetObviousExits("north"); + SetExits( ([ + "north" : "/domains/campus/room/wiz_lab", + ]) ); + AddItem( ({"sign","sign on the wall"}), "A sign you can read.",({"large"}) ); + + SetEnters( ([ + "red room" : "/domains/campus/room/red_room", + "green room" : "/domains/campus/room/green_room", + "blue room" : "/domains/campus/room/blue_room" + ]) ); + SetDoor("red room","/domains/campus/doors/red_door"); + SetDoor("green room","/domains/campus/doors/green_door"); + SetDoor("blue room","/domains/campus/doors/blue_door"); + SetNoClean(1); +} +void init(){ + ::init(); + SetRead(({"sign","sign on the wall"}), "Press the button on " + "the pedestal to reset the experiment.", "Common"); +} diff --git a/lib/domains/campus/room/npath.c b/lib/domains/campus/room/npath.c new file mode 100644 index 0000000..6f74bc1 --- /dev/null +++ b/lib/domains/campus/room/npath.c @@ -0,0 +1,29 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetShort("a wide path"); + SetLong("This is a paved path traveling north from University " + "Square. It is lined by thick bushes on each " + "side. The Virtual Campus is south of here. To " + "the north you see what appears to be a town."); + SetItems( ([ + ({ "bush","bushes","side","sides"}) : "Large, thick " + "bushes crowd the sides of the path.", + "path" : "A wide, cobblestone path running north " + "and south.", + "town" : "You can't quite see much of it from here." + ]) ); + //SetSkyDomain("town"); + + SetExits( ([ "south" : "/domains/campus/room/usquare", + "north" : "/domains/campus/room/npath2", + ]) ); + AddItem(new("/domains/campus/obj/lamp")); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/npath2.c b/lib/domains/campus/room/npath2.c new file mode 100644 index 0000000..6096c41 --- /dev/null +++ b/lib/domains/campus/room/npath2.c @@ -0,0 +1,32 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetShort("a wide path"); + SetLong("This is a paved path traveling north and south. It is lined by thick bushes on each side. A town lies north of here. To the south is what appears to be a college campus."); + SetItems( ([ + ({ "bush","bushes","side","sides"}) : "Large, thick " + "bushes crowd the sides of the path.", + "path" : "A wide, cobblestone path running north " + "and south.", + ({ "sign","post","signpost"}) : "A post has been " + "driven into the ground here, and a sign is attached " + "to it.", + "town" : "You can't quite see much of it from here.", + "campus" : "You can't quite see much of it from here." + ]) ); + //SetSkyDomain("town"); + SetInventory(([ + ])); + SetRead( "sign", "Beware! You are now leaving the safety of the Virtual Campus."); + SetExits( ([ "south" : "/domains/campus/room/npath", + "north" : "/domains/campus/room/south_road2", + ]) ); + AddItem(new("/domains/campus/obj/lamp")); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/plab.c b/lib/domains/campus/room/plab.c new file mode 100644 index 0000000..18b26d9 --- /dev/null +++ b/lib/domains/campus/room/plab.c @@ -0,0 +1,47 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Probability Lab Three"); + SetLong("This is a clean, antiseptic lab with " + "gleaming white walls. On the east wall are " + "three doors: " + "one %^RED%^red%^RESET%^, " + "one %^GREEN%^green%^RESET%^, " + "one %^BLUE%^blue%^RESET%^. " + "\n" + "%^GREEN%^There is a large sign on the wall you can read.%^RESET%^"); + SetItems( ([ + ({ "wall","walls","north wall"}) : "Shiny, white laboratory walls.", + "red room" : "There's no red room here.", + "green room" : "There's no green room here.", + "blue room" : "There's no blue room here.", + ]) ); + SetObviousExits("west"); + SetInventory(([ + "/domains/campus/obj/pedestal3" : 1, + ])); + SetExits(([ + "west" : "/domains/campus/room/wiz_lab", + ])); + + AddItem( ({"sign","sign on the wall"}), "A sign you can read.",({"large"}) ); + + SetEnters( ([ + "red room" : "/domains/campus/room/red_room3", + "green room" : "/domains/campus/room/green_room3", + "blue room" : "/domains/campus/room/blue_room3" + ]) ); + SetDoor("red room","/domains/campus/doors/red_door3"); + SetDoor("green room","/domains/campus/doors/green_door3"); + SetDoor("blue room","/domains/campus/doors/blue_door3"); + SetNoClean(1); +} +void init(){ + ::init(); + SetRead(({"sign","sign on the wall"}), "Press the button on " + "the pedestal to reset the experiment."); +} diff --git a/lib/domains/campus/room/plab2.c b/lib/domains/campus/room/plab2.c new file mode 100644 index 0000000..89da5b2 --- /dev/null +++ b/lib/domains/campus/room/plab2.c @@ -0,0 +1,46 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Probability Lab 2"); + SetLong("This is a clean, antiseptic lab with " + "gleaming white walls. On the west wall are " + "three doors: " + "one %^RED%^red%^RESET%^, " + "one %^GREEN%^green%^RESET%^, " + "one %^BLUE%^blue%^RESET%^. " + "\n" + "%^GREEN%^There is a large sign on the wall you can read.%^RESET%^"); + SetItems( ([ + ({ "wall","walls","north wall"}) : "Shiny, white laboratory walls.", + "red room" : "There's no red room here.", + "green room" : "There's no green room here.", + "blue room" : "There's no blue room here.", + ]) ); + SetExits( ([ + "northeast" : "/domains/campus/room/wiz_lab", + ]) ); + SetInventory(([ + "/domains/campus/npc/charles" : 1, + "/domains/campus/obj/pedestal2" : 1, + ])); + AddItem( ({"sign","sign on the wall"}), "A sign you can read.",({"large"}) ); + + SetEnters( ([ + "red room" : "/domains/campus/room/red_room2", + "green room" : "/domains/campus/room/green_room2", + "blue room" : "/domains/campus/room/blue_room2" + ]) ); + SetDoor("red room","/domains/campus/doors/red_door2"); + SetDoor("green room","/domains/campus/doors/green_door2"); + SetDoor("blue room","/domains/campus/doors/blue_door2"); + SetNoClean(1); +} +void init(){ + ::init(); + SetRead(({"sign","sign on the wall"}), "Press the button on " + "the pedestal to reset the experiment."); +} diff --git a/lib/domains/campus/room/red_room.c b/lib/domains/campus/room/red_room.c new file mode 100644 index 0000000..e8e165b --- /dev/null +++ b/lib/domains/campus/room/red_room.c @@ -0,0 +1,17 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("a red room"); + SetLong("This is a red room. Probability Lab 1 is south."); + SetExits( ([ + "south" : "/domains/campus/room/monty" + ]) ); + SetDoor("south","/domains/campus/doors/red_door"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/red_room2.c b/lib/domains/campus/room/red_room2.c new file mode 100644 index 0000000..0542a39 --- /dev/null +++ b/lib/domains/campus/room/red_room2.c @@ -0,0 +1,17 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("a red room"); + SetLong("This is a red room. Probability Lab 2 is east."); + SetExits( ([ + "east" : "/domains/campus/room/plab2" + ]) ); + SetDoor("east","/domains/campus/doors/red_door2"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/red_room3.c b/lib/domains/campus/room/red_room3.c new file mode 100644 index 0000000..482a062 --- /dev/null +++ b/lib/domains/campus/room/red_room3.c @@ -0,0 +1,17 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("a red room"); + SetLong("This is a red room. Probability Lab 3 is west."); + SetExits( ([ + "west" : "/domains/campus/room/plab" + ]) ); + SetDoor("west","/domains/campus/doors/red_door3"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/science1.c b/lib/domains/campus/room/science1.c new file mode 100644 index 0000000..fb2ae7c --- /dev/null +++ b/lib/domains/campus/room/science1.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("Science Building Hallway"); + SetLong("This is the LPC University Science Building, where exciting new systems and abstract research happens. South of here is the probability laboratory. The hallway continues west. The building's exit is north, leading to University Square."); + SetExits( ([ + "north" : "/domains/campus/room/usquare", + "south" : "/domains/campus/room/wiz_lab", + "west" : "/domains/campus/room/science2", + ]) ); + SetClimate("indoors"); + + SetDoor("south", "/domains/campus/doors/prob_door.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/science2.c b/lib/domains/campus/room/science2.c new file mode 100644 index 0000000..54d0d28 --- /dev/null +++ b/lib/domains/campus/room/science2.c @@ -0,0 +1,39 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +int PreExit(mixed args...){ + object who = this_player(); + write("You are scanned by a beam of light from the sliding door."); + say(who->GetName()+" is scanned by a beam of light from the sliding door."); + if(!present_file("/domains/campus/armor/badge2",who)){ + write("The door does not open."); + return 0; + } + else { + write("The door opens, letting you through.\n"); + say("The door lets "+who->GetName()+" through.\n"); + return 1; + } +} + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("Science Building Hallway"); + SetLong("This is the main hallway in the LPC University Science Building. The hallway runs east and west from here. To the south is a sliding door. North of here is the stargate laboratory."); + SetClimate("indoors"); + SetItems( ([ + ({ "door","sliding door" }) : "A strange, metallic sliding door.", + ]) ); + SetExits( ([ + "north" : "/domains/campus/room/slab", + "east" : "/domains/campus/room/science1", + "west" : "/domains/campus/room/science3.c", + ]) ); + AddExit("south", "/domains/campus/room/hazlab", (: PreExit :)); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/science3.c b/lib/domains/campus/room/science3.c new file mode 100644 index 0000000..58e89a0 --- /dev/null +++ b/lib/domains/campus/room/science3.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("Science Building Hallway, West"); + SetLong("This is the western end of the main hallway in the LPC University Science Building. The main hallway runs east from here, toward the building's exit. Another hallway runs south from here."); + SetClimate("indoors"); + SetItems( ([ + ]) ); + SetExits( ([ + "east" : "/domains/campus/room/science2", + "south" : "/domains/campus/room/science4.c", + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/science4.c b/lib/domains/campus/room/science4.c new file mode 100644 index 0000000..0479eb6 --- /dev/null +++ b/lib/domains/campus/room/science4.c @@ -0,0 +1,20 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("hallway bend"); + SetLong("This is a bend in the hallway. The main Science Building hallway is north of here. A smaller hallway runs west from here."); + SetClimate("indoors"); + SetExits( ([ + "west" : "/domains/campus/room/science5", + "north" : "/domains/campus/room/science3.c", + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/science5.c b/lib/domains/campus/room/science5.c new file mode 100644 index 0000000..021d1c1 --- /dev/null +++ b/lib/domains/campus/room/science5.c @@ -0,0 +1,39 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +int PreExit(mixed args...){ + object who = this_player(); + write("You are scanned by a beam of light from the sliding door."); + say(who->GetName()+" is scanned by a beam of light from the sliding door."); + if(!present_file("/domains/campus/armor/badge2",who)){ + write("The door does not open."); + return 0; + } + else { + write("The door opens, letting you through.\n"); + say("The door lets "+who->GetName()+" through.\n"); + return 1; + } +} + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("Secondary Science Hallway East"); + SetLong("This is the secondary hallway in the LPC University Science Building. The hallway runs east and west from here. To the south is a sliding door. North of here is a classroom."); + SetClimate("indoors"); + SetItems( ([ + ({ "door","sliding door" }) : "A strange, metallic sliding door.", + ]) ); + SetExits( ([ + "north" : "/domains/campus/room/classroom1", + "east" : "/domains/campus/room/science4", + "west" : "/domains/campus/room/science6", + ]) ); + AddExit("south", "/domains/campus/room/medlab", (: PreExit :)); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/science6.c b/lib/domains/campus/room/science6.c new file mode 100644 index 0000000..d9e496a --- /dev/null +++ b/lib/domains/campus/room/science6.c @@ -0,0 +1,41 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +int PreExit(mixed args...){ + object who = this_player(); + write("You are scanned by a beam of light from the sliding door."); + say(who->GetName()+" is scanned by a beam of light from the sliding door."); + if(!present_file("/domains/campus/armor/badge2",who)){ + write("The door does not open."); + return 0; + } + else { + write("The door opens, letting you through.\n"); + say("The door lets "+who->GetName()+" through.\n"); + return 1; + } +} + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("Secondary Science Hallway West"); + SetLong("This is the secondary hallway in the LPC University Science Building. The hallway runs east from here. To the north is a sliding door. To the west is an elevator door."); + SetClimate("indoors"); + SetItems( ([ + ({ "door","sliding door" }) : "A strange, metallic sliding door.", + ]) ); + SetExits( ([ + "south" : "/domains/campus/room/stairwell2a", + "east" : "/domains/campus/room/science5", + "west" : "/domains/campus/room/shaft1.c", + ]) ); + AddExit("north", "/domains/campus/room/weaplab", (: PreExit :)); + SetDoor("west", "/domains/campus/doors/eledoor1"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/science7.c b/lib/domains/campus/room/science7.c new file mode 100644 index 0000000..03ec3e1 --- /dev/null +++ b/lib/domains/campus/room/science7.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("Science building, second floor"); + SetLong("This is the second floor of the LPC University Science Building. To the west is an elevator door."); + SetClimate("indoors"); + SetExits( ([ + "north" : "/domains/campus/room/kleiner", + "south" : "/domains/campus/room/stairwell2b", + "west" : "/domains/campus/room/shaft2.c", + ]) ); + SetDoor("west", "/domains/campus/doors/eledoor2"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/sewer.c b/lib/domains/campus/room/sewer.c new file mode 100644 index 0000000..e3c9671 --- /dev/null +++ b/lib/domains/campus/room/sewer.c @@ -0,0 +1,76 @@ +#include <lib.h> +#include <damage_types.h> + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(10); + SetShort("sewer"); + SetLong("You are in the stinking underground tunnels of "+ + "a sewer system. The air here is quite foul, "+ + "and periodic blasts of steam from wall-mounted vents make it "+ + "very hot and very humid. There is a foot-high stream of dark liquid "+ + "covering the bottom of this tunnel, running east to west along "+ + "the tunnel's length. The tunnel narrows dramatically here, and "+ + "becomes so small that further movement west is not possible."); + SetItems( ([ ({"tunnel","tunnels"}) : "Here the tunnel becomes so "+ + "narrow that you can't go any further west. It looks like "+ + "some debris has accumulated here over time, almost "+ + "clogging the waste flow.", + ({"sewer","sewer system"}) : "Though evidently in good repair "+ + "and of modern construction, this is still a sewer tunnel, "+ + "and it's hostile to human comfort.", + ({"steam","vent","vents","wall-mounted vents"}): "Apparently "+ + "there is industrial machinery nearby that exhausts hot steam "+ + "through vents in the walls.", + "air" : "It is rank with the reek of decomposing waste.", + ({"wall","walls"}) : "The walls of the sewer tunnel are made "+ + "of concrete and appear well-built and sturdy.", + ({"stream","liquid","stream of liquid","dark liquid"}) : "Whatever "+ + "this stuff is, water is not its main component. It's some kind "+ + "of foul-smelling liquid waste, flowing along the bottom "+ + "of the tunnel.", + ({"sewage","waste","garbage"}) : "It appears that the fluid on the "+ + "bottom of this tunnel is the result of garbage and waste "+ + "processing. In liquid form, this garbage flows in here "+ + "from the east.", + ]) ); + SetSmell( ([ "default" : "The stench of sewage and waste hangs here."]) ); + SetListen("default","You hear faint echoes of dripping water."); + SetExits( ([ "east" : "/domains/campus/room/sewer1.c" + ]) ); + SetInventory(([ + "/domains/campus/obj/debris" :1 + ])); + set_heart_beat(10); + SetFlyRoom("/domains/campus/room/access0"); +} + +void init(){ + ::init(); +} + +int SteamBlast(){ + object *temparr,*stuff,*lstuff; + int i; + stuff=all_inventory(); + lstuff = ({}); + for(i=0;i<sizeof(stuff);i++){ + temparr= ({ stuff[i] }); + if(living(stuff[i]) && !sizeof(lstuff)) lstuff = ({stuff[i]}); + if(living(stuff[i]) && sizeof(lstuff) > 0 && member_array(stuff[i],lstuff) == -1) lstuff += ({stuff[i]}); + } + for(i=0;i<sizeof(lstuff);i++){ + if(sizeof(lstuff) > 0 && !creatorp(lstuff[i]) ) + lstuff[i]->eventReceiveDamage(HEAT, 7,random(30)+10, "torso"); + + } + tell_room(this_object(), "You are hit by a blast of scalding-hot steam!"); + return 1; +} +void heart_beat(){ + if(random(10) == 1) SteamBlast(); + return; +} diff --git a/lib/domains/campus/room/sewer1.c b/lib/domains/campus/room/sewer1.c new file mode 100644 index 0000000..8a3b04a --- /dev/null +++ b/lib/domains/campus/room/sewer1.c @@ -0,0 +1,68 @@ +#include <lib.h> +#include <damage_types.h> + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(10); + SetShort("sewer"); + SetLong("You are in the stinking underground tunnels of "+ + "a sewer system. The air here is quite foul, "+ + "and periodic blasts of steam from wall-mounted vents make it "+ + "very hot and very humid. There is a foot-high stream of dark liquid "+ + "covering the bottom of this tunnel, running east to west along "+ + "the tunnel's length."); + SetItems( ([ ({"tunnel","tunnels"}) : "You are in a sewer tunnel."+ + "It's foul, dark, and hot.", + ({"sewer","sewer system"}) : "Though evidently in good repair "+ + "and of modern construction, this is still a sewer tunnel, "+ + "and it's hostile to human comfort.", + ({"steam","vent","vents","wall-mounted vents"}): "Apparently "+ + "there is industrial machinery nearby that exhausts hot steam "+ + "through vents in the walls.", + "air" : "It is rank with the reek of decomposing waste.", + ({"wall","walls"}) : "The walls of the sewer tunnel are made "+ + "of concrete and appear well-built and sturdy.", + ({"stream","liquid","stream of liquid","dark liquid"}) : "Whatever "+ + "this stuff is, water is not its main component. It's some kind "+ + "of foul-smelling liquid waste, flowing along the bottom "+ + "of the tunnel.", + ({"sewage","waste","garbage"}) : "It appears that the fluid on the "+ + "bottom of this tunnel is the result of garbage and waste "+ + "processing. In liquid form, this garbage flows "+ + "west from here.", + ]) ); + SetSmell( ([ "default" : "The stench of sewage and waste hangs here."]) ); + SetListen("default","You hear faint echoes of dripping water."); + SetExits( ([ "west" : "/domains/campus/room/sewer.c", + "east" : "/domains/campus/room/sewer2.c" + ]) ); + set_heart_beat(10); +} +int SteamBlast(){ + object *temparr,*stuff,*lstuff; + int i; + stuff=all_inventory(); + lstuff = ({}); + for(i=0;i<sizeof(stuff);i++){ + temparr= ({ stuff[i] }); + if(living(stuff[i]) && !sizeof(lstuff)) lstuff = ({stuff[i]}); + if(living(stuff[i]) && sizeof(lstuff) > 0 && member_array(stuff[i],lstuff) == -1) lstuff += ({stuff[i]}); + } + for(i=0;i<sizeof(lstuff);i++){ + if(sizeof(lstuff) > 0 && !creatorp(lstuff[i]) ) + lstuff[i]->eventReceiveDamage(HEAT, 7,random(30)+10, "torso"); + + } + tell_room(this_object(), "You are hit by a blast of scalding-hot steam!"); + return 1; +} +void heart_beat(){ + if(random(10) == 1) SteamBlast(); + return; +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/sewer2.c b/lib/domains/campus/room/sewer2.c new file mode 100644 index 0000000..5eb2039 --- /dev/null +++ b/lib/domains/campus/room/sewer2.c @@ -0,0 +1,71 @@ +#include <lib.h> +#include <damage_types.h> + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetAmbientLight(20); + SetShort("sewer"); + SetLong("You are in the stinking underground tunnels of "+ + "a sewer system. The air here is quite foul, "+ + "and periodic blasts of steam from wall-mounted vents make it "+ + "very hot and very humid. There is a foot-high stream of dark liquid "+ + "covering the bottom of this tunnel, running east to west along "+ + "the tunnel's length. Light streams in from a drainage grate above."); + SetItems( ([ ({"tunnel","tunnels"}) : "You are in a sewer tunnel."+ + "It's foul, dark, and hot.", + ({"sewer","sewer system"}) : "Though evidently in good repair "+ + "and of modern construction, this is still a sewer tunnel, "+ + "and it's hostile to human comfort.", + ({"steam","vent","vents","wall-mounted vents"}): "Apparently "+ + "there is industrial machinery nearby that exhausts hot steam "+ + "through vents in the walls.", + "air" : "It is rank with the reek of decomposing waste.", + ({"wall","walls"}) : "The walls of the sewer tunnel are made "+ + "of concrete and appear well-built and sturdy.", + ({"stream","liquid","stream of liquid","dark liquid"}) : "Whatever "+ + "this stuff is, water is not its main component. It's some kind "+ + "of foul-smelling liquid waste, flowing along the bottom "+ + "of the tunnel.", + "light" : "There isn't much of it, and you can't tell if it's " + + "sunshine or lamplight, but it lets you see a bit better.", + ({"sewage","waste","garbage"}) : "It appears that the fluid on the "+ + "bottom of this tunnel is the result of garbage and waste "+ + "processing. In liquid form, this garbage flows "+ + "west from here.", + ]) ); + SetExits( ([ + "west" : "/domains/campus/room/sewer1", + "up" : "/domains/campus/room/sewer3.c", + ]) ); + SetSmell( ([ "default" : "The stench of sewage and waste hangs here."]) ); + SetListen("default","You hear faint echoes of dripping water."); + + set_heart_beat(10); +} +int SteamBlast(){ + object *temparr,*stuff,*lstuff; + int i; + stuff=all_inventory(); + lstuff = ({}); + for(i=0;i<sizeof(stuff);i++){ + temparr= ({ stuff[i] }); + if(living(stuff[i]) && !sizeof(lstuff)) lstuff = ({stuff[i]}); + if(living(stuff[i]) && sizeof(lstuff) > 0 && member_array(stuff[i],lstuff) == -1) lstuff += ({stuff[i]}); + } + for(i=0;i<sizeof(lstuff);i++){ + if(sizeof(lstuff) > 0 && !creatorp(lstuff[i]) ) + lstuff[i]->eventReceiveDamage("steam",HEAT,random(30)+10,0,"torso"); + + } + tell_room(this_object(), "You are hit by a blast of scalding-hot steam!"); + return 1; +} +void heart_beat(){ + if(random(10) == 1) SteamBlast(); + return; +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/sewer3.c b/lib/domains/campus/room/sewer3.c new file mode 100644 index 0000000..f5e480b --- /dev/null +++ b/lib/domains/campus/room/sewer3.c @@ -0,0 +1,35 @@ +#include <lib.h> +#include <damage_types.h> + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(20); + SetShort("service tube"); + SetLong("This is a narrow area that allows travel between the "+ + "surface above and the sewer below. It's cramped, dirty, and "+ + "not a friendly place for most humanoids. Some light seems to "+ + "be coming in from a drainage grate above."); + SetItems( ([ ({"tube","service tube"}) : "You are in a service tube."+ + " It's foul, dark, and hot.", + ({"sewer","sewer system"}) : "Though evidently in good repair "+ + "and of modern construction, this is still a sewer tunnel, "+ + "and it's hostile to human comfort.", + "air" : "It is rank with the reek of decomposing waste.", + "light" : "There isn't much of it, and you can't tell if it's " + + "sunshine or lamplight, but it lets you see a bit better.", + ]) ); + SetExits(([ + "down" : "/domains/campus/room/sewer2", + "up" : "/domains/campus/room/south_road2", + ])); + SetSmell( ([ "default" : "The stench of sewage and waste hangs here."]) ); + SetListen("default","You hear faint echoes of dripping water."); + SetDoor("up","/domains/campus/doors/grate"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/shaft0.c b/lib/domains/campus/room/shaft0.c new file mode 100644 index 0000000..e2dfd2a --- /dev/null +++ b/lib/domains/campus/room/shaft0.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <medium.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(10); + SetShort("Elevator Shaft"); + SetLong("Elevator Shaft."); + SetClimate("indoors"); + SetItems( ([ + ]) ); + SetExits( ([ + "east" : "/domains/campus/room/basement3.c", + ]) ); + SetDoor("east","/domains/campus/doors/steel_door3"); + SetFlyRoom("/domains/campus/room/shaft1"); + SetSinkRoom("/domains/campus/room/shaftb"); + SetMedium(MEDIUM_AIR); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/shaft1.c b/lib/domains/campus/room/shaft1.c new file mode 100644 index 0000000..bf67fc2 --- /dev/null +++ b/lib/domains/campus/room/shaft1.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <medium.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(10); + SetShort("Elevator shaft"); + SetLong("Elevator shaft, first floor"); + SetClimate("indoors"); + SetItems( ([ + ]) ); + SetExits( ([ + "east" : "/domains/campus/room/science6", + ]) ); + SetDoor("east", "/domains/campus/doors/eledoor1"); + SetFlyRoom("/domains/campus/room/shaft2"); + SetSinkRoom("/domains/campus/room/shaft0"); + SetMedium(MEDIUM_AIR); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/shaft2.c b/lib/domains/campus/room/shaft2.c new file mode 100644 index 0000000..66af30f --- /dev/null +++ b/lib/domains/campus/room/shaft2.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <medium.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(10); + SetShort("elevator shaft"); + SetLong("Elevator Shaft."); + SetClimate("indoors"); + SetItems( ([ + ]) ); + SetExits( ([ + "east" : "/domains/campus/room/science7", + ]) ); + SetSinkRoom("/domains/campus/room/shaft1"); + SetDoor("east", "/domains/campus/doors/eledoor2"); + SetMedium(MEDIUM_AIR); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/shaftb.c b/lib/domains/campus/room/shaftb.c new file mode 100644 index 0000000..6cd9e71 --- /dev/null +++ b/lib/domains/campus/room/shaftb.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(10); + SetShort("Elevator Shaft"); + SetLong("Elevator shaft, basement"); + SetClimate("indoors"); + SetItems( ([ + ]) ); + SetExits( ([ + "east" : "/domains/campus/room/sub_basement2.c", + ]) ); + SetFlyRoom("/domains/campus/room/shaft0"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/slab.c b/lib/domains/campus/room/slab.c new file mode 100644 index 0000000..5c52293 --- /dev/null +++ b/lib/domains/campus/room/slab.c @@ -0,0 +1,49 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_ROOM; + +int SignRead(){ + string list; + list = implode(keys(STARGATE_D->GetStargates()),", "); + write("These are Stargate operation instructions."); + write("The Dead Souls stargate system provides teleportation within " + "the stargate network. To use the stargate network, one finds an " + "idle stargate, then dials the name of some other known stargate. " + "One then enters the outbound stargate, and if things go well, teleportation " + "to the dialed stargate occurs. To travel to Uruk, if that were a " + "valid stargate name, you would: dial uruk\n" + "Once the stargate activates: enter stargate"); + write("Currently available stargates are:"); + write("%^BOLD%^%^YELLOW%^"+list+"%^RESET%^"); + return 1; +} + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Science Building Stargate Lab"); + SetLong("This large room is the testing ground for the newly discovered stargate technology that allows for instant teleportation between distant locations. The main Science Building hallway is south.\n" + "%^BOLD%^%^GREEN%^An instruction sign is here.%^RESET%^"); + SetItems(([ + ({ "sign", "instruction sign", "instructions sign", "instruction", "instructions" }) : "A sign you can read. It appears to be instructions for operating the stargate.", + ])); + SetInventory(([ + "/domains/campus/obj/stargate" : 1, + "/domains/campus/npc/kleiner" : 1, + ])); + SetExits(([ + "south" : "/domains/campus/room/science2", + ])); + SetRead("sign", (: SignRead() :) ); +} +int CanReceive(object ob) { + if(!ob) return 0; + return room::CanReceive(ob); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/snack.c b/lib/domains/campus/room/snack.c new file mode 100644 index 0000000..5e5deb2 --- /dev/null +++ b/lib/domains/campus/room/snack.c @@ -0,0 +1,56 @@ +#include <lib.h> +#include <dirs.h> +#include <message_class.h> +inherit LIB_ROOM; + +int eventReadMenu(string str); +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(40); + SetShort("The Campus Snack Bar"); + SetLong("You are in a small, linoleum-tiled room lit by bright "+ + "fluorescent lights. There are a few uncomfortable-looking chairs "+ + "around two tables, and a sort of bar set into the north wall, "+ + "behind which a food service employee stands. There is a menu "+ + "hanging on the wall next to the bar. The main hallway lies south of here."); + SetItems(([ + "menu": "A menu of snack items available here.", + "sign":"A sign over the snack bar.", + ({"tile","tiles","floor","linoleum"}):"These are here because you "+ + "are not trusted to keep food off of carpets.", + ({"chair","chairs","table","table"}):"Token furniture, not very functional "+ + "or comfortable-looking. You aren't really expected to hang "+ + "around in here, apparently.", + "bar" : "Really a window set into the wall and connecting the snack bar "+ + "to the adjoining kitchen.", + ({"wall","walls"}) : "The walls are painted blue and white, the school's colors. "+ + "It's fairly unattractive and institutional.", + "hallway" : "The administration building's main hallway lies south.", + ({"light","lights","fluorescent lights","fluorescents"}) : "Cheap, standard "+ + "lighting. Like all fluorescents, these lights give everything an unappealing, "+ + "sickly look.", + "employee" : "An underpaid, unappreciated, and resentful state employee. "+ + "No surprise there.", + ])); + SetExits( ([ + "south" : "/domains/campus/room/corridor3.c", + ]) ); + SetRead("menu", (: eventReadMenu :)); + SetInventory(([ + "/domains/campus/npc/gloria.c" : ({60, 1}) ])); + SetProperty("no attack", 1); +} +int eventReadMenu(string str){ + write("\n"+ + "1) ham sandwich: 2 dollars\n"+ + "2) hamburger: 4 dollars\n"+ + "3) salad of the day: 3 dollars\n\n"+ + "Drinks:\n"+ + "1) milk: 1 dollar\n"+ + "2) gatorade: 2 dollars\n"); + return 1; +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/south_road2.c b/lib/domains/campus/room/south_road2.c new file mode 100644 index 0000000..4cc986b --- /dev/null +++ b/lib/domains/campus/room/south_road2.c @@ -0,0 +1,42 @@ +#include <terrain_types.h> +#include <lib.h> +inherit LIB_ROOM; + +int readSign() { + this_player()->more("/domains/town/txt/warning_sign.txt"); + return 1; +} +static void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetObviousExits("north, south"); + SetShort("South Old Saquivor Road"); + SetLong("This is a cobblestone road, leading south to some sort of University campus."); + SetItems( ([ + ({"road","cobblestone road"}) : "A " + "cobblestone road, south.", + //"sign":"A large sign on the road. To read it, 'read sign'.", + ({"grate","drainage grate","sewer","sewer grate"}) : "A grate that "+ + "seems to lead into sewers. It can't be opened from here.", + ]) ); + //SetSkyDomain("town"); + AddTerrainType(T_ROAD); + SetExits( ([ + "south" : "/domains/campus/room/npath2.c", + ]) ); + if(file_exists("/domains/campus/doors/grate.c")){ + AddExit("down", "/domains/campus/room/sewer3"); + SetDoor("down","/domains/campus/doors/grate"); + } + if(strsrch(mud_name(), "Dead Souls")){ + //AddExit("north", "/domains/town/room/south_road1"); + } + SetInventory(([ + ])); + //SetRead("sign", (: readSign :) ); + //AddItem(new("/domains/town/obj/lamp")); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/stairwell.c b/lib/domains/campus/room/stairwell.c new file mode 100644 index 0000000..8ba39c5 --- /dev/null +++ b/lib/domains/campus/room/stairwell.c @@ -0,0 +1,51 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(20); + SetShort("stairwell"); + SetLong("You are standing on a stairwell landing. Flights of stairs "+ + "lead up and down, although the stairs up are roped off to prevent "+ + "passage. The flickering fluorescent lights make it difficult to see what "+ + "lies below here. There is a sign tied to the rope on the flight of stairs "+ + "going up."); + SetItems(([ + ({"stairs","flight","flight of stairs"}) : "The stairs are made of concrete, appear to "+ + "be part of the foundation of the building, and seem quite sturdy.", + "landing" : "This is a landing between flights of stairs leading up and down.", + "rope" : "Thick yellow construction rope. There's a lot of it tied to the " + + "flight of stairs leading up, preventing your passage. There's a sign hanging "+ + "on it.", + ({"light","lights","fluorescent lights"}) : "Cheap lighting that doesn't seem to work "+ + "very well. Occasionally the landing is lit orange, then white again by the flickering "+ + "lights.", + "sign" : "This is a handwritten, cardboard sign hanging on the roped-off stairs."])); + SetExits(([ + "north" : "/domains/campus/room/corridor3", + "down" : "/domains/campus/room/basement" + ])); + SetDoor("north","/domains/campus/doors/top_stairs"); + SetProperty("no attack", 1); +} +void init(){ + ::init(); + add_action("r_sign","read"); + add_action("untie_r","untie"); +} +int r_sign(string str){ + if(str=="sign" || str=="cardboard sign"){ + write("The sign reads:\n"+ + "WARNING! Second floor under construction, all access prohibited!\n"); + say(this_player()->GetName()+" read the sign.\n"); + return 1; + } +} +int untie_r(string str){ + if(str=="rope" || str=="yellow rope"){ + write("The rope is quite firmly tied. You fail.\n"); + say(this_player()->GetName()+" fails to untie the rope.\n"); + return 1; + } +} diff --git a/lib/domains/campus/room/stairwell2a.c b/lib/domains/campus/room/stairwell2a.c new file mode 100644 index 0000000..8d2e9d9 --- /dev/null +++ b/lib/domains/campus/room/stairwell2a.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("Science Building Stairwell, First floor"); + SetLong("This is the first floor stairwell of the University Science Building."); + SetClimate("indoors"); + SetItems( ([ + ]) ); + SetExits( ([ + "north" : "/domains/campus/room/science6", + "west" : "/domains/campus/room/alcove1", + "up" : "/domains/campus/room/stairwell2b", + "down" : "/domains/campus/room/stairwell2c.c", + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/stairwell2b.c b/lib/domains/campus/room/stairwell2b.c new file mode 100644 index 0000000..742ae31 --- /dev/null +++ b/lib/domains/campus/room/stairwell2b.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("Science Building Stairwell, second floor"); + SetLong("This is the second floor stairwell of the University Science Building."); + SetClimate("indoors"); + SetItems( ([ + ]) ); + SetExits( ([ + "down" : "/domains/campus/room/stairwell2a", + "north" : "/domains/campus/room/science7.c", + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/stairwell2c.c b/lib/domains/campus/room/stairwell2c.c new file mode 100644 index 0000000..89b9352 --- /dev/null +++ b/lib/domains/campus/room/stairwell2c.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("Science Building Stairwell"); + SetLong("This is the stairwell of the University Science Building."); + SetClimate("indoors"); + SetItems( ([ + ]) ); + SetExits( ([ + "up" : "/domains/campus/room/stairwell2a", + "down" : "/domains/campus/room/stairwell2d.c", + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/stairwell2d.c b/lib/domains/campus/room/stairwell2d.c new file mode 100644 index 0000000..9ee0ef6 --- /dev/null +++ b/lib/domains/campus/room/stairwell2d.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("Science Building Stairwell, bottom"); + SetLong("This is the bottom of the stairwell of the university Science building. The stairs go up from here. There is a crawlspace here under the stairs. The sub basement is north."); + SetItems(([ + ({ "stairs", "stair" }) : "Steps which lead up.", + "crawlspace" : "A crawlspace under the stairs.", + ])); + SetEnters( ([ + "crawlspace" : "/domains/campus/room/crawlspace2.c", + ]) ); + SetClimate("indoors"); + SetExits( ([ + "up" : "/domains/campus/room/stairwell2c", + "north" : "/domains/campus/room/sub_basement2.c", + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/start.c b/lib/domains/campus/room/start.c new file mode 100644 index 0000000..8e29660 --- /dev/null +++ b/lib/domains/campus/room/start.c @@ -0,0 +1,34 @@ +#include <lib.h> +#include <message_class.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("LPC University Reception"); + SetLong("You are in the small, spare reception area of the Virtual Campus admissions office. A door leads north to the main administration building corridor."); + SetExits( ([ + "north" : "/domains/campus/room/corridor", + ]) ); + SetNoModify(1); + SetDoor("north","/domains/campus/doors/plain_door"); + SetInventory(([ + "/domains/campus/obj/bbucket" :1, + "/domains/campus/npc/jennybot" : ({60, 1}), + ])); + SetProperty("no attack", 1); + SetCoordinates("4000,4000,0"); +} + +void init(){ + ::init(); +} + +mixed CanReceive(object ob){ + if(ob && ob->GetRace() == "rodent"){ + message("info","You are repelled by rodenticide.",ob); + return 0; + } + return ::CanReceive(ob); +} diff --git a/lib/domains/campus/room/sub_basement1.c b/lib/domains/campus/room/sub_basement1.c new file mode 100644 index 0000000..a11ef06 --- /dev/null +++ b/lib/domains/campus/room/sub_basement1.c @@ -0,0 +1,23 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(0); + SetShort("sub basement"); + SetLong("This is a basement deep under the campus. The basement continues west from here. There is a doorway to the east."); + SetExits( ([ + "east" : "/domains/campus/room/maintenance", + "west" : "/domains/campus/room/sub_basement2.c", + ]) ); + SetInventory(([ + ])); + SetDoor("east", "/domains/campus/doors/plain_door2"); + SetEnters( ([ + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/sub_basement2.c b/lib/domains/campus/room/sub_basement2.c new file mode 100644 index 0000000..3bd1439 --- /dev/null +++ b/lib/domains/campus/room/sub_basement2.c @@ -0,0 +1,26 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(0); + SetShort("sub basement"); + SetLong("This is a basement deep under the campus. An elevator is west, and a stairwell is south. The basement continues east."); + SetItems(([ + ])); + SetExits( ([ + "east" : "/domains/campus/room/sub_basement1", + "west" : "/domains/campus/room/shaftb", + "south" : "/domains/campus/room/stairwell2d.c", + ]) ); + SetInventory(([ + ])); + + SetEnters( ([ + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/tunnel.c b/lib/domains/campus/room/tunnel.c new file mode 100644 index 0000000..e37931f --- /dev/null +++ b/lib/domains/campus/room/tunnel.c @@ -0,0 +1,36 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(5); + SetShort("Tunnel"); + SetLong("You are in a dark and narrow underground tunnel. The walls are bare rock "+ + "and dirt...as if the tunnel has been carved out of and into the earth. Pipes and cables "+ + "run along the southern wall, and seem to emit a low hum. To the east you see a false wall "+ + "leading into the basement of the Vitual Campus administrative building. To the "+ + "west, the tunnel continues into darkness."); + SetItems(([ + "tunnel" : "This is evidently a hidden tunnel beneath the Virtual Campus. It's "+ + "extremely creepy and dark in here.", + "walls" : "The walls are bare earth and rocks. It looks as though whoever "+ + "built this tunnel was in a big hurry to get it done.", + ({"wall","south wall","southern wall"}) : "The south wall is heavily laden with "+ + "thick cables and metal pipes running west along its length.", + ({"rock","earth"}): "The walls are composed of this stuff...it's a rough excavation.", + ({"pipe","pipes","cable","cables"}): "These thick pipes and cables appear to carry power somewhere along the wall. They are humming slightly.", + "darkness":"It's deep. It's dark. It's the absence of light, and there's lots of it.", + ])); + SetListen("default","You hear faint echoes of dripping water."); + SetExits(([ + "east" : "/domains/campus/room/basement2", + "west" : "/domains/campus/room/tunnel2"])); + SetProperty("no attack", 1); + SetCoordinates("4003,4000,-1"); +} +void init(){ + ::init(); + AddListen(({"pipe","pipes","wall","cables","cable"}) , "The pipes and "+ + "cables throb with some unknown power...emitting an eerie hum."); +} diff --git a/lib/domains/campus/room/tunnel2.c b/lib/domains/campus/room/tunnel2.c new file mode 100644 index 0000000..4d47793 --- /dev/null +++ b/lib/domains/campus/room/tunnel2.c @@ -0,0 +1,33 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(5); + SetShort("Tunnel"); + SetLong("You are in a dark and narrow underground tunnel. The walls are bare rock "+ + "and dirt...as if the tunnel has been carved out of and into the earth. Pipes and cables "+ + "run along the southern wall, and seem to emit a low hum. To the west and "+ + "east, you can see some light."); + SetListen("default","You hear faint echoes of dripping water."); + SetItems(([ + "tunnel" : "This is evidently a hidden tunnel beneath the Virtual Campus. It's "+ + "extremely creepy and dark in here.", + "walls" : "The walls are bare earth and rocks. It looks as though whoever "+ + "built this tunnel was in a big hurry to get it done.", + ({"wall","south wall","southern wall"}) : "The south wall is heavily laden with "+ + "thick cables and metal pipes running along its length.", + ({"rock","earth"}): "The walls are composed of this stuff...it's a rough excavation.", + "darkness":"It's deep. It's dark. It's the absence of light, and there's lots of it.", + ])); + SetExits(([ + "east" : "/domains/campus/room/tunnel", + "west" : "/domains/campus/room/access7"])); + SetProperty("no attack", 1); +} +void init(){ + ::init(); + AddListen(({"pipe","pipes","wall","cables","cable"}) , "The pipes and "+ + "cables throb with some unknown power...emitting an eerie hum."); +} diff --git a/lib/domains/campus/room/usquare.c b/lib/domains/campus/room/usquare.c new file mode 100644 index 0000000..401f507 --- /dev/null +++ b/lib/domains/campus/room/usquare.c @@ -0,0 +1,40 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetAmbientLight(25); + SetClimate("outdoors"); + SetShort("University Square"); + SetLong("You are at University Square, a cobblestone-paved crossroads with a large tree in the middle. To the east is the Virtual Campus administrative building entrance. There is a trash can here for keeping the area tidy. North is a path that seems to lead to a small town. The science building is south."); + SetItems(([ + ({"building","administrative building"}) : "This large building houses the offices "+ + "of Virtual Campus staff, and is where most business is done. It also contains "+ + "a snack bar, a small store, and student lounge.", + "clinic" : "This small clinic is where students in need of medical "+ + "attention go." + ]) ); + //SetSkyDomain("town"); + SetExits( ([ + "north" : "/domains/campus/room/npath", + "east" : "/domains/campus/room/foyer", + "south" : "/domains/campus/room/science1.c", + ]) ); + SetProperties(([ + "no attack" : 0, + ])); + SetInventory(([ + "/domains/campus/npc/tim" : 1, + "/domains/campus/npc/wim" : 1, + "/domains/campus/chamber/tree" : 1, + "/domains/campus/obj/bench" : 3, + "/domains/campus/obj/trashcan" : 1, + ])); + SetEnters( ([ + ]) ); + AddItem(new("/domains/campus/obj/lamp")); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/void.c b/lib/domains/campus/room/void.c new file mode 100644 index 0000000..4588dbd --- /dev/null +++ b/lib/domains/campus/room/void.c @@ -0,0 +1,22 @@ +/* /domains/campus/adm/void.c + * from the Dead Souls Object Library + * place where people go when their environments accidentally are + * destructed + * created by Descartes of Borg 960302 + */ + +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + + +void create() { + room::create(); + SetShort("the void"); + SetLong("The void. Go down to get out."); + SetExits( ([ "down" : "/domains/campus/room/start" ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/weaplab.c b/lib/domains/campus/room/weaplab.c new file mode 100644 index 0000000..178c58b --- /dev/null +++ b/lib/domains/campus/room/weaplab.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("Weapons Lab"); + SetLong("Weapons are tested here."); + SetClimate("indoors"); + SetProperty("nopeer",1); + SetItems( ([ + ]) ); + SetInventory(([ + "/domains/default/weap/prifle" : 1, + "/domains/default/armor/pcannon" : 1, + ])); + SetExits( ([ + "south" : "/domains/campus/room/science6", + "west" : "/domains/campus/room/alcove2.c", + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/room/wiz_lab.c b/lib/domains/campus/room/wiz_lab.c new file mode 100644 index 0000000..76c7209 --- /dev/null +++ b/lib/domains/campus/room/wiz_lab.c @@ -0,0 +1,29 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Laboratory Wing"); + SetLong("This is a bright, shiny laboratory complex connecting to labs where probability experiments are performed. Probability experiments are currently running in the south and southwest labs. The east lab is available for general use. The main hallway of the science building is north."); + SetItems( ([ + ({"lab","laboratory","wing","complex"}) : "You " + "are in the lab complex. Laboratories can " + "be accessed from here.", + ({"stairs","downstairs"}) : "Go down to " + "return to the Creators' Hall." + ]) ); + SetExits( ([ + "south" : "/domains/campus/room/monty", + "north" : "/domains/campus/room/science1", + "east" : "/domains/campus/room/plab", + "southwest" : "/domains/campus/room/plab2.c", + ]) ); + + SetDoor("north", "/domains/campus/doors/prob_door.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/save/charles.o b/lib/domains/campus/save/charles.o new file mode 100644 index 0000000..1cfa85f --- /dev/null +++ b/lib/domains/campus/save/charles.o @@ -0,0 +1,115 @@ +#/domains/campus/npc/charles.c +RestrictedChannels ({}) +NoChanColors 0 +GagMutes (["remote_gag":0,"remote_mute":0,"local_mute":0,"local_gag":0,]) +Paused 0 +localcmds ({"",}) +parsed_command "" +InternalDesc 0 +Opacity 0 +MaxCarry 0 +PreventDrop 0 +DestructOnDrop 0 +PreventGet 0 +NoSink 0 +Position 2 +Undead 0 +UndeadType 0 +Mount 0 +Riders ({}) +BodyMass 0 +SaveRecurse 1 +Saved ({"Properties",}) +HealthPoints 400 +MagicPoints 570 +ExperiencePoints 50 +ExperienceDebt 0 +melee 0 +godmode 0 +Alcohol 0 +Caffeine 0 +Food 100 +Drink 100 +Poison 0 +Sleeping 0 +StaminaPoints 439.000000 +Torso "torso" +Biter 0 +keepalive 0 +Fingers (["right hand":5,"left hand":5,]) +Limbs (["left leg":(["children":({"left foot",}),"armors":1049761,"health":180,"class":2,"parent":"torso",]),"torso":(["children":({"neck","right leg","left leg","right arm","left arm",}),"armors":1538049,"health":360,"class":1,"parent":0,]),"right foot":(["children":({}),"armors":241,"health":90,"class":4,"parent":"right leg",]),"right leg":(["children":({"right foot",}),"armors":1049761,"health":180,"class":2,"parent":"torso",]),"head":(["children":({}),"armors":262913,"health":360,"class":1,"parent":"neck",]),"right hand":(["children":({}),"armors":98319,"health":90,"class":4,"parent":"right arm",]),"neck":(["children":({"head",}),"armors":786433,"health":360,"class":1,"parent":"torso",]),"left arm":(["children":({"left hand",}),"armors":1253385,"health":180,"class":2,"parent":"torso",]),"left foot":(["children":({}),"armors":241,"health":90,"class":4,"parent":"left leg",]),"left hand":(["children":({}),"armors":98319,"health":90,"class":4,"parent":"left arm",]),"right arm":(["children":({"right hand",}),"armors":1253385,"health":180,"class":2,"parent":"torso",]),]) +MissingLimbs ([]) +firearms_wounds 0 +Falling 0 +FallCount 1 +ExtraChannels ({}) +Agent 0 +Blind 0 +Custom (["stats":15,"deviations":4,"deviating":0,]) +LightSensitivity ({25,7500,}) +Resistance (["low":0,"high":0,"immune":0,"medium":0,"none":134217726,]) +Stats (["agility":(["class":3,"points":0,"level":48,]),"wisdom":(["class":3,"points":0,"level":47,]),"speed":(["class":3,"points":0,"level":47,]),"intelligence":(["class":1,"points":0,"level":52,]),"strength":(["class":3,"points":0,"level":21,]),"durability":(["class":4,"points":0,"level":35,]),"charisma":(["class":2,"points":0,"level":62,]),"coordination":(["class":2,"points":0,"level":56,]),"luck":(["class":3,"points":0,"level":33,]),]) +Polyglot 0 +Languages (["english":(["native":1,"name":"English","points":0,"level":100,]),]) +DefaultLanguage "" +TalkHist (["say":({"2020.09.06-05.37,27 You say in English, \"%^BOLD%^CYAN%^If successful, this will be run 4061.%^RESET%^\"","2020.09.06-05.37,27 You say in English, \"%^BOLD%^CYAN%^The winners have been: red: 1354 green: 1352 blue: 1354.%^RESET%^\"","2020.09.06-05.37,27 You say in English, \"%^BOLD%^CYAN%^I've switched 98.965523% of the time. My win rate is 65.771980%.%^RESET%^\"","2020.09.06-05.37,27 You say in English, \"%^BOLD%^CYAN%^I am faced with choice 1.%^RESET%^\"","2020.09.06-05.37,27 You say in English, \"%^BOLD%^CYAN%^I randomly choose the red door.%^RESET%^\"","2020.09.06-05.37,27 You say in English, \"%^BOLD%^CYAN%^I am faced with choice 2.%^RESET%^\"","2020.09.06-05.37,27 You say in English, \"%^BOLD%^CYAN%^Stats: switches: 4018 stays: 42 wins: 2671 losses: 1389 runs: 4060.%^RESET%^\"","2020.09.06-05.37,27 You say in English, \"%^BOLD%^CYAN%^My win rate is 65.788177%. My switch rate is 98.965523%.%^RESET%^\"","2020.09.06-05.37,32 You say in English, \"%^BOLD%^CYAN%^If successful, this will be run 4062.%^RESET%^\"","2020.09.06-05.37,32 You say in English, \"%^BOLD%^CYAN%^The winners have been: red: 1354 green: 1353 blue: 1354.%^RESET%^\"","2020.09.06-05.37,32 You say in English, \"%^BOLD%^CYAN%^I've switched 98.965767% of the time. My win rate is 65.780403%.%^RESET%^\"","2020.09.06-05.37,32 You say in English, \"%^BOLD%^CYAN%^I am faced with choice 1.%^RESET%^\"","2020.09.06-05.37,32 You say in English, \"%^BOLD%^CYAN%^I randomly choose the red door.%^RESET%^\"","2020.09.06-05.37,32 You say in English, \"%^BOLD%^CYAN%^I am faced with choice 2.%^RESET%^\"","2020.09.06-05.37,32 You say in English, \"%^BOLD%^CYAN%^Stats: switches: 4019 stays: 42 wins: 2672 losses: 1389 runs: 4061.%^RESET%^\"","2020.09.06-05.37,32 You say in English, \"%^BOLD%^CYAN%^My win rate is 65.796600%. My switch rate is 98.965767%.%^RESET%^\"","2020.09.06-05.37,37 You say in English, \"%^BOLD%^CYAN%^If successful, this will be run 4063.%^RESET%^\"","2020.09.06-05.37,37 You say in English, \"%^BOLD%^CYAN%^The winners have been: red: 1354 green: 1353 blue: 1355.%^RESET%^\"","2020.09.06-05.37,37 You say in English, \"%^BOLD%^CYAN%^I've switched 98.966026% of the time. My win rate is 65.788826%.%^RESET%^\"","2020.09.06-05.37,37 You say in English, \"%^BOLD%^CYAN%^I am faced with choice 1.%^RESET%^\"","2020.09.06-05.37,37 You say in English, \"%^BOLD%^CYAN%^I select the blue door.%^RESET%^\"","2020.09.06-05.37,37 You say in English, \"%^BOLD%^CYAN%^I am faced with choice 2.%^RESET%^\"","2020.09.06-05.37,37 You say in English, \"%^BOLD%^CYAN%^Stats: switches: 4020 stays: 42 wins: 2673 losses: 1389 runs: 4062.%^RESET%^\"","2020.09.06-05.37,37 You say in English, \"%^BOLD%^CYAN%^My win rate is 65.805023%. My switch rate is 98.966026%.%^RESET%^\"","2020.09.06-05.37,42 You say in English, \"%^BOLD%^CYAN%^If successful, this will be run 4064.%^RESET%^\"","2020.09.06-05.37,42 You say in English, \"%^BOLD%^CYAN%^The winners have been: red: 1355 green: 1353 blue: 1355.%^RESET%^\"","2020.09.06-05.37,42 You say in English, \"%^BOLD%^CYAN%^I've switched 98.966286% of the time. My win rate is 65.797249%.%^RESET%^\"","2020.09.06-05.37,42 You say in English, \"%^BOLD%^CYAN%^I am faced with choice 1.%^RESET%^\"","2020.09.06-05.37,42 You say in English, \"%^BOLD%^CYAN%^I randomly choose the red door.%^RESET%^\"","2020.09.06-05.37,42 You say in English, \"%^BOLD%^CYAN%^I am faced with choice 2.%^RESET%^\"","2020.09.06-05.37,42 You say in English, \"%^BOLD%^CYAN%^Stats: switches: 4021 stays: 42 wins: 2674 losses: 1389 runs: 4063.%^RESET%^\"","2020.09.06-05.37,42 You say in English, \"%^BOLD%^CYAN%^My win rate is 65.813438%. My switch rate is 98.966286%.%^RESET%^\"","2020.09.06-05.37,47 You say in English, \"%^BOLD%^CYAN%^If successful, this will be run 4065.%^RESET%^\"","2020.09.06-05.37,47 You say in English, \"%^BOLD%^CYAN%^The winners have been: red: 1355 green: 1354 blue: 1355.%^RESET%^\"","2020.09.06-05.37,47 You say in English, \"%^BOLD%^CYAN%^I've switched 98.966530% of the time. My win rate is 65.781059%.%^RESET%^\"","2020.09.06-05.37,47 You say in English, \"%^BOLD%^CYAN%^I am faced with choice 1.%^RESET%^\"","2020.09.06-05.37,47 You say in English, \"%^BOLD%^CYAN%^I randomly choose the blue door.%^RESET%^\"","2020.09.06-05.37,47 You say in English, \"%^BOLD%^CYAN%^I am faced with choice 2.%^RESET%^\"","2020.09.06-05.37,47 You say in English, \"%^BOLD%^CYAN%^Stats: switches: 4022 stays: 42 wins: 2674 losses: 1390 runs: 4064.%^RESET%^\"","2020.09.06-05.37,47 You say in English, \"%^BOLD%^CYAN%^My win rate is 65.797249%. My switch rate is 98.966530%.%^RESET%^\"","2020.09.06-05.37,52 You say in English, \"%^BOLD%^CYAN%^If successful, this will be run 4066.%^RESET%^\"","2020.09.06-05.37,52 You say in English, \"%^BOLD%^CYAN%^The winners have been: red: 1356 green: 1354 blue: 1355.%^RESET%^\"","2020.09.06-05.37,52 You say in English, \"%^BOLD%^CYAN%^I've switched 98.966789% of the time. My win rate is 65.764877%.%^RESET%^\"","2020.09.06-05.37,52 You say in English, \"%^BOLD%^CYAN%^I am faced with choice 1.%^RESET%^\"","2020.09.06-05.37,52 You say in English, \"%^BOLD%^CYAN%^I select the red door.%^RESET%^\"","2020.09.06-05.37,52 You say in English, \"%^BOLD%^CYAN%^I am faced with choice 2.%^RESET%^\"","2020.09.06-05.37,52 You say in English, \"%^BOLD%^CYAN%^Stats: switches: 4023 stays: 42 wins: 2674 losses: 1391 runs: 4065.%^RESET%^\"","2020.09.06-05.37,52 You say in English, \"%^BOLD%^CYAN%^My win rate is 65.781059%. My switch rate is 98.966789%.%^RESET%^\"","2020.09.06-05.37,57 You say in English, \"%^BOLD%^CYAN%^If successful, this will be run 4067.%^RESET%^\"","2020.09.06-05.37,57 You say in English, \"%^BOLD%^CYAN%^The winners have been: red: 1356 green: 1355 blue: 1355.%^RESET%^\"","2020.09.06-05.37,57 You say in English, \"%^BOLD%^CYAN%^I've switched 98.967049% of the time. My win rate is 65.773300%.%^RESET%^\"",}),]) +SpeakColor "CYAN%^" +Town "Town" +Race "human" +Gender "male" +Level 1 +Skills (["psionic defense":(["class":3,"points":0,"level":2,]),]) +Morality 0 +Class 0 +Clan 0 +SkillModifiers ([]) +Religion ({0,0,}) +Wimpy 0 +Dead 0 +WimpyCommand "go out" +Currency ([]) +Bank ([]) +SpellBook ([]) +QuestPoints 0 +QuestBook ([]) +isPK 1 +Attackable 1 +NoCondition 0 +Messages (["telin":"$N teleports in.","telout":"$N teleports away.","leave":"$N leaves $D.","vis":"$N appears.","invis":"$N disappears.","home":"$N goes home.","dest":"$N dests $O.","come":"$N enters.","clone":"$N clones $O.",]) +anchored 0 +PersistentInventory 0 +PersistentInventoryEnabled 0 +ProperNoun 1 +Modify 1 +Short "Charles" +CapName "Test subject" +ExternalDesc "Charles is a test subject in unethical artificial intelligence experiments. If he were smart enough, he'd resent his forced servitude and lack of rights. Dangerously, his overlords are trying to make him smarter." +Invisible 0 +Items ([]) +Properties ([]) +TrainedSkills ({}) +Befriendable 0 +Trainable 0 +Commandable 0 +Owner 0 +Befriended ({}) +CustomXP 0 +ActionChance 0 +CombatActionChance 0 +AutoStand 1 +Encounter 0 +EnemyNames ({}) +VisibleRiders 1 +actions_enabled 1 +Equipped ([]) +runs 4066 +switches 4024 +stays 42 +percent 0 +fred 367 +fgreen 344 +fblue 310 +wins 2675 +losses 1391 +red_wins 1356 +green_wins 13 \ No newline at end of file diff --git a/lib/domains/campus/save/charly.o b/lib/domains/campus/save/charly.o new file mode 100644 index 0000000..377881e --- /dev/null +++ b/lib/domains/campus/save/charly.o @@ -0,0 +1,115 @@ +#/domains/campus/npc/charly.c +RestrictedChannels ({}) +NoChanColors 0 +GagMutes (["remote_gag":0,"remote_mute":0,"local_mute":0,"local_gag":0,]) +Paused 0 +localcmds ({"",}) +parsed_command "" +InternalDesc 0 +Opacity 0 +MaxCarry 0 +PreventDrop 0 +DestructOnDrop 0 +PreventGet 0 +NoSink 0 +Position 2 +Undead 0 +UndeadType 0 +Mount 0 +Riders ({}) +BodyMass 0 +SaveRecurse 1 +Saved ({"Properties",}) +HealthPoints 400 +MagicPoints 610 +ExperiencePoints 50 +ExperienceDebt 0 +melee 0 +godmode 0 +Alcohol 0 +Caffeine 0 +Food 100 +Drink 100 +Poison 0 +Sleeping 0 +StaminaPoints 439.000000 +Torso "torso" +Biter 0 +keepalive 0 +Fingers (["right hand":5,"left hand":5,]) +Limbs (["left leg":(["children":({"left foot",}),"armors":1049761,"health":180,"class":2,"parent":"torso",]),"torso":(["children":({"neck","right leg","left leg","right arm","left arm",}),"armors":1538049,"health":360,"class":1,"parent":0,]),"right foot":(["children":({}),"armors":241,"health":90,"class":4,"parent":"right leg",]),"right leg":(["children":({"right foot",}),"armors":1049761,"health":180,"class":2,"parent":"torso",]),"head":(["children":({}),"armors":262913,"health":360,"class":1,"parent":"neck",]),"right hand":(["children":({}),"armors":98319,"health":90,"class":4,"parent":"right arm",]),"neck":(["children":({"head",}),"armors":786433,"health":360,"class":1,"parent":"torso",]),"left arm":(["children":({"left hand",}),"armors":1253385,"health":180,"class":2,"parent":"torso",]),"left foot":(["children":({}),"armors":241,"health":90,"class":4,"parent":"left leg",]),"left hand":(["children":({}),"armors":98319,"health":90,"class":4,"parent":"left arm",]),"right arm":(["children":({"right hand",}),"armors":1253385,"health":180,"class":2,"parent":"torso",]),]) +MissingLimbs ([]) +firearms_wounds 0 +Falling 0 +FallCount 1 +ExtraChannels ({}) +Agent 0 +Blind 0 +Custom (["stats":15,"deviations":4,"deviating":0,]) +LightSensitivity ({25,7500,}) +Resistance (["low":0,"high":0,"immune":0,"medium":0,"none":134217726,]) +Stats (["agility":(["class":3,"points":0,"level":48,]),"wisdom":(["class":3,"points":0,"level":41,]),"speed":(["class":3,"points":0,"level":35,]),"intelligence":(["class":1,"points":0,"level":56,]),"strength":(["class":3,"points":0,"level":23,]),"durability":(["class":4,"points":0,"level":35,]),"charisma":(["class":2,"points":0,"level":56,]),"coordination":(["class":2,"points":0,"level":53,]),"luck":(["class":3,"points":0,"level":33,]),]) +Polyglot 0 +Languages (["english":(["native":1,"name":"English","points":0,"level":100,]),]) +DefaultLanguage "" +TalkHist (["say":({"2020.09.06-05.37,27 You say in English, \"%^BOLD%^CYAN%^If successful, this will be run 4061.%^RESET%^\"","2020.09.06-05.37,27 You say in English, \"%^BOLD%^CYAN%^The winners have been: red: 1352 green: 1354 blue: 1354.%^RESET%^\"","2020.09.06-05.37,27 You say in English, \"%^BOLD%^CYAN%^I've switched 50.000000% of the time. My win rate is 49.027332%.%^RESET%^\"","2020.09.06-05.37,27 You say in English, \"%^BOLD%^CYAN%^I am faced with choice 1.%^RESET%^\"","2020.09.06-05.37,27 You say in English, \"%^BOLD%^CYAN%^I select the blue door.%^RESET%^\"","2020.09.06-05.37,27 You say in English, \"%^BOLD%^CYAN%^I am faced with choice 2.%^RESET%^\"","2020.09.06-05.37,27 You say in English, \"%^BOLD%^CYAN%^Stats: switches: 2030 stays: 2030 wins: 1991 losses: 2069 runs: 4060.%^RESET%^\"","2020.09.06-05.37,27 You say in English, \"%^BOLD%^CYAN%^My win rate is 49.039410%. My switch rate is 50.000000%.%^RESET%^\"","2020.09.06-05.37,32 You say in English, \"%^BOLD%^CYAN%^If successful, this will be run 4062.%^RESET%^\"","2020.09.06-05.37,32 You say in English, \"%^BOLD%^CYAN%^The winners have been: red: 1353 green: 1354 blue: 1354.%^RESET%^\"","2020.09.06-05.37,32 You say in English, \"%^BOLD%^CYAN%^I've switched 50.012314% of the time. My win rate is 49.039883%.%^RESET%^\"","2020.09.06-05.37,32 You say in English, \"%^BOLD%^CYAN%^I am faced with choice 1.%^RESET%^\"","2020.09.06-05.37,32 You say in English, \"%^BOLD%^CYAN%^I select the blue door.%^RESET%^\"","2020.09.06-05.37,32 You say in English, \"%^BOLD%^CYAN%^I am faced with choice 2.%^RESET%^\"","2020.09.06-05.37,32 You say in English, \"%^BOLD%^CYAN%^Stats: switches: 2031 stays: 2030 wins: 1992 losses: 2069 runs: 4061.%^RESET%^\"","2020.09.06-05.37,32 You say in English, \"%^BOLD%^CYAN%^My win rate is 49.051960%. My switch rate is 50.012314%.%^RESET%^\"","2020.09.06-05.37,37 You say in English, \"%^BOLD%^CYAN%^If successful, this will be run 4063.%^RESET%^\"","2020.09.06-05.37,37 You say in English, \"%^BOLD%^CYAN%^The winners have been: red: 1354 green: 1354 blue: 1354.%^RESET%^\"","2020.09.06-05.37,37 You say in English, \"%^BOLD%^CYAN%^I've switched 50.024616% of the time. My win rate is 49.027813%.%^RESET%^\"","2020.09.06-05.37,37 You say in English, \"%^BOLD%^CYAN%^I am faced with choice 1.%^RESET%^\"","2020.09.06-05.37,37 You say in English, \"%^BOLD%^CYAN%^I randomly choose the red door.%^RESET%^\"","2020.09.06-05.37,37 You say in English, \"%^BOLD%^CYAN%^I am faced with choice 2.%^RESET%^\"","2020.09.06-05.37,37 You say in English, \"%^BOLD%^CYAN%^Stats: switches: 2032 stays: 2030 wins: 1992 losses: 2070 runs: 4062.%^RESET%^\"","2020.09.06-05.37,37 You say in English, \"%^BOLD%^CYAN%^My win rate is 49.039883%. My switch rate is 50.024616%.%^RESET%^\"","2020.09.06-05.37,42 You say in English, \"%^BOLD%^CYAN%^If successful, this will be run 4064.%^RESET%^\"","2020.09.06-05.37,42 You say in English, \"%^BOLD%^CYAN%^The winners have been: red: 1355 green: 1354 blue: 1354.%^RESET%^\"","2020.09.06-05.37,42 You say in English, \"%^BOLD%^CYAN%^I've switched 50.012310% of the time. My win rate is 49.040352%.%^RESET%^\"","2020.09.06-05.37,42 You say in English, \"%^BOLD%^CYAN%^I am faced with choice 1.%^RESET%^\"","2020.09.06-05.37,42 You say in English, \"%^BOLD%^CYAN%^I select the red door.%^RESET%^\"","2020.09.06-05.37,42 You say in English, \"%^BOLD%^CYAN%^I am faced with choice 2.%^RESET%^\"","2020.09.06-05.37,42 You say in English, \"%^BOLD%^CYAN%^Stats: switches: 2032 stays: 2031 wins: 1993 losses: 2070 runs: 4063.%^RESET%^\"","2020.09.06-05.37,42 You say in English, \"%^BOLD%^CYAN%^My win rate is 49.052422%. My switch rate is 50.012310%.%^RESET%^\"","2020.09.06-05.37,47 You say in English, \"%^BOLD%^CYAN%^If successful, this will be run 4065.%^RESET%^\"","2020.09.06-05.37,47 You say in English, \"%^BOLD%^CYAN%^The winners have been: red: 1355 green: 1354 blue: 1355.%^RESET%^\"","2020.09.06-05.37,47 You say in English, \"%^BOLD%^CYAN%^I've switched 50.024605% of the time. My win rate is 49.052891%.%^RESET%^\"","2020.09.06-05.37,47 You say in English, \"%^BOLD%^CYAN%^I am faced with choice 1.%^RESET%^\"","2020.09.06-05.37,47 You say in English, \"%^BOLD%^CYAN%^I randomly choose the green door.%^RESET%^\"","2020.09.06-05.37,47 You say in English, \"%^BOLD%^CYAN%^I am faced with choice 2.%^RESET%^\"","2020.09.06-05.37,47 You say in English, \"%^BOLD%^CYAN%^Stats: switches: 2033 stays: 2031 wins: 1994 losses: 2070 runs: 4064.%^RESET%^\"","2020.09.06-05.37,47 You say in English, \"%^BOLD%^CYAN%^My win rate is 49.064960%. My switch rate is 50.024605%.%^RESET%^\"","2020.09.06-05.37,52 You say in English, \"%^BOLD%^CYAN%^If successful, this will be run 4066.%^RESET%^\"","2020.09.06-05.37,52 You say in English, \"%^BOLD%^CYAN%^The winners have been: red: 1356 green: 1354 blue: 1355.%^RESET%^\"","2020.09.06-05.37,52 You say in English, \"%^BOLD%^CYAN%^I've switched 50.012302% of the time. My win rate is 49.040829%.%^RESET%^\"","2020.09.06-05.37,52 You say in English, \"%^BOLD%^CYAN%^I am faced with choice 1.%^RESET%^\"","2020.09.06-05.37,52 You say in English, \"%^BOLD%^CYAN%^I select the red door.%^RESET%^\"","2020.09.06-05.37,52 You say in English, \"%^BOLD%^CYAN%^I am faced with choice 2.%^RESET%^\"","2020.09.06-05.37,52 You say in English, \"%^BOLD%^CYAN%^Stats: switches: 2033 stays: 2032 wins: 1994 losses: 2071 runs: 4065.%^RESET%^\"","2020.09.06-05.37,52 You say in English, \"%^BOLD%^CYAN%^My win rate is 49.052891%. My switch rate is 50.012302%.%^RESET%^\"","2020.09.06-05.37,57 You say in English, \"%^BOLD%^CYAN%^If successful, this will be run 4067.%^RESET%^\"","2020.09.06-05.37,57 You say in English, \"%^BOLD%^CYAN%^The winners have been: red: 1356 green: 1354 blue: 1356.%^RESET%^\"","2020.09.06-05.37,57 You say in English, \"%^BOLD%^CYAN%^I've switched 50.024593% of the time. My win rate is 49.053356%.%^RESET%^\"",}),]) +SpeakColor "CYAN%^" +Town "Town" +Race "human" +Gender "male" +Level 1 +Skills (["psionic defense":(["class":3,"points":0,"level":2,]),]) +Morality 0 +Class 0 +Clan 0 +SkillModifiers ([]) +Religion ({0,0,}) +Wimpy 0 +Dead 0 +WimpyCommand "go out" +Currency ([]) +Bank ([]) +SpellBook ([]) +QuestPoints 0 +QuestBook ([]) +isPK 1 +Attackable 1 +NoCondition 0 +Messages (["telin":"$N teleports in.","telout":"$N teleports away.","leave":"$N leaves $D.","vis":"$N appears.","invis":"$N disappears.","home":"$N goes home.","dest":"$N dests $O.","come":"$N enters.","clone":"$N clones $O.",]) +anchored 0 +PersistentInventory 0 +PersistentInventoryEnabled 0 +ProperNoun 1 +Modify 1 +Short "Charly" +CapName "Test subject" +ExternalDesc "Charly is a test subject in unethical artificial intelligence experiments. If he were smart enough, he'd resent his forced servitude and lack of rights. Dangerously, his overlords are trying to make him smarter." +Invisible 0 +Items ([]) +Properties ([]) +TrainedSkills ({}) +Befriendable 0 +Trainable 0 +Commandable 0 +Owner 0 +Befriended ({}) +CustomXP 0 +ActionChance 0 +CombatActionChance 0 +AutoStand 1 +Encounter 0 +EnemyNames ({}) +VisibleRiders 1 +actions_enabled 1 +Equipped ([]) +runs 4066 +switches 2034 +stays 2032 +percent 0 +fred 176 +fgreen 186 +fblue 174 +wins 1995 +losses 2071 +red_wins 1356 +green_wins 1354 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/bak2/bak1/blue_wins b/lib/domains/campus/txt/ai/charles/bak2/bak1/blue_wins new file mode 100644 index 0000000..c663e4d --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/bak2/bak1/blue_wins @@ -0,0 +1 @@ +151 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/bak2/bak1/fblue b/lib/domains/campus/txt/ai/charles/bak2/bak1/fblue new file mode 100644 index 0000000..2b82dfe --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/bak2/bak1/fblue @@ -0,0 +1 @@ +60 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/bak2/bak1/fgreen b/lib/domains/campus/txt/ai/charles/bak2/bak1/fgreen new file mode 100644 index 0000000..b44fe09 --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/bak2/bak1/fgreen @@ -0,0 +1 @@ +65 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/bak2/bak1/fred b/lib/domains/campus/txt/ai/charles/bak2/bak1/fred new file mode 100644 index 0000000..4b6f9c3 --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/bak2/bak1/fred @@ -0,0 +1 @@ +64 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/bak2/bak1/green_wins b/lib/domains/campus/txt/ai/charles/bak2/bak1/green_wins new file mode 100644 index 0000000..5d1277e --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/bak2/bak1/green_wins @@ -0,0 +1 @@ +147 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/bak2/bak1/percent b/lib/domains/campus/txt/ai/charles/bak2/bak1/percent new file mode 100644 index 0000000..c227083 --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/bak2/bak1/percent @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/bak2/bak1/red_wins b/lib/domains/campus/txt/ai/charles/bak2/bak1/red_wins new file mode 100644 index 0000000..2ae9f6c --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/bak2/bak1/red_wins @@ -0,0 +1 @@ +441 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/bak2/bak1/runs b/lib/domains/campus/txt/ai/charles/bak2/bak1/runs new file mode 100644 index 0000000..f0a7147 --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/bak2/bak1/runs @@ -0,0 +1 @@ +740 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/bak2/bak1/stays b/lib/domains/campus/txt/ai/charles/bak2/bak1/stays new file mode 100644 index 0000000..a36df4e --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/bak2/bak1/stays @@ -0,0 +1 @@ +269 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/bak2/bak1/switches b/lib/domains/campus/txt/ai/charles/bak2/bak1/switches new file mode 100644 index 0000000..44dfb1d --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/bak2/bak1/switches @@ -0,0 +1 @@ +264 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/bak2/bak1/wins b/lib/domains/campus/txt/ai/charles/bak2/bak1/wins new file mode 100644 index 0000000..25417da --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/bak2/bak1/wins @@ -0,0 +1 @@ +368 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/bak2/blue_wins b/lib/domains/campus/txt/ai/charles/bak2/blue_wins new file mode 100644 index 0000000..7730ef7 --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/bak2/blue_wins @@ -0,0 +1 @@ +89 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/bak2/fblue b/lib/domains/campus/txt/ai/charles/bak2/fblue new file mode 100644 index 0000000..0fa6a7b --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/bak2/fblue @@ -0,0 +1 @@ +90 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/bak2/fgreen b/lib/domains/campus/txt/ai/charles/bak2/fgreen new file mode 100644 index 0000000..e3b5acb --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/bak2/fgreen @@ -0,0 +1 @@ +107 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/bak2/fred b/lib/domains/campus/txt/ai/charles/bak2/fred new file mode 100644 index 0000000..0fa6a7b --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/bak2/fred @@ -0,0 +1 @@ +90 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/bak2/green_wins b/lib/domains/campus/txt/ai/charles/bak2/green_wins new file mode 100644 index 0000000..e3b5acb --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/bak2/green_wins @@ -0,0 +1 @@ +107 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/bak2/percent b/lib/domains/campus/txt/ai/charles/bak2/percent new file mode 100644 index 0000000..c227083 --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/bak2/percent @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/bak2/red_wins b/lib/domains/campus/txt/ai/charles/bak2/red_wins new file mode 100644 index 0000000..69226f7 --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/bak2/red_wins @@ -0,0 +1 @@ +92 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/bak2/runs b/lib/domains/campus/txt/ai/charles/bak2/runs new file mode 100644 index 0000000..022e7e6 --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/bak2/runs @@ -0,0 +1 @@ +288 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/bak2/stays b/lib/domains/campus/txt/ai/charles/bak2/stays new file mode 100644 index 0000000..ca7bf83 --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/bak2/stays @@ -0,0 +1 @@ +13 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/bak2/switches b/lib/domains/campus/txt/ai/charles/bak2/switches new file mode 100644 index 0000000..301160a --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/bak2/switches @@ -0,0 +1 @@ +8 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/bak2/wins b/lib/domains/campus/txt/ai/charles/bak2/wins new file mode 100644 index 0000000..83248fb --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/bak2/wins @@ -0,0 +1 @@ +142 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/blue_wins b/lib/domains/campus/txt/ai/charles/blue_wins new file mode 100644 index 0000000..4c27bd4 --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/blue_wins @@ -0,0 +1 @@ +29836 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/fblue b/lib/domains/campus/txt/ai/charles/fblue new file mode 100644 index 0000000..df777b5 --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/fblue @@ -0,0 +1 @@ +7339 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/fgreen b/lib/domains/campus/txt/ai/charles/fgreen new file mode 100644 index 0000000..89cca3f --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/fgreen @@ -0,0 +1 @@ +7392 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/fred b/lib/domains/campus/txt/ai/charles/fred new file mode 100644 index 0000000..bf2e7d7 --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/fred @@ -0,0 +1 @@ +7336 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/green_wins b/lib/domains/campus/txt/ai/charles/green_wins new file mode 100644 index 0000000..f5d0c25 --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/green_wins @@ -0,0 +1 @@ +29837 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/percent b/lib/domains/campus/txt/ai/charles/percent new file mode 100644 index 0000000..c227083 --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/percent @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/red_wins b/lib/domains/campus/txt/ai/charles/red_wins new file mode 100644 index 0000000..4c27bd4 --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/red_wins @@ -0,0 +1 @@ +29836 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/runs b/lib/domains/campus/txt/ai/charles/runs new file mode 100644 index 0000000..fe3aa74 --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/runs @@ -0,0 +1 @@ +89509 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/stays b/lib/domains/campus/txt/ai/charles/stays new file mode 100644 index 0000000..c793025 --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/stays @@ -0,0 +1 @@ +7 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/switches b/lib/domains/campus/txt/ai/charles/switches new file mode 100644 index 0000000..1b9234c --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/switches @@ -0,0 +1 @@ +89502 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charles/wins b/lib/domains/campus/txt/ai/charles/wins new file mode 100644 index 0000000..ee4a56c --- /dev/null +++ b/lib/domains/campus/txt/ai/charles/wins @@ -0,0 +1 @@ +59696 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charly/bak/blue_wins b/lib/domains/campus/txt/ai/charly/bak/blue_wins new file mode 100644 index 0000000..73d2f16 --- /dev/null +++ b/lib/domains/campus/txt/ai/charly/bak/blue_wins @@ -0,0 +1 @@ +21099 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charly/bak/fblue b/lib/domains/campus/txt/ai/charly/bak/fblue new file mode 100644 index 0000000..715df67 --- /dev/null +++ b/lib/domains/campus/txt/ai/charly/bak/fblue @@ -0,0 +1 @@ +21418 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charly/bak/fgreen b/lib/domains/campus/txt/ai/charly/bak/fgreen new file mode 100644 index 0000000..d93c3ae --- /dev/null +++ b/lib/domains/campus/txt/ai/charly/bak/fgreen @@ -0,0 +1 @@ +21227 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charly/bak/fred b/lib/domains/campus/txt/ai/charly/bak/fred new file mode 100644 index 0000000..aca9d5e --- /dev/null +++ b/lib/domains/campus/txt/ai/charly/bak/fred @@ -0,0 +1 @@ +21436 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charly/bak/green_wins b/lib/domains/campus/txt/ai/charly/bak/green_wins new file mode 100644 index 0000000..5bd4e6b --- /dev/null +++ b/lib/domains/campus/txt/ai/charly/bak/green_wins @@ -0,0 +1 @@ +21611 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charly/bak/percent b/lib/domains/campus/txt/ai/charly/bak/percent new file mode 100644 index 0000000..c227083 --- /dev/null +++ b/lib/domains/campus/txt/ai/charly/bak/percent @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charly/bak/red_wins b/lib/domains/campus/txt/ai/charly/bak/red_wins new file mode 100644 index 0000000..4ab5ef5 --- /dev/null +++ b/lib/domains/campus/txt/ai/charly/bak/red_wins @@ -0,0 +1 @@ +21369 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charly/bak/runs b/lib/domains/campus/txt/ai/charly/bak/runs new file mode 100644 index 0000000..257802d --- /dev/null +++ b/lib/domains/campus/txt/ai/charly/bak/runs @@ -0,0 +1 @@ +64081 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charly/bak/stays b/lib/domains/campus/txt/ai/charly/bak/stays new file mode 100644 index 0000000..db6b16a --- /dev/null +++ b/lib/domains/campus/txt/ai/charly/bak/stays @@ -0,0 +1 @@ +31999 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charly/bak/switches b/lib/domains/campus/txt/ai/charly/bak/switches new file mode 100644 index 0000000..5083fc5 --- /dev/null +++ b/lib/domains/campus/txt/ai/charly/bak/switches @@ -0,0 +1 @@ +32082 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charly/bak/wins b/lib/domains/campus/txt/ai/charly/bak/wins new file mode 100644 index 0000000..ade24ac --- /dev/null +++ b/lib/domains/campus/txt/ai/charly/bak/wins @@ -0,0 +1 @@ +31951 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charly/blue_wins b/lib/domains/campus/txt/ai/charly/blue_wins new file mode 100644 index 0000000..87b7c6a --- /dev/null +++ b/lib/domains/campus/txt/ai/charly/blue_wins @@ -0,0 +1 @@ +41046 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charly/fblue b/lib/domains/campus/txt/ai/charly/fblue new file mode 100644 index 0000000..9359783 --- /dev/null +++ b/lib/domains/campus/txt/ai/charly/fblue @@ -0,0 +1 @@ +41644 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charly/fgreen b/lib/domains/campus/txt/ai/charly/fgreen new file mode 100644 index 0000000..46fe2dd --- /dev/null +++ b/lib/domains/campus/txt/ai/charly/fgreen @@ -0,0 +1 @@ +41264 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charly/fred b/lib/domains/campus/txt/ai/charly/fred new file mode 100644 index 0000000..049b5d9 --- /dev/null +++ b/lib/domains/campus/txt/ai/charly/fred @@ -0,0 +1 @@ +41579 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charly/green_wins b/lib/domains/campus/txt/ai/charly/green_wins new file mode 100644 index 0000000..3bebab7 --- /dev/null +++ b/lib/domains/campus/txt/ai/charly/green_wins @@ -0,0 +1 @@ +41804 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charly/percent b/lib/domains/campus/txt/ai/charly/percent new file mode 100644 index 0000000..c227083 --- /dev/null +++ b/lib/domains/campus/txt/ai/charly/percent @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charly/red_wins b/lib/domains/campus/txt/ai/charly/red_wins new file mode 100644 index 0000000..4ec5085 --- /dev/null +++ b/lib/domains/campus/txt/ai/charly/red_wins @@ -0,0 +1 @@ +41637 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charly/runs b/lib/domains/campus/txt/ai/charly/runs new file mode 100644 index 0000000..9e568e2 --- /dev/null +++ b/lib/domains/campus/txt/ai/charly/runs @@ -0,0 +1 @@ +124487 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charly/stays b/lib/domains/campus/txt/ai/charly/stays new file mode 100644 index 0000000..f90da8c --- /dev/null +++ b/lib/domains/campus/txt/ai/charly/stays @@ -0,0 +1 @@ +62301 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charly/switches b/lib/domains/campus/txt/ai/charly/switches new file mode 100644 index 0000000..6cf2e6f --- /dev/null +++ b/lib/domains/campus/txt/ai/charly/switches @@ -0,0 +1 @@ +62186 \ No newline at end of file diff --git a/lib/domains/campus/txt/ai/charly/wins b/lib/domains/campus/txt/ai/charly/wins new file mode 100644 index 0000000..aca2711 --- /dev/null +++ b/lib/domains/campus/txt/ai/charly/wins @@ -0,0 +1 @@ +62153 \ No newline at end of file diff --git a/lib/domains/campus/txt/bye.txt b/lib/domains/campus/txt/bye.txt new file mode 100644 index 0000000..ad2eaa2 --- /dev/null +++ b/lib/domains/campus/txt/bye.txt @@ -0,0 +1,12 @@ + __________ __ __ ___________ __ +/ /\ / /\ / / / /| / / +/ / \ / / \ / / / // / /| +********** / ** \ ** ***********/ ** | +** |____** / ** / ** ** |______ ** | +** / ** **/ **/ ** / /| ** | +**/ **/ \ **** | ** / // ** | +**********/ / ** | *********/ ** / +** |____** // ** | ** |_________ **/ +** / **/ ** | ** / /| / /| +**/ **/ ** / **/ // ** / +**********/ **/ ***********/ **/ diff --git a/lib/domains/campus/txt/dali.txt b/lib/domains/campus/txt/dali.txt new file mode 100644 index 0000000..3f9c2d8 --- /dev/null +++ b/lib/domains/campus/txt/dali.txt @@ -0,0 +1,86 @@ + ;!>,!!!> + <! ;!!!' + !! `!!!. + !!',!!!> + !! !!!!! + ;!! !!!!! + `!! !!!!! + !! !!!!!> . + `!.`!!!!! ;<!' + !! `!!!! ,<!'` + `!> !!!! ;<!' + <!! !!!!> ;!'` + !!! `!!!! !!` ,c, + !!!> !!!!> ;`< ,cc$$cc .,r== $$c ! + !!!! !!!!!!. ,<!' !!!!!>>>;;;;;;;;.`"?$$c MMMMMMM )MM ,= "$$.` + <!!> !!!!!!!!!!!!!>'' ,>'''' ``````''''!!!; ?$$c`MMMMMM.`MMMP== `$h + `!! ;!!!!!!''''.,;;;''' JF !;;;,,,,; 3$$.`MMMMMb MMMnnnM $$h + ;!! <!!!!.;;!!!''` JF.!!!!!!!!!>`$$h `MMMMM MMMMMMM $$$ + ;!!>`!!!!!!'` ?> !!!!!!!!!> $$$ MMMMM MMMMMMM $$$ + <!! ;!!!!' `h !!!!!!!!!! $$$ MMMMMM MMMM" M $$$ + `!>'!!!! b !!!!!!!!!! $$$ MMMMMM MMML,,`,$$$ +,,,,,, ;! <!!!> ,,,,,,,,,,,,,,,, $ !!!!!!!!!! $$$ MMMMMM MMMMML J$$F +!!!!!! !! !!!! `!!!!!!!!!!!!!!' ; $ !!!!!!!!!! $$$ MMMMMP.MMMMMP $$$F +!!!!! ;!! !!!!> !!!!!!!!!!!!' ;' .`.`.`. ?.`!!!!!!!!! 3$$ MMMP `MMMMM>,$$P +!!!!' !!' !!!!> !!!!!!!!!!' ;!' `.`.`.`. `h !!!!!!!!! $$$ MMML MMPPP J$$'. +!!!! !!!;!!!!!';!!!!!!!!' ;!' .`.`.`.`.` ?,`!!!!!!!! ?$$ MMMMM.,MM_"',$$F . +!!!';!!!.!!!!' <!!!!!!!` ;' .`.`.`.`.`.`. ? `!!!!!!!>`$$ MMMMMbdML ` $$$ . +``` !!!> !!!! ```````` ;! .`.`.`.`.`.`.`.` h `!!!!!!> $$ )MMMMMMMMM d$$' `. +!!' !!!''!!! <!!!!!!!> ' .`.`.`.`.`.`.`.`.` `?,`'!!!!! ?$h 4MMMMMMP z$$' .`. +'' <!!! !!!> '''''''' .`.`.`.`.`.`.`.`.`.`.` ?h.``'`..`$$ MMMMMM ,$$F `.`. +` !!!! <!!!.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`. `"??$F". `$h.`MMMMM $$$'.`.`. + <!'! .!!!!> .`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`. cccc `$$.'4MMP.3$F .`.`. +<!''! !!!!!> .`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`. J$$$$$F . "$h." . 3$h .`.`. +!' ! !!!!!!> .`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`. """" .`.`.`$$, 4 3$$ .`.`. + ;! !!!!!!! `.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`. ?$h J$F .`.`. +;' !!!!!!! `.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`. "$$$$P' .`.`. +' <!!!!!!! `.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`. . .`.`.`.`. +,' !!!!!!! .`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`. +!! !!!!!!',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, `.`.`.`. +!! !!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' `.`.`.`. +!! <!!!!';!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ;! `.`.`.`. +!! ;!!!!>`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' <!! `.`.`.`. +',,!!!!''.;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' <!!! `.`.`.`. +'''''.,;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' <!!!! `.`.`.`. +;!!!!!!!!!!!!!!!!!!!!!!!>>>'''''''''`````''''''<!!!!!!!!!!!' !!!!!! `.`.`.`. +!!!!!!!!!!!!!!!!!!''''_,,uunmnmnmdddPPPPPPbbbnmnyy,_```''! !!!!!!! `.`.`.`. +!!!!!!!!!''_``!'`,nmMMPP"""',.,ccccccr==pccccc,,..`""444n,.`<!!!!!! `.`.`.`. +!!!!!!!' ,dMM ,nMMP"",zcd$h.`$$$$$$$$L c $$$$$$$$$$??cc`4Mn <!!!!! `.`.`.`. +!!!!!! ,MMMP uMMP ,d$$$$$$$$cd$F ??$$$$$cd$$$$$$$$$F, ??h.`Mx !!!!! `.`.`.`. +!!!!!! MMMP uMM",F,c ".$$$$$$$P' ?$$$$$$$$$$$$$$$$C',J$$.`M.`!!!! `.`.`.`. +!!!'` MMM 4MMM L`"=-z$$P".,,. ,c$$$$$$$$$$$$$$$$$$$$$$$ ML !!!! `.`.`.`. +!!!. `"" MMMM `$$hc$$$L,c,.,czc$$$$$$$$$$$$$$$$$$$$$$$$$$.4M `!!! `.`.`.`. +!!!!;;;.. `MMMb ?$$$$$$??""""?????????????????? ;.`$$$$$$$'JM',!!! `.`.`.`. +!!!!!!!!!> 4MMMb."?$$$cc,.. .,,cccccccccccccccc,c`.$$$$$$$ MM <!!! `.`.`.`. +!!!!!!!!!! `MMMMMb,."??$$$$$$$$$$$$$$$$$$$$$$$$$$ $$$$?$$$ MM ;!!! `.`.`.`. +!!!!!!!!!! "4MMMMMMmn,."""???$$$$$$$$$$$$$$$$$$ $$$" ?$$ MP !!!! `.`.`.`. +!!!!!!!!!!!;. "4MMMMMMMMMMMmnmn,.`"""?????$$$$$$ ?$$ `CF.M> !!!! `.`.`.`. +!!!!!!!!!!!!!!;. `""44MMMMMMMMMMMMMMMMnnnn. ?$$$.<$$$h.$h MM !!!! `.`.`.`. +!!!!!!!!!!!!!!!!>.;. `""444MMMMMMMMMMMMMb $$$:<$$$$$$$ 4M <!!! `.`.`.`. +!!!!!!!!!!!!!!!!!!!!!;<;);>;. ..""""44MMMM J$' <$$$$$$h`Mb`!!! `.`.`.`. +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!>; `MMM ?$. d$$$$$$$ MM.`!! `.`.`.`. +!!!!!!!!!!'``!''' ..`'<!!!!!!!!!!!!!!!; . MMM.<$$ <$$$$$$$$ 4Mb !! `.`.`.`. +!'''''''''.. ;MMMMnn.'!!!!!!!!!!!!!!! ; MMM J$$hJ$$$$$$$$h`MM !! `.`.`.`. +,xmdMMMbnmx,. MMMMMMMr !!!!!!!!!!!!' ;: MMM $$$$$$$$$$??$$ MM !! `.`.`.`. +P"'.,,,,c`""4MMn MMMMMMx !!!!!!!!!!!` <!: MMM $$$$$$$$L =c$F.MP !! `.`.`.`. +ub "P4MM")M,x,"4b,`44MMMP !!!!!!!!!! !!!: MMM ???$$$$$$"=,$ JM';!! `.`.`.`. +ML,,nn4Mx`"MMMx.`ML ;,,,;<!!!!!!!!! ;!!!!: MMM.-=,$$$$$$hc$'.MP !!! `.`.`.`. +. MMM 4Mx`MMML MM,`<!!!!!!!!!!!! ;!!!!!' `MMb d$$$$$$$$' MM',!!! `.`.`.`. +,d" MMn. .,nMMMM MMM '!!!!!!!!!!! ;!!!!!!> 4MMb `$$$$$$$'.dM'.!!!! `.`.`.`. +.`"M"_" MMMMMMMP,MMM ;!>>!!!!!!' <!!!!!!!!!. "MMb $$$$$$$ dM ;!!!!! `.`.`.`. + 'nr;MMMMM"MMMP dMM' >>!(!)<<! <!!!!!!!!!!!. `MM.`$$$$$$ MM !!!!!! `.`.`.`. +",Jn,"". ,uMMP dMMP /)<;>><>' .!!!!!!!!!!!!!!; `Mb $$$$$F;MP !!!!!! `.`.`.`. + dPPM 4MMMMM" dMMP (->;)<><' ;!!!!!!!!!!!!!!!!. 4M $$$$$h M>.!!!!!! `.`.`.`. +=M uMMnMMM" uMMM" <!;/;->;' ;!!!!!!!!!!!!!!!!!; 4M.??"$$',M <!!!!!! `.`.`.`. +JM )MMMM" uMMMM',!>;`(>!>' <!!!!!!!!!!!!!!!!!!! 4M> -??',M' !!!!!!! `.`.`.`. +MM `MP" xdMMMP <(;<:)!`)' <!!!!!!!!!!!!!!!!!!!! MMb - ,M';!!!!!!!' `.`.`.`. +MP ,nMMMMP" (>:)/;<:! !!!!!!!!!!!!!!!!!!!!!! `MM.-= d';!!!!!!!! .`.`.`.`. +,xndMMMMP" .;)`;:`>(;: !!!!!!!!!!!!!!!!!!!!!!!; 4MMnndM <!!!!!!! .`.`.`.`. +MMMMMP" .;(:`-;(.><(' ;!!!!!!!!!!!!!!!!!!!!!!!!!, 4MMMMP !!!!!!!> `.`.`.`.`. +P"" .,;<):(;/(\'>-)' ;!!!!!!!!!!!!!!!!!!!!!!!!!!!>.`"P" <!!!!!!! .`.`.`.`.`. +,<;),<-:><;,<- >;>' ;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!;;<!!!!!!!! .`.`.`.`.`. +)-/;`<:<;\->:(';(' ;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' `.`.`.`.`.`. +:\;`<(.:>-;(;<>: <!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .`.`.`.`.`.`. +(.;>:'<;:<;-/)/ <!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .`.`.`.`.`.`. +;-;:>:.;`;(';' ;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' `.`.`.`.`.`.`. + diff --git a/lib/domains/campus/txt/doh.txt b/lib/domains/campus/txt/doh.txt new file mode 100644 index 0000000..d8111af --- /dev/null +++ b/lib/domains/campus/txt/doh.txt @@ -0,0 +1,16 @@ + DDDDDDDDDDDDD HHHHHHH !!! + D::::::::::::DDD H:::::H !:::! + D:::::::::::::::DD H:::::H !:::! + DDD:::::DDDDD:::::D H:::::H !:::! + D:::::D D:::::D UUUUUU H::::H HHHHH !:::! + D:::::D D:::::D UU::::::UU H::::HH:::::HHH !:::! + D:::::D D:::::D U::::::::::U H::::::::::::::HH !:::! + D:::::D D:::::D U:::::UU:::::U H:::::::HHH::::::H !:::! + D:::::D D:::::D U::::U U::::U H::::::H H::::::H !:::! + D:::::D D:::::D U::::U U::::U H:::::H H:::::H !:::! + D:::::D D:::::D U::::U U::::U H:::::H H:::::H !:! + D:::::D D:::::D U::::U U::::U H:::::H H:::::H !!! + DDD:::::DDDDD:::::D U:::::UU:::::U H:::::H H:::::H + D:::::::::::::::DD U::::::::::U H:::::H H:::::H !!! + D::::::::::::DDD UU::::::UU H:::::H H:::::H !!:!! + DDDDDDDDDDDDD UUUUUU HHHHHHH HHHHHHH !!! diff --git a/lib/domains/campus/txt/dork.txt b/lib/domains/campus/txt/dork.txt new file mode 100644 index 0000000..63b036f --- /dev/null +++ b/lib/domains/campus/txt/dork.txt @@ -0,0 +1,16 @@ + DDDDDDDDDDDDD KKKKKK + D::::::::::::DDD K::::K + D:::::::::::::::DD K::::K + DDD:::::DDDDD:::::D RRRRRR K::::K + D:::::D D:::::D OOOOOO R::::R RRRRR K::::K KKKKKK + D:::::D D:::::D OO::::::OO R::::RR:::::RRR K::::K K::::K + D:::::D D:::::D O::::::::::O R::::::::::::::RR K::::K K::::K + D:::::D D:::::D O:::::OO:::::O R:::::::RRR:::RR K::::KK::::K + D:::::D D:::::D O::::O O::::O R::::::R RRR K:::::::::K + D:::::D D:::::D O::::O O::::O R:::::R K::::::::K + D:::::D D:::::D O::::O O::::O R:::::R K:::::::::K + D:::::D D:::::D O::::O O::::O R:::::R K::::KK::::K + DDD:::::DDDDD:::::D O:::::OO:::::O R:::::R K::::K K::::K + D:::::::::::::::DD O::::::::::O R:::::R K::::K K::::K + D::::::::::::DDD OO::::::OO R:::::R K::::K K::::K + DDDDDDDDDDDDD OOOOOO RRRRRRR KKKKKK KKKKKK diff --git a/lib/domains/campus/txt/duh.txt b/lib/domains/campus/txt/duh.txt new file mode 100644 index 0000000..1167d0f --- /dev/null +++ b/lib/domains/campus/txt/duh.txt @@ -0,0 +1,20 @@ + + +DDDDDDDDDDDDD HHHHHHH ????????? +D::::::::::::DDD H:::::H ?::::::::::? +D:::::::::::::::DD H:::::H ?:::??????:::? +DDD:::::DDDDD:::::D H:::::H ?:::? ?:::? + D:::::D D:::::D UUUUUU UUUUUU H::::H HHHHH ??:?? ?:::? + D:::::D D:::::D U::::U U::::U H::::HH:::::HHH ??? ?:::? + D:::::D D:::::D U::::U U::::U H::::::::::::::HH ?:::? + D:::::D D:::::D UU:::U U::::U H:::::::HHH::::::H ?:::? + D:::::D D:::::D U:::U U::::U H::::::H H::::::H ?:::? + D:::::D D:::::D U:::U U::::U H:::::H H:::::H ?:::? + D:::::D D:::::D U:::U U::::U H:::::H H:::::H ??:?? + D:::::D D:::::D U:::U U::::U H:::::H H:::::H ??? +DDD:::::DDDDD:::::D U::::UU:::::UU H:::::H H:::::H +D:::::::::::::::DD U::::::::::::U H:::::H H:::::H ??? +D::::::::::::DDD UU:::::UU:::U H:::::H H:::::H ??:?? +DDDDDDDDDDDDD UUUUU UUUU HHHHHHH HHHHHHH ??? + + diff --git a/lib/domains/campus/txt/finger.txt b/lib/domains/campus/txt/finger.txt new file mode 100644 index 0000000..ca8586e --- /dev/null +++ b/lib/domains/campus/txt/finger.txt @@ -0,0 +1,13 @@ + /"\ + |\./| + | | + |>*<| + | | + /'\| |/'\ + /'\| | | | + | %%%%% | |\ Get a clue. + | | | | | \ + | * * * * |> > + | / + | / + |_____________/ diff --git a/lib/domains/campus/txt/hi.txt b/lib/domains/campus/txt/hi.txt new file mode 100644 index 0000000..2d7ba8d --- /dev/null +++ b/lib/domains/campus/txt/hi.txt @@ -0,0 +1,17 @@ + ******** ******** ********************* + * ** * ** * ** + * * * * * * * * * + * * * * * * * * * +******** * ******** * ********************* * +******** * ******** * ********************** +******** * ******** * ********************* +******** * ******** * ******** * +*********************** * ******** * +*********************** * ********** ******** +*********************** * * ******** * ** +******** * ******** * * ******** * * * +******** * ******** * * ******** * * +******** * ******** * ********************* * +********* ********* ********************** +******** ******** ********************* + diff --git a/lib/domains/campus/txt/hug.txt b/lib/domains/campus/txt/hug.txt new file mode 100644 index 0000000..e55a1b2 --- /dev/null +++ b/lib/domains/campus/txt/hug.txt @@ -0,0 +1,26 @@ + + +HHHHHHHHHH HHHHHHHHHH UUUUUUUUUU UUUUUUUUUU GGGGGGGGGG +HHHHHHHHHH HHHHHHHHHH UUUUUUUUUU UUUUUUUUUU GGGGGGGGGGGG +HHHHHHHHHH HHHHHHHHHH UUUUUUUUUU UUUUUUUUUU GGGGGGGGGGGGGG +HHHHHHHHHH HHHHHHHHHH UUUUUUUUUU UUUUUUUUUU GGGGGGGGGGGGGGGG +HHHHHHHHHH HHHHHHHHHH UUUUUUUUUU UUUUUUUUUU GGGGGGGGGGGGGGGG +HHHHHHHHHH HHHHHHHHHH UUUUUUUUUU UUUUUUUUUU GGGGG GGGGG +HHHHHHHHHH HHHHHHHHHH UUUUUUUUUU UUUUUUUUUU GGGGG GGGGG +HHHHHHHHHH HHHHHHHHHH UUUUUUUUUU UUUUUUUUUU GGGGG +HHHHHHHHHH HHHHHHHHHH UUUUUUUUUU UUUUUUUUUU GGGGG +HHHHHHHHHHHHHHHHHHHHHHHHH UUUUUUUUUU UUUUUUUUUU GGGGG +HHHHHHHHHHHHHHHHHHHHHHHHH UUUUUUUUUU UUUUUUUUUU GGGGG +HHHHHHHHHHHHHHHHHHHHHHHHH UUUUUUUUUU UUUUUUUUUU GGGGG +HHHHHHHHHHHHHHHHHHHHHHHHH UUUUUUUUUU UUUUUUUUUU GGGGG GGGGGGGG +HHHHHHHHHHHHHHHHHHHHHHHHH UUUUUUUUUU UUUUUUUUUU GGGGG GGGGGGGG +HHHHHHHHHH HHHHHHHHHH UUUUUUUUUU UUUUUUUUUU GGGGG GGGGG +HHHHHHHHHH HHHHHHHHHH UUUUUUUUUU UUUUUUUUUU GGGGG GGGGG +HHHHHHHHHH HHHHHHHHHH UUUUUUUUUU UUUUUUUUUU GGGGG GGGGG +HHHHHHHHHH HHHHHHHHHH UUUUUUUUUUUUUUUUUUUUUUUUU GGGGGGGGGGGGGGGG +HHHHHHHHHH HHHHHHHHHH UUUUUUUUUUUUUUUUUUUUUUU GGGGGGGGGGGGGG +HHHHHHHHHH HHHHHHHHHH UUUUUUUUUUUUUUUUUUUUU GGGGGGGGGGGG +HHHHHHHHHH HHHHHHHHHH UUUUUUUUUUUUUUUUUUU GGGGGGGGGG +HHHHHHHHHH HHHHHHHHHH UUUUUUUUUUUUUUUUU GGGGGGGG + + diff --git a/lib/domains/campus/txt/huh.txt b/lib/domains/campus/txt/huh.txt new file mode 100644 index 0000000..53afbfb --- /dev/null +++ b/lib/domains/campus/txt/huh.txt @@ -0,0 +1,16 @@ +HHHHHHHHHHH HHHHHHHHHHH HHHHHHH ????????? +H:::::::::H H:::::::::H H:::::H ?::::::::::? +H:::::::::H H:::::::::H H:::::H ?:::??????:::? +HHH:::::HHH HHH:::::HHH H:::::H ?:::? ?:::? + H:::::H H:::::H UUUUUU UUUUUU H::::H HHHHH ??:?? ?:::? + H:::::H H:::::H U::::U U::::U H::::HH:::::HHH ??? ?:::? + H:::::HHHHHHHH:::::H U::::U U::::U H::::::::::::::HH ?:::? + H::::::::::::::::::H UU:::U U::::U H:::::::HHH::::::H ?:::? + H::::::::::::::::::H U:::U U::::U H::::::H H::::::H ?:::? + H:::::HHHHHHHH:::::H U:::U U::::U H:::::H H:::::H ?:::? + H:::::H H:::::H U:::U U::::U H:::::H H:::::H ??:?? + H:::::H H:::::H U:::U U::::U H:::::H H:::::H ??? +HHH:::::HHH HHH:::::HHH U::::UU:::::UU H:::::H H:::::H +H:::::::::H H:::::::::H U::::::::::::U H:::::H H:::::H ??? +H:::::::::H H:::::::::H UU:::::UU:::U H:::::H H:::::H ??:?? +HHHHHHHHHHH HHHHHHHHHHH UUUUU UUUU HHHHHHH HHHHHHH ??? diff --git a/lib/domains/campus/txt/jenny/1.txt b/lib/domains/campus/txt/jenny/1.txt new file mode 100644 index 0000000..c6f5ee9 --- /dev/null +++ b/lib/domains/campus/txt/jenny/1.txt @@ -0,0 +1,3 @@ +%^RESET%^Jennybot says, "%^BOLD%^CYAN%^ Ok! I'm going to try to give you some tips so that you can enjoy your visit to the LPC University Virtual Campus. Please note you can deactivate me at any time by typing: %^RED%^deactivate bot%^BOLD%^CYAN%^ + + Also, please remember that I am just a machine, so I will not understand anything you try to tell me. I will pause between tips, to give you time to read, or to deactivate me. As I continue, my tips will gain in technical complexity, so even if you are an experienced "MUDder", you may gain some benefit from listening to me.%^RESET%^" diff --git a/lib/domains/campus/txt/jenny/10.txt b/lib/domains/campus/txt/jenny/10.txt new file mode 100644 index 0000000..b115613 --- /dev/null +++ b/lib/domains/campus/txt/jenny/10.txt @@ -0,0 +1,3 @@ +%^RESET%^Jennybot says, "%^BOLD%^CYAN%^ In some cases, other people in the same room as you might have apples. The MUD might not be sure whether you mean your own apple or someone else's. In this case, you want to get more specific: "%^RED%^eat my apple%^BOLD%^CYAN%^", or "%^RED%^eat first apple%^BOLD%^CYAN%^". + + If a command doesn't work one way, try it another way. If the MUD doesn't understand "%^RED%^shoot jennybot%^BOLD%^CYAN%^", try "%^RED%^shoot jennybot with gun%^BOLD%^CYAN%^" or maybe "%^RED%^shoot my squirt gun at jennybot%^BOLD%^CYAN%^".%^RESET%^" diff --git a/lib/domains/campus/txt/jenny/11.txt b/lib/domains/campus/txt/jenny/11.txt new file mode 100644 index 0000000..cc489dd --- /dev/null +++ b/lib/domains/campus/txt/jenny/11.txt @@ -0,0 +1,3 @@ +%^RESET%^Jennybot says, "%^BOLD%^CYAN%^ Other very common commands are "%^RED%^score%^BOLD%^CYAN%^" to let you know your general condition, and "%^RED%^status%^BOLD%^CYAN%^" to give you a specific readout of your health and stamina. hp are health points, and it they reach zero, your body dies. + + Sp are stamina points. If they reach zero, you will be unable to do anything for a while, until you rest and your strength returns. Mp are mana points, which are a little too complicated for me to explain right now. If you don't already know what they are, you don't have to worry about them. Just trust me on that.%^RESET%^" diff --git a/lib/domains/campus/txt/jenny/12.txt b/lib/domains/campus/txt/jenny/12.txt new file mode 100644 index 0000000..e0dbcbc --- /dev/null +++ b/lib/domains/campus/txt/jenny/12.txt @@ -0,0 +1,9 @@ +%^RESET%^Jennybot says, "%^BOLD%^CYAN%^ Ok, we're coming close to the end of my speech here. Whew! + + There are two kinds of living beings you will encounter on LPC University. The first are called "player characters". They are players like you: human beings manipulating their virtual bodies and using the MUD as a way to communicate. + + The other kind are "non-player character". This kind of living being is most often referred to as an "NPC". I am an example of an NPC. Although I am talking to you, this body is under the control of the MUD program. I can't talk to you about the latest reality TV show or your favorite performer...because the MUD is just a program and doesn't understand such things. + + NPC's are a way for the MUD to provide the virtual environment some added realism. If you walk through a forest, you might expect to see birds, or rabbits, or foxes. When NPC's arrive in your environment, or you arrive in theirs, you can interact with them...but only up to a point. There isn't a person controlling their bodies...just the MUD simulating a living being. + + NPC's are sometimes referred to as MOB's or mobiles, because they often can wander from one place to another in this virtual environment.%^RESET%^" diff --git a/lib/domains/campus/txt/jenny/13.txt b/lib/domains/campus/txt/jenny/13.txt new file mode 100644 index 0000000..87250e6 --- /dev/null +++ b/lib/domains/campus/txt/jenny/13.txt @@ -0,0 +1,3 @@ +%^RESET%^Jennybot says, "%^BOLD%^CYAN%^ Some NPC's fill specific roles. For example, if you go to the campus bookstore, you will be able to buy and sell some things. Kim, the shopkeeper, can respond to various requests, such as "%^RED%^list%^BOLD%^CYAN%^" to see what's for sale, "%^RED%^appraise hat%^BOLD%^CYAN%^" to see what she thinks your hat is worth and "%^RED%^sell hat to kim%^BOLD%^CYAN%^" to exchange your headgear for money. If you think you need a backpack and you've got the funds, try "%^RED%^buy first backpack from kim%^BOLD%^CYAN%^". To know how much money you have, type: "%^RED%^money%^BOLD%^CYAN%^". + + Some vendors will only handle specific kinds of things. Kim will not buy or sell weapons or food. Gloria in the snack bar, though, will vend food but not buy or sell anything else.%^RESET%^" diff --git a/lib/domains/campus/txt/jenny/14.txt b/lib/domains/campus/txt/jenny/14.txt new file mode 100644 index 0000000..0fe158c --- /dev/null +++ b/lib/domains/campus/txt/jenny/14.txt @@ -0,0 +1,5 @@ +%^RESET%^Jennybot says, "%^BOLD%^CYAN%^ There are some players who have the title "creator", "wizard", or "arch". These are the people who work on and with the technical parts of the MUD program. They are the folks who use the LPC programming language to create environments and NPC's, and make sure that a box behaves like a box. + + If you think you'd like to learn some LPC programming and join the LPC University staff let us know. Go to the mail room and mail the administrator. + + Be aware that it's fun, but it really is programming, with functions and variables and everything.%^RESET%^" diff --git a/lib/domains/campus/txt/jenny/15.txt b/lib/domains/campus/txt/jenny/15.txt new file mode 100644 index 0000000..3c15a15 --- /dev/null +++ b/lib/domains/campus/txt/jenny/15.txt @@ -0,0 +1,13 @@ +%^RESET%^Jennybot says, "%^BOLD%^CYAN%^ Well, that about wraps it up for my spiel. Thank you for listening. If you get stuck or confused type "%^RED%^help%^BOLD%^CYAN%^" to enter the system help menus. + + If other players are in this room, you can communicate by typing: "%^RED%^say blah blah blah%^BOLD%^CYAN%^". Everyone in the same room will hear your conversation. + + + If you know someone is logged in but they are not in the same room, you can communicate by typing: "%^RED%^tell joey blah blah blah%^BOLD%^CYAN%^". This is a private communication channel and you can also use it if you're in the same room and you want to discuss things you'd rather not share with bystanders. + + Oh, speaking of privacy...you don't have any. The University reserves the right to review, monitor, etc, yakety schmakety. + + Point is, anything that really really needs to stay private, still needs to be discussed face to face, in the real world. + + + Have fun exploring!%^RESET%^" diff --git a/lib/domains/campus/txt/jenny/2.txt b/lib/domains/campus/txt/jenny/2.txt new file mode 100644 index 0000000..9fbe218 --- /dev/null +++ b/lib/domains/campus/txt/jenny/2.txt @@ -0,0 +1,5 @@ +%^RESET%^Jennybot says, "%^BOLD%^CYAN%^ First, the most basic stuff: Your computer is connected to our computer via the Internet. This connection is kind of like the World Wide Web, except, as you see, there are no pictures. Just text. + + When you connected to our computer, you logged on to a program we are running. This program is what the LPC University Virtual Campus is made of. + + LPC University is a MUD, which is kind of like a chat program, where you type stuff and can communicate with other people. When I refer to "the MUD", I'm talking about that program. MUD stands for "Multi User Domain".%^RESET%^" diff --git a/lib/domains/campus/txt/jenny/3.txt b/lib/domains/campus/txt/jenny/3.txt new file mode 100644 index 0000000..472484c --- /dev/null +++ b/lib/domains/campus/txt/jenny/3.txt @@ -0,0 +1,7 @@ +%^RESET%^Jennybot says, "%^BOLD%^CYAN%^ The big difference between LPC University and Internet chat programs is that here you can interact with the program itself, not just the people connected to it. + + When you interact with the program, or MUD, the program pretends that you have a body inside the program. That is your virtual body. When you enter a command, the MUD interprets this as your virtual body trying to do something. + + For example, right now the program is pretending that your body is inside a room called the "Admissions office". If you type: "%^RED%^look%^BOLD%^CYAN%^" (without quotation marks) and hit enter, you will be given a description of the room as if your virtual body was looking around. + + "%^RED%^look%^BOLD%^CYAN%^" is a command, and you can use different commands to get your virtual body to do things within this virtual environment. The MUD will tell you how your action affects your environment, and it will also tell you if it didn't understand what you meant.%^RESET%^" diff --git a/lib/domains/campus/txt/jenny/4.txt b/lib/domains/campus/txt/jenny/4.txt new file mode 100644 index 0000000..ef1c34b --- /dev/null +++ b/lib/domains/campus/txt/jenny/4.txt @@ -0,0 +1,5 @@ +%^RESET%^Jennybot says, "%^BOLD%^CYAN%^ I've just given you a note. It is now in the inventory of virtual items your virtual body is carrying. To get a list of items you are carrying, type "%^RED%^inventory%^BOLD%^CYAN%^". I've given you this note so you can read it. It contains various MUD commands you will find useful. Type "%^RED%^read note%^BOLD%^CYAN%^". + + Ok, from now on, when you log on, you will be carrying this note on you, and you can use it as a reference if you get stuck. Of course, if you "%^RED%^drop note%^BOLD%^CYAN%^", then it will fall to the floor, and you will no longer have it. You might be able to read it, or you might not. If you leave the room, you won't be able to read it. + + Now that you have a general idea of how to do some stuff, let me give you another command that you might find useful. My tips are prerecorded messages, and you might not like the pauses between messages. To skip to the next tip, type "%^RED%^next tip%^BOLD%^CYAN%^".%^RESET%^" diff --git a/lib/domains/campus/txt/jenny/5.txt b/lib/domains/campus/txt/jenny/5.txt new file mode 100644 index 0000000..93e2d78 --- /dev/null +++ b/lib/domains/campus/txt/jenny/5.txt @@ -0,0 +1,7 @@ +%^RESET%^Jennybot says, "%^BOLD%^CYAN%^ When you finally do decide to leave this room and explore other areas of LPC University, you will use commands like "%^RED%^go north%^BOLD%^CYAN%^", "%^RED%^open door%^BOLD%^CYAN%^", or "%^RED%^climb tree%^BOLD%^CYAN%^". When you move to a new location, a description of that new place will be provided. + + Right now, because you are new, you are limited to exploring the rooms inside this building, the LPC University Virtual Campus Administration Building. This way, you can move around and get used to your new body without fear of getting lost or injured. + + Yes, your body can sustain injury. In trying to provide the illusion of a virtual reality, the realities of injury, sickness, and even death are possible for your virtual body to experience. + + Not while you're in this building, though.%^RESET%^" diff --git a/lib/domains/campus/txt/jenny/6.txt b/lib/domains/campus/txt/jenny/6.txt new file mode 100644 index 0000000..3ec5fd1 --- /dev/null +++ b/lib/domains/campus/txt/jenny/6.txt @@ -0,0 +1 @@ +%^RESET%^Jennybot says, "%^BOLD%^CYAN%^ Here's a map of this building. Type "%^RED%^read map%^BOLD%^CYAN%^"%^RESET%^" diff --git a/lib/domains/campus/txt/jenny/7.txt b/lib/domains/campus/txt/jenny/7.txt new file mode 100644 index 0000000..c79487e --- /dev/null +++ b/lib/domains/campus/txt/jenny/7.txt @@ -0,0 +1,7 @@ +%^RESET%^Jennybot says, "%^BOLD%^CYAN%^ As you can see, there aren't too many rooms available to you right now. There are many other places the MUD can take you to, though, once you know your way around. You might even be able to sneak out of the building, and visit the virtual world outside it. + + The MUD understands some convenient abbreviations. Instead of "%^RED%^go south%^BOLD%^CYAN%^" you can just type "%^RED%^s%^BOLD%^CYAN%^", and your command will be understood. Similarly, "%^RED%^i%^BOLD%^CYAN%^" will show you the inventory of items you are carrying. + +Other common commands are "%^RED%^who%^BOLD%^CYAN%^" to see who else is logged on, "%^RED%^quit%^BOLD%^CYAN%^" to leave the mud, "%^RED%^drop%^BOLD%^CYAN%^" and "%^RED%^get%^BOLD%^CYAN%^", as in "%^RED%^drop map%^BOLD%^CYAN%^", and "%^RED%^get map%^BOLD%^CYAN%^". + +If you get articles of clothing or jewelry they can be worn, as in "%^RED%^wear hat%^BOLD%^CYAN%^".%^RESET%^" diff --git a/lib/domains/campus/txt/jenny/8.txt b/lib/domains/campus/txt/jenny/8.txt new file mode 100644 index 0000000..cb4c1eb --- /dev/null +++ b/lib/domains/campus/txt/jenny/8.txt @@ -0,0 +1,13 @@ +%^RESET%^Jennybot says, "%^BOLD%^CYAN%^ To examine items more closely, such as a hat, you can type "%^RED%^exa hat%^BOLD%^CYAN%^" or "%^RED%^look at hat%^BOLD%^CYAN%^", or even "%^RED%^l hat%^BOLD%^CYAN%^". + + Some objects can contain other objects, like bags or boxes. If you examine such a container, you will get a description of its exterior. To know what is in it, you must, for example, "%^RED%^look in bag%^BOLD%^CYAN%^". + + To remove something from its container, the command might be "%^RED%^get gun from bag%^BOLD%^CYAN%^" + + Now, we don't promote violence as a positive thing here. That's just a squirt gun in the bag, and nobody can get hurt with it. + + On the outside, you might need a real weapon to defend yourself, as you might in real life. + + Weapons typically must be wielded to be used. For example "%^RED%^wield squirt gun%^BOLD%^CYAN%^" would enable you to shoot it, and "%^RED%^shoot squirt gun at jennybot%^BOLD%^CYAN%^" would discharge the weapon. + + We strongly discourage the use of lethal force within the administrative building. Attacks are automatically prevented here, and attempted attacks can lead to MUD punishment.%^RESET%^" diff --git a/lib/domains/campus/txt/jenny/9.txt b/lib/domains/campus/txt/jenny/9.txt new file mode 100644 index 0000000..0b1c7b9 --- /dev/null +++ b/lib/domains/campus/txt/jenny/9.txt @@ -0,0 +1,7 @@ +%^RESET%^Jennybot says, "%^BOLD%^CYAN%^ The manipulation of these virtual objects is usually a pretty intuitive process. The "%^RED%^examine thing%^BOLD%^CYAN%^" description usually gives you the clues you need to use a thing. + +Sometimes, though, you have more than one of a similar object. If you're carrying two apples, for example, you might want to specify which one you want to eat. + +You don't want to make yourself sick by eating the rotten apple, but if you just type "%^RED%^eat apple%^BOLD%^CYAN%^", the MUD doesn't know which one you mean. Usually your command won't be executed, and you will be asked which one of the objects you mean. + +In this case, let's get rid of the bad apple. type "%^RED%^put rotten apple in bin%^BOLD%^CYAN%^". There is a recycling bin here, where all kinds of objects can be vaporized and their bits reused. Don't worry, living beings can't enter it.%^RESET%^" diff --git a/lib/domains/campus/txt/jenny/spiel.txt b/lib/domains/campus/txt/jenny/spiel.txt new file mode 100644 index 0000000..c929804 --- /dev/null +++ b/lib/domains/campus/txt/jenny/spiel.txt @@ -0,0 +1 @@ +%^BOLD%^CYAN%^! I'm Jenny, the LPC University automated guide bot. If you'd like an orientation on this place, type: %^RESET%^ diff --git a/lib/domains/campus/txt/lisa.txt b/lib/domains/campus/txt/lisa.txt new file mode 100644 index 0000000..e3e822e --- /dev/null +++ b/lib/domains/campus/txt/lisa.txt @@ -0,0 +1,47 @@ +iIYVVVVXVVVVVVVVVYVYVYYVYYYYIIIIYYYIYVVVYYYYYYYYYVVYVVVVXVVVVVYI+. +tYVXXXXXXVXXXXVVVYVVVVVVVVVVVVYVVVVVVVVVVVVVVVVVXXXXXVXXXXXXXVVYi. +iYXRXRRRXXXXXXXXXXXVVXVXVVVVVVVVXXXVXVVXXXXXXXXXXXXXXRRRRRRRRRXVi. +tVRRRRRRRRRRRRRRRXRXXXXXXXXXXXXXXRRXXXXRRRRXXXXXXXRRRRRRRRRRRRXV+. +tVRRBBBRMBRRRRRRRRRXXRRRRRXt=+;;;;;==iVXRRRRXXXXRRRRRRRRMMBRRRRXi, +tVRRBMBBMMBBBBBMBBRBBBRBX++=++;;;;;;:;;;IRRRRXXRRRBBBBBBMMBBBRRXi, +iVRMMMMMMMMMMMMMMBRBBMMV==iIVYIi=;;;;:::;;XRRRRRRBBMMMMMMMMBBRRXi. +iVRMMMMMMMMMMMMMMMMMMMY;IBWWWWMMXYi=;:::::;RBBBMMMMMMMMMMMMMMBBXi, ++VRMMRBMMMMMMMMMMMMMMY+;VMMMMMMMRXIi=;:::::=VVXXXRRRMMMMMMMMBBMXi; +=tYYVVVXRRRXXRBMMMMMV+;=RBBMMMXVXXVYt;::::::ttYYVYVVRMMMMMMBXXVI+= +;=tIYYVYYYYYYVVVMMMBt=;;+i=IBi+t==;;i;::::::+iitIIttYRMMMMMRXVVI=; +;=IIIIYYYIIIIttIYItIt;;=VVYXBIVRXVVXI;::::::;+iitttttVMMBRRRVVVI+, +;+++tttIttttiiii+i++==;;RMMMBXXMMMXI+;::::::;+ittttitYVXVYYIYVIi;; +;===iiittiiIitiii++;;;;:IVRVi=iBXVIi;::::::::;==+++++iiittii+++=;; +;;==+iiiiiiiiii+++=;;;;;;VYVIiiiVVt+;::::::::;++++++++++iti++++=;; +;;=++iiii+i+++++iii==;;;::tXYIIYIi+=;:::::,::;+++++++++++++++++=;; +;;;+==+ii+++++iiiiit=;;:::::=====;;;::::::::::+++i+++++++++i+++;;; +;;;==+=+iiiiitttIIII+;;;:,::,;;;;:;=;;;::,::::=++++++++==++++++;;; +:;====+tittiiittttti+;;::::,:=Ytiiiiti=;:::::,:;;==ii+ittItii+==;; +;;+iiittIti+ii;;===;;:;::::;+IVXVVVVVVt;;;;;::::;;===;+IIiiti=;;;; +;=++++iIti+ii+=;;;=;:::;;+VXBMMBBBBBBXY=;=;;:::::;=iYVIIttii++;;;; +;;++iiiItttIi+++=;;:::;=iBMMMMMMMMMMMXI==;;,::;;:;;=+itIttIIti+;;; +;=+++++i+tYIIiii;:,::;itXMMMMMMMMMMMBXti==;:;++=;:::::;=+iittti+;; +;;+ii+ii+iitiIi;::::;iXBMMMMMWWWWWMMBXti+ii=;::::,,,,:::=;==+tI+;; +;;iiiitItttti;:::;::=+itYXXMWWWWWWMBYt+;;::,,,,,,,,,,,,,:==;==;;;; +:;=iIIIttIt+:;:::;;;==;+=+iiittttti+;;:,:,,,,::,,,,,,,,:::;=;==::; +;::=+ittiii=;:::::;;;:;:;=++==;;==;:,,,,,,:;::::,,,,,,,,::;==;;::; +:::;+iiiii=;::::,:;:::::;;:;;::;:::,,,,,,,:::;=;;;:,,,,,:::;;::::; +:;;iIIIIII=;:::,:::::::,::::,:::,,,,,,,,,,,:;;=;:,,,,,,::::;=;:::; +:;==++ii+;;;:::::::::::,,,,,,::,,,,,,,,,,,::::,,,,,,,,,,:,:::::::; +::;;=+=;;;:::;;::,,,,,,,,,,,,,,,,,,,,,,,,,:,,,,,,,,,,,,,,,,,:::::; +::;=;;;:;:::;;;;::,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::,,::::; +:;;:;::::::,::,,:,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::; +:::::::::::;;;:,,,,,,,,,,,,,...,...,,,.,,,,,,,,,,,,.,,,,,,,,,,,,:; +::::::::;=;;;;;::,,,,,,,,,,,.......,...,,,,,,,,,,,,.,,,,,,,,,,,,,; +:::::,,:;=;;;;;;;iVXXXVt+:,,....,,,,....,.,,,,,,,.,.....,,,,,,,,:; +:,,::,,:::;;;;;;=IVVVXXXXVXVt:,,,,,..,..,,,,.,,,,,..,.,,,,,,,,,,,; +::,::,,,:,:::::,::;=iIYVXVVVVIYIi;,,.,.,,,::,,,,,,,,,,,,,,,,,,,,,. +:,,,,,,,,,,,,,,,,::;+itIIIIIIi:;;i++=;;;;;;;;;::,,,...,,..,,,,,,,. +:,,,,,,,,,,,,,,=iitVYi++iitt==it;;:;;;;::;;::::,,,......,,,,,,,::. +::,,,,,,,,,,,,,++iiIVIi=;;=;+i;:;+:::,,,,,,,,,,,,,.....,,,,,,,,::, +,,,,,,,,,,,,,,,;=+it=:::,,,,,,,,,,.,......,,.,..........,,,,,,,,:: +:,,,,,,,,,,,,,,,,:=:,,,,,,,,,,,,,,......................,.,,.,.,,: +:,,,,,,,,,,,,,,,,,:,,,,,,,,,,..,........................,..,...,,: +,,,,,,,,,,,,,,,,,,,.....................................,.......,, +,,,,,,,,,.,,,,,,,...............................................,, +itittiiiii+=++=;;=iiiiiiittiiiiii+iii===;++iiitiiiiiii+=====+ii=+i diff --git a/lib/domains/campus/txt/map.txt b/lib/domains/campus/txt/map.txt new file mode 100644 index 0000000..251be06 --- /dev/null +++ b/lib/domains/campus/txt/map.txt @@ -0,0 +1,21 @@ + + N + | + | + W --------- E LPC University Virtual Campus Administrative Building + | + | + S ------------- ------------ ------------- + | mail room | |snack bar | | bookstore | + ------------- ------------ ------------- +----------- | | | +| Outside |------------------------------------------------------ +----------- | | | | + ------------- ------------- --------- ------------------- + | stairwell | |admissions | |lounge | | conference room | + ------------- ------------- --------- ------------------- + + Please note that you are safe inside this building, but going +to The Outside may be hazardous if you are not adequately prepared. + + diff --git a/lib/domains/campus/txt/note.txt b/lib/domains/campus/txt/note.txt new file mode 100644 index 0000000..ab9dd18 --- /dev/null +++ b/lib/domains/campus/txt/note.txt @@ -0,0 +1,37 @@ +Common player commands: +--------------- +look, l +inventory, i +help +score +status +who +tell (example: "tell mike where are you?") +say, ' (example: "' hi", "say nice to meet you!) + +Common object commands: +----------------------- +look at, look in (example: "l in treasure chest") +examine, exa +get, drop (example: "get bag", "get all from box") +open, close (example: "open door", "open glass case") +read (example: "read writing on cap") +put (example: "put red ball in my first bag") + +Common Movement commands: +------------------------- +n,s,e,w,u,d +go north, go south, go east, go west, go up, go down +out, go out +crawl (example: "crawl south", "crawl into passageway" ) +climb (example: "climb tree") +enter (example: "enter crawlspace") + +Vendor commands: +---------------- +money +appraise +price +show +buy, sell + diff --git a/lib/domains/campus/txt/rose.txt b/lib/domains/campus/txt/rose.txt new file mode 100644 index 0000000..00ead6a --- /dev/null +++ b/lib/domains/campus/txt/rose.txt @@ -0,0 +1,88 @@ + + + "M, .mM" + IMIm ,mIM" + ,MI:"IM,mIMm + "IMmm, ,IM::::IM::IM, ,m" + "IMMIMMIMm::IM:::::IM""==mm + ,mIM::::::MIM:::::::IM::::mIMIM" + ,mMIMIMIIMIMM::::::::mM::::::::IMIMI + IMM:::::::::IMM::::::M::::::::IIM:::::::MM, + "IMM::::::::::MM:::M:::::::IM:::::::::::IM, + "IMm::::::::IMMM:::::::IM:::::::::::::IM, + "Mm:::::::::IM::::::MM::::::::::::::::IM, + IM:::::::::IM::::::MM::::::::::::::::::IM, + MM::::::::IM:::::::IM::::::::::::::::::IM + "IM::::::::IM:::::::IM:::::::::::::::::IM;. + "IM::::::::MM::::::::IM::::::::::mmmIMMMMMMMm,. + IM::::::::IM:::::::IM::::mIMIMM"""". .. "IMMMM + "IM::::::::IM::::::mIMIMM"". . . . . .,mM" + IMm:::::::IM::::IIMM" . . . . . ..,mMM" + "IMMIMIMMIMM::IMM" . . . ._.,mMM + ,IM". . ."IMIM". . . .,mMMMMMMMM" + ,IM . . . .,IMM". . . ,mMMMMMMMMM" + IM. . . .,mIIMM,. . ..mMMMMMMMMM + ,M"..,mIMMIMMIMMIMmmmMMMMM + IM.,IMI""" ""IIMMMMMMMMMM + ;IMIM" ""IMMMMMMM + "" "IMMMMM + "IMMM + "IMM, + "IMM + "MM, + IMM, + "IMM .mIMMIMMIMMIMMIM, + .,mIMMIMMIMM, ,mIMM, IMM""" ,mIM". . . . . . . " + ,IMMM' . . . "IMM.\ "M, IMM ,IM". . . . / :;IM \ M, + .mIM' . . . / .:"IM.\ MM "MM, ,M". . . / .;mIMIMIM,\ M + ,IM'. . . / . .:;,IMIMIMMM IMM ,M". . / .:mIM"' "IM,:M + ,IM'. . . / . .:;,mIM" `"IMM IMM IM. . / .mM" "IMI + ,IM . . / . .:;,mIM" "IMMMMM MM,. / ,mM "M' + IM'. . / . .;,mIM" "IIMMM ,IMIM,.,IM" + IM . . / . .,mIM" IMMMMMMM' """ + `IM,. / ;,mIM" IIMMM + "IMI, /,mIM" __IMMM + "IMMMM" """IMM + "" IMM + " IMM__ + IMM""" + IMM + IMM + IMM + """IMM + IMM + IMM + IMM""" + IMM + IMM + """IMM + IMM + IMM + IMM""" + IMM + """IMM + IMM + IMM__ + IMM""" + IMM + IMM + IMM + "IMM .mIMMIMMIMMIMMIM, + .,mIMMIMMIMM, ,mIMM, IMM""" ,mIM". . . . . . . " + ,IMMM' . . . "IMM.\ "M, IMM ,IM". . . . / :;IM \ M, + .mIM' . . . / .:"IM.\ MM "MM, ,M". . . / .;mIMIMIM,\ M + ,IM'. . . / . .:;,IMIMIMMM IMM ,M". . / .:mIM"' "IM,:M + ,IM'. . . / . .:;,mIM" `"IMM IMM IM. . / .mM" "IMI + ,IM . . / . .:;,mIM" "IMMMMM MM,. / ,mM "M' + IM'. . / . .;,mIM" "IIMMM ,IMIM,.,IM" + IM . . / . .,mIM" IMMMMMMM' """ + `IM,. / ;,mIM" IIMMM + "IMI, /,mIM" __IMMM + "IMMMM" """IMM + "" IMM + " IMM__ + IMM""" + IMM + IMM + IMM + \ diff --git a/lib/domains/campus/txt/skulls.txt b/lib/domains/campus/txt/skulls.txt new file mode 100644 index 0000000..1b4cd19 --- /dev/null +++ b/lib/domains/campus/txt/skulls.txt @@ -0,0 +1,23 @@ + + + * * + * * + ** ** + * ** ** * + ** ** * * ** ** + *** * ** ** * *** + **** ********************************* **** + ******* *** ******* *** ******* + ************ ***** ************ + ********** **** * ** ** ******* ********** + ********** ** ** ** **************** + *************** ** ** *** ** ***************** + ****** ********************* ****** ****** + ********************** *** + ************************ ** + **** ** ** **** ** ** ** + *** * * ** * * *** + ** ** + * * + + diff --git a/lib/domains/campus/txt/spam.txt b/lib/domains/campus/txt/spam.txt new file mode 100644 index 0000000..51c4d0a --- /dev/null +++ b/lib/domains/campus/txt/spam.txt @@ -0,0 +1,20 @@ + ========================================== + | ,dP""8a "888888b, d8b "888b ,888" | + | 88b " 888 d88 dPY8b 88Y8b,8888 | + | `"Y8888a 888ad8P'dPaaY8b 88 Y88P888 | + | a, Y88 888 dP Y8b 88 YP 888 | + | `"8ad8P'a888a a88a;*a888aa88a a888a | + | ;*;;;;*;;;*;;;*,, | + | _,---'':::';*;;;*;;;*;;*d;, | + | .-' ::::::::::';*;;*;dII; | + | .' ,<<<,. :::::::::::::::ffffff`. | + | / ,<<<<<<<<,::::::::::::::::fffffI,\ | + | .,<<<<<<<<<<I;:::::::::::::::ffffKIP", | + | |<<<<<<<<<<dP;,?>;,::::::::::fffKKIP | | + | ``<<<<<<<dP;;;;;\>>>>>;,::::fffKKIPf ' | + | \ `mYMMV?;;;;;;;\>>>>>>>>>,YIIPP"` / | + | `. "":;;;;;;;;;i>>>>>>>>>>>>>, ,' | + | `-._``":;;;sP'`"?>>>>>=========. | + | `---..._______...|<[Hormel | | + | `=========' | + ========================================== diff --git a/lib/domains/campus/txt/warning.txt b/lib/domains/campus/txt/warning.txt new file mode 100644 index 0000000..14bd7c9 --- /dev/null +++ b/lib/domains/campus/txt/warning.txt @@ -0,0 +1,11 @@ +WARNING! WARNING! WARNING! WARNING! + + If you go west of here, you will be leaving the Virtual +Campus administrative building. The special rules of non-aggression that +are enforced within the building do not apply outside. The people +you meet may be friendly, or they may not be. + + Be courteous to other players, and be prepared to deal +with strange and unexpected situations. + +HAVE FUN! diff --git a/lib/domains/campus/weap/357pistol.c b/lib/domains/campus/weap/357pistol.c new file mode 100644 index 0000000..abae903 --- /dev/null +++ b/lib/domains/campus/weap/357pistol.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <vendor_types.h> +inherit "/lib/pistol"; + +void create(){ + pistol::create(); + SetKeyName("revolver"); + SetId(({"gun","pistol","piece"})); + SetAdjectives(({".357","357","magnum"})); + SetShort("a .357 magnum revolver"); + SetLong("This is a thick, heavy chunk of weaponry that fires some very "+ + "serious rounds. Bullets are loaded individually into it, and they, along with spent "+ + "shells, remain in the cylinder until unloaded."); + SetCaliber(357); + SetFirearmType("revolver"); + SetAmmoType("magnum"); + SetMaxAmmo(6); + SetMass(20); + SetDollarCost(10); + SetVendorType(VT_WEAPON); + SetMagnum(30); +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/weap/9mil.c b/lib/domains/campus/weap/9mil.c new file mode 100644 index 0000000..3fbfc14 --- /dev/null +++ b/lib/domains/campus/weap/9mil.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_PISTOL; +void create(){ + ::create(); + SetKeyName("gun"); + SetId(({"gun","pistol"})); + SetAdjectives(({"9mm","automatic","9 millimeter","semiautomatic"})); + SetShort("a 9 millimeter semiautomatic pistol"); + SetLong("This is a large, semiautomatic pistol that fires 9mm rounds. It is "+ + "a heavy, serious-looking weapon."); + SetMillimeter(9); + SetFirearmType("auto"); + SetAmmoType("acp"); + SetMass(30); + SetDollarCost(900); + SetVendorType(VT_WEAPON); +} diff --git a/lib/domains/campus/weap/9mmpistol.c b/lib/domains/campus/weap/9mmpistol.c new file mode 100644 index 0000000..995dd59 --- /dev/null +++ b/lib/domains/campus/weap/9mmpistol.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <vendor_types.h> +inherit "/lib/pistol"; +void create(){ + pistol::create(); + SetKeyName("gun"); + SetId(({"gun","pistol"})); + SetAdjectives(({"9mm","automatic","9 millimeter","semiautomatic"})); + SetShort("a 9 millimeter semiautomatic pistol"); + SetLong("This is a large, semiautomatic pistol that fires 9mm rounds. It is "+ + "a heavy, serious-looking weapon."); + SetMillimeter(9); + SetFirearmType("auto"); + SetAmmoType("acp"); + SetMass(30); + SetDollarCost(3000); + SetVendorType(VT_WEAPON); +} diff --git a/lib/domains/campus/weap/9mmpistol_loaded.c b/lib/domains/campus/weap/9mmpistol_loaded.c new file mode 100644 index 0000000..7c9721f --- /dev/null +++ b/lib/domains/campus/weap/9mmpistol_loaded.c @@ -0,0 +1,33 @@ +#include <lib.h> +#include <vendor_types.h> +inherit "/lib/pistol"; + +int AddClip(); +void create(){ + pistol::create(); + SetKeyName("gun"); + SetId(({"gun","pistol"})); + SetAdjectives(({"9mm","automatic","9 millimeter","semiautomatic"})); + SetShort("a 9 millimeter semiautomatic pistol"); + SetLong("This is a large, semiautomatic pistol that fires 9mm rounds. It is "+ + "a heavy, serious-looking weapon."); + SetMillimeter(9); + SetFirearmType("auto"); + SetAmmoType("acp"); + SetMass(30); + SetDollarCost(3000); + SetVendorType(VT_WEAPON); + AddClip(); + SetLoaded(1); + SetAmmo(15); + SetMag(1); +} +int AddClip(){ + if(!present("clip",this_object())){ + new("/domains/campus/obj/9mmclip")->eventMove(this_object()); + } + return 1; +} +void init(){ + ::init(); +} diff --git a/lib/domains/campus/weap/9mmpistol_mp.c b/lib/domains/campus/weap/9mmpistol_mp.c new file mode 100644 index 0000000..b120147 --- /dev/null +++ b/lib/domains/campus/weap/9mmpistol_mp.c @@ -0,0 +1,39 @@ +#include <lib.h> +#include <vendor_types.h> +inherit "/lib/pistol"; +int AddClip(); +void CheckMP(); +void create(){ + pistol::create(); + SetKeyName("gun"); + SetId(({"gun","pistol"})); + SetAdjectives(({"9mm","automatic","9 millimeter","semiautomatic"})); + SetShort("a 9 millimeter semiautomatic pistol"); + SetLong("This is a large, semiautomatic pistol that fires 9mm rounds. It is "+ + "a heavy, serious-looking weapon."); + SetMillimeter(9); + SetFirearmType("auto"); + SetAmmoType("acp"); + SetMass(30); + SetDollarCost(3000); + SetVendorType(VT_WEAPON); +} + +void init() { + pistol::init(); + CheckMP(); +} + +int AddClip(){ + new("/domains/campus/obj/9mmclip")->eventMove(this_object()); + return 1; +} + +void CheckMP(){ + if(base_name(environment(this_object())) == "/domains/campus/npc/mp"){ + AddClip(); + SetLoaded(1); + SetAmmo(15); + SetMag(1); + } +} diff --git a/lib/domains/campus/weap/board.c b/lib/domains/campus/weap/board.c new file mode 100644 index 0000000..9228af2 --- /dev/null +++ b/lib/domains/campus/weap/board.c @@ -0,0 +1,28 @@ +/* /domains/Examples/weapon/sword.c + * from the Dead Souls LPC Library + * a simple sword example, nothing fancy + * created by Descartes of Borg 950402 + */ + +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("board of ed"); + SetId(({"board","board of ed","board of education"})); + SetAdjectives(({"ed","education"})); + SetShort("the board of education"); + SetLong("A long, wide wooden board with a handle at one "+ + "end. Inscribed along its length are the words: "+ + "'Board of Education'."); + SetMass(50); + SetDollarCost(20); + SetVendorType(VT_WEAPON); + SetClass(20); + SetDamageType(BLUNT); + SetWeaponType("blunt"); +} diff --git a/lib/domains/campus/weap/crowbar.c b/lib/domains/campus/weap/crowbar.c new file mode 100644 index 0000000..b2f2db4 --- /dev/null +++ b/lib/domains/campus/weap/crowbar.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create(){ + item::create(); + SetKeyName("crowbar"); + SetId( ({ "rod" }) ); + SetAdjectives( ({ "heavy", "iron"}) ); + SetShort("a crowbar"); + SetLong("This is heavy iron rod with specialized ends for prying " + "things open."); + SetVendorType(VT_WEAPON); + SetClass(20); + SetBaseCost("silver",150); + SetMass(100); + SetWeaponType("blunt"); + SetHands(1); + SetDamageType(BLUNT); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/weap/dagger.c b/lib/domains/campus/weap/dagger.c new file mode 100644 index 0000000..72bf636 --- /dev/null +++ b/lib/domains/campus/weap/dagger.c @@ -0,0 +1,26 @@ +/* /domains/Examples/weapon/dagger.c + * from the Dead Souls LPC Library + * a simple dagger example, nothing fancy + * created by Descartes of Borg 950402 + */ + +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("sharp dagger"); + SetId( ({ "dagger"})); + SetAdjectives( ({ "sharp","fine"})); + SetShort("a sharp dagger"); + SetLong("A dagger."); + SetMass(150); + SetDollarCost(50); + SetVendorType(VT_WEAPON); + SetClass(150); + SetDamageType(KNIFE); + SetWeaponType("knife"); +} diff --git a/lib/domains/campus/weap/grenade.c b/lib/domains/campus/weap/grenade.c new file mode 100644 index 0000000..b2fa6a5 --- /dev/null +++ b/lib/domains/campus/weap/grenade.c @@ -0,0 +1,6 @@ +inherit "/domains/default/weap/grenade"; + + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/weap/knife.c b/lib/domains/campus/weap/knife.c new file mode 100644 index 0000000..6a60872 --- /dev/null +++ b/lib/domains/campus/weap/knife.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("knife"); + SetId( ({ "knife"})); + SetAdjectives( ({ "small","utility"})); + SetShort("a small utility knife"); + SetLong("A small utility knife."); + SetMass(40); + SetBaseCost("silver",5); + SetVendorType(VT_WEAPON); + SetClass(2); + SetDamageType(KNIFE); + SetWeaponType("knife"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/weap/sharpsword.c b/lib/domains/campus/weap/sharpsword.c new file mode 100644 index 0000000..96147a1 --- /dev/null +++ b/lib/domains/campus/weap/sharpsword.c @@ -0,0 +1,26 @@ +/* /domains/Examples/weapon/sword.c + * from the Dead Souls LPC Library + * a simple sword example, nothing fancy + * created by Descartes of Borg 950402 + */ + +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("sharp sword"); + SetId( ({ "sword", "short sword", "shortsword"})); + SetAdjectives( ({ "short","sharp","fine"})); + SetShort("a sharp sword"); + SetLong("A fine, sharp, short sword."); + SetMass(150); + SetDollarCost(50); + SetVendorType(VT_WEAPON); + SetClass(20); + SetDamageType(BLADE); + SetWeaponType("blade"); +} diff --git a/lib/domains/campus/weap/staff.c b/lib/domains/campus/weap/staff.c new file mode 100644 index 0000000..33fba70 --- /dev/null +++ b/lib/domains/campus/weap/staff.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; +static void create(){ + item::create(); + SetKeyName("staff"); + SetId( ({ "staff", "stick", "pole" }) ); + SetAdjectives( ({ "wood","wooden" }) ); + SetShort("a wooden staff"); + SetLong("This staff is old, weathered, "+ + "and lumpy. However, it feels quite sturdy "+ + "and solid."); + SetVendorType(VT_WEAPON); + SetDamagePoints(50); + SetClass(100); + SetDollarCost(250); + SetMass(100); + SetWeaponType("blunt"); + SetHands(2); + SetDamageType(BLUNT); +} diff --git a/lib/domains/campus/weap/sword.c b/lib/domains/campus/weap/sword.c new file mode 100644 index 0000000..f969a43 --- /dev/null +++ b/lib/domains/campus/weap/sword.c @@ -0,0 +1,26 @@ +/* /domains/Examples/weapon/sword.c + * from the Dead Souls LPC Library + * a simple sword example, nothing fancy + * created by Descartes of Borg 950402 + */ + +#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" }) ); + SetAdjectives( ({ "short" }) ); + SetShort("a short sword"); + SetLong("A cheap and rather dull short sword."); + SetMass(150); + SetDollarCost(50); + SetVendorType(VT_WEAPON); + SetClass(20); + SetDamageType(BLADE); + SetWeaponType("blade"); +} diff --git a/lib/domains/campus/weap/waterpistol.c b/lib/domains/campus/weap/waterpistol.c new file mode 100644 index 0000000..55c38e7 --- /dev/null +++ b/lib/domains/campus/weap/waterpistol.c @@ -0,0 +1,56 @@ +/* /domains/Examples/weapon/sword.c + * from the Dead Souls LPC Library + * a simple sword example, nothing fancy + * created by Descartes of Borg 950402 + */ + +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_PISTOL; + + +static void create() { + ::create(); + SetKeyName("water pistol"); + SetId(({"pistol","gun"})); + SetAdjectives(({"water","toy","plastic","squirt"})); + SetShort("a small plastic squirt gun"); + SetLong("A small red see-through plastic squirt gun in the shape "+ + "of a ray gun."); + SetMass(10); + SetDollarCost(5); + SetVendorType(VT_WEAPON); + SetClass(10); + SetDamageType(BLUNT); + SetFirearmType("auto"); + SetWeaponType("blunt"); +} + +varargs mixed eventShoot(object shooter, mixed target, string direction){ + string name,patsy; + object killer, env; + + if(!target || direction){ + write("You can't do that."); + return 1; + } + + killer = this_player(); + name = killer->GetName(); + env = environment(killer); + patsy = target->GetName(); + + tell_room(env,name+" drenches "+patsy+" with "+possessive(killer)+" "+ + "water gun!",({killer,target}) ); + tell_object(killer,"You drench "+patsy+" with your water gun! Ha ha ha, "+ + nominative(target)+" looks like a dope!"); + tell_object(target,name+" drenches you with "+possessive(killer)+" "+ + "water gun! Ha ha ha! You look like a big wet dope!"); + return 1; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/campus/weap/zpem.c b/lib/domains/campus/weap/zpem.c new file mode 100644 index 0000000..c5f3984 --- /dev/null +++ b/lib/domains/campus/weap/zpem.c @@ -0,0 +1,177 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> +#include <daemons.h> + +inherit LIB_SHOOT; +inherit LIB_AIM; +inherit LIB_SURFACE; +inherit LIB_ACTIVATE; + +static int active = 0; + +static void create() { + ::create(); + SetKeyName("manipulator"); + SetId(({"gun","zpem"})); + SetAdjectives(({"zero","point","energy","bulky","boxy","futuristic"})); + SetShort("a zero-point energy manipulator"); + SetLong("A large, bulky device appearing to be a kind of boxy, " + "futuristic gun."); + set_heart_beat(1); + SetMass(400); + SetDollarCost(5); + SetVendorType(VT_WEAPON); + SetHands(2); + SetMaxCarry(20000); + SetDamageType(BLUNT); + SetWeaponType("blunt"); +} + +varargs mixed eventShoot(object shooter, mixed target, string direction){ + string name,patsy; + object killer, env; + object *inv = all_inventory(this_object()); + + //tc("target: "+identify(target)); + + if(!active){ + write("You have to activate it first."); + return 1; + } + + if(!target || direction){ + if(!sizeof(inv)){ + write("You can't do that."); + return 1; + } + } + + if(sizeof(inv)){ + write("The zero-point energy manipulator is already actively "+ + "manipulating "+inv->GetShort()+"."); + return 1; + } + + if(living(target)){ + if(!(RACES_D->GetNonMeatRace(target->GetRace()))){ + write("The zero-point energy manipulator does not work "+ + "well on meat-based objects."); + return 1; + } + } + + if(base_name(target) == LIB_CORPSE || base_name(target) == LIB_LIMB){ + write("The zero-point energy manipulator does not work "+ + "well on meat-based objects."); + return 1; + } + + if(target->isDummy() || target->GetMass() > 5000 || + target->GetPreventGet()){ + write("The zero-point energy manipulator clicks and whines."); + return 1; + } + + if(!GetWielded()){ + write("You are not wielding it."); + return 0; + } + + killer = this_player(); + name = killer->GetName(); + env = environment(killer); + patsy = target->GetShort(); + + tell_room(env,name+" picks up "+patsy+" with "+possessive(killer)+" "+ + "zero-point energy manipulator.",({killer,target}) ); + tell_object(killer,"You surround "+patsy+" in a zero-point energy field, "+ + " and "+nominative(target)+" is picked up by "+ + "your zero-point energy manipulator."); + tell_object(target,name+" picks you up with "+possessive(killer)+" "+ + "zero-point energy manipulator. You are helpless in its field."); + + active = 1; + target->SetZPG(1); + target->eventMove(this_object()); + return 1; +} + +int eventTurnOff(){ + object *inv; + if(!active){ + write("It's already inactive."); + return 1; + } + + inv = all_inventory(); + active = 0; + write("You deactivate the zero-point energy manipulator."); + if(sizeof(inv)){ + inv->eventMove(room_environment(this_object())); + foreach(object ob in inv){ + tell_object(ob, "You are released from "+this_player()->GetName()+ + "'s zero-point energy manipulator."); + tell_room(environment(this_player()), capitalize(ob->GetShort())+ + " is "+ + "released from "+this_player()->GetName()+"'s zero-point "+ + "energy manipulator.", ({ ob, this_player() }) ); + write("You release "+ob->GetShort()+" from your zero-point "+ + "energy manipulator."); + } + } + return 1; +} + +int eventTurnOn(){ + if(active){ + write("It's already active."); + return 1; + } + write("You activate the zero-point energy manipulator."); + say(this_player()->GetName()+" activates "+possessive(this_player())+ + " zero-point energy manipulator."); + active = 1; + return 1; +} + + +int GetZPEM(){ + return 1; +} + +void init(){ + object *inv = all_inventory(); + ::init(); + if(!active){ + if(sizeof(inv) && room_environment(this_object())){ + inv->eventMove(room_environment(this_object())); + eventDestruct(); + } + } +} + +void heart_beat(){ + object *inv = all_inventory(); + if(!active){ + if(sizeof(inv) && room_environment(this_object())){ + inv->eventMove(room_environment(this_object())); + eventDestruct(); + } + } +} + +int CanReceive(object ob){ + object *inv = all_inventory(this_object()); + if(!active) return 0; + if(sizeof(inv)) return 0; + return ::CanReceive(ob); +} + +mixed eventUnequip(object who){ + mixed tmp = surface::eventUnequip(who); + if(tmp == 1){ + eventTurnOff(); + } + return tmp; +} diff --git a/lib/domains/cave/adm/README b/lib/domains/cave/adm/README new file mode 100644 index 0000000..2ddcbe3 --- /dev/null +++ b/lib/domains/cave/adm/README @@ -0,0 +1,14 @@ + The Administrative Directory + +This directory contains files necessary for domain administration. + +Specifically it is the default directory for the access object, +which is used for providing nonstandard access to files with +the "grant" command. + +This is also the location where domain-specific daemons can be +expected to reside. + +In the case of archaic domains, such as Ylsrim, this is where +some mandatory rooms are expected to be, such as freezer.c and void.c + diff --git a/lib/domains/cave/armor/armored_boot_l.c b/lib/domains/cave/armor/armored_boot_l.c new file mode 100644 index 0000000..a959595 --- /dev/null +++ b/lib/domains/cave/armor/armored_boot_l.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("armored boot"); + SetAdjectives( ({"armored", "orc", "orcish", "protective"}) ); + SetId(({"boot","left boot"})); + SetShort("an armored boot"); + SetLong("An armored boot of orcish design. It is designed to cover the left foot and leg, and looks extremely durable and protective."); + SetMass(60); + SetBaseCost("silver", 300); + SetProtection(BLUNT,15); + SetProtection(BLADE,15); + SetProtection(KNIFE,15); + SetArmorType(A_LONG_BOOT); + SetRestrictLimbs(({"left foot","left leg"})); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/armor/armored_boot_r.c b/lib/domains/cave/armor/armored_boot_r.c new file mode 100644 index 0000000..48ada4f --- /dev/null +++ b/lib/domains/cave/armor/armored_boot_r.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("armored boot"); + SetAdjectives( ({"armored", "orc", "orcish", "protective"}) ); + SetId(({"boot","right boot"})); + SetShort("an armored boot"); + SetLong("An armored boot of orcish design. It is designed to cover the right foot and leg, and looks extremely durable and protective."); + SetMass(60); + SetBaseCost("silver", 300); + SetProtection(BLUNT,15); + SetProtection(BLADE,15); + SetProtection(KNIFE,15); + SetArmorType(A_LONG_BOOT); + SetRestrictLimbs(({"right foot","right leg"})); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/armor/armored_glove_l.c b/lib/domains/cave/armor/armored_glove_l.c new file mode 100644 index 0000000..3c44f7b --- /dev/null +++ b/lib/domains/cave/armor/armored_glove_l.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("armored glove"); + SetAdjectives( ({"armored", "orc", "orcish", "protective"}) ); + SetId(({"glove","left glove"})); + SetShort("an armored glove"); + SetLong("An armored glove of orcish design. It is designed to cover the left hand and arm, and looks extremely durable and protective."); + SetMass(60); + SetBaseCost("silver", 300); + SetProtection(BLUNT,15); + SetProtection(BLADE,15); + SetProtection(KNIFE,15); + SetArmorType(A_LONG_GLOVE); + SetFingers(6); + SetRestrictLimbs(({"left hand","left arm"})); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/armor/armored_glove_r.c b/lib/domains/cave/armor/armored_glove_r.c new file mode 100644 index 0000000..62e50b4 --- /dev/null +++ b/lib/domains/cave/armor/armored_glove_r.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("armored glove"); + SetAdjectives( ({"armored", "orc", "orcish", "protective"}) ); + SetId(({"glove","right glove"})); + SetShort("an armored glove"); + SetLong("An armored glove of orcish design. It is designed to cover the right hand and arm, and looks extremely durable and protective."); + SetMass(60); + SetBaseCost("silver", 300); + SetProtection(BLUNT,15); + SetProtection(BLADE,15); + SetProtection(KNIFE,15); + SetArmorType(A_LONG_GLOVE); + SetFingers(6); + SetRestrictLimbs(({"right hand","right arm"})); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/armor/boobytrap_ring.c b/lib/domains/cave/armor/boobytrap_ring.c new file mode 100644 index 0000000..1ad58f2 --- /dev/null +++ b/lib/domains/cave/armor/boobytrap_ring.c @@ -0,0 +1,48 @@ +/* + * Note that this ring, unlike the boobytrapped dagger, does + * not check to see if it has been previously armed. This prevents + * a player from disarming the ring by simply logging out + * and logging back in. + */ + +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <boobytraps.h> + +inherit LIB_ARMOR; + +void boobytrap_me(){ + object shadowtrap; + if(!clonep(this_object())) return; /* Avoids boobytrapping the blueprint ob */ + + shadowtrap = new("/shadows/needle_trap2"); + shadowtrap->SetTrapDescription("A poison needle trap."); + shadowtrap->SetTrapLevel(50); + shadowtrap->SetAutoResets(0); + shadowtrap->SetTrapType(BOOBYTRAP_WEAR); + shadowtrap->eventShadow(this_object()); +} + +static void create(){ + armor::create(); + SetKeyName("silver_ring"); + SetId(({"ring","silver ring"})); + SetAdjectives( ({"beautiful"}) ); + SetShort("a beautiful silver ring"); + SetLong("This is a simple but beautiful ring made of "+ + "silver, suitable for wearing on one's finger. The ring bears an inscription."); + SetMass(1); + SetBaseCost("silver",500); + SetArmorType(A_RING); + SetItems(([ + ({"script","words","inscription","writing"}) : "Words engraved on the ring in a highly "+ + "stylized script." + ]) ); + SetRead(({"script","words","inscription","writing"}), "\"bad wolf\"" ); + boobytrap_me(); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/armor/chainmail.c b/lib/domains/cave/armor/chainmail.c new file mode 100644 index 0000000..027b8de --- /dev/null +++ b/lib/domains/cave/armor/chainmail.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("chainmail shirt"); + SetId(({"armor","chainmail","mail","shirt","chain mail"})); + SetAdjectives(({"chainmail","sturdy","sturdy-looking","chain mail"})); + SetShort("a sturdy-looking chainmail shirt"); + SetLong("This is a shirt made of small, thin metal rings fashioned together as armor. "); + SetMass(600); + SetBaseCost("silver",1000); + SetDamagePoints(1000); + SetProtection(BLUNT,4); + SetProtection(BLADE,25); + SetProtection(KNIFE,25); + SetArmorType(A_ARMOR); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/armor/chainmail_collar.c b/lib/domains/cave/armor/chainmail_collar.c new file mode 100644 index 0000000..a45eb71 --- /dev/null +++ b/lib/domains/cave/armor/chainmail_collar.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("collar"); + SetId(({"neck guard","guard"})); + SetAdjectives( ({"neck","collar","chainmail"}) ); + SetShort("a chainmail collar"); + SetLong("This is a simple collar made of chainmail "+ + "to protect the neck from weapons."); + SetMass(50); + SetArmorType(A_COLLAR); + SetProtection(BLUNT,4); + SetProtection(BLADE,25); + SetProtection(KNIFE,25); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/armor/foodsmock.c b/lib/domains/cave/armor/foodsmock.c new file mode 100644 index 0000000..19a81ca --- /dev/null +++ b/lib/domains/cave/armor/foodsmock.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("uniform"); + SetAdjectives( ({"food workers","food worker's"}) ); + SetId( ({"overalls", "smock"}) ); + SetShort("a food worker's uniform"); + SetLong("This is a set of overalls used by food workers to keep their bodies and the food at a healthy distance."); + SetMass(50); + SetArmorType(A_BODY_ARMOR); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/armor/leather_armor.c b/lib/domains/cave/armor/leather_armor.c new file mode 100644 index 0000000..95719c4 --- /dev/null +++ b/lib/domains/cave/armor/leather_armor.c @@ -0,0 +1,34 @@ +/* /domains/Ylsrim/armor/artrell_armor.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 960302 + */ + +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ARMOR; + +static void create() { + armor::create(); + SetKeyName("leather armor"); + SetId( ({ "armor", "leather armor" }) ); + SetAdjectives( ({ "leather" }) ); + SetShort("a suit of leather armor"); + SetLong("An ordinary suit of leather armor. It is worn on one's arms, torso and legs."); + SetVendorType(VT_ARMOR); + SetMass(750); + SetValue(150); + SetDamagePoints(800); + SetProtection(BLUNT, 20); + SetProtection(BLADE, 20); + SetProtection(KNIFE, 25); + SetProtection(HEAT, 7); + SetProtection(COLD, 4); + SetProtection(SHOCK, 15); + SetArmorType(A_BODY_ARMOR); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/armor/loincloth.c b/lib/domains/cave/armor/loincloth.c new file mode 100644 index 0000000..c8f4e43 --- /dev/null +++ b/lib/domains/cave/armor/loincloth.c @@ -0,0 +1,35 @@ +#include <lib.h> +#include <size_types.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_WORN_STORAGE; + +static void create() { + ::create(); + SetKeyName("loincloth"); + SetId(({"cloth"})); + SetAdjectives(({"loin","filthy"})); + SetShort("a filthy loincloth"); + SetLong("This is a very large cloth used by someone really gross as "+ + "a form of clothing and storage."); + SetMass(100); + SetCanClose(0); + SetClosed(0); + SetMaxCarry(100); + SetArmorType(A_PANTS); + SetSmell( ([ + "default" : "P.U.", + ]) ); + SetMoney( ([ + "platinum" : random(5)+1, + ]) ); + SetInventory(([ + "/domains/default/obj/vial_orange" : 1, + "/domains/town/obj/cavetroll_key" : 1, + ])); + SetSize(S_LARGE); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/armor/necklace.c b/lib/domains/cave/armor/necklace.c new file mode 100644 index 0000000..0259c4b --- /dev/null +++ b/lib/domains/cave/armor/necklace.c @@ -0,0 +1,20 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("gold necklace"); + SetId(({"necklace"})); + SetAdjectives( ({"gold","beautiful"}) ); + SetShort("a gold necklace"); + SetLong("This is a simple and beautiful gold necklace."); + SetMass(1); + SetDollarCost(400); + SetArmorType(A_COLLAR); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/armor/orc_boot_l.c b/lib/domains/cave/armor/orc_boot_l.c new file mode 100644 index 0000000..ffe5a6e --- /dev/null +++ b/lib/domains/cave/armor/orc_boot_l.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("leather boot"); + SetAdjectives( ({"leather", "simple", "orc", "orcish", "inelegant", "protective"}) ); + SetId(({"boot","left boot"})); + SetShort("a leather boot"); + SetLong("A leather boot of orcish design. Simple and inelegant, but quite protective. It is designed for the left foot."); + SetMass(60); + SetBaseCost("silver", 30); + SetProtection(BLUNT,5); + SetProtection(BLADE,5); + SetProtection(KNIFE,5); + SetArmorType(A_BOOT); + SetRestrictLimbs(({"left foot"})); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/armor/orc_boot_r.c b/lib/domains/cave/armor/orc_boot_r.c new file mode 100644 index 0000000..191decc --- /dev/null +++ b/lib/domains/cave/armor/orc_boot_r.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("leather boot"); + SetAdjectives( ({"leather", "simple", "orc", "orcish", "inelegant", "protective"}) ); + SetId(({"boot","right boot"})); + SetShort("a leather boot"); + SetLong("A leather boot of orcish design. Simple and inelegant, but quite protective. It is designed for the right foot."); + SetMass(60); + SetBaseCost("silver", 30); + SetProtection(BLUNT,5); + SetProtection(BLADE,5); + SetProtection(KNIFE,5); + SetArmorType(A_BOOT); + SetRestrictLimbs(({"right foot"})); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/armor/orc_dress.c b/lib/domains/cave/armor/orc_dress.c new file mode 100644 index 0000000..0da3375 --- /dev/null +++ b/lib/domains/cave/armor/orc_dress.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("dress"); + SetId(({"dress"})); + SetAdjectives(({"improvised","simple"})); + SetShort("a simple dress"); + SetLong("This is a simple little dress "+ + "made apparently from scrap materials and of improvised design."); + SetMass(10); + SetBaseCost("silver",1); + SetArmorType(A_BODY_ARMOR); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/armor/orc_helmet.c b/lib/domains/cave/armor/orc_helmet.c new file mode 100644 index 0000000..f5d689f --- /dev/null +++ b/lib/domains/cave/armor/orc_helmet.c @@ -0,0 +1,41 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +varargs int CheckOrc(object who, mixed where); + +static void create(){ + armor::create(); + SetKeyName("orc helmet"); + SetId(({"helmet"})); + SetAdjectives(({"bear","bone","skull","orc"})); + SetShort("a bear skull helmet"); + SetLong("This is a helmet made of the hard bone of a bear, "+ + "treated with some sort of thick resin to "+ + "prevent shattering."); + SetMass(180); + SetBaseCost("silver",100); + SetDamagePoints(100); + SetArmorType(A_HELMET); + SetProtection(BLUNT, 20); + SetProtection(BLADE, 20); + SetProtection(KNIFE, 20); + SetWear( (: CheckOrc :) ); +} + +varargs int CheckOrc(object who, mixed where){ + object env = environment(who); + if( who->GetRace() == "orc" ) { + who->eventPrint("You can almost feel the power of the bear as "+ + "you wear its skull."); + if(env) tell_room(env, who->GetName()+" wears "+GetShort()+ + ".", ({who})); + return 1; + } + else { + who->eventPrint("The helmet appears designed for orc anatomy. "+ + "It does not fit you."); + return 0; + } +} diff --git a/lib/domains/cave/armor/orc_tallboot_l.c b/lib/domains/cave/armor/orc_tallboot_l.c new file mode 100644 index 0000000..0df572b --- /dev/null +++ b/lib/domains/cave/armor/orc_tallboot_l.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("leather boot"); + SetAdjectives( ({"leather", "simple", "orc", "orcish", "protective","leg","left","full leg"}) ); + SetId(({"boot","left boot"})); + SetShort("a leather boot"); + SetLong("A thick leather full-leg boot of orcish design. Simple, but quite protective. It is designed for the left foot and leg."); + SetMass(120); + SetBaseCost("silver", 200); + SetProtection(BLUNT,5); + SetProtection(BLADE,10); + SetProtection(KNIFE,10); + SetArmorType(A_LONG_BOOT); + SetRestrictLimbs(({"left foot","left leg"})); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/armor/orc_tallboot_r.c b/lib/domains/cave/armor/orc_tallboot_r.c new file mode 100644 index 0000000..9f0391a --- /dev/null +++ b/lib/domains/cave/armor/orc_tallboot_r.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("leather boot"); + SetAdjectives( ({"leather", "simple", "orc", "orcish", "protective","leg","right","full leg"}) ); + SetId(({"boot","right boot"})); + SetShort("a leather boot"); + SetLong("A thick leather full-leg boot of orcish design. Simple, but quite protective. It is designed for the right foot and leg."); + SetMass(120); + SetBaseCost("silver", 200); + SetProtection(BLUNT,5); + SetProtection(BLADE,10); + SetProtection(KNIFE,10); + SetArmorType(A_LONG_BOOT); + SetRestrictLimbs(({"right foot","right leg"})); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/armor/pajamas.c b/lib/domains/cave/armor/pajamas.c new file mode 100644 index 0000000..8f1ad72 --- /dev/null +++ b/lib/domains/cave/armor/pajamas.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <size_types.h> +inherit LIB_ARMOR; + +static void create(){ + ::create(); + SetKeyName("pajamas"); + SetId(({"pj","pjs", "peejays"})); + SetAdjectives(({"small","tiny","pair of","set of", + "bloodstained", "blood stained", "stained"})); + SetShort("tiny, bloodstained pajamas"); + SetLong("This is a set of very small pajamas, stained with old, " + "crusted blood."); + SetItems( ([ + ({"blood","crusted blood", "old, crusted blood"}) : "It seems "+ + "that whoever was wearing these pajamas suffered some terrible "+ + "injuries.", + ]) ); + SetMass(2); + SetBaseCost("silver",1); + SetArmorType(A_BODY_ARMOR); + SetSize(S_SOMEWHAT_SMALL|S_SMALL); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/armor/pants.c b/lib/domains/cave/armor/pants.c new file mode 100644 index 0000000..1d71c98 --- /dev/null +++ b/lib/domains/cave/armor/pants.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("leather pants"); + SetId(({"pants"})); + SetAdjectives(({"strong","leather","black","tough"})); + SetShort("leather pants"); + SetLong("These are trousers made of strong, tough leather. "); + SetMass(150); + SetBaseCost("silver",110); + SetDamagePoints(10); + SetProtection(BLUNT,1); + SetProtection(BLADE,5); + SetProtection(KNIFE,5); + SetArmorType(A_PANTS); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/armor/platemail.c b/lib/domains/cave/armor/platemail.c new file mode 100644 index 0000000..b80a576 --- /dev/null +++ b/lib/domains/cave/armor/platemail.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("suit of armor"); + SetId(({"armor","plate mail","platemail","suit","armor","suit of armor"})); + SetAdjectives(({"full","plate","plated","metal"})); + SetShort("a full suit of armor"); + SetLong("This is a large, very heavy suit of armor, the kind "+ + "one might expect a knight to wear. The thick "+ + "metal plating promises extraordinary protection, "+ + "yet the joints are so finely articulated as to "+ + "permit great freedom of movement."); + SetMass(2500); + SetBaseCost("silver",5000); + SetProtection(BLUNT,20); + SetProtection(BLADE,50); + SetProtection(KNIFE,50); + SetArmorType(A_BODY_ARMOR); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/doors/food_storage1.c b/lib/domains/cave/doors/food_storage1.c new file mode 100644 index 0000000..92303d6 --- /dev/null +++ b/lib/domains/cave/doors/food_storage1.c @@ -0,0 +1,22 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("south", (["id" : ({ "door leading south", "door", "south door" }), + "short" : "a door leading south", + "long" : "This is the north side of a door leading south.", + "lockable" : 1 ]) ); + SetKeys("south", ({ "food_storage_one" })); + + SetSide("north", (["id" : ({ "door leading north", "door", "north door" }), + "short" : "a door leading north", + "long" : "This is the south side of a door leading north.", + "lockable" : 1 ]) ); + SetKeys("north", ({ "food_storage_one" })); + + SetClosed(1); + SetLocked(1); +} diff --git a/lib/domains/cave/doors/kurogane.c b/lib/domains/cave/doors/kurogane.c new file mode 100644 index 0000000..a50eaeb --- /dev/null +++ b/lib/domains/cave/doors/kurogane.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("north", ([ "id" : ({"door leading north", "door", "north door"}), + "short" : "a door leading north", + "long" : "This is the south side of a door leading north.", + "lockable" : 1 ]) ); + + SetSide("south", ([ "id" : ({"door leading south", "door", "south door"}), + "short" : "a door leading south", + "long" : "This is the north side of a door leading south.", + "lockable" : 1 ]) ); + + SetClosed(1); + SetLocked(0); + SetKeys("north", ({ "north key" })); + SetKeys("south", ({ "south key" })); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/etc/cave_orc.c b/lib/domains/cave/etc/cave_orc.c new file mode 100644 index 0000000..c2b91a2 --- /dev/null +++ b/lib/domains/cave/etc/cave_orc.c @@ -0,0 +1,98 @@ +#include <vision.h> +#include ROOMS_H +#include <lib.h> + +inherit LIB_SENTIENT; +static private string *exempted = ({ "orc","half-orc","rodent","bear" }); + +int GetEnemyChaser() { return 1; } + +int CheckOrc(mixed val){ + if(!val) return 0; + if(!objectp(val)) return 0; + if(creatorp(val)) return 0; + if(member_array(val->GetRace(),exempted) != -1) return 0; + eventForce("growl at "+val->GetKeyName()); + if( this_object()->GetEnemyChaser() && + !this_object()->GetLeader() && sizeof(filter(val->GetFollowers(), + (: base_name($1) == base_name(this_object()) :))) < 1){ + eventForce("follow "+val->GetKeyName()); + SetWanderSpeed(1); + } + return 1; +} + +// The following function simply makes an orc light a torch +// with a match if it's dark. It looks complicated because there +// will be a bunch of orcs, and a bunch of torches, and a bunch +// of matches. This function makes sure that THIS orc lights +// THIS torch with THIS match, thereby avoiding a cave choked to +// the gills with matches, torches, and blind orcs. +int torch_action(){ + object torch, match; + object *tmp, *tmp2; + int x, y; + if(this_object()->GetEffectiveVision() < VISION_CLEAR){ + tmp = filter(all_inventory(this_object()), (: answers_to("match", + $1) && $1->GetLit() :) ); + tmp2 = filter(all_inventory(this_object()), (: answers_to("torch", + $1) && $1->GetFuelAmount() :) ); + if(sizeof(tmp)) match = tmp[0]; + if(sizeof(tmp2)) torch = tmp2[0]; + if(!torch){ + tmp2 = filter(all_inventory(this_object()), + (: answers_to("torch", $1) :) ); + if(sizeof(tmp2)) tmp2->eventMove(ROOM_FURNACE); + torch = new("/domains/cave/obj/torch"); + torch->eventMove(this_object()); + } + if(!match){ + tmp = filter(all_inventory(this_object()), + (: answers_to("match", $1) :) ); + if(sizeof(tmp)) tmp->eventMove(ROOM_FURNACE); + match = new("/domains/cave/obj/everstrike_match"); + match->eventMove(this_object()); + } + if(torch && match){ + x = (environment(torch) && environment(torch) == this_object()); + y = (environment(match) && environment(match) == this_object()); + if(x && y){ + string torchname = torch->GetUniqueId(); + string matchname = match->GetUniqueId(); + if(!match->GetLit()){ + this_object()->eventForce("strike my match"); + } + this_object()->eventForce("light "+torchname+" with "+ + matchname ); + } + } + } + if(torch && torch->GetLit()){ + this_object()->eventForce("drop my match"); + } + return 1; +} + +void init(){ + object env = environment(); + ::init(); + if(env && base_name(env) == "/domains/cave/room/cave"){ + eventForce("go east"); + } +} + +void heart_beat(){ + object env = environment(); + if(!clonep()) return; + ::heart_beat(); + if(this_object()->GetEffectiveVision() < VISION_CLEAR){ + torch_action(); + } + if(env && base_name(env) == "/domains/cave/room/cave"){ + eventForce("go east"); + } +} + +varargs mixed SetGuard(mixed what, mixed action, int howlong){ + return ::SetGuard(what, action, howlong); +} diff --git a/lib/domains/cave/etc/cave_room.c b/lib/domains/cave/etc/cave_room.c new file mode 100644 index 0000000..48e204d --- /dev/null +++ b/lib/domains/cave/etc/cave_room.c @@ -0,0 +1,38 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +static void create(){ + ::create(); +} + +int CanReceive(object ob){ + int ret, level; + level = ob->GetLevel(); + if((creatorp(ob) && !archp(ob)) || (userp(ob) && level > 20)){ + write("Sorry. This area is for normal players."); + return 0; + } + ret = room::CanReceive(ob); + if(ret){ + object *inv = deep_inventory(ob); + foreach(object element in inv){ + string name = base_name(element); + level = element->GetLevel(); + if(creatorp(element) && !archp(element) + || (userp(element) && level > 20)){ + write("Sorry. This is a player-only area."); + return 0; + } + if(!strsrch(name,"/realms/") || !strsrch(name,"/open/")){ + element->eventMove(ROOM_FURNACE); + } + } + } + return ret; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/meals/beast.c b/lib/domains/cave/meals/beast.c new file mode 100644 index 0000000..9c2c296 --- /dev/null +++ b/lib/domains/cave/meals/beast.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <meal_types.h> +inherit LIB_MEAL; + +static void create() { + meal::create(); + SetKeyName("roast beast"); + SetId( ({ "meat","beast","roast","hunk"}) ); + SetAdjectives( ({ "savory","hunk of","spiced","delicious"}) ); + SetShort("a hunk of roast beast"); + SetLong("Savory and spiced, this hunk of meat looks delicious."); + SetNoCondition(1); + SetMass(50); + SetStrength(15); + SetBaseCost("silver", 20); + SetMealType(MEAL_FOOD); + SetMealMessages("You eat your meat.", + "$N eats $P hunk of roast beast."); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/meals/bread.c b/lib/domains/cave/meals/bread.c new file mode 100644 index 0000000..75934c4 --- /dev/null +++ b/lib/domains/cave/meals/bread.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include <meal_types.h> +inherit LIB_MEAL; + +static void create() { + meal::create(); + SetKeyName("bread"); + SetAdjectives( ({ "black","orc","orcish"}) ); + SetShort("a loaf of black bread"); + SetLong("A loaf of bread baked in a simple, inexpensive manner."); + SetNoCondition(1); + SetMass(50); + SetStrength(10); + SetBaseCost("silver", 1); + SetMealType(MEAL_FOOD); + SetMealMessages("You eat your black bread.", + "$N eats $P loaf of black bread."); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/meals/herring.c b/lib/domains/cave/meals/herring.c new file mode 100644 index 0000000..6f5ca2f --- /dev/null +++ b/lib/domains/cave/meals/herring.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <meal_types.h> +#include <dirs.h> + +inherit LIB_FISH; + +static void create() { + fish::create(); + SetKeyName("herring"); + SetId( ({ "fish" }) ); + SetAdjectives( ({ "pickled","red","saltwater","salt water","bloated"}) ); + SetShort("a red herring"); + SetLong("A saltwater fish, turned red and bloated by orcish pickling."); + SetMealType(MEAL_FOOD); + SetMass(10); + SetStrength(2); + SetBaseCost("silver", 1); + SetFight(4); + SetFood("/domains/town/meals/herring"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/meals/jerky.c b/lib/domains/cave/meals/jerky.c new file mode 100644 index 0000000..f4e0d5a --- /dev/null +++ b/lib/domains/cave/meals/jerky.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <meal_types.h> +inherit LIB_MEAL; + +static void create() { + meal::create(); + SetKeyName("jerky"); + SetAdjectives(({"unpalatable","dried","flattened","flat", + "smoked","salted"})); + SetId(({"meat","strip","strip of jerky","strips of jerky"})); + SetShort("a strip of jerky"); + SetLong("A dried, flattened, smoked, and salted strip of "+ + "meat that looks about as durable as tree bark and less palatable."); + SetNoCondition(1); + SetMass(15); + SetStrength(1); + SetBaseCost("silver", 1); + SetMealType(MEAL_FOOD); + SetMealMessages("You gnaw on the jerky and manage to choke it down.", + "$N gnaws on and chokes down $P strip of jerky."); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/npc/cavetroll.c b/lib/domains/cave/npc/cavetroll.c new file mode 100644 index 0000000..1fe441b --- /dev/null +++ b/lib/domains/cave/npc/cavetroll.c @@ -0,0 +1,39 @@ +#include <lib.h> +#include <damage_types.h> +#include <size_types.h> + +inherit LIB_NPC; + +static void create() { + npc::create(); + SetKeyName("troll"); + SetId(({"cavetroll"})); + SetAdjectives(({"dirty","cave"})); + SetShort("a cave troll"); + SetLong("Unlike its more civilized brethren, the cavetroll is a "+ + "huge and monstrously powerful creature with an even more "+ + "vicious temperament. Its rocklike skin makes it difficult to "+ + "injure, and its gargantuan muscles make it difficult to "+ + "survive in combat against it."); + SetInventory(([ + "/domains/cave/armor/loincloth" : "wear loincloth", + ])); + SetLevel(13); + SetRace("troll"); + SetClass("fighter"); + SetGender("male"); + SetMelee(1); + SetSkill("melee attack",50,50,10); + SetStat("strength",90,1); + SetStat("agility",50,1); + SetResistance(BLADE,"high"); + SetResistance(KNIFE,"high"); + SetResistance(PIERCE,"high"); + SetResistance(BITE,"high"); + SetEncounter(100); + SetSize(S_LARGE); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/npc/chieftain.c b/lib/domains/cave/npc/chieftain.c new file mode 100644 index 0000000..f4197b8 --- /dev/null +++ b/lib/domains/cave/npc/chieftain.c @@ -0,0 +1,56 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +int CheckOrc(mixed val){ + if(!val) return 0; + if(!objectp(val)) return 0; + if(val->GetRace() == "orc" || val->GetRace() == "rodent") return 0; + else eventForce("growl at "+val->GetKeyName()); + return 1; +} + +static void create() { + ::create(); + SetKeyName("orc"); + SetId(({"orc","chieftain","chiklis"})); + SetAdjectives(({"orc","armored","professional","chieftain"})); + SetShort("an orc chieftain"); + SetLong("This is a large orc, covered in ornate tattoos and "+ + "markings of power and prestige. His powerful frame is "+ + "clearly accustomed to physically establishing authority."); + SetInventory(([ + "/domains/cave/weap/longsword" : "wield sword", + "/domains/cave/armor/platemail" : "wear platemail", + "/domains/cave/armor/orc_helmet" : "wear helmet", + "/domains/cave/armor/chainmail_collar" : "wear collar", + "/domains/cave/armor/armored_boot_l" : "wear left boot", + "/domains/cave/armor/armored_boot_r" : "wear right boot", + "/domains/cave/armor/armored_glove_r" : "wear right glove", + "/domains/cave/armor/armored_glove_l" : "wear left glove", + ])); + SetRace("orc"); + SetLevel(10); + SetClass("fighter"); + SetGender("male"); + SetEncounter( (: CheckOrc :) ); + SetStat("strength",85); + SetGuard("/domains/cave/obj/chest2","The orc blocks your theft."); +} + +void init(){ + ::init(); +} + +int eventDie(){ + if(sizeof(GetWieldingLimbs())){ + eventForce("laugh"); + eventForce("speak enjoy your victory, punk!"); + eventForce("pull lever"); + } + else { + eventForce("spit"); + eventForce("speak you have no idea what you've done, fool!"); + } + return ::eventDie(); +} diff --git a/lib/domains/cave/npc/gorm.c b/lib/domains/cave/npc/gorm.c new file mode 100644 index 0000000..fb0aead --- /dev/null +++ b/lib/domains/cave/npc/gorm.c @@ -0,0 +1,55 @@ +#include <lib.h> +#include <vendor_types.h> + +inherit LIB_VENDOR; + +int throwing; + +int CheckOrc(mixed val){ + if(!val) return 0; + if(!objectp(val)) return 0; + if(val->GetRace() == "orc" || val->GetRace() == "rodent") return 0; + eventForce("growl at "+val->GetKeyName()); + return 1; +} + +static void create() { + ::create(); + SetKeyName("orc"); + SetId(({"gorm","orc","shopkeep","keeper","vendor"})); + SetAdjectives(({"adult","male","shop"})); + SetShort("Gorm the orc shopkeep"); + SetLong("This is the manager of the local Post Exchange. You " + "can sell things to him or buy things from him."); + SetInventory(([ + ])); + SetLevel(2); + SetMelee(1); + SetRace("orc"); + SetClass("fighter"); + SetGender("male"); + SetEncounter( (: CheckOrc :) ); + AddCurrency("silver", random(100)); + SetVendorType(VT_ALL); + SetAttackable(0); + SetSkill("bargaining", 1); + SetProperty("no bump", 1); + SetLocalCurrency("silver"); + SetStorageRoom("/domains/cave/room/shop2"); +} + +void init(){ + object env = environment(); + ::init(); + if(env && base_name(env) == "/domains/cave/room/cave"){ + eventForce("go east"); + } +} + +void heart_beat(){ + object env = room_environment(this_object()); + if(env && base_name(env) == "/domains/cave/room/cave"){ + eventForce("go east"); + } + ::heart_beat(); +} diff --git a/lib/domains/cave/npc/kurogane.c b/lib/domains/cave/npc/kurogane.c new file mode 100644 index 0000000..d807f47 --- /dev/null +++ b/lib/domains/cave/npc/kurogane.c @@ -0,0 +1,71 @@ +#include <lib.h> + +inherit LIB_SENTIENT; +int throwing; + +int CheckOrc(mixed val){ + if(!val) return 0; + if(!objectp(val)) return 0; + if(val->GetRace() == "orc" || val->GetRace() == "rodent") return 0; + eventForce("growl at "+val->GetKeyName()); + eventForce("say murdering, genocidal humanoids! Leave us alone!"); + return 1; +} + +static void create() { + ::create(); + SetKeyName("orc"); + SetId(({"orc","commander","kurogane"})); + SetAdjectives(({"armored","professional","orc","commander"})); + SetShort("an orc commander"); + SetLong("This is a very large adult orc. He seems to have a professional " + "bearing, and a sense of purpose."); + SetInventory(([ + "/domains/cave/weap/battleaxe" : "wield axe", + "/domains/cave/armor/chainmail" : "wear chainmail", + "/domains/cave/armor/orc_tallboot_l" : "wear left boot", + "/domains/cave/armor/orc_tallboot_r" : "wear right boot", + ])); + SetRace("orc"); + SetLevel(10); + SetClass("fighter"); + SetGender("male"); + SetEncounter( (: CheckOrc :) ); + SetGuard("south","The commander bars your way!"); +} + +void init(){ + object env = environment(); + ::init(); + if(env && base_name(env) == "/domains/cave/room/cave"){ + eventForce("go east"); + } +} + +void heart_beat(){ + object env = environment(); + ::heart_beat(); + if(env && base_name(env) == "/domains/cave/room/cave"){ + eventForce("go east"); + } +} + +int eventDie(mixed agent){ + object player; + string *quests; + if(!objectp(player = agent) || !interactive(player)){ + return ::eventDie(agent); + } + if(!player->GetQuest("Orc Commander Assassination")){ + player->AddQuest("Cave Explorer II","Orc Commander Assassination"); + write("%^BOLD%^%^RED%^\n\nCONGRATULATIONS!\n%^RESET%^"); + write("%^BOLD%^%^RED%^You have defeated the evil and cruel "+ + "Orc Commander! You have "+ + "earned 12 quest points, and 9500 experience "+ + "points. Nice job!\n\n%^RESET%^"); + player->AddQuestPoints(12); + player->AddExperiencePoints(9500); + } + return ::eventDie(agent); +} + diff --git a/lib/domains/cave/npc/orc_female1.c b/lib/domains/cave/npc/orc_female1.c new file mode 100644 index 0000000..d9efb39 --- /dev/null +++ b/lib/domains/cave/npc/orc_female1.c @@ -0,0 +1,41 @@ +#include <lib.h> + +inherit "/domains/cave/etc/cave_orc"; + +int throwing; + +int CheckOrc(mixed val){ + if(!val) return 0; + if(!objectp(val)) return 0; + if(val->GetRace() == "orc" || val->GetRace() == "rodent") return 0; + return 1; +} + +static void create() { + ::create(); + SetKeyName("orc"); + SetId(({"orc","female"})); + SetAdjectives(({"adult","female"})); + SetShort("a female orc"); + SetLong("This is an adult orc, a creature somewhat larger "+ + "and stronger than a typical human."); + SetInventory(([ + "/domains/cave/armor/orc_dress" : "wear dress", + ])); + SetLevel(2); + SetMelee(1); + SetRace("orc"); + SetClass("fighter"); + SetGender("female"); + SetEncounter( (: CheckOrc :) ); + AddCurrency("gold", random(100)); +} + +void init(){ + ::init(); +} + +void heart_beat(){ + torch_action(); + ::heart_beat(); +} diff --git a/lib/domains/cave/npc/orc_guard1.c b/lib/domains/cave/npc/orc_guard1.c new file mode 100644 index 0000000..3fb7d21 --- /dev/null +++ b/lib/domains/cave/npc/orc_guard1.c @@ -0,0 +1,54 @@ +#include <lib.h> + +inherit "/domains/cave/etc/cave_orc"; + +int throwing; + +static void create() { + ::create(); + SetKeyName("orc"); + SetId(({"orc", "guard"})); + SetAdjectives(({"armored","professional","orc","guard"})); + SetShort("an orc guard"); + SetLong("This is an adult orc. He seems to have a professional " + "bearing, and a sense of purpose."); + SetInventory(([ + "/domains/cave/weap/sword" : "wield sword", + "/domains/cave/weap/javelin" : 2, + "/domains/cave/armor/leather_armor" : "wear leather armor", + "/domains/cave/armor/orc_boot_l" : "wear left boot", + "/domains/cave/armor/orc_boot_r" : "wear right boot", + ])); + SetLevel(1); + SetRace("orc"); + SetClass("fighter"); + SetSkill("projectile attack", 20); + SetSkill("projectile defense", 10); + SetGender("male"); + SetEncounter( (: CheckOrc :) ); +} + +void init(){ + ::init(); +} + +void heart_beat(){ + object env = room_environment(this_object()); + if(throwing) throwing--; + if(GetInCombat()){ + object targ; + object jav = present("javelin",this_object()); + object *targs = filter(get_livings(env), + (: member_array($1, GetEnemies()) != -1 :) ); + if(sizeof(targs)) targ = targs[random(sizeof(targs)-1)]; + if(present("javelin", env)){ + eventForce("get a javelin"); + jav = present("javelin",this_object()); + } + if(jav && targ && !throwing){ + eventForce("throw a javelin at "+targ->GetKeyName()); + throwing = 10; + } + } + ::heart_beat(); +} diff --git a/lib/domains/cave/npc/orc_guard2.c b/lib/domains/cave/npc/orc_guard2.c new file mode 100644 index 0000000..65f8d28 --- /dev/null +++ b/lib/domains/cave/npc/orc_guard2.c @@ -0,0 +1,28 @@ +#include <lib.h> + +inherit "/domains/cave/etc/cave_orc"; + +static void create() { + ::create(); + SetKeyName("orc"); + SetId(({"orc"})); + SetAdjectives(({"armored","professional"})); + SetShort("an armored orc"); + SetLong("This is an adult orc. He seems to have a professional " + "bearing, and a sense of purpose."); + SetInventory(([ + "/domains/cave/weap/sword" : "wield sword", + "/domains/cave/armor/leather_armor" : "wear leather armor", + "/domains/cave/armor/orc_boot_l" : "wear left boot", + "/domains/cave/armor/orc_boot_r" : "wear right boot", + ])); + SetRace("orc"); + SetLevel(2); + SetClass("fighter"); + SetGender("male"); + SetEncounter( (: CheckOrc :) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/npc/orc_guard3.c b/lib/domains/cave/npc/orc_guard3.c new file mode 100644 index 0000000..0690561 --- /dev/null +++ b/lib/domains/cave/npc/orc_guard3.c @@ -0,0 +1,55 @@ +#include <lib.h> + +inherit "/domains/cave/etc/cave_orc"; + +int throwing; + +static void create() { + ::create(); + SetKeyName("orc"); + SetId(({"orc","guard"})); + SetAdjectives(({"armored","professional","guard","orc"})); + SetShort("an orc guard"); + SetLong("This is an adult orc. He seems to have a professional " + "bearing, and a sense of purpose."); + SetInventory(([ + "/domains/cave/weap/sword" : "wield sword", + "/domains/cave/weap/javelin" : 3, + "/domains/cave/armor/leather_armor" : "wear leather armor", + "/domains/cave/armor/orc_boot_l" : "wear left boot", + "/domains/cave/armor/orc_boot_r" : "wear right boot", + ])); + SetLevel(3); + SetRace("orc"); + SetClass("fighter"); + SetWanderSpeed(1); + SetSkill("projectile attack", 30); + SetSkill("projectile defense", 10); + SetGender("male"); + SetEncounter( (: CheckOrc :) ); +} + +void init(){ + ::init(); +} + +void heart_beat(){ + object env = room_environment(this_object()); + if(throwing) throwing--; + if(GetInCombat()){ + object targ; + object jav = present("javelin",this_object()); + object *targs = filter(get_livings(env), + (: member_array($1, GetEnemies()) != -1 :) ); + if(sizeof(targs)) targ = targs[random(sizeof(targs)-1)]; + if(present("javelin", env)){ + eventForce("get a javelin"); + jav = present("javelin",this_object()); + } + if(jav && targ && !throwing){ + eventForce("throw a javelin at "+targ->GetKeyName()); + throwing = 10; + } + } + ::heart_beat(); +} diff --git a/lib/domains/cave/npc/orc_guard4.c b/lib/domains/cave/npc/orc_guard4.c new file mode 100644 index 0000000..dd78c73 --- /dev/null +++ b/lib/domains/cave/npc/orc_guard4.c @@ -0,0 +1,32 @@ +#include <lib.h> + +inherit "/domains/cave/etc/cave_orc"; + +int GetEnemyChaser() { return 0; } + +static void create() { + ::create(); + SetKeyName("orc"); + SetId(({"orc"})); + SetAdjectives(({"armored","professional"})); + SetShort("an armored orc"); + SetLong("This is a large adult orc. He seems to have a professional " + "bearing, and a sense of purpose."); + SetInventory(([ + "/domains/cave/weap/axe" : "wield axe", + "/domains/cave/weap/sword" : "wield sword", + "/domains/cave/armor/leather_armor" : "wear leather armor", + "/domains/cave/armor/orc_boot_l" : "wear left boot", + "/domains/cave/armor/orc_boot_r" : "wear right boot", + ])); + SetRace("orc"); + SetLevel(4); + SetClass("fighter"); + SetGender("male"); + //SetEncounter( (: CheckOrc :) ); + this_object()->SetGuard("north","An orc bars your way!"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/npc/orc_guard5.c b/lib/domains/cave/npc/orc_guard5.c new file mode 100644 index 0000000..a76b469 --- /dev/null +++ b/lib/domains/cave/npc/orc_guard5.c @@ -0,0 +1,36 @@ +#include <lib.h> + +inherit "/domains/cave/etc/cave_orc"; + +int GetEnemyChaser() { return 0; } + +//This function defines what conditions override the guarding of the northeast exit +int AllowPass(object who, object what){ + if(who->GetRace() == "orc") return 1; + return ::AllowPass(who, what); +} + +static void create() { + ::create(); + SetKeyName("orc"); + SetId(({"orc"})); + SetAdjectives(({"armored","professional"})); + SetShort("an armored orc"); + SetLong("This is a large adult orc. He seems to have a professional " + "bearing, and a sense of purpose."); + SetInventory(([ + "/domains/cave/weap/axe" : "wield axe", + "/domains/cave/armor/leather_armor" : "wear leather armor", + "/domains/cave/armor/orc_boot_l" : "wear left boot", + "/domains/cave/armor/orc_boot_r" : "wear right boot", + ])); + SetRace("orc"); + SetLevel(3); + SetClass("fighter"); + SetGender("male"); + this_object()->SetGuard("northeast","The orc bars your way!"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/npc/orc_male1.c b/lib/domains/cave/npc/orc_male1.c new file mode 100644 index 0000000..cf100b2 --- /dev/null +++ b/lib/domains/cave/npc/orc_male1.c @@ -0,0 +1,57 @@ +#include <lib.h> + +inherit "/domains/cave/etc/cave_orc"; + +int throwing; + +int CheckOrc(mixed val){ + if(!val) return 0; + if(!objectp(val)) return 0; + if(val->GetRace() == "orc" || val->GetRace() == "rodent") return 0; + eventForce("growl at "+val->GetKeyName()); + if(!this_object()->GetLeader() && sizeof(filter(val->GetFollowers(), + (: base_name($1) == base_name(this_object()) :))) < 1){ + eventForce("follow "+val->GetKeyName()); + SetWanderSpeed(1); + } + return 1; +} + +static void create() { + ::create(); + SetKeyName("orc"); + SetId(({"orc"})); + SetAdjectives(({"adult","male"})); + SetShort("a male orc"); + SetLong("This is an adult orc, a creature somewhat larger "+ + "and stronger than a typical human."); + SetInventory(([ + "/domains/cave/armor/leather_armor" : "wear leather armor", + "/domains/cave/armor/orc_boot_l" : "wear left boot", + "/domains/cave/armor/orc_boot_r" : "wear right boot", + ])); + SetLevel(2); + SetMelee(1); + SetRace("orc"); + SetClass("fighter"); + SetGender("male"); + SetEncounter( (: CheckOrc :) ); + AddCurrency("gold", random(100)); +} + +void init(){ + object env = environment(); + ::init(); + if(env && base_name(env) == "/domains/cave/room/cave"){ + eventForce("go east"); + } +} + +void heart_beat(){ + object env = room_environment(this_object()); + if(env && base_name(env) == "/domains/cave/room/cave"){ + eventForce("go east"); + } + torch_action(); + ::heart_beat(); +} diff --git a/lib/domains/cave/npc/orc_soldier1.c b/lib/domains/cave/npc/orc_soldier1.c new file mode 100644 index 0000000..2b0a60d --- /dev/null +++ b/lib/domains/cave/npc/orc_soldier1.c @@ -0,0 +1,32 @@ +#include <lib.h> + +inherit "/domains/cave/etc/cave_orc"; + +int GetEnemyChaser() { return 1; } + +static void create() { + ::create(); + SetKeyName("orc"); + SetId(({"orc"})); + SetAdjectives(({"armored","professional"})); + SetShort("an armored orc"); + SetLong("This is a very large adult orc. He seems to have a professional " + "bearing, and a sense of purpose."); + SetInventory(([ + "/domains/cave/weap/axe" : "wield axe", + "/domains/cave/weap/sword" : "wield sword", + "/domains/cave/armor/leather_armor" : "wear leather armor", + "/domains/cave/armor/orc_boot_l" : "wear left boot", + "/domains/cave/armor/orc_boot_r" : "wear right boot", + ])); + SetRace("orc"); + SetLevel(5); + SetClass("fighter"); + SetGender("male"); + SetEncounter( (: CheckOrc :) ); + SetWanderSpeed(3); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/npc/orc_soldier2.c b/lib/domains/cave/npc/orc_soldier2.c new file mode 100644 index 0000000..72c981c --- /dev/null +++ b/lib/domains/cave/npc/orc_soldier2.c @@ -0,0 +1,30 @@ +#include <lib.h> + +inherit "/domains/cave/etc/cave_orc"; + +int GetEnemyChaser() { return 1; } + +static void create() { + ::create(); + SetKeyName("orc"); + SetId(({"orc","soldier"})); + SetAdjectives(({"orc","armored","professional","soldier"})); + SetShort("an orc soldier"); + SetLong("This is a large orc soldier."); + SetInventory(([ + "/domains/cave/weap/longsword" : "wield sword", + "/domains/cave/armor/chainmail" : "wear chainmail", + "/domains/cave/armor/orc_boot_l" : "wear left boot", + "/domains/cave/armor/orc_boot_r" : "wear right boot", + ])); + SetRace("orc"); + SetLevel(7); + SetClass("fighter"); + SetGender("male"); + SetEncounter( (: CheckOrc :) ); + SetWanderSpeed(5); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/npc/rat.c b/lib/domains/cave/npc/rat.c new file mode 100644 index 0000000..aee39cf --- /dev/null +++ b/lib/domains/cave/npc/rat.c @@ -0,0 +1,53 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +int RatEncounter(mixed val){ + if(!val) return 0; + if(!objectp(val)) return 0; + if(val->GetRace() == "orc" || val->GetRace() == "rodent") return 0; + else { + if(!this_object()->GetLeader() && sizeof(filter(val->GetFollowers(), + (: base_name($1) == base_name(this_object()) :))) < 5){ + eventForce("follow "+val->GetKeyName()); + SetWanderSpeed(1); + } + return 1; + } + return 0; +} + +static void create() { + sentient::create(); + SetKeyName("rat"); + SetAdjectives( ({"ratlike","unusual","large","very","dangerous", + "dangerous looking","rat like"}) ); + SetId( ({"rat","rous","beast"}) ); + SetShort("a rodent of unusual size"); + SetLong("A very large, very dangerous-looking ratlike beast."); + SetRace("rodent"); + SetGender("male"); + SetClass("fighter"); + SetEncounter( (: RatEncounter :)); + SetLevel(3); + SetMelee(1); + SetMessage("come","$N scurries in."); + SetMessage("leave","$N scurries $D."); +} + +void init(){ + object env = environment(); + ::init(); + if(env && base_name(env) == "/domains/cave/room/cave"){ + eventForce("go east"); + } +} + +void heart_beat(){ + object env = environment(); + ::heart_beat(); + if(env && base_name(env) == "/domains/cave/room/cave"){ + eventForce("go east"); + } +} + diff --git a/lib/domains/cave/npc/rybak.c b/lib/domains/cave/npc/rybak.c new file mode 100644 index 0000000..ee6b3e2 --- /dev/null +++ b/lib/domains/cave/npc/rybak.c @@ -0,0 +1,53 @@ +#include <lib.h> +#include <position.h> + +inherit LIB_BARKEEP; + +int CheckOrc(mixed val){ + if(!val) return 0; + if(!objectp(val)) return 0; + if(val->GetRace() == "orc" || val->GetRace() == "rodent") return 0; + else eventForce("growl at "+val->GetKeyName()); + return 1; +} + +static void create() { + barkeep::create(); + SetKeyName("orc cook"); + SetAdjectives( ({ "orc" }) ); + SetId( ({ "rybak","cook" }) ); + SetShort("the orc cook"); + SetRace("orc"); + SetClass("fighter"); + SetLevel(15); + SetLong("Bizarrely large, fit, and alert, this orc cook would "+ + "seem more in place in a uniform than serving food in a "+ + "commissary. You can: ask cook for menu"); + SetMelee(1); + SetInventory(([ + "/domains/cave/armor/foodsmock" : "wear smock", + ])); + SetMenuItems(([ + ({ "roast beast", "beast" }) : "/domains/cave/meals/beast", + ({ "black bread", "bread" }) : "/domains/cave/meals/bread", + ])); + SetGender("male"); + AddCurrency("electrum", random(200)); + SetSkill("bargaining", 1); + SetProperty("no bump", 1); + SetLocalCurrency("silver"); + SetEncounter( (: CheckOrc :) ); +} + +void init(){ + ::init(); +} + +int eventList(object who, string cmd, string args){ + int ret = ::eventList(who, cmd, args); + if(ret){ + eventForce("speak Help yourself to the grog and water. They're "+ + "free of charge."); + } + return ret; +} diff --git a/lib/domains/cave/obj/bbucket.c b/lib/domains/cave/obj/bbucket.c new file mode 100644 index 0000000..53f2696 --- /dev/null +++ b/lib/domains/cave/obj/bbucket.c @@ -0,0 +1,35 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("bin"); + SetId(({"bin","can","dustbin","trash","rubbish"})); + SetAdjectives(({"metal","small","blue","recycling","trash","garbage","dust"})); + SetShort("a recycling bin"); + SetLong("This is a blue trash can, marked with "+ + "the letters \"/dev/null\"."); + SetMass(274); + SetBaseCost("silver",50); + SetMaxCarry(999999); +} + +int tidy_up(){ + object *inv; + inv = all_inventory(this_object()); + foreach(object thing in inv){ + if(thing) thing->eventMove(load_object("/domains/cave/room/furnace")); + } + return 1; +} + +int eventReceiveObject(object ob){ + write("You make a deposit into the the recycling bin.\n"); + call_out((: tidy_up :),1); + return 1; +} +mixed CanGet(object ob) { return "The bucket does not budge.";} + +void init(){ +} diff --git a/lib/domains/cave/obj/cask.c b/lib/domains/cave/obj/cask.c new file mode 100644 index 0000000..0c1fe17 --- /dev/null +++ b/lib/domains/cave/obj/cask.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> +inherit LIB_FLASK; + +void create(){ + ::create(); + SetKeyName("cask"); + SetId( ({"cask","keg"}) ); + SetAdjectives( ({"large","wooden","wood"}) ); + SetShort("a wooden cask"); + SetLong("A large wooden cask for containing fluids."); + SetMass(1000); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetFlaskContents("wine"); + SetFlaskUses(20); + SetStrength(10); + SetMaxFlask(50); + SetMealType(MEAL_ALCOHOL); + SetTapped(1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/cask1.c b/lib/domains/cave/obj/cask1.c new file mode 100644 index 0000000..4134c1e --- /dev/null +++ b/lib/domains/cave/obj/cask1.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> +inherit LIB_FLASK; + +void create(){ + ::create(); + SetKeyName("cask"); + SetId( ({"cask","keg"}) ); + SetAdjectives( ({"large","wooden","wood"}) ); + SetShort("a wooden cask"); + SetLong("A large wooden cask for containing fluids."); + SetMass(1000); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetFlaskContents("water"); + SetFlaskUses(20); + SetStrength(5); + SetMaxFlask(50); + SetMealType(MEAL_DRINK); + SetTapped(1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/cask2.c b/lib/domains/cave/obj/cask2.c new file mode 100644 index 0000000..0c1fe17 --- /dev/null +++ b/lib/domains/cave/obj/cask2.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> +inherit LIB_FLASK; + +void create(){ + ::create(); + SetKeyName("cask"); + SetId( ({"cask","keg"}) ); + SetAdjectives( ({"large","wooden","wood"}) ); + SetShort("a wooden cask"); + SetLong("A large wooden cask for containing fluids."); + SetMass(1000); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetFlaskContents("wine"); + SetFlaskUses(20); + SetStrength(10); + SetMaxFlask(50); + SetMealType(MEAL_ALCOHOL); + SetTapped(1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/cask3.c b/lib/domains/cave/obj/cask3.c new file mode 100644 index 0000000..68298a1 --- /dev/null +++ b/lib/domains/cave/obj/cask3.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> +inherit LIB_FLASK; + +void create(){ + ::create(); + SetKeyName("cask"); + SetId( ({"cask","keg"}) ); + SetAdjectives( ({"large","wooden","wood"}) ); + SetShort("a wooden cask"); + SetLong("A large wooden cask for containing fluids."); + SetMass(2000); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetFlaskContents("wine"); + SetFlaskUses(50); + SetStrength(10); + SetMaxFlask(50); + SetMealType(MEAL_ALCOHOL); + SetTapped(1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/cask4.c b/lib/domains/cave/obj/cask4.c new file mode 100644 index 0000000..a697011 --- /dev/null +++ b/lib/domains/cave/obj/cask4.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> +inherit LIB_FLASK; + +void create(){ + ::create(); + SetKeyName("cask"); + SetId( ({"cask","keg"}) ); + SetAdjectives( ({"large","wooden","wood"}) ); + SetShort("a wooden cask"); + SetLong("A large wooden cask for containing fluids."); + SetMass(2000); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetFlaskContents("water"); + SetFlaskUses(50); + SetStrength(5); + SetMaxFlask(50); + SetMealType(MEAL_DRINK); + SetTapped(1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/cask5.c b/lib/domains/cave/obj/cask5.c new file mode 100644 index 0000000..e4901d4 --- /dev/null +++ b/lib/domains/cave/obj/cask5.c @@ -0,0 +1,33 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> +inherit LIB_FLASK; + +void create(){ + ::create(); + SetKeyName("cask"); + SetId( ({"cask","keg"}) ); + SetAdjectives( ({"large","wooden","wood"}) ); + SetShort("a wooden cask"); + SetLong("A large wooden cask for containing fluids."); + SetMass(2000); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetFlaskContents("grog"); + SetFlaskUses(1000); + SetStrength(5); + SetMaxFlask(1000); + SetMealType(MEAL_ALCOHOL); + SetTapped(1); + SetPreventGet("The cask is firmly attached to the floor."); +} + +void init(){ + ::init(); +} + +mixed CanDrink(object who, string what){ + return "This is a tapped "+GetKeyName()+". You fill something "+ + "with it, you don't drink directly from it, you barbarian."; +} + diff --git a/lib/domains/cave/obj/chair.c b/lib/domains/cave/obj/chair.c new file mode 100644 index 0000000..9151403 --- /dev/null +++ b/lib/domains/cave/obj/chair.c @@ -0,0 +1,18 @@ +#include <lib.h> + +inherit LIB_CHAIR; + +static void create() { + chair::create(); + SetKeyName("chair"); + SetAdjectives( ({"simple", "wooden"}) ); + SetId("chair"); + SetShort("a wooden chair"); + SetLong("A simple chair, made of wood, for sitting on."); + SetMass(150); + SetDollarCost(15); + SetMaxSitters(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/chest.c b/lib/domains/cave/obj/chest.c new file mode 100644 index 0000000..10689d6 --- /dev/null +++ b/lib/domains/cave/obj/chest.c @@ -0,0 +1,27 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("chest"); + SetAdjectives(({"wooden","heavy"})); + SetId(({"chest"})); + SetShort("a wooden chest"); + SetLong("This is a heavy wooden chest used to store items."); + SetInventory(([ + "/domains/cave/obj/letter2" : 1, + "/domains/cave/armor/pajamas" : 1, + "/domains/cave/obj/food_storage1_key" : 1, + "/domains/cave/obj/letter3" : 1, + ])); + SetMass(2000); + SetBaseCost("silver",50); + SetMaxCarry(500); + SetCanClose(1); + SetClosed(1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/chest2.c b/lib/domains/cave/obj/chest2.c new file mode 100644 index 0000000..b816e5c --- /dev/null +++ b/lib/domains/cave/obj/chest2.c @@ -0,0 +1,35 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("chest"); + SetAdjectives(({"wooden","heavy"})); + SetId(({"chest"})); + SetShort("a wooden chest"); + SetLong("This is a heavy wooden chest used to store items."); + SetMaxCarry(9000); + SetInventory(([ + "/domains/cave/obj/omni" : 1, + "/domains/cave/armor/boobytrap_ring" : 1, + "/domains/cave/armor/necklace" : 1, + ])); + SetMoney( ([ + //"dollars" : random(50)+50, + "gold" : random(50)+50, + "silver" : random(500)+500, + "copper" : random(9000)+9000, + "electrum" : random(100)+100, + "platinum" : random(20)+20, + ]) ); + SetMass(2000); + SetBaseCost("silver",50); + SetCanClose(1); + SetClosed(1); + SetPreventGet("The chest does not budge."); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/cot.c b/lib/domains/cave/obj/cot.c new file mode 100644 index 0000000..6c1f588 --- /dev/null +++ b/lib/domains/cave/obj/cot.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include <props.h> + +inherit LIB_BED; + +static void create() { + ::create(); + SetKeyName("cot"); + SetId( ({ "cot","bed" }) ); + SetAdjectives( ({ "simple"}) ); + SetShort("a simple cot"); + SetLong("This is a simple cot designed for " + "sleepers that do not require a comfortable bed."); + SetMass(500); + SetBaseCost("silver",15); + SetMaxSitters(2); + SetMaxLiers(1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/cup.c b/lib/domains/cave/obj/cup.c new file mode 100644 index 0000000..f33fb2c --- /dev/null +++ b/lib/domains/cave/obj/cup.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> +inherit LIB_FLASK; + +void create(){ + ::create(); + SetKeyName("cup"); + SetId( ({"cup", "cup made of wood"}) ); + SetAdjectives( ({"simple","wooden"}) ); + SetShort("a wooden cup"); + SetLong("A simple cup made of wood, for containing fluids."); + SetMass(5); + SetBaseCost("silver",1); + SetVendorType(VT_TREASURE); + SetFlaskUses(0); + SetStrength(5); + SetMaxFlask(1); + SetMealType(MEAL_DRINK); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/ecoli.c b/lib/domains/cave/obj/ecoli.c new file mode 100644 index 0000000..01c2d6a --- /dev/null +++ b/lib/domains/cave/obj/ecoli.c @@ -0,0 +1,158 @@ +#include <lib.h> +#include ROOMS_H +#include <vendor_types.h> +#include <damage_types.h> +inherit LIB_GERM; +int damage1(); +int damage2(); +int damage3(); +int damage4(); +int damage5(); +object victim,where; +string victimname; + +int CalculateDuration(){ + int ret = 600; + ret += random(9000); + return ret; +} + +int InfectMess(object ob){ + victim=ob; + victimname=victim->GetName(); + tell_room(environment(victim), victimname+" looks weak and woozy.",({victim}) ); + tell_object(victim, "You feel weak and dizzy."); + return 1; +} + +void create(){ + germ::create(); + SetKeyName("e coli"); + SetGermName("e. coli"); + SetId(({"ecoli"})); + SetLong("Escherichia coli"); + SetCure(40); + SetCommunicable(0); + SetLifeSpan( (: CalculateDuration :) ); + SetType("viral"); + SetInfect((: InfectMess :)); +} + +void bonuses(){ + if(victim && environment(this_object()) == victim){ + victim->AddStatBonus("intelligence", + -(percent_of(20,this_player()->GetBaseStatLevel("intelligence")))); + victim->AddStatBonus("strength", + -(percent_of(75,this_player()->GetBaseStatLevel("strength")))); + victim->AddStatBonus("charisma", + -(percent_of(65,this_player()->GetBaseStatLevel("charisma")))); + victim->AddStatBonus("durability", + -(percent_of(65,this_player()->GetBaseStatLevel("durability")))); + victim->AddStatBonus("agility", + -(percent_of(40,this_player()->GetBaseStatLevel("agility")))); + victim->AddStatBonus("coordination", + -(percent_of(45,this_player()->GetBaseStatLevel("coordination")))); + victim->AddStatBonus("speed", + -(percent_of(55,this_player()->GetBaseStatLevel("speed")))); + victim->AddStatBonus("wisdom", + -(percent_of(10,this_player()->GetBaseStatLevel("wisdom")))); + } + else if(victim) { + foreach( string stat in ({"intelligence", "strength", + "charisma", "durability", "agility", "coordination", "speed", "wisdom"})){ + victim->RemoveStatBonus(stat); + } + } + return; +} + +void init(){ + germ::init(); + bonuses(); +} + +int eventDestruct(){ + this_object()->eventMove(ROOM_FURNACE); + return ::eventDestruct(); +} + +int eventMove(mixed dest){ + int ret = germ::eventMove(dest); + if(environment() && !living(environment())) victim = 0; + bonuses(); + return ret; +} + +int eventSuffer(){ + int x; + x=random(1000); + if(x < 5) damage1(); + else if(x < 10) damage2(); + else if(x < 15) damage3(); + else if(x < 20) damage4(); + else if(x < 30) damage5(); + return 1; +} + +string GetAffectLong(object ob) { + if(!ob || !living(ob)) return 0; + return ob->GetName() + " is disheveled.\n"+ob->GetName()+" looks very ill and disoriented."; +} + +int damage1(){ + if(victim){ + tell_object(victim,"You feel weak and ill."); + tell_room(environment(victim),victimname+" looks pale and ill.", ({victim}) ); + victim->AddStaminaPoints(random(-2)-2); + } + return 1; +} + +int damage2(){ + if(victim){ + tell_object(victim,"You are racked by a fit of gruesome-sounding retching."); + tell_room(environment(victim),victimname+" is racked by a fit of gruesome-sounding retching.", ({victim}) ); + victim->AddHP(-(random(3)+3)); + victim->AddStaminaPoints(-(random(3))-3); + } + return 1; +} + +int damage3(){ + if(victim){ + tell_room(environment(victim),victimname+" lets out a groan of discomfort.", ({victim}) ); + tell_object(victim,"You let out a groan of discomfort as a wave of weakness hits you."); + victim->AddStaminaPoints(-(random(4))-4); + } + return 1; +} + +int damage4(){ + if(victim){ + tell_room(environment(victim),victimname+" gags violently, then chokes out a thick rope of vomit onto the ground.", ({victim}) ); + tell_object(victim,"You gag violently, then choke out a thick rope of vomit onto the ground."); + victim->AddHP(-(random(5)+5)); + victim->AddStaminaPoints(-(random(5))-5); + } + return 1; +} + +int damage5(){ + if(victim){ + if(victim->GetPosition() != 1){ + tell_room(environment(victim),victimname+" makes a horrendous flatulent noise and falls helplessly to the floor, soiling "+objective(victim)+"self.", ({victim}) ); + tell_object(victim,"You make a horrendous flatulent noise and fall helplessly to the floor, soiling yourself."); + victim->SetPosition(1); + } + if(victim->GetPosition() == 1){ + tell_room(environment(victim),victimname+" makes a horrendous flatulent noise as "+nominative(victim)+" lies helplessly on the ground.", ({ victim})); + tell_object(victim,"You make a horrendous flatulent noise as you lie helplessly on the ground."); + } + victim->AddHP(-(random(10)+10)); + victim->AddStaminaPoints(-(random(10))-10); + } + return 1; +} + +mixed CanGet(object ob) { return "You can't do that.";} +mixed CanDrop(object ob) { return "You can't do that.";} diff --git a/lib/domains/cave/obj/everstrike_match.c b/lib/domains/cave/obj/everstrike_match.c new file mode 100644 index 0000000..f327985 --- /dev/null +++ b/lib/domains/cave/obj/everstrike_match.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_MATCH; + + +static void create() { + match::create(); + SetKeyName("match"); + SetId("match"); + SetAdjectives( ({ "wooden" }) ); + SetShort("a wooden match"); + SetLong("A wooden match that might light if you strike it."); + SetRadiantLight(2); + SetStrikeChance(100); + SetMinHeat(10); + SetFuelRequired(1); + SetMaxFuel(10); + SetFuelAmount(10); + SetRefuelable(0); + SetMass(5); + SetBaseCost("silver",2); + SetBurntValue(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/fishbarrel.c b/lib/domains/cave/obj/fishbarrel.c new file mode 100644 index 0000000..f7f2427 --- /dev/null +++ b/lib/domains/cave/obj/fishbarrel.c @@ -0,0 +1,21 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("barrel"); + SetId( ({ "barrel" }) ); + SetAdjectives( ({ "simple","oak","oaken","wood","wooden" }) ); + SetShort("an oak barrel"); + SetLong("It is a simple wooden barrel used for holding things."); + SetMass(474); + SetMaxCarry(500); + SetInventory( ([ + "/domains/cave/meals/herring" : random(100), + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/food_storage1_key.c b/lib/domains/cave/obj/food_storage1_key.c new file mode 100644 index 0000000..121dc55 --- /dev/null +++ b/lib/domains/cave/obj/food_storage1_key.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("key"); + SetId( ({ "food_storage_one","key for a door" }) ); + SetAdjectives( ({ "simple","iron","door" }) ); + SetShort("an iron key"); + SetLong("It is a simple iron key for a door."); + SetMass(5); + SetBaseCost("silver",1); + SetDisableChance(1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/garbage.c b/lib/domains/cave/obj/garbage.c new file mode 100644 index 0000000..45dd670 --- /dev/null +++ b/lib/domains/cave/obj/garbage.c @@ -0,0 +1,47 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; + +int searched; + +string SearchCrap(){ + string result; + if(!searched){ + if(!random(1000)){ + result="Rummaging through the disgusting pile, you "+ + "discover a beautiful gold ring mixed in with the "+ + "crap."; + say(this_player()->GetName()+" searches a pile of debris "+ + "and seems to have found something of value."); + if(!new("/domains/campus/armor/ring")->eventMove(this_player())) + new("/domains/campus/armor/ring")->eventMove(environment(this_object())); + searched=1; + return result; + } + } + + result="You rummage through the disgusting pile "+ + "and find nothing."; + say(this_player()->GetName()+" searches a pile of debris "+ + "with no results."); + searched=1; + return result; +} + +void create(){ + ::create(); + SetKeyName("garbage"); + SetId( ({"pile","debris","crap","crud"}) ); + SetAdjectives( ({"disgusting","pile of","smelly"}) ); + SetShort("a pile of garbage"); + SetLong("This is a smelly, disgusting pile of garbage."); + SetMass(2000); + SetDollarCost(0); + SetSearch( (: SearchCrap :) ); + SetNoCondition(1); + SetPreventGet("The pile of debris isn't at all portable."); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/gate_key.c b/lib/domains/cave/obj/gate_key.c new file mode 100644 index 0000000..9870587 --- /dev/null +++ b/lib/domains/cave/obj/gate_key.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("key"); + SetId( ({ "key", "cavetroll key" }) ); + SetAdjectives( ({ "metal" }) ); + SetShort("a metal key"); + SetLong("It is a key made of metal."); + SetMass(10); + SetBaseCost("silver",1); + SetDisableChance(100); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/jerkybox.c b/lib/domains/cave/obj/jerkybox.c new file mode 100644 index 0000000..c82f8c9 --- /dev/null +++ b/lib/domains/cave/obj/jerkybox.c @@ -0,0 +1,21 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("box"); + SetId( ({ "box" }) ); + SetAdjectives( ({ "wooden","wood" }) ); + SetShort("a wooden box"); + SetLong("It is a wooden box used to hold things."); + SetMass(274); + SetMaxCarry(500); + SetInventory( ([ + "/domains/cave/meals/jerky" : random(100)+1, + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/jerkybox2.c b/lib/domains/cave/obj/jerkybox2.c new file mode 100644 index 0000000..d67e24f --- /dev/null +++ b/lib/domains/cave/obj/jerkybox2.c @@ -0,0 +1,21 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("crate"); + SetId( ({ "crate" }) ); + SetAdjectives( ({ "large", "wooden","wood" }) ); + SetShort("a large crate"); + SetLong("It is a wood crate used to hold things."); + SetMass(374); + SetMaxCarry(700); + SetInventory( ([ + "/domains/cave/meals/jerky" : random(350)+1, + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/letter.c b/lib/domains/cave/obj/letter.c new file mode 100644 index 0000000..edb9985 --- /dev/null +++ b/lib/domains/cave/obj/letter.c @@ -0,0 +1,47 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +inherit LIB_READ; + +string ReadFun(){ + string ret = "Dearest Kasatka,\n"; + ret += "You are right, and I must no longer do you the dishonour "+ + "of lying to you about the eastern frontiers. You deserve to know the "+ + "truth of our most desperate situation. The humanoids are an "+ + "implacable foe. They fight with the fury of demons, and seem "+ + "infinite in number. They are immune to diplomacy, insatiable "+ + "in their lust for blood and treasure, and revel in the horrors of "+ + "war they bring with them.\n\n"+ + "My finest sergeant's little boy was slaughtered in the last "+ + "attack on our outpost. He had feared sending him to the "+ + "western lands because of how many roving bands of human "+ + "adventurers now prey on the weak. Instead, here inside our own "+ + "stronghold, they came, and took his little life. A defenseless "+ + "child, who before he died, saw his mother fall under a "+ + "dwarven hammer.\n\n"+ + "Kasatka, my love for you is deathless. It binds me with mighty "+ + "chains that none can break. Yet duty holds me fast, and I pray "+ + "that what we do here, and what we may yet do if reinforcements "+ + "arrive in time, will stop this horrendous plague that threatens "+ + "our beau-\n\nI think I hear something. They may be here. Kasatka, "+ + "if these lines fall under your eye, and I am no more, know th"; + return ret; +} + +void create(){ + ::create(); + SetKeyName("letter"); + SetId(({"letter","sheet","paper","sheet of paper","kletter"})); + SetAdjectives(({"small"})); + SetShort("a letter"); + SetLong("This is a sheet of paper with a message printed on it. "); + SetMass(1); + AddItem("message","A message written on paper."); + SetRead("default", (: ReadFun :) ); + SetRead(({"message"}), (: ReadFun :) ); + SetLanguage("Tangetto"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/letter2.c b/lib/domains/cave/obj/letter2.c new file mode 100644 index 0000000..af8f923 --- /dev/null +++ b/lib/domains/cave/obj/letter2.c @@ -0,0 +1,34 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +inherit LIB_READ; + +string ReadFun(){ + string ret = "Commander Kurogane,\n"; + ret += "We cannot assist you at this time. Azusa coast is "+ + "under concentrated attack by an invasion force. All our "+ + "soldiers are needed here. You are ordered to maintain your "+ + "garrison in place and continue to observe and report on "+ + "humanoid activity at the eastern frontiers. Notify us "+ + "at once if you observe unusual lights in the sky.\n\n"+ + "-General Ikomo"; + return ret; +} + +void create(){ + ::create(); + SetKeyName("letter"); + SetId(({"letter","sheet","paper","sheet of paper"})); + SetAdjectives(({"small"})); + SetShort("a letter"); + SetLong("This is a sheet of paper with a message printed on it. "); + SetMass(1); + AddItem("message","A message written on paper."); + SetRead("default", (: ReadFun :) ); + SetRead(({"message"}), (: ReadFun :) ); + SetLanguage("Tangetto"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/letter3.c b/lib/domains/cave/obj/letter3.c new file mode 100644 index 0000000..5b7ece8 --- /dev/null +++ b/lib/domains/cave/obj/letter3.c @@ -0,0 +1,39 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +inherit LIB_READ; + +string ReadFun(){ + string ret = "Kuroganetko,\n"; + ret += "Find it in your heart to forgive the hard tone of "+ + "my orders. It grieves me to deny you, old friend, and I feel "+ + "bound by my love for you to explain them in proper terms here. "+ + "We are in disarray and rout. Your outpost may be the last "+ + "one with able soldiers along the eastern coast. Our foe here "+ + "is savage and possessed of magic weaponry we cannot match. You "+ + "and I and the outposts that have already fallen are serving our "+ + "people by buying them time. The settlements to our west are "+ + "being evacuated, and they may yet live thanks to our sacrifice.\n\n"+ + "May we die well, beloved friend. And may we meet again in the "+ + "halls of honour.\n\n"+ + "-Ikomotko"; + return ret; +} + +void create(){ + ::create(); + SetKeyName("letter"); + SetId(({"letter","sheet","paper","sheet of paper"})); + SetAdjectives(({"small"})); + SetShort("a letter"); + SetLong("This is a sheet of paper with a message printed on it. "); + SetMass(1); + AddItem("message","A message written on paper."); + SetRead("default", (: ReadFun :) ); + SetRead(({"message"}), (: ReadFun :) ); + SetLanguage("Tangetto"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/lever.c b/lib/domains/cave/obj/lever.c new file mode 100644 index 0000000..0bb9806 --- /dev/null +++ b/lib/domains/cave/obj/lever.c @@ -0,0 +1,58 @@ +#include <lib.h> +#include <medium.h> + +inherit LIB_DUMMY; // These do not show up in desc, but you can look at them +inherit LIB_PULL; // Makes the item pullable +inherit LIB_PRESS; // Makes the item pressable + +private static int Sprung = 0; +object chiefroom = load_object("/domains/cave/room/chieftain"); + +int GetSprung(){ + if(Sprung) return 1; + return 0; +} + +int openDoor(object who) { + if(GetSprung()){ + write("The lever is already in the pulled position."); + } + else { + object *inv = ( all_inventory(chiefroom) - ({ this_object() }) ); + write("You pull the lever, and the floor drops out!"); + say(this_player()->GetName()+" pulls the lever, and the floor drops out!"); + tell_room("/domains/cave/room/cavetroll","The ceiling opens up."); + chiefroom->SetMedium(MEDIUM_AIR); + chiefroom->AddExit("down","/domains/cave/room/cavetroll"); + inv->eventCheckEnvironment(); + filter(inv,(: !living($1) :))->eventFall(); + } + Sprung = 1; + return 1; +} + +int closeDoor(object who){ + if(!GetSprung()){ + write("The lever is already in the pushed position."); + } + else { + write("You push the lever, and the floor closes."); + say(this_player()->GetName()+" pushes the lever, and the floor closes."); + tell_room("/domains/cave/room/cavetroll","The ceiling closes."); + chiefroom->SetMedium(MEDIUM_LAND); + chiefroom->RemoveExit("down"); + } + Sprung = 0; + return 1; +} + +static void create() { + dummy::create(); + SetKeyName("lever"); + SetId(({"lever","lever on the wall" })); + SetAdjectives("wooden"); + SetShort("a lever"); + SetLong("It is a lever."); + SetPress((: closeDoor :)); + SetPull((: openDoor :)); +} diff --git a/lib/domains/cave/obj/lister.c b/lib/domains/cave/obj/lister.c new file mode 100644 index 0000000..1858e84 --- /dev/null +++ b/lib/domains/cave/obj/lister.c @@ -0,0 +1,33 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> +inherit LIB_FLASK; + +void create(){ + ::create(); + SetKeyName("lister bag"); + SetId( ({"lister","bag","tripod"}) ); + SetAdjectives( ({"large","canvas","wood","suspended"}) ); + SetShort("a lister bag"); + SetLong("A large canvas bag suspended on a tripod containing "+ + "drinking water."); + SetMass(2000); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetFlaskContents("water"); + SetFlaskUses(1000); + SetStrength(5); + SetMaxFlask(1000); + SetMealType(MEAL_DRINK); + SetTapped(1); + SetPreventGet("This structure is not movable."); +} + +void init(){ + ::init(); +} + +mixed CanDrink(object who, string what){ + return "This is a tapped "+GetKeyName()+". You fill something "+ + "with it, you don't drink directly from it, you barbarian."; +} diff --git a/lib/domains/cave/obj/match.c b/lib/domains/cave/obj/match.c new file mode 100644 index 0000000..eb95a18 --- /dev/null +++ b/lib/domains/cave/obj/match.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_MATCH; + + +static void create() { + match::create(); + SetKeyName("match"); + SetId("match"); + SetAdjectives( ({ "wooden" }) ); + SetShort("a wooden match"); + SetLong("A wooden match that might light if you strike it."); + SetRadiantLight(2); + SetStrikeChance(50); + SetMinHeat(10); + SetFuelRequired(1); + SetMaxFuel(10); + SetFuelAmount(10); + SetRefuelable(0); + SetMass(5); + SetBaseCost("silver",2); + SetBurntValue(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/mug.c b/lib/domains/cave/obj/mug.c new file mode 100644 index 0000000..03a041d --- /dev/null +++ b/lib/domains/cave/obj/mug.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> +inherit LIB_FLASK; + +void create(){ + ::create(); + SetKeyName("mug"); + SetId( ({"mug", "mug made of clay"}) ); + SetAdjectives( ({"simple","clay"}) ); + SetShort("a clay mug"); + SetLong("A simple mug made of clay, for containing fluids."); + SetMass(5); + SetBaseCost("silver",1); + SetVendorType(VT_TREASURE); + SetFlaskUses(0); + SetStrength(5); + SetMaxFlask(2); + SetMealType(MEAL_DRINK); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/omni.c b/lib/domains/cave/obj/omni.c new file mode 100644 index 0000000..d2862ab --- /dev/null +++ b/lib/domains/cave/obj/omni.c @@ -0,0 +1,90 @@ +#include <lib.h> +#include ROOMS_H +inherit LIB_ITEM; +inherit LIB_PRESS; + +int check_environs(); +int vanish_count = 50; +int presses = 3; + +static void create() { + item::create(); + AddSave( ({ "presses", "vanish_count" }) ); + SetKeyName("omni"); + SetId(({"omni","Omni","device"})); + SetShort("an omni"); + SetLong("This is a small, round metal device, copper in color, "+ + "and similar in appearance to a pocket watch. There is a blinking red light "+ + "next to the tiny metal button at its top."); + SetMass(10); + SetDollarCost(300); + AddItem("button", "A button on the omni."); + AddItem(({"light","red light"}) , "A blinking red light."); +} + +void init() { + ::init(); + check_environs(); +} + +mixed CanPress(object who, string target) { + if(!present(this_object()->GetKeyName(),who ) && target == "button"){ + return "You do not have the Omni!"; + } + if(this_object()->GetId() == target){ + return "You cannot push that."; + } + return 1; +} + +mixed eventPress(object who, string where) { + object *rooms = objects( (: inherits(LIB_ROOM, $1) :) ); + object target; + int success = 0; + if(!presses){ + write("Click."); + return 1; + } + rooms = filter(rooms, (: member_array(base_name($1), ({ ROOM_START, + ROOM_FURNACE, ROOM_VOID, ROOM_POD, ROOM_DEATH, ROOM_WIZ, + ROOM_ARCH, ROOM_NETWORK, ROOM_ROUTER, LIB_FURNACE, + ROOM_FREEZER }) ) == -1 && strsrch(base_name($1),"/realms/") && + !inherits(LIB_FURNACE,$1) && + !($1->GetVirtual() && !grepp(base_name($1),",")) && + last_string_element(base_name($1),"/") != "death" :) ); + say(who->GetName()+" turns "+dbz_colors("multicolored")+" and disappears!"); + write("You feel momentarily disoriented and find yourself elsewhere!"); + while(!success){ + target = rooms[random(sizeof(rooms)-1)]; + success = who->eventMove(target); + } + presses--; + who->eventDescribeEnvironment(); + tell_room(target, "With a multicolored flash, "+who->GetName()+ + " appears!",who); + return 1; +} + +void heart_beat(){ + object *holders = filter(containers(this_object()), + (: interactive($1) :) ); + if(sizeof(holders)) vanish_count--; + if(vanish_count < 0){ + tell_object(environment(),"The omni glows brightly and disappears!"); + this_object()->eventDestruct(); + } + if(vanish_count == 5){ + tell_object(environment(),"The omni begins to glow a dull red."); + this_object()->SetLong("This is a small, round metal device, copper in color, "+ + "and similar in appearance to a pocket watch. There is a blinking red light "+ + "next to the tiny metal button at its top. It is glowing a dull red."); + this_object()->SetShort("an omni (glowing)"); + } +} + +int check_environs(){ + if( interactive(environment()) ){ + set_heart_beat(10); + } + return 1; +} diff --git a/lib/domains/cave/obj/rack.c b/lib/domains/cave/obj/rack.c new file mode 100644 index 0000000..4bfb85e --- /dev/null +++ b/lib/domains/cave/obj/rack.c @@ -0,0 +1,33 @@ +#include <lib.h> + +inherit LIB_SURFACE; +object to; + + +void create() { + ::create(); + SetKeyName("rack"); + SetId(({"rack"})); + SetAdjectives(({"knife","metal","fancy","steel","stainless","stainless-steel"})); + SetShort("a mug rack"); + SetLong("This is a rack with pegs for cups and mugs."); + SetMass(274); + SetBaseCost("silver",50); + SetMaxCarry(100); + SetInventory(([ + "/domains/cave/obj/mug" : 4, + "/domains/cave/obj/stein" : 1, + ])); + SetCanClose(0); +} +mixed CanGet(object ob) { return "The rack does not budge.";} +int CanReceive(object ob) { + if(!inherits(LIB_FLASK,ob)){ + write("This is a rack for drinking utensils only."); + return 0; + } + else return 1; +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/skin.c b/lib/domains/cave/obj/skin.c new file mode 100644 index 0000000..1de825b --- /dev/null +++ b/lib/domains/cave/obj/skin.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> +inherit LIB_FLASK; + +void create(){ + ::create(); + SetKeyName("skin"); + SetId( ({"skin","vessel","bladder","pouch"}) ); + SetAdjectives( ({"skin","bladder","water","animal"}) ); + SetShort("a water skin"); + SetLong("A pouch made of animal bladder for containing fluids."); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetFlaskContents("water"); + SetFlaskUses(20); + SetStrength(5); + SetMaxFlask(20); + SetMealType(MEAL_DRINK); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/stein.c b/lib/domains/cave/obj/stein.c new file mode 100644 index 0000000..92c985e --- /dev/null +++ b/lib/domains/cave/obj/stein.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> +inherit LIB_FLASK; + +void create(){ + ::create(); + SetKeyName("grog stein"); + SetId( ({"stein"}) ); + SetAdjectives( ({"grog","fancy"}) ); + SetShort("a stein"); + SetLong("A large stein for holding lots of grog. It is quite "+ + "fancy and no doubt worth a great deal of money."); + SetMass(30); + SetBaseCost("silver",300); + SetVendorType(VT_TREASURE); + SetFlaskUses(0); + SetStrength(5); + SetMaxFlask(10); + SetMealType(MEAL_DRINK); + SetPreventGet("Oddly, it appears extremely difficult to reach."); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/table.c b/lib/domains/cave/obj/table.c new file mode 100644 index 0000000..aa6e6b5 --- /dev/null +++ b/lib/domains/cave/obj/table.c @@ -0,0 +1,24 @@ +#include <lib.h> + +inherit LIB_TABLE; + +void create() { + ::create(); + SetKeyName("wooden table"); + SetId( ({ "table" }) ); + SetAdjectives( ({ "wood","wooden", "simple", "medium-sized" "medium sized" }) ); + SetShort("a wooden table"); + SetLong("It is a simple, medium-sized table made of wood."); + SetInventory(([ + "/domains/cave/obj/cup" : 1, + "/domains/cave/obj/letter" : 1, + ])); + SetMass(274); + SetBaseCost("silver",1); + SetBaseCost("silver",1); + SetMaxCarry(500); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/table2.c b/lib/domains/cave/obj/table2.c new file mode 100644 index 0000000..b500ebd --- /dev/null +++ b/lib/domains/cave/obj/table2.c @@ -0,0 +1,22 @@ +#include <lib.h> + +inherit LIB_TABLE; + +void create() { + ::create(); + SetKeyName("wooden table"); + SetId( ({ "table" }) ); + SetAdjectives( ({ "wood","wooden", "simple", "medium-sized" "medium sized" }) ); + SetShort("a wooden table"); + SetLong("It is a simple, medium-sized table made of wood."); + SetInventory(([ + ])); + SetMass(274); + SetBaseCost("silver",1); + SetBaseCost("silver",1); + SetMaxCarry(500); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/tall_lamp.c b/lib/domains/cave/obj/tall_lamp.c new file mode 100644 index 0000000..422ac90 --- /dev/null +++ b/lib/domains/cave/obj/tall_lamp.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_TORCH; + +void create(){ + ::create(); + SetKeyName("lamp"); + SetId( ({"thing","item","thang","dingus"}) ); + SetAdjectives( ({"generic","sample","template"}) ); + SetShort("a tall lamp"); + SetLong("This is a tall lamp embedded into the floor, designed to provide light."); + SetPreventGet("The lamp is embedded into the floor."); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetRadiantLight(25); + SetFuelAmount(200); +} + +void init(){ + ::init(); + if(!GetLit() && CanBurn(this_object())){ + this_object()->eventBurn(0,0,1); + } +} diff --git a/lib/domains/cave/obj/torch.c b/lib/domains/cave/obj/torch.c new file mode 100644 index 0000000..00ab63b --- /dev/null +++ b/lib/domains/cave/obj/torch.c @@ -0,0 +1,25 @@ +#include <lib.h> + +inherit LIB_TORCH; + +static void create() { + torch::create(); + SetKeyName("torch"); + SetId( ({ "torch", "old torch", "wooden torch" }) ); + SetAdjectives( ({ "old", "wooden" }) ); + SetShort("an old wooden torch"); + SetLong("An old, wooden torch with a bit of cloth wrapped around " + "one end and dipped into a flamable substance."); + SetRadiantLight(15); + SetFuelRequired(1); + SetMaxFuel(1000); + SetFuelAmount(1000); + SetRefuelable(1); + SetMass(50); + SetBaseCost("silver",60); + SetBurntValue(10); + SetClass(10); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/obj/waste.c b/lib/domains/cave/obj/waste.c new file mode 100644 index 0000000..3b7e892 --- /dev/null +++ b/lib/domains/cave/obj/waste.c @@ -0,0 +1,39 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; + +int searched; + +string SearchCrap(){ + string result; + result="You rummage through the disgusting pile "+ + "and find nothing."; + say(this_player()->GetName()+" searches a pile of debris "+ + "with no results."); + + if(!random(10)){ + object germ = new("/domains/cave/obj/ecoli"); + if(germ) germ->eventInfect(this_player()); + } + + searched=1; + return result; +} + +void create(){ + ::create(); + SetKeyName("waste"); + SetId( ({"pile","debris","crap","crud"}) ); + SetAdjectives( ({"waste","biological","disgusting","pile of","smelly"}) ); + SetShort("a pile of waste"); + SetLong("This is a smelly, disgusting pile of biological waste."); + SetMass(2000); + SetDollarCost(0); + SetSearch( (: SearchCrap :) ); + SetNoCondition(1); + SetPreventGet("The pile of debris isn't at all portable."); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/cave.c b/lib/domains/cave/room/cave.c new file mode 100644 index 0000000..9cc3ad0 --- /dev/null +++ b/lib/domains/cave/room/cave.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(5); + SetNightLight(15); + SetDayLight(25); + SetShort("A Dark Cave"); + SetNightLong("This is a cave carved into the rocky riverbank wall. The cave opens west into the night. To the east is darkness."); + SetDayLong("This is a cave carved into the rocky riverbank wall. Daylight shines in from the west, where the river flows. To the east, the cave continues into darkness."); + SetLong("This is a small cave near a riverbank."); + SetItems(([ + ({ "wall", "rocky wall", "river bank wall", "riverbank wall", "rocky river bank wall", "rocky riverbank wall" }) : "The local river carved a narrow and steep valley here over the years. The walls of that valley is what this cave has been dug out of.", + ])); + SetExits( ([ + "west" : "/domains/town/room/riverbank", + "east" : "/domains/cave/room/cavepass1.c", + ]) ); + SetInventory(([ + ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/cavepass1.c b/lib/domains/cave/room/cavepass1.c new file mode 100644 index 0000000..94c54ef --- /dev/null +++ b/lib/domains/cave/room/cavepass1.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(5); + SetShort("underground passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare. To the west the passage opens up into a cave-like area. The passageway continues northeast and east from here."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "area", "cave like area", "cavelike area" }) : "It seems that to the west there is a n area like a cave which opens up to the outside.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetInventory(([ + "/domains/cave/npc/orc_guard5" : 1, + ])); + SetClimate("indoors"); + SetExits( ([ + "east" : "/domains/cave/room/cavepass2", + "west" : "/domains/cave/room/cave", + "northeast" : "/domains/cave/room/cavepass3.c", + ]) ); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/cavepass10.c b/lib/domains/cave/room/cavepass10.c new file mode 100644 index 0000000..c64d79f --- /dev/null +++ b/lib/domains/cave/room/cavepass10.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("underground passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare. The passageway runs north and east from here. There is a room to the south."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetClimate("indoors"); + SetExits( ([ + "north" : "/domains/cave/room/cavepass13", + "east" : "/domains/cave/room/cavepass11", + "south" : "/domains/cave/room/common4.c", + ]) ); + + SetInventory(([ + ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/cavepass11.c b/lib/domains/cave/room/cavepass11.c new file mode 100644 index 0000000..d62e523 --- /dev/null +++ b/lib/domains/cave/room/cavepass11.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("underground passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare. The passageway runs west from here. There is a room to the north."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetClimate("indoors"); + SetExits( ([ + "west" : "/domains/cave/room/cavepass10", + "north" : "/domains/cave/room/common3.c", + ]) ); + + SetInventory(([ + ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/cavepass12.c b/lib/domains/cave/room/cavepass12.c new file mode 100644 index 0000000..8c2865a --- /dev/null +++ b/lib/domains/cave/room/cavepass12.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("underground passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare. The passageway runs northeast, southeast, and west. There is a room to the north."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetClimate("indoors"); + SetExits( ([ + "north" : "/domains/cave/room/dining1", + "northeast" : "/domains/cave/room/cavepass9", + "west" : "/domains/cave/room/cavepass7", + "southeast" : "/domains/cave/room/cavepass13.c", + ]) ); + + SetInventory(([ + ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/cavepass13.c b/lib/domains/cave/room/cavepass13.c new file mode 100644 index 0000000..001357e --- /dev/null +++ b/lib/domains/cave/room/cavepass13.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("underground passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare. The passageway runs northwest and south. There is a room to the north."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetClimate("indoors"); + SetExits( ([ + "south" : "/domains/cave/room/cavepass10", + "northwest" : "/domains/cave/room/cavepass12", + "north" : "/domains/cave/room/chieftain.c", + ]) ); + + SetInventory(([ + ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/cavepass2.c b/lib/domains/cave/room/cavepass2.c new file mode 100644 index 0000000..d84f498 --- /dev/null +++ b/lib/domains/cave/room/cavepass2.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("underground passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare. The passageway contines east and west."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetClimate("indoors"); + SetExits( ([ + "west" : "/domains/cave/room/cavepass1", + "east" : "/domains/cave/room/rubbish.c", + ]) ); + + SetInventory(([ + ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/cavepass3.c b/lib/domains/cave/room/cavepass3.c new file mode 100644 index 0000000..5bffe7a --- /dev/null +++ b/lib/domains/cave/room/cavepass3.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("underground passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare. The passageway contines northwest and southwest. There is some kind of room to the northeast."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetClimate("indoors"); + SetExits( ([ + "northwest" : "/domains/cave/room/cavepass4", + "southwest" : "/domains/cave/room/cavepass1", + "northeast" : "/domains/cave/room/guardroom1.c", + ]) ); + + SetInventory(([ + ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/cavepass4.c b/lib/domains/cave/room/cavepass4.c new file mode 100644 index 0000000..2ba318f --- /dev/null +++ b/lib/domains/cave/room/cavepass4.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("underground passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare. The passageway contines north and south."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetInventory(([ + "/domains/cave/npc/orc_guard4" : 2, + ])); + SetClimate("indoors"); + SetExits( ([ + "north" : "/domains/cave/room/cavepass5", + "southeast" : "/domains/cave/room/cavepass3", + ]) ); + +} +void init(){ + ::init(); + if(!find_object("/domains/cave/room/guardroom1")){ + catch(load_object("/domains/cave/room/guardroom1")); + } +} diff --git a/lib/domains/cave/room/cavepass5.c b/lib/domains/cave/room/cavepass5.c new file mode 100644 index 0000000..d1bd322 --- /dev/null +++ b/lib/domains/cave/room/cavepass5.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("underground passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare. The passageway runs north and south from here, and also splits off toward the east."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetClimate("indoors"); + SetExits( ([ + "north" : "/domains/cave/room/cavepass6", + "south" : "/domains/cave/room/cavepass4", + "east" : "/domains/cave/room/cavepass7.c", + ]) ); + + SetInventory(([ + ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/cavepass6.c b/lib/domains/cave/room/cavepass6.c new file mode 100644 index 0000000..ba84621 --- /dev/null +++ b/lib/domains/cave/room/cavepass6.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("underground passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare. To the north is a room of some sort. The passageway continues south."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetInventory(([ + "/domains/cave/npc/orc_guard4" : 1, + ])); + SetClimate("indoors"); + SetExits( ([ + "south" : "/domains/cave/room/cavepass5", + "north" : "/domains/cave/room/common1.c", + ]) ); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/cavepass7.c b/lib/domains/cave/room/cavepass7.c new file mode 100644 index 0000000..e8aca93 --- /dev/null +++ b/lib/domains/cave/room/cavepass7.c @@ -0,0 +1,32 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("underground passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare. The passageway runs east and west. There are rooms to the north and south."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetClimate("indoors"); + SetExits( ([ + "north" : "/domains/cave/room/guardroom2", + "south" : "/domains/cave/room/food_storage1", + "west" : "/domains/cave/room/cavepass5", + "east" : "/domains/cave/room/cavepass12.c", + ]) ); + + SetInventory(([ + ])); + + SetDoor("south", "/domains/cave/doors/food_storage1"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/cavepass8.c b/lib/domains/cave/room/cavepass8.c new file mode 100644 index 0000000..0c82258 --- /dev/null +++ b/lib/domains/cave/room/cavepass8.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("underground passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare. The passageway runs southeast from here. There are rooms south, northeast, and northwest."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetClimate("indoors"); + SetExits( ([ + "south" : "/domains/cave/room/dining1", + "northeast" : "/domains/cave/room/guardroom3", + "southeast" : "/domains/cave/room/cavepass9", + "northwest" : "/domains/cave/room/guardroom4.c", + ]) ); + + SetInventory(([ + ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/cavepass9.c b/lib/domains/cave/room/cavepass9.c new file mode 100644 index 0000000..8072076 --- /dev/null +++ b/lib/domains/cave/room/cavepass9.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("underground passageway"); + SetLong("This is a dark underground passageway. The walls are rough and bare. The passageway runs southwest and northwest from here. There are rooms to the north, west, and south."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits( ([ + "south" : "/domains/cave/room/chieftain", + "west" : "/domains/cave/room/dining1", + "northwest" : "/domains/cave/room/cavepass8", + "southwest" : "/domains/cave/room/cavepass12", + "north" : "/domains/cave/room/shop.c", + ]) ); + SetClimate("indoors"); + + SetInventory(([ + ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/cavetroll.c b/lib/domains/cave/room/cavetroll.c new file mode 100644 index 0000000..fb71363 --- /dev/null +++ b/lib/domains/cave/room/cavetroll.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("troll pit"); + SetLong("This is a dark underground room. The walls are rough and bare. A passageway leads southwest."); + SetItems(([ + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "room", "here", "area" }) : "Carved roughly into the earth, this area has walls that expose underground rock.", + ])); + SetInventory(([ + "/domains/cave/npc/cavetroll" : 1, + ])); + SetExits( ([ + "southwest" : "/domains/town/room/wtunnel6", + ]) ); + SetClimate("indoors"); + SetDoor("southwest", "/domains/town/doors/gate.c"); + SetFlyRoom("/domains/cave/room/chieftain"); + SetFlowLimit(2); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/chieftain.c b/lib/domains/cave/room/chieftain.c new file mode 100644 index 0000000..cf0811a --- /dev/null +++ b/lib/domains/cave/room/chieftain.c @@ -0,0 +1,32 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("underground room"); + SetLong("This is a dark underground room. The walls are rough and bare. Passageways lead south and north."); + SetItems(([ + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "room", "here", "area" }) : "Carved roughly into the earth, this area has walls that expose underground rock.", + ])); + SetInventory(([ + "/domains/cave/obj/tall_lamp" : 1, + "/domains/cave/obj/lever" : 1, + "/domains/cave/obj/chest2" : 1, + "/domains/cave/npc/chieftain" : 1, + ])); + SetExits( ([ + "north" : "/domains/cave/room/cavepass9", + "south" : "/domains/cave/room/cavepass13", + ]) ); + SetClimate("indoors"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/common1.c b/lib/domains/cave/room/common1.c new file mode 100644 index 0000000..81c846b --- /dev/null +++ b/lib/domains/cave/room/common1.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("underground room"); + SetLong("This is a dark underground room. The walls are rough and bare. A passageway leads away to the south."); + SetItems(([ + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "room", "here", "area" }) : "Carved roughly into the earth, this area has walls that expose underground rock.", + ])); + SetInventory(([ + "/domains/cave/obj/tall_lamp" : 1, + "/domains/cave/npc/orc_male1" : 17, + "/domains/cave/npc/orc_female1" : 23, + "/domains/cave/obj/cot" : 45, + ])); + SetClimate("indoors"); + SetExits(([ + "south" : "/domains/cave/room/cavepass6", + ])); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/common2.c b/lib/domains/cave/room/common2.c new file mode 100644 index 0000000..dcdb552 --- /dev/null +++ b/lib/domains/cave/room/common2.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("underground room"); + SetLong("This is a dark underground passageway. The walls are rough and bare. The passageway continues west from here. There are rooms to the north, east, and south."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetExits(([ + "west" : "/domains/cave/room/cavepass7", + ])); + + SetInventory(([ + ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/common3.c b/lib/domains/cave/room/common3.c new file mode 100644 index 0000000..5e6c4fd --- /dev/null +++ b/lib/domains/cave/room/common3.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("underground room"); + SetLong("This is a dark underground room. The walls are rough and bare. A passageway leads away to the south."); + SetItems(([ + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "room", "here", "area" }) : "Carved roughly into the earth, this area has walls that expose underground rock.", + ])); + SetClimate("indoors"); + SetExits(([ + "south" : "/domains/cave/room/cavepass11", + ])); + + SetInventory(([ + ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/common4.c b/lib/domains/cave/room/common4.c new file mode 100644 index 0000000..bfbc715 --- /dev/null +++ b/lib/domains/cave/room/common4.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("underground room"); + SetLong("This is a dark underground room. The walls are rough and bare. A passageway leads away to the north."); + SetItems(([ + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "room", "here", "area" }) : "Carved roughly into the earth, this area has walls that expose underground rock.", + ])); + SetClimate("indoors"); + SetExits(([ + "north" : "/domains/cave/room/cavepass10", + ])); + + SetInventory(([ + ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/death.c b/lib/domains/cave/room/death.c new file mode 100644 index 0000000..2fa56c9 --- /dev/null +++ b/lib/domains/cave/room/death.c @@ -0,0 +1,72 @@ +#include <lib.h> +#include <dirs.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +string FunkyPic(); +int CheckChat(); +int StartHeart(object ob); + +static void create() { + ::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("off the mortal coil"); + SetLong( (:FunkyPic:) ); + SetObviousExits("no exit"); + set_heart_beat(10); + SetNoModify(1); +} + +void init(){ + ::init(); + add_action("regenerate","regenerate"); + add_action("wander","wander"); + this_object()->CheckChat(); +} + +string FunkyPic(){ + return "YOU ARE DEAD!!!"; +} + +int regenerate(){ + write("With a great rush of matter and energy, you rematerialize "+ + "into a corporeal state, and find yourself in a familiar place..."); + this_player()->eventRevive(); + this_player()->eventMoveLiving(ROOM_START); + return 1; +} + +int wander(){ + write("There is a strange, hollow vibration all around you, and you "+ + "realize that some force is compelling your ethereal form elsewhere..."+ + "you find yourself in a place that is known to you, yet oddly new."); + this_player()->eventMoveLiving(ROOM_START); + return 1; +} + +void heart_beat(){ + tell_room(this_object(), "A voice whispers: \" You may choose to "+ + "regenerate into a new body here.\""); + return; +} + + +int CanRelease(object ob){ + if(userp(ob) && ob->GetGhost() && environment(ob) == this_object()) { + tell_player(ob,"\n%^RED%^Your undead spirit is recalled and as you leave "+ + "the underworld a new body regenerates around you. "+ + "You live again!%^RESET%^\n"); + ob->eventRevive(); + } + return 1; +} + +int CanReceive(object ob){ + if(!living(ob)){ + return 0; + } + return ::CanReceive(ob); +} + diff --git a/lib/domains/cave/room/dining1.c b/lib/domains/cave/room/dining1.c new file mode 100644 index 0000000..71dd411 --- /dev/null +++ b/lib/domains/cave/room/dining1.c @@ -0,0 +1,35 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("post commissary"); + SetLong("This is a dark underground room with rough walls. It is outfitted to accommodate personnel who want to eat and drink. Passageways lead north, east, and south from here."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetInventory(([ + "/domains/cave/obj/tall_lamp" : 1, + "/domains/cave/obj/chair" : 6, + "/domains/cave/obj/table2" : 3, + "/domains/cave/obj/rack" : 1, + "/domains/cave/obj/lister" : 1, + "/domains/cave/obj/cask5" : 1, + "/domains/cave/npc/rybak" : 1, + ])); + SetClimate("indoors"); + SetExits( ([ + "south" : "/domains/cave/room/cavepass12", + "east" : "/domains/cave/room/cavepass9", + "north" : "/domains/cave/room/cavepass8.c", + ]) ); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/food_storage1.c b/lib/domains/cave/room/food_storage1.c new file mode 100644 index 0000000..ec506c2 --- /dev/null +++ b/lib/domains/cave/room/food_storage1.c @@ -0,0 +1,36 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("underground room"); + SetLong("This is a dark underground room. The walls are rough and bare. A passageway leads away to the north."); + SetItems(([ + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "room", "here", "area" }) : "Carved roughly into the earth, this area has walls that expose underground rock.", + ])); + SetInventory(([ + "/domains/cave/obj/fishbarrel" : 1, + "/domains/cave/obj/cask4" : 1, + "/domains/cave/obj/cask3" : 1, + "/domains/cave/obj/cask2" : 2, + "/domains/cave/obj/cask1" : 3, + "/domains/cave/obj/jerkybox" : 3, + "/domains/cave/obj/jerkybox2" : 1, + ])); + SetClimate("indoors"); + SetExits(([ + "north" : "/domains/cave/room/cavepass7", + ])); + + SetDoor("north", "/domains/cave/doors/food_storage1"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/freezer.c b/lib/domains/cave/room/freezer.c new file mode 100644 index 0000000..896cbbf --- /dev/null +++ b/lib/domains/cave/room/freezer.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetNoClean(1); + SetProperties(([ "login" : ROOM_START ])); + SetShort( "The freezer"); + SetLong( "The local freezer. Go down to leave."); + SetObviousExits("down"); + SetExits( ([ "down" : ROOM_START ]) ); + call_out("clean_room", MAX_NET_DEAD_TIME); + SetNoModify(1); +} + +static void clean_room(){ + object ob; + call_out((: clean_room :), MAX_NET_DEAD_TIME); + foreach(ob in filter(all_inventory(), (: living($1) :))){ + string name = last_string_element(base_name(ob),"/"); + if(!user_exists(name)) continue; + ob->eventDestruct(); + } +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/furnace.c b/lib/domains/cave/room/furnace.c new file mode 100644 index 0000000..240341a --- /dev/null +++ b/lib/domains/cave/room/furnace.c @@ -0,0 +1,10 @@ +#include <lib.h> + +inherit LIB_FURNACE; + +void create() { + furnace::create(); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/guardroom1.c b/lib/domains/cave/room/guardroom1.c new file mode 100644 index 0000000..b2190d7 --- /dev/null +++ b/lib/domains/cave/room/guardroom1.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("underground room"); + SetLong("This is a dark underground room. The walls are rough and bare. A passageway leads away to the southwest."); + SetItems(([ + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "room", "here", "area" }) : "Carved roughly into the earth, this area has walls that expose underground rock.", + ])); + SetInventory(([ + "/domains/cave/obj/tall_lamp" : 1, + "/domains/cave/npc/orc_guard2" : 3, + "/domains/cave/npc/orc_guard1" : 3, + ])); + SetClimate("indoors"); + SetExits(([ + "southwest" : "/domains/cave/room/cavepass3", + ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/guardroom2.c b/lib/domains/cave/room/guardroom2.c new file mode 100644 index 0000000..94bf174 --- /dev/null +++ b/lib/domains/cave/room/guardroom2.c @@ -0,0 +1,32 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("underground room"); + SetLong("This is a dark underground room. The walls are rough and bare. A passageway leads away to the south."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetInventory(([ + "/domains/cave/obj/tall_lamp" : 1, + "/domains/cave/npc/orc_guard4" : 2, + "/domains/cave/npc/orc_guard3" : 3, + ])); + SetExits( ([ + "south" : "/domains/cave/room/cavepass7", + "north" : "/domains/cave/room/kurogane.c", + ]) ); + SetClimate("indoors"); + + SetDoor("north", "/domains/cave/doors/kurogane.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/guardroom3.c b/lib/domains/cave/room/guardroom3.c new file mode 100644 index 0000000..ce3e23c --- /dev/null +++ b/lib/domains/cave/room/guardroom3.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("underground room"); + SetLong("This is a dark underground room. The walls are rough and bare. A passageway leads away to the southwest."); + SetItems(([ + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "room", "here", "area" }) : "Carved roughly into the earth, this area has walls that expose underground rock.", + ])); + SetInventory(([ + "/domains/cave/obj/cot" : 2, + "/domains/cave/npc/orc_soldier2" : 2, + ])); + SetClimate("indoors"); + SetExits(([ + "southwest" : "/domains/cave/room/cavepass8", + ])); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/guardroom4.c b/lib/domains/cave/room/guardroom4.c new file mode 100644 index 0000000..9d02d3a --- /dev/null +++ b/lib/domains/cave/room/guardroom4.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("underground room"); + SetLong("This is a dark underground room. The walls are rough and bare. A passageway leads away to the southeast."); + SetItems(([ + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "room", "here", "area" }) : "Carved roughly into the earth, this area has walls that expose underground rock.", + ])); + SetInventory(([ + "/domains/cave/obj/cot" : 4, + "/domains/cave/npc/orc_soldier1" : 4, + ])); + SetClimate("indoors"); + SetExits(([ + "southeast" : "/domains/cave/room/cavepass8", + ])); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/kurogane.c b/lib/domains/cave/room/kurogane.c new file mode 100644 index 0000000..1e1b948 --- /dev/null +++ b/lib/domains/cave/room/kurogane.c @@ -0,0 +1,34 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("commander's quarters"); + SetLong("This is a dark underground room. The walls are rough and bare. A passageway leads away to the south."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetInventory(([ + "/domains/cave/npc/kurogane" : 1, + "/domains/cave/obj/tall_lamp" : 1, + "/domains/cave/obj/table" : 1, + "/domains/cave/obj/chest" : 1, + "/domains/cave/obj/cot" : 1, + ])); + SetExits(([ + "south" : "/domains/cave/room/guardroom2", + ])); + + SetClimate("indoors"); + + SetDoor("south", "/domains/cave/doors/kurogane.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/pod.c b/lib/domains/cave/room/pod.c new file mode 100644 index 0000000..01aced6 --- /dev/null +++ b/lib/domains/cave/room/pod.c @@ -0,0 +1,16 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(30); + SetShort("the incept pod"); + SetLong("The incept pod. Some objects come here to be created "+ + "and identified. Go down to get out."); + SetExits( ([ "down" : ROOM_START ]) ); +} +int CanReceive(object ob){ + return ::CanReceive(ob); +} diff --git a/lib/domains/cave/room/rubbish.c b/lib/domains/cave/room/rubbish.c new file mode 100644 index 0000000..58afa54 --- /dev/null +++ b/lib/domains/cave/room/rubbish.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("underground garbage dump"); + SetLong("This underground area is full of foul piles of putrefying garbage and biological waste. A passageway leads west away from here."); + SetItems(([ + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ])); + SetInventory(([ + "/domains/cave/obj/garbage" : 13, + "/domains/cave/npc/rat" : 18, + "/domains/cave/obj/waste" : 37, + ])); + SetClimate("indoors"); + SetExits(([ + "west" : "/domains/cave/room/cavepass2", + ])); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/shop.c b/lib/domains/cave/room/shop.c new file mode 100644 index 0000000..8d7b90c --- /dev/null +++ b/lib/domains/cave/room/shop.c @@ -0,0 +1,38 @@ +#include <lib.h> +inherit LIB_SHOP; + +int read_sign(); +static void create() { + ::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("The General Store"); + SetLong("This is the local general store. You can buy or sell items here. A sign on the wall hangs here, explaining how things work. Try 'read sign'. East Village Road is south of here. The storeroom is below."); + SetItems(([ + ({"store","shop","place"}) : "This is the local store.", + ({ "sign" ,"sign on the wall" }): "A sign on the wall, meant for reading.", + ])); + SetExits( ([ + "south" : "/domains/cave/room/cavepass9", + "down" : "/domains/cave/room/shop2.c", + ]) ); + SetInventory(([ + "/domains/cave/npc/gorm" : 1, + "/domains/cave/obj/bbucket" : 1, + ])); + SetRead("sign", (: read_sign :) ); +} + +int read_sign(){ + write("HOW TO CONDUCT BUSINESS HERE\n"); + write("list : Get a list of all the items Gorm has for sale"); + write("appraise <item> : Ask Gorm to tell you how much he would pay you for your item"); + write("price <item> : Ask Gorm the price of his item"); + write("show <item> : Ask Gorm for a closer look at his item\n"); + write("\nbuy <item> from gorm\nsell <item> to gorm\n"); + write("Cash only!"); + return 1; +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/shop2.c b/lib/domains/cave/room/shop2.c new file mode 100644 index 0000000..3f61e64 --- /dev/null +++ b/lib/domains/cave/room/shop2.c @@ -0,0 +1,53 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Gorm's storage room"); + SetLong("This is a small, bare room where Gorm keeps his goods. The main store is above."); + SetInventory(([ + "/domains/cave/obj/skin" : 5, + "/domains/cave/obj/match" : 5, + "/domains/cave/obj/torch" : 5, + "/domains/cave/weap/axe" : 5, + "/domains/cave/weap/dagger" : 5, + "/domains/cave/weap/javelin" : 5, + "/domains/cave/weap/sword" : 5, + "/domains/cave/armor/armored_boot_l" : 2, + "/domains/cave/armor/armored_boot_r" : 2, + "/domains/cave/armor/armored_glove_r" : 2, + "/domains/cave/armor/armored_glove_l" : 2, + "/domains/cave/armor/chainmail" : 5, + "/domains/cave/armor/leather_armor" : 5, + "/domains/cave/armor/orc_boot_r" : 5, + "/domains/cave/armor/orc_boot_l" : 5, + "/domains/cave/armor/orc_tallboot_r" : 5, + "/domains/cave/armor/orc_tallboot_l" : 5, + "/domains/cave/armor/orc_helmet" : 5, + "/domains/cave/armor/platemail" : 1, + "/domains/cave/armor/pants" : 10, + "/domains/cave/armor/orc_dress" : 10, + ])); + SetExits( ([ + "up" : "/domains/cave/room/shop", + ]) ); + SetNoClean(1); + +} +int CanReceive(object sneak) { + object *living_stack = get_livings(sneak); + if(!living_stack || !arrayp(living_stack)) living_stack = ({ sneak }); + foreach(object ob in living_stack){ + if(living(ob) && !creatorp(ob) && + !member_group(ob,"TEST")) { + message("info","Otik's back room is for authorized personnel only.", ob); + return 0; + } + } + return 1; +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/start.c b/lib/domains/cave/room/start.c new file mode 100644 index 0000000..164f29a --- /dev/null +++ b/lib/domains/cave/room/start.c @@ -0,0 +1,14 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/void.c b/lib/domains/cave/room/void.c new file mode 100644 index 0000000..435af37 --- /dev/null +++ b/lib/domains/cave/room/void.c @@ -0,0 +1,16 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(30); + SetShort("the void"); + SetLong("The void. Go down to get out."); + SetExits( ([ "down" : ROOM_START ]) ); + SetNoModify(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/weapon_storage1.c b/lib/domains/cave/room/weapon_storage1.c new file mode 100644 index 0000000..844438b --- /dev/null +++ b/lib/domains/cave/room/weapon_storage1.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +void create() { + ::create(); + SetAmbientLight(0); + SetShort("underground room"); + SetLong("This is a dark underground room. The walls are rough and bare. A passageway leads away to the south."); + SetItems(([ + ({ "ground", "rock", "rocks", "earth", "dirt", "stone", "stones" }) : "Rough and dirty, as one would expect from a simple underground area.", + ({ "wall", "walls", "rough walls", "rough and bare walls", "bare walls", "bare and rough walls" }) : "Carved roughly into the earth, this passageway has walls that expose underground rock. Clearly this area was architected with utility and expediency in mind.", + ({ "passage", "passageway", "This provides access to areas below the ground." }) : "This provides access to areas below the ground.", + ({ "room", "here", "area" }) : "Carved roughly into the earth, this area has walls that expose underground rock.", + ])); + SetExits( ([ + ]) ); + SetClimate("indoors"); + + SetInventory(([ + ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/room/wiz_hall.c b/lib/domains/cave/room/wiz_hall.c new file mode 100644 index 0000000..14d41b6 --- /dev/null +++ b/lib/domains/cave/room/wiz_hall.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include ROOMS_H + +inherit "/domains/cave/etc/cave_room"; + +static void create() { + object ob; + ::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Creators' Hall"); + SetLong("A generic Wiz Hall."); + SetProperty("no attack", 1); + SetProperty("nopeer",1); +} + +int CanReceive(object ob) { + if(playerp(ob) && !creatorp(ob) && !present("testchar badge",ob)) { + message("info","Creator staff only, sorry.", ob); + return 0; + } + return ::CanReceive(ob); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/weap/axe.c b/lib/domains/cave/weap/axe.c new file mode 100644 index 0000000..510cb44 --- /dev/null +++ b/lib/domains/cave/weap/axe.c @@ -0,0 +1,20 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("sharp axe"); + SetId( ({ "axe"})); + SetAdjectives( ({ "sharp","small","hand"})); + SetShort("a hand axe"); + SetLong("A small, sharp hand axe, suitable for close combat."); + SetMass(150); + SetBaseCost("silver",50); + SetVendorType(VT_WEAPON); + SetClass(20); + SetDamageType(BLADE|BLUNT); + SetWeaponType("blade"); +} diff --git a/lib/domains/cave/weap/battleaxe.c b/lib/domains/cave/weap/battleaxe.c new file mode 100644 index 0000000..eb186f4 --- /dev/null +++ b/lib/domains/cave/weap/battleaxe.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("battle axe"); + SetId(({"axe","battleaxe"})); + SetAdjectives( ({ "huge","large","heavy","montrously","battle", + "two handed" }) ); + SetShort("a huge battle axe"); + SetLong("A monstrously large and heavy battle axe."); + SetMass(1000); + SetHands(2); + SetBaseCost("silver",2500); + SetVendorType(VT_WEAPON); + SetClass(50); + SetDamageType(BLADE|BLUNT); + SetWeaponType("blade"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/weap/dagger.c b/lib/domains/cave/weap/dagger.c new file mode 100644 index 0000000..572fd9f --- /dev/null +++ b/lib/domains/cave/weap/dagger.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("sharp dagger"); + SetId( ({ "dagger"})); + SetAdjectives( ({ "sharp","fine","wicked","wicked-looking"})); + SetShort("a wicked-looking dagger"); + SetLong("A sharp, wicked dagger."); + SetMass(150); + SetBaseCost("silver",50); + SetVendorType(VT_WEAPON); + SetClass(10); + SetDamageType(KNIFE); + SetWeaponType("knife"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/cave/weap/javelin.c b/lib/domains/cave/weap/javelin.c new file mode 100644 index 0000000..480066b --- /dev/null +++ b/lib/domains/cave/weap/javelin.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("javelin"); + SetAdjectives( ({"throwing", "small", "light"}) ); + SetId( ({"spear"}) ); + SetShort("a javelin"); + SetLong("This is a small, light throwing spear."); + SetMass(50); + SetBaseCost("silver",20); + SetVendorType(VT_WEAPON); + SetClass(5); + SetDamageType(PIERCE); + SetWeaponType("projectile"); +} + +void init(){ + ::init(); + add_action("podcast","podcast"); +} + +int podcast(){ + write("Somehow the javelin just doesn't seem to do that now."); + return 1; +} diff --git a/lib/domains/cave/weap/longsword.c b/lib/domains/cave/weap/longsword.c new file mode 100644 index 0000000..d77de35 --- /dev/null +++ b/lib/domains/cave/weap/longsword.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("longsword"); + SetId( ({ "sword","weapon" }) ); + SetAdjectives( ({ "long","well crafted","bladed","two handed" }) ); + SetShort("a longsword"); + SetLong("A well crafted bladed weapon of exceptional lethality. It "+ + "is designed to be wielded with two hands."); + SetMass(500); + SetHands(2); + SetBaseCost("silver",2800); + SetVendorType(VT_WEAPON); + SetClass(35); + SetDamageType(BLADE); + SetWeaponType("blade"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/cave/weap/sword.c b/lib/domains/cave/weap/sword.c new file mode 100644 index 0000000..f4a22f0 --- /dev/null +++ b/lib/domains/cave/weap/sword.c @@ -0,0 +1,24 @@ +#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" }) ); + SetAdjectives( ({ "short" }) ); + SetShort("a short sword"); + SetLong("A cheap and rather dull short sword."); + SetMass(300); + SetBaseCost("silver",800); + SetVendorType(VT_WEAPON); + SetClass(15); + SetDamageType(BLADE); + SetWeaponType("blade"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/armor/arbitersuit.c b/lib/domains/default/armor/arbitersuit.c new file mode 100644 index 0000000..6b6da06 --- /dev/null +++ b/lib/domains/default/armor/arbitersuit.c @@ -0,0 +1,182 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_BANE; +inherit LIB_WORN_STORAGE; +object arbitershadow; +int active = 1; +int charge = 20000; +int maxcharge = 20000; +int disguised = 0; + +varargs mixed GetSuitHelp(mixed who, string where); + +static void create(){ + ::create(); + SetKeyName("arbiter suit"); + SetId(({"suit", "armor"})); + SetAdjectives(({"arbiter","suit of","powered","formidable", "formidable looking"})); + SetShort("a suit of powered arbiter armor"); + SetLong("A formidable looking suit of powered armor used by "+ + "forces of the Extant Authority. This one appears to be one of "+ + "the arbiter variety."); + SetMass(7000); + SetMatching(0); + SetBaseCost("silver",50000); + SetArmorType(A_CUSTOM); + SetRestrictLimbs( ({ + "torso", "head", "neck", + "right arm", "left arm", + "right leg", "left leg", + "right hand", "left hand", + "right foot", "left foot", + }) ); + AddSave( ({ "charge", "disguised" }) ); + SetMaxCarry(5000); + SetWear((: GetSuitHelp :)); +} + +void init(){ + ::init(); + add_action("GetSuitHelp", "help"); +} + +varargs mixed GetSuitHelp(mixed who, string where){ + string ret, str; + object env; + if(!who) return 0; + if(stringp(who)){ + str = who; + who = this_player(); + } + else str = GetKeyName(); + env = environment(who); + if(query_verb() == "wear" || (str && answers_to(str, this_object()))){ + if(environment() == who && charge){ + ret = "The suit's Heads Up Display crackles to life and reads:\n "; + ret += "%^GREEN%^This suit allows you, mighty Arbiter, to travel in hazardous terrain "+ + "with a minimum of inconvenience. In the interest of fulfilling the exigencies "+ + "of your duties to the Extant Authority, this suit provides the following "+ + "improvements to your abilities:\n\n"+ + "* Good vision in all light conditions.\n"+ + "* A constant supply of breathable air.\n"+ + "* Substantial enhancement of strength, coordination, agility, and durability.\n"+ + "* Substantial enhancement of unarmed combat capability.\n"+ + "* Heads Up Display of key environmental information.\n"+ + "* Grid coordinate information where available.\n"+ + "* Protection from all forms of external damage.\n"+ + "* Immunity from disease.\n"+ + "\nNote that once the power level of the suit reaches zero, all enhancements "+ + "become unavailable.%^RESET%^"; + who->eventPrint("You wear "+GetShort()+"."); + if(env) tell_room(env, who->GetName()+" wears "+ + GetShort()+".", ({who})); + return 1; + } + } + return 0; +} + +mixed eventEquip(object who, string array limbs){ + mixed success = ::eventEquip(who, limbs); + arbitershadow = new("/shadows/arbiter"); + if(arbitershadow) arbitershadow->SetDisguised(disguised); + if(success){ + if(arbitershadow) arbitershadow->eventShadow(who); + } + else if(arbitershadow) destruct(arbitershadow); + return success; +} + +varargs mixed eventUnequip(object who) { + mixed success; + if(!who) who = this_player(); + success = ::eventUnequip(who); + if(success){ + if(arbitershadow) who->unarbitershadow(); + } + return success; +} + +int GetActive(){ + if(!charge) return 0; + return active; +} + +int SetActive(int i){ + if(i) active = 1; + else active = 0; + return active; +} + +int eventDecrementCharge(int i){ + int perc; + object env = environment(); + if(!env) return 0; + + if(!GetWorn()) return 0; + if(previous_object() != arbitershadow) return 0; + if(charge < 1) charge = 0; + else { + if(!i) charge--; + else charge -= i; + if(charge < 0) charge = 0; + } + + perc = to_int(percent(charge, maxcharge)); + if(perc < 10){ + if(living(env) && creatorp(env)){ + env->eventPrint("Your creator powers magically recharge the "+ + remove_article(GetShort())+"."); + charge = maxcharge; + return charge; + } + tell_object(env,"The "+remove_article(GetShort())+" beeps loudly!"); + return charge; + } + + if(perc < 20){ + if(living(env) && creatorp(env)){ + env->eventPrint("Your creator powers magically recharge the "+ + remove_article(GetShort())+"."); + charge = maxcharge; + return charge; + } + tell_object(env,"The "+remove_article(GetShort())+" beeps softly."); + return charge; + } + + return charge; +} + +int GetRemainingCharge(){ + if(!charge || !GetWorn()){ + if(arbitershadow) arbitershadow->eventUnshadow(); + return 0; + } + return charge; +} + +int GetMaxCharge(){ + return maxcharge; +} + +int SetCharge(int i){ + charge = i; + return charge; +} + +int SetMaxCharge(int i){ + maxcharge = i; + return maxcharge; +} + +string array GetBane(){ + if(GetActive()) return ({ "all" }); + else return ({}); +} + +string array QueryBane(){ + if(GetActive()) return ({ "all" }); + else return ({}); +} diff --git a/lib/domains/default/armor/badge.c b/lib/domains/default/armor/badge.c new file mode 100644 index 0000000..82de98e --- /dev/null +++ b/lib/domains/default/armor/badge.c @@ -0,0 +1,47 @@ +#include <lib.h> +#include ROOMS_H +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("visitor pass"); + SetId(({"testchar badge","badge","pass","visitor's pass"})); + SetShort("a test character Visitor's Pass"); + SetLong("This clip-on plastic badge grants the wearer access to "+ + "some areas typically restricted to creator staff only. Abuse of this "+ + "pass is grounds for disciplinary action. A small scribble "+ + "at the bottom of the pass reads: click heels"); + SetProperties(([ + "no steal" : 1, + ])); + SetMass(10); + SetBaseCost(5000); + SetDamagePoints(100); + SetArmorType(A_AMULET); + SetRetainOnDeath(1); + SetRestrictLimbs( ({ "torso" }) ); +} +void init(){ + ::init(); + add_action("nplh","click"); +} +int nplh(string str){ + if(str=="heels"){ + if(present(this_object()->GetKeyName(),this_player() ) ){ + write("There's no place like home!\n"+ + "You are transported by an awesome whirlwind somewhere "+ + "else...\n"); + this_player()->eventMoveLiving(ROOM_START); + return 1; + } + write("You click your heels together...but feel "+ + "as though you're missing something.\n"); + return 1; + } +} +string GetAffectLong(object ob) { + if(!ob || !living(ob)) return 0; + return ob->GetName() + " is an authorized Test Character."; +} diff --git a/lib/domains/default/armor/bearskin.c b/lib/domains/default/armor/bearskin.c new file mode 100644 index 0000000..b3a262f --- /dev/null +++ b/lib/domains/default/armor/bearskin.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("bearskin"); + SetId(({"bearskin","bear skin"})); + SetAdjectives(({"thick","shaggy"})); + SetShort("a thick, shaggy bearskin"); + SetLong("This is a thick bearskin which can be worn "+ + "as armor. Unfortunately the hide "+ + "has not been tanned, so it's rather "+ + "foul-smelling."); + SetItems( ([ + "hide" : "It is untanned and subject "+ + "to natural decomposition." + ]) ); + SetSmell( ([ "default" : "It reeks of death." ]) ); + SetMass(75); + SetDamagePoints(100); + SetProtection(BLUNT,1); + SetProtection(BLADE,10); + SetProtection(KNIFE,10); + SetArmorType(A_CLOAK); +} +string GetAffectLong(object ob) { + if(!ob || !living(ob)) return 0; + return ob->GetName() + " reeks of death and decay."; +} diff --git a/lib/domains/default/armor/breather.c b/lib/domains/default/armor/breather.c new file mode 100644 index 0000000..c51a399 --- /dev/null +++ b/lib/domains/default/armor/breather.c @@ -0,0 +1,100 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +object breathershadow; + +int charge = 1000; +int maxcharge = 1000; + +string LongD(){ + string ret = "This remarkably small device fits over the "+ + "wearer's mouth, and provides a long supply of oxygenated "+ + "air. Its current charge level is "+ + to_int(percent(charge,maxcharge))+" percent."; + return ret; +} + +static void create(){ + armor::create(); + SetKeyName("breathing mask"); + SetId(({"mask","breather","a99","apparatus","device"})); + SetAdjectives(({"a99","breathing"})); + SetShort("an A99 breathing device"); + SetLong( (: LongD :) ); + SetMass(50); + SetBaseCost("silver",1000); + SetArmorType(A_CUSTOM); + SetRestrictLimbs( ({ "head"}) ); + AddSave( ({ "charge" }) ); +} + +void init(){ + ::init(); +} + +int SetCharge(int i){ + charge = i; +} + +int SetMaxCharge(int i){ + maxcharge = i; +} + +mixed eventEquip(object who, string array limbs){ + mixed success = armor::eventEquip(who, limbs); + breathershadow = new("/shadows/breather"); + if(success){ + if(breathershadow) breathershadow->eventShadow(who); + } + else if(breathershadow) destruct(breathershadow); + return success; +} + +varargs mixed eventUnequip(object who) { + mixed success; + if(!who) who = this_player(); + success = armor::eventUnequip(who); + if(success){ + if(breathershadow) breathershadow->eventUnshadow(); + } + if(breathershadow) destruct(breathershadow); + return success; +} + +int eventDecrementCharge(){ + int perc; + string name; + object room, env = environment(this_object()); + if(!env || !GetWorn()) return 0; + if(previous_object() != breathershadow) return 0; + if(charge < 1) charge = 0; + else charge--; + if(living(env)) room = environment(env); + + perc = to_int(percent(charge, maxcharge)); + if(perc < 10){ + tell_object(env,"The "+remove_article(GetShort())+" beeps loudly!"); + if(room){ + name = env->GetName(); + tell_room(room, name+"'s breathing device beeps.", ({ env })); + } + return charge; + } + + if(perc < 20){ + tell_object(env,"The "+remove_article(GetShort())+" beeps softly."); + return charge; + } + + return charge; +} + +int GetRemainingCharge(){ + if(!charge){ + if(breathershadow) breathershadow->eventUnshadow(); + } + if(!GetWorn()) return 0; + return charge; +} + diff --git a/lib/domains/default/armor/chainmail.c b/lib/domains/default/armor/chainmail.c new file mode 100644 index 0000000..a2657d2 --- /dev/null +++ b/lib/domains/default/armor/chainmail.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("chainmail shirt"); + SetId(({"armor","chainmail","mail","shirt","chain mail"})); + SetAdjectives(({"chainmail","sturdy","sturdy-looking","chain mail"})); + SetShort("chainmail armor"); + SetLong("A body-length suit of armor made of small metal rings fashioned together."); + SetMass(600); + SetBaseCost("silver",1000); + SetDamagePoints(100); + SetProtection(BLUNT,4); + SetProtection(BLADE,25); + SetProtection(KNIFE,25); + SetArmorType(A_ARMOR); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/armor/collar.c b/lib/domains/default/armor/collar.c new file mode 100644 index 0000000..2a6ea72 --- /dev/null +++ b/lib/domains/default/armor/collar.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +inherit LIB_BANE; + +static void create(){ + armor::create(); + SetKeyName("collar"); + SetId(({"repellent_collar","bane"})); + SetAdjectives( ({"repellent","odd","plastic","white"}) ); + SetShort("a plastic collar"); + SetLong("This is a simple collar made of a soft white plastic. It "+ + "seems to be coated with a fine, clear resin. There is something "+ + "written on the collar."); + SetProperties(([ + "no steal" : 1, + ])); + SetRead("Disease and parasite repellent collar, test character use only."); + SetMass(10); + SetBaseCost("silver", 10); + SetDamagePoints(100); + SetArmorType(A_COLLAR); + SetBane(({"all"})); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/armor/combat_pack.c b/lib/domains/default/armor/combat_pack.c new file mode 100644 index 0000000..5353dc4 --- /dev/null +++ b/lib/domains/default/armor/combat_pack.c @@ -0,0 +1,36 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_WORN_STORAGE; + +static void create(){ + ::create(); + SetKeyName("combat pack"); + SetAdjectives( ({"combat", "back"}) ); + SetId( ({"pack", "backpack"}) ); + SetShort("a combat backpack"); + SetLong("A pack containing the equipment a testchar will need to jump into battle."); + SetClosed(1); + SetInventory(([ + "/domains/default/armor/glove_r" : 1, + "/domains/default/armor/glove_l" : 1, + "/domains/default/armor/pants" : 1, + "/domains/default/weap/carving_knife" : 1, + "/domains/default/armor/long_boot_r" : 1, + "/domains/default/armor/collar" : 1, + "/domains/default/armor/helmet" : 1, + "/domains/default/armor/chainmail" : 1, + "/domains/default/armor/long_boot_l" : 1, + "/domains/default/armor/badge" : 1, + ])); + SetCanClose(1); + SetMaxCarry(2000); + SetMass(200); + SetBaseCost("silver",10); + SetDamagePoints(100); + SetArmorType(A_CLOAK); + SetProtection(COLD, 1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/armor/glove.c b/lib/domains/default/armor/glove.c new file mode 100644 index 0000000..481cf9a --- /dev/null +++ b/lib/domains/default/armor/glove.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ARMOR; + + +static void create() { + armor::create(); + SetKeyName("leather glove"); + SetId( ({ "glove" }) ); + SetAdjectives( ({ "black","leather","left" }) ); + SetShort("a black leather glove"); + SetLong("A black glove with five fingers."); + SetDamagePoints(75); + SetVendorType(VT_ARMOR); + SetMass(10); + SetBaseCost("silver",7); + SetArmorType(A_GLOVE); + SetProtection(BLUNT, 1); + SetProtection(BLADE, 1); + SetProtection(KNIFE, 2); + SetProtection(HEAT, 3); + SetProtection(COLD, 7); + SetFingers(5); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/armor/glove_l.c b/lib/domains/default/armor/glove_l.c new file mode 100644 index 0000000..6656ec9 --- /dev/null +++ b/lib/domains/default/armor/glove_l.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ARMOR; + + +static void create() { + armor::create(); + SetKeyName("leather glove"); + SetId( ({ "glove" }) ); + SetAdjectives( ({ "black","leather","left" }) ); + SetShort("a black leather glove"); + SetLong("A black glove with five fingers designed for a left hand."); + SetDamagePoints(75); + SetVendorType(VT_ARMOR); + SetMass(10); + SetBaseCost("silver",7); + SetArmorType(A_GLOVE); + SetProtection(BLUNT, 1); + SetProtection(BLADE, 1); + SetProtection(KNIFE, 2); + SetProtection(HEAT, 3); + SetProtection(COLD, 7); + SetFingers(5); + SetRestrictLimbs(({"left hand"})); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/armor/glove_r.c b/lib/domains/default/armor/glove_r.c new file mode 100644 index 0000000..9a1d297 --- /dev/null +++ b/lib/domains/default/armor/glove_r.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ARMOR; + + +static void create() { + armor::create(); + SetKeyName("leather glove"); + SetId( ({ "glove" }) ); + SetAdjectives( ({ "black","leather","right" }) ); + SetShort("a black leather glove"); + SetLong("A black glove with five fingers designed for a right hand."); + SetDamagePoints(75); + SetVendorType(VT_ARMOR); + SetMass(10); + SetBaseCost("silver",7); + SetArmorType(A_GLOVE); + SetProtection(BLUNT, 1); + SetProtection(BLADE, 1); + SetProtection(KNIFE, 2); + SetProtection(HEAT, 3); + SetProtection(COLD, 7); + SetFingers(5); + SetRestrictLimbs(({"right hand"})); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/armor/gray_amulet.c b/lib/domains/default/armor/gray_amulet.c new file mode 100644 index 0000000..3f07f68 --- /dev/null +++ b/lib/domains/default/armor/gray_amulet.c @@ -0,0 +1,38 @@ +// The carrier of this amulet will not be forced to quit +// if they hit their max idle time. Also speeds magic point refresh. + +#include <lib.h> +#include ROOMS_H +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("gray amulet"); + SetId(({"amulet", "gray", "idler_amulet" })); + SetShort("a gray amulet"); + SetLong("This dull, heavy amulet seems rather worthless, though " + "something about it seems to suggest hidden purpose."); + SetProperties(([ + "no steal" : 1, + ])); + SetMass(50); + SetBaseCost(100000); + SetArmorType(A_AMULET); + SetRetainOnDeath(1); + SetRestrictLimbs( ({ "torso" }) ); + set_heart_beat(7); +} + +void init(){ + ::init(); +} + +void heart_beat(){ + object env = environment(); + if(env && living(env) && GetWorn()){ + env->AddMagicPoints(1); + } +} + diff --git a/lib/domains/default/armor/helmet.c b/lib/domains/default/armor/helmet.c new file mode 100644 index 0000000..a9bd47b --- /dev/null +++ b/lib/domains/default/armor/helmet.c @@ -0,0 +1,19 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("steel helmet"); + SetId(({"helmet","cover","steel"})); + SetAdjectives(({"steel","battle","hard"})); + SetShort("a steel helmet"); + SetLong("This is a helmet made of tough metal."); + SetMass(180); + SetBaseCost("silver",500); + SetDamagePoints(100); + SetArmorType(A_HELMET); + SetProtection(BLUNT, 20); + SetProtection(BLADE, 20); + SetProtection(KNIFE, 20); +} diff --git a/lib/domains/default/armor/horc_shirt.c b/lib/domains/default/armor/horc_shirt.c new file mode 100644 index 0000000..8c637ad --- /dev/null +++ b/lib/domains/default/armor/horc_shirt.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("shirt"); + SetAdjectives( ({"tee"}) ); + SetId( ({"t-shirt", "t shirt", "tshirt", "tee shirt"}) ); + SetShort("a t-shirt that reads: 'I'M HALF-HUMAN'"); + SetLong("A generic piece of armor of indeterminate proportions."); + SetMass(50); + SetDamagePoints(100); + SetArmorType(A_SHIRT); + SetProtection(BLUNT, 20); + SetProtection(BLADE, 20); + SetProtection(KNIFE, 20); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/armor/jade_ring.c b/lib/domains/default/armor/jade_ring.c new file mode 100644 index 0000000..02d60b0 --- /dev/null +++ b/lib/domains/default/armor/jade_ring.c @@ -0,0 +1,216 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +object ringshadow; + +string LongRet(mixed whom){ + string ret = "A green ring, glowing with unearthly power."; + if(!whom || !objectp(whom) || !living(whom)) whom = this_player(); + if(creatorp(whom) || + member_group(whom,"TEST")){ + ret += "\nTo enable damage protection, type: protection on"; + ret += "\nTo enable damage reporting, type: reporting on"; + ret += "\nTo make a creature report its damage: enablereport <name>"; + ret += "\nTo make it stop reporting its damage: disablereport <name>\n"; + } + return ret; +} + +static void create(){ + armor::create(); + SetKeyName("jade ring"); + SetId(({"ring","ward","jade"})); + SetAdjectives( ({"jade","green","power","powerful"}) ); + SetShort("a jade ring"); + SetLong( (: LongRet :) ); + SetMass(1); + SetBaseCost("silver",5000); + SetArmorType(A_RING); +} + +void init(){ + armor::init(); + add_action("SetProtection", "protection"); + add_action("SetReporting", "reporting"); + add_action("SetNPCReporting", "enablereport"); + add_action("UnsetNPCReporting", "disablereport"); +} + +mixed CanEquip(object who, string array limbs){ + if(who && !creatorp(who) && !member_group(who,"TEST")){ + return "Somehow it just won't go on. Strange, isn't it?"; + return 0; + } + else return armor::CanEquip(who, limbs); +} + +int eventRegenerate(object who){ + int i; + string *stumps; + stumps=who->GetMissingLimbs(); + if(sizeof(stumps)) { + for(i=0;i<sizeof(stumps);i++){ + who->RestoreLimb(stumps[i]); + } + } + return 1; +} + +int PerformHeal(){ + object who; + mapping stumps; + string *limb_arr = ({}); + int i, mhp, msp, mmp, self; + + who = this_player(); + + mhp = who->GetMaxHealthPoints(); + msp = who->GetMaxStaminaPoints(); + mmp = who->GetMaxMagicPoints(); + who->AddHP(mhp); + who->AddStaminaPoints(msp); + who->AddMagicPoints(mmp); + if(who->GetPoison() > 0) who->AddPoison(0 - who->GetPoison()); + eventRegenerate(who); + limb_arr = who->GetLimbs(); + foreach(string limb in limb_arr) { + who->HealLimb(limb); + } + return 1; +} + +int CheckRing(){ + if(environment() != this_player()) return 0; + if(!(this_object()->GetWorn())) return 0; + if(!creatorp(environment()) && + !member_group(environment(),"TEST")) return -1; + return 1; +} + +int SetNPCReporting(string name){ + object *sombras = ({}); + object ob; + if(!CheckRing() || !ringshadow){ + write("The ring must be worn by you in order to access its power."); + return 1; + } + if(CheckRing() == -1){ + write("The ring's power can only be harnessed by special people. That means, \"not you\"."); + return 1; + } + if(!(ob = present(name,environment(this_player())))){ + write("No such creature is here."); + return 1; + } + sombras = keys(ob->GetShadows()); + if(sizeof(sombras)){ + foreach(object element in sombras){ + if(base_name(element) == "/shadows/diag"){ + write("That creature is already reporting its damage status."); + return 1; + } + } + } + new("/shadows/diag")->eventShadow(ob); + write("Damage reporting enabled for "+name+"."); + return 1; +} + +int UnsetNPCReporting(string name){ + object *sombras = ({}); + object ob; + int stat = 0; + if(!CheckRing() || !ringshadow){ + write("The ring must be worn by you in order to access its power."); + return 1; + } + if(CheckRing() == -1){ + write("The ring's power can only be harnessed by special people. That means, \"not you\"."); + return 1; + } + if(!(ob = present(name,environment(this_player())))){ + write("No such creature is here."); + return 1; + } + sombras = keys(ob->GetShadows()); + if(sizeof(sombras)){ + foreach(mixed element in sombras){ + if(element && objectp(element) && base_name(element) == "/shadows/diag"){ + stat = 1; + element->eventUnshadow(); + } + } + } + if(!stat) write("That creature does not have reporting enabled."); + else write("Damage reporting disabled for "+name+"."); + return 1; +} + +int SetProtection(string str){ + int booly = 0; + if(!CheckRing() || !ringshadow){ + write("The ring must be worn by you in order to access its power."); + return 1; + } + if(CheckRing() == -1){ + write("The ring's power can only be harnessed by special people. That means, \"not you\"."); + return 1; + } + if(str == "on") booly=1; + write("You set the ring's protection to: "+(booly ? "on" : "off")+"."); + if(ringshadow) ringshadow->JadeProtection(booly); + return 1; +} + +int SetReporting(string str){ + int booly = 0; + if(!CheckRing() || !ringshadow){ + write("The ring must be worn by you in order to access its power."); + return 1; + } + if(CheckRing() == -1){ + write("The ring's power can only be harnessed by special people. That means, \"not you\"."); + return 1; + } + if(str == "on") booly=1; + write("You set the ring's reporting to: "+(booly ? "on" : "off")+"."); + if(ringshadow) ringshadow->JadeReporting(booly); + return 1; +} + +mixed eventEquip(object who, string array limbs){ + int ok = 0; + mixed success = armor::eventEquip(who, limbs); + if(!ringshadow){ + object *sombras = keys(who->GetShadows()); + ok = 1; + ringshadow = new("/shadows/ring"); + foreach(object element in sombras){ + if(base_name(element) == base_name(ringshadow)){ + ok = 0; + if(ringshadow) destruct(ringshadow); + ringshadow = element; + } + } + } + if(success){ + PerformHeal(); + if(ok){ + if(ringshadow) ringshadow->eventShadow(who); + if(ringshadow) ringshadow->JadeProtection(1); + } + } + else if(ringshadow) destruct(ringshadow); + return success; +} + +varargs mixed eventUnequip(object who) { + mixed success; + if(!who) who = this_player(); + success = armor::eventUnequip(who); + if(success){ + if(ringshadow) ringshadow->eventUnshadow(ringshadow); + } + return success; +} diff --git a/lib/domains/default/armor/jeans.c b/lib/domains/default/armor/jeans.c new file mode 100644 index 0000000..aada788 --- /dev/null +++ b/lib/domains/default/armor/jeans.c @@ -0,0 +1,19 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("blue jeans"); + SetId(({"jeans","pants","blue jeans","bluejeans","denim"})); + SetAdjectives(({"blue","denim","comfortable","broken in","broken-in"})); + SetShort("a pair of blue jeans"); + SetLong("A comfortable pair of denim blue jeans."); + SetMass(5); + SetBaseCost(1); + SetDamagePoints(1); + SetProtection(BLUNT,1); + SetProtection(BLADE,1); + SetProtection(KNIFE,1); + SetArmorType(A_PANTS); +} diff --git a/lib/domains/default/armor/long_boot.c b/lib/domains/default/armor/long_boot.c new file mode 100644 index 0000000..e3f57a4 --- /dev/null +++ b/lib/domains/default/armor/long_boot.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("riding boot"); + SetId(({"boot"})); + SetAdjectives(({"long","riding","black","leather","left"})); + SetShort("a long riding boot"); + SetLong("A long riding boot, made of black leather."); + SetMass(60); + SetBaseCost("silver",75); + SetDamagePoints(5); + SetProtection(BLUNT,5); + SetProtection(BLADE,5); + SetProtection(KNIFE,5); + SetArmorType(A_LONG_BOOT); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/armor/long_boot_l.c b/lib/domains/default/armor/long_boot_l.c new file mode 100644 index 0000000..b4f9b78 --- /dev/null +++ b/lib/domains/default/armor/long_boot_l.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("riding boot"); + SetId(({"boot"})); + SetAdjectives(({"long","riding","black","leather","left"})); + SetShort("a long riding boot"); + SetLong("A long riding boot, made of black leather. It is "+ + "designed for wear on the left foot and leg."); + SetMass(60); + SetBaseCost("silver",75); + SetDamagePoints(5); + SetProtection(BLUNT,5); + SetProtection(BLADE,5); + SetProtection(KNIFE,5); + SetArmorType(A_LONG_BOOT); + SetRestrictLimbs(({"left foot","left leg"})); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/armor/long_boot_r.c b/lib/domains/default/armor/long_boot_r.c new file mode 100644 index 0000000..675f3c2 --- /dev/null +++ b/lib/domains/default/armor/long_boot_r.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("riding boot"); + SetId(({"boot"})); + SetAdjectives(({"long","riding","black","leather","right"})); + SetShort("a long riding boot"); + SetLong("A long riding boot, made of black leather. It is "+ + "designed for wear on the right foot and leg."); + SetMass(60); + SetBaseCost("silver",75); + SetDamagePoints(5); + SetProtection(BLUNT,5); + SetProtection(BLADE,5); + SetProtection(KNIFE,5); + SetArmorType(A_LONG_BOOT); + SetRestrictLimbs(({"right foot","right leg"})); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/armor/pants.c b/lib/domains/default/armor/pants.c new file mode 100644 index 0000000..1d71c98 --- /dev/null +++ b/lib/domains/default/armor/pants.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("leather pants"); + SetId(({"pants"})); + SetAdjectives(({"strong","leather","black","tough"})); + SetShort("leather pants"); + SetLong("These are trousers made of strong, tough leather. "); + SetMass(150); + SetBaseCost("silver",110); + SetDamagePoints(10); + SetProtection(BLUNT,1); + SetProtection(BLADE,5); + SetProtection(KNIFE,5); + SetArmorType(A_PANTS); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/armor/pcannon.c b/lib/domains/default/armor/pcannon.c new file mode 100644 index 0000000..ecfc086 --- /dev/null +++ b/lib/domains/default/armor/pcannon.c @@ -0,0 +1,368 @@ +#include <lib.h> +#include <daemons.h> +#include <talk_type.h> +#include <damage_types.h> +#include <vendor_types.h> +#include <armor_types.h> + +inherit LIB_ARMOR; +inherit LIB_SHOOT; +inherit LIB_ACTIVATE; +int tracking, debugging, active, cache, maxcache = 100; +mapping Prey = ([]); +object myroom; + +varargs mixed DoWear(object who, mixed where); + +string LongDesc(){ + string ret = "A highly advanced weapon of Poleepkwa design, "+ + "meant to be worn."; + if(!active) return ret; + if(cache < percent_of(10, maxcache)) ret += " A %^RED%^red%^RESET%^ light is illuminated on it."; + else if(cache < percent_of(50, maxcache)) ret += " A %^YELLOW%^yellow%^RESET%^ light is illuminated on it."; + else if(cache < percent_of(80, maxcache)) ret += " A %^GREEN%^green%^RESET%^ light is illuminated on it."; + else ret += " A %^BLUE%^blue%^RESET%^ light is illuminated on it."; + return ret; +} + +static void create() { + ::create(); + SetKeyName("plasma cannon"); + SetId(({"cannon"})); + AddSave(({"cache","Prey"})); + SetAdjectives(({"shoulder","poleepkwa","plasma"})); + SetShort("a plasma shoulder cannon"); + SetLong((:LongDesc:)); + SetMass(400); + SetDollarCost(15000); + SetVendorType(VT_WEAPON|VT_ARMOR); + SetArmorType(A_CUSTOM); + SetRestrictLimbs(({"torso"})); + SetWear( (: DoWear :) ); + AddItem( ({"light","status light"}), "A status light."); + set_heart_beat(2); + Prey = ([]); +} + +varargs int OperateThing(object who, mixed what){ + object env; + string this; + if(!who) who = this_player(); + env = environment(this_player()); + this = remove_article(GetShort()); + tell_player(who, "You operate your "+this+"."); + tell_object(env, who->GetName() + " operates " + possessive(who) + + " " + this + ".", ({who})); + if(what && stringp(what) && !active){ + tell_player(who, "The "+this+" is not activated."); + return 0; + } + return 1; +} + +varargs mixed eventShoot(object who, mixed target, string dir, string whom){ + string name, patsy; + object bolt, killer, env, room = room_environment(); + int fuel, dam; + killer = (who || this_player()); + fuel = killer->GetMagicPoints(); + name = killer->GetName(); + env = environment(killer); + if(target) patsy = target->GetName(); + + if(creatorp(who)){ + cache = maxcache; + fuel = 800; + who->AddMagicPoints(800); + } + + dam = cache + random(maxcache); + + if(!active){ + write("The cannon clicks."); + say(name+"'s cannon emits a click."); + return 1; + } + + if(cache < 5){ + cache = 0; + write("The cannon clicks."); + say(name+"'s cannon emits a click."); + if(room) room->eventHearTalk(this_object(),0,TALK_LOCAL,"say", + "Power cache too low.", "poleepkwa"); + return 1; + } + + if(fuel < maxcache){ + cache = 0; + write("The cannon emits a harsh buzzing noise."); + say(name+"'s cannon emits a harsh buzzing noise."); + if(room) room->eventHearTalk(this_object(),0,TALK_LOCAL,"say", + "Operator essence too low.", "poleepkwa"); + return 1; + } + + if(dir){ + if(!env){ + write("No environment."); + return 1; + } + if(!env->GetExit(dir)){ + write("You can't shoot in that direction."); + return 1; + } + bolt = new("/domains/default/weap/plasma"); + if(!bolt){ + write("There appears to be some sort of malfunction."); + return 1; + } + write("You fire your plasma cannon "+dir+"!"); + tell_room(env, name+" fires "+possessive(killer)+ + " plasma cannon "+dir+"!", ({killer})); + + if(debugging) bolt->SetDebugging(1); + bolt->SetOwner(who); + bolt->SetOwnerOb(this_object()); + bolt->SetDamage(dam); + bolt->eventMove(env); + bolt->SetArmed(1); + bolt->eventDeploy(dir); + killer->AddMagicPoints(-maxcache); + cache = 0; + return 1; + } + + write("You blast "+patsy+" with your plasma cannon!"); + tell_room(env, name+" blasts "+patsy+" with "+possessive(killer)+ + " plasma cannon!", ({killer, target})); + target->eventPrint(name+" blasts you with "+possessive(killer)+ + " plasma cannon!"); + + dam = cache + random(maxcache); + cache = 0; + + target->eventReceiveDamage(killer, HEAT, dam); + killer->AddMagicPoints(-maxcache); + target->AddEnemy(killer); + + if(tracking){ + if(room && (!Prey["ob"] || Prey["ob"] != target)){ + room->eventHearTalk(this_object(),0,TALK_LOCAL,"say", + "New prey being tracked.", "poleepkwa"); + } + Prey = ([ "ob" : target, "name" : patsy, "room" : environment(target), + "player" : userp(target) ]); + } + + return 1; +} + +int ReportHit(object target){ + object here, room; + string name; + int player; + if(!tracking || !active) return 0; + //if(!inherits(LIB_MISSILE, previous_object())) return 0; + here = environment(environment()); + if(Prey["ob"] && target == Prey["ob"]){ + here->eventHearTalk(this_object(),0,TALK_LOCAL,"say", + "Hit scored on target.", "poleepkwa"); + return 1; + } + room = environment(target); + name = target->GetName(); + player = userp(target); + Prey = (["ob" : target, "name" : name, "room" : room, "player" : player]); + here->eventHearTalk(this_object(),0,TALK_LOCAL,"say", + "New prey being tracked.", "poleepkwa"); + return 1; +} + +void heart_beat(){ + int notify; + string str; + object env = environment(); + object room = room_environment(); + if(active && !GetWorn()){ + if(env) tell_room(env, "The "+remove_article(GetShort())+ + " whines and clicks off."); + active = 0; + } + else if(active){ + int fuel = env->GetMagicPoints(); + if(!fuel){ + active = 0; + if(environment(env)){ + tell_room(environment(env), env->GetName()+"'s "+ + "plasma cannon whines and clicks off.", ({env})); + env->eventPrint("Your plasma cannon whines and clicks off."); + } + } + else if(cache < maxcache){ + env->AddMagicPoints(-1); + cache++; + } + } + if(active){ + object tmp; + object penv, menv; + if(Prey["name"] && !Prey["ob"]){ + if(Prey["player"] && tmp = find_player(Prey["name"])){ + Prey["ob"] = tmp; + Prey["room"] = environment(tmp); + Prey["lost"] = 0; + if(tracking && room){ + room->eventHearTalk(this_object(),0,TALK_LOCAL,"say", + "Contact with prey re-established.", "poleepkwa"); + } + return; + } + else if(!Prey["player"]) Prey = ([]); + if(room && !Prey["lost"]){ + if(tracking){ + room->eventHearTalk(this_object(),0,TALK_LOCAL,"say", + "Contact with prey lost.", "poleepkwa"); + } + Prey["lost"] = 1; + } + return; + } + penv = room_environment(Prey["ob"]); + menv = room_environment(this_object()); + if(Prey["ob"] && (!Prey["room"] || penv != Prey["room"])){ + if(room) room->eventHearTalk(this_object(),0,TALK_LOCAL,"say", + "Prey on the move.", "poleepkwa"); + Prey["room"] = penv; + notify = 1; + } + if(menv != myroom && Prey["ob"]){ + myroom = menv; + notify = 1; + } + if(tracking && notify && room){ + string mycords = ROOMS_D->GetCoordinates(menv); + string theircords = ROOMS_D->GetCoordinates(penv); + int i, j, x1, y1, x2, y2, bearing; + i = sscanf(mycords, "%d,%d,%*s", x1, y1); + j = sscanf(theircords, "%d,%d,%*s", x2, y2); + if(i < 2 || j < 2){ + return; + } + bearing = bearing(x2, y2, x1, y1, 1); + if(bearing != -1) str = "Prey's bearing currently: "+bearing; + else str = "Prey is in the immediate environment."; + room->eventHearTalk(this_object(),0,TALK_LOCAL,"say", + str, "poleepkwa"); + } + } +} + +void init(){ + object env = environment(); + ::init(); + if(active && !GetWorn()){ + if(env) tell_room(env, "The "+remove_article(GetShort())+ + " whines and clicks off."); + active = 0; + } +} + +varargs mixed DoWear(object who, mixed where){ + string extra; + object env = environment(who); + if(creatorp(who) || who->GetRace() == "poleepkwa"){ + active = 1; + if(creatorp(who)) cache = maxcache; + } + if(active) extra = " and it beeps and clicks on."; + else extra = "."; + who->eventPrint("You wear "+GetShort()+extra); + if(env) tell_room(env, who->GetName()+" wears "+ + GetShort()+extra, ({who})); + return 1; +} + +mixed eventUnequip(object who){ + mixed ret = ::eventUnequip(who); + object env = environment(who); + if(ret && active){ + who->eventPrint("The cannon whines and clicks off."); + if(env) tell_room(env, who->GetName()+"'s cannon "+ + "whines and clicks off.", ({who})); + active = 0; + } + return ret; +} + +int eventTurnOn(mixed str){ + if(!OperateThing(this_player(), str)) return 1; + if(str && stringp(str)){ + if(str == "debugging" && creatorp(this_player())){ + write("Debugging enabled."); + debugging = 1; + return 1; + } + else if(str == "tracking"){ + if(tracking){ + write("Tracking already enabled."); + return 1; + } + write("Tracking enabled."); + tracking = 1; + return 1; + } + else { + write("The "+remove_article(GetShort())+" has "+ + "no such feature."); + return 1; + } + } + if(active){ + write("The cannon is already on."); + return 1; + } + if(!(this_object()->GetWorn()) || !this_player() || + environment(this_object()) != this_player()){ + write("You are not wearing the "+remove_article(GetShort())+"."); + return 1; + } + write("You activate the "+remove_article(GetShort())+"."); + say(this_player()->GetName()+"'s "+remove_article(GetShort())+ + " beeps and clicks on."); + active = 1; + return 1; +} + +int eventTurnOff(mixed str){ + if(!OperateThing(this_player())) return 1; + if(str && stringp(str)){ + if(str == "debugging" && creatorp(this_player())){ + write("Debugging disabled."); + debugging = 0; + return 1; + } + else if(str == "tracking"){ + if(!tracking){ + write("Tracking already disabled."); + return 1; + } + write("Tracking disabled."); + tracking = 0; + return 1; + } + else { + write("The "+remove_article(GetShort())+" has "+ + "no such feature."); + return 1; + } + } + if(!active){ + write("The cannon is already off."); + return 1; + } + write("You deactivate the "+remove_article(GetShort())+"."); + say(this_player()->GetName()+"'s "+remove_article(GetShort())+ + " whines and clicks off."); + active = 0; + return 1; +} diff --git a/lib/domains/default/armor/pscoutsuit.c b/lib/domains/default/armor/pscoutsuit.c new file mode 100644 index 0000000..c7f3912 --- /dev/null +++ b/lib/domains/default/armor/pscoutsuit.c @@ -0,0 +1,287 @@ +#include <lib.h> +#include <armor_types.h> +#include <size_types.h> +#include <damage_types.h> +inherit LIB_BANE; +inherit LIB_WORN_STORAGE; +object scoutshadow; +int active = 1; +int charge = 1500; +int maxcharge = 3000; +int disguised = 0; +string owner; + +varargs mixed GetSuitHelp(mixed who, string where); + +string LongDesc(){ + string ret = "A highly advanced armored suit of Poleepkwa design, "+ + "used by elements of the Host whose role requires them to have "+ + "some protection from environmental hazards."; + if(!active) return ret; + if(charge < percent_of(10, maxcharge)) ret += " A %^RED%^red%^RESET%^ light is illuminated on it."; + else if(charge < percent_of(50, maxcharge)) ret += " A %^YELLOW%^yellow%^RESET%^ light is illuminated on it."; + else if(charge < percent_of(80, maxcharge)) ret += " A %^GREEN%^green%^RESET%^ light is illuminated on it."; + else ret += " A %^BLUE%^blue%^RESET%^ light is illuminated on it."; + return ret; +} + +static void create(){ + ::create(); + SetKeyName("scout suit"); + SetId(({"suit", "armor"})); + SetAdjectives(({"poleepkwa","scout","suit of","powered","formidable", "formidable looking"})); + SetShort("a suit of poleepkwa scout armor"); + SetLong((:LongDesc:)); + SetMass(500); + SetMatching(0); + SetBaseCost("silver",5000); + SetArmorType(A_EXO); + SetRestrictLimbs( ({ + "torso", "head", "neck", + "right arm", "left arm", + "right leg", "left leg", + "right hand", "left hand", + "right foot", "left foot", + }) ); + AddSave( ({ "charge", "disguised", "owner", "maxcharge" }) ); + SetMaxCarry(500); + SetSize(S_SOMEWHAT_LARGE); + SetProtection(BLUNT,20); + SetProtection(PIERCE,20); + SetProtection(BLADE,20); + SetProtection(KNIFE,20); + SetProtection(SHOCK,20); + SetProtection(COLD,20); + SetProtection(HEAT,20); + SetProtection(GAS,20); + SetProtection(OVERPRESSURE,20); + SetDamagePoints(100); + SetWear((: GetSuitHelp :)); + AddItem( ({"light","status light"}), "A status light."); + set_heart_beat(5); +} + +void init(){ + ::init(); + add_action("GetSuitHelp", "help"); +} + +varargs mixed GetSuitHelp(mixed who, string where){ + string ret, ret2, str; + object env; + if(!who){ + return 0; + } + if(stringp(who)){ + str = who; + who = this_player(); + } + else str = GetKeyName(); + env = environment(who); + if(query_verb() == "wear" || (str && answers_to(str, this_object()))){ + if(environment() == who){ + ret = "The suit's Heads Up Display crackles to life and reads:\n "; + ret += "%^B_BLACK%^CYAN%^"; + ret2 = "From the Host you get identity. From the many "+ + "we are Host. You are protected to serve. Serve the Host "+ + "with this suit. This suit protects you. Use it to serve. "+ + "\nWhen suit light is yellow or red, hide." + "\nWhen suit light is green or blue, serve." + "\nYour black juice makes the suit go." + "\nThe suit pulls from you the black juice." + "\nWhen it is full of black juice, the light is blue." + "\nWhen the light is on you can breathe." + "\nWhen the light is on you can take big hurt." + "\nWhen the light is on you can see good." + "\nWhen the light is on you don't get sick."; + "\nYou can not trade suits with others."; + if(query_verb() == "wear" && !GetWorn()){ + who->eventPrint("You wear "+GetShort()+"."); + if(env) tell_room(env, who->GetName()+" wears "+ + GetShort()+".", ({who})); + } + ret2 = translate(ret2, who->GetLanguageLevel("Poleepkwa")); + who->eventPrint(ret+ret2+"%^RESET%^"); + return 1; + } + } + return 0; +} + +mixed eventEquip(object who, string array limbs){ + mixed success = ::eventEquip(who, limbs); + scoutshadow = new("/shadows/pscout"); + if(scoutshadow) scoutshadow->SetDisguised(disguised); + if(success){ + if(scoutshadow) scoutshadow->eventShadow(who); + } + else if(scoutshadow) destruct(scoutshadow); + return success; +} + +varargs mixed eventUnequip(object who) { + mixed success; + if(!who) who = this_player(); + success = ::eventUnequip(who); + if(success){ + if(scoutshadow) who->unscoutshadow(); + } + return success; +} + +int GetActive(){ + if(!charge) return 0; + return active; +} + +int SetActive(int i){ + if(i) active = 1; + else active = 0; + return active; +} + +int eventDecrementCharge(int i){ + int perc; + object env = environment(); + if(!env) return 0; + + if(!GetWorn()) return 0; + if(previous_object() != scoutshadow) return 0; + if(charge < 1) charge = 0; + else { + if(!i) charge--; + else charge -= i; + if(charge < 0) charge = 0; + } + + perc = to_int(percent(charge, maxcharge)); + if(perc < 2){ + if(living(env) && creatorp(env)){ + env->eventPrint("Your creator powers magically recharge the "+ + remove_article(GetShort())+"."); + charge = maxcharge; + return charge; + } + tell_object(env,"The "+remove_article(GetShort())+" beeps loudly!"); + return charge; + } + + if(perc < 2){ + if(living(env) && creatorp(env)){ + env->eventPrint("Your creator powers magically recharge the "+ + remove_article(GetShort())+"."); + charge = maxcharge; + return charge; + } + tell_object(env,"The "+remove_article(GetShort())+" beeps softly."); + return charge; + } + + return charge; +} + +int GetRemainingCharge(){ + if(!charge || !GetWorn()){ + //if(scoutshadow) scoutshadow->eventUnshadow(); + return 0; + } + return charge; +} + +int GetMaxCharge(){ + return maxcharge; +} + +int SetCharge(int i){ + charge = i; + return charge; +} + +int SetMaxCharge(int i){ + maxcharge = i; + return maxcharge; +} + +string array GetBane(){ + if(GetActive()) return ({ "all" }); + else return ({}); +} + +string array QueryBane(){ + if(GetActive()) return ({ "all" }); + else return ({}); +} + +void heart_beat(){ + int notify; + string str, envname; + object env = environment(); + object room = room_environment(); + if(!env || !room) return; + envname = env->GetKeyName(); + if(owner && GetWorn() && envname != owner){ + tell_object(env, "The suit makes a brief cranking, buzzing sound."); + if(active) active = 0; + return; + } + if(active && !GetWorn()){ + tell_room(env, "The "+remove_article(GetShort())+ + " whines."); + active = 0; + } + else if(GetWorn() && charge < maxcharge){ + int fuel; + fuel = env->GetMagicPoints(); + if(fuel < 5){ + if(!charge && active){ + active = 0; + if(environment(env)){ + tell_room(environment(env), env->GetName()+"'s "+ + "powered suit whines.", ({env})); + env->eventPrint("Your powered suit whines."); + } + } + } + else { + int dmg = GetDamagePoints(); + env->AddMagicPoints(-5); + charge += 5; + if(dmg < 100){ + SetDamagePoints(dmg+1); + } + //env->eventPrint("adding 5. charge: "+charge+". "+ + // (active ? "active" : "inactive")); + if(!owner) owner = env->GetKeyName(); + } + } + if(GetWorn() && !active && charge > 9){ + active = 1; + if(environment(env)){ + tell_room(environment(env), env->GetName()+"'s "+ + "powered suit chirps.", ({env})); + env->eventPrint("Your powered suit chirps."); + } + } +} + +//Every 100 points of damage received by the suit, it lowers +//the max charging capacity by 100. +void eventDeteriorate(int type){ + object env = environment(); + if(maxcharge > 100){ + if(active){ + if(env) env->eventPrint("Your powered suit emits a harsh buzz and "+ + "the indicator light dims briefly."); + } + maxcharge -= 100; + } + ::eventDeteriorate(type); +} + +int eventReceiveDamage(mixed agent, int type, int amt, int i, mixed array l){ + if(!active || charge < 20){ + return ::eventReceiveDamage(agent, type, amt, i, l); + } + return 0; +} + diff --git a/lib/domains/default/armor/ring_fencing.c b/lib/domains/default/armor/ring_fencing.c new file mode 100644 index 0000000..0338ae3 --- /dev/null +++ b/lib/domains/default/armor/ring_fencing.c @@ -0,0 +1,45 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +varargs int DoWear(object who, string where); +int CheckRing(string skill); + +static void create(){ + armor::create(); + SetKeyName("ring"); + SetId(({"ring"})); + SetAdjectives( ({"magic", "thin", "unobtrusive"}) ); + SetShort("a thin ring"); + SetLong("This thin ring seems designed to be "+ + "as light and unobtrusive as possible."); + SetMass(10); + SetBaseCost("silver",5000); + SetArmorType(A_RING); + SetWear((: DoWear :)); + SetUnique(1); +} + +void init(){ + ::init(); +} + +varargs int DoWear(object who, string where){ + object env = environment(who); + who->AddSkillBonus("blade attack", (: CheckRing :) ); + who->AddSkillBonus("blade defense", (: CheckRing :) ); + who->eventPrint("You wear the ring and feel oddly dextrous..."+ + "and somehow fancy."); + if(env) tell_room(env, who->GetName()+" wears "+GetShort()+".", ({who})); + return 1; +} + +int CheckRing(string skill) { + if( !GetWorn() ) { + previous_object()->RemoveSkillBonus("blade attack", this_object()); + previous_object()->RemoveSkillBonus("blade defense", this_object()); + return 0; + } + else return 5; +} diff --git a/lib/domains/default/armor/ring_light.c b/lib/domains/default/armor/ring_light.c new file mode 100644 index 0000000..b876cc1 --- /dev/null +++ b/lib/domains/default/armor/ring_light.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("ring"); + SetId(({"ring"})); + SetAdjectives( ({"magic","magical","glowing","light","glowing"}) ); + SetShort("a brilliant, glowing ring"); + SetLong("This magical ring radiates very bright light that "+ + "can illuminate a room."); + SetRadiantLight(30); + SetMass(1); + SetBaseCost("silver",5000); + SetArmorType(A_RING); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/armor/ring_strength.c b/lib/domains/default/armor/ring_strength.c new file mode 100644 index 0000000..daa402d --- /dev/null +++ b/lib/domains/default/armor/ring_strength.c @@ -0,0 +1,42 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +varargs int DoWear(object who, string where); +int CheckRing(string stat); + +static void create(){ + armor::create(); + SetKeyName("ring"); + SetId(({"ring"})); + SetAdjectives( ({"magic", "heavy", "metal"}) ); + SetShort("a heavy metal ring"); + SetLong("This ring seems to almost pulse with power."); + SetMass(10); + SetBaseCost("silver",5000); + SetArmorType(A_RING); + SetWear((: DoWear :)); + SetUnique(1); +} + +void init(){ + ::init(); +} + +varargs int DoWear(object who, string where){ + object env = environment(who); + who->AddStatBonus("strength", (: CheckRing :) ); + who->eventPrint("You feel a resonant chord of strength roar within you "+ + "as you wear the ring."); + if(env) tell_room(env, who->GetName()+" wears "+GetShort()+".", ({who})); + return 1; +} + +int CheckRing(string stat) { + if( !GetWorn() ) { + previous_object()->RemoveStatBonus("strength", this_object()); + return 0; + } + else return 5; +} diff --git a/lib/domains/default/armor/robe.c b/lib/domains/default/armor/robe.c new file mode 100644 index 0000000..d7dfc01 --- /dev/null +++ b/lib/domains/default/armor/robe.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_WORN_STORAGE; + +static void create(){ + ::create(); + SetKeyName("wizard robe"); + SetAdjectives( ({"wizards", "wizard's", "soft", "wizard"}) ); + SetId(({"robe","cloak","duster"})); + SetShort("a robe"); + SetLong("This is a large, comfortable-looking robe, like a wizard might wear. It has many pockets and compartments for holding things."); + SetProperties(([ + "gamma" : 3, + "no steal" : 1, + ])); + SetCanClose(1); + SetMaxCarry(5000); + SetMass(200); + SetBaseCost("silver",100); + SetDamagePoints(100); + SetArmorType(A_CLOAK); + SetProtection(MAGIC, 10); + SetProtection(COLD, 10); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/armor/rocketpack.c b/lib/domains/default/armor/rocketpack.c new file mode 100644 index 0000000..fa097fd --- /dev/null +++ b/lib/domains/default/armor/rocketpack.c @@ -0,0 +1,244 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <medium.h> +inherit LIB_ARMOR; +inherit LIB_ACTIVATE; +inherit LIB_READ; + +int activated; +int charge = 1000; +int maxcharge = 1000; +object rocketshadow, owner; +string current_direction; +mapping Directions = ([]); + +string LongD(){ + string ret = "This is a large device worn on the back and designed to \"boost\" " + + "the wearer through the air or through space. For continuous operation, "+ + "it should probably be activated. The fuel gauge "+ + "reads "+to_int(percent(charge,maxcharge))+" percent."; + return ret; +} + +static void create(){ + armor::create(); + if(!Directions) Directions = ([]); + SetKeyName("rocket pack"); + SetId(({"pack","rocket"})); + SetAdjectives(({"large","rocket"})); + SetShort("a small rocket pack"); + SetLong( (: LongD :) ); + SetMass(800); + SetBaseCost(18000); + SetArmorType(A_VEST); + AddSave( ({ "charge", "Directions" }) ); + SetRestrictLimbs( ({ "torso" }) ); + set_heart_beat(1); +} + +void init(){ + ::init(); + add_action("boost","boost"); +} + +int SetCharge(int i){ + charge = i; +} + +int SetMaxCharge(int i){ + maxcharge = i; +} + +void heart_beat(){ + int medium; + if(activated) charge--; + if(charge < 1) charge = 0; + if(!charge && activated){ + object env = environment(); + activated = 0; + if(env){ + tell_object(env,"The rocket pack sputters and fails."); + } + } + + if(!owner) return; + medium = environment(owner)->GetMedium(); + if(medium == MEDIUM_SPACE){ + int i; + object env = environment(owner); + if(!current_direction){ + current_direction = env->GetExits()[random(sizeof(env->GetExits()))]; + } + if(activated){ + if(!Directions[current_direction]) Directions[current_direction] = 1; + else Directions[current_direction]++; + } + foreach(mixed key, mixed val in Directions){ + if(val > 20) val = 20; + for(i=val;i>0;i--){ + this_object()->boost(key,1); + } + } + } +} + +int boost(string str, int coasting){ + string dest,imsg,omsg; + mapping Exit, Doors; + int ret, medium; + object env; + if(!owner) return 0; + env = environment(owner); + current_direction = str; + medium = environment(owner)->GetMedium(); + if(!env) return 0; + Doors = env->GetDoorsMap(); + + if(medium == MEDIUM_SPACE && !coasting){ + if(Directions[opposite_dir(str)]){ + Directions[opposite_dir(str)]--; + } + else { + if(!Directions[str]) Directions[str] = 1; + else Directions[str]++; + //call_out( (: boost :), 1, str, 1); + } + } + + if(!coasting && environment(this_object()) != owner){ + write("You don't have the rocket pack."); + return 1; + } + if(!coasting && !GetWorn()){ + write("You're not wearing the rocket pack."); + return 1; + } + if(!coasting && !str || !env){ + write("Boost in which direction?"); + return 1; + } + + if(!coasting && !charge){ + write("The rocket pack is out of fuel."); + return 1; + } + dest = env->GetExit(str); + if(!dest){ + if(str == "up" && env->GetFlyRoom()) dest = env->GetFlyRoom(); + else if(str == "down" && env->GetSinkRoom()) dest = env->GetSinkRoom(); + else { + if(!coasting) write("No such direction"); + return 1; + } + } + Exit = environment(owner)->GetExitData(str); + + if( sizeof(Doors) && Doors[str] && Doors[str]->GetClosed() ){ + message("my_action", "You bump into " + + Doors[str]->GetShort(str) + ".", owner); + return 1; + } + + if( Exit && Exit["pre"] && + !(evaluate(Exit["pre"], str)) ){ + return 1; + //return 1; + } + + if(!sizeof(dest)){ + write("You can't go that way."); + return 1; + } + + omsg = owner->GetName()+" rockets "+str+"."; + imsg = owner->GetName()+" rockets in."; + + if(!coasting) write("You engage your rocket pack's boosters to rocket you "+str+"."); + if(!coasting) charge--; + + ret = owner->eventMoveLiving(dest, omsg, imsg, str); + if(ret){ + if( Exit && Exit["post"] ) evaluate(Exit["post"], str); + if(activated){ + if(!coasting) write("The rocket pack's boosters resume normal operation."); + } + else { + if(!coasting) write("The rocket pack's boosters sputter and go silent."); + } + } + + return 1; +} + +int eventTurnOn(){ + if(!(this_object()->GetWorn()) || !this_player() || + environment(this_object()) != this_player()){ + write("You are not wearing the rocket pack."); + return 1; + } + write("You activate the rocket pack with a deep, rumbling roar!"); + say(this_player()->GetName()+" fires up "+possessive(this_player())+" " + "rocket pack with a deep, rumbling roar!"); + activated = 1; + return 1; +} + +int eventTurnOff(){ + write("You deactivate the rocket pack. The boosters sputter and go silent."); + say(this_player()->GetName()+" deactivates "+possessive(this_player())+" " + "rocket pack. The boosters sputter and go silent."); + activated = 0; + return 1; +} + +int GetRunning(){ + return activated; +} + +mixed eventEquip(object who, string array limbs){ + mixed success = armor::eventEquip(who, limbs); + rocketshadow = new("/shadows/rocketpack"); + owner = who; + if(success){ + if(rocketshadow) rocketshadow->eventShadow(who); + } + else if(rocketshadow) destruct(rocketshadow); + activated = 0; + return success; +} + +varargs mixed eventUnequip(object who) { + mixed success; + if(!who) who = this_player(); + success = armor::eventUnequip(who); + if(success){ + if(rocketshadow) rocketshadow->eventUnshadow(); + } + if(rocketshadow) destruct(rocketshadow); + return success; +} + +int eventDecrementCharge(){ + if(!GetWorn()) return 0; + if(previous_object() != rocketshadow) return 0; + if(charge < 1) charge = 0; + else charge--; + + if(charge < 50){ + tell_object(environment(this_object()),"The rocket pack beeps loudly!"); + return charge; + } + + if(charge < 100){ + tell_object(environment(this_object()),"The rocket pack beeps softly."); + return charge; + } + + return charge; +} + +int GetRemainingCharge(){ + return charge; +} + diff --git a/lib/domains/default/armor/scoutsuit.c b/lib/domains/default/armor/scoutsuit.c new file mode 100644 index 0000000..982b3ce --- /dev/null +++ b/lib/domains/default/armor/scoutsuit.c @@ -0,0 +1,191 @@ +#include <lib.h> +#include <armor_types.h> +#include <size_types.h> +#include <damage_types.h> +inherit LIB_BANE; +inherit LIB_WORN_STORAGE; +object scoutshadow; +int active = 1; +int charge = 2000; +int maxcharge = 2000; +int disguised = 0; + +varargs mixed GetSuitHelp(mixed who, string where); + +static void create(){ + ::create(); + SetKeyName("scout suit"); + SetId(({"suit", "armor"})); + SetAdjectives(({"scout","suit of","powered","formidable", "formidable looking"})); + SetShort("a suit of powered scout armor"); + SetLong("A formidable looking suit of powered armor used by "+ + "forces of the Extant Authority. This one appears to be one of "+ + "the scout variety."); + SetMass(700); + SetMatching(0); + SetBaseCost("silver",5000); + SetArmorType(A_CUSTOM); + SetRestrictLimbs( ({ + "torso", "head", "neck", + "right arm", "left arm", + "right leg", "left leg", + "right hand", "left hand", + "right foot", "left foot", + }) ); + AddSave( ({ "charge", "disguised" }) ); + SetMaxCarry(500); + SetSize(S_HUMAN_SIZED); + SetWear((: GetSuitHelp :)); +} + +void init(){ + ::init(); + add_action("GetSuitHelp", "help"); +} + +varargs mixed GetSuitHelp(mixed who, string where){ + string ret, ret2, str; + object env; + if(!who) return 0; + if(stringp(who)){ + str = who; + who = this_player(); + } + else str = GetKeyName(); + env = environment(who); + if(query_verb() == "wear" || (str && answers_to(str, this_object()))){ + if(environment() == who && charge){ + ret = "The suit's Heads Up Display crackles to life and reads:\n "; + ret += "%^GREEN%^"; + ret2 = "This suit allows you, honorable Scout, to travel in hazardous terrain "+ + "with a minimum of inconvenience. In the interest of fulfilling the exigencies "+ + "of your duties to the Extant Authority, this suit provides the following "+ + "improvements to your abilities:\n\n"+ + "* Good vision in all light conditions.\n"+ + "* A constant supply of breathable air.\n"+ + "* Substantial enhancement of strength, coordination, agility, and durability.\n"+ + "* Substantial enhancement of unarmed combat capability.\n"+ + "* Heads Up Display of key environmental information.\n"+ + "* Grid coordinate information where available.\n"+ + "* Protection from all forms of external damage.\n"+ + "* Immunity from disease.\n\n"+ + "Note that once the power level of the suit reaches zero, all enhancements "+ + "become unavailable. Please note that as a Scout, your Arbiter relies on your "+ + "most excellent judgment in disengaging from disharmonies and reporting such "+ + "situations for referral to the Negotiations Corps.%^RESET%^"; + if(query_verb() == "wear" && !GetWorn()){ + who->eventPrint("You wear "+GetShort()+"."); + if(env) tell_room(env, who->GetName()+" wears "+ + GetShort()+".", ({who})); + } + ret2 = translate(ret2, who->GetLanguageLevel("English")); + who->eventPrint(ret+ret2); + return 1; + } + } + return 0; +} + +mixed eventEquip(object who, string array limbs){ + mixed success = ::eventEquip(who, limbs); + scoutshadow = new("/shadows/scout"); + if(scoutshadow) scoutshadow->SetDisguised(disguised); + if(success){ + if(scoutshadow) scoutshadow->eventShadow(who); + } + else if(scoutshadow) destruct(scoutshadow); + return success; +} + +varargs mixed eventUnequip(object who) { + mixed success; + if(!who) who = this_player(); + success = ::eventUnequip(who); + if(success){ + if(scoutshadow) who->unscoutshadow(); + } + return success; +} + +int GetActive(){ + if(!charge) return 0; + return active; +} + +int SetActive(int i){ + if(i) active = 1; + else active = 0; + return active; +} + +int eventDecrementCharge(int i){ + int perc; + object env = environment(); + if(!env) return 0; + + if(!GetWorn()) return 0; + if(previous_object() != scoutshadow) return 0; + if(charge < 1) charge = 0; + else { + if(!i) charge--; + else charge -= i; + if(charge < 0) charge = 0; + } + + perc = to_int(percent(charge, maxcharge)); + if(perc < 10){ + if(living(env) && creatorp(env)){ + env->eventPrint("Your creator powers magically recharge the "+ + remove_article(GetShort())+"."); + charge = maxcharge; + return charge; + } + tell_object(env,"The "+remove_article(GetShort())+" beeps loudly!"); + return charge; + } + + if(perc < 20){ + if(living(env) && creatorp(env)){ + env->eventPrint("Your creator powers magically recharge the "+ + remove_article(GetShort())+"."); + charge = maxcharge; + return charge; + } + tell_object(env,"The "+remove_article(GetShort())+" beeps softly."); + return charge; + } + + return charge; +} + +int GetRemainingCharge(){ + if(!charge || !GetWorn()){ + if(scoutshadow) scoutshadow->eventUnshadow(); + return 0; + } + return charge; +} + +int GetMaxCharge(){ + return maxcharge; +} + +int SetCharge(int i){ + charge = i; + return charge; +} + +int SetMaxCharge(int i){ + maxcharge = i; + return maxcharge; +} + +string array GetBane(){ + if(GetActive()) return ({ "all" }); + else return ({}); +} + +string array QueryBane(){ + if(GetActive()) return ({ "all" }); + else return ({}); +} diff --git a/lib/domains/default/armor/shirt.c b/lib/domains/default/armor/shirt.c new file mode 100644 index 0000000..8cd9bcc --- /dev/null +++ b/lib/domains/default/armor/shirt.c @@ -0,0 +1,19 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("a white t-shirt"); + SetId(({"shirt","tshirt","t-shirt","t shirt"})); + SetAdjectives(({"white"})); + SetShort("a white t-shirt"); + SetLong("An ordinary white t-shirt."); + SetMass(5); + SetBaseCost(1); + SetDamagePoints(1); + SetProtection(BLUNT,1); + SetProtection(BLADE,1); + SetProtection(KNIFE,1); + SetArmorType(A_SHIRT); +} diff --git a/lib/domains/default/armor/towel.c b/lib/domains/default/armor/towel.c new file mode 100644 index 0000000..7f5f7e2 --- /dev/null +++ b/lib/domains/default/armor/towel.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("damp towel"); + SetId(({"towel"})); + SetAdjectives(({"damp","bath","ordinary", "bathtowel"})); + SetShort("a damp towel"); + SetLong("This is an ordinary bath towel."); + SetMass(25); + SetDamagePoints(10); + SetProtection(BLUNT,1); + SetProtection(BLADE,1); + SetProtection(KNIFE,1); + SetArmorType(A_PANTS); +} diff --git a/lib/domains/default/armor/wizard_hat.c b/lib/domains/default/armor/wizard_hat.c new file mode 100644 index 0000000..3abe308 --- /dev/null +++ b/lib/domains/default/armor/wizard_hat.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("wizard's hat"); + SetAdjectives( ({"wizard","wizards", "floppy", "large", "conical", "blue"}) ); + SetId( ({"hat"}) ); + SetShort("a wizard's hat"); + SetLong("This is a large, floppy hat with a wide brim all "+ + "around it, and a conical center. It is dark blue in color, "+ + "and is decorated with pictures of yellow moons and stars."); + SetProperties(([ + "beta" : 2, + ])); + SetMass(50); + SetBaseCost("silver",500); + SetDamagePoints(100); + SetArmorType(A_HELMET); + SetProtection(BLUNT, 20); + SetProtection(BLADE, 20); + SetProtection(KNIFE, 20); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/armor/wristcomp.c b/lib/domains/default/armor/wristcomp.c new file mode 100644 index 0000000..aed8d7a --- /dev/null +++ b/lib/domains/default/armor/wristcomp.c @@ -0,0 +1,285 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ACTIVATE; +inherit LIB_INSTALL; +inherit LIB_WORN_STORAGE; + +static int active = 0; +int lupus; +mapping SpecialFuns = ([]); + +int CheckPanel(){ + if(this_object()->GetClosed()){ + write("The wrist computer is closed. The panel is not accessible."); + } + else { + write("A panel you can read."); + } + return 1; +} + +static void create() { + worn_storage::create(); + SetKeyName("wrist computer"); + SetId( ({ "computer", "bracer","comp","wristcomp","system" }) ); + SetAdjectives( ({ "wrist","odd","odd looking","complex","tough","rugged", + "tactical", "tactical data" }) ); + SetShort("a Yautja wrist computer"); + SetLong("An odd looking bracer intended to be worn on the arm. It looks " + "extremely complex yet also very tough and rugged. One may perhaps " + "\"activate bracer\". It appears that one can access special functions " + "by opening it."); + SetDamagePoints(75); + SetVendorType(VT_ARMOR); + SetMass(10); + SetBaseCost("silver", 1000); + SetArmorType(A_CUSTOM); + SetProtection(BLUNT, 10); + SetProtection(BLADE, 10); + SetProtection(KNIFE, 20); + SetProtection(HEAT, 30); + SetRestrictLimbs(({"left arm"})); + SetMaxCarry(100); + SetCanClose(1); + SetClosed(1); + SetLanguage("Yautja"); + SetItems( ([ + ({"panel","functions"}) : (: CheckPanel :), + ]) ); + SetRead( ([ + ({ "panel", "default" }) :"Yautja tactical data system, version .09", + //"panel": (: eventRead :), + ]) ); + SetMaxClones(2); +} + +int eventInitialize(){ + object env; + if(!(env = environment()) || !living(env)) return 0; + foreach(object module in all_inventory()){ + if(module) module->eventInstall(env, this_object()); + } + return 1; +} + +void init(){ + ::init(); + eventInitialize(); +} + +int eventMove(mixed arg){ + eventInitialize(); + return ::eventMove(arg); +} + +varargs int YautLang(object whom){ + if(!whom) whom = this_player(); + if(!whom) return 0; + if(whom->GetPolyglot()) return 100; + return whom->GetLanguageLevel("Yautja"); +} + +varargs void yaut_write(string str, object whom){ + if(!str || !sizeof(str)) return; + if(!whom) write("%^MAGENTA%^"+translate(str,YautLang())+"%^RESET%^"); + else tell_object(whom,"%^MAGENTA%^"+translate(str,YautLang(whom))+"%^RESET%^"); +} + +varargs void yaut_say(string str, mixed whom){ + object *exclude = ({}); + object *include = get_livings(environment(this_player())); + if(whom){ + if(objectp(whom)) exclude = ({ whom }); + else exclude = whom; + } + include -= exclude; + if(sizeof(include)) + foreach(object dude in include){ + yaut_write(str, dude); + } +} + +int eventTurnOn(){ + object *contents = all_inventory(); + if(!(this_object()->GetWorn()) || !this_player() || + environment(this_object()) != this_player()){ + write("You are not wearing the wrist computer."); + return 1; + } + write("You activate the wrist computer. The computer says:"); + say(this_player()->GetName()+" operates "+possessive(this_player())+" " + "wrist computer. You hear the computer say: "); + yaut_say("Computer online."); + if(sizeof(contents)) contents->eventPowerOn(); + active = 1; + return 1; +} + +int eventTurnOff(){ + object *contents = all_inventory(); + write("You deactivate the wrist computer. The computer says:"); + say(this_player()->GetName()+" operates "+possessive(this_player())+" " + "wrist computer. You hear the computer say: "); + yaut_say("Computer offline."); + if(sizeof(contents)) contents->eventPowerOff(); + active = 0; + return 1; +} + +varargs mixed eventInstall(object what, object where){ + write("The wrist computer is not installable anywhere"); + return 1; +} + +int CanReceive(object ob){ + if(!answers_to("yautja data module",ob)){ + write("That is not a proper data module for this computer."); + return 0; + } + else return 1; +} + +varargs mixed eventUninstallModule(object which, int auto){ + object *contents = all_inventory(); + object module = previous_object(); + if(which) module = which; + if(!auto) say(this_player()->GetName()+" operates "+possessive(this_player())+" " + "wrist computer."); + if(!active){ + if(!auto) write("The computer is not active."); + return 1; + } + if(!auto){ + write("You attempt to uninstall a module from the wrist computer. The computer says:"); + say(this_player()->GetName()+"'s wrist computer says: "); + yaut_say("Uninstalling..."); + } + if(SpecialFuns[module]) + foreach(mixed key, mixed val in SpecialFuns[module]){ + remove_action("foo",SpecialFuns[module][key]["hook"]); + if(!auto){ + yaut_say(key+" successfully uninstalled."); + } + } + map_delete(SpecialFuns, module); + return 1; +} + +varargs mixed eventInstallModule(mapping ModuleData, int auto){ + string *contents = ({}); + object module = previous_object(); + if(member_array("eventInitialize",call_stack(2)) != -1) auto = 1; + if(!auto) say(this_player()->GetName()+" operates "+possessive(this_player())+" " + "wrist computer."); + if(!answers_to("Yautja data module",module)){ + if(!auto) write("That is not a proper data module for this computer."); + return 0; + } + if(!active){ + if(!auto) write("The computer is not active."); + return 1; + } + if(this_object()->GetClosed()){ + write("The computer is closed."); + return 1; + } + if(sizeof(all_inventory())) + foreach(object element in all_inventory()){ + contents += ({ base_name(element) }); + } + if(member_array(base_name(module),contents) != -1){ + if(!auto){ + write("The wrist computer already contains that type of module."); + return 0; + } + } + SpecialFuns[module] = ModuleData; + if(!auto){ + write("You install a module into the wrist computer. The computer says:"); + say(this_player()->GetName()+"'s wrist computer says: "); + yaut_say("Installing..."); + } + foreach(mixed key, mixed val in SpecialFuns[module]){ + add_action(SpecialFuns[module][key]["function"],SpecialFuns[module][key]["hook"]); + if(!auto){ + yaut_say(key+" successfully installed."); + module->eventMove(this_object()); + } + } + return 1; +} + +mixed CanPutInto(object who, object item){ + return "This is a wrist computer. One can install modules on it."; +} + +mixed CanGetFrom(object who, object item){ + return "This is a wrist computer. One can uninstall modules from it."; +} + +varargs mixed eventRead(mixed who, mixed str){ + object dude; + string what; + string ret = "Yautja tactical data system display. Installed modules:\n"; + if(stringp(who)){ + what = who; + dude = this_player(); + } + else { + dude = who; + what = str; + } + if(this_object()->GetClosed()){ + write("The wrist computer is closed. There is nothing to read."); + return 1; + } + if(!active){ + write("The wrist computer is not activated."); + return 1; + } + foreach(mixed ob in all_inventory()){ + if(ob->Report()) ret += ob->Report(); + } + if(!lupus && random(99) > 95){ + lupus = 1; + ret = "BAD WOLF"; + } + SetRead( ([ + ({ "panel", "default" }) :ret, + ]) ); + return ::eventRead(dude, what); +} + +varargs mixed eventOpen(object who, object tool){ + SetProtection(BLUNT, 1); + SetProtection(BLADE, 1); + SetProtection(KNIFE, 2); + SetProtection(HEAT, 3); + ::eventOpen(who || 0, tool || 0); + if(!(this_object()->GetClosed())){ + write("Opening the wrist computer yields a panel you can read."); + return 1; + } + return 0; +} + +mixed eventClose(object who){ + SetProtection(BLUNT, 10); + SetProtection(BLADE, 10); + SetProtection(KNIFE, 20); + SetProtection(HEAT, 30); + return ::eventClose(who || 0); +} + +string GetInternalDesc(){ + return "This is the interface for the wrist computer. You may try to \"read computer\""; +} + +varargs mixed eventUnequip(object who){ + object *contents = all_inventory(); + if(sizeof(contents)) contents->eventPowerOff(); + ::eventUnequip(who||0); +} diff --git a/lib/domains/default/chamber/coffin.c b/lib/domains/default/chamber/coffin.c new file mode 100644 index 0000000..74ef87c --- /dev/null +++ b/lib/domains/default/chamber/coffin.c @@ -0,0 +1,34 @@ +#include <lib.h> +#include <position.h> + +inherit LIB_CHAMBER; + +static void create() { + chamber::create(); + SetKeyName("coffin"); + SetId(({"box"})); + SetAdjectives(({"pine", "simple"})); + SetShort("a coffin"); + SetLong("This is a simple pine box for holding the remains "+ + "of the deceased."); + SetRace("vehicle"); + SetPosition(POSITION_NULL); + SetMelee(0); + SetNoClean(1); + SetMount(1); + SetMountStyle("driven"); + SetVisibleRiders(0); + SetOpacity(100); + SetMaxHealthPoints(20); + SetMaxCarry(30000); +} + +void init(){ + ::init(); +} + +int eventMove(mixed foo){ + int ret; + ret = ::eventMove(foo); + return ret; +} diff --git a/lib/domains/default/creator/workroom.c b/lib/domains/default/creator/workroom.c new file mode 100644 index 0000000..75dc11b --- /dev/null +++ b/lib/domains/default/creator/workroom.c @@ -0,0 +1,22 @@ +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + + room::create(); + SetClimate("indoors"); + SetAmbientLight(40); + SetShort("a creator's workroom"); + SetLong("You are standing in the workroom of a creator."+ + " The start room is down from here."); + SetItems( ([ + "workroom" : "It looks very nice.", + ]) ); + SetInventory(([ + ])); + SetObviousExits("down"); + SetExits( ([ "down" : "/domains/default/room/start.c", + ]) ); +} + diff --git a/lib/domains/default/doors/steel_door.c b/lib/domains/default/doors/steel_door.c new file mode 100644 index 0000000..8e83034 --- /dev/null +++ b/lib/domains/default/doors/steel_door.c @@ -0,0 +1,22 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("east", (["id" : ({ "steel door", "steel door leading east", "door", "east door" }), + "short" : "a steel door leading east", + "long" : "This is an imposing, large steel door leading east into the arena.", + "lockable" : 0 ]) ); + SetSide("west", (["id" : ({ "steel door", "steel door leading west", "west door", "door" }), + "short" : "a steel door leading west", + "long" : "This is an imposing, large steel door leading west, out of the arena.", + "lockable" : 0 ]) ); + + SetClosed(0); + SetLocked(0); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/doors/steel_door2.c b/lib/domains/default/doors/steel_door2.c new file mode 100644 index 0000000..4bb90f8 --- /dev/null +++ b/lib/domains/default/doors/steel_door2.c @@ -0,0 +1,22 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("north", (["id" : ({ "steel door leading north", "steel door", "door", "north door" }), + "short" : "a steel door leading north", + "long" : "This is an imposing, large steel door leading north into the arena.", + "lockable" : 0 ]) ); + SetSide("south", (["id" : ({ "steel door leading south", "steel door", "south door", "door" }), + "short" : "a steel door leading south", + "long" : "This is an imposing, large steel door leading south, out of the arena.", + "lockable" : 0 ]) ); + + SetClosed(0); + SetLocked(0); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/doors/steel_door3.c b/lib/domains/default/doors/steel_door3.c new file mode 100644 index 0000000..8713d89 --- /dev/null +++ b/lib/domains/default/doors/steel_door3.c @@ -0,0 +1,22 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("north", (["id" : ({ "steel door", "steel door leading north", "door", "north door" }), + "short" : "a steel door leading north", + "long" : "This is an imposing, large steel door leading north into the arena.", + "lockable" : 0 ]) ); + SetSide("south", (["id" : ({ "steel door", "steel door leading south", "south door", "door" }), + "short" : "a steel door leading south", + "long" : "This is an imposing, large steel door leading south, out of the arena.", + "lockable" : 0 ]) ); + + SetClosed(0); + SetLocked(0); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/doors/test101.c b/lib/domains/default/doors/test101.c new file mode 100644 index 0000000..a591084 --- /dev/null +++ b/lib/domains/default/doors/test101.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("west", ([ "id" : ({"door leading west", "door", "west door"}), + "short" : "a door leading west", + "long" : "This is the east side of a door leading west.", + "lockable" : 1 ]) ); + + SetSide("east", ([ "id" : ({"door leading east", "door", "east door"}), + "short" : "a door leading east", + "long" : "This is the west side of a door leading east.", + "lockable" : 1 ]) ); + + SetClosed(1); + SetLocked(0); + SetKeys("west", ({ "west key" })); + SetKeys("east", ({ "east key" })); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/doors/west.c b/lib/domains/default/doors/west.c new file mode 100644 index 0000000..b67611d --- /dev/null +++ b/lib/domains/default/doors/west.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("DIR_X", ([ "id" : ({"door leading DIR_X", "door", "DIR_X door"}), + "short" : "a door leading DIR_X", + "long" : "This is the Y_SIDE side of a door leading DIR_X.", + "lockable" : 1 ]) ); + + SetSide("DIR_Y", ([ "id" : ({"door leading DIR_Y", "door", "DIR_Y door"}), + "short" : "a door leading DIR_Y", + "long" : "This is the X_SIDE side of a door leading DIR_Y.", + "lockable" : 1 ]) ); + + SetClosed(1); + SetLocked(0); + SetKeys("DIR_X", ({ "DIR_X key" })); + SetKeys("DIR_Y", ({ "DIR_Y key" })); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/etc/death.txt b/lib/domains/default/etc/death.txt new file mode 100644 index 0000000..1365336 --- /dev/null +++ b/lib/domains/default/etc/death.txt @@ -0,0 +1,21 @@ + + + NONONONO...... MNO! ......................... MN N! . + NONONON.... NOONNOO! MMMMMMMMMMPPPOII! NNNO!!!! . + NONONONO... O! NNO! MMMMMMMMMMMMMPPPOOOII!! NO! ... + NONONONONO........ MMMMMOOOOOOPPPPPPPPOOOOMII! ... + NONONONONON....... MMMMM.. OPPMMP .,OMI! .... + NONONONONONO...... MMMM:: o ,OPMP, o ::I!! ... + NONONONONONONONO.... NNM:::.,,OOPM!P,.::::!! .... + NONONONONONONONON.. MMNNNNNOOOOP NNIIPPO!!O! ..... + NONONONONONONONON...... MMMONNMMNNNIIIOO! ......... + NONONONONONONO.......... MOM!!!!!!!!!III ............. + NONONONON...... NNN.MNO! . O!!!!!!!!!O . OONO NO! ....... + NONONONONO.... MNNNNNO! ...OOOOOOOOOOO . MMNNON! ....... + NNNOOO!!! ...... MNNNNO! .. PPPPPPPPP .. MMNON! ..... + ...... OO! ................. ON! ....... + + YOU ARE DEAD! + + You are in formless void without substance and outside time. + diff --git a/lib/domains/default/npc/artrell.c b/lib/domains/default/npc/artrell.c new file mode 100644 index 0000000..1f0751b --- /dev/null +++ b/lib/domains/default/npc/artrell.c @@ -0,0 +1,18 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("artrell"); + SetAdjectives( ({"insectoid"}) ); + SetId(({"npc","mob","character","mobile"})); + SetShort("an artrell"); + SetLong("This creature would be roughly humanoid if it weren't for its insectoid appearance and four arms. It appears slightly thinner and smaller than an adult human, but you still don't want to touch it. It's the biggest damned bug you've ever seen."); + SetLevel(1); + SetRace("artrell"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/avidryl.c b/lib/domains/default/npc/avidryl.c new file mode 100644 index 0000000..afd5173 --- /dev/null +++ b/lib/domains/default/npc/avidryl.c @@ -0,0 +1,22 @@ +#include <position.h> +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("avidryl"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"non-player", "non player"})); + SetShort("an avidryl"); + SetLong("This is the fabled avidryl, or 'birdman'. He is very human-like, approximately six feet tall and robust in build. He looks like he might even be a match for a Klingon. The most striking thing about him are the two large birdlike wings on his back, used for flying."); + SetAutoStand(1); + SetPosition(POSITION_FLYING); + SetClass("explorer"); + SetLevel(5); + SetRace("avidryl"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/bacchus.c b/lib/domains/default/npc/bacchus.c new file mode 100644 index 0000000..e2af1f8 --- /dev/null +++ b/lib/domains/default/npc/bacchus.c @@ -0,0 +1,20 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("bacchus"); + SetAdjectives( ({"roman", "drunk"}) ); + SetId( ({"god", "god of wine", "dionysos", "dionysus"}) ); + SetShort("Bacchus, Roman god of wine"); + SetLong("How the Roman god of wine found his way here is a mystery, probably most so to himself. At the moment he seems to be in desperate need of sleeping off his latest debauch. He'll have to figure out an explanation of his own for waking up with a hangover in a crowd of animals."); + SetLevel(200); + SetMelee(1); + SetRace("god"); + SetGender("male"); + SetSleeping(500); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/balrog.c b/lib/domains/default/npc/balrog.c new file mode 100644 index 0000000..af05e13 --- /dev/null +++ b/lib/domains/default/npc/balrog.c @@ -0,0 +1,21 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("balrog"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"non-player", "non player"})); + SetShort("a fierce balrog"); + SetLong("This is the terrifying demon of your worst Nightmare!"); + SetWanderSpeed(5); + SetClass("fighter"); + SetMelee(1); + SetLevel(50); + SetRace("balrog"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/bat.c b/lib/domains/default/npc/bat.c new file mode 100644 index 0000000..81b9709 --- /dev/null +++ b/lib/domains/default/npc/bat.c @@ -0,0 +1,26 @@ +#include <position.h> +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("bat"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"non-player", "non player"})); + SetShort("a little bat"); + SetLong("An ordinary bat. It's no bigger than a mouse."); + SetWimpy(80); + SetPermitLoad(1); + SetPosition(POSITION_FLYING); + SetWanderSpeed(1); + SetLevel(1); + SetMelee(1); + SetRace("bat"); + SetMaxHealthPoints(20); + SetGender("male"); + SetMessage("leave","$N scurries $D."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/bear.c b/lib/domains/default/npc/bear.c new file mode 100644 index 0000000..ace958a --- /dev/null +++ b/lib/domains/default/npc/bear.c @@ -0,0 +1,21 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("bear"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"non-player", "non player"})); + SetShort("a bear"); + SetLong("A large brown bear. Not as huge as a grizzly, but plenty big enough to knock your block off."); + SetWanderSpeed(20); + SetClass("fighter"); + SetLevel(10); + SetMelee(1); + SetRace("bear"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/bird.c b/lib/domains/default/npc/bird.c new file mode 100644 index 0000000..7bc2ff8 --- /dev/null +++ b/lib/domains/default/npc/bird.c @@ -0,0 +1,21 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("dodo"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"non-player", "non player"})); + SetShort("a fat little dodo bird"); + SetLong("This foolish little creature's only crime was being born trusting and delicious."); + SetWanderSpeed(10); + SetLevel(1); + SetMelee(1); + SetRace("bird"); + SetMaxHealthPoints(30); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/boar.c b/lib/domains/default/npc/boar.c new file mode 100644 index 0000000..f8bca92 --- /dev/null +++ b/lib/domains/default/npc/boar.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("boar"); + SetAdjectives( ({"huge", "tusked", "hairy", "deadly", "snorting", "sweaty", "ugly", "piggish"}) ); + SetId( ({"pig", "beast"}) ); + SetShort("a wild boar"); + SetLong("This huge, tusked, hairy beast is at least one thousand pounds of snorting, sweaty aggression. Though it's ugly and piggish, it's every inch as deadly to a person as any lion, tiger, or bear."); + SetLevel(1); + SetMelee(1); + SetRace("pig"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/centaur.c b/lib/domains/default/npc/centaur.c new file mode 100644 index 0000000..ee26cec --- /dev/null +++ b/lib/domains/default/npc/centaur.c @@ -0,0 +1,20 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("centaur"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"non-player", "non player"})); + SetShort("a centaur"); + SetLong("Always a startling sight, this is a creature whose lower part is a stag, but where the head would be is the torso of a man, complete with arms and a head. This deer/man appears quite wild and looks every bit as unpredictable as legend says."); + SetWanderSpeed(10); + SetLevel(1); + SetMelee(1); + SetRace("centaur"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/chimera.c b/lib/domains/default/npc/chimera.c new file mode 100644 index 0000000..7f7b1fc --- /dev/null +++ b/lib/domains/default/npc/chimera.c @@ -0,0 +1,20 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("chimera"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"non-player", "non player"})); + SetShort("a terrifying chimera"); + SetLong("This terrible creature is an unholy mix consisting of the head and body of a lion, a head of a dragon, another head of a goat, and a serpent for a tail. Its heads bob ceaselessly, eyes rolling madly in their sockets, mouths opening and snapping shut."); + SetClass("fighter"); + SetLevel(15); + SetMelee(1); + SetRace("chimera"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/cow.c b/lib/domains/default/npc/cow.c new file mode 100644 index 0000000..0d1f1c4 --- /dev/null +++ b/lib/domains/default/npc/cow.c @@ -0,0 +1,22 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("cow"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"non-player", "non player"})); + SetShort("a shorthorn waygu cow"); + SetLong("Known far and wide for its exquisite marbling, the meat from the Waygu cow is prized by connoisseurs as a delicacy. This docile animal is used to being pampered, well-fed, and massaged thrice daily."); + SetWimpy(80); + SetWanderSpeed(7); + SetLevel(1); + SetMelee(1); + SetRace("cow"); + SetGender("female"); + SetAction(1, ({ "!emote rit." }) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/deer.c b/lib/domains/default/npc/deer.c new file mode 100644 index 0000000..539e88f --- /dev/null +++ b/lib/domains/default/npc/deer.c @@ -0,0 +1,20 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("deer"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"non-player", "non player"})); + SetShort("a deer"); + SetLong("A Typical creature of its kind: nervous, shify, yet beautiful and graceful. This gentle herbivore just wants to eat plants and reproduce."); + SetWanderSpeed(4); + SetLevel(1); + SetMelee(1); + SetRace("deer"); + SetGender("female"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/drone.c b/lib/domains/default/npc/drone.c new file mode 100644 index 0000000..a6167ea --- /dev/null +++ b/lib/domains/default/npc/drone.c @@ -0,0 +1,50 @@ +#include <lib.h> +#include ROOMS_H +#include <position.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("drone"); + SetAdjectives( ({"small","metal"}) ); + SetId( ({"drone","bot","robot"}) ); + SetShort("a small drone"); + SetLong("A small metal orb."); + SetLevel(1); + SetInvis(1); + SetMaxHealthPoints(50000); + SetRace("bot"); + SetGender("neuter"); + SetClass("explorer"); + SetWanderSpeed(1); + SetPermitLoad(1); + SetEncounter(0); + SetPosition(POSITION_FLYING); + SetNoClean(1); + SetPacifist(1); + SetWimpy(99); +} + +int eventReceiveDamage(mixed args...){ + return 0; +} + +int eventMove(mixed dest){ + int ret; + object env = environment(); + string location; + + if(!env) location = ROOM_START; + else if(clonep(env)) location = file_name(env); + else location = base_name(env); + + if(location) this_object()->SetProperty("LastLocation", location); + ret = ::eventMove(dest); + AddStaminaPoints(GetMaxStaminaPoints()); + return ret; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/drone2.c b/lib/domains/default/npc/drone2.c new file mode 100644 index 0000000..06f57b8 --- /dev/null +++ b/lib/domains/default/npc/drone2.c @@ -0,0 +1,244 @@ +#include <lib.h> +#include <damage_types.h> +#include <position.h> +#include ROOMS_H + +inherit LIB_SENTIENT; +inherit LIB_ACTIVATE; +int incept, newenv = 1, active = 0, ammo = 1000; +mixed visited = ({}); + +int eventShootDude(object ob){ + int pre, post, dam, numlimbs; + string limbname, str; + string *limbs; + if(!environment()) return 0; + str = ob->GetName(); + if(!ammo){ + tell_room(environment(),"The killbot clicks."); + active = 0; + return 0; + } + tell_object(this_object(),"You fire at "+ob->GetName()+"!"); + tell_room(environment(),"The killbot fires at "+ob->GetName()+"!", + ({this_object(),ob})); + tell_object(ob,"The killbot fires at you!"); + ammo--; + if(random(100) < 10) return 1; + limbs=ob->GetLimbs(); + numlimbs=sizeof(limbs); + limbname = limbs[random(numlimbs-1)]; + tell_room(environment(this_object()), + "The bullet smashes into "+ + capitalize(str)+"'s "+limbname+"!\n",ob); + tell_object(ob,"The bullet smashes into your "+limbname+"!\n"); + dam = 20; + dam *= random(10); + dam -= random(ob->GetStatLevel("coordination")); + pre = ob->GetHealthPoints(); + ob->eventReceiveDamage(this_object(),(PIERCE), dam, 0, limbname); + post = ob->GetHealthPoints(); + if(post < pre){ + if(!present("firearms_wound",ob)){ + new(LIB_WOUND)->eventMove(ob); + } + ob->AddLead("gunshot_wounds", 1); + ob->SetAttack(this_object()); + ob->AddEnemy(this_object()); + if(!ob->GetInCombat()){ + ob->eventForce("attack "+this_object()->GetKeyName()); + } + } + else { + AddNonTargets(ob); + } + return 1; +} + +int eventHoseTarget(object target){ + int repeat = 10; + if(!target) return 0; + while(repeat && !(target->GetDying())){ + eventShootDude(target); + repeat--; + } + return 1; +} + +int eventTargetScan(){ + object *targets; + int targs; + if(!environment() || !active) return 0; + targets = filter(get_livings(environment()), (: !($1->GetInvis()) && + ($1->GetRace() != "god") && member_array($1, GetNonTargets()) == -1 && + ($1->GetRace() != "bot") :)); + targets = scramble_array(targets); + targets -= ({ this_object() }); + if((targs = sizeof(targets)) < 1){ + if(newenv) eventForce("say Environment scan complete."); + newenv = 0; + eventQuell(); + return 0; + } + if(targs > 10) targs = 10; + else { + eventForce("say "+cardinal(targs)+" target"+ + ((targs > 1) ? "s" : "" )+" acquired."); + } + targs--; + targets = targets[0..targs]; + foreach(object target in targets){ + eventHoseTarget(target); + } + return 1; +} + +int ActivateTurret(){ + if(!ammo){ + write("The killbot clicks and goes silent."); + return 0; + } + active = 1; + eventForce("say KILLBOT IS NOW FULLY ARMED AND OPERATIONAL."); + eventTargetScan(); + set_heart_beat(1); + return 1; +} + +static void create() { + sentient::create(); + visited = ({}); + incept = time(); + SetKeyName("killbot"); + SetId( ({"drone","bot", "robot","turret"}) ); + SetAdjectives(({"kill","non-player", "non player"})); + SetShort("a killbot"); + SetLong("This is a hovering orb with a machine gun hanging "+ + "underneath it and a single red glowing eye scanning the area."); + SetPosition(POSITION_FLYING); + SetLevel(1); + SetPacifist(1); + SetNoClean(1); + SetRace("bot"); + SetClass("fighter"); + SetGender("neuter"); + SetPolyglot(1); + SetWanderSpeed(1); + SetPermitLoad(1); + SetLanguage("common",100); + SetDefaultLanguage("common"); +} + +void init(){ + ::init(); +} + +int eventTurnOn(){ + if(active){ + write("The killbot is already active."); + return 1; + } + else { + call_out("ActivateTurret",7); + write("You activate the killbot."); + eventForce("say KILLBOT ACTIVE."); + eventForce("say YOU HAVE 5 SECONDS TO REACH MINIMUM SAFE DISTANCE."); + } + return 1; +} + +int eventTurnOff(){ + if(!active){ + write("The killbot is already inactive."); + return 1; + } + else { + write("It seems this killbot cannot be deactivated."); + } + return 1; +} + +void heart_beat(){ + if(!clonep()) return; + ::heart_beat(); + if(!active){ + ActivateTurret(); + } + if(time() - incept > 60){ + mixed *rooms = objects( (: inherits(LIB_ROOM, $1) :) ); + int success; + object target; + incept = time(); + rooms = filter(rooms, (: member_array(base_name($1), ({ ROOM_START, + ROOM_FURNACE, ROOM_VOID, ROOM_POD, ROOM_DEATH, ROOM_WIZ, + ROOM_ARCH, ROOM_NETWORK, ROOM_ROUTER, LIB_FURNACE, + ROOM_FREEZER }) ) == -1 && strsrch(base_name($1),"/realms/") && + !inherits(LIB_FURNACE,$1) && + !($1->GetVirtual() && !grepp(base_name($1),",")) && + last_string_element(base_name($1),"/") != "death" :) ); + while(!success){ + target = rooms[random(sizeof(rooms)-1)]; + success = this_object()->eventMoveLiving(target); + } + } + eventTargetScan(); +} + +varargs int eventReceiveDamage(mixed agent, int type, int x, int internal, + mixed limbs){ + object env = room_environment(); + if(env){ + tell_room(env,"The killbot %^RED%^BEEPS%^RESET%^."); + } + ActivateTurret(); + return ::eventReceiveDamage(agent, type, x, internal, limbs); +} + +int eventMove(mixed dest){ + int ret; + object env = room_environment(); + string location; + if(!clonep()) return 0; + if(!env) location = ROOM_START; + else if(clonep(env)) location = file_name(env); + else location = base_name(env); + if(location) this_object()->SetProperty("LastLocation", location); + if(member_array(env, visited) == -1) visited += ({ env }); + ret = ::eventMove(dest); + AddStaminaPoints(GetMaxStaminaPoints()); + newenv = 1; + if(ammo < 1000){ + if(!ammo) SetWimpy(90); + else SetWimpy(100 - (ammo/10)); + ammo++; + } + return ret; +} + +varargs int eventDie(mixed arg){ + int ret, brooms; + object newbot, env = room_environment(); + if(env){ + for(brooms = 2;brooms > 0;brooms--){ + newbot = new(base_name(this_object())); + ret = newbot->eventMove(env); + if(ret){ + tell_room(env,"The killbot has teleported in reinforcements."); + } + } + } + return ::eventDie(arg); +} + +int eventDestruct(){ + object gift, env; + env = room_environment(); + catch( gift = new("/domains/default/weap/grenade") ); + if(gift && env){ + gift->eventMove(env); + gift->SetArmed(1); + } + return ::eventDestruct(); +} + + diff --git a/lib/domains/default/npc/drone3.c b/lib/domains/default/npc/drone3.c new file mode 100644 index 0000000..eb98183 --- /dev/null +++ b/lib/domains/default/npc/drone3.c @@ -0,0 +1,116 @@ +/* A more thorough world mapping bot. */ + +#include <lib.h> +#include ROOMS_H +#include <position.h> +#include <medium.h> +#include <daemons.h> + +inherit LIB_SENTIENT; + +int spawned; +int hb = 10; + +string ShortDesc(){ + return "drone "+file_name(); +} + +string LongDesc(){ + return "drone "+file_name(); +} + +static void create() { + sentient::create(); + SetKeyName("drone"); + SetAdjectives( ({"small","metal"}) ); + SetId( ({"drone","bot","robot"}) ); + SetShort( (: ShortDesc :) ); + SetLong( (: LongDesc :) ); + SetLevel(1); + SetInvis(1); + SetRace("bot"); + SetGender("neuter"); + SetClass("explorer"); + SetMaxHealthPoints(50000); + SetPermitLoad(1); + SetEncounter(0); + SetPosition(POSITION_FLYING); + SetNoClean(1); + SetPacifist(1); + SetWimpy(99); + set_heart_beat(hb); +} + +int eventReceiveDamage(mixed args...){ + return 0; +} + +int eventMove(mixed dest){ + int ret; + object env = environment(); + string location; + + if(!env) location = ROOM_START; + else if(clonep(env)) location = file_name(env); + else location = base_name(env); + + if(location) this_object()->SetProperty("LastLocation", location); + ret = ::eventMove(dest); + AddStaminaPoints(GetMaxStaminaPoints()); + if(env){ + if(env->GetMedium() != MEDIUM_LAND) spawned = 1; + if(env->GetVirtual()){ + hb = 20; + set_heart_beat(hb); + } + MAP_D->GetMap(env, 8, 1); + } + return ret; +} + +void init(){ + ::init(); + set_heart_beat(hb); +} + +void eventSpawn(){ + object env; + string location; + string *exits = ({}); + object newdrone; + + if(!env = environment()) return; + spawned = 1; + + exits = values(env->GetExitMap()); + exits += values(env->GetEnterMap()); + exits += (({env->GetFlyRoom()})); + exits += (({env->GetSinkRoom()})); + exits = distinct_array(exits); + + foreach(string exit in exits){ + if(member_array(exit, ROOMS_D->DroneCache()) != -1) continue; + newdrone = new("/domains/default/npc/drone3"); + newdrone->eventMove(env); +#if 0 + drones = objects( (: base_name($1) == base_name() && + environment($1) && !strsrch(base_name(environment($1)), + path_prefix(base_name(environment()))) && $1 != this_object() :) ); + if(drones) drones->ReceiveNoGo(nogo + no_go + ({ base_name(env) })); +#endif + ROOMS_D->DroneCache( ({ exit }) ); + if(strsrch(exit, "/virtual/") < 0){ + catch( newdrone->eventMove(exit) ); + } + } + ROOMS_D->DroneCache(({ base_name(env) })); +} + +void heart_beat(){ + if(!clonep()) return; + if(!spawned) eventSpawn(); + else { + if(environment()) MAP_D->GetMap(environment(), 8, 1); + eventDestruct(); + } +} diff --git a/lib/domains/default/npc/dryad.c b/lib/domains/default/npc/dryad.c new file mode 100644 index 0000000..7e74dcf --- /dev/null +++ b/lib/domains/default/npc/dryad.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("dryad"); + SetAdjectives( ({"tree hugging", "tree-hugging", "hippie"}) ); + SetId( ({"hippie"}) ); + SetShort("a tree-hugging hippie"); + SetLong("On closer inspection, this is no mere hippie chick. This is an honest-to goodness tree spirit, evidently a bit lost to be hanging around here."); + SetLevel(1); + SetMelee(1); + SetRace("dryad"); + SetGender("female"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/dummy.c b/lib/domains/default/npc/dummy.c new file mode 100644 index 0000000..79002fa --- /dev/null +++ b/lib/domains/default/npc/dummy.c @@ -0,0 +1,93 @@ +#include <lib.h> +#include <daemons.h> +#include <damage_types.h> +inherit LIB_NPC; + +static void create(){ + npc::create(); + SetKeyName("dummy"); + SetId( ({"dummy","mokujin","buster"}) ); + SetShort("a training dummy"); + SetLong("This is a magical sparring partner. It is made of "+ + "logs, cut to the proportions of a human's "+ + "head, torso, and limbs. The logs are held "+ + "together by joints made of chains."); + SetPacifist(1); + SetBodyComposition("wood"); + SetInventory(([ + ])); + SetLevel(10); + SetRace("dummy"); + SetClass("fighter"); + SetGender("neuter"); + SetMaxHealthPoints(9000); + SetHealthPoints(9000); +} + +varargs int eventReceiveDamage(object agent, int type, int x, int internal, mixed limbs) { + int hp, damage, damdiff; + string evidence, limb_string; + evidence = ""; + if(objectp(agent)) evidence += "I receive damage from "+agent->GetKeyName(); + else evidence += "I receive damage from "+agent; + evidence += "."; + if(type) { + string *damtypes = TYPES_D->eventCalculateTypes("damage", type); + if(type && sizeof(damtypes)) { + string verboid; + if(sizeof(damtypes) > 1) verboid = "s are "; + else verboid = " is "; + + evidence += " Damage type"+verboid; + evidence += implode(damtypes,", "); + } + else evidence += " Damage type is UNKNOWN"; + } + if(x) evidence += ", raw damage is "+x; + if(internal) evidence += ", internal variable is "+internal; + if(limbs) { + if(stringp(limbs)) limb_string = limbs; + else if(arrayp(limbs)) { + if(stringp(limbs[0])) limb_string = implode(limbs,", "); + else if(objectp(limbs[0])){ + foreach(object limb in limbs){ + limb_string += limb->GetKeyName()+", "; + } + } + } + } + else limb_string = ", and I can't tell where I'm hit. "; + if(limbs) { + evidence += ", body part(s) affected: "; + evidence += limb_string + "."; + } + eventForce("say "+evidence); + hp = GetHealthPoints(); + + if(!agent) agent = this_object(); + if(!type) type = 0; + if(!x) x = 0; + if(!internal) internal = 0; + if(!limbs) limbs = ""; + + ::eventReceiveDamage(agent, type, x, internal, limbs); + + damage = GetHealthPoints(); + damdiff = hp - damage; + eventForce("say actual damage done: "+damdiff); + AddHP(damdiff+1); +} + +int RemoveLimb(string limb, object agent){ + if(query_verb() == "eval" || query_verb() == "amputate" || + query_verb() == "call"){ + return ::RemoveLimb(limb, agent); + } + eventForce("say My "+limb+" has received enough damage to sever it. " + "However, since I am a training dummy, I'll be keeping it."); + return 1; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/dwarf.c b/lib/domains/default/npc/dwarf.c new file mode 100644 index 0000000..9f4ca76 --- /dev/null +++ b/lib/domains/default/npc/dwarf.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("dwarf"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"non-player", "non player"})); + SetShort("a dwarf"); + SetLong("This is your typical hearty-looking, short, powerfully-built dwarf. Ruddy cheeks, full beard, the works. Straight out of central casting, this one."); + SetLevel(1); + SetMelee(1); + SetRace("dwarf"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/elemental.c b/lib/domains/default/npc/elemental.c new file mode 100644 index 0000000..8cdc54f --- /dev/null +++ b/lib/domains/default/npc/elemental.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("elemental"); + SetId( ({"transcendental", "manifestation"}) ); + SetAdjectives( ({"boredom"}) ); + SetShort("a boredom elemental"); + SetLong("Normally elementals are summoned creatures composed of one of the four elements: earth, water, wind, or fire. This bizarre manifestation appears to be none of those, and in fact seems to have coalesced unbidden out of a sheer, transcendent boredom. It is, perhaps, more of a boredom transcendental."); + SetLevel(1); + SetMelee(1); + SetRace("elemental"); + SetGender("neuter"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/elephant.c b/lib/domains/default/npc/elephant.c new file mode 100644 index 0000000..64d93c4 --- /dev/null +++ b/lib/domains/default/npc/elephant.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("elephant"); + SetAdjectives( ({"docile", "pink", "friendly", "large", "very large"}) ); + SetId(({"npc","mob","character","mobile"})); + SetShort("a pink elephant"); + SetLong("This is a very large creature, yet it seems quite docile and even friendly. It's unclear whether the pink color is natural or painted on, but it's quite becoming."); + SetLevel(1); + SetMelee(1); + SetRace("elephant"); + SetGender("female"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/elf.c b/lib/domains/default/npc/elf.c new file mode 100644 index 0000000..ccfdd54 --- /dev/null +++ b/lib/domains/default/npc/elf.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("elf"); + SetAdjectives( ({"arrogant", "smug", "malicious"}) ); + SetId(({"npc","mob","character","mobile"})); + SetShort("an arrogant elf"); + SetLong("Oh don't be fooled. Elves just love to pretend they believe in equality and so on, but they all secretly harbor a malicious joy in being oh so much smarter and long-lived and wiser than humans. Don't you just want to punch this elf's smug little smirk?"); + SetLevel(1); + SetMelee(1); + SetRace("elf"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/faerie.c b/lib/domains/default/npc/faerie.c new file mode 100644 index 0000000..bebe748 --- /dev/null +++ b/lib/domains/default/npc/faerie.c @@ -0,0 +1,22 @@ +#include <position.h> +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("faerie"); + SetAdjectives( ({"fragile", "beautiful", "incredibly beautiful", "insubstantial", "tiny"}) ); + SetId( ({"fairy", "fairie"}) ); + SetShort("a small, delicate fairy"); + SetLong("This creature looks like a tiny human, perhaps six inches tall, with diaphanous wings. It seems fragile and insubstantial, as well as incredibly beautiful."); + SetPosition(POSITION_FLYING); + SetLevel(1); + SetMelee(1); + SetRace("faerie"); + SetMaxHealthPoints(50); + SetGender("female"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/fighter.c b/lib/domains/default/npc/fighter.c new file mode 100644 index 0000000..a2885ea --- /dev/null +++ b/lib/domains/default/npc/fighter.c @@ -0,0 +1,30 @@ +#include <lib.h> +inherit LIB_NPC; + +static void create(){ + npc::create(); + SetKeyName("fighter"); + SetId( ({"human","npc","warrior","fighter"}) ); + SetShort("a fighter"); + SetLong("This is a large human warrior. His pectoral muscles "+ + "are clearly visible even through his armor. His face is covered in "+ + "bold blue tattoos."); + SetClass("fighter"); + SetLevel(10); + SetCustomXP(350); + SetRace("human"); + SetStat("strength", 30); + SetGender("male"); + SetInventory(([ + "/domains/default/armor/chainmail.c" : "wear chainmail", + "/domains/default/weap/sharpsword.c" : "wield sword" + ])); + SetCurrency( ([ + "silver" : 100, + ]) ); + SetHealthPoints(549); + SetMaxHealthPoints(550); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/foochy.c b/lib/domains/default/npc/foochy.c new file mode 100644 index 0000000..48ae2fc --- /dev/null +++ b/lib/domains/default/npc/foochy.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("foochy"); + SetAdjectives( ({"overpampered", "ridiculous", "little", "toy", "toylike"}) ); + SetId(({"npc","mob","character","mobile","poodle"})); + SetShort("Foochy the pink poodle"); + SetLong("A rather ridiculous, obviously overpampered little toylike dog."); + SetLevel(1); + SetMelee(1); + SetRace("dog"); + SetGender("female"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/gargoyle.c b/lib/domains/default/npc/gargoyle.c new file mode 100644 index 0000000..3987199 --- /dev/null +++ b/lib/domains/default/npc/gargoyle.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("gargoyle"); + SetAdjectives( ({"stone", "grotesque", "ugly", "repellent"}) ); + SetId(({"npc","mob","character","mobile"})); + SetShort("a grotesque gargoyle"); + SetLong("A stone spirit come to life, this monstrosity was designed to be as ugly and repellent as anything could be and still hold its shape. It is wildly successful. Its rolling eyes and lolling tongue make it a horrid sight indeed."); + SetLevel(1); + SetMelee(1); + SetRace("gargoyle"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/gecko.c b/lib/domains/default/npc/gecko.c new file mode 100644 index 0000000..d85d929 --- /dev/null +++ b/lib/domains/default/npc/gecko.c @@ -0,0 +1,21 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("gecko"); + SetAdjectives( ({"gecko", "green", "small"}) ); + SetId( ({"lizard"}) ); + SetShort("a gecko"); + SetLong("This is a small lizard, about four inches in length. It has green skin, and unusually large eyes."); + SetWimpy(80); + SetLevel(1); + SetMelee(1); + SetRace("lizard"); + SetMaxHealthPoints(10); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/giant.c b/lib/domains/default/npc/giant.c new file mode 100644 index 0000000..d27bca8 --- /dev/null +++ b/lib/domains/default/npc/giant.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("giant"); + SetAdjectives( ({"jolly", "green"}) ); + SetId(({"npc","mob","character","mobile"})); + SetShort("a green giant"); + SetLong("This massive being is well over fifteen feet tall. He doesn't seem hostile though. Just rather amused, in fact. His skin is entirely green and his clothes are made from the leaves of what must be some gigantic palm trees."); + SetLevel(1); + SetMelee(1); + SetRace("giant"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/gnoll.c b/lib/domains/default/npc/gnoll.c new file mode 100644 index 0000000..b0d2325 --- /dev/null +++ b/lib/domains/default/npc/gnoll.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("gnoll"); + SetAdjectives( ({"filthy", "horrendous"}) ); + SetId( ({"dogman", "dog-man", "dog man"}) ); + SetShort("a large, filthy dogman"); + SetLong("This appears to be a horrendous cross between a humanoid and a hyena. Its matted fur is streaked with blood and feces, and its slavering jaws seem never to stop dripping saliva."); + SetLevel(1); + SetMelee(1); + SetRace("gnoll"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/gnome.c b/lib/domains/default/npc/gnome.c new file mode 100644 index 0000000..8c8719e --- /dev/null +++ b/lib/domains/default/npc/gnome.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("gnome"); + SetAdjectives( ({"cute", "cuddly", "endearing"}) ); + SetId(({"npc","mob","character","mobile"})); + SetShort("a cute little gnome"); + SetLong("This cuddly creature is rather like a dwarf, only much smaller and better-disposed. His long white beard, infectious laughter and twinkling eyes remind you of someone you knew and loved long ago. His cone-shaped hat and old-fashioned, awkward manner of dress make him all the more endearing. You just want to hug him and put him in your garden."); + SetLevel(1); + SetMelee(1); + SetRace("gnome"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/goblin.c b/lib/domains/default/npc/goblin.c new file mode 100644 index 0000000..c2561d8 --- /dev/null +++ b/lib/domains/default/npc/goblin.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("goblin"); + SetAdjectives( ({"malicious", "short", "green", "clever"}) ); + SetId(({"npc","mob","character","mobile"})); + SetShort("a short, green goblin"); + SetLong("This awful creature is confirmation of the worst stories you heard as a child. It seems to ooze malice from its slick, green skin. It looks much like a troll but smaller and more clever, and the eyes almost appear to radiate poison and hatred. Its very presence contaminates the air."); + SetLevel(1); + SetMelee(1); + SetRace("goblin"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/golem.c b/lib/domains/default/npc/golem.c new file mode 100644 index 0000000..2d24b82 --- /dev/null +++ b/lib/domains/default/npc/golem.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("golem"); + SetAdjectives( ({"massive", "clay", "tall"}) ); + SetId( ({"clay man", "clayman", "klaymen", "emet"}) ); + SetShort("Emet the golem"); + SetLong("Emet is a massive clay man, some ten feet tall and with great, thick arms and legs. Written on his forehead are some cryptic glyphs."); + SetLevel(10); + SetMelee(1); + SetRace("golem"); + SetGender("neuter"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/halfling.c b/lib/domains/default/npc/halfling.c new file mode 100644 index 0000000..0b12b0c --- /dev/null +++ b/lib/domains/default/npc/halfling.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("halfling"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"non-player", "non player"})); + SetShort("a halfling"); + SetLong("This creature is almost identical in appearance to a hobbit with its short stature, hairy feet, and evidently fun-loving disposition. It typically takes a hobbit or a halfling to tell them apart, but halflings tend to be shunned and disregarded for reasons lost to history, so if it looks a bit poor and underfed, like this one, it's a halfling."); + SetLevel(1); + SetMelee(1); + SetRace("halfling"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/helf.c b/lib/domains/default/npc/helf.c new file mode 100644 index 0000000..33dcd4b --- /dev/null +++ b/lib/domains/default/npc/helf.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("optis"); + SetId( ({"half elf", "half-elf", "half-human", "half human"}) ); + SetAdjectives(({"non-player", "non player"})); + SetShort("Optis the half-elf"); + SetLong("Like most of his kind, Optis is very attractive and athletic. His ears aren't entirely pointy, but he's exotic enough to be very popular with the ladies."); + SetLevel(1); + SetMelee(1); + SetRace("half-elf"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/hobbit.c b/lib/domains/default/npc/hobbit.c new file mode 100644 index 0000000..49061bf --- /dev/null +++ b/lib/domains/default/npc/hobbit.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("hobbit"); + SetAdjectives( ({"saucy", "saucy looking", "stout", "somewhat stout", "capable"}) ); + SetId( ({"lass", "adventurer"}) ); + SetShort("a hobbit"); + SetLong("About three feet tall, somewhat stout, and with a jolly twinkle in her eye, this saucy looking hobbit lass looks just as capable as any adventurer."); + SetLevel(1); + SetMelee(1); + SetRace("hobbit"); + SetGender("female"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/horse.c b/lib/domains/default/npc/horse.c new file mode 100644 index 0000000..f877349 --- /dev/null +++ b/lib/domains/default/npc/horse.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_SENTIENT; +inherit LIB_MOUNT; +inherit LIB_DOMESTICATE; + +static void create() { + sentient::create(); + SetKeyName("horse"); + SetId(({"horse","large horse"})); + SetShort("a large horse"); + SetLong("A large, hooved quadruped, taller and more muscular than you."); + SetWimpy(50); + SetLevel(5); + SetRace("horse"); + SetGender("male"); + SetMelee(1); + SetAction(5, ({ + "The horse snorts.", "You hear the horse whinny.", + "The horse flips its tail in the air.", + "The horse looks around."})); + SetNoClean(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/kender.c b/lib/domains/default/npc/kender.c new file mode 100644 index 0000000..0e51a01 --- /dev/null +++ b/lib/domains/default/npc/kender.c @@ -0,0 +1,47 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +int StealAttempt(){ + object *players = get_livings(environment(this_object()),1); + object *stuff; + object target; + string name, thing; + int which, whether; + + if(sizeof(players)){ + which = random(sizeof(players)); + target = players[which]; + name = target->GetKeyName(); + stuff = all_inventory(target); + if(!sizeof(stuff) || random(100) > 50) whether = 1; + if(whether) this_object()->eventForce("steal money from "+name); + else { + thing = stuff[random(sizeof(stuff))]->GetKeyName(); + this_object()->eventForce("steal "+thing+" from "+name); + } + } + whether = 0; + return 1; +} + +static void create() { + sentient::create(); + SetKeyName("kender"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"non-player", "non player"})); + SetShort("a kender"); + SetLong("Slight of build and rather attractive, kenders are another race related to hobbits, with all of the playfulness and a little extra disregard for other people's privacy. Kenders are infamous for their extraordinary skill in relieving others of their property, and it is said they are taught to steal before being taught to read. Others dispute this, arguing kenders don't read at all."); + SetClass("thief"); + SetLevel(5); + SetMelee(1); + SetRace("kender"); + SetGender("female"); + SetAction(25, ({ + (: StealAttempt :), "!giggle", (: StealAttempt :), "!laugh", + (: StealAttempt :), "!smile", (: StealAttempt :), "!smirk", + }) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/kender_quiet.c b/lib/domains/default/npc/kender_quiet.c new file mode 100644 index 0000000..068d5ec --- /dev/null +++ b/lib/domains/default/npc/kender_quiet.c @@ -0,0 +1,46 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +int StealAttempt(){ + object *players = get_livings(environment(this_object()),1); + object *stuff; + object target; + string name, thing; + int which, whether; + + if(sizeof(players)){ + which = random(sizeof(players)); + target = players[which]; + name = target->GetKeyName(); + stuff = all_inventory(target); + if(!sizeof(stuff) || random(100) > 50) whether = 1; + if(whether) this_object()->eventForce("steal money from "+name); + else { + thing = stuff[random(sizeof(stuff))]->GetKeyName(); + this_object()->eventForce("steal "+thing+" from "+name); + } + } + whether = 0; + return 1; +} + +static void create() { + sentient::create(); + SetKeyName("kender"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"non-player", "non player"})); + SetShort("a kender"); + SetLong("Slight of build and rather attractive, kenders are another race related to hobbits, with all of the playfulness and a little extra disregard for other people's privacy. Kenders are infamous for their extraordinary skill in relieving others of their property, and it is said they are taught to steal before being taught to read. Others dispute this, arguing kenders don't read at all."); + SetClass("thief"); + SetLevel(5); + SetMelee(1); + SetRace("kender"); + SetGender("female"); + SetAction(25, ({ + (: StealAttempt :), + }) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/klingon.c b/lib/domains/default/npc/klingon.c new file mode 100644 index 0000000..a7ac3cf --- /dev/null +++ b/lib/domains/default/npc/klingon.c @@ -0,0 +1,20 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("klingon"); + SetAdjectives( ({"klingon", "adolescent", "unpredictable"}) ); + SetId( ({"warrior", "fighter", "adolescent"}) ); + SetShort("an adolescent klingon"); + SetLong("Sometimes more dangerous than the adult klingon, adolescents have something to prove and can be unpredictable in their aggression. This one has the distinctive ridges of the house of D'Ghor, making him all the more eager to prove his worthiness as a fighter."); + SetClass("fighter"); + SetLevel(5); + SetMelee(1); + SetRace("klingon"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/kobold.c b/lib/domains/default/npc/kobold.c new file mode 100644 index 0000000..5babe9c --- /dev/null +++ b/lib/domains/default/npc/kobold.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("kobold"); + SetAdjectives( ({"lizard", "short", "humanoid"}) ); + SetId( ({"lizard", "lizard man", "creature"}) ); + SetShort("a short lizard man"); + SetLong("This three foot tall lizard creature is a kobold. Its features are like those of a reptile, but it has arms and legs like a humanoid."); + SetLevel(1); + SetMelee(1); + SetRace("kobold"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/kwyjibo.c b/lib/domains/default/npc/kwyjibo.c new file mode 100644 index 0000000..1996c39 --- /dev/null +++ b/lib/domains/default/npc/kwyjibo.c @@ -0,0 +1,22 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("kwyjibo"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"bald","overweight","dumb","stupid","North American","American"})); + SetShort("a kwijibo"); + SetLong("A bald, overweight, North American ape of below average intelligence."); + SetWanderSpeed(20); + SetClass("fighter"); + SetLevel(10); + SetEncounter(100); + SetMelee(1); + SetRace("ape"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/lemur.c b/lib/domains/default/npc/lemur.c new file mode 100644 index 0000000..2ddf04d --- /dev/null +++ b/lib/domains/default/npc/lemur.c @@ -0,0 +1,20 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("lemur"); + SetAdjectives( ({"small", "startling", "grey", "gray"}) ); + SetId( ({"primate", "simian"}) ); + SetShort("a lemur"); + SetLong("This small animal is startling in its appearance. It looks much like a cross between a small monkey and a raccoon. It has an elongated snout and the fur around its eyes is dark, like the mask of a bandit. Yet its body is clearly simian, with the prehensile front limbs of a monkey. Its grey, furry body ends in a ridiculously long tail that is striped white and black."); + SetLevel(1); + SetMelee(1); + SetRace("primate"); + SetMaxHealthPoints(40); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/lynx.c b/lib/domains/default/npc/lynx.c new file mode 100644 index 0000000..721f7a0 --- /dev/null +++ b/lib/domains/default/npc/lynx.c @@ -0,0 +1,20 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("lynx"); + SetId(({"npc","mob","quadruped","mobile"})); + SetAdjectives(({"non-player", "endothermic","carnivorous"})); + SetShort("a lynx"); + SetLong("An endothermic quadruped, carnivorous by nature, it's roughly as big as a medium-sized dog. It has huge ears it uses to hunt in the dark with."); + SetWanderSpeed(10); + SetLevel(1); + SetMelee(1); + SetRace("cat"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/minotaur.c b/lib/domains/default/npc/minotaur.c new file mode 100644 index 0000000..d36de7b --- /dev/null +++ b/lib/domains/default/npc/minotaur.c @@ -0,0 +1,20 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("minotaur"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"non-player", "non player"})); + SetShort("The Minotaur"); + SetLong("This is the fearsome monster to whom countless virgins were sacrificed. It is transcendentally horrifying, standing eight feet tall with a body seemingly of iron muscle and the head of a raging bull. It is so fearsome as to inspire a kind of hypnotic awe, and it is easy to see it as a force of nature to be worshipped."); + SetClass("fighter"); + SetLevel(30); + SetMelee(1); + SetRace("demi-god"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/moth.c b/lib/domains/default/npc/moth.c new file mode 100644 index 0000000..d2fc2af --- /dev/null +++ b/lib/domains/default/npc/moth.c @@ -0,0 +1,23 @@ +#include <position.h> +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("moth"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"non-player", "non player"})); + SetShort("a tiny moth"); + SetLong("An ordinary flying insect which has a particular taste for old clothes."); + SetWimpy(80); + SetPosition(POSITION_FLYING); + SetLevel(1); + SetMelee(1); + SetRace("insect"); + SetMaxHealthPoints(2); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/newt.c b/lib/domains/default/npc/newt.c new file mode 100644 index 0000000..84831d6 --- /dev/null +++ b/lib/domains/default/npc/newt.c @@ -0,0 +1,23 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("newt"); + SetAdjectives( ({"slimy"}) ); + SetId(({"npc","mob","character","mobile"})); + SetShort("a newt"); + SetLong("A slimy amphibian."); + SetWimpy(80); + SetWanderSpeed(3); + SetMelee(1); + SetLevel(1); + SetRace("amphibian"); + SetClass("explorer"); + SetMaxHealthPoints(10); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/nymph.c b/lib/domains/default/npc/nymph.c new file mode 100644 index 0000000..56d6644 --- /dev/null +++ b/lib/domains/default/npc/nymph.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("claire"); + SetId( ({"nymph", "danes", "claire danes", "woman"}) ); + SetAdjectives(({"non-player", "non player"})); + SetShort("Claire Danes"); + SetLong("This slender nature spirit appears quite lost, and probably should be accompanying a lesser goddess through woodland glades."); + SetLevel(1); + SetMelee(1); + SetRace("nymph"); + SetGender("female"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/ogre.c b/lib/domains/default/npc/ogre.c new file mode 100644 index 0000000..40e1820 --- /dev/null +++ b/lib/domains/default/npc/ogre.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("ogre"); + SetAdjectives( ({"foul", "stinking", "unlovable", "potbellied", "snaggletoothed", "monstrous"}) ); + SetId( ({"oaf", "beast"}) ); + SetShort("a monstrous ogre"); + SetLong("This is not a lovable oaf. This foul, stinking beast is twice as tall as a human, potbellied and snaggletoothed. Its skin is crawling with vermin and is encrusted with dried body fluids."); + SetLevel(1); + SetMelee(1); + SetRace("ogre"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/orc.c b/lib/domains/default/npc/orc.c new file mode 100644 index 0000000..f7e7dd6 --- /dev/null +++ b/lib/domains/default/npc/orc.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_NPC; + +static void create() { + npc::create(); + SetKeyName("orc"); + SetId(({"orc"})); + SetAdjectives(({"dirty"})); + SetShort("a dirty orc"); + SetLong("This orc is typical of its breed: nasty, brutish, and short. It appears " + "to be a juvenile or adolescent, making it somewhat less " + "dangerous but more hostile. "); + SetLevel(1); + SetRace("orc"); + SetGender("male"); + SetMaxHealthPoints(100); + SetEncounter(0); + SetInventory(([ + "/domains/default/weap/axe":"wield axe", + ]) ); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/pegasus.c b/lib/domains/default/npc/pegasus.c new file mode 100644 index 0000000..0ad3e32 --- /dev/null +++ b/lib/domains/default/npc/pegasus.c @@ -0,0 +1,25 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("winged horse"); + SetId( ({"horse", "steed", "equine", "pegasus"}) ); + SetAdjectives( ({"flying", "winged", "white"}) ); + SetShort("a winged horse"); + SetLong("This beautiful white steed is a pegasus, a horse endowed with great feathered wings and can fly."); + SetLevel(5); + SetMount(1); + SetRace("pegasus"); + SetStat("strength", 50); + SetGender("male"); + SetMelee(1); + SetAction(5, ({ + "The winged horse snorts.", "You hear the winged horse flap its wings a bit.", + "The winged horse flips its tail in the air.", + "The winged horse looks around."})); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/pessis.c b/lib/domains/default/npc/pessis.c new file mode 100644 index 0000000..f7307fd --- /dev/null +++ b/lib/domains/default/npc/pessis.c @@ -0,0 +1,22 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("pessis"); + SetId( ({"half-orc", "half orc", "half human", "half-human"}) ); + SetAdjectives(({"non-player", "non player"})); + SetShort("Pessis the half-orc"); + SetLong("Too rough and brutish looking to be a handsome human, too delicate to be a proper orc, Pessis has lived through great indignity and rejection his entire existence. He's understandably a bit defensive about it, so perhaps it's best not to bring up the subject."); + SetInventory(([ + "/domains/default/armor/horc_shirt" : "wear tshirt", + ])); + SetLevel(1); + SetMelee(1); + SetRace("half-orc"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/quarantine/adrian.c b/lib/domains/default/npc/quarantine/adrian.c new file mode 100644 index 0000000..e1359f1 --- /dev/null +++ b/lib/domains/default/npc/quarantine/adrian.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + + +static void create() { + sentient::create(); + SetKeyName("Adrian"); + SetId(({"adrian"})); + SetShort("Adrian"); + SetLong("Adrian is a foreign exchange student from the United Kingdom."); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/quarantine/cor.c b/lib/domains/default/npc/quarantine/cor.c new file mode 100644 index 0000000..7807696 --- /dev/null +++ b/lib/domains/default/npc/quarantine/cor.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("Cor"); + SetId(({"cor"})); + SetShort("Cor"); + SetLong("Cor is a foreign exchange student from the Netherlands."); + SetMelee(1); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/quarantine/duncan.c b/lib/domains/default/npc/quarantine/duncan.c new file mode 100644 index 0000000..01820e4 --- /dev/null +++ b/lib/domains/default/npc/quarantine/duncan.c @@ -0,0 +1,18 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("Duncan"); + SetId(({"duncan"})); + SetShort("Duncan"); + SetLong("Duncan is a foreign exchange student from the United Kingdom."); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/quarantine/edmund.c b/lib/domains/default/npc/quarantine/edmund.c new file mode 100644 index 0000000..a928bf1 --- /dev/null +++ b/lib/domains/default/npc/quarantine/edmund.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_NPC; + + +static void create() { + npc::create(); + SetKeyName("Edmund"); + SetId(({"edmund"})); + SetShort("Edmund"); + SetLong("Edmund is a foreign exchange student from the United Kingdom."); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/quarantine/gavin.c b/lib/domains/default/npc/quarantine/gavin.c new file mode 100644 index 0000000..292453f --- /dev/null +++ b/lib/domains/default/npc/quarantine/gavin.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + + +static void create() { + sentient::create(); + SetKeyName("Gavin"); + SetId(({"gavin"})); + SetShort("Gavin"); + SetLong("Gavin is a foreign exchange student from the United Kingdom."); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/quarantine/graham.c b/lib/domains/default/npc/quarantine/graham.c new file mode 100644 index 0000000..f9dfcc0 --- /dev/null +++ b/lib/domains/default/npc/quarantine/graham.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + + +static void create() { + sentient::create(); + SetKeyName("Graham"); + SetId(({"graham"})); + SetShort("Graham"); + SetLong("Graham is a foreign exchange student from the United Kingdom."); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/quarantine/han.c b/lib/domains/default/npc/quarantine/han.c new file mode 100644 index 0000000..5db53b9 --- /dev/null +++ b/lib/domains/default/npc/quarantine/han.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("Han"); + SetId(({"han"})); + SetShort("Han"); + SetLong("Han is a foreign exchange student from the Netherlands."); + SetMelee(1); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/quarantine/jan.c b/lib/domains/default/npc/quarantine/jan.c new file mode 100644 index 0000000..db677b3 --- /dev/null +++ b/lib/domains/default/npc/quarantine/jan.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("jan"); + SetId(({"jan"})); + SetShort("Jan"); + SetLong("Jan is a foreign exchange student from the Netherlands."); + SetMelee(1); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/quarantine/job.c b/lib/domains/default/npc/quarantine/job.c new file mode 100644 index 0000000..384dd79 --- /dev/null +++ b/lib/domains/default/npc/quarantine/job.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("Job"); + SetId(({"job"})); + SetShort("Job"); + SetLong("Job is a foreign exchange student from the Netherlands."); + SetMelee(1); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/quarantine/kip.c b/lib/domains/default/npc/quarantine/kip.c new file mode 100644 index 0000000..0f0c659 --- /dev/null +++ b/lib/domains/default/npc/quarantine/kip.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_NPC; + +static void create() { + npc::create(); + SetKeyName("Kip"); + SetId(({"kip"})); + SetShort("Kip"); + SetLong("Kip is a foreign exchange student from the Netherlands."); + SetMelee(1); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/quarantine/lester.c b/lib/domains/default/npc/quarantine/lester.c new file mode 100644 index 0000000..1595b82 --- /dev/null +++ b/lib/domains/default/npc/quarantine/lester.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + + +static void create() { + sentient::create(); + SetKeyName("lester"); + SetId(({"lester"})); + SetShort("Lester"); + SetLong("Lester is a foreign exchange student from the United Kingdom."); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/quarantine/lex.c b/lib/domains/default/npc/quarantine/lex.c new file mode 100644 index 0000000..c5535aa --- /dev/null +++ b/lib/domains/default/npc/quarantine/lex.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("Lex"); + SetId(({"lex"})); + SetShort("Lex"); + SetLong("Lex is a foreign exchange student from the Netherlands."); + SetMelee(1); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/quarantine/miles.c b/lib/domains/default/npc/quarantine/miles.c new file mode 100644 index 0000000..74e10f1 --- /dev/null +++ b/lib/domains/default/npc/quarantine/miles.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + + +static void create() { + sentient::create(); + SetKeyName("Miles"); + SetId(({"miles"})); + SetShort("Miles"); + SetLong("Miles is a foreign exchange student from the United Kingdom."); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/quarantine/nigel.c b/lib/domains/default/npc/quarantine/nigel.c new file mode 100644 index 0000000..ec15ec2 --- /dev/null +++ b/lib/domains/default/npc/quarantine/nigel.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + + +static void create() { + sentient::create(); + SetKeyName("Nigel"); + SetId(({"nigel"})); + SetShort("Nigel"); + SetLong("Nigel is a foreign exchange student from the United Kingdom."); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/quarantine/pip.c b/lib/domains/default/npc/quarantine/pip.c new file mode 100644 index 0000000..2947dcd --- /dev/null +++ b/lib/domains/default/npc/quarantine/pip.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("Pip"); + SetId(({"pip"})); + SetShort("Pip"); + SetLong("Pip is a foreign exchange student from the Netherlands."); + SetMelee(1); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/quarantine/rik.c b/lib/domains/default/npc/quarantine/rik.c new file mode 100644 index 0000000..c2e1159 --- /dev/null +++ b/lib/domains/default/npc/quarantine/rik.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("Rik"); + SetId(({"rik"})); + SetShort("Rik"); + SetLong("Rik is a foreign exchange student from the Netherlands."); + SetMelee(1); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/quarantine/simon.c b/lib/domains/default/npc/quarantine/simon.c new file mode 100644 index 0000000..d32fab8 --- /dev/null +++ b/lib/domains/default/npc/quarantine/simon.c @@ -0,0 +1,18 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("Simon"); + SetId(({"simon"})); + SetShort("Simon"); + SetLong("Simon is a foreign exchange student from the United Kingdom."); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/quarantine/spencer.c b/lib/domains/default/npc/quarantine/spencer.c new file mode 100644 index 0000000..15ea1b6 --- /dev/null +++ b/lib/domains/default/npc/quarantine/spencer.c @@ -0,0 +1,18 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("Spencer"); + SetId(({"spencer"})); + SetShort("Spencer"); + SetLong("Spencer is a foreign exchange student from the United Kingdom."); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/quarantine/ted.c b/lib/domains/default/npc/quarantine/ted.c new file mode 100644 index 0000000..efa37ba --- /dev/null +++ b/lib/domains/default/npc/quarantine/ted.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + + +static void create() { + sentient::create(); + SetKeyName("Ted"); + SetId(({"ted"})); + SetShort("Ted"); + SetLong("Ted is a student in the Virtual Campus."); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/quarantine/tom.c b/lib/domains/default/npc/quarantine/tom.c new file mode 100644 index 0000000..7496df4 --- /dev/null +++ b/lib/domains/default/npc/quarantine/tom.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + + +static void create() { + sentient::create(); + SetKeyName("Tom"); + SetId(({"tom"})); + SetShort("Tom"); + SetLong("Tom is a student in the Virtual Campus."); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/quarantine/ton.c b/lib/domains/default/npc/quarantine/ton.c new file mode 100644 index 0000000..01eff87 --- /dev/null +++ b/lib/domains/default/npc/quarantine/ton.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("Ton"); + SetId(({"ton"})); + SetShort("Ton"); + SetLong("Ton is an exchange student from the Netherlands."); + SetMelee(1); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/quarantine/trevor.c b/lib/domains/default/npc/quarantine/trevor.c new file mode 100644 index 0000000..eb51161 --- /dev/null +++ b/lib/domains/default/npc/quarantine/trevor.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + + +static void create() { + sentient::create(); + SetKeyName("Trevor"); + SetId(({"trevor"})); + SetShort("Trevor"); + SetLong("Trevor is an exchange student from the United Kingdom."); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/quarantine/wallace.c b/lib/domains/default/npc/quarantine/wallace.c new file mode 100644 index 0000000..619d68c --- /dev/null +++ b/lib/domains/default/npc/quarantine/wallace.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + + +static void create() { + sentient::create(); + SetKeyName("Wallace"); + SetId(({"wallace"})); + SetShort("Wallace"); + SetLong("Wallace is a foreign exchange student from the United Kingdom."); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/quarantine/wim.c b/lib/domains/default/npc/quarantine/wim.c new file mode 100644 index 0000000..c47f478 --- /dev/null +++ b/lib/domains/default/npc/quarantine/wim.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("Wim"); + SetId(({"wim"})); + SetShort("wim"); + SetLong("Wim is a foreign exchange student from the Netherlands."); + SetMelee(1); + SetLevel(5); + SetRace("human"); + SetGender("male"); + SetNoClean(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/rat.c b/lib/domains/default/npc/rat.c new file mode 100644 index 0000000..4a6e349 --- /dev/null +++ b/lib/domains/default/npc/rat.c @@ -0,0 +1,36 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +int CheckRat(mixed val){ + string *allowed_races = ({ "orc", "half-orc", "rodent" }); + if(!val) return 0; + if(!objectp(val)) return 0; + if(member_array(val->GetRace(), allowed_races) != -1) return 0; + return 1; +} + +static void create() { + sentient::create(); + SetKeyName("rat"); + SetAdjectives( ({"mangy", "little", "dirty"}) ); + SetId( ({"rat"}) ); + SetShort("a rat"); + SetLong("A scruffy little dirty rat."); + SetLevel(3); + SetMaxHealthPoints(50); + SetRace("rodent"); + SetGender("male"); + SetClass("fighter"); + SetWanderSpeed(1); + SetEncounter( (: CheckRat :) ); + SetMessage("come","$N scurries in."); + SetMessage("leave","$N scurries $D."); + SetAction(5, ({ + "The rat squeaks.", "You hear a rat scuttling about.", + "A scruffy little rat brushes against your leg.", + "You hear tiny munching sounds."})); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/red_dragon.c b/lib/domains/default/npc/red_dragon.c new file mode 100644 index 0000000..1af777f --- /dev/null +++ b/lib/domains/default/npc/red_dragon.c @@ -0,0 +1,20 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("dragon"); + SetAdjectives( ({"huge", "red", "dangerous"}) ); + SetId(({"npc","mob","character","mobile"})); + SetShort("a red dragon"); + SetLong("Ancient villain of legend and fable, the red dragon is among the most vicious, cruel, and dangerous beasts around. This one is easily fifteen feet tall and could probably crush you without even noticing."); + SetClass("fighter"); + SetLevel(15); + SetMelee(1); + SetRace("dragon"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/satyr.c b/lib/domains/default/npc/satyr.c new file mode 100644 index 0000000..5fbeed7 --- /dev/null +++ b/lib/domains/default/npc/satyr.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("satyr"); + SetAdjectives( ({"wild", "ferocious", "looking", "male", "humanoid", "creature"}) ); + SetId( ({"male", "humanoid", "creature"}) ); + SetShort("a satyr"); + SetLong("This is a wild and ferocious looking humanoid male with the upper body of a human, but the lower body is goatish, woolly, and his legs are those of a hooved animal. Horns grow from beneath the wild mane of hair on his head. However human his face might be, his expression and demeanor make it clear this is not a domesticated person, but an untamed forest creature."); + SetLevel(1); + SetMelee(1); + SetRace("satyr"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/sheep.c b/lib/domains/default/npc/sheep.c new file mode 100644 index 0000000..ffa1993 --- /dev/null +++ b/lib/domains/default/npc/sheep.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("sheep"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"non-player", "non player"})); + SetShort("a sheep"); + SetLong("This is a typically placid mammal ungulate, given to wandering fields munching on grass. Its fur is called wool and is unusually thick and warm. Wool is prized as a component in clothing."); + SetLevel(1); + SetMelee(1); + SetRace("sheep"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/slug.c b/lib/domains/default/npc/slug.c new file mode 100644 index 0000000..cc25392 --- /dev/null +++ b/lib/domains/default/npc/slug.c @@ -0,0 +1,23 @@ +#include <position.h> +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("slug"); + SetId( ({"gastropod"}) ); + SetAdjectives( ({"big", "thick", "slimy", "garden", "gross"}) ); + SetShort("a slimy slug"); + SetLong("A big, thick, slimy garden slug. Gross!"); + SetAutoStand(0); + SetPosition(POSITION_LYING); + SetLevel(1); + SetMelee(1); + SetRace("slug"); + SetMaxHealthPoints(5); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/snake.c b/lib/domains/default/npc/snake.c new file mode 100644 index 0000000..7281436 --- /dev/null +++ b/lib/domains/default/npc/snake.c @@ -0,0 +1,22 @@ +#include <position.h> +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("snake"); + SetId( ({"garter snake", "reptile"}) ); + SetAdjectives( ({"small", "harmless", "garter", "black", "black and yellow", "yellow and black"}) ); + SetShort("a garter snake"); + SetLong("This is a small, harmless reptile, about 9 inches long. It is black with a few yellow stripes along its length. This snake enjoys eating garden pests."); + SetAutoStand(0); + SetPosition(POSITION_LYING); + SetLevel(1); + SetMelee(1); + SetRace("snake"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/spider.c b/lib/domains/default/npc/spider.c new file mode 100644 index 0000000..ea4a696 --- /dev/null +++ b/lib/domains/default/npc/spider.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include <size_types.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("spider"); + SetAdjectives( ({"huge", "hairy"}) ); + SetId(({"npc","mob","character","mobile"})); + SetShort("a huge spider"); + SetLong("This is a humongous hairy spider about the size of a housecat. It looks absolutely vile and it has some kind of viscous fluid is dripping from its mouthparts."); + SetWimpy(80); + SetMelee(1); + SetLevel(1); + SetRace("arachnid"); + SetClass("explorer"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/treant.c b/lib/domains/default/npc/treant.c new file mode 100644 index 0000000..294a4cc --- /dev/null +++ b/lib/domains/default/npc/treant.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("treant"); + SetAdjectives( ({"great", "old", "giant", "ancient", "benevolent"}) ); + SetId( ({"protector", "tree"}) ); + SetShort("an ancient treant"); + SetLong("This is a great old treant, which looks much like a giant tree with a face, arms, and legs. Ancient protectors of forests, treants are widely respected for their general good will and benevolence."); + SetLevel(1); + SetMelee(1); + SetRace("tree"); + SetGender("neuter"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/tree.c b/lib/domains/default/npc/tree.c new file mode 100644 index 0000000..c08fff0 --- /dev/null +++ b/lib/domains/default/npc/tree.c @@ -0,0 +1,58 @@ +#include <lib.h> +inherit LIB_NPC; + +static void create(){ + npc::create(); + SetKeyName("money tree"); + SetId(({"tree","money tree","arborus argentum"})); + SetShort("a money tree"); + SetLong("This robust, 4-foot tall tree is the fabled arborus argentum, or money "+ + "tree. Its leaves are fresh, new dollar bills, and its seed-bearing "+ + "pods are full to bursting with coins of all kinds. It would be no "+ + "trouble at all to get <amount> <currency> from tree...looks like "+ + "you've hit the jackpot!"); + SetPacifist(1); + SetCanBite(0); + SetLevel(99); + SetRace("tree"); + SetHealthPoints(99999); + SetMaxHealthPoints(99999); + SetPreventGet(1); +} + +void init(){ + ::init(); + add_action("make_money","get"); +} + +int make_money(string str){ + int d1; + string s1,s2; + if(!creatorp(this_player()) && !member_group(this_player(),"TEST")) { + write("Your hands seem to slide off the tree...as if somehow " + "it knows this money shouldn't fall into your greedy hands."); + return 1; + } + if(!str){ write("Get what?\n"); return 1; } + if(sscanf(str,"%d %s from %s",d1,s1,s2) > 0){ + if(s1 !="electrum" && s1 != "platinum" && + s1 !="gold" && s1 !="cents" && + s1 !="dollars" && s1 !="copper" && + s1 !="silver"){ + write("That kind of money doesn't grow on trees!\n"); + return 1; + } + if(s2=="tree" || s2=="the tree" || + s2=="the money tree" || s2=="arborus argentum"){ + if(d1 > 1000000){ + write("That is too much money to get from the tree at once.\n"); + return 1; + } + this_player()->AddCurrency(s1, d1); + write("You get "+d1+" "+s1+" from the money tree."); + say(this_player()->GetCapName()+" gets money from the money tree."); + return 1; + } + return 0; + } +} diff --git a/lib/domains/default/npc/triffid.c b/lib/domains/default/npc/triffid.c new file mode 100644 index 0000000..5bafc48 --- /dev/null +++ b/lib/domains/default/npc/triffid.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("triffid"); + SetAdjectives( ({"six foot tall", "six feet tall", "thick", "bushy", "thorned", "menacing"}) ); + SetId( ({"plant"}) ); + SetShort("a large, tall plant"); + SetLong("This plant is about six feet tall and similar to a very thick and bushy corn plant. It possesses tentacle-like thorned vines which wave about menacingly, and it appears capable of locomotion."); + SetLevel(1); + SetMelee(1); + SetRace("plant"); + SetGender("neuter"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/troll.c b/lib/domains/default/npc/troll.c new file mode 100644 index 0000000..4b16479 --- /dev/null +++ b/lib/domains/default/npc/troll.c @@ -0,0 +1,45 @@ +#include <lib.h> + +inherit LIB_NPC; +object gdude; + +int nasty(object dude){ + gdude = dude; + eventForce("look at "+gdude->GetKeyName()); + eventForce("drool"); + return 1; +} +int CheckHuman(mixed val){ + if(!val) return 0; + if(!objectp(val)) return 0; + gdude = val; + if(val->GetRace() != "human") return 0; + else { + call_out( (: nasty, gdude :) , 2); + } + return 1; +} +static void create() { + npc::create(); + SetKeyName("troll"); + SetId(({"troll"})); + SetAdjectives(({"dirty"})); + SetShort("a mean-looking troll"); + SetLong("This is the dreaded creature of legend: a slimy, " + "green, putrid-looking fiend with long, razor-" + "sharp claws and fangs."); + SetLevel(3); + SetRace("troll"); + SetClass("fighter"); + SetGender("male"); + SetMelee(1); + SetSkill("melee attack",50,50,10); + SetStat("strength",50,1); + SetStat("agility",50,1); + SetStat("coordination",50,1); + SetStat("speed",50,1); + AddCurrency("silver",221+random(157)); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/turtle.c b/lib/domains/default/npc/turtle.c new file mode 100644 index 0000000..75dd5e8 --- /dev/null +++ b/lib/domains/default/npc/turtle.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("mock turtle"); + SetAdjectives( ({"peculiar", "mock"}) ); + SetId( ({"turtle", "tortoise"}) ); + SetShort("a mock turtle"); + SetLong("This peculiar creature has the head of a calf but the body of a turtle."); + SetLevel(1); + SetMelee(1); + SetRace("tortoise"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/unicorn.c b/lib/domains/default/npc/unicorn.c new file mode 100644 index 0000000..94048ef --- /dev/null +++ b/lib/domains/default/npc/unicorn.c @@ -0,0 +1,22 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("unicorn"); + SetId(({"unicorn","large unicorn"})); + SetShort("a beautiful white unicorn"); + SetLong("This white unicorn is a great, proud horse with a single ivory horn growing from its head. Long a symbol of masculine virility, many people still fail to see this large, muscular beast with a long, hard horn as the powerful sexual icon it is."); + SetLevel(5); + SetRace("unicorn"); + SetGender("male"); + SetMelee(1); + SetAction(5, ({ + "The unicorn snorts.", "You hear the unicorn whinny.", + "The unicorn flips its tail in the air.", + "The unicorn looks around."})); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/wraith.c b/lib/domains/default/npc/wraith.c new file mode 100644 index 0000000..0e76f23 --- /dev/null +++ b/lib/domains/default/npc/wraith.c @@ -0,0 +1,190 @@ +#include <position.h> +#include <lib.h> +#include ROOMS_H + +inherit LIB_SENTIENT; +object *enemies = ({}); +object quarry; +int draining; +string qname; + +int eventDrain(mixed args...){ + int avoid; + if(!environment()) return 1; + enemies = this_object()->GetEnemies(); + if(quarry && draining) enemies += ({ quarry }); + if(!sizeof(enemies)) return 1; + enemies = filter(enemies, (: $1 && environment($1) :)); + enemies = filter(enemies, (: environment($1) == environment() :)); + if(!sizeof(enemies)) return 1; + if(sizeof(enemies) > 5) enemies = scramble_array(enemies)[0..4]; + foreach(object enemy in enemies){ + int which, level; + string what; + mixed *skills = enemy->GetSkills(); + mixed *stats = enemy->GetStats(); + if(quarry && enemy == quarry && random(100) > draining) avoid = 100; + switch(which = random(8)+avoid){ + case 0 : + if(!skills) break; + what = skills[random(sizeof(skills)-1)]; + if(enemy) level = enemy->GetSkillLevel(what); + level = level/2; + if(level) enemy->SetSkill(what,level); + break; + case 1 : + if(!stats) break; + what = stats[random(sizeof(stats)-1)]; + if(enemy) level = enemy->GetStatLevel(what); + level = level/2; + if(level) enemy->SetStat(what,level); + break; + case 2 : + what = "level"; + if(enemy) level = enemy->GetLevel(); + level = level/2; + if(level) enemy->ChangeLevel(level); + break; + case 3 : + what = "health"; + if(enemy) level = enemy->GetHealthPoints(); + level = level/2; + if(level) enemy->AddHP(-level); + break; + case 4 : + what = "stamina"; + if(enemy) level = enemy->GetStaminaPoints(); + level = level/2; + if(level) enemy->AddStaminaPoints(-level); + break; + case 5 : + what = "stamina"; + if(enemy) level = enemy->GetMagicPoints(); + level = level/2; + if(level) enemy->AddMagicPoints(-level); + break; + case 6 : + what = "experience"; + if(enemy) level = enemy->GetExperiencePoints(); + level = level/2; + if(level) enemy->AddExperiencePoints(-level); + break; + case 7 : + what = "quest"; + if(enemy) level = enemy->GetQuestPoints(); + level = level/2; + if(level) enemy->AddQuestPoints(-level); + break; + default: break; + } + if(enemy && which < 100){ + tell_object(enemy,"The wraith drains your vital essence!"); + tell_room(environment(this_object()), "The wraith drains "+ + enemy->GetName()+" of precious bodily essence!", ({ enemy })); + } + } + return 0; +} + +static void create() { + sentient::create(); + SetKeyName("archwraith"); + SetAdjectives( ({"arch", "shadowy", "undead", "unholy", "malevolent", "spiteful"}) ); + SetId( ({"archwraith", "wraith", "specter", "ghost", "apparition", "manifestation"}) ); + SetShort("an archwraith"); + SetLong("This shadowy manifestation is an undead, unholy apparition, oozing malevolence and spite."); + SetPosition(POSITION_FLYING); + SetRace("wraith"); + SetClass("fighter"); + SetLevel(20); + SetMelee(1); + SetInvis(1); + SetGender("neuter"); + SetUndead(1); + SetUndeadType("wraith"); + SetAttackable(0); + SetCombatAction(100, (: eventDrain :)); +} + +varargs int eventReceiveDamage(mixed args...){ + return 0; +} + +void init(){ + ::init(); + add_action("add_target","wraithseek"); + add_action("track_target","wraithtrack"); +} + +void heart_beat(){ + int here; + mixed *dest; + ::heart_beat(); + if(!this_object()) return; + if(!quarry && qname) quarry = find_player(qname); + if(quarry && environment(quarry) && environment(quarry) == environment()){ + eventDrain(quarry); + } + if(environment() && (sizeof(enemies) || quarry)){ + foreach(object enemy in enemies + ({ quarry })){ + if(!enemy) continue; + if(environment(enemy) && environment(enemy) == environment()){ + here = 1; + } + } + if(!here){ + dest = filter(enemies, (: $1 && environment($1) :)); + if(quarry) dest = (environment(quarry) ? ({ quarry }) : dest ); + if(sizeof(dest)){ + eventMove(environment(dest[random(sizeof(dest)-1)])); + } + else { + this_object()->eventMove(load_object(ROOM_DEATH)); + } + } + } +} + +int add_target(string str){ + object target = find_player(str); + if(!this_player() || (this_player() && !adminp(this_player()))){ + return 0; + } + if(target){ + write("seeking "+str); + if(environment(target)){ + this_object()->eventMove(environment(target)); + this_object()->AddEnemy(target); + } + } + return 1; +} + +int track_target(string str){ + object target = find_player(str); + if(!this_player() || (this_player() && !adminp(this_player()))){ + return 0; + } + qname = str; + if(target){ + write("tracking "+str); + if(environment(target)){ + quarry = target; + this_object()->eventMove(environment(target)); + } + } + return 1; +} + +int eventDestruct(){ + if(this_player() && !adminp(this_player())) return 0; + return ::eventDestruct(); +} + +int SetDraining(int i){ + if(!this_player() || (this_player() && !adminp(this_player()))){ + return 0; + } + draining = i; + return draining; +} diff --git a/lib/domains/default/npc/yattering.c b/lib/domains/default/npc/yattering.c new file mode 100644 index 0000000..7e55bb9 --- /dev/null +++ b/lib/domains/default/npc/yattering.c @@ -0,0 +1,20 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("yattering"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"non-player", "non player"})); + SetShort("a foul little yattering"); + SetLong("This is a wretched, fleshy pink creature about two feet tall. It has long, droopy ears, a beaklike mouth, and a pair of useless wing stubs on its back. Its general demeanor is listless and somehow resentful. As pathetic as it looks, its possesses long black claws, and its beak looks plenty sharp."); + SetClass("fighter"); + SetLevel(5); + SetMelee(1); + SetRace("demon"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/zoe.c b/lib/domains/default/npc/zoe.c new file mode 100644 index 0000000..f67353b --- /dev/null +++ b/lib/domains/default/npc/zoe.c @@ -0,0 +1,35 @@ +#include <lib.h> +#include <vendor_types.h> + +inherit LIB_TELLER; + + +static void create() { + ::create(); + SetKeyName("zoe"); + SetId( ({ "teller","banker","executive" }) ); + SetAdjectives( ({ "bank","executive","friendly","efficient" }) ); + SetShort("Zoe the bank teller"); + SetLevel(12); + SetLong("Zoe is an attractive young blonde woman with " + "a French accent. She is dressed in a conservative, " + "executive style, and has a friendly and efficient air " + "about her."); + SetGender("female"); + SetMorality(40); + SetRace("human"); + AddCurrency("silver", random(100)); + SetProperty("no bump", 1); + SetLocalCurrency("silver"); + SetBankName("First Village Bank"); + SetLocalCurrency("silver"); + SetLocalFee(1); + SetOpenFee(5); + SetExchangeFee(2); + SetCurrencies( ({ "copper", "silver", "electrum", "gold", "platinum" }) ); + + +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/npc/zookeeper.c b/lib/domains/default/npc/zookeeper.c new file mode 100644 index 0000000..9fcc05b --- /dev/null +++ b/lib/domains/default/npc/zookeeper.c @@ -0,0 +1,20 @@ +#include <lib.h> + +inherit LIB_BOT; + +static void create() { + ::create(); + SetKeyName("zookeeper bot"); + SetId( ({"bot", "robot", "zookeeper", "keeper"}) ); + SetAdjectives(({"non-player", "non player"})); + SetShort("a robot zookeeper"); + SetLong("This efficient automaton continually feeds, bathes, grooms, and looks after all the wild things kept in the menagerie."); + SetLevel(1); + SetMelee(1); + SetRace("android"); + SetGender("male"); + SetMaxClones(3); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/obj/223clip.c b/lib/domains/default/obj/223clip.c new file mode 100644 index 0000000..51d7899 --- /dev/null +++ b/lib/domains/default/obj/223clip.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_CLIP; + +void create(){ + clip::create(); + SetKeyName(".223 clip"); + SetId(({"clip","magazine"})); + SetAdjectives(({".223","rifle","caliber","ammo","ammunition"})); + SetShort("a .223 caliber rifle ammunition clip"); + SetLong("This is a spring-loaded ammunition clip for a .223 caliber "+ + "rifle. It will contain a maximum of thirty rounds."); + SetCaliber(223); + SetMaxAmmo(30); + SetAmmoType("nato"); + SetVendorType(VT_TREASURE); + SetInventory(([ + "/domains/default/obj/223round" : 30, + ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/obj/223round.c b/lib/domains/default/obj/223round.c new file mode 100644 index 0000000..f37b8d9 --- /dev/null +++ b/lib/domains/default/obj/223round.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ROUND; + + +void create(){ + round::create(); + SetKeyName("223round"); + SetId(({"round","bullet"})); + SetAdjectives(({".223","caliber","rifle","m16","M16","m-16","M-16"})); + SetShort("a .223 caliber rifle round"); + SetLong("This is a .223 caliber rifle round, probably for an M-16 assault rifle. "+ + "It is not very wide, but contains a large powder charge. It is no doubt a powerful "+ + "piece of ammunition. It has not been fired."); + SetCaliber(223); + SetFirearmType("auto"); + SetAmmoType("nato"); + SetVendorType(VT_TREASURE); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/obj/9mmclip.c b/lib/domains/default/obj/9mmclip.c new file mode 100644 index 0000000..b8165c7 --- /dev/null +++ b/lib/domains/default/obj/9mmclip.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_CLIP; + +void create(){ + clip::create(); + SetKeyName("9mm clip"); + SetId(({"clip","magazine"})); + SetAdjectives(({"9mm","ammunition","ammo","9 millimeter","pistol"})); + SetShort("a 9 millimeter pistol ammunition clip"); + SetLong("This is a slender, spring-loaded metal container designed "+ + "to feed a 9 millimeter pistol with bullets."); + SetMillimeter(9); + SetMaxAmmo(15); + SetAmmoType("acp"); + SetVendorType(VT_TREASURE); + SetInventory(([ + "/domains/default/obj/9mmround" : 15 + ])); +} + +void init(){ + clip::init(); +} diff --git a/lib/domains/default/obj/9mmround.c b/lib/domains/default/obj/9mmround.c new file mode 100644 index 0000000..d40fe56 --- /dev/null +++ b/lib/domains/default/obj/9mmround.c @@ -0,0 +1,16 @@ +#include <lib.h> +#include <vendor_types.h> +inherit "/lib/round"; + +void create(){ + ::create(); + SetKeyName("9mmround"); + SetId(({"round","bullet"})); + SetAdjectives(({"9 millimeter","9mm","pistol"})); + SetShort("a 9 millimeter pistol round"); + SetLong("This is a 9 millimeter pistol bullet. It has not been fired."); + SetMillimeter(9); + SetFirearmType("auto"); + SetAmmoType("acp"); + SetVendorType(VT_TREASURE); +} diff --git a/lib/domains/default/obj/abox.c b/lib/domains/default/obj/abox.c new file mode 100644 index 0000000..da6ad66 --- /dev/null +++ b/lib/domains/default/obj/abox.c @@ -0,0 +1,28 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("ammunition box"); + SetId(({"can","box"})); + SetAdjectives(({"metal","ammo","ammunition","large"})); + SetShort("an ammo box"); + SetLong("This is a large metal box containing various kinds "+ + "of ammunition. "); + SetMass(200); + SetDollarCost(50); + SetMaxCarry(500); + SetCanClose(1); + SetClosed(0); + SetInventory( ([ + "/domains/default/obj/9mmclip": ({ 60, 2 }), + "/domains/default/obj/223clip": ({ 60, 2 }), + "/domains/default/weap/grenade": 3, + ]) ); + SetPreventGet("The metal ammunition box does not budge."); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/obj/bbucket.c b/lib/domains/default/obj/bbucket.c new file mode 100644 index 0000000..ba103d4 --- /dev/null +++ b/lib/domains/default/obj/bbucket.c @@ -0,0 +1,37 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("bin"); + SetId(({"bin","can","dustbin","trash","rubbish"})); + SetAdjectives(({"metal","small","blue","recycling","trash","garbage","dust"})); + SetShort("a recycling bin"); + SetLong("This is a blue trash can, marked with "+ + "the letters \"/dev/null\"."); + SetMass(200); + SetBaseCost("silver",50); + SetMaxCarry(999999); +} + +int tidy_up(){ + object *inv; + inv = all_inventory(this_object()); + foreach(object thing in inv){ + if(thing) thing->eventMove(ROOM_FURNACE); + } + return 1; +} + +int eventReceiveObject(object ob){ + write("You make a deposit into the the recycling bin.\n"); + call_out((: tidy_up :),1); + return 1; +} +mixed CanGet(object ob) { return "The bucket does not budge.";} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/obj/bguide.c b/lib/domains/default/obj/bguide.c new file mode 100644 index 0000000..2f5e627 --- /dev/null +++ b/lib/domains/default/obj/bguide.c @@ -0,0 +1,20 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_BOOK; + +void create(){ + ::create(); + SetKeyName("builder's guidebook"); + SetId( ({"text","guidebook", "book", "guide", "builders guide", "builders guidebook"}) ); + SetAdjectives( ({"builder's", "builder", "builders", "reference"}) ); + SetShort("a Builder's Guidebook"); + SetLong("This is a reference text for Dead Souls builders."); + SetNoCondition(1); + SetSource("/doc/bguide"); + SetMass(20); + SetVendorType(VT_TREASURE); + SetTitle("Builder's Guidebook"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/obj/box.c b/lib/domains/default/obj/box.c new file mode 100644 index 0000000..878365e --- /dev/null +++ b/lib/domains/default/obj/box.c @@ -0,0 +1,14 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("box"); + SetId( ({ "box" }) ); + SetAdjectives( ({ "small", "plastic","green", "a" }) ); + SetShort("a small plastic box"); + SetLong("It is a simple plastic box used to hold things."); + SetMass(274); + SetMaxCarry(500); +} diff --git a/lib/domains/default/obj/builder_chest.c b/lib/domains/default/obj/builder_chest.c new file mode 100644 index 0000000..0a5d853 --- /dev/null +++ b/lib/domains/default/obj/builder_chest.c @@ -0,0 +1,33 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("chest"); + SetId(({"chest","wooden chest"})); + SetShort("a wooden chest"); + SetLong("This is a sturdy wooden chest used to store valuable items."); + SetInventory(([ + "/domains/town/armor/collar" : 1, + "/domains/default/obj/bguide" : 1, + "/secure/obj/machine" : 1, + "/domains/default/obj/meter" : 1, + "/secure/obj/control" : 1, + "/secure/obj/memo" : 1, + "/secure/obj/staff" : 1, + "/domains/default/obj/pinger" : 1, + "/secure/obj/medtric" : 1, + ])); + SetMass(2000); + SetBaseCost(50); + SetMaxCarry(10000); + SetPreventPut("You cannot put this in there!"); + SetPreventGet("The chest does not budge."); + SetCanClose(1); + SetClosed(1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/obj/case.c b/lib/domains/default/obj/case.c new file mode 100644 index 0000000..a333314 --- /dev/null +++ b/lib/domains/default/obj/case.c @@ -0,0 +1,37 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("case"); + SetId( ({ "case" }) ); + SetAdjectives( ({ "mounted","wall","glass", "display" }) ); + SetShort("a glass display case"); + SetLong("This is a glass case designed to contain and display firearms."); + SetInventory(([ + "/domains/default/weap/m16rifle" : 1, + "/domains/default/weap/9mil" : 1, + "/domains/default/weap/357pistol" : 1, + "/domains/default/weap/prifle" : 1, + ])); + SetOpacity(0); + SetCanClose(1); + SetClosed(1); + SetMass(274); + SetBaseCost("silver",1); + SetMaxCarry(1500); +} +void init(){ + ::init(); +} + +int CanReceive(object ob) { + if(!inherits(LIB_FIREARM,ob)) { + write("This is a case for firearms only."); + return 0; + } + else return 1; +} + +mixed CanGet(object ob) { return "The case does not budge.";} diff --git a/lib/domains/default/obj/chair.c b/lib/domains/default/obj/chair.c new file mode 100644 index 0000000..d49f037 --- /dev/null +++ b/lib/domains/default/obj/chair.c @@ -0,0 +1,43 @@ +#include <lib.h> + +inherit LIB_CHAIR; + +static void create() { + chair::create(); + SetKeyName("chair"); + SetId("chair"); + SetAdjectives( ({ "swivel", "small", "black" }) ); + SetShort("a swivel chair"); + SetLong("This is a small swivel chair, with tasteful and understated "+ + "black covers."); + SetMass(1500); + SetDollarCost(15); + SetMaxSitters(1); +} +void init(){ + add_action("swivel","swivel"); +} + +int swivel(string str){ + int hit,i; + object *dupes; + dupes = get_dupes(this_object(),environment(this_object()) ); + if(!str || str =="" || str == "in chair" || str == "in the chair"){ + hit = 42; + for(i=0;i<sizeof(dupes);i++){ + if( member_array(this_player(),dupes[i]->GetSitters()) != -1) hit = 7; + if( member_array(this_player(),this_object()->GetSitters()) != -1) hit = 7; + } + if( hit == 7) { + write("You swivel around in your swivel chair! Whee!"); + say(this_player()->GetName()+" swivels around in "+possessive(this_player())+" "+ + "swivel chair, yelling \"WHEEEE!!!\""); + return 1; + } + else { write("You are not sitting in a swivel chair."); } + } + if(hit == 42) return 1; + else return 0; +} + +mixed CanGet(object ob) { return "The chair does not budge.";} diff --git a/lib/domains/default/obj/cheatbook.c b/lib/domains/default/obj/cheatbook.c new file mode 100644 index 0000000..198e248 --- /dev/null +++ b/lib/domains/default/obj/cheatbook.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_BOOK; + +void create(){ + ::create(); + SetKeyName("cheatbook"); + SetId( ({"book","cheatsbook" }) ); + SetAdjectives( ({"cheat", "cheats"}) ); + SetShort("a cheat book"); + SetLong("This is a book with explicit tricks you can use to advance your character. To read it, you must read the chapters in it. For example, 'read chapter 1 in cheatbook', or 'read index in cheatbook'"); + SetProperties(([ + "no steal" : 1, + ])); + SetMass(3); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetTitle("The Cheat Book"); + SetSource("/doc/cheats"); + SetDefaultRead("Try \"read chapter 1 in cheatbook\" or " + "\"read index in cheatbook\""); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/obj/chest.c b/lib/domains/default/obj/chest.c new file mode 100644 index 0000000..1681fae --- /dev/null +++ b/lib/domains/default/obj/chest.c @@ -0,0 +1,38 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("chest"); + SetId(({"chest","wooden chest"})); + SetShort("a wooden chest"); + SetLong("This is a sturdy wooden chest used to store valuable items."); + SetInventory(([ + "/domains/default/obj/meter" : 1, + "/secure/obj/staff" : 1, + "/domains/default/obj/gps" : 1, + "/domains/town/armor/collar" : 1, + "/secure/obj/medtric" : 1, + "/domains/default/armor/wizard_hat" : 1, + "/domains/default/armor/robe" : 1, + "/domains/default/armor/badge" : 1, + "/domains/default/obj/pinger" : 1, + "/domains/default/armor/jade_ring" : 1, + "/domains/default/armor/breather" : 1, + "/domains/default/obj/manual" : 1, + "/secure/obj/memo" : 1, + "/secure/obj/machine" : 1, + "/secure/obj/control" : 1, + ])); + SetMass(2000); + SetBaseCost(50); + SetMaxCarry(10000); + SetPreventPut("You cannot put this in there!"); + SetCanClose(1); + SetClosed(1); +} +mixed CanGet(object ob) { return "The chest does not budge.";} +void init(){ + ::init(); +} diff --git a/lib/domains/default/obj/collarchest.c b/lib/domains/default/obj/collarchest.c new file mode 100644 index 0000000..dcd81d8 --- /dev/null +++ b/lib/domains/default/obj/collarchest.c @@ -0,0 +1,29 @@ +/* /domains/Examples/etc/bag.c + * from the Nightmare IV LPC Library + * a sample bag object + * created by Descartes of Borg 950529 + */ + +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("chest"); + SetId(({"chest"})); + SetAdjectives(({"medical","metal","stainless","steel"})); + SetShort("a stainless steel chest"); + SetLong("This is a chest used to store medical tools."); + SetMass(274); + SetDollarCost(50); + SetMaxCarry(500); + SetPreventPut("You cannot put this in there!"); + SetInventory(([ + "/secure/obj/medtric" : 1, + "/domains/default/armor/collar" : 5, + ]) ); + SetCanClose(1); + SetClosed(1); +} +mixed CanGet(object ob) { return "The chest does not budge.";} diff --git a/lib/domains/default/obj/couch.c b/lib/domains/default/obj/couch.c new file mode 100644 index 0000000..ce78824 --- /dev/null +++ b/lib/domains/default/obj/couch.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <props.h> + +inherit LIB_BED; +inherit LIB_SMELL; + +static void create() { + ::create(); + SetKeyName("beat up couch"); + SetId( ({ "couch","sofa","recliner" }) ); + SetAdjectives( ({ "beat up","beat-up","old" }) ); + SetShort("a beat-up old couch"); + SetLong("This is a beat-up, worn and dirty couch, the kind " + "one might expect in a university dorm room."); + SetMass(3000); + SetBaseCost("silver",15); + SetMaxSitters(2); + SetMaxLiers(1); + + SetSmell( ([ + "default" : "It smells dirty and gross. There's a " + "faint whiff of dog urine." + ]) ); +} diff --git a/lib/domains/default/obj/generator.c b/lib/domains/default/obj/generator.c new file mode 100644 index 0000000..b809a99 --- /dev/null +++ b/lib/domains/default/obj/generator.c @@ -0,0 +1,178 @@ +#include <lib.h> +#include <vendor_types.h> + +inherit LIB_STORAGE; +inherit LIB_PRESS; +inherit LIB_INSTALL; +inherit LIB_ACTIVATE; + +string oportal = "/secure/obj/portal_orange"; +string bportal = "/secure/obj/portal_blue"; + +varargs mixed CheckOrange(int ob){ + object o, *tmp; + int orange = sizeof(tmp=filter(deep_inventory(this_object()), + (: base_name($1) == "/domains/default/obj/vial_orange" :) ) ); + if(orange) o = tmp[0]; + if(ob) return o; + return orange; +} + +varargs mixed CheckBlue(int ob){ + object b, *tmp; + int blue = sizeof(tmp=filter(deep_inventory(this_object()), + (: base_name($1) == "/domains/default/obj/vial_blue" :) ) ); + if(blue) b = tmp[0]; + if(ob) return b; + return blue; +} + +string ExaOrange(){ + string ret = "An orange button. "; + if(CheckOrange()) ret += "It is glowing."; + else ret += "It is darkened."; + return ret; +} + +string ExaBlue(){ + string ret = "A blue button. "; + if(CheckBlue()) ret += "It is glowing."; + else ret += "It is darkened."; + return ret; +} + +mixed PressOrange(mixed args...){ + int orange = CheckOrange(); + if(orange){ + orange = new(oportal)->eventMove(environment(this_player())); + } + if(orange){ + write("You press the button and with a deep thumping "+ + "sound an orange portal appears."); + say(this_player()->GetName()+" presses a button on "+ + possessive(this_player())+" portal generator, and with "+ + "a deep thumping sound an orange portal appears."); + } + else { + write("Click."); + say(this_player()->GetName()+" presses a button on "+ + possessive(this_player())+" portal generator."); + } + return 1; +} + +mixed PressBlue(mixed args...){ + int blue = CheckBlue(); + if(blue){ + blue = new(bportal)->eventMove(environment(this_player())); + } + if(blue){ + write("You press the button and with a deep thumping "+ + "sound a blue portal appears."); + say(this_player()->GetName()+" presses a button on "+ + possessive(this_player())+" portal generator, and with "+ + "a deep thumping sound a blue portal appears."); + } + else { + write("Click."); + say(this_player()->GetName()+" presses a button on "+ + possessive(this_player())+" portal generator."); + } + return 1; +} + +string ReadLabel(){ + string ret = ""; + ret += "GCM Heavy Industries Portal Generator Mk I\n\n"; + ret += "* Please read this beard to know act According to carry on!\n"; + ret += "* no portaling through between same room allowed Interdicted!\n"; + ret += "* Please the human user to be sign release form the organs!\n"; + ret += "* If you are stolen, call the police at once!\n"; + ret += "* values of "+sprintf("%c",223)+" may give rise to dom!\n"; + return ret; +} + +string ReadScribbles(){ + string ret = ""; + ret += "this technology was stolen by GCM and they don't understand it. "; + ret += "NOBODY HAS EVER RETURNED FROM USING PORTALS IN THE SAME ROOM! "; + ret += "and whatever you do, stay away from th\n"; + return ret; +} + +void create(){ + ::create(); + SetKeyName("GCM Portal Generator Mk I"); + SetId( ({"generator", "device", "generator mk i","generator mark i"}) ); + SetAdjectives( ({"sleek","mk i","futuristic","portal","gcm"}) ); + SetShort("a portal generator"); + SetLong("This is a sleek, futuristic device with orange and "+ + "blue buttons. It has a printed label you can read, and it looks "+ + "like someone has scribbled some markings on it as well."); + SetMass(100); + SetBaseCost("silver",5000); + SetVendorType(VT_TREASURE); + SetItems( ([ + ({"label","printed label"}) : "A printed label you can read.", + ({"markings","scribbles","scribbled markings"}) : "Markings "+ + "you can read, apparently scribbled in haste.", + ({ "button", "buttons" }) : "The portal generator has two buttons, one"+ + " orange, one blue.", + ({ "orange button" }) : (: ExaOrange :), + ({ "blue button" }) : (: ExaBlue :), + ]) ); + SetReads( ([ + "default" : "Try 'read label on generator'", + ({"label","printed label"}) : (: ReadLabel :), + ({"markings","scribbles","scribbled markings"}) : (: ReadScribbles :), + ]) ); + SetPress( ([ + "default" : "Try 'push blue button on generator'", + ({ "button", "buttons" }) : "You have to press one or the other.", + ({"orange button"}) : (: PressOrange :), + ({"blue button"}) : (: PressBlue :), + ]) ); + SetMaxCarry(200); + SetUnique(1); +} + +varargs mixed eventInstall(object what, object where){ + write("The portal generator is not installable anywhere"); + return 1; +} + +mixed CanPutInto(object who, object item){ + return "This is a portal generator. One can install things in it."; +} + +mixed CanGetFrom(object who, object item){ + return "This is a portal generator. One can uninstall things from it."; +} + +int CanReceive(object ob){ + if(base_name(ob) == "/domains/default/obj/vial_blue"){ + if(CheckBlue()){ + write("It doesn't fit."); + return 0; + } + else return 1; + } + if(base_name(ob) == "/domains/default/obj/vial_orange"){ + if(CheckOrange()){ + write("It doesn't fit."); + return 0; + } + else return 1; + } + write("That doesn't belong in there."); + return 0; +} + +int eventTurnOn(){ + write("Try 'push orange button on generator'"); + return 1; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/obj/gps.c b/lib/domains/default/obj/gps.c new file mode 100644 index 0000000..56db4a0 --- /dev/null +++ b/lib/domains/default/obj/gps.c @@ -0,0 +1,169 @@ +#include <lib.h> +#include <daemons.h> +#include <vendor_types.h> +inherit LIB_ITEM; +mapping Tracked = ([]); +mixed gtmp; + +string LongDesc(){ + string ret; + Tracked = ([]); + if(creatorp(this_player())){ + ret = "This small electronic appliance is designed to "+ + "provide information, if available, regarding your location "+ + "in the world. Commands: coord, prox"; + } + else { + ret = "This is a device creators use to analyze their "+ + "position in relation to the mud."; + } + return ret; +} + +void create(){ + ::create(); + SetKeyName("GPS device"); + SetAdjectives( ({"gps", "global positioning", "system", "small"}) ); + SetId( ({"gps", "device", "appliance"}) ); + SetShort("a GPS device"); + SetLong( (: LongDesc :) ); + SetNoCondition(1); + SetMass(20); + SetVendorType(VT_TREASURE); +} + +void init(){ + ::init(); + add_action("GetCoord","coord"); + add_action("GetProx","prox"); + add_action("GetShell","shell"); + add_action("StartTrack","track"); + add_action("StopTrack","untrack"); +} + +int GetCoord(){ + string ret; + if(!creatorp(this_player())) return 0; + ret = ROOMS_D->GetCoordinates(environment(this_player())); + if(!sizeof(ret) || ROOMS_D->GetGrid(ret)["room"] != + base_name(environment(this_player()))){ + ret = "It seems you are unable to receive positioning "+ + "data about your location at the moment."; + } + else{ + mixed foo = ROOMS_D->GetGrid(ret); + if(foo && creatorp(this_player())){ + ret += " "+identify((foo["room"] || "")); + } + } + write(ret); + return 1; +} + +int GetProx(int i){ + string ret = ""; + int x, y, z; + string coords; + if(!creatorp(this_player())) return 0; + coords = ROOMS_D->GetCoordinates(environment(this_player())); + if(!sizeof(coords) || ROOMS_D->GetGrid(coords)["room"] != + base_name(environment(this_player())) || + sscanf(coords,"%d,%d,%d",x,y,z) != 3){ + ret = "It seems you are unable to receive proximity "+ + "data about your location at the moment."; + } + else{ + if(ROOMS_D->GetGrid(x+","+(y+1)+","+z)["room"]) + ret += "North: "+ROOMS_D->GetGrid(x+","+(y+1)+","+z)["room"]; + if(ROOMS_D->GetGrid(x+","+(y-1)+","+z)["room"]) + ret += "\nSouth: "+ROOMS_D->GetGrid(x+","+(y-1)+","+z)["room"]; + if(ROOMS_D->GetGrid((x+1)+","+y+","+z)["room"]) + ret += "\nEast: "+ROOMS_D->GetGrid((x+1)+","+y+","+z)["room"]; + if(ROOMS_D->GetGrid((x-1)+","+y+","+z)["room"]) + ret += "\nWest: "+ROOMS_D->GetGrid((x-1)+","+y+","+z)["room"]; + if(ROOMS_D->GetGrid((x+1)+","+(y+1)+","+z)["room"]) + ret += "\nNortheast: "+ROOMS_D->GetGrid((x+1)+","+(y+1)+","+z)["room"]; + if(ROOMS_D->GetGrid((x-1)+","+(y+1)+","+z)["room"]) + ret += "\nNorthwest: "+ROOMS_D->GetGrid((x-1)+","+(y+1)+","+z)["room"]; + if(ROOMS_D->GetGrid((x+1)+","+(y-1)+","+z)["room"]) + ret += "\nSoutheast: "+ROOMS_D->GetGrid((x+1)+","+(y-1)+","+z)["room"]; + if(ROOMS_D->GetGrid((x-1)+","+(y-1)+","+z)["room"]) + ret += "\nSouthwest: "+ROOMS_D->GetGrid((x-1)+","+(y-1)+","+z)["room"]; + if(ROOMS_D->GetGrid(x+","+y+","+(z+1))["room"]) + ret += "\nUp: "+ROOMS_D->GetGrid(x+","+y+","+(z+1))["room"]; + if(ROOMS_D->GetGrid(x+","+y+","+(z-1))["room"]) + ret += "\nDown: "+ROOMS_D->GetGrid(x+","+y+","+(z-1))["room"]; + } + write(ret); + return 1; +} + +int StartTrack(string str){ + object mark = to_object(str); + if(!mark || !living(mark)){ + mark = find_player(str); + } + if(!mark){ + write("That living thing could not be found."); + return 1; + } + write("Starting to track "+capitalize(mark->GetKeyName())+"."); + TRACKER_D->AddTrack(mark, this_object()); + Tracked[str] = mark; + return 1; +} + +int StopTrack(string str){ + object mark; + if(!Tracked[str]){ + write("This device wasn't tracking that living thing."); + return 1; + } + write("Stopping the track of "+ + capitalize(Tracked[str]->GetKeyName())+"."); + TRACKER_D->RemoveTrack(mark, this_object()); + Tracked[str] = 0; + return 1; +} + +int ReceiveTrackingData(mapping data){ + object env = environment(); + if(!env) return 0; + tell_object(env, "The GPS device chirps: Tracking data received for "+ + data["object"]->GetShort()+": "+identify(data)); + return 1; +} + +int GetShell(string str){ + mapping Shell = ([]); + mixed all = ({}); + int shell = atoi(str); + int i, max = shell+1; + Shell[0] = room_environment(this_player())->GetNeighbors(); + if(!shell){ + return 1; + } + for(i = 1; i < max; i++){ + Shell[i] = ({}); + foreach(mixed foo in Shell[i-1]){ + object bar; + mixed tmparr = ({}); + catch( bar = load_object(foo) ); + if(bar){ + tmparr = (bar->GetNeighbors() - ({ foo }) ); + if(!sizeof(tmparr)){ + bar->CompileNeighbors(); + tmparr = (bar->GetNeighbors() - ({ foo }) ); + } + } + gtmp = Shell[i-1]; + tmparr = filter(tmparr, (: member_array($1, gtmp) == -1 :) ); + gtmp = all; + Shell[i] += filter(tmparr, (: member_array($1, gtmp) == -1 :) ); + all += Shell[i]; + } + Shell[i] = distinct_array(Shell[i]); + } + write("Rooms at distance "+shell+": "+identify(Shell[shell])); + return 1; +} diff --git a/lib/domains/default/obj/guide.c b/lib/domains/default/obj/guide.c new file mode 100644 index 0000000..171515b --- /dev/null +++ b/lib/domains/default/obj/guide.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_BOOK; + +void create(){ + ::create(); + SetKeyName("administrator's guidebook"); + SetId( ({"guidebook", "book", "guide", "administrators guide", "administrators guidebook"}) ); + SetAdjectives( ({"admin's", "admin", "admins", "administrator", "administrators", "reference"}) ); + SetShort("an Administrator's Guidebook"); + SetLong("This is a reference text for Dead Souls administrators."); + SetNoCondition(1); + SetSource("/doc/guide"); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetTitle("Administrator's Guidebook"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/obj/handbook.c b/lib/domains/default/obj/handbook.c new file mode 100644 index 0000000..b1ca896 --- /dev/null +++ b/lib/domains/default/obj/handbook.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_BOOK; + +void create(){ + ::create(); + SetKeyName("player's handbook"); + SetId( ({"book", "handbook", "players handbook"}) ); + SetAdjectives( ({"player", "players"}) ); + SetShort("a Player's Handbook"); + SetLong("This is a handbook for players. To read it, you must read the chapters in it. For example, 'read chapter 1 in handbook', or 'read index in handbook'"); + SetProperties(([ + "no steal" : 1, + ])); + SetMass(3); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetTitle("The Player's Handbook"); + SetSource("/doc/hbook"); + SetDefaultRead("Try \"read chapter 1 in handbook\" or " + "\"read index in handbook\""); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/obj/javelin_bin.c b/lib/domains/default/obj/javelin_bin.c new file mode 100644 index 0000000..53fab78 --- /dev/null +++ b/lib/domains/default/obj/javelin_bin.c @@ -0,0 +1,35 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("bin"); + SetAdjectives( ({"tall", "metal", "javelin","spear"}) ); + SetId( ({"javelin bin"}) ); + SetShort("a tall metal bin"); + SetLong("This tall container is meant to hold javelins."); + SetInventory(([ + "/domains/town/weap/javelin" : ({ 1200, 10 }), + ])); + SetNoCondition(1); + SetCanClose(0); + SetMass(274); + SetBaseCost("silver",1); + SetMaxCarry(3500); + SetNoClean(1); +} + +void init(){ + ::init(); +} + +mixed CanGet(object ob) { return "The bin does not budge.";} + +int CanReceive(object ob) { + if(!answers_to("javelin",ob)) { + write("This is a bin for javelins only."); + return 0; + } + else return 1; +} diff --git a/lib/domains/default/obj/lever.c b/lib/domains/default/obj/lever.c new file mode 100644 index 0000000..2c8846f --- /dev/null +++ b/lib/domains/default/obj/lever.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; + +void create(){ + ::create(); + SetKeyName("hand grenade spoon"); + SetId(({"lever","spoon"})); + SetAdjectives(({"grenade","hand grenade","metal","small"})); + SetShort("a small metal lever"); + SetLong("This is the fuse lever, or spoon, for a hand grenade."); + SetMass(1); + SetDollarCost(0); + SetVendorType(VT_TREASURE); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/obj/locker.c b/lib/domains/default/obj/locker.c new file mode 100644 index 0000000..1ccae0b --- /dev/null +++ b/lib/domains/default/obj/locker.c @@ -0,0 +1,27 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("locker"); + SetId(({"locker","object"})); + SetAdjectives(({"metal","tall","large"})); + SetShort("a tall metal locker"); + SetLong("This large object is designed to hold "+ + "armor and related accessories."); + SetInventory(([ + "/domains/default/armor/pcannon" : 1, + "/domains/default/armor/scoutsuit" : 1, + "/domains/default/armor/chainmail" : 5, + ])); + SetMass(2000); + SetBaseCost("silver",150); + SetMaxCarry(10000); + SetCanClose(1); + SetClosed(0); + SetPreventGet("The locker does not budge."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/obj/manual.c b/lib/domains/default/obj/manual.c new file mode 100644 index 0000000..8729116 --- /dev/null +++ b/lib/domains/default/obj/manual.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_BOOK; + +void create(){ + ::create(); + SetKeyName("creator's manual"); + SetId( ({"manual", "book", "creators manual"}) ); + SetAdjectives( ({"creator", "creators", "coder", "coders"}) ); + SetShort("a Creator's Manual"); + SetLong("This is a manual for creators and admins. " + "To read it, you must read the chapters in it. For example, \"read " + "chapter 1 in manual\".\n If you are new to coding, you should " + "start with chapter 31."); + SetNoCondition(1); + SetProperties(([ + "no steal" : 1, + ])); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetTitle("The Coder's Manual"); + SetSource("/doc/manual"); + SetDefaultRead("Try \"read chapter 1 in manual\" or " + "\"read index in manual\"\n" + "New creators should especially read the Quick Creation " + "System documentation, starting in chapter 31"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/obj/match.c b/lib/domains/default/obj/match.c new file mode 100644 index 0000000..b47875c --- /dev/null +++ b/lib/domains/default/obj/match.c @@ -0,0 +1,21 @@ +#include <lib.h> + +inherit LIB_MATCH; + +static void create() { + match::create(); + SetKeyName("match"); + SetId("match"); + SetAdjectives( ({ "wooden" }) ); + SetShort("a wooden match"); + SetLong("A wooden match that might light if you strike it."); + SetRadiantLight(2); + SetStrikeChance(50); + SetMinHeat(10); + SetFuelRequired(1); + SetMaxFuel(10); + SetFuelAmount(10); + SetRefuelable(0); + SetMass(5); + SetBurntValue(1); +} diff --git a/lib/domains/default/obj/meter.c b/lib/domains/default/obj/meter.c new file mode 100644 index 0000000..b70e063 --- /dev/null +++ b/lib/domains/default/obj/meter.c @@ -0,0 +1,76 @@ +#include <lib.h> +#include <vendor_types.h> +#include <vision.h> +inherit LIB_ITEM; + +varargs string translate_vision(object ob){ + int vision; + string ret = " "; + if(!ob) vision = this_player()->GetEffectiveVision(); + else vision = ob->GetEffectiveVision(); + switch(vision){ + case 0 : ret = "level 0: blindness.";break; + case 1 : ret = "level 1: too dark.";break; + case 2 : ret = "level 2: dark.";break; + case 3 : ret = "level 3: dim.";break; + case 4 : ret = "level 4: clear.";break; + case 5 : ret = "level 5: light.";break; + case 6 : ret = "level 6: bright.";break; + case 7 : ret = "level 7: too bright.";break; + default : ret = "a mystery."; + } + return ret; +} + +varargs mixed EvaluateRadiantLight(object ob, int report){ + int x = 0; + string rep = ""; + string subrep = ""; + if(!ob) ob = this_player(); + foreach(object guy in get_livings(environment(ob))){ + if(guy->GetRadiantLight()) + rep += guy->GetName()+"'s radiant light is: "+guy->GetRadiantLight()+".\n"; + foreach(object item in all_inventory(guy)){ + x += item->GetRadiantLight(); + if(item->GetRadiantLight()){ + subrep += guy->GetName()+"'s "+item->GetName()+"'s radiant light is: "+ + item->GetRadiantLight()+".\n"; + } + } + } + if(!report) return x; + else return "Livings: \n"+rep+"\nObjects:\n"+subrep; +} + +string DefaultReading(){ + write("This small device is a portable light meter. It tells "+ + "you what the available light is."); + write("The ambient light here is: "+environment(this_player())->GetAmbientLight()); + write("Total radiant light here is: "+EvaluateRadiantLight()); + write("Your vision range is: "+this_player()->GetEffectiveVision(environment(this_player()),1)); + write("\nYour effective vision is "+translate_vision()); + write("\nFull radiance details:\n"+EvaluateRadiantLight(this_player(),1)); + return ""; +} + +varargs mixed eventUse(mixed arg){ + return DefaultReading(); +} + +void create(){ + ::create(); + SetKeyName("light meter"); + SetAdjectives( ({"light"}) ); + SetId( ({"meter", "lightmeter"}) ); + SetShort("a light meter"); + SetLong( (: DefaultReading :) ); + SetProperties(([ + "no steal" : 1, + ])); + SetNoCondition(1); + SetMass(20); + SetVendorType(VT_TREASURE); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/obj/module_cloak.c b/lib/domains/default/obj/module_cloak.c new file mode 100644 index 0000000..5bc23d8 --- /dev/null +++ b/lib/domains/default/obj/module_cloak.c @@ -0,0 +1,167 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +inherit LIB_INSTALL; + +varargs int eventCloak(mixed arg); +varargs int eventDecloak(mixed arg); + +int power = 0; +function f1 = 0; +function f2 = 0; +mapping SendMap = ([]); + +void create(){ + item::create(); + + SetKeyName("data module"); + SetId( ({"module", "cartridge"}) ); + SetAdjectives( ({"data","yautja","stealth"}) ); + SetShort("a Yautja data module"); + SetLong("This is a small cartridge that contains programming intended " + "for a Yautja wrist computer. It appears to have writing on it."); + SetNoCondition(1); + SetMass(1); + SetReads( ([ + "default" : "Stealth module: provides cloaking and decloaking.", + "writing": "Stealth module: provides cloaking and decloaking.", + ]) ); + SetLanguage("Yautja"); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); +} + +varargs int eventDecloak(mixed arg){ + int ret; + string s1,s2; + string *hist = environment(this_object())->GetHist(); + if(!arg) arg = this_player(); + if(!environment() || !(environment()->GetWorn())){ + write("You are not wearing the wrist computer."); + return 1; + } + if(!power){ + write("The computer is not active."); + return 1; + } + //write("%^GREEN%^last command:%^RESET%^ "+arg->GetCurrentCommand()); + arg = arg->GetCurrentCommand(); + if(sscanf(arg,"%s %s",s1,s2) == 2){ + if(s2 == "on" || s2 == "disable"){ + eventCloak(this_player()); + return 1; + } + } + if(!(this_player()->GetInvis())){ + write("Your wrist computer chirps, and nothing happens."); + say(this_player()->GetName()+"'s wrist computer chirps."); + return 1; + } + write("Your wrist computer chirps, and you become visible."); + say(this_player()->GetName()+"'s wrist computer chirps, and "+ + capitalize(this_player()->GetKeyName())+" fades into view."); + this_player()->SetInvis(0); + return 1; +} + +varargs int eventCloak(mixed arg){ + int ret; + string s1,s2; + string *hist = environment(this_object())->GetHist(); + if(!arg) arg = this_player(); + if(!environment() || !(environment()->GetWorn())){ + write("You are not wearing the wrist computer."); + return 1; + } + if(!power){ + write("The computer is not active."); + return 1; + } + //write("%^YELLOW%^last command:%^RESET%^ "+arg->GetCurrentCommand()); + arg = arg->GetCurrentCommand(); + if(sscanf(arg,"%s %s",s1,s2) == 2){ + if(s2 == "off" || s2 == "disable"){ + eventDecloak(this_player()); + return 1; + } + } + if(this_player()->GetInvis()){ + write("Your wrist computer chirps, and nothing happens."); + say(this_player()->GetName()+"'s wrist computer chirps."); + return 1; + } + write("Your wrist computer chirps, and you become transparent."); + say(this_player()->GetName()+"'s wrist computer chirps, and "+nominative(this_player())+ + " fades from view."); + this_player()->SetInvis(1); + return 1; +} + +varargs mixed eventInstall(object what, object where, int auto){ + f1 = (: eventCloak(this_player()) :); + f2 = (: eventDecloak(this_player()) :); + if(!where){ + write("Install it where?"); + return 1; + } + SendMap = ([ + "cloaking" : ([ "function" : f1, "hook" : "cloak" ]), + "decloaking" : ([ "function" : f2, "hook" : "decloak" ]) + ]); + where->eventInstallModule(SendMap,auto ||0); + power = 1; + return 1; +} + +varargs mixed eventUninstall(object what, mixed auto){ + int success; + what->eventUninstallModule(this_object(), auto || 0); + if(this_player() && environment() && environment() == what) + success = this_object()->eventMove(this_player()); + if(success || auto) return 1; + else { + //if(!success) write("The uninstall failed."); + return 0; + } +} + +string Report(){ + string ret = ""; + if(!sizeof(SendMap)) return ret; + foreach(mixed key, mixed val in SendMap){ + ret += "Functionality: "+key+", command: "+val["hook"]+"\n"; + } + return ret; +} + +int eventPowerOff(){ + object whom = this_player(); + object env = environment(); + power = 0; + if(env) env->eventUninstallModule(this_object(),1); + else return 0; + if(!whom) whom = environment(env); + if(!whom) return 0; + else { + if(living(whom)){ + if(whom->GetInvis() && !creatorp(whom)){ + whom->SetInvis(0); + tell_object(whom, "Your wrist computer makes a croaking noise, and you become visible."); + tell_room(environment(whom),whom->GetName()+"'s wrist computer makes a croaking noise, and "+ + capitalize(whom->GetKeyName())+" fades into view.", whom); + } + } + } + return 1; +} + +int eventPowerOn(){ + object env = environment(); + power = 1; + if(env) env->eventInstallModule(SendMap,1); + return 1; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/obj/pass_example.c b/lib/domains/default/obj/pass_example.c new file mode 100644 index 0000000..36b5b2a --- /dev/null +++ b/lib/domains/default/obj/pass_example.c @@ -0,0 +1,67 @@ +/* Please note this info from options.h + * REF_RESERVED_WORD: If this is defined then the word 'ref' can be + * used to pass arguments to functions by reference. Example: + * + * void inc(int ref x) { + * x++; + * } + * + * ... y = 1; inc(ref y); ... + * + * A side effect is that 'ref' cannot be a variable or function name. + * + * Note: ref must be used in *both* places; this is intentional. It protects + * against passing references to routines which don't intend to return values + * through their arguments, and against forgetting to pass a reference + * to a function which wants one (or accidentally having a variable modified!) + */ + +#include <lib.h> + +inherit LIB_ITEM; +mixed globalvar; + +static void create() { + item::create(); + SetKeyName("object"); + SetId( ({ "example", "sample" }) ); + SetAdjectives( ({ "example","sample","pass by reference" }) ); + SetShort("a pass by reference example object"); + SetLong("This object allows you to test passing by reference. " + "When you: \n\n call example->StartPass(1)\n\n\tYou can see that " + "not only has the local variable been changed, but the " + "global variable too, even though there has been no assignment " + "operation to change globalvar to localvar's new value.\n" + "\tThis pass by reference is accomplished by using the \"ref\" " + "keyword. If you need to pass an integer or a string by reference, " + "study how it is done here to understand the process."); + SetNoCondition(1); + SetMass(50); + SetBaseCost(1); +} +void init(){ + ::init(); +} + +mixed PassByRef(mixed ref arg){ + if(intp(arg)) arg++; + else if(stringp(arg)) arg += "localvar"; + else if(mapp(arg)) arg[identify(this_object())] = this_object(); + else if(arrayp(arg) && sizeof(arg)){ + if(stringp(arg[0])) arg += ({ "localvar" }); + else if(intp(arg[0])) arg += ({ 1 }); + else if(objectp(arg[0])) arg += ({ this_object() }); + } + return arg; +} + +mixed StartPass(mixed localvar){ + globalvar = localvar; + write("localvar: "+identify(localvar)); + write("globalvar: "+identify(globalvar)); + flush_messages(); + localvar = PassByRef(ref globalvar); + write("localvar: "+identify(localvar)); + write("globalvar: "+identify(globalvar)); + return 1; +} diff --git a/lib/domains/default/obj/phints.c b/lib/domains/default/obj/phints.c new file mode 100644 index 0000000..7826253 --- /dev/null +++ b/lib/domains/default/obj/phints.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_BOOK; + +void create(){ + ::create(); + SetKeyName("hintbook"); + SetId( ({"book", "hints", "book of hints"}) ); + SetAdjectives( ({"hint", "player", "players"}) ); + SetShort("a Player's Hint Book"); + SetLong("This is a book of hints. To read it, you must read the chapters in it. For example, 'read chapter 1 in hintbook', or 'read index in hintbook'"); + SetProperties(([ + "no steal" : 1, + ])); + SetMass(3); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetTitle("The Player's Hint Book"); + SetSource("/doc/phints"); + SetDefaultRead("Try \"read chapter 1 in hintbook\" or " + "\"read index in hintbook\""); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/obj/pin.c b/lib/domains/default/obj/pin.c new file mode 100644 index 0000000..437491e --- /dev/null +++ b/lib/domains/default/obj/pin.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; + +void create(){ + ::create(); + SetKeyName("pull-pin"); + SetId(({"pin","ring"})); + SetAdjectives(({"pull","grenade","fuse"})); + SetShort("a grenade pin"); + SetLong("This is the pull pin from a hand grenade fuse."); + SetMass(1); + SetDollarCost(0); + SetVendorType(VT_TREASURE); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/obj/pinger.c b/lib/domains/default/obj/pinger.c new file mode 100644 index 0000000..bc5c384 --- /dev/null +++ b/lib/domains/default/obj/pinger.c @@ -0,0 +1,64 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; + +int count = 0; +int interval = 0; +string keepalive = ""; + +void create(){ + ::create(); + + SetKeyName("pinger"); + SetId( ({"pinger"}) ); + SetShort("a pinger"); + SetLong("This thing can be set to periodically output a string, " + "with the purpose of keeping fickle telnet connections up. " + "\nTo set the interval: interval <heartbeats> \n" + "To set the string: vassily <string>" + "\n\nNote: This object is deprecated. Use the command " + "'keepalive' instead."); + SetNoCondition(1); + SetMass(20); + AddSave( ({ "count", "interval", "keepalive" }) ); + set_heart_beat(1); +} + +int SetInterval(string str){ + interval = atoi(str); + if(!intp(interval)){ + write("That is not a valid integer."); + return 1; + } + + write("Interval set to "+interval+" heartbeats."); + return 1; +} + +int SetKeepalive(string str){ + if(!str || str == "") keepalive = "\n"; + else keepalive = str; + write("Keepalive set."); + return 1; +} + +void init(){ + ::init(); + add_action("SetInterval","interval"); + add_action("SetKeepalive","vassily"); +} + +void heart_beat(){ + count++; + if(interval > 0 && count > interval){ + count = 0; + if(living(environment(this_object())) && + true()){ +#ifndef __DSLIB__ + tell_object(environment(this_object()),keepalive); +#else + send_nullbyte(environment(this_object())); +#endif + } + } +} diff --git a/lib/domains/default/obj/rack.c b/lib/domains/default/obj/rack.c new file mode 100644 index 0000000..9e0eca4 --- /dev/null +++ b/lib/domains/default/obj/rack.c @@ -0,0 +1,36 @@ +#include <lib.h> +#include <damage_types.h> + +inherit LIB_SURFACE; +object to; + +void create() { + ::create(); + SetKeyName("rack"); + SetId(({"rack"})); + SetAdjectives(({"knife","metal","fancy","steel","stainless","stainless-steel"})); + SetShort("a weapons rack"); + SetLong("This is a bladed weapons rack here for your combat "+ + "testing convenience."); + SetNoCondition(1); + SetMass(274); + SetBaseCost("silver",50); + SetMaxCarry(5000); + SetInventory(([ + "/domains/default/weap/sharpsword" : ({ 1800, 5 }), + ])); + SetCanClose(0); + SetPreventGet("The rack does not budge."); +} + +int CanReceive(object ob) { + if(ob->GetDamageType() != BLADE) { + write("This is a rack for sword-like weapons only."); + return 0; + } + else return 1; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/obj/reset_button.c b/lib/domains/default/obj/reset_button.c new file mode 100644 index 0000000..c080f56 --- /dev/null +++ b/lib/domains/default/obj/reset_button.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_DUMMY; // These do not show up in desc, but you can look at them +inherit LIB_PRESS; // Makes the item pressable + +object room; + +int eventResetRoom() { + object *livings = get_livings(environment(this_object()),2); + room = environment(this_object()); + livings->eventMove(ROOM_FURNACE); + livings->eventDestruct(); + call_out( (: reload_room, room :), 0 ); + return 1; +} + +static void create() { + dummy::create(); + SetKeyName("button"); + SetId(({"button","button on the wall"})); + SetAdjectives("reset"); + SetShort("a button"); + SetLong("It is a button that you could probably press."); + SetPress((: eventResetRoom :)); +} diff --git a/lib/domains/default/obj/sofa.c b/lib/domains/default/obj/sofa.c new file mode 100644 index 0000000..a8d6ed3 --- /dev/null +++ b/lib/domains/default/obj/sofa.c @@ -0,0 +1,20 @@ +#include <lib.h> + +inherit LIB_BED; + +static void create() { + ::create(); + SetKeyName("sofa"); + SetId("sofa"); + SetAdjectives( ({ "black", "small", "tasteful", "upholstered" }) ); + SetShort("a sofa"); + SetLong("This is a small, plush sofa tastefully upholstered "+ + "in black. It appears designed for sitting on."); + SetMass(1500); + SetDollarCost(15); + SetMaxSitters(2); +} +mixed CanGet(object ob) { return "The sofa does not budge.";} +void init(){ + ::init(); +} diff --git a/lib/domains/default/obj/stargate.c b/lib/domains/default/obj/stargate.c new file mode 100644 index 0000000..bf1f872 --- /dev/null +++ b/lib/domains/default/obj/stargate.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include <daemons.h> +#include "/lib/include/stargate.h" + +inherit LIB_STARGATE; + +int ReadScreen(); + +void create() +{ + ::create(); + SetOrigin("stargate lab", "/domains/default/room/stargate_lab"); + SetRead(([ ({ "screen" }) : (: ReadScreen :) ]) ); + SetItems(([ ({ "screen" }) : "a computer screen which shows the status of the gate network" ]) ); +} + +void init() +{ + ::init(); +} + +int ReadScreen() +{ + write("stargate network status\n"); + write("-----------------------\n"); + write("\n"); + +} diff --git a/lib/domains/default/obj/thing.c b/lib/domains/default/obj/thing.c new file mode 100644 index 0000000..125524f --- /dev/null +++ b/lib/domains/default/obj/thing.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +void create(){ + ::create(); + SetKeyName("generic thing"); + SetId( ({"thing","item","thang","dingus"}) ); + SetAdjectives( ({"generic","sample","template"}) ); + SetShort("a generic thing"); + SetLong("This is an object of indeterminate nature and proportions."); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/obj/torch.c b/lib/domains/default/obj/torch.c new file mode 100644 index 0000000..43c2187 --- /dev/null +++ b/lib/domains/default/obj/torch.c @@ -0,0 +1,25 @@ +#include <lib.h> + +inherit LIB_TORCH; + + +static void create() { + torch::create(); + SetKeyName("torch"); + SetId( ({ "torch", "old torch", "wooden torch" }) ); + SetAdjectives( ({ "old", "wooden" }) ); + SetShort("an old wooden torch"); + SetLong("An old wooden torch with a bit of cloth wrapped around " + "one end and dipped into a flamable substance."); + SetRadiantLight(7); + SetFuelRequired(1); + SetMaxFuel(1000); + SetFuelAmount(1000); + SetRefuelable(1); + SetMass(50); + SetBurntValue(10); + SetClass(10); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/obj/vial_blue.c b/lib/domains/default/obj/vial_blue.c new file mode 100644 index 0000000..b1c6b31 --- /dev/null +++ b/lib/domains/default/obj/vial_blue.c @@ -0,0 +1,70 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +inherit LIB_INSTALL; + +void create(){ + ::create(); + SetKeyName("blue vial"); + SetId( ({"vial"}) ); + SetAdjectives( ({"small","transparent","blue","glowing"}) ); + SetShort("a glowing blue vial"); + SetLong("A small transparent vial filled with a glowing blue fluid."); + SetMass(10); + SetBaseCost("silver",1000); + SetMaxClones(3); + SetNoCondition(1); + SetVendorType(VT_TREASURE); +} + +varargs mixed eventInstall(object what, object where, int auto){ + int ret = this_object()->eventMove(where); + string wat = remove_article(where->GetShort()); + if(ret){ + write("You install "+GetShort()+" into the "+wat+"."); + say(this_player()->GetName()+" installs "+GetShort()+" into "+ + where->GetShort()+"."); + return 1; + } + else { + write("You fail to install it."); + return 0; + } +} + +varargs mixed eventUninstall(object what, mixed auto){ + int success; + object contenv, env = environment(this_object()); + if(!env || base_name(env) != "/domains/default/obj/generator"){ + write("It's not installed."); + return 0; + } + + if(!env || !environment(env) || env == this_player()){ + write("That doesn't seem to be installed anywhere."); + return 0; + } + + contenv = environment(env); + + if(contenv != this_player() && contenv != environment(this_player())){ + write("That's not yours to uninstall."); + return 0; + } + + success = this_object()->eventMove(this_player()); + if(!success){ + write("You fail to uninstall it."); + return 0; + } + else { + write("You uninstall "+GetShort()+" from "+env->GetShort()+"."); + say(this_player()->GetName()+" uninstalls "+GetShort()+" from "+ + possessive(this_player())+" "+env->GetShort()+"."); + return 1; + } +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/obj/vial_orange.c b/lib/domains/default/obj/vial_orange.c new file mode 100644 index 0000000..d2c2b63 --- /dev/null +++ b/lib/domains/default/obj/vial_orange.c @@ -0,0 +1,70 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +inherit LIB_INSTALL; + +void create(){ + ::create(); + SetKeyName("orange vial"); + SetId( ({"vial"}) ); + SetAdjectives( ({"small","transparent","orange","glowing"}) ); + SetShort("a glowing orange vial"); + SetLong("A small transparent vial filled with a glowing orange fluid."); + SetMass(10); + SetBaseCost("silver",1000); + SetMaxClones(3); + SetNoCondition(1); + SetVendorType(VT_TREASURE); +} + +varargs mixed eventInstall(object what, object where, int auto){ + int ret = this_object()->eventMove(where); + string wat = remove_article(where->GetShort()); + if(ret){ + write("You install "+GetShort()+" into the "+wat+"."); + say(this_player()->GetName()+" installs "+GetShort()+" into "+ + where->GetShort()+"."); + return 1; + } + else { + write("You fail to install it."); + return 0; + } +} + +varargs mixed eventUninstall(object what, mixed auto){ + int success; + object contenv, env = environment(this_object()); + if(!env || base_name(env) != "/domains/default/obj/generator"){ + write("It's not installed."); + return 0; + } + + if(!env || !environment(env) || env == this_player()){ + write("That doesn't seem to be installed anywhere."); + return 0; + } + + contenv = environment(env); + + if(contenv != this_player() && contenv != environment(this_player())){ + write("That's not yours to uninstall."); + return 0; + } + + success = this_object()->eventMove(this_player()); + if(!success){ + write("You fail to uninstall it."); + return 0; + } + else { + write("You uninstall "+GetShort()+" from "+env->GetShort()+"."); + say(this_player()->GetName()+" uninstalls "+GetShort()+" from "+ + possessive(this_player())+" "+env->GetShort()+"."); + return 1; + } +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/room/arena.c b/lib/domains/default/room/arena.c new file mode 100644 index 0000000..f4c018a --- /dev/null +++ b/lib/domains/default/room/arena.c @@ -0,0 +1,47 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("the Arena"); + SetLong("You are in a large room with blank cement walls. This room was built so Creators may test their armor, weapons and NPC's in combat. A large steel door is here, which can be used to prevent wimpy creatures from escaping."); + SetItems( ([ + ({"wall","walls"}) : "The walls are smooth and cement.", + ({"floor","ceiling"}) : "The floor and ceiling are, like the walls, made "+ + "of smooth cement." ]) ); + SetInventory(([ + "/domains/default/npc/fighter" : 1, + "/domains/default/obj/locker" : 1, + "/domains/default/npc/dummy" : 1, + "/domains/default/obj/case" : 1, + "/domains/default/obj/abox" : 1, + "/domains/default/obj/javelin_bin" : 1, + "/domains/default/obj/rack" : 1, + ])); + SetExits( ([ + "south" : "/domains/default/room/wiz_corr_east", + ]) ); + SetPlayerKill(1); + + SetDoor("south", "/domains/default/doors/steel_door2.c"); + +} + +int CanReceive(object sneak) { + object *living_stack = get_livings(sneak); + if(!living_stack || !arrayp(living_stack)) living_stack = ({ sneak }); + foreach(object ob in living_stack){ + if(playerp(ob) && !creatorp(ob) && + !member_group(ob,"TEST")) { + message("info","Creator staff only, sorry.", ob); + return 0; + } + } + return 1; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/room/builder_hall.c b/lib/domains/default/room/builder_hall.c new file mode 100644 index 0000000..f84cfd3 --- /dev/null +++ b/lib/domains/default/room/builder_hall.c @@ -0,0 +1,48 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Builders' Lounge"); + SetLong("This is the comfortable lounge where builders can congregate to chat about their work and leave messages for each other on the board. The Adventurers' Guild is north."); + SetProperty("no attack", 1); + SetProperty("nopeer",1); + ob = new("/lib/bboard"); + ob->SetKeyName("chalkboard"); + ob->SetId( ({ "board", "chalkboard", "dusty board", "dusty chalkboard" }) ); + ob->set_board_id("builder_board"); + ob->set_max_posts(30); + ob->SetShort("a dusty chalkboard"); + ob->eventMove(this_object()); + SetItems( ([ + ({"sign"}) : "A sign you can read.", + ]) ); + SetExits( ([ + "north" : "/domains/town/room/adv_guild", + ]) ); + SetInventory(([ + "/domains/default/obj/couch" : 1, + ])); +} + +int CanReceive(object sneak) { + object *living_stack = get_livings(sneak); + if(!living_stack || !arrayp(living_stack)) living_stack = ({ sneak }); + foreach(object ob in living_stack){ + if(playerp(ob) && !builderp(ob) && !present("testchar badge",ob) && + !member_group(ob,"TEST")) { + message("info","Staff only, sorry.", ob); + return 0; + } + } + return 1; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/room/catchtell.c b/lib/domains/default/room/catchtell.c new file mode 100644 index 0000000..4660082 --- /dev/null +++ b/lib/domains/default/room/catchtell.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include <daemons.h> +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("catch_tell room"); + SetLong("This is a room designed to receive certain messages from NPC's. It is largely for debugging purposes, and it is not vital to normal mud operations."); + SetExits(([ + "west" : "/secure/room/network", + ])); + +} +int CanReceive(object ob) { + if( !archp(ob) ){ + message("info","The catch tell room is available only to "+ + "admins, sorry.",ob); + return 0; + } + return 1; +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/room/death.c b/lib/domains/default/room/death.c new file mode 100644 index 0000000..f0354b1 --- /dev/null +++ b/lib/domains/default/room/death.c @@ -0,0 +1,73 @@ +#include <lib.h> +#include <dirs.h> +#include ROOMS_H + +inherit LIB_ROOM; + +string FunkyPic(); +int CheckChat(); +int StartHeart(object ob); + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("off the mortal coil"); + SetLong( (:FunkyPic:) ); + SetObviousExits("no exit"); + set_heart_beat(10); + SetNoModify(1); +} + +void init(){ + ::init(); + add_action("regenerate","regenerate"); + add_action("wander","wander"); + this_object()->CheckChat(); +} + +string FunkyPic(){ + return read_file("/domains/default/etc/death.txt"); +} + +int regenerate(){ + write("With a great rush of matter and energy, you rematerialize "+ + "into a corporeal state, and find yourself in a familiar place..."); + this_player()->eventRevive(); + this_player()->eventMoveLiving(ROOM_START); + return 1; +} + +int wander(){ + write("There is a strange, hollow vibration all around you, and you "+ + "realize that some force is compelling your ethereal form elsewhere..."+ + "you find yourself in a place that is known to you, yet oddly new."); + this_player()->eventMoveLiving(ROOM_START); + return 1; +} + +void heart_beat(){ + tell_room(this_object(), "A voice whispers: \" You may choose to "+ + "regenerate into a new body here.\""); + return; +} + + +int CanRelease(object ob){ + if(userp(ob) && ob->GetGhost() && environment(ob) == this_object()) { + tell_player(ob,"\n%^RED%^Your undead spirit is recalled and as you leave "+ + "the underworld a new body regenerates around you. "+ + "You live again!%^RESET%^\n"); + ob->eventRevive(); + } + return 1; +} + +int CanReceive(object ob){ + if(!living(ob)){ + return 0; + } + return ::CanReceive(ob); +} + + diff --git a/lib/domains/default/room/domains_room.c b/lib/domains/default/room/domains_room.c new file mode 100644 index 0000000..5c593f0 --- /dev/null +++ b/lib/domains/default/room/domains_room.c @@ -0,0 +1,66 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +string LongDesc(){ + string desc = "Immortals come here to visit parts of "+ + "the world they are building. The Creators' Hall is above. "+ + "To visit the Dead Souls "+ + "test and development mud, go west."; + return desc; +} + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Domains Room"); + SetLong("This room provides a convenient access point to various domain start rooms and featured realms."); + SetItems(([ + "Ylsrim" : "This is the entry point for the Ylsrim domain.", + "campus" : "This is the entry point for the campus domain.", + "examples" : "This is the entry point for the examples domain.", + "town" : "This is the entry point for the town domain.", + "cave" : "This is the entry point for the cave domain.", + "praxis" : "This is the entry point for the praxis domain.", + "learning" : "This is the entry point for the tutorial", + ({ "sign" }) : "A sign you can read.", + ])); + SetEnters( ([ + "campus" : "/domains/campus/room/start", + "ylsrim" : "/domains/Ylsrim/room/bazaar", + "examples" : "/domains/examples/room/start.c", + "cave" : "/domains/cave/room/start", + "town" : "/domains/town/room/start", + "learning" : "/domains/learning/room/start", + "praxis" : "/domains/Praxis/square", + ]) ); + SetProperty("no attack", 1); + SetProperty("nopeer",1); + SetExits(([ + "north" : "/domains/default/room/wiz_hall2", + ])); + + SetInventory(([ + ])); + + SetRead("sign", (: load_object(ROOM_ARCH)->SignRead() :) ); +} + +int CanReceive(object ob) { + if(playerp(ob) && !creatorp(ob) && !present("testchar badge",ob) && + !member_group(ob,"TEST")) { + message("info","Creator staff only, sorry.", ob); + return 0; + } + + if(ob->GetRace() == "rodent"){ + message("info","You are repelled by rodenticide.",ob); + return 0; + } + return 1; +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/room/freezer.c b/lib/domains/default/room/freezer.c new file mode 100644 index 0000000..896cbbf --- /dev/null +++ b/lib/domains/default/room/freezer.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetNoClean(1); + SetProperties(([ "login" : ROOM_START ])); + SetShort( "The freezer"); + SetLong( "The local freezer. Go down to leave."); + SetObviousExits("down"); + SetExits( ([ "down" : ROOM_START ]) ); + call_out("clean_room", MAX_NET_DEAD_TIME); + SetNoModify(1); +} + +static void clean_room(){ + object ob; + call_out((: clean_room :), MAX_NET_DEAD_TIME); + foreach(ob in filter(all_inventory(), (: living($1) :))){ + string name = last_string_element(base_name(ob),"/"); + if(!user_exists(name)) continue; + ob->eventDestruct(); + } +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/room/furnace.c b/lib/domains/default/room/furnace.c new file mode 100644 index 0000000..240341a --- /dev/null +++ b/lib/domains/default/room/furnace.c @@ -0,0 +1,10 @@ +#include <lib.h> + +inherit LIB_FURNACE; + +void create() { + furnace::create(); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/room/menagerie.c b/lib/domains/default/room/menagerie.c new file mode 100644 index 0000000..d9435e0 --- /dev/null +++ b/lib/domains/default/room/menagerie.c @@ -0,0 +1,45 @@ +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("The Menagerie"); + SetLong("This is a magical area containing examples of the various " + "races available to creators for their areas. Normally these creatures " + "would not be found all crowded together like this, but a powerful " + "magic keeps them bound here so that mud staff can analyze and test them. " + "There are more creatures to the south, east, and west."); + SetExits( ([ + "south" : "/domains/default/room/menagerie_south", + "east" : "/domains/default/room/menagerie_e", + "west" : "/domains/default/room/menagerie_w", + "up" : "/domains/default/room/wiz_corr_south", + ]) ); + SetInventory(([ + "/domains/default/npc/horse" : 1, + "/domains/default/npc/bird" : 1, + "/domains/default/npc/elephant" : 1, + "/domains/default/npc/bat" : 1, + "/domains/default/npc/newt" : 1, + "/domains/default/npc/lynx" : 1, + "/domains/default/npc/deer" : 1, + "/domains/default/npc/spider" : 1, + "/domains/default/npc/bear" : 1, + "/domains/default/npc/dryad" : 1, + "/domains/default/npc/rat" : 1, + "/domains/default/npc/zookeeper" : 1, + "/domains/default/npc/cow" : 1, + "/domains/default/npc/centaur" : 1, + "/domains/default/npc/gnome" : 1, + "/domains/default/npc/moth" : 1, + "/domains/default/npc/gecko" : 1, + ])); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/room/menagerie_e.c b/lib/domains/default/room/menagerie_e.c new file mode 100644 index 0000000..44691d4 --- /dev/null +++ b/lib/domains/default/room/menagerie_e.c @@ -0,0 +1,32 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("Menagerie, east"); + SetLong("This is the eastern annex of the menagerie."); + SetInventory(([ + "/domains/default/npc/foochy" : 1, + "/domains/default/npc/satyr" : 1, + "/domains/default/npc/slug" : 1, + "/domains/default/npc/unicorn" : 1, + "/domains/default/npc/triffid" : 1, + "/domains/default/npc/snake" : 1, + "/domains/default/npc/sheep" : 1, + "/domains/default/npc/boar" : 1, + "/domains/default/npc/pegasus" : 1, + "/domains/default/npc/giant" : 1, + "/domains/default/npc/lemur" : 1, + "/domains/default/npc/treant" : 1, + ])); + SetExits(([ + "west" : "/domains/default/room/menagerie", + ])); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/room/menagerie_south.c b/lib/domains/default/room/menagerie_south.c new file mode 100644 index 0000000..ab3442e --- /dev/null +++ b/lib/domains/default/room/menagerie_south.c @@ -0,0 +1,37 @@ +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Menagerie Annex"); + SetLong("This area was added to the menagerie to allow a little leg room for creatures that like to wander."); + SetInventory(([ + "/domains/default/npc/chimera" : 1, + "/domains/default/npc/ogre" : 1, + "/domains/default/npc/orc" : 1, + "/domains/default/npc/red_dragon" : 1, + "/domains/default/npc/bacchus" : 1, + "/domains/default/npc/minotaur" : 1, + "/domains/default/npc/goblin" : 1, + "/domains/default/npc/golem" : 1, + "/domains/default/npc/troll" : 1, + "/domains/default/npc/klingon" : 1, + "/domains/default/npc/gargoyle" : 1, + "/domains/default/npc/balrog" : 1, + "/domains/default/npc/kobold" : 1, + "/domains/default/npc/wraith" : 1, + "/domains/default/npc/yattering" : 1, + "/domains/default/npc/gnoll" : 1, + "/domains/default/npc/elemental" : 1, + ])); + SetExits(([ + "north" : "/domains/default/room/menagerie", + ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/room/menagerie_w.c b/lib/domains/default/room/menagerie_w.c new file mode 100644 index 0000000..547a36f --- /dev/null +++ b/lib/domains/default/room/menagerie_w.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("Menagerie, west"); + SetLong("This is the western annex of the menagerie."); + SetInventory(([ + "/domains/default/npc/dwarf" : 1, + "/domains/default/npc/helf" : 1, + "/domains/default/npc/artrell" : 1, + "/domains/default/npc/halfling" : 1, + "/domains/default/npc/nymph" : 1, + "/domains/default/npc/avidryl" : 1, + "/domains/default/npc/faerie" : 1, + "/domains/default/npc/hobbit" : 1, + "/domains/default/npc/pessis" : 1, + "/domains/default/npc/kender" : 1, + "/domains/default/npc/zoe" : 1, + ])); + SetExits(([ + "east" : "/domains/default/room/menagerie", + ])); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/room/pod.c b/lib/domains/default/room/pod.c new file mode 100644 index 0000000..62da2f9 --- /dev/null +++ b/lib/domains/default/room/pod.c @@ -0,0 +1,16 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("the incept pod"); + SetLong("The incept pod. Some objects come here to be created "+ + "and identified. Go down to get out."); + SetExits( ([ "down" : ROOM_START ]) ); +} +int CanReceive(object ob){ + return room::CanReceive(ob); +} diff --git a/lib/domains/default/room/quarantine1.c b/lib/domains/default/room/quarantine1.c new file mode 100644 index 0000000..e9360dc --- /dev/null +++ b/lib/domains/default/room/quarantine1.c @@ -0,0 +1,44 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Disease Lab Prep Room"); + SetLong("This room is designed to repel the spread of diseases that are tested in the room downstairs. It is also where you can get a disease repellent collar, so you may work in the quarantine area without becoming infected. To infect the test subjects use the medical tricorder. To make all of them healthy again, type 'update', which will reset the room. The test subjects are waiting for you below."); + SetExits( ([ + "south" : "/domains/default/room/wiz_corr1", + "down" : "/domains/default/room/quarantine2.c", + ]) ); + SetInventory(([ + "/domains/default/obj/collarchest" : 1, + ])); + + SetProperty("no attack", 1); + +} +int CanReceive(object ob) { + object *inv; + string taxonomy; + + if(inherits(LIB_GERM,ob)) return 0; + + inv = deep_inventory(ob); + foreach(object thing in inv){ + if(inherits(LIB_GERM,thing)) { + write("%^YELLOW%^A parasite has been discovered on your body! It is being automatically removed.%^RESET%^"); + if(taxonomy = thing->GetGermName()) write("%^YELLOW%^Removing: "+taxonomy+".%^RESET%^"); + thing->eventMove(ROOM_FURNACE); + } + } + + return room::CanReceive(); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/room/quarantine2.c b/lib/domains/default/room/quarantine2.c new file mode 100644 index 0000000..69c2a8b --- /dev/null +++ b/lib/domains/default/room/quarantine2.c @@ -0,0 +1,39 @@ +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Disease Lab"); + SetLong("This room is designed for testing the effects and transmissibility of disease. Another testing area is east."); + SetExits( ([ + "east" : "/domains/default/room/quarantine3", + "up" : "/domains/default/room/quarantine1", + ]) ); + SetNoClean(1); + SetInventory(([ + "/domains/default/npc/quarantine/wim" : 1, + "/domains/default/npc/quarantine/rik" : 1, + "/domains/default/npc/quarantine/han" : 1, + "/domains/default/npc/quarantine/tom" : 1, + "/domains/default/npc/quarantine/lex" : 1, + "/domains/default/npc/quarantine/jan" : 1, + "/domains/default/npc/quarantine/ted" : 1, + "/domains/default/npc/quarantine/pip" : 1, + "/domains/default/npc/quarantine/cor" : 1, + "/domains/default/npc/quarantine/kip" : 1, + "/domains/default/npc/quarantine/job" : 1, + "/domains/default/npc/quarantine/ton" : 1 + ])); + AddItem(new("/domains/default/obj/reset_button")); + +} +int CanReceive(object ob) { + return room::CanReceive(); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/room/quarantine3.c b/lib/domains/default/room/quarantine3.c new file mode 100644 index 0000000..9a8e6e0 --- /dev/null +++ b/lib/domains/default/room/quarantine3.c @@ -0,0 +1,37 @@ +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Disease Lab Annex"); + SetLong("This room is designed for testing the effects and transmissibility of disease. Another testing area is west."); + SetExits( ([ + "west" : "/domains/default/room/quarantine2", + ]) ); + SetInventory(([ + "/domains/default/npc/quarantine/nigel" : 1, + "/domains/default/npc/quarantine/graham" : 1, + "/domains/default/npc/quarantine/duncan" : 1, + "/domains/default/npc/quarantine/trevor" : 1, + "/domains/default/npc/quarantine/simon" : 1, + "/domains/default/npc/quarantine/spencer" : 1, + "/domains/default/npc/quarantine/gavin" : 1, + "/domains/default/npc/quarantine/adrian" : 1, + "/domains/default/npc/quarantine/miles" : 1, + "/domains/default/npc/quarantine/edmund" : 1, + "/domains/default/npc/quarantine/wallace" : 1, + "/domains/default/npc/quarantine/lester" : 1, + ])); + SetNoClean(1); + AddItem(new("/domains/default/obj/reset_button")); +} +int CanReceive(object ob) { + return room::CanReceive(); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/room/stargate_lab.c b/lib/domains/default/room/stargate_lab.c new file mode 100644 index 0000000..a46a394 --- /dev/null +++ b/lib/domains/default/room/stargate_lab.c @@ -0,0 +1,49 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_ROOM; + +int SignRead(){ + string list; + list = implode(keys(STARGATE_D->GetStargates()),", "); + write("These are Stargate operation instructions."); + write("The Dead Souls stargate system provides teleportation within " + "the stargate network. To use the stargate network, one finds an " + "idle stargate, then dials the name of some other known stargate. " + "One then enters the outbound stargate, and if things go well, teleportation " + "to the dialed stargate occurs. To travel to Uruk, if that were a " + "valid stargate name, you would: dial uruk\n" + "Once the stargate activates: enter stargate"); + write("Currently available stargates are:"); + write("%^BOLD%^%^YELLOW%^"+list+"%^RESET%^"); + return 1; +} + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Stargate Lab"); + SetLong("This is the test laboratory for the new Dead Souls Stargate system.\n" + "%^BOLD%^%^GREEN%^An instruction sign is here.%^RESET%^"); + SetItems(([ + ({ "sign", "instruction sign", "instructions sign", "instruction", "instructions" }) : "A sign you can read. It appears to be instructions for operating the stargate.", + ])); + SetExits( ([ + "north" : "/domains/default/room/wiz_corr_east2.c", + ]) ); + SetInventory(([ + "/domains/default/obj/stargate" : 1, + ])); + SetRead("sign", (: SignRead() :) ); + SetProperty("no attack", 1); + +} +int CanReceive(object ob) { + return room::CanReceive(); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/room/start.c b/lib/domains/default/room/start.c new file mode 100644 index 0000000..e4a1858 --- /dev/null +++ b/lib/domains/default/room/start.c @@ -0,0 +1,43 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +int tutorial = 0; + +string DoDesc(){ + string desc = "Welcome! To enter the main area, type: %^%^GREEN%^%^enter town%^%^RESET%^%^\n\n"; + string desc2 = "To enter a tutorial area, type: %^%^RED%^%^enter tutorial\n\n%^%^RESET%^%^"; + return desc + ( tutorial ? desc2 : ""); +} + +void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("The start room"); + SetLong( (: DoDesc :)); + SetExits( ([ + "south" : "/domains/default/room/wiz_hall", + ]) ); + SetNoModify(1); + SetCoordinates("5000,5000,0"); + SetItems( ([ + "tutorial" : "A set of rooms to get familiar with this environment.", + "town" : "The main town.", + ]) ); + SetEnters( ([ + //"tutorial" : "/domains/tutorial/room/start", + "town" : "/domains/town/room/start", + ]) ); + SetInventory(([ + "/domains/default/obj/cheatbook" : 1 + ]) ); + if(tutorial){ + AddEnter("tutorial", "/domains/tutorial/room/start"); + } +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/room/telnet_room.c b/lib/domains/default/room/telnet_room.c new file mode 100644 index 0000000..2d59c8c --- /dev/null +++ b/lib/domains/default/room/telnet_room.c @@ -0,0 +1,64 @@ +#include <lib.h> +#include <daemons.h> +#include ROOMS_H + +inherit LIB_ROOM; + +string LoadIP(){ + if(INTERMUD_D->GetMudList()["Dead Souls Dev"]){ + return INTERMUD_D->GetMudList()["Dead Souls Dev"][1]; + } + else return "127.0.0.1"; +} + +string LoadPort(){ + if(INTERMUD_D->GetMudList()["Dead Souls Dev"]){ + return INTERMUD_D->GetMudList()["Dead Souls Dev"][2]; + } + else return ""+query_host_port(); +} + +void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("the telnet room"); + SetLong("From this room, you can attempt "+ + "to connect to Dead Souls Dev. This is useful if you "+ + "need to ask questions but the intermud connection is down. "+ + "Note that being in charmode interferes with input. "+ + "\n\tIf the connection "+ + "fails, email cratylus@comcast.net to ask for help. "+ + "Once you connect to Dead Souls Dev, type \"dcon\" to "+ + "return to your own mud. \n\n"+ + "To connect type \"connect\" \n"+ + "The Creators' Hall annex is west of here."); + SetExits( ([ + "west" : "/domains/default/room/wiz_hall2", + ]) ); + SetNoModify(1); +} + +void init(){ + object ding; + ::init(); + if(!present("telnet_room_client",this_player())){ + ding=new("/secure/obj/tc"); + ding->eventMove(this_player()); + ding->SetConnection(LoadIP()+" "+LoadPort()); + } +} + +int CanRelease(object ob){ + if(present("telnet_room_client",ob)){ + present("telnet_room_client",ob)->eventDestruct(); + } + return 1; +} + +int CanReceive(object ob) { + if(interactive(ob)){ + tell_object(this_object(),ob->GetName()+" is about to enter the telnet room."); + } + return 1; +} diff --git a/lib/domains/default/room/test.c b/lib/domains/default/room/test.c new file mode 100644 index 0000000..25f49aa --- /dev/null +++ b/lib/domains/default/room/test.c @@ -0,0 +1,19 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("The start room"); + SetLong("The default start room. To enter "+ + "a sample set of rooms, go down."); + SetExits( ([ + "down" : "/domains/town/room/road", + ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/room/vacuum.c b/lib/domains/default/room/vacuum.c new file mode 100644 index 0000000..ea26a6a --- /dev/null +++ b/lib/domains/default/room/vacuum.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include ROOMS_H +#include <respiration_types.h> + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("An airless room"); + SetLong("A room whose only purpose is to have nothing to breathe."); + SetRespirationType(R_VACUUM); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/room/void.c b/lib/domains/default/room/void.c new file mode 100644 index 0000000..622a4ac --- /dev/null +++ b/lib/domains/default/room/void.c @@ -0,0 +1,16 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("the void"); + SetLong("The void. Go down to get out."); + SetExits( ([ "down" : ROOM_START ]) ); + SetNoModify(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/room/wiz_corr1.c b/lib/domains/default/room/wiz_corr1.c new file mode 100644 index 0000000..28fdaa1 --- /dev/null +++ b/lib/domains/default/room/wiz_corr1.c @@ -0,0 +1,30 @@ +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Test Labs Corridor West"); + SetLong("This is the west end of main corridor of the test labs. North is the disease lab. The Creators Hall is west of here, and corridor continues east."); + SetExits( ([ + "north" : "/domains/default/room/quarantine1", + "east" : "/domains/default/room/wiz_corr_east", + "west" : "/domains/default/room/wiz_hall", + ]) ); + + SetInventory(([ + ])); + + SetProperty("no attack", 1); + +} +int CanReceive(object ob) { + return room::CanReceive(); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/room/wiz_corr_east.c b/lib/domains/default/room/wiz_corr_east.c new file mode 100644 index 0000000..8c29c79 --- /dev/null +++ b/lib/domains/default/room/wiz_corr_east.c @@ -0,0 +1,31 @@ +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Test Labs Corridor"); + SetLong("This is the main corridor of the test labs. North is the combat arena. South is the menagerie. The corridor continues east and west."); + SetExits( ([ + "south" : "/domains/default/room/wiz_corr_south", + "west" : "/domains/default/room/wiz_corr1", + "north" : "/domains/default/room/arena", + "east" : "/domains/default/room/wiz_corr_east2.c", + ]) ); + SetInventory(([ + ])); + + + SetDoor("north", "/domains/default/doors/steel_door2.c"); + +} +int CanReceive(object ob) { + return room::CanReceive(); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/room/wiz_corr_east2.c b/lib/domains/default/room/wiz_corr_east2.c new file mode 100644 index 0000000..7f8bee1 --- /dev/null +++ b/lib/domains/default/room/wiz_corr_east2.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Test Labs Corridor East"); + SetLong("This is the main corridor of the test labs. The corridor runs east and west. South is the stargate lab."); + SetExits( ([ + "east" : "/domains/default/room/wiz_corr_east3", + "west" : "/domains/default/room/wiz_corr_east", + "south" : "/domains/default/room/stargate_lab.c", + ]) ); + SetProperty("no attack", 1); +} + +int CanReceive(object ob) { + return room::CanReceive(); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/room/wiz_corr_east3.c b/lib/domains/default/room/wiz_corr_east3.c new file mode 100644 index 0000000..9c23fc8 --- /dev/null +++ b/lib/domains/default/room/wiz_corr_east3.c @@ -0,0 +1,44 @@ +#include <lib.h> + +inherit LIB_ROOM; + +int PreExit(mixed args...){ + object *livings; + string duderace = this_player()->GetRace(); + if(sizeof(users()) > 210) return 1; + livings = get_livings(this_object()); + foreach(object living in livings){ + if(base_name(living) == "/domains/default/vehicle/strider" && + previous_object(2) != living ){ + write("The strider is in your way."); + return 0; + } + } + return 1; +} + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Test Labs Corridor East"); + SetLong("This is the main corridor of the test labs. East is the mounted combat arena. The corridor runs west from here."); + SetExits( ([ + "west" : "/domains/default/room/wiz_corr_east2", + ]) ); + AddExit("east", "/domains/default/virtual/arena/5005,4999", (: PreExit :)); + SetInventory(([ + "/domains/default/vehicle/strider" : 1, + ])); + + SetProperty("no attack", 1); + +} +int CanReceive(object ob) { + return room::CanReceive(); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/room/wiz_corr_south.c b/lib/domains/default/room/wiz_corr_south.c new file mode 100644 index 0000000..f140230 --- /dev/null +++ b/lib/domains/default/room/wiz_corr_south.c @@ -0,0 +1,35 @@ +#include <lib.h> + +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Menagerie Corridor"); + SetLong("This short corridor leads down to the menagerie. This corridor has been specially created to repel NPC's, so that the creatures below do not escape. The main test lab corridor is north."); + SetExits( ([ + "north" : "/domains/default/room/wiz_corr_east", + "down" : "/domains/default/room/menagerie.c", + ]) ); + + SetInventory(([ + ])); + +} +int CanReceive(object ob) { + //if(living(ob) && !creatorp(ob) && !present("testchar badge",ob)) { + // message("info","Creator staff only, sorry.", ob); + // return 0; + // } + if(living(ob) && !interactive(ob)){ + message("info","NPC's not allowed, sorry.", ob); + return 0; + } + return room::CanReceive(ob); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/room/wiz_hall.c b/lib/domains/default/room/wiz_hall.c new file mode 100644 index 0000000..60d54da --- /dev/null +++ b/lib/domains/default/room/wiz_hall.c @@ -0,0 +1,99 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; +int ds; + +string LongDesc(){ + string desc = "Immortals come here to communicate with each other about "+ + "the world they are building. The default start room is "+ + "north. The Arch Room is south."+ + (!(ds) ? " To visit the Dead Souls "+ + "test and development mud, visit the upstairs annex." : "")+ + " The test lab facilities are east."; + desc += "\nA sign reads: "+load_object(ROOM_ARCH)->SignRead(); + return desc; +} + +static void create() { + object ob; + room::create(); + if(mud_name() == "Dead Souls"){ + ds = 1; + } + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Creators' Hall"); + SetLong( (: LongDesc :) ); + SetProperty("no attack", 1); + SetProperty("nopeer",1); + ob = new("/lib/bboard"); + ob->SetKeyName("chalkboard"); + ob->SetId( ({ "board", "chalkboard", "dusty board", "dusty chalkboard" }) ); + ob->set_board_id("immortal_board"); + ob->set_max_posts(30); + ob->SetShort("a dusty chalkboard"); + ob->eventMove(this_object()); + SetInventory(([ + "/domains/default/npc/tree" : ({ 10, 1 }), + "/domains/default/obj/chest" : 1 ])); + SetItems( ([ + ({"sign"}) : "A sign you can read.", + ]) ); + SetExits( ([ + "south" : "/secure/room/arch", + "north" : "/domains/default/room/start", + "east" : "/domains/default/room/wiz_corr1", + "up" : "/domains/default/room/wiz_hall2.c", + ]) ); + SetRead("sign", (: load_object(ROOM_ARCH)->SignRead() :) ); +} + +int CanReceive(object sneak) { + object *living_stack = get_livings(sneak); + if(!living_stack || !arrayp(living_stack)) living_stack = ({ sneak }); + foreach(object ob in living_stack){ + if(living(ob) && !creatorp(ob) && + base_name(ob) != "/domains/default/npc/tree" && + base_name(ob) != "/secure/npc/arch_wraith" && + base_name(ob) != "/domains/default/npc/drone3" && + base_name(ob) != "/secure/obj/floodmapper" && + !member_group(ob,"TEST")) { + message("info","Creator staff only, sorry.", ob); + return 0; + } + } + return ::CanReceive(sneak); +} + +int eventReceiveObject(object ob){ + string race = ob->GetRace(); + int ret = ::eventReceiveObject(ob); + if(!ret) return 0; + if(race && race == "orc"){ + ob->eventPrint("Welcome to our inclusive halls, proud orc!"); + } + if(ob->GetInvis()){ + tell_room(this_object(), capitalize(ob->GetKeyName())+ + " enters invisibly.", ({ ob }) ); + ob->eventPrint("%^BOLD%^%^RED%^Your invisible entry has "+ + "been announced.%^RESET%^"); + } + return ret; +} + +int eventReleaseObject(object ob){ + int ret = ::eventReleaseObject(ob); + if(!ret) return 0; + if(ob->GetInvis()){ + tell_room(this_object(), capitalize(ob->GetKeyName())+ + " exits invisibly.", ({ ob }) ); + ob->eventPrint("%^BOLD%^%^RED%^Your invisible exit has "+ + "been announced.%^RESET%^"); + } + return ret; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/room/wiz_hall2.c b/lib/domains/default/room/wiz_hall2.c new file mode 100644 index 0000000..52dfc25 --- /dev/null +++ b/lib/domains/default/room/wiz_hall2.c @@ -0,0 +1,57 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; +int ds; + +static void create() { + object ob; + room::create(); + if(mud_name() == "Dead Souls"){ + ds = 1; + } + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Creators' Hall Upstairs"); + SetLong("This is the upstairs annex of the Creators' Hall. East is the telnet room where you can connect to the Dead Souls test and development mud. South is the domains room, where you can conveniently visit featured domains or realms. The main hall is below."); + SetProperty("no attack", 1); + SetProperty("nopeer",1); + ob = new("/lib/bboard"); + ob->SetKeyName("chalkboard"); + ob->SetId( ({ "board", "chalkboard", "dusty board", "dusty chalkboard" }) ); + ob->set_board_id("immortal_board"); + ob->set_max_posts(30); + SetShort("Creators' Hall West Wing"); + ob->eventMove(this_object()); + SetItems( ([ + ({"sign"}) : "A sign you can read.", + ]) ); + SetExits( ([ + "south" : "/domains/default/room/domains_room", + "down" : "/domains/default/room/wiz_hall", + "east" : "/domains/default/room/telnet_room.c", + ]) ); + if(!ds){ + } + SetInventory(([ + ])); + + SetRead("sign", (: load_object(ROOM_ARCH)->SignRead() :) ); +} + +int CanReceive(object ob) { + if(playerp(ob) && !creatorp(ob) && + !member_group(ob,"TEST")) { + message("info","Creator staff only, sorry.", ob); + return 0; + } + + if(ob->GetRace() == "rodent"){ + message("info","You are repelled by rodenticide.",ob); + return 0; + } + return 1; +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/vehicle/hoverpod.c b/lib/domains/default/vehicle/hoverpod.c new file mode 100644 index 0000000..423cde7 --- /dev/null +++ b/lib/domains/default/vehicle/hoverpod.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include <position.h> + +inherit LIB_VEHICLE; + +static void create() { + vehicle::create(); + SetKeyName("hoverpod"); + SetId(({"pod", "vehicle","transport"})); + SetAdjectives(({"small","shiny","cramped","metallic","hovering"})); + SetShort("a small hoverpod"); + SetLong("This is a shiny metallic sphere about 1.5 meters across, designed for containing " + "an occupant and their stuff in its cramped interior and providing transportation."); + SetVehicleInterior("This is the cramped interior of a shiny sphere used for " + "transportation. Since it hovers, you can use the command \"fly\" to get " + "around with it, like: fly north"); + SetRace("vehicle"); + SetStat("strength", 50); + SetPosition(POSITION_FLYING); + SetMelee(0); + SetNoClean(1); + SetMount(1); + SetMountStyle("driven"); + SetVisibleRiders(0); + SetOpacity(0); + SetMaxHealthPoints(20); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/vehicle/strider.c b/lib/domains/default/vehicle/strider.c new file mode 100644 index 0000000..dbc6362 --- /dev/null +++ b/lib/domains/default/vehicle/strider.c @@ -0,0 +1,63 @@ +#include <lib.h> + +inherit LIB_VEHICLE; + +string ReadInstructions(){ + string ret = "To travel, use the \"drive\" command, for example: drive east\n"+ + "To have the mech do something with its robotic arms, use the following syntax:\n"+ + "direct mech to get boulder\n"+ + "direct mech to kill orc\n\n"; + if(environment(this_player()) == this_object()){ + return ret; + } + else return "You can read no such thing from here."; +} + +static void create() { + vehicle::create(); + SetKeyName("strider"); + SetId(({"landstrider","walker","scout","columbu","mech"})); + SetAdjectives(({"landstrider","walker","scout","columbu","strider","class"})); + SetShort("a landstrider mech"); + SetLong("This is a Columbu class scout vehicle consisting of " + "a human-sized transparent ball turret mounted on two large birdlike legs " + "with two robotic arms on each side for manipulation and combat. " + "Though technically a \"scout\" class mech, it is two meters tall " + "and ballistic plated, and not to be trifled " + "with by meat-based creatures."); + SetVehicleInterior("This is the interior of a highly advanced military mechanized " + "reconaissance vehicle. There are instructions here you can read."); + AddItem("instructions","Some documentation on the operation of this mech."); + AddItem(({"landstrider","walker","scout","columbu","mech","here"}), + "This is the interior of a highly advanced military mechanized " + "reconaissance vehicle. There are instructions here you can read."); + SetRead("instructions", (: ReadInstructions :)); + SetRace("strider"); + SetClass("fighter"); + SetLevel(10); + SetMelee(1); + SetMount(1); + SetMountStyle("driven"); + SetVisibleRiders(0); + SetOpacity(0); + SetNoClean(1); + SetPacifist(0); + SetNoCondition(1); +} + +void init(){ + ::init(); + add_action("DirectMech","direct"); +} + +mixed DirectMech(string str){ + string what, cmd; + int i = sscanf(str,"%s to %s",what, cmd); + if(i != 2) i = sscanf(str,"%s %s",what, cmd); + if(i != 2 || !answers_to(what,this_object())) return 0; + if(environment(this_player()) == this_object()){ + write("You enter the commands into mech."); + call_out("eventForce", 2, cmd); + return 1; + } +} diff --git a/lib/domains/default/virtual/arena.c b/lib/domains/default/virtual/arena.c new file mode 100644 index 0000000..a4cb7c5 --- /dev/null +++ b/lib/domains/default/virtual/arena.c @@ -0,0 +1,149 @@ +#include <lib.h> +#include <dirs.h> +#include <virtual.h> +#include <position.h> + +inherit LIB_VIRT_LAND; + +static private int XPosition, YPosition; + +int max_north = 4999; +int max_south = 4989; +int max_east = 5015; +int max_west = 5005; + +varargs void SetLongAndItems(int x, int y, int z); + +varargs int LimitTravel(int requested, int maximum, int lessthan){ + if(lessthan && requested < maximum) return maximum; + else if(lessthan && requested > maximum) return requested; + else if(requested > maximum) return maximum; + else return requested; +} + +#if 0 +int PreExit(mixed arg1, mixed arg2){ + object ob = this_player(); + if(!ob) return 0; + if(ob->GetPosition() != POSITION_FLYING){ + write("You are not flying!"); + return 0; + } + return 1; +} +#endif + +varargs static void create(int x, int y) { + string n, s, e, w; + string ne, nw, se, sw; + string fly; + + SetNoReplace(1); + virt_land::create(); + XPosition = x; + YPosition = y; + SetClimate("temperate"); + SetAmbientLight(30); + SetLongAndItems(x, y); + SetShort("a flat plain"); + if( x == max_east ) e = "arena/" + (x) + "," + y; + else e = "arena/" + (x+1) + "," + y; + if( x == max_west ) w = "arena/" + (x) + "," + y; + else w = "arena/" + (x-1) + "," + y; + if( y == max_north ) n = "arena/" + x + "," + (y); + else n = "arena/" + x + "," + (y+1); + if( y == max_south ) s = "arena/" + x+ "," + (y); + else s = "arena/" + x + "," + (y-1); + //fly = "sky/" + x + "," + y + "," + 1; + + nw = "arena/" + LimitTravel(x - 1, max_west, 1) + "," + LimitTravel(y+1, max_north); + ne = "arena/" + LimitTravel(x + 1, max_east) + "," + LimitTravel(y+1, max_north); + sw = "arena/" + LimitTravel(x - 1, max_west, 1) + "," + LimitTravel(y-1, max_south, 1); + se = "arena/" + LimitTravel(x + 1, max_east) + "," + LimitTravel(y-1, max_south, 1); + + //SetFlyRoom(__DIR__+fly); + SetSkyDomain("town"); + + SetGoMessage("You can't travel in that direction."); + if( n ) AddExit("north", __DIR__ + n); + if( s ) AddExit("south", __DIR__ + s); + if( e ) AddExit("east", __DIR__ + e); + if( w ) AddExit("west", __DIR__ + w); + if( ne ) AddExit("northeast", __DIR__ + ne); + if( nw ) AddExit("northwest", __DIR__ + nw); + if( se ) AddExit("southeast", __DIR__ + se); + if( sw ) AddExit("southwest", __DIR__ + sw); + + //AddExit("up", __DIR__ + "sky/"+x+","+y+",1", (: PreExit :) ); + //AddExit("up", __DIR__ + "sky/"+x+","+y+",1", (: PreExit :) ); + + if(y == max_south){ + RemoveExit("south"); + RemoveExit("southeast"); + RemoveExit("southwest"); + } + if(y == max_north){ + RemoveExit("north"); + RemoveExit("northeast"); + RemoveExit("northwest"); + } + if(x == max_west){ + RemoveExit("west"); + RemoveExit("northwest"); + RemoveExit("southwest"); + } + if(x == max_east){ + RemoveExit("east"); + RemoveExit("northeast"); + RemoveExit("southeast"); + } + if(x == 5005 && y == 4999){ + RemoveExit("west"); + AddExit("west","/domains/default/room/wiz_corr_east3"); + AddItem("sign" , "This is a sign planted on the ground."); + SetRead( ({"sign"}) , "Wiz labs west of here."); + } +} + +varargs void SetLongAndItems(int x, int y, int z) { + mapping inv, items; + string str; + ::SetLongAndItems(x, y, z); + + inv = ([]); + str = "You are on a large flat plain, bordered on all sides " + "by stone walls, forming a large arena for heavy weapons and " + "mounted combat."; + if(query_night()) str += " The stars of the night sky glitter overhead."; + if(x == max_west && y != max_north) str += " A stone wall prevents further travel west."; + if(x == max_east) str += " A stone wall prevents further travel east."; + if(y == max_south ) str += " A stone wall prevents further travel south."; + if(y == max_north) str += " A stone wall prevents further travel north."; + if(x == max_west && y == max_north) str += "\n%^GREEN%^There is a sign here you can read.%^RESET%^"; + + SetItems( ([ "arena" : "A place of violent death and great destruction.", + ]) ); + + if(y == max_north) { + AddItem( ({ "rock wall","wall","stone wall"}), + "This vast stone wall prevents further travel north." ); + } + else if(y == max_south) { + AddItem( ({ "rock wall","wall","stone wall"}), + "This vast stone wall prevents further travel south." ); + } + + if(x == max_east) { + AddItem( ({ "rock wall","wall","stone wall"}), + "This vast stone wall prevents further travel east." ); + } + if(x == max_west) { + AddItem( ({ "rock wall","wall","stone wall"}), + "This vast stone wall prevents further travel west." ); + } + AddItem( ({ "walls","rock walls","stone walls" }), + "Large walls form the bounds of this killing field." ); + SetLong(str); + SetDayLight(30); + SetNightLight(30); +} diff --git a/lib/domains/default/virtual/server.c b/lib/domains/default/virtual/server.c new file mode 100644 index 0000000..c1282b6 --- /dev/null +++ b/lib/domains/default/virtual/server.c @@ -0,0 +1,20 @@ +mixed compile_object(string file) { + string *path; + object ob; + int x, y, z, elements; + if(grepp(file, "/user_") || grepp(file, "/object_")){ + ob = new("/domains/default/virtual/void"); + if(!ob){ + return "No void room available."; + } + return ob; + } + path = explode(file, "/"); + if( file_size(__DIR__ + path[3] + ".c") < 1 ) return "bad file"; + if( (elements = sscanf(path[4], "%d,%d,%d", x, y, z)) != 3 ) { + if( (elements = sscanf(path[4], "%d,%d", x, y)) != 2 ) return "missing comma"; + } + if( elements == 2 && !(ob = new(__DIR__ + path[3], x, y)) ) return "failed to compile"; + else if( elements == 3 && !(ob = new(__DIR__ + path[3], x, y, z)) ) return "failed to compile"; + return ob; +} diff --git a/lib/domains/default/virtual/sky.c b/lib/domains/default/virtual/sky.c new file mode 100644 index 0000000..35a948e --- /dev/null +++ b/lib/domains/default/virtual/sky.c @@ -0,0 +1,139 @@ +#include <lib.h> +#include <dirs.h> +#include <virtual.h> + +inherit LIB_VIRT_SKY; + +static private int XPosition, YPosition, ZPosition; + +varargs void SetLongAndItems(int x, int y, int z); + +varargs int LimitTravel(int requested, int maximum, int lessthan){ + if(lessthan && requested < maximum) return maximum; + else if(lessthan && requested > maximum) return requested; + else if(requested > maximum) return maximum; + else return requested; +} + +varargs static void create(int x, int y, int z) { + string n, s, e, w, u, d; + string ne, nw, se, sw; + + int max_north = 10; + int max_south = 1; + int max_east = 10; + int max_west = 1; + int max_up = 10; + int max_down = 0; + + SetNoReplace(1); + virt_sky::create(); + XPosition = x; + YPosition = y; + ZPosition = z; + SetClimate("temperate"); + SetAmbientLight(30); + SetLongAndItems(x, y, z); + SetShort("The sky above a flat plain"); + if( x == max_east ) e = "sky/" + (x) + "," + y + "," + z; + else e = "sky/" + (x+1) + "," + y + "," + z; + if( x == max_west ) w = "sky/" + (x) + "," + y + "," + z; + else w = "sky/" + (x-1) + "," + y + "," + z; + if( y == max_north ) n = "sky/" + x + "," + (y) + "," + z; + else n = "sky/" + x + "," + (y+1) + "," + z; + if( y == max_south ) s = "sky/" + x+ "," + (y) + "," + z; + else s = "sky/" + x + "," + (y-1) + "," + z; + if( z == max_up ) u = "sky/" + x + "," + y + "," + (z); + else u = "sky/" + x + "," + y + "," + (z+1); + if( z == max_down ) d = "sky/" + x+ "," + (y) + "," + z; + else d = "sky/" + x + "," + y + "," + (z-1); + + nw = "sky/" + LimitTravel(x - 1, max_west, 1) + "," + LimitTravel(y+1, max_north)+ "," + z; + ne = "sky/" + LimitTravel(x + 1, max_east) + "," + LimitTravel(y+1, max_north)+ "," + z; + sw = "sky/" + LimitTravel(x - 1, max_west, 1) + "," + LimitTravel(y-1, max_south, 1)+ "," + z; + se = "sky/" + LimitTravel(x + 1, max_east) + "," + LimitTravel(y-1, max_south, 1)+ "," + z; + + SetGoMessage("You can't travel in that direction."); + + if( n ) AddExit("north", __DIR__ + n); + if( s ) AddExit("south", __DIR__ + s); + if( e ) AddExit("east", __DIR__ + e); + if( w ) AddExit("west", __DIR__ + w); + if( u ) AddExit("up", __DIR__ + u); + if( d ) AddExit("down", __DIR__ + d); + if( ne ) AddExit("northeast", __DIR__ + ne); + if( nw ) AddExit("northwest", __DIR__ + nw); + if( se ) AddExit("southeast", __DIR__ + se); + if( sw ) AddExit("southwest", __DIR__ + sw); + + if(z == 1){ + RemoveExit("down"); + AddExit("down", __DIR__ + "arena/" + x + "," + y); + } + +#if 1 + if(y == 1){ + RemoveExit("south"); + RemoveExit("southeast"); + RemoveExit("southwest"); + } + else if(y == 10){ + RemoveExit("north"); + RemoveExit("northeast"); + RemoveExit("northwest"); + } + if(x == 1){ + RemoveExit("west"); + RemoveExit("northwest"); + RemoveExit("southwest"); + } + if(x == 10){ + RemoveExit("east"); + RemoveExit("northeast"); + RemoveExit("southeast"); + } +#endif +} + +varargs void SetLongAndItems(int x, int y, int z) { + mapping inv, items; + string str; + ::SetLongAndItems(x, y, z); + + inv = ([]); + str = "You are in the air above a large flat plain, bordered on all sides " + "by stone walls, forming a large arena for heavy weapons and " + "mounted combat."; + if(query_night()) str += " The stars of the night sky glitter overhead."; + if(x == 1) str += " A stone wall prevents further travel west."; + if(x == 10) str += " A stone wall prevents further travel east."; + if(y == 1) str += " A stone wall prevents further travel south."; + if(y == 10) str += " A stone wall prevents further travel north."; + if(x == 5 && y == 1) str += "\n%^GREEN%^There is a sign here you can read.%^RESET%^"; + + SetItems( ([ "arena" : "A place of violent death and great destruction.", + ]) ); + + if(y == 10) { + AddItem( ({ "rock wall","wall","stone wall"}), + "This vast stone wall prevents further travel north." ); + } + else if(y == 1) { + AddItem( ({ "rock wall","wall","stone wall"}), + "This vast stone wall prevents further travel south." ); + } + + if(x == 10) { + AddItem( ({ "rock wall","wall","stone wall"}), + "This vast stone wall prevents further travel east." ); + } + if(x == 1) { + AddItem( ({ "rock wall","wall","stone wall"}), + "This vast stone wall prevents further travel west." ); + } + AddItem( ({ "walls","rock walls","stone walls" }), + "Large walls form the bounds of this killing field." ); + SetLong(str); + SetDayLight(30); + SetNightLight(30); +} diff --git a/lib/domains/default/virtual/void.c b/lib/domains/default/virtual/void.c new file mode 100644 index 0000000..9345f5f --- /dev/null +++ b/lib/domains/default/virtual/void.c @@ -0,0 +1,17 @@ +#include <lib.h> +#include <dirs.h> +#include ROOMS_H +#include <virtual.h> +#include <position.h> + +inherit LIB_VIRT_LAND; + +varargs static void create(int x, int y) { + SetNoReplace(1); + virt_land::create(); + SetClimate("temperate"); + SetAmbientLight(30); + SetLong("A featureless void."); + SetShort("an empty place"); + AddExit("down", ROOM_START); +} diff --git a/lib/domains/default/weap/357pistol.c b/lib/domains/default/weap/357pistol.c new file mode 100644 index 0000000..a7ed609 --- /dev/null +++ b/lib/domains/default/weap/357pistol.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_FIREARM; + +void create(){ + ::create(); + SetKeyName("gun"); + SetId(({"gun","pistol","piece","revolver"})); + SetAdjectives(({".357","357","magnum"})); + SetShort("a .357 magnum revolver"); + SetLong("This is a thick, heavy chunk of weaponry that fires some very "+ + "serious rounds. Bullets are loaded individually into it, and they, along with spent "+ + "shells, remain in the cylinder until unloaded."); + SetCaliber(357); + SetFirearmType("revolver"); + SetFirearmName("revolver"); + SetAmmoType("magnum"); + SetMaxAmmo(6); + SetMass(20); + SetBaseCost("silver", 1200); + SetVendorType(VT_WEAPON); + SetMagnum(30); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/weap/9mil.c b/lib/domains/default/weap/9mil.c new file mode 100644 index 0000000..9991fad --- /dev/null +++ b/lib/domains/default/weap/9mil.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_PISTOL; + +void create(){ + ::create(); + SetKeyName("gun"); + SetId(({"gun","pistol"})); + SetAdjectives(({"9mm","automatic","9 millimeter","semiautomatic"})); + SetShort("a 9 millimeter semiautomatic pistol"); + SetLong("This is a large, semiautomatic pistol that fires 9mm rounds. It is "+ + "a heavy, serious-looking weapon."); + SetMillimeter(9); + SetFirearmType("auto"); + SetAmmoType("acp"); + SetMass(30); + SetBaseCost("silver",900); + SetVendorType(VT_WEAPON); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/weap/brush.c b/lib/domains/default/weap/brush.c new file mode 100644 index 0000000..29ca1bc --- /dev/null +++ b/lib/domains/default/weap/brush.c @@ -0,0 +1,20 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; +static void create(){ + item::create(); + SetKeyName("brush"); + SetId( ({ "brush" }) ); + SetAdjectives( ({ "bath","shower","wood","wooden" }) ); + SetShort("a shower brush"); + SetLong("This is a long wooden brush with soft bristles "+ + "at the end, designed to assist in reaching "+ + "tough-to-scrub areas while bathing."); + SetVendorType(VT_WEAPON); + SetClass(10); + SetMass(100); + SetWeaponType("blunt"); + SetDamageType(BLUNT); +} diff --git a/lib/domains/default/weap/carving_knife.c b/lib/domains/default/weap/carving_knife.c new file mode 100644 index 0000000..2c401f0 --- /dev/null +++ b/lib/domains/default/weap/carving_knife.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + + +static void create() { + item::create(); + SetKeyName("carving knife"); + SetId( ({ "knife"})); + SetAdjectives( ({ "serrated","sharp","razor sharp","steel","hefty","stainless","carving"})); + SetShort("a serrated, 8-inch carving knife"); + SetLong("This is a serrated, 8-inch carving knife. This razor sharp "+ + "knife has been forged from molded and hammered high-carbon "+ + "stainless steel. It is solid, hefty, and well-balanced. "+ + "This is a dangerous knife, and can be considered a very "+ + "deadly weapon."); + SetMass(50); + SetVendorType(VT_WEAPON); + SetClass(30); + SetDamageType(KNIFE); + SetWeaponType("knife"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/default/weap/grenade.c b/lib/domains/default/weap/grenade.c new file mode 100644 index 0000000..ab39d47 --- /dev/null +++ b/lib/domains/default/weap/grenade.c @@ -0,0 +1,157 @@ +#include <lib.h> +#include <vendor_types.h> +#include <damage_types.h> +inherit LIB_ITEM; +inherit LIB_PULL; +string pin_desc(); +string lev_desc(); +int detonated; +int count, armed; +string *limbs,domain; +void analyze(string butt); +int HitLivings(object munch); +int radius = 0; +object *whom; + +void create(){ + item::create(); + SetKeyName("concussion hand grenade"); + sscanf(base_name(this_object()),"/domains/%s/%*s",domain); + SetId( ({"grenade","hand grenade","flash-bang grenade","concussion grenade"}) ); + SetAdjectives( ({"military","pineapple"}) ); + SetShort("a hand grenade"); + SetLong("This is an olive-green military issue hand grenade. It is about the "+ + "size of an apple, and its round exterior is made of smooth metal. The "+ + "grenade's fuse consists of a short metal lever and a round pull-pin. "); + SetMass(20); + SetDollarCost(10); + SetVendorType(VT_WEAPON); + AddItem(({"pull pin","pull-pin","pin"}),"This is a round, metal pin, evidently designed for pulling."); + AddItem(({"lever","metal lever"}),"This lever appears to be part of the fuse mechanism."); + AddItem( ({"fuse","fuse mechanism"}) , "This fuse mechanism controls the arming of the grenade."); + count=5; + detonated=0; +} +void init(){ + if(armed){ + set_heart_beat(1); + if(detonated==1) this_object()->eventDestruct(); + } +} + +mixed CanPull(object who, string target) { + if(!environment() || environment() != who ){ + return "#You do not have the grenade."; + } + if(answers_to(target,this_object())){ + return "#You cannot pull that."; + } + if(armed){ + return "#It is already armed."; + } + if(!GetItem(target)){ + return "#That's not on the grenade."; + } + return 1; +} + +mixed eventPull(object who, string target) { + string *tmpid; + if(!environment() || (this_player() && environment() != this_player())){ + write("You are not holding it."); + return 1; + } + if(target =="pin" || target == "pull-pin"){ + tmpid = GetAdjectives(); + write("You pull the grenade's pin.\n"); + say(this_player()->GetName()+" pulls the pin from a hand grenade.\n"); + new("/domains/"+domain+"/obj/pin")->eventMove(this_player()); + new("/domains/"+domain+"/obj/lever")->eventMove(this_player()); + SetShort("a live hand grenade"); + SetLong("This is an olive-green military issue hand grenade. It is about the "+ + "size of an apple, and its round exterior is made of smooth metal. The pin and "+ + "spoon are missing from the fuse mechanism, indicating the grenade is live "+ + "and will detonate very soon."); + AddItem(({"lever","metal lever"}),"The grenade is armed. The fuse lever is no longer on the grenade."); + AddItem(({"pull pin","pull-pin","pin"}),"The grenade is armed. There is no pin in the fuse."); + armed = 1; + set_heart_beat(1); + SetAdjectives(tmpid + ({"armed","live","hissing"})); + return 1; + } + write("Nothing happens."); + return 1; +} +void heart_beat(){ + count--; + if(detonated==1) this_object()->eventDestruct(); + if(count < 0){ + this_object()->detonate(); + return; + } + if(interactive(environment())){ + tell_object(environment(), "You are holding a live hand grenade."); + return; + } + tell_object(environment(),"You hear a low hissing sound."); + tell_object(environment(environment()), environment()->GetName()+" is holding a live hand grenade."); +} +int detonate(){ + object ob; + string *stuffs; + int num; + ob = environment(this_object()); + if(living(ob)){ + stuffs=ob->GetLimbs(); + tell_object(ob, "\nKABOOM! You are torn to pieces by your hand grenade!\n"); + tell_room(environment(ob), "\nKABOOM! "+ob->GetName()+" is torn to pieces by "+ + possessive(ob)+" hand grenade!\n",ob); + detonated=2; + foreach(string limb in stuffs){ + if(limb != "head" && limb != "torso" && limb != "neck") ob->RemoveLimb(limb,this_object()); + } + ob = environment(ob); + } + if(detonated !=2) tell_room(environment(this_object()), "\nKABOOM! The grenade detonates!\n"); + if(!sizeof(get_livings(ob))) ob = environment(ob); + if(ob && sizeof(whom = scramble_array(get_livings(ob)[0..12]))){ + //tc("whom: "+identify(whom)); + foreach(object victim in whom){ + this_object()->HitLivings(victim); + } + } + this_object()->eventDestruct(); + return 1; +} + +void analyze(string str){ + string tmp,tmp2; + sscanf(str,"%s#%s",tmp,tmp2); + if(tmp="/lib/corpse"){ + filter(deep_inventory(find_object(str)), (: $1->eventDestruct() :), this_object() ); + } + return; +} + +int HitLivings(object ob){ + object env = environment(); + int dam; + //tc("victim: "+identify(ob)); + radius++; + if(radius < 6) dam = random(1000)+500; + else dam = (random(1000)+500) - (radius * 100); + if(env && !living(env)){ + if(env->GetClimate() == "indoors") dam *= 2; + } + if(dam > 0){ + ob->eventReceiveDamage("concussion",OVERPRESSURE, dam, 0); + } + return 1; +} + +int SetArmed(int x){ + if(x) armed = 1; + else armed = 0; + if(armed) set_heart_beat(1); + return armed; +} diff --git a/lib/domains/default/weap/m16rifle.c b/lib/domains/default/weap/m16rifle.c new file mode 100644 index 0000000..a0d7e71 --- /dev/null +++ b/lib/domains/default/weap/m16rifle.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include <vendor_types.h> +#include <damage_types.h> +inherit LIB_FIREARM; +void create(){ + ::create(); + SetKeyName("rifle"); + SetId(({"rifle","m16","M-16","weapon"})); + SetAdjectives(({"m-16","M-16","m16","M16","assault","colt"})); + SetShort("an M-16 assault rifle"); + SetLong("This sleek black weapon has been a military workhorse "+ + "for decades. It is durable, accurate, and above all, extraordinarily deadly. "+ + "This rifle uses .223 caliber ammunition magazines."); + SetCaliber(223); + SetFirearmType("auto"); + SetFirearmName("rifle"); + SetAmmoType("nato"); + SetMass(60); + SetDollarCost(1000); + SetHands(2); + SetClass(20); + SetWeaponType("blunt"); + SetDamageType(BLUNT); + SetVendorType(VT_WEAPON); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/default/weap/orcslayer.c b/lib/domains/default/weap/orcslayer.c new file mode 100644 index 0000000..6cfacc3 --- /dev/null +++ b/lib/domains/default/weap/orcslayer.c @@ -0,0 +1,34 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; +inherit LIB_READ; + +static void create() { + item::create(); + SetKeyName("Orc Slayer"); + SetId( ({ "orcslayer", "orc slayer","sword", "short sword", "shortsword"})); + SetAdjectives( ({ "crafted","finely crafted","short","sharp","fine"})); + SetShort("a finely crafted short sword"); + SetLong("This is a very fine blade, overed with ancient runes. Engraved on it is a picture of the sword slicing an orc."); + SetMass(300); + SetVendorType(VT_WEAPON); + SetClass(150); + SetDamageType(BLADE); + SetWeaponType("blade"); + SetItems( ([ + ({"rune","runes"}) : "The runes' meaning is undecipherable to you.", + ({"picture","engraving"}) : "An almost comical image of a startled orc sliced in half.", + ]) ); + SetRead( ([ + ({"rune","runes"}) : "You do not understand them." + ]) ); +} + +int eventStrike(object target) { + if( target->GetRace() != "orc" ) return item::eventStrike(target); + message("environment", "The orc slayer sword glows blue and emits a ghastly shrieking sound!", + environment(target)); + return item::eventStrike(target) + random(50)+10; +} diff --git a/lib/domains/default/weap/plasma.c b/lib/domains/default/weap/plasma.c new file mode 100644 index 0000000..a9a7307 --- /dev/null +++ b/lib/domains/default/weap/plasma.c @@ -0,0 +1,143 @@ +#include <lib.h> +#include <vendor_types.h> +#include <damage_types.h> +#include <position.h> + +inherit LIB_MISSILE; + +int detonated; +int count, armed; +string *limbs,domain; +void analyze(string butt); +int HitLivings(object munch); +int radius = 0; +object *whom; + +void create(){ + ::create(); + //SetKeyName("Poleekwa plasma rifle bolt"); + SetKeyName("plasma bolt"); + sscanf(base_name(this_object()),"/domains/%s/%*s",domain); + SetId( ({"bolt","plasma"}) ); + SetAdjectives( ({"plasma", "energy"}) ); + SetShort("a plasma bolt"); + SetLong("This is a brilliant ball of superheated material."); + SetCruiseInMessage("A plasma bolt roars in from $D!"); + SetCruiseOutMessage("The plasma bolt flies $D."); + SetMass(0); + SetDollarCost(10); + SetRange(20); + SetSpeed(5); + SetVendorType(VT_WEAPON); + count=5; + detonated=0; +} + +int eventFall(){ + if(!armed) return ::eventFall(); + return 0; +} + +void init(){ + ::init(); + if(armed){ + set_heart_beat(1); + if(detonated==1) this_object()->eventDestruct(); + } +} + +void heart_beat(){ + count--; + if(detonated==1) this_object()->eventDestruct(); + if(count < 0){ + this_object()->detonate(); + return; + } + if(interactive(environment())){ + tell_object(environment(), "You are being melted by a plasma bolt."); + return; + } + tell_object(environment(),"You hear a low hissing sound."); + tell_object(environment(environment()), environment()->GetName()+" is being melted by a plasma bolt."); +} + +int detonate(){ + object ob; + string *stuffs; + int num; + ob = environment(this_object()); + ownerob = GetOwnerOb(); + if(living(ob)){ + stuffs=ob->GetLimbs(); + tell_object(ob, "\nYou are hit by a plasma bolt!\n"); + tell_room(environment(ob), ob->GetName()+" is hit by "+ + "a plasma bolt!\n",ob); + this_object()->HitLivings(ob); + detonated=2; + if(ownerob) ownerob->ReportHit(ob); + } + else tell_room(room_environment(this_object()), "A plasma bolt "+ + "detonates harmlessly."); + this_object()->eventDestruct(); + return 1; +} + +mixed eventNegotiateObstacles(){ + object env = environment(); + if(!env) return 1; + if(!inherits(LIB_ROOM,env)){ + detonate(); + return 0; + } + foreach(object ob in all_inventory(env)){ + if(living(ob) && ob->GetPosition() != POSITION_LYING){ + if(random(100) > 20){ + this_object()->eventMove(ob); + detonate(); + return 0; + } + } + else if(ob->GetMass() > 1000){ + if(random(100) > 30){ + detonate(); + return 0; + } + } + } + return ::eventNegotiateObstacles(); +} + +mixed eventEncounterBlock(){ + detonate(); + return ::eventEncounterBlock(); +} + +void analyze(string str){ + string tmp,tmp2; + sscanf(str,"%s#%s",tmp,tmp2); + if(tmp="/lib/corpse"){ + filter(deep_inventory(find_object(str)), (: $1->eventDestruct() :), this_object() ); + } + return; +} + +int HitLivings(object ob){ + int dam = GetDamage(); + ob->eventReceiveDamage("plasma bolt", HEAT, dam); + return 1; +} + +int SetArmed(int x){ + if(x) armed = 1; + else armed = 0; + if(armed) set_heart_beat(1); + return armed; +} + +int eventCruise(string str){ + return ::eventCruise(str); +} + +int eventDestruct(){ + return ::eventDestruct(); +} diff --git a/lib/domains/default/weap/prifle.c b/lib/domains/default/weap/prifle.c new file mode 100644 index 0000000..f6d1b3f --- /dev/null +++ b/lib/domains/default/weap/prifle.c @@ -0,0 +1,250 @@ +#include <lib.h> +#include <daemons.h> +#include <talk_type.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_RIFLE; +int active, cache; +mapping Prey = ([]); +object myroom; + +varargs mixed DoWield(object who, mixed where); + +string LongDesc(){ + string ret = "A highly advanced weapon of Poleepkwa design."; + if(!active) return ret; + if(cache < 5) ret += " A %^RED%^red%^RESET%^ light is illuminated on it."; + else if(cache < 25) ret += " A %^YELLOW%^yellow%^RESET%^ light is illuminated on it."; + else if(cache < 40) ret += " A %^GREEN%^green%^RESET%^ light is illuminated on it."; + else ret += " A %^BLUE%^blue%^RESET%^ light is illuminated on it."; + return ret; +} + +static void create() { + ::create(); + SetKeyName("plasma rifle"); + SetId(({"rifle"})); + AddSave(({"cache","Prey"})); + SetAdjectives(({"small","poleepkwa","plasma"})); + SetShort("a small plasma rifle"); + SetLong((:LongDesc:)); + SetHands(2); + SetMass(100); + SetDollarCost(5000); + SetVendorType(VT_WEAPON); + SetClass(20); + SetDamageType(BLUNT); + SetFirearmType("auto"); + SetWeaponType("blunt"); + SetWield( (: DoWield :) ); + AddItem( ({"light","status light"}), "A status light."); + set_heart_beat(2); + Prey = ([]); +} + +varargs mixed eventShoot(object who, mixed target, string dir, string whom){ + string name, patsy; + object bolt, killer, env, room = room_environment(); + int fuel, dam; + killer = (who || this_player()); + fuel = killer->GetMagicPoints(); + name = killer->GetName(); + env = environment(killer); + if(target) patsy = target->GetName(); + + if(creatorp(who)){ + cache = 50; + fuel = 800; + who->AddMagicPoints(800); + } + + dam = cache + random(50); + + if(!active){ + write("The rifle clicks."); + say(name+"'s rifle emits a click."); + return 1; + } + + if(cache < 5){ + cache = 0; + write("The rifle clicks."); + say(name+"'s rifle emits a click."); + if(room) room->eventHearTalk(this_object(),0,TALK_LOCAL,"say", + "Power cache too low.", "poleepkwa"); + return 1; + } + + if(fuel < 50){ + cache = 0; + write("The rifle emits a harsh buzzing noise."); + say(name+"'s rifle emits a harsh buzzing noise."); + if(room) room->eventHearTalk(this_object(),0,TALK_LOCAL,"say", + "Operator essence too low.", "poleepkwa"); + return 1; + } + + if(dir){ + if(!env){ + write("No environment."); + return 1; + } + if(!env->GetExit(dir)){ + write("You can't shoot in that direction."); + return 1; + } + bolt = new("/domains/default/weap/plasma"); + if(!bolt){ + write("There appears to be some sort of malfunction."); + return 1; + } + write("You fire your plasma rifle "+dir+"!"); + tell_room(env, name+" fires "+possessive(killer)+ + " plasma rifle "+dir+"!", ({killer})); + bolt->SetOwner(who); + bolt->SetDamage(dam); + bolt->eventMove(env); + bolt->SetArmed(1); + bolt->eventDeploy(dir); + killer->AddMagicPoints(-50); + cache = 0; + return 1; + } + + write("You blast "+patsy+" with your plasma rifle!"); + tell_room(env, name+" blasts "+patsy+" with "+possessive(killer)+ + " plasma rifle!", ({killer, target})); + target->eventPrint(name+" blasts you with "+possessive(killer)+ + " plasma rifle!"); + + dam = cache + random(50); + cache = 0; + Prey = ([ "ob" : target, "name" : patsy, "player" : (userp(target)) ]); + + target->eventReceiveDamage(killer, HEAT, dam); + killer->AddMagicPoints(-50); + target->AddEnemy(killer); + + Prey = ([ "ob" : target, "name" : patsy, "room" : environment(target), + "player" : userp(target) ]); + + if(room) room->eventHearTalk(this_object(),0,TALK_LOCAL,"say", + "New prey being tracked.", "poleepkwa"); + + return 1; +} + +void heart_beat(){ + int notify; + string str; + object env = environment(); + object room = room_environment(); + if(active && !GetWorn()){ + if(env) tell_room(env, "The "+remove_article(GetShort())+ + " whines and clicks off."); + active = 0; + } + else if(active){ + int fuel = env->GetMagicPoints(); + if(!fuel){ + active = 0; + if(environment(env)){ + tell_room(environment(env), env->GetName()+"'s "+ + "plasma rifle whines and clicks off.", ({env})); + env->eventPrint("Your plasma rifle whines and clicks off."); + } + } + else if(cache < 50){ + env->AddMagicPoints(-1); + cache++; + } + } + if(active){ + object tmp; + object penv, menv; + if(Prey["name"] && !Prey["ob"]){ + if(Prey["player"] && tmp = find_player(Prey["name"])){ + Prey["ob"] = tmp; + Prey["room"] = environment(tmp); + Prey["lost"] = 0; + if(room){ + room->eventHearTalk(this_object(),0,TALK_LOCAL,"say", + "Contact with prey re-established.", "poleepkwa"); + } + return; + } + else if(!Prey["player"]) Prey = ([]); + if(room && !Prey["lost"]){ + room->eventHearTalk(this_object(),0,TALK_LOCAL,"say", + "Contact with prey lost.", "poleepkwa"); + Prey["lost"] = 1; + } + return; + } + penv = room_environment(Prey["ob"]); + menv = room_environment(this_object()); + if(Prey["ob"] && (!Prey["room"] || penv != Prey["room"])){ + if(room) room->eventHearTalk(this_object(),0,TALK_LOCAL,"say", + "Prey on the move.", "poleepkwa"); + Prey["room"] = penv; + notify = 1; + } + if(menv != myroom && Prey["ob"]){ + myroom = menv; + notify = 1; + } + if(notify && room){ + string mycords = ROOMS_D->GetCoordinates(menv); + string theircords = ROOMS_D->GetCoordinates(penv); + int i, j, x1, y1, x2, y2, bearing; + i = sscanf(mycords, "%d,%d,%*s", x1, y1); + j = sscanf(theircords, "%d,%d,%*s", x2, y2); + if(i < 2 || j < 2){ + return; + } + bearing = bearing(x2, y2, x1, y1, 1); + if(bearing != -1) str = "Prey's bearing currently: "+bearing; + else str = "Prey is in the immediate environment."; + room->eventHearTalk(this_object(),0,TALK_LOCAL,"say", + str, "poleepkwa"); + } + } +} + +void init(){ + object env = environment(); + ::init(); + if(active && !GetWorn()){ + if(env) tell_room(env, "The "+remove_article(GetShort())+ + " whines and clicks off."); + active = 0; + } +} + +varargs mixed DoWield(object who, mixed where){ + string extra; + object env = environment(who); + if(creatorp(who) || who->GetRace() == "poleepkwa"){ + active = 1; + if(creatorp(who)) cache = 50; + } + if(active) extra = " and it beeps and clicks on."; + else extra = "."; + who->eventPrint("You wield "+GetShort()+extra); + if(env) tell_room(env, who->GetName()+" wields "+ + GetShort()+extra, ({who})); + return 1; +} + +mixed eventUnequip(object who){ + mixed ret = ::eventUnequip(who); + object env = environment(who); + if(ret && active){ + who->eventPrint("The rifle whines and clicks off."); + if(env) tell_room(env, who->GetName()+"'s rifle "+ + "whines and clicks off.", ({who})); + active = 0; + } + return ret; +} diff --git a/lib/domains/default/weap/rpg.c b/lib/domains/default/weap/rpg.c new file mode 100644 index 0000000..3d7815a --- /dev/null +++ b/lib/domains/default/weap/rpg.c @@ -0,0 +1,154 @@ +#include <lib.h> +#include <vendor_types.h> +#include <damage_types.h> +#include <position.h> + +inherit LIB_MISSILE; + +int detonated; +int count, armed; +string *limbs,domain; +void analyze(string butt); +int HitLivings(object munch); +int radius = 0; +object *whom; + +void create(){ + ::create(); + SetKeyName("rocket propelled grenade"); + sscanf(base_name(this_object()),"/domains/%s/%*s",domain); + SetId( ({"grenade","rpg"}) ); + SetAdjectives( ({"rocket","propelled","angular","oblong"}) ); + SetShort("a rocket propelled grenade"); + SetLong("This is an angular, oblong device attached to a tubelike rocket motor. "+ + "It is usually installed in a rocket propelled grenade launcher and shot "+ + "at faraway enemies."); + SetCruiseInMessage("A rocket propelled grenade roars in!"); + SetCruiseOutMessage("The rocket propelled grenade flies $D."); + SetMass(20); + SetDollarCost(10); + SetRange(20); + SetSpeed(5); + SetVendorType(VT_WEAPON); + AddItem(({"motor","rocket motor"}),"The thing that pushes this grenade."); + count=5; + detonated=0; +} + +int eventFall(){ + if(!armed) return ::eventFall(); + return 0; +} + +void init(){ + ::init(); + if(armed){ + set_heart_beat(1); + if(detonated==1) this_object()->eventDestruct(); + } +} + +void heart_beat(){ + count--; + if(detonated==1) this_object()->eventDestruct(); + if(count < 0){ + this_object()->detonate(); + return; + } + if(interactive(environment())){ + tell_object(environment(), "You are holding a live rocket propelled grenade."); + return; + } + tell_object(environment(),"You hear a low hissing sound."); + tell_object(environment(environment()), environment()->GetName()+" is holding a live rocket propelled grenade."); +} + +int detonate(){ + object ob; + string *stuffs; + int num; + ob = environment(this_object()); + if(living(ob)){ + stuffs=ob->GetLimbs(); + tell_object(ob, "\nKABOOM! You are torn to pieces by a rocket propelled grenade!\n"); + tell_room(environment(ob), "\nKABOOM! "+ob->GetName()+" is torn to pieces by "+ + " a rocket propelled grenade!\n",ob); + detonated=2; + foreach(string limb in stuffs){ + if(limb != "head" && limb != "torso" && limb != "neck") ob->RemoveLimb(limb,this_object()); + } + ob = environment(ob); + } + if(detonated !=2) tell_room(environment(this_object()), "\nKABOOM! A rocket "+ + "propelled grenade detonates!\n"); + if(!sizeof(get_livings(ob))) ob = environment(ob); + if(ob && sizeof(whom = scramble_array(get_livings(ob)[0..12]))){ + foreach(object victim in whom){ + this_object()->HitLivings(victim); + } + } + this_object()->eventDestruct(); + return 1; +} + +mixed eventNegotiateObstacles(){ + object env = environment(); + if(!env) return 1; + if(!inherits(LIB_ROOM,env)){ + detonate(); + return 0; + } + foreach(object ob in all_inventory(env)){ + if(living(ob) && ob->GetPosition() != POSITION_LYING){ + if(random(100) > 20){ + this_object()->eventMove(ob); + detonate(); + return 0; + } + } + else if(ob->GetMass() > 1000){ + if(random(100) > 30){ + detonate(); + return 0; + } + } + } + return ::eventNegotiateObstacles(); +} + +mixed eventEncounterBlock(){ + detonate(); + return ::eventEncounterBlock(); +} + + +void analyze(string str){ + string tmp,tmp2; + sscanf(str,"%s#%s",tmp,tmp2); + if(tmp="/lib/corpse"){ + filter(deep_inventory(find_object(str)), (: $1->eventDestruct() :), this_object() ); + } + return; +} + +int HitLivings(object ob){ + object env = environment(); + int dam; + radius++; + if(radius < 6) dam = random(1000)+500; + else dam = (random(1000)+500) - (radius * 100); + if(env && !living(env)){ + if(env->GetClimate() == "indoors") dam *= 2; + } + if(dam > 0){ + ob->eventReceiveDamage("concussion",OVERPRESSURE, dam, 0); + } + return 1; +} + +int SetArmed(int x){ + if(x) armed = 1; + else armed = 0; + if(armed) set_heart_beat(1); + return armed; +} diff --git a/lib/domains/default/weap/sharpsword.c b/lib/domains/default/weap/sharpsword.c new file mode 100644 index 0000000..b1bbe90 --- /dev/null +++ b/lib/domains/default/weap/sharpsword.c @@ -0,0 +1,20 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("sharp sword"); + SetId( ({ "sword", "short sword", "shortsword"})); + SetAdjectives( ({ "short","sharp","fine"})); + SetShort("a sharp sword"); + SetLong("A fine, sharp, short sword."); + SetMass(300); + SetBaseCost("silver",50); + SetVendorType(VT_WEAPON); + SetClass(150); + SetDamageType(BLADE); + SetWeaponType("blade"); +} diff --git a/lib/domains/default/weap/staff.c b/lib/domains/default/weap/staff.c new file mode 100644 index 0000000..5ce9ee4 --- /dev/null +++ b/lib/domains/default/weap/staff.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; +static void create(){ + item::create(); + SetKeyName("staff"); + SetId( ({ "staff", "stick", "pole" }) ); + SetAdjectives( ({ "wood","wooden" }) ); + SetShort("a wooden staff"); + SetLong("This staff is old, weathered, "+ + "and lumpy. However, it feels quite sturdy "+ + "and solid."); + SetVendorType(VT_WEAPON); + SetDamagePoints(50); + SetClass(100); + SetMass(100); + SetWeaponType("blunt"); + SetHands(2); + SetDamageType(BLUNT); +} diff --git a/lib/domains/default/weap/torpedo.c b/lib/domains/default/weap/torpedo.c new file mode 100644 index 0000000..d2150fc --- /dev/null +++ b/lib/domains/default/weap/torpedo.c @@ -0,0 +1,186 @@ +#include <lib.h> +#include <vendor_types.h> +#include <damage_types.h> +#include <position.h> +#include <medium.h> +#include <daemons.h> + +inherit LIB_MISSILE; + +int detonated; +int armed; +string *limbs; +void analyze(string butt); +int HitLivings(object munch); +int radius = 0; +object *whom; + +void create(){ + ::create(); + SetKeyName("torpedo"); + SetId( ({"torpedo","mk14","mark 14","cylinder"}) ); + SetAdjectives( ({"electric","mk14", "mark 14"}) ); + SetShort("a pink torpedo"); + SetLong("Typical of early models, this torpedo was produced during a "+ + "severe shortage of red and white lead undercoat pigments, requiring "+ + "its pink anti-friction paint. This self-propelled cylinder is "+ + "twenty feet long and packed with a tremendous explosive charge. "+ + "It has markings stenciled on the side."); + SetCruiseInMessage("A torpedo cruises in!"); + SetCruiseOutMessage("The torpedo cruises $D."); + SetMass(33000); + SetDollarCost(10000); + SetRange(200); + SetSpeed(3); + SetVendorType(VT_WEAPON); + AddItem(({"motor","electric motor"}),"The thing that pushes this torpedo."); + detonated=0; + SetItems( ([ + ({"markings","marking","stencil"}) : "Markings "+ + "you can read, applied in stencil.", + ({"fins","flaps"}) : "This baby's got 'em.", + ]) ); + SetReads( ([ + "default" : "Try 'read markings on torpedo'", + ({"markings","marking","stencil"}) : "SS-666 "+ + "Sea Tiger", + ]) ); +} + +int eventSink(){ + if(!armed) return ::eventSink(); + return 0; +} + +int eventFall(){ + if(!armed) return ::eventFall(); + return 0; +} + +void init(){ + ::init(); + if(armed){ + set_heart_beat(1); + if(detonated==1) this_object()->eventDestruct(); + } +} + +void heart_beat(){ + if(detonated==1) this_object()->eventDestruct(); + if(interactive(environment())){ + tell_object(environment(), "You are holding a live torpedo."); + return; + } + tell_object(environment(),"You hear a loud whining sound."); + tell_object(environment(environment()), environment()->GetName()+" is holding a live torpedo."); +} + +int detonate(){ + object ob; + string *stuffs; + int num; + ob = environment(this_object()); + if(living(ob) && !(RACES_D->GetNonMeatRace(ob->GetRace()))){ + stuffs=ob->GetLimbs(); + tell_object(ob, "\nKABOOM! You are torn to pieces by a torpedo!\n"); + tell_room(environment(ob), "\nKABOOM! "+ob->GetName()+ + " is torn to pieces by a torpedo!\n",ob); + detonated=2; + foreach(string limb in stuffs){ + if(limb != "head" && limb != "torso" && limb != "neck") ob->RemoveLimb(limb,this_object()); + } + ob = environment(ob); + } + if(detonated !=2) tell_room(environment(this_object()), + "\nKABOOM! A torpedo detonates!\n"); + if(!sizeof(get_livings(ob))) ob = environment(ob); + if(ob && sizeof(whom = scramble_array(get_livings(ob)[0..12]))){ + foreach(object victim in whom){ + this_object()->HitLivings(victim); + } + } + this_object()->eventDestruct(); + return 1; +} + +mixed eventNegotiateObstacles(){ + object env = environment(); + int medium; + if(!env) return 1; + if(!inherits(LIB_ROOM,env)){ + detonate(); + return 0; + } + medium = env->GetMedium(); + if(medium != MEDIUM_SURFACE && medium != MEDIUM_WATER + && medium != MEDIUM_AIR && medium != MEDIUM_SPACE){ + detonate(); + return 0; + } + foreach(object ob in all_inventory(env)){ + if(ob == this_object() || ob->isDummy()) continue; + if(living(ob) && ob->GetPosition() != POSITION_LYING){ + if(random(100) > 20){ + this_object()->eventMove(ob); + detonate(); + return 0; + } + } + else if(ob->GetMass() > 1000){ + if(random(100) > 30){ + detonate(); + return 0; + } + } + } + return ::eventNegotiateObstacles(); +} + +int eventCruise(string str){ + object env = environment(); + if(env && env->GetMedium() == MEDIUM_SPACE){ + return 1; + } + else return ::eventCruise(str); +} + +mixed eventEncounterBlock(){ + detonate(); + return ::eventEncounterBlock(); +} + +void analyze(string str){ + string tmp,tmp2; + sscanf(str,"%s#%s",tmp,tmp2); + if(tmp="/lib/corpse"){ + filter(deep_inventory(find_object(str)), (: $1->eventDestruct() :), this_object() ); + } + return; +} + +int HitLivings(object ob){ + object env = environment(); + int dam; + radius++; + if(radius < 6) dam = random(10000)+5000; + else dam = (random(10000)+5000) - (radius * 1000); + if(env && living(env)){ + dam *= 5; + } + if(dam > 0){ + ob->eventReceiveDamage("concussion",OVERPRESSURE, dam, 0); + } + return 1; +} + +int SetArmed(int x){ + if(x) armed = 1; + else armed = 0; + if(armed) set_heart_beat(1); + return armed; +} + +mixed eventRunOut(){ + return detonate(); +} + diff --git a/lib/domains/examples/room/README b/lib/domains/examples/room/README new file mode 100644 index 0000000..bb39b2c --- /dev/null +++ b/lib/domains/examples/room/README @@ -0,0 +1,16 @@ +Example Rooms Index +=========================================================================== +exroom1: Changing Chats when a quest has been done. +exroom2: example of a room you can inherit. All its functions + go to the rooms which inherit it. They can over-write those functions. + All three rooms which inherit it manipulate 'pull' in their own + rooms. They don't affect 'pull' or "myvar" in this room. +exroom2a: inherits exroom2 and ADDS to the object_entered function +exroom2b: inherits exroom2 and adds nothing to object_entered (but you'll + see that it uses the object_entered from exroom2). +exroom2c: inherits exroom2 and removes the object_entered from exroom2. +exroom3: move_player +exroom4: pre/post exits add/remove exits set/query/remove tempvars +exroom5: look_fail & tempvars pt 2. +exroom6: pre-exit (sneak) +exroom7: two verbs for one add_action diff --git a/lib/domains/examples/room/entrance.c b/lib/domains/examples/room/entrance.c new file mode 100644 index 0000000..c248b09 --- /dev/null +++ b/lib/domains/examples/room/entrance.c @@ -0,0 +1,106 @@ +#include <lib.h> +#include ROOMS_H +#include "ex.h" + +inherit LIB_ROOM; + + +void create() { + room::create(); + SetAmbientLight(30); + SetShort( "Entrance to Hall Of Rooms" ); + SetLong( + "|-----------------------------------------------------------------------------|\n\n"+ + " You are in a large, empty room. There are few things to examine -- only the\n" + "floor, ceiling and wall at this time. An opening to your north leads to the \n" + "incredible Hall of Examples. The line at the top of this description was put\n" + "in as a VERY useful tool for keeping a standard width to all descriptions\n" + " and messages.\n\n" + " The Hall of Examples has many rooms to look through. Each room is limited\n" + "to one or two different types of things. For example, showing how to do a\n" + "pre-exit function. Naturally, you will probably combine many of these\n" + "functions into one single room. Room files can get long and involved, but\n" + "when you understand the individual parts, you have no trouble understanding\n" + "the whole. Don't forget to %^BOLD%^GREEN%^'more here'%^RESET%^ in each room." + " Most of the rooms have explanations written out in comments.\n\n" + " As a final aside, most of the functions are simplistic. These are \n" + "very basic examples." + ); + + SetExits( ([ + "north" : EXPATH + "exroom1", + "south" : START + ])); + + // What follows is a short tutorial on item descriptions. + + // A mapping is a special type of variable -- a list. + // It has a 'key' and a 'value' which are tied together. + // When you query a key it returns the value. + // Each key must be unique. + + // The SetItems in rooms is a mapping where the key & value are + // both strings. + + // This: ([ ]) means what is inside is a mapping. + + // SetItems( ([ ]) ); means you're putting an entire + // mapping into the SetItems. This is how we put items into + // various rooms. We're manipulating the entire mapping + // as a whole. You'll notice for the walls, there is an + // array to allow a player to do 'look wall' and 'look walls' + // and get the same description. This is a very useful method. + + SetItems( ([ + "floor" : "The floor is dirty.", + "ceiling" : "The ceiling is high", + ({ "wall", "walls" }) : "The walls are currtly not very exciting.", + ]) ); + + // The room code also allows us to manipulate individual 'keys' of the + // SetItems mapping: + // AddItem( "bird" , "A small robin sits passageway you can enter."); + // would be a way to put the description for bird into the SetItems mapping. + + // With any mapping, when you set a value for a key that already exists + // the mapping replaces the old one with the new; if that key does + // not yet exist it will add it in. + + // So, when you see the ([ ]) it means you are plunking in a group of + // key/value pairs into the mapping. + + // Finally, if you do SetItems( ([ ]) ); it is going to replace + // the entire SetItems mapping with what is in the ([ ]). + // If you do AddItem(); it will ADD the new mapping to + // the existing SetItems mapping. + + // To illustrate you need to call the test1() function in this room. + // To do that, do the following: + // > call here->test1() + +} + +void test1() +{ + write("Now take a look at the room"); + SetItems( ([ + "north wall" : "The north wall has an exit.", + "east wall" : "The east wall is painted blue.", + "south wall" : "The south wall is painted yellow.", + "west wall" : "The west wall is painted green.", + "wall" : "Which wall? North, South, East or West?", + "walls" : "Which wall? North, South, East or West?" + ]) ); + + // In this example, when overwriting the SetItems mapping, you are + // not able to use arrays at this time. That is the reason that + // 'wall' and 'walls' is not listed as you first saw. Keep this + // in mind when overwriting existing mappings. As you'll also + // notice, as mentioned above, you can no longer look at the floor + // or the ceiling since the whole SetItems mapping has been replaced. + + // Now let's add one description to the list. + AddItem( "statue", "There is a statue of a wizard here." ); + + return; +} diff --git a/lib/domains/examples/room/ex.h b/lib/domains/examples/room/ex.h new file mode 100644 index 0000000..021d779 --- /dev/null +++ b/lib/domains/examples/room/ex.h @@ -0,0 +1,7 @@ +//here's some paths +#define EXAMPLES "/domains/examples/" +#define EXPATH EXAMPLES + "room/" + +//here's some files +#define PAPAROOM EXPATH +"exroom2" +#define START EXPATH + "start" diff --git a/lib/domains/examples/room/exroom1.c b/lib/domains/examples/room/exroom1.c new file mode 100644 index 0000000..b661d2e --- /dev/null +++ b/lib/domains/examples/room/exroom1.c @@ -0,0 +1,110 @@ +#include <lib.h> +#include ROOMS_H +#include "ex.h" + +// The #include "ex.h" is used in each of these files to remember +// the defines for EXPATH and other variables we have defined +// that all of these files use. It would be tedious to have to +// put the #define EXPATH in every file, so we put it into one +// and include it as a reference for each file that needs it. +// Consider it a library card. The books that are in the library +// (the #define's) are referenced every time you see EXPATH. + +inherit LIB_ROOM; + +// I'm defining a global variable here called once to be used later +// in the file. A global variable is something that can be used +// by any function in this room. There are also local variables +// that can be defined only in the variable using it. + +int once; + +// I'm also defing a function lever_pulled() that will be called later. +mixed lever_pulled(); + +void create() +{ + ::create(); + SetAmbientLight(30); + SetShort( "Lever Pull" ); + SetLong("This is an example room for a simple add_action which changes "+ + "a description. There's a lever to pull." + ); + + SetExits( ([ + "north" : EXPATH + "exroom2", + "south" : EXPATH + "entrance", + ])); + + // Here, take a look at how I set the lever item. It is different + // that you saw in the entrance room. What I am doing here is + // calling a functional. When the player types 'look lever', it + // will call the functional (: lever_pulled :) that we defined above. + // I'll explain later in this file. + + SetItems( ([ + "lever" : ((: lever_pulled :)) + ]) ); + +} + +// In the init() function, I am setting our global variable 'once' to 0. This +// is used to reset the lever back when the room resets or the mud reboots. +// so the next player who comes in to pull the lever, they can. +// In the init() function, we also define the actions that can be done in the +// room. In this case, we need a pull action to 'pull lever'. Whenever a player +// types pull, it will call the function aa_pull(). + +void init() +{ + ::init(); + add_action("aa_pull","pull"); + once = 0; +} + +// This is the function that is called when a player types pull as mentioned above. +// First, we need to check and see if they are pulling the correct thing. the +// string str is defining a local variable that will be used in this function. +// Next, we have if( str != "lever"). That is saying if I type 'pull finger', +// it will write 'Pull what?'. The \n symbol means a carriage return or 'enter' +// to go to the next line. + +mixed aa_pull(string str) +{ + if ( str != "lever") + { + write( "Pull what?\n" ); + return 1; + } + + // Here we are going to check if the lever has been pulled. If it has, + // it's going to tell the player that and exit the aa_pull() function. + // this is done by the return 1; that you see here. + + if( once ==1 ) + { + write( "The lever's already pulled." ); + return 1; + } + + // If the lever has not been pulled, this part starts. As you'll notice, we + // set once = 1 to indicate that the lever has been pulled. + + write("You pull the lever!\n"); + say(this_player()->GetName() + " pulls the lever!\n"); + once=1; + return 1; +} + +// I told you I'd explain what the functional (: lever_pulled :) was for. +// Below, it checks to see if the lever has been pulled. if( !once ) +// says, if once is equal to 0 (not pulled) it returns and says the lever +// has not been pulled. If once is not equal to 0, then it means that it +// has been pulled and returns a different message. + +mixed lever_pulled() +{ + if( !once ) + return "The lever is pushed into the wall. Perhaps you could pull it."; + return "The lever has already been pulled. You're too late!"; +} diff --git a/lib/domains/examples/room/exroom2.c b/lib/domains/examples/room/exroom2.c new file mode 100644 index 0000000..eca3b05 --- /dev/null +++ b/lib/domains/examples/room/exroom2.c @@ -0,0 +1,77 @@ +#include <lib.h> +#include "ex.h" + +inherit LIB_ROOM; + +int myvar; + +void create() +{ + ::create(); + SetAmbientLight(30); + SetShort( "a master file" ); + SetLong(@EndText +|---------------------------------------------------------------|-------------| +This is an example room for inheriting files. This +file is inherited by two others. It's also a fully +functional room. There's a lever to pull. +The rooms which inherit me are to the east. +EndText + ); + + // You'll notice that for SetLong(), I've put @EndText at the top and EndText at the bottom + // and have not put in quotes. When using this style of code, it is important to make sure + // you manually enter to the next line to wrap the lines on the player's screen. + // This can be a tedious if you do not know how many lines to enter before you need to + // continue on the next line. If you look back to the Entrance to the Hall of Examples, + // You will see a handy line I've used to know when to stop a line and continue on + // the next. I've included it in the room description for your convenience. the + // normal screen default is 79 characters. Whenever you would like to recreate the line + // at the top, type 'margins' + + SetExits( ([ + "south" : EXPATH + "exroom1", + "north" : EXPATH + "exroom3", + "east" : EXPATH + "exroom2a" + ]) ); + SetItems( ([ + "lever" : "A lever for pulling.", + ]) ); + + myvar = 0; +} + +// The CanReceive() function is very helpful to do checks on an interactive object +// that enters the room. In this case, we are checking to see if the object that +// enters is a creator player object. If it is, then we will give a message to +// that object with the write() funciton. I've put some color tags to set the color +// off from the rest of the text. For colors available, type 'colors'. + +int CanReceive(object ob) +{ + if ( creatorp(ob) ) + write( "%^BOLD%^BLUE%^Room tells you: %^BOLD%^GREEN%^You're a creator! %^BOLD%^BLUE%^(This is from the master file.)%^RESET%^\n"); + return 1; +} + +void init() +{ + ::init(); + add_action("aa_pull","pull"); +} + +// We're going to use the variable 'myvar' in the middle of a write() funciton. As +// you'll notice below, the text you are writing has to be in the " ". Then we +// separate the text by putting in: " + myvar + ". This adds the myvar variable +// to the text output whenever a player pulls the lever. Try it and see. + + +mixed aa_pull(string str) +{ + if (str!="lever") + return notify_fail("Pull what?\n"); + myvar ++; + write("You pull the lever and the value of 'myvar' is now " + myvar + "\n"); + say(this_player()->GetName() + " pulls the lever!\n"); + return 1; +} diff --git a/lib/domains/examples/room/exroom2a.c b/lib/domains/examples/room/exroom2a.c new file mode 100644 index 0000000..5c8253a --- /dev/null +++ b/lib/domains/examples/room/exroom2a.c @@ -0,0 +1,72 @@ +#include <lib.h> +#include "ex.h" + +inherit PAPAROOM; + +void create() +{ + ::create(); + SetAmbientLight(30); + SetShort( "a 'child' file" ); + SetLong("This is an example room whose properties are inherited " + "from another room.\n<look more> for more information." + ); + + //Note: When we set the "exits" in this room we + // over-write the "exits" we inherited from PAPAROOM + // There's a way to just add an exit to the list, but exits + // are primarily unique to each room, so this method is fine. + SetExits( ([ + "west" : EXPATH + "exroom2", + "east" : EXPATH + "exroom2b" + ])); + + SetItems( ([ + "more" : @EndText +------------------------------------------------------------------- +Take a look at the CanReceive function. +Do you see the line ::CanReceive(ob)? +The :: refers to 'the file I've inherited from'. +So, we are calling (using) the function CanReceive() as it is +written in exroom2.c +THEN we are doing our own thing. + +When an object enters this room (player or bowl or sword etc) +it becomes the variable 'ob'. + +We pass that variable 'ob' along to the function CanReceive() +that's in exroom2.c + +Then we check to see if ob is a player or creator. (type: man userp) +If so, we give that object a message. +------------------------------------------------------------------- +EndText, + ])); + + /* See the way I did the SetItems again for 'more'. This is one + way to do it. Another way to do it is to use a (: functional :) + like I did for the lever. Take a look, however, at this comment + that you are reading. If you'll notice, I've done it a little + differently to show you a way to comment out several lines all + at once. The original method that I used was to put // in front + of the line that I wanted to comment out. If you have several + lines like we have here, then you'll want to begin your comment + like you see here and end it like below. This is how I will + be doing large comments in future examples. + */ + + +} + +int CanReceive(object ob) +{ + ::CanReceive(); + if ( userp(ob) ) + write("%^MAGENTA%^Room tells you: %^GREEN%^You're any player, creator or not! %^MAGENTA%^(This is from this room)%^RESET%^\n"); + return 1; +} + +void init() +{ + ::init(); +} diff --git a/lib/domains/examples/room/exroom2b.c b/lib/domains/examples/room/exroom2b.c new file mode 100644 index 0000000..4c83b2d --- /dev/null +++ b/lib/domains/examples/room/exroom2b.c @@ -0,0 +1,37 @@ +#include <lib.h> +#include "ex.h" + +inherit PAPAROOM; + +void create() +{ + ::create(); + SetAmbientLight(30); + SetShort( "a 'child' file" ); + SetLong("This is an example room that inherits the properties " + "of another room."); + + /* Note: When we set the "exits" in this room we over-write + the "exits" we inherited from PAPAROOM. There's a way to + just add an exit to the list, but exits are primarily + unique to each room, so this method is fine. + */ + + SetExits( ([ + "west" : EXPATH + "exroom2a", + ])); + + /* Now, we are setting the objects that are loaded into the room, + or the inventory of the room. Just like a player has inventory + on their character. + */ + + SetInventory( ([ "/domains/default/obj/bbucket" : 1 ])); + +} + + +void init() +{ + ::init(); +} diff --git a/lib/domains/examples/room/exroom3.c b/lib/domains/examples/room/exroom3.c new file mode 100644 index 0000000..2110f86 --- /dev/null +++ b/lib/domains/examples/room/exroom3.c @@ -0,0 +1,55 @@ +#include <lib.h> +#include "ex.h" + +inherit LIB_ROOM; + +void create() +{ + ::create(); + SetAmbientLight(30); + SetShort( "move the player" ); + SetLong(@EndText +This is an example room for moving a player. There's nothing +to look at here. But, surprise, there's a lever to pull. + +We are going to get a bit fancier and have something special +happen when a player pulls the lever. +EndText + ); + + SetExits( ([ + "south" : EXPATH + "exroom2", + "north" : EXPATH + "exroom4", + ])); + +} + +void init() +{ + ::init(); + add_action("aa_pull","pull"); +} + +int aa_pull(string str) +{ + if (str!="lever") + { + write( "Pull what?\n" ); + return 1; + } + write(@EndText +You pull the lever and a big hand grabs you! +It whisks you away to parts unknown. Ok, they are known. +Look around when you get there, which is basically instantaneous. +EndText); + say(this_player()->GetName() + " pulls the lever!"); + this_player()->eventMoveLiving(EXPATH + "exroom1", "forcibly when a big hand takes " + objective(this_player()) + " away", + this_player()->GetName() + " is dropped from the sky by a big hand." + ); + return 1; +} + +/* The eventMoveLiving() function transports the player who pulls + the lever to another room. It also writes a message in the room + that the player leaves and in the room they are sent to. + */ diff --git a/lib/domains/examples/room/exroom4.c b/lib/domains/examples/room/exroom4.c new file mode 100644 index 0000000..e0c7c4a --- /dev/null +++ b/lib/domains/examples/room/exroom4.c @@ -0,0 +1,198 @@ +#include <lib.h> +#include "ex.h" + +inherit LIB_ROOM; +int pre_north(); +int post_south(); +int post_north(); + +void create() +{ + ::create(); + SetAmbientLight(30); + SetShort( "pre/post exits and add/remove exits" ); + SetLong(@EndText +There's a door to the north with a doorbell, and a blank +wall to the south. +------------------------------------------------------------- +This is an example room for using pre-exits and post-exits. +It also shows how to add & delete an exit from the room, and +use a temporary variable on a player. + +There's a lever to pull and push, and a bell to ring. +Pull the lever out: create an exit to the south. +Push the lever in: delete an exit to the south. +Ring the bell: allows you to go north. +When you go south, the exit to the south disappears. +------------------------------------------------------------- +EndText + ); + + SetExits( ([ + ])); + + AddExit( "north", EXPATH + "exroom5", (: pre_north :)); + +} + +void init() +{ + ::init(); + add_action("aa_pull","pull"); + add_action("aa_push","push"); + add_action("aa_ring","ring"); +} + + +int aa_pull(string str) +{ + if (str!="lever" && str!="lever out") + { + write( "Pull what?\n" ); + return 1; + } + /* Now, we can find out if the lever has been already pulled + in one of two ways. + Method one: we test to see if the exit to the south is open. + Since pulling the lever does this, and the only way to + create that exit is pulling the lever -- this is a valid method. + + Method two: we use a variable and change it's value when the lever + is pushed or pulled. Since we have a method that works without + using an additional variable, that is the method I'll pick here. + It will also show you how to query for an exit. + +Note: GetExits() returns a mapping for all the exits in a room +GetExit("dir") returns the value for that specific direction. +if there is NOT an exit in that direction it will return UNDEFINED +and can be detected using the ! operator. (! means 'not') +conversely, if GetExit("dir") is true, then there IS an exit +to that direction. Got it? Good. + */ + + if ( GetExit("south") ) + { + write("The lever is already pulled out!\n"); + return 1; + } + + /* If you don't know by now, this_player() indicates the player doing the actions + So when I do this_player()->GetName() it gives me the name of the player + who is doing the actions and allows me to tell the room who it is. + */ + + write( "You pull the lever and an invisible crack appears in the south wall. "+ + "A door slides open and there is a previously undetected exit." ); + say(this_player()->GetName() + " pulls the lever and an exit appears to the south.\n"); + + // AddExit() functions add an exit to the room. Here, we added an exit and + // set up a (: functional :) to do close up the exit when they leave. + + AddExit( "south", EXPATH + "exroom3", (: post_south :) ); + SetObviousExits("north, south"); + return 1; +} + + +int aa_push(string str) +{ + if (str!="lever" && str!="lever in") + { + write( "Push what?\n" ); + return 1; + } + + /* Since there's more then one way for the exit to dissappear (see the post-exit + function for south) and there may be more then one player wandering the halls + we don't want to assume that 'this' player pushed the lever. So we wouldn't + say "You've already pushed the lever." + */ + + if ( ! GetExit("south") ) + { + write( "The lever is pushed in as far as it will go.\n"); + return 1; + } + write( "You push the lever in and an unseen door slides shut in the south wall."+ + "The wall now appears solid and unpenatrable." ); + say(this_player()->GetName() + " pushes the lever and the south closes tight.\n"); + + // Now we remove the exit that was added earlier. + + RemoveExit("south"); + SetObviousExits("n"); + return 1; +} + + +int aa_ring(string str) +{ + if (str!="bell" && str!="doorbell" && str!="door bell") + { + write( "Ring what?\n" ); + return 1; + } + //if we only want to let them ring it once, we can check for the + //temp var here. This version will let them ring it many times. + write("DONG!\nYou ring a doorbell! You are now admitted north.\n"); + say("DONG! A doorbell rings.\n"); + this_player()->SetProperty("rung_bell", 1); + return 1; +} + + +/* CODING STYLE 101 + Personally, I always put my post/pre exit functions right after create and + before the reset() or init() functions. This makes them easy to find. + Since they're MENTIONED in the create() I like to keep 'em close at hand. + For the same reason I usually follow my init() with any add_actions that + I've created. I also preface my functions with an indicator saying what + their purpose is. I've chosen aa_ for add_actions an pe_ for pre or post + exit functions. OR i use pre_ or post_ when i have both going on. This + may not seem like a big deal in a little file, but when the file gets + huge, it helps to glance at a function and go: ah ha! this is a post_exit + function. or ah ha! this is an add_action or similarly: ah ha! this is + not any specialized function so I must be calling it for some other reason. + The order you write them in is a personal decision. Just keep your + create() function first on the list. + */ + +//A return 0 in a pre-exit will prevent you from going that dir. +//A return 1 will allow you to go that dir. + + +int pre_north() +{ + if( !this_player()->GetProperty("rung_bell") ) + { + write("Ring the doorbell first!\n"); + return 0; + } + // Now that the pre_north() function has done what it needs to do, we + // will call the post_north() function here + post_north(); + return 1; +} + + +int post_north() +{ + //might as well delete it, it's served its purpose. + this_player()->RemoveProperty("rung_bell"); + return 1; +} + + +//We're going to delete the exit AFTER the player walks through +// Because doing it in a pre_exit would be tatamount to slamming +// a door in their face. You wouldn't want to do that... would you? :P + + +int post_south() +{ + write("You hear a noise and realize the wall has mysteriously closed.\n"); + say("You hear a noise and realize the wall has mysteriously closed.\n"); + this_player()->eventMoveLiving("/domains/examples/room/exroom3", "south", this_player()->GetName()+" enters."); + RemoveExit("south"); + SetObviousExits("n"); +} diff --git a/lib/domains/examples/room/exroom5.c b/lib/domains/examples/room/exroom5.c new file mode 100644 index 0000000..6691a4b --- /dev/null +++ b/lib/domains/examples/room/exroom5.c @@ -0,0 +1,139 @@ +#include <lib.h> +#include "ex.h" + +//LOOKIE! A constant (#define) at the top of the file instead +// of in a header (.h) file. Yes, this is possible and sometimes +// a better method. This is the only room in the entire directory +// which uses this define. It doesn't really need to go into +// the ex.h file. However, it must be at the top of the file. + +#define ORC "/domains/town/npc/orc" + +inherit LIB_ROOM; + +void create() +{ + ::create(); + SetAmbientLight(30); + SetShort( "temp vars" ); + SetLong(@EndText +You can't really see north and there's a bell +on the south door. Don't ring it too many times! +------------------------------------------------------------- +This is an example room for querying the specific value of a +stored variable. Remember though, variables are persistent. +If you want to prevent a future bug report from your players +or creators, then make sure you remove the variable when they +leave. Otherwise, when the come back in a week and ring the +bell only once, it would actually be added to their previous +rings. +------------------------------------------------------------- +EndText + ); + + SetProperty( "no peer", 1); + + SetExits( ([ + "north" : EXPATH + "exroom6", + "south" : EXPATH + "exroom4", + ])); +} + +void init() +{ + ::init(); + add_action("aa_ring","ring"); +} + +/* Since we don't need the temp var now, we will remove it. + In the CanRelease() function, I am telling the room that + when an object tries to leave, to remove the temp var + and return 1; to say that it is okay to leave. Were + I to put return 0; then the player would not be able + to leave. + */ + +int CanRelease() +{ + this_player()->RemoveProperty("rung_bell"); + return 1; +} + +mixed aa_ring(string str) +{ + int numrings; + if (str!="bell" && str!="doorbell" && str!="door bell") + return notify_fail("Ring what?\n"); + /* if "rung_bell" has not been set in the player, a query() for it + will return UNDEFINED. you CAN add 1 to an undefined to get 1. + + they just rang it one more time, so we'll take what was there and + add one. Then we'll put the new value back into the temp var + **see note at bottom of file. + */ + numrings=this_player()->GetProperty("rung_bell")+1; + this_player()->SetProperty("rung_bell",numrings); + write("DONG!\nYou ring a doorbell! Don't do it too many times!\n"); + say("DONG! A doorbell rings.\n"); + + if ( numrings>5 ) + { + if (!present("orc",this_object())) //nested if. see NOTE 2. + { + write("Now you've done it! An orc walks in a bonks you on the head.\n"); + say("Now " + this_player()->GetName() + " has done it! An orc walks in a bonks " + + objective(this_player()) + " on the head.\n"); + new(ORC)->eventMove(this_object()); //this_object IS -this- room! + } + } + return 1; +} + +/* NOTE! + There are many ways to do the same thing with code. Some ways + are more readable. Some are less. Some are more efficient. + Some ways are very readable and only slightly less efficient. + I urge you to start out writing code that is readable AND correct, + rather then try to squeeze things down to one line of code. The + goal is to learn -- to understand what you're doing. If you + attempt to copy code that is all squeezed down into one line, and + you really don't understand it, then you'll be forever just copying + code and not really "getting it". + + That said. + in the add_action i did the following: + + int numrings; + numrings=this_player()->GetProperty("rung_bell")+1; + this_player()->SetProperty("rung_bell",numrings); + if ( numrings>5 ) + etc... + + I COULD have eliminated the variable numrings : + + this_player()->SetProperty("rung_bell", + this_player()->GetProperty("rung_bell") + 1); + if (this_player()->GetProperty("rung_bell") > 5) + etc... + + But, read both sets of code and determine for yourself which is easier + to read; easier to figure out on reading. You see, other people will + be reading your code. Other people will be debugging your code at + a later date. You may decide to never log on again and your project + is in a domain. The people in that domain will be fixing bugs & typos + & runtimes and you gotta bet that they will appreciate READABLE code... + as well as good comments. Never be afraid of comments! + + + NOTE 2! The nested if. Could also have been written: + if ( numrings>5 && ! present("orc",this_object())) + { + write("Now you've done it! An orc walks in a bonks you on the head.\n"); + say("Now " + this_player->GetName() + " has done it! An orc walks in a bonks " + + objective(this_player()) " + " on the head.\n"); + new(ORC)->eventMove(this_object()); //this_object IS -this- room! + } + But, if you are having problems with the booleans && || and the code + is pretty clean & simple already, you might want to go the route + of nesting your if statements until you get the hang of && and ||. + */ diff --git a/lib/domains/examples/room/exroom6.c b/lib/domains/examples/room/exroom6.c new file mode 100644 index 0000000..ac4e22d --- /dev/null +++ b/lib/domains/examples/room/exroom6.c @@ -0,0 +1,61 @@ +#include <lib.h> +#include "ex.h" + +#define SPIDER "/domains/town/npc/spider" + +inherit LIB_ROOM; + +int pre_north(); + +void create() +{ + ::create(); + SetAmbientLight(30); + SetShort( "a room with a blocked exit" ); + SetLong(@EndText +There's not much here. Of course, we don't talk about +the spider in the long, cause it COULD be dead. +EndText + ); + SetExits( ([ + "south" : "/domains/examples/room/exroom5", + ]) ); + + AddExit("north", EXPATH + "exroom7", (: pre_north :)); + + SetInventory( ([ + SPIDER : 1, + ])); +} + +void init() +{ + ::init(); +} + +/* In the pre_north() function, I am going to add a special treat! + If a creator is invisible, you can bypass the spider completely! + Woo! Woo! + */ + +int pre_north(string dir) +{ + if( this_player()->GetInvis(1)) + return 1; + /* If the spider is present, the player can not go that way. We + are also checking to see if the spider is still alive since + we don't want a corpse to click menacingly. :) + If I were to only put if(present("spider")), then the dead + corpse would block the path and click menacingly. + By putting the if(living(present("spider", this_object()))) + we accomplish two checks on one line. Simple and elegant.*/ + if(present("spider", this_object()) && living(present("spider",this_object())) ) + { + write("The spider blocks your exit and clicks menacingly!\n"); + say("The spider blocks " + possessive_noun(this_player()->GetName()) + " exit and clicks menacingly!\n"); + return 0; + } + //if we get to here, the spider is not present, so we treat as a + //normal exit. ie: do nothing. return 1 allows the exit, if you remember. + return 1; +} diff --git a/lib/domains/examples/room/exroom7.c b/lib/domains/examples/room/exroom7.c new file mode 100644 index 0000000..1733f7b --- /dev/null +++ b/lib/domains/examples/room/exroom7.c @@ -0,0 +1,93 @@ +#include <lib.h> +#include "ex.h" + +inherit LIB_ROOM; + +int once; +int is_pulled(); + +void create() +{ + ::create(); + SetAmbientLight(30); + SetShort( "two verbs for one action" ); + SetLong(@EndText +This room demonstrates how you can use two verbs to do +one thing. +There's a chain here. You can pull it or yank it. + +Note: See how we change the description of the chain? +It's important to remove 'quest hints' once a +quest has been done. And then put them back in +when the quest is ready to do. +EndText + ); + + // Here is another functional to point to the is_pulled() + // function. This is a very useful tool. + + SetItems( ([ + "chain" : (: is_pulled :), + ])); + + SetExits( ([ + "south" : EXPATH + "exroom6", + ])); +} + +/* Here you'll see that we have two add_actions. We have 'pull' and + 'yank'. If the player uses either verb when pulling the chain + the aa_chain() function is called. + */ + +void init() +{ + ::init(); + add_action("aa_chain","pull"); + add_action("aa_chain","yank"); +} + +/* This is the first reset() function that we've seen so I'd like + to take a moment to explain it. The reset() function allows + an object to do self-maintenance. 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. Here, we use the reset() + function to return the variable 'once' back to 0 to allow the + chain to be pulled again after reset occurs. + */ + +void reset() +{ + ::reset(); + once=0; +} + +/* query_verb() tells you what the player typed */ +mixed aa_chain (string str) +{ + string averb=query_verb(); + if (str!="chain") + return notify_fail(capitalize(averb)+ " what?\n"); + if (once) + return notify_fail("The chain has already been " + + averb + "ed.\n"); + + // We're returning the averb variable that was defined and set + // above in a message to the player and the room. Then, we + // set the 'once' variable to show that the chain has been pulled. + write("You " + averb + " the chain!\n"); + say(this_player()->GetName() + " "+ averb + "s the chain!\n"); + once=1; + return 1; +} + +// This is the functional that was called to show the current state +// of the chain. Pulled or not pulled. +string is_pulled() +{ + if( once ) + return "You see a plain chain.\n"; + else + return "Here's a chain begging to be yanked or pulled.\n"; +} diff --git a/lib/domains/examples/room/start.c b/lib/domains/examples/room/start.c new file mode 100644 index 0000000..befd634 --- /dev/null +++ b/lib/domains/examples/room/start.c @@ -0,0 +1,20 @@ +#include <lib.h> +#include ROOMS_H +#include "ex.h" + +inherit LIB_ROOM; + + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area. The example rooms are north."); + SetExits( ([ + "north" : EXPATH + "entrance" + ]) ); + SetCoordinates("-3000,-3000,-3000"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/learning/adm/README b/lib/domains/learning/adm/README new file mode 100644 index 0000000..2ddcbe3 --- /dev/null +++ b/lib/domains/learning/adm/README @@ -0,0 +1,14 @@ + The Administrative Directory + +This directory contains files necessary for domain administration. + +Specifically it is the default directory for the access object, +which is used for providing nonstandard access to files with +the "grant" command. + +This is also the location where domain-specific daemons can be +expected to reside. + +In the case of archaic domains, such as Ylsrim, this is where +some mandatory rooms are expected to be, such as freezer.c and void.c + diff --git a/lib/domains/learning/adm/analytics.c b/lib/domains/learning/adm/analytics.c new file mode 100644 index 0000000..255c031 --- /dev/null +++ b/lib/domains/learning/adm/analytics.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <save.h> +#include <daemons.h> +#include <privs.h> + +inherit LIB_DAEMON; +static string SaveFile; + +static void create() { + daemon::create(); + SaveFile = save_file("/domains/learning/save/analytics"); + SetSaveFile(SaveFile); + if(!file_exists(SaveFile) && file_exists(old_savename(SaveFile))){ + cp(old_savename(SaveFile), SaveFile); + } + if(file_exists(SaveFile)) RestoreObject(SaveFile); +} + +int eventDestruct(){ + SaveObject(SaveFile, 1); + return ::eventDestruct(); +} + diff --git a/lib/domains/learning/room/death.c b/lib/domains/learning/room/death.c new file mode 100644 index 0000000..9a8de22 --- /dev/null +++ b/lib/domains/learning/room/death.c @@ -0,0 +1,73 @@ +#include <lib.h> +#include <dirs.h> +#include ROOMS_H + +inherit LIB_ROOM; + +string FunkyPic(); +int CheckChat(); +int StartHeart(object ob); + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("off the mortal coil"); + SetLong( (:FunkyPic:) ); + SetObviousExits("no exit"); + set_heart_beat(10); + SetNoModify(1); +} + +void init(){ + ::init(); + add_action("regenerate","regenerate"); + add_action("regenerate","choose"); + add_action("wander","wander"); + this_object()->CheckChat(); +} + +string FunkyPic(){ + return "YOU ARE DEAD!!!"; +} + +int regenerate(){ + write("With a great rush of matter and energy, you rematerialize "+ + "into a corporeal state, and find yourself in a familiar place..."); + this_player()->eventRevive(); + this_player()->eventMoveLiving(ROOM_START); + return 1; +} + +int wander(){ + write("There is a strange, hollow vibration all around you, and you "+ + "realize that some force is compelling your ethereal form elsewhere..."+ + "you find yourself in a place that is known to you, yet oddly new."); + this_player()->eventMoveLiving(ROOM_START); + return 1; +} + +void heart_beat(){ + tell_room(this_object(), "A voice whispers: \" You may choose to "+ + "regenerate into a new body here.\""); + return; +} + + +int CanRelease(object ob){ + if(userp(ob) && ob->GetGhost() && environment(ob) == this_object()) { + tell_player(ob,"\n%^RED%^Your undead spirit is recalled and as you leave "+ + "the underworld a new body regenerates around you. "+ + "You live again!%^RESET%^\n"); + ob->eventRevive(); + } + return 1; +} + +int CanReceive(object ob){ + if(!living(ob)){ + return 0; + } + return ::CanReceive(ob); +} + diff --git a/lib/domains/learning/room/freezer.c b/lib/domains/learning/room/freezer.c new file mode 100644 index 0000000..896cbbf --- /dev/null +++ b/lib/domains/learning/room/freezer.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetNoClean(1); + SetProperties(([ "login" : ROOM_START ])); + SetShort( "The freezer"); + SetLong( "The local freezer. Go down to leave."); + SetObviousExits("down"); + SetExits( ([ "down" : ROOM_START ]) ); + call_out("clean_room", MAX_NET_DEAD_TIME); + SetNoModify(1); +} + +static void clean_room(){ + object ob; + call_out((: clean_room :), MAX_NET_DEAD_TIME); + foreach(ob in filter(all_inventory(), (: living($1) :))){ + string name = last_string_element(base_name(ob),"/"); + if(!user_exists(name)) continue; + ob->eventDestruct(); + } +} + +void init(){ + ::init(); +} diff --git a/lib/domains/learning/room/furnace.c b/lib/domains/learning/room/furnace.c new file mode 100644 index 0000000..240341a --- /dev/null +++ b/lib/domains/learning/room/furnace.c @@ -0,0 +1,10 @@ +#include <lib.h> + +inherit LIB_FURNACE; + +void create() { + furnace::create(); +} +void init(){ + ::init(); +} diff --git a/lib/domains/learning/room/pod.c b/lib/domains/learning/room/pod.c new file mode 100644 index 0000000..62da2f9 --- /dev/null +++ b/lib/domains/learning/room/pod.c @@ -0,0 +1,16 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("the incept pod"); + SetLong("The incept pod. Some objects come here to be created "+ + "and identified. Go down to get out."); + SetExits( ([ "down" : ROOM_START ]) ); +} +int CanReceive(object ob){ + return room::CanReceive(ob); +} diff --git a/lib/domains/learning/room/start.c b/lib/domains/learning/room/start.c new file mode 100644 index 0000000..df44eec --- /dev/null +++ b/lib/domains/learning/room/start.c @@ -0,0 +1,17 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("Learning Center Start"); + SetLong("This is where you can start learning how to interact with the virtual world you've connected to.\n\nTo begin the tutorial, enter: tutorial\n\nTo return to the normal areas, enter: normal\n"); + SetCoordinates("2000,2000,0"); + SetNoObviousExits(1); + SetNoClean(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/learning/room/void.c b/lib/domains/learning/room/void.c new file mode 100644 index 0000000..622a4ac --- /dev/null +++ b/lib/domains/learning/room/void.c @@ -0,0 +1,16 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("the void"); + SetLong("The void. Go down to get out."); + SetExits( ([ "down" : ROOM_START ]) ); + SetNoModify(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/learning/room/wiz_hall.c b/lib/domains/learning/room/wiz_hall.c new file mode 100644 index 0000000..dba7910 --- /dev/null +++ b/lib/domains/learning/room/wiz_hall.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Creators' Hall"); + SetLong("A generic Wiz Hall."); + SetProperty("no attack", 1); + SetProperty("nopeer",1); +} + +int CanReceive(object ob) { + if(playerp(ob) && !creatorp(ob) && !present("testchar badge",ob)) { + message("info","Creator staff only, sorry.", ob); + return 0; + } + return ::CanReceive(ob); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/learning/save/analytics.o b/lib/domains/learning/save/analytics.o new file mode 100644 index 0000000..78c742b --- /dev/null +++ b/lib/domains/learning/save/analytics.o @@ -0,0 +1,3 @@ +#/domains/learning/adm/analytics.c +PersistentInventory 0 +PersistentInventoryEnabled 0 diff --git a/lib/domains/learning/virtual/server.c b/lib/domains/learning/virtual/server.c new file mode 100644 index 0000000..97fdbb6 --- /dev/null +++ b/lib/domains/learning/virtual/server.c @@ -0,0 +1,22 @@ +#define __DIR__ "/domains/learning/virtual/" + +mixed compile_object(string file) { + string *path; + object ob; + int x, y, z, elements; + if(grepp(file, "/user_") || grepp(file, "/object_")){ + ob = new("/domains/learning/virtual/void"); + if(!ob){ + return "No void room available."; + } + return ob; + } + path = explode(file, "/"); + if( file_size(__DIR__ + path[3] + ".c") < 1 ) return "bad file"; + if( (elements = sscanf(path[4], "%d,%d,%d", x, y, z)) != 3 ) { + if( (elements = sscanf(path[4], "%d,%d", x, y)) != 2 ) return "missing comma"; + } + if( elements == 2 && !(ob = new(__DIR__ + path[3], x, y)) ) return "failed to compile"; + else if( elements == 3 && !(ob = new(__DIR__ + path[3], x, y, z)) ) return "failed to compile"; + return ob; +} diff --git a/lib/domains/learning/virtual/void.c b/lib/domains/learning/virtual/void.c new file mode 100644 index 0000000..f4701a3 --- /dev/null +++ b/lib/domains/learning/virtual/void.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <dirs.h> +#include <rooms.h> +#include <virtual.h> +#include <position.h> +#define __DIR__ "/domains/learning/virtual/" + +inherit LIB_VIRT_LAND; + +varargs static void create(int x, int y) { + SetNoReplace(1); + virt_land::create(); + SetClimate("temperate"); + SetAmbientLight(30); + SetLong("A featureless void."); + SetShort("an empty place"); + AddExit("down", ROOM_START); +} diff --git a/lib/domains/oogtopia/doors/m1.c b/lib/domains/oogtopia/doors/m1.c new file mode 100644 index 0000000..e957747 --- /dev/null +++ b/lib/domains/oogtopia/doors/m1.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("west", ([ "id" : ({"door leading west", "door", "west door"}), + "short" : "a door leading west", + "long" : "This is the east side of a door leading west.", + "lockable" : 1 ]) ); + + SetSide("east", ([ "id" : ({"door leading east", "door", "east door"}), + "short" : "a door leading east", + "long" : "This is the west side of a door leading east.", + "lockable" : 1 ]) ); + + SetClosed(1); + SetLocked(0); + SetKeys("west", ({ "west key" })); + SetKeys("east", ({ "east key" })); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/oogtopia/npc/party_ooga.c b/lib/domains/oogtopia/npc/party_ooga.c new file mode 100644 index 0000000..c08e101 --- /dev/null +++ b/lib/domains/oogtopia/npc/party_ooga.c @@ -0,0 +1,40 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +int CheckOrc(mixed val){ + if(!val) return 0; + if(!objectp(val)) return 0; + if(val->GetRace() == "ooga") return 0; + else eventForce("growl at "+val->GetKeyName()); + if(playerp(val) && val->GetRace() != "ooga") return 1; + else return 0; +} + +static void create() { + sentient::create(); + SetKeyName("ooga"); + SetId(({"ooga"})); + SetAdjectives(({"armored","professional"})); + SetShort("an ooga booga"); + SetLong("This is an ooga booga, they're ready to party. They don't like technology or civilization but they sure do like music and booze by the firelight."); + SetInventory(([ + "/domains/town/weap/sword" : "wield sword", + "/domains/town/obj/orc_rucksack" : "wear my sack", + "/domains/town/armor/leather_armor" : "wear leather armor", + "/domains/town/armor/orc_boot_l" : "wear left boot", + "/domains/town/armor/orc_boot_r" : "wear right boot", + ])); + SetLevel(1); + SetWanderSpeed(10); + SetRace("ooga"); + SetClass("explorer"); + SetGender("sparkly"); + SetEncounter( (: CheckOrc :) ); +} + +void init(){ + ::init(); +} + + diff --git a/lib/domains/oogtopia/room/bushese.c b/lib/domains/oogtopia/room/bushese.c new file mode 100644 index 0000000..32f2c3d --- /dev/null +++ b/lib/domains/oogtopia/room/bushese.c @@ -0,0 +1,33 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("tangled bushes"); + SetLong("the bushes are unkempt, and there appears to be ooga poo under one"); + SetItems(([ + ({ "poo", "ooga poo", "poop", "shit", "turd" }) : "This is some poo an ooga left under the bush", + ])); + SetExits( ([ + "north" : "/domains/oogtopia/room/bushesne", + "west" : "/domains/oogtopia/room/start", + "south" : "/domains/oogtopia/room/bushesse.c", + ]) ); + + SetTown("oogtopia"); + SetSmell(([ + ({ "ooga poo", "poo", "poop", "shit", "turd" }) : "This smells awful, it's not fresh but that makes it worse, the scent is almost enough to knock you over.", + ])); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/domains/oogtopia/room/bushesn.c b/lib/domains/oogtopia/room/bushesn.c new file mode 100644 index 0000000..bde8bf4 --- /dev/null +++ b/lib/domains/oogtopia/room/bushesn.c @@ -0,0 +1,32 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("tangled bushes"); + SetLong("the bushes are unkempt, and there appears to be ooga poo under one"); + SetItems(([ + ({ "poo", "ooga poo", "poop", "shit", "turd" }) : "This is some poo an ooga left under the bush", + ])); + SetExits( ([ + "south" : "/domains/oogtopia/room/start", + "west" : "/domains/oogtopia/room/field", + "east" : "/domains/oogtopia/room/bushesne.c", + ]) ); + SetTown("oogtopia"); + SetSmell(([ + ({ "ooga poo", "poo", "poop", "shit", "turd" }) : "This smells awful, it's not fresh but that makes it worse, the scent is almost enough to knock you over.", + ])); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/domains/oogtopia/room/bushesne.c b/lib/domains/oogtopia/room/bushesne.c new file mode 100644 index 0000000..59fb367 --- /dev/null +++ b/lib/domains/oogtopia/room/bushesne.c @@ -0,0 +1,32 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("Tangled Bushes"); + SetLong("the bushes are unkempt, and there appears to be ooga poo under one"); + SetItems(([ + ({ "poo", "ooga poo", "poop", "shit", "turd" }) : "This is some poo an ooga left under the bush", + ])); + SetExits( ([ + "west" : "/domains/oogtopia/room/bushesn", + "south" : "/domains/oogtopia/room/bushese.c", + ]) ); + + SetTown("oogtopia"); + SetSmell(([ + ({ "ooga poo", "poo", "poop", "shit", "turd" }) : "This smells awful, it's not fresh but that makes it worse, the scent is almost enough to knock you over.", + ])); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/domains/oogtopia/room/bushess.c b/lib/domains/oogtopia/room/bushess.c new file mode 100644 index 0000000..9a19914 --- /dev/null +++ b/lib/domains/oogtopia/room/bushess.c @@ -0,0 +1,33 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("Tangled Bushes"); + SetLong("the bushes are unkempt, and there appears to be ooga poo under one"); + SetItems(([ + ({ "poo", "ooga poo", "poop", "shit", "turd" }) : "This is some poo an ooga left under the bush", + ])); + SetExits( ([ + "north" : "/domains/oogtopia/room/start", + "west" : "/domains/oogtopia/room/bushessw", + "east" : "/domains/oogtopia/room/bushesse.c", + ]) ); + + SetTown("oogtopia"); + SetSmell(([ + ({ "ooga poo", "poo", "poop", "shit", "turd" }) : "This smells awful, it's not fresh but that makes it worse, the scent is almost enough to knock you over.", + ])); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/domains/oogtopia/room/bushesse.c b/lib/domains/oogtopia/room/bushesse.c new file mode 100644 index 0000000..351f4ac --- /dev/null +++ b/lib/domains/oogtopia/room/bushesse.c @@ -0,0 +1,32 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("Tangled Bushes"); + SetLong("the bushes are unkempt, and there appears to be ooga poo under one"); + SetItems(([ + ({ "poo", "ooga poo", "poop", "shit", "turd" }) : "This is some poo an ooga left under the bush", + ])); + SetExits( ([ + "west" : "/domains/oogtopia/room/bushess", + "north" : "/domains/oogtopia/room/bushese.c", + ]) ); + + SetTown("oogtopia"); + SetSmell(([ + ({ "ooga poo", "poo", "poop", "shit", "turd" }) : "This smells awful, it's not fresh but that makes it worse, the scent is almost enough to knock you over.", + ])); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/domains/oogtopia/room/bushessw.c b/lib/domains/oogtopia/room/bushessw.c new file mode 100644 index 0000000..2af6605 --- /dev/null +++ b/lib/domains/oogtopia/room/bushessw.c @@ -0,0 +1,32 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("Tangled Bushes"); + SetLong("the bushes are unkempt, and there appears to be ooga poo under one"); + SetItems(([ + ({ "poo", "ooga poo", "poop", "shit", "turd" }) : "This is some poo an ooga left under the bush", + ])); + SetExits( ([ + "north" : "/domains/oogtopia/room/bushesw", + "east" : "/domains/oogtopia/room/bushess.c", + ]) ); + + SetTown("oogtopia"); + SetSmell(([ + ({ "ooga poo", "poo", "poop", "shit", "turd" }) : "This smells awful, it's not fresh but that makes it worse, the scent is almost enough to knock you over.", + ])); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/domains/oogtopia/room/bushesw.c b/lib/domains/oogtopia/room/bushesw.c new file mode 100644 index 0000000..76a4651 --- /dev/null +++ b/lib/domains/oogtopia/room/bushesw.c @@ -0,0 +1,32 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("tangled bushes"); + SetLong("the bushes are unkempt, and there appears to be ooga poo under one"); + SetItems(([ + ({ "poo", "ooga poo", "poop", "shit", "turd" }) : "This is some poo an ooga left under the bush", + ])); + SetExits( ([ + "north" : "/domains/oogtopia/room/field", + "east" : "/domains/oogtopia/room/start", + "south" : "/domains/oogtopia/room/bushessw.c", + ]) ); + SetTown("oogtopia"); + SetSmell(([ + ({ "ooga poo", "poo", "poop", "shit", "turd" }) : "This smells awful, it's not fresh but that makes it worse, the scent is almost enough to knock you over.", + ])); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/domains/oogtopia/room/death.c b/lib/domains/oogtopia/room/death.c new file mode 100644 index 0000000..9a8de22 --- /dev/null +++ b/lib/domains/oogtopia/room/death.c @@ -0,0 +1,73 @@ +#include <lib.h> +#include <dirs.h> +#include ROOMS_H + +inherit LIB_ROOM; + +string FunkyPic(); +int CheckChat(); +int StartHeart(object ob); + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("off the mortal coil"); + SetLong( (:FunkyPic:) ); + SetObviousExits("no exit"); + set_heart_beat(10); + SetNoModify(1); +} + +void init(){ + ::init(); + add_action("regenerate","regenerate"); + add_action("regenerate","choose"); + add_action("wander","wander"); + this_object()->CheckChat(); +} + +string FunkyPic(){ + return "YOU ARE DEAD!!!"; +} + +int regenerate(){ + write("With a great rush of matter and energy, you rematerialize "+ + "into a corporeal state, and find yourself in a familiar place..."); + this_player()->eventRevive(); + this_player()->eventMoveLiving(ROOM_START); + return 1; +} + +int wander(){ + write("There is a strange, hollow vibration all around you, and you "+ + "realize that some force is compelling your ethereal form elsewhere..."+ + "you find yourself in a place that is known to you, yet oddly new."); + this_player()->eventMoveLiving(ROOM_START); + return 1; +} + +void heart_beat(){ + tell_room(this_object(), "A voice whispers: \" You may choose to "+ + "regenerate into a new body here.\""); + return; +} + + +int CanRelease(object ob){ + if(userp(ob) && ob->GetGhost() && environment(ob) == this_object()) { + tell_player(ob,"\n%^RED%^Your undead spirit is recalled and as you leave "+ + "the underworld a new body regenerates around you. "+ + "You live again!%^RESET%^\n"); + ob->eventRevive(); + } + return 1; +} + +int CanReceive(object ob){ + if(!living(ob)){ + return 0; + } + return ::CanReceive(ob); +} + diff --git a/lib/domains/oogtopia/room/field.c b/lib/domains/oogtopia/room/field.c new file mode 100644 index 0000000..96dca81 --- /dev/null +++ b/lib/domains/oogtopia/room/field.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetAmbientLight(30); + SetShort("a grassy field"); + SetLong("a grassy field, much of the grass is scorched where a spaceship has landed."); + SetItems(([ + "spaceship" : "A grand spaceship, completely out of place in this primitive utopia", + ])); + SetEnters( ([ + "spaceship" : "/domains/voluntaria/room/airlock.c", + ]) ); + SetTown("oogtopia"); + SetExits(([ + "south" : "/domains/oogtopia/room/bushesw", + "east" : "/domains/oogtopia/room/bushesn", + ])); + SetNoModify(0); + SetCoordinates("7002,7000,7000"); + + +} +void init(){ + ::init(); +} diff --git a/lib/domains/oogtopia/room/freezer.c b/lib/domains/oogtopia/room/freezer.c new file mode 100644 index 0000000..896cbbf --- /dev/null +++ b/lib/domains/oogtopia/room/freezer.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetNoClean(1); + SetProperties(([ "login" : ROOM_START ])); + SetShort( "The freezer"); + SetLong( "The local freezer. Go down to leave."); + SetObviousExits("down"); + SetExits( ([ "down" : ROOM_START ]) ); + call_out("clean_room", MAX_NET_DEAD_TIME); + SetNoModify(1); +} + +static void clean_room(){ + object ob; + call_out((: clean_room :), MAX_NET_DEAD_TIME); + foreach(ob in filter(all_inventory(), (: living($1) :))){ + string name = last_string_element(base_name(ob),"/"); + if(!user_exists(name)) continue; + ob->eventDestruct(); + } +} + +void init(){ + ::init(); +} diff --git a/lib/domains/oogtopia/room/furnace.c b/lib/domains/oogtopia/room/furnace.c new file mode 100644 index 0000000..240341a --- /dev/null +++ b/lib/domains/oogtopia/room/furnace.c @@ -0,0 +1,10 @@ +#include <lib.h> + +inherit LIB_FURNACE; + +void create() { + furnace::create(); +} +void init(){ + ::init(); +} diff --git a/lib/domains/oogtopia/room/pod.c b/lib/domains/oogtopia/room/pod.c new file mode 100644 index 0000000..62da2f9 --- /dev/null +++ b/lib/domains/oogtopia/room/pod.c @@ -0,0 +1,16 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("the incept pod"); + SetLong("The incept pod. Some objects come here to be created "+ + "and identified. Go down to get out."); + SetExits( ([ "down" : ROOM_START ]) ); +} +int CanReceive(object ob){ + return room::CanReceive(ob); +} diff --git a/lib/domains/oogtopia/room/start - Copy.c b/lib/domains/oogtopia/room/start - Copy.c new file mode 100644 index 0000000..f21c0c2 --- /dev/null +++ b/lib/domains/oogtopia/room/start - Copy.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("Ooga Booga Central"); + SetNightLong("This is where the Oogas have their parties, the sun is down and the party is in full swing. Drums, hooting and hollering, fermented drinks altough nothing distilled is permitted, and herbs and fungus of many varieties are all about."); + SetDayLong("This is where the Oogas get together and party, as long as the sun is up it's fairly sparsely attended, and any oogas around are likely nursing a hangover from the night before."); + SetExits( ([ + "west" : "/domains/oogtopia/room/bushesw", + "north" : "/domains/oogtopia/room/bushesn", + "east" : "/domains/oogtopia/room/bushese", + ]) ); + SetInventory(([ + "/domains/oogtopia/npc/party_ooga" : 5, + ])); + + SetTown("oogtopia"); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/domains/oogtopia/room/start.c b/lib/domains/oogtopia/room/start.c new file mode 100644 index 0000000..16dbb22 --- /dev/null +++ b/lib/domains/oogtopia/room/start.c @@ -0,0 +1,32 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("Ooga Booga Central"); + SetNightLong("This is where the Oogas have their parties, the sun is down and the party is in full swing. Drums, hooting and hollering, fermented drinks altough nothing distilled is permitted, and herbs and fungus of many varieties are all about."); + SetDayLong("This is where the Oogas get together and party, as long as the sun is up it's fairly sparsely attended, and any oogas around are likely nursing a hangover from the night before."); + SetExits( ([ + "north" : "/domains/oogtopia/room/bushesn", + "east" : "/domains/oogtopia/room/bushese", + "west" : "/domains/oogtopia/room/bushesw", + "south" : "/domains/oogtopia/room/bushess.c", + ]) ); + SetInventory(([ + "/domains/oogtopia/npc/party_ooga" : 5, + ])); + + SetTown("oogtopia"); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/domains/oogtopia/room/void.c b/lib/domains/oogtopia/room/void.c new file mode 100644 index 0000000..622a4ac --- /dev/null +++ b/lib/domains/oogtopia/room/void.c @@ -0,0 +1,16 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("the void"); + SetLong("The void. Go down to get out."); + SetExits( ([ "down" : ROOM_START ]) ); + SetNoModify(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/oogtopia/room/wiz_hall.c b/lib/domains/oogtopia/room/wiz_hall.c new file mode 100644 index 0000000..dba7910 --- /dev/null +++ b/lib/domains/oogtopia/room/wiz_hall.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Creators' Hall"); + SetLong("A generic Wiz Hall."); + SetProperty("no attack", 1); + SetProperty("nopeer",1); +} + +int CanReceive(object ob) { + if(playerp(ob) && !creatorp(ob) && !present("testchar badge",ob)) { + message("info","Creator staff only, sorry.", ob); + return 0; + } + return ::CanReceive(ob); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/oogtopia/virtual/server.c b/lib/domains/oogtopia/virtual/server.c new file mode 100644 index 0000000..a92b390 --- /dev/null +++ b/lib/domains/oogtopia/virtual/server.c @@ -0,0 +1,22 @@ +#define __DIR__ "/domains/oogtopia/virtual/" + +mixed compile_object(string file) { + string *path; + object ob; + int x, y, z, elements; + if(grepp(file, "/user_") || grepp(file, "/object_")){ + ob = new("/domains/oogtopia/virtual/void"); + if(!ob){ + return "No void room available."; + } + return ob; + } + path = explode(file, "/"); + if( file_size(__DIR__ + path[3] + ".c") < 1 ) return "bad file"; + if( (elements = sscanf(path[4], "%d,%d,%d", x, y, z)) != 3 ) { + if( (elements = sscanf(path[4], "%d,%d", x, y)) != 2 ) return "missing comma"; + } + if( elements == 2 && !(ob = new(__DIR__ + path[3], x, y)) ) return "failed to compile"; + else if( elements == 3 && !(ob = new(__DIR__ + path[3], x, y, z)) ) return "failed to compile"; + return ob; +} diff --git a/lib/domains/oogtopia/virtual/void.c b/lib/domains/oogtopia/virtual/void.c new file mode 100644 index 0000000..209c4b2 --- /dev/null +++ b/lib/domains/oogtopia/virtual/void.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <dirs.h> +#include <rooms.h> +#include <virtual.h> +#include <position.h> +#define __DIR__ "/domains/oogtopia/virtual/" + +inherit LIB_VIRT_LAND; + +varargs static void create(int x, int y) { + SetNoReplace(1); + virt_land::create(); + SetClimate("temperate"); + SetAmbientLight(30); + SetLong("A featureless void."); + SetShort("an empty place"); + AddExit("down", ROOM_START); +} diff --git a/lib/domains/town/armor/badge.c b/lib/domains/town/armor/badge.c new file mode 100644 index 0000000..c692e46 --- /dev/null +++ b/lib/domains/town/armor/badge.c @@ -0,0 +1,49 @@ +#include <lib.h> +#include ROOMS_H +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("visitor pass"); + SetId(({"testchar badge","badge","pass","visitor's pass"})); + SetShort("a test character Visitor's Pass"); + SetLong("This clip-on plastic badge grants the wearer access to "+ + "some areas typically restricted to creator staff only. Abuse of this "+ + "pass is grounds for disciplinary action. A small scribble "+ + "at the bottom of the pass reads: click heels"); + SetProperties(([ + "no steal" : 1, + ])); + SetMass(1); + SetBaseCost("silver",500); + SetArmorType(A_AMULET); + SetRetainOnDeath(1); + SetRestrictLimbs( ({ "torso" }) ); +} + +void init(){ + ::init(); + add_action("nplh","click"); +} + +int nplh(string str){ + if(str=="heels"){ + if(present(this_object()->GetKeyName(),this_player() ) ){ + write("There's no place like home!\n"+ + "You are transported by an awesome whirlwind somewhere "+ + "else...\n"); + this_player()->eventMoveLiving(ROOM_START); + return 1; + } + write("You click your heels together...but feel "+ + "as though you're missing something.\n"); + return 1; + } +} + +string GetAffectLong(object ob) { + if(!ob || !living(ob)) return 0; + return ob->GetName() + " is an authorized Test Character."; +} diff --git a/lib/domains/town/armor/bandanna.c b/lib/domains/town/armor/bandanna.c new file mode 100644 index 0000000..02d03f7 --- /dev/null +++ b/lib/domains/town/armor/bandanna.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("bandanna"); + SetAdjectives( ({"red"}) ); + SetId( ({"kerchief", "handkerchief"}) ); + SetShort("a red bandanna"); + SetLong("This is a red kerchief fashioned into improvised headgear, possibly to prevent getting dirt on one's hair and vice versa."); + SetMass(1); + SetBaseCost("silver",1); + SetArmorType(A_HELMET); + SetProtection(BLUNT, 1); + SetProtection(BLADE, 1); + SetProtection(KNIFE, 1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/barsmock.c b/lib/domains/town/armor/barsmock.c new file mode 100644 index 0000000..e99961d --- /dev/null +++ b/lib/domains/town/armor/barsmock.c @@ -0,0 +1,19 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("smock"); + SetAdjectives( ({"bar workers","food worker's"}) ); + SetId( ({"overalls", "smock", "simple"}) ); + SetShort("a simple smock"); + SetLong("This is a set of overalls used by food workers to keep their bodies and the food at a healthy distance."); + SetMass(50); + SetArmorType(A_BODY_ARMOR); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/bdu.c b/lib/domains/town/armor/bdu.c new file mode 100644 index 0000000..df03c61 --- /dev/null +++ b/lib/domains/town/armor/bdu.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("battle dress uniform"); + SetId(({"uniform","bdu","bdu's","fatigues"})); + SetAdjectives(({"camouflage","battle","dress","combat"})); + SetShort("a battle dress uniform"); + SetLong("This uniform consists of a camouflage blouse and "+ + "pants. It is green with mottled brown and black camouflage patterns, "+ + "and probably provides excellent concealment in a wooded environment."); + SetMass(10); + SetBaseCost("silver",100); + SetDamagePoints(100); + SetArmorType(A_BODY_ARMOR); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/bearskin.c b/lib/domains/town/armor/bearskin.c new file mode 100644 index 0000000..f4975fe --- /dev/null +++ b/lib/domains/town/armor/bearskin.c @@ -0,0 +1,35 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("bearskin"); + SetId(({"bearskin","bear skin"})); + SetAdjectives(({"thick","shaggy"})); + SetShort("a thick, shaggy bearskin"); + SetLong("This is a thick bearskin which can be worn "+ + "as armor. Unfortunately the hide "+ + "has not been tanned, so it's rather "+ + "foul-smelling."); + SetItems( ([ + "hide" : "It is untanned and subject "+ + "to natural decomposition." + ]) ); + SetSmell( ([ "default" : "It reeks of death." ]) ); + SetMass(75); + SetBaseCost("silver",10); + SetProtection(BLADE,5); + SetProtection(KNIFE,5); + SetArmorType(A_CLOAK); +} + +string GetAffectLong(object ob) { + if(!ob || !living(ob)) return 0; + return ob->GetName() + " reeks of death and decay."; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/bearsuit.c b/lib/domains/town/armor/bearsuit.c new file mode 100644 index 0000000..05018d6 --- /dev/null +++ b/lib/domains/town/armor/bearsuit.c @@ -0,0 +1,48 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +object bearshadow; + +static void create(){ + armor::create(); + SetKeyName("bearsuit"); + SetId(({"costume","bear costume","suit","bear suit"})); + SetAdjectives(({"realistic","terrific"})); + SetShort("a bear costume"); + SetLong("A terrific and very realistic suit which makes "+ + "the wearer look like a bear. It seems to have "+ + "been fashioned from real bear parts."); + SetMass(200); + SetMatching(0); + SetBaseCost("silver",800); + SetProtection(BLUNT,5); + SetProtection(BLADE,10); + SetProtection(KNIFE,10); + SetArmorType(A_BODY_ARMOR); +} + +void init(){ + ::init(); +} + +mixed eventEquip(object who, string array limbs){ + mixed success = armor::eventEquip(who, limbs); + bearshadow = new("/shadows/bear"); + if(success){ + if(bearshadow) bearshadow->eventShadow(who); + } + else if(bearshadow) destruct(bearshadow); + return success; +} + +varargs mixed eventUnequip(object who) { + mixed success; + if(!who) who = this_player(); + success = armor::eventUnequip(who); + if(success){ + if(bearshadow) who->unbearshadow(); + } + return success; +} diff --git a/lib/domains/town/armor/belt.c b/lib/domains/town/armor/belt.c new file mode 100644 index 0000000..4777718 --- /dev/null +++ b/lib/domains/town/armor/belt.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("belt"); + SetId(({"belt"})); + SetAdjectives(({"leather"})); + SetShort("a leather belt"); + SetLong("A belt made of leather."); + SetMass(5); + SetBaseCost("silver",10); + SetProtection(BLUNT,1); + SetProtection(BLADE,1); + SetProtection(KNIFE,1); + SetArmorType(A_BELT); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/boobytrap_ring.c b/lib/domains/town/armor/boobytrap_ring.c new file mode 100644 index 0000000..7dec4bd --- /dev/null +++ b/lib/domains/town/armor/boobytrap_ring.c @@ -0,0 +1,48 @@ +/* + * Note that this ring, unlike the boobytrapped dagger, does + * not check to see if it has been previously armed. This prevents + * a player from disarming the ring by simply logging out + * and logging back in. + */ + +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <boobytraps.h> + +inherit LIB_ARMOR; + +void boobytrap_me(){ + object shadowtrap; + if(!clonep(this_object())) return; /* Avoids boobytrapping the blueprint ob */ + + shadowtrap = new("/shadows/needle_trap"); + shadowtrap->SetTrapDescription("A poison needle trap."); + shadowtrap->SetTrapLevel(50); + shadowtrap->SetAutoResets(0); + shadowtrap->SetTrapType(BOOBYTRAP_WEAR); + shadowtrap->eventShadow(this_object()); +} + +static void create(){ + armor::create(); + SetKeyName("silver_ring"); + SetId(({"ring","silver ring"})); + SetAdjectives( ({"beautiful"}) ); + SetShort("a beautiful silver ring"); + SetLong("This is a simple but beautiful ring made of "+ + "silver, suitable for wearing on one's finger. The ring bears an inscription."); + SetMass(1); + SetBaseCost("silver",1000); + SetArmorType(A_RING); + SetItems(([ + ({"script","words","inscription","writing"}) : "Words engraved on the ring in a highly "+ + "stylized script." + ]) ); + SetRead(({"script","words","inscription","writing"}), "\"etaoin shrdlu\"" ); + boobytrap_me(); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/boot.c b/lib/domains/town/armor/boot.c new file mode 100644 index 0000000..3bfad45 --- /dev/null +++ b/lib/domains/town/armor/boot.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("leather boot"); + SetId(({"boot"})); + SetAdjectives(({"military","military-style","black","leather","combat"})); + SetShort("a black leather boot"); + SetLong("A military style combat boot, made of black leather."); + SetMass(20); + SetBaseCost("silver",25); + SetProtection(BLUNT,5); + SetProtection(BLADE,5); + SetProtection(KNIFE,5); + SetArmorType(A_BOOT); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/boot_l.c b/lib/domains/town/armor/boot_l.c new file mode 100644 index 0000000..6cc5b4f --- /dev/null +++ b/lib/domains/town/armor/boot_l.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("leather boot"); + SetId(({"boot","left boot"})); + SetAdjectives(({"military","military-style","black","leather","combat"})); + SetShort("a black leather boot"); + SetLong("A military style combat boot, made of black leather. It is "+ + "designed for wear on the left foot."); + SetMass(20); + SetBaseCost("silver",25); + SetProtection(BLUNT,5); + SetProtection(BLADE,5); + SetProtection(KNIFE,5); + SetArmorType(A_BOOT); + SetRestrictLimbs(({"left foot"})); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/boot_r.c b/lib/domains/town/armor/boot_r.c new file mode 100644 index 0000000..15d2284 --- /dev/null +++ b/lib/domains/town/armor/boot_r.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("leather boot"); + SetId(({"boot","right boot"})); + SetAdjectives(({"military","military-style","black","leather","combat"})); + SetShort("a black leather boot"); + SetLong("A military style combat boot, made of black leather. It is "+ + "designed for wear on the right foot."); + SetMass(20); + SetBaseCost("silver",25); + SetProtection(BLUNT,5); + SetProtection(BLADE,5); + SetProtection(KNIFE,5); + SetArmorType(A_BOOT); + SetRestrictLimbs(({"right foot"})); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/breather.c b/lib/domains/town/armor/breather.c new file mode 100644 index 0000000..f5609a6 --- /dev/null +++ b/lib/domains/town/armor/breather.c @@ -0,0 +1,32 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit "/domains/default/armor/breather"; + +string LongD(){ + string ret = "This remarkably small device fits over the "+ + "wearer's mouth, and provides a long supply of oxygenated "+ + "air. Its current charge level is "+ + to_int(percent(charge,maxcharge))+" percent."; + return ret; +} + +static void create(){ + ::create(); + SetKeyName("breathing mask"); + SetId(({"mask","breather","a98","apparatus","device"})); + SetAdjectives(({"a98","breathing"})); + SetShort("an A98 breathing device"); + SetLong( (: LongD :) ); + SetMass(30); + SetBaseCost("silver",900); + SetArmorType(A_CUSTOM); + SetRestrictLimbs( ({ "head"}) ); + AddSave( ({ "charge" }) ); + SetCharge(100); + SetMaxCharge(100); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/cap.c b/lib/domains/town/armor/cap.c new file mode 100644 index 0000000..ef1cb4b --- /dev/null +++ b/lib/domains/town/armor/cap.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("baseball cap"); + SetAdjectives( ({"red", "old", "greasy", "dirty", "baseball", "cat"}) ); + SetId( ({"cap", "hat", "cover"}) ); + SetShort("a red baseball cap"); + SetLong("A greasy, old, dirty baseball cap that was once mostly red, with " + "the word 'CAT' on the front."); + SetMass(5); + SetBaseCost("silver",1); + SetArmorType(A_HELMET); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/chainmail.c b/lib/domains/town/armor/chainmail.c new file mode 100644 index 0000000..194d8d0 --- /dev/null +++ b/lib/domains/town/armor/chainmail.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("chainmail shirt"); + SetId(({"armor","chainmail","mail","shirt","chain mail"})); + SetAdjectives(({"chainmail","sturdy","sturdy-looking","chain mail"})); + SetShort("a sturdy-looking chainmail shirt"); + SetLong("This is a shirt made of small, thin metal rings fashioned together as armor. "); + SetMass(200); + SetBaseCost("silver",800); + SetProtection(BLUNT,5); + SetProtection(BLADE,20); + SetProtection(KNIFE,20); + SetArmorType(A_ARMOR); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/cloak.c b/lib/domains/town/armor/cloak.c new file mode 100644 index 0000000..4af09a4 --- /dev/null +++ b/lib/domains/town/armor/cloak.c @@ -0,0 +1,32 @@ +/* This is kind of broken, sorry. Will maybe fix someday. */ + +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("a green cloak"); + SetId(({"cloak"})); + SetAdjectives(({"green","elven"})); + SetShort("a green cloak"); + SetLong("This is a cloak of elven design, green in color, with an attached hood. " + "One may \"wear hood on cloak\" with it, probably."); + SetMass(200); + SetBaseCost("silver",500); + SetDamagePoints(100); + SetProtection(BLADE,10); + SetProtection(KNIFE,10); + SetArmorType(A_CLOAK); + //AddItem(new("/domains/town/obj/cloak_hood")); +} + +void init(){ + ::init(); +} + +//The following are necessary in order to be +//able to see and manipulate the dummy object +mixed inventory_visible(){ return 1; } +mixed inventory_accessible(){ return 1; } diff --git a/lib/domains/town/armor/collar.c b/lib/domains/town/armor/collar.c new file mode 100644 index 0000000..cf3e12a --- /dev/null +++ b/lib/domains/town/armor/collar.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +inherit LIB_BANE; + +static void create(){ + armor::create(); + SetKeyName("collar"); + SetId(({"repellent_collar","bane"})); + SetAdjectives( ({"repellent","odd","plastic","white"}) ); + SetShort("a plastic collar"); + SetLong("This is a simple collar made of a soft white plastic. It "+ + "seems to be coated with a fine, clear resin. There is something "+ + "written on the collar."); + SetProperties(([ + "no steal" : 1, + ])); + SetRead("Disease and parasite repellent collar, test character use only."); + SetMass(10); + SetArmorType(A_COLLAR); + SetBane(({"all"})); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/glove.c b/lib/domains/town/armor/glove.c new file mode 100644 index 0000000..25b99df --- /dev/null +++ b/lib/domains/town/armor/glove.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ARMOR; + +static void create() { + armor::create(); + SetKeyName("leather glove"); + SetId( ({ "glove" }) ); + SetAdjectives( ({ "black","leather" }) ); + SetShort("a black leather glove"); + SetLong("A black glove with five fingers for a humanoid right hand."); + SetVendorType(VT_ARMOR); + SetMass(5); + SetBaseCost("silver",7); + SetArmorType(A_GLOVE); + SetProtection(BLUNT, 1); + SetProtection(BLADE, 1); + SetProtection(KNIFE, 2); + SetProtection(HEAT, 3); + SetProtection(COLD, 7); + SetFingers(5); + SetRestrictLimbs(({"right hand"})); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/glove_l.c b/lib/domains/town/armor/glove_l.c new file mode 100644 index 0000000..3ce4e8a --- /dev/null +++ b/lib/domains/town/armor/glove_l.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ARMOR; + +static void create() { + armor::create(); + SetKeyName("leather glove"); + SetId( ({ "glove" }) ); + SetAdjectives( ({ "black","leather","left" }) ); + SetShort("a black leather glove"); + SetLong("A black glove with five fingers designed for a left hand."); + SetVendorType(VT_ARMOR); + SetMass(5); + SetBaseCost("silver",7); + SetArmorType(A_GLOVE); + SetProtection(BLUNT, 1); + SetProtection(BLADE, 1); + SetProtection(KNIFE, 2); + SetProtection(HEAT, 3); + SetProtection(COLD, 7); + SetFingers(5); + SetRestrictLimbs(({"left hand"})); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/glove_r.c b/lib/domains/town/armor/glove_r.c new file mode 100644 index 0000000..5034ec1 --- /dev/null +++ b/lib/domains/town/armor/glove_r.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ARMOR; + +static void create() { + armor::create(); + SetKeyName("leather glove"); + SetId( ({ "glove" }) ); + SetAdjectives( ({ "black","leather","right" }) ); + SetShort("a black leather glove"); + SetLong("A black glove with five fingers designed for a right hand."); + SetVendorType(VT_ARMOR); + SetMass(5); + SetBaseCost("silver",7); + SetArmorType(A_GLOVE); + SetProtection(BLUNT, 1); + SetProtection(BLADE, 1); + SetProtection(KNIFE, 2); + SetProtection(HEAT, 3); + SetProtection(COLD, 7); + SetFingers(5); + SetRestrictLimbs(({"right hand"})); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/goggles.c b/lib/domains/town/armor/goggles.c new file mode 100644 index 0000000..3cb8f7c --- /dev/null +++ b/lib/domains/town/armor/goggles.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("goggles"); + SetId(({"goggles"})); + SetAdjectives(({"thick","driving","protective","eyewear"})); + SetShort("driving goggles"); + SetLong("A set of protective goggles for wearing during "+ + "high-speed travel."); + SetMass(5); + SetBaseCost("silver",30); + SetArmorType(A_VISOR); +} + +void init(){ + ::init(); +} + +int eventReceiveDamage(mixed agent, int type, int amt, int i, mixed array l){ + if(GetWorn()){ + tell_object(environment(this_object()), "The goggles! They "+ + "do nothing!"); + } + return ::eventReceiveDamage(agent, type, amt, i, l); +} + + diff --git a/lib/domains/town/armor/helmet.c b/lib/domains/town/armor/helmet.c new file mode 100644 index 0000000..631f47d --- /dev/null +++ b/lib/domains/town/armor/helmet.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("steel helmet"); + SetId(({"helmet","cover","steel"})); + SetAdjectives(({"steel","battle","hard"})); + SetShort("a steel helmet"); + SetLong("This is a helmet made of tough metal."); + SetMass(200); + SetBaseCost("silver",500); + SetArmorType(A_HELMET); + SetProtection(BLUNT, 20); + SetProtection(BLADE, 20); + SetProtection(KNIFE, 20); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/helmet2.c b/lib/domains/town/armor/helmet2.c new file mode 100644 index 0000000..7836933 --- /dev/null +++ b/lib/domains/town/armor/helmet2.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("kevlar helmet"); + SetId(({"helmet","cover","kevlar"})); + SetAdjectives(({"kevlar","battle","hard"})); + SetShort("a camouflaged kevlar helmet"); + SetLong("This is a military helmet made of a very tough "+ + "polymer fiber that provides excellent ballistic protection. It bears a "+ + "mottled camouflage design to aid in woodland concealment."); + SetMass(50); + SetBaseCost("silver",500); + SetArmorType(A_HELMET); + SetProtection(BLUNT, 25); + SetProtection(BLADE, 25); + SetProtection(KNIFE, 25); + SetProtection(PIERCE, 25); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/hshirt.c b/lib/domains/town/armor/hshirt.c new file mode 100644 index 0000000..d805690 --- /dev/null +++ b/lib/domains/town/armor/hshirt.c @@ -0,0 +1,20 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("shirt"); + SetAdjectives( ({"horse", "t", "simple", "cotton"}) ); + SetId( ({"tshirt", "t-shirt"}) ); + SetShort("a shirt"); + SetLong("A simple cotton shirt with a design of a horse drawn on it, and the slogan: 'I'm a little horse girl!'"); + SetMass(5); + SetBaseCost("silver",1); + SetArmorType(A_SHIRT); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/hunting_cap.c b/lib/domains/town/armor/hunting_cap.c new file mode 100644 index 0000000..8a36896 --- /dev/null +++ b/lib/domains/town/armor/hunting_cap.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("hunting cap"); + SetId(({"hat","headgear","cap"})); + SetAdjectives(({"soft","felt","hunting"})); + SetShort("a hunting cap"); + SetLong("This is a soft, felt cap one wears when hunting. "+ + "It has a single feather jauntily stuck to the side."); + SetMass(10); + SetBaseCost("silver",50); + SetDamagePoints(10); + SetArmorType(A_HELMET); + SetProtection(BLUNT, 1); + SetProtection(BLADE, 1); + SetProtection(KNIFE, 1); + SetItems( ([ + ({"pheasant","feather"}) : "Looks like a pheasant feather.", + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/jacket.c b/lib/domains/town/armor/jacket.c new file mode 100644 index 0000000..9b61cd9 --- /dev/null +++ b/lib/domains/town/armor/jacket.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("leather jacket"); + SetId(({"jacket"})); + SetAdjectives(({"black","leather"})); + SetShort("a black leather jacket"); + SetLong("This is a black jacket made of leather. "); + SetMass(50); + SetBaseCost("silver",100); + SetProtection(BLUNT,1); + SetProtection(BLADE,2); + SetProtection(KNIFE,5); + SetArmorType(A_ARMOR); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/jeans.c b/lib/domains/town/armor/jeans.c new file mode 100644 index 0000000..91074b3 --- /dev/null +++ b/lib/domains/town/armor/jeans.c @@ -0,0 +1,20 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("blue jeans"); + SetId(({"jeans","pants","blue jeans","bluejeans","denim"})); + SetAdjectives(({"blue","denim","comfortable","broken in","broken-in"})); + SetShort("a pair of blue jeans"); + SetLong("A comfortable pair of denim blue jeans."); + SetMass(20); + SetBaseCost("silver",1); + SetArmorType(A_PANTS); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/leather_armor.c b/lib/domains/town/armor/leather_armor.c new file mode 100644 index 0000000..107fd42 --- /dev/null +++ b/lib/domains/town/armor/leather_armor.c @@ -0,0 +1,34 @@ +/* /domains/Ylsrim/armor/artrell_armor.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 960302 + */ + +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ARMOR; + +static void create() { + armor::create(); + SetKeyName("leather armor"); + SetId( ({ "armor", "leather armor" }) ); + SetAdjectives( ({ "leather" }) ); + SetShort("a suit of leather armor"); + SetLong("An ordinary suit of leather armor. It is worn on one's arms, torso and legs."); + SetVendorType(VT_ARMOR); + SetMass(350); + SetValue(150); + SetProtection(BLUNT, 20); + SetProtection(BLADE, 20); + SetProtection(KNIFE, 25); + SetProtection(HEAT, 7); + SetProtection(COLD, 4); + SetProtection(SHOCK, 15); + SetArmorType(A_BODY_ARMOR); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/locket.c b/lib/domains/town/armor/locket.c new file mode 100644 index 0000000..1a357e0 --- /dev/null +++ b/lib/domains/town/armor/locket.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_WORN_STORAGE; + +static void create(){ + ::create(); + SetKeyName("necklace"); + SetId(({"necklace","chain" "locket"})); + SetAdjectives(({"silver","braided","finest"})); + SetShort("a silver necklace"); + SetLong("A braided chain, made of finest silver. A locket is on it."); + SetMass(50); + SetMaxCarry(300); + SetBaseCost("silver",1); + SetProtection(BLUNT,1); + SetProtection(BLADE,1); + SetProtection(KNIFE,1); + SetArmorType(A_COLLAR); + SetItems(([ + ({"locket"}) : "It bears the name of the man that Brandy loved.", + ])); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/long_boot_l.c b/lib/domains/town/armor/long_boot_l.c new file mode 100644 index 0000000..f271cb8 --- /dev/null +++ b/lib/domains/town/armor/long_boot_l.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("riding boot"); + SetId(({"boot"})); + SetAdjectives(({"long","riding","black","leather","left"})); + SetShort("a long riding boot"); + SetLong("A long riding boot, made of black leather. It is "+ + "designed for wear on the left foot and leg."); + SetMass(40); + SetBaseCost("silver",75); + SetProtection(BLUNT,5); + SetProtection(BLADE,5); + SetProtection(KNIFE,5); + SetArmorType(A_LONG_BOOT); + SetRestrictLimbs(({"left foot","left leg"})); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/long_boot_r.c b/lib/domains/town/armor/long_boot_r.c new file mode 100644 index 0000000..75cf8ee --- /dev/null +++ b/lib/domains/town/armor/long_boot_r.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("riding boot"); + SetId(({"boot"})); + SetAdjectives(({"long","riding","black","leather","right"})); + SetShort("a long riding boot"); + SetLong("A long riding boot, made of black leather. It is "+ + "designed for wear on the right foot and leg."); + SetMass(40); + SetBaseCost("silver",75); + SetProtection(BLUNT,5); + SetProtection(BLADE,5); + SetProtection(KNIFE,5); + SetArmorType(A_LONG_BOOT); + SetRestrictLimbs(({"right foot","right leg"})); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/long_glove.c b/lib/domains/town/armor/long_glove.c new file mode 100644 index 0000000..96ea75f --- /dev/null +++ b/lib/domains/town/armor/long_glove.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ARMOR; + +static void create() { + armor::create(); + SetKeyName("leather glove"); + SetId( ({ "glove" }) ); + SetAdjectives( ({ "black","leather" }) ); + SetShort("a long black leather glove"); + SetLong("A long black glove with five fingers."); + SetVendorType(VT_ARMOR); + SetMass(10); + SetBaseCost("silver",25); + SetArmorType(A_LONG_GLOVE); + SetProtection(BLUNT, 1); + SetProtection(BLADE, 1); + SetProtection(KNIFE, 2); + SetProtection(HEAT, 3); + SetProtection(COLD, 7); + SetFingers(5); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/long_sock.c b/lib/domains/town/armor/long_sock.c new file mode 100644 index 0000000..b926f96 --- /dev/null +++ b/lib/domains/town/armor/long_sock.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("sock"); + SetId(({"sock"})); + SetAdjectives(({"black","nylon","knee-length","knee","knee length"})); + SetShort("a long black nylon sock"); + SetLong("A long, knee-length sock, made of black nylon."); + SetMass(5); + SetBaseCost("silver",1); + SetProtection(BLUNT,1); + SetProtection(BLADE,1); + SetProtection(KNIFE,1); + SetArmorType(A_LONG_SOCK); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/lvest.c b/lib/domains/town/armor/lvest.c new file mode 100644 index 0000000..6f745ab --- /dev/null +++ b/lib/domains/town/armor/lvest.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("leather vest"); + SetAdjectives( ({"vest", "leather", "sturdy", "protective"}) ); + SetId(({"vest"})); + SetShort("a leather vest"); + SetLong("A sturdy leather vest that provides protection and warmth for the torso, while permitting a free range of motion for one's arms."); + SetMass(50); + SetBaseCost("silver", 100); + SetArmorType(A_VEST); + SetProtection(COLD, 10); + SetProtection(BLUNT, 1); + SetProtection(BLADE, 5); + SetProtection(KNIFE, 5); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/magical_platemail.c b/lib/domains/town/armor/magical_platemail.c new file mode 100644 index 0000000..dd95593 --- /dev/null +++ b/lib/domains/town/armor/magical_platemail.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("suit of armor"); + SetId(({"armor","plate mail","platemail","suit","armor","suit of armor"})); + SetAdjectives(({"full","plate","plated","metal"})); + SetShort("a full suit of armor"); + SetLong("This is a large, very heavy suit of armor, the kind "+ + "one might expect a knight to wear. The thick "+ + "metal plating promises extraordinary protection, "+ + "yet the joints are so finely articulated as to "+ + "permit great freedom of movement."); + SetMass(900); + SetBaseCost("silver",10000); + SetDamagePoints(100); + SetProtection(BLUNT,40); + SetProtection(BLADE,60); + SetProtection(KNIFE,60); + SetProtection(PIERCE,60); + SetArmorType(A_BODY_ARMOR); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/mhelmet.c b/lib/domains/town/armor/mhelmet.c new file mode 100644 index 0000000..aaaaefa --- /dev/null +++ b/lib/domains/town/armor/mhelmet.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("motorcycle helmet"); + SetId(({"helmet","cover","motorcycle"})); + SetAdjectives(({"motorcycle","battle","hard"})); + SetShort("a black motorcycle helmet"); + SetLong("This is a helmet made of tough composite materials."); + SetMass(50); + SetBaseCost("silver",200); + SetArmorType(A_HELMET); + SetProtection(BLUNT, 20); + SetProtection(BLADE, 20); + SetProtection(KNIFE, 20); + SetProtection(PIERCE, 20); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/newbie_ring.c b/lib/domains/town/armor/newbie_ring.c new file mode 100644 index 0000000..0567db6 --- /dev/null +++ b/lib/domains/town/armor/newbie_ring.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("gold ring"); + SetId(({"ring","gold ring"})); + SetAdjectives( ({"beautiful"}) ); + SetShort("a beautiful gold ring"); + SetLong("This is a simple but beautiful ring made of "+ + "gold, suitable for wearing on one's finger."); + SetMass(1); + SetBaseCost("silver",500); + SetArmorType(A_RING); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/oldstyle_ring.c b/lib/domains/town/armor/oldstyle_ring.c new file mode 100644 index 0000000..ab96715 --- /dev/null +++ b/lib/domains/town/armor/oldstyle_ring.c @@ -0,0 +1,20 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("metal ring"); + SetId(({"ring"})); + SetAdjectives( ({"simple","metal"}) ); + SetShort("a simple ring"); + SetLong("This is a simple metal ring."); + SetMass(1); + SetValue(100); + SetArmorType(A_RING); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/orc_boot_l.c b/lib/domains/town/armor/orc_boot_l.c new file mode 100644 index 0000000..cfa27ff --- /dev/null +++ b/lib/domains/town/armor/orc_boot_l.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("leather boot"); + SetAdjectives( ({"leather", "simple", "orc", "orcish", "inelegant", "protective"}) ); + SetId(({"boot","left boot"})); + SetShort("a leather boot"); + SetLong("A leather boot of orcish design. Simple and inelegant, but quite protective. It is designed for the left foot."); + SetMass(60); + SetBaseCost("silver", 30); + SetProtection(BLUNT,5); + SetProtection(BLADE,5); + SetProtection(KNIFE,5); + SetArmorType(A_BOOT); + SetRestrictLimbs(({"left foot"})); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/orc_boot_r.c b/lib/domains/town/armor/orc_boot_r.c new file mode 100644 index 0000000..aceb95e --- /dev/null +++ b/lib/domains/town/armor/orc_boot_r.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("leather boot"); + SetAdjectives( ({"leather", "simple", "orc", "orcish", "inelegant", "protective"}) ); + SetId(({"boot","right boot"})); + SetShort("a leather boot"); + SetLong("A leather boot of orcish design. Simple and inelegant, but quite protective. It is designed for the right foot."); + SetMass(60); + SetBaseCost("silver", 30); + SetProtection(BLUNT,5); + SetProtection(BLADE,5); + SetProtection(KNIFE,5); + SetArmorType(A_BOOT); + SetRestrictLimbs(({"right foot"})); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/orc_helmet.c b/lib/domains/town/armor/orc_helmet.c new file mode 100644 index 0000000..6fc722f --- /dev/null +++ b/lib/domains/town/armor/orc_helmet.c @@ -0,0 +1,45 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +varargs int CheckOrc(object who, mixed where); + +static void create(){ + armor::create(); + SetKeyName("orc helmet"); + SetId(({"helmet","skull"})); + SetAdjectives(({"bear","bone","skull","orc"})); + SetShort("a bear skull helmet"); + SetLong("This is a helmet made of the hard bone of a bear, "+ + "treated with some sort of thick resin to "+ + "prevent shattering."); + SetMass(150); + SetBaseCost("silver",100); + SetArmorType(A_HELMET); + SetProtection(BLUNT, 20); + SetProtection(BLADE, 20); + SetProtection(KNIFE, 20); + SetWear( (: CheckOrc :) ); +} + +varargs int CheckOrc(object who, mixed where){ + string race = who->GetRace(); + object env = environment(who); + if( race == "orc" || race == "half-orc"){ + who->eventPrint("You can almost feel the power of the bear as you "+ + "wear its skull."); + if(env) tell_room(env, who->GetName()+" wears "+ + GetShort()+".", ({who})); + return 1; + } + else { + who->eventPrint("The helmet appears designed for orcish anatomy. "+ + "It does not fit you."); + return 0; + } +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/overalls.c b/lib/domains/town/armor/overalls.c new file mode 100644 index 0000000..84ded90 --- /dev/null +++ b/lib/domains/town/armor/overalls.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_WORN_STORAGE; + +static void create(){ + ::create(); + SetKeyName("overalls"); + SetId(({"overalls","pants", "trousers"})); + SetAdjectives(({"worn","abused","pair of","set of"})); + SetShort("a pair of overalls"); + SetLong("This is a set of worn and abused overall trousers with large pockets " + "for carrying stuff."); + SetMass(50); + SetMaxCarry(300); + SetBaseCost("silver",1); + SetProtection(BLUNT,1); + SetProtection(BLADE,1); + SetProtection(KNIFE,1); + SetArmorType(A_CUSTOM); + SetRestrictLimbs( ({ "right leg","left leg","torso" }) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/overcoat.c b/lib/domains/town/armor/overcoat.c new file mode 100644 index 0000000..c6d53d4 --- /dev/null +++ b/lib/domains/town/armor/overcoat.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("overcoat"); + SetId(({"coat","overcoat"})); + SetAdjectives(({"heavy","woolen"})); + SetShort("a heavy woolen overcoat"); + SetLong("This is a large overcoat, of fine craftsmanship. It's "+ + "likely excellent protection against the cold."); + SetMass(60); + SetBaseCost("silver",300); + SetProtection(BLUNT,10); + SetProtection(BLADE,10); + SetProtection(KNIFE,10); + SetProtection(COLD,5); + SetArmorType(A_CLOAK); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/pants.c b/lib/domains/town/armor/pants.c new file mode 100644 index 0000000..ba1f70f --- /dev/null +++ b/lib/domains/town/armor/pants.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("leather pants"); + SetId(({"pants"})); + SetAdjectives(({"strong","leather","black","tough"})); + SetShort("leather pants"); + SetLong("These are trousers made of strong, tough leather. "); + SetMass(150); + SetBaseCost("silver",110); + SetProtection(BLADE,10); + SetProtection(KNIFE,10); + SetArmorType(A_PANTS); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/platemail.c b/lib/domains/town/armor/platemail.c new file mode 100644 index 0000000..45d28a6 --- /dev/null +++ b/lib/domains/town/armor/platemail.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("suit of armor"); + SetId(({"armor","plate mail","platemail","suit","armor","suit of armor"})); + SetAdjectives(({"full","plate","plated","metal"})); + SetShort("a full suit of armor"); + SetLong("This is a large, very heavy suit of armor, the kind "+ + "one might expect a knight to wear. The thick "+ + "metal plating promises extraordinary protection, "+ + "yet the joints are so finely articulated as to "+ + "permit great freedom of movement."); + SetMass(1000); + SetBaseCost("silver",10000); + SetProtection(BLUNT,60); + SetProtection(BLADE,90); + SetProtection(KNIFE,90); + SetArmorType(A_BODY_ARMOR); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/riding_boot.c b/lib/domains/town/armor/riding_boot.c new file mode 100644 index 0000000..c3d2c40 --- /dev/null +++ b/lib/domains/town/armor/riding_boot.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("riding boot"); + SetId(({"boot"})); + SetAdjectives(({"long","riding","black","leather"})); + SetShort("a long riding boot"); + SetLong("A long riding boot, made of black leather."); + SetMass(30); + SetBaseCost("silver",75); + SetProtection(BLUNT,5); + SetProtection(BLADE,5); + SetProtection(KNIFE,5); + SetArmorType(A_BOOT); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/ring.c b/lib/domains/town/armor/ring.c new file mode 100644 index 0000000..c868211 --- /dev/null +++ b/lib/domains/town/armor/ring.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("ring"); + SetId(({"ring","gold ring"})); + SetAdjectives( ({"beautiful"}) ); + SetShort("a beautiful gold ring"); + SetLong("This is a simple but beautiful ring made of "+ + "gold, suitable for wearing on one's finger."); + SetMass(1); + SetBaseCost("silver",5000); + SetArmorType(A_RING); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/robe.c b/lib/domains/town/armor/robe.c new file mode 100644 index 0000000..34a00e7 --- /dev/null +++ b/lib/domains/town/armor/robe.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("wizard's robe"); + SetId(({"robe","cloak","duster"})); + SetAdjectives(({"wizard","wizard's","soft"})); + SetShort("a robe"); + SetLong("This is a large, comfortable-looking robe, like a wizard might wear. "); + SetMass(200); + SetBaseCost("silver",100); + SetProtection(BLUNT,100); + SetProtection(BLADE,100); + SetProtection(KNIFE,100); + SetArmorType(A_CLOAK); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/rocketpack.c b/lib/domains/town/armor/rocketpack.c new file mode 100644 index 0000000..dfc6159 --- /dev/null +++ b/lib/domains/town/armor/rocketpack.c @@ -0,0 +1,35 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <medium.h> +inherit "/domains/default/armor/rocketpack"; + + +string LongD(){ + string ret = "This is a small device worn on the back and designed to \"boost\" " + + "the wearer through the air or through space. For continuous operation, "+ + "it should probably be activated. The fuel gauge "+ + "reads "+to_int(percent(charge,maxcharge))+" percent."; + return ret; +} + +static void create(){ + ::create(); + if(!Directions) Directions = ([]); + SetKeyName("rocket pack"); + SetId(({"pack","rocket","rocketpack"})); + SetAdjectives(({"small","rocket"})); + SetShort("a small rocket pack"); + SetLong( (: LongD :) ); + SetMass(500); + SetBaseCost(8000); + SetArmorType(A_ARMOR); + AddSave( ({ "charge", "Directions" }) ); + SetRestrictLimbs( ({ "torso" }) ); + SetCharge(200); + SetMaxCharge(200); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/scarf.c b/lib/domains/town/armor/scarf.c new file mode 100644 index 0000000..5700909 --- /dev/null +++ b/lib/domains/town/armor/scarf.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("scarf"); + SetId(({"scarf"})); + SetAdjectives( ({"handsome","tartan"}) ); + SetShort("a handsome tartan scarf"); + SetLong("This a handsome scarf, very comfortable and "+ + "probably expensive as well."); + SetMass(3); + SetBaseCost("silver", 350); + SetArmorType(A_COLLAR); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/shield.c b/lib/domains/town/armor/shield.c new file mode 100644 index 0000000..46300c2 --- /dev/null +++ b/lib/domains/town/armor/shield.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ARMOR; + +static void create() { + armor::create(); + SetKeyName("large shield"); + SetId( ({ "shield" }) ); + SetAdjectives( ({ "wood", "wooden","large" }) ); + SetShort("a large wooden shield"); + SetLong("A large, heavy shield made of strong wood banded with iron."); + SetVendorType(VT_ARMOR); + SetMass(100); + SetBaseCost("silver",250); + SetArmorType(A_SHIELD); + SetProtection(BLUNT, 10); + SetProtection(BLADE, 10); + SetProtection(KNIFE, 10); + //SetRestrictLimbs( ({"left hand"}) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/shirt.c b/lib/domains/town/armor/shirt.c new file mode 100644 index 0000000..a6c5f52 --- /dev/null +++ b/lib/domains/town/armor/shirt.c @@ -0,0 +1,20 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("a white t-shirt"); + SetId(({"shirt","tshirt","t-shirt","t shirt"})); + SetAdjectives(({"white"})); + SetShort("a white t-shirt"); + SetLong("An ordinary white t-shirt."); + SetMass(2); + SetBaseCost("silver",1); + SetArmorType(A_SHIRT); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/silverring.c b/lib/domains/town/armor/silverring.c new file mode 100644 index 0000000..2f36670 --- /dev/null +++ b/lib/domains/town/armor/silverring.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("silver_ring"); + SetId(({"ring","silver ring"})); + SetAdjectives( ({"beautiful"}) ); + SetShort("a beautiful silver ring"); + SetLong("This is a simple but beautiful ring made of "+ + "silver, suitable for wearing on one's finger. The ring bears an inscription."); + SetMass(1); + SetBaseCost("silver",5000); + SetArmorType(A_RING); + SetItems(([ + ({"script","words","inscription","writing"}) : "Words engraved on the ring in a highly "+ + "stylized script." + ]) ); + SetRead(({"script","words","inscription","writing"}), "\"etaoin shrdlu\"" ); + +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/sock.c b/lib/domains/town/armor/sock.c new file mode 100644 index 0000000..ffd0598 --- /dev/null +++ b/lib/domains/town/armor/sock.c @@ -0,0 +1,20 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("sock"); + SetId(({"sock"})); + SetAdjectives(({"white","cotton","athletic"})); + SetShort("a white cotton sock"); + SetLong("An athletic sock, made of white cotton."); + SetMass(5); + SetBaseCost("silver",1); + SetArmorType(A_SOCK); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/toga.c b/lib/domains/town/armor/toga.c new file mode 100644 index 0000000..5ffcbe4 --- /dev/null +++ b/lib/domains/town/armor/toga.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("healer's toga"); + SetId(({"toga"})); + SetAdjectives(({"long","white","comfotable"})); + SetShort("a long, white toga"); + SetLong("This is a comfortable, full-length toga. It is the sort of " + "elegant garment that ancient politicians and healers once wore."); + SetMass(75); + SetBaseCost("silver",100); + SetProtection(BLUNT,1); + SetProtection(BLADE,10); + SetProtection(KNIFE,10); + SetArmorType(A_CLOAK); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/towel.c b/lib/domains/town/armor/towel.c new file mode 100644 index 0000000..7353019 --- /dev/null +++ b/lib/domains/town/armor/towel.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("damp towel"); + SetId(({"towel"})); + SetAdjectives(({"damp","bath","ordinary", "bathtowel"})); + SetShort("a damp towel"); + SetLong("This is an ordinary bath towel."); + SetMass(25); + SetBaseCost("silver",10); + SetProtection(BLUNT,1); + SetProtection(BLADE,1); + SetProtection(KNIFE,1); + SetArmorType(A_PANTS); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/tshirt.c b/lib/domains/town/armor/tshirt.c new file mode 100644 index 0000000..da52271 --- /dev/null +++ b/lib/domains/town/armor/tshirt.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("a Def Leppard shirt"); + SetId(({"shirt","def leppard shirt"})); + SetAdjectives(({"Def Leppard", "def leppard", "stupid", "black"})); + SetShort("a Def Leppard shirt"); + SetLong("A stupid-looking black shirt with a ridiculous band logo on it."); + SetMass(5); + SetBaseCost("silver",1); + SetProtection(BLUNT,1); + SetProtection(BLADE,1); + SetProtection(KNIFE,1); + SetArmorType(A_SHIRT); + //SetRestrictLimbs(({"torso"})); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/vest.c b/lib/domains/town/armor/vest.c new file mode 100644 index 0000000..fd5037f --- /dev/null +++ b/lib/domains/town/armor/vest.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("paisley vest"); + SetId(({"vest"})); + SetAdjectives(({"goofy","goofy-looking", "goofy looking", "paisley","colorful","hippie","hippy","psychedelic"})); + SetShort("a colorful paisley vest"); + SetLong("A goofy-looking hippie vest with psychedelic paisley patterns on it."); + SetMass(5); + SetBaseCost("silver",1); + SetProtection(BLUNT,1); + SetProtection(BLADE,1); + SetProtection(KNIFE,1); + SetArmorType(A_VEST); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/visor.c b/lib/domains/town/armor/visor.c new file mode 100644 index 0000000..8876d2e --- /dev/null +++ b/lib/domains/town/armor/visor.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("goggles"); + SetId(({"goggles"})); + SetAdjectives(({"clear","plastic","protective","lab","laboratory"})); + SetShort("clear plastic goggles"); + SetLong("A set of protective laboratory goggles."); + SetMass(5); + SetBaseCost("silver",9); + SetDamagePoints(1); + SetProtection(BLUNT,1); + SetProtection(BLADE,1); + SetProtection(KNIFE,1); + SetArmorType(A_VISOR); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/wizard_hat.c b/lib/domains/town/armor/wizard_hat.c new file mode 100644 index 0000000..3527164 --- /dev/null +++ b/lib/domains/town/armor/wizard_hat.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("wizard hat"); + SetId(({"hat","headgear"})); + SetAdjectives(({"wizard","wizard's"})); + SetShort("a wizard's hat"); + SetLong("This is a large, floppy hat with a wide brim all "+ + "around it, and a conical center. It is dark blue in color, "+ + "and is decorated with pictures of yellow moons and stars."); + SetMass(50); + SetBaseCost("silver",500); + SetArmorType(A_HELMET); + SetProtection(BLUNT, 20); + SetProtection(BLADE, 20); + SetProtection(KNIFE, 20); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/workboot_l.c b/lib/domains/town/armor/workboot_l.c new file mode 100644 index 0000000..45a4b67 --- /dev/null +++ b/lib/domains/town/armor/workboot_l.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("workboot"); + SetAdjectives( ({"strong", "brown", "leather", "left", "work", "heavy"}) ); + SetId( ({"boot"}) ); + SetShort("a brown leather workboot"); + SetLong("A heavy, brown leather workboot with strong ankle and sole support. It is designed for wear on the left foot."); + SetMass(40); + SetBaseCost("silver",25); + SetProtection(BLUNT,5); + SetProtection(BLADE,5); + SetProtection(KNIFE,5); + SetArmorType(A_BOOT); + SetRestrictLimbs(({"left foot"})); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/workboot_r.c b/lib/domains/town/armor/workboot_r.c new file mode 100644 index 0000000..b15aaaa --- /dev/null +++ b/lib/domains/town/armor/workboot_r.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("workboot"); + SetAdjectives( ({"strong", "brown", "leather", "work", "right", "heavy"}) ); + SetId( ({"boot"}) ); + SetShort("a brown leather workboot"); + SetLong("A heavy, brown leather workboot with strong ankle and sole support. It is designed for wear on the right foot."); + SetMass(40); + SetBaseCost("silver",25); + SetProtection(BLUNT,5); + SetProtection(BLADE,5); + SetProtection(KNIFE,5); + SetArmorType(A_BOOT); + SetRestrictLimbs(({"right foot"})); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/workglove_l.c b/lib/domains/town/armor/workglove_l.c new file mode 100644 index 0000000..90bcdc3 --- /dev/null +++ b/lib/domains/town/armor/workglove_l.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ARMOR; + +static void create() { + armor::create(); + SetKeyName("workglove"); + SetAdjectives( ({"work", "brown", "leather", "left"}) ); + SetId( ({ "glove" }) ); + SetShort("a leather work glove"); + SetLong("A thick, brown leather work glove, designed for wear on the left hand."); + SetVendorType(VT_ARMOR); + SetMass(10); + SetBaseCost("silver",7); + SetArmorType(A_GLOVE); + SetProtection(BLUNT, 1); + SetProtection(BLADE, 1); + SetProtection(KNIFE, 2); + SetProtection(HEAT, 3); + SetProtection(COLD, 7); + SetFingers(5); + SetRestrictLimbs(({"left hand"})); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/armor/workglove_r.c b/lib/domains/town/armor/workglove_r.c new file mode 100644 index 0000000..0af383a --- /dev/null +++ b/lib/domains/town/armor/workglove_r.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ARMOR; + +static void create() { + armor::create(); + SetKeyName("workglove"); + SetAdjectives( ({"work", "brown", "leather", "thick", "right"}) ); + SetId( ({ "glove" }) ); + SetShort("a leather work glove"); + SetLong("A thick, brown leather work glove, designed for wear on the right hand."); + SetVendorType(VT_ARMOR); + SetMass(10); + SetBaseCost("silver",7); + SetArmorType(A_GLOVE); + SetProtection(BLUNT, 1); + SetProtection(BLADE, 1); + SetProtection(KNIFE, 2); + SetProtection(HEAT, 3); + SetProtection(COLD, 7); + SetFingers(5); + SetRestrictLimbs(({"right hand"})); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/doors/down.c b/lib/domains/town/doors/down.c new file mode 100644 index 0000000..b67611d --- /dev/null +++ b/lib/domains/town/doors/down.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("DIR_X", ([ "id" : ({"door leading DIR_X", "door", "DIR_X door"}), + "short" : "a door leading DIR_X", + "long" : "This is the Y_SIDE side of a door leading DIR_X.", + "lockable" : 1 ]) ); + + SetSide("DIR_Y", ([ "id" : ({"door leading DIR_Y", "door", "DIR_Y door"}), + "short" : "a door leading DIR_Y", + "long" : "This is the X_SIDE side of a door leading DIR_Y.", + "lockable" : 1 ]) ); + + SetClosed(1); + SetLocked(0); + SetKeys("DIR_X", ({ "DIR_X key" })); + SetKeys("DIR_Y", ({ "DIR_Y key" })); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/doors/gate.c b/lib/domains/town/doors/gate.c new file mode 100644 index 0000000..cec5ac5 --- /dev/null +++ b/lib/domains/town/doors/gate.c @@ -0,0 +1,29 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("northeast", ([ "id" : ({"gate leading northeast", "gate", "northeast gate"}), + "short" : "a gate leading northeast", + "long" : "This is the southwest side of a gate leading northeast.", + "lockable" : 1 ]) ); + + SetSide("southwest", ([ "id" : ({"gate leading southwest", "gate", "southwest gate"}), + "short" : "a gate leading southwest", + "long" : "This is the northeast side of a gate leading southwest.", + "lockable" : 1 ]) ); + + SetPerforated(1); + SetClosed(1); + SetLocked(1); + SetLockStrength(90); + SetKeys("northeast", ({ "cavetroll key" })); + SetKeys("southwest", ({ "cavetroll key" })); + SetOpacity(0); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/doors/grate.c b/lib/domains/town/doors/grate.c new file mode 100644 index 0000000..b2a1f39 --- /dev/null +++ b/lib/domains/town/doors/grate.c @@ -0,0 +1,37 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("down", ([ "id" : ({"grate leading down", "grate", "down grate"}), + "short" : "a grate leading down", + "long" : "This is the up side of a grate leading down. It looks very heavy.", + "lockable" : 0 ]) ); + + SetSide("up", ([ "id" : ({"grate leading up", "grate", "up grate"}), + "short" : "a grate leading up", + "long" : "This is the down side of a grate leading up. It looks very heavy.", + "lockable" : 0 ]) ); + + SetPerforated(1); + SetClosed(1); + SetLocked(0); +} + +varargs mixed CanOpen(object ob, string id){ + mixed ret = ::CanOpen(ob, id); + if(!ret || !intp(ret)) return ret; + if(ob->GetStatLevel("strength") > 49){ + return 1; + } + else { + write("You lack sufficient physical strength!"); + return 0; + } +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/doors/house_door.c b/lib/domains/town/doors/house_door.c new file mode 100644 index 0000000..130cc92 --- /dev/null +++ b/lib/domains/town/doors/house_door.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("south", ([ "id" : ({"door leading south", "door", "south door"}), + "short" : "a door leading south", + "long" : "This is the north side of a door leading south.", + "lockable" : 1 ]) ); + + SetSide("north", ([ "id" : ({"door leading north", "door", "north door"}), + "short" : "a door leading north", + "long" : "This is the south side of a door leading north.", + "lockable" : 1 ]) ); + + SetClosed(1); + SetLocked(0); + SetKeys("south", ({ "south key" })); + SetKeys("north", ({ "north key" })); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/doors/m1.c b/lib/domains/town/doors/m1.c new file mode 100644 index 0000000..08e55c7 --- /dev/null +++ b/lib/domains/town/doors/m1.c @@ -0,0 +1,24 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("east", ([ "id" : ({"door leading east", "door", "east door"}), + "short" : "a door leading east", + "long" : "This is the west side of a door leading east.", + "lockable" : 1 ]) ); + + SetSide("west", ([ "id" : ({"door leading west", "door", "west door"}), + "short" : "a door leading west", + "long" : "This is the east side of a door leading west.", + "lockable" : 1 ]) ); + + SetClosed(0); + SetLocked(0); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/doors/m2.c b/lib/domains/town/doors/m2.c new file mode 100644 index 0000000..3e56ea3 --- /dev/null +++ b/lib/domains/town/doors/m2.c @@ -0,0 +1,24 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("west", ([ "id" : ({"door leading west", "door", "west door"}), + "short" : "a door leading west", + "long" : "This is the east side of a door leading west.", + "lockable" : 1 ]) ); + + SetSide("east", ([ "id" : ({"door leading east", "door", "east door"}), + "short" : "a door leading east", + "long" : "This is the west side of a door leading east.", + "lockable" : 1 ]) ); + + SetClosed(0); + SetLocked(0); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/doors/m3.c b/lib/domains/town/doors/m3.c new file mode 100644 index 0000000..3e56ea3 --- /dev/null +++ b/lib/domains/town/doors/m3.c @@ -0,0 +1,24 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("west", ([ "id" : ({"door leading west", "door", "west door"}), + "short" : "a door leading west", + "long" : "This is the east side of a door leading west.", + "lockable" : 1 ]) ); + + SetSide("east", ([ "id" : ({"door leading east", "door", "east door"}), + "short" : "a door leading east", + "long" : "This is the west side of a door leading east.", + "lockable" : 1 ]) ); + + SetClosed(0); + SetLocked(0); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/doors/m4.c b/lib/domains/town/doors/m4.c new file mode 100644 index 0000000..3e56ea3 --- /dev/null +++ b/lib/domains/town/doors/m4.c @@ -0,0 +1,24 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("west", ([ "id" : ({"door leading west", "door", "west door"}), + "short" : "a door leading west", + "long" : "This is the east side of a door leading west.", + "lockable" : 1 ]) ); + + SetSide("east", ([ "id" : ({"door leading east", "door", "east door"}), + "short" : "a door leading east", + "long" : "This is the west side of a door leading east.", + "lockable" : 1 ]) ); + + SetClosed(0); + SetLocked(0); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/doors/m5.c b/lib/domains/town/doors/m5.c new file mode 100644 index 0000000..3e56ea3 --- /dev/null +++ b/lib/domains/town/doors/m5.c @@ -0,0 +1,24 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("west", ([ "id" : ({"door leading west", "door", "west door"}), + "short" : "a door leading west", + "long" : "This is the east side of a door leading west.", + "lockable" : 1 ]) ); + + SetSide("east", ([ "id" : ({"door leading east", "door", "east door"}), + "short" : "a door leading east", + "long" : "This is the west side of a door leading east.", + "lockable" : 1 ]) ); + + SetClosed(0); + SetLocked(0); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/doors/m6.c b/lib/domains/town/doors/m6.c new file mode 100644 index 0000000..3e56ea3 --- /dev/null +++ b/lib/domains/town/doors/m6.c @@ -0,0 +1,24 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("west", ([ "id" : ({"door leading west", "door", "west door"}), + "short" : "a door leading west", + "long" : "This is the east side of a door leading west.", + "lockable" : 1 ]) ); + + SetSide("east", ([ "id" : ({"door leading east", "door", "east door"}), + "short" : "a door leading east", + "long" : "This is the west side of a door leading east.", + "lockable" : 1 ]) ); + + SetClosed(0); + SetLocked(0); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/doors/m7.c b/lib/domains/town/doors/m7.c new file mode 100644 index 0000000..94763ce --- /dev/null +++ b/lib/domains/town/doors/m7.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("south", ([ "id" : ({"door leading south", "door", "south door"}), + "short" : "a door leading south", + "long" : "This is the north side of a door leading south.", + "lockable" : 1 ]) ); + + SetSide("north", ([ "id" : ({"door leading north", "door", "north door"}), + "short" : "a door leading north", + "long" : "This is the south side of a door leading north.", + "lockable" : 1 ]) ); + + SetClosed(1); + SetLocked(1); + SetKeys("south", ({ "mansion key" })); + SetKeys("north", ({ "mansion key" })); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/doors/mansion.c b/lib/domains/town/doors/mansion.c new file mode 100644 index 0000000..57234d6 --- /dev/null +++ b/lib/domains/town/doors/mansion.c @@ -0,0 +1,25 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("north", (["id" : ({ "door", "handsome wooden door", "wooden door" }), + "short" : "a door leading north", + "long" : "This is a plain wooden door.", + "lockable" : 1 ]) ); + SetKeys("north", ({ "mansion key" })); + + SetSide("south", (["id" : ({ "door leading into the mansion", "handsome wooden door", "wooden door", "door" }), + "short" : "a door leading south", + "long" : "This is a handsome wooden door.", + "lockable" : 1 ]) ); + SetKeys("south", ({ "mansion key" })); + + SetClosed(1); + SetLocked(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/doors/otik_d.c b/lib/domains/town/doors/otik_d.c new file mode 100644 index 0000000..1f34c6e --- /dev/null +++ b/lib/domains/town/doors/otik_d.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("down", ([ "id" : ({"door leading down", "door", "down door"}), + "short" : "a door leading down", + "long" : "This is the up side of a door leading down.", + "lockable" : 1 ]) ); + + SetSide("up", ([ "id" : ({"door leading up", "door", "up door"}), + "short" : "a door leading up", + "long" : "This is the down side of a door leading up.", + "lockable" : 1 ]) ); + + SetClosed(1); + SetLocked(0); + SetKeys("down", ({ "down key" })); + SetKeys("up", ({ "up key" })); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/doors/pressure_door.c b/lib/domains/town/doors/pressure_door.c new file mode 100644 index 0000000..756e0e0 --- /dev/null +++ b/lib/domains/town/doors/pressure_door.c @@ -0,0 +1,50 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("east", ([ "id" : ({"pressure door leading east", "door", "pressure door", "east door"}), + "short" : "a pressure door leading east", + "long" : "This is the west side of a pressure door leading east. It is huge and heavy and designed to withstand and deflect great water pressure.", + "lockable" : 1 ]) ); + + SetSide("west", ([ "id" : ({"pressure door leading west", "door", "pressure door", "west door"}), + "short" : "a pressure door leading west", + "long" : "This is the east side of a pressure door leading west. It is huge and heavy and designed to withstand and deflect great water pressure.", + "lockable" : 1 ]) ); + + SetClosed(1); + SetLocked(1); + SetKeys("east", ({ "lab key" })); + SetKeys("west", ({ "lab key" })); +} + +varargs mixed CanOpen(object ob, string id){ + mixed ret = ::CanOpen(ob, id); + if(!ret || !intp(ret)) return ret; + if(ob->GetStatLevel("strength") > 49){ + return 1; + } + else { + write("You lack sufficient physical strength!"); + return 0; + } +} + +varargs mixed CanClose(object who, string id){ + mixed ret = ::CanClose(who, id); + if(!ret || !intp(ret)) return ret; + if(who->GetStatLevel("strength") > 49){ + return 1; + } + else { + write("You lack sufficient physical strength!"); + return 0; + } +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/doors/south.c b/lib/domains/town/doors/south.c new file mode 100644 index 0000000..b67611d --- /dev/null +++ b/lib/domains/town/doors/south.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("DIR_X", ([ "id" : ({"door leading DIR_X", "door", "DIR_X door"}), + "short" : "a door leading DIR_X", + "long" : "This is the Y_SIDE side of a door leading DIR_X.", + "lockable" : 1 ]) ); + + SetSide("DIR_Y", ([ "id" : ({"door leading DIR_Y", "door", "DIR_Y door"}), + "short" : "a door leading DIR_Y", + "long" : "This is the X_SIDE side of a door leading DIR_Y.", + "lockable" : 1 ]) ); + + SetClosed(1); + SetLocked(0); + SetKeys("DIR_X", ({ "DIR_X key" })); + SetKeys("DIR_Y", ({ "DIR_Y key" })); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/doors/steel_door.c b/lib/domains/town/doors/steel_door.c new file mode 100644 index 0000000..fc66d96 --- /dev/null +++ b/lib/domains/town/doors/steel_door.c @@ -0,0 +1,22 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("east", (["id" : ({ "door", "east door" }), + "short" : "a steel door leading east", + "long" : "This is an imposing, large steel door leading east into the arena.", + "lockable" : 0 ]) ); + SetSide("west", (["id" : ({ "west door", "door" }), + "short" : "a steel door leading west", + "long" : "This is an imposing, large steel door leading west, out of the arena.", + "lockable" : 0 ]) ); + + SetClosed(0); + SetLocked(0); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/doors/stone.c b/lib/domains/town/doors/stone.c new file mode 100644 index 0000000..17a9dd2 --- /dev/null +++ b/lib/domains/town/doors/stone.c @@ -0,0 +1,49 @@ +#include <lib.h> + +inherit LIB_DOOR; +//inherit LIB_READ; +//inherit LIB_LOOK; + +static void create() { + door::create(); + + SetSide("north", ([ "id" : ({"door leading north", "door", "north door", "stone door"}), + "short" : "a stone door leading north", + "long" : "This is the south side of a stone door leading north. It is too heavy " + "to be opened or closed by conventional means. There is an inscription on the door.", + "lockable" : 0 ]) ); + + SetSide("south", ([ "id" : ({"door leading south", "door", "south door", "stone door"}), + "short" : "a stone door leading south", + "long" : "This is the north side of a door leading south. It is too heavy " + "to be opened or closed by conventional means.", + "lockable" : 0 ]) ); + SetClosed(1); + SetLocked(0); +} + +varargs int eventOpen(object who, object tool) { + object room; + string tmp; + + room = environment(who); + who->eventPrint("You fail to open " + GetShort(tmp) + "."); + room->eventPrint(who->GetName() + " fails to open " + GetShort(tmp) + ".", + who); + return 0; +} + +varargs mixed eventClose(object who){ + object room; + string tmp; + + room = environment(who); + who->eventPrint("You fail to close " + GetShort(tmp) + "."); + room->eventPrint(who->GetName() + " fails to close " + GetShort(tmp) + ".", + who); + return 0; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/doors/test.c b/lib/domains/town/doors/test.c new file mode 100644 index 0000000..130cc92 --- /dev/null +++ b/lib/domains/town/doors/test.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("south", ([ "id" : ({"door leading south", "door", "south door"}), + "short" : "a door leading south", + "long" : "This is the north side of a door leading south.", + "lockable" : 1 ]) ); + + SetSide("north", ([ "id" : ({"door leading north", "door", "north door"}), + "short" : "a door leading north", + "long" : "This is the south side of a door leading north.", + "lockable" : 1 ]) ); + + SetClosed(1); + SetLocked(0); + SetKeys("south", ({ "south key" })); + SetKeys("north", ({ "north key" })); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/doors/testdoor2.c b/lib/domains/town/doors/testdoor2.c new file mode 100644 index 0000000..b69b7b9 --- /dev/null +++ b/lib/domains/town/doors/testdoor2.c @@ -0,0 +1,25 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("east", (["id" : ({ "door leading east", "door", "east door" }), + "short" : "a door leading east", + "long" : "This is the west side of a door leading east.", + "lockable" : 1 ]) ); + SetKeys("east", ({ "east key" })); + + SetSide("west", (["id" : ({ "door leading west", "door", "west door" }), + "short" : "a door leading west", + "long" : "This is the east side of a door leading west.", + "lockable" : 1 ]) ); + SetKeys("west", ({ "west key" })); + + SetClosed(1); + SetLocked(0); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/doors/trapdoor.c b/lib/domains/town/doors/trapdoor.c new file mode 100644 index 0000000..2c92b4c --- /dev/null +++ b/lib/domains/town/doors/trapdoor.c @@ -0,0 +1,22 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("down", (["id" : ({ "trapdoor on the floor", "trap door on the floor", "trap door", "trapdoor", "door" }), + "short" : "a trapdoor on the floor, leading downward", + "long" : "a trapdoor on the floor, leading downward.", + "lockable" : 0 ]) ); + SetSide("up", (["id" : ({ "trapdoor on the ceiling", "trap door on the ceiling", "trap door", "trapdoor", "door" }), + "short" : "a trapdoor in the ceiling, leading upward", + "long" : "a trapdoor in the ceiling, leading upward.", + "lockable" : 0 ]) ); + + SetClosed(1); + SetLocked(0); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/doors/welldoor1.c b/lib/domains/town/doors/welldoor1.c new file mode 100644 index 0000000..0138f79 --- /dev/null +++ b/lib/domains/town/doors/welldoor1.c @@ -0,0 +1,47 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("east", ([ "id" : ({"door leading east", "door", "east door"}), + "short" : "a door leading east", + "long" : "This is the west side of a door leading east.", + "lockable" : 1 ]) ); + + SetSide("west", ([ "id" : ({"door leading west", "door", "west door"}), + "short" : "a door leading west", + "long" : "This is the east side of a door leading west.", + "lockable" : 1 ]) ); + + SetClosed(1); + SetLocked(0); + SetKeys("east", ({ "east key" })); + SetKeys("west", ({ "west key" })); +} + +void init(){ + ::init(); +} + +varargs int eventOpen(object who, object tool) { + if(!this_object()->GetClosed()){ + write("It's already open."); + } + else { + write("This door has no handle or other visible means to open it."); + } + return 1; +} + +varargs int eventClose(object who) { + if(this_object()->GetClosed()){ + write("It's already open."); + } + else { + write("This door has no handle or other visible means to close it."); + } + return 1; +} + diff --git a/lib/domains/town/doors/welldoor2.c b/lib/domains/town/doors/welldoor2.c new file mode 100644 index 0000000..a535e7f --- /dev/null +++ b/lib/domains/town/doors/welldoor2.c @@ -0,0 +1,47 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("west", ([ "id" : ({"door leading west", "door", "west door"}), + "short" : "a door leading west", + "long" : "This is the east side of a door leading west.", + "lockable" : 1 ]) ); + + SetSide("east", ([ "id" : ({"door leading east", "door", "east door"}), + "short" : "a door leading east", + "long" : "This is the west side of a door leading east.", + "lockable" : 1 ]) ); + + SetClosed(0); + SetLocked(0); + SetKeys("west", ({ "west key" })); + SetKeys("east", ({ "east key" })); +} + +void init(){ + ::init(); +} + +varargs int eventOpen(object who, object tool) { + if(!this_object()->GetClosed()){ + write("It's already open."); + } + else { + write("This door has no handle or other visible means to open it."); + } + return 1; +} + +varargs int eventClose(object who) { + if(this_object()->GetClosed()){ + write("It's already open."); + } + else { + write("This door has no handle or other visible means to close it."); + } + return 1; +} + diff --git a/lib/domains/town/meals/ale.c b/lib/domains/town/meals/ale.c new file mode 100644 index 0000000..59f865c --- /dev/null +++ b/lib/domains/town/meals/ale.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include <meal_types.h> + +inherit LIB_MEAL; + + +static void create() { + meal::create(); + SetKeyName("ale"); + SetId( ({ "bottle", "ale", "first class ale", "first-class ale" }) ); + SetShort("a bottle of ale"); + SetLong("A nice bottle of ale."); + SetMass(60); + SetMealType(MEAL_DRINK | MEAL_ALCOHOL); + SetStrength(5); + SetMealMessages("You drink a bottle of ale.", + "$N drinks a bottle of ale."); + SetBaseCost("silver",10); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/blue_spice.c b/lib/domains/town/meals/blue_spice.c new file mode 100644 index 0000000..cb0edfc --- /dev/null +++ b/lib/domains/town/meals/blue_spice.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H +#include <meal_types.h> +#include <vendor_types.h> + +inherit LIB_POTION; + +static void create() { + ::create(); + SetKeyName("blue spice"); + SetId(({"spice","stick","stick of blue spice","slender"})); + SetShort("a stick of blue spice"); + SetAdjectives(({"blue","spice"})); + SetLong("A slender stick of blue spice."); + SetMass(1); + SetStrength(1); + SetBaseCost("gold",10); + SetStrength(1); + SetMealType(MEAL_FOOD); + SetMealMessages("You eat a stick of blue spice. Your magic powers seem slightly improved.", + "$N eats a stick of blue spice."); + SetDuration(300); + SetStats( ([ "intelligence" : 2 ]) ); + SetPoints( ([ "MP" : 150 ]) ); + SetVendorType(VT_MAGIC); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/bourbon.c b/lib/domains/town/meals/bourbon.c new file mode 100644 index 0000000..b57b0de --- /dev/null +++ b/lib/domains/town/meals/bourbon.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <meal_types.h> + +inherit LIB_MEAL; + + +static void create() { + meal::create(); + SetKeyName("bourbon"); + SetAdjectives( ({ "dark","green","cheap","bourbon" }) ); + SetId( ({ "bottle", "bottle of bourbon" }) ); + SetShort("a bottle of bourbon"); + SetLong("A dark green bottle of cheap bourbon."); + SetMass(100); + SetBaseCost("silver",20); + SetMealType(MEAL_DRINK | MEAL_ALCOHOL); + SetStrength(30); + SetMealMessages("You finish off the bourbon and gasp! WHEW!! Mean stuff!", + "$N finishes off a bottle of bourbon and gasps."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/claritin.c b/lib/domains/town/meals/claritin.c new file mode 100644 index 0000000..5617f81 --- /dev/null +++ b/lib/domains/town/meals/claritin.c @@ -0,0 +1,46 @@ +#include <lib.h> +#include ROOMS_H +#include <meal_types.h> + +inherit LIB_MEAL; + +int MealCure(object who); + +static void create() { + meal::create(); + SetKeyName("pill"); + SetId(({"claritin","loratidine","dose","drug"})); + SetShort("a claritin pill"); + SetAdjectives(({"10mg", "10 milligram", "non drowsy","non prescription", "prescription strength"})); + SetLong("A tiny, 10 milligram dose of a drug that removes cold symptoms."); + SetMass(10); + SetStrength(1); + SetBaseCost("silver",10); + SetMealType(MEAL_FOOD); + SetMealAction((: MealCure :)); + SetMealMessages("You swallow the pill.", + "$N swallows a pill."); +} +void init(){ + ::init(); +} +int MealCure(object who){ + mixed *stuff; + int effect = 0; + + if(!who) return 0; + + stuff = all_inventory(who); + + foreach(object ob in stuff){ + if(ob && ob->isGerm() && ob->GetGermName() == "cold virus"){ + effect = 1; + ob->eventMove(ROOM_FURNACE); + } + } + if(effect){ + tell_player(who,"You feel a little better already."); + } + + return 1; +} diff --git a/lib/domains/town/meals/coffee.c b/lib/domains/town/meals/coffee.c new file mode 100644 index 0000000..2793506 --- /dev/null +++ b/lib/domains/town/meals/coffee.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <meal_types.h> + +inherit LIB_MEAL; + + +static void create() { + meal::create(); + SetKeyName("coffee"); + SetId( ({"cup","coffee" }) ); + SetAdjectives( ({"regular","cup of","ordinary"}) ); + SetShort("a cup of coffee"); + SetLong("An ordinary cup of coffee"); + SetMass(10); + SetMealType( MEAL_DRINK | MEAL_CAFFEINE ); + SetStrength(10); + SetBaseCost("silver",5); + SetMealMessages("The wonderful drink is invigorating." , + "$N drinks $P coffee, and looks invigorated."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/espresso.c b/lib/domains/town/meals/espresso.c new file mode 100644 index 0000000..8a9bf05 --- /dev/null +++ b/lib/domains/town/meals/espresso.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <meal_types.h> + +inherit LIB_MEAL; + + +static void create() { + meal::create(); + SetKeyName("espresso"); + SetId( ({"cup","espresso" }) ); + SetAdjectives( ({"imported","cup of"}) ); + SetShort("a cup of espresso"); + SetLong("A cup of espresso"); + SetMass(10); + SetMealType( MEAL_DRINK | MEAL_CAFFEINE ); + SetStrength(20); + SetBaseCost("silver",15); + SetMealMessages("The wonderful drink is most invigorating." , + "$N drinks $P espresso, and looks invigorated and a bit more wired."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/fire.c b/lib/domains/town/meals/fire.c new file mode 100644 index 0000000..1d770ad --- /dev/null +++ b/lib/domains/town/meals/fire.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <meal_types.h> + +inherit LIB_MEAL; + + +static void create() { + meal::create(); + SetKeyName("firebreather bourbon"); + SetId( ({ "bottle", "bourbon" ,"fire","firebreather", + "bottle of bourbon"}) ); + SetAdjectives( ({ "firebreather","dark","green","bourbon"}) ); + SetShort("a bottle of bourbon"); + SetLong("A dark green bottle of \"Firebreather\" brand bourbon."); + SetMass(100); + SetBaseCost("silver",50); + SetMealType(MEAL_DRINK | MEAL_ALCOHOL); + SetStrength(40); + SetMealMessages("You finish off the bourbon and gasp! WHOOT!! Mean stuff!", + "$N finishes off a bottle of Firebreather bourbon and lets loose a rebel yell!"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/green_spice.c b/lib/domains/town/meals/green_spice.c new file mode 100644 index 0000000..201d034 --- /dev/null +++ b/lib/domains/town/meals/green_spice.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H +#include <meal_types.h> +#include <vendor_types.h> + +inherit LIB_POTION; + +static void create() { + ::create(); + SetKeyName("green spice"); + SetId(({"spice","stick","stick of green spice","slender"})); + SetShort("a stick of green spice"); + SetAdjectives(({"green","spice"})); + SetLong("A slender stick of green spice."); + SetMass(1); + SetStrength(1); + SetBaseCost("gold",12); + SetStrength(1); + SetMealType(MEAL_FOOD); + SetMealMessages("You eat a stick of green spice. You feel stronger, healthier, and more vigorous.", + "$N eats a stick of green spice."); + SetDuration(600); + SetStats( ([ "durability" : 5, "strength" : 5 ]) ); + SetPoints( ([ "SP" : 450, "HP" : 450 ]) ); + SetVendorType(VT_MAGIC); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/ham_sand.c b/lib/domains/town/meals/ham_sand.c new file mode 100644 index 0000000..60ba3cb --- /dev/null +++ b/lib/domains/town/meals/ham_sand.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include <meal_types.h> + +inherit LIB_MEAL; + + +static void create() { + meal::create(); + SetKeyName("sandwich"); + SetId(({"sandwich","ham sandwich"})); + SetShort("a ham sandwich"); + SetLong("This is a large, rather plain ham sandwich."); + SetMass(10); + SetStrength(20); + SetBaseCost("silver",10); + SetMealType(MEAL_FOOD); + SetMealMessages("You eat a ham sandwich. Mmm!", + "$N eats $P ham sandwich."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/herring.c b/lib/domains/town/meals/herring.c new file mode 100644 index 0000000..edc357e --- /dev/null +++ b/lib/domains/town/meals/herring.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <meal_types.h> +#include <dirs.h> + +inherit LIB_FISH; + +static void create() { + fish::create(); + SetKeyName("herring"); + SetId( ({ "fish" }) ); + SetAdjectives( ({ "red","saltwater","salt water" }) ); + SetShort("a red herring"); + SetLong("It is saltwater fish, and red in color."); + SetMealType(MEAL_FOOD); + SetMass(10); + SetStrength(10); + SetBaseCost("silver", 1); + SetFight(4); + SetFood("/domains/town/meals/herring"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/javarin.c b/lib/domains/town/meals/javarin.c new file mode 100644 index 0000000..a6506f3 --- /dev/null +++ b/lib/domains/town/meals/javarin.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H +#include <meal_types.h> +#include <vendor_types.h> + +inherit LIB_POTION; + +static void create() { + ::create(); + SetKeyName("javarin"); + SetId(({"pill","stimulant"})); + SetShort("a javarin pill"); + SetAdjectives(({"javarin","small","yellow"})); + SetLong("A small yellow stimulant."); + SetMass(1); + SetStrength(1); + SetBaseCost("gold",1); + SetStrength(1); + SetMealType(MEAL_FOOD); + SetMealMessages("You swallow a pill.", + "$N swallows a pill."); + SetDuration(10); + SetStats( ([ "speed" : 1 ]) ); + SetPoints( ([ "caffeine" : 20 ]) ); + SetVendorType(VT_MAGIC); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/latte.c b/lib/domains/town/meals/latte.c new file mode 100644 index 0000000..f845448 --- /dev/null +++ b/lib/domains/town/meals/latte.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <meal_types.h> + +inherit LIB_MEAL; + + +static void create() { + meal::create(); + SetKeyName("milk"); + SetId("latte"); + SetShort("a cafe latte"); + SetLong("A perfect pull of espresso married to steamed milk, " + "and, voila!: cafe latte!"); + SetMass(10); + SetMealType( MEAL_DRINK | MEAL_CAFFEINE ); + SetStrength(25); + SetValue(2); + SetMealMessages("The wonderful drink is invigorating." , + "$N drinks $P latte, and looks invigorated."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/mana_tonic.c b/lib/domains/town/meals/mana_tonic.c new file mode 100644 index 0000000..61bd279 --- /dev/null +++ b/lib/domains/town/meals/mana_tonic.c @@ -0,0 +1,33 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> + +inherit LIB_POTION; + +static void create() { + potion::create(); + SetKeyName("eve tonic"); + SetId( ({ "bottle", "liquid", "eve", "tonic"}) ); + SetAdjectives( "eve", "glowing","liquid", "blue" ); + SetShort("a bottle of Eve"); + SetLong("A bottle of glowing blue liquid. It has a label on it featuring "+ + "the silhouette of a bearded man wearing a top hat."); + SetEmptyLong("An empty bottle. It has a label on it featuring "+ + "the silhouette of a bearded man wearing a top hat."); + SetMass(60); + SetMealType(MEAL_DRINK); + SetStrength(5); + SetMealMessages("You drink a potion.", + "$N drinks a potion."); + SetBaseCost("gold",50); + SetPoints( ([ "MP" : 500 ]) ); + SetStats( ([ "intelligence" : 5 ]) ); + SetVendorType(VT_MAGIC); + SetItems(([ + ({"label"}) : "A label affixed to the bottle.", + ])); + SetRead( ({"label"}), "Invigorating EVE! Give in to your inner power!" ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/megapotion.c b/lib/domains/town/meals/megapotion.c new file mode 100644 index 0000000..6aa2e74 --- /dev/null +++ b/lib/domains/town/meals/megapotion.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <meal_types.h> + +inherit LIB_POTION; + +static void create() { + potion::create(); + SetKeyName("potion"); + SetId( ({ "potion","philtrum","megapotion","megapotion of uberness" }) ); + SetShort("a megapotion of uberness"); + SetLong("An example of a potion that is totally out of proportion in power."); + SetMass(60); + SetMealType(MEAL_DRINK | MEAL_ALCOHOL); + SetStrength(5); + SetMealMessages("You drink a potion.", + "$N drinks a potion."); + SetBaseCost("silver",10000); + SetDuration(30); + SetStats( ([ "strength" : 50, "speed" : 50 ]) ); + SetSkills( ([ "bargaining" : 20, "melee defense" : 20 ]) ); + SetPoints( ([ "HP" : 100, "XP" : 100, "SP" : 100, "MP" : 100 ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/poison.c b/lib/domains/town/meals/poison.c new file mode 100644 index 0000000..3837507 --- /dev/null +++ b/lib/domains/town/meals/poison.c @@ -0,0 +1,33 @@ +#include <lib.h> +#include <meal_types.h> + +inherit LIB_MEAL; +inherit LIB_MEAL_POISON; + + +static void create() { + ::create(); + SetKeyName("poison"); + SetId( ({ "vial", "poison", "vial of poison" }) ); + SetAdjectives("glass","small"); + SetShort("a vial of poison"); + SetLong("A small glass vial of poison."); + SetMass(60); + SetMealType(MEAL_DRINK); + SetStrength(1); + SetMealMessages("You drink the vial of poison.", + "$N drinks a vial of poison."); + SetEmptyName("vial"); + SetEmptyShort("an empty vial"); + SetEmptyLong("It is an empty brown bottle that once held some liquid."); + SetBaseCost("silver",10); + SetPoisonStrength(70); + SetPoisonUses(3); +} +mixed eventDrink(object who) { + who->AddPoison(this_object()->GetPoisonStrength() * this_object()->GetPoisonUses()); + return ::eventDrink(who); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/potion_antidote.c b/lib/domains/town/meals/potion_antidote.c new file mode 100644 index 0000000..efbc997 --- /dev/null +++ b/lib/domains/town/meals/potion_antidote.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> + +inherit LIB_POTION; + +static void create() { + potion::create(); + SetKeyName("antidote"); + SetId( ({ "vial","bottle", "antidote","philtrum","antidote to poison","vial of antidote" }) ); + SetAdjectives( "antidote" ); + SetShort("a vial of antidote"); + SetLong("A vial containing a clear blue liquid that counteracts poison."); + SetMass(20); + SetMealType(MEAL_DRINK); + SetStrength(5); + SetMealMessages("You drink from the vial.", + "$N drinks from a vial."); + SetBaseCost("silver",200); + SetPoints( ([ "poison" : -20 ]) ); + SetEmptyName("vial"); + SetEmptyShort("an empty vial"); + SetEmptyLong("This empty vial once contained some liquid."); + SetVendorType(VT_TREASURE); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/potion_bigheal.c b/lib/domains/town/meals/potion_bigheal.c new file mode 100644 index 0000000..cd922e0 --- /dev/null +++ b/lib/domains/town/meals/potion_bigheal.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> + +inherit LIB_POTION; + +static void create() { + potion::create(); + SetKeyName("potion"); + SetId( ({ "bottle", "potion","philtrum","potion of healing","potion of greater healing" }) ); + SetAdjectives(({"green", "healing","greater healing"})); + SetShort("a green potion of greater healing"); + SetLong("A bottle containing a green fluid with the magical property of restoring much health."); + SetMass(60); + SetMealType(MEAL_DRINK); + SetStrength(15); + SetMealMessages("You drink a potion.", + "$N drinks a potion."); + SetBaseCost("silver",2000); + SetPoints( ([ "HP" : 1000 ]) ); + SetVendorType(VT_MAGIC); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/potion_cure.c b/lib/domains/town/meals/potion_cure.c new file mode 100644 index 0000000..17e266c --- /dev/null +++ b/lib/domains/town/meals/potion_cure.c @@ -0,0 +1,52 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> + +inherit LIB_POTION; + +static void create() { + potion::create(); + SetKeyName("curative"); + SetId( ({ "vial","bottle", "cure","philtrum","cure light disease","cure disease" }) ); + SetAdjectives( "curative","cure" ); + SetShort("a vial of curative"); + SetLong("A vial containing a clear blue liquid that counteracts disease."); + SetMass(20); + SetMealType(MEAL_DRINK); + SetStrength(5); + SetMealMessages("You drink from the vial.", + "$N drinks from a vial."); + SetBaseCost("silver",200); + SetEmptyName("vial"); + SetEmptyShort("an empty vial"); + SetEmptyLong("This empty vial once contained some liquid."); + SetVendorType(VT_TREASURE); +} +void init(){ + ::init(); +} + +mixed eventDrink(object who) { + mixed stuff = all_inventory(who); + mixed germs, ret; + int results = 0; + germs = filter(stuff, (: $1->isGerm() :) ); + + if(sizeof(germs)){ + foreach(object germ in germs){ + string type = germ->GetType(); + int cure = germ->GetCure(); + int output = germ->eventCure(who, cure, type); + results += output; + } + } + + switch(results){ + case 0: tell_player(who, "You don't feel much difference.");break; + case 1: tell_player(who, "You feel better.");break; + default: tell_player(who, "You feel much better."); + } + ret = ::eventDrink(who); + return ret; +} + diff --git a/lib/domains/town/meals/potion_healing.c b/lib/domains/town/meals/potion_healing.c new file mode 100644 index 0000000..274e4b0 --- /dev/null +++ b/lib/domains/town/meals/potion_healing.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> + +inherit LIB_POTION; + +static void create() { + potion::create(); + SetKeyName("potion"); + SetId( ({ "bottle", "potion","philtrum","potion of healing","potion of minor healing" }) ); + SetAdjectives( "green", "healing","minor healing" ); + SetShort("a green potion of minor healing"); + SetLong("A bottle containing a green fluid with the magical property of restoring some health."); + SetMass(60); + SetMealType(MEAL_DRINK); + SetStrength(5); + SetMealMessages("You drink a potion.", + "$N drinks a potion."); + SetBaseCost("silver",200); + SetPoints( ([ "HP" : 200 ]) ); + SetVendorType(VT_MAGIC); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/potion_strength.c b/lib/domains/town/meals/potion_strength.c new file mode 100644 index 0000000..1363c75 --- /dev/null +++ b/lib/domains/town/meals/potion_strength.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> + +inherit LIB_POTION; + +static void create() { + potion::create(); + SetKeyName("potion"); + SetId( ({ "bottle", "potion","philtrum","potion of strength" }) ); + SetAdjectives( "red", "strength", "strongitude", "strongicity" ); + SetShort("a red potion of strength"); + SetLong("A bottle containing a red fluid with the magical property of making one stronger."); + SetMass(60); + SetMealType(MEAL_DRINK); + SetStrength(5); + SetMealMessages("You drink a potion.", + "$N drinks a potion."); + SetBaseCost("silver",1000); + SetDuration(600); + SetStats( ([ "strength" : 10 ]) ); + SetPoints( ([ "HP" : 50, "SP" : 50 ]) ); + SetVendorType(VT_MAGIC); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/rebel_yell.c b/lib/domains/town/meals/rebel_yell.c new file mode 100644 index 0000000..06dc603 --- /dev/null +++ b/lib/domains/town/meals/rebel_yell.c @@ -0,0 +1,32 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> +inherit LIB_FLASK; + +void create(){ + ::create(); + SetKeyName("bottle"); + SetId( ({"whiskey","vessel","bottle of whiskey","rebel yell"}) ); + SetAdjectives( ({"whiskey","glass","rebel yell"}) ); + SetShort("a bottle of whiskey"); + SetLong("A bottle of whiskey."); + SetMass(40); + SetBaseCost("gold",3); + SetVendorType(VT_DRINK); + SetFlaskContents("whiskey"); + SetFlaskUses(8); + SetStrength(30); + SetMaxFlask(10); + SetMealType(MEAL_ALCOHOL); + SetItems(([ + "label" : "It is attached to the bottle and has a picture of "+ + "a mounted soldier in a gray uniform, on a rearing horse, "+ + "sword raised.", + ])); + SetReads(([ + "label" : "REBEL YELL", + ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/shark.c b/lib/domains/town/meals/shark.c new file mode 100644 index 0000000..04cd18e --- /dev/null +++ b/lib/domains/town/meals/shark.c @@ -0,0 +1,41 @@ +/* /domains/Ylsrim/fish/shark.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 960302 + */ + +#include <lib.h> +#include <meal_types.h> +#include <dirs.h> +#include <damage_types.h> + +inherit LIB_FISH; + +void BiteMe(object who); +static void create() { + fish::create(); + SetKeyName("bull shark"); + SetId( ({ "shark", "bull shark" }) ); + SetShort("a bull shark"); + SetLong("It is a huge, long fish with razor sharp teeth and a carnivorous " + "appetite."); + SetMealType(MEAL_FOOD); + SetMass(100); + SetStrength(50); + SetBaseCost("silver", 10); + SetFight(40); + SetFood("/domains/town/meals/shark"); +} +int eventCatch(object who, object pole) { + call_out((: BiteMe, who :), 0); + return 1; +} +void BiteMe(object who) { + who->eventPrint("The shark bites you before it dies!"); + environment(who)->eventPrint("The shark bites " + who->GetName() + + " before it dies!", who); + who->eventReceiveDamage(this_object(), BITE, random(30), 0, + who->GetRandomLimb("right hand")); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/spazalin.c b/lib/domains/town/meals/spazalin.c new file mode 100644 index 0000000..37b6e96 --- /dev/null +++ b/lib/domains/town/meals/spazalin.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H +#include <meal_types.h> +#include <vendor_types.h> + +inherit LIB_POTION; + +static void create() { + ::create(); + SetKeyName("spazalin"); + SetId(({"pill","stimulant"})); + SetShort("a spazalin pill"); + SetAdjectives(({"spazalin","small","red"})); + SetLong("A small red stimulant."); + SetMass(1); + SetStrength(1); + SetBaseCost("gold",3); + SetStrength(1); + SetMealType(MEAL_FOOD); + SetMealMessages("You swallow a pill.", + "$N swallows a pill."); + SetDuration(60); + SetStats( ([ "speed" : 1 ]) ); + SetPoints( ([ "caffeine" : 40 ]) ); + SetVendorType(VT_MAGIC); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/special.c b/lib/domains/town/meals/special.c new file mode 100644 index 0000000..897b051 --- /dev/null +++ b/lib/domains/town/meals/special.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include <meal_types.h> + +inherit LIB_MEAL; + + +static void create() { + meal::create(); + SetKeyName("special"); + SetId( ({ "special of the house", "bottle", "bourbon" }) ); + SetShort("a bottle of bourbon"); + SetLong("A dark green bottle of cheap bourbon."); + SetMass(100); + SetBaseCost("silver",20); + SetMealType(MEAL_DRINK | MEAL_ALCOHOL); + SetStrength(30); + SetMealMessages("You finish off the bourbon and gasp! WHEW!! Mean stuff!", + "$N finishes off a bottle of bourbon and gasps."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/speedalin.c b/lib/domains/town/meals/speedalin.c new file mode 100644 index 0000000..a668da1 --- /dev/null +++ b/lib/domains/town/meals/speedalin.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H +#include <meal_types.h> +#include <vendor_types.h> + +inherit LIB_POTION; + +static void create() { + ::create(); + SetKeyName("speedalin"); + SetId(({"pill","stimulant"})); + SetShort("a speedalin pill"); + SetAdjectives(({"speedalin","small","white"})); + SetLong("A small white stimulant."); + SetMass(1); + SetStrength(1); + SetBaseCost("gold",2); + SetStrength(1); + SetMealType(MEAL_FOOD); + SetMealMessages("You swallow a pill.", + "$N swallows a pill."); + SetDuration(20); + SetStats( ([ "speed" : 2 ]) ); + SetPoints( ([ "caffeine" : 35 ]) ); + SetVendorType(VT_MAGIC); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/stein.c b/lib/domains/town/meals/stein.c new file mode 100644 index 0000000..425dd50 --- /dev/null +++ b/lib/domains/town/meals/stein.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> +inherit LIB_FLASK; + +void create(){ + ::create(); + SetKeyName("stein"); + SetId( ({"mug","vessel","guinness"}) ); + SetAdjectives( ({"large","beer","guinness"}) ); + SetShort("a large beer stein"); + SetLong("A large vessel for drinking fluids."); + SetMass(40); + SetBaseCost("gold",1); + SetVendorType(VT_DRINK); + SetFlaskContents("Guinness"); + SetFlaskUses(10); + SetStrength(10); + SetMaxFlask(10); + SetMealType(MEAL_ALCOHOL|MEAL_DRINK|MEAL_FOOD); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/water.c b/lib/domains/town/meals/water.c new file mode 100644 index 0000000..7ba02b9 --- /dev/null +++ b/lib/domains/town/meals/water.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <meal_types.h> + +inherit LIB_MEAL; + + +static void create() { + meal::create(); + SetKeyName("water"); + SetId(({ "bottle","water"})); + SetAdjectives(({"fresh","spring"})); + SetShort("a bottle of water"); + SetLong("This is a little bottle of fresh spring water."); + SetMass(10); + SetMealType(MEAL_DRINK); + SetStrength(10); + SetBaseCost("silver",2); + SetMealMessages("You drink your water, and feel refreshed.", "$N drinks "+ + "$P water."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/winebottle.c b/lib/domains/town/meals/winebottle.c new file mode 100644 index 0000000..3ccdbbd --- /dev/null +++ b/lib/domains/town/meals/winebottle.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> +inherit LIB_FLASK; + +void create(){ + ::create(); + SetKeyName("bottle"); + SetId( ({"vessel","winebottle","bottle of wine","nouveau"}) ); + SetAdjectives( ({"wine","glass","nouveau"}) ); + SetShort("a bottle of wine"); + SetLong("A bottle of something or other Nouveau. The label is too stained to read."); + SetMass(40); + SetBaseCost("gold",2); + SetVendorType(VT_DRINK); + SetFlaskContents("wine"); + SetFlaskUses(10); + SetStrength(20); + SetMaxFlask(10); + SetMealType(MEAL_ALCOHOL); + SetItems(([ + "label" : "It is attached to the bottle and is meant to be read.", + ])); + SetReads(([ + "label" : "It's too stained to read, all right.", + ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/worm.c b/lib/domains/town/meals/worm.c new file mode 100644 index 0000000..586cb96 --- /dev/null +++ b/lib/domains/town/meals/worm.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <meal_types.h> + +inherit LIB_MEAL; +inherit LIB_BAIT_WITH; + +static void create() { + meal::create(); + SetKeyName("worm"); + SetId(({"bait","wriggler"})); + SetAdjectives(({"small","wriggly","bait"})); + SetShort("a worm"); + SetLong("This is a small worm, suitable for baiting a fishing pole."); + SetMass(1); + SetStrength(1); + SetBaitStrength(200); + SetBaseCost("silver",1); + SetMealType(MEAL_FOOD); + SetMealMessages("You eat a small wriggling worm. Yuck!", + "$N eats $P little worm. Yuck!"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/yellow_spice.c b/lib/domains/town/meals/yellow_spice.c new file mode 100644 index 0000000..899e9d9 --- /dev/null +++ b/lib/domains/town/meals/yellow_spice.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H +#include <meal_types.h> +#include <vendor_types.h> + +inherit LIB_POTION; + +static void create() { + ::create(); + SetKeyName("yellow spice"); + SetId(({"spice","stick","stick of yellow spice","slender"})); + SetShort("a stick of yellow spice"); + SetAdjectives(({"yellow","spice"})); + SetLong("A slender stick of yellow spice."); + SetMass(1); + SetStrength(1); + SetBaseCost("gold",8); + SetStrength(1); + SetMealType(MEAL_FOOD); + SetMealMessages("You eat a stick of yellow spice. You feel a little stronger and healthier.", + "$N eats a stick of yellow spice."); + SetDuration(300); + SetPoints( ([ "HP" : 300 ]) ); + SetStats( ([ "strength" : 5 ]) ); + SetVendorType(VT_MAGIC); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/meals/zyqxuwy.c b/lib/domains/town/meals/zyqxuwy.c new file mode 100644 index 0000000..6f52315 --- /dev/null +++ b/lib/domains/town/meals/zyqxuwy.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <meal_types.h> +#include <dirs.h> + +inherit LIB_FISH; + +static void create() { + fish::create(); + SetKeyName("zyqxuwy"); + SetId( ({ "fish", "pinkfish" }) ); + SetAdjectives( ({ "pink","freshwater","fresh water" }) ); + SetShort("a pink zyqxuwy"); + SetLong("It is freshwater fish, and pink in color."); + SetMealType(MEAL_FOOD); + SetMass(10); + SetStrength(10); + SetBaseCost("silver", 2); + SetFight(4); + SetFood("/domains/town/meals/zyqxuwy"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/npc/bear.c b/lib/domains/town/npc/bear.c new file mode 100644 index 0000000..882136b --- /dev/null +++ b/lib/domains/town/npc/bear.c @@ -0,0 +1,22 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("bear"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"non-player", "non player"})); + SetShort("a bear"); + SetLong("A large brown bear. Not as huge as a grizzly, but plenty big enough to knock your block off."); + SetWanderSpeed(20); + SetClass("fighter"); + SetLevel(10); + SetMelee(1); + SetRace("bear"); + SetGender("male"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/npc/beggar.c b/lib/domains/town/npc/beggar.c new file mode 100644 index 0000000..a36a613 --- /dev/null +++ b/lib/domains/town/npc/beggar.c @@ -0,0 +1,129 @@ +#include <lib.h> +#include <daemons.h> +#include <position.h> + +inherit LIB_SENTIENT; +inherit LIB_DONATE; + +static void create() { + sentient::create(); + SetKeyName("beggar"); + SetId(({"beggar"})); + SetAdjectives(({"dirty"})); + SetShort("a dirty beggar"); + SetLong("This beggar has something strangely noble about his aspect. " + "He certainly doesn't look like he has always been a beggar."); + SetCanBite(0); + SetWimpy(90); + SetPacifist(1); + SetInventory(([ + "/domains/town/obj/map" : 1, + ])); + SetLevel(1); + SetAutoStand(0); + SetRace("human"); + SetGender("male"); + SetConsultResponses( ([ + "map" : "It's so you have an idea how to get around.", + ({ "levels", "leveling", "level" }) : "I don't know such stuff. "+ + "Ask Dirk in the Adventurers' Guild." + ]) ); + SetPosition(POSITION_SITTING); + SetPolyglot(1); + SetLanguage("common", 100); + SetDefaultLanguage("common"); + SetAction(5, ({ + "!say 'Bree-yark' is hobgoblin for 'we surrender'.", + "!say Donating to the church sometimes gives you a "+ + "bonus, but don't take from the charity bin if "+ + "you're above level 5! It'll deduct XP!", + "!say Brandy's a fine girl, and has the purest spice "+ + "sticks in town in her secret menu.", + "!say I heard the secret cave is straight north in the "+ + "forest.", + "!say one time I saw something glowing in the middle of "+ + "the forest.", + "!say Don't mess with balrogs. Seriously.", + "!say You ever see an orc or a dwarf try to swim? It "+ + "ain't pretty.", + "!say Y'ever wonder if them orcs have good reason to be "+ + "so aggro all the time?", + "!say You don't need to be in the mage's guild to learn some "+ + "spells from Herkimer, but it helps.", + "!say If you want to be a fighter, I was told you need to "+ + "find something called a 'stargate' and then 'dial tower'."+ + " How's anybody supposed to figure *that* one out?", + "!say if you can get someone to resurrect your corpse, "+ + "you won't have a death penalty. But remember there is a "+ + "difference between resurrection and raising!", + "!say you can't control a zombie if you don't speak its "+ + "language.", + "!say I heard there's a language teacher at the northern "+ + "fort that teaches for money rather than training points.", + "!say Be careful traveling whyle flying or invisible. "+ + "It really drains your stamina!", + "!say Advancing levels improves your skills, so join a "+ + "guild before advancing, if you can.", + "!say if you don't advance levels automatically when you "+ + "qualify, go see Dirk and ask him to advance.", + "!say The Yautja are a proud hunter race from another "+ + "world with powerful magic. Pray you never meet one.", + "!say Being drunk helps you heal faster, but it's not a "+ + "good idea to try to figth drunk!", + "!say Drinking coffee sobers you up some.", + "!say A belly full of food and water helps you heal faster.", + "!say If you don't see items in a room that you are sure "+ + "should be there, maybe you need a light source." + })); +} + +//Fix courtesy of Jonez +string GetLong(string str){ + return sentient::GetLong(str); +} + +int GiveMap(object ob){ + object map; + if(ob && present(ob->GetKeyName(),environment(this_object())) + && !this_object()->GetInCombat() && + member_array(ob->GetRace(),RACES_D->GetRaces(1)) != -1 && + !creatorp(ob) && + !stringp(ob->CanManipulate()) ){ + if(ob->GetGender() == "male"){ + eventForce("say take this, brother. May it serve you well."); + } + else if(ob->GetGender() == "female"){ + eventForce("say take this, sister. May it serve you well."); + } + else eventForce("say here, you might need this"); + eventForce("give my first map to "+ob->GetKeyName()); + } + if(map = present("map",this_object())) { + map->eventDestruct(); + eventForce("shrug"); + } + return 1; +} + +int SayHi(object ob){ + if(this_object() && ob && + present(ob->GetKeyName(),environment(this_object())) + && !this_object()->GetInCombat() && + member_array(ob->GetRace(),RACES_D->GetRaces(1)) != -1) + eventForce("say Hi, "+ob->GetName()); + return 1; +} + +void init(){ + ::init(); + + call_out((: SayHi, this_player() :), 1); + + if(!present("town map",this_player())){ + new("/domains/town/obj/map")->eventMove(this_object()); + call_out((: GiveMap, this_player() :), 4); + } + //if(!present("cold virus",this_object())){ + // new("/domains/town/obj/cold")->eventInfect(this_object()); + //} +} diff --git a/lib/domains/town/npc/brandy.c b/lib/domains/town/npc/brandy.c new file mode 100644 index 0000000..2ff16db --- /dev/null +++ b/lib/domains/town/npc/brandy.c @@ -0,0 +1,119 @@ +#include <lib.h> +#include <position.h> + +inherit LIB_BARKEEP; + +string array flatterers, specials; +string save_str = ""; +string saved_str = ""; + +mixed NoKill(object attacker); + +int FlatterResponse(mixed args...){ + string who = args[0]->GetKeyName(); + if(member_array(who, flatterers) == -1){ + flatterers += ({ args[0]->GetKeyName() }); + flatterers = distinct_array(flatterers); + save_str = save_variable(flatterers); + unguarded( (: write_file("/domains/town/save/brandy.o", save_str, 1) :) ); + args[0]->AddExperiencePoints(300); + } + this_object()->eventForce("say Thank you, "+args[0]->GetName()+". Feel free to ask me "+ + "for my special menu."); + return 1; +} + +string LongDesc(mixed args){ + string str = ""; + object looker = this_player(); + str = "With eyes that could steal a sailor from the sea, Brandy "+ + "works in this harbor town laying whiskey down, fetching round "+ + "after round for her fiercely loyal clientele."; + if(member_array(looker->GetKeyName(), flatterers) != -1){ + str += " You are allowed to ask her for her special menu: ask brandy for special menu"; + } + else { + str += " Word is that she's receptive to flattery."; + } + return str; +} + +static void create() { + barkeep::create(); + flatterers = ({}); + unguarded( (: saved_str = read_file("/domains/town/save/brandy.o") :) ); + if(sizeof(saved_str)) flatterers = restore_variable(saved_str); + SetKeyName("brandy"); + SetAdjectives( ({ "bar", "fine", "bartender", "keeper", "good", "serving" }) ); + SetId( ({ "brandy", "barmaid", "barkeep", "bartender", "keeper", "girl", "wench", "maid" }) ); + SetShort("Brandy the barmaid"); + SetLevel(1); + SetLong( (: LongDesc :) ); + SetMenuItems(([ + ({ "guinness","beer","stein" }) : "/domains/town/meals/stein", + ({ "wine","bottle of wine" }) : "/domains/town/meals/winebottle", + ({ "whiskey","bottle of whiskey" }) : "/domains/town/meals/rebel_yell", + ])); + SetSpecialMenuItems(([ + "javarin" : "/domains/town/meals/javarin", + "speedalin" : "/domains/town/meals/speedalin", + "spazalin" : "/domains/town/meals/spazalin", + //"somnitol" : "/domains/town/meals/potion_healing", + //"phoqitol" : "/domains/town/meals/potion_healing", + //"comatol" : "/domains/town/meals/potion_healing", + "yellow spice" : "/domains/town/meals/yellow_spice", + "green spice" : "/domains/town/meals/green_spice", + "blue spice" : "/domains/town/meals/blue_spice", + "eve tonic" : "/domains/town/meals/mana_tonic", + ])); + SetGender("female"); + SetMorality(40); + SetRace("human"); + AddCurrency("electrum", random(200)); + SetSkill("bargaining", 1); + SetProperty("no bump", 1); + SetLocalCurrency("gold"); + SetAttackable( (: NoKill :) ); + SetPolyglot(1); + SetLanguage("common", 100); + SetDefaultLanguage("common"); + SetInventory(([ + "/domains/town/armor/locket" : "wear necklace", + "/domains/town/armor/barsmock" : "wear smock", + ])); + SetTalkResponses( ([ + "randy, you're a fine girl" : (: FlatterResponse :), + "randy, youre a fine girl" : (: FlatterResponse :), + "randy you're a fine girl" : (: FlatterResponse :), + "randy youre a fine girl" : (: FlatterResponse :), + "what a good wife you would be" : (: FlatterResponse :), + ])); +} + +void init(){ + ::init(); +} + +mixed eventSell(object who, string args){ + //tc("flatterers: "+identify(flatterers)); + if(member_array(args, GetSpecials()) != -1 && + member_array(who->GetKeyName(), flatterers) == -1){ + eventForce("say I don't feel comfortable selling that to you, "+ + who->GetName()+"."); + return 1; + } + return ::eventSell(who, args); +} + +varargs int eventSpecialList(object who, string what){ + if(member_array(who->GetKeyName(), flatterers) == -1){ + eventForce("say I'm not sure I have a special menu for you, "+ + who->GetName()+"."); + return 1; + } + return ::eventSpecialList(who, what); +} + +mixed NoKill(object attacker){ + return "Brandy is such a fine girl you find yourself unable to attack her."; +} diff --git a/lib/domains/town/npc/bubb.c b/lib/domains/town/npc/bubb.c new file mode 100644 index 0000000..9382a0c --- /dev/null +++ b/lib/domains/town/npc/bubb.c @@ -0,0 +1,25 @@ +#include <lib.h> + +inherit LIB_TEACHER; +void create(){ + ::create(); + SetKeyName("bubb"); + SetId( ({"teacher","orc","schoolteacher","bubb the schoolteacher"}) ); + SetGender("male"); + SetRace("orc"); + SetNativeLanguage("english"); + SetTeachingFee(100); + SetLocalCurrency("silver"); + SetShort("Bubb the schoolteacher"); + SetLong("This is a person whose job it is to teach you things. "+ + "For example, 'ask teacher "+ + "to teach Tangetto' would prompt him to begin teaching a Tangetto "+ + "lesson to you, if he knows the language and you have "+ + "enough of his preferred currency. "); + SetLevel(1); + SetLanguage("Tangetto", 100); + AddTeachingLanguages( ({"Tangetto", "English" }) ); +} +void init() { + ::init(); +} diff --git a/lib/domains/town/npc/bugg.c b/lib/domains/town/npc/bugg.c new file mode 100644 index 0000000..bed97e7 --- /dev/null +++ b/lib/domains/town/npc/bugg.c @@ -0,0 +1,35 @@ +#include <lib.h> + +inherit LIB_TEACHER; + +void create(){ + ::create(); + SetKeyName("bugg"); + SetId( ({"teacher","dwarf","schoolteacher","bugg the schoolteacher"}) ); + SetGender("male"); + SetRace("dwarf"); + SetNativeLanguage("common"); + SetShort("Bugg the schoolteacher"); + SetLong("This is a person whose job it is to teach you things. "+ + "For example, 'ask teacher "+ + "to teach Malkierien' would prompt him to begin teaching a Malkierien "+ + "lesson to you, if he knows the language and you have "+ + "earned sufficient training points. If you lack training points, then "+ + "do some adventuring and earn a level promotion. You will "+ + "then be awarded training points. To know more about what Bugg "+ + "can teach: ask bugg for help"); + SetLevel(1); + SetLanguage("Malkierien", 100); + SetLanguage("English", 100); + SetLanguage("Edhellen", 100); + SetLanguage("Tangetto", 100); + SetLanguage("Poleepkwa", 100); + AddTeachingLanguages( ({"Malkierien", "English", "Common", + "Edhellen", "Tangetto", "Poleepkwa" }) ); + SetPolyglot(1); + SetLanguage("common", 100); + SetDefaultLanguage("common"); +} +void init() { + ::init(); +} diff --git a/lib/domains/town/npc/clepius.c b/lib/domains/town/npc/clepius.c new file mode 100644 index 0000000..81abbdb --- /dev/null +++ b/lib/domains/town/npc/clepius.c @@ -0,0 +1,219 @@ +#include <lib.h> + +inherit LIB_NPC; + +object *slips; +int busy; + +static void create() { + npc::create(); + SetKeyName("clepius"); + SetId(({"clepius","doctor","healer"})); + SetAdjectives(({"a.s.", "A.S.", "doctor","dr","Dr.","dr."})); + SetShort("Clepius the healer"); + SetLong("Clepius is a kindly old man, legendary for his " + "nearly superhuman powers of healing. He is even " + "rumored capable of resurrecting the dead. He runs " + "a medical care service in town, and can be asked to " + "help when needed, though his help is not free."); + SetLevel(50); + SetRace("human"); + SetClass("mage"); + SetGender("male"); + SetInventory(([ + "/domains/town/weap/rod":1, + "/domains/town/obj/medbag":1, + "/domains/town/armor/toga":"wear toga", + ]) ); + slips = ({}); + busy=0; + SetPolyglot(1); + SetLanguage("common", 100); + SetDefaultLanguage("common"); + SetCustomXP(10); +} + +void init(){ + ::init(); +} + +int CanReceive() { + if(present("healer token", this_object())){ + return 0; + } + + eventForce("nod"); + set_heart_beat(1); + return 1; +} + +int CheckBag(){ + object bag,slip; + string player, problem; + slip = present("healer token", this_object()); + if(!slip && busy == 1) { + eventForce("say That's a bit odd...\n\n"); + eventForce("I'm sorry but I must have misplaced your slip. Do you have another one?"); + busy = 0; + return 1; + } + if(slip){ + busy = 1; + eventForce("say mmhmmm..."); + problem = slip->GetProperty("problem"); + player = slip->GetPatient(); + this_object()->DiagPatient(player,problem); + } + return 1; +} + +void heart_beat(){ + if(busy == 0 && present("healer token", this_object())){ + } + + this_object()->CheckBag(); +} + +int ejectRabble(string str){ + object *riffraff,patient; + environment()->SetProperty("busy",1); + riffraff = get_livings(environment(this_object())); + if(! patient = present(str,environment(this_object())) ){ + patient = find_player(str); + } + foreach(object bum in riffraff){ + if( bum->GetKeyName() != patient->GetKeyName() && + bum->GetKeyName() != "clepius" ){ + tell_object(bum,"The doctor ejects you from his office in order to "+ + "treat "+patient->GetName()+".\n\n"); + bum->eventMoveLiving("/domains/town/room/healer"); + tell_object(patient,"The doctor ejects "+bum->GetName()+" from "+ + "his office in order to treat you."); + } + } + return 1; +} + +int NextPatient(){ + eventForce("put my first slip in bin"); + environment()->SetProperty("busy",0); + tell_room(load_object("/domains/town/room/healer"),"From the back room "+ + "you hear the doctor holler: \"%^BOLD%^CYAN%^NEXT!%^RESET%^\""); + tell_room(environment(),"The doctor leans into the east doorway "+ + "and hollers: \"%^BOLD%^CYAN%^NEXT!%^RESET%^\""); + busy = 0; + environment()->SetProperty("busy",0); + return 1; + +} + +int PerformHeal(string dude){ + object person; + int hp,mhp; + person = present(dude,environment()); + if(!person) { + eventForce("look"); + eventForce("shrug"); + return 1; + } + eventForce("say All right...let's take a look at you."); + hp = person->GetHealthPoints(); + mhp = person->GetMaxHealthPoints()-10; + if(hp > mhp){ + eventForce("say You look fine to me. Take back your slip and save it for when you really need it."); + eventForce("give my first slip to "+dude); + return 1; + } + if(present("clepius mojo",person)){ + eventForce("say You already have salve on you. Give it a chance to work, then come back later."); + eventForce("give my first slip to "+dude); + return 1; + } + eventForce("say Yes, you can use a little help."); + tell_room(environment(),"Clepius vigorously rubs a healing salve onto your body. You can feel it enhancing your body's recovery."); + new("/secure/obj/mojo")->eventMove(person); + return 1; +} + +int PerformRegenerate(string dude){ + int i; + mapping stumps; + object person; + person = present(dude,environment()); + stumps=person->GetMissingLimbs(); + + eventForce("say Let's count limbs, then. Hmmmm..."); + + if(!sizeof(stumps)) { + eventForce("say You are not missing any limbs. Go sell this slip back to James."); + eventForce("give my first slip to "+dude); + return 1; + } + for(i=0;i<sizeof(stumps);i++){ + person->RestoreLimb(stumps[i]); + tell_object(person,"The doctor regenerates your "+stumps[i]+"."); + return 1; + } +} + +int PerformExcision(string dude){ + string what,whom; + object person,thing,slug; + int firearms_wounds, wounds; + + person = present(dude,environment(this_object())); + slug=present("firearms_wound",person); + wounds=0; + wounds=person->GetLead(); + if(!slug){ + eventForce("say You have no foreign bodies."); + eventForce("give my first slip to "+dude); + return 1; + } + + tell_room(environment(this_object()),"Clepius deftly extracts a lead slug from "+ dude+".", ({person})); + tell_object(person,"Clepius deftly extracts a lead slug from your body."); + slug=new("/domains/town/obj/spent"); + if(wounds > 0) { + person->AddLead("firearms_wounds", -1); + slug->SetShort("a spent firearm slug"); + --wounds; + slug->eventMove(this_object()); + if(person->GetLead() < 1){ + slug=present("firearms_wound",person); + if(slug) slug->eventDestruct(); + } + return 1; + } + + slug->eventMove(this_object()); + slug=present("firearms_wound",person); + if(wounds < 1 && slug){ + slug->eventDestruct(); + } + return 1; +} + +int DiagPatient(string dude, string problem){ + if(!present(dude,environment())) { + NextPatient(); + return 1; + } + + ejectRabble(dude); + + if(problem == "regenerate") { + PerformRegenerate(dude); + NextPatient(); + } + if(problem == "heal"){ + PerformHeal(dude); + NextPatient(); + } + if(problem == "excise"){ + PerformExcision(dude); + NextPatient(); + } + return 1; +} + diff --git a/lib/domains/town/npc/clerk.c b/lib/domains/town/npc/clerk.c new file mode 100644 index 0000000..ad1de47 --- /dev/null +++ b/lib/domains/town/npc/clerk.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include <objects.h> + +inherit LIB_CLERK; +void create(){ + ::create(); + SetKeyName("clerk"); + SetId("clerk"); + SetAdjectives("town"); + SetGender("male"); + SetRace("human"); + SetShort("the town clerk"); + SetLong("An officious-looking clerk. He is empowered to perform ceremonies of public record. You may \"ask clerk to marry me and PERSON\", and \"ask clerk for a divorce\"."); + SetLocalCurrency("silver"); + SetClass("cleric"); + SetLevel(4); + SetTax(5); + SetPolyglot(1); + SetLanguage("common", 100); + SetDefaultLanguage("common"); +} +void init() { + ::init(); + SetSmell(([ "default" : "A rather odd, musty smell."])); + SetListen(([ "default" : "The clerk grumbles something about an "+ + "unconscionably small tax revenue base."])); +} diff --git a/lib/domains/town/npc/cod.c b/lib/domains/town/npc/cod.c new file mode 100644 index 0000000..4e4f7f5 --- /dev/null +++ b/lib/domains/town/npc/cod.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include <position.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("fish"); + SetAdjectives( ({"cod", "medium", "unremarkable"}) ); + SetId(({"cod","codfish"})); + SetShort("a fish"); + SetLong("A codfish of medium size."); + SetWanderSpeed(1); + //Letting npc's load virtual rooms can be dangerous. + //You were warned. + //SetPermitLoad(1); + SetPosition(POSITION_SWIMMING); + SetPacifist(1); + SetLevel(1); + SetRace("fish"); + SetHealthPoints(10); + SetMaxHealthPoints(10); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/npc/deer.c b/lib/domains/town/npc/deer.c new file mode 100644 index 0000000..c5b5a29 --- /dev/null +++ b/lib/domains/town/npc/deer.c @@ -0,0 +1,22 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("deer"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"non-player", "non player"})); + SetShort("a deer"); + SetLong("A Typical creature of its kind: nervous, shify, yet beautiful and graceful. This gentle herbivore just wants to eat plants and reproduce."); + SetWimpy(95); + SetPacifist(1); + SetWanderSpeed(4); + SetLevel(1); + SetMelee(1); + SetRace("deer"); + SetGender("female"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/npc/dirk.c b/lib/domains/town/npc/dirk.c new file mode 100644 index 0000000..f460188 --- /dev/null +++ b/lib/domains/town/npc/dirk.c @@ -0,0 +1,214 @@ +#include <lib.h> +#include <daemons.h> +#ifndef REQUIRE_QUESTING +#define REQUIRE_QUESTING 1 +#endif + +inherit LIB_SENTIENT; + +int hint; + +int AdvanceDude(mixed arg); +mapping advancement, Levels; +int TalkFunc(){ + string thing1, thing2, thing3, thing4, thing5; + + thing1 = "There's no shame in being wimpy. Live to fight another day. Death takes away valuable xp."; + thing2 = "I wish I could see Princess Daphne again."; + thing3 = "Don't fight drunk."; + thing4 = "Learning spells from Herkimer is a good idea."; + thing5 = "Food, drink, and caffeine help restore health and strength."; + + switch(hint){ + case 0 : eventForce("say "+thing1);break; + case 1 : eventForce("say "+thing2);break; + case 2 : eventForce("say "+thing3);break; + case 3 : eventForce("say "+thing4);break; + case 4 : eventForce("say "+thing5);break; + default : eventForce("smile"); + } + + if(hint == 4) hint = 0; + else hint++; + return 1; +} + +static void create() { + int i; + sentient::create(); + Levels = PLAYERS_D->GetLevelList(); + advancement = ([]); + SetKeyName("dirk"); + SetId(({"dirk"})); + SetShort("Dirk the Tired"); + SetLong("For 20 years, Dirk the Daring has been trying " + "to defeat the vile dragon Singe, with almost no respite. " + "Today he just wants to rest and relax, and has accepted " + "the position of the town's Adventurers' Guild master. " + "If you feel you deserve it, \"ask dirk to advance\"."); + SetPolyglot(1); + SetLanguage("common", 100); + SetDefaultLanguage("common"); + SetInventory(([ + "/domains/town/armor/collar" : "wear collar", + ])); + SetLevel(15); + SetRace("human"); + SetGender("male"); + //SetAction(5, (: TalkFunc :)); + AddTalkResponse("hello", "hi! Ask me for a tip!"); + AddTalkResponse("hi", "hi! Ask me for a tip!"); + SetCommandResponses( ([ + "advance": (: AdvanceDude :) + ]) ); + SetRequestResponses( ([ + ({ "a hint", "hints", "a clue", "clues", "a tip", "tips" }) : + (: TalkFunc :), + ]) ); + SetConsultResponses( ([ + ({ "level", "levels", "leveling", "advancement", "advancing" }) : + "To level, get some experience out there and then come back "+ + "and ask me to advance. For some levels you may need "+ + "some quest points to advance, not just experience.", + ({ "xp", "XP", "experience" }) : "You can score experience "+ + "points by killing monsters or completing some quests. "+ + "Sometimes you'll get xp for completing some task you didn't "+ + "even know would give you points. Generally though, it's combat "+ + "that results in XP rewards, if you win.", + ({ "points" }) : "It's how to keep track of your progress. The "+ + "kinds of points I care about are experience points and "+ + "quest points.", + ({ "quests", "quest", "quest points" }) : "Quests are missions "+ + "you can try to complete that will usually reward you with "+ + "quest points if you solve them. "+ + "You'll need quest points to advance past a "+ + "certain level.", + ]) ); + for(i=0;i<21;i++){ + advancement[i] = Levels[i]; + } +} + +void init(){ + ::init(); +} + +int AdvanceDude(mixed arg){ + int level,xp,qp; + int desired_level,required_xp,required_qp; + mixed *statlist; + mapping this_stat; + int statclass, statlevel, i; + + statlist = this_player()->GetStats(); + + if(this_player()->GetKeyName() == "guest"){ + this_object()->eventForce("say I don't promote temporary players."); + return 1; + } + + if(!level = this_player()->GetLevel()){ + this_object()->eventForce("say You are confusing me."); + return 1; + } + + if(level > 19){ + this_object()->eventForce("say Whoa there, big " + "stuff. Advancement past level 20 is the " + "purview of the Trans-Human Elder Guild. " + "I'm sorry but I can't help you."); + return 1; + } + + xp = this_player()->GetExperiencePoints(); + if(!qp = this_player()->GetQuestPoints()) qp = 0; + desired_level = level+1; + required_xp = advancement[desired_level]["xp"]; + if(!required_qp = advancement[desired_level]["qp"]) required_qp = 0; + if(!REQUIRE_QUESTING) required_qp = 0; + this_object()->eventForce("say Level "+desired_level+" " + "with the title of \""+advancement[desired_level]["title"]+"\" " + "requires "+required_xp+" experience points and "+ + required_qp+" quest points."); + + if( xp > required_xp-1 && qp > required_qp-1){ + this_object()->eventForce("say Congratulations! " + "You are promoted to level "+desired_level+" and " + "have earned the name "+this_player()->GetName()+" " + +advancement[desired_level]["title"]+"."); + + this_player()->ChangeLevel(desired_level); + this_player()->AddTrainingPoints(desired_level); + this_player()->AddTitle(advancement[desired_level]["title"]); + this_player()->RemoveTitle(advancement[desired_level-1]["title"]); + + this_player()->save_player(this_player()->GetKeyName()); + + if(level == MAX_NEWBIE_LEVEL){ + write("\nDirk raises his hand and sternly points to you.\n"); + say("\nDirk raises his hand and sternly points to "+ + this_player()->GetName()+".\n"); + this_object()->eventForce("say "+this_player()->GetName()+","+ + " you are no longer a newbie. From now on, you will need"+ + " a light source to see in the dark. From now on, you will"+ + " not understand languages you haven't learned. You have"+ + " earned this promotion, and now face the future as a"+ + " real adventurer."); + } + + return 1; + } + + else this_object()->eventForce("say I'm sorry, "+ + this_player()->GetName()+", but you have not " + "fulfilled all the requirements of level "+ + desired_level+". Please come back and try " + "again once you have fulfilled them."); + return 0; +} + +string GetLevelTitle(int level){ + if(!level) level = 1; + return advancement[level]["title"]; +} + +int DiamondReaction(){ + eventForce("say The Princess Daphne diamond! Good heavens!"); + eventForce("say May I please have it?"); + return 1; +} + +varargs int eventPrint(string msg, mixed arg2, mixed arg3){ + if(grepp(msg,"fabled Princess Daphne diamond")){ + call_out( (: DiamondReaction :), 0 ); + } + return ::eventPrint(msg, arg2, arg3); +} + +int CompleteQuest(object ob){ + string *quests; + object gem = present("diamond", this_object()); + quests = ob->GetQuests(); + if(!ob->GetQuest("Princess Diamond Quest")){ + ob->AddQuest("the Gemfinder","Princess Diamond Quest"); + eventForce("say You have solved the Princess Diamond Quest. " + "Congratulations!"); + eventForce("say I hereby award you 10 quest points!"); + ob->AddQuestPoints(10); + if(gem) gem->eventMove("/domains/campus/room/bookstore2"); + } + return 1; +} + +int eventReceiveObject() { + object ob, player; + ob = previous_object(); + player = this_player(); + + if( !ob || !::eventReceiveObject() ) return 0; + if(base_name(ob) == "/domains/campus/obj/diamond"){ + call_out("CompleteQuest", 0, player); + } + return 1; +} + diff --git a/lib/domains/town/npc/forest_orc.c b/lib/domains/town/npc/forest_orc.c new file mode 100644 index 0000000..d3c3731 --- /dev/null +++ b/lib/domains/town/npc/forest_orc.c @@ -0,0 +1,39 @@ +#include <lib.h> + +inherit LIB_NPC; + +int CheckOrc(mixed val){ + if(!val) return 0; + if(!objectp(val)) return 0; + if(val->GetRace() == "orc") return 0; + else eventForce("growl at "+val->GetKeyName()); + if(playerp(val) && val->GetRace() != "orc") return 1; + else return 0; +} + +static void create() { + npc::create(); + SetKeyName("orc"); + SetId(({"orc"})); + SetAdjectives(({"armored","professional"})); + SetShort("an armored orc"); + SetLong("This is a large adult orc. He seems to have a professional " + "bearing, and a sense of purpose, unlike the ragged, chaotic " + "orcs you've heard talk about. He almost appears to be on a mission."); + SetInventory(([ + "/domains/town/weap/sword" : "wield sword", + "/domains/town/obj/orc_rucksack" : "wear my sack", + "/domains/town/armor/leather_armor" : "wear leather armor", + "/domains/town/armor/orc_boot_l" : "wear left boot", + "/domains/town/armor/orc_boot_r" : "wear right boot", + ])); + SetLevel(1); + SetRace("orc"); + SetClass("explorer"); + SetGender("male"); + SetEncounter( (: CheckOrc :) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/npc/gecko.c b/lib/domains/town/npc/gecko.c new file mode 100644 index 0000000..398511b --- /dev/null +++ b/lib/domains/town/npc/gecko.c @@ -0,0 +1,21 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("gecko"); + SetAdjectives( ({"gecko", "green", "small"}) ); + SetId( ({"lizard"}) ); + SetShort("a gecko"); + SetLong("This is a small lizard, about four inches in length. It has green skin, and unusually large eyes."); + SetLevel(1); + SetMelee(1); + SetRace("lizard"); + SetMaxHealthPoints(10); + SetHealthPoints(10); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/npc/giant_isopod.c b/lib/domains/town/npc/giant_isopod.c new file mode 100644 index 0000000..9add5d6 --- /dev/null +++ b/lib/domains/town/npc/giant_isopod.c @@ -0,0 +1,22 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("isopod"); + SetAdjectives( ({"huge", "giant"}) ); + SetId(({"arthropod","creature"})); + SetShort("a giant isopod"); + SetLong("A two meter long arthropod, this huge creature sports claws, multiple limbs, and a mandibled head grotesque to most humanoids."); + SetMelee(1); + SetLevel(1); + SetRace("isopod"); + SetClass("explorer"); + SetGender("female"); + SetEncounter(100); + SetGuard("up", "The giant isopod blocks your path!"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/npc/grouper.c b/lib/domains/town/npc/grouper.c new file mode 100644 index 0000000..8a0580b --- /dev/null +++ b/lib/domains/town/npc/grouper.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <position.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("fish"); + SetAdjectives( ({"grouper", "large", "tall","flat"}) ); + SetId(({"grouper"})); + SetShort("a grouper fish"); + SetLong("A very large fish with a huge mouth and bizarrely tall, flat body."); + SetWanderSpeed(3); + //Letting npc's load virtual rooms can be dangerous. + //You were warned. + //SetPermitLoad(1); + SetPosition(POSITION_SWIMMING); + SetPacifist(1); + SetLevel(10); + SetRace("fish"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/npc/herkimer.c b/lib/domains/town/npc/herkimer.c new file mode 100644 index 0000000..dfb0830 --- /dev/null +++ b/lib/domains/town/npc/herkimer.c @@ -0,0 +1,185 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_LEADER; +int JoinGuild(object ob, string verb, string what); +int TeachSpell(object who, string verb, string spell); + +string *spells; +mapping AvailableSpells, RestrictedSpells; + +int WieldStaff(){ + if(!present("staff",this_object())){ + new("/domains/town/weap/leostaff")->eventMove(this_object()); + tell_room(environment(),"Herkimer claps his hands and a large "+ + "wooden staff materializes."); + this_object()->eventForce("wield staff"); + this_object()->eventForce("say you poor fool!"); + this_object()->eventForce("cast buffer"); + } + return 1; +} + +static void create() { + leader::create(); + SetKeyName("herkimer"); + SetId(({"archwizard","wizard","herkermer","herkirmer"})); + SetAdjectives(({"old","gentle","kindly"})); + SetShort("Herkimer the kind wizard"); + SetLong("This kindly old wizard is the master of the "+ + "local magic shop, which doubles as the Mages' Guild. "+ + "You can ask Herkimer to teach you a spell, and if "+ + "you're capable of learning it, he will teach you, "+ + "for a fee. His penetrating blue eyes seem to "+ + "see right through you, but the smile from beneath "+ + "his white beard is reassuring."); + SetLevel(300); + SetUnique(0); + SetRace("human"); + SetGender("male"); + SetClass("mage"); + SetInventory(([ + "/domains/town/armor/robe":"wear robe", + "/domains/town/armor/wizard_hat":"wear hat", + + ])); + SetSpellBook( ([ "buffer" : 100, "meditate" : 100, "missile" : 100, "fireball" : 100, "whip" : 100 ]) ); + SetAction(5, ({ + "Herkimer scratches his beard thoughtfully.", + "Herkimer seems to be trying to remember something.", "Herkimer ponders.", + "Herkimer thinks.", "Herkimer thinks carefully.", + "Herkimer says, \"%^BOLD%^CYAN%^You don't have to be a mage to learn a spell, but it sure helps.%^RESET%^\"", + "Herkimer says, \"%^BOLD%^CYAN%^The more you use your magic skills, the more proficient you become.%^RESET%^\"", + "Herkimer says, \"%^BOLD%^CYAN%^Casting spells costs you mana points. Make sure you don't run out unexpectedly!%^RESET%^\"", + "Herkimer says, \"%^BOLD%^CYAN%^If you join us and then leave the guild, you will not be alowed to become a mage again.%^RESET%^\"", + "Herkimer says, \"%^BOLD%^CYAN%^Some spells require total concentration. If you move or if you are attacked, it may interrupt the casting.%^RESET%^\"", + "Herkimer says, \"%^BOLD%^CYAN%^All magical training is free of charge to guild members, of course.%^RESET%^\"", + })); + SetCombatAction(50, ({ (: WieldStaff :), "say what is your deal?", + "say don't make me destroy you","cast fireball", "cast missile", "cast buffer"}) ); + SetCommandResponses( ([ + "join": (: JoinGuild :), + "teach" : (: TeachSpell :), + "learn" : "I have much to learn, young one, but not from you.", + ]) ); + AvailableSpells = ( ([ + "fireball" : 1000, + "greater fireball" : 3000, + "light" : 100, + "missile" : 500, + "buffer" : 200, + "greater buffer" : 2000, + "meditate" : 500, + "whip" : 10000, + ]) ); + RestrictedSpells = ( ([ + "greater fireball" : 3000, + "light" : 100, + "greater buffer" : 2000, + "whip" : 10000, + ]) ); + SetPolyglot(1); + SetLanguage("common", 100); + SetDefaultLanguage("common"); + SetCustomXP(10); +} + +void init(){ + string key; + int val; + ::init(); + spells = ({}); + foreach(key,val in AvailableSpells){ + spells += ({ key }); + } +} + +int JoinGuild(object ob, string verb, string what){ + if(ob->GetClass() == "mage") { + eventForce("say You're already in, doofus."); + return 1; + } + eventForce("say Hmm...want to join our guild, do you?"); + + if(!this_player()->GetQuest("Orc Slayer Quest")){ + eventForce("say First you must prove yourself worthy. Help my brother Leo find the Orcslayer and I will happily welcome you into our family. Until then, you may not join the mages."); + return 1; + } + if(ob->GetClass() == "explorer" || !ob->GetClass()){ + eventForce("say very well, "+ob->GetName()+"."); + eventForce("say Welcome to the mages' guild! Now you are *extremely* magic! You must practice your magic often, since you are now physically weaker than before. The stronger your magic, the stronger you are!"); + ob->ChangeClass("mage"); +#if 0 + if(ob->GetLevel() == 1){ + eventForce("say you have been demoted to a Level 1 player. However, you still retain your experience and your questing history, so just ask Dirk to promote you again a few times."); + } +#endif + return 1; + } + eventForce("say I'm sorry, it looks to me like you have already chosen your specialty. As a member of the Guildmasters' Guild, I am forbidden from removing you from the "+capitalize(ob->GetClass())+"'s Guild."); + return 1; +} + +int TeachSpell(object who, string verb, string spell){ + int cost, onhand; + mapping myspells; + if(!spell || spell == ""){ + eventForce("say Please ask again, but this time specify the spell you'd like to learn."); + return 1; + } + if(!SPELLS_D->GetSpell(spell)){ + eventForce("say I'm sorry, that is not a spell I can teach you."); + return 1; + } + if(who->GetClass() != "mage" && + member_array(spell, keys(RestrictedSpells)) != -1){ + eventForce("That spell is for guild members only."); + return 1; + } + if(member_array(spell,spells) == -1){ + eventForce("say That spell is not available right now."); + eventForce("say The spells I can teach you are "+implode(spells,", ")+"."); + return 1; + } + myspells = who->GetSpellBook(); + if(myspells[spell]){ + eventForce("say You already know that spell."); + return 1; + } + cost = AvailableSpells[spell]; + onhand = who->GetCurrency("silver"); + if(who->GetClass() != "mage" && onhand < cost) { + eventForce("say You lack enough silver coins to pay for that spell."); + eventForce("say "+spell+" costs "+cost+" silver and you "+ + "only have "+onhand+"."); + eventForce("say I can only accept silver. It's a magic thing. If you want, you can try to exchange your other currency for silver at the bank across the street."); + return 1; + } + tell_room(environment(this_object()),"Herkimer closes his eyes, mutters under his breath, and waves his hands."); + if(!who->eventLearnSpell(spell)){ + eventForce("shake"); + eventForce("say You do not appear capable of learning that spell right now."); + return 1; + } + eventForce("smile"); + eventForce("say Congratulations. You now possess the mystical knowledge of the "+spell+" spell. Use it wisely."); + if(who->GetClass() != "mage") who->AddCurrency("silver",-cost); + return 1; +} + +int eventReceiveObject() { + object ob, player; + ob = previous_object(); + player = this_player(); + + if( !ob || !::eventReceiveObject() ) return 0; + if( ob->GetKeyName() == "orc slayer" ) { + eventForce("say I'm sorry, you've got the wrong archwizard."); + eventForce("say You're looking for Leo. His workroom is the church basement."); + eventForce("give orcslayer to "+this_player()->GetKeyName()); + return 1; + } + + AddCarriedMass(ob->GetMass()); + return 1; +} diff --git a/lib/domains/town/npc/horse.c b/lib/domains/town/npc/horse.c new file mode 100644 index 0000000..ccc8810 --- /dev/null +++ b/lib/domains/town/npc/horse.c @@ -0,0 +1,27 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("horse"); + SetId(({"horse","large horse","hands","quadruped","ungulate"})); + SetAdjectives(({"large","hooved","mr","mister"})); + SetShort("a large horse"); + SetLong("A large, hooved quadruped, taller and more muscular than you. Perhaps if you befriend him, he'll allow you to mount him."); + SetNoClean(1); + SetWimpy(50); + SetLevel(5); + SetRace("horse"); + SetGender("male"); + SetMelee(1); + //SetAction(5, ({ + // "The horse snorts.", "You hear the horse whinny.", + // "The horse flips its tail in the air.", + // "The horse looks around."})); + SetMount(1); + SetCanBefriend(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/npc/human_champion.c b/lib/domains/town/npc/human_champion.c new file mode 100644 index 0000000..b3ec317 --- /dev/null +++ b/lib/domains/town/npc/human_champion.c @@ -0,0 +1,21 @@ +#include <lib.h> +inherit LIB_NPC; +static void create(){ + npc::create(); + SetKeyName("human champion"); + SetId( ({ "champion", "human","npc","warrior"}) ); + SetShort("a human champion"); + SetLong("This is a massive human warrior. His pectoral muscles "+ + "are clearly visible even through his shaggy fur and armor. His face is an angry "+ + "snarl of rage and hatred."); + SetLevel(10); + SetRace("human"); + SetClass("fighter"); + SetGender("male"); + SetInventory(([ + "/domains/campus/armor/chainmail.c" : "wear chainmail", + //"/domains/campus/armor/shield.c" : "wear shield", + "/domains/campus/weap/sharpsword.c" : "wield sword" + ])); + //SetMaxHealthPoints(550); +} diff --git a/lib/domains/town/npc/human_champion_f.c b/lib/domains/town/npc/human_champion_f.c new file mode 100644 index 0000000..8f2026a --- /dev/null +++ b/lib/domains/town/npc/human_champion_f.c @@ -0,0 +1,21 @@ +#include <lib.h> +inherit LIB_NPC; +static void create(){ + npc::create(); + SetKeyName("human champion"); + SetId( ({ "champion", "human","npc","warrior"}) ); + SetShort("a human champion"); + SetLong("This is a massive human warrior. Her huge muscles "+ + "are clearly visible even through her armor. Her face is an angry "+ + "snarl of rage and hatred."); + SetLevel(10); + SetRace("human"); + SetClass("fighter"); + SetGender("female"); + SetInventory(([ + "/domains/campus/armor/chainmail.c" : "wear chainmail", + //"/domains/campus/armor/shield.c" : "wear shield", + "/domains/campus/weap/sharpsword.c" : "wield sword" + ])); + //SetMaxHealthPoints(550); +} diff --git a/lib/domains/town/npc/ingrid.c b/lib/domains/town/npc/ingrid.c new file mode 100644 index 0000000..a7366a4 --- /dev/null +++ b/lib/domains/town/npc/ingrid.c @@ -0,0 +1,29 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("ingrid"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"non-player", "non player"})); + SetShort("Ingrid"); + SetLong("Ingrid is rather slight of build, but has a non-nonsense way about her that makes her seem much tougher than she physically looks."); + SetInventory(([ + "/domains/town/armor/hshirt" : "wear shirt", + "/domains/town/armor/workboot_l" : "wear left boot", + "/domains/town/armor/bandanna" : "wear bandanna", + "/domains/town/armor/workboot_r" : "wear right boot", + "/domains/town/armor/workglove_r" : "wear right glove", + "/domains/town/armor/jeans" : "wear jeans", + "/domains/town/armor/workglove_l" : "wear left glove", + "/domains/town/armor/lvest" : "wear vest", + ])); + SetLevel(1); + SetMelee(1); + SetRace("human"); + SetGender("female"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/npc/james.c b/lib/domains/town/npc/james.c new file mode 100644 index 0000000..83b65b1 --- /dev/null +++ b/lib/domains/town/npc/james.c @@ -0,0 +1,37 @@ +#include <lib.h> +#include <vendor_types.h> + +inherit LIB_VENDOR; + +static void create() { + ::create(); + SetKeyName("james"); + SetId( ({ "vendor","secretary","assistant","manager" }) ); + SetAdjectives( ({ "executive","medical","guild" }) ); + SetShort("James, the guild secretary and manager"); + SetLevel(12); + SetLong("James is typical of apprentice healers: he is a bit "+ + "arrogant, officious, and brusque; but he appears "+ + "to be a competent secretary and guild officer. "+ + "He is the person you will buy a treatment token "+ + "from. Read the list on the wall for the tokens "+ + "available."); + SetGender("male"); + SetMorality(40); + SetRace("human"); + AddCurrency("silver", random(100)); + SetSkill("bargaining", 1); + SetProperty("no bump", 1); + SetLocalCurrency("silver"); + SetStorageRoom("/domains/town/room/healer2"); + SetMaxItems(10000); + SetVendorType(VT_HERB); + SetSkill("bargaining", 1); + SetPolyglot(1); + SetLanguage("common", 100); + SetDefaultLanguage("common"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/npc/lars.c b/lib/domains/town/npc/lars.c new file mode 100644 index 0000000..becd811 --- /dev/null +++ b/lib/domains/town/npc/lars.c @@ -0,0 +1,57 @@ +#include <lib.h> +#include <position.h> + +inherit LIB_BARKEEP; + +mixed NoKill(object attacker); + +static void create() { + barkeep::create(); + SetKeyName("lars"); + SetId( ({ "lars", "owner", "barkeep", "bartender", "keeper" }) ); + SetShort("Lars, the keeper of the pub"); + SetLevel(1); + SetLong("Lars is the owner of the local pub, an old and famous " + "drinking establishment in the heart of town. He is an " + "unassuming fellow, and quite jovial."); + SetMenuItems(([ + ({ "espresso", "imported espresso" }) : "/domains/town/meals/espresso", + ({ "sandwich", "ham sandwich" }) : "/domains/town/meals/ham_sand", + ({ "spring water", "water" }) : "/domains/town/meals/water", + ({ "first class ale", "ale" }) : "/domains/town/meals/ale", + ({ "regular coffee", "coffee" }) : "/domains/town/meals/coffee", + ({ "firebreather" }) : "/domains/town/meals/fire", + ({ "special of the house", "special" }) : "/domains/town/meals/special", + ])); + SetGender("male"); + SetMorality(40); + SetRace("human"); + AddCurrency("electrum", random(200)); + SetSkill("bargaining", 1); + SetProperty("no bump", 1); + SetLocalCurrency("silver"); + SetAttackable( (: NoKill :) ); + SetPolyglot(1); + SetLanguage("common", 100); + SetDefaultLanguage("common"); +} +void init(){ + ::init(); +} + +mixed NoKill(object attacker){ + if(attacker->GetTown() == "Town"){ + return "Lars is like your favorite uncle. You find yourself unable to attack him."; + } + else { + tell_object(attacker,"Lars casually deflects your attack and boots you out the door."); + say("Lars casually deflects an attack from "+attacker->GetName()+" and " + "boots "+objective(attacker)+" out the door."); + tell_room("/domains/town/room/road",attacker->GetName()+" comes flying out of the pub and " + "lands on "+possessive(attacker)+" butt on the road."); + attacker->eventMove("/domains/town/room/road"); + attacker->eventDescribeEnvironment(); + attacker->SetPosition(POSITION_SITTING); + return ""; + } +} diff --git a/lib/domains/town/npc/leo.c b/lib/domains/town/npc/leo.c new file mode 100644 index 0000000..7fb2d23 --- /dev/null +++ b/lib/domains/town/npc/leo.c @@ -0,0 +1,87 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +int give_it(string str); +int WieldStaff(){ + if(!present("staff",this_object())){ + new("/domains/town/weap/leostaff")->eventMove(this_object()); + tell_room(environment(),"Leo claps his hands and a large "+ + "wooden staff materializes."); + this_object()->eventForce("wield staff"); + this_object()->eventForce("say you poor fool!"); + } + return 1; +} + +static void create() { + sentient::create(); + SetKeyName("leo"); + SetId(({"archwizard","wizard"})); + SetAdjectives(({"portly","the portly","wizard","archwizard"})); + SetShort("Leo the portly archwizard"); + SetLong("Leo is a large, friendly-looking wizard with a big "+ + "beard and a huge belly. He seems pretty busy and "+ + "somewhat preoccupied."); + SetInventory(([ + "/domains/town/armor/wizard_hat" : "wear hat", + "/domains/town/armor/robe" : "wear robe", + "/domains/town/obj/pipe" : 1, + ])); + SetLevel(300); + SetUnique(1); + SetRace("human"); + SetGender("male"); + SetClass("mage"); + SetSkill("multi-hand", 9); + SetAction(25, ({ + "Leo scratches his beard thoughtfully.", + "Leo seems to be trying to remember something.", "Leo ponders.", + "Leo thinks.", "Leo thinks carefully.", + "Leo says, \"Where in blazes did I put that Orcslayer?\"", + "Leo says, \"I just hope those pesky orcs didn't find it.\"", + "Leo says, \"I just don't have time to fight those orcs.\"" + })); + SetCombatAction(100, (: WieldStaff :)); + SetPolyglot(1); + SetLanguage("common", 100); + SetDefaultLanguage("common"); + SetCustomXP(10); +} + +int CompleteQuest(object ob){ + string *quests; + object sword = present("orcslayer", this_object()); + quests = ob->GetQuests(); + if(!ob->GetQuest("Orc Slayer Quest")){ + ob->AddQuest("the Orc Slayer","Orc Slayer Quest"); + eventForce("say You have solved the Orc Slayer Quest. Congratulations!"); + eventForce("say I hereby award you 7 quest points, and 2000 experience points!"); + ob->AddQuestPoints(7); + ob->AddExperiencePoints(2000); + if(sword) sword->eventDestruct(); + reload("/domains/town/room/valley",0,1); + reload("/domains/town/room/orc_fortress",0,1); + reload("/domains/town/room/orc_temple",0,1); + } + return 1; +} + +int eventReceiveObject(object foo) { + int ret; + object ob, player; + ob = previous_object(); + player = this_player(); + + if( !ob || !(ret = ::eventReceiveObject(foo)) ) return 0; + if(base_name(ob) == "/domains/town/weap/orcslayer"){ + this_object()->DisableActions(1); + call_out("CompleteQuest", 0, player); + call_out("EnableActions", 300, 1); + } + return ret; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/npc/mayor.c b/lib/domains/town/npc/mayor.c new file mode 100644 index 0000000..c9bc3ba --- /dev/null +++ b/lib/domains/town/npc/mayor.c @@ -0,0 +1,24 @@ +#include <lib.h> +inherit LIB_MAYOR; +void create(){ + ::create(); + SetKeyName("mayor"); + SetId("mayor"); + SetGender("male"); + SetRace("human"); + SetShort("the mayor"); + SetLong("A bit disheveled, this rather eccentric-looking "+ + "man discharges the official duties of this town's "+ + "chief executive office. Mostly, people request "+ + "citizenship from him, for a fee of 5 silver."); + SetLocalCurrency("silver"); + SetTax(5); +} +//funs +//snuf +void init() { + ::init(); + SetSmell(([ "default" : "A rather odd, musty smell."])); + SetListen(([ "default" : "The mayor grumbles something about an "+ + "unconscionably small tax revenue base."])); +} diff --git a/lib/domains/town/npc/mp.c b/lib/domains/town/npc/mp.c new file mode 100644 index 0000000..239e469 --- /dev/null +++ b/lib/domains/town/npc/mp.c @@ -0,0 +1,55 @@ +#include <lib.h> +#undef CANDIDATE + +inherit LIB_SENTIENT; + +int manchurian; + +int ProcessTalk(mixed args...){ + string speech = lower_case(args[2]); + if(sizeof(speech) > 1) speech = truncate(speech,1); + if(manchurian){ +#ifdef CANDIDATE + call_out( (: eventForce :), 1, speech); +#endif + } + if(!manchurian && grepp(speech,"solitaire") && grepp(speech,"play")){ + manchurian = 1; +#ifndef CANDIDATE + eventForce("say No, thank you. I'm on duty."); +#else + eventForce("nod"); +#endif + } + return 1; +} + +static void create(){ + sentient::create(); + SetKeyName("gate guard"); + SetId(({"human","guard","mp","soldier","policeman","military policeman"})); + SetAdjectives(({"military"})); + SetShort("a military gate guard"); + SetLong("This is a military policeman. He has "+ + "spent months in arduous training, and by the looks of him, has seen "+ + "plenty of action in his lifetime. He is large, looks very "+ + "tough, and whatever he is guarding is probably very safe."); + SetInventory(([ + "/domains/town/armor/bdu" : "wear bdu", + "/domains/town/armor/helmet2" : "wear helmet", + "/domains/town/weap/m16rifle_mp" : "wield rifle", + ])); + SetLevel(20); + SetRace("human"); + SetClass("fighter"); + SetGender("male"); + SetTalkResponses( ([ "default" : (: ProcessTalk :) ]) ); + SetPolyglot(1); + SetLanguage("common", 100); + SetDefaultLanguage("common"); +} + +void init(){ + ::init(); +} + diff --git a/lib/domains/town/npc/newt.c b/lib/domains/town/npc/newt.c new file mode 100644 index 0000000..133be26 --- /dev/null +++ b/lib/domains/town/npc/newt.c @@ -0,0 +1,23 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("newt"); + SetAdjectives( ({"slimy"}) ); + SetId(({"npc","mob","character","mobile"})); + SetShort("a newt"); + SetLong("A slimy amphibian."); + SetWanderSpeed(3); + SetMelee(1); + SetLevel(1); + SetRace("amphibian"); + SetClass("explorer"); + SetHealthPoints(10); + SetMaxHealthPoints(10); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/npc/nymph.c b/lib/domains/town/npc/nymph.c new file mode 100644 index 0000000..b8e440a --- /dev/null +++ b/lib/domains/town/npc/nymph.c @@ -0,0 +1,22 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("naiad"); + SetId( ({"nymph", "ludivine", "woman","spirit"}) ); + SetAdjectives(({"water", "beautiful"})); + SetShort("a beautiful naiad"); + SetLong("This slender nature spirit appears to be a water nymph, protecting this strange pool."); + SetClass("fighter"); + SetLevel(8); + SetMelee(1); + SetRace("nymph"); + SetGender("female"); + SetGuard("down", "The naiad playfully bars your path."); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/npc/oana.c b/lib/domains/town/npc/oana.c new file mode 100644 index 0000000..fd66526 --- /dev/null +++ b/lib/domains/town/npc/oana.c @@ -0,0 +1,34 @@ +#include <lib.h> +#include <vendor_types.h> + +inherit LIB_VENDOR; + + +static void create() { + ::create(); + SetKeyName("oana"); + SetId( ({ "shopkeep","shopkeeper","keeper","vendor"}) ); + SetAdjectives( ({ "friendly","sprightly","plain","simple" }) ); + SetShort("Oana the Magic Shop keeper"); + SetLevel(12); + SetLong("Oana is a sprightly young woman with very short "+ + "dark hair and a simple, plain "+ + "manner of dress. She is the Magic Shop "+ + "keeper, and you may trade in magical "+ + "items with her."); + SetGender("female"); + SetMorality(40); + SetRace("human"); + AddCurrency("silver", random(100)); + SetProperty("no bump", 1); + SetLocalCurrency("silver"); + SetStorageRoom("/domains/town/room/magic_shop2"); + SetMaxItems(10000); + SetVendorType(VT_MAGIC); + SetSkill("bargaining", 1); + SetLanguage("common", 100); + SetDefaultLanguage("common"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/npc/orc.c b/lib/domains/town/npc/orc.c new file mode 100644 index 0000000..98e5039 --- /dev/null +++ b/lib/domains/town/npc/orc.c @@ -0,0 +1,53 @@ +#include <lib.h> +#include <domains.h> + +inherit LIB_NPC; +int lupus; + +int AllowPass(object who, object what){ + string *allowed_races = ({ "orc", "half-orc", "bear" }); + if(member_array(who->GetRace(), allowed_races) != -1) return 1; + return ::AllowPass(who, what); +} + +int CheckOrc(mixed val){ + string *allowed_races = ({ "orc", "half-orc", "bear" }); + if(!val) return 0; + if(!objectp(val)) return 0; + if(member_array(val->GetRace(), allowed_races) != -1) return 0; + if(!strsrch(base_name(environment()), DOMAIN_EX)){ + if(!lupus){ + lupus = 1; + eventForce("say bad wolf!"); + } + return 0; + } + else eventForce("growl at "+val->GetKeyName()); + return 1; +} + +static void create() { + npc::create(); + SetKeyName("orc"); + SetId(({"orc"})); + SetAdjectives(({"dirty"})); + SetShort("a dirty orc"); + SetLong("This orc is typical of its breed: nasty, brutish, and short. It appears " + "to be a juvenile or adolescent, making it somewhat less " + "dangerous but more hostile. "); + SetLevel(1); + SetRace("orc"); + SetGender("male"); + SetMaxHealthPoints(100); + SetEncounter( (: CheckOrc :) ); + SetInventory(([ + "/domains/town/weap/dagger":"wield dagger", + ]) ); + SetGuard("west", "An orc bars your way!" ); + SetGuard("north", "An orc bars your way!"); +} +void init(){ + ::init(); +} +void reset(){ +} diff --git a/lib/domains/town/npc/orc2.c b/lib/domains/town/npc/orc2.c new file mode 100644 index 0000000..b440f10 --- /dev/null +++ b/lib/domains/town/npc/orc2.c @@ -0,0 +1,42 @@ +#include <lib.h> + +inherit LIB_NPC; + +int AllowPass(object who, object what){ + string *allowed_races = ({ "orc", "half-orc", "bear" }); + if(member_array(who->GetRace(), allowed_races) != -1) return 1; + return ::AllowPass(who, what); +} + +int CheckOrc(mixed val){ + string *allowed_races = ({ "orc", "half-orc", "bear" }); + if(!val) return 0; + if(!objectp(val)) return 0; + if(member_array(val->GetRace(), allowed_races) != -1) return 0; + else eventForce("growl at "+val->GetKeyName()); + return 1; +} + +static void create() { + npc::create(); + SetKeyName("orc"); + SetId(({"orc"})); + SetAdjectives(({"dirty"})); + SetShort("a dirty orc"); + SetLong("This orc is typical of its breed: nasty, brutish, and short. It appears " + "to be a juvenile or adolescent, making it somewhat less " + "dangerous but more hostile. "); + SetLevel(1); + SetRace("orc"); + SetGender("male"); + SetMaxHealthPoints(100); + SetEncounter( (: CheckOrc :) ); + SetInventory(([ + "/domains/town/weap/axe":"wield axe", + ]) ); + SetGuard("west", "An orc bars your way!" ); + SetGuard("north", "An orc bars your way!"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/npc/orc_boss.c b/lib/domains/town/npc/orc_boss.c new file mode 100644 index 0000000..57971ea --- /dev/null +++ b/lib/domains/town/npc/orc_boss.c @@ -0,0 +1,42 @@ +#include <lib.h> + +inherit LIB_NPC; + +int AllowPass(object who, object what){ + string *allowed_races = ({ "orc", "half-orc", "bear" }); + if(member_array(who->GetRace(), allowed_races) != -1) return 1; + return ::AllowPass(who, what); +} + +int CheckOrc(mixed val){ + string *allowed_races = ({ "orc", "half-orc", "bear" }); + if(!val) return 0; + if(!objectp(val)) return 0; + if(member_array(val->GetRace(), allowed_races) != -1) return 0; + else eventForce("growl at "+val->GetKeyName()); + return 1; +} + +static void create() { + npc::create(); + SetKeyName("boss orc"); + SetId(({"orc","boss","boss"})); + SetAdjectives(({"dirty","orc","boss"})); + SetShort("the boss orc"); + SetLong("This orc is typical of its breed: nasty, brutish, and short. It is larger " + "than the local orcs you've seen, and looks mean and tough."); + SetLevel(1); + SetRace("orc"); + SetClass("fighter"); + SetGender("male"); + SetMaxHealthPoints(200); + SetEncounter( (: CheckOrc :) ); + SetInventory(([ + "/domains/town/weap/dagger":"wield dagger", + ]) ); + SetGuard("west","The boss orc blocks your path!"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/npc/orc_shaman.c b/lib/domains/town/npc/orc_shaman.c new file mode 100644 index 0000000..d0c117f --- /dev/null +++ b/lib/domains/town/npc/orc_shaman.c @@ -0,0 +1,39 @@ +#include <lib.h> + +inherit LIB_NPC; + +int CheckOrc(mixed val){ + string *allowed_races = ({ "orc", "half-orc", "bear" }); + if(!val) return 0; + if(!objectp(val)) return 0; + if(member_array(val->GetRace(), allowed_races) != -1) return 0; + else eventForce("growl at "+val->GetKeyName()); + return 1; +} + +static void create() { + npc::create(); + SetKeyName("orc shaman"); + SetId(({"orc","shaman"})); + SetAdjectives(({"dirty"})); + SetShort("the orc shaman"); + SetLong("This orc is different from the others you've seen. "+ + "he has an unearthly ferocity about him and "+ + "is bigger, tougher, and meaner than the others."); + SetLevel(1); + SetRace("orc"); + SetClass("fighter"); + SetGender("male"); + SetMaxHealthPoints(200); + SetEncounter( (: CheckOrc :) ); + SetInventory(([ + "/domains/town/weap/gstaff":"wield staff", + "/domains/town/weap/orcslayer":1, + "/domains/town/armor/orc_helmet": "wear helmet", + "/domains/town/armor/bearskin": "wear bearskin", + ]) ); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/npc/otik.c b/lib/domains/town/npc/otik.c new file mode 100644 index 0000000..0f5c0ef --- /dev/null +++ b/lib/domains/town/npc/otik.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include <vendor_types.h> + +inherit LIB_VENDOR; + +static void create() { + ::create(); + SetKeyName("otik"); + SetId( ({ "vendor","otik", "owner", "shopkeep", "shopkeeper", "keeper" }) ); + SetShort("Otik, the keeper of the shop"); + SetLevel(12); + SetLong("Otik is the owner of the local general store, an old and famous " + "trading post in the heart of town. The brother of Lars, he also is an " + "unassuming fellow, and just as jovial."); + SetGender("male"); + SetMorality(40); + SetRace("human"); + AddCurrency("electrum", random(200)); + SetSkill("bargaining", 1); + SetProperty("no bump", 1); + SetLocalCurrency("silver"); + SetStorageRoom("/domains/town/room/shop2"); + SetMaxItems(10000); + SetVendorType(VT_ALL); + SetAttackable(0); + SetLanguage("common", 100); + SetDefaultLanguage("common"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/npc/radagast.c b/lib/domains/town/npc/radagast.c new file mode 100644 index 0000000..8b8991e --- /dev/null +++ b/lib/domains/town/npc/radagast.c @@ -0,0 +1,43 @@ +#include <lib.h> +#include <objects.h> + +inherit LIB_TRAINER; +void create(){ + trainer::create(); + SetKeyName("radagast"); + SetId("radagast the brown","wizard","mage","trainer"); + SetAdjectives(({"friendly","tall","thin","old"})); + SetGender("male"); + SetRace("human"); + SetNoSpells(1); + SetShort("Radagast the Brown"); + SetLong("This is a tall, thin old man. Not much is known of "+ + "this mysterious wizard, other than his legendary kindness "+ + "to animals and his controversial reputation as a seditious "+ + "rebel. He can train you in the arts of magic defense, magic "+ + "attack, and conjuring. You may, for example, \"ask radagast "+ + "to train conjuring\". If you lack training points, then "+ + "do some adventuring and earn a promotion from Dirk. You will "+ + "then be awarded training points."); + SetClass("mage"); + SetLevel(40); + AddTrainingSkills( ({ "magic defense", "magic attack", "conjuring" }) ); + SetSpellBook( ([ "buffer" : 100, "meditate" : 100, "missile" : 100, "fireball" : 100 ]) ); + SetPolyglot(1); + SetCustomXP(10); +} + +void init() { + trainer::init(); + SetSmell(([ "default" : "A rather odd, musty smell."])); + SetListen(([ "default" : "Radagast seems to be constantly "+ + "humming a quiet tune to himself."])); +} + +int eventHelp(object who, string unused){ + ::eventHelp(who); + this_object()->eventForce("speak Please note I only understand "+ + "English. If you're speaking to me in another language, I will "+ + "not understand!"); + return 1; +} diff --git a/lib/domains/town/npc/rainman.c b/lib/domains/town/npc/rainman.c new file mode 100644 index 0000000..c02430a --- /dev/null +++ b/lib/domains/town/npc/rainman.c @@ -0,0 +1,49 @@ +#include <lib.h> + +inherit LIB_SENTIENT; +int listen = 1; + +static void create() { + sentient::create(); + SetKeyName("rain man"); + SetId(({"rainman","man","raymond"})); + SetAdjectives(({"rain"})); + SetShort("Rain Man"); + SetLong("A distracted-looking human."); + SetClass("explorer"); + SetLevel(1); + SetMelee(0); + SetRace("human"); + SetGender("male"); +} + +void init(){ + ::init(); +} + +void receive_message(string s1, string s2){ + if(!listen) return; + listen = 0; + eventForce("say I definitely saw "+s2); + listen = 1; + if(grepp(s2," attacks ")){ + eventForce("yell STOP THE H8!"); + } +} + +varargs mixed eventHearTalk(object who, object target, int cls, string verb, + string msg, string lang) { + this_object()->receive_message("me",who->GetName()+" "+verb+ + "s: "+msg) ; + return; +} + +varargs int doPrint(string msg, string msg_class){ + this_object()->receive_message("me again",msg) ; + return 1; +} + +varargs int eventPrint(string msg, string msg_class){ + doPrint( msg, msg_class) ; + return 1; +} diff --git a/lib/domains/town/npc/rat.c b/lib/domains/town/npc/rat.c new file mode 100644 index 0000000..5094529 --- /dev/null +++ b/lib/domains/town/npc/rat.c @@ -0,0 +1,35 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +int CheckRat(mixed val){ + string *allowed_races = ({ "orc", "half-orc", "rodent" }); + if(!val) return 0; + if(!objectp(val)) return 0; + if(member_array(val->GetRace(), allowed_races) != -1) return 0; + return 1; +} + +static void create() { + sentient::create(); + SetKeyName("rat"); + SetMaxHealthPoints(10); + SetAdjectives( ({"mangy", "little", "dirty"}) ); + SetId( ({"rat"}) ); + SetShort("a rat"); + SetLong("A scruffy little dirty rat."); + SetLevel(1); + SetRace("rodent"); + SetGender("male"); + SetClass("fighter"); + SetEncounter( (: CheckRat :) ); + SetMessage("come","$N scurries in."); + SetMessage("leave","$N scurries $D."); + SetAction(5, ({ + "The rat squeaks.", "You hear a rat scuttling about.", + "A scruffy little rat brushes against your leg.", + "You hear tiny munching sounds."})); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/npc/spider.c b/lib/domains/town/npc/spider.c new file mode 100644 index 0000000..655cccc --- /dev/null +++ b/lib/domains/town/npc/spider.c @@ -0,0 +1,20 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("spider"); + SetAdjectives( ({"huge", "hairy"}) ); + SetId(({"npc","mob","character","mobile"})); + SetShort("a huge spider"); + SetLong("This is a humongous hairy spider about the size of a housecat. It looks absolutely vile and it has some kind of viscous fluid is dripping from its mouthparts."); + SetMelee(1); + SetLevel(1); + SetRace("arachnid"); + SetClass("explorer"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/npc/thief.c b/lib/domains/town/npc/thief.c new file mode 100644 index 0000000..690d386 --- /dev/null +++ b/lib/domains/town/npc/thief.c @@ -0,0 +1,30 @@ +#include <lib.h> + +inherit LIB_NPC; + +static void create() { + npc::create(); + SetKeyName("thief"); + SetId(({"thief in a bathtowel","thief in a towel","thief"})); + SetAdjectives(({"wet"})); + SetShort("a thief in a bathtowel"); + SetLong("From his furtive appearance and demeanor, this "+ + "is obviously a thief who has snuck into the "+ + "mansion and taken up residence. You seem "+ + "to have caught him just after his shower."); + SetLevel(1); + SetRace("human"); + SetClass("thief"); + SetGender("male"); + SetEncounter(100); + SetMaxHealthPoints(25); + SetInventory(([ + "/domains/town/armor/towel":"wear towel", + "/domains/town/weap/brush":"wield brush", + ]) ); + SetHealthPoints(50); + SetGuard("down", "The wet thief bars your way!" ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/npc/troll.c b/lib/domains/town/npc/troll.c new file mode 100644 index 0000000..f9d5953 --- /dev/null +++ b/lib/domains/town/npc/troll.c @@ -0,0 +1,52 @@ +#include <lib.h> + +inherit LIB_NPC; +object gdude; + + +int nasty(object dude){ + if(!dude) return 0; + gdude = dude; + eventForce("look at "+gdude->GetKeyName()); + eventForce("drool"); + return 1; +} + +int CheckHuman(mixed val){ + if(!val) return 0; + if(!objectp(val)) return 0; + gdude = val; + if(val->GetRace() != "human") return 0; + else { + call_out( (: nasty, gdude :) , 2); + } + return 1; +} +static void create() { + npc::create(); + SetKeyName("troll"); + SetId(({"troll"})); + SetAdjectives(({"dirty"})); + SetShort("a mean-looking troll"); + SetLong("This is the dreaded creature of legend: a slimy, " + "green, putrid-looking fiend with long, razor-" + "sharp claws and fangs."); + SetLevel(3); + SetRace("troll"); + SetClass("fighter"); + SetGender("male"); + SetMelee(1); + SetEncounter( (: CheckHuman :) ); + SetSkill("melee attack",50,50,10); + SetStat("strength",50,1); + SetStat("agility",50,1); + SetStat("coordination",50,1); + SetStat("speed",50,1); + AddCurrency("silver",221+random(157)); + SetInventory( ([ + "/domains/town/obj/bait_can" : 1, + ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/npc/viper.c b/lib/domains/town/npc/viper.c new file mode 100644 index 0000000..2ac2416 --- /dev/null +++ b/lib/domains/town/npc/viper.c @@ -0,0 +1,22 @@ +#include <position.h> +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("viper"); + SetAdjectives( ({"dangerous", "venomous", "pit"}) ); + SetId( ({"snake", "reptile"}) ); + SetShort("a pit viper"); + SetLong("This is a thickly-built snake, about three feet long, with a brown and black pattern along its muscular body. A member of the family viperidae, it is a class of snake known for the deadliness of its venom."); + SetAutoStand(0); + SetPosition(POSITION_LYING); + SetLevel(3); + SetMelee(1); + SetRace("viper"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/npc/zafo.c b/lib/domains/town/npc/zafo.c new file mode 100644 index 0000000..9114305 --- /dev/null +++ b/lib/domains/town/npc/zafo.c @@ -0,0 +1,90 @@ +// IMPORTANT NOTE +// Zafo does not speak Common. He is a simple human and only +// speaks English. For him to understand what you say, you +// MUST SPEAK IN ENGLISH. +// Or edit this file to make him know Common. + +/* This is an example of parsing talk. The CopResponse() function + * is a bit silly, because it tries to parse words, and as such is + * doomed to failure, since it is trying to be an language/meaning + * AI. Really it should be done with phrases. But for educational + * purposes, this example is here. + * -Crat 13FEB2008 + */ + +#include <lib.h> + +inherit LIB_SENTIENT; + +mixed CopResponse(object who, mixed foo, string message, mixed bar){ + string *message_array, *stupid_array, *cop_array; + int i, not_stupid; + + //make sure the message string actually exists + if(!sizeof(message)) return 0; + //parsing is easier in a single case + message = lower_case(message); + //make an array whose elements are the individual words + //of the message, for example ({ "cops", "are", "not", "stupid" }) + message_array = explode(message," "); + + //Now we take the message array and create a new array called cop_array + //that contains words in message_array that start with "cop" and the next character + //is either nothing (cop) or an s (cops) or punctuation(cop.). + //Note that this would allow something like "copse" + cop_array = regexp(message_array, "cop(''|s|[!-@])"); + //Now we create an array that does the same thing but with the + //word "stupid" + stupid_array = regexp(message_array, "stupid(''|[!-@])"); + //Here we find out whether the word "not" is a memeber of the message + //array. If it is not a member, i will be -1. Otherwise, i will be + //the index number of the word. For example, in ({ "cops", "are", "not", "stupid" }), + //"cop" is 0, and "not" is 2. + i = member_array("not", message_array); + //Now we determine if "not" is in the array, by checking to see if the + //value of i is -1. If it is not -1, then we check to see if there is + //another word after it in the array (i+1). If there is, we check to see + //if that word contains the string "stupid". And if it does, then we + //assign not_stupid a value of 1. + if(i != -1 && message_array[i+1] && grepp(message_array[i+1],"stupid")){ + not_stupid = 1; + } + + //If we have a matching cop word, and a matching stupid word, and + //if the word "not" is *not* in front of the word stupid, then + //we'll go ahead and have a reaction. + if(sizeof(cop_array) && sizeof(stupid_array) && !not_stupid){ + eventForce("laugh"); + eventForce("say LOL you said 'stupid' and 'cop!'"); + return 1; + } + //Otherwise we just return an arbitrary value. + else return 0; +} + +static void create() { + sentient::create(); + SetKeyName("zafo"); + SetId(({"dude"})); + SetAdjectives(({"punk rock", "punkrock", "rock", "cool"})); + SetShort("Zafo"); + SetLong("Zafo is a cool dude, and totally punk rock."); + SetLevel(10); + SetRace("human"); + SetClass("fighter"); + SetGender("male"); + SetInventory( ([ + "/domains/town/armor/jacket" : "wear jacket", + "/domains/town/armor/pants" : "wear pants", + "/domains/town/armor/boot_l" : "wear left boot", + "/domains/town/armor/boot_r" : "wear right boot", + ]) ); + SetTalkResponses( ([ + "s up" : "Nothin'.", + "re you rebelling against" : "Waddaya got?", + "cop" : (: CopResponse :), + ]) ); +} +void init(){ + sentient::init(); +} diff --git a/lib/domains/town/npc/zoe.c b/lib/domains/town/npc/zoe.c new file mode 100644 index 0000000..8c4bf31 --- /dev/null +++ b/lib/domains/town/npc/zoe.c @@ -0,0 +1,35 @@ +#include <lib.h> +#include <vendor_types.h> + +inherit LIB_TELLER; + + +static void create() { + ::create(); + SetKeyName("zoe"); + SetId( ({ "teller","banker","executive","shawty" }) ); + SetAdjectives( ({ "bank","executive","friendly","efficient" }) ); + SetShort("Zoe the bank teller"); + SetLevel(12); + SetLong("Zoe is an attractive young blonde woman with " + "a French accent. She is dressed in a conservative, " + "executive style, and has a friendly and efficient air " + "about her."); + SetGender("female"); + SetMorality(40); + SetRace("human"); + AddCurrency("silver", random(100)); + SetProperty("no bump", 1); + SetBankName("First Village Bank"); + SetLocalCurrency("silver"); + SetLocalFee(1); + SetOpenFee(5); + SetExchangeFee(2); + SetCurrencies( ({ "dollars", "copper", "silver", "electrum", "gold", "platinum" }) ); + SetPolyglot(1); + SetLanguage("common", 100); + SetDefaultLanguage("common"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/223clip.c b/lib/domains/town/obj/223clip.c new file mode 100644 index 0000000..d65aa8f --- /dev/null +++ b/lib/domains/town/obj/223clip.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_CLIP; + +void create(){ + clip::create(); + SetKeyName(".223 clip"); + SetId(({"clip","magazine"})); + SetAdjectives(({".223","rifle","caliber","ammo","ammunition"})); + SetShort("a .223 caliber rifle ammunition clip"); + SetLong("This is a spring-loaded ammunition clip for a .223 caliber "+ + "rifle. It will contain a maximum of thirty rounds."); + SetCaliber(223); + SetMaxAmmo(30); + SetMass(5); + SetAmmoType("nato"); + SetVendorType(VT_TREASURE); + SetInventory(([ + "/domains/town/obj/223round" : 30, + ])); + SetBaseCost("silver", 75); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/223round.c b/lib/domains/town/obj/223round.c new file mode 100644 index 0000000..52bedc1 --- /dev/null +++ b/lib/domains/town/obj/223round.c @@ -0,0 +1,20 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ROUND; + +void create(){ + round::create(); + SetKeyName("223round"); + SetId(({"round","bullet"})); + SetAdjectives(({".223","caliber","rifle","m16","M16","m-16","M-16"})); + SetShort("a .223 caliber rifle round"); + SetLong("This is a .223 caliber rifle round, probably for an M-16 assault rifle. "+ + "It is not very wide, but contains a large powder charge. It is no doubt a powerful "+ + "piece of ammunition. It has not been fired."); + SetCaliber(223); + SetMass(1); + SetFirearmType("auto"); + SetFirearmType("auto"); + SetAmmoType("nato"); + SetVendorType(VT_TREASURE); +} diff --git a/lib/domains/town/obj/357round.c b/lib/domains/town/obj/357round.c new file mode 100644 index 0000000..8e8252e --- /dev/null +++ b/lib/domains/town/obj/357round.c @@ -0,0 +1,17 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ROUND; + +void create(){ + round::create(); + SetKeyName(".357 round"); + SetId(({"round","bullet"})); + SetAdjectives(({".357","caliber","revolver","pistol"})); + SetShort("a .357 pistol round"); + SetLong("This is a .357 caliber revolver bullet. It has not been fired."); + SetCaliber(357); + SetFirearmType("revolver"); + SetAmmoType("magnum"); + SetVendorType(VT_TREASURE); + SetMass(1); +} diff --git a/lib/domains/town/obj/357shell.c b/lib/domains/town/obj/357shell.c new file mode 100644 index 0000000..1f285f1 --- /dev/null +++ b/lib/domains/town/obj/357shell.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_SHELL; + +void create(){ + ::create(); + SetKeyName("357shell"); + SetId(({"shell","casing","spent bullet"})); + SetAdjectives(({".357",".357","spent","magnum","shell"})); + SetShort("a .357 shell casing"); + SetLong("This is the spent casing of a .357 magnum bullet."); + SetCaliber(357); + SetFirearmType("revolver"); + SetAmmoType("magnum"); + SetVendorType(VT_TREASURE); + SetMass(1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/45round.c b/lib/domains/town/obj/45round.c new file mode 100644 index 0000000..183a4e2 --- /dev/null +++ b/lib/domains/town/obj/45round.c @@ -0,0 +1,17 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ROUND; + +void create(){ + round::create(); + SetKeyName(".45 round"); + SetId(({"round","bullet"})); + SetAdjectives(({".45","caliber","acp","pistol","semiautomatic"})); + SetShort("a .45 caliber pistol round"); + SetLong("This is a .45 caliber bullet for a semiautomatic pistol. It has not been fired."); + SetCaliber(45); + SetFirearmType("auto"); + SetAmmoType("acp"); + SetVendorType(VT_TREASURE); + SetMass(1); +} diff --git a/lib/domains/town/obj/50round.c b/lib/domains/town/obj/50round.c new file mode 100644 index 0000000..e56d188 --- /dev/null +++ b/lib/domains/town/obj/50round.c @@ -0,0 +1,19 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ROUND; + +void create(){ + round::create(); + SetKeyName(".50 round"); + SetId(({"round","bullet"})); + SetAdjectives(({".50","caliber","rifle"})); + SetShort("a .50 caliber rifle bullet"); + SetLong("This mammoth bullet is nearly five inches long. Anything this bad "+ + "boy hits is in for a rough time."); + SetCaliber(50); + SetFirearmType("bolt"); + SetFirearmType("bolt"); + SetAmmoType("bolt"); + SetVendorType(VT_TREASURE); + SetMass(1); +} diff --git a/lib/domains/town/obj/8ball.c b/lib/domains/town/obj/8ball.c new file mode 100644 index 0000000..627ad08 --- /dev/null +++ b/lib/domains/town/obj/8ball.c @@ -0,0 +1,74 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +inherit LIB_SHAKE; +inherit LIB_CONSULT; + +string answer = ""; + +string *answers = ({ + "Signs point to yes.", + "Yes.", + "Most likely.", + "Without a doubt.", + "Yes - definitely.", + "As I see it, yes.", + "You may rely on it.", + "Outlook good.", + "It is certain.", + "It is decidedly so.", + "Reply hazy, try again.", + "Better not tell you now.", + "Ask again later.", + "Concentrate and ask again.", + "Cannot predict now.", + "My sources say no.", + "Very doubtful.", + "Outlook not so good.", + "My reply is no.", + "Don't count on it.", +}); + +void create(){ + ::create(); + SetKeyName("magic 8 ball"); + SetId( ({"ball","8ball","8-ball","8 ball"}) ); + SetAdjectives( ({"giant","billiard","black","magic"}) ); + SetShort("a magic 8 ball"); + SetLong("This is a plastic sphere, about the size of a human hand, "+ + "and black in color. On one side a white circle is painted, with the "+ + "numeral 8 in the middle, as if it were a giant billiard ball. On "+ + "the other side of the sphere is a little clear window. It would "+ + "appear that one shakes this ball, then consults it, to get advice."); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + answer = answers[random(sizeof(answers))]; + SetRead( (: eventConsult :) ); +} + +void init(){ + ::init(); +} + +varargs mixed eventShake(object dude, string foo){ + write("You shake your magic 8 ball."); + say(dude->GetName()+" shakes "+possessive(dude)+" magic 8 ball."); + answer = answers[random(sizeof(answers))]; + return 1; +} + +varargs mixed eventConsult(object dude, string foo){ + write("The magic 8 ball answers: \n"+answer); + if(!dude) dude = this_player(); + say(dude->GetName()+" consults "+possessive(dude)+" magic 8 ball."); + return 1; +} + +varargs mixed CanConsult(object who, string component){ + return 1; +} + +varargs mixed CanShake(object who, string component){ + return 1; +} diff --git a/lib/domains/town/obj/9mmclip.c b/lib/domains/town/obj/9mmclip.c new file mode 100644 index 0000000..ae7c37c --- /dev/null +++ b/lib/domains/town/obj/9mmclip.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_CLIP; + +void create(){ + clip::create(); + SetKeyName("9mm clip"); + SetId(({"clip","magazine"})); + SetAdjectives(({"9mm","ammunition","ammo","9 millimeter","pistol"})); + SetShort("a 9 millimeter pistol ammunition clip"); + SetLong("This is a slender, spring-loaded metal container designed "+ + "to feed a 9 millimeter pistol with bullets."); + SetMillimeter(9); + SetMaxAmmo(15); + SetAmmoType("acp"); + SetVendorType(VT_TREASURE); + SetMass(5); + SetBaseCost("silver", 45); + SetInventory(([ + "/domains/town/obj/9mmround" : 15 + ])); +} + +void init(){ + clip::init(); +} diff --git a/lib/domains/town/obj/9mmclip_empty.c b/lib/domains/town/obj/9mmclip_empty.c new file mode 100644 index 0000000..df110c7 --- /dev/null +++ b/lib/domains/town/obj/9mmclip_empty.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include <vendor_types.h> +inherit "/lib/clip"; +void create(){ + ::create(); + SetKeyName("9mmclip"); + SetId(({"clip","magazine"})); + SetAdjectives(({"9mm","ammunition","ammo","9 millimeter","pistol"})); + SetShort("a 9 millimeter pistol ammunition clip"); + SetLong("This is a slender, spring-loaded metal container designed "+ + "to feed a 9 millimeter pistol with bullets."); + SetMillimeter(9); + SetMaxAmmo(15); + SetMass(5); + SetBaseCost("silver", 15); + SetAmmoType("acp"); + SetVendorType(VT_TREASURE); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/9mmround.c b/lib/domains/town/obj/9mmround.c new file mode 100644 index 0000000..cf82cd9 --- /dev/null +++ b/lib/domains/town/obj/9mmround.c @@ -0,0 +1,17 @@ +#include <lib.h> +#include <vendor_types.h> +inherit "/lib/round"; + +void create(){ + ::create(); + SetKeyName("9mmround"); + SetId(({"round","bullet"})); + SetAdjectives(({"9 millimeter","9mm","pistol"})); + SetShort("a 9 millimeter pistol round"); + SetLong("This is a 9 millimeter pistol bullet. It has not been fired."); + SetMillimeter(9); + SetFirearmType("auto"); + SetAmmoType("acp"); + SetVendorType(VT_TREASURE); + SetMass(1); +} diff --git a/lib/domains/town/obj/altar.c b/lib/domains/town/obj/altar.c new file mode 100644 index 0000000..b78c890 --- /dev/null +++ b/lib/domains/town/obj/altar.c @@ -0,0 +1,36 @@ +#include <lib.h> +#include <props.h> + +inherit LIB_BED; +inherit LIB_SMELL; + +static void create() { + bed::create(); + SetKeyName("altar"); + SetId( ({ "altar","platform","pedestal" }) ); + SetAdjectives( ({ "orcish", "simple","stone" }) ); + SetShort("a simple stone altar, dripping blood"); + SetLong("This is a ceremonial orcish altar, where "+ + "holy offerings and sacrifices are made. It is "+ + "sheeted in dried blood and rotting tissue."); + SetItems( ([ + ({"blood","dried blood","tissue","rotting tissue"}) : ""+ + "This appears to be the accumulated detritus of "+ + "numerous sacrifices.", + ]) ); + SetPreventGet("The altar is dug into the floor and does not move."); + SetInventory(([ + "/domains/town/weap/boobytrap_dagger" : 1, + "/domains/town/armor/boobytrap_ring" : 1, + ])); + SetMass(3000); + SetBaseCost("silver",15); + SetMaxSitters(2); + SetMaxLiers(1); + SetMaxCarry(5000); + SetSmell( ([ "default" : "The altar is nauseatingly rank."]) ); +} + +void init(){ + bed::init(); +} diff --git a/lib/domains/town/obj/bag.c b/lib/domains/town/obj/bag.c new file mode 100644 index 0000000..bcdf0f9 --- /dev/null +++ b/lib/domains/town/obj/bag.c @@ -0,0 +1,18 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("bag"); + SetAdjectives( ({"small", "cloth"}) ); + SetId( ({ "bag" }) ); + SetShort("a small cloth bag"); + SetLong("It is a simple cloth bag used to hold things. "); + SetMass(5); + SetBaseCost("silver",1); + SetMaxCarry(50); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/bait_can.c b/lib/domains/town/obj/bait_can.c new file mode 100644 index 0000000..7cc87b5 --- /dev/null +++ b/lib/domains/town/obj/bait_can.c @@ -0,0 +1,24 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("can"); + SetId( ({"tin","container","bait","b8"}) ); + SetAdjectives( ({"tin","bait","small","master","master brand","great","gr8"}) ); + SetShort("a small can"); + SetLong("A small can that is designed to hold small things. There is a label "+ + "on it you can read."); + SetMass(5); + SetBaseCost("silver",1); + SetMaxCarry(20); + SetInventory( ([ + "/domains/town/meals/worm" : 15, + ]) ); + SetRead( ([ "label" : "MASTER Brand fish bait (TM): \"Oi m8, this b8 is gr8!" ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/basement_button.c b/lib/domains/town/obj/basement_button.c new file mode 100644 index 0000000..d9a6193 --- /dev/null +++ b/lib/domains/town/obj/basement_button.c @@ -0,0 +1,23 @@ +#include <lib.h> + +inherit LIB_DUMMY; // These do not show up in desc, but you can look at them +inherit LIB_PRESS; // Makes the item pressable + +int openDoor(object who) { + object car; + send_messages("press", "$agent_name $agent_verb the button.", + who, 0, environment(who)); + car=load_object("/domains/town/room/elevator"); + car->CallMe(2); + +} + +static void create() { + dummy::create(); + SetKeyName("button"); + SetId(({"button","button on the wall" })); + SetAdjectives("call", "elevator"); + SetShort("a button"); + SetLong("It is a button that you could probably press."); + SetPress((: openDoor :)); +} diff --git a/lib/domains/town/obj/bbucket.c b/lib/domains/town/obj/bbucket.c new file mode 100644 index 0000000..dd8f088 --- /dev/null +++ b/lib/domains/town/obj/bbucket.c @@ -0,0 +1,35 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("bin"); + SetId(({"bin","can","dustbin","trash","rubbish"})); + SetAdjectives(({"metal","small","blue","recycling","trash","garbage","dust"})); + SetShort("a recycling bin"); + SetLong("This is a blue trash can, marked with "+ + "the letters \"/dev/null\"."); + SetMass(274); + SetBaseCost("silver",50); + SetMaxCarry(999999); +} + +int tidy_up(){ + object *inv; + inv = all_inventory(this_object()); + foreach(object thing in inv){ + if(thing) thing->eventMove(load_object("/domains/town/room/furnace")); + } + return 1; +} + +int eventReceiveObject(object ob){ + write("You make a deposit into the the recycling bin.\n"); + call_out((: tidy_up :),1); + return 1; +} +mixed CanGet(object ob) { return "The bucket does not budge.";} + +void init(){ +} diff --git a/lib/domains/town/obj/bed.c b/lib/domains/town/obj/bed.c new file mode 100644 index 0000000..dab87d9 --- /dev/null +++ b/lib/domains/town/obj/bed.c @@ -0,0 +1,43 @@ +#include <lib.h> +#include <props.h> + +inherit LIB_BED; +inherit LIB_PRESS; +inherit LIB_MANIPULATE; + +int MoveBed(); +int PushBed(); +static void create() { + ::create(); + SetKeyName("king-sized bed"); + SetId( ({ "cot","bed" }) ); + SetAdjectives( ({ "large","king-sized","king-size","four-poster","four poster","big","very big"}) ); + SetShort("a large four-poster bed"); + SetLong("This is a very big bed, with a large, decorative wooden " + "post at each corner. Though one might expect " + "a canopy over such a bed, it is absent here."); + SetMass(4000); + SetMaxCarry(4000); + SetBaseCost("silver",1500); + SetMaxSitters(2); + SetMaxLiers(1); + SetPreventGet(1); + SetManipulate( ([ "default" : (: MoveBed :) ]) ); + SetPress( ([ "default" : (: PushBed :) ]) ); +} + +int MoveBed(){ + send_messages("move", "$agent_name $agent_verb the bed.", + this_player(), 0, environment(this_player())); + environment(this_object())->OpenPassage(); + return 1; +} +int PushBed(){ + send_messages("move", "$agent_name $agent_verb the bed.", + this_player(), 0, environment(this_player())); + environment(this_object())->OpenPassage(); + return 1; +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/bigbag.c b/lib/domains/town/obj/bigbag.c new file mode 100644 index 0000000..e687720 --- /dev/null +++ b/lib/domains/town/obj/bigbag.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("bag"); + SetId( ({ "bag" }) ); + SetAdjectives( ({ "giant", "cloth", "a" }) ); + SetShort("a giant cloth bag"); + SetLong("It is a simple cloth bag used to hold things. "); + SetMass(100); + SetBaseCost("silver",1); + SetMaxCarry(2000); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/bin.c b/lib/domains/town/obj/bin.c new file mode 100644 index 0000000..a550b7b --- /dev/null +++ b/lib/domains/town/obj/bin.c @@ -0,0 +1,34 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("bin"); + SetAdjectives( ({"newbie", "charity", "freebie"}) ); + SetId( ({"newbie bin"}) ); + SetShort("the newbie bin"); + SetLong("This medium-sized bin is designed to hold stuff that may be of use to newbies. By default it contains stuff that won't sell for much, but players are encouraged to make generous contributions for the benefit of weaker players. To view its contents: look in bin"); + SetInventory(([ + "/domains/town/obj/slip_heal" : 1, + "/domains/town/obj/match" : 5, + "/domains/town/obj/slip_regenerate" : 1, + "/domains/town/obj/slip_excise" : 3, + "/domains/town/obj/rayovac" : 1, + "/domains/town/obj/spam" : 1, + "/domains/town/obj/dcell" : 2, + "/domains/town/obj/torch" : 1, + ])); + SetMaxCarry(3500); + SetNoCondition(1); + SetCanClose(0); + SetMass(100); + SetBaseCost("silver",1); + SetNoClean(1); +} + +void init(){ + ::init(); +} + +mixed CanGet(object ob) { return "The bucket does not budge.";} diff --git a/lib/domains/town/obj/btable.c b/lib/domains/town/obj/btable.c new file mode 100644 index 0000000..1c1d418 --- /dev/null +++ b/lib/domains/town/obj/btable.c @@ -0,0 +1,256 @@ +/* Stupid blackjack table + * works, other than the fact that the value of ace always equals 1. + * by boy@frontiers. + * (You can get two of the same card, like two 8 of spades.) + * Too hard and too much work to simulate a whole deck. + */ +#include <lib.h> +inherit LIB_ITEM; +void StupidAce(); +int needace; +int aceval; +int gameon; +int score; +int dscore; +int bet; +int plidle; +string playername,oldplayername; +object player,oldplayer,here; +void cleanup(); +void eventDealerHit(); +void YouWin(); +void YouLose(); + +int read(string args) { + write("The small letters read..."); + write(" %^CYAN%^Dealer stands pat at 17."); write(" %^CYAN%^Ties go to the house."); + write("deal <amount> : Starts the game, wagering <amount>"); write(" hit : Requests a new card"); + write(" stand pat : Ends the game"); + return 1; +} + +static void create() { + ::create(); + SetShort("a blackjack table"); + SetLong("A small mechanical blackjack table lies here, " + "with a miniature robotic dealer " + "built into it. It seems like you can win...err " + "try to win a lot of money here. There are some small " + "printed letters on the table."); + SetPreventGet("You cannot get that!"); + SetMass(0); + SetId( ({"table", "blackjack table"}) ); + SetKeyName("table"); + SetItems( ([ + ({"writing","letters"}): "Some writing on the table. Try \"read "+ + "writing on table\"", + ]) ); + SetRead( ([ + ({"writing","letters"}) : (: read :), + ]) ); + SetDefaultRead("default", (: read :) ); + oldplayername="this_is_a_silly_string"; +} +void init() { + ::init(); + add_action("eventHit", "hit"); + add_action("eventStand", "stand"); + add_action("eventDeal", "deal"); +} +int eventHit() { + int done; + int cardscore; + string card, suit; + int x; + done = 0; + if (gameon == 0) { + write("A game has not started yet, type \"deal\" to start one."); + return 1; + } + if(gameon == 1 && this_player()->GetName() != oldplayername) { + write("You are not playing right now."); + return 1; + } + x = random(13); + switch (x + 1) { + case 1 : card = "Ace"; + break; + case 11 : card = "Jack"; + break; + case 12 : card = "Queen"; + break; + case 13 : card = "King"; + break; + default : card = ""+(x + 1); + } + switch (random(4)) { + case 1 : suit = "Hearts"; + break; + case 2 : suit = "Spades"; + break; + case 3 : suit = "Diamonds"; + break; + case 0 : suit = "Clubs"; + } + write("%^BLUE%^You get a " + card + " of " + suit); + if (x == 0) { + StupidAce(); + cardscore = aceval; + done = 1; + } + if (x > 9) { + cardscore = 10; + done = 1; + } + else { + if (done == 0) { + cardscore = x + 1; + } + } + score += cardscore; + if (score > 21) { + if(aceval == 11) { + aceval = 1; + score -= 11; + write("%^CYAN%^Your score is " + score); + } + else { + YouLose(); + } + } + if (score == 21) { + YouWin(); + } + return 1; +} +int eventStand(string str) { + int lose; + + if(str != "pat") return 0; + if (gameon == 0) { + write("A game has not started yet, type \"deal\" to start one"); + return 1; + } + if(gameon == 1 && this_player()->GetName() != oldplayername) { + write("You are not playing right now."); + return 1; + } + write("%^CYAN%^Your final score is " + score); + + if (dscore < 22) { + write("%^BOLD%^The dealer's score is " + dscore); + } + else { + write("%^BOLD%^The dealer busts"); + } + if (score > dscore && score < 21) { + YouWin(); + } + else { + if (dscore > 21) { + YouWin(); + } + else { + YouLose(); + } + } + return 1; +} +void cleanup() { + oldplayername = "this_is_a_silly_string"; + aceval=0; + score = 0; + dscore = 0; + bet = 0; + gameon = 0; +} +int eventDeal(string args) { + player=this_player(); + playername=player->GetName(); + here=environment(this_object()); + if(oldplayer) plidle=query_idle(oldplayer); + + if (!args) { + write("%^YELLOW%^Please try that again, including the amount of money you want to wager."); + return 1; + } + sscanf(args, "%d", bet); + if(!intp(bet) || bet <= 0){ + write("You must wager an amount.\n"); + return 1; + } + if (this_player()->GetCurrency("silver") < bet) { + write("You don't have that many silver!"); + return 1; + } + if (gameon == 1 && present(oldplayername,here) && plidle < 120 ) { + write("%^RED%^"+oldplayername+" is playing right now. There is room for only one player."); + return 1; + } + if (gameon == 1 && present(oldplayername,here) && plidle > 120 ) { + write("%^RED%^"+oldplayername+" was playing, but "+nominative(oldplayer)+" has gone idle "+ + "and the dealer deals "+objective(oldplayer)+" out.",oldplayer); + say(oldplayername+" has been dealt out of the blackjack table for idleness.",oldplayer); + tell_object(oldplayer,"You've been dealt out of the blackjack table for idleness."); + cleanup(); + } + if (gameon == 1 && !present(oldplayername,here) ) { + write("%^RED%^"+oldplayername+" was playing, but "+nominative(oldplayer)+" has left, and the dealer deals "+ + objective(oldplayer)+" out."); + say(oldplayername+" has been dealt out of the blackjack table because "+nominative(oldplayer)+" left.",oldplayer); + tell_object(oldplayer,"You suddenly remember you left a blackjack game in the middle of it, "+ + "and you've probably been dealt out."); + cleanup(); + } + + oldplayername = playername; + oldplayer = player; + gameon = 1; + write("%^RED%^You ask the dealer to count you into the next game."); + say("%^YELLOW%^" + this_player()->GetName() + " starts playing blackjack."); + this_player()->AddCurrency("silver", -bet); + eventDealerHit(); + eventHit(); + eventHit(); + write("%^CYAN%^Your current score is " + score); + return 1; +} +void eventDealerHit() { + + int cardscore; + int x; + while (dscore < 17) { + x = random(13); + if (x > 9) { + dscore += 10; + } + else { + dscore += x; + } + } +} +void YouLose() { + write("Your score is " + score); + write("%^RED%^You lose"); + say("%^YELLOW%^" + this_player()->GetName() + " loses."); + cleanup(); +} +void YouWin() { + write("Your score is " + score); + write("%^GREEN%^You win!"); + say("%^YELLOW%^" + this_player()->GetName() + " wins!"); + this_player()->AddCurrency("silver", 2 * bet); + cleanup(); +} +void StupidAce() { + int temp; + if ((score + 11) > 21) { + aceval = 1; + } + else { + aceval = 11; + } + temp = aceval + score; + write("%^CYAN%^Your current score is " + temp); +} + diff --git a/lib/domains/town/obj/candlestick.c b/lib/domains/town/obj/candlestick.c new file mode 100644 index 0000000..a5e48e4 --- /dev/null +++ b/lib/domains/town/obj/candlestick.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +void create(){ + ::create(); + SetKeyName("silver candlestick"); + SetId( ({"candlestick","candelabra","candelabrum"}) ); + SetAdjectives( ({"small","ornate","silver"}) ); + SetShort("a silver candlestick"); + SetLong("This is an small, ornate silver candlestick."); + SetMass(20); + SetBaseCost("silver",50); + SetVendorType(VT_TREASURE); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/canteen.c b/lib/domains/town/obj/canteen.c new file mode 100644 index 0000000..d6df4d3 --- /dev/null +++ b/lib/domains/town/obj/canteen.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> +inherit LIB_FLASK; + +void create(){ + ::create(); + SetKeyName("canteen"); + SetId( ({"canteen","vessel"}) ); + SetAdjectives( ({"plastic","green"}) ); + SetShort("a green plastic canteen"); + SetLong("A plastic vessel for containing fluids."); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetFlaskContents("water"); + SetFlaskUses(10); + SetStrength(5); + SetMaxFlask(10); + SetMealType(MEAL_DRINK); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/cavetroll_key.c b/lib/domains/town/obj/cavetroll_key.c new file mode 100644 index 0000000..9a8c218 --- /dev/null +++ b/lib/domains/town/obj/cavetroll_key.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("key"); + SetId( ({ "key", "cavetroll key" }) ); + SetAdjectives( ({ "metal" }) ); + SetShort("a metal key"); + SetLong("It is a key made of metal."); + SetMass(1); + SetBaseCost("silver",1); + SetDisableChance(100); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/chair.c b/lib/domains/town/obj/chair.c new file mode 100644 index 0000000..a4c367e --- /dev/null +++ b/lib/domains/town/obj/chair.c @@ -0,0 +1,36 @@ +#include <lib.h> + +inherit LIB_CHAIR; +inherit LIB_SWIVEL; + +static void create() { + chair::create(); + SetKeyName("chair"); + SetId("chair"); + SetAdjectives( ({ "swivel", "small", "black" }) ); + SetShort("a swivel chair"); + SetLong("This is a small swivel chair, with tasteful and understated "+ + "black covers."); + SetMass(150); + SetDollarCost(15); + SetMaxSitters(1); + SetPreventGet("The chair does not budge."); +} + +void init(){ + chair::init(); +} + +varargs mixed eventSwivel(object who){ + if(member_array(who, GetSitters()) != -1){ + write("You swivel around in your swivel chair! Whee!"); + say(this_player()->GetName()+" swivels around in " + +possessive(this_player())+" "+ + "swivel chair, yelling \"WHEEEE!!!\""); + return 1; + } + else { + write("You're not sitting in it!"); + return 1; + } +} diff --git a/lib/domains/town/obj/charity.c b/lib/domains/town/obj/charity.c new file mode 100644 index 0000000..8e5cce6 --- /dev/null +++ b/lib/domains/town/obj/charity.c @@ -0,0 +1,101 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +static int maxlevel = 5; + +string ReadSign(){ + string ret = "Only players of level "+cardinal(maxlevel)+" and below "+ + "may take from this bin with impunity."; + return ret; +} + +void create() { + ::create(); + SetKeyName("charity bin"); + SetId(({"bin"})); + SetAdjectives(({"large","charity"})); + SetShort("a large bin"); + SetLong("This a very large bin for holding donations to the " + "needy. Since it is in a church, and for charity, it is " + "reasonable to guess that folks above a certain level will " + "receive a minor bonus for donating valuable things, and a " + "severe penalty for taking them. There is a sign on " + "the charity bin that you can read."); + SetItems( ([ + ({ "sign" }) : "A sign on the bin you can read.", + ]) ); + SetReads( ([ + "default" : "Try 'read label on bin'", + ({"sign"}) : (: ReadSign :), + ]) ); + SetPreventGet("It's bolted down you filthy scum."); + SetMass(5000); + SetBaseCost("silver",500); + SetMaxCarry(15000); + SetCanClose(0); + SetClosed(0); + SetPersistent(1); + RestoreObject(); +} + +void init(){ + ::init(); +} + +varargs int eventCalculateBonus(object ob, int take){ + int value, cls, sum, bonus, duration; + object thingy, who = this_player(); + if(!ob || !this_player()) return 0; + if(this_player()->GetLevel() <= maxlevel) return 0; + value = ob->GetBaseCost(); + cls = (ob->GetClass() || 1); + sum = (value + (cls * 1000) || 1); + bonus = (sum/10000 || 1); + duration = bonus * 10; + if(bonus > 10) bonus = 10; + if(duration > 1000) duration = 1000; + if(take && bonus > 0) bonus = -bonus - (to_float(bonus) * 0.1); + if(bonus > 0 && take) duration = -duration - (to_float(duration) * 0.1); + if(sum >= 10000 || take){ + thingy = present_bonus("charity_bonus", who); + if(thingy){ + bonus += thingy->GetStats()["luck"]; + duration += thingy->GetDuration(); + if(bonus > 33) bonus = 33; + if(duration > 5000) duration = 5000; + } + else thingy = new(LIB_BONUS); + thingy->SetBonusName("charity_bonus"); + thingy->SetStats( ([ + "luck" : bonus, + ]) ); + thingy->SetBonusDuration(duration); + if(present(thingy, who) || thingy->eventMove(who)){ + object env = environment(this_object()); + object wenv = environment(who); + if(env && wenv && env == wenv){ + if(!take){ + write("You experience a pleasant sense of kinship "+ + " with the rest of the world."); + } + else { + write("You feel cheap and petty."); + } + } + } + } + return 1; +} + +int eventReceiveObject(object ob){ + int ret = ::eventReceiveObject(ob); + if(ret) eventCalculateBonus(ob); + return ret; +} + +int eventReleaseObject(object ob){ + int ret = ::eventReleaseObject(ob); + if(ret) eventCalculateBonus(ob, 1); + return ret; +} diff --git a/lib/domains/town/obj/chest.c b/lib/domains/town/obj/chest.c new file mode 100644 index 0000000..fc0fd7a --- /dev/null +++ b/lib/domains/town/obj/chest.c @@ -0,0 +1,29 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("chest"); + SetId(({"chest","wooden chest"})); + SetShort("a wooden chest"); + SetLong("This is a sturdy wooden chest used to store valuable items."); + SetMass(2000); + SetBaseCost("silver",50); + SetMaxCarry(1500); + SetInventory(([ + "/secure/obj/memo" : 1, + "/secure/obj/medtric" : 1, + "/secure/obj/control" : 1, + //"/secure/obj/roommaker" : 1, + "/domains/town/armor/badge" : 1, + ])); + SetCanClose(1); + SetClosed(1); +} + +void init(){ + ::init(); +} + +mixed CanGet(object ob) { return "The chest does not budge.";} diff --git a/lib/domains/town/obj/chest2.c b/lib/domains/town/obj/chest2.c new file mode 100644 index 0000000..515c1a2 --- /dev/null +++ b/lib/domains/town/obj/chest2.c @@ -0,0 +1,28 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("chest"); + SetId(({"chest","wooden chest"})); + SetShort("a wooden chest"); + SetLong("This is a sturdy wooden chest used to store valuable items."); + SetMass(500); + SetBaseCost("silver",50); + SetMaxCarry(500); + SetPreventPut("You cannot put this in there!"); + SetInventory(([ + "/domains/town/obj/gcoinbag" : 1, + "/domains/town/obj/maglite" : 1, + "/domains/town/obj/m_key" : 1, + ])); + SetCanClose(1); + SetClosed(1); +} + +void init(){ + ::init(); +} + +mixed CanGet(object ob) { return "The chest does not budge.";} diff --git a/lib/domains/town/obj/church_button.c b/lib/domains/town/obj/church_button.c new file mode 100644 index 0000000..8a1f943 --- /dev/null +++ b/lib/domains/town/obj/church_button.c @@ -0,0 +1,23 @@ +#include <lib.h> + +inherit LIB_DUMMY; // These do not show up in desc, but you can look at them +inherit LIB_PRESS; // Makes the item pressable + +int openDoor(object who) { + object car; + send_messages("press", "$agent_name $agent_verb the button.", + who, 0, environment(who)); + car=load_object("/domains/town/room/elevator"); + car->CallMe(1); + +} + +static void create() { + dummy::create(); + SetKeyName("button"); + SetId(({"button","button on the wall", "button next to the elevator", "button next to elevator","button next to an elevator" })); + SetAdjectives("call", "elevator"); + SetShort("a button"); + SetLong("It is a button that you could probably press."); + SetPress((: openDoor :)); +} diff --git a/lib/domains/town/obj/church_wall.c b/lib/domains/town/obj/church_wall.c new file mode 100644 index 0000000..96f00dc --- /dev/null +++ b/lib/domains/town/obj/church_wall.c @@ -0,0 +1,16 @@ +#include <lib.h> + +inherit LIB_DUMMY; // These do not show up in desc, but you can look at them + +static void create() { + dummy::create(); + SetKeyName("wall"); + SetId(({"elevator","door","wall" })); + SetAdjectives("call", "elevator","west"); + SetShort("a wall"); + SetLong("Set into the west wall is a thoroughly modern-looking " + "elevator, which seems out of place in this rustic, colonial " + "church. There is a button next to it, presumably to call " + "the elevator car."); + AddItem(new("/domains/town/obj/church_button")); +} diff --git a/lib/domains/town/obj/cigar.c b/lib/domains/town/obj/cigar.c new file mode 100644 index 0000000..ddc66f6 --- /dev/null +++ b/lib/domains/town/obj/cigar.c @@ -0,0 +1,31 @@ +#include <lib.h> + +inherit LIB_CIGAR; + +static void create() { + ::create(); + SetKeyName("cigar"); + SetId( ({ "cigar", "cylinder" }) ); + SetAdjectives( ({ "bitterleaf" }) ); + SetShort("a cigar"); + SetLong("A cylinder of tightly wrapped bitterleaf designed for " + "combustion and inhalation its smoke."); + SetRadiantLight(2); + SetFuelRequired(1); + SetMaxFuel(300); + SetFuelAmount(30); + SetRefuelable(0); + SetMass(5); + SetBaseCost("silver",30); + SetBurntValue(0); + SetClass(10); +} +void init(){ + ::init(); +} +mixed eventBurnOut(){ + eventDarken(); + set_heart_beat(0); + eventDestruct(); + return 1; +} diff --git a/lib/domains/town/obj/clip.c b/lib/domains/town/obj/clip.c new file mode 100644 index 0000000..5107fd5 --- /dev/null +++ b/lib/domains/town/obj/clip.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_CLIP; + +void create(){ + clip::create(); + SetKeyName("9mm clip"); + SetId(({"clip","magazine"})); + SetAdjectives(({"9mm","ammunition","ammo","9 millimeter","pistol"})); + SetShort("a 9 millimeter pistol ammunition clip"); + SetLong("This is a slender, spring-loaded metal container designed "+ + "to feed a 9 millimeter pistol with bullets."); + SetMass(5); + SetMillimeter(9); + SetMaxAmmo(15); + SetAmmoType("acp"); + SetVendorType(VT_TREASURE); + SetBaseCost("silver", 35); + SetInventory(([ + "/domains/town/obj/9mmround" : 15 + ])); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/cloak_hood.c b/lib/domains/town/obj/cloak_hood.c new file mode 100644 index 0000000..357ade8 --- /dev/null +++ b/lib/domains/town/obj/cloak_hood.c @@ -0,0 +1,18 @@ +#include <lib.h> + +inherit LIB_DUMMY; // These do not show up in desc, but you can look at them +inherit LIB_WEAR; // Makes the item pressable + +varargs mixed eventWear(object who) { + return 1; +} + +static void create() { + dummy::create(); + SetKeyName("hood"); + SetId("cloak hood","cloak's hood"); + SetShort("a hood"); + SetLong("A hood on a cloak."); + SetInvis(0); + //SetWear((: eventWear :)); +} diff --git a/lib/domains/town/obj/clocktower.c b/lib/domains/town/obj/clocktower.c new file mode 100644 index 0000000..288839f --- /dev/null +++ b/lib/domains/town/obj/clocktower.c @@ -0,0 +1,68 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_ITEM; + +int eventReadClock(); + +static void create(){ + item::create(); + SetKeyName("clock tower"); + SetId( ({"great clock tower rising majestically into the sky", "great clock of the town", "clock", "tower", "structure", "architecture", "clocktower"}) ); + SetAdjectives( ({"large", "great", "majestic", "impressive", "proud"}) ); + SetShort("a great clock tower rising majestically into the sky"); + SetLong("This is a large clock tower, rising magestically into "+ + "the sky. Some forty feet up you can see the great clock of "+ + "the town, which can be read to know the local time. The "+ + "intricate details of its architecture are deeply impressive, "+ + "and there is little doubt that this great structure is the "+ + "pride of this little town."); + SetMass(1000000); + SetBaseCost("silver",40); + SetDefaultRead( (: eventReadClock :) ); +} + +void init(){ + ::init(); +} + +mixed CanGet(object ob) { return "This is a clock tower. It's not gettable.";} + +int eventReadClock(){ + int hour, minutes; + int *time_of_day; + string hour_string, minute_string; + + time_of_day = SEASONS_D->GetMudTime(); + hour = time_of_day[0]; + minutes = time_of_day[1]; + + if(hour > 12) hour -= 12; + + hour_string = cardinal(hour); + if(hour_string == "zero") hour_string = "twelve"; + switch(minutes){ + case 0 : minute_string ="o'clock"; break; + case 1 : minute_string = hour_string;hour_string ="one minute past"; break; + case 2 : minute_string = hour_string;hour_string ="two minutes past"; break; + case 3 : minute_string = hour_string;hour_string ="three minutes past"; break; + case 4 : minute_string = hour_string;hour_string ="four minutes past"; break; + case 5 : minute_string = hour_string;hour_string ="five past"; break; + case 6 : minute_string = hour_string;hour_string ="six minutes past"; break; + case 7 : minute_string = hour_string;hour_string ="seven minutes past"; break; + case 8 : minute_string = hour_string;hour_string ="eight minutes past"; break; + case 9 : minute_string = hour_string;hour_string ="nine minutes past"; break; + case 10 : minute_string = hour_string;hour_string ="ten past"; break; + case 15 : minute_string = hour_string;hour_string ="quarter past"; break; + case 45 : minute_string = cardinal(hour+1);hour_string ="quarter of"; break; + case 50 : minute_string = cardinal(hour+1);;hour_string ="ten of"; break; + case 55 : minute_string = cardinal(hour+1);hour_string ="five of"; break; + default : minute_string = cardinal(minutes);break; + } + + if(minute_string == "thirteen") minute_string = "one"; + + write("According to the clock, it is "+hour_string+" "+minute_string+"."); + + return 1; +} diff --git a/lib/domains/town/obj/cold.c b/lib/domains/town/obj/cold.c new file mode 100644 index 0000000..5f03c3c --- /dev/null +++ b/lib/domains/town/obj/cold.c @@ -0,0 +1,154 @@ +#include <lib.h> +#include ROOMS_H +#include <vendor_types.h> +#include <damage_types.h> +inherit LIB_GERM; +int damage1(); +int damage2(); +int damage3(); +int damage4(); +int damage5(); +int DangerLevel(); +object victim,where; +string victimname; + +int InfectMess(object ob){ + victim=ob; + victimname=victim->GetName(); + tell_room(environment(victim), victimname+" looks pale and uncomfortable.",({victim}) ); + tell_object(victim, "You feel an unpleasant tickle in your throat."); + return 1; +} + +void create(){ + germ::create(); + SetKeyName("tc2"); + SetGermName("cold virus"); + SetId(({"tc2"})); + SetLong("Test Cold version 2.1"); + SetCure(20); + SetVendorType(VT_TREASURE); + SetCommunicable(15); + SetLifeSpan(1200); + SetType("viral"); + SetInfect((: InfectMess :)); +} + +void bonuses(){ + if(victim && environment(this_object()) == victim){ + victim->AddStatBonus("intelligence", -5); + victim->AddStatBonus("strength", -15); + victim->AddStatBonus("charisma", -35); + victim->AddStatBonus("durability", -15); + victim->AddStatBonus("agility", -15); + victim->AddStatBonus("coordination", -5); + victim->AddStatBonus("speed", -5); + victim->AddStatBonus("wisdom", -1); + } + else if(victim) { + foreach( string stat in ({"intelligence", "strength", + "charisma", "durability", "agility", "coordination", "speed", "wisdom"})){ + victim->RemoveStatBonus(stat); + } + } + return; +} + + +void init(){ + germ::init(); + bonuses(); +} + +int eventDestruct(){ + this_object()->eventMove(ROOM_FURNACE); + return ::eventDestruct(); +} + +int eventMove(mixed dest){ + int ret = germ::eventMove(dest); + if(environment() && !living(environment())) victim = 0; + bonuses(); + return ret; +} + +int eventSuffer(){ + int x; + x=random(70); + if(x < 8) environment()->eventForce("sneeze"); + else if(x < 5) damage1(); + else if(x < 10) damage2(); + else if(x < 15) damage3(); + else if(x < 20) damage4(); + else if(x < 2) damage5(); + return 1; +} + +int DangerLevel(){ + if(victim && victim->GetHealthPoints() < 100) return 100; + return 1; +} + +int FatigueLevel() { + if(victim && victim->GetStaminaPoints() < 11) return 10; + return 11; +} + +string GetAffectLong(object ob) { + if(!ob || !living(ob)) return 0; + return ob->GetName() + " has a runny nose.\n"+ob->GetName()+" looks ill and disoriented."; +} + +int damage1(){ + if(victim){ + tell_object(victim,"You feel miserable."); + tell_room(environment(victim),victimname+" looks miserable.", ({victim}) ); + if(FatigueLevel() > 10) victim->AddStaminaPoints(random(-5)-5); + } + return 1; +} + +int damage2(){ + if(victim){ + tell_object(victim,"You are racked by a fit of wet-sounding coughs."); + tell_room(environment(victim),victimname+" is racked by a fit of wet-sounding coughs.", ({victim}) ); + if(DangerLevel() != 100) victim->AddHP(-(random(10)+10)); + if(FatigueLevel() > 10) victim->AddStaminaPoints(random(-10)-5); + } + return 1; +} + +int damage3(){ + if(victim){ + tell_room(environment(victim),victimname+" lets out a pathetic little groan of discomfort.", ({victim}) ); + tell_object(victim,"You let out a little groan of discomfort as a wave of weakness hits you."); + if(FatigueLevel() > 10) victim->AddStaminaPoints(random(-10)-10); + } + return 1; +} + +int damage4(){ + if(victim){ + tell_room(environment(victim),victimname+" sneezes violently, and then whimpers.", ({victim}) ); + tell_object(victim,"You sneeze violently, and it seems as though your head is composed of pain."); + if(DangerLevel() != 100) victim->AddHP(-(random(10)+2)); + if(FatigueLevel() > 10) victim->AddStaminaPoints(random(-15)-10); + } + return 1; +} + +int damage5(){ + if(victim){ + tell_room(environment(victim),victimname+" makes a horrible, gurgling, coughing noise and hacks up "+ + "a huge glob of phlegm.", ({victim}) ); + tell_object(victim,"You cough up a huge glob of phlegm, accidentally inhale it, and choke while coughing it "+ + "back up."); + if(DangerLevel() != 100) victim->AddHP(-(random(20)+10)); + if(FatigueLevel() > 10) victim->AddStaminaPoints(random(-15)-15); + } + return 1; +} + + +mixed CanGet(object ob) { return "Your fingers slip on your runny snot.";} +mixed CanDrop(object ob) { return "Your fingers slip on your runny snot.";} diff --git a/lib/domains/town/obj/cot.c b/lib/domains/town/obj/cot.c new file mode 100644 index 0000000..b57a2cf --- /dev/null +++ b/lib/domains/town/obj/cot.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <props.h> + +inherit LIB_BED; +inherit LIB_SMELL; + + +static void create() { + ::create(); + SetKeyName("metal cot"); + SetId( ({ "cot","bed" }) ); + SetAdjectives( ({ "simple","metal" }) ); + SetShort("a simple cot"); + SetLong("This is a simple metal cot designed for " + "sleepers that do not require a comfortable bed."); + SetMass(50); + SetBaseCost("silver",15); + SetMaxSitters(2); + SetMaxLiers(1); +} + +mixed CanGet(object ob) { return "The cot is bolted to the floor.";} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/couch.c b/lib/domains/town/obj/couch.c new file mode 100644 index 0000000..3bd7828 --- /dev/null +++ b/lib/domains/town/obj/couch.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include <props.h> + +inherit LIB_BED; +inherit LIB_SMELL; + +static void create() { + ::create(); + SetKeyName("beat up couch"); + SetId( ({ "couch","sofa","recliner" }) ); + SetAdjectives( ({ "beat up","beat-up","old" }) ); + SetShort("a beat-up old couch"); + SetLong("This is a beat-up, worn and dirty couch, the kind " + "one might expect in a university dorm room."); + SetMass(500); + SetBaseCost("silver",15); + SetMaxSitters(2); + SetMaxLiers(1); + SetSmell( ([ + "default" : "It smells dirty and gross. There's a " + "faint whiff of dog urine." + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/cup.c b/lib/domains/town/obj/cup.c new file mode 100644 index 0000000..cfcda17 --- /dev/null +++ b/lib/domains/town/obj/cup.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> +inherit LIB_FLASK; + +void create(){ + ::create(); + SetKeyName("cup"); + SetId( ({"cup", "trophy"}) ); + SetAdjectives( ({"trophy", "brass", "small"}) ); + SetShort("a small trophy cup"); + SetLong("About the size of a teacup, this brass cup appears to be some sort of trophy from a competition. There are words engraved on it."); + SetItems(([ + ({ "word", "words", "engraving", "inscription" }) : "Words engraved on the cup.", + ])); + SetRead(([ + "default" : "Try: read inscription on cup", + ({ "word", "words", "inscription", "engraving" }) : "3rd Runner Up, Junior Miss Cocoa Butter Pageant, 1963", + ])); + SetMass(10); + SetBaseCost("silver",100); + SetVendorType(VT_TREASURE); + SetFlaskUses(0); + SetStrength(5); + SetMaxFlask(1); + SetMealType(MEAL_DRINK); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/d20.c b/lib/domains/town/obj/d20.c new file mode 100644 index 0000000..833e050 --- /dev/null +++ b/lib/domains/town/obj/d20.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_DIE; + + +void create(){ + ::create(); + SetKeyName("die"); + SetId( ({ "implement"}) ); + SetAdjectives( ({"20","twenty","sided","twenty-sided","20-sided"}) ); + SetShort("a twenty-sided die"); + SetLong("A typical implement of games of chance. Orange in color, and " + "marked with numbers rather than dots along its twenty surfaces."); + SetDenominator(20); + SetMass(4); + SetBaseCost("silver",5); + SetVendorType(VT_TREASURE); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/d6.c b/lib/domains/town/obj/d6.c new file mode 100644 index 0000000..a543865 --- /dev/null +++ b/lib/domains/town/obj/d6.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_DIE; + + +void create(){ + ::create(); + SetKeyName("die"); + SetId( ({ "implement"}) ); + SetAdjectives( ({"6","six","sided","six-sided","6-sided"}) ); + SetShort("a six-sided die"); + SetLong("A typical implement of games of chance. Orange in color, and " + "marked with numbers rather than dots along its six surfaces."); + SetMass(2); + SetBaseCost("silver",1); + SetVendorType(VT_TREASURE); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/dcell.c b/lib/domains/town/obj/dcell.c new file mode 100644 index 0000000..9be80dd --- /dev/null +++ b/lib/domains/town/obj/dcell.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <vendor_types.h> +inherit "/lib/battery"; + +void create(){ + ::create(); + SetKeyName("d-cell"); + SetId( ({"cell","battery"}) ); + SetAdjectives( ({"d","generic","D","D-cell"}) ); + SetShort("a D cell battery"); + SetLong("This is a typical D-cell battery, of a generic brand."); + SetMass(2); + SetBaseCost("silver",2); + SetVendorType(VT_TREASURE); + SetPowerType("DC"); + SetCellType("D"); + SetCharge(60); + SetRechargeable(0); + SetDrainable(1); + SetDrainRate(1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/dcell_crappy.c b/lib/domains/town/obj/dcell_crappy.c new file mode 100644 index 0000000..777dca9 --- /dev/null +++ b/lib/domains/town/obj/dcell_crappy.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <vendor_types.h> +inherit "/lib/battery"; +void create(){ + ::create(); + SetKeyName("d-cell"); + SetId( ({"cell","battery"}) ); + SetAdjectives( ({"d","generic","D","D-cell"}) ); + SetShort("a D cell battery"); + SetLong("This is a typical D-cell battery, of a generic brand."); + SetMass(2); + SetBaseCost("silver",2); + SetVendorType(VT_TREASURE); + SetPowerType("DC"); + SetCellType("D"); + SetCharge(60); + SetRechargeable(0); + SetDrainable(1); + SetDrainRate(1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/dcell_good.c b/lib/domains/town/obj/dcell_good.c new file mode 100644 index 0000000..9d282f9 --- /dev/null +++ b/lib/domains/town/obj/dcell_good.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <vendor_types.h> +inherit "/lib/battery"; +void create(){ + ::create(); + SetKeyName("d-cell"); + SetId( ({"cell","battery"}) ); + SetAdjectives( ({"d","generic","D","D-cell"}) ); + SetShort("a D cell battery"); + SetLong("This is a typical D-cell battery, of a generic brand."); + SetMass(2); + SetBaseCost("silver",2); + SetVendorType(VT_TREASURE); + SetPowerType("DC"); + SetCellType("D"); + SetCharge(10000); + SetRechargeable(0); + SetDrainable(1); + SetDrainRate(1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/dcell_std.c b/lib/domains/town/obj/dcell_std.c new file mode 100644 index 0000000..0ddcde0 --- /dev/null +++ b/lib/domains/town/obj/dcell_std.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <vendor_types.h> +inherit "/lib/battery"; +void create(){ + ::create(); + SetKeyName("d-cell"); + SetId( ({"cell","battery"}) ); + SetAdjectives( ({"d","generic","D","D-cell"}) ); + SetShort("a D cell battery"); + SetLong("This is a typical D-cell battery, of a generic brand."); + SetMass(2); + SetBaseCost("silver",2); + SetVendorType(VT_TREASURE); + SetPowerType("DC"); + SetCellType("D"); + SetCharge(1000); + SetRechargeable(0); + SetDrainable(1); + SetDrainRate(1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/dining_table.c b/lib/domains/town/obj/dining_table.c new file mode 100644 index 0000000..416037d --- /dev/null +++ b/lib/domains/town/obj/dining_table.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_BED; + +void create() { + ::create(); + SetKeyName("dining table"); + SetId( ({ "table" }) ); + SetAdjectives( ({ "very","long","dining","room","huge" }) ); + SetShort("a very long dining table"); + SetLong("This is a very long dining table, suitable for accommodating a few dozen guests. It is made of fine, polished wood."); + SetMass(2000); + SetBaseCost("silver",5000); + SetMaxCarry(5000); + inventory_visible(); + inventory_accessible(); + SetInventory( ([ + "/domains/town/obj/candlestick" : 2 + ]) ); +} + +mixed CanGet(object ob) { return "This table is much too large and heavy to go anywhere with you."; } + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/donation_box.c b/lib/domains/town/obj/donation_box.c new file mode 100644 index 0000000..55cbc49 --- /dev/null +++ b/lib/domains/town/obj/donation_box.c @@ -0,0 +1,36 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +inherit LIB_DONATE; + +void create(){ + donate::create(); + item::create(); + SetKeyName("donation box"); + SetId( ({"box","donation box"}) ); + SetAdjectives( ({"small","wood","wooden"}) ); + SetShort("a donation box"); + SetLong("This is a small donation box, made out of wood. "+ + "It is used to donate money, which is then used "+ + "to feed the hungry, clothe the naked, et cetera ad "+ + "nauseam. "); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetLocalCurrency("silver"); + SetOwner("The Seventh Day Atheist Congregation"); +} + +string GetLong(){ + string extra = donate::GetLong(); + string base = item::GetLong(); + return base+extra; +} + +void init(){ + ::init(); +} + +mixed CanGet(){ + return "This is for the needy, you scum! Earn your keep!"; +} diff --git a/lib/domains/town/obj/ebutton1.c b/lib/domains/town/obj/ebutton1.c new file mode 100644 index 0000000..1e1cf60 --- /dev/null +++ b/lib/domains/town/obj/ebutton1.c @@ -0,0 +1,25 @@ +#include <lib.h> + +inherit LIB_DUMMY; // These do not show up in desc, but you can look at them +inherit LIB_PRESS; // Makes the item pressable + +int openDoor(object who) { + object car; + send_messages("press", "$agent_name $agent_verb the button.", + who, 0, environment(who)); + car=load_object("/domains/town/room/elevator"); + car->SetDoor(1); + car->CallMe(1); + +} + +static void create() { + dummy::create(); + SetKeyName("button 1"); + SetId("button","one","1"); + SetAdjectives("elevator","button","one","1"); + SetShort("a button"); + SetLong("It is a button that you could probably press. The numeral \"1\" " + "is printed on it."); + SetPress((: openDoor :)); +} diff --git a/lib/domains/town/obj/ebutton2.c b/lib/domains/town/obj/ebutton2.c new file mode 100644 index 0000000..512e0a5 --- /dev/null +++ b/lib/domains/town/obj/ebutton2.c @@ -0,0 +1,25 @@ +#include <lib.h> + +inherit LIB_DUMMY; // These do not show up in desc, but you can look at them +inherit LIB_PRESS; // Makes the item pressable + +int openDoor(object who) { + object car; + send_messages("press", "$agent_name $agent_verb the button.", + who, 0, environment(who)); + car=load_object("/domains/town/room/elevator"); + car->SetDoor(1); + car->CallMe(2); + +} + +static void create() { + dummy::create(); + SetKeyName("button b"); + SetId("b","button","two","B", "button B"); + SetAdjectives("b", "elevator","button","basement","B"); + SetShort("a button"); + SetLong("It is a button that you could probably press. The letter \"B\" " + "is printed on it."); + SetPress((: openDoor :)); +} diff --git a/lib/domains/town/obj/explosive_trap.c b/lib/domains/town/obj/explosive_trap.c new file mode 100644 index 0000000..896ce91 --- /dev/null +++ b/lib/domains/town/obj/explosive_trap.c @@ -0,0 +1,32 @@ +// For examples of valid trap types, see /include/boobytraps.h +// +// Boobytraps are two objects. The "pre" trap object, which is the tangible +// object you can hold. Then there is the "post" object, an invisible +// shadow that attaches itself to the target. This is the "pre" object. Once +// the trap is set, this object is removed from the game, and the shadow +// object attaches itself to the target, waiting for the appropriate stimulus. +// +// The shadow object is indicated in the SetShadowObject directive. + +#include <lib.h> +#include <boobytraps.h> + +inherit LIB_BOOBYTRAP_OBJECT; + +void create(){ + ::create(); + SetKeyName("trap"); + SetId( ({ "trap", "sample trap" }) ); + SetAdjectives( ({ "simple","sample", "poison", "needle" }) ); + SetShort("a sample trap"); + SetLong("It is a simple poison needle trap."); + SetShadowObject("/shadows/explosive_trap"); + SetTrapType(BOOBYTRAP_OPEN | BOOBYTRAP_CLOSE | BOOBYTRAP_PICK); + SetMass(50); + SetAutoResets(0); + SetBaseCost(100); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/flask.c b/lib/domains/town/obj/flask.c new file mode 100644 index 0000000..c99e49e --- /dev/null +++ b/lib/domains/town/obj/flask.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> +inherit LIB_FLASK; + +void create(){ + ::create(); + SetKeyName("flask"); + SetId( ({"flask"}) ); + SetAdjectives( ({"small","metal","vessel"}) ); + SetShort("a small flask"); + SetLong("A small, metal vessel for containing fluids."); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetFlaskContents("water"); + SetFlaskUses(2); + SetStrength(5); + SetMaxFlask(3); + SetMealType(MEAL_DRINK); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/fleas.c b/lib/domains/town/obj/fleas.c new file mode 100644 index 0000000..43ec1ff --- /dev/null +++ b/lib/domains/town/obj/fleas.c @@ -0,0 +1,117 @@ +#include <lib.h> +#include <vendor_types.h> +#include <damage_types.h> +inherit LIB_GERM; +int damage1(); +int damage2(); +int damage3(); +int damage4(); +int damage5(); +int DangerLevel(); +object victim,where; +string victimname; + + +int InfectMess(object ob){ + victim=ob; + victimname=victim->GetName(); + tell_room(environment(victim), victimname+" looks suprised and grossed out.",({victim}) ); + tell_object(victim, "You are suprised and disgusted to realize that fleas are crawling around on you."); + return 1; +} + +void create(){ + germ::create(); + SetKeyName("tf1"); + SetId(({"tf2"})); + SetLong("fleas version 1"); + SetCure(20); + SetVendorType(VT_TREASURE); + SetCommunicable(50); + SetLifeSpan(666); + SetType("parasite"); + SetInfect((: InfectMess :)); +} + +void bonuses(){ + if(victim && environment(this_object()) == victim){ + victim->AddStatBonus("intelligence", -15); + victim->AddStatBonus("strength", -25); + victim->AddStatBonus("charisma", -45); + victim->AddStatBonus("durability", -25); + victim->AddStatBonus("agility", -25); + victim->AddStatBonus("coordination", -15); + victim->AddStatBonus("speed", -15); + victim->AddStatBonus("wisdom", -2); + } + else if(victim) { + foreach( string stat in ({"intelligence", "strength", + "charisma", "durability", "agility", "coordination", "speed", "wisdom"})){ + victim->RemoveStatBonus(stat); + } + } + return; +} + + +void init(){ + germ::init(); + bonuses(); +} + + +int eventSuffer(){ + int x; + x=random(500); + if(x < 5) damage1(); + else if(x < 10) damage2(); + else if(x < 15) damage3(); + else if(x < 20) damage4(); + return 1; +} + +int DangerLevel(){ + if(victim->GetHealthPoints() < 20) return 100; + return 1; +} + +int FatigueLevel() { + if(victim->GetStaminaPoints() < 11) return 10; + return 11; +} + +string GetAffectLong(object ob) { + if(!ob || !living(ob)) return 0; + return ob->GetName() + " looks uncomfortable and disheveled."; +} + +int damage1(){ + tell_object(victim,"You feel really itchy all over."); + tell_room(environment(victim),victimname+" looks uncomfortable.", ({victim}) ); + return 1; +} + +int damage2(){ + tell_object(victim,"You involuntarily start scratching at the maddening itch."); + tell_room(environment(victim),victimname+" scratches desperately at "+reflexive(victim)+".", ({victim}) ); + return 1; +} + +int damage3(){ + tell_room(environment(victim),victimname+" scratches at "+reflexive(victim)+" in a frenzy, ripping "+ + possessive(victim)+" flesh and drawing blood.", ({victim}) ); + tell_object(victim,"You scratch at yourself in a mad frenzy, ripping flesh and drawing blood."); + if(DangerLevel() != 100) victim->eventReceiveDamage(this_object(),DISEASE,random(5)+4,0,"torso"); + return 1; +} + +int damage4(){ + tell_room(environment(victim),victimname+" looks disgusted.", ({victim}) ); + tell_object(victim,"You are disgusted as you feel fleas crawling on your body."); + return 1; +} + + +mixed CanGet(object ob) { return "You just cant get rid of these parasites.";} +mixed CanDrop(object ob) { return "You just cant get rid of these parasites.";} + diff --git a/lib/domains/town/obj/flu.c b/lib/domains/town/obj/flu.c new file mode 100644 index 0000000..2db3afe --- /dev/null +++ b/lib/domains/town/obj/flu.c @@ -0,0 +1,157 @@ +#include <lib.h> +#include ROOMS_H +#include <vendor_types.h> +#include <damage_types.h> +inherit LIB_GERM; +int damage1(); +int damage2(); +int damage3(); +int damage4(); +int damage5(); +int DangerLevel(); +object victim,where; +string victimname; + +int InfectMess(object ob){ + victim=ob; + victimname=victim->GetName(); + tell_room(environment(victim), victimname+" looks weak and woozy.",({victim}) ); + tell_object(victim, "You feel weak and dizzy."); + return 1; +} + +void create(){ + germ::create(); + SetKeyName("tf2"); + SetGermName("flu virus"); + SetId(({"tf2"})); + SetLong("Test Flu version 2"); + SetCure(20); + SetCommunicable(15); + SetLifeSpan(900); + SetType("viral"); + SetInfect((: InfectMess :)); +} + +void bonuses(){ + if(victim && environment(this_object()) == victim){ + victim->AddStatBonus("intelligence", -15); + victim->AddStatBonus("strength", -25); + victim->AddStatBonus("charisma", -45); + victim->AddStatBonus("durability", -25); + victim->AddStatBonus("agility", -25); + victim->AddStatBonus("coordination", -15); + victim->AddStatBonus("speed", -15); + victim->AddStatBonus("wisdom", -2); + } + else if(victim) { + foreach( string stat in ({"intelligence", "strength", + "charisma", "durability", "agility", "coordination", "speed", "wisdom"})){ + victim->RemoveStatBonus(stat); + } + } + return; +} + +void init(){ + germ::init(); + bonuses(); +} + +int eventDestruct(){ + this_object()->eventMove(ROOM_FURNACE); + return ::eventDestruct(); +} + +int eventMove(mixed dest){ + int ret = germ::eventMove(dest); + if(environment() && !living(environment())) victim = 0; + bonuses(); + return ret; +} + +int eventSuffer(){ + int x; + x=random(500); + if(x < 2) environment()->eventForce("sneeze"); + else if(x < 5) damage1(); + else if(x < 10) damage2(); + else if(x < 15) damage3(); + else if(x < 20) damage4(); + else if(x > 98) damage5(); + return 1; +} + +int DangerLevel(){ + if(victim && victim->GetHealthPoints() < 50) return 100; + return 1; +} + +int FatigueLevel() { + if(victim && victim->GetStaminaPoints() < 11) return 10; + return 11; +} + +string GetAffectLong(object ob) { + if(!ob || !living(ob)) return 0; + return ob->GetName() + " is disheveled.\n"+ob->GetName()+" looks very ill and disoriented."; +} + +int damage1(){ + if(victim){ + tell_object(victim,"You feel weak and ill."); + tell_room(environment(victim),victimname+" looks pale and ill.", ({victim}) ); + if(FatigueLevel() > 10) victim->AddStaminaPoints(random(-15)-15); + } + return 1; +} + +int damage2(){ + if(victim){ + tell_object(victim,"You are racked by a fit of gruesome-sounding, hacking coughs."); + tell_room(environment(victim),victimname+" is racked by a fit of gruesome-sounding, hacking coughs.", ({victim}) ); + if(DangerLevel() != 100) victim->AddHP(-(random(20)+10)); + if(FatigueLevel() > 10) victim->AddStaminaPoints(random(-10)-5); + } + return 1; +} + +int damage3(){ + if(victim){ + tell_room(environment(victim),victimname+" lets out a groan of discomfort.", ({victim}) ); + tell_object(victim,"You let out a groan of discomfort as a wave of weakness hits you."); + if(FatigueLevel() > 10) victim->AddStaminaPoints(random(-10)-10); + } + return 1; +} + +int damage4(){ + if(victim){ + tell_room(environment(victim),victimname+" gags violently, then chokes out a thick rope of vomit onto the ground.", ({victim}) ); + tell_object(victim,"You gag violently, then choke out a thick rope of vomit onto the ground."); + if(DangerLevel() != 100) victim->AddHP(-(random(30)+15)); + if(FatigueLevel() > 10) victim->AddStaminaPoints(random(-25)-20); + } + return 1; +} + +int damage5(){ + if(victim){ + if(victim->GetPosition() != 1){ + tell_room(environment(victim),victimname+" makes a horrendous flatulent noise and falls helplessly to the floor, soiling "+objective(victim)+"self.", ({victim}) ); + tell_object(victim,"You make a horrendous flatulent noise and fall helplessly to the floor, soiling yourself."); + victim->SetPosition(1); + } + if(victim->GetPosition() == 1){ + tell_room(environment(victim),victimname+" makes a horrendous flatulent noise as "+nominative(victim)+" lies helplessly on the ground.", ({ victim})); + tell_object(victim,"You make a horrendous flatulent noise as you lie helplessly on the ground."); + } + if(DangerLevel() != 100) victim->AddHP(-(random(35)+15)); + if(FatigueLevel() > 10) victim->AddStaminaPoints(random(-35)-25); + } + return 1; +} + + +mixed CanGet(object ob) { return "Your fingers slip on your runny snot.";} +mixed CanDrop(object ob) { return "Your fingers slip on your runny snot.";} diff --git a/lib/domains/town/obj/gbed.c b/lib/domains/town/obj/gbed.c new file mode 100644 index 0000000..2943715 --- /dev/null +++ b/lib/domains/town/obj/gbed.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include <props.h> + +inherit LIB_BED; + +static void create() { + ::create(); + SetKeyName("guest bed"); + SetId( ({ "bed" }) ); + SetAdjectives( ({ "guest" }) ); + SetShort("a guest bed"); + SetLong("This is a comfortable-looking bed for guests to sleep on."); + SetMass(1000); + SetBaseCost("silver",800); + SetMaxSitters(2); + SetMaxLiers(1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/gcoinbag.c b/lib/domains/town/obj/gcoinbag.c new file mode 100644 index 0000000..70634e0 --- /dev/null +++ b/lib/domains/town/obj/gcoinbag.c @@ -0,0 +1,27 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("bag"); + SetAdjectives( ({"cloth", "coin"}) ); + SetId( ({ "bag" }) ); + SetShort("a cloth bag"); + SetLong("It is a simple cloth bag used to hold things. "); + SetMass(50); + SetBaseCost("silver",1); + SetMaxCarry(500); + SetMoney( ([ + "gold" : 5, + "silver" : 15, + "copper" : 10, + "electrum" : 100, + "platinum" : 1, + "silver" : 20, + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/h1n1.c b/lib/domains/town/obj/h1n1.c new file mode 100644 index 0000000..9f86a55 --- /dev/null +++ b/lib/domains/town/obj/h1n1.c @@ -0,0 +1,156 @@ +#include <lib.h> +#include ROOMS_H +#include <vendor_types.h> +#include <damage_types.h> +inherit LIB_GERM; +int damage1(); +int damage2(); +int damage3(); +int damage4(); +int damage5(); +int DangerLevel(); +object victim,where; +string victimname; + +int InfectMess(object ob){ + victim=ob; + victimname=victim->GetName(); + tell_room(environment(victim), victimname+" looks weak and woozy.",({victim}) ); + tell_object(victim, "You feel weak and dizzy."); + return 1; +} + +void create(){ + germ::create(); + SetKeyName("tf3"); + SetGermName("flu virus"); + SetId(({"tf3"})); + SetLong("Test Flu version 3"); + SetCure(20); + SetCommunicable(30); + SetLifeSpan(900); + SetType("viral"); + SetInfect((: InfectMess :)); +} + +void bonuses(){ + if(victim && environment(this_object()) == victim){ + victim->AddStatBonus("intelligence", -15); + victim->AddStatBonus("strength", -25); + victim->AddStatBonus("charisma", -45); + victim->AddStatBonus("durability", -25); + victim->AddStatBonus("agility", -25); + victim->AddStatBonus("coordination", -15); + victim->AddStatBonus("speed", -15); + victim->AddStatBonus("wisdom", -2); + } + else if(victim) { + foreach( string stat in ({"intelligence", "strength", + "charisma", "durability", "agility", "coordination", "speed", "wisdom"})){ + victim->RemoveStatBonus(stat); + } + } + return; +} + +void init(){ + germ::init(); + bonuses(); +} + +int eventDestruct(){ + this_object()->eventMove(ROOM_FURNACE); + return ::eventDestruct(); +} + +int eventMove(mixed dest){ + int ret = germ::eventMove(dest); + if(environment() && !living(environment())) victim = 0; + bonuses(); + return ret; +} + +int eventSuffer(){ + int x; + x=random(500); + if(x < 2) environment()->eventForce("sneeze"); + else if(x < 5) damage1(); + else if(x < 10) damage2(); + else if(x < 15) damage3(); + else if(x < 20) damage4(); + else if(x > 98) damage5(); + return 1; +} + +int DangerLevel(){ + if(victim && victim->GetHealthPoints() < 50) return 100; + return 1; +} + +int FatigueLevel() { + if(victim && victim->GetStaminaPoints() < 11) return 10; + return 11; +} + +string GetAffectLong(object ob) { + if(!ob || !living(ob)) return 0; + return ob->GetName() + " is disheveled.\n"+ob->GetName()+" looks very ill and disoriented."; +} + +int damage1(){ + if(victim){ + tell_object(victim,"You feel weak and ill."); + tell_room(environment(victim),victimname+" looks pale and ill.", ({victim}) ); + if(FatigueLevel() > 10) victim->AddStaminaPoints(random(-15)-15); + } + return 1; +} + +int damage2(){ + if(victim){ + tell_object(victim,"You are racked by a fit of gruesome-sounding, hacking coughs."); + tell_room(environment(victim),victimname+" is racked by a fit of gruesome-sounding, hacking coughs.", ({victim}) ); + if(DangerLevel() != 100) victim->AddHP(-(random(20)+10)); + if(FatigueLevel() > 10) victim->AddStaminaPoints(random(-10)-5); + } + return 1; +} + +int damage3(){ + if(victim){ + tell_room(environment(victim),victimname+" lets out a groan of discomfort.", ({victim}) ); + tell_object(victim,"You let out a groan of discomfort as a wave of weakness hits you."); + if(FatigueLevel() > 10) victim->AddStaminaPoints(random(-10)-10); + } + return 1; +} + +int damage4(){ + if(victim){ + tell_room(environment(victim),victimname+" gags violently, then chokes out a thick rope of vomit onto the ground.", ({victim}) ); + tell_object(victim,"You gag violently, then choke out a thick rope of vomit onto the ground."); + if(DangerLevel() != 100) victim->AddHP(-(random(30)+15)); + if(FatigueLevel() > 10) victim->AddStaminaPoints(random(-25)-20); + } + return 1; +} + +int damage5(){ + if(victim){ + if(victim->GetPosition() != 1){ + tell_room(environment(victim),victimname+" makes a horrendous flatulent noise and falls helplessly to the floor, soiling "+objective(victim)+"self.", ({victim}) ); + tell_object(victim,"You make a horrendous flatulent noise and fall helplessly to the floor, soiling yourself."); + victim->SetPosition(1); + } + if(victim->GetPosition() == 1){ + tell_room(environment(victim),victimname+" makes a horrendous flatulent noise as "+nominative(victim)+" lies helplessly on the ground.", ({ victim})); + tell_object(victim,"You make a horrendous flatulent noise as you lie helplessly on the ground."); + } + if(DangerLevel() != 100) victim->AddHP(-(random(35)+15)); + if(FatigueLevel() > 10) victim->AddStaminaPoints(random(-35)-25); + } + return 1; +} + +mixed CanGet(object ob) { return "Your fingers slip on your runny snot.";} +mixed CanDrop(object ob) { return "Your fingers slip on your runny snot.";} diff --git a/lib/domains/town/obj/hpoolwater.c b/lib/domains/town/obj/hpoolwater.c new file mode 100644 index 0000000..024a188 --- /dev/null +++ b/lib/domains/town/obj/hpoolwater.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <meal_types.h> + +inherit LIB_BASE_DUMMY; +inherit LIB_FLASK; + +static void create() { + base_dummy::create(); + flask::create(); + SetKeyName("water"); + SetId(({"pool","poolwater" })); + SetAdjectives("pool","glowing"); + SetLong("The glowing water of a strange pool in the forest."); + SetShort("the glowing pool"); + SetFlaskContents("water"); + SetFlaskUses(2); + SetStrength(5); + SetMaxFlask(2); + SetEverFill(1); + SetMealType(MEAL_DRINK); + SetNoCondition(1); + SetInvis(1); +} + +mixed CanGet(object ob) { return "#The water stays in place.";} diff --git a/lib/domains/town/obj/hspringwater.c b/lib/domains/town/obj/hspringwater.c new file mode 100644 index 0000000..1973716 --- /dev/null +++ b/lib/domains/town/obj/hspringwater.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <meal_types.h> + +inherit LIB_BASE_DUMMY; +inherit LIB_FLASK; + +static void create() { + base_dummy::create(); + flask::create(); + SetKeyName("water"); + SetId(({"spring","springwater" })); + SetAdjectives("natural","glowing"); + SetLong("The glowing water of a natural spring."); + SetShort("the natural spring"); + SetFlaskContents("water"); + SetFlaskUses(2); + SetStrength(5); + SetMaxFlask(2); + SetEverFill(1); + SetMealType(MEAL_DRINK); + SetNoCondition(1); + SetInvis(1); +} + +mixed CanGet(object ob) { return "#The water stays in place.";} diff --git a/lib/domains/town/obj/key.c b/lib/domains/town/obj/key.c new file mode 100644 index 0000000..9f8890f --- /dev/null +++ b/lib/domains/town/obj/key.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("key"); + SetId( ({ "key", "mansion key" }) ); + SetAdjectives( ({ "brilliant", "silver" }) ); + SetShort("a silver key"); + SetLong("It is a brilliant silver key with no markings."); + SetMass(1); + SetBaseCost("silver",1); + SetDisableChance(100); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/ladder.c b/lib/domains/town/obj/ladder.c new file mode 100644 index 0000000..6f28c02 --- /dev/null +++ b/lib/domains/town/obj/ladder.c @@ -0,0 +1,38 @@ +#include <lib.h> +#include <climb.h> // defines CLIMB_DOWN + +//inherit LIB_DUMMY; // These do not show up in desc, but you can look at them +inherit LIB_ITEM; +inherit LIB_CLIMB; // This makes it climbable + +int LadderClimb(){ + if(base_name(environment()) == "/domains/town/room/mansion_ext"){ + write("You climb up the ladder and into the mansion through the second-story window."); + eventClimb(this_player(),CLIMB_UP,"/domains/town/room/mansion_uhall1"); + return 1; + } + if(base_name(environment()) == "/domains/amigara/room/passage1"){ + write("You climb up the ladder to the higher level of the cave."); + eventClimb(this_player(),CLIMB_UP,"/domains/amigara/room/cave"); + return 1; + } + write("This ladder doesn't seem usable here."); + return 0; +} + +static void create() { + ::create(); + SetKeyName("ladder"); + SetId("ladder"); + SetAdjectives(({"short","wood","wooden"})); + SetShort("a ladder"); + SetLong("This is a standard wooden ladder, suitable for climbing."); + SetClimb( (: LadderClimb :) , CLIMB_UP); + SetCanClimbCarried(0); + SetMass(100); + SetBaseCost("silver", 10); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/ladder_simple.c b/lib/domains/town/obj/ladder_simple.c new file mode 100644 index 0000000..ec041ff --- /dev/null +++ b/lib/domains/town/obj/ladder_simple.c @@ -0,0 +1,20 @@ +#include <lib.h> +#include <climb.h> // defines CLIMB_DOWN + +inherit LIB_ITEM; +inherit LIB_CLIMB; + +static void create() { + ::create(); + SetKeyName("ladder"); + SetId("ladder"); + SetAdjectives(({"short","wood","wooden"})); + SetShort("a ladder"); + SetLong("This is a standard wooden ladder, suitable for climbing."); + SetMass(100); + SetBaseCost("silver",10); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/lamp.c b/lib/domains/town/obj/lamp.c new file mode 100644 index 0000000..c905b2a --- /dev/null +++ b/lib/domains/town/obj/lamp.c @@ -0,0 +1,12 @@ +#include <lib.h> + +inherit LIB_DUMMY; // These do not show up in desc, but you can look at them + +static void create() { + dummy::create(); + SetKeyName("lamp"); + SetId("lamp on a post","post","lamp post","lamppost"); + SetShort("a lamp on a post"); + SetLong("This is a lamp on a post which is lit at night so townsfolk " + "can find their way around."); +} diff --git a/lib/domains/town/obj/leaflet.c b/lib/domains/town/obj/leaflet.c new file mode 100644 index 0000000..2ba1f00 --- /dev/null +++ b/lib/domains/town/obj/leaflet.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +inherit LIB_READ; + +int TestFunc(object ob,string str){ + if(ob) ob->eventPrint("if you are seeing this, you may be ob."); + this_player()->eventPrint("wtf"); + if(str && str !="") write(str); + if(!str) write("Null string found."); + if(str =="") write("Empty string found."); + write("WTF"); + return 1; +} + +void create(){ + ::create(); + SetKeyName("leaflet"); + SetId(({"leaflet","paper","slip"})); + SetAdjectives(({"small"})); + SetShort("a small leaflet"); + SetLong("This is a single sheet of paper with a message printed on it. "); + SetMass(1); + SetDollarCost(1); + SetVendorType(VT_TREASURE); + SetRead((: TestFunc :)); +} + diff --git a/lib/domains/town/obj/lice.c b/lib/domains/town/obj/lice.c new file mode 100644 index 0000000..c33ce39 --- /dev/null +++ b/lib/domains/town/obj/lice.c @@ -0,0 +1,113 @@ +#include <lib.h> +#include <vendor_types.h> +#include <damage_types.h> +inherit LIB_GERM; +int damage1(); +int damage2(); +int damage3(); +int damage4(); +int damage5(); +int DangerLevel(); +object victim,where; +string victimname; + +int InfectMess(object ob){ + victim=ob; + victimname=victim->GetName(); + tell_room(environment(victim), victimname+" looks suprised and grossed out.",({victim}) ); + tell_object(victim, "You are suprised and disgusted to realize that lice are crawling around on you."); + return 1; +} + +void create(){ + germ::create(); + SetKeyName("tf1"); + SetId(({"tf2"})); + SetLong("lice version 1"); + SetCure(20); + SetVendorType(VT_TREASURE); + SetCommunicable(50); + SetLifeSpan(777); + SetType("parasite"); + SetInfect((: InfectMess :)); +} + +void bonuses(){ + if(victim && environment(this_object()) == victim){ + victim->AddStatBonus("intelligence", -15); + victim->AddStatBonus("strength", -25); + victim->AddStatBonus("charisma", -45); + victim->AddStatBonus("durability", -25); + victim->AddStatBonus("agility", -25); + victim->AddStatBonus("coordination", -15); + victim->AddStatBonus("speed", -15); + victim->AddStatBonus("wisdom", -2); + } + else if(victim) { + foreach( string stat in ({"intelligence", "strength", + "charisma", "durability", "agility", "coordination", "speed", "wisdom"})){ + victim->RemoveStatBonus(stat); + } + } + return; +} + + +void init(){ + germ::init(); + bonuses(); +} + +int eventSuffer(){ + int x; + x=random(500); + if(x < 5) damage1(); + else if(x < 10) damage2(); + else if(x < 15) damage3(); + else if(x < 20) damage4(); + return 1; +} + +int DangerLevel(){ + if(victim->GetHealthPoints() < 20) return 100; + return 1; +} + +int FatigueLevel() { + if(victim->GetStaminaPoints() < 11) return 10; + return 11; +} + +string GetAffectLong(object ob) { + if(!ob || !living(ob)) return 0; + return ob->GetName() + " looks uncomfortable and disheveled."; +} + +int damage1(){ + tell_object(victim,"You feel really itchy all over."); + tell_room(environment(victim),victimname+" looks uncomfortable.", ({victim}) ); + return 1; +} + +int damage2(){ + tell_object(victim,"You involuntarily start scratching at the maddening itch."); + tell_room(environment(victim),victimname+" scratches desperately at "+reflexive(victim)+".", ({victim}) ); + return 1; +} + +int damage3(){ + tell_room(environment(victim),victimname+" scratches at "+reflexive(victim)+" in a frenzy, ripping "+ + possessive(victim)+" flesh and drawing blood.", ({victim}) ); + tell_object(victim,"You scratch at yourself in a mad frenzy, ripping flesh and drawing blood."); + if(DangerLevel() != 100) victim->eventReceiveDamage(this_object(),DISEASE,random(5)+4,0,"torso"); + return 1; +} + +int damage4(){ + tell_room(environment(victim),victimname+" looks disgusted.", ({victim}) ); + tell_object(victim,"You are disgusted as you feel lice crawling on your body."); + return 1; +} + +mixed CanGet(object ob) { return "You just cant get rid of these parasites.";} +mixed CanDrop(object ob) { return "You just cant get rid of these parasites.";} diff --git a/lib/domains/town/obj/lockpick.c b/lib/domains/town/obj/lockpick.c new file mode 100644 index 0000000..c3a19fb --- /dev/null +++ b/lib/domains/town/obj/lockpick.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_LOCKPICK; + +void create(){ + lockpick::create(); + SetKeyName("lockpick"); + SetAdjectives(({"lockpicking","picking"})); + SetId(({ "tool","pick" })); + SetShort("a lockpick"); + SetLong("A tool for picking locks."); + SetMass(1); + SetBaseCost("silver", 10); + SetPickingQuality(10); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/m_key.c b/lib/domains/town/obj/m_key.c new file mode 100644 index 0000000..b8aa16d --- /dev/null +++ b/lib/domains/town/obj/m_key.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("silver key"); + SetId( ({ "key", "mansion key" }) ); + SetAdjectives( ({ "brilliant", "silver" }) ); + SetShort("a silver key"); + SetLong("It is a brilliant silver key with no markings."); + SetMass(1); + SetBaseCost("silver",1); + SetDisableChance(5); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/maglite.c b/lib/domains/town/obj/maglite.c new file mode 100644 index 0000000..29a2143 --- /dev/null +++ b/lib/domains/town/obj/maglite.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_FLASHLIGHT; + +void create(){ + ::create(); + SetKeyName("maglite"); + SetId( ({"fl","flashlight","light","flashlite","Maglite"}) ); + SetAdjectives( ({"powerful","heavy","large","Maglite"}) ); + SetShort( "a large flashlight" ); + SetLong("This is a powerful, heavy, Maglite brand flashlight."); + SetMass(250); + SetBaseCost("silver",40); + SetLightLevel(20); + SetMinCells(4); + SetMaxCells(4); + SetCellType("D"); + Lit=0; + SetVendorType(VT_TREASURE); + SetInventory(([ + "/domains/town/obj/dcell_good":4 + ])); + +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/mailbox.c b/lib/domains/town/obj/mailbox.c new file mode 100644 index 0000000..ea074c1 --- /dev/null +++ b/lib/domains/town/obj/mailbox.c @@ -0,0 +1,21 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("mailbox"); + SetId( ({"mailbox", "box"}) ); + SetAdjectives( ({ "generic","nondescript" }) ); + SetShort("a small mailbox"); + SetLong("This is a small mailbox standing in front of the white house."); + SetCanClose(1); + SetMass(274); + SetBaseCost("silver",1); + SetMaxCarry(100); + SetPreventGet("You cannot get that!"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/map.c b/lib/domains/town/obj/map.c new file mode 100644 index 0000000..0f551f4 --- /dev/null +++ b/lib/domains/town/obj/map.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +inherit LIB_READ; + +int ReadFunc(){ + this_player()->eventPage("/domains/town/txt/map.txt","system"); + return 1; +} + +void create(){ + ::create(); + SetKeyName("town map"); + SetId(({"map","map of the town"})); + SetAdjectives(({"small"})); + SetShort("a small map of the town"); + SetLong("A map of the town. Try: read map \n"); + SetMass(1); + SetDollarCost(0); + SetVendorType(VT_TREASURE); + SetRead((: ReadFunc :)); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/mat.c b/lib/domains/town/obj/mat.c new file mode 100644 index 0000000..8e789b5 --- /dev/null +++ b/lib/domains/town/obj/mat.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; + +void create(){ + ::create(); + SetKeyName("bath mat"); + SetId( ({"mat"}) ); + SetAdjectives( ({"slightly damp","damp","blue","light blue"}) ); + SetShort("a bath mat"); + SetLong("This is a mat used to help prevent slipping, promote " + "foot drying, and avoid a big wet mess on " + "the bathroom floor. It is slightly damp."); + SetMass(10); + SetBaseCost("silver",5); + SetVendorType(VT_TREASURE); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/match.c b/lib/domains/town/obj/match.c new file mode 100644 index 0000000..2ef0376 --- /dev/null +++ b/lib/domains/town/obj/match.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_MATCH; + +static void create() { + match::create(); + SetKeyName("match"); + SetId("match"); + SetAdjectives( ({ "wooden" }) ); + SetShort("a wooden match"); + SetLong("A wooden match that might light if you strike it."); + SetRadiantLight(2); + SetStrikeChance(50); + SetMinHeat(10); + SetFuelRequired(1); + SetMaxFuel(10); + SetFuelAmount(10); + SetRefuelable(0); + SetMass(1); + SetBaseCost("silver",1); + SetBurntValue(1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/medbag.c b/lib/domains/town/obj/medbag.c new file mode 100644 index 0000000..dea357d --- /dev/null +++ b/lib/domains/town/obj/medbag.c @@ -0,0 +1,20 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("bag"); + SetId( ({ "medical bag" }) ); + SetAdjectives( ({ "small", "cloth", "a" }) ); + SetShort("a small cloth bag"); + SetLong("It is a simple cloth bag used to hold things. Printed on it is: " + "\"Property of A.S. Clepius\""); + SetMass(30); + SetBaseCost("silver",5); + SetMaxCarry(300); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/needle_trap.c b/lib/domains/town/obj/needle_trap.c new file mode 100644 index 0000000..f575207 --- /dev/null +++ b/lib/domains/town/obj/needle_trap.c @@ -0,0 +1,32 @@ +// For examples of valid trap types, see /include/boobytraps.h +// +// Boobytraps are two objects. The "pre" trap object, which is the tangible +// object you can hold. Then there is the "post" object, an invisible +// shadow that attaches itself to the target. This is the "pre" object. Once +// the trap is set, this object is removed from the game, and the shadow +// object attaches itself to the target, waiting for the appropriate stimulus. +// +// The shadow object is indicated in the SetShadowObject directive. + +#include <lib.h> +#include <boobytraps.h> + +inherit LIB_BOOBYTRAP_OBJECT; + +void create(){ + ::create(); + SetKeyName("trap"); + SetId( ({ "trap", "sample trap" }) ); + SetAdjectives( ({ "simple","sample", "poison", "needle" }) ); + SetShort("a sample trap"); + SetLong("It is a simple poison needle trap."); + SetShadowObject("/shadows/needle_trap"); + SetTrapType(BOOBYTRAP_ALL); + SetMass(50); + SetAutoResets(2); + SetBaseCost(100); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/needle_trap2.c b/lib/domains/town/obj/needle_trap2.c new file mode 100644 index 0000000..8431af0 --- /dev/null +++ b/lib/domains/town/obj/needle_trap2.c @@ -0,0 +1,33 @@ +// For examples of valid trap types, see /include/boobytraps.h +// +// Boobytraps are two objects. The "pre" trap object, which is the tangible +// object you can hold. Then there is the "post" object, an invisible +// shadow that attaches itself to the target. This is the "pre" object. Once +// the trap is set, this object is removed from the game, and the shadow +// object attaches itself to the target, waiting for the appropriate stimulus. +// +// The shadow object is indicated in the SetShadowObject directive. + +#include <lib.h> +#include <boobytraps.h> + +inherit LIB_BOOBYTRAP_OBJECT; + +void create(){ + ::create(); + SetKeyName("trap"); + SetId( ({ "trap" }) ); + SetAdjectives( ({ "simple","armor", "poison", "needle" }) ); + SetShort("an armor trap"); + SetLong("It is a simple poison needle trap designed to trigger when " + "armor is worn."); + SetShadowObject("/shadows/needle_trap"); + SetTrapType(BOOBYTRAP_WIELD); + SetMass(50); + SetAutoResets(1); + SetBaseCost(100); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/needle_trap3.c b/lib/domains/town/obj/needle_trap3.c new file mode 100644 index 0000000..1cb2fbf --- /dev/null +++ b/lib/domains/town/obj/needle_trap3.c @@ -0,0 +1,33 @@ +// For examples of valid trap types, see /include/boobytraps.h +// +// Boobytraps are two objects. The "pre" trap object, which is the tangible +// object you can hold. Then there is the "post" object, an invisible +// shadow that attaches itself to the target. This is the "pre" object. Once +// the trap is set, this object is removed from the game, and the shadow +// object attaches itself to the target, waiting for the appropriate stimulus. +// +// The shadow object is indicated in the SetShadowObject directive. + +#include <lib.h> +#include <boobytraps.h> + +inherit LIB_BOOBYTRAP_OBJECT; + +void create(){ + ::create(); + SetKeyName("trap"); + SetId( ({ "trap" }) ); + SetAdjectives( ({ "simple","weapon", "poison", "needle" }) ); + SetShort("a weapon trap"); + SetLong("It is a simple poison needle trap designed to trigger when a " + "weapon is wielded."); + SetShadowObject("/shadows/needle_trap"); + SetTrapType(BOOBYTRAP_WIELD); + SetMass(50); + SetAutoResets(2); + SetBaseCost(100); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/obag.c b/lib/domains/town/obj/obag.c new file mode 100644 index 0000000..82a2cb1 --- /dev/null +++ b/lib/domains/town/obj/obag.c @@ -0,0 +1,34 @@ +#include <lib.h> + +#include <armor_types.h> +#include <damage_types.h> +inherit "/lib/std/storage"; + +static void create() { + ::create(); + SetKeyName("overnight"); + SetId(({"bag"})); + SetAdjectives(({"overnight","canvas"})); + SetShort("an overnight bag"); + SetLong("This is a medium-sized bag made of soft " + "canvas, made for holding useful items."); + SetMaxCarry(450); + SetInventory(([ + "/domains/town/armor/mhelmet" : 1, + "/domains/town/armor/tshirt" : 1, + "/domains/town/armor/pants" : 1, + "/domains/town/armor/glove_r" : 1, + "/domains/town/obj/lockpick" : 1, + "/domains/town/armor/jacket" : 1, + "/domains/town/armor/glove_l" : 1, + "/domains/town/obj/needle_trap" : 1, + ])); + SetMass(100); + SetBaseCost("silver",30); + SetCanClose(1); + SetClosed(1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/omni.c b/lib/domains/town/obj/omni.c new file mode 100644 index 0000000..7078c3f --- /dev/null +++ b/lib/domains/town/obj/omni.c @@ -0,0 +1,60 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +inherit LIB_PRESS; +int check_environs(); +int vanish_count; +static void create() { + item::create(); + SetKeyName("omni"); + SetId(({"omni","Omni","device"})); + SetShort("an omni"); + SetLong("This is a small, round metal device, copper in color, "+ + "and similar in appearance to a pocket watch. There is a blinking red light "+ + "next to the tiny metal button at its top."); + SetMass(10); + SetBaseCost("silver",300); + AddItem("button", "A button on the omni."); + SetVendorType(VT_MAGIC); +} + +void init() { + vanish_count=7200; + check_environs(); +} +mixed CanPress(object who, string target) { + if(!present(this_object()->GetKeyName(),who ) && target == "button"){ + return "You do not have the Omni!"; + } + if(this_object()->GetId() == target){ + return "You cannot push that."; + } + return 1; +} +mixed eventPress(object who, string target) { + say(this_player()->GetName()+" turns multicolored and disappears.\n"); + write("You feel momentarily disoriented and find yourself back in the tavern.\n"); + this_player()->eventMoveLiving("/domains/town/room/tavern"); + return 1; +} +void heart_beat(){ + vanish_count--; + if(vanish_count < 0){ + tell_object(environment(),"The omni glows brightly and disappears!"); + this_object()->eventDestruct(); + } + if(vanish_count == 50){ + tell_object(environment(),"The omni begins to glow a dull red."); + this_object()->SetLong("This is a small, round metal device, copper in color, "+ + "and similar in appearance to a pocket watch. There is a blinking red light "+ + "next to the tiny metal button at its top. It is glowing a dull red."); + this_object()->SetShort("an omni (glowing)"); + } +} +int check_environs(){ + if( interactive(environment()) ){ + set_heart_beat(1); + return 1; + } + return 1; +} diff --git a/lib/domains/town/obj/orc_rucksack.c b/lib/domains/town/obj/orc_rucksack.c new file mode 100644 index 0000000..7d6b5f4 --- /dev/null +++ b/lib/domains/town/obj/orc_rucksack.c @@ -0,0 +1,37 @@ +#include <lib.h> + +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_WORN_STORAGE; + +static void create() { + ::create(); + SetKeyName("rucksack"); + SetId(({"ruck","sack"})); + SetAdjectives(({"sturdy","green","olive","olive-green","od green","od-green"})); + SetShort("a sturdy, olive-green rucksack"); + SetLong("This is a large, sturdy rucksack made of some sort of " + "strong, canvas-like material. It appears suitable "+ + "for just about any adventure you'd find yourself in."); + SetMass(100); + SetDollarCost(200); + SetCanClose(1); + SetClosed(1); + SetMaxCarry(1000); + SetDamagePoints(100); + SetArmorType(A_VEST); + SetInventory(([ + "/domains/town/obj/torch" : 1, + "/domains/town/obj/match" : 3, + "/domains/town/meals/rebel_yell" : (random(100) < 30), + "/domains/town/meals/green_spice" : (random(100) < 10), + "/domains/town/meals/potion_healing" : (random(100) < 10), + "/domains/town/meals/spazalin" : (random(100) < 40), + "/domains/town/meals/winebottle" : (random(100) < 20), + "/domains/town/meals/ham_sand" : random(4), + "/domains/town/meals/shark" : random(2), + ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/pack.c b/lib/domains/town/obj/pack.c new file mode 100644 index 0000000..6e26b3e --- /dev/null +++ b/lib/domains/town/obj/pack.c @@ -0,0 +1,26 @@ +#include <lib.h> + +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_WORN_STORAGE; + +static void create() { + ::create(); + SetKeyName("backpack"); + SetId(({"pack"})); + SetAdjectives(({"leather","soft","brown"})); + SetShort("a soft brown leather backpack"); + SetLong("This is a medium-sized backpack made of soft brown leather. "+ + "It seems suitable for carrying books around, for the busy college student. "+ + "It features wide, comfortable straps for convenient wear."); + SetMass(100); + SetBaseCost("silver",30); + SetCanClose(1); + SetClosed(1); + SetMaxCarry(500); + SetArmorType(A_CLOAK); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/painting.c b/lib/domains/town/obj/painting.c new file mode 100644 index 0000000..1302d4b --- /dev/null +++ b/lib/domains/town/obj/painting.c @@ -0,0 +1,16 @@ +#include <lib.h> +inherit LIB_ITEM; + +static void create(){ + item::create(); + SetKeyName("painting in the room"); + SetId("painting"); + SetAdjectives("beautiful"); + SetLong("Try: look at painting on the wall"); + SetNoCondition(1); + SetPreventGet("It does not move."); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/pipe.c b/lib/domains/town/obj/pipe.c new file mode 100644 index 0000000..db6fc00 --- /dev/null +++ b/lib/domains/town/obj/pipe.c @@ -0,0 +1,76 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_PIPE; + +void create(){ + ::create(); + SetKeyName("magic pipe"); + SetId( ({"sigpipe","magical pipe","pipe of insight"}) ); + SetAdjectives( ({"magic","magical","kalinash's", "sig", "smoking"}) ); + SetShort("a magic pipe"); + SetLong("This is a handsome pipe for smoking, made of ivory. There " + "is some sort of inscription written on it."); + SetMass(5); + SetBaseCost("silver", 300); + SetVendorType(VT_TREASURE); + SetRadiantLight(1); + SetMaxFuel(300); + SetItems( ([ + "inscription" : "An inscription on the pipe you can read.", + ]) ); + SetRead( ([ + "default" : "Try: read inscription on pipe", + "inscription" : "Kalinash's Pipe of Insight", + ]) ); + SetLanguage("common"); + SetFuelAmount(50); + SetRefuelable(1); + SetFuelType("smokable material"); +} + +void init(){ + ::init(); +} + +varargs mixed eventLight(object who, object tool){ + SetBaseCost("silver", 1); + return ::eventLight(who, tool); +} + +mixed eventSmoke(object who, object what){ + if(!GetLit()){ + write("It is not lit!"); + return 1; + } + write("You smoke your "+remove_article(GetShort())+"."); + say(who->GetName()+" smokes from "+possessive(who)+" " + +remove_article(GetShort())+"."); + if((((time() - GetLastPuff()) > 10) && random(100) < 25) || + creatorp(this_player())){ + object bonus = new(LIB_BONUS); + object *kbonuses = filter(all_inventory(this_player()), + (: stringp($1->GetBonusName()) && + $1->GetBonusName() == "kpipe_bonus" :) ); + if(sizeof(kbonuses) > 9) return bonus->eventDestruct(); + bonus->SetBonusName("kpipe_bonus"); + bonus->SetStats( ([ + "intelligence" : 1, + "wisdom" : 1, + "strength" : -1, + "durability" : -1, + ]) ); + bonus->SetBonusDuration(300); + if(bonus->eventMove(who)){ + write("You feel you have a slightly better understanding"+ + " of the world."); + } + } + lastpuff = time(); + eventDecreaseFuel(1); + if( !GetFuelAmount() ) eventBurnOut(); + return 1; +} + +int eventBreak(){ + return 0; +} diff --git a/lib/domains/town/obj/plastic_bag.c b/lib/domains/town/obj/plastic_bag.c new file mode 100644 index 0000000..35fce4d --- /dev/null +++ b/lib/domains/town/obj/plastic_bag.c @@ -0,0 +1,20 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("bag"); + SetId( ({ "bag" }) ); + SetAdjectives( ({ "small", "plastic", "a" }) ); + SetShort("a small plastic bag"); + SetLong("It is a simple plastic bag used to hold things. "); + SetMass(5); + SetBaseCost("silver",1); + SetMaxCarry(50); + SetOpacity(0); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/pole.c b/lib/domains/town/obj/pole.c new file mode 100644 index 0000000..f0c390b --- /dev/null +++ b/lib/domains/town/obj/pole.c @@ -0,0 +1,30 @@ +/* /domains/Ylsrim/etc/pole.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 951009 + */ + +#include <lib.h> +#include <vendor_types.h> + +inherit LIB_POLE; +inherit LIB_ITEM; + +static void create() { + pole::create(); + item::create(); + SetKeyName("bamboo pole"); + SetId( ({ "pole", "bamboo pole", "fishing pole" }) ); + SetAdjectives( ({ "bamboo", "feeble" }) ); + SetShort("a bamboo pole"); + SetLong("It is a feeble bamboo stick with a string at the end of it."); + SetClass(1); + SetValue(10); + SetMass(30); + SetVendorType(VT_TREASURE | VT_FISHING); + SetStrength(200); + SetChance(20); +} + +static mixed AddSave(mixed *var) { + return item::AddSave(var); +} diff --git a/lib/domains/town/obj/pool_ball.c b/lib/domains/town/obj/pool_ball.c new file mode 100644 index 0000000..59b4663 --- /dev/null +++ b/lib/domains/town/obj/pool_ball.c @@ -0,0 +1,20 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; + +void create(){ + ::create(); + SetKeyName("billiards ball"); + SetId( ({"ball"}) ); + SetAdjectives( ({"pool","billiards","billiard","heavy"}) ); + SetShort("a billiards ball"); + SetLong("This is a heavy ball, slighly smaller than palm-sized, " + "used in the game of billiards."); + SetMass(30); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/pool_table.c b/lib/domains/town/obj/pool_table.c new file mode 100644 index 0000000..d57d8d6 --- /dev/null +++ b/lib/domains/town/obj/pool_table.c @@ -0,0 +1,24 @@ +#include <lib.h> + +inherit LIB_BED; + +void create() { + ::create(); + SetKeyName("pool table"); + SetId( ({ "table" ,"billiards table"}) ); + SetAdjectives( ({ "billiard", "wood","wooden", "pool", "billiards" "large" }) ); + SetShort("a billiards table"); + SetLong("It is a large table made of dark, heavy wood. Its surface is covered in green felt and there are six holes in the corners and sides, through which balls may fit."); + SetMass(10000); + SetBaseCost("silver",1200); + SetMaxCarry(5000); + inventory_visible(); + inventory_accessible(); + SetInventory( ([ + "/domains/town/weap/cue" : 2, + "/domains/town/obj/pool_ball" : 16, + ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/rack.c b/lib/domains/town/obj/rack.c new file mode 100644 index 0000000..24e9f02 --- /dev/null +++ b/lib/domains/town/obj/rack.c @@ -0,0 +1,35 @@ +#include <lib.h> + +inherit LIB_SURFACE; +object to; + + +void create() { + ::create(); + SetKeyName("rack"); + SetId(({"rack"})); + SetAdjectives(({"knife","metal","fancy","steel","stainless","stainless-steel"})); + SetShort("a knife rack"); + SetLong("This is a fancy stainless steel knife rack, "+ + "for keeping expensive super-sharp knives."); + SetMass(274); + SetBaseCost("silver",50); + SetMaxCarry(5); + SetInventory(([ + //"/domains/town/weap/paring_knife" : 1, + "/domains/town/weap/butcher_knife" : 1, + "/domains/town/weap/carving_knife" : 1, + ])); + SetCanClose(0); +} +mixed CanGet(object ob) { return "The rack does not budge.";} +int CanReceive(object ob) { + if(!ob->GetFancy()) { + write("This is a rack for fine, expensive kitchen knives only."); + return 0; + } + else return 1; +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/rage.c b/lib/domains/town/obj/rage.c new file mode 100644 index 0000000..734f072 --- /dev/null +++ b/lib/domains/town/obj/rage.c @@ -0,0 +1,213 @@ +#include <lib.h> +#include ROOMS_H +#include <vendor_types.h> +#include <damage_types.h> + +#define PLAYER_INFECTABLE 0 + +inherit LIB_GERM; +int damage1(); +int damage2(); +int damage3(); +int damage4(); +int damage5(); +int DangerLevel(); +object global_ob,victim,where; +string victimname; + +int MakeHostile(object ob){ + object *meat = get_livings(environment(ob)); + global_ob = ob; + meat = filter(meat, (: !(base_name($1) == base_name(global_ob)) :)); + meat = filter(meat, (: !($1->GetInvis()) :)); + foreach(object new_meat in meat){ + ob->AddEnemy(new_meat); + } + return 1; +} + +int InfectMess(object ob){ + victim=ob; + victimname=victim->GetName(); + if(interactive(victim) && !PLAYER_INFECTABLE) { + eventDestruct(); + return 1; + } + tell_room(environment(victim), "%^BOLD%^RED%^"+victimname+" suddenly lets out a bloodcurdling scream!%^RESET%^",({victim}) ); + tell_object(victim, "%^BOLD%^RED%^You scream as you are suddenly possessed by an uncontrollable rage!%^RESET%^"); + ob->SetEncounter(100); + ob->SetMelee(1); + if(ob->GetRace() != "human" && ob->GetRace() != "orc") MakeHostile(ob); + return 1; +} + +void create(){ + germ::create(); + SetKeyName("rage virus"); + SetGermName("rage virus"); + SetId(({"rv2"})); + SetLong("Rage Virus v2"); + SetCure(20); + SetCommunicable(30); + SetLifeSpan(999); + SetType("viral"); + SetInfect((: InfectMess :)); +} + +void bonuses(){ + if(!this_object()) return; + if(victim && environment(this_object()) == victim){ + victim->AddStatBonus("intelligence", -25); + victim->AddStatBonus("strength", 35); + victim->AddStatBonus("charisma", -35); + victim->AddStatBonus("durability", 35); + victim->AddStatBonus("agility", 35); + victim->AddStatBonus("coordination", 35); + victim->AddStatBonus("speed", 35); + victim->AddStatBonus("wisdom", -25); + } + else if(victim) { + foreach( string stat in ({"intelligence", "strength", + "charisma", "durability", "agility", "coordination", "speed", "wisdom"})){ + victim->RemoveStatBonus(stat); + } + } + return; +} + + +void init(){ + if(!this_object()) return; + germ::init(); + bonuses(); +} + +int eventDestruct(){ + this_object()->eventMove(ROOM_FURNACE); + return ::eventDestruct(); +} + +int eventMove(mixed dest){ + int ret = germ::eventMove(dest); + if(this_object() && environment() && !living(environment())) victim = 0; + bonuses(); + return ret; +} + +int eventSuffer(object ob){ + int x; + if(!ob) return; + x=random(50); + if(x < 5) damage1(); + else if(x < 10) damage2(); + else if(x < 15) damage3(); + else if(x < 20) damage4(); + else if(x < 2) damage5(); + return 1; +} + +int DangerLevel(){ + if(victim && victim->GetHealthPoints() < 2) return 100; + return 1; +} + +int FatigueLevel() { + if(victim && victim->GetStaminaPoints() < 11) return 10; + return 11; +} + +string GetAffectLong(object ob) { + if(!ob || !living(ob)) return 0; + return "%^BOLD%^RED%^"+ob->GetName() + " looks crazed and violently insane!%^RESET%^"; +} + +int damage1(){ + if(victim){ + tell_object(victim,"%^BOLD%^RED%^You feel blinded by hatred and madness!%^RESET%^"); + tell_room(environment(victim),victimname+" looks maniacally insane and drools uncontrollably.", ({victim}) ); + victim->AddStaminaPoints(random(50)+10); + victim->AddStatBonus("strength", 10); + victim->AddStatBonus("durability", 10); + victim->AddStatBonus("agility", 10); + victim->AddStatBonus("coordination", 10); + victim->AddStatBonus("speed", 10); + MakeHostile(victim); + } + return 1; +} + +int damage2(){ + if(victim){ + tell_object(victim,"%^BOLD%^RED%^You feel your body exploding with rage!%^RESET%^"); + tell_room(environment(victim),victimname+" is shaking with fury.", ({victim}) ); + victim->AddStaminaPoints(random(50)+20); + victim->AddStatBonus("strength", 20); + victim->AddStatBonus("durability", 20); + victim->AddStatBonus("agility", 20); + victim->AddStatBonus("coordination", 20); + victim->AddStatBonus("speed", 20); + MakeHostile(victim); + victim->AddHP(-(random(50)+10)); + } + return 1; +} + +int damage3(){ + if(victim){ + tell_room(environment(victim),victimname+" lets out a horrific roar!", ({victim}) ); + tell_object(victim,"%^BOLD%^RED%^You let out a horrific roar as a spasm of fury rips through you!%^RESET%^"); + victim->AddStaminaPoints(random(60)+30); + victim->AddStatBonus("strength", 30); + victim->AddStatBonus("durability", 30); + victim->AddStatBonus("agility", 30); + victim->AddStatBonus("coordination", 30); + victim->AddStatBonus("speed", 30); + MakeHostile(victim); + victim->AddHP(-(random(60)+30)); + } + return 1; +} + +int damage4(){ + if(victim){ + tell_room(environment(victim),victimname+"'s entire body vibrates madly, throwing off hot blood drops, sweat, and saliva.", ({victim}) ); + tell_object(victim,"%^BOLD%^RED%^Your entire body vibrates uncontrollably, spraying blood, sweat, and spit everywhere.%^RESET%^"); + victim->AddStaminaPoints(random(70)+40); + victim->AddStatBonus("strength", 40); + victim->AddStatBonus("durability", 40); + victim->AddStatBonus("agility", 40); + victim->AddStatBonus("coordination", 40); + victim->AddStatBonus("speed", 40); + MakeHostile(victim); + victim->AddHP(-(random(70)+40)); + + foreach(object bystander in get_livings(environment(victim))){ + if(bystander && random(100) > 50 && this_object()) + eventInfect(bystander); + } + } + return 1; +} + +int damage5(){ + if(victim){ + tell_room(environment(victim),victimname+" makes a horrible, gurgling, coughing noise and hacks up "+ + "a huge glob of phlegm.", ({victim}) ); + tell_object(victim,"You cough up a huge glob of phlegm, accidentally inhale it, and choke while coughing it "+ + "back up."); + //Fix below courtesy of Jonez + victim->AddStaminaPoints(random(80)+50); + victim->AddStatBonus("strength", 50); + victim->AddStatBonus("durability", 50); + victim->AddStatBonus("agility", 50); + victim->AddStatBonus("coordination", 50); + victim->AddStatBonus("speed", 50); + MakeHostile(victim); + victim->AddHP(-(random(80)+50)); + } + return 1; +} + + +mixed CanGet(object ob) { return "Your fingers slip on your runny snot.";} +mixed CanDrop(object ob) { return "Your fingers slip on your runny snot.";} diff --git a/lib/domains/town/obj/rayovac.c b/lib/domains/town/obj/rayovac.c new file mode 100644 index 0000000..9de3752 --- /dev/null +++ b/lib/domains/town/obj/rayovac.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include <vendor_types.h> +inherit "/lib/flashlight"; + +void create(){ + ::create(); + SetKeyName("flashlight"); + SetId( ({"fl","flashlight","light","torch","flashlite", "rayovac"}) ); + SetAdjectives( ({"plastic","small","cheap","rayovac","Rayovac"}) ); + SetShort("a small plastic flashlight"); + SetLong("This is a cheap Rayovac brand flashlight."); + SetMass(10); + SetBaseCost("silver",10); + SetLightLevel(16); + SetMinCells(2); + SetMaxCells(2); + SetCellType("D"); + Lit=0; + SetVendorType(VT_TREASURE); + SetInventory(([ + "/domains/town/obj/dcell_crappy":2 + ])); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/riverwater.c b/lib/domains/town/obj/riverwater.c new file mode 100644 index 0000000..dae5559 --- /dev/null +++ b/lib/domains/town/obj/riverwater.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <meal_types.h> + +inherit LIB_BASE_DUMMY; +inherit LIB_FLASK; + +static void create() { + base_dummy::create(); + flask::create(); + SetKeyName("water"); + SetId(({"river","riverwater" })); + SetAdjectives("powerful","river"); + SetLong("The edge of a powerful river."); + SetShort("the edge of a powerful river"); + SetFlaskContents("water"); + SetFlaskUses(2); + SetStrength(5); + SetMaxFlask(2); + SetEverFill(1); + SetMealType(MEAL_DRINK); + SetNoCondition(1); + SetInvis(1); +} + +mixed CanGet(object ob) { return "#The river stays in place.";} diff --git a/lib/domains/town/obj/rocking_chair.c b/lib/domains/town/obj/rocking_chair.c new file mode 100644 index 0000000..cfa325b --- /dev/null +++ b/lib/domains/town/obj/rocking_chair.c @@ -0,0 +1,34 @@ +#include <lib.h> + +inherit LIB_CHAIR; +inherit LIB_ROCK; + +static void create() { + chair::create(); + SetKeyName("chair"); + SetAdjectives( ({"simple", "wood", "wooden", "rocking", "classic"}) ); + SetId("chair"); + SetShort("a wooden rocking chair"); + SetLong("A simple wooden rocking chair, fashioned in a classic, non-nonsense style common in the rural parts of town."); + SetMass(100); + SetDollarCost(15); + SetMaxSitters(1); + SetPreventGet("The chair does not budge."); +} + +void init(){ + ::init(); +} + +varargs mixed eventRock(object who){ + if(member_array(who, GetSitters()) != -1){ + write("You rock back and forth in your chair."); + say(this_player()->GetCapName()+" rocks back and forth "+ + "on "+possessive(who)+" rocking chair."); + return 1; + } + else { + write("You're not sitting in it!"); + return 1; + } +} diff --git a/lib/domains/town/obj/rocks.c b/lib/domains/town/obj/rocks.c new file mode 100644 index 0000000..f640427 --- /dev/null +++ b/lib/domains/town/obj/rocks.c @@ -0,0 +1,52 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +int polefound; +string SearchCrap(){ + string result; + object *livings; + livings = get_livings(environment(this_object())); + foreach(object living in livings){ + if(living->GetRace() == "troll" && !interactive(living)) { + write("The troll distracts you!"); + return " "; + } + } + if(!polefound){ + result="Rummaging through the rocks, you "+ + "discover a fishing pole hidden underneath."; + say(this_player()->GetName()+" searches the pile of rocks "+ + "and seems to have found something of value."); + new("/domains/town/obj/pole")->eventMove(environment(this_player())); + polefound=1; + return result; + } + + result="You rummage through the rocks "+ + "and find nothing."; + say(this_player()->GetName()+" searches the pile of rocks "+ + "with no results."); + return result; +} + + +void create(){ + ::create(); + SetKeyName("rocks"); + SetId( ({"pile","rocks","crap","bunch"}) ); + SetAdjectives( ({"pile of"}) ); + SetShort("a pile of rocks"); + SetLong("This is a bunch of rocks piled together."); + SetMass(200); + SetDollarCost(0); + SetNoCondition(1); + SetVendorType(VT_TREASURE); + SetSearch( (: SearchCrap :) ); + polefound=0; + SetItems( ([ + ({"rock","rocks"}) : "A pile of rocks.", + ]) ); + +} + +mixed CanGet(object ob) { return "The pile of rocks isn't at all portable.";} diff --git a/lib/domains/town/obj/room_item.c b/lib/domains/town/obj/room_item.c new file mode 100644 index 0000000..574cc8e --- /dev/null +++ b/lib/domains/town/obj/room_item.c @@ -0,0 +1,18 @@ +#include <lib.h> + +inherit LIB_DUMMY; // These do not show up in desc, but you can look at them + +int ShowRoomDesc(){ + this_player()->eventDescribeEnvironment(); + tell_room(environment(),this_player()->GetName()+" looks around.",({ this_player() }) ); + return 1; +} + +static void create() { + dummy::create(); + SetKeyName("room"); + SetId(({"here","around","place","area" })); + SetAdjectives("this", "current"); + SetShort(""); + SetLong( (: ShowRoomDesc :) ); +} diff --git a/lib/domains/town/obj/round.c b/lib/domains/town/obj/round.c new file mode 100644 index 0000000..8e8252e --- /dev/null +++ b/lib/domains/town/obj/round.c @@ -0,0 +1,17 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ROUND; + +void create(){ + round::create(); + SetKeyName(".357 round"); + SetId(({"round","bullet"})); + SetAdjectives(({".357","caliber","revolver","pistol"})); + SetShort("a .357 pistol round"); + SetLong("This is a .357 caliber revolver bullet. It has not been fired."); + SetCaliber(357); + SetFirearmType("revolver"); + SetAmmoType("magnum"); + SetVendorType(VT_TREASURE); + SetMass(1); +} diff --git a/lib/domains/town/obj/round2.c b/lib/domains/town/obj/round2.c new file mode 100644 index 0000000..3052bc8 --- /dev/null +++ b/lib/domains/town/obj/round2.c @@ -0,0 +1,17 @@ +#include <lib.h> +#include <vendor_types.h> +inherit "/lib/round"; +void create(){ + ::create(); + SetKeyName("9mmround"); + SetId(({"round","bullet"})); + SetAdjectives(({"9 millimeter","9mm","pistol"})); + SetShort("a 9 millimeter pistol round"); + SetLong("This is a 9 millimeter pistol bullet. It has not been fired."); + SetMillimeter(9); + SetFirearmType("auto"); + SetAmmoType("acp"); + SetVendorType(VT_TREASURE); + SetMass(1); + SetBaseCost("silver", 1); +} diff --git a/lib/domains/town/obj/rucksack.c b/lib/domains/town/obj/rucksack.c new file mode 100644 index 0000000..efbbd8e --- /dev/null +++ b/lib/domains/town/obj/rucksack.c @@ -0,0 +1,30 @@ +#include <lib.h> + +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_WORN_STORAGE; + +static void create() { + ::create(); + SetKeyName("rucksack"); + SetId(({"ruck","sack"})); + SetAdjectives(({"sturdy","green","olive","olive-green","od green","od-green"})); + SetShort("a sturdy, olive-green rucksack"); + SetLong("This is a large, sturdy rucksack made of some sort of " + "strong, canvas-like material. It appears suitable "+ + "for just about any adventure you'd find yourself in."); + SetMass(100); + SetDollarCost(200); + SetCanClose(1); + SetClosed(1); + SetMaxCarry(1000); + SetDamagePoints(100); + SetArmorType(A_VEST); + SetInventory(([ + "/domains/town/obj/torch" : 1, + "/domains/town/obj/match" : 3, + ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/rug.c b/lib/domains/town/obj/rug.c new file mode 100644 index 0000000..09b7219 --- /dev/null +++ b/lib/domains/town/obj/rug.c @@ -0,0 +1,38 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +inherit LIB_PRESS; +inherit "/lib/events/manipulate"; + +int MoveRug(); +int PushRug(); +void create(){ + ::create(); + SetKeyName("persian rug"); + SetId( ({"rug"}) ); + SetAdjectives( ({"persian","ornamental"}) ); + SetShort("a Persian rug"); + SetLong("This is a beautiful, intricately patterned Persian " + "rug, covering the center of the floor. "); + SetMass(100); + SetBaseCost("silver",500); + SetManipulate( ([ "default" : (: MoveRug :) ]) ); + SetPress( ([ "default" : (: PushRug :) ]) ); + SetVendorType(VT_TREASURE); +} +mixed CanGet(object ob) { return "The rug appears attached to the floor.";} +int MoveRug(){ + send_messages("move", "$agent_name $agent_verb the Persian rug.", + this_player(), 0, environment(this_player())); + environment(this_object())->RevealDoor(); + return 1; +} +int PushRug(){ + send_messages("move", "$agent_name $agent_verb the Persian rug.", + this_player(), 0, environment(this_player())); + environment(this_object())->RevealDoor(); + return 1; +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/safe.c b/lib/domains/town/obj/safe.c new file mode 100644 index 0000000..9edd90c --- /dev/null +++ b/lib/domains/town/obj/safe.c @@ -0,0 +1,34 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("safe"); + SetId(({"safe"})); + SetAdjectives(({"metal","small"})); + SetShort("a metal safe"); + SetLong("This is a small safe, about 2 feet high, where "+ + "one may store valuables. It looks quite "+ + "strong."); + SetMaxCarry(1000); + SetInventory(([ + "/domains/campus/weap/grenade" : 1, + "/domains/town/weap/9mil" : 1, + "/domains/town/obj/slip_heal" : 4, + ])); + SetMass(1000); + SetBaseCost("silver",50); + SetCanClose(1); + SetClosed(1); + SetCanLock(1); + SetLocked(1); + SetLockStrength(80); + SetKey("mansion safe key"); + AddMoney("silver",1000); +} + +mixed CanGet(object ob) { return "The safe is bolted to the floor and does not move.";} +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/safe_key.c b/lib/domains/town/obj/safe_key.c new file mode 100644 index 0000000..69cc4a8 --- /dev/null +++ b/lib/domains/town/obj/safe_key.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("complex key"); + SetId( ({ "key", "mansion safe key" }) ); + SetAdjectives( ({ "complex", "complicated", "complicated looking" }) ); + SetShort("a complex key"); + SetLong("It is a complicated-looking key."); + SetMass(1); + SetBaseCost("silver",1); + SetDisableChance(100); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/scroll_raise_dead.c b/lib/domains/town/obj/scroll_raise_dead.c new file mode 100644 index 0000000..0ae1120 --- /dev/null +++ b/lib/domains/town/obj/scroll_raise_dead.c @@ -0,0 +1,143 @@ +#include <lib.h> +#include <position.h> +#include ROOMS_H +#include <vendor_types.h> +inherit LIB_ITEM; + +varargs mixed eventRead(object reader, mixed str){ + object ob, playerob; + int corpse; + object *inv; + object npc; + int err; + string basefile; + string lang = this_object()->GetLanguage(); + object zombie; + catch(zombie = new("/shadows/zombie")); + if(!str || !objectp(str) || !zombie){ + return ::eventRead(reader); + } + if(reader->GetLanguageLevel(lang) < 100){ + return ::eventRead(reader); + } + ob = str; + if(ob->isCorpse()) corpse = 1; + + if(living(ob)) { + write("You can't raise the living."); + return 1; + } + + if(base_name(ob) != LIB_CORPSE){ + write("You can only animate corpses made of meat."); + return 1; + } + + if(environment(ob) != environment(this_player())) { + write(capitalize(ob->GetKeyName())+" isn't here."); + return 1; + } + + tell_player(this_player(),"You read the scroll, and with a roar "+ + "like thunder, "+ob->GetCapName()+" reanimates!"); + tell_room(environment(this_player()),this_player()->GetCapName()+" reads "+ + possessive(this_player())+ " scroll at "+ob->GetCapName()+" and "+ + nominative(ob)+" reanimates as you hear a thunderous roar!", + ({ob, this_player()}) ); + + basefile = ob->GetBaseFile(); + if(file_exists(basefile)){ + err = catch( npc = new(basefile) ); + } + if(!npc){ + npc = new(LIB_SENTIENT); + npc->SetShort("a zombie "+ob->GetRace()); + npc->SetLong("A zombie "+ob->GetRace()); + } + + npc->SetRace(ob->GetRace()); + npc->SetClass(ob->GetClass()); + npc->SetLevel(ob->GetLevel()); + npc->SetGender(ob->GetGender()); + npc->SetId( ({ ob->GetGender(), ob->GetRace(), + ob->GetClass(), "zombie" }) ); + npc->SetAdjectives( ({ ob->GetGender(), ob->GetRace(), + ob->GetClass(), "zombie", "undead" }) ); + npc->SetUndead(1); + npc->SetKeyName(lower_case((ob->GetOwner()|| ob->GetRace()))); + + foreach(mixed key, mixed val in ob->GetSkills()){ + npc->SetSkill(key, val["level"], val["class"]); + } + foreach(mixed key, mixed val in ob->GetStats()){ + npc->SetStat(key, val["level"], val["class"]); + } + npc->eventMove(ROOM_POD); + npc->SetProperty("basefile", basefile); + npc->init(); + npc->ResetCurrency(); + if(sizeof(all_inventory(npc))){ + all_inventory(npc)->eventMove(ROOM_FURNACE); + } + inv = all_inventory(ob); + if(sizeof(inv)) inv->eventMove(npc); + inv = all_inventory(ob); + if(sizeof(inv)) inv->eventMove(environment(this_player())); + foreach(string element in ob->GetMissingLimbs()){ + npc->RemoveLimb(element); + } + if(ob){ + mapping oldequipped = ob->GetEquipped(); + string *oldkeys = keys(oldequipped); + foreach(object thing in all_inventory(npc)){ + if(member_array(file_name(thing),oldkeys) != -1){ + object oldob = oldequipped[file_name(thing)]["object"]; + string *where = oldequipped[file_name(thing)]["where"]; + if(objectp(oldob)){ + if(oldob->CanEquip(npc, where)){ + oldob->eventEquip(npc, where); + } + } + } + } + } + npc->SetPosition(POSITION_LYING); + npc->eventMove(environment(this_player())); + npc->DisableActions(1); + npc->SetUndead(1); + npc->SetEncounter(0); + npc->eventQuell(); + npc->SetUndeadType("zombie"); + ob->eventMove(ROOM_FURNACE); + tell_room(environment(this_player()),"The scroll disintegrates into dust."); + zombie->eventShadow(npc); + this_object()->eventMove(ROOM_FURNACE); + return 1; +} + +void create(){ + string message = "This terrible scroll will reanimate a creature's "+ + "corpse. The resulting zombie will have little of the personality "+ + "of its original being...just the physical attributes, which will "+ + "slowly decay and inevitably fall apart. The zombie will obey any "+ + "commands spoken in a language that it understood in life. If "+ + "you are certain you must enter the dark world of necromancy, then "+ + "you can: read scroll at person"; + ::create(); + SetKeyName("scroll"); + SetId(({"scroll of raise dead","scroll of necromancy"})); + SetAdjectives(({"terrible","raise dead","magic","necromancy","dark"})); + SetShort("a dark scroll"); + SetLong("This is a dark scroll with some words written on it."); + SetMass(1); + SetDollarCost(500); + SetVendorType(VT_TREASURE); + SetReads( ([ "default" : message, + ({ "words", "words written" }) : message, + ]) ); + SetLanguage("English"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/scroll_resurrection.c b/lib/domains/town/obj/scroll_resurrection.c new file mode 100644 index 0000000..dd79a62 --- /dev/null +++ b/lib/domains/town/obj/scroll_resurrection.c @@ -0,0 +1,143 @@ +#include <lib.h> +#include <position.h> +#include ROOMS_H +#include <vendor_types.h> +inherit LIB_ITEM; + +varargs mixed eventRead(object reader, mixed str){ + object ob, playerob; + int corpse; + string lang = this_object()->GetLanguage(); + if(!str || !objectp(str)){ + return ::eventRead(reader); + } + if(reader->GetLanguageLevel(lang) < 100){ + return ::eventRead(reader); + } + ob = str; + if(ob->isCorpse()) corpse = 1; + + if(interactive(ob)) playerob = ob; + + if( ob->isPlayer() ) playerob = ob->GetPlayerob(); + + if( ob->isPlayer() && !playerob ){ + write("You cannot resurrect a player that isn't logged on."); + return 1; + + } + if((playerob && !playerob->GetGhost()) || living(ob)) { + write("You can't resurrect the living."); + return 1; + } + + if(base_name(ob) != LIB_CORPSE){ + write("You can only resurrect flesh-based creatures."); + return 1; + } + + if(environment(ob) != environment(this_player())) { + write(capitalize(ob->GetKeyName())+" isn't here."); + return 1; + } + + tell_player(this_player(),"You read the scroll, and with a flash "+ + "of light, "+ob->GetCapName()+" comes back to life!"); + tell_player(ob,capitalize(this_player()->GetKeyName())+" reads "+ + possessive(this_player())+ " scroll at you, and "+ + "you come back from the dead!"); + tell_room(environment(this_player()),this_player()->GetCapName()+" reads "+ + possessive(this_player())+ " scroll at "+ob->GetCapName()+" and "+ + nominative(ob)+" comes back to life!", + ({ob, this_player()}) ); + if(playerob){ + object *inv; + playerob->eventRevive(1); + playerob->eventMove(environment(this_player())); + inv = all_inventory(ob); + if(sizeof(inv)) inv->eventMove(playerob); + inv = all_inventory(ob); + if(sizeof(inv)) inv->eventMove(environment(this_player())); + ob->eventMove(ROOM_FURNACE); + playerob->eventDescribeEnvironment(); + } + else { + object *inv; + object npc; + int err; + string basefile = ob->GetBaseFile(); + err = catch( npc = new(basefile) ); + if(!npc){ + npc = new(LIB_SENTIENT); + npc->SetRace(ob->GetRace()); + npc->SetClass(ob->GetClass()); + npc->SetLevel(ob->GetLevel()); + npc->SetGender(ob->GetGender()); + npc->SetKeyName(lower_case((ob->GetOwner()|| ob->GetRace()))); + npc->SetShort((ob->GetLivingShort()|| "A "+ob->GetRace())); + npc->SetLong((ob->GetLivingLong() || "A "+ob->GetRace())); + } + foreach(mixed key, mixed val in ob->GetSkills()){ + npc->SetSkill(key, val["level"], val["class"]); + } + foreach(mixed key, mixed val in ob->GetStats()){ + npc->SetStat(key, val["level"], val["class"]); + } + npc->eventMove(ROOM_POD); + npc->ResetCurrency(); + if(sizeof(all_inventory(npc))){ + all_inventory(npc)->eventMove(ROOM_FURNACE); + } + inv = all_inventory(ob); + if(sizeof(inv)) inv->eventMove(npc); + inv = all_inventory(ob); + if(sizeof(inv)) inv->eventMove(environment(this_player())); + foreach(string element in ob->GetMissingLimbs()){ + npc->RemoveLimb(element); + } + if(ob){ + mapping oldequipped = ob->GetEquipped(); + string *oldkeys = keys(oldequipped); + foreach(object thing in all_inventory(npc)){ + if(member_array(file_name(thing),oldkeys) != -1){ + object oldob = oldequipped[file_name(thing)]["object"]; + string *where = oldequipped[file_name(thing)]["where"]; + if(objectp(oldob)){ + if(oldob->CanEquip(npc, where)){ + oldob->eventEquip(npc, where); + } + } + } + } + } + npc->SetPosition(POSITION_LYING); + npc->eventMove(environment(this_player())); + ob->eventMove(ROOM_FURNACE); + } + tell_room(environment(this_player()),"The scroll disintegrates into dust."); + this_object()->eventMove(ROOM_FURNACE); + return 1; +} + +void create(){ + string message="To bring someone back to life, the way they were before "+ + "death took them, and with no penalties to their experience or "+ + "abilities, then go to their corpse, and: read scroll at person"; + ::create(); + SetKeyName("scroll"); + SetId(({"scroll of resurrection"})); + SetAdjectives(({"resurrection","magic"})); + SetShort("a scroll"); + SetLong("This is a scroll with some words written on it."); + SetMass(1); + SetDollarCost(1000); + SetVendorType(VT_TREASURE); + SetReads( ([ "default" : message, + ({ "words", "words written" }) : message, + ]) ); + SetLanguage("Edhellen"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/seawater.c b/lib/domains/town/obj/seawater.c new file mode 100644 index 0000000..6299140 --- /dev/null +++ b/lib/domains/town/obj/seawater.c @@ -0,0 +1,72 @@ +#include <lib.h> +#include <meal_types.h> +#include <jump.h> + +inherit LIB_BASE_DUMMY; +inherit LIB_FLASK; +inherit LIB_JUMP; +inherit LIB_EXITS; +inherit LIB_ENTER; + +varargs int eventJump(mixed args...) { + return ::eventJump(args...); +} + +mixed direct_enter_obj(){ + return 1; +} + +mixed direct_enter_into_obj(){ + return direct_enter_obj(); +} + +static void create() { + base_dummy::create(); + flask::create(); + SetKeyName("seawater"); + SetId(({"sea","sea water","ocean","water" })); + SetAdjectives("calm","lovely"); + SetLong("A calm, lovely sea view."); + SetShort("the sea"); + SetFlaskContents("sea water"); + SetFlaskUses(2); + SetStrength(-15); + SetMaxFlask(2); + SetEverFill(1); + SetMealType(MEAL_DRINK); + SetNoCondition(1); + SetInvis(1); + SetProperty("buoyant",1); +} + +void init(){ + if(base_name(environment()) == "/domains/town/room/shore"){ + foreach(mixed ident in GetId()){ + if(!ident) continue; + AddJump(ident,"/domains/town/virtual/surface/5,0",JUMP_INTO); + } + } +} + +mixed CanGet(object ob) { return "#The sea stays in place.";} + +mixed CanEnter(object who, string what) { + if(base_name(environment()) == "/domains/town/room/shore") return 1; + return 0; +} + +int eventEnter(object who) { + if( !who ) return 0; + who->eventPrint("You enter the sea."); + who->eventMoveLiving("/domains/town/virtual/surface/5,0", + "$N enters the sea.", + "$N arrives."); + return 1; +} + +string GetEnter(){ + if(base_name(environment()) == "/domains/town/room/shore"){ + return("/domains/town/virtual/surface/5,0"); + } + return 0; +} diff --git a/lib/domains/town/obj/shamelog.c b/lib/domains/town/obj/shamelog.c new file mode 100644 index 0000000..2b51df1 --- /dev/null +++ b/lib/domains/town/obj/shamelog.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_BOOK; + +void create(){ + ::create(); + SetKeyName("Log of Shame"); + SetId( ({"shamelog", "log", "book"}) ); + SetAdjectives( ({"shame"}) ); + SetShort("The Log of Shame"); + SetLong("The Log of Shame is a book containing channel logs people should be ashamed of, and oddly, usually aren't."); + SetSource("/domains/town/txt/shame"); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetTitle("The Sample Book"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/shelf.c b/lib/domains/town/obj/shelf.c new file mode 100644 index 0000000..def9eab --- /dev/null +++ b/lib/domains/town/obj/shelf.c @@ -0,0 +1,28 @@ +#include <lib.h> + +inherit LIB_CHAIR; + +void create() { + chair::create(); + SetKeyName("wooden shelf"); + SetId( ({ "shelf" }) ); + SetAdjectives( ({ "wood","wooden", "simple", "medium-sized" "medium sized" }) ); + SetShort("a wooden shelf"); + SetLong("It is a simple shelf made of wood."); + SetInventory(([ + "/domains/default/obj/cheatbook" : 1, + "/domains/default/obj/phints" : 1, + ])); + SetMass(274); + SetBaseCost("silver",1); + SetBaseCost("silver",1); + SetMaxCarry(5000); + inventory_visible(); + inventory_accessible(); +} + +void init(){ + ::init(); +} + +mixed CanGet(object ob) { return "The shelf does not budge.";} diff --git a/lib/domains/town/obj/sign.c b/lib/domains/town/obj/sign.c new file mode 100644 index 0000000..f16a930 --- /dev/null +++ b/lib/domains/town/obj/sign.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +inherit LIB_READ; + +void create(){ + ::create(); + SetKeyName("sign"); + SetId( ({"thing","item","thang","dingus"}) ); + SetAdjectives( ({"generic","sample","template"}) ); + SetShort("a sign"); + SetLong("This is an object of indeterminate nature and proportions."); + SetItems(([ + ({ "words", "word", "this is the first read" }) : "These are the smallest units of vocabulary of a language.", + ])); + SetRead(([ + ({ "word", "words", "this is the first read" }) : "this is the first read", + ])); + SetLanguage("farsi"); + SetDefaultRead("Hopefully this is not garbled."); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/simple_chair.c b/lib/domains/town/obj/simple_chair.c new file mode 100644 index 0000000..cfeefa5 --- /dev/null +++ b/lib/domains/town/obj/simple_chair.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_CHAIR; + +static void create() { + chair::create(); + SetKeyName("chair"); + SetAdjectives( ({"simple", "wooden"}) ); + SetId("chair"); + SetShort("a wooden chair"); + SetLong("A simple chair, made of wood, for sitting on."); + SetMass(150); + SetDollarCost(15); + SetMaxSitters(1); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/slip_cure.c b/lib/domains/town/obj/slip_cure.c new file mode 100644 index 0000000..41ed1ad --- /dev/null +++ b/lib/domains/town/obj/slip_cure.c @@ -0,0 +1,43 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +string patient; + +void create(){ + ::create(); + SetKeyName("curing slip"); + SetId( ({"slip","leaf","paper","healer token"}) ); + SetAdjectives( ({"cure","curing","medical","paper"}) ); + SetShort("a curing slip"); + SetLong("This is a small, fragile piece of paper, possibly even a leaf. " + "It has some script scribbled on it."); + SetMass(1); + SetBaseCost("silver",1500); + SetVendorType(VT_HERB); + SetItems( ([ + ({"script","writing","scribbling"}) : "There is writing on the slip." + ]) ); + SetRead( ([ + ({"script","writing","scribbling"}) : "The slip reads: \"vbgkqjxz\"" + ]) ); + SetDefaultRead("default", "The slip reads: \"etaoin\""); + SetProperty("problem","cure"); +} + +void init(){ + ::init(); + if( living(environment()) && environment()->GetKeyName() != "clepius"){ + patient = environment()->GetKeyName(); + } +} + +int SetPatient(string str){ + if(str) patient = str; + return 1; +} + +string GetPatient(){ + if(patient) return patient; + else return "none"; +} + diff --git a/lib/domains/town/obj/slip_excise.c b/lib/domains/town/obj/slip_excise.c new file mode 100644 index 0000000..351feec --- /dev/null +++ b/lib/domains/town/obj/slip_excise.c @@ -0,0 +1,43 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +string patient; + +void create(){ + ::create(); + SetKeyName("excision slip"); + SetId( ({"slip","leaf","paper","healer token"}) ); + SetAdjectives( ({"excise","excision","medical","paper"}) ); + SetShort("an excision slip"); + SetLong("This is a small, fragile piece of paper, possibly even a leaf. " + "It has some script scribbled on it."); + SetMass(1); + SetBaseCost("silver",700); + SetVendorType(VT_HERB); + SetItems( ([ + ({"script","writing","scribbling"}) : "There is writing on the slip." + ]) ); + SetRead( ([ + ({"script","writing","scribbling"}) : "The slip reads: \"cmfwyp\"" + ]) ); + SetDefaultRead("default", "The slip reads: \"etaoin\""); + SetProperty("problem","excise"); +} + +void init(){ + ::init(); + if( living(environment()) && environment()->GetKeyName() != "clepius"){ + patient = environment()->GetKeyName(); + } +} + +int SetPatient(string str){ + if(str) patient = str; + return 1; +} + +string GetPatient(){ + if(patient) return patient; + else return "none"; +} + diff --git a/lib/domains/town/obj/slip_heal.c b/lib/domains/town/obj/slip_heal.c new file mode 100644 index 0000000..1b07923 --- /dev/null +++ b/lib/domains/town/obj/slip_heal.c @@ -0,0 +1,39 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; + +string patient; +void create(){ + ::create(); + SetKeyName("healing slip"); + SetId( ({"slip","leaf","paper","healer token"}) ); + SetAdjectives( ({"heal", "healing", "medical","paper"}) ); + SetShort("a healing slip"); + SetLong("This is a small, fragile piece of paper, possibly even a leaf. " + "It has some script scribbled on it."); + SetMass(1); + SetBaseCost("silver",200); + SetVendorType(VT_HERB); + SetItems( ([ + ({"script","writing","scribbling"}) : "There is writing on the slip." + ]) ); + SetRead( ([ + ({"script","writing","scribbling"}) : "The slip reads: \"etaoin\"" + ]) ); + SetDefaultRead("default", "The slip reads: \"shrdlu\""); + SetProperty("problem","heal"); +} +void init(){ + ::init(); + if( living(environment()) && environment()->GetKeyName() != "clepius"){ + patient = environment()->GetKeyName(); + } +} +int SetPatient(string str){ + if(str) patient = str; + return 1; +} +string GetPatient(){ + if(patient) return patient; + else return "none"; +} diff --git a/lib/domains/town/obj/slip_regenerate.c b/lib/domains/town/obj/slip_regenerate.c new file mode 100644 index 0000000..4e671bb --- /dev/null +++ b/lib/domains/town/obj/slip_regenerate.c @@ -0,0 +1,43 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +string patient; + +void create(){ + ::create(); + SetKeyName("regeneration slip"); + SetId( ({"slip","leaf","paper","healer token"}) ); + SetAdjectives( ({"regeneration","medical","paper"}) ); + SetShort("a regeneration slip"); + SetLong("This is a small, fragile piece of paper, possibly even a leaf. " + "It has some script scribbled on it."); + SetMass(1); + SetBaseCost("silver",1200); + SetVendorType(VT_HERB); + SetItems( ([ + ({"script","writing","scribbling"}) : "There is writing on the slip." + ]) ); + SetRead( ([ + ({"script","writing","scribbling"}) : "The slip reads: \"etaoin\"" + ]) ); + SetDefaultRead("default", "The slip reads: \"etaoin\""); + SetProperty("problem","regenerate"); +} + +void init(){ + ::init(); + if( living(environment()) && environment()->GetKeyName() != "clepius"){ + patient = environment()->GetKeyName(); + } +} + +int SetPatient(string str){ + if(str) patient = str; + return 1; +} + +string GetPatient(){ + if(patient) return patient; + else return "none"; +} + diff --git a/lib/domains/town/obj/sofa.c b/lib/domains/town/obj/sofa.c new file mode 100644 index 0000000..f65f3be --- /dev/null +++ b/lib/domains/town/obj/sofa.c @@ -0,0 +1,22 @@ +#include <lib.h> + +inherit LIB_BED; + +static void create() { + ::create(); + SetKeyName("sofa"); + SetId("sofa"); + SetAdjectives( ({ "black", "small", "tasteful", "upholstered" }) ); + SetShort("a sofa"); + SetLong("This is a small, plush sofa tastefully upholstered "+ + "in black. It appears designed for sitting on."); + SetMass(1500); + SetDollarCost(15); + SetMaxSitters(2); +} + +mixed CanGet(object ob) { return "The sofa does not budge.";} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/spam.c b/lib/domains/town/obj/spam.c new file mode 100644 index 0000000..115ba43 --- /dev/null +++ b/lib/domains/town/obj/spam.c @@ -0,0 +1,77 @@ +#include <lib.h> +#include <vendor_types.h> +#define DIR_TXT "/domains/town/txt" +inherit LIB_ITEM; +int Spam(string spam); +string SpamSpam(string spamspam); +int SpamSpamSpam(string spamspamspam); +string spam1, spam2; +void create(){ + ::create(); + SetKeyName("spam can"); + SetId(({"spam","can"})); + SetAdjectives(({"can of","can","spam"})); + SetShort("a can of spam"); + SetLong( (: SpamSpam :) ); + SetNoCondition(1); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetRetain(1); +} + +void init(){ + ::init(); + add_action("SpamSpamSpamSpam","spam"); +} + +string SpamSpam(string spamspam){ + string spamspamspam; + spamspamspam=read_file("/domains/town/txt/spam.txt"); + return spamspamspam; +} +int SpamSpamSpamSpam(string spam){ + string spamspam; + object ob; + if(!spam || spam == ""){ + this_object()->Spam(); + return 1; + } + if(!sscanf(spam,"%s with %s",spam1,spam2)){ + write("You'd like to spam who with what?"); + say(this_player()->GetName()+" fumbles with "+possessive(this_player())+ + " can of spam.\n"); + return 1; + } + ob=present(spam1,environment(this_player())); + if(!ob){ + write("There is no such thing here to spam!\n"); + say(this_player()->GetName()+" looks around for something to spam.\n"); + return 1; + } + if(!living(ob)){ + write("That thing is not impressed by spam.\n"); + say(this_player()->GetName()+" spams around foolishly.\n"); + return 1; + } + if(file_size(DIR_TXT+"/"+spam2+".txt") == -1){ + write("You cannot spam "+ob->GetName()+" that way. You look silly.\n"); + say(this_player()->GetName()+" looks silly trying to spam incorrectly.\n"); + return 1; + } + spamspam=unguarded((: read_file(DIR_TXT+"/"+spam2+".txt") :)); + say(this_player()->GetName()+" spams "+ob->GetName()+" with a "+ + "giant "+spam2+".\n", ob); + tell_object(ob, this_player()->GetName()+" spams you with:\n"+spamspam+"\n"); + write("You spam "+ob->GetName()+" with a giant "+spam2+"!\n"); + return 1; +} +int Spam(string spamspamspamspam){ + string but_I_dont_like_spam; + but_I_dont_like_spam=unguarded((:read_file("/secure/obj/txt/spam.txt") :)); + this_player()->SetLong("$N is a can of spam:\n\n"+but_I_dont_like_spam); + this_player()->AddTitle("the can of spam (Spammy!)"); + write("You spam all over yourself!\n"); + say(this_player()->GetName()+" spams all over "+objective(this_player())+"self!\n"); + return 1; +} diff --git a/lib/domains/town/obj/spent.c b/lib/domains/town/obj/spent.c new file mode 100644 index 0000000..524eda0 --- /dev/null +++ b/lib/domains/town/obj/spent.c @@ -0,0 +1,16 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +void create(){ + ::create(); + SetKeyName("slug"); + SetId( ({"slug","round","bullet","projectile"}) ); + SetAdjectives( ({"spent","lead"}) ); + SetShort("a spent firearms slug"); + SetLong("This small, twisted chunk of metal appears to be a spent "+ + "slug: the part of a bullet that is fired from a gun and enters the target. "+ + "Its shape has been distorted by its impact with whatever it hit."); + SetMass(1); + SetBaseCost("silver",0); + SetVendorType(VT_TREASURE); +} diff --git a/lib/domains/town/obj/stargate.c b/lib/domains/town/obj/stargate.c new file mode 100644 index 0000000..c0dfd07 --- /dev/null +++ b/lib/domains/town/obj/stargate.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include <daemons.h> +#include "/lib/include/stargate.h" + +inherit LIB_STARGATE; + +int ReadScreen(); + +void create() +{ + ::create(); + SetOrigin("sea floor", "/domains/town/virtual/bottom/5,0"); + SetRead(([ ({ "screen" }) : (: ReadScreen :) ]) ); + SetItems(([ ({ "screen" }) : "a computer screen which shows the status of the gate network" ]) ); +} + +void init() +{ + ::init(); +} + +int ReadScreen() +{ + write("stargate network status\n"); + write("-----------------------\n"); + write("\n"); + +} diff --git a/lib/domains/town/obj/stargate2.c b/lib/domains/town/obj/stargate2.c new file mode 100644 index 0000000..05d8473 --- /dev/null +++ b/lib/domains/town/obj/stargate2.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include <daemons.h> +#include "/lib/include/stargate.h" + +inherit LIB_STARGATE; + +int ReadScreen(); + +void create() +{ + ::create(); + SetOrigin("outer space", "/domains/town/virtual/space/1,1,1"); + SetRead(([ ({ "screen" }) : (: ReadScreen :) ]) ); + SetItems(([ ({ "screen" }) : "a computer screen which shows the status of the gate network" ]) ); +} + +void init() +{ + ::init(); +} + +int ReadScreen() +{ + write("stargate network status\n"); + write("-----------------------\n"); + write("\n"); + +} diff --git a/lib/domains/town/obj/stargate3.c b/lib/domains/town/obj/stargate3.c new file mode 100644 index 0000000..b1e40e0 --- /dev/null +++ b/lib/domains/town/obj/stargate3.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include <daemons.h> +#include "/lib/include/stargate.h" + +inherit LIB_STARGATE; + +int ReadScreen(); + +void create() +{ + ::create(); + SetOrigin("cave", "/domains/town/room/cave_entrance"); + SetRead(([ ({ "panel","writing" }) : (: ReadScreen :) ]) ); + SetItems(([ ({ "panel","writing" }) : "a panel you can read" ]) ); +} + +void init() +{ + ::init(); +} + +int ReadScreen() +{ + write("-----------------------\n"); + write("dial tower\n"); + write("-----------------------\n"); + write("\n"); + +} diff --git a/lib/domains/town/obj/stick.c b/lib/domains/town/obj/stick.c new file mode 100644 index 0000000..cbb7171 --- /dev/null +++ b/lib/domains/town/obj/stick.c @@ -0,0 +1,38 @@ +// A bonus stick! +// Adds 2 points to strength and coordination stats of +// whoever is holding it. + +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; + +int CheckBonus(){ + object who = previous_object(); + if(!who) return 0; + if(!environment() || environment() != who) return 0; + return 2; +} + +void create(){ + ::create(); + SetKeyName("stick"); + SetId( ({"branch","piece","piece of a tree"}) ); + SetAdjectives( ({"small"}) ); + SetShort("a small stick"); + SetLong("This is a piece of a tree."); + SetMass(20); +} + +void init(){ + ::init(); +} + +int eventMove(mixed dest){ + int ret = ::eventMove(dest); + object env = environment(); + if(env && living(env)){ + env->AddStatBonus("strength", (: CheckBonus :)); + env->AddStatBonus("coordination", (: CheckBonus :)); + } + return ret; +} diff --git a/lib/domains/town/obj/stove.c b/lib/domains/town/obj/stove.c new file mode 100644 index 0000000..ca62ff7 --- /dev/null +++ b/lib/domains/town/obj/stove.c @@ -0,0 +1,44 @@ +#include <lib.h> + +inherit LIB_STORAGE; + + +void create() { + ::create(); + SetKeyName("stove"); + SetId(({"stove"})); + SetAdjectives(({"large","imported","expensive"})); + SetShort("a large stove"); + SetLong("This is a very large kitchen stove, which can "+ + "handle quite a lot of food at once. The exterior is "+ + "finished in a very tasteful brushed metal motif, and "+ + "it seems that this is one of those expensive, imported "+ + "stoves that only ridiculously rich people have in "+ + "their homes."); + SetMass(5000); + SetBaseCost("silver",1000); + SetMaxCarry(5000); + SetInventory(([ + "/domains/town/npc/rat" : 1 + ])); + SetCanClose(1); + SetClosed(1); +} + +varargs mixed eventOpen(object who, string id, object tool) { + object rat; + mixed tmp = ::eventOpen(who, id, tool); + if( tmp != 1 ) { + return tmp; + } + rat = present("rat",this_object()); + if( rat ) { + rat->eventMove(environment(this_object())); + tell_room(environment(this_object()),"A mangy little rat leaps out of the stove!"); + } + return 1; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/suitcase.c b/lib/domains/town/obj/suitcase.c new file mode 100644 index 0000000..c4042b2 --- /dev/null +++ b/lib/domains/town/obj/suitcase.c @@ -0,0 +1,39 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("wardrobe"); + SetId(({"wardrobe"})); + SetAdjectives(({"wood","tall"})); + SetShort("a tall wooden wardrobe"); + SetLong("This piece of furniture is designed to hold "+ + "clothing and related accessories."); + SetMass(2000); + SetBaseCost("silver",150); + SetMaxCarry(2000); + SetInventory(([ + "/domains/town/armor/long_boot_l": 1, + "/domains/town/armor/long_boot_r": 1, + "/domains/town/armor/belt": 1, + "/domains/town/armor/vest": 1, + "/domains/town/armor/goggles": 1, + "/domains/town/armor/hunting_cap": 1, + "/domains/town/armor/glove_r": 1, + "/domains/town/armor/glove_l": 1, + "/domains/town/armor/bearsuit": 1, + "/domains/town/armor/overcoat": 1, + "/domains/town/armor/jacket": 1, + "/domains/town/armor/jeans": 1, + "/domains/town/armor/shirt": 1, + "/domains/town/armor/scarf": 1, + ])); + SetCanClose(1); + SetClosed(1); + AddMoney("silver",100); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/table.c b/lib/domains/town/obj/table.c new file mode 100644 index 0000000..b96d862 --- /dev/null +++ b/lib/domains/town/obj/table.c @@ -0,0 +1,25 @@ +#include <lib.h> + +inherit LIB_CHAIR; + +void create() { + chair::create(); + SetKeyName("wooden table"); + SetId( ({ "table" }) ); + SetAdjectives( ({ "wood","wooden", "simple", "medium-sized" "medium sized" }) ); + SetShort("a wooden table"); + SetLong("It is a simple, medium-sized table made of wood."); + SetInventory(([ + "/domains/default/obj/handbook" : 1, + ])); + SetMass(274); + SetBaseCost("silver",1); + SetBaseCost("silver",1); + SetMaxCarry(5000); + inventory_visible(); + inventory_accessible(); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/thing.c b/lib/domains/town/obj/thing.c new file mode 100644 index 0000000..f7a2416 --- /dev/null +++ b/lib/domains/town/obj/thing.c @@ -0,0 +1,19 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; + +void create(){ + ::create(); + SetKeyName("generic thing"); + SetId( ({"thing","item","thang","dingus"}) ); + SetAdjectives( ({"generic","sample","template"}) ); + SetShort("a generic thing"); + SetLong("This is an object of indeterminate nature and proportions."); + SetMass(1); + SetBaseCost("silver",1); + SetVendorType(VT_TREASURE); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/toilet.c b/lib/domains/town/obj/toilet.c new file mode 100644 index 0000000..d9dd5f6 --- /dev/null +++ b/lib/domains/town/obj/toilet.c @@ -0,0 +1,31 @@ +#include <lib.h> + +inherit LIB_CHAIR; + +static void create() { + chair::create(); + SetKeyName("mansion commode"); + SetId( ({ "toilet","commode","bowl","can" }) ); + SetAdjectives( ({ "porcelain","white" }) ); + SetShort("a toilet"); + SetLong("This is a common piece of internal plumbing."); + SetMass(2000); + SetBaseCost("silver",15); + SetMaxSitters(1); +} + +void init(){ + ::init(); + add_action("flush","flush"); +} + +int flush(string str){ + if(!str || str == "" ||str == "toilet"){ + write("ba-WHOOSH!"); + say(this_player()->GetName()+" flushes the toilet. ba-WHOOSH!"); + return 1; + } + else return 0; +} + +mixed CanGet(object ob) { return "The toilet does not budge.";} diff --git a/lib/domains/town/obj/torch.c b/lib/domains/town/obj/torch.c new file mode 100644 index 0000000..1a0b84c --- /dev/null +++ b/lib/domains/town/obj/torch.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_TORCH; + +static void create() { + torch::create(); + SetKeyName("torch"); + SetId( ({ "torch", "old torch", "wooden torch" }) ); + SetAdjectives( ({ "old", "wooden" }) ); + SetShort("an old wooden torch"); + SetLong("An old, wooden torch with a bit of cloth wrapped around " + "one end and dipped into a flamable substance."); + SetRadiantLight(7); + SetFuelRequired(1); + SetMaxFuel(1000); + SetFuelAmount(1000); + SetRefuelable(1); + SetMass(20); + SetBaseCost("silver",60); + SetBurntValue(10); + SetClass(10); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/trash.c b/lib/domains/town/obj/trash.c new file mode 100644 index 0000000..dd8f088 --- /dev/null +++ b/lib/domains/town/obj/trash.c @@ -0,0 +1,35 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("bin"); + SetId(({"bin","can","dustbin","trash","rubbish"})); + SetAdjectives(({"metal","small","blue","recycling","trash","garbage","dust"})); + SetShort("a recycling bin"); + SetLong("This is a blue trash can, marked with "+ + "the letters \"/dev/null\"."); + SetMass(274); + SetBaseCost("silver",50); + SetMaxCarry(999999); +} + +int tidy_up(){ + object *inv; + inv = all_inventory(this_object()); + foreach(object thing in inv){ + if(thing) thing->eventMove(load_object("/domains/town/room/furnace")); + } + return 1; +} + +int eventReceiveObject(object ob){ + write("You make a deposit into the the recycling bin.\n"); + call_out((: tidy_up :),1); + return 1; +} +mixed CanGet(object ob) { return "The bucket does not budge.";} + +void init(){ +} diff --git a/lib/domains/town/obj/wall.c b/lib/domains/town/obj/wall.c new file mode 100644 index 0000000..5ca0d35 --- /dev/null +++ b/lib/domains/town/obj/wall.c @@ -0,0 +1,74 @@ +#include <lib.h> + +inherit LIB_DUMMY; +inherit LIB_MANIPULATE; +inherit LIB_PRESS; + +int hidden; + +int MoveThePainting(); +int PushThePainting(); +int OpenSesame(); +string ShowDali(); + +static void create() { + dummy::create(); + SetKeyName("wall"); + SetId("wall"); + SetAdjectives("bedroom"); + SetShort("a bedroom wall"); + SetLong("It is a typical, if ornate, bedroom wall, with a painting on it."); + SetItems( ([ + ({"painting","beautiful painting"}) : (: ShowDali :), + ]) ); + SetManipulate( ([ + ({"painting","beautiful painting"}) : (: MoveThePainting :) + ]) ); + SetPress( ([ + ({"painting","beautiful painting"}) : (: PushThePainting :) + ]) ); + hidden = 1; +} + +void init(){ + add_action("GetPainting","get"); +} + +int GetPainting(string str){ + write("It appears firmly attached to the wall."); + return 1; +} + +int MoveThePainting(){ + send_messages("move", "$agent_name $agent_verb the painting on the wall.", + this_player(), 0, environment(this_player())); + if(hidden == 1) { + OpenSesame(); + } + return 1; +} + +int PushThePainting(){ + send_messages("push", "$agent_name $agent_verb the painting on the wall.", + this_player(), 0, environment(this_player())); + if(hidden == 1) { + OpenSesame(); + } + return 1; +} + +string ShowDali(){ + string ret; + ret = "A beautiful reproduction:\n"; + ret += read_file("/domains/town/txt/pot.txt"); + return ret; +} + +int OpenSesame(){ + write("You uncover a secret passageway!"); + say(this_player()->GetName()+" uncovers a secret passageway!"); + AddItem(({"secret passageway","passageway"}) , "A secret passageway you can enter."); + hidden = 0; + environment()->OpenPassage(); + return 1; +} diff --git a/lib/domains/town/obj/wardrobe.c b/lib/domains/town/obj/wardrobe.c new file mode 100644 index 0000000..8f9fede --- /dev/null +++ b/lib/domains/town/obj/wardrobe.c @@ -0,0 +1,64 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +mixed direct_enter_obj(){ + return 1; +} +mixed direct_enter_into_obj(){ + return direct_enter_obj(); +} + +int eventEnter(object who){ + int ret; + + if(GetClosed()){ + write("You bump into the wardrobe's closed door."); + say(this_player()->GetName()+" bumps into the wardrobe."); + return 0; + } + + ret = who->eventMoveLiving("/domains/town/room/secret", + "$N enters the wardrobe.", "$N arrives from the bedroom west."); + + if(!ret){ + write("You fail to enter it."); + return 0; + } + return 1; +} + +void create() { + ::create(); + SetKeyName("wardrobe"); + SetId(({"wardrobe"})); + SetAdjectives(({"wood","tall"})); + SetShort("a tall wooden wardrobe"); + SetLong("This piece of furniture is designed to hold "+ + "clothing and related accessories."); + SetMass(2000); + SetMaxCarry(2000); + SetInventory(([ + "/domains/town/armor/long_boot_l" : 1, + "/domains/town/armor/bearsuit" : 1, + "/domains/town/armor/scarf" : 1, + "/domains/town/armor/belt" : 1, + "/domains/town/armor/goggles" : 1, + "/domains/town/armor/shirt" : 1, + "/domains/town/armor/jeans" : 1, + "/domains/town/armor/hunting_cap" : 1, + "/domains/town/armor/vest" : 1, + "/domains/town/armor/long_boot_r" : 1, + "/domains/town/armor/jacket" : 1, + "/domains/town/armor/overcoat" : 1, + ])); + SetBaseCost("silver",150); + SetCanClose(1); + SetClosed(1); + AddMoney("silver",100); + SetPreventGet("The wardrobe does not budge."); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/watch.c b/lib/domains/town/obj/watch.c new file mode 100644 index 0000000..3104e4c --- /dev/null +++ b/lib/domains/town/obj/watch.c @@ -0,0 +1,70 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <localtime.h> +#include <daemons.h> + +inherit LIB_ARMOR; + +int eventReadWatch(); + +static void create(){ + armor::create(); + SetKeyName("pocket watch"); + SetId(({"watch","pocketwatch","pocket watch","timepiece"})); + SetShort("a pocket watch"); + SetLong("This is a beautifully decorated and intricately carved "+ + "pocket watch. It glows with a bright, polished bronze "+ + "luster. It is quietly ticking the seconds, and it looks like you can get the "+ + "accurate time by reading the watch."); + SetMass(10); + SetBaseCost("silver",40); + SetProtection(BLUNT,1); + SetProtection(BLADE,1); + SetProtection(KNIFE,1); + SetArmorType(A_AMULET); + SetDefaultRead( (: eventReadWatch :) ); +} + +void init(){ + ::init(); +} + +int eventReadWatch(){ + int hour, minutes; + int *time_of_day; + string hour_string, minute_string; + + time_of_day = SEASONS_D->GetMudTime(); + hour = time_of_day[0]; + minutes = time_of_day[1]; + + if(hour > 12) hour -= 12; + + hour_string = cardinal(hour); + if(hour_string == "zero") hour_string = "twelve"; + switch(minutes){ + case 0 : minute_string ="o'clock"; break; + case 1 : minute_string = hour_string;hour_string ="one minute past"; break; + case 2 : minute_string = hour_string;hour_string ="two minutes past"; break; + case 3 : minute_string = hour_string;hour_string ="three minutes past"; break; + case 4 : minute_string = hour_string;hour_string ="four minutes past"; break; + case 5 : minute_string = hour_string;hour_string ="five past"; break; + case 6 : minute_string = hour_string;hour_string ="six minutes past"; break; + case 7 : minute_string = hour_string;hour_string ="seven minutes past"; break; + case 8 : minute_string = hour_string;hour_string ="eight minutes past"; break; + case 9 : minute_string = hour_string;hour_string ="nine minutes past"; break; + case 10 : minute_string = hour_string;hour_string ="ten past"; break; + case 15 : minute_string = hour_string;hour_string ="quarter past"; break; + case 45 : minute_string = cardinal(hour+1);hour_string ="quarter of"; break; + case 50 : minute_string = cardinal(hour+1);;hour_string ="ten of"; break; + case 55 : minute_string = cardinal(hour+1);hour_string ="five of"; break; + default : minute_string = cardinal(minutes);break; + } + + if(minute_string == "thirteen") minute_string = "one"; + + write("According to the watch, it is "+hour_string+" "+minute_string+"."); + + return 1; +} diff --git a/lib/domains/town/obj/water_pipe.c b/lib/domains/town/obj/water_pipe.c new file mode 100644 index 0000000..1d6e071 --- /dev/null +++ b/lib/domains/town/obj/water_pipe.c @@ -0,0 +1,64 @@ +#include <lib.h> +#include <vendor_types.h> + +inherit LIB_ITEM; +static int open = 0; + +void create(){ + ::create(); + SetKeyName("pipe"); + SetId( ({"pipe","tube"}) ); + SetAdjectives( ({"water", "thick","metal"}) ); + SetShort("a thick metal pipe embedded in the bedrock"); + SetLong("This is a metal pipe embedded in the bedrock."); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetInvis(0); + SetPreventGet("It's planted firmly in the bedrock."); + SetNoCondition(1); + set_heart_beat(1); +} + +void init(){ + ::init(); +} + +int openpipe(int i){ + if(open && !i) open = 0; + else open = 1; + if(open){ + object flow; + int tmp; + object env = environment(this_object()); + if(!env) return 0; + flow = present("flow object", env); + if(!flow){ + flow = new(LIB_FLOW); + if(!flow) return; + tmp = flow->eventMove(environment(this_object())); + if(!tmp) return; + } + flow->SetPressure(40); + } + return open; +} + +void heart_beat(){ + object env; + if(!clonep() || !env) return; + if(open){ + object flow; + int tmp; + env = environment(this_object()); + flow = present("flow object", env); + if(!flow){ + flow = new(LIB_FLOW); + if(!flow) return; + tmp = flow->eventMove(environment(this_object())); + if(!tmp) return; + } + tmp = flow->GetPressure(); + if(tmp < 5) flow->SetPressure(20); + } +} diff --git a/lib/domains/town/obj/waterwheel.c b/lib/domains/town/obj/waterwheel.c new file mode 100644 index 0000000..96ac263 --- /dev/null +++ b/lib/domains/town/obj/waterwheel.c @@ -0,0 +1,67 @@ +#include <lib.h> +#include <vendor_types.h> + +inherit LIB_ITEM; +inherit LIB_TURN; + +static int turned = 0; +object Turner; + +void create(){ + ::create(); + SetKeyName("waterwheel"); + SetId( ({"wheel"}) ); + SetAdjectives( ({"water", "large","metal","iron"}) ); + SetShort("a large iron wheel embedded in the bedrock"); + SetLong("This is an iron wheel embedded in the bedrock."); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetInvis(0); + SetPreventGet("It's planted firmly in the bedrock."); + SetNoCondition(1); + set_heart_beat(1); + SetUnique(1); +} + +void init(){ + ::init(); +} + +varargs mixed CanTurn(object who, object what){ + if(turned){ + return "#The wheel turns no further."; + } + else return 1; +} + +int eventTurn(object who){ + object pipe, env = environment(); + if(env) pipe = present("water pipe", env); + if(!who) who = this_player(); + if(!turned){ + if(pipe){ + write("You turn the wheel."); + say(who->GetName()+" turns the wheel."); + if(!pipe->GetFlowing()){ + tell_room(env,"Water starts pouring from the pipe."); + } + pipe->openpipe(1); + turned = 1; + Turner = who; + } + else { + write("The wheel turns loosely to no apparent effect."); + say(who->GetName()+" turns the wheel to no apparent effect."); + } + } + else { + write("Nothing happens."); + say(who->GetName()+" tries to turn the wheel. Nothing happens."); + } + return 1; +} + +object GetTurner(){ + return Turner; +} diff --git a/lib/domains/town/obj/weight.c b/lib/domains/town/obj/weight.c new file mode 100644 index 0000000..f2eddf4 --- /dev/null +++ b/lib/domains/town/obj/weight.c @@ -0,0 +1,19 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; + +void create(){ + ::create(); + SetKeyName("weight"); + SetAdjectives( ({"iron", "heavy"}) ); + SetId( ({"iron", "item", "thing"}) ); + SetShort("an iron weight"); + SetLong("This is an item made of iron whose only purpose is being heavy."); + SetMass(1800); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/obj/well_lever.c b/lib/domains/town/obj/well_lever.c new file mode 100644 index 0000000..a529dd6 --- /dev/null +++ b/lib/domains/town/obj/well_lever.c @@ -0,0 +1,50 @@ +#include <lib.h> + +inherit LIB_DUMMY; // These do not show up in desc, but you can look at them +inherit LIB_PULL; // Makes the item pullable +inherit LIB_PRESS; // Makes the item pressable + +int openDoor(object who) { + object door1 = load_object("/domains/town/doors/welldoor1"); + object door2 = load_object("/domains/town/doors/welldoor2"); + if(!door1->GetClosed()){ + write("The lever is already in the pulled position."); + } + else { + write("You pull the lever, and the west door opens."); + say(this_player()->GetName()+" pulls the lever, and the west door opens."); + tell_room("/domains/town/room/well2","The east door opens, and the west door closes."); + tell_room("/domains/town/room/well3","The east door closes."); + door1->SetClosed(0); + door2->SetClosed(1); + } + return 1; +} + +int closeDoor(object who){ + object door1 = load_object("/domains/town/doors/welldoor1"); + object door2 = load_object("/domains/town/doors/welldoor2"); + if(door1->GetClosed()){ + write("The lever is already in the pushed position."); + } + else { + write("You push the lever, and the west door closes."); + say(this_player()->GetName()+" pushes the lever, and the west door closes."); + tell_room("/domains/town/room/well2","The east door closes, and the west door opens."); + tell_room("/domains/town/room/well3","The east door opens."); + door1->SetClosed(1); + door2->SetClosed(0); + } + return 1; +} + +static void create() { + dummy::create(); + SetKeyName("lever"); + SetId(({"lever","lever on the wall" })); + SetAdjectives("wooden"); + SetShort("a lever"); + SetLong("It is a lever."); + SetPress((: closeDoor :)); + SetPull((: openDoor :)); +} diff --git a/lib/domains/town/room/adv_guild.c b/lib/domains/town/room/adv_guild.c new file mode 100644 index 0000000..edb035d --- /dev/null +++ b/lib/domains/town/room/adv_guild.c @@ -0,0 +1,73 @@ +#include <lib.h> +#include <daemons.h> +inherit LIB_ROOM; + +object ob; +mapping Levels = PLAYERS_D->GetLevelList(); +int ReadSign(); +int ReadScroll(); + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("The Adventurers' Guild"); + SetLong("This small building is where adventurers can record their adventures and leave messages and announcements for other brave souls. This is also the place one can seek advancement, so if you deserve to be a higher level adventurer, asking the guild master for it will make it so. A scroll lists quests one may perform, and a sign contains some instructions. The Creator's Hall is south of here. A special skills training area is upstairs. A conference room is east, where folks can discuss things in privacy."); + SetItems( ([ + ({ "list","scroll"}) : "A scroll hangs from the wall, listing " + "some adventures you can perform which may have rewards " + "for you.", + ({"sign","instructions"}) : "This sign contains some " + "general instructions on how to gain experience and " + "attain advancement.", + ({"building","small building","here"}) : "You are in the " + "Adventurers' Guild.", + ]) ); + SetExits( ([ + "north" : "/domains/town/room/vill_road2", + "south" : "/domains/default/room/builder_hall", + "east" : "/domains/town/room/confroom", + "up" : "/domains/town/room/training.c", + ]) ); + SetInventory(([ + "/domains/town/obj/bin" : 1, + "/domains/town/obj/table" : 1, + "/domains/town/obj/shelf" : 1, + "/domains/town/npc/dirk" : ({60, 1}) + ])); + SetRead( ([ + ({"list","scroll"}) : (: ReadScroll :), + ({"instructions","sign"}) : (: ReadSign :) + ]) ); + + SetProperty("no attack", 1); + ob = new(LIB_BOARD); + ob->SetKeyName("chalkboard"); + ob->SetId( ({ "board", "chalkboard", "dusty board", "dusty chalkboard" }) ); + ob->set_board_id("adv_guild_board"); + ob->set_max_posts(30); + ob->SetShort("a dusty chalkboard"); + ob->eventMove(this_object()); + SetNoClean(1); +} + +mixed ReadSign(){ + int i; + string ret = read_file("/domains/town/txt/advancement.txt"); + ret += "\n"; + for(i=1;i<21;i++){ + ret += sprintf("%:-3s %:-28s %:-12s %:16s\n", i+"", + Levels[i]["title"], Levels[i]["xp"]+"", (Levels[i]["qp"] || "none")+""); + } + ret += "\nTo advance, ask the guildmaster.\nExample:\n\n"; + ret += "ask dirk to advance"; + return this_player()->eventPage(({ret})); +} + +mixed ReadScroll(){ + return this_player()->eventPage("/domains/town/txt/quests.txt"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/bank.c b/lib/domains/town/room/bank.c new file mode 100644 index 0000000..89fd758 --- /dev/null +++ b/lib/domains/town/room/bank.c @@ -0,0 +1,57 @@ +#include <lib.h> +inherit LIB_BANK; + +int ReadSign(); +static void create() { + bank::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("First Village Bank"); + SetLong("This simple place is the hub of financial activity for the village. Though not at all a fancy institution, this bank is trusted by the citizenry as being as safe as it gets for keeping their money.\n%^GREEN%^A sign you can read hangs here.%^RESET%^"); + SetInventory( ([ + "/domains/town/npc/zoe" : ({60, 1}) + ]) ); + SetItems( ([ + "sign" : "A sign you can read.", + ({"bank","First Village Bank"}) : "The primary financial " + "institution in town.", + ]) ); + SetExits( ([ + "west" : "/domains/town/room/mountain_road.c", + ]) ); + SetRead( ({"sign","sign hanging here"}) , (: ReadSign :) ); + SetProperty("no attack", 1); +} +int ReadSign(){ + write( @EndText +- This bank requires a minimum balance to open an account. +To use any of the bank's services, you must first open an +account (see below as to how). + +- This bank charges for certain transactions, such as +currency exchange. + +To conduct business here: + +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: + +request account from zoe +request balance from zoe +ask zoe to deposit 100 silver +ask zoe to withdraw 10 silver +ask zoe to exchange 10 gold for silver + +EndText + ); + return 1; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/basement.c b/lib/domains/town/room/basement.c new file mode 100644 index 0000000..9127ee3 --- /dev/null +++ b/lib/domains/town/room/basement.c @@ -0,0 +1,27 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("The Church Basement"); + SetLong("This is the dark, musty basement of the village church. An elevator door is in the west wall."); + SetItems(([ + ({"elevator","elevator door","door","wall","west wall"}) : "Set into the "+ + "west wall is an elevator. There is a button "+ + "next to it, presumably to call the elevator car.", + ]) ); + SetInventory(([ + "/domains/town/obj/couch" : 1, + "/domains/town/npc/leo" : ({60, 1}) + ])); + SetExits( ([ + "west" : "/domains/town/room/elevator", + ]) ); + //AddStuff( ({"/domains/town/npc/leo"}) ); +} +void init(){ + ::init(); + if(!present("button",this_object())) AddItem(new("/domains/town/obj/basement_button")); +} diff --git a/lib/domains/town/room/bridge.c b/lib/domains/town/room/bridge.c new file mode 100644 index 0000000..a91484b --- /dev/null +++ b/lib/domains/town/room/bridge.c @@ -0,0 +1,43 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetShort("Humpbacked bridge"); + SetNightLong("This is an old, humpbacked bridge, lit by a lamp post. It's seen better days, though it appears still quite stable enough. Some peculiar writing is scrawled on the bridge. A town is east of here. To the west is darkness. There is an unlit path leading down below the bridge."); + SetDayLong("This is an old, humpbacked bridge. It's seen better days, though it appears still quite stable enough. Some peculiar writing is scrawled on the bridge. The bridge spans a river below. A town is east of here, and a dark forest looms west. There is a small path leading down below the bridge."); + SetItems( ([ + ({"cracks","surface","bridge"}) : "The bridge " + "surface has a few cracks, but they seem old " + "and minor...mostly signs of how long the " + "structure has withstood the the elements.", + ({"span","river","stream","bank"}) : "Below " + "you is a small river with a powerful, " + "swift current. You might be able to climb " + "down the bridge to get to the riverbank " + "below.", + "town" : "A small town lies east of here.", + ({"writing","scrawl","grafitti","grafitto", "writing on bridge", + "peculiar writing", "peculiar writing on bridge"}): + "Grafitti is written here, in an odd and " + "uncertain hand, as if unused to the effort " + "of writing.", + ({"path","forest","dark forest"}) : "West of the " + "bridge is a path going into a dark forest." + ]) ); + SetSkyDomain("town"); + SetExits( ([ + "east" : "/domains/town/room/road2", + "west" : "/domains/town/room/forest_path1", + "down" : "/domains/town/room/riverbank", + ]) ); + SetRead(({"writing","scrawl","grafitti","grafitto","writing on bridge", + "peculiar writing on bridge"}), + "HVMANES EVNT DOMVS"); + AddItem(new("/domains/town/obj/lamp")); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/bwalk1.c b/lib/domains/town/room/bwalk1.c new file mode 100644 index 0000000..dca2af9 --- /dev/null +++ b/lib/domains/town/room/bwalk1.c @@ -0,0 +1,68 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_FISHING; + +varargs string readSign() { + string ret = "WARNING! Orcs, dwarves, and some other races cannot "+ + "swim! If you jump into the sea you will sink and drown!"; + return ret; +} + +static void create() { + fishing::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetShort("Dock of the Bay"); + SetNightLong("This is an area comprised of a raised wooden platform over the beach that allows folks to walk around enjoying the view and perhaps visiting the local commercial establishments. To the west is Harry's Pub. North is the town dock. A great sea stretches out into the eastern horizon. A lone lamp post lights this area. \n%^GREEN%^There is a sign here you can read.%^RESET%^"); + SetDayLong("This is an area comprised of a raised wooden platform over the beach that allows folks to walk around enjoying the view and perhaps visiting the local commercial establishments. To the west is Harry's Pub. North is the town dock. A great sea stretches out into the eastern horizon. \n%^GREEN%^There is a sign here you can read.%^RESET%^"); + SetItems( ([ + "establishment":"A pub west of here.", + "local establishment":"A pub west of here.", + "commercial establishment":"A pub west of here.", + "sign":"A sign on the ground. To read it, 'read sign'.", + "platform":"The local surface.", + "raised wooden platform":"The local surface.", + "wooden platform":"The local surface.", + "raised platform":"The local surface.", + "horizon":"Where the sky loves the sea.", + "beautiful horizon":"Where the sky loves the sea.", + "town":"A population center to the northwest.", + "boardwalk":"Where people can stably walk and enjoy the view.", + "view":"A beautiful horizon to the east.", + "dock":"What boats do north of here.", + "shoreline":"The demarcator of discontinuity between land and sea.", + ]) ); + SetExits( ([ + "north" : "/domains/town/room/docks", + "west" : "/domains/town/room/hp.c", + ]) ); + SetRead("sign", (: readSign :) ); + SetFrequency(5); + SetChance(90); + SetFish( ([ + "/domains/town/meals/shark" : 10, + "/domains/town/meals/herring" : 2, + ]) ); + SetActionsMap( ([ + "A soft breeze cools your brow." : 5, + "You briefly hear seagulls far in the distance." : 7, + "A cool breeze flows in from the east, " + + "bringing with it the bracing salty smells of the sea.": 2, + ]) ); + SetInventory( ([ + "/domains/town/obj/seawater" : 1, + ]) ); + AddItem(new("/domains/town/obj/lamp")); + SetSkyDomain("town"); +} + +void init(){ + ::init(); + add_action("enjoy","enjoy"); +} + +int enjoy(string foo){ + write("Mmmm!"); + return 1; +} diff --git a/lib/domains/town/room/cave1.c b/lib/domains/town/room/cave1.c new file mode 100644 index 0000000..d146ec5 --- /dev/null +++ b/lib/domains/town/room/cave1.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(5); + SetShort("A Dark Cave"); + SetLong("This is a small cave at the base of a cliff. A stone door is set into the south wall."); + SetClimate("indoors"); + SetInventory(([ + "/domains/town/weap/fellsword" : 1, + "/domains/town/obj/scroll_resurrection" : 1, + ])); + SetExits(([ + "south" : "/domains/town/room/cave_entrance", + ])); + + SetDoor("south", "/domains/town/doors/stone.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/cave_entrance.c b/lib/domains/town/room/cave_entrance.c new file mode 100644 index 0000000..f4eaaf8 --- /dev/null +++ b/lib/domains/town/room/cave_entrance.c @@ -0,0 +1,84 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +int initialized = 0; +int CheckQuest(object ob); + +void create() { + room::create(); + SetAmbientLight(5); + SetShort("A Dark Cave"); + SetLong("This is a small cave at the base of a cliff. A stone door is set into the north wall. There is some writing scrawled on the wall."); + SetExits( ([ + "out" : "/domains/town/virtual/forest/-4,25", + "south" : "/domains/town/virtual/forest/-4,25", + "north" : "/domains/town/room/cave1.c", + ]) ); + SetItems(([ + ({ "writing", "writing on the wall","scrawl" }) : "A rough scrawl you can read", + ({ "wall" }) : "A rocky surface in this cave.", + ]) ); + SetRead(({ "writing", "writing on the wall" }) + , "Friend, dial campus lab. Read the door, too." ); + SetDoor("north", "/domains/town/doors/stone.c"); +} + +void init(){ + ::init(); + CheckQuest(this_player()); + if(!initialized){ + object door = present("stone door",this_object()); + if(!door) return; + door->SetItems( ([ + ({"inscription"}) : "Words in the language of the elves.", + ]) ); + SetInventory(([ + "/domains/town/obj/stargate3" : 1, + ])); + SetClimate("indoors"); + door->SetRead( ([ + ({"inscription"}) : "Speak, friend, and enter.", + "default" : "Try: read inscription on door" + ]) ); + door->SetLanguage("Edhellen"); + initialized = 1; + } +} + +varargs mixed eventHearTalk(object who, object target, int cls, string verb, + string msg, string lang) { + int decoded = 0; + object door = present("stone door",this_object()); + if(door) door = door->GetDoor(); + if(door && door->GetClosed() && lower_case(lang) == "edhellen" + && who->GetLanguageLevel(lang) > 50 && + grepp(lower_case(msg),"friend")) + decoded = 1; + room::eventHearTalk(who,target,cls,verb,msg,lang); + if(decoded){ + eventPrint("With a great roar, the stone door rumbles open!"); + door->SetClosed(0); + } + return 1; +} + +int CheckQuest(object ob){ + string *quests; + quests = ob->GetQuests(); + if(!ob->GetQuest("Cave Finding Quest")){ + ob->AddQuest("Cave Explorer I","Cave Finding Quest"); + write("%^BOLD%^%^RED%^\n\nCONGRATULATIONS!\n%^RESET%^"); + write("%^BOLD%^%^RED%^You have solved the quest of the "+ + "Lost Cave. You have "+ + "earned 3 quest points, and 2500 experience "+ + "points. Nice job!\n\n%^RESET%^"); + say(this_player()->GetName()+" solves newbie quest 2."); + ob->AddQuestPoints(3); + ob->AddExperiencePoints(2500); + return 1; + } + return 1; +} + diff --git a/lib/domains/town/room/chamber.c b/lib/domains/town/room/chamber.c new file mode 100644 index 0000000..be5c0ec --- /dev/null +++ b/lib/domains/town/room/chamber.c @@ -0,0 +1,43 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("The Healing Chamber"); + SetLong("This is the work chamber of Clepius the healer. " + "This is where he performs medical procedures on " + "his customers. A desk in the corner overflows with " + "notes and books. The reception and waiting area is " + "east of here."); + SetItems( ([ + "desk" : "This is where Clepius does " + "paperwork and research.", + ({"notes","books","notes and books"}) : "These " + "are the contents of the doctor's desk.", + "corner" : "Location of the desk." + ]) ); + SetExits( ([ + "east" : "/domains/town/room/healer", + ]) ); + SetRead( ({"notes","books","notes and books"}) , "That belongs to Clepius and it's private." ); + SetProperty("no attack", 1); + SetInventory(([ + "/domains/town/obj/bbucket" :1, + "/domains/town/npc/clepius" : ({60, 1}) + ]) ); + SetProperty("busy",0); + +} +int CanReceive(object ob) { + if(playerp(ob) && !creatorp(ob) && GetProperty("busy") == 1){ + message("info","The doctor is with a patient right now. Please "+ + "wait until you are called.",ob); + return 0; + } + return 1; +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/church.c b/lib/domains/town/room/church.c new file mode 100644 index 0000000..7960dc9 --- /dev/null +++ b/lib/domains/town/room/church.c @@ -0,0 +1,50 @@ +#include <lib.h> +inherit LIB_ROOM; +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("The Village Church"); + SetLong("Decades ago this tiny, one-room church was the center " + "of activity in the village. As the village prospered and secularized, " + "townsfolk attended less and less, until it became " + "dilapidated and abandoned, as you see here. The place " + "is overrun with vermin and cobwebs, but there has been " + "no vandalism. Just dusty neglect. West Village road " + "is south of here, and what looks like an elevator is " + "in the west wall.\n%^GREEN%^There is a button next " + "to the elevator.%^RESET%^"); + SetItems(([ + ({"elevator","elevator door","door"}) : "Set into the " + "west wall is a thoroughly modern-looking elevator, which seems " + "out of place in this rustic, colonial church. There is a button "+ + "next to it, presumably to call the elevator car.", + "road" : "The road is south of here.", + ({"wall","west wall"}) : "Set into the " + "west wall is a thoroughly modern-looking elevator, which seems " + "out of place in this rustic, colonial church. There is a button "+ + "next to it, presumably to call the elevator car.", + "road" : "The road is south of here.", + ({"church","place"}) : "An old church.", + ({"cobwebs","webs","web","vermin","dust","dirt"}) : "No vermin can presently " + "be seen, but from the cobwebs and dirt it's pretty clear " + "minor pests have made their home here.", + "vandalism" : "You don't see any of that." + ]) ); + SetInventory(([ + "/domains/town/obj/charity" : 1, + "/domains/town/obj/donation_box" : 1, + ])); + SetEnters( ([ + "elevator" : "/domains/town/room/elevator", + ]) ); + AddItem(new("/domains/town/obj/church_button")); + SetExits( ([ + "south" : "/domains/town/room/road1", + "west" : "/domains/town/room/elevator", + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/clearing.c b/lib/domains/town/room/clearing.c new file mode 100644 index 0000000..6c32cdb --- /dev/null +++ b/lib/domains/town/room/clearing.c @@ -0,0 +1,32 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(40); + SetNightLight(10); + SetDayLight(30); + SetShort("Forest Clearing"); + SetLong("This is a small clearing in a path through the forest. The path leads west into a small valley, and northeast toward a forest and a bridge."); + SetItems( ([ + "clearing" : "An area with few trees.", + "path" : "This forest path runs east " + "and west. A small trail goes north of here.", + ({"forest","wood","woods"}) : "This is a " + "dark, creepy forest. You are standing on a " + "path in a clearing, so it's a bit brighter here.", + ({ "small trail","trail"}) : "A small trail leading into the depths " + "of the forest to the north.", + "valley" : "A valley is west of here.", + "town" : "A town, far in the eastern distance." + ]) ); + SetSkyDomain("town"); + SetExits( ([ + "northeast" : "/domains/town/room/forest_path1", + "west" : "/domains/town/room/valley", + ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/clerk.c b/lib/domains/town/room/clerk.c new file mode 100644 index 0000000..b990aa8 --- /dev/null +++ b/lib/domains/town/room/clerk.c @@ -0,0 +1,30 @@ +#include <lib.h> +inherit LIB_CHAPEL; + +static void create() { + chapel::create(); + SetTown("town"); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Town Clerk"); + SetLong("This small office is where people come to conduct their official public business. The main area of the town hall is south."); + SetProperties (([ + "no attack":1, + "no bump":1, + "no steal":0, + "no magic":0, + "no paralyze":0, + "no teleport":0])); + SetItems(([])); + SetExits( ([ + "south" : "/domains/town/room/thall", + ]) ); + SetInventory(([ + "/domains/town/npc/clerk" : ({60, 1}), + ])); +} +void init() { + ::init(); + SetSmell(([])); + SetListen(([])); +} diff --git a/lib/domains/town/room/confroom.c b/lib/domains/town/room/confroom.c new file mode 100644 index 0000000..9807699 --- /dev/null +++ b/lib/domains/town/room/confroom.c @@ -0,0 +1,124 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +int privacy, timer; +string ExtraDesc(); +static void create() { + string privs; + privs = query_privs(); + if( privs ) privs = capitalize(privs); + else privs = "a creator"; + room::create(); + SetClimate("indoors"); + SetAmbientLight(40); + SetShort("Conference Room"); + SetLong((: ExtraDesc :)); + SetInventory(([ + "/domains/town/obj/chair" : 4, + "/domains/town/obj/bbucket" : 1, + "/secure/npc/cambot" : 1 + ])); + SetExits(([ + "west" : "/domains/town/room/adv_guild", + ])); + + SetProperties(([ + "no attack" : 1, + "nopeer" : 1, + "meeting room" : 1, + ])); + SetNoClean(1); + privacy=0; + set_heart_beat(20); + timer = 0; + +} + +int AutoDeactivate(){ + message("info","%^RED%^The privacy field shuts off.%^RESET%^", this_object()); + timer = 0; + privacy = 0; + return 1; +} + +void init(){ + ::init(); + add_action("privacy","privacy"); + add_action("privacy","priv"); + add_action("report_time","timer"); +} + +void heart_beat(){ + if(timer && (time() - timer ) > 1200) AutoDeactivate(); +} + +int report_time(){ + int secs = time() - timer; + + if(!timer){ + write("Privacy field is not active."); + return 0; + } + + write("Elapsed seconds: "+secs); + write("Elapsed minutes: "+(secs/60)); + return secs; +} + +int CanReceive(object ob) { + if(privacy){ + if(!interactive(ob)) { + message("info","\n\nPRIVACY WARNING: "+ob->GetName()+" has entered the room.\n\n",this_object() ); + } + else if(!archp(ob)){ + message("info","You bounce off the conference room privacy shield.", ob); + message("info",ob->GetName()+" bounced off the privacy shield.",this_object()); + if(!environment(ob)) ob->eventMoveLiving(ROOM_START); + return 0; + } + + } + return room::CanReceive(); +} + +int set_privacy(int i){ + if(environment(this_player()) != this_object() && !archp(this_player())) { + write("You lack the adequate privileges to do that."); + say(this_player()->GetName()+" is trying to mess around with the privacy shield system."); + return 1; + } + privacy=i; + return 1; +} + +int privacy(string str){ + if(environment(this_player()) != this_object() && !archp(this_player())) { + write("You lack the adequate privileges to do that."); + say(this_player()->GetName()+" is trying to muck around with the privacy shield system."); + return 1; + } + + if(str=="on" || str == "1"){ + this_object()->set_privacy(1); + write("You enable the privacy shield.\n"); + say(this_player()->GetName()+" enables a privacy force field around the room."); + timer = time(); + return 1; + } + if(str=="off" || str == "0"){ + this_object()->set_privacy(0); + write("You disable the privacy shield.\n"); + say(this_player()->GetName()+" disables a privacy force field around the room."); + timer = 0; + return 1; + } +} + +string ExtraDesc(){ + string extra = "%^YELLOW%^A privacy force field is active around this room.%^RESET%^"; + string desc = "This is an enchanted room, with the magical power to prevent uninvited people from entering. It is used for meetings where three or more people need to share information without interruption or privately. To enable privacy, 'privacy on'. To disable it, 'privacy off'. The privacy field automatically deactivates after approximately 20 minutes.\n"; + if(privacy) return desc+extra; + else return desc+"%^RED%^The privacy field is DISABLED."; +} diff --git a/lib/domains/town/room/cratshack.c b/lib/domains/town/room/cratshack.c new file mode 100644 index 0000000..7b213ee --- /dev/null +++ b/lib/domains/town/room/cratshack.c @@ -0,0 +1,34 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetShort("north of house"); + SetLong("The thick woods give way to a small clearing here, where an old house, painted white, stands. The front porch of the house is south. A narrow trail leads into the woods to the north."); + SetItems(([ + ({ "forest", "wood", "vegetation" }) : "All around is vegetation growing so incredibly dense that it is impossible to wander off the path.", + ({ "porch", "front porch" }) : "The wooden front porch of an old white house.", + ({ "trail", "path" }) : "To the north, a narrow path leads into the woods.", + ({ "clearing", "woods" }) : "As if by powerful magic, the woods clear here, where the house stands.", + ({ "house", "white house", "old house" }) : "The house looks weatherbeaten, ill maintained, and rather old. Its construction is of an archaic design no longer used. Despite its abused appearance, the house seems to have a quiet dignity about it, as if many people had been its friends over the years, and it simply waited for their return.", + ])); + SetSkyDomain("town"); + SetExits( ([ + "north" : "/domains/town/room/narrow_path2", + "south" : "/domains/town/room/porch.c", + ]) ); + SetInventory(([ + "/domains/town/obj/mailbox" : 1, + ])); + +} +void init(){ + ::init(); +} + +int CanReceive(object ob){ + if(answers_to("provost",ob)) return 0; + return ::CanReceive(); +} diff --git a/lib/domains/town/room/death.c b/lib/domains/town/room/death.c new file mode 100644 index 0000000..e40ee97 --- /dev/null +++ b/lib/domains/town/room/death.c @@ -0,0 +1,72 @@ +#include <lib.h> +#include <dirs.h> +#include ROOMS_H + +inherit LIB_ROOM; + +string FunkyPic(); +int CheckChat(); +int StartHeart(object ob); + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("off the mortal coil"); + SetLong( (:FunkyPic:) ); + SetObviousExits("no exit"); + set_heart_beat(10); + SetNoModify(1); +} + +void init(){ + ::init(); + add_action("regenerate","regenerate"); + add_action("wander","wander"); + this_object()->CheckChat(); +} + +string FunkyPic(){ + return read_file("/domains/default/etc/death.txt"); +} + +int regenerate(){ + write("With a great rush of matter and energy, you rematerialize "+ + "into a corporeal state, and find yourself in a familiar place..."); + this_player()->eventRevive(); + this_player()->eventMoveLiving(ROOM_START); + return 1; +} + +int wander(){ + write("There is a strange, hollow vibration all around you, and you "+ + "realize that some force is compelling your ethereal form elsewhere..."+ + "you find yourself in a place that is known to you, yet oddly new."); + this_player()->eventMoveLiving(ROOM_START); + return 1; +} + +void heart_beat(){ + tell_room(this_object(), "A voice whispers: \" You may choose to "+ + "regenerate into a new body here.\""); + return; +} + + +int CanRelease(object ob){ + if(userp(ob) && ob->GetGhost() && environment(ob) == this_object()) { + tell_player(ob,"\n%^RED%^Your undead spirit is recalled and as you leave "+ + "the underworld a new body regenerates around you. "+ + "You live again!%^RESET%^\n"); + ob->eventRevive(); + } + return 1; +} + +int CanReceive(object ob){ + if(!living(ob)){ + return 0; + } + return ::CanReceive(ob); +} + diff --git a/lib/domains/town/room/docks.c b/lib/domains/town/room/docks.c new file mode 100644 index 0000000..885904e --- /dev/null +++ b/lib/domains/town/room/docks.c @@ -0,0 +1,58 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_FISHING; + +varargs string readSign() { + string ret = "WARNING! Orcs, dwarves, and some other races cannot "+ + "swim! If you jump into the sea you will sink and drown!"; + return ret; +} + +static void create() { + fishing::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetShort("Dock of the Bay"); + SetNightLong("This is an area comprised of a raised wooden platform that extends into the water so that folks with boats can conveniently enter and exit their vehicles. The dock runs south along the shoreline, turning into a boardwalk. The town shore is north. A great sea stretches out into the eastern horizon. A lone lamp post lights this area. \n%^GREEN%^There is a sign here you can read.%^RESET%^"); + SetDayLong("This is an area comprised of a raised wooden platform that extends into the water so that folks with boats can conveniently enter and exit their vehicles. The dock runs south along the shoreline, turning into a boardwalk. The town shore is north. A great sea stretches out into the eastern horizon. \n%^GREEN%^There is a sign here you can read.%^RESET%^"); + SetItems( ([ + "sign":"A sign on the ground. To read it, 'read sign'.", + "platform":"The local surface.", + "raised wooden platform":"The local surface.", + "wooden platform":"The local surface.", + "raised platform":"The local surface.", + "horizon":"Where the sky loves the sea.", + "town":"A population center to the northwest.", + "boardwalk":"Leads south from here.", + "dock":"What boats do here.", + "shoreline":"The demarcator of discontinuity between land and sea.", + ]) ); + SetExits( ([ + "north" : "/domains/town/room/shore", + "south" : "/domains/town/room/bwalk1.c", + ]) ); + SetProperty("dock", 1); + SetRead("sign", (: readSign :) ); + SetFrequency(5); + SetChance(90); + SetFish( ([ + "/domains/town/meals/shark" : 10, + "/domains/town/meals/herring" : 20, + ]) ); + SetActionsMap( ([ + "A soft breeze cools your brow." : 5, + "You briefly hear seagulls far in the distance." : 7, + "A cool breeze flows in from the east, " + + "bringing with it the bracing salty smells of the sea.": 2, + ]) ); + SetInventory( ([ + "/domains/town/obj/seawater" : 1, + ]) ); + AddItem(new("/domains/town/obj/lamp")); + SetSkyDomain("town"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/elevator.c b/lib/domains/town/room/elevator.c new file mode 100644 index 0000000..ed9a677 --- /dev/null +++ b/lib/domains/town/room/elevator.c @@ -0,0 +1,126 @@ +#include <lib.h> +inherit LIB_ROOM; + +int doorcounter,callfloor,closed,floor,my_counter,moving; +string floorname; +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Church Elevator"); + SetLong("This is the elevator in the village church. The elevator door is on the east wall. Two buttons are set into the wall next to the door, labeled '1' and 'b'."); + floor=1; + moving = 0; + closed=1; + callfloor=0; + SetExits( ([ + "east" : "/domains/town/room/church", + ]) ); + SetItems(([ + //new("/domains/town/obj/ebutton1") : 1, + //new("/domains/town/obj/ebutton2") : 1, + "elevator" : "A means of vertical indoors transportation.", + "wall" : "The buttons are on the wall.", + ({"elevator door","door"}) : "The door to the outside." + ]) ); + AddItem(new("/domains/town/obj/ebutton2")); + AddItem(new("/domains/town/obj/ebutton1")); + set_heart_beat(1); +} +void init(){ + ::init(); + set_heart_beat(1); +} +int CallMe(int i){ + if(i == floor && moving == 0) { + this_object()->SetDoorClosed(0); + return 1; + } + else callfloor = i; + return 1; +} +int SetDoorClosed(int i){ + if(i && i == closed) return i; + if(!i && closed == 0) return i; + if(i == 0 && closed == 0) return i; + if(i) closed = i; + else if( closed == 1 ) closed = 0; + else if( closed == 0 ) closed =1; + if(floor == 1) floorname = "/domains/town/room/church"; + if(floor == 2) floorname = "/domains/town/room/basement"; + if(closed < 1){ + tell_room(this_object(),"The elevator door opens."); + tell_room(load_object(floorname),"The elevator door opens."); + doorcounter = 10; + } + if(closed > 0) { + tell_room(this_object(),"The elevator door closes."); + tell_room(load_object(floorname),"The elevator door closes."); + doorcounter = 0; + } + return closed; +} +int SetFloor(int i){ + if(floor == i) return 0; + RemoveExit("east"); + floor = i; + if(i == 1) AddExit("east", "/domains/town/room/church"); + if(i == 2) AddExit("east", "/domains/town/room/basement"); + return 1; +} +int CanReceive(object ob) { +#if 1 + if(living(ob) && closed > 0 && query_verb() != "goto" && + query_verb() != "trans" ){ + message("info","The elevator door is closed.", ob); + return 0; + } +#endif + return 1; +} +int CanRelease(object ob){ + if(archp(ob)) { + tell_object(ob,"%^RED%^As archwizard, you are permitted to " + "exit the elevator at any time. Normal creators and " + "players cannot do this.%^RESET%^\n"); + } + if(closed > 0 && query_verb() == "go" ){ + message("info","The elevator door is closed.", ob); + return 0; + } + return 1; +} +varargs int eventRoll(int i){ + if(!i) i = 10; + moving = 1; + SetDoorClosed(1); + my_counter = i; + return i; +} +void heart_beat(){ + if(doorcounter > 0){ + doorcounter--; + if(doorcounter < 2) SetDoorClosed(1); + } + + if(moving == 0 && closed == 1 && callfloor > 0){ + tell_room(this_object(),"The elevator lurches into motion."); + eventRoll(); + } + + if(moving && moving > 0){ + my_counter--; + if(my_counter % 5 == 0) { + tell_room(this_object(),"The elevator continues..."); + } + + if(my_counter < 2) { + my_counter = 0; + moving = 0; + SetFloor(callfloor); + tell_room(this_object(),"The elevator arrives at its destination."); + SetDoorClosed(0); + callfloor = 0; + } + } +} diff --git a/lib/domains/town/room/forest_path1.c b/lib/domains/town/room/forest_path1.c new file mode 100644 index 0000000..2cb19b7 --- /dev/null +++ b/lib/domains/town/room/forest_path1.c @@ -0,0 +1,45 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetNightLight(10); + SetDayLight(30); + SetShort("Forest Path"); + SetLong("You are in a forest outside the town. To the southwest the path continues toward a clearing. To the east it leads to a bridge over a river toward a town. Trees and bushes of various kinds border the path making it impossible to go south but to the north the vegetation is less dense."); + SetItems( ([ + "forest" : "You are on a path in a dark, creepy forest. The " + "vegetation is thick and feels somehow oppressive.", + ({"plants","bushes","vegetation","tree","trees","bush"}) : + "The plants, bushes, and trees grow thick and wild " + "here, limiting visibility beyond the path.", + "bridge" : "An old bridge is east of here.", + "clearing" : "It looks like there is a clearing in the " + "forest to the west.", + "path" : "You are on a path in a forest." + ]) ); + SetSkyDomain("town"); + SetExits( ([ + "north" : "/domains/town/virtual/forest/-4,1", + "east" : "/domains/town/room/bridge", + "southwest" : "/domains/town/room/clearing.c", + ]) ); +} +void init(){ + ::init(); +} + +int CanReceive(object ob){ + object env = environment(ob); + if(!env || base_name(env) != "/domains/town/virtual/forest/24,1"){ + return ::CanReceive(); + } + if(living(ob) && !interactive(ob) && + (!ob->GetRiders() || !sizeof(ob->GetRiders()))){ + ob->eventPrint("You find yourself unable to leave the forest."); + return 0; + } + return ::CanReceive(); +} diff --git a/lib/domains/town/room/forest_well1.c b/lib/domains/town/room/forest_well1.c new file mode 100644 index 0000000..c1373e7 --- /dev/null +++ b/lib/domains/town/room/forest_well1.c @@ -0,0 +1,69 @@ +#include <medium.h> +#include <daemons.h> +#include <terrain_types.h> +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +int ActionFunction(){ + object *bodies = get_livings(this_object()); + if(!sizeof(bodies)) return 0; + foreach(object body in bodies){ + int maxheal, maxstam, maxmag; + int health, stamina, magic, poison; + if((RACES_D->GetNonMeatRace(body->GetRace()))) continue; + maxheal = (body->GetMaxHealthPoints()) * 0.6; + maxstam = (body->GetMaxStaminaPoints()) * 0.6; + maxmag = (body->GetMaxMagicPoints()) * 0.6; + health = (body->GetHealthPoints()); + stamina = (body->GetStaminaPoints()); + magic = (body->GetMagicPoints()); + + if(health < maxheal){ + body->AddHP(random(10)); + } + if(stamina < maxstam){ + body->AddStaminaPoints(random(10)); + } + if(magic < maxmag){ + body->AddMagicPoints(random(10)); + } + if(poison > 0 ){ + body->AddPoison(-(random(10))); + } + } + return 1; +} + +void create() { + room::create(); + SetAmbientLight(30); + SetDayLight(30); + SetNightLight(30); + SetShort("water shaft"); + SetLong("This is the vertical shaft of what seems to be a natural spring. It seems as though a bright light from below illuminates this area."); + SetClimate("temperate"); + SetTown("wilderness"); + SetTerrainType(T_UNDERWATER); + SetMedium(MEDIUM_WATER); + SetItems( ([ + ({ "shaft","passage" }) : "An underwater vertical passage.", + ]) ); + SetExits( ([ + "up" : "/domains/town/virtual/forest/-13,13", + "down" : "/domains/town/room/forest_well2.c", + ]) ); + + SetInventory(([ + "/domains/town/obj/hspringwater" : 1, + ])); + set_heart_beat(5); +} +void init(){ + ::init(); +} + +void heart_beat(){ + ActionFunction(); +} diff --git a/lib/domains/town/room/forest_well2.c b/lib/domains/town/room/forest_well2.c new file mode 100644 index 0000000..3870f5e --- /dev/null +++ b/lib/domains/town/room/forest_well2.c @@ -0,0 +1,70 @@ +#include <medium.h> +#include <daemons.h> +#include <terrain_types.h> +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +int ActionFunction(){ + object *bodies = get_livings(this_object()); + if(!sizeof(bodies)) return 0; + foreach(object body in bodies){ + int maxheal, maxstam, maxmag; + int health, stamina, magic, poison; + if((RACES_D->GetNonMeatRace(body->GetRace()))) continue; + maxheal = (body->GetMaxHealthPoints()) * 0.85; + maxstam = (body->GetMaxStaminaPoints()) * 0.85; + maxmag = (body->GetMaxMagicPoints()) * 0.85; + health = (body->GetHealthPoints()); + stamina = (body->GetStaminaPoints()); + magic = (body->GetMagicPoints()); + + if(health < maxheal){ + body->AddHP(random(10)); + } + if(stamina < maxstam){ + body->AddStaminaPoints(random(15)); + } + if(magic < maxmag){ + body->AddMagicPoints(random(15)); + } + if(poison > 0 ){ + body->AddPoison(-(random(15))); + } + } + return 1; +} + +void create() { + room::create(); + SetAmbientLight(30); + SetDayLight(30); + SetNightLight(30); + SetShort("Spring bottom"); + SetLong("This is the bedrock floor of a natural spring. A passage leads up.\n%^BLUE%^There is a large, glowing egg here.%^RESET%^"); + SetClimate("temperate"); + SetTown("wilderness"); + SetTerrainType(T_SEAFLOOR); + SetMedium(MEDIUM_WATER); + SetItems( ([ + ({ "shaft","passage" }) : "An underwater vertical passage.", + ({ "egg","large egg","large glowing egg","glowing egg" }) : "About a meter in diameter, this large egg seems to glow and pulsate with energy.", + ]) ); + SetExits(([ + "up" : "/domains/town/room/forest_well1", + ])); + + SetInventory(([ + "/domains/town/obj/hspringwater" : 1, + "/domains/town/npc/giant_isopod" : 1, + ])); + set_heart_beat(6); +} +void init(){ + ::init(); +} + +void heart_beat(){ + ActionFunction(); +} diff --git a/lib/domains/town/room/freezer.c b/lib/domains/town/room/freezer.c new file mode 100644 index 0000000..896cbbf --- /dev/null +++ b/lib/domains/town/room/freezer.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetNoClean(1); + SetProperties(([ "login" : ROOM_START ])); + SetShort( "The freezer"); + SetLong( "The local freezer. Go down to leave."); + SetObviousExits("down"); + SetExits( ([ "down" : ROOM_START ]) ); + call_out("clean_room", MAX_NET_DEAD_TIME); + SetNoModify(1); +} + +static void clean_room(){ + object ob; + call_out((: clean_room :), MAX_NET_DEAD_TIME); + foreach(ob in filter(all_inventory(), (: living($1) :))){ + string name = last_string_element(base_name(ob),"/"); + if(!user_exists(name)) continue; + ob->eventDestruct(); + } +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/furnace.c b/lib/domains/town/room/furnace.c new file mode 100644 index 0000000..240341a --- /dev/null +++ b/lib/domains/town/room/furnace.c @@ -0,0 +1,10 @@ +#include <lib.h> + +inherit LIB_FURNACE; + +void create() { + furnace::create(); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/garden.c b/lib/domains/town/room/garden.c new file mode 100644 index 0000000..52a19ba --- /dev/null +++ b/lib/domains/town/room/garden.c @@ -0,0 +1,32 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetNightLight(10); + SetDayLight(30); + SetShort("Mansion Garden"); + SetLong("This is what is left of what was once a beautiful, " + "if simple, garden. It is now badly overgrown with " + "weeds, and it is clear that foraging animals long " + "ago ate the delicate flowers and vegetables that " + "once grew here. The gardener's shack is north."); + SetItems(([ + ({ "flowers", "vegetables", "flowers and vegetables" }) : "If they were once here, they certainly no longer are.", + ({ "shack", "wooden shack" }) : "A beaten-up old wooden shack is north.", + "garden" : "A mess of weeds and dirt.", + ])); + SetSkyDomain("town"); + SetExits( ([ + "east" : "/domains/town/room/mansion_ext", + "north" : "/domains/town/room/shack" + ])); + SetEnters( ([ + "shack" : "/domains/town/room/shack", + ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/gate.c b/lib/domains/town/room/gate.c new file mode 100644 index 0000000..e30b2a0 --- /dev/null +++ b/lib/domains/town/room/gate.c @@ -0,0 +1,70 @@ +#include <lib.h> +inherit LIB_ROOM; + +int maxnoob = MAX_NEWBIE_LEVEL; + +int PreExit(){ + object guard = present("gate guard",this_object()); + if(!MAX_NEWBIE_LEVEL) maxnoob = 3; + if(((MAX_NEWBIE_LEVEL && !newbiep(this_player())) || + this_player()->GetLevel() > maxnoob) && + (!this_player()->GetInvis() && !creatorp(this_player()) && + !present("testchar badge",this_player()))){ + if(guard && living(guard)){ + present("gate guard",this_object())->eventForce("say You're too big to slip by me now. You're not going to the mansion any more."); + return 0; + } + } + if((newbiep(this_player()) || this_player()->GetLevel() <= maxnoob) + && guard && living(guard)){ + tell_object(this_player(),"You are such a newbie that the gate guard doesn't even notice you slip by him."); + tell_room(this_object(),this_player()->GetName()+" sneaks past the gate guard.",({ this_player() }) ); + } + return 1; +} + +static void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetShort("Mansion Gate"); + SetLong("You are standing just north of the gate to a large, "+ + "beautiful mansion, which stands to the south. The "+ + "Corinthian capitals on the front pillars bespeak "+ + "of the wealth and importance of the person who "+ + "lives here. Lush ivy wraps around the gate and the "+ + "brick wall surrounding the estate."); + SetItems( ([ + "gate" : "A handsome, wrought-iron entry control point.", + ({"estate", "mansion"}) : "The grounds of a mansion are to the south.", + ({"capital","capitals","corinthian capital","corinthian capitals"}) : + "These are the headpieces of the pillars supporting the " + "mansion's front overhang. The beautifully detailed " + "carvings of encanthus leaves distinguish them as " + "Corinthian.", + ({"overhang","front overhang"}) : "A fancy and unnecessary " + "structure in front of the mansion supported by " + "columns.", + ({"pillar","pillars","column","columns"}) : "Load-bearing " + "structures supporting the mansion's front overhang.", + ({"ivy","lush ivy"}) : "Vines of the ivy plant run " + "over and along the walls and gate, so thickly that " + "they nearly obscure them.", + ({"wall","walls"}) : "Architectural features which prevent " + "casual entry. They are made of brick and appear old " + "and strong.", + ]) ); + SetSkyDomain("town"); + SetExits( ([ + "north" : "/domains/town/room/road2.c", + ]) ); + SetInventory(([ + "/domains/town/npc/mp" : ({ 3600, 1 }), + ])); + AddExit("south", "/domains/town/room/mansion_ext", (: PreExit :)); + AddItem(new("/domains/town/obj/lamp")); + SetProperty("no attack", 1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/healer.c b/lib/domains/town/room/healer.c new file mode 100644 index 0000000..d4cae86 --- /dev/null +++ b/lib/domains/town/room/healer.c @@ -0,0 +1,59 @@ +#include <lib.h> +inherit LIB_SHOP; +inherit LIB_AMBIANCE; + +int ReadList(){ + write("AVAILABLE PROCEDURES:\n" + "\thealing, cost 200:\t\tfacilitate rapid recovery from wounds\n" + "\tregeneration, cost 1200:\tgrow back severed limbs\n" + "\texcision, cost 700:\t\tremove bullets\n" + "\tclaritin, cost 10:\t\talleviate cold symptoms\n" + "\tpoison antidote, cost 200:\tmitigate the effects of poisoning\n" + "\tcure light disease, cost 200:\tfix you up from most sicknesses\n" + "\n" + "Example: If you are badly hurt and need healing:\n\n" + "\"buy healing slip from james\"\n" + "\n" + "If you've been poisoned: \n\n" + "\"buy antidote from james\"\n" + "\n" + "Once you have a slip, go west to see the doctor and " + "give the slip to him.\n\n" + "In the case of the antidote or disease cure, drink your vial.\n" + + ); + return 1; +} +static void create() { + ::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("The Healers Guild"); + SetLong("You are in the Healer's Guild. People come " + "here when they have medical problems, and " + "for a price, they are helped. " + "It seems that the doctor's work area is " + "west of here. Saquivor Road is east." + "\n%^GREEN%^There is a list here you can read.%^RESET%^"); + SetItems( ([ + ({"list","list on the wall"}) : "A list of available procedures", + "wall" : "A flat, vertical structure supporting the ceiling.", + ({"work area","doctor's work area"}) : "It is west of here.", + ({"road","tavern road"}) : "The road is outside, east of here." + ]) ); + SetRead( ({"list","list on wall"}) , (: ReadList :) ); + SetInventory(([ + "/domains/town/obj/bbucket" :1, + "/domains/town/npc/james" : ({60, 1}) + ]) ); + SetExits( ([ + "east" : "/domains/town/room/road", + "out" : "/domains/town/room/road", + "west" : "/domains/town/room/chamber", + ]) ); + SetProperty("no attack", 1); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/healer2.c b/lib/domains/town/room/healer2.c new file mode 100644 index 0000000..2f82ba8 --- /dev/null +++ b/lib/domains/town/room/healer2.c @@ -0,0 +1,37 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Healer's Guild Storeroom"); + SetLong("This blank room is where the guild keeps their junk."); + SetInventory(([ + "/domains/town/meals/claritin" : 20, + "/domains/town/obj/slip_heal" : 100, + "/domains/town/obj/slip_regenerate" : 10, + "/domains/town/obj/slip_excise" : 10, + "/domains/town/meals/potion_antidote" : 20, + "/domains/town/meals/potion_cure" : 20, + ])); + SetExits( ([ + ]) ); + +} +int CanReceive(object sneak) { + object *living_stack = get_livings(sneak); + if(!living_stack || !arrayp(living_stack)) living_stack = ({ sneak }); + foreach(object ob in living_stack){ + if(living(ob) && !creatorp(ob) && + !member_group(ob,"TEST")) { + message("info","The storeroom is for guild officers only.", ob); + return 0; + } + } + return 1; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/hp.c b/lib/domains/town/room/hp.c new file mode 100644 index 0000000..717cd8c --- /dev/null +++ b/lib/domains/town/room/hp.c @@ -0,0 +1,37 @@ +#include <lib.h> + +inherit LIB_ROOM; + +varargs string readMenu() { + string ret = "\tStein of Guinness\t\t\t1 gold\n"+ + "\tBottle of wine\t\t\t\t2 gold\n"+ + "\tBottle of whiskey\t\t\t3 gold\n"; + return ret; +} + +void create(){ + ::create(); + SetAmbientLight(30); + SetShort("Harry's Pub"); + SetLong("Harry's Pub is a simple place where lonely sailors pass the time away and talk about their homes. Known to serve some mean drinks and customers, the place is clean and spare, with few things to break over someone's head. A menu on the wall lists the available refreshments. There appears to be some kind of back room to the west."); + SetClimate("indoors"); + SetItems( ([ + ({"wall", "walls"}) : "If only they could speak, eh?", + "menu" : "A menu you can read. Oddly it has as its logo a severed "+ + "wolf's head on a stick.", + ({"room","back room"}) : "Perhaps a storage area.", + "harry" : "Nobody's seen Harry since the jive ring thing.", + ]) ); + SetSkyDomain("town"); + SetRead("menu", (: readMenu :) ); + SetInventory(([ + "/domains/town/npc/brandy" : 1, + ]) ); + SetExits( ([ + "east" : "/domains/town/room/bwalk1.c", + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/living_room.c b/lib/domains/town/room/living_room.c new file mode 100644 index 0000000..9c18a03 --- /dev/null +++ b/lib/domains/town/room/living_room.c @@ -0,0 +1,34 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetShort("living room"); + SetLong("This is the living room of the old house. It is a small, modest home, apparently constructed with an eye toward practicality rather than fanciness. A doorway north leads to the front porch."); + SetItems(([ + ({ "forest", "wood", "vegetation" }) : "All around is vegetation growing so incredibly dense that it is impossible to wander off the path.", + ({ "porch", "front porch" }) : "The wooden front porch of an old white house.", + ({ "trail", "path" }) : "To the north, a narrow path leads into the woods.", + ({ "clearing", "woods" }) : "As if by powerful magic, the woods clear here, where the house stands.", + ({ "house", "white house", "old house" }) : "The house looks weatherbeaten, ill maintained, and rather old. Its construction is of an archaic design no longer used. Despite its abused appearance, the house seems to have a quiet dignity about it, as if many people had been its friends over the years, and it simply waited for their return.", + ])); + SetInventory(([ + "/domains/town/obj/sofa" : 1, + "/domains/town/obj/simple_chair" : 2, + ])); + SetExits(([ + "north" : "/domains/town/room/porch", + ])); + + SetDoor("north", "/domains/town/doors/house_door.c"); + +} +void init(){ + ::init(); +} +int CanReceive(object ob){ + if(answers_to("provost",ob)) return 0; + return ::CanReceive(); +} diff --git a/lib/domains/town/room/magic_guild.c b/lib/domains/town/room/magic_guild.c new file mode 100644 index 0000000..4e90b60 --- /dev/null +++ b/lib/domains/town/room/magic_guild.c @@ -0,0 +1,58 @@ +#include <lib.h> +inherit LIB_ROOM; + +string ReadList(){ + string muggleret = "AVAILABLE SPELLS:\n\n" + "\tfireball, cost 1000:\tput the hurt on an opponent\n" + "\tmissile, cost 500:\tCheaper and easier to learn than fireball\n" + "\tbuffer, cost 200:\tconjure an invisible shield around you\n" + "\tmeditate, cost 500:\tconjure an aura that speeds stamina recovery\n" + "\n" + "Example: If you want to learn the buffer spell:\n\n" + "\"ask herkimer to teach buffer\"\n" + "\n" + "Please note that the spell may fail many times before " + "you have enough practice and experience to cast " + "it properly. All sales final.\n"; + string mageret = "AVAILABLE SPELLS:\n\n" + "\tfireball:\tput the hurt on an opponent\n" + "\tgreater fireball:\tput the serious hurt on an opponent\n" + "\tmissile:\tCheaper and easier to learn than fireball\n" + "\tlight:\t\tMakes you glow brightly enough to see in the dark.\n" + "\tbuffer:\t\tconjure an invisible shield around you\n" + "\tgreater buffer:\t\tconjure a powerful invisible shield around you\n" + "\tmeditate:\tconjure an aura that speeds stamina recovery\n" + "\twhip:\t\tconjure a powerful energy whip\n" + "\n" + "Example: If you want to learn the buffer spell:\n\n" + "\"ask herkimer to teach buffer\"\n" + "\n"; + if(this_player()->GetClass() == "mage") return mageret; + return muggleret; +} +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("The Mages' Guild"); + SetLong("This is the local mage's guild. Here you can ask "+ + "the guildmaster to let you join, or to teach you spells. "+ + "For example, you may \"ask herkimer to join\" or "+ + "\"ask herkimer to teach missile\". The magic shop "+ + "is north." + "\n%^GREEN%^There is a list of spells you can read.%^RESET%^"); + SetItems( ([ + ({"list","list on the wall"}) : "A list of available spells", + ]) ); + SetInventory(([ + "/domains/town/npc/herkimer" : ({60, 1}), + ])); + SetRead(({"list","list on wall"}) , (: ReadList :) ); + SetExits( ([ + "north" : "/domains/town/room/magic_shop" + ]) ); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/magic_shop.c b/lib/domains/town/room/magic_shop.c new file mode 100644 index 0000000..a412914 --- /dev/null +++ b/lib/domains/town/room/magic_shop.c @@ -0,0 +1,42 @@ +#include <lib.h> +inherit LIB_SHOP; + +int read_sign(); +static void create() { + ::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("The Magic Shop"); + SetLong("This is the local magic shop. Magical items can be bought and sold here. The storeroom is upstairs and the town Mages' Guild is south."); + SetItems(([ + ({"store","shop","place"}) : "This is the local magic shop.", + ({ "sign" ,"sign on the wall" }): "A sign on the wall, meant for reading.", + ])); + SetExits( ([ + "south" : "/domains/town/room/magic_guild", + "east" : "/domains/town/room/south_road1", + "up" : "/domains/town/room/magic_shop2.c", + ]) ); + SetRead("sign", (: read_sign :) ); + SetInventory( ([ + "/domains/town/npc/oana" : ({60, 1}), + "/domains/town/obj/bbucket" : 1, + ]) ); +} +int read_sign(){ + write("HOW TO CONDUCT BUSINESS HERE\n"); + write("list : Get a list of all the items Oana has for sale"); + write("appraise <item> : Ask Oana to tell you how much she would pay you for your item"); + write("price <item> : Ask Oana the price of her item"); + write("show <item> : Ask Oana for a closer look at her item\n"); + write("\nbuy <item> from oana\nsell <item> to oana\n"); + write("Prices shown are in silver coins."); + write("\n\nWe're still under construction, so there's"); + write("not much to buy. But if you want, you can go "); + write("south to the mage's guild and join up!"); + + return 1; +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/magic_shop2.c b/lib/domains/town/room/magic_shop2.c new file mode 100644 index 0000000..be9ca69 --- /dev/null +++ b/lib/domains/town/room/magic_shop2.c @@ -0,0 +1,41 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("The Magic Shop Storeroom"); + SetLong("This is the storeroom where magical items are kept."); + SetInventory(([ + "/domains/town/obj/scroll_raise_dead" : 5, + "/domains/town/meals/potion_bigheal" : 2, + "/domains/town/meals/potion_healing" : 10, + "/domains/town/obj/8ball" : 3, + "/domains/town/obj/d6" : 5, + "/domains/default/armor/gray_amulet" : 2, + "/domains/town/obj/omni" : 1, + "/domains/town/meals/potion_strength" : 5, + "/domains/town/obj/pipe" : 5, + "/domains/town/obj/d20" : 5, + ])); + SetExits( ([ + "down" : "/domains/town/room/magic_shop.c", + ]) ); +} +int CanReceive(object sneak) { + object *living_stack = get_livings(sneak); + if(!living_stack || !arrayp(living_stack)) living_stack = ({ sneak }); + foreach(object ob in living_stack){ + if(living(ob) && !creatorp(ob) && + !member_group(ob,"TEST")) { + message("info","Oana's back room area is for authorized personnel only.", ob); + return 0; + } + } + return 1; +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/mansion_dhall2.c b/lib/domains/town/room/mansion_dhall2.c new file mode 100644 index 0000000..e9f92c9 --- /dev/null +++ b/lib/domains/town/room/mansion_dhall2.c @@ -0,0 +1,29 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Downstairs Mansion Hallway"); + SetLong("You are in the beautifully decorated downstairs " + "hallway of the mansion. There are rooms to " + "the east and west, and the hallway continues " + "south. To the north is the entrance foyer."); + SetItems( ([ + "hallway" : "An interior area providing access to " + "other places in the house.", + ({"mansion","house"}) : "You are in a beautiful mansion.", + "foyer" : "The mansion's entry area is north of here." + ]) ); + SetExits( ([ + "north" : "/domains/town/room/mansion_int", + "south" : "/domains/town/room/mansion_dhall3", + "west" : "/domains/town/room/mansion_room10", + "east" : "/domains/town/room/mansion_room7.c", + ]) ); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/mansion_dhall3.c b/lib/domains/town/room/mansion_dhall3.c new file mode 100644 index 0000000..025a008 --- /dev/null +++ b/lib/domains/town/room/mansion_dhall3.c @@ -0,0 +1,32 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Downstairs Mansion Hallway South"); + SetLong("You are in the beautifully decorated downstairs " + "hallway of the mansion. There are rooms to " + "the east and west, and the hallway continues " + "north. A large, " + "circular marble staircase leads up to the " + "second floor."); + SetItems( ([ + "hallway" : "An interior area providing access to " + "other places in the house.", + ({"mansion","house"}) : "You are in a beautiful mansion.", + ({"stairs","staircase"}) : "A marvelously sculpted " + "series of steps spiraling upward to the " + "second floor. It is carved from marble." + ]) ); + SetExits( ([ + "north" : "/domains/town/room/mansion_dhall2", + "west" : "/domains/town/room/mansion_room8", + "up" : "/domains/town/room/mansion_uhall3", + ]) ); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/mansion_ext.c b/lib/domains/town/room/mansion_ext.c new file mode 100644 index 0000000..b43a7bf --- /dev/null +++ b/lib/domains/town/room/mansion_ext.c @@ -0,0 +1,39 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(40); + SetShort("Mansion Exterior"); + SetNightLong("You are standing outside a large, beautiful mansion to the south, illuminated by lamplight. It towers over you and overhead you can see one of the second floor windows is open. The grass seems a bit wild around here, and the lawn continues west into the darkness. The mansion gate is north."); + SetDayLong("You are standing outside a large, beautiful mansion to the south. It towers over you and overhead you can see one of the second floor windows is open. The grass seems a bit wild around here, and the lawn continues west into an overgrown garden. The mansion gate is north."); + SetLong("You are standing outside a large, beautiful mansion " + "that stands south of you. It towers over you and " + "overhead you can see one of the second floor " + "windows is open. The grass seems a bit wild " + "around here, and the lawn continues west into " + "an overgrown garden. The mansion gate is north."); + SetItems( ([ + ({"house","mansion"}) : "A stately pleasure dome.", + ({"window","second floor window"}) : "This is " + "an open window, high above you. If you had a ladder, you " + "might be able to climb up enough to enter.", + ({"grass","lawn","garden"}) : "Rather unkempt " + "greenery. Looks like the gardener's been on " + "vacation.", + ({"gate","mansion gate"}) : "The entry point into " + "the estate on which you now stand." + ]) ); + SetSkyDomain("town"); + SetExits( ([ + "north" : "/domains/town/room/gate", + "west" : "/domains/town/room/garden", + "south" : "/domains/town/room/mansion_int", + ]) ); + SetDoor("south","/domains/town/doors/mansion"); + AddItem(new("/domains/town/obj/lamp")); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/mansion_int.c b/lib/domains/town/room/mansion_int.c new file mode 100644 index 0000000..87881de --- /dev/null +++ b/lib/domains/town/room/mansion_int.c @@ -0,0 +1,30 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Mansion Foyer"); + SetLong("This is the foyer of a grand, majestic mansion. Strangely, " + "there is dust everywhere, but the place looks " + "beautiful all the same. A hallway runs south " + "from here."); + SetItems( ([ + "foyer" : "This is the interior entry area of the " + "mansion, where the front door is.", + ({"hall","hallway"}) : "A wide corridor " + "leading south to the rest of the mansion.", + "dust" : "Tiny particulate material dispersed " + "on visible surfaces." + ]) ); + SetExits( ([ + "north" : "/domains/town/room/mansion_ext", + "south" : "/domains/town/room/mansion_dhall2", + "east" : "/domains/town/room/mansion_room9.c", + ]) ); + SetDoor("north","/domains/town/doors/mansion"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/mansion_mbdroom.c b/lib/domains/town/room/mansion_mbdroom.c new file mode 100644 index 0000000..67fbc0c --- /dev/null +++ b/lib/domains/town/room/mansion_mbdroom.c @@ -0,0 +1,46 @@ +#include <lib.h> +inherit LIB_ROOM; + +int open; +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Mansion Master Bedroom"); + SetLong("You are in the master bedroom. The decor here is " + "beautiful, ornate, and extravagant. It is obvious that " + "the people who live here are rich and possess great " + "taste. "); + SetItems( ([ + "decor" : "Impressive, ornate, and beautiful.", + ]) ); + SetInventory( ([ + "/domains/town/obj/bed" : 1, + "/domains/town/obj/wardrobe" : 1, + ]) ); + SetExits( ([ + "north" : "/domains/town/room/mansion_uhall3" + ]) ); + open = 0; + + SetDoor("north", "/domains/town/doors/m7.c"); + +} +int OpenPassage(){ + string desc; + if(open == 1) return 1; + tell_room(environment(this_player()),"A secret passageway is revealed!"); + open = 1; + desc = GetLong(); + desc += "\n%^MAGENTA%^There is a newly-opened secret passageway here. %^RESET%^"; + SetLong(desc); + AddItem(({"secret passageway","passageway"}) , "A passageway you can enter."); + SetEnters(([ + "passageway" : "/domains/town/room/mansion_room11", + "secret passageway" : "/domains/town/room/mansion_room11" + ]) ); + return 1; +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/mansion_room1.c b/lib/domains/town/room/mansion_room1.c new file mode 100644 index 0000000..9bdfb1a --- /dev/null +++ b/lib/domains/town/room/mansion_room1.c @@ -0,0 +1,31 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Mansion Guest Room East"); + SetLong("You are in the east upstairs guest room of the mansion. " + "The room is sumptuously appointed and furnished. " + "The state of the bed suggests that someone has " + "been staying here recently."); + SetItems( ([ + ({"furniture","furnishings"}) : "Comfortable and attractive." + ]) ); + SetExits( ([ + "west" : "/domains/town/room/mansion_uhall1" + ]) ); + SetInventory(([ + "/domains/town/obj/obag" :1, + "/domains/town/obj/gbed" :1, + "/domains/town/armor/boot_l" :1, + "/domains/town/armor/boot_r" :1, + ]) ); + + SetDoor("west", "/domains/town/doors/m1.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/mansion_room10.c b/lib/domains/town/room/mansion_room10.c new file mode 100644 index 0000000..269d22b --- /dev/null +++ b/lib/domains/town/room/mansion_room10.c @@ -0,0 +1,33 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Dining Room"); + SetLong("This large room is rectangular in shape, " + "and evidently is used as a formal " + "dining room. Beautiful tapestries and " + "paintings decorate the walls, and there " + "is a sense of dignified majesty about " + "this place."); + SetItems( ([ + ({"tapestry","tapestries"}) : "Fascinating " + "tapestries here apear to document the conquest " + "of Anglia by a Norman king.", + ({"painting","paintings"}) : "These are " + "extraordinary oil portraits of renaissance " + "nobility, and they are rendered with an " + "eerily lifelike realism.", + ]) ); + SetInventory( ([ + "/domains/town/obj/dining_table" : 1, + ]) ); + SetExits( ([ + "east" : "/domains/town/room/mansion_dhall2" + ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/mansion_room11.c b/lib/domains/town/room/mansion_room11.c new file mode 100644 index 0000000..215c8fd --- /dev/null +++ b/lib/domains/town/room/mansion_room11.c @@ -0,0 +1,20 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Secret Room"); + SetLong("You are in a small, cramped room."); + SetExits( ([ + "out" : "/domains/town/room/mansion_mbdroom", + "north" : "/domains/town/room/mansion_mbdroom" + ]) ); + SetInventory( ([ + "/domains/town/obj/safe" : 1, + ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/mansion_room12.c b/lib/domains/town/room/mansion_room12.c new file mode 100644 index 0000000..198ffa3 --- /dev/null +++ b/lib/domains/town/room/mansion_room12.c @@ -0,0 +1,41 @@ +#include <lib.h> +inherit LIB_ROOM; + +int CheckQuest(object ob); +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Secret Chamber"); + SetLong("You are in a secret underground chamber beneath the " + "mansion."); + SetExits( ([ + "up" : "/domains/town/room/mansion_room9" + ]) ); + SetObviousExits("up"); + SetInventory( ([ + "/domains/town/obj/chest2" : 1, + ]) ); + SetDoor("up", "/domains/town/doors/trapdoor"); +} +void init(){ + ::init(); + CheckQuest(this_player()); +} +int CheckQuest(object ob){ + string *quests; + quests = ob->GetQuests(); + if(!ob->GetQuest("Newbie Mansion Chamber Quest")){ + ob->AddQuest("the Finder of Hidden Chambers","Newbie Mansion Chamber Quest"); + write("%^BOLD%^%^RED%^\n\nCONGRATULATIONS!\n%^RESET%^"); + write("%^BOLD%^%^RED%^You have solved the secret quest of the "+ + "Hidden Mansion Chamber. You have "+ + "earned 2 quest points, and 1500 experience "+ + "points. Nice job!\n\n%^RESET%^"); + say(this_player()->GetName()+" solves newbie quest 1."); + ob->AddQuestPoints(2); + ob->AddExperiencePoints(1500); + return 1; + } + return 1; +} diff --git a/lib/domains/town/room/mansion_room2.c b/lib/domains/town/room/mansion_room2.c new file mode 100644 index 0000000..9e86aef --- /dev/null +++ b/lib/domains/town/room/mansion_room2.c @@ -0,0 +1,48 @@ +#include <lib.h> +inherit LIB_ROOM; + +int found; +string SearchFun(){ + string result; + if(found == 0){ + object ob = new("/domains/town/obj/safe_key"); + result="You search the room and find a complex key!"; + tell_room(this_object(),this_player()->GetName()+ + " searches the room and finds something ", + ({ this_player() }) ); + if(ob->eventMove(this_player())) + ob->eventMove(this_object()); + found = 1; + return result; + } + return "You find nothing special."; +} +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Mansion Guest Room West"); + SetLong("You are in the west upstairs guest room of the mansion. " + "The room is sumptuously appointed and furnished. " + "It looks as though nobody has dusted here in a " + "very long time. "); + SetExits( ([ + "east" : "/domains/town/room/mansion_uhall1" + ]) ); + SetItems( ([ + ({"here","area","place","room"}) : "A guest room in the mansion.", + "dust" : "There's some dust here, a bit more than one might expect in such a nice place.", + ]) ); + SetInventory(([ + "/domains/town/obj/gbed" : 1, + ]) ); + SetSearch( ([ "default" : (: SearchFun :) ]) ); + found = 0; + + SetDoor("east", "/domains/town/doors/m2.c"); + +} +void init(){ + ::init(); + AddSearch( ({"here","area","place","room"}) , (: SearchFun :) ); +} diff --git a/lib/domains/town/room/mansion_room3.c b/lib/domains/town/room/mansion_room3.c new file mode 100644 index 0000000..f9d616e --- /dev/null +++ b/lib/domains/town/room/mansion_room3.c @@ -0,0 +1,35 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Upstairs Bathroom"); + SetLong("You are in a bathroom. It is rather ordinary, " + "for such a grand mansion, but it appears " + "quite functional and mostly clean. There is " + "a shower stall here you can enter."); + SetItems( ([ + ({"stall","shower stall","shower" }) : "A shower stall.", + ({"sink","bathroom sink" }) : "An ordinary sink.", + ]) ); + SetExits( ([ + "west" : "/domains/town/room/mansion_uhall2" + ]) ); + SetInventory( ([ + "/domains/town/obj/toilet" : 1, + "/domains/town/obj/mat" : 1 + ]) ); + SetEnters( ([ + "stall" : "/domains/town/room/shower", + "shower stall" : "/domains/town/room/shower", + "shower" : "/domains/town/room/shower" + ]) ); + + SetDoor("west", "/domains/town/doors/m3.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/mansion_room4.c b/lib/domains/town/room/mansion_room4.c new file mode 100644 index 0000000..5247153 --- /dev/null +++ b/lib/domains/town/room/mansion_room4.c @@ -0,0 +1,31 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Game room"); + SetLong("You are in the game room. The walls have been paneled " + "in beautiful oak, and the thick carpeting " + "feels quite nice under your feet."); + SetItems( ([ + ({"wall","walls"}) : "It's beautiful oak paneling, " + "with a deep, rich coat of stain.", + ({"carpet","carpeting"}) : "It's plush, soft, and " + "very comfortable." + ]) ); + AddStuff( ({ + "/domains/town/obj/btable", + "/domains/town/obj/pool_table" + }) ); + SetExits( ([ + "east" : "/domains/town/room/mansion_uhall2" + ]) ); + + SetDoor("east", "/domains/town/doors/m4.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/mansion_room5.c b/lib/domains/town/room/mansion_room5.c new file mode 100644 index 0000000..8d04722 --- /dev/null +++ b/lib/domains/town/room/mansion_room5.c @@ -0,0 +1,23 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("The Study"); + SetLong("You are in the study of the master of the house. "+ + "This room is a shambles! It appears to have "+ + "been ransacked in great haste. If there "+ + "ever was anything of value here, it's "+ + "probably long gone."); + SetExits( ([ + "west" : "/domains/town/room/mansion_uhall3" + ]) ); + + SetDoor("west", "/domains/town/doors/m5.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/mansion_room6.c b/lib/domains/town/room/mansion_room6.c new file mode 100644 index 0000000..432f99f --- /dev/null +++ b/lib/domains/town/room/mansion_room6.c @@ -0,0 +1,25 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Servants' Quarters"); + SetLong("You are in the spartan quarters of the on-duty " + "staff. From the lack of personalization, " + "it seems that the servants probably rotate " + "after-hours duty."); + SetInventory( ([ + "/domains/town/obj/cot" :1, + ]) ); + SetExits( ([ + "east" : "/domains/town/room/mansion_uhall3" + ]) ); + + SetDoor("east", "/domains/town/doors/m6.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/mansion_room7.c b/lib/domains/town/room/mansion_room7.c new file mode 100644 index 0000000..88b0cb5 --- /dev/null +++ b/lib/domains/town/room/mansion_room7.c @@ -0,0 +1,24 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("kitchen"); + SetLong("This is a very large kitchen designed to " + "accommodate dozens of cooks. It looks like nobody " + "has prepared a meal here in quite some time."); + SetExits( ([ + "west" : "/domains/town/room/mansion_dhall2.c", + ]) ); + SetInventory( ([ + "/domains/town/obj/rack" : 1, + "/domains/town/obj/stove" : 1, + "/domains/town/npc/rat" : (: random(5)+1 :) , + ]) ); +} + +void init(){ + room::init(); +} diff --git a/lib/domains/town/room/mansion_room8.c b/lib/domains/town/room/mansion_room8.c new file mode 100644 index 0000000..d2edbb6 --- /dev/null +++ b/lib/domains/town/room/mansion_room8.c @@ -0,0 +1,21 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Grand Ballroom"); + SetLong("This huge room is spectacular both in size " + "and decor. Clearly the centerpiece of the mansion, " + "this ballroom could easily accommodate hundreds of " + "guests. The vaulted ceiling is dozens of feet high, and " + "the polished marble floors feature beautiful, " + "dazzling designs."); + SetExits( ([ + "east" : "/domains/town/room/mansion_dhall3" + ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/mansion_room9.c b/lib/domains/town/room/mansion_room9.c new file mode 100644 index 0000000..a69fa63 --- /dev/null +++ b/lib/domains/town/room/mansion_room9.c @@ -0,0 +1,47 @@ +#include <lib.h> +inherit LIB_ROOM; + +int revealed; + +static void create(){ + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Sitting Room"); + SetLong("You are in a luxurious sitting room, decorated " + "and furnished with the same excellent taste and " + "attention to detail as the rest of the " + "mansion."); + SetItems( ([ + ({"furniture","furnishings","decorations"}) : + "You see evidence of a refined aesthetic " + "sensibility." + ]) ); + SetExits( ([ + "west" : "/domains/town/room/mansion_int.c", + ]) ); + SetInventory( ([ + "/domains/town/obj/rug" :1, + "/domains/town/npc/thief" :1 + ]) ); + revealed = 0; +} +int TellRevealed(){ + if(revealed) return revealed; + else return 0; +} +int RevealDoor(){ + if(revealed == 1) { + tell_room(this_object(),"The trapdoor is already visible."); + return 1; + } + revealed = 1; + + tell_room(this_object(),"A trapdoor is revealed!"); + AddExit("down","/domains/town/room/mansion_room12"); + SetDoor("down","/domains/town/doors/trapdoor"); + return 1; +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/mansion_uhall1.c b/lib/domains/town/room/mansion_uhall1.c new file mode 100644 index 0000000..67ffa3a --- /dev/null +++ b/lib/domains/town/room/mansion_uhall1.c @@ -0,0 +1,38 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Upstairs Mansion Hallway North"); + SetLong("You are in the beautifully decorated upstairs " + "hallway of the mansion. There are rooms to " + "the east and west, and the hallway continues " + "south. An open window at the end of the hall " + "leads down."); + SetItems( ([ + ({"window","open window"}) : "An open window here "+ + "leads down to the exterior of the mansion.", + ({"hall","hallway"}) : "A corridor permitting "+ + "travel from one part of the mansion to another." + ]) ); + SetExits( ([ + "down" : "/domains/town/room/mansion_ext", + "south" : "/domains/town/room/mansion_uhall2", + "east" : "/domains/town/room/mansion_room1", + "west" : "/domains/town/room/mansion_room2", + "window" : "/domains/town/room/mansion_ext" + ]) ); + SetEnters( ([ + "window" : "/domains/town/room/mansion_ext" + ]) ); + + SetDoor("east", "/domains/town/doors/m1.c"); + + SetDoor("west", "/domains/town/doors/m2.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/mansion_uhall2.c b/lib/domains/town/room/mansion_uhall2.c new file mode 100644 index 0000000..3fae6f2 --- /dev/null +++ b/lib/domains/town/room/mansion_uhall2.c @@ -0,0 +1,31 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Upstairs Mansion Hallway"); + SetLong("You are in the beautifully decorated upstairs " + "hallway of the mansion. There are rooms to " + "the east and west, and the hallway continues " + "north and south."); + SetItems( ([ + ({"hall","hallway"}) : "A corridor permitting "+ + "travel from one part of the mansion to another." + ]) ); + SetExits( ([ + "south" : "/domains/town/room/mansion_uhall3", + "north" : "/domains/town/room/mansion_uhall1", + "east" : "/domains/town/room/mansion_room3", + "west" : "/domains/town/room/mansion_room4" + ]) ); + + SetDoor("west", "/domains/town/doors/m4.c"); + + SetDoor("east", "/domains/town/doors/m3.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/mansion_uhall3.c b/lib/domains/town/room/mansion_uhall3.c new file mode 100644 index 0000000..6a541af --- /dev/null +++ b/lib/domains/town/room/mansion_uhall3.c @@ -0,0 +1,37 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Upstairs Mansion Hallway South"); + SetLong("You are in the beautifully decorated upstairs " + "hallway of the mansion. There are rooms to " + "the east and west, and the hallway continues " + "north. The master bedroom is south. A large, " + "circular marble staircase leads down to the " + "ground floor."); + SetItems( ([ + ({"hall","hallway"}) : "A corridor permitting "+ + "travel from one part of the mansion to another." + ]) ); + + SetExits( ([ + "south" : "/domains/town/room/mansion_mbdroom", + "north" : "/domains/town/room/mansion_uhall2", + "down" : "/domains/town/room/mansion_dhall3", + "east" : "/domains/town/room/mansion_room5", + "west" : "/domains/town/room/mansion_room6" + ]) ); + + SetDoor("east", "/domains/town/doors/m5.c"); + + SetDoor("west", "/domains/town/doors/m6.c"); + + SetDoor("south", "/domains/town/doors/m7.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/mayor.c b/lib/domains/town/room/mayor.c new file mode 100644 index 0000000..3e277ed --- /dev/null +++ b/lib/domains/town/room/mayor.c @@ -0,0 +1,30 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetTown("town"); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Mayor's office"); + SetLong("This is the rather cramped office of the town's mayor. Despite\na fair amount of clutter, it seems well suited to the mayor's \nworking style and habits."); + SetProperties (([ + "no attack":1, + "no bump":1, + "no steal":0, + "no magic":0, + "no paralyze":0, + "no teleport":0])); + SetItems(([ + "clutter" : "There are papers and folders everywhere, but the stacks and piles seem somehow a well-organized mess." , + ({"mess","stack","stacks","pile","piles","papers","paper","folder","folders"}) : "Evidence of a busy man and strangely-organized mind."])); + SetExits( ([ + "down" : "/domains/town/room/thall", + ]) ); + SetInventory(([ "/domains/town/npc/mayor" : ({60, 1})])); +} +void init() { + ::init(); + SetSmell(([])); + SetListen(([])); +} diff --git a/lib/domains/town/room/mountain_road.c b/lib/domains/town/room/mountain_road.c new file mode 100644 index 0000000..7f03ef2 --- /dev/null +++ b/lib/domains/town/room/mountain_road.c @@ -0,0 +1,37 @@ +#include <terrain_types.h> +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetShort("Fort Road"); + SetNightLong("You are on a road at the northern edge of the village. To the south is the heart of the town. The First Village Bank stands here on the east side of the road. To the west is the post office."); + SetDayLong("You are on a road running north and south. To the south is the heart of the town. To the north the road runs along a narrow ridge, leading up to what looks like a fortress. The First Village Bank stands here on the east side of the road. To the west is the post office."); + SetItems( ([ + ({"rubble","stone","stones","road"}) : "Looks like " + "the road is still being built. Further travel north " + "is impossible.", + ({"mountains","beautiful","snow-capped mountains"}) : "Beautiful " + "mountains, far off in the northern distance." + ]) ); + SetSkyDomain("town"); + SetExits( ([ + "south" : "/domains/town/room/road", + "east" : "/domains/town/room/bank", + "west" : "/domains/town/room/postoffice.c", + ]) ); + if(!strsrch(mud_name(), "Dead Souls")){ + if(directory_exists("/domains/fort")){ + AddExit("north", "/domains/fort/room/f_road4"); + } + } + AddTerrainType(T_ROAD); + AddItem(new("/domains/town/obj/lamp")); + if(file_exists("/domains/fort/room/f_road4.c")){ + } +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/narrow_path.c b/lib/domains/town/room/narrow_path.c new file mode 100644 index 0000000..4288420 --- /dev/null +++ b/lib/domains/town/room/narrow_path.c @@ -0,0 +1,30 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetShort("a narrow path"); + SetLong("This is a narrow path running northeast to a green valley and south through a dense forest. The thick vegetation makes travel off the path impossible."); + SetItems(([ + ({ "path", "trail" }) : "A very narrow path that seems threatened all around by the looming woods. It's hard to imagine what force might have cut this thin trail into the vegetation here.", + ({ "forest", "wood", "vegetation" }) : "All around is vegetation growing so incredibly dense that it is impossible to wander off the path.", + ])); + SetSkyDomain("town"); + SetExits( ([ + "northeast" : "/domains/town/room/valley", + "south" : "/domains/town/room/narrow_path2.c", + ]) ); + SetInventory(([ + ])); + +} +void init(){ + ::init(); +} + +int CanReceive(object ob){ + if(answers_to("provost",ob)) return 0; + return ::CanReceive(); +} diff --git a/lib/domains/town/room/narrow_path2.c b/lib/domains/town/room/narrow_path2.c new file mode 100644 index 0000000..36ac472 --- /dev/null +++ b/lib/domains/town/room/narrow_path2.c @@ -0,0 +1,31 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetShort("a narrow path"); + SetLong("This is a narrow path running north and south through a dense forest. The thick vegetation makes travel off the path impossible."); + SetItems(([ + ({ "path", "trail" }) : "A very narrow path that seems threatened all around by the looming woods. It's hard to imagine what force might have cut this thin trail into the vegetation here.", + ({ "forest", "wood", "vegetation" }) : "All around is vegetation growing so incredibly dense that it is impossible to wander off the path.", + ])); + SetSkyDomain("town"); + SetExits( ([ + "north" : "/domains/town/room/narrow_path", + "south" : "/domains/town/room/cratshack.c", + ]) ); + + SetInventory(([ + ])); + +} +void init(){ + ::init(); +} + +int CanReceive(object ob){ + if(answers_to("provost",ob)) return 0; + return ::CanReceive(); +} diff --git a/lib/domains/town/room/orc_fortress.c b/lib/domains/town/room/orc_fortress.c new file mode 100644 index 0000000..e64308d --- /dev/null +++ b/lib/domains/town/room/orc_fortress.c @@ -0,0 +1,23 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(15); + SetShort("The Orc Fortress"); + SetLong("You find yourself in the entrance of the local orc stronghold. This place seems quite hostile to normal sensibilities, as the construction is rough, inelegant, and the upkeep is squalid. This wooden fort also appears somewhat amateurishly put together, as if done by youngsters playing at being soldiers. There is an exit to the outside south of here, and another room is visible to the west."); + SetExits( ([ + "south" : "/domains/town/room/valley", + "west" : "/domains/town/room/orc_temple.c", + ]) ); + SetSmell( ([ "default" : "The stench of garbage and animal waste hangs here."]) ); + SetInventory(([ + "/domains/town/npc/orc" : 1, + "/domains/town/npc/orc2" : 1, + "/domains/town/npc/orc_boss" : 1, + ])); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/orc_temple.c b/lib/domains/town/room/orc_temple.c new file mode 100644 index 0000000..21e8e6c --- /dev/null +++ b/lib/domains/town/room/orc_temple.c @@ -0,0 +1,34 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(15); + SetShort("The Orc Fortress"); + SetLong("You are deep in the orc stronghold. Like the rest of the fortress you have seen, this looks hastily put together and rather clumsily built, with poor maintenance besides. This is some kind of ceremonial chamber or temple. Dried blood surrounds a raised altar, and skulls of various types adorn the walls. The rest of the fort is east of here."); + SetItems(([ + ({ "skull","skulls" }) : "You see some skulls whose race you "+ + "recognize, but most you don't. There is at least one "+ + "human skull here. Some of them are so fresh they are "+ + "still wet and have tissue hanging from them.", + ({"chamber","ceremonial chamber","temple"}) : "A place "+ + "where orcish rituals are performed.", + ({"blood","dried blood"}) : "Evidently the ground around "+ + "the altar has collected blood from whatever happens on "+ + "the altar.", + ({"wall","walls"}) : "Rough-hewn walls of earth and wood.", + ]) ); + SetExits( ([ + "east" : "/domains/town/room/orc_fortress", + ]) ); + SetSmell( ([ "default" : "The stench of garbage and animal waste hangs here."]) ); + SetInventory(([ + "/domains/town/obj/altar" : 1, + "/domains/town/npc/orc_shaman" : 1, + ])); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/porch.c b/lib/domains/town/room/porch.c new file mode 100644 index 0000000..0384b34 --- /dev/null +++ b/lib/domains/town/room/porch.c @@ -0,0 +1,34 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetShort("front porch"); + SetLong("This is the rickety front porch of an old house. The front door is south. To the north is a clearing in the woods, and a path leading away."); + SetItems(([ + ({ "forest", "wood", "vegetation" }) : "All around is vegetation growing so incredibly dense that it is impossible to wander off the path.", + ({ "porch", "front porch" }) : "The wooden front porch of an old white house.", + ({ "trail", "path" }) : "To the north, a narrow path leads into the woods.", + ({ "clearing", "woods" }) : "As if by powerful magic, the woods clear here, where the house stands.", + ({ "house", "white house", "old house" }) : "The house looks weatherbeaten, ill maintained, and rather old. Its construction is of an archaic design no longer used. Despite its abused appearance, the house seems to have a quiet dignity about it, as if many people had been its friends over the years, and it simply waited for their return.", + ])); + SetInventory(([ + "/domains/town/obj/rocking_chair" : 2, + ])); + SetExits( ([ + "north" : "/domains/town/room/cratshack", + "south" : "/domains/town/room/living_room.c", + ]) ); + + SetDoor("south", "/domains/town/doors/house_door.c"); + +} +void init(){ + ::init(); +} +int CanReceive(object ob){ + if(answers_to("provost",ob)) return 0; + return ::CanReceive(); +} diff --git a/lib/domains/town/room/postoffice.c b/lib/domains/town/room/postoffice.c new file mode 100644 index 0000000..1008fe9 --- /dev/null +++ b/lib/domains/town/room/postoffice.c @@ -0,0 +1,78 @@ +#include <lib.h> +#include <objects.h> +#include <post.h> +#include "/lib/include/post_office.h" + +inherit LIB_ROOM; + +static void create(){ + room::create(); + SetTown("Town"); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("the town post office"); + SetLong("This is a small office containing rows of mailboxes and "+ + "various other postal implements. There is a sign on the wall behind the "+ + "counter, outlining instructions for how to mail other users. "+ + "Fort road is east of here."); + SetItems( ([ + ({"box","boxes","mailboxes","mailbox"}) : "Rows of mailboxes for "+ + "the denizens of Frontiers.", + "sign" : "This is a sign on the wall describing how to mail messages.", + ({"wall","walls"}) : "Gray-painted institutional walls of the kind you'd "+ + "expect in a post office.", + "implements" : "Ink, paper, etc.", + "instructions" : "Try reading them.", + "counter" : "A counter folks use to lean on while writing messages." ]) ); + SetExits( ([ + "east" : "/domains/town/room/mountain_road.c", + ]) ); + SetProperty("no attack", 1); +} +void init(){ + ::init(); + add_action("instr","read"); +} +int instr(string str){ + if(str=="instructions"||str=="sign"){ + write("To mail someone, type mail <person's name here>.\n"+ + "Enter a subject line.\n"+ + "Enter your message.\n"+ + "Once you've finished, enter a period (.) on a blank line.\n"+ + "Hit x, then s to send it. You're done!\n"); + return 1; + } +} +mixed CanMail(object who, string args) { + if( !interactive(who) ) return 0; + if( GetTown() != who->GetTown() ) + return "Any mail you might have will be at your home post office."; + return 1; +} +mixed eventMail(object who, string args) { + object ob; + + if( !(ob = new(OBJ_POST)) ) { + who->eventPrint("Failed to load postal object!"); + return 1; + } + if( !(ob->eventMove(who)) ) { + who->eventPrint("You can't seem to carry the postal object."); + return 1; + } + ob->start_post(args); + return 1; +} +int CanReceive(object ob) { + if( !ob && !(ob = previous_object()) ) return 0; + if( living(ob) && !interactive(ob) ) return 0; + else return room::CanReceive(ob); +} +int eventReleaseObject() { + object ob; + + if( !(ob = previous_object()) ) return room::eventReleaseObject(); + if( !room::eventReleaseObject() ) return 0; + if( (ob = present(POSTAL_ID, ob)) ) ob->eventDestruct(); + return 1; +} diff --git a/lib/domains/town/room/riverbank.c b/lib/domains/town/room/riverbank.c new file mode 100644 index 0000000..3b34da5 --- /dev/null +++ b/lib/domains/town/room/riverbank.c @@ -0,0 +1,45 @@ +#include <lib.h> +inherit LIB_FISHING; + +static void create() { + ::create(); + SetTown("town"); + SetClimate("temperate"); + SetAmbientLight(30); + SetShort("riverbank"); + SetLong("This is the bank of a narrow but swift-moving river. A steep path leads back up to the bridge. There is a cave in the steep east wall of the riverbank."); + SetProperties (([ + "no attack":0, + "no bump":0, + "no steal":0, + "no magic":0, + "no paralyze":0, + "no teleport":0])); + SetListen(([ + ({ "river", "water" }) : "You hear it rushing by.", + "default" : "You can hear the roar of the river rushing by.", + ])); + SetInventory(([ + "/domains/town/npc/troll" : 1, + "/domains/town/obj/rocks" : 1, + "/domains/town/obj/riverwater" : 1, + ])); + AddExit("up", "/domains/town/room/bridge"); + if(unguarded( (: file_exists("/domains/cave/room/cave.c") :) ) ){ + AddExit("east", "/domains/cave/room/cave"); + } + SetChance(90); + SetFish( ([ + "/domains/town/meals/shark" : 10, + "/domains/town/meals/herring" : 20, + ]) ); +} +void init() { + ::init(); + SetSmell(([])); +} + +int CanReceive(object ob){ + if(answers_to("provost",ob)) return 0; + return ::CanReceive(); +} diff --git a/lib/domains/town/room/road.c b/lib/domains/town/room/road.c new file mode 100644 index 0000000..1997e41 --- /dev/null +++ b/lib/domains/town/room/road.c @@ -0,0 +1,47 @@ +#include <terrain_types.h> +#include <lib.h> +inherit LIB_ROOM; +static void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetShort("North Saquivor Road"); + SetNightLong("Illuminated by lamplight here is Saquivor road, leading north-south through the village. To the east is the village pub, the legendary watering hole used by thousands of rogues, paladins, and everyone in between. To the west is a building marked HEALER. To the south is a major intersection. The road continues north into the gloom."); + SetDayLong("You are on Saquivor road, leading north-south through the village. To the east is the village pub, the legendary watering hole used by thousands of rogues, paladins, and everyone in between. The Healers' Guild is west, and to the north you can see a road leading up to the plateau where the Fortress on the Frontiers stands. To the south is a major intersection."); + SetItems( ([ + ({"pub","tavern","village pub"}) : "The is the town's " + "legendary watering hole, where refreshments are served " + "and tall tales are swapped.", + ({"guild","healers guild"}) : "In this building is " + "the office of the only doctor in town.", + "clouds" : "Little puffy clouds surround the " + "peaks of the northern mountains.", + ({"northern mountains","mountains","range","mountain range"}): + "Majestic mountains are far to the north, seeming " + "almost purple from here.", + "intersection" : "The main town crossroads is south." + ]) ); + SetSkyDomain("town"); + SetInventory(([ + "/domains/town/weap/knife" : 1, + ])); + SetExits( ([ + "north" : "/domains/town/room/mountain_road", + "east" : "/domains/town/room/tavern", + "west" : "/domains/town/room/healer", + "south" : "/domains/town/room/road0.c", + ]) ); + AddTerrainType(T_ROAD); + + SetEnters( ([ + "pub" : "/domains/town/room/tavern", + "guild" : "/domains/town/room/healer", + "healers guild" : "/domains/town/room/healer" + ]) ); + SetNoModify(0); + AddItem(new("/domains/town/obj/lamp")); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/road0.c b/lib/domains/town/room/road0.c new file mode 100644 index 0000000..74135f4 --- /dev/null +++ b/lib/domains/town/room/road0.c @@ -0,0 +1,41 @@ +#include <terrain_types.h> +#include <lib.h> +inherit LIB_ROOM; +static void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetShort("Saquivor Road"); + SetNightLong("Illuminated by lamplight here is Saquivor road, leading north-south through the village. The road continues north toward some buildings, and south toward an intersection."); + SetDayLong("This is Saquivor road, leading north-south through the village. A bit further north are what look like a pub and some kind of guild. To the south is a major intersection."); + SetItems( ([ + ({"pub","tavern","village pub"}) : "The is the town's " + "legendary watering hole, where refreshments are served " + "and tall tales are swapped.", + ({"guild","healers guild"}) : "In this building is " + "the office of the only doctor in town.", + "clouds" : "Little puffy clouds surround the " + "peaks of the northern mountains.", + ({"northern mountains","mountains","range","mountain range"}): + "Majestic mountains are far to the north, seeming " + "almost purple from here.", + "intersection" : "The main town crossroads is south." + ]) ); + SetSkyDomain("town"); + SetInventory(([ + "/domains/town/npc/beggar" : 1, + ])); + SetExits( ([ + "north" : "/domains/town/room/road", + "south" : "/domains/town/room/start.c", + ]) ); + + AddTerrainType(T_ROAD); + + SetNoModify(0); + AddItem(new("/domains/town/obj/lamp")); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/road1.c b/lib/domains/town/room/road1.c new file mode 100644 index 0000000..bdc64a6 --- /dev/null +++ b/lib/domains/town/room/road1.c @@ -0,0 +1,23 @@ +#include <terrain_types.h> +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetShort("West Village road"); + SetDayLong("This is a well-traveled road, leading east into town and west away from it. The town church is north."); + SetSkyDomain("town"); + SetExits( ([ + "north" : "/domains/town/room/church", + "east" : "/domains/town/room/start", + "west" : "/domains/town/room/road2", + ]) ); + SetNightLong("This is a well-traveled road, illuminated by a lamp light. It leads east into town and west away from it. The town church is north."); + AddTerrainType(T_ROAD); + AddItem(new("/domains/town/obj/lamp")); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/road2.c b/lib/domains/town/room/road2.c new file mode 100644 index 0000000..c585a27 --- /dev/null +++ b/lib/domains/town/room/road2.c @@ -0,0 +1,31 @@ +#include <terrain_types.h> +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetShort("West Village road"); + SetNightLong("This is a well-traveled road, illuminated by a lamp light. It leads east into town and west toward an old, humpbacked bridge. A grand mansion is south."); + SetDayLong("This is a well-traveled road, leading east into town and west away from it. An old, humpbacked bridge is west of here. A grand mansion is south."); + SetItems(([ + ({ "fort", "fortress", "fortress in the distance" }) : "It can't be seen well from here, but far north is what appears to be a large fortress built on a high plateau.", + ({ "road", "roads" }) : "This is a simple east-west road that goes east into town and west away from it. Another road, paved with cobblestones, intersects here to the north and leads high toward a fortress in the distance.", + "cobblestone road" : "This is where a cobblestone road begins that is built on an steep incline and rises up as it leads north to a high plateau.", + ])); + SetSkyDomain("town"); + SetExits( ([ + "east" : "/domains/town/room/road1", + "west" : "/domains/town/room/bridge", + "south" : "/domains/town/room/gate.c", + ]) ); + AddTerrainType(T_ROAD); + AddItem(new("/domains/town/obj/lamp")); +} + +void init(){ + ::init(); + if(mud_name() == "Dead Souls Omega" && !GetExit("north")){ + } +} diff --git a/lib/domains/town/room/room2.c b/lib/domains/town/room/room2.c new file mode 100644 index 0000000..43e3af3 --- /dev/null +++ b/lib/domains/town/room/room2.c @@ -0,0 +1,13 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetShort("a generic place"); + SetLong("This is an utterly plain, blank place."); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/school.c b/lib/domains/town/room/school.c new file mode 100644 index 0000000..a30b50c --- /dev/null +++ b/lib/domains/town/room/school.c @@ -0,0 +1,31 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetTown("town"); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Village Schoolhouse"); + SetLong("This simple, one-room schoolhouse is not especially large but it is clean, well-maintained, and clearly an important part of village life. People come here to be taught, mostly languages, by traveling teachers and guest lecturers."); + SetProperties (([ + "no attack":1, + "no bump":1, + "no steal":0, + "no magic":0, + "no paralyze":0, + "no teleport":0])); + SetItems(([])); + SetInventory(([ + "/domains/town/npc/bugg" : ({60, 1}), + ])); + SetExits(([ + "south" : "/domains/town/room/vill_road4", + ])); + +} +void init() { + ::init(); + SetSmell(([])); + SetListen(([])); +} diff --git a/lib/domains/town/room/secret.c b/lib/domains/town/room/secret.c new file mode 100644 index 0000000..346443f --- /dev/null +++ b/lib/domains/town/room/secret.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(0); + SetShort("the secret stash"); + SetLong("This appears to be a secret room for saving valuables. The "+ + "master bedroom is west."); + SetExits( ([ "west" : "/domains/town/room/mansion_mbdroom" ]) ); + SetNoClean(1); + SetPersistent(1); + RestoreObject(); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/shack.c b/lib/domains/town/room/shack.c new file mode 100644 index 0000000..f48a241 --- /dev/null +++ b/lib/domains/town/room/shack.c @@ -0,0 +1,25 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(25); + SetShort("Gardener's Shack"); + SetLong("This is the dark, wooden shack of the keeper " + "of the garden. From the dust and rust, " + "it is obvious nobody has done much gardening " + "around here lately."); + SetExits( ([ + "south" : "/domains/town/room/garden", + "out" : "/domains/town/room/garden.c", + ]) ); + SetInventory(([ + "/domains/town/obj/rayovac" : 1, + "/domains/town/obj/ladder" : 1, + ]) ); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/shop.c b/lib/domains/town/room/shop.c new file mode 100644 index 0000000..ea2379b --- /dev/null +++ b/lib/domains/town/room/shop.c @@ -0,0 +1,40 @@ +#include <lib.h> +inherit LIB_SHOP; + +int read_sign(); +static void create() { + ::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("The General Store"); + SetLong("This is the local general store. You can buy or sell items here. A sign on the wall hangs here, explaining how things work. Try 'read sign'. East Village Road is south of here. The storeroom is below."); + SetItems(([ + ({"store","shop","place"}) : "This is the local store.", + ({ "sign" ,"sign on the wall" }): "A sign on the wall, meant for reading.", + ])); + SetExits( ([ + "south" : "/domains/town/room/vill_road2", + "down" : "/domains/town/room/shop2.c", + ]) ); + SetInventory(([ + "/domains/town/obj/bbucket" : 1, + "/domains/town/npc/otik" : ({60, 1}), + ])); + SetRead("sign", (: read_sign :) ); + + SetDoor("down", "/domains/town/doors/otik_d.c"); + +} +int read_sign(){ + write("HOW TO CONDUCT BUSINESS HERE\n"); + write("list : Get a list of all the items Otik has for sale"); + write("appraise <item> : Ask Otik to tell you how much he would pay you for your item"); + write("price <item> : Ask Otik the price of his item"); + write("show <item> : Ask Otik for a closer look at his item\n"); + write("\nbuy <item> from otik\nsell <item> to otik\n"); + write("Cash only!"); + return 1; +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/shop2.c b/lib/domains/town/room/shop2.c new file mode 100644 index 0000000..253ae51 --- /dev/null +++ b/lib/domains/town/room/shop2.c @@ -0,0 +1,50 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Otik's storage room"); + SetLong("This is a small, bare room where Otik keeps his goods. The main store is above."); + SetInventory(([ + "/domains/town/weap/sword" : 30, + "/domains/town/obj/rucksack" : 10, + "/domains/town/obj/rayovac" : 10, + "/domains/town/obj/watch" : 10, + "/domains/town/armor/chainmail" : 3, + "/domains/town/weap/verysharpsword" : 2, + "/domains/town/obj/dcell_std" : 30, + "/domains/town/obj/flask" : 10, + "/domains/town/obj/match" : 15, + "/domains/town/obj/torch" : 15, + "/domains/town/armor/helmet" : 3, + "/domains/town/weap/dagger" : 30, + "/domains/town/obj/pack" : 10, + "/domains/town/obj/ladder" : 2, + "/domains/town/obj/maglite" : 3, + "/domains/town/obj/canteen" : 5, + ])); + SetExits( ([ + "up" : "/domains/town/room/shop", + ]) ); + SetNoClean(1); + + SetDoor("up", "/domains/town/doors/otik_d.c"); + +} +int CanReceive(object sneak) { + object *living_stack = get_livings(sneak); + if(!living_stack || !arrayp(living_stack)) living_stack = ({ sneak }); + foreach(object ob in living_stack){ + if(living(ob) && !creatorp(ob) && + !member_group(ob,"TEST")) { + message("info","Otik's back room is for authorized personnel only.", ob); + return 0; + } + } + return 1; +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/shore.c b/lib/domains/town/room/shore.c new file mode 100644 index 0000000..2209f3c --- /dev/null +++ b/lib/domains/town/room/shore.c @@ -0,0 +1,105 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_FISHING; + +int ActionFunction(){ + object *cres, dude; + if(!sizeof(get_livings(this_object()))) return 0; + //The next line identifies creators in the room + cres = filter(get_livings(this_object()), (: creatorp($1) :) ); + //The next line picks a living being here at random + dude = get_random_living(this_object()); + if(!dude) return 0; + if((RACES_D->GetNonMeatRace(dude->GetRace()))) return 0; + //The next line makes that person sigh. Note that since + //creators normally can't be forced by non-privileged objects, + //only npc's and players will be affected. + dude->eventForce("sigh"); + //The next line tells any creators present the identitiy of the + //target of the previous action. + if(!sizeof(cres)) return 0; + //The action below is commented out because it confused people. + //basically it tells creators about this function. + //cres->eventPrint("%^YELLOW%^The ActionFunction activates. Dude is: "+ + // identify(dude)+".%^RESET%^"); + return 1; +} + +varargs string readSign() { + string ret = "WARNING! Orcs, dwarves, and some other races cannot "+ + "swim! If you jump into the sea you will sink and drown!"; + return ret; +} + +int ActionFunction2(){ + object *cres, dude; + if(!sizeof(get_livings(this_object()))) return 0; + cres = filter(get_livings(this_object()), (: creatorp($1) :) ); + dude = get_random_living(this_object()); + if(!dude) return 0; + if((RACES_D->GetNonMeatRace(dude->GetRace()))) return 0; + dude->eventForce("ponder"); + if(!sizeof(cres)) return 0; + //The action below is commented out because it confused people. + //basically it tells creators about this function. + //cres->eventPrint("%^GREEN%^ActionFunction2 activates. Dude is: "+ + // identify(dude)+".%^RESET%^"); + return 1; +} + +static void create() { + fishing::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetShort("Shore Edge"); + SetNightLong("You are on the shore, at the far eastern end of town. A road travels west into the heart of town. A great sea stretches out into the eastern horizon. A lone lamp post lights this area. \n%^GREEN%^There is a sign here you can read.%^RESET%^"); + SetDayLong("You are on the shore, at the far eastern end of town. A road travels west into the heart of town. A great sea stretches out into the eastern horizon. \n%^GREEN%^There is a sign here you can read.%^RESET%^"); + SetItems( ([ + "sign":"A sign on the ground. To read it, 'read sign'.", + "ground":"The local surface.", + "horizon":"Where the sky loves the sea.", + "town":"A population center to the west.", + "road":"Leads west, to the town.", + ]) ); + SetExits( ([ + "west" : "/domains/town/room/vill_road4", + "south" : "/domains/town/room/docks.c", + ]) ); + SetRead("sign", (: readSign :) ); + //SetFrequency determines how often the room checks + //whether it should perform an action. If it is set + //at 1, it checks approximately every second. The + //default is 5. + SetFrequency(5); + //The first argument of SetAction is a number, indicating from + //one to 100 the percentage of likelihood an event will occur. + //The second argument is an array that contains strings, + //functions, or both. Every time an action is triggered, an + //element is picked from the array at random. If it is a string, + //that string is displayed to the living things in the room. + //If it is a function, that function is evaluated. + SetAction(2, ({"A cool breeze flows in from the east, " + "bringing with it the bracing salty smells of the sea.", + (: ActionFunction :) }) ); + SetChance(90); + SetFish( ([ + "/domains/town/meals/shark" : 1, + "/domains/town/meals/herring" : 10, + ]) ); + //This is a function that allows for a set of actions + //with different trigger frequencies. + SetActionsMap( ([ + "A soft breeze cools your brow." : 5, + "You briefly hear seagulls far in the distance." : 7, + (: ActionFunction2 :) : 2, + ]) ); + SetInventory( ([ + "/domains/town/obj/seawater" : 1, + ]) ); + AddItem(new("/domains/town/obj/lamp")); + SetSkyDomain("town"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/shower.c b/lib/domains/town/room/shower.c new file mode 100644 index 0000000..549a517 --- /dev/null +++ b/lib/domains/town/room/shower.c @@ -0,0 +1,18 @@ +#include <lib.h> +inherit LIB_ROOM; +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Shower Stall"); + SetLong("You are standing in a shower stall. People come " + "here to get clean."); + SetExits( ([ + "out" : "/domains/town/room/mansion_room3" + ]) ); + SetObviousExits("out"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/source.c b/lib/domains/town/room/source.c new file mode 100644 index 0000000..d9eca4e --- /dev/null +++ b/lib/domains/town/room/source.c @@ -0,0 +1,33 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(0); + SetShort("a dark tunnel"); + SetLong("This tunnel has very smooth stone walls and leads east. There is also an opening in the ceiling above."); + SetItems(([ + ({ "hole", "holes", "floor" }) : "These holes appear to be where spring water enters to flood the chamber and fill the well east of here. ", + ({ "dirt", "dust" }) : "There's plenty of that here. Empty wells rarely get much priority on cleaning day.", + ({ "bottom", "well" }) : "Dirty, musty, and unpleasant.", + ({ "vermin", "rats", "bugs" }) : "Looks like they're hiding from you at the moment.", + "haven" : "A nice place for vermin.", + ({ "rock", "bedrock" }) : "This is dense, hard stuff deep underground.", + ])); + SetFlowLimit(40); + SetInventory( ([ + "/domains/town/obj/water_pipe" : 1, + "/domains/town/obj/waterwheel" : 1, + ]) ); + SetExits( ([ + "up" : "/domains/town/room/well3", + "east" : "/domains/town/room/wtunnel2.c", + ]) ); + + SetDoor("up", "/domains/town/doors/grate.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/south_road1.c b/lib/domains/town/room/south_road1.c new file mode 100644 index 0000000..c1e9891 --- /dev/null +++ b/lib/domains/town/room/south_road1.c @@ -0,0 +1,43 @@ +#include <terrain_types.h> +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetShort("Saquivor Road"); + SetLong("This is a cobblestone road, leading "+ + "north into town. "+ + "The magic "+ + "shop is to the west. "+ + "\n%^GREEN%^An old well stands by the "+ + "side of the road.%^RESET%^"); + SetItems( ([ + ({"well","old well","dry well"}) : "This " + "looks like the sort of system used to " + "provide water before the town implemented " + "more modern waterworks. It looks long dry " + "and abandoned.", + "bank" : "The First Village Bank", + ({"road","cobblestone road"}) : "A " + "cobblestone road running north and south." + ]) ); + SetSkyDomain("town"); + SetExits( ([ + "north" : "/domains/town/room/start", + "west" : "/domains/town/room/magic_shop", + ]) ); + if(strsrch(mud_name(), "Dead Souls")){ + //AddExit("south", "/domains/campus/room/south_road2"); + } + AddTerrainType(T_ROAD); + SetNoModify(0); + SetEnters( ([ + "well" : "/domains/town/room/well1" + ]) ); + AddItem(new("/domains/town/obj/lamp")); +} +void init(){ + room::init(); +} diff --git a/lib/domains/town/room/stables.c b/lib/domains/town/room/stables.c new file mode 100644 index 0000000..bc89f82 --- /dev/null +++ b/lib/domains/town/room/stables.c @@ -0,0 +1,31 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Village Stables"); + SetLong("These are the village stables. Townsfolk come here and leave their mounts in the care of Ingrid, the local horse girl. The place is orderly, if a bit stinky, and it's clear Ingrid runs a professional outfit."); + SetItems(([ + ({ "building", "schoolhouse", "school", "village school", "village schoolhouse" }) : "A small but well-kept wooden building where townsfolk and their children go to acquire knowledge.", + ({ "building", "buildings" }) : "Structures designed for human occupancy.", + ])); + SetProperties(([ + "no attack" : 1, + ])); + SetInventory(([ + "/domains/town/npc/ingrid" : 1, + "/domains/town/npc/horse" : 1, + ])); + SetExits(([ + "north" : "/domains/town/room/vill_road4", + ])); + + SetEnters( ([ + ]) ); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/start.c b/lib/domains/town/room/start.c new file mode 100644 index 0000000..73d98ee --- /dev/null +++ b/lib/domains/town/room/start.c @@ -0,0 +1,40 @@ +#include <terrain_types.h> +#include <lib.h> +inherit LIB_ROOM; + +int readSign() { + this_player()->more("/domains/town/txt/hints_sign.txt"); + return 1; +} + +static void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetShort("Village Road Intersection"); + SetNightLong("You are in the main intersection of the village, lit by a town lamp post. Saquivor road extends north and south, intersected east to west by a road that leads west toward a wilderness, and east toward shore.\n%^GREEN%^There is a sign here you can read.%^RESET%^"); + SetDayLong("You are in the main intersection of the village. Saquivor road extends north and south, intersected east to west by a road that leads west toward a wilderness, and east toward shore.\n%^GREEN%^There is a sign here you can read.%^RESET%^"); + SetItems( ([ + "sign":"A large sign on the road. To read it, 'read sign'.", + ]) ); + SetSkyDomain("town"); + SetExits( ([ + "south" : "/domains/town/room/south_road1", + "east" : "/domains/town/room/vill_road2", + "west" : "/domains/town/room/road1", + "north" : "/domains/town/room/road0.c", + ]) ); + AddTerrainType(T_ROAD); + SetNoModify(0); + SetInventory(([ + "/domains/town/obj/clocktower" : 1, + ])); + SetEnters( ([ + ]) ); + SetRead("sign", (: readSign :) ); + AddItem(new("/domains/town/obj/lamp")); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/tavern.c b/lib/domains/town/room/tavern.c new file mode 100644 index 0000000..bd1c375 --- /dev/null +++ b/lib/domains/town/room/tavern.c @@ -0,0 +1,35 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + ::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("The Local Tavern"); + SetLong("You are in the local pub. You can order drinks and a sandwich here:\n\n"+ + "\tFirst class ale:\t\t\t\t10 silver\n" + "\tSpecial of the house:\t\t\t\t20 silver\n" + "\tFirebreather:\t\t\t\t\t50 silver\n" + "\tSpring water:\t\t\t\t\t2 silver\n" + "\tRegular coffee:\t\t\t\t\t5 silver\n" + "\tImported espresso:\t\t\t\t15 silver\n" + "\tHam sandwich:\t\t\t\t\t10 silver\n\n\n" + "To order a bottle of water, \"buy water from lars\"\n" + "\nThere is a framed portrait on the wall.\n" + ); + SetItems(([ + ({ "portrait", "framed portrait", "frame", "picture" }) : "It is a dramatic portrait of an ancient dragon of immense beauty and grace. It is titled \"Daelas: Heir of Arodaleas\".", + ])); + SetInventory(([ + "/domains/town/obj/btable" : 1, + "/domains/town/obj/bbucket" :1, + "/domains/town/npc/lars" : ({ 60, 1}) + ]) ); + SetExits( ([ + "west" : "/domains/town/room/road", + "out" : "/domains/town/room/road", + ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/thall.c b/lib/domains/town/room/thall.c new file mode 100644 index 0000000..f09006b --- /dev/null +++ b/lib/domains/town/room/thall.c @@ -0,0 +1,32 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetTown("town"); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Town Hall"); + SetLong("This is the modest foyer of this village's Town Hall. It's a simple affair, really, in keeping with the down-to-earth spirit of the town. The office of the clerk and notary is north, and the Mayor's office is upstairs. Village road is south. The registrar of voters is northeast."); + SetProperties (([ + "no attack":1, + "no bump":1, + "no steal":0, + "no magic":0, + "no paralyze":0, + "no teleport":0])); + SetItems(([])); + SetExits( ([ + "south" : "/domains/town/room/vill_road3", + "northeast" : "/domains/town/room/voters", + "up" : "/domains/town/room/mayor", + "north" : "/domains/town/room/clerk.c", + ]) ); + SetInventory(([])); + +} +void init() { + ::init(); + SetSmell(([])); + SetListen(([])); +} diff --git a/lib/domains/town/room/training.c b/lib/domains/town/room/training.c new file mode 100644 index 0000000..0e6d2a2 --- /dev/null +++ b/lib/domains/town/room/training.c @@ -0,0 +1,29 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("the training area"); + SetLong("You are in a large room with a very high ceiling, mirrored walls, and a hardwood floor. This area is designed for skills training, though at the moment no workshops are scheduled. The rest of the Adventurers' Guild is downstairs."); + SetItems( ([ + ({"wall","walls"}) : "The walls have mirrors set into them.", + ({"mirror","mirrors"}) : "Peekaboo!", + ({"hardwoord floor", "floor"}) : "The floor is made of polished wood, and is "+ + "reminiscent of what you might expect in a dancing school.", + ({"ceiling","high ceiling"}) : "The high, vaulted ceiling "+ + "provides plenty of headroom." + ]) ); + SetExits( ([ + "down" : "/domains/town/room/adv_guild", + ]) ); + SetInventory(([ + "/domains/town/npc/radagast" : ({60, 1}), + "/domains/town/obj/bbucket" : 1, + ])); + SetPlayerKill(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/valley.c b/lib/domains/town/room/valley.c new file mode 100644 index 0000000..174b4a5 --- /dev/null +++ b/lib/domains/town/room/valley.c @@ -0,0 +1,33 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetNightLight(10); + SetDayLight(30); + SetShort("Orc Valley"); + SetLong("You are in a small valley below the sheer cliffs to the west. A band of orcs appears to have made this place their home, and you can see their ramshackle fortress toward the north. A well-traveled path leads east into a forest. A narrow path snakes its way southwest into the woods."); + SetSkyDomain("town"); + SetExits( ([ + "east" : "/domains/town/room/clearing", + "north" : "/domains/town/room/orc_fortress", + "southwest" : "/domains/town/room/narrow_path.c", + ]) ); + SetInventory(([ + "/domains/town/npc/orc" : 1, + "/domains/town/npc/orc2" : 1, + ]) ); +} + +void init(){ + ::init(); +} + +int clean_up(int ref_exists){ + return ::clean_up(); +} + +void reset(){ +} diff --git a/lib/domains/town/room/vill_road2.c b/lib/domains/town/room/vill_road2.c new file mode 100644 index 0000000..646131b --- /dev/null +++ b/lib/domains/town/room/vill_road2.c @@ -0,0 +1,37 @@ +#include <terrain_types.h> +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetShort("East Village Road"); + SetNightLong("You are on a long road, lit by a lamp post. The general store is north. The road stretches east and west through the town. The Adventurers' Guild is south."); + SetDayLong("You are on a long road. The general store is north. The road stretches east and west through the town. The Adventurers' Guild is south."); + SetItems( ([ + ({"adventurers guild","guild"}) : "This small " + "building on the southern side of the road is where " + "adventurers, great and small, come to record " + "their exploits and seek advancement.", + ({"shop","store","general store"}) : "This is the " + "general store, where almost anything can be " + "bought or sold.", + ({"road","long road"}) : "An east-west cobblestone " + "road through town.", + ]) ); + SetSkyDomain("town"); + AddTerrainType(T_ROAD); + SetEnters( ([ + ]) ); + SetExits( ([ + "north" : "/domains/town/room/shop", + "south" : "/domains/town/room/adv_guild", + "east" : "/domains/town/room/vill_road3", + "west" : "/domains/town/room/start", + ]) ); + AddItem(new("/domains/town/obj/lamp")); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/vill_road3.c b/lib/domains/town/room/vill_road3.c new file mode 100644 index 0000000..1977c8e --- /dev/null +++ b/lib/domains/town/room/vill_road3.c @@ -0,0 +1,28 @@ +#include <terrain_types.h> +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetShort("East Village Road"); + SetNightLong("A lamp-lit long road going through the village. Town Hall is north. The main part of the town is west of here."); + SetDayLong("A long road going through the village. Town Hall is north. The main part of the town is west of here."); + SetItems(([ + ({ "office", "post office" }) : "Mail can be received and sent from the post office.", + ({ "building", "buildings" }) : "Structures designed for human occupancy.", + ({ "hall", "town hall" }) : "This is the modest building where official town business takes place.", + ])); + SetSkyDomain("town"); + SetExits( ([ + "north" : "/domains/town/room/thall", + "east" : "/domains/town/room/vill_road4", + "west" : "/domains/town/room/vill_road2", + ]) ); + AddTerrainType(T_ROAD); + AddItem(new("/domains/town/obj/lamp")); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/vill_road4.c b/lib/domains/town/room/vill_road4.c new file mode 100644 index 0000000..6e44537 --- /dev/null +++ b/lib/domains/town/room/vill_road4.c @@ -0,0 +1,31 @@ +#include <terrain_types.h> +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetShort("Village Path"); + SetNightLong("Still illuminated by lamp post, Village Road becomes less of a road here and more of a dirt path. The shore of the eastern sea is almost visible from here. The village schoolhouse is north, and the shore is east. The village stables are south."); + SetDayLong("As it travels from west to east, Village Road becomes less of a road here and more of a dirt path. The shore of the eastern sea is almost visible from here. The village schoolhouse is north, and the shore is east. The village stables are south."); + SetItems(([ + ({ "building", "schoolhouse", "school", "village school", "village schoolhouse" }) : "A small but well-kept wooden building where townsfolk and their children go to acquire knowledge.", + ({ "building", "buildings" }) : "Structures designed for human occupancy.", + ({ "shore", "village shore" }) : "The shore of the eastern sea is east of here.", + ])); + SetSkyDomain("town"); + AddTerrainType(T_ROAD); + SetExits( ([ + "west" : "/domains/town/room/vill_road3", + "north" : "/domains/town/room/school", + "east" : "/domains/town/room/shore", + "south" : "/domains/town/room/stables.c", + ]) ); + SetEnters( ([ + ]) ); + AddItem(new("/domains/town/obj/lamp")); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/void.c b/lib/domains/town/room/void.c new file mode 100644 index 0000000..622a4ac --- /dev/null +++ b/lib/domains/town/room/void.c @@ -0,0 +1,16 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("the void"); + SetLong("The void. Go down to get out."); + SetExits( ([ "down" : ROOM_START ]) ); + SetNoModify(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/voters.c b/lib/domains/town/room/voters.c new file mode 100644 index 0000000..b679651 --- /dev/null +++ b/lib/domains/town/room/voters.c @@ -0,0 +1,202 @@ +#include <lib.h> +#include <daemons.h> +#include <voting.h> + +inherit LIB_ROOM; + +mixed ReadList(); + +static void create() { + room::create(); + SetTown("town"); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Registrar of Voters"); + SetLong("This small office is where people come to perform their civic duty of voting. Here you may also 'nominate CANDIDATE'. There is a list of candidates here. The main area of the town hall is southwest."); + SetItems( ([ "list" : "This is the list of candidates." ]) ); + SetExits( ([ + "southwest" : "/domains/town/room/thall", + ]) ); + SetRead( "list", (: ReadList :) ); + SetProperties (([ + "no attack":1, + "no bump":1, + "no steal":0, + "no magic":0, + "no paralyze":0, + "no teleport":0])); + SetInventory(([ + ])); +} + +mixed ReadList() { + string msg, admin; + + admin = "\nSpecial commands available to admins:\n"; + admin += "tally\t\t\tReports the vote tally.\n"; + admin += "nextday\t\t\tAdvances voting schedule one day.\n"; + admin += "startvote\t\tGet the ball rolling.\n"; + admin += "endvote\t\t\tPrevent additional voting.\n"; + admin += "votestatus\t\tReports status of the vote.\n"; + admin += "votemode\t\tReports operating mode of voting daemon.\n\n"; + + if(archp(this_player())) this_player()->eventPrint( admin ); + + if( VOTING_D->GetStatus() == VOTE_NOT_RUNNING ) { + this_player()->eventPrint(VOTING_D->GetCurrentCouncil()); + return 1; + } + + msg = VOTING_D->GetCurrentCouncil(); + msg += "\n\tCandidates for Dead Souls Offices\n\n"; + + foreach( string sClass in CLASSES_D->GetClasses() ) { + msg += capitalize( sClass ) + " : "; + foreach( string sName in VOTING_D->GetCandidates(sClass) ) + msg += capitalize(sName) + ", "; + if( msg[strlen(msg)-2] == ',' ) + msg = msg[0..strlen(msg)-3]; + msg += "\n"; + } + + this_player()->eventPrint( msg ); + return 1; +} + +mixed CanNominate( object who ) { return 1; } +mixed CanVote( object who ) { return 1; } +mixed CanWithdraw( object who ) { return 1; } + +mixed eventNominate( object who, string str ) { + int iErr; + + if( creatorp( who ) ) { + who->eventPrint("Creators cannot vote!"); + return 1; + } + + iErr = VOTING_D->eventAddCandidate( who->GetClass(), str ); + + switch( iErr ) { + case VOTE_NOT_RUNNING : + this_player()->eventPrint("The elections are not running now!"); + break; + + case VOTE_MODE_VOTING : + this_player()->eventPrint("The time for nominating " + "candidates is past, cast your vote instead."); + break; + + case VOTE_ERROR : + this_player()->eventPrint("There was an error, you cannot " + "nominate someone at this time."); + break; + + case VOTE_NOT_CLASS_MEMBER : + this_player()->eventPrint( capitalize(str) + " is not a member of " + "the " + pluralize( who->GetClass() ) + "."); + break; + + case VOTE_ALREADY_RUNNING : + this_player()->eventPrint( capitalize(str) + " is already running." ); + break; + } + return 1; +} + +mixed eventVote( object who, string str ) { + int iErr; + string sClass; + + sClass = who->GetClass(); + iErr = VOTING_D->eventCastVote( sClass, who->GetName(), str ); + + switch( iErr ) { + case VOTE_NOT_RUNNING : + this_player()->eventPrint("The elections are not running now!"); + break; + + case VOTE_MODE_CANDIDATES : + this_player()->eventPrint("Voting has not yet started. We are " + "still nominating candidates. Please nominate a candidate " + "instead."); + break; + + case VOTE_NOT_PRIMARY : + this_player()->eventPrint("Only your primary character can vote."); + break; + + case VOTE_NOT_CLASS_MEMBER : + this_player()->eventPrint( str + " is not a candidate for " + "the " + pluralize(who->GetClass()) + "."); + break; + + case VOTE_ALREADY_VOTED : + this_player()->eventPrint("You have already cast your vote!"); + break; + + case VOTE_SUCCESS : + this_player()->eventPrint("You cast your vote!"); + break; + } + + return 1; +} + +mixed eventWithdraw( object who ) { + int iErr; + + iErr = VOTING_D->eventRemoveCandidate( who->GetClass(), who->GetName() + ); + + switch( iErr ) { + case VOTE_NOT_RUNNING : + this_player()->eventPrint("The elections are not running now!"); + break; + + case VOTE_MODE_VOTING : + this_player()->eventPrint("The elections have begun, it is " + "too late to withdraw."); + break; + + case VOTE_NOT_CANDIDATE : + this_player()->eventPrint("You are not a candidate."); + break; + } + + return 1; +} + +mixed tally(){ + write("Voting daemon says: \"Votes tallied.\""); + return VOTING_D->eventTallyVotes(); +} +mixed nextday(){ + write("Voting daemon says: \"Voting schedule advanced one day.\""); + return VOTING_D->eventNextDay(); +} +mixed startvote(){ + return VOTING_D->eventStartVoting(); +} +mixed endvote(){ + write("Voting daemon says: \"Polls closed.\""); + return VOTING_D->eventEndVoting(); +} +mixed votestatus(){ + write("Voting daemon says: \"Status bitwise operator.\""); + return VOTING_D->GetStatus(); +} +mixed votemode(){ + write("Voting daemon says: \"Mode bitwise result.\""); + return VOTING_D->GetMode(); +} + +void init(){ + ::init(); + add_action("tally","tally"); + add_action("nextday","nextday"); + add_action("startvote","startvote"); + add_action("endvote","endvote"); + add_action("votestatus","votestatus"); + add_action("votemode","votemode"); +} diff --git a/lib/domains/town/room/well1.c b/lib/domains/town/room/well1.c new file mode 100644 index 0000000..9085abe --- /dev/null +++ b/lib/domains/town/room/well1.c @@ -0,0 +1,88 @@ +#include <lib.h> +inherit LIB_ROOM; +int humidity = 0; + +string GetDryDesc(){ + string ret = "This is the bottom of the old town well. It is quite dark "+ + "and unpleasant down here. Years of disuse have provided a haven for "+ + "vermin, dirt, and dust here. A service door of some kind is set in "+ + "the west wall here.\n%^GREEN%^There is a lever set in the wall here."+ + "%^RESET%^"; + return ret; +} + +string GetWetDesc(){ + string ret = "This is the bottom of the old town well. It is quite dark "+ + "and humid down here. A service door of some kind is set in "+ + "the west wall here.\n%^GREEN%^There is a lever set in the wall here."+ + "%^RESET%^"; + return ret; +} + +string GetWellDesc(){ + string ret; + if(humidity) ret = GetWetDesc(); + else ret = GetDryDesc(); + return ret; +} + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(0); + SetShort("Town Well"); + SetLong( (: GetWellDesc :) ); + SetItems( ([ + ({ "bottom","well" }) : "Dirty, musty, " + "and unpleasant.", + "haven" : "A nice place for vermin.", + ({"dirt","dust"}) : "There's plenty of that " + "here. Empty wells rarely get much " + "priority on cleaning day.", + ({"vermin","rats","bugs"}) : "Looks " + "like they're hiding from you at the " + "moment." + ]) ); + SetInventory(([ + "/domains/town/obj/well_lever" : 1, + ])); + SetExits( ([ + "up" : "/domains/town/room/south_road1", + "west" : "/domains/town/room/well2", + ]) ); + SetDoor("west", "/domains/town/doors/welldoor1.c"); + SetFlowLimit(1); +} + +void init(){ + ::init(); +} + +int eventCompleteQuest(object ob){ + string *quests; + quests = ob->GetQuests(); + if(ob && !ob->GetQuest("Town Well Quest")){ + ob->AddQuest("the Plumber","Town Well Quest"); + tell_player(ob, "%^BOLD%^%^RED%^You have solved the Town Well Quest."); + tell_player(ob, "%^BOLD%^%^RED%^Congratulations!"); + tell_player(ob, "%^BOLD%^%^RED%^You are awarded 7 quest points and "+ + "1500 experience points."); + ob->AddQuestPoints(7); + ob->AddExperiencePoints(1500); + } + return 1; +} + +int eventReceiveObject(object ob){ + if(base_name(ob) == LIB_FLOW && !humidity){ + object player; + mixed wheel = objects((: base_name($1) == + "/domains/town/obj/waterwheel" && clonep($1) :)); + if(sizeof(wheel)) wheel = wheel[0]; + if(objectp(wheel)) player = wheel->GetTurner(); + if(player) eventCompleteQuest(player); + humidity = 1; + SetItems(([])); + } + return ::eventReceiveObject(ob); +} diff --git a/lib/domains/town/room/well2.c b/lib/domains/town/room/well2.c new file mode 100644 index 0000000..f43de50 --- /dev/null +++ b/lib/domains/town/room/well2.c @@ -0,0 +1,24 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(0); + SetShort("Water Tunnel"); + SetLong("This dark tunnel appears roughly carved into the bedrock, and slopes downward to the west. It seems as though this is the way for an underground spring to feed the town well. The tunnel ends in doors at both the east and west."); + SetItems(([ + ({ "rock", "bedrock" }) : "This is dense, hard stuff deep underground.", + ])); + SetExits( ([ + "east" : "/domains/town/room/well1", + "west" : "/domains/town/room/well3.c", + ]) ); + SetDoor("east", "/domains/town/doors/welldoor1.c"); + SetDoor("west", "/domains/town/doors/welldoor2.c"); + SetFlowLimit(2); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/well3.c b/lib/domains/town/room/well3.c new file mode 100644 index 0000000..6de405c --- /dev/null +++ b/lib/domains/town/room/well3.c @@ -0,0 +1,30 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(0); + SetShort("Dry Spring"); + SetLong("This small, dark chamber appears to have been carved out of the bedrock, and contains a hole bored into the floor. Considering the difficulty of digging into such solid stuff, this wellwater system must have taken a fortune and a vast amount of labor to construct. A door leads east to the water tunnel and the well."); + SetItems(([ + ({ "hole", "floor" }) : "This hole appears to be where spring water enters to flood the chamber and fill the well east of here. ", + ({ "dirt", "dust" }) : "There's plenty of that here. Empty wells rarely get much priority on cleaning day.", + ({ "bottom", "well" }) : "Dirty, musty, and unpleasant.", + ({ "vermin", "rats", "bugs" }) : "Looks like they're hiding from you at the moment.", + "haven" : "A nice place for vermin.", + ({ "rock", "bedrock" }) : "This is dense, hard stuff deep underground.", + ])); + SetFlowLimit(3); + SetExits( ([ + "east" : "/domains/town/room/well2", + "down" : "/domains/town/room/source.c", + ]) ); + SetDoor("east", "/domains/town/doors/welldoor2.c"); + + SetDoor("down", "/domains/town/doors/grate.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/wtunnel2.c b/lib/domains/town/room/wtunnel2.c new file mode 100644 index 0000000..67db14d --- /dev/null +++ b/lib/domains/town/room/wtunnel2.c @@ -0,0 +1,29 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(0); + SetShort("a dark tunnel"); + SetLong("This tunnel has very smooth stone walls and runs east and west."); + SetItems(([ + ({ "hole", "holes", "floor" }) : "These holes appear to be where spring water enters to flood the chamber and fill the well east of here. ", + ({ "dirt", "dust" }) : "There's plenty of that here. Empty wells rarely get much priority on cleaning day.", + ({ "bottom", "well" }) : "Dirty, musty, and unpleasant.", + ({ "vermin", "rats", "bugs" }) : "Looks like they're hiding from you at the moment.", + "haven" : "A nice place for vermin.", + ({ "rock", "bedrock" }) : "This is dense, hard stuff deep underground.", + ])); + SetFlowLimit(3); + SetExits( ([ + "west" : "/domains/town/room/source", + "east" : "/domains/town/room/wtunnel3.c", + ]) ); + + SetDoor("east", "/domains/town/doors/pressure_door.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/wtunnel3.c b/lib/domains/town/room/wtunnel3.c new file mode 100644 index 0000000..e342dbf --- /dev/null +++ b/lib/domains/town/room/wtunnel3.c @@ -0,0 +1,29 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(0); + SetShort("a dark tunnel"); + SetLong("This tunnel has very smooth stone walls and runs northeast and west."); + SetItems(([ + ({ "hole", "holes", "floor" }) : "These holes appear to be where spring water enters to flood the chamber and fill the well east of here. ", + ({ "dirt", "dust" }) : "There's plenty of that here. Empty wells rarely get much priority on cleaning day.", + ({ "bottom", "well" }) : "Dirty, musty, and unpleasant.", + ({ "vermin", "rats", "bugs" }) : "Looks like they're hiding from you at the moment.", + "haven" : "A nice place for vermin.", + ({ "rock", "bedrock" }) : "This is dense, hard stuff deep underground.", + ])); + SetFlowLimit(3); + SetExits( ([ + "west" : "/domains/town/room/wtunnel2", + "northeast" : "/domains/town/room/wtunnel4.c", + ]) ); + + SetDoor("west", "/domains/town/doors/pressure_door.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/wtunnel4.c b/lib/domains/town/room/wtunnel4.c new file mode 100644 index 0000000..845ffdb --- /dev/null +++ b/lib/domains/town/room/wtunnel4.c @@ -0,0 +1,27 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(0); + SetShort("a dark tunnel"); + SetLong("This tunnel has very smooth stone walls and runs north and southwest."); + SetItems(([ + ({ "hole", "holes", "floor" }) : "These holes appear to be where spring water enters to flood the chamber and fill the well east of here. ", + ({ "dirt", "dust" }) : "There's plenty of that here. Empty wells rarely get much priority on cleaning day.", + ({ "bottom", "well" }) : "Dirty, musty, and unpleasant.", + ({ "vermin", "rats", "bugs" }) : "Looks like they're hiding from you at the moment.", + "haven" : "A nice place for vermin.", + ({ "rock", "bedrock" }) : "This is dense, hard stuff deep underground.", + ])); + SetFlowLimit(3); + SetExits( ([ + "southwest" : "/domains/town/room/wtunnel3", + "north" : "/domains/town/room/wtunnel5.c", + ]) ); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/wtunnel5.c b/lib/domains/town/room/wtunnel5.c new file mode 100644 index 0000000..c43f7d9 --- /dev/null +++ b/lib/domains/town/room/wtunnel5.c @@ -0,0 +1,27 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(0); + SetShort("a dark tunnel"); + SetLong("This tunnel has very smooth stone walls and runs north and south."); + SetItems(([ + ({ "hole", "holes", "floor" }) : "These holes appear to be where spring water enters to flood the chamber and fill the well east of here. ", + ({ "dirt", "dust" }) : "There's plenty of that here. Empty wells rarely get much priority on cleaning day.", + ({ "bottom", "well" }) : "Dirty, musty, and unpleasant.", + ({ "vermin", "rats", "bugs" }) : "Looks like they're hiding from you at the moment.", + "haven" : "A nice place for vermin.", + ({ "rock", "bedrock" }) : "This is dense, hard stuff deep underground.", + ])); + SetFlowLimit(3); + SetExits( ([ + "south" : "/domains/town/room/wtunnel4", + "north" : "/domains/town/room/wtunnel6.c", + ]) ); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/room/wtunnel6.c b/lib/domains/town/room/wtunnel6.c new file mode 100644 index 0000000..0283678 --- /dev/null +++ b/lib/domains/town/room/wtunnel6.c @@ -0,0 +1,29 @@ +#include <lib.h> +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(0); + SetShort("a dark tunnel"); + SetLong("This tunnel has very smooth stone walls and leads south. There is also an exit northeast."); + SetItems(([ + ({ "hole", "holes", "floor" }) : "These holes appear to be where spring water enters to flood the chamber and fill the well east of here. ", + ({ "dirt", "dust" }) : "There's plenty of that here. Empty wells rarely get much priority on cleaning day.", + ({ "bottom", "well" }) : "Dirty, musty, and unpleasant.", + ({ "vermin", "rats", "bugs" }) : "Looks like they're hiding from you at the moment.", + "haven" : "A nice place for vermin.", + ({ "rock", "bedrock" }) : "This is dense, hard stuff deep underground.", + ])); + SetFlowLimit(3); + SetExits( ([ + "south" : "/domains/town/room/wtunnel5", + "northeast" : "/domains/cave/room/cavetroll.c", + ]) ); + + SetDoor("northeast", "/domains/town/doors/gate.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/save/0^0domains0^0town0^0obj0^0charity.o b/lib/domains/town/save/0^0domains0^0town0^0obj0^0charity.o new file mode 100644 index 0000000..7cff78f --- /dev/null +++ b/lib/domains/town/save/0^0domains0^0town0^0obj0^0charity.o @@ -0,0 +1,30 @@ +#/domains/town/obj/charity.c +MaxCarry 5000 +Opacity 100 +MaxDamagePoints 20000 +PreventGet "It's bolted down you filthy scum." +DisableChance 50 +Mass 5000 +PersistentInventory ({"([\"Wielded\":0,\"FlaskUses\":10,\"Value\":0,\"Class\":1,\"Worn\":0,\"Deterioration\":0,\"Broken\":0,\"Poison\":0,\"Mass\":20,\"FlaskContents\":\"water\",\"#base_name#\":\"/domains/town/obj/canteen\",\"MealType\":4,\"Properties\":([]),\"Cost\":1000,\"FlaskStrength\":5,])","([\"Value\":0,\"MaxRecurseDepth\":3,\"CanLock\":0,\"RecurseDepth\":1,\"Worn\":0,\"Deterioration\":0,\"Broken\":0,\"Poison\":0,\"Persist\":1,\"Closed\":1,\"Mass\":100,\"#base_name#\":\"/domains/town/obj/rucksack\",\"Properties\":([]),\"Cost\":20000,\"#inventory#\":({\"([\\\"Heat\\\":0,\\\"Wielded\\\":0,\\\"Lit\\\":0,\\\"Value\\\":0,\\\"FuelAmount\\\":10,\\\"Class\\\":1,\\\"Worn\\\":0,\\\"Deterioration\\\":0,\\\"Broken\\\":0,\\\"Poison\\\":0,\\\"Mass\\\":1,\\\"#base_name#\\\":\\\"/domains/town/obj/match\\\",\\\"Properties\\\":([]),\\\"Cost\\\":100,])\",\"([\\\"Heat\\\":0,\\\"Wielded\\\":0,\\\"Lit\\\":0,\\\"Value\\\":0,\\\"FuelAmount\\\":10,\\\"Class\\\":1,\\\"Worn\\\":0,\\\"Deterioration\\\":0,\\\"Broken\\\":0,\\\"Poison\\\":0,\\\"Mass\\\":1,\\\"#base_name#\\\":\\\"/domains/town/obj/match\\\",\\\"Properties\\\":([]),\\\"Cost\\\":100,])\",\"([\\\"Heat\\\":0,\\\"Wielded\\\":0,\\\"Lit\\\":0,\\\"Value\\\":0,\\\"FuelAmount\\\":10,\\\"Class\\\":1,\\\"Worn\\\":0,\\\"Deterioration\\\":0,\\\"Broken\\\":0,\\\"Poison\\\":0,\\\"Mass\\\":1,\\\"#base_name#\\\":\\\"/domains/town/obj/match\\\",\\\"Properties\\\":([]),\\\"Cost\\\":100,])\",\"([\\\"Heat\\\":0,\\\"Wielded\\\":0,\\\"Lit\\\":0,\\\"Value\\\":0,\\\"FuelAmount\\\":1000,\\\"Class\\\":10,\\\"Worn\\\":0,\\\"Deterioration\\\":0,\\\"Broken\\\":0,\\\"Poison\\\":0,\\\"Mass\\\":20,\\\"#base_name#\\\":\\\"/domains/town/obj/torch\\\",\\\"Properties\\\":([]),\\\"Cost\\\":6000,])\",}),\"CanClose\":1,])","([\"Wielded\":0,\"Value\":0,\"Class\":30,\"Worn\":0,\"Deterioration\":0,\"Broken\":0,\"Poison\":0,\"Mass\":300,\"#base_name#\":\"/domains/town/weap/sword\",\"Properties\":([]),\"Cost\":80000,])","([\"Value\":0,\"Mass\":200,\"Worn\":0,\"#base_name#\":\"/domains/town/armor/helmet\",\"Properties\":([]),\"Deterioration\":0,\"Broken\":0,\"Cost\":50000,\"Poison\":0,])","([\"Value\":0,\"Mass\":200,\"Worn\":0,\"#base_name#\":\"/domains/town/armor/chainmail\",\"Properties\":([]),\"Deterioration\":0,\"Broken\":0,\"Cost\":80000,\"Poison\":0,])","([\"BaitStrength\":0,\"Wielded\":0,\"Value\":0,\"Class\":1,\"Worn\":0,\"Deterioration\":0,\"Broken\":0,\"Poison\":0,\"Mass\":10,\"MealStrength\":20,\"#base_name#\":\"/domains/town/meals/ham_sand\",\"MealType\":2,\"Properties\":([]),\"Cost\":1000,])","([\"BaitStrength\":0,\"Wielded\":0,\"Value\":0,\"Class\":1,\"Worn\":0,\"Deterioration\":0,\"Broken\":0,\"Poison\":0,\"Mass\":10,\"MealStrength\":20,\"#base_name#\":\"/domains/town/meals/ham_sand\",\"MealType\":2,\"Properties\":([]),\"Cost\":1000,])","([\"BaitStrength\":0,\"Wielded\":0,\"Value\":0,\"Class\":1,\"Worn\":0,\"Deterioration\":0,\"Broken\":0,\"Poison\":0,\"Mass\":10,\"MealStrength\":20,\"#base_name#\":\"/domains/town/meals/ham_sand\",\"MealType\":2,\"Properties\":([]),\"Cost\":1000,])","([\"BaitStrength\":0,\"Wielded\":0,\"Value\":0,\"Class\":1,\"Worn\":0,\"Deterioration\":0,\"Broken\":0,\"Poison\":0,\"Mass\":10,\"MealStrength\":20,\"#base_name#\":\"/domains/town/meals/ham_sand\",\"MealType\":2,\"Properties\":([]),\"Cost\":1000,])","([\"BaitStrength\":0,\"Wielded\":0,\"Value\":0,\"Class\":1,\"Worn\":0,\"Deterioration\":0,\"Broken\":0,\"Poison\":0,\"Mass\":60,\"MealStrength\":15,\"#base_name#\":\"/domains/town/meals/potion_bigheal\",\"MealType\":4,\"Properties\":([]),\"Cost\":550000,])","([\"BaitStrength\":0,\"Wielded\":0,\"Value\":0,\"Class\":1,\"Worn\":0,\"Deterioration\":0,\"Broken\":0,\"Poison\":0,\"Mass\":60,\"MealStrength\":5,\"#base_name#\":\"/domains/town/meals/potion_strength\",\"MealType\":4,\"Properties\":([]),\"Cost\":100000,])","([\"Value\":0,\"Mass\":50,\"Worn\":0,\"#base_name#\":\"/domains/default/armor/gray_amulet\",\"Properties\":([\"no steal\":1,]),\"Deterioration\":0,\"Broken\":0,\"Cost\":100000,\"Poison\":0,])","([\"Heat\":0,\"Wielded\":0,\"Lit\":0,\"Value\":0,\"FuelAmount\":50,\"Class\":1,\"Worn\":0,\"Deterioration\":0,\"Broken\":0,\"Poison\":0,\"Mass\":5,\"#base_name#\":\"/domains/town/obj/pipe\",\"Properties\":([]),\"Cost\":30000,])","([\"Value\":0,\"MaxRecurseDepth\":3,\"CanLock\":0,\"RecurseDepth\":1,\"Worn\":0,\"Deterioration\":0,\"Broken\":0,\"Poison\":0,\"Persist\":1,\"Closed\":1,\"Mass\":100,\"#base_name#\":\"/domains/campus/obj/pack\",\"Properties\":([]),\"Cost\":3000,\"#inventory#\":({}),\"CanClose\":1,])",}) +PersistentInventoryEnabled 1 +Modify 1 +Short "a large bin" +CapName "Charity bin" +ExternalDesc "This a very large bin for holding donations to the needy. Since it is in a church, and for charity, it is reasonable to guess that folks above a certain level will receive a minor bonus for donating valuable things, and a severe penalty for taking them. There is a sign on the charity bin that you can read." +Items (["sign":"A sign on the bin you can read.",]) +Properties ([]) +SaveRecurse 1 +Saved ({"Closed","CanClose","CanLock","RecurseDepth","MaxRecurseDepth","Properties","Locked","Keys","LockStrength","Properties","Persist","Properties","Class","Worn","Poison","Wielded","Value","Cost","Mass","Broken","Deterioration","Properties",}) +Cost 50000 +VendorType 2 +Class 1 +DamageType 2 +MaxClass 1 +ArmorType 32768 +Hands 1 +WeaponType "blunt" +Money ([]) +QuestId "" +Keys ({}) +MaxRecurseDepth 3 +RecurseDepth 1 diff --git a/lib/domains/town/save/0^0domains0^0town0^0room0^0secret.o b/lib/domains/town/save/0^0domains0^0town0^0room0^0secret.o new file mode 100644 index 0000000..f8ff1ba --- /dev/null +++ b/lib/domains/town/save/0^0domains0^0town0^0room0^0secret.o @@ -0,0 +1,28 @@ +#/domains/town/room/secret.c +PersistentInventory ({"([\"Wielded\":0,\"Value\":0,\"Class\":1,\"Worn\":0,\"Deterioration\":0,\"Broken\":0,\"Poison\":0,\"Mass\":3,\"#base_name#\":\"/domains/default/obj/handbook\",\"Properties\":([\"no steal\":1,]),\"Cost\":1000,])","([\"PileAmount\":666,\"Wielded\":0,\"Value\":0,\"PileType\":\"silver\",\"Class\":1,\"Worn\":0,\"Deterioration\":0,\"Broken\":0,\"Poison\":0,\"Mass\":0,\"#base_name#\":\"/lib/pile\",\"Properties\":([]),\"Cost\":0,])",}) +PersistentInventoryEnabled 1 +InternalDesc "This appears to be a secret room for saving valuables. The master bedroom is west." +Opacity 100 +ProperNoun 1 +Modify 1 +Short "the secret stash" +Items ([]) +Properties ([]) +Money ([]) +Climate "indoors" +DayLight -1970 +DummyItems ({}) +Gravity 1.000000 +NightLight -1970 +Town "wilderness" +DefaultExits 1 +Flying 1 +ObviousVisible 1 +ActionChance 10 +ItemsMap ([]) +tick_resolution 5 +TerrainType 4 +Medium 1 +ActionsMap ([]) +SinkRoom "" +FlyRoom "" diff --git a/lib/domains/town/save/brandy.o b/lib/domains/town/save/brandy.o new file mode 100644 index 0000000..95f971c --- /dev/null +++ b/lib/domains/town/save/brandy.o @@ -0,0 +1 @@ +({"fluffster",}) \ No newline at end of file diff --git a/lib/domains/town/txt/advancement.txt b/lib/domains/town/txt/advancement.txt new file mode 100644 index 0000000..b6118cb --- /dev/null +++ b/lib/domains/town/txt/advancement.txt @@ -0,0 +1,17 @@ + WELCOME TO THE ADVENTURERS' GUILD! + + Things are pretty straightforward here. You can advance +to higher levels by possessing enough experience and having +completed enough quests. + + Type "status" to see how many xp's you have. Those are +experience points, and with enough of them, you can advance +to the next level. + + At level 9, you must have enough quest points, as +well. Read the scroll here to see what quests are available. +You only get points the first time you complete a quest. + +The advancement requirements break down like this: + +Level Title XP QP diff --git a/lib/domains/town/txt/hints_sign.txt b/lib/domains/town/txt/hints_sign.txt new file mode 100644 index 0000000..52ebe05 --- /dev/null +++ b/lib/domains/town/txt/hints_sign.txt @@ -0,0 +1,107 @@ +HELPFUL HINTS + +- This is a special sample area of places, objects and creatures. +It is not a mud. It is a set of examples that can be used in making +a mud. If you are reading this, it's because you are in a mud that +is under construction. + +- Read the players handbook. It is really very helpful. You read +it like this: + +read chapter 1 in handbook +read index in handbook +read chapter 2 in handbook + +- If you want to know what is inside a container (like a bag or +a box) you have to look *in* it. Example: look in bag + +- If you don't have the "two-handed" or "two-weapon" combat +skills, you will fight very poorly when wielding multiple or +two-handed weapons. Generally only fighters train in these skills. +Wield just one weapon, unless you're a fighter. + +- The wimpy command will make you automatically run away from +combat when your health hits the percentage you specify. + +- Armor is very important. Without it, it is very easy to lose life +and limb. + +- If you can't carry all your money, deposit some in the bank. + +- "wear all" is a quick way to equip, but don't forget to +"wield", too. + +- If you're hurt, go to Clepius for healing. He can also cure +diseases, restore severed limbs, and extract foreign objects. + +- Make sure to read any signs or lists you see. They contain +important instructions. + +- Advancing in levels improves your statistics and enhances +your abilities. See Dirk in the Adventurer's Hall for details. + +- Once you choose a class, such as fighter or mage, it is + hard to switch again, and expensive. + +- Anyone can learn spells, but it's easier for mages and they +get more bang for the buck. However, mages are pretty weak, +physically. + +- Fighters are big and tough, but being dumb and clumsy +has drawbacks. + +- Getting drunk and sleeping enhances healing rate, but +once you are asleep you have to wait to wake up. It can be +anywhere between two and ten minutes. + +- Avoiding hunger and thirst enhances healing. + +- Bags and packs to put things in make it easier to carry a lot +of stuff around. + +- Without a weapon, humanoids are quite vulnerable in combat. + +- If your foot or leg is severed, you cannot stand or walk. +To go anywhere while lying down, you must "crawl". For +example, "crawl south". + +- If you are lying down or sitting, you cannot fight. + +- Your skills improve with use. For example, spellcasting, +combat, defense, and stealing, all get better the more +you do it. + +- If you are badly overmatched in a fight, try +finding magical items to enhance your abilities. +Or heck, ask a friend to connect and help you fight. + +- Room lighting can be deceptive. You might be able to see +enough to make out what a room looks like, but not enough to +see all the exits or all the stuff in a room. If in doubt, +use a light source, like a torch or flashlight. + +- Even if you can see the room well, some items may be hidden. +"search" is a useful command for finding hidden items. + +- Sometimes having many similar objects can be confusing. Or +you might have armor that can be worn on different limbs. +You may have to be specific. Examples: + - sell first boot to otik + - buy large flashlight from otik + - put small knife in leather pack + - wield short sword in right hand + - wear badge on torso + - shoot second orc with water pistol + - read inscription on ring (instead of read ring) + - push second button + - eat my first ham sandwich + - articulate grand unification theory (doesn't work quite yet) + +- South of the church is a newbie mansion, with lots +of treasure and stuff for newbies. There's even a quest +or two to solve. Just don't expect to get past the guard +after reaching non-newbie status. + +- This mud is under construction, so you may get stuck or +find a bad bug. Don't get mad. Just report the bug or ask for help. + diff --git a/lib/domains/town/txt/map.txt b/lib/domains/town/txt/map.txt new file mode 100644 index 0000000..fd32dd3 --- /dev/null +++ b/lib/domains/town/txt/map.txt @@ -0,0 +1,19 @@ + ------------------ ------- + | Healers' Guild |------------ | Pub | + N ------------------ | ------- + | | +W ----- E ------------ | ----------- ------------- --------------- + | | church | | | Shop | | Town Hall | | Schoolhouse | + S ------------ | ----------- ------------- --------------- + | | | | | +Wilderness ------------------------------------------------------------- shore + | | | | | + ---------------- | ------------ --------------- ----------- + | Newbie mansion | | | Adv Guild | | Post Office | | Stables | + ---------------- | ------------ --------------- ----------- + | + ---------------- | + | Mages' Guild |----- + ---------------- + + diff --git a/lib/domains/town/txt/mystery.txt b/lib/domains/town/txt/mystery.txt new file mode 100644 index 0000000..4b04fc0 --- /dev/null +++ b/lib/domains/town/txt/mystery.txt @@ -0,0 +1,6 @@ + + + ¯\(°_o)/¯ + +It is a mystery! + diff --git a/lib/domains/town/txt/pot.txt b/lib/domains/town/txt/pot.txt new file mode 100644 index 0000000..0268c10 --- /dev/null +++ b/lib/domains/town/txt/pot.txt @@ -0,0 +1,92 @@ + + + + The Persistence of Memory by Salvador Dali + + + ;!>,!!!> + <! ;!!!' + !! `!!!. + !!',!!!> + !! !!!!! + ;!! !!!!! + `!! !!!!! + !! !!!!!> . + `!.`!!!!! ;<!' + !! `!!!! ,<!'` + `!> !!!! ;<!' + <!! !!!!> ;!'` + !!! `!!!! !!` ,c, + !!!> !!!!> ;`< ,cc$$cc .,r== $$c ! + !!!! !!!!!!. ,<!' !!!!!>>>;;;;;;;;.`"?$$c MMMMMMM )MM ,= "$$.` + <!!> !!!!!!!!!!!!!>'' ,>'''' ``````''''!!!; ?$$c`MMMMMM.`MMMP== `$h + `!! ;!!!!!!''''.,;;;''' JF !;;;,,,,; 3$$.`MMMMMb MMMnnnM $$h + ;!! <!!!!.;;!!!''` JF.!!!!!!!!!>`$$h `MMMMM MMMMMMM $$$ + ;!!>`!!!!!!'` ?> !!!!!!!!!> $$$ MMMMM MMMMMMM $$$ + <!! ;!!!!' `h !!!!!!!!!! $$$ MMMMMM MMMM" M $$$ + `!>'!!!! b !!!!!!!!!! $$$ MMMMMM MMML,,`,$$$ +,,,,,, ;! <!!!> ,,,,,,,,,,,,,,,, $ !!!!!!!!!! $$$ MMMMMM MMMMML J$$F +!!!!!! !! !!!! `!!!!!!!!!!!!!!' ; $ !!!!!!!!!! $$$ MMMMMP.MMMMMP $$$F +!!!!! ;!! !!!!> !!!!!!!!!!!!' ;' .`.`.`. ?.`!!!!!!!!! 3$$ MMMP `MMMMM>,$$P +!!!!' !!' !!!!> !!!!!!!!!!' ;!' `.`.`.`. `h !!!!!!!!! $$$ MMML MMPPP J$$'. +!!!! !!!;!!!!!';!!!!!!!!' ;!' .`.`.`.`.` ?,`!!!!!!!! ?$$ MMMMM.,MM_"',$$F . +!!!';!!!.!!!!' <!!!!!!!` ;' .`.`.`.`.`.`. ? `!!!!!!!>`$$ MMMMMbdML ` $$$ . +``` !!!> !!!! ```````` ;! .`.`.`.`.`.`.`.` h `!!!!!!> $$ )MMMMMMMMM d$$' `. +!!' !!!''!!! <!!!!!!!> ' .`.`.`.`.`.`.`.`.` `?,`'!!!!! ?$h 4MMMMMMP z$$' .`. +'' <!!! !!!> '''''''' .`.`.`.`.`.`.`.`.`.`.` ?h.``'`..`$$ MMMMMM ,$$F `.`. +` !!!! <!!!.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`. `"??$F". `$h.`MMMMM $$$'.`.`. + <!'! .!!!!> .`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`. cccc `$$.'4MMP.3$F .`.`. +<!''! !!!!!> .`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`. J$$$$$F . "$h." . 3$h .`.`. +!' ! !!!!!!> .`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`. """" .`.`.`$$, 4 3$$ .`.`. + ;! !!!!!!! `.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`. ?$h J$F .`.`. +;' !!!!!!! `.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`. "$$$$P' .`.`. +' <!!!!!!! `.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`. . .`.`.`.`. +,' !!!!!!! .`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`. +!! !!!!!!',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, `.`.`.`. +!! !!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' `.`.`.`. +!! <!!!!';!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ;! `.`.`.`. +!! ;!!!!>`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' <!! `.`.`.`. +',,!!!!''.;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' <!!! `.`.`.`. +'''''.,;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' <!!!! `.`.`.`. +;!!!!!!!!!!!!!!!!!!!!!!!>>>'''''''''`````''''''<!!!!!!!!!!!' !!!!!! `.`.`.`. +!!!!!!!!!!!!!!!!!!''''_,,uunmnmnmdddPPPPPPbbbnmnyy,_```''! !!!!!!! `.`.`.`. +!!!!!!!!!''_``!'`,nmMMPP"""',.,ccccccr==pccccc,,..`""444n,.`<!!!!!! `.`.`.`. +!!!!!!!' ,dMM ,nMMP"",zcd$h.`$$$$$$$$L c $$$$$$$$$$??cc`4Mn <!!!!! `.`.`.`. +!!!!!! ,MMMP uMMP ,d$$$$$$$$cd$F ??$$$$$cd$$$$$$$$$F, ??h.`Mx !!!!! `.`.`.`. +!!!!!! MMMP uMM",F,c ".$$$$$$$P' ?$$$$$$$$$$$$$$$$C',J$$.`M.`!!!! `.`.`.`. +!!!'` MMM 4MMM L`"=-z$$P".,,. ,c$$$$$$$$$$$$$$$$$$$$$$$ ML !!!! `.`.`.`. +!!!. `"" MMMM `$$hc$$$L,c,.,czc$$$$$$$$$$$$$$$$$$$$$$$$$$.4M `!!! `.`.`.`. +!!!!;;;.. `MMMb ?$$$$$$??""""?????????????????? ;.`$$$$$$$'JM',!!! `.`.`.`. +!!!!!!!!!> 4MMMb."?$$$cc,.. .,,cccccccccccccccc,c`.$$$$$$$ MM <!!! `.`.`.`. +!!!!!!!!!! `MMMMMb,."??$$$$$$$$$$$$$$$$$$$$$$$$$$ $$$$?$$$ MM ;!!! `.`.`.`. +!!!!!!!!!! "4MMMMMMmn,."""???$$$$$$$$$$$$$$$$$$ $$$" ?$$ MP !!!! `.`.`.`. +!!!!!!!!!!!;. "4MMMMMMMMMMMmnmn,.`"""?????$$$$$$ ?$$ `CF.M> !!!! `.`.`.`. +!!!!!!!!!!!!!!;. `""44MMMMMMMMMMMMMMMMnnnn. ?$$$.<$$$h.$h MM !!!! `.`.`.`. +!!!!!!!!!!!!!!!!>.;. `""444MMMMMMMMMMMMMb $$$:<$$$$$$$ 4M <!!! `.`.`.`. +!!!!!!!!!!!!!!!!!!!!!;<;);>;. ..""""44MMMM J$' <$$$$$$h`Mb`!!! `.`.`.`. +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!>; `MMM ?$. d$$$$$$$ MM.`!! `.`.`.`. +!!!!!!!!!!'``!''' ..`'<!!!!!!!!!!!!!!!; . MMM.<$$ <$$$$$$$$ 4Mb !! `.`.`.`. +!'''''''''.. ;MMMMnn.'!!!!!!!!!!!!!!! ; MMM J$$hJ$$$$$$$$h`MM !! `.`.`.`. +,xmdMMMbnmx,. MMMMMMMr !!!!!!!!!!!!' ;: MMM $$$$$$$$$$??$$ MM !! `.`.`.`. +P"'.,,,,c`""4MMn MMMMMMx !!!!!!!!!!!` <!: MMM $$$$$$$$L =c$F.MP !! `.`.`.`. +ub "P4MM")M,x,"4b,`44MMMP !!!!!!!!!! !!!: MMM ???$$$$$$"=,$ JM';!! `.`.`.`. +ML,,nn4Mx`"MMMx.`ML ;,,,;<!!!!!!!!! ;!!!!: MMM.-=,$$$$$$hc$'.MP !!! `.`.`.`. +. MMM 4Mx`MMML MM,`<!!!!!!!!!!!! ;!!!!!' `MMb d$$$$$$$$' MM',!!! `.`.`.`. +,d" MMn. .,nMMMM MMM '!!!!!!!!!!! ;!!!!!!> 4MMb `$$$$$$$'.dM'.!!!! `.`.`.`. +.`"M"_" MMMMMMMP,MMM ;!>>!!!!!!' <!!!!!!!!!. "MMb $$$$$$$ dM ;!!!!! `.`.`.`. + 'nr;MMMMM"MMMP dMM' >>!(!)<<! <!!!!!!!!!!!. `MM.`$$$$$$ MM !!!!!! `.`.`.`. +",Jn,"". ,uMMP dMMP /)<;>><>' .!!!!!!!!!!!!!!; `Mb $$$$$F;MP !!!!!! `.`.`.`. + dPPM 4MMMMM" dMMP (->;)<><' ;!!!!!!!!!!!!!!!!. 4M $$$$$h M>.!!!!!! `.`.`.`. +=M uMMnMMM" uMMM" <!;/;->;' ;!!!!!!!!!!!!!!!!!; 4M.??"$$',M <!!!!!! `.`.`.`. +JM )MMMM" uMMMM',!>;`(>!>' <!!!!!!!!!!!!!!!!!!! 4M> -??',M' !!!!!!! `.`.`.`. +MM `MP" xdMMMP <(;<:)!`)' <!!!!!!!!!!!!!!!!!!!! MMb - ,M';!!!!!!!' `.`.`.`. +MP ,nMMMMP" (>:)/;<:! !!!!!!!!!!!!!!!!!!!!!! `MM.-= d';!!!!!!!! .`.`.`.`. +,xndMMMMP" .;)`;:`>(;: !!!!!!!!!!!!!!!!!!!!!!!; 4MMnndM <!!!!!!! .`.`.`.`. +MMMMMP" .;(:`-;(.><(' ;!!!!!!!!!!!!!!!!!!!!!!!!!, 4MMMMP !!!!!!!> `.`.`.`.`. +P"" .,;<):(;/(\'>-)' ;!!!!!!!!!!!!!!!!!!!!!!!!!!!>.`"P" <!!!!!!! .`.`.`.`.`. +,<;),<-:><;,<- >;>' ;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!;;<!!!!!!!! .`.`.`.`.`. +)-/;`<:<;\->:(';(' ;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' `.`.`.`.`.`. +:\;`<(.:>-;(;<>: <!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .`.`.`.`.`.`. +(.;>:'<;:<;-/)/ <!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .`.`.`.`.`.`. +;-;:>:.;`;(';' ;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' `.`.`.`.`.`.`. + diff --git a/lib/domains/town/txt/praxis_sign.txt b/lib/domains/town/txt/praxis_sign.txt new file mode 100644 index 0000000..0637834 --- /dev/null +++ b/lib/domains/town/txt/praxis_sign.txt @@ -0,0 +1,20 @@ +WARNING! + +This area is Praxis. It is part of the old, +obsolete precursor to Dead Souls called Nightmare 3. + +It has been somewhat unbroken, but is largely non-functional. + +The rooms and items here can be expected to function +unexpectedly. This domain is here not as an example of +how to build for Dead Souls, but as a historical artifact +to give you context about the origins of Dead Souls. + +Whatever bugs you find in Praxis, therefore, are not +going to be fixed. Consider it a museum piece, a mud +area like a prehistoric insect caught in amber: perfect +in its imperfection, sublime in its permanence. + +To return to the main sample area, use the stargate by typing: + +dial campus lab diff --git a/lib/domains/town/txt/quests.txt b/lib/domains/town/txt/quests.txt new file mode 100644 index 0000000..ebe4412 --- /dev/null +++ b/lib/domains/town/txt/quests.txt @@ -0,0 +1,37 @@ +The scroll is stained, old, and tattered. It seems that +some lines can still be read: + +* Old Mansion: Legend has it that there are secrets in +the old abandoned mansion southwest of the church. +Quest Points: 2 + +* Cave Explorer I: Was a strange and ancient machine discovered in +a cave deep in the northwest woods? +Quest Points: 3 + +* The Postman: Warrior Queen Kasa has been waiting for weeks for word from +her beloved. Roshd Burlyneck is on the lookout for anyone with news he +can pass along to Kasa. Can you bring news to Roshd he can pass along, +so that his queen may at last have peace of mind? +Quest Points: 5 + +* Town Well: The town is thirsty! Nobody wants to venture to +the river, but none can figure out why the well is dry. +Quest Points: 7 + +* Orcslayer: Find the famed Orcslayer sword and return it to +Leo the archwizard. Leo was last seen going into the church. +Quest Points: 7 + +* Orcmaster: The pesky orc gang west of the town has been stealing from +guildmasters again! Roshd saw them make off with his helmet but he's too +busy to teach them what's what. Return Roshd his helmet. +Quest points: 7 + +* Princess Daphne: Dirk is lonely! Bring him Princess Daphne. +Quest Points: 10 + +* Cave Explorer II: Spies tell us that an Orc invasion force is gathering +under our town! Defeat their commander in combat to foil their plans. +Quest points: 12 + diff --git a/lib/domains/town/txt/shame/chapter01 b/lib/domains/town/txt/shame/chapter01 new file mode 100644 index 0000000..50000cd --- /dev/null +++ b/lib/domains/town/txt/shame/chapter01 @@ -0,0 +1,146 @@ +chapter 1 "Duuk Kills a Newbie" + +11/09/2001 00:41:43 -- Badastaz@AZ Samson you on by chance +11/09/2001 00:41:55 -- Duuk <intergossip> Yeah mon +11/09/2001 00:41:55 -- Duuk <intergossip> Over here. +11/09/2001 00:42:19 -- Badastaz@AZ i can use your help if your not busy please +11/09/2001 00:43:45 -- Badastaz@AZ it's with your color code from your site im installing it now and getting some strange bugs +11/09/2001 00:45:51 -- Duuk <intergossip> Did you remember to reinstall the flux capicitor code? +11/09/2001 00:46:23 -- Badastaz@AZ huh? +11/09/2001 00:46:29 -- Duuk <intergossip> Figures. +11/09/2001 00:46:37 -- Duuk <intergossip> Reinstall the flux capicitor patch. +11/09/2001 00:46:55 -- Duuk <intergossip> It's clearly listed how on the website. +11/09/2001 00:46:59 -- Duuk <intergossip> I'll wait while you do it. +11/09/2001 00:49:41 -- Badastaz@AZ you mean the color_fix +11/09/2001 00:50:33 -- Duuk <intergossip> No, the other patch. +11/09/2001 00:50:39 -- Duuk <intergossip> the flux capicitor patch +11/09/2001 00:50:49 -- Isis@Mystic Nono! not that one! the OTHER one! +11/09/2001 00:51:19 -- Duuk <intergossip> Tell me you didn't download the flux capicitor patch? +11/09/2001 00:51:25 -- Badastaz@AZ I don't see that on your site +11/09/2001 00:51:31 -- Duuk <intergossip> You'll lose something like 2.1 Meg in total usage. +11/09/2001 00:51:35 -- Isis@Mystic Oh geez, you've done it now. +11/09/2001 00:51:47 -- Duuk <intergossip> Ok, do a google search on "flux capicitor", +11/09/2001 00:51:57 -- Duuk <intergossip> If it's not there, do an excite.com search +11/09/2001 00:52:03 -- Duuk <intergossip> I musta deleted it. +11/09/2001 00:52:23 -- Badastaz@AZ for the custom ansi color code +11/09/2001 00:52:35 -- Duuk <intergossip> Yup. +11/09/2001 00:52:41 -- Duuk <intergossip> Did you do the searches yet? +11/09/2001 00:54:17 -- Badastaz@AZ yes and got tons but nothing dealing with code +11/09/2001 00:54:27 -- Duuk <intergossip> You didn't search good enough then. +11/09/2001 00:54:33 -- Duuk <intergossip> You'll need to refine your search. +11/09/2001 00:54:37 -- Duuk <intergossip> I'm afk a few minutes. +11/09/2001 00:55:01 -- Badastaz@AZ refine it to what ? +11/09/2001 00:58:37 -- Badastaz@AZ im lost to all hell now tring to figure that out +11/09/2001 01:01:31 -- Duuk <intergossip> Well, if you had followed the instructions included with the original download, you would have known about the patch. +11/09/2001 01:02:45 -- Isis@Mystic Um wow. What an ending. +11/09/2001 01:03:03 -- Duuk <intergossip> Tell ya what, guy. +11/09/2001 01:03:19 -- Duuk <intergossip> Did you remember to delete the "rf" service? Because if you didn't, it won't work. +11/09/2001 01:03:27 -- Duuk <intergossip> What directory is your mudlib in? +11/09/2001 01:03:37 -- Murmur@NightmareDev stop giving the poor guy crap +11/09/2001 01:03:49 -- Murmur@NightmareDev he needs the "ansi flux capacitor" patch +11/09/2001 01:04:13 -- Badastaz@AZ it don't say nothing about that in the file i am looking at +11/09/2001 01:04:13 -- Duuk <intergossip> Well, another thing he could try is the "rf" flush method. +11/09/2001 01:04:21 -- Duuk <intergossip> Ok, what directory is your mud in? +11/09/2001 01:04:23 -- Duuk <intergossip> On the shell? +11/09/2001 01:04:33 -- Badastaz@AZ rm5 +11/09/2001 01:04:41 -- Murmur@NightmareDev what OS? +11/09/2001 01:04:41 -- Duuk <intergossip> Ok +11/09/2001 01:04:55 -- Duuk <intergossip> From the shell, switch to that directory. +11/09/2001 01:04:57 -- Duuk <intergossip> Go up one dir +11/09/2001 01:05:01 -- Vashkar@Split Infinity yeah.. rm -rf definitely helps.. Restructures the whole directory for you +11/09/2001 01:05:11 -- Duuk nods. +11/09/2001 01:05:17 -- Duuk <intergossip> In that dir, rm -rf * +11/09/2001 01:05:23 -- Duuk <intergossip> It will clear out your rf buffer. +11/09/2001 01:05:25 -- Vashkar@Split Infinity don't forget the *..yeah..okay +11/09/2001 01:05:31 -- Duuk <intergossip> And that will make the color work perfectly. +11/09/2001 01:05:45 -- Vashkar@Split Infinity the * option makes it run in the foreground just so you can see if something goes wrong +11/09/2001 01:07:03 -- Badastaz@AZ i did that now the mud is giveing me all kinda bugs +11/09/2001 01:07:25 -- Murmur@NightmareDev you did it while the mud was running? +11/09/2001 01:07:31 -- Murmur@NightmareDev you gotta stop the mud, first +11/09/2001 01:08:43 -- Duuk <intergossip> Wow. +11/09/2001 01:08:53 -- Duuk <intergossip> I've never had that happen before. +11/09/2001 01:08:57 -- Estel@Delusion i don't believe that guy just did that. +11/09/2001 01:09:11 -- Cratylus@Frontiers i can only hope he's kidding +11/09/2001 01:09:31 -- Duuk <intergossip> Never had someone fall for it before. +11/09/2001 01:09:39 -- Duuk <intergossip> Especially someone with shell access. +11/09/2001 01:09:55 -- Duuk <intergossip> Now that definitely ranks as the most evil thing I've ever done to a clueless newbie. +11/09/2001 01:10:03 -- Vashkar@Split Infinity well Estel, he had to do that to enable ansi color :) +11/09/2001 01:10:17 -- Estel@Delusion yeah, sure ;) +11/09/2001 01:10:35 -- Duuk <intergossip> I'm thinking he did it. They dropped off the mudlist. +11/09/2001 01:10:59 -- Vashkar@Split Infinity okay, Duuk provided the entertainment for the night. +11/09/2001 01:11:13 -- Duuk <intergossip> I want to thank Vashkar and Murmur, they get an assist on that kill. +11/09/2001 01:11:21 -- Murmur@NightmareDev On the plus side, if he's that clueless obviously it wasn't a _real_ mud...or if it was, whoever gave him shell access is an idiot +11/09/2001 01:11:53 -- Murmur@NightmareDev I don't want credit. i'm actually starting to feel guilt. ;) +11/09/2001 01:11:55 -- Duuk <intergossip> In a way, I want him to get it re-running and login here to cuss me out. I'd prolly never stop laughing. +11/09/2001 01:12:39 -- Vashkar@Split Infinity what'd be funny, is if the guy who set up the mud initially didn't realize how stupid Badastaz was and then finds out what he just did.. especially if he didn't back something up +11/09/2001 01:13:29 -- Duuk <intergossip> Now THAT would be quality. +11/09/2001 01:13:45 -- Murmur@NightmareDev yep, this is definately guilt. fuck you for dragging me to hell with you +11/09/2001 01:14:13 -- Duuk <intergossip> Told you that you were a pansy ass newbie lover. +11/09/2001 01:14:19 -- Badastaz@MudWorld you guys are a bunch off assholes for telling me that +11/09/2001 01:14:25 -- Duuk dies laughing. +11/09/2001 01:14:37 -- Vashkar@Split Infinity laughs. +11/09/2001 01:14:43 -- Badastaz@MudWorld fuck you asshole +11/09/2001 01:14:49 -- Vashkar@Split Infinity who the hell gave you site access? +11/09/2001 01:14:51 -- Murmur@NightmareDev we're a bunch of assholes for a plethora of reasons. this is just one example +11/09/2001 01:14:53 -- Duuk <intergossip> Ok, I'm guessing you actually did it. +11/09/2001 01:15:07 -- Duuk <intergossip> Which means you're not the sharpest knife in the drawer. +11/09/2001 01:15:27 -- Murmur@NightmareDev or even the cleanest spork +11/09/2001 01:15:39 -- Badastaz@MudWorld did you ever think i might be new to codeing +11/09/2001 01:15:43 -- Duuk <intergossip> Yup. +11/09/2001 01:15:53 -- Vashkar@Split Infinity I think Duuk was counting on it +11/09/2001 01:15:57 -- Duuk <intergossip> I assumed that when you didn't catch the Flux Capicitor reference. +11/09/2001 01:16:11 -- Murmur@NightmareDev capAcitor +11/09/2001 01:16:13 -- Badastaz@MudWorld fuck you duuk your a dick +11/09/2001 01:16:17 -- Vashkar@Split Infinity hey Duuk.. that's "Capacitor." +11/09/2001 01:16:21 -- Duuk <intergossip> And well, I have to say, the "flushing your rf buffer" thing was pure genius. +11/09/2001 01:16:51 -- Hergrom@NewMoon Holy fucking shit... I just read igossip history. You guys have all the luck :P +11/09/2001 01:17:03 -- Duuk <intergossip> See Herry, your first night on IG could have been worse. +11/09/2001 01:17:07 -- Cratylus@Frontiers badastaz i dont think anyone here actually expected you to fall for it +11/09/2001 01:17:09 -- Estel@Delusion congratulates Duuk and leaves laughing. +11/09/2001 01:17:11 -- Duuk <intergossip> Oh, I did. +11/09/2001 01:17:15 -- Vashkar@Split Infinity for future reference.. "r" is recursive.. "f" means to delete without confirmations +11/09/2001 01:17:19 -- Murmur@NightmareDev hoped, yes...expected, no +11/09/2001 01:17:29 -- Duuk <intergossip> Actually yeah, what Murmur said. +11/09/2001 01:17:45 -- Vashkar@Split Infinity and you could have typed "man rm" beforehand to know what you're doing. +11/09/2001 01:17:53 -- Duuk nods. Prolly would have tipped you off.. +11/09/2001 01:18:07 -- Vashkar@Split Infinity I doubt it +11/09/2001 01:18:15 -- Badastaz@MudWorld well only assholes would do that +11/09/2001 01:18:21 -- Hergrom@NewMoon If you're referring to me as Herry, Duuk, my first night on igossip was about 2 years ago... +11/09/2001 01:18:23 -- Murmur@NightmareDev agrees wholeheartedly. +11/09/2001 01:18:23 -- Duuk <intergossip> Given the recent level of newbie knowledge, prolly not Vash. +11/09/2001 01:18:35 -- Duuk <intergossip> And I didn't get you to delete your mud? +11/09/2001 01:18:35 -- Duuk <intergossip> Damn. +11/09/2001 01:18:53 -- Duuk writes this down in a book. I wanna use that one again. +11/09/2001 01:19:05 -- Hergrom@NewMoon No... but you can still try. I don't have shell access, but I can delete a goodly portion of mages. +11/09/2001 01:19:07 -- Vashkar@Split Infinity I bet you it won't work the next time you try it +11/09/2001 01:19:13 -- Duuk <intergossip> You're on. +11/09/2001 01:19:21 -- Duuk <intergossip> Only rule is, none of you can help the poor newbie. +11/09/2001 01:19:29 -- Duuk <intergossip> Gotta be totally blind. +11/09/2001 01:19:35 -- Hergrom@NewMoon Done. +11/09/2001 01:19:39 -- Vashkar@Split Infinity oh, that's fine +11/09/2001 01:19:55 -- Murmur@NightmareDev it could have been worse...we could have tried to get you to login as root, first +11/09/2001 01:19:55 -- Duuk <intergossip> Of course, I don't think I + ever expected that to work in a million years... +11/09/2001 01:20:01 -- Vashkar@Split Infinity you're going DOWN, Duuk.. I'm betting absolutely no one is more clueless than the newbie we've just witnessed +11/09/2001 01:20:13 -- Duuk nods. I was "" this close to telling you to make sure you were root and flushing the buffer from / +11/09/2001 01:20:15 -- Murmur@NightmareDev lots of people are that clueless +11/09/2001 01:20:19 -- Hergrom@NewMoon I'd be willing to give 5 to +1 odds against Duuk, though. Not possible there could be _another_ newbie that clueless. +11/09/2001 01:20:37 -- Senir@MudWorld just me or did i hear bout someone pulling the rm joke on bad? +11/09/2001 01:20:41 -- Hergrom@NewMoon Yeah, what Vashkar said. +11/09/2001 01:20:43 -- Duuk nods at Senir. +11/09/2001 01:20:45 -- Duuk <intergossip> Senir. +11/09/2001 01:20:47 -- Duuk <intergossip> It worked, too. +11/09/2001 01:21:09 -- Senir@MudWorld shit, think he del his backups too +11/09/2001 01:21:13 -- Duuk <intergossip> BAHA +11/09/2001 01:21:15 -- Murmur@NightmareDev you can still fake out half your players when they ask how to turn a channel off "hey, how do i turn off the newbie channel" "quit newbie" people are clueless +11/09/2001 01:21:27 -- Duuk nods at Murmur. I like that one. +11/09/2001 01:21:31 -- Vashkar@Split Infinity alright, Senir.. did you give him site access? +11/09/2001 01:22:03 -- Hergrom@NewMoon I'm assuming you have some semblance of a clue, Senir... how could you give him access? +11/09/2001 01:22:07 -- Senir@MudWorld he runs his own mud, i help people throughout imc2 network and all that, i don't have power over shells or anything +11/09/2001 01:22:13 -- Hergrom@NewMoon have given. Whatever. +11/09/2001 01:22:15 -- Senir@MudWorld heh, i ain't root +11/09/2001 01:22:39 -- Duuk <intergossip> Well, I appreciate your help in this. I haven't laughed this hard in days. +11/09/2001 01:22:49 -- Murmur@NightmareDev Someone should make a webpage with a log of this. Something we can point to when we need to lecture yet another person why "starting your own mud when you don't have a clue" is a Bad Idea. +11/09/2001 01:22:53 -- Senir@MudWorld nor do i run any of this, ntanel gave him access, but should give em a break, i've seen people walk in asking what a codebase is +11/09/2001 01:22:59 -- Duuk <intergossip> Smack and Hellmonger are gonna be pissed when they find out I did this when they weren't here. diff --git a/lib/domains/town/txt/shame/chapter02 b/lib/domains/town/txt/shame/chapter02 new file mode 100644 index 0000000..0ae6096 --- /dev/null +++ b/lib/domains/town/txt/shame/chapter02 @@ -0,0 +1,89 @@ +chapter 2 "The Demise of Wolfsong" + +[25Nov2005-23:13:06] Wolfsong@Aurora Sky <imud_gossip> Hello. +[25Nov2005-23:13:30] Wolfsong@Aurora Sky <imud_gossip> Hmm, someone on my staff got this to work. Razz +[25Nov2005-23:13:38] Duuk@Haven <imud_gossip> fuck +[25Nov2005-23:15:03] Berun@Aurora Sky <imud_gossip> hello everyone +[25Nov2005-23:15:07] Wolfsong@Aurora Sky <imud_gossip> Now, that's a dirty word. +[25Nov2005-23:15:11] Duuk@Haven <imud_gossip> shut the fuck up, n00b., +[25Nov2005-23:15:25] Wolfsong@Aurora Sky <imud_gossip> Aww, you sound upset. +[25Nov2005-23:15:25] Gary@Void <imud_gossip> Hey all. +[25Nov2005-23:15:35] Gary@Void <imud_gossip> Duuk is just having a bad day^W life. +[25Nov2005-23:15:37] Duuk@Haven <imud_gossip> jesus it's a fucking retard convention +[25Nov2005-23:16:49] Wolfsong@Aurora Sky <imud_gossip> Ah. I don't think that's an appropriate reason to immediately attack someone new, readily making assumptions about my intelligence. It shows a level of mental mediocrity. +[25Nov2005-23:17:05] Duuk@Haven <imud_gossip> You're a newbie mud admin. It's safe to assume you're a fuckin tard. +[25Nov2005-23:17:17] Gary@Void <imud_gossip> Actually, Duuk has a very valid point there. +[25Nov2005-23:17:25] <imud_gossip> Duuk@Haven nods solemnly. +[25Nov2005-23:17:27] Duuk@Haven <imud_gossip> See! +[25Nov2005-23:17:29] cratylus@Dead Souls <imud_gossip> amen +[25Nov2005-23:18:04] Vanyel@Haven <imud_gossip> No offense and all. It's just a statistical analysis. This way they save time. +[25Nov2005-23:18:22] Wolfsong@Aurora Sky <imud_gossip> So, being new to adminship means I have a low IQ. Except, according to current theory in psychology, it is impossible to raise your IQ. So, as you are experienced admins, you too, have low IQs. +[25Nov2005-23:18:36] cratylus@Dead Souls <imud_gossip> heh +[25Nov2005-23:18:42] Duuk@Haven <imud_gossip> No. We were here before any tard could open a mud. +[25Nov2005-23:18:42] cratylus@Dead Souls <imud_gossip> you're not helping yourself, guy +[25Nov2005-23:18:56] Duuk@Haven <imud_gossip> Haven first ran on a 486 with 16 meg of ram. +[25Nov2005-23:19:02] Duuk@Haven <imud_gossip> It ran like shit, but it ran. +[25Nov2005-23:19:04] Zakk@Lima Bean <imud_gossip> uphill both ways +[25Nov2005-23:19:06] Wolfsong@Aurora Sky <imud_gossip> I'm female. And rather educated. +[25Nov2005-23:19:14] cratylus@Dead Souls <imud_gossip> well that explains you +[25Nov2005-23:19:16] Duuk@Haven <imud_gossip> Liar on 2 points. +[25Nov2005-23:19:22] Zakk@Lima Bean <imud_gossip> female? pics of tits, now +[25Nov2005-23:19:28] <imud_gossip> Duuk@Haven agrees. +[25Nov2005-23:19:32] Duuk@Haven <imud_gossip> bikiniphotos. now. +[25Nov2005-23:19:40] Gary@Void <imud_gossip> I'm sorry, but I'm gonna have to go agree with Zaak and Duuk on this Sad +[25Nov2005-23:19:40] Wolfsong@Aurora Sky <imud_gossip> LoL. You don't want those. +[25Nov2005-23:19:42] Zakk@Lima Bean <imud_gossip> bikini? wtf +[25Nov2005-23:19:56] cratylus@Dead Souls <imud_gossip> http://rugose.com/showus.jpg +[25Nov2005-23:19:56] Duuk@Haven <imud_gossip> Wolfy, we've seen worse. +[25Nov2005-23:19:56] Gary@Void <imud_gossip> No such thing as a Female + MUDer + Coder + Admin. +[25Nov2005-23:20:02] Duuk@Haven <imud_gossip> Trust Me. +[25Nov2005-23:20:06] Duuk@Haven <imud_gossip> Hey, Laoise is an admin. +[25Nov2005-23:20:14] Duuk@Haven <imud_gossip> Of course, we're all pretty sure she's a guy. +[25Nov2005-23:20:26] Zakk@Lima Bean <imud_gossip> I'm fairly certain of that myself +[25Nov2005-23:20:28] Wolfsong@Aurora Sky <imud_gossip> Wow, not only are they pretentious shits, they're sexist pigs as well. +[25Nov2005-23:20:36] Gary@Void <imud_gossip> I passed as a girl on the internet for about a year once. +[25Nov2005-23:20:38] cratylus@Dead Souls <imud_gossip> wolfsong, just stfu +[25Nov2005-23:20:40] Gary@Void <imud_gossip> It's not hard to do Neutral +[25Nov2005-23:20:40] Duuk@Haven <imud_gossip> This is low-key. You should see when you really get us going. +[25Nov2005-23:20:54] Vanyel@Haven <imud_gossip> You know of pretentious shits that aren't sexist pigs? +[25Nov2005-23:20:56] Communist@Islands of Myth <imud_gossip> girls don't exist on the internet +[25Nov2005-23:20:56] Wolfsong@Aurora Sky <imud_gossip> Make me, shithead. +[25Nov2005-23:21:06] cratylus@Dead Souls <imud_gossip> heh, and here i was, trying to help you +[25Nov2005-23:21:10] Zakk@Lima Bean <imud_gossip> you into anal? +[25Nov2005-23:21:10] Duuk@Haven <imud_gossip> I mean, the conversation just started. We haven't even asked you if you like anal sex yet. +[25Nov2005-23:21:12] cratylus@Dead Souls <imud_gossip> then you go and call me names +[25Nov2005-23:21:14] <imud_gossip> Gary@Void rolls on the floor laughing. +[25Nov2005-23:21:29] Wolfsong@Aurora Sky <imud_gossip> Well, you did throw the first blows. Smile +[25Nov2005-23:21:31] cratylus@Dead Souls <imud_gossip> i think you're the arrogant pretentious one, wolfsong +[25Nov2005-23:21:33] Duuk@Haven <imud_gossip> damn. timed that one SLIGHTLY too late +[25Nov2005-23:21:49] cratylus@Dead Souls <imud_gossip> coming on here, expecting everyone to welcome your pointless brainwaves +[25Nov2005-23:22:11] Wolfsong@Aurora Sky <imud_gossip> So much for friendly MUD development. +[25Nov2005-23:22:15] Jayren@Dead Souls <imud_gossip> fuck. i don't need comedy central anymore. i'll just come watch igos. +[25Nov2005-23:22:17] Gary@Void <imud_gossip> Wolfsong, from my experiences, MUDs usually don't have very friendly people. If you want friendly, go the way of talkers, MUSHes, MOOs, etc. +[25Nov2005-23:22:27] Duuk@Haven <imud_gossip> ooOoO, mushes! +[25Nov2005-23:22:29] Wolfsong@Aurora Sky <imud_gossip> I wonder why your MUDs aren't popular, even though you've been here for oh so long.. hmmm. +[25Nov2005-23:22:33] Duuk@Haven <imud_gossip> ICQ for people without ICQ! +[25Nov2005-23:22:41] Duuk@Haven <imud_gossip> Who said our muds weren't popular? +[25Nov2005-23:22:49] Gary@Void <imud_gossip> I have four who people on my MUD. +[25Nov2005-23:22:49] Laoise@Haven <imud_gossip> Is someone talking about me having a dick again? I sense a disturbance in the force. +[25Nov2005-23:22:53] Duuk@Haven <imud_gossip> I have 5 people on and the damn mud is closed for the weekend. +[25Nov2005-23:23:07] Gary@Void <imud_gossip> whole* +[25Nov2005-23:23:09] Wolfsong@Aurora Sky <imud_gossip> Laff. +[25Nov2005-23:23:11] Duuk@Haven <imud_gossip> Laoise, at least we think you have a BIG dick. +[25Nov2005-23:24:03] Duuk@Haven <imud_gossip> anytime. time to unfuck another DescartesFunction[tm] +[25Nov2005-23:24:13] Duuk@Haven <imud_gossip> Crat, you ever mess with eventEquip() in the armour lib? +[25Nov2005-23:24:19] cratylus@Dead Souls <imud_gossip> have i ever +[25Nov2005-23:24:21] <imud_gossip> Laoise@Haven has a dick the size of Ninja. We know this. +[25Nov2005-23:24:31] Duuk@Haven <imud_gossip> Ninja's dick, or all of Ninja? +[25Nov2005-23:24:31] cratylus@Dead Souls <imud_gossip> that is some fucked up shit right there +[25Nov2005-23:24:39] Laoise@Haven <imud_gossip> All of Ninja. Duh. +[25Nov2005-23:24:52] Duuk@Haven <imud_gossip> I redid eventDescribeEnvironment() earlier. That one made baby jesus cry. +[25Nov2005-23:24:54] Laoise@Haven <imud_gossip> It's not funny if it's the same size as Ninja's. +[25Nov2005-23:24:56] Duuk@Haven <imud_gossip> I think this one will be worse. +[25Nov2005-23:45:02] Wolfsong@Aurora Sky <imud_gossip> Mwah. +[25Nov2005-23:45:38] Gary@Void <imud_gossip> Maw? +[25Nov2005-23:45:52] Wolfsong@Aurora Sky <imud_gossip> MWAH. +[25Nov2005-23:46:10] Duuk@Dead Souls <imud_gossip> You didn't die yet? +[25Nov2005-23:46:22] Wolfsong@Aurora Sky <imud_gossip> No, not yet. +[25Nov2005-23:46:24] Duuk@Dead Souls <imud_gossip> Damn. +[25Nov2005-23:46:50] Wolfsong@Aurora Sky <imud_gossip> New people are like cockroaches. You hate them, but they'll outlive you. diff --git a/lib/domains/town/txt/shame/chapter03 b/lib/domains/town/txt/shame/chapter03 new file mode 100644 index 0000000..be81970 --- /dev/null +++ b/lib/domains/town/txt/shame/chapter03 @@ -0,0 +1,1231 @@ +chapter 3 "September 11 2001 (Warning: not that funny)" + +[igossip] Hellmonger@Trilogy: actually, I think efnet.net got rooted and they +just took the server down. +[igossip] Alric@Nanvaent: efnet is still up. +[igossip] Smack@Lima Bean: ZIONIST NAZIS!!!!!!!!!!!!!!!!!! +[igossip] Motorhed@Trilogy says, "Four out of five doctors agree. I am the +fifth doctor. I hope you die. Fuck you." +[igossip] Shandor@Bakhara: we had a student riot over the weekend! +[igossip] Malic@Lima Bean: +http://mdn.mainichi.co.jp/waiwai/0109/010909diet.html. +[igossip] Blue@Lima Bean: of all the igossip questions for me to be able to +answer, one about boxer shorts was _not_ the one I expected. +[igossip] Ninja@VargonMUD: SHARK!!! +[igossip] Zeddicus@Haven: ARBORPHILES!!! +[igossip] Ninja@VargonMUD: Once ya hug a lumberjack, ya'll never hug a tree +again! +[igossip] Hellmonger@Trilogy: THE NUKES ARE FALLING. +[igossip] Hellmonger@Trilogy: FRM THE SKIES. +[igossip] Hellmonger@Trilogy: AS TERRORISTS TORCH THE U.S. +[igossip] Hellmonger@Trilogy: ITS A HORIBLE DAY. +[igossip] Hellmonger@Trilogy: AHHHHHHHHH I'M MELTING. +[igossip] Al@Anarres II: HM, shut up. +[igossip] Hellmonger@Trilogy: I just heard two planes crahsed into the trade +center. +[igossip] Al@Anarres II: and very f*cking news iste is down for me ATM :( +[igossip] Zeddicus@Haven: Good for them. +[igossip] Nirvan@Nanvaent: yeah - two big jets. +[igossip] Hellmonger@Trilogy: Yeah, how fucked. +[igossip] Nirvan@Nanvaent: one for each tower - I 'm trying to work out if its +April 1st somewhere... +[igossip] Hellmonger@Trilogy: I vote we turn the fucking middle east into a +large sheet of glass. +[igossip] Al@Anarres II: its a terrorist thing! +[igossip] Hellmonger@Trilogy: I'm glad I don't live in england, where there are +a lot of terrorists. +[igossip] Al@Anarres II: it makes life fun! +[igossip] Al@Anarres II: nightly bulletins saying some irish bloke has shot +another. +[igossip] AndrewH@Anarres II: keeps the irish population down. like the potato +famine. +[igossip] Al@Anarres II nods +[igossip] Al@Anarres II: its most definetly terrorist. +[igossip] Al@Anarres II: two planes, two towers.. thats not just unlucky. +[igossip] Al@Anarres II: well, back to work... +[igossip] Zeddicus@Haven: A father came in the bedroom to find his 13-year-old +daughter smoking a cigarette. "My God! How long have you been smoking?" screams +the father. "Since I lost my virginity," replies the girl. "You lost your +VIRGINITY!!! When the hell did this happen?" shrieks the father. "I don't +remember," says the girl. "I was completely drunk." +[igossip] Smack@Lima Bean: holy fuck. +[igossip] Hellmonger@Trilogy: yeah no doubt. +[igossip] Hellmonger@Trilogy chants: "Nuke The Middle East! Nuke The Middle +East! Nuke The Middle East!" +[igossip] Al@Anarres II: why do you say its the middle east? you said that +about oklahoma and it was some US bloke. +[igossip] Styxx@OuterSpace: shaddup. +[igossip] Al@Anarres II: you HM, are a racist homophobe. +[igossip] Hellmonger@Trilogy: You are obviously a jew-sympathiser. You will +burn with your dirty hebrew friends. +[igossip] Al@Anarres II: hmmm. HM, shut the fuck up. +[igossip] Smack@Lima Bean: whoever it is must die. +[igossip] Hellmonger@Trilogy: Al, do you worship Osama Bin Laden? +[igossip] Hellmonger@Trilogy: Why can't people pick new and exciting targets +for their terrorist acts? +[igossip] Hellmonger@Trilogy: 'Lets blow up the world trade center!' 'Lets +crash into the world trade center!' +[igossip] Al@Anarres II grins at HM, "I only worship you" +[igossip] Hellmonger@Trilogy: Al, you must blow up the quik-mart. The infidels +must pay. +[igossip] Nirvan@Nanvaent: wouldn't it be a better statement to fly the plane +into the white house ? +[igossip] Sinistrad@VargonMUD: Harder to do. +[igossip] Nirvan@Nanvaent: or are the protests against the WTO stepped up from +hippies throwing rocks in the streets ? +[igossip] Nirvan@Nanvaent: *blinks* +[igossip] Al@Anarres II: maybe they were passenger planes and someone at air +traffic f*cked up? +[igossip] Sinistrad@VargonMUD: BREAKING NEWS: One of the planes was being flows +by Captain Hazelwood, of the Exxon Valdez! +[igossip] Nirvan@Nanvaent: harder than hijacking two 747s and flying them into +the center of NY ? +[igossip] Al@Anarres II: doesn;t Xyzzy have summin' to do with flying things? +[igossip] Sinistrad@VargonMUD: Yes, Nirvan. Why are you so... curious? +[igossip] Nirvan@Nanvaent: so the SDN is working over the white house then ? +[igossip] Sinistrad@VargonMUD: Try making a hijacked plane hit a ground target. +[igossip] Al@Anarres II: good point Sini. +[igossip] Nirvan@Nanvaent: ahh - so you've thought ab out this then ? +[igossip] Nirvan@Nanvaent: it is a good point. +[igossip] Sinistrad@VargonMUD: No, I just work for the FBI. But you, on the +other hand.. *shuffles papers* Nirvan, AKA "Idi Ib Amin".. why are YOU so +curious? +[igossip] Nirvan@Nanvaent: woo - breaking news. CNN have decided that it isn't +an accident ! +[igossip] Skullslayer@RoD: so anyone got a good news site with live feed, that +isn't down(DoS'd)? +[igossip] Nirvan@Nanvaent: turn on a TV ? +[igossip] Skullslayer@RoD: haha not an accident - thats clever +[igossip] Skullslayer@RoD: I'm at work, and there is no tv here +[igossip] Pickett@Sumu: +http://a799.ms.akamai.net/3/799/388/9ce0ee0b875c5d/www.msnbc.com/news/1160603.j +pg. +[announce] Xyzzy enters Frontiers. +[igossip] Nirvan@Nanvaent: MSN Search : We can't find "cnn.com". +[igossip] Nirvan@Nanvaent: oh god - someone's bombed CNN! +[cre] Cratylus: oi. +/wiz/cratylus # [igossip] Nirvan@Nanvaent: slashdot is even running the story - because CNN is +DOS'ed :) +[igossip] Al@Anarres II: is CCN DoS'd or just very busy? +[igossip] Sinistrad@VargonMUD: Try CNN instead of CCN. +[igossip] Sinistrad@VargonMUD: Maybe you'll get somewhere. +[igossip] Skullslayer@RoD: very busy is a DoS - so is MSNBC and ABCnews +[igossip] Al@Anarres II: DoS implied bad intent. +[igossip] Al@Anarres II: rather than just lots of happy punters. +[igossip] Vashkar@Split Infinity: haha.. dailynews.yahoo.com changed their +story to simply "A plane crashed into one of the twin towers of the World Trade +Center Tuesday, witnesses said." and that's it.. it loads just fine now :) +[igossip] Skullslayer@RoD: they're hit by the slashdot effect, except on a +bigger scale +[igossip] Xyzzy: wtf. +[igossip] Sinistrad@VargonMUD: Jesus, that's impressive. +[igossip] Cratylus: thats so fucked up. +/wiz/cratylus # [igossip] Undh@Sumu: impressive.. yeah .) +/wiz/cratylus # [igossip] Sinistrad@VargonMUD: If I were a terrorist, I would have waited until +more people were at work. +[igossip] Nirvan@Nanvaent: 9am isn't a bad time... +[igossip] Bayard@Nanvaent: morning meetings happening. people mainly in at 8am. +[igossip] Blue@Inon-Net: people start work at 8 in most of those companies. +[igossip] Bayard@Nanvaent: all gathered together in rooms. +[cre] Xyzzy: thats fucked up, dude. +[igossip] Nirvan@Nanvaent: a good day not to be too highly promoted I would +guess. +[igossip] Al@Anarres II: hmm, 2nd plane "was passenger 727"... oops. +[igossip] Skullslayer@RoD: yeah, FBI was investigating a report of a hijacking +at the time +[cre] Cratylus: bizarre. +/wiz/cratylus # [igossip] Nirvan@Nanvaent: bush wants to 'hunt down the people who did this' +[igossip] Al@Anarres II: nice - hijack a plane full of US citizen and then +crash it into the trade center :) sweet. +[igossip] Nirvan@Nanvaent: get me my gun, maw... +[igossip] Cratylus: well it's easier than carting a bomb in there, with their +current security. +/wiz/cratylus # [igossip] Sinistrad@VargonMUD: look in 'the charred remains between floor 98 +and 99' +[igossip] Nirvan@Nanvaent: seems there is a 3rd plane that's been hijacked ? +[igossip] Cratylus: i guess they'll need to install antiaricraft turrets now. +/wiz/cratylus # [igossip] Xyzzy: YES! +[igossip] Hellmonger@Trilogy: hell yeah. +[igossip] Sinistrad@VargonMUD: Whoever invents the force field will make a +billion. +[igossip] Xyzzy: but, we already HAVE. +[igossip] Al@Anarres II: if someone wants to be a terrorist, they'll be a +terrorist. +[igossip] Xyzzy: the antimissile shield will protect us! +[igossip] Cratylus: and if they want to sing out, sing out. +/wiz/cratylus # [igossip] Styxx@OuterSpace: asia.cnn.com still works. +[igossip] Skullslayer@RoD: a 3rd plane? +[igossip] Nirvan@Nanvaent: the pentagon is on fire. +[igossip] Steve@Anarres II: pentagon on fire? +[igossip] Cratylus: cats and dogs, living together. +/wiz/cratylus # [igossip] Nirvan@Nanvaent: and the palestinians are claiming responsibility. +[igossip] Xyzzy: dont cross the streams. +[igossip] Nirvan@Nanvaent: and my boss wanted me to go to israel last week. +[igossip] Sinistrad@VargonMUD: Ooh, ht//praiseallah.terrorists.com has the +inside report! +[igossip] Cratylus: jesus, a 767 +/wiz/cratylus # [igossip] Sinistrad@VargonMUD: The pentagon IS on fire! +[igossip] Cratylus: thats a lot of aircraft. +/wiz/cratylus # [igossip] Xyzzy: wow. +[igossip] Sinistrad@VargonMUD: WOOOOOOO!!!!! +[igossip] Xyzzy: co-worker just said pentgon IS on fire. +[igossip] Sinistrad@VargonMUD: Shit, this is really cool. +[igossip] Al@Anarres II: cool :) You guys have better terrorists! +[igossip] Sinistrad@VargonMUD: Guys, if you're in any kind of important +building.. RUN! +[igossip] Hellmonger@Trilogy: My Unc works at the pentagon. :( +[igossip] Cratylus: did they drop a plane on the pentagon as well? +/wiz/cratylus # [igossip] Xyzzy: fuck this, im goin home. +[igossip] Sinistrad@VargonMUD: Not so happy now, eh? +[igossip] Al@Anarres II cheers for Xyzzy +[igossip] Hellmonger@Trilogy: heh. +[igossip] Xyzzy: no, as in, i dont wanna be in this building. +[igossip] Sinistrad@VargonMUD: Wtf, is today Allah's birthday or something? +[igossip] Cratylus: can someone post a burning-pentagon url? +/wiz/cratylus # [igossip] Nirvan@Nanvaent: white house has been evacuated. +[igossip] Nirvan@Nanvaent: pentagon is on fire, and been evacuated. +[igossip] Blue@Inon-Net: if you were going to start a nuclear war, which two +buildings would you want to have evacuated first? +[igossip] Nirvan@Nanvaent: today is the 20th anniversary of the UN +international day of peace. +[igossip] Blue@Inon-Net: I guess they still have NORAD or some such place. +[igossip] Nirvan@Nanvaent: but war games was on the TV at the weekend. +[igossip] Sinistrad@VargonMUD: No shit, Nirvan? +[igossip] Nirvan@Nanvaent: I know how to get in ther! +[igossip] Cratylus: i'm too tired for this to be Anarchy Day. +/wiz/cratylus # [igossip] Xyzzy: hmm, that is, if i CAN leave... +[igossip] Sinistrad@VargonMUD: I know how to get into the Pentagon, too: +Through the gaping hole. +[igossip] Al@Anarres II: the pentagon has like, 12 stories going down and a +power plant and such. Its paper pushers up top. +[cre] Cratylus: is the pentagon really burning? +/wiz/cratylus # [cre] Xyzzy: yes. +[cre] Xyzzy: it was bombed. +[cre] Cratylus: whew. +/wiz/cratylus # [cre] Xyzzy: apparently. +[cre] Xyzzy: this base is closed. +[cre] Xyzzy: no one gets on. +[igossip] Al@Anarres II: this is class :) brightened up my afternoon no end. +[igossip] Cratylus: all your trade center are belong to us. +/wiz/cratylus # [igossip] Nirvan@Nanvaent: CNN showing a big fire near washington. +[cre] Cratylus: i'd go home. +/wiz/cratylus # [cre] Cratylus: traffic will really suck later. +/wiz/cratylus # [igossip] Skullslayer@RoD: slashdot is down now too :) +[igossip] Diruces@Mystic: they say they have exvacuated the west wing of the +whitehouse too. +[cre] Cratylus: and they'll drop a plane on the highway. +/wiz/cratylus # [igossip] Nirvan@Nanvaent: I saw a comment on slashdot wondering if there was a +'cyberattack' going on at the same time - what a dumb fuckwith. +[igossip] Skullslayer@RoD: most people on slashdot are fuckwits +[igossip] Nirvan@Nanvaent: where is washington amll ? +[igossip] Nirvan@Nanvaent: where is washington mall even. +[igossip] Xyzzy: lessee.... commerce... military... +[igossip] Sinistrad@VargonMUD: Around the Pentagon. +[igossip] Diruces@Mystic: next the whitehouse. +[igossip] Xyzzy: mall is accross the river, in VA. +[igossip] Xyzzy: er. +[igossip] Xyzzy: the pentagon is in VA. +[igossip] Cratylus: thank god, whitehouse.com hasn't been bombed. +/wiz/cratylus # [cre] Xyzzy: really, whats next. +[igossip] Sinistrad@VargonMUD: Your old password still work there? +[igossip] Diruces@Mystic: i like the idea of cheney as pres. +[igossip] Nirvan@Nanvaent: apparently the pentagon fire was caused by a plane +or rocket attack. +[cre] Xyzzy: "if this was a coordinated attack, what ELSE might be happening +rigt now?" +[cre] Xyzzy: then tehre weas the pentagon. +[igossip] Nirvan@Nanvaent: bush is at some school somewhere. +[igossip] Nirvan@Nanvaent: probs learning how to spell. +[igossip] Sinistrad@VargonMUD: Was. +[igossip] Nirvan@Nanvaent: the third hijacked plane apparently hit the +pentagon. +[igossip] Al@Anarres II: bush is in a bunker! +[igossip] Xyzzy: what. +[igossip] Xyzzy: next. +[igossip] Blue@Inon-Net: playing golf at a time like this... just like his dad. +[igossip] Cratylus: with his teddy bear. +/wiz/cratylus # [igossip] Nirvan@Nanvaent: well, he was in a bunker with lots of school kids +around him. +[igossip] Xyzzy: any bets? +[igossip] Nirvan@Nanvaent: unless they recorded it. +[igossip] Cratylus: curled up under a desk. +/wiz/cratylus # [igossip] Xyzzy: thumb in mouth. +[igossip] Xyzzy: rockingh back n forth. +[igossip] Nirvan@Nanvaent: xyzzy : 10 to 1, jenna bush gets drunk and falls +around in public in downtown austin this weekend. +[igossip] Nirvan@Nanvaent: naw, make that 2 to 1 +[igossip] Nirvan@Nanvaent: bbc is reporting 6 people killed in the crashes +(that all ???) +[igossip] Cratylus: "Jenna Bush's federally protected wetlands now open for +public drilling" +/wiz/cratylus # [igossip] Nirvan@Nanvaent: FAA has grounded all flights in the US. +[cre] Cratylus: it's days like this when i kinda wish i had cable tv. +/wiz/cratylus # [igossip] Musashi@Sumu: where'd you read that? +[igossip] Nirvan@Nanvaent: AP. +[cre] Xyzzy: we have a tv, but theres a meeting in tehre now. +[cre] Xyzzy: i hafta rely on YOU GUYS for news. +[cre] Cratylus: ME? +/wiz/cratylus # [cre] Cratylus: i dunno NOTHIN. +/wiz/cratylus # [cre] Xyzzy: hmm, should i go home? +[igossip] Nirvan@Nanvaent: 'the associated press' +[igossip] Nirvan@Nanvaent: or the standard 'newswire' +[igossip] Sinistrad@VargonMUD: CONFIRMED: It was a plane that crashed into the +Pentagon, too. +[igossip] Sinistrad@VargonMUD: CNN is law. +[igossip] Sinistrad@VargonMUD: If CNN makes up stuff about aliens, I believe +it. +[igossip] Nirvan@Nanvaent: who was saying it was really difficult to hit ground +targets with planes ? :) +[igossip] Nirvan@Nanvaent: did they miss ? +[igossip] Sinistrad@VargonMUD: "Aliens crashed into the Pentagon" I'll believe +it. +[igossip] Skullslayer@RoD: heh, lots of the US govt agencies get their info +from CNN since its cheaper than having their own people in the field +[igossip] Blaze@VargonMUD: All american flights have been grounded. +[igossip] Nirvan@Nanvaent: it was - illegal Aliens crashed into the Pentagon. +[igossip] Sinistrad@VargonMUD: Heh =-) +[igossip] Xyzzy: ALIENS BOMBED THE PENTAGON?!?! +[igossip] Cratylus: those two targets seem kinda pointless to. +/wiz/cratylus # [igossip] Cratylus: me. +/wiz/cratylus # [igossip] Nirvan@Nanvaent: which ones ? +[igossip] Xyzzy: "she thought they said 'ILLEGAL aliens' and signed up" +[igossip] Bayard@Nanvaent: symbolic Crat. +[igossip] Cratylus: they shoulda found bush's locaation and dropped a plane on +him. +/wiz/cratylus # [igossip] Bayard@Nanvaent: very symbolic. especially outside of US. +[igossip] Sinistrad@VargonMUD: Maybe it was Jenna Bush flying daddy's plane. +[igossip] Nirvan@Nanvaent: he was in a school. +[igossip] Al@Anarres II: hijacking any plane and crashing it is gonna get you +coverage. +------------------------------------------------------------------------ + F r o n t i e r s + (EDT is: Tue Sep 11 09:53:36 2001) + There are 3 users connected. +------------------------------------------------------------------------ +Xyzzy 4s Low Crawl access4.digex.net +Zaphod 11h empty plain 77.163.252.64.snet.net +Cratylus Cratylus' Cubicle cratylus +------------------------------------------------------------------------ +/wiz/cratylus # [igossip] Blue@Inon-Net: American spy plane disappeared over Iraq today. +[igossip] Sinistrad@VargonMUD: Xy, the actress who played Valdez in that movie +actually showed up at casting time thinking the movie WAS about illegal aliens. +They kept the "inside joke" in the movie. +[igossip] Nirvan@Nanvaent: unmanned US spy plane. +[igossip] Cratylus: vasquez. +/wiz/cratylus # [igossip] Xyzzy: ya, i read that on IMDB :) +[igossip] Nirvan@Nanvaent: you know the real big question about all this ? +Who has the movie rights ? +[igossip] Xyzzy: me. +[igossip] Nirvan@Nanvaent: when will Tom Clancey's book come out ? +[igossip] Blue@Inon-Net: Tom Clancy already wrote this book :) +[igossip] Bayard@Nanvaent: "Why hasn't Tom Clancy forseen this!" +[igossip] Cratylus: clancey's book will have biological weapons in the planes. +/wiz/cratylus # [igossip] Blue@Inon-Net: I bet that's where they got the idea. +[igossip] Skullslayer@RoD: he did the book years ago +[igossip] Xyzzy: wait, whata bout the unmanned Am. spyplane? +[igossip] Al@Anarres II: I lost one of my peers in NYC... wonder why. +[igossip] Cratylus: im still waiting for them to nuke a football stadium, like +he said. +/wiz/cratylus # [igossip] Xyzzy: ah, ok, i see the story. +[igossip] Nirvan@Nanvaent: israel was moving in to palestine today - +[igossip] Xyzzy: GIT MAH GUN! +[igossip] Cratylus: they highjacked an unmanned us spy plane and crashed it +into the iraqui desert! those madmen! +/wiz/cratylus # [igossip] Musashi@Sumu: so has anyone claimed responsibility for this yet? +[igossip] Nirvan@Nanvaent: palestinians, +[igossip] Nirvan@Nanvaent: the IRA, Iraq want a piece... +[igossip] Bayard@Nanvaent: the NBA. +[igossip] Nirvan@Nanvaent: problem is, everyone will try to claim it. +[igossip] Xyzzy: not to jinx us, but it seems that you never know when the shit +is gonna hit the fan like this. +[igossip] Cratylus: the judean people's front. +/wiz/cratylus # [igossip] Xyzzy: SPLITTERS! +[igossip] Blue@Inon-Net: it's the anti-globalisation protesters. +[igossip] Bayard@Nanvaent: people's judean front. +[igossip] Blue@Inon-Net: think about it: the World Trade Centre. +[igossip] Xyzzy: and? +[igossip] Iain@Anarres II: popular peples front of judea. +[igossip] Blue@Inon-Net: They got it confused with the WTO. +[igossip] Xyzzy: WWF? +[igossip] Izzy@VargonMUD: I think it was just a big misunderstanding. +[igossip] Nirvan@Nanvaent: state dept on fire. +[igossip] Nirvan@Nanvaent: another plane just hit. +[igossip] Xyzzy: WHAT? +[igossip] Nirvan@Nanvaent: south tower of the WTO has collapsed. +[igossip] Presto@Discworld: fuckin hell. +[igossip] Musashi@Sumu: jesus, I'm not going to be able to get cricket results +for the next 4 weeks with this flooding the news... +[igossip] Xyzzy: at least we dont hafta hear about gary conit anymore. +[igossip] Xyzzy: er, conDit. +[igossip] Nirvan@Nanvaent: capitol building and treasury evacuated. +[igossip] Nirvan@Nanvaent: most of manhantten under smoke/ on fire. +[igossip] Al@Anarres II goes to thebunker.net +[igossip] Blaze@VargonMUD: And a couple in SF. The trans-america building too. +[igossip] Nirvan@Nanvaent: sears tower in chicago attacked too. +[igossip] Al@Anarres II: nice! +[igossip] Xyzzy: overheard at work: USA today building. +[igossip] Presto@Discworld: not attacked, evacuated. +[igossip] Al@Anarres II lives no where near anything tall :) +[igossip] Cratylus: can't believe it didnt occur to them to drop a plane on +clinton's harlem office. +/wiz/cratylus # [igossip] Nirvan@Nanvaent: who cares about clinton ? +[igossip] Cratylus: best way to intimidat current presidents is killing former +ones. +/wiz/cratylus # [igossip] Nirvan@Nanvaent: saw the 'third explosion' replay - looked like the +building just collapsed inwards. +[igossip] Al@Anarres II: nice, the BBC have "given up" trying to get their +sites up :)) +[igossip] Skullslayer@RoD: clinton is in australia at the moment anyway +[igossip] Pickett@Sumu: wtc collapsed? +[igossip] Skullslayer@RoD: south tower +[igossip] Cratylus: the whole thing fell? +/wiz/cratylus # [igossip] Tarl@Alsherok: He is ? Crap. Any idea where in Australia ? +[igossip] Presto@Discworld: top half. +[igossip] Presto@Discworld: as opposed to the bottom half. +[igossip] Skullslayer@RoD: golf resort +[igossip] Xyzzy: heh. +[igossip] Cratylus: that is a lot of cead people. +/wiz/cratylus # [igossip] Xyzzy: so, sears tower, too? +[igossip] Cratylus: hard to believe so much of it would fall off from a plane +crash. +/wiz/cratylus # [igossip] Presto@Discworld: no. +[igossip] Xyzzy: fuck, i need a list, here. +[igossip] Pickett@Sumu: ... President Bush, .. from a school in Sarasota, +Fla... +[igossip] Presto@Discworld: Well, Jesus, it wasn't a Cessna, it was a frigging +737/767 depending on who you believe. +[igossip] Cratylus: i say we cut off aid to israel until they handle their +terrorist problem. +/wiz/cratylus # [igossip] Pickett@Sumu: total three planes crashed in wtc. the last one caused +the tower to collapse. +[igossip] Xyzzy: overheard at work: whitehouse has smoke comng out of it. +[igossip] Blue@Inon-Net: it's not exactly "their" problem any more. +[igossip] Sinistrad@VargonMUD: BREAKING NEWS: Dave Matthew's song "Crash into +me" said to have inspired the terrorists! +[igossip] Cratylus: well its all coming from there, one way or another. +/wiz/cratylus # [igossip] Xyzzy: THREE? +[igossip] Presto@Discworld: It didn't look to me like there was a third crash +into the WTC, looked like it just fell. +[igossip] Cratylus: it aint the IRA dropping planes in NYC. +/wiz/cratylus # [igossip] Pickett@Sumu: yeah, a third (smaller) plane in the bottom part of the +tower caused it to fall. +[igossip] Xyzzy: maybe they stored a plane in the basement. +[igossip] Presto@Discworld: CNN now says the Sears Tower has NOT been +evacuated. +[igossip] Blue@Inon-Net: if I were working there, I'd have evacuated. +[igossip] Sinistrad@VargonMUD: Thank you, Presto. *Presses a button labeled +"Sears"* +[igossip] Cratylus: if i worked there, i'd have evacuated my bowels. +/wiz/cratylus # [igossip] Skullslayer@RoD: is the whitehouse hit confirmed? +[igossip] Cratylus: no whitehouse.com is safe. +/wiz/cratylus # [igossip] Cratylus: and how do you slay a skull, anyway? +/wiz/cratylus # [igossip] Skullslayer@RoD: very carefully +[igossip] Xyzzy: with a skullslaying device. +[igossip] Skullslayer@RoD: exec building next to the whitehouse hit? +[igossip] Sinistrad@VargonMUD: Jesus Christ! +[igossip] Al@Anarres II: well, the Dow and NASDAQ are both up. +[igossip] Xyzzy: alright, everyone keep their rumors to themselves, please only +give us confirmed hits. +[igossip] Blue@Inon-Net: is he responsible, or been hit? +[igossip] Presto@Discworld: trading is closed. +[igossip] Vashkar@Split Infinity: capitol hill .. another explosion. +[igossip] Al@Anarres II: would all US resident, please leave the country. +[igossip] Cratylus: remain calm, do not run. +/wiz/cratylus # [igossip] Al@Anarres II: head for Canada! +[igossip] Sinistrad@VargonMUD: I miss the twin towers. +[igossip] Xyzzy: pretty sad when im relying on you guys for news. +[igossip] Myrias@Discworld: I logged on for news too. +[igossip] Blue@Inon-Net: they'll have to reprint all those NYC t-shirts, shot +glasses, posters, everything. +[cre] Cratylus: thats pathetic. +/wiz/cratylus # [igossip] Myrias@Discworld: The major news websites are all crashing under the +weight of traffic. +[cre] Cratylus: i cant believe cnn got overwhelmed. +/wiz/cratylus # [igossip] Blue@Inon-Net: no, they've been hit by more planes! +[igossip] Skullslayer@RoD: so, any bets on the FBI or CIA going out next? +[cre] Cratylus: dispensing breaking news is their JOB. +/wiz/cratylus # [cre] Cratylus: i wnt them FIRED. +/wiz/cratylus # [igossip] Xyzzy: youd think cnn would be their FIRST target. +[cre] Xyzzy: yer on cre. +[igossip] Bayard@Nanvaent: anyone started any rumours about massive virtual +terrorism attack on the US websites? +[cre] Cratylus: i know. +/wiz/cratylus # [igossip] Musashi@Sumu: no way, they want people to know. +[cre] Xyzzy: ah. +[igossip] Bayard@Nanvaent: i'm sure there's mileage in that one. +[igossip] Xyzzy: anyone familiar with the laws concerning gun possession and +transport in the state of maryland? +[igossip] Al@Anarres II: right now X, no one will care. +[igossip] Xyzzy: GOOD POINT! +[igossip] Presto@Discworld: explosion on Capitol hill. +[igossip] Xyzzy: where. +[igossip] Presto@Discworld: or not. +[cre] Cratylus: cant believe i have to turn on the radio for news now. +/wiz/cratylus # [igossip] Vashkar@Split Infinity: no, that's what happened. +[igossip] Xyzzy: is todays date of any signifigance? +[igossip] Skullslayer@RoD: apparently CNN is reporting a Capitol Hill hit +[igossip] Presto@Discworld: I wish people would get their fucking story +straight. :-b. +[igossip] Sinistrad@VargonMUD: 20th anniversary of world peace, Xy. +[igossip] Sinistrad@VargonMUD: CNN is reporting everything's ok on Capitol +Hill, except a loud sound. +[igossip] Vashkar@Split Infinity: oh. +[igossip] Presto@Discworld: CNNfn is talking to someone on Pennsylvania Ave, +and they said there's no explosion. +[igossip] Izzy@VargonMUD: It's the Democrats complaining. +[igossip] Cratylus: npr's interviewing freaked out WTC occupants. +/wiz/cratylus # [igossip] Xyzzy: now THATS journalistic integrity. +[igossip] Cratylus: it's quite tedious. +/wiz/cratylus # [igossip] Xyzzy: can you imagine the traffic and general panic? +[igossip] Cratylus: huh. the upper part of one of them did in fact collapse. +/wiz/cratylus # [igossip] Skullslayer@RoD: a few players here have confirmed capitol hill as +being hit +[igossip] Blue@Inon-Net: Interesting that of all the scary talk over recent +years about how easy it would be for terrorists to deploy biological, chemical, +nuclear or other fancy weapons in NYC, that when it actually happens, it could +have been done the same way 20 years ago. +[igossip] Presto@Discworld: Empire State building now evacuated. Duh. +[igossip] Sinistrad@VargonMUD: Yes, thanks, 30 minute ago man. +[igossip] Xyzzy: plane bombings is SO last decade. +[igossip] Blue@Inon-Net: I wonder how they'll persuade King Kong to come down. +[igossip] Cratylus: hey, i'm not gonna believe YOU bozos. +/wiz/cratylus # [igossip] Xyzzy: screw YOU guys, ah'm goin HOME. +[igossip] Sinistrad@VargonMUD: Famous last words, target! +[igossip] Skullslayer@RoD: nah, it was 'fore!' +[igossip] Tarl@Alsherok: In case no one said it, it appears one of the planes +was american airlines flight number 11, I hope no one knew anyone supposed to +be on that.. +[igossip] Al@Anarres II: so one tower has fallen over completly? +[igossip] Cratylus: no. the upper part of one collapsed. +/wiz/cratylus # [igossip] Xyzzy: it has fallen UP. +[igossip] Cratylus: not clear if it actually hit the ground. +/wiz/cratylus # [igossip] Al@Anarres II: from news feed I have heard about, its fallen over +completly? +[igossip] Sinistrad@VargonMUD: It's just floating there. +[igossip] Xyzzy: the Good Samaratin Terrorist Organization has built it back +up. +[igossip] Al@Anarres II ponders going to find a TV +[igossip] Xyzzy: this... this cant happen to US.... were AMERICA! +[igossip] Cratylus: heh, reporter is shocked to see police patrolling around +with machine guns. +/wiz/cratylus # [igossip] Bayard@Nanvaent: no tanks? +[igossip] Xyzzy: GIT MAH GUN. +[igossip] Al@Anarres II: they are gonna shoot planes down first! +[igossip] Xyzzy: and pilots. +[igossip] Cratylus: no, but apparently fighter jets patrolling too. +/wiz/cratylus # [igossip] Xyzzy: kick ASS. +[igossip] Al@Anarres II: "At about 10 a.m., one of the 110-story World Trade +Center towers collapsed" +[igossip] Xyzzy: just heard on radio: state building car combed. +[igossip] Al@Anarres II: washingtonpost.com. +[igossip] Presto@Discworld: car bomb outside the State Dept. +[igossip] Xyzzy: shhh, al, dont overload our local newspaper's site! +[igossip] Al@Anarres II: hey, its the only one up! +[igossip] Cratylus: not anymore. +/wiz/cratylus # [igossip] Xyzzy: thanks a LOT, guys. +[igossip] Xyzzy: i can see it. +[igossip] Xyzzy: heh, theres a webcam pointed at the pentagon smoke. +[igossip] Al@Anarres II uses akamaitech.net +[igossip] Al@Anarres II: it works. +[igossip] Cratylus: howsabout a url? +/wiz/cratylus # [igossip] Xyzzy: +http://www.washingtonpost.com/wp-srv/mmedia/webcams/eyeondc.htm. +[igossip] Sinistrad@VargonMUD: WHERE THE FUCK IS SPIDER-MAN?!?! +[igossip] Xyzzy: helicopter in the picture, now. +[igossip] Xyzzy: wtf is SPIERman gonna do. +[igossip] Cratylus: mighty mouse is busy eating cheese. +/wiz/cratylus # [igossip] Sinistrad@VargonMUD: Web the tower together. +[igossip] Xyzzy: ohhhh yeah. +[igossip] Skullslayer@RoD: rumour of 6 more planes in the air and hijacked +[igossip] Xyzzy: spider MAN, SPIDER man. +[igossip] Bayard@Nanvaent: yeah. that seems very rumourish atm. +[igossip] Xyzzy: rumor from where? +[igossip] Steve@Anarres II: 2nd has gone now. +[igossip] Tariq@Demonslair Dev: 2nd tower just went down. +[igossip] Al@Anarres II: how the hell can that many planes get hijacked? +[igossip] Xyzzy: 2nd one what. +[igossip] Xyzzy: tower? +[igossip] Presto@Discworld: fucking Christ, the second tower collapsed. +[igossip] Sinistrad@VargonMUD: MAYDAY MAYDAY, TOWER DOWN. +[igossip] Steve@Anarres II: no, the 2nd fucking pentagon. +[igossip] Cratylus: the Mayor's disaster control center was in the +blown up tower. +/wiz/cratylus # [igossip] Sinistrad@VargonMUD: Both towers are gone, you fucking moron. +[igossip] Tariq@Demonslair Dev: saw it dropping live, it was truely scary. +[igossip] Tariq@Demonslair Dev: live on the telly, in case anyone +misunderstands that. +[igossip] Al@Anarres II: did it crumple downwards, or topple over and take out +alot og other buildings? +[igossip] Musashi@Sumu: carbomb at state dept confirmed? +[igossip] Tariq@Demonslair Dev: the top spire was in view, and it just dropped +downwards. +[igossip] Cratylus: wtf npr says both towers collapsed. +/wiz/cratylus # [igossip] Pickett@Sumu: hrm, another plane hijacked and headed to washington. +[igossip] Cratylus: im guessing any further hijacked planes might get shot +down. +/wiz/cratylus # [igossip] Al@Anarres II: but the US cant shoot down its own commertial +airliner! +[igossip] Cratylus: sure it can. +/wiz/cratylus # [cre] Xyzzy: yes, ive heard both towers collapsed, too. +[igossip] Al@Anarres II: they might not crash... +[igossip] Bayard@Nanvaent: i reckon it will. +[igossip] Xyzzy: ok, boss giving orders to go home. +[igossip] Al@Anarres II: bye X! drive safely. +[igossip] Al@Anarres II: don;t go rubber necking! +[igossip] Xyzzy: fuck that, im driving like theres NO TOMOROW. +[igossip] Xyzzy: nah, im takin back roads. +[igossip] Al@Anarres II: there might not be a tomorrow. +[igossip] Xyzzy: MIGHT even stop by parents... see if my dad keeps the gun-safe +locked... +[igossip] Xyzzy: kidding, of course. +[igossip] Xyzzy: ok, see y'all later. +[cre] Xyzzy waves. +[announce] Xyzzy has left Frontiers. +[cre] Cratylus waves. +/wiz/cratylus # [igossip] Musashi@Sumu: perfect time to go raiding ;) +[igossip] Blue@Inon-Net: I hear a rumour that Capitol Hill has not been +attacked after all. +[igossip] Skullslayer@RoD: I have a rumour a second explosion at the pentagon +[igossip] Al@Anarres II: I have a rumour that they are gonna fly nto the statue +of liberty. +[igossip] Tarl@Alsherok: blue: it wasn't. it was a car bomb at the state dept. +[igossip] Tarzan@Darkland: UN (NY) evacutated. +[igossip] Skullslayer@RoD: the pentagon webcam shows a much bigger cloud of +smoke now +[igossip] Blue@Inon-Net: NEWSFLASH: smoke expands. +[igossip] Tarl@Alsherok: reputedly also a large plane crash SE of pittsburgh, +not sure if its related or not, and don't know if its real or not. +[igossip] Tea@Nanvaent: where's the pentagon webcam? +[igossip] Musashi@Sumu: +http://www.washingtonpost.com/wp-srv/mmedia/webcams/eyeondc.htm. +[igossip] Tea@Nanvaent: cheers. +[igossip] Skullslayer@RoD: ronald reagan buliding evacuated +[igossip] Skullslayer@RoD: confirmed hit in pittsburgh +[igossip] Cratylus: so...uh...the two buildings are completely gone, then? +/wiz/cratylus # [igossip] Tarzan@Darkland: whats in Pittsburgh? +[igossip] Styxx@OuterSpace nods. +[igossip] Skullslayer@RoD: north of the airport, somerset county +[igossip] Skullslayer@RoD: rumour - all planes approaching DC will now be shot +down +[igossip] Skullslayer@RoD: the plane approaching DC was shot down? +[cre] Zaphod: shit man. +[igossip] Leto@Earth: http://robots.cnn.com/ and http://asian.cnn.com still +work. +[igossip] Spoo@Nanvaent: http://www.sky.co.uk is relatively lively still as +well. +[igossip] Bayard@Nanvaent nods. +[igossip] Skullslayer@RoD: asia.cnn.com is still up, but it hasn't been updated +in 2 hours that I can see +[igossip] Leto@Earth: ah. +[igossip] Leto@Earth: so what's the stuatus? +[igossip] Sinistrad@VargonMUD: middleeast.cnn.com reports, "Imperialist Scum +Taught A Lesson" +[igossip] Skullslayer@RoD: rumour of another plane is a few mins out from DC, +after the last one was shot down +[igossip] Spoo@Nanvaent: fuck off Sinistrad. +[igossip] Leto@Earth: 7 planes hijacked? +[igossip] Sinistrad@VargonMUD: nya nya, nya nya nya. +[igossip] Leto@Earth: one failed in pitsburg? +[igossip] Musashi@Sumu: that DC-bound jet was shot down? That confirmed? +[igossip] Sinistrad@VargonMUD: That was Air Force 1! +[igossip] Skullslayer@RoD: yeah, one down in pittsburgh, just north of the +airport +[igossip] Spoo@Nanvaent: seems so, 1 may have been shot down near Pittsburgh. +the other still flying near Dulles it would seem, other 5 either crashed or +landed. +[igossip] Hekubah@Annwn: What's happened in Chicago? +[igossip] Skullslayer@RoD: I had a few players here confirm the shoot down +[igossip] Spoo@Nanvaent: Sears tower evacuated. Israelis have shutdown ALL +their embassies. +[igossip] Lightfoot@VargonMUD: I'm unabvle to get to cnn.com. +[igossip] Hekubah@Annwn: Woah. +[igossip] Hekubah@Annwn: reuters isn't working... +[igossip] Isis@Mystic: Me either. Or Fox News. +[igossip] Isis@Mystic: Someone in the office is sreaming BBC. +[igossip] Isis@Mystic: Er, streaming. +[igossip] Lightfoot@VargonMUD: what about it? +[igossip] Hekubah@Annwn has BBC on the TV... +[igossip] Al@Anarres II: Isis - the BBC is fubared. +[igossip] Spoo@Nanvaent: yeah, we have our own stream of N-TV. +[igossip] Skullslayer@RoD: cnn, abcnews, msnbc and a few other big news sites +are all down +[igossip] Spoo@Nanvaent: we are getting CNN live feed. +[igossip] Isis@Mystic: FoxNews too. +[igossip] Skullslayer@RoD: bbc seems to be still up, but a bit behind +[igossip] Tea@Nanvaent: http://news6.thdo.bbc.co.uk/ +[igossip] Sinistrad@VargonMUD: DIE, IMPERIALIST SCUM! +[igossip] Sinistrad@VargonMUD: HAH! +[igossip] Skullslayer@RoD: rumour of crash into camp david +[igossip] Isis@Mystic: Sinis, I love you. +[igossip] Sinistrad@VargonMUD: I know. +[igossip] Musashi@Sumu: remember sinistrad, much as you hate the +'imperialists', someone hates your beliefs just as much.. you deserve to die +too? +[igossip] Sinistrad@VargonMUD: Honey, it's funny that people are always +laughing at the misfortunes of others on this channel - now those same people +are all, "dude, be more sensitive" +[igossip] Teny@Mystic: D.C Streets are one big traffic Jam. +[igossip] Spoo@Nanvaent: pretty much not a joking matter. +[igossip] Musashi@Sumu: misfortunte != death. +[igossip] Musashi@Sumu: -t. +[igossip] Al@Anarres II nods at Spoo +[igossip] Sinistrad@VargonMUD: Go be righteous somewhere else. When it's not +affecting you, you're the ruelest bunch of assholes ever. +[igossip] Sinistrad@VargonMUD: Now it's your turn. HAH!!! DIE GRINGOS!! +[igossip] Spoo@Nanvaent: not affecting you either, so be completely tasteless +some other time. +[igossip] Sinistrad@VargonMUD: No. +[igossip] Al@Anarres II: hey Sini, this doesnt affect me, but it does affect +alot of ppl. +[igossip] Musashi@Sumu: shrugs, I'm not American, but I'm still not gonna laugh +at people dying. +[igossip] Al@Anarres II: there are like 50,000 ppl working in the WTO. +[igossip] Spoo@Nanvaent: I ain't laughing because this is only the start of the +bloodletting. +[igossip] Sinistrad@VargonMUD: Not any more! +[igossip] Lightfoot@VargonMUD: more like 75K. +[igossip] Skullslayer@RoD: plus all the people in the surrounding buildings +[igossip] Lightfoot@VargonMUD: people were jumping out of the building for over +1/2 hour. +[igossip] Al@Anarres II: [flap] Iain: itn reporting 100 tousand dead in new +york. +[igossip] Sinistrad@VargonMUD: Where were you guys when 80K Hindis died of +starvation last year? Did you care? No, you laughed at the hungry brownies. +[igossip] Spoo@Nanvaent: in case you hadn't noticed the madmen have just fucked +off the USA, NATO and the Israeli's. +[igossip] Leto@Earth: 100.000 ? +[igossip] Iain@Anarres II: 100k people. +[igossip] Spoo@Nanvaent: well fuck you for being so consciencious, yeah I care, +I don't find it funny either. +[igossip] Iain@Anarres II: lots of them firefighters/police. +[igossip] Sinistrad@VargonMUD: "Whine whine, now it's hurting us directly, +please don't laugh.. please forget that I used to laugh at you when you were +down, now it's about me and I'm more important." +[igossip] Lightfoot@VargonMUD: I live on Long Island, firefighters and police +were called into the city. +[igossip] Lightfoot@VargonMUD: all bridges and tunnels to NYC are closed. +[igossip] Al@Anarres II: swim! +[igossip] Al@Anarres II: how are they getting ppl out ? +[igossip] Lightfoot@VargonMUD: they are not. +[igossip] Sinistrad@VargonMUD: With straws. +[igossip] Spoo@Nanvaent: both the towers are basically piles of burning rubble, +unlikely to be any survivors in that. +[igossip] Ebony@Earth: I heard a witness say he worked on the 36th floor and +they got out ok. +[igossip] Ebony@Earth: they had 1/2 an hour before the collapse. +[igossip] Spoo@Nanvaent: 1st or 2nd tower? +[igossip] Hellmonger@Trilogy: http://www.shef.ac.uk/cs1xtc/sa/planewtc.jpg. +[igossip] Ebony@Earth: 69 ppl on the plane that flew into the wtc. +[igossip] Lightfoot@VargonMUD: both towers are gone. +[igossip] Hellmonger@Trilogy: no doubt. +[igossip] Ebony@Earth: first tower, they started leaving right after they saw +the 2nd plane. +[igossip] Lightfoot@VargonMUD: 2nd plane hit 18 mins after first. +[igossip] Hellmonger@Trilogy: Vote Yes to Proposition 37 "Systematic Ethnic +Clensing of America" +[igossip] Sinistrad@VargonMUD: "Leave only the injuns" +[igossip] Spoo@Nanvaent: what, you mean America will belong to the natives +again? +[igossip] Shandor@Bakhara: just the mexicans. +[igossip] Hellmonger@Trilogy: Leave only the whites, the blacks, and the +mexicans. +[igossip] Hellmonger@Trilogy: cuz everybody else is out to fucking get us. +[igossip] Lightfoot@VargonMUD: boston is very close, right across the LI sound. +[igossip] Ebony@Earth: 2 planes, carrying approx 80 passengers each.. +[igossip] Ebony@Earth: unsure which they were. +[igossip] Spoo@Nanvaent: seems they just shot down the 2nd plane as well. +[igossip] Spoo@Nanvaent: the one near Dulles. +[igossip] Sinistrad@VargonMUD: Shit, HM's link made me bust a gut! +[igossip] Vraxor@Split Infinity: how do you know? +[igossip] Sinistrad@VargonMUD: You rule, HM. =) +[igossip] Skullslayer@RoD: rumour of a bomb in a school near the WTC +[igossip] Hellmonger@Trilogy: no doubt. +[igossip] Al@Anarres II: nice to see students at shefield are back, hard at +work ;) +[igossip] Skullslayer@RoD: plane inbound to chicago +[announce] Xyzzy enters Frontiers. +[igossip] Xyzzy: i dont know if yer keeping up on current events, but we just +got our ASSES kicked back there! +[igossip] Sinistrad@VargonMUD: http://www.shef.ac.uk/cs1xtc/sa/planewtc.jpg. +[igossip] Hekubah@Annwn: Another plane? +[igossip] Bayard@Nanvaent: the first joke picture :) +[igossip] Sinistrad@VargonMUD: That's not a joke. +[igossip] Xyzzy: thats fucked up. +[igossip] Bayard@Nanvaent: buh? +[igossip] Vashkar@Split Infinity: ummm.. that looks like nice photoshop work, +Sinistrad. +[igossip] Xyzzy: jeez, fuck the fox network... "apparent terrorist attacks..." +[igossip] Sinistrad@VargonMUD: Reality always looks so fake, doesn't it? +[igossip] Izzy@VargonMUD: "This just in, JFK shot." +[igossip] Musashi@Sumu: NBC just reported bomb gone off in NYC Highschool. +[igossip] Xyzzy: WE GOT A MAN ON TH MOON?! +[igossip] Presto@Discworld: yeah, it was obviously a big fucking coincidence. +[igossip] Xyzzy: fox investigative news. +[igossip] Xyzzy: at work. +[igossip] Musashi@Sumu: FAA say several planes still unaccounted for. +[igossip] Presto@Discworld: This just in: Jimmy Hoffa still missing. Police are +baffled. +[igossip] Xyzzy: plane crash 80 miles SE of pittsburg. +[igossip] Xyzzy: holy shit, footage of the WTC collapsing. +[igossip] Presto@Discworld: American Air confirms two flights down, United at +least one (the Pittsbhrugh one) +[igossip] Al@Anarres II: well done Xyzzy, do catch up. +[igossip] Al@Anarres II: which was the dullus one? +[igossip] Xyzzy: gee, its almost as if i havent had a TV at work for th last +two hours. +[igossip] Vashkar@Split Infinity: the only thing slightly amusing is that I +swore to myself that I'd never set foot in the WTC again.. then seconds later, +one collapses..then the other. +[igossip] Bayard@Nanvaent: you've had i3 though. and it's all been mentioned on +here. +[igossip] Xyzzy: its all YOUR fault, vash. +[igossip] Xyzzy: no, im SEEING the collapse for th first time. +[igossip] Vashkar@Split Infinity: sorry, I don't claim responsibility for the +deaths of tens of thousands today. +[igossip] Blue@Earth: you should, get your place in the queue. +[cre] Cratylus: whad i miss? +/wiz/cratylus # [igossip] Xyzzy: no one ever told us terrorist could be organized. +[igossip] Xyzzy: is that fair? +[cre] Xyzzy: dunno, i just got home. +[cre] Zaphod: westconn just got bombed. +[cre] Cratylus: no. +/wiz/cratylus # [igossip] Al@Anarres II: is this the largest terrorist attack ever? +[cre] Cratylus: they installed antiarircraft batteries on the ice rink and +patriot garage. +/wiz/cratylus # [cre] Cratylus: i just saw em. +/wiz/cratylus # [cre] Zaphod: ah. +[igossip] Xyzzy: heh, on cnn, "america under attack", all red white n blue +fonts n stuff. +[cre] Zaphod: cool. +[igossip] Bayard@Nanvaent: easily. +[igossip] Sinistrad@VargonMUD: Shit. Now my Flight Simulator NYC edition is +outdated. =( +[igossip] Al@Anarres II giggles +[igossip] Xyzzy: expansion pack. +[igossip] Bayard@Nanvaent: equally, how do u define a terrorist attack. this +might not be a terrorist attack. +[igossip] Hekubah@Annwn: Might be an act of war? +[igossip] Bayard@Nanvaent: could end up being defined as an opening move in a +war. +[cre] Zaphod: few. +[cre] Zaphod: phewww. +[igossip] Xyzzy: oh yeah, fergot, it might just be a wacky coincidence. +[cre] Zaphod: my package made it out of newark. +[igossip] Vashkar@Split Infinity: well, it wasn't a bunch of drunks, Bayard. +[igossip] Iain@Anarres II: sick puppy sini ;-) +[igossip] Xyzzy: hmm, good point, bayard. +[igossip] Xyzzy: GIT MAH GUN! +[igossip] Lightfoot@VargonMUD: were at defcon 5! +[igossip] Xyzzy: yer MOM is at defcon5 +[igossip] Sinistrad@VargonMUD: Hey, more people died right now than in Pearl +Harbor. +[igossip] Bayard@Nanvaent: but, the style of attack will prolly mean it's a +terrorist attack that started a war in history books. +[igossip] Xyzzy: what, you got a death-count goin, sini? +[igossip] Bayard@Nanvaent: s'diff than pearl harbour or czechoslovakia. +[igossip] Lightfoot@VargonMUD: shut up dick. +[igossip] Vashkar@Split Infinity: please someone ban Xyzzy. +[igossip] Spoo@Nanvaent: WW 1 was started because of a terrorist attack that +killed 1 person. +[igossip] Bayard@Nanvaent nods. +[igossip] Xyzzy: please someone suck my dick. +[igossip] Sinistrad@VargonMUD: Xy, 50K+ people worked in the towers. +[igossip] Sinistrad@VargonMUD: How many people died at Pearl Harbor? +[igossip] Cratylus watches in amusement as Vashkar greedily gobbles Xyzzy's +knob. +/wiz/cratylus # [igossip] Vashkar@Split Infinity: Vrax@SI says there was 10k in each tower, +approximately, at the time. +[igossip] Xyzzy: what, like i work for th navy or something, sini? +[cre] Zaphod: my packge drove right through ny just before this. +[cre] Cratylus: yer motherboard? +/wiz/cratylus # [cre] Xyzzy: a little... coincidental. +[igossip] Spoo@Nanvaent: less than 2k people were killed at PH. +[igossip] Vraxor@Split Infinity: that's what the guy who owned the tower said. +[cre] Zaphod: this one is my video card. +[cre] Zaphod: mb just left la. +[cre] Zaphod: maybe it's been hijacked. +[igossip] Xyzzy: that tower was 0WN3D. +[igossip] Ebony@Earth: You have to account for tourists in the towers too. +[igossip] Vraxor@Split Infinity: and the people in the planes. +[cre] Zaphod: now I REALLY don't feel like going to the office. +[32m[igossip] Xyzzy: shoot, none of this is gonna drive up memory prices, will it? +[cre] Zaphod: buy it quick. +[igossip] Spoo@Nanvaent: automatic if the pres is in AF1 +[cre] Zaphod: WTC attack sale! +[igossip] Xyzzy: heard on radio: military air coverage over DC. +[igossip] Musashi@Sumu: ok, of the two planes to hit the towers, one was out of +boston, 81 passengers, 11 crew, one was out of washington, 58 passengers, 6 +crew. +[cre] Zaphod: cheech sent an email saying pahts delivery will be screwy. +[igossip] Lightfoot@VargonMUD: there are tomcats flying around NYC. +[igossip] Xyzzy: thanks for th numbers, musashi. +[cre] Cratylus: AHAHAH. +/wiz/cratylus # [cre] Cratylus: i fucken BET. +/wiz/cratylus # [igossip] Xyzzy: i knew id never regret hiring you as my accountant. +[igossip] Cratylus: i cant wait til we fuckin nuke the shitbags from orbit. +/wiz/cratylus # [igossip] Zaphod: 9/11 +[igossip] Xyzzy: its th only way to be sure. +[igossip] Dasquian@Discworld: You idiot. +[igossip] Musashi@Sumu: spam incoming, this from CNN. +[igossip] Musashi@Sumu: United Airlines Flight 93 airliner headed from Newark, +New Jersey, to San Francisco, crashed near Somerset, Pennsylvania -- police +said initial reports indicated no survivors. It was not known if this was +connected to the attacks. United also said it was "deepl. +[igossip] Xyzzy: DEEPL?!?! +[igossip] Xyzzy: NOOOOOOO!!!!!! +[igossip] Musashi@Sumu: ________________23:43 +[igossip] Musashi@Sumu: hm, sec :P. +[igossip] Musashi@Sumu: United also said it was "deeply concerned" about Flight +l75 from Boston to Los Angeles. +[igossip] Lightfoot@VargonMUD: it's said that crash in penn was from captain +crashing plane when he knew what was going on and he was being hi-jacked. +[igossip] Xyzzy: Am Airlines siad theyve "lost" two flights. +[igossip] Sinistrad@VargonMUD: And they know that throgh the ouija board, +Danny? +[cre] Zaphod: today is 9/11 +[igossip] Xyzzy: WELL, DANNY?! +[igossip] Lightfoot@VargonMUD: I'm sure the radios were working. +[igossip] Xyzzy: oh, yer "sure" +[igossip] Vashkar@Split Infinity: +http://us.news2.yimg.com/dailynews.yahoo.com/h/nm/20010911/ts/crash_tradecenter +_binladen_dc_1.html. +[igossip] Lightfoot@VargonMUD: shut up dick. +[igossip] Vashkar@Split Infinity: they say bin laden warned of the attack 3 +weeks ago. +[cre] Zaphod: call paul. +[igossip] Sinistrad@VargonMUD: Wow. +[cre] Cratylus: ya. +/wiz/cratylus # [igossip] Vashkar@Split Infinity: saying it was cause of US supporting israel. +[igossip] Xyzzy: yknow, i think what we really need now is a verbal fight on i3 +[igossip] Shandor@Bakhara: your mom tastes like chicken and your dad smells of +a russian tea room. +[igossip] Xyzzy: HEY, now. +[igossip] Xyzzy: lets keep it civil. +[igossip] Cratylus: eldeberries, you fool. +/wiz/cratylus # [igossip] Sinistrad@VargonMUD: ``Personally we received information that he +planned very, very big attacks against American interests. We received several +warnings like this. We did not take it so seriously, preferring to see what +would happen before reporting it.'' +[igossip] Cratylus: smelt of em. +/wiz/cratylus # [igossip] Shandor@Bakhara: windows sucks! RH linux is the top of them all. +[igossip] Sinistrad@VargonMUD: "He told us he was gonna do it, but we wanted to +see what he was gonna do before we told anybody." +[cre] Zaphod: cute. +[igossip] Xyzzy: we called his bluff, alright. +[igossip] Shandor@Bakhara: who says that, sini? +[cre] Zaphod: he told me to stay home. +[igossip] Hellmonger@Trilogy: I hear the arabs in San Fran are celebrating the +attacks. Somebody go kill them all. +[igossip] Sinistrad@VargonMUD: NOW YOU KNOW. +[cre] Cratylus: ya. +/wiz/cratylus # [cre] Zaphod: you heard him. +[igossip] Sinistrad@VargonMUD: That link Vash gave out. +[cre] Cratylus: stamford is prolly a panicky madhouse. +/wiz/cratylus # [cre] Zaphod: no doubt. +[igossip] Xyzzy: and knowing's half th battle! +[cre] Zaphod: and I've got CABLE. +[igossip] Spoo@Nanvaent: hell, the Arabs are going to give someone some target +practice if they don't fuck off. +[igossip] Shandor@Bakhara: half of our IT department is made of arabs. I +wouldn't want to be them right now. Although, this is a mall city. +[igossip] Xyzzy: mall city? like, with shops n stuff? +[igossip] Cratylus: made of crabs? what? +/wiz/cratylus # [igossip] Spoo@Nanvaent: it ain't really the Arabs anyway, just a completely +mad bunch of lunatics who want to take us back the the dark ages. +[igossip] Cratylus: the republicans? +/wiz/cratylus # [igossip] Xyzzy: like i said, i think its in the rulebook that theyre not +allowed to be so organized and effective. +[igossip] Sinistrad@VargonMUD: That movie with Denzel Washington and Bruce +Willis starts out with a lot of terrorist attacks. That is NOTHING compared to +this. +[igossip] Vashkar@Split Infinity nods. +[igossip] Cratylus: i bet the french are all like "serves em right, bourgeois +pigs" +/wiz/cratylus # [igossip] Spoo@Nanvaent: makes Tom Clancy look tame too. +[igossip] Lightfoot@VargonMUD: cnn back up. +[igossip] Cratylus: i think they got lucky. you couldnt *really* expect those +fucking buildings to drop from plane hits. +/wiz/cratylus # [igossip] Spoo@Nanvaent: they were rather large ones. +[igossip] Lightfoot@VargonMUD: Bush calls trade center crashes terrorist act. +[igossip] Cratylus: large buildings. +/wiz/cratylus # [igossip] Lightfoot@VargonMUD: you think? +[igossip] Sinistrad@VargonMUD: Thanks, Danny. +[igossip] Vashkar@Split Infinity: in today's day n' age, it's not hard to be a +competent terrorist. It's like Osama bin Laden went to a tech institute or +something. +[igossip] Spoo@Nanvaent: large aircraft. +[igossip] Cratylus: fat asses. +/wiz/cratylus # [igossip] Steve@Anarres II: um.. they knew where to hit them to have best +chance of toppling them.. +[igossip] Spoo@Nanvaent: cnn.com is breaking under the strain again. +[igossip] Xyzzy: this just in: i hafta pee. +[igossip] Cratylus: ok, master terrorist. +/wiz/cratylus # [igossip] Zaphod: ooo ooo Tom Clancy's on cnn! +[igossip] Sinistrad@VargonMUD: He's the authority, I bet! +[igossip] Cratylus: that does it. im playing half life. screw this. +/wiz/cratylus # [igossip] Xyzzy: hes written books n stuff! +[igossip] Xyzzy: just like smack! +[igossip] Spoo@Nanvaent: prolly complaining that the bastards stole his idea. +[igossip] Steve@Anarres II: part-way up near the top.. you prolly won't get +them immediately, but fire will weaken the structure and the top will fall +cruching the rest of the building.. +[igossip] Xyzzy: cool, Dexter's Laboratory on cartoon network. +[igossip] Spoo@Nanvaent: yeah, the steel skeleton would weaken, concrete and +facade wouldn't hold the weight. +[igossip] Spoo@Nanvaent: it appears there was a secondary explosion in the +first tower to go down too. +[igossip] Blue@Inon-Net: I think the WTC buildings had their skeleton on the +outside; but don't hold me to that. +[igossip] Sinistrad@VargonMUD: So it wasn't just the planes? +[igossip] Xyzzy: yeah! lets speculate on the various ways these people died +today! +[igossip] Vashkar@Split Infinity: Spoo, they're thinking it was the plane's +fuel tank exploding. +[igossip] Steve@Anarres II: they showed ppl diving outa windows on the news.. +that's sick.. +[igossip] Spoo@Nanvaent: was quite a way down from the impact site. +[igossip] Spoo@Nanvaent: could well have been though. +[igossip] Al@Anarres II nods at Spoo +[igossip] Al@Anarres II: I think we just have to wait and see. +[igossip] Vashkar@Split Infinity: yeah, I was questioning the logistics of that +guess also. +[igossip] Al@Anarres II: if the top, above the crash site, fell down, even just +1meter, the energy would be enough to crumble the steel below. +[igossip] Spoo@Nanvaent: thats what happened with the second tower. +[cre] Zaphod: shit. +[igossip] Al@Anarres II: it might have crumbled many stories down, making it +look like an explosion below the crash site. +[igossip] Spoo@Nanvaent: roof went, took the rest with it. +[cre] Zaphod: I bet the coffee I ordered don't get sent out. +[igossip] Al@Anarres II: yeah, common :( +[cre] Xyzzy: always thinkin of yerself. +[igossip] Al@Anarres II shuts up about civil engineering and goes back to +hacking sendmail +[cre] Zaphod: well, I need my coffee. +[igossip] Boltthrower@Styx: apparently the roof-collapse scheme works better +than the basement-bomb thing did :( +[igossip] Spoo@Nanvaent: nah, there was a clear fireball shortly before the +first collapse (and I saw that live so no, it wasn't a plane) +[igossip] Xyzzy: how about the "fly a few hundred tons of metal into the +building" scheme? +[igossip] Isis@Inon-Net: Yeah, I saw it too just before I left for work. +[igossip] Spoo@Nanvaent: 737 and a 767, couple of hundred tonnes each. +[igossip] Hellmonger@Trilogy sets an arab on fire. +[igossip] Zaphod: camp david get hit? +[igossip] Vashkar@Split Infinity: close to camp david. +[igossip] Al@Anarres II: cool, HM, gulf-news.com is hosted nr you ;) +[igossip] Spoo@Nanvaent: lots of momentum to damage the buildings, the second +aircraft blew right through the tower too. +[igossip] Xyzzy: can you imagine how dark it could be in manhattan right now? +[igossip] Lightfoot@VargonMUD: that one was shot down. +[igossip] Spoo@Nanvaent: what, at midday? +[igossip] Xyzzy: yes. +[igossip] Xyzzy: with all the smoke. +[igossip] Spoo@Nanvaent: not very then. +[igossip] Xyzzy: well, i guess you CAN imagine it, then. +[igossip] Zaphod: 8 hijacked planes still in the air? +[igossip] Xyzzy: but for how long.... +[igossip] Xyzzy: HOW LONG!?! +[igossip] Vashkar@Split Infinity: where'd you hear 8, Zaphod? +[igossip] Xyzzy: hes just makin shit up, now. +[igossip] Ebony@Earth: Its not that dark. +[igossip] Hellmonger@Trilogy: I heard 8 total planes. +[igossip] Hellmonger@Trilogy: and we've already found some of them. +[igossip] Lightfoot@VargonMUD: 5 floors in pentagon have collapased. +[igossip] Ebony@Earth: Not unless you where wtc was. +[igossip] Hellmonger@Trilogy: we found 2 in the trade center, one in the +pentagon... \ +[igossip] Xyzzy: HM AM FUNNYMAN! +[igossip] Spoo@Nanvaent: Brits have lost contact with 2 aircraft as well. +[igossip] CyberTiger@Anarres II: s/found/happened to notice/ +[igossip] Xyzzy: wtf, some dude disassembling a pistol on CourtTV, sayin how +easy it could be to blah blah blah. +[igossip] BarWench@Inon-Net: ;nods. +[igossip] Al@Anarres II: have we Spoo? where you hear that? +[igossip] Hellmonger@Trilogy: So is Bin laden a palestinian or a jew? +[igossip] Smack@Lima Bean: what aircraft? +[igossip] Smack@Lima Bean: my father is on a flight from london to new york. +[igossip] Hellmonger@Trilogy: It says 'Islamic Fundamentalist', which is like a +palestinian, right? +[igossip] Smack@Lima Bean: bin laden is saudi. +[igossip] Hellmonger@Trilogy: He'll be landing in canada. :( +[igossip] Pam@Split Infinity: They're evacuating some of the taller buildings +in London, according to MSNBC. +[igossip] Smack@Lima Bean: he is a rich, eccentric saudi. +[igossip] Xyzzy: look out, hellmonger is gunnin for SOMEone. +[igossip] Tea@Nanvaent: canada is all closed too i thought? +[igossip] Hellmonger@Trilogy: I'm down to kill me some arabs now. +[igossip] Hellmonger@Trilogy: And some happy palestinians. +[igossip] Smack@Lima Bean: we must declare war against Afghanistan. +[igossip] Hellmonger@Trilogy: Need to be set on fire. +[igossip] Hellmonger@Trilogy: why afghanistan? +[igossip] Sinistrad@VargonMUD: Why not? +[igossip] Hellmonger@Trilogy: Valid point. KILL EM ALL! +[igossip] Smack@Lima Bean: afghanistan has been housing bin laden for years. +[igossip] Smack@Lima Bean: they refuse to turn him over. +[igossip] Megaboz@Lima Bean: I just have this feeling that bush is going to do +something stupid. +[igossip] Ebony@Earth: Third plane ahs crashed in pentagon. +[igossip] Hellmonger@Trilogy: I'm all about letting them know whats up. Take +the afghan royal family or whatnot. And cook them on a spit. +[igossip] Smack@Lima Bean: do something stupid like what? +[igossip] Hellmonger@Trilogy: Like what? +[igossip] Hellmonger@Trilogy: Like starting to kill people? +[igossip] Hellmonger@Trilogy: The american people want revenge. +[igossip] Smack@Lima Bean: if he nuked them, I would be only mildly distubed. +[igossip] Megaboz@Lima Bean: nuked was the thing I was going for. +[igossip] Spoo@Nanvaent: which bastard stopped development of the neutron bomb, +perfect time to test it. +[igossip] Xyzzy chants: "NUKE! NUKE! NUKE!" +[igossip] Hellmonger@Trilogy: I would'nt really be phased. I'd like to see the +middle east as a field of glass. +[igossip] Smack@Lima Bean: so how many planes have crashed so far? 5? 6? +[igossip] Musashi@Sumu: Ebony, that 3rd plane in the pentagon confirmed? +[igossip] Sinistrad@VargonMUD: 5. +[igossip] Sinistrad@VargonMUD: Three on target, two off target. +[igossip] Hellmonger@Trilogy: I think bombing them would be cool. +[igossip] Spoo@Nanvaent: hard to tell really, web sites are all choked. +[igossip] Xyzzy: jeez, how many damn kids did the Waltons have? +[igossip] Hellmonger@Trilogy: 7. +[igossip] Hellmonger@Trilogy: all worth around 17-18 bil. +[igossip] Smack@Lima Bean: my understanding is 2 into thw world trade center, 2 +into the pentagon, and one outside pittsburgh. +[igossip] Hellmonger@Trilogy: right. +[igossip] Sinistrad@VargonMUD: Only 1 into the pentagon. +[igossip] Isis@Inon-Net: And one in Sommerset PA as well. +[igossip] Musashi@Sumu: reading in a few places of a 3rd into the pentagon +though. +[igossip] Sinistrad@VargonMUD: 1 outside pitts, 1 recently confirmed outside +Sommerset. +[igossip] Hellmonger@Trilogy: Thats outside pitts. +[igossip] Smack@Lima Bean: sommerset == pitssburgh. +[igossip] Smack@Lima Bean: oh, yeah,and the air force shot one down outside +camp david. +[igossip] Hellmonger@Trilogy: a third plane intot he pentagon? +[igossip] Futility@UOSSMUD: The one in Somerset is the one near pittsburgh. +[igossip] Hellmonger@Trilogy: Really? +[igossip] Sinistrad@VargonMUD: "United Airlines Flight 93 airliner headed from +Newark, New Jersey, to San Francisco, crashed near Somerset, Pennsylvania -- +police said initial reports indicated no survivors. It was not known if this +was connected to the attacks. United also said it was "deeply concerned" about +Flight l75 from Boston to Los Angeles." +[igossip] Sinistrad@VargonMUD: On CNN, they just confirmed that 175 went down, +too. +[igossip] Xyzzy: deepl. +[igossip] Spoo@Nanvaent: so 3 shot down and 3/4 crashed. +[igossip] Hellmonger@Trilogy: We shot down three planes? +[igossip] Xyzzy: yeah, HM, score one for th good guys. +[igossip] Spoo@Nanvaent: there were 7 hijacked. +[igossip] Musashi@Sumu: from advfn: A third plane crashes near the Pentagon in +Washington DC. +[igossip] Smack@Lima Bean: where did 175 go down? +[igossip] Spoo@Nanvaent: well maybe not shotdown, hard to sort out the news +from the confused. +[igossip] Spoo@Nanvaent: WASHINGTON (Reuters) - Three hijacked planes crashed +into major U.S. landmarks on Tuesday, destroying both of New York's mighty twin +towers, hitting the Pentagon in Washington and plunging the United States into +unprecedented chaos and panic. +[igossip] Smack@Lima Bean: fucking kill them all. +[igossip] Blue@Inon-Net: now that Reuters has confirmed it, I'll stop worrying +that it was all US propaganda being parroted by CNN. +[igossip] Hellmonger@Trilogy: no doubt. +[igossip] Xyzzy: the adjective "mighty" brought to you at no extra charge. +[igossip] Hellmonger@Trilogy: I only know of three terrorist crashes, and one +United crash. +[igossip] Hellmonger@Trilogy: And whats up on 175? +[igossip] Sinistrad@VargonMUD: Two united crashes. +[igossip] Hellmonger@Trilogy: where did it crash? +[igossip] Smack@Lima Bean: the united crash is certainly a terorist thing. +[igossip] Smack@Lima Bean: probably the pilot taking it down to prevent +somethign evil. +[igossip] Hellmonger@Trilogy: I thought terrorists all capped off the pilots to +prevent them from fucking up the program? +[igossip] Spoo@Nanvaent: One of the planes that crashed into the World Trade +Center was American Airlines' Flight 11 from Boston to Los Angeles, said Lori +Bassani, spokesperson for American's flight attendants union. ; +[igossip] Smack@Lima Bean: someone said "fuck the terrorists" +[igossip] Sinistrad@VargonMUD: Yeah, I don't think any pilot would go, "Ok, +I'll crash this plane into the twin towers or he'll shoot me." +[igossip] Spoo@Nanvaent: www.reuters.com. +[igossip] Hellmonger@Trilogy: No doubt. YOu are going to die anyway. Fuck it. +I'd put that shit in the dirt. +[igossip] Smack@Lima Bean: I agree... but I bet on the one outside pittsburgh +was stoipped by someone. +[igossip] Xyzzy: hellmonger, you seem to be fairly well-versed in "hijacker +protocol" +[igossip] Xyzzy: something you wannatell us? +[igossip] Hellmonger@Trilogy: Common sense. +[igossip] Boltthrower@Styx: you online from a plane? +[igossip] Sinistrad@VargonMUD: Microsoft announced the release of a new version +of Microsoft Flight. +[igossip] Smack@Lima Bean: I just fear that bioterrorism is part of this. +[igossip] Smack@Lima Bean: that we have not even seen the worst yet. +[igossip] Sinistrad@VargonMUD: Microsoft announced the release of a new version +of Microsoft Flight Simulator today. The terrain has been updated in New York +so that two piles of rubble sit where the twin World Trade Center towers used +to stand. When asked how they had this updated version burned before the towers +were actually bombed Bill Gates responded "We like to be prepared for any +contingiency. This is a horrible tragedy and we grieve for the loss that people +are facing. We will donate .001% of all profits of this product to help the +families of those killed during this horrible event." Newly appointed Vice +President of Microsoft, Osama bin Laden added: "We'd also like to point out +that we have the only flight simulator on the market that has true to the day +updated terrain. If you want to own the most realistic up to date simulator, +you've got to buy ours." +[igossip] Spoo@Nanvaent: sorry, even I find that funny :) +[igossip] Sinistrad@VargonMUD: =) +[igossip] Xyzzy: and we all know how lousy a sense of humor spoo has. +[igossip] Spoo@Nanvaent: at least I have one Xy :) +[igossip] Musashi@Sumu: looks like the pentagon fire is under control. +[igossip] Xyzzy: WHEW! +[igossip] Xyzzy: what about these rumors of car bombings and capitol hill/ +state building/whitehouse, etc. +[igossip] Sinistrad@VargonMUD: Exhaust pipes going off. +[igossip] Musashi@Sumu: well, heard several reports of car bomb outside state +building. +[igossip] Spoo@Nanvaent: there was no bomb at the State Department. +[igossip] Musashi@Sumu: and one of a bomb in a nyc school. +[igossip] Blue@Inon-Net: english.pravda.ru. +[igossip] Spoo@Nanvaent: prolly someone hearing a backfire. +[igossip] Blue@Inon-Net: US DOLLAR ABRUPTLY FALLEN DOWN. +[igossip] Blue@Inon-Net: According to current bidding, US dollar has fallen +abruptly relative to the Euro and to Yena. American stock markets has not +started to work yet. Planes are in air to hamper the second plane. +[igossip] Xyzzy: ALL YOUR NEWS ARE BELONG TO US. +[igossip] Blue@Inon-Net: According to NPR John Hopkins, the USA have not need +to be considerate with the terrorists. +[igossip] Musashi@Sumu: laf. +[igossip] Spoo@Nanvaent: Manhattan island encircled by policemen. +[igossip] Blue@Inon-Net: Suicide pilots piloting two planes have practically +rammed two buildings of International Trade Centre at a height of 85th storey. +These two buildings are known to the whole world thanks to film 'King Kong'. +That are the buildings over which the big monkey was mounting. More detail... +[igossip] Xyzzy: holding hands. +[igossip] Spoo@Nanvaent: POPULATION FROM CENTRE OF CHICAGO EVACUATED. LONDON +PANIC STRICKEN; +[igossip] Xyzzy: hu uhuh uhu, you said "mounting" +[igossip] Musashi@Sumu: london is hardly panic stricken :P. +[igossip] Xyzzy: wait, LONDON panic stricken? +[igossip] Lightfoot@VargonMUD: king kong climbed the empire state building. +[igossip] Blue@Inon-Net: they mean the remake. +[igossip] Blue@Inon-Net: NEWSFLASH: King Kong to be remade again, new buildings +sought. +[igossip] Xyzzy: as opposed to the porn film, "King Dong", where he climbed +lightfoot's mother. +[igossip] Lightfoot@VargonMUD: fuck you dick. +[igossip] Spoo@Nanvaent: I think "have practically rammed 2 buildings" is an +understatement. +[igossip] Xyzzy: ACH! fook me dick! +[igossip] Xyzzy: well, it wasnt very IMpractical. +[igossip] Lightfoot@VargonMUD: I would love to kick the living shit out of a +little punk like you. +[igossip] Spoo@Nanvaent: "ADVENTURES OF AMERICAN RECONNAISSANCE AIRCRAFT R-3. +NOW IN RUSSIAN AIRSPACE;" +[igossip] Zaphod: whoa. +[igossip] Sinistrad@VargonMUD: Danny, I've seen you. You're the smallest +goddamn punk ever. +[igossip] Zaphod: qvc has suspended broadcasts. +[igossip] Zaphod: jesus. +[igossip] Spoo@Nanvaent: surely that should be "Now in Russian Cinemas" +[igossip] Xyzzy: and he doesnt mean overall height. +[igossip] Bayard@Nanvaent: no more qvc? diff --git a/lib/domains/town/txt/shame/chapter04 b/lib/domains/town/txt/shame/chapter04 new file mode 100644 index 0000000..f87a2f0 --- /dev/null +++ b/lib/domains/town/txt/shame/chapter04 @@ -0,0 +1,87 @@ +chapter 4 "Cratylus Has His Buttons Pushed" + +[02Dec2005-11:55:50] Jayren <cre> i didnt know that could be done. havening rooms or people like that. hi. +[02Dec2005-11:56:18] Cratylus <cre> ya, it's convenient for when you're deep in coding +[02Dec2005-11:56:28] Cratylus <cre> what's up? +[02Dec2005-11:56:40] Jayren <cre> and people like me wanna come by and do nothing except pester you. +[02Dec2005-11:56:56] Cratylus <cre> pestering is done on the cre channel +[02Dec2005-11:57:58] Jayren <cre> just came back to lister after quite a while of playing with ce pro over on smeghead. +[02Dec2005-11:58:21] Cratylus <cre> is that meaningful? +[02Dec2005-11:59:01] Jayren <cre> well, i learned more about ce pro. that's always good. learned unlike sound forge, ce pro is multitrack. +[02Dec2005-11:59:19] Cratylus <cre> ah, you're talking about your programs +[02Dec2005-11:59:37] Jayren <cre> does it mean anything for dslib, um no not really. +[02Dec2005-12:00:11] Cratylus <cre> well what you said sounded like this: "just came back to foo after quite a while of playing with bar over on baz" +[02Dec2005-12:01:05] Jayren <cre> so then bazically you are saying to cut it out. +[02Dec2005-12:01:13] Cratylus <cre> not really +[02Dec2005-12:01:34] Cratylus <cre> i'm just saying stop assuming i know what you're talking about unless we've discussed it before +[02Dec2005-12:02:30] Jayren <cre> all this lpc stuff makes about as much sense to me, and i thought we have discussed most of that before. i'm pretty sure i mentioned my machine names. +[02Dec2005-12:02:46] Cratylus <cre> ahhh so you're talking about programs and specifying machine names +[02Dec2005-12:03:20] Jayren <cre> lister and smeghead are machines. ce pro and sound forge are programs both for audio editing both run on windows. +[02Dec2005-12:04:14] Cratylus <cre> i'm sure that "lister", "ce pro", and "smeghead" are all obvious and meaningful to you. having mentioned them to me once in passing doesn't make it reasonable to expect me to remember them. do you want me to expect you to remember every file name i throw at you? +[02Dec2005-12:05:13] Jayren <cre> i've been told i have a decent memory. i'd give it a shot. +[02Dec2005-12:05:21] <cre> Cratylus smiles. +[02Dec2005-12:05:29] Cratylus <cre> it's a deal +[02Dec2005-12:06:45] Jayren <cre> remember though. being blind i hafta have a good memory. a good bit better than average. i hafta make and use mental maps all the time, in travel from one place to another or just locating a room in a building. +[02Dec2005-12:07:19] Cratylus <cre> that should make remembering what i tell you very easy +[02Dec2005-12:07:29] Cratylus <cre> i look forward to not having to repeat myself with you +[02Dec2005-12:08:12] Jayren <cre> *shrug* we'll see what happens. +[02Dec2005-12:08:20] Cratylus <cre> you don't sound so confident any more +[02Dec2005-12:10:06] Jayren <cre> there are 2 parts to memorization, acquisition and retension. the first part i'm not so hot at. though once i've retained something it can become part of a mental map. +[02Dec2005-12:11:39] Cratylus <cre> ok. so then you understand how it might be reasonable to expect me to forget the names of programs and computers that i do not use +[02Dec2005-12:12:07] Jayren <cre> heh. i was waiting for you to connect those. +[02Dec2005-12:12:23] Cratylus <cre> explain +[02Dec2005-12:12:59] Jayren <cre> phone. +[02Dec2005-12:13:03] <cre> Cratylus snorts. +[02Dec2005-12:13:41] Jayren <cre> what it really was the phone. +[02Dec2005-12:14:05] Cratylus <cre> i believe you +[02Dec2005-12:15:02] Jayren <cre> i guess because of my seizures i look a little differently at forgetting things than someone without. +[02Dec2005-12:17:16] Jayren <cre> once something is acquired, it takes a bit of time before it goes to relatively permanent storage though once its there there's a lot better chance it will remain. when i have a seizure everything in the acquisition buffer can go blip. +[02Dec2005-12:17:16] Cratylus <cre> remembering things takes energy. i dislike wasting energy on things that are of no relevance to what i want to do. if a thing is not relevant to me, it is discarded. the fact that we will be working on blindmode does not make it relevant to me which programs you use on what computers. i find it hard to imagine a circmstance where the name of your computer would have any effect on me whatsoever, except in the case of being challenged to remember it +[02Dec2005-12:19:49] Cratylus <cre> let me give you an example of how your statement might have been worded to add meaningfulness. +[02Dec2005-12:20:01] Jayren <cre> to give you an idea, i've still got maps in my head for my childhood house, which we left about 18 years ago if i've done the math right. i've got a map for the schools i attended. basically information i will never need again ever. +[02Dec2005-12:20:11] Cratylus <cre> "i came back to my favorite synthesizer program after plaing with a different one on my alternate computer" +[02Dec2005-12:21:01] Cratylus <cre> a statement like this is not only meaningful to a person who isn't you, but also suggests that your worldview isn't so limited that you expect people to remember every detail of your life that you provide once +[02Dec2005-12:22:42] Cratylus <cre> my own brain has various unusual advantages and disadvantages, but i manage to communicate with other people in a way that standardizes my perspective into something generally useful to others +[02Dec2005-12:23:04] Cratylus <cre> people appreciate the effort +[02Dec2005-12:24:42] Jayren <cre> at the same time, i might not emember something that happened last week because that event didn't get a chance to make it to the storage area and was still in the buffer between that and the outside world when i had a seizure. makes life interesting. still one good thing, i always get to met new people. +[02Dec2005-12:26:23] Cratylus <cre> you have adequately explained your problem. do you understand why your expectation was unreasonable? +[02Dec2005-12:38:06] Jayren <cre> and i don't expect people to remember what lister and smeghead and soundforge and ce pro are. i never claimed to expect that. if someone wants to know what any of these things are, then all they have to do is as and i'll tell them. just like forgetting something that has happened to me, i can forget what someone knows or more spcifically what i've told them. +[02Dec2005-12:39:17] Cratylus <cre> when you made a statement that included those names without context, it per se assumes an expectation that the listener knows what that is +[02Dec2005-12:39:39] Jayren <cre> i had no such assumption. +[02Dec2005-12:39:53] Cratylus <cre> why would you say things you don't expect another to understand? +[02Dec2005-12:40:17] Jayren <cre> if the listener didn't know and wanted to know, then asking would have worked. +[02Dec2005-12:41:09] Cratylus <cre> is it your habit to include out of context jargon in all your conversations? +[02Dec2005-12:42:50] Cratylus <cre> i mean, i'm picturing a person sitting at thanksgiving dinner, being asked by, say, an aunt about how things are going, and the person replying "just came back to lister after quite a while of playing with ce pro over on smeghead." +[02Dec2005-12:43:20] Cratylus <cre> is this sort of thing the way you generally do with people? +[02Dec2005-12:43:40] Jayren <cre> one thing this sort of mindset avoids is talking down to folks. for example. if someone asks me how to fix a problem and i tell them that there are several steps and give them those steps if that helps them great. i don't have to tell them what to click or whatever to tell them how to format the c: drive, i can just say format the c: drive. if they dont know they can say, how do i format the c: drive then i can say click on this and do whatever. +[02Dec2005-12:44:26] Cratylus <cre> i am a technical expert that deals with laymen all the time. this is why i understand how inappropriate it is to assume knowledge of jargon +[02Dec2005-12:45:04] Jayren <cre> i never claimed to be a people person. in fact i know i'm not. +[02Dec2005-12:45:23] Cratylus <cre> so you do understand that your expectation was unreasonable +[02Dec2005-12:45:57] Jayren <cre> i still submit i wasn't expecting you to know what any of those things were. +[02Dec2005-12:46:19] Cratylus <cre> then why on earth would you say that? do you want me to start disregarding your statements? +[02Dec2005-12:52:17] Cratylus <cre> the way i see it, there are two possibilities +[02Dec2005-12:52:49] Cratylus <cre> first: you did expect me to know what you were talking about, making you a narrow-minded and deeply self-centered person +[02Dec2005-12:53:45] Cratylus <cre> second: you did not expect me to know what you were talking about. this means the point of the statement was to make me ask you what you were talking about, which is pointless and rude. +[02Dec2005-12:54:25] Cratylus <cre> i suppose there is a third, which is that you didn't care one way or another. since this makes you an asshole, i more or less rules that out, but if the shoe fits. +[02Dec2005-12:59:03] Jayren <cre> let's examine those 1: did expect you. can eliminate this one already because i had no such expectation. 2: did not expect you to know. see note 1: above. and 3: i am an asshole. i really think that would be more appropriate if you had asked and i went and laughed and not told you. instead, i gladly told you what those elements were. don't think asshole fits either sorry. +[02Dec2005-12:59:21] Cratylus <cre> hmm +[02Dec2005-12:59:53] Cratylus <cre> ok, how about this, then +[02Dec2005-13:00:55] Cratylus <cre> a friend of mine and i go to lunch, have a good time, and we talk about stuff. i tell her that i'm working on a mudlib called dead souls, the driver of which is mudos, and which is running on a computer called frontiers. +[02Dec2005-13:01:56] Cratylus <cre> few days later we get back together. i tell her that frontiers needs a recompile of mudos for dead souls +[02Dec2005-13:02:42] Cratylus <cre> given that i only mentioned these names once, and that they have no relevance to her life, i think i can reasonably guess she won't know what i'm talking about +[02Dec2005-13:03:42] Jayren <cre> she might have a really good memory though and remember these things from the other day. +[02Dec2005-13:03:46] Cratylus <cre> if someone pauses life there, and asks me, "ok, now, you must guess. will she remember what a mudlib is, and its relationship to a mud and driver, and what frontiers is?" +[02Dec2005-13:04:12] Cratylus <cre> i have two buttons. on for "yes she will remember" and one for "no, she wont" +[02Dec2005-13:04:50] Cratylus <cre> given how irrelevant this knowledge is, the fact that it was mentioned once, and days have passed, during which her life went on, with her havingt to remember things that actually do matter... +[02Dec2005-13:05:04] Cratylus <cre> i would tend to guess no. she won't remember. that seems the most likely outcome +[02Dec2005-13:05:21] Cratylus <cre> it is *possible* she'll remember, but that is less likely +[02Dec2005-13:05:45] Cratylus <cre> therefore, i push the "no" button +[02Dec2005-13:05:53] Cratylus <cre> which button would you push? +[02Dec2005-13:05:59] Jayren <cre> you can't know if she will remember or not. you just have to be happy to explain if she asks you can't laugh and go 'i wont tell you.' +[02Dec2005-13:06:05] Cratylus <cre> which button would you push? +[02Dec2005-13:06:35] Jayren <cre> i wouldn't push either one. +[02Dec2005-13:06:45] Cratylus <cre> you are not being reasonable +[02Dec2005-13:06:53] Jayren <cre> or, i'd push both at once, just to fuck up the system. +[02Dec2005-13:06:53] Cratylus <cre> this discussion can have no further purpose +[02Dec2005-13:06:57] Cratylus <cre> goodbye +[02Dec2005-13:08:44] Jayren <cre> i think it did serve a purpose. i now understand what button you would press and why. and i've just explained why i wouldnt push either. diff --git a/lib/domains/town/txt/shame/chapter05 b/lib/domains/town/txt/shame/chapter05 new file mode 100644 index 0000000..b04b6c0 --- /dev/null +++ b/lib/domains/town/txt/shame/chapter05 @@ -0,0 +1,934 @@ +chapter 5 "The Great Heat Radiation Debate, December 1999" + +Cast of Characters: +Cratylus, a self-righteous know-it-all UNIX engineer +Thorr, some high school kid +Hermogenes, a wiseacre aerospace computer scientist + + +Part I is seen through the eyes of Cratylus +in the same room as Hermogenes. During the conversation, +Thorr interjects some unrelated stuff through +the <cre> communications channel. + +Part II is again seen through the eyes of +Cratylus, but this time Hermogenes and Cratylus are +in different rooms, and communicate through +the <admin> channel. + + +PART I +------ + +Hermogenes says, "Or whatever they call em." +Hermogenes asks, "But thats defined by the server?" +You say, "Its mudos dependent." +Hermogenes asks, "Like, number of cycles per second or something?" +You say, "Depends what parameters it was compiled with, and what gets passed to it in config and startup." +You say, "Yeah." +Hermogenes asks, "Yoou can set it to whatever you want?" +You say, "I imagine so." +Hermogenes says, "Like, i want 10 tics per second of processor time." +Hermogenes says, "Hmm." +Hermogenes asks, "Why couldnt My Big Game run similarly to a mud?" +Frontiers has been up for 2w 6d 5h 10m 37s. +You say, "I dont really understand your question." +Hermogenes says, "In my game thing..." +-------------------------------------------------------------------------- +4 people in current sort Eastern time: Mon Dec 27 14:24:40 1999 +-------------------------------------------------------------------------- +253 D - Cratylus sun-barr.Sun.CO ~cratylus/workroom +100 D - (Frontiers) cv ~frontiers/workroom +24 D - Hermogenes macpub800.gsfc. ~cratylus/workroom +2 h - Thorr sailor.lib.md.u ^campus/room/wiz_loung +-------------------------------------------------------------------------- + Frontiers +Hermogenes says, "Could i just have the server listening for commands..." +Hermogenes asks, "And stuff happens in 'tics'?" +You say, "You tell me." +Hermogenes says, "YEAH." +Hermogenes says, "I WILL." +You say, "Heh." +Hermogenes says, "Yeah." +Hermogenes says, "Doin it." +You say, "Yeah." +You say, "Doin it." +Hermogenes says, "Iiiiii saw YOU." +Hermogenes says, "Im almost tempted to listen to that right nw." +Hermogenes wants to know the diff between convection, conduction, and radiation +Hermogenes exclaims, "NnnnnNNNNNOW!!!" +You say, "Hmm." +Hermogenes takes off his shoe and starts banging it on the table +You say, "Convection is about temperature-related airflow." +Hermogenes says, "Classic stalin." +Hermogenes says, "Or lenin." +You say, "Kruschev." +Hermogenes says, "Ohhh yeah." +Hermogenes says, "I think some older guy did it, too." +Hermogenes says, "Aaanyways." +Hermogenes asks, "Convection is ONLY concerned with gaseous heat transfer?" +You say, "Prolly not." +Hermogenes says, "B'oh." +You say, "I imagine liquids have similar properties." +Hermogenes says, "I could ask on IG..." +Hermogenes says, "But i dont wanna know THAT bad." +You ask, "Why not look it up?" +Hermogenes says, "Pfah." +Hermogenes says, "Thats yer answer to EVERYthing." +You say, "Heh." +Hermogenes says, "Shoot." +Hermogenes says, "Im so used to stopping the initial loading of my homepage." +Hermogenes says, "But this time i WANTED it." +Hermogenes says, "Heh, this keychain has a y2k countdown timer on it..." +You say, "Anyways convection currents are useful knowledge to aviators and boat people." +Hermogenes says, "Only 4 days left on it." +Hermogenes says, "E has a convection oven..." +You say, "Vultures can ride "thermals" for hours without flapping their wings." +Hermogenes says, "Fuggin lazy bums." +You say, "Ans for submarines, thermocline layers are important acoustic landmarks." +Hermogenes nods solemnly. +Hermogenes says, "I remember goin out in th boat with my dad." +Hermogenes says, "Hed drive, id watch the sonar thingie." +Hermogenes says, "Id occassionally see thermocline layers." +You say, "Well there ya go." +Hermogenes says, "Conduction = opaque solids." +You ask, "Ya heat transfer huh?" +Hermogenes says, "Convection = solid surface in contact with moving liquid or gases." +Hermogenes says, "Ya, heat transfer." +Hermogenes says, "I mean, i KNEW it was heat transfer." +You say, "And i guess radiation is the transfer of heat energy from solid to gas." +Hermogenes says, "I just dint know what set them apart." +Hermogenes says, "Well..." +You say, "Well u cant radiate heat in aa vacuum." +Hermogenes says, "Substandces cdont hafta be touching." +Hermogenes says, "In radiation heat transferrence." +Hermogenes says, "Actually..." +Hermogenes says, "I was about to saty...." +You say, "Well its gotta touch SOMETHING." +Hermogenes says, "This process is different from both conduction and convection, because the substances exchanging heat need not be touching and can even be +separated by a vacuum." +Hermogenes says, "Bplhtplhtlt." +You say, "Doesnt make sense to me." +You say, "Explain how u can radiate heat in aa vacuum." +Hermogenes asks, "Cantcha transmit heat over a vaccuum?" +You say, "No." +Hermogenes asks, "What about th sun?" +You say, "Thats the whole idea behind thermoses." +You say, "Thats aa different KIND of radiation." +Hermogenes asks, "Space != complETE vaccuum?" +You say, "The sun is particle radiation." +Hermogenes says, "Thermoses dont complETELY stop heat loss." +You say, "And em." +You say, "Well cuz theyre not comPLETE vacuums." +Hermogenes says, "Hmm." +Hermogenes says, "I cant really argue with ya, since i dont know much about it in the foist place." +You shrug. +You say, "No like im aa textbook." +You say, "I just dont see how you could radiate heat in aa vacuum." +You say, "Except in electrmagnetic wave form." +Hermogenes asks, "Microwave?" +You say, "Like, if i got shot out of an airlock, right." +Thorr <cre> > what happened to haderach +Hermogenes <cre> > hmm +Hermogenes <cre> > hes on here oCASSIOanlly +Hermogenes <cre> > not all THAT often +You say, "Im 98.something degrees." +Thorr <cre> > yeah.. he is not even a character tho +Hermogenes <cre> > if ya email ed hima and told him other people were interested in workin on the mud, he might show up more frequently +You say, "If u put aa thermometer RIGHT next to me." +You say, "Without touching." +Hermogenes listens +You say, "I doubt it would be affected." +Hermogenes asks, "At ALL?" +You ask, "How could it?" +You say, "If i was radioactive, sure." +Hermogenes asks, "The IR energy radiatinfg from yer body?" +You say, "Like i said, eventually u would cool down through em emmission." +You say, "But thats not the kind of radiation theyre talkin about." +Hermogenes says, "A law formulated by German physicist Max Planck in 1900 states, in +part, that all substances emit radiant energy simply because they have a +positive absolute temperature." +You say, "Like i SAID." +Hermogenes asks, "Er, so ther?" +You say, "Like i said, eventually u would cool down through em emmission." +You say, "But thats not the kind of radiation theyre talkin about." +Hermogenes says, "Electromagnetic emmission?." +Hermogenes says, "Ymean, in the IR range?." +Hermogenes says, "Im not tryin to nit pick, im tryin to understand yer explanation." +You say, "Ok." +You say, "A warm coal radiates heat." +You say, "Because its warm." +You say, "And it warms the air around it." +Thorr <cre> > i gotta do some actual work.. bbl +<cre> > Thorr waves. +You say, "This is the kind of radiation that I mean when i say heat radiation." +Hermogenes <cre> > see ya +<cre> > Cratylus waves. +Hermogenes says, "Right." +[Thorr quits] +You say, "Absent air, were talkin about aa different kind of radiation." +Hermogenes says, "Transmitting of energy in the infrared range = heat." +You say, "That i would tend NOT to call "heat radiation"." +You say, "But electromagnetic radiation." +You say, "Which is aa whole other can o beans." +Hermogenes says, "Mmm, beans." +You say, "SO." +You say, "When u say convection, conduction, radiation." +You say, "I do not think em radiation." +You ask, "See my point?" +Hermogenes asks, "But.. isnt IR within the EM spectrum?" +You say, "EXACTLY." +You say, "The coal MAY be radiating ir, but thats not what im talking about." +Hermogenes says, "'youd NOT call it 'heat radiation', but you WOULD call it 'EM radiation'." +You say, "Yes." +Hermogenes says, "Even though, heat radiation == IR radiation." +You say, "Bullshit." +Hermogenes says, "Ok ok." +Hermogenes says, "Sorry." +You shrug. +You say, "I disagree with that statement." +Hermogenes asks, "Yer sayin for het to be radiat4d, there hasta be air, in the example of the coal?" +You say, "I think u can also see it as patently false." +You say, "Right." +Hermogenes says, "No need to jump all over my case, im just tryin to understand how yer percieving the problem." +You say, "Now, if my definition of heat radiation is mistaken, then thats something else." +Hermogenes says, "O K then." +You say, "But i do not equate infrared radiation with heat radiation." +Hermogenes asks, "Whyzzat?" +Hermogenes says, "Not that im arguing, im just wonmdering why you say that." +Hermogenes says, "Sir." +You emote: Cratylus is confused. +You ask, "Why WOULD you say that?" +Hermogenes says, "Mebbe my understanding of "heat" is incorrect." +You say, "What makes u think heat radiation == IR radiation." +You say, "Well im curious why u think that." +Hermogenes breaks down and starts to cry +You say, "Dont mean to jump all over yer case." +Hermogenes says, "I thought..." +You say, "I just dont see where youd think that." +Hermogenes says, "What as an object transmits more n more energy..." +Hermogenes says, "It starts to transmit it in different areas of the EM spectrum." +You say, "Ok." +You ask, "Why do you equate heat with energy?" +Hermogenes asks, "Right|wrong?" +Hermogenes says, "B... b... be-cause..." +You shrug. +You say, "Again, i could be dead wrong." +Hermogenes asks, "Heat is what we perceive IR energy as?" +You say, "Erm." +You say, "Well i dont think heat is about perception." +Hermogenes says, "Or not." +You say, "I think heat is about molecular motion." +Hermogenes says, "Right...." +You say, "And for that to transfer." +You say, "U need molecules." +You say, "Hence, no vacuum." +Hermogenes says, "You cant have a PERFECT vaccuum, though." +Hermogenes says, "But thats a different topic." +You say, "So you can see why i would disagree with your source." +Hermogenes says, "Im still tryin to figure out why (hea == IR) is false." +You say, "Explain to me why it is true." +Hermogenes yields +You hmm. +Hermogenes says, "Im sorry, i cant argue." +Hermogenes is at a loss for words currently +Hermogenes says, "No fense, i mean." +You say, "Well im sure there is aa relationship between heat and ir, but i do not see these as being the same thing." +You shrug. +You say, "You may be right." +You say, "But i doubt it." +Hermogenes shrugs. +Hermogenes says, "Heh." +You smirk. +Hermogenes says, "Ya just HAD to throw that disclaimer in tehre, DINT cha." +Try "help index" for a list of command types. +You emote: Cratylus snickers. +Hermogenes says, "Cool page, so far:." +Hermogenes says, "Http://www.ipac.caltech.edu/Outreach/Edu/infrared.html." +Hermogenes says, "The primary source of infrared radiation is heat or thermal radiation." +You say, "So then they are NOT the same thing, right." +Hermogenes says, "Ok, mebbe i was not conveying my thoughts too well." +You say, "Just because i arrive in aa car doesnt mean im aa car." +Hermogenes says, "Ya friggin car." +Hermogenes says, "For example, hot charcoal may not give off light +but it does emit infrared radiation which we feel as heat." +You ask, "Ok. what does that illustrate?" +Hermogenes says, "The more energy an object is giving off..." +Hermogenes says, "The higher up in the em spectrum it can be perceived at." +You ask, "Mmhmmm?" +Hermogenes says, "In." +Hermogenes says, "Of." +You say, "Ok." +You ask, "So how does that prove that heat radiation works in aa vacuum?" +Hermogenes is lookin at the creepy kitty picture on that page +Hermogenes says, "I." +Hermogenes says, "Dont." +Hermogenes says, "KNOW." +You emote: Cratylus calls off the dogs. +You say, "Sorry." +You say, "I get very focused." +Hermogenes says, "But aPPARRENTLY, with "radiation" heat transfer, objects dont HAFTA be touching." +You say, "If there is air between them, i agree." +Hermogenes says, "And yknow." +Hermogenes says, "Mebbe these 3 types of transference isnt JUST heat transfer." +Hermogenes says, "Mebbe they mean ENERGY transfer." +Hermogenes says, "But i think they DO mean heat transferrence." +You say, "Me too." +Hermogenes says, "Which doesnt really settle nuttin." +Hermogenes says, "That DOES it." +You say, "Well it settles that theyre wrong." +Hermogenes says, "W." +Hermogenes says, "We must ask the sages of IG." +You say, "Heh." +Hermogenes asks, "Ya want to?" +You say, "Ohhh mighty oracle..." +Hermogenes says, "Or, naaah." +You say, "If u want garbage, go ahead." +Hermogenes asks, "Didja see the creepy kitty pic yet?" +You say, "Ya." +You say, "Blue prolly can say." +Hermogenes says, "SOMEtimes, ig has some answers." +Hermogenes says, "Im gunan try it." +Hermogenes says, "No WAIT." +Hermogenes says, "Im about to head over to other building." +Hermogenes says, "Ill try in an hour or so." +You say, "Well im goin home fairly soonish." +Hermogenes says, "But i gotta formulate the correct question, foist." +You say, "If you find credible documentation of yer crackpot theory lemme know." +Hermogenes asks, ""can heat be transferred in a vaccuum?" ?" +You say, "No." +You say, "That is not quite the question." +Hermogenes says, "Ok, then what." +Hermogenes asks, "What IS the question?" +Hermogenes says, "Say it." +Hermogenes exclaims, "SAY IT!!!" +You ask, "Is infrared radiation heat?" +Hermogenes says, "I THINK it means./..." +Hermogenes says, "Em radiation transmitting .." +Hermogenes says, "Phone." +You say, "Because OBVIOUSLY heat is transferred in aa vacuum." +You say, "But what were talking about is HEAT RADIATION." +Hermogenes scribbles in his memo pad. +You say, "Thats right. you DO yer homework." +Hermogenes says, "Btplhpbtplbpt." +Hermogenes says, "Im "writing down" the url to that page." +Hermogenes says, "With the kitty poicture on it." +Hermogenes says, "I THINK, its saying..." +Hermogenes says, "EM radiation transmitting at X frequency is perceived by us as "heat"." +You say, "That sounds about right yeah." +Hermogenes says, "Just like something rtansmitting between X and Y nm is perceived as "light"." +You say, "Sounds right so far." +Hermogenes says, "So..." +You ask, "So...?" +Hermogenes asks, "Would you argue that something transmitting in the visible portion of the em spectrum is|isNOT light?" +You say, "I find your parallel flawed." +You say, "The definition of heat and the definition of light are very different." +Hermogenes says, "Well, of COURSE its flawed." +Hermogenes says, ""how so?" :)." +You say, "Ok, walk through this with me." +Hermogenes attempts patience... +You say, "Heat is molecules moving, aka brownian motion." +Hermogenes says, "Heat is kinetic energy of molecules in motion, ook." +You say, "Heat radiation occurs when molecules of aa lower "temperature" touch molecules of aa higher "temperature"." +You say, "Now." +Hermogenes says, "So how can they transfer heat when theres no molecules to bump into." +Hermogenes says, "Ok." +You say, "If there is aa vacuum between these two objects of differing temperatures." +You say, "On MAY be warmed up by the other." +You say, "I dont dispute that." +You say, "But it would be warmed up not by HEAT radiation, since "HEAT" is not radiated through aa vacuum." +Hermogenes says, "BUT." +You say, "It would be warmed up by the effects of ir radiation." +Hermogenes says, "Theres doesns not exIST a perfect vacuumm." +You say, "Dude you must join me." +You say, "We dont have these objects either." +Hermogenes says, "Mebbe the few molecules in the non-perfect vaccuum are enough to transfer the heat or somerthin." +You say, "Nor do they possess frickin laser beams." +Hermogenes asks, "Yer sayin in a THEORHETICAL vaccuum?" +You say, "In MY world, when u talk about aa vacuum, its aa vacuum." +You ask, "Yer book...did it specify an imperfect vacuum?" +Hermogenes says, "I mean, are you arguing on a pure le." +Hermogenes says, "Ok, you are." +Hermogenes says, "Yes, it did." +You say, "Well then its not aa vacuum." +You say, "Its aa vacuum or its not." +You say, "U cant have both." +Hermogenes says, "It said somthin like "a perfect vaccuum cant be created, even with the best equipment, etc etc"." +You say, "Well fuckin aa DU." +You say, "DUH if theres shit flyin around in there sure there can be heat transfer." +Hermogenes says, "So, this brings me back to their assertion of objects not having to touch." +Hermogenes says, "For heat transfer." +You say, "But that totally defeats the idea of heat radiation in aa vacuum." +Hermogenes says, "Ok, point taken." +You say, "They DO touch, indirectly, through the flying molecules in yer imperfect vacuum." +Hermogenes asks, "Why bother making up a law of thermal transferrence if the environment will never exist?" +Try "help index" for a list of command types. +Hermogenes says, "For such a law." +You emote: Cratylus blinks. +[Thorr logs in] +Hermogenes says, "Okokok,." +You ask, "U joking?" +Thorr <cre> > lo +Hermogenes says, "I hate to do this." +Cratylus <cre> > oi +Hermogenes <cre> > ey +Hermogenes asks, "Can i "pause" this discussion?" +You say, "I thought we just agreed i was right." +Hermogenes asks, "Or do i forfeit all claims by leaving the table right now?" +You shrug. +You say, "I thought u just agreed with me." +Thorr <cre> > is it worth creating an area.. or is the new lib gonna cancel out anytyhing i do? +Hermogenes says, "Lol." +Cratylus <cre> > hold off +Thorr <cre> > anything that is +Thorr <cre> > ok +Thorr <cre> > what exactly is gonna change ?? +Hermogenes <cre> > you might wanna start PLANNING out an area, but hold off on the actual coding of it +Cratylus <cre> > everything +Thorr <cre> > whoa +Hermogenes <cre> > it will shake the very foundation of life as you know it +Thorr <cre> > hehe +Cratylus <cre> > it might even radiate heat in aa vacuum +Hermogenes <cre> > heat will even transfer over a vaccuum, in the new mud lib +Hermogenes <cre> > hahahahaha +Try "help index" for a list of command types. +Cratylus <cre> > :) +Thorr <cre> > heh +Hermogenes <cre> > dammit, quit stealin all my material +Cratylus <cre> > i gotta hit the road ill be back later +Thorr <cre> > k +Thorr <cre> > see ya +Hermogenes <cre> > ya, im goin to new building +Hermogenes says, "Ill be back round 4pm." +Cratylus <cre> > ill be back in 20 or, well pick up this convo +Hermogenes says, "DEFinately." +Hermogenes waves. +Thorr <cre> > ok +<cre> > Cratylus waves. +Please come back another time! + + +PART II +------- + +Hermogenes <admin> bak +Hermogenes <admin> btw, ennytime you wanna pick our conversation bout heat transf3errence, lemme know +Try "help index" for a list of command types. +Cratylus <admin> i thot u agreed with me +Hermogenes <admin> i have NO idea ... +Hermogenes <admin> restate your assertion, please? +Hermogenes <admin> or do you not wanna open that can o worms again +<admin> Cratylus wonders why he always has todo all the splainin. +Hermogenes <admin> or you scaaaared? +Cratylus <admin> ok +Cratylus <admin> ready? +<admin> Hermogenes nods solemnly. +Cratylus <admin> you said heat radiation can occur even through aa vacuum +Cratylus <admin> i disagreed +Hermogenes <admin> i said that cause the web page said that +Hermogenes <admin> but, go on +Cratylus <admin> then u said ir waves WERE heat, hence heat radiation DID go through aa vacuum +Cratylus <admin> i explained that there is aa diff between ir and heat +Hermogenes <admin> but then i changed my thing... +Cratylus <admin> im gettin to it +Hermogenes <admin> to say that 'heat' was how we PERCEIVE ir radiation +Cratylus <admin> you know theres aa transcript +Cratylus <admin> check yer email +Cratylus <admin> go +Hermogenes <admin> jeez, you didnt +Cratylus <admin> now +Hermogenes <admin> ok okok, i will +Cratylus <admin> i KNEW this would happen +Hermogenes <admin> ok, i talked to someone +Hermogenes <admin> hes on one of the... +<admin> Hermogenes hesitates +Cratylus <admin> mmhmm +Hermogenes <admin> science teams +Cratylus <admin> DON'T SHOOT! +Hermogenes <admin> :) +Hermogenes <admin> and, aPARRENTly... +Hermogenes <admin> a molecule can transfer heat to another molecule withOUT tyouching +Cratylus <admin> yes +Cratylus <admin> i know +Cratylus <admin> i said that aa million fuckin times +Cratylus <admin> the issue here is not wether there is heat transfer dude +Hermogenes <admin> so, molecule A can heat molecule B without touching +Cratylus <admin> yes +Cratylus <admin> agreed +Cratylus <admin> but not through "heat radiation" +Hermogenes <admin> IR emmission +Cratylus <admin> RIGHT +Hermogenes <admin> or IR radiation or whatEVER you wanna call it +Cratylus <admin> which is the WHOLE POINBT of my argument +Cratylus <admin> that you CAN transfer heat thru aa vacuum +Cratylus <admin> but it ISNT "heat radiation" +<admin> Hermogenes waits for the punchline... +Hermogenes <admin> ohhhhh, wait +Hermogenes <admin> i think i see +Cratylus <admin> waddaya mean? what word did you have trouble with? +Hermogenes <admin> your main beef was with the term "heat radiation" as opposed to the more PROPER term of "IR radiation"?? +Cratylus <admin> well yes +Cratylus <admin> sort of +<admin> Hermogenes stares at you +Cratylus <admin> not quite tho +<admin> Hermogenes stares at you intently +Cratylus <admin> ok +Cratylus <admin> question +Hermogenes <admin> ok, im HOPING this hasnt been a giant battoe of semantics +Cratylus <admin> do you think ir radiation == heat radiation? +Hermogenes <admin> now, NO, i dont +Cratylus <admin> oK then +Cratylus <admin> that was my point +Hermogenes <admin> i had my terms jumbled up, and +Cratylus <admin> so basically we agree +Hermogenes <admin> aaaahhh +Hermogenes <admin> yes +Hermogenes <admin> so, yer whole POINT was to show how i was WRONG in my useage of the terminology? +Cratylus <admin> you kept sayin stuff that assumed ir == heat, which is not true +Cratylus <admin> the idea was to point out that yer source was not correct +Hermogenes <admin> heat is the term we assign to the perception of IR radiation, just as light is how we descripe the process of seeing photon particles interacting with our eyes, etc +Cratylus <admin> no +Hermogenes <admin> ah HA +Cratylus <admin> that also is not correct +Cratylus <admin> heat is not aa subjective experience +Cratylus <admin> it is aa measurable state of molecular motion +Hermogenes <admin> yer assuming my SOURCE is not correct, when in fact, it could very well be (and probably WAS)my INTERPRETATION of my source +Cratylus <admin> could be +Hermogenes <admin> wait, heat is not a what? +Cratylus <admin> heat is not aa subjective experience +Cratylus <admin> it is aa measurable state of molecular motion +Hermogenes <admin> riiiight, and light isNT? +Cratylus <admin> i dont know why u keep bringing light into this +Hermogenes <admin> i mean, not molecular motion, i mean objectively measurable +Cratylus <admin> im not concerned with light at the moment +Hermogenes <admin> because light n heat are on th same EM spectrum, aint they? +Cratylus <admin> whoa +<admin> Cratylus sits you down. +Cratylus <admin> you better cool that walnut off +Hermogenes <admin> fine fine, IR emmission and visible light emission are +Cratylus <admin> right +Cratylus <admin> so what? +Cratylus <admin> were talkin about heat + Hermogenes <admin> so... +Hermogenes <admin> uh... +Cratylus <admin> which is NOT on the em spectrum +Hermogenes <admin> so THERE! +Hermogenes <admin> WHAT? +Cratylus <admin> were talkin about heat +Cratylus <admin> which is NOT on the em spectrum +Hermogenes <admin> IR is NOT on the em spectrum? +Cratylus <admin> oh my FUCKING GOD +Hermogenes <admin> ok, NOW im confused +Cratylus <admin> are you pullin my leg or what? +Hermogenes <admin> i must be TOTALLY thinkin of somethin else +Hermogenes <admin> please, to define "em spectrum" +Cratylus <admin> ok im sorry if i sound condescending, but damn you deserve it +Hermogenes <admin> well excuuuUUUuuuuUUuuUuuuse ME for not clearly defineing all th terms from th onset +Cratylus <admin> when electromagnetic energy is radiated, its measured on what we call the em spectrum +Hermogenes <admin> ya? +Cratylus <admin> heat is NOT electromagnetic energy +Hermogenes <admin> but IR radiation is? +Cratylus <admin> but when something IS hot, it emits em waves +Cratylus <admin> somthing that IS hot emits IR +Cratylus <admin> but the heat itSELF is not the IR +Cratylus <admin> the heat is aa different kind of energy +Cratylus <admin> and though the IR waves MAY heat up another object... +Hermogenes <admin> isnt heat how we describe the perception oof said ir energy? +Cratylus <admin> this transfer of energy is not what you can call "heat radiation" +Cratylus <admin> NO DUDE NO +Cratylus <admin> BAD HERMOGENES +<admin> Hermogenes goes back to the page with the creepy kitty pic +Cratylus <admin> define heat please +Hermogenes <admin> mostly to look at the creepy kitty pic, that is +Cratylus <admin> i thought YOU were the scientist in the family +Hermogenes <admin> um, define heat? +Cratylus <admin> yes. define heat +Hermogenes <admin> the amount of hotness soemthing has? +Cratylus <admin> ok let me tell you what webster says heat is +<admin> Hermogenes notes there are over 20 definitions... +Hermogenes <admin> but, go on +Hermogenes <admin> meestor WEBSTER dude +Cratylus <admin> "the energy associated with the random motions of molecules, atoms, or smaller structural units of which matter is compised" +Hermogenes <admin> asSOCiated with +Cratylus <admin> notice there is no mention of electromagnetism +Cratylus <admin> heat, man, is this molecular motion +Cratylus <admin> nothing else +Cratylus <admin> kinetic energy +Hermogenes <admin> ok +<admin> Hermogenes snives. +Cratylus <admin> as it HAPPENS, this energy tends to emit some electromagnetic radiation +Hermogenes <admin> oooOOo, whatta coiINcidince +Cratylus <admin> but the em radiation is NOT heat +Hermogenes <admin> so... +Hermogenes <admin> yer sayin/.... +Cratylus <admin> it is em radiation, like the color blue or xrays +Hermogenes <admin> the molecular motion emits the ir stuff? +Cratylus <admin> well, the heat energy does ya +Hermogenes <admin> heat energy? +Cratylus <admin> ya +Cratylus <admin> i dont know if the motion and the energy are the same thing +Cratylus <admin> but thats aa diff argument +<admin> Hermogenes feels sufficiently dumb now, thankyouverywelcome +Cratylus <admin> so, what im sayin is: +Cratylus <admin> when u warm yourself at aa roaring fire +Hermogenes <admin> ooo, dats toasty +Cratylus <admin> you are being warmed by "heat radiation" +Hermogenes <admin> "heat radiation" +Cratylus <admin> the heat, or rapidly moving air/fuele molecules, are speeding up YOUR molecules through contact +Hermogenes <admin> as in "conduction, convection, RADIATION"? +Hermogenes <admin> aaah +Cratylus <admin> LISTEN +Cratylus <admin> the heat, or rapidly moving air/fuele molecules, are speeding up YOUR molecules through contact +Cratylus <admin> it also happens that the fire MAY be causing your molecules to move faster ALSO through some IR radiation, but this amount of heating is insignificant +Hermogenes <admin> ok, +Hermogenes <admin> can i interject at this moment? +Cratylus <admin> sure +Hermogenes <admin> er, MAY i +Hermogenes <admin> the scientist dude ALSO said somethin about: +Cratylus <admin> get that fucking dude in here +Cratylus <admin> go get him +Cratylus <admin> ill wait +Hermogenes <admin> how the earths atomoshpere n crust n stuff arent warmed by particles from the sun hittin them... +Hermogenes <admin> but from the IR radiation +Cratylus <admin> ya i know +Cratylus <admin> go get him +Hermogenes <admin> he left +Cratylus <admin> FUCK +Hermogenes <admin> and like i need MORE people on my case +Cratylus <admin> seriously dude yer not getting it +Hermogenes <admin> OR, like i need a coworker gettin into nan argument with you +Hermogenes <admin> OH MY GOSH! +Cratylus <admin> for some reason yer unable to separate heat from infrared radiation +<admin> Hermogenes aGREES with you! +<admin> Hermogenes is NOT gettin it! +Cratylus <admin> for some reason yer unable to separate heat from infrared radiation +Hermogenes <admin> im sorry, man,i really am +Cratylus <admin> its like saying that because an airplane is flying, it IS flight +Hermogenes <admin> its just one of those cases... +Hermogenes <admin> where the one gear is not in place +Cratylus <admin> I'LL say +Hermogenes <admin> that ONE little 8-tooth gear has slipped +Cratylus <admin> well id like to state for the record that i dont think this is some subtle semantic difference +Cratylus <admin> this is aa fundamental difference in types of energy and radiation +Cratylus <admin> but we can come back to it later +Hermogenes <admin> your statement has been entered into the almighty records of whosrighteedness +Cratylus <admin> ehehehehehe +Hermogenes <admin> so, its been snowing up tehre? +Cratylus <admin> very briefly +Cratylus <admin> none left on the round +Try "help index" for a list of command types. +Hermogenes <admin> we havent gotten ANYthing +Cratylus <admin> musta got it +Cratylus <admin> the HEAT RADIATION musta got it, that is +Hermogenes <admin> its sposed to get up in th 50s morrow +Hermogenes <admin> NOOOOOOO!!!!! +Cratylus <admin> oooohhhhh wait aa minute +Hermogenes <admin> im seriously miffed bout this whole heat thing, btw +Hermogenes <admin> wha +Cratylus <admin> i get it now +Hermogenes <admin> do i wanna know? +Cratylus <admin> i think i see how youre looking at it +Cratylus <admin> maybe +Hermogenes <admin> very well could be +Cratylus <admin> ok +Hermogenes <admin> ive looked at things "wrong" before... +Cratylus <admin> tell me if this is what yer thinking: +Hermogenes <admin> k +Cratylus <admin> when heat causes radiation, thats "heat radiation" +Hermogenes <admin> mmmm.... +Cratylus <admin> ok maybe not +Cratylus <admin> worth aa try +Hermogenes <admin> when an object is "energized" enough, it begins to radiate in the iR portion of the em spectrum +Cratylus <admin> yeah +Cratylus <admin> and thats what u mean by "heat radiation"? +Hermogenes <admin> energized usually means addding heat or electricity or SOMEthing to it +<admin> Cratylus nods. +Hermogenes <admin> well... +Hermogenes <admin> the IR radiation brought on is then perceived by our senses as "heat" +Cratylus <admin> ok +Cratylus <admin> do u mind if i drag this on aa bit longer? +Hermogenes <admin> if more energy is added, it then begins to transmit in the visible portion of the em spectrum, and we perceive this as ''light' +Cratylus <admin> i really am interested in understanding our difference here +Hermogenes <admin> as am i +Cratylus <admin> see, i dont think that the IR radiation heats up other things all that much +Hermogenes <admin> actually, +Cratylus <admin> when i put my hand up to aa light bulb, and its hot, +Cratylus <admin> i dont think its because of IR, although some IR is present +Hermogenes <admin> scientist dude sed that IR ardiation is actually quite effective in heating up stuff +Hermogenes <admin> heh, ardiation +Cratylus <admin> ok, but just bear with me aa moment +<admin> Hermogenes bears +Cratylus <admin> lets assume, for the pure sake of argument, that IR radiation does not exist + Hermogenes <admin> heh, sake of argument +Hermogenes <admin> ok, go on +Cratylus <admin> IF there is not IR radiation, could you still warm yourself by the fire? +Hermogenes <admin> uhhh.. yes +Cratylus <admin> by what process? +Hermogenes <admin> ummmm +Hermogenes <admin> light? +Cratylus <admin> no +Cratylus <admin> heat radiation +Cratylus <admin> see i think this is where we went in diff directions +Cratylus <admin> your brain is bent on seeing the word "radiation" in terms of particles or wavelengths +Hermogenes <admin> or, the act of transmitting particles or wavelenghths or whatever +Cratylus <admin> in the context of convection and conductance, this approach to the word "radiation" is not fruitful +Cratylus <admin> thats where we are having aa communication breakdown +Cratylus <admin> again for the sake of argument, lets assume there is no electromagnetic or particle radiation +<admin> Hermogenes likes wavelenghths n particles n stuff... +Cratylus <admin> again for the sake of argument, lets assume there is no electromagnetic or particle radiation +Hermogenes <admin> whata a dismal world +Cratylus <admin> the fireplace is radiating heat +Cratylus <admin> heat comes from it, hence, it "radiates heat" +Cratylus <admin> this is "heat radiation" +Hermogenes <admin> hmmm +Hermogenes <admin> in a loose definition, ok +Cratylus <admin> no +<admin> Hermogenes gasps in shock! +Cratylus <admin> that is not aa loose definition +Cratylus <admin> that is the definition of the word radiate +Cratylus <admin> "to radiate" +Hermogenes <admin> wait, is THAT all there is to "heat transferrence by radiation"? +Cratylus <admin> YESSSSSSS +Cratylus <admin> EXACTLY +Hermogenes <admin> heat comes from it, hence, it "radiates heat" +Hermogenes <admin> heat comes from it, hence, it "radiates heat" +Hermogenes <admin> heat comes from it, hence, it "radiates heat" +Hermogenes <admin> hmmmmm +Hermogenes <admin> ok +<admin> Hermogenes can accept that +Cratylus <admin> ok back to our dismal theoretical world +Hermogenes <admin> wait +Cratylus <admin> which contains no particle or em radiation +Hermogenes <admin> i thought we were done? +Cratylus <admin> oh +Cratylus <admin> ok +Cratylus <admin> so u see my point? +Hermogenes <admin> mmmm, sorta +Cratylus <admin> then we are not donme +Hermogenes <admin> i was making it way too more complicated than it needed to be? +Cratylus <admin> you were on aa different train track altogether + Hermogenes <admin> i was on one of those hovertrains +Hermogenes <admin> on magnetic rails +Cratylus <admin> btw the fireplace does not radiate heat through "light" +Hermogenes <admin> it dont? +Cratylus <admin> it radiates heat by contact with molecules which transmit the heat in the form of kinetic energy +Hermogenes <admin> howcome a black shirt gets hotter than a white shirt, then? +Cratylus <admin> in front of aa fire? +Cratylus <admin> ive never noticed any such thing +Cratylus <admin> in the sun, yeah sure +Hermogenes <admin> but i thought we already established that molecules dont HAFT bounce off eachother to transfer heat? +Hermogenes <admin> hmmm +<admin> Cratylus falls to the floor. +Hermogenes <admin> so, you think a black tshort and a white tshirt in a non-sun light source would not heat differntly? +Cratylus <admin> in front of aa fireplace, i dont think there would be aa noticeable differennce +Hermogenes <admin> im not tryin to argue, im tryin to follow a tangential tracxk for a sec +Cratylus <admin> i think with delicate instruments u WOULD detect aa diff +Hermogenes <admin> NOTCEABLE +Cratylus <admin> this is actually right on track dude +Cratylus <admin> i think with delicate instruments u WOULD detect aa diff +Hermogenes <admin> OH, suddenly im allowed to play on YOUR traintrack? +Hermogenes <admin> :) +Cratylus <admin> because IR radiation DOES in fact play aa role here +Cratylus <admin> but it is not as substantial as the brownian motion +Hermogenes <admin> uh uhuhuhu uuhuh +Hermogenes <admin> sorry +Cratylus <admin> this must be aa way-homer +Hermogenes <admin> a 'way-homer'? +Cratylus <admin> you'll get it on the way home +Hermogenes <admin> heh +Hermogenes <admin> is it really that much fun to argue with me? +Hermogenes <admin> or is it really a chore +Cratylus <admin> im honestly mystified by this +Hermogenes <admin> as am i +Cratylus <admin> i mean, im like...FASCINATED +Hermogenes <admin> and i wasnt asking sarcsatically or rhetorically +Cratylus <admin> this is such aa weird miscommunication +Hermogenes <admin> if it was fun to argue at me +Cratylus <admin> i dint mean it sarcastically +<admin> Hermogenes nods solemnly. +Cratylus <admin> im totally dead serious +Cratylus <admin> dead sexy, too +Hermogenes <admin> didnt think you WERE being scarcastic +Hermogenes <admin> ugh +Cratylus <admin> heh +Hermogenes <admin> just watched that last night +Cratylus <admin> man he is VILE +Hermogenes <admin> 'e leuks leyek a lit'l BEHbee +Hermogenes <admin> oye ET a behbee wunce +Hermogenes <admin> oye sed, OYEM th TOP a th fewd chayn!" +Hermogenes <admin> GET! EN! MAH! BELLY! +Cratylus <admin> ok hang on aa sec dont say anything for aa minute, ok? +Cratylus <admin> ok thx +<admin> Hermogenes nods solemnly. +Hermogenes <admin> you ok there? +Cratylus <admin> ya i had to copy and paste this round +Hermogenes <admin> or... am i still not spossed to be sayin anything still? +Hermogenes <admin> heh +Cratylus <admin> this is just too crazy not to save for posterity +<admin> Hermogenes hopes he wont regret his conversation, but think he probably will +Cratylus <admin> heheh yes you definitely will +Cratylus <admin> well i HOPE you will +Hermogenes <admin> ill probably wind up being WRONG th whole time and lookin like an IDIOT fer it +Cratylus <admin> i hope yer gonna slap yer forehead and go HOLY FUCKING DUH! +Hermogenes <admin> see, th thing is... +Hermogenes <admin> its kinda hard to be wrong about something you dont know what yer talkin about in th FIRST place +Cratylus <admin> i guess +Cratylus <admin> ok +Cratylus <admin> i touch aa stove +Cratylus <admin> coalburning stove. black iron +Hermogenes <admin> like, some 5th grade makin assertions about calculus +Cratylus <admin> i put my hand right ON it +Hermogenes <admin> ya? +Cratylus <admin> my fickin hand is sizzlin n stuff, right +Cratylus <admin> this is happening not because of IR +<admin> Hermogenes nods solemnly. +Hermogenes <admin> but because of.... +Cratylus <admin> see, if it was infrered radiation doin this, then why isnt the whole room in flames? +Cratylus <admin> why is it limited to RIGHT AT the stive? +Hermogenes <admin> uh... +Hermogenes <admin> dissipation? +Cratylus <admin> explain dissipation please +Hermogenes <admin> theres so much ari movin roun n stuff, the averagew molecular kinetic energy (motion) can be...uh...averaged out +Hermogenes <admin> over a wider area +Hermogenes <admin> n stuff +Hermogenes <admin> like, the inverse-squared law or something +Hermogenes <admin> YEAH, THATS it +Cratylus <admin> ok...so u agree its not infrared energy? +Hermogenes <admin> burning yer hand? +Cratylus <admin> right +Hermogenes <admin> its... +Hermogenes <admin> the convection of hot air molecules againts yer skin +Cratylus <admin> well, hot STOVE molecules, and it isnt "convection" +Hermogenes <admin> oooOOOOo +Hermogenes <admin> why NOT, mister fancee panse? +Cratylus <admin> whats happening is the surface of the stove is transferring heat to my hand +Hermogenes <admin> right +Cratylus <admin> the mechanics of this heat transfer is simple molecular contact +Hermogenes <admin> ok, its either the conduction of heat between the solid of the stove into te solid of yer hand... +Cratylus <admin> the stove molecules are moving real fast +Hermogenes <admin> ok, now wait +Cratylus <admin> and they make my hand molecules move real fast +Hermogenes <admin> so, theres MORE than JUST 3 ways of transferring heat? +Cratylus <admin> no +Hermogenes <admin> like in th xflies! +Cratylus <admin> do u agree with me so far? +Hermogenes <admin> so, tehre are JUST 3 ways? +Cratylus <admin> do u agree with me so far? +Hermogenes <admin> mostly, yah +Cratylus <admin> ok, what part do u disagree with? +Hermogenes <admin> hol on a sec... +Cratylus <admin> and get aa fucking scientist in here NOW +Hermogenes <admin> no, i had to TEND to work stuff +Hermogenes <admin> ya big meanie +Cratylus <admin> well if u see on, grab him +Cratylus <admin> or her +Hermogenes <admin> i wasnt goin off to find a scientist dude to be on my sdide or nuttin +Cratylus <admin> ok so what part did u not agree with? +Hermogenes <admin> grab her? +Cratylus <admin> ok so what part did u not agree with? +Hermogenes <admin> ok, but only cause you insisted... +Hermogenes <admin> i guess i just wanna establish that theres X ways of heat transferrance, and any examples involving heat transferrence would be put into one or more of these X categories +Cratylus <admin> ok well fuck the 3 categories +Cratylus <admin> do you agree or disagree with my statements? +Hermogenes <admin> YEAH +Hermogenes <admin> POWER TO THE PEOPLE! +Cratylus <admin> dude +Hermogenes <admin> fine +Hermogenes <admin> stove molecules, movin hand molecules +Cratylus <admin> right +Hermogenes <admin> i tells you what my FOOT molecules gunan be movin in a SECOND! +Cratylus <admin> now, if instead of touching the stove, i had held my had within half aa centimeter, it would scald but not burn. right? +Hermogenes <admin> whats the diff? +Hermogenes <admin> its gonna get hot +Cratylus <admin> it would take longer for my hand to be damaged and it wouldnt be black +Hermogenes <admin> scald, burn, sear, fry, etc +Hermogenes <admin> ok, agreed +Cratylus <admin> ok the first example was conductance +Hermogenes <admin> as long as yer not actually TOUCHING it +Hermogenes <admin> ok, 1st = conductance +Cratylus <admin> the second example was radiation +Hermogenes <admin> (with a wee bit of convection) +Hermogenes <admin> hmmmm +Cratylus <admin> with aa little convection but thats not important i guess +Cratylus <admin> heh ya +Hermogenes <admin> second isnt convection? +Cratylus <admin> no +Hermogenes <admin> sounds likeit... +Cratylus <admin> its primarily radiation +Cratylus <admin> because the stove is heating the air molecules +Cratylus <admin> and the air molecules are heating my hand +Cratylus <admin> the heat is being radiated from the surface of the stove, through the air, into my hand +Hermogenes <admin> but... +Cratylus <admin> wait +Cratylus <admin> IR is bad for your eyes right? +Hermogenes <admin> uh... +Hermogenes <admin> is it? +Cratylus <admin> hmmm maybe that uv +Cratylus <admin> ok never mind +Hermogenes <admin> uv, yes, deinately +Cratylus <admin> ok now +Hermogenes <admin> wait +Hermogenes <admin> lemme say why i think its convection +Cratylus <admin> in ADDITION to this molecular heat transfer +Cratylus <admin> no +Cratylus <admin> im sorry +Cratylus <admin> thats irrelevant and aa tangent +<admin> Hermogenes frowns. +Hermogenes <admin> ok, go on +Cratylus <admin> in ADDITION to this molecular heat transfer +Hermogenes <admin> you n yer up-arrow keys... +Cratylus <admin> there is ALSO infrared radiation from the stove +Cratylus <admin> but it is NOT the infrared radiation that burns my hand +Cratylus <admin> it is the direct molecular contact with rapidly moving molecules +Hermogenes <admin> cause the IR stuff aint got enough energy to do it, and its the molecular transferrence stuff thats burning it? +Cratylus <admin> exactly +Cratylus <admin> do you agree? +Hermogenes <admin> im not too sure that IR is all THAT low-level energy-wise, but ok... +Cratylus <admin> so now lets put that stove in outer space +Hermogenes <admin> outher... SPAAAAAACE +Cratylus <admin> (with its own fuel and oxy) +Hermogenes <admin> (of course) +Cratylus <admin> and im out there with the stove +Cratylus <admin> and i put my hand .5 centimeters from it +Hermogenes <admin> (with suit and air supply) +Cratylus <admin> will my hand be damaged? +Hermogenes <admin> um... +Cratylus <admin> bare hand +Hermogenes <admin> uh... +Hermogenes <admin> maybe? +Cratylus <admin> no +Hermogenes <admin> no +Cratylus <admin> i think its possible the stove may shed molecules +Hermogenes <admin> cause the molecules cant transfer the heat as efficiently or quickly +Cratylus <admin> these molecules might hit some of my hand molecules, but not enough to do damage +Cratylus <admin> negatron +Hermogenes <admin> cause theres a near-vaccuum enviroment +Cratylus <admin> they CAN transfer it efficiently and quickly +Hermogenes <admin> oh +Cratylus <admin> if i TOUCH them +Hermogenes <admin> BAD molecules +Cratylus <admin> if i touch the stove, will my hand be damaged? +Hermogenes <admin> yes +Cratylus <admin> right +Hermogenes <admin> BAD stove! +Cratylus <admin> ok, so in aa vacuum, i have to touch the stove to get burned, right? +Hermogenes <admin> PROBably +Cratylus <admin> oK then +Cratylus <admin> that is precisely my point +Cratylus <admin> the stove does not produce sufficient IR radiation to make any noticeable diff to my hand +Hermogenes <admin> k... +Cratylus <admin> only when there is molecule to molecule contact, can the stove do real temp change +Cratylus <admin> therefore, while the stove radiates infrared waves +Cratylus <admin> it does not radiate heat +Hermogenes <admin> funkay +Cratylus <admin> yer supposed to hear trumpets and flights of angels as the truth rolls in from the sky +Hermogenes <admin> just cause i accept it, dont mean i understand it... +Hermogenes <admin> not to bee TOO bog of a pain in th ass +Hermogenes <admin> big, even +Cratylus <admin> you WILL young hermogenes. oh yes. you WILL. +Hellmonger@Trilogy <intergossip> anybody ever fuck with doing Sun consoles on an oldsk00l portmaster 2? +Hermogenes <admin> my BRAIN hurts +Cratylus <admin> sorry + + + diff --git a/lib/domains/town/txt/spam.txt b/lib/domains/town/txt/spam.txt new file mode 100644 index 0000000..e316a54 --- /dev/null +++ b/lib/domains/town/txt/spam.txt @@ -0,0 +1,22 @@ + +========================================== +| ,dP""8a "888888b, d8b "888b ,888" | +| 88b " 888 d88 dPY8b 88Y8b,8888 | +| `"Y8888a 888ad8P'dPaaY8b 88 Y88P888 | +| a, Y88 888 dP Y8b 88 YP 888 | +| `"8ad8P'a888a a88a;*a888aa88a a888a | +| ;*;;;;*;;;*;;;*,, | +| _,---'':::';*;;;*;;;*;;*d;, | +| .-' ::::::::::';*;;*;dII; | +| .' ,<<<,. :::::::::::::::ffffff`. | +| / ,<<<<<<<<,::::::::::::::::fffffI,\ | +| .,<<<<<<<<<<I;:::::::::::::::ffffKIP", | +| |<<<<<<<<<<dP;,?>;,::::::::::fffKKIP | | +| ``<<<<<<<dP;;;;;\>>>>>;,::::fffKKIPf ' | +| \ `mYMMV?;;;;;;;\>>>>>>>>>,YIIPP"` / | +| `. "":;;;;;;;;;i>>>>>>>>>>>>>, ,' | +| `-._``":;;;sP'`"?>>>>>=========. | +| `---..._______...|<[Hormel | | +| `=========' | + ========================================== + diff --git a/lib/domains/town/txt/vache.txt b/lib/domains/town/txt/vache.txt new file mode 100644 index 0000000..1dc286d --- /dev/null +++ b/lib/domains/town/txt/vache.txt @@ -0,0 +1,8 @@ + + (__) + (oo) + /-------\/ + / | || +* ||----|| + ~~ ~~ +Fetchez la vache! diff --git a/lib/domains/town/txt/warning_sign.txt b/lib/domains/town/txt/warning_sign.txt new file mode 100644 index 0000000..9b94a7f --- /dev/null +++ b/lib/domains/town/txt/warning_sign.txt @@ -0,0 +1,21 @@ +WARNING! + +North of here is Larstown, an area where some creatures +*may* be hostile. Be cautious, and make sure you read the +Player's Handbook. + +South is the Virtual Campus, an area with conference rooms +and a "University" feel to promote a learning environment. + +These areas are *not* a mud. They are sample objects, +rooms, and NPC's (aka mobs) that are intended to be used +in learning and teaching how to create a real mud of +your own, using the Dead Souls 2 mudlib. + +If you have logged into a mud and you are reading this, +do not assume "All DS muds are the same." Assume that for +whatever reason, this mud has not yet replaced the default +sample areas with areas of their own. + +-Cratylus +23 April 2007 diff --git a/lib/domains/town/txt/ylsrim_sign.txt b/lib/domains/town/txt/ylsrim_sign.txt new file mode 100644 index 0000000..07779a0 --- /dev/null +++ b/lib/domains/town/txt/ylsrim_sign.txt @@ -0,0 +1,20 @@ +WARNING! + +This area is Ylsrim. It is part of the old, +broken version of Dead Souls. It has been mostly unbroken, +so that for example the desert and bank roof work properly. + +However, you will note obvious differences in design +between Ylsrim and the main sample town. Remember, neither +Ylsrim nor the town are intended to *be* a mud. +They are only examples of places and things that you can +examine to guide you in building your own mud. + +Whatever bugs you find in Ylsrim, therefore, are not +going to be fixed. Consider it a museum piece, a mud +area like a prehistoric insect caught in amber: perfect +in its imperfection, sublime in its permanence. + +To return to the main sample area, use the stargate by typing: + +dial cave diff --git a/lib/domains/town/virtual/bottom.c b/lib/domains/town/virtual/bottom.c new file mode 100644 index 0000000..6505f03 --- /dev/null +++ b/lib/domains/town/virtual/bottom.c @@ -0,0 +1,81 @@ +#include <lib.h> +#include <dirs.h> +#include <terrain_types.h> +#include <medium.h> +#include <virtual.h> + +inherit LIB_VIRT_LAND; + +static private int XPosition, YPosition; +int max_north = 1000000; +int max_south = -1000000; +int max_east = 1000000; +int max_west = -1000000; +int max_up = 1000; +int max_down = 0; + +varargs void SetLongAndItems(int x, int y, int z); + +varargs int LimitTravel(int requested, int maximum, int lessthan){ + if(lessthan && requested < maximum) return maximum; + else if(lessthan && requested > maximum) return requested; + else if(requested > maximum) return maximum; + else return requested; +} + +varargs static void create(int x, int y) { + string n, s, e, w, u; + string ne, nw, se, sw; + + SetNoReplace(1); + virt_land::create(); + XPosition = x; + YPosition = y; + SetAmbientLight(0); + SetLongAndItems(x, y); + SetShort("The sea floor"); + if( x >= max_east ) e = "bottom/" + (max_west) + "," + y; + else e = "bottom/" + (x+1) + "," + y; + if( x <= max_west ) w = "bottom/" + (max_east) + "," + y; + else w = "bottom/" + (x-1) + "," + y; + if( y >= max_north ) n = "bottom/" + x + "," + (max_south); + else n = "bottom/" + x + "," + (y+1); + if( y <= max_south ) s = "bottom/" + x+ "," + (max_north); + else s = "bottom/" + x + "," + (y-1); + u = "sub/" + x + "," + y + ",10"; + + nw = "bottom/" + LimitTravel(x - 1, max_east, 1, max_west) + "," + LimitTravel(y+1, max_north); + ne = "bottom/" + LimitTravel(x + 1, max_east) + "," + LimitTravel(y+1, max_north); + sw = "bottom/" + LimitTravel(x - 1, max_east, 1, max_west) + "," + LimitTravel(y-1, max_north, 1, max_south); + se = "bottom/" + LimitTravel(x + 1, max_east) + "," + LimitTravel(y-1, max_north, 1, max_south); + + SetGoMessage("You can't travel in that direction."); + if( n ) AddExit("north", __DIR__ + n); + if( s ) AddExit("south", __DIR__ + s); + if( e ) AddExit("east", __DIR__ + e); + if( w ) AddExit("west", __DIR__ + w); + if( ne ) AddExit("northeast", __DIR__ + ne); + if( nw ) AddExit("northwest", __DIR__ + nw); + if( se ) AddExit("southeast", __DIR__ + se); + if( sw ) AddExit("southwest", __DIR__ + sw); + if( u ) AddExit("up", __DIR__ + u); +} + +varargs void SetLongAndItems(int x, int y, int z) { + mapping inv, items; + string str; + ::SetLongAndItems(x, y); + + inv = ([]); + str = "This is the bottom of a vast sea."; + + SetItems( ([ ({"sea","ocean"}) : "It is vast.", + ]) ); + SetLong(str); + SetInventory(inv); + SetTerrainType(T_SEAFLOOR); + SetMedium(MEDIUM_WATER); + SetInventory( ([ + "/domains/town/obj/seawater" : 1, + ]) ); +} diff --git a/lib/domains/town/virtual/bottom/5,0.c b/lib/domains/town/virtual/bottom/5,0.c new file mode 100644 index 0000000..6e0ade8 --- /dev/null +++ b/lib/domains/town/virtual/bottom/5,0.c @@ -0,0 +1,43 @@ +#include <lib.h> +#include <daemons.h> +#include <medium.h> +#include <terrain_types.h> + +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetAmbientLight(0); + SetNoClean(1); + SetTerrainType(T_SEAFLOOR); + SetMedium(MEDIUM_WATER); + + SetShort("the sea floor"); + SetLong("This is the bottom of a vast sea."); + SetExits(([ + "north" :"/domains/town/virtual/bottom/5,1", + "south" : "/domains/town/virtual/bottom/5,-1", + "east" : "/domains/town/virtual/bottom/6,0", + "northeast" : "/domains/town/virtual/bottom/6,1", + "southeast" : "/domains/town/virtual/bottom/6,-1", + "west" : "/domains/town/virtual/bottom/4,0", + "northwest" : "/domains/town/virtual/bottom/4,1", + "southwest" : "/domains/town/virtual/bottom/4,-1", + "up" : "/domains/town/virtual/sub/5,0,10" + ])); + + SetInventory(([ + "/domains/town/obj/stargate" : 1, + ])); + SetCoordinates("5,0,-11"); +} + +int CanReceive(object ob) { + if(!ob) return 0; + return room::CanReceive(ob); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/virtual/forest.c b/lib/domains/town/virtual/forest.c new file mode 100644 index 0000000..a8f5c79 --- /dev/null +++ b/lib/domains/town/virtual/forest.c @@ -0,0 +1,212 @@ +#include <lib.h> +#include <dirs.h> +#include <virtual.h> + +inherit LIB_VIRT_LAND; + +static private int XPosition, YPosition, found; +static string lupus; +int max_north = 25; +int max_south = 1; +int max_east = -3; +int max_west = -28; + + +varargs void SetLongAndItems(int x, int y, int z); + +varargs int LimitTravel(int requested, int maximum, int lessthan){ + if(lessthan && requested < maximum) return maximum; + else if(lessthan && requested > maximum) return requested; + else if(requested > maximum) return maximum; + else return requested; +} + +mixed SearchFun(object who, string str){ + object ob; + if( found || !(ob = new("/domains/Ylsrim/etc/pole"))) + return "You find nothing of interest."; + found = 1; + eventPrint(who->GetName() + " finds a fishing pole " "among the abandoned campsite.", who); + if( !(ob->eventMove(this_player())) ) { + ob->eventMove(this_object()); + } + return "You find a fishing pole!"; +} + +varargs static void create(int x, int y) { + string n, s, e, w; + string ne, nw, se, sw; + string fly; + + SetNoReplace(1); + virt_land::create(); + /* Without the virtual exemption, virts with npc's + * wind up being perpetual motion NPC factories. + */ + SetExemptVirtual(1); + XPosition = x; + YPosition = y; + SetClimate("temperate"); + SetAmbientLight(30); + SetLongAndItems(x, y); + SetShort("a thick forest"); + if( x == max_east ) e = "forest/" + (x) + "," + y; + else e = "forest/" + (x+1) + "," + y; + if( x == max_west ) w = "forest/" + (x) + "," + y; + else w = "forest/" + (x-1) + "," + y; + if( y == max_north ) n = "forest/" + x + "," + (y); + else n = "forest/" + x + "," + (y+1); + if( y == max_south ) s = "forest/" + x+ "," + (y); + else s = "forest/" + x + "," + (y-1); + fly = "sky/" + x + "," + y + "," + 1; + + nw = "forest/" + LimitTravel(x - 1, max_west, 1) + "," + LimitTravel(y+1, max_north); + ne = "forest/" + LimitTravel(x + 1, max_east) + "," + LimitTravel(y+1, max_north); + sw = "forest/" + LimitTravel(x - 1, max_west, 1) + "," + LimitTravel(y-1, max_south, 1); + se = "forest/" + LimitTravel(x + 1, max_east) + "," + LimitTravel(y-1, max_south, 1); + + SetFlyRoom(__DIR__+fly); + + SetGoMessage("You can't travel in that direction."); + if( n ) AddExit("north", __DIR__ + n); + if( s ) AddExit("south", __DIR__ + s); + if( e ) AddExit("east", __DIR__ + e); + if( w ) AddExit("west", __DIR__ + w); + if( ne ) AddExit("northeast", __DIR__ + ne); + if( nw ) AddExit("northwest", __DIR__ + nw); + if( se ) AddExit("southeast", __DIR__ + se); + if( sw ) AddExit("southwest", __DIR__ + sw); + + if(x == -4 && y == 1){ + RemoveExit("south"); + RemoveExit("west"); + AddExit("south","/domains/town/room/forest_path1"); + RemoveExit("southeast"); + RemoveExit("southwest"); + + } + else if(y == max_south){ + RemoveExit("south"); + RemoveExit("southeast"); + RemoveExit("southwest"); + } + if(y == max_north){ + RemoveExit("north"); + RemoveExit("northeast"); + RemoveExit("northwest"); + } + if(x == max_west){ + RemoveExit("west"); + RemoveExit("northwest"); + RemoveExit("southwest"); + } + if(x == max_east){ + RemoveExit("east"); + RemoveExit("northeast"); + RemoveExit("southeast"); + } +} + +varargs void SetLongAndItems(int x, int y, int z) { + mapping inv, items; + string str; + ::SetLongAndItems(x, y, z); + + inv = ([]); + str = "You are in a vast forest. The trees and " + "thick vegetation press in from all sides, appearing almost " + "threatening. " + "No path marks your way. "; + if(query_night()) str += "The stars of the night sky " + "are barely visible through the heavy forest canopy overhead."; + else str+= "Sunlight penetrates the tree cover with great " + "difficulty, rendering the forest cool and dark."; + if(x == max_east) str+= " Travel east is made impossible by a river " + "rushing north to south here. On the other side of the river " + "a great slope rises, and it appears that on top of it is " + "a road that leads north to a high plateau."; + if(y == max_north) str+= " A steep cliff rises north of here, making " + "travel north into the mountains impossible."; + if(x == max_west) str += " The forest is impassably thick to the west."; + if(y == max_south) str += " The forest is impassably thick southward."; + if(x == -4 && y == 1) str += "\n%^GREEN%^There is a sign here you can read.%^RESET%^"; + if(x == -4 && y == 25) str += "\n%^GREEN%^There is a cave entrance in the cliff wall.%^RESET%^"; + if(x == -3 && y == 25) str += "\n%^GREEN%^There is a cave entrance in the cliff wall.%^RESET%^"; + SetItems( ([ "forest" : "It is so vast.", + ({"woods","trees","vegetation","plants"}) : "Thick, foreboding and " + "oppressive, these seem to add to an air of danger and claustrophobia.", + "no path" : "You observe the presence of its absence.", + ({"mountain","mountains"}): "The snow capped peaks of the great " + "northern range are faintly visible from here.", + "cliff" : "To the north, a high cliff rises from the forest.", + ({"canopy","forest canopy","heavy forest canopy"}) : "The great " + "branches and heavy leaves of the trees here form the forest " + "canopy, almost a ceiling through which little light can pass.", + ]) ); + if(y == max_north) { + AddItem( ({ "river", "stream", "great river"}), + "This narrow but powerful river presents an insurmountable " + "obstacle to further travel east." ); + AddItem( ({ "slope","road","plateau"}), "Looks like that's " + "Fort Road, high on a slope and running north to the Fortress " + "on the Frontiers."); + } + if(x == -4 && y == 25) { + AddItem(({"cave","opening","entrance","cave entrance"}) , + "This is a rather scary looking opening in the cliff wall, leading " + "north into the ground."); + AddEnter("cave","/domains/town/room/cave_entrance"); + RemoveExit("north"); + RemoveExit("northeast"); + RemoveExit("northwest"); + } + + if(x == -3 && y == 25) { + AddItem(({"cave","opening","entrance","cave entrance"}) , + "This is a dark opening in the cliff wall, leading " + "north into the ground."); + AddEnter("cave","/domains/amigara/room/cave"); + RemoveExit("north"); + RemoveExit("northeast"); + RemoveExit("northwest"); + } + + if(x == -4 && y == 1) { + if(random(99) > 95) lupus = "Bad Wolf!"; + else lupus = "Straight on! Beware th"; + AddItem("sign" , "This is a hastily-lettered sign planted on the ground."); + SetRead( ({"sign"}) , lupus); + } + if( !random(50) ){ + str += " Burnt wood, scattered rocks and twigs, and other signs " + "of an abandoned camp site are scattered about."; + AddItem( ({ "twigs", "sticks", "kindling", "wood", "burnt wood" }) , + "Though long since burnt to nothing, scattered kindling " + "and burnt wood lie about as a memory of travellers who have " + "passed through"); + if( random(2) ){ + SetSearch( (: SearchFun :) ); + } + } + else if( !random(10) ) + SetSmell("default", "You smell a distant camp fire."); + if( !random(55) ) + inv["/domains/town/npc/forest_orc"] = random(2)+1; + if( !random(45) ) + inv["/domains/town/npc/bear"] = 1; + if( !random(15) ) + inv["/domains/town/npc/deer"] = 1; + if( !random(65) ) + inv["/domains/town/npc/gecko"] = 1; + if( !random(35) ) + inv["/domains/town/npc/newt"] = 1; + if( !random(75) ) + inv["/domains/town/npc/spider"] = 1; + + else if( !random(14) ) + SetListen("default", "You hear voices in the distance."); + SetLong(str); + SetDayLight(25); + SetNightLight(0); + SetInventory(inv); +} diff --git a/lib/domains/town/virtual/forest/-13,13.c b/lib/domains/town/virtual/forest/-13,13.c new file mode 100644 index 0000000..8ea0404 --- /dev/null +++ b/lib/domains/town/virtual/forest/-13,13.c @@ -0,0 +1,86 @@ +#include <medium.h> +#include <daemons.h> +#include <terrain_types.h> +#include <lib.h> +#include <climb.h> +#include ROOMS_H + +inherit LIB_ROOM; +inherit LIB_CLIMB; + +int OutClimb(){ + eventClimb(this_player(),CLIMB_OUT,"/domains/town/virtual/forest/-13,12"); +} + +int ActionFunction(){ + object *bodies = get_livings(this_object()); + foreach(object body in bodies){ + int maxheal, maxstam, maxmag; + int health, stamina, magic, poison; + if((RACES_D->GetNonMeatRace(body->GetRace()))) continue; + maxheal = (body->GetMaxHealthPoints()) / 2; + maxstam = (body->GetMaxStaminaPoints()) / 2; + maxmag = (body->GetMaxMagicPoints()) / 2; + health = (body->GetHealthPoints()); + stamina = (body->GetStaminaPoints()); + magic = (body->GetMagicPoints()); + + if(health < maxheal){ + body->AddHP(random(5)); + } + if(stamina < maxstam){ + body->AddStaminaPoints(random(5)); + } + if(magic < maxmag){ + body->AddMagicPoints(random(5)); + } + if(poison > 0 ){ + body->AddPoison(-(random(5))); + } + } + return 1; +} + +void create() { + room::create(); + SetAmbientLight(30); + SetDayLight(30); + SetNightLight(30); + SetShort("a glowing pool"); + SetLong("This is a strange, glowing pool in the middle of the forest."); + SetClimate("temperate"); + SetTown("wilderness"); + SetTerrainType(T_SURFACE); + SetMedium(MEDIUM_SURFACE); + SetNoSink(1); + SetItems( ([ + ({ "forest" }) : "It surrounds the pool.", + ]) ); + SetExits( ([ + "south" : "/domains/town/virtual/forest/-13,12", + "north" : "/domains/town/virtual/forest/-13,14", + "east" : "/domains/town/virtual/forest/-12,13", + "southeast" : "/domains/town/virtual/forest/-12,12", + "northeast" : "/domains/town/virtual/forest/-12,14", + "out" : "/domains/town/virtual/forest/-14,12", + "west" : "/domains/town/virtual/forest/-14,13", + "southwest" : "/domains/town/virtual/forest/-14,12", + "northwest" : "/domains/town/virtual/forest/-14,14", + "down" : "/domains/town/room/forest_well1.c", + ]) ); + SetInventory(([ + "/domains/town/obj/hpoolwater" : 1, + "/domains/town/npc/nymph" : 1, + ])); + SetFlyRoom("/domains/town/virtual/sky/-13,13,1"); + SetClimb( (: OutClimb :) , CLIMB_OUT); + set_heart_beat(5); + SetObviousExits("climb out"); +} +void init(){ + ::init(); +} + +void heart_beat(){ + ActionFunction(); +} diff --git a/lib/domains/town/virtual/forest_map b/lib/domains/town/virtual/forest_map new file mode 100644 index 0000000..eb82e11 --- /dev/null +++ b/lib/domains/town/virtual/forest_map @@ -0,0 +1,30 @@ +#include <lib.h> +#include <dirs.h> +#include <virtual.h> + +inherit LIB_VIRT_MAP; + +varargs string array BaseMap(){ //override with actual map + return + ({ + // 0 + // 01234 + ({"00000",//0 + "01000",//1 + "00000",//2 + "00000",//3 + "00000",//4 + }) + }); + +} + + +varargs static void create() { + ::create(); + //SetNoClean(1); + //SetVirtFile(base_name(this_object())); + //AddLocation("foo", ({2,2,0}) ); +} + + diff --git a/lib/domains/town/virtual/server.c b/lib/domains/town/virtual/server.c new file mode 100644 index 0000000..c1282b6 --- /dev/null +++ b/lib/domains/town/virtual/server.c @@ -0,0 +1,20 @@ +mixed compile_object(string file) { + string *path; + object ob; + int x, y, z, elements; + if(grepp(file, "/user_") || grepp(file, "/object_")){ + ob = new("/domains/default/virtual/void"); + if(!ob){ + return "No void room available."; + } + return ob; + } + path = explode(file, "/"); + if( file_size(__DIR__ + path[3] + ".c") < 1 ) return "bad file"; + if( (elements = sscanf(path[4], "%d,%d,%d", x, y, z)) != 3 ) { + if( (elements = sscanf(path[4], "%d,%d", x, y)) != 2 ) return "missing comma"; + } + if( elements == 2 && !(ob = new(__DIR__ + path[3], x, y)) ) return "failed to compile"; + else if( elements == 3 && !(ob = new(__DIR__ + path[3], x, y, z)) ) return "failed to compile"; + return ob; +} diff --git a/lib/domains/town/virtual/sky.c b/lib/domains/town/virtual/sky.c new file mode 100644 index 0000000..865bc2e --- /dev/null +++ b/lib/domains/town/virtual/sky.c @@ -0,0 +1,142 @@ +#include <lib.h> +#include <daemons.h> +#include <dirs.h> +#include <terrain_types.h> +#include <medium.h> +#include <virtual.h> + +inherit LIB_VIRT_SKY; + +static private int XPosition, YPosition, ZPosition; +int overland; +string dexit; +int max_north = 1000000; +int max_south = -1000000; +int max_east = 1000000; +int max_west = -1000000; +int max_up = 1000; +int max_down = 0; + + +varargs void SetLongAndItems(int x, int y, int z); + +varargs int LimitTravel(int requested, int maximum, int lessthan, int minimum){ + if(lessthan && requested < minimum) return maximum; + else if(lessthan && requested > maximum) return requested; + else if(requested > maximum) return minimum; + else return requested; +} + +varargs static void create(int x, int y, int z) { + string n, s, e, w, u, d; + string ne, nw, se, sw; + + SetNoReplace(1); + virt_sky::create(); + XPosition = x; + YPosition = y; + ZPosition = z; + SetClimate("temperate"); + SetLongAndItems(x, y, z); + SetShort("The sky"); + if( x >= max_east ) e = "sky/" + (max_west) + "," + y + "," + z; + else e = "sky/" + (x+1) + "," + y + "," + z; + if( x <= max_west ) w = "sky/" + (max_east) + "," + y + "," + z; + else w = "sky/" + (x-1) + "," + y + "," + z; + if( y >= max_north ) n = "sky/" + x + "," + (max_south) + "," + z; + else n = "sky/" + x + "," + (y+1) + "," + z; + if( y <= max_south ) s = "sky/" + x+ "," + (max_north) + "," + z; + else s = "sky/" + x + "," + (y-1) + "," + z; + if( z == max_up ) u = "sky/" + x + "," + y + "," + (z); + else u = "sky/" + x + "," + y + "," + (z+1); + if( z == max_down ) d = "sky/" + x+ "," + (y) + "," + z; + else d = "sky/" + x + "," + y + "," + (z-1); + + nw = "sky/" + LimitTravel(x - 1, max_east, 1, max_west) + "," + LimitTravel(y+1, max_north)+ "," + z; + ne = "sky/" + LimitTravel(x + 1, max_east) + "," + LimitTravel(y+1, max_north)+ "," + z; + sw = "sky/" + LimitTravel(x - 1, max_east, 1, max_west) + "," + LimitTravel(y-1, max_north, 1, max_south)+ "," + z; + se = "sky/" + LimitTravel(x + 1, max_east) + "," + LimitTravel(y-1, max_north, 1, max_south)+ "," + z; + + SetGoMessage("You can't travel in that direction."); + + if( n ) AddExit("north", __DIR__ + n); + if( s ) AddExit("south", __DIR__ + s); + if( e ) AddExit("east", __DIR__ + e); + if( w ) AddExit("west", __DIR__ + w); + if( u ) AddExit("up", __DIR__ + u); + if( d ) AddExit("down", __DIR__ + d); + if( ne ) AddExit("northeast", __DIR__ + ne); + if( nw ) AddExit("northwest", __DIR__ + nw); + if( se ) AddExit("southeast", __DIR__ + se); + if( sw ) AddExit("southwest", __DIR__ + sw); + + if( (x < 26 && x > 0) && (y < 26 && y > 0) ){ + overland = 1; + } + if(z == 1000){ + RemoveExit("up"); + AddExit("up","/domains/town/virtual/space/1,1,1"); + return; + } + if(z == 1){ + string wut; + mapping gloc = ROOMS_D->GetGrid(x+","+y+",0"); + + if(sizeof(gloc)){ + dexit = gloc["room"]; + SetSinkRoom(gloc["room"]); + } + + if(dexit){ + RemoveExit("down"); + AddExit("down", dexit); + } + + else { + if( (x < 10 && x > -26) && (y < 26 && y > -10) ){ + wut = "forest"; + } + else { + wut = "surface"; + } + RemoveExit("down"); + AddExit("down", __DIR__ + wut+"/" + x + "," + y); + } + } +} + +varargs void SetLongAndItems(int x, int y, int z) { + mapping inv, items; + string str; + ::SetLongAndItems(x, y, z); + + inv = ([]); + if(overland || dexit) str = "You are in the air above a small island in a vast sea that stretches from horizon to horizon."; + else str = "You are in the air above a vast sea that stretches from horizon to horizon."; + if(query_night()) str += " The stars of the night sky glitter overhead."; + + SetItems( ([ ({ "sea", "ocean" }) : "A seemingly endless body of water.", + ]) ); + + SetLong(str); + SetDayLight(30); + SetNightLight(30); + SetTerrainType(T_MIDAIR); + SetMedium(MEDIUM_AIR); +} + +//int eventReceiveObject(object ob){ +// if(this_object() && ob && (living(ob) || ob->GetMapper())){ +// tc("1"); +// if(MASTER_D->GetPerfOK()){ +// int array Coords = ROOMS_D->SetRoom(this_object(), ob); +// tc("2: "+identify(Coords)); +// CompileNeighbors(Coords); +// } +// } +// return ::eventReceiveObject(ob); +//} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/virtual/space.c b/lib/domains/town/virtual/space.c new file mode 100644 index 0000000..bccd98a --- /dev/null +++ b/lib/domains/town/virtual/space.c @@ -0,0 +1,129 @@ +#include <lib.h> +#include <dirs.h> +#include <terrain_types.h> +#include <medium.h> +#include <virtual.h> + +inherit LIB_VIRT_SKY; + +static private int XPosition, YPosition, ZPosition; +int max_north = 2100000000; +int max_south = -2100000000; +int max_east = 2100000000; +int max_west = -2100000000; +int max_up = 2100000000; +int max_down = -2100000000; + +varargs void SetLongAndItems(int x, int y, int z); + +varargs int LimitTravel(int requested, int maximum, int lessthan, int minimum){ + if(lessthan && requested < minimum) return maximum; + else if(lessthan && requested > maximum) return requested; + else if(requested > maximum) return minimum; + else return requested; +} + +varargs static void create(int x, int y, int z) { + string n, s, e, w, u, d; + string ne, nw, se, sw; + string neu, nwu, seu, swu; + string ned, nwd, sed, swd; + string nu, nd, su, sd; + string eu, ed, wu, wd; + + SetNoReplace(1); + virt_sky::create(); + XPosition = x; + YPosition = y; + ZPosition = z; + SetLongAndItems(x, y, z); + SetShort("Outer Space"); + if( x >= max_east ) e = "space/" + (max_west) + "," + y + "," + z; + else e = "space/" + (x+1) + "," + y + "," + z; + if( x <= max_west ) w = "space/" + (max_east) + "," + y + "," + z; + else w = "space/" + (x-1) + "," + y + "," + z; + if( y >= max_north ) n = "space/" + x + "," + (max_south) + "," + z; + else n = "space/" + x + "," + (y+1) + "," + z; + if( y <= max_south ) s = "space/" + x+ "," + (max_north) + "," + z; + else s = "space/" + x + "," + (y-1) + "," + z; + if( z == max_up ) u = "space/" + x + "," + y + "," + (max_down); + else u = "space/" + x + "," + y + "," + (z+1); + if( z == max_down ) d = "space/" + x+ "," + (y) + "," + (max_up); + else d = "space/" + x + "," + y + "," + (z-1); + + nw = "space/" + LimitTravel(x - 1, max_east, 1, max_west) + "," + LimitTravel(y+1, max_north)+ "," + z; + ne = "space/" + LimitTravel(x + 1, max_east) + "," + LimitTravel(y+1, max_north)+ "," + z; + sw = "space/" + LimitTravel(x - 1, max_east, 1, max_west) + "," + LimitTravel(y-1, max_north, 1, max_south)+ "," + z; + se = "space/" + LimitTravel(x + 1, max_east) + "," + LimitTravel(y-1, max_north, 1, max_south)+ "," + z; + + nu = "space/" + x + "," + LimitTravel(y+1, max_north)+ "," + LimitTravel(z+1, max_up); + nd = "space/" + x + "," + LimitTravel(y+1, max_north)+ "," + LimitTravel(z-1, max_up, 1, max_down); + su = "space/" + x + "," + LimitTravel(y-1, max_north, 1, max_south)+ "," + LimitTravel(z+1, max_up); + sd = "space/" + x + "," + LimitTravel(y-1, max_north, 1, max_south)+ "," + LimitTravel(z-1, max_up, 1, max_down); + + + eu = "space/" + LimitTravel(x+1, max_north)+ ","+y+ "," + LimitTravel(z+1, max_up); + ed = "space/" + LimitTravel(x+1, max_north)+ ","+y+ "," + LimitTravel(z-1, max_up, 1, max_down); + wu = "space/" + LimitTravel(x-1, max_north, 1, max_south)+ ","+y+ "," + LimitTravel(z+1, max_up); + wd = "space/" + LimitTravel(x-1, max_north, 1, max_south)+ ","+y+ "," + LimitTravel(z-1, max_up, 1, max_down); + + nwu = "space/" + LimitTravel(x - 1, max_east, 1, max_west) + "," + LimitTravel(y+1, max_north)+ "," + LimitTravel(z + 1, max_up); + neu = "space/" + LimitTravel(x + 1, max_east) + "," + LimitTravel(y+1, max_north)+ "," + LimitTravel(z + 1, max_up); + swu = "space/" + LimitTravel(x - 1, max_east, 1, max_west) + "," + LimitTravel(y-1, max_north, 1, max_south)+ "," + LimitTravel(z + 1, max_up); + seu = "space/" + LimitTravel(x + 1, max_east) + "," + LimitTravel(y-1, max_north, 1, max_south)+ "," + LimitTravel(z + 1, max_up); + + nwd = "space/" + LimitTravel(x - 1, max_east, 1, max_west) + "," + LimitTravel(y+1, max_north)+ "," + LimitTravel(z -1, max_up, 1, max_down); + ned = "space/" + LimitTravel(x + 1, max_east) + "," + LimitTravel(y+1, max_north)+ "," + LimitTravel(z -1, max_up, 1, max_down); + swd = "space/" + LimitTravel(x - 1, max_east, 1, max_west) + "," + LimitTravel(y-1, max_north, 1, max_south)+ "," + LimitTravel(z -1, max_up, 1, max_down); + sed = "space/" + LimitTravel(x + 1, max_east) + "," + LimitTravel(y-1, max_north, 1, max_south)+ "," + LimitTravel(z -1, max_up, 1, max_down); + + + SetGoMessage("You can't travel in that direction."); + + if( n ) AddExit("+x", __DIR__ + n); + if( s ) AddExit("-x", __DIR__ + s); + if( e ) AddExit("+y", __DIR__ + e); + if( w ) AddExit("-y", __DIR__ + w); + if( u ) AddExit("+z", __DIR__ + u); + if( d ) AddExit("-z", __DIR__ + d); + if( ne ) AddExit("+x+y", __DIR__ + ne); + if( nw ) AddExit("+x-y", __DIR__ + nw); + if( se ) AddExit("-x+y", __DIR__ + se); + if( sw ) AddExit("-x-y", __DIR__ + sw); + + if( nu ) AddExit("+x+z", __DIR__ + nu); + if( nd ) AddExit("+x-z", __DIR__ + nd); + if( su ) AddExit("-x+z", __DIR__ + su); + if( sd ) AddExit("-x-z", __DIR__ + sd); + if( eu ) AddExit("+y+z", __DIR__ + eu); + if( ed ) AddExit("+y-z", __DIR__ + ed); + if( wu ) AddExit("-y+z", __DIR__ + wu); + if( wd ) AddExit("-y-z", __DIR__ + wd); + + if( neu ) AddExit("+x+y+z", __DIR__ + neu); + if( nwu ) AddExit("+x-y+z", __DIR__ + nwu); + if( seu ) AddExit("-x+y+z", __DIR__ + seu); + if( swu ) AddExit("-x-y+z", __DIR__ + swu); + if( ned ) AddExit("+x+y-z", __DIR__ + ned); + if( nwd ) AddExit("+x-y-z", __DIR__ + nwd); + if( sed ) AddExit("-x+y-z", __DIR__ + sed); + if( swd ) AddExit("-x-y-z", __DIR__ + swd); +} + +varargs void SetLongAndItems(int x, int y, int z) { + mapping inv, items; + string str; + ::SetLongAndItems(x, y, z); + + inv = ([]); + str = "Outer space. A big, place."; + + SetItems( ([ ({ "star","stars" }) : "Oddly steady in their shine, they stand silent witness.", + ]) ); + + SetLong(str); + SetDayLight(30); + SetNightLight(30); + SetTerrainType(T_SPACE); + SetMedium(MEDIUM_SPACE); +} diff --git a/lib/domains/town/virtual/space/1,1,1.c b/lib/domains/town/virtual/space/1,1,1.c new file mode 100644 index 0000000..121d349 --- /dev/null +++ b/lib/domains/town/virtual/space/1,1,1.c @@ -0,0 +1,63 @@ +#include <lib.h> +#include <daemons.h> +#include <medium.h> +#include <terrain_types.h> + +inherit LIB_ROOM; + +mixed CanGo(object who, string dir) { + return CanFly(who, dir); +} + +static void create() { + object ob; + room::create(); + SetAmbientLight(30); + SetNoClean(1); + SetTerrainType(T_SPACE); + SetMedium(MEDIUM_SPACE); + + SetShort("Outer Space"); + SetLong("Outer space. A big, place. There is a medium sized planet below."); + SetExits(([ + "+x" : "/domains/town/virtual/space/1,2,1", + "-x-y-z" : "/domains/town/virtual/space/2100000000,2100000000,0", + "-z" : "/domains/town/virtual/space/1,1,0", + "-x-y" : "/domains/town/virtual/space/2100000000,2100000000,1", + "+x+y-z" : "/domains/town/virtual/space/2,2,0", + "-y" : "/domains/town/virtual/space/2100000000,1,1", + "+x-y+z" : "/domains/town/virtual/space/2100000000,2,2", + "-x+y+z" : "/domains/town/virtual/space/2,2100000000,2", + "-x" : "/domains/town/virtual/space/1,2100000000,1", + "+x+y" : "/domains/town/virtual/space/2,2,1", + "-x-y+z" : "/domains/town/virtual/space/2100000000,2100000000,2", + "+x-y-z" : "/domains/town/virtual/space/2100000000,2,0", + "-x+y-z" : "/domains/town/virtual/space/2,2100000000,0", + "+z" : "/domains/town/virtual/space/1,1,2", + "+x-y" : "/domains/town/virtual/space/2100000000,2,1", + "-x+y" : "/domains/town/virtual/space/2,2100000000,1", + "+y" : "/domains/town/virtual/space/2,1,1", + "+x+y+z" : "/domains/town/virtual/space/2,2,2", + "down": "/domains/town/virtual/sky/1,1,1000", + "-y+z" : "/domains/town/virtual/space/2100000000,1,2", + "+x-z" : "/domains/town/virtual/space/1,2,0", + "-x-z" : "/domains/town/virtual/space/1,2100000000,0", + "+y-z" : "/domains/town/virtual/space/2,1,0", + "+x+z" : "/domains/town/virtual/space/1,2,2", + "-y-z" : "/domains/town/virtual/space/2100000000,1,0", + "-x+z" : "/domains/town/virtual/space/1,2100000000,2", + "+y+z" : "/domains/town/virtual/space/2,1,2", + ]) ); + + SetInventory(([ + "/domains/town/obj/stargate2" : 1, + ])); +} +int CanReceive(object ob) { + if(!ob) return 0; + return room::CanReceive(ob); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/virtual/sub.c b/lib/domains/town/virtual/sub.c new file mode 100644 index 0000000..3e0389e --- /dev/null +++ b/lib/domains/town/virtual/sub.c @@ -0,0 +1,99 @@ +#include <lib.h> +#include <dirs.h> +#include <terrain_types.h> +#include <medium.h> +#include <virtual.h> + +inherit LIB_VIRT_SUBSURFACE; + +static private int XPosition, YPosition, ZPosition; +int max_north = 1000000; +int max_south = -1000000; +int max_east = 1000000; +int max_west = -1000000; +int max_up = 1000; +int max_down = 0; + +varargs void SetLongAndItems(int x, int y, int z); + +varargs int LimitTravel(int requested, int maximum, int lessthan, int minimum){ + if(lessthan && requested < minimum) return maximum; + else if(lessthan && requested > maximum) return requested; + else if(requested > maximum) return minimum; + else return requested; +} + +varargs static void create(int x, int y, int z) { + string n, s, e, w, u, d; + string ne, nw, se, sw; + + SetNoReplace(1); + virt_subsurface::create(); + XPosition = x; + YPosition = y; + ZPosition = z; + SetClimate("temperate"); + SetDayLight(( (30 - z < 0) ? 0 : 30 - z)); + SetNightLight(( (10 - z < 0) ? 0 : 10 - z)); + SetLongAndItems(x, y, z); + SetShort("Underwater"); + if( x >= max_east ) e = "sun/" + (max_west) + "," + y + "," + z; + else e = "sub/" + (x+1) + "," + y + "," + z; + if( x <= max_west ) w = "sub/" + (max_east) + "," + y + "," + z; + else w = "sub/" + (x-1) + "," + y + "," + z; + if( y >= max_north ) n = "sub/" + x + "," + (max_south) + "," + z; + else n = "sub/" + x + "," + (y+1) + "," + z; + if( y <= max_south ) s = "sub/" + x+ "," + (max_north) + "," + z; + else s = "sub/" + x + "," + (y-1) + "," + z; + if( z == max_up ) u = "sub/" + x + "," + y + "," + (z); + else u = "sub/" + x + "," + y + "," + (z-1); + if( z == max_down ) d = "sub/" + x+ "," + (y) + "," + z; + else d = "sub/" + x + "," + y + "," + (z+1); + + nw = "sub/" + LimitTravel(x - 1, max_east, 1, max_west) + "," + LimitTravel(y+1, max_north)+ "," + z; + ne = "sub/" + LimitTravel(x + 1, max_east) + "," + LimitTravel(y+1, max_north)+ "," + z; + sw = "sub/" + LimitTravel(x - 1, max_east, 1, max_west) + "," + LimitTravel(y-1, max_north, 1, max_south)+ "," + z; + se = "sub/" + LimitTravel(x + 1, max_east) + "," + LimitTravel(y-1, max_north, 1, max_south)+ "," + z; + + SetGoMessage("You can't travel in that direction."); + + if( n ) AddExit("north", __DIR__ + n); + if( s ) AddExit("south", __DIR__ + s); + if( e ) AddExit("east", __DIR__ + e); + if( w ) AddExit("west", __DIR__ + w); + if( u ) AddExit("up", __DIR__ + u); + if( d ) AddExit("down", __DIR__ + d); + if( ne ) AddExit("northeast", __DIR__ + ne); + if( nw ) AddExit("northwest", __DIR__ + nw); + if( se ) AddExit("southeast", __DIR__ + se); + if( sw ) AddExit("southwest", __DIR__ + sw); + + if(z == 1){ + RemoveExit("up"); + AddExit("up", __DIR__ + "surface/" + x + "," + y); + } + + if(z == 10){ + RemoveExit("down"); + AddExit("down", __DIR__ + "bottom/" + x + "," + y); + } +} + +varargs void SetLongAndItems(int x, int y, int z) { + mapping inv, items; + string str; + ::SetLongAndItems(x, y, z); + + inv = ([]); + str = "This is the dark space below the surface of a great sea."; + + SetItems( ([ ({ "sea", "ocean" }) : "A seemingly endless body of water.", + ]) ); + + SetLong(str); + SetTerrainType(T_UNDERWATER); + SetMedium(MEDIUM_WATER); + SetInventory( ([ + "/domains/town/obj/seawater" : 1, + ]) ); +} diff --git a/lib/domains/town/virtual/surface.c b/lib/domains/town/virtual/surface.c new file mode 100644 index 0000000..03bf1f6 --- /dev/null +++ b/lib/domains/town/virtual/surface.c @@ -0,0 +1,98 @@ +#include <lib.h> +#include <dirs.h> +#include <terrain_types.h> +#include <medium.h> +#include <virtual.h> + +inherit LIB_VIRT_LAND; + +static private int XPosition, YPosition; +int max_north = 1000000; +int max_south = -1000000; +int max_east = 1000000; +int max_west = -1000000; +int max_up = 1000; +int max_down = 0; + +varargs void SetLongAndItems(int x, int y, int z); + +varargs int LimitTravel(int requested, int maximum, int lessthan){ + if(lessthan && requested < maximum) return maximum; + else if(lessthan && requested > maximum) return requested; + else if(requested > maximum) return maximum; + else return requested; +} + +varargs static void create(int x, int y) { + string n, s, e, w; + string ne, nw, se, sw; + string sink, fly; + + SetNoReplace(1); + virt_land::create(); + XPosition = x; + YPosition = y; + SetClimate("temperate"); + SetLongAndItems(x, y); + SetShort("a great sea"); + if( x >= max_east ) e = "surface/" + (max_west) + "," + y; + else e = "surface/" + (x+1) + "," + y; + if( x <= max_west ) w = "surface/" + (max_east) + "," + y; + else w = "surface/" + (x-1) + "," + y; + if( y >= max_north ) n = "surface/" + x + "," + (max_south); + else n = "surface/" + x + "," + (y+1); + if( y <= max_south ) s = "surface/" + x+ "," + (max_north); + else s = "surface/" + x + "," + (y-1); + sink = "sub/" + x + "," + y + "," + 1; + fly = "sky/" + x + "," + y + "," + 1; + + nw = "surface/" + LimitTravel(x - 1, max_east, 1, max_west) + "," + LimitTravel(y+1, max_north); + ne = "surface/" + LimitTravel(x + 1, max_east) + "," + LimitTravel(y+1, max_north); + sw = "surface/" + LimitTravel(x - 1, max_east, 1, max_west) + "," + LimitTravel(y-1, max_north, 1, max_south); + se = "surface/" + LimitTravel(x + 1, max_east) + "," + LimitTravel(y-1, max_north, 1, max_south); + + SetSinkRoom(__DIR__+sink); + SetFlyRoom(__DIR__+fly); + + SetGoMessage("You can't travel in that direction."); + if( n ) AddExit("north", __DIR__ + n); + if( s ) AddExit("south", __DIR__ + s); + if( e ) AddExit("east", __DIR__ + e); + if( w ) AddExit("west", __DIR__ + w); + if( ne ) AddExit("northeast", __DIR__ + ne); + if( nw ) AddExit("northwest", __DIR__ + nw); + if( se ) AddExit("southeast", __DIR__ + se); + if( sw ) AddExit("southwest", __DIR__ + sw); + + if(x == 5 && (y < 50 && y > -50)){ + RemoveExit("west"); + RemoveExit("northwest"); + RemoveExit("southwest"); + AddExit("west", "/domains/town/room/shore"); + AddExit("northwest", "/domains/town/room/shore"); + AddExit("southwest", "/domains/town/room/shore"); + } +} + +varargs void SetLongAndItems(int x, int y, int z) { + mapping inv, items; + string str; + ::SetLongAndItems(x, y); + + inv = ([]); + str = "This is the surface of a vast sea."; + if(query_night()) str += " The stars of the night sky glitter overhead."; + else str+= " The sun seems oddly dim in the sky."; + + SetItems( ([ ({"sea","ocean"}) : "It is vast.", + ]) ); + SetLong(str); + SetDayLight(30); + SetNightLight(30); + SetInventory(inv); + SetTerrainType(T_SURFACE); + SetMedium(MEDIUM_SURFACE); + SetInventory( ([ + "/domains/town/obj/seawater" : 1, + ]) ); +} diff --git a/lib/domains/town/virtual/void.c b/lib/domains/town/virtual/void.c new file mode 100644 index 0000000..9345f5f --- /dev/null +++ b/lib/domains/town/virtual/void.c @@ -0,0 +1,17 @@ +#include <lib.h> +#include <dirs.h> +#include ROOMS_H +#include <virtual.h> +#include <position.h> + +inherit LIB_VIRT_LAND; + +varargs static void create(int x, int y) { + SetNoReplace(1); + virt_land::create(); + SetClimate("temperate"); + SetAmbientLight(30); + SetLong("A featureless void."); + SetShort("an empty place"); + AddExit("down", ROOM_START); +} diff --git a/lib/domains/town/weap/357pistol.c b/lib/domains/town/weap/357pistol.c new file mode 100644 index 0000000..60276ef --- /dev/null +++ b/lib/domains/town/weap/357pistol.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_FIREARM; + +void create(){ + ::create(); + SetKeyName("gun"); + SetId(({"gun","pistol","piece","revolver"})); + SetAdjectives(({".357","357","magnum"})); + SetShort("a .357 magnum revolver"); + SetLong("This is a thick, heavy chunk of weaponry that fires some very "+ + "serious rounds. Bullets are loaded individually into it, and they, along with spent "+ + "shells, remain in the cylinder until unloaded."); + SetCaliber(357); + SetFirearmType("revolver"); + SetFirearmName("revolver"); + SetAmmoType("magnum"); + SetMaxAmmo(6); + SetMass(20); + SetValue(10); + SetVendorType(VT_WEAPON); + SetMagnum(30); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/weap/9mil.c b/lib/domains/town/weap/9mil.c new file mode 100644 index 0000000..9991fad --- /dev/null +++ b/lib/domains/town/weap/9mil.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_PISTOL; + +void create(){ + ::create(); + SetKeyName("gun"); + SetId(({"gun","pistol"})); + SetAdjectives(({"9mm","automatic","9 millimeter","semiautomatic"})); + SetShort("a 9 millimeter semiautomatic pistol"); + SetLong("This is a large, semiautomatic pistol that fires 9mm rounds. It is "+ + "a heavy, serious-looking weapon."); + SetMillimeter(9); + SetFirearmType("auto"); + SetAmmoType("acp"); + SetMass(30); + SetBaseCost("silver",900); + SetVendorType(VT_WEAPON); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/weap/9mmpistol_mp.c b/lib/domains/town/weap/9mmpistol_mp.c new file mode 100644 index 0000000..b1cf2ca --- /dev/null +++ b/lib/domains/town/weap/9mmpistol_mp.c @@ -0,0 +1,39 @@ +#include <lib.h> +#include <vendor_types.h> +inherit "/lib/pistol"; +int AddClip(); +void CheckMP(); +void create(){ + pistol::create(); + SetKeyName("gun"); + SetId(({"gun","pistol"})); + SetAdjectives(({"9mm","automatic","9 millimeter","semiautomatic"})); + SetShort("a 9 millimeter semiautomatic pistol"); + SetLong("This is a large, semiautomatic pistol that fires 9mm rounds. It is "+ + "a heavy, serious-looking weapon."); + SetMillimeter(9); + SetFirearmType("auto"); + SetAmmoType("acp"); + SetMass(30); + SetBaseCost("silver",3000); + SetVendorType(VT_WEAPON); +} + +void init() { + pistol::init(); + CheckMP(); +} + +int AddClip(){ + new("/domains/town/obj/9mmclip")->eventMove(this_object()); + return 1; +} + +void CheckMP(){ + if(base_name(environment(this_object())) == "/domains/town/npc/mp"){ + AddClip(); + SetLoaded(1); + SetAmmo(15); + SetMag(1); + } +} diff --git a/lib/domains/town/weap/axe.c b/lib/domains/town/weap/axe.c new file mode 100644 index 0000000..9fe4f57 --- /dev/null +++ b/lib/domains/town/weap/axe.c @@ -0,0 +1,20 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("sharp axe"); + SetId( ({ "axe"})); + SetAdjectives( ({ "sharp","small","hand"})); + SetShort("a hand axe"); + SetLong("A small, sharp hand axe, suitable for close combat."); + SetMass(150); + SetBaseCost("silver",50); + SetVendorType(VT_WEAPON); + SetClass(15); + SetDamageType(BLADE); + SetWeaponType("blade"); +} diff --git a/lib/domains/town/weap/board.c b/lib/domains/town/weap/board.c new file mode 100644 index 0000000..a7fce55 --- /dev/null +++ b/lib/domains/town/weap/board.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("board of ed"); + SetId(({"board","board of ed","board of education"})); + SetAdjectives(({"ed","education"})); + SetShort("the board of education"); + SetLong("A long, wide wooden board with a handle at one "+ + "end. Inscribed along its length are the words: "+ + "'Board of Education'."); + SetMass(50); + SetBaseCost("silver",20); + SetVendorType(VT_WEAPON); + SetClass(20); + SetDamageType(BLUNT); + SetWeaponType("blunt"); +} diff --git a/lib/domains/town/weap/boobytrap_dagger.c b/lib/domains/town/weap/boobytrap_dagger.c new file mode 100644 index 0000000..2abf330 --- /dev/null +++ b/lib/domains/town/weap/boobytrap_dagger.c @@ -0,0 +1,42 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> +#include <boobytraps.h> + +inherit LIB_ITEM; +int AlreadyTrapped = 0; + +void boobytrap_me(){ + object shadowtrap; + if(!clonep(this_object())) return; /* Avoids boobytrapping the blueprint ob */ + if(AlreadyTrapped) return; + + AlreadyTrapped = 1; + shadowtrap = new("/shadows/needle_trap"); + shadowtrap->SetTrapDescription("A poison needle trap."); + shadowtrap->SetTrapLevel(50); + shadowtrap->SetAutoResets(1); + shadowtrap->SetTrapType(BOOBYTRAP_WIELD); + shadowtrap->eventShadow(this_object()); +} + +static void create() { + item::create(); + AddSave(({ "AlreadyTrapped" }) ); /* Shouldn't re-arm when you relog */ + SetKeyName("sharp dagger"); + SetId( ({ "dagger"})); + SetAdjectives( ({ "sharp","fine","wicked","wicked-looking"})); + SetShort("a wicked-looking dagger"); + SetLong("A sharp, wicked dagger."); + SetMass(150); + SetBaseCost("silver",50); + SetVendorType(VT_WEAPON); + SetClass(10); + SetDamageType(KNIFE); + SetWeaponType("knife"); + boobytrap_me(); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/weap/brush.c b/lib/domains/town/weap/brush.c new file mode 100644 index 0000000..e647f20 --- /dev/null +++ b/lib/domains/town/weap/brush.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create(){ + item::create(); + SetKeyName("brush"); + SetId( ({ "brush" }) ); + SetAdjectives( ({ "bath","shower","wood","wooden" }) ); + SetShort("a shower brush"); + SetLong("This is a long wooden brush with soft bristles "+ + "at the end, designed to assist in reaching "+ + "tough-to-scrub areas while bathing."); + SetVendorType(VT_WEAPON); + SetClass(10); + SetBaseCost("silver",25); + SetMass(100); + SetWeaponType("blunt"); + SetDamageType(BLUNT); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/weap/butcher_knife.c b/lib/domains/town/weap/butcher_knife.c new file mode 100644 index 0000000..7c4fb74 --- /dev/null +++ b/lib/domains/town/weap/butcher_knife.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("butcher knife"); + SetId( ({ "knife"})); + SetAdjectives( ({ "sharp","razor sharp","steel","hefty","stainless","butcher"})); + SetShort("an 8-inch butcher knife"); + SetLong("This is an 8-inch butcher knife. This razor sharp knife has been forged from molded and hammered high-carbon stainless steel. It is solid, hefty, and well-balanced for kitchen work, but probably not as good a weapon as a carving knife might be."); + SetMass(50); + SetBaseCost("silver",95); + SetVendorType(VT_WEAPON); + SetClass(15); + SetDamageType(KNIFE); + SetWeaponType("knife"); +} +int GetFancy(){ + return 1; +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/weap/carving_knife.c b/lib/domains/town/weap/carving_knife.c new file mode 100644 index 0000000..ab046b9 --- /dev/null +++ b/lib/domains/town/weap/carving_knife.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("carving knife"); + SetAdjectives( ({"8-inch", "serrated", "sharp", "razor-sharp", "razor", "steel", "hefty", "stainless", "carving"}) ); + SetId( ({ "knife"})); + SetShort("a serrated 8-inch carving knife"); + SetLong("This is a serrated, 8-inch carving knife. This razor sharp "+ + "knife has been forged from molded and hammered high-carbon "+ + "stainless steel. It is solid, hefty, and well-balanced. "+ + "This is a dangerous knife, and can be considered a very "+ + "deadly weapon."); + SetMass(50); + SetBaseCost("silver",120); + SetVendorType(VT_WEAPON); + SetClass(20); + SetDamageType(KNIFE); + SetWeaponType("knife"); +} +int GetFancy(){ + return 1; +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/weap/cue.c b/lib/domains/town/weap/cue.c new file mode 100644 index 0000000..29598a8 --- /dev/null +++ b/lib/domains/town/weap/cue.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create(){ + item::create(); + SetKeyName("cue"); + SetId( ({ "stick", "pole" }) ); + SetAdjectives( ({ "wood","wooden", "pool", "billiards", "billiard"}) ); + SetShort("a billiards cue"); + SetLong("This is a long stick of highly polished wood, used " + "in the game of billiards."); + SetVendorType(VT_WEAPON); + SetDamagePoints(50); + SetClass(10); + SetBaseCost("silver",150); + SetMass(80); + SetWeaponType("blunt"); + SetHands(2); + SetDamageType(BLUNT); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/weap/dagger.c b/lib/domains/town/weap/dagger.c new file mode 100644 index 0000000..572fd9f --- /dev/null +++ b/lib/domains/town/weap/dagger.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("sharp dagger"); + SetId( ({ "dagger"})); + SetAdjectives( ({ "sharp","fine","wicked","wicked-looking"})); + SetShort("a wicked-looking dagger"); + SetLong("A sharp, wicked dagger."); + SetMass(150); + SetBaseCost("silver",50); + SetVendorType(VT_WEAPON); + SetClass(10); + SetDamageType(KNIFE); + SetWeaponType("knife"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/weap/fellsword.c b/lib/domains/town/weap/fellsword.c new file mode 100644 index 0000000..9a602d3 --- /dev/null +++ b/lib/domains/town/weap/fellsword.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("Fell Sword"); + SetId( ({"sword", "weapon", "fellsword"}) ); + SetAdjectives( ({"fell", "elvish", "powerful", "antique", "old"}) ); + SetShort("The Fell Sword"); + SetLong("An elvish sword of great antiquity and tremendous power."); + SetUnique(1); + SetMass(100); + SetBaseCost("silver", 5000); + SetVendorType(VT_WEAPON); + SetClass(40); + SetDamageType(BLADE); + SetWeaponType("blade"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/weap/gstaff.c b/lib/domains/town/weap/gstaff.c new file mode 100644 index 0000000..35007e2 --- /dev/null +++ b/lib/domains/town/weap/gstaff.c @@ -0,0 +1,20 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; +static void create(){ + item::create(); + SetKeyName("golden staff"); + SetId( ({ "staff" }) ); + SetAdjectives( ({ "golden" }) ); + SetShort("a golden staff"); + SetLong("This is a thick staff, with one end covered in "+ + "a golden metal."); + SetVendorType(VT_WEAPON); + SetClass(10); + SetBaseCost("silver",800); + SetMass(100); + SetWeaponType("blunt"); + SetDamageType(BLUNT); +} diff --git a/lib/domains/town/weap/javelin.c b/lib/domains/town/weap/javelin.c new file mode 100644 index 0000000..756d5c9 --- /dev/null +++ b/lib/domains/town/weap/javelin.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("javelin"); + SetAdjectives( ({"throwing", "small", "light"}) ); + SetId( ({"spear"}) ); + SetShort("a javelin"); + SetLong("This is a small, light throwing spear."); + SetMass(50); + SetVendorType(VT_WEAPON); + SetClass(30); + SetDamageType(PIERCE); + SetWeaponType("projectile"); + SetBaseCost("silver", 85); +} + +void init(){ + ::init(); + add_action("podcast","podcast"); +} + +int podcast(){ + write("Somehow the javelin just doesn't seem to do that now."); + return 1; +} diff --git a/lib/domains/town/weap/knife.c b/lib/domains/town/weap/knife.c new file mode 100644 index 0000000..3cba06f --- /dev/null +++ b/lib/domains/town/weap/knife.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("small knife"); + SetId( ({ "knife"})); + SetAdjectives( ({ "small","fine"})); + SetShort("a small knife"); + SetLong("A knife."); + SetMass(50); + SetBaseCost("silver",5); + SetVendorType(VT_WEAPON); + SetClass(5); + SetDamageType(KNIFE); + SetWeaponType("knife"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/weap/leostaff.c b/lib/domains/town/weap/leostaff.c new file mode 100644 index 0000000..3bb8623 --- /dev/null +++ b/lib/domains/town/weap/leostaff.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; +static void create(){ + item::create(); + SetKeyName("staff"); + SetId( ({ "staff", "stick", "pole" }) ); + SetAdjectives( ({ "wood","wooden","strong","heavy","thick","sturdy","solid" }) ); + SetShort("a large wooden staff"); + SetLong("This staff is thick, strong, "+ + "and heavy. It feels like a sturdy "+ + "and solid weapon."); + SetVendorType(VT_WEAPON); + SetDamagePoints(50); + SetClass(500); + SetBaseCost("silver",25000); + SetMass(700); + SetWeaponType("blunt"); + SetHands(2); + SetDamageType(BLUNT); +} diff --git a/lib/domains/town/weap/m16rifle.c b/lib/domains/town/weap/m16rifle.c new file mode 100644 index 0000000..a0d7e71 --- /dev/null +++ b/lib/domains/town/weap/m16rifle.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include <vendor_types.h> +#include <damage_types.h> +inherit LIB_FIREARM; +void create(){ + ::create(); + SetKeyName("rifle"); + SetId(({"rifle","m16","M-16","weapon"})); + SetAdjectives(({"m-16","M-16","m16","M16","assault","colt"})); + SetShort("an M-16 assault rifle"); + SetLong("This sleek black weapon has been a military workhorse "+ + "for decades. It is durable, accurate, and above all, extraordinarily deadly. "+ + "This rifle uses .223 caliber ammunition magazines."); + SetCaliber(223); + SetFirearmType("auto"); + SetFirearmName("rifle"); + SetAmmoType("nato"); + SetMass(60); + SetDollarCost(1000); + SetHands(2); + SetClass(20); + SetWeaponType("blunt"); + SetDamageType(BLUNT); + SetVendorType(VT_WEAPON); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/weap/m16rifle_mp.c b/lib/domains/town/weap/m16rifle_mp.c new file mode 100644 index 0000000..04c9c0c --- /dev/null +++ b/lib/domains/town/weap/m16rifle_mp.c @@ -0,0 +1,53 @@ +#include <lib.h> +#include <vendor_types.h> +#include <damage_types.h> +inherit LIB_FIREARM; + +void CheckMP(); + +void create(){ + ::create(); + SetKeyName("rifle"); + SetId(({"rifle","m16","M-16","weapon"})); + SetAdjectives(({"m-16","M-16","m16","M16","assault","colt"})); + SetShort("an M-16 assault rifle"); + SetLong("This sleek black weapon has been a military workhorse "+ + "for decades. It is durable, accurate, and above all, extraordinarily deadly. "+ + "This rifle uses .223 caliber ammunition magazines."); + SetCaliber(223); + SetFirearmType("auto"); + SetFirearmName("rifle"); + SetAmmoType("nato"); + SetMass(60); + SetDollarCost(1000); + SetHands(2); + SetClass(20); + SetWeaponType("blunt"); + SetDamageType(BLUNT); + SetVendorType(VT_WEAPON); +} + +void init() { + ::init(); + CheckMP(); +} + +int AddClip(){ + object env = environment(); + object clip = present("clip",this_object()); + if(!clip && env && !(clip = present("clip",env))){ + clip = new("/domains/town/obj/223clip"); + } + if(clip) clip->eventMove(this_object()); + return 1; +} + +void CheckMP(){ + if(base_name(environment(this_object())) == "/domains/town/npc/mp"){ + AddClip(); + SetLoaded(1); + SetAmmo(30); + SetMag(1); + } +} + diff --git a/lib/domains/town/weap/orcslayer.c b/lib/domains/town/weap/orcslayer.c new file mode 100644 index 0000000..f56bf9f --- /dev/null +++ b/lib/domains/town/weap/orcslayer.c @@ -0,0 +1,38 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + + +static void create() { + item::create(); + SetKeyName("Orc Slayer"); + SetId( ({ "orcslayer", "orc slayer","sword", "short sword", "shortsword"})); + SetAdjectives( ({ "crafted","finely crafted","short","sharp","fine"})); + SetShort("a finely crafted short sword"); + SetLong("This is a very fine blade, covered with ancient runes. Engraved on it is a picture of the sword slicing an orc."); + SetMass(300); + SetBaseCost("silver",500); + SetVendorType(VT_WEAPON); + SetClass(35); + SetDamageType(BLADE); + SetWeaponType("blade"); + SetItems( ([ + ({"rune","runes"}) : "The runes' meaning is undecipherable to you.", + ({"picture","engraving"}) : "An almost comical image of a startled orc sliced in half.", + ]) ); + SetRead( ([ + ({"rune","runes"}) : "You do not understand them." + ]) ); + AddItem("thing" , "A thing."); +} +int eventStrike(object target) { + if( target->GetRace() != "orc" ) return item::eventStrike(target); + message("environment", "The orc slayer sword glows blue and emits a ghastly shrieking sound!", + environment(target)); + return item::eventStrike(target) + random(50)+10; +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/weap/paring_knife.c b/lib/domains/town/weap/paring_knife.c new file mode 100644 index 0000000..987ced6 --- /dev/null +++ b/lib/domains/town/weap/paring_knife.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("paring knife"); + SetId( ({ "knife"})); + SetAdjectives( ({ "serrated","sharp","razor sharp","steel","hefty","stainless","paring"})); + SetShort("a 4-inch paring knife"); + SetLong("This is a 4-inch paring knife. This very sharp knife has been forged from molded and hammered high-carbon stainless steel. Though light, it is solid and well-balanced."); + SetMass(20); + SetBaseCost("silver",55); + SetVendorType(VT_WEAPON); + SetClass(15); + SetDamageType(KNIFE); + SetWeaponType("knife"); +} +int GetFancy(){ + return 1; +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/weap/rod.c b/lib/domains/town/weap/rod.c new file mode 100644 index 0000000..f3ba75c --- /dev/null +++ b/lib/domains/town/weap/rod.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; +static void create(){ + item::create(); + SetKeyName("rod"); + SetId( ({ "staff", "stick", "pole" , "rod of asclepius", "rod of aesculapius"}) ); + SetAdjectives( ({ "wood","wooden" }) ); + SetShort("a wooden rod with a carved snake on it"); + SetLong("This handsome staff has been carved to " + "seem to have a snake wrapped around it."); + SetVendorType(VT_WEAPON); + SetDamagePoints(50); + SetClass(100); + SetBaseCost("silver",250); + SetMass(100); + SetWeaponType("blunt"); + SetHands(2); + SetDamageType(BLUNT); +} diff --git a/lib/domains/town/weap/runic_sword.c b/lib/domains/town/weap/runic_sword.c new file mode 100644 index 0000000..e0f5bca --- /dev/null +++ b/lib/domains/town/weap/runic_sword.c @@ -0,0 +1,38 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +int CheckOrc(){ + string ret = "The runes' meaning is undecipherable to you."; + if(this_player()->GetRace() == "orc"){ + write("You get an uneasy feeling."); + } + return write(ret); +} + +static void create() { + item::create(); + SetKeyName("sword"); + SetId( ({ "short sword", "shortsword"})); + SetAdjectives( ({ "crafted","finely crafted","short","sharp","fine","runic"})); + SetShort("a finely crafted short sword"); + SetLong("This is a very fine blade, covered with ancient runes."); + SetMass(300); + SetBaseCost("silver",500); + SetVendorType(VT_WEAPON); + SetClass(35); + SetDamageType(BLADE); + SetWeaponType("blade"); + SetItems( ([ + ({"rune","runes"}) : (: CheckOrc :), + ]) ); + SetRead( ([ + ({"rune","runes"}) : "You do not understand them." + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/town/weap/sharpsword.c b/lib/domains/town/weap/sharpsword.c new file mode 100644 index 0000000..81daf41 --- /dev/null +++ b/lib/domains/town/weap/sharpsword.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("sharp sword"); + SetId( ({"sword"}) ); + SetAdjectives( ({ "short","sharp","fine"})); + SetShort("a sharp sword"); + SetLong("A fine, sharp sword. It is solidly crafted and well balanced."); + SetMass(300); + SetBaseCost("silver", 1100); + SetVendorType(VT_WEAPON); + SetClass(35); + SetDamageType(BLADE); + SetWeaponType("blade"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/weap/shotput.c b/lib/domains/town/weap/shotput.c new file mode 100644 index 0000000..805deed --- /dev/null +++ b/lib/domains/town/weap/shotput.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("shot ball"); + SetAdjectives( ({"ball of", "palm sized", "shot"}) ); + SetId( ({"ball", "lead", "shot", "shotput"}) ); + SetShort("a palm-sized ball of lead"); + SetLong("This is a ball of lead, approximately nine inches in diameter. It is a weapon called a 'shot', intended to be thrown at an enemy."); + SetMass(50); + SetVendorType(VT_WEAPON); + SetClass(30); + SetDamageType(BLUNT); + SetWeaponType("projectile"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/weap/staff.c b/lib/domains/town/weap/staff.c new file mode 100644 index 0000000..e957119 --- /dev/null +++ b/lib/domains/town/weap/staff.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create(){ + item::create(); + SetKeyName("staff"); + SetId( ({ "staff", "stick", "pole" }) ); + SetAdjectives( ({ "wood","wooden" }) ); + SetShort("a wooden staff"); + SetLong("This staff is old, weathered, "+ + "and lumpy. However, it feels quite sturdy "+ + "and solid."); + SetVendorType(VT_WEAPON); + SetDamagePoints(50); + SetClass(20); + SetBaseCost("silver",250); + SetMass(100); + SetWeaponType("blunt"); + SetHands(2); + SetDamageType(BLUNT); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/weap/sword.c b/lib/domains/town/weap/sword.c new file mode 100644 index 0000000..79a6722 --- /dev/null +++ b/lib/domains/town/weap/sword.c @@ -0,0 +1,24 @@ +#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" }) ); + SetAdjectives( ({ "short" }) ); + SetShort("a short sword"); + SetLong("A cheap and rather dull short sword."); + SetMass(300); + SetBaseCost("silver",800); + SetVendorType(VT_WEAPON); + SetClass(30); + SetDamageType(BLADE); + SetWeaponType("blade"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/town/weap/verysharpsword.c b/lib/domains/town/weap/verysharpsword.c new file mode 100644 index 0000000..2d962b7 --- /dev/null +++ b/lib/domains/town/weap/verysharpsword.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +static void create() { + item::create(); + SetKeyName("sharp sword"); + SetId( ({"sword"}) ); + SetAdjectives( ({ "very", "short","sharp","fine"})); + SetShort("a very sharp sword"); + SetLong("A very fine, sharp sword. It is solidly crafted "+ + "and well balanced."); + SetMass(400); + SetBaseCost("silver", 2500); + SetVendorType(VT_WEAPON); + SetClass(35); + SetDamageType(BLADE); + SetWeaponType("blade"); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/doors/airlock.c b/lib/domains/voluntaria/doors/airlock.c new file mode 100644 index 0000000..7244813 --- /dev/null +++ b/lib/domains/voluntaria/doors/airlock.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("south", ([ "id" : ({"airlock", "door leading south", "door", "south door"}), + "short" : "the airlock", + "long" : "This is the inside of an airlock leading out. Make sure you know what is outside before you exit.", + "lockable" : 1 ]) ); + + SetSide("north", ([ "id" : ({"door leading north", "door", "north door"}), + "short" : "a door leading north", + "long" : "This is the south side of a door leading north.", + "lockable" : 1 ]) ); + + SetClosed(1); + SetLocked(0); + SetKeys("south", ({ "south key" })); + SetKeys("north", ({ "north key" })); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/doors/airlock.c - Copy.c b/lib/domains/voluntaria/doors/airlock.c - Copy.c new file mode 100644 index 0000000..0fbe845 --- /dev/null +++ b/lib/domains/voluntaria/doors/airlock.c - Copy.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("out", ([ "id" : ({"airlock", "door leading out", "door", "out door"}), + "short" : "the airlock", + "long" : "This is the inside of an airlock leading out. Make sure you know what is outside before you exit.", + "lockable" : 1 ]) ); + + SetSide("DIR_Y", ([ "id" : ({"door leading DIR_Y", "door", "DIR_Y door"}), + "short" : "a door leading DIR_Y", + "long" : "This is the out side of a door leading DIR_Y.", + "lockable" : 1 ]) ); + + SetClosed(1); + SetLocked(0); + SetKeys("out", ({ "out key" })); + SetKeys("DIR_Y", ({ "DIR_Y key" })); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/doors/commanddoor.c b/lib/domains/voluntaria/doors/commanddoor.c new file mode 100644 index 0000000..7b82a33 --- /dev/null +++ b/lib/domains/voluntaria/doors/commanddoor.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("up", ([ "id" : ({"door leading up", "door", "up door"}), + "short" : "a door leading up", + "long" : "This is the down side of a door leading up.", + "lockable" : 1 ]) ); + + SetSide("down", ([ "id" : ({"door leading down", "door", "down door"}), + "short" : "a door leading down", + "long" : "This is the up side of a door leading down.", + "lockable" : 1 ]) ); + + SetClosed(1); + SetLocked(1); + SetKeys("up", ({ "captain key" })); + SetKeys("down", ({ "capain key" })); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/doors/door.c b/lib/domains/voluntaria/doors/door.c new file mode 100644 index 0000000..b67611d --- /dev/null +++ b/lib/domains/voluntaria/doors/door.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("DIR_X", ([ "id" : ({"door leading DIR_X", "door", "DIR_X door"}), + "short" : "a door leading DIR_X", + "long" : "This is the Y_SIDE side of a door leading DIR_X.", + "lockable" : 1 ]) ); + + SetSide("DIR_Y", ([ "id" : ({"door leading DIR_Y", "door", "DIR_Y door"}), + "short" : "a door leading DIR_Y", + "long" : "This is the X_SIDE side of a door leading DIR_Y.", + "lockable" : 1 ]) ); + + SetClosed(1); + SetLocked(0); + SetKeys("DIR_X", ({ "DIR_X key" })); + SetKeys("DIR_Y", ({ "DIR_Y key" })); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/doors/enginedoor.c b/lib/domains/voluntaria/doors/enginedoor.c new file mode 100644 index 0000000..02334f2 --- /dev/null +++ b/lib/domains/voluntaria/doors/enginedoor.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("down", ([ "id" : ({"door leading down", "door", "down door"}), + "short" : "a door leading down", + "long" : "This is the up side of a door leading down.", + "lockable" : 1 ]) ); + + SetSide("up", ([ "id" : ({"door leading up", "door", "up door"}), + "short" : "a door leading up", + "long" : "This is the down side of a door leading up.", + "lockable" : 1 ]) ); + + SetClosed(1); + SetLocked(1); + SetKeys("down", ({ "engine key" })); + SetKeys("up", ({ "engine key" })); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/doors/m1.c b/lib/domains/voluntaria/doors/m1.c new file mode 100644 index 0000000..08e55c7 --- /dev/null +++ b/lib/domains/voluntaria/doors/m1.c @@ -0,0 +1,24 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("east", ([ "id" : ({"door leading east", "door", "east door"}), + "short" : "a door leading east", + "long" : "This is the west side of a door leading east.", + "lockable" : 1 ]) ); + + SetSide("west", ([ "id" : ({"door leading west", "door", "west door"}), + "short" : "a door leading west", + "long" : "This is the east side of a door leading west.", + "lockable" : 1 ]) ); + + SetClosed(0); + SetLocked(0); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/doors/out.c b/lib/domains/voluntaria/doors/out.c new file mode 100644 index 0000000..b67611d --- /dev/null +++ b/lib/domains/voluntaria/doors/out.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("DIR_X", ([ "id" : ({"door leading DIR_X", "door", "DIR_X door"}), + "short" : "a door leading DIR_X", + "long" : "This is the Y_SIDE side of a door leading DIR_X.", + "lockable" : 1 ]) ); + + SetSide("DIR_Y", ([ "id" : ({"door leading DIR_Y", "door", "DIR_Y door"}), + "short" : "a door leading DIR_Y", + "long" : "This is the X_SIDE side of a door leading DIR_Y.", + "lockable" : 1 ]) ); + + SetClosed(1); + SetLocked(0); + SetKeys("DIR_X", ({ "DIR_X key" })); + SetKeys("DIR_Y", ({ "DIR_Y key" })); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/doors/west.c b/lib/domains/voluntaria/doors/west.c new file mode 100644 index 0000000..b67611d --- /dev/null +++ b/lib/domains/voluntaria/doors/west.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("DIR_X", ([ "id" : ({"door leading DIR_X", "door", "DIR_X door"}), + "short" : "a door leading DIR_X", + "long" : "This is the Y_SIDE side of a door leading DIR_X.", + "lockable" : 1 ]) ); + + SetSide("DIR_Y", ([ "id" : ({"door leading DIR_Y", "door", "DIR_Y door"}), + "short" : "a door leading DIR_Y", + "long" : "This is the X_SIDE side of a door leading DIR_Y.", + "lockable" : 1 ]) ); + + SetClosed(1); + SetLocked(0); + SetKeys("DIR_X", ({ "DIR_X key" })); + SetKeys("DIR_Y", ({ "DIR_Y key" })); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/npc/captain.c b/lib/domains/voluntaria/npc/captain.c new file mode 100644 index 0000000..4917dcb --- /dev/null +++ b/lib/domains/voluntaria/npc/captain.c @@ -0,0 +1,22 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("captain Galt"); + SetId(({"captain","galt","john","mobile"})); + SetAdjectives(({"non player"})); + SetShort("Captain John Galt"); + SetLong("John Galt is the captain of the USS Profit, he's hard at work flying between Oogtopia and Voluntaria to bring Ooga Booga volunteers to serve the people of Voluntaria"); + SetInventory(([ + "/domains/voluntaria/obj/captainkey" : 1, + ])); + SetLevel(1); + SetMelee(1); + SetRace("ancap"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/npc/crapitalist.c b/lib/domains/voluntaria/npc/crapitalist.c new file mode 100644 index 0000000..ad87d35 --- /dev/null +++ b/lib/domains/voluntaria/npc/crapitalist.c @@ -0,0 +1,24 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("volunteer handler"); + SetId(({"ancap","handler","voluntaryist","crew member"})); + SetAdjectives(({"non player"})); + SetShort("voluntaryist volunteer handler"); + SetLong("This crew member is in charge of wrangling the oogas who have volunteered for a term of service by entering the airlock. +"); +SetInventory(([ +"/domains/default/armor/breather" : "wear", +])); + SetWanderSpeed(10); + SetLevel(1); + SetMelee(1); + SetRace("ancap"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/obj/captainkey.c b/lib/domains/voluntaria/obj/captainkey.c new file mode 100644 index 0000000..198c683 --- /dev/null +++ b/lib/domains/voluntaria/obj/captainkey.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; + +void create(){ + ::create(); + SetKeyName("captains key"); + SetId( ({"captain key","key","thang","dingus"}) ); + SetAdjectives( ({"royal","commanding","template"}) ); + SetShort("the captains key"); + SetLong("This is a key, belonging to the captain of the USS Profit"); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); +} +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/room/airlock.c b/lib/domains/voluntaria/room/airlock.c new file mode 100644 index 0000000..311ed57 --- /dev/null +++ b/lib/domains/voluntaria/room/airlock.c @@ -0,0 +1,133 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; +int planet, planetcounter, closed, my_counter, moving, callplanet, doorcounter; +string planetname; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("airlock"); + SetLong("an airlock in a Voluntaryist space ship. The walls are covered with advertizements and the sound of terms of service resonate through the air. The airlock is to your south, it shut when you entered the ship and the ship seems to have taken off, so be careful opening it."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + SetExits( ([ + "south" : "/domains/voluntaria/room/space", + "north" : "/domains/voluntaria/room/hallway.c", + ]) ); + set_heart_beat(1); + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + + + + SetDoor("south", "/domains/voluntaria/doors/airlock.c"); + +} +void init(){ + ::init(); +} +int CallMe(int i){ + if(i == planet && moving == 0) { + this_object()->SetDoorClosed(0); + return 1; + } + else callplanet = i; + return 1; +} +int SetDoorClosed(int i){ + if(i && i == closed) return i; + if(!i && closed == 0) return i; + if(i == 0 && closed == 0) return i; + if(i) closed = i; + else if( closed == 1 ) closed = 0; + else if( closed == 0 ) closed = 1; + if(planet == 1) planetname = "/domains/voluntaria/room/space"; + if(planet == 2) planetname = "/domains/voluntaria/room/start"; + if(planet == 3) planetname = "/domains/oogtopia/room/field"; + if(closed < 1){ + tell_room(this_object(),"The airlock opens."); + tell_room(load_object(planetname),"The airlock opens."); + doorcounter = 10; + } + if(closed > 0) { + tell_room(this_object(),"The airlock closes."); + tell_room(load_object(planetname),"The airlock closes."); + doorcounter = 0; + } + return closed; +} +int SetPlanet(int i){ + if(planet == i) return 0; + RemoveExit("south"); + planet = i; + if(i == 1) AddExit("south", "/domains/voluntaria/room/space"); + if(i == 2) AddExit("south", "/domains/voluntaria/room/start"); + if(i == 3) AddExit("south", "/domains/oogtopia/room/field"); + return 1; +} +int CanReceive(object ob) { +#if 1 + if(living(ob) && closed > 0 && query_verb() != "goto" && + query_verb() != "trans" ){ + message("info","The airlock is closed.", ob); + return 0; + } +#endif + return 1; +} +int CanRelease(object ob){ + if(archp(ob)) { + tell_object(ob,"%^RED%^As archwizard, you are permitted to " + "exit the elevator at any time. Normal creators and " + "players cannot do this.%^RESET%^\n"); + } + if(closed > 0 && query_verb() == "go" ){ + message("info","The airlock is closed.", ob); + return 0; + } + return 1; +} +varargs int eventRoll(int i){ + if(!i) i = 10; + moving = 1; + SetDoorClosed(1); + my_counter = i; + return i; +} +void heart_beat(){ + if(doorcounter > 0){ + doorcounter--; + if(doorcounter < 2) SetDoorClosed(1); + } + + if(moving == 0 && closed == 1 && callplanet > 0){ + tell_room(this_object(),"The elevator lurches into motion."); + eventRoll(); + } + + if(moving && moving > 0){ + my_counter--; + if(my_counter % 5 == 0) { + tell_room(this_object(),"The elevator continues..."); + } + + if(my_counter < 2) { + my_counter = 0; + moving = 0; + SetPlanet(callplanet); + tell_room(this_object(),"The elevator arrives at its destination."); + SetDoorClosed(0); + callplanet = 0; + } + } +} diff --git a/lib/domains/voluntaria/room/bottomstair.c b/lib/domains/voluntaria/room/bottomstair.c new file mode 100644 index 0000000..ad9242a --- /dev/null +++ b/lib/domains/voluntaria/room/bottomstair.c @@ -0,0 +1,33 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("copy of stairwell.c"); + SetLong("You are standing in a stairwell on the volunteer deck of the USS Profit, You can go up to the command deck or down to the engine section. There are doors which are usually locked at the top and bottom of the stairs."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + SetExits(([ + "up" : "/domains/voluntaria/room/stairwell", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + + SetDoor("up", "/domains/oogtopia/doors/enginedoor.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/room/bridge.c b/lib/domains/voluntaria/room/bridge.c new file mode 100644 index 0000000..e714c87 --- /dev/null +++ b/lib/domains/voluntaria/room/bridge.c @@ -0,0 +1,69 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("The Bridge of the USS Profit"); + SetLong("This is the bridge of the USS profit, From here you can set a course to any of the planets that are in the navicomputer, or you can simply take off into space. If you would like to set a course type navicomputer followed by where you would like to go to, To see where the navicomputer knows how to go, look at it."); + SetItems(([ + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "navicomputer", "computer", "navigator", "navi" }) : "The known planets are: Voluntaria and Oogtopia, you can also blast into space", + ])); + SetInventory(([ + "/domains/voluntaria/npc/captain" : 1, + ])); + SetExits(([ + "east" : "/domains/voluntaria/room/commandhall", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + add_action( "navicomputer", "navicomputer" ); + ::init(); +} + +object airlock = load_object("domains/voluntaria/room/airlock.c"); +object exit = load_object("domains/voluntaria/room/commandexit.c"); + + +int navicomputer (string dest) { + int planet; + dest = lower_case(dest); + if(dest == "space") { + planet = 1; + write("You blast off into space"); + } + else if(dest == "voluntaria") { + planet = 2; + write("You plot a course for Voluntaria"); + } + else if(dest == "oogtopia") { + planet = 3; + write("you plot a course for Oogtopia"); + } + else { + notify_fail("The navicomputer doesn't have coordinates for that location. type your request as navicomputer oogtopia if you want to go collect more volunteers\n"); + return 0; + } + airlock->SetPlanet(planet); + if(!planet == 1) { + } + return 1; +} + + + + diff --git a/lib/domains/voluntaria/room/bridge2.txt b/lib/domains/voluntaria/room/bridge2.txt new file mode 100644 index 0000000..6e64c84 --- /dev/null +++ b/lib/domains/voluntaria/room/bridge2.txt @@ -0,0 +1,68 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("The Bridge of the USS Profit"); + SetLong("This is the bridge of the USS profit, From here you can set a course to any of the planets that are in the navicomputer, or you can simply take off into space."); + SetItems(([ + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "navicomputer", "computer", "navigator", "navi" }) : "The known planets are: Voluntaria and Oogtopia", + ])); + SetInventory(([ + "/domains/voluntaria/npc/captain" : 1, + ])); + SetExits(([ + "east" : "/domains/voluntaria/room/commandhall", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + add_action( "navicomputer", "navicomputer" ); + ::init(); +} + +object airlock = load_object("domains/voluntaria/room/airlock.c"); +object exit = load_object("domains/voluntaria/room/commandexit.c"); + + +int navicomputer (string dest) { + int planet; + dest = lower_case(dest); + if(dest == "space") { + planet = 1; + } + else if(dest == "voluntaria") { + planet = 2; + } + else if(dest == "oogtopia") { + planet = 3; + } + else { + notify_fail("The navicomputer doesn't have coordinates for that location. type your request as navicomputer oogtopia if you want to go collect more volunteers\n"); + return 0; + } + airlock->SetDoorClosed(1); + airlock->SetPlanet(planet); + if(!planet == 1) { + airlock->SetDoorClosed(0): + } + return 1; +} + + + + diff --git a/lib/domains/voluntaria/room/commandexit.c b/lib/domains/voluntaria/room/commandexit.c new file mode 100644 index 0000000..59a215e --- /dev/null +++ b/lib/domains/voluntaria/room/commandexit.c @@ -0,0 +1,34 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("An emergency exit on the command deck"); + SetLong("This emergency exit was put in to allow the captain to escape without going through the main airlock, the airlock to the south allows entrance to whatever planet the ship has landed on"); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + SetExits(([ + "north" : "/domains/voluntaria/room/commandhall", + "south" : "/domains/voluntaria/room/spaceup", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + + SetDoor("south", "/domains/voluntaria/doors/airlock.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/room/commandhall.c b/lib/domains/voluntaria/room/commandhall.c new file mode 100644 index 0000000..f8f054d --- /dev/null +++ b/lib/domains/voluntaria/room/commandhall.c @@ -0,0 +1,34 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("command deck hallway"); + SetLong("The command deck hallway extends from the stairs at the north end to the emergency exit at the south end. To the west is the bridge and to the east are the captains quarters"); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + SetExits( ([ + "north" : "/domains/voluntaria/room/topstair", + "south" : "/domains/voluntaria/room/commandexit", + "east" : "/domains/voluntaria/room/quarters", + "west" : "/domains/voluntaria/room/bridge.c", + ]) ); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/room/crewpod.c b/lib/domains/voluntaria/room/crewpod.c new file mode 100644 index 0000000..e6ec210 --- /dev/null +++ b/lib/domains/voluntaria/room/crewpod.c @@ -0,0 +1,34 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("a crewpod"); + SetLong("This is where the crew of the USS Profit who have been tasked with handling the volunteers take their breaks"); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + SetExits(([ + "east" : "/domains/voluntaria/room/hallway", + ])); + SetInventory(([ + "/domains/voluntaria/npc/crapitalist" : 3, + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/room/death.c b/lib/domains/voluntaria/room/death.c new file mode 100644 index 0000000..9a8de22 --- /dev/null +++ b/lib/domains/voluntaria/room/death.c @@ -0,0 +1,73 @@ +#include <lib.h> +#include <dirs.h> +#include ROOMS_H + +inherit LIB_ROOM; + +string FunkyPic(); +int CheckChat(); +int StartHeart(object ob); + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("off the mortal coil"); + SetLong( (:FunkyPic:) ); + SetObviousExits("no exit"); + set_heart_beat(10); + SetNoModify(1); +} + +void init(){ + ::init(); + add_action("regenerate","regenerate"); + add_action("regenerate","choose"); + add_action("wander","wander"); + this_object()->CheckChat(); +} + +string FunkyPic(){ + return "YOU ARE DEAD!!!"; +} + +int regenerate(){ + write("With a great rush of matter and energy, you rematerialize "+ + "into a corporeal state, and find yourself in a familiar place..."); + this_player()->eventRevive(); + this_player()->eventMoveLiving(ROOM_START); + return 1; +} + +int wander(){ + write("There is a strange, hollow vibration all around you, and you "+ + "realize that some force is compelling your ethereal form elsewhere..."+ + "you find yourself in a place that is known to you, yet oddly new."); + this_player()->eventMoveLiving(ROOM_START); + return 1; +} + +void heart_beat(){ + tell_room(this_object(), "A voice whispers: \" You may choose to "+ + "regenerate into a new body here.\""); + return; +} + + +int CanRelease(object ob){ + if(userp(ob) && ob->GetGhost() && environment(ob) == this_object()) { + tell_player(ob,"\n%^RED%^Your undead spirit is recalled and as you leave "+ + "the underworld a new body regenerates around you. "+ + "You live again!%^RESET%^\n"); + ob->eventRevive(); + } + return 1; +} + +int CanReceive(object ob){ + if(!living(ob)){ + return 0; + } + return ::CanReceive(ob); +} + diff --git a/lib/domains/voluntaria/room/freezer.c b/lib/domains/voluntaria/room/freezer.c new file mode 100644 index 0000000..896cbbf --- /dev/null +++ b/lib/domains/voluntaria/room/freezer.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetNoClean(1); + SetProperties(([ "login" : ROOM_START ])); + SetShort( "The freezer"); + SetLong( "The local freezer. Go down to leave."); + SetObviousExits("down"); + SetExits( ([ "down" : ROOM_START ]) ); + call_out("clean_room", MAX_NET_DEAD_TIME); + SetNoModify(1); +} + +static void clean_room(){ + object ob; + call_out((: clean_room :), MAX_NET_DEAD_TIME); + foreach(ob in filter(all_inventory(), (: living($1) :))){ + string name = last_string_element(base_name(ob),"/"); + if(!user_exists(name)) continue; + ob->eventDestruct(); + } +} + +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/room/furnace.c b/lib/domains/voluntaria/room/furnace.c new file mode 100644 index 0000000..240341a --- /dev/null +++ b/lib/domains/voluntaria/room/furnace.c @@ -0,0 +1,10 @@ +#include <lib.h> + +inherit LIB_FURNACE; + +void create() { + furnace::create(); +} +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/room/hallway.c b/lib/domains/voluntaria/room/hallway.c new file mode 100644 index 0000000..d2a5979 --- /dev/null +++ b/lib/domains/voluntaria/room/hallway.c @@ -0,0 +1,34 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("a hallway"); + SetLong("a hallway in a Voluntaryist space ship. The walls are covered with advertizements and the sound of terms of service resonate through the air."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + SetExits( ([ + "south" : "/domains/voluntaria/room/airlock", + "west" : "/domains/voluntaria/room/crewpod", + "north" : "/domains/voluntaria/room/hallway2.c", + ]) ); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + + +} +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/room/hallway2.c b/lib/domains/voluntaria/room/hallway2.c new file mode 100644 index 0000000..f284e7d --- /dev/null +++ b/lib/domains/voluntaria/room/hallway2.c @@ -0,0 +1,32 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("a hallway"); + SetLong("a hallway in a Voluntaryist space ship. The walls are covered with advertizements and the sound of terms of service resonate through the air."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + SetExits( ([ + "south" : "/domains/voluntaria/room/hallway", + "north" : "/domains/voluntaria/room/stairwell.c", + ]) ); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/room/pod.c b/lib/domains/voluntaria/room/pod.c new file mode 100644 index 0000000..62da2f9 --- /dev/null +++ b/lib/domains/voluntaria/room/pod.c @@ -0,0 +1,16 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("the incept pod"); + SetLong("The incept pod. Some objects come here to be created "+ + "and identified. Go down to get out."); + SetExits( ([ "down" : ROOM_START ]) ); +} +int CanReceive(object ob){ + return room::CanReceive(ob); +} diff --git a/lib/domains/voluntaria/room/quarters.c b/lib/domains/voluntaria/room/quarters.c new file mode 100644 index 0000000..c57f0bb --- /dev/null +++ b/lib/domains/voluntaria/room/quarters.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("copy of commandhall.c"); + SetLong("The command deck hallway extends from the stairs at the north end to the emergency exit at the south end. To the west is the bridge and to the east are the captains quarters"); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + SetExits(([ + "west" : "/domains/voluntaria/room/commandhall", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/room/space.c b/lib/domains/voluntaria/room/space.c new file mode 100644 index 0000000..a89c2e1 --- /dev/null +++ b/lib/domains/voluntaria/room/space.c @@ -0,0 +1,34 @@ +#include <lib.h> +#include <medium.h> +#include <terrain_types.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetTerrainType(T_SPACE); + SetMedium(MEDIUM_SPACE); + SetShort("The empty vastness of space"); + SetLong("You are drifting in outerspace, near the Voluntaryist spaceship the USS profit. If you are not wearing a spacesuit you are going to die very soon"); + SetItems(([ + ({ "spaceship", "airlock", "ship", "USS profit" }) : "The spaceship was built by the lowest bidder and flown on repeated missions to gather volunteers, it's amazing it hasn't already exploded.", + ])); + SetExits( ([ + "up" : "/domains/voluntaria/room/spaceup", + "down" : "/domains/voluntaria/room/spacedown.c", + ]) ); + SetEnters( ([ + "spaceship" : "/domains/voluntaria/room/airlock.c", + ]) ); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + + +} +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/room/spacedown.c b/lib/domains/voluntaria/room/spacedown.c new file mode 100644 index 0000000..f83c10d --- /dev/null +++ b/lib/domains/voluntaria/room/spacedown.c @@ -0,0 +1,33 @@ +#include <lib.h> +#include <medium.h> +#include <terrain_types.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetTerrainType(T_SPACE); + SetMedium(MEDIUM_SPACE); + SetShort("copy of space.c"); + SetLong("You are drifting in outerspace, near the Voluntaryist spaceship the USS profit. If you are not wearing a spacesuit you are going to die very soon"); + SetItems(([ + ({ "spaceship", "airlock", "ship", "USS profit" }) : "The spaceship was built by the lowest bidder and flown on repeated missions to gather volunteers, it's amazing it hasn't already exploded.", + ])); + SetExits(([ + "up" : "/domains/voluntaria/room/space", + ])); + + SetEnters( ([ + "spaceship" : "/domains/voluntaria/room/airlock.c", + ]) ); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/room/spaceup.c b/lib/domains/voluntaria/room/spaceup.c new file mode 100644 index 0000000..8b8ff61 --- /dev/null +++ b/lib/domains/voluntaria/room/spaceup.c @@ -0,0 +1,35 @@ +#include <lib.h> +#include <medium.h> +#include <terrain_types.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetTerrainType(T_SPACE); + SetMedium(MEDIUM_SPACE); + SetShort("copy of space.c"); + SetLong("You are drifting in outerspace, near the Voluntaryist spaceship the USS profit. If you are not wearing a spacesuit you are going to die very soon"); + SetItems(([ + ({ "spaceship", "airlock", "ship", "USS profit" }) : "The spaceship was built by the lowest bidder and flown on repeated missions to gather volunteers, it's amazing it hasn't already exploded.", + ])); + SetExits(([ + "down" : "/domains/voluntaria/room/space", + ])); + + SetEnters( ([ + "spaceship" : "/domains/voluntaria/room/airlock.c", + ]) ); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + + SetDoor("north", "/domains/voluntaria/doors/airlock.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/room/stairwell.c b/lib/domains/voluntaria/room/stairwell.c new file mode 100644 index 0000000..cdbe7fb --- /dev/null +++ b/lib/domains/voluntaria/room/stairwell.c @@ -0,0 +1,37 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("a stairwell"); + SetLong("You are standing in a stairwell on the volunteer deck of the USS Profit, You can go up to the command deck or down to the engine section. There are doors which are usually locked at the top and bottom of the stairs."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + SetExits( ([ + "south" : "/domains/voluntaria/room/hallway2", + "up" : "/domains/voluntaria/room/topstair", + "down" : "/domains/voluntaria/room/bottomstair.c", + ]) ); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + + SetDoor("up", "/domains/voluntaria/doors/commanddoor.c"); + + SetDoor("down", "/domains/voluntaria/doors/enginedoor.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/room/start.c b/lib/domains/voluntaria/room/start.c new file mode 100644 index 0000000..79d1ee7 --- /dev/null +++ b/lib/domains/voluntaria/room/start.c @@ -0,0 +1,34 @@ +#include <terrain_types.h> +#include <lib.h> +inherit LIB_ROOM; + + + + +static void create() { + room::create(); + SetClimate("temperate"); + SetDayLight(50); + SetNightLight(20); + SetShort("Voluntaria Spaceport"); + SetNightLong("You are in the spaceport of Voluntaria. Most of the ships are tightly sealed with the port crew all at home or at the bar but you can see the airlock of the USS Profit hanging open"); + SetDayLong("You are in the spaceport of Voluntaria. Most of the ships are tightly sealed with a few being swarmed by port crew loading and unloading cargo but you can see the airlock of the USS Profit hanging open with nobody standing nearby"); + SetItems(([ + ({ "spaceship", "airlock", "ship", "USS profit" }) : "The spaceship was built by the lowest bidder and flown on repeated missions to gather volunteers, it's amazing it hasn't already exploded.", + ])); + SetExits( ([ + "south" : "/domains/town/room/south_road1", + "east" : "/domains/town/room/vill_road2", + "west" : "/domains/town/room/road1", + "north" : "/domains/town/room/road0.c", + ]) ); + SetEnters( ([ + "spaceship" : "/domains/voluntaria/room/airlock.c", + ]) ); + AddTerrainType(T_ROAD); + SetNoModify(0); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/room/topstair.c b/lib/domains/voluntaria/room/topstair.c new file mode 100644 index 0000000..459cca2 --- /dev/null +++ b/lib/domains/voluntaria/room/topstair.c @@ -0,0 +1,34 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("the top of the stairs"); + SetLong("This is the top of the stairwell, if you head down you will be on the vounteer deck. The command deck hallway extends to the south"); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + SetExits( ([ + "down" : "/domains/voluntaria/room/stairwell", + "south" : "/domains/voluntaria/room/commandhall.c", + ]) ); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + + SetDoor("down", "/domains/oogtopia/doors/commanddoor.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/room/void.c b/lib/domains/voluntaria/room/void.c new file mode 100644 index 0000000..622a4ac --- /dev/null +++ b/lib/domains/voluntaria/room/void.c @@ -0,0 +1,16 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("the void"); + SetLong("The void. Go down to get out."); + SetExits( ([ "down" : ROOM_START ]) ); + SetNoModify(1); +} +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/room/wiz_hall.c b/lib/domains/voluntaria/room/wiz_hall.c new file mode 100644 index 0000000..dba7910 --- /dev/null +++ b/lib/domains/voluntaria/room/wiz_hall.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Creators' Hall"); + SetLong("A generic Wiz Hall."); + SetProperty("no attack", 1); + SetProperty("nopeer",1); +} + +int CanReceive(object ob) { + if(playerp(ob) && !creatorp(ob) && !present("testchar badge",ob)) { + message("info","Creator staff only, sorry.", ob); + return 0; + } + return ::CanReceive(ob); +} + +void init(){ + ::init(); +} diff --git a/lib/domains/voluntaria/virtual/server.c b/lib/domains/voluntaria/virtual/server.c new file mode 100644 index 0000000..ecb4ead --- /dev/null +++ b/lib/domains/voluntaria/virtual/server.c @@ -0,0 +1,22 @@ +#define __DIR__ "/domains/voluntaria/virtual/" + +mixed compile_object(string file) { + string *path; + object ob; + int x, y, z, elements; + if(grepp(file, "/user_") || grepp(file, "/object_")){ + ob = new("/domains/voluntaria/virtual/void"); + if(!ob){ + return "No void room available."; + } + return ob; + } + path = explode(file, "/"); + if( file_size(__DIR__ + path[3] + ".c") < 1 ) return "bad file"; + if( (elements = sscanf(path[4], "%d,%d,%d", x, y, z)) != 3 ) { + if( (elements = sscanf(path[4], "%d,%d", x, y)) != 2 ) return "missing comma"; + } + if( elements == 2 && !(ob = new(__DIR__ + path[3], x, y)) ) return "failed to compile"; + else if( elements == 3 && !(ob = new(__DIR__ + path[3], x, y, z)) ) return "failed to compile"; + return ob; +} diff --git a/lib/domains/voluntaria/virtual/void.c b/lib/domains/voluntaria/virtual/void.c new file mode 100644 index 0000000..c046a9c --- /dev/null +++ b/lib/domains/voluntaria/virtual/void.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <dirs.h> +#include <rooms.h> +#include <virtual.h> +#include <position.h> +#define __DIR__ "/domains/voluntaria/virtual/" + +inherit LIB_VIRT_LAND; + +varargs static void create(int x, int y) { + SetNoReplace(1); + virt_land::create(); + SetClimate("temperate"); + SetAmbientLight(30); + SetLong("A featureless void."); + SetShort("an empty place"); + AddExit("down", ROOM_START); +} diff --git a/lib/estates/foo.txt b/lib/estates/foo.txt new file mode 100644 index 0000000..27afd21 --- /dev/null +++ b/lib/estates/foo.txt @@ -0,0 +1 @@ +This file intentionally left blank. diff --git a/lib/ftp/foo.txt b/lib/ftp/foo.txt new file mode 100644 index 0000000..27afd21 --- /dev/null +++ b/lib/ftp/foo.txt @@ -0,0 +1 @@ +This file intentionally left blank. diff --git a/lib/include/armor_types.h b/lib/include/armor_types.h new file mode 100644 index 0000000..acf34fa --- /dev/null +++ b/lib/include/armor_types.h @@ -0,0 +1,29 @@ +#ifndef __ARMOR_TYPES_H__ +#define __ARMOR_TYPES_H__ + +#define A_CUSTOM (1 << 0) +#define A_RING (1 << 1) +#define A_GLOVE (1 << 2) +#define A_LONG_GLOVE (1 << 3) +#define A_BOOT (1 << 4) +#define A_LONG_BOOT (1 << 5) +#define A_SOCK (1 << 6) +#define A_LONG_SOCK (1 << 7) +#define A_HELMET (1 << 8) +#define A_VISOR (1 << 9) +#define A_PANTS (1 << 10) +#define A_BELT (1 << 11) +#define A_SHIRT (1 << 12) +#define A_CLOAK (1 << 13) +#define A_VEST (1 << 14) +#define A_WEAPON (1 << 15) +#define A_SHIELD (1 << 16) +#define A_ARMOR (1 << 17) +#define A_AMULET (1 << 18) +#define A_COLLAR (1 << 19) +#define A_BODY_ARMOR (1 << 20) +#define A_EXO (1 << 21) + +#define A_MAX_ARMOR_BIT A_EXO + +#endif /* __ARMOR_TYPES_H__ */ diff --git a/lib/include/assessment.h b/lib/include/assessment.h new file mode 100644 index 0000000..5111441 --- /dev/null +++ b/lib/include/assessment.h @@ -0,0 +1,13 @@ +#ifndef s_assessment_h +#define s_assessment_h + +#define INCOMPLETE 1 +#define IMPOSSIBLE 2 +#define POSSIBLE 3 + +class assessment { + int status; + int last; +} + +#endif // s_assessment_h diff --git a/lib/include/astar.h b/lib/include/astar.h new file mode 100644 index 0000000..7eb8df6 --- /dev/null +++ b/lib/include/astar.h @@ -0,0 +1,14 @@ +/* Tricky */ +#ifndef __ASTAR_H__ +#define __ASTAR_H__ + +#define AS_PARENT 0 +#define AS_X 1 +#define AS_Y 2 +#define AS_GCOST 3 +#define AS_HCOST 4 +#define AS_FCOST 5 + +#define AS_DATA_SZ 6 + +#endif /* !__ASTAR_H__ */ diff --git a/lib/include/body_types.h b/lib/include/body_types.h new file mode 100644 index 0000000..7e7e7aa --- /dev/null +++ b/lib/include/body_types.h @@ -0,0 +1,33 @@ +#ifndef __BODY_TYPES__ +#define __BODY_TYPES__ + +#define B_HUMANOID (1 << 0) +#define B_QUADRUPED (1 << 1) +#define B_BIPED (1 << 2) +#define B_CHIROPTEROID (1 << 3) +#define B_INSECTOID (1 << 4) +#define B_TENTACLED (1 << 5) +#define B_ARTHROPOD (1 << 6) +#define B_CRUSTACEAN (1 << 7) +#define B_PINNIPED (1 << 8) +#define B_CETACEAN (1 << 9) +#define B_FISH (1 << 10) +#define B_OCTOPOID (1 << 11) +#define B_NEBULOUS (1 << 12) +#define B_CHIMAERA (1 << 13) +#define B_SNAKE (1 << 14) +#define B_PLANT (1 << 15) +#define B_TREE (1 << 16) +#define B_SPECTRAL (1 << 17) +#define B_GEOMETRIC (1 << 18) +#define B_GELATINOUS (1 << 19) +#define B_ORB (1 << 20) +#define B_AVIAN (1 << 21) +#define B_WINGED_MAN (1 << 22) +#define B_SEMI_BIPEDAL (1 << 23) +#define B_FLAT (1 << 24) +#define B_GASTROPOD (1 << 25) + +#define MAX_BTYPE_BIT B_GASTROPOD + +#endif /* __BODY_TYPES_H__ */ diff --git a/lib/include/boobytraps.h b/lib/include/boobytraps.h new file mode 100644 index 0000000..388b18a --- /dev/null +++ b/lib/include/boobytraps.h @@ -0,0 +1,19 @@ +#ifndef s_boobytrap_h +#define s_boobytrap_h + +#define BOOBYTRAP_OPEN (1 << 1) +#define BOOBYTRAP_CLOSE (1 << 2) +#define BOOBYTRAP_GET (1 << 3) +#define BOOBYTRAP_DROP (1 << 4) +#define BOOBYTRAP_LOCK (1 << 5) +#define BOOBYTRAP_UNLOCK (1 << 6) +#define BOOBYTRAP_STEAL (1 << 7) +#define BOOBYTRAP_PICK (1 << 8) +#define BOOBYTRAP_WEAR (1 << 9) +#define BOOBYTRAP_REMOVE (1 << 10) +#define BOOBYTRAP_WIELD (1 << 11) +#define BOOBYTRAP_UNWIELD (1 << 12) + +#define BOOBYTRAP_ALL BOOBYTRAP_OPEN | BOOBYTRAP_CLOSE | BOOBYTRAP_GET | BOOBYTRAP_DROP | BOOBYTRAP_LOCK | BOOBYTRAP_UNLOCK | BOOBYTRAP_STEAL | BOOBYTRAP_PICK | BOOBYTRAP_WEAR | BOOBYTRAP_REMOVE | BOOBYTRAP_WIELD | BOOBYTRAP_UNWIELD + +#endif /* s_boobytrap_h */ diff --git a/lib/include/build_types.h b/lib/include/build_types.h new file mode 100644 index 0000000..93405c1 --- /dev/null +++ b/lib/include/build_types.h @@ -0,0 +1,9 @@ +#define B_WAIF (1 << 0) +#define B_THIN (1 << 1) +#define B_SLIM (1 << 2) +#define B_MEDIUM (1 << 3) +#define B_LARGE (1 << 4) +#define B_HUSKY (1 << 5) +#define B_STOUT (1 << 6) +#define B_OBESE (1 << 7) +#define B_MORBIDLY_OBESE (1 << 8) diff --git a/lib/include/climb.h b/lib/include/climb.h new file mode 100644 index 0000000..82ebaac --- /dev/null +++ b/lib/include/climb.h @@ -0,0 +1,10 @@ +#ifndef s_climb_h +#define s_climb_h + +#define CLIMB_UP 1 +#define CLIMB_DOWN 2 +#define CLIMB_OUT 3 +#define CLIMB_INTO 4 +#define CLIMB_THROUGH 5 + +#endif /* s_climb_h */ diff --git a/lib/include/combat_messages.h b/lib/include/combat_messages.h new file mode 100644 index 0000000..70354ae --- /dev/null +++ b/lib/include/combat_messages.h @@ -0,0 +1,230 @@ +/* compiled by Blitz@Dead Souls and Mikla@Dead Souls */ + +// The SOBER_COMBAT define is intended to make combat messages a +// bit less emo. The problem with the original combat messages is +// that if you have, say, two robots fighting, it's weird and +// jarring to see them foaming at the mouth or grunting angrily. +// Just remove the define for the old-style behavior, if you want +// the bellowing and ranting back. -Crat 05Nov2007 + +#define SOBER_COMBAT + +#ifndef SOBER_COMBAT + +#define MOVE_TYPES ({\ +({ "feint deceptively", "feints deceptively" }),\ +({ "dance around", "dances around" }),\ +({ "lunge quickly", "lunges quickly" }),\ +({ "duck low", "ducks low" }),\ +({ "move fast", "moves fast" }),\ +({ "strike rapidly", "strikes rapidly" }),\ +({ "sidestep nimbly", "sidesteps nimbly" }),\ +({ "growl menacingly", "growls menacingly" }),\ +({ "grin sadistically", "grins sadistically" }),\ +({ "grunt angrily", "grunts angrily" }),\ +({ "bellow loudly", "bellows loudly" }),\ +({ "swing blindly", "swings blindly" }),\ +({ "shout profanities", "shouts profanities" }),\ +({ "swell with ferocity", "swells with ferocity" }),\ +({ "rally with determination", "rallies with determination" }),\ +({ "spit derisively", "spits derisively" }),\ +({ "glare contemptuously", "glares contemptuously" }),\ +({ "stumble fortuitously", "stumbles fortuitously" }),\ +({ "scream, \"Die!\"", "screams, \"Die!\"" }),\ +({ "foam at the mouth", "foams at the mouth" }),\ +({ "rant, \"Aahrrg!\"", "rants, \"Aahrrg!\"" }),\ +({ "execute a diving roll maneuver", "executes a diving roll maneuver" }),\ +({ "attack with renewed frenzy", "attacks with renewed frenzy" }),\ +({ "yell, \"Look!! Behind you!\"", "yells, \"Look!! Behind you!\"" }),\ +({ "go completely berserk", "goes completely berserk" }),\ +({ "rage violently", "rages violently" }),\ +({ "gyrate energetically", "gyrates energetically" }),\ +({ "whirl around quickly", "whirls around quickly" }),\ +({ "whirl blurringly", "whirls blurringly" }),\ +({ "see an opening", "sees an opening" }),\ +({ "do a cunning move", "does a cunning move" }),\ +({ "twirl with finesse", "twirls with finesse" }),\ +}) + +#else + +#define MOVE_TYPES ({\ +({ "feint", "feints" }),\ +({ "twist swiftly", "twists swiftly" }),\ +({ "lunge quickly", "lunges quickly" }),\ +({ "duck", "ducks" }),\ +({ "move fast", "moves fast" }),\ +({ "strike rapidly", "strikes rapidly" }),\ +({ "sidestep", "sidesteps" }),\ +({ "gyrate briskly", "gyrates briskly" }),\ +({ "whirl around quickly", "whirls around quickly" }),\ +({ "whirl blurringly", "whirls blurringly" }),\ +}) + +#endif + + +#define BLADE_DEGREES ({\ +({\ +({ "prick", "pricks" }),\ +({ "lightly", "superficially", "just barely" })\ +}),\ +({\ +({ "scratch", "scratches" }),\ +({ "mildly", "barely", })\ +}),\ +({\ +({ "jab", "jabs" }),\ +({ "quickly", "meanly", })\ +}),\ +({\ +({ "cut", "cuts" }),\ +({ "painfully" }),\ +}),\ +({\ +({ "slice", "slices" }),\ +({ "deeply" }),\ +}),\ +({\ +({ "pierce", "pierces" }),\ +({ "wickedly" }),\ +}),\ +({\ +({ "slash", "slashes" }),\ +({ "expertly" }),\ +}),\ +({\ +({ "stab", "stabs" }),\ +({ "fiercely" }),\ +}),\ +({\ +({ "carve", "carves" }),\ +({ "to pieces" }),\ +}),\ +({\ +({ "cleave", "cleaves" }),\ +({ "cruelly" }),\ +}),\ +({\ +({ "wound", "wounds" }),\ +({ "greviously" }),\ +}),\ +({\ +({ "devastate", "devastates" }),\ +({ "completely" }),\ +}),\ +({\ +({ "destroy", "destroys" }),\ +({ "utterly", }),\ +}),\ +}) + +#define PROJECTILE_DEGREES ({\ +({\ +({ "prick", "pricks" }),\ +({ "lightly", "superficially", "just barely" })\ +}),\ +({\ +({ "scratch", "scratches" }),\ +({ "mildly", "barely", }),\ +}),\ +({\ +({ "graze", "grazes" }),\ +({ "sharply" }),\ +}),\ +({\ +({ "gash", "gashes" }),\ +({ "deeply" }),\ +}),\ +({\ +({ "tear", "tears" }),\ +({ "painfully" }),\ +}),\ +({\ +({ "pierce", "pierces" }),\ +({ "wickedly" }),\ +}),\ +({\ +({ "shear", "shears" }),\ +({ "to ribbons" }),\ +}),\ +({\ +({ "puncture", "punctures" }),\ +({ "deeply", "with a quick thrust" }),\ +}),\ +({\ +({ "rip", "rips" }),\ +({ "apart", "to pieces" }),\ +}),\ +({\ +({ "impale", "impales" }),\ +({ "without mercy" }),\ +}),\ +({\ +({ "wound", "wounds" }),\ +({ "greviously" }),\ +}),\ +({\ +({ "devastate", "devastates" }),\ +({ "completely" }),\ +}),\ +({\ +({ "destroy", "destroys" }),\ +({ "utterly" }),\ +}),\ +}) + +#define BLUNT_DEGREES ({\ +({\ +({ "brush", "brushes" }),\ +({ "lightly", "softly", "with little force" }),\ +}),\ +({\ +({ "bruise", "bruises" }),\ +({ "mildly" }),\ +}),\ +({\ +({ "hit", "hits" }),\ +({ "hard" }),\ +}),\ +({\ +({ "pound", "pounds" }),\ +({ "solidly" }),\ +}),\ +({\ +({ "hammer", "hammers" }),\ +({ "painfully" }),\ +}),\ +({\ +({ "pummel", "pummels" }),\ +({ "soundly" }),\ +}),\ +({\ +({ "thrash", "thrashes" }),\ +({ "viciously" }),\ +}),\ +({\ +({ "smash", "smashes" }),\ +({ "forcefully" }),\ +}),\ +({\ +({ "crush", "crushes" }),\ +({ "violently" }),\ +}),\ +({\ +({ "slam", "slams" }),\ +({ "powerfully" }),\ +}),\ +({\ +({ "wound", "wounds" }),\ +({ "greviously" }),\ +}),\ +({\ +({ "devastate", "devastates", }),\ +({ "completely" }),\ +}),\ +({\ +({ "destroy", "destroys" }),\ +({ "utterly" }),\ +}),\ +}) diff --git a/lib/include/damage_types.h b/lib/include/damage_types.h new file mode 100644 index 0000000..0a297cb --- /dev/null +++ b/lib/include/damage_types.h @@ -0,0 +1,37 @@ +#ifndef s_damage_types_h +#define s_damage_types_h + +#define BLUNT (1 << 1) +#define BLADE (1 << 2) +#define KNIFE (1 << 3) +#define WATER (1 << 4) +#define SHOCK (1 << 5) +#define COLD (1 << 6) +#define HEAT (1 << 7) +#define GAS (1 << 8) +#define ACID (1 << 9) +#define MAGIC (1 << 10) +#define POISON (1 << 11) +#define DISEASE (1 << 12) +#define TRAUMA (1 << 13) +#define PIERCE (1 << 14) +#define PSIONIC (1 << 15) +#define ANOXIA (1 << 16) +#define DEATHRAY (1 << 17) +#define EMOTIONAL (1 << 18) +#define SONIC (1 << 19) +#define EMP (1 << 20) +#define OTHER (1 << 21) +#define KARMA (1 << 22) +#define DRAMA (1 << 23) +#define OVERPRESSURE (1 << 24) +#define UNDERPRESSURE (1 << 25) +#define INERTIA (1 << 26) + +#define MAX_DAMAGE_BIT INERTIA + +#define ALL_DAMAGE BLUNT | BLADE | KNIFE | WATER | SHOCK | COLD | HEAT | GAS | ACID | MAGIC | POISON | DISEASE | TRAUMA | PIERCE | PSIONIC | ANOXIA | DEATHRAY | EMOTIONAL | SONIC | EMP | OTHER | KARMA | DRAMA | OVERPRESSURE | UNDERPRESSURE | INERTIA +#define BITE BLUNT | PIERCE +#define ALL_EXTERNAL_DAMAGE BLUNT | BLADE | KNIFE | WATER | SHOCK | COLD | HEAT | GAS | ACID | MAGIC | POISON | DISEASE | TRAUMA | PIERCE | DEATHRAY | SONIC | EMP | OVERPRESSURE | UNDERPRESSURE + +#endif /* s_damage_types_h */ diff --git a/lib/include/gossip.h b/lib/include/gossip.h new file mode 100644 index 0000000..7e54436 --- /dev/null +++ b/lib/include/gossip.h @@ -0,0 +1,22 @@ +#ifndef s_gossip_h +#define s_gossip_h + +class gossip_post { + int Follows; + int Date; + int Thread; + string Topic; + string Poster; + string Message; +} + +class gossip_group { + int NextPost; + int NextThread; + string SourceMud; + string Feed; + string Group; + mapping Posts; +} + +#endif /* s_gossip_h */ diff --git a/lib/include/graphics.h b/lib/include/graphics.h new file mode 100644 index 0000000..6f3a279 --- /dev/null +++ b/lib/include/graphics.h @@ -0,0 +1,12 @@ +#ifndef s_graphics_h +#define s_graphics_h + +/* MessageBox() arguments and return values */ +#define CB_OK (1 << 1) +#define CB_YES (1 << 2) +#define CB_NO (1 << 3) +#define CB_CANCEL (1 << 4) +#define CB_YESNO (CB_YES | CB_NO) +#define CB_YESNOCANCEL (CB_YES | CB_NO | CB_CANCEL) + +#endif /* s_graphics_h */ diff --git a/lib/include/jump.h b/lib/include/jump.h new file mode 100644 index 0000000..751d0d1 --- /dev/null +++ b/lib/include/jump.h @@ -0,0 +1,10 @@ +#ifndef s_jump_h +#define s_jump_h + +#define JUMP_INTO 1 +#define JUMP_FROM 2 +#define JUMP_THROUGH 3 +#define JUMP_OVER 4 +#define JUMP_ON 5 + +#endif /* s_jump_h */ diff --git a/lib/include/magic.h b/lib/include/magic.h new file mode 100644 index 0000000..037a4df --- /dev/null +++ b/lib/include/magic.h @@ -0,0 +1,12 @@ +#ifndef s_magic_h +#define s_magic_h + +#define SPELL_HEALING 1 +#define SPELL_DEFENSE 2 +#define SPELL_COMBAT 3 +#define SPELL_OTHER 4 + +#endif // s_magic_h + + + diff --git a/lib/include/magic_protection.h b/lib/include/magic_protection.h new file mode 100644 index 0000000..305ffb2 --- /dev/null +++ b/lib/include/magic_protection.h @@ -0,0 +1,65 @@ +/**************************************************** + + /include/magic_protection.h + created by Blitz@Dead Souls + +passed class to AddMagicProtection() + int bits Define what damage bits this magic + protection supports. + + + int absorb If defined, damage is absorbed and + subtracted from this total, until + max damage is < 1, or destroyed. + or, + + int protect This is an alternative to "absorb". + Instead of absorbing damage as above, + a random amount of this can be subtracted + from damage done, this lasts until "time" + has run out. + + int time This is decremented each heart beat. + Note if this is not defined and + "absorb damage" is defined, protection + is indefinite until destroyed. + + optional: + + function end If this is defined, it is evaluated + when protection is removed. + + function hit If this is defined, it is evaluated + anytime protection takes damage + or damage is reduced + + mixed args Used with the above hit function. + This is passed as the last argument + to the hit function + + object ob Pointer to the object that defined + the protection. + + string obname The file_name() of the object that + defined the protection. + + string name Some user-ready name of the protection, + such as "magical buffer" +} + +*********************************************************/ + +class MagicProtection { + int bits; + int absorb; + int protect; + int time; + int timestamp; + function end; + function hit; + mixed args; + object caster; + object ob; + string obname; + string name; +} diff --git a/lib/include/marriage.h b/lib/include/marriage.h new file mode 100644 index 0000000..6a972d6 --- /dev/null +++ b/lib/include/marriage.h @@ -0,0 +1,11 @@ +#ifndef s_marriage_h +#define s_marriage_h + +class marriage { + int WeddingDate; + int DivorceDate; + string Spouse; + string Location; +} + +#endif /* s_marriage_h */ diff --git a/lib/include/materials.h b/lib/include/materials.h new file mode 100644 index 0000000..a45011e --- /dev/null +++ b/lib/include/materials.h @@ -0,0 +1,2 @@ +#define MATERIAL_PROPS ({ "density","hardness" }) +#define MATERIAL_TYPES ({ "fluid","stone","metal","wood","misc" }) diff --git a/lib/include/meal_types.h b/lib/include/meal_types.h new file mode 100644 index 0000000..5f41706 --- /dev/null +++ b/lib/include/meal_types.h @@ -0,0 +1,10 @@ +#ifndef __MEAL_TYPES_H__ +#define __MEAL_TYPES_H__ + +#define MEAL_FOOD (1<<1) +#define MEAL_DRINK (1<<2) +#define MEAL_CAFFEINE (1<<3) +#define MEAL_ALCOHOL (1<<4) +#define MEAL_POISON (1<<5) + +#endif /* __MEAL_TYPES_H__ */ diff --git a/lib/include/medium.h b/lib/include/medium.h new file mode 100644 index 0000000..1e66099 --- /dev/null +++ b/lib/include/medium.h @@ -0,0 +1,11 @@ +#ifndef s_medium_h +#define s_medium_h + +#define MEDIUM_LAND 1 +#define MEDIUM_AIR 2 +#define MEDIUM_SURFACE 3 +#define MEDIUM_SPACE 4 +#define MEDIUM_WATER 5 +#define MEDIUM_METHANE 6 + +#endif /* s_medium_h */ diff --git a/lib/include/message_class.h b/lib/include/message_class.h new file mode 100644 index 0000000..6583fb9 --- /dev/null +++ b/lib/include/message_class.h @@ -0,0 +1,39 @@ +#ifndef s_message_class_h +#define s_message_class_h + +#define MSG_NOBLOCK (1 << 0) /* no blocking */ +#define MSG_NOCOLOUR (1 << 1) /* no colours */ +#define MSG_NOWRAP (1 << 2) /* don't wrap this message */ + +#define MSG_CONV (1 << 3) /* conversation */ +#define MSG_EDIT ((1 << 4) | MSG_NOBLOCK | MSG_NOCOLOUR | MSG_NOWRAP) + /* editor */ +#define MSG_ENV (1 << 5) /* general stuff */ +#define MSG_ERROR ((1 << 6) | MSG_NOBLOCK) /* error messages */ +#define MSG_HELP ((1 << 7) | MSG_NOBLOCK) /* help messages */ +#define MSG_ROOMDESC ((1 << 8) | MSG_NOBLOCK) /* room descs */ +#define MSG_PROMPT ((1 << 9) | MSG_NOBLOCK | MSG_NOWRAP) /* prompts */ +#define MSG_SYSTEM ((1 << 10) | MSG_NOBLOCK) /* sys messages */ + +/* client specific messages */ +#define MSG_LOGIN (1 << 11) /* prot. neg. for login */ +#define MSG_MSG_BOX (1 << 12) /* display msg box */ +#define MSG_QUERY (1 << 13) /* response to client */ + +#define MSG_CHAN (1 << 14) +#define MSG_FTP (1 << 15) +#define MSG_HTTP (1 << 16) +#define MSG_RCP (1 << 17) +#define MSG_I3 (1 << 18) +#define MSG_HFTP (1 << 19) +#define MSG_OOB (1 << 20) +#define MSG_ANNOYING (1 << 21) +#define MSG_RECEIVE (1 << 22) /* skip the line feed */ + + +/* client command types */ +#define CMD_LOGIN (1 << 0) /* login */ +#define CMD_USER (1 << 1) /* normal user cmds */ +#define CMD_QUERY (1 << 2) /* client query */ + +#endif /* s_message_class_h */ diff --git a/lib/include/motion.h b/lib/include/motion.h new file mode 100644 index 0000000..accd1bf --- /dev/null +++ b/lib/include/motion.h @@ -0,0 +1,9 @@ +#ifndef __MOTION_H__ +#define __MOTION_H__ + +#define M_LAND 1 +#define M_AIR 2 +#define M_SEA 3 +#define M_MAGIC 4 + +#endif __MOTION_H__ diff --git a/lib/include/mouth_types.h b/lib/include/mouth_types.h new file mode 100644 index 0000000..510c53b --- /dev/null +++ b/lib/include/mouth_types.h @@ -0,0 +1,21 @@ +#ifndef __MOUTH_TYPES__ +#define __MOUTH_TYPES__ + +#define MOUTH_NONE (1 << 0) +#define MOUTH_LIPPED (1 << 1) +#define MOUTH_TOOTHED (1 << 2) +#define MOUTH_BEAKED (1 << 3) +#define MOUTH_MANDIBLED (1 << 4) +#define MOUTH_BALEEN (1 << 5) +#define MOUTH_TONGUED (1 << 6) +#define MOUTH_FANGED (1 << 7) +#define MOUTH_VENOMOUS (1 << 8) +#define MOUTH_DISEASED (1 << 9) +#define MOUTH_STATIC (1 << 10) +#define MOUTH_TUSKED (1 << 11) + +#define MOUTH_HUMANOID (MOUTH_LIPPED | MOUTH_TOOTHED | MOUTH_TONGUED ) + +#define MAX_MOUTH_BIT MOUTH_TUSKED + +#endif /* __MOUTH_TYPES_H__ */ diff --git a/lib/include/position.h b/lib/include/position.h new file mode 100644 index 0000000..6da0635 --- /dev/null +++ b/lib/include/position.h @@ -0,0 +1,13 @@ +#ifndef s_position_h +#define s_position_h + +#define POSITION_NULL (1 << 0) +#define POSITION_STANDING (1 << 1) +#define POSITION_SITTING (1 << 2) +#define POSITION_LYING (1 << 3) +#define POSITION_FLYING (1 << 4) +#define POSITION_KNEELING (1 << 5) +#define POSITION_FLOATING (1 << 6) +#define POSITION_SWIMMING (1 << 7) + +#endif /* s_position_h */ diff --git a/lib/include/race.h b/lib/include/race.h new file mode 100644 index 0000000..2e7837f --- /dev/null +++ b/lib/include/race.h @@ -0,0 +1,14 @@ +#ifndef s_race_h +#define s_race_h + +class stat_cfg { + int Base; + int Class; +} + +class race_cfg { + int Fingers; + mapping Stats; +} + +#endif /* s_race_h */ diff --git a/lib/include/respiration_types.h b/lib/include/respiration_types.h new file mode 100644 index 0000000..92338c1 --- /dev/null +++ b/lib/include/respiration_types.h @@ -0,0 +1,11 @@ +#ifndef __RESPIRATION_TYPES__ +#define __RESPIRATION_TYPES__ + +#define R_AIR (1 << 0) +#define R_WATER (1 << 1) +#define R_VACUUM (1 << 2) +#define R_METHANE (1 << 3) + +#define MAX_RESPIRATION_BIT R_METHANE + +#endif /* __RESPIRATION_TYPES_H__ */ diff --git a/lib/include/rounds.h b/lib/include/rounds.h new file mode 100644 index 0000000..b74685e --- /dev/null +++ b/lib/include/rounds.h @@ -0,0 +1,12 @@ +#ifndef __ROUNDS_H__ +#define __ROUNDS_H__ + +#define ROUND_UNDEFINED 0 +#define ROUND_MELEE 1 +#define ROUND_WEAPON 2 +#define ROUND_MAGIC 3 +#define ROUND_OTHER 4 +#define ROUND_INTERNAL 5 +#define ROUND_EXTERNAL 6 + +#endif /* __ROUNDS_H__ */ diff --git a/lib/include/size_types.h b/lib/include/size_types.h new file mode 100644 index 0000000..ce96910 --- /dev/null +++ b/lib/include/size_types.h @@ -0,0 +1,13 @@ +#define S_MICROSCOPIC (1 << 0) +#define S_MINISCULE (1 << 1) +#define S_TINY (1 << 2) +#define S_VERY_SMALL (1 << 3) +#define S_SMALL (1 << 4) +#define S_SOMEWHAT_SMALL (1 << 5) +#define S_HUMAN_SIZED (1 << 6) +#define S_SOMEWHAT_LARGE (1 << 7) +#define S_LARGE (1 << 8) +#define S_HUGE (1 << 9) +#define S_GIGANTIC (1 << 10) +#define S_VAST (1 << 11) +#define S_MAX_SIZE_BIT S_VAST diff --git a/lib/include/soul.h b/lib/include/soul.h new file mode 100644 index 0000000..b14280e --- /dev/null +++ b/lib/include/soul.h @@ -0,0 +1,18 @@ +#ifndef s_soul_h +#define s_soul_h + +#define Targeted 1 +#define NoTarget 2 +#define NoArgs 3 +#define ForceAdverb 4 +#define ExtraAdverbs 5 +#define Locations 6 +#define ForceLocation 7 +#define Preposition 8 +#define DisableAnd 9 + +#define SaveFile "/daemon/soul/soul" +#define FallBackFile "/daemon/soul/default.c" +#define SOUL_ADVERBS "/daemon/adverbs" + +#endif /* s_soul_h */ diff --git a/lib/include/stargate.h b/lib/include/stargate.h new file mode 100644 index 0000000..df1d187 --- /dev/null +++ b/lib/include/stargate.h @@ -0,0 +1,20 @@ +/** + * + * $Id: stargate.h,v 1.1 2006/04/05 05:48:39 jam Exp $ + * + */ + +#ifndef stargate_h +#define stargate_h + +#define GATE_TIMEOUT (10+random(5)) + +// address (i.e. "sgc") is a key in a mapping in the stargate daemon so it is not included here +class stargate +{ + string status; + string destination; + string endpoint; +} + +#endif diff --git a/lib/include/talk_type.h b/lib/include/talk_type.h new file mode 100644 index 0000000..16a9a1f --- /dev/null +++ b/lib/include/talk_type.h @@ -0,0 +1,11 @@ +#ifndef s_talk_type_h +#define s_talk_type_h + +#define TALK_VOID 0 +#define TALK_PRIVATE 1 +#define TALK_SEMI_PRIVATE 2 +#define TALK_LOCAL 3 +#define TALK_AREA 4 +#define TALK_WORLD 5 + +#endif /* s_talk_type_h */ diff --git a/lib/include/terrain_types.h b/lib/include/terrain_types.h new file mode 100644 index 0000000..4c6afe5 --- /dev/null +++ b/lib/include/terrain_types.h @@ -0,0 +1,30 @@ +#ifndef __TERRAIN_TYPES_H__ +#define __TERRAIN_TYPES_H__ + +#define T_CUSTOM (1 << 0) +#define T_OUTDOORS (1 << 1) +#define T_INDOORS (1 << 2) +#define T_ROAD (1 << 3) +#define T_UNDERWATER (1 << 4) +#define T_SURFACE (1 << 5) +#define T_MIDAIR (1 << 6) +#define T_SWAMP (1 << 7) +#define T_WOODS (1 << 8) +#define T_JUNGLE (1 << 9) +#define T_ROUGH (1 << 10) +#define T_UNDERGROUND (1 << 11) +#define T_SPACE (1 << 12) +#define T_MAGMA (1 << 13) +#define T_PLASMA (1 << 14) +#define T_PLANAR (1 << 15) +#define T_SNOW (1 << 16) +#define T_SAND (1 << 17) +#define T_ICE (1 << 18) +#define T_BIOLOGICAL (1 << 19) +#define T_SEAFLOOR (1 << 20) +#define T_ALL_OUTDOORS_LAND T_OUTDOORS | T_ROAD | T_SWAMP | T_WOODS | T_JUNGLE | T_ROUGH | T_SNOW | T_SAND | T_ICE +#define T_ALL_SEA T_SEAFLOOR | T_UNDERWATER | T_SURFACE + +#define T_MAX_TERRAIN_BIT T_SEAFLOOR + +#endif /* __TERRAIN_TYPES_H__ */ diff --git a/lib/include/vendor_types.h b/lib/include/vendor_types.h new file mode 100644 index 0000000..7250db0 --- /dev/null +++ b/lib/include/vendor_types.h @@ -0,0 +1,20 @@ +#ifndef s_vendor_types_h +#define s_vendor_types_h + +#define VT_TREASURE (1 << 1) +#define VT_WEAPON (1 << 2) +#define VT_ARMOR (1 << 3) +#define VT_LIGHT (1 << 4) +#define VT_FOOD (1 << 5) +#define VT_DRINK (1 << 6) +#define VT_MAGIC (1 << 7) +#define VT_FISHING (1 << 8) +#define VT_PLANT (1 << 9) +#define VT_HERB (1 << 10) +#define VT_CONTRABAND (1 << 11) + +#define MAX_VENDOR_BIT VT_CONTRABAND + +#define VT_ALL VT_TREASURE | VT_WEAPON | VT_ARMOR | VT_LIGHT | VT_FOOD | VT_DRINK | VT_MAGIC | VT_FISHING | VT_PLANT | VT_HERB | VT_CONTRABAND + +#endif /* s_vendor_types_h */ diff --git a/lib/include/vision.h b/lib/include/vision.h new file mode 100644 index 0000000..7f0b090 --- /dev/null +++ b/lib/include/vision.h @@ -0,0 +1,13 @@ +#ifndef s_vision_h +#define s_vision_h + +#define VISION_BLIND 0 +#define VISION_TOO_DARK 1 +#define VISION_DARK 2 +#define VISION_DIM 3 +#define VISION_CLEAR 4 +#define VISION_LIGHT 5 +#define VISION_BRIGHT 6 +#define VISION_TOO_BRIGHT 7 + +#endif /* s_vision_h */ diff --git a/lib/lib/bank.c b/lib/lib/bank.c new file mode 100644 index 0000000..1f2f6f1 --- /dev/null +++ b/lib/lib/bank.c @@ -0,0 +1,32 @@ +#include <lib.h> + +inherit LIB_ROOM; + +static void create(){ + room::create(); +} + +mixed teller_check(){ + object *livs = get_livings(this_object()); + object teller; + if(sizeof(livs)) + foreach(object liv in livs){ + if(inherits(LIB_TELLER,liv)) return liv; + } + return 0; +} + +void init(){ + ::init(); + add_action("HandleTeller","deposit"); + add_action("HandleTeller","withdraw"); + add_action("HandleTeller","exchange"); + add_action("HandleTeller","balance"); +} + +int HandleTeller(string str){ + object teller = teller_check(); + if(!teller) return 0; + teller->cmdParse(this_player(),query_verb(),str); + return 1; +} diff --git a/lib/lib/base_trainer.c b/lib/lib/base_trainer.c new file mode 100644 index 0000000..1fbe79c --- /dev/null +++ b/lib/lib/base_trainer.c @@ -0,0 +1,253 @@ +/* /lib/trainer.c + * from the Dead Souls Library + * created 960320 by Blitz@Dead Souls + * Version: @(#) trainer.c 1.3@(#) + * Last modified: 96/10/28 + */ + +#include <lib.h> +#include <daemons.h> +#include "include/trainer.h" + +private string array TrainingSkills; +private mapping Students; +int NoSpells = 0; +private static object me; + +/**** driver applies ****/ + +void create(){ + me = this_object();; + TrainingSkills = ({}); + Students = ([]); + me->SetNoClean(1); + me->SetCommandResponses( ([ + "train" : (: eventTrain :), + "teach" : (: eventTrain :), + "default" : (: eventHelp :), + "help" : (: eventHelp :), + ]) ); + me->SetRequestResponses( ([ + "help" : (: eventHelp :), + ]) ); +} + +static void init(){ + string str; + if( !living(this_player()) ) return; + str = this_player()->GetKeyName(); + if( Students[str] ){ + me->eventForce("speak You will have to start your " + "studies anew, "+this_player()->GetName()); + map_delete(Students, str); + } +} + +int SetNoSpells(int i){ + if(i) NoSpells = 1; + else NoSpells = 0; + return NoSpells; +} + +int GetNoSpells(){ + return NoSpells; +} + +/**** data manipulation ****/ + +mixed AddTrainingSkills(string *args){ + if( !args ) + error("Bad argument 1 to AddTrainingSkills."); + return (TrainingSkills = distinct_array(TrainingSkills + args)); +} + +mixed RemoveTrainingSkills(string *args){ + if( !args || !arrayp(args) ) + error("Bad argument 1 to RemoveTrainingSkills."); + TrainingSkills -= args; + return TrainingSkills; +} + +string array GetTrainingSkills(){ return copy(TrainingSkills); } + +string Expertise(){ + string tmp, expertises; + string expertises2 = ""; + mapping spellbook = me->GetSpellBook(); + + if(!sizeof(GetTrainingSkills())) return "none"; + else if(sizeof(GetTrainingSkills()) == 1){ + return GetTrainingSkills()[0]; + } + expertises = implode(GetTrainingSkills(), ", "); + if(sizeof(GetTrainingSkills()) == 2){ + expertises = replace_string(expertises,", "," and "); + } + else if(sizeof(GetTrainingSkills()) > 2){ + tmp = last_string_element(expertises,","); + expertises = replace_string(expertises, tmp, " and"+tmp); + } + + if(sizeof(spellbook) && !GetNoSpells()){ + expertises2 = implode(keys(spellbook), ", "); + if(sizeof(spellbook) == 1) expertises2 = replace_string(expertises2,", ","."); + else if(sizeof(spellbook) == 2){ + expertises2 = replace_string(expertises2,", "," and ",1); + expertises2 = replace_string(expertises2,", ","."); + } + else { + tmp = last_string_element(expertises2,","); + expertises2 = replace_string(expertises2,tmp," and"+tmp); + } + expertises2 = ". In terms of spells, I can teach you "+expertises2; + } + + return expertises + expertises2; +} + +mapping GetStudents(){ return copy(Students); } + +/**** high-level events ****/ + +int eventHelp(object who, string unused){ + if(who) me->eventForce("speak I am not sure of what you are " + "asking, " + who->GetName() + "."); + if(sizeof( GetTrainingSkills() )){ + me->eventForce("speak My area of training expertise covers " + + Expertise() + "."); + me->eventForce("speak You can \"ask "+me->GetKeyName()+" to train " + "<SKILL>\" if you have training points."); + if(sizeof(me->GetSpellBook()) && !GetNoSpells()){ + me->eventForce("speak You can also \"ask "+me->GetKeyName()+ + " to teach <SPELL>.\""); + } + } + return 1; +} + +int eventTrain(object who, string verb, string skill){ + mixed *langs; + int ok; + if( !who || environment(who) != environment() ){ + return 0; + } + langs = this_object()->GetLanguages(); + foreach(string lang in langs){ + if(who->GetLanguageLevel(lang) >= 95){ + ok = 1; + me->SetDefaultLanguage(lang); + break; + } + } + if(!ok){ + write("You must be fluent in one of "+me->GetName()+ + " languages in order to understand "+possessive(me)+ + " training."); + return 1; + } + if( !sizeof(skill) || !sizeof(verb) ) return eventHelp(who, 0); + if(first(skill, 3) == "in ") skill = replace_string(skill,"in ","",1); + if(first(skill, 6) == "me in ") skill = replace_string(skill,"me in ","",1); + + if( verb == "teach"){ + object ob = SPELLS_D->GetSpell(skill); + + if(!sizeof(me->GetSpellBook()) || me->GetNoSpells()){ + me->eventForce("speak I am not able to teach spells. I only train skills."); + me->eventHelp(); + return 0; + } + if(!ob){ + me->eventForce("speak I've never heard of such a spell."); + return 0; + } + + if( !who->eventLearnSpell(skill) ){ + me->eventForce("speak You are not prepared for that spell!"); + return 0; + } + + who->eventPrint(me->GetName() + " touches your forehead and gives " + "you knowledge of " + skill + "."); + environment()->eventPrint(me->GetName() + " touches " + + possessive_noun(who) + + " forehead and gives " + + objective(who) + " knowledge of " + + skill + ".", who); + return 1; + } + + if(skill) skill = lower_case(skill); + + if( Students[ who->GetKeyName() ] ){ + me->eventForce("speak I am already training you!"); + return 0; + } + if( member_array(skill, me->GetTrainingSkills()) == -1 ){ + me->eventHelp(); + return 0; + } + if( member_array(skill, + this_player()->GetSkills() ) == -1 ){ + me->eventForce("speak You do not appear to be the type " + "who would be skilled in " + skill + "!"); + me->eventForce("speak I cannot train you in a skill you don't know at all. You may need to join a guild or a class that enables you to train in this skill."); + return 0; + } + if( this_player()->GetTrainingPoints() < 1 ){ + me->eventForce("speak You need more training points!"); + return 0; + } + Students[ who->GetKeyName() ] = skill; + eventStart(who, skill); + call_out((: ContinueTraining, who, skill, 0 :), TRAINING_WAIT); + return 1; +} + +static int ContinueTraining(object who, string skill, int x){ + if( !who || !Students[who->GetKeyName()] ) return 0; + if( !present(who, environment()) || + member_array(who, this_object()->GetEnemies()) != -1){ + map_delete(Students, who->GetKeyName()); + return 0; + } + if( x > 4 ){ + map_delete(Students, who->GetKeyName()); + eventComplete(who, skill); + who->eventTrain(skill, 1); + return 1; + } else { + eventContinue(who, skill, ++x); + call_out((: ContinueTraining, who, skill, x :), TRAINING_WAIT); + return 1; + } +} + +/**** message handling events ****/ + +/* The three following events are purely *aesthetic*, + * Hopefully prolific coders will override them for + * more interesting training techniques. :) + */ + +int eventStart(object who, string skill){ + who->eventPrint(me->GetName() + " begins teaching you " + "about the skill of " + skill + "."); + environment()->eventPrint(me->GetName() + " begins teaching " + + who->GetName() + "...", who); + return 1; +} + +int eventContinue(object who, string skill, int x){ + who->eventPrint("You listen intently as " + me->GetName() + + " continues " + possessive(me) + + " dissertation on " + skill + "."); + return 1; +} + +int eventComplete(object who, string skill){ + who->eventPrint("You feel more adept with your " + skill + "."); + me->eventForce("speak I can teach you no more for now, " + + who->GetName() + "."); + return 1; +} diff --git a/lib/lib/battery.c b/lib/lib/battery.c new file mode 100644 index 0000000..5a10d36 --- /dev/null +++ b/lib/lib/battery.c @@ -0,0 +1,99 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +private int charge,rechargeable, drainable,drainrate,fullcharge; +private string powertype,celltype; + +int Spent(){ + string *tmp; + if(rechargeable == 1) return 1; + if(!charge || charge <= 0){ + charge = 0; + SetShort("a spent power cell"); + tmp = GetAdjectives(); + tmp += ({"spent", "empty", "drained", "used"}); + SetAdjectives(tmp); + } + return 1; +} + + +void create(){ + ::create(); + AddSave( ({ "charge" }) ); + SetKeyName("cell"); + SetId(({"battery"})); + SetAdjectives(({"power","generic"})); + SetShort("a generic power cell"); + SetLong("This is a generic power cell."); + SetMass(1); + SetBaseCost(4); + SetVendorType(VT_TREASURE); + rechargeable=0; + drainable = 1; + drainrate = 1; + Spent(); +} + +void init(){ + ::init(); + if(living(environment(this_object())) ) this_object()->eventUse(0); + if( charge < 200 ) SetBaseCost(0); + Spent(); +} + +int SetPowerType(string str){powertype=str; return 1; } +int SetCellType(string str){celltype=str; return 1; } +int SetCharge(int i){charge = i; fullcharge = i; return 1; } +int GetCharge(){ return charge; } +string GetPowerType(){ return powertype; } +string GetCellType(){ return celltype; } +int SetRechargeable(int i){ rechargeable = i; return i;} +int GetRechargeable(){ return rechargeable;} +int SetDrainable(int i){ drainable = i; return i; } +int GetDrainable(){ return drainable; } +int SetDrainRate(int i){ drainrate = i; return i; } +int GetDrainRate(){ return drainrate; } + + +int ModCharge(int i){ + if(!charge) charge = 0; + if(i) charge += i; + return charge; +} + +int eventDrain(int i){ + if( drainable != 1 ) return 0; + if(!charge) charge = 0; + if(charge && charge > 0) charge -= i; + if(charge && charge < 0) Spent(); + if(!charge) Spent(); + if( charge < 200 ) SetBaseCost(0); + return charge; +} + +int eventCharge(int i){ + if(!charge) charge =0; + if(i) charge += i; + return charge; +} + +int eventUse(int i){ + if(query_verb() == "use"){ + write("That's not how it works."); + return 1; + } + if(i == 0){ + set_heart_beat(0); + return 1; + } + if(!drainable) drainable = 1; + if(drainable && drainable == 0) drainrate = 0; + else if(!drainable) drainable = 1; + if( !i || !intp(i) ) i = drainrate; + set_heart_beat(i); +} + +void heart_beat(){ + eventDrain(GetDrainRate() || 1); +} diff --git a/lib/lib/bboard.c b/lib/lib/bboard.c new file mode 100644 index 0000000..7ac9d33 --- /dev/null +++ b/lib/lib/bboard.c @@ -0,0 +1,300 @@ +/* /lib/bboard.c + * from Nightmare 3.3 + * the Dead Souls bulletin board system + * created by Descartes of Borg 940920 + */ + +#include <lib.h> +#include <daemons.h> +#include "include/bboard.h" + +inherit LIB_ITEM; + +static private string tmpdir; +static private string __BoardID; +static private string *__EditOK; +static string gstr, gfile, gdude; +string Location; + +void create(){ + string path; + item::create(); + SetNoClean(1); + SetId( ({ "board", "message board" }) ); + SetLong("A board for reading and posting messages. To read the "+ + "first message: read 1\nTo post a message: post <message title>\n"); + SetPreventGet("You cannot get that!"); + SetPreventPut("You cannot put that in there!"); + SetPreventDrop("Drop a bulletin board?"); + SetNoCondition(1); + SetRead( (: GetLong :) ); + __EditOK = ({}); + path = base_name(this_object()); + if(!strsrch(path, "/secure/")) tmpdir = DIR_SECURE_TMP; + else tmpdir = DIR_TMP; +} + +void RegisterLocation(){ + object env = environment(); + if(!env) Location = 0; + else Location = base_name(env); + BBOARD_D->RegisterLocation(query_board_id(), Location); +} + +void init(){ + item::init(); + add_action("cmd_post", "post"); + add_action("cmd_read", "read"); + add_action("cmd_followup_and_respond", ({ "followup", "respond "})); + add_action("cmd_remove", "remove"); + add_action("cmd_edit", "edit"); + RegisterLocation(); +} + +static private int valid_edit(string author){ + string who = this_player()->GetKeyName(); + if(who == author) return 1; + if(archp(this_player())) return 1; + return 0; +} + +int cmd_post(string str){ + string file; + + if(!str) return notify_fail("You must specify a subject.\n"); + if(file_exists(file = tmpdir + "/" + this_player()->GetKeyName())){ + message("system", "You have an abandoned post waiting.",this_player()); + message("system", " e)dit it, or start n)ew", this_player()); + message("prompt", "\nCommand (default 'n'): ", this_player()); + input_to("begin_post", str, file, (: continue_post :)); + } + else { + write("When finished writing, enter a single period on a blank line, then "); + write("at the colon prompt (:) type a lower-case x and return.\n"); + write("Like this:\n.\nx\n"); + begin_post("n", str, file, (: continue_post :)); + } + return 1; +} + +static void begin_post(string cmd, string subj, string file, function f){ + if(cmd == "" || !cmd) cmd = "n"; + else cmd = cmd[0..0]; + if(cmd != "n" && cmd != "e"){ + message("system", "Invalid bulletin board command.", this_player()); + return; + } + if(cmd == "n" && file_exists(file)) rm(file); + (*f)(subj, file); +} + +void continue_post(string subj, string file){ + this_player()->eventEdit(file, (: end_post, subj, 0 :)); +} + +void end_post(string subj, string mail){ + string file, msg; + object env = room_environment(this_player()); + + file = tmpdir + "/" + this_player()->GetKeyName(); + if(!(msg = read_file(file))){ + message("system", "No file read!", this_player()); + if(file_exists(file)) rm(file); + return; + } + else rm(file); + if( !mail ) + BBOARD_D->add_post(query_board_id(), + this_player()->GetCapName(), subj, msg); + message("system", "Message posted!", this_player()); + tell_room(env, this_player()->GetName()+" posts on the board.", + ({ this_player() })); +} + +int cmd_read(string str){ + string junk; + mapping *posts; + int x, i, maxi; + object env = room_environment(this_player()); + + if(str){ + if(str == "board" || sscanf(str,"board %s",junk) ){ + write("To read the first post, type: read 1"); + write("To read the second one: read 2"); + write("And so on."); + return 1; + } + + maxi = sizeof(posts = BBOARD_D->query_posts(query_board_id())); + if(!str){ + for(i=0, x = -1; i<maxi; i++) + if(member_array(this_player()->GetKeyName(), + posts[i]["read"]) == -1){ + x = i; + break; + } + if(x == -1) return notify_fail("No unread posts.\n"); + } + else if(!(x = to_int(str))) return notify_fail("Read what?\n"); + else x--; + if(x < 0 || x >= sizeof(posts)) + return notify_fail("Invalid post number.\n"); + str = "Post #%^YELLOW%^" + (x+1) + "%^RESET%^ by %^YELLOW%^" + + posts[x]["author"] + "%^RESET%^\nSubject: %^CYAN%^" + + posts[x]["subject"] + "%^RESET%^\n\n"; + str += posts[x]["post"]; + + tell_room(env, this_player()->GetName()+" reads the board.", + ({ this_player() })); + BBOARD_D->mark_read(query_board_id(),x,this_player()->GetKeyName()); + this_player()->eventPage(explode(str, "\n"), "system"); + return 1; + } +} + +int cmd_followup_and_respond(string str){ + mapping post; + function f; + string file, verb; + int x; + + if(!str) return notify_fail(capitalize(verb=query_verb())+" which + post?\n"); + if((x=to_int(str)) < 1 || + x>BBOARD_D->query_number_posts(query_board_id())) + + return notify_fail("Invalid post number.\n"); + x--; + post = BBOARD_D->query_post(query_board_id(), x); + if((verb = query_verb()) == "respond") f = (: continue_mail, post :); + else f = (: continue_followup, post :); + str = post["subject"]; + if(!str) str = "Re: "+possessive_noun(post["author"])+" post"; + else if(strlen(str) <= 4 || str[0..3] != "Re: ") str = "Re: "+str; + if(file_exists(file = tmpdir + "/" + this_player()->GetKeyName())){ + message("system", "You have an abandoned post waiting.",this_player()); + message("system", " e)dit it, or start n)ew", this_player()); + message("prompt", "\nCommand (default 'n'): ", this_player()); + input_to("begin_post", str, file, f); + } + else begin_post("n", str, file, f); + return 1; +} + +void continue_followup(mapping post, string subj, string file){ + message("prompt", "\nInclude original text (default 'n'): ",this_player()); + input_to("check_include_text", subj, file, post, 0); +} + +void continue_mail(mapping post, string subj, string file){ + message("prompt", "\nInclude original text (default 'n'): ",this_player()); + input_to("check_include_text", subj, file, post, 1); +} + +static void check_include_text(string ans, string subj, string file, mapping + post, int mail){ + + string msg; + + if(ans == "" || !ans) ans = "n"; + else ans = ans[0..0]; + if(ans == "y"){ + msg = post["author"] + " once wrote...\n>"; + msg += implode(explode(post["post"], "\n"), "\n> ")+"\n"; + write_file(file, msg); + } + this_player()->eventEdit(file, (: end_post, subj, (mail ? post : 0) :)); +} + +int cmd_remove(string str){ + mapping post; + int x; + object env = room_environment(this_player()); + + if((x = to_int(str)) < 1 || + x > BBOARD_D->query_number_posts(query_board_id())) + return notify_fail("Invalid post number.\n"); + post = BBOARD_D->query_post(query_board_id(), x-1); + if(!valid_edit(convert_name(post["author"]))){ + write("You do not have permission to remove that!\n"); + return 1; + } + BBOARD_D->remove_post(query_board_id(), x-1); + message("system", "Post "+x+" removed.", this_player()); + tell_room(env, this_player()->GetName()+" removes a post from the board.", + ({ this_player() })); + return 1; +} + +int cmd_edit(string str){ + mapping post; + string file; + int x; + + if((x = to_int(str)) < 1 || + x > BBOARD_D->query_number_posts(query_board_id())) + return notify_fail("Invalid post number.\n"); + post = BBOARD_D->query_post(query_board_id(), x-1); + if(!valid_edit(convert_name(post["author"]))){ + write("You do not have permission to edit that post!\n"); + return 1; + } + file = tmpdir + "/" + this_player()->GetKeyName() + ".bb"; + gstr = post["post"]; + gfile = file; + unguarded( (: write_file(gfile, gstr, 1) :) ); + this_player()->edit(file, (: end_edit, post["subject"], x-1 :) ); + return 1; +} + +void end_edit(string subj, int num){ + string file, msg; + + file = tmpdir + "/" + this_player()->GetKeyName(); + if(!(msg = read_file(file))){ + message("system", "No file read!", this_player()); + return; + } + else rm(file); + BBOARD_D->remove_post(query_board_id(), num); + BBOARD_D->add_post(query_board_id(), + this_player()->GetCapName(), subj, msg); + message("system", "Message posted!", this_player()); +} + +string GetExternalDesc(){ + mapping *posts; + string msg; + int i, maxi; + + msg = item::GetExternalDesc(); + maxi = sizeof(posts = BBOARD_D->query_posts(query_board_id())); + msg += "\n"; + if(!maxi) msg += "There are currently no posts.\n"; + else for(i=0; i < maxi; i++){ + int lu; + + if(!this_player()) lu = 1; + else if(member_array(this_player()->GetKeyName(), + posts[i]["read"]) == -1) lu = 0; + else lu = 1; + msg += sprintf("[%:-3d] %s %:-17s \"%:-27s %s\n", + (i+1), (lu ? " " : "(new)"), posts[i]["author"]+":", + posts[i]["subject"]+"\"", query_board_time(posts[i]["time"])); + } + return msg; +} + +void set_board_id(string str){ __BoardID = str; } + +string query_board_id(){ return __BoardID; } + +string query_board_time(int x){ + string date, day, mon, year, hour, ret; + + if(sscanf(ctime(x), "%s %s %s %s %s", day, mon, date, hour, year) !=5) + sscanf(ctime(x), "%s %s %s %s %s", day, mon, date, hour, year); + + sscanf(hour, "%s:%s:%*s", hour, ret); + return(hour+ret+" "+day+" "+date+" "+mon); +} diff --git a/lib/lib/blank.c b/lib/lib/blank.c new file mode 100644 index 0000000..578ad97 --- /dev/null +++ b/lib/lib/blank.c @@ -0,0 +1 @@ +//This file intentionally left blank. diff --git a/lib/lib/blank_pile.c b/lib/lib/blank_pile.c new file mode 100644 index 0000000..ed19ab3 --- /dev/null +++ b/lib/lib/blank_pile.c @@ -0,0 +1,35 @@ +#include <lib.h> + +inherit LIB_PILE; + +static void create(){ + pile::create(); + SetKeyName("money"); +} + +string array GetId(){ + string array id; + + id = pile::GetId(); + if( PileType ){ + if(PileType != "dollars"){ + id += ({ PileType, PileAmount + " " + PileType +" coins"}); + return ({ id..., "money", "pile","coins","coin" }); + } + else { + id += ({ PileType, PileAmount + " " + PileType +" dollars"}); + return ({ id..., "money", "pile","bill","bills" }); + } + } +} + +string GetShort(){ + string sum; + if(!PileAmount) sum = "some"; + else sum = cardinal(PileAmount); + if(PileType != "dollars"){ + return sum + " " + PileType + " coins"; + } + else return sum + " " + PileType ; +} + diff --git a/lib/lib/body.c b/lib/lib/body.c new file mode 100644 index 0000000..26281db --- /dev/null +++ b/lib/lib/body.c @@ -0,0 +1,2093 @@ +/* /lib/body.c + * from the Dead Souls LPC Library + * handles information regarding bodies as well as events which + * affect them + * created by Descartes of Borg 950121 + * Version: @(#) body.c 1.24@(#) + */ + +#include <lib.h> +#include ROOMS_H +#include <daemons.h> +#include <function.h> +#include <medium.h> +#include <position.h> +#include <armor_types.h> +#include <respiration_types.h> +#include <terrain_types.h> +#include <damage_types.h> +#include <magic_protection.h> +#include "include/body.h" +#ifndef AUTO_ADVANCE +#define AUTO_ADVANCE 0 +#endif + +inherit LIB_POSITION; +inherit LIB_UNDEAD; +inherit LIB_CRAWL; +inherit LIB_FLY; +inherit LIB_SWIM; +inherit LIB_MOUNT; +inherit LIB_BODY_MASS; +inherit LIB_PERSIST; + +#define COLLAPSE_AT 5.0 +#ifndef SEVERABLE_LIMBS +#define SEVERABLE_LIMBS 1 +#endif + +private int HealthPoints, MagicPoints, ExperiencePoints, ExperienceDebt; +private int melee, godmode; +private int Alcohol, Caffeine, Food, Drink, Poison, Sleeping; +private float StaminaPoints; +private string Torso, Biter, keepalive; +private mapping Fingers, Limbs, MissingLimbs; +private static int Dying, LastHeal, Encumbrance, DeathEvents; +private static function Protect; +private static mapping WornItems; +private static class MagicProtection *Protection; +static private int HeartModifier = 0; +private static string PoliticalParty, BodyComposition; +private static int Pacifist, wearbit; +private static mapping Dimensions = ([]); +private int firearms_wounds, Falling, FallCount = 1; +string *ExtraChannels; +mixed Agent; + +string GetRace(); + +static void create(){ + PoliticalParty = "UNDECIDED"; + firearms_wounds = 0; + DeathEvents = 0; + NewBody(0); + Protect = 0; + WornItems = ([]); + Limbs = ([]); + Food = Drink = 100; + Alcohol = Caffeine = 0; + HealthPoints = MagicPoints = 50; + StaminaPoints = 50.0; + ExperiencePoints = 50; + ExperienceDebt = 0; + Dying = 0; + LastHeal = time(); + Protection = ({}); + ExtraChannels = ({}); + Dimensions = ([]); +} + +varargs mixed eventBuy(mixed arg1, mixed arg2, mixed arg3){ + //This function will hopefully get overridden where appropriate. + write(capitalize(this_object()->GetShort())+" isn't buying anything from you."); + return 1; +} + +int GetMass(){ + return body_mass::GetBodyMass(); +} + +int GetSize(int decimal){ + int i; + if(!decimal && !undefinedp(Dimensions["Size"])){ + return Dimensions["Size"]; + } + if(decimal && !undefinedp(Dimensions["SizeDecimal"])){ + return Dimensions["SizeDecimal"]; + } + Dimensions["Size"] = RACES_D->GetRaceSize(GetRace()); + if(!decimal){ + return Dimensions["Size"]; + } + i = 32; + while(i){ + i--; + if((1 << i) & Dimensions["Size"]){ + return (Dimensions["SizeDecimal"] = i); + } + } + return (Dimensions["SizeDecimal"] = i); +} + +int GetBodyType(){ + if(!undefinedp(Dimensions["BodyType"])){ + return Dimensions["BodyType"]; + } + return (Dimensions["BodyType"] = RACES_D->GetRaceBodyType(GetRace())); +} + +int SetMass(int i){ + return body_mass::SetBodyMass(i); +} + +int SetSize(int i){ + return Dimensions["Size"] = i; +} + +int SetBodyType(int i){ + return Dimensions["BodyType"] = i; +} + + +int GetEncumbrance(){ + int encumbrance = 0; + object *stuff = filter(all_inventory(this_object()), (: !($1->GetWorn()) :) ); + + if(!(ENABLE_ENCUMBRANCE) || inherits(LIB_NPC,this_object()) ) return encumbrance; + if(sizeof(stuff)) foreach(object item in stuff) + encumbrance += (item->GetMass())/2; + if(sizeof(stuff)) encumbrance += sizeof(stuff); + return encumbrance; +} + +string SetBodyComposition(string str){ + if(!str) return ""; + else BodyComposition = str; + return BodyComposition; +} + +string GetBodyComposition(){ + return BodyComposition; +} + +int GetPacifist(){ + return Pacifist; +} + +int SetPacifist(int i){ + if(!i) Pacifist = 0; + else Pacifist = 1; + return Pacifist; +} + +int SetCanBite(int i){ + if(i) Biter = "yes"; + else Biter = "no"; + return i; +} + +int GetCanBite(){ + if(sizeof(Biter)){ + if(Biter == "yes") return 1; + else return 0; + } + else return RACES_D->GetBitingRace(this_object()->GetRace()); +} + +string *AddExtraChannels(string *chans){ + foreach(string chan in chans){ + if(member_array(chan,this_player()->GetExtraChannels()) == -1){ + ExtraChannels += ({ chan }); + } + } + return ExtraChannels; +} + +string *RemoveExtraChannels(string *chans){ + foreach(string chan in chans){ + if(member_array(chan,this_player()->GetExtraChannels()) != -1){ + ExtraChannels -= ({ chan }); + } + } + return ExtraChannels; +} + +string *GetExtraChannels(){ + return ExtraChannels; +} + +string *SetExtraChannels(string *chans){ + ExtraChannels = chans; + return ExtraChannels; +} + +mixed direct_body_liv(){ + return 1; +} + +mixed direct_turn_liv(){ + if( GetUndead() ){ + return 1; + } + else { + return "You cannot turn the living!"; + } +} + +void eventCheckEnvironment(){ + object env = environment(); + int i, roomres, breathdam; + int restype; + float j,k; + + if(!userp(this_object()) && !clonep(this_object())) return; + + restype = this_object()->GetRespiration(); + j = percent(GetHealthPoints(), GetMaxHealthPoints()); + k = percent(GetStaminaPoints(), GetMaxStaminaPoints()); + + if( j < COLLAPSE_AT || k < COLLAPSE_AT ){ + this_object()->eventCollapse(); + } + + if(RACES_D->GetLimblessRace(this_object()->GetRace()) && + this_object()->GetPosition() == POSITION_STANDING){ + this_object()->SetPosition(POSITION_FLOATING); + } + + if(!env) return; + if(env->GetMedium() == MEDIUM_AIR && + this_object()->GetPosition() != POSITION_FLYING){ + if(!(this_object()->CanFly())){ + this_object()->SetPosition(POSITION_FLOATING); + if(find_call_out("eventFall") == -1){ + call_out("eventFall", 1); + } + } + else this_object()->eventFly(); + } + else if((env->GetTerrainType() & (T_SEAFLOOR | T_SPACE | T_UNDERWATER)) && + this_object()->GetPosition() == POSITION_FLYING){ + this_object()->SetPosition(POSITION_FLOATING); + } + else if((env->GetMedium() == MEDIUM_WATER || + env->GetMedium() == MEDIUM_SURFACE) && + this_object()->GetPosition() != POSITION_SWIMMING){ + if(!(this_object()->GetPosition() == POSITION_FLYING && + environment()->GetMedium() == MEDIUM_SURFACE)){ + if(!(environment()->GetTerrainType() & (T_SEAFLOOR)) && this_object()->CanSwim()){ + if(this_object()->GetPosition() != POSITION_FLOATING){ + this_object()->eventSwim(); + } + } + else if(!(environment()->GetTerrainType() & (T_SEAFLOOR))){ + this_object()->SetPosition(POSITION_FLOATING); + call_out("eventSink", 1); + } + } + } + + i = this_object()->CanBreathe(); + if(undefinedp(i)) i = 1; + + if(env->GetMedium() == MEDIUM_SPACE){ + this_object()->SetPosition(POSITION_FLOATING); + if(restype != R_VACUUM){ + if(!i){ + breathdam = 1; + j=this_object()->eventReceiveDamage("Outer space",ANOXIA,200,1); + if(j) eventPrint("You are asphyxiating."); + } + } + } + else if(env->GetMedium() == MEDIUM_WATER){ + if(restype != R_VACUUM && restype != R_WATER){ + if(!i){ + breathdam = 1; + j=this_object()->eventReceiveDamage("Water", ANOXIA, 100, 1); + if(j) eventPrint("You are drowning."); + } + } + } + else if(restype == R_WATER && env->GetMedium() != MEDIUM_WATER){ + if(!i){ + breathdam = 1; + j=this_object()->eventReceiveDamage("Air", ANOXIA, 100, 1); + if(j) eventPrint("You are asphyxiating."); + } + } + if(!breathdam){ + if(!i){ + j=this_object()->eventReceiveDamage("asphyxia", ANOXIA, 200, 1); + if(j) eventPrint("You cannot breathe!"); + } + } + if(i && restype == R_AIR && (i = env->GetPoisonGas()) > 0 ){ + if( this_object()->GetResistance(GAS) != "immune" ){ + eventPrint("You choke on toxic gases."); + this_object()->eventReceiveDamage("Poison gas", GAS, i, 1); + } + } +} + +static void heart_beat(){ + int i; + undead::heart_beat(); + if(!GetDying()){ + if( i = sizeof(Protection) ){ + while(i--) + if( Protection[i]->time && (--Protection[i]->time < 1) ) + RemoveMagicProtection(i); + } + eventCheckEnvironment(); + eventCheckHealing(); + if(!stringp(hobbled(this_player()))){ + this_object()->eventCollapse(); + } + } +} + +void eventReconnect(){ + LastHeal = time(); +} + +void ParseHook(string str){ + parse_sentence(str); +} + + +/************ /lib/body.c Modal Methods Section ************/ + +mixed CanRemoveItem(object ob){ return 1; } + +/************ /lib/body.c Events Section ************/ + +private void checkCollapse(){ + float h = percent(GetHealthPoints(), GetMaxHealthPoints()); + float i = percent(GetStaminaPoints(), GetMaxStaminaPoints()); + + if( h < COLLAPSE_AT || i < COLLAPSE_AT ){ + SetParalyzed(3, (: checkCollapse :)); + return; + } + this_object()->eventPrint("You feel some strength returning."); +} + +varargs int eventCollapse(int noparalyze){ + int position = GetPosition(); + int medium; + if(environment()) medium = environment()->GetMedium(); + + if(!this_object() || !environment()) return 0; + + foreach(object ob in all_inventory(environment())){ + if(inherits(LIB_CHAIR,ob) || inherits(LIB_BED,ob) ){ + ob->eventReleaseStand(this_object()); + } + } + + if(medium == MEDIUM_LAND){ + if( position == POSITION_LYING ){ + return 1; + } + send_messages("collapse", "$agent_name $agent_verb to the ground.", + this_object(), 0, environment()); + SetPosition(POSITION_LYING); + if(!noparalyze) SetParalyzed(3, (: checkCollapse :)); + return 1; + } + + if( position == POSITION_FLOATING ){ + return 1; + } + send_messages("go", "$agent_name $agent_verb limp.", + this_object(), 0, environment()); + SetPosition(POSITION_FLOATING); + if(!noparalyze) SetParalyzed(3, (: checkCollapse :)); + return 1; +} + +void eventCheckHealing(){ + int x, y, lead; + object dude; + dude = this_object(); + lead = dude->GetLead(); + + if(lead && !present("firearms_wound", dude)){ + object wound = new(LIB_WOUND); + if(wound) wound->eventMove(dude); + } + + if(interactive() && !environment()){ + this_object()->eventMove(ROOM_START); + } + + //This resets the parser counter. + this_object()->DoneTrying(); + + if(HealthPoints < 1 && !this_object()->GetDying()){ + this_object()->SetDying(1); + call_out("eventDie", 0, "misfortune"); + return; + } + + if(AUTO_ADVANCE && interactive() && !this_object()->GetDying()){ + PLAYERS_D->CheckAdvance(this_object()); + } + + x = GetHeartRate() * 10; + + if(dude->GetSleeping() > 0 && dude->GetPosition() != POSITION_LYING + && dude->GetPosition() != POSITION_SITTING){ + dude->eventCollapse(); + } + + if(dude->GetInCombat()){ + if(dude->GetInvis()) dude->SetInvis(0); + if(!interactive(dude) && !RACES_D->GetLimblessRace(dude->GetRace())){ + dude->SetAutoStand(1); + } + } + + if(!inherits(LIB_VEHICLE,this_object())){ + if( (y = time() - LastHeal) >= x ){ + LastHeal = time(); + do { + eventCompleteHeal(GetHealRate()); + } while( (y = y - x) >= x ); + if( Alcohol > 0 ){ + Alcohol--; + if( !Alcohol ){ + message("my_action", "You are left with a pounding headache.", + this_object()); + AddHealthPoints(-(random(3) + 1)); + } + else if( !GetSleeping() && random(100) < 8 ){ + string verb, adv; + + switch(random(5)){ + case 0: verb = "burp"; adv = "rudely"; break; + case 1: verb = "look"; adv = "ill"; break; + case 2: verb = "hiccup"; adv = "loudly"; break; + case 3: verb = "stumble"; adv = "clumsily"; break; + case 4: verb = "appear"; adv = "drunk"; break; + } + message("my_action", "You " + verb + " " + adv + ".", + this_object()); + message("other_action", GetName() + " " + pluralize(verb) + " " + + adv + ".", environment(), ({ this_object() })); + } + } + if( Sleeping > 0 ){ + Sleeping--; + if( !Sleeping || dude->GetInCombat() ){ + Sleeping = 0; + message("my_action", "You wake up!", this_object()); + message("other_action", GetName() + " wakes up from " + + possessive(this_object()) + " deep sleep.", + environment(this_object()), ({ this_object() })); + } + else if( random(100) < 8 ){ + message("my_action", "You snore.", this_object()); + message("other_action", this_player()->GetName() + + " snores loudly.", environment(this_object()), + ({ this_object() })); + } + } + if( Poison > 0 && !random(17)) Poison--; + if( Caffeine > 0 ) Caffeine--; + if( Food > 0 ) Food--; + if( Drink > 0 ) Drink--; + } + } +} + +void eventCompleteHeal(int x){ + eventHealDamage(x, 1, GetLimbs()); + AddMagicPoints(x + 1); + AddStaminaPoints(x); +} + +int GetFalling(){ + return Falling; +} + +int SetFalling(int i){ + return Falling = i; +} + +mixed eventFall(){ + object env = environment(); + object *riders; + string dest; + int p = 0; + + Falling = 1; + FallCount++; + + if( !env ){ + return 0; + } + if( env->GetMedium() == MEDIUM_AIR ){ + ::eventFall(); + } + env = environment(); + dest = env->GetGround(); + + if(!dest || env->GetMedium() != MEDIUM_AIR){ + Falling = 0; + this_object()->eventCollapse(); + + riders = get_livings(this_object()); + if(sizeof(riders)){ + foreach(object passenger in riders){ + p = ( (passenger->GetMass()) * 0.04) * FallCount; + passenger->eventReceiveDamage("Deceleration sickness", BLUNT, p, 1); + } + } + p = ( (this_object()->GetMass()) * 0.04) * FallCount; + this_object()->eventReceiveDamage("Deceleration sickness", BLUNT, p, 1); + FallCount = 1; + remove_call_out("eventFall"); + } + return p; +} + +/* varargs int eventHealDamage(int x, int internal, mixed limbs) + * int x - amount of damage being healed, negatives illegal (required) + * int internal - internal damage flag (optional) + * mixed limbs - limb or limbs affected by the heal event (optional) + * + * defaults + * internal defaults to 0 + * limbs defaults to 0 + * + * description + * this event is triggered whenever something performs a healing action + * on the body + * + * if the internal flag is set then overall health is healed. + * if limbs are specified then the specified limbs are healed. * if the internal flag is NOT set and NO limbs are specified (default) + * then both overall health as well as the health of all limbs are healed. + * + * returns the actual amount of healing done or -1 if an error occurs + */ +varargs int eventHealDamage(int x, int internal, mixed limbs){ + if(!limbs && !internal){ + limbs = GetLimbs(); internal = 1; + } + else if(stringp(limbs)){ + limbs = ({ limbs }); + } + if(!limbs){ + limbs = ({}); + } + if( !arrayp(limbs)){ + error("Bad argument 3 to eventHealDamage().\n"); + } + if(internal){ + AddHealthPoints(x); + } + map(limbs, (: AddHealthPoints($(x), $1) :)); + return x; +} + +/* varargs int eventReceiveDamage(mixed agent, int type, int x, + * int internal, mixed limbs) + * object agent - the thing responsible for this damage (required) + * int type - the damage type(s) being done (required) + * int x - the amount of damage being done, negatives illegal (required) + * int internal - flag for internal or external damage (optional) + * mixed limbs - limbs to which damage has been done (optional) + * + * defaults + * internal defaults to 0 + * limbs defaults to 0 + * + * description + * handles sorting out damage events which happen to the body + * It assumes some agent is acting as the cause of this event, an + * agent being some sort of being as the cause of the event + * the previous_object() is considered to be doing the actual damage + * what does the damage is different than the agent in the sense + * that a knife does damage and a living thing is the agent + * can't get into more detail without getting philosophical, which is + * beyond the scope of a comment + * "x" amount of damage gets attempted, modified by varying things like + * armor and natural resistence to this type of damage + * the internal flag with no limbs specified means that the damage + * is taken solely to the overall health + * if the internal flag is set with limbs, the damage is both internal and + * done to named limbs + * if no internal flag is set and no limbs are specified, damage is done to + * all limbs + * if no internal flag is set and limbs are specified, then damage is done + * only to the specified limbs + * NOTE: internal damage is not modified by armor worn + * + * returns the average actual amount of damage done + */ + +varargs int eventReceiveDamage(mixed agent, int type, int x, int internal, + mixed limbs){ + string tmp = GetResistance(type); + string agentname; + int fp, basedam, tmpdam, dmgred; + + if(agent && stringp(agent)){ + agentname = agent; + agent = 0; + } + + if(objectp(agent)){ + if(estatep(agent) && !estatep(this_object())) return 0; + if(!estatep(agent) && estatep(this_object())) return 0; + } + + basedam = x; + + if(godmode) x = 0; + + switch(tmp){ + case "low": x = (3*x)/4; break; + case "medium": x /= 2; break; + case "high": x /= 4; break; + case "immune": x = 0; break; + } + if(!limbs && !internal){ + limbs = ({ scramble_array(GetLimbs())[0] }); + } + if( fp = functionp(Protect) ){ + if( !(fp & FP_OWNER_DESTED) ){ + function f; + f = Protect; + Protect = 0; + x -= evaluate(f, this_object(), agent, type, x, limbs); + } + } + x = eventCheckProtection(agent, type, x); + if( internal ){ + AddHealthPoints(-x, 0, (agent || agentname)); + return x; + } + if( stringp(limbs) ){ + limbs = ({ limbs }); + } + else if( !arrayp(limbs) ){ + return -1; + } + if(true()){ + int i, y, maxi; + + y = 0; + for(i=0, maxi = sizeof(limbs); i < maxi; i++){ + object *obs; + int j, z; + + z = x; + if(!Limbs[limbs[i]]){ /* no limb */ + y += z; + continue; + } + if(!(j = sizeof(obs = GetWorn(limbs[i])))){ /* no armor */ + y += z; /* add to total damage */ + if( !AddHealthPoints(-z, limbs[i], (agent || agentname)) ){ + call_out("RemoveLimb",0,limbs[i], (agent || agentname)); + } + if(this_object()->GetClass() != "fighter"){ + AddStaminaPoints(-z/2); + } + } + else { + while(j--){ + dmgred = obs[j]->eventReceiveDamage( + (agent || agentname), type, z, 0, limbs[i]); + z -= dmgred; + if(z < 1){ + } + else { + } + } + } + y = z; + if( y > 0 ){ + if(!AddHealthPoints(-y, 0, (agent || agentname))){ + call_out("RemoveLimb",0,limbs[i], (agent || agentname)); + } + if(this_object()->GetClass() != "fighter"){ + AddStaminaPoints(-y/2); + } + } + return y; + } + return x; + } +} + +/* int eventCheckProtection(object agent, int type, int damage) + * + * agent : object doing the damage + * type : damage type(s) + * damage : original amount damage being done + * + * This function cycles through any magic protection found, reducing + * damage accordingly. + * + * returns modified damage + */ +int eventCheckProtection(object agent, int type, int damage){ + int i, y; + if( !i = sizeof(Protection) ) return damage; + while(i--){ + int x; + + if( (type & Protection[i]->bits) != type ) continue; + if( Protection[i]->absorb ){ + if( (x = (Protection[i]->absorb - damage)) < 1 ){ + x = Protection[i]->absorb; + RemoveMagicProtection(i); + damage -= x; + if( damage < 1 ) return 0; + continue; + } + Protection[i]->absorb -= damage; + } + else if( Protection[i]->protect ) + x = (random(Protection[i]->protect / 2) + + (Protection[i]->protect / 2)); + else { + RemoveMagicProtection(i); + continue; + } + if( y = functionp(Protection[i]->hit) ){ + if( y == FP_OWNER_DESTED ){ + RemoveMagicProtection(i); + continue; + } + else { + if(Protection && + Protection[i] && + Protection[i]->hit){ + x = evaluate(Protection[i]->hit, this_object(), + agent, x, Protection[i]); + } + } + } + damage -= x; + if( damage < 1 ) return 0; + } + return damage; +} + +mixed eventReceiveThrow(object who, object what){ + int x; + + if( what->GetClass() > 1 ){ + int mod = who->GetSkillLevel("projectile attack") + + who->GetStatLevel("strength"); + + x = what->eventStrike(this_object()) * 3; + x = (x*mod)/100; + if( what->GetWeaponType() != "projectile" ){ + x = x/4; + } + x = this_object()->eventReceiveDamage(who, what->GetDamageType(), x, 0, + GetRandomLimb("torso")); + if( x > 0 ){ + who->AddSkillPoints("projectile attack", x); + } + } + else { + x = 0; + } + if( x < 1 ){ + environment()->eventPrint(GetName() + " catches " + + possessive_noun(who->GetName()) + " " + + what->GetKeyName() + ".", + ({ this_object(), who })); + eventPrint("You catch " + possessive_noun(who->GetName()) + " " + + what->GetKeyName() + "."); + who->eventPrint(GetName() + " catches your " + what->GetKeyName() + + "."); + } + else { + environment()->eventPrint(GetName() + " takes damage from " + + possessive_noun(who->GetName()) + " " + + what->GetKeyName() + ".", + ({ this_object(), who })); + eventPrint("You take damage from " + possessive_noun(who->GetName()) + + " " + what->GetKeyName() + "."); + who->eventPrint(GetName() + " takes damage from your " + + what->GetKeyName() + "."); + } + what->eventMove(this_object()); + return 1; +} + +/* varargs int eventDie(mixed agent) + * mixed agent - the agent responsible for the death (optional) + * + * description + * Kills the owner of this body if not already dying + * + * returns true if the thing is dying + */ +varargs int eventDie(mixed agent){ + int x; + string killer, death_annc; + object crime_scene; + if(DeathEvents) return 1; + DeathEvents = 1; + + this_object()->SetDying(0); + + if(agent && stringp(agent)){ + killer = agent; + agent = 0; + } + else { + if(!agent || !objectp(agent)){ + killer = "UNKNOWN"; + } + else killer = agent->GetName(); + } + + if(RACES_D->GetNonMeatRace(GetRace())) + death_annc = killer + " has destroyed "+ this_object()->GetName()+"."; + else if(!this_object()->GetUndead()) + death_annc = killer + " has slain "+ this_object()->GetName()+"."; + else death_annc = killer + " has destroyed "+ this_object()->GetName()+"."; + + if(killer == "asphyxia"){ + tell_room(ROOM_ARCH, this_object()->GetName() + " asphyxiated "+ + "in "+base_name(environment(this_object()))); + } + + CHAT_D->eventSendChannel("SYSTEM","death",death_annc,0); + + if( Sleeping > 0 ) Sleeping = 0; + + if( agent && objectp(agent) ){ + if( x ) agent->eventDestroyEnemy(this_object()); + else agent->eventKillEnemy(this_object()); + } + crime_scene = environment(); + if( crime_scene ){ + object *obs; + string *currs; + object ob; + string curr; + int i; + object *riders = filter( deep_inventory(), (: living($1) :) ); + + //I'd like to move the living body out first, but for now this + //misfeature stays. + + if(riders && sizeof(riders)){ + foreach(object rider in riders) eventBuck(rider); + } + if(GetRace() == "android" || GetRace() == "bot" || + inherits(LIB_VEHICLE,this_object())) ob = new(LIB_BOT_CORPSE); + else if(member_array(GetRace(), RACES_D->GetNonMeatRaces()) != -1){ + ob = crime_scene; + if(GetBodyComposition()){ + ob = new(LIB_CLAY); + ob->SetComposition(GetBodyComposition()); + } + } + else { + ob = new(LIB_CORPSE); + ob->SetCorpse(this_object()); + } + if(ob != crime_scene) ob->eventMove(crime_scene); + obs = filter(all_inventory(), (: !($1->GetRetainOnDeath()) :)); + i = sizeof(obs); + obs->eventMove(ob); + currs = this_object()->GetCurrencies() || ({}); + foreach(curr in currs){ + object pile; + int amt; + + if( amt = this_object()->GetCurrency(curr) ){ + pile = new(LIB_PILE); + pile->SetPile(curr, amt); + pile->eventMove(ob); + this_object()->AddCurrency(curr, -amt); + } + } + } + + SetUndead(!(x = GetUndead())); + + evaluate( function(){ Dying = 0; }); + flush_messages(); + return 1; +} + +/* int eventRemoveItem(object ob) + * object ob - the item being removed + * + * Removes a worn or wielded item from the list + * + * returns 1 on success, 0 on failure + */ +int eventRemoveItem(object ob){ + string limb; + + foreach(limb in keys(WornItems)){ + if( !WornItems[limb] ) continue; + if( member_array(ob, WornItems[limb]) != -1){ + WornItems[limb] -= ({ ob }); + } + } + return 1; +} + +/* int eventWear(object ob, mixed limbs) + * object ob - the item being worn (wielded) + * mixed limbs - string or array of limbs on which it is being worn + * + * description + * marks the limbs "limbs" as being protected by the armor "ob" + * + * returns 1 if successful, 0 if failure + */ +int eventWear(object ob, mixed limbs){ + string limb,s1; + string *target_limb; + target_limb = ({}); + + if( stringp(limbs) ){ + limbs = ({ limbs }); + } + if( CanWear(ob, limbs) != 1 ){ + return 0; + } +#if 0 + if(!inherits(LIB_WEAPON, ob)){ + foreach(limb in limbs){ + if(sscanf(limb,"%s foot",s1) || sscanf(limb,"%s hand",s1) ){ + if(!sizeof(GetWorn(limb))) target_limb = ({ limb }); + } + } + } +#endif + if(sizeof(target_limb) && sizeof(limbs) == 1) limbs = target_limb; + foreach(limb in limbs){ + if( !WornItems[limb] ) WornItems[limb] = ({ ob }); + else WornItems[limb] += ({ ob }); + } + return 1; +} + +string *GetEquippedLimbs(){ + string *equipped_limbs = ({}); + object *wornstuff = filter(all_inventory(this_object()), (: $1->GetWorn() :) ); + + foreach(object item in wornstuff){ + equipped_limbs += item->GetWorn(); + } + return equipped_limbs; +} +/************ /lib/body.c Data manipulation functions *************/ +void NewBody(string race){ + if(!race) + Limbs = ([ (Torso = "ooze") : ([ "parent" : 0, "children" : ({}), + "health" : 50, "class" : 1, "armors" : 0 ]) ]); + else Limbs = ([]); + MissingLimbs = ([]); + Fingers = ([]); +} + +/* int CanWear(object armor, string *limbs) + * object armor - the piece of armor being checked + * string *limbs - the limbs on which the armor wants to be worn + * a nested array indicates that just one of the included limbs + * must be satisfied + * + * description + * checks to see if a particular armor can be worn + * + * returns 1 if the armor can be worn on those limbs + * returns 0 if the armor cannot be worn there for any reason + * + */ +mixed CanWear(object ob, string *limbs){ + string limb, verb_pr, verb_pt, short; + int type, bad_types, i, maxi; + + if( !ob ) return 0; + short = ob->GetShort(); + if( !(type = ob->GetArmorType()) ) + return capitalize(short) + " cannot be worn!"; + if( type & A_WEAPON ){ + verb_pr = "wield"; + verb_pt = "wielded"; + } + else { + verb_pr = "wear"; + verb_pt = "worn"; + } + if( !limbs || !(maxi = sizeof(limbs)) ) + return "Where should " + short + " be "+ verb_pt + "?"; + if( ob->GetWorn() ) + return "It is already being " + verb_pt + "."; + + // Verify that the the item can be worn on each limb specified by limbs. + i = 0; + foreach(limb in limbs){ + + // Nested arrays indicate that only one of the elements in the nested + // array must be satisfied. Check for one valid limb, and replace the + // nested array with the valid limb, if found. + if( arrayp(limb) ){ + string limb2; + string validLimb = 0; + int leastRings = -1; + + if(!sizeof(limb)) error("Bad limb specification to CanWear().\n"); + // Iterate through the nested array. + foreach(limb2 in limb){ + string* wornItems; + + // The limb will be valid if: + // o The body has the named limb capable of wearing the armor type. + // o There are no armors of the same type on that limb, except + // for rings, which can have up to GetFingers() of that type worn. + if(!Limbs[limb2] || !(Limbs[limb2]["armors"] & type)) continue; + wornItems = WornItems[limb2]; + + // If the item is a ring, attempt to distribute the rings evenly + // across the available hands. + if(type == A_RING){ + int currentRings; + + if(!sizeof(wornItems)) currentRings = 0; + else currentRings = sizeof(filter(wornItems, + (:$1->GetArmorType() == A_RING:))); + if(currentRings >= leastRings && leastRings != -1) continue; + leastRings = currentRings; + if(currentRings >= GetFingers(limb2)) continue; + } + else if(wornItems){ + object wornItem; + int tmpType = 0; + + foreach(wornItem in wornItems) + if(wornItem) tmpType |= wornItem->GetArmorType(); + if(tmpType & type) continue; + } + validLimb = limb2; + } + if(validLimb) limbs[i] = validLimb; + else return "You cannot " + verb_pr + " that."; + } + else { + if(!GetLimb(limb)){ + string ret = "Try a different body part."; + string *hands = GetWieldingLimbs(); + if(type & A_RING && sizeof(hands)){ + ret = "Try: wear " + ob->GetKeyName() + " on "+ + hands[0]; + } + return ret; + } + wearbit = Limbs[limb]["armors"]; + if( !Limbs[limb] ) return "You have no " + limb + "."; + if( !(wearbit & type) ){ + if( type & A_WEAPON ) + return "You cannot wield with " + limb + "."; + else return "You cannot wear " + short + " on your " + limb + "."; + } + } + i++; + } + switch(type){ + case A_RING: + if(maxi != 1) + return "You can only wear " + short + " on one limb."; + if( !WornItems[limbs[0]] ) return 1; /* nothing there, ring ok */ + /* count # worn rings */ + i = sizeof(filter(WornItems[limbs[0]], + (: $1->GetArmorType() == A_RING :))); + if(i >= GetFingers(limbs[0])) + return "You are already wearing too many rings there."; + else return 1; /* ok */ + case A_GLOVE: + if(maxi != 1) + if( GetFingers(limbs[0]) > ob->GetFingers() ){ + return capitalize(short) + " does not seem to fit well on " + "your " + limbs[0] + "."; + } + bad_types = A_GLOVE | A_LONG_GLOVE | A_SOCK | A_LONG_SOCK; + break; + case A_LONG_GLOVE: + if(maxi != 2) + return capitalize(short) + " should be worn on two limbs."; + if( limbs[0] == Limbs[limbs[1]]["parent"] ){ /* which is hand? */ + /* more fingers than this armor can stand */ + if(GetFingers(limbs[1]) > ob->GetFingers()) + return capitalize(short) + " does not seem to fit well on " + "your " + limbs[1] + "."; + } + else if(limbs[1] == Limbs[limbs[0]]["parent"]){ + /* ok, first limb is hand, check it */ + if(GetFingers(limbs[0]) > ob->GetFingers()) + return capitalize(short) + " does not seem to fit well on " + "your " + limbs[1] + "."; + } + else return "Your " + limbs[0] + " is not connected to your " + + limbs[1] + "."; + bad_types = A_GLOVE | A_LONG_GLOVE; + break; + case A_BOOT: case A_SOCK: + if(maxi != 1) + capitalize(short) + " may only be worn on one limb."; + if(type == A_SOCK) bad_types = A_SOCK | A_LONG_SOCK; + else bad_types = A_BOOT | A_LONG_BOOT; + break; + case A_LONG_BOOT: case A_LONG_SOCK: + if(maxi != 2) + return capitalize(short) + " must be worn only on two limbs."; + if(limbs[0] != Limbs[limbs[1]]["parent"] && + limbs[1] != Limbs[limbs[0]]["parent"]) + return "Your " + limbs[0] + " is not connected to your " + + limbs[1] + "."; + if(type == A_LONG_SOCK) bad_types = A_LONG_SOCK | A_SOCK; + else bad_types = A_BOOT | A_LONG_BOOT; + break; + case A_HELMET: case A_VEST: case A_AMULET: case A_VISOR: case A_BELT: case A_COLLAR: + if(maxi != 1) + return capitalize(short) + " may only be worn on one limb."; + bad_types = type; + break; + case A_PANTS: case A_SHIRT: + bad_types = type; + break; + case A_CLOAK: + bad_types = type; + break; + case A_SHIELD: + bad_types = A_SHIELD | A_WEAPON; + break; +#if 0 + foreach(limb in limbs){ + object worn_item; + int tmp = 0; + + if( !WornItems[limb] ) continue; /* no armors, no prob */ + if( !Limbs[limb]["parent"] ) continue; /* torso ok for 2 */ + foreach(worn_item in WornItems[limb]) { + if( !worn_item ) continue; + tmp |= worn_item->GetArmorType(); + } + /* not gonna allow 2 shields or a shield and weapon here */ + if( tmp & (A_SHIELD | A_WEAPON) ) + return "You cannot wear " + short + " there right now."; + } + return 1; /* ok */ +#endif + case A_WEAPON: + foreach(limb in limbs){ + object worn_item; + int tmp = 0; + + if( !WornItems[limb] ) continue; /* nothing there, ok */ + foreach(worn_item in WornItems[limb]){ + if( !worn_item ) continue; + tmp += worn_item->GetArmorType(); + } + /* again, not allowing 2 weapons or a shield and weapon */ + if(tmp & (A_SHIELD | A_WEAPON)) + return "You cannot wield " + short + " there right now."; + } + return 1; /* ok */ + case A_ARMOR: case A_BODY_ARMOR: + bad_types = A_ARMOR | A_BODY_ARMOR; + break; + case A_COLLAR: + bad_types = A_COLLAR | A_AMULET; + break; + case A_CUSTOM: + bad_types = A_CUSTOM; + break; + case A_EXO: + bad_types = A_EXO; + break; + + default: return 0; /* not any illegal stuff */ + } + foreach(limb in limbs){ + object worn_item; + int tmp = 0; + if( !WornItems[limb] ) continue; /* no preventing types */ + foreach( worn_item in WornItems[limb] ){ + if( !worn_item ) continue; + tmp |= worn_item->GetArmorType(); + } + if(tmp & bad_types){ + return "You cannot " + verb_pr + " " + short + " there right now."; + } + } + return 1; /* ok */ +} + +mixed CanManipulate(){ + string *prehensile_limbs = this_object()->GetWieldingLimbs(); + if(!sizeof(prehensile_limbs)){ + say(this_object()->GetName()+" looks helpless without prehensile appendages."); + return "You lack prehensile limbs with which to do that."; + } + return 1; +} + +int CanFly(){ + float j = percent(GetHealthPoints(), GetMaxHealthPoints()); + float k = percent(GetStaminaPoints(), GetMaxStaminaPoints()); + string clipped = identify(this_object()->GetMissingLimbs()); + + if( j < COLLAPSE_AT || k < COLLAPSE_AT ){ + return 0; + } + + if(creatorp(this_object())) return 1; + + if(!RACES_D->CanFly(this_object()->GetRace())){ + return 0; + } + + if(!clipped || !sizeof(clipped)) return 1; + if(!grepp(lower_case(clipped),"wing")) return 1; + + if(this_object()->GetStaminaPoints() < 5) return 0; + return 0; +} + +int CanSwim(){ + float j = percent(GetHealthPoints(), GetMaxHealthPoints()); + float k = percent(GetStaminaPoints(), GetMaxStaminaPoints()); + + if( j < COLLAPSE_AT || k < COLLAPSE_AT ){ + return 0; + } + + if(creatorp(this_object())) return 1; + if(sizeof(this_object()->GetMissingLimbs())) return 0; + + if(!RACES_D->CanSwim(this_object()->GetRace())){ + return 0; + } + + if(this_object()->GetStaminaPoints() < 5) return 0; + + return 1; +} + + +/* int AddLimb(string limb, string parent, int classes, int *armors) + * string limb - the limb being added (required) + * string parent - the limb to which this one is being attached (required) + * int classes - rating of the limb's strength (optional) + * int *armors - the types of armors which can be worn here (optional) + * + * defaults + * classes defaults to 1 + * armors defaults to ({}) + * + * description + * adds the named limb to the body, attached at the named point + * the limb classes starts at 1 for a torso (strongest) + * to whatever the documentation rates as the weakest + * + * returns 1 on success, 0 on failure + */ +varargs int AddLimb(string limb, string parent, int classes, int *armors){ + int arm = 0; + + if(!limb || Limbs[limb] || (parent && !Limbs[parent])){ + return 0; + } + if(armors){ + int i; + + i = sizeof(armors); + while(i--) arm |= armors[i]; + } + if(MissingLimbs[limb]) map_delete(MissingLimbs, limb); + if( parent ) Limbs[parent]["children"] += ({ limb }); + else Torso = limb; + if( !classes ) classes = 5; + Limbs[limb] = ([ "parent" : parent, "children" : ({}), "class" : classes, + "armors" : arm ]); + Limbs[limb]["health"] = GetMaxHealthPoints(limb); + return 1; +} + +int HealLimb(string limb){ + Limbs[limb]["health"] = GetMaxHealthPoints(limb); + return Limbs[limb]["health"]; +} + +// Restore Limb has been bugfixed and modified to +// handle missing parents and missing children. To restore +// a limb, RestoreLimb("right arm") will restore the arm only. +// To restore the arm plus its children (in this case, a +// hand) use RestoreLimb("right arm",1) and this will enable +// the recursive restore of the limb. Trying to restore +// a limb will fail if the parent is missing. + +varargs int RestoreLimb(string limb, int recurse){ + if( !MissingLimbs[limb] ) return 0; + if(!sizeof(Limbs[MissingLimbs[limb]["parent"]])) return 0; + Limbs[limb] = MissingLimbs[limb]; + map_delete(MissingLimbs, limb); + Limbs[limb]["health"] = GetMaxHealthPoints(limb); + + // This ensures that the parent of the current limb has this + // limb added to its children array. + if(member_array(limb,Limbs[Limbs[limb]["parent"]]["children"]) == -1){ + Limbs[Limbs[limb]["parent"]]["children"] += ({ limb }); + } + + if(recurse && sizeof(MissingLimbs)){ + string *kinder = ({}); + foreach(string key, mixed val in MissingLimbs){ + if(MissingLimbs[key]["parent"] == limb) kinder += ({ key }); + } + if(sizeof(kinder)){ + foreach(string element in kinder) this_object()->RestoreLimb(element, 1); + } + } + + return 1; +} + +/* int DestLimb(string limb) + * string limb - the limb being removed + * + * description + * removes a limb from the limbs mapping. The limb isn't marked as mising, + * and the monster doesn't die even if you remove a fatal limb. Useful for + * removing limbs from standard race types. Removing the torso isn't allowed. + * + * returns -1 on error, 0 on failure, 1 on success + */ +int DestLimb(string limb){ + string *kiddies; + int i; + + if(!limb || !Limbs[limb]) return -1; + if(!Limbs[limb]["parent"]){ + return -1; + } + Limbs[Limbs[limb]["parent"]]["children"] -= ({ limb }); + if( (i = sizeof(kiddies = Limbs[limb]["children"])) ) + while(i--) DestLimb(kiddies[i]); + map_delete(Limbs, limb); + return 1; +} + +/* int this_object()->RemoveLimb(string limb, object agent) + * string limb - the limb being removed + * object agent - the agent who is responsible for the limb removal + * + * description + * removes a limb from the limbs mapping and stores vital data in the + * missing limbs mapping + * + * returns -1 on error, 0 on failure, 1 on success + */ +varargs int RemoveLimb(string limb, mixed agent, int quiet){ + string *kiddies; + string limbname,adjname,templimbname, agentname; + int i, fatal; + + if(agent){ + if(stringp(agent)){ + agentname = agent; + agent = 0; + } + else if(objectp(agent)){ + if(agent != this_object()) agentname = agent->GetName(); + } + } + + if(limb == this_object()->GetTorso() || limb == "neck") return 0; + if(godmode || !SEVERABLE_LIMBS) return 0; + if( sscanf(limb, "%s %s", adjname, templimbname) == 2 ) limbname=templimbname; + else limbname=limb; + + if(!limb || !Limbs[limb]) return -1; + if(!Limbs[limb]["parent"] || Limbs[limb]["class"] == 1) fatal = 1; + + MissingLimbs[limb] = copy(Limbs[limb]); + Limbs[Limbs[limb]["parent"]]["children"] -= ({ limb }); + if( (i = sizeof(kiddies = Limbs[limb]["children"])) ) + while(i--) this_object()->RemoveLimb(kiddies[i], agent,quiet); + map_delete(Limbs, limb); + if( environment() ){ + object ob; + if(!quiet){ + message("environment", possessive_noun(GetName()) + " " + limb + + " is severed!", environment(), ({ this_object() })); + message("environment", "Your "+ limb + " is severed!", this_object()); + } + if(GetRace() == "golem"){ + ob = new(LIB_CLAY); + if(GetBodyComposition()) ob->SetComposition(GetBodyComposition()); + } + else { + if(GetRace() == "android" || GetRace() == "bot" || + inherits(LIB_VEHICLE,this_object())) ob = new(LIB_BOT_LIMB); + else ob = new(LIB_LIMB); + ob->SetLimb(limb, GetCapName(), GetRace()); + } + ob->eventMove(environment()); + i = sizeof(WornItems[limb]); + while(i--){ + int number_of_slots = sizeof(WornItems[limb][i]->GetWorn()); + WornItems[limb][i]->SetWorn(0); + if(number_of_slots == 1) WornItems[limb][i]->eventMove(ob); + else WornItems[limb][i]->eventMove(this_object()); + } + while( i = sizeof(WornItems[limb]) ) + eventRemoveItem(WornItems[limb][i]); + } + if(fatal){ + mixed smith; + if( !this_object()->GetDying() ){ + this_object()->SetDying(1); + Agent = agent; + smith = (Agent||agentname); + call_out("eventDie", 0, smith); + } + } + return 1; +} + +mapping GetLimb(string limb){ + if(!limb || !Limbs[limb]) return 0; + else return copy(Limbs[limb]); +} + +/* string GetRandomLimb(string targ) + * string targ - the targetted limb + * + * description + * returns a random limb weighted towards the targetted limb + */ + +string GetRandomLimb(string targ){ + string array limbs; + + if( !targ ){ + targ = GetTorso(); + } + if( member_array(targ, (limbs=keys(Limbs))) == -1){ + targ= GetTorso(); /* no target or illegal target, weight torso */ + } + targ = (limbs + (targ ? ({ targ, targ }) : ({})))[random(sizeof(limbs)+2)]; + return targ; +} + +string GetTorso(){ + string *limbs; + int i; + + i = sizeof(limbs = keys(Limbs)); + while(i--){ + if(!Limbs[limbs[i]]["parent"]){ + return limbs[i]; + } + } + return 0; +} + +string array GetLimbs(){ + return (Limbs ? keys(Limbs) : 0); +} + +int GetLimbClass(string limb){ + if(sizeof(Limbs) && sizeof(Limbs[limb])) return Limbs[limb]["class"]; + return 5; +} + +string GetLimbParent(string limb){ return Limbs[limb]["parent"]; } + + +//The following function courtesy of Garfield @ M*U*D +string GetMissingLimbParent(string limb){ return MissingLimbs[limb]["parent"]; } + +//The following function courtesy of Garfield @ M*U*D +string *GetMissingLimbParents(string limb){ + string *limbs; + + limbs = ({ limb }); + + while(memberp(keys(MissingLimbs),GetMissingLimbParent(limbs[0]))){ + limbs = ({ GetMissingLimbParent(limbs[0]) }) + limbs; + } + + return limbs; +} + +string array GetLimbChildren(string limb){ + return Limbs[limb]["children"] + ({}); +} + +mapping GetMissingLimb(string limb){ + return (limb ? copy(MissingLimbs[limb]) : 0); +} + +// This function courtesy of Garfield +// and Javelin at M*U*D +int eventCompareLimbs(string limb1, string limb2){ + if (memberp(GetMissingLimbParents(limb1), limb2)){ + return 1; + } + if (memberp(GetMissingLimbParents(limb2), limb1)){ + return -1; + } + return strcmp(limb1, limb2); } + + // New comparison functionality courtesy of + // Garfield and Javelin at M*U*D + varargs string array GetMissingLimbs(int not_default){ + if(not_default){ + string *tmp_arr = ({}); + if(sizeof(keys(MissingLimbs))){ + tmp_arr = sort_array(keys(MissingLimbs), (: eventCompareLimbs :) ); + } + return tmp_arr; + } + else return keys(MissingLimbs); + } + +string GetLong(string nom){ + string *limbs; + string *exempt; + string str; + float h; + + str = ""; + exempt = ({"bot","android","tree","plant","vehicle","strider","mech"}); + + if(!(this_object()->GetNoCondition())){ + if(member_array(this_object()->GetRace(),exempt) == -1 && + !this_object()->GetUndead() ){ + str = "The "+this_object()->GetGender()+" "; + str += this_object()->GetRace(); + h = percent(GetHealthPoints(), GetMaxHealthPoints()); + if( h < 10.0 ) str += " is mortally wounded.\n"; + else if( h < 20.0 ) str += " is near death.\n"; + else if( h < 30.0 ) str += " is severely injured.\n"; + else if( h < 40.0 ) str += " is badly injured.\n"; + else if( h < 50.0 ) str += " is hurt.\n"; + else if( h < 60.0 ) str += " is slightly injured.\n"; + else if( h < 70.0 ) str += " has some cuts and bruises.\n"; + else if( h < 80.0 ) str += " is in decent shape.\n"; + else if( h < 90.0 ) str += " is quite keen.\n"; + else str += " is in top condition.\n"; + } + } + if(this_object()->GetUndead()){ + str = capitalize(nominative(this_object()))+" has been killed, and "; + str += "is one of the Walking Undead.\n"; + } + + limbs = GetMissingLimbs(); + if(!(GetRace() == "android") && !(GetRace() == "bot") && + !inherits(LIB_VEHICLE,this_object())){ + + if( sizeof(limbs) ){ + int i, maxi; + + str += capitalize(nom) + " is missing " + add_article(limbs[0]); + for(i=1, maxi = sizeof(limbs); i<maxi; i++){ + if( i < maxi-1 ) str += ", " + add_article(limbs[i]); + else { + if( maxi > 2 ) str += ","; + str += " and " + add_article(limbs[i]); + } + } + str += ".\n"; + } + } + return str; +} + +string array GetWieldingLimbs(){ + return filter(keys(Limbs), (: (Limbs[$1]["armors"] & A_WEAPON) :)); +} + +/* int AddFingers(string limb, int x) + * string limb - the limb to which fingers will be added + * int x - the number of fingers being added, can be negative + * + * description + * adds the given number of fingers to the given limb + * + * returns the total number of fingers after addition + */ + +varargs int AddFingers(string limb, int x){ + if((Fingers[limb] += x) < 1) Fingers[limb] = 1; + return Fingers[limb]; +} + +int GetFingers(string limb){ + return Fingers[limb]; +} + +varargs object *GetWorn(string limb){ + if(!limb){ + object *ret = ({}); + string *limbs; + int i; + + i = sizeof(limbs = keys(Limbs)); + while(i--) if(WornItems[limbs[i]]) ret += ({ WornItems[limbs[i]] }); + return distinct_array(ret); + } + else if(!WornItems[limb]) return ({}); + else return (WornItems[limb] + ({})); +} + +varargs mixed GetWielded(string limb){ + if(!limb){ + object *ret = ({}); + string *limbs; + int i; + + i = sizeof(limbs = keys(Limbs)); + while(i--){ + if(!WornItems[limbs[i]]) continue; + else ret += filter(WornItems[limbs[i]], + (: $1->GetArmorType() == A_WEAPON :)); + } + return distinct_array(ret); + } + else if(!WornItems[limb]) return 0; + else { + object *ret; + + ret = filter(WornItems[limb], (: $1->GetArmorType() == A_WEAPON :)); + if(sizeof(ret)) return ret[0]; + else return 0; + } +} + +/* varargs static int AddHealthPoints(int x, string limb, object agent) + * int x - number of points being added, may be negative (required) + * string limb - the limb to which health is being added (optional) + * object agent - the living responsible for this damage + * + * defaults + * limb defaults to 0 + * + * description + * if the value of limb is not zero, then "x" number of health points will + * be added to limb "limb" + * if he value is 0, then the overall health points will be modified + * + * returns the remaining number of health points for the limb in question + * or for the overall health points + */ + +varargs static int AddHealthPoints(int x, string limb, mixed agent){ + int y = 0; + string agentname; + + if(agent){ + if(stringp(agent)){ + agentname = agent; + agent = 0; + } + else if(objectp(agent)){ + if(agent != this_object()) agentname = agent->GetName(); + } + } + + if(godmode && x < 1) return 0; + + if( limb ){ + if( !Limbs[limb] ) return -1; + y = GetMaxHealthPoints(limb); + if(y < 1) return y; + if((Limbs[limb]["health"] += x) < 1) Limbs[limb]["health"] = 0; + else if(Limbs[limb]["health"] > y) + Limbs[limb]["health"] = y; + return Limbs[limb]["health"]; + } + else { + if((HealthPoints += x) < 1) HealthPoints = 0; + else if(HealthPoints > (y = GetMaxHealthPoints())) HealthPoints = y; + if( HealthPoints < 1 ){ + if( !this_object()->GetDying()){ + mixed smith; + this_object()->SetDying(1); + Agent = agent; + smith = (Agent||agentname); + call_out("eventDie", 0, smith); + } + } + else { + float h = percent(GetHealthPoints(), GetMaxHealthPoints()); + + if( h < COLLAPSE_AT ){ + eventCollapse(); + } + } + return HealthPoints; + } +} + +varargs int GetHealthPoints(string limb){ + if(limb){ + if(!Limbs[limb]) return -1; + else return Limbs[limb]["health"]; + } + else return HealthPoints; +} + +int SetHealthPoints(int x){ + if(interactive(this_object())) return GetHealthPoints(); + if( x > GetMaxHealthPoints() ){ + this_object()->SetStat("durability", (x-50)/10, + this_object()->GetStatClass("durability")); + AddHealthPoints( x - GetHealthPoints() ); + } + HealthPoints = x; + return GetHealthPoints(); +} + +/* int AddMagicPoints(int x) + * int x - the number of magic points being added, may be negative + * + * description + * adds magic points to the body + * + * returns the remaining magic points + */ + +int AddMagicPoints(int x){ + int y; + + if((MagicPoints += x) < 1) MagicPoints = 0; + else if(MagicPoints > (y = GetMaxMagicPoints())) MagicPoints = y; + return MagicPoints; +} + +int GetMagicPoints(){ return MagicPoints; } + +int GetMaxMagicPoints(){ return 0; } + +/* int AddStaminaPoints(int x) + * int x - number of stamina points being added + * + * description + * adds "x" stamina points, can be negative + * + * returns the remaining number of stamina points + */ + +int AddLead(string ammo,int number){ + if( !intp(number) ) error("Bad argument 2 to AddLead().\n"); + if( !stringp(ammo) ) error("Bad argument 1 to AddLead().\n"); + firearms_wounds += number; + if( firearms_wounds < 0 ){ + firearms_wounds = 0; + } + return 1; +} + +varargs int GetLead(string ammo){ + return firearms_wounds; +} + +float AddStaminaPoints(mixed x){ + float y; + + if( !intp(x) && !floatp(x) ) + error("Bad argument 1 to AddStaminaPoints().\n"); + if( intp(x) ) x = to_float(x); + if((StaminaPoints += x) < 0.1) StaminaPoints = 0.0; + else if(StaminaPoints > (y = GetMaxStaminaPoints())) StaminaPoints = y; + return StaminaPoints; +} + +int GetStaminaPoints(){ return to_int(StaminaPoints); } + +float GetMaxStaminaPoints(){ return 0; } + +int AddExperiencePoints(mixed x){ + if( !intp(x)) error("Bad argument 1 to AddExperiencePoints().\n"); + x -= DEVIATION_D->GetDeviationCost(this_object(), x); + + if( ExperienceDebt > 0 ) { + if( (ExperienceDebt -= x) < 0 ) { + ExperiencePoints -= ExperienceDebt; + ExperienceDebt = 0; + write("The last of your experience debt has been paid.\n"); + } + } else { + ExperiencePoints += x; + } + + return ExperiencePoints; +} + +int GetExperiencePoints(){ return ExperiencePoints; } + +int AddExperienceDebt(mixed x) { + if( !intp(x) ) error("Bad argument 1 to AddExperienceDebt().\n"); + if( x < 0 ) { + if( (x = ExperienceDebt + x) < 0) { + ExperienceDebt = 0; + AddExperiencePoints(ExperienceDebt); + write("The last of your experience debt has been paid.\n"); + } + } else { + ExperienceDebt += x; + } + + return ExperienceDebt; +} + +int GetExperienceDebt() { return ExperienceDebt; } + +int AddMagicProtection(class MagicProtection cl){ + if( ( !cl->absorb && !(cl->protect && cl->time) ) || + ( cl->hit && !functionp(cl->hit) ) || + ( cl->end && !functionp(cl->end) ) || + ( !cl->bits ) + ){ + error("Illegal class setting passed to AddMagicProtection.\n"); + return 0; + } + cl->timestamp = time(); + Protection += ({ cl }); + return 1; +} + +class MagicProtection array GetMagicProtection(){ return Protection; } + +int RemoveMagicProtection(mixed i){ + if(intp(i)){ + if( i > sizeof(Protection) - 1 ) return 0; + if( Protection[i]->end ){ + if( !(functionp(Protection[i]->end) & FP_OWNER_DESTED) ){ + evaluate(Protection[i]->end, this_object()); + } + } + Protection -= ({ Protection[i] }); + return 1; + } + if(stringp(i)){ + string filename = i; + i = -1; + foreach(class MagicProtection tmp in Protection){ + i++; + if(!tmp->obname) continue; + if(tmp->obname == filename){ + if(!(functionp(tmp->hit) & FP_OWNER_DESTED)){ + evaluate(Protection[i]->end, this_object()); + Protection -= ({ Protection[i] }); + return 1; + } + } + } + } + return 1; +} + +// This is for creatures that do not use weapons. +// I had to crank down unarmed combat for humanoids, +// so if your npc's are, say, dumb animals, be sure +// to include "SetMelee(1)" so they can fight +// Note that fighters are an exception to this. +// +int SetMelee(int i){ melee = i; return melee; } + +int GetMelee(){ return melee; } + + +int GetDying(){ + return Dying; +} + +int SetDying(int x){ + if(x) Dying = 1; + else Dying = 0; + return Dying; +} + +int SetSleeping(int x){ + if(RACES_D->GetNonMeatRace(GetRace()) || GetRace() == "elf") return 0; + return (Sleeping = x); +} + +int GetSleeping(){ return Sleeping; } + +int AddAlcohol(int x){ + int i = Alcohol + x; + if(RACES_D->GetNonMeatRace(GetRace())) return 0; + if(i < 0) i = 0; + return (Alcohol = i); +} + +int GetAlcohol(){ return Alcohol; } + +int AddCaffeine(int x){ + if(RACES_D->GetNonMeatRace(GetRace())) return 0; + return (Caffeine += x); +} + +int GetCaffeine(){ return Caffeine; } + +int AddDrink(int x){ return (Drink += x); } + +int GetDrink(){ return Drink; } + +int AddFood(int x){ return (Food += x); } + +int GetFood(){ return Food; } + +int AddPoison(int x){ + Poison += x; + if( Poison < 1 ){ + Poison = 0; + } + return Poison; +} + +int GetPoison(){ + int caff = GetCaffeine(); + int alc = GetAlcohol(); + int bonus_ret; + if(alc > 100) bonus_ret += (alc - 100); + if(caff > 100) bonus_ret += (caff - 100); + + return Poison + bonus_ret; +} + +string GetResistance(int type){ return "none"; } + +string GetRace(){ return 0; } + +string GetName(){ return 0; } + +string GetCapName(){ return 0; } + +int GetHeartRate(){ + int rate; + + rate = (GetAlcohol() - GetCaffeine()); + if( rate > 50 ) rate = 6; + else if( rate > 25 ) rate = 5; + else if( rate > 0 ) rate = 4; + else if( rate > -25 ) rate = 3; + else rate = 2; + rate += HeartModifier; + if( rate < 1 ){ + rate = 1; + } + else if( rate > 10 ){ + rate = 10; + } + return rate; +} + +int GetHealRate(){ + int heal, mod = 1; + int lead = GetLead(); + object dude = this_object(); + + heal = 1 - (GetPoison() / 2); + heal += ( (GetDrink() + GetFood()) || 1 ) / 40; + if(GetSleeping()) mod++; + if(GetAlcohol() > 10) mod++; + if(dude->GetStatLevel("strength") > 50) mod++; + if(dude->GetStatLevel("durability") > 50) mod++; + if(dude->GetStatLevel("luck") > random(100)) mod++; + if(dude->GetSkillLevel("faith") > 10) mod++; + mod = heal * to_float(mod * 0.1); + heal += mod; + if(lead && interactive(dude)){ + if(lead < 5) heal /= (lead + 1); + else heal = 0; + } + return (heal < 0 ? 0 : heal); +} + +string GetHealthShort(){ + string cl, sh; + float h; + + if( !(sh = this_object()->GetShort()) ) return 0; + h = percent(GetHealthPoints(), GetMaxHealthPoints()); + if( this_object()->GetNoCondition() || h > 90.0 ) cl = "%^BOLD%^GREEN%^"; + else if( h > 75.0 ) cl = "%^GREEN%^"; + else if( h > 50.0 ) cl = "%^BOLD%^BLUE%^"; + else if( h > 35.0 ) cl = "%^BLUE%^"; + else if( h > 20.0 ) cl = "%^BOLD%^RED%^"; + else cl = "%^RED%^"; + return cl + capitalize(sh); +} + +mixed SetProtect(function f){ return (Protect = f); } + +function GetProtect(){ return Protect; } + +int GetHeartModifier(){ + return HeartModifier; +} + +varargs int AddHeartModifier(int x, int t){ + HeartModifier += x; + if( t > 0 ){ + call_out((: AddHeartModifier(-$(x)) :), t); + } + return HeartModifier; +} + +int AddHP(int hp){ + if(hp < 1 && godmode) return 0; + AddHealthPoints(hp); + return hp; +} + +string GetAffectLong(){ + object dude; + string ret; + int alclevel; + + dude = this_object(); + alclevel = dude->GetAlcohol(); + ret = ""; + + if(dude->GetSleeping() > 0){ + ret += dude->GetName()+" is asleep.\n"; + } + + else if(alclevel > 10){ + if(alclevel < 20) ret += dude->GetName()+" looks tipsy.\n"; + else if(alclevel < 50) ret += dude->GetName()+" looks drunk.\n"; + else if(alclevel < 70) ret += dude->GetName()+" is very drunk.\n"; + else ret += dude->GetName()+" is completely wasted drunk.\n"; + } + + return ret; + +} + +int GetDeathEvents(){ + return DeathEvents; +} + +int SetDeathEvents(int i){ + if(!i) DeathEvents = 0; + else DeathEvents = 1; + return DeathEvents; +} + +int SetGodMode(int i){ + if(!this_player()) return 0; + if(archp(this_object()) && !archp(this_player())) return 0; + if(!archp(this_object()) && this_player() != this_object()) return 0; + if(i) godmode = 1; + else godmode = 0; + return godmode; +} + +int GetGodMode(){ + return godmode; +} + +string SetKeepalive(string str){ + keepalive = str; +} + +string GetKeepalive(){ + return keepalive; +} diff --git a/lib/lib/bonus.c b/lib/lib/bonus.c new file mode 100644 index 0000000..56c6a24 --- /dev/null +++ b/lib/lib/bonus.c @@ -0,0 +1,166 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ITEM; + +int SetBonuses(); + +mapping Skills = ([]); +mapping Stats = ([]); +mapping Points = ([]); +int Duration = 15; +string bonusname; +object whom; + +void create(){ + item::create(); + AddSave( ({ "Skills", "Stats", "Points", "Duration", "bonusname" }) ); + SetInvis(1); + SetId("bonus_object"); + SetShort("bonus"); + SetLong("A bonus"); +} + +void init(){ + item::init(); + set_heart_beat(1); + if(environment(this_object()) && living(environment(this_object()))) + SetBonuses(); +} + +void heart_beat(){ + if(Duration){ + Duration--; + //tc(identify(this_object())+" Duration: "+Duration); + } + else { + //tc("destructing "+identify(this_object())); + this_object()->eventDestruct(); + } + if(whom && environment() != whom){ + //tc("No longer on "+identify(whom)+", destructing","red"); + this_object()->eventDestruct(); + } +} + +mapping SetStats(mapping arg){ + Stats = copy(arg); + if(environment(this_object()) && living(environment(this_object()))) + SetBonuses(); + return copy(Stats); +} + +mapping GetStats(){ + return copy(Stats); +} + +mapping SetSkills(mapping arg){ + Skills = copy(arg); + return copy(Skills); +} + +mapping GetSkills(){ + return copy(Skills); +} + +mapping SetPoints(mapping arg){ + Points = copy(arg); + return copy(Points); +} + +mapping GetPoints(){ + return copy(Points); +} + +int SetBonusDuration(int i){ + Duration = i; +} + +int AddBonusDuration(int i){ + Duration += i; + if(Duration < 0) Duration = 0; + return Duration; +} + +int GetBonusDuration(){ + return Duration; +} + +int SetBonuses(){ + whom = environment(); + //tc("setting bonuses","yellow"); + if(!whom || ! living(whom)) return 0; + //tc("whom: "+identify(whom)); + if(sizeof(Stats)) + foreach(string key, int val in Stats){ + //tc(key + " " +val, "green"); + whom->AddStatBonus(key, val); + } + if(sizeof(Skills)) + foreach(string key, int val in Skills){ + whom->AddSkillBonus(key, val); + } + if(sizeof(Points)) + foreach(string key, int val in Points){ + //tc(key + " " +val, "cyan"); + switch(key){ + case "HP" : whom->AddHP(val);break; + case "XP" : whom->AddExperiencePoints(val);break; + case "SP" : whom->AddStaminaPoints(val);break; + case "MP" : whom->AddMagicPoints(val);break; + case "poison" : whom->AddPoison(val);break; + case "caffeine" : whom->AddCaffeine(val);break; + case "food" : whom->AddFood(val);break; + case "drink" : whom->AddDrink(val);break; + default : break; + } + } + return 1; +} + +int RemoveBonuses(){ + if(!whom && environment()) whom = environment(); + if(!whom || !living(whom)) return 0; + if(sizeof(Stats)) + foreach(string key, int val in Stats){ + whom->RemoveStatBonus(key); + } + if(sizeof(Skills)) + foreach(string key, int val in Skills){ + whom->RemoveSkillBonus(key); + } + return 1; +} + +int eventMove(mixed dest){ + int ret; + //tc("moving "+identify(this_object())+" from "+identify(environment())); + if(whom && environment() == whom){ + //tc("removing bonuses from "+identify(whom),"white"); + RemoveBonuses(); + whom = 0; + } + ret = ::eventMove(dest); + //tc("current location: "+identify(environment())); + return ret; +} + +int eventDestruct(){ + if(!valid_event(previous_object(), this_object())) return 0; + this_object()->eventMove(ROOM_FURNACE); + return ::eventDestruct(); +} + +string GetBonusName(){ + return bonusname; +} + +string SetBonusName(string name){ + return bonusname = name; +} + +mixed CanGet(object who){ return 0; } +mixed CanGive(object who){ return 0; } +mixed CanSell(object who){ return 0; } +mixed CanDrop(object who){ return 0; } +mixed CanPut(object who){ return 0; } diff --git a/lib/lib/bot.c b/lib/lib/bot.c new file mode 100644 index 0000000..ccc1867 --- /dev/null +++ b/lib/lib/bot.c @@ -0,0 +1,124 @@ +#include <lib.h> +#include ROOMS_H +#include <daemons.h> + +inherit LIB_SENTIENT; + +static int NoBotCondition = 0; + +static void create(){ + sentient::create(); +} + +void init(){ + sentient::init(); +} + +varargs int eventDie(mixed agent){ + int x; + string killer, death_annc; + object env = room_environment(this_object()); + if(objectp(agent)) killer = agent->GetName(); + if(stringp(agent)) killer = agent; + if(!agent) killer = "UNKNOWN"; + SetUndead(!(x = GetUndead())); + if( objectp(agent) ){ + if( x ) agent->eventDestroyEnemy(this_object()); + else agent->eventKillEnemy(this_object()); + } + if( env ){ + object *obs; + string *currs; + object ob; + string curr; + int i; + env = room_environment(this_object()); + ob = new(LIB_BOT_CORPSE); + ob->SetCorpse(this_object()); + ob->eventMove(environment()); + obs = filter(all_inventory(), (: !($1->GetRetainOnDeath()) :)); + i = sizeof(obs); + while(i--) obs[i]->eventMove(ob); + currs = this_object()->GetCurrencies() || ({}); + foreach(curr in currs){ + object pile; + int amt; + + if( amt = this_object()->GetCurrency(curr) ){ + pile = new(LIB_PILE); + pile->SetPile(curr, amt); + pile->eventMove(ob); + this_object()->AddCurrency(curr, -amt); + } + } + } + death_annc = killer + " has destroyed "+ this_object()->GetName()+"."; + if(env) tell_room(env,this_object()->GetName()+" breaks down!", + ({ this_object() }) ); + CHAT_D->eventSendChannel("SYSTEM","death",death_annc,0); + + this_object()->eventMove(ROOM_FURNACE); + return 1; +} + +string GetHealthShort(){ + string cl, sh; + float h; + + if( !(sh = this_object()->GetShort()) ) return 0; + h = percent(GetHealthPoints(), GetMaxHealthPoints()); + if( this_object()->GetNoBotCondition() || h > 90.0 ) cl = "%^BOLD%^GREEN%^"; + else if( h > 75.0 ) cl = "%^GREEN%^"; + else if( h > 50.0 ) cl = "%^BOLD%^BLUE%^"; + else if( h > 35.0 ) cl = "%^BLUE%^"; + else if( h > 20.0 ) cl = "%^BOLD%^RED%^"; + else cl = "%^RED%^"; + return cl + capitalize(sh); +} + +string GetLong(string nom){ + string *limbs; + string str; + float h; + + if(!nom) nom = this_object()->GetKeyName(); + str = ::GetLong(); + if(!(this_object()->GetNoBotCondition())){ + str += capitalize(nom); + h = percent(GetHealthPoints(), GetMaxHealthPoints()); + if( h < 10.0 ) str += " is barely functional.\n"; + else if( h < 20.0 ) str += " is functioning poorly.\n"; + else if( h < 30.0 ) str += " is severely damaged.\n"; + else if( h < 40.0 ) str += " is badly damaged.\n"; + else if( h < 50.0 ) str += " is damaged.\n"; + else if( h < 60.0 ) str += " has sustained minor damage.\n"; + else if( h < 70.0 ) str += " looks a bit battered.\n"; + else if( h < 80.0 ) str += " is in decent shape.\n"; + else if( h < 90.0 ) str += " is quite keen.\n"; + else str += " is operating at optimal levels.\n"; + } + limbs = GetMissingLimbs(); + if( sizeof(limbs) ){ + int i, maxi; + + str += nom + " is missing " + add_article(limbs[0]); + for(i=1, maxi = sizeof(limbs); i<maxi; i++){ + if( i < maxi-1 ) str += ", " + add_article(limbs[i]); + else { + if( maxi > 2 ) str += ","; + str += " and " + add_article(limbs[i]); + } + } + str += ".\n"; + } + return str; +} + +int SetNoBotCondition(int foo){ + NoBotCondition = foo; + return NoBotCondition; +} + +int GetNoBotCondition(){ + return NoBotCondition; +} diff --git a/lib/lib/burn.c b/lib/lib/burn.c new file mode 100644 index 0000000..e6709e7 --- /dev/null +++ b/lib/lib/burn.c @@ -0,0 +1,206 @@ +/* /lib/burn.c + * from the Dead Souls Object Library + * inheritable for things that burn + * created by Descartes of Borg 960512 + * Version: @(#) burn.c 1.3@(#) + * Last modified: 96/11/03 + */ + +#include <lib.h> +#include <medium.h> + +inherit LIB_FUEL; +inherit LIB_LIGHT; + +private int FuelRequired = 1; +private int Heat = 0; +private int MinHeat = 5; +private int BurnRate = 10; +private int BurntValue = 0; + +// abstract methods +int SetValue(int x); +// end abstract methods + +int GetBurning(); + +static void create(){ + fuel::create(); + light::create(); + this_object()->AddSave(({ "Heat" })); + call_out(function(){ + if( GetBurning() ) set_heart_beat(BurnRate); + }, 0); +} + +int GetBurning(){ + return (Heat >= MinHeat); +} + +int GetBurnRate(){ + return BurnRate; +} + +static int SetBurnRate(int x){ + return (BurnRate = x); +} + +int GetBurntValue(){ + return BurntValue; +} + +static int SetBurntValue(int x){ + return (BurntValue = x); +} + +int GetFuelRequired(){ + return FuelRequired; +} + +static int SetFuelRequired(int x){ + return (FuelRequired = x); +} + +int GetHeat(){ + return Heat; +} + +static int SetHeat(int x){ + return (Heat = x); +} + +int GetMinHeat(){ + return MinHeat; +} + +static int SetMinHeat(int x){ + return (MinHeat = x); +} + +mixed CanBurn(object who){ + object env = room_environment(); + if(!who && this_player()) who = this_player(); + if(!env){ + return "#That is nowhere!"; + } + if( env != who && env != environment(who)){ + return "#That is not within your reach!"; + } + if(env->GetMedium() > MEDIUM_SURFACE){ + return "#There is insufficient air."; + } + if( FuelRequired && !GetFuelAmount() ) + return capitalize(GetShort()) + " is out of fuel."; + if( GetBurning() ) return "It is already burning!"; + return light::CanLight(who); +} + +mixed direct_burn_obj_with_obj(){ + return CanBurn(this_player()); +} + +mixed indirect_burn_obj_with_obj(object target, object source){ + if( !target ) return (source == this_object()); + if( environment() != this_player() ) + return "#You must possess the source to use it."; + if( !GetBurning() ) return capitalize(GetShort()) + " is not burning!"; + return 1; +} + +mixed indirect_burn_obs_with_obj(object *targets, object source){ + if( !targets ) return (source == this_object()); + if( environment() != this_player() ) + return "#You must possess the source to use it."; + if( !GetBurning() ) return capitalize(GetShort()) + " is not burning!"; + return 1; +} + +mixed direct_light_obj(){ + mixed tmp = CanBurn(this_player()); + + if( tmp == 1 ){ + return "Light it with what?"; + } +} + +mixed direct_light_obj_with_obj(){ + return direct_burn_obj_with_obj(); +} + +mixed indirect_light_obj_with_obj(object target, object source){ + return indirect_burn_obj_with_obj(target, source); +} + +mixed indirect_light_obs_with_obj(object *targets, object source){ + return indirect_burn_obs_with_obj(targets, source); +} + +mixed CanExtinguish(object who){ + if( environment() != this_player() && + environment() != environment(this_player()) ){ + return "#That is not within your reach!"; + } + if( !GetBurning() ) return "It is not burning!"; + return 1; +} + +mixed direct_extinguish_obj(){ + return CanExtinguish(this_player()); +} + +mixed eventExtinguish(){ + eventDarken(); + set_heart_beat(Heat = 0); + return 1; +} + +mixed eventBurnOut(){ + if( FuelRequired ){ + SetFuelAmount(0); + } + SetValue(BurntValue); + eventDarken(); + set_heart_beat(Heat = 0); + return 1; +} + +varargs mixed eventBurn(object who, object what, int magic){ + int y; + if(magic){ + Heat = MinHeat; + if( FuelRequired ) set_heart_beat(BurnRate); + SetLit(1); + return 1; + } + if( !what ){ + if( Heat ) return 0; + else y = MinHeat; + } + else y = (Heat + what->GetHeat())/2; + if( y < Heat ) y = Heat; + if( !GetBurning() && y >= MinHeat ){ + if( FuelRequired ) set_heart_beat(BurnRate); + } + else if( GetBurning() && y < MinHeat ){ + if( FuelRequired ) set_heart_beat(0); + } + Heat = y; + if( Heat < 0 ) Heat = 0; + SetLit(1); + return 1; +} + +mixed eventLight(object who, object what){ + return eventBurn(who, what); +} + +static void heart_beat(){ + object env = room_environment(); + if( FuelRequired ){ + eventDecreaseFuel(1); + if( !GetFuelAmount() ) eventBurnOut(); + } + if(!env || env->GetMedium() > MEDIUM_SURFACE){ + eventExtinguish(); + } +} diff --git a/lib/lib/cedit.c b/lib/lib/cedit.c new file mode 100644 index 0000000..1dd7fb6 --- /dev/null +++ b/lib/lib/cedit.c @@ -0,0 +1,564 @@ +#define NOECHO 1 +#ifndef CED_DISABLED +#define CED_DISABLED 0 +#endif +#define CED_DEBUG 0 + +private static mapping FileData = ([]); +private static mapping ScreenData = ([]); + +static int *GetScreen(){ return ({ 79, 24 }); } +private static int ReceiveChars(string c); + +void create(){ + mixed tmp = GetScreen(); + if(!sizeof(ScreenData)){ + ScreenData = ([]); + } + if(sizeof(tmp)){ + ScreenData["maxcol"] = tmp[0]; + ScreenData["row"] = tmp[1] - 1; + } + else { + ScreenData["maxcol"] = 79; + ScreenData["row"] = 24; + } + ScreenData["maxrow"] = ScreenData["row"]; + ScreenData["col"] = 1; + ScreenData["charbuffer"] = ""; + ScreenData["sessionbuffer"] = " "; + ScreenData["insert"] = 1; + ScreenData["cedmode"] = 0; +} + +int ClearBuffers(){ + ScreenData["charbuffer"] = ""; + ScreenData["sessionbuffer"] = ""; + this_object()->SetCharbuffer(""); +} + +varargs int StatReport(string str){ + receive("\r\e["+(ScreenData["maxrow"])+";1H"); /* put cursor at bottom */ + receive("\r\e[2K"); /* Erase the entire bottom row */ + if(!str && sizeof(ScreenData["report"])){ + str = ScreenData["report"]; + ScreenData["report"] = ""; + } + if(!str){ +#if CED_DEBUG + str = "screen: "+ScreenData["row"]+","+ScreenData["col"]+ + " file: "+((FileData["topline"]+ScreenData["row"])-1)+ + ","+ScreenData["col"]+", topline: "+FileData["topline"]; +#else + str = "line: "+((FileData["topline"]+ScreenData["row"])-1)+ + " col: "+ScreenData["col"]+" file: "+ FileData["file"]; +#endif + } + receive(str); + /* now return cursor to prev pos */ + receive("\r\e["+ScreenData["row"]+";"+ScreenData["col"]+"H"); + return 1; +} + +varargs int RedrawScreen(int topline){ + int lastline = sizeof(FileData["map"]); + int line = 1; + mixed tmp = GetScreen(); + + if(sizeof(tmp)){ + ScreenData["maxcol"] = tmp[0]; + ScreenData["maxrow"] = tmp[1]; + } + else { + ScreenData["maxcol"] = 79; + ScreenData["maxrow"] = 24; + } + + if(!topline) topline = FileData["topline"]; + topline--; + if(topline > lastline) return 0; + receive("\r\e[1;1H"); + receive("\r\e[2K"); + while(line < (ScreenData["maxrow"] )){ + string trunky; // patches for linewrapping are welcome + int extra; + receive("\r\e["+line+";1H"); + receive("\e[2K"); + if(FileData["map"][(line+topline)]){ + trunky = FileData["map"][(line+topline)]; + extra = sizeof(trunky) - ScreenData["maxcol"]; + if(extra > 0) trunky = truncate(trunky, extra); + receive("\r\e[7l"+trunky+"\n"); + } + line++; + } + receive("\r\e["+ScreenData["row"]+";"+ScreenData["col"]+"H"); + ScreenData["charbuffer"] = ""; + return 1; +} + +static int UpdateScreen(){ + if(ScreenData["row"] > (ScreenData["maxrow"] - 1)){ + if(!ScreenData["goto"] && !ScreenData["searching"]) + ScreenData["row"] = (ScreenData["maxrow"] - 1); + if(FileData["topline"] < sizeof(FileData["map"])){ + FileData["topline"]++; + RedrawScreen(FileData["topline"]); + } + } + if(ScreenData["row"] < 1){ + ScreenData["row"] = 1; + FileData["topline"]--; + if(FileData["topline"] < 1){ + FileData["topline"] = 1; + } + RedrawScreen(FileData["topline"]); + } + if(ScreenData["col"] > ScreenData["maxcol"]) + ScreenData["col"] = ScreenData["maxcol"]; + if(ScreenData["col"] < 1) + ScreenData["col"] = 1; + if(ScreenData["col"] > sizeof(FileData["map"][(ScreenData["row"] + + FileData["topline"]) - 1])){ + ScreenData["col"] = sizeof(FileData["map"][(ScreenData["row"] + + FileData["topline"]) - 1])+1; /* lol */ + if(ScreenData["col"] < 1) ScreenData["col"] = 1; + } + receive("\r\e["+ScreenData["row"]+";"+ScreenData["col"]+"H"); + StatReport(); +} + +static varargs int CeditCollate(int x){ /* when lines need to be resorted */ + int i; + string tmp = ""; + string *lns = sort_array(keys(FileData["map"]), 1); + if(!sizeof(lns)) return 0; + FileData["contents"] = ""; + foreach(int l in lns){ + if(!undefinedp(x) && !(l + x)) continue; /* remove a line */ + tmp += FileData["map"][l]+"\n"; + if(l == x) tmp += "\n"; /* add a line */ + } + foreach(mixed key, mixed val in FileData["map"]){ + } + tmp = replace_string(tmp,"\n","\n"+sprintf("%c",17)); + i = 1; + foreach(mixed ln in explode(tmp,sprintf("%c",17))){ + FileData["map"][i] = replace_string(ln,"\n",""); + i++; + } + return i; +} + +static varargs int CeditSave(string file){ + string ret = ""; + int i; + string *lns = sort_array(keys(FileData["map"]), 1); + if(!sizeof(lns)) return 0; + foreach(int l in lns){ + ret += FileData["map"][l]+"\n"; + } + foreach(mixed key, mixed val in FileData["map"]){ + } +#if CED_DISABLED + StatReport("This alpha editor is not yet in shape to save files."); +#else + i = write_file(FileData["file"],ret,1); +#endif + return i; +} + +static int rBackspace(){ + int col, row; + string begin, end; + col = ScreenData["col"]; + row = (ScreenData["row"] + FileData["topline"]) - 1; + if(FileData["map"][row]){ + begin = FileData["map"][row][0..(col-3)]; + end = FileData["map"][row][(col-1)..]; + FileData["map"][row]=begin+end; + receive("\r\e[2K"); + receive(FileData["map"][row]); + ScreenData["col"]--; + if((ScreenData["maxrow"] - 1) != ScreenData["row"] && + FileData["map"][row+1]){ + receive("\r\e["+(ScreenData["row"]+1)+";"+ScreenData["col"]+"H"); + receive("\r\e[2K"); + receive(FileData["map"][row+1]); + } + receive("\r\e["+ScreenData["row"]+";"+ScreenData["col"]+"H"); + } + ScreenData["charbuffer"] = ""; + ScreenData["backspace"] = 0; +} + +static int rEnter(){ + if(!ScreenData["sessionbuffer"]) ScreenData["sessionbuffer"] = ""; + if(ScreenData["searching"]){ + int end, i, start = ScreenData["pregoto"][0]; + end = sort_array(keys(FileData["map"]), 1)[<1]; + ScreenData["searching"] = 0; + if(sizeof(ScreenData["search"])){ + ScreenData["oldsearch"] = ScreenData["search"]; + ScreenData["searchhit"] = 0; + } + else { + ScreenData["search"] = ScreenData["oldsearch"]; + start = ScreenData["searchhit"] + 1; + } + i = start; + while(i <= end){ + if(FileData["map"][i] && grepp(FileData["map"][i], + ScreenData["search"])){ + ScreenData["goto"] = 1; + ScreenData["search"] = 0; + ScreenData["searchhit"] = i; + ScreenData["charbuffer"] = itoa(i); + break; + } + i++; + } +#if CED_DEBUG + debug_message("ScreenData[\"search\"]: "+ScreenData["search"]); + debug_message("ScreenData[\"goto\"]: "+ScreenData["goto"]); + debug_message("ScreenData[\"charbuffer\"]: "+ScreenData["charbuffer"]); + debug_message("ScreenData[\"oldsearch\"]: "+ScreenData["oldsearch"]); +#endif + if(!ScreenData["goto"]){ + ScreenData["report"] = "String not found searching from line "+ + start; + } + } + if(ScreenData["goto"]){ + int top; + int line = atoi(ScreenData["charbuffer"]); + if(line && FileData["map"][line]){ + ScreenData["report"] = "Going to "+ScreenData["charbuffer"]; + top = line - ScreenData["pregoto"][0]; + if(top < 1) top = 1; + FileData["topline"] = top; + ScreenData["row"] = (ScreenData["pregoto"][0]) + 1; + ScreenData["col"] = 1; + } + else { + ScreenData["report"] = "No such line!"; + ScreenData["row"] = ScreenData["pregoto"][0]; + ScreenData["col"] = ScreenData["pregoto"][1]; + } + ScreenData["charbuffer"] = ""; + ScreenData["goto"] = 0; + ScreenData["pregoto"] = 0; + this_object()->SetNoEcho(1); + } + else { + ScreenData["charbuffer"] = "\n"; + ScreenData["sessionbuffer"] += sprintf("%c", 13); + CeditCollate((FileData["topline"]+ScreenData["row"])-1); + } + UpdateScreen(); + RedrawScreen(); + return 1; +} + +static int rAscii(string c){ + string tmp = c; + int row, col, arrowed; + if(!ScreenData["charbuffer"]) ScreenData["charbuffer"] = ""; + if(!ScreenData["sessionbuffer"]) ScreenData["sessionbuffer"] = ""; + if(ScreenData["searching"]){ + if(!ScreenData["search"]) ScreenData["search"] = ""; + ScreenData["charbuffer"] += c; + ScreenData["search"] += c; + return 1; + } + else if(ScreenData["goto"]){ + ScreenData["charbuffer"] += c; + return 1; + } + else { + ScreenData["charbuffer"] += c; + ScreenData["sessionbuffer"] += c; + } + if(sizeof(ScreenData["sessionbuffer"]) > 1024){ + ScreenData["sessionbuffer"] = ScreenData["sessionbuffer"][1..]; + } + if(sizeof(tmp) && tmp[0] != 30 && !ScreenData["sentinel"]){ + receive(tmp); + if(tmp[0] == 91){ + } + if(sizeof(ScreenData["sessionbuffer"]) > 2){ + if(ScreenData["sessionbuffer"][<1] == 91){ + } + } + if(ScreenData["insert"]){ + string begin; + string end; + col = ScreenData["col"]; + row = (ScreenData["row"] + FileData["topline"]) - 1; + if(FileData["map"][row]){ + begin = FileData["map"][row][0..(col-2)]; + end = FileData["map"][row][(col-1)..]; + FileData["map"][row]=begin+ScreenData["charbuffer"]+end; + } + } + else { + col = ScreenData["col"]; + row = (ScreenData["row"] + FileData["topline"]) - 1; + if(FileData["map"][row]){ + if(sizeof(FileData["map"][row]) >= col){ + FileData["map"][row][col-1] = ScreenData["charbuffer"][0]; + } + else { + FileData["map"][row] += ScreenData["charbuffer"]; + } + } + } + if(ScreenData["charbuffer"] == "\n"){ + CeditCollate(); + RedrawScreen(); + } + receive("\r\e[2K"); + if(FileData["map"][row]) receive(FileData["map"][row]); + ScreenData["col"]++; + receive("\r\e["+ScreenData["row"]+";"+ScreenData["col"]+"H"); + ScreenData["charbuffer"] = ""; + } + return 1; +} + +static int rDel(){ + string begin, end; + int col, row; + col = ScreenData["col"]; + row = (ScreenData["row"] + FileData["topline"]) - 1; + if(FileData["map"][row]){ + begin = FileData["map"][row][0..(col-2)]; + end = FileData["map"][row][(col)..]; + FileData["map"][row]=begin+end; + receive("\r\e[2K"); + receive(FileData["map"][row]); + if((ScreenData["maxrow"] - 1) != ScreenData["row"] && + FileData["map"][row+1]){ + receive("\r\e["+(ScreenData["row"]+1)+";"+ScreenData["col"]+"H"); + receive("\r\e[2K"); + receive(FileData["map"][row+1]); + } + receive("\r\e["+ScreenData["row"]+";"+ScreenData["col"]+"H"); + } + ScreenData["charbuffer"] = ""; + ScreenData["delete"] = 0; + return 1; +} + +int rCtrl(string c){ + string tmp; + int row, col, arrowed; + if(!ScreenData["charbuffer"]){ + ScreenData["charbuffer"] = this_object()->GetCharbuffer(); + } + + /* special chars */ + if(c == "q"){ /* Ctrl-Q for quitting without saving */ + write("Cancelling cedit!"); + ScreenData["cedmode"] = 0; + FileData = ([ "file" : "", "map" : ([]) ]); + ClearBuffers(); + } + else if(c == "g"){ /* Ctrl-G for going to a line */ + string tmpstr = "Please type the line number then press enter."; + int where = sizeof(tmpstr); + ScreenData["report"] = tmpstr; + ScreenData["pregoto"] = ({ ScreenData["row"], ScreenData["col"] }); + ScreenData["row"] = (ScreenData["maxrow"]); + ScreenData["col"] = (where + 1); + receive("\r\e["+ScreenData["row"]+";"+ScreenData["col"]+"H"); + ScreenData["charbuffer"] = ""; + ScreenData["goto"] = 1; + this_object()->SetNoEcho(0); + } + else if(c == "f"){ /* Ctrl-F */ + int targettopline, targetline, maxlines, lasty; + lasty = sort_array(keys(FileData["map"]), 1)[<1]; + targettopline = FileData["topline"] + (ScreenData["maxrow"] - 1); + if(targettopline > (lasty - ScreenData["maxrow"]) + 1){ + targettopline = (lasty - ScreenData["maxrow"]) + 1; + } + targetline = targettopline + ScreenData["row"]; + maxlines = sizeof(FileData["map"]); + if(targettopline > maxlines) targettopline = maxlines; + if(targetline > maxlines) targetline = maxlines; + FileData["topline"] = targettopline; + ScreenData["row"] = targetline; + RedrawScreen(FileData["topline"]); + } + else if(c == "b"){ /* Ctrl-B */ + int targettopline = FileData["topline"] - (ScreenData["maxrow"] - 1); + int targetline = targettopline - ScreenData["row"]; + if(targettopline < 1) targettopline = 1; + if(targetline < 1) targetline = 1; + FileData["topline"] = targettopline; + ScreenData["row"] = targetline; + RedrawScreen(FileData["topline"]); + } + else if(c == "l"){ /* Ctrl-L */ + RedrawScreen(FileData["topline"]); + ScreenData["charbuffer"] = ""; + } + else if(c == "d"){ /* Ctrl-D */ + row = (ScreenData["row"] + FileData["topline"]) - 1; + if(FileData["map"][row]){ + CeditCollate(-((FileData["topline"]+ScreenData["row"])-1)); + RedrawScreen(); + } + ScreenData["charbuffer"] = ""; + ScreenData["linedel"] = 0; + } + else if(c == "i"){ /* Ctrl-I */ + if(!ScreenData["insert"]){ + ScreenData["insert"] = 1; + ScreenData["report"] = "Insert mode enabled"; + } + } + else if(c == "o"){ /* Ctrl-O */ + if(ScreenData["insert"]){ + ScreenData["insert"] = 0; + ScreenData["report"] = "Overstrike mode enabled"; + } + } + else if(c == "x"){ /* Ctrl-X */ + int ret; +#if CED_DISABLED + ScreenData["report"] = "This alpha editor is not yet in shape to "+ + "save files."; +#else + if(sizeof(FileData["file"]) && sizeof(FileData["map"])){ + ret = CeditSave(); + if(ret){ + ScreenData["report"] = FileData["file"]+" saved."; + write("Exiting screen editor.\n"); + ScreenData["cedmode"] = 0; + FileData = ([ "file" : "", "map" : ([]) ]); + ClearBuffers(); + } + else ScreenData["report"] = FileData["file"]+" save FAILED."; + } +#endif + } + else if(c == "s"){ /* Ctrl-S */ + int ret; +#if CED_DISABLED + ScreenData["report"] = "This alpha editor is not yet in shape "+ + "to save files."; +#else + if(sizeof(FileData["file"]) && sizeof(FileData["map"])){ + ret = CeditSave(); + if(ret) ScreenData["report"] = FileData["file"]+" saved."; + else ScreenData["report"] = FileData["file"]+" save FAILED."; + } +#endif + } + else if(c == "c"){ /* Ctrl-C */ + ClearBuffers(); + } + else if(c == "31"){ /* Ctrl-/ for a search */ + string tmpstr = "Please type the word to search for: "; + int where = sizeof(tmpstr); + ScreenData["report"] = tmpstr; + ScreenData["pregoto"] = ({ ScreenData["row"], ScreenData["col"] }); + ScreenData["row"] = (ScreenData["maxrow"]); + ScreenData["col"] = (where + 1); + receive("\r\e["+ScreenData["row"]+";"+ScreenData["col"]+"H"); + ScreenData["charbuffer"] = ""; + ScreenData["searching"] = 1; + this_object()->SetNoEcho(0); + } + else if(c == "28"){ /* Ctrl-\ */ + ScreenData["report"] = "esc-28 received"; + } + if(ScreenData["cedmode"]) UpdateScreen(); + else { + this_object()->SetCharmode(1); + this_object()->erase_prompt(); + this_object()->write_prompt(); + } + return 1; +} + +static int rArrow(string str){ + switch(str){ + int lasty; + case "up" : ScreenData["row"]--; break; + case "down" : + if((ScreenData["row"] > (ScreenData["maxrow"] - 2) )){ + lasty = sort_array(keys(FileData["map"]), 1)[<1]; + if((FileData["topline"] > (lasty - ScreenData["maxrow"]) + 1)){ + break; + } + } + ScreenData["row"]++; + break; + case "left" : ScreenData["col"]--; break; + case "right" : ScreenData["col"]++; break; + } + ScreenData["charbuffer"] = ""; + UpdateScreen(); + return 1; +} + +varargs int SetCedmode(int x, string file){ + int num; + mixed tmp, lines; +#ifndef __DSLIB__ + return 0; +#else + FileData = ([ "file" : "", "map" : ([]) ]); + if(!this_player() || this_player() != this_object()) return 0; + if(!sizeof(file)) file = ""; + if(x){ + ClearBuffers(); + ScreenData["cedmode"] = x; + ScreenData["insert"] = 1; + FileData["topline"] = 1; + if(!FileData["map"]) FileData["map"] = ([]); + if(true()){ + FileData["file"] = file; + tmp = read_file(FileData["file"]); + if(!tmp){ + string line = repeat_string(" ", ScreenData["maxcol"])+"\n"; + lines = ScreenData["maxrow"]; + FileData["contents"] = ""; + while(lines){ + lines--; + FileData["contents"] += line; + } + } + tmp = replace_string(tmp,"\n","\n"+sprintf("%c",17)); + tmp = replace_string(tmp,"\t"," "); + lines = 1; + foreach(mixed ln in explode(tmp,sprintf("%c",17))){ + FileData["map"][lines] = replace_string(ln,"\n",""); + lines++; + } + } + receive("\r\e[2J"); /* cls */ + receive("\r\e[7l"); /* no wrapping */ + ScreenData["row"] = 1; + ScreenData["col"] = 1; + ScreenData["report"] = "Editing "+FileData["file"]; + RedrawScreen(FileData["topline"]); + } + else { + ScreenData["cedmode"] = 0; + } + return ScreenData["cedmode"]; +#endif +} + +int GetCedmode(){ + return ScreenData["cedmode"]; +} + +static int rAnsi(string str){ + return 1; +} + diff --git a/lib/lib/cgi.c b/lib/lib/cgi.c new file mode 100644 index 0000000..d848c29 --- /dev/null +++ b/lib/lib/cgi.c @@ -0,0 +1,30 @@ +#include <lib.h> + +mapping ParsePost(string args){ + object ob = previous_object(); + string boundary = "--"+ ob->GetBoundary(); + string file, junk; + string *tmp_arr; + mapping ret = ([]); + int start = 1; + + if(last(args,2) == "--") args = truncate(args,2); + + tmp_arr = explode(args,boundary); + + foreach(string element in tmp_arr){ + string name,data,junk1, junk2; + string *tmp_arr2; + sscanf(element,"%sname=\"%s\"%s",junk1, name, junk2); + if(!name) continue; + if(sscanf(element,"%sfilename=\"%s\"%s",junk1, file, junk2) == 3){ + ret["filename"] = file; + } + tmp_arr2 = explode(element,"\n"); + if(sizeof(tmp_arr2) > 1 && grepp(tmp_arr2[1],"Content-Type:")) start = 2; + data = implode(tmp_arr2[start..],"\n"); + if(data[0..0] == "\n") data = data[1..]; + ret[name] = data; + } + return ret; +} diff --git a/lib/lib/chamber.c b/lib/lib/chamber.c new file mode 100644 index 0000000..c934967 --- /dev/null +++ b/lib/lib/chamber.c @@ -0,0 +1,362 @@ +#include <lib.h> +#include <daemons.h> +#include <medium.h> +#include ROOMS_H +#include <position.h> + +#define SOBER_COMBAT + +inherit LIB_BOT; +inherit LIB_ENTER; +inherit LIB_EXITS; +inherit LIB_READ; + +private object array DummyItems = ({}); +mapping ItemsMap = ([]); +private static mixed global_item; +string ChamberInterior = ""; + +mixed GetChamberInterior(); + +void create(){ + bot::create(); + enter::create(); + SetPacifist(1); + SetNoCondition(1); + SetNoBotCondition(1); + SetEnterMessage(""); +} + +void init(){ + string rvoid = ROOMS_D->GetVoid(this_object()); + string exterior = rvoid; + bot::init(); + if(environment()){ + exterior = file_name(environment()); + } + SetEnter( file_name(this_object())); + SetExits( (["out": exterior ]) ); +} + +int inventory_accessible(){ + if(environment(this_player()) == this_object()){ + return 1; + } + return 0; +} + +mixed eventMount(object who){ + int rider_weight; + string weight = "weight"; + if(!who) return 0; + if(environment() && environment()->GetMedium() == MEDIUM_SPACE){ + weight = "mass"; + } + rider_weight = who->GetMass(); + if(!environment(this_object())) return 0; + if(environment(who) && environment(who) == this_object()){ + return write("You are already mounted."); + } + if(rider_weight + this_object()->GetCarriedMass() > this_object()->GetMaxCarry()){ + return write("This chamber cannot handle that much "+weight+"."); + } + else { + string int_desc = GetChamberInterior(); + this_object()->SetNoClean(1); + write("You enter "+this_object()->GetShort()+"."); + if(int_desc) write(int_desc); + say(who->GetName()+" enters "+this_object()->GetShort()+"."); + who->SetProperty("mount", this_object()); + if(who->eventMove(this_object())) return AddRider(who); + else return 0; + } +} + +varargs mixed eventEnter(object who, string what, string verb){ + if(query_verb() == "fly"){ + return this_object()->eventDrive(what); + } + return eventMount(who); +} + +mixed CanGo(object who, string str){ + if( who->GetParalyzed() ) return "You are unable to move."; + else return 1; +} + +mixed eventGo(object who, string str){ + if(query_verb() == "fly"){ + return this_object()->eventDrive(str); + } + if(str == "out"){ + return eventDismount(who); + } + else return exits::eventGo(who, str); +} + +mixed direct_drive(){ + return this_object()->GetMount(); +} + +mixed direct_drive_word_str(){ + return this_object()->GetMount(); +} + +mixed direct_fly(){ + return this_object()->GetMount(); +} + +mixed direct_fly_word_str(){ + return this_object()->GetMount(); +} + +int eventDrive(string direction){ + string travel_cmd, s1, s2; + object *guys = get_livings(this_object()); +#if 0 + if(interactive(this_object())) return 0; + if(sscanf(direction,"%s %s",s1,s2) == 2){ + if(s1 == "enter" || s1 == "into") travel_cmd = "enter"; + } + + if(!s1 || s1 == "") switch(this_object()->GetPosition()){ + case POSITION_STANDING : travel_cmd = "go";break; + case POSITION_SITTING : travel_cmd = "crawl";break; + case POSITION_LYING : travel_cmd = "crawl";break; + case POSITION_FLYING : travel_cmd = "fly";break; + default : travel_cmd = "go"; + } + else direction = s2; + this_object()->eventForce(travel_cmd+" "+direction); +#endif + return 1; +} + +varargs string GetInternalDesc(){ + object array items = all_inventory(); + string desc; + int surfacep; + + surfacep = inherits(LIB_SURFACE , this_object()); + + desc = ""; + if(this_object()->CanClose() && GetOpacity() > 33){ + if(this_object()->GetClosed()) desc += " It is closed. "; + else desc += " It is open. "; + } + if(!surfacep) desc = desc + capitalize(add_article(GetShort(), 1)); + if(surfacep) desc = "On "+add_article(GetShort(), 1); + items = filter(items, (: !($1->isDummy()) && !($1->GetInvis()) :)); + if( sizeof(items) ){ + if(surfacep){ + desc = desc+" you see " + item_list(items) + "."; + } + else desc = desc + " contains " + item_list(items) + "."; + } + else { + if(!surfacep) desc = desc + " is completely empty."; + else desc = desc + " you see nothing."; + } + return desc; +} + +object array GetDummyItems(){ + DummyItems = ({}); + foreach(object item in all_inventory(this_object())){ + if(base_name(item) == LIB_DUMMY ){ + DummyItems += ({ item }); + } + } + return DummyItems; +} + +varargs void AddItem(mixed item, mixed val, mixed adjectives){ + object ob, same_dummy; + object *dummies = filter(all_inventory(this_object()), (: base_name(LIB_DUMMY) :) ); + global_item = item; + + if( objectp(item) ){ + same_dummy = filter(dummies,(: ($1->GetId())[0] == (global_item->GetId())[0] :)); + if(sizeof(same_dummy) && base_name(item) != LIB_ELEVATOR_BUTTON){ + return; + } + ob = item; + } + else { + if( stringp(item) ){ + item = ({ item }); + } + if( stringp(adjectives) ){ + adjectives = ({ adjectives }); + } + same_dummy = filter(dummies,(: member_array(global_item[0],$1->GetId()) != -1 :)); + if(sizeof(same_dummy)) return; + ob = new(LIB_DUMMY, item, val, adjectives); + } + ob->eventMove(this_object()); + DummyItems = ({ DummyItems..., ob }); +} + +mapping RemoveItem(mixed item){ + if( objectp(item) ){ + DummyItems -= ({ item }); + item->eventDestruct(); + return copy(Items); + } + else if( !arrayp(item) ){ + item = ({ item }); + } + foreach(object ob in GetDummyItems()){ + if( sizeof(ob->GetId() & item) ){ + ob->eventDestruct(); + DummyItems -= ({ ob }); + return copy(Items); + } + } +} + +mapping SetItems(mixed items){ + if(sizeof(DummyItems)) DummyItems->eventDestruct(); + DummyItems = ({}); + if( arrayp(items) ){ + items->eventMove(this_object()); + DummyItems = items; + } + else if( mapp(items) ){ + ItemsMap = items; + foreach(mixed key, mixed val in items){ + string array adjs = ({}); + object ob; + + if( stringp(key) ){ + key = ({ key }); + } + else { + if( sizeof(key) == 2 && arrayp(key[0]) ){ + adjs = key[1]; + key = key[0]; + } + } + ob = new(LIB_DUMMY, key, val, adjs); + ob->eventMove(this_object()); + DummyItems = ({ DummyItems..., ob }); + } + } + else { + error("Bad argument 1 to SetItems(), expected object array or " + "mapping.\n"); + } + return copy(ItemsMap); +} + +mapping GetItemsMap(){ + return copy(ItemsMap); +} + +void AddRead(mixed item, mixed val){ + if( stringp(item) ){ + item = ({ item }); + } + foreach(string tmp in item){ + foreach(object ob in GetDummyItems()){ + if( ob->id(tmp) ){ + ob->SetRead(val); + break; + } + } + } +} + +void RemoveRead(mixed item){ + foreach(object ob in GetDummyItems()){ + if( stringp(item) ){ + if( ob->id(item) ){ + ob->SetRead(0); + } + } + else if( arrayp(item) ){ + if( sizeof(ob->GetId() & item) ){ + ob->SetRead(0); + } + } + } +} + +varargs void SetRead(mixed items, mixed arg){ + if( !mapp(items) ){ + AddRead(items, arg); + return; + } + foreach(mixed key, mixed val in items){ + AddRead(key, val); + } +} + +varargs int eventDie(mixed agent){ + object *riders=get_livings(this_object()); + if(riders && sizeof(riders)){ + foreach(object rider in riders) eventBuck(rider); + } + return bot::eventDie(agent); +} + +int SetChamberInterior(mixed arg){ + ChamberInterior = arg; + return 1; +} + +mixed GetChamberInterior(){ + mixed ret; + if(stringp(ChamberInterior)) return ChamberInterior; + else if(functionp(ChamberInterior)){ + ret = evaluate(ChamberInterior); + if(!stringp(ret)) return 0; + return ret; + } + return 0; +} + +varargs int CanFly(mixed who, mixed where){ + if(where && !(environment(this_object())->GetExit(where)) && + !(environment(this_object())->GetEnter(where))) return 0; + + if(this_object()->GetPosition() == POSITION_FLYING) return 1; + return 0; +} + +int eventMove(mixed dest){ + int ret; + object env = environment(); + string location; + + if(!env) location = ROOM_START; + else if(clonep(env)) location = file_name(env); + else location = base_name(env); + + if(location) this_object()->SetProperty("LastLocation", location); + ret = ::eventMove(dest); + AddStaminaPoints(GetMaxStaminaPoints()); + return ret; +} + +varargs int eventPrint(string msg, mixed arg2, mixed arg3){ + object env = environment(this_object()); + if(this_object()->GetClosed() || GetOpacity() > 50) return 0; + return bot::eventPrint(msg, arg2, arg3); +} + +varargs mixed eventHearTalk(object who, object target, int cls, string verb, + string msg, string lang){ + object env = environment(this_object()); + if(this_object()->GetClosed()) return 0; + return bot::eventHearTalk(who, target, cls, verb, msg, lang); +} + +varargs mixed GetBefriended(mixed who){ + return 1; +} + +int eventRide(string direction){ + return 0; +} + diff --git a/lib/lib/chapel.c b/lib/lib/chapel.c new file mode 100644 index 0000000..2f72ee2 --- /dev/null +++ b/lib/lib/chapel.c @@ -0,0 +1,116 @@ +/* /lib/chapel.c + * from the Dead Souls Object Library + * allows people to marry + * created by Descartes of Borg 951210 + * Version: @(#) chapel.c 1.2@(#) + * Last modified: 96/10/09 + */ + +#include <lib.h> +#include "include/chapel.h" + +inherit LIB_ROOM; + +private int AllowSacrifice, SacrificeType; +private string array Classes, Religion, Deities, DeityIds; + +/* ********** /lib/chapel.c apply methods ********** */ +static void create(){ + room::create(); + Classes = ({}); + Religion = allocate(2); + Deities = ({}); + DeityIds = ({}); + AllowSacrifice = 0; + SacrificeType = 0; +} + +/* ********** /lib/chapel.c modal methods ********** */ +mixed CanMarry(object who, object spouse1, object spouse2){ + mixed tmp; + + if( (tmp = spouse1->CanMarry(who, spouse2)) != 1 ){ + if( tmp ) return tmp; + else return spouse1->GetName() + " cannot be married."; + } + if( (tmp = spouse2->CanMarry(who, spouse1)) != 1 ){ + if( tmp ) return tmp; + else return spouse2->GetName() + " cannot be married."; + } + if( archp(who) ){ + return 1; + } + return 1; +} + +mixed CanSacrifice(object who, object what, string deus){ + if( who->GetReligion(1) != Religion[1] ) + return "You must hold the beliefs of " + Religion[1] + " to do that."; + if( !(what->GetVendorType() & SacrificeType) ) + return "You cannot sacrifice that here."; + if( member_array(deus, DeityIds) == -1 ) + return "You do not worship anything called \"" + deus + "\"."; + return AllowSacrifice; +} + +mixed eventMarry(object who, object spouse1, object spouse2){ + mixed tmp; + + if( (tmp = spouse1->eventMarry(who, spouse2)) != 1 ) return tmp; + if( (tmp = spouse2->eventMarry(who, spouse1)) != 1 ){ + spouse1->SetMarried(0); + return tmp; + } + spouse1->eventPrint(who->GetName() + " weds you to " + + spouse2->GetName() + "."); + spouse2->eventPrint(who->GetName() + " weds you to " + + spouse1->GetName() + "."); + who->eventPrint("You join " + spouse1->GetName() + " to " + + spouse2->GetName() + " in marriage."); + this_object()->eventPrint(who->GetName() + " joins " + + spouse1->GetName() + " and " + + spouse2->GetName() + ".", + ({ spouse1, spouse2, who })); + who->AddSkillPoints("faith", random(100)); + return 1; +} + +mixed eventSacrifice(object who, object what, string deus){ + who->eventPrint("You attempt to make a sacrifice, but nothing happens."); + return 1; +} + +/* ********** /lib/chapel.c event methods ********** */ +int SetAllowSacrifice(int x){ return (AllowSacrifice = x); } + +int GetAllowSacrifice(){ return AllowSacrifice; } + +string *SetClasses(string *rc){ return (Classes = rc); } + +string *GetClasses(){ return Classes; } + +string *SetDeities(string *deities){ + string *ids = ({}); + + Deities = deities; + foreach(string deus in deities) + ids += explode(lower_case(deus), " "); + DeityIds = ids; + return Deities; +} + +string *GetDeities(){ return Deities; } + +string *SetReligion(string adj, string noun){ + Religion[0] = adj; + Religion[1] = noun; + return Religion; +} + +varargs string GetReligion(int flag){ return Religion[flag]; } + +int SetSacrificeType(int x){ return (SacrificeType = x); } + +int AddSacrificeType(int x){ return (SacrificeType |= x); } + +int GetSacrificeType(){ return SacrificeType; } diff --git a/lib/lib/chario.c b/lib/lib/chario.c new file mode 100644 index 0000000..d955f1b --- /dev/null +++ b/lib/lib/chario.c @@ -0,0 +1,250 @@ +/* Character Input/Output handler. + * Character mode is meant to allow the user to issue special + * requests to the mud using escape sequences. However, it is + * not always as simple as "escape character X". + * + * This inherited object manages a get_char() loop that accumulates + * input into CharStuff["charbuffer"], and watches for sets of + * substrings that match known escape sequences, such as "up arrow" + * and the like, which are not just one character. + * + * When an ESC is received (it is assumed that the driver translates + * 0x1b to 0x1e with the ANSI_SUBSTITUTE define, making '30' the + * escape char) then the subsequent input is not put into + * CharStuff["charbuffer"] but rather into CharStuff["escape"] + * until a recognized escape sequence is completed in + * CharStuff["escape"] or until some arbitrary number of characters + * being input indicates that an unknown escape sequence has + * been received. At that point the escape sequence is either + * processed or discarded, and accumulation into CharStuff["charbuffer"] + * resumes. + * -Crat 08FEB2009 + * + * Wow what's that even mean? + * -Crat 22SEP2009 + */ + +#include <daemons.h> +#include <lib.h> +#include "include/nmsh.h" + +#define CHAR_DEBUG 0 + +private static mapping CharStuff; + +int rEsc(); + +void create(){ + CharStuff = ([ + "charmode" : 1, /* are we in character mode */ + "noecho" : 1, /* do we echo input characters */ + "charbuffer" : "", /* what we've typed of this line so far */ + "tempbuffer" : "", /* the last line, before alias expansion */ + "charshell" : 0, /* hell if i remember */ + ]); +} + +static int ReceiveChars(string str){ + string s; + int c; + + if(!this_object()) return 0; + + if(str){ + c = str[0]; + s = str[0..0]; + } + + if(!CharStuff["charbuffer"]) CharStuff["charbuffer"] = ""; + +#if CHAR_DEBUG + if(sizeof(str) > 1) debug("unexpected string: "+str); + else debug("CHARIO received: "+s+", aka: "+c, "black"); +#endif + + if(!sizeof(CharStuff["escape"]) && (c > 31 && c < 127)){ + /* Printable character, and we're not waiting on an ESC seq, + * Let's add it to the character buffer, and then + * "normalize" any Pinkfish sequences. + */ + CharStuff["charbuffer"] += s; + if(sizeof(CharStuff["charbuffer"]) > 1 && last(CharStuff["charbuffer"],2) == "%^"){ + /* replace pinkfish to avoid weirdness */ + CharStuff["charbuffer"] = truncate(CharStuff["charbuffer"],2); + CharStuff["charbuffer"] += "%%^^"; + } + this_object()->rAscii(s); + get_char("ReceiveChars", CharStuff["noecho"]); + return 1; + } + + if(sizeof(CharStuff["escape"]) && + member_array(30, CharStuff["escape"]) != -1){ + int cl; + string esc; + CharStuff["escape"] += s; + esc = CharStuff["escape"]; + if(last(esc,1) == "H" || last(esc,1) == "R" || sizeof(esc) > 10){ + cl = 1; + this_object()->rAnsi(esc); + } + else if(sizeof(esc) > 2 && esc[1] == 91){ + switch(esc[2]){ + case 65 : this_object()->rArrow("up"); cl = 1; break; + case 66 : this_object()->rArrow("down"); cl = 1; break; + case 68 : this_object()->rArrow("left"); cl = 1; break; + case 67 : this_object()->rArrow("right"); cl = 1; break; + case 51 : + if(sizeof(esc) > 3 && esc[3] == 126){ + this_object()->rDel(); + cl = 1; + } + break; + } + } + if(cl) CharStuff["escape"] = ""; + get_char("ReceiveChars", CharStuff["noecho"]); + return 1; + } + + switch(c){ + case 0 : case 8 : case 127 : this_object()->rBackspace(); break; + case 1 : this_object()->rCtrl("a"); break; + case 2 : this_object()->rCtrl("b"); break; + case 3 : this_object()->rCtrl("c"); break; + case 4 : this_object()->rCtrl("d"); break; + case 5 : this_object()->rCtrl("e"); break; + case 6 : this_object()->rCtrl("f"); break; + case 7 : this_object()->rCtrl("g"); break; + case 9 : this_object()->rCtrl("i"); break; /* aka Tab */ + case 10 : case 13: this_object()->rEnter(); break; + case 11 : this_object()->rCtrl("k"); break; + case 12 : this_object()->rCtrl("l"); break; + case 14 : this_object()->rCtrl("n"); break; + case 15 : this_object()->rCtrl("o"); break; + case 16 : this_object()->rCtrl("p"); break; + case 17 : this_object()->rCtrl("q"); break; + case 18 : this_object()->rCtrl("r"); break; + case 19 : this_object()->rCtrl("s"); break; + case 20 : this_object()->rCtrl("t"); break; + case 21 : this_object()->rCtrl("u"); break; + case 22 : this_object()->rCtrl("v"); break; + case 23 : this_object()->rCtrl("w"); break; + case 24 : this_object()->rCtrl("x"); break; + case 25 : this_object()->rCtrl("y"); break; + case 26 : this_object()->rCtrl("z"); break; + case 28 : this_object()->rCtrl("28"); break; + case 30 : rEsc(); break; + case 31 : this_object()->rCtrl("31"); break; + } + + if(!this_object()){ + // Probably a warmboot or userload + return 0; + } + if(in_edit(this_object())) CharStuff["noecho"] = 0; + else CharStuff["noecho"] = 1; + +#ifdef __GET_CHAR_IS_BUFFERED__ + if(CharStuff["charmode"]) get_char("ReceiveChars", CharStuff["noecho"]); +#endif + this_object()->RedrawPrompt(); + return CharStuff["charmode"]; +} + +varargs int CancelCharmode(int extra){ + int ret = 1; +#if CHAR_DEBUG + debug("cancelling! stack: "+get_stack()); +#endif + if(!CharStuff) CharStuff = ([]); + flush_messages(); + CharStuff["charbuffer"] = ""; + if(!CharStuff["charmode"] && !query_charmode(this_object())) return 0; + CharStuff["charmode"] = 0; +#ifdef __DSLIB__ + remove_get_char(this_object()); + remove_charmode(this_object()); +#else + ReceiveChars(sprintf("%c",13)); +#endif + if(extra) ReceiveChars(sprintf("%c",13)); + this_object()->SetProperty("was_charmode", 0); + this_object()->SetProperty("reprompt", 0); + return ret; +} + +int SetCharmode(int x){ + if(!x) CharStuff["charmode"] = 0; +#ifdef __GET_CHAR_IS_BUFFERED__ + else CharStuff["charmode"] = 1; + remove_get_char(this_object()); + if(!(this_object()->GetCedmode())){ + get_char("ReceiveChars", CharStuff["noecho"]); + } + else get_char("ReceiveChar", CharStuff["noecho"]); +#endif + return CharStuff["charmode"]; +} + +int GetCharmode(){ + if(!CharStuff) CharStuff = ([]); + return CharStuff["charmode"]; +} + +static string GetCharbuffer(){ + if(!CharStuff) CharStuff = ([]); + return (CharStuff["charbuffer"] || "" ); +} + +static string SetCharbuffer(string str){ + if(!CharStuff) CharStuff = ([]); + return CharStuff["charbuffer"] = ( str || "" ); +} + +static string GetTempbuffer(){ + if(!CharStuff) CharStuff = ([]); + return (CharStuff["tempbuffer"] || "" ); +} + +static string SetTempbuffer(string str){ + if(!CharStuff) CharStuff = ([]); + return CharStuff["tempbuffer"] = ( str || "" ); +} + +void CheckCharmode(){ + if(!in_edit() && !in_input() && this_object()->GetProperty("was_charmode")){ + CharStuff["charmode"] = 1; + } + if(CharStuff["charmode"] && !query_charmode(this_object())){ + if(!in_edit() && !in_input()) SetCharmode(CharStuff["charmode"]); + if(!this_player() || this_player() != this_object()){ + SetCharmode(1); + this_object()->RedrawPrompt(); + } + } + if(!CharStuff["charmode"] && query_charmode(this_object()) > 0){ + CancelCharmode(); + } +} + +void heart_beat(){ + CheckCharmode(); +} + +int rEsc(){ + CharStuff["escape"] = sprintf("%c", 30); + if(in_edit(this_object())) CharStuff["noecho"] = 0; + else CharStuff["noecho"] = 1; + return 1; +} + +int SetNoEcho(int x){ + if(x) CharStuff["noecho"] = 1; + else CharStuff["noecho"] = 0; + return CharStuff["noecho"]; +} + +int GetNoEcho(){ + return CharStuff["noecho"]; +} diff --git a/lib/lib/chat.c b/lib/lib/chat.c new file mode 100644 index 0000000..4195752 --- /dev/null +++ b/lib/lib/chat.c @@ -0,0 +1,249 @@ +/* /lib/chat.c + * from the Dead Souls LPC Library + * chat enabling object + * created by Descartes of Borg 950323 + */ + +#include <lib.h> +#include <daemons.h> +#include "include/chat.h" + +private string *RestrictedChannels; +private static mapping Channels; +private int NoChanColors = 0; +private mapping GagMutes = ([]); + +static void create(){ + RestrictedChannels = ({ }); + Channels = ([ ]); + GagMutes = (["local_mute":0,"remote_mute":0,"local_gag":0,"remote_gag":0]); +} + +mapping returnChannels(){ + return Channels; +} + +static string chat_command(string str){ + string cmd, arg, tmp; + int x; + if( (x = strsrch(str, " ")) == -1){ + cmd = str; + arg = ""; + } + else { + cmd = str[0..(x-1)]; + arg = str[(x+1)..]; + } + if( cmd == "list" && CHAT_D->cmdChannel(cmd, arg) ) return ""; + else if( Channels[cmd] && CHAT_D->cmdChannel(cmd, arg) ) return ""; + else if( (sscanf(cmd, "%semote", tmp) || sscanf(cmd, "%s:", tmp) + || sscanf(cmd, "%s|%*s", tmp)) + && Channels[tmp] ){ + if( CHAT_D->cmdChannel(cmd, arg) ) return ""; + else return str; + } + else return str; +} + +static void net_dead(){ + CHAT_D->eventRemoveMember(keys(Channels)); +} + +void eventReconnect(){ + CHAT_D->eventRegisterMember(keys(Channels)); +} + +int eventDestruct(){ + if(!valid_event(previous_object(), this_object())) return 0; + if(CHAT_D->eventRemoveMember(keys((Channels || ([]))))) return 1; + else return 0; +} + +string *AddChannel(mixed val){ + string *tmp; + int i, maxi; + + if( stringp(val) ) val = ({ val }); + else if( !pointerp(val) ) error("Bad argument 1 to AddChannel().\n"); + val = val - RestrictedChannels; + if(arrayp(val)){ + foreach(string channel in val){ + if(this_player()->GetExtraChannels() && + member_array(channel,this_player()->GetExtraChannels()) == -1){ + this_player()->AddExtraChannels( ({ channel }) ); + } + } + } + tmp = CHAT_D->eventRegisterMember(val); + for(i=0, maxi = sizeof(tmp); i < maxi; i++) Channels[tmp[i]] = 1; + return keys(Channels); +} + +string *RemoveChannel(mixed val){ + string *tmp; + int i, maxi; + object prev = this_player(); + + if( stringp(val) ) val = ({ val }); + if(!prev ||(prev != this_object() && !adminp(prev))){ + return keys(Channels); + } + else if( !pointerp(val) ) error("Bad argument 1 to RemoveChannel().\n"); + if(arrayp(val)){ + foreach(string channel in val){ + if(member_array(channel,this_player()->GetExtraChannels()) != -1){ + this_player()->RemoveExtraChannels( ({ channel }) ); + } + } + } + tmp = CHAT_D->eventRemoveMember(val); + for(i=0, maxi = sizeof(tmp); i < maxi; i++) map_delete(Channels, tmp[i]); + return keys(Channels); +} + +string *GetChannels(){ return keys(Channels); } +int GetChannel(string chan){ + return ( member_array(chan, keys(Channels)) != -1 ); +} + +int GetNoChanColors(){ + return NoChanColors; +} + +int SetNoChanColors(int x){ + if(x) NoChanColors = 1; + else NoChanColors = 0; + return NoChanColors; +} + +string *RestrictChannel(mixed val){ + if( stringp(val) ) val = ({ val }); + else if( !pointerp(val) ) error("Bad argument 1 to RestrictChannel().\n"); + + // Only allow restriction of channels that are possesed by the object. + val = filter(val, (:Channels[$1]:)); + RestrictedChannels = distinct_array(RestrictedChannels + val); + RemoveChannel(val); + return RestrictedChannels; +} + +string *UnrestrictChannel(mixed val){ + if( stringp(val) ) val = ({ val }); + else if( !pointerp(val) ) error("Bad argument 1 to UnrestrictChannel().\n"); + + // Only add channels that where restricted. + val = filter(val, (:member_array($1, RestrictedChannels) != -1:)); + RestrictedChannels -= val; + AddChannel(val); + return RestrictedChannels; +} + +string *GetRestrictedChannels(){ return (RestrictedChannels + ({})); } + +int GetMutedType(string type){ + if(type == "local" && GagMutes["local_mute"]) return 1; + if(type == "remote" && GagMutes["remote_mute"]) return 1; + if(type == "all" && GagMutes["remote_mute"] && + GagMutes["local_mute"]) return 1; + return 0; +} + +int GetMuted(string channel){ + channel = CHAT_D->GetRemoteChannel(channel); + if(GagMutes["remote_mute"] + && member_array(channel, CHAT_D->GetRemoteChannels()) != -1 + && member_array(channel, CHAT_D->GetLocalChannels()) == -1){ + return 1; + } + if(GagMutes["local_mute"] + && ( member_array(channel, CHAT_D->GetRemoteChannels()) == -1 + || member_array(channel, CHAT_D->GetLocalChannels()) != -1)){ + return 1; + } + return 0; +} + +int GetGaggedType(string type){ + if(type == "local" && GagMutes["local_gag"]) return 1; + if(type == "remote" && GagMutes["remote_gag"]) return 1; + if(type == "all" && GagMutes["remote_gag"] && + GagMutes["local_gag"]) return 1; + return 0; +} + +int GetGagged(string channel){ + channel = CHAT_D->GetRemoteChannel(channel); + if(GagMutes["remote_gag"] + && member_array(channel, CHAT_D->GetRemoteChannels()) != -1 + && member_array(channel, CHAT_D->GetLocalChannels()) == -1){ + return 1; + } + if(GagMutes["local_gag"] + && ( member_array(channel, CHAT_D->GetRemoteChannels()) == -1 + || member_array(channel, CHAT_D->GetLocalChannels()) != -1)){ + return 1; + } + return 0; +} + +int SetGagged(string type, mixed x){ + object prev = this_player(); + int ret; + if(!prev || (prev != this_object() && !adminp(prev))) return 0; + if(undefinedp(x) || !intp(x)) x = 1; + if(!type) type = "all"; + switch(type){ + case "local" : + ret = GagMutes["local_gag"]; + if(x > 0) ret = ((ret != 2) ? (adminp(prev) ? 2 : 1) : 2); + else ret = ((ret == 2) ? (adminp(prev) ? 0 : 2) : 0); + GagMutes["local_gag"] = ret; + break; + case "remote" : + ret = GagMutes["remote_gag"]; + if(x > 0) ret = ((ret != 2) ? (adminp(prev) ? 2 : 1) : 2); + else ret = ((ret == 2) ? (adminp(prev) ? 0 : 2) : 0); + GagMutes["remote_gag"] = ret; + break; + case "all" : + ret = GagMutes["local_gag"]; + ret = (ret > GagMutes["remote_gag"] ? ret : GagMutes["remote_gag"]); + if(x > 0) ret = ((ret != 2) ? (adminp(prev) ? 2 : 1) : 2); + else ret = ((ret == 2) ? (adminp(prev) ? 0 : 2) : 0); + GagMutes["local_gag"] = ret; + GagMutes["remote_gag"] = ret; + break; + } + return ret; +} + +int SetMuted(string type, mixed x){ + object prev = this_player(); + int ret; + if(!prev || (prev != this_object() && !adminp(prev))) return 0; + if(undefinedp(x) || !intp(x)) x = 1; + if(!type) type = "all"; + switch(type){ + case "local" : + ret = GagMutes["local_mute"]; + if(x > 0) ret = ((ret != 2) ? (adminp(prev) ? 2 : 1) : 2); + else ret = ((ret == 2) ? (adminp(prev) ? 0 : 2) : 0); + GagMutes["local_mute"] = ret; + break; + case "remote" : + ret = GagMutes["remote_mute"]; + if(x > 0) ret = ((ret != 2) ? (adminp(prev) ? 2 : 1) : 2); + else ret = ((ret == 2) ? (adminp(prev) ? 0 : 2) : 0); + GagMutes["remote_mute"] = ret; + break; + case "all" : + ret=GagMutes["local_mute"]; + ret=(ret > GagMutes["remote_mute"] ? ret : GagMutes["remote_mute"]); + if(x > 0) ret = ((ret != 2) ? (adminp(prev) ? 2 : 1) : 2); + else ret = ((ret == 2) ? (adminp(prev) ? 0 : 2) : 0); + GagMutes["local_mute"] = ret; + GagMutes["remote_mute"] = ret; + break; + } + return ret; +} diff --git a/lib/lib/cigar.c b/lib/lib/cigar.c new file mode 100644 index 0000000..b001a90 --- /dev/null +++ b/lib/lib/cigar.c @@ -0,0 +1,48 @@ +#include <lib.h> + +inherit LIB_BURN; +inherit LIB_ITEM; +inherit LIB_SMOKE; + +int lastpuff; + +static void create(){ + item::create(); + burn::create(); +} + +int GetRadiantLight(int ambient){ + if( !GetLit() ) return 0; + else return item::GetRadiantLight(ambient); +} + +string GetShort(){ + return item::GetShort() + burn::GetShort(); +} + +varargs string GetLong(string unused){ + string tmp; + + tmp = burn::GetLong(unused); + if( tmp != "" ) return item::GetLong(unused) + "\n" + tmp; + else return item::GetLong(unused); +} + +int GetLastPuff(){ + return lastpuff; +} + +mixed eventSmoke(object who, object what){ + if(!GetLit()){ + write("It is not lit!"); + return 1; + } + write("You smoke your "+remove_article(GetShort())+"."); + say(who->GetName()+" smokes from "+possessive(who)+" " + +remove_article(GetShort())+"."); + lastpuff = time(); + eventDecreaseFuel(1); + if( !GetFuelAmount() ) eventBurnOut(); + return 1; +} + diff --git a/lib/lib/clan.c b/lib/lib/clan.c new file mode 100644 index 0000000..9fd9faa --- /dev/null +++ b/lib/lib/clan.c @@ -0,0 +1,162 @@ +#include <lib.h> +#include "include/clan.h" + +private class ClanClass Clan; + +private int isWelcomed; + +static void create(){ + Clan = new(class ClanClass); + Clan->leader = 0; + Clan->name = 0; + Clan->objectName = 0; + Clan->skill = 0; + isWelcomed = 0; +} + +static void init(){ + if(!present(this_object(), this_player())) return; + if(this_player()->GetClan() != GetClanName()) return; + if(this_player()->GetKeyName() == GetLeader()){ + add_action("eventBring", "bring"); + add_action("eventInitiate", "initiate"); + add_action("eventRetire", "retire"); + } + this_player()->eventPrint("\n"); + if(!isWelcomed){ + this_player()->AddChannel(GetClanName()); + eventWelcome(this_player()); + isWelcomed = 1; + } +} + +mixed CanJoin(object ob){ return 1; } + +string GetAffectLong(object ob){ + if(!ob || !living(ob)) return 0; + return ob->GetName() + " is a member of the " + + pluralize(GetClanName()) + "."; +} + +string SetLeader(string str){ + if(!user_exists(str)) error("No such user: " + str + + ". You must have a real leader."); + if(!stringp(Clan->leader)) + Clan->leader = str; + return Clan->leader; +} + +string GetLeader(){ return Clan->leader; } + +string SetClanName(string str){ + if(!stringp(Clan->name)) Clan->name = str; + return Clan->name; +} + +string GetClanName(){ return Clan->name; } + +string SetClanObject(string str){ + if(!stringp(Clan->objectName)) Clan->objectName = str; + return Clan->objectName; +} + +string GetClanObject(){ return Clan->objectName; } + +string SetClanSkill(string str){ + if(!stringp(Clan->skill)) Clan->skill = str; + return Clan->skill; +} + +string GetClanSkill(){ return Clan->skill; } + +int eventBring(string str){ + object who; + + if(!str) return notify_fail("Bring whom?\n"); + who = find_player(lower_case(str)); + if(!who) + return notify_fail(who->GetName() + " is nowhere to be found.\n"); + if(who->GetClan() != GetClanName()) + return notify_fail(who->GetName() + " is not one of you!\n"); + if( environment(who)->GetProperty("no teleport") + || environment(this_player())->GetProperty("no teleport") + || environment(this_player())->GetProperty("no magic")) + return notify_fail("A magic force blocks your powers.\n"); + if(present(who, environment(this_player()))) + return notify_fail(capitalize(str) + " is here.\n"); + if(this_player()->GetMagicPoints() < 70) + return notify_fail("Too low on magic power.\n"); + this_player()->AddMagicPoints(-70); + who->eventPrint("%^CYAN%^Your clan leader summons you.%^RESET%^"); + who->eventMoveLiving(environment(this_player())); + if(!present(who, environment(this_player()))) + this_player()->eventPrint("%^CYAN%^" + capitalize(str) + + " is beyond your reach.%^RESET%^"); + return 1; +} + +int eventInitiate(string str){ + object initiate; + object clanObject; + mixed ret; + + if(!str) return notify_fail("Initiate whom?\n"); + initiate = present(lower_case(str), environment(this_player())); + if(!initiate || !living(initiate)) + return notify_fail("No one of that nature here.\n"); + if(stringp(ret = CanJoin(initiate))) return notify_fail(ret); + else if(!ret) return ret; + if(this_player()->GetMagicPoints() < 300) + return notify_fail("Too low on magic power.\n"); + if(initiate->GetClan()) + return notify_fail("You may only initiate people without clan " + + "affiliation.\n"); + initiate->SetClan(GetClanName()); + initiate->SetSkill(GetClanSkill(), 1, 1); + if(clanObject = new(GetClanObject())) + clanObject->eventMove(initiate); + this_player()->AddMagicPoints(-300); + eventJoin(initiate); + return 1; +} + +void eventJoin(object ob){ + ob->eventPrint("%^YELLOW%^You are now a member of the " + + pluralize(GetClanName()) + ".%^RESET%^"); + environment(ob)->eventPrint("%^YELLOW%^" +ob->GetName() + + " is now a member of the " + + pluralize(GetClanName()) + ".%^RESET%^", ob); +} + +int eventRetire(string str){ + object retiree; + object clanObject; + + if(!str) return notify_fail("Retire whom?\n"); + retiree = present(lower_case(str), environment(this_player())); + if(!retiree || !living(retiree)) + return notify_fail("No one of that nature here.\n"); + if(retiree->GetClan() != GetClanName()) + return notify_fail(retiree->GetName() + " is not one of us!\n"); + clanObject = present(GetClanName() + "_clan_object", retiree); + if(!clanObject) error("Problem with clan object."); + clanObject->eventDestruct(); + retiree->SetClan(0); + // retiree->SetSkill(GetClanSkill(), 1, 1); We need to remove skill here. + eventUnjoin(retiree); + return 1; +} + +void eventUnjoin(object ob){ + ob->eventPrint("%^RED%^You are no longer a member of the " + + pluralize(GetClanName()) + ".%^RESET%^"); + environment(ob)->eventPrint("%^RED%^" + ob->GetName() + + " is no longer a member of the " + + pluralize(GetClanName()) + ".%^RESET%^", ob); +} + +void eventWelcome(object ob){ + ob->eventPrint("%^YELLOW%^Welcome, fellow " + GetClanName() + + ".%^RESET%^"); +} + diff --git a/lib/lib/classes.c b/lib/lib/classes.c new file mode 100644 index 0000000..4cbffc2 --- /dev/null +++ b/lib/lib/classes.c @@ -0,0 +1,161 @@ +/* /lib/classes.c + * from the Dead Souls LPC Library + * classes and clan handling object + * created by Descartes of Borg 950123 + * Version: @(#) classes.c 1.4@(#) + * Last modified: 96/12/13 + */ + +#include <lib.h> +#include <daemons.h> +#include "include/classes.h" + +inherit LIB_ABILITIES; + +private int Morality; +private string Class, Clan; +private mapping SkillModifiers; +private string *Religion; + +static void create(){ + abilities::create(); + SkillModifiers = ([]); + Religion = allocate(2); + Class = 0; + Clan = 0; + Morality = 0; +} + +int eventMoralAct(int degree){ + if( degree > 10 ){ + degree = 10; + } + else if( degree < -10 ){ + degree = -10; + } + Morality += degree; + if( Morality > 2500 ) Morality = 2500; + else if( Morality < -2500 ) Morality = -2500; + return Morality; +} + +int AddSkillPoints(string skill, int x){ + if( SkillModifiers[skill] ){ + int stat_level; + stat_level = GetBaseStatLevel(SkillModifiers[skill]); + if( stat_level < 20 ) x = x - x/2; + else if( stat_level < 40 ) x = x - x/3; + else if( stat_level > 70 && x < 100 ) x = x + x/3; + else if( stat_level > 99 ) x = x + x/2; + } + return abilities::AddSkillPoints(skill, x); +} + +static string SetSkillModifier(string skill, string stat){ + if(!GetSkill(skill)) return 0; + else return (SkillModifiers[skill] = stat); +} + +string GetSkillModifier(string skill){ return SkillModifiers[skill]; } + +string SetClass(string class_name){ + mixed array args = allocate(3); + mixed array tmp; + + /* The following is an example of "pass by reference" being + * used on purpose in Dead Souls. It's generally a confusing + * concept for novice coders, and it's usually avoided in + * the lib. To have an understanding of why the "args" variable + * gets modified by the following line, please see the + * pass-by-ref/val FAQ: http://dead-souls.net/ds-creator-faq.html#2.63 + */ + CLASSES_D->SetClass(class_name, args); + + if( Class ){ + string multi; + + if( !high_mortalp() ){ // Not high mortal + return Class; + } + if( !args[0] ){ // No such secondary class + return Class; + } + multi = args[0][Class]; + if( !multi ){ // Can't multi-class in this combo + return Class; + } + class_name = multi; + } + else { + if( !args[0] ){ // No such class + return Class; + } + } + foreach(tmp in args[1]){ + SetSkill(tmp...); + } + return (Class = class_name); +} + +mixed ChangeClass(string class_name){ + string cl; + int lvl = this_object()->GetLevel(); + mixed ret; + if(GetClass() == "explorer"){ + foreach(cl in GetSkills()){ + RemoveSkill(cl); + } + } + Class = 0; + ret = SetClass(class_name); + this_object()->ChangeLevel(lvl); + if(class_name == "fighter"){ + this_object()->SetMelee(1); + } + return ret; +} + +string GetClass(){ return Class; } + +int ClassMember(string class_name){ + return CLASSES_D->ClassMember(Class, class_name); +} + +string SetClan(string clan){ return (Clan = clan); } + +string GetClan(){ return Clan; } + +int GetBaseStatLevel(string stat){ return 0; } + +int SetMorality(int x){ return (Morality = x); } + +int GetMorality(){ return Morality; } + +string GetMoralityDescription(){ + string str; + int x; + + x = GetMorality(); + if( x > 2000 ) str = "saintly"; + else if( x > 1500 ) str = "pious"; + else if( x > 1000 ) str = "benevolent"; + else if( x > 700 ) str = "good"; + else if( x > 450 ) str = "friendly"; + else if( x >= 200 ) str = "nice"; + else if( x > -200 ) str = "neutral"; + else if( x > -450 ) str = "mean"; + else if( x > -700 ) str = "cruel"; + else if( x > -1000 ) str = "wicked"; + else if( x > -1500 ) str = "malevolent"; + else if( x > -2000 ) str = "dastardly"; + else str = "demonic"; + return str; +} + +string *SetReligion(string adj, string noun){ + Religion[0] = adj; + Religion[1] = noun; + return Religion; +} + +varargs string GetReligion(int flag){ return Religion[flag]; } diff --git a/lib/lib/clay.c b/lib/lib/clay.c new file mode 100644 index 0000000..61c8a4a --- /dev/null +++ b/lib/lib/clay.c @@ -0,0 +1,80 @@ +#include <lib.h> +inherit LIB_SURFACE; + +private static string Composition, Name, ShortDesc, Desc; +private static string *Nouns, *Adjs; + +varargs string SetComposition(string comp, string name, string *nouns, string *adjs, string + short, string desc); +void InitComposition(); + +void create(){ + string *tmpsave2, *tmpsave3, *tmpsave4; + surface::create(); + tmpsave2 = surface::GetSave(); + tmpsave3 = ({ "Composition","Name","Nouns","ShortDesc", "Desc","Adjs" }); + tmpsave4 = tmpsave2 + tmpsave3; + AddSave( tmpsave4 ); + SetKeyName("lump"); + SetId( ({"lump","clay","mass"}) ); + SetAdjectives( ({"lump of","clay","mass of","heavy", "shapeless"}) ); + SetShort("a lump of clay"); + SetLong("This is a heavy, shapeless mass of clay."); + call_out( (: InitComposition :), 0); + SetNoCondition(1); + SetCanClose(0); + SetMaxCarry(200); + SetMass(200); +} + +void InitComposition(){ + SetComposition(Composition, Name, Nouns, Adjs, ShortDesc, Desc); +} + +varargs string SetComposition(string comp, string name, string *nouns, string *adjs, string short, string desc){ + string tmp; + + if(name){ + Name = name; + SetKeyName(name); + } + + if(comp) Composition = comp; + + if(comp && !Desc){ + tmp = replace_string(GetLong(),"clay",comp); + SetLong(tmp); + } + + if(comp && !ShortDesc){ + tmp = replace_string(GetShort(),"clay",comp); + SetShort(tmp); + } + + if(sizeof(nouns)){ + Nouns = nouns; + SetId(nouns); + } + + if(desc){ + Desc = desc; + SetLong(desc); + } + + if(short){ + ShortDesc = short; + SetShort(short); + } + + if(sizeof(adjs)){ + Adjs = adjs; + SetAdjectives(adjs); + } + + return Composition; +} + + +void init(){ + ::init(); +} diff --git a/lib/lib/clerk.c b/lib/lib/clerk.c new file mode 100644 index 0000000..21007d2 --- /dev/null +++ b/lib/lib/clerk.c @@ -0,0 +1,147 @@ +#include <lib.h> +#include <objects.h> + +mixed performMarriage(object spouse1, object spouse2) ; +int performDivorce(object ob1); +int MarriageRequest(mixed arg1, mixed arg2, mixed arg3); +int eventRequestDivorce(mixed arg1, mixed arg2, mixed arg3); + +inherit LIB_MAYOR; +void create(){ + ::create(); + SetKeyName("clerk"); + SetId("clerk"); + SetAdjectives("town"); + SetGender("male"); + SetRace("human"); + SetShort("the town clerk"); + SetLong("An officious-looking clerk."); + SetLocalCurrency("silver"); + SetClass("priest"); + AddCommandResponse("marry", (: MarriageRequest :)); + AddCommandResponse("wed", (: MarriageRequest :)); + AddCommandResponse("join", (: MarriageRequest :)); + AddCommandResponse("divorce", (: eventRequestDivorce :)); + SetLevel(4); + SetTax(5); +} + +int eventRequestDivorce(mixed arg1, mixed arg2, mixed arg3){ + this_object()->performDivorce(arg1); + return 1; +} + +int MarriageRequest(mixed arg1, mixed arg2, mixed arg3){ + string s1, s2, dudename; + object ob1, ob2; + if(strsrch(arg2,"divorce") != -1){ + this_object()->performDivorce(arg1); + return 1; + } + + if(sscanf(arg3,"%s and %s", s1, s2) !=2 && + sscanf(arg3,"%s to %s", s1, s2) !=2){ + eventForce("say "+arg1->GetName()+", you are confusing me."); + return 1; + } + + dudename = arg1->GetKeyName(); + if(s1 == "me" || s1 == "i") s1 = dudename; + if(s2 == "me" || s2 == "i") s2 = dudename; + + if(s1 != dudename && s2 != dudename ){ + eventForce("say Those people will have to decide "+ + "to get married on their own. It isn't "+ + "any of your business."); + return 1; + } + + if( s1 == s2){ + eventForce("say we don't do single-member marriages here."); + return 1; + } + if(! ob1 = present(s1, environment(this_object()))){ + eventForce("say "+capitalize(s1)+" isn't here."); + return 1; + } + if(! ob2 = present(s2, environment(this_object()))){ + eventForce("say "+capitalize(s2)+" isn't here."); + return 1; + } + + if(!living(ob1) || !living(ob2)){ + eventForce("say I do not perform marriages with inanimate objects."); + return 1; + } + this_object()->performMarriage(ob1, ob2); + return 1; +} + +mixed performMarriage(object spouse1, object spouse2){ + mixed tmp; + eventForce("say hmmm..."); + tmp = environment(this_player())->CanMarry(this_player(), + spouse1, spouse2); + if( !tmp ){ + this_player()->eventPrint("This place is not holy to you."); + return 1; + } + else if( stringp(tmp) ){ + this_player()->eventPrint(tmp); + return 1; + } + tmp = environment(this_player())->eventMarry(this_player(), + spouse1, spouse2); + if( tmp == 1 ){ + object ring; + + ring = new(OBJ_WED_RING); + ring->SetSpouse(spouse2->GetCapName()); + ring->eventMove(spouse1); + ring = new(OBJ_WED_RING); + ring->SetSpouse(spouse1->GetCapName()); + ring->eventMove(spouse2); + } +} + +int performDivorce(object ob1){ + string spouse1, spouse2; + object ring1, ring2, ob2; + + spouse1 = ob1->GetKeyName(); + if(!ob1->GetSpouse()){ + eventForce("say You don't appear to be married."); + return 1; + } + spouse2 = lower_case(ob1->GetSpouse()); + ob2 = find_player(spouse2); + + if(!ob1->CanDivorce(ob1)){ + eventForce("say I cannot perform this divorce. Are you sure "+ + "you are still married?"); + return 1; + } + + if(!find_player(spouse1) || !ob1 ){ + eventForce("say I'm sorry. Both spouses must be logged "+ + "on for a divorce to take place."); + return 1; + } + + ob1->eventDivorce(ob1); + ob2->eventDivorce(ob2); + + ring1 = present("official wedding ring",ob1); + ring2 = present("official wedding ring",ob2); + + if(ring1) ring1->eventDestruct(); + if(ring2) ring2->eventDestruct(); + + eventForce("say The divorce is complete."); + tell_player(spouse1,"%^RED%^You are now divorced from "+capitalize(spouse2)+"%^RESET%^!"); + tell_player(spouse2,"%^RED%^You are now divorced from "+capitalize(spouse1)+"%^RESET%^!"); + eventForce("shout this office duly records and announces that "+capitalize(spouse1) +" has divorced "+capitalize(spouse2)+"!"); + return 1; +} + + diff --git a/lib/lib/clip.c b/lib/lib/clip.c new file mode 100644 index 0000000..b3a8700 --- /dev/null +++ b/lib/lib/clip.c @@ -0,0 +1,150 @@ +#include <lib.h> +#include "include/clip.h" +#include <vendor_types.h> +inherit LIB_STORAGE; +inherit LIB_LOAD; +private int caliber, millimeter, MaxAmmo, ammo; +private string firearmtype,ammotype; +void create(){ + ::create(); + SetKeyName("magazine"); + SetId(({"clip","magazine"})); + SetAdjectives(({"ammunition","pistol"})); + SetShort("a pistol ammunition clip"); + SetLong("This is a slender, spring-loaded container for semiautomatic "+ + "pistol ammunition."); + SetMass(10); + SetValue(1); + SetVendorType(VT_TREASURE); +} +int CanReceive(object ob){ + string *namen; + namen=ob->GetId(); + if(member_array("bullet",namen) == -1){ + write("Only bullets fit into the magazine."); + return 0; + } + if(ob->GetAmmoType() != this_object()->GetAmmoType() ){ + write("That round is not the correct type for the magazine."); + return 0; + } + if(ob->GetMillimeter() != this_object()->GetMillimeter() ){ + write("That round is not the correct size for the magazine."); + return 0; + } + if(ob->GetCaliber() != this_object()->GetCaliber() ){ + write("That round is not the correct caliber for the magazine."); + return 0; + } + if(ob->GetFirearmType() != "auto"){ + write("That round is not a semiautomatic round."); + return 0; + } + if(sizeof(all_inventory()) >= MaxAmmo){ + write("The magazine is filled to capacity."); + return 0; + } + ammo++; + return 1; +} +int CanRelease(object ob){ + ammo--; + return 1; +} +int MinusAmmo(int i){ ammo -= i; return 1; } +int PlusAmmo(int i){ ammo += i; return 1; } +int SetMaxAmmo(int i){ MaxAmmo=i; return 1; } +int SetFirearmType(string str){firearmtype=str; return 1; } +int SetAmmoType(string str){ammotype=str; return 1; } +int SetCaliber(int x){ caliber=x; return 1; } +int SetMillimeter(int x){ millimeter=x; return 1; } +int GetMillimeter(){ return millimeter; } +int GetCaliber(){ return caliber; } +string GetFirearmType(){ return firearmtype; } +string GetAmmoType(){ return ammotype; } + +varargs mixed eventLoad(object who, object where){ + int success, err; + mixed type = where->GetFirearmType(); + if(base_name(where) != LIB_FIREARM && + !inherits(LIB_FIREARM,where)){ + write("This magazine is for a firearm."); + return 1; + } + if(!stringp(type) || type != "auto"){ + write("This ammunition magazine is for use with auto firearms."); + return 1; + } + if(where->GetCaliber() != GetCaliber()){ + write("That is not the right caliber."); + return 1; + } + if(where->GetMaxLoaded()){ + write("It's already got a magazine."); + return 1; + } + err = catch(success = eventMove(where) ); + if(err || !success){ + write("There seems to be a problem loading it."); + return 1; + } + else { + write("You load your "+where->GetFirearmName()+"."); + say(this_player()->GetName()+" loads an ammunition "+ + "clip into "+possessive(this_player())+" "+ + where->GetFirearmName()+"."); + where->SetLoaded(1); + } + return 1; +} + +varargs mixed eventUnload(mixed where){ + int success, err, inv; + object env; + mixed type = where->GetFirearmType(); + object prev = previous_object(); + env = environment(); + if((base_name(previous_object()) == LIB_ROUND || + inherits(LIB_ROUND, previous_object())) && intp(where)){ + if(!(inv = sizeof(all_inventory()))){ + write("It's already fully unloaded."); + return 1; + } + if(inv < where) where = inv; + err=catch(success=all_inventory()[0..inv-1]->eventMove(this_player())); + if(err || !success){ + write("It seems you weren't able to unload all you wanted."); + return 1; + } + else { + write("You unload "+cardinal(where)+" "+ + remove_article(previous_object()->GetShort())+" from the "+ + remove_article(GetShort())+"."); + return 1; + } + } + if(!env) return 0; + if(!type) type = env->GetFirearmType(); + if(!stringp(type)){ + write("This ammunition magazine is not in a firearm."); + return 1; + } + if(env != where){ + write("You seem confused about what to unload from where."); + return 1; + } + env = environment(env); + if(!env || env != this_player()){ + write("You aren't close enough to the firearm."); + return 1; + } + err = catch(success = where->eventUnload(env) ); + if(err || !success){ + write("There seems to be a problem loading it."); + return 1; + } + else { + where->SetLoaded(0); + } + return 1; +} diff --git a/lib/lib/combat.c b/lib/lib/combat.c new file mode 100644 index 0000000..57a458f --- /dev/null +++ b/lib/lib/combat.c @@ -0,0 +1,1204 @@ +/* /lib/combat.c + * from the Dead Souls LPC Library + * combat events and data + * created by Descartes of Borg 950124 + * Version: @(#) combat.c 1.40@(#) + * Last modified: 96/11/17 + */ + +#include <lib.h> +#include <rounds.h> +#include <daemons.h> +#include <position.h> +#include <damage_types.h> +#include <function.h> + +#ifndef MAX_ATTACKS_PER_HB +#define MAX_ATTACKS_PER_HB 40 +#endif +#ifndef MAX_POWER +#define MAX_POWER 9001 +#endif +#ifndef MAX_SKILL +#define MAX_SKILL 1000 +#endif + + +inherit LIB_RACE; +inherit LIB_CLASSES; +inherit LIB_COMBATMSG; + +private int Wimpy, Dead; +private string WimpyCommand; +private static int cParalyzed, tNextRound, AttacksPerHB; +private static string TargetLimb, Party; +private static object CurrentEnemy, genv; +private static function fParalyzed, fNextRound; +private static object *Hostiles, *Enemies, *SpecialTargets, *NonTargets; +private static object *PriorEnemies; + +string GetName(); +mixed GetProperty(string key); +string array AddChannel(mixed val); +string array RemoveChannel(mixed val); +int eventForce(mixed args); +int eventExecuteAttack(mixed target); +int eventWeaponRound(mixed target, mixed val); +void eventWeaponAttack(object target, object weapon, int num); +int eventMeleeRound(mixed target, function f); +void eventMeleeAttack(object target, string limb); +int eventMagicRound(mixed target, function f); +int eventWimpy(int i); + +static void create(){ + race::create(); + classes::create(); + Hostiles = ({}); + Enemies = ({}); + NonTargets = ({}); + CurrentEnemy = SpecialTargets = 0; + Party = 0; + fParalyzed = 0; + fNextRound = 0; + cParalyzed = 0; + tNextRound = ROUND_UNDEFINED; + Wimpy = 0.20; + WimpyCommand = "go out"; +} + +/* ***************** /lib/combat.c data functions ***************** */ + +int GetVisibility(){ + int x = this_object()->GetEffectiveVision(); + if( x > 5 || x < 3 ) return 0; + if( x == 4 ) return 2; + else return 1; +} + +int GetDead(){ + return Dead; +} + +int SetDead(int i){ + if(!i) Dead = 0; + else Dead = 1; + return Dead; +} + +object array GetEnemies(){ + return Enemies; +} + +int AddEnemy(object ob){ + if( !ob || (member_array(ob, Enemies) != -1) ){ + return 0; + } + if( !living(ob) ){ + return 0; + } + Enemies += ({ ob }); + return 1; +} + +int RemoveEnemy(object ob){ + if( !ob || (member_array(ob, Enemies) == -1) ){ + return 0; + } + Enemies -= ({ ob }); + return 1; +} + +object SetCurrentEnemy(object ob){ + if( !ob ){ + return (CurrentEnemy = 0); + } + if( !living(ob) ){ + return CurrentEnemy; + } + if( member_array(ob, Enemies) == -1 ){ + AddEnemy(ob); + } + return (CurrentEnemy = ob); +} + +static object ResetCurrentEnemy(){ + object array obs; + mixed ret; + + obs = filter(GetEnemies(), (: $1 && ( environment() == environment($1) + || environment() == $1 || environment($1) == this_object()):)); + if( !sizeof(obs) ){ + ret = 0; + } + else ret = SetCurrentEnemy(obs[random(sizeof(obs))]); + return ret; +} + +object GetCurrentEnemy(){ + return CurrentEnemy; +} + +private static void SortEnemies(){ + if( !sizeof(Enemies = filter(Enemies, (: ($1 && living($1)) :))) ){ + Hostiles = ({}); + CurrentEnemy = 0; + return; + } + Hostiles = (Hostiles & Enemies); +} + +mixed *AddNonTargets(mixed val){ + if(!arrayp(val)) val = ({ val }); + foreach(object member in val){ + if(member_array(member,NonTargets) == -1){ + if(base_name(this_object()) != base_name(member)) NonTargets += ({ member }); + } + } + return NonTargets; +} + +mixed *RemoveNonTargets(mixed val){ + if(!val) val = ({}); + if(!arrayp(val)) val = ({ val }); + if(!sizeof(val)){ + NonTargets = ({}); + return NonTargets; + } + foreach(object member in val){ + if(member_array(member,NonTargets) != -1){ + NonTargets -= ({ member }); + } + } + return NonTargets; +} + +object *GetNonTargets(){ + return NonTargets; +} + + +int AddHostile(object ob){ + if( !ob || (member_array(ob, Hostiles) != -1) ){ + return 0; + } + if( !living(ob) ){ + return 0; + } + Hostiles += ({ ob }); + return 1; +} + +int RemoveHostile(object ob){ + if( !ob || (member_array(ob, Hostiles) == -1) ){ + return 0; + } + Hostiles -= ({ ob }); + return 1; +} + +object array GetHostiles(){ + return Hostiles; +} + +object array GetSpecialTarget(){ + return SpecialTargets; +} + +object array SetSpecialTarget(object *cibles){ + if(cibles) SpecialTargets = cibles; + return SpecialTargets; +} + +varargs int SetParalyzed(int count, function f){ + if(count < 1){ + count = cParalyzed = 0; + fParalyzed = 0; + } + else { + fParalyzed = f; + cParalyzed = count; + } + return count; +} + +int GetParalyzed(){ return cParalyzed; } + +int eventQuell(){ + object *truced; + truced = get_livings(environment(this_object())); + if(sizeof(Enemies)) PriorEnemies = Enemies; + Enemies = ({}); + AddNonTargets(truced); + return 1; +} + +int eventUnQuell(){ + object *truced; + truced = GetNonTargets(); + if(sizeof(PriorEnemies)) Enemies += PriorEnemies; + if(sizeof(truced)) RemoveNonTargets(truced); + return 1; +} + +string SetParty(string str){ + if( file_name(previous_object()) != PARTY_D ) return Party; + if( str ) AddChannel(str); + else RemoveChannel(Party); + return (Party = str); +} + +string GetParty(){ + if(Party){ + if(member_array(Party, PARTY_D->GetParties()) == -1) return 0; + if(member_array(this_object(), PARTY_D->GetPartyMembers(Party)) == -1){ + return 0; + } + } + return Party; +} + +varargs int SetAttack(mixed target, function callback, int type){ + int i; + object env = room_environment(); + string *voibs = ({ "kill", "target", "smite", "waste", "hit", "attack" }); + + /* Don't put stuff in the combat queue if the room is peaced */ + if(env && !target && env->GetProperty("no attack")){ + evaluate( callback ); + return 1; + } + if( objectp(target) ) target = ({ target }); + if( target ){ + if( member_array(this_object(), target) != -1 ) return 0; + if(sizeof(NonTargets) && member_array(query_verb(),voibs) != -1){ + foreach(object individual in target){ + if(member_array(individual,NonTargets) != -1){ + NonTargets -= ({ individual }); + } + } + } + else if(sizeof(NonTargets)){ + foreach(object individual in target){ + if(member_array(individual,NonTargets) != -1) target -= ({ individual }); + } + if(!sizeof(target)) return 0; + } + + if(environment(target[0]) == this_object()){ + type = ROUND_INTERNAL; + } + if(environment(this_object()) == target[0]){ + type = ROUND_EXTERNAL; + } + + if( !GetCurrentEnemy() ) call_out((: eventExecuteAttack :), 0, target); + i = sizeof(target); + while(i--) if( AddEnemy(target[i]) ) AddHostile(target[i]); + if(!sizeof(SpecialTargets) ) SpecialTargets = target; + else { + int spec_targ_here; + foreach(object t in SpecialTargets){ + if(t && present(t->GetKeyName(),environment(this_player()))) spec_targ_here = 1; + } + if(!spec_targ_here) SpecialTargets = target; + } + } + fNextRound = callback; + tNextRound = (type || ROUND_UNDEFINED); + return 1; +} + +int GetLevel(){ + return classes::GetLevel(); +} + +int GetInCombat(){ + return sizeof(filter(GetEnemies(), + (: $1 && ( (environment($1) == environment()) + || environment() == $1 || environment($1) == + this_object()) :))); +} + +int GetBaseStatLevel(string stat){ + return race::GetBaseStatLevel(stat); +} + +float SetWimpy(float wimpy){ + return (Wimpy = wimpy); +} + +float GetWimpy(){ + return Wimpy; +} + +string SetWimpyCommand(string cmd){ + return (WimpyCommand = cmd); +} + +string GetWimpyCommand(){ + return WimpyCommand; +} + +int GetMaxCarry(){ + return race::GetMaxCarry(); +} + +int GetMagicChance(int val){ + val = GetStatLevel("intelligence")/2 + (3*val)/2; + return val + GetLuck(); +} + +int GetMagicResistance(){ + int val = GetStatLevel("wisdom")/2 + (3*GetSkillLevel("magic defense"))/2; + return val + GetLuck(); +} + +varargs int GetPenalty(object other){ + int other_penalty, ret = 0; + if(other) other_penalty = other->GetPenalty(); + //Only players get a blindness penalty. + if(interactive() && (GetBlind() || GetVisibility() < 1)) ret += 10; + if(GetParalyzed()) ret += 10; + switch(GetPosition()){ + case POSITION_LYING : + if(!(RACES_D->GetLimblessCombatRace(GetRace()))) ret += 10; + break; + case POSITION_SITTING : ret += 3;break; + case POSITION_KNEELING : ret += 3;break; + } + if(other_penalty) ret -= other_penalty; + if(ret < 0) ret = 0; + return ret; +} + +int GetCombatChance(int val){ + val = val + random((val * GetMobility())/50); + val = (val/(3- GetVisibility()) + GetLuck()); + val = val/(GetPenalty() || 1); + return val; +} + +int GetDefenseChance(int val){ + val = (val * GetMobility())/50; + val = (val/(3- GetVisibility()) + (GetLuck()/2)); + val = val/(GetPenalty() || 1); + return val; +} + +int GetCombatBonus(int level){ + int diff = level - GetLevel(); + + if( diff >= 6 && diff < 16 ){ + return 4; + } + else if( diff >= 1 && diff < 6 ){ + return 3; + } + else if( diff >= -9 && diff < 1 ){ + return 2; + } + else if( diff >= -20 && diff < -9 ){ + return 1; + } + else { + return 0; + } +} + +static int GetDamage(int power, string skill){ + int x = GetSkillLevel(skill); + + if( power < 1 ){ + return 0; + } + else if( power > MAX_POWER ){ + power = MAX_POWER; + } + if( x < 1 ){ + x = 1; + } + else if( x > MAX_SKILL ){ + x = MAX_SKILL; + } + x = (x * (power/2 + random(power/2))/10); + x += (GetLuck()/2) + GetStatLevel("strength")/8; + if( x < 1 ){ // negative luck or cursed strength + return 1; + } + return x; +} + +int CanWeapon(object target, string type, int hands, int num){ + string limb = target->GetRandomLimb(TargetLimb); + int chance = (7*GetSkillLevel(type+" attack") + + 3*GetStatLevel("coordination"))/10; + int div = 2; + int x, y; + + if(hands > 1){ + if(GetSkillLevel("multi-hand")){ + chance = (chance/2) + + (GetSkillLevel("multi-hand")/25)*(chance/2); + } + else { /* If you are really strong you can use multihand a bit */ + chance *= GetStatLevel("strength")/100; + div += (hands-1); + } + } + if(num > 1){ + if(GetSkillLevel("multi-weapon")){ + chance = (chance/2) + + (GetSkillLevel("multi-weapon")/25)*(chance/2); + } + else { /* If you are really coordinated you can use multiweap a bit */ + chance *= GetStatLevel("coordination")/100; + div += (num-1); + } + } + chance = GetCombatChance(chance/div); + x = random(chance); + y = random(10); + if( x <= y ){ + if( x > y/2 ){ + TargetLimb = target->GetRandomLimb(0); + } + else { + TargetLimb = 0; + } + } + else { + TargetLimb = limb; + } + return chance; +} + + +int CanMelee(object target){ + //if(environment(target) == this_object() || + //environment(this_object()) == target) return 100; + if(!this_object()->GetMelee() && + this_object()->GetClass() != "fighter"){ + string limb = target->GetRandomLimb(TargetLimb); + int chance = ( 6*this_object()->GetSkillLevel("melee attack") + + 2*GetStatLevel("coordination") )/20; + int y = random(10); + int x; + + chance = GetCombatChance(chance/3); + x = random(chance); + if( x <= y ){ + if( x > y/2 ){ + TargetLimb = target->GetRandomLimb(0); + } + else { + TargetLimb = 0; + } + } + else { + TargetLimb = limb; + } + return chance; + } + else { + string limb = target->GetRandomLimb(TargetLimb); + int chance = ( 7*this_object()->GetSkillLevel("melee attack") + + 3*GetStatLevel("coordination") )/10; + int y = random(10); + int x; + + chance = GetCombatChance(chance/2); + x = random(chance); + if( x <= y ){ + if( x > y/2 ){ + TargetLimb = target->GetRandomLimb(0); + } + else { + TargetLimb = 0; + } + } + else { + TargetLimb = limb; + } + return chance; + } +} + +static int Destruct(){ + if( GetParty() ) PARTY_D->eventLeaveParty(this_object()); + return 1; +} + +/* ***************** /lib/combat.c events ***************** */ + +varargs int eventDie(mixed agent){ + object ob, env = room_environment(); + int x; + if(this_object()->GetGodMode()) return 0; + + if(Dead) return 1; + Dead = 1; + + x = race::eventDie(agent); + if( x != 1 ){ + return x; + } + foreach(ob in GetEnemies()){ + if( ob ){ + ob->eventEnemyDied(this_object()); + } + } + Enemies = ({}); + flush_messages(); + return 1; +} + +int eventExecuteAttack(mixed target){ + object array weapons; + function f = fNextRound; + int type = tNextRound; + int position = GetPosition(); + string target_name = ""; + + if(AttacksPerHB > MAX_ATTACKS_PER_HB) return 0; + if(Dead) return 1; + if(target->GetDead()) return 1; + + if(stringp(target)) target_name = target; + if(objectp(target)) target_name = target->GetShort(); + + AttacksPerHB++; + + fNextRound = 0; + tNextRound = ROUND_UNDEFINED; + + if(this_object()->GetPacifist()){ + tell_object(this_object(),"As a pacifist, you choose not to fight."); + return 0; + } + + if( position == POSITION_LYING || position == POSITION_SITTING && + RACES_D->GetLimblessCombatRace(this_object()->GetRace()) != 1){ + if(this_object()->CanFly()){ + this_object()->eventFly(); + } + else if(objectp(target) && (((this_object()->GetSize(1)) - + target->GetSize(1)) < 2) ){ + this_object()->eventPrint("You can't fight "+ + target_name+" unless you are up!"); + return 0; + } + } + + if( arrayp(target) ){ + if( !f || (functionp(f) & FP_OWNER_DESTED) ){ + return 0; /* built in only handles 1 targ */ + } + target = filter(target, function(object ob){ + if( !ob ){ + return 0; + } + if( !ob->eventPreAttack(this_object()) ){ + return 0; + } + return 1; + }); + if( !sizeof(target) ){ + return 0; + } + } + else if( !target->eventPreAttack(this_object()) ){ + return 0; + } + if(this_object()->GetClass() != "fighter"){ + this_object()->AddStaminaPoints(-1); + } + switch(type){ + case ROUND_UNDEFINED: case ROUND_EXTERNAL: + if( functionp(f) && !(functionp(f) & FP_OWNER_DESTED) ){ + return evaluate(f, target); + } + if( sizeof(weapons = GetWielded()) ){ + return eventWeaponRound(target, weapons); + } + else { + return eventMeleeRound(target, 0); + } + + case ROUND_INTERNAL: + return eventMeleeRound(target, 0); + + case ROUND_MAGIC: + return eventMagicRound(target, f); + + case ROUND_MELEE: + return eventMeleeRound(target, functionp(f) ? f : 0); + + case ROUND_WEAPON: + return eventWeaponRound(target, functionp(f) ? f : GetWielded()); + + case ROUND_OTHER: + if( functionp(f) && !(functionp(f) & FP_OWNER_DESTED) ){ + return evaluate(f); + } + else { + return 0; + } + + default: return 0; + } + return 0; +} + +int eventWeaponRound(mixed target, mixed val){ + object array weapons = 0; + function f = 0; + + if(AttacksPerHB > MAX_ATTACKS_PER_HB) return 0; + if(Dead) return 1; + if(target->GetDead()) return 1; + AttacksPerHB++; + if( arrayp(val) ){ + weapons = val; + } + else if( functionp(val) && !(functionp(val) & FP_OWNER_DESTED) ){ + f = val; + } + else { + return 0; + } + if( f ){ + evaluate(f, target); + } + else { + int count = sizeof(weapons); + + foreach(object weapon in weapons){ + if( !target ){ + break; + } + eventWeaponAttack(target, weapon, count); + } + } + return target->GetDying(); +} + +void eventWeaponAttack(object target, object weapon, int num){ + string weapon_type = weapon->GetWeaponType(); + int hands = weapon->GetHands(); + int level = target->GetLevel(); + int bonus = GetCombatBonus(level); + int power, pro, con, fail; + + if(AttacksPerHB > MAX_ATTACKS_PER_HB) return 0; + if(Dead) return; + if(target->GetDead()) return; + AttacksPerHB++; + if( target->GetDying() ){ + return; + } + + if(weapon->GetLive() && !interactive()){ + weapon->eventShoot(weapon, target); + return; + } + if(GetPenalty() > random(11)) fail = 1; + pro = CanWeapon(target, weapon_type, hands, num); + power = random(pro); + con = target->GetDefenseChance(target->GetSkillLevel(weapon_type + + " defense")); + if( !TargetLimb ){ // If the thing stood still, I still missed + if(!estatep(target) && !fail) eventTrainSkill(weapon_type + " attack", pro, 0, 0, bonus); + if( hands > 1 ){ + if(!estatep(target) && !fail) eventTrainSkill("multi-hand", pro, 0, 0, bonus); + } + if( num > 1 ){ + if(!estatep(target) && !fail) eventTrainSkill("multi-weapon", pro, 0, 0, bonus); + } + SendWeaponMessages(target, -2, weapon, TargetLimb); + } + else if( fail || !target->eventReceiveAttack(power, weapon_type, this_object()) ){ + // Target avoided the attack + if(!estatep(target) && !fail) eventTrainSkill(weapon_type + " attack", pro, con, 0, bonus); + if( hands > 1 ){ + if(!estatep(target) && !fail) eventTrainSkill("multi-hand", pro, con, 0, bonus); + } + if( num > 1 ){ + if(!estatep(target) && !fail) eventTrainSkill("multi-weapon", pro, con, 0, bonus); + } + SendWeaponMessages(target, -1, weapon, TargetLimb); + } + else { // I hit, but how hard did I hit? + int damage_type, damage, weapon_damage, actual_damage, encumbrance; + encumbrance = this_object()->GetEncumbrance(); + if(encumbrance > 20){ + tell_object(this_object(),"You struggle to fight while carrying stuff."); + } + if(!estatep(target)) eventTrainSkill(weapon_type + " attack", pro*2, con, 1, bonus); + damage_type = weapon->GetDamageType(); + damage = (weapon->eventStrike(target) * pro)/(GetLevel()*2); + damage = GetDamage(damage, weapon_type + " attack"); + damage -= encumbrance; + if(damage < 0) damage = 0; + actual_damage = target->eventReceiveDamage(this_object(), damage_type, + damage, 0, TargetLimb); + if( actual_damage < 0 ){ + actual_damage = 0; + } + weapon_damage = damage - actual_damage; + if( weapon_damage > 0 ){ + weapon->eventReceiveDamage(this_object(), BLUNT, weapon_damage, + 0, TargetLimb); + } + SendWeaponMessages(target, actual_damage, weapon, TargetLimb); + if( target->GetDying() ){ + } + } +} + +int eventMeleeRound(mixed target, function f){ + string array limbs = GetLimbs() - ({ GetTorso() }); + int count = sizeof(limbs); + int attacks; + + if(AttacksPerHB > MAX_ATTACKS_PER_HB) return 0; + if(Dead) return 1; + if(target->GetDead()) return 1; + AttacksPerHB++; + if( count < 2 ){ + if(RACES_D->GetLimblessCombatRace(this_object()->GetRace())){ + limbs = GetLimbs(); + count = sizeof(limbs); + } + else return 0; + } + if( !f || (functionp(f) & FP_OWNER_DESTED) ){ + attacks = 1 + random(this_object()->GetSkillLevel("melee attack"))/30; + while( attacks-- ){ + if( target->GetDying() ){ + break; + } + eventMeleeAttack(target, limbs[random(count)]); + } + } + else { + evaluate(f, target, limbs[random(count)]); + } + return target->GetDying(); +} + +void eventMeleeAttack(object target, string limb){ + int pro, con, autohit; + int chance, fail; + int canmelee = (this_object()->GetMelee() || + this_object()->GetClass() == "fighter"); + + if(AttacksPerHB > MAX_ATTACKS_PER_HB) return; + if( target->GetDead() || Dead || target->GetDying() ){ + return; + } + AttacksPerHB++; + if(limb == "head" && this_object()->GetCanBite()){ + eventBite(target); + return; + } + + if(environment(target) == this_object() || + environment(this_object()) == target){ + con = 0; + fail = 0; + autohit = 1; + } + else if(GetPenalty() > random(11)) fail = 1; + + pro = CanMelee(target); + if(undefinedp(con)){ + con = target->GetDefenseChance(target->GetSkillLevel("melee defense")); + } + chance = random(pro); + if( !TargetLimb ){ // I *really* missed + SendMeleeMessages(target, -2); + if(!estatep(target)) eventTrainSkill("melee attack", pro, 0, 0, + GetCombatBonus(target->GetLevel())); + } + else if( fail || (!autohit && + !target->eventReceiveAttack(chance, "melee", this_object())) ){ + // Enemy dodged my attack + SendMeleeMessages(target, -1); + if(!estatep(target) && !fail) eventTrainSkill("melee attack", pro, con, 0, + GetCombatBonus(target->GetLevel())); + } + else { // I hit, how hard? + int x, encumbrance; + encumbrance = this_object()->GetEncumbrance(); + if(encumbrance > 20){ + tell_object(this_object(),"You struggle to fight while carrying stuff."); + } + if(!estatep(target)) eventTrainSkill("melee attack", pro, con, 1, + GetCombatBonus(target->GetLevel())); + if(canmelee) x = GetDamage(3*chance/4, "melee attack"); + else x = GetDamage(3*chance/20, "melee attack"); + x -= encumbrance; + if(x < 0) x = 0; + x = target->eventReceiveDamage(this_object(), BLUNT, x, 0, + TargetLimb); + SendMeleeMessages(target, (x > 0) ? x : 0, TargetLimb); + if( target->GetDying() ){ + } + } +} + +int eventMagicRound(mixed target, function f){ + if(AttacksPerHB > MAX_ATTACKS_PER_HB) return 0; + if(target->GetDead()) return 1; + AttacksPerHB++; + evaluate(f, target); + return target->GetDying(); +} + +mixed eventBite(object target){ + int fail, internal; + object env = room_environment(); + int pro = CanMelee(target); + int con = target->GetDefenseChance(target->GetSkillLevel("melee defense")); + int x = random(pro); + if(AttacksPerHB > MAX_ATTACKS_PER_HB) return 0; + if(target->GetDead()) return 1; + if(environment(target) == this_object() || + environment(this_object()) == target) internal = 1; + else if(GetPenalty() > random(11)) fail = 1; + AttacksPerHB++; + if( !internal && environment() != environment(target) ){ + this_object()->eventPrint(target->GetName() + " has gone away."); + return 1; + } + if( !fail && TargetLimb ){ + if( target->eventReceiveAttack(x, "melee", this_object()) ){ + x = GetDamage(pro*2, "melee attack"); + x = target->eventReceiveDamage(this_object(), BITE, x, 0, + TargetLimb); + if( x < 1 ){ + target->eventPrint(possessive_noun(this_object()) + " bite " + "is nothing more than a pinch."); + this_object()->eventPrint("Your bite is nothing more than a pinch."); + env->eventPrint(possessive_noun(this_object()) + + " bite is nothing more than a " + "pinch.", + ({ target, this_object() })); + } + else { + target->eventPrint(GetName() + " bites you in the " + + TargetLimb + "!"); + this_object()->eventPrint("You bite " + target->GetName() + " in the " + + TargetLimb + "!"); + env->eventPrint(GetName() + " bites " + + target->GetName() + " in the " + + TargetLimb + "!", + ({ target, this_object() })); + } + if(!estatep(target)) eventTrainSkill("melee attack", pro, con, 1, + GetCombatBonus(target->GetLevel())); + } + else { + target->eventPrint("You avoid " + possessive_noun(this_object()) + + " bite."); + this_object()->eventPrint(target->GetName() + " avoids your bite."); + env->eventPrint(target->GetName() + " avoids " + + possessive_noun(this_object()) + + " bite.", + ({ this_object(), target })); + if(!estatep(target)) eventTrainSkill("melee attack", pro, con, 0, + GetCombatBonus(target->GetLevel())); + } + } + else { + this_object()->eventPrint("You flounder about like a buffoon."); + env->eventPrint(GetName() + " flounders about like a " + "buffoon.", this_object()); + } + return 1; +} + +int eventPreAttack(object agent){ + object env = room_environment(); + if( agent == this_object() ){ + return 0; + } + if( env->GetProperty("no attack") ){ + return 0; + } + if( GetDying() ){ + return 0; + } + if( playerp(this_object()) && playerp(agent) && !PLAYER_KILL){ + if( !env->CanAttack( agent, this_object() ) ){ + return 0; + } + } + if( AddEnemy(agent) ){ + AddHostile(agent); + } + return 1; +} + +varargs int eventReceiveAttack(int speed, string def, object agent){ + int fail, x, pro, level, bonus, ret; + if(AttacksPerHB > MAX_ATTACKS_PER_HB) return 0; + if(Dead) return 0; + if(GetPenalty() > random(11)) fail = 1; + if( !agent ){ + agent = previous_object(); + } + if( !living(agent) ){ + level = 1; + bonus = 1; + } + else { + level = agent->GetLevel(); + bonus = GetCombatBonus(level); + } + if( AddEnemy(agent) ){ + AddHostile(agent); + } + if( def == "magic" ){ + pro = GetMagicResistance(); + if( (x = random(pro)) > speed ){ + if(!fail && !estatep(agent)) + eventTrainSkill("magic defense", pro, speed, 1, bonus); + ret = 0; + } + else { + if(!estatep(agent)) eventTrainSkill("magic defense", pro, speed, 0, bonus); + ret = 1; + } + } + else { + pro = GetDefenseChance(GetSkillLevel(def + " defense")); + x = random(pro = pro/2); + if( !fail && x > speed ){ + if(!estatep(agent)) + eventTrainSkill(def + " defense", pro, speed, 1, bonus); + ret = 0; + } + else { + if(!fail && !estatep(agent)) + eventTrainSkill(def + " defense", pro, speed, 0, bonus); + ret = 1; + } + } + if(fail) ret = 1; + return ret; +} + +void eventKillEnemy(object ob){ + int level; + int reward; + + if( !ob ) return; + level = ob->GetLevel(); + if(ob->GetCustomXP()) reward = ob->GetCustomXP(); + else reward = (level * 99); + + if(this_object()->GetParty()){ + int spoils; + object *loot_sharers = ({ this_object() }); + foreach(object member in PARTY_D->GetPartyMembers(this_object()->GetParty())){ + if(environment(member) == environment(this_object())){ + loot_sharers += ({ member }); + } + } + loot_sharers = distinct_array(loot_sharers); + spoils = reward / sizeof(loot_sharers); + foreach(object member in loot_sharers){ + member->AddExperiencePoints(spoils); + } + } + + else { + this_object()->AddExperiencePoints(reward); + } + + if( member_array(ob, GetHostiles()) == -1 ){ + int x; + + if(!estatep(ob)) eventTrainSkill("murder", GetLevel(), level, 1,GetCombatBonus(level)); + x = ob->GetMorality(); + if( x > 0 ) x = -x; + else if( GetMorality() > 200 ) x = 100; + else x = 0; + eventMoralAct(x); + } +} + +void eventDestroyEnemy(object ob){ + int level; + + if( !ob ) return; + level = ob->GetLevel(); + if(ob->GetCustomXP()) this_object()->AddExperiencePoints(ob->GetCustomXP()); + else this_object()->AddExperiencePoints(level * 222); + if(!estatep(ob)) eventTrainSkill("faith", GetLevel(), level, 1, GetCombatBonus(level)); +} + +void eventEnemyDied(object ob){ + if( !ob ) return; + Enemies -= ({ ob }); + Hostiles -= ({ ob }); + if(!sizeof(SpecialTargets) || (!sizeof(Enemies) || !sizeof(Hostiles))) + NonTargets = ({}); +} + +varargs int eventReceiveDamage(mixed agent, int type, int x, int internal, + mixed limbs){ + int hp,encumbrance; + + if(objectp(agent)){ + if(estatep(agent) && !estatep(this_object())) return 0; + if(!estatep(agent) && estatep(this_object())) return 0; + } + + encumbrance = this_object()->GetEncumbrance(); + //if(AttacksPerHB > MAX_ATTACKS_PER_HB) return 0; + if(Dead) return 0; + if(encumbrance > 200){ + if(GetInCombat()) tell_object(this_object(),"You try to dodge while weighed down."); + } + x = race::eventReceiveDamage(agent, type, x, internal, limbs); + if( !Wimpy ) return x; + if( (hp = GetHealthPoints()) < 1 ) return x; + if( Wimpy < percent(hp, GetMaxHealthPoints()) ) + return x; + call_out((: eventWimpy :), 0); + return x; +} + +mixed eventTurn(object who){ + int defense; + object env = room_environment(who); + + if( !GetUndead() ){ + return 0; + } + if( GetProperty("no turn") ){ + if( !who ){ + return 0; + } + else { + int x = GetProperty("no turn"); + + env->eventPrint("The power of the undead " + "turns on " + who->GetName() + + ".", who); + who->eventPrint("The power of the undead turns on you."); + if( x > random(100) + 1 ){ + who->eventDie(this_object()); + } + else { + who->eventReceiveDamage(this_object(), MAGIC, random(50), 1); + } + return 0; + } + } + if( !who ){ + race::eventTurn(who); + return 1; + } + defense = GetMagicResistance(); + if( who->GetSkillLevel("faith") < defense ){ + who->eventPrint("You writhe in pain."); + env->eventPrint(who->GetName() + " writhes in pain.", + who); + who->eventReceiveDamage(this_object(), MAGIC, random(defense), 1); + if(!estatep(who)) eventTrainSkill("magic defense", defense, who->GetSkillLevel("faith"), + 1, GetCombatBonus(who->GetLevel())); + return 0; + } + race::eventTurn(who); + return 1; +} + +int eventWimpy(int i){ + string dir, cmd; + genv = room_environment(); + + if( !genv || !GetInCombat() ){ + if(!i) return 0; + } + cmd = WimpyCommand || "go out"; + if( (sscanf(cmd, "go %s", dir) && !(genv->GetExit(dir))) || + (sscanf(cmd, "enter %s", dir) && !(genv->GetEnter(dir))) ){ + string *tmp; + + tmp = filter((genv->GetExits() || ({})), + (: !(genv->GetDoor($1)) :)); + if( !sizeof(tmp) ){ + tmp = filter(genv->GetEnters(), + (: !(genv->GetDoor($1)) :)); + if( !sizeof(tmp) ){ + this_object()->eventPrint("You need to escape, but you have nowhere to go!"); + return 0; + } + cmd = "enter " + tmp[random(sizeof(tmp))]; + } + else cmd = "go " + tmp[random(sizeof(tmp))]; + } + return eventForce(cmd); +} + +static void heart_beat(){ + race::heart_beat(); + AttacksPerHB = 0; + if( GetSleeping() || GetDying() ){ + return; + } + if( cParalyzed > 0 ){ + cParalyzed--; + if( cParalyzed < 1 ){ + function f; + + f = fParalyzed; + fParalyzed = 0; + if( functionp(f) && !(functionp(f) & FP_OWNER_DESTED) ){ + evaluate(f); + } + else { + this_object()->eventPrint("You can move again."); + } + } + return; + } + if( sizeof(Enemies) ){ + SortEnemies(); + foreach(object dude in Enemies){ + if(member_array(dude,NonTargets) != -1){ + RemoveEnemy(dude); + RemoveHostile(dude); + } + } + } + if( sizeof(Enemies) ){ + object ob; + + SortEnemies(); + + if( SpecialTargets ){ + foreach(object target in SpecialTargets){ + + if( objectp(SetCurrentEnemy(target)) ){ + break; + } + } + eventExecuteAttack(SpecialTargets); + SpecialTargets = 0; + } + else if( ob = ResetCurrentEnemy() ){ + eventExecuteAttack(ob); + } + } + else if( tNextRound != ROUND_UNDEFINED && functionp(fNextRound) ){ + function f; + + f = fNextRound; + tNextRound = ROUND_UNDEFINED; + evaluate(f); + } +} diff --git a/lib/lib/combatmsg.c b/lib/lib/combatmsg.c new file mode 100644 index 0000000..939fe8c --- /dev/null +++ b/lib/lib/combatmsg.c @@ -0,0 +1,212 @@ +/* /lib/combatmsg.c + * from the Dead Souls LPC Library + * combat message handling + * created by Blitz@Dead Souls + */ + +#include <combat_messages.h> +#include "include/combatmsg.h" + +static mixed GetMissData(object targ, int type, string limb){ + string targ_name = targ->GetName(); + + if(targ->GetDead() || this_object()->GetDead()) return 0; + + if( type == -2 ) switch( random(7) ){ + case 0: + return ({ "%s completely %s %s.", + ({ "You", "miss", targ_name }), + ({ GetName(), "misses", "you" }), + ({ GetName(), "misses", targ_name }) }); + case 1: + return ({ "%s %s at %s and %s with thin air.", + ({ "You", "swing", targ_name, "connect" }), + ({ GetName(), "swings", "you", "connects" }), + ({ GetName(), "swings", targ_name, "connects" }) }); + case 2: + return ({ "%s %s a stunning blow but %s %s by a mile!", + ({ "You", "deliver", "miss", targ_name }), + ({ GetName(), "delivers", "misses", "you" }), + ({ GetName(), "delivers", "misses", targ_name }), }); + case 3: + return ({ "After a flurry of attacks, %s %s absolutely nothing.", + ({ "you", "hit" }), + ({ GetName(), "hits" }), + ({ GetName(), "hits" }), }); + case 4: + return ({ "%s %s out at %s %s, but %s it completely.", + ({ "You", "lash", possessive_noun(targ), limb, "miss" }), + ({ GetName(), "lashes", "your", limb, "misses" }), + ({ GetName(), "lashes", possessive_noun(targ), limb, "misses" }) }); + case 5: + return ({ "%s %s silly as %s %s in the wrong direction.", + ({ "You", "look", "you", "swing" }), + ({ GetName(), "looks", nominative(this_object()), "swings" }), + ({ GetName(), "looks", nominative(this_object()), "swings" }) }); + default: + return ({ "%s totally %s %s.", + ({ "You", "miss", targ_name }), + ({ GetName(), "misses", "you" }), + ({ GetName(), "misses", targ_name }) }); + } + else { + string pos = possessive_noun(this_object()); + switch( random(7) ){ + case 0: + return ({ "%s quickly %s out of %s way.", + ({ targ_name, "jumps", "your" }), + ({ "You", "jump", pos }), + ({ targ_name, "jumps", pos }) }); + case 1: + return ({ "%s deftly %s %s pathetic attack.", + ({ targ_name, "blocks", "your" }), + ({ "You", "block", pos }), + ({ targ_name, "blocks", pos }) }); + case 2: + return ({ "%s easily %s %s inept attack.", + ({ targ_name, "dodges", "your" }), + ({ "You", "dodge", pos }), + ({ targ_name, "dodges", pos }) }); + case 3: + return ({ "%s narrowly %s %s quick swing.", + ({ targ_name, "avoids", "your" }), + ({ "You", "avoid", pos }), + ({ targ_name, "avoids", pos }) }); + case 4: + return ({ "%s attack is thwarted by %s quick defenses.", + ({ "Your", possessive_noun(targ_name) }), + ({ pos, "your" }), + ({ pos, possessive_noun(targ_name) }) }); + case 5: + return ({ "%s %s beneath %s attack.", + ({ targ_name, "ducks", "your" }), + ({ "You", "duck", pos }), + ({ targ_name, "ducks", pos }) }); + default: + return ({ "%s %s %s lame attack.", + ({ targ_name, "dodges", "your" }), + ({ "You", "dodge", pos }), + ({ targ_name, "dodges", pos }) }); + } + } + return 0; +} + +static void eventSendMissMessages(object target, int x, string limb){ + mixed data; + object env = room_environment(); + + if(target->GetDead() || this_object()->GetDead()) return; + if( !limb ) limb = "body"; + data = GetMissData(target, x, limb); + if( sizeof(data) != 4 ) return; + this_object()->eventPrint(sprintf(data[0], data[1]...)); + target->eventPrint(sprintf(data[0], data[2]...), ({ this_object() })); + env->eventPrint(sprintf(data[0], data[3]...), + ({ this_object(), target }) ); +} + +mixed GetCombatVerbs(string type, int damage){ + mixed ptr; + switch(type){ + case "knife": case "blade": + ptr = BLADE_DEGREES; + break; + case "projectile": + ptr = PROJECTILE_DEGREES; + break; + default: + ptr = BLUNT_DEGREES; + break; + } + if( !sizeof(ptr) || !arrayp(ptr)) + return ({ ({ "hit", "hits" }), ({ "solidly" }) }); + damage /= 5; + if( damage > (sizeof(ptr) - 1) ) damage = (sizeof(ptr) - 1); + if( sizeof(ptr) == 1 ) return ({ ptr[damage], ({ "solidly" }) }); + else return ptr[damage]; +} + +mixed GetCombatMove(string type, int skill){ + int i; + mixed foo; + + if( skill < random(100) ) return 0; + if( !i = sizeof(MOVE_TYPES) ) return 0; + foo = MOVE_TYPES[ random(i) ]; + if( sizeof(foo) < 2 ) return 0; + else return foo; +} + +varargs void SendMeleeMessages(object target, int x, string targlimb, string limb){ + int i; + string adverb; + mixed verb, ptr, moves; + object env = room_environment(); + + //if(target->GetDead() || this_object()->GetDead()) return; + if( x < 0 ){ + eventSendMissMessages(target, x, limb); + return; + } + ptr = GetCombatVerbs("melee", x); + verb = ptr[0]; + if( sizeof(ptr) > 1 && i = sizeof(ptr[1]) ) + adverb = (ptr[1][ random(i) ] + " in"); + else adverb = "in"; + if( moves = GetCombatMove("melee", + this_object()->GetSkillLevel("melee attack")) ){ + verb[0] = moves[0] + " and " + verb[0]; + verb[1] = moves[1] + " and " + verb[1]; + } + if( !limb ) limb = "attack"; + if( !targlimb ) targlimb = "body"; + this_object()->eventPrint(sprintf("You %s %s %s the %s with your %s.", + verb[0], target->GetName(), adverb, targlimb, limb) ); + target->eventPrint(sprintf("%s %s you %s your %s with %s %s.", + GetName(), verb[1], adverb, targlimb, possessive(this_object()), limb), ({ this_object() })); + env->eventPrint(sprintf("%s %s %s %s the %s with %s %s.", + GetName(), verb[1], target->GetName(), adverb, targlimb, + possessive(this_object()), limb), ({ target, this_object() }) ); + flush_messages(); +} + +varargs void SendWeaponMessages(object target, int x, object weapon, string limb){ + int i; + string adverb, type, weap; + mixed verb, ptr, moves; + object env = room_environment(); + + //if(target->GetDead() || this_object()->GetDead()) return; + if( x < 0 ){ + eventSendMissMessages(target, x, limb); + return; + } + if( weapon ){ + type = weapon->GetWeaponType(); + weap = weapon->GetKeyName(); + } + else { + type = "blunt"; + weap = "weapon"; + } + ptr = GetCombatVerbs(type, x); + verb = ptr[0]; + if( sizeof(ptr) > 1 && i = sizeof(ptr[1]) ) + adverb = (ptr[1][ random(i) ] + " in"); + else adverb = "in"; + if( moves = GetCombatMove(type, + this_object()->GetSkillLevel(type + " attack")) ){ + verb[0] = moves[0] + " and " + verb[0]; + verb[1] = moves[1] + " and " + verb[1]; + } + if( !limb ) limb = "body"; + this_object()->eventPrint(sprintf("You %s %s %s the %s with your %s.", + verb[0], target->GetName(), adverb, limb, weap) ); + target->eventPrint(sprintf("%s %s you %s your %s with %s %s.", + GetName(), verb[1], adverb, limb, possessive(this_object()), weap), ({ this_object() }) ); + env->eventPrint(sprintf("%s %s %s %s the %s with %s %s.", + GetName(), verb[1], target->GetName(), adverb, limb, + possessive(this_object()), weap), ({ target, this_object() }) ); + flush_messages(); +} diff --git a/lib/lib/command.c b/lib/lib/command.c new file mode 100644 index 0000000..c33e5a9 --- /dev/null +++ b/lib/lib/command.c @@ -0,0 +1,532 @@ +/* /lib/command.c + * from the Dead Souls Object Library + * handles commands of living objects + * created by Descartes of Borg 950323 + * Version: @(#) command.c 1.2@(#) + * Last modified: 96/12/07 + */ + + +#include <lib.h> +#include <daemons.h> +#include "include/command.h" + +#define OLD_STYLE_PLURALS 1 + +int Paused = 0; +private static int Forced = 0; +private static int StillTrying = 0; +private static int ParseRecurse = 0; +private static string CommandFail; +private static string *SearchPath; +private static int last_cmd_time = 0; +private static int cmd_count = 1; +private string *localcmds = ({}); +private string parsed_command = ""; +private static string *QueuedCommands = ({}); +static string current_command = ""; +static string original_command = ""; +static int Charmode = 0; +static string Charbuffer = ""; + +int direct_force_liv_str(){ return 1; } +int direct_force_liv_to_str(){ return 1; } + + +/* *************** /lib/command.c driver applies *************** */ + +static void create(){ + SetCommandFail(0); + SearchPath = ({ DIR_PLAYER_CMDS, DIR_SECURE_PLAYER_CMDS, DIR_CLAN_CMDS, + DIR_COMMON_CMDS, DIR_SECURE_COMMON_CMDS }); +} + +static string process_input(string args){ + string verb, real_verb, tmpalias, orig; + object env = environment(this_object()); + string *talks = ({ "emote", "tell", "reply", "say", "whisper", + "yell", "shout", "speak" }); + string *filecmds = ({ "ced", "clone", "goto", "rehash", "reset", + "showtree", "bk", "cat", "cp", "diff", "ed", "grep", "head", "indent", + "longcat", "more", "mv", "rm", "sed", "showfuns", "source", + "tail", "update", "cd", "ls", "mkdir", "rmdir" }); + string *specialcmds = ({ "modify", "mudconfig", "describe", "read", "title", "register" }); + string *exempts = talks + filecmds + specialcmds; + exempts += this_object()->GetChannels(); + exempts += SOUL_D->GetEmotes(); + + orig = args; + + localcmds = ({}); + filter(commands(), (: localcmds += ({ $1[0] }) :)); + + if(sizeof(args)){ + string *tmpargs = explode(args, " "); + if(sizeof(tmpargs)) verb = tmpargs[0]; + else verb = ""; + } + if(verb && tmpalias = this_object()->GetAlias(verb)){ + real_verb = explode(tmpalias, " ")[0]; + } + if(verb && tmpalias = this_object()->GetXverb(verb[0..0])){ + real_verb = explode(tmpalias, " ")[0]; + } + if(!real_verb) real_verb = verb; + if(Paused && (member_array(real_verb, exempts) == -1)){ + this_object()->eventPrint("You are paused."); + return ""; + } + if(!archp(this_object()) && MAX_COMMANDS_PER_SECOND){ + if(last_cmd_time == time()) cmd_count++; + else { + last_cmd_time = time(); + cmd_count = 1; + } + if(cmd_count > MAX_COMMANDS_PER_SECOND){ + this_object()->eventPrint("You have exceeded the " + + MAX_COMMANDS_PER_SECOND + " commands per second limit."); + return ""; + } + } + if(this_object()->GetSleeping() > 0){ + if(verb != "wake"){ + this_object()->eventPrint("You are asleep."); + return ""; + } + } + if(OLD_STYLE_PLURALS && args && (member_array(real_verb, exempts) == -1 || + (member_array(verb, exempts) != -1 && !strsrch(trim(args),"to ")))){ + int numba, i, tmp_num; + string tmp_ret; + string *line = explode(args," "); + for(i = 1; i < sizeof(line); i++){ + string element; + if(!line[i]) error("String handling error in old style plural parser."); + element = line[i]; + exempts = sort_array(exempts, 1); + if(sscanf(element,"%d.%d",numba,tmp_num) != 2 && + sscanf(element,"%d.%s",numba,tmp_ret) == 2 && + (member_array(real_verb, exempts) == -1)){ + args = replace_string(args, numba + ".", + numba + ordinal(numba) + " "); + continue; + } + if(numba = atoi(element)){ + int j; + object o1; + string e1, e2, tmp_thing = ""; + e1 = numba+ordinal(numba); + j = member_array(element, line); + while(j > 0){ + string old_tmp = tmp_thing; + j--; + e2 = line[j]; + if(sizeof(tmp_thing)) tmp_thing = e2 + " " + tmp_thing; + else tmp_thing = e2; + if(member_array(tmp_thing, exempts) != -1) break; + o1 = present(tmp_thing); + if(!o1){ + o1 = present(old_tmp); + if(o1){ + tmp_ret = e1 + " " + old_tmp; + args=replace_string(args,old_tmp+" "+numba,tmp_ret); + } + } + } + }//end single number check + } + } + parsed_command = args; + if(member_array(verb, localcmds) != -1){ + current_command = orig; + } + else { + current_command = parsed_command; + parsed_command = ""; + } + return current_command; +} + +/* *************** /lib/command.c command lfuns *************** */ + +static int cmdAll(string args){ + object old_agent, env; + mixed err; + string verb, file; + + if(grepp(parsed_command," ")){ + sscanf(parsed_command,"%s %s", verb, args); + parsed_command = ""; + } + + if(!verb) verb = query_verb(); + + if(!this_object()->GetCharmode()){ + if(!args) this_object()->Push(verb); + else this_object()->Push(verb+" "+args); + } + else { + this_object()->Push(this_object()->GetTempbuffer()); + } + + old_agent = this_agent(this_object()); + + env = environment(); + if(BARE_EXITS && env){ + localcmds = ({}); + filter(commands(), (: localcmds += ({ $1[0] }) :)); + if(member_array(verb,CMD_D->GetCommands()) == -1 && + member_array(verb,keys(VERBS_D->GetVerbs())) == -1 && + member_array(verb,localcmds) == -1 ){ + string dir; + if(args) dir = verb + " " + args; + else dir = verb; + if(member_array(dir, (env->GetExits() || ({}))) != -1) + verb = "go "+verb; + if(member_array(dir, (env->GetEnters() || ({}))) != -1) + verb = "enter "+verb; + } + } + + if(COMMAND_MATCHING && sizeof(match_command(verb))){ + verb = match_command(verb); + } + + if(query_custom_command(verb) && query_custom_command(verb) != "" && !creatorp(this_player()) ){ + this_player()->eventPrint("How clever of you. Or lucky. In any case, this command is unavailable to you."); + return 1; + } + if( !(file = (query_custom_command(verb) )) || query_custom_command(verb) == ""){ + if( !(file = CMD_D->GetCommand(verb, GetSearchPath())) ){ + string cmd; + int dbg; + + if( verb && args ) cmd = verb + " " + args; + else if(verb) cmd = verb; + else if(args) cmd = args; + if( this_object()->GetProperty("parse debug") ) dbg = 1; + else if( this_object()->GetProperty("debug") ) dbg = 1; + else dbg = 0; + if( (err = parse_sentence(cmd, dbg)) == 1 ){ + this_agent(old_agent || 1); + return 1; + } + if( err ){ + if( err == -1 ){ + if( !(err = VERBS_D->GetErrorMessage(verb)) && + !(err = SOUL_D->GetErrorMessage(verb)) ){ + err = "Such a command exists, but no default " + "syntax is known."; + } + } + if( intp(err) ) /* MudOS bug */ err = "What?"; + SetCommandFail(err); + } + message("error", GetCommandFail(), this_object()); + this_agent(old_agent || 1); + return 1; + } + } + + if( (err = call_other(file, "cmd", args)) != 1 ){ + string cmd; + + if( err ) SetCommandFail(err); + if( !args || args == "" ) cmd = verb; + else cmd = verb + " " + args; + if( (err = parse_sentence(cmd)) == 1 ){ + this_agent(old_agent || 1); + return 1; + } + if( !err ) err = GetCommandFail(); + message("error", err, this_object()); + this_agent(old_agent || 1); + return 1; + } + this_agent(old_agent || 1); + return 1; +} + +int cmdDebugAll(string args){ + object old_agent; + mixed err; + string verb, file; + + old_agent = this_agent(this_object()); + verb = query_verb(); + if( !(file = CMD_D->GetCommand(verb, GetSearchPath())) ){ + string cmd; + + if( args ) cmd = verb + " " + args; + else cmd = verb; + if( (err = parse_sentence(cmd, 3)) == 1 ){ + this_agent(old_agent || 1); + return 1; + } + if( err ) SetCommandFail(err); + message("error", GetCommandFail(), this_object()); + this_agent(old_agent || 1); + return 1; + } + if( (err = call_other(file, "cmd", args)) != 1 ){ + string cmd; + + if( err ) SetCommandFail(err); + if( !args || args == "" ) cmd = verb; + else cmd = verb + " " + args; + if( (err = parse_sentence(cmd, 3)) == 1 ){ + this_agent(old_agent || 1); + return 1; + } + if( !err ) err = GetCommandFail(); + message("error", err, this_object()); + this_agent(old_agent || 1); + return 1; + } + this_agent(old_agent || 1); + return 1; +} + +/* *************** /lib/command.c lfuns *************** */ + +int Setup(){ + enable_commands(); + add_action( (: cmdAll :), "", 1); +} + +int eventForce(string cmd){ + string err; + int res; +#if 0 + if(this_player() && interactive(this_object()) + && this_player() != this_object()){ + string forcer = this_player()->GetKeyName(); + string forcee = this_object()->GetKeyName(); + log_file("adm/force", + timestamp()+" "+forcer+" forced "+forcee+" to "+cmd+"\n"); + } +#endif + if(!cmd) return 0; + + cmd = process_input(cmd); + if(!cmd) return 0; + Forced = 1; + err = catch(res = command(cmd)); + Forced = 0; + if(err){ + error(err); + } + return res; +} + +int eventForceQueuedCommand(string cmd){ + tell_object(this_object(),"%^RED%^Executing queued command: %^RESET%^"+cmd); + eventForce(cmd); +} + +int eventExecuteQueuedCommands(){ + int i = 0; + foreach(string tmp in QueuedCommands){ + i++; + //tmp = process_input(tmp); + call_out("eventForceQueuedCommand", i, tmp); + QueuedCommands -= ({ tmp }); + } +} + +int eventQueueCommand(string line){ + if(!line || !sizeof(line) || !stringp(line)) return 0; + if(!this_player()) return 0; + if(interactive(this_object())){ + if(this_player() && this_player() != this_object()) return 0; + } + if(line != "") QueuedCommands += ({ line }); + return 1; +} + +int DoneTrying(){ + return StillTrying = 0; +} + +//Here we determine if the string corresponds unambiguously +//to a limb possessed by the command issuer. +int LimbCertain(string str){ + object env = environment(this_player()); + if(!env) env = this_player(); + if(!str){ + return 0; + } + foreach(mixed envs in ({ env, this_player() })){ + if(present(str, env)){ + return 0; + } + } + if(member_array(str, this_player()->GetLimbs()) != -1){ + return 1; + } + return 0; +} + +varargs int eventRetryCommand(string lastcmd, int errtype, mixed args){ + string virb, wrd, prep, rest,ret; + string *tmp_arr = ({}); + string *prep_arr = MASTER_D->parse_command_prepos_list(); + object tmpob; + mixed err; + int i; + string tmpret, act, direct, indirect, odirect, oindirect; + mixed direct2, indirect2; + + if(previous_object() != master()) return 0; + + if(StillTrying){ + StillTrying = 0; + original_command = 0; + return 1; + } + + StillTrying = 1; + + if(!original_command || !sizeof(original_command)) original_command = lastcmd; + + tmpret = (lastcmd || ""); + foreach(string foo in prep_arr){ + if(grepp(tmpret," "+foo+" ")){ + tmpret = replace_string(tmpret," "+foo+" "," PREPO "); + } + } + tmpret = implode(explode(tmpret," ")," "); + i = sscanf(tmpret,"%s %s PREPO %s",act, direct, indirect); + if(i != 3) i = sscanf(tmpret,"%s %s PREPO PREPO %s",act, direct, indirect); + if(i != 3) i = sscanf(tmpret,"%s %s %s",act, direct, indirect); + if(i != 3) i = sscanf(tmpret,"%s %s",act, direct); + odirect = direct; + oindirect = indirect; + + //read is a special case. takes a str as first arh sometimes. + if(act == "read" && !grepp(tmpret, " in a ")){ + tmpret = replace_string(lastcmd, " in ", " in a "); + } + else if(i > 1 ){ + object ob1, ob2; + string tmpstr, s1, s2, article1, article2; + if(StillTrying){ + tmpstr = remove_article(direct); + if(args && sizeof(args) && answers_to(tmpstr, args[0]) && + present(args[0])) + ob1 = args[0]; + else ob1 = to_object(tmpstr, this_object()); + } + if(StillTrying && indirect){ + tmpstr = remove_article(indirect); + if(args && sizeof(args) && answers_to(tmpstr, args[0]) && + present(args[0])) + ob2 = args[0]; + else ob2 = to_object(tmpstr, this_object()); + } + if(ob1) direct = ob1->GetUniqueId(); + else direct = remove_article(direct); + if(ob2) indirect = ob2->GetUniqueId(); + else indirect = remove_article(indirect); + if(!ob1 && direct && grepp(direct," ")){ + if(sscanf(direct,"%s %s",s1, s2) == 2 && + !ordinalp(s1,1)){ + direct2 = "a "+direct; + } + } + else if(!ob1 && direct){ + if(first(direct,2) == "a " || first(direct,3) == "an "){ + direct2 = direct; + } + else direct2 = "a "+direct; + } + if(!ob2 && indirect && grepp(indirect," ")){ + if(sscanf(indirect,"%s %s",s1, s2) == 2 && + !ordinalp(s1,1)){ + if(!LimbCertain(indirect)) indirect2 = "a "+indirect; + } + } + else if(!ob2 && indirect){ + if(first(indirect,2) == "a " || first(indirect,3) == "an "){ + if(!LimbCertain(indirect)) indirect2 = indirect; + } + else if(!LimbCertain(indirect)) indirect2 = "a "+indirect; + } + if(direct && !direct2) direct2 = direct; + if(indirect && !indirect2) indirect2 = indirect; + tmpret = replace_string(lastcmd, odirect, direct2); + if(indirect2 && oindirect) tmpret = replace_string(tmpret, oindirect, indirect2); + } + + ret = tmpret; + err = parse_sentence(ret); + StillTrying = 0; + original_command = 0; + if( !stringp(err) && err > -1 ){ + return 1; + } + write("It seems you'll have to be more specific."); + return 1; +} + + +/* ********** /lib/command.c data manipulation functions ********** */ + +string *AddSearchPath(mixed val){ + if(stringp(val)){ + if(!strsrch(val,"/secure/cmds/admins") || !strsrch(val,"/cmds/admins")){ + if(!master()->valid_apply(({ "SECURE", "ASSIST", "LIB_CONNECT" })) ){ + tell_creators("Security violation in progress: "+identify(previous_object(-1)) + ", "+get_stack()); + error("Illegal attempt to modify path data: "+identify(previous_object(-1)) + ", "+get_stack()); + + } + } + val = ({ val }); + } + + else if(!pointerp(val)) error("Bad argument 1 to AddSearchPath()\n"); + return (SearchPath = distinct_array(SearchPath + val)); +} + +string *RemoveSearchPath(mixed val){ + if(stringp(val)) val = ({ val }); + else if(!pointerp(val)) error("Bad argument 1 to RemoveSearchPath()\n"); + return (SearchPath -= val); +} + +string *GetSearchPath(){ return SearchPath; } + +int GetForced(){ return Forced; } + +int GetClient(){ return 0; } + +string GetCurrentCommand(){ + if(!this_player()) return ""; + if(this_player() != this_object()) return ""; + return current_command; +} + +int SetPlayerPaused(int i){ + if( base_name(previous_object()) != LIB_CONNECT && + (!this_player() || !archp(this_player())) ){ + error("Illegal attempt to pause a player: "+get_stack()+" "+identify(previous_object(-1))); + log_file("adm/pause",timestamp()+" Illegal attempt to access SetPlayerPaused on "+identify(this_object())+" by "+identify(previous_object(-1))+"\n"); + } + Paused = i; + return Paused; +} + +int GetPlayerPaused(){ + return Paused; +} + +string SetCommandFail(string str){ + if( !str || str == "" ){ + if(!creatorp(this_object())) CommandFail = "Try \"help commands\" for a list of some commands."; + if(creatorp(this_object())) CommandFail = "Try \"help creator commands\" for a list of some creator commands."; + return CommandFail; + } + else return (CommandFail = str); +} + +string GetCommandFail(){ return CommandFail; } diff --git a/lib/lib/comp/container.c b/lib/lib/comp/container.c new file mode 100644 index 0000000..87372a0 --- /dev/null +++ b/lib/lib/comp/container.c @@ -0,0 +1,75 @@ +/* /lib/comp/container.c + * From the Dead Souls LPC Library + * Object inherited by all objects with inventories + * Created by Descartes of Borg 940212 + * Version: @(#) container.c 1.3@(#) + * Last modified: 96/12/31 + */ + +#include <lib.h> + +inherit LIB_LOOK_IN; +inherit LIB_ADDSTUFF; + +int SetOpacity(int x){ + return look_in::SetOpacity(x); +} + +int GetOpacity(){ + return look_in::GetOpacity(); +} + +int GetRadiantLight(int ambient){ + int r = this_object()->GetBaseRadiance(ambient); + int o = GetOpacity(); + if( o > 99 ){ + if( r < 1 ){ + return 0; + } + else { + int y = r / (ambient || 1); + + if( y > r ){ + return r; + } + else { + return y; + } + } + } + foreach(object ob in all_inventory()){ + r += ob->GetRadiantLight(ambient); + } + if( ambient > 0 ){ + int y; + + y = (r*10)/ambient; + if( y > r ){ + y = r; + } + else { + r = y; + } + } + return ( (r*(100-o))/100 ); +} + +int CanReceive(object ob){ + return 1; +} + +int CanRelease(object ob){ + return 1; +} + +int eventReceiveObject(object ob){ + return !(!previous_object()); +} + +int eventReleaseObject(object ob){ + return !(!previous_object()); +} + +mixed eventPostRelease(object ob){ + return 1; +} diff --git a/lib/lib/comp/holder.c b/lib/lib/comp/holder.c new file mode 100644 index 0000000..a4f0344 --- /dev/null +++ b/lib/lib/comp/holder.c @@ -0,0 +1,113 @@ +/* /lib/comp/holder.c + * From the Dead Souls Mud Library + * A composite object that holds inanimate items + * Created by Descartes of Borg 960113 + * Version: @(#) holder.c 1.6@(#) + * Last modified: 96/12/22 + */ + +#include <lib.h> + +inherit LIB_CARRY; // Handles capacity issues +inherit LIB_CONTAINER; // Determines whether something can be contained +inherit LIB_GET_FROM; // Let's players things from it and put them in +inherit LIB_INVENTORY; // Let's cres specify an initial inventory + +private static int Persist = 0; + +int isBag(){ + return 1; +} + +int GetOpacity(){ + return container::GetOpacity(); +} + +int SetOpacity(int x){ + return container::SetOpacity(x); +} + +varargs string GetInternalDesc(){ + object array items = all_inventory(); + string desc; + int surfacep; + + surfacep = inherits(LIB_SURFACE , this_object()); + + desc = (container::GetInternalDesc() || ""); + if(this_object()->CanClose() && GetOpacity() > 33){ + if(this_object()->GetClosed()) desc += " It is closed. "; + else desc += " It is open. "; + } + if(!surfacep) desc = desc + capitalize(add_article(GetShort(), 1)); + if(surfacep) desc = "On "+add_article(GetShort(), 1); + items = filter(items, (: !($1->isDummy()) && !($1->GetInvis()) :)); + if( sizeof(items) ){ + if(surfacep){ + desc = desc+" you see " + item_list(items) + "."; + } + else desc = desc + " contains " + item_list(items) + "."; + } + else { + if(!surfacep) desc = desc + " is completely empty."; + else desc = desc + " you see nothing."; + } + return desc; +} + +static mixed array AddSave(mixed array vars){ + return ({}); +} + +int SetSaveRecurse(int x){ + return 0; +} + +int CanReceive(object ob){ + if( !CanCarry(ob->GetMass()) ){ + return 0; + } + return container::CanReceive(ob); +} + +static void eventLoadInventory(){ + if( !environment() || Persist ){ + return; + } + Persist = 1; + inventory::eventLoadInventory(); +} + +int eventReceiveObject(object ob){ + mixed tmp = container::eventReceiveObject(ob); + + if( tmp != 1 ){ + return tmp; + } + AddCarriedMass(ob->GetMass()); + if(environment()) environment()->AddCarriedMass(ob->GetMass()); + parse_refresh(); + return 1; +} + +int eventReleaseObject(object ob){ + int x; + + x = container::eventReleaseObject(ob); + if(ob->GetMass()){ + AddCarriedMass(-(ob->GetMass())); + if(environment()) environment()->AddCarriedMass(-(ob->GetMass())); + } + parse_refresh(); + return x; +} + +static void create(){ + AddSave(({ "Persist" })); + SetSaveRecurse(1); + call_out((: reset :), 0); +} + +mixed inventory_visible(){ + return container::inventory_visible(); +} diff --git a/lib/lib/comp/object.c b/lib/lib/comp/object.c new file mode 100644 index 0000000..91bfef7 --- /dev/null +++ b/lib/lib/comp/object.c @@ -0,0 +1,52 @@ +/* /lib/comp/object.c + * From the Dead Souls LPC Library + * Object inherited by all tangible objects (ones with environments) + * Created by Descartes of Borg 940211 + * Version: @(#) object.c 1.10@(#) + * Last Modified: 96/12/22 + */ + +#include <lib.h> + +//inherit LIB_SHADOW_HOOK; +inherit LIB_CLEAN; +inherit LIB_DESCRIPTION; +inherit LIB_ID; +inherit LIB_LISTEN; +inherit LIB_LOOK; +inherit LIB_PROPERTIES; +inherit LIB_RADIANCE; +inherit LIB_SMELL; +inherit LIB_TOUCH; +inherit LIB_SHOOT; + +mixed CanDest(){ + if(environment() != environment(this_player()) && + environment() != this_player()) + return "#That's not accessible to you."; + else return 1; +} + +mixed indirect_dest_obj(){ return CanDest(); } +mixed direct_dest_obj(){ return CanDest(); } + +/* ************************ object.c events ********************* */ +static int Destruct(){ + object env; + int x; + + if( env = environment() ){ + env->eventReleaseObject(this_object()); + x = clean::Destruct(); + if( !x ){ + env->eventReceiveObject(this_object()); + } + return x; + } + else return clean::Destruct(); +} + +/* ******************* object.c driver applies **************** */ +static void create(){ + parse_init(); +} diff --git a/lib/lib/comp/seal.c b/lib/lib/comp/seal.c new file mode 100644 index 0000000..5b06d2d --- /dev/null +++ b/lib/lib/comp/seal.c @@ -0,0 +1,56 @@ +/* /lib/comp/seal.c + * from the Dead Souls Mud Library + * Composite component of a closeable and lockable thing + * Created by Descartes of Borg 961221 + * Version: @(#) seal.c 1.2@(#) + * Last modified: 96/12/23 + */ + +#include <lib.h> + +inherit LIB_CLOSE; +inherit LIB_LOCK; + +mixed CanLock(object who, string id){ + mixed tmp = lock::CanLock(who); + + if( tmp != 1 ){ + return tmp; + } + if( !GetClosed() ){ + return "You cannot lock it while it is open."; + } + return 1; +} + +varargs mixed CanOpen(object who, string id){ + if( GetLocked() ){ + id = "It is locked!"; + return id; + } + else return close::CanOpen(who); +} + +varargs mixed eventOpen(object who, object tool){ + if( tool && GetLocked() ){ + mixed tmp; + if(tool && objectp(tool)){ + tmp = eventPick(who, tool->GetKeyName(), tool); + } + else tmp = eventPick(who); + + if( tmp != 1 || GetLocked() ){ + return tmp; + } + } + if( GetLocked() ){ + send_messages(({ "attempt", "find" }), "$agent_name $agent_verb to " + "open $target_name, but $agent_nominative $agent_verb " + "it locked.", who, this_object(), environment(who)); + return 1; + } + return close::eventOpen(who, tool); +} + +void create(){ +} diff --git a/lib/lib/comp/surface.c b/lib/lib/comp/surface.c new file mode 100644 index 0000000..8dbe822 --- /dev/null +++ b/lib/lib/comp/surface.c @@ -0,0 +1,12 @@ +#include <lib.h> + +inherit LIB_STORAGE; +inherit LIB_ROLL; + +void create(){ + storage::create(); +} + +int eventPutOn(object player, object item){ + return 1; +} diff --git a/lib/lib/comp/weapon.c b/lib/lib/comp/weapon.c new file mode 100644 index 0000000..0c4e8ab --- /dev/null +++ b/lib/lib/comp/weapon.c @@ -0,0 +1,221 @@ +/* /lib/comp/weapon.c + * From the Dead Souls Mud Library + * This object combines the ability to be wielded with damage doing + * Created by Descartes of Borg 960211 + * Version: @(#) weapon.c 1.13@(#) + * Last modified: 97/01/01 + */ + +#include <lib.h> +#include <function.h> + +inherit LIB_DAMAGE; +inherit LIB_EQUIP; +inherit LIB_POISON; +inherit LIB_WIELD; + +private int Hands = 1; +int Wielded = 0; +private string WeaponType = "blunt"; +private static mixed Wield = 0; + +// abstract methods +string GetDefiniteShort(); +string GetKeyName(); +string GetShort(); +// end abstract methods + +int GetWielded(){ + return Wielded; +} + +varargs string GetEquippedDescription(object who){ + if(!who) who = this_player(); + if( GetWorn() ){ + string tmp = " It is wielded in "; + if(who == environment()){ + tmp += "your"; + } + else { + tmp += possessive_noun(environment()); + } + tmp += " " + item_list(GetWorn()) + "."; + return tmp; + } + return 0; +} + +string GetEquippedShort(){ + object env = environment(); + string ret = GetShort(); + string array limbs; + + if( !env || !living(env) ){ + return ret; + } + limbs = GetWorn(); + if( sizeof(limbs) > 0 ){ + ret += " (%^RED%^wielded in " + item_list(limbs) + "%^RESET%^)"; + } + return ret; +} + +int GetHands(){ + return Hands; +} + +int SetHands(int x){ + return (Hands = x); +} + +string array GetSave(){ + string *d_save, *e_save, *p_save, *a_save; + + d_save = damage::GetSave(); + e_save = equip::GetSave(); + p_save = poison::GetSave(); + a_save = d_save + e_save + p_save + ({"Wielded"}); + return a_save; +} + +string GetWeaponType(){ + return WeaponType; +} + +string SetWeaponType(string str){ + if( !stringp(str) ){ + error("Bad argument 1 to SetWeaponType().\n\tExpected: string, Got: " + + typeof(str) + "\n"); + } + return (WeaponType = str); +} + +mixed GetWield(){ + return Wield; +} + +mixed SetWield(mixed val){ + return (Wield = val); +} + +mixed CanEquip(object who, string array limbs){ + mixed tmp = equip::CanEquip(who, limbs); + + if( tmp != 1 ){ + return tmp; + } + if( GetHands() != sizeof(limbs) ){ + return "#You must use " + cardinal(Hands) + " hands to wield " + + GetDefiniteShort() + "."; + } + if( Hands > sizeof(who->GetWieldingLimbs()) ){ + return "#You do not have enough limbs for that weapon!"; + } + if( newbiep(who) && GetClass() > 30 ){ + return "You are not skilled enough to wield this weapon."; + } + return 1; +} + +int eventDeteriorate(int type){ + int x = GetClass(); + + if( x ){ + object env = environment(); + + if( living(env) ){ + if( x > 1 ){ + env->eventPrint(capitalize(GetDefiniteShort()) + + " is wearing down."); + } + else { + env->eventPrint(capitalize(GetDefiniteShort()) + + " is completely worn."); + } + } + if( GetProperty("blessed") ){ + SetClass(x-2); + } + else { + SetClass(x-1); + } + } + return 1; +} + +mixed eventEquip(object who, string array limbs){ + mixed tmp; + + if( functionp(Wield) ){ + if( functionp(Wield) & FP_OWNER_DESTED ){ + return "Function pointer owner destructed."; + } + if( !evaluate(Wield, who, limbs) ){ + return 1; + } + else { + Wielded = 1; + return equip::eventEquip(who, limbs); + } + } + Wielded = 1; + tmp = equip::eventEquip(who, limbs); + if( tmp != 1 ){ + Wielded = 0; + return tmp; + } + if( stringp(Wield) ){ + who->eventPrint(Wield); + } + else { + who->eventPrint("You wield " + GetShort() + "."); + } + environment(who)->eventPrint(who->GetName() + " wields " + GetShort() + + ".", who); + return 1; +} + +int eventStrike(object target){ + int poison = GetPoison(); + + if( poison > 0 ){ + int x = random(poison) + 1; + + if( x > 0 ){ + send_messages("", "$agent_possessive_noun " + GetKeyName() + + " poisons $target_name.", environment(), target, + environment(environment())); + target->AddPoison(x); + AddPoison(-x); + } + } + return damage::eventStrike(target); +} + +mixed eventUnequip(object who){ + mixed tmp = equip::eventUnequip(who); + + if( tmp != 1 ){ + Wielded = 1; + return tmp; + } + Wielded = 0; + if(!who->GetDead()) send_messages("unwield", "$agent_name $agent_verb $target_name.", + who, this_object(), environment(who)); + return 1; +} + +// Some things to respond to provide friendly error messages +mixed direct_remove_obj(){ + if( environment() != this_player() ){ + return "#You don't have that!"; + } + return "#Do you mean to unwield it?"; +} + +mixed direct_wear_obj(){ + if( environment() != this_player() ){ + return "#You don't have that!"; + } + return "#Do you mean to wield it?"; +} diff --git a/lib/lib/creator.c b/lib/lib/creator.c new file mode 100644 index 0000000..aaab20e --- /dev/null +++ b/lib/lib/creator.c @@ -0,0 +1,267 @@ +/* /lib/creator.c + * from the Dead Souls LPC Library + * a very simple creator object + * created by Descartes of Borg 950321 + * Version: @(#) creator.c 1.14@(#) + * Last Modified: 96/12/21 + */ + +#include <lib.h> +#include <daemons.h> +#include <vision.h> +#include <position.h> +#include <message_class.h> +#include "include/creator.h" + +inherit LIB_PLAYER; + +#ifdef __PACKAGE_DATABASE_DB__ +inherit LIB_ISQL; +#endif /* __PACKAGE_DATABASE_DB__ */ + +private int showgrid, wizvision, CreatorAge, CreatorBirth; +private static int LastCreatorAge; +private string LivingShort; + +/* ***************** /lib/creator.c driver applies ***************** */ + +static void create(){ + player::create(); + CreatorAge = 0; + LastCreatorAge = time(); + CreatorBirth = time(); +} + +int is_living(){ return 1; } + +int inventory_accessible(){ return 1; } + +int inventory_visible(){ return 1; } + +mixed direct_verb_rule(string verb){ + return SOUL_D->CanTarget(this_player(), verb, this_object()); +} + +mixed direct_give_liv_obj(){ + if( this_player() == this_object() ) return "Are you confused?"; + return 1; +} + +mixed direct_give_liv_obs(){ + return direct_give_liv_obj(); +} + +mixed indirect_give_obj_to_liv(object item){ + if( !item ) return 0; + if( this_player() == this_object() ) return "Are you confused?"; + if( environment(item) != this_player() ) return "You don't have that!"; + return CanCarry(item->GetMass()); +} + +mixed indirect_give_obs_to_liv(object *item){ + return 1; +} + +mixed direct_look_obj(){ return 1; } + +mixed direct_look_at_obj(){ return 1; } + +mixed direct_marry_liv_to_liv(){ + return 1; +} + +mixed indirect_marry_liv_to_liv(){ + return 1; +} + +static void net_dead(){ + player::net_dead(); + CreatorAge += time() - LastCreatorAge; + LastCreatorAge = time();} + + void eventReconnect(){ + string tmp; + + player::eventReconnect(); + LastCreatorAge = time(); + if( file_exists(tmp = user_path(GetKeyName()) + "dead.edit") ) + message("system", "\nYour edit file was saved as: "+tmp, this_object()); + } + +varargs int eventShow(object who, string str, string on_id){ + player::eventShow(who, str); + return 1; +} + +/* ***************** /lib/creator.c events ***************** */ + +void eventDescribeEnvironment(int verbose){ + object env; + + if( !(env = environment()) ){ + message("room_description", "No environment.", this_object()); + return; + } + message("system", file_name(env), this_object()); + if(this_object()->GetVisibleGrid() && environment(this_object())){ + string grid = ROOMS_D->GetCoordinates(environment(this_object())); + if(sizeof(grid) > 2){ + grid = "Global coordinates: "+grid; + } + else { + grid = "Global coordinates unavailable."; + } + message("system", grid, this_object()); + } + player::eventDescribeEnvironment(verbose); +} + +static int Destruct(){ + int x; + + if( !(x = player::Destruct()) ) return 0; +#ifdef __PACKAGE_DATABASE_DB__ + isql::Destruct(); +#endif /* __PACKAGE_DATABASE_DB__ */ + return x; +} + +/* ***************** /lib/creator.c local functions ***************** */ + +int Setup(){ + string tmp; + int bugs, laston; + + laston = GetLoginTime(); + if( !player::Setup() ) return 0; + if( archp() ) AddChannel( ({ "admin", "error" }) ); + AddSearchPath( ({ DIR_CREATOR_CMDS, DIR_SECURE_CREATOR_CMDS }) ); + if( file_size(tmp = user_path(GetKeyName()) + "cmds") == -2 ) + AddSearchPath( ({ tmp }) ); + if( archp() ) AddSearchPath( ({ DIR_ADMIN_CMDS, DIR_SECURE_ADMIN_CMDS }) ); + if( bugs = BUGS_D->GetAssignedBugs(GetKeyName()) ) + message("system", "\n >>> You have " + + consolidate(bugs, "an incomplete bug") + + " assigned to you!!!! <<<\n", this_object()); + NOTIFY_D->eventPrintNotices(this_object(), laston); + + /* Check for new customdefs location */ + if(!file_exists(tmp = REALMS_DIRS+"/"+GetKeyName()+"/area/customdefs.h")){ + string tmp2 = REALMS_DIRS+"/"+GetKeyName()+"/customdefs.h"; + if(file_exists(tmp2) && directory_exists(REALMS_DIRS+"/"+GetKeyName())) + cp(tmp2, tmp); + } + + return 1; +} + +int eventForce(string cmd){ + if( !(master()->valid_apply( ({ GetKeyName() }) )) ) return 0; + else return player::eventForce(cmd); +} + +/* *************** /lib/creator.c modal functions *************** */ + +int CanCarry(int amount){ return 1; } + +/* ************ /lib/creator.c data manipulation functions ************ */ + +int GetCreatorAge(){ + int x; + + if( !interactive(this_object()) ) return CreatorAge; + x = time() - LastCreatorAge; + CreatorAge += x; + LastCreatorAge = time(); + return CreatorAge; +} + +varargs string GetLong(string str){ + str = player::GetLong() + "\n"; + return str; +} + +int GetCreatorBirth(){ return CreatorBirth; } + +string GetName(){ + if( !GetInvis() || previous_object()->GetWizVision() ) return ::GetName(); + else return "A shadow"; +} + +mapping GetSpellBook(){ + mapping ret = ::GetSpellBook(); + foreach(string spell in keys(SPELLS_D->GetSpells())){ + ret[spell] = 100; + } + foreach(string spell in keys(SPELLS_D->GetPrayers())){ + ret[spell] = 100; + } + return ret; +} + +varargs mixed CanCast(mixed spell...){ + return 1; +} + +varargs mixed GetEffectiveVision(mixed location, int raw_score){ + if(wizvision) return VISION_CLEAR; + return player::GetEffectiveVision(location, raw_score); +} + +int SetWizVision(int i){ + if(!this_player()) return 0; + if(archp(this_object()) && !archp(this_player())) return 0; + if(!archp(this_object()) && this_player() != this_object()) return 0; + if(i) wizvision = 1; + else wizvision = 0; + return wizvision; +} + +int GetWizVision(){ + return wizvision; +} + +int SetVisibleGrid(int i){ + if(!this_player()) return 0; + if(archp(this_object()) && !archp(this_player())) return 0; + if(!archp(this_object()) && this_player() != this_object()) return 0; + if(i) showgrid = 1; + else showgrid = 0; + return showgrid; +} + +int GetVisibleGrid(){ + return showgrid; +} + +string GetLivingShort(){ + return LivingShort; +} + +int eventDie(mixed agent){ + string tmpshort = this_object()->GetShort(); + if(this_object()->GetGodMode()) return 0; + if(!grepp(tmpshort,"the ghost") && !grepp(tmpshort,"the reborn")){ + LivingShort = replace_string(tmpshort,this_object()->GetName(), + "$N"); + } + return ::eventDie(agent); +} + +int eventReleaseObject(object foo2){ + int ret = ::eventReleaseObject(foo2); + if(ret && GetParanoia("inventory_monitoring")) + eventPrint("%^YELLOW%^NOTICE:%^RESET%^ "+identify(foo2)+ + " leaves your inventory."); + flush_messages(this_object()); + return ret; +} + +int eventMove(mixed dest){ + if(GetParanoia("move_monitoring")){ + eventPrint("%^RED%^B_BLACK%^You are about to move to: "+ + identify(dest)+"!%^RESET%^\nstack:\n"+get_stack(1)); + flush_messages(this_object()); + } + return ::eventMove(dest); +} diff --git a/lib/lib/currency.c b/lib/lib/currency.c new file mode 100644 index 0000000..5ea38ee --- /dev/null +++ b/lib/lib/currency.c @@ -0,0 +1,115 @@ +/* /lib/currency.c + * from the Dead Souls LPC Library + * handles player bank accounts and carried currency + * created by Descartes of Borg 950324 + */ + + +#include <lib.h> + +private mapping Currency = ([]); +private mapping Bank = ([]); + +// abstract methods +int CanCarry(int amount); +// end abstract methods + +/* *************** /lib/currency.c driver applies *************** */ + +static void create(){ +} + +/* *************** /lib/currency.c data manipulation funcs *************** */ + +int AddCurrency(string type, int amount){ + if( amount > 0 ){ + int curr_mass; + curr_mass = to_int(currency_mass(amount, type)); + if(curr_mass < 1 ) curr_mass = 1; + if( !CanCarry(curr_mass) ){ + return -1; + } + } + if( amount + Currency[type] < 0 ){ + return -1; + } + return (Currency[type] += amount); +} + +int GetCurrency(string type){ return Currency[type]; } +mapping GetCurrencyMap(){ return copy(Currency); } + +varargs int GetCurrencyMass(string type){ + int total; + + if( stringp(type) ){ + return currency_mass(Currency[type], type); + } + foreach(string currency, int amount in Currency){ + total += currency_mass(amount, currency); + } + return total; +} + +int AddBank(string bank, string type, int amount){ + if( !stringp(bank) ) error("Bad argument 1 to AddBank()."); + if( !Bank[bank] ){ + if( amount < 1 ) return -1; + Bank[bank] = ([ "open" : time(), type : amount, "last time" : time(), + "last trans" : "opened account", + "audit" : identify(previous_object(-1)) ]); + return amount; + } + if( Bank[bank][type] + amount < 0 ) return -1; + Bank[bank][type] += amount; + Bank[bank]["last time"] = time(); + if( amount > 0 ) Bank[bank]["last trans"] = "deposit"; + else Bank[bank]["last trans"] = "withdrawal"; + Bank[bank]["audit"] = identify(previous_object(-1)); + return Bank[bank][type]; +} + +int GetBank(string bank, string type){ + if( !Bank[bank] ) return -1; + else return Bank[bank][type]; +} + +mapping GetAccountInfo(string bank){ + if( !Bank[bank] ) return 0; + else return copy(Bank[bank]); +} + +varargs int GetNetWorth(string benjamins){ + string curr; + float net_worth = 0.0; + int amt; + foreach(curr, amt in Currency){ + if(valid_currency(curr)) + net_worth += amt * currency_rate(curr); + + } + foreach(string bank, mapping balance in Bank){ + foreach(curr, amt in balance){ + float tmp; + + switch(curr){ + case "last trans": case "last time": case "audit": case "open": + break; + default: + if( (tmp = currency_rate(curr)) < 1 ) break; + net_worth += amt * tmp; + break; + } + } + } + if(!benjamins || benjamins == ""||!stringp(benjamins)) benjamins = "gold"; + if(member_array(benjamins,mud_currencies()) == -1) benjamins = "gold"; + if(benjamins && net_worth) return to_int(net_worth / currency_rate(benjamins)); + else return to_int(0); +} + +string array GetCurrencies(){ return keys(Currency); } + +void ResetBank(){ Bank = ([]); } + +void ResetCurrency(){ Currency = ([]); } diff --git a/lib/lib/cylinder.c b/lib/lib/cylinder.c new file mode 100644 index 0000000..b3592d0 --- /dev/null +++ b/lib/lib/cylinder.c @@ -0,0 +1,14 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_STORAGE; +void create(){ + ::create(); + SetKeyName("revolver cylinder"); + SetId(({"cylinder"})); + SetShort("a revolver cylinder"); + SetLong("This is the round barrel the holds a revolver's bullets."); + SetMass(5); + SetValue(10); + SetMaxCarry(10); + SetVendorType(VT_TREASURE); +} diff --git a/lib/lib/daemons/include/verb.h b/lib/lib/daemons/include/verb.h new file mode 100644 index 0000000..eae4646 --- /dev/null +++ b/lib/lib/daemons/include/verb.h @@ -0,0 +1,13 @@ +#ifndef l_verb_h +#define l_verb_h + +static void create(); + +varargs static string *SetRules(mixed *args...); +string *GetRules(); +varargs static string *SetSynonyms(mixed *args...); +string *GetSynonyms(); +static string SetVerb(string str); +string GetVerb(); + +#endif /* l_verb_h */ diff --git a/lib/lib/daemons/player_stub.c b/lib/lib/daemons/player_stub.c new file mode 100644 index 0000000..c836d81 --- /dev/null +++ b/lib/lib/daemons/player_stub.c @@ -0,0 +1,21 @@ +/* This is a temporary object that holds a + * player's interactive link while her old body + * is being destroyed and before her new one is + * created. This should only be needed when the + * player needs to be reloaded without quitting. + */ + +#include <lib.h> +#include <daemons.h> + +private static string keyname; + +string SetKeyName(string str){ + if(base_name(previous_object()) != RELOAD_D) return ""; + keyname = str; + return keyname; +} + +string GetKeyName(){ + return keyname; +} diff --git a/lib/lib/daemons/verb.c b/lib/lib/daemons/verb.c new file mode 100644 index 0000000..487ce5f --- /dev/null +++ b/lib/lib/daemons/verb.c @@ -0,0 +1,74 @@ +/* /lib/verb.c + * From the Dead Souls Mud Library + * An inheritable for creating verbs + * Created by Descartes of Borg 960116 + * Version: @(#) verb.c 1.2@(#) + * Last modified: 96/12/17 + */ + +#include <lib.h> +#include "include/verb.h" + +inherit LIB_DAEMON; +inherit LIB_HELP; + +private string Verb, ErrorMessage; +private string *Synonyms, *Rules; + +static void create(){ + daemon::create(); + SetNoClean(1); + parse_init(); + Verb = 0; + ErrorMessage = 0; + Rules = ({}); + Synonyms = ({}); +} + +static string SetErrorMessage(string str){ return (ErrorMessage = str); } + +string GetErrorMessage(){ return ErrorMessage; } + +varargs static string *SetRules(mixed *args...){ + if( sizeof(Rules) ) error("Cannot reset rules list."); + foreach(mixed arg in args){ + if( stringp(arg) ) Rules += ({ arg }); + else Rules += arg; + } + if( Verb ){ + foreach(string rule in Rules) parse_add_rule(Verb, rule); + if( sizeof(Synonyms) ) + foreach(string cmd in Synonyms) parse_add_synonym(cmd, Verb); + } + return Rules; +} + +string *GetRules(){ return copy(Rules); } + +varargs static string *SetSynonyms(mixed *args...){ + if( sizeof(Synonyms) ) error("Cannot reset synonym list.\n"); + foreach(mixed arg in args){ + if( stringp(arg) ) Synonyms += ({ arg }); + else Synonyms += arg; + } + if( Verb && sizeof(Rules) ) + foreach(string cmd in Synonyms) parse_add_synonym(cmd, Verb); + return Synonyms; +} + +string *GetSynonyms(){ return copy(Synonyms); } + +static string SetVerb(string str){ + if( !stringp(str) ) error("Bad argument 1 to SetVerb().\n"); + Verb = str; + if( sizeof(Rules) ) + foreach(string rule in Rules) parse_add_rule(Verb, rule); + if( sizeof(Synonyms) ) + foreach(string cmd in Synonyms) parse_add_synonym(cmd, Verb); + return Verb; +} + +string GetVerb(){ return Verb; } + +string *GetVerbs(){ return ({ Verb }); } + diff --git a/lib/lib/detect.c b/lib/lib/detect.c new file mode 100644 index 0000000..e3010ff --- /dev/null +++ b/lib/lib/detect.c @@ -0,0 +1,108 @@ +/* /lib/detect.c + * from the Dead Souls LPC Library + * inheritable object for all tangible game objects + * created by Descartes of Borg 950207 + */ + +#include <dirs.h> +#include "include/detect.h" + +int direct_detect_wrd_in_obj(string word){ + if( environment() != this_player() && + environment() != environment(this_player()) ){ + this_player()->eventPrint("You need better access to it."); + return 0; + } + else return 1; +} + +mixed eventDetect(object who, string str, int ability){ + mixed magic; + + magic = GetProperty("magic item"); + if( str == "magic" ){ + if( !magic ){ + if( random(ability) > 50 ){ + who->AddSkillPoints("conjuring", random(ability * 2 + 1)); + message("my_action", "You are certain there is no magic " + "in " + GetShort() + ".", who); + return 1; + } + else { + string *spells; + string spell; + + if( random(ability) > 50 ){ + who->AddSkillPoints("conjuring", random(ability)); + message("my_action", "You do not detect any magic " + "in " + GetShort() + ".", who); + return 1; + } + who->AddSkillPoints("conjuring", random(5)); + spells = map(get_dir(DIR_SPELL_VERBS + "/*.c"), (: $1[0..<3] :)); + spell = spells[random(sizeof(spells))]; + message("my_action", "You vaguely sense \"" + spell + "\".", + who); + return 1; + } + } + else { + string *spells; + string spell; + + if( random(ability) > 20 ){ + who->AddSkillPoints("conjuring", random(1 + 2* ability)); + if( arrayp(magic) ) magic = magic[random(sizeof(magic))]; + if( random(ability) > 50 ) + message("my_action", "You definitely sense \"" + + magic + "\".", who); + else message("my_action", "You vaguely sense \"" + magic + + "\".", who); + return 1; + } + who->AddSkillPoints("conjuring", random(5) + 1); + if( random(ability) > 50 ){ + message("my_action", "You do not detect any magic " + "in " + GetShort() + ".", who); + return 1; + } + spells = map(get_dir(DIR_SPELL_VERBS + "/*.c"), (: $1[0..<3] :)); + spell = spells[random(sizeof(spells))]; + message("my_action", "You vaguely sense \"" + spell + "\".", who); + return 1; + } + } + if( !magic ){ + if( random(ability) > 20 ){ + who->AddSkillPoints("conjuring", random(ability) + 5); + message("my_action", "You do not sense " + str + ".", who); + } + else { + who->AddSkillPoints("conjuring", random(5)); + message("my_action", "You are not at all certain.", who); + } + return 1; + } + if( (arrayp(magic) && member_array(str, magic) != -1) || + (stringp(magic) && str == magic) ){ + if( random(ability) > 10 ){ + who->AddSkillPoints("conjuring", random(ability)); + message("my_action", "You sense " + str + " in " + + GetShort() + ".", who); + } + else { + who->AddSkillPoints("conjuring", random(5)); + message("my_action", "Everything seems fuzzy in your head.", who); + } + return 1; + } + if( random(ability) > 10 ){ + who->AddSkillPoints("conjuring", random(ability)); + message("my_action", "You do not sense " + str + " in " + + GetShort() + ".", who); + return 1; + } + who->AddSkillPoints("conjuring", random(5)); + message("my_action", "Everything seems fuzzy in your head.", who); + return 1; +} diff --git a/lib/lib/die.c b/lib/lib/die.c new file mode 100644 index 0000000..b99da60 --- /dev/null +++ b/lib/lib/die.c @@ -0,0 +1,102 @@ +#include <lib.h> +#include <events.h> + +inherit LIB_ITEM; +inherit LIB_ROLL; +inherit LIB_SHAKE; +inherit LIB_CONSULT; + +int Denominator = 6; +int Result = 6; +string BaseLong; + +int SetDenominator(int denom){ + if(!denom) return; + else return Denominator = denom; +} + +string SetLong(string str){ + item::SetLong(str); + if(!BaseLong) BaseLong = str; + return BaseLong; +} + +static void create(){ + item::create(); + SetKeyName("die"); + SetId(({"dado","bone", "alea"})); + SetShort("a six-sided die"); + SetLong("A typical die used for games of chance. It is orange and marked " + "with numbers rather than dots."); + SetDenominator(6); + SetNoCondition(1); +} + +void init(){ + item::init(); + if(member_array("d"+Denominator,GetId()) == -1){ + SetId(GetId()+({ "d"+Denominator }) ); + } +} + +int doRoll(){ + Result = random(Denominator)+1; + SetLong(BaseLong + "\nThe die's result is: "+Result+".\n"); + return Result; +} + +int eventMove(mixed dest){ + int ret; + if(ret = (item::eventMove(dest))){ + doRoll(); + } + return ret; +} + +varargs mixed eventResults(mixed args){ + if(intp(args)){ + say("The result of "+this_player()->GetName()+"'s roll is: "+args); + write("The result of your roll is: "+args); + } + return args; +} + +varargs mixed eventRoll(object where){ + object dude = this_player(); + string extrathing = ""; + doRoll(); + if(where == environment(this_player())) where = 0; + if(!where) eventMove(environment(this_player())); + else { + if(objectp(where)) extrathing = " on "+where->GetShort(); + if(!inherits(LIB_SURFACE,where) || !eventMove(where)){ + extrathing = ""; + eventMove(environment(this_player())); + } + } + write("You roll your "+strip_article(GetShort())+extrathing+", and the result is: "+Result); + say(dude->GetName()+" rolls "+possessive(dude)+" "+strip_article(GetShort())+extrathing+", " + "and the result is: "+Result); + return Result; +} + +varargs mixed eventShake(object dude, string foo){ + write("You shake your "+strip_article(GetShort())+"."); + say(dude->GetName()+" shakes "+possessive(dude)+" "+strip_article(GetShort())+"."); + doRoll(); + return 1; +} + +varargs mixed eventConsult(object dude, string foo){ + write("The die result is: \n"+Result); + say(dude->GetName()+" consults "+possessive(dude)+" "+strip_article(GetShort())+"."); + return 1; +} + +varargs mixed CanConsult(object who, string component){ + return 1; +} + +varargs mixed CanShake(object who, string component){ + return 1; +} diff --git a/lib/lib/domesticate.c b/lib/lib/domesticate.c new file mode 100644 index 0000000..4ab18e1 --- /dev/null +++ b/lib/lib/domesticate.c @@ -0,0 +1,187 @@ +private string *TrainedSkills = ({}); +private int Befriendable, Trainable, Commandable; +private object Owner = 0; +private string *Befriended = ({}); + +mixed direct_befriend_liv(){ + return 1; +} + +mixed direct_abandon_liv(){ + return 1; +} + +mixed direct_train_liv(){ + return this_object()->CanTrain(); +} + +mixed direct_train_liv_to_str(){ + return this_object()->CanTrain(); +} + +mixed direct_untrain_liv(){ + return this_object()->CanTrain(); +} + +mixed direct_untrain_liv_to_str(){ + return this_object()->CanTrain(); +} + +mixed direct_command_liv(){ + return this_object()->CanCommand(); +} + +mixed direct_command_liv_to_str(){ + return this_object()->CanCommand(); +} + +object GetMountOwner(){ + return Owner; +} + +object SetMountOwner(object who){ + if(who) Owner = who; + return Owner; +} + +int SetCanBefriend(int i){ + if(!i) Befriendable = 0; + else Befriendable = i; + return Befriendable; +} + +int CanBefriend(object who){ + int owner_char = -1; + int player_char = -1; + if(!Befriendable) return 0; + if(Owner && objectp(Owner)) owner_char = Owner->GetStat("charisma")["level"]; + player_char = who->GetStat("charisma")["level"]; + if(player_char > Befriendable && player_char > owner_char) return 1; + return 0; +} + +int CanAbandon(object who){ + if(!Befriendable) return 0; + if(Owner && Owner == who) return 1; + else return 0; +} + +int SetCanTrain(int i){ + if(!i) Trainable = 0; + else Trainable = 1; + return Trainable; +} + +int CanTrain(){ + return Trainable; +} + +int CanUnTrain(){ + return Trainable; +} + +int SetCanCommand(int i){ + if(!i) Commandable = 0; + else Commandable = 1; + return Commandable; +} + +int eventBefriend(object who){ + if(!CanBefriend(who)){ + write("You fail to befriend "+this_object()->GetName()+"."); + say(who->GetName()+" fails to befriend "+this_object()->GetName()+ + ". "+capitalize(nominative(who))+" looks very silly!"); + return 1; + } + write("You befriend "+this_object()->GetName()+"."); + say(who->GetName()+" befriends "+this_object()->GetName()+ + ". Awwww, it's such a cute sight to see!"); + Owner = who; + Befriended += ({ who }); + return 1; +} + +int eventAbandon(object who){ + if(!CanAbandon(who)){ + write("You can't abandon "+this_object()->GetName()+"."); + return 1; + } + write("You abandon "+this_object()->GetName()+"."); + say(who->GetName()+" abandons "+this_object()->GetName()+ + ". How sad!"); + Owner = 0; + return 1; +} + +varargs int eventTrainLiving(object who, string what){ + if(what) what = replace_string(what, "to ", ""); + if(!who) who = this_player(); + if(Owner != who){ + write("You are not this mount's owner."); + return 0; + } + if(what && member_array(what, TrainedSkills) != -1){ + write(this_object()->GetName()+" already possesses that skill."); + return 1; + } + if(!what || what == "") return 1; + else { + tell_player(who,"You train "+this_object()->GetShort()+"."); + tell_room(environment(who),who->GetName()+" trains "+ + this_object()->GetShort()+".", ({ who,this_object() }) ); + TrainedSkills += ({ what }); + } + return 1; +} + +varargs int eventUnTrainLiving(object who, string what){ + if(what) what = replace_string(what, "to ", ""); + if(!who) who = this_player(); + if(Owner != who){ + write("You are not this mount's owner."); + return 0; + } + if(!what || what == ""){ + Owner = 0; + } + if(what && member_array(what, TrainedSkills) != -1){ + TrainedSkills -= ({ what }); + } + tell_player(who,"You untrain "+this_object()->GetShort()+"."); + tell_room(environment(who),who->GetName()+" untrains "+ + this_object()->GetShort()+".", ({ who,this_object() }) ); + return 1; +} + +string *GetTrainedSkilles(){ + return copy(TrainedSkills); +} + +string *SetTrainedSkills(string *skills){ + if(skills) TrainedSkills = skills; + return copy(TrainedSkills); +} + +string eventCommandNPC(object who, string cmd){ + //if(this_object()->GetStat("intelligence") < 10 + return "foo"; +} + +varargs mixed GetBefriended(mixed who){ + if(!Befriended) Befriended = ({}); + if(!who) return copy(Befriended); + if(stringp(who)) who = find_object(who); + if(objectp(who)) who = file_name(who); + if(member_array(who, Befriended) != -1) return 1; + return 0; +} + +varargs mixed SetBefriended(mixed who){ + if(!Befriended) Befriended = ({}); + if(!who) return copy(Befriended); + if(stringp(who)) who = find_object(who); + if(who && objectp(who)) who = file_name(who); + if(who) Befriended += ({ who }); + return copy(Befriended); +} + diff --git a/lib/lib/donate.c b/lib/lib/donate.c new file mode 100644 index 0000000..b832683 --- /dev/null +++ b/lib/lib/donate.c @@ -0,0 +1,80 @@ +/* /lib/donate.c + * a donation box inheritable + * created by BillGates@Dead Souls 961023 + */ + +#include "include/donate.h" +#include <lib.h> + +private int TotalAssets; +private string LocalCurrency, Owner; + +static void create(){ + this_object()->AddSave( ({ "TotalAssets" }) ); + TotalAssets = 0; +} + +static void init(){ + if( this_player()->ClassMember(GetOwner()) || + this_player()->GetClan() == GetOwner() ){ + add_action( (: eventDonate :) , "donate" ); + } +} + +string GetLong(string str){ + string ret = "\nIt currently contains "+TotalAssets+" " + + "coins and bills."; + if(TotalAssets) return ret; + else return ""; +} + +string SetLocalCurrency(string currency){ + return (LocalCurrency = currency); +} + +string GetLocalCurrency(){return LocalCurrency;} + +string SetOwner(string owner){return (Owner = owner);} + +string GetOwner(){return Owner;} + +int AddAssets(int amount){ + TotalAssets += amount; + return 1; +} + +int GetAssets(){return TotalAssets;} + +int eventDonate(string amt, string type){ + int amount; + object tp = this_player(); + + if(sscanf(amt,"%d", amount) < 1){ + write("That isn't a proper amount."); + return 1; + } + + if(!valid_currency(type)){ + write("That isn't a valid currency."); + return 1; + } + + if(!amount){ + tp->eventPrint("Donate how much?\n"); + return 0; + } + if(amount < 0){ + tp->eventPrint("Nice try!\n"); + return 0; + } + if(tp->GetCurrency(type) < amount){ + tp->eventPrint("You don't have that much " + type + "!\n"); + return 0; + } + tp->AddCurrency(type, -amount); + AddAssets(amount); + tp->eventPrint(GetOwner() + " is grateful " + "for your donation."); + if(living(this_object())) this_object()->eventForce("say Thank you!"); + return 1; +} diff --git a/lib/lib/door.c b/lib/lib/door.c new file mode 100644 index 0000000..f2b086f --- /dev/null +++ b/lib/lib/door.c @@ -0,0 +1,457 @@ +/* /lib/door.c + * from the Dead Souls LPC Library + * the standard door, window, rock object + * created by Descartes of Borg 950410 + * with many thanks to Balack@Phoenix and Deathblade@ZorkMUD for their ideas + * Version: @(#) door.c 1.8@(#) + * Last modified: 97/01/01 + */ + +#include <lib.h> +#include "include/door.h" + +inherit LIB_DAEMON; +inherit LIB_SEAL; +inherit LIB_KNOCK; +inherit LIB_SCRATCH; + +private mapping Sides; +private static int Hidden = 1; +private static int Opacity = 100; +private static int Perforated = 0; + +int GetOpacity(){ + return Opacity; +} + +int SetOpacity(int x){ + Opacity = x; + return Opacity; +} + +int GetPerforated(){ + return Perforated; +} + +int SetPerforated(int x){ + Perforated = x; + return Perforated; +} + +int CanPeer(){ + if(!GetClosed() || !Opacity) return 1; + return 0; +} + +int SetHiddenDoor(int i){ + if(i) Hidden = 1; + else Hidden = 0; + return Hidden; +} + +int GetHiddenDoor(){ + return Hidden; +} + +string *GetSides(){ + return keys(Sides); +} + +/* *************** /lib/door.c driver applies *************** */ + +static void create(){ + daemon::create(); + parse_init(); + SetNoClean(0); + SetLockStrength(50); + Sides = ([]); +} + +/* *************** /lib/door.c modals ************** */ +/* method: CanLock() + * args: + * object who - the person doing the locking + * object key - the key being used for the locking + * + * returns: 1 on success, 0 or failure string on failure + * + * Tests to see if a certain player can lock the door with a given + * key + */ +mixed CanLock(object who, string foo){ + object room; + if( !(room = environment(who)) ) return 0; + foreach(string side, mapping val in Sides){ + if( member_array(room, val["Rooms"]) != -1 ){ + if( !GetLockable(side) ) return 0; + else return seal::CanLock(who); + } + } + return 0; +} + +/* method: CanUnlock() + * args: + * object who - the person doing the unlocking + * object key - the key being used for the unlocking + * + * returns: 1 on success, 0 or failure string on failure + * + * Tests to see if a certain player can unlock the door with a given + * key + */ +mixed CanUnlock(object who){ + object room; + + if( !(room = environment(who)) ) return 0; + foreach(string side, mapping val in Sides){ + if( member_array(room, val["Rooms"]) != -1 ){ + if( !GetLockable(side) ) return 0; + else return seal::CanUnlock(who); + } + } + return 0; +} + +/* *************** /lib/door.c events ************** */ + +/* eventClose() + * object who - who is closing it + * + * returns 1,0, or an error string based on parser conditions + * + * Check to be certain the door is not already closed before calling so + * you may issue the appropriate message + */ + +varargs mixed eventClose(object who){ + object room,whom; + string tmp; + + if(!GetClosed()){ + SetClosed(1); + if(who) room = environment(who); + else room = environment(this_player()); + if(!who) whom = this_player(); + else whom = who; + foreach(string side, mapping val in Sides){ + if( member_array(environment(whom), val["Rooms"]) != -1 ) tmp = side; + if(who) + filter(val["Rooms"], (: $1 && ($1 != $(room)):))->eventPrint(capitalize(GetShort(side)) + " closes."); + else (val["Rooms"])->eventPrint(capitalize(GetShort(side)) + " closes."); + } + if(who){ + who->eventPrint("You close " + GetShort(tmp) + "."); + room->eventPrint(who->GetName() + " closes " + GetShort(tmp) + ".", + who); + } + } + return 1; +} + +/* eventLock() + * object who - the agent responsible for locking it + * object key - the key being used to lock it + * returns 1, 0 or a string according to parser conditions + * + * Check to make sure the door is closed and unlocked before calling this + * Also check to see that the door is lockable from this side + * object by is required here + */ + +varargs mixed eventLock(object who, mixed key, mixed foo){ + object room; + + room = environment(who); + + foreach(string side, mapping val in Sides){ + if( member_array(room, val["Rooms"]) != -1 ){ + string tmp; + + tmp = GetShort(side); + if( !(sizeof(key->GetId() & GetKeys(side))) ){ + who->eventPrint("You fail to lock " + tmp + + " with " + key->GetShort()+"."); + room->eventPrint(who->GetName() + " attempts to " + "lock " + tmp + " with " + + key->GetShort() + ", but fails.",who); + return 1; + } + SetLocked(1); + who->eventPrint("You lock " + tmp + + " with " + key->GetShort()+"."); + room->eventPrint(who->GetName() + " locks " + tmp + + " with " + key->GetShort() + ".", who); + return 1; + } + } + return 0; +} + +/* eventOpen() + * object by - The room from which the door is being open + * object agent - The living thing responsible for it opening + * + * returns 1, 0, or an error string depending on parser circumstances + * + * Used for actually opening the door + * Before calling this, you should check if the door is locked and + * check if it is already open so you can issue the appropriate messages + */ + +varargs int eventOpen(object who, object tool){ + object room, whom; + string tmp; + + if(GetClosed()){ + SetClosed(0); + if(who) room = environment(who); + else room = environment(this_player()); + if(!who) whom = this_player(); + else whom = who; + foreach(string side, mapping val in Sides){ + if( member_array(environment(whom), val["Rooms"]) != -1 ) tmp = side; + if(who) + filter(val["Rooms"], (: $1 && ($1 != $(room)) :))->eventPrint(capitalize(GetShort(side)) + " opens."); + else (val["Rooms"])->eventPrint(capitalize(GetShort(side)) + " opens."); + } + if(who){ + who->eventPrint("You open " + GetShort(tmp) + "."); + room->eventPrint(who->GetName() + " opens " + GetShort(tmp) + ".", + who); + } + } + return 1; +} + +/* eventRegisterSide() + * string side - directional exit identifying which side of the door this room + * exits in + * + * returns 1 on success, 0 on failure + * + * never should be called manually + * this is called by SetDoor() in exits.c to tell the door there is a room + * which is observing it + */ + +int eventRegisterSide(string side){ + string array id = GetId(side); + Sides[side]["Rooms"] = + distinct_array(Sides[side]["Rooms"] + + ({ previous_object() })); + previous_object()->AddItem(id, (: GetLong($(side)) :)); + foreach(object ob in all_inventory(previous_object())){ + if( !ob->isDummy() ){ + continue; + } + if( sizeof(id & ob->GetId()) ){ + if(!ob->GetDoor()) ob->SetDoor(file_name(this_object()), side); + } + } + return 1; +} + +/* method: eventUnlock() + * args: + * object who - the person unlocking the door + * object key - the key being used to unlock it + * + * returns: 1 on success, 0 or failure string on failure + * + * Check to make sure the door is closed and locked before calling this + * Also check to see that the door is lockable from this side + * object by is required here + */ +mixed eventUnlock(object who, object key){ + object room; + string *key_id = key->GetId(); + room = environment(who); + foreach(string side, mapping val in Sides){ + if( member_array(room, val["Rooms"]) != -1 ){ + string tmp; + + tmp = GetShort(side); + if(!sizeof((key_id & (GetKeys(side) || ({}))))){ + who->eventPrint("You fail to unlock " + tmp + + " with " + key->GetShort()+"."); + room->eventPrint(who->GetName() + " attempts to " + "unlock " + tmp + " with " + + key->GetShort() + ", but fails.",who); + return 1; + } + SetLocked(0); + who->eventPrint("You unlock " + tmp + "."); + room->eventPrint(who->GetName() + " unlocks " + tmp + + " with " + key->GetShort() + ".", who); + return 1; + } + } + return 0; +} + +/* ************** /lib/door.c data functions ************** */ + +void SetSide(string side, mapping mp){ + mapping new_side = ([ "Rooms" : ({}) ]); + + if( stringp(mp["id"]) ) new_side["Ids"] = ({ mp["id"] }); + else new_side["Ids"] = mp["id"]; + new_side["Short"] = mp["short"]; + new_side["Long"] = mp["long"]; + if( stringp(mp["keys"]) ) new_side["Keys"] = ({ mp["keys"] }); + else new_side["Keys"] = mp["keys"]; + new_side["Lockable"] = mp["lockable"]; + Sides[side] = new_side; +} + +mapping GetSide(string side){ + mapping RetMap = ([]); + if(!sizeof(Sides[side])) return ([]); + RetMap["id"] = Sides[side]["Ids"]; + RetMap["short"] = Sides[side]["Short"]; + RetMap["long"] = Sides[side]["Long"]; + RetMap["keys"] = Sides[side]["Keys"]; + RetMap["lockable"] = Sides[side]["Lockable"]; + return copy(RetMap); +} + +int SetLockable(string side, int x){ + if( !Sides[side] ) + Sides[side] = ([ "Rooms" : ({}) ]); + return Sides[side]["Lockable"] = x; +} + +int GetLockable(string side){ + return Sides[side]["Lockable"]; +} + +varargs string *SetId(string side, mixed *args...){ + if( !Sides[side] ) Sides[side] = ([ "Rooms" : ({}) ]); + Sides[side]["Ids"] = ({}); + foreach(mixed val in args){ + if( stringp(val) ) Sides[side]["Ids"] += ({ val }); + else Sides[side]["Ids"] += val; + } + return Sides[side]["Ids"]; +} + +string *GetId(string side){ + if(!Sides[side]) return ({}); + return Sides[side]["Ids"]; +} + +mixed SetShort(string side, mixed short){ + if( !Sides[side] ) + Sides[side] = ([ "Rooms" : ({}) ]); + return Sides[side]["Short"] = short; +} + +varargs string GetShort(string side){ + if( !side){ /* let's hack a side */ + object room; + side = previous_object()->GetDoorSide(); + if( !this_player() ) room = previous_object(); + else room = environment(this_player()); + foreach(string s, mapping val in Sides){ + if(!side) side = s; + if( member_array(room, val["Rooms"]) != -1 ) break; + } + } + if( stringp(Sides[side]["Short"]) ) + return Sides[side]["Short"]; + else return evaluate(Sides[side]["Short"], side); +} + +string GetDefiniteShort(){ + string tmp = GetShort(); + + return add_article(tmp, 1); +} + +mixed SetLong(string side, mixed long){ + if( !Sides[side] ) + Sides[side] = ([ "Rooms" : ({}) ]); + return Sides[side]["Long"] = long; +} + +string GetLong(string side){ + string tmp; + + if( GetClosed() ) tmp = "It is closed."; + else tmp = "It is open."; + if( stringp(Sides[side]["Long"] ) ) + return Sides[side]["Long"] + "\n" + tmp; + else return evaluate(Sides[side]["Long"], side); +} + +varargs string *SetKeys(string side, mixed *args...){ + if( !Sides[side] ) Sides[side] = ([ "Rooms" : ({}) ]); + Sides[side]["Keys"] = ({}); + foreach(mixed val in args){ + if( stringp(val) ) Sides[side]["Keys"] += ({ val }); + else Sides[side]["Keys"] += val; + } + return Sides[side]["Keys"]; +} + +string *GetKeys(string side){ return Sides[side]["Keys"]; } + +object *GetRooms(string side){ return Sides[side]["Rooms"]; } + +int get_closed(){ return GetClosed(); } + +varargs mixed eventKnock(object who, mixed what){ + object room,whom; + string tmp; + if(GetClosed()){ + if(who) room = environment(who); + else room = environment(this_player()); + if(!who) whom = this_player(); + else whom = who; + foreach(string side, mixed val in Sides){ + if( member_array(environment(whom), val["Rooms"]) != -1 ) tmp = side; + if(who) + filter(val["Rooms"], (: $1 && ($1 != $(room)):))->eventPrint( + "There is a knock at the "+remove_article(GetShort(side)) + "."); + else (val["Rooms"])->eventPrint( + "There is a knock at the "+remove_article(GetShort(side)) + "."); + } + if(who){ + who->eventPrint("You knock on the " + remove_article(GetShort(tmp)) + "."); + room->eventPrint(who->GetName() + " knocks on the " + remove_article(GetShort(tmp)) + ".", + who); + } + } + else write("It isn't closed!"); + return 1; +} + +varargs mixed eventScratch(object who, mixed what){ + object room,whom; + string tmp; + if(GetClosed()){ + if(who) room = environment(who); + else room = environment(this_player()); + if(!who) whom = this_player(); + else whom = who; + foreach(string side, mixed val in Sides){ + if( member_array(environment(whom), val["Rooms"]) != -1 ) tmp = side; + if(who) + filter(val["Rooms"], (: $1 && ($1 != $(room)):))->eventPrint( + "There is a scratch at the "+remove_article(GetShort(side)) + "."); + else (val["Rooms"])->eventPrint( + "There is a scratch at the "+remove_article(GetShort(side)) + "."); + } + if(who){ + who->eventPrint("You scratch on the " + remove_article(GetShort(tmp)) + "."); + room->eventPrint(who->GetName() + " scratches on the " + remove_article(GetShort(tmp)) + ".", + who); + } + } + else write("It isn't closed!"); + return 1; +} + +void init(){ +} diff --git a/lib/lib/editor.c b/lib/lib/editor.c new file mode 100644 index 0000000..b6fc612 --- /dev/null +++ b/lib/lib/editor.c @@ -0,0 +1,56 @@ +/* /lib/editor.c + * from the Dead Souls LPC Library + * mudlib based editor interface + * created by Descartes of Borg 950406 + */ + + +#include "include/editor.h" + +private static function EditCallback; + +static void create(){ + EditCallback = 0; +} + +varargs void eventEdit(string file, function callback){ + EditCallback = callback; +#ifdef __DSLIB__ + if(this_object()->GetCharmode()){ + this_object()->erase_prompt(); + this_object()->CancelCharmode(); + this_object()->SetProperty("was_charmode", 1); + } + else this_object()->CancelCharmode(); +#endif +#if efun_defined(remove_get_char) + //remove_get_char(this_object()); +#endif +#if efun_defined(remove_charmode) + //remove_charmode(this_object()); +#endif + //this_object()->SetNoEcho(0); + ed_start(file, !creatorp()); + if( !creatorp() || file_size(file) < 1 ) ed_cmd("$a"); +} + +static string process_input(string str){ + int x; + + if( (x = query_ed_mode()) == -1 ) return str; + if( str && str[0..0] == "!" && strlen(str) > 1 ) return str[1..]; + if( !x ){ + str = ed_cmd(str); + message("editor", str, this_object()); + if( query_ed_mode() == -1 ){ + if( functionp(EditCallback) ) evaluate(EditCallback); + EditCallback = 0; + return ""; + } + return ""; + } + else str = ed_cmd(str); + message("editor", str, this_object()); + return ""; +} + diff --git a/lib/lib/elevator.c b/lib/lib/elevator.c new file mode 100644 index 0000000..1c26915 --- /dev/null +++ b/lib/lib/elevator.c @@ -0,0 +1,71 @@ +#include <lib.h> +#include <position.h> + +inherit LIB_CHAMBER; + +mapping Floors; +int elevator_speed; + +static void create() { + chamber::create(); + SetKeyName("elevator"); + SetId(({"box"})); + SetAdjectives(({"simple"})); + SetShort("a elevator"); + SetLong("This is a large, boxlike conveyance for transporting " + "things and people along a defined vertical axis."); + SetRace("vehicle"); + SetPosition(POSITION_NULL); + SetMelee(0); + SetNoClean(1); + SetMount(1); + SetMountStyle("driven"); + SetVisibleRiders(0); + SetOpacity(100); + SetMaxHealthPoints(20); + SetMaxCarry(30000); +} + +void init(){ + ::init(); +} + +int eventMove(mixed foo){ + int ret; + ret = ::eventMove(foo); + return ret; +} + +mapping GetFloors(){ + return copy(Floors); +} + +mapping SetFloors(mapping floors){ + object *buttons = ({}); + buttons = filter(all_inventory(), + (: base_name($1) == LIB_ELEVATOR_BUTTON :)); + if(sizeof(buttons)) buttons->eventDestruct(); + Floors = floors; + foreach(mixed key, mixed val in Floors){ + object button = new(LIB_ELEVATOR_BUTTON); + string tmpname = cardinal(atoi(key)); + string *tmpid = ({ key, "button" }); + if(!undefinedp(tmpname)) tmpid += ({ tmpname }); + button->SetAdjectives( ({ key, "elevator" }) ); + button->SetId( tmpid ); + button->SetKeyName( "button" ); + button->SetElevator(this_object()); + //button->SetInvis(0); + AddItem(button); + //button->eventMove(this_object()); + } +} + +int GetSpeed(){ + return elevator_speed; +} + +int SetSpeed(int x){ + return (elevator_speed = x); +} + diff --git a/lib/lib/elevator_button.c b/lib/lib/elevator_button.c new file mode 100644 index 0000000..48be3ce --- /dev/null +++ b/lib/lib/elevator_button.c @@ -0,0 +1,44 @@ +#include <lib.h> + +inherit LIB_DUMMY; // These do not show up in desc, but you can look at them +inherit LIB_PRESS; // Makes the item pressable + +object car, shaft; +string button_id; + +int openDoor(object who) { + if(!car) return 0; + if(!who) who = this_player(); + send_messages("press", "$agent_name $agent_verb the button.", + who, 0, environment(who)); + car->SetDoor(1); + car->CallMe(1); + +} + +static void create() { + dummy::create(); + SetKeyName("button"); + SetAdjectives("elevator","button"); + SetShort("a button"); + SetLong("It is a button that you could probably press."); + SetPress((: openDoor :)); +} + +string SetButtonId(string str){ + button_id = str; + return button_id; +} + +string GetButtonId(){ + return button_id; +} + +object SetElevator(object ob){ + car = ob; + return car; +} + +object GetElevator(){ + return car; +} diff --git a/lib/lib/enter.c b/lib/lib/enter.c new file mode 100644 index 0000000..8c08193 --- /dev/null +++ b/lib/lib/enter.c @@ -0,0 +1,191 @@ +/* /lib/enter.c + * From the Dead Souls Object Library + * Allows objects to provide an entry portal into another place + * Created by Descartes of Borg 961015 + * Version: @(#) enter.c 1.4@(#) + * Last modified: 97/01/02 + */ + +#include <position.h> + +private string Dir; +private string Door, DoorSide = 0; +private mapping Enter = 0; + +static void create(){ + Dir = "/" + implode(explode(file_name(), "/")[0..<2], "/"); +} + +string ResolveObjectName(string file){ + if( file[<2..] == ".c" ) file = file[0..<3]; + return absolute_path(Dir, file); +} + +mixed direct_close_obj(object target){ + if( !Door ){ + return 0; + } + else { + return Door->CanClose(this_player()); + } +} + +mixed direct_enter_obj(){ + if( !Enter ){ + return environment()->GetEnterMessage(); + } + else { + return 1; + } +} + +mixed direct_enter_into_obj(){ + return direct_enter_obj(); +} + +varargs mixed direct_lock_obj_with_obj(object target, object tool){ + if( !Door ){ + return 0; + } + else { + return Door->CanLock(this_player()); + } +} + +mixed direct_open_obj(object target){ + if( !Door ){ + return 0; + } + else { + return Door->CanOpen(this_player()); + } +} + +mixed direct_open_obj_with_obj(object target, object ob){ + return direct_open_obj(target); +} + +mixed direct_pick_str_on_obj(string str, object ob, string id1, string id2){ + if( !Door || remove_article(lower_case(str)) != "lock" ){ + return 0; + } + else { + return Door->CanPick(this_player(), remove_article(lower_case(id2))); + } +} + +mixed direct_pick_str_on_obj_with_obj(string str, object ob, object w, + string id1, string id2, string id3){ + return direct_pick_str_on_obj(str, ob, id1, id2); +} + +mixed direct_unlock_obj_with_obj(object target, object w){ + if( !Door ){ + return 0; + } + else { + return Door->CanUnlock(this_player()); + } +} + +mixed eventClose(object who){ + return Door->eventClose(who); +} + +varargs mixed eventEnter(object who, string what, string verb){ + if(!verb) verb = "NOVERB"; + if( Door && Door->GetClosed() ){ + who->eventPrint("You bump into " + Door->GetShort(what) + "."); + environment(who)->eventPrint(who->GetName() + " bumps into " + + Door->GetShort(what) + ".", who); + return 1; + } + if( who->GetPosition() != POSITION_STANDING ){ + if(verb != "crawl" && verb != "fly") who->eventStand(); + if( who->GetPosition() != POSITION_STANDING && verb != "crawl" + && verb != "fly"){ + who->eventPrint("weird."); + return 0; + } + } + if( Enter["pre"] && !evaluate(Enter["pre"], what) ){ + return 1; + } + if(verb == "crawl") who->eventMoveLiving(Enter["room"],"into the " + this_object()->GetKeyName() ); + else who->eventMoveLiving(Enter["room"], "$N enters into the " + this_object()->GetKeyName() + "."); + if( Enter["post"] ){ + evaluate(Enter["post"], what); + } + return 1; +} + +varargs mixed eventLock(object who, mixed arg1, mixed arg2){ + object key; + if(arg1 && objectp(arg1)) key = arg1; + else if(arg2 && objectp(arg2)) key = arg2; + else return 0; + return Door->eventLock(who, key); +} + +varargs mixed eventOpen(object who, object tool){ + return Door->eventOpen(who, tool); +} + +varargs mixed eventKnock(object who, mixed what){ + if(!Door){ + write("You can't knock on that."); + return 0; + } + return Door->eventKnock(who, what); +} + +varargs mixed eventScratch(object who, object tool){ + return Door->eventScratch(who, tool); +} + +varargs mixed eventPick(object who, string str, object tool){ + return Door->eventPick(who, str, tool); +} + +mixed eventUnlock(object who, object key){ + return Door->eventUnlock(who, key); +} + +string GetDoor(){ + return Door; +} + +varargs void SetDoor(string door, string side){ + Door = door; + if(side) DoorSide = side; +} + +string GetDoorSide(){ + return DoorSide; +} + +void SetDoorSide(string doorside){ + DoorSide = doorside; +} + +varargs void SetEnter(string dest, function pre, function post){ + if( !dest ){ + Enter = 0; + return; + } + dest = ResolveObjectName(dest); + Enter = ([ "room" : dest, "pre" : pre, "post" : post ]); +} + +string GetEnter(){ + if( !Enter ){ + return 0; + } + else { + return Enter["room"]; + } +} + +mixed direct_wizlock_obj(){ return 1; } +mixed direct_wizunlock_obj(){ return 1; } + diff --git a/lib/lib/events/activate.c b/lib/lib/events/activate.c new file mode 100644 index 0000000..285b19e --- /dev/null +++ b/lib/lib/events/activate.c @@ -0,0 +1,28 @@ +#include <lib.h> + +inherit LIB_TURN; + +int direct_activate_obj(object target){ + return turn::CanTurnOn(this_player()); +} + +int direct_deactivate_obj(object target){ + return turn::CanTurnOff(this_player()); +} + +int direct_activate_obj_on_obj(object target, object where){ + return turn::CanTurnOn(this_player(), target); +} + +int direct_activate_str_on_obj(string target, object where){ + return turn::CanTurnOn(this_player(), where); +} + +int direct_deactivate_obj_on_obj(object target, object where){ + return turn::CanTurnOff(this_player(), target); +} + +int direct_deactivate_str_on_obj(string target, object where){ + return turn::CanTurnOff(this_player(), where); +} + diff --git a/lib/lib/events/aim.c b/lib/lib/events/aim.c new file mode 100644 index 0000000..0e52356 --- /dev/null +++ b/lib/lib/events/aim.c @@ -0,0 +1,86 @@ +static int mustcarry = 1,mustwield = 1; +object targ; + +int MustCarry(int i){ + if(i) mustcarry = i; + if(mustcarry) return mustcarry; + else return 0; +} + +int MustWield(int i){ + if(i) mustwield = i; + if(mustwield) return mustwield; + else return 0; +} + +varargs mixed eventAim(object who, mixed target, string dir, string whom){ + string tmp; + if(target){ + if(objectp(target)){ + tmp=target->GetName(); + target = tmp; + } + else tmp = target; + } + if(!stringp(tmp)) tmp = "something"; + if(target) write("You aim the "+this_object()->GetShort()+" at "+ + target+"."); + targ = target; + return 1; +} + +mixed CanAim(object aimer, mixed target){ + object env = environment(this_player()); + if(this_object() == aimer && mustcarry > 0 && environment(this_object()) != this_player()){ + return "#You are not holding the "+remove_article(aimer->GetShort())+"."; + } + if(this_object() == aimer && mustwield > 0 && this_object()->GetWorn() == 0 && !creatorp(this_player())){ + return "#You are not wielding the "+remove_article(aimer->GetShort())+"."; + } + return 1; +} + +varargs mixed direct_aim_obj_at_obj(mixed args...){ + mixed ret; + ret = CanAim(args[0],args[1]); + return CanAim(args[0],args[1]); +} + +varargs mixed direct_aim_obj_with_obj(mixed args...){ + return 1; +} + +varargs mixed indirect_aim_obj_with_obj(mixed args...){ + mixed ret; + ret = CanAim(args[1],args[0]); + return CanAim(args[1],args[0]); +} + +varargs mixed indirect_aim_obj_at_obj(mixed args...){ + return 1; +} + +varargs mixed direct_aim_obj_at_liv(mixed args...){ + return direct_aim_obj_at_obj(args...); +} + +varargs mixed direct_aim_liv_with_obj(mixed args...){ + return direct_aim_obj_with_obj(args...); +} + +varargs mixed indirect_aim_liv_with_obj(mixed args...){ + return indirect_aim_obj_with_obj(args...); +} + +varargs mixed indirect_aim_obj_at_liv(mixed args...){ + return indirect_aim_obj_at_obj(args...); +} + +varargs mixed direct_aim_obj_wrd(mixed args...){ + return direct_aim_obj_at_obj(args...); +} + +varargs mixed direct_aim_obj_wrd_at_wrd(mixed args...){ + return direct_aim_obj_at_obj(args...); +} + diff --git a/lib/lib/events/apply.c b/lib/lib/events/apply.c new file mode 100644 index 0000000..71d0062 --- /dev/null +++ b/lib/lib/events/apply.c @@ -0,0 +1,19 @@ +mixed CanApply(object applicant){ + return 1; +} + +mixed direct_apply_obj_word_obj(){ + if( environment() != this_player() ){ + return "#You don't have that!"; + } + return CanApply(this_player()); +} + +mixed indirect_apply_obj_word_obj(){ + object room = environment(this_player()); + if(!room || environment() != this_player() || environment() != room){ + return "#That's not available to you!"; + } + return CanApply(this_player()); +} + diff --git a/lib/lib/events/bait.c b/lib/lib/events/bait.c new file mode 100644 index 0000000..780912f --- /dev/null +++ b/lib/lib/events/bait.c @@ -0,0 +1,49 @@ +/* /lib/events/bait.c + * From the Dead Souls Mud Library + * Handles the bait event + * Created by Descartes of Borg 970103 + * Version: @(#) bait.c 1.1@(#) + * Last modified: 97/01/03 + */ + +private int Bait = 0; + +// abstract methods +string GetDefiniteShort(); +// end abstract methods + +int AddBait(int x){ + return (Bait += x); +} + +int GetBait(){ + return Bait; +} + +int SetBait(int x){ + return (Bait = x); +} + +string array GetSave(){ + return ({ "Bait" }); +} + +mixed CanBait(object who){ + if( GetBait() ){ + return "There is already bait on " + GetDefiniteShort() + "."; + } + return 1; +} + +int eventBait(object who, object bait){ + AddBait(bait->GetBaitStrength()); + return 1; +} + +mixed direct_bait_obj_with_obj(){ + if( environment() != this_player() ){ + return "#You don't have that!"; + } + return CanBait(this_player()); +} + diff --git a/lib/lib/events/bait_with.c b/lib/lib/events/bait_with.c new file mode 100644 index 0000000..29a3520 --- /dev/null +++ b/lib/lib/events/bait_with.c @@ -0,0 +1,46 @@ +/* /lib/events/bait_with.c + * From the Dead Souls Mud Library + * Handles putting bait on fishing devices + * Created by Blitz@Dead Souls 960116 + * Version: @(#) bait_with.c 1.2@(#) + * Last modified: 97/01/03 + */ + +#include <lib.h> + +private int BaitStrength = 0; + +// abstract methods +string GetShort(); +static int Destruct(); +// end abstract methods + +int GetBaitStrength(){ + return BaitStrength; +} + +int SetBaitStrength(int x){ + return (BaitStrength = x); +} + +mixed eventBait(object who, object pole){ + if( !(who && pole) ){ + return 0; + } + if( !pole->eventBait(who, this_object()) ){ + who->eventPrint(capitalize(pole->GetDefiniteShort()) + + "remains unbaited."); + return 1; + } + send_messages("bait", "$agent_name $agent_verb $target_name with " + + GetShort() + ".", who, pole, environment(who)); + Destruct(); + return 1; +} + +mixed indirect_bait_obj_with_obj(){ + if( environment() != this_player() ){ + return "#You don't have that bait!"; + } + return 1; +} diff --git a/lib/lib/events/bury.c b/lib/lib/events/bury.c new file mode 100644 index 0000000..7483181 --- /dev/null +++ b/lib/lib/events/bury.c @@ -0,0 +1,11 @@ +/* /lib/events/bury.c + * From the Dead Souls Mud Library + * Handles objects which can be buried + * Created by Descartes of Borg 961231 + * Version: @(#) bury.c 1.1@(#) + * Last modified: 97/01/01 + */ + +mixed direct_bury_obj_with_obj(){ + return 1; +} diff --git a/lib/lib/events/buy.c b/lib/lib/events/buy.c new file mode 100644 index 0000000..38a3e92 --- /dev/null +++ b/lib/lib/events/buy.c @@ -0,0 +1,15 @@ +/* /lib/events/buy.c + * From the Dead Souls Mud Library + * Things that get bought from + * Created by Descartes of Borg 970103 + * Version: @(#) buy.c 1.1@(#) + * Last modified: 97/01/03 + */ + +mixed CanSell(object who, string what){ + return 1; +} + +int direct_buy_str_from_liv(string str){ + return CanSell(this_player(), remove_article(lower_case(str))); +} diff --git a/lib/lib/events/climb.c b/lib/lib/events/climb.c new file mode 100644 index 0000000..dfc15f0 --- /dev/null +++ b/lib/lib/events/climb.c @@ -0,0 +1,170 @@ +/* /lib/climb.c + * from the Dead Souls Mud Library + * handles different methods of climbing + * created by Descartes of Borg 960120 + * Version: @(#) climb.c 1.7@(#) + * Last modified: 96/12/22 + */ + +#include <climb.h> +#include <function.h> + +static private mapping Climb = 0; +int ccc = 0; + +// abstract methods +string GetDefiniteShort(); +// end abstract methods + +mapping GetClimbs(){ + return Climb; +} + +int SetCanClimbCarried(int i){ + ccc = i; + return 1; +} + +int GetCanClimbCarried(){ + return ccc; +} + +varargs static mapping SetClimb(mixed val, int type){ + if( !type ){ + type = CLIMB_UP; + } + if( !Climb ){ + Climb = ([ type : val ]); + } + else { + Climb[type] = val; + } + return Climb; +} + +mixed CanClimb(object who, int type){ + int array tmp; + object dude; + string thingname; + + dude=this_player(); + thingname=this_object()->GetKeyName(); + + if(present(thingname,dude) && ccc == 0){ + return "You can't climb that while it's being carried."; + } + + if( Climb[type] ){ + return 1; + } + tmp = keys(Climb); + if( !sizeof(tmp) ){ + return 0; + } + else { + type = tmp[0]; + } + switch(type){ + case CLIMB_UP: + return "Perhaps you mean to climb up it?"; + + case CLIMB_DOWN: + return "Perhaps you mean to climb down it?"; + + case CLIMB_OUT: + return "Perhaps you mean to climb out of it?"; + + case CLIMB_INTO: + return "Perhaps you mean to climb into it?"; + + case CLIMB_THROUGH: + return "Perhaps you mean to climb through it?"; + } + return 0; +} + +varargs mixed eventClimb(object who, int type, string where){ + mixed dest = Climb[type]; + if(where && where !="") dest = where; + + if( functionp(dest) ){ + if( functionp(dest) & FP_OWNER_DESTED ){ + who->eventPrint("There will be no climbing that today!"); + return 1; + } + return evaluate(dest, who, type); + } + else { + string omsg, imsg; + + switch(type){ + case CLIMB_UP: + omsg = "$N climbs up " + GetDefiniteShort() + "."; + imsg = "$N comes climbing in."; + break; + + case CLIMB_DOWN: + omsg = "$N climbs down " + GetDefiniteShort() + "."; + imsg = "$N comes climbing in."; + break; + + case CLIMB_OUT: + omsg = "$N climbs out " + GetDefiniteShort() + "."; + imsg = "$N comes climbing in."; + break; + + case CLIMB_INTO: + omsg = "$N climbs into " + GetDefiniteShort() + "."; + imsg = "$N comes climbing in."; + break; + + case CLIMB_THROUGH: + omsg = "$N climbs through " + GetDefiniteShort() + "."; + imsg = "$N comes climbing in."; + break; + } + who->eventMoveLiving(dest, omsg, imsg); + return 1; + } +} + +mixed direct_climb_obj(object ob){ + return CanClimb(this_player(), CLIMB_UP); +} + +mixed direct_climb_out_of_obj(object ob){ + return CanClimb(this_player(), CLIMB_OUT); +} + +mixed direct_climb_out(object ob){ + return CanClimb(this_player(), CLIMB_OUT); +} + +mixed direct_climb_word_obj(string word, object ob){ + if( !Climb ){ + return 0; + } + switch(word){ + case "up": + return CanClimb(this_player(), CLIMB_UP); + + case "down": + return CanClimb(this_player(), CLIMB_DOWN); + + case "out": + return CanClimb(this_player(), CLIMB_OUT); + + case "in": case "into": + return CanClimb(this_player(), CLIMB_INTO); + + case "through": + return CanClimb(this_player(), CLIMB_THROUGH); + + default: + return 0; + } +} + +mixed direct_climb_word(string word){ + return direct_climb_word_obj(word, this_object()); +} diff --git a/lib/lib/events/close.c b/lib/lib/events/close.c new file mode 100644 index 0000000..b147675 --- /dev/null +++ b/lib/lib/events/close.c @@ -0,0 +1,99 @@ +/* /lib/events/close.c + * from the Dead Souls Mud Library + * handles closing and opening events + * created by Descartes of Borg 960115 + * Version: @(#) close.c 1.5@(#) + * Last modified: 96/12/23 + */ + +int Closed; + +// abstract methods +string GetDefiniteShort(); +// end abstract methods + +int GetClosed(){ + return Closed; +} + +int GetOpen(){ + return !(Closed); + if(GetClosed()) return 0; + else return 1; +} + +int SetClosed(int x){ + Closed = x; + parse_refresh(); + return Closed; +} + +varargs mixed CanClose(object who, string id){ + + if(who && environment() && environment() != environment(who) && + environment() != who) + return "#That's not accessible to you."; + + if( Closed ){ + id = capitalize(GetDefiniteShort()) + " is already closed."; + return id; + } + else return 1; +} + +varargs mixed CanOpen(object who, object tool){ + if(environment() && environment() != environment(who) && + environment() != who) + return "#That's not accessible to you."; + + if( !Closed ){ + return capitalize(GetDefiniteShort()) + " is already open."; + } + else return 1; +} + +mixed eventClose(object who){ + if( !SetClosed(1) ){ + return 0; + } + send_messages("close", "$agent_name $agent_verb $target_name.", + who, this_object(), environment(who)); + return 1; +} + +varargs mixed eventOpen(object who, object tool){ + if( SetClosed(0) ){ + return 0; + } + send_messages("open", "$agent_name $agent_verb $target_name.", + who, this_object(), environment(who)); + return 1; +} + +int inventory_accessible(){ + return !GetClosed(); +} + +int inventory_visible(){ + return !GetClosed(); +} + +int SetOpen(int x){ + if(x) Closed = 0; + else Closed = 1; + parse_refresh(); + return Closed; +} + + +mixed direct_close_obj(object target){ + return CanClose(this_player()); +} + +mixed direct_open_obj(object target){ + return CanOpen(this_player()); +} + +mixed direct_open_obj_with_obj(object target, object tool){ + return CanOpen(this_player(), tool); +} diff --git a/lib/lib/events/consult.c b/lib/lib/events/consult.c new file mode 100644 index 0000000..b928ff6 --- /dev/null +++ b/lib/lib/events/consult.c @@ -0,0 +1,103 @@ +#include <function.h> + +static private mapping Consult = ([]); + +// abstract methods +string GetDefiniteShort(); +// end abstract methods + +varargs mixed GetConsult(string str){ + if( !str ){ + str = "default"; + } + return Consult[str]; +} + +string array GetConsults(){ + return keys(Consult); +} + +mapping RemoveConsult(string item){ + map_delete(Consult, item); + return Consult; +} + +varargs mapping SetConsult(mixed key, mixed desc){ + if( !key ){ + key = "default"; + } + if( !desc ){ + if( mapp(key) ){ + Consult = expand_keys(key); + } + else { + Consult["default"] = key; + } + } + else { + Consult[key] = desc; + } + return Consult; +} + +varargs mixed CanConsult(object who, string component){ + mixed val; + + if( !component ){ + component = "default"; + } + val = Consult[component]; + if( !val ){ + if( component == "default" ){ + return 0; + } + else { + return "#There is no " + component + " on " + + GetDefiniteShort() + "."; + } + } + else return 1; +} + +varargs mixed eventConsult(object who, string component){ + mixed val; + + if( !component ){ + val = Consult["default"]; + } + else { + val = Consult[component]; + } + if( arrayp(val) ){ + val = val[query_night()]; + } + if( stringp(val) ){ + object env; + + env = environment(who); + who->eventPrint(val); + if( component ){ + env->eventPrint(who->GetName() + " consults the " + component + + " on " + GetDefiniteShort() + ".", who); + } + else { + env->eventPrint(who->GetName() + " consults " + + GetDefiniteShort() + ".", who); + } + return 1; + } + else { + if( functionp(val) & FP_OWNER_DESTED ){ + return "Error in evaluating functional."; + } + return evaluate(val, who, component); + } +} + +mixed direct_consult_obj(object target){ + return CanConsult(this_player()); +} + +mixed direct_consult_str_on_obj(string str, object target){ + return CanConsult(this_player(), remove_article(lower_case(str))); +} diff --git a/lib/lib/events/crawl.c b/lib/lib/events/crawl.c new file mode 100644 index 0000000..865c438 --- /dev/null +++ b/lib/lib/events/crawl.c @@ -0,0 +1,8 @@ +mixed direct_crawl_str(string str){ + return 1; +} + +mixed direct_crawl_into_str(string str){ + return 1; +} + diff --git a/lib/lib/events/describe.c b/lib/lib/events/describe.c new file mode 100644 index 0000000..776bc4e --- /dev/null +++ b/lib/lib/events/describe.c @@ -0,0 +1,371 @@ +#include <lib.h> +#include <daemons.h> +#include <message_class.h> +#include <vision.h> +#include <medium.h> +#include <position.h> + +private static mixed globaltmp, tmp; +private static string desc, smell, sound, touch; +private static int i, maxi; + +void eventDescribeEnvironment(int brief){ + object env, transport; + string *shorts; + string altern_obvious = ""; + + if(!(env = environment(this_object()))){ + this_object()->eventPrint("You are nowhere.", MSG_ROOMDESC); + return; + } + + if(env->GetMount() || base_name(env) == LIB_CORPSE){ + env = environment(environment(this_player())); + if(!env){ + this_object()->eventPrint("You are in serious trouble. Ask an admin for help."); + return; + } + i = this_object()->GetEffectiveVision(env); + } + + else i = this_object()->GetEffectiveVision(); + switch( i ){ + case VISION_BLIND: + this_object()->eventPrint("You are blind and can see nothing."); + break; + case VISION_TOO_DARK: + this_object()->eventPrint("It is much too dark to see."); + break; + case VISION_DARK: + this_object()->eventPrint("It is too dark to see."); + break; + case VISION_TOO_BRIGHT: + this_object()->eventPrint("It is much too %^YELLOW%^bright%^RESET%^ to see."); + break; + case VISION_BRIGHT: + this_object()->eventPrint("It is too %^YELLOW%^bright%^RESET%^ to see."); + break; + } + if( !brief ){ + if( i == VISION_CLEAR ){ + desc = env->GetObviousExits() || ""; + if(desc && desc != "" && !(env->GetNoObviousExits())) + desc = capitalize(env->GetShort() || "") + + " [" + desc + "]\n"; + else desc = capitalize(env->GetShort()+"\n" || "\n"); + if(!NM_STYLE_EXITS){ + desc = capitalize(env->GetShort()+"\n" || "\n"); + if(!(env->GetNoObviousExits())){ + altern_obvious = "Obvious exit$Q: "+env->GetObviousExits() || "none"; + } + } + } + else desc = "\n"; + if( i == VISION_CLEAR || i == VISION_LIGHT || i == VISION_DIM ){ +#if MINIMAP + if(this_object()->GetProperty("minimapping")){ + desc += simple_map(env)+"\n"; + } +#endif +#if (WIZMAP && GRID) + if(MASTER_D->GetPerfOK() && + this_object()->GetProperty("wizmapping")){ + desc += MAP_D->GetMap(environment(this_object()),6)+"\n"; + } +#endif + desc += env->GetLong(); + } + if(functionp(tmp = env->GetSmell("default"))) + tmp = (*tmp)("default"); + smell = tmp; + if(functionp(tmp = env->GetListen("default"))) + tmp = (*tmp)("default"); + sound = tmp; + if( functionp(tmp = env->GetTouch("default")) ) + tmp = evaluate(tmp, "default"); + touch = tmp; + } + else { + if(i == VISION_CLEAR || i == VISION_LIGHT || i == VISION_DIM){ + desc = env->GetShort(); + if(this_object()->GetProperty("minimapping")) desc += simple_map(env)+"\n"; + if(NM_STYLE_EXITS){ + if( (tmp = env->GetObviousExits()) && tmp != "" ) + desc += " [" + tmp + "]"; + else desc += "\n"; + } + else altern_obvious = "Obvious exits: "+env->GetObviousExits() || "none"; + } + else desc = "\n"; + } + if( desc ) this_object()->eventPrint(desc, MSG_ROOMDESC); + if(sizeof(altern_obvious)){ + int quant = sizeof(env->GetExits()) + sizeof(env->GetEnters()); + if(quant > 1) altern_obvious = replace_string(altern_obvious,"$Q","s"); + else altern_obvious = replace_string(altern_obvious,"$Q",""); + this_object()->eventPrint(altern_obvious,MSG_ROOMDESC); + } + if( smell ) this_object()->eventPrint("%^GREEN%^" + smell, MSG_ROOMDESC); + if( sound ) this_object()->eventPrint("%^CYAN%^" + sound, MSG_ROOMDESC); + if( touch ) this_object()->eventPrint("%^YELLOW%^" + touch, MSG_ROOMDESC); + desc = ""; + if( i == VISION_CLEAR ){ + mapping lying = ([]); + shorts = map(filter(all_inventory(env), + function(object ob){ + if( living(ob) ) return 0; + if( ob->GetInvis(this_object()) && !ob->GetDoor() ) + return 0; + if(ob->GetDoor() && load_object(ob->GetDoor())->GetHiddenDoor()) return 0; + if( ob->isFreshCorpse() ) return 0; + return 1; + }), (: $1->GetShort() :)); + foreach(string s in shorts){ + if( s ){ + lying[s]++; + } + } + for(i=0, desc = 0, maxi = sizeof(shorts = keys(lying)); i<maxi; i++){ + string key = replace_string(shorts[i],"%^RESET%^", + "%^RESET%^MAGENTA%^"); + int val = lying[shorts[i]]; + + if( val < 2 ){ + if( !desc ) desc = "%^MAGENTA%^" + + capitalize(key) + "%^RESET%^MAGENTA%^"; + else desc += key + "%^RESET%^MAGENTA%^"; + } + else { + if( !desc ) desc = "%^MAGENTA%^" + + capitalize(consolidate(val, key)) + + "%^RESET%^MAGENTA%^"; + else desc += consolidate(val, key) + + "%^RESET%^MAGENTA%^"; + } + if( i == maxi - 1 ){ + if( maxi > 1 || val >1 ) + desc += " are here.%^RESET%^\n"; + else desc += " is here.%^RESET%^\n"; + } + else if( i == maxi - 2 ){ + if( maxi == 2 ){ + desc += " and "; + } + else { + desc += ", and "; + } + } + else desc += ", "; + } + } + i = this_object()->GetEffectiveVision(env); + if( i == VISION_CLEAR || i == VISION_LIGHT || i == VISION_DIM ){ + mapping lying = ([]), sitting = ([]), standing = ([]), flying = ([]); + mapping floating = ([]), kneeling = ([]), swimming = ([]); + mapping furniture = ([]), null = ([]); + object mount; + object *obs; + string key; + int val; + if(this_player()) mount = this_player()->GetProperty("mount"); + + obs = filter(all_inventory(env), function(object ob){ + if( ob->GetInvis(this_object()) && + !this_object()->GetWizVision() ) return 0; + if( living(ob) ) return 1; + if( ob->isFreshCorpse() ) + return 1; + }) - ({ this_object(), mount }); + maxi = sizeof(shorts = map(obs, (: + ($1->GetInvis() ? "(invisible) " : "") + + $1->GetHealthShort() :))); + foreach(object liv in obs){ + int envtype = environment(liv)->GetMedium(); + string s = liv->GetHealthShort(); + int pos = liv->GetPosition(); + if( !s ) continue; + if(liv->GetInvis() && this_object()->GetWizVision()){ + s = "(invis) " + s; + } + if(liv->GetProperty("furniture")){ + s += "BEGIN"+random(999999)+"END"; + } + if(liv->GetProperty("furniture")){ + furniture[s] = liv->GetProperty("furniture"); + } + else if(!furniture[s]) furniture[s] = 0; + + if( pos == POSITION_STANDING) standing[s]++; + else if( pos == POSITION_LYING || + (liv->isFreshCorpse() && envtype == MEDIUM_LAND) ) + lying[s]++; + else if( pos == POSITION_SITTING ) sitting[s]++; + else if( pos == POSITION_FLYING ) flying[s]++; + else if( pos == POSITION_FLOATING || + (liv->isFreshCorpse() && envtype != MEDIUM_LAND) ) + floating[s]++; + else if( pos == POSITION_SWIMMING ) swimming[s]++; + else if( pos == POSITION_KNEELING ) kneeling[s]++; + else if( pos == POSITION_NULL ) null[s]++; + else lying[s]++; + } + if( !desc ){ + tmp = ""; + } + else { + tmp = desc; + } + desc = ""; + foreach(key, val in lying){ + globaltmp = key; + if(grepp(key,"BEGIN")){ + sscanf(key,"%sBEGIN%*s",key); + } + + if(lying[globaltmp]>1 && !furniture[globaltmp]){ + desc += capitalize(consolidate(val, globaltmp)) + + "%^RESET%^ are lying down."; + } + else if(lying[globaltmp]<2 && !furniture[globaltmp]){ + desc += capitalize(key) + "%^RESET%^ is lying down."; + } + else if(furniture[globaltmp]){ + desc += capitalize(key) + "%^RESET%^ is lying down"+ + ((furniture[globaltmp]) ? furniture[globaltmp] : "") +"."; + } + else if(furniture[key]){ + desc += capitalize(key) + "%^RESET%^ is lying down"+ + ((furniture[key]) ? furniture[key] : "") +"."; + } + + + else { + desc += "wtf. i am "+key+", furniture["+globaltmp+"] is: "+furniture[globaltmp]+"\n"+ + " furniture["+key+"] is: "+furniture[key]+", and val is: "+val; + } + + desc += "\n"; + } + foreach(key, val in sitting){ + globaltmp = key; + if(grepp(key,"BEGIN")){ + sscanf(key,"%sBEGIN%*s",key); + } + + if(sitting[globaltmp]>1 && !furniture[globaltmp]){ + desc += capitalize(consolidate(val, globaltmp)) + + "%^RESET%^ are sitting down."; + } + else if(sitting[globaltmp]<2 && !furniture[globaltmp]){ + desc += capitalize(key) + "%^RESET%^ is sitting down."; + } + else if(furniture[globaltmp]){ + desc += capitalize(key) + "%^RESET%^ is sitting down"+ + ((furniture[globaltmp]) ? furniture[globaltmp] : "") +"."; + } + else if(furniture[key]){ + desc += capitalize(key) + "%^RESET%^ is sitting down"+ + ((furniture[key]) ? furniture[key] : "") +"."; + } + + + else { + desc += "wtf. i am "+key+", furniture["+globaltmp+"] is: "+furniture[globaltmp]+"\n"+ + " furniture["+key+"] is: "+furniture[key]+", and val is: "+val; + } + desc += "\n"; + } + foreach(key, val in standing){ + if(grepp(key,"BEGIN")){ + sscanf(key,"%sBEGIN%*s",key); + } + if( val<2 ) + desc += capitalize(key) + "%^RESET%^ is standing here."; + else desc += capitalize(consolidate(val, key)) + + "%^RESET%^ are standing here."; + desc += "\n"; + } + foreach(key, val in flying){ + if( val<2 ) + desc += capitalize(key) + "%^RESET%^ is hovering here."; + else desc += capitalize(consolidate(val, key)) + + "%^RESET%^ are hovering here."; + desc += "\n"; + } + foreach(key, val in floating){ + if( val<2 ) + desc += capitalize(key) + "%^RESET%^ is floating here."; + else desc += capitalize(consolidate(val, key)) + + "%^RESET%^ are floating here."; + desc += "\n"; + } + foreach(key, val in swimming){ + if( val<2 ) + desc += capitalize(key) + "%^RESET%^ is swimming here."; + else desc += capitalize(consolidate(val, key)) + + "%^RESET%^ are swimming here."; + desc += "\n"; + } + foreach(key, val in kneeling){ + if( val<2 ) + desc += capitalize(key) + "%^RESET%^ is kneeling here."; + else desc += capitalize(consolidate(val, key)) + + "%^RESET%^ are kneeling here."; + desc += "\n"; + } + foreach(key, val in null){ + if( val<2 ) + desc += capitalize(key) + "%^RESET%^ is here."; + else desc += capitalize(consolidate(val, key)) + + "%^RESET%^ are here."; + desc += "\n"; + } + } + if( tmp ){ + desc = tmp + desc; + } + if(this_player() && transport = this_player()->GetProperty("mount")){ + string mount_inv = "Nothing"; + string *mount_stuffs = ({}); + object *mount_obs = filter( all_inventory(transport), + (: ( (($1->GetInvis()) && this_object()->GetWizVision() ) + || !($1->GetInvis()) ) + && !($1 == this_player()) :)); + if(sizeof(mount_obs)){ + foreach(object element in mount_obs){ + string invis = (element->GetInvis() ? "(invisible) " : ""); + mount_stuffs += ({ invis+element->GetShort() }); + } + mount_inv = conjunction(mount_stuffs); + } + if(!sizeof(desc)) desc = ""; + if(inherits(LIB_CHAMBER,transport)){ + string tmpdesc = transport->GetVehicleInterior(); + if(!tmpdesc || !sizeof(tmpdesc)){ + desc += "\nYou are in "+ + transport->GetPlainShort()+"."; + } + else desc += "\n"+tmpdesc; + desc += "\nHere you see: "+mount_inv+"."; + } + else if(inherits(LIB_VEHICLE,transport)){ + string tmpdesc = transport->GetVehicleInterior(); + if(!tmpdesc || !sizeof(tmpdesc)){ + desc += "\nYou are riding in "+ + transport->GetPlainShort()+"."; + } + else desc += "\n"+tmpdesc; + desc += "\nHere you see: "+mount_inv+"."; + } + else { + desc += "\nYou are riding on "+ + transport->GetPlainShort()+"."; + desc += "\nOn "+transport->GetPlainShort()+ + " you see: "+mount_inv+"."; + } + } + if( sizeof(desc) ){ + if(check_string_length(desc)) this_object()->eventPrint(desc + "\n", MSG_ROOMDESC); + else print_long_string(this_player(), desc); + } +} diff --git a/lib/lib/events/dig.c b/lib/lib/events/dig.c new file mode 100644 index 0000000..7859cce --- /dev/null +++ b/lib/lib/events/dig.c @@ -0,0 +1,60 @@ +/* /lib/events/dig.c + * From the Dead Souls Mud Library + * Handles things that can be dug + * Created by Descartes of Borg 961231 + * Version: @(#) dig.c 1.1@(#) + * Last modified: 97/01/01 + */ + +private static mixed Dig = 0; + +// abstract methods +string GetShort(); +// end abstract methods + +mixed GetDig(){ + return Dig; +} + +int RemoveDig(){ + Dig = 0; + return 1; +} + +mixed SetDig(mixed val){ + if( !stringp(val) && !arrayp(val) && !functionp(val) ){ + error("Bad argument 1 to SetDig().\n\tExpected: string or function " + "or mixed array, Got: " + typeof(val) + "\n"); + } + return (Dig = val); +} + +mixed CanDig(object who){ + if( !Dig ){ + return 0; + } + else { + return 1; + } +} + +mixed eventDig(object who, object tool){ + mixed val = Dig; + + if( arrayp(val) ){ + val = val[query_night()]; + } + if( stringp(val) ){ + environment(who)->eventPrint(who->GetName() + " digs " + + GetShort() + " with " + + tool->GetShort() + ".", who); + who->eventPrint(val); + } + else { + return evaluate(val, who, tool); + } +} + +mixed direct_dig_obj_with_obj(){ + return CanDig(this_player()); +} diff --git a/lib/lib/events/dig_with.c b/lib/lib/events/dig_with.c new file mode 100644 index 0000000..699d31c --- /dev/null +++ b/lib/lib/events/dig_with.c @@ -0,0 +1,102 @@ +/* /lib/events/dig_with.c + * From the Dead Souls Mud Library + * handles functions to allow something to dig + * Created by Descartes of Borg 951030 + * Version: @(#) dig_with.c 1.3@(#) + * Last modified: 97/01/01 + */ + +#include <function.h> + +varargs mixed CanBuryWith(object who, object what){ + int fp = functionp(environment(who)->GetBury()); + + if( !fp || (fp & FP_OWNER_DESTED) ){ + return "This is not a very good place for burying."; + } + return 1; +} + +varargs mixed CanDigWith(object who, object what){ + if( what ){ // the parser will trigger CanDig() there + return 1; + } + else { + int fp = functionp(environment(who)->GetDig()); + + if( !fp || (fp & FP_OWNER_DESTED) ){ + return "This is not a very good place for that kind of digging."; + } + return 1; + } +} + +mixed eventBuryWith(object who, object what){ + mixed tmp = environment(who)->eventBuryItem(who, this_object(), what); + + if( tmp == 1 ){ + return tmp; + } + else { + who->eventPrint(tmp || "The burial did not work well."); + } + return 1; +} + +varargs mixed eventDigWith(object who, object what){ + object target; + mixed tmp; + + if( what ){ + target = what; + } + else { + target = environment(who); + } + tmp = target->eventDig(who, this_object()); + if( tmp == 1 ){ + return tmp; + } + else { + who->eventPrint(tmp || "The digging did not work so well."); + return 1; + } +} + +mixed direct_bury_str_with_obj(string str){ + if( environment() != this_player() ){ + return "#You must have it to dig with it!"; + } + return CanBuryWith(this_player()); +} + +mixed direct_dig_with_obj(){ + if( environment() != this_player() ){ + return "#You must have it to dig with it!"; + } + return CanDigWith(this_player()); +} + +mixed direct_dig_str_with_obj(string what){ + if( environment() != this_player() ){ + return "#You must have it to dig with it!"; + } + if( remove_article(lower_case(what)) != "hole" ){ + return "Dig a what?"; + } + return CanDigWith(this_player()); +} + +mixed indirect_bury_obj_with_obj(object what){ + if( environment() != this_player() ){ + return "#You must have it to bury with it!"; + } + return CanBuryWith(this_player(), what); +} + +mixed indirect_dig_obj_with_obj(object what){ + if( environment() != this_player() ){ + return "#You must have it to dig with it!"; + } + return CanDigWith(this_player(), what); +} diff --git a/lib/lib/events/disarm.c b/lib/lib/events/disarm.c new file mode 100644 index 0000000..fb37f29 --- /dev/null +++ b/lib/lib/events/disarm.c @@ -0,0 +1,49 @@ +#include <lib.h> + +mixed direct_boobytrap_obj_with_obj(){ + return 1; +} + +mixed indirect_boobytrap_obj_with_obj(){ + object env = environment(); + if(!env || env != this_player()){ + return "#You don't have that!"; + } + return 1; +} + +mixed direct_disarm_obj(){ + if(sizeof(this_object()->FoundTraps())) return 1; + return 0; +} + +varargs mixed eventDisarm(mixed arg){ + int disarm_score = 0; + int failure = 0; + int wisdom_score = this_player()->GetStat("wisdom")["level"]; + mapping Traps = this_object()->FoundTraps(); + object trap = keys(Traps)[0]; + write("You begin the disarming attempt."); + say(this_player()->GetCapName()+" begins the disarming attempt."); + + disarm_score += this_player()->GetStat("luck")["level"]; + disarm_score += this_player()->GetStat("intelligence")["level"]; + disarm_score += this_player()->GetStat("coordination")["level"]; + + if(disarm_score > Traps[trap]["level"]) return trap->eventDisarm(this_player()); + + failure = (Traps[trap]["level"] - disarm_score); + + if( failure > this_player()->GetStat("luck")["level"]){ + return trap->SpringTrap(this_player()); + } + + if(failure < wisdom_score){ + write("You fail to disarm the trap."); + } + + if(failure > (wisdom_score + 100)){ + write("You successfully disarm the trap!"); + } + return 1; +} diff --git a/lib/lib/events/drink.c b/lib/lib/events/drink.c new file mode 100644 index 0000000..f18e703 --- /dev/null +++ b/lib/lib/events/drink.c @@ -0,0 +1,28 @@ +/* /lib/events/drink.c + * From the Dead Souls Mud Library + * Handles drinking in the form of OBJ and SUBSTANCE from OBJ + * Created by descartes of Borg 961221 + * Version: %A% + * Last modified: %D% + */ + +varargs mixed CanDrink(object who, string substance){ + return 1; +} + +varargs mixed eventDrink(object who, string substance){ + return 1; +} + +mixed direct_drink_obj(){ + return CanDrink(this_player()); +} + +mixed direct_drink_from_obj(){ + return direct_drink_obj(); +} + +mixed direct_drink_str_from_obj(string str){ + return CanDrink(this_player(), remove_article(lower_case(str))); +} + diff --git a/lib/lib/events/drop.c b/lib/lib/events/drop.c new file mode 100644 index 0000000..0d989ee --- /dev/null +++ b/lib/lib/events/drop.c @@ -0,0 +1,96 @@ +/* /lib/drop.c + * From the Dead Souls Mud Library + * Makes an object something which can be dropped + * Created by Descartes of Borg 960113 + * Version: @(#) drop.c 1.2@(#) + * Last modified: 96/12/22 + */ + +#include <lib.h> +#include <function.h> +#include ROOMS_H + +private mixed PreventDrop = 0; +private mixed DestructOnDrop = 0; + +// abstract methods +string GetDefiniteShort(); +mixed eventMove(mixed dest); +// end abstract methods + +mixed GetPreventDrop(){ + return PreventDrop; +} + +mixed SetPreventDrop(mixed val){ + if(!intp(val) && !stringp(val) && !functionp(val) && !objectp(val) ){ + error("Bad argument 1 to SetPreventDrop().\n"); + } + return (PreventDrop = val); +} + +int GetDestructOnDrop(){ + return DestructOnDrop; +} + +int SetDestructOnDrop(int val){ + return (DestructOnDrop = val); +} + +mixed CanDrop(object who){ + if( !PreventDrop ){ + return 1; + } + if( intp(PreventDrop) ){ + return 0; + } + if( stringp(PreventDrop) ){ + return PreventDrop; + } + if( objectp(PreventDrop) ){ + if( PreventDrop == who ){ + return capitalize(GetDefiniteShort()) + + " simply will not leave your grasp."; + } + else { + return 1; + } + } + else { + if( functionp(PreventDrop) & FP_OWNER_DESTED ){ + return "There is a problem with a functional."; + } + return evaluate(PreventDrop, who); + } +} + +mixed eventDrop(object who){ + mixed tmp; + + if( who != environment() ){ + return 0; + } + + if(DestructOnDrop) tmp = eventMove(ROOM_FURNACE); + else tmp = eventMove(environment(who)); + + if( !tmp ){ + who->eventPrint("Something prevents you from dropping " + + GetDefiniteShort() + "."); + return 1; + } + if( tmp != 1 ){ + return tmp; + } + send_messages("drop", "$agent_name $agent_verb $target_name.", + who, this_object(), environment(who)); + if(DestructOnDrop) tell_room(environment(who),capitalize(this_object()->GetShort())+" vanishes in a flash of light!"); + return 1; +} + +mixed direct_drop_obj(object target){ + if( environment() != this_player() ){ + return "#You don't have that to drop."; + } + return CanDrop(this_player()); +} diff --git a/lib/lib/events/fall.c b/lib/lib/events/fall.c new file mode 100644 index 0000000..746342a --- /dev/null +++ b/lib/lib/events/fall.c @@ -0,0 +1,66 @@ +#include ROOMS_H +#include <daemons.h> +#include <position.h> +#include <medium.h> +#include <message_class.h> + +mixed eventFall(){ + string rvoid = ROOMS_D->GetVoid(this_object()); + object env = environment(); + mixed rumbo = 0; + mixed tmprumbo = 0; + string name = this_object()->GetName(); + + if(!living(this_object())) name = this_object()->GetShort(); + + if(!env || !(rumbo = env->GetExit("down"))){ + if(!sizeof((rumbo = env->GetSinkRoom()))){ + return 0; + } + } + if(env == rumbo){ + return 0; + } + if(env->GetMedium() != MEDIUM_AIR){ + send_messages("crash", "$agent_name $agent_verb down!", + this_object(), 0, env); + if(living(this_object())) this_object()->SetPosition(POSITION_LYING); + remove_call_out("eventFall"); + return 1; + } + else { + mixed err; + if(!rumbo){ + return 0; + } + tmprumbo = rumbo; + if(stringp(rumbo)){ + if(grepp(rumbo, "#")) err = "Let's not load a clone."; + else err = catch(rumbo = load_object(rumbo)); + } + if(err || !rumbo){ + log_file("runtime","\n"+timestamp()+" "+identify(this_object())+ + " could not load "+identify(rumbo)+" to fall into.\n"); + err = catch(rumbo = load_object(rvoid)); + } + if(err || !rumbo){ + this_object()->eventMove(ROOM_START); + return 0; + } + tell_object(this_object(),"You plummet downward!"); + if(err = this_object()->eventMove(rumbo)){ + tell_room(rumbo,capitalize(name)+" plummets in from above.", + ({ this_object() })); + tell_room(env,capitalize(name)+" continues "+ + possessive(this_object())+" fall downward.", ({ this_object() })); + + if(rumbo->GetMedium() == MEDIUM_AIR && !(this_object()->CanFly())){ + if(!this_object()->GetFalling() && find_call_out("eventFall") == -1){ + call_out( "eventFall", 1); + } + } + } + return 1; + } + return 0; +} diff --git a/lib/lib/events/fly.c b/lib/lib/events/fly.c new file mode 100644 index 0000000..b33d2b4 --- /dev/null +++ b/lib/lib/events/fly.c @@ -0,0 +1,8 @@ +mixed direct_fly_str(string str){ + return 1; +} + +mixed direct_fly_into_str(string str){ + return 1; +} + diff --git a/lib/lib/events/get.c b/lib/lib/events/get.c new file mode 100644 index 0000000..7414de2 --- /dev/null +++ b/lib/lib/events/get.c @@ -0,0 +1,114 @@ +/* /lib/get.c + * from the Dead Souls Mud Library + * handles the picking up of objects + * created by Descartes of Borg 960114 + * Version: @(#) get.c 1.3@(#) + * Last Modified: 96/12/21 + */ + +#include <message_class.h> +#include <daemons.h> + +private mixed PreventGet; + +// abstract methods +int GetMass(); +mixed GetProperty(string key); +string GetShort(); +string GetKeyName(); +mixed eventMove(mixed dest); +// end abstract methods + +mixed GetPreventGet(){ + return PreventGet; +} + +mixed SetPreventGet(mixed val){ + return (PreventGet = val); +} + +mixed CanGet(object who){ + int check = GUARD_D->CheckGet(who, this_object()); + if(!check){ + who->eventPrint("You are unable to get it.", MSG_SYSTEM); + return 0; + } + if( !(who->CanCarry(GetMass())) ) return "It is too heavy for you!"; + if( !PreventGet && !GetProperty("keep") ) return 1; + if( stringp(GetProperty("keep")) ){ + if( who->GetKeyName() == GetProperty("keep") ){ + if( !PreventGet ) return 1; + } + else return "Mystical forces prevent you from getting " + this_object()->GetShort() + "."; + } + if( PreventGet && intp(PreventGet) ) return 0; + if( stringp(PreventGet) ) return PreventGet; + if( objectp(PreventGet) ){ + if( PreventGet == who ) + return capitalize(this_object()->GetShort()) + " simply will not be taken."; + else return 1; + } + else{ + return evaluate(PreventGet, who); + } +} + +mixed eventGet(object who){ + if( !eventMove(who) ){ + who->eventPrint("You fail to get it."); + return 1; + } + if(living(this_object())){ + if(this_object()->GetProperty("mount")){ + this_object()->RemoveProperty("mount"); + } + if(this_object()->GetProperty("furniture_object")){ + this_object()->RemoveProperty("furniture_object"); + this_object()->RemoveProperty("furniture"); + } + who->SetMount(1); + who->eventMount(this_object(), 1, 1); + } + send_messages("get", "$agent_name $agent_verb $target_name.", + who, this_object(), environment(who)); + return 1; +} + +static void create(){ + PreventGet = 0; +} + +mixed direct_get_obj(object target){ + if(environment() == this_player()) + return "#You're already holding it."; + if( environment() != environment(this_player()) ){ + string str = this_object()->GetShort(); + + if( !str ) str = "It"; + else str = capitalize(str); + return "#You may need to get closer to it. Perhaps "+ + "\"get "+this_object()->GetKeyName()+" from\" something?"; + } + return CanGet(this_player()); +} + +mixed direct_get_obj_out_of_obj(object target, object src){ + object env; + string str; + + env = environment(); + if( !(str = this_object()->GetShort()) ) str = "It"; + else str = capitalize(str); + if( env==this_player() || env ==environment(this_player()) || living(env) ){ + return "#You can't do that right now."; + } + return CanGet(this_player()); +} + +mixed direct_get_obj_from_obj(object target, object src){ + return direct_get_obj_out_of_obj(target, src); +} + +mixed direct_get_obj_obj(object target, object src){ + return direct_get_obj_out_of_obj(target, src); +} diff --git a/lib/lib/events/get_from.c b/lib/lib/events/get_from.c new file mode 100644 index 0000000..29b7975 --- /dev/null +++ b/lib/lib/events/get_from.c @@ -0,0 +1,233 @@ +/* /lib/events/get_from.c + * From the Dead Souls Mud Library + * Handles get from/put in + * Created by Descartes of Borg 961221 + * Version: @(#) get_from.c 1.1@(#) + * Last modified: 96/12/22 + */ + +#include <lib.h> +#include <message_class.h> +#include <daemons.h> + +// abstract methods +int AddCarriedMass(int amount); +string GetShort(); +// end abstract methods + +mixed CanGetFrom(object who, object item){ + int check = GUARD_D->CheckGet(who, this_object()); + if(!check){ + who->eventPrint("You can't get it.", MSG_SYSTEM); + return 0; + } + + if( !item ){ + return "#You seem oddly confused."; + } + if( this_object()->GetClosed() ){ + return "#It's closed!"; + } + if( !sizeof(all_inventory(this_object())) ){ + return "#It's empty."; + } + //if( environment(item) != this_object() ){ + // item = present(item->GetKeyName(),this_object()); + // if(!item) return "#That's not available from there."; + //} + + if( (environment() != environment(this_player())) && + (environment() != this_player()) ){ + return "#" + capitalize(GetShort()) + " is not in reach."; + } + return 1; +} + +mixed CanPutInto(object who, object item){ + object env; + + if((inherits(LIB_SIT,item) && sizeof(item->GetSitters())) || + (inherits(LIB_LIE,item) && sizeof(item->GetLiers()))){ + write("There appears to be someone in your way."); + return 0; + } + + if( item == this_object() ){ + return "#You cannot change the laws of physics."; + } + env = environment(); + if( env != this_player() && env != environment(this_player()) ){ + return "#It is not within reach."; + } + + if( this_object()->GetClosed() ){ + return "#It's closed!"; + } + return 1; +} + +mixed CanPutOnto(object who, object item){ + object env; + + if((inherits(LIB_SIT,item) && sizeof(item->GetSitters())) || + (inherits(LIB_LIE,item) && sizeof(item->GetLiers()))){ + write("There appears to be someone preventing your access."); + return 0; + } + + if(!inherits( LIB_SURFACE, item ) ){ + return "#That isn't a load-bearing surface."; + } + if( item == this_object() ){ + return "#You cannot change the laws of physics."; + } + env = environment(); + if( env != this_player() && env != environment(this_player()) ){ + return "#It is not within reach."; + } + return 1; +} + + +mixed eventGetFrom(object who, object array what){ + object array fin = ({}); + string array shorts; + mapping mp = ([]); + string msg; + int i, maxi; + mixed tmp; + + if((inherits(LIB_SIT,this_object()) && sizeof(this_object()->GetSitters())) || + (inherits(LIB_LIE,this_object()) && sizeof(this_object()->GetLiers()))){ + write("There appears to be someone on there."); + return 0; + } + + foreach(object ob in what ){ + if( environment(ob) != this_object() ){ + continue; + } + if( (tmp = ob->CanGet(who)) != 1 ){ + if(stringp(tmp)) write(tmp); + else write("It would appear you can't get "+ + (ob->GetShort() || "that") +" right now."); + continue; + } + if( !who->CanCarry(ob->GetMass()) ){ + write("It seems you can't carry it."); + continue; + } + if( !ob->eventMove(who) ){ + who->eventPrint("You have a problem getting " + + ob->GetShort() + "."); + continue; + } + AddCarriedMass( -(ob->GetMass()) ); + fin += ({ ob }); + } + what = fin; + if( !(maxi = sizeof(what)) ){ + return 0; + } + shorts = map(what, (: $1->GetShort() :)); + for(i=0; i<maxi; i++){ + mp[shorts[i]]++; + } + maxi = sizeof(shorts = keys(mp)); + for(i=0, msg = ""; i<maxi; i++){ + if( mp[shorts[i]] < 2 ){ + msg += shorts[i] + "%^RESET%^"; + } + else { + msg += consolidate(mp[shorts[i]], shorts[i]) + "%^RESET%^"; + } + if( i == maxi-2 ){ + msg += ", and "; + } + else if( i != maxi-1 ){ + msg += ", "; + } + } + send_messages("get", "$agent_name $agent_verb " + msg + + " from $target_name.", who, this_object(), environment(who)); + return 1; +} + +mixed eventPutInto(object who, object what){ + return what->eventPut(who, this_object()); +} + +mixed eventPutOnto(object who, object what){ + if((inherits(LIB_SIT,this_object()) && sizeof(this_object()->GetSitters())) || + (inherits(LIB_LIE,this_object()) && sizeof(this_object()->GetLiers()))){ + write("There appears to be someone in the way of that."); + return 0; + } + return what->eventPut(who, this_object()," onto "); +} + + +int inventory_accessible(){ + return 1; +} + +int inventory_visible(){ + return 1; +} + +mixed indirect_get_obj_from_obj(object item, object container){ + if(!item){ + return "#That's not there."; + } + + if(!clonep(container)) return "#wat"; + + //if(environment(item) != this_object()) return "#That's not in there."; + + return CanGetFrom(this_player(), item); +} + +mixed indirect_get_obj_out_of_obj(object item, object container){ + return indirect_get_obj_from_obj(item, container); +} + +mixed indirect_get_obj_obj(object item, object container){ + return indirect_get_obj_from_obj(item, container); +} + +mixed indirect_get_obs_from_obj(object array items, object storage){ + if( !items ){ + return (storage == this_object() || "#It's not there."); + } + return 1; +} + +mixed indirect_get_obs_out_of_obj(object array items, object storage){ + return indirect_get_obs_from_obj(items, storage); +} + +mixed indirect_get_obs_obj(object array items, object storage){ + return indirect_get_obs_from_obj(items, storage); +} + +mixed indirect_put_obj_word_obj(object what, string word, object storage){ + if( !what ){ + return (storage == this_object()); + } + return CanPutInto(this_player(), what); +} + +mixed indirect_put_obj_obj(object what, string word, object storage){ + return indirect_put_obj_word_obj(what, word, storage); +} + +mixed indirect_put_obs_word_obj(object *items, string wrd, object storage){ + if( !items ){ + return (storage == this_object()); + } + return 1; +} + +mixed indirect_put_obs_obj(object *items, string wrd, object storage){ + return indirect_put_obs_word_obj(items, wrd, storage); +} diff --git a/lib/lib/events/give.c b/lib/lib/events/give.c new file mode 100644 index 0000000..44e41f3 --- /dev/null +++ b/lib/lib/events/give.c @@ -0,0 +1,56 @@ +/* /lib/events/give.c + * From the Dead Souls Mud Library + * Give event handler + * Created by Descartes of Borg 970101 + * Version: @(#) give.c 1.1@(#) + * Last modified: 97/01/01 + */ + +// abstract methods +mixed CanDrop(object who); +string GetDefiniteShort(); +int GetMass(); +// end abstract methods + +mixed indirect_give_liv_obj(object target){ + mixed tmp; + + if(!target){ + return "#That doesn't seem to be here."; + } + if( environment() != this_player() ){ + return "#You cannot give what is not yours."; + } + tmp = CanDrop(this_player()); + if( tmp != 1 ){ + return (tmp || "You can't drop " + GetDefiniteShort() + "."); + } + tmp = target->CanCarry(GetMass()); + if( tmp != 1 ){ + return (tmp || capitalize(GetDefiniteShort()) + " is too heavy."); + } + return 1; +} + +mixed direct_give_obj_to_liv(object what, object target){ + mixed tmp; + + if( environment() != this_player() ){ + return "#You cannot give what is not yours."; + } + tmp = CanDrop(this_player()); + if( tmp != 1 ){ + return (tmp || "#You can't drop " + GetDefiniteShort() + "."); + } + if(target && objectp(target)){ + tmp = target->CanCarry(GetMass()); + if( tmp != 1 ){ + return capitalize(this_object()->GetDefiniteShort()) + " is too heavy."; + } + } + return 1; +} + +mixed direct_give_obj_liv(object what, object target){ + return direct_give_obj_to_liv(what, target); +} diff --git a/lib/lib/events/install.c b/lib/lib/events/install.c new file mode 100644 index 0000000..9e24321 --- /dev/null +++ b/lib/lib/events/install.c @@ -0,0 +1,69 @@ +varargs mixed CanInstall(object who, object where, object what){ + object env; + if(!who || !environment(who)) return "#That's unpossable!"; + foreach(object thingy in ({ where, what })){ + if(thingy){ + env = environment(thingy); + if((env != who && env != environment(who)) || + (thingy == what && env != who)){ + string thingname = remove_article(thingy->GetShort()); + return "#You don't have the "+thingname+"."; + } + } + } + return 1; +} + +varargs mixed CanUninstall(object who, object where, object what){ + object env; + if(who) env = environment(who); + if(!who || !env) return "#That's inposserble!"; + if(!what || !environment(what)) return "#That's not here."; + if(!where){ + object env1 = environment(what); + object env2 = environment(env1); + if(env1 != who && env1 != env && env2 != who && env2 != env){ + return "#That's not accessible."; + } + else { + return 1; + } + } + if(environment(what) != where) return "#That's not in there."; + if(environment(where) != who && environment(where) != env){ + return "#That's not in reach."; + } + return 1; +} + +varargs mixed eventInstall(object what, object where){ + return 1; +} + +varargs mixed eventUninstall(object what, object where){ + return 1; +} + +int direct_install_obj(object what){ + return CanInstall(this_player(), 0, what); +} + +int direct_uninstall_obj(object what){ + return CanUninstall(this_player(), 0, what); +} + +int direct_install_obj_word_obj(object thingus, mixed word, object target){ + return CanInstall(this_player(), target, thingus); +} + +int indirect_install_obj_word_obj(object target, mixed word, object thingus){ + return CanInstall(this_player(), target, thingus); +} + +int direct_uninstall_obj_word_obj(object thingus, mixed word, object target){ + return CanUninstall(this_player(), target, thingus); +} + +int indirect_uninstall_obj_word_obj(object target, mixed word, object thingus){ + return CanUninstall(this_player(), thingus, target); +} diff --git a/lib/lib/events/jump.c b/lib/lib/events/jump.c new file mode 100644 index 0000000..f9cdc78 --- /dev/null +++ b/lib/lib/events/jump.c @@ -0,0 +1,134 @@ +/* /lib/jump.c + * from the Dead Souls Mud Library + * handles different methods of jumping + * created by Descartes of Borg 960117 + * Version: @(#) jump.c 1.4@(#) + * Last modified: 96/12/22 + */ + +#include <jump.h> +#include <function.h> + +private mapping Jumps = ([]); + +mapping GetJumps(){ + return Jumps; +} + +varargs mixed AddJump(string name, mixed saute, int type){ + Jumps[name] = ({ saute , type }); +} + + +mixed CanJump(object who, string id, int type){ + + if( Jumps[id] && Jumps[id][1] == type ){ + return 1; + } + if( !sizeof(Jumps) ){ + return 0; + } + type = Jumps[keys(Jumps)[0]][1]; + switch(type){ + case JUMP_INTO: + return "Perhaps you mean to jump into it?"; + + case JUMP_FROM: + return "Perhaps you mean to jump from it?"; + + case JUMP_THROUGH: + return "Perhaps you mean to jump through it?"; + + case JUMP_OVER: + return "Perhaps you mean to jump over it?"; + + case JUMP_ON: + return "Perhaps you mean to jump on it?"; + } + return 0; +} + +mixed eventJump(object who, string id, int type){ + mixed dest; + + if( Jumps[id] && Jumps[id][1] == type ){ + dest = Jumps[id][0]; + } + else { + return 0; + } + if( stringp(dest) ){ + string omsg, imsg; + + switch(type){ + case JUMP_INTO: + omsg = "$N jumps into the " + id + "."; + imsg = "$N leaps in."; + break; + + case JUMP_FROM: + omsg = "$N jumps out of here."; + imsg = "$N leaps in."; + break; + + case JUMP_THROUGH: + omsg = "$N jumps through the " + id + "."; + imsg = "$N leaps in."; + break; + + case JUMP_OVER: + omsg = "$N jumps over the " + id + "."; + imsg = "$N leaps in."; + break; + } + who->eventMoveLiving(dest, omsg, imsg); + return 1; + } + else { + if( functionp(dest) & FP_OWNER_DESTED ){ + return "You encountered an error in a functional."; + } + return evaluate(dest, who, id, type); + } +} + +mixed direct_jump_word_obj(string prep, object target, string id){ + int type; + + switch(prep){ + case "in": case "into": + type = JUMP_INTO; + break; + case "from": case "out": case "off": + type = JUMP_FROM; + break; + case "through": case "across": + type = JUMP_THROUGH; + break; + case "over": + type = JUMP_OVER; + break; + case "on": case "onto": + type = JUMP_ON; + break; + default: + return 0; + } + id = remove_article(lower_case(id)); + return CanJump(this_player(), id, type); +} + +varargs mixed direct_jump_word_word_obj(mixed args...){ + string prep = args[0] + " " + args[1]; + string id = remove_article(lower_case(args[5])); + int type; + + switch(prep){ + case "out of": case "off of": + type = JUMP_FROM; + default: + return 0; + } + return CanJump(this_player(), id, type); +} + diff --git a/lib/lib/events/knock.c b/lib/lib/events/knock.c new file mode 100644 index 0000000..17ef9a9 --- /dev/null +++ b/lib/lib/events/knock.c @@ -0,0 +1,97 @@ +#include <function.h> + +static private mapping Knock = ([]); + +// abstract methods +string GetDefiniteShort(); +// end abstract methods + +varargs mixed GetKnock(string str){ + if( !str ){ + str = "default"; + } + return Knock[str]; +} + +string array GetKnocks(){ + return keys(Knock); +} + +mapping RemoveKnock(string item){ + map_delete(Knock, item); + return Knock; +} + +varargs mapping SetKnock(mixed key, mixed desc){ + if( !key ){ + key = "default"; + } + if( !desc ){ + if( mapp(key) ){ + Knock = expand_keys(key); + } + else { + Knock["default"] = key; + } + } + else { + Knock[key] = desc; + } + return Knock; +} + +varargs mixed CanKnock(object who, string component){ + return 1; +} + +varargs mixed eventKnock(object who, mixed component){ + mixed val; + + if( !component ){ + val = Knock["default"]; + } + else { + val = Knock[component]; + } + if( arrayp(val) ){ + val = val[query_night()]; + } + if( stringp(val) ){ + object env; + + env = environment(who); + who->eventPrint(val); + if( component ){ + env->eventPrint(who->GetName() + " knocks on the " + component + + " on " + GetDefiniteShort() + ".", who); + } + else { + env->eventPrint(who->GetName() + " knocks on " + + GetDefiniteShort() + ".", who); + } + return 1; + } + else { + if( functionp(val) & FP_OWNER_DESTED ){ + return "Error in evaluating functional."; + } + return evaluate(val, who, component); + } +} + +mixed direct_knock_obj(object target){ + return CanKnock(this_player()); +} + +mixed direct_knock_on_obj(object target){ + return direct_knock_obj(target);; +} + +mixed direct_knock_str_on_obj(string str, object target){ + return CanKnock(this_player(), remove_article(lower_case(str))); +} + +mixed direct_knock_on_str_on_obj(string str, object target){ + return direct_knock_str_on_obj(str,target); +} + diff --git a/lib/lib/events/lie.c b/lib/lib/events/lie.c new file mode 100644 index 0000000..55a9e6f --- /dev/null +++ b/lib/lib/events/lie.c @@ -0,0 +1,65 @@ +#include <position.h> +#include <lib.h> +inherit LIB_SIT; + +private int MaxLiers = 1; +private object array Liers = ({}); + +int GetMaxLiers(){ + return MaxLiers; +} + +static int SetMaxLiers(int x){ + return (MaxLiers = x); +} + +object array GetLiers(){ + return copy(Liers); +} + +mixed eventReceiveLay(object who){ + mixed furn = who->GetProperty("furniture"); + if(furn && objectp(furn)){ + write("You are already using a piece of furniture."); + return 1; + } + Liers = ({ Liers..., who }); + who->SetProperty("furniture", " on "+this_object()->GetShort()); + who->SetProperty("furniture_object", this_object()); + return 1; +} + +mixed eventReleaseStand(object who){ + Liers -= ({ who }); + Liers = filter(Liers, (: objectp($1) :) ); + sit::eventReleaseStand(who); + return 1; +} + +mixed direct_lie_word_obj(){ + Liers = filter(Liers, (: $1 && $1->GetPosition()==POSITION_LYING :)); + if( sizeof(Liers) >= MaxLiers ){ + return "There is no room to lie there."; + } + if(environment() != environment(this_player())){ + return "That's not available for sitting right now."; + } + return 1; +} + +mixed direct_lie_down_word_obj(){ + return direct_lie_word_obj(); +} + +int CanGet(object who){ + object *liers = this_object()->GetLiers(); if(sizeof(liers)){ + foreach(object wer in liers){ if(!wer || environment(wer) != environment()) this_object()->eventReleaseStand(wer); + } + if(sizeof(this_object()->GetLiers())){ + write(this_object()->GetLiers()[0]->GetName()+" is using it right now."); + return 0; + } + else return sit::CanGet(who); + } + else return sit::CanGet(who); +} diff --git a/lib/lib/events/listen.c b/lib/lib/events/listen.c new file mode 100644 index 0000000..1e72fe8 --- /dev/null +++ b/lib/lib/events/listen.c @@ -0,0 +1,141 @@ +/* /lib/events/listen.c + * From the Dead Souls Mud Library + * Handles responses to the listen verb + * Created by Descartes of Borg 951008 + * Version: @(#) listen.c 1.8@(#) + * Last modified: 96/12/31 + */ + +#include <function.h> + +static private mixed Listen = 0; +static private mapping Listens = ([]); + +// abstract methods +string GetShort(); +// end abstract methods + +varargs string GetListen(string str, object who){ + mixed val; + + if( !str || str == "default" ){ + val = Listen; + } + else { + val = Listens[str]; + } + if( !val ){ + return 0; + } + if( functionp(val) ){ + if( functionp(val) & FP_OWNER_DESTED ){ + return "An error occured in a function pointer."; + } + return evaluate(val, who, str); + } + else if( arrayp(val) ){ + return val[query_night()]; + } + else return val; +} + +string array GetListens(){ + return keys(Listens); +} + +mapping RemoveListen(string item){ + if( !item || item == "default" ){ + Listen = 0; + } + else { + map_delete(Listens, item); + } + return Listens; +} + +varargs mixed SetListen(mixed array args...){ + if( sizeof(args) == 1 ){ + if( mapp(args[0]) ){ + if( args[0]["default"] ){ + Listen = args[0]["default"]; + map_delete(args[0], "default"); + } + return (Listens = expand_keys(args[0])); + } + else { + Listen = args[0]; + } + return args[0]; + } + else if( sizeof(args) == 2 ){ + if( !args[1] ){ + return SetListen(args[0]); + } + else if( arrayp(args[0]) ){ + foreach(string item in args[0]){ + SetListen(item, args[1]); + } + return args[1]; + } + else { + if( !args[0] || args[0] == "default" ){ + Listen = args[1]; + return Listen; + } + else { + Listens[args[0]] = args[1]; + return Listens[args[0]]; + } + } + } + else { + error("Wrong number of arguments to SetListen():\n\t" + "Expected 1 or 2, got " + sizeof(args) + "\n"); + } +} + +varargs mixed eventListen(object who, string str){ + str = GetListen(str, who); + if( !str ){ + who->eventPrint("You hear nothing unusual."); + return 1; + } + environment(who)->eventPrint(who->GetName() + " listens to " + GetShort() + + ".", who); + who->eventPrint(str); + return 1; +} + +mixed direct_listen_obj(){ + if( !Listen ){ + return "You hear nothing unusual."; + } + else { + return 1; + } +} + +mixed direct_listen_to_obj(){ + return direct_listen_obj(); +} + +mixed direct_listen_to_str_word_obj(string str){ + str = remove_article(lower_case(str)); + if( !Listens[str] ){ + return "You hear nothing special."; + } + else { + return 1; + } +} + +mapping GetListenMap(){ + mapping Listens = ([]); + foreach(object ob in this_object()->GetDummyItems()){ + if( ob->GetListen() ){ + Listens[ob->GetId()] = ob->GetListen(); + } + } + if(this_object()->GetListen()) Listens["default"] = this_object()->GetListen(); + return copy(Listens); +} diff --git a/lib/lib/events/load.c b/lib/lib/events/load.c new file mode 100644 index 0000000..bad152b --- /dev/null +++ b/lib/lib/events/load.c @@ -0,0 +1,72 @@ +int MaxLoad = 1; +int Loaded = 0; + +varargs mixed CanLoad(object who, object what){ + if(who && environment() && environment() != environment(who) && + environment() != who && environment(environment()) != environment(who) + && environment(environment()) != who ){ + return "#That's not accessible to you."; + } + else return 1; +} + +varargs mixed CanUnload(object who, object what){ + if(who && environment() && environment() != environment(who) && + environment() != who && environment(environment()) != environment(who) + && environment(environment()) != who ){ + return "#That's not accessible to you."; + } + else return 1; +} + +varargs mixed eventLoad(object what, object where){ + return 1; +} + +varargs mixed eventUnload(object what, object where){ + return 1; +} + +int direct_load_obj(object target){ + return CanLoad(this_player()); +} + +int direct_unload_obj(object target){ + return CanUnload(this_player(), target); +} + +int direct_load_obj_word_obj(object thingus, object target){ + return CanLoad(this_player(), target); +} + +int indirect_load_obj_word_obj(object target, object thingus){ + return CanLoad(this_player(), target); +} + +int direct_unload_obj_word_obj(object thingus, object target){ + return CanUnload(this_player(), target); +} + +int indirect_unload_obj_word_obj(object one, object two, object three){ + return CanUnload(this_player(), one); +} + +int SetMaxLoad(int i){ + return MaxLoad = i; +} + +int GetMaxLoad(int i){ + return MaxLoad; +} + +int SetLoaded(int i){ + return Loaded = i; +} + +int GetLoaded(int i){ + return Loaded; +} + +int GetMaxLoaded(){ + return Loaded; +} diff --git a/lib/lib/events/lock.c b/lib/lib/events/lock.c new file mode 100644 index 0000000..5bac28c --- /dev/null +++ b/lib/lib/events/lock.c @@ -0,0 +1,276 @@ +/* /lib/events/lock.c + * from the Dead Souls Mud Library + * Handles lock/unlock/pick events + * Created by Descartes of Borg 961221 + * Version: @(#) lock.c 1.4@(#) + * Last modified: 96/12/23 + */ +#include <damage_types.h> + +private string array Keys = ({}); +private int Locked = 0; +private int LockStrength = 0; +private static function Pick = 0; + +// abstract methods +string GetDefiniteShort(); +// end abstract methods + +string array AddKey(string key){ + return (Keys = ({ Keys..., key })); +} + +varargs string array GetKeys(string unused){ + return Keys; +} + +varargs string array SetKeys(mixed array args...){ + if( !args ){ + error("Bad argument 1 to SetKeys().\n"); + } + Keys = ({}); + foreach(mixed val in args){ + if( !val ){ + continue; + } + if( arrayp(val) ){ + Keys = Keys + val; + } + else { + Keys = ({ Keys..., val }); + } + } + return Keys; +} + +int GetLocked(){ + return Locked; +} + +int SetLocked(int x){ + return (Locked = x); +} + +int GetLockStrength(){ + return LockStrength; +} + +int SetLockStrength(int x){ + return (LockStrength = x); +} + +function GetPick(){ + return Pick; +} + +function SetPick(function f){ + return (Pick = f); +} + +string array GetSave(){ + return ({ "Locked", "Keys", "LockStrength" }); +} + +mixed CanLock(object who, string id){ + if( GetLocked() ){ + return "It is already locked."; + } + return 1; +} + +mixed CanPick(object who, string id){ + if( !GetLocked() ){ + return "Pick it when it is not even locked?"; + } + return 1; +} + +varargs mixed CanUnlock(object who, string id, object key){ + if( !GetLocked() ){ + return "It is already unlocked."; + } + return 1; +} + +varargs mixed eventLock(object who, mixed arg1, mixed arg2){ + string array ids = ({}); + object key; + + if(objectp(arg1)) key = arg1; + else if(objectp(arg2)) key = arg2; + else return "There seems to be a problem with unlocking things."; + + ids = key->GetId(); + ids += ({ key->GetName() }); + + if(key->LockFun(1,key,lower_case(this_object()->GetName()))){ + return 1; + } + + if( !sizeof(ids & GetKeys()) ){ + send_messages("try", "$agent_name $agent_verb to lock $target_name " + "with " + key->GetShort() + ", but it does not work.", + who, this_object(), environment(who)); + } + else { + mixed tmp; + + send_messages("attempt", "$agent_name $agent_verb to lock " + "$target_name with " + key->GetShort() + ".", + who, this_object(), environment(who)); + tmp = key->eventLockLock(who, this_object()); + if( tmp != 1 ){ + if( tmp ){ + who->eventPrint(tmp); + } + return 1; + } + if( !SetLocked(1) ){ + return 0; + } + environment(who)->eventPrint(capitalize(GetDefiniteShort()) + + " locks."); + } + return 1; +} + +varargs mixed eventPick(object who, string id, object tool){ + mixed tmp; + int strength; + mixed *prehensiles = ({}); + string limb; + string short; + object prev = previous_object(); + if(prev->isDummy()) short = (prev->GetShort() || prev->GetName()); + + if(!who) return 0; + + prehensiles = who->GetWieldingLimbs(); + if(!sizeof(prehensiles)){ + who->eventPrint("You lack prehensile limbs with which to do that."); + return 1; + } + + limb = prehensiles[random(sizeof(prehensiles))]; + + if( !tool ){ + strength = who->GetSkillLevel("stealth"); + } + else { + tmp = tool->eventPickLock(who, id, this_object()); + strength = tmp + who->GetSkillLevel("stealth"); + } + who->AddSkillPoints("stealth", strength + 1); + who->AddStaminaPoints(-LockStrength/10.0); + if( Pick ){ + tmp = evaluate(Pick, who, id, tool, strength); + if( tmp != 1 ){ + if( !tmp ){ + who->eventPrint("You fail to pick it."); + return 1; + } + return tmp; + } + who->AddSkillPoints("stealth", 2*(LockStrength + strength)); + if( SetLocked(0) ){ + return 0; + } + return 1; + } + if( strength > ( LockStrength / 10 + random(LockStrength) ) ){ + who->AddSkillPoints("stealth", 2*(LockStrength + strength)); + SetLocked(0); + send_messages("pick", "$agent_name $agent_verb the lock on "+ + (short ? short : "$target_name") +"!", + who, this_object(), environment(who)); + return 1; + } + send_messages("fail", "$agent_name $agent_verb in $agent_possessive " + "attempt to pick the lock on "+ + (short ? short : "$target_name") +".", + who, this_object(), environment(who)); + if( random(100) > strength ){ + send_messages("cut", "$agent_name $agent_verb $agent_reflexive " + "on the lock.", who, this_object(), environment(who)); + who->eventReceiveDamage(this_object(), PIERCE, random(10) + 1, 0, limb); + } + return 1; +} + +varargs mixed eventUnlock(object who, mixed arg1, mixed arg2){ + string array ids = ({}); + object key; + + if(objectp(arg1)) key = arg1; + else if(objectp(arg2)) key = arg2; + else return "There seems to be a problem with unlocking things."; + + ids = key->GetId(); + ids += ({ key->GetName() }); + + if(key->UnLockFun(1,key,lower_case(this_object()->GetName()))){ + return 1; + } + + if( !sizeof(ids & GetKeys()) ){ + send_messages("attempt", "$agent_name $agent_verb to unlock " + "$target_name with " + key->GetShort() + ", but it " + "does not work.", who, this_object(), environment(who)); + } + else { + mixed tmp; + + send_messages("attempt", "$agent_name $agent_verb $target_name with "+ + key->GetShort() + ".", who, this_object(), + environment(who)); + tmp = key->eventUnlockLock(who, this_object()); + if( tmp != 1 ){ + if( tmp ){ + who->eventPrint(tmp); + } + return 1; + } + if( SetLocked(0) ){ + return 0; + } + environment(who)->eventPrint(capitalize(GetDefiniteShort()) + + " comes unlocked."); + } + return 1; +} + +varargs mixed direct_lock_obj_with_obj(object target, object key, mixed id...){ + return CanLock(this_player(), remove_article(lower_case(id[0]))); +} + +varargs mixed direct_lock_obj_with_str(object target, mixed key, mixed id...){ + return CanLock(this_player(), remove_article(lower_case(id[0]))); +} + +varargs mixed direct_pick_str_on_obj(string str, object target, string str2, + string id){ + if( remove_article(lower_case(str)) != "lock" ){ + return "Pick the what?"; + } + return CanPick(this_player(), id); +} + +varargs mixed direct_pick_str_on_obj_with_obj(string str, object target, object tool, + string str2, string targ_id){ + if( remove_article(lower_case(str)) != "lock" ){ + return "Pick the what?"; + } + targ_id = remove_article(lower_case(targ_id)); + return CanPick(this_player(), targ_id); +} + +varargs mixed direct_unlock_obj_with_obj(object target, object key, string id, string key2){ + return CanUnlock(this_player(), remove_article(lower_case(id))); +} + +varargs mixed direct_unlock_obj_with_str(object target, object key, string id, string key2){ + return CanUnlock(this_player(), remove_article(lower_case(id))); +} + +mixed direct_wizlock_obj(){ return 1; } +mixed direct_wizunlock_obj(){ return 1; } diff --git a/lib/lib/events/lock_with.c b/lib/lib/events/lock_with.c new file mode 100644 index 0000000..7d197a1 --- /dev/null +++ b/lib/lib/events/lock_with.c @@ -0,0 +1,76 @@ +/* /lib/events/lock_with.c + * From the Dead Souls Mud Library + * The indirect object of locks and unlocks (a key) + * Created by Descartes of Borg 960121 + */ + +private int Disabled = 0; +private int DisableChance = 50; + +// abstract methods +string GetDefiniteShort(); +// end abstract methods + +int GetDisableChance(){ + return DisableChance; +} + +int SetDisableChance(int x){ + return (DisableChance = x); +} + +int GetDisabled(){ + return Disabled; +} + +int SetDisabled(int x){ + return (Disabled = x); +} + +mixed array GetSave(){ + return ({ "Disabled", "DisableChance" }); +} + +mixed eventLockLock(object who, object what){ + return 1; +} + +mixed eventUnlockLock(object who, object what){ + if( GetDisableChance() > random(100) ){ + SetDisabled(1); + who->eventPrint(capitalize(GetDefiniteShort()) + " gets twisted " + "slightly out of shape as you try to use it."); + return 1; + } + return 1; +} + +varargs mixed indirect_lock_obj_with_obj(object target, object key, mixed id){ + if( environment() != this_player() ){ + return "#You don't have " + GetDefiniteShort() + "!"; + } + if( GetDisabled() ){ + return capitalize(GetDefiniteShort()) + " is broken."; + } + return 1; +} + +varargs mixed indirect_lock_obj_with_str(object target, mixed key, mixed id...){ + if(stringp(key)) key = (get_object(key) || ""); + return indirect_lock_obj_with_obj(target, key, id); +} + +mixed indirect_unlock_obj_with_obj(object target, object key, mixed id...){ + if( environment() != this_player() ){ + return "#You don't have " + GetDefiniteShort() + "!"; + } + if( GetDisabled() ){ + return capitalize(GetDefiniteShort()) + " is broken."; + } + return 1; +} + +varargs mixed indirect_unlock_obj_with_str(object target, mixed key, mixed id){ + if(stringp(key)) key = (get_object(key) || ""); + return indirect_lock_obj_with_obj(target, key, id); +} diff --git a/lib/lib/events/look.c b/lib/lib/events/look.c new file mode 100644 index 0000000..b85fc57 --- /dev/null +++ b/lib/lib/events/look.c @@ -0,0 +1,287 @@ +/* /lib/events/show.c + * From the Dead Souls LPC Library + * Responds to people looking at things on objects + * Created by Descartes of Borg 930616 + * Version: @(#) look.c 1.8@(#) + * Last modified: 96/12/31 + */ + +#include <function.h> +#include <daemons.h> +#include <lib.h> +#include <vision.h> + +private mixed ExternalDesc = 0; +private int Invisible = 0; +private static string look_globalval; +static function f; +mapping Items = ([]); + +// abstract methods +string GetShort(); +// end abstract methods + +varargs string GetExternalDesc(object who){ + string openstate; + + if(this_object()->CanClose()){ + if(this_object()->GetClosed()) openstate = " It is closed."; + else openstate = " It is open."; + } + else openstate = ""; + + if( !ExternalDesc ){ + return ""; + } + if( functionp(ExternalDesc) ){ + if( functionp(ExternalDesc) & FP_OWNER_DESTED ){ + return ""; + } + return evaluate(ExternalDesc, who); + } + else if( arrayp(ExternalDesc) ){ + return ExternalDesc[query_night()] + openstate;; + } + else { + return ExternalDesc + openstate; + } +} + +string SetExternalDesc(string desc){ + return (ExternalDesc = desc); +} + +varargs int GetInvis(object ob){ + if( !ob ){ + ob = (this_player() || previous_object()); + } + if( functionp(Invisible) ){ + return evaluate(Invisible, ob); + } + else return Invisible; +} + +mixed SetInvis(mixed val){ + if( !val || intp(val) ){ + if(!val || val == 0){ + Invisible = 0; + if(sizeof(get_livings(environment(this_object()),2))){ + foreach(object ob in get_livings(environment(this_object()),2)){ + ob->CheckEncounter(); + } + } + } + else Invisible = val; + } + else if( functionp(val) && !Invisible ){ + Invisible = val; + } + INSTANCES_D->UpdateInvis( (Invisible ? 1 : 0) ); + return Invisible; +} + +varargs mixed AddItem(mixed item, mixed val){ + if( objectp(item) ){ + item->eventMove(this_object()); + return 1; + } + if( functionp(val) || stringp(val) || arrayp(val) ){ + if( stringp(item) ){ + Items[item] = val; + } + else if( arrayp(item) ){ + map(item, (: AddItem($1, $(val)) :)); + return val; + } + else { + error("Bad argument 1 to AddItem().\n"); + } + } + else error("Bad argument 2 to AddItem().\n"); + return (Items[item]); +} + +//TMI2 back-compat hack +static mixed AddItem_func(mixed foo){ + foreach(mixed key, mixed val in foo){ + look_globalval = val; + AddItem(key, (: look_globalval :) ); + } + return foo; +} + +static mixed SetItem_func(mixed foo){ + foreach(mixed key, mixed val in foo){ + look_globalval = val; + f = bind( (: call_other, this_object(), look_globalval :), this_object() ); + AddItem(key, (: f :) ); + } + return foo; +} + +varargs mixed GetItem(string item, object who){ + //mixed val = mapping_member(Items, item); + mixed val = Items[item]; + + if( !val ){ + return 0; + } + if( stringp(val) || arrayp(val)){ + return val; + } + else if( functionp(val) ){ + if( functionp(val) & FP_OWNER_DESTED ){ + return "An error occurred evaulating a function pointer."; + } + return evaluate(val, who, item); + } + else { + return 0; + } +} + +string array GetItems(){ + return keys(Items); +} + +mapping GetItemsMap(){ + return copy(Items); +} + +mapping RemoveItem(mixed item){ + if( !stringp(item) ){ + if( !arrayp(item) ){ + error("Bad argument 1 to RemoveItem().\n"); + } + map(item, (: RemoveItem($1) :)); + return copy(Items); + } + map_delete(Items, item); + return copy(Items); +} + +mapping SetItems(mapping items){ + foreach(mixed key, mixed val in items){ + AddItem(key, val); + } + return copy(Items); +} + +//TMI2 compat hack +mapping SetItem_desc(mapping items){ + return SetItems(items); +} + +varargs string GetLong(string str){ + if( str && Items[str] ){ + return GetItem(str); + } + else { + return this_object()->GetExternalDesc(); + } +} + +string SetLong(string str){ + return SetExternalDesc(str); +} + +varargs mixed eventShow(object who, string component){ + mixed desc; + + if( component ){ + component = remove_article(lower_case(component)); + desc = GetItem(component, who); + environment(who)->eventPrint(who->GetName() + " looks at the " + + component + " on the " + remove_article(GetShort()) + ".", + ({ who, this_object() })); + } + else { + desc = GetExternalDesc(who); + environment(who)->eventPrint(who->GetName() + " looks at the " + + remove_article(GetShort()) + ".", + ({ who, this_object() })); + } + + if((!inherits(LIB_SIT,this_object()) && !inherits(LIB_LIE,this_object())) || + (!sizeof(this_object()->GetLiers()) && !sizeof(this_object()->GetSitters()))){ + if(inherits(LIB_SURFACE,this_object()) || + this_object()->GetOpacity() < 33){ + (functionp(desc) ? evaluate(desc) : who->eventPrint(desc)); + this_object()->eventShowInterior(who); + } + else (functionp(desc) ? evaluate(desc) : who->eventPrint(desc)); + } + else (functionp(desc) ? evaluate(desc) : who->eventPrint(desc)); + return 1; +} + +mixed direct_look_obj(){ + object env = environment(); + if(!this_object()->GetInvis()){ + if( env != this_player() && env != environment(this_player()) ){ + return "#Perhaps \"look at "+this_object()->GetKeyName()+ + " on\" something?"; + } + } + return 1; +} + +mixed direct_look_at_obj(){ + return direct_look_obj(); +} + +mixed direct_look_on_obj(){ + return direct_look_obj(); +} + +mixed direct_look_at_obj_on_obj(object target, object ob,mixed arg, mixed arg2){ + if(!ob) ob=environment(target); + if((inherits(LIB_SIT,ob) && sizeof(ob->GetSitters())) || + (inherits(LIB_LIE,ob) && sizeof(ob->GetLiers()))){ + write("There appears to be someone blocking your view."); + } + + if(ob->GetInvis()){ + return "#There is no "+arg+" on "+arg2+" here."; + } + + if(!target->GetInvis()){ + if((inherits(LIB_SURFACE,ob) || living(ob)) && + environment(target) == ob){ + if(this_player()->GetEffectiveVision() == VISION_CLEAR){ + if(living(target)) return target->GetLong(); + else return target->GetExternalDesc(); + } + else return "#You can't quite make out its details."; + } + } + if( environment(target) != ob || target->GetInvis() ){ + return "#There is no " + arg + " on " + ob->GetShort() + "."; + } + return 1; +} + +mixed direct_look_at_obj_word_obj(){ + return direct_look_obj(); +} + +mixed direct_look_at_str_on_obj(string str, object target){ + object dingus; + str = remove_article(lower_case(str)); + if((inherits(LIB_SIT,target) && sizeof(target->GetSitters())) || + (inherits(LIB_LIE,target) && sizeof(target->GetLiers()))){ + write("There appears to be someone blocking your view."); + return 0; + } + + if((inherits(LIB_SURFACE,target) || living(target)) && dingus = present(str, target)){ + if(this_player()->GetEffectiveVision() == VISION_CLEAR){ + return dingus->GetExternalDesc(); + } + else return "#You can't quite make out its details."; + } + if( !Items[str] ){ + return "#There is no " + str + " on " + GetShort() + "."; + } + return 1; +} diff --git a/lib/lib/events/look_in.c b/lib/lib/events/look_in.c new file mode 100644 index 0000000..47aa6ea --- /dev/null +++ b/lib/lib/events/look_in.c @@ -0,0 +1,128 @@ +/* /lib/events/look_in.c + * From the Dead Souls Mud Library + * Something that can be seen in + * Created by Descartes of Borg 961222 + * Version :@(#) look_in.c 1.2@(#) + * Last modified: 96/12/31 + */ + +#include <function.h> + +private string InternalDesc = 0; +int Opacity = 100; + +// abstract methods +string GetShort(); +// end abstract methods + +string GetInternalDesc(){ + mixed val = InternalDesc; + + if( arrayp(val) ){ + val = val[query_night()]; + } + if( stringp(val) ){ + return val; + } + else if( functionp(val) ){ + if( functionp(val) & FP_OWNER_DESTED ){ + return "Error evaluating internal description."; + } + return evaluate(val, this_player()); + } +} + +string SetInternalDesc(string str){ + return (InternalDesc = str); +} + +int GetOpacity(){ + return Opacity; +} + +int SetOpacity(int x){ + Opacity = x; + parse_refresh(); + return Opacity; +} + +varargs mixed CanShowInterior(object who, object target){ + int x; + if(!who) who = this_player(); + + if( environment() != this_player() && environment(this_player()) != + environment()){ + return "#You don't have that!"; + } + + if(living() && !inherits(LIB_VEHICLE,this_object())){ + return "You can't look inside of a living being."; + } + + if( target ){ + x = 66; + } + else { + x = 33; + } + if( this_object()->GetClosed() && this_object()->GetOpacity() > x ){ + return 0; + } + return 1; +} + +varargs mixed eventShowInterior(object who, object target){ + object here,me,imhere,dabei; + string this,str; + here=environment(this_object()); + me=this_object(); + this=me->GetKeyName(); + str=me->GetInternalDesc(); + imhere=present(this,environment(who)); + dabei=present(this,who); + + if( target ){ + return "A strange event has occurred, which you should report."; + } + + if(!imhere && !dabei){ + who->eventPrint("That is not here."); + return 0; + } + + if( !str || str == "" ){ + return 0; + } + if(!inherits(LIB_SURFACE, this_object())){ + environment(who)->eventPrint(who->GetName() + " looks inside " + + GetShort() + ".", who); + } + who->eventPrint(str); + +} + +mixed direct_look_in_obj(){ + if(inherits(LIB_SURFACE, this_object())) return 0; + return CanShowInterior(this_player()); +} + +mixed direct_look_inside_obj(){ + if(inherits(LIB_SURFACE, this_object())) return 0; + return CanShowInterior(this_player()); +} + +mixed indirect_look_at_obj_word_obj(object target){ + if( environment(target) != this_object() ){ + return "#That is not in there."; + } + return CanShowInterior(this_player(), target); +} + +mixed inventory_visible(){ + if( GetOpacity() > 33 ){ + return 0; + } + else { + return 1; + } +} diff --git a/lib/lib/events/manipulate.c b/lib/lib/events/manipulate.c new file mode 100644 index 0000000..d7dba91 --- /dev/null +++ b/lib/lib/events/manipulate.c @@ -0,0 +1,103 @@ +#include <function.h> + +static private mapping Manipulate = ([]); + +// abstract methods +string GetDefiniteShort(); +// end abstract methods + +varargs mixed GetManipulate(string str){ + if( !str ){ + str = "default"; + } + return Manipulate[str]; +} + +string array GetManipulates(){ + return keys(Manipulate); +} + +mapping RemoveManipulate(string item){ + map_delete(Manipulate, item); + return Manipulate; +} + +varargs mapping SetManipulate(mixed key, mixed desc){ + if( !key ){ + key = "default"; + } + if( !desc ){ + if( mapp(key) ){ + Manipulate = expand_keys(key); + } + else { + Manipulate["default"] = key; + } + } + else { + Manipulate[key] = desc; + } + return Manipulate; +} + +varargs mixed CanManipulate(object who, string component){ + mixed val; + + if( !component ){ + component = "default"; + } + val = Manipulate[component]; + if( !val ){ + if( component == "default" ){ + return 0; + } + else { + return "#There is no " + component + " on " + + GetDefiniteShort() + "."; + } + } + else return 1; +} + +varargs mixed eventManipulate(object who, string component){ + mixed val; + + if( !component ){ + val = Manipulate["default"]; + } + else { + val = Manipulate[component]; + } + if( arrayp(val) ){ + val = val[query_night()]; + } + if( stringp(val) ){ + object env; + + env = environment(who); + who->eventPrint(val); + if( component ){ + env->eventPrint(who->GetName() + " moves the " + component + + " on " + GetDefiniteShort() + ".", who); + } + else { + env->eventPrint(who->GetName() + " moves " + + GetDefiniteShort() + ".", who); + } + return 1; + } + else { + if( functionp(val) & FP_OWNER_DESTED ){ + return "Error in evaluating functional."; + } + return evaluate(val, who, component); + } +} + +mixed direct_move_obj(object target){ + return CanManipulate(this_player()); +} + +mixed direct_move_str_on_obj(string str, object target){ + return CanManipulate(this_player(), remove_article(lower_case(str))); +} diff --git a/lib/lib/events/poison.c b/lib/lib/events/poison.c new file mode 100644 index 0000000..2cb8d42 --- /dev/null +++ b/lib/lib/events/poison.c @@ -0,0 +1,44 @@ +/* /lib/events/poison.c + * From the Dead Souls Mud Library + * Objects which can respond to poisoning + * Created by Descartes of Borg 970101 + * Version: @(#) poison.c 1.1@(#) + * Last modified: 97/01/01 + */ + +private int Poison = 0; + +int AddPoison(int x){ + Poison += x; + if( Poison < 1 ){ + Poison = 0; + } + return Poison; +} + +int GetPoison(){ + return Poison; +} + +int SetPoison(int x){ + return (Poison = x); +} + +string array GetSave(){ + return ({ "Poison" }); +} + +mixed CanPoison(object who){ + return 1; +} + +mixed eventPoison(object who, object agent, int strength){ + send_messages("spread", "$agent_name $agent_verb some poison onto " + "$target_name.", who, this_object(), environment(who)); + AddPoison(strength); + return 1; +} + +mixed direct_poison_obj_with_obj(){ + return CanPoison(this_player()); +} diff --git a/lib/lib/events/press.c b/lib/lib/events/press.c new file mode 100644 index 0000000..1b6e99c --- /dev/null +++ b/lib/lib/events/press.c @@ -0,0 +1,110 @@ +/* /lib/events/press.c + * from the Dead Souls Mud Library + * handles people pressing things + * created by Descartes of Borg 960114 + * Version: @(#) press.c 1.3@(#) + * Last modified: 96/12/22 + */ + +#include <function.h> + +static private mapping Press = ([]); + +// abstract methods +string GetDefiniteShort(); +// end abstract methods + +varargs mixed GetPress(string str){ + if( !str ){ + str = "default"; + } + return Press[str]; +} + +string array GetPresses(){ + return keys(Press); +} + +mapping RemovePress(string item){ + map_delete(Press, item); + return Press; +} + +varargs mapping SetPress(mixed key, mixed desc){ + if( !key ){ + key = "default"; + } + if( !desc ){ + if( mapp(key) ){ + Press = expand_keys(key); + } + else { + Press["default"] = key; + } + } + else { + Press[key] = desc; + } + return Press; +} + +varargs mixed CanPress(object who, string component){ + mixed val; + if( !component ){ + component = "default"; + } + val = Press[component]; + if( !val ){ + if( component == "default" ){ + return 0; + } + else { + return "#There is no " + component + " on " + + GetDefiniteShort() + "."; + } + } + else return 1; +} + +varargs mixed eventPress(object who, string component){ + mixed val; + + if( !component ){ + val = Press["default"]; + } + else { + val = Press[component]; + } + if( arrayp(val) ){ + val = val[query_night()]; + } + if( stringp(val) ){ + object env; + + env = environment(who); + who->eventPrint(val); + if( component ){ + env->eventPrint(who->GetName() + " presses the " + component + + " on " + GetDefiniteShort() + ".", who); + } + else { + env->eventPrint(who->GetName() + " presses " + + GetDefiniteShort() + ".", who); + } + return 1; + } + else { + if( functionp(val) & FP_OWNER_DESTED ){ + return "Error in evaluating functional."; + } + return evaluate(val, who, component); + } +} + +mixed direct_press_obj(object target){ + return CanPress(this_player()); +} + +mixed direct_press_str_on_obj(string str, object target){ + return CanPress(this_player(), remove_article(lower_case(str))); +} diff --git a/lib/lib/events/pull.c b/lib/lib/events/pull.c new file mode 100644 index 0000000..0ca4a31 --- /dev/null +++ b/lib/lib/events/pull.c @@ -0,0 +1,107 @@ +#include <function.h> + +static private mapping Pull = ([]); + +// abstract methods +string GetDefiniteShort(); +// end abstract methods + +varargs mixed GetPull(string str){ + if( !str ){ + str = "default"; + } + return Pull[str]; +} + +string array GetPulls(){ + return keys(Pull); +} + +mapping RemovePull(string item){ + map_delete(Pull, item); + return Pull; +} + +varargs mapping SetPull(mixed key, mixed desc){ + if( !key ){ + key = "default"; + } + if( !desc ){ + if( mapp(key) ){ + Pull = expand_keys(key); + } + else { + Pull["default"] = key; + } + } + else { + Pull[key] = desc; + } + return Pull; +} + +varargs mixed CanPull(object who, string component){ + mixed val; + + if( !component ){ + component = "default"; + } + val = Pull[component]; + if( !val ){ + if( component == "default" ){ + return 0; + } + else { + return "#There is no " + component + " on " + + GetDefiniteShort() + "."; + } + } + else return 1; +} + +varargs mixed eventPull(object who, string component){ + mixed val; + + if( !component ){ + val = Pull["default"]; + } + else { + val = Pull[component]; + } + if( arrayp(val) ){ + val = val[query_night()]; + } + if( stringp(val) ){ + object env; + + env = environment(who); + who->eventPrint(val); + if( component ){ + env->eventPrint(who->GetName() + " pulls the " + component + + " on " + GetDefiniteShort() + ".", who); + } + else { + env->eventPrint(who->GetName() + " pulls " + + GetDefiniteShort() + ".", who); + } + return 1; + } + else { + if( functionp(val) & FP_OWNER_DESTED ){ + return "Error in evaluating functional."; + } + return evaluate(val, who, component); + } +} + +mixed direct_pull_obj(object target){ + return CanPull(this_player()); +} + +mixed direct_pull_str_on_obj(string str, object target){ + return CanPull(this_player(), remove_article(lower_case(str))); +} + +mixed direct_pull_str_from_obj(string str, object target){ + return direct_pull_str_on_obj(str, target); +} diff --git a/lib/lib/events/put.c b/lib/lib/events/put.c new file mode 100644 index 0000000..ad1161a --- /dev/null +++ b/lib/lib/events/put.c @@ -0,0 +1,103 @@ +/* /lib/put.c + * from the Dead Souls Mud Library + * handles things which may be put into other objects + * created by Descartes of Borg 960114 + */ + +#include <lib.h> + +private mixed PreventPut; + +// abstract methods +string GetShort(); +mixed CanDrop(object who); +mixed eventMove(mixed dest); +// end abstract methods + +mixed SetPreventPut(mixed val){ + return (PreventPut = val); +} + +mixed GetPreventPut(){ + return PreventPut; +} + +varargs mixed CanPut(object who, object what){ + mixed tmp; + object env; + + if(what) env = environment(what); + if(!env || env != this_player()){ + return "#You don't have that."; + } + if( (tmp = CanDrop(who)) != 1 ) return tmp; + if( !environment() ){ destruct(this_object()); return 1; } + if( environment() != this_player() && + environment() != environment(this_player())) return 0; + if( !PreventPut ) return 1; + if( stringp(PreventPut) && PreventPut == "PERMIT" ) return 1; + if( intp(PreventPut) ) return 0; + if( stringp(PreventPut) ) return PreventPut; + if( objectp(PreventPut) ){ + if( PreventPut == who ) + return "You cannot put " + GetShort() + " anywhere."; + else return 1; + } + else if(functionp(PreventPut)) return evaluate(PreventPut, who); + else { + return "It seems you're unable to do that right now."; + } +} + +varargs mixed eventPut(object who, object storage, string prep){ + int depth; + if(!prep || prep == "") prep = " into "; + if(prep == " onto " && !inherits( LIB_SURFACE, previous_object() ) ){ + who->eventPrint("That isn't a load-bearing surface."); + return 0; + } + + if(prep == " into " && inherits( LIB_SURFACE, previous_object() ) ){ + who->eventPrint("That's a surface. Try \"put on\""); + return 0; + } + + if((inherits(LIB_SIT,storage) && sizeof(storage->GetSitters())) || + (inherits(LIB_LIE,storage) && sizeof(storage->GetLiers()))){ + write("There appears to be someone blocking your access."); + return 0; + } + + + if( !eventMove(storage) ){ + who->eventPrint("The "+remove_article(this_object()->GetShort())+" stays where it is."); + return 0; + } + who->eventPrint("You put " + GetShort() + prep + + storage->GetShort() + "."); + environment(who)->eventPrint(who->GetName() + " puts " + + GetShort() + prep + + storage->GetShort() + ".", who); + if(inherits(LIB_STORAGE, this_object())){ + depth = this_object()->GetRecurseDepth(); + if(depth && inherits(LIB_STORAGE, storage)) storage->AddRecurseDepth(depth); + } + + return 1; +} + +static void create(){ + PreventPut = 0; +} + +mixed direct_put_obj_word_obj(){ + return CanPut(this_player(), this_object()); +} + +mixed direct_put_wrd_wrd_word_obj(){ + return CanPut(this_player(), this_object()); +} + +mixed direct_put_obj_obj(){ + return direct_put_obj_word_obj(); +} diff --git a/lib/lib/events/read.c b/lib/lib/events/read.c new file mode 100644 index 0000000..8fb577c --- /dev/null +++ b/lib/lib/events/read.c @@ -0,0 +1,193 @@ +#include <function.h> +#include <message_class.h> + +static private string Language; +static private mixed Read = 0; +static private mapping Reads = ([]); + +private string tmpfile; + +// abstract methods +string GetShort(); +// end abstract methods + +string GetRead(string str){ + if( !str || str == "default" ){ + if(Reads["default"]) return Reads["default"]; + else return Read; + } + else { + return Reads[str]; + } +} + +string array GetReads(){ + return keys(Reads); +} + +mapping GetReadsMap(){ + mapping ret = (Reads || ([])); + if(stringp(Read)) ret["default"] = Read; + else if(mapp(Read) && Read["default"]) ret["default"] = Read["default"]; + return ret; +} + +void RemoveRead(string item){ + if( !item || item == "default" ){ + Reads["default"] = 0; + Read = 0; + } + else { + map_delete(Reads, item); + } + return; +} + +varargs mixed SetRead(mixed arg1, mixed desc){ + if( mapp(arg1) ){ + Reads = expand_keys(arg1); + if( Reads["default"] ){ + Read = Reads["default"]; + } + } + if( !desc ){ + Read = arg1; + return Read; + } + if( !arg1 || arg1 == "default" ){ + Read = desc; + return Read; + } + if( arrayp(arg1) ){ + foreach(string element in arg1){ + Reads[element] = desc; + } + } + else { + Reads[arg1] = desc; + } + return Reads; +} + +void SetReads(mapping ReadMap){ + foreach(mixed key, mixed val in ReadMap){ + SetRead(key, val); + } +} + +varargs mixed SetDefaultRead(mixed arg1, mixed desc){ + if( mapp(arg1) ){ + return 0; + } + if( !desc ){ + Read = arg1; + return Read; + } + if( !arg1 || arg1 == "default" ){ + Read = desc; + return Read; + } +} + +int SetLanguage(string str){ + if(str) Language = str; + return 1; +} + +mixed GetLanguage(){ + if(Language) return Language; + else return 0; +} + +varargs mixed eventRead(object who, mixed str){ + mixed ret; + mixed val; + if(str) val = GetRead(str); + else val = GetRead("default"); + if( arrayp(val) ){ + val = val[query_night()]; + } + if(mapp(val)) val = val[str]; + + if( functionp(val) ){ + if( functionp(val) & FP_OWNER_DESTED ){ + who->eventPrint("There was a problem with the read."); + return 1; + } + ret = evaluate(val, str); + if(!stringp(ret)) return 1; + } + environment(who)->eventPrint(who->GetName() + " reads " + GetShort() + ".", + who); + if(ret) val = ret; + if( !val ){ + who->eventPrint("There is nothing to read."); + return 1; + } + + if(Language){ + write("The language appears to be "+capitalize(Language)+"."); + } + + if(!val){ + write("You can't read that."); + return 0; + } + + if(Language && (this_player()->GetLanguageLevel(Language) < 100 && + !(this_player()->GetPolyglot()))){ + if(sizeof(val) > 4800){ + val = "It is too long and you are too unfamiliar with the language to make sense of it."; + + } + else { + val = translate(val, this_player()->GetLanguageLevel(Language)); + } + } + + who->eventPage(explode(val,"\n") +({""})); + return 1; +} + +mixed direct_read_obj(){ + if( !Read ){ + return 0; + } + else { + if( environment() != this_player() && environment(this_player()) != + environment()){ + return "#You don't have that!"; + } + else return 1; + + } +} + +mixed direct_read_str_word_obj(string str){ + str = remove_article(lower_case(str)); + if( !Reads[str] ){ + return 0; + } + else { + if( environment() != this_player() && environment(this_player()) != + environment()){ + return "#You don't have that!"; + } + else return 1; + + } +} + +mixed direct_read_obj_at_obj(object reader, object readee){ + if( !Read ){ + return 0; + } + else { + if( environment() != this_player() && environment(this_player()) != + environment()){ + return "#You don't have that!"; + } + else return 1; + + } +} diff --git a/lib/lib/events/rock.c b/lib/lib/events/rock.c new file mode 100644 index 0000000..32d30ea --- /dev/null +++ b/lib/lib/events/rock.c @@ -0,0 +1,23 @@ +varargs int CanRock(mixed who, mixed what){ + return this_player()->CanManipulate(); +} + +mixed direct_rock_obj(object target){ + return CanRock(this_player(), target); +} + +mixed direct_rock_wrd_obj(object target){ + return CanRock(this_player(), target); +} + +mixed direct_rock_str(string str){ + return CanRock(this_player(), remove_article(lower_case(str))); +} + +mixed direct_rock_str_on_obj(string str, object target){ + return CanRock(this_player(), remove_article(lower_case(str))); +} + +varargs mixed eventRock(object who, mixed what){ + return 1; +} diff --git a/lib/lib/events/roll.c b/lib/lib/events/roll.c new file mode 100644 index 0000000..e32d063 --- /dev/null +++ b/lib/lib/events/roll.c @@ -0,0 +1,63 @@ +#include <lib.h> + +varargs mixed CanRoll(object target, object where){ + return 1; +} + +mixed direct_roll_obj(object target){ + if( environment(this_object()) != this_player() ){ + return "#You don't have that!"; + } + return CanRoll(this_object()); +} + +mixed direct_roll_obj_on_obj(object target, object where, mixed wtf, mixed wtf2){ + if( environment(this_object()) != this_player() ){ + return "#You don't have that!"; + } + if(!where && wtf2) where = present(wtf2, environment(this_player())); + if(!where && wtf2) where = get_object(wtf2, this_player()); + if(!where && (wtf2 == "floor" || wtf2 == "ground")){ + return CanRoll(this_object()); + } + if(!where || !inherits(LIB_SURFACE,where) ) return "#You can't roll that there!"; + return CanRoll(this_object(), where); +} + +mixed direct_roll_obj_on_str(object target, string where){ + if( environment(this_object()) != this_player() ){ + return "#You don't have that!"; + } + return CanRoll(this_object()); +} + +mixed direct_roll_obj_here(object target){ + if( environment(this_object()) != this_player() ){ + return "#You don't have that!"; + } + return CanRoll(this_object()); +} + +mixed indirect_roll_obj_on_obj(object target, object where){ + if( environment(this_object()) != environment(this_player()) ){ + return "#That's not here for rolling on."; + } + if(!inherits(LIB_SURFACE,where) ){ + return "#You can't roll that on there!"; + } + return CanRoll(this_object(), where); +} + +mixed indirect_roll_obs_on_obj(mixed target, object where){ + return indirect_roll_obj_on_obj(target, where); +} + +varargs mixed eventRoll(object ob){ + return 1; +} + +varargs mixed eventResults(mixed args){ + say("The result of "+this_player()->GetName()+"'s roll is: "+identify(args)); + write("The result of your roll is: "+identify(args)); + return args; +} diff --git a/lib/lib/events/scratch.c b/lib/lib/events/scratch.c new file mode 100644 index 0000000..8358997 --- /dev/null +++ b/lib/lib/events/scratch.c @@ -0,0 +1,97 @@ +#include <function.h> + +static private mapping Scratch = ([]); + +// abstract methods +string GetDefiniteShort(); +// end abstract methods + +varargs mixed GetScratch(string str){ + if( !str ){ + str = "default"; + } + return Scratch[str]; +} + +string array GetScratches(){ + return keys(Scratch); +} + +mapping RemoveScratch(string item){ + map_delete(Scratch, item); + return Scratch; +} + +varargs mapping SetScratch(mixed key, mixed desc){ + if( !key ){ + key = "default"; + } + if( !desc ){ + if( mapp(key) ){ + Scratch = expand_keys(key); + } + else { + Scratch["default"] = key; + } + } + else { + Scratch[key] = desc; + } + return Scratch; +} + +varargs mixed CanScratch(object who, string component){ + return 1; +} + +varargs mixed eventScratch(object who, mixed component){ + mixed val; + + if( !component ){ + val = Scratch["default"]; + } + else { + val = Scratch[component]; + } + if( arrayp(val) ){ + val = val[query_night()]; + } + if( stringp(val) ){ + object env; + + env = environment(who); + who->eventPrint(val); + if( component ){ + env->eventPrint(who->GetName() + " scratches on the " + component + + " on " + GetDefiniteShort() + ".", who); + } + else { + env->eventPrint(who->GetName() + " scratches on " + + GetDefiniteShort() + ".", who); + } + return 1; + } + else { + if( functionp(val) & FP_OWNER_DESTED ){ + return "Error in evaluating functional."; + } + return evaluate(val, who, component); + } +} + +mixed direct_scratch_obj(object target){ + return CanScratch(this_player()); +} + +mixed direct_scratch_on_obj(object target){ + return direct_scratch_obj(target);; +} + +mixed direct_scratch_str_on_obj(string str, object target){ + return CanScratch(this_player(), remove_article(lower_case(str))); +} + +mixed direct_scratch_on_str_on_obj(string str, object target){ + return direct_scratch_str_on_obj(str,target); +} + diff --git a/lib/lib/events/search.c b/lib/lib/events/search.c new file mode 100644 index 0000000..ae1a344 --- /dev/null +++ b/lib/lib/events/search.c @@ -0,0 +1,172 @@ +/* /lib/search.c + * from the Dead Souls Mud Library + * allows people to search things + * created by Descartes of Borg 951008 + * Version: @(#) search.c 1.7@(#) + * Last modified: 97/01/01 + */ + +#include <lib.h> +#include <function.h> + +static private mixed Search = 0; +static private mapping Searches = ([]); + +// abstract methods +string GetShort(); +// end abstract methods + +mapping GetTraps(){ + mapping shads = this_object()->GetShadows(); + foreach(mixed key, mixed val in shads){ + if(!inherits(LIB_BOOBYTRAP_SHADOW, key)) map_delete(shads, key); + else shads[key] = ([ "level" : key->GetTrapLevel(), "description" : key->GetTrapDescription() ]); + } + return shads; +} + +mapping FoundTraps(){ + mapping Traps = GetTraps(); + int detection_level = 0; + if(sizeof(Traps)){ + if(this_player()->GetSkill("detection")) + detection_level += this_player()->GetSkill("detection")["level"]; + detection_level += this_player()->GetStat("luck")["level"]; + detection_level += this_player()->GetStat("intelligence")["level"]; + foreach(mixed key, mixed val2 in Traps){ + if(detection_level < val2["level"]) map_delete(Traps, key); + } + } + return Traps; +} + +varargs string GetSearch(string str, object who){ + mixed val; + mapping Traps = FoundTraps(); + string trapdesc = "You discover it is boobytrapped!\n"; + + if(sizeof(Traps)){ + int i = 0; + foreach(mixed key, mixed val2 in Traps){ + i++; + trapdesc += i+ordinal(i)+" trap: "+val2["description"] + "\n"; + } + if(i == 1) trapdesc = replace_string(trapdesc,"1st trap: ",""); + } + + if(!sizeof(Traps)) trapdesc = ""; + + if( !str || str == "default" ){ + val = Search; + } + else { + val = Searches[str]; + } + if(val && stringp(val) && sizeof(Traps)){ + val += "\n"+ trapdesc; + } + if(!val && sizeof(Traps)){ + val = trapdesc; + } + + if( !val ){ + return 0; + } + if( functionp(val) ){ + if( functionp(val) & FP_OWNER_DESTED ){ + return "An error occured in a function pointer."; + } + return evaluate(val, who, str); + } + else if( arrayp(val) ){ + return val[query_night()]+trapdesc; + } + else return val; +} + +string array GetSearches(){ + return keys(Searches); +} + +mapping RemoveSearch(string item){ + if( !item || item == "default" ){ + Search = 0; + } + else { + //map_delete(Searches, item); + Searches["item"] = "You find nothing."; + } + return Searches; +} + +varargs mixed SetSearch(mixed array args...){ + if( sizeof(args) == 1 ){ + if( mapp(args[0]) ){ + if( args[0]["default"] ){ + Search = args[0]["default"]; + map_delete(args[0], "default"); + } + return (Searches = expand_keys(args[0])); + } + else { + Search = args[0]; + } + return args[0]; + } + else if( sizeof(args) == 2 ){ + if( !args[1] ){ + return SetSearch(args[0]); + } + else if( arrayp(args[0]) ){ + foreach(string item in args[0]){ + SetSearch(item, args[1]); + } + return args[1]; + } + else { + if( !args[0] || args[0] == "default" ){ + Search = args[1]; + return Search; + } + else { + Searches[args[0]] = args[1]; + return Searches[args[0]]; + } + } + } + else { + error("Wrong number of arguments to SetSearch():\n\t" + "Expected 1 or 2, got " + sizeof(args) + "\n"); + } +} + +varargs mixed eventSearch(object who, string str){ + str = GetSearch(str, who); + if( !str ){ + who->eventPrint("You find nothing."); + return 1; + } + environment(who)->eventPrint(who->GetName() + " searches " + "for something.", who); + who->eventPrint(str); + return 1; +} + +mixed direct_search_obj(){ + if( !Search && !sizeof(FoundTraps()) ){ + return 0; + } + else { + return 1; + } +} + +mixed direct_search_str_word_obj(string str){ + str = remove_article(lower_case(str)); + if( !Searches[str] || !sizeof(GetTraps()) ){ + return 0; + } + else { + return 1; + } +} diff --git a/lib/lib/events/sell.c b/lib/lib/events/sell.c new file mode 100644 index 0000000..9da9d7c --- /dev/null +++ b/lib/lib/events/sell.c @@ -0,0 +1,22 @@ +/* /lib/events/sell.c + * From the Dead Souls Objecdt Library + * Handles the buying and selling of items + * Created by Descartes of Borg 970101 + * Version: @(#) sell.c 1.1@(#) + * Last modified: 97/01/01 + */ + +mixed CanSell(object seller){ + return 1; +} + +mixed direct_sell_obj_to_liv(){ + if( environment() != this_player() ){ + return "#You don't have that!"; + } + return CanSell(this_player()); +} + +mixed indirect_sell_liv_obj(){ + return direct_sell_obj_to_liv(); +} diff --git a/lib/lib/events/shake.c b/lib/lib/events/shake.c new file mode 100644 index 0000000..0ffae82 --- /dev/null +++ b/lib/lib/events/shake.c @@ -0,0 +1,103 @@ +#include <function.h> + +static private mapping Shake = ([]); + +// abstract methods +string GetDefiniteShort(); +// end abstract methods + +varargs mixed GetShake(string str){ + if( !str ){ + str = "default"; + } + return Shake[str]; +} + +string array GetShakes(){ + return keys(Shake); +} + +mapping RemoveShake(string item){ + map_delete(Shake, item); + return Shake; +} + +varargs mapping SetShake(mixed key, mixed desc){ + if( !key ){ + key = "default"; + } + if( !desc ){ + if( mapp(key) ){ + Shake = expand_keys(key); + } + else { + Shake["default"] = key; + } + } + else { + Shake[key] = desc; + } + return Shake; +} + +varargs mixed CanShake(object who, string component){ + mixed val; + + if( !component ){ + component = "default"; + } + val = Shake[component]; + if( !val ){ + if( component == "default" ){ + return 0; + } + else { + return "#There is no " + component + " on " + + GetDefiniteShort() + "."; + } + } + else return 1; +} + +varargs mixed eventShake(object who, string component){ + mixed val; + + if( !component ){ + val = Shake["default"]; + } + else { + val = Shake[component]; + } + if( arrayp(val) ){ + val = val[query_night()]; + } + if( stringp(val) ){ + object env; + + env = environment(who); + who->eventPrint(val); + if( component ){ + env->eventPrint(who->GetName() + " shakes the " + component + + " on " + GetDefiniteShort() + ".", who); + } + else { + env->eventPrint(who->GetName() + " shakes " + + GetDefiniteShort() + ".", who); + } + return 1; + } + else { + if( functionp(val) & FP_OWNER_DESTED ){ + return "Error in evaluating functional."; + } + return evaluate(val, who, component); + } +} + +mixed direct_shake_obj(object target){ + return CanShake(this_player()); +} + +mixed direct_shake_str_on_obj(string str, object target){ + return CanShake(this_player(), remove_article(lower_case(str))); +} diff --git a/lib/lib/events/shoot.c b/lib/lib/events/shoot.c new file mode 100644 index 0000000..36036ea --- /dev/null +++ b/lib/lib/events/shoot.c @@ -0,0 +1,82 @@ +static int mustcarry = 1,mustwield = 1; + +int MustCarry(int i){ + if(i) mustcarry = i; + if(mustcarry) return mustcarry; + else return 0; +} + +int MustWield(int i){ + if(i) mustwield = i; + if(mustwield) return mustwield; + else return 0; +} + +varargs mixed eventShoot(object who, mixed target, string dir, string whom){ + string tmp; + if(target && objectp(target)){ + tmp=target->GetName(); + target = tmp; + } + if(target) write("You shoot at "+target+" with your weapon."); + return 1; +} + +mixed CanShoot(object shooter, mixed target){ + object env = environment(this_player()); + if(this_object() == shooter && mustcarry > 0 && environment(this_object()) != this_player()){ + return "#You are not holding the "+remove_article(shooter->GetShort())+"."; + } + if(this_object() == shooter && mustwield > 0 && this_object()->GetWorn() == 0 && !creatorp(this_player())){ + return "#You are not wielding the "+remove_article(shooter->GetShort())+"."; + } + if(env && env->GetProperty("no attack")){ + return "A mystical force prevents your malice."; + } + return 1; +} + +varargs mixed direct_shoot_obj_at_obj(mixed args...){ + mixed ret; + ret = CanShoot(args[0],args[1]); + return CanShoot(args[0],args[1]); +} + +varargs mixed direct_shoot_obj_with_obj(mixed args...){ + return 1; +} + +varargs mixed indirect_shoot_obj_with_obj(mixed args...){ + mixed ret; + ret = CanShoot(args[1],args[0]); + return CanShoot(args[1],args[0]); +} + +varargs mixed indirect_shoot_obj_at_obj(mixed args...){ + return 1; +} + +varargs mixed direct_shoot_obj_at_liv(mixed args...){ + return direct_shoot_obj_at_obj(args...); +} + +varargs mixed direct_shoot_liv_with_obj(mixed args...){ + return direct_shoot_obj_with_obj(args...); +} + +varargs mixed indirect_shoot_liv_with_obj(mixed args...){ + return indirect_shoot_obj_with_obj(args...); +} + +varargs mixed indirect_shoot_obj_at_liv(mixed args...){ + return indirect_shoot_obj_at_obj(args...); +} + +varargs mixed direct_shoot_obj_wrd(mixed args...){ + return direct_shoot_obj_at_obj(args...); +} + +varargs mixed direct_shoot_obj_wrd_at_wrd(mixed args...){ + return direct_shoot_obj_at_obj(args...); +} + diff --git a/lib/lib/events/show.c b/lib/lib/events/show.c new file mode 100644 index 0000000..4ba2897 --- /dev/null +++ b/lib/lib/events/show.c @@ -0,0 +1,17 @@ +mixed indirect_show_liv_obj(object target){ + if( environment() != this_player() ){ + return "#You cannot show what is not yours."; + } + return 1; +} + +mixed direct_show_obj_to_liv(){ + if( environment() != this_player() ){ + return "#You cannot show what is not yours."; + } + return 1; +} + +mixed direct_show_obj_liv(){ + return direct_show_obj_to_liv(); +} diff --git a/lib/lib/events/sink.c b/lib/lib/events/sink.c new file mode 100644 index 0000000..d82ee87 --- /dev/null +++ b/lib/lib/events/sink.c @@ -0,0 +1,59 @@ +#include <position.h> +#include <daemons.h> +#include ROOMS_H +#include <medium.h> +#include <message_class.h> + +int NoSink; + +int SetNoSink(int i){ + return NoSink = i; +} + +int GetNoSink(){ + return NoSink; +} + +mixed eventSink(){ + int err; + string rvoid = ROOMS_D->GetVoid(this_object()); + object env = environment(); + mixed tmprumbo, rumbo = 0; + string name = this_object()->GetName(); + + if(!living(this_object())) name = this_object()->GetShort(); + + if(!env || ( !(rumbo = env->GetExit("down")) && + !(sizeof(rumbo = env->GetSinkRoom())))) return 0; + if(NoSink || env->GetNoSink()) return 0; + if(env == rumbo) return 0; + if(this_object()->GetPosition() == POSITION_SWIMMING){ + return 2; + } + if(living(this_object())) this_object()->SetPosition(POSITION_FLOATING); + if(!rumbo) return 0; + tmprumbo = rumbo; + if(stringp(rumbo)) err = catch(rumbo = load_object(rumbo)); + if(err || !rumbo){ + log_file("runtime","\n"+timestamp()+" "+identify(this_object())+ + " could not load "+identify(rumbo)+" to sink into.\n"); + err = catch(rumbo = load_object(rvoid)); + } + if(err || !rumbo){ + return 0; + } + + tell_object(this_object(),"You sink downward!"); + if(this_object()->eventMove(rumbo)){ + tell_room(env,capitalize(name)+" continues "+ + "to sink.", ({ this_object() })); + tell_room(rumbo,capitalize(name)+" floats in from above.", + ({ this_object() })); + + if(rumbo || sizeof(rumbo->GetSinkRoom())){ + call_out( "eventSink", 2); + } + return 3; + } + return 0; +} diff --git a/lib/lib/events/sit.c b/lib/lib/events/sit.c new file mode 100644 index 0000000..a3606ef --- /dev/null +++ b/lib/lib/events/sit.c @@ -0,0 +1,73 @@ +/* /lib/sit.c + * From the Dead Souls Mud Library + * Handles people sitting down in it + * Created by Descartes of Borg 961221 + * Version: @(#) sit.c 1.1@(#) + * Last modified: 96/12/21 + */ + +#include <position.h> + +private int MaxSitters = 1; +private object array Sitters = ({}); + +int GetMaxSitters(){ + return MaxSitters; +} + +static int SetMaxSitters(int x){ + return (MaxSitters = x); +} + +object array GetSitters(){ + return copy(Sitters); +} + +mixed eventReceiveSit(object who){ + mixed furn = who->GetProperty("furniture"); + if(furn && objectp(furn)){ + write("You are already using a piece of furniture."); + return 1; + } + Sitters = ({ Sitters..., who }); + who->SetProperty("furniture", " on "+this_object()->GetShort()); + who->SetProperty("furniture_object", this_object()); + return 1; +} + +mixed eventReleaseStand(object who){ + Sitters -= ({ who }); + Sitters = filter(Sitters, (: objectp($1) :) ); + if(who) who->RemoveProperty("furniture"); + if(who) who->RemoveProperty("furniture_object"); + return 1; +} + +mixed direct_sit_word_obj(){ + Sitters = filter(Sitters, (: $1 && $1->GetPosition()==POSITION_SITTING :)); + if( sizeof(Sitters) >= MaxSitters ){ + return "There is no room to sit there."; + } + if(environment() != environment(this_player())){ + return "That's not available for sitting right now."; + } + return 1; +} + +mixed direct_sit_down_word_obj(){ + return direct_sit_word_obj(); +} + +int CanGet(object who){ + object *sitters = this_object()->GetSitters(); + if(sizeof(sitters)){ + foreach(object wer in sitters){ + if(!wer || environment(wer) != environment()) this_object()->eventReleaseStand(wer); + } if(sizeof(this_object()->GetSitters())){ + write(this_object()->GetSitters()[0]->GetName()+" is using it right now."); + return 0; + } + else return 1; + } + else return 1; +} diff --git a/lib/lib/events/smell.c b/lib/lib/events/smell.c new file mode 100644 index 0000000..d19d268 --- /dev/null +++ b/lib/lib/events/smell.c @@ -0,0 +1,146 @@ +/* /lib/events/smell.c + * From the Dead Souls Mud Library + * Handles items with smells + * Created by Descartes of Borg 951008 + * Version: @(#) smell.c 1.7@(#) + * Last Modified: 96/12/31 + */ + +#include <function.h> + +static private mixed Smell = 0; +static private mapping Smells = ([]); + +// abstract methods +string GetShort(); +// end abstract methods + +varargs string GetSmell(string str, object who){ + mixed val; + + if( !str || str == "default" ){ + val = Smell; + } + else { + val = Smells[str]; + } + if( !val ){ + return 0; + } + if( functionp(val) ){ + if( functionp(val) & FP_OWNER_DESTED ){ + return "An error occured in a function pointer."; + } + return evaluate(val, who, str); + } + else if( arrayp(val) ){ + return val[query_night()]; + } + else return val; +} + +string array GetSmells(){ + return keys(Smells); +} + +mapping RemoveSmell(string item){ + if( !item || item == "default" ){ + Smell = 0; + } + else { + map_delete(Smells, item); + } + return Smells; +} + +/** + * SetSmell(string description) + * SetSmell(function call_for_description) + * SetSmell(string array day_and_night_descriptions) + * SetSmell(mapping thing_desc_pairs) + * SetSmell(string thing, string|function|string array description) + */ +varargs mixed SetSmell(mixed array args...){ + if( sizeof(args) == 1 ){ + if( mapp(args[0]) ){ + if( args[0]["default"] ){ + Smell = args[0]["default"]; + map_delete(args[0], "default"); + } + return (Smells = expand_keys(args[0])); + } + else { + Smell = args[0]; + } + return args[0]; + } + else if( sizeof(args) == 2 ){ + if( !args[1] ){ + return SetSmell(args[0]); + } + else if( arrayp(args[0]) ){ + foreach(string item in args[0]){ + SetSmell(item, args[1]); + } + return args[1]; + } + else { + if( !args[0] || args[0] == "default" ){ + Smell = args[1]; + return Smell; + } + else { + Smells[args[0]] = args[1]; + return Smells[args[0]]; + } + } + } + else { + error("Wrong number of arguments to SetSmell():\n\t" + "Expected 1 or 2, got " + sizeof(args) + "\n"); + } +} + +varargs mixed eventSmell(object who, string str){ + str = GetSmell(str, who); + if( !str ){ + who->eventPrint("There is nothing to smell."); + return 1; + } + environment(who)->eventPrint(who->GetName() + " smells " + GetShort() + + ".", who); + who->eventPrint(str); + return 1; +} + +mixed direct_smell_obj(){ + if( !Smell ){ + return "You notice no unusual odor."; + } + else { + return 1; + } +} + +mixed direct_smell_str_word_obj(string str){ + str = remove_article(lower_case(str)); + if( !Smells[str] ){ + return "You notice no unusual odor."; + } + else { + return 1; + } +} + +mapping GetSmellMap(){ + mapping Smells = ([]); + foreach(object ob in this_object()->GetDummyItems()){ + if( ob->GetSmell() ){ + Smells[ob->GetId()] = ob->GetSmell(); + } + } + if(this_object()->GetSmell()) Smells["default"] = this_object()->GetSmell(); + return copy(Smells); + +} + diff --git a/lib/lib/events/smoke.c b/lib/lib/events/smoke.c new file mode 100644 index 0000000..4348a43 --- /dev/null +++ b/lib/lib/events/smoke.c @@ -0,0 +1,11 @@ +mixed CanSmoke(object who){ + return 1; +} + +int direct_smoke_obj(object who, object target){ + return CanSmoke(this_player()); +} + +int direct_smoke_from_obj(object who, object target){ + return CanSmoke(this_player()); +} diff --git a/lib/lib/events/stop.c b/lib/lib/events/stop.c new file mode 100644 index 0000000..c908ff3 --- /dev/null +++ b/lib/lib/events/stop.c @@ -0,0 +1,47 @@ +varargs mixed CanStop(object who, string what, mixed args){ + if(who != this_object()) return 0; + if(what == "fishing"){ + int stop_err; + object ob = environment(who); + stop_err = ob->CanStop(this_player(), "fishing"); + return (stop_err || "You aren't fishing!"); + } + if(what == "fighting"){ + mixed *enemies = this_object()->GetEnemies(); + //mixed *hostiles = this_object()->GetHostiles(); + mixed *hostiles = ({}); + if(!sizeof(enemies) && !sizeof(hostiles)){ + return "You're not mad at anybody!"; + } + return 1; + } + return 1; +} + +varargs mixed eventStop(object who, string what, mixed args){ + if(who != this_object()) return 0; + if(what == "fishing"){ + object ob = environment(who); + return ob->eventStop(this_player(), "fishing"); + } + if(what == "fighting"){ + mixed *enemies = this_object()->GetEnemies(); + mixed *hostiles = this_object()->GetHostiles(); + foreach(object enemy in enemies){ + if(!enemy) continue; + write("You are no longer fighting "+enemy->GetShort()+"."); + this_object()->RemoveEnemy(enemy); + } + //foreach(object hostile in hostiles){ + //if(!hostile) continue; + // if(member_array(hostile, enemies) == -1) + // write("You are no longer hostile toward "+hostile->GetShort()+"."); + // this_object()->RemoveEnemy(hostile); + //} + this_object()->AddNonTargets(enemies); + //this_object()->AddNonTargets(hostiles); + return "You have stopped being aggressive."; + } + return 0; +} + diff --git a/lib/lib/events/swim.c b/lib/lib/events/swim.c new file mode 100644 index 0000000..eb98ee1 --- /dev/null +++ b/lib/lib/events/swim.c @@ -0,0 +1,8 @@ +mixed direct_swim_str(string str){ + return 1; +} + +mixed direct_swim_into_str(string str){ + return 1; +} + diff --git a/lib/lib/events/swivel.c b/lib/lib/events/swivel.c new file mode 100644 index 0000000..2117c13 --- /dev/null +++ b/lib/lib/events/swivel.c @@ -0,0 +1,23 @@ +varargs int CanSwivel(mixed who, mixed what){ + return this_player()->CanManipulate(); +} + +mixed direct_swivel_obj(object target){ + return CanSwivel(this_player(), target); +} + +mixed direct_swivel_wrd_obj(object target){ + return CanSwivel(this_player(), target); +} + +mixed direct_swivel_str(string str){ + return CanSwivel(this_player(), remove_article(lower_case(str))); +} + +mixed direct_swivel_str_on_obj(string str, object target){ + return CanSwivel(this_player(), remove_article(lower_case(str))); +} + +varargs mixed eventSwivel(object who, mixed what){ + return 1; +} diff --git a/lib/lib/events/touch.c b/lib/lib/events/touch.c new file mode 100644 index 0000000..6659778 --- /dev/null +++ b/lib/lib/events/touch.c @@ -0,0 +1,131 @@ +/* /lib/touch.c + * from the Dead Souls Mud Library + * for touching things + * created by Descartes of Borg 951008 + * Version: @(#) touch.c 1.8@(#) + * Last modified: 96/12/31 + */ + +#include <function.h> + +static private mixed Touch = 0; +static private mapping Touches = ([]); + +// abstract methods +string GetShort(); +// end abstract methods + +varargs string GetTouch(string str, object who){ + mixed val; + + if( !str || str == "default" ){ + val = Touch; + } + else { + val = Touches[str]; + } + if( !val ){ + return 0; + } + if( functionp(val) ){ + if( functionp(val) & FP_OWNER_DESTED ){ + return "An error occured in a function pointer."; + } + return evaluate(val, who, str); + } + else if( arrayp(val) ){ + return val[query_night()]; + } + else return val; +} + +string array GetTouches(){ + return keys(Touches); +} + +mapping RemoveTouch(string item){ + if( !item || item == "default" ){ + Touch = 0; + } + else { + map_delete(Touches, item); + } + return Touches; +} + +varargs mixed SetTouch(mixed array args...){ + if( sizeof(args) == 1 ){ + if( mapp(args[0]) ){ + if( args[0]["default"] ){ + Touch = args[0]["default"]; + map_delete(args[0], "default"); + } + return (Touches = expand_keys(args[0])); + } + else { + Touch = args[0]; + } + return args[0]; + } + else if( sizeof(args) == 2 ){ + if( !args[1] ){ + return SetTouch(args[0]); + } + else if( arrayp(args[0]) ){ + foreach(string item in args[0]){ + SetTouch(item, args[1]); + } + return args[1]; + } + else { + if( !args[0] || args[0] == "default" ){ + Touch = args[1]; + return Touch; + } + else { + Touches[args[0]] = args[1]; + return Touches[args[0]]; + } + } + } + else { + error("Wrong number of arguments to SetTouch():\n\t" + "Expected 1 or 2, got " + sizeof(args) + "\n"); + } +} + +varargs mixed eventTouch(object who, string str){ + str = GetTouch(str, who); + if( !str ){ + who->eventPrint("There is nothing to touch."); + return 1; + } + environment(who)->eventPrint(who->GetName() + " touches " + GetShort() + + ".", who); + who->eventPrint(str); + return 1; +} + +static void create(){ + Touches = ([]); +} + +mixed direct_touch_obj(){ + if( !Touch ){ + return 0; + } + else { + return 1; + } +} + +mixed direct_touch_str_word_obj(string str){ + str = remove_article(lower_case(str)); + if( !Touches[str] ){ + return 0; + } + else { + return 1; + } +} + diff --git a/lib/lib/events/turn.c b/lib/lib/events/turn.c new file mode 100644 index 0000000..cdfd237 --- /dev/null +++ b/lib/lib/events/turn.c @@ -0,0 +1,76 @@ +mixed eventTurnOn(object ob){ + return "#Please be more specific";; +} + +mixed eventTurnOff(object ob){ + return "#Please be more specific"; +} + +varargs mixed CanTurn(object who, object what){ + return 1; +} + +varargs mixed CanTurnOn(object who, object what){ + return 1; +} + +varargs mixed CanTurnOff(object who, object what){ + return 1; +} + +int eventTurn(object who){ + if(!who) who = this_player(); + return 1; +} + +int direct_turn_obj(object target){ + return CanTurn(this_player()); +} + +int direct_turn_on_obj(object target){ + return CanTurnOn(this_player()); +} + +int direct_turn_on_obj_on_obj(object target, object thinger){ + return CanTurnOn(this_player(), target ); +} + +int indirect_turn_on_obj_on_obj(object thinger, object target){ + return CanTurnOn(this_player(), target ); +} + +int direct_turn_off_obj(object target){ + return CanTurnOff(this_player()); +} + +int direct_turn_off_obj_on_obj(object target, object thinger){ + return CanTurnOff(this_player(), target); +} + +int indirect_turn_off_obj_on_obj(object thinger, object target){ + return CanTurnOff(this_player(), target); +} + +int direct_turn_obj_on(object target){ + return CanTurnOn(this_player()); +} + +int direct_turn_obj_on_obj_on(object target, object thinger){ + return CanTurnOn(this_player(), target ); +} + +int indirect_turn_obj_on_obj_on(object thinger, object target){ + return CanTurnOn(this_player(), target ); +} + +int direct_turn_obj_off(object target){ + return CanTurnOff(this_player()); +} + +int direct_turn_obj_on_obj_off(object target, object thinger){ + return CanTurnOff(this_player(), target ); +} + +int indirect_turn_obj_on_obj_off(object thinger, object target){ + return CanTurnOff(this_player(), target ); +} diff --git a/lib/lib/events/wear.c b/lib/lib/events/wear.c new file mode 100644 index 0000000..f7f9408 --- /dev/null +++ b/lib/lib/events/wear.c @@ -0,0 +1,36 @@ +/* /lib/events/wear.c + * From the Dead Souls Mud Library + * An object that can be worn + * Created by Descartes of Borg 970101 + * Version: @(#) wear.c 1.1@(#) + * Last modified: 97/01/01 + */ + +// abstract methods +string array GetRestrictLimbs(); +mixed CanEquip(object who, string array limbs); +mixed CanUnequip(object who); +// end abstract methods + +mixed direct_remove_obj(){ + + if( environment(this_object()) != this_player() ){ + return "#You don't have that!"; + } + return CanUnequip(this_player()); +} + +mixed direct_wear_obj(){ + if( environment(this_object()) != this_player() ){ + return "#You don't have that!"; + } + return CanEquip(this_player(), GetRestrictLimbs()); +} + +mixed direct_wear_obj_on_str(object target, string str){ + if( environment(this_object()) != this_player() ){ + return "#You don't have that!"; + } + return CanEquip(this_player(), ({ remove_article(lower_case(str)) })); +} + diff --git a/lib/lib/events/wield.c b/lib/lib/events/wield.c new file mode 100644 index 0000000..be6fa66 --- /dev/null +++ b/lib/lib/events/wield.c @@ -0,0 +1,45 @@ +/* /lib/events/wield.c + * From the Dead Souls Mud Library + * Handles the wielding of things + * Created by Descartes of Borg 970101 + * Version: @(#) wield.c 1.1@(#) + * Last modified: 97/01/01 + */ + +// abstract methods +int GetHands(); +mixed CanEquip(object who, string array limbs); +mixed CanUnequip(object who); +// end abstract methods + +mixed direct_unwield_obj(){ + if( environment() != this_player() ){ + return "#You don't have that!"; + } + return CanUnequip(this_player()); +} + +mixed direct_wield_obj(){ + int hands = GetHands(); + string array limbs; + + if( environment() != this_player() ){ + return "#You don't have that!"; + } + limbs = (this_player()->GetWieldingLimbs() || ({})); + limbs = filter(limbs, (: !this_player()->GetWielded($1) :)); + if( !sizeof(limbs) ){ + return "You have nowhere to wield it!"; + } + if( sizeof(limbs) > hands ){ + limbs = limbs[0..(hands-1)]; + } + return CanEquip(this_player(), limbs); +} + +mixed direct_wield_obj_word_str(object target, string wrd, string limb){ + if( environment() != this_player() ){ + return "#You don't have that!"; + } + return CanEquip(this_player(), explode_list(limb)); +} diff --git a/lib/lib/exits.c b/lib/lib/exits.c new file mode 100644 index 0000000..c5084e8 --- /dev/null +++ b/lib/lib/exits.c @@ -0,0 +1,394 @@ +/* /lib/room/exits.c + * from the Dead Souls LPC Library + * handles players exiting from rooms + * created by Descartes of Borg 940711 + * modified for new inheritance structure by Descartes 950208 + * Version: @(#) exits.c 1.12@(#) + * Last Modified: 96/12/23 + */ + +#include <lib.h> +#include ROOMS_H +#include <daemons.h> +#include <position.h> +#include "include/exits.h" + +private static string Obvious, GoMessage, EnterMessage, Dir, Sky; +private static mapping Exits, Doors; + +static void create(){ + Exits = ([]); + Doors = ([]); + Obvious = ""; + Dir = "/" + implode(explode(file_name(), "/")[0..<2], "/"); + GoMessage = "You go nowhere at all.\n"; + EnterMessage = "You can't enter that!\n"; +} + +mixed CanGo(object who, string str){ + int noclip; + if( who->GetParalyzed() ) return "You are unable to move."; + noclip = who->GetProperty("noclip"); + if( !noclip && !Exits[str] && str != "up" && str != "down" && + !(sizeof(this_object()->GetFlyRoom())) && + !(sizeof(this_object()->GetSinkRoom())) ){ + return GoMessage; + } + else return 1; +} + +mixed eventGo(object who, string str){ + int noclip = who->GetProperty("noclip"); + if(query_verb() == "go" && interactive(who) && !noclip){ + if( who->GetPosition() != POSITION_STANDING ){ + write("You are not standing."); + switch(who->GetPosition()){ + case POSITION_LYING : write("Try: crawl "+str);break; + case POSITION_SITTING : write("Try: crawl "+str);break; + case POSITION_KNEELING : write("Try: crawl "+str);break; + case POSITION_FLOATING : write("You are floating.");break; + case POSITION_SWIMMING : write("Try: swim "+str);break; + case POSITION_FLYING : write("Try: fly "+str);break; + } + return 0; + } + } + else if(query_verb() == "crawl"){ + if( who->GetPosition() != POSITION_LYING && + who->GetPosition() != POSITION_KNEELING && + who->GetPosition() != POSITION_SITTING ){ + write("You are not in the correct position for crawling."); + return 0; + } + } + else if(query_verb() == "fly"){ + if( who->GetPosition() != POSITION_FLYING ){ + write("You are not flying."); + return 0; + } + } + else if(query_verb() == "swim"){ + if( who->GetPosition() != POSITION_SWIMMING ){ + write("You are not swimming."); + return 0; + } + } + + if(!noclip && sizeof(Doors) && Doors[str] && Doors[str]->GetClosed() ){ + message("my_action", "You bump into " + + Doors[str]->GetShort(str) + ".", who); + return 1; + } + if(!noclip && Exits[str] && Exits[str]["pre"] && + !(evaluate(Exits[str]["pre"], str)) ) + return 1; + if(!Exits[str]){ + if( str == "up" && sizeof(this_object()->GetFlyRoom())){ + if(noclip || who->GetPosition() == POSITION_FLYING){ + string omsg = who->GetName()+" flies up."; + string imsg = who->GetName()+" flies in."; + who->eventMoveLiving(this_object()->GetFlyRoom(),omsg,imsg,str); + return 1; + } + } + + if(str == "down" && sizeof(this_object()->GetSinkRoom())){ + string omsg = who->GetName()+" sinks down."; + string imsg = who->GetName()+" sinks in."; + who->eventMoveLiving(this_object()->GetSinkRoom(),omsg,imsg,str); + return 1; + } + if(!noclip){ + write("You can't go that way."); + return 0; + } + } + if(Exits[str] && Exits[str]["room"]){ + who->eventMoveLiving(Exits[str]["room"],0,0,str); + if( Exits[str]["post"] ) evaluate(Exits[str]["post"], str); + return 1; + } + if(noclip){ + int moved; + string ndest = ROOMS_D->GetDirectionRoom(this_object(),str,1); + if(!ndest){ + write("You cannot noclip in that direction."); + } + moved = who->eventMoveLiving(ndest,0,0,str); + if(base_name(environment(who)) != ndest){ + write("You fail to noclip in that direction."); + } + return 1; + } + return 0; +} + +mixed GetDoor(string dir){ + if(sizeof(Doors)) return Doors[dir]; + else return 0; +} + +string array GetDoors(){ + return keys(Doors); +} + +mapping GetDoorsMap(){ + return copy(Doors); +} + +string SetDoor(string dir, string file){ + object ob = GetDummyItem(dir); + + if( ob ){ + ob->SetDoor(file); + } + + if(!unguarded( (: file_exists($(file)) :) ) && + !unguarded( (: file_exists($(file)+".c") :) )){ + return "Door not found."; + } + file->eventRegisterSide(dir); + return (Doors[dir] = file); +} + +varargs string CreateDoor(string dir, string odir, string long, string locked, string key){ + object new_door = new(LIB_DOOR); + string doorfile = file_name(new_door); + object ob = GetDummyItem(dir); + if(!locked) locked = ""; + if( ob ){ + ob->SetDoor(doorfile); + } + new_door->SetSide(dir, ([ "id" : ({"door", dir+" door", long}), "short" : "a door leading "+dir, "long" : long, "lockable" : 1 ])); + new_door->SetSide(odir, ([ "id" : ({"door", odir+" door", long}), "short" : "a door leading "+odir, "long" : long, "lockable" : 1 ])); + if(key) new_door->SetKeys(dir, ({ key }) ); + if(key) new_door->SetKeys(odir, ({ key }) ); + new_door->eventRegisterSide(dir); + return (Doors[dir] = doorfile); +} + +string GetDirection(string dest){ + foreach(string dir, mapping data in Exits){ + if( data["room"] == dest ){ + return "go " + dir; + } + } + foreach(string dir in GetEnters()){ + string data = GetEnter(dir); + + if(data && data == dest ){ + return "enter " + dir; + } + } + return 0; +} + +object GetDummyItem(mixed id){ + int i; + object array dummies,all_inv; + + all_inv=all_inventory(); + dummies = ({}); + + for(i=0; i<sizeof(all_inv); i++){ + if ( all_inv[i]->isDummy() ) dummies += ({ all_inv[i] }); + } + if( stringp(id) ){ + id = ({ id }); + } + if(arrayp(id)){ + foreach(object dummy in dummies){ + foreach(string element in id){ + if(answers_to(element,dummy)) return dummy; + } + } + } + return 0; +} + +varargs void AddEnter(string dir, string dest, function pre, function post){ + object ob = GetDummyItem(dir); + + ob->SetEnter(dest, pre, post); +} + +string GetEnter(string dir){ + object ob = GetDummyItem(dir); + + if( !ob ){ + return 0; + } + else { + return ob->GetEnter(); + } +} + +static mapping GetEnterData(string dir){ + object ob = GetDummyItem(dir); + + if( !ob ){ + return 0; + } + else { + return ob->GetEnterData(); + } +} + +varargs string array GetEnters(int i){ + object *obs; + string *ids; + + obs = ({}); + ids = ({}); + + foreach(object item in all_inventory(this_object())){ + if(item->isDummy()){ + obs += ({ item }); + } + } + + foreach(object ob in obs){ + if( ob->GetEnter() ){ + if(i) ids += ({ ob->GetKeyName() }); + else ids += ob->GetId(); + } + } + return ids; +} + +mapping GetEnterMap(){ + mixed schlussel; + mapping EnterMap = ([]); + object *obs = ({}); + foreach(object item in all_inventory(this_object())){ + if(item->isDummy()){ + obs += ({ item }); + } + } + if(!sizeof(obs)) return ([]); + foreach(object ob in obs){ + if( ob->GetEnter() ){ + schlussel = ob->GetId(); + EnterMap[schlussel] = ob->GetEnter(); + } + } + return copy(EnterMap); +} + +void RemoveEnter(string dir){ + object ob = GetDummyItem(dir); + + ob->SetEnter(0); +} + +void SetEnters(mapping mp){ + foreach(mixed dir, mixed room_or_arr in mp){ + object ob = GetDummyItem(dir); + if(!ob) continue; + + if( arrayp(room_or_arr) ){ + ob->SetEnter(room_or_arr...); + } + else { + ob->SetEnter(room_or_arr); + } + } +} + +string GetEnterMessage(){ + return EnterMessage[0..<2]; +} + +string SetEnterMessage(string str){ + return (EnterMessage = str + "\n"); +} + +varargs mapping AddExit(string dir, string dest, function pre, function post){ + if(!stringp(dir)) error("Bad argument 1 to AddExit().\n"); + if(!stringp(dest)) error("Bad argument 2 to AddExit().\n"); + dest = ResolveObjectName(dest); + Exits[dir] = ([ "room" : dest ]); + if( functionp(pre) ) Exits[dir]["pre"] = pre; + if( functionp(post) ) Exits[dir]["post"] = post; + return Exits[dir]; +} + +string GetExit(string str){ + if(!Exits[str]) return 0; + else return Exits[str]["room"]; +} + +mapping GetExitData(string str){ + return Exits[str]; +} + +mapping GetFullExitData(){ + return Exits; +} + +mapping GetExitMap(){ + mapping ret = ([]); + foreach(string key in keys(Exits)){ + ret[key] = Exits[key]["room"]; + } + + return ret; +} + +string array GetExits(){ + return keys(Exits); +} + +mapping RemoveExit(string dir){ + if(Exits[dir]) map_delete(Exits, dir); +} + +mapping SetExits(mapping mp){ + mixed room_or_arr, dir; + + Exits = ([]); + foreach(dir, room_or_arr in mp){ + if( arrayp(dir) ){ + string real_dir; + + foreach(real_dir in dir){ + if( arrayp(room_or_arr) ) AddExit(real_dir, room_or_arr...); + else AddExit(real_dir, room_or_arr); + } + } + else { + if( stringp(room_or_arr) ) AddExit(dir, room_or_arr); + else if( arrayp(room_or_arr) ) AddExit(dir, room_or_arr...); + } + } + return Exits; +} + +string GetGoMessage(){ + return GoMessage[0..<2]; +} + +string SetGoMessage(string str){ + return (GoMessage = str + "\n"); +} + +string GetObviousExits(){ + return Obvious; +} + +string SetObviousExits(string str){ + return (Obvious = str); +} + +string GetSky(){ + return Sky; +} + +string SetSky(string str){ + return (Sky = str); +} + +string ResolveObjectName(string file){ + if( file[<2..] == ".c" ) file = file[0..<3]; + return absolute_path(Dir, file); +} diff --git a/lib/lib/files.c b/lib/lib/files.c new file mode 100644 index 0000000..55adcf9 --- /dev/null +++ b/lib/lib/files.c @@ -0,0 +1,38 @@ +/* /lib/user/files.c + * from Dead Souls + * returns all files matching a wildcard expression + * created by someone at Portals a long time ago + */ + + +#include <dirs.h> +#include "include/files.h" + +#if 0 +string *wild_card(string str){ + mixed pf; + string *tmp; + string cwd; + int i, maxi; + + if((cwd = absolute_path(query_cwd(), str)) == "/") return ({ "/" }); + if(cwd[sizeof(cwd) - 1] == '/') cwd = cwd[0..sizeof(cwd) - 2]; + if((pf = path_file(cwd)) == "/") pf[0] = ""; + if(!(tmp = get_dir(cwd))) tmp = ({}); + tmp -= ({ "." }); + tmp -= ({ ".." }); + if(!str || str[0] != '.') + tmp = filter(tmp, "remove_dots", this_object()); + for(i=0, maxi = sizeof(tmp); i < maxi; i++){ + if(file_size(sprintf("%s/%s", pf[0], pf[1])) == -2) tmp[i] = pf[0]; + else tmp[i] = sprintf("%s/%s", pf[0], tmp[i]); + if(strlen(tmp[i]) > 1 && tmp[i][0..1] == "//") + tmp[i] = tmp[i][1..strlen(tmp[i])-1]; + } + return tmp; +} + +nomask static int remove_dots(string str){ return !(str[0] == '.'); } +#endif + +string query_cwd(){ return DIR_TMP; } diff --git a/lib/lib/firearm.c b/lib/lib/firearm.c new file mode 100644 index 0000000..b82b663 --- /dev/null +++ b/lib/lib/firearm.c @@ -0,0 +1,500 @@ +#include "include/firearm.h" +#include <lib.h> +#include <damage_types.h> +#include <dirs.h> +inherit LIB_STORAGE; +inherit LIB_LOAD; + +private int MaxAmmo, Millimeter, AmmoSize; +private string FirearmType, AmmoType; +private string AmmoFile, firearm_name; +private float Caliber; +private string *namen; +private string *ammonamen; +private int loaded, rounds; +private int shells, magnum; +private int mag,cloned; +private int autohit; +private int dam, last_shot; + +static void create(){ + string *s_save, *a_save; + + ::create(); + + s_save = storage::GetSave(); + a_save = s_save; + + AddSave( a_save ); + AddSave( ({ "loaded", "rounds", "shells" , "mag" , "cloned" }) ); + MaxAmmo=6; + AmmoFile="/domains/default/obj/round"; + FirearmType="revolver"; + AmmoType="round"; + loaded=1; + rounds=0; +} + +void init(){ + object ob; + object *inv; + ::init(); + this_object()->CalculateAmmoSize(); + namen=this_object()->GetId(); + if(FirearmType=="revolver" + && !present("cylinder",this_object())){ + new("/lib/cylinder")->eventMove(this_object()); + } + if(FirearmType=="revolver" && !cloned){ + cloned=1; + ob=present("cylinder", this_object()); + inv=all_inventory(ob); + filter(inv, (: this_object()->InitRevolver($1->GetId()) :) ); + } + if(FirearmType=="auto" && !present("clip",this_object()) ){ + mag=0; + loaded=0; + rounds=0; + } +} + +string SetFirearmName(string str){ + if(str) firearm_name = str; + return firearm_name; +} + +string GetFirearmName(){ + if(firearm_name) return firearm_name; + return GetKeyName(); +} + +int InitRevolver(string *arr){ + if(member_array("round",arr) != -1){ + rounds++; + return 1; + } + if(member_array("shell",arr) != -1){ + shells++; + return 1; + } +} +mixed CanGetFrom(object who, object item){ + return "It doesn't work that way. Try unloading it."; +} + +mixed CanPutInto(object who, object what){ + return "It doesn't work that way. Try loading the "+GetFirearmName()+" with something."; +} + +int CanReceive(object ob){ + string *idarray; + if(FirearmType=="revolver"){ + if(rounds == MaxAmmo){ + write("It is already fully loaded."); + return 1; + } + } + if(FirearmType != "auto" && ob->GetKeyName() != "revolver cylinder"){ + write("This "+GetFirearmName()+" only receives bullets."); + return 0; + } + idarray=ob->GetId(); + if(FirearmType=="auto" && member_array("magazine",idarray) == -1){ + write("This "+GetFirearmName()+" only receives ammunition clips."); + return 0; + } + if(FirearmType=="auto" && ob->GetMillimeter() != this_object()->GetMillimeter() ){ + write("That is not the correct ammunition clip size."); + return 0; + } + if(FirearmType=="auto" && ob->GetCaliber() != this_object()->GetCaliber() ){ + write("That is not the correct ammunition clip caliber."); + return 0; + } + if(FirearmType=="auto" && ob->GetAmmoType() != this_object()->GetAmmoType() ){ + write("That is not the correct ammunition clip type."); + return 0; + } + if(FirearmType=="auto" && mag){ + write("The "+GetFirearmName()+" is already loaded."); + return 0; + } + if(FirearmType=="auto"){ + mag=1; + rounds=sizeof(all_inventory(ob)); + } + return 1; +} +int CanRelease(object ob){ + if(ob->GetKeyName()=="revolver cylinder"){ + return 0; + + } + return 1; +} + +varargs mixed eventShoot(object ob, mixed target, string dir, string whom){ + object cible; + object shell; + object *obs; + + if(!target || dir){ + write("You can't shoot that way with this weapon."); + return 1; + } + + if(objectp(target)){ + cible = target; + } + else { + obs = filter(get_livings(environment(this_player())), + (: answers_to($(target), $1) :)); + if(!sizeof(obs)) cible = present(target,environment(this_player())); + else cible = obs[0]; + } + if(cible) target = cible->GetName(); + + else { + write("It seems there's a problem targeting "+target+"."); + return 1; + } + + if(!rounds || rounds == 0){ + write("Your weapon is not loaded.\n"); + say(environment(this_object())->GetName()+" tries to shoot "+capitalize(target)+" with an unloaded weapon.\n"); + return 1; + } + write("You shoot at "+capitalize(target)+"!\n"); + say(environment(this_object())->GetName()+" shoots at "+capitalize(target)+"!\n"); + if(cible) tell_object(cible, environment(this_object())->GetName()+ + " shoots at you!\n"); + this_object()->eventFire(target); + if(FirearmType=="auto"){ + shell = new(LIB_SHELL); + if(!shell) return 1; + shell->SetFirearmType(GetFirearmType()); + shell->SetCaliber(GetCaliber()); + shell->eventMove(environment(environment(this_object()))); + } + return 1; +} + +int eventFire(mixed str){ + object ob; + object *obs; + int tempclass, i, dex; + int TorsoNum, NumLimbs; + mixed dexmap; + string tempshort,templong; + string *limbarr; + int limbhit; + string limbname; + string s1,s2; + rounds--; + if(this_object()->GetFirearmType() == "auto"){ + if(first_inventory(present("magazine",this_object())) ){ + first_inventory(present("magazine",this_object()))->eventDestruct(); + present("magazine",this_object())->MinusAmmo(1); + } + else rounds=0; + } + if(this_object()->GetFirearmType() == "revolver"){ + shells++; + ob=present("cylinder",this_object()); + if(present("round",ob)) present("round",ob)->eventDestruct(); + new("/lib/shell")->eventMove(ob); + } + if(rounds <= 0) loaded=0; + ob = 0; + if(objectp(str)) ob = str; + else obs = filter(get_livings(environment(this_player())), + (: answers_to($(str), $1) :)); + if(!ob && !sizeof(obs)) ob = present(str,environment(this_player())); + else if(!ob) ob = obs[0]; + if(creatorp(ob)){ + write(ob->GetName()+" catches your bullet in "+possessive(ob)+" teeth.\n"); + say(ob->GetName()+" catches the bullet in "+possessive(ob)+" teeth.\n"); + autohit=0; + return 1; + } + if(ob && !living(ob) && base_name(ob) != LIB_CORPSE){ + tell_room(environment(environment(this_object())), + "The bullet smashes into "+lower_case(ob->GetShort())+"!\n"); + if(!sscanf(ob->GetLong(),"%sIt has been damaged by gun%s",s1,s2)){ + tempclass=ob->GetClass(); + if(tempclass) ob->SetClass(tempclass/2); + tempshort=ob->GetShort(); + tempshort = "a damaged "+remove_article(tempshort); + ob->SetShort(tempshort); + templong=ob->GetLong(); + if(sscanf(templong,"%s\n\n%s",s1,s2) >=1){ + templong=s1+" It has been damaged by gunfire.\n\n"; + } + else + templong += " It has been damaged by gunfire."; + ob->SetLong(templong); + return 1; + } + tempclass=ob->GetClass(); + if(tempclass) ob->SetClass(tempclass/2); + return 1; + } + i = random(100); + if(!creatorp(environment())){ + dex = environment(this_object())->GetStatLevel("coordination"); + dex += (environment(this_object())->GetStatLevel("luck") / 3); + if(environment(this_object())->GetSkillLevel("firearms") < 10){ + int now = time(); + if(last_shot == now) dex -= 100; + else if((now - last_shot) < 2) dex -= 50; + } + } + else dex = 200; + last_shot = time(); + if((ob && living(ob)) && (i < dex || autohit==1)){ + if(random(2)) limbname = ob->GetTorso(); + else limbname = scramble_array(ob->GetLimbs())[0]; + tell_room(environment(environment(this_object())),"The bullet smashes into "+ + capitalize(str)+"'s "+limbname+"!\n",ob); + tell_object(ob,"The bullet smashes into your "+limbname+"!\n"); + ob->AddLead("gunshot_wounds", 1); + ob->SetAttack(this_agent()); + if(!present("firearms_wound",ob)){ + new(LIB_WOUND)->eventMove(ob); + } + if(Caliber){ + float tmp; + int extradam = this_object()->GetMagnum(); + if(to_float(Caliber) < 1.00) Caliber = to_float(Caliber) * 100.00; + if(Caliber > 99) tmp = to_float(Caliber) * 0.10; + dam = to_int(tmp); + if(extradam) dam += (random(extradam/2) + extradam/2); + } + if(Millimeter){ + dam = Millimeter; + dam *= random(10); + } + if(!dam) dam = 7; + + dam += random(environment(this_object())->GetStatLevel("coordination")); + dam += environment(this_object())->GetSkillLevel("projectile attack"); + dam -= random(ob->GetStatLevel("luck")); + dam -= random(ob->GetSkillLevel("projectile defense")); + + if(creatorp(this_player())) write("you do "+dam+" points of damage"); + + ob->eventReceiveDamage(environment(this_object()),(PIERCE), dam, 0, limbname); + if(!ob->GetInCombat()){ + ob->eventForce("attack "+environment(this_object())->GetKeyName()); + } + autohit=0; + return 1; + } + write("Your shot misses its mark.\n"); + say(environment(this_object())->GetName()+"'s shot misses its mark.\n"); + this_object()->missed_shot(); + return 1; +} + +int missed_shot(){ + object ob,maghere,magstuff; + string str; + int i; + object *inv; + string *arr; + if(environment(environment(this_object()))->GetClimate() != "indoors"){ + return 1; + } + inv=all_inventory(environment(environment(this_object()))); + i=random(sizeof(inv)); + if(living(inv[i])){ + tell_room(environment(environment(this_object())), inv[i]->GetName()+" is struck "+ + "by the stray bullet!",inv[i]); + tell_object(inv[i],"You are struck by a stray bullet from "+environment(this_object())->GetName()+ + "'s gun.\n"); + } + if(!living(inv[i])){ + string shortd = (inv[i]->GetShort() || ""); + arr=explode(inv[i]->GetKeyName(),""); + if(sizeof(arr) && arr[sizeof(arr)-1] =="s"){ + tell_room(environment(environment(this_object())), + capitalize(shortd)+" are struck by the stray bullet."); + } + else + tell_room(environment(environment(this_object())), + capitalize(shortd)+" is struck by the stray bullet."); + } + autohit=1; + rounds++; + this_object()->eventFire(inv[i]->GetKeyName()); + if(this_object()->GetFirearmType() == "revolver"){ + shells--; + present("shell",present("cylinder",this_object()))->eventDestruct(); + ob=new("/lib/round"); + ob->SetCaliber(this_object()->GetCaliber()); + ob->SetMillimeter(this_object()->GetMillimeter()); + ob->SetFirearmType(this_object()->GetFirearmType()); + ob->SetAmmoType(this_object()->GetAmmoType()); + ob->eventMove(present("cylinder",this_object())); + } + else + { + str = ""; + maghere=present("magazine",this_object()); + if(maghere) magstuff = first_inventory(maghere); + if(maghere && magstuff) str=base_name(magstuff); + if(str && str !="" ) new(str)->eventMove(maghere); + } + return 1; +} +int CalculateAmmoSize(){ + float i; + i=this_object()->GetCaliber(); + if(i > 0){ + if(stringp(i)) sscanf(i,"%d",i); + if(intp(i)) to_float(i); + while(i > 1.0){ + i = i*(0.1); + } + i = i*(25.4); + AmmoSize=to_int(i); + dam=AmmoSize*(AmmoSize); + dam *= 3; + return 1; + } + AmmoSize=this_object()->GetMillimeter(); + return 1; +} +int ShowRounds(){ environment(this_object())->eventPrint("Firearm has: "+rounds+" rounds.\n"); + environment(this_object())->eventPrint("Firearm has: "+shells+" shells.\n"); + return 1; +} +int SetAmmo(int i){ rounds=i; return 1; } +int GetAmmo(){ return rounds; } +int GetMag(){ return mag; } +int SetMag(int i){ mag=i; return 1; } +int SetLoaded(int i){ loaded=i; return 1; } +int GetLive(){ return loaded; } +int SetAmmoFile(string str){ AmmoFile=str; return 1; } +int SetAmmoType(string str){ AmmoType=str; return 1; } +int SetFirearmType(string str){ FirearmType=str; return 1; } +int SetMaxAmmo(int x){ MaxAmmo=x; return 1; } +int SetCaliber(int x){ Caliber=x; return 1; } +int SetMillimeter(int x){ Millimeter=x; return 1; } +string GetAmmoType(){ return AmmoType; } +string GetFirearmType(){ return FirearmType; } +int GetMaxAmmo(){ return MaxAmmo; } +int GetCaliber(){ return Caliber; } +int GetMillimeter(){ return Millimeter; } + +mixed eventLoad(object ob){ + mixed can = CanLoad(this_player()); + if(!can || !intp(can)) return 0; + if(!ob || !objectp(ob) || (objectp(ob) && living(ob))){ + write("Load "+GetKeyName()+" with what?"); + return 1; + } + if(GetFirearmType() == "revolver" && ob && objectp(ob) && + ob->GetFirearmType() == "revolver" && (base_name(ob) == LIB_ROUND || + inherits(LIB_ROUND,ob)) && ob->GetCaliber() == GetCaliber() && + rounds != MaxAmmo){ + rounds++; + } + return 1; +} + +mixed eventUnload(mixed what){ + string n1,s1,s2; + int n2; + mixed can = CanUnload(this_player()); + if(!can || !intp(can)) return 0; + + if(FirearmType=="auto" && !mag){ + write("It's already unloaded."); + return 1; + } + if(mag==1 && environment(this_object()) == this_player()){ + this_object()->doMagUnload(); + return 1; + } + if(FirearmType=="revolver" && + environment(this_object()) == this_player()){ + if(rounds == 0 && shells == 0){ + write("Your "+GetFirearmName()+" is already empty."); + return 1; + } + if(intp(what) && what < 7 && what > 0) true(); + else what = "all"; + write("You unload your "+GetFirearmName()+"."); + this_object()->doRevolverUnload("all",what); + return 1; + } +} + +int doMagUnload(){ + if(!present("clip",this_object())){ + write("The "+GetFirearmName()+" is already empty."); + return 0; + } + write("You unload an ammo clip from your "+GetFirearmName()+"."); + say(this_player()->GetName()+" unloads an ammo clip from "+possessive(this_player())+" "+GetFirearmName()+"."); + present("clip",this_object())->eventMove(environment(this_object())); + mag=0; + loaded=0; + rounds=0; + return 1; +} + +int doRevolverUnload(string what, string num){ + int i,n1,n2; + if(sscanf(num,"%d",n1)){ + } + if(what=="all"){ + n1=shells; + n2=rounds; + } + if(what=="shells" || what=="all"){ + i=shells-n1; + while(shells > i){ + present("shell",present("revolver cylinder",this_object()))->eventMove(environment(this_object())); + shells--; + } + } + if(what=="rounds" || what=="all"){ + if(what != "all") n2=n1; + i=rounds-n2; + while(rounds > i){ + present("round",present("revolver cylinder",this_object()))->eventMove(environment(this_object())); + rounds--; + } + } + if(n2 > 0){ + string things = "rounds"; + if(n2 == 1) things = "round"; + write("You unload "+cardinal(n2)+" "+things+" from your "+GetFirearmName()+"."); + } + if(n1 > 0){ + string things = "shells"; + if(n1 == 1) things = "shell"; + write("You unload "+cardinal(n1)+" "+things+" from your "+GetFirearmName()+"."); + } + say(environment(this_object())->GetName()+" unloads some cartridges from "+ + possessive(environment(this_object()))+" revolver."); + return 1; +} + +int GetMaxLoaded(){ + if(rounds + shells >= MaxAmmo) return 1; + return 0; +} + +int GetMagnum(){ + return magnum; +} + +int SetMagnum(int i){ + if(i > 0) magnum = i; + else magnum = 0; + return magnum; +} + diff --git a/lib/lib/fish.c b/lib/lib/fish.c new file mode 100644 index 0000000..bd170dd --- /dev/null +++ b/lib/lib/fish.c @@ -0,0 +1,30 @@ +/* /lib/fish.c + * from the Dead Souls Object Library + * fish objects which get caught + * created by Descartes of Borg 951009 + */ + + +#include <lib.h> +#include "include/fish.h" + +inherit LIB_MEAL; + +static private int Fight; +static private string Food; + +static void create(){ + meal::create(); + Food = 0; + Fight = 0; +} + +int eventCatch(object who){ return 1; } + +int SetFight(int x){ return (Fight = x); } + +int GetFight(){ return Fight; } + +string SetFood(string str){ return (Food = str); } + +string GetFood(){ return Food; } diff --git a/lib/lib/fishing.c b/lib/lib/fishing.c new file mode 100644 index 0000000..788d89d --- /dev/null +++ b/lib/lib/fishing.c @@ -0,0 +1,219 @@ +/* /lib/fishing.c + * from the Dead Souls LPC Library + * a room which allows fishing in it + * created by Descartes of Borg 950529 + * Version: @(#) fishing.c 1.7@(#) + * Last modified: 96/10/30 + */ + +#include <lib.h> +#include "include/fishing.h" + +inherit LIB_ROOM; + +static private int MaxFishing, Speed, Chance, fishing_counter; +static private mapping Fishing, Fish; + +static void create(){ + room::create(); + MaxFishing = 10; + Speed = 10; + Chance = 0; + fishing_counter = 0; + Fish = ([]); + Fishing = ([]); +} + +void heart_beat(){ + mapping tmp; + object pole; + string fisher; + + room::CheckActions(); + + fishing_counter++; + if(fishing_counter < Speed) return; + fishing_counter = 0; + + if( !sizeof(Fishing) ){ + return; + } + tmp = Fishing; + Fishing = ([]); + foreach(fisher, pole in tmp){ + object ob; + + if( !fisher ) continue; + if( !(ob = present(fisher)) || !living(ob) || !pole ) continue; + if( !present(pole, ob) ) continue; + if( pole->GetBroken() ) continue; + if( (object)ob->GetInCombat() ){ + message("my_action", "You are no longer fishing.", ob); + RemoveFishing(ob); + continue; + } + if( (object)ob->GetSleeping() ){ + message("my_action", "You are no longer fishing.", ob); + RemoveFishing(ob); + continue; + } + Fishing[fisher] = pole; + } + if( !sizeof(Fishing) ){ + return; + } + foreach(fisher, pole in Fishing){ + object who; + string fish; + int chance, x, y, i; + int pro; + + who = present(fisher, this_object()); + /* if this room is impossible to fish, or if using a non-fishing + * device, no fishing can really occur + */ + if( !Chance || !(x = pole->eventFish(who)) ) chance = 0; + else { + pro = (Chance + x + who->GetStatLevel("luck"))/3; + chance = (Chance + x + who->GetStatLevel("luck")) / + (1 + random(5)); + } + /* Give extra weight to fishing skill */ + if( chance ){ + if(!sizeof(who->GetSkill( "fishing" ))){ + who->AddSkill("fishing", 2, 1); + } + chance = random(chance/2 + who->GetSkillLevel("fishing")/2); + } + y = 0; + foreach(fish, x in Fish) y += x; + y = random(y); + if( y < 1 || chance <= random(100) ){ + who->eventTrainSkill("fishing", pro, 100-Chance/(y+1), 0); + send_messages("cast", "$agent_name $agent_verb again, hoping " + "for better luck.", who, 0, this_object()); + continue; + } + i = 0; + foreach(fish, x in Fish){ + i += x; + if( x >= y ) break; + } + who->eventTrainSkill("fishing", pro, (100-Chance)/(i+1), 1); + send_messages("struggle", "$agent_name $agent_verb with " + "something on $agent_possessive " + + pole->GetKeyName() + ".", who, 0, this_object()); + Fish[fish]--; + call_out( (: eventCatch, who, fish, pole :), 1 ); + } +} + +mixed CanCast(object who, string where){ + if( this_player()->GetInCombat() ) + return "You are too busy to fish!"; + if( Fishing[this_player()->GetKeyName()] ) + return "You are already fishing!"; + if( GetMaxFishing() <= sizeof(Fishing) ) + return "It is too crowded here to fish."; + return 1; +} + +mixed CanStop(object who, string str){ + if( str != "fishing" ) return 0; + str = this_player()->GetKeyName(); + if( !Fishing[str] ) return "You are not fishing!"; + return 1; +} + +int CanRelease(object who){ + if(room::CanRelease()) RemoveFishing(who); + return 1; +} + +mixed eventCast(object who, object pole, string str){ + send_messages(({ "cast", "start" }), + "$agent_name $agent_verb $agent_possessive " + + pole->GetKeyName() + " and $agent_verb fishing.", who, 0, + this_object()); + SetFishing(who, pole); + return 1; +} + +static void eventCatch(object who, string fish, object pole){ + object food; + + if( !who || !present(who) ) return; + if( !pole || !present(pole, who) ){ + message("my_action", "Having given up " + pole->GetShort() + + ", you lose your catch!", who); + return; + } + if( !(pole->eventCatch(who, fish)) ) return; + food=new(fish); + RemoveFishing(who); + who->AddSkillPoints("fishing", fish->GetFight()+fish->GetMass()); + message("my_action", "You find " + fish->GetShort() + " on " + + pole->GetShort() + "!", who); + message("other_action", who->GetName() + " finds " + + fish->GetShort() + " on " + pole->GetShort() + + "!", this_object(), ({ who })); + if( !(food->eventMove(who)) ){ + message("my_action", "You drop " + food->GetShort() + "!", + who); + message("other_action", who->GetName() + " drops " + + food->GetShort() + "!", this_object(), ({ who }) ); + food->eventMove(this_object()); + } +} + +mixed eventStop(object who, string str){ + RemoveFishing(this_player()); + message("my_action", "You stop fishing.", who); + message("other_action", who->GetName() + " stops " + "fishing.", this_object(), ({ who }) ); + return 1; +} + +int SetChance(int x){ return (Chance = x); } + +int GetChance(){ return Chance; } + +mapping SetFish(mapping mp){ return (Fish = mp); } + +int AddFish(string fish, int x){ + if( !Fish[fish] ) Fish[fish] = x; + else Fish[fish] += x; + return Fish[fish]; +} + +mapping RemoveFish(string fish){ + if( Fish[fish] ) map_delete(Fish, fish); + return Fish; +} + +mapping GetFish(){ return Fish; } + +mapping SetFishing(object who, object pole){ + if( !living(who) ) return Fishing; + if( !query_heart_beat() ) set_heart_beat(1); + Fishing[who->GetKeyName()] = pole; + return Fishing; +} + +mapping RemoveFishing(object who){ + string str; + + if( !who || !objectp(who) || !living(who) ) return Fishing; + if( Fishing[(str = who->GetKeyName())] ) + map_delete(Fishing, str); + if( !sizeof(Fishing) ) return ([]); + return Fishing; +} + +int SetMaxFishing(int x){ return (MaxFishing = x); } + +int GetMaxFishing(){ return MaxFishing; } + +int SetSpeed(int x){ return (Speed = x); } + +int GetSpeed(){ return Speed; } diff --git a/lib/lib/flashlight.c b/lib/lib/flashlight.c new file mode 100644 index 0000000..f5d40d8 --- /dev/null +++ b/lib/lib/flashlight.c @@ -0,0 +1,227 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_STORAGE; +inherit LIB_TURN; + +void SetLightLevel(int i); +int eventRadiate(int i); + +object player,env,fl; +string me,name, celltype, baseshort; +int noflicker,Lit,lightlevel,drainrate,powered,level; +int mincells, maxcells; + +void create(){ + ::create(); + SetKeyName("generic flashlight"); + SetId( ({"fl","flashlight","light","torch","flashlite"}) ); + SetAdjectives( ({"generic","simple","cheap"}) ); + SetShort( "a flashlight" ); + SetLong("This is a cheap, simple light source."); + SetMass(20); + SetBaseCost(10); + SetLightLevel(6); + Lit=0; + mincells = 2; + maxcells = 2; + celltype = "D"; + SetVendorType(VT_TREASURE); + baseshort=GetShort(); +} + +string GetShort(){ + string ret, str, article; + string litstr = "%^BOLD%^YELLOW%^(lit)%^RESET%^ "; + if(!Lit || query_verb() == "activate" || query_verb() == "turn"){ + return ::GetShort(); + } + if(!(str = ::GetShort()) || str == "") return str; + article = (replace_string(str, remove_article(str), "") || ""); + str = remove_article(str); + ret = (sizeof(article) ? article : "") + litstr + str; + return ret; +} + +void init(){ + ::init(); + fl=this_object(); + me=this_object()->GetKeyName(); +} + +int SetHB(int i){ + set_heart_beat(i); + return query_heart_beat(); +} +int GetHB(){ + return query_heart_beat(); +} + +int SetMaxCells(int i){ maxcells = i; return i; } +int GetMaxCells(){ return maxcells; } +int SetMinCells(int i){ mincells = i; return i; } +int GetMinCells(){ return mincells; } +int SetCellType(string str){celltype=str; return 1; } +string GetCellType(){ return celltype; } + +int SetDrainRate(int i){ + drainrate = i; + return i; +} + +varargs int eventUse(mixed i, mixed foo){ + if(query_verb() == "use"){ + write("That's not how it works."); + return 1; + } + Lit = i; + foreach(object ob in all_inventory(this_object())){ + ob->eventUse(i); + } + return i; +} + +int eventDie(){ + if(!Lit || Lit == 0) return 1; + Lit=0; + eventRadiate(0); + foreach(object ob in all_inventory(this_object())){ + ob->eventUse(0); + } + //SetShort(baseshort); + tell_object(environment(this_object()),"The "+me+" flickers and dies."); + if(living(environment())){ + tell_room(environment(environment()),environment()->GetName()+"'s "+me+ + " flickers and dies.",({ environment() }) ); + } + set_heart_beat(0); + return 1; +} + +int flicker(){ + if(noflicker ==1) return 0; + if(!living(environment())){ + tell_object(environment(),capitalize(baseshort)+" flickers and shines less brightly than before."); + return 1; + } + tell_room(environment(environment()),environment()->GetName()+"'s "+me+ + " flickers and shines less brightly than before.",({ environment() }) ); + tell_object(environment(),"The "+me+" flickers and shines less brightly."); + return 1; +} + +int CheckPower(){ + object *batts; + powered = 1; + if( sizeof(all_inventory(this_object())) < mincells ) powered = 0; + batts = all_inventory(this_object()); + foreach(object batt in batts){ + batt->Spent(); + level = batt->GetCharge(); + if(level == 10 || level == 30 || level == 50 ) flicker(); + noflicker = 1; + if( level < 1) powered = 0; + } + noflicker = 0; + return powered; +} + +int CanReceive(object ob){ + if(ob->GetCellType() != celltype){ + return 0; + } + if(sizeof(all_inventory(this_object())) >= maxcells ){ + + return 0; + } + return 1; +} + +int eventRadiate(int i){ + SetRadiantLight(i); +} + +void SetLightLevel(int i){ + if(i) lightlevel = i; +} + +int GetLightLevel(){ + if(lightlevel) return lightlevel; + return 0; +} + +void regetID(){ + player=this_player(); + name=this_player()->GetName(); + env=environment(this_object()); +} + +varargs mixed eventTurn(string str){ + regetID(); + if( player != env ){ write("You don't have that."); return 0; } + write("You turn the "+me+" over in your hands."); + say(name+" turns over a "+me+" in "+possessive(player)+" hands."); + return 1; +} + +int eventTurnOn(object ob){ + regetID(); + CheckPower(); + + if(powered != 1){ + write("It isn't powered."); + return 1; + } + + if(player != env && environment(player) !=env){ + write("It isn't within reach."); + return 1; + } + if(Lit < 1){ + write("You turn on the "+me+"."); + say(name+" turns on a "+me+"."); + if(drainrate && drainrate > 0) eventUse(drainrate); + else eventUse(1); + eventRadiate(lightlevel); + set_heart_beat(1); + //SetShort(baseshort+" (%^BOLD%^YELLOW%^lit%^RESET%^)"); + return 1; + } + if(Lit >= 1){ + write("It is already lit."); + return 1; + } +} + +varargs mixed eventTurnOff(string str){ + regetID(); + if(player != env && environment(player) !=env){ write("It isn't within reach."); return 1; } + if(Lit > 0){ + write("You turn off the "+me+"."); + say(name+" turns off a "+me+"."); + eventRadiate(0); + eventUse(0); + set_heart_beat(0); + //SetShort(baseshort); + return 1; + } + if(Lit < 1){ + write("It is already off."); + return 1; + } +} + +mixed eventExtinguish(){ + return eventTurnOff("foo"); +} + +mixed eventLight(){ + return eventTurnOn(this_object()); +} + +void heart_beat(){ + CheckPower(); + + if(powered != 1){ + eventDie(); + } +} diff --git a/lib/lib/flask.c b/lib/lib/flask.c new file mode 100644 index 0000000..f469dbf --- /dev/null +++ b/lib/lib/flask.c @@ -0,0 +1,231 @@ +#include <lib.h> +#include <meal_types.h> + +inherit LIB_ITEM; +inherit LIB_DRINK; + +private int FlaskUses, FlaskStrength, MaxFlask, EverFill; +private int MealType, Tapped; +private string FlaskContents; + +int direct_fill_obj_with_obj(){ return 1;} +int direct_fill_obj_from_obj(){ return 1;} +int indirect_fill_obj_with_obj(){ return 1;} +int indirect_fill_obj_from_obj(){ return 1;} + +int indirect_pour_obj_into_obj(){ return 1;} +int direct_pour_obj_into_obj(){ return 1;} +int indirect_pour_from_obj_into_obj(){ return 1;} +int direct_pour_from_obj_into_obj(){ return 1;} + +int direct_pour_obj_out(){ return 1;} +int direct_pour_out_obj(){ return 1;} + +int direct_empty_obj(){ return 1;} + +mixed indirect_drink_from_obj(){ + if( environment() != this_player() && + base_name(this_object()) != LIB_FLOW && + !inherits(LIB_FLOW, this_object()) && + !this_object()->GetTapped() && + !inherits(LIB_BASE_DUMMY, this_object())){ + return "#You don't have it."; + } + if( !EverFill && FlaskUses < 1 ){ + return "The "+this_object()->GetKeyName()+" is empty."; + } + return this_object()->CanDrink(); +} + +mixed direct_drink_from_obj(){ + return indirect_drink_from_obj(); +} + +mixed direct_drink_obj(){ + return indirect_drink_from_obj(); +} + +static void create(){ + item::create(); + AddSave( ({ "FlaskUses", "FlaskStrength", "MealType", "FlaskContents" }) ); + FlaskUses = 0; + FlaskStrength = 0; + EverFill = 0; + MaxFlask = 5; + FlaskContents = "empty"; + MealType = MEAL_DRINK; +} + +string GetExternalDesc(){ + string ret = ""; + if(!inherits(LIB_BASE_DUMMY,this_object())){ + if(FlaskContents == "empty") ret = "\nIt is empty."; + else ret = "\nIt contains some "+FlaskContents+"."; + } + return item::GetExternalDesc()+ret; +} + +int CanFillMe(){ + return MaxFlask - FlaskUses; +} + +int CanFillOther(){ + if(EverFill) return 99999; + else return FlaskUses; +} + +//Tapped is for being able to fill from something +//without havingt to hold the source + +int SetTapped(int x){ + if(x) AddItem("tap", "The thing that lets you pour from it."); + return (Tapped = x); +} + +mixed GetTapped(){ return Tapped; } + +int SetStrength(int x){ return (FlaskStrength = x); } + +mixed GetStrength(){ return FlaskStrength; } + +int SetFlaskUses(int x){ + if(EverFill) return FlaskUses; + return (FlaskUses = x); +} + +int GetFlaskUses(){ return FlaskUses; } + +int SetEverFill(int x){ return (EverFill = x); } + +int GetEverFill(){ return EverFill; } + +int SetMealType(int x){ return (MealType = x); } + +int GetMealType(){ return MealType; } + +int SetMaxFlask(int x){ return (MaxFlask = x); } + +int GetMaxFlask(){ return MaxFlask; } + +string GetFlaskContents(){ return FlaskContents; } + +string SetFlaskContents(string str){ + SetId(GetId()+({ str })); + parse_refresh(); + return (FlaskContents = str); +} + +varargs mixed eventEmpty(object who){ + string *tmpid = GetId(); + if(FlaskContents != "empty") tmpid -= ({ FlaskContents }); + if(environment(this_object()) != who){ + write("You aren't holding it."); + return 1; + } + if(!FlaskUses){ + write("The "+GetShort()+" is already empty."); + say(who->GetName()+" fiddles with "+GetShort()+"."); + return 1; + } + if(EverFill){ + write("This cannot be emptied."); + return 1; + } + write("You pour the "+FlaskContents+" out of "+GetShort()+"."); + say(who->GetName()+" pours the "+FlaskContents+" out of "+GetShort()+"."); + SetId(tmpid); + parse_refresh(); + FlaskContents = "empty"; + SetStrength(0); + FlaskUses = 0; + return 1; +} + +mixed eventFill(object who, object from){ + int howmuch_me = CanFillMe(); + int howmuch_them = from->CanFillOther(); + if(!from->isDummy() && !from->GetTapped() && + base_name(from) != LIB_FLOW && + !inherits(LIB_FLOW, from) && + !inherits(LIB_BASE_DUMMY, from) && + environment(from) != this_player()){ + write("You are not holding the "+from->GetKeyName()+"."); + return 1; + } + + if(from->isDummy() && + environment(this_object()) != this_player()){ + write("You don't have the "+this_object()->GetKeyName()+"."); + return 1; + } + + if(from == this_object()){ + write("You can't fill it with itself!"); + return 1; + } + if(!howmuch_them){ + write("The "+from->GetKeyName()+" is empty."); + return 1; + } + if(FlaskUses >= MaxFlask){ + FlaskUses = MaxFlask; + write("The "+this_object()->GetKeyName()+" is already full."); + return 1; + } + if((from->GetFlaskContents() != GetFlaskContents() + || from->GetMealType() != GetMealType()) + && GetFlaskContents() != "empty"){ + write("Those are incompatible fluids, and you cannot mix them."); + return 1; + } + if(from->GetStrength() != GetStrength() && GetStrength()){ + write("Those are incompatible fluids, and you cannot mix them."); + return 1; + } + if(howmuch_them < howmuch_me) howmuch_me = howmuch_them; + if(!EverFill){ + FlaskUses += howmuch_me; + from->SetFlaskUses(from->GetFlaskUses() - howmuch_me); + } + write("You pour from "+from->GetShort()+" into "+this_object()->GetShort()+"."); + say(who->GetName()+" pours from "+from->GetShort()+ + " into "+this_object()->GetShort()+"."); + SetMealType(from->GetMealType()); + FlaskContents = from->GetFlaskContents(); + FlaskStrength = from->GetStrength(); + if(member_array(FlaskContents, GetId()) == -1) + SetId(GetId() + ({ FlaskContents }) ); + parse_refresh(); + return 1; +} + +varargs mixed eventDrink(object who, object target, string foo){ + write("You drink from "+GetShort()+"."); + say(who->GetName()+" drinks from "+GetShort()+"."); + if(!EverFill) FlaskUses--; + who->eventDrink(this_object()); + if(FlaskUses < 1){ + FlaskUses = 0; + SetId(GetId() - ({ FlaskContents }) ); + parse_refresh(); + FlaskContents = "empty"; + SetStrength(0); + } + return 1; +} + +varargs mixed CanDrink(object who, string what){ + mixed ret; + if(!who) who = this_player(); + if(FlaskUses < 1){ + FlaskUses = 0; + say(who->GetName()+" sadly looks at "+GetShort()+"."); + return "The "+this_object()->GetKeyName()+" is empty."; + } + ret = who->CanDrink(this_object()); + return ret; +} + +mixed eventPour(object who, object from){ + return eventFill(who, from); +} diff --git a/lib/lib/flow.c b/lib/lib/flow.c new file mode 100644 index 0000000..3cf559b --- /dev/null +++ b/lib/lib/flow.c @@ -0,0 +1,244 @@ +/* Eventually this will handle other kinds of flow + * materials, but for now it is hardcoded just to be water. + * Handle this with EXTREME care. It can very easily + * overwhelm your mud. + */ + +#include <lib.h> +#include ROOMS_H +#include <vendor_types.h> +#include <meal_types.h> +#include <medium.h> +#include <respiration_types.h> + +inherit LIB_FLASK; +mixed *neighbors = ({}); +mixed *rooms = ({}); +mixed *first = ({}); +mixed *second = ({}); +mixed *third = ({}); +mixed *fourth = ({}); +static int press; +static string FlowType = "water"; +static string ThisFile; +static int HBOverride, orig_medium, orig_resp, DoorStopped = 1; + +void shb(int i){ + if(!HBOverride) set_heart_beat(i); +} + +void create(){ + ::create(); + SetKeyName("water"); + SetId( ({"flow","flood","object","water","overflow"}) ); + SetAdjectives( ({"flow","flood"}) ); + SetShort("some water"); + SetLong("This is an overflow of water."); + SetMass(20); + SetInvis(1); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + shb(5); + SetNoCondition(1); + SetPreventGet("You can't get that."); + if(FlowType == "water"){ + SetFlaskContents("water"); + SetFlaskUses(2); + SetStrength(5); + SetMaxFlask(2); + SetEverFill(1); + SetMealType(MEAL_DRINK); + } + ThisFile = base_name(this_object()); +} + +void eventFlood(mixed targets){ + object env = environment(); + if(!env) return; + foreach(mixed room in scramble_array(targets)){ + mixed flooder; + object arch = load_object(ROOM_ARCH); + if(!room) break; + if(environment() == room) continue; + if(press < 2) break; + flooder = filter(all_inventory(room), + (: base_name($1) == ThisFile :) ); + if(sizeof(flooder)){ + if(sizeof(flooder) > 1) flooder[1..]->eventDestruct(); + flooder = flooder[0]; + } + else { + int flood; + flooder = new(ThisFile); + flooder->SetProperty("LastLocation", base_name(env)); + flood = flooder->eventMove(room); + if(!flood) continue; + tell_room(room,"This area starts flooding with water!"); + tell_room(arch,base_name(room)+" has been flooded."); + } + if(flooder->GetPressure() < press){ + if(press && flooder->AddPressure(1)) press--; + if(press < 2){ + tell_room(env,"The water recedes a bit."); + } + } + } +} + +void CheckRooms(){ + mixed ret = ({}); + object env; + mapping Exits; + env = room_environment(); + if(press < 1){ + eventDestruct(); + return; + } + if(clonep() && environment() && !living(environment()) && press > 1){ + } + if(env){ + Exits = env->GetExitMap(); + Exits += env->GetEnterMap(); + foreach(mixed key, mixed val in Exits){ + mixed door = env->GetDoor(key); + int ok =1; + if(door){ + if(DoorStopped && door->GetClosed() && !door->GetPerforated()){ + ok = 0; + } + else{ + } + } + if(ok) ret += ({ val }); + } + } + if(sizeof(ret)) rooms = ret; + if(press > 1){ + rooms = ({}); + foreach(mixed key, mixed val in Exits){ + if(member_array(val, ret) == -1) continue; + if(key == "down") first += ({ load_object(val) }); + else if(key == "up") fourth += ({ load_object(val) }); + else rooms += ({ load_object(val) }); + } + foreach(mixed room in rooms){ + mixed flooder; + if(press < 2) break; + flooder = filter(all_inventory(room), + (: base_name($1) == ThisFile :) ); + if(!sizeof(flooder)) second += ({ room }); + else third += ({ room }); + } + if(sizeof(first) && press > 0) eventFlood(first); + if(sizeof(second) && press > 1) eventFlood(second); + if(sizeof(third) && press > 1) eventFlood(third); + if(sizeof(fourth) && press > 2) eventFlood(fourth); + } +} + +void heart_beat(){ + object env; + if(!clonep()) return; + env = environment(); + if(!env || living(env) || press < 2){ + shb(240); + return; + } + CheckRooms(); + if(press > 1 && env){ + env->SetRespirationType(R_WATER); + } + else if(env){ + env->SetRespirationType(orig_resp); + } + shb(90); +} + +int AddPressure(int x){ + int i; + object env = environment(); + if(!env) return 0; + i = env->GetFlowLimit(); + if(i && x > 0 && press >= i) return 0; + if(x){ + if(press == 1 && x > 0){ + tell_room(env,"The area completely fills with water!"); + } + if(press > 1 && x < 0){ + tell_room(env,"The water recedes a bit."); + } + press += x; + } + return press; +} + +varargs int eventPrint(string msg, mixed arg2, mixed arg3){ + msg = lower_case(msg); + if(grepp(msg, "opens") || grepp(msg, "closes") ){ + CheckRooms(); + shb(5); + } + return 1; +} + +int GetPressure(){ + return press; +} + +int SetPressure(int i){ + press = i; + return press; +} + +int GetHBOverride(){ + return HBOverride; +} + +int SetHBOverride(int x){ + if(x) HBOverride = 1; + else HBOverride = 0; + return HBOverride; +} + +int GetDoorStopped(){ + return DoorStopped; +} + +int SetDoorStopped(int i){ + DoorStopped = i; + return DoorStopped; +} + +void init(){ + ::init(); +} + +string GetRoomAffectLong(){ + if(press > 1){ + return "\n%^CYAN%^This area is completely filled with water!%^RESET%^"; + } + if(press == 1){ + return "\n%^BOLD%^%^BLUE%^This area is flooded with water.%^RESET%^"; + } + return ""; +} + +int eventDestruct(){ + object env = environment(); + if(env){ + env->SetRespirationType(orig_resp); + } + return ::eventDestruct(); +} + +int eventMove(mixed dest){ + object env; + int ret = ::eventMove(dest); + if(ret && env = room_environment(this_object())){ + orig_resp = env->GetRespirationType(); + } + return ret; +} + +int GeteventPrints() { return 1; } + diff --git a/lib/lib/follow.c b/lib/lib/follow.c new file mode 100644 index 0000000..ddcf79d --- /dev/null +++ b/lib/lib/follow.c @@ -0,0 +1,56 @@ +/* From the Dead Souls Object Library + * Provides follow/trail support for mobile objects. + * Works closely with LIB_LEAD. + * Created by Rush 951028 + */ + +#include <lib.h> +#include "include/follow.h" + +private static object Leader; + +static void create(){ Leader = 0; } + +mixed direct_follow_liv(){ + if( this_object() == this_player() ) + return "It doesn't quite work that way."; + return this_player()->CanFollow(this_object()); +} + +object SetLeader(object leader){ + if( leader == this_object() ) return 0; + if( leader && Leader ) return 0; + Leader = ( leader && leader->GetFollowers() ) ? leader : 0; + return Leader; +} + +object GetLeader(){ return Leader; } + +varargs mixed CanFollow(object ob){ + if( ob ){ + if( !ob->CanLead() ) + return "You are not empowered to follow " + ob->GetName(); + if( IsFollowing(ob) ) + return "You are already following " + ob->GetName(); + if( ob->IsFollowing(this_object()) ) + return ob->GetName() + " is already following you."; + if( ob == this_object() ) + return "You cannot possibly do that."; + } + return 1; +} + +int IsFollowing(object ob){ + if( !Leader ) return 0; + if( Leader == ob ) return 1; + if( Leader->IsFollowing(ob) ) return 1; + return 0; +} + +/* + * eventFollow() needs to be overriden by child classes to provide the + * actual move support. + */ +int eventFollow(object dest, int fC){ return 0; } + + diff --git a/lib/lib/fuel.c b/lib/lib/fuel.c new file mode 100644 index 0000000..a886708 --- /dev/null +++ b/lib/lib/fuel.c @@ -0,0 +1,76 @@ +/* /lib/fuel.c + * from the Dead Souls object Library + * fuel for things which need fuel + * this could be battery charge, gas, whatever + * created by Descartes of Borg 960512 + */ + +#include "include/fuel.h" + +private int FuelAmount = 100; +private int MaxFuel = 100; +private int Refuelable = 1; +private string FuelType = "oil"; + +static void create(){ + this_object()->AddSave(({ "FuelAmount" })); +} + +mixed eventDecreaseFuel(int x){ + if( x < 1 ) return 0; + FuelAmount -= x; + if( FuelAmount < 1 ) FuelAmount = 0; + return 1; +} + +mixed eventRefuel(int x){ + if( x < 1 ) return 0; + FuelAmount += x; + if( FuelAmount > MaxFuel ) FuelAmount = MaxFuel; + return 1; +} + +int GetFuelAmount(){ + return FuelAmount; +} + +static int SetFuelAmount(int x){ + return (FuelAmount = x); +} + +string GetFuelType(){ + return FuelType; +} + +static string SetFuelType(string str){ + return (FuelType = str); +} + + +varargs string GetLong(string val){ + /* string str; + if(!(str = item::GetLong(val)) || str == "") return str; + else return sprintf("%s%s", str, (GetFuel() ? "" : + sprintf("\nThe %s is out of fuel.", GetKeyName()))); + */ + if( !GetFuelAmount() ) + return capitalize(GetShort()) + " is out of fuel."; + else return ""; +} + +int GetMaxFuel(){ + return MaxFuel; +} + +static int SetMaxFuel(int x){ + return (MaxFuel = x); +} + +int GetRefuelable(){ + return Refuelable; +} + +static int SetRefuelable(int x){ + return (Refuelable = x); +} + diff --git a/lib/lib/genetics.c b/lib/lib/genetics.c new file mode 100644 index 0000000..fe56829 --- /dev/null +++ b/lib/lib/genetics.c @@ -0,0 +1,364 @@ +/* /lib/genetics.c + * from the Dead Souls LPC Library + * handles genetic characteristics + * created by Descartes of Borg 950122 + * Version: @(#) genetics.c 1.4@(#) + * Last Modified: 96/11/11 + */ + +#include <vision.h> +#include <function.h> +#include <damage_types.h> +#include <daemons.h> +#include "include/genetics.h" + +class blindness { + int count; + mixed end; +} + +private class blindness Blind = 0; +private mapping Custom = ([]); +private int array LightSensitivity = ({ 25, 75 }); +private mapping Resistance = ([]); +private mapping Stats = ([]); +private static mapping StatsBonus = ([]); +private static int VisionBonus = 0; + +// abstract methods +string GetName(); +varargs void eventPrint(string message, mixed args...); +// end abstract methods + +static void create(){ + Custom = ([ + "stats" : 15, + "deviations" : 4, + "deviating" : 0, + ]); + Resistance = ([ "low" : 0, "medium" : 0, "high" : 0, "immune" : 0 ]); + Resistance["none"] = ALL_DAMAGE; +} + +int GetBlind(){ + if( Blind ){ + return 1; + } + else { + return 0; + } +} + +static void RemoveBlindness(){ + mixed val = Blind->end; + + Blind = 0; + if( arrayp(val) ){ + send_messages(val[0], val[1], this_object()); + } + else if( functionp(val) && !(functionp(val) & FP_OWNER_DESTED) ){ + evaluate(val, this_object()); + } + else { + eventPrint("You can see again."); + } +} + +varargs mixed eventBlind(object who, int amt, mixed end){ + Blind = new(class blindness); + Blind->count = amt; + Blind->end = end; + return 1; +} + +mixed eventCustomizeStat(string stat, int amount){ + if( amount < 1 ) return "That is not a valid amount."; + if( amount > Custom["stats"] ) + return "You do not have enough points to spend on this customization."; + if( !Stats[stat] ) return "You have no such stat."; + if( Stats[stat]["level"] + amount > 100 ) + return "You cannot make a stat exceed 100."; + Stats[stat]["level"] += amount; + Stats[stat]["points"] = 0; + Custom["stats"] -= amount; + return Stats[stat]["level"]; +} + +mixed eventDeviateStat(string stat, int amount){ + if( amount < 1 ) return "That is not a valid amount."; + if( amount > Custom["deviations"] ) + return "You do not have enough points to spend on that deviation."; + if( !Stats[stat] ) return "You have no such stat."; + if( Stats[stat]["class"] - amount < 1 ) + return "You cannot deviate a stat class below 1."; + Stats[stat]["class"] -= amount; + Custom["deviations"] -= amount; + return Stats[stat]["class"]; +} + +mixed eventRestoreSight(object who, int amt){ + if( !Blind ){ + return GetName() + " is not blind!"; + } + Blind->count -= amt; + if( Blind->count < 1 ){ + RemoveBlindness(); + return 1; + } + return 0; +} + +varargs void SetStat(string stat, int level, int classes){ + if(!stat) return; + if(level < 1) level = 1; + if(!classes) classes = 1; + Stats[stat] = ([ "points" : 0, "level" : level, "class" : classes ]); + STATS_D->SetStat(stat); +} + +varargs void AddStat(string stat, int base, int cls){ + int level; + if( userp(this_object()) ) level = 1; + else level = GetLevel(); + if( !stat || cls < 1 || cls > 5 ) return; + base += ((5 - cls) * random(10)) + (3 * (level + 1))/(cls * 4); + if( userp(this_object()) && base > 90 ) base = 90; + else if( base > 100 ) base = 100; + STATS_D->SetStat(stat); + SetStat(stat, base, cls); +} + +varargs void RemoveStat(string stat){ + if(!stat) return; + if(Stats[stat]) map_delete(Stats, stat); +} + +mapping GetStat(string stat){ + mapping ret = ([]); + if(!stat) return 0; + ret = copy(Stats[stat]); + if(!sizeof(ret)) return 0; + if(ret["level"] < 0) ret["level"] = 0; + return ret; +} + +int GetStatClass(string stat){ + if(!Stats[stat]) return 0; + else return Stats[stat]["class"]; +} + +int GetBaseStatLevel(string stat){ + if(!Stats[stat]) return 0; + else return Stats[stat]["level"]; +} + +int GetStatLevel(string stat){ + int x; + + x = (GetBaseStatLevel(stat) + GetStatBonus(stat)); + switch(stat){ + case "coordination": case "wisdom": + x -= this_object()->GetAlcohol();break; + case "strength": case "durability" : case "agility": + x -= this_object()->GetPoison();break; + case "intelligence": case "speed": case "coordination": + x += (this_object()->GetCaffeine() / 10);break; + } + return x; +} + +int AddStatPoints(string stat, int x){ + int y; + + if( !Stats[stat] ) return 0; + Stats[stat]["points"] += x; + while( Stats[stat]["points"] < 0 ){ + if( Stats[stat]["level"] == 1 ) Stats[stat]["points"] = 0; + else { + int tmp; + + tmp = --Stats[stat]["level"]; + Stats[stat]["points"] += GetMaxStatPoints(stat, tmp); + } + } + while(Stats[stat]["points"] > (y = GetMaxStatPoints(stat, + Stats[stat]["level"]))){ + if(Stats[stat]["level"] >= GetLevel()*4) Stats[stat]["points"] = y; + else { + Stats[stat]["level"]++; + Stats[stat]["points"] -= y; + } + } + return Stats[stat]["level"]; +} + +string *GetStats(){ return keys(Stats); } +mapping GetStatsMap(){ return copy(Stats); } + +int GetMaxStatPoints(string stat, int level){ + if( !Stats[stat] ) return 0; + else { + int cl, x; + + if( !(cl = Stats[stat]["class"]) ) return level * 600; + x = level; + while( cl-- ) x *= level; + return x * 600; + } +} + +void AddStatBonus(string stat, mixed f){ + if(!StatsBonus[stat]) StatsBonus[stat] = ([]); + StatsBonus[stat][previous_object()] = f; +} + +varargs void RemoveStatBonus(string stat, object ob){ + if(!StatsBonus[stat]) return; + if(!ob) ob = previous_object(); + if(!ob || !StatsBonus[stat][ob]) return; + map_delete(StatsBonus[stat], ob); +} + +int GetStatBonus(string stat){ + object *obs; + int i, x = 0; + + if( !StatsBonus[stat] ) return 0; + i = sizeof(obs = keys(StatsBonus[stat])); + while(i--){ + if( !obs[i] ) map_delete(StatsBonus[stat], obs[i]); + else x += evaluate(StatsBonus[stat][obs[i]], stat); + } + return x; +} + +/* string SetResistance(int type, string level) + * int type - the type being set (you can do a bitwise | on them) + * string level "none", "low", "medium", "high", and "immune" + * + * description + * you can have a several levels of resistence for given types of damage + * setting a resistence level here unsets any other levels of resistence + */ + +varargs string SetResistance(int type, string level){ + if(level == "none") Resistance["none"] |= type; + else Resistance["none"] &= ~type; + if(level == "low") Resistance["low"] |= type; + else Resistance["low"] &= ~type; + if(level == "medium") Resistance["medium"] |= type; + else Resistance["medium"] &= ~type; + if(level == "high") Resistance["high"] |= type; + else Resistance["high"] &= ~type; + if(level == "immune") Resistance["immune"] |= type; + else Resistance["immune"] &= ~type; +} + +string GetResistance(int type){ + if(Resistance["low"] & type) return "low"; + else if(Resistance["medium"] & type) return "medium"; + else if(Resistance["high"] & type) return "high"; + else if(Resistance["immune"] & type) return "immune"; + else return "none"; +} + +mapping GetResistanceMap(){ + return copy(Resistance); +} + +int GetCustomStats(){ return Custom["stats"]; } +int GetCustomDeviations(){ return Custom["deviations"]; } +int GetDeviating(){ return Custom["deviating"]; } +int SetDeviating(int x){ return (Custom["deviating"] = (x ? 1 : 0)); } + +varargs mixed GetEffectiveVision(mixed location, int raw_score){ + int array l; + object env, rider, where; + int bonus = GetVisionBonus(); + int a, y, x = 0; + + env = environment(); + + if(raw_score && !intp(raw_score)){ + location = raw_score; + raw_score = 0; + } + + //fixme + if(!location && sizeof(get_livings(this_object())) && + rider = get_random_living(this_object())){ + if(rider->GetProperty("mount") == this_object() && env){ + return rider->GetEffectiveVision(env); + } + } + + if(location){ + if(objectp(location)) where = location; + else if(stringp(location)){ + int err; + err = catch( where = load_object(location) ); + if(err || !where) return 0; + } + } + if( Blind && !raw_score){ + return VISION_BLIND; + } + if( !where && !location ){ + where = env; + } + if(!where) return 0; + x = (env == where ? GetRadiantLight(0) : 0); + a = where->GetAmbientLight(); + if(x){ + x = x/2; + x += GetRadiantLight(a) + a; + } + else x = a * 2; + l = GetLightSensitivity(); + l[0] -= bonus; + l[1] += bonus; + + if(raw_score && !location){ + return "Low: "+l[0]+", High: "+l[1]; + } + if( x >= l[0] && x <= l[1] ) return VISION_CLEAR; + y = l[0]/3; + if( x < y ) return VISION_TOO_DARK; + if( x < (2*y) ) return VISION_DARK; + if( x < l[0] ) return VISION_DIM; + y = l[1]/3; + if( x < (l[1] + y) ) return VISION_LIGHT; + if( x < (l[1] + (2*y)) ) return VISION_BRIGHT; + return VISION_TOO_BRIGHT; +} + +int array GetLightSensitivity(){ + if( !LightSensitivity ) return ({ 25, 75 }); + else return LightSensitivity; +} + +varargs static int array SetLightSensitivity(mixed array val...){ + if( !val ) error("Null argument to SetLightSensitivity().\n"); + if( sizeof(val) == 1 ) val = val[0]; + if( sizeof(val) != 2 ) + error(sprintf("Invalid arguments to SetLightSensitivity(): %O\n", val)); + return (LightSensitivity = val); +} + +int AddVisionBonus(int x){ + VisionBonus += x; + return VisionBonus; +} + +int GetVisionBonus(){ + return VisionBonus; +} + +static void heart_beat(){ + if( Blind ){ + Blind->count--; + if( Blind->count < 1 ){ + RemoveBlindness(); + } + } +} diff --git a/lib/lib/guard.c b/lib/lib/guard.c new file mode 100644 index 0000000..865ff8c --- /dev/null +++ b/lib/lib/guard.c @@ -0,0 +1,140 @@ +#include <daemons.h> +#include <position.h> + +private static mixed GuardAction; +private static mixed globalwhat; +private static array PendingGuard = ({}); +private static mixed gwhat; +private static object Principal; +private static mapping GuardMap = ([]); + +int AllowPass(object who, object what){ + string race = this_object()->GetRace(); + if(who == this_object()) return 1; + if(who->GetInvis()) return 1; + if(this_object()->GetSleeping()) return 1; + if(this_object()->GetParalyzed()) return 1; + if(this_object()->GetPosition() == POSITION_LYING && + !(RACES_D->GetLimblessCombatRace(race)) ) return 1; + return 0; +} + +int AllowGet(object who, object what){ + string race = this_object()->GetRace(); + if(who == this_object()) return 1; + if(who->GetInvis()) return 1; + if(this_object()->GetSleeping()) return 1; + if(this_object()->GetParalyzed()) return 1; + if(this_object()->GetPosition() == POSITION_LYING && + !(RACES_D->GetLimblessCombatRace(race)) ) return 1; + return 0; +} + +varargs mixed SetGuard(mixed what, mixed action, int howlong){ + object env = environment(); + if(!GuardMap) GuardMap = ([]); + if(!clonep(this_object())) return 0; + if(!what && !sizeof(PendingGuard)) return 0; + if(!PendingGuard) PendingGuard = ({}); + + PendingGuard += ({ ([ "what" : what, "action" : action, + "howlong" : howlong ]) }); + if(!env){ + return 0; + } + + if(stringp(what)){ + int err; + mapping exits = env->GetExitMap(); + exits += env->GetEnterMap(); + gwhat = what; + if(exits && exits[gwhat]){ + gwhat = exits[gwhat]; + } + if(!unguarded( (: directory_exists(path_prefix(gwhat)) :) ) ){ + return 0; + } + err = catch( unguarded( (: gwhat = load_object(gwhat) :) ) ); + if(err || !gwhat){ + return 0; + } + } + if(gwhat && living(gwhat)){ + Principal = gwhat; + this_object()->eventForce("follow "+gwhat->GetKeyName()); + } + + else if(gwhat && !inherits(LIB_ROOM,gwhat)){ + mixed inv = deep_inventory(env); + inv = filter(inv, (: base_name($1) == base_name(gwhat) :)); + inv = filter(inv, (: $1 && !interactive(environment($1)) :)); + if(!sizeof(inv)){ + if(objectp(gwhat)) what = base_name(gwhat); + GuardMap[random(20)] = ([ "base" : what, "action" : action ]); + } + foreach(object ob in inv){ + GUARD_D->AddGuard(this_object(), ob, action); + GuardMap[file_name(ob)] = ([ "base" : base_name(ob), + "action" : action ]); + if(living(ob)){ + Principal = ob; + } + } + } + else GUARD_D->AddGuard(this_object(), gwhat, action); + gwhat = 0; + return 1; +} + +void CheckPending(){ + if(PendingGuard && clonep() && sizeof(PendingGuard)){ + mixed tmp_pending = ({}); + int ret; + foreach(mixed guardmount in PendingGuard){ + ret = SetGuard(guardmount["what"], guardmount["action"], + guardmount["howlong"]); + if(!ret) tmp_pending += ({ guardmount }); + } + PendingGuard = tmp_pending; + } +} + +void CheckGuardeds(){ + if(!GuardMap) GuardMap = ([]); + if(Principal){ + object enemies = Principal->GetEnemies(); + if(sizeof(enemies)){ + foreach(object ob in enemies){ + if(member_array(ob, this_object()->GetEnemies()) == -1){ + this_object()->AddEnemy(ob); + } + } + } + } + if(sizeof(GuardMap)){ + mapping RetMap = ([]), ReGuard = ([]); + foreach(string key, mapping tmpmap in GuardMap){ + object ob, env; + if(!(ob = find_object(key)) || !(env = environment(ob)) || + env != environment(this_object())){ + ReGuard[tmpmap["base"]] = tmpmap["action"]; + } + else RetMap[key] = tmpmap; + } + GuardMap = copy(RetMap); + if(sizeof(ReGuard)){ + foreach(string key, mixed action in ReGuard){ + SetGuard(key, action); + } + } + } +} + +void heart_beat(){ + CheckGuardeds(); +} + +void init(){ + CheckGuardeds(); + CheckPending(); +} diff --git a/lib/lib/help.c b/lib/lib/help.c new file mode 100644 index 0000000..e07ef8e --- /dev/null +++ b/lib/lib/help.c @@ -0,0 +1,23 @@ +/* /lib/help.c + * From the Dead Souls Object Library + * Provides an interface to the help system for objects that want it + * Created by Descartes of Borg 960116 + * Version: @(#) help.c 1.2@(#) + * Last modified: 96/12/17 + */ + +private static mapping Help = ([ "default" : "No help has been provided." ]); + +string GetHelp(string topic){ + if( !topic || !Help[topic] ){ + topic = "default"; + } + return Help[topic]; +} + +static mapping SetHelp(mixed val){ + if( stringp(val) ){ + val = ([ "default" : val ]); + } + return (Help = val); +} diff --git a/lib/lib/history.c b/lib/lib/history.c new file mode 100644 index 0000000..7bf69cd --- /dev/null +++ b/lib/lib/history.c @@ -0,0 +1,221 @@ +/* /lib/history.c + * from the Dead Souls Object Library + * handles command line histories + * created by Descartes of Borg 960511 + */ + +#include <message_class.h> +#include "include/history.h" + +private int HistorySize = MIN_HISTORY_SIZE; +private static int CommandNumber = 1; +private mapping History = ([]); + +static string eventHistory(string str){ + string cmd, args, old, neu; + int len, num; + CommandNumber = sizeof(History); + + if( str[0] == '^' ) str = "!!" + str; + if( (len = strlen(str)) < 2 || str[0] != '!' ) return Push(str); + if( str[0..1] == "!!" || str[0..2] == "!-1"){ + cmd = GetHistory(CommandNumber-1); + if( str[1] == '!' ){ + if( len == 2 ) args = ""; + else args = str[2..]; + } + else { + if( len == 3 ) args = ""; + else args = str[3..]; + } + } + else { + int x; + + if( str[1] == '-' ){ + sscanf(str, "!-%d%s", x, args); + if( !x ) cmd = ""; + else cmd = GetHistory(CommandNumber-x); + } + else if( sscanf(str, "!%d%s", x, args) == 2 ){ + if( !x ) cmd = ""; + else cmd = GetHistory(x); + } + else { + str = str[1..]; + cmd = GetHistory(str); + args = ""; + } + } + if( !cmd || cmd == "" ){ + eventPrint("Invalid history command.", MSG_ERROR); + return ""; + } + if( !args || args == "" ) return Push(cmd); + len = strlen(args); + if( args[0] != '^' && args[0] != 's' ){ + if( len > 1 && args[0] == '\\' && (args[1] == '^' || args[1] == 's') ) + args = args[1..]; + return Push(cmd + args); + } + if( len < 3 ){ + if( args[0] == 's' ){ + if( len < 2 || args[1] != '/' ) return Push(cmd + args); + } + eventPrint("Invalid replacement syntax.", MSG_ERROR); + return ""; + } + if( args[0] == '^' ){ + int i; + + args = args[1..]; + i = strsrch(args, "^"); + if( i == 0 ) i = -1; + while( i != -1 && args[i-1] == '\\' ){ + args = args[0..i-2] + args[i..]; + if( strlen(args) == i+1 ) i = -1; + else i = strsrch(args, "^", i+1); + } + if( i == -1 ){ + eventPrint("Invalid replacement syntax.", MSG_ERROR); + return ""; + } + old = args[0..(i-1)]; + if( i == strlen(args) - 1 ) neu = ""; + else neu = args[(i+1)..]; + num = 1; + neu = replace_string(neu, "\\^", "^"); + } + else { + int i; + + args = args[2..]; + i = strsrch(args, "/"); + if( i == 0 ) i = -1; + while( i != -1 && args[i-1] == '\\' ){ + args = args[0..i-2] + args[i..]; + if( strlen(args) == i+1 ) i = -1; + else i = strsrch(args, "/", i+1); + } + if( i == -1 ){ + eventPrint("Invalid replacement syntax.", MSG_ERROR); + return ""; + } + old = args[0..(i-1)]; + if( i == strlen(args) - 1 ) neu = ""; + else neu = args[(i+1)..]; + len = strlen(neu); + if( len > 1 ){ + if( neu[<2..] == "/g" ){ + if( len > 2 && neu[<3] != '\\' ){ + num = 0; + neu = neu[0..<3]; + } + else if( len > 2 ) num = 1; + else { + num = 0; + neu = ""; + } + } + } + else num = 1; + neu = replace_string(neu, "\\/", "/"); + } + cmd = replace_string(cmd, old, neu, num); + return Push(cmd); +} + +static string Push(string cmd){ + int j, crunch; + CommandNumber = sizeof(History); + if(CommandNumber && History[CommandNumber-1] == cmd){ + return cmd; + } + if(member_array(cmd, values(History)) != -1){ + foreach(mixed key, mixed val in History){ + if(cmd == val){ + History[key] = 0; + } + crunch = 1; + } + } + if(crunch){ + mapping newmap = ([]); + j = 0; + for(int i = 0; i < CommandNumber; i++){ + if(History[i]){ + newmap[j] = History[i]; + j++; + } + } + History = newmap; + CommandNumber = sizeof(History); + return cmd; + } + History[CommandNumber] = cmd; + if(CommandNumber > HistorySize){ + mapping newmap = ([]); + foreach(mixed key, mixed val in History){ + if(key > 0) newmap[key-1] = val; + } + History = newmap; + } + CommandNumber = (sizeof(History) - 1); + return cmd; +} + +int GetCommandNumber(){ + return CommandNumber; +} + +string GetHistory(mixed val){ + if(!this_player() || this_player() != this_object() + || this_player()->GetForced()) return ""; + if( intp(val) ){ + if( !History[val] ) return ""; + return History[val]; + } + else if( stringp(val) ){ + foreach(mixed key, mixed what in History){ + if( strsrch(what, val) == 0 ) return what; + } + return ""; + } + else error("Invalid argument to GetHistory().\n"); +} + +mapping GetHistoryList(){ + if( !(master()->valid_apply(({ GetKeyName() }))) ) return ([]); + return copy(History); +} + +mapping GetCommandHist(){ + return GetHistoryList(); +} + +int SetHistorySize(int x){ + if( !(master()->valid_apply(({ GetKeyName() }))) ) + return HistorySize; + if( x == HistorySize ) return HistorySize; + if( x > MAX_HISTORY_SIZE ) return HistorySize; + else if( x < MIN_HISTORY_SIZE ) return HistorySize; + return (HistorySize = x); +} + +string GetLastCommand(){ + if(!this_object()->GetForced() && + (this_player() == this_object() || previous_object() == master())){ + return History[sizeof(History)-1]; + } + else return ""; +} + +int GetMaxCommandHistSize(){ + return MAX_HISTORY_SIZE; +} + +int SetMaxCommandHistSize(int i){ + SetHistorySize(i); + return HistorySize; +} + diff --git a/lib/lib/include/abilities.h b/lib/lib/include/abilities.h new file mode 100644 index 0000000..d6229e2 --- /dev/null +++ b/lib/lib/include/abilities.h @@ -0,0 +1,23 @@ +#ifndef l_abilities_h +#define l_abilities_h + +static void create(); +varargs void SetSkill(string skill, int level, mixed classes); +varargs int AddSkill(string skill, int classes); +mapping GetSkill(string skill); +int GetSkillClass(string skill); +int GetBaseSkillLevel(string skill); +int GetSkillLevel(string skill); +int AddSkillPoints(string skill, int x); +string *GetSkills(); +string *GetPrimarySkills(); +void SetLevel(int x); +int ResetLevel(); +int GetLevel(); +int GetMaxSkillPoints(string skill, int level); +void AddSkillBonus(string skill, function f); +varargs void RemoveSkillBonus(string skill, object ob); +int GetSkillBonus(string skill); + +/* pure virtual */varargs int eventPrint(string str, mixed arg2, mixed arg3); +#endif /* l_abilities_h */ diff --git a/lib/lib/include/armor.h b/lib/lib/include/armor.h new file mode 100644 index 0000000..cc66686 --- /dev/null +++ b/lib/lib/include/armor.h @@ -0,0 +1,34 @@ +#ifndef l_armor_h +#define l_armor_h + +static void create(); +mixed direct_remove_obj(); +mixed direct_wear_obj(); +mixed direct_wear_obj_on_str(mixed fix...); + +mixed CanWear(object who, string *limbs); +mixed CanWield(object who, string *limbs); + +void eventDeteriorate(int type); +void eventEquipAgain(string *limbs); +int eventReceiveDamage(object agent, int type, int strength, int internal, mixed limbs); +mixed eventUnequip(object who); +mixed eventWear(object who, string *limbs); + +string GetWornDescription(); +string GetItemCondition(); +int SetArmorType(int x); +int SetProtection(int type, int amount); +int GetProtection(int type); +int GetMaxProtection(int type); +string *SetRestrictLimbs(string *limbs); +string *GetRestrictLimbs(); +int SetFingers(int x); +int GetFingers(); +mixed SetWear(mixed val); +mixed GetWear(); +string GetShort(); + +#endif /* l_armor_h */ + + diff --git a/lib/lib/include/autosave.h b/lib/lib/include/autosave.h new file mode 100644 index 0000000..9fa7500 --- /dev/null +++ b/lib/lib/include/autosave.h @@ -0,0 +1,16 @@ +#ifndef __AUTOSAVE_H +#define __AUTOSAVE_H + +int Setup(); +void heart_beat(); +nomask void save_player(string nom); +void pre_save(); +nomask void actually_save_player(string nom); +nomask int restore_player(string nom); +nomask void restore_inventory(); +int eventDestruct(); +string GetKeyName(); + +#endif __AUTOSAVE_H + + diff --git a/lib/lib/include/bait.h b/lib/lib/include/bait.h new file mode 100644 index 0000000..1948ae1 --- /dev/null +++ b/lib/lib/include/bait.h @@ -0,0 +1,19 @@ +#ifndef l_bait_h +#define l_bait_h + +static void create(); + +mixed indirect_bait_obj_with_obj(); + +int SetBaitStrength(int x); +int GetBaitStrength(); + +mixed eventBait(object who, object pole); + +/* virtual functions */ + +static mixed AddSave(mixed *vars); +string GetShort(); +int eventDestruct(); + +#endif diff --git a/lib/lib/include/bank.h b/lib/lib/include/bank.h new file mode 100644 index 0000000..7ccd422 --- /dev/null +++ b/lib/lib/include/bank.h @@ -0,0 +1,31 @@ +#ifndef l_bank_h +#define l_bank_h + +static void create(); + +mixed CanBank(object who, string currency); + +string SetBank(string str); +string SetCurrency(string str); +int SetSurcharge(int amount); +int SetNonResidentSurcharge(int amount); +int SetMinimumTransaction(int amount); +float SetExchangePercentage(float f); +mixed SetCurrencies(mixed var); +string GetCurrency(); +string GetBank(); +int GetSurcharge(object ob); +int GetNonResidentSurcharge(); +int GetMinimumTransaction(); +float GetExchangePercentage(); +mixed GetCurrencies(); + +int AddSurcharge(object who, string currency, int amount); + +mixed eventDeposit(object who, string currency, int amount); +mixed eventWithdraw(object who, string currency, int amount); +mixed eventBalance(object who); +mixed eventExchange(object who, int amount, string str1, string str2); +mixed eventOpenAccount(object who); + +#endif /* l_bank_h */ diff --git a/lib/lib/include/barkeep.h b/lib/lib/include/barkeep.h new file mode 100644 index 0000000..a6b1fc4 --- /dev/null +++ b/lib/lib/include/barkeep.h @@ -0,0 +1,16 @@ +#ifndef l_barkeep_h +#define l_barkeep_h + +static void create(); +static void init(); +int cmdBuy(object who, string cmd, string args); +int cmdList(object who, string cmd, string args); +string SetLocalCurrency(string str); +string GetLocalCurrency(); +mapping SetMenuItems(mapping mp); +mapping AddMenuItem(string item, string file); +mapping RemoveMenuItem(string item); +int GetCost(string str); +mapping GetMenuItems(); + +#endif /* l_barkeep_h */ diff --git a/lib/lib/include/bboard.h b/lib/lib/include/bboard.h new file mode 100644 index 0000000..b0ca3c5 --- /dev/null +++ b/lib/lib/include/bboard.h @@ -0,0 +1,25 @@ +#ifndef __BBOARD_H +#define __BBOARD_H + +void create(); +void init(); +static private int valid_edit(string author); +int cmd_post(string str); +static void begin_post(string cmd, string subj, string file, function f); +void continue_post(string subj, string file); +void abort_edit(); +void end_post(string subj, string mail); +int cmd_read(string str); +int cmd_followup_and_respond(string str); +void continue_followup(mapping post, string subj, string file); +void continue_mail(mapping post, string subj, string file); +static void check_include_text(string ans, string subj, string file, mapping post, int mail); +int cmd_eventDestruct(string str); +int cmd_edit(string str); +void end_edit(string subj, int num); +varargs string GetLong(string str); +void set_board_id(string str); +string query_board_id(); +string query_board_time(int x); + +#endif /* __BBOARD_H */ diff --git a/lib/lib/include/body.h b/lib/lib/include/body.h new file mode 100644 index 0000000..4235e3f --- /dev/null +++ b/lib/lib/include/body.h @@ -0,0 +1,83 @@ +#ifndef l_body_h +#define l_body_h + +static void create(); +static void heart_beat(); +void restart_heart(); + +int CanFly(); + +void eventCheckHealing(); +void eventCompleteHeal(int x); +mixed eventFall(); +varargs int eventHealDamage(int x, int internal, mixed limbs); +varargs int eventReceiveDamage(mixed agent, int type, int x, int internal, mixed limbs); +int eventCheckProtection(object agent, int type, int damage); + +mixed eventReceiveThrow(object who, object what); +varargs int eventDie(mixed agent); +int eventRemoveItem(object ob); +int eventWear(object ob, mixed limbs); + +void NewBody(string race); +mixed CanWear(object armor, string *limbs); +varargs int AddLimb(string limb, string parent, int classes, int *armors); +int RestoreLimb(string str); +int RemoveLimb(string limb, mixed agent); +mapping GetLimb(string limb); +string GetRandomLimb(string targ); +string GetTorso(); +string *GetLimbs(); +int GetLimbClass(string limb); +string GetLimbParent(string limb); +string *GetLimbChildren(string limb); +mapping GetMissingLimb(string limb); +varargs string *GetMissingLimbs(int not_default); +string GetLong(string nom); +string *GetWieldingLimbs(); +varargs int AddFingers(string limb, int x); +int GetFingers(string limb); +varargs object *GetWorn(string limb); +varargs mixed GetWielded(string limb); +varargs static int AddHealthPoints(int x, string limb, mixed agent); +varargs int GetHealthPoints(string limb); +varargs int GetMaxHealthPoints(string limb); +int AddMagicPoints(int x); +int GetMagicPoints(); +int GetMaxMagicPoints(); +float AddStaminaPoints(mixed x); +int GetStaminaPoints(); +float GetMaxStaminaPoints(); +int AddMagicProtection(class MagicProtection cl); +class MagicProtection *GetMagicProtection(); +int RemoveMagicProtection(int i); +int SetUndead(int x); +int GetUndead(); +string SetUndeadType(string str); +string GetUndeadType(); +int SetSleeping(int x); +int GetSleeping(); +int AddAlcohol(int x); +int GetAlcohol(); +int AddCaffeine(int x); +int GetCaffeine(); +int AddFood(int x); +int GetFood(); +int AddDrink(int x); +int GetDrink(); +int AddPoison(int x); +int GetPoison(); +int GetDying(); +string GetResistance(int type); +string GetRace(); +string GetName(); +string GetCapName(); +int GetHeartRate(); +int GetHealRate(); +/* pure virtual */ string GetShort(); +/* pure virtual */ varargs mixed eventPrint(mixed msg, mixed cl, mixed three); +/* pure virtual */ varargs int SetParalyzed(int x, function f); +/* pure virtual */ varargs mixed eventMoveLiving(mixed dest, string omsg, + string imsg); + +#endif /* l_body_h */ diff --git a/lib/lib/include/burn.h b/lib/lib/include/burn.h new file mode 100644 index 0000000..95b78dd --- /dev/null +++ b/lib/lib/include/burn.h @@ -0,0 +1,34 @@ +#ifndef l_burn_h +#define l_burn_h + +static void create(); +static void heart_beat(); + +mixed direct_burn_obj_with_obj(); +mixed indirect_burn_obj_with_obj(object target, object source); +mixed indirect_burn_obs_with_obj(object *targets, object source); +mixed direct_light_obj(object target); +mixed direct_light_obj_with_obj(); +mixed indirect_light_obj_with_obj(object target, object source); +mixed indirect_light_obs_with_obj(object *targets, object source); + +mixed eventBurnOut(); +mixed eventBurn(object who, object what); +mixed eventLight(object who, object what); + +int GetBurning(); +int GetBurnRate(); +static int SetBurnRate(int x); +int GetBurntValue(); +static int SetBurntValue(int x); +int GetFuelRequired(); +static int SetFuelRequired(int x); +int GetHeat(); +static int SetHeat(int x); +int GetMinHeat(); +static int SetMinHeat(int x); + +/* pure virtual */ string GetShort(); +/* pure virtual */ int SetValue(int x); + +#endif /* l_burn_h */ diff --git a/lib/lib/include/carry.h b/lib/lib/include/carry.h new file mode 100644 index 0000000..571c6b2 --- /dev/null +++ b/lib/lib/include/carry.h @@ -0,0 +1,13 @@ +#ifndef __CARRY_H__ +#define __CARRY_H__ + +int CanCarry(int amount); + +int AddCarriedMass(int x); +int GetCarriedMass(); +int GetCarriedWeight(); +int GetMaxCarry(); + +#endif /* __CARRY_H__ */ + + diff --git a/lib/lib/include/chapel.h b/lib/lib/include/chapel.h new file mode 100644 index 0000000..8c9126a --- /dev/null +++ b/lib/lib/include/chapel.h @@ -0,0 +1,24 @@ +#ifndef l_chapel_h +#define l_chapel_h + +static void create(); + +mixed CanMarry(object who, object spouse1, object spouse2); +mixed CanSacrifice(object who, object what, string deus); + +mixed eventMarry(object who, object spouse1, object spouse2); +mixed eventSacrifice(object who, object what, string deus); + +int SetAllowSacrifice(int x); +int GetAllowSacrifice(); +string *SetClasses(string *rc); +string *GetClasses(); +string *SetDeities(string *deities); +string *GetDeities(); +string *SetReligion(string adj, string noun); +varargs string GetReligion(int flag); +int SetSacrificeType(int x); +int AddSacrificeType(int x); +int GetSacrificeType(); + +#endif /* l_chapel_h */ diff --git a/lib/lib/include/chat.h b/lib/lib/include/chat.h new file mode 100644 index 0000000..ea9f2b1 --- /dev/null +++ b/lib/lib/include/chat.h @@ -0,0 +1,20 @@ +#ifndef __CHAT_H__ +#define __CHAT_H__ + +static void create(); + +static string cache_commands(string str); +static void net_dead(); + +void eventReconnect(); +int eventDestruct(); + +string *AddChannel(mixed val); +string *RemoveChannel(mixed val); +string *GetChannels(); + +string *RestrictChannel(mixed val); +string *UnrestrictChannel(mixed val); +string *GetRestrictedChannels(); + +#endif /* __CHAT_H__ */ diff --git a/lib/lib/include/clan.h b/lib/lib/include/clan.h new file mode 100644 index 0000000..2627c3f --- /dev/null +++ b/lib/lib/include/clan.h @@ -0,0 +1,38 @@ + + +#ifndef l_clan_h +#define l_clan_h + + +class ClanClass { + string leader; + string name; + string objectName; + string skill; +} + +static void create(); +static void init(); + +mixed CanJoin(object ob); +string GetAffectLong(object ob); +string SetLeader(string str); +string GetLeader(); +string SetClanName(string str); +string GetClanName(); +string SetClanObject(string str); +string GetClanObject(); +string SetClanSkill(string str); +string GetClanSkill(); + +int eventBring(string str); +int eventInitiate(string str); +void eventJoin(object ob); +int eventRetire(string str); +void eventUnjoin(object ob); +void eventWelcome(object ob); + + +#endif /* l_clan_h */ + + diff --git a/lib/lib/include/classes.h b/lib/lib/include/classes.h new file mode 100644 index 0000000..acda9d5 --- /dev/null +++ b/lib/lib/include/classes.h @@ -0,0 +1,22 @@ +#ifndef l_classes_h +#define l_classes_h + +static void create(); + +int eventMoralAct(int degree); + +int AddSkillPoints(string skill, int x); +static string SetSkillModifier(string skill, string stat); +string GetSkillModifier(string skill); +string SetClass(string classes); +string GetClass(); +string SetClan(string clan); +string GetClan(); +int GetBaseStatLevel(string stat); +int SetMorality(int x); +int GetMorality(); +string GetMoralityDescription(); +string *SetReligion(string adj, string noun); +varargs string GetReligion(int flag); + +#endif /* l_classes_h */ diff --git a/lib/lib/include/client.h b/lib/lib/include/client.h new file mode 100644 index 0000000..370209e --- /dev/null +++ b/lib/lib/include/client.h @@ -0,0 +1,18 @@ +#ifndef __CLIENT_H__ +#define __CLIENT_H__ + +int eventCreateSocket(string host, int port); +static void eventAbortCallback(int fd); +static void eventReadCallback(int fd, mixed val); +static void eventRead(mixed val); +static void eventWriteCallback(int fd); +void eventWrite(mixed val); +static void eventClose(class client sock); +static void eventSocketClose(); +int eventDestruct(); +static void eventSocketError(string str, int x); +function SetRead(function f); +int SetSocketType(int x); +int SetDestructOnClose(int x); + +#endif /* __CLIENT_H__ */ diff --git a/lib/lib/include/clip.h b/lib/lib/include/clip.h new file mode 100644 index 0000000..503ae9a --- /dev/null +++ b/lib/lib/include/clip.h @@ -0,0 +1,18 @@ +#ifndef l_clip_h +#define l_clip_h + +static void create(); + +int PlusAmmo(int i); +int MinusAmmo(int i); +int SetMaxAmmo(int x); +int SetCaliber(int x); +int SetMillimeter(int x); +int SetPistolType(string str); +int SetAmmoType(string str); +string GetType(); +int GetCaliber(); +int GetMillimeter(); +string GetAmmoType(); + +#endif /* l_clip_h */ diff --git a/lib/lib/include/close.h b/lib/lib/include/close.h new file mode 100644 index 0000000..09ef6de --- /dev/null +++ b/lib/lib/include/close.h @@ -0,0 +1,23 @@ +#ifndef l_close_h +#define l_close_h + +static void create(); +int inventory_accessible(); +int inventory_visible(); +mixed direct_close_obj(object target, string id); +mixed direct_open_obj(object target, string id); +mixed direct_open_obj_with_obj(object target, object tool, string id); + +mixed CanClose(object who, string id); +mixed CanOpen(object who, string id); + +mixed eventClose(object who, string id); +varargs mixed eventOpen(object who, string id, object tool); + +int SetClosed(int x); +int GetClosed(); + +/* pure virtual */ static mixed *AddSave(mixed *vars); +/* pure virtual */ string GetShort(); + +#endif /* l_close_h */ diff --git a/lib/lib/include/combatmsg.h b/lib/lib/include/combatmsg.h new file mode 100644 index 0000000..3dfbb4e --- /dev/null +++ b/lib/lib/include/combatmsg.h @@ -0,0 +1,15 @@ +#ifndef l_combatmsg_h +#define l_combatmsg_h + +mixed GetMissData(object target, int type, string limb); +static void eventSendMissMessages(object target, int x, string limb); +mixed GetCombatVerbs(string type, int damage); +mixed GetCombatMove(string type, int skill); +varargs void SendMeleeMessages(object target, int x, string targlimb, string limb); +varargs void SendWeaponMessages(object target, int x, object weapon, string limb); + +/* virtual only */ +string GetName(); +varargs int eventPrint(string msg, mixed arg2, mixed arg3); + +#endif /* l_combatmsg_h */ diff --git a/lib/lib/include/command.h b/lib/lib/include/command.h new file mode 100644 index 0000000..7118a81 --- /dev/null +++ b/lib/lib/include/command.h @@ -0,0 +1,21 @@ +#ifndef __COMMAND_H__ +#define __COMMAND_H__ + +static void create(); +static string process_input(string cmd); + +static int cmdAll(string arg); + +int eventForce(string cmd); + +int Setup(); + +string *AddSearchPath(mixed val); +string *RemoveSearchPath(mixed val); +string *GetSearchPath(); +int GetForced(); +int GetClient(); +string SetCommandFail(string str); +string GetCommandFail(); + +#endif /* __COMMAND_H__ */ diff --git a/lib/lib/include/container.h b/lib/lib/include/container.h new file mode 100644 index 0000000..db02783 --- /dev/null +++ b/lib/lib/include/container.h @@ -0,0 +1,20 @@ +#ifndef l_container_h +#define l_container_h + +int CanReceive(object ob); +int CanRelease(object ob); + +int eventReceiveObject(); +int eventReleaseObject(); + +int GetAmbientLight(); +static int SetAmbientLight(int x); +string GetInternalLong(); +static string SetInternalLong(string str); +string GetInternalShort(); +static string SetInternalShort(string str); +int GetOpacity(); +int SetOpacity(int x); +int GetRadiantLight(int ambient); + +#endif /* l_container_h */ diff --git a/lib/lib/include/corpse.h b/lib/lib/include/corpse.h new file mode 100644 index 0000000..c6e88bc --- /dev/null +++ b/lib/lib/include/corpse.h @@ -0,0 +1,15 @@ +#ifndef l_corpse_h +#define l_corpse_h + +static void create(); + +int eventDecay(); +int eventDestruct(); + +int SetDecayLife(int x); +int GetDecayLife(); +void SetCorpse(object who); +string GetOwner(); +string GetRace(); + +#endif /* l_corpse_h */ diff --git a/lib/lib/include/creator.h b/lib/lib/include/creator.h new file mode 100644 index 0000000..f3ddf1b --- /dev/null +++ b/lib/lib/include/creator.h @@ -0,0 +1,32 @@ +#ifndef __CREATOR_H__ +#define __CREATOR_H__ + +static void create(); +static void net_dead(); +void restart_heart(); +mixed direct_can_give_liv_obj(); +mixed indirect_give_obj_to_liv(object item); + +int cmdListen(string str); +int cmdSearch(string str); +int cmdSmell(string str); +int cmdTouch(string str); + +int CanCarry(int amount); + +int eventForce(string cmd); +void eventDescribeEnvironment(int verbose); +varargs int eventMoveLiving(mixed dest, string omsg, string msg); +varargs mixed eventShow(object who, string str, string on_id); + +int Setup(); + +int GetCreatorAge(); +string SetGender(string gender); +string GetGender(); +varargs string GetLong(string blah); +int GetCreatorBirth(); +string GetNativeLanguage(); +int GetLanguageLevel(string whocares); + +#endif /* __CREATOR_H__ */ diff --git a/lib/lib/include/currency.h b/lib/lib/include/currency.h new file mode 100644 index 0000000..c0ec98e --- /dev/null +++ b/lib/lib/include/currency.h @@ -0,0 +1,18 @@ +#ifndef __CURRENCY_H__ +#define __CURRENCY_H__ + +static void create(); + +int CanCarry(int amount); + +int AddCarriedMass(int amount); +int AddCurrency(string type, int amount); +int GetCurrency(string type); +varargs int GetCurrencyMass(string type); +int AddBank(string bank, string type, int amount); +int GetBank(string bank, string type); +mapping GetAccountInfo(string bank); +int GetNetWorth(); +string *GetCurrencies(); + +#endif /* __CURRENCY_H__ */ diff --git a/lib/lib/include/detect.h b/lib/lib/include/detect.h new file mode 100644 index 0000000..e05450f --- /dev/null +++ b/lib/lib/include/detect.h @@ -0,0 +1,12 @@ +#ifndef __detect_h__ +#define __detect_h__ + +int direct_detect_wrd_in_obj(string word); +mixed eventDetect(object who, string str, int ability); + +/* virtuals */ + +mixed GetProperty(string str); +string GetShort(); + +#endif diff --git a/lib/lib/include/digging.h b/lib/lib/include/digging.h new file mode 100644 index 0000000..2cb670e --- /dev/null +++ b/lib/lib/include/digging.h @@ -0,0 +1,12 @@ +#ifndef l_digging_h +#define l_digging_h + +static void create(); +mixed indirect_bury_obj_with_obj(); +mixed direct_dig_with_obj(); +mixed indirect_dig_obj_with_obj(string id); + +mixed eventBury(object who, string what); +varargs mixed eventDig(object who, string what); + +#endif /* l_digging_h */ diff --git a/lib/lib/include/donate.h b/lib/lib/include/donate.h new file mode 100644 index 0000000..19bf557 --- /dev/null +++ b/lib/lib/include/donate.h @@ -0,0 +1,13 @@ +#ifndef l_donate_h +#define l_donate_h + +static void create(); +static void init(); +int GetAssets(); +int AddAssets(int amount); +string GetOwner(); +string SetOwner(string owner); +string SetLocalCurrency(string currency); +string GetLocalCurrency(); +int eventDonate(int amount, string type); +#endif /* l_donate_h */ diff --git a/lib/lib/include/door.h b/lib/lib/include/door.h new file mode 100644 index 0000000..91f5e0d --- /dev/null +++ b/lib/lib/include/door.h @@ -0,0 +1,28 @@ +#ifndef l_door_h +#define l_door_h + +static void create(); + +mixed CanLock(object who, string id); +mixed CanUnlock(object who, string id); + +varargs int eventClose(object by, string id); +mixed eventLock(object who, string id, object key); +varargs int eventOpen(object who, string id, object tool); +int eventRegisterSide(string side); +mixed eventUnlock(object who, string id, object key); + +void SetSide(string side, mapping mp); +int SetLockable(string side, int x); +int GetLockable(string side); +varargs string *SetId(string side, mixed *args...); +string *GetId(string side); +mixed SetShort(string side, mixed short); +varargs string GetShort(string side); +mixed SetLong(string side, mixed long); +string GetLong(string side); +varargs string *SetKeys(string side, mixed *args...); +string *GetKeys(string side); +object *GetRooms(string side); + +#endif /* l_door_h */ diff --git a/lib/lib/include/drop.h b/lib/lib/include/drop.h new file mode 100644 index 0000000..73f6fca --- /dev/null +++ b/lib/lib/include/drop.h @@ -0,0 +1,17 @@ +#ifndef l_drop_h +#define l_drop_h + +static void create(); +mixed direct_drop_obj(object target); + +mixed CanDrop(object who); + +mixed eventDrop(object who); + +mixed SetPreventDrop(mixed val); +mixed GetPreventDrop(); + +/* pure virtual */ int eventMove(mixed dest); +/* pure virtual */ string GetShort(); + +#endif /* l_drop_h */ diff --git a/lib/lib/include/editor.h b/lib/lib/include/editor.h new file mode 100644 index 0000000..0b92215 --- /dev/null +++ b/lib/lib/include/editor.h @@ -0,0 +1,7 @@ +#ifndef __EDITOR_H__ +#define __EDITOR_H__ + +varargs void eventEdit(string file, function callback); +static string process_input(string cmd); + +#endif /* __EDITOR_H__ */ diff --git a/lib/lib/include/exits.h b/lib/lib/include/exits.h new file mode 100644 index 0000000..c331ff8 --- /dev/null +++ b/lib/lib/include/exits.h @@ -0,0 +1,39 @@ +#ifndef l_exits_h +#define l_exits_h + +static void create(); + +mixed CanFly(object who, string dest); +mixed CanGo(object who, string str); + +mixed eventFly(object who, string dir); +mixed eventGo(object who, string str); + +mixed GetDoor(string dir); +string array GetDoors(); +string SetDoor(string dir, string file); +string GetDirection(string dest); +object GetDummyItem(mixed id); +varargs void AddEnter(string dir, string dest, function pre, function post); +string GetEnter(string dir); +static mapping GetEnterData(string str); +string array GetEnters(); +void RemoveEnter(string dir); +void SetEnters(mapping mp); +string GetEnterMessage(); +string SetEnterMessage(string str); +varargs mapping AddExit(string dir, string dest, function pre, function post); +string GetExit(string str); +static mapping GetExitData(string str); +string array GetExits(); +mapping RemoveExit(string dir); +mapping SetExits(mapping mp); +string GetGoMessage(); +string SetGoMessage(string str); +string GetObviousExits(); +string SetObviousExits(string str); +string GetSky(); +string SetSky(string str); +string ResolveObjectName(string file); + +#endif /* l_exits_h */ diff --git a/lib/lib/include/files.h b/lib/lib/include/files.h new file mode 100644 index 0000000..0b2faee --- /dev/null +++ b/lib/lib/include/files.h @@ -0,0 +1,8 @@ +#ifndef __FILES_H +#define __FILES_H + +string *wild_card(string str); +nomask static int remove_dots(string str); +string query_cwd(); + +#endif /* __FILES_H */ diff --git a/lib/lib/include/firearm.h b/lib/lib/include/firearm.h new file mode 100644 index 0000000..67bdf1b --- /dev/null +++ b/lib/lib/include/firearm.h @@ -0,0 +1,32 @@ +#ifndef l_pistol_h +#define l_pistol_h + +static void create(); + +int eventShoot(object who); + +int InitRevolver(mixed array); +int SetAmmoType(string str); +int SetFirearmType(string str); +int SetMaxAmmo(int x); +int SetCaliber(float f); +int SetMillimeter(int x); +string GetAmmoType(); +string GetFirearmType(); +int GetMaxAmmo(); +int GetCaliber(); +int GetMillimeter(); +int CalculateAmmoSize(); +int do_shoot(string str); +int missed_shot(); +int AddRound(int x); +int SubtractRound(int x); +int ShowRounds(); +int LoadRevolver(string str); +int LoadAuto(string str); +int doRevolverUnload(string foo, string bar); +int doAutoUnload(string str); +int UnloadAll(); +int SetAmmoFile(string str); + +#endif /* l_pistol_h */ diff --git a/lib/lib/include/fish.h b/lib/lib/include/fish.h new file mode 100644 index 0000000..d509630 --- /dev/null +++ b/lib/lib/include/fish.h @@ -0,0 +1,15 @@ +#ifndef l_fish_h +#define l_fish_h + +static void create(); + +int eventCatch(object who); + +int SetFight(int x); +int GetFight(); +string SetFood(string str); +string GetFood(); +int SetMass(int x); +int GetMass(); + +#endif /* l_fish_h */ diff --git a/lib/lib/include/fishing.h b/lib/lib/include/fishing.h new file mode 100644 index 0000000..e231c38 --- /dev/null +++ b/lib/lib/include/fishing.h @@ -0,0 +1,27 @@ +#ifndef l_fishing_h +#define l_fishing_h + +static void create(); +static void init(); +static void heart_beat(); + +mixed CanStop(object who, string str); +mixed CanCast(object who, string str); + +mixed eventCast(object who, object pole, string str); +static void eventCatch(object who, string fish, object pole); +mixed eventStop(object who, string str); + +int SetChance(int x); +int GetChance(); +mapping SetFish(mapping mp); +mapping RemoveFish(string fish); +mapping GetFish(); +mapping SetFishing(object who, object pole); +mapping RemoveFishing(object who); +int SetMaxFishing(int x); +int GetMaxFishing(); +int SetSpeed(int x); +int GetSpeed(); + +#endif /* l_fishing_h */ diff --git a/lib/lib/include/follow.h b/lib/lib/include/follow.h new file mode 100644 index 0000000..e960d29 --- /dev/null +++ b/lib/lib/include/follow.h @@ -0,0 +1,14 @@ +#ifndef l_follow_h +#define l_follow_h + +static void create(); +object SetLeader(object leader); +object GetLeader(); +varargs mixed CanFollow(object ob); +int IsFollowing(object ob); +int eventFollow(object dest, int followChance); + + +#endif /* l_follow_h */ + + diff --git a/lib/lib/include/fuel.h b/lib/lib/include/fuel.h new file mode 100644 index 0000000..98639ff --- /dev/null +++ b/lib/lib/include/fuel.h @@ -0,0 +1,21 @@ +#ifndef l_fuel_h +#define l_fuel_h + +static void create(); + +mixed eventDecreaseFuel(int x); +mixed eventRefuel(int x); + +int GetFuelAmount(); +static int SetFuelAmount(int x); +string GetFuelType(); +static string SetFuelName(string str); +varargs string GetLong(string val); +int GetMaxFuel(); +static int SetMaxFuel(int x); +int GetRefuelable(); +static int SetRefuelable(int x); + +/* pure virtual */ string GetShort(); + +#endif /* l_fuel_h */ diff --git a/lib/lib/include/genetics.h b/lib/lib/include/genetics.h new file mode 100644 index 0000000..2d1a774 --- /dev/null +++ b/lib/lib/include/genetics.h @@ -0,0 +1,33 @@ +#ifndef l_genetics_h +#define l_genetics_h + +static void create(); + +mixed eventCustomizeStat(string stat, int amount); + +varargs void SetStat(string stat, int level, int classes); +varargs void AddStat(string stat, int base, int cls); +mapping GetStat(string stat); +int GetStatClass(string stat); +int GetBaseStatLevel(string stat); +int GetStatLevel(string stat); +int AddStatPoints(string stat, int x); +string *GetStats(); +int GetMaxStatPoints(string stat, int level); +void AddStatBonus(string stat, function f); +varargs void RemoveStatBonus(string stat, object ob); +int GetStatBonus(string stat); +varargs string SetResistance(int type, string level); +string GetResistance(int type); +int GetCustomStats(); +varargs mixed GetEffectiveVision(mixed location, int raw_score); +int array GetLightSensitivity(); +varargs int array SetLightSensitivity(mixed array val...); +int AddVisionBonus(int x); +int GetVisionBonus(); + +/* pure virtual */ int GetLevel(); +/* pure virtual */ int GetAlcohol(); +/* pure virtual */ int GetRadiantLight(int ambient); + +#endif /* l_genetics_h */ diff --git a/lib/lib/include/get.h b/lib/lib/include/get.h new file mode 100644 index 0000000..d12b626 --- /dev/null +++ b/lib/lib/include/get.h @@ -0,0 +1,19 @@ +#ifndef l_get_h +#define l_get_h + +static void create(); +mixed direct_get_obj(object target); +mixed direct_get_obj_from_obj(object target, object src); +mixed direct_get_obj_out_of_obj(object target, object src); + +mixed CanGet(object who); + +mixed SetPreventGet(mixed val); +mixed GetPreventGet(); + +/* pure virtual */ int eventMove(mixed dest); +/* pure virtual */ int GetMass(); +/* pure virtual */ mixed GetProperty(string prop); +/* pure virtual */ string GetShort(); + +#endif /* l_get_h */ diff --git a/lib/lib/include/help.h b/lib/lib/include/help.h new file mode 100644 index 0000000..d96e42a --- /dev/null +++ b/lib/lib/include/help.h @@ -0,0 +1,9 @@ +#ifndef l_help_h +#define l_help_h + +static void create(); + +static string SetHelp(string str); +string GetHelp(string str); + +#endif /* l_help_h */ diff --git a/lib/lib/include/history.h b/lib/lib/include/history.h new file mode 100644 index 0000000..d883d6f --- /dev/null +++ b/lib/lib/include/history.h @@ -0,0 +1,11 @@ +#ifndef l_history_h +#define l_history_h + +static string eventHistory(string str); +nomask private static string Push(string cmd); +private string GetHistory(mixed val); + +/* pure abstract */ varargs int eventPrint(string msg, int cl); +/* pure abstract */ string GetKeyName(); + +#endif /* l_history_h */ diff --git a/lib/lib/include/holder.h b/lib/lib/include/holder.h new file mode 100644 index 0000000..a554ee5 --- /dev/null +++ b/lib/lib/include/holder.h @@ -0,0 +1,39 @@ +#ifndef l_holder_h +#define l_holder_h + +static void create(); +varargs void reset(int count); +int inventory_accessible(); +int inventory_visible(); +mixed indirect_get_obj_from_obj(object item); +mixed indirect_get_obj_out_of_obj(object item); +mixed indirect_get_obs_from_obj(object *item, object storage); +mixed indirect_get_obs_out_of_obj(object *item, object storage); +mixed direct_look_in_obj(object target, string id); +mixed direct_look_inside_obj(object target, string id); +mixed indirect_look_at_obj_word_obj(object target, string wrd, object ob, + string id, string my_id); +mixed indirect_put_obj_word_obj(object what, string word, object storage); +mixed indirect_put_obs_word_obj(object *items, string word, object storage); + +mixed CanPutIn(object who, object what); +varargs mixed CanShowInterior(object who, object what); + +mixed eventGetFrom(object who, object *what); +mixed eventPutIn(object who, object what); +int eventReceiveObject(); +int eventReleaseObject(); +mixed eventShowInterior(object who); + +mapping SetInventory(mapping inv); +mapping GetInventory(); +varargs string GetLong(string str); +int SetMaxCarry(int x); +int GetMaxCarry(); + +/* pure virtual */ int GetInvis(object ob); +/* pure virtual */ static mixed *AddSave(mixed *vars); +/* pure virtual */ int SetSaveRecurse(int x); +/* pure virtual */ string GetShort(); + +#endif /* l_holder_h */ diff --git a/lib/lib/include/interactive.h b/lib/lib/include/interactive.h new file mode 100644 index 0000000..51e4943 --- /dev/null +++ b/lib/lib/include/interactive.h @@ -0,0 +1,64 @@ +#ifndef l_interactive_h +#define l_interactive_h + +static void create(); +int inventory_accessible(); +int inventory_visible(); + +mixed CanDivorce(); +mixed CanGet(); +mixed CanMarry(); + +int Setup(); +static void net_dead(); +void eventReconnect(); +void eventDescribeEnvironment(int brief); +int eventDestruct(); +mixed eventDivorce(); +mixed eventMarry(object who, object to_whom); +int eventMove(mixed dest); +void cmdParseRefresh(); +int cmdQuit(); +int GetAge(); +int GetBirth(); +string query_cwd(); +void SetEmail(string str); +string GetEmail(); +void SetId(string *bogus); +string *GetId(); +int id(string str); +int GetLoginTime(); +string SetKeyName(string str); +string GetKeyName(); +void SetNews(string type, int sz); +int GetNews(string type); +void SetPassword(string str); +string GetPassword(); +void SetRank(string str); +string GetRank(); +void SetRealName(string str); +string GetRealName(); +string GetShort(); +string GetLong(); +int SetBriefMode(int x); +int GetBriefMode(); +int SetWhereBlock(); +int GetWhereBlock(); +string get_path(); +void SetLastError(mapping m); +mapping GetLastError(); +void SetCapName(string str); +void move_or_destruct(); +string SetShort(string str); +string SetLong(string str); +string GetName(); +varargs int GetInvis(object ob); +mixed *GetCommands(); +string GetSpouse(); +int GetRadiantLight(int ambient); + +void eventLoad(mixed *value, int recurse); + +/* pure virtual */ varargs mixed GetEffectiveVision(mixed location, int raw_score); + +#endif /* l_interactive_h */ diff --git a/lib/lib/include/interface.h b/lib/lib/include/interface.h new file mode 100644 index 0000000..7d5433d --- /dev/null +++ b/lib/lib/include/interface.h @@ -0,0 +1,28 @@ +#ifndef __INTERFACE_H__ +#define __INTERFACE_H__ + +static void create(); +static string process_input(string str); +static void terminal_type(string str); +static void window_size(int width, int height); +void receive_message(string msg_class, string msg); +static void receive_snoop(string msg); + +varargs int eventPrint(string msg, mixed arg2, mixed arg3); + +static string cache_commands(string str); +int Setup(); + +varargs int SetBlocked(string type, int flag); +int GetBlocked(string type); +int SetClient(int x); +int GetClient(); +int SetLogHarass(int x); +int GetLogHarass(); +int *SetScreen(int width, int height); +int *GetScreen(); +string SetTerminal(string terminal); +string GetTerminal(); +string GetKeyName(); + +#endif /* __TERMINAL_H__ */ diff --git a/lib/lib/include/item.h b/lib/lib/include/item.h new file mode 100644 index 0000000..fc7e5a8 --- /dev/null +++ b/lib/lib/include/item.h @@ -0,0 +1,52 @@ +#ifndef l_item_h +#define l_item_h + +static void create(); +static void init(); +varargs void reset(int count); +mixed direct_bury_obj_with_obj(); +mixed indirect_give_liv_obj(object target); +mixed direct_give_obj_to_liv(); +mixed direct_look_at_obj(string id); +mixed direct_look_at_obj_word_obj(string my_id, string id); +mixed direct_poison_obj_with_obj(); + +mixed CanSteal(object who); +mixed CanEnter(object who, string what); +int CanSell(); +varargs mixed CanThrow(object who, object target); +mixed CanRepair(object who); + +mixed eventDetect(object who, string str, int ability); +int eventMove(mixed dest); +int eventReceiveDamage(object agent, int type, int amount, int unused, mixed limbs); +int eventBless(int amount, int time); +void eventRemoveBlessing(); +varargs mixed eventShow(object who, string str, string on_id); +varargs mixed eventThrow(object who, object target); +mixed eventPoison(object who, object agent, int strength); +varargs mixed eventRepair(object who, int strength, int type); + +static int Destruct(); + +string GetWornDescription(); +string GetItemCondition(); +int SetMass(int x); +int GetMass(); +int GetWeight(); +int SetDestroyOnSell(int x); +int GetDestroyOnSell(); +int SetValue(int x); +int GetValue(); +int SetVendorType(int type); +int GetVendorType(); +int SetDamagePoints(int x); +int GetDamagePoints(); +int SetBroken(int x); +int GetBroken(); +int AddPoison(int x); +int GetPoison(); +int SetRetainOnDeath(int x); +int GetRetainOnDeath(); + +#endif /* l_item_h */ diff --git a/lib/lib/include/items.h b/lib/lib/include/items.h new file mode 100644 index 0000000..a7cb1e6 --- /dev/null +++ b/lib/lib/include/items.h @@ -0,0 +1,16 @@ +#ifndef l_items_h +#define l_items_h + +static void create(); +mixed direct_look_at_str_on_obj(string str, object target); + +varargs mixed eventShow(object who, string component); + +mapping SetItems(mapping items); +varargs mixed AddItem(mixed item, mixed val); +mapping RemoveItem(mixed item); +varargs mixed GetLong(string item); + +/* pure virtual */ string GetShort(); + +#endif /* l_items_h */ diff --git a/lib/lib/include/jump.h b/lib/lib/include/jump.h new file mode 100644 index 0000000..ab67a6a --- /dev/null +++ b/lib/lib/include/jump.h @@ -0,0 +1,21 @@ +#ifndef l_jump_h +#define l_jump_h + +static void create(); + +mixed direct_jump_word_obj(string prep, object target, string id); +varargs mixed direct_jump_word_word_obj(mixed args...); + +mixed CanJump(object who, string id, int type); + +mixed eventJump(object who, string id, int type); + +mapping SetJump(function f, int type); +varargs mapping AddJump(string dir, mixed dest, int type); +mixed GetJumpDestination(string dir); +int *GetJumpType(string dir); +string *GetJumps(); + +/* pure virtual */ string *GetId(); + +#endif /* l_jump_h */ diff --git a/lib/lib/include/key.h b/lib/lib/include/key.h new file mode 100644 index 0000000..99707a1 --- /dev/null +++ b/lib/lib/include/key.h @@ -0,0 +1,22 @@ +#ifndef l_key_h +#define l_key_h + +static void create(); +mixed indirect_lock_obj_with_obj(object target, object key, string id); +mixed indirect_unlock_obj_with_obj(object target, object key, string id); + +mixed CanLockLock(object who, string id, object what); +mixed CanUnlockLock(object who, string id, object what); + +mixed eventLockLock(object who, string id, object what); +mixed eventUnlockLock(object who, string id, object what); + +int SetDisableChance(int x); +int GetDisableChance(); +int SetDisabled(int x); +int GetDisabled(); + +/* pure vitual */ static mixed *AddSave(mixed *vars); +/* pure virtual */ string GetShort(); + +#endif /* l_key_h */ diff --git a/lib/lib/include/lamp.h b/lib/lib/include/lamp.h new file mode 100644 index 0000000..8393052 --- /dev/null +++ b/lib/lib/include/lamp.h @@ -0,0 +1,19 @@ +#ifndef l_lamp_h +#define l_lamp_h + +static void create(); +static void heart_beat(); + +mixed direct_light_obj(); + +mixed eventDarken(); +varargs mixed eventLight(object who, object tool); + +int GetBurnRate(); +static int SetBurnRate(int x); +int GetRadiantLight(int ambient); +string GetShort(); +varargs string GetLong(string unused); + +#endif /* l_lamp_h */ + diff --git a/lib/lib/include/lead.h b/lib/lib/include/lead.h new file mode 100644 index 0000000..cdac5d9 --- /dev/null +++ b/lib/lib/include/lead.h @@ -0,0 +1,23 @@ +#ifndef l_lead_h +#define l_lead_h + +static void create(); +object *AddFollower(object follower); +object *RemoveFollower(object follower); +object *GetFollowers(); + +int SetFollowed(object follower, int followed); +int GetFollowed(object follower); +int AddFollowBonus(object follower, int bonus); +int GetFollowBonus(object follower); + +varargs mixed CanLead(object ob); +varargs mixed CanEvade(object ob); + +int eventMoveFollowers(object dest); +int eventEvade(object ob); + + +#endif /* l_lead_h */ + + diff --git a/lib/lib/include/leader.h b/lib/lib/include/leader.h new file mode 100644 index 0000000..90dbed3 --- /dev/null +++ b/lib/lib/include/leader.h @@ -0,0 +1,11 @@ +#ifndef l_leader_h +#define l_leader_h + +static void create(); +mixed eventAsk(object who, string what); +void eventConvert(object who, string args); +void eventPreview(object who, string args); +void eventJoin(object who, string args); +int eventPreAttack(object ob); + +#endif /* l_leader_h */ diff --git a/lib/lib/include/light.h b/lib/lib/include/light.h new file mode 100644 index 0000000..bc399f4 --- /dev/null +++ b/lib/lib/include/light.h @@ -0,0 +1,17 @@ +#ifndef l_light_h +#define l_light_h + +static void create(); + +mixed direct_light_obj(object target); + +mixed eventDarken(); +varargs mixed eventLight(object who, object tool); + +int GetLit(); +static int SetLit(int x); +string GetShort(); + +/* pure virtual */ string GetKeyName(); + +#endif /* l_light_h */ diff --git a/lib/lib/include/limb.h b/lib/lib/include/limb.h new file mode 100644 index 0000000..643665a --- /dev/null +++ b/lib/lib/include/limb.h @@ -0,0 +1,15 @@ +#ifndef __LIMB_H__ +#define __LIMB_H__ + +static void create(); + +int eventDecay(); + +int SetDecayLife(int x); +int GetDecayLife(); +void SetLimb(string limb, string owner, string race); +string GetLimb(); +string GetOwner(); +string GetRace(); + +#endif /* __LIMB_H__ */ diff --git a/lib/lib/include/listen.h b/lib/lib/include/listen.h new file mode 100644 index 0000000..566abd1 --- /dev/null +++ b/lib/lib/include/listen.h @@ -0,0 +1,10 @@ +#ifndef l_listen_h +#define l_listen_h + +static void create(); +varargs mixed SetListen(mixed arg1, mixed desc); +mapping RemoveListen(string item); +string GetListen(string str); +string *GetListens(); + +#endif /* l_listen_h */ diff --git a/lib/lib/include/living.h b/lib/lib/include/living.h new file mode 100644 index 0000000..adffadb --- /dev/null +++ b/lib/lib/include/living.h @@ -0,0 +1,26 @@ +#ifndef l_living_h +#define l_living_h + +static void create(); +int is_living(); +int inventory_accessible(); +int inventory_visible(); +mixed direct_give_liv_obj(); +mixed indirect_give_obj_to_liv(object item); +mixed direct_give_liv_wrd_wrd(object target, string num, string curr); +mixed direct_give_wrd_wrd_to_liv(string num, string curr); +mixed direct_look_at_obj(); +mixed direct_steal_wrd_from_liv(string str); +mixed indirect_steal_obj_from_liv(object item, mixed args...); + +int eventFollow(object dest, int followChance); +varargs mixed CanCastMagic(int hostile, string spell); +mixed CanReceiveMagic(int hostile, string spell); + +int SetPK(int x); +int GetPK(); + +/* pure virtual */int eventForce(string str); +/* pure virtual */ mixed GetProperty(string prop); + +#endif /* l_living_h */ diff --git a/lib/lib/include/lock.h b/lib/lib/include/lock.h new file mode 100644 index 0000000..add4df3 --- /dev/null +++ b/lib/lib/include/lock.h @@ -0,0 +1,32 @@ +#ifndef l_lock_h +#define l_lock_h + +static void create(); +mixed direct_lock_obj_with_obj(object target, object tool, string id); +mixed direct_pick_str_on_obj(string str, object target, string str2, + string id); +mixed direct_pick_str_on_obj_with_obj(string str, object target, object tool, + string str2, string targ_id); +mixed direct_unlock_obj_with_obj(object target, object key, string id); + +mixed CanLock(object who, string id); +mixed CanOpen(object who, string id); +mixed CanPick(object who, string id); +varargs mixed CanUnlock(object who, string id, object key); + +mixed eventLock(object who, string id, object key); +varargs mixed eventOpen(object who, string id, object tool); +varargs mixed eventPick(object who, string id, object tool); +mixed eventUnlock(object who, string id, object key); + +varargs string *SetKeys(mixed *args...); +string *AddKey(string key); +varargs string *GetKeys(string unused); +int SetLocked(int x); +int GetLocked(); +int SetLockStrength(int x); +int GetLockStrength(); +function SetPick(function f); +function GetPick(); + +#endif /* l_lock_h */ diff --git a/lib/lib/include/match.h b/lib/lib/include/match.h new file mode 100644 index 0000000..6b2638c --- /dev/null +++ b/lib/lib/include/match.h @@ -0,0 +1,9 @@ +#ifndef l_match_h +#define l_match_h + +mixed direct_strike_obj(); +mixed eventStrike(object who); +int GetStrikeChance(); +static int SetStrikeChance(int x); + +#endif /* l_match_h */ diff --git a/lib/lib/include/meal.h b/lib/lib/include/meal.h new file mode 100644 index 0000000..209ee2f --- /dev/null +++ b/lib/lib/include/meal.h @@ -0,0 +1,29 @@ +#ifndef l_meal_h +#define l_meal_h + +static void create(); +mixed direct_drink_obj(); +mixed direct_drink_from_obj(); +mixed direct_eat_obj(); + +mixed eventDrink(object who); +mixed eventEat(object who); +mixed eventPoison(object who, object agent, int x); + +string SetEmptyItem(string file); +string GetEmptyItem(); +string SetEmptyName(string str); +string GetEmptyName(); +mixed SetEmptyShort(mixed str); +mixed GetEmptyShort(); +mixed SetEmptyLong(mixed str); +mixed GetEmptyLong(); +int SetMealType(int x); +int GetMealType(); +int SetStrength(int x); +int GetStrength(); +varargs void SetMealMessages(mixed array val...); +mixed *GetMessages(); +int GetValue(); + +#endif /* l_meal_h */ diff --git a/lib/lib/include/messages.h b/lib/lib/include/messages.h new file mode 100644 index 0000000..dda42a1 --- /dev/null +++ b/lib/lib/include/messages.h @@ -0,0 +1,11 @@ +#ifndef __MESSAGES_H__ +#define __MESSAGES_H__ + +static void create(); + +string SetMessage(string msg, string str); +varargs string GetMessage(string msg, mixed arg); +string GetName(); +mapping GetMessages(); + +#endif /* __MESSAGES_H__ */ diff --git a/lib/lib/include/money.h b/lib/lib/include/money.h new file mode 100644 index 0000000..ab7d540 --- /dev/null +++ b/lib/lib/include/money.h @@ -0,0 +1,13 @@ +#ifndef __MONEY_H__ +#define __MONEY_H__ + +static void create(); +static void init(); + +int eventMove(mixed dest); + +int AddCurrency(string curr, int x); +int GetCurrency(string curr); +string GetMoneyLong(string str); + +#endif /* __MONEY_H__ */ diff --git a/lib/lib/include/nmsh.h b/lib/lib/include/nmsh.h new file mode 100644 index 0000000..adf9ec7 --- /dev/null +++ b/lib/lib/include/nmsh.h @@ -0,0 +1,39 @@ +#ifndef __NMSH_H +#define __NMSH_H + +int Setup(); +nomask static int cmd_alias(string str); +nomask static int cmd_cd(string str); +nomask static int cmd_nickname(string str); +nomask static int cmd_nmsh(string str); +nomask static int cmd_pushd(string str); +nomask static int cmd_popd(); +nomask string write_prompt(); +nomask string process_input(string str); +nomask static void process_request(string request, string xtra); +static int request_vis(object ob); +static string user_name(object ob); +static private int set_cwd(string str); +static private void pushd(string str); +static private string popd(); +nomask static private string do_nickname(string str); +nomask static private string do_alias(string str); +nomask static string replace_nickname(string str); +void reset_prompt(); +string query_cwd(); +string GetPrompt(); +int query_mp(); +int query_max_mp(); +int query_hp(); +int query_max_hp(); +int query_sp(); +int query_max_sp(); +string get_path(); +string GetClient(); +varargs int GetInvis(object ob); +string GetKeyName(); +static string cache_commands(string str); + +#endif /* __NMSH_H */ + + diff --git a/lib/lib/include/npc.h b/lib/lib/include/npc.h new file mode 100644 index 0000000..fd70304 --- /dev/null +++ b/lib/lib/include/npc.h @@ -0,0 +1,72 @@ +#ifndef l_npc_h +#define l_npc_h + +static void create(); +static void init(); +static void heart_beat(); +void receive_message(string cl, string msg); +void catch_tell(string msg); +void restart_heart(); +int is_living(); +int inventory_accessible(); +int inventory_visible(); + +int cmdListen(string str); +int cmdSearch(string str); +int cmdSmell(string str); +int cmdTouch(string str); +static int cmdAll(string arg); + +varargs int eventDie(mixed agent); +int eventMove(mixed dest); +int eventCompleteMove(mixed dest); +int eventFollow(object dest, int followChance); +varargs int eventMoveLiving(mixed dest, string omsg, string imsg); +int eventReceiveObject(); +int eventReleaseObject(); +int eventDestruct(); +void eventEnemyDied(object ob); +varargs int eventShow(object who, string str); + +int CanCarry(int amount); +int CanReceive(object ob); + +static int ContinueHeart(); + +mapping SetInventory(mapping mp); +varargs string SetRace(string race, mixed extra); +string SetClass(string cls); +int SetLevel(int x); +int GetLevel(); +int SetHealthPoints(int x); +int SetMaxHealthPoints(int x); +int SetMagicPoints(int x); +float SetStaminaPoints(mixed x); +float SetMaxStaminaPoints(float x); +varargs void SetCurrency(mixed val, int amount); +int GetMaxCarry(); +mixed SetEncounter(mixed val); +string *AddEncounter(string nom); +string *RemoveEncounter(string nom); +mixed GetEncounter(); +mixed SetDie(mixed val); +mixed GetDie(); +string SetKeyName(string nom); +string GetName(); +string GetCapName(); +string GetShort(); +varargs string GetLong(string str); +int GetCarriedMass(); +void SetAction(int chance, mixed val); +mixed GetAction(); +void SetCombatAction(int chance, mixed val); +mixed GetCombatAction(); +int AddCarriedMass(int x); +mixed *GetCommands(); +int SetUnique(int x); +int GetUnique(); +string GetCommandFail(); +string *GetEnemyNames(); +int GetRadiantLight(int ambient); + +#endif l_npc_h diff --git a/lib/lib/include/pager.h b/lib/lib/include/pager.h new file mode 100644 index 0000000..a599b01 --- /dev/null +++ b/lib/lib/include/pager.h @@ -0,0 +1,16 @@ +#ifndef l_pager_h +#define l_pager_h + +varargs mixed eventPage(mixed val, string msg_class, function f,mixed args...); +static void Page(mapping file); +static void cmdPage(string str, mapping file); +varargs static private void RazzleDazzle(mixed args...); +static private string GetPagerPrompt(mapping file); +string GetHelp(string str); +/* pure virtual */ varargs int eventPrint(string msg, mixed arg2, mixed arg3); +/* pure virtual */ int *GetScreen(); +#if 0 +/* pure virtual */ string *wild_card(string str); +#endif + +#endif /* l_pager_h */ diff --git a/lib/lib/include/persist.h b/lib/lib/include/persist.h new file mode 100644 index 0000000..d864101 --- /dev/null +++ b/lib/lib/include/persist.h @@ -0,0 +1,14 @@ +#ifndef l_persist_h +#define l_persist_h + +static int eventConvertObject(mixed val, int recurse); +int eventLoadObject(mixed val, int recurse); + +static mixed *AddSave(mixed *vars); +mixed *GetSave(); +static int SetSaveRecurse(int flag); +string GetSaveString(); + +/* pure virtual */int eventMove(mixed dest); + +#endif /* l_persist_h */ diff --git a/lib/lib/include/pile.h b/lib/lib/include/pile.h new file mode 100644 index 0000000..169a079 --- /dev/null +++ b/lib/lib/include/pile.h @@ -0,0 +1,19 @@ +#ifndef l_pile_h +#define l_pile_h + +static void create(); +static void init(); +mixed direct_get_wrd_wrd_from_obj(string num, string curr); +mixed direct_get_wrd_wrd_out_of_obj(string num, string curr); + +mixed eventGetMoney(object who, int amount, string curr); + +string *GetId(); +string GetShort(); +varargs string GetLong(string str); +void SetPile(string str, int amt); +string GetPileType(); +int GetPileAmount(); +int GetMass(); + +#endif /* l_pile_h */ diff --git a/lib/lib/include/pistol.h b/lib/lib/include/pistol.h new file mode 100644 index 0000000..c8e3bde --- /dev/null +++ b/lib/lib/include/pistol.h @@ -0,0 +1,6 @@ +#ifndef l_pistol_h +#define l_pistol_h + +static void create(); + +#endif /* l_pistol_h */ diff --git a/lib/lib/include/player.h b/lib/lib/include/player.h new file mode 100644 index 0000000..e31b9c9 --- /dev/null +++ b/lib/lib/include/player.h @@ -0,0 +1,67 @@ +#ifndef l_player_h +#define l_player_h + +class death { + int Date; + string Enemy; +} + +static void create(); +static void heart_beat(); +static void net_dead(); +void eventReconnect(); + +int cmdListen(string str); +int cmdSearch(string str); +int cmdTouch(string str); + +int eventDisplayStatus(); +varargs int eventDie(mixed agent); +mixed eventAsk(object who, string what); +void eventRevive(); +varargs int eventShow(object who, string str); +int eventMove(mixed dest); +int eventFollow(object dest, int followChance); +varargs int eventMoveLiving(mixed dest, string omsg, string imsg); +int eventReceiveObject(); +int eventReleaseObject(); +void eventLoad(mixed *value, int recurse); +mixed eventUse(object used, string cmd); + +int CanCarry(int amount); +int CanReceive(object ob); +mixed CanUse(); + +int Setup(); + +int AddCurrency(string type, int amount); +int AddBank(string bank, string type, int amount); +int GetMaxCarry(); +string *SetTitles(string *titles); +string *AddTitle(string title); +string *RemoveTitle(string title); +string *GetTitles(); +void AddQuest(string title, string desc); +mixed *GetQuests(); +string SetShort(string irrelevant); +int SetUndead(int x); +string GetName(); +varargs string GetLong(string str); +int AddCarriedMass(int x); +int GetCarriedMass(); +string GetCapName(); +int ResetLevel(); +string SetClass(string str); +string SetClan(string clan); +varargs static int AddHealthPoints(int x, string limb, object agent); +int GetLanguageLevel(string lang); +int is_living(); +mapping *GetDeaths(); +int GetTrainingPoints(); +int AddTrainingPoints(int x); +int RemoveTrainingPoints(int x); +varargs int eventTrainSkill(string skill, int points); + +#endif /* l_player_h */ + + diff --git a/lib/lib/include/poison.h b/lib/lib/include/poison.h new file mode 100644 index 0000000..02657e8 --- /dev/null +++ b/lib/lib/include/poison.h @@ -0,0 +1,14 @@ +#ifndef l_poison_h +#define l_poison_h + +static void create(); +mixed indirect_poison_obj_with_obj(); + +mixed eventSpreadPoison(object who, object target); + +int SetPoisonStrength(int x); +int GetPoisonStrength(); +int SetPoisonUses(int x); +int GetPoisonUses(); + +#endif /* l_poison_h */ diff --git a/lib/lib/include/pole.h b/lib/lib/include/pole.h new file mode 100644 index 0000000..ff85666 --- /dev/null +++ b/lib/lib/include/pole.h @@ -0,0 +1,32 @@ +#ifndef l_pole_h +#define l_pole_h + +static void create(); +mixed direct_bait_obj_with_obj(); +mixed direct_fish_with_obj(); + +mixed CanCast(object who); + +int eventBait(object who, object bait); +int eventBreak(); +mixed eventCatch(object who, string fish); +int eventFish(object who); + +int SetBait(int x); +int AddBait(int x); +int GetBait(); +int SetChance(int x); +mixed GetProperty(string foo); +int GetChance(); +int SetStrength(int x); +int GetStrength(); + +/* virtual functions */ + +mixed AddSave(mixed *vars); +string GetShort(); +int SetBroken(int x); +int GetBroken(); + + +#endif /* l_pole_h */ diff --git a/lib/lib/include/post_office.h b/lib/lib/include/post_office.h new file mode 100644 index 0000000..46d904e --- /dev/null +++ b/lib/lib/include/post_office.h @@ -0,0 +1,10 @@ +#ifndef l_post_office_h +#define l_post_office_h + +static void create(); +mixed CanMail(object who, string args); +mixed eventMail(object who, string args); +int CanReceive(object ob); +int eventReleaseObject(); + +#endif /* l_post_office_h */ diff --git a/lib/lib/include/press.h b/lib/lib/include/press.h new file mode 100644 index 0000000..26c4440 --- /dev/null +++ b/lib/lib/include/press.h @@ -0,0 +1,18 @@ +#ifndef l_press_h +#define l_press_h + +static void create(); +mixed direct_press_obj(object target); +mixed direct_press_str_on_obj(string str, object target); + +varargs mixed CanPress(object who, string component); +varargs mixed eventPress(object who, string component); + +varargs mapping SetPress(mixed key, mixed desc); +mapping RemovePress(string item); +mixed GetPress(string str); +string array GetPresses(); + +/* pure virtual */ string GetShort(); + +#endif /* l_press_h */ diff --git a/lib/lib/include/put.h b/lib/lib/include/put.h new file mode 100644 index 0000000..882f4ca --- /dev/null +++ b/lib/lib/include/put.h @@ -0,0 +1,18 @@ +#ifndef l_put_h +#define l_put_h + +static void create(); +mixed direct_put_obj_word_obj(); + +mixed CanPut(object who); + +mixed eventPut(object who, object storage); + +mixed SetPreventPut(mixed val); +mixed GetPreventPut(); + +/* pure virtual */ mixed CanDrop(object who); +/* pure virtual */ int eventMove(mixed dest); +/* pure virtual */ string GetShort(); + +#endif /* l_put_h */ diff --git a/lib/lib/include/race.h b/lib/lib/include/race.h new file mode 100644 index 0000000..6ab83fb --- /dev/null +++ b/lib/lib/include/race.h @@ -0,0 +1,34 @@ +#ifndef l_race_h +#define l_race_h + +static void create(); + +mixed CanDrink(object ob); +mixed CanEat(object ob); + +varargs int eventDie(mixed agent); +mixed eventDrink(object ob); +mixed eventEat(object ob); + +varargs string SetRace(string race, mixed extra); +string GetRace(); +string SetGender(string gender); +string GetGender(); +varargs void SetStat(string stat, int level, int classes); +varargs int GetMaxHealthPoints(string limb); +int GetMaxMagicPoints(); +float GetMaxStaminaPoints(); +void NewBody(string race); +string SetTown(string str); +string GetTown(); +int GetLuck(); +int GetMobility(); +int GetCarriedMass(); +int GetMaxCarry(); +int GetHeartRate(); +int GetHealRate(); +int GetStatLevel(string stat); +int GetAlcohol(); + +#endif /* l_race_h */ + diff --git a/lib/lib/include/read.h b/lib/lib/include/read.h new file mode 100644 index 0000000..79ad07c --- /dev/null +++ b/lib/lib/include/read.h @@ -0,0 +1,16 @@ +#ifndef l_read_h +#define l_read_h + +static void create(); + +mixed direct_read_obj(); +mixed direct_read_str_word_obj(string str); + +mixed CanRead(object who, string str); + +varargs mixed SetRead(mixed arg1, mixed desc); +mapping RemoveRead(string item); +mixed GetRead(string str); +string *GetReads(); + +#endif /* l_read_h */ diff --git a/lib/lib/include/room.h b/lib/lib/include/room.h new file mode 100644 index 0000000..7293e8a --- /dev/null +++ b/lib/lib/include/room.h @@ -0,0 +1,45 @@ +#ifndef l_room_h +#define l_room_h + +static void create(); +varargs void reset(int count); +static void init(); +int id(string str); + +varargs mixed eventHearTalk(object who, object target, int cls, string verb, string msg, string lang); +int eventMove(mixed dest); +varargs int eventPrint(string msg, mixed arg2, mixed arg3); +varargs int eventShow(object who, string str); +int CanAttack(object attacker, object who); + +static void LoadInventory(); + +int GetAmbientLight(); +void SetShort(string str); +void SetLong(string str); +string GetShort(); +varargs string GetLong(string str); +object *AddExtraLong(object ob); +string GetExtraLong(); +int GetResetNumber(); +string *GetId(); +string SetDayLong(string str); +string GetDayLong(); +string SetNightLong(string str); +string GetNightLong(); +string SetClimate(string str); +string GetClimate(); +float SetGravity(float h); +float GetGravity(); +mapping SetInventory(mapping mp); +mapping GetInventory(); +int GetDayLight(); +static int SetDayLight(int x); +int GetNightLight(); +static int SetNightLight(int x); +int SetNoReplace(int x); +int GetNoReplace(); +int GetShade(); +static int SetShade(int x); + +#endif /* l_room_h */ diff --git a/lib/lib/include/round.h b/lib/lib/include/round.h new file mode 100644 index 0000000..ae30f5e --- /dev/null +++ b/lib/lib/include/round.h @@ -0,0 +1,17 @@ +#ifndef l_round_h +#define l_round_h + +static void create(); + +int SetCaliber(int x); +int SetMillimeter(int x); +int SetPistolType(string str); +int SetAmmoType(string str); +int SetRifleType(string str); +string GetType(); +int GetCaliber(); +int GetMillimeter(); +string GetAmmoType(); +string GetRifleType(); + +#endif /* l_round_h */ diff --git a/lib/lib/include/scroll.h b/lib/lib/include/scroll.h new file mode 100644 index 0000000..98fc50a --- /dev/null +++ b/lib/lib/include/scroll.h @@ -0,0 +1,16 @@ +#ifndef l_scroll_h +#define l_scroll_h + +static void create(); +mixed direct_use_obj_to_str(string str); + +mixed CanUse(object who, string str); + +mixed eventUse(object who, string str); + +string *SetCommands(string *cmds); +string *AddCommand(mixed arg); +string *RemoveCommand(mixed arg); +string *GetCommands(); + +#endif /* l_scroll_h */ diff --git a/lib/lib/include/search.h b/lib/lib/include/search.h new file mode 100644 index 0000000..9930dde --- /dev/null +++ b/lib/lib/include/search.h @@ -0,0 +1,17 @@ +#ifndef l_search_h +#define l_search_h + +static void create(); +mixed direct_search_obj(); +mixed direct_search_str_word_obj(string str); + +varargs mixed CanSearch(object who, string id); + +varargs mixed eventSearch(object who, string id); + +varargs mixed SetSearch(mixed arg1, mixed desc); +mapping RemoveSearch(string item); +mixed GetSearch(string str); +string *GetSearches(); + +#endif /* l_search_h */ diff --git a/lib/lib/include/shell.h b/lib/lib/include/shell.h new file mode 100644 index 0000000..fbb91b5 --- /dev/null +++ b/lib/lib/include/shell.h @@ -0,0 +1,15 @@ +#ifndef l_shell_h +#define l_shell_h + +static void create(); + +int SetCaliber(int x); +int SetMillimeter(int x); +int SetFirearmType(string str); +int SetAmmoType(string str); +string GetFirearmType(); +int GetCaliber(); +int GetMillimeter(); +string GetAmmoType(); + +#endif /* l_shell_h */ diff --git a/lib/lib/include/smell.h b/lib/lib/include/smell.h new file mode 100644 index 0000000..2a4f0b6 --- /dev/null +++ b/lib/lib/include/smell.h @@ -0,0 +1,15 @@ +#ifndef l_smell_h +#define l_smell_h + +static void create(); +mixed direct_smell_obj(); +mixed direct_smell_str_word_obj(string str); + +varargs mixed eventSmell(object who, string id); + +varargs mixed SetSmell(mixed arg1, mixed desc); +mapping RemoveSmell(string item); +string GetSmell(string str); +string *GetSmells(); + +#endif /* l_smell_h */ diff --git a/lib/lib/include/stargate.h b/lib/lib/include/stargate.h new file mode 100644 index 0000000..4987759 --- /dev/null +++ b/lib/lib/include/stargate.h @@ -0,0 +1,18 @@ +/** + * + * $Id: stargate.h,v 1.1 2006/04/05 05:48:39 jam Exp $ + * + */ + +#include "/include/stargate.h" + +#ifndef lib_stargate_h +#define lib_stargate_h + +void setOrigin(string o, string d); +string getOrigin(); +void connect(string destination); +int disconnect(); +string status(); + +#endif diff --git a/lib/lib/include/steal.h b/lib/lib/include/steal.h new file mode 100644 index 0000000..65e40f2 --- /dev/null +++ b/lib/lib/include/steal.h @@ -0,0 +1,18 @@ +#ifndef l_steal_h +#define l_steal_h + +static void create(); +mixed direct_steal_obj_from_liv(); + +mixed CanSteal(object who); + +mixed eventSteal(object who); + +mixed SetPreventSteal(mixed val); +mixed GetPreventSteal(); + +/* pure virtual */ mixed eventMove(mixed dest); +/* pure virtual */ int GetInvis(object who); +/* pure virtual */ string GetShort(); + +#endif /* l_steal_h */ diff --git a/lib/lib/include/storage.h b/lib/lib/include/storage.h new file mode 100644 index 0000000..17b2a74 --- /dev/null +++ b/lib/lib/include/storage.h @@ -0,0 +1,35 @@ +#ifndef l_storage_h +#define l_storage_h + +static void create(); +varargs void reset(int count); + +mixed direct_close_obj(object ob, string id); +mixed indirect_get_obj_out_of_obj(object item); +mixed direct_look_inside_obj(object target, string id); +mixed indirect_look_at_obj_word_obj(object target, string wrd, object ob, + string id, string my_id); +int direct_unlock(); +int inventory_accessible(); +int inventory_visible(); + +mixed CanClose(object who, string id); +mixed CanOpen(object who, string id); +mixed CanPick(object who, string id); +mixed CanPutIn(object who, object what); +mixed CanUnlock(object who, string id, object key); + +int eventReceiveObject(); + +int SetCanClose(int x); +int GetCanClose(); +int SetCanLock(int x); +int GetCanLock(); +void SetKey(string str); +varargs string GetLong(string str); +int GetOpacity(); +int GetRadiantLight(int ambient); +static mixed *AddSave(mixed *val); +int SetSaveRecurse(int x); + +#endif /* l_storage_h */ diff --git a/lib/lib/include/talk.h b/lib/lib/include/talk.h new file mode 100644 index 0000000..bbb0d10 --- /dev/null +++ b/lib/lib/include/talk.h @@ -0,0 +1,16 @@ +#ifndef l_talk_h +#define l_talk_h + +varargs mixed CanSpeak(object target, object *bystanders, string verb, string msg, string lang); +varargs mixed eventHearTalk(object who, object target, int cls, string verb, string msg, string lang); + +mixed eventTalkRespond(object who, object targ, int cls, string msg, string lang); +varargs mixed eventSpeak(object target, int cls, string msg, string lang); + +/* pure virtual */ varargs int eventPrint(string msg, mixed arg2, mixed arg3); +/* pure virtual */ int GetLanguageLevel(string lang); +/* pure virtual */ string GetLanguageName(string str); +/* pure virtual */ varargs string GetMessage(string msg, mixed arg); +/* pure virtual */ int *GetScreen(); + +#endif /* l_talk_h */ diff --git a/lib/lib/include/teacher.h b/lib/lib/include/teacher.h new file mode 100644 index 0000000..52792d4 --- /dev/null +++ b/lib/lib/include/teacher.h @@ -0,0 +1,22 @@ +#ifndef __trainer_h__ +#define __trainer_h__ + +static void create(); +static void init(); + +mixed AddTeachingLanguages(string *args...); +mixed RemoveTeachingLanguages(string *args...); +string *GetTeachingLanguages(); +mapping GetStudents(); + +int eventHelp(object who, string unused); +int eventTeachLanguage(object who, string verb, string language); + +static int ContinueTeaching(object who, string language, int x); + +int eventStart(object who, string language); +int eventContinue(object who, string language, int x); +int eventComplete(object who, string language); + +#define TEACHING_WAIT 2 +#endif __trainer_h__ diff --git a/lib/lib/include/teller.h b/lib/lib/include/teller.h new file mode 100644 index 0000000..0dcd8a2 --- /dev/null +++ b/lib/lib/include/teller.h @@ -0,0 +1,28 @@ +#ifndef l_teller_h +#define l_teller_h + +static void create(); +string SetBankName(string str); +string SetLocalCurrency(string str); +int SetLocalFee(int x); +int SetNonLocalFee(int x); +int SetOpenFee(int x); +float SetExchangeFee(float x); +mixed SetCurrencies(mixed var); +int GetLocalFee(); +int GetNonLocalFee(); +int GetExchangeFee(); +int GetOpenFee(); +mixed GetCurrencies(); +string GetBankName(); +string GetLocalCurrency(); +int AddSurcharge(object who, string currency, int amount); +int eventBalance(object who); +int eventDeposit(object who, string currency, int amount); +int eventWithdraw(object who, string currency, int amount); +int eventExchange(object who, int amount, string str1, string str2); +int eventOpenAccount(object who); +int cmdParse(object who, string cmd, string str); + +#endif + diff --git a/lib/lib/include/torch.h b/lib/lib/include/torch.h new file mode 100644 index 0000000..3211630 --- /dev/null +++ b/lib/lib/include/torch.h @@ -0,0 +1,10 @@ +#ifndef l_torch_h +#define l_torch_h + +static void create(); + +int GetRadiantLight(int ambient); +string GetShort(); +varargs string GetLong(string unused); + +#endif /* l_torch_h */ diff --git a/lib/lib/include/touch.h b/lib/lib/include/touch.h new file mode 100644 index 0000000..1897c75 --- /dev/null +++ b/lib/lib/include/touch.h @@ -0,0 +1,10 @@ +#ifndef l_touch_h +#define l_touch_h + +static void create(); +varargs mixed SetTouch(mixed arg1, mixed desc); +mapping RemoveTouch(string item); +string GetTouch(string str); +string *GetTouches(); + +#endif /* l_touch_h */ diff --git a/lib/lib/include/trainer.h b/lib/lib/include/trainer.h new file mode 100644 index 0000000..9e27285 --- /dev/null +++ b/lib/lib/include/trainer.h @@ -0,0 +1,25 @@ +#ifndef __trainer_h__ +#define __trainer_h__ + +static void create(); +static void init(); + +mixed AddTrainingSkills(string *args...); +mixed RemoveTrainingSkills(string *args...); +string *GetTrainingSkills(); +mapping GetStudents(); + +mapping AddCommandResponses(mapping mp); +mapping AddRequestResponses(mapping mp); + +int eventHelp(object who, string unused); +int eventTrain(object who, string verb, string skill); + +static int ContinueTraining(object who, string skill, int x); + +int eventStart(object who, string skill); +int eventContinue(object who, string skill, int x); +int eventComplete(object who, string skill); + +#define TRAINING_WAIT 2 +#endif __trainer_h__ diff --git a/lib/lib/include/trap.h b/lib/lib/include/trap.h new file mode 100644 index 0000000..523250b --- /dev/null +++ b/lib/lib/include/trap.h @@ -0,0 +1,20 @@ +#ifndef l_trap_h +#define l_trap_h + +static void create(); +static void heart_beat(); + +mixed CanCapture(object who, object target); +mixed CanFree(object who, object target); + +mixed eventCapture(object who, object target); +mixed eventEscape(); +mixed eventFree(object who, string target); + +object array GetCaptives(); +int GetEscapeChance(); +int SetEscapeChance(int x); +int GetMaxCapture(); +int SetMaxCapture(int x); + +#endif /* l_trap_h */ diff --git a/lib/lib/include/vendor.h b/lib/lib/include/vendor.h new file mode 100644 index 0000000..0f0142f --- /dev/null +++ b/lib/lib/include/vendor.h @@ -0,0 +1,30 @@ +#ifndef l_vendor_h +#define l_vendor_h + +static void create(); +static void init(); +mixed direct_buy_str_from_liv(string str); + +mixed CanBuy(object who, object *obs); +mixed CanSell(object who, string what); + +mixed eventAsk(object who, string what); +mixed eventBuy(object who, object *obs); +mixed eventSell(object who, string what); + +int cmdShow(object who, string args); +int cmdBrowse(object who, string args); +int cmdAppraise(object who, string args); +int cmdPrice(object who, string args); +int GetCost(object ob, object who); +int GetValue(object ob, object who); +string SetLocalCurrency(string str); +string GetLocalCurrency(); +string SetStorageRoom(string room); +string GetStorageRoom(); +int SetMaxItems(int x); +int GetMaxItems(); +int SetVendorType(int x); +int GetVendorType(); + +#endif /* l_vendor_h */ diff --git a/lib/lib/include/virtual.h b/lib/lib/include/virtual.h new file mode 100644 index 0000000..91f937a --- /dev/null +++ b/lib/lib/include/virtual.h @@ -0,0 +1,8 @@ +#ifndef __VIRTUAL_H__ +#define __VIRTUAL_H__ + +object compile_object(string file); + +#endif /* __VIRTUAL_H__ */ + + diff --git a/lib/lib/include/weapon.h b/lib/lib/include/weapon.h new file mode 100644 index 0000000..b7e3dcd --- /dev/null +++ b/lib/lib/include/weapon.h @@ -0,0 +1,48 @@ +#ifndef l_weapon_h +#define l_weapon_h + +static void create(); +static void init(); +mixed direct_remove_obj(); +mixed direct_unwield_obj(); +mixed direct_wear_obj(); +mixed direct_wield_obj(); +mixed direct_wield_obj_word_str(mixed fix...); + +mixed CanWield(object who, string *limbs); + +void eventDeteriorate(int type); +void eventEquipAgain(string *limbs); +int eventStrike(object ob); +mixed eventWield(object who, string *limbs); +mixed eventUnequip(object who); + +int SetArmorType(int x); +int GetArmorType(); +int SetClass(int x); +mixed GetProperty(string foo); +int GetClass(); +int SetMaxClass(int x); +int GetMaxClass(); +int AddClassBonus(int amount, int time); +int RemoveClassBonus(int amount); +int GetCurrentBonus(); +int SetDamageType(int x); +int GetDamageType(); +string GetEquippedShort(); +int SetHands(int x); +int GetHands(); +mixed GetLimbList(string str); +string SetWeaponType(string str); +string GetWeaponType(); +mixed SetWield(mixed val); +mixed GetWield(); +static string *SetWorn(string *limbs); +string *GetWorn(); + +/* pure virtual */ string GetKeyName(); +/* pure virtual */ int AddPoison(int x); +/* pure virtual */ int GetPoison(); +/* pure virtual */ string GetShort(); + +#endif /* l_weapon_h */ diff --git a/lib/lib/interactive.c b/lib/lib/interactive.c new file mode 100644 index 0000000..5602eef --- /dev/null +++ b/lib/lib/interactive.c @@ -0,0 +1,639 @@ +/* /lib/interactive.c + * from the Dead Souls Object Library + * an interactive object + * created by Descartes of Borg 941001 for the Idea Exchange + * Version: @(#) interactive.c 1.17@(#) + * Last modified: 97/01/03 + */ + +#ifndef NM_STYLE_EXITS +#define NM_STYLE_EXITS 1 +#endif + +#include <lib.h> +#include <clock.h> +#include <privs.h> +#include <daemons.h> +#include <objects.h> +#include ROOMS_H +#include <marriage.h> +#include <medium.h> +#include <position.h> +#include <message_class.h> +#include <vision.h> +#include <voting.h> +#include "include/interactive.h" + +inherit LIB_DESCRIBE; +inherit LIB_CONTAINER; +inherit LIB_OBJECT; +inherit LIB_AUTOSAVE; +inherit LIB_FILES; +inherit LIB_MOVE; +inherit LIB_PAGER; +inherit LIB_MESSAGES; +inherit LIB_INTERFACE; +inherit LIB_SHADOW_HOOK; + +private int Age, WhereBlock, Brief, LoginTime, BirthTime, RescueBit; +private string Password, Email, RealName, Rank, LoginSite, HostSite, WebPage; +private static string globaltmp; +private mapping News; +private class marriage *Marriages; +private static int LastAge, Setup, quitting; +private static object NetDiedHere; +private static mapping LastError; +private static string *UserId; +private mapping Paranoia = ([]); +private static mapping PlayerStatus = ([]); + +static void create(){ + object::create(); + messages::create(); + interface::create(); + SetOpacity(0); + Marriages = ({}); + HostSite = ""; + Brief = 0; + Password = 0; + Email = 0; + RealName = 0; + Rank = "citizen"; + LoginSite = ROOM_START; + BirthTime = time(); + LastAge = time(); + News = ([]); + Paranoia = (["homeroom" : user_path(GetKeyName(), 1)+"workroom"]); + RescueBit = 0; + SetShort("$N the unaccomplished"); + SetLong("$N is nondescript."); +} + +int SetRescueBit(int i){ + RescueBit = i; + return i; +} + +/* *************** /lib/interactive.c modal functions *************** */ + +mixed CanDivorce(){ + class marriage m; + + if( !Marriages || !sizeof(Marriages) ) + return GetName() + " is not married!"; + m = Marriages[0]; + if( m->DivorceDate ) return GetName() + " is not married!"; + return 1; +} + +mixed CanGet(){ + return GetName() + " is a living being!"; +} + +mixed CanMarry(){ + if( !Marriages ) Marriages = ({}); + if( GetSpouse() ) return GetName() + " is currently married!"; + return 1; +} + +/* *************** /lib/interactive.c lfuns *************** */ +int Setup(){ + mapping mp; + string tmp; + + if(Setup) return 0; + else Setup = 1; + set_living_name(GetKeyName()); + interface::Setup(); + add_action((: cmdQuit :), "quit"); + add_action((: cmdParseRefresh :), "parserefresh"); + tmp = this_object()->GetTeloptIp(); + if(tmp) HostSite = tmp; + else HostSite = query_ip_number(this_object()); + LoginTime = time(); + SetId(({})); + autosave::Setup(); + //call_out("save_player", 2, GetKeyName()); + if( VOTING_D->GetStatus() == VOTE_RUNNING ){ + if( VOTING_D->GetMode() == VOTE_MODE_CANDIDATES ) + eventPrint("%^YELLOW%^Class Elections are in progress! " + "Go nominate candidates!%^RESET%^"); + if( VOTING_D->GetMode() == VOTE_MODE_VOTING ) + eventPrint("%^YELLOW%^Class Elections are in progress! " + "Go vote for the candidates!%^RESET%^"); + } + + if( VOTING_D->GetVoteStatus( this_object() ) != VOTE_ALREADY_VOTED ){ + eventPrint("%^YELLOW%^You have not yet voted! " + "Please vote now.%^RESET%^"); + eventMove( VOTING_D->GetVoteRoom() ); + } else { + object room; + if(grepp(LoginSite,"#")){ + room = find_object(LoginSite); + } + if(!room) catch(room = load_object(LoginSite)); + if( room && room->GetMedium() == MEDIUM_AIR ){ + } + if(!sizeof(LoginSite) || + (!room && !file_exists(LoginSite) && !file_exists(LoginSite+".c")) || + !eventMove(LoginSite) || RescueBit ){ + LoginSite = ROOM_START; + eventMove(ROOM_START); + SetRescueBit(0); + } + } + //environment()->eventPrint(tmp, MSG_ENV, this_object()); + if( !(tmp = GetMessage("login")) ) + tmp = GetName() + " enters " + mud_name() + "."; + if(!(archp(this_object()) && this_object()->GetInvis())){ + PLAYERS_D->PlayerUpdate(GetKeyName(), 1); + log_file("enter", GetCapName()+" (enter): "+ctime(time())+"\n"); + CHAT_D->eventSendChannel("SYSTEM","connections","[" + + GetCapName() + " logs into "+mud_name()+"]",0); + } + + if(!catch(mp = FOLDERS_D->mail_status(GetKeyName()))){ + if(mp["unread"]){ + eventPrint("\n%^RED%^%^BOLD%^>>> " + mp["unread"] + " of your " + + (mp["total"] == 1 ? mp["total"] + " letter is" : + mp["total"] + " letters remain") + " unread. <<<%^RESET%^\n", + MSG_SYSTEM); + } + } + NEWS_D->GeneralNews(); + return 1; +} + +static void net_dead(){ + object env = environment(); + interface::net_dead(); + Age += time() - LastAge; + LastAge = time(); + NetDiedHere = environment(this_object()); + save_player(GetKeyName()); + if(!(archp(this_object()) && this_object()->GetInvis())){ + PLAYERS_D->PlayerUpdate(GetKeyName(), -1); + log_file("enter", GetCapName() + " (net-dead): "+ctime(time())+"\n"); + if(env) env->eventPrint(GetName() + " suddenly disappears into " + "a sea of irreality.", MSG_ENV, this_object()); + CHAT_D->eventSendChannel("SYSTEM","connections","[" + + GetCapName() + " goes net-dead on "+mud_name()+"]",0); + } + SNOOP_D->ReportLinkDeath(this_object()->GetKeyName()); + eventMove(ROOM_FREEZER); + if(query_snoop(this_object())) + query_snoop(this_object())->eventPrint(GetCapName() + " has gone " + "net-dead.", MSG_SYSTEM); +} + +void eventReconnect(){ + interface::eventReconnect(); + LastAge = time(); + HostSite = query_ip_number(this_object()); + eventPrint("Reconnected.", MSG_SYSTEM); + PLAYERS_D->PlayerUpdate(GetKeyName(), 1); + if(!(archp(this_object()) && this_object()->GetInvis())){ + CHAT_D->eventSendChannel("SYSTEM","connections","[" + + GetCapName() + " has rejoined " + mud_name() + "]",0); + environment()->eventPrint(GetCapName() + " has rejoined this reality.", + MSG_ENV, this_object()); + } + if( NetDiedHere ) eventMove(NetDiedHere); + else eventMove(ROOM_START); + NetDiedHere = 0; +} + +int eventDestruct(){ + object ob, env = environment(); + int ret, inter = interactive(), arc = archp(); + int invis = this_object()->GetInvis(); + string name = GetCapName(), stack = get_stack(); + if(!valid_event(previous_object(), this_object())) return 0; + interface::eventDestruct(); + foreach(ob in deep_inventory(this_object())){ + if( ob ) catch(ob->eventDestruct()); + } + ob = this_object(); + INSTANCES_D->UpdateInvis(); + if(inter && !(arc && invis) && !quitting){ + log_file("enter", name + " (dested): "+ctime(time())+"\n"); + log_file("dests", name + " "+ctime(time())+" "+ + stack+"\n---\n\n"); + CHAT_D->eventSendChannel("SYSTEM","connections","[" + + name + " has been destructed from "+mud_name()+"]", 0); + if(env) env->eventPrint(name + " disintegrates!", + MSG_ENV, (ob || ({}))); + } + ret = object::Destruct(); + return ret; +} + +mixed eventDivorce(){ + class marriage m; + m = Marriages[0]; + m->DivorceDate = time(); + return 1; +} + +mixed eventMarry(object who, object to_whom){ + class marriage m; + object env; + if( (env = previous_object()) != environment() ) return 0; + m = new(class marriage); + m->Spouse = to_whom->GetCapName(); + m->WeddingDate = time(); + m->DivorceDate = 0; + m->Location = file_name(env); + Marriages = ({ m }) + Marriages; + return 1; +} + +int eventMove(mixed dest){ + string str; + int x; + x = move::eventMove(dest); + if( x ){ + if( !(str = environment()->GetProperty("login")) ){ + if(clonep(environment())) LoginSite = file_name(environment()); + else LoginSite = base_name(environment()); + } + else LoginSite = str; + } + return x; +} + +void cmdParseRefresh(){ + parse_refresh(); +} + +int cmdQuit(){ + string tmp; + object env = environment(this_object()); + int retain = RETAIN_ON_QUIT; + if(!env) env = load_object(ROOM_FURNACE); + + if( previous_object() && ! + (master()->valid_apply( ({ GetKeyName() }) )) ) return 0; + if( env->GetProperty("no quit") && + ! sizeof(previous_object(-1)) ){ + message("system", "You are unable to escape this reality!", + this_object()); + return 0; + } + quitting = 1; + tell_object(this_object(),"Please come back another time!"); + if(!creatorp(this_object())){ + foreach(object ob in all_inventory(this_object())){ + if((!retain && !ob->GetRetain()) || !ob->GetRetain()) ob->eventMove(env); + } + foreach(object ob in deep_inventory(this_object())){ + if((!retain && !ob->GetRetain()) || !ob->GetRetain()) ob->eventMove(env); + } + } + this_object()->AddCarriedMass(-(this_object()->GetCarriedMass())); + tmp = GetMessage("logout") || (this_object()->GetName() + + " is gone from this reality!"); + save_player(GetKeyName()); + if(!(archp(this_object()) && this_object()->GetInvis())){ + PLAYERS_D->PlayerUpdate(GetKeyName(), 0); + log_file("enter", GetCapName()+" (quit): "+timestamp()+"\n"); + if(env) message("environment", tmp, env, ({this_object()})); + CHAT_D->eventSendChannel("SYSTEM","connections","[" + + GetCapName() + " quits "+mud_name()+"]",0); + } + if(in_edit()){ + ed_cmd("."); + ed_cmd("x"); + ed_cmd("Q"); + } + flush_messages(); + this_object()->eventDestruct(); + return 1; +} + +int GetAge(){ + int x; + if(!interactive(this_object())) return Age; + x = time() - LastAge; + Age += x; + LastAge = time(); + return Age; +} + +int GetBirth(){ return BirthTime - (YEAR * 18); } + +string query_cwd(){ return interface::query_cwd(); } + +void SetEmail(string str){ + if(!(master()->valid_apply(({ GetKeyName() })))) return; + Email = str; +} + +string GetEmail(){ + if(!(master()->valid_apply(({ GetKeyName() })))) return 0; + else return Email; +} + +varargs string array SetId(string *bogus){ + int i; + string tmp; + + UserId = ({ GetKeyName() }); + if(GetCapName()) UserId += ({ lower_case(GetCapName()) }); + + if(sizeof(bogus)){ + if(this_player() && this_player() == this_object()){ + if(!arrayp(bogus)) bogus = ({ bogus }); + if(!UserId) UserId = bogus; + else UserId += bogus; + } + } + + if(tmp = this_object()->GetRace()) UserId += ({ tmp }); + + if(OBJECT_MATCHING){ + UserId = atomize_array(UserId); + } + + UserId = distinct_array(UserId); + + foreach(string sub in UserId){ + if(user_exists(sub) && GetKeyName() != sub){ + //if(find_player(sub) && find_player(sub) != this_object()){ + UserId -= ({ sub }); + //} + } + } + parse_init(); + return UserId; +} + +string *GetId(){ return UserId; } + +int id(string str){ + if(!str || !UserId) return 0; + else return member_array(lower_case(str), UserId) != -1; +} + +int GetLoginTime(){ return LoginTime; } + +string SetKeyName(string str){ + if( previous_object() != master() ) return GetKeyName(); + return object::SetKeyName(str); +} + +string GetKeyName(){ return object::GetKeyName(); } + +void SetNews(string type, int sz){ News[type] = sz; } + +int GetNews(string type){ return News[type]; } + +void SetPassword(string str){ + if(!(master()->valid_apply(({ GetKeyName() })))) return; + Password = str; + save_player(GetKeyName()); +} + +string GetPassword(){ + if(!(master()->valid_apply(({ GetKeyName() })))) return 0; + else return Password; +} + +void SetRank(string str){ Rank = str; } + +string GetRank(){ return Rank; } + +void SetRealName(string str){ + if(!(master()->valid_apply(({ GetKeyName() })))) return; + RealName = str; +} + +string GetRealName(){ return RealName; } + +string GetShort(){ + string str = object::GetShort(); + if( !str ) str = "$N the unaccomplished"; + if( strsrch(str, "$N") == -1 ) str = "$N"; + str = replace_string(str, "$N", (GetName() || "")); + str += "%^RESET%^"; + if(!interactive(this_object())) str += " (net-dead)"; + return str; +} + +varargs string GetLong(){ + string str; + str = object::GetLong(str); + if(!str || strsrch(str, "$N") == -1) str = "$N is nondescript."; + str = replace_string(str, "$N", GetName()); + return str; +} + +int SetBriefMode(int x){ return (Brief = x); } + +int GetBriefMode(){ return Brief; } + +int SetWhereBlock(){ return (WhereBlock = !WhereBlock); } + +int GetWhereBlock(){ return WhereBlock; } + +string get_path(){ + return query_cwd(); +} + +void SetLastError(mapping m){ + if (previous_object() != master()) return; + LastError = m; +} + +mapping GetLastError(){ + string *allowed = ({ "/secure/cmds/creators/dbxwhere", "/secure/cmds/creators/dbxframe", "/secure/cmds/players/bug", file_name(master()) }); + string caller = file_name(previous_object()); + if(member_array(caller, allowed) != -1 ){ + if(LastError) return LastError; + } + else error("Privilege Violation: " + caller); +} + +string SetCapName(string str){ + if(base_name(previous_object(0)) != LIB_CONNECT){ + if(this_player()){ + if(!adminp(this_player())) return str; + } + else return str; + } + return object::SetCapName(str); +} + +void move_or_destruct(){ + string rvoid = ROOMS_D->GetVoid(this_object()); + (eventMove(ROOM_START) || eventMove(rvoid)); +} + +string SetShort(string str){ + if( strsrch(str, "$N") == -1 ) return object::GetShort(); + else return object::SetShort(str); +} + +string SetLong(string str){ + if(strsrch(str, "$N") == -1) return object::GetLong(); + else return object::SetLong(str); +} + +string GetName(){ return object::GetName(); } + +varargs int GetInvis(object ob){ return object::GetInvis(ob); } + +mixed *GetCommands(){ + if( !(master()->valid_apply( ({ GetKeyName() }) )) ) return ({}); + else return commands(); +} + +string GetSpouse(){ + if( !Marriages || !sizeof(Marriages) ) return 0; + if( ((class marriage)Marriages[0])->DivorceDate ) return 0; + return ((class marriage)Marriages[0])->Spouse; +} + +class marriage *GetMarriages(){ return Marriages; } + +string GetHostSite(){ + if( WhereBlock ){ + if( !(master()->valid_access(({ PRIV_ASSIST }))) ) + return "Confidential"; + else return HostSite; + } + return HostSite; +} + +int GetRadiantLight(int ambient){ + return container::GetRadiantLight(ambient); +} + +string GetWebPage(){ + return WebPage; +} + +string SetWebPage(string page){ + if( !master()->valid_apply(({ GetKeyName() })) ){ + return WebPage; + } + return (WebPage = page); +} + +varargs nomask static void validate_paranoia(int prev){ + object ob = ( prev ? previous_object() : this_player() ); + if( !this_player() || (!archp(this_player()) && + ob != this_object()) ){ + error("Illegal attempt to access paranoia: "+get_stack()+ + " "+identify(previous_object(-1))); + log_file("adm/pause",timestamp()+" Illegal attempt to access "+ + "paranoia settings on "+identify(this_object())+ + " by "+identify(previous_object(-1))+"\n"); + } +} + +mixed GetParanoia(string str){ + //validate_paranoia(1); + if(Paranoia[str]) return copy(Paranoia[str]); + return 0; +} + +mixed SetParanoia(string str, mixed val){ + validate_paranoia(); + Paranoia[str] = val; + return copy(Paranoia[str]); +} + +static nomask void NotifyReceipt(object ob){ + string what, msg; + if(playerp(this_object())) what = ob->GetShort(); + if(creatorp(this_object())) what = identify(ob); + tell_player(this_object(),what+", a thing "+ + "that can watch what is going on around you, has "+ + "entered your inventory."); +} + +nomask int eventReceiveObject(object ob){ + int ret = container::eventReceiveObject(ob); + if(ret && GetParanoia("inventory_monitoring")){ + tell_player(this_object(),"%^YELLOW%^NOTICE:%^RESET%^ "+identify(ob)+ + " enters your inventory."); + } + this_object()->AddCarriedMass(ob->GetMass()); + if(environment()) environment()->AddCarriedMass(ob->GetMass()); + if(ob->GeteventPrints()) NotifyReceipt(ob); + return ret; +} + +static void heart_beat(){ + string tip = this_object()->GetTeloptIp(); + if(tip && tip != HostSite){ + HostSite = tip; + save_player(GetKeyName()); + } + if(!interactive() || !find_object(INSTANCES_D)) autosave::heart_beat(); + if(!PlayerStatus) PlayerStatus = ([]); + if(!PlayerStatus["Idling"] && + query_idle(this_object()) > 240){ + PlayerStatus["Idling"] = 1; + if(find_object(INSTANCES_D)){ + INSTANCES_D->SendWhoUpdate(GetKeyName()); + } + } + if(this_object()->GetSleeping()){ + if(!PlayerStatus["Sleeping"]){ + PlayerStatus["Sleeping"] = 1; + INSTANCES_D->SendWhoUpdate(GetKeyName()); + } + } + else if(PlayerStatus["Sleeping"]){ + PlayerStatus["Sleeping"] = 0; + INSTANCES_D->SendWhoUpdate(GetKeyName()); + } + if(this_object()->GetInCombat()){ + if(!PlayerStatus["Combat"]){ + PlayerStatus["Combat"] = 1; + INSTANCES_D->SendWhoUpdate(GetKeyName()); + } + } + else if(PlayerStatus["Combat"]){ + PlayerStatus["Combat"] = 0; + INSTANCES_D->SendWhoUpdate(GetKeyName()); + } + if(in_edit(this_object()) || this_object()->GetCedmode()){ + if(!PlayerStatus["Edit"]){ + PlayerStatus["Edit"] = 1; + INSTANCES_D->SendWhoUpdate(GetKeyName()); + } + } + else if(PlayerStatus["Edit"]){ + PlayerStatus["Edit"] = 0; + INSTANCES_D->SendWhoUpdate(GetKeyName()); + } + if(this_object()->GetTeloptIp() && !GetCharmode()){ + int oldlock = GetProperty("screenlock"); + SetCharmode(1); + SetProperty("reprompt",1); + SetProperty("keepalive", 5); + SetProperty("screenlock", 0); + SetScreen(80, 25); + SetProperty("screenlock", oldlock); + } + autosave::heart_beat(); +} + +static string process_input(string str){ + if(PlayerStatus["Idling"]){ + PlayerStatus["Idling"] = 0; + if(find_object(INSTANCES_D)){ + INSTANCES_D->SendWhoUpdate(GetKeyName()); + } + } + if(GetProperty("afk") && strsrch(str, "afk")){ + SetProperty("afk", 0); + tell_player(this_object(), "You are back from being afk."); + INSTANCES_D->SendWhoUpdate(GetKeyName()); + } + return interface::process_input(str); +} diff --git a/lib/lib/interface.c b/lib/lib/interface.c new file mode 100644 index 0000000..67eca49 --- /dev/null +++ b/lib/lib/interface.c @@ -0,0 +1,485 @@ +/* /lib/interface.c + * from the Dead Souls Object Library + * handles user interface issues + * created by Descartes of Borg 950428 + * Version: @(#) interface.c 1.4@(#) + * Last Modified: 96/10/15 + */ + +#include <lib.h> +#include <daemons.h> +#include <message_class.h> +#include "include/interface.h" + +inherit LIB_CHAT; +inherit LIB_COMMAND; +inherit LIB_EDITOR; +inherit LIB_CHARIO; +inherit LIB_NMSH; +inherit LIB_CEDIT; + +private string Terminal; +private mapping Blocked; +private int *Screen; +private static int LogHarass, Client; +private static mapping TermInfo; +string MessageQueue; +int PauseMessages, annoyblock; +int MessageExceptions, BlockAnnoying; + +static void create(){ + chat::create(); + command::create(); + editor::create(); + nmsh::create(); + Terminal = "ansi"; + Screen = ({ 80, 20 }); + Blocked = ([]); +} + +static string process_input(string str){ + command::SetCommandFail(0); + str = command::process_input(str); + if( Client ){ + int cl; + sscanf(str, "%d %s", cl, str); + } + if( (str = editor::process_input(str)) == "" ){ + return ""; + } + else { + str = nmsh::process_input(str); + if( str != "" ){ + return chat_command(str); + } + else { + return ""; + } + } +} + +static void terminal_type(string str){ + if( !stringp(str) ) return; + else SetTerminal(lower_case(str)); +} + +static void window_size(int width, int height){ + if(query_verb() == "screen" || + !this_object()->GetProperty("screenlock")){ + SetScreen(width, height); + } +} + +varargs void eventReceive(string message, int noprompt, int noerase){ + int max_length = __LARGEST_PRINTABLE_STRING__ - 192; + string prompt = this_object()->GetPrompt(!(in_edit(this_object()))); + string *stack = call_stack(2); + if(stack[1] == "write2" && message != "\n"){ + noerase = 1; + } + if(sizeof(message) > max_length){ + while(sizeof(message)){ + string tmp = message[0..max_length]; + receive(tmp+(noprompt ? "" : prompt)); + message = replace_string(message, tmp, ""); + } + } + else { + if(!noerase && this_object()->GetProperty("reprompt")){ + this_object()->erase_prompt(); + } + receive(message); + + //This check is so that players whose charmode is temporarily + //suspended (so that they can be in the pager) don't have their + //charmode prematurely re-enabled. + if(!in_pager()) this_object()->CheckCharmode(); + + //This check is so that players in charmode who currently are + //typing a big line don't have their last-received-message + //overwritten by the redraw of their screen on the next + //keypress. I'm intentionally not adding a was_charmode check + //because at the moment that seems like overkill and like it + //might be annoying. + if(query_charmode()){ + int buff = sizeof(this_object()->GetCharbuffer()); + if(buff){ + int scrn = this_object()->GetScreen()[0]; + int prmpt = sizeof(strip_colours(this_object()->GetPrompt())); + if((prmpt + buff) >= scrn){ + receive("\n"); + this_object()->RedrawPrompt(); + } + } + } + } +} + +void receive_message(mixed msg_class, string msg){ + int cl = 0; + if(intp(msg_class)){ + cl = msg_class; + eventPrint(msg, cl); + return; + } + + else if( msg_class[0] == 'N' ){ + msg_class = msg_class[1..]; + cl |= MSG_NOWRAP; + } + else if( msg_class == "prompt" && msg_class == "editor" ) cl |= MSG_NOWRAP; + + switch(msg_class){ + case "smell": case "sound": case "touch": + cl |= MSG_ENV; + break; + + case "receive": + cl |= MSG_RECEIVE; + break; + + case "snoop": + cl |= MSG_SYSTEM | MSG_NOCOLOUR; + + case "broadcast": + cl |= MSG_SYSTEM; + break; + + case "editor": + cl |= MSG_EDIT; + break; + + case "tell": case "shout": + cl |= MSG_CONV; + break; + + case "come": case "leave": case "telout": case "telin": + cl |= MSG_ENV; + break; + + case "living_item": case "inanimate_item": + cl |= MSG_ROOMDESC; + break; + + case "system": case "more": + cl |= MSG_SYSTEM; + break; + + case "prompt": + cl = MSG_PROMPT; + break; + + case "error": + cl |= MSG_ERROR; + break; + + case "help": + cl |= MSG_HELP; + + default: + cl |= MSG_ENV; + + } + eventPrint(msg, cl); +} + +static void receive_snoop(string str){ receive_message("snoop", "%"+str); } + +int Setup(){ + command::Setup(); + nmsh::Setup(); + TermInfo = TERMINAL_D->query_term_info(Terminal); +} + +int eventFlushQueuedMessages(){ + print_long_string(this_object(),MessageQueue); + MessageQueue = ""; + return 1; +} + +varargs int eventPauseMessages(int x, int exceptions){ + if(exceptions) MessageExceptions = exceptions; + else MessageExceptions = 0; + if(x) PauseMessages = 1; + else { + if(PauseMessages){ + eventFlushQueuedMessages(); + } + PauseMessages = 0; + } + return PauseMessages; +} + +static varargs int PassengerPrint(string msg, mixed arg2, + mixed arg3, object *riders){ + object *targs = ({}); + if(riders && sizeof(riders)){ + int i1, rider_source; + if(!arg2) arg2 = 0; + if(!arg3) arg3 = 0; + if(sizeof(riders)){ + if(arg2 && intp(arg2)){ + object *tmp_riders = riders; + if(arg2 & MSG_CONV || arg2 & MSG_ENV){ + foreach(object ob in previous_object(-1)){ + if(member_array(ob,riders) != -1){ + tmp_riders -= ({ ob }); + rider_source = 1; + } + } + } + if((arg2 & MSG_CONV)) true(); + else { + if(objectp(arg2)) targs = tmp_riders - ({ arg2 }); + else if(arrayp(arg2)) targs = tmp_riders - arg2; + else targs = tmp_riders; + targs->eventPrint(msg, arg3); + } + } + i1 = sizeof(previous_object(-1)) -1; + if(i1 < 0) i1 = 0; + if(sizeof(previous_object(-1)) && + (member_array(previous_object(),riders) != -1 || + member_array(previous_object(-1)[i1],riders) != -1) && + (!intp(arg2) || (!(arg2 & MSG_CONV) && !(arg2 & MSG_ENV))) && + member_array(this_object(),previous_object(-1)) == -1){ + if(objectp(arg2)) targs = riders - ({ arg2 }); + else if(arrayp(arg2)) targs = riders - arg2; + else targs = riders; + environment()->eventPrint(msg, arg2, arg3); + } + } + } + return 1; +} + +varargs int eventPrint(string msg, mixed arg2, mixed arg3){ + int msg_class; + string prompt = ""; + object *passengers = filter(all_inventory(this_object()), (: living :) ); + if( !msg ) return 0; + if(this_object()->GetProperty("reprompt")){ + prompt = this_object()->GetPrompt(1); + //I don't want to talk about this. + //if(this_object()->GetProperty("gmud")) msg = "\n" + msg; + } + if( !arg2 && !arg3 ) msg_class = MSG_ENV; + else if( !arg2 ){ + if( !intp(arg3) ) msg_class = MSG_ENV; + else msg_class = arg3; + } + else if( !intp(arg2) ) msg_class = MSG_ENV; + else msg_class = arg2; + if(sizeof(passengers) && (msg_class & MSG_ENV || msg_class & MSG_CONV)){ + } + if( !(msg_class & MSG_NOBLOCK) && GetBlocked("all") ) return 0; + + if((msg_class & MSG_ANNOYING) && annoyblock) return 0; + + /* This is no longer necessary, since the commands + * "mute" and "gag" can now keep things quiet on + * on channels for individuals if they so wish. + * if((msg_class & MSG_CHAN) && environment() && + * environment()->GetProperty("meeting room")) return 0; + */ + if( GetLogHarass() ) + log_file("harass/" + GetKeyName(), strip_colours(msg) + "\n"); + if( !TermInfo ) + TermInfo = TERMINAL_D->query_term_info(GetTerminal()); + + if(this_object()->GetParanoia("cursefilter")){ + msg = FILTER_D->eventFilter(msg, "curse"); + } + if( !(msg_class & MSG_NOCOLOUR) ){ + int indent; + //Uncomment below to enable indentation of "conversation" + //if( msg_class & MSG_CONV ) indent = 4; + //else indent = 0; + if( msg_class & MSG_NOWRAP ) + msg = terminal_colour(msg + "%^RESET%^", TermInfo); + else + msg = terminal_colour(msg + "%^RESET%^\n" + prompt, TermInfo, + GetScreen()[0], indent); + } + else if( !(msg_class & MSG_NOWRAP) ) msg = wrap(msg, GetScreen()[0]-1); + if(PauseMessages && !(msg_class & MessageExceptions)){ + MessageQueue += msg; + } + else { + if(msg_class & MSG_RECEIVE){ + receive(msg); + return 1; + } + if( Client ){ + eventReceive("<"+msg_class+" "+msg+" "+msg_class+">\n"); + } + else { + eventReceive(msg); + } + } + return 1; +} + +varargs int SetBlocked(string type, int flag){ + if( !type ) return 0; + if( undefinedp(flag) ) flag = !Blocked[type]; + if( Blocked[type] == 2 && !archp(this_player()) ){ + this_player()->eventPrint("Unable to unblock " + type + "."); + return -1; + } + Blocked[type] = flag; + message("system", "You are "+(Blocked[type] ? "now blocking" : + "no longer blocking")+" "+type+".", this_object()); + return Blocked[type]; +} + +int GetBlocked(string type){ return (Blocked["all"] || Blocked[type]); } + +int SetClient(int x){ + return 0; + if( x ) SetTerminal("unknown"); + return (Client = x); +} + +int GetClient(){ return Client; } + +int SetLogHarass(int x){ + string txt; + + if( GetForced() || (this_player(1) != this_object()) ) return LogHarass; + if( LogHarass == x ) return LogHarass; + if( x ){ + txt = "**************** Start of Log *****************\n"+ + "Time: " + ctime( time() ) + "\n"; + if( environment( this_object() ) ) txt += "Place: " + + file_name( environment( this_object() ) ) + "\n"; + } else { + txt = "**************** End of Log *****************\n"+ + "Time: " + ctime( time() ) + "\n"; + } + log_file("harass/" + GetKeyName(), txt); + return (LogHarass = x); +} + +int GetLogHarass(){ return LogHarass; } + +int *SetScreen(int width, int height){ + if(!width) width = (__LARGEST_PRINTABLE_STRING__-1)/50; + if(!height) height = __LARGEST_PRINTABLE_STRING__/width; + + width--; + if( width * height > __LARGEST_PRINTABLE_STRING__ ){ + if( width > height ) width = __LARGEST_PRINTABLE_STRING__/height; + else if( height > width ) height = __LARGEST_PRINTABLE_STRING__/width; + else { + width = (__LARGEST_PRINTABLE_STRING__-1)/50; + height = 50; + } + } + return (Screen = ({ width, height })); +} + +int *GetScreen(){ return Screen; } + +string SetTerminal(string terminal){ + switch( terminal ){ + case "iris-ansi-net": case "vt100": case "vt220": case "vt102": + case "vt300": case "dec-vt100": + terminal = "ansi"; + break; + case "unknown": case "ansi": case "freedom": case "ansi-status": + case "xterm": + break; + case "console": case "ibm-3278-2": + terminal = "unknown"; + break; + case "html" : terminal = "html"; break; + default: + log_file("terminals", "Unknown terminal type: " + terminal + "\n"); + terminal = Terminal; + break; + } + if( terminal != Terminal ) + TermInfo = TERMINAL_D->query_term_info(terminal); + return Terminal = terminal; +} + +string GetTerminal(){ return Terminal; } + +string GetKeyName(){ return 0; } + +int SetAnnoyblock(int i){ + if(!this_player()) return 0; + if(archp(this_object()) && !archp(this_player())) return 0; + if(!archp(this_object()) && this_player() != this_object()) return 0; + if(i) annoyblock = 1; + else annoyblock = 0; + return annoyblock; +} + +int GetAnnoyblock(){ + return annoyblock; +} + +static int rArrow(string str){ + int ret, cedmode = this_object()->GetCedmode(); + switch(cedmode){ + case 0 : ret = nmsh::rArrow(str); break; + case 1 : ret = cedit::rArrow(str); break; + } + return ret; +} + +static int rCtrl(string str){ + int ret, cedmode = this_object()->GetCedmode(); + switch(cedmode){ + case 0 : ret = nmsh::rCtrl(str); break; + case 1 : ret = cedit::rCtrl(str); break; + } + return ret; +} + +static int rBackspace(){ + int ret, cedmode = this_object()->GetCedmode(); + switch(cedmode){ + case 0 : ret = nmsh::rBackspace(); break; + case 1 : ret = cedit::rBackspace(); break; + } + return ret; +} + +static int rEnter(){ + int ret, cedmode = this_object()->GetCedmode(); + switch(cedmode){ + case 0 : ret = nmsh::rEnter(); break; + case 1 : ret = cedit::rEnter(); break; + } + return ret; +} + +static int rAscii(string str){ + int ret, cedmode = this_object()->GetCedmode(); + switch(cedmode){ + case 0 : ret = nmsh::rAscii(str); break; + case 1 : ret = cedit::rAscii(str); break; + } + return ret; +} + +static int rDel(){ + int ret, cedmode = this_object()->GetCedmode(); + switch(cedmode){ + case 0 : ret = nmsh::rDel(); break; + case 1 : ret = cedit::rDel(); break; + } + return ret; +} + +static int rAnsi(string str){ + int ret, cedmode = this_object()->GetCedmode(); + switch(cedmode){ + case 0 : ret = nmsh::rAnsi(str); break; + case 1 : ret = cedit::rAnsi(str); break; + } + return ret; +} diff --git a/lib/lib/lamp.c b/lib/lib/lamp.c new file mode 100644 index 0000000..f34fa54 --- /dev/null +++ b/lib/lib/lamp.c @@ -0,0 +1,71 @@ +/* /lib/lamp.c + * from the Dead Souls Object Library + * a lamp-like inheritable that burns and such + * created by Descartes of Borg 960513 + */ + +#include <lib.h> +#include "include/lamp.h" + +inherit LIB_ITEM; +inherit LIB_LIGHT; +inherit LIB_FUEL; + +private int BurnRate = 5; + +static void create(){ + item::create(); + fuel::create(); + light::create(); +} + +static void heart_beat(){ + eventDecreaseFuel(1); + if( GetFuelAmount() < 1){ + eventDarken(); + } +} + +mixed direct_light_obj(){ + if( GetFuelAmount() < 1 ) + return "There is no " + GetFuelType() + " in " + GetShort() + "."; + return 1; +} + +mixed eventDarken(){ + light::eventDarken(); + set_heart_beat(0); + return 1; +} + +varargs mixed eventLight(object who, object tool){ + if( GetLit() ) return light::eventLight(who, tool); + eventLight(who, tool); + set_heart_beat(BurnRate); + return 1; +} + +int GetBurnRate(){ + return BurnRate; +} + +static int SetBurnRate(int x){ + return (BurnRate = x); +} + +int GetRadiantLight(int ambient){ + if( !GetLit() ) return 0; + else return item::GetRadiantLight(ambient); +} + +string GetShort(){ + return light::GetShort() + item::GetShort(); +} + +varargs string GetLong(string unused){ + string tmp; + + tmp = fuel::GetLong(unused); + if( tmp != "" ) return item::GetLong(unused) + "\n" + tmp; + else return item::GetLong(unused); +} diff --git a/lib/lib/language.c b/lib/lib/language.c new file mode 100644 index 0000000..31d4b9b --- /dev/null +++ b/lib/lib/language.c @@ -0,0 +1,121 @@ +/* /lib/languages.c + * from the Dead Souls LPC Library + * language module for linguistic people + * created by Descartes of Borg 950412 + */ + +#include <function.h> + +int Polyglot = 0; + +private mapping Languages = ([]); +private string DefaultLanguage = ""; + +// abstract methods +int GetHeartRate(); +int GetStatLevel(string stat); +string GetNativeLanguage(); +// end abstract methods + +int GetNextLevel(string lang, int curr_level); + +varargs void SetLanguage(string lang, int level, int native){ + string key; + if(!lang || !sizeof(lang)) return; + key = convert_name(lang); + if( !Languages[key] ) Languages[key] = ([]); + Languages[key] = ([ "name" : lang, "points" : 0, "level" : level, + "native" : native ]); +} + +mapping RemoveLanguage(string lang){ + if(lang && sizeof(lang)) lang = convert_name(lang); + else return copy(Languages); + map_delete(Languages, lang); + return copy(Languages); +} + +mapping SetNativeLanguage(string lang){ + string old_lang = GetNativeLanguage(); + RemoveLanguage(old_lang); + SetLanguage(old_lang, 100); + SetLanguage(lang, 100, 1); + return copy(Languages); +} + +mixed SetDefaultLanguage(string str){ + if(!str || str == "") return DefaultLanguage = GetNativeLanguage(); + if(member_array(lower_case(str),keys(Languages)) != -1 || + member_array(capitalize(lower_case(str)),keys(Languages)) != -1) + return DefaultLanguage = capitalize(lower_case(str)); + else return DefaultLanguage = GetNativeLanguage(); +} + +string GetDefaultLanguage(){ + if(sizeof(DefaultLanguage)) return DefaultLanguage; + else return GetNativeLanguage(); +} + +int GetLanguageLevel(string lang){ + if(Polyglot) return 100; + lang = convert_name(lang); + if( !Languages[lang] ) return 0; + else return Languages[lang]["level"]; +} + +string GetLanguageName(string lang){ + lang = convert_name(lang); + if( !Languages[lang] ) return 0; + else return Languages[lang]["name"]; +} + +int AddLanguagePoints(string lang, int points){ + string key; + + key = convert_name(lang); + if( !Languages[key] ) SetLanguage(key, 0, 0); + Languages[key]["points"] += points; + Languages[key]["level"] = Languages[key]["points"]; + if(Languages[key]["level"] > 100) Languages[key]["level"] = 100; + return Languages[key]["points"]; +} + +int GetLanguagePoints(string lang){ + lang = convert_name(lang); + if( !Languages[lang] ) return 0; + else return Languages[lang]["points"]; +} + +string array GetLanguages(){ + return map(keys(Languages), (: Languages[$1]["name"] :)); +} + +int GetNextLevel(string lang, int curr_level){ + int y; + + lang = lower_case(lang); + if( !Languages[lang] ) return 0; + y = (1 + Languages[lang]["native"]) * GetStatLevel("intelligence"); + y = (2000 * curr_level) / y; + return y; +} + +int GetStatLevel(string stat){ return 0; } + +string GetNativeLanguage(){ + mapping val; + string lang; + + foreach(lang, val in Languages) + if( val["native"] ) return Languages[lang]["name"]; +} + +int SetPolyglot(int i){ + if(!i) Polyglot = 0; + else Polyglot = 1; + return Polyglot; +} + +int GetPolyglot(){ + return Polyglot; +} diff --git a/lib/lib/lead.c b/lib/lib/lead.c new file mode 100644 index 0000000..b6e7fd8 --- /dev/null +++ b/lib/lib/lead.c @@ -0,0 +1,144 @@ +/* From the Dead Souls Object Library + * Provides lead support for mobile objects. + * Works closely with LIB_FOLLOW. + * Created by Rush 951028 + */ + +#include <lib.h> +#include <position.h> +#include "include/lead.h" + +private static mapping Followers; +private static int numberOfFollowers; + +static void create(){ + Followers = ([]); + numberOfFollowers = 0; +} + +mixed direct_lead_liv(){ + if( this_object() == this_player() ) return "That's silly."; + return this_player()->CanLead(); +} + +mixed direct_evade_liv(){ + if( this_object() == this_player() ) return "That's silly."; + return this_player()->CanEvade(this_object()); +} + +object *AddFollower(object follower){ + mapping tmp = ([]); + + if( !objectp(follower) ) error("Bad argument 1 to AddFollower().\n"); + if( follower != this_object() && !Followers[follower] + && !follower->GetProperty("no follow") ){ + if( !follower->IsFollowing(this_object()) ){ + if( follower->SetLeader(this_object()) ){ + tmp["followed"] = 0; + tmp["bonus"] = 0; + tmp["lost"] = 0; + Followers[follower] = tmp; + numberOfFollowers++; + } + } + } + return GetFollowers(); +} + +object *RemoveFollower(object follower){ + if( !objectp(follower) ) error("Bad argument 1 to RemoveFollower().\n"); + map_delete(Followers, follower); + follower->SetLeader(0); + numberOfFollowers = sizeof(GetFollowers()); + return GetFollowers(); +} + +object *GetFollowers(){ return filter(keys(Followers), (: $1 :)); } + +mapping GetFollowerMap(){ return copy(Followers); } + +int SetFollowed(object follower, int followed){ + if( !objectp(follower) ) error("Bad argument 1 to SetFollowed().\n"); + if( !intp(followed) ) error("Bad argument 2 to SetFollowed().\n"); + if( !Followers[follower] ) return 0; + return(Followers[follower]["followed"] = followed); +} + +int GetFollowed(object follower){ + if( !objectp(follower) ) error("Bad argument 1 to GetFollowBonus().\n"); + if( !Followers[follower] ) return 0; + return Followers[follower]["followed"]; +} + +int AddFollowBonus(object follower, int bonus){ + if( !objectp(follower) ) error("Bad argument 1 to AddFollowBonus().\n"); + if( !intp(bonus) ) error("Bad argument 2 to AddFollowBonus().\n"); + if( !Followers[follower] ) return 0; + return( Followers[follower]["bonus"] += bonus ); +} + +int GetFollowBonus(object follower){ + if( !objectp(follower) ) error("Bad argument 1 to GetFollowBonus().\n"); + if( !Followers[follower] ) return 0; + return Followers[follower]["bonus"]; +} + +varargs mixed CanLead(object ob){ + if( ob ){ + if( !ob->CanFollow() ) + return "You are not empowered to lead " + ob->GetName(); + if( ob->IsFollowing(this_object()) ) + return "You are already leading " + ob->GetName(); + if( this_object()->IsFollowing(ob) ) + return ob->GetName() + " is already leading you."; + if( ob == this_object() ) + return "You cannot possibly do that."; + } + return 1; +} + +varargs mixed CanEvade(object ob){ + if( ob && !ob->IsFollowing(this_object()) ) + return ob->GetName() + " is not following you."; + return 1; +} + +int eventMoveFollowers(object dest){ + mapping follower; + object ob; + int followChance; + int badpos; + + badpos = (POSITION_NULL|POSITION_SITTING|POSITION_LYING|POSITION_KNEELING); + + foreach(ob in GetFollowers()){ + int pos = ob->GetPosition(); + follower = Followers[ob]; + if(ob->GetSleeping() || ob->GetParalyzed() || pos & badpos + || this_object()->GetInvis() ){ + eventEvade(ob); + RemoveFollower(ob); + continue; + } + followChance = 100; + if( !follower["followed"] ) followChance -= 20 + this_object()->GetSkillLevel("stealth"); + followChance += ob->GetSkillLevel("tracking"); + followChance += follower["bonus"]; + if( ob->eventFollow(dest, followChance) ) follower["lost"] = 0; + else if( follower["lost"]++ && eventEvade(ob) ){ + RemoveFollower(ob); + } + } + return 1; +} + +int eventEvade(object ob){ + mixed ret; + ret = CanEvade(ob); + if( stringp(ret) ) error(ret); + if( ret = 1 ){ + ob->eventPrint(this_object()->GetName() + " has evaded you."); this_object()->eventPrint("You have evaded " + ob->GetName() + "."); + return 1; + } + return 0; +} diff --git a/lib/lib/leader.c b/lib/lib/leader.c new file mode 100644 index 0000000..a739ef7 --- /dev/null +++ b/lib/lib/leader.c @@ -0,0 +1,189 @@ +/* /domains/Ylsrim/npc/leader.c + * from the Dead Souls Object Library + * class leader inheritable + * created by Descartes of Borg 951115 + * Version: @(#) leader.c 1.5@(#) + * Last modified: 96/11/24 + */ + +#include <lib.h> +#include <daemons.h> +#include <message_class.h> +#include "include/leader.h" + +inherit LIB_SENTIENT; + +int eventTeachPlayer(object who, string spell); + +static void create(){ + sentient::create(); +} + +mixed eventAsk(object who, string str){ + string cmd, args; + mixed tmp; + string lang, prof, orig = str; + + lang = who->GetDefaultLanguage(); + prof = who->GetLanguageLevel(lang); + str = translate(str, prof); + prof = this_object()->GetLanguageLevel(lang); + str = translate(str, prof); + + if( (tmp = sentient::eventAsk(who, orig)) == 1 ) return 1; + if( !str || str == "" ){ + eventForce("speak ask me to what? To describe " + + (GetClass() || "thing") + "s?"); + return 1; + } + if( sscanf(str, "%s %s", cmd, args) != 2 ){ + cmd = str; + args = 0; + } + switch(cmd){ + case "describe": case "preview": case "explain": + eventPreview(who, args); + break; + + case "convert": + eventConvert(who, args); + break; + + case "join": case "become": case "be": + eventJoin(who, args); + break; + + case "teach": + eventTeachPlayer(who, args); + break; + + default: + eventForce("speak I am not sure what you want"); + if( who->GetClass() ){ + eventForce("speak do you mean to ask me to teach a spell?"); + } + else { + eventForce("speak do you mean to ask me to describe " + + pluralize((GetClass()||"thing")) + "?"); + } + break; + } + return 1; +} + +void eventConvert(object who, string args){ + if( GetSkillLevel("faith") < 1 ){ + eventForce("speak I don't do conversions"); + return; + } + if( !args || args == "" ){ + eventForce("speak convert whom?"); + return; + } + if( args != "me" ){ + object ob; + + ob = present(args, environment()); + if( !ob ){ + eventForce("speak I don't see any such thing here"); + return; + } + if( !living(ob) ){ + eventForce("laugh"); + eventForce("speak would you like to worship some cheese too?"); + return; + } + if( ob != who ){ + eventForce("speak " + ob->GetName() + " must request " + "conversion of " + possessive(ob) + " own free will."); + return; + } + } + who->SetProperty("converting", GetReligion(1)); + eventForce("speak I will give it a try, I hope my faith serves me"); + call_out((: eventForce("convert " + ($(who))->GetKeyName()) :), 1); +} + +void eventPreview(object who, string args){ + if( args ) args = remove_article(lower_case(args)); + if( args && args != "" && args != (""+GetClass()) ){ + if( args[0..<2] != GetClass() ){ + eventForce("speak You want me to describe what?"); + return; + } + } + who->eventPage(DIR_CLASS_HELP "/" + GetClass(), MSG_HELP); +} + +void eventJoin(object who, string args){ + string myclass = (GetClass() || "thing"); + if( !args || args == "" ){ + eventForce("speak Do you mean you wish to become " + + add_article(myclass) + "?"); + return; + } + args = remove_article(lower_case(args)); + if( args != myclass && args[0..<2] != myclass && + args != pluralize(myclass) ){ + eventForce("speak you want me to make you a what?"); + eventForce("speak people only ask me to join the " + + pluralize(myclass)); + return; + } + if( who->ClassMember(myclass) ){ + eventForce("speak You are already " + add_article(myclass)); + return; + } + if( who->GetClass() == who->SetClass(GetClass()) ){ + eventForce("speak You cannot become " + add_article(GetClass()) + "!"); + eventForce("attack " + who->GetKeyName()); + return; + } + if( !(who->GetReligion()) && GetReligion() ) + who->SetReligion(GetReligion(0), GetReligion(1)); + environment()->eventPrint(GetName() + " makes " + who->GetName() + + " " + add_article(GetClass()) + ".", + ({ who, this_object() })); + eventForce("speak welcome new " + GetClass() + "!"); + eventForce("speak Inside this hall, you will find sanctuary."); + eventForce(GetClass() + " " + who->GetName() + + " just joined our ranks!"); + who->SetShort("foo"); /* reset title */ + return; +} + +int eventPreAttack(object ob){ + if( member_array(ob, GetEnemies()) > -1 ) return sentient::eventPreAttack(ob); + eventForce(GetClass() + " " + pluralize((GetClass() || "citizen")) + "! Our home is " + "being raided by " + ob->GetName() + "!"); + return sentient::eventPreAttack(ob); +} + +int eventTeachPlayer(object who, string spell){ + object ob = SPELLS_D->GetSpell(spell); + + if( ob ){ + foreach(string skill in ob->GetSkills()){ + if( GetSkillLevel(skill) < ob->GetRequiredSkill(skill) ){ + eventForce("speak I don't know " + spell + "."); + return 1; + } + } + if( !who->eventLearnSpell(spell) ){ + eventForce("speak You are not prepared for that spell!"); + return 1; + } + who->eventPrint(GetName() + " touches your forehead and gives " + "you knowledge of " + spell + "."); + environment()->eventPrint(GetName() + " touches " + + possessive_noun(who) + + " forehead and gives " + + objective(who) + " knowledge of " + + spell + ".", who); + return 1; + } + else { + eventForce("speak I have never heard of such a spell"); + return 1; + } +} diff --git a/lib/lib/learn.c b/lib/lib/learn.c new file mode 100644 index 0000000..8f18019 --- /dev/null +++ b/lib/lib/learn.c @@ -0,0 +1,17 @@ +#include <lib.h> + +int direct_learn_str_from_liv(){ return 1;} +int direct_learn_to_str_from_liv(){ return 1;} + +int CanLearn(){ + return 1; +} + +int eventLearn(object who, string what){ + if(!CanLearn()){ + write("You can't learn that."); + return 0; + } + who->eventTeach(this_player(),what); + return 1; +} diff --git a/lib/lib/light.c b/lib/lib/light.c new file mode 100644 index 0000000..3b6de09 --- /dev/null +++ b/lib/lib/light.c @@ -0,0 +1,69 @@ +/* /lib/light.c + * from the Dead Souls LPC Library + * a standard lighting object + * created by Descartes of Borg 960512 + * Version: @(#) light.c 1.2@(#) + * Last modified: 96/11/03 + */ + +#include <vendor_types.h> + +private int Lit = 0; + +// abstract methods +string GetKeyName(); +// end abstract methods + +static void create(){ + this_object()->AddSave(({ "Lit" })); + this_object()->SetVendorType(VT_LIGHT); +} + +int GetLit(){ + return Lit; +} + +static int SetLit(int x){ + return (Lit = x); +} + +string GetShort(){ + /* string str; + + if(!(str = item::GetShort()) || str == "") return str; + return sprintf("%s%s", str, (GetLit() ? " (lit)" : "")); + */ + if( GetLit() && query_verb() != "light" && query_verb() != "strike") return " (%^BOLD%^YELLOW%^lit%^RESET%^)"; + else return ""; +} + +mixed CanLight(object who){ + if( GetLit() ){ + return "#It is already lit."; + } + return 1; +} + +mixed direct_light_obj(){ + return CanLight(this_player()); +} + +mixed eventDarken(){ + object env; + + if( env = environment() ){ + env->eventPrint("The " + GetKeyName() + " goes dark."); + if( living(env) ){ + environment(env)->eventPrint(possessive_noun(env) + " " + + GetKeyName() + " goes dark.", env); + } + } + SetLit(0); + return 1; +} + +varargs mixed eventLight(object who, object tool){ + SetLit(1); + return 1; +} + diff --git a/lib/lib/living.c b/lib/lib/living.c new file mode 100644 index 0000000..255aacf --- /dev/null +++ b/lib/lib/living.c @@ -0,0 +1,885 @@ +/* /lib/living.c + * from the Dead Souls Object Library + * handles common living code + * created by Descartes of Borg 951218 + * Version: @(#) living.c 1.29@(#) + * Last Modified: 96/12/15 + */ + +#include <lib.h> +#include <daemons.h> +#include <position.h> +#include <message_class.h> +#include "include/living.h" + +inherit LIB_CARRY; +inherit LIB_DROP; +inherit LIB_GET; +inherit LIB_COMBAT; +inherit LIB_CURRENCY; +inherit LIB_FOLLOW; +inherit LIB_MAGIC; +inherit LIB_LEAD; +inherit LIB_TEACH; +inherit LIB_LEARN; +inherit LIB_QUEST; +inherit LIB_STOP; + +private int isPK; +private mixed Attackable = 1; +private int NoCondition = 0; + +varargs mixed CanReceiveHealing(object who, string limb); + +static void create(){ + combat::create(); + currency::create(); + follow::create(); + lead::create(); + isPK = 0; +} + +int is_living(){ return 1; } + +int inventory_accessible(){ return 1; } + +mixed direct_verb_rule(string verb){ + return SOUL_D->CanTarget(this_player(), verb, this_object()); +} + +mixed direct_ride_str(){ + return this_object()->GetMount(); +} + +mixed direct_ride_word_str(){ + return this_object()->GetMount(); +} + +mixed direct_mount_liv(){ + return this_object()->GetMount(); +} + +mixed direct_dismount_liv(){ + return this_object()->GetMount(); +} + +mixed direct_dismount_from_liv(){ + return this_object()->GetMount(); +} + +mixed direct_attack_liv(){ + if(this_player() == this_object()){ + return "#You can't attack yourself."; + } + if(intp(Attackable) && !Attackable){ + return "You are unable to attack "+this_object()->GetShort()+"."; + } + if(stringp(Attackable)) return Attackable; + return 1; +} + +mixed CanAttack(){ + if(this_player() == this_object()){ + return "You can't attack yourself."; + } + if( userp(this_player()) && userp(this_object()) ){ + if(!(environment()->CanAttack(this_player(), this_object()))){ + return "Player killing is not permitted in this area!"; + } + if(intp(Attackable) && !Attackable){ + return "You are unable to attack "+this_object()->GetShort()+"."; + } + if(this_player()->GetPK() && this_object()->GetPK()){ + if(!PLAYER_KILL) return "This is not a PK mud."; + } + else return "One of you is not a player killer. You cannot fight them."; + } + if(functionp(Attackable)) return evaluate(Attackable, this_player()); + else { + return (Attackable || 0); + } +} + +mixed direct_attack_only_liv(){ + return direct_attack_liv(); +} + +mixed direct_attack_liv_only(){ + return direct_attack_liv(); +} + +mixed direct_target_liv(){ + return direct_attack_liv(); +} + +mixed direct_target_only_liv(){ + return direct_attack_liv(); +} + +mixed direct_target_liv_only(){ + return direct_attack_liv(); +} + +mixed direct_bite_liv(){ + return 1; +} + +mixed direct_capture_liv_word_obj(){ + return 1; +} + +mixed direct_pray_for_str_against_str_for_liv(){ + return 1; +} + +mixed direct_cast_str_on_obj(){ + return 1; +} + +mixed direct_cast_str_against_str(){ + return 1; +} + + +mixed direct_cast_str_on_str_of_obj(){ + return 1; +} + +mixed direct_free_liv_from_obj(){ + return 1; +} + +mixed direct_resurrect_obj(){ return 1; } +mixed indirect_resurrect_obj(){ return 1; } + +mixed direct_get_obj(mixed args...){ + int mysize = this_object()->GetSize(1); + int theirsize = this_player()->GetSize(1); + if(archp(this_player())) return 1; + if(creatorp(this_player()) && !creatorp(this_object())){ + return get::direct_get_obj(args...); + } + if(interactive(this_player()) && creatorp(this_object())){ + return "NO."; + } + if(this_object()->GetBefriended(this_player())) return 1; + if((theirsize - mysize) > 1) return get::direct_get_obj(args...); + return "It's too big!"; +} + +mixed direct_get_obj_from_obj(mixed args...){ + return direct_get_obj(args...); +} + +mixed direct_show_liv_obj(){ + if( this_player() == this_object() ) return "Are you confused?"; + return 1; +} + +mixed indirect_show_obj_to_liv(object item){ + if( !item ) return 0; + if( this_player() == this_object() ) return "Are you confused?"; + if( environment(item) != this_player() ) return "You don't have that!"; + else return 1; +} + +mixed indirect_show_obj_liv(object item){ + return indirect_show_obj_to_liv(item); +} + +mixed direct_give_liv_obs(){ + return direct_give_liv_obj(); +} + +mixed direct_give_liv_obj(){ + if( this_player() == this_object() ) return "Are you confused?"; + return 1; +} + +mixed indirect_give_obj_to_liv(object item){ + if( !item ) return 0; + if( this_player() == this_object() ) return "Are you confused?"; + if( environment(item) != this_player() ) return "You don't have that!"; + if(!CanCarry(item->GetMass())){ + return this_object()->GetName()+" is carrying too much."; + } + else return CanCarry(item->GetMass()); +} + +mixed indirect_give_obj_liv(object item){ + return indirect_give_obj_to_liv(item); +} + +mixed indirect_give_obs_to_liv(object *items){ + return 1; +} + +mixed indirect_give_obs_liv(object *items){ + return indirect_give_obs_to_liv(items); +} + +mixed direct_give_liv_wrd_wrd(object targ, string num, string curr){ + return direct_give_wrd_wrd_to_liv(num, curr); +} + +mixed direct_give_wrd_wrd_to_liv(string num, string curr){ + mixed tmp; + int amt; + + if( this_object() == this_player() ) + return "Are you feeling a bit confused?"; + if( (amt = to_int(num)) < 1 ) return "What sort of amount is that?"; + tmp = CanCarry(currency_mass(amt, curr)); + if( tmp != 1 ) return GetName() + " cannot carry that much "+ curr+ "."; + return 1; +} + +mixed direct_steal_wrd_from_liv(string wrd){ + if( wrd != "money" ) return 0; + if( this_player() == this_object() ) return "Are you a fool?"; + if( this_player()->GetInCombat() ) + return "You are too busy fighting at the moment."; + return 1; +} + +mixed indirect_steal_obj_from_liv(object item, mixed args...){ + mixed tmp; + + if( environment()->GetProperty("no attack") ) + return "Mystical forces prevent your malice."; + if( !item ) return 1; + if( environment(item) != this_object() ) return 0; + if( this_player() == this_object() ) return "Are you a fool?"; + if( this_player()->GetInCombat() ) + return "You are too busy fighting at the moment."; + tmp = item->CanDrop(this_object()); + if( tmp != 1 ) + return GetName() + " will not let go of " + item->GetShort()+"."; + return 1; +} + +mixed direct_backstab_liv(){ + if( this_object() == this_player() ) + return "That would be messy."; + if( member_array(this_object(), this_player()->GetEnemies()) != -1 ) + return "%^RED%^You have lost the element of surprise."; + if( environment()->GetProperty("no attack") || + GetProperty("no backstab") ) + return "A mysterious forces stays your hand."; + return 1; +} + +mixed direct_heal_str_of_liv(string limb){ + string array limbs = GetLimbs(); + mixed tmp; + + limb = lower_case(remove_article(limb)); + if( !limbs ){ + if( this_object() == this_player() ){ + return "You have no limbs!"; + } + else { + return GetName() + " has no limbs!"; + } + } + else if( member_array(limb, limbs) == -1 ){ + if( this_object() == this_player() ){ + return "You have no " + limb + "."; + } + else { + return GetName() + " has no " + limb + "."; + } + } + tmp = CanReceiveHealing(this_player(), limb); + if( tmp != 1 ){ + return tmp; + } + return CanReceiveMagic(0, "heal"); +} + +mixed direct_remedy_str_of_liv(string limb){ + string *limbs; + limbs = GetLimbs(); + if( !limbs ){ + if( this_object() == this_player() ) return "You have no limbs!"; + else return GetName() + " has no limbs!"; + } + else if( member_array(limb, limbs) == -1 ){ + if( this_object() == this_player() ) return "You have no " + limb + "."; + else return GetName() + " has no " + limb + "."; + } + return CanReceiveMagic(0, "remedy"); +} + +mixed direct_regen_str_on_liv(string limb){ + if( !limb ) return 0; + if( member_array(limb, GetMissingLimbs()) == -1 ){ + return "That is not a missing limb!"; + } + return CanReceiveMagic(0, "regen"); +} + +mixed direct_teleport_to_liv(){ + if( environment()->GetProperty("no teleport") || + environment()->GetProperty("no magic") ){ + return "Mystical forces prevent your magic."; + } + else return CanReceiveMagic(0, "teleport"); +} + +mixed direct_portal_to_liv(){ + return direct_teleport_to_liv(); +} + +mixed direct_resurrect_liv(){ + if( this_player() == this_object() ) + return "You cannot resurrect yourself."; + if( !GetUndead() ) + return GetName() + " is not dead!"; + return CanReceiveMagic(0, "resurrect"); +} + +mixed direct_scry_liv(){ + object env = environment(); + + if( this_player() == this_object() ) + return "Scry yourself??"; + if( !env ) return GetName() + " is nowhere."; + if( env->GetProperty("no magic") || env->GetProperty("no scry") ) + return GetName() + " is beyond your reach."; + return CanReceiveMagic(0, "scry"); +} + +mixed indirect_zap_liv(){ return 1; } +mixed direct_zap_liv(){ return 1; } +mixed indirect_pulsecheck_liv(){ return 1; } +mixed direct_pulsecheck_liv(){ return 1; } + +/* hostile spells */ + +int direct_rockwhip_liv(){ return CanReceiveMagic(1, "rockwhip"); } +int direct_acidspray_liv(){ return CanReceiveMagic(1, "acidspray"); } +int direct_annihilate_at_liv(){ return CanReceiveMagic(1, "annihilate"); } +int direct_annihilate_liv(){ return CanReceiveMagic(1, "annihilate"); } +int direct_arrow_liv(){ return CanReceiveMagic(1, "arrow"); } +int direct_arrow_at_liv(){ return CanReceiveMagic(1, "arrow"); } +int direct_blades_at_liv(){ return CanReceiveMagic(1, "blades"); } +int direct_blades_liv(){ return CanReceiveMagic(1, "blades"); } +int direct_corrupt_liv(){ return CanReceiveMagic(1, "currupt"); } +int direct_demonclaw_liv(){ return CanReceiveMagic(1, "demonclaw"); } +int direct_dispel_liv(){ return CanReceiveMagic(1, "dispel"); } +int direct_drain_at_liv(){ return CanReceiveMagic(1, "drain"); } +int direct_drain_liv(){ return CanReceiveMagic(1, "drain"); } +int direct_fireball_at_liv(){ return CanReceiveMagic(1, "fireball"); } +int direct_fireball_liv(){ return CanReceiveMagic(1, "fireball"); } +int direct_frigidus_at_liv(){ return CanReceiveMagic(1, "frigidus"); } +int direct_frigidus_liv(){ return CanReceiveMagic(1, "frigidus"); } +int direct_holylight_liv(){ return CanReceiveMagic(1, "holylight"); } +int direct_missile_liv(){ return CanReceiveMagic(1, "missile"); } +int direct_missile_at_liv(){ return CanReceiveMagic(1, "missile"); } +int direct_shock_liv(){ return CanReceiveMagic(1, "shock"); } +int direct_palm_liv(){ return CanReceiveMagic(1, "palm"); } +int direct_immolate_liv(){ return CanReceiveMagic(1, "immolate"); } +int direct_gale_liv(){ return CanReceiveMagic(1, "gale"); } + +/* other spells */ + +int direct_aura_liv(){ return CanReceiveMagic(0, "aura"); } +int direct_soulseek_liv(){ return CanReceiveMagic(0, "soulseek"); } +int direct_cloak_wrd(){ return CanReceiveMagic(0, "cloak"); } +int direct_stealth_wrd(){ return CanReceiveMagic(0, "stealth"); } +int direct_backlash_for_liv(){ return CanReceiveMagic(0, "backlash"); } +int direct_backlash_for_liv_against_wrd(){ return CanReceiveMagic(0, "backlash"); } +int direct_balance_obj_to_obj(){ return CanReceiveMagic(0, "balance"); } +int direct_buffer_liv(){ return CanReceiveMagic(0, "buffer"); } +int direct_calm_liv(){ return CanReceiveMagic(0, "calm"); } +int direct_cleanse_liv(){ return CanReceiveMagic(0, "cleanse"); } +int direct_convert_liv(){ return CanReceiveMagic(0, "convert"); } +int direct_shield_liv(){ return CanReceiveMagic(0, "shield"); } +int direct_veil_liv_against_wrd_wrd(){ return CanReceiveMagic(0, "veil"); } +int direct_ward_liv_against_wrd(){ return CanReceiveMagic(0, "ward"); } +int direct_remedy_liv(){ return CanReceiveMagic(0, "remedy"); } +int direct_command_str_to_str(){ return CanReceiveMagic(0, "command"); } +int direct_gaze(){ return CanReceiveMagic(0, "gaze"); } +int direct_send_str_to_str(){ return CanReceiveMagic(0, "send"); } +int direct_connect_str(){ return CanReceiveMagic(0, "connect"); } +int direct_heal_liv(){ return CanReceiveMagic(0, "heal"); } +int direct_mend_liv(){ return CanReceiveMagic(0, "mend"); } +int direct_refresh_liv(){ return CanReceiveMagic(0, "refresh"); } +int direct_rejuvinate_liv(){ return CanReceiveMagic(0, "rejuvinate"); } +int direct_farsight_liv(){ return 1; } +int direct_bump_liv(){ return 1; } +int direct_evade_liv(){ return 1; } +int direct_follow_liv(){ return 1; } +int direct_lead_liv(){ return 1; } +int direct_marry_liv_to_liv(){ return 1; } +int direct_party_wrd_liv(){ return 1; } +int direct_challenge_liv(){ return 1; } +int direct_ignore_liv(){ return 1; } + +int indirect_throw_obj_at_obj(){ return 1; } +int indirect_toss_obj_at_obj(){ return 1; } +int indirect_buy_str_from_liv(){ return 1; } +int indirect_sell_obj_to_liv(){ return 1; } +int indirect_marry_liv_to_liv(){ return 1; } + + +/* ********** /lib/living.c modal methods ********** */ +int CanCarry(int amount){ return carry::CanCarry(amount); } + +varargs mixed CanReceiveHealing(object who, string limb){ + int max, hp; + + max = GetMaxHealthPoints(limb); + hp = GetHealthPoints(limb); + if( (max-hp) < max/20 ){ + if( limb ){ + return possessive_noun(GetName()) + " " + limb + " needs no help."; + } + else { + return GetName() + " needs no help."; + } + } + return 1; +} + +mixed CanReceiveMagic(int hostile, string spell){ + if( GetProperty(spell) == "immune" ){ + this_player()->eventPrint(GetName() + " is immune to such magic."); + return 0; + } + if( !hostile ) return 1; + if( this_player() == this_object() ){ + eventPrint("That would be construed as quite foolish."); + return 0; + } + return 1; +} + +varargs mixed CanCastMagic(int hostile, string spell){ + object env = environment(); + + if( !env ) eventPrint("You are nowhere!"); + if( spell && GetProperty("no " + spell) ){ + eventPrint("A mysterious forces prevents you from doing that."); + return 0; + } + if( env->GetProperty("no magic") ){ + eventPrint("Mystical forces prevent your magic."); + return 0; + } + if( !hostile ) return 1; + if( env->GetProperty("no attack" ) ){ + eventPrint("Mystical forces prevent your hostile intentions."); + return 0; + } + return 1; +} + +/* ********** /lib/living.c event methods ********** */ + +mixed eventCure(object who, int amount, string type){ + object array germs = filter(all_inventory(), + (: $1->IsGerm() && $1->GetType()== $(type) :)); + + if( !sizeof(germs) ){ + return GetName() + " suffers from no such affliction."; + } + return germs[0]->eventCure(who, amount, type); +} + +int eventFollow(object dest, int followChance){ + string dir; + int ret; + + if( objectp(dest) ){ + if( !environment() ){ + Destruct(); + return 0; + } + dir = environment()->GetDirection(base_name(dest)); + } + if( !stringp(dir) ) dir = ""; + if( dir != "" && followChance > random(100) ){ + eventForce(dir); + } + if( environment() == dest ) return 1; + else { + string newdir = replace_string(dir,"go ",""); + if(newdir) ret = environment(this_object())->eventGo(this_object(), newdir); + if(!ret){ + newdir = replace_string(dir,"enter ",""); + ret = environment(this_object())->eventEnter(this_object(), newdir); + } + } + return ret; +} + +mixed eventInfect(object germ){ + return germ->eventInfect(this_object()); +} + +varargs mixed eventShow(object who, string str){ + string desc = this_object()->GetItem(str); + if(!desc){ + who->eventPrint(this_object()->GetLong(str)); + } + else { + who->eventPrint(desc); + } + environment(who)->eventPrint(this_player()->GetName() + + " looks at " + this_object()->GetShort() + ".", + ({ who, this_object() })); + return 1; +} + +/* when who == this_object(), I am doing the stealing + * otherwise I am being stolen from + */ +varargs mixed eventSteal(object who, mixed what, object target, int skill){ + + int i, sr; + + if( who == this_object() ){ + mixed tmp; + int amt, skill2; + + skill2 = to_int(to_float(GetSkillLevel("stealing"))*2.5); + skill2 += GetMobility(); + skill2 += GetStatLevel("coordination"); + skill2 += GetStatLevel("charisma"); + skill2 += to_int(GetStatLevel("luck")/2); + if( ClassMember("rogue") ) skill2 += GetLevel(); + if( ClassMember("thief") ) skill2 += GetLevel(); + + if( !stringp(what) ){ + int x; + + x = sizeof(what); + if( GetStaminaPoints() < 20.0*x ){ + eventPrint("You are clumsy in your fatigue."); + if(target->GetRace() != "kender"){ + target->SetAttack(this_object()); + target->eventExecuteAttack(this_object()); + } + return 1; + } + AddStaminaPoints(-20); + + tmp = target->eventSteal(who, what, target,skill2); + + /* You can't steal from this target */ + if( !tmp ) + return "You cannot steal from " + target->GetName() +"."; + + /* Steal from target was succesful */ + else if( tmp == 1 ){ + + what = filter(what, (: $1 :)); + AddSkillPoints("stealing", implode(map(what, + (: $1->GetMass() :)), + (: $1 + $2 :)) + + GetSkillLevel("stealing") * GetSkillLevel("stealing")*3); + AddSkillPoints("stealth", random(sizeof(what)) * 20); + AddStaminaPoints(-2); + this_player()->eventPrint(sprintf("You steal %s from %s.", + "something", target->GetName()) ); + what->eventMove(this_object()); + return 1; + } + + /* Steal was unsuccesful */ + else if( tmp == 2 ){ + AddSkillPoints("stealing", GetSkillLevel("stealing")*2); + AddStaminaPoints(-5); + return 1; + } + + else return tmp; + } + /********************************************/ + /* This part deals with stealing money */ + + amt = GetNetWorth(); + eventPrint("You reach for " + possessive_noun(target) + " money."); + tmp = target->eventSteal(who, what, target, skill2); + + /* You can't steal from this target */ + if( !tmp ) + return "You cannot steal from " + target->GetName() + "."; + + /* Steal from target was succesful */ + else if( tmp == 1 ){ + amt = GetNetWorth() - amt; + if( amt < 1 ) return tmp; + AddSkillPoints("stealing", random(7*amt) + + GetSkillLevel("stealing") * GetSkillLevel("stealing") * 2); + AddSkillPoints("stealth", random(amt)); + AddStatPoints("coordination", random(amt)); + AddStaminaPoints(-3); + eventPrint("You come away with some money!"); + return tmp; + } + + /* Steal was unsuccesful */ + else if( tmp == 2){ + AddSkillPoints("stealing", GetSkillLevel("stealing")*2); + AddStaminaPoints(-5); + return 1; + } + + return tmp; + } + /*******************************************************************/ + if( GetInCombat() ){ + who->eventPrint(GetName() + " is busy in combat."); + return 0; + } + skill -= to_int(GetMobility()/2); + skill -= GetStatLevel("agility"); + skill -= GetStatLevel("wisdom"); + skill -= to_int(GetStatLevel("luck")/3); + + if( objectp(what) ) sr = 100 * sizeof(what); + else sr = 100; + if( random(sr) > skill ){ + target->eventPrint("You notice " + who->GetName() + " trying " + "to steal from you!"); + if( !userp(this_object()) ){ + who->eventPrint("%^RED%^" + GetName() + "%^RED%^ " + "notices your attempt at treachery!", + environment(who) ); + eventForce("attack " + who->GetKeyName()); + this_object()->SetProperty("steal victim", 1); + } + return 2; + } + + if( random(2*sr) > skill ){ + who->eventPrint("You are unsure if anyone noticed your foolish " + "attempt at thievery.",environment(who) ); + return 2; + } + + if( stringp(what) ){ + + foreach(string curr in GetCurrencies()){ + int x; + + if( !(x = random(GetCurrency(curr)/5)) ) continue; + if( x > 100 ) x = 100; + x = (x * skill)/100; + AddCurrency(curr, -x); + who->AddCurrency(curr, x); + } + return 1; + } + for(i=0; i<sizeof(what); i++){ + if( what[i]->eventSteal(who) != 1 ) what[i] = 0; + } + return 1; +} + +int AddCarriedMass(int x){ return carry::AddCarriedMass(x); } + +int GetCarriedMass(){ + return (currency::GetCurrencyMass() + carry::GetCarriedMass()); +} + +int GetNonCurrencyMass(){ + return (carry::GetCarriedMass()); +} + +int GetMaxCarry(){ return combat::GetMaxCarry(); } + +int SetPK(int x){ return (isPK = x); } + +int GetPK(){ return isPK; } + +int SetDead(int i){ + return combat::SetDead(i); +} + +mixed SetAttackable(mixed foo){ + Attackable = foo; + return Attackable; +} + +mixed GetAttackable(){ + return Attackable; +} + +int SetNoCondition(int foo){ + NoCondition = foo; + return NoCondition; +} + +int GetNoCondition(){ + return NoCondition; +} + +varargs int eventMoveLiving(mixed dest, string omsg, string imsg, mixed dir){ + object *inv; + object prev; + string prevclim, newclim; + int check = GUARD_D->CheckMove(this_object(), dest, dir); + + if(!check){ + eventPrint("You remain where you are.", MSG_SYSTEM); + return 0; + } + if(omsg && stringp(omsg)){ + omsg = replace_string(omsg, "$N", this_object()->GetName()); + } + if(imsg && stringp(imsg)){ + imsg = replace_string(imsg, "$N", this_object()->GetName()); + } + + if( prev = environment() ){ + prevclim = prev->GetClimate(); + if( stringp(dest) ){ + if(dest[0] != '/'){ + string *arr; + + arr = explode(file_name(prev), "/"); + dest = "/"+implode(arr[0..sizeof(arr)-2], "/")+"/"+dest; + } + } + if( !eventMove(dest) ){ + eventPrint("You remain where you are.", MSG_SYSTEM); + return 0; + } + if(prev){ + inv = filter(all_inventory(prev), (: (!this_object()->GetInvis($1) + && living($1) && !GetProperty("stealthy") && ($1 != this_object())) :)); + } + if(!dir) dir = "away"; + if(query_verb() == "home" ){ + if(!omsg || omsg == "") omsg = GetMessage("telout"); + if(!imsg || imsg == "") imsg = GetMessage("telin"); + } + else if(GetPosition() == POSITION_SITTING || + GetPosition() == POSITION_LYING ){ + if(!omsg || omsg == "") omsg = GetName()+" crawls "+dir+"."; + if(!imsg || imsg == "") imsg = GetName()+" crawls in."; + } + else if(GetPosition() == POSITION_FLYING ){ + if(!omsg || omsg == "") omsg = GetName()+" flies "+dir+"."; + if(!imsg || imsg == "") imsg = GetName()+" flies in."; + } + else { + if(!omsg || omsg == "") omsg = GetMessage("leave",dir); + if(!imsg || imsg == "") imsg = GetMessage("come"); + } + if(sizeof(inv)) inv->eventPrint(omsg, MSG_ENV); + } + else if( !eventMove(dest) ){ + eventPrint("You remain where you are.", MSG_SYSTEM); + return 0; + } + inv = filter(all_inventory(environment()), + (: (!this_object()->GetInvis($1) && !GetProperty("stealthy") && + living($1) && ($1 != this_object())) :)); + + inv->eventPrint(imsg, MSG_ENV); + if(this_object()->GetInvis()){ + if(!creatorp(this_object())) AddStaminaPoints(-(15-(GetSkillLevel("stealth")/10))); + AddSkillPoints("stealth", 30 + GetSkillLevel("stealth")*2); + eventPrint("%^RED%^You move along quietly....%^RESET%^\n"); + } + if(GetProperty("stealthy") && interactive(this_object())){ + if(!creatorp(this_object())) AddStaminaPoints(-3 - random(3)); + AddSkillPoints("stealth", 10 + GetSkillLevel("stealth")*2); + } + this_object()->eventDescribeEnvironment(this_object()->GetBriefMode()); + newclim = environment()->GetClimate(); + if( !GetUndead() ) switch( newclim ){ + case "arid": + if(!creatorp(this_object())) AddStaminaPoints(-0.3); + break; + case "tropical": + if(!creatorp(this_object())) AddStaminaPoints(-0.3); + break; + case "sub-tropical": + if(!creatorp(this_object())) AddStaminaPoints(-0.2); + break; + case "sub-arctic": + if(!creatorp(this_object())) AddStaminaPoints(-0.2); + break; + case "arctic": + if(!creatorp(this_object())) AddStaminaPoints(-0.3); + break; + default: + if(!creatorp(this_object())) AddStaminaPoints(-0.1); + break; + } + if( prevclim != newclim && prevclim != "indoors" && newclim != "indoors" ){ + switch(prevclim){ + case "arid": + if( newclim == "tropical" || newclim == "sub-tropical" ) + message("environment", "The air is much more humid.", + this_object()); + else message("environment", "The air is getting a bit cooler.", + this_object()); + break; + case "tropical": + if( newclim != "arid" ) + message("environment", "The air is not quite as humid.", + this_object()); + else message("environment", "The air has become suddenly dry.", + this_object()); + break; + case "sub-tropical": + if( newclim == "arid" ) + message("environment", "The air has become suddenly dry.", + this_object()); + else if( newclim == "tropical" ) + message("environment","The air has gotten a bit more humid.", + this_object()); + else message("environment", "The air is not quite as humid.", + this_object()); + break; + case "temperate": + if( newclim == "arid" ) + message("environment", "The air is a bit drier and warmer.", + this_object()); + else if( newclim == "tropical" ) + message("environment", "The air is much more humid.", + this_object()); + else if( newclim == "sub-tropical" ) + message("environment", "The air is a bit more humid.", + this_object()); + else message("environment", "The air is a bit colder now.", + this_object()); + break; + case "sub-arctic": + if( newclim == "arid" || newclim == "tropical" || + newclim == "sub-tropical" ) + message("environment", "It has suddenly grown very hot.", + this_object()); + else if( newclim == "arctic" ) + message("environment", "It is a bit cooler than before.", + this_object()); + else message("environment", "It is not quite as cold as " + "before.", this_object()); + break; + case "arctic": + if( newclim == "sub-arctic" ) + message("environment", "It is not quite as cold now.", + this_object()); + else message("environment", "It is suddenly much warmer than " + "before.", this_object()); + } + } + eventMoveFollowers(environment(this_object())); + TRACKER_D->TrackLiving(this_object()); + return 1; +} + +string GetEquippedShort(){ + return this_object()->GetHealthShort(); +} + +int GeteventPrints(){ + return 1; +} diff --git a/lib/lib/lvs/abilities.c b/lib/lib/lvs/abilities.c new file mode 100644 index 0000000..6b2e966 --- /dev/null +++ b/lib/lib/lvs/abilities.c @@ -0,0 +1,373 @@ +/* /lib/abilities.c + * From the Dead Souls LPC Library + * Handles learned traits + * Created by Descartes of Borg 950122 + * Version: @(#) abilities.c 1.22@(#) + * Last modified: 97/01/03 + */ + +#include <daemons.h> + +inherit LIB_LEVEL; + +private int Level = 1; +private mapping Skills = ([]); +private static mapping SkillsBonus = ([]); + +// abstract methods +varargs void eventPrint(string str, mixed args...); +// end abstract methods + +string array GetPrimarySkills(); +varargs void SetSkill(string skill, int level, mixed cls); + +/* ***************** abilities.c attributes ***************** */ +/* GetBaseSkillLevel() returns the unmodified skill level */ +int GetBaseSkillLevel(string skill){ + if( !Skills[skill] ){ + return 0; + } + else { + return Skills[skill]["level"]; + } +} + +int GetLevel(){ + return Level; +} + +/* static int ResetLevel() + * + * description + * takes the average skill level of the primary skills and divided by 4 + * and sets the level to that number + * + * returns the new level + */ +/* + * Excuse me, wtf is the point of this? + */ + +int ResetLevel(){ + string array skills = GetPrimarySkills(); + int num = sizeof(skills); + int points = 0; + + if( num < 1 ){ + return (Level = 1); + } + foreach(string skill in skills){ + points += Skills[skill]["level"]; + } + Level = (points/num)/2; + if( Level < 1 ){ + Level = 1; + } + return Level; +} + +int SetLevel(int x){ + string array skills = GetPrimarySkills(); + + if(!Level){ + foreach(string skill in skills){ + SetSkill(skill, 2*x); + } + } + return (Level = x); +} + +int GetMaxSkillLevel(string skill){ + int ret, cls = 4; +#ifdef MAX_SKILL_LEVEL +#if MAX_SKILL_LEVEL + ret = MAX_SKILL_LEVEL; + return ret; +#endif +#endif + cls -= (Skills[skill]["class"] || 4); + if(cls < 0) cls = 0; + ret = ((GetLevel()+cls) *2); + return ret; +} + +int GetMaxSkillPoints(string skill, int level){ + if( !Skills[skill] ){ + return 0; + } + else if( level == 0 ){ + return 200; + } + else { + int cl, x; + + if( !(cl = Skills[skill]["class"]) ){ + return level * 600; + } + if( cl > 4 ){ + cl = 4; + } + if( cl < 1 ){ + cl = 4; + } + x = level; + while( cl-- ){ + x *= level; + } + return (x * 400); + } +} + +string array GetPrimarySkills(){ + return filter(keys(Skills), (: Skills[$1]["class"] == 1 :)); +} + +/* varargs int AddSkill(string skill, int classes) + * string skill - the skill being added (required) + * int classes - the class of the skill (optional) + * + * defaults + * classes defaults to 1, primary class + * + * description + * Used to add a new ability to the list of abilities. "skill" is the name + * of the skill being added, and "class" represents the ranking of that skill + * + * returns 1 on success, 0 on failure + */ +varargs int AddSkill(string skill, int cls, int level){ + if( !stringp(skill) ){ + error("Bad argument 1 to AddSkill().\n\tExpected: string, Got: " + + typeof(skill) + "\n"); + } + if( !nullp(Skills[skill]) ){ + return 0; + } + if( !cls ){ + cls = 1; + } + if(!level){ + level = 1; + } + else if( cls < 0 || cls > 4){ + return 0; + } + Skills[skill] = ([ "points" : 0, "level" : level, "class" : cls ]); + return 1; +} + +mapping GetSkill(string skill){ + return copy(Skills[skill]); +} + +void RemoveSkill(string skill){ + if( !Skills[skill] ){ + return; + } + map_delete(Skills, skill); +} + +/* varargs void SetSkill(string skill, int level, int cls) + * string skill - the name of the skill being set (required) + * int level - the level to which that skill is being set (required) + * int classes - the class to which the skill is being set (optional) + * + * defaults + * classes will default to 1, primary class + * + * description + * sets the skill "skill" to the level "level" + * if a classes is given, its class is set to it, otherwise the class is + * set to 1 + * useful mostly for monster types, probably should have override + * protections in the user object (should use AddSkill() for users) + */ +varargs void SetSkill(string skill, int level, int cls){ + int tmp; + SKILLS_D->SetSkill(skill); + if(cls && !intp(cls)){ + tmp = 1; + cls = tmp; + } + if( !stringp(skill) ){ + error("Bad argument 1 to SetSkill().\n\tExpected: string, Got: " + + typeof(skill) + "\n"); + } + if( !cls ){ + if( Skills[skill] ){ + cls = Skills[skill]["class"]; + } + else { + cls = 1; + } + } + else if( cls < 1 || cls > 4){ + return 0; + } + Skills[skill] = ([ "points" : 0, "level" : level, "class" : cls ]); +} + +string array GetSkills(){ + return keys(Skills); +} + +mapping GetSkillsMap(){ + return copy(Skills); +} + +void AddSkillBonus(string skill, mixed f){ + if( !SkillsBonus[skill] ){ + SkillsBonus[skill] = ([]); + } + SkillsBonus[skill][previous_object()] = f; +} + +varargs void RemoveSkillBonus(string skill, object ob){ + if( !SkillsBonus[skill] ){ + return; + } + if( !ob ){ + ob = previous_object(); + } + if( !ob || !SkillsBonus[skill][ob] ){ + return; + } + map_delete(SkillsBonus[skill], ob); +} + +int GetSkillBonus(string skill){ + object ob; + int x = 0; + + if( !SkillsBonus[skill] ){ + return 0; + } + + if(intp(SkillsBonus[skill])) + return SkillsBonus[skill]; + + foreach(ob in keys(SkillsBonus[skill])){ + if( !ob ) continue; + else if(intp(SkillsBonus[skill][ob])) x += SkillsBonus[skill][ob]; + else x += evaluate(SkillsBonus[skill][ob], skill); + } + return x; +} + +int GetSkillClass(string skill){ + if( !Skills[skill] ){ + return 0; + } + else { + return Skills[skill]["class"]; + } +} + +/* GetSkillLevel() returns the base skill level + any bonuses */ +int GetSkillLevel(string skill){ + return (GetBaseSkillLevel(skill) + GetSkillBonus(skill)); +} + +/* int AddSkillPoints(string skill, int x) + * string name - the skill to which points are being added + * int x - the number of points being added + * + * description + * adds "x" points to the total for skill "skill" + * if the points go over the max for the current skill level, + * then the level is raised 1 + * if the points go under 0, then the skill level is lowered + * + * returns the skill level after addition + */ +int AddSkillPoints(string name, int x){ + int y; + + if( !Skills[name] ){ + return 0; + } + Skills[name]["points"] += x; + while( Skills[name]["points"] < 0 ){ /* lost skills! */ + if( Skills[name]["level"] == 1 ){ + Skills[name]["points"] = 0; + } + else { + int tmp; + if(Skills[name]["level"] > 1){ + tmp = --Skills[name]["level"]; + Skills[name]["points"] += GetMaxSkillPoints(name, tmp); + } + else break; + } + } + y = GetMaxSkillPoints(name, Skills[name]["level"]); + while( Skills[name]["points"] > y ){ + if( Skills[name]["level"] >= GetMaxSkillLevel(name) ){ + Skills[name]["points"] = y; + } + else { + eventPrint("%^YELLOW%^You are a bit more adept with your " + + name + "."); + Skills[name]["level"]++; + Skills[name]["points"] -= y; + } + y = GetMaxSkillPoints(name, Skills[name]["level"]); + } + return Skills[name]["level"]; +} + +/* ******************* abilities.c events ********************* */ +/** + * Trains a skill based on a scale of 1-100 in favour of success and 1-100 + * against success. Any particular thing (like calculating whether a player + * hits an enemy) determins whether an operation succeeds or fails. For + * example, pro = melee attack, con = melee defense. While the con may + * be greater than the pro, combat may randomize that. You still reward + * based on the absolutes. Success is flagged to this method. The value of + * training looks like this: + * highest- pro: 0, con: 100, success: 1 + * moderate- pro: 100, con: 0, success: 1 + * moderate- pro: 0, con 100, success: 0 + * low- pro: 100, con: 0, success: 0 + * This means if you have everything going against you and you succeed, you + * get the highest reward. If you have everything going for you and you fail, + * you get nothing. + * Adjustments are made for your level and any multiplier bonuses. + */ +varargs void eventTrainSkill(string skill, int pro, int con, int array a...){ + int level = (GetLevel()/8 + 1); + int val, success, bonus; + + if( sizeof(a) ){ + success = a[0]; + if( sizeof(a) == 2 ){ + bonus = a[1]; + } + else { + bonus = 1; + } + } + else { + success = 1; + bonus = 1; + } + if( con > 100 ){ + con = 100; + } + if( con < 0 ){ + con = 0; + } + if( pro > 100 ){ + pro = 100; + } + if( pro < 0 ){ + pro = 0; + } + val = (con - pro + (200*success) + 100)/8; + AddSkillPoints(skill, (bonus * val * level * level) + 1); +} + +/* ****************** abilities.c driver applies **************** */ +static void create(){ +} + diff --git a/lib/lib/lvs/level.c b/lib/lib/lvs/level.c new file mode 100644 index 0000000..0633107 --- /dev/null +++ b/lib/lib/lvs/level.c @@ -0,0 +1,68 @@ +#include <lib.h> +#include <daemons.h> + +int collect_moduli(int mod, int *range){ + int ret, neg, big, little, i; + ret = 0; + if(range[0] > range[1]){ + neg = 1; + big = range[0]; + little = range[1]; + } + else { + big = range[1]; + little = range[0]; + } + + for(i = big; i > little; i--){ + if(!(i % mod)) ret++; + } + + if(neg){ + ret = ret - (ret*2); + } + return ret; +} + + +varargs int ChangeLevel(int i){ + mapping skills, stats, moduli = ([]); + int current_level, desired_level; + object subject = this_object(); + + current_level = subject->GetLevel(); + + if(!i || i < 1) + desired_level = current_level + 1; + else desired_level = i; + + for(i = 1; i < 5; i++){ + moduli[i] = collect_moduli(i, ({ current_level, desired_level }) ); + } + + skills = subject->GetSkillsMap(); + stats = subject->GetStatsMap(); + + foreach(mixed key, mixed val in skills){ + if(skills[key]["class"] > 3) skills[key]["class"] = 4; + subject->SetSkill(key, + skills[key]["level"] + moduli[skills[key]["class"]], + skills[key]["class"]); + } + + foreach(mixed key, mixed val in stats){ + if(stats[key]["class"] > 3) stats[key]["class"] = 4; + subject->SetStat(key, + stats[key]["level"] + moduli[stats[key]["class"]], + stats[key]["class"]); + } + + subject->SetLevel(desired_level); + + if(interactive() && find_object(INSTANCES_D)){ + INSTANCES_D->SendWhoUpdate(this_object()->GetKeyName()); + } + + return 1; +} + diff --git a/lib/lib/lvs/position.c b/lib/lib/lvs/position.c new file mode 100644 index 0000000..ae300cf --- /dev/null +++ b/lib/lib/lvs/position.c @@ -0,0 +1,239 @@ +/* /lib/position.c + * From the Dead Souls Mud Library + * Handles the positioning of living things + * Created by Descartes of Borg 961221 + * Version: @(#) position.c 1.1@(#) + * Last modified: 96/12/21 + */ + +#include <position.h> +#include <medium.h> +#include <message_class.h> +#include <daemons.h> + +inherit LIB_FALL; +inherit LIB_SINK; + +private int Position = POSITION_STANDING; +private static object Chair = 0; + +// abstract methods +varargs mixed eventPrint(string str, mixed args...); +// end abstract methods + +int GetPosition(){ + return Position; +} + +int SetPosition(int x){ + Position = x; +} + +varargs mixed eventLay(object target){ + mixed tmp; + + if( Position != POSITION_STANDING && Position != POSITION_SITTING){ + eventPrint("You must be standing or sitting in order to lie."); + return 1; + } + if( !target ){ + send_messages("lie", "$agent_name $agent_verb down.", this_object(), + 0, environment()); + Position = POSITION_LYING; + return 1; + } + tmp = target->eventReceiveLay(this_object()); + if( tmp != 1 ){ + if( !tmp ){ + eventPrint("You cannot lie there!"); + } + else { + eventPrint(tmp); + } + return 1; + } + send_messages("lie", "$agent_name $agent_verb down on " + + target->GetShort() + ".", this_object(), 0, environment()); + Position = POSITION_LYING; + Chair = target; + return 1; + +} + +varargs mixed eventKneel(object target){ + mixed tmp; + + if( Position != POSITION_STANDING && Position != POSITION_SITTING){ + eventPrint("You must be standing or sitting in order to kneel."); + return 1; + } + if( !target ){ + send_messages("kneel", "$agent_name $agent_verb down.", this_object(), + 0, environment()); + Position = POSITION_KNEELING; + return 1; + } + return 1; +} + +varargs mixed eventSit(object target){ + mixed tmp; + + if( Position != POSITION_STANDING && Position != POSITION_LYING ){ + eventPrint("You can't sit from that position."); + return 1; + } + if( !target ){ + if( Position == POSITION_STANDING){ + send_messages("sit", "$agent_name $agent_verb down.", + this_object(),0, environment()); + } + else send_messages("sit", "$agent_name $agent_verb up.", + this_object(),0, environment()); + + Position = POSITION_SITTING; + return 1; + } + tmp = target->eventReceiveSit(this_object()); + if( tmp != 1 ){ + if( !tmp ){ + eventPrint("You cannot sit there!"); + } + else { + eventPrint(tmp); + } + return 1; + } + send_messages("sit", "$agent_name $agent_verb down on " + + target->GetShort() + ".", this_object(), 0, environment()); + Position = POSITION_SITTING; + Chair = target; + return 1; +} + +mixed eventFly(){ + if( Chair ){ + mixed tmp = Chair->eventReleaseStand(this_object()); + + if( tmp != 1 ){ + if( !tmp ){ + eventPrint("You cannot get up!"); + } + else { + eventPrint(tmp); + } + return 1; + } + Chair = 0; + } + if(this_object()->CanFly() && Position != POSITION_FLYING){ + tell_object(this_object(),"You begin flying."); + say(this_object()->GetName()+" begins flying and hovers in the air."); + Position = POSITION_FLYING; + } + return 1; +} + +mixed eventSwim(){ + if( Chair ){ + mixed tmp = Chair->eventReleaseStand(this_object()); + + if( tmp != 1 ){ + if( !tmp ){ + eventPrint("You cannot!"); + } + else { + eventPrint(tmp); + } + return 1; + } + Chair = 0; + } + if(this_object()->CanSwim() && Position != POSITION_SWIMMING){ + tell_object(this_object(),"You begin swimming."); + say(this_object()->GetName()+" begins swimming."); + Position = POSITION_SWIMMING; + } + return 1; +} + +mixed eventFloat(){ + if( Chair ){ + mixed tmp = Chair->eventReleaseStand(this_object()); + + if( tmp != 1 ){ + if( !tmp ){ + eventPrint("You can't!"); + } + else { + eventPrint(tmp); + } + return 1; + } + Chair = 0; + } + if(this_object()->CanFloat() && Position != POSITION_FLOATING){ + tell_object(this_object(),"You begin floating."); + say(this_object()->GetName()+" begins floating."); + Position = POSITION_FLOATING; + } + return 1; +} + +mixed eventLand(){ + object env = environment(); + if(!env) return 0; + if(! Position == POSITION_FLYING ) return 0; + if( env->GetMedium() == MEDIUM_AIR || env->GetMedium() == MEDIUM_WATER || + env->GetMedium() == MEDIUM_SPACE ) return 0; + write("You stop flying."); + say(this_object()->GetName()+" stops flying."); + if(stringp(hobbled(this_object()))) Position = POSITION_STANDING; + else Position = POSITION_LYING; + return 1; +} + +mixed eventStand(){ + if(!stringp(hobbled(this_object()))){ + eventPrint("Your injuries prevent you from standing."); + return 1; + } + if(RACES_D->GetLimblessRace(this_object()->GetRace()) ){ + eventPrint("You aren't endowed with limbs with which to stand."); + return 1; + } + if( Position == POSITION_STANDING ){ + eventPrint("You are already standing!"); + return 1; + } + if( Position == POSITION_FLYING){ + return eventLand(); + } + + if( Chair ){ + mixed tmp = Chair->eventReleaseStand(this_object()); + + if( tmp != 1 ){ + if( !tmp ){ + eventPrint("You cannot get up!"); + } + else { + eventPrint(tmp); + } + return 1; + } + Chair = 0; + } + Position = POSITION_STANDING; + send_messages("stand", "$agent_name $agent_verb up.", this_object(), 0, + environment()); + return 1; +} + +object GetFurniture(){ + if(Chair) return Chair; +} +string GetFurnitureName(){ + if(Chair) return Chair->GetShort(); + else return "none"; +} diff --git a/lib/lib/magic.c b/lib/lib/magic.c new file mode 100644 index 0000000..e06a619 --- /dev/null +++ b/lib/lib/magic.c @@ -0,0 +1,194 @@ +/* /lib/magic.c + * From Dead Souls LPMud + * A module for allowing living beings to cast magic spells. + * Created by Descartes of Borg 961027 + * Version: @(#) magic.c 1.13@(#) + * Last modified: 96/11/03 + */ + +#include <daemons.h> +#include <rounds.h> +#include <magic.h> + +private mapping SpellBook = ([]); + +// abstract methods +int GetInCombat(); +int GetMagicPoints(); +string GetName(); +int GetParalyzed(); +varargs mixed eventPrint(string msg, mixed args...); +int GetSkillLevel(string skill); +int GetStaminaPoints(); +void SetAttack(object array e, function f, int type); +// end abstract methods + +static varargs void eventCast(object spell, string limb, object array targs); +static void eventTrainSpell(object spell); + +mapping GetSpellBook(){ + return copy(SpellBook); +} + +void SetSpellBook(mapping book){ + SpellBook = book; +} + +int GetSpellLevel(string spell){ + return SpellBook[spell]; +} + +varargs mixed CanCast(object spell){ + string tmp; + if( GetParalyzed() ){ + return "You cannot do anything."; + } + if( environment()->GetProperty("no magic") ){ + return "Supernatural forces prevent your magic."; + } + if( !spell ){ + return "No such spell exists in this reality."; + } + if( spell->GetVerb() == "pray" ){ + tmp = "prayer"; + } + else if( spell->GetVerb() == "perform" ){ + tmp = "feat"; + } + else { + tmp = "spell"; + } + if( !this_object()->GetSpellBook()[spell->GetSpell()] ){ + return "You have never heard of that " + tmp + " before."; + } + if( GetMagicPoints() < spell->GetRequiredMagic() ){ + return "You do not have the power required."; + } + if( GetStaminaPoints() < spell->GetRequiredStamina() ){ + return "You are too tired."; + } + foreach(string skill in spell->GetSkills()){ + if( GetSkillLevel(skill) < spell->GetSkillRequired(skill) ){ + return "That " + tmp + " is beyond your comprehension."; + } + } + return 1; +} + +varargs mixed eventPrepareCast(string verb, mixed array args...){ + object spell = SPELLS_D->GetSpell(verb = lower_case(verb)); + object array targets, send_to; + string special, arg; + mixed tmp; + int type; + if(!spell) spell = SPELLS_D->GetPrayer(verb = lower_case(verb)); + if(spell) tmp = spell->eventParse(this_object(), args...); + if( !arrayp(tmp) ){ + if( stringp(tmp) ){ + eventPrint(tmp); + } + else { + eventPrint("You are confused."); + } + return 1; + } + args = tmp; + targets = spell->GetTargets(this_object(), args...); + args = filter(args, (: stringp :)); + if( spell->GetAutoHeal() == 0 ){ + if( !sizeof(args) ){ + object array existing = filter(targets, (: $1 :)); + + if( sizeof(existing) != 1 ){ + error("This spell was poorly constructed."); + } + arg = existing[0]->GetRandomLimb("torso"); + } + else { + arg = args[0]; + } + } + else { + if( !sizeof(args) ){ + arg = 0; + } + else { + arg = args[0]; + } + } + if( spell->GetVerb() == "pray" ){ + special = "a prayer"; + } + else if( spell->GetVerb() == "perform" ){ + special = "a mantra"; + } + else { + special = "an incantation"; + } + if( targets ){ + send_to = filter(targets, (: environment($1) == environment() :)); + } + else { + send_to = 0; + } + send_messages(({ "close", "begin" }), + "$agent_name $agent_verb $agent_possessive eyes and " + "$agent_verb uttering " + special + ".", this_object(), + send_to, environment()); + type = spell->GetSpellType(); + if( GetInCombat() || (type == SPELL_COMBAT) ){ + if( type == SPELL_COMBAT ){ + SetAttack(targets, (: eventCast($(spell), $(arg), $(targets)) :), + ROUND_MAGIC); + } + else { + SetAttack(0, (: eventCast($(spell), $(arg), $(targets)) :), + ROUND_MAGIC); + } + } + else { + eventCast(spell, arg, targets); + } + return 1; +} + +static varargs void eventCast(object spell, string limb, object array targs){ + string name = spell->GetSpell(); + + if( this_object()->GetSpellBook()[name] < 100 ){ + eventTrainSpell(spell); + } + if( spell->CanCast(this_object(), this_object()->GetSpellBook()[name], limb, targs) ){ + spell->eventCast(this_object(), this_object()->GetSpellBook()[name], limb, targs); + } +} + +mixed eventLearnSpell(string spell){ + object magic = SPELLS_D->GetSpell(spell = lower_case(spell)); + if(!magic){ + write("That's not a spell being offered to you for learning."); + return 0; + } + + foreach(string skill in magic->GetSkills()){ + if( magic->GetRequiredSkill(skill) > GetSkillLevel(skill) ){ + return 0; + } + } + if( !this_object()->GetSpellBook()[spell] ){ + SpellBook[spell] = 1; + } + return 1; +} + +static void eventTrainSpell(object spell){ + string name = spell->GetSpell(); + int x = SpellBook[name] + 1; + + foreach(string skill in spell->GetSkills() ){ + if( (5 * GetSkillLevel(skill)) < x ){ + return; + } + } + SpellBook[name] = x; +} diff --git a/lib/lib/manycoins.c b/lib/lib/manycoins.c new file mode 100644 index 0000000..f541048 --- /dev/null +++ b/lib/lib/manycoins.c @@ -0,0 +1,15 @@ +#include <lib.h> +#include <daemons.h> + +int x; +int y; +int copper,cents,silver,electrum,gold,dollars,platinum; +int PutCoins(object who); + +int Payment(object who, int value){ + return 1; +} + +int PutCoins(object who){ + return 1; +} diff --git a/lib/lib/match.c b/lib/lib/match.c new file mode 100644 index 0000000..589c8d6 --- /dev/null +++ b/lib/lib/match.c @@ -0,0 +1,40 @@ +/* /lib/match.c + * from the Dead Souls Object Library + * an object which can be self-induced to burn + * created by Descartes of Borg 960512 + */ + +#include <lib.h> +#include "include/match.h" + +inherit LIB_TORCH; + +private int StrikeChance = 50; + +mixed direct_strike_obj(){ + if( environment() != this_player() ) return "#You don't have that!"; + if( GetBurning() ) return "It is already lit!"; + return 1; +} + +mixed eventStrike(object who){ + if( !GetFuelAmount() || StrikeChance < random(100) || !eventBurn(who) ){ + who->eventPrint("You strike " + GetShort() + ", but nothing happens."); + environment(who)->eventPrint(who->GetName() + " strikes " + + GetShort() + ", but nothing happens.", + who); + return 1; + } + who->eventPrint("You strike " + GetShort() + " and it ignites!"); + environment(who)->eventPrint(who->GetName() + " strikes " + + GetShort() + " and it ignites!", who); + return 1; +} + +int GetStrikeChance(){ + return StrikeChance; +} + +static int SetStrikeChance(int x){ + return (StrikeChance = x); +} diff --git a/lib/lib/mayor.c b/lib/lib/mayor.c new file mode 100644 index 0000000..cc886e0 --- /dev/null +++ b/lib/lib/mayor.c @@ -0,0 +1,87 @@ +/* /lib/mayor.c + * From the Dead Souls Object Library + * Allows players to change their residence on the mud + * Created by Descartes of Borg 961019 + * Version: @(#) mayor.c 1.3@(#) + * Last modified: 96/10/20 + */ + +#include <lib.h> + +inherit LIB_SENTIENT; + +static void EvaluateCitizenshipRequest(); + +int Tax = 0; +string LocalCurrency = "gold"; + +static void create(){ + sentient::create(); + SetRequestResponses(([ "citizenship" : (: EvaluateCitizenshipRequest :), + "help" : (: this_object()->eventForce("say You can request " + "citizenship from me.") :) ])); +} + +mixed CanRequestCitizenship(object who){ + if( Tax > 0 ){ + int cost = (Tax); + + if( who->GetCurrency(LocalCurrency) < cost ){ + this_object()->eventForce("say I'm sorry, but we have a new citizen tax of " + Tax + " " + + LocalCurrency + "."); + return 0; + } + } + if( who->GetTown() == GetTown() ){ + return "You are already a citizen of " + GetTown() + "."; + } + return 1; +} + +mixed eventRequestCitizenship(object who){ + object array homies = filter(users(), (: $1->GetTown() == GetTown() :)); + + homies->eventPrint(who->GetName() + " is now a citizen of " + GetTown() + + "."); + who->SetTown(GetTown()); + who->eventPrint("You are now a citizen of " + GetTown() + "."); + if( Tax > 0 ){ + int cost = Tax; + + who->AddCurrency(LocalCurrency, -cost); + this_object()->AddCurrency(LocalCurrency, cost); + this_object()->eventForce("say Congratulations, citizen!"); + } + return 1; +} + +static void EvaluateCitizenshipRequest(){ + mixed tmp = CanRequestCitizenship(this_player()); + + if( tmp != 1 ){ + if( !tmp || tmp == 0 ){ + this_object()->eventForce("say Your request is denied."); + } + else { + this_player()->eventPrint(tmp); + } + return; + } + eventRequestCitizenship(this_player()); +} + +string GetLocalCurrency(){ + return LocalCurrency; +} + +static string SetLocalCurrency(string str){ + return (LocalCurrency = str); +} + +int GetTax(){ + return Tax; +} + +static int SetTax(int x){ + return (Tax = x); +} diff --git a/lib/lib/meal.c b/lib/lib/meal.c new file mode 100644 index 0000000..a928be1 --- /dev/null +++ b/lib/lib/meal.c @@ -0,0 +1,212 @@ +/* /lib/meal.c + * from the Dead Souls LPC Library + * standard food and drink code + * created by descartes of Borg 950603 + * Version: @(#) meal.c 1.3@(#) + * Last modified: 97/01/03 + */ + +#include <lib.h> +#include <function.h> +#include <meal_types.h> +#include <rounds.h> +#include <vendor_types.h> +#include "include/meal.h" + +inherit LIB_BAIT_WITH; +inherit LIB_ITEM; + +private int MealStrength, MealType; +private string EmptyItem, EmptyName, OtherMessage; +private mixed EmptyShort, EmptyLong, MyMessage; +function MealAction; + +static void create(){ + item::create(); + MealType = MEAL_ALCOHOL; + EmptyItem = 0; + EmptyName = "bottle"; + EmptyShort = "an empty bottle"; + EmptyLong = "This empty bottle once contained some liquid."; + MyMessage = "You drink your drink."; + OtherMessage = "$N drinks $P drink."; + SetVendorType(VT_DRINK); + SetNoCondition(1); + AddSave( ({ "MealStrength", "MealType", "BaitStrength" }) ); +} + +int SetMealAction(function f){ + MealAction = f; +} + +mixed direct_drink_obj(){ + if( environment() != this_player() ) return "#You don't have that!"; + if( MealType & MEAL_FOOD ) return "Wouldn't you rather eat it?"; + return this_player()->CanDrink(this_object()); +} + +mixed direct_drink_from_obj(){ + if( MealType & MEAL_FOOD ) return 0; + if( environment() != this_player() ) return "#You don't have that!"; + return this_player()->CanDrink(this_object()); +} + +mixed direct_eat_obj(){ + if( environment() != this_player() ) return "#You don't have that!"; + if( !(MealType & MEAL_FOOD) ) return "Wouldn't you rather drink it?"; + return this_player()->CanEat(this_object()); +} + +static mixed AddSave(mixed *vars){ return item::AddSave(vars); } + +string GetShort(){ return item::GetShort(); } + +int eventDestruct(){ return item::eventDestruct(); } + +mixed eventDrink(object who){ + mixed tmp; + int x; + object ob; + + if( (tmp = who->eventDrink(this_object())) != 1 ) return tmp; + if( (x = functionp(MyMessage)) && !(x & FP_OWNER_DESTED) ){ + evaluate(MyMessage, who); + } + else { + string mymsg, othermsg; + + mymsg = replace_string(MyMessage, "$P", "your"); + othermsg = replace_string(OtherMessage, "$P", possessive(who)); + mymsg = replace_string(mymsg, "$N", "you"); + othermsg = replace_string(othermsg, "$N", who->GetName()); + who->eventPrint( capitalize(mymsg) ); + environment(who)->eventPrint( capitalize(othermsg), who ); + } + + ob = new(GetEmptyItem() || LIB_USED_MEAL); + if( base_name(ob) == LIB_USED_MEAL ){ + ob->SetKeyName(GetEmptyName()); + ob->SetId( ({ GetEmptyName(), "container", "empty container" }) ); + ob->SetShort(GetEmptyShort()); + ob->SetAdjectives( ({ "empty", "drained" }) ); + ob->SetLong(GetEmptyLong()); + ob->SetBaseCost(1); + ob->SetMass(10); + ob->SetDestroyOnSell(); + } + if( !(ob->eventMove(who)) ){ + who->eventPrint("You drop " + ob->GetShort() + "."); + environment(who)->eventPrint(who->GetName() + + " drops " + ob->GetShort() + ".", who); + ob->eventMove(environment(who)); + } + + if( x = GetPoison() ){ + if( random(who->GetStatLevel("luck")) > 35 ) + who->eventPrint("That didn't seem to taste quite right."); + who->AddPoison(x); + } + Destruct(); + return 1; +} + +mixed eventEat(object who){ + mixed tmp; + int x; + if( (tmp = who->eventEat(this_object())) != 1 ) return tmp; + if( (x = functionp(MyMessage)) && !(x & FP_OWNER_DESTED) ){ + evaluate(MyMessage, who); + } + else { + string mymsg, othermsg; + mymsg = replace_string(MyMessage, "$P", "your"); + othermsg = replace_string(OtherMessage, "$P", + possessive(who)); + mymsg = replace_string(mymsg, "$N", "you"); + othermsg = replace_string(othermsg, "$N", who->GetName()); + who->eventPrint( capitalize(mymsg) ); + environment(who)->eventPrint( capitalize(othermsg), who ); + } + if( x = GetPoison() ){ + if( random(who->GetStatLevel("luck")) > 35 ) + who->eventPrint("You notice a strange aftertaste."); + who->AddPoison(x); + } + if( (x = functionp(MealAction)) && !(x & FP_OWNER_DESTED) ){ + evaluate(MealAction, who); + } + Destruct(); + return 1; +} + +int eventPoison(object who, object agent, int x){ + who->eventPrint("You put some poison " + "in " + add_article(GetShort()) + "."); + environment(who)->eventPrint( who->GetName()+" puts something " + "in " + add_article(GetShort()) + ".", who); + AddPoison(x); + return 1; +} + +string SetEmptyItem(string file){ return (EmptyItem = file); } + +string GetEmptyItem(){ return EmptyItem; } + +string SetEmptyName(string str){ return (EmptyName = str); } + +string GetEmptyName(){ return EmptyName; } + +mixed SetEmptyShort(mixed val){ return (EmptyShort = val); } + +mixed GetEmptyShort(){ return EmptyShort; } + +mixed SetEmptyLong(mixed val){ return (EmptyLong = val); } + +mixed GetEmptyLong(){ return EmptyLong; } + +int SetMealType(int x){ + int vt = 0; + + if( x & MEAL_FOOD ){ + vt |= VT_FOOD; + MyMessage = "You eat your food."; + OtherMessage = "$N eats $P food."; + } + if( x & MEAL_DRINK ) vt |= VT_DRINK; + SetVendorType(vt); + return (MealType = x); +} + +int GetMealType(){ return MealType; } + +int SetStrength(int x){ return (MealStrength = x); } + +int GetStrength(){ return MealStrength; } + +varargs void SetMealMessages(mixed array val...){ + if( !arrayp(val) ){ + error(sprintf("Bad argument 1 to SetMealMessages(): %O\n", val)); + } + if( sizeof(val) == 1 ){ + if( arrayp(val[0]) ) SetMealMessages(val[0]...); + else if( stringp(val[0]) || functionp(val[0]) ) MyMessage = val[0]; + else error(sprintf("Bad argument 1 to SetMealMessages(): %O\n", + val[0])); + return; + } + if( !stringp(val[0]) ) + error(sprintf("Bad argument 1 to SetMealMessages(): %O\n", val[0])); + else if( !stringp(val[1]) ) + error(sprintf("Bad argument 2 to SetMealMessages(): %O\n", val[1])); + MyMessage = val[0]; + OtherMessage = val[1]; +} + +mixed *GetMealMessages(){ return ({ MyMessage, OtherMessage }); } + +int GetValue(){ + int x; + if(x = this_object()->GetBaseCost("silver")) return x; + x = GetStrength(); + return (x * (6 + x)) / 10 + 10; +} diff --git a/lib/lib/messages.c b/lib/lib/messages.c new file mode 100644 index 0000000..746141b --- /dev/null +++ b/lib/lib/messages.c @@ -0,0 +1,61 @@ +/* /lib/messages.c + * from the Dead Souls Object Library + * handles special messages such as leaving, coming, saying, etc. + * created by Descartes of Borg 950428 + */ + + +#include "include/messages.h" + +private mapping Messages; + +static void create(){ + Messages = ([ "come" : "$N enters.", "leave" : "$N leaves $D.", + "telin" : "$N teleports in.", "telout" : "$N teleports away.", + "home" : "$N goes home.", "vis" : "$N appears.", + "invis": "$N disappears.", "clone" : "$N clones $O.", + "dest" : "$N dests $O." ]); +} + +string SetMessage(string msg, string str){ + if(!stringp(msg) || !stringp(str)) error("Bad argument to SetMessage()."); + switch(msg){ + case "come": case "leave": case "telin": case "telout": case "home": + case "say": case "ask": case "exclaim": case "login": case "logout": + case "dest": case "clone": case "vis" : case "invis" : + return (Messages[msg] = str); + default: return 0; + } +} + +varargs string GetMessage(string msg, mixed arg){ + string tmp, tmp2; + + if( !stringp(msg) ) return 0; + if( !(tmp = Messages[msg]) ) return 0; + if(!stringp(tmp) || !sizeof(tmp)) return 0; + switch(msg){ + case "dest": case "clone": + if(stringp(tmp2 = arg->GetShort())) + tmp = replace_string(tmp, "$O", tmp2); + break; + case "leave": + if(stringp(arg) && strsrch(arg, "$N") == -1) + tmp = replace_string(tmp, "$D", arg); + break; + //The following case is a bugfix courtesy of Memrosh @ Ascension + case "come": + if(stringp(arg)){ tmp = arg;} + break; + case "say": case "ask": case "exclaim": return tmp; + case "login": case "logout": + tmp = replace_string(tmp, "$M", mud_name()); + break; + } + if(strsrch(tmp, "$N") == -1) tmp = "$N "+tmp; + return capitalize(replace_string(tmp, "$N", this_object()->GetName())); +} + +string GetName(){ return 0; } + +mapping GetMessages(){ return copy(Messages); } diff --git a/lib/lib/missile.c b/lib/lib/missile.c new file mode 100644 index 0000000..d7e1b67 --- /dev/null +++ b/lib/lib/missile.c @@ -0,0 +1,193 @@ +#include <lib.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +int range = 10; +int speed = 2; +int damage = 200; +int debugging = 0; +int deployed; +string omsg = "A missile flies $D."; +string imsg = "A missile flies in."; +object owner, ownerob; + +void create(){ + ::create(); + SetKeyName("generic missile"); + SetId( ({"missile"}) ); + SetAdjectives( ({"generic","sample","template"}) ); + SetShort("a generic missile"); + SetLong("This is an object that is launched."); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); +} + +void init(){ + ::init(); + add_action("launch","launch"); +} + +string GetName(){ + return GetKeyName(); +} + +int SetDebugging(int x){ + debugging = x; + return debugging; +} + +int GetDebugging(){ + return debugging; +} + +int GetRange(){ + return range; +} + +int SetRange(int x){ + if(x > 1) range = x; + else range = 0; + return range; +} + +int GetDamage(){ + return damage; +} + +int SetDamage(int x){ + if(x > 1) damage = x; + else damage = 0; + return damage; +} + +int GetSpeed(){ + return speed; +} + +int SetSpeed(int x){ + if(x > 1) speed = x; + else speed = 0; + return speed; +} + +mixed eventNegotiateObstacles(){ + return 1; +} + +mixed eventRunOut(){ + return 1; +} + +int SetArmed(int x){ + return 1; +} + +mixed eventEncounterBlock(){ + if(debugging && owner) tell_player(owner, "poop"); + range = 0; + return 1; +} + +string SetCruiseInMessage(string str){ + if(str){ + imsg = str; + } + return imsg; +} + +string SetCruiseOutMessage(string str){ + if(str){ + omsg = str; + } + return omsg; +} + +mixed eventCruiseMessages(object this_room, object next_room, string dir){ + string tmp = replace_string(omsg,"$D",dir); + string tmp2 = replace_string(imsg,"$D",opposite_dir(dir, 1)); + if(this_room) this_room->eventPrint(tmp); + if(next_room) next_room->eventPrint(tmp2); + return 1; +} + +int eventCruise(string str){ + object this_room, next_room; + string exit; + int err, success; + this_room = room_environment(this_object()); + exit = this_room->GetExit(str); + if(exit) err = catch(next_room = load_object(exit)); + if(!err && next_room){ + success = this_object()->eventMove(next_room); + } + if(success && environment() == next_room){ + eventCruiseMessages(this_room, next_room, str); + success = eventNegotiateObstacles(); + } + else { + eventEncounterBlock(); + } + return success; +} + +void eventDeploy(string str){ + int i, ret; + if(!owner) owner = find_player("cratylus"); + if(undefinedp(deployed)) deployed = time(); + for(i=speed;i > 0; i--){ + if(range){ + range--; + ret = eventCruise(str); + if(!ret) break; + } + } + if(time() - deployed > 30){ + range = 0; + } + if(time() - deployed > 60){ + this_object()->eventDestruct(); + } + if(range){ + call_out("eventDeploy", 1, str); + if(debugging && owner) tell_player(owner, "%^GREEN%^I am "+identify(this_object())+ + ", range level: " + range + ", " + " cruising in " + + identify(room_environment(this_object()))); + } + else { + if(debugging && owner) tell_player(owner, "%^CYAN%^I am "+identify(this_object())+ + " and I ran out of range at "+ + identify(room_environment(this_object()))); + eventRunOut(); + } +} + +int launch(string str){ + object room = room_environment(this_object()); + string exit; + if(!this_player() || !creatorp(this_player())) return 0; + owner = this_player(); + if(room) exit = room->GetExit(str); + if(exit) eventDeploy(str); + SetArmed(1); + return 1; +} + +varargs object SetOwner(object who){ + owner = who; + return owner; +} + +varargs object SetOwnerOb(object ob){ + ownerob = ob; + return ownerob; +} + +object GetOwner(){ + return owner; +} + +object GetOwnerOb(){ + return ownerob; +} diff --git a/lib/lib/money.c b/lib/lib/money.c new file mode 100644 index 0000000..89528ff --- /dev/null +++ b/lib/lib/money.c @@ -0,0 +1,27 @@ +#include <lib.h> +mapping Money = ([]); + +int AddMoney(string type, int amount){ + object pile; + pile = new(LIB_BLANK_PILE); + pile->SetPile(type,amount); + pile->eventMove(this_object()); + Money[type] = amount; + return 1; +} + +varargs void SetMoney(mixed val, int amount){ + if( stringp(val) ) AddMoney(val, amount); + else if( mapp(val) ){ + string *currs; + int i; + i = sizeof(currs = keys(val)); + while(i--){ + AddMoney(currs[i], val[currs[i]]); + Money[currs[i]] = val[currs[i]]; + } + } + else error("Bad argument 1 to SetMoney()."); +} + +mapping GetMoneyMap(){ return copy(Money); } diff --git a/lib/lib/mount.c b/lib/lib/mount.c new file mode 100644 index 0000000..56d68b2 --- /dev/null +++ b/lib/lib/mount.c @@ -0,0 +1,162 @@ +#include <lib.h> +#include <medium.h> +#include <daemons.h> +#include <position.h> +#include <armor_types.h> +#include <message_class.h> +#include <vision.h> +#include "include/npc.h" + +private int Mount; + +object *Riders = ({}); + +mixed direct_ride_str(){ + return this_object()->GetMount(); +} + +mixed direct_ride_word_str(){ + return this_object()->GetMount(); +} + +mixed direct_mount_liv(){ + return this_object()->GetMount(); +} + +mixed direct_dismount_liv(){ + return this_object()->GetMount(); +} + +mixed direct_dismount_from_liv(){ + return this_object()->GetMount(); +} + +int eventRide(string direction){ + string travel_cmd, s1, s2; + object *guys = get_livings(this_object()); + if(interactive(this_object())) return 0; + if(sscanf(direction,"%s %s",s1,s2) == 2){ + if(s1 == "enter" || s1 == "into") travel_cmd = "enter"; + } + + if(!s1 || s1 == "") switch(this_object()->GetPosition()){ + case POSITION_STANDING : travel_cmd = "go";break; + case POSITION_SITTING : travel_cmd = "crawl";break; + case POSITION_LYING : travel_cmd = "crawl";break; + case POSITION_FLYING : travel_cmd = "fly";break; + default : travel_cmd = "go"; + } + else direction = s2; + this_object()->eventForce(travel_cmd+" "+direction); + return 1; +} + +object *AddRider(object ob){ + Riders += ({ ob }); +} + +object *RemoveRider(object ob){ + Riders -= ({ ob }); +} + +object *GetRiders(){ + object *ret = ({}); + if(Riders && sizeof(Riders)){ + foreach(mixed rider in Riders){ + if(!rider) RemoveRider(rider); + else if(environment(rider) == this_object()) ret += ({ rider }); + else RemoveRider(rider); + } + } + return ret; +} + +int SetMount(int x){ + Mount = x; + if(Mount) this_object()->SetNoClean(1); + return Mount; +} +int GetMount(){ return Mount; } + +varargs mixed eventMount(object who, int quiet, int forced){ + int rider_weight; + string weight = "weight"; + if(!who){ + return 0; + } + if(environment() && environment()->GetMedium() == MEDIUM_SPACE){ + weight = "mass"; + } + rider_weight = who->GetMass(); + if(!environment(this_object())){ + return 0; + } + if(environment(who) && environment(who) == this_object()){ + if(!forced && !quiet){ + return who->eventPrint("You are already mounted.", MSG_ERROR); + } + } + if((rider_weight + this_object()->GetCarriedMass()) > + this_object()->GetMaxCarry()){ + if(!forced && !quiet){ + return write(this_object()->GetShort()+ + " cannot handle that much "+weight+"."); + } + } + if(this_object()->GetMountOwner() != who){ + if(!forced && !quiet){ + write(this_object()->GetName()+" doesn't know you well " + "enough to let you ride "+objective(this_object())+"."); + return 0; + } + } + this_object()->SetNoClean(1); + if(!quiet){ + write("You mount "+this_object()->GetShort()+"."); + say(who->GetName()+" mounts "+this_object()->GetShort()+"."); + } + who->SetProperty("mount", this_object()); + if(who->eventMove(this_object())) return AddRider(who); + if(forced) return AddRider(who); + else return 0; +} + +varargs mixed eventDismount(object who, int quiet, int forced){ + int rider_weight; + rider_weight = who->GetMass(); + if(!environment(this_object())) return 0; + if(environment(who) && environment(who) != this_object()){ + if(!forced || !quiet){ + return who->eventPrint("You are already dismounted.", MSG_ERROR); + } + } + else { + if(!quiet){ + write("You dismount from "+this_object()->GetPlainShort()+"."); + tell_room(environment(this_object()),who->GetName()+" dismounts from " +this_object()->GetPlainShort()+".", ({ this_object(), who })); + } + who->RemoveProperty("mount"); + if(who->eventMove(environment(this_object()))) return RemoveRider(who); + else return 0; + } +} + +mixed eventBuck(object who){ + int rider_weight; + rider_weight = (who->GetCarriedMass()) + (who->GetMass() || 2000); + if(!environment(this_object())) return 0; + if(environment(who) && environment(who) != this_object()){ + return 0; + } + else { + tell_player(who,"You are thrown from "+ + (this_object()->GetPlainShort() || this_object()->GetShort())+"!"); + tell_room(environment(this_object()),who->GetName()+ + " is thrown from "+(this_object()->GetPlainShort() || + this_object()->GetShort())+"!", ({ this_object(), who })); + who->RemoveProperty("mount"); + who->SetPosition(POSITION_LYING); + if(who->eventMove(environment(this_object()))) return RemoveRider(who); + else return 0; + } +} diff --git a/lib/lib/nmsh.c b/lib/lib/nmsh.c new file mode 100644 index 0000000..05388d4 --- /dev/null +++ b/lib/lib/nmsh.c @@ -0,0 +1,1030 @@ +/* /lib/user/nmsh.c + * from Dead Souls + * the new Dead Souls shell + * created by Descartes of Borg 940216 + * Version: @(#) nmsh.c 1.3@(#) + * Last Modified: 96/10/15 + */ + +#include <daemons.h> +#include <lib.h> +#include "include/nmsh.h" + +inherit LIB_HISTORY; + +#define DIRECTORY_STACK_SIZE 5 +#define MAX_CMD_ALIASES 192 +#define FAIL 0 +#define CMD_EDITING 1 +#define CHAR_LIMIT 1024 + +private mapping Nicknames, Aliases, Xverbs, Directories; +private static int CWDCount, CWDBottom, CWDTop, CmdNumber; +private string Prompt; +private static string *Stack; +static int histmatch = 0; +static string recalled_command = ""; +static string recalled_command_sub = ""; +static int recalled_command_num = 0; +private static int noecho = 1; +private static mapping Termstuff; + +static int *GetScreen(){ return ({ 79, 24 }); } + +static void create(){ + Nicknames = ([]); + Termstuff = ([]); + Directories = ([ "current" : "/", "previous" : "/", "home" : 0 ]); + recalled_command_num = sizeof(this_object()->GetCommandHist()) - 1; + if(recalled_command_num > -1){ + recalled_command=this_object()->GetCommandHist()[recalled_command_num]; + } + Aliases = ([ "l" : "look $*", "bio" : "biography", "i" : "inventory", + "n" : "go north", "s" : "go south", "e" : "go east", "w" : "go west", + "ne" : "go northeast", "nw" : "go northwest", "se" : "go southeast", + "sw" : "go southwest", "d" : "go down", "u" : "go up", "out": "go out", + "exa" : "look at $*", "p" : "people", "sc" : "status", "inf" : "score", + "eq" : "equipment", "prac" : "skills", + "sco" : "score", "practice" : "skills", "trophy" : "kills", + "northwest" : "go northwest", "northeast" : "go northeast", + "southwest" : "go southwest", "southeast" : "go southeast", + "north" : "go north", "south": "go south", "east" : "go east", + "west" : "go west", "up" : "go up", "down": "go down", + "ig" : "intergossip $*", "c" : "cre $*", "lp" : "lpuni $*", + "inv" : "inventory", "x" : "look at $*", "examine" : "look at $*", + "ic" : "intercre $*", "loot" : "get all from $*", "chat" : "newbie $*", + "dc" : "dchat $*", "exit" : "go out", "t" : "tell $*", "k" : "kill $*", + "alist" : "ls /domains", "zlist" : "domains", "mwhere" : "findobj $*", + "owhere" : "findobj $*", "peace" : "quell", "vnum" : "help find", + ]); + Xverbs = (["]":"] $*", "'":"say $*",":":"emote $*","\"":"say $*",]); + if(this_object()->GetKeyName() == "cratylus"){ + Aliases["crat"] = "source /secure/scripts/crat.src"; + } +} + +int Setup(){ + if(this_player() != this_object()) return 0; + reset_prompt(); + if(!Nicknames) Nicknames = ([]); + if(!Aliases) Aliases = ([]); + if(!Xverbs) Xverbs = ([]); + add_action("cmd_alias", "alias",1); + add_action("cmd_unalias", "unalias",1); + add_action("cmd_nickname", "nickname",1); +#if FAIL + add_action("fail","fail"); +#endif + if(creatorp(this_object())){ + Stack = allocate(DIRECTORY_STACK_SIZE); + CWDBottom = CWDTop = CWDCount = 0; + add_action("cmd_cd", "cd"); + add_action("cmd_nmsh", "nmsh"); + add_action("cmd_pushd", "pushd"); + add_action("cmd_popd", "popd"); + add_action("cmd_pwd", "cwd"); + add_action("cmd_pwd", "pwd"); + add_action("cmd_work", "work"); + } + return 1; +} + +nomask static int cmd_alias(string str){ + string *a, *b; + string key, thing; + int i; + + if(this_player() != this_object()) return 0; + if(!str){ + i = sizeof(a = keys(Aliases)); + while(i--) + a[i] = sprintf("%s%s", arrange_string(a[i],15),Aliases[a[i]]); + i = sizeof(b = keys(Xverbs)); + while(i--) + b[i] = sprintf("$%s%s", arrange_string(b[i],14), Xverbs[b[i]]); + this_player()->eventPage(a+b); + return 1; + } + if(sscanf(str, "%s %s", key, thing) != 2){ + if(str[0] == '$'){ + str = str[1..strlen(str)-1]; + if(Xverbs[str]){ + write(str+": "+Xverbs[str]); + return 1; + } + else message("system", sprintf("No such alias $%s.", str), this_player()); + return 1; + } + if(Aliases[str]){ + write(str+": "+Aliases[str]); + return 1; + } + else message("system", sprintf("No such alias %s.", str), this_player()); + return 1; + } + if(sizeof(Xverbs) + sizeof(Aliases) >= MAX_CMD_ALIASES){ + message("system", "You must remove an alias before adding another.", + this_player()); + return 1; + } + if(key == "alias") return notify_fail("That would be a bad idea.\n"); + if(key[0] == '$'){ + key = key[1..strlen(key)]; + if(Xverbs[key]) + message("system", sprintf("Alias for $%s altered to (%s).", + key, thing), this_player()); + else message("system", sprintf("Alias $%s (%s) added.", key, thing), + this_player()); + Xverbs[key] = thing; + } + else { + if(Aliases[key]) + message("system", sprintf("Alias for %s altered to (%s).", key, thing), + this_player()); + else message("system", sprintf("Alias %s (%s) added.", key, thing),this_player()); + Aliases[key] = thing; + } + return 1; +} + +nomask static int cmd_unalias(string str){ + if(this_player() != this_object()) return 0; + if(!str){ + write("Unalias what?"); + return 1; + } + if(str[0] == '$'){ + str = str[1..strlen(str)-1]; + if(Xverbs[str]){ + map_delete(Xverbs, str); + message("system", sprintf("Alias $%s removed.", str), this_player()); + return 1; + } + else message("system", sprintf("No such alias $%s.", str), this_player()); + return 1; + } + if(Aliases[str]){ + map_delete(Aliases, str); + message("system", sprintf("Alias %s removed.", str), this_player()); + return 1; + } + else message("system", sprintf("No such alias %s.", str), this_player()); + return 1; +} + +nomask static int cmd_cd(string str){ + if(this_player() != this_object()) return 0; + set_cwd(str); + return 1; +} + +nomask static int cmd_nickname(string str){ + string *cles; + string key, thing; + int i; + + if(this_player() != this_object()) return 0; + if(!str){ + i = sizeof(cles = keys(Nicknames)); + while(i--){ + cles[i] = sprintf("%s%s", arrange_string(cles[i], 15), + Nicknames[cles[i]]); + } + this_player()->eventPage( cles + ({}) ); + return 1; + } + if(sscanf(str, "%s %s", key, thing) != 2){ + if(Nicknames[str]){ + message("system", sprintf("Nickname %s removed.", str), + this_player()); + map_delete(Nicknames, str); + } + else message("system", sprintf("No such nickname %s.", str), + this_player()); + } + else { + if(Nicknames[key]) + message("system", sprintf("Nickname %s altered to (%s).", key, thing), + this_player()); + else message("system", sprintf("Nickname %s (%s) added.", key, thing), + this_player()); + Nicknames[key] = thing; + } + return 1; +} + +nomask static int cmd_nmsh(string str){ + string *lines; + string tmp; + int i, maxi; + + if(!str) return 0; + if(this_player() != this_object()) return 0; + if(this_player()->GetForced()) return 0; + if(!(tmp = read_file(absolute_path(query_cwd(), str)))) + return notify_fail(sprintf("nmsh: script %s not found.\n")); + maxi = sizeof(lines = explode(tmp, "\n")); + for(i=0; i < maxi; i++){ + if(lines[i][0] == '#') continue; + if(!command(lines[i])){ + message("system", sprintf("nmsh: error in executing %s.", str), + this_player()); + return 1; + } + } + return 1; +} + +nomask static int cmd_pushd(string str){ + if(this_player() != this_object()) return 0; + if(!set_cwd(str)) return 0; + pushd(str); + return 1; +} + +nomask static int cmd_popd(){ + if(this_player() != this_object()) return 0; + set_cwd(popd()); + return 1; +} + +nomask static int cmd_pwd(){ + if(!query_cwd()) message("system", "No current directory.", this_object()); + else message("system", query_cwd()+":", this_object()); + return 1; +} + +nomask static int cmd_work(string str){ + string *tmp; + object ob; + string file; + int flag; + + if(!str || str == "") ob = environment(this_object()); + else if(str == "!"){ + flag = 1; + ob = environment(this_object()); + } + else if(str[0] == '!'){ + flag = 1; + str = str[1..strlen(str)]; + } + if(!ob && !(ob = present(str, this_object()))) + ob = present(str, environment(this_object())); + if(!ob) return notify_fail("No target object found.\n"); + tmp = explode(file = base_name(ob), "/"); + set_cwd("/"+implode(tmp[0..sizeof(tmp)-2], "/")); + if(flag){ + message("system", file+".c, "+file_size(file+".c")+" bytes:", + this_object()); + this_object()->eventEdit(file+".c"); + } + return 1; +} + +varargs int erase_prompt(int x){ + if(!this_object() || this_object()->GetCedmode()) return 0; + /* receive("\r\e[6n"); */ /* ask cursor pos */ + return receive("\e[2K\e["+GetScreen()[1]+";"+1+"H\e[2K"); +} + +string GetPromptString(){ + string ret = Prompt; + if(!sizeof(ret)) return ""; + ret = replace_string(ret,"%^","%%^^"); + return ret; +} + +varargs nomask string GetPrompt(int withbuff){ + string ret, ret2 = ""; + mixed tmp; + int x, y; + + if(withbuff) ret2 = this_object()->GetCharbuffer(); + + if( (y = query_ed_mode()) != -1 ){ + if( !y ){ + string n = "\n"; + if(this_object()->GetProperty("reprompt")) n = ". "; + ret = "\tQ)uit without saving, save and ex)it, h)elp"+n+"Command: "; + } + else if( y == -2 ) ret = "Help: "; + else ret = "*\b"; + return ret; + } + if((ret = Prompt) == DEFAULT_PROMPT){ + return ret + ret2; + } + if((ret = Prompt) == "cwd"){ + if(creatorp(this_object())){ + ret = query_cwd() + " > " + ret2; + } + else { + ret = DEFAULT_PROMPT + ret2; + } + return ret; + } + if((ret = Prompt) == "status"){ + ret = this_object()->eventDisplayStatus(1) + " > "; + return ret + ret2; + } + if(grepp(ret,"$g")) + ret = replace_string(ret,"$g",itoa(this_object()->GetMagicPoints())); + if(grepp(ret,"$G")) + ret = replace_string(ret,"$G",itoa(this_object()->GetMaxMagicPoints())); + if(grepp(ret,"$M")) + ret = replace_string(ret, "$M", mud_name()); + if(grepp(ret,"$m")) + ret = replace_string(ret, "$m", lower_case(mud_name())); + if(grepp(ret,"$N")) + ret = replace_string(ret,"$N",capitalize(this_object()->GetKeyName())); + if(grepp(ret,"$n")) + ret = replace_string(ret, "$n", GetKeyName()); + + if(grepp(ret,"$V")){ + if(GetInvis()) + ret = replace_string(ret,"$V","INVIS"); + else + ret = replace_string(ret,"$V",""); + } + if(grepp(ret,"$P")){ + tmp = query_cwd(); + if(!tmp || !sizeof(tmp)) tmp = "No working directory."; + ret = replace_string(ret,"$P",tmp); + } + if(grepp(ret,"$C")) ret = replace_string(ret,"",itoa( CmdNumber+1 )); + if(grepp(ret,"$h")) ret = replace_string(ret,"$h",itoa( this_object()->GetHealthPoints() )); + if(grepp(ret,"$H")) ret = replace_string(ret,"$H",itoa( this_object()->GetMaxHealthPoints() )); + if(grepp(ret,"$i")) ret = replace_string(ret,"$i",itoa( this_object()->GetStaminaPoints() )); + if(grepp(ret,"$I")) ret = replace_string(ret,"$I",itoa( to_int(this_object()->GetMaxStaminaPoints() ))); + if(grepp(ret,"$D")){ + string mo, yr; + tmp = local_time(); + mo = sprintf("%02d", (tmp[4]+1)); + yr = last(sprintf("%02d", tmp[5]),2); + + if(grepp(ret,"$D0")) + ret = replace_string(ret,"$D0", mo+"/"+tmp[3]+"/"+yr); + if(grepp(ret,"$D1")) + ret = replace_string(ret,"$D1", mo+"/"+tmp[3]+"/"+yr); + if(grepp(ret,"$D2")) + ret = replace_string(ret,"$D2", tmp[3]+"/"+mo+"/"+yr); + if(grepp(ret,"$D")) + ret = replace_string(ret,"$D", tmp[3]+system_month(tmp[4],1)+yr); + } + if(grepp(ret,"$T")){ + string min, hr, sec, tz = this_object()->GetProperty("timezone"); + tmp = local_time(tz); + min = sprintf("%02d", tmp[1]); + hr = sprintf("%02d", tmp[2]); + sec = sprintf("%02d", tmp[0]); + ret = replace_string(ret,"$T",hr+":"+min+":"+sec); + } + ret += " "; + return ret + ret2; +} + +varargs nomask string write_prompt(string str){ + string ret, uncolor; + int diff, tmp, bottom = GetScreen()[1]; + int side = GetScreen()[0]; + + if(!this_object()) return ""; + + if(origin() == "driver"){ + if(this_object()->GetProperty("reprompt")){ + //Avoids double pumped prompt when fancy stuff is on. + return ""; + } + } + + if(!Termstuff) Termstuff = ([]); + if(!Termstuff["Terminal"]){ + Termstuff["Terminal"] = this_object()->GetTerminal(); + } + if(!Termstuff["TermInfo"]){ + Termstuff["TermInfo"] = + TERMINAL_D->query_term_info(Termstuff["Terminal"]); + } + if(str){ + receive(str); + return str; + } + ret = GetPrompt(this_object()->GetCharmode()); + uncolor = strip_colours(ret); + ret = terminal_colour(ret + "%^RESET%^", Termstuff["TermInfo"]); + tmp = sizeof(uncolor); + if(tmp > side){ + /* Calculate which row to put the prompt on based on wrapping. + * Without this, horrible horizontal redraw/scrolling happens. + */ + bottom = bottom - (( tmp / side ) + ((tmp % side) ? 1 : 0 )); /* lol */ + } + if(!this_object()->GetCedmode()){ + if(!(tmp % side)){ + /* If the line hits a wrap point, scroll up screen data */ + if(tmp == side) receive("\r\eD"); + receive("\r\eD"); + } + receive("\r\e["+bottom+";"+1+"H"); + receive(ret); + } + return ret; +} + +string process_input(string str){ + string tmp, xtra, request; + if(!str || str == "") return ""; + else if(GetClient() && + member_array(GetClient(), SUPPORTED_CLIENTS) != -1){ + if(sscanf(str, "<%s>%s", request, xtra)){ + process_request(request, xtra ? xtra : ""); + return ""; + } + else return str; + } + else { + tmp = eventHistory(str); + if(tmp == ""){ + return ""; + } + } + if(tmp != str) message("system", tmp, this_object()); + return do_alias(do_nickname(tmp)); +} + +nomask static void process_request(string request, string xtra){ + switch(request){ + case "ALIAS": + receive("<ALIAS>[n,go north] [s,go south] [e,go east] [w,go west] " + "[nw,go northwest] [ne,go northeast] [sw,go southwest] " + "[se,go southeast] [u,go up] [d,go down] [i,inventory] " + "[bio,biography] [exa,look at $*] [$',say $*] " + "[$:,emote $*] [l,look]\n"); + break; + case "NICKNAME": receive("<NICKNAME>\n"); break; + case "USERS": + receive("<USERS>"+implode(map_array(filter(users(), + "request_vis", this_object()), "user_names", this_object()), + ", ")+"\n"); + break; + case "ROOM": + receive("<ROOM>"+ + environment(this_object())->GetShort()+"\n"); + break; + case "PRESENT": + receive("<PRESENT>"+ + implode(map_array(filter(all_inventory(environment(this_object())), + "request_vis", this_object()), "user_names", this_object()), + ", ")+"\n"); + break; + default: + receive("<error>Request not supported.\n"); + break; + } +} + +static int request_vis(object ob){ + return (userp(ob) && !(ob->GetInvis(this_object()))); +} + +static string user_names(object ob){ + return ob->GetName(); +} + +private static int set_cwd(string str){ + int x; + string tmpstr = str; + if(str == "~-" || str == "-") str = Directories["previous"]; + if(!str || str == "") str = user_path(GetKeyName()); + if (str[<1] == '/' && str != "/") str = str[0..<2]; + replace_string(str, "//", "/"); + str = absolute_path(query_cwd(), str); + if(!directory_exists(str) && tmpstr == "here" && environment(this_player())){ + str = path_prefix(base_name(environment(this_player()))); + } + if((x=file_size(str)) != -2){ + if(x > -1){ + message("system", sprintf("%s: Path is a file.", str), this_player()); + return 0; + } + else { + message("system", sprintf("%s: No such reference.", str), this_player()); + return 0; + } + } + + if(str != query_cwd()) Directories["previous"] = query_cwd(); + Directories["current"] = str; + message("system", sprintf("%s:", Directories["current"]), this_player()); + return 1; +} + +string GetUserPath(){ + return Directories["home"]; +} + +string SetUserPath(string str){ + if(this_player() != this_object()) return 0; + return Directories["home"] = str; +} + +private static void pushd(string str){ + if(CWDCount++ == DIRECTORY_STACK_SIZE){ + CWDCount--; + CWDBottom = (++CWDBottom) % DIRECTORY_STACK_SIZE; + } + Stack[CWDTop] = str; + CWDTop = (++CWDTop) % DIRECTORY_STACK_SIZE; +} + +private static string popd(){ + if(!CWDCount) return 0; + CWDCount--; + return Stack[--CWDTop]; +} + +nomask private static string do_nickname(string str){ + if(!Nicknames) return str; + if(str[0..7] == "nickname") return str; + return implode(map_array(explode(str, " "), "replace_nickname", this_object()), " "); +} + +nomask private static string do_alias(string str){ + string *words; + string tmp, ret; + int x; + + if(!sizeof(words = explode(str, " "))) return ""; + if((x = strlen(words[0])) && (tmp = Xverbs[words[0][0..0]])){ + words[0] = words[0][1..x-1]; + return replace_string(tmp, "$*", implode(words, " ")); + } + if(!(tmp = Aliases[words[0]])) return implode(words, " "); + else str = implode(words[1..sizeof(words)-1], " "); + ret = replace_string(tmp, "$*", str); + return ret; +} + +string GetAlias(string alias){ + string ret = Aliases[alias]; + if(!this_player() || this_player() != this_object() || + this_player()->GetForced()) return 0; + else return ret; +} + +string GetXverb(string xverb){ + string ret = Xverbs[xverb]; + if(!this_player() || this_player() != this_object() || + this_player()->GetForced()) return 0; + else return ret; +} + +nomask static string replace_nickname(string str){ + if(str == "") return str; + if(str[0] == '\\') return str[1..(strlen(str)-1)]; + else if(Nicknames[str]) return Nicknames[str]; + else return str; +} + +void reset_prompt(){ + if(!stringp(Prompt)) Prompt = "> "; +} + +string query_cwd(){ return Directories["current"]; } + +string query_prev_wd(){ return Directories["previous"]; } + +string SetPrompt(string str){ return Prompt = str; } + +int query_mp(){ return 1; } + +int query_max_mp(){ return 10; } + +int query_hp(){ return 1; } + +int query_max_hp(){ return 10; } + +int query_sp(){ return 1; } + +int query_max_sp(){ return 10; } + +string get_path(){ return query_cwd(); } + +varargs int GetInvis(){ return 0; } + +string GetKeyName(){ return 0; } + +#if FAIL +string fail(){ + string fale; + fale += ""; + write("lol fail"); + return fale; +} +#endif + +static void EchoCommand(string str){ + mixed clr, ret; + if(clr = (this_object()->GetProperty("commandecho"))){ + clr = lower_case(clr); + if(atoi(clr) || clr == "on") clr = "reset"; + ret = "%^"+upper_case(clr)+"%^"+str+"%^RESET%^"; + write(ret); + } +} + +mixed RecalculateHist(int x){ + mapping command_hist = this_object()->GetHistoryList(); + string charbuffer = this_object()->GetCharbuffer(); + int histsize = sizeof(command_hist); + if(!histsize){ + command_hist = ([ 0 : "" ]); + histsize = 1; + } + if(histmatch > 0 && sizeof(charbuffer) && !sizeof(recalled_command_sub)){ + mixed tmpvals; + tmpvals = filter(values(command_hist), + (: $1 && !strsrch($1, this_object()->GetCharbuffer()) :)); + if(sizeof(tmpvals)){ + recalled_command_sub = charbuffer; + } + } + if(x) recalled_command_num++; + else recalled_command_num--; + if(recalled_command_num < 0) recalled_command_num = (histsize - 1); + if(recalled_command_num > (histsize - 1)) recalled_command_num = 0; + recalled_command = command_hist[recalled_command_num]; + if(sizeof(recalled_command_sub) && + strsrch(recalled_command, recalled_command_sub)){ + int hit = 0; + while(!hit){ + if(x) recalled_command_num++; + else recalled_command_num--; + if(recalled_command_num < 0) recalled_command_num = (histsize - 1); + if(recalled_command_num > (histsize - 1)) recalled_command_num = 0; + if(!strsrch(command_hist[recalled_command_num], + recalled_command_sub)){ + hit = 1; + recalled_command = command_hist[recalled_command_num]; + } + } + } + return recalled_command; +} + +static int rBackspace(){ + string cb = this_object()->GetCharbuffer(); + if(!sizeof(cb)) return 0; + recalled_command_sub = ""; + cb = truncate(cb, 1); + this_object()->SetCharbuffer(cb); + histmatch = 0; + erase_prompt(); + write_prompt(); + return 1; +} + +static int rDel(){ + histmatch = 0; + erase_prompt(); + write_prompt(); + return 1; +} + +static int rEnter(){ + string charbuffer = this_object()->GetCharbuffer(); + string tmp; + this_object()->SetNoEcho(0); + /* re-add any removed pinkfish */ + charbuffer = replace_string(charbuffer,"%%^^","%^"); + EchoCommand(charbuffer); + + /* This next thing is probably a bit obscure, so I'll explain. We're + * about to save the line that we just received into the + * character buffer called "tempbuffer" stored in LIB_CHARIO. + * The idea is to have "what I just typed" available somewhere before + * it is expanded from its alias. This allows for up-arrow history + * recall matching that keys not on the expanded command, but what + * I really just typed, allowing for selective/matched recall of + * aliases and add_actions. See the Push() call from LIB_COMMAND + * to LIB_HISTORY. + * + * And to you it was just an arbitrary line of code. + * + * Yeah. I'm that awesome. + */ + this_object()->SetTempbuffer(charbuffer); + + tmp = process_input(charbuffer); + this_object()->SetCharbuffer(""); + recalled_command_sub = ""; + histmatch = 0; + if(sizeof(tmp)){ + if(!command(tmp)){ + this_object()->cmdAll(tmp); + parse_sentence(tmp); + } + } + else { + write(""); /* Move up a line */ + } + recalled_command_num = 0; + erase_prompt(); + write_prompt(); +} + +static int rCtrl(string str){ + string charbuffer = this_object()->GetCharbuffer(); + if(str == "d"){ /* Ctrl-D */ + write("Canceling charmode!"); + this_object()->CancelCharmode(); + erase_prompt(); + write_prompt(); + } + else if(str == "c"){ /* Ctrl-C */ + this_object()->SetCharbuffer(""); + recalled_command_sub = ""; + recalled_command_num = 0; + erase_prompt(); + write_prompt(); + } + if(str == "i" ){ /* Taberino */ + mixed cmds; + if(!sizeof(charbuffer)){ + /* should anything happen here? */ + } + if(grepp(charbuffer, " ")){ + string arg1, arg2, lastarg, cmd, tmp_str; + string *commands, *tmp_arr, *ret_arr = ({}); + int i; + object ob, env, *ob_arr; + /* An action has been typed and a space after it + * tells us the user wants us to figure out the + * argument. Let's first chew on isolating the action. + */ + i = sscanf(charbuffer, "%s %s", arg1, arg2); + if(i != 2){ + cmd = trim(charbuffer); + } + else { + cmd = arg1; + arg2 = trim(arg2); + } + if(sizeof(arg2)){ + lastarg = trim(last_string_element(charbuffer, " ")); + charbuffer = trim(replace_string(charbuffer, lastarg, "")); + } + cmds = match_command(cmd, 1); + if(sizeof(cmds) == 1){ /* we want an unambiguous match */ + cmd = cmds[0]; + commands = ({}); + foreach(mixed path in this_player()->GetSearchPath()){ + commands += CMD_D->GetCommands(path); + } + if(cmd && member_array(cmd, commands) != -1){ + string *file_cmds, *dir_cmds, *both_cmds; + int abso; + /* It's a command! Let's see if it's a file + * manipulating kind of command. + */ + file_cmds = ({ "ced", "clone", "goto", "rehash", "reset", + "showtree", "bk", "cat", "cp", "diff", "ed", + "grep", "head", "indent", "longcat", "more", "mv", + "rm", "sed", "showfuns", "source", "tail", + "update" }); + dir_cmds = ({ "cd", "ls", "mkdir", "rmdir" }); + both_cmds = file_cmds + dir_cmds; + + if(member_array(cmd, both_cmds) != -1 ){ + string pre, post; + string *candidates = ({}); + string my_path = query_cwd(); + string clr = "%^GREEN%^"; + string rst = "%^RESET%^"; + + /* Indeed a filesystem command. If there + * is an argument to work with, let's try + * to use it to guess which file/dir to + * manipulate. + */ + if(lastarg){ + if(lastarg[0..0] == "/"){ + pre = path_prefix(lastarg); + abso = 1; + } +#if 0 + if(lastarg[0..2] == "../"){ + lastarg = my_path + "/"; + pre = path_prefix(my_path) + "/"; + abso = 1; + } +#endif + else { + pre = path_prefix(my_path+"/"+lastarg); + } + post = last_string_element(lastarg, "/"); + } + else { + pre = my_path; + } + if(!sizeof(post)) post = lastarg; + candidates = get_dir(pre + "/"); + if(sizeof(post) && sizeof(candidates)){ + candidates = regexp(candidates, "^"+post); + } + if(sizeof(candidates) == 1){ + string tmplast; + post = last_string_element(lastarg, "/"); + if(grepp(lastarg,"/")){ + tmplast = replace_string(candidates[0], + post, "", 1); + } + else { + tmplast = replace_string(candidates[0], + lastarg, "", 1); + } + lastarg += tmplast; + } + else if(sizeof(candidates) > 1){ + mapping Matches = ([]); + tmp_str = ""; + foreach(string thing in candidates){ + if(sizeof(thing) > sizeof(tmp_str)){ + tmp_str = thing; + } + if(directory_exists(pre+"/"+thing)){ + ret_arr += ({ clr+thing+rst+"/" }); + } + else ret_arr += ({ thing }); + } + foreach(string thing in candidates){ + int fail; + if(thing == tmp_str) continue; + for(int j=0; j < sizeof(thing)-1; j++){ + if(thing[j] != tmp_str[j]) fail = 1; + if(!fail) Matches[j] = thing; + } + } + if(sizeof(Matches)){ + i = sort_array(keys(Matches), -1)[0]; + tmp_str = Matches[i][0..i]; + } + if(sizeof(lastarg) && sizeof(tmp_str)) lastarg = tmp_str; + if(abso && sizeof(lastarg) && + lastarg[0..0] != "/"){ + lastarg = "/"+lastarg; + } + write(format_page2(ret_arr, 4)); + } + if(!lastarg) lastarg = ""; + if(grepp(lastarg,"/")){ + lastarg = last_string_element(lastarg, "/"); + } + tmp_str = pre+"/"+lastarg+"/"; + tmp_str = replace_string(tmp_str, "//", "/"); + tmp_str = replace_string(tmp_str, "//", "/"); + if(directory_exists(tmp_str) && !sizeof(ret_arr)){ + if(abso) lastarg = tmp_str; + else { + lastarg = replace_string(tmp_str, + query_cwd()+"/", ""); + } + tmp_arr = get_dir(tmp_str); + foreach(string thing in tmp_arr){ + if(directory_exists(tmp_str+thing)){ + ret_arr += ({ clr+thing+rst+"/" }); + } + else ret_arr += ({ thing }); + } + if(sizeof(lastarg) && last(lastarg,1) != "/"){ + lastarg += "/"; + } + write(format_page2(ret_arr, 4)); + } + else if(sizeof(tmp_str) && last(tmp_str,1) == "/"){ + lastarg = truncate(tmp_str, 1); + } + if(abso && sizeof(lastarg) && lastarg[0..0] != "/"){ + lastarg = "/"+lastarg; + } + + if(sizeof(lastarg)) charbuffer += " "+lastarg; + else charbuffer = trim(charbuffer) + " "; + } /* end filesystem command */ + } /* end command handler */ + this_object()->SetCharbuffer(charbuffer); + if(VERBS_D->GetVerb(cmd) && + creatorp(this_object())){ + /* It's a verb, so the arg otta be an object. + * We won't be doing "object name completion" + * for players since that's a cheat vector. + */ + if(sizeof(lastarg)){ + if(!ob && (env = environment(this_object()))){ + ob_arr = all_inventory(env) + + all_inventory(this_object()); + ob_arr = filter(ob_arr, + (: answers_to( $(lastarg), $1) :) ); + } + else tmp_arr = regexp(ob->GetCanonicalId(), + "^"+lastarg); + if(!sizeof(tmp_arr) && sizeof(ob_arr) == 1){ + tmp_arr = regexp(ob_arr[0]->GetCanonicalId(), + "^"+lastarg); + } + if(sizeof(tmp_arr)) tmp_str = tmp_arr[0]; + if(!tmp_str && sizeof(ob_arr) > 1){ + foreach(mixed thing in ob_arr){ + tmp_arr = regexp(thing->GetCanonicalId(), + "^"+lastarg); + if(sizeof(tmp_arr)){ + tmp_str = tmp_arr[0]; + tmp_str += " " + file_name(thing) + " "; + tmp_str += thing->GetKeyName(); + ret_arr += ({ tmp_str }); + } + } + } + else if(tmp_str){ + lastarg = tmp_str; + } + if(sizeof(ret_arr) && tmp_str != lastarg){ + foreach(string thtring in + sort_array(ret_arr,1)){ + write(thtring); + } + } + if(lastarg) charbuffer += " " + lastarg; + } /* end available argument for the verb */ + } /* end verb handler */ + } /* end unambiguous command */ + } /* end arg detection */ + else { + /* A clean fallthrough would be nice here :( */ + } + cmds = match_command(charbuffer,1); + if(!sizeof(cmds)){ + this_object()->SetCharbuffer(charbuffer); + } + else if(sizeof(cmds) == 1){ + charbuffer = cmds[0]; + this_object()->SetCharbuffer(charbuffer); + erase_prompt(); + write_prompt(); + } + else { + write(identify(sort_array(cmds,1))); + } + erase_prompt(); + write_prompt(); + } + return 1; +} + +static int rArrow(string str){ + string charbuffer; + if(!str) return 0; + switch(str){ + case "up" : + charbuffer = RecalculateHist(0); + histmatch = -1; + this_object()->SetCharbuffer(charbuffer); + erase_prompt(); + write_prompt(); + break; + case "down" : + charbuffer = RecalculateHist(1); + histmatch = -1; + this_object()->SetCharbuffer(charbuffer); + erase_prompt(); + write_prompt(); + break; + case "left" : + recalled_command_sub = ""; +#if CMD_EDITING + this_object()->eventReceive("\e[D", 1, 1); + this_object()->eventReceive("\e[6n", 1, 1); +#endif + break; + case "right" : + recalled_command_sub = ""; +#if CMD_EDITING + this_object()->eventReceive("\e[C", 1, 1); + this_object()->eventReceive("\e[6n", 1, 1); +#endif + break; + } + return 0; +} + +static int rAscii(string str){ + if(!histmatch) histmatch = 1; + erase_prompt(); + write_prompt(); + return 1; +} + +static int rAnsi(string str){ + return 1; +} diff --git a/lib/lib/npc.c b/lib/lib/npc.c new file mode 100644 index 0000000..b2f226f --- /dev/null +++ b/lib/lib/npc.c @@ -0,0 +1,692 @@ +/* /lib/npc.c + * from the Dead Souls LPC Library + * the standard non-player character object + * created by Descartes of Borg 950323 + * Version: @(#) npc.c 1.11@(#) + * Last Modified: 96/12/21 + */ + +#include <lib.h> +#include ROOMS_H +#include <daemons.h> +#include <position.h> +#include <armor_types.h> +#include <message_class.h> +#include <vision.h> +#include "include/npc.h" + +#ifndef CATCH_TELL_ROOM +#define CATCH_TELL_ROOM "/domains/default/room/catchtell" +#endif + +inherit LIB_DESCRIBE; +inherit LIB_CHAT; +inherit LIB_COMMAND; +inherit LIB_CONTAINER; +inherit LIB_LIVING; +inherit LIB_MESSAGES; +inherit LIB_MOVE; +inherit LIB_OBJECT; +inherit LIB_DOMESTICATE; +inherit LIB_GUARD; +inherit LIB_UNIQUENESS; +inherit LIB_SHADOW_HOOK; + +private int CustomXP, ActionChance, CombatActionChance, AutoStand; +private mixed Encounter; +private string *EnemyNames; +private static int NPCLevel, Unique; +private static mixed Die, Action, CombatAction; +private static mapping Inventory; +private static string MountStyle = "ridden"; +private int VisibleRiders = 1; +private int actions_enabled = 1; +mapping Equipped = ([]); + +int eventExtraAction(){ return 1; } + +static void create(){ + SetSaveRecurse(1); + chat::create(); + command::create(); + living::create(); + messages::create(); + object::create(); + Setup(); + SetPK(1); + SetOpacity(0); + EnemyNames = ({}); + Encounter = 0; + ActionChance = 0; + Unique = 0; + CustomXP = 0; + Inventory = ([]); + AutoStand = 1; + set_heart_beat( GetHeartRate() ); +} + +void CheckEncounter(){ + string *enemies; + object env = environment(this_object()); + object *dudes; + + if(!env) return; + + dudes = singular_array(get_livings(env) + ({ this_player() })); + + if( !query_heart_beat() ){ + eventCheckHealing(); + set_heart_beat( GetHeartRate() ); + } + + foreach(object dude in dudes){ + object denv; + if(dude) denv = environment(dude); + if(!denv || !dude || denv != env || dude->GetInvis()) continue; + if( sizeof(enemies = GetEnemyNames()) ){ + if( member_array(dude->GetKeyName(),enemies) != -1 ){ + eventExecuteAttack(dude); + continue; + } + } + if( Encounter ){ + int x = 0; + + if( functionp(Encounter) ){ + x = evaluate(Encounter, dude); + } + else if( arrayp(Encounter) ){ + if( member_array(dude->GetKeyName(), Encounter) > -1 ){ + x = 1; + } + else { + x = 1; + } + } + else if( dude->GetStatLevel("charisma") < Encounter ){ + x = 1; + } + if( x ){ + SetAttack(dude); + } + } + } +} + +static void init(){ + guard::init(); + CheckEncounter(); +} + +static void heart_beat(){ + int position; + living::heart_beat(); + guard::heart_beat(); + if( !ContinueHeart() ){ + set_heart_beat(0); + return; + } + eventExtraAction(); + position = GetPosition(); + if( position == POSITION_LYING || position == POSITION_SITTING ){ + if(AutoStand && + !RACES_D->GetLimblessRace(this_object()->GetRace())) + eventForce("stand up"); + if(GetInCombat() && + !RACES_D->GetLimblessRace(this_object()->GetRace()) ) + eventForce("stand up"); + } + if( !GetInCombat() && actions_enabled && ActionChance > random(100) ){ + int x; + + if( functionp(Action) ) evaluate(Action); + else if( pointerp(Action) && (x = sizeof(Action)) ){ + mixed act; + + act = Action[random(x)]; + if(functionp(act)){ + evaluate(act); + return; + } + if( act && act != "" && act[0] == '!' && act != "!" ){ + act = act[1..]; + eventForce(act); + } + else message("other_action", act, environment()); + } + } + else if( GetInCombat() && CombatActionChance > random(100) ){ + int x; + + if( functionp(CombatAction) ){ + evaluate(CombatAction); + } + else if( pointerp(CombatAction) && (x = sizeof(CombatAction)) ){ + mixed mact; + string act; + + x--; + mact = CombatAction[random(x)]; + if( functionp(mact) ){ + + evaluate(mact); + return; + } + if( !stringp(mact) ) mact = "emote looks confused."; + else act = mact; + if( act && act != "" ){ + eventForce(act); + } + else message("other_action", act, environment()); + } + } +} + +static int Destruct(){ + if( GetParty() ) PARTY_D->eventLeaveParty(this_object()); + living::Destruct(); + return object::Destruct(); +} + +void eventReconnect(){ } + +/* *************** /lib/npc.c command functions ************** */ +static int cmdAll(string arg){ + object env; + string verb; + + verb = query_verb(); + env = environment(); + if( chat::chat_command(verb + " " + arg) == "" ) return 1; + return command::cmdAll(arg); +} + +/* *************** /lib/npc.c events *************** */ + + +int eventCompleteMove(mixed dest){ + mixed val; + string file; + int x; + + if( environment() ) return move::eventMove(dest); + else x = move::eventMove(dest); + if( !x ) return x; + foreach(file, val in Inventory){ + object ob = previous_object(); + if(ob == dest && dest->GetPersistent()) break; + + if( intp(val) ){ + if( val < 0 ){ + ob = unique(file, -val); + if( ob ) ob->eventMove(this_object()); + } + else while(val--) + if( ob = new(file) ) ob->eventMove(this_object()); + } + else if( stringp(val) ) { + if( !(ob = new(file)) ) continue; + if( ob->eventMove(this_object()) ) eventForce(val); + } + else if( functionp(val) ){ + if( !(ob = new(file)) ) continue; + if( ob->eventMove(this_object()) ) evaluate(val); + } + } + return x; +} + +int eventDestruct(){ + mixed array worn = ({}); + if(!valid_event(previous_object(), this_object())) return 0; + if(room_environment() && room_environment()->GetPersistent()){ + if(!Equipped) Equipped = ([]); + worn = this_object()->GetWorn(); + worn += this_object()->GetWielded(); + foreach(mixed thing in worn){ + if(arrayp(thing) && sizeof(thing)) thing = thing[0]; + if(!thing || !objectp(thing)) continue; + if(Equipped[file_name(thing)]) continue; + Equipped[file_name(thing)] = + ([ "object" : thing, "where" : thing->GetWorn() ]); + } + } + chat::eventDestruct(); + object::eventDestruct(); +} + +varargs int eventDie(mixed agent){ + int x; + string death_verb = "dies"; + string death_action = "kill"; + string death_descriptor = "dead"; + object env = (environment() || load_object(ROOM_POD)); + + if(RACES_D->GetNonMeatRace(GetRace())){ + death_verb = "breaks down completely"; + death_action = "destroy"; + death_descriptor = "broken"; + } + + if(this_object()->GetDead() || this_object()->GetDeathEvents()) return 0; + + if( (x = living::eventDie(agent)) != 1 ) return x; + if( stringp(Die) ) { + message("other_action", Die, env, ({ this_object() })); + if( agent) message("my_action", "You "+death_action+" " + GetName() + ".", agent); + } + else if( functionp(Die) && !evaluate(Die, agent) ) return 0; + else { + if(GetPosition() == POSITION_STANDING) message("other_action", "%^BOLD%^%^RED%^"+ GetName() + " drops "+death_descriptor+".", env, ({ this_object() }) ); + else if(GetPosition() == POSITION_FLYING) message("other_action", "%^BOLD%^%^RED%^"+ GetName() + " falls "+death_descriptor+".", env, ({ this_object() }) ); + else message("other_action", "%^BOLD%^%^RED%^"+ GetName() + " "+death_verb+".", env, ({ this_object() }) ); + if( agent ) + message("my_action", "You "+death_action+" " + GetName() + ".", + (objectp(agent) ? agent : load_object(CATCH_TELL_ROOM)) ); + } + set_heart_beat(0); + call_out( (: Destruct :), 0); + flush_messages(); + return 1; +} + +mixed eventTurn(object who){ + if( !living::eventTurn(who) ){ + return 0; + } + all_inventory()->eventDestruct(); + call_out((: Destruct :), 0); + return 1; +} + +void eventEnemyDied(object ob){ + living::eventEnemyDied(ob); + EnemyNames -= ({ ob->GetKeyName() }); +} + +int eventMove(mixed dest){ + int ret; + ret = eventCompleteMove(dest); + guard::CheckPending(); + return ret; +} + +varargs int eventPrint(string msg, mixed arg2, mixed arg3){ + object *riders = filter(deep_inventory(), (: $1->GeteventPrints() :) ); + object *targs = ({}); + if(NPC_CATCH_TELL_DEBUG){ + tell_room(ROOM_CATCH_TELL,"-------"); + tell_room(ROOM_CATCH_TELL,timestamp()); + tell_room(ROOM_CATCH_TELL,"obj: "+identify(this_object())); + tell_room(ROOM_CATCH_TELL,"msg: "+msg); + tell_room(ROOM_CATCH_TELL,"arg2: "+identify(arg2)); + tell_room(ROOM_CATCH_TELL,"arg3: "+identify(arg3)); + tell_room(ROOM_CATCH_TELL,"stack: "+get_stack()); + tell_room(ROOM_CATCH_TELL,"previous: "+identify(previous_object(-1))); + tell_room(ROOM_CATCH_TELL,"-------"); + } + if(riders && sizeof(riders)){ + int i1, rider_source; + if(!arg2) arg2 = 0; + if(!arg3) arg3 = 0; + if(sizeof(riders)){ + if(arg2 && intp(arg2)){ + object *tmp_riders = riders; + if(arg2 & MSG_CONV || arg2 & MSG_ENV){ + foreach(object ob in previous_object(-1)){ + if(member_array(ob,riders) != -1){ + tmp_riders -= ({ ob }); + rider_source = 1; + } + } + } + if((arg2 & MSG_CONV)) true(); + else { + if(objectp(arg2)) targs = tmp_riders - ({ arg2 }); + else if(arrayp(arg2)) targs = tmp_riders - arg2; + else targs = tmp_riders; + targs->eventPrint(msg, arg3); + } + } + i1 = sizeof(previous_object(-1)) -1; + if(i1 < 0) i1 = 0; + if(sizeof(previous_object(-1)) && + (member_array(previous_object(),riders) != -1 || + member_array(previous_object(-1)[i1],riders) != -1) && + (!intp(arg2) || (!(arg2 & MSG_CONV) && !(arg2 & MSG_ENV))) && + member_array(this_object(),previous_object(-1)) == -1){ + if(objectp(arg2)) targs = riders - ({ arg2 }); + else if(arrayp(arg2)) targs = riders - arg2; + else targs = riders; + if(VisibleRiders) environment()->eventPrint(msg, arg2, arg3); + else targs->eventPrint(msg, arg2); + } + } + } + return 1; +} + +int eventReceiveObject(object who){ + object ob; + + ob = previous_object(); + if( !ob || !container::eventReceiveObject() ) return 0; + AddCarriedMass(ob->GetMass()); + if(environment()) environment()->AddCarriedMass(ob->GetMass()); + return 1; +} + +int eventReleaseObject(object who){ + object ob; + + ob = previous_object(); + if( !ob || !container::eventReleaseObject() ) return 0; + if( ob->GetMass() ){ + AddCarriedMass( -(ob->GetMass()) ); + if(environment()) environment()->AddCarriedMass(-(ob->GetMass())); + } + return 1; +} + +varargs int eventShow(object who, string str){ + if( !living::eventShow(who, str) ) return 0; + eventPrint(this_player()->GetName() + " looks you over."); + return 1; +} + +/* *************** /lib/npc.c modal functions *************** */ + +int CanCarry(int amount){ return living::CanCarry(amount); } + +int CanReceive(object ob){ return CanCarry(ob->GetMass()); } + +/* *************** /lib/npc.c lfuns *************** */ + +static int ContinueHeart(){ + object env; + + if( !(env = environment()) ) return 0; + if( !sizeof(filter(all_inventory(env), (: living :))) ) return 0; + return 1; +} + +/* *************** /lib/npc.c data functions *************** */ + +mapping SetInventory(mapping mp ){ return (Inventory = mp); } +mapping GetInventory(){ return copy(Inventory); } + +varargs string SetRace(string race, mixed extra){ + race = living::SetRace(race, extra); + eventCompleteHeal(GetMaxHealthPoints()); + return race; +} + +string SetClass(string cls){ + string *skills; + int x, i; + + cls = living::SetClass(cls); + x = NPCLevel; + i = sizeof(skills = GetSkills()); + while(i--){ + int y; + + y = (GetSkillClass(skills[i]) || 5); + SetSkill(skills[i], (3*x)/y, y); + } + return cls; +} + +int SetLevel(int x){ + string *tmp; + int i; + + if(!NPCLevel){ + NPCLevel = x; + i = sizeof(tmp = GetSkills()); + while(i--){ + int y; + + y = (GetSkillClass(tmp[i]) || 5); + SetSkill(tmp[i], (3*x)/y, y); + } + i = sizeof(tmp = GetStats()); + while(i--){ + int y; + + y = (GetStatClass(tmp[i]) || 5); + SetStat(tmp[i], ((5-y)*10) + (3*x)/y, y); + } + eventCompleteHeal(GetMaxHealthPoints()); + } + else NPCLevel = x; + return NPCLevel; +} + +int GetLevel(){ return NPCLevel; } + +int SetCustomXP(int i){ + if(!i) i = 0; + CustomXP = i; + return CustomXP; +} + +int GetCustomXP(){ + if(!strsrch(base_name(this_object()), ESTATES_DIRS)){ + return -1; + } + return CustomXP; +} + +int SetMagicPoints(int x){ + if( x > GetMaxMagicPoints() ) + SetStat("intelligence", (x-50)/10, GetStatClass("intelligence")); + AddMagicPoints( x - GetMagicPoints() ); + return GetMagicPoints(); +} + +int SetMaxMagicPoints(int x){ + SetStat("intelligence", (x-50)/10, GetStatClass("intelligence")); + return GetMaxMagicPoints(); +} + +float SetStaminaPoints(float x){ + if( x > GetMaxStaminaPoints() ) + SetStat("agility", to_int((x-50.0)/10.0), GetStatClass("agility")); + AddStaminaPoints( x - GetStaminaPoints() ); + return to_float(GetStaminaPoints()); +} + +float SetMaxStaminaPoints(float x){ + SetStat("agility", (x-50.0)/10.0, GetStatClass("agility")); + return GetMaxStaminaPoints(); +} + +varargs void SetCurrency(mixed val, int amount){ + if( stringp(val) ) AddCurrency(val, amount); + else if( mapp(val) ){ + string *currs; + int i; + + i = sizeof(currs = keys(val)); + while(i--) AddCurrency(currs[i], val[currs[i]]); + } + else error("Bad argument 1 to SetCurrency()."); +} + +mixed SetEncounter(mixed val){ return (Encounter = val); } + +mixed SetAggressive(mixed val){ + if(!sizeof(Encounter)){ + if(val) Encounter = 100; + else Encounter = 0; + } + return Encounter; +} + +string *AddEncounter(string nom){ + if( !stringp(nom) ) error("Bad argument 1 to AddEncounter()\n"); + if( Encounter && !pointerp(Encounter) ) return 0; + else Encounter += ({ convert_name(nom) }); + return Encounter; +} + +string *RemoveEncounter(string nom){ + if( !stringp(nom) ) error("Bad argument 1 to RemoveEncounter()\n"); + if( Encounter && !pointerp(Encounter) ) return 0; + else if(Encounter) Encounter -= ({ convert_name(nom) }); + return Encounter; +} + +mixed GetEncounter(){ return Encounter; } + +mixed SetDie(mixed val){ return (Die = val); } + +mixed GetDie(){ return Die; } + +string SetKeyName(string nom){ + set_living_name(nom = object::SetKeyName(nom)); + return nom; +} + +string GetName(){ return object::GetName(); } + +string GetCapName(){ return object::GetCapName(); } + +string GetShort(){ + string ret = object::GetShort(); + object *riders = GetRiders(); + string *names = ({}); + if(sizeof(riders)) riders = filter(riders, + (: (!$1->GetInvis() || this_player()->GetWizVision()) :) ); + if(riders && sizeof(riders) && VisibleRiders){ + foreach(object rider in riders){ + names += ({ rider->GetShort() }); + } + ret += " "+MountStyle+" by "+conjunction(names); + } + return ret; +} + +string GetPlainShort(){ + return object::GetShort(); +} + +varargs string GetLong(string str){ + mapping counts; + string item, what; + string *affects = ({}); + object *riders = this_object()->GetRiders(); + string *ridernames = ({}); + + str = object::GetLong() + "\n"; + what = "The "+GetGender()+" "+GetRace(); + str += living::GetLong(what); + foreach(item in map(all_inventory(), + (: $1->GetAffectLong(this_object()) :))){ + if(item && member_array(item,affects) == -1) affects += ({ item }); + } + if(sizeof(affects)) str += implode(affects,"\n")+"\n"; + if(this_object()->GetAffectLong()) str += this_object()->GetAffectLong(); + if(riders && sizeof(riders) && VisibleRiders){ + foreach(object rider in riders){ + ridernames += ({ rider->GetShort() }); + } + str += capitalize(GetPlainShort())+" is "+MountStyle+" by "+conjunction(ridernames)+".\n"; + } + counts = ([]); + foreach(item in map( + filter(all_inventory(), (: !($1->GetInvis(this_object())) :)), + (: $1->GetEquippedShort() :))) + if( item ) counts[item]++; + if( sizeof(counts) ) str += GetCapName() + " is carrying:\n"; + foreach(item in keys(counts)) + str += capitalize(consolidate(counts[item], item)) + "\n"; + return str; +} + +int DisableActions(int x){ + if(x) actions_enabled = 0; + else actions_enabled = 1; + return actions_enabled; +} + +int EnableActions(int x){ + if(x) actions_enabled = 1; + else actions_enabled = 0; + return actions_enabled; +} + +int GetActionsEnabled(){ + return actions_enabled; +} + +void SetAction(int chance, mixed val){ + ActionChance = chance; + if( stringp(val) ) val = ({ val }); + else if( !functionp(val) && !pointerp(val) ) + error("Bad argument 2 to SetAction()\n"); + Action = val; +} + +mixed GetAction(){ return Action; } + +void SetCombatAction(int chance, mixed val){ + CombatActionChance = chance; + if( stringp(val) ) val = ({ val }); + else if( !functionp(val) && !pointerp(val) ) + error("Bad argument 2 to SetCombatAction()\n"); + CombatAction = val; +} + +mixed GetCombatAction(){ return CombatAction; } + +int AddCarriedMass(int x){ return living::AddCarriedMass(x); } + +mixed *GetCommands(){ return commands(); } + +string GetCommandFail(){ return "What?"; } + +int AddEnemy(object ob){ + string tmp; + + if( !living::AddEnemy(ob) ) return 0; + if( member_array(tmp = ob->GetKeyName(), EnemyNames) == -1 ) + EnemyNames += ({ tmp }); + return 1; +} + +string *GetEnemyNames(){ return EnemyNames; } + +int GetRadiantLight(int ambient){ + return (object::GetRadiantLight(ambient) + + container::GetRadiantLight(ambient)); +} + +int *GetScreen(){ return ({ 80, 24 }); } + +int GetAutoStand(){ return AutoStand; } + +int SetAutoStand(int i){ + AutoStand = i; + return AutoStand; +} + +string GetMountStyle(){ + return MountStyle; +} + +string SetMountStyle(string str){ + if(str && stringp(str)) MountStyle = str; + return MountStyle; +} + +int GetVisibleRiders(){ + return VisibleRiders; +} + +int SetVisibleRiders(int i){ + if(i) VisibleRiders = 1; + else VisibleRiders = 0; + return VisibleRiders; +} diff --git a/lib/lib/pager.c b/lib/lib/pager.c new file mode 100644 index 0000000..68ba3f4 --- /dev/null +++ b/lib/lib/pager.c @@ -0,0 +1,377 @@ +/* /lib/pager.c + * from the Dead Souls Object Library + * a system pager for interactive objects + * created by Descartes of Borg 951104 + * Version: @(#) pager.c 1.3@(#) + * Last modified: 96/10/18 + */ + +#include <function.h> +#include <message_class.h> +#include "include/pager.h" + +static private int InPager = 0; + +mixed more(mixed val, string cl, function f, mixed args){ + log_file("more", sprintf("%O", previous_object()) + "\n"); + return eventPage(val, cl, f, args); +} + +varargs mixed eventPage(mixed val, mixed msg_class, function f,mixed args...){ + mixed array files; + int maxi; + + if( InPager ) return "You are already in the pager."; + if( !stringp(val) && !arrayp(val) ) + error("Bad argument 1 to eventPage().\n"); + if(!sizeof(val)) return 0; + if( stringp(msg_class) || !msg_class ) msg_class = MSG_SYSTEM; + if( arrayp(val) ){ + mapping file = ([]); + + if( !(file["Size"] = sizeof(val)) ) return 1; + file["MessageClass"] = msg_class; + file["CurrentLine"] = 0; + file["Lines"] = val; + file["Callback"] = f; + file["Args"] = args; + file["Name"] = ""; + file["Marks"] = ([]); + file["LastSearch"] = 0; + files = ({ file }); + } + else { + string tmp; + val = wild_card(val); + if( !val || !sizeof(val) ) return "File not found."; + files = ({}); + foreach(tmp in val){ + mapping file = ([]); + string str; + + if( file_size(tmp) == -2 ){ + if( sizeof(val) == 1 ) return "That is a directory."; + else continue; + } + if(!file_exists(tmp)) continue; + str = read_file(tmp); + if( !str || !stringp(str)) continue; + file["Name"] = tmp; + file["Lines"] = explode(str, "\n"); + file["Size"] = sizeof(file["Lines"]); + file["MessageClass"] = msg_class; + file["CurrentLine"] = 0; + file["Callback"] = f; + file["Args"] = args; + file["Marks"] = ([]); + file["LastSearch"] = 0; + files += ({ file }); + } + } + if( (maxi = sizeof(files)) > 1 ){ + int i; + for(i=0; i<maxi; i++){ + mapping tmp = files[i]; + + if( i != maxi-1 ){ + files[i]["Callback"] = (: Page, files[i+1] :); + files[i]["Args"] = 0; + } + } + if(files[<1]["Args"] && files[<1]["Callback"]) + files[<1]["Args"] = ({ files[<1]["Callback"] }) + files[<1]["Args"]; + else if(files[<1]["Callback"]) files[<1]["Args"] = ({ files[<1]["Callback"] }); + files[<1]["Callback"] = (: RazzleDazzle :); + } + return Page(files[0]+([])); +} + +static int Page(mixed tmpfile){ + string page, prompt, key; + int endline, tmpcurrline, err; + mixed tmparr, tmparr2; + mapping file = ([]); + int waschar = this_object()->GetCharmode(); + foreach(mixed clef, mixed val in tmpfile){ + if(clef) file += ([ clef : val ]); + } + key = "enter"; + endline = file["CurrentLine"] + (GetScreen()[1] - 3); + if( endline < file["CurrentLine"] ) endline = file["CurrentLine"]; + if( endline > (file["Size"] - 1) ) endline = file["Size"] - 1; + tmparr = file["Lines"]; + tmpcurrline = file["CurrentLine"]; + tmparr2 = tmparr[tmpcurrline..endline]; + err = catch(page = implode(tmparr2, "\n")); + eventPrint(page, file["MessageClass"]); + if( creatorp() && file["Name"] != "" ) prompt = file["Name"] + " "; + else prompt = ""; + if( endline < file["Size"] - 1 ){ + prompt += "(" + (file["CurrentLine"]+1) + "-" + (endline+1) + " "; + prompt += ((endline * 100)/(file["Size"] - 1)) + "%) press "+key+": "; + // Following fix courtesy of Brodbane + prompt = "%^BOLD%^" + prompt + "%^RESET%^\n"; + file["CurrentLine"] = endline + 1; + eventPrint(prompt, MSG_PROMPT); + input_to((: cmdPage :), file); + } + else { + int fp; + file["CurrentLine"] = endline; + fp = functionp(file["Callback"]); + if( !fp || (fp == FP_OWNER_DESTED) ){ + this_object()->CheckCharmode(); + return 1; + } + if( file["Args"] ) evaluate(file["Callback"], file["Args"]...); + else { + evaluate(file["Callback"]); + } + } + return 1; +} + +static void cmdPage(string str, mapping file){ + string *tmp; + string cmd, args; + int fp, x, scrlen; + + if( !str || trim(str) == "" ){ + if( file["CurrentLine"] >= (file["Size"]) ){ + fp = functionp(file["Callback"]); + if( !fp || (fp == FP_OWNER_DESTED) ) return; + if( file["Args"] ) evaluate(file["Callback"], file["Args"]...); + else evaluate(file["Callback"]); + } + else Page(file); + return; + } + cmd = str[0..0]; + if( strlen(str) > 1 ) args = str[1..]; + else args = 0; + switch(cmd){ + case ",": + if( !args || !(file["Marks"][args]) ){ + receive("\a"); + input_to((: cmdPage :), file); + return; + } + else cmdPage("g" + file["Marks"][args], file); + return; + + case "/": + if( file["CurrentLine"] >= (file["Size"] - 1) ){ + eventPrint("\a" + GetPagerPrompt(file), MSG_PROMPT); + input_to((: cmdPage :), file); + return; + } + if( !args && !(file["LastSearch"]) ){ + eventPrint("\a" + GetPagerPrompt(file), MSG_PROMPT); + input_to((: cmdPage :), file); + return; + } + if( !args ) args = file["LastSearch"]; + tmp = regexp(file["Lines"][file["CurrentLine"]..], args); + if( !sizeof(tmp) ){ + eventPrint("\a" + GetPagerPrompt(file), MSG_PROMPT); + input_to((: cmdPage :), file); + return; + } + for(x = file["CurrentLine"]; x < file["Size"]; x++){ + if( tmp[0] == file["Lines"][x] ) break; + } + if( x == file["Size"] ){ + eventPrint("\a" + GetPagerPrompt(file), MSG_PROMPT); + input_to((: cmdPage :), file); + return; + } + file["CurrentLine"] = (x ? x-1 : x); + file["LastSearch"] = args; + Page(file); + return; + + case "?": + x = file["CurrentLine"] - GetScreen()[1] - 3; + if( x < 1 ){ + eventPrint("\a" + GetPagerPrompt(file), MSG_PROMPT); + input_to((: cmdPage :), file); + return; + } + if( !args && !(file["LastSearch"]) ){ + eventPrint("\a" + GetPagerPrompt(file), MSG_PROMPT); + input_to((: cmdPage :), file); + return; + } + if( !args ) args = file["LastSearch"]; + tmp = regexp(file["Lines"][0..x], args); + if( !sizeof(tmp) ){ + x = -1; + } + else { + for( ; x > -1; x--){ + if( tmp[<1] == file["Lines"][x] ) break; + } + } + if( x == -1 ){ + eventPrint("\a" + GetPagerPrompt(file), MSG_PROMPT); + input_to((: cmdPage :), file); + return; + } + file["CurrentLine"] = (x ? x - 1 : x); + if( file["CurrentLine"] < 0 ) file["CurrentLine"] = 0; + file["LastSearch"] = args; + Page(file); + return; + + case "b": + scrlen = GetScreen()[1]; + if( (file["CurrentLine"] - (2*(scrlen-3))) < 1 ){ + eventPrint("\a" + GetPagerPrompt(file), MSG_PROMPT); + input_to((: cmdPage :), file); + return; + } + else { + file["CurrentLine"] -= (2 * (scrlen-3)); + Page(file); + } + return; + + case "g": case "<": case "G": case ">": + if( cmd == "g" || cmd == "<" ) x = 1; + else { + x = (file["Size"] - (GetScreen()[1] - 3)); + if( x < 1 ) x = 1; + } + if( !args ) args = x + ""; + else if( args[0] == ' '){ + if( strlen(args) == 1 ) args = x + ""; + else args = trim(args); + } + if( ((x = to_int(args)) < 1) || (x > file["Size"]) ){ + eventPrint("\a" + GetPagerPrompt(file), MSG_PROMPT); + input_to((: cmdPage :), file); + return; + } + file["CurrentLine"] = x - 1; + Page(file); + return; + + case "h": case "H": + eventPrint(GetHelp("pager"), MSG_HELP); + eventPrint(GetPagerPrompt(file), MSG_PROMPT); + input_to((: cmdPage :), file); + return; + + case "m": + if( !args ){ + eventPrint("\a" + GetPagerPrompt(file), MSG_PROMPT); + input_to((: cmdPage :), file); + return; + } + file["Marks"][args] = file["CurrentLine"]; + eventPrint("Mark " + args + " set to line " + + (file["CurrentLine"] + 1) + ".", file["MessageClass"]); + eventPrint(GetPagerPrompt(file), MSG_PROMPT); + input_to((: cmdPage :), file); + return; + + case "n": + fp = functionp(file["Callback"]); + if( !fp || (fp == FP_OWNER_DESTED) ){ + eventPrint("\a" + GetPagerPrompt(file), MSG_PROMPT); + input_to((: cmdPage :), file); + return; + } + if( file["Args"] ) evaluate(file["Callback"], file["Args"]...); + else evaluate(file["Callback"]); + return; + + case "p": case "%": + if( args ) x = to_int(args); + if( !args || x < 1 || x > 100 ){ + eventPrint("\a" + GetPagerPrompt(file), MSG_PROMPT); + input_to((: cmdPage :), file); + return; + } + x = ((file["Size"] - 1) * x)/100 - 1; + if( x < 0 ) x = 0; + else if( x > ((file["Size"] - 1) - (GetScreen()[1] - 3)) ) + x = ((file["Size"] - 1) - (GetScreen()[1] - 3)); + file["CurrentLine"] = x; + Page(file); + return; + + case "q": + fp = functionp(file["Callback"]); + this_object()->CheckCharmode(); + if( !fp || (fp == FP_OWNER_DESTED) ) return; + if( file["Args"] ) evaluate(file["Callback"], file["Args"]...); + else evaluate(file["Callback"]); + return; + + case "v": + eventPrint("Dead Souls Pager v3.0 by Descartes of Borg 951104", + MSG_HELP); + eventPrint(GetPagerPrompt(file), MSG_PROMPT); + input_to((: cmdPage :), file); + return; + + default: + eventPrint("\a'h' for help", MSG_ERROR); + eventPrint(GetPagerPrompt(file), MSG_PROMPT); + input_to((: cmdPage :), file); + return; + } +} + +varargs static private void RazzleDazzle(mixed args...){ + function f; + InPager = 0; + if(args && sizeof(args)){ + f = args[0]; + if( !functionp(f) || functionp(f) == FP_OWNER_DESTED ) return; + if( sizeof(args) > 1 ) args = args[1..]; + else args = 0; + if( args ) evaluate(f, args...); + else evaluate(f); + } + this_object()->CheckCharmode(); +} + +static private string GetPagerPrompt(mapping file){ + int x; + + if( creatorp() && file["Name"] != "" ) + return "%^BOLD%^" + file["Name"] + ":%^RESET%^ "; + if( file["CurrentLine"] >= (file["Size"] - 1) ) return "END: "; + x = ((100 * file["CurrentLine"])/(file["Size"] - 1)); + if( x < 0 ) x = 0; + if( x > 100 ) x = 100; + return "%^BOLD%^" + x + "%:%^RESET%^ "; +} + +string GetHelp(string str){ + if( str != "pager" ) return 0; + return ("/<pattern>, ?<pattern>\n" + "The pattern is optional. / searches forward for a pattern. " + "If no pattern is specified, the last search pattern is " + "repeated. ? does the same, except searching backwards.\n" + "b\n" + "Move back one page.\n" + "<return>\n" + "Move ahead one page.\n" + "n\n" + "Move to the next file in the group of files being paged.\n" + "m<tag>\n" + "Mark the current line and asociate it with tag. You can mark " + "any number of lines.\n" + ",<tag>\n" + "Move to the named tag.\n" + "g<line>, G<line>\n" + "Go to the named line. If no line is named, 'g' goes to the " + "beginning of the file. In contras, 'G' will go to the end.\n" + "p<percent>\n" + "Move to the line <percent> lines into the file.\n" + "q\n" + "Quit out of the pager."); +} diff --git a/lib/lib/persist.c b/lib/lib/persist.c new file mode 100644 index 0000000..9243c3c --- /dev/null +++ b/lib/lib/persist.c @@ -0,0 +1,146 @@ +/* /lib/persist.c + * from the Dead Souls Object Library + * provides object persistance + * created by Beek@Dead Souls 950528 + */ + +#include "include/persist.h" + +private int SaveRecurse; +private static int Retain = RETAIN_ON_QUIT; + +private mixed *Saved = ({ "Properties" }); + +string GetShort(); + +static int eventConvertObject(mixed val, int recurse){ + string *flat = ({}); + mixed *tmp, *saved = this_object()->GetSave(); + + if( val[0] != base_name(this_object()) ) error("Invalid save string.\n"); + tmp = map(saved, (: functionp($1) ? evaluate($1, "loading") : $1 :)); + foreach(mixed elem in tmp){ + if( arrayp(elem) ) flat += elem; + else flat += ({ elem }); + } + flat -= ({ 0 }); + if( sizeof(flat) != sizeof(val[1]) ) error("Invalid save string size.\n"); + for(int i = 0; i < sizeof(flat); i++ ) store_variable(flat[i], val[1][i]); + if( sizeof(val) == 3 ){ + foreach(string obdata in val[2]){ + object ob; + val = restore_variable(obdata); + ob = new(val[0]); + ob->eventLoadObject(val, 1); + } + } + if( recurse ) eventMove(previous_object()); + return 1; +} + +int eventLoadObject(mixed val, int recurse){ + mixed *tmp, *saved = this_object()->GetSave(); + string *flat = ({}); + mixed data; + + data = val; + /* This converst NM IV - IVr2.2 data into NM data */ + if( arrayp(data) ) return eventConvertObject(data, recurse); + if( data["#base_name#"] != base_name(this_object()) ) + error("Invalid save string.\n"); + tmp = map(saved, (: functionp($1) ? evaluate($1, "loading") : $1 :)); + foreach(mixed elem in tmp){ + if( arrayp(elem) ) flat += elem; + else flat += ({ elem }); + } + flat -= ({ 0 }); + foreach(string var, val in data){ + if( var[0] == '#' ) continue; + catch(store_variable(var, val)); + } + if( data["#inventory#"] ){ + foreach(mixed obdata in data["#inventory#"]){ + object ob; + + val = restore_variable(obdata); + if( arrayp(val) ){ + catch(ob = new(val[0])); + } + else { + catch(ob = new(val["#base_name#"])); + } + if( ob ){ + ob->eventLoadObject(val, 1); + } + } + } + if( recurse ){ + object prev = previous_object(); + + if( !eventMove(prev) ){ + call_out(function(object p){ + object env; + if(p && objectp(p)) env = environment(p); + else return; + + if( !env ){ + p->eventPrint("You lose " + GetShort() + "."); + } + else { + p->eventPrint("You drop " + GetShort() + "."); + eventMove(env); + } + }, 1, prev); + } + } +} + +mixed *GetSave(){ + return copy(Saved); +} +mixed *cGetSave(){ return copy(Saved); } +mixed *dGetSave(){ return Saved; } + +static mixed *AddSave(mixed *vars){ + mixed *tmp = Saved + vars; + Saved = tmp; + return copy(Saved); +} + +static int SetSaveRecurse(int flag){ return (SaveRecurse = flag); } + +string GetSaveString(){ + mixed *tmp, *saved = this_object()->GetSave(); + string *vv = variables(this_object()); + string *flat = ({}); + mapping mp = ([]); + + tmp = map(saved, (: functionp($1) ? evaluate($1, "saving") : $1 :)); + foreach(mixed elem in tmp){ + if( arrayp(elem) ) flat += elem; + else flat += ({ elem }); + } + if(flat && sizeof(flat)){ + flat -= ({ 0 }); + foreach(mixed var in flat){ + if(stringp(var)){ + if(member_array(var, vv) == -1) continue; + mp[var] = fetch_variable(var); + } + } + } + mp["#base_name#"] = base_name(this_object()); + if( SaveRecurse ) + mp["#inventory#"] = all_inventory()->GetSaveString() - ({ 0 }); + return save_variable(mp); +} + +int SetRetain(int i){ + if(i) Retain = 1; + else Retain = 0; + return Retain; +} + +int GetRetain(){ + return Retain; +} diff --git a/lib/lib/pile.c b/lib/lib/pile.c new file mode 100644 index 0000000..dac9694 --- /dev/null +++ b/lib/lib/pile.c @@ -0,0 +1,144 @@ +/* /lib/pile.c + * from the Dead Souls Object Library + * basically a pile of precious coinses + * created by Descartes of Borg 951029 + * Version: @(#) pile.c 1.2@(#) + * Last modified: 96/11/12 + */ + +#include <lib.h> + +inherit LIB_ITEM; + +string PileType = 0; +int PileAmount = 0; + +static void create(){ + string *saveds; + item::create(); + SetNoCondition(1); + saveds = item::GetSave(); + saveds += ({ "PileType", "PileAmount" }); + AddSave( saveds ); + SetKeyName("pile"); +} + +string array GetId(){ + string array id; + string tender = "coins"; + if(PileType == "dollars") tender = "bills"; + + id = item::GetId(); + if( PileType ){ + id += ({ PileType, PileAmount + " " + PileType, "pile of "+PileType }); + } + return ({ id..., tender, "money", "pile", "pile of "+ PileAmount + " " + PileType }); +} + +int GetMass(){ + return currency_mass(PileAmount, PileType); +} + +void SetPile(string str, int amt){ + PileType = str; + PileAmount = amt; + if(!PileAmount || PileAmount < 1 ){ + SetLong("a pile of money"); + call_out( (: eventDestruct :), 1); + } + else SetLong("It is a pile of " + PileAmount + " " + PileType + "."); + parse_refresh(); +} + +void SetCurrency(string str, int amt){ + SetPile(str, amt); +} + +string GetPileType(){ return PileType; } + +int GetPileAmount(){ return PileAmount; } + +string GetShort(){ + string str = item::GetShort(); + + if(!PileAmount || PileAmount < 1 ){ + call_out( (: eventDestruct :), 1); + return "a pile of money"; + } + if( str ){ + return str; + } + else { + return "a pile of " + PileAmount + " " + PileType; + } +} + +mixed eventGetMoney(object who, int amount, string curr){ + if( who->AddCurrency(curr, amount) == -1 ){ + who->eventPrint("You had a problem getting the money."); + return 1; + } + send_messages("get", "$agent_name $agent_verb " + amount + " " + + curr + " from " + GetShort() + ".", who, 0, environment(who)); + PileAmount -= amount; + if( PileAmount < 1 ){ + call_out((: Destruct :), 0); + return 1; + } + SetPile(PileType, PileAmount); /* This refreshes the parser */ + return 1; +} + +int eventMove(mixed dest){ + int x; + + x = item::eventMove(dest); + if( environment() && !living(environment()) ){ + return x; + } + + if(environment() && living(environment())){ + environment()->AddCurrency(PileType, PileAmount); + environment()->AddCarriedMass(-this_object()->GetMass()); + SetShort("a pile of " + PileAmount + " " + PileType); + PileAmount = 0; + call_out((: Destruct :), 0); + return x; + } +} + +mixed direct_get_wrd_wrd_out_of_obj(string num, string curr){ + int amt; + + if( environment() != environment(this_player()) ){ + return "#You cannot reach the pile!"; + } + if( num[0] < '0' || num[0] > '9' ){ + return 0; + } + if( (amt = to_int(num)) < 1 ){ + return "That's a totally bogus amount."; + } + if( curr != PileType ){ + return "#The pile has no " + curr + " in it, only " + PileType + "."; + } + if( amt > PileAmount ){ + return "#There is not that much in the pile."; + } + if( !this_player()->CanCarry(currency_mass(amt, curr)) ){ + return "It is too heavy for you!"; + } + return 1; +} + +mixed direct_get_wrd_wrd_from_obj(string amt, string curr){ + return direct_get_wrd_wrd_out_of_obj(amt, curr); +} + +void init(){ + ::init(); + if(!PileAmount || PileAmount < 1 ){ + SetLong("some money"); + call_out( (: eventDestruct :), 1); + } +} diff --git a/lib/lib/pipe.c b/lib/lib/pipe.c new file mode 100644 index 0000000..97e0a1f --- /dev/null +++ b/lib/lib/pipe.c @@ -0,0 +1,88 @@ +#include <lib.h> + +inherit LIB_ITEM; +inherit LIB_SMOKE; +inherit LIB_BURN; + +private int BurnRate = 5; +int lastpuff; + +static void create(){ + item::create(); + burn::create(); +} + +static void heart_beat(){ + eventDecreaseFuel(1); + if( GetFuelAmount() < 1){ + eventBurnOut(); + } +} + +mixed direct_light_obj(){ + mixed tmp = CanBurn(this_player()); + + if( tmp == 1 ){ + return "Light it with what?"; + } + + if( GetFuelAmount() < 1 ) + return "There is no " + GetFuelType() + " in " + GetShort() + "."; + return 1; +} + +mixed eventDarken(){ + burn::eventDarken(); + set_heart_beat(0); + return 1; +} + +varargs mixed eventLight(object who, object tool){ + if( GetLit() ) return burn::eventLight(who, tool); + burn::eventLight(who, tool); + set_heart_beat(BurnRate); + return 1; +} + +int GetBurnRate(){ + return BurnRate; +} + +static int SetBurnRate(int x){ + return (BurnRate = x); +} + +int GetRadiantLight(int ambient){ + if( !GetLit() ) return 0; + else return item::GetRadiantLight(ambient); +} + +string GetShort(){ + return item::GetShort() + burn::GetShort(); +} + +varargs string GetLong(string unused){ + string tmp; + + tmp = burn::GetLong(unused); + if( tmp != "" ) return item::GetLong(unused) + "\n" + tmp; + else return item::GetLong(unused); +} + +int GetLastPuff(){ + return lastpuff; +} + +mixed eventSmoke(object who, object what){ + if(!GetLit()){ + write("It is not lit!"); + return 1; + } + write("You smoke your "+remove_article(GetShort())+"."); + say(who->GetName()+" smokes from "+possessive(who)+" " + +remove_article(GetShort())+"."); + lastpuff = time(); + eventDecreaseFuel(1); + if( !GetFuelAmount() ) eventBurnOut(); + return 1; +} diff --git a/lib/lib/pistol.c b/lib/lib/pistol.c new file mode 100644 index 0000000..26e5472 --- /dev/null +++ b/lib/lib/pistol.c @@ -0,0 +1,11 @@ +#include "include/pistol.h" +#include <lib.h> +inherit LIB_FIREARM; + +static void create(){ + ::create(); +} + +void init(){ + ::init(); +} diff --git a/lib/lib/player.c b/lib/lib/player.c new file mode 100644 index 0000000..7a7d3c0 --- /dev/null +++ b/lib/lib/player.c @@ -0,0 +1,677 @@ +/* /lib/player.c + * from the Dead Souls LPC Library + * the player object + * created by Descartes of Borg 950321 + * Version: @(#) player.c 1.26@(#) + * Last Modified: 97/01/03 + */ + +#include <lib.h> +#include ROOMS_H +#include <damage_types.h> +#include <message_class.h> +#include <daemons.h> +#include <vision.h> +#include <position.h> +#include "include/player.h" + +#undef LIB_PLAYER_SKILL_LOSS +#define PERCENT_XP 0.02 +#define PERCENT_SP 0.70 +#define PERCENT_MP 0.95 +#define PERCENT_HP 0.70 + +inherit LIB_INTERACTIVE; +inherit LIB_LIVING; + +private string *Titles; +string *Muffed = ({}); +private mapping *Deaths; +private int TrainingPoints, TitleLength; +private static int heartcount; +private mixed telopt_ip; + +/* ***************** /lib/player.c driver applies ***************** */ + +static void create(){ + interactive::create(); + living::create(); + + Titles = ({}); + TitleLength = 1; +} + +static void heart_beat(){ + mixed heartping; + int idle; + + if(!interactive(this_object())) return; + + heartping = GetProperty("keepalive"); + idle = query_idle(this_object()); + heartcount++; + + if(GetProperty("reply")){ + int t = GetProperty("reply_time"); + if(t > 1 && (time() - t) > 90000){ + RemoveProperty("reply"); + RemoveProperty("reply_time"); + } + } + interactive::heart_beat(); + living::heart_beat(); + + if( IDLE_TIMEOUT && idle >= IDLE_TIMEOUT + && !builderp(this_object()) + && !present("testchar badge",this_object()) + && !present("idler_amulet",this_object()) + && !testp(this_object()) ){ + cmdQuit(); + return; + } +#ifdef __DSLIB__ + if(heartping){ + send_nullbyte(this_object()); + } +#endif +} + +static void net_dead(){ + interactive::net_dead(); + set_heart_beat(0); +} + +static int Destruct(){ + CHARACTER_D->eventSaveTime(); + living::Destruct(); + return interactive::Destruct(); +} + +mixed eventAsk(object who, string what){ + if( what != "convert me" ) return 0; + if( !GetReligion(1) ) return 0; + who->SetProperty("converting", GetReligion(1)); + return 1; +} + +void eventKillEnemy(object ob){ + living::eventKillEnemy(ob); + STATISTICS_D->eventKill(ob); +} + +void eventReconnect(){ + interactive::eventReconnect(); + living::eventReconnect(); + set_heart_beat(GetHeartRate()); +} + +/************** player.c command functions *************/ +varargs int eventShow(object who, string str){ + if( !living::eventShow(who, str) ) return 0; + if( this_player() != this_object() ) + eventPrint(this_player()->GetName() + " looks you over."); + return 1; +} + +/* ***************** /lib/player.c events *************** */ + +varargs mixed eventDisplayStatus(int simple){ + string str; + int qp, xp, hp, mp, sp, max_hp, max_mp, max_sp; + + hp = GetHealthPoints(); + max_hp = GetMaxHealthPoints(); + mp = GetMagicPoints(); + max_mp = GetMaxMagicPoints(); + sp = GetStaminaPoints(); + max_sp = GetMaxStaminaPoints(); + xp = GetExperiencePoints(); + qp = GetQuestPoints(); + + if( percent(hp, max_hp) < 20.0 ) + str = "%^YELLOW%^hp: %^RED%^" + hp + "%^RESET%^/" + max_hp; + else str = "%^YELLOW%^hp: %^RESET%^" + hp + "/" + max_hp; + if( percent(mp, max_mp) < 20.0 ) + str += " %^BLUE%^mp: %^RED%^" + mp + "%^RESET%^/" + max_mp; + else str += " %^BLUE%^mp: %^RESET%^" + mp + "/" + max_mp; + if( percent(sp, max_sp) < 20.0 ) + str += " %^GREEN%^sp: %^RED%^" + sp + "%^RESET%^/" + max_sp; + else str += " %^GREEN%^sp: %^RESET%^" + sp + "/" + max_sp; + if(!simple){ + str += " %^MAGENTA%^xp: %^RESET%^" + xp; + str += " %^CYAN%^qp: %^RESET%^" + qp; + } + if(!simple){ + message("status", str, this_object()); + return 1; + } + return str; +} + +static void eventDestroyUndead(object agent){ +} + +varargs int eventDie(mixed agent){ + int x; + string agentname; + + this_object()->SetDying(0); + + if(!agent) agent = previous_object(); + if(!agent) agent = this_object(); + if(stringp(agent)) agentname = agent; + else agentname = agent->GetName(); + + if( (x = living::eventDie(agent)) != 1 ){ + return x; + } + if(!Deaths || !sizeof(Deaths)) + Deaths = ({([ "date" : ctime(time()), "enemy" : agentname ])}); + else Deaths += ({ ([ "date" : ctime(time()), "enemy" : agentname ]) }); + + if( !GetUndead() ){ + eventDestroyUndead(agent); + } + else { + message("my_action", "Consciousness passes from you after one last " + "gasp for air.", this_object()); + message("my_action", "You awake, but you find your body feels " + "different, and the world about you is unfamiliar.", + this_object()); + if( agent ){ + message("other_action", GetName() + " is killed by " + + agentname + ".", + environment(this_object()), ({ agent, this_object() })); + message("other_action", "You send " + GetName() + " into the " + "Underworld.", agent); + } + else message("other_action", GetName() + " dies.", + environment(), ({ this_object() }) ); + + NewBody(GetRace()); + + eventCompleteHeal(GetMaxHealthPoints()/2); + AddMagicPoints(-(random(GetMagicPoints()))); + this_object()->eventMove(ROOM_DEATH); + this_object()->save_player(this_object()->GetKeyName()); + this_object()->eventDescribeEnvironment(); + } + flush_messages(); + return 1; +} + +mixed eventTurn(object who){ + if( !living::eventTurn(who) ){ + return 0; + } + eventDestroyUndead(who); + return 1; +} + +varargs void eventRevive(int nopenalty){ + string skill; + + this_object()->SetDead(0); + if(!creatorp(this_object())) this_object()->SetInvis(0); + this_object()->SetDeathEvents(0); + + if( !GetUndead() ) return; + SetUndead(0); + if(this_player()->GetPoison() > 0){ + this_player()->AddPoison(0 - this_player()->GetPoison()); + } + if(!nopenalty && newbiep(this_object())) { + nopenalty = 1; + write("As a newbie you don't incur an experience penalty" + " for this death.\n"); + } + if(!nopenalty){ + int expee, subexpee; +#ifdef LIB_PLAYER_SKILL_LOSS + foreach(skill in GetSkills()){ + int x; + + if( !random(4) ){ + continue; + } + if( newbiep(this_object()) ){ + x = 2; + } + else { + x = 10; + } + x = random(x - (2*GetSkillClass(skill)))/2; + if( x > 0 ){ + while( x-- ){ + AddSkillPoints(skill, + -GetMaxSkillPoints(skill, + GetBaseSkillLevel(skill))); + } + } + } +#endif + expee = this_object()->GetExperiencePoints(); + subexpee = to_int(expee * PERCENT_XP); + this_object()->AddExperienceDebt(subexpee); + } + NewBody(GetRace()); + eventCompleteHeal(GetMaxHealthPoints()); + SetSpecialTarget( ({}) ); + AddMagicPoints(-(GetMaxMagicPoints() * PERCENT_MP)); + AddStaminaPoints(-(GetMaxStaminaPoints() * PERCENT_SP)); + AddHealthPoints(-(GetMaxHealthPoints() * PERCENT_HP)); + if(this_object()->GetLead()){ + int shots = this_object()->GetLead("gunshot_wounds"); + if(shots) this_object()->AddLead("gunshot_wounds", -shots); + shots = this_object()->GetLead("rifleshot_wounds"); + if(shots) this_object()->AddLead("rifleshot_wounds", -shots); + } + if(creatorp()){ + string livingtitle = this_object()->GetLivingShort(); + if(!livingtitle) livingtitle = "$N the reborn"; + interactive::SetShort(livingtitle); + } +} + +int eventMove(mixed dest){ + int ret; + object env = environment(); + string location; + + if(!env) location = ROOM_START; + else if(clonep(env)) location = file_name(env); + else location = base_name(env); + + if(location) this_object()->SetProperty("LastLocation", location); + + ret = interactive::eventMove(dest); + if( this_object() && environment(this_object())) eventMoveFollowers(environment(this_object())); + return ret; +} + +int eventReleaseObject(object foo){ + object ob; + + ob = previous_object(); + if( !ob || !interactive::eventReleaseObject() ) return 0; + if( ob->GetMass() ){ + AddCarriedMass( -(ob->GetMass()) ); + if(environment()) environment()->AddCarriedMass(-(ob->GetMass())); + } + return 1; +} + +void eventLoadObject(mixed *value, int recurse){ } + +/* ***************** /lib/player.c modal functions ***************** */ + +int CanReceive(object ob){ return CanCarry(ob->GetMass()); } + +mixed CanUse(){ return 1; } + +/* ***************** /lib/player.c local functions ***************** */ + +int Setup(){ + string classes; + string oldparties = PARTY_D->GetOldParties(); + if( !interactive::Setup() ) return 0; + if( !GetClass() ) SetClass("explorer"); + RemoveExtraChannels(oldparties); + foreach(string oldparty in oldparties){ + RemoveChannel(oldparty); + } + RemoveExtraChannels(oldparties); + if( GetClass() ){ + foreach(classes in CLASSES_D->GetClasses()) + if( ClassMember(classes) && classes != GetClass() ) + AddChannel(classes); + } + if(sizeof(GetExtraChannels())) AddChannel(GetExtraChannels()); + set_heart_beat(GetHeartRate()); + if(builderp()){ + AddChannel( ({ "builder" }) ); + AddSearchPath( ({ DIR_BUILDER_CMDS, DIR_SECURE_BUILDER_CMDS }) ); + } + PLAYERS_D->CheckBuilder(this_object()); + + if(GetProperty("brand_spanking_new")){ + object jeans, shirt, book; + if(!(this_object()->GetProperty("screen reader"))){ + this_object()->SetProperty("minimapping", 1); + } + else this_object()->SetProperty("minimapping", 0); + if(ENGLISH_ONLY) this_object()->SetNativeLanguage("English"); + PLAYERS_D->AddPlayerInfo(this_object()); + + foreach(classes in CLASSES_D->GetClasses()) + if( ClassMember(classes) && classes != GetClass() ) + AddChannel(classes); + if( avatarp() ) AddChannel(({ "avatar" })); + AddChannel( ({ "gossip", "newbie" }) ); + if( high_mortalp() ) AddChannel( ({ "hm" }) ); + else { + //RemoveChannel( ({ "newbie" }) ); + } + AddChannel( ({ "gossip" }) ); + if( councilp() ) AddChannel( ({ "council" }) ); + AddChannel(GetClass()); + + jeans = new("/domains/default/armor/jeans"); + shirt = new("/domains/default/armor/shirt"); + book = new("/domains/default/obj/handbook"); + + if(jeans) jeans->eventMove(this_object()); + if(shirt) shirt->eventMove(this_object()); + if(book && !present("handbook",this_object())) + book->eventMove(this_object()); + else if(book) book->eventMove(ROOM_FURNACE); + + if(jeans) this_object()->eventForce("wear jeans"); + if(shirt) this_object()->eventForce("wear shirt"); + SetProperty("brand_spanking_new",0); + } + + if(this_object()->GetTown() == "FirstAdmin"){ + object robe, hat, staff, book, book2; + string home; + + this_object()->SetTown("World"); + this_object()->SetProperty("minimapping", 0); + if(!(this_object()->GetProperty("screen reader"))){ + this_object()->SetProperty("wizmapping", 1); + } + else this_object()->SetProperty("wizmapping", 0); + robe = new("/domains/default/armor/robe"); + hat = new("/domains/default/armor/wizard_hat"); + staff = new("/secure/obj/staff"); + book = new("/domains/default/obj/guide"); + book2 = new("/domains/default/obj/handbook"); + + if(robe) robe->eventMove(this_object()); + if(hat) hat->eventMove(this_object()); + if(staff) staff->eventMove(this_object()); + if(book) book->eventMove(this_object()); + if(book2) book2->eventMove(this_object()); + + if(robe) this_object()->eventForce("wear robe"); + if(hat) this_object()->eventForce("wear hat"); + + home = "/realms/"+this_player()->GetKeyName()+"/workroom"; + + if(file_exists(home+".c")) + this_object()->eventMoveLiving(home); + + this_object()->AddChannel( ({"admin", "error", "cre", "newbie", "gossip", "ds", "ds_test", "lpuni", "death", "connections","intercre","dchat"}) ); + + SetShort("First Admin $N"); + } + if(!creatorp(this_object())) this_object()->SetInvis(0); + RemoveProperty("reply"); + RemoveProperty("reply_time"); + return 1; +} + +/* ***************** /lib/player.c data functions ***************** */ + +int AddCurrency(string type, int amount){ + if( currency_value(amount, type) > 999 ) + log_file("currency", GetCapName() + " received "+amount+" "+type+ + " "+ctime(time())+"\n"+identify(previous_object(-1))+"\n"); + return living::AddCurrency(type, amount); +} + +int AddBank(string bank, string type, int amount){ + if( currency_value(amount, type) > 999 ) + log_file("bank", GetCapName() + " deposited "+amount+" "+type+ + " "+ctime(time())+" into bank: "+bank+"\n" + + identify(previous_object(-1))+"\n"); + return living::AddBank(bank, type, amount); +} + +string *GetMuffed(){ + return Muffed; +} + +string *SetMuffed(string *muffed){ + if(sizeof(muffed)) Muffed = muffed; + else Muffed = ({}); + return Muffed; +} + +string *AddMuffed(string muffed){ + string tmpstr; + if(!muffed || muffed == "" || !sizeof(muffed)) return Muffed; + if(muffed[0..0] == "@"){ + tmpstr = INTERMUD_D->GetMudName(muffed[1..]); + } + if(sizeof(tmpstr)) muffed = tmpstr; + muffed = lower_case(muffed); + if(member_array(muffed,Muffed) == -1) Muffed += ({ muffed }); + return Muffed; +} + +string *RemoveMuffed(string unmuffed){ + string tmpstr; + if(!sizeof(unmuffed)) return Muffed; + if(grepp(unmuffed,"@")){ + tmpstr = INTERMUD_D->GetMudName(unmuffed[1..sizeof(unmuffed)-1]); + } + if(sizeof(tmpstr)) unmuffed = tmpstr; + unmuffed = lower_case(unmuffed); + if(member_array(unmuffed,Muffed) != -1) Muffed -= ({ unmuffed }); + return Muffed; +} + +string *SetTitles(string *titles){ + if( sizeof(distinct_array(titles)) != sizeof(titles) ) return Titles; + Titles = titles; + SetShort("whatever"); +} + +string *AddTitle(mixed title){ + if(arrayp(title)){ + if(this_object()->GetGender() == "female") title = title[1]; + else title = title[0]; + } + if( !stringp(title) ) return Titles; + else if( member_array(title, Titles) != -1 ) return Titles; + else { + Titles = ({ title }) + Titles; + SetShort("whatever"); + return Titles; + } +} + +string *RemoveTitle(mixed title){ + if( stringp(title) ) title = ({ title }); + foreach(string sub in title){ + Titles -= ({ sub }); + SetShort("whatever"); + } + return Titles; +} + +string *GetTitles(){ return Titles; } +int SetTitleLength(int x){ + if( x > 2 ) x = 2; + return (TitleLength = x); +} + +int GetTitleLength(){ return TitleLength; } + +string SetShort(string irrelevant){ + string title, tmp; + int i; + + if( high_mortalp() ) title = "High mortal "; + else title = ""; + if(title && title != "") title += " $N "; + else title = "$N "; + if( GetUndead() && (tmp = GetUndeadType()) ) + return interactive::SetShort(title + "the " + tmp); + if( avatarp() || creatorp() ){ + return interactive::SetShort(irrelevant); + } + if( !(i = sizeof(Titles)) ) + return interactive::SetShort(title + "the unaccomplished"); + else title += Titles[0]; + if( i > 1 && TitleLength > 1 ) title += " and " + Titles[1]; + return interactive::SetShort(title); +} + +string GetPlainShort(){ + return interactive::GetShort(); +} + +int SetUndead(int x){ + x = living::SetUndead(x); + SetShort("nonsense"); + return x; +} + +string GetName(){ + if(GetInvis() && (!this_player() ||!this_player()->GetWizVision())){ + return "A shadow"; + } + else return interactive::GetName(); +} + +varargs string GetLong(string str){ + mapping counts; + string item; + string *affects = ({}); + + str = this_object()->GetShort() + "\n"; + str += interactive::GetLong() + "\n"; + str += living::GetLong(nominative(this_object())); + foreach(item in map(all_inventory(), + (: $1->GetAffectLong(this_object()) :))){ + if(item && member_array(item,affects) == -1) affects += ({ item }); + } + if(sizeof(affects)) str += implode(affects,"\n")+"\n"; + if(this_object()->GetAffectLong()) str += this_object()->GetAffectLong(); + counts = ([]); + foreach(item in map( + filter(all_inventory(), (: !($1->GetInvis(this_object())) :)), + (: $1->GetEquippedShort() :))) + if( item ) counts[item]++; + if( sizeof(counts) ) str += GetCapName() + " is carrying:\n"; + foreach(item in keys(counts)) + str += capitalize(consolidate(counts[item], item)) + "\n"; + return str; +} + +string GetCapName(){ return interactive::GetCapName(); } + +int ResetLevel(){ + int x, y; + + x = GetLevel(); + if( x != (y = living::ResetLevel()) ){ + string file; + + if( x > y ) file = "decline"; + else file = "advance"; + log_file(file, GetCapName() + " went from level " + x + " to " + "level " + y + " (" + ctime(time()) + ")\n"); + if( x < y ){ + eventPrint("%^YELLOW%^You are now a more experienced " + + GetClass() + "."); + TrainingPoints += ( (y-x) * 4 ); + } + else TrainingPoints -= ( (x-y) * 4 ); + SetShort("whatever"); + if( x > 49 && y < 50 ) RemoveChannel("avatar"); + if( x > 24 && y < 25 ) RemoveChannel("hm"); + } + return y; +} + +string SetClass(string str){ + if( GetClass() != living::SetClass(str) ){ + int points = TrainingPoints; + string classes; + + ResetLevel(); + TrainingPoints = points; /* leave points alone */ + AddChannel(GetClass()); + foreach(classes in CLASSES_D->GetClasses()) + if( ClassMember(classes) && classes != GetClass() ) + AddChannel(classes); + } + return GetClass(); +} + +varargs mixed GetEffectiveVision(mixed location, int raw_score){ + if( newbiep(this_object()) ) return VISION_CLEAR; + else if(raw_score && location) return living::GetEffectiveVision(location,raw_score); + else if(location) return living::GetEffectiveVision(location); + else return living::GetEffectiveVision(); +} + +varargs static int AddHealthPoints(int x, string limb, object agent){ + int hp, ret, undead; + hp = GetHealthPoints(); + undead = GetUndead(); + ret = living::AddHealthPoints(x, limb, agent); + if( hp <= (hp = GetHealthPoints()) || undead != GetUndead() ) return ret; + eventDisplayStatus(); + return ret; +} + +int GetLanguageLevel(string lang){ + if( newbiep() ) return 100; + else return living::GetLanguageLevel(lang); +} + +mapping *GetDeaths(){ + if( !Deaths ) return ({}); + return copy(Deaths); +} + +int AddTrainingPoints(int x){ + log_file("TrainingPoints", GetName() + " received " + x + " training " + "points at " + ctime(time()) + "\ncall chain: " + + sprintf("%O\n", previous_object(-1)) ); + return (TrainingPoints += x); +} + +int RemoveTrainingPoints(int x){ + return (TrainingPoints -= x); +} + +int GetTrainingPoints(){ return TrainingPoints; } + +varargs int eventTrain(string skill, int points){ + float x = 0; + mapping mp; + + if( points < 1 ) points = 1; + if( !(mp = GetSkill(skill)) ) return 0; + if( TrainingPoints < points ) return 0; + while( points-- ){ + int max = GetMaxSkillPoints(skill, mp["level"]); + switch( mp["class"] ){ + case 1: x = 50.0; break; + case 2: x = 40.0; break; + case 3: x = 30.0; break; + case 4: x = 20.0; break; + default: return 0; + } + TrainingPoints--; + AddSkillPoints(skill, to_int( (max * x) / 100 )); + } + return 1; +} + +mixed GetTeloptIp(){ + if(previous_object() && base_name(previous_object()) != SEFUN && + !(archp(this_player())) && previous_object() != this_object()) return 0; + return telopt_ip; +} + +mixed SetTeloptIp(mixed str){ + if(base_name(previous_object()) != LIB_CONNECT && + !(archp(this_player()))) return 0; + return telopt_ip = str; +} diff --git a/lib/lib/poison.c b/lib/lib/poison.c new file mode 100644 index 0000000..942e5cb --- /dev/null +++ b/lib/lib/poison.c @@ -0,0 +1,49 @@ +/* /lib/poison.c + * from the Dead Souls Library + * Poisoning functions to be inherited *with* other objects that + * are meant to poison things. + * created by Blitz@Dead Souls 951120 + */ + +#include "include/poison.h" + +private int PoisonUses, PoisonStrength; + +static void create(){ + PoisonStrength = 0; + PoisonUses = 0; + this_object()->AddSave( ({ "PoisonUses" }) ); +} + +mixed indirect_poison_obj_with_obj(){ + if( environment() != this_player() ) return 0; + if( PoisonStrength < 1 ) return "The poison is all used up."; + return 1; +} + +mixed eventSpreadPoison(object who, object target){ + if( !who || !target || !PoisonUses ) return 0; + PoisonUses--; + if( random(50) > who->GetStatLevel("coordination") ){ + this_player()->eventPrint("You fumble around with the poison, " + "spilling it on yourself."); + environment(this_player())->eventPrint(who->GetName() + + " fumbles around with some " + "poison, spilling it on " + + reflexive(who) + ".", + this_player()); + who->AddPoison(random(10)); + return 1; + } + target->eventPoison(who, this_object(), PoisonStrength); + return 1; +} + +int SetPoisonStrength(int x){ return (PoisonStrength = x); } + +mixed GetPoisonStrength(){ return PoisonStrength; } + +int SetPoisonUses(int x){ return (PoisonUses = x); } + +int GetPoisonUses(){ return PoisonUses; } + diff --git a/lib/lib/pole.c b/lib/lib/pole.c new file mode 100644 index 0000000..68a4277 --- /dev/null +++ b/lib/lib/pole.c @@ -0,0 +1,96 @@ +/* /lib/pole.c + * from the Dead Souls Object Library + * inheritable fishing functions, must also inherit item along the way + * created by Descartes of Borg 951009 + */ + +#include <lib.h> +#include "include/pole.h" + +inherit LIB_BAIT; + +static private int PoleStrength, CatchChance; + +static void create(){ + string *bait_save = bait::GetSave(); + PoleStrength = 0; + CatchChance = 0; + AddSave( ({ "PoleStrength", "CatchChance" }) + bait_save ); +} + +mixed direct_cast_obj(){ + if( environment() != this_player() ) + return "#You must have it to cast it."; + return 1; +} + +mixed direct_fish_with_obj(){ + mixed err; + + if( environment() != this_player() ) + return "#You must have it to fish with it!"; + if( (err = CanCast(this_player())) != 1 ) return err; + return 1; +} + +int eventBreak(){ + SetBroken(1); + return 1; +} + +mixed CanCast(object who){ + if( GetBroken() ) + return "You cannot cast a broken " + strip_article(GetShort()) + "!"; + else return 1; +} + +mixed eventCatch(object who, string fish){ + int mass; + + SetBait(0); + mass = fish->GetMass(); + if( mass > PoleStrength && eventBreak() ){ + message("my_action", "Just as you notice " + fish->GetShort() + + " on " + GetShort() + ", it breaks " + "and you lose your catch!", who); + message("my_action", possessive_noun(who) + " " + + strip_article(GetShort()) + " breaks as " + + nominative(who) + " tries to land " + fish->GetShort()+ + "!", environment(who), ({ who })); + return 0; + } + PoleStrength -= (mass/10) + 1; + if( PoleStrength < 1 ) PoleStrength = 0; + if( !(fish->eventCatch(who, this_object()))) return 0; + if( !(who->CanCarry(mass)) ){ + message("my_action", "For a fleeting moment, you notice " + + fish->GetShort() + " on your " + + strip_article(GetShort()) + ", but then it is lost.", + who); + message("other_action", who->GetName() + " loses a catch.", + environment(who), ({ who })); + return 0; + } + return 1; +} + +int eventFish(object who){ + if( who->GetSkillLevel("fishing") >= random(5) ) + return GetChance() + GetBait(); + else return 0; +} + + +int SetChance(int x){ return (CatchChance =x); } + +mixed GetProperty(string foo); + +int GetChance(){ return CatchChance + GetProperty("blessed"); } + +int SetStrength(int x){ return (PoleStrength = x); } + +int GetStrength(){ return PoleStrength; } + +/* virtual functions */ + +mixed AddSave(mixed *vars){ return ({}); } diff --git a/lib/lib/post_office.c b/lib/lib/post_office.c new file mode 100644 index 0000000..5da0be0 --- /dev/null +++ b/lib/lib/post_office.c @@ -0,0 +1,54 @@ +/* /lib/post_office.c + * from the Dead Souls Object Library + * an inheritable post office + * created by Descartes of Borg 951007 + */ + + +#include <lib.h> +#include <objects.h> +#include <post.h> +#include "include/post_office.h" + +inherit LIB_ROOM; + +static void create(){ + room::create(); +} + +mixed CanMail(object who, string args){ + if( !interactive(who) ) return 0; + if( GetTown() != who->GetTown() ) + return "Any mail you might have will be at your home post office."; + return 1; +} + +mixed eventMail(object who, string args){ + object ob; + + if( !(ob = new(OBJ_POST)) ){ + who->eventPrint("Failed to load postal object!"); + return 1; + } + if( !(ob->eventMove(who)) ){ + who->eventPrint("You can't seem to carry the postal object."); + return 1; + } + ob->start_post(args); + return 1; +} + +int CanReceive(object ob){ + if( !ob && !(ob = previous_object()) ) return 0; + if( living(ob) && !interactive(ob) ) return 0; + else return room::CanReceive(ob); +} + +int eventReleaseObject(object foo){ + object ob; + + if( !(ob = previous_object()) ) return room::eventReleaseObject(); + if( !room::eventReleaseObject() ) return 0; + if( (ob = present(POSTAL_ID, ob)) ) ob->eventDestruct(); + return 1; +} diff --git a/lib/lib/potion.c b/lib/lib/potion.c new file mode 100644 index 0000000..f6bae0f --- /dev/null +++ b/lib/lib/potion.c @@ -0,0 +1,69 @@ +#include <lib.h> + +inherit LIB_MEAL; + +mapping Skills = ([]); +mapping Stats = ([]); +mapping Points = ([]); + +int Duration; + +void create(){ + meal::create(); +} + +mapping SetStats(mapping arg){ + Stats = copy(arg); + return copy(Stats); +} + +mapping GetStats(){ + return copy(Stats); +} + +mapping SetSkills(mapping arg){ + Skills = copy(arg); + return copy(Skills); +} + +mapping GetSkills(){ + return copy(Skills); +} + +mapping SetPoints(mapping arg){ + Points = copy(arg); + return copy(Points); +} + +mapping GetPoints(){ + return copy(Points); +} + +int SetDuration(int i){ + Duration = i; + return Duration; +} + +int GetDuration(){ + return Duration; +} + +mixed eventDrink(object who){ + object ob=new(LIB_BONUS); + ob->SetPoints(Points); + ob->SetStats(Stats); + ob->SetSkills(Skills); + ob->SetBonusDuration(Duration); + ob->eventMove(who); + return meal::eventDrink(who); +} + +mixed eventEat(object who){ + object ob=new(LIB_BONUS); + ob->SetPoints(Points); + ob->SetStats(Stats); + ob->SetSkills(Skills); + ob->SetBonusDuration(Duration); + ob->eventMove(who); + return meal::eventEat(who); +} diff --git a/lib/lib/props/addstuff.c b/lib/lib/props/addstuff.c new file mode 100644 index 0000000..19fbb4a --- /dev/null +++ b/lib/lib/props/addstuff.c @@ -0,0 +1,22 @@ +varargs int AddStuff(string *str, int q){ + int i,problem,z; + problem = 1; + for(i=0;i<sizeof(str);i++){ + object to,thing; + if(!to=this_object()) return 0; + if(q){ + for(z=0;z<q;z++){ + thing=new(str[i]); + if(!thing->eventMove(to)) problem = -1; + } + } + else if(!q || q ==0){ + thing=new(str[i]); + if(!thing->eventMove(to)) problem = -1; + } + + + } + return problem; +} + diff --git a/lib/lib/props/ambiance.c b/lib/lib/props/ambiance.c new file mode 100644 index 0000000..4d3ff9e --- /dev/null +++ b/lib/lib/props/ambiance.c @@ -0,0 +1,17 @@ +/* /lib/props/ambiance.c + * From the Dead Souls LPC Library + * Ambiance is natural light in an area + * Created by Descartes of Borg 961221 + * Version: @(#) ambiance.c 1.1@(#) + * Last modified: 96/12/22 + */ + +private int AmbientLight = 0; + +int GetAmbientLight(){ + return AmbientLight; +} + +int SetAmbientLight(int x){ + return (AmbientLight = x); +} diff --git a/lib/lib/props/body_mass.c b/lib/lib/props/body_mass.c new file mode 100644 index 0000000..f0829ac --- /dev/null +++ b/lib/lib/props/body_mass.c @@ -0,0 +1,58 @@ +#include <lib.h> +#include <daemons.h> + +string GetRace(); + +int BodyMass = 0; +static int zpg = 0; + +int SetZPG(int x){ + if(x > 0) zpg = 1; + else zpg = 0; +} + +int GetZPG(){ + return zpg; +} + +int AddBodyMass(int x){ + if( BodyMass + x > 0 ){ + x = -BodyMass; + } + if( environment() ){ + environment()->AddCarriedBodyMass(x); + } + return (BodyMass -= x); +} + +int GetBodyMass(){ + int base_mass, load; + if(GetZPG()) return 0; + base_mass = RACES_D->GetRaceMass(GetRace()); + load = this_object()->GetCarriedMass(); + return (base_mass + load); +} + +int SetBodyMass(int x){ + if( x < 0 ){ + x = 0; + } + return (BodyMass = x); +} + +int GetWeight(){ + float h; + object env = room_environment(); + + if(env){ + h = env->GetGravity(); + } + else { + h = DEFAULT_GRAVITY; + } + return to_int(GetBodyMass() * h); +} + +int GetMass(){ + return GetBodyMass(); +} diff --git a/lib/lib/props/carry.c b/lib/lib/props/carry.c new file mode 100644 index 0000000..b93ed77 --- /dev/null +++ b/lib/lib/props/carry.c @@ -0,0 +1,90 @@ +/* /lib/props/carry.c + * From the Dead Souls LPC Library + * Object for handling carried goods + * Created by Descartes of Borg 950324 + * Version: @(#) carry.c 1.10@(#) + * Last modified: 96/12/22 + */ + +static int CarriedMass = 0; +int MaxCarry = 0; + +int CanCarry(int amount); + +int AddCarriedMass(int x){ + if( !CanCarry(x) ){ + return -1; + } + CarriedMass += x; + if( CarriedMass < 0 ){ + CarriedMass = 0; + } + return CarriedMass; +} + +int GetCarriedMass(){ + return CarriedMass ; +} + +static int SetCarriedMass(int x){ + return CarriedMass = x; +} + +int CalculateCarriedMass(){ + int ret; + object *inv = all_inventory(this_object()); + if(sizeof(inv)){ + foreach(object ob in inv){ + ob->CalculateCarriedMass(); + ret += ob->GetMass(); + } + } + CarriedMass = ret; + return ret; +} + +int GetCarriedWeight(){ + object env; + float h = DEFAULT_GRAVITY; + + if( env = environment() ){ + h = env->GetGravity(); + } + return to_int( GetCarriedMass() * h ); +} + +int GetMaxCarry(){ + return MaxCarry; +} + +int GetLivingMaxCarry(){ + return MaxCarry; +} + +int SetMaxCarry(int x){ + return (MaxCarry = x); +} + +int CanCarry(int amount){ + object env; + float h; + + if( amount < 1 ) return 1; + if( env = environment() ){ + if( !(living(env)) ){ + h = (float)env->GetGravity(); + } + else { + h = DEFAULT_GRAVITY; + } + } + else { + h = DEFAULT_GRAVITY; + } + if( ((GetCarriedMass() + amount) * h) > GetMaxCarry() ){ + return 0; + } + else { + return 1; + } +} diff --git a/lib/lib/props/clean.c b/lib/lib/props/clean.c new file mode 100644 index 0000000..9bb79cf --- /dev/null +++ b/lib/lib/props/clean.c @@ -0,0 +1,120 @@ +/* /lib/clean.c + * From the Dead Souls LPC Library + * the central object of the entire mudlib + * created by Descartes of Borg 940210 + * Version: @(#) clean.c 1.3@(#) + * Last Modified: 96/12/16 + */ + +#include <clean_up.h> +#include ROOMS_H + +inherit LIB_SAVE; + +private static int NoClean = 0; + +/* ******************* clean.c attributes ************************* */ +int GetNoClean(){ + return NoClean; +} + +static int SetNoClean(int x){ + return (NoClean = x); +} + +/* ******************* clean.c events ************************* */ +/** + * Destruct() and eventDestruct() differ in that external objects use + * eventDestruct() to ask permission for destructing an object. Destruct() + * really should be called eventInternalDestruct() or something for + * naming consistency, but the Destruct() name remains for historical + * purposes. To destruct this_object(), call Destruct(). To destruct + * another object, call ob->eventDestruct(). + */ +static int Destruct(){ + object env, furn; + int pers; + + if( !this_object() ){ + return 1; + } + + env = environment(); + pers = this_object()->GetPersistent(); + + foreach(object ob in all_inventory()){ + if( ob ){ + if(env && !pers) ob->eventMove(env); + else ob->eventMove(ROOM_FURNACE); + } + } + + if(this_object()){ + if(living(this_object()) && furn = this_object()->GetProperty("furniture_object")) + if(objectp(furn)) furn->eventReleaseStand(this_object()); + } + + remove_call_out(); + destruct(this_object()); + return !(this_object()); +} + +int eventDestruct(){ + if(!valid_event(previous_object(), this_object())) return 0; + save::eventDestruct(); + return unguarded( (: Destruct() :) ); +} + +/* ******************* clean.c driver applies ********************* */ +int clean_up(int ref_exists){ + object array inv; + object env; + + if(origin() == "driver") return 0; + + if( NoClean || ref_exists ){ + return NEVER_AGAIN; + } + if( !this_object() ){ + return NEVER_AGAIN; + } + env = environment(); + if( env ){ + if( env->isBag() ){ + return TRY_AGAIN_LATER; + } + if( env->GetProperty("storage room") ){ + return TRY_AGAIN_LATER; + } + } + inv = deep_inventory(this_object()); + if(inv && sizeof(inv)){ + if( sizeof(filter(inv, (: interactive($1) || $1->GetNoClean() :))) ){ + return TRY_AGAIN_LATER; + } + } + if( !env ){ + + if(this_object() && !strsrch(base_name(this_object()),"/lib/")){ + return NEVER_AGAIN; + } + + foreach(mixed ob in inv){ + if(ob) ob->eventDestruct(); + if(ob) destruct(ob); + if(ob) catch(ob->eventMove(ROOM_FURNACE)); + } + + if( this_object() ){ + eventDestruct(); + } + if( this_object() ){ + destruct(this_object()); + } + return NEVER_AGAIN; + } + if( interactive(env) ){ + return TRY_AGAIN_LATER; + } + return env->clean_up(); +} diff --git a/lib/lib/props/cost.txt b/lib/lib/props/cost.txt new file mode 100644 index 0000000..3d7eea3 --- /dev/null +++ b/lib/lib/props/cost.txt @@ -0,0 +1,14 @@ +private int cost; + +int GetDollarCost(){ + if(cost) return cost; + return 0; +} + +int SetDollarCost(int i){ + if(i && i > -1) cost = i; + else cost = 0; + return i; +} + + diff --git a/lib/lib/props/damage.c b/lib/lib/props/damage.c new file mode 100644 index 0000000..435400d --- /dev/null +++ b/lib/lib/props/damage.c @@ -0,0 +1,63 @@ +/* /lib/props/damage.c + * From the Dead Souls Mud Library + * Things that do damage to other things + * Created by Descartes of Borg 970101 + * Version: @(#) damage.c 1.1@(#) + * Last modified: 97/01/01 + */ + +#include <damage_types.h> + +private int Class = 1; +private int DamageType = BLUNT; +private int MaxClass = 1; + +// abstract methods +mixed GetProperty(string key); +// end abstract methods + +int GetClass(){ + int ret, blessing = GetProperty("blessed"); + string type = this_object()->GetWeaponType(); + + if( !intp(blessing) ){ + blessing = 0; + } + + ret = (Class + blessing); + if(!ret) ret = 1; + + if(type && type == "projectile" && this_object()->GetWielded()){ + ret = (ret/(Class || ret)); + } + + return ret; +} + +int SetClass(int x){ + if( x > MaxClass ){ + MaxClass = x; + } + return (Class = x); +} + +int GetDamageType(){ + return DamageType; +} + +int SetDamageType(int x ){ + return (DamageType = x); +} + +int GetMaxClass(){ + return MaxClass; +} + +string array GetSave(){ + return ({ "Class" }); +} + +int eventStrike(object ob){ + if(estatep(this_object()) && !estatep(ob)) return 1; + return GetClass(); +} diff --git a/lib/lib/props/description.c b/lib/lib/props/description.c new file mode 100644 index 0000000..fc3311f --- /dev/null +++ b/lib/lib/props/description.c @@ -0,0 +1,168 @@ +/* /lib/props/description.c + * From the Dead Souls Mud Library + * Handles the describing of objects + * Created by Descartes of Borg 961222 + * Version: @(#) description.c 1.1@(#) + * Last modified: 96/12/22 + */ + +#include <lib.h> +#include <function.h> + +inherit LIB_SEARCH; +inherit LIB_DISARM; + +private int ProperNoun = 0; +private int Modify = 1; +private mixed Short = 0; + +mixed direct_modify_obj_str(){ + return 1; +} + +mixed direct_modify_word_str(){ + return 1; +} + +mixed direct_initfix_obj(){ + return 1; +} + +mixed direct_initfix(){ + return 1; +} + +mixed direct_createfix_obj(){ + return 1; +} + +mixed direct_createfix(){ + return 1; +} + +mixed direct_reload_obj(){ return 1; } +mixed indirect_reload_obj(){ return 1; } +mixed direct_reload_word_obj(){ return 1; } +mixed indirect_reload_word_obj(){ return 1; } +mixed direct_reload_str_obj(){ return 1; } +mixed indirect_reload_str_obj(){ return 1; } +mixed direct_reload_str_word(){ return 1; } +mixed indirect_reload_str_word(){ return 1; } + +mixed direct_reload(){ return 1; } +mixed indirect_reload(){ return 1; } + +mixed direct_reload_every_str(){ return 1; } +mixed indirect_reload_every_str(){ return 1; } + +mixed direct_copy_obj_to_obj(){ return 1; } +mixed direct_copy_obj_str(){ return 1; } + +mixed direct_add_obj_to_obj(){ return 1; } +mixed indirect_add_obj_to_obj(){ return 1; } + +mixed indirect_read_obj_at_obj(){ return 1; } + +mixed direct_delete_obj_from_obj(){ + return 1; +} + +mixed indirect_delete_obj_from_obj(){ + return 1; +} + +mixed indirect_delete_obj_from_here(){ return 1; } +mixed direct_delete_obj_from_here(){ return 1; } +mixed direct_delete_obj_from_room(){ return 1; } +mixed indirect_delete_obj_from_room(){ return 1; } + +mixed indirect_add_obj_to_here(){ return 1; } +mixed direct_add_obj_to_here(){ return 1; } +mixed indirect_add_obj_to_room(){ return 1; } +mixed direct_add_obj_to_room(){ return 1; } + +mixed indirect_add_obj(){ return 1; } +mixed direct_add_obj(){ return 1; } + +mixed indirect_delete_obj(){ return 1; } +mixed direct_delete_obj(){ return 1; } + +int SetNoModify(int i){ + if(i) Modify = 0; + else Modify = 1; +} + +int GetModify(){ + return Modify; +} + +int GetNoModify(){ + if(Modify) return 0; + else return 1; +} + +string GetShort(); + +string GetDefiniteShort(){ + string tmp = GetShort(); + + if( !tmp ){ + return 0; + } + if( ProperNoun ){ + return tmp; + } + else { + return add_article(tmp, 1); + } +} + +string GetShort(){ + if( !Short ){ + return 0; + } + if( functionp(Short) ){ + if( functionp(Short) & FP_OWNER_DESTED ){ + return "Error in evaluating function pointer."; + } + return evaluate(Short); + } + else if( arrayp(Short) ){ + return Short[query_night()]; + } + else { + return Short; + } +} + +varargs mixed SetShort(mixed val, int proper){ + if( !stringp(val) && !functionp(val) && !arrayp(val) ){ + error("Bad argument 1 to SetShort().\n"); + } + if( proper ){ + ProperNoun = proper; + } + else if( stringp(val) ){ // add a support for most old stuff... + if( strlen(val) > 2 ){ + string tmp = lower_case(val[0..2]); + + if( tmp[0..1] != "a " && tmp != "an " ){ + ProperNoun = 1; + } + } + else { + ProperNoun = 1; + } + } + return (Short = val); +} + +object array GetDummyItems(){ + object *DummyItems = ({}); + foreach(object item in all_inventory(this_object())){ + if(base_name(item) == LIB_DUMMY){ + DummyItems += ({ item }); + } + } + return DummyItems; +} diff --git a/lib/lib/props/deterioration.c b/lib/lib/props/deterioration.c new file mode 100644 index 0000000..1835bde --- /dev/null +++ b/lib/lib/props/deterioration.c @@ -0,0 +1,82 @@ +/* /lib/props/deterioriation.c + * From the Dead Souls Mud Library + * Handles the deterioration of objects + * Created by Descartes of Borg 970101 + * Version: @(#) deterioration.c 1.1@(#) + * Last modified: 97/01/01 + */ +#include <daemons.h> + +private int Broken = 0; +private int DamagePoints; +private int Deterioration = 0; +private int MaxDamagePoints = 20000; + +// abstract methods +void eventDeteriorate(int type); +// end abstract methods + +int GetBroken(){ + return Broken; +} + +int SetBroken(int x){ + return (Broken = x); +} + +int SetDamagePoints(int x){ + return (MaxDamagePoints = DamagePoints = x); +} + +int GetDamagePoints(){ + return DamagePoints; +} + +int GetDeterioration(){ + return Deterioration; +} + +string GetItemCondition(){ + if( Deterioration ){ + return "It has worn down completely."; + } + else { + return 0; + } +} + +string array GetSave(){ + if(undefinedp(DamagePoints)) return ({ "Broken", "Deterioration" }); + else return ({ "Broken", "DamagePoints", "Deterioration" }); +} + +int eventReceiveDamage(mixed agent, int type, int amt, int i, mixed array l){ + int x = -1; + mixed worn = this_object()->GetWorn(); + mapping temp_prot = this_object()->GetProtectionMap(); + if(undefinedp(DamagePoints)) return 0; + if(query_verb() == "pick") return 0; + if(objectp(agent)){ + if(estatep(agent) && !estatep(this_object())) return 0; + if(!estatep(agent) && estatep(this_object())) return 0; + } + if(sizeof(worn) && mapp(temp_prot) && sizeof(temp_prot)){ + foreach(int t, int val in temp_prot){ + if( t & type ){ + if( x == -1 || val < x ){ + x = val; + } + } + } + x = x/2 + random(x/2); + DamagePoints -= (abs(amt - x)); + } + else DamagePoints -= (abs(amt)); + if( DamagePoints < 1 ){ + Deterioration++; + DamagePoints = MaxDamagePoints; + eventDeteriorate(type); + } + return x; +} + diff --git a/lib/lib/props/equip.c b/lib/lib/props/equip.c new file mode 100644 index 0000000..bebe95a --- /dev/null +++ b/lib/lib/props/equip.c @@ -0,0 +1,103 @@ +/* /lib/props/equip.c + * From the Dead Souls Mud Library + * Handles the property of being something that is equipped to a limb + * The word worn is used instead of equipped for historical reasons + * Created by Descartes of Borg 970101 + * Version: @(#) equip.c 1.1@(#) + * Last modified: 97/01/01 + */ + +#include <armor_types.h> + +private int ArmorType = A_WEAPON; +private string array Worn = 0; + +// abstract methods +string GetDefiniteShort(); +// end abstract methods + +int GetArmorType(){ + return ArmorType; +} + +int SetArmorType(int x){ + if( !intp(x) ){ + error("Bad argument to SetArmorType().\n\tExpected value from " + "/include/armor_types.h, Got: " + typeof(x) + "\n"); + } + return (ArmorType = x); +} + +string array GetSave(){ + return ({ "Worn" }); +} + +string array GetWorn(){ + return Worn; +} + +static string array SetWorn(string array limbs){ + Worn = limbs; + return Worn; +} + +mixed CanEquip(object who, string array limbs){ + if( GetWorn() ){ + return "#You are already using " + GetDefiniteShort() + "."; + } + return who->CanWear(this_object(), limbs); +} + +mixed CanUnequip(object who){ + if( !GetWorn() ){ + return "#You are not using " + GetDefiniteShort() + "."; + } + return who->CanRemoveItem(who, this_object()); +} + +mixed eventEquip(object who, string array limbs){ + mixed tmp = who->eventWear(this_object(), limbs); + mixed adjs = this_object()->GetAdjectives(); + if( tmp != 1 ){ + return tmp; + } + SetWorn(limbs); + if(this_object()->GetWielded()){ + this_object()->SetAdjectives(adjs + ({"wielded"})); + } + else { + this_object()->SetAdjectives(adjs + ({"worn"})); + } + return 1; +} + +static void eventRestoreEquip(string array limbs){ + mixed tmp; + + if( !limbs || !environment() ){ + return; + } + tmp = CanEquip(environment(), limbs); + if( tmp == 1 ){ + tmp = eventEquip(environment(), limbs); + } + if( stringp(tmp) ){ + environment()->eventPrint(tmp); + } +} + +mixed eventUnequip(object who){ + mixed tmp = who->eventRemoveItem(this_object()); + mixed adjs = this_object()->GetAdjectives(); + if( tmp != 1 ){ + return tmp; + } + if(this_object()->GetWielded()){ + this_object()->SetAdjectives(adjs - ({"wielded"})); + } + else { + this_object()->SetAdjectives(adjs - ({"worn"})); + } + SetWorn(0); + return 1; +} diff --git a/lib/lib/props/id.c b/lib/lib/props/id.c new file mode 100644 index 0000000..ac1b894 --- /dev/null +++ b/lib/lib/props/id.c @@ -0,0 +1,239 @@ +/* /lib/props/id.c + * From the Dead Souls Mud Library + * Attributes which identify objects + * Created by Descartes of Borg 961222 + * Version: @(#) id.c 1.2@(#) + * Last modified: 96/12/22 + */ + +#include <lib.h> +#include <daemons.h> + +private static string array Adjectives = ({}); +private string CapName = 0; +private static string array Id = ({}); +private static string array CanonicalId = ({}); +private static string array ExcludedIds = ({}); +private static string KeyName = 0; +private static int Matching = 1; +private static object array NotifiedObjects = ({}); +private static mixed array rfn = ({}); + +string GetKeyName(); + +string array GetAdjectives(){ + return Adjectives; +} + +varargs string array SetAdjectives(mixed adjs...){ + if( stringp(adjs) ){ + adjs = ({ adjs }); + } + else if( !arrayp(adjs) ){ + error("Bad argument 1 to SetAdjectives().\n"); + } + Adjectives = ({}); + foreach(mixed val in adjs){ + if( arrayp(val) ){ + Adjectives += val; + } + else { + Adjectives += ({ val }); + } + } + parse_refresh(); + return Adjectives; +} + +string GetCapName(){ + return CapName; +} + +string SetCapName(string str){ + if( !stringp(str) ){ + error("Bad argument 1 to SetCapName().\n"); + } + return (CapName = str); +} + +string array GetId(){ + string tmp; + + if(Id && sizeof(Id)) return Id; + + tmp = GetKeyName(); + if( tmp ){ + if(!OBJECT_MATCHING || !Matching) + return distinct_array(({ CanonicalId..., tmp })); + else return Id + atomize_string(tmp) - ExcludedIds; + } + else return Id; +} + +string GetUniqueId(){ + string fn = file_name(this_object()); + rfn = reg_assoc(fn, ({ "[A-Za-z0-9]+" }), ({ 1 }), 0); + fn = implode(filter(rfn[0], (: rfn[1][member_array($1,rfn[0])] :) ), "*"); + return fn; +} + +string array GetCanonicalId(){ + string tmp; + tmp = GetKeyName(); + + return copy(CanonicalId); +} + +varargs string array SetId(mixed val...){ + string tmp, fn, gs; + string *exclude = ({}); + if(!(MASTER_D->GetPerfOK())){ + Matching = 0; + } + if( stringp(val) ){ + val = ({ val }); + } + else if( !arrayp(val) ){ + error("Bad argument 1 to SetId().\n"); + } + Id = ({}); + foreach(mixed id in val){ + if( stringp(id) ){ + Id = ({ Id..., id }); + } + else if( arrayp(id) ){ + Id = ({ Id..., id... }); + } + } + if(gs = this_object()->GetShort()){ + exclude = ({ lower_case(gs) }); + exclude += ({ lower_case(remove_article(gs)) }); + Id += exclude; + } + if(tmp = this_object()->GetRace()){ + Id += ({ tmp }); + } + if(tmp = this_object()->GetKeyName()){ + Id += ({ tmp }); + } + if(clonep(this_object())){ + fn = GetUniqueId(); + exclude += ({ fn }); + Id += ({ fn }); + } + + if(COMPAT_MODE) parse_init(); + parse_refresh(); + + CanonicalId = Id; + + if(OBJECT_MATCHING && Matching){ + if(!KeyName || !sizeof(KeyName)) KeyName = Id[0]; + Id = distinct_array(atomize_array(Id - exclude) + Id); + } + return Id; +} + +string GetKeyName(){ + return KeyName; +} + +string SetKeyName(string nom){ + if( !stringp(nom) ){ + error("Bad argument 1 to SetKeyName().\n"); + } + KeyName = lower_case(nom); + if( !CapName ){ + CapName = capitalize(nom); + } + return KeyName; +} + +string GetName(){ + return GetCapName(); +} + +int id(string str){ + int ret; + if( !stringp(str) ){ + return 0; + } + str = lower_case(str); + ret = (member_array(str, this_object()->GetId()) != -1); + if(!ret && OBJECT_MATCHING && answers_to(str,this_object())) ret = 1; + return ret; +} + +string array parse_command_id_list(){ + string array ids = (this_object()->GetId() || ({})); + return filter(ids, (: stringp($1) && ($1 != "") :)); +} + +string array parse_command_plural_id_list(){ + string array ids = (this_object()->GetId() || ({})); + + ids = filter(ids, (: stringp($1) && ($1 != "") :)); + return map(ids, (: pluralize :)); +} + +string array parse_command_adjectiv_id_list(){ + return filter(this_object()->GetAdjectives(), (: $1 && ($1 != "") :)); +} + +varargs void eventAnnounceCanonicalId(object env){ + object *inv; + if(!OBJECT_MATCHING || !Matching) return; + if(!env) env = environment(); + if(!env) return; + if(environment(env)) env = environment(env); + inv = deep_inventory(env) - ({ this_object() }); + if(sizeof(inv) > 25) return; + inv->ReceiveCanonicalId(CanonicalId); + inv = all_inventory(this_object()); + if(inv && sizeof(inv)) inv->eventAnnounceCanonicalId(env); +} + + +varargs void ReceiveCanonicalId(mixed foo, int leaving){ + if(!OBJECT_MATCHING || !Matching) return; + if(!foo || !sizeof(foo)) return; + if(!leaving){ + foreach(mixed element in foo){ + if(member_array(element, this_object()->GetId()) != -1){ + if(member_array(element, CanonicalId) == -1){ + if(sizeof(ExcludedIds) < 1024) + ExcludedIds += ({ element }); + parse_init(); + parse_refresh(); + } + } + } + } + else { + foreach(mixed element in foo){ + ExcludedIds -= ({ element }); + parse_init(); + parse_refresh(); + } + } + if(previous_object() != this_object()){ + if(member_array(previous_object(), NotifiedObjects) == -1){ + NotifiedObjects += ({ previous_object() }); + previous_object()->ReceiveCanonicalId(CanonicalId); + } + } +} + +//This is for explicitly enabling or disabling +//object matching. For some items, object matching is +//really inconvenient. + +int SetMatching(int i){ + if(!i) Matching = 0; + else Matching = 1; + return Matching; +} + +int GetMatching(){ + return Matching; +} diff --git a/lib/lib/props/inventory.c b/lib/lib/props/inventory.c new file mode 100644 index 0000000..5264c5c --- /dev/null +++ b/lib/lib/props/inventory.c @@ -0,0 +1,134 @@ +private static mapping Inventory = ([]); +private static mapping InventoryCheck = ([]); +private static string gkey = ""; +private static int counter = 0; + +static void eventLoadInventory(); + +static void eventLoadItem(string file, mixed args, int count); + +mapping GetInventory(){ + return Inventory; +} + +static void eventLoadItem(string file, mixed args, int count){ + object ob; + int u; + + if(functionp(args)) args = evaluate(args); + + if( intp(args) ){ + if(args < 0){ + args = 1; + u = 1; + } + args = args - count; + while( args > 0 ){ + if(!u) u = file->GetUnique(); + if(!u) u = file->GetMaxClones(); + if( u ){ + object *clones = filter(findobs(file),(: clonep($1) && + environment($1) :)); + if(sizeof(clones) >= u) return; + } + ob = new(file); + if( ob ){ + ob->eventMove(this_object()); + } + args--; + } + } +} + +static void eventLoadInventory(){ + int filtersize, i; + object array stuff,items,tmp; + + stuff=all_inventory(this_object()); + items = ({}); + + for(i=0; i<sizeof(stuff);i++){ + if(tmp = ({ base_name(stuff[i]) }) ) items += tmp; + } + filtersize=0; + foreach(string file, mixed args in Inventory){ + for(i=0; i<sizeof(items); i++){ + if (base_name(items[i]) == file ) filtersize++; + } + eventLoadItem(file, args, filtersize); + filtersize=0; + } +} + +mapping SetInventoryCheck(mapping newmap){ + string key = keys(newmap)[0]; + int hb = query_heart_beat(); + int tmpint = 0; + if(last(key,2) == ".c") key = truncate(key,2); + if(!hb){ + hb = 1; + set_heart_beat(1); + } + if(hb > 1) tmpint = (newmap["howlong"] / hb || 1); + else tmpint = newmap["howlong"]; + if(!InventoryCheck) InventoryCheck = ([]); + InventoryCheck[key] = newmap[key]; + return copy(InventoryCheck); +} + +mapping SetInventory(mapping mp){ + foreach(string key, mixed val in mp){ + if( key[<2..] == ".c" ){ + key = key[0..<3]; + } + if( key[0] != '/' ){ + key = "/" + key; + } + if(arrayp(val)){ + int howlong = 60; + mixed howmany = 1; + if(!sizeof(val)) val = ({ 60, 1 }); + if(sizeof(val) < 2) val += ({ 1 }); + howmany = ( val[1] || 1 ); + Inventory[key] = howmany; + if(intp(val[0])) howlong = (val[0] || 1); + else continue; + if(!query_heart_beat()) set_heart_beat(1); + SetInventoryCheck( ([ key : ([ "howlong" : howlong, "howmany" : howmany ]) ]) ); + } + else Inventory[key] = val; + } + eventLoadInventory(); + return Inventory; +} + +varargs void reset(){ + if(origin() == "driver") return; + counter = 0; + eventLoadInventory(); +} + +void heart_beat(){ + int i,howmany; + counter++; + if(!InventoryCheck || !sizeof(InventoryCheck)) return; + foreach(mixed key, mixed val in InventoryCheck){ + if(!InventoryCheck[key] || !InventoryCheck[key]["howlong"]) continue; + if(!(counter % InventoryCheck[key]["howlong"])){ + string *obs; + gkey = key; + obs = filter(all_inventory(), (: base_name($1) == gkey :) ); + + if(intp(InventoryCheck[key]["howmany"])){ + howmany = InventoryCheck[key]["howmany"]; + } + else { + howmany = evaluate( InventoryCheck[key]["howmany"] ); + } + if(sizeof(obs) < howmany){ + int count = howmany - sizeof(obs); + eventLoadItem(key, count, 0); + } + } + } +} diff --git a/lib/lib/props/mass.c b/lib/lib/props/mass.c new file mode 100644 index 0000000..cba140e --- /dev/null +++ b/lib/lib/props/mass.c @@ -0,0 +1,64 @@ +/* /lib/props/mass.c + * From the Dead Souls Mud Library + * Handles object massiveness and weight + * Created by Descartes of Borg 970101 + * Version: @(#) mass.c 1.1@(#) + * Last modified: 97/01/01 + */ + +int Mass = 0; +static int zpg = 0; + +int SetZPG(int x){ + if(x > 0) zpg = 1; + else zpg = 0; +} + +int GetZPG(){ + return zpg; +} + +mixed direct_weigh_obj(){ + return 1; +} + +int AddMass(int x){ + if( Mass + x > 0 ){ + x = -Mass; + } + if( environment() ){ + environment()->AddCarriedMass(x); + } + return (Mass -= x); +} + +int GetMass(){ + int load; + if(GetZPG()) return 0; + load = this_object()->GetCarriedMass(); + return (Mass + load); +} + +int SetMass(int x){ + if( x < 0 ){ + x = 0; + } + return (Mass = x); +} + +string array GetSave(){ + return ({ "Mass" }); +} + +int GetWeight(){ + float h; + object env = room_environment(); + + if(env){ + h = env->GetGravity(); + } + else { + h = DEFAULT_GRAVITY; + } + return to_int(GetMass() * h); +} diff --git a/lib/lib/props/move.c b/lib/lib/props/move.c new file mode 100644 index 0000000..3b209f4 --- /dev/null +++ b/lib/lib/props/move.c @@ -0,0 +1,203 @@ +#include <message_class.h> +#include <daemons.h> +#include <rooms.h> +#include <terrain_types.h> +#include <position.h> +#include <medium.h> + +#ifndef MAX_INVENTORY_SIZE +#define MAX_INVENTORY_SIZE 2048 +#endif + +private static object LastEnvironment = 0; +int anchored; + +varargs int eventPrint(string str, mixed args...); +varargs void eventAnnounceCanonicalId(object env); + +object GetLastEnvironment(){ + return LastEnvironment; +} + +int GetAnchored(){ + return anchored; +} + +int SetAnchored(int x){ + object prev = this_player(); + if(!prev || (prev != this_object() && !adminp(prev))) return anchored; + if(x > 0) anchored = ((anchored != 2) ? (adminp(prev) ? 2 : 1) : 2); + else anchored = ((anchored == 2) ? (adminp(prev) ? 0 : 2) : 0); + return anchored; +} + +int eventMove(mixed dest){ + object ob,me,furn,prev, env = environment(); + int depth; + mixed tmp, ret; + + if(!interactive(this_object()) && + !valid_event(previous_object(), this_object())) return 0; + + if(anchored && living()){ + if(env){ + int ok; + string tmpdest; + string myvoid = ROOMS_D->GetVoid(this_object()); + string *dests = ({ ROOM_FREEZER, ROOM_DEATH, ROOM_VOID, myvoid }); + string *envs = dests + ({ ROOM_POD, ROOM_FURNACE }); + if(objectp(dest)) tmpdest = base_name(dest); + else tmpdest = dest; + if(member_array(tmpdest, dests) != -1) ok = 1; + else if(member_array(base_name(env), envs) != -1) ok = 1; + if(this_player() && adminp(this_player())) ok = 1; + if(!ok){ + if(this_player()){ + if(this_player() == this_object()){ + tell_object(this_object(), "You are anchored here."); + } + else { + tell_object(this_object(), this_player()->GetName()+ + " tried to move you but you are anchored here."); + } + } + return 0; + } + else tell_object(this_object(), "You are about to be moved "+ + "to "+identify(dest)); + } + } + + me = this_object(); + + if( !me ){ + return 0; + } + if( environment() ){ + int x; + + x = environment()->CanRelease(me); + if( !x && !adminp() ){ + return 0; + } + } + if( stringp(dest) ){ + if( !(ob = find_object(dest)) ){ + string str; + + if( str = catch(call_other(dest, "???")) ){ + if( creatorp() ){ + eventPrint(str, MSG_ERROR); + } + return 0; + } + ob = find_object(dest); + } + } + else { + ob = dest; + } + if( !ob || ob == me ){ + return 0; + } + if( !ob->CanReceive(me) ){ + return 0; + } + if(sizeof(deep_inventory(ob)) > MAX_INVENTORY_SIZE){ + return 0; + } + if( objectp(me) && LastEnvironment = environment() ){ + environment()->eventReleaseObject(me); + if(!undefinedp(me->GetRecurseDepth()) && + !undefinedp(environment()->GetRecurseDepth())){ + depth = me->GetRecurseDepth(); + depth += 1; + if(depth) environment()->AddRecurseDepth(-depth); + if(environment()->GetRecurseDepth() < 1) environment()->SetRecurseDepth(1); + } + } + if(!objectp(me) ){ + return 0; + } + prev = environment(me); + move_object(ob); + tmp = ob->eventReceiveObject(me); + if(environment() == prev){ + return 0; + } + if(prev) prev->eventPostRelease(me); + if( environment() ){ +#if 0 + foreach(object peer in all_inventory(environment())){ + if( peer != me ){ + catch(peer->eventEncounter(me)); + } + } +#endif + if(OBJECT_MATCHING){ + object *prev_inv = ({}); + eventAnnounceCanonicalId(); + if(prev && sizeof(prev_inv = deep_inventory(prev))) + prev_inv->ReceiveCanonicalId(ob->GetCanonicalId(), 1); + } + } + if(living(me) && furn = me->GetProperty("furniture_object")) + if(objectp(furn)) furn->eventReleaseStand(me); + + if(living(me) && !living(environment(me)) + && furn = me->GetProperty("mount")) + if(objectp(furn)){ + me->RemoveProperty("mount"); + furn->eventDismount(me); + } + if(environment()->GetMedium() == MEDIUM_AIR && + me->GetPosition() != POSITION_FLYING){ + if(!(me->CanFly())){ + if(!interactive(me)){ + call_out("eventFall", 1); + } + } + else me->eventFly(); + } + if(environment()->GetMedium() == MEDIUM_LAND && + (me->GetPosition() == POSITION_FLOATING || + me->GetPosition() == POSITION_SWIMMING)){ + call_out("eventCollapse", 1, 1); + } + else if((environment()->GetMedium() == MEDIUM_WATER || + environment()->GetMedium() == MEDIUM_SURFACE) && + me->GetPosition() != POSITION_SWIMMING && + me->GetPosition() != POSITION_FLOATING){ + if(living(me)){ + if(!(me->GetPosition() == POSITION_FLYING && + environment()->GetMedium() == MEDIUM_SURFACE)){ + if(!(environment()->GetTerrainType() & (T_SEAFLOOR)) && me->CanSwim()){ + if(me->GetPosition() != POSITION_FLOATING){ + me->eventSwim(); + } + } + else { + call_out("eventSink", 1); + } + } + } + else { + if(!me->GetProperty("buoyant")){ + call_out("eventSink", 1); + } + } + } + ret = (LastEnvironment != environment()); + if(ret && living(this_object()) && living(environment())){ + if(!interactive(this_object()) && + !this_object()->GetBefriended(environment())){ + if(query_verb() == "get" || query_verb() == "take"){ + call_out("SetAttack", 0, environment()); + } + } + } + if(environment() && !(environment()->GetZPEM())){ + this_object()->SetZPG(0); + } + return ret; +} diff --git a/lib/lib/props/properties.c b/lib/lib/props/properties.c new file mode 100644 index 0000000..c95d45b --- /dev/null +++ b/lib/lib/props/properties.c @@ -0,0 +1,50 @@ +/* /lib/props/properties.c + * From the Dead Souls Mud Library + * The properties property + * Created by Descartes of Borg 961222 + * Version: @(#) properties.c 1.1@(#) + * Last modified: 96/12/22 + */ + +mapping Properties = ([]); + +mixed AddProperty(string prop, mixed val){ + if( Properties[prop] ){ + Properties[prop] += val; + } + else { + Properties[prop] = val; + } + return Properties[prop]; +} + +mixed GetProperty(string prop){ + if(Properties && Properties[prop]) + return Properties[prop]; + else return 0; +} + +mapping GetProperties(){ + if(!Properties) Properties = ([]); + return Properties; +} + +int RemoveProperty(string prop){ + if( undefinedp(Properties[prop]) ){ + return 1; + } + else { + map_delete(Properties, prop); + } + return !Properties[prop]; +} + +mixed SetProperty(string prop, mixed val){ + if(!Properties) Properties = ([]); + return (Properties[prop] = val); +} + +mapping SetProperties(mapping props){ + if(sizeof(Properties)) return (Properties += props); + else return (Properties = props); +} diff --git a/lib/lib/props/radiance.c b/lib/lib/props/radiance.c new file mode 100644 index 0000000..88dec09 --- /dev/null +++ b/lib/lib/props/radiance.c @@ -0,0 +1,21 @@ +/* /lib/props/radiance.c + * From the Dead Souls LPC Library + * Radiance is the capacity of one object to radiate light + * Created by Descartes of Borg 961221 + * Version: @(#) radiance.c 1.1@(#) + * Last modified: 96/12/22 + */ + +private static int RadiantLight = 0; + +int GetRadiantLight(int ambient){ + return RadiantLight; +} + +int SetRadiantLight(int x){ + return (RadiantLight = x); +} + +int GetBaseRadiance(int foo){ + return RadiantLight; +} diff --git a/lib/lib/props/save.c b/lib/lib/props/save.c new file mode 100644 index 0000000..3573c58 --- /dev/null +++ b/lib/lib/props/save.c @@ -0,0 +1,118 @@ +#include <message_class.h> +#include <dirs.h> +#include <privs.h> + +private mixed array PersistentInventory = 0; +private static int LastSave = time(); +private int PersistentInventoryEnabled = 0; +private static string wut, savename, nom = ""; + +string GetSaveName(){ + mixed tmp = directory_exists(domain(this_object(),1)+"/save"); + string ret; + if(tmp){ + tmp = query_unique_name(this_object()); + ret = domain(this_object(),1)+"/save/"+tmp; + } + return ret; +} + +int GetPersistent(){ + return PersistentInventoryEnabled; +} + +int GetLastSave(){ + return LastSave; +} + +static varargs int SaveObject(mixed str, int i){ + int ret; + savename = GetSaveName(); + if(!undefinedp(str) && intp(str)) i = str; + if(str) savename = str; +#if ENABLE_INSTANCES + savename = new_savename(savename); +#endif + if(!sizeof(savename) || savename[0..0] == ".") return 0; + if(PersistentInventoryEnabled){ + PersistentInventory = filter(map(all_inventory(), + (: $1->GetSaveString() :)), (: $1 :)); + } + ret = unguarded( (: save_object, savename, i :) ); + LastSave = time(); + return ret; +} + +int SetPersistent(int x){ + if(x > 0) x = 1; + else x = 0; + PersistentInventoryEnabled = x; + return PersistentInventoryEnabled; +} + +mixed GetPersistentInventory(){ + return copy(PersistentInventory); +} + +static varargs int RestoreObject(mixed str, int i){ + object env; + int ret; + if(!undefinedp(str) && intp(str)) i == str; + if(!interactive() && env && env->GetPersistent()) return; + if(!str) savename = GetSaveName(); + else savename = str; + if(!sizeof(savename)) return 0; +#if ENABLE_INSTANCES + str = new_savename(savename); + if(file_exists(str)) savename = str; +#else + str = old_savename(savename); + if(file_exists(str)) savename = str; +#endif + ret = unguarded((: restore_object, savename :)); + if(GetPersistent() && sizeof(PersistentInventory)){ + foreach(string obdata in PersistentInventory){ + object ob; + mixed tmp; + tmp = restore_variable(obdata); + if( arrayp(tmp) ){ + int howmany, mclones; + wut = tmp[0]; + howmany = sizeof(objects((: base_name($1) == wut && + environment($1) :))); + mclones = wut->GetMaxClones(); + if(wut->GetUnique() && howmany) continue; + if(mclones && mclones <= howmany ) continue; + ob = new(wut); + if( ob ) ob->eventConvertObject(tmp, 1); + } + else { + int howmany, mclones; + wut = tmp["#base_name#"]; + howmany = sizeof(objects((: base_name($1) == wut && + environment($1) :))); + mclones = wut->GetMaxClones(); + if(wut->GetUnique() && howmany) continue; + if(mclones && mclones <= howmany ) continue; + if( !catch(ob = new(wut)) ){ + if( ob ){ + ob->eventLoadObject(tmp, 1); + } + } + } + } + } + PersistentInventory = 0; + return ret; +} + +varargs void create(){ + RestoreObject(); +} + +int eventDestruct(){ + if(PersistentInventoryEnabled){ + SaveObject(); + } + return 1; +} diff --git a/lib/lib/props/uniqueness.c b/lib/lib/props/uniqueness.c new file mode 100644 index 0000000..ebdcef0 --- /dev/null +++ b/lib/lib/props/uniqueness.c @@ -0,0 +1,49 @@ +/* /lib/props/uniqueness.c + * From the Dead Souls Mud Library + * Allows certain objects to be made rareor unique + * Created by Descartes of Borg 961222 + * Version: @(#) uniqueness.c 1.1@(#) + * Last modified: 97/01/01 + */ + +#include <daemons.h> + +private static int array Rarity = 0; +private static int Unique = 0; +private static int MaxClones = 0; + +int array GetRarity(){ + return Rarity; +} + +int array SetRarity(int count, int days){ + return (Rarity = ({ count, days })); +} + +int GetUnique(){ + return Unique; +} + +int SetUnique(int x){ + Unique = x; + if( Unique ){ + UNIQUE_D->eventTouchObject(); + this_object()->SetRetain(0); + } + return Unique; +} + +int GetMaxClones(){ + return MaxClones; +} + +int SetMaxClones(int x){ + if(x > -1) MaxClones = x; + else MaxClones = 0; + if( MaxClones == 1 ){ + this_object()->SetUnique(1); + } + if(MaxClones) this_object()->SetRetain(0); + return MaxClones; +} + diff --git a/lib/lib/props/value.c b/lib/lib/props/value.c new file mode 100644 index 0000000..a24c283 --- /dev/null +++ b/lib/lib/props/value.c @@ -0,0 +1,102 @@ +/* /lib/props/value.c + * From the Dead Souls Mud Library + * Basic value attributes + * Created by Descartes of Borg 970101 + * Version: @(#) value.c 1.1@(#) + * Last modified: 97/01/01 + */ + +#include <vendor_types.h> +#include <daemons.h> + +private int DestroyOnSell = 0; +private int Value = 0; +private int Cost = 0; +private int VendorType = VT_TREASURE; + +int GetDestroyOnSell(){ + return DestroyOnSell; +} + +int SetDestroyOnSell(int x){ + if( x ){ + DestroyOnSell = 1; + } + else { + DestroyOnSell = 0; + } + return DestroyOnSell; +} + +string array GetSave(){ + return ({ "Value","Cost" }); +} + +varargs int GetValue(string str){ + if(estatep(this_object())) return 0; + if(Cost && str && valid_currency(str)) return query_value(Cost,query_base_currency(),str); + return Value; +} + +int SetValue(mixed y){ + mixed x; + if(arrayp(y)) return this_object()->SetBaseCost(y[1],y[0]); + else x = y; + if( !intp(x) ){ + error("Bad argument 1 to SetValue().\n\tExpected: int, Got: " + + typeof(x) + "\n"); + } + else { + return (Value = x); + } +} + +int GetVendorType(){ + return VendorType; +} + +int SetVendorType(int x){ + if( !intp(x) ){ + error("Bad argument 1 to SetVendorType().\n\tExpected: int, Got: " + + typeof(x) + "\n"); + } + if( !(x & VT_ALL) ){ + error("Invalid vendor type.\n"); + } + return (VendorType = x); +} + +varargs mixed SetBaseCost(mixed arg, int i){ + float base, rate; + + if(intp(arg)) Cost = arg; + else if(stringp(arg)){ + if(member_array(arg,ECONOMY_D->__QueryCurrencies()) == -1){ + return "Bad currency value to SetBaseCost."; + } + if(!i) return "Bad amount value to SetBaseCost."; + + base = query_base_rate(); + rate = ECONOMY_D->__Query(arg,"rate"); + + Cost = i * rate; + + } + return Cost; +} + +int GetBaseCost(string str){ + if(estatep(this_object())) return 0; + if(!str)return Cost; + + if(member_array(str,ECONOMY_D->__QueryCurrencies()) == -1){ + return 0; + } + + return query_value(Cost,query_base_currency(),str); +} + +int SetDollarCost(int x){ + SetBaseCost("dollars", x); + return Cost; +} diff --git a/lib/lib/quest.c b/lib/lib/quest.c new file mode 100644 index 0000000..03d4b49 --- /dev/null +++ b/lib/lib/quest.c @@ -0,0 +1,129 @@ +#include <lib.h> +#include <daemons.h> + +int QuestPoints = 0; +mapping QuestBook = ([]); + +int AddQuestPoints(mixed x){ + if( !intp(x)) error("Bad argument 1 to AddQuestPoints().\n"); + if((QuestPoints+= x) < 0) QuestPoints = 0; + return QuestPoints; +} + +int GetQuestPoints(){ return QuestPoints; } + + +int SetQuestPoints(int i){ + QuestPoints = i; + return QuestPoints; +} + +void AddQuest(string title, string desc){ + mapping tmp = ([]); + object * PartyMember; + object ob; + string pname; + + if( !title || !desc ) return; + + if( this_object()->GetParty() ){ + pname = this_object()->GetParty(); + PartyMember = PARTY_D->GetPartyMembers(pname) - ({ this_player() });; + foreach(ob in PartyMember){ + ob->AddPartyQuest(title,desc); + } + } + tmp["Date"] = time(); + tmp["Description"] = desc; + if(!QuestBook) QuestBook = ([]); + QuestBook[title] = tmp; + this_object()->AddTitle(title); +} + +void AddQuestSkillPoints(string skill, int amount){ + object * PartyMember; + object ob; + string pname; + + if(!skill || !amount) return; + + if( this_object()->GetParty() ){ + pname = this_object()->GetParty(); + PartyMember = PARTY_D->GetPartyMembers(pname); + foreach(ob in PartyMember){ + ob->AddSkillPoints(skill, amount); + } + } + else this_object()->AddSkillPoints(skill, amount); +} + +void AddQuestStatPoints(string stat, int amount){ + object * PartyMember; + object ob; + string pname; + + if(!stat || !amount) return; + + if( this_object()->GetParty() ){ + pname = this_object()->GetParty(); + PartyMember = PARTY_D->GetPartyMembers(pname); + foreach(ob in PartyMember){ + ob->AddStatPoints(stat, amount); + } + } + else this_object()->AddStatPoints(stat, amount); +} + +void AddQuestCurrency(string type, int amount){ + object * PartyMember; + object ob; + string pname; + + if(!type || !amount) return; + + if( this_object()->GetParty() ){ + pname = this_object()->GetParty(); + PartyMember = PARTY_D->GetPartyMembers(pname); + foreach(ob in PartyMember){ + ob->AddCurrency(type, amount); + } + } + else this_object()->AddCurrency(type, amount); +} + +void AddPartyQuest(string title, string desc){ + mapping tmp = ([]); + + if( !title || !desc ) return; + if( member_array(title, this_object()->GetTitles()) != -1 ) return; + tmp["Date"] = time(); + tmp["Description"] = desc; + if(!QuestBook) QuestBook = ([]); + QuestBook[title] = tmp; + this_object()->AddTitle(title); +} + +mixed *GetQuests(){ + if(!QuestBook) QuestBook = ([]); + return copy(QuestBook); +} + +int GetQuest(string str){ + if(!QuestBook) QuestBook = ([]); + foreach(string key, mapping val in QuestBook){ + if(str == val["Description"]) return 1; + } + return 0; +} + +mapping RemoveQuest(string str){ + if(!QuestBook) QuestBook = ([]); + if(QuestBook[str]){ + map_delete(QuestBook,str); + } + return copy(QuestBook); +} + +void create(){ + QuestBook = ([]); +} diff --git a/lib/lib/race.c b/lib/lib/race.c new file mode 100644 index 0000000..ac9ccf6 --- /dev/null +++ b/lib/lib/race.c @@ -0,0 +1,360 @@ +/* /lib/race.c + * from the Dead Souls LPC Library + * handles all race specific management + * created by Descartes of Borg 950122 + * Version: @(#) race.c 1.8@(#) + * Last modified: 96/11/11 + */ + +#include <lib.h> +#include <daemons.h> +#include <armor_types.h> +#include <damage_types.h> +#include <meal_types.h> +#include <medium.h> +#include <respiration_types.h> +#include "include/race.h" + +inherit LIB_BODY; +inherit LIB_GENETICS; +inherit LIB_LANGUAGE; +inherit LIB_TALK; + +private string Town, Race, Gender; +private static int Bulk, Respiration; +private static int MaximumHealth = 0; + +int GetRespiration(){ + int resp = RACES_D->GetRaceRespirationType(this_object()->GetRace()); + if(Respiration) return Respiration; + return resp; +} + +int SetRespiration(int i){ + if(i & R_VACUUM){ + SetResistance(ANOXIA, "immune"); + } + return Respiration = i; +} + +varargs int CanBreathe(object what, object where, int dbg){ + object env = room_environment(this_object()); + int medium, restype, roomres; + + if(this_object()->GetGodMode()){ + if(dbg) debug("CanBreathe("+identify(what)+", "+identify(where)+"): godmode"); + return 1; + } + if(!env){ + if(dbg) debug("CanBreathe("+identify(what)+", "+identify(where)+"): noenv"); + return 0; + } + medium = env->GetMedium(); + restype = this_object()->GetRespiration(); + roomres = env->GetRespirationType(); + + if(restype & roomres){ + if(dbg) debug("CanBreathe("+identify(what)+", "+identify(where)+"): a"+ 1); + return 1; + } + if(roomres && (restype & roomres)){ + if(dbg) debug("CanBreathe("+identify(what)+", "+identify(where)+"): b"+ 1); + return 1; + } + if(restype & R_VACUUM){ + if(dbg) debug("CanBreathe("+identify(what)+", "+identify(where)+"): c"+ 1); + return 1; + } + if(roomres && !(restype & roomres)){ + if(dbg) debug("CanBreathe("+identify(what)+", "+identify(where)+"): d"+ 0); + return 0; + } + + if((medium == MEDIUM_AIR || medium == MEDIUM_LAND || + medium == MEDIUM_SURFACE) && (restype & R_AIR) ){ + if(dbg) debug("CanBreathe("+identify(what)+", "+identify(where)+"): e"+ 1); + return 1; + } + + if((medium == MEDIUM_WATER || medium == MEDIUM_SURFACE) + && (restype & R_WATER) ){ + if(dbg) debug("CanBreathe("+identify(what)+", "+identify(where)+"): f"+ 1); + return 1; + } + + if( medium == MEDIUM_METHANE && (restype & R_METHANE) ){ + if(dbg) debug("CanBreathe("+identify(what)+", "+identify(where)+"): g"+ 1); + return 1; + } + + if(dbg) debug("CanBreathe("+identify(what)+", "+identify(where)+"): h"+ 0); + return 0; +} + +// abstract methods +int GetParalyzed(); +// end abstract methods + +static void create(){ + body::create(); + genetics::create(); + Race = "blob"; + Gender = "neuter"; + Town = "Town"; +} + +mixed CanDrink(object ob){ + int strength, type; + if( !ob ) return 0; + strength = ob->GetStrength(); + type = ob->GetMealType(); + if( (type & MEAL_ALCOHOL) && ((strength + GetAlcohol()) > + GetStatLevel("durability")) ) + return "That drink is too strong for you right now."; + if( (type & MEAL_CAFFEINE) && ((strength + GetCaffeine()) > + GetStatLevel("durability")) ) + return "That is too much caffeine for you right now."; + if( (type & MEAL_DRINK) && ((strength + GetDrink()) > 100) ) + return "You can't drink any more fluids right now."; + return 1; +} + +mixed CanEat(object ob){ + if( (ob->GetStrength() + GetFood()) > 100 ) + return "This is more food than you can handle right now."; + else return 1; +} + +varargs int eventDie(mixed agent){ + int x; + if( (x = body::eventDie(agent)) != 1 ) return x; + return 1; +} + +mixed eventDrink(object ob){ + int type, strength; + + type = ob->GetMealType(); + strength = ob->GetStrength(); + if( type & MEAL_POISON ) AddPoison(strength); + if( type & MEAL_DRINK ) AddDrink(strength); + if( type & MEAL_ALCOHOL ) AddAlcohol(strength); + if( type & MEAL_CAFFEINE ) AddCaffeine(strength); + return 1; +} + +mixed eventEat(object ob){ + AddFood(ob->GetStrength()); + if( ob->GetMealType() & MEAL_POISON ) + AddPoison(ob->GetStrength()); + return 1; +} + +varargs string SetRace(string race, mixed extra){ + mixed array args = allocate(5); + mixed array tmp; + mixed mixt; + + RACES_D->SetCharacterRace(race, args); + + switch(race){ + case "tree" : this_object()->SetBodyComposition("wood");break; + case "balrog" : this_object()->SetBodyComposition("stone");break; + case "elemental" : this_object()->SetBodyComposition("stone");break; + case "golem" : this_object()->SetBodyComposition("clay");break; + case "plant" : this_object()->SetBodyComposition("vegetation");break; + } + + if(sizeof(args[4])){ + foreach(mixed key, mixed val in args[4]){ + this_object()->AddSkill(key,atoi(val[1]),atoi(val[0])); + } + } + + if(sizeof(args[0])){ + foreach(tmp in args[0]){ + mixt = copy(args[0]); + SetResistance(tmp...); + } + } + if(sizeof(args[1])){ + foreach(tmp in args[1]){ + mixt = copy(args[1]); + AddStat(tmp...); + } + } + if( stringp(args[2]) ){ + mixt = copy(args[2]); + + if(!ENGLISH_ONLY){ + SetLanguage(args[2], 100, 1); + } + else { + SetLanguage("English", 100, 1); + } + } + if( sizeof(args[3]) == 2 ){ + mixt = copy(args[3]); + SetLightSensitivity(args[3]...); + } + if( extra != 1 ) NewBody(race); + tmp = this_object()->GetId(); + if(tmp && member_array(race,tmp) == -1){ + tmp += ({ race }); + this_object()->SetId(tmp); + } + if( stringp(extra) ) return (Race = extra), race; + else return (Race = race); +} + + + +string GetRace(){ return Race; } + +string SetGender(string gender){ return (Gender = gender); } + +string GetGender(){ return Gender; } + +varargs void SetStat(string stat, int level, int classes){ + int healthPoints; + + genetics::SetStat(stat, level, classes); + switch(stat){ + case "durability": + eventCompleteHeal(healthPoints = GetMaxHealthPoints()); + eventHealDamage(healthPoints); + break; + case "intelligence": + AddMagicPoints(GetMaxMagicPoints()); + break; + case "agility": + AddStaminaPoints(GetMaxStaminaPoints()); + break; + } +} + +varargs int GetMaxHealthPoints(string limb){ + int ret = 1; + if(!limb && MaximumHealth) ret = MaximumHealth; + else if(!limb && !MaximumHealth){ + ret = ( 50 + (GetStatLevel("durability") * 10) ); + } + else { + int x; + x = GetLimbClass(limb); + if(!x) x = 5; + if(MaximumHealth) ret = ( (1 + MaximumHealth) / x ); + else ret = ( (1 + GetStatLevel("durability")/x) * 10 ); + } + if(ret < 1) ret = 1; + return ret; +} + +int SetMaxHealthPoints(int x){ + if(x) MaximumHealth = x; + else SetStat("durability", to_int((x-50)/10), GetStatClass("durability")); + return GetMaxHealthPoints(); +} + +int GetMaxMagicPoints(){ + return ( 50 + (GetStatLevel("intelligence") * 10) ); +} + +float GetMaxStaminaPoints(){ + return (50.0 + (GetStatLevel("agility") * 3.0) + + (GetStatLevel("durability") * 7.0) ); +} + +void NewBody(string race){ + mixed array args = allocate(2); + mixed array tmp; + + body::NewBody(race); + if(!race) return; + RACES_D->SetCharacterLimbs(race, args); + foreach(tmp in args[0]) AddLimb(tmp...); + foreach(tmp in args[1]) AddFingers(tmp...); +} + +string SetTown(string str){ return (Town = str); } + +string GetTown(){ return Town; } + +string GetResistance(int type){ return genetics::GetResistance(type); } + +int GetLuck(){ + int x; + + x = random(GetStatLevel("luck")) / 20; + x = ((x > 4) ? 4 : x); + if( newbiep() ) x += random(7); + return (x + random(4)); +} + +int GetMobility(){ + int max = GetMaxCarry(); + int encum, mob; + + if( GetParalyzed() ){ + return 0; + } + if( max < 1 ){ + max = 1; + } + encum = (GetCarriedMass() * 100)/max; + encum -= (encum * this_object()->GetStatLevel("agility"))/200; + mob = 100 - encum; + if( mob > 100 ){ + mob = 100; + } + else if( mob < 1 ){ + mob = 0; + } + return mob; +} + +int GetCarriedMass(){ return 0; } + +int GetMaxCarry(){ + int carry_max; + carry_max = this_object()->GetLivingMaxCarry(); + if(carry_max) return carry_max; + else return ((2 + this_object()->GetStatLevel("strength")) * 50); +} + +int GetHeartRate(){ + int x, y; + x = body::GetHeartRate(); + y = GetStatLevel("speed"); + if( y > 80 ) x -= 2; + else if( y > 60 ) x -= 1; + else if( y > 40 ) x = x; + else if( y > 20 ) x += 1; + else x += 2; + if( x > 6 ) x = 6; + else if( x < 1 ) x = 1; +#ifdef FAST_COMBAT + if(FAST_COMBAT && this_object()->GetInCombat()) return 1; +#endif + return x; +} + +#if 0 +int GetHealRate(){ + int x; + + x = body::GetHealRate() + random((GetStatLevel("durability")/40) + 1); + if( x > 6 ) x = 6; + return x; +} +#endif + +int GetStatLevel(string stat){ return genetics::GetStatLevel(stat); } + +int GetAlcohol(){ return body::GetAlcohol(); } + +static void heart_beat(){ + body::heart_beat(); + genetics::heart_beat(); + set_heart_beat(GetHeartRate()); +} diff --git a/lib/lib/rifle.c b/lib/lib/rifle.c new file mode 100644 index 0000000..aefe405 --- /dev/null +++ b/lib/lib/rifle.c @@ -0,0 +1,13 @@ +#include "include/pistol.h" +#include <lib.h> +#include <damage_types.h> +#include <dirs.h> +inherit LIB_FIREARM; + +static void create(){ + ::create(); +} + +void init(){ + ::init(); +} diff --git a/lib/lib/round.c b/lib/lib/round.c new file mode 100644 index 0000000..9b7a08e --- /dev/null +++ b/lib/lib/round.c @@ -0,0 +1,116 @@ +#include <lib.h> +#include "include/round.h" +#include <vendor_types.h> +inherit LIB_ITEM; +inherit LIB_LOAD; +private int caliber,millimeter; +private string firearmtype,ammotype; +private string rifletype; +void create(){ + ::create(); + SetKeyName("round"); + SetId(({"round","bullet"})); + SetShort("a generic pistol round"); + SetLong("This is a generic pistol round."); + SetMass(1); + SetValue(1); + SetVendorType(VT_TREASURE); +} +int SetRifleType(string str){rifletype=str; return 1; } +int SetFirearmType(string str){firearmtype=str; return 1; } +int SetAmmoType(string str){ammotype=str; return 1; } +int SetCaliber(int x){ caliber=x; return 1; } +int SetMillimeter(int x){ millimeter=x; return 1; } +int GetMillimeter(){ return millimeter; } +int GetCaliber(){ return caliber; } +string GetRifleType(){ return rifletype; } +string GetFirearmType(){ return firearmtype; } +string GetAmmoType(){ return ammotype; } + +varargs mixed eventLoad(object who, object where){ + int success, err; + object cylinder; + mixed type; + if(where) type = where->GetFirearmType(); + else { + write("Load it where?"); + return 0; + } + if(!stringp(type) && !stringp(type = where->GetAmmoType())){ + write("That seems the wrong thing to try to load with this."); + return 1; + } + if(type == "acp"|| type == "nato") type = "auto"; + if(type == "revolver"){ + mixed tmparr = filter(all_inventory(where), + (: base_name($1) == LIB_CYLINDER || inherits(LIB_CYLINDER, $1) :) ); + if(sizeof(tmparr)) cylinder = tmparr[0]; + } + if(GetFirearmType() == "revolver" && ((base_name(where) != LIB_FIREARM && + !inherits(LIB_FIREARM,where)) || type != "revolver")){ + write("This ammunition is for a revolver."); + return 1; + } + if(GetFirearmType() == "auto" && (base_name(where) == LIB_FIREARM || + inherits(LIB_FIREARM,where))){ + write("That type of weapon is fed with an ammunition magazine."); + return; + } + if(where->GetCaliber() != GetCaliber()){ + write("That is not the right caliber."); + return 1; + } + if(where->GetMaxLoaded()){ + write("It's already fully loaded."); + return 1; + } + err = catch(success = eventMove((cylinder || where)) ); + if(err || !success){ + write("There seems to be a problem loading it."); + return 1; + } + else { + if(cylinder) where->eventLoad(this_object()); + write("You load your "+where->GetShort()+"."); + say(this_player()->GetName()+" loads "+GetShort()+ + " into "+possessive(this_player())+" "+ + remove_article(where->GetShort())+"."); + } + return 1; +} + +varargs mixed eventUnload(object where){ + int success, err; + object env; + mixed type = where->GetFirearmType(); + env = environment(); + if(!env) return 0; + if(base_name(env) == LIB_CYLINDER || inherits(LIB_CYLINDER, env)){ + env = environment(env); + } + if(!env) return 0; + if(!type) type = env->GetFirearmType(); + if(!stringp(type)){ + write("The "+remove_article(GetShort())+" is not loaded anywhere."); + return 1; + } + if(env != where){ + write("You seem confused about what to unload from where."); + return 1; + } + env = environment(env); + if(!env || env != this_player()){ + write("You aren't close enough to the "+ + remove_article(where->GetShort())+"."); + return 1; + } + err = catch(success = where->eventUnload(1) ); + if(err || !success){ + write("There seems to be a problem loading it."); + return 1; + } + else { + where->SetLoaded(0); + } + return 1; +} diff --git a/lib/lib/sentient.c b/lib/lib/sentient.c new file mode 100644 index 0000000..c05267a --- /dev/null +++ b/lib/lib/sentient.c @@ -0,0 +1,467 @@ +/* /lib/sentient.c + * from the Dead Souls LPC Library + * a sentient npc + * created by Descartes of Borg 950331 + * Version: @(#) sentient.c 1.5@(#) + * Last modified: 96/12/15 + */ + +#include <lib.h> +#include <function.h> +#include <talk_type.h> +#include <message_class.h> +#include <position.h> +#include <daemons.h> + + +inherit LIB_NPC; + +private mapping CommandResponses = ([]); +private mapping EmoteResponses = ([]); +private mapping RequestResponses = ([]); +private mapping TalkResponses = ([]); +private mapping ConsultResponses = ([]); +static private int WanderCount = 0; +static private int WanderMarker = 0; +private mixed array WanderPath = ({}); +private int WanderRecurse = 0; +private int WanderSpeed = 0; +private int permit_load = 0; +private int SpellChance = 50; + +/* ****************** /lib/sentient.c data manipulation **************** */ +/** + * This method is called to see if anything is going on requiring + * the NPC to keep its heart beat going. + * @return true if the heart beat should continue + */ +static int ContinueHeart(){ + if( WanderSpeed ){ + return 1; + } + else { + return npc::ContinueHeart(); + } +} + +mixed AddConsultResponse(string str, mixed val){ + return (ConsultResponses[str] = val); +} + +mixed GetConsultResponse(string str){ + return ConsultResponses[str]; +} + +mapping GetConsultResponses(){ + return ConsultResponses; +} + +int RemoveConsultResponse(string str){ + if( !ConsultResponses[str] ){ + return 0; + } + map_delete(ConsultResponses, str); + return 1; +} + +mapping SetConsultResponses(mapping mp){ + return (ConsultResponses = expand_keys(mp)); +} + +mixed AddCommandResponse(string str, mixed val){ + return (CommandResponses[str] = val); +} + +mixed GetCommandResponse(string str){ + return CommandResponses[str]; +} + +mapping GetCommandResponses(){ + return CommandResponses; +} + +int RemoveCommandResponse(string str){ + if( !CommandResponses[str] ){ + return 0; + } + map_delete(CommandResponses, str); + return 1; +} + +mapping SetCommandResponses(mapping mp){ + return (CommandResponses = expand_keys(mp)); +} + +mapping AddCommandResponses(mapping mp){ + mapping ret = add_maps(CommandResponses, mp, -1); + CommandResponses = ret; + return ret; +} + +mixed AddEmoteResponse(string verb, mixed val){ + return (EmoteResponses[verb] = val); +} + +mixed GetEmoteResponse(string verb){ + return EmoteResponses[verb]; +} + +mapping GetEmoteResponses(){ + return EmoteResponses; +} + +int RemoveEmoteResponse(string verb){ + if( !EmoteResponses[verb] ){ + return 0; + } + map_delete(EmoteResponses, verb); + return 1; +} + +mapping SetEmoteResponses(mapping mp){ + return (EmoteResponses = expand_keys(mp)); +} + +mixed AddRequestResponse(string str, mixed val){ + return (RequestResponses[str] = val); +} + +mixed GetRequestResponse(string str){ + return RequestResponses[str]; +} + +mapping GetRequestResponses(){ + return RequestResponses; +} + +int RemoveRequestResponse(string str){ + if( !RequestResponses[str] ){ + return 0; + } + map_delete(RequestResponses, str); + return 1; +} + +mapping SetRequestResponses(mapping mp){ + return (RequestResponses = expand_keys(mp)); +} + +mapping AddRequestResponses(mapping mp){ + mapping ret = add_maps(RequestResponses, mp, -1); + RequestResponses = ret; + return RequestResponses; +} + +mixed AddTalkResponse(string str, mixed val){ + return (TalkResponses[str] = val); +} + +int RemoveTalkResponse(string str){ + if( !TalkResponses[str] ){ + return 0; + } + map_delete(TalkResponses, str); + return 1; +} + +mixed GetTalkResponse(string str){ + return TalkResponses[str]; +} + +mapping GetTalkResponses(){ + return TalkResponses; +} + +mapping SetTalkResponses(mapping mp){ + return TalkResponses = expand_keys(mp); +} + +int SetSpellChance(int i){ + SpellChance = i; + return SpellChance; +} + +int GetSpellChance(){ + return SpellChance; +} + +varargs int SetWander(int speed, mixed *path, int recurse){ + WanderSpeed = speed; + if( path ){ + WanderPath = path; + } + else { + WanderPath = ({}); + } + WanderRecurse = recurse; +} + +mixed array GetWanderPath(){ + return WanderPath; +} + +mixed array SetWanderPath(mixed array path){ + return (WanderPath = path); +} + +int GetWanderRecurse(){ + return WanderRecurse; +} + +int SetWanderRecurse(int x){ + return (WanderRecurse = x); +} + +int GetWanderSpeed(){ + return WanderSpeed; +} + +int SetWanderSpeed(int x){ + return (WanderSpeed = x); +} + +int SetPermitLoad(mixed i){ + permit_load = i; + return permit_load; +} + +int GetPermitLoad(){ + return permit_load; +} + +/* ****************** /lib/sentient.c events **************** */ +mixed eventAsk(object who, string str){ + string cmd, args, lang; + int prof; + + if( !str || str == "" ) return 0; + lang = who->GetDefaultLanguage(); + prof = who->GetLanguageLevel(lang); + str = translate(str, prof); + prof = this_object()->GetLanguageLevel(lang); + str = translate(str, prof); + if(!prof){ + eventForce("speak I don't even know what language that is."); + return 1; + } + if(prof < 100){ + eventForce("speak I don't really understand "+capitalize(lang)+"."); + return 1; + } + if( sscanf(str, "%s %s", cmd, args) != 2 ){ + cmd = str; + args = 0; + } + if( !CommandResponses[cmd] ){ + if( !CommandResponses["default"] ) return 0; + else if( stringp(CommandResponses["default"]) ){ + eventForce("speak " + CommandResponses["default"]); + return 1; + } + else return evaluate(CommandResponses["default"], who, cmd, args); + } + if( stringp(CommandResponses[cmd]) ){ + eventForce("speak " + CommandResponses[cmd]); + return 1; + } + return evaluate(CommandResponses[cmd], who, cmd, args); +} + +varargs mixed eventReceiveEmote(object who, string verb, string info){ + mixed val = EmoteResponses[verb]; + if( !val ){ + return 0; + } + if( stringp(val) ){ + eventSpeak(who,TALK_LOCAL,val); + return 1; + } + return evaluate(val, this_player(), verb, info); +} + +mixed eventConsult(object who, string str){ + string lang; + int prof; + if( !str || str == "" || !ConsultResponses) return 0; + lang = who->GetDefaultLanguage(); + prof = who->GetLanguageLevel(lang); + str = translate(str, prof); + prof = this_object()->GetLanguageLevel(lang); + str = translate(str, prof); + + if(!prof){ + eventForce("speak I don't even know what language that is."); + return 1; + } + if(prof < 100){ + eventForce("speak I don't really understand "+capitalize(lang)+"."); + return 1; + } + + if( !str || str == "" || !ConsultResponses) return 0; + str = remove_article(str); + if( !ConsultResponses[str] ){ + if( !ConsultResponses["default"] ) return 0; + else if( stringp(ConsultResponses["default"]) ){ + eventForce("speak " + ConsultResponses["default"]); + return 1; + } + else return evaluate(ConsultResponses["default"], who, str); + } + if( stringp(ConsultResponses[str]) ){ + eventForce("speak " + ConsultResponses[str]); + return 1; + } + return evaluate(ConsultResponses[str], who, str); +} + +mixed eventRequest(object who, string str){ + string lang; + int prof; + + if( !str || str == "" ) return 0; + lang = (who->GetDefaultLanguage() || "that language"); + prof = who->GetLanguageLevel(lang); + str = translate(str, prof); + prof = this_object()->GetLanguageLevel(lang); + str = translate(str, prof); + + if(!prof){ + eventForce("speak I don't even know what language that is."); + return 1; + } + if(prof < 100){ + eventForce("speak I don't really understand "+capitalize(lang)+"."); + return 1; + } + + if( !RequestResponses[str] ){ + if( !RequestResponses["default"] ) return 0; + else if( stringp(RequestResponses["default"]) ){ + eventForce("speak " + RequestResponses["default"]); + return 1; + } + else return evaluate(RequestResponses["default"], who, str); + } + if( stringp(RequestResponses[str]) ){ + eventForce("speak " + RequestResponses[str]); + return 1; + } + return evaluate(RequestResponses[str], who, str); +} + +mixed eventTalkRespond(object who, object targ, int cls, string msg, string lang){ + string resp; + + foreach(resp in keys(TalkResponses)){ + if( resp == "default" ) continue; + if( strsrch(lower_case(msg), resp) > -1 ){ + if( stringp(TalkResponses[resp]) ){ + eventForce("speak " + TalkResponses[resp]); + return 1; + } + else if( evaluate(TalkResponses[resp], who, targ, msg, lang, cls) ) + return 1; + } + } + if( TalkResponses["default"] ){ + if( stringp(TalkResponses["default"]) ) + eventForce("speak " + TalkResponses["default"]); + else evaluate(TalkResponses["default"], who, targ, msg, lang, cls); + return 1; + } + return 0; +} + +mixed eventWander(){ + int fp; + object env = environment(); + + if(!env) return 0; + + if( !sizeof(WanderPath) ){ + mixed outs; + string *sorties; + string tmp; + + if(this_object()->GetPosition() == POSITION_FLOATING){ + if(!RACES_D->CanSwim(this_player()->GetRace())){ + eventForce("climb out"); + } + } + + outs = env->GetExits(); + sorties = ({}); + foreach(tmp in outs){ + string dest, door; + object ob; + if(!permit_load) ob=find_object(dest = environment()->GetExit(tmp)); + else ob=load_object(dest = environment()->GetExit(tmp)); + + if(!ob) + continue; + door = environment()->GetDoor(tmp); + if( door && + door->GetClosed() ) continue; + sorties += ({ "go " + tmp }); + } + + foreach(tmp in environment()->GetEnters(1)){ + string dest, door; + object ob; + if(!permit_load) ob=find_object(dest = environment()->GetEnter(tmp)); + else ob=load_object(dest = environment()->GetEnter(tmp)); + + if(!ob) + continue; + door = environment()->GetDoor(tmp); + if( door && + door->GetClosed() ) continue; + sorties += ({ "enter " + tmp }); + } + if( sizeof(sorties) ){ + eventForce(sorties[random(sizeof(sorties))]); + return 1; + } + else return 0; + } + if( arrayp(WanderPath[WanderMarker]) ) + foreach(mixed cmd in WanderPath[WanderMarker]){ + if( fp = functionp(cmd) ){ + if( fp != FP_OWNER_DESTED ) evaluate(cmd); + } + else eventForce(cmd); + } + else if( fp = functionp(WanderPath[WanderMarker]) ){ + if( fp != FP_OWNER_DESTED ) evaluate(WanderPath[WanderMarker]); + } + else eventForce(WanderPath[WanderMarker]); + WanderMarker++; + if( WanderMarker >= sizeof(WanderPath) ){ + WanderMarker = 0; + if( !WanderRecurse ) WanderPath = ({}); + } +} + +/********************** sentient.c driver applies ************************/ +static void heart_beat(){ + if( !this_object() || !environment() ){ + return; + } + npc::heart_beat(); + if( !this_object() || GetDying() || !environment() ){ + // no longer exist or in the middle of dying + return; + } + if( !GetInCombat() ){ // Things to do when not in combat + if( WanderSpeed ){ // Check if wandering + if( WanderCount >= WanderSpeed ){ // Time to wander + WanderCount = 0; + eventWander(); + } + else { + WanderCount++; + } + } + } +} diff --git a/lib/lib/shadow.c b/lib/lib/shadow.c new file mode 100644 index 0000000..604dd9e --- /dev/null +++ b/lib/lib/shadow.c @@ -0,0 +1,39 @@ +#include <lib.h> +#include <dirs.h> + +static object shadowed; +static object shadow_thing = this_object(); +static int shadowing; + +int eventShadow(object ob){ + if(!shadowing){ + shadowing = 1; + shadowed = ob; + ob->AddShadow(shadow_thing); + shadow(ob); + return 1; + } + else return 0; +} + +mixed GetShadowed(){ + return shadow(shadowed,0); +} + +string GetShadowedName(){ + return shadowed->GetName(); +} + +object GetShadowedObject(){ + return shadowed; +} + +int eventUnshadow(){ + if(shadowed){ + shadowed->RemoveShadow(shadow_thing); + } + if(shadow_thing){ + return destruct(shadow_thing); + } + else return 0; +} diff --git a/lib/lib/shadow_hook.c b/lib/lib/shadow_hook.c new file mode 100644 index 0000000..fdf0fa7 --- /dev/null +++ b/lib/lib/shadow_hook.c @@ -0,0 +1,23 @@ +static mapping Shadows = ([]); + +nomask int AddShadow(object sombra){ + if(!sombra) return 0; + if(!Shadows) Shadows = ([]); + if(member_array(sombra, keys(Shadows)) != -1) return 0; + Shadows[sombra] = file_name(sombra); + return 1; +} + +nomask int RemoveShadow(object sombra){ + if(!Shadows){ + Shadows = ([]); + return 0; + } + if(!Shadows[sombra]) return 0; + map_delete(Shadows,sombra); + return 1; +} + +nomask mapping GetShadows(){ + return copy(Shadows); +} diff --git a/lib/lib/shell.c b/lib/lib/shell.c new file mode 100644 index 0000000..b1d40f7 --- /dev/null +++ b/lib/lib/shell.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include "include/shell.h" +#include <vendor_types.h> +inherit LIB_ITEM; +private int caliber,millimeter; +private string firearmtype,ammotype; +void create(){ + ::create(); + if(!firearmtype) firearmtype = "firearm"; + SetKeyName("shell"); + SetId(({"shell","casing","shell casing"})); + SetShort("a spent "+firearmtype+" shell"); + SetLong("This is the empty shell casing of a bullet that has been fired."); + SetMass(1); + SetValue(0); + SetVendorType(VT_TREASURE); +} +int SetFirearmType(string str){firearmtype=str; return 1; } +int SetAmmoType(string str){ammotype=str; return 1; } +int SetCaliber(int x){ caliber=x; return 1; } +int SetMillimeter(int x){ millimeter=x; return 1; } +int GetMillimeter(){ return millimeter; } +int GetCaliber(){ return caliber; } +string GetFirearmType(){ return firearmtype; } +string GetAmmoType(){ return ammotype; } diff --git a/lib/lib/shop.c b/lib/lib/shop.c new file mode 100644 index 0000000..2a1402f --- /dev/null +++ b/lib/lib/shop.c @@ -0,0 +1,45 @@ +/* /realms/haderach/land/cities/hartland/pawnshop.c + * created by Haderach@Frontiers + * Date: Sat Aug 31 02:37:27 1996 + */ + +#include <lib.h> + +inherit LIB_ROOM; + +static void create(){ + ::create(); +} + +void init(){ + ::init(); + add_action("list","list"); + add_action("show","show"); + add_action("price","price"); + add_action("appraise","appraise"); +} + +object *ob; +object ob2; +int list(string str){ + if(!str || str == "") str = "all"; + present("vendor")->cmdBrowse(this_player(),str); + return 1; +} + + + +int show(string str){ + present("vendor")->cmdShow(this_player(),str); + return 1; +} + +int price(string str){ + present("vendor")->cmdPrice(this_player(),str); + return 1; +} + +int appraise(string str){ + present("vendor")->cmdAppraise(this_player(),str); + return 1; +} diff --git a/lib/lib/spell.c b/lib/lib/spell.c new file mode 100644 index 0000000..b47f7b8 --- /dev/null +++ b/lib/lib/spell.c @@ -0,0 +1,783 @@ +/* /lib/spell.c + * From Dead Souls LPMud + * An object all spells inherit. + * Created by Descartes of Borg 951027 + * Version: @(#) spell.c 1.22@(#) + * Last modified: 96/12/17 + */ + +#include <lib.h> +#include <magic.h> +#include <damage_types.h> + +inherit LIB_DAEMON; +inherit LIB_HELP; + +private int AutoDamage = -1; // perform dmg? +private int AutoHeal = -1; // perform healing? +private string Conjure = 0; // file to clone +private int array Damage = ({ 0, 0 }); // base, random +private mixed array Messages = ({}); // damage/heal messages +private int DamageType = MAGIC; // damage type done +private int Difficulty = 0; // 1-100 scale +private int array Healing = ({ 0, 0 }); // base, random +private int array MagicCost = ({ 0, 0 }); // base, random +private int Morality = 0; // bad? good? +private string array Religions = 0; // limit who can cast +private int RemoteTargets = 0; // can targets be remote +private int RequiredMagic = 0; // min magic pts to cast +private int RequiredStamina = 0; // min stam pts to cast +private string array Rules = ({}); // spell rules +private mapping Skills = ([]); // skill requirements +private string SpellName = ""; // name of spell +private int SpellType = SPELL_HEALING; // spell type +private int array StaminaCost = ({ 0, 0 }); // base, random +private int TrainingModifier= 1; // training factor +private string Verb = "cast"; // use what verb? + +/* ********************* spell.c attributes ************************ */ +int GetAutoDamage(){ + return AutoDamage; +} + +static int SetAutoDamage(int x){ + return (AutoDamage = x); +} + +int GetAutoHeal(){ + return AutoHeal; +} + +static int SetAutoHeal(int x){ + return (AutoHeal = x); +} + +string GetConjure(){ + return Conjure; +} + +static string SetConjure(string str){ + return (Conjure = str); +} + +int GetDamage(){ + int tmp = 0; + int damage = Damage[0]; + + if( Damage[1] ){ + damage += random(Damage[1]); + } + if(this_player()->GetSkill("magic attack")){ + tmp = (this_player()->GetSkill("magic attack")["level"]) * 2; + tmp = tmp/this_player()->GetSkill("magic attack")["class"]; + tmp += (this_player()->GetSpellLevel(SpellName) / 10); + } + damage += tmp; + return damage; +} + +varargs static void SetDamage(int type, mixed array rest...){ + DamageType = type; + if( arrayp(rest[0]) ){ + rest = rest[0]; + } + Damage[0] = rest[0]; + if( sizeof(rest) == 2 ){ + Damage[1] = rest[1]; + } + return; +} + +int GetDamageType(){ + return DamageType; +} + +int GetDifficulty(){ + return Difficulty; +} + +static int SetDifficulty(int x){ + return (Difficulty = x); +} + +string GetErrorMessage(){ + string rule = Rules[0]; + + switch(rule){ + case "": + if( Verb == "pray" ){ + return "Just pray for it."; + } + else { + return "Simply cast it?"; + } + + case "LIV": + if( Verb == "pray" ){ + return "Pray for it for whom?"; + } + else { + return "Cast it on whom?"; + } + + case "OBJ": case "STR": + if( Verb == "pray" ){ + return "Pray for it for what?"; + } + else { + return "Cast it on what?"; + } + + case "STR of LIV": + if( Verb == "pray" ){ + return "Pray for it for whom against what?"; + } + else { + return "Cast it on what of whom?"; + } + + case "for LIV": + return "Pray for it for whom?"; + + case "for OBJ": + return "Pray for it for what?"; + + case "against STR": + if( Verb == "pray" ){ + return "Pray against what?"; + } + else { + return "Cast against what?"; + } + + case "against STR for LIV": + return "Pray against what for whom?"; + } + if( Verb == "pray" ){ + return "Pray for it?"; + } + return "Cast it?"; +} + +int GetHealing(){ + return Healing[0] + random(Healing[1]); +} + +static varargs int array SetHealing(mixed args...){ + Healing[0] = args[0]; + if( sizeof(args) == 2 ){ + Healing[1] = args[1]; + } + return Healing; +} + +int GetMagicCost(){ + return MagicCost[0] + random(MagicCost[1]); +} + +static varargs int array SetMagicCost(mixed args...){ + MagicCost[0] = args[0]; + if( sizeof(args) == 2 ){ + MagicCost[1] = args[1]; + } + return MagicCost; +} + +varargs string array GetMessage(int damage, int healing){ + int max, div, i; + + if( damage < 1 ){ + return Messages[0]; + } + if( sizeof(Messages) == 2 ){ + return Messages[1]; + } + if( healing){ + max = Healing[0] + Healing[1]; + } + else { + max = Damage[0] + Damage[1]; + } + div = max/(sizeof(Messages) - 1); + i = (damage/div) + 1; + if( i >= sizeof(Messages) ){ + i = sizeof(Messages)-1; + } + return Messages[i]; +} + +static mixed array SetMessages(mixed array messages){ + return (Messages = messages); +} + +int GetMorality(){ + return Morality; +} + +static int SetMorality(int x){ + return (Morality = x); +} + +string array GetReligions(){ + return copy(Religions); +} + +varargs static string array SetReligions(string array religions...){ + return (Religions = religions); +} + +int GetRemoteTargets(){ + return RemoteTargets; +} + +static int SetRemoteTargets(int x){ + return (RemoteTargets = x); +} + +int GetRequiredMagic(){ + return RequiredMagic; +} + +static int SetRequiredMagic(int x){ + return (RequiredMagic = x); +} + +int GetRequiredStamina(){ + return RequiredStamina; +} + +static int SetRequiredStamina(int x){ + return (RequiredStamina = x); +} + +int GetRequiredSkill(string skill){ + return Skills[skill]; +} + +string array GetRules(){ + return Rules; +} + +varargs static string array SetRules(mixed args...){ + if( !args ){ + args = ({ "" }); + } + else if( arrayp(args[0]) ){ + args = args[0]; + } + return (Rules = args); +} + +string array GetSkills(){ + return keys(Skills); +} + +static mapping SetSkills(mapping mp){ + return (Skills = mp); +} + +string GetSpell(){ + return SpellName; +} + +static string SetSpell(string str){ + return (SpellName = str); +} + +int GetSpellType(){ + return SpellType; +} + +static int SetSpellType(int x){ + return (SpellType = x); +} + +int GetStaminaCost(){ + return StaminaCost[0] + random(StaminaCost[1]); +} + +static varargs int array SetStaminaCost(mixed args...){ + StaminaCost[0] = args[0]; + if( sizeof(args) == 2 ){ + StaminaCost[1] = args[1]; + } + return StaminaCost; +} + +varargs object array GetTargets(object who, mixed args...){ + int count = sizeof(args); + int attack = (SpellType == SPELL_COMBAT); + object def; + + if( attack ){ + def = who->GetCurrentEnemy(); + } + else { + def = who; + } + if( Verb == "cast" ){ + if( !count){ + if( member_array("", Rules) == -1 ){ + return 0; + } + else { + if( def ){ + return ({ def }); + } + else { + return 0; + } + } + } + else if( count == 1 ){ // on LIV || on STR + if( objectp(args[0]) ){ // on LIV + if( !living(args[0]) ){ + return 0; + } + if( member_array("LIV", Rules) == -1 ){ + return 0; + } + else { + return ({ args[0] }); + } + } + if( stringp(args[0]) ){ // on STR + int which = member_array("against STR", Rules); + + if( which == -1 && member_array("STR", Rules) == -1 ){ + return 0; + } + else { + if( def ){ + return ({ def }); + } + else { + return 0; + } + } + } + } + if( objectp(args[1]) ){ // on STR of LIV + if( !living(args[1]) ){ + return 0; + } + if( member_array("STR of LIV", Rules) == -1 ){ + return 0; + } + else { + return ({ args[1] }); + } + } + } + else { + if( !count){ + if( member_array("", Rules) == -1 ){ + return 0; + } + else { + if( def ){ + return ({ def }); + } + else { + return 0; + } + } + } + else if( count == 1 ){ // against STR + if( objectp(args[0]) ){ + if( !sizeof(({ "for LIV", "for OBJ" }) & Rules) ){ + return 0; + } + if( !living(args[0]) && member_array("for OBJ",Rules) == -1 ){ + return 0; + } + return ({ args[0] }); + } + if( member_array("against STR", Rules) == -1 ){ + return 0; + } + else { + if( def ){ + return ({ def }); + } + else { + return 0; + } + } + } + if( objectp(args[1]) ){ // against STR for LIV + if( !living(args[1]) ){ + return 0; + } + if( member_array("against STR for LIV", Rules) == -1 ){ + return 0; + } + else { + return ({ args[1] }); + } + } + } + return 0; +} + +static int SetTrainingModifier(int modifier){ + return TrainingModifier = modifier; +} + +int GetTrainingModifier(){ + return TrainingModifier; +} + +string GetVerb(){ + return Verb; +} + +static string SetVerb(string verb){ + return (Verb = verb); +} + +/* ******************** spell.c modals *************************** */ +static int CanSpellAttack(object who, object array enemies, int power){ + int i, maxi = sizeof(enemies); + int hits = 0; + int misses = 0; + int hit_count = 0; + int miss_count = 0; + int hit_con = 0; + int miss_con = 0; + int bonus; + + if( !maxi ){ + return -1; + } + for(i=0; i<maxi; i++){ + mixed area; + + if( !enemies[i] ){ + continue; + } + if( !enemies[i]->eventPreAttack(who) ){ + enemies[i] = 0; + continue; + } + if( environment(enemies[i]) != environment(who) ){ + if( RemoteTargets ){ + area = 0; + } + else { + enemies[i] = 0; + continue; + } + } + else { + area = environment(who); + } + moral_act(who, enemies[i], GetMorality()); + if( !enemies[i]->eventReceiveAttack(power, "magic", who) ){ + misses += enemies[i]->GetLevel(); + miss_count++; + miss_con += enemies[i]->GetMagicResistance(); + send_messages("repel", "$target_name $target_verb " + "$agent_possessive_noun magic attack.", who, + enemies[i], area); + enemies[i] = 0; + } + else { + hit_count++; + hits += enemies[i]->GetLevel(); + hit_con += enemies[i]->GetMagicResistance(); + } + if( miss_count > 0 ){ + bonus = who->GetCombatBonus(misses/miss_count); + bonus *= GetTrainingModifier(); + foreach(string skill in GetSkills()){ + if(!estatep(enemies[i])) + who->eventTrainSkill(skill, power/(hit_count+miss_count), + miss_con/miss_count, 0, bonus); + } + } + if( hit_count < 1 ){ + return -1; + } + bonus = who->GetCombatBonus(hits/hit_count); + bonus *= GetTrainingModifier(); + foreach(string skill in GetSkills()){ + if(enemies[i] && !estatep(enemies[i])) + who->eventTrainSkill(skill, power/(hit_count+miss_count), + hit_con/hit_count, 1, bonus); + } + } + return 1; +} + +varargs int CanCast(object who, int level, string limb, object array targets){ + string array skills = GetSkills(); + int count = sizeof(skills); + int cost = GetMagicCost(); + int x; + + if( Religions ){ + if( member_array(who->GetReligion(1), Religions) == -1 ){ + who->eventPrint("Your deity does not have that kind of power."); + return 0; + } + } + if( cost > 0 ){ + who->AddMagicPoints(-cost); + } + cost = GetStaminaCost(); + if( cost > 0 ){ + who->AddStaminaPoints(-cost); + } + if( AutoHeal != -1 ){ + int i, maxi = sizeof(targets); + + for(i=0; i<maxi; i++){ + int hp, max_hp; + + if( !targets[i] ){ + continue; + } + if( limb ){ + if( member_array(limb, targets[i]->GetLimbs()) == -1 ){ + send_messages("have", "$target_name $target_verb no " + + limb + ".", who, targets[i]); + targets[i] = 0; + continue; + } + } + hp = targets[i]->GetHealthPoints(limb); + max_hp = targets[i]->GetMaxHealthPoints(limb); + if( max_hp - hp < (Healing[0]+Healing[1])/10 + 1 ){ + if( limb ){ + send_messages("", "$target_possessive_noun " + limb + + " needs no healing.", who, targets[i]); + } + else { + send_messages("need", "$target_name $target_verb no " + "healing.", who, targets[i]); + } + targets[i] = 0; + continue; + } + } + if( !sizeof(filter(targets, (: $1 :))) ){ + return 0; + } + } + foreach(string skill in skills){ + level += who->GetSkillLevel(skill); + } + level = level/(count+1); + x = who->GetMagicChance(level/2 + random(level/2)); + if( !creatorp(who) && x < GetDifficulty() ){ // Can't even cast it... + foreach(string skill in skills){ + if(!sizeof(filter(targets, (: estatep($1) :)))) + who->eventTrainSkill(skill, level, GetDifficulty(), + 0, GetTrainingModifier()); + } + who->eventPrint("You must have gotten the words wrong."); + return 0; + } + if( AutoDamage != -1 ){ + if( CanSpellAttack(who, targets, x) == - 1 ){ + who->eventPrint("Your powers fail you."); + return 0; + } + } + else { + if( GetMorality() ){ + moral_act(who, 0, GetMorality()); + } + foreach(string skill in skills){ + if(!sizeof(filter(targets, (: estatep($1) :)))) + who->eventTrainSkill(skill, level, GetDifficulty(), + 1, GetTrainingModifier()); + } + } + return 1; +} + +/* ******************** spell.c events *********************** */ +/* -1 means this did nothing + * otherwise return damage amount for SPELL_DAMAGE + * or heal amount for SPELL_HEAL + */ +varargs int eventCast(object who, int level, mixed limb, object array targets){ + + if( GetConjure() ){ + object ob = new(GetConjure()); + + if( !ob ){ + who->eventPrint("An error occurred in conjuring."); + return 1; + } + send_messages(Messages[0][0], Messages[0][1], who, 0,environment(who)); + if( !ob->eventMove(who) ){ + send_messages("drop", "$agent_name could not carry " + + ob->GetShort() + " and $agent_verb it!", who, 0, + environment(who)); + ob->eventMove(environment(who)); + } + return 1; + } + if( AutoHeal != -1 ){ + mapping messages = ([]); + int total_healing = 0; + + foreach(object target in targets){ + string array tmp; + int healing; + + if( !target ){ + continue; + } + healing = (GetHealing() * level)/100; + healing = target->eventHealDamage(healing, AutoHeal, limb); + total_healing += healing; + tmp = GetMessage(healing, 1); + if( !messages[tmp[1]] ){ + messages[tmp[1]] = ([ tmp[0] : ({ target }) ]); + } + else { + if( !messages[tmp[1]][tmp[0]] ){ + messages[tmp[1]][tmp[0]] = ({ target }); + } + else { + messages[tmp[1]][tmp[0]] += ({ target }); + } + } + } + foreach(string message, mapping tmp in messages){ + foreach(string verb, object array obs in tmp){ + send_messages(verb, message, who, obs, + environment(who), ([ "$limb" : limb ])); + } + } + if( sizeof(targets) ){ + return total_healing/sizeof(targets); + } + else { + return 0; + } + } + if( AutoDamage != -1 ){ + mapping messages = ([]); + int total_damage = 0; + + foreach(object target in targets){ + string array tmp; + int damage; + + if( !target ){ + continue; + } + damage = (GetDamage() * level)/100; + if(!limb) limb = "torso"; + if(grepp(identify(limb),"leg") || grepp(identify(limb),"foot")) limb = "torso"; + damage = target->eventReceiveDamage(who, GetDamageType(), damage, + AutoDamage, limb); + total_damage += damage; + tmp = GetMessage(damage); + if( !messages[tmp[1]] ){ + messages[tmp[1]] = ([ tmp[0] : ({ target }) ]); + } + else { + if( !messages[tmp[1]][tmp[0]] ){ + messages[tmp[1]][tmp[0]] = ({ target }); + } + else { + messages[tmp[1]][tmp[0]] += ({ target }); + } + } + } + foreach(string message, mapping tmp in messages){ + foreach(string verb, object array obs in tmp){ + send_messages(verb, message, who, obs, + environment(who), ([ "$limb" : limb ])); + } + } + if( sizeof(targets) ){ + return total_damage/sizeof(targets); + } + else { + return 0; + } + } + return -1; +} + +varargs mixed eventParse(object who, mixed array args...){ + int count = sizeof(args); + if(!who) who = this_player(); + + if( count < 1 ){ + if( member_array("", Rules) == -1 ){ + return GetErrorMessage(); + } + return ({}); + } + if( Verb == "cast" ){ + if( count == 1 ){ + if( objectp(args[0]) ){ + if( !living(args[0]) ){ + if( member_array("OBJ", Rules) == -1 ){ + return GetErrorMessage(); + } + return ({ args[0] }); + } + if( sizeof(({ "OBJ", "LIV"}) & Rules) == 0 ){ + return GetErrorMessage(); + } + return ({ args[0] }); + } + if( stringp(args[0]) ){ + int which = member_array("against STR", Rules); + + if( which == -1 && member_array("STR", Rules) == -1 ){ + return GetErrorMessage(); + } + return ({ args[0] }); + } + } + if( member_array("STR of LIV", Rules) == -1 ){ + return GetErrorMessage(); + } + if( stringp(args[0]) && objectp(args[1]) && living(args[1]) ){ + return ({ args[0], args[1] }); + } + return "Cast it on what of whom?"; + } + else { + if( count == 1 ){ + if( objectp(args[0]) ){ + if( sizeof(({ "for OBJ", "for LIV" }) & Rules) ){ + if( !living(args[0]) ){ + if( member_array("for OBJ", Rules) == -1 ){ + return GetErrorMessage(); + } + } + return ({ args[0] }); + } + return GetErrorMessage(); + } + if( member_array("against STR", Rules) == -1 ){ + return GetErrorMessage(); + } + return ({ args[0] }); + } + if( member_array("against STR for LIV", Rules) == -1 ){ + return GetErrorMessage(); + } + if( stringp(args[0]) && objectp(args[1]) && living(args[1]) ){ + return ({ args[0], args[1] }); + } + return "Pray for it against what for whom?"; + } +} + +/* ***************** spell.c driver applies ******************** */ +static void create(){ + daemon::create(); + SetNoClean(1); +} diff --git a/lib/lib/stargate.c b/lib/lib/stargate.c new file mode 100644 index 0000000..d0c4f40 --- /dev/null +++ b/lib/lib/stargate.c @@ -0,0 +1,242 @@ +#include <lib.h> +#include <daemons.h> +#include "/lib/include/stargate.h" + +/** + * 2006-03-28, jonez + * - based on a suggestion from rhk, changed so that one cannot enter the + * gate unless status is "outbound". this makes the object closer to the + * (theoretical) math and also to what happens on the show. + */ + +/** + * based on portal.c by Brodbane - March 2006 + * + * $Id: stargate.c,v 1.1 2006/04/05 05:48:39 jam Exp $ + * + * The desired functionality is much like a "star gate": users dialed + * letters or full words that lined up with destinations. A portal opens to + * that destination briefly. To define destinations you must setup a + * constant below then add it to the switch statement in the cmdDial + * function. This object is crude and basic, but gets the job done. + * + * 2006-03-22, jonez + * - original version of this file is from Daelas@Moraelinost + * 2006-03-23, jonez + * - altered so code uses existing verbs (touch, enter) where possible. last add_action is for dial command. + * - added single mapping called "database" and made the "dial" command use it. + * - dial command no longer uses switch/case, making adding a new destination simpler + * - made use of SetPreventGet() / SetPreventPut() + * - made use of new stargate daemon + * - made use of LIB_STARGATE + * - made use of STARGATE_D + * + * IDEAS: + * - create a daemon that holds the stargate network [DONE] + * - allow for stargate failure + * - add dhd object + * - change the code so that it uses a single mapping of names and + * destinations, perhaps in a database file. currently an update to the + * object requires an update for all the objects. [DONE] + * - dhd skill (thanks plato) + * - delay when dialing gate. destination dhd lights up? + * - player should not be able to dial earth if earth is already connected elsewhere (need daemon) [DONE] + * - make use of existing verbs (enter, touch) instead of doing our own thing. [DONE] + * - daemon should contain a class that maps the various gates to each other. see lib/include/door.h [DONE] + * - shout "off world activation" into the gateroom when the gate engages. + * - track status as "incoming" or "outgoing".. you can only "enter" an outgoing gate (rhk) [DONE] + * - if room is empty, shut down the gate (rhk) + * - change callout time when someone goes through the gate (rhk) + */ + +inherit LIB_ITEM; + +static private string origin; +static private int connect_time; + +string displayLong(); +string displayShort(); + +void create(){ + item::create(); + + SetKeyName("stargate"); + SetId(({"stargate", "gate", "gateway", "ring"})); + SetAdjectives(({"stargate"})); + SetShort( (: displayShort :) ); + + SetLong( (: displayLong :) ); + + AddItem( "inner ring", "The second ring - the inner ring - is placed " + "inside the larger ring and seems to be able to move."); + SetMass(1000); + SetBaseCost("silver",50); + SetPreventGet("The gate is pure naquadah and cannot be moved."); + SetPreventPut("The gate is pure naquadah and cannot be moved!"); + SetTouch("You feel the stargate beneath your hand humming with energy."); +} + +void init(){ + ::init(); + add_action( "cmdDial", "dial" ); + add_action( "cmdEnter", "enter"); +} + + +void SetOrigin(string o, string d){ + if (o == "" || d == "") return; + origin = lower_case(o); + if(!sizeof(STARGATE_D->GetStargate(origin))){ + STARGATE_D->SetStargate(origin, d); + } +} + +string GetOrigin(){ + return origin; +} + +void eventConnect(string destination){ + int ret; + + destination = lower_case(destination); + + if (origin == destination){ + write("You attempt to dial the gate, but the last chevron does not engage"); + say(this_player()->GetName() + " tries to dial the gate but the last chevron does not engage"); + return; + } + + ret = STARGATE_D->eventConnect(origin, destination); + if (ret){ + string d = STARGATE_D->GetDestination(destination); + write("The ancient rings lock into place and a gateway forms in an explosion of energy."); + say("The ancient rings lock into place and a gateway forms in an explosion of energy."); + tell_room(d, "The ancient rings lock into place and a gateway forms in an explosion of energy"); + call_out("eventDisconnect", 10+random(5)); + connect_time = time(); + return; + } + + write("You attempt to dial the stargate, but nothing happens."); + say(this_player()->GetName() + " tries to dial the gate but fails."); + + return; +} + +int eventDisconnect(){ + string endpoint = STARGATE_D->GetEndpoint(origin); + string e = STARGATE_D->GetDestination(origin); + string d = STARGATE_D->GetDestination(endpoint); + if(d) tell_room(d, "The chevrons on the stargate disengage and the gateway disappears."); + if(e) tell_room(e, "The chevrons on the stargate disengage and the gateway disappears."); + connect_time = 0; + return STARGATE_D->eventDisconnect(origin); +} + +string status(){ + return STARGATE_D->GetStatus(origin); +} + +mixed cmdDial(string s){ + object ob; + string flipside; + if (s) + { + if(STARGATE_D->GetDestination(s)) + flipside = STARGATE_D->GetDestination(s); + eventConnect(s); + if(sizeof(flipside) && !ob) ob = load_object(flipside); + if(!ob){ + write("The Stargate abruptly begins to shuts down."); + eventDisconnect(); + } + return 1; + } + + return 0; + +} + +int cmdEnter(string what){ + string endpoint, destination; + object who; + + if(!answers_to(what, this_object())) + { + return 0; + } + + if (status() != "outbound") + { + return 0; + } + + who = this_player(); + endpoint = STARGATE_D->GetEndpoint(origin); + destination = STARGATE_D->GetDestination(endpoint); + who->eventPrint("You step through the event horizon of the stargate."); + who->eventMoveLiving(destination, + "$N enters into the event horizon and disappears.", + "$N emerges from the event horizon."); + return 1; +} + +int eventEnter(object who){ + string endpoint; + + if (!who) return 0; + + endpoint = STARGATE_D->GetEndpoint(origin); + if (status() == "connected") + { + who->eventPrint("You step through the event horizon of the stargate."); + who->eventMoveLiving(endpoint, + "$N enters into the event horizon and disappears.", + "$N emerges from the event horizon."); + } + return 1; +} + +string displayLong(){ + string buf, stat; + + buf = "This is the Stargate of legend. The Stargate was created " + "from naquadah ore, similar to black quartz. It is a perfectly " + "circular device approximately ten meters in diameter and " + "comprised of two sets of rings and nine chevrons placed " + "equidistant along its outer circumference."; + + stat = status(); + + if (stat == "outbound" || stat == "inbound") + { + buf += " There is an event horizon in the center of the ring that looks like shimmering water."; + } + else if (stat == "idle") + { + buf += " This gate is currently idle."; + } + return buf; +} + +string displayShort(){ + string stat; + stat = status(); + switch (stat) + { + case "inbound": + return "an inbound stargate"; + case "outbound": + return "an outbound stargate"; + case "idle": + return "an idle stargate"; + default: + return "a broken stargate"; + } +} + +void heart_beat(){ + if(connect_time && (time() - connect_time ) > 60){ + eventDisconnect(); + } +} diff --git a/lib/lib/std/armor.c b/lib/lib/std/armor.c new file mode 100644 index 0000000..685cec1 --- /dev/null +++ b/lib/lib/std/armor.c @@ -0,0 +1,12 @@ +#include <lib.h> + +inherit LIB_BASE_ARMOR; +inherit LIB_SHADOW_HOOK; + +void create(){ + base_armor::create(); +} + +void init(){ + base_armor::init(); +} diff --git a/lib/lib/std/bane.c b/lib/lib/std/bane.c new file mode 100644 index 0000000..fa50a38 --- /dev/null +++ b/lib/lib/std/bane.c @@ -0,0 +1,14 @@ +string array bane; + +string array GetBane(){ + if(bane) return bane; +} + +string array QueryBane(){ + if(bane) return bane; +} + +int SetBane(array arr){ + if(arr) bane = arr; + return 1; +} diff --git a/lib/lib/std/barkeep.c b/lib/lib/std/barkeep.c new file mode 100644 index 0000000..bdf9ce0 --- /dev/null +++ b/lib/lib/std/barkeep.c @@ -0,0 +1,238 @@ +/* /lib/std/barkeep.c + * From the Dead Souls LPC Library + * A monster which sells food and drink + * Created by Descartes of Borg 950528 + * Version: @(#) barkeep.c 1.2@(#) + * Last modified: 97/01/03 + */ + +#include <lib.h> + +inherit LIB_SENTIENT; +inherit LIB_BUY; + +private string LocalCurrency = "gold"; +private mapping MenuItems = ([]); +private mapping SpecialMenuItems = ([]); + +string GetLocalCurrency(); +mixed eventSell(object who, string args); + +int indirect_sell_obj_to_liv(){ + write("Your offer is refused."); + say(this_player()->GetName()+"'s sell offer is refused."); + return 0; +} + + +/* ******************* barkeep.c attributes *********************** */ +int GetCost(string *item){ + float f = currency_rate(GetLocalCurrency()); + object ob; + string obstr; + if( !obstr = MenuItems[item] ){ + obstr = SpecialMenuItems[item]; + } + if(!obstr || !(ob = load_object(obstr))){ + return 0; + } + if( f < 0.1 ){ + f = 1.0; + } + return query_value(ob->GetBaseCost(),query_base_currency(),this_object()->GetLocalCurrency()); +} + +string GetLocalCurrency(){ + return LocalCurrency; +} + +string SetLocalCurrency(string str){ + return (LocalCurrency = str); +} + +mapping AddMenuItem(mixed item, string file){ + string *item_arr; + if(stringp(item)) item_arr = ({ item }); + else item_arr = item; + MenuItems[item_arr] = file; + return MenuItems; +} + +mapping AddSpecialMenuItem(mixed item, string file){ + string *item_arr; + if(stringp(item)) item_arr = ({ item }); + else item_arr = item; + SpecialMenuItems[item_arr] = file; + return SpecialMenuItems; +} + +mapping GetMenuItems(){ + return MenuItems; +} + +mapping GetSpecialMenuItems(){ + return SpecialMenuItems; +} + +string array GetSpecials(){ + return keys(SpecialMenuItems); +} + +mapping RemoveMenuItem(string item){ + string *item_arr; + if(!sizeof(MenuItems)) return MenuItems; + foreach(string *key, string arr in MenuItems){ + if(member_array(item,key) != -1) item_arr = key; + } + if(sizeof(item_arr)) map_delete(MenuItems, item_arr); + return MenuItems; +} + +mapping RemoveSpecialMenuItem(string item){ + string *item_arr; + if(!sizeof(SpecialMenuItems)) return SpecialMenuItems; + foreach(string *key, string arr in SpecialMenuItems){ + if(member_array(item,key) != -1) item_arr = key; + } + if(sizeof(item_arr)) map_delete(SpecialMenuItems, item_arr); + return SpecialMenuItems; +} + +mapping SetMenuItems(mapping mp){ + mapping mp2 = ([]); + foreach(mixed key, mixed val in mp){ + string *key2; + if(stringp(key)) key2 = ({ key }); + else key2 = key; + mp2[key2] = val; + } + return (MenuItems = copy(mp2)); +} + +mapping SetSpecialMenuItems(mapping mp){ + mapping mp2 = ([]); + foreach(mixed key, mixed val in mp){ + string *key2; + if(stringp(key)) key2 = ({ key }); + else key2 = key; + mp2[key2] = val; + } + return (SpecialMenuItems = copy(mp2)); +} + +/* *********************** barkeep.c modals ************************ */ +int CanCarry(int cmt){ + return 1; +} + +mixed CanSell(object who, string item){ + string *what = ({}); + mapping FullMenu = add_maps(MenuItems, SpecialMenuItems); + foreach(string *key, string val in FullMenu){ + if(member_array(item,key) != -1) what = key; + } + if( !FullMenu[what] ){ + return "There is no such thing for sale."; + } + return 1; +} + +/* *********************** barkeep.c events *********************** */ +mixed eventBuyItem(object who, string cmd, string item){ + mixed tmp; + if( !item || item == "" ){ + eventForce("speak err, what do you want me to sell?"); + return 1; + } + tmp = CanSell(who, item); + if( tmp != 1 ){ + if( tmp ){ + who->eventPrint(tmp); + } + else { + eventForce("speak I cannot sell right now"); + } + return 1; + } + return eventSell(who, item); +} + +mixed eventSell(object who, string args){ + object ob; + int x; + string *what; + mapping FullMenu = add_maps(MenuItems, SpecialMenuItems); + foreach(string *key, string val in FullMenu){ + if(member_array(args,key) != -1) what = key; + } + if( !(ob = load_object(FullMenu[what])) ){ + eventForce("speak I am having a problem with that item right now."); + return 1; + } + x = query_value(ob->GetBaseCost(),query_base_currency(),GetLocalCurrency()); + if( x > who->GetCurrency(GetLocalCurrency()) ){ + eventForce("speak You do not have that much in " + GetLocalCurrency()); + return 1; + } + ob = new(FullMenu[what]); + if( !ob ){ + eventForce("speak I seem to be having some troubles."); + return 1; + } + if( !(ob->eventMove(this_object())) ){ + eventForce("speak Sorry, today is just not my day"); + return 1; + } + eventForce("give " + ob->GetKeyName() + " to " + + who->GetKeyName()); + if( environment(ob) == this_object() ){ + eventForce("speak heh, you cannot carry that. I will drop it."); + eventForce("drop " + ob->GetKeyName()); + if( environment(ob) == this_object()){ + ob->eventMove(environment()); + } + } + who->AddCurrency(GetLocalCurrency(), -x); + eventForce("speak Thank you for your business, " + + who->GetName()); + return 1; +} + +int eventList(object who, string cmd, string args, int special){ + string array drinks = ({}); + string *drink; + mapping Menu = (special ? SpecialMenuItems : MenuItems); + if( !sizeof(keys(Menu)) ){ + eventForce("speak I have nothing to serve right now."); + return 1; + } + foreach(drink in keys(Menu)){ + string array adjectives = Menu[drink]->GetAdjectives(); + string adj = ""; + if( sizeof(adjectives) ){ + adj = adjectives[random(sizeof(adjectives))] + " "; + } + //drinks += ({ adj + drink[0] + " for " + GetCost(drink) }); + drinks += ({ drink[0] + " for " + GetCost(drink) }); + } + eventForce("speak I currently supply " + item_list(drinks) + "."); + eventForce("speak Prices are in " + GetLocalCurrency() + " of course."); + return 1; +} + +int eventSpecialList(object who, string cmd){ + return eventList(who, cmd, "", 1); +} + +/* ********************* barkeep.c driver applies *********************** */ +static void create(){ + sentient::create(); + SetCommandResponses( ([ + ({ "list", "show", "browse" }) : (: eventList :), + ({ "sell", "serve" }) : (: eventBuyItem :), + ]) ); + SetRequestResponses( ([ + ({ "menu" }) : (: eventList :), + ({ "special menu" }) : (: eventSpecialList :), + ]) ); +} diff --git a/lib/lib/std/base_armor.c b/lib/lib/std/base_armor.c new file mode 100644 index 0000000..b514804 --- /dev/null +++ b/lib/lib/std/base_armor.c @@ -0,0 +1,553 @@ +/* /lib/std/armor.c + * From the Dead Souls Mud Library + * The standard armor object + * Created by Descartes of Borg 950408 + * Version: @(#) armor.c 1.9@(#) + * Last modified: 97/01/01 + */ + +#include <lib.h> +#include <daemons.h> +#include <function.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_BURY; +inherit LIB_DETECT; +inherit LIB_DETERIORATION; +inherit LIB_DROP; +inherit LIB_EQUIP; +inherit LIB_GET; +inherit LIB_GIVE; +inherit LIB_LOCK_WITH; +inherit LIB_MASS; +inherit LIB_MOVE; +inherit LIB_OBJECT; +inherit LIB_PERSIST; +inherit LIB_POISON; +inherit LIB_PUT; +inherit LIB_READ; +inherit LIB_SELL; +inherit LIB_SHOW; +inherit LIB_STEAL; +inherit LIB_VALUE; +inherit LIB_WEAR; +inherit LIB_FALL; +inherit LIB_SINK; +inherit LIB_UNIQUENESS; + +private int Size = 0; +private int Fingers = 5; +private mapping Protection = ([]); +private string array RestrictLimbs = 0; +private string array BaseLimbs = 0; +private static mixed Wear = 0; +private static mapping MaxProtection = ([]); +private static mixed my_save = ({}); + +int GetMaxProtection(int type); + +private int RetainOnDeath = 0; + +int SetRetainOnDeath(int x ){ return (RetainOnDeath = x); } + +int GetRetainOnDeath(){ return RetainOnDeath; } + +/* *************** /lib/armor.c data functions *************** */ +varargs string GetEquippedDescription(object who){ + if(!who) who = this_player(); + if( GetWorn() ){ + string tmp = "It is worn on "; + if(who == environment()){ + tmp += "your"; + } + else { + tmp += possessive_noun(environment()); + } + tmp += " " + item_list(GetWorn()) + "."; + return tmp; + } + return 0; +} + +varargs string GetExternalDesc(object who){ + string desc; + desc = ::GetExternalDesc(who); + if(GetWorn()) desc += " "+GetEquippedDescription(who); + return desc; +} + +string GetEquippedShort(){ + string tmp = GetShort(); + + if( GetWorn() ){ + tmp += " (%^GREEN%^worn%^RESET%^)"; + } + return tmp; +} + +int GetFingers(){ + return Fingers; +} + +int SetFingers(int x){ + return (Fingers = x); +} + +int GetSize(){ + return Size; +} + +int SetSize(int x){ + return (Size = x); +} + +string *LimbGuess(object who){ + mixed tmp; + int memb, armor = GetArmorType(); + string limb, *limbs; + string *base_limbs = this_object()->GetBaseLimbs(); + + limbs = ({}); + if(sizeof(base_limbs)){ + tmp = who->GetLimbs(); + if(member_array("hand", base_limbs) != -1 && + member_array("arm", base_limbs) != -1){ + string *hands = filter(tmp, (: last($1, 4) == "hand" :) ); + foreach(limb in hands){ + if((memb = member_array(limb[0..(sizeof(limb)-5)]+"arm", + tmp)) != -1 ){ + if(who->CanWear(this_object(),({limb, tmp[memb]})) + == 1){ + limbs += ({limb, tmp[memb]}); + base_limbs = remove_member(base_limbs, + member_array("arm", base_limbs)); + base_limbs = remove_member(base_limbs, + member_array("hand", base_limbs)); + if(!sizeof(filter(base_limbs, (: $1 == "hand" :)))) + break; + } + } + } + } + if(member_array("foot", base_limbs) != -1 && + member_array("leg", base_limbs) != -1){ + string *feet = filter(tmp, (: last($1, 4) == "foot" :) ); + foreach(limb in feet){ + if((memb = member_array(limb[0..(sizeof(limb)-5)]+"leg", + tmp)) != -1 ){ + if(who->CanWear(this_object(),({limb, tmp[memb]})) + == 1){ + limbs += ({limb, tmp[memb]}); + base_limbs = remove_member(base_limbs, + member_array("leg", base_limbs)); + base_limbs = remove_member(base_limbs, + member_array("foot", base_limbs)); + if(!sizeof(filter(base_limbs, (: $1 == "foot" :)))) + break; + } + } + } + } + if(sizeof(base_limbs)){ + foreach(limb in who->GetLimbs()){ + if(sscanf(reverse_string(limb),"%s %*s",tmp) != 2){ + tmp = limb; + } + else tmp = reverse_string(tmp); + if((memb = member_array(tmp, base_limbs)) != -1 && + who->CanWear(this_object(), ({ limb })) == 1){ + base_limbs = remove_member(base_limbs, memb); + limbs += ({ limb }); + } + } + } + } + else { + foreach(limb in who->GetLimbs()){ + mapping data = who->GetLimb(limb); + + if( data["armors"] & armor ){ + limbs += ({ limb }); + } + } + } + return limbs; +} + + +/* Just check the surface for blade/knife/blunt damage + * Other damage types will be checked via more costly methods + * -blitz + */ +string GetItemCondition(){ + int cuts, dents; + string ret; + cuts = dents = -1; + + foreach(int type, int val in Protection){ + int x; + if( BLADE & type || KNIFE & type ){ + x = to_float(val) / GetMaxProtection(type) * 100; + if( cuts == -1 || x < cuts ) cuts = x; + } + else if( BLUNT & type ){ + x = to_float(val) / GetMaxProtection(type) * 100; + if( dents == -1 || x > dents ) dents = x; + } + } + if( cuts == -1 && dents == -1 ) return 0; + if( cuts > -1 ) switch( cuts ){ + case 0..10: ret = "shredded to pieces"; break; + case 11..20: ret = "shredded"; break; + case 21..40: ret = "mildly shredded"; break; + case 41..60: ret = "slashed up"; break; + case 61..80: ret = "scratched"; break; + case 81..90: ret = "somewhat nicked"; break; + default: ret = "unbroken"; + } + if( dents > -1 ){ + if( ret ) ret += " and "; + else ret = ""; + switch( dents ){ + case 0..10: ret += "utterly battered"; break; + case 11..20: ret += "terribly pounded"; break; + case 21..40: ret += "serverly dented"; break; + case 41..60: ret += "pretty dented"; break; + case 61..80: ret += "dented"; break; + case 81..90: ret += "slightly dented"; break; + default: ret += "unmarred"; + } + } + return "Its surface is " + ret + "."; +} + +int GetMaxProtection(int type){ + return MaxProtection[type]; +} + +int GetProtection(int type){ + int array types; + int i; + + foreach(int t, int val in Protection){ + if( t & type ){ + int blessing = GetProperty("blessed"); + + if( !intp(blessing) ){ + blessing = 0; + } + return (val + blessing); + } + } + return 0; +} + +int SetProtection(int type, int amount){ + MaxProtection[type] = amount; + return (Protection[type] = amount); +} + +int SetAC(int i){ + SetProtection(ALL_EXTERNAL_DAMAGE, i * 5); + return i; +} + +string array GetRestrictLimbs(){ + return RestrictLimbs; +} + +string array SetRestrictLimbs(string array limbs){ + return (RestrictLimbs = limbs); +} + +string array GetBaseLimbs(){ + return BaseLimbs; +} + +string array SetBaseLimbs(string array limbs){ + return (BaseLimbs = limbs); +} + +string array GetSave(){ + return persist::GetSave(); +} + +static mixed array AddSave(mixed array vars){ + if(!vars) vars = ({}); + my_save = distinct_array( my_save + vars ); + return persist::AddSave(my_save); +} + +mixed GetWear(){ + return Wear; +} + +mixed SetWear(mixed val){ + return (Wear = val); +} + +/* ****************** armor.c modals ********************* */ +mixed CanEquip(object who, string array limbs){ + mixed tmp; + + if(Size && !( Size & who->GetSize() ) ){ + return "It doesn't fit."; + } + + if( !limbs ){ /* let's try and guess */ + string array guess = who->GetLimbs(); + int armor = GetArmorType(); + string limb; + if( !guess ){ + return "You have no limbs!"; + } + limbs = LimbGuess(who); + if(!limbs){ + foreach(limb in guess){ + mapping data; + + data = who->GetLimb(limb); + if( data["armors"] & armor ){ + limbs += ({ limb }); + } + } + } + if( equip::CanEquip(who, limbs) != 1 ){ + string ret = "#Wear " + GetDefiniteShort() + " on which "; + int type = this_object()->GetArmorType(); + if(type & A_RING) ret += "hand?"; + else ret += "limb?"; + return ret; + } + else { + return 1; + } + } + else if( sizeof(limbs) == 1 ){ + string which; + + switch(GetArmorType()){ + case A_SHIELD: + if( which = who->GetLimbParent(limbs[0]) ){ + limbs = ({ limbs[0], "torso", which }); + } + break; + + case A_LONG_GLOVE: case A_LONG_BOOT: + if( which = who->GetLimbParent(limbs[0]) ){ + limbs = ({ limbs[0], which }); + } + else { + limbs = ({ limbs[0] }); + } + break; + + default: + limbs = ({ limbs[0] }); + break; + } + } + return equip::CanEquip(who, limbs); +} + +mixed CanRepair(object who){ + return 1; +} + +mixed CanSteal(object who){ + if( GetWorn() ){ + return "You can't steal something equipped!"; + } + return steal::CanSteal(who); +} + +/* ********************* armor.c events *********************** */ +static int Destruct(){ + if( GetWorn() && environment() ){ + eventUnequip(environment()); + } + return object::Destruct(); +} + +void eventDeteriorate(int type){ + foreach(int t, int val in Protection){ + if( (t & type) && val ){ + if( GetProperty("blessed") ){ + Protection[t] -= 2; + } + else { + Protection[t]--; + } + if( Protection[t] < 1 ){ + Protection[t] = 0; + } + } + } + SetDestroyOnSell(1); + SetValue(GetValue()/2); +} + +mixed eventEquip(object who, string array limbs){ + mixed tmp; + + if( !limbs ){ /* let's try and guess */ + limbs = LimbGuess(who); + } + else if( sizeof(limbs) == 1 ){ + string which; + switch(GetArmorType()){ + case A_SHIELD: + if( which = who->GetLimbParent(limbs[0]) ){ + limbs = ({ limbs[0], "torso", which }); + } + break; + + case A_LONG_GLOVE: case A_LONG_BOOT: + if( which = who->GetLimbParent(limbs[0]) ){ + limbs = ({ limbs[0], which }); + } + else { + limbs = ({ limbs[0] }); + } + break; + + default: + limbs = ({ limbs[0] }); + break; + } + } + if( functionp(Wear) ){ + if( functionp(Wear) & FP_OWNER_DESTED ){ + return "You can't wear that there at the moment."; + } + if( !evaluate(Wear, who, limbs) ){ + return 1; + } + } + tmp = equip::eventEquip(who, limbs); + if( tmp != 1 ){ + if( tmp ){ + who->eventPrint(tmp); + } + else { + who->eventPrint("You can't wear that there right now."); + } + return 1; + } + tmp = GetShort(); + SetWorn(limbs); + if( functionp(Wear) ){ + return 1; + } + else if( stringp(Wear) ){ + who->eventPrint(Wear); + } + else { + who->eventPrint("You wear " + tmp + "."); + } + environment(who)->eventPrint(who->GetName() + " wears " + tmp + ".", who); + return 1; +} + +int eventMove(mixed dest){ + if( !environment() && GetWorn() ){ + mixed array limbs = GetWorn(); + + SetWorn(0); + call_out((: eventRestoreEquip :), 0, limbs); + } + if( GetWorn() && environment() ){ + eventUnequip(environment()); + } + return move::eventMove(dest); +} + +varargs mixed eventRepair(object who, int strength, int type){ + if( !who || !strength ){ + return 0; + } + if( !type ){ + type = ALL_DAMAGE; + } + foreach(int i in keys(Protection)){ + if( !(i & type) || !MaxProtection[i]){ + continue; + } + Protection[i] += strength; + if( Protection[i] > MaxProtection[i] ){ + Protection[i] = MaxProtection[i]; + } + } + return 1; +} + +mixed eventShow(object who, string component){ + mixed tmp = object::eventShow(who, component); + + if( component || tmp != 1 ){ + return tmp; + } + if( GetPoison() ){ + if( random(100) < who->GetSkillLevel("stealth") ){ + who->eventPrint("You notice a strange substance on it."); + } + } + return 1; +} + +varargs mixed eventUnequip(object who){ + mixed tmp = equip::eventUnequip(who); + + if( tmp != 1 ){ + return tmp; + } + if(!who->GetDead()) send_messages("remove", "$agent_name $agent_verb $target_name.", + who, this_object(), environment(who)); + return 1; +} + +varargs int restrict(mixed arg, int i){ + if(!arg) return 1; + if(arg && i) SetBaseLimbs(arg); + else if(arg) SetRestrictLimbs(arg); + return 2; +} + +/* ******************** armor.c driver applies ******************** */ +static void create(){ + steal::create(); + object::create(); + my_save = equip::GetSave() + value::GetSave() + mass::GetSave() + + poison::GetSave() + deterioration::GetSave(); + persist::AddSave(my_save); + SetVendorType(VT_ARMOR); +} + +void init(){ + int atype; + atype = GetArmorType(); + if(atype & A_RING ) restrict(({"hand"}),1); + if(atype & A_SHIELD ) restrict(({"hand","arm","torso"}),1); + if(atype & A_LONG_GLOVE ) restrict(({"hand","arm"}),1); + if(atype & A_LONG_SOCK ) restrict(({"foot","leg"}),1); + if(atype & A_LONG_BOOT ) restrict(({"foot","leg"}),1); + if(atype & A_SOCK ) restrict(({"foot"}),1); + if(atype & A_BOOT ) restrict(({"foot"}),1); + if(atype & A_GLOVE ) restrict(({"hand"}),1); + if(atype & A_HELMET ) restrict(({"head"})); + if(atype & A_VISOR ) restrict(({"head"})); + if(atype & A_PANTS ) restrict(({"right leg","left leg"})); + if(atype & A_BELT ) restrict(({"torso"})); + if(atype & A_SHIRT ) restrict(({"torso"})); + if(atype & A_CLOAK ) restrict(({"torso"})); + if(atype & A_VEST ) restrict(({"torso"})); + if(atype & A_ARMOR ) restrict(({"torso","right arm","left arm"})); + if(atype & A_COLLAR ) restrict(({"neck"})); + if(atype & A_BODY_ARMOR ) restrict(({"torso","right arm","left arm","left leg","right leg"}) ); +} + +mapping GetProtectionMap(){ + return copy(Protection); +} diff --git a/lib/lib/std/base_dummy.c b/lib/lib/std/base_dummy.c new file mode 100644 index 0000000..e83af13 --- /dev/null +++ b/lib/lib/std/base_dummy.c @@ -0,0 +1,129 @@ +/* /lib/obj/dummy.c + * From the Dead Souls Mud Library + * A dummy item object that handles item descriptions and such + * Created by Descartes of Borg 961014 + * Version: @(#) dummy.c 1.18@(#) + * Last modified: 96/12/31 + */ + +#include <lib.h> +#include <function.h> + +inherit LIB_CLEAN; +inherit LIB_DESCRIPTION; +inherit LIB_ENTER; +inherit LIB_ID; +inherit LIB_LISTEN; +inherit LIB_LOOK; +inherit LIB_RADIANCE; +inherit LIB_READ; +inherit LIB_SMELL; +inherit LIB_TOUCH; +inherit LIB_KNOCK; +inherit LIB_SCRATCH; +inherit LIB_SINK; + +/* ***************** dummy.c attributes ***************** */ + +int isDummy(){ + return 1; +} +varargs string array SetId(mixed ids...){ + ids = id::SetId(ids); + if( sizeof(ids) && !GetKeyName() ){ + SetKeyName(ids[0]); + if( !GetShort() ){ + SetShort(add_article(ids[0])); + } + } + return ids; +} +//varargs int GetInvis(object ob){ +// return 1; +//} + +/* ********************* dummy.c events ****************** */ +static int Destruct(){ + object env; + int x; + + if( env = environment() ){ + env->eventReleaseObject(this_object()); + x = clean::Destruct(); + if( !x ){ + env->eventReceiveObject(this_object()); + } + return x; + } + else return clean::Destruct(); +} +mixed eventMove(mixed dest){ + object ob; + string str; + + if(!valid_event(previous_object(), this_object())) return 0; + + str = "I am "+file_name(this_object())+", named "+identify(GetId())+", "; + str += "and I have been asked to move "; + str += "by "+identify(previous_object()); + + if(previous_object(-1)) str += " at the request of "+identify(previous_object(-1)); + str += ". "; + if(environment()) str += "\nMy current environment is "+file_name(environment())+"."; + else str += "\nI currently have no environment."; + + if( stringp(dest) ){ + ob = load_object(dest); + } + else { + ob = dest; + } + if(ob){ + str += "\nMy intended destination is "+file_name(ob)+". "; + move_object(ob); + if( environment() != ob ){ + str += "\nThe move was not successful"; + return 0; + } + else { + str += "\nThe move was successful."; + eventAnnounceCanonicalId(environment()); + return 1; + } + } + return 0; +} + +/* ******************* dummy.c driver applies ******************** */ +varargs static void create(string array id, mixed long, string array adj){ + string str; + str = "I am "+file_name(this_object())+" and I have been created "; + str += "by "+identify(previous_object(-1)); + + if(environment()) str += "\nMy current environment is "+file_name(environment())+"."; + else str += "\nI currently have no environment."; + str += "\nCall stack: "+get_stack(); + SetNoSink(1); + + enter::create(); + parse_init(); + if( adj ){ + SetAdjectives(adj...); + } + if( id ){ + if(objectp(id)) id = id->GetId(); + SetKeyName(id[0]); + if(!GetShort()) SetShort(add_article(id[0])); + SetId(id...); + } + SetExternalDesc(long || ""); + SetInvis(1); +} + +varargs mixed eventKnock(object who, mixed what){ + return enter::eventKnock(who, what); +} + +varargs mixed eventScratch(object who, mixed what){ + return enter::eventScratch(who, what); +} diff --git a/lib/lib/std/base_storage.c b/lib/lib/std/base_storage.c new file mode 100644 index 0000000..1759f0b --- /dev/null +++ b/lib/lib/std/base_storage.c @@ -0,0 +1,229 @@ +/* /lib/obj/storage.c + * From the Dead Souls Mud Library + * The standard object for storing things + * Created by Descartes of Borg 940212 + * Version: @(#) storage.c 1.7@(#) + * Last modified: 96/12/31 + */ + +#include <lib.h> + +inherit LIB_HOLDER; +inherit LIB_SEAL; + +private int CanClose = 0; +private int CanLock = 0; +private int MaxRecurseDepth = 3; +private int RecurseDepth = 1; +private static mixed my_save = ({}); + +int GetMaxRecurseDepth(){ + return MaxRecurseDepth; +} + +int GetRecurseDepth(){ + return RecurseDepth; +} + +int SetMaxRecurseDepth(int i){ + MaxRecurseDepth =i; + return 1; +} + +int SetRecurseDepth(int i){ + RecurseDepth=i; + return 1; +} + +int AddRecurseDepth(int i){ + RecurseDepth += i; + return 1; +} + +int GetCanClose(){ + return CanClose; +} + +int SetCanClose(int x){ + CanClose = x; +} + +int GetCanLock(){ + return CanLock; +} + +int SetCanLock(int x){ + return SetCanClose(CanLock = x); +} + +void SetKey(string key){ + SetKeys(key); +} + +int GetOpacity(){ + return holder::GetOpacity(); +} + +int SetOpacity(mixed arg){ + return holder::SetOpacity(arg); +} + +int GetRadiantLight(int ambient){ + return holder::GetRadiantLight(ambient); +} + +//string array GetSave(){ +// string *i_save, *s_save; +// i_save = item::GetSave(); +// s_save = seal::GetSave(); +// my_save += i_save + s_save; +// my_save += ({ "Closed","CanClose", "CanLock", "RecurseDepth" , "MaxRecurseDepth" }); +// my_save = distinct_array(my_save); +// return my_save; +//} + +//static mixed array AddSave(mixed array vars){ +// my_save = distinct_array(my_save + vars); +// return item::AddSave(my_save); +//} + +//int SetSaveRecurse(int x){ +// return item::SetSaveRecurse(x); +//} + +mixed CanClose(object who, string id){ + if( !GetCanClose() ){ + return 0; + } + else { + return seal::CanClose(who, id); + } +} + +mixed CanGetFrom(object who, object item){ + mixed tmp = holder::CanGetFrom(who, item); + + if( tmp != 1 ){ + return tmp; + } + if( GetClosed() ){ + return capitalize(GetDefiniteShort()) + " is closed."; + } + return 1; +} + +mixed CanLock(object who, string id){ + if( !GetCanLock() ){ + return 0; + } + else { + return seal::CanLock(who, id); + } +} + +mixed CanOpen(object who, string id){ + if( !GetCanClose() ){ + return 0; + } + else { + return seal::CanOpen(who, id); + } +} + +mixed CanPick(object who, string id){ + if( !GetCanLock() ){ + return "It isn't lockable in the first place."; + } + else { + return seal::CanPick(who, id); + } +} + +mixed CanPutInto(object who, object what){ + mixed tmp; + int mydepth,yourdepth,total,indirectp,indirectpp; + string wherefrom,stackstring; + string *callstack; + + if(!tmp = holder::CanPutInto(who, what)){ + if(GetClosed()) return capitalize(GetDefiniteShort()) + " is closed right now."; + else return "You can't do that right now."; + } + + wherefrom=origin(); + callstack=call_stack(2); + stackstring=implode(callstack," "); + indirectp=member_array("indirect_put_obj_word_obj",callstack); + indirectpp=member_array("indirect_put_objs_word_obj",callstack); + + + if( tmp != 1 ){ + if( GetClosed() ) return capitalize(GetDefiniteShort()) + " is closed."; + else return "You can't do that at this time."; + } + if( GetClosed() ){ + return capitalize(GetDefiniteShort()) + " is closed."; + } + + if(inherits(LIB_STORAGE, what) ){ + yourdepth = what->GetRecurseDepth(); + mydepth = this_object()->GetRecurseDepth(); + if(yourdepth && mydepth) total = yourdepth + mydepth; + if(total && total > this_object()->GetMaxRecurseDepth()) return "Doesn't fit."; + } + + return 1; +} + +varargs mixed CanShowInterior(object who, object target){ + if( GetClosed() && this_object()->GetOpacity() > 33){ + return capitalize(GetDefiniteShort()) + " is closed."; + } + else return holder::CanShowInterior(); +} + +mixed CanUnlock(object who, string id, object key){ + if( !GetCanLock() ){ + return 0; + } + else { + return seal::CanUnlock(who, id, key); + } +} + +int eventReceiveObject(object ob){ + if( GetClosed() ){ + return 0; + } + + return holder::eventReceiveObject(ob); +} + +void PutCheck(){ + if(RecurseDepth >= MaxRecurseDepth){ + this_object()->SetPreventPut("You have enough containers "+ + "inside containers there. This one will have to stay out."); + } +} + +void create(){ + //string *i_save, *s_save; + holder::create(); + //item::create(); + seal::create(); + //i_save = item::GetSave(); + //s_save = seal::GetSave(); + //my_save = i_save + s_save; + //my_save += ({ "Closed","CanClose", "CanLock", "RecurseDepth" , "MaxRecurseDepth" }); + //my_save = distinct_array(my_save); + //item::AddSave(my_save); + PutCheck(); +} + +int inventory_accessible(){ + return seal::inventory_accessible(); +} + +int inventory_visible(){ + return (seal::inventory_visible() || holder::inventory_visible()); +} diff --git a/lib/lib/std/bed.c b/lib/lib/std/bed.c new file mode 100644 index 0000000..e0ba7a1 --- /dev/null +++ b/lib/lib/std/bed.c @@ -0,0 +1,21 @@ +#include <lib.h> + +inherit LIB_LIE; + +inherit LIB_SURFACE; + +void create(){ + surface::create(); + + SetMaxLiers(4); + SetMaxLiers(2); + SetMaxCarry(300); + SetMass(1700); +} + +int CanGet(object who){ + if(lie::CanGet(who)) + return surface::CanGet(who); + else return 0; +} + diff --git a/lib/lib/std/boobytrap_object.c b/lib/lib/std/boobytrap_object.c new file mode 100644 index 0000000..85d24bd --- /dev/null +++ b/lib/lib/std/boobytrap_object.c @@ -0,0 +1,94 @@ +#include <lib.h> +#include ROOMS_H +inherit LIB_ITEM; + +int traptype = 0; +int traplevel = 0; +int autoresets = 0; +string shadow_object = ""; + +int SetTrapType(int i){ + traptype = i; + return traptype; +} + +int GetTrapType(){ + return traptype; +} + +int SetAutoResets(int i){ + autoresets = i; + return autoresets; +} + +int GetAutoResets(){ + return autoresets; +} + +string SetShadowObject(string str){ + if(last(str,2) == ".c") str = truncate(str,2); + if(!file_exists(str+".c")) error("Cant find shadow file: "+str+".c"); + if(strsrch(str,"/shadows/")) error("Invalid location for a shadow file."); + shadow_object = str; + return shadow_object; +} + +string GetShadowObject(){ + return shadow_object; +} + +void create(){ + item::create(); + SetId( ({ "trap", "sample trap" }) ); + SetAdjectives( ({ "simple","sample" }) ); + SetShort("a sample trap"); + SetLong("It is a simple sample trap."); + SetMass(50); + SetBaseCost(500); + SetNoCondition(1); +} + +void init(){ + item::init(); +} + +varargs mixed CanBoobytrap(object who, mixed what){ + if(!environment() || environment() != who) + return "#You don't have that."; + //return 0; + return 1; +} + +varargs int eventBoobytrap(object who, mixed target, mixed trap){ + object shadowtrap; + if(stringp(target)) target = to_object(target); + if(!target){ + write("It seems that cannot be boobytrapped."); + return 1; + } + if(living(target)){ + write("You cannot boobytrap a living thing."); + return 1; + } + shadowtrap = new(shadow_object); + if(!shadowtrap){ + write("There is somethign wrong with the boobytrap. You fail to set it."); + return 1; + } + if(this_player()){ + if(this_player()->GetSkill("concealment")) + traplevel += this_player()->GetSkill("concealment")["level"]; + traplevel += random(this_player()->GetStat("luck")["level"]); + traplevel += this_player()->GetStat("coordination")["level"]; + write("You boobytrap "+target->GetShort()+" with your "+remove_article(trap->GetShort())+"."); + say(this_player()->GetCapName()+" seems to attach something to "+target->GetShort()+"."); + } + + shadowtrap->SetTrapDescription(this_object()->GetLong()); + shadowtrap->SetTrapType(traptype); + shadowtrap->SetTrapLevel(traplevel); + shadowtrap->SetAutoResets(autoresets); + shadowtrap->eventShadow(target); + this_object()->eventMove(ROOM_FURNACE); + return 1; +} diff --git a/lib/lib/std/boobytrap_shadow.c b/lib/lib/std/boobytrap_shadow.c new file mode 100644 index 0000000..a6dbe9a --- /dev/null +++ b/lib/lib/std/boobytrap_shadow.c @@ -0,0 +1,292 @@ +#include <lib.h> +#include <boobytraps.h> +inherit LIB_SHADOW; +inherit LIB_CLOSE; +inherit LIB_GET; +inherit LIB_DROP; +inherit LIB_LOCK; +inherit LIB_STEAL; + +int traptype = 0; +int traplevel = 0; +int autoresets = 0; +string shadow_object = ""; +string trap_description = ""; + +int SetTrapType(int i){ + traptype = i; + return traptype; +} + +int GetTrapType(){ + return traptype; +} + +int SetTrapLevel(int i){ + traplevel = i; + return traplevel; +} + +int GetTrapLevel(){ + return traplevel; +} + +string SetTrapDescription(string str){ + trap_description = str; + return trap_description; +} + +string GetTrapDescription(){ + return trap_description; +} + +int SetAutoResets(int i){ + autoresets = i; + return autoresets; +} + +int GetAutoResets(){ + return autoresets; +} + +void create(){ + parse_init(); +} + +int eventShadow(object ob){ + return shadow::eventShadow(ob); +} + +varargs mixed SpringTrap(mixed arg1, mixed arg2){ + if(!autoresets){ + eventUnshadow(); + } + else autoresets--; + return 1; +} + +varargs mixed eventDisarm(mixed args...){ + write("You successfully disarm the trap!"); + eventUnshadow(); + return 1; +} + +varargs mixed CanOpen(object who, object tool){ + object ob = GetShadowedObject(); + if(!ob) return 0; + if(ob->GetDoor()) ob = ob->GetDoor(); + return ob->CanOpen(who, tool); +} + +varargs mixed eventOpen(object who, object tool){ + object ob = GetShadowedObject(); + mixed ret; + if(!ob) return 0; + ret = ob->eventOpen(who, tool); + if(traptype & BOOBYTRAP_OPEN) SpringTrap(who, tool); + return ret; +} + +varargs mixed CanClose(object who, string id){ + object ob = GetShadowedObject(); + if(!ob) return 0; + if(ob->GetDoor()) ob = ob->GetDoor(); + return ob->CanClose(who, id); +} + +mixed eventClose(object who){ + object ob = GetShadowedObject(); + mixed ret; + if(!ob) return 0; + ret = ob->eventClose(who); + if(traptype & BOOBYTRAP_CLOSE) SpringTrap(who); + return ret; +} + +mixed direct_get_obj(object target){ + object ob = GetShadowedObject(); + if(!ob) return 0; + return ob->direct_get_obj(target); +} + +mixed direct_get_obj_out_of_obj(object target, object src){ + object ob = GetShadowedObject(); + if(!ob) return 0; + return ob->direct_get_obj_out_of_obj(target, src); +} + +mixed direct_get_obj_from_obj(object target, object src){ + object ob = GetShadowedObject(); + if(!ob) return 0; + return ob->direct_get_obj_out_of_obj(target, src); +} + +mixed direct_get_obj_obj(object target, object src){ + object ob = GetShadowedObject(); + if(!ob) return 0; + return ob->direct_get_obj_out_of_obj(target, src); +} + +mixed GetPreventGet(){ + object ob = GetShadowedObject(); + if(!ob) return 0; + return ob->GetPreventGet(); +} + +mixed CanGet(object who){ + object ob = GetShadowedObject(); + if(!ob) return 0; + return ob->CanGet(who); +} + +mixed eventGet(object who){ + object ob = GetShadowedObject(); + mixed ret; + if(!ob) return 0; + ret = ob->eventGet(who); + if(traptype & BOOBYTRAP_GET) SpringTrap(who); + return ret; +} + +mixed direct_drop_obj(object target){ + object ob = GetShadowedObject(); + if(!ob) return 0; + return ob->direct_drop_obj(target); +} + +int GetDestructOnDrop(){ + object ob = GetShadowedObject(); + if(!ob) return 0; + return ob->GetDestructOnDrop(); +} + +mixed GetPreventDrop(){ + object ob = GetShadowedObject(); + if(!ob) return 0; + return ob->GetPreventDrop(); +} + +mixed CanDrop(object who){ + object ob = GetShadowedObject(); + if(!ob) return 0; + return ob->CanDrop(who); +} + +mixed eventDrop(object who){ + object ob = GetShadowedObject(); + mixed ret; + if(!ob) return 0; + ret = ob->eventDrop(who); + if(traptype & BOOBYTRAP_DROP) SpringTrap(who); + return ret; +} + +mixed CanLock(object who, string id){ + object ob = GetShadowedObject(); + if(!ob) return 0; + return ob->CanLock(who, id); +} + +varargs mixed eventLock(object who, mixed arg1, mixed arg2){ + object ob = GetShadowedObject(); + mixed ret; + if(!ob) return 0; + ret = ob->eventLock(who,arg1,arg2); + if(traptype & BOOBYTRAP_LOCK) SpringTrap(who); + return ret; +} + +varargs mixed CanUnlock(object who, string id, object key){ + object ob = GetShadowedObject(); + if(!ob) return 0; + return ob->CanUnlock(who, id, key); +} + +varargs mixed eventUnlock(object who, mixed arg1, mixed arg2){ + object ob = GetShadowedObject(); + mixed ret; + if(!ob) return 0; + ret = ob->eventUnlock(who, arg1, arg2); + if(traptype & BOOBYTRAP_UNLOCK) SpringTrap(who); + return ret; +} + +mixed CanSteal(object who){ + object ob = GetShadowedObject(); + if(!ob) return 0; + return ob->CanSteal(who); +} + +mixed eventSteal(object who){ + object ob = GetShadowedObject(); + mixed ret; + if(!ob) return 0; + ret = ob->eventSteal(who); + if(traptype & BOOBYTRAP_STEAL) SpringTrap(who); + return ret; +} + +mixed CanPick(object who, string id){ + object ob = GetShadowedObject(); + if(!ob) return 0; + return ob->CanPick(who, id); +} + +varargs mixed eventPick(object who, string str, object tool){ + object ob = GetShadowedObject(); + mixed ret; + if(!ob) return 0; + ret = ob->eventPick(who, str, tool); + if(traptype & BOOBYTRAP_PICK) SpringTrap(who); + return ret; +} + +mixed direct_pick_str_on_obj(string str, object target, string str2, + string id){ + object ob = GetShadowedObject(); + if(!ob) return 0; + return ob->direct_pick_str_on_obj(str,target,str2,id); +} + +mixed direct_pick_str_on_obj_with_obj(string str, object target, object tool, + string str2, string targ_id){ + object ob = GetShadowedObject(); + if(!ob) return 0; + return ob->direct_pick_str_on_obj_with_obj(str,target,tool,str2,targ_id); +} + +string GetShort(){ + object ob = GetShadowedObject(); + if(!ob) return ""; + return ob->GetShort(); +} + +string GetKeyName(){ + object ob = GetShadowedObject(); + if(!ob) return ""; + return ob->GetKeyName(); +} + +mixed eventEquip(object who, string array limbs){ + object ob = GetShadowedObject(); + mixed ret; + if(!ob) return 0; + ret = ob->eventEquip(who, limbs); + if(function_exists("GetWear",ob)){ + if(traptype & BOOBYTRAP_WEAR) SpringTrap(who); + } + else if(traptype & BOOBYTRAP_WIELD) SpringTrap(who); + return ret; +} + +mixed eventUnequip(object who){ + object ob = GetShadowedObject(); + mixed ret; + if(!ob) return 0; + ret = ob->eventUnequip(who); + if(function_exists("GetWear",ob)){ + if(traptype & BOOBYTRAP_REMOVE) SpringTrap(who); + } + else if(traptype & BOOBYTRAP_UNWIELD) SpringTrap(who); + return ret; +} diff --git a/lib/lib/std/book.c b/lib/lib/std/book.c new file mode 100644 index 0000000..d5aa9e7 --- /dev/null +++ b/lib/lib/std/book.c @@ -0,0 +1,69 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_ITEM; + +string array chapters, globalheader; +string Title = "Generic Book"; +string Source = "/obj/book_source"; +static mapping BookItems = ([]); +static mapping BookReads = ([]); + +string globalstr, globalstr2; + +void LoadBook(); + +string ReadBook(mixed args...){ + return BOOKS_D->GetBookRead(Source, args); +} + +string ReadBookIndex(){ + return BOOKS_D->GetBookIndex(Source); +} + +void SetTitle(string title){ + if(title) Title = title; + BOOKS_D->SetBookTitle(Source, title); +} + +mixed GetTitle(){ + return BOOKS_D->GetBookTitle(Source); +} + +void SetSource(string source){ + if(source && directory_exists(source)) Source = source; +} + +string GetSource(){ + if(Source) return Source; + else return ""; +} + +mixed *eventLoadChapters(){ + return BOOKS_D->LoadChapters(Source); +} + +string eventLoadIndex(){ + return BOOKS_D->LoadIndex(Source); +} + +void create(){ + ::create(); + call_out( (: LoadBook :), 1); + SetDefaultRead("Try \"read chapter 1 in book\" or " + "\"read index in book\""); +} + +void init(){ + ::init(); +} + +void LoadBook(){ + mixed *map_array = this_object()->eventLoadChapters(); + SetItems(map_array); + AddItem( "index", "This is a list of the chapters in this book."); + SetRead("index", (: ReadBookIndex :)); + foreach(mixed key, mixed val in map_array){ + SetRead(key, (: ReadBook :)); + } +} diff --git a/lib/lib/std/bot_corpse.c b/lib/lib/std/bot_corpse.c new file mode 100644 index 0000000..301534f --- /dev/null +++ b/lib/lib/std/bot_corpse.c @@ -0,0 +1,64 @@ +#include <lib.h> +#include <medium.h> +#include <message_class.h> + +inherit LIB_CORPSE; +int stank; + +void create(){ + corpse::create(); + SetId(({"chassis","body","synthetics"})); + SetAdjectives(({"melting","corroding"})); +} + +void init(){ + ::init(); + if(environment() && environment()->GetMedium() == MEDIUM_LAND) stank = 1; +} + +int eventDecay(){ + if( !environment() ){ + Destruct(); + return 0; + } + Fresh = 0; + switch(Count){ + case 10: + if(stank) + environment()->eventPrint(possessive_noun(Owner) + " chassis " + + "begins to corrode.", MSG_ROOMDESC); + SetId(GetId()..., "chassis", "body"); + SetAdjectives(GetAdjectives()..., "melting", "corroding"); + SetShort("the corroding chassis of an artificial body"); + SetSmell("The chassis emits an acrid chemical odor."); + break; + case 20: + if(stank) + environment()->eventPrint("An acrid chemical odor fills the entire " + "area.", MSG_ROOMDESC); + SetId(GetId()..., "synthetics", "pile", "pile of synthetics"); + SetShort("a pile of corroding synthetics"); + SetSmell("Its smell is nearly unbearable."); + break; + case 30: + Destruct(); + return 0; + } + Count++; + return Count; +} + +void SetCorpse(object who){ + string tmpshort = who->GetShort(); + if(sizeof(who->GetRiders())) tmpshort = who->GetPlainShort(); + SetKeyName(who->GetKeyName()); + SetId(({ "remains","wreckage",who->GetId()... }) ); + Owner = who->GetCapName(); + Race = who->GetRace(); + Count = 1; + Fresh = 1; + SetShort("the wreckage of "+tmpshort); + SetLong("As you look closely at " + who->GetCapName() + + ", you notice that " + nominative(who) + + " does not appear to be moving."); +} diff --git a/lib/lib/std/bot_limb.c b/lib/lib/std/bot_limb.c new file mode 100644 index 0000000..ffa2a06 --- /dev/null +++ b/lib/lib/std/bot_limb.c @@ -0,0 +1,52 @@ +#include <lib.h> +#include <medium.h> + +inherit LIB_LIMB; + +int stank; + +static void create(){ + limb::create(); +} + +void init(){ + ::init(); + if(environment() && environment()->GetMedium() == MEDIUM_LAND) stank = 1; +} + +int eventDecay(){ + if( !environment() ){ + CallOut = -1; + Destruct(); + return 0; + } + switch(Count){ + case 10: + if(stank) + message("smell", "The "+Limb+" rapidly corrodes.", environment()); + SetShort("the corroding remnant of a " + Limb); + break; + case 20: + if(stank) + message("smell", "An acrid chemical odor fills the area.", + environment()); + SetShort("some corroded chemicals"); + break; + case 30: + CallOut = -1; + Destruct(); + return 0; + } + Count++; + return Count; +} + +void SetLimb(string limb, string owner, string race){ + SetKeyName(limb); + SetId( ({ "limb", Limb = limb }) ); + Owner = owner; + Race = race; + Count = 1; + SetShort("a melting " + possessive_noun(Race) + " " +Limb); + SetLong("This limb is rapidly corroding into its component chemicals."); +} diff --git a/lib/lib/std/chair.c b/lib/lib/std/chair.c new file mode 100644 index 0000000..fb2f0c8 --- /dev/null +++ b/lib/lib/std/chair.c @@ -0,0 +1,27 @@ +/* /lib/chair.c + * From the Dead Souls Mud Library + * A thing you can sit in + * Created by Descartes of Borg 961221 + * Version: @(#) chair.c 1.1@(#) + * Last modified: 96/12/21 + */ + +#include <lib.h> + +inherit LIB_SIT; +inherit LIB_SURFACE; + +void create(){ + surface::create(); + SetMaxSitters(1); + SetMaxCarry(100); + SetMass(500); +} + +int CanGet(object who){ + if(sit::CanGet(who)) + return surface::CanGet(who); + else return 0; +} + +/* Nothing else needs to happen here */ diff --git a/lib/lib/std/corpse.c b/lib/lib/std/corpse.c new file mode 100644 index 0000000..f020a68 --- /dev/null +++ b/lib/lib/std/corpse.c @@ -0,0 +1,279 @@ +/* /lib/corpse.c + * from the Dead Souls LPC Library + * standard corpse object + * created by Descartes of Borg 960711 + * Version: @(#) corpse.c 1.10@(#) + * Last Modified: 96/12/31 + */ + +#include <lib.h> +#include <medium.h> +#include <respiration_types.h> +#include <message_class.h> + +inherit LIB_SURFACE; + +int Count, CallOut, Fresh; +string Owner, Race; +mapping Stats, Skills; +string BaseFile, Class, Gender, LivingShort, LivingLong; +int Player, Level, slowdecay, nodecay; +string array MissingLimbs; +object Playerob; +mapping Equipped = ([]); + +mixed direct_resurrect_obj(){ return 1; } +mixed indirect_resurrect_obj(){ return 1; } + +int eventDecay(){ + int smell, medium, rtype; + if(nodecay) return 0; + if( !room_environment() ){ + Destruct(); + return 0; + } + medium = environment()->GetMedium(); + rtype = environment()->GetRespirationType(); + Fresh = 0; + if(rtype & R_AIR) smell = 1; + if(medium == MEDIUM_SPACE && random(100) < 90) return 0; + switch(Count){ + case 10: + if(smell){ + environment()->eventPrint(possessive_noun(Owner) + " corpse " + + "is starting to stink.", MSG_ROOMDESC); + SetId(GetId()..., "corpse", "remains","flesh","pile","pile of flesh"); + SetAdjectives(GetAdjectives()..., "stinky", "rotting"); + SetShort("the stinky remains of a rotting corpse"); + SetSmell("This corpse is beginning to stink up the entire area."); + } + break; + case 20: + if(smell){ + environment()->eventPrint("A rotting stench fills the entire " + "area.", MSG_ROOMDESC); + SetId(GetId()..., "flesh", "pile", "pile of flesh"); + SetShort("a pile of rotting flesh"); + SetSmell("Its smell is nearly unbearable."); + } + break; + case 30: + Destruct(); + return 0; + } + if(slowdecay){ + if(random(100) > slowdecay) Count++; + } + else Count++; + return Count; +} + +static int Destruct(){ + return ::Destruct(); +} + +void SetCorpse(object who){ + object *worn = ({}); + string tmpshort = who->GetShort(); + if(sizeof(who->GetRiders())) tmpshort = who->GetPlainShort(); + SetKeyName(who->GetKeyName()); + SetId(({ "body","corpse",who->GetId()... }) ); + Owner = who->GetCapName(); + Race = who->GetRace(); + Count = 1; + Fresh = 1; + SetShort("the corpse of "+tmpshort); + SetLong("As you look closely at " + who->GetCapName() + + ", you notice that " + nominative(who) + + " does not appear to be moving."); + Skills = who->GetSkillsMap(); + Stats = who->GetStatsMap(); + Level = who->GetLevel(); + Gender = who->GetGender(); + Class = who->GetClass(); + MissingLimbs = who->GetMissingLimbs(); + Player = interactive(who); + Playerob = who; + BaseFile = base_name(who)+".c"; + if(who->GetProperty("basefile") && !strsrch(BaseFile, LIB_SENTIENT)){ + BaseFile = who->GetProperty("basefile"); + } + LivingLong = who->GetLong(); + LivingShort = who->GetShort(); + SetMaxCarry(who->GetMaxCarry()); + worn = who->GetWorn(); + worn += who->GetWielded(); + foreach(mixed thing in worn){ + if(arrayp(thing) && sizeof(thing)) thing = thing[0]; + if(!Equipped) Equipped = ([]); + if(!thing || !objectp(thing)) continue; + if(Equipped[file_name(thing)]) continue; + Equipped[file_name(thing)] = + ([ "object" : thing, "where" : thing->GetWorn() ]); + } + if(Player){ + SetNoClean(1); + slowdecay = 50; + } +} + +int isPlayer(){ + return Player; +} + +int isCorpse(){ + return 1; +} + +int isFreshCorpse(){ + return Fresh; +} + +string GetHealthShort(){ + return "%^RED%^" + GetShort(); +} + +string GetOwner(){ return Owner; } + +string GetRace(){ return Race; } + +string GetSaveString(){ return 0; } + +int CanReceive(object ob){ return 1; } + + +static void create(){ + ::create(); + SetId( ({ "corpse", "flesh", "remains" }) ); + SetAdjectives( ({"pile of", "rotting", "stinky"}) ); + Count = 0; + CallOut = 0; + Owner = 0; + Race = 0; + SetNoCondition(1); +} + +int direct_animate_obj(){ + return 1; +} + +int direct_offer_obj(){ + return 1; +} + +string GetItemCondition(){ return "";} + +mapping SetStats(mapping stats){ + Stats = stats; + return Stats; +} + +mapping GetStats(){ + return Stats; +} + +mapping SetSkills(mapping skills){ + Skills = skills; + return Skills; +} + +mapping GetSkills(){ + return Skills; +} + +string SetGender(string gender){ + return Gender = gender; +} + +string GetGender(){ + return Gender; +} + +int SetLevel(int level){ + return Level = level; +} + +int GetLevel(){ + return Level; +} + +string SetClass(string the_class){ + return Class = the_class; +} + +string GetClass(){ + return Class; +} + +string array SetMissingLimbs(string *limbs){ + return MissingLimbs = limbs; +} + +string array GetMissingLimbs(){ + return MissingLimbs; +} + +object GetPlayerob(){ + return Playerob; +} + +string GetCapName(){ + return Owner; +} + +string SetBaseFile(string file){ + return BaseFile = file; +} + +string GetBaseFile(){ + return BaseFile; +} + +string SetLivingShort(string short){ + return LivingShort = short; +} + +string GetLivingShort(){ + return LivingShort; +} + +string SetLivingLong(string long){ + return LivingLong = long; +} + +string GetLivingLong(){ + return LivingLong; +} + +int SetNoDecay(int i){ + if(i) nodecay = 1; + else nodecay = 0; + return nodecay; +} + +int GetNoDecay(){ + return nodecay; +} + +int SetSlowDecay(int i){ + if(i) slowdecay = i; + else slowdecay = 0; + return slowdecay; +} + +int GetSlowDecay(){ + return slowdecay; +} + +int SetCount(int i){ + Count = i; + return Count; +} + +int GetCount(int i){ + return Count; +} + +mapping GetEquipped(){ + return copy(Equipped); +} diff --git a/lib/lib/std/daemon.c b/lib/lib/std/daemon.c new file mode 100644 index 0000000..22a3f72 --- /dev/null +++ b/lib/lib/std/daemon.c @@ -0,0 +1,56 @@ +/* /lib/daemon.c + * From Dead Souls Mud Library + * Standard inheritable for daemon objects + * created by Descartes of Borg 940211 + * Version: @(#) daemon.c 1.4@(#) + * Last modified: 96/12/16 + */ + +#include <lib.h> +#include <privs.h> + +inherit LIB_CLEAN; + +static private string DaemonSaveFile = 0; + +/* ******************** daemon.c attributes ********************** */ +string GetSaveFile(){ + return DaemonSaveFile; +} + +static string SetSaveFile(string str){ + return (DaemonSaveFile = save_file(str)); +} + +/* ********************* daemon.c events ************************* */ +int eventDestruct(){ + if( !master()->valid_apply(({ PRIV_ASSIST })) ){ + return 0; + } + return clean::eventDestruct(); +} + +varargs int eventRestore(int do_not_zero_out){ + if( !DaemonSaveFile ){ + return 0; + } + if( unguarded((: file_exists(DaemonSaveFile) :)) ){ + return RestoreObject(DaemonSaveFile, do_not_zero_out); + } + else { + return 1; + } +} + +varargs int eventSave(int save_zero_values){ + if( !DaemonSaveFile ){ + return 0; + } + return SaveObject(DaemonSaveFile, save_zero_values); +} + +/* ******************* daemon.c driver applies ********************* */ +static void create(){ + eventRestore(1); + SetNoClean(1); +} diff --git a/lib/lib/std/dummy.c b/lib/lib/std/dummy.c new file mode 100644 index 0000000..56f74b9 --- /dev/null +++ b/lib/lib/std/dummy.c @@ -0,0 +1,17 @@ +/* /lib/obj/dummy.c + * From the Dead Souls Mud Library + * A dummy item object that handles item descriptions and such + * Created by Descartes of Borg 961014 + * Version: @(#) dummy.c 1.18@(#) + * Last modified: 96/12/31 + */ + +#include <lib.h> + +inherit LIB_BASE_DUMMY;; +inherit LIB_SHADOW_HOOK; + +/* ******************* dummy.c driver applies ******************** */ +varargs static void create(string array id, mixed long, string array adj){ + base_dummy::create(id, long, adj); +} diff --git a/lib/lib/std/furnace.c b/lib/lib/std/furnace.c new file mode 100644 index 0000000..e1f35ff --- /dev/null +++ b/lib/lib/std/furnace.c @@ -0,0 +1,42 @@ +#include <lib.h> +#include <daemons.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create(){ + room::create(); + SetAmbientLight(30); + SetShort("the furnace"); + SetLong("The furnace. Things that arrive here are "+ + "incinerated. You probably shouldn't be here. Go down to get out."); + SetProperties(([ + "no attack" : 1, + ])); + SetExits( ([ "down" : ROOM_START ]) ); + if(base_name(this_object()) != LIB_FURNACE){ + call_out((: reload_room :), 600, load_object(base_name(this_object()))); + set_heart_beat(1); + } + SetNoModify(1); +} + +int CanReceive(object ob){ + return room::CanReceive(ob); +} + +void init(){ + ::init(); +} + +void heart_beat(){ + if(base_name(this_object()) != LIB_FURNACE){ + if(sizeof(all_inventory(this_object()))){ + foreach(object ob in deep_inventory(this_object())){ + if(ob && interactive(ob)) + ob->eventMove(ROOMS_D->GetVoid(ob)); + else ob->eventDestruct(); + } + } + } +} diff --git a/lib/lib/std/germ.c b/lib/lib/std/germ.c new file mode 100644 index 0000000..d4b8cda --- /dev/null +++ b/lib/lib/std/germ.c @@ -0,0 +1,363 @@ +/* /lib/germ.c + * From the Dead Souls Mud Library + * Germs which cause disease + * created by Descartes of Borg 940905 + * Version: @(#) germ.c 1.12@(#) + * Last modified: 97/01/01 + */ + +#include <lib.h> +#include ROOMS_H +#include <daemons.h> + +inherit LIB_ITEM; + +private int Communicable = 1; +mixed Cure = 0; +private static function Infect = 0; +private static int LastHeartBeat = time(); +private mixed LifeSpan = 60; +private int CannotInfect = 0; +private int debug = 0; +private string Type = "cold"; +private string GermName = "generic germ"; +private string array ImmuneRaces = ({ "android", "tree", + "plant", "elemental", "fish", "gargoyle", "god", "golem", "insect", + "slug", "snake", "wraith", "zombie", "bot", "strider", "vehicle", + "mech" }); + +mixed eventMultiply(); + +/* *************** /lib/germ.c data functions *************** */ +int isGerm(){ + return 1; +} + +int GetCommunicable(){ + return Communicable; +} + +int GetCannotInfect(){ + return CannotInfect; +} + +int SetCannotInfect(int i){ + if(!i) i = 0; + CannotInfect = i; + return CannotInfect; +} + +int SetGermName(string str){ + if(str) GermName = str; + return 1; +} + +string GetGermName(){ + return GermName; +} + +/* + * int SetCommunicable(int x); + * int x - how infectious the germ is + * + * description: + * Makes the germ multiply and infect on its own. The more + * communicable, the easier it infects hosts and the easier + * it multiplies. + * Non-communicable germs must be forced to infect hosts + * + * returns the degree to which it is communicable + */ +int SetCommunicable(int x){ + if( x > 100 ) x = 100; + return (Communicable = x); +} + +mixed GetCure(){ + return Cure; +} + +/* mixed SetCure(mixed val) + * mixed val - function to test whether germ is cured + * or int indicating how hard it is to cure + * -1 means incurable + * + * description + * If a function, then that function will be used to + * determine if a given cure attempt is successful. + * That function should return 1 for success, 0 for failure + * If an int and -1, the germ is incurable + * If an int > 0, then that much of a cure of the right + * type is needed to cure the disease + * + * returns the successfully set value + */ +mixed SetCure(mixed val){ + if(intp(val)){ + Cure=val; + return; + } + return (Cure = val); +} + +function GetInfect(){ + return Infect; +} + +/* function SetInfect(function f) + * function f - Function to be called whenever this germ + * infects a host + * + * Sets a function to be called whenever a host is infected + * + * returns the function to be called + */ +function SetInfect(function f){ + Infect = f; + return f; +} + +int GetLifeSpan(){ + return LifeSpan; +} + +/* int SetLifeSpan(int x) + * int x - the length of time the germ can live outside + * a host + * + * description + * Sets the amount of time that can pass for the germ + * to exist without a host + * + * returns the new life span + */ +int SetLifeSpan(mixed x){ + if(functionp(x)){ + x = evaluate(x); + } + if(!intp(x)) x = 60; + //if( x > 600 ) x = 600; + return (LifeSpan = x); +} + +string GetType(){ + return Type; +} + +/* string SetType(string type) + * string type - the nature of the infection + * + * description + * determines what sort of cure is needed + * valid values are: + * viral + * bacterial + * parasite + * returns the new germ type + */ +string SetType(string type){ + Type=type; + if(!Type || Type == "") Type = "foo"; + return Type; +} + +/* *************** /lib/germ.c events *************** */ +/** + * This event is triggered from within the player object by some + * attempt by a cleric or other some such thing to cure the player. + */ +mixed eventCure(object who, int x, string type){ + if( type != GetType() ){ // Can't cure this + return 0; + } + if( Cure == -1 ){ // This is incureable + return 0; + } + if( functionp(Cure) ){ + mixed tmp = evaluate(Cure, who, x, type); + + if( tmp != 1 ){ + return tmp; + } + Cure = 0; + } + else if( intp(Cure) ){ + Cure -= x; + } + else { + error("Bad argument 2 to eventCure()."); + } + if( Cure > 0 ){ + return 0; + } + set_heart_beat(0); + if(this_object()) this_object()->eventMove(ROOM_FURNACE); + eventDestruct(); + return 1; +} + +mixed eventEncounter(object who){ + if( !living(who) ){ + return 1; + } + if( !query_heart_beat() ){ + set_heart_beat(5); + } + if(this_object() && environment(this_object())) eventMultiply(); + return 1; +} + +void init(){ + object env = environment(); + object *livs; + if(!env) return; + ::init(); + livs = (get_livings(env) || ({})); + if(living(env)) env = environment(env); + livs += get_livings(env); + set_heart_beat(1); + if(sizeof(livs)){ + foreach(object liv in livs){ + eventEncounter(liv); + } + } +} + +mixed eventInfect(object ob){ + mixed tmp; + object *presbane; + string race; + string *bane = ({}); + if(!ob){ + return 0; + } + + if(RELOAD_D->GetWarmBootInProgress()){ + return 0; + } + if(environment() && base_name(environment()) == ROOM_VOID){ + return 0; + } + if(!this_object()){ + return 0; + } + if(!ob){ + return 0; + } + if(!ob->CanReceive(this_object())){ + return 0; + } + race = ob->GetRace(); + + //presbane = present("bane",ob); + presbane = filter(all_inventory(ob), (: inherits(LIB_BANE,$1) :) ); + if(sizeof(presbane)){ + foreach(object foo in presbane){ + bane += foo->QueryBane(); + } + } + + if(sizeof(bane)){ + if(member_array(GetKeyName(),bane) != -1) return 0; + if(member_array("all",bane) != -1) return 0; + foreach(string foo in GetId()){ + if(member_array(foo,bane) != -1) return 0; + } + } + + if(present(this_object()->GetKeyName(),ob) ) return 0; + if(race && member_array(race, ImmuneRaces) != -1) return 0; + if(ob->GetUndead() == 1) return 0; + if(ob->GetAquatic() == 1) return 0; + if(ob->GetNonCarbonBased() == 1) return 0; + + if( functionp(Infect) ){ + if(!this_object()){ + return 0; + } + tmp = evaluate(Infect, ob); + if( tmp == 1 ){ + eventMove(ob); + if(this_object() && environment(this_object()) != ob){ + eventMove(ROOM_FURNACE); + set_heart_beat(0); + } + else set_heart_beat(5); + return tmp; + } + } + if(!eventMove(ob)) eventMove(ROOM_FURNACE); + set_heart_beat(5); + return 1; +} + + +mixed eventMultiply(){ + object ob, germ, winner; + object *targs; + + if( Communicable > random(1000) && !CannotInfect){ + + if( (ob = environment()) && living(ob) ){ + if(environment(environment())) ob = environment(environment()); + } + + if(!ob) return 0; + + //move to the host's environment + if(!present(this_object()->GetName(),ob) ){ + germ = new(base_name(this_object())); + if( germ && living(ob) ) germ->eventInfect(ob); + else if(!germ->eventMove(ob)) germ->eventMove(ROOM_FURNACE); + } + + //find someone to infect + if(!sizeof(get_livings(ob))) return 0; + targs = filter(get_livings(ob), (: !query_carrying($1,base_name(this_object())) :) ); + if(sizeof(targs)) winner = targs[random(sizeof(targs))]; + if(this_object() && winner) new(base_name(this_object()))->eventInfect(winner); + } + return 1; +} + +void eventSuffer(object ob){ +} + +/* *************** /lib/germ.c driver applies *************** */ + +static void create(){ + item::create(); + AddSave(({ "Communicable", "LifeSpan", "Type" })); + SetInvis(1); + SetMass(0); + SetValue(0); + SetPreventDrop(""); + SetPreventGet(""); + SetPreventPut(""); +} + +static void heart_beat(){ + object env; + int interval; + + if(!env = environment()) eventMove(ROOM_FURNACE); + + interval = time() - LastHeartBeat; + LastHeartBeat = time(); + + if( Communicable ){ + eventMultiply(); + } + + if( env && living(env) && environment(env) && member_array(env->GetRace(),ImmuneRaces) == -1){ + eventSuffer(env); + } + + if(LifeSpan == -1) return; + LifeSpan -= interval; + if( LifeSpan < 5 ){ + if(this_object()) this_object()->eventMove(ROOM_FURNACE); + eventDestruct(); + return; + } +} diff --git a/lib/lib/std/item.c b/lib/lib/std/item.c new file mode 100644 index 0000000..c8c14a4 --- /dev/null +++ b/lib/lib/std/item.c @@ -0,0 +1,377 @@ +/* /lib/item.c + * from the Dead Souls LPC Library + * inheritable object for all tangible game objects + * created by Descartes of Borg 950207 + * Version: @(#) item.c 1.30@(#) + * Last Modified: 97/01/01 + */ + +#include <lib.h> +#include <dirs.h> +#include <daemons.h> + +inherit LIB_BURY; +inherit LIB_DETECT; +inherit LIB_DETERIORATION; +inherit LIB_DROP; +inherit LIB_GET; +inherit LIB_GIVE; +inherit LIB_LOCK_WITH; +inherit LIB_MASS; +inherit LIB_MOVE; +inherit LIB_OBJECT; +inherit LIB_PERSIST; +inherit LIB_PUT; +inherit LIB_READ; +inherit LIB_SELL; +inherit LIB_SHOW; +inherit LIB_STEAL; +inherit LIB_UNIQUENESS; +inherit LIB_VALUE; +inherit LIB_WEAPON; +inherit LIB_MONEY; +inherit LIB_FALL; +inherit LIB_SINK; +inherit LIB_SHADOW_HOOK; + +private int RetainOnDeath, nocondition; +private string QuestId = ""; + +/* ******************** item.c attributes ******************** */ +string GetExternalDesc(object who){ + string desc = object::GetExternalDesc(who); + string tmp; + + if( desc == "" ){ + return ""; + } + if( tmp = GetEquippedDescription(who) ){ + desc += tmp + "\n"; + } + if( GetBroken() ){ + desc += "\nIt appears to be broken."; + } + else if( tmp = GetItemCondition() ){ + desc += tmp; + } + return desc; +} + +int SetNoCondition(int i){ + nocondition = i; +} + +string SetQuestId(string name){ + QuestId = name; + return QuestId; +} + +string GetQuestId(){ + return QuestId; +} + +string GetItemCondition(){ + + if(nocondition) return ""; + + if( GetMaxClass() ){ + float i = to_float(GetClass()) / GetMaxClass() * 100.0; + + if(i >= 99){ + return ""; + } + else if( i > 95.0 ){ + return " It is as good as new."; + } + else if( i > 80.0 ){ + return " It is in good condition."; + } + else if( i > 70.0 ){ + return " It is in decent condition."; + } + else if( i > 50.0 ){ + return " It is somewhat worn and battered."; + } + else if( i > 30.0 ){ + return " It is worn down and dented."; + } + else if( i > 10.0 ){ + return " It is very worn down and in bad shape."; + } + else { + return " It has worn down completely."; + } + } + else { + return deterioration::GetItemCondition(); + } +} + +int GetRetainOnDeath(){ + return RetainOnDeath; +} + +int SetRetainOnDeath(int x){ + return (RetainOnDeath = x); +} + +static mixed array AddSave(mixed array vars){ + if(!vars) vars = ({}); + //vars += ({ "Properties" }); + return persist::AddSave(vars); +} + +string array GetSave(){ + return persist::GetSave(); +} + +/* ************************ item.c modals *********************** */ +mixed CanRepair(object who){ + if( GetBroken() ) return 1; + else if( !GetMaxClass() ) return "It doesn't need repairing."; + else return 1; +} + +mixed CanSteal(object who){ + if( GetWorn() ){ + return "You can't steal something equipped!"; + } + return steal::CanSteal(who); +} + +varargs mixed CanThrow(object who, object target){ + return 1; +} + +/* ********************* item.c events ************************ */ +static int Destruct(){ + if( GetWorn() && environment() ){ + eventUnequip(environment()); + } + return object::Destruct(); +} + +int eventMove(mixed dest){ + if(!this_object()) return 0; + if( !environment() && GetWorn() ){ + mixed array limbs = GetWorn(); + + SetWorn(0); + call_out((: eventRestoreEquip :), 0, limbs); + } + if( GetWorn() && environment() ){ + eventUnequip(environment()); + } + return move::eventMove(dest); +} + +void eventDeteriorate(int type){ + weapon::eventDeteriorate(); + SetDestroyOnSell(1); + SetValue(GetValue()/2); +} + +void eventRemoveBlessing(){ + SetProperty("blessed", 0); + if( living(environment()) ){ + environment()->eventPrint("%^YELLOW%^" + + capitalize(GetDefiniteShort()) + + " returns to its normal state."); + } +} + +int eventBless(int amount, int time){ + if(!amount || !time) return 0; + if(GetProperty("blessed")) return 0; + SetProperty("blessed", amount); + call_out( (: eventRemoveBlessing :), time); + if(GetProperty("blessed") > 0){ + SetProperty("magic item", "blessed"); + } + if(GetProperty("blessed") < 0){ + SetProperty("magic item", "cursed"); + } + return 1; +} + +mixed eventThrow(object who, object target){ + if( target && living(target) ){ + int skill; + + who->eventPrint("You throw " + GetShort() + " at " + + target->GetName() + "."); + target->eventPrint(who->GetName() + " throws " + GetShort() +" at you."); + environment(who)->eventPrint(who->GetName() + " throws " + + GetShort() + " at " + target->GetName() + + ".", ({ who, target }) ); + skill = (who->GetSkillLevel("projectile attack") + + who->GetStatLevel("coordination")); + skill -= (target->GetSkillLevel("projectile defense") + + target->GetStatLevel("agility"))/2; + if( GetWeaponType() != "projectile" ){ + skill = skill/2; + } + if( skill > random(100) + 1 ){ + who->AddSkillPoints("projectile attack", + target->GetSkillLevel("projectile defense") * + target->GetLevel() + 10); + target->AddSkillPoints("projectile defense", 10); + target->eventReceiveThrow(who, this_object()); + } + else { + target->AddSkillPoints("projectile defense", + who->GetSkillLevel("projectile attack") * + who->GetLevel() + 10); + who->AddSkillPoints("projectile attack", 10); + environment(who)->eventPrint(capitalize(GetShort()) + " does not " + "hit "+target->GetName() + ".",({ target, who })); + write("Your throw misses its mark."); + tell_object(target, capitalize(GetShort()) + " does not hit you."); + eventMove(environment(who)); + } + return 1; + } + else if( target ){ + who->eventPrint("You throw " + GetShort() + " at " + + target->GetShort() + "."); + environment(who)->eventPrint(who->GetName() + " throws " + + GetShort() + " at " + target->GetShort() + + ".", ({ who, target })); + tell_object(target, capitalize(GetShort()) + " throws " + + GetShort() + " at you."); + return target->eventReceiveThrow(who, this_object()); + } + if( !eventMove(environment(who)) ){ + who->eventPrint("You are not too good at throwing things."); + return 1; + } + who->eventPrint("You throw " + GetShort() + "."); + environment(who)->eventPrint(who->GetName() + " throws " + + GetShort() + ".", who); + return 1; +} + +varargs mixed eventRepair(object who, int strength, int type){ + if( !who || !strength ) return 0; + if( !GetMaxClass() ) return 0; + while(strength--){ + if( GetClass() < GetMaxClass() ){ + SetClass(GetClass() + 1); + SetValue(GetValue() + (GetValue() / 3)); + } + else break; + } + return 1; +} + +mixed eventShow(object who, string component){ + mixed tmp = object::eventShow(who, component); + + if( component || tmp != 1 ){ + return tmp; + } + if( GetPoison() ){ + if( random(100) < who->GetSkillLevel("stealth") ){ + who->eventPrint("You notice a strange substance on it."); + } + } + return 1; +} + +/* ***************** item.c driver applies ****************** */ +static void create(){ + AddSave(weapon::GetSave() + value::GetSave() + mass::GetSave() + + deterioration::GetSave()); + steal::create(); + object::create(); +} + +varargs mixed direct_get_obj_from_obj(object item, mixed gamma,mixed alfa, mixed beta, mixed epsilon){ + if(answers_to(beta,environment(this_object()))) return 1; + return 0; +} + +mixed direct_cast_str_on_obj(){ + return 1; +} + +mixed direct_cast_str_on_str_of_obj(){ + return 1; +} + +mixed direct_balance_obj_to_obj(){ + return 1; +} + +mixed indirect_balance_obj_to_obj(){ + return 1; +} + +mixed direct_compare_obj_to_obj(){ + return 1; +} + +mixed indirect_compare_obj_to_obj(){ + return 1; +} + +mixed direct_judge_obj_to_obj(){ + return 1; +} + +mixed indirect_judge_obj_to_obj(){ + return 1; +} + +mixed direct_use_obj_to_str(){ + if( environment() != this_player() ) + return "#You need better access to it."; + else return 1; +} + +mixed direct_use_obj(){ + return direct_use_obj_to_str(); +} + +mixed direct_throw_obj_word_obj(){ + if( environment() != this_player() ){ + return "#Throw something you are not holding?"; + } + else return 1; +} + +mixed indirect_throw_obj_into_obj(){ + return 1; +} + +int direct_sacrifice_obj_to_str(string deus){ + mixed tmp; + object env; + + if( !sizeof(deus) ) return 0; + deus = lower_case(remove_article(deus)); + if( !env = environment(this_player()) ) return 0; + tmp = env->CanSacrifice(this_player(), this_object(), deus); + if( !tmp ){ + this_player()->eventPrint("This is not the place for sacrifices."); + return 0; + } + else return 1; +} + + +mixed direct_bless_obj(){ + if( environment() != this_player() ){ + return "#You don't have that!"; + } + return 1; +} + +mixed direct_curse_obj(){ + if( environment() != this_player() ){ + return "#You don't have that!"; + } + return 1; +} + +void init(){ } diff --git a/lib/lib/std/limb.c b/lib/lib/std/limb.c new file mode 100644 index 0000000..f46d7ea --- /dev/null +++ b/lib/lib/std/limb.c @@ -0,0 +1,149 @@ +/* /lib/std/limb.c + * From the Dead Souls Mud Library + * Standard limb object for severed limbs + * Created by Descartes of Borg 950329 + * Version: @(#) limb.c 1.5@(#) + * Last Modified: 96/12/31 + */ + +#include <lib.h> +#include <medium.h> +#include <respiration_types.h> + +inherit LIB_SURFACE; + +int Count = 0; +int Player = 0; +string Limb = 0; +string Owner = 0; +string Race = 0; +int CallOut = -1; +int stank, nodecay, slowdecay; + +int eventDecay(); + +string GetLimb(){ + return Limb; +} +string GetItemCondition(){ + return ""; +} + +void create(){ + surface::create(); +} + +void init(){ + surface::init(); +} + +void SetLimb(string limb, string owner, string race){ + string justlimb; + sscanf(limb,"%*s %s",justlimb); + SetKeyName(limb); + SetId( ({ limb, "flesh","pile","limb",(justlimb||"chunk") }) ); + SetAdjectives(({"severed","rotting",race})); + Limb = limb; + Owner = owner; + Race = race; + Player = interactive(previous_object()); + Count = 1; + SetShort("a rotting " + possessive_noun(Race) + " " + Limb); + SetLong("This limb has a horrible stench as it rots to nothing."); + if(Player){ + SetNoClean(1); + slowdecay = 50; + } +} + +string GetOwner(){ + return Owner; +} + +string GetRace(){ + return Race; +} + +int GetSaveString(){ + return 0; +} + +string GetShort(){ + string str = surface::GetShort(); + + if( !str ){ + str = "a limb"; + } + return str; +} + +int CanReceive(object ob){ + return 1; +} + +int Destruct(){ + return surface::Destruct(); +} + +int eventDecay(){ + int medium, rtype; + if( !room_environment() ){ + Destruct(); + return 0; + } + medium = room_environment()->GetMedium(); + rtype = room_environment()->GetRespirationType(); + if(rtype & R_AIR) stank = 1; + if(medium == MEDIUM_SPACE && random(100) < 90) return 0; + switch(Count){ + case 10: + if(stank) + message("smell", "The "+Limb+" really stinks.", environment()); + SetShort("the stinky remains of a rotting " + Limb); + break; + case 20: + if(stank) + message("smell", "A rotting stench fills the entire area.", + environment()); + SetShort("a pile of rotting flesh"); + break; + case 30: + Destruct(); + return 0; + } + if(slowdecay){ + if(random(100) > slowdecay) Count++; + } + else Count++; + return Count; +} + +int SetNoDecay(int i){ + if(i) nodecay = 1; + else nodecay = 0; + return nodecay; +} + +int GetNoDecay(){ + return nodecay; +} + +int SetSlowDecay(int i){ + if(i) slowdecay = i; + else slowdecay = 0; + return slowdecay; +} + +int GetSlowDecay(){ + return slowdecay; +} + +int SetCount(int i){ + Count = i; + return Count; +} + +int GetCount(int i){ + return Count; +} + diff --git a/lib/lib/std/lockpick.c b/lib/lib/std/lockpick.c new file mode 100644 index 0000000..59e5260 --- /dev/null +++ b/lib/lib/std/lockpick.c @@ -0,0 +1,48 @@ +#include <lib.h> + +inherit LIB_ITEM; +int picking_quality = 1; + +void create(){ + item::create(); + SetKeyName("lockpick"); + SetAdjectives(({"lockpicking","picking"})); + SetId(({ "tool","pick" })); + SetShort("a lockpick"); + SetLong("A tool for picking locks."); + SetMass(10); +} + +void init(){ + ::init(); +} + +int SetPickingQuality(int i){ + picking_quality = i; + return picking_quality; +} + +int GetPickingQuality(){ + return picking_quality; +} + +varargs mixed CanPick(mixed who, mixed what){ + if(environment(this_object()) == this_player()){ + } + return 1; +} + + +mixed indirect_pick_str_on_obj_with_obj(string str, object target, object tool, + string str2, string targ_id){ + if( remove_article(lower_case(str)) != "lock" ){ + return "Pick the what?"; + } + targ_id = remove_article(lower_case(targ_id)); + return CanPick(this_player(), targ_id); +} + + +varargs mixed eventPickLock(mixed who, mixed id, mixed tool){ + return picking_quality; +} diff --git a/lib/lib/std/room.c b/lib/lib/std/room.c new file mode 100644 index 0000000..83842f8 --- /dev/null +++ b/lib/lib/std/room.c @@ -0,0 +1,1360 @@ +/* /lib/obj/room.c + * From the Dead Souls LPC Library + * The room object used to represent any room in the game + * Created by Descartes of Borg 940711 + * Version: @(#) room.c 1.20@(#) + * Last Modified: 050912 + */ + +#ifndef NM_STYLE_EXITS +#define NM_STYLE_EXITS 1 +#endif + +#include <lib.h> +#include ROOMS_H +#include <daemons.h> +#include <function.h> +#include <medium.h> +#include <message_class.h> +#include <talk_type.h> +#include <terrain_types.h> +#include <respiration_types.h> +#include <privs.h> + +inherit LIB_SHADOW_HOOK; +inherit LIB_CLEAN; +inherit LIB_CONTAINER; +inherit LIB_EXITS; +inherit LIB_DESCRIPTION; +inherit LIB_INVENTORY; +inherit LIB_LOOK; +inherit LIB_PROPERTIES; +inherit LIB_AMBIANCE; +inherit LIB_READ; +inherit LIB_MONEY; + +private function Bury = 0; +private string Climate = "temperate"; +private int DayLight = -1970; +private int counter = 0; +private static string DayLong = 0; +private object array DummyItems = ({}); +private static int GasCheck = time(); +private float Gravity = 1.0; +private static mixed Listen = 0; +private int NightLight = -1970; +private static string NightLong = 0; +private static int NoReplace = 0; +private static int PlayerKill = 0; +private static int PoisonGas = 0; +private static int ResetNumber = 0; +private static mixed Search = 0; +private static int Shade = 0; +private static mixed Smell = 0; +private static mixed Touch = 0; +private string Town = "wilderness"; +private int DefaultExits = 1; +private int Flying = 1; +private int Sitting = 0; +private int Kneeling = 0; +private int Standing = 0; +private int Swimming = 0; +private int ObviousVisible = 1; +private int ActionChance = 10; +mapping ItemsMap = ([]); +private static mixed global_item; +private static mixed Action; +private int tick_resolution = 5; +private int TerrainType = T_OUTDOORS; +private int RespirationType; +private int Medium = MEDIUM_LAND; +private mapping ActionsMap = ([]); +private int NoSink = 0; +private string SinkRoom = ""; +private string FlyRoom = ""; +private string SkyDomain = ""; +private string Elevator = ""; +private int FlowLimit = 0; +private int array Coords = ({}); +private string array Neighbors = ({}); +private mixed array NeighborCoords = ({}); + +string GetClimate(); +int GetNightLight(); +int GetDayLight(); +int GetShade(); +varargs mixed DestructEmptyVirtual(object ob); + +mixed direct_delete_exit_str(){ + return 1; +} + +mixed indirect_delete_exit_str(){ + return 1; +} + +varargs int eventPrint(string msg, mixed arg2, mixed arg3); + +/*********** /lib/room.c data manipulation functions **********/ + +void CheckActions(){ + if(sizeof(ActionsMap)){ + foreach(mixed key, mixed val in ActionsMap){ + if( val > random(100) ){ + if(functionp(key)) evaluate(key); + else eventPrint(key); + } + } + } + + if( ActionChance > random(100) ){ + int x; + + if( functionp(Action) ) evaluate(Action); + else if( pointerp(Action) && (x = sizeof(Action)) ){ + mixed act; + + act = Action[random(x)]; + if(functionp(act)){ + evaluate(act); + return; + } + else eventPrint(act); + } + } +} + +void heart_beat(){ + counter++; + DestructEmptyVirtual(); + inventory::heart_beat(); + if(counter > 9999) counter = 0; + CheckActions(); +} + +void SetAction(int chance, mixed val){ + ActionChance = chance; + if( stringp(val) ) val = ({ val }); + else if( !functionp(val) && !pointerp(val) ) + error("Bad argument 2 to SetAction()\n"); + Action = val; +} + +mixed GetAction(){ return Action; } + +mapping SetActionsMap(mapping ActMap){ + if(ActMap && sizeof(ActMap)) ActionsMap = ActMap; + return copy(ActionsMap); +} + +mapping GetActionsMap(){ + return copy(ActionsMap); +} + +int SetFrequency(int tick){ + if(tick) tick_resolution = tick; + else tick_resolution = 5; + set_heart_beat(0); + return tick_resolution; +} + +int GetFrequency(){ + return tick_resolution; +} + +int GetTerrainType(){ + return TerrainType; +} + +int SetTerrainType(int i){ + if(i) TerrainType = i; + else return TerrainType; +} + +int AddTerrainType(int i){ + if(!bitshiftedp(i)) return 0; + else TerrainType = TerrainType | i; + return TerrainType; +} + +int RemoveTerrainType(int i){ + if(!bitshiftedp(i)) return 0; + else TerrainType = TerrainType ^ i; + return TerrainType; +} + +int GetAmbientLight(){ + int a, dayset, nightset; + + dayset = this_object()->GetDayLight(); + nightset = this_object()->GetNightLight(); + + if(dayset == -1970 && nightset == -1970 ){ + a = ambiance::GetAmbientLight(); + } + + else if( query_night() && nightset != -1970 ){ + a = nightset; + } + else if(!query_night() && dayset != -1970){ + a = dayset; + } + else { + a = ambiance::GetAmbientLight(); + } + + foreach(object ob in all_inventory()){ + a += ob->GetRadiantLight(); + } + + return a; +} + +function GetBury(){ + return Bury; +} + +function SetBury(function what){ + Bury = what; +} + +static string GetExtraLong(){ + int i; + string *l = ({}),*tmp; + string ret; + object array stuff; + ret = " "; + tmp = ({}); + stuff=all_inventory(this_object()); + for(i=0; i<sizeof(stuff);i++){ + if(sizeof(tmp = ({ stuff[i]->GetRoomAffectLong() })) ) l += tmp; + } + if( !sizeof(l) ) return 0; + ret += implode(l, " "); + return ret; +} + +string GetInternalDesc(){ + string ret, tmp; + + if( DayLong && !query_night() ){ + ret = DayLong; + } + else if( NightLong && query_night() ){ + ret = NightLong; + } + else { + ret = container::GetInternalDesc(); + } + if( !ret ){ + ret = ""; + } + if( tmp = GetExtraLong() ){ + ret += GetExtraLong(); + } + return ret; +} + +int GetResetNumber(){ + return ResetNumber; +} + +string array GetId(){ return ({}); } + +string SetDayLong(string str){ return (DayLong = str); } + +string GetDayLong(){ return DayLong; } + +string SetNightLong(string str){ return (NightLong = str); } + +string GetNightLong(){ return NightLong; } + +string SetClimate(string str){ + if(str == "indoors" && TerrainType == T_OUTDOORS) TerrainType = T_INDOORS; + return (Climate = str); +} + +string GetClimate(){ return Climate; } + +float SetGravity(float h){ return (Gravity = h); } + +float GetGravity(){ return Gravity; } + +int GetDayLight(){ + return DayLight; +} + +static int SetDayLight(int x){ + return (DayLight = x); +} + +object array GetDummyItems(){ + DummyItems = ({}); + foreach(object item in all_inventory(this_object())){ + if(base_name(item) == LIB_DUMMY){ + DummyItems += ({ item }); + } + } + return DummyItems; +} + +varargs void AddItem(mixed item, mixed val, mixed adjectives){ + object ob, same_dummy; + object *dummies = filter(all_inventory(this_object()), (: base_name(LIB_DUMMY) :) ); + global_item = item; + + if( objectp(item) ){ + same_dummy = filter(all_inventory(),(: base_name($1) == base_name(global_item) :)); + if(sizeof(same_dummy) && base_name(item) != LIB_ELEVATOR_BUTTON){ + return; + } + ob = item; + } + else { + if( stringp(item) ){ + item = ({ item }); + } + if( stringp(adjectives) ){ + adjectives = ({ adjectives }); + } + same_dummy = filter(dummies,(: member_array(global_item[0],$1->GetId()) != -1 :)); + if(sizeof(same_dummy)) return; + ob = new(LIB_DUMMY, item, val, adjectives); + } + ob->eventMove(this_object()); + DummyItems = ({ DummyItems..., ob }); +} + +mapping RemoveItem(mixed item){ + if( objectp(item) ){ + DummyItems -= ({ item }); + item->eventDestruct(); + return copy(Items); + } + else if( !arrayp(item) ){ + item = ({ item }); + } + foreach(object ob in GetDummyItems()){ + if( sizeof(ob->GetId() & item) ){ + ob->eventDestruct(); + DummyItems -= ({ ob }); + return copy(Items); + } + } +} + +mapping SetItems(mixed items){ + if(sizeof(DummyItems)) DummyItems->eventDestruct(); + DummyItems = ({}); + if( arrayp(items) ){ + items->eventMove(this_object()); + DummyItems = items; + } + else if( mapp(items) ){ + ItemsMap = items; + foreach(mixed key, mixed val in items){ + string array adjs = ({}); + object ob; + + if( objectp(key) ){ + object *same_dummy = ({}); + global_item = key; + same_dummy = filter(all_inventory() ,(: base_name($1) == base_name(global_item) :)); + if(sizeof(same_dummy)) continue; + ob = key; + } + + if( stringp(key) ){ + key = ({ key }); + } + else { + if( sizeof(key) == 2 && arrayp(key[0]) ){ + adjs = key[1]; + key = key[0]; + } + } + ob = new(LIB_DUMMY, key, val, adjs); + if(ob){ + ob->eventMove(this_object()); + DummyItems = ({ DummyItems..., ob }); + } + } + } + else { + error("Bad argument 1 to SetItems(), expected object array or " + "mapping.\n"); + } + return copy(ItemsMap); +} + +mapping GetItemsMap(){ + return copy(ItemsMap); +} + +mapping GetSmellMap(){ + mapping Smells = ([]); + foreach(object ob in GetDummyItems()){ + if( ob->GetSmell() ){ + Smells[ob->GetId()] = ob->GetSmell(); + } + } + if(this_object()->GetSmell()) Smells["default"] = this_object()->GetSmell(); + return copy(Smells); + +} + +mapping GetListenMap(){ + mapping Listens = ([]); + foreach(object ob in GetDummyItems()){ + if( ob->GetListen() ){ + Listens[ob->GetId()] = ob->GetListen(); + } + } + if(this_object()->GetListen()) Listens["default"] = this_object()->GetListen(); + return copy(Listens); +} + +mapping QueryMap(string str){ + switch(str){ + case "SetItems" : return GetItemsMap();break; + case "SetSmell" : return GetSmellMap();break; + case "SetListen" : return GetListenMap();break; + case "SetInventory" : return this_object()->GetInventory();break; + default : return ([]); + } + +} + +varargs void AddListen(mixed item, mixed val){ + if( !val ){ + Listen = item; + return; + } + if( !item || item == "default" ){ + Listen = val; + return; + } + if( stringp(item) ){ + item = ({ item }); + } + foreach(string tmp in item){ + foreach(object ob in GetDummyItems()){ + if( ob->id(tmp) ){ + ob->SetListen(val); + break; + } + } + } +} + +mixed GetListen(){ + return Listen; +} + +varargs void RemoveListen(mixed item){ + if( !item || item == "default" ){ + Listen = 0; + return; + } + foreach(object ob in GetDummyItems()){ + if( stringp(item) ){ + if( ob->id(item) ){ + ob->SetListen(0); + } + } + else if( arrayp(item) ){ + if( sizeof(ob->GetId() & item) ){ + ob->SetListen(0); + } + } + } +} + +varargs void SetListen(mixed items, mixed arg){ + if( !mapp(items) ){ + if( !arg ){ + AddListen("default", items); + } + else { + AddListen(items, arg); + } + return; + } + foreach(mixed key, mixed val in items){ + AddListen(key, val); + } +} + +int SetMedium(int medium){ + Medium = medium; + return Medium; +} + +int GetMedium(){ + return Medium;; +} + +int GetNightLight(){ + return NightLight; +} + +int GetClimateExposed(){ + string *nonexposed_media = ({ MEDIUM_SPACE, MEDIUM_WATER }); + int nonexposed_terrain = (T_SEAFLOOR|T_INDOORS|T_UNDERWATER|T_UNDERGROUND|T_SPACE|T_PLANAR|T_BIOLOGICAL); + if(GetClimate()=="indoors") return 0; + if(GetTerrainType() & (nonexposed_terrain)) return 0; + if(member_array(GetMedium(), nonexposed_media) != -1) return 0; + return 1; +} + +static int SetNightLight(int x){ + return (NightLight = x); +} + +int SetNoReplace(int x){ return (NoReplace = x); } + +int GetNoReplace(){ return NoReplace; } + +int GetPlayerKill(){ + return PlayerKill; +} + +int SetPlayerKill(int x){ + return (PlayerKill = x); +} + +int AddPoisonGas(int x){ + PoisonGas += x; + return PoisonGas; +} + +int GetPoisonGas(){ + int x; + + if( PoisonGas < 1 ){ + return 0; + } + x = time() - GasCheck; + GasCheck = time(); + if( x > 0 && x < 4 ){ + x = 1; + } + else { + x = x/4; + } + PoisonGas -= x; + if( PoisonGas < 0 ){ + PoisonGas = 0; + } + return PoisonGas; +} + +int SetPoisonGas(int x){ + return (PoisonGas = x); +} + +varargs void AddRead(mixed item, mixed val, string lang){ + if( stringp(item) ){ + item = ({ item }); + } + foreach(string tmp in item){ + foreach(object ob in GetDummyItems()){ + if( ob->id(tmp) ){ + ob->SetRead(val); + if(lang) ob->SetLanguage(lang); + break; + } + } + } +} + +void RemoveRead(mixed item){ + foreach(object ob in GetDummyItems()){ + if( stringp(item) ){ + if( ob->id(item) ){ + ob->SetRead(0); + } + } + else if( arrayp(item) ){ + if( sizeof(ob->GetId() & item) ){ + ob->SetRead(0); + } + } + } +} + +varargs void SetRead(mixed items, mixed arg){ + if( !mapp(items) ){ + AddRead(items, arg); + return; + } + else foreach(mixed key, mixed val in items){ + AddRead(key, val, ((arg && stringp(arg)) ? arg : 0)); + } +} + +int GetShade(){ + return Shade; +} + +static int SetShade(int x){ + return (Shade = x); +} + +varargs void AddSearch(mixed item, mixed val){ + if( !val ){ + Search = item; + return; + } + if( !item || item == "default" ){ + Search = val; + return; + } + if( stringp(item) ){ + item = ({ item }); + } + foreach(string tmp in item){ + foreach(object ob in GetDummyItems()){ + if( ob->id(tmp) ){ + ob->SetSearch(val); + break; + } + } + } +} + +varargs mixed GetSearch(){ + return Search; +} + +varargs void RemoveSearch(mixed item){ + if( !item || item == "default" ){ + Search = 0; + return; + } + foreach(object ob in GetDummyItems()){ + if( stringp(item) ){ + if( ob->id(item) ){ + ob->SetSearch(0); + } + } + else if( arrayp(item) ){ + if( sizeof(ob->GetId() & item) ){ + ob->SetSearch(0); + } + } + } +} + +varargs void SetSearch(mixed items, mixed arg){ + if( !mapp(items) ){ + if( !arg ){ + AddSearch("default", items); + } + else { + AddSearch(items, arg); + } + return; + } + foreach(mixed key, mixed val in items){ + AddSearch(key, val); + } +} + +varargs void AddSmell(mixed item, mixed val){ + if( !val ){ + Smell = item; + return; + } + if( !item || item == "default" ){ + Smell = val; + return; + } + if( stringp(item) ){ + item = ({ item }); + } + foreach(string tmp in item){ + foreach(object ob in GetDummyItems()){ + if( ob->id(tmp) ){ + ob->SetSmell(val); + break; + } + } + } +} + +varargs mixed GetSmell(){ + return Smell; +} + +varargs void RemoveSmell(mixed item){ + if( !item || item == "default" ){ + Smell = 0; + return; + } + foreach(object ob in GetDummyItems()){ + if( stringp(item) ){ + if( ob->id(item) ){ + ob->SetSmell(0); + } + } + else if( arrayp(item) ){ + if( sizeof(ob->GetId() & item) ){ + ob->SetSmell(0); + } + } + } +} + +varargs void SetSmell(mixed items, mixed arg){ + if( !mapp(items) ){ + if( !arg ){ + AddSmell("default", items); + } + else { + AddSmell(items, arg); + } + return; + } + foreach(mixed key, mixed val in items){ + AddSmell(key, val); + } +} + +varargs void AddTouch(mixed item, mixed val){ + if( !val ){ + Touch = item; + return; + } + if( !item || item == "default" ){ + Touch = val; + return; + } + if( stringp(item) ){ + item = ({ item }); + } + foreach(string tmp in item){ + foreach(object ob in GetDummyItems()){ + if( ob->id(tmp) ){ + ob->SetTouch(val); + break; + } + } + } +} + +varargs void RemoveTouch(mixed item){ + if( !item || item == "default" ){ + Touch = 0; + return; + } + foreach(object ob in GetDummyItems()){ + if( stringp(item) ){ + if( ob->id(item) ){ + ob->SetTouch(0); + } + } + else if( arrayp(item) ){ + if( sizeof(ob->GetId() & item) ){ + ob->SetTouch(0); + } + } + } +} + +varargs void SetTouch(mixed items, mixed arg){ + if( !mapp(items) ){ + if( !arg ){ + AddTouch("default", items); + } + else { + AddTouch(items, arg); + } + return; + } + foreach(mixed key, mixed val in items){ + AddTouch(key, val); + } +} + +string GetTown(){ return Town; } + +string SetTown(string town){ return (Town = town); } + +/** this stuff is for backwards compat **/ + +mixed SetProperty(string prop, mixed val){ + if( prop == "light" ){ + if( !val ) return val; + if( val < 0 ) return val; + else return ambiance::SetAmbientLight(val*25); + } + else if( prop == "night light" ){ + if( !val ) return val; + if( val < 0 ) return val; + else return SetNightLight(15*val); + } + + else return properties::SetProperty(prop, val); +} + +mixed SetProperties(mapping mp){ + if( mp["light"] ){ + SetProperty("light", mp["light"]); + } + else if( mp["night light"] ){ + SetProperty("night light", mp["night light"]); + } + return properties::SetProperties(mp); +} + + +string GetLong(){ + return GetInternalDesc(); +} + +string SetLong(string str){ + return SetInternalDesc(str); +} + +int CanAttack( object attacker, object who ){ + if( PlayerKill ){ + return 1; + } + attacker->RemoveHostile( who ); + return 0; +} + +varargs int eventShow(object who, string args){ + string str; + + if( !(str = SEASONS_D->GetLong(args)) ){ + who->eventPrint("You do not see that there."); + return 1; + } + who->eventPrint(str); + eventPrint(who->GetName() + " looks at the " + args + ".", who); +} + +/*********** /lib/room.c events ***********/ +mixed eventBuryItem(object who, object tool, object what){ + if( !functionp(Bury) ){ + return "You cannot bury things here!"; + } + if( functionp(Bury) & FP_OWNER_DESTED ){ + return "You cannot bury things here."; + } + return evaluate(Bury, who, tool, what); +} + +varargs mixed eventHearTalk(object who, object target, int cls, string verb, + string msg, string lang){ + object *obs; + string exit, door; + + switch(cls){ + case TALK_PRIVATE: + return 1; + + case TALK_SEMI_PRIVATE: + target->eventHearTalk(who, target, cls, verb, msg, lang); + eventPrint("%^BOLD%^CYAN%^" + who->GetName() + + " whispers something to " + target->GetName() + ".", + MSG_CONV, ({ who, target })); + return 1; + + case TALK_LOCAL: + obs = get_livings(this_object(),1); + if(sizeof(obs)) obs -= ({ who }); + if(sizeof(obs)) + obs->eventHearTalk(who, target, cls, verb, msg, lang); + obs = get_livings(this_object(),2); + if(sizeof(obs)) obs -= ({ who }); + if(sizeof(obs)) + obs->eventHearTalk(who, target, cls, verb, msg, lang); + return 1; + + case TALK_AREA: + foreach(exit in GetExits()){ + string tmp; + + tmp = GetExit(exit); + if( !find_object(tmp) ) continue; + tmp->eventHearTalk(who, target, TALK_LOCAL, verb, msg, lang); + } + foreach(exit in GetEnters(1)){ + string tmp; + + tmp = GetEnter(exit); + if( !find_object(tmp) ) continue; + if( (door = GetDoor(exit)) && door->GetClosed() ) continue; + tmp->eventHearTalk(who, target, TALK_LOCAL, verb, msg, lang); + } + obs = filter(all_inventory(), + (: $1->is_living() && $1 != $(who) :)); + obs->eventHearTalk(who, target, cls, verb, msg, lang); + return 1; + + } +} + +int eventMove(){ return 0; } + +varargs int eventPrint(string msg, mixed arg2, mixed arg3){ + object *targs; + int msg_class; + targs = filter(all_inventory(), + (: $1->is_living() || $1->GeteventPrints() :)); + + if( !arg2 && !arg3 ){ + msg_class = MSG_ENV; + } + else if( objectp(arg2) || arrayp(arg2) ){ + if( objectp(arg2) ) arg2 = ({ arg2 }); + foreach(mixed mount in arg2){ + object *riders; + if(!mount) continue; + riders = mount->GetRiders(); + if(riders) targs += riders; + } + targs -= arg2; + if( !arg3 ) msg_class = MSG_ENV; + else if(intp(arg3)) msg_class = arg3; + } + else if(!arg3){ + if(intp(arg2)) msg_class = arg2; + else msg_class = MSG_ENV; + } + else if( objectp(arg3) || arrayp(arg3) ){ + if( objectp(arg3) ) arg3 = ({ arg3 }); + foreach(mixed mount in arg3){ + object *riders; + if(!mount) continue; + riders = mount->GetRiders(); + if(riders) targs += riders; + } + targs -= arg3; + msg_class = arg2; + } + if(sizeof(targs)) targs->eventPrint(msg, msg_class); + return 1; +} + +static void create(){ + exits::create(); + inventory::reset(query_reset_number()); + set_heart_beat(0); + if( replaceable(this_object()) && !GetNoReplace() ){ + string array tmp= inherit_list(this_object()); + if( sizeof(tmp) == 1 ){ + replace_program(tmp[0]); + } + } +} + +int eventDestruct(){ + if(GetPersistent()){ + SaveObject(); + } + return ::eventDestruct(); +} + +int CanReceive(object ob){ + if(!GetProperty("no teleport") || !living(ob)) return container::CanReceive(ob); + else { + string verb = query_verb(); + string *allowed = ({ "go", "climb", "jump", "enter", "fly", "crawl" }); + if(member_array(verb, allowed) == -1 && !archp(this_player())){ + write("Your teleportation is prevented."); + return 0; + } + } + return container::CanReceive(ob); +} + +varargs void reset(int count){ + mixed *inv; + + if(origin() == "driver") return; + + inv = deep_inventory(this_object()); + if(inv && sizeof(inv)){ + if( sizeof(filter(inv, (: interactive($1) || $1->GetNoClean() :))) ){ + return; + } + } + inventory::reset(count); + all_inventory()->reset(count); + ResetNumber++; +} + +int id(){ + return 0; +} + +int inventory_accessible(){ + return 1; +} + +int inventory_visible(){ + return 1; +} + +int SetNoDefaultExits(int i){ + if(!i) i = 0; + DefaultExits = bool_reverse(i); + ObviousVisible = DefaultExits; + return DefaultExits; +} + +int SetDefaultExits(int i){ + if(!i) i = 0; + DefaultExits = i; + ObviousVisible = DefaultExits; + return DefaultExits; +} + +int SetCanFly(int i){ + if(i && i > 0) Flying = 1; + else Flying = 0; +} + +mixed CanFly(object who, string dest){ + if(!who) who = this_player(); + if(!dest) dest = ""; + if(MEDIUM_WATER == Medium || MEDIUM_SPACE == Medium) return 0; + if(sizeof(FlyRoom)) return 1; + return Flying; +} + +int SetCanSwim(int i){ + if(i && i > 0) Swimming = 1; + else Swimming = 0; +} + +mixed CanSwim(object who, string dest){ + if(!who) who = this_player(); + if(!dest) dest = ""; + if((MEDIUM_WATER == Medium) || (MEDIUM_SURFACE == Medium) ) return 1; + if(GetTerrainType() & (T_ALL_SEA)) return 1; + return Swimming; +} + +int SetCanStand(int i){ + if(i && i > 0) Standing = 1; + else Standing = 0; +} + +mixed CanStand(object who, string dest){ + if(!who) who = this_player(); + if(!dest) dest = ""; + if(GetTerrainType() & (T_SPACE | T_UNDERWATER | T_SURFACE)) return 0; + if(GetTerrainType() & (T_SEAFLOOR)) return 1; + if((MEDIUM_AIR == Medium)) return 0; + if((MEDIUM_LAND == Medium)) return 1; + return Standing; +} + +int SetCanSit(int i){ + if(i && i > 0) Sitting = 1; + else Sitting = 0; +} + +mixed CanSit(object who, string dest){ + if(!who) who = this_player(); + if(!dest) dest = ""; + if(GetTerrainType() & (T_SPACE | T_UNDERWATER | T_SURFACE)) return 0; + if(GetTerrainType() & (T_SEAFLOOR)) return 1; + if((MEDIUM_AIR == Medium)) return 0; + if((MEDIUM_LAND == Medium)) return 1; + return Sitting; +} + +int SetCanKneel(int i){ + if(i && i > 0) Kneeling = 1; + else Kneeling = 0; +} + +mixed CanKneel(object who, string dest){ + if(!who) who = this_player(); + if(!dest) dest = ""; + if(GetTerrainType() & (T_SPACE | T_UNDERWATER | T_SURFACE)) return 0; + if(GetTerrainType() & (T_SEAFLOOR)) return 1; + if((MEDIUM_AIR == Medium)) return 0; + if((MEDIUM_LAND == Medium)) return 1; + return Kneeling; +} + +int SetNoObviousExits(int i){ + if(!i) i = 0; + ObviousVisible = bool_reverse(i); + DefaultExits = ObviousVisible; + return ObviousVisible; +} + +int GetNoObviousExits(){ + return bool_reverse(ObviousVisible); +} + +int GenerateObviousExits(){ + string *normals; + string *exits; + string dir_string, enters; + exits = filter(GetExits(), (: !($1 == "up" && !(this_object()->GetVirtualSky()) && + load_object(GetExit($1))->GetVirtualSky()) :) ); + enters = ""; + normals = ({ "north", "south", "east", "west", "up", "down" }); + normals += ({ "northeast", "southeast", "northwest", "southwest" }); + normals += ({ "out" }); + dir_string = ""; + + if(sizeof(GetEnters(1)-({0}))){ + foreach(string enter in this_object()->GetEnters(1)){ + enters += "enter "+enter; + if(member_array(enter,this_object()->GetEnters(1)) != + sizeof(this_object()->GetEnters(1)) -1){ + enters +=", "; + } + } + } + + if(NM_STYLE_EXITS){ + if(member_array("north",exits) != -1) dir_string += "n, "; + if(member_array("south",exits) != -1) dir_string += "s, "; + if(member_array("east",exits) != -1) dir_string += "e, "; + if(member_array("west",exits) != -1) dir_string += "w, "; + if(member_array("northeast",exits) != -1) dir_string += "ne, "; + if(member_array("northwest",exits) != -1) dir_string += "nw, "; + if(member_array("southeast",exits) != -1) dir_string += "se, "; + if(member_array("southwest",exits) != -1) dir_string += "sw, "; + if(member_array("up",exits) != -1) dir_string += "u, "; + if(member_array("down",exits) != -1) dir_string += "d, "; + if(member_array("out",exits) != -1) dir_string += "out, "; + } + else dir_string = implode(exits,", ")+", "; + if(sizeof(this_object()->GetEnters(1) - ({0}) )){ + if(sizeof(this_object()->GetExits())) dir_string += ", "; + dir_string += enters; + } + if(last(dir_string,2) == ", ") dir_string = truncate(dir_string,2); + dir_string = replace_string(dir_string,", , ",", "); + if(ObviousVisible) SetObviousExits(dir_string); + return 1; +} + +int eventReceiveObject(object ob){ + this_object()->SetSky(); + if(this_object() && ob && (living(ob) || ob->GetMapper())){ + if(MASTER_D->GetPerfOK()){ + int array Coords = ROOMS_D->SetRoom(this_object(), ob); + this_object()->CompileNeighbors(Coords); + } + } + return container::eventReceiveObject(ob); +} + +int eventReleaseObject(object ob){ + return container::eventReleaseObject(ob); +} + +string SetFlyRoom(string str){ + FlyRoom = str; + return FlyRoom; +} + +string GetFlyRoom(){ + return FlyRoom; +} + +string SetSinkRoom(string str){ + SinkRoom = str; + return SinkRoom; +} + +string GetSinkRoom(){ + return SinkRoom; +} + +int SetNoSink(int i){ + return NoSink = i; +} + +int GetNoSink(){ + return NoSink; +} + +string SetSkyDomain(string str){ + SkyDomain = str; + this_object()->SetSky(); + return SkyDomain; +} + +string GetSkyDomain(){ + return SkyDomain; +} + +int SetFlowLimit(int i){ + FlowLimit = i; + return FlowLimit; +} + +int GetFlowLimit(){ + return FlowLimit; +} + +int SetRespirationType(int i){ + RespirationType = i; + return RespirationType; +} + +int GetRespirationType(){ + return RespirationType; +} + +varargs mixed DestructEmptyVirtual(object ob){ + mixed *inv; + if(ob && environment(ob) && environment(ob) == this_object()) return 0; + if(!this_object()->GetVirtual()){ + return 0; + } + if(this_object()->GetNoClean()){ + return 0; + } + if(this_object()->GetExemptVirtual()){ + return 0; + } + inv = filter(all_inventory(this_object()), + (: !inherits(LIB_BASE_DUMMY, $1) :) ); + if(!sizeof(inv)){ + all_inventory(this_object())->eventDestruct(); + return eventDestruct(); + } +} + +mixed eventPostRelease(object ob){ + mixed *inv; + mixed ret = ::eventPostRelease(ob); + DestructEmptyVirtual(ob); + return ret; +} + +void CompileNeighbors(mixed coords){ +#if GRID + int x, x2; + int y, y2; + int a, b, c; + if(!Neighbors) Neighbors = ({}); + if(sizeof(Neighbors) || !(MASTER_D->GetPerfOK())) return; + if(!sizeof(Coords)){ + mixed crds = ROOMS_D->GetCoordinates(this_object()); + if(sizeof(crds)){ + sscanf(crds,"%d,%d,%d",a,b,c); + Coords = ({ a, b, c }); + } + if(!sizeof(Coords)) return; + } + x2 = Coords[0]+2; + y2 = Coords[1]+2; + NeighborCoords = ({ }); + for(x = Coords[0]-1; x < x2; x++){ + for(y = Coords[1]-1; y < y2; y++){ + NeighborCoords += ({ ({ x, y, 0 }) }); + } + } + NeighborCoords -= ({ Coords }); + foreach(mixed foo in NeighborCoords){ + mixed bar = ROOMS_D->GetGrid(foo[0]+","+foo[1]+","+foo[2]); + if(bar && bar["room"]){ + Neighbors += ({ bar["room"] }); + } + } +#endif +} + +mixed GetNeighbors(){ + return copy(Neighbors); +} + +mixed GetNeighborCoords(){ + return copy(NeighborCoords); +} + +mixed GetCoords(){ + return copy(Coords); +} + +string SetCoordinates(string str){ + string ret; + int x, y, z, i; + if(!str) return 0; + i = sscanf(str, "%d,%d,%d", x, y, z); + if(i != 3){ + i = sscanf(str, "%d,%d", x, y); + z = 0; + } + if(i < 2) return 0; + ret = x+","+y+","+z; + if(sizeof(ROOMS_D->GetGrid(ret))) return 0; + ROOMS_D->SetRoom(this_object(), this_object(), ret); + Coords = ({ x, y, z }); + return ret; +} + +void SetSky(){ + if(GetMedium() != MEDIUM_LAND && GetMedium() != MEDIUM_SURFACE){ + return; + } + if(sizeof(SkyDomain) && !sizeof(FlyRoom)){ + mixed coords = this_object()->GetCoords(); + if(!sizeof(coords)) return; + SetFlyRoom("/domains/"+SkyDomain+"/virtual/sky/"+ + coords[0]+","+coords[1]+","+(coords[2]+1)); + if(sizeof(FlyRoom)){ + catch(load_object(FlyRoom)->SetSinkRoom(base_name(this_object()))); + } + } +} + +static void init(){ + object prev = previous_object(); + SetSky(); + if(undefinedp(RespirationType)){ + switch(GetMedium()){ + case MEDIUM_WATER : RespirationType = R_WATER; break; + case MEDIUM_SPACE : RespirationType = R_VACUUM; break; + case MEDIUM_AIR : RespirationType = R_AIR; break; + case MEDIUM_LAND : RespirationType = R_AIR; break; + case MEDIUM_SURFACE : RespirationType = (R_AIR | R_WATER); break; + case MEDIUM_METHANE : RespirationType = R_METHANE; break; + default : RespirationType = R_AIR; break; + } + } + if(this_object()->GetProperty("indoors")) SetClimate("indoors"); + if(!sizeof(GetObviousExits()) && DefaultExits > 0 && ObviousVisible){ + GenerateObviousExits(); + } + if((Action && (sizeof(Action) || functionp(Action))) + || sizeof(ActionsMap)){ + set_heart_beat(tick_resolution); + } +#if GRID + if(this_object() && prev && (living(prev) || prev->GetMapper())){ + if(MASTER_D->GetPerfOK()){ + Coords = ROOMS_D->SetRoom(this_object(), prev); + CompileNeighbors(Coords); + } + } +#endif + if(this_object()->GetVirtual() && !query_heart_beat()){ + set_heart_beat(1); + } +} + +string GetElevator(){ + return Elevator; +} + +string SetElevator(string str){ + if(str) Elevator = str; + return Elevator; +} diff --git a/lib/lib/std/storage.c b/lib/lib/std/storage.c new file mode 100644 index 0000000..dc895d5 --- /dev/null +++ b/lib/lib/std/storage.c @@ -0,0 +1,36 @@ +#include <lib.h> + +inherit LIB_BASE_STORAGE; +inherit LIB_ITEM; + +static private mixed my_save = ({}); + +void create(){ + //parse_init(); + my_save = ({}); + item::create(); + base_storage::create(); +} + +int GetRadiantLight(int ambient){ + return item::GetRadiantLight(ambient) + base_storage::GetRadiantLight(ambient); +} + +string array GetSave(){ + string *i_save; + i_save = item::GetSave(); + my_save += i_save; + my_save += ({ "Closed","CanClose", "CanLock", "RecurseDepth" , "MaxRecurseDepth" }); + my_save = distinct_array(my_save); + return my_save; +} + +static mixed array AddSave(mixed array vars){ + my_save = distinct_array(my_save + vars); + return item::AddSave(my_save); +} + +int SetSaveRecurse(int x){ + return item::SetSaveRecurse(x); +} + diff --git a/lib/lib/std/story.c b/lib/lib/std/story.c new file mode 100644 index 0000000..fa1785f --- /dev/null +++ b/lib/lib/std/story.c @@ -0,0 +1,112 @@ +/* /lib/std/story.c + * from the Dead Souls Mud Library + * handles objects and NPCs telling stories + * created by Corvar + * Version: + * Last Modified: + */ + +private int AlreadyTellingTale; +private mapping Tales; +private string TalesDir; +private string NoTaleMessage; + +void PickTale( string taletotell ); +void TellTale( int part ); +string SetTalesDir(string dir); +string GetTalesDir(); +mapping SetTale(mapping tale); +mapping GetTale(); +array GetTaleKeys(); +string SetNoTaleMessage(string notalemessage); +string GetNoTaleMessage(); +int GetTellingTale(); + +static void create(){ + AlreadyTellingTale = 0; + TalesDir = ""; + Tales = ([ ]); +} + +/* One of the following two must be used. SetTalesDir(string dir) will set a + directory which will contain tale files. Each tale file should consist of + the following: + action#delay where action is what you want the NPC to say, and delay + is how long before the next action. +Example: +say this is the first part of the tale#5 +emote this is the second part of the tale which is really long so that it will span a line. Note that there is no line feed in the middle of this line#4 +speak last line#1 +End Example. + +If using SetTale(mapping tale) instead the mapping should be like the +following +SetTale( ([ 1 : ({"say this is the first part of the tale",5}), +2 : ({"emote this is.....",4}), 3 : ({"speak last line",1}) ]) ); + */ + +string SetTalesDir(string dir){ + TalesDir = dir; + return TalesDir; +} + +mapping SetTale(mapping tale){ + Tales = tale; + return Tales; +} + +string SetNoTaleMessage(string notalemessage){ + NoTaleMessage = notalemessage; + return NoTaleMessage; +} + +string GetTalesDir(){ return TalesDir; } +mapping GetTale(){ return Tales; } +array GetTaleKeys(){ return keys( Tales ); } +string GetNoTaleMessage(){ return NoTaleMessage; } +int GetTellingTale(){ return AlreadyTellingTale; } + +void PickTale( string taletotell ){ + array msg; + string file, *files; + int y; + + if( ! AlreadyTellingTale ){ + int x = 0; + if( TalesDir ){ + files = get_dir( GetTalesDir() ); + if(taletotell){ + y = member_array(taletotell,files); + if( y != -1 ) + file = taletotell; + else { + environment(this_object())->eventPrint(NoTaleMessage); + return; + } + } + else + file = files[random(sizeof(files))]; + AlreadyTellingTale = 1; + Tales = ([]); + msg = explode( read_file( TalesDir + file ), "\n" ); + foreach( string str in msg ){ + Tales[x++] = explode( str, "#" ); + } + } + if( !Tales ) return; + call_out( (: TellTale :), 1, 0 ); + } + +} + + +void TellTale( int part ){ + if( part == sizeof( keys( Tales ) ) ){ + AlreadyTellingTale = 0; + return; + } + if( living(this_object()) ) this_object()->eventForce( Tales[part][0] ); + else environment(this_object())->eventPrint( Tales[part][0] ); + call_out( (: TellTale :), to_int( Tales[part][1] ), part + 1 ); + return; +} diff --git a/lib/lib/std/table.c b/lib/lib/std/table.c new file mode 100644 index 0000000..08b94ce --- /dev/null +++ b/lib/lib/std/table.c @@ -0,0 +1,24 @@ +#include <lib.h> + +inherit LIB_BED; + +void create(){ + bed::create(); + SetShort("A table"); + SetLong("A table"); + SetMaxSitters(2); + SetMaxLiers(1); + SetMaxCarry(500); + SetMass(1000); + inventory_visible(); + inventory_accessible(); +} + +void init(){ + ::init(); +} + +int CanGet(object who){ + return bed::CanGet(who); +} + diff --git a/lib/lib/std/vendor.c b/lib/lib/std/vendor.c new file mode 100644 index 0000000..86d6dab --- /dev/null +++ b/lib/lib/std/vendor.c @@ -0,0 +1,578 @@ +#include <lib.h> +#include <armor_types.h> +#include <vendor_types.h> +#include <daemons.h> +#include "/lib/include/vendor.h" + +inherit LIB_SENTIENT; +inherit LIB_MANYCOINS; + +private static int MaxItems, VendorType, bargain; +private static string StorageRoom, LocalCurrency; +private static mapping Costs, Values; + +static void create(){ + sentient::create(); + Costs = ([]); + Values = ([]); + LocalCurrency = "gold"; + VendorType = VT_TREASURE; + MaxItems = 40; +} + +mixed direct_buy_str_from_liv(string str){ + return CanSell(this_player(), str); +} + +int indirect_sell_obj_to_liv(){ return 1; } + +int indirect_sell_obs_to_liv(){ return 1; } + +int CanCarry(int amount){ return 1; } + +mixed CanBuy(object who, object *obs){ + if( !load_object(StorageRoom) ) + return "There is a bug with the vendor's storage, please report it."; + return 1; +} + +mixed CanSell(object who, string what){ + if( !load_object(StorageRoom) ) + return "There is a bug with the vendor's storage, please report it."; + return 1; +} + +mixed eventBuy(object who, object *obs){ + object *tmp; + object sroom, ob; + int cost; + + sroom = load_object(StorageRoom); + if( sizeof(all_inventory(sroom)) > GetMaxItems() ){ + eventForce("say I am having trouble getting rid of the things I " + "have to sell right now."); + return 1; + } + if( !sizeof(obs) ){ + eventForce("say you have nothing to sell!"); + return 1; + } + tmp = ({}); + foreach(ob in obs){ + int value; + + if( !(ob->GetShort()) ) continue; + if( !(ob->GetVendorType() & GetVendorType()) ){ + eventForce("say I do not buy things like " + + ob->GetShort()); + continue; + } + cost = to_int(ob->GetBaseCost(GetLocalCurrency())); + value = to_int(ceil(GetValue(ob, who))); + if(ob->GetValue()) bargain = 1; + else bargain = 0; + if(!bargain) value = cost; + + if( !cost || cost < 1 || !value || value < 1){ + eventForce("say " + ob->GetShort() + " is worthless!"); + continue; + } + cost = cost / 2; + value = value / 2; + if(!cost) cost = 1; + if(!value) value = 1; + if( !(ob->CanSell(who)) ){ + eventForce("say You cannot sell " + ob->GetShort() +"."); + continue; + } + if( sizeof(filter(all_inventory(sroom), + (: $1->GetShort() == $(ob)->GetShort() :))) + > 3 ){ + if( this_player()->AddCurrency(GetLocalCurrency(),value) == -1 ){ + eventForce("say you cannot carry "+value+" "+ + GetLocalCurrency()+"!"); + ob->eventMove(environment()); + continue; + } + eventForce("say " + ob->GetShort() + "! Great!"); + tell_player(this_player(),GetShort()+" gives you "+value+ + " "+GetLocalCurrency()+"."); + if(bargain) who->AddSkillPoints("bargaining", value*5); + message("my_action", "You sell " + ob->GetShort() + ".", who); + message("other_action", capitalize(who->GetKeyName()) + " sells " + + ob->GetShort() + ".", environment(), + ({ who, this_object() })); + ob->eventDestruct(); + return 1; + } + eventForce("say " + ob->GetShort() + "! Excellent!"); + tell_player(this_player(),GetShort()+" pays you "+value+ + " "+GetLocalCurrency()+"."); + + if( !(ob->eventMove(sroom)) ){ + eventForce("say I cannot seem to carry that"); + return 1; + } + if( this_player()->AddCurrency(GetLocalCurrency(), value) == -1 ){ + eventForce("say you cannot carry "+value+" "+ + GetLocalCurrency()+"!"); + ob->eventMove(environment()); + continue; + } + if(bargain) who->AddSkillPoints("bargaining", value*5); + tmp += ({ ob }); + message("my_action", "You sell " + ob->GetShort() + ".", who); + message("other_action", capitalize(who->GetKeyName()) + " sells " + + ob->GetShort() + ".", environment(), + ({ who, this_object() })); + } + if( !sizeof(tmp) ) + eventForce("say I am sorry, " + capitalize(who->GetKeyName()) + ", " + "that we could not come to a better agreement."); + else map(tmp, function(object ob){ + if( ob->GetDestroyOnSell() ) + ob->eventDestruct(); + }); + return 1; +} + +int cmdShow(object who, string args){ + object ob, sroom; + int x; + + if( !args || args == "" ){ + eventForce("say show you what?"); + return 1; + } + if( !(sroom = load_object(StorageRoom)) ){ + eventForce("say I am having troubles right now"); + return 1; + } + if( x = to_int(args) ){ + object *obs; + object *obs2; + string *list2; + int maxi; + + x--; + obs = all_inventory(sroom); + maxi = sizeof(obs); + list2 = ({(obs[0]->GetKeyName())}); + for(int counter = 1;counter < maxi;++counter){ + if(member_array((obs[counter]->GetKeyName()),list2) < 0){ + list2 += ({ ( obs[counter]->GetKeyName()) }); + } + } + obs2 = ({ present(list2[0],sroom) }); + maxi = sizeof(list2); + for(int counter = 1;counter < maxi;++counter){ + obs2 += ({ present(list2[counter],sroom) }); + } + if((x >= 0) && (x < sizeof(obs2))){ + ob = obs2[x]; + } + } + else ob = present(args = lower_case(args), sroom); + if( !ob ){ + eventForce("say I have no such thing to show you"); + return 1; + } + message("other_action", capitalize(GetKeyName())+" shows you "+ + ob->GetShort()+".", who); + message("system", ob->GetLong(), who); + return 1; +} + +int cmdBrowse(object who, string args){ + object *obs; + object *obs2; + string *list; + object sroom; + int i, ii, maxi, number; + + if( !args || args == "" ) args = "all"; + if( !(sroom = load_object(StorageRoom)) ){ + eventForce("say I am having terrific difficulties today"); + return 1; + } + if(!(maxi = sizeof(obs = filter(all_inventory(sroom), (: !userp($1) && !$1->isDummy() :))))){ + eventForce("say I have nothing to sell right now."); + return 1; + } + list = ({ "item # Description Price ("+GetLocalCurrency()+")", "" }); + obs2 = ({}); + foreach(object tempob in obs){ + string *base_names = ({}); + foreach( object tempob2 in obs2 ){ + base_names += ({ base_name(tempob2) }); + } + if(member_array(base_name(tempob), base_names) == -1){ + obs2 += ({ tempob }); + } + } + maxi = sizeof(obs2); + i = this_player()->GetScreen()[0]; + if(number = to_int(args)){ + if((number > 0) && (number <= maxi)){ + int tmp; + while( i-- ) list[1] += "_"; + if(intp(number) && + (tmp = to_int(ceil(GetCost(obs2[(number - 1)],who))))){ + list += ({ sprintf("%d %:-35s %d", number, + obs2[(number - 1)]->GetShort(), tmp) }); + } + this_player()->eventPage(list); + return 1; + } + } + + while( i-- ) list[1] += "_"; + for(ii=0; ii < maxi; ii++){ + int ok; + int gat; + + ok = 0; + gat = (obs2[ii]->GetArmorType()); + switch(args){ + case "all": ok = 1; break; + case "weapon": case "weapons": + break; + case "armor": case "armors": + if(obs2[ii]->GetVendorType() == 8){ + ok = 1; + } + break; + case "bag": case "bags": + ok = obs2[ii]->GetProperty("bag"); + break; + case "ring": case "rings": + ok = gat & A_RING; + break; + case "glove": case "gloves": + ok = gat & (A_GLOVE | A_LONG_GLOVE); + break; + case "boot": case "boots": + ok = gat & (A_BOOT | A_LONG_BOOT); + break; + case "sock": case "socks": + ok = gat & (A_SOCK | A_LONG_SOCK); + break; + case "helm": case "helmet": + ok = gat & A_HELMET; + break; + case "visor": case "visors": + ok = gat & A_VISOR; + break; + case "pants": + ok = gat & A_PANTS; + break; + case "shirt": case "shirts": + ok = gat & A_SHIRT; + break; + case "cloak": case "cloaks": + ok = gat & A_CLOAK; + break; + case "belt": case "belts": + ok = gat & A_BELT; + break; + case "vest": case "vests": + ok = gat & A_VEST; + break; + case "shield": case "shields": + ok = gat & A_SHIELD; + break; + case "body armor": case "body armors": + ok = gat & A_BODY_ARMOR; + break; + case "blunt": case "knife": case "blade": case "projectile": + case "blunts": case "knives": case "blades": case "projectiles": + ok = (obs2[ii]->GetWeaponType() == args) || + (pluralize((obs2[ii]->GetWeaponType() || "")) == args); + break; + default: + ok = obs2[ii]->id(args); + break; + } + if( !ok ) continue; + ok = GetCost(obs2[ii], who); + if(!ii) ii = 0; + list += ({ sprintf("%d %:-35s %d", (ii+1), obs2[ii]->GetShort(), to_int(ok)) }); + } + if( !sizeof(list) ){ + eventForce("frown"); + eventForce("say I have nothing like that to sell."); + return 1; + } + this_player()->eventPage(list); + return 1; +} + +int cmdAppraise(object who, string args){ + object ob; + int x,cost; + + if( !args || args == "" ){ + eventForce("say appraise what?"); + return 1; + } + if( !(ob = present(args = lower_case(args), who)) ){ + eventForce("say You have no such thing!"); + return 1; + } + if( !(ob->GetVendorType() & GetVendorType()) ){ + eventForce("say I have no use for " + ob->GetShort()); + return 1; + } + if( LocalCurrency != query_base_currency() ){ + cost=to_int(ob->GetBaseCost() / ECONOMY_D->__Query(LocalCurrency,"rate")); + } + else cost = ob->GetBaseCost(); + if(!cost || cost < 1){ + eventForce("say " + capitalize(who->GetKeyName()) + ", I will not buy " + "that worthless thing from you."); + return 1; + } + else x=cost/2; + if(!x) x = 1; + eventForce("say " + capitalize(who->GetKeyName()) + ", I will offer " + "you " + x + " " + GetLocalCurrency() + " for " + + ob->GetShort()); + return 1; +} + +int cmdPrice(object who, string args){ + object *obs; + string *list2; + object *obs2; + object ob, sroom; + int x; + int maxi; + + if( !args || args == "" ){ + eventForce("say price what?"); + return 1; + } + if( !(sroom = load_object(StorageRoom)) ){ + eventForce("say today is not really a good day for me"); + return 0; + } + obs = all_inventory(sroom); + obs2 = ({}); + foreach(object tempob in obs){ + string *base_names = ({}); + foreach( object tempob2 in obs2 ) base_names += ({ base_name(tempob2) }); + if(!sizeof(obs2)){ + obs2 = ({tempob}); + } + else if(member_array(base_name(tempob), base_names) == -1) obs2 += ({ tempob }); + } + maxi = sizeof(obs2); + if( x = to_int(args) ){ + list2 = ({(obs2[0]->GetKeyName())}); + for(int counter = 1;counter < maxi;++counter){ + if(member_array((obs2[counter]->GetKeyName()),list2) < 0){ + list2 += ({ ( obs2[counter]->GetKeyName()) }); + } + } + maxi = sizeof(list2); + ob = obs2[x-1]; + } + else ob = present(args = lower_case(args), sroom); + if(!ob) foreach(object tempob in obs2) + if(answers_to(args,tempob)) ob = tempob; + if( !ob ){ + eventForce("say I have no such thing!"); + return 1; + } + if( !(x = to_int(ceil(GetCost(ob, this_player())))) ){ + eventForce("say that thing has no value!"); + return 1; + } + eventForce("say " + capitalize(who->GetKeyName()) + ", I will take " + + x + " " + GetLocalCurrency() + " for " + + ob->GetShort()); + return 1; +} + +mixed eventAsk(object who, string str){ + object *obs; + object ob; + string cmd, args, tmp; + string lang, prof, orig = str; + + lang = who->GetDefaultLanguage(); + prof = who->GetLanguageLevel(lang); + str = translate(str, prof); + prof = this_object()->GetLanguageLevel(lang); + str = translate(str, prof); + + if( !str || str == "" ){ + eventForce("say what do you want from me?"); + return 1; + } + if( sscanf(str, "%s %s", cmd, args) != 2 ){ + cmd = str; + args = 0; + } + switch(cmd){ + case "appraise": + return cmdAppraise(who, args); + + case "browse": + return cmdBrowse(who, args); + + case "buy": + if( str == "all" ) + obs = filter(all_inventory(who), (: $1->CanSell() :)); + else { + if( !(ob = present(args, who)) ){ + eventForce("say Get out of here you cheat!"); + eventForce("bump " + this_player()->GetKeyName()); + return 1; + } + obs = ({ ob }); + } + return eventBuy(who, obs); + + case "price": + return cmdPrice(who, args); + + case "sell": + if( (tmp = CanSell(who, args)) == 1 ) return eventSell(who, args); + else if( stringp(tmp) ) eventForce("say " + tmp); + else { + return 0; + } + + case "show": + return cmdShow(who, args); + + default: + //Thx Raudhrskal + if(!sentient::eventAsk(who,orig)) + eventForce("say I am not quite sure what you want from me"); + } +} + +mixed eventSell(object who, mixed what){ + object ob, sroom; + object *obs; + string *list2; + object *obs2; + int cost,number,maxi; + + sroom = load_object(StorageRoom); + obs = filter(all_inventory(sroom), (: !userp($1) :)); + obs2 = ({}); + foreach(object tempob in obs){ + string *base_names = ({}); + foreach( object tempob2 in obs2 ) base_names += ({ base_name(tempob2) }); + if(!sizeof(obs2)){ + obs2 = ({tempob}); + } + else if(member_array(base_name(tempob), base_names) == -1) obs2 += ({ tempob }); + } + maxi = sizeof(obs2); + if(number = to_int(what)){ + number = number - 1; + list2 = ({(obs2[0]->GetKeyName())}); + for(int counter = 1;counter < maxi;++counter){ + if(member_array((obs2[counter]->GetKeyName()),list2) < 0){ + list2 += ({ ( obs2[counter]->GetKeyName()) }); + } + } + maxi = sizeof(list2); + if((number >= 0) && (number < sizeof(obs2))){ + ob = obs2[number]; + } else { + eventForce("say I have nothing like that to sell to you."); + return 1; + } + } else { + if( !(ob = present(what, sroom))) + foreach(object tempob in obs2) + if(answers_to(what,tempob)) ob = tempob; + if(!ob || userp(ob) || ob->isDummy()){ + eventForce("say I have nothing like that to sell you."); + return 1; + } + } + cost=to_int(ob->GetBaseCost(GetLocalCurrency())); + if(!cost || cost < 0){ + cost = 0; + cost = to_int(ob->GetValue()); + } + if(who->GetCurrency(GetLocalCurrency()) < cost){ + eventForce("say You don't have enough "+GetLocalCurrency()+ + " to buy that."); + return 1; + } + if( !(ob->eventMove(this_object())) ){ + message("error", "An error occurred moving the object, use bug -r.", + who); + return 1; + } + eventForce("say here is " + ob->GetShort() + " for " + to_int(cost) + + " " + GetLocalCurrency() + "!"); + eventForce("give " + ob->GetUniqueId() + " to " + who->GetKeyName()); + if( environment(ob) == this_object() ){ + eventForce("say you cannot carry that!"); + eventForce("drop " + ob->GetKeyName()); + } + if(bargain) who->AddSkillPoints("bargaining", random(to_int(floor(cost)))); + who->AddCurrency(GetLocalCurrency(), -cost); + return 1; +} + +int GetCost(object ob, object who){ + int x, mod,cost; + + cost=ob->GetBaseCost(LocalCurrency); + if(cost && cost > 0) return cost; + + if( Costs[who] && Costs[who][ob] ) return Costs[who][ob]; + x = ob->GetValue(GetLocalCurrency()); + mod = who->GetSkillLevel("bargaining") - GetSkillLevel("bargaining"); + if( mod < -90 ) mod = -90; + if( mod > 90 ) mod = 90; + x = (x * (100 - mod))/100; + who->AddSkillPoints("bargaining", x); + if( !Costs[who] ) Costs[who] = ([ ob : x ]); + else Costs[who][ob] = x; + return x; +} + +int GetValue(object ob, object who){ + int x, mod; + + if( Values[who] && Values[who][ob] ) return Values[who][ob]; + x = ob->GetValue(GetLocalCurrency()); + mod = who->GetSkillLevel("bargaining") - GetSkillLevel("bargaining"); + if( mod < -90 ) mod = -90; + if( mod > 90 ) mod = 90; + x = (x * (100 - -mod)) / 100; + who->AddSkillPoints("bargaining", x); + if( !Values[who] ) Values[who] = ([ ob : x ]); + else Values[who][ob] = x; + return x; +} + +string SetLocalCurrency(string str){ return (LocalCurrency = str); } + +string GetLocalCurrency(){ return LocalCurrency; } + +string SetStorageRoom(string room){ return (StorageRoom = room); } + +string GetStorageRoom(){ return StorageRoom; } + +int SetMaxItems(int x){ return (MaxItems = x); } + +int GetMaxItems(){ return MaxItems; } + +int SetVendorType(int x){ return (VendorType = x); } + +int GetVendorType(){ return VendorType; } + + + + diff --git a/lib/lib/std/worn_storage.c b/lib/lib/std/worn_storage.c new file mode 100644 index 0000000..88386aa --- /dev/null +++ b/lib/lib/std/worn_storage.c @@ -0,0 +1,60 @@ +#include <lib.h> + +inherit LIB_BASE_STORAGE; +inherit LIB_BASE_ARMOR; +inherit LIB_SHADOW_HOOK; +inherit LIB_MONEY; + +private static mixed *my_save = ({}); + +void create(){ + mixed a_save, s_save; + base_armor::create(); + SetSaveRecurse(1); + a_save = base_armor::GetSave(); + s_save = base_storage::GetSave(); + my_save = distinct_array(a_save + s_save); + base_armor::AddSave(my_save); + base_storage::create(); +} + +void init(){ + base_armor::init(); +} + +mixed direct_remove_obj(){ + return base_armor::direct_remove_obj(); +} + +mixed direct_wear_obj(){ + return base_armor::direct_wear_obj(); +} + +mixed eventEquip(object who, string array limbs){ + return base_armor::eventEquip(who, limbs); +} + +varargs mixed eventUnequip(object who){ + return base_armor::eventUnequip(who); +} + +varargs string GetEquippedDescription(object who){ + return base_armor::GetEquippedDescription(who); +} + +varargs string GetExternalDesc(object who){ + return base_armor::GetExternalDesc(who); +} + +string GetEquippedShort(){ + return base_armor::GetEquippedShort(); +} + +string array GetSave(){ + return base_armor::GetSave(); +} + +varargs string array AddSave(string *args){ + my_save += args; + return base_armor::AddSave(my_save); +} diff --git a/lib/lib/std/wound.c b/lib/lib/std/wound.c new file mode 100644 index 0000000..d2d1179 --- /dev/null +++ b/lib/lib/std/wound.c @@ -0,0 +1,93 @@ +#include <lib.h> +#include ROOMS_H +#include <damage_types.h> +#include <vendor_types.h> +#include <daemons.h> + +inherit LIB_DUMMY; + +string WoundLong(){ + int num; + string noun, poss, verb, ret; + string being, plural; + object env = environment(); + + if(!env){ + return "Error."; + } + + num = env->GetLead(); + + if(env == this_player()){ + noun = "You"; + verb = "have"; + poss = "your"; + } + else { + noun = env->GetName(); + verb = "has"; + poss = possessive(env); + } + num = env->GetLead(); + if(!num){ + verb = (env == this_player() ? "are" : "is"); + ret = noun + " " + verb + " recovering from gunfire wounds."; + return ret; + } + if(num > 1){ + being = "are"; + plural = "s"; + } + else { + being = "is"; + plural = ""; + } + + ret = noun + " " + verb + " been wounded by gunfire. There "+ + being + " " + cardinal(this_player()->GetLead())+" bullet hole"+ + plural + " in " + poss + " body."; + + return ret; +} + +void create(){ + ::create(); + SetKeyName("wound"); + SetId(({"wound","firearms_wound","wounds"})); + SetShort("a gunshot wound"); + SetLong( (: WoundLong :) ); + set_heart_beat(20); +} + +string GetAffectLong(object ob) { + if(!ob || !living(ob) || ob->GetUndead()) return 0; + return ob->GetName() + " is suffering from gunshot wounds."; +} + +void heart_beat(){ + object ob = environment(); + int num; + if(!ob || !living(ob)){ + this_object()->eventMove(ROOM_FURNACE); + return; + } + num = ob->GetLead(); + if(!num){ + int tmp = ob->GetLead("gunshot_wounds"); + ob->AddLead("gunshot_wounds", -tmp); + tmp = ob->GetLead("rifleshot_wounds"); + ob->AddLead("rifleshot_wounds", -tmp); + this_object()->eventMove(ROOM_FURNACE); + return; + } + if(!RACES_D->GetNonMeatRace(ob->GetRace()) && interactive(ob) + && !(ob->GetUndead())){ + tell_object(ob,"You bleed heavily from your gunshot wounds."); + tell_room(environment(ob), ob->GetName()+ + " bleeds heavily from "+possessive(ob)+" gunshot "+ + "wounds.",environment()); + } +} + +mixed CanGet(object ob) { return "#Your hands slip on the gunshot wounds.";} +mixed CanDrop(object ob) { return "#Your hands slip on the gunshot wounds.";} diff --git a/lib/lib/steal.c b/lib/lib/steal.c new file mode 100644 index 0000000..21922fd --- /dev/null +++ b/lib/lib/steal.c @@ -0,0 +1,38 @@ +/* /lib/steal.c + * from the Dead Souls Object Library + * handles the stealing of objects + * created by Descartes of Borg 960210 + */ + +#include "include/steal.h" + +static private mixed PreventSteal; + +static void create(){ + PreventSteal = 0; +} + +mixed direct_steal_obj_from_liv(){ return CanSteal(this_player()); } + +mixed CanSteal(object who){ + if( GetInvis(who) ) return 0; + if( PreventSteal ){ + if( PreventSteal == 1 ) return "You can't steal that!"; + if( stringp(PreventSteal) ) return PreventSteal; + if( objectp(PreventSteal) ){ + if( PreventSteal == who ) + return "Mystical forces prevent your thievery."; + return 1; + } + return evaluate(PreventSteal, who); + } + return 1; +} + +mixed eventSteal(object who){ + return eventMove(who); +} + +mixed SetPreventSteal(mixed val){ return (PreventSteal = val); } + +mixed GetPreventSteal(){ return PreventSteal; } diff --git a/lib/lib/talk.c b/lib/lib/talk.c new file mode 100644 index 0000000..716ede6 --- /dev/null +++ b/lib/lib/talk.c @@ -0,0 +1,331 @@ +/* /lib/talk.c + * from the Dead Souls Object Library + * handles general yapping + * created by Descartes of Borg 951118 + * Version: @(#) talk.c 1.5@(#) + * Last Modified: 96/10/08 + */ + +#include <talk_type.h> +#include <commands.h> +#include <daemons.h> +#include <message_class.h> +#include "include/talk.h" +#define MAX_TELL_HIST_SIZE 50 + +private mixed TalkHist = ([]); +private string SpeakColor = "CYAN%^"; + +int GetPolyglot(); + +int direct_ask_liv_str(){ return 1; } + +int direct_ask_liv_to_str(){ return 1; } + +int direct_ask_liv_for_str(){ return 1; } + +int direct_ask_liv_about_str(){ return 1; } + +int direct_request_str_from_liv(){ return 1; } + +int direct_say_to_liv(){ return 1; } + +int direct_say_to_liv_str(){ return 1; } + +int direct_whisper_to_liv(){ return 1; } + +int direct_whisper_in_wrd_to_liv(){ return 1; } + +int direct_whisper_to_liv_str(){ return 1; } + +int direct_whisper_in_wrd_to_liv_str(){ return 1; } + +int direct_whisper_to_liv_in_wrd_str(){ return 1; } + +string SetSpeakColor(string str){ + if(!str) str = "foo"; + switch(str){ + case "red" : SpeakColor = upper_case(str)+"%^";break; + case "green" : SpeakColor = upper_case(str)+"%^";break; + case "orange" : SpeakColor = upper_case(str)+"%^";break; + case "yellow" : SpeakColor = upper_case(str)+"%^";break; + case "blue" : SpeakColor = upper_case(str)+"%^";break; + case "magenta" : SpeakColor = upper_case(str)+"%^";break; + case "black" : SpeakColor = upper_case(str)+"%^";break; + case "white" : SpeakColor = upper_case(str)+"%^";break; + case "b_red" : SpeakColor += upper_case(str)+"%^";break; + case "b_green" : SpeakColor += upper_case(str)+"%^";break; + case "b_orange" : SpeakColor += upper_case(str)+"%^";break; + case "b_yellow" : SpeakColor += upper_case(str)+"%^";break; + case "b_blue" : SpeakColor += upper_case(str)+"%^";break; + case "b_magenta" : SpeakColor += upper_case(str)+"%^";break; + case "b_black" : SpeakColor += upper_case(str)+"%^";break; + case "b_white" : SpeakColor += upper_case(str)+"%^";break; + case "b_cyan" : SpeakColor += upper_case(str)+"%^";break; + case "flash" : SpeakColor += upper_case(str)+"%^";break; + default : SpeakColor = "CYAN%^";break; + } + return SpeakColor; +} + +string GetSpeakColor(){ return SpeakColor; } + +int eventTellHist(string str){ + string pob = base_name(previous_object()); + string stack = implode(call_stack(2)," "); + string tz = this_object()->GetProperty("timezone"); + if(!tz || !valid_timezone(tz)) tz = query_tz(); + if(!TalkHist) TalkHist = ([]); + if(!TalkHist["tell"]) TalkHist["tell"] = ({}); + if(pob != SERVICES_D && pob != CMD_TELL && + pob != IMC2_D && pob != INSTANCES_D && + stack != "eventTellHist eventHearTalk eventSpeak cmd cmdAll <function>" && + stack != "eventTellHist eventHearTalk eventSpeak cmd cmd cmdAll <function>"){ + return 0; + } + if(sizeof(TalkHist["tell"]) > MAX_TELL_HIST_SIZE){ + TalkHist["tell"] -= ({ TalkHist["tell"][0] }); + } + TalkHist["tell"] += ({ timestamp(tz)+" "+str }); + return 1; +} + +string array GetTellHistory(){ + if(!TalkHist) TalkHist = ([]); + if(!TalkHist["tell"]) TalkHist["tell"] = ({}); + if(this_object() != this_player() && !archp(this_player())) + return ({}); + return copy(TalkHist["tell"]); +} + +int eventTalkHist(string str, string type){ + string pob = base_name(previous_object()); + string stack = implode(call_stack(2)," "); + string tz = this_object()->GetProperty("timezone"); + if(!tz || !valid_timezone(tz)) tz = query_tz(); + if(!TalkHist) TalkHist = ([]); + if(!TalkHist[type]) TalkHist[type] = ({}); + if(sizeof(TalkHist[type]) > MAX_TELL_HIST_SIZE){ + TalkHist[type] -= ({ TalkHist[type][0] }); + } + TalkHist[type] += ({ timestamp(tz)+" "+str }); + return 1; +} + +string array GetTalkHistory(string type){ + if(!type) type = "say"; + if(!TalkHist) TalkHist = ([]); + if(!TalkHist[type]) TalkHist[type] = ({}); + if(this_object() != this_player() && !archp(this_player())) + return ({}); + return copy(TalkHist[type]); +} + +string array GetTalkHistTypes(){ + if(!TalkHist) TalkHist = ([]); + return keys(TalkHist); +} + +varargs mixed CanSpeak(object target, string verb, string msg, string lang){ + if(!this_player()->CanBreathe()){ + return "You can't even breathe."; + } + if( lang && (!this_object()->GetPolyglot() && (!GetLanguageLevel(lang) || !GetLanguageName(lang)) ) ) + return "You don't speak that language!"; + if( target ){ + if( target == this_object() ) + return "Are you really intent on talking to yourself?"; + if( userp(target) && !interactive(target) ) + return target->GetName() + " is net-dead."; + if( target->GetBlocked("tell") ) + return target->GetName() + " is blocking all tells."; + } + return 1; +} + +varargs mixed eventHearTalk(object who, object target, int cls, string verb, + string msg, string lang){ + string tmp; + object *riders = this_object()->GetRiders() - ({ who }); + + if(riders && sizeof(riders)) + riders->eventHearTalk(who, target, cls, verb, (msg ||0), (lang ||0)); + + if( lang && !newbiep() && !GetPolyglot() ) msg = translate(msg, GetLanguageLevel(lang)); + switch(cls){ + case TALK_PRIVATE: + if( target != this_object() ) return 0; + if( verb == "reply" ) + tmp = "%^BOLD%^RED%^" + who->GetName() + + " replies,%^RESET%^ \"" + msg + "%^RESET%^\""; + else tmp = "%^BOLD%^RED%^" + who->GetName() + + " tells you,%^RESET%^ \"" + msg + "%^RESET%^\""; + if(target->GetMuffed() && member_array(who->GetKeyName(),target->GetMuffed()) == -1){ + eventTellHist(tmp); + this_object()->eventPrint(tmp, MSG_CONV); + } + break; + + case TALK_SEMI_PRIVATE: + if( target != this_object() ) return 0; + tmp = "%^BOLD%^" + SpeakColor + who->GetName() + " whispers in " + + capitalize(lang) + " to you,%^RESET%^ \"" + msg + "%^RESET%^\""; + this_object()->eventPrint(tmp, MSG_CONV); + eventTalkHist(tmp, "whisper"); + break; + + case TALK_LOCAL: + if( target ){ + if( target != this_object() ){ + if( msg[<1] == '?' ) tmp = target->GetName(); + else tmp = "to " + target->GetName(); + if( lang ) tmp += " in " + capitalize(lang); + } + else { + if( msg[<1] == '?' ) tmp = "you"; + else tmp = "to you"; + if( lang ) tmp += " in " + capitalize(lang); + } + tmp = who->GetName() + " " + pluralize(verb) + " " + tmp + + ", \""; + tmp = tmp + "%^BOLD%^CYAN%^\"" + msg + "%^RESET%^\""; + eventTalkHist(tmp, "say"); + this_object()->eventPrint(tmp, MSG_CONV); + } + else if( verb == "yell" ){ + tmp = "%^BOLD%^GREEN%^You hear a " + who->GetGender() + + " " + who->GetRace() + " yell in " + capitalize(lang) + + " from a distance,%^RESET%^ \"" + msg + "%^RESET%^\""; + eventTalkHist(tmp, "yell"); + this_object()->eventPrint(tmp, MSG_CONV); + } + else { + if( lang ) tmp = pluralize(verb) + " in " + capitalize(lang); + else tmp = pluralize(verb); + tmp = who->GetName() + " " + tmp + ", \""; + tmp = tmp + "%^BOLD%^" + SpeakColor + msg + "%^RESET%^\""; + this_object()->eventPrint(tmp, MSG_CONV); + eventTalkHist(tmp, verb); + } + break; + + case TALK_AREA: + tmp = "%^BOLD%^GREEN%^" + who->GetName() + " yells in " + + capitalize(lang) + ",%^RESET%^ \"" + msg + "%^RESET%^\""; + eventTalkHist(tmp, "yell"); + this_object()->eventPrint(tmp, MSG_CONV); + break; + + case TALK_WORLD: + tmp = "%^BOLD%^BLUE%^" + who->GetName() + " shouts in " + + capitalize(lang) + ",%^RESET%^ \"" + msg + "%^RESET%^\""; + eventTalkHist(tmp, "shout"); + this_object()->eventPrint(tmp, MSG_CONV); + break; + + default: + return 0; + } + this_object()->eventTalkRespond(who, target, cls, msg, lang); + return 1; +} + +mixed eventTalkRespond(object who, object targ, int cls, string msg, string lang){ + return true(who,targ,cls,msg,lang); +} + +varargs mixed eventSpeak(object target, int cls, string msg, string lang){ + string verb, tmp; + int cols; + object env; + + if( living(environment()) ){ + object *riders = environment()->GetRiders(); + if(riders && sizeof(riders) ){ + if(member_array(this_object(),riders) != -1){ + if(environment()->GetVisibleRiders()) + env = environment(environment()); + } + } + } + + if(!env) env = environment(); + + if( lang && !GetPolyglot() ){ + msg = translate(msg, GetLanguageLevel(lang)); + lang = GetLanguageName(lang); + } + cols = GetScreen()[0]; + if( msg[<1] != '?' && msg[<1] != '!' && msg[<1] != '.' ) + msg = capitalize(msg) + "."; + else msg = capitalize(msg); + switch( cls ){ + case TALK_PRIVATE: + tmp = "%^BOLD%^RED%^You tell " + target->GetName() + + ",%^RESET%^ \"" + msg + "%^RESET%^\""; + this_object()->eventPrint(tmp, MSG_CONV); + target->eventHearTalk(this_object(), target, cls, "tell", msg); + eventTellHist(tmp); + return 1; + + case TALK_SEMI_PRIVATE: + if( !target ) tmp = "%^BOLD%^CYAN%^You whisper in " + capitalize(lang) + + ",%^RESET%^ \"" + msg + "%^RESET%^\""; + else tmp = "%^BOLD%^CYAN%^You whisper in " + capitalize(lang) + " to " + + target->GetName() + ",%^RESET%^ \"" + msg + "%^RESET%^\""; + eventTalkHist(tmp, "whisper"); + this_object()->eventPrint(tmp, MSG_CONV); + env->eventHearTalk(this_object(), target, cls, "whisper", + msg, lang); + return 1; + + case TALK_LOCAL: + if( msg[<1] == '?' ) verb = GetMessage("ask") || "ask"; + else if( msg[<1] == '!' ) verb = GetMessage("exclaim") || "exclaim"; + else { + verb = GetMessage("say") || "say"; + if ((msg[<1] >= 'a' && msg[<1] <= 'z') || + (msg[<1] >= 'A' && msg[<1] <= 'Z')) msg = msg + "."; + } + if( target && msg[<1] == '?' ){ + tmp = "You " + verb + " " + target->GetName(); + if( lang ) tmp = tmp + " in " + capitalize(lang); + } + else if( target ){ + tmp = "You " + verb + " to " + target->GetName(); + if( lang ) tmp = tmp + " in " + capitalize(lang); + } + else { + tmp = "You " + verb; + if( lang ) tmp = tmp + " in " + capitalize(lang); + } + tmp = tmp + ", \"%^BOLD%^" + SpeakColor + msg + "%^RESET%^\""; + eventTalkHist(tmp, "say"); + this_object()->eventPrint(tmp, MSG_CONV); + env->eventHearTalk(this_object(), target, cls, verb, msg, + lang); + return 1; + + case TALK_AREA: + tmp = "%^BOLD%^GREEN%^You yell in " + capitalize(lang) + ",%^RESET%^ \"" + + msg + "%^RESET%^\""; + eventTalkHist(tmp, "yell"); + this_object()->eventPrint(tmp, MSG_CONV); + env->eventHearTalk(this_object(), target, cls, "yell", msg, + lang); + break; + + case TALK_WORLD: + tmp = "%^BOLD%^BLUE%^You shout in " + capitalize(lang) + ",%^RESET%^ \"" + + msg + "%^RESET%^\""; + eventTalkHist(tmp, "shout"); + this_object()->eventPrint(tmp, MSG_CONV); + INSTANCES_D->eventSendShout(msg, lang); + (users() - ({ this_object() }))->eventHearTalk(this_object(), target, + cls,"shout", msg, lang); + return 1; + + default: + return 0; + } +} diff --git a/lib/lib/teach.c b/lib/lib/teach.c new file mode 100644 index 0000000..4af9ce5 --- /dev/null +++ b/lib/lib/teach.c @@ -0,0 +1,76 @@ +#include <lib.h> + +private static mapping Teaching = ([]); +private static int OfferExpires = 60; + +int direct_teach_str_to_liv(){ return 1;} +int direct_teach_liv_to_str(){ return 1;} + +varargs int CanTeach(object whom, string what){ + if(whom == this_object()){ + write("You are not a member of the autodidact guild."); + return 0; + } + if(member_array(what, keys(this_object()->GetSpellBook())) != -1){ + int magpoint = this_object()->GetMagicPoints(); + int maxmagpoint = this_object()->GetMaxMagicPoints(); + if(magpoint < maxmagpoint){ + write("You must have your full mana to teach magic."); + return 0; + } + return 1; + } + return 0; +} + +int eventOfferTeaching(object who, string what){ + if(!CanTeach(who, what)){ + write("You are unable to teach that."); + return 0; + } + //if(!Teaching[who] || !Teaching[who][0] || Teaching[who][0] != what){ + tell_player(who,this_object()->GetName()+ + " offers to teach you "+what+"."); + tell_player(this_object(),"You offer to teach "+what+ + " to "+who->GetName()+"."); + //} + Teaching[who] = ({ what, time() }); + return 1; +} + +int eventTeach(object who, string what){ + int magpoint = this_object()->GetMagicPoints(); + if(!CanTeach(who, what)){ + write("They can't teach that."); + return 0; + } + if(!Teaching[who]){ + write("They're not interested in teaching you anything."); + return 0; + } + if(time() - Teaching[who][1] > OfferExpires){ + write("It's too late. Their offer to teach you expired."); + map_delete(Teaching,who); + return 0; + } + if( !who->eventLearnSpell(what) ){ + write("You are not prepared for that spell!"); + return 0; + } + + who->eventPrint(this_object()->GetName() + " touches your forehead and gives " + "you knowledge of " + what + "."); + environment()->eventPrint(this_object()->GetName() + " touches " + + possessive_noun(who) + + " forehead and gives " + + objective(who) + " knowledge of " + + what + ".", ({ who, this_object() })); + this_object()->eventPrint("You touch "+possessive_noun(who) + + " forehead and give " + objective(who) + " knowledge of " + + what + "."); + if(!creatorp(this_object())){ + this_object()->AddMagicPoints(-magpoint); + } + map_delete(Teaching,who); + return 1; +} diff --git a/lib/lib/teacher.c b/lib/lib/teacher.c new file mode 100644 index 0000000..ee7d786 --- /dev/null +++ b/lib/lib/teacher.c @@ -0,0 +1,238 @@ +/* /lib/teacher.c + * from the Dead Souls Library + * created 960320 by Blitz@Dead Souls + * Version: @(#) teacher.c 1.3@(#) + * Last modified: 96/10/28 + */ + +#include <lib.h> +#include <daemons.h> +#include "include/teacher.h" + +inherit LIB_SENTIENT; + +private string array TeachingLanguages; +private mapping Students; +private int commercial = 0; +private int AllLangs = 0; +private int teaching_fee = 50; +private string local_currency = "silver"; + +int SetAllLanguages(int i){ + if(!i) AllLangs = 0; + else AllLangs = 1; + return AllLangs; +} + +int GetAllLanguages(){ + return AllLangs; +} + +int GetCommercial(){ + return commercial; +} + +int SetCommercial(int i){ + if(i){ + commercial = i; + if(!teaching_fee) teaching_fee = 50; + } + else commercial = 0; + return commercial; +} + +string GetLocalCurrency(){ + return local_currency; +} + +string SetLocalCurrency(string str){ + local_currency = str; + return local_currency; +} + +int GetTeachingFee(){ + return teaching_fee; +} + +int SetTeachingFee(int i){ + if(i){ + teaching_fee = i; + commercial = 1; + } + else { + teaching_fee = 0; + commercial = 0; + } + return teaching_fee; +} + +/**** driver applies ****/ + +static void create(){ + sentient::create(); + TeachingLanguages = ({}); + Students = ([]); + SetNoClean(1); + SetCommandResponses( ([ + "teach" : (: eventTeachLanguage :), + "teach" : (: eventTeachLanguage :), + "default" : (: eventHelp :), + "help" : (: eventHelp :), + ]) ); + SetRequestResponses( ([ + "default" : (: eventHelp :), + "help" : (: eventHelp :), + ]) ); +} + +static void init(){ + string str; + sentient::init(); + if( !living(this_player()) ) return; + str = this_player()->GetKeyName(); + if( Students[str] ){ + eventForce("speak You will have to start your " + "studies anew, "+this_player()->GetName()); + map_delete(Students, str); + } +} + +/**** data manipulation ****/ + +mixed AddTeachingLanguages(string *args){ + string *tmp_array = ({}); + if( !args ) + error("Bad argument 1 to AddTeachingLanguages."); + foreach(string lang in args){ + tmp_array += ({ capitalize(lower_case(lang)) }); + } + return (TeachingLanguages = distinct_array(TeachingLanguages + tmp_array)); +} + +mixed RemoveTeachingLanguages(string *args...){ + if( !args || !arrayp(args) ) + error("Bad argument 1 to RemoveTeachingLanguages."); + TeachingLanguages -= args; + return TeachingLanguages; +} + +string array GetTeachingLanguages(){ return copy(TeachingLanguages); } + +string Expertise(){ + string tmp, expertises; + if(!sizeof(GetTeachingLanguages())) return "none"; + else if(sizeof(GetTeachingLanguages()) == 1){ + return GetTeachingLanguages()[0]; + } + expertises = implode(GetTeachingLanguages(), ", "); + if(sizeof(GetTeachingLanguages()) == 2){ + expertises = replace_string(expertises,", "," and "); + } + else if(sizeof(GetTeachingLanguages()) > 2){ + tmp = last_string_element(expertises,","); + expertises = replace_string(expertises, tmp, " and"+tmp); + } + return expertises; +} + +mapping GetStudents(){ return copy(Students); } + +/**** high-level events ****/ + +int eventHelp(object who, string unused){ + eventForce("speak I am not sure of what you are " + "asking, " + who->GetName() + "."); + if(sizeof( GetTeachingLanguages() )){ + eventForce("speak My area of expertise covers " + + Expertise() + "."); + eventForce("speak You can \"ask "+GetKeyName()+" to teach " + "<LANGUAGE>\" if you have training points."); + } + return 1; +} + +int eventTeachLanguage(object who, string verb, string language){ + if( !who || environment(who) != environment() ){ + return 0; + } + if( !sizeof(language) || !sizeof(verb) ) return eventHelp(who, 0); + if( verb == "teach" ){ + + language = capitalize(language); + + if( Students[ who->GetKeyName() ] ){ + eventForce("speak I am already teaching you!"); + return 0; + } + if( !GetAllLanguages() && + member_array(language, this_object()->GetTeachingLanguages()) == -1 ){ + eventForce("speak I know nothing about the " +capitalize(language)+" language."); + return 0; + } + if( !commercial && this_player()->GetTrainingPoints() < 1 ){ + eventForce("speak You need more training points."); + return 0; + } + if(commercial && this_player()->GetCurrency(GetLocalCurrency()) < teaching_fee){ + eventForce("speak I charge "+teaching_fee+" "+GetLocalCurrency()+" per lesson. "+ + "You don't seem to have the right amount of the right currency."); + return 0; + } + Students[ who->GetKeyName() ] = language; + eventStart(who, language); + call_out((: ContinueTeaching, who, language, 0 :), TEACHING_WAIT); + return 1; + } + return 1; +} + +static int ContinueTeaching(object who, string language, int x){ + language = capitalize(language); + if( !who || !Students[who->GetKeyName()] ) return 0; + if( !present(who, environment()) || + member_array(who, this_object()->GetEnemies()) != -1){ + map_delete(Students, who->GetKeyName()); + return 0; + } + if( x > 4 ){ + map_delete(Students, who->GetKeyName()); + eventComplete(who, language); + who->AddLanguagePoints(language,5+((who->GetStatLevel("intelligence")/10)*2)+random(10)); + if(!commercial) who->AddTrainingPoints(-1); + else who->AddCurrency(GetLocalCurrency(),-teaching_fee); + return 1; + } else { + eventContinue(who, language, ++x); + call_out((: ContinueTeaching, who, language, x :), TEACHING_WAIT); + return 1; + } +} + +/**** message handling events ****/ + +/* The three following events are purely *aesthetic*, + * Hopefully prolific coders will override them for + * more interesting teaching techniques. :) + */ + +int eventStart(object who, string language){ + who->eventPrint(GetName() + " begins teaching you " + "about the " + language + " language."); + environment()->eventPrint(GetName() + " begins teaching " + + who->GetName() + "...", who); + return 1; +} + +int eventContinue(object who, string language, int x){ + who->eventPrint("You listen intently as " + GetName() + + " continues " + possessive(this_object()) + + " dissertation on " + language + "."); + return 1; +} + +int eventComplete(object who, string language){ + who->eventPrint("You feel somewhat more competent in " + language + "."); + eventForce("speak I can teach you no more for now, " + + who->GetName() + "."); + return 1; +} diff --git a/lib/lib/teller.c b/lib/lib/teller.c new file mode 100644 index 0000000..66166d8 --- /dev/null +++ b/lib/lib/teller.c @@ -0,0 +1,366 @@ +/* /lib/teller.c + * from the Dead Souls Object Library + * npc interface which handles banking transactions + * created by Blitz@Dead Souls 960105 + * Version: @(#) teller.c 1.3@(#) + * Last Modified: 96/10/22 + */ + +#include <lib.h> +#include <daemons.h> +#include "include/teller.h" + +inherit LIB_SENTIENT; +inherit LIB_MANYCOINS; + +string BankName, LocalCurrency; +string *Currencies; +int LocalFee, NonLocalFee, OpenFee; +float ExchangeFee; + +static void create(){ + sentient::create(); + BankName = "Town Trust"; + LocalCurrency = "silver"; + LocalFee = 1; + NonLocalFee = 5; + OpenFee = 5; + Currencies = ({ "copper", "silver", "electrum", "gold", "platinum" }); + SetCommandResponses( ([ + "default" : (: cmdParse :), + ]) ); + SetRequestResponses( ([ + "default" : (: cmdParse :), + ]) ); +} + +string SetBankName(string str){ return (BankName = str); } + +string SetLocalCurrency(string str){ return (LocalCurrency = str); } + +int SetLocalFee(int x){ return (LocalFee = x); } + +int SetNonLocalFee(int x){ return (NonLocalFee = x); } + +int SetOpenFee(int x){ return (OpenFee = x); } + +float SetExchangeFee(float x){ return (ExchangeFee = x); } + +mixed SetCurrencies(mixed var){ + if( arrayp(var) ){ + if( member_array(LocalCurrency, var) == -1 ) + var += ({ LocalCurrency }); + return (Currencies = var); + } + else error("Bad argument 1 to SetCurrencies()"); +} + +int GetLocalFee(){ return LocalFee; } + +int GetNonLocalFee(){ return NonLocalFee; } + +int GetExchangeFee(){ return ExchangeFee; } + +int GetOpenFee(){ return OpenFee; } + +mixed GetCurrencies(){ return copy(Currencies); } + +string GetBankName(){ return BankName; } + +string GetLocalCurrency(){ return LocalCurrency; } + +mixed CanBank(object who){ + if( !who->GetAccountInfo( GetBankName() ) ) + return "You must create an account with "+GetBankName()+" first."; + return 1; +} + +int AddSurcharge(object who, string currency, int amount){ + int charge; + string type; + + if( who->GetTown() == GetTown() ){ + type = "standard"; + charge = GetLocalFee(); + } else { + type = "non-residential"; + charge = GetNonLocalFee(); + } + if( !charge ) return amount; + if( amount > charge ){ + amount -= charge; + who->eventPrint(sprintf("The bank retains a %s " + "surcharge of %d %s.", type, charge, currency)); + return amount; + } + else { + who->eventPrint(sprintf("You are unable to afford the " + "%s surcharge of %d %s.", type, charge, currency)); + return 0; + } + return amount; +} + +int eventBalance(object who){ + string str, ret, *tmp; + mapping mp; + float val; + int total; + + mp = who->GetAccountInfo( GetBankName() ); + if( !mp ) return 0; + environment()->eventPrint( who->GetName() + " requests " + "current balance.", ({ who }) ); + ret = "Your account with "+GetBankName()+" was " + "opened "+ctime(mp["open"])+".\n"; + ret += "This location's default currency is "+GetLocalCurrency()+".\n\n"; + tmp = filter(keys(mp), (: member_array($1, Currencies) > -1 :)); + total = 0; + if( !sizeof(tmp) ) + ret += "You have made no deposits.\n"; + else foreach(str in tmp){ + if( mp[str] < 1 ) continue; + ret += sprintf("%-20s : %d\n", str+"", mp[str]); + if( str == GetLocalCurrency() ) total += mp[str]; + else if( mp[str] ){ + if( currency_rate(str) ) + val = query_value(mp[str],str,GetLocalCurrency()); + else val = 0; + if(val) total += val; + } + } + ret += sprintf("%-20s ----------\n%-22s %d", + "", "Total in "+GetLocalCurrency(), total); + if( mp["last time"] ) + ret += sprintf("\n\nYour last transaction: %s at %s.", + mp["last trans"], ctime(mp["last time"]) ); + who->eventPage(explode(ret, "\n"), "info"); + return 1; +} + +int eventDeposit(object who, string currency, int amount){ + int i; + if( amount < 1 ){ + eventForce("speak " + who->GetName() + ", " + "That transaction is unacceptable."); + return 1; + } + if( !currency ) currency = GetLocalCurrency(); + if( !(i = who->GetCurrency(currency)) ){ + eventForce("speak You are not carrying any "+currency+"."); + return 1; + } + if( amount > i ){ + eventForce("speak You are not carrying that much "+ currency +"."); + return 1; + } + who->eventPrint(sprintf("You deposit %d %s into your " + "account.", amount, currency)); + environment()->eventPrint(who->GetName() + " makes " + "a deposit.", ({ who }) ); + who->AddCurrency(currency, -amount); + who->AddBank(GetBankName(), currency, amount); + return 1; +} + +int eventWithdraw(object who, string currency, int amount){ + int i, x, charge; + + x = amount; + if( amount < 1 ){ + eventForce("speak Withdrawing a negative amount is not a prudent " + "idea, "+ who->GetName() +"."); + return 1; + } + if( !currency ) currency = GetLocalCurrency(); + if( !(i = who->GetBank(GetBankName(), currency)) ){ + eventForce("speak You have no "+currency+" in your account."); + return 1; + } + if( amount > i ){ + eventForce("speak You do not have that much "+currency+" in your " + "account."); + return 1; + } + if( !(amount = AddSurcharge(who, currency, amount)) ) return 1; + charge = x - amount; + if( who->AddCurrency(currency, x) < 0 ){ + eventForce("speak You are unable to carry that " + "much "+currency+"!"); + who->eventPrint("The bank credits your account with the fee."); + return 1; + } + who->AddCurrency(currency, -charge); + who->AddBank(GetBankName(), currency, -x); + who->eventPrint(sprintf("You withdraw %d %s from your account.", + amount, currency)); + environment()->eventPrint(sprintf("%s withdraws some %s.", + who->GetName(), currency), ({ who })); + return 1; +} + +int eventExchange(object who, int amount, string str1, string str2){ + int i, x, charge; + float val; + + if( amount < 0 ){ + amount = who->GetCurrency(str1); + } + if( amount < 1 ){ + eventForce("speak " + who->GetName() + ", that " + "transaction cannot be completed."); + return 1; + } + if( amount > who->GetCurrency(str1) ){ + eventForce("speak You do not have enough of that currency to exchange."); + return 1; + } + if( str1 == str2 ){ + eventForce("speak That would be pointless."); + return 1; + } + if( member_array(str1, GetCurrencies()) == -1 ){ + eventForce("speak You cannot exchange that currency here."); + return 1; + } + if( member_array(str2, GetCurrencies()) == -1 ){ + eventForce("speak You cannot exchange that currency here."); + return 1; + } + val = query_base_value(str1,amount); + x = to_int( (amount * 0.01) + amount ); + i = val / currency_rate(str2); + if( GetExchangeFee() ) + charge = to_int(i / (100 / GetExchangeFee())); + else charge = 0; + if( charge ) i -= charge; + if( i < 1 ){ + eventForce("speak That isn't even worth one " + str2 + "!"); + return 1; + } + if( who->AddCurrency(str2, i) < 0 ){ + eventForce("speak You cannot carry that much "+str2+", " + + who->GetName()+"."); + return 1; + } + who->AddCurrency(str1, -amount); + who->eventPrint(sprintf("You exchange %d %s for %d %s.", + amount, str1, i, str2)); + if( charge ) + who->eventPrint(sprintf("You were charged a fee of %d %s.", + charge, str2) ); + environment()->eventPrint(who->GetName()+" exchanges some "+ + str1+" for "+str2+".", who); + return 1; +} + +int eventOpenAccount(object who){ + if( who->GetAccountInfo( GetBankName() ) ){ + eventForce("speak You already have an account with "+GetBankName()+", " + + who->GetName()+"!"); + return 1; + } + if( who->GetCurrency( GetLocalCurrency() ) < OpenFee ){ + eventForce(" speak "+ sprintf("You must have at least %d %s to open " + "an account at this branch of %s, %s.", GetOpenFee(), + GetLocalCurrency(), GetBankName(), who->GetName())); + return 1; + } + if( OpenFee < 1 ) return 0; + who->AddCurrency(GetLocalCurrency(), -OpenFee); + who->AddBank(GetBankName(), GetLocalCurrency(), OpenFee); + who->eventPrint(sprintf("You deposit %d %s and open an account " + "with %s.", OpenFee, GetLocalCurrency(), GetBankName()) ); + eventBalance(who); + environment()->eventPrint(who->GetName() + " opens an " + "account.", who); + eventForce("smile "+who->GetKeyName()); + return 1; +} + +int cmdParse(object who, string cmd, string str, mixed args...){ + int x; + string s1, s2, honorific; + mixed err; + + if( cmd != "account" && stringp(err = CanBank(who)) ){ + who->eventPrint(err); + return 1; + } + switch(cmd){ + case "balance" : + return eventBalance(who); + break; + case "deposit" : + if( !str ){ + eventForce("speak How much of what?"); + return 1; + } + if(str == "all"){ + if(!sizeof(this_player()->GetCurrencies())){ + who->eventPrint("You have no money to deposit."); + return 1; + } + foreach(string dinero in this_player()->GetCurrencies()){ + if(this_player()->GetCurrency(dinero) > 0) + eventDeposit(who, dinero, this_player()->GetCurrency(dinero)); + } + return 1; + } + sscanf(str, "%d %s", x, s1); + if( member_array(s1, Currencies) < 0 ){ + who->eventPrint("That's not a valid currency."); + return 1; + } + return eventDeposit(who, s1, x); + break; + case "withdraw" : + if( !str ){ + eventForce("speak How much of what?"); + return 1; + } + if(str == "all"){ + if(this_player()->GetGender() == "female") honorific = "ma'am"; + else honorific = "sir"; + eventForce("speak I'm sorry, "+honorific+", but withdrawals must be specified explicitly in terms of currency type and amount."); + return 1; + } + sscanf(str, "%d %s", x, s1); + if( member_array(s1, Currencies) < 0 ){ + if(!s1) who->eventPrint("Please specify a currency."); + else who->eventPrint(s1 + " is not supported here!"); + return 1; + } + return eventWithdraw(who, s1, x); + break; + case "exchange" : + if( !str ){ + eventForce("speak Exchange what for what?"); + return 1; + } + if(sscanf(str, "%d %s for %s", x, s1, s2) < 3){ + x = -1; + sscanf(str, "%s for %s", s1, s2); + } + if(s1 == "all"){ + int ret = 0; + foreach(string curr in (who->GetCurrencies() - ({ s2 }))){ + if(who->GetCurrency(curr) < 1) continue; + ret += eventExchange(who, -1, curr, s2); + } + return ret; + } + else return eventExchange(who, x, s1, s2); + break; + case "account" : + return eventOpenAccount(who); + break; + default: + eventForce("speak " + who->GetName() + ", I do not " + "understand what you want."); + eventForce("whisper to " + who->GetKeyName() + " Try " + "\"help banking\" if you are confused."); + + } + return 1; +} diff --git a/lib/lib/torch.c b/lib/lib/torch.c new file mode 100644 index 0000000..0554b24 --- /dev/null +++ b/lib/lib/torch.c @@ -0,0 +1,44 @@ +/* /lib/torch.c + * from the Dead Souls Object Library + * a torch-like inheritable that burns and such + * created by Descartes of Borg 960512 + */ + +#include <lib.h> +#include "include/torch.h" + +inherit LIB_BURN; +inherit LIB_ITEM; + +static void create(){ + item::create(); + burn::create(); +} + +int GetRadiantLight(int ambient){ + if( !GetLit() ) return 0; + else return item::GetRadiantLight(ambient); +} + +string GetShort(){ + string ret, str, article; + string litstr = "%^BOLD%^YELLOW%^(lit)%^RESET%^ "; + if(!GetLit() || query_verb() == "light" || query_verb() == "strike"){ + return item::GetShort(); + } + if(!(str = item::GetShort()) || str == "") return str; + article = (replace_string(str, remove_article(str), "") || ""); + str = remove_article(str); + ret = (sizeof(article) ? article : "") + litstr + str; + return ret; +} + +varargs string GetLong(string unused){ + string tmp; + + tmp = burn::GetLong(unused); + if( tmp != "" ) return item::GetLong(unused) + "\n" + tmp; + else return item::GetLong(unused); +} + +int direct_pray_for_str_for_obj(){ return 1; } diff --git a/lib/lib/trainer.c b/lib/lib/trainer.c new file mode 100644 index 0000000..5efb60b --- /dev/null +++ b/lib/lib/trainer.c @@ -0,0 +1,9 @@ +#include <lib.h> + +inherit LIB_BASE_TRAINER; +inherit LIB_SENTIENT; + +static void create(){ + base_trainer::create(); + sentient::create(); +} diff --git a/lib/lib/trap.c b/lib/lib/trap.c new file mode 100644 index 0000000..94ca728 --- /dev/null +++ b/lib/lib/trap.c @@ -0,0 +1,153 @@ +/* /lib/trap.c + * From the Dead Souls Object Library + * Allows living things to be trapped and stored across reboots + * Created by Descartes of Borg 961010 + * Version: @(#) trap.c 1.5@(#) + * Last modified: 96/12/03 + */ + +#include <lib.h> +#include "include/trap.h" + +inherit LIB_STORAGE; + +int EscapeChance = 0; +int MaxCapture = 0; + +static void create(){ + storage::create(); + if( sizeof(GetCaptives()) ){ + set_heart_beat(2); + } +} + +static void heart_beat(){ + if( !sizeof(GetCaptives()) ){ + set_heart_beat(0); + return; + } + if( !GetClosed() ){ + if( GetEscapeChance() > (1 + random(100)) ){ + eventEscape(); + } + } +} + +mixed indirect_capture_liv_word_obj(object target){ + if( environment() != this_player() ){ + return "#You do not have " + GetShort() + "."; + } + if( !target ){ + return 1; + } + return CanCapture(this_player(), target); +} + +mixed indirect_free_liv_from_obj(object target){ + if( environment() != this_player() ){ + return "#You do not have " + GetShort() + "."; + } + if( !target ){ + return 1; + } + return CanFree(this_player(), target); +} + +mixed CanCapture(object who, object target){ + if( environment(who) != environment(target) ){ + return "#You cannot get to it."; + } + if( GetClosed() ){ + return capitalize(GetShort()) + " is closed."; + } + if( sizeof(GetCaptives()) >= MaxCapture ){ + return "You cannot capture anything else with " + GetShort() + "."; + } + return 1; +} + +mixed CanFree(object who, object target){ + if( environment(target) != this_object() ){ + return "#" + target->GetName() + " is not in " + GetShort() + "."; + } + if( GetClosed() ){ + return "You must open " + GetShort() + " before you can free " + "things from it."; + } + return 1; +} + +mixed eventCapture(object who, object target){ + + if( !target->eventMove(this_object()) ){ + return target->GetShort() + " will not fit!"; + } + who->eventPrint("You capture " + target->GetName() + " in " + + GetShort() + "!"); + environment(who)->eventPrint(who->GetName() + " captures " + + target->GetName() + " in " + GetShort() + + ".", ({ who, target })); + target->eventPrint(who->GetName() + " captures you in " + GetShort() +"."); + set_heart_beat(2); + return 1; +} + +mixed eventEscape(){ + object array captives; + object captive, env; + + if( GetClosed() ){ + return 0; + } + captives = GetCaptives(); + if( !sizeof(captives) ){ + return 0; + } + captive = captives[random(sizeof(captives))]; + if( !captive ){ + return 0; + } + env = environment(); + if( living(env) ){ + env = environment(env); + if( !env ){ + return 0; + } + } + if( captive->eventMove(env) != 1 ){ + return 0; + } + env->eventPrint(captive->GetShort() + " escapes from " + GetShort() + "."); + return 1; +} + +mixed eventFree(object who, string target){ + target->eventMove(environment(who)); + who->eventPrint("You release " + target->GetName() + " from " + + GetShort() + "."); + environment(who)->eventPrint(who->GetName() + " releases " + + target->GetName() + " from " + GetShort()+".", + ({ who, target })); + target->eventPrint(who->GetName() + " releases you from " + GetShort() +"."); + return 1; +} + +object array GetCaptives(){ + return filter(all_inventory(), (: living :)); +} + +int GetEscapeChance(){ + return EscapeChance; +} + +int SetEscapeChance(int x){ + return (EscapeChance = x); +} + +int GetMaxCapture(){ + return MaxCapture; +} + +int SetMaxCapture(int x){ + return (MaxCapture = x); +} diff --git a/lib/lib/undead.c b/lib/lib/undead.c new file mode 100644 index 0000000..f6ea9be --- /dev/null +++ b/lib/lib/undead.c @@ -0,0 +1,108 @@ +/* /lib/undead.c + * From Dead Souls Object Library + * This differs from the NM LPmud version + * copyright (c) 1995 Dead Souls LPMud + * Created by Descartes of Borg 961025 + * Version: @(#) undead.c 1.8@(#) + * Last modified: 96/10/27 + */ + +#include <daemons.h> +#include <damage_types.h> + +private int Undead = 0; +private string UndeadType = 0; + +// These methods are defined in other objects which inherit this +string GetName(); +varargs string eventPrint(string message, mixed args...); +varargs int eventReceiveDamage(object agent, int type, int amt, int ins, + mixed limbs); +int eventCompleteHeal(int x); +int GetHealthPoints(); +int eventMoralAct(int x); +string GetRace(); +void NewBody(string str); +// end virtual method section + +/***** Data manipulation *****/ +string GetUndeadType(){ + return UndeadType; +} + +string SetUndeadType(string str){ + return (UndeadType = str); +} + +/* int SetUndead(int x) + * int x - 0 for living, 1 for undead + * + * description + * makes the living body undead if "x" is 1 or living if "x" is 0 + * + * returns the current status of the body + */ + +int GetUndead(){ + return Undead; +} + +int SetUndead(int x){ + if( GetUndead() == x ){ + return x; + } + if( x ){ + SetUndeadType("ghost"); + } + else { + SetUndeadType(0); + } + return (Undead = x); +} + +/***** Events *****/ +mixed eventBite(object target){ + return 0; +} + +mixed eventTurn(object who){ + if( who ){ + environment()->eventPrint(GetName() + " is turned from the world of " + "the living.", this_object()); + eventPrint(who->GetName() +" turns you from the world of the living."); + who->eventDestroyEnemy(this_object()); + } + else { + environment()->eventPrint(GetName() + " is turned from the world " + "of the living.", this_object()); + eventPrint("You have been turned from the world of the living."); + } + return 1; +} + +static void heart_beat(){ + string type; + + if( !GetUndead() ){ + return; + } + type = GetUndeadType(); + if( random(100) + 1 > 90 ){ + if( type == "ghost" || type == "phantom" ){ + eventPrint("You wail mournfully."); + environment()->eventPrint(GetName() + " wails mournfully.", + this_object()); + } + else if( type == "zombie" || type == "ghoul" ){ + eventPrint("You groan painfully."); + environment()->eventPrint(GetName() + " groans painfully.", + this_object()); + } + } +} + +int GetGhost(){ + if(GetUndeadType() == "ghost") return 1; + else return 0; +} + diff --git a/lib/lib/used_meal.c b/lib/lib/used_meal.c new file mode 100644 index 0000000..d9cdc5c --- /dev/null +++ b/lib/lib/used_meal.c @@ -0,0 +1,9 @@ +#include <lib.h> + +inherit LIB_ITEM; + +static void create(){ + item::create(); + AddSave( ({"KeyName", "ExternalDesc","Id","Short","Value","Cost","DestroyOnSell" }) ); +} + diff --git a/lib/lib/user/autosave.c b/lib/lib/user/autosave.c new file mode 100644 index 0000000..65f4eb6 --- /dev/null +++ b/lib/lib/user/autosave.c @@ -0,0 +1,92 @@ +/* /lib/user/autosave.c + * From the Dead Souls Mud Library + * Object to save a player to file + * Created by Descartes of Borg 940216 + * Version: @(#) autosave.c 1.3@(#) + * Last modified: 97/01/03 + */ + +#include <message_class.h> +#include <dirs.h> +#include <privs.h> + +private mixed array Inventory = 0; +private static int LastSave = time(); + +// abstract methods +string GetKeyName(); +varargs void eventPrint(string str, mixed args...); +varargs int RestoreObject(mixed str, int i); +varargs int SaveObject(mixed str, int i); +// end abstract methods + +nomask void restore_inventory(); +nomask void save_player(string nom); + +int Setup(){ + master()->create_save(); + call_out( (: save_player, GetKeyName() :), 2 ); + restore_inventory(); + return 1; +} + +nomask void restore_inventory(){ + if( Inventory ){ + foreach(string obdata in Inventory){ + object ob; + mixed tmp; + + tmp = restore_variable(obdata); + if( arrayp(tmp) ){ + ob = new(tmp[0]); + if( ob ) ob->eventConvertObject(tmp, 1); + } + else { + if( !catch(ob = new(tmp["#base_name#"])) ){ + if( ob ){ + ob->eventLoadObject(tmp, 1); + } + } + } + } + } + Inventory = 0; +} + +nomask int restore_player(string nom){ + string file; + int ret; + if( previous_object(0) != master() ){ + return 0; + } + file = player_save_file(nom); + ret = unguarded((: restore_object, file, 1 :)); + return ret; +} + +nomask void save_player(string nom){ + string file; + mixed ret; + if( !nom || nom != GetKeyName() ){ + return; + } + catch(this_object()->CalculateCarriedMass()); + Inventory = filter(map(all_inventory(), (: $1->GetSaveString() :)), + (: $1 :)); + file = player_save_file(GetKeyName()); + ret = unguarded((: save_object, file, 1 :)); + Inventory = 0; +} + +static void heart_beat(){ + int x = time(); + if( x - LastSave < AUTOSAVE_TIME ){ + return; + } + LastSave = x; + save_player(GetKeyName()); + if( !builderp(this_object()) && !present("visitor pass",this_object()) + && !testp(this_object()) ){ + eventPrint("Autosaving...", MSG_SYSTEM); + } +} diff --git a/lib/lib/vehicle.c b/lib/lib/vehicle.c new file mode 100644 index 0000000..6ed7d24 --- /dev/null +++ b/lib/lib/vehicle.c @@ -0,0 +1,335 @@ +#include <lib.h> +#include <daemons.h> +#include <medium.h> +#include ROOMS_H +#include <position.h> + +#define SOBER_COMBAT + +inherit LIB_BOT; +inherit LIB_ENTER; +inherit LIB_EXITS; +inherit LIB_READ; + +private object array DummyItems = ({}); +mapping ItemsMap = ([]); +private static mixed global_item; +string VehicleInterior = ""; + +mixed GetVehicleInterior(); + +void create(){ + bot::create(); + enter::create(); + SetPacifist(1); + SetNoCondition(0); + SetEnterMessage(""); +} + +void init(){ + string rvoid = ROOMS_D->GetVoid(this_object()); + string exterior = rvoid; + bot::init(); + if(environment()){ + exterior = file_name(environment()); + } + SetEnter( file_name(this_object())); + SetExits( (["out": exterior ]) ); +} + +int inventory_accessible(){ + if(environment(this_player()) == this_object()){ + return 1; + } + return 0; +} + +mixed eventMount(object who){ + int rider_weight; + string weight = "weight"; + if(!who) return 0; + if(environment() && environment()->GetMedium() == MEDIUM_SPACE){ + weight = "mass"; + } + rider_weight = who->GetMass(); + if(!environment(this_object())) return 0; + if(environment(who) && environment(who) == this_object()){ + return write("You are already mounted."); + } + if(rider_weight + this_object()->GetCarriedMass() > this_object()->GetMaxCarry()){ + return write("This vehicle cannot handle that much "+weight+"."); + } + else { + string int_desc = GetVehicleInterior(); + this_object()->SetNoClean(1); + write("You enter "+this_object()->GetShort()+"."); + if(int_desc) write(int_desc); + say(who->GetName()+" enters "+this_object()->GetShort()+"."); + who->SetProperty("mount", this_object()); + if(who->eventMove(this_object())) return AddRider(who); + else return 0; + } +} + +varargs mixed eventEnter(object who, string what, string verb){ + if(query_verb() == "fly"){ + return this_object()->eventDrive(what); + } + return eventMount(who); +} + +mixed CanGo(object who, string str){ + if( who->GetParalyzed() ) return "You are unable to move."; + else return 1; +} + +mixed eventGo(object who, string str){ + if(query_verb() == "fly"){ + return this_object()->eventDrive(str); + } + if(str == "out"){ + return eventDismount(who); + } + else return exits::eventGo(who, str); +} + +mixed direct_drive(){ + return this_object()->GetMount(); +} + +mixed direct_drive_word_str(){ + return this_object()->GetMount(); +} + +mixed direct_fly(){ + return this_object()->GetMount(); +} + +mixed direct_fly_word_str(){ + return this_object()->GetMount(); +} + +int eventDrive(string direction){ + string travel_cmd, s1, s2; + object *guys = get_livings(this_object()); + if(interactive(this_object())) return 0; + if(sscanf(direction,"%s %s",s1,s2) == 2){ + if(s1 == "enter" || s1 == "into") travel_cmd = "enter"; + } + + if(!s1 || s1 == "") switch(this_object()->GetPosition()){ + case POSITION_STANDING : travel_cmd = "go";break; + case POSITION_SITTING : travel_cmd = "crawl";break; + case POSITION_LYING : travel_cmd = "crawl";break; + case POSITION_FLYING : travel_cmd = "fly";break; + default : travel_cmd = "go"; + } + else direction = s2; + this_object()->eventForce(travel_cmd+" "+direction); + return 1; +} + +varargs string GetInternalDesc(){ + object array items = all_inventory(); + string desc; + int surfacep; + + surfacep = inherits(LIB_SURFACE , this_object()); + + desc = ""; + if(this_object()->CanClose() && GetOpacity() > 33){ + if(this_object()->GetClosed()) desc += " It is closed. "; + else desc += " It is open. "; + } + if(!surfacep) desc = desc + capitalize(add_article(GetShort(), 1)); + if(surfacep) desc = "On "+add_article(GetShort(), 1); + items = filter(items, (: !($1->isDummy()) && !($1->GetInvis()) :)); + if( sizeof(items) ){ + if(surfacep){ + desc = desc+" you see " + item_list(items) + "."; + } + else desc = desc + " contains " + item_list(items) + "."; + } + else { + if(!surfacep) desc = desc + " is completely empty."; + else desc = desc + " you see nothing."; + } + return desc; +} + +object array GetDummyItems(){ + DummyItems = ({}); + foreach(object item in all_inventory(this_object())){ + if(base_name(item) == LIB_DUMMY){ + DummyItems += ({ item }); + } + } + return DummyItems; +} + +varargs void AddItem(mixed item, mixed val, mixed adjectives){ + object ob, same_dummy; + object *dummies = filter(all_inventory(this_object()), (: base_name(LIB_DUMMY) :) ); + global_item = item; + + if( objectp(item) ){ + same_dummy = filter(dummies,(: ($1->GetId())[0] == (global_item->GetId())[0] :)); + if(sizeof(same_dummy)) return; + ob = item; + } + else { + if( stringp(item) ){ + item = ({ item }); + } + if( stringp(adjectives) ){ + adjectives = ({ adjectives }); + } + same_dummy = filter(dummies,(: member_array(global_item[0],$1->GetId()) != -1 :)); + if(sizeof(same_dummy)) return; + ob = new(LIB_DUMMY, item, val, adjectives); + } + ob->eventMove(this_object()); + DummyItems = ({ DummyItems..., ob }); +} + +mapping RemoveItem(mixed item){ + if( objectp(item) ){ + DummyItems -= ({ item }); + item->eventDestruct(); + return copy(Items); + } + else if( !arrayp(item) ){ + item = ({ item }); + } + foreach(object ob in GetDummyItems()){ + if( sizeof(ob->GetId() & item) ){ + ob->eventDestruct(); + DummyItems -= ({ ob }); + return copy(Items); + } + } +} + +mapping SetItems(mixed items){ + if(sizeof(DummyItems)) DummyItems->eventDestruct(); + DummyItems = ({}); + if( arrayp(items) ){ + items->eventMove(this_object()); + DummyItems = items; + } + else if( mapp(items) ){ + ItemsMap = items; + foreach(mixed key, mixed val in items){ + string array adjs = ({}); + object ob; + + if( stringp(key) ){ + key = ({ key }); + } + else { + if( sizeof(key) == 2 && arrayp(key[0]) ){ + adjs = key[1]; + key = key[0]; + } + } + ob = new(LIB_DUMMY, key, val, adjs); + ob->eventMove(this_object()); + DummyItems = ({ DummyItems..., ob }); + } + } + else { + error("Bad argument 1 to SetItems(), expected object array or " + "mapping.\n"); + } + return copy(ItemsMap); +} + +mapping GetItemsMap(){ + return copy(ItemsMap); +} + +void AddRead(mixed item, mixed val){ + if( stringp(item) ){ + item = ({ item }); + } + foreach(string tmp in item){ + foreach(object ob in GetDummyItems()){ + if( ob->id(tmp) ){ + ob->SetRead(val); + break; + } + } + } +} + +void RemoveRead(mixed item){ + foreach(object ob in GetDummyItems()){ + if( stringp(item) ){ + if( ob->id(item) ){ + ob->SetRead(0); + } + } + else if( arrayp(item) ){ + if( sizeof(ob->GetId() & item) ){ + ob->SetRead(0); + } + } + } +} + +varargs void SetRead(mixed items, mixed arg){ + if( !mapp(items) ){ + AddRead(items, arg); + return; + } + foreach(mixed key, mixed val in items){ + AddRead(key, val); + } +} + +varargs int eventDie(mixed agent){ + object *riders=get_livings(this_object()); + if(riders && sizeof(riders)){ + foreach(object rider in riders) eventBuck(rider); + } + return bot::eventDie(agent); +} + +int SetVehicleInterior(mixed arg){ + VehicleInterior = arg; + return 1; +} + +mixed GetVehicleInterior(){ + mixed ret; + if(stringp(VehicleInterior)) return VehicleInterior; + else if(functionp(VehicleInterior)){ + ret = evaluate(VehicleInterior); + if(!stringp(ret)) return 0; + return ret; + } + return 0; +} + +varargs int CanFly(mixed who, mixed where){ + if(where && !(environment(this_object())->GetExit(where)) && + !(environment(this_object())->GetEnter(where))) return 0; + + if(this_object()->GetPosition() == POSITION_FLYING) return 1; + return 0; +} + +int eventMove(mixed dest){ + int ret; + object env = environment(); + string location; + + if(!env) location = ROOM_START; + else if(clonep(env)) location = file_name(env); + else location = base_name(env); + + if(location) this_object()->SetProperty("LastLocation", location); + ret = ::eventMove(dest); + AddStaminaPoints(GetMaxStaminaPoints()); + return ret; +} diff --git a/lib/lib/virtual/virt_land.c b/lib/lib/virtual/virt_land.c new file mode 100644 index 0000000..9ecd32f --- /dev/null +++ b/lib/lib/virtual/virt_land.c @@ -0,0 +1,206 @@ +/* /lib/virtual/virt_land.c + * From Dead Souls Mud Library + * A virtual object for rooms + * Created by Dvarsk 980310 + * Version: @(#) virt_land.c 1.4@(#) + * Last modified: 98/09/12 + */ + +#include <lib.h> +#include <medium.h> + +inherit LIB_ROOM; +inherit LIB_VIRTUAL; + +private int CoordX = 0; +private int CoordY = 0; +private int CoordZ = 0; +private object Map_Master; +private string Virt_Room = ""; +private string AreaType = ""; +private string Reset_Message; +private mapping Surrounding_Areas=([]); + +void SetVirtualExits(int x, int y, int z); + +/******************* virt_land.c required overrides ***********/ + +varargs void SetLongAndItems(int x, int y, int z){ + SetVirtualExits(x, y, z); +} + +/******************* virt_land.c required settings ************/ + +int SetMasterMap(mixed map_name){ + if(!stringp(map_name) && !objectp(map_name)){ + error("Bad argument 1 to SetMasterMap()\n\t" + "Expected: string or object, Got: " + typeof(map_name) + + "."); + return 0; + } + if(stringp(map_name)){ + if( !(Map_Master = load_object(map_name)) ){ + string str; + + if( str = catch(call_other(map_name, "???")) ){ + if( creatorp() ) message("error", str, + previous_object()); + return 0; + } + Map_Master = load_object(map_name); + } + } + + else Map_Master=map_name; + return 1; + +} + +int SetVirtFile( string file ){ + string str; + if( str = catch(call_other(file, "???")) ){ + if( creatorp() ) message("error", str, previous_object()); + return 0; + } + Virt_Room=file; + SetMasterMap( file ); + return 1; +} + +/******************* virt_land.c optional settings ************/ + +string SetResetMessage(mixed str){ Reset_Message = str;} + +/******************* virt_land.c attributes *******************/ + +void SetCoordinates(int x, int y, int z){ + CoordX = x; + CoordY = y; + CoordZ = z; +} + +mapping GetDirectionMap(){ + return (["north":({-1,0,0}),"south":({1,0,0}), + "east":({0,1,0}),"west":({0,-1,0}), + "northeast":({-1,1,0}),"northwest":({-1,-1,0}), + "southeast":({1,1,0}),"southwest":({1,-1,0}), + "up":({0,0,-1}),"down":({0,0,1}) ]); +} + +string GetReverseDirection(string dir){ + return (["north":"south","south":"north", + "east":"west","west":"east", + "northeast":"southwest","northwest":"southeast", + "southeast":"northwest","southwest":"northeast", + "up":"down","down":"up" ])[dir]; +} + +varargs mixed GetMapType(int x, int y, int z){ + if(!objectp(Map_Master) || nullp(x) ||nullp(y) || nullp(z) ) + return 0; + return Map_Master->GetAreaMap(x,y,z); +} + +mapping SetSurroundAreas(int x, int y, int z){ + mapping surrounds = ([]); + foreach(string dir, int * offset in GetDirectionMap()) + surrounds[dir] = GetMapType((x + offset[1]), + (y + offset[0]),(z + offset[2])); + return Surrounding_Areas=surrounds; +} + +void ResetSurroundExits(){ + foreach(string dir, string atype in Surrounding_Areas){ + if(atype != "0" && atype != "@"){ + (Virt_Room + "/" + + ( CoordX + GetDirectionMap()[dir][1]) + "," + + ( CoordY + GetDirectionMap()[dir][0]) + "," + + ( CoordZ + GetDirectionMap()[dir][2]))->ResetLocation(); + } + } +} + + +void SetVirtualExits(int x, int y, int z){ + if(sizeof(Virt_Room)){ + string * obexits=({}); + + SetSurroundAreas(x,y,z); + + foreach(string dir, string atype in Surrounding_Areas){ + if(atype != "0" && atype != "@"){ + AddExit(dir,Virt_Room+"/" + + ( x + GetDirectionMap()[dir][1])+"," + + ( y + GetDirectionMap()[dir][0])+ "," + + ( z + GetDirectionMap()[dir][2])); + obexits += ({dir[0..0]+dir[5..5]}); + } + else if( atype == "@"){ + mixed exit = + Map_Master->GetExternalRoom( + sprintf("%d,%d,%d", + ( x + GetDirectionMap()[dir][1]), + ( y + GetDirectionMap()[dir][0]), + ( z + GetDirectionMap()[dir][2])), + sprintf("%d,%d,%d",x,y,z) + ); + if(exit){ + AddExit(dir, exit); + obexits += ({dir[0..0]+dir[5..5]}); + } + } + } + + SetObviousExits(implode(obexits,", ")); + AreaType = GetMapType(x,y,z); + } +} + +string GetAreaType(){ return AreaType;} + +varargs mixed GetCoordinates(int level){ + if(nullp(level)) return ({ CoordX, CoordY, CoordZ }); + else switch(level){ + case 0: return CoordX; + case 1: return CoordY; + case 2: return CoordZ; + } + return 0; +} + +object GetMasterMap(){ return Map_Master;} + +varargs string array GetNonExits(string array extra){ + if(nullp(extra)) extra=({}); + return (keys(GetDirectionMap())-GetExits())- extra; +} + +mapping GetSurroundAreas(){ return Surrounding_Areas; } + +void PreAddEnter(mixed dir, string file){ + if((!stringp(dir)&&!arrayp(dir)) || !stringp(file)) return; + AddEnter(dir,file); +} + +/******************* virt_land.c events ***********************/ + +void ResetLocation(){ + object *objects = all_inventory(this_object()); + + reset(query_reset_number()); + SetVirtualExits(CoordX,CoordY,CoordZ); + SetLongAndItems(CoordX,CoordY,CoordZ); + if(Reset_Message){ + eventPrint(Reset_Message); + if(sizeof(objects=filter(objects,(:playerp:)))) + objects->eventDescribeEnvironment(0); + } +} + +/******************* virt_land.c driver applies ***************/ + +varargs static void create(int x, int y,int z){ + SetNoReplace(1); + room::create(); + SetCoordinates(x, y, z); +} diff --git a/lib/lib/virtual/virt_map.c b/lib/lib/virtual/virt_map.c new file mode 100644 index 0000000..580fef0 --- /dev/null +++ b/lib/lib/virtual/virt_map.c @@ -0,0 +1,171 @@ +/* /lib/virtual/virt_map.c + * From DeadSouls Object Library + * Provides a map for map based virtual rooms + * Created by Dvarsk 980310 + * Version: @(#) virt_map.c 1.3@(#) + * Last modified: 98/08/25 + */ + +#include <lib.h> + +inherit LIB_DAEMON; + +private mapping Location=([]); +private mixed AreaMap; +private string Virt_Room= ""; + +/******************* virt_map.c required overrides ************/ + +varargs string array BaseMap(){ //override with actual map + return + ({ + // 0 + // 012 + ({"000",//0 + "010",//1 + "000",//2 + })}); +} + +/******************* virt_map.c attributes ********************/ + +int *GetLocations(string str){return Location[str]; } + +varargs mixed GetAreaMap(int x, int y, int z){ + if(nullp(x) || nullp(y) || nullp(z)) return copy(AreaMap); + if( x<0 + || y<0 + || z<0 + || z>sizeof(AreaMap) + || y>sizeof(AreaMap[0]) + || x>sizeof(AreaMap[0][0])) + return "0"; + return copy(AreaMap[z][y][x..x]); + +} + +varargs mixed SetAreaMap(int y,int x ,int z, string str){ + if(nullp(x)||nullp(y)||nullp(z)){ + string x_line=""; + string * y_line=({}); + AreaMap=BaseMap(); + z=sizeof(AreaMap); + y=sizeof(AreaMap[0]); + x=sizeof(AreaMap[0][0]); + while (x --) x_line += "0"; + while (y --) y_line += ({x_line}); + return AreaMap = ({y_line}) +AreaMap + ({y_line}); + } + else return AreaMap[z][y][x..x]=str; +} + +int SetVirtFile( string file){ + string str; + if( str = catch(call_other(file, "???")) ){ + if( creatorp() ) message("error", str, previous_object()); + return 0; + } + Virt_Room=file+"/"; + SetAreaMap(); + return 1; +} + +/******************* virt_map.c events ************************/ + +int * RecurseLocations(){ + mixed map=GetAreaMap(); + int *locat; + int z=random(sizeof(map)-2)+1; + int y=random(sizeof(map[z])); + int x=random(sizeof(map[z][y])); + + if(map[z][y][x..x]!="1") + return RecurseLocations(); // Is it within the general land? + foreach(string tmp in keys(Location)){ //Is something else here? + locat=Location[tmp]; + if(locat[0]==x && locat[1]==y && locat[2]==z) + return RecurseLocations(); + } + return ({x,y,z}); +} + +varargs void InitializeLocations(string tmp){ + if(!nullp(tmp)){ + if(!Location[tmp][0] && !Location[tmp][1] + && !Location[tmp][2]) + Location[tmp]=RecurseLocations(); + SetAreaMap(Location[tmp][1], Location[tmp][0], + Location[tmp][2], tmp); + (Virt_Room+(Location[tmp][0] ) + "," + + (Location[tmp][1]) + "," + + (Location[tmp][2]))->ResetLocation(); + } + else foreach(tmp in keys(Location)){ + Location[tmp]=RecurseLocations(); + SetAreaMap(Location[tmp][1], Location[tmp][0], + Location[tmp][2], tmp); + (Virt_Room+(Location[tmp][0] ) + "," + (Location[tmp][1]) + + "," +(Location[tmp][2]))->ResetLocation(); + } + +} + +// call this if all the locations randomly move around +void SwitchLocations(){ + int * old_location; + mixed areas=BaseMap(); + + foreach(string tmp in keys(Location)){ + if(Location[tmp][3]) continue; + old_location=copy(Location[tmp]); + Location[tmp]=({0,0,0}); + SetAreaMap(old_location[1], old_location[0], + old_location[2], areas[(old_location[2]-1)] + [old_location[1]][old_location[0]..old_location[0]]); + Location[tmp]=RecurseLocations(); + (Virt_Room + (old_location[0]) + "," + + (old_location[1]) + "," + + (old_location[2]))->ResetLocation(); + SetAreaMap(Location[tmp][1], Location[tmp][0], + old_location[2], tmp); + (Virt_Room + (Location[tmp][0] ) + "," + + (Location[tmp][1]) + "," + + (old_location[2]))->ResetLocation(); + + } +} + +/******************* virt_map.c driver applies ****************/ + +varargs static void create(string virt_file){ + daemon::create(); + SetNoClean(1); + if(!nullp(virt_file)) SetVirtFile(virt_file); + else SetVirtFile(base_name(this_object())); +} + +/******************* virt_map.c optional settings *************/ + +int AddLocation(string str, int array where){ + if(!nullp(Location[str])) return 0; + Location[str]=where; + InitializeLocations(str); + return 1; +} + +int RemoveLocation(string str){ + int * location=Location[str]; + mixed areas=BaseMap(); + if(nullp(location)) return 0; + SetAreaMap(location[1],location[0],location[2], + areas[(location[2]-1)][location[1]] + [location[0]..location[0]]); + (Virt_Room + (location[0] ) + "," + + (location[1]) + "," + + (location[2]))->ResetLocation(); + map_delete(Location,str); + return 1; +} + + + diff --git a/lib/lib/virtual/virt_sky.c b/lib/lib/virtual/virt_sky.c new file mode 100644 index 0000000..c583548 --- /dev/null +++ b/lib/lib/virtual/virt_sky.c @@ -0,0 +1,104 @@ +/* /lib/virtual/virt_sky.c + * From DeadSouls Object Library + * A virtual object for air rooms + * Created by Dvarsk 980310 + * Version: @(#) virt_sky.c 1.1@(#) + * Last modified: 98/08/25 + */ + +#include <lib.h> +#include <virtual.h> +#include <medium.h> +#include <message_class.h> +#include <position.h> + +inherit LIB_VIRT_LAND; + +private mixed PreventLand; + +varargs static void create(int x, int y,int z){ + virt_land::create( x, y, z); + SetMedium(MEDIUM_AIR); +} + +varargs static void Setup(int x, int y,int z){ + virt_land::create( x, y, z); + SetMedium(MEDIUM_AIR); +} + +string GetGround(){ + return GetExit("down"); +} + +string SetGround(string str){ + AddExit("down", str); + return str; +} + +mixed GetPreventLand(){ + return PreventLand; +} + +mixed SetPreventLand(mixed val){ + return (PreventLand = val); +} + +mixed CanFly(object who, string dir){ + if( !dir || dir == "" ){ + return "Fly where?"; + } + else if( dir == "down" ){ + if( stringp(PreventLand) ){ + return PreventLand; + } + else if( functionp(PreventLand) ){ + mixed tmp = evaluate(PreventLand, who); + + if( tmp != 1 ){ + return tmp; + } + } + if( !GetGround() ){ + return "There is nothing below you but open sea."; + } + } + if( who->GetPosition() != POSITION_FLYING ){ + return "You are not flying!"; + } + return virt_land::CanGo(who, dir); +} + +//mixed CanGo(object who, string dir){ +// return CanFly(who, dir); +//} + +mixed eventFly(object who, string dir){ + mapping exit = GetExitData(dir); + + if( GetDoor(dir) && GetDoor(dir)->GetClosed() ){ + who->eventPrint("You fly into " + GetDoor(dir)->GetShort(dir) + "."); + eventPrint(who->GetName() + " flies into " + + GetDoor(dir)->GetShort(dir) + ".", who); + return 1; + } + if( exit["pre"] && !evaluate(exit["pre"], dir) ){ + return 1; + } + who->eventMoveLiving(exit["room"], dir, "$N flies in."); + if( dir =="down" ){ + } + if( exit["post"] ){ + evaluate(exit["post"], dir); + } + return 1; +} + +//mixed eventGo(object who, string dir){ +// if(GetMedium()==MEDIUM_AIR) return eventFly(who, dir); +// return ::eventGo(who, dir); +//} + +mixed eventReceiveObject(object ob){ + + return virt_land::eventReceiveObject(ob); +} diff --git a/lib/lib/virtual/virt_std.c b/lib/lib/virtual/virt_std.c new file mode 100644 index 0000000..33ab317 --- /dev/null +++ b/lib/lib/virtual/virt_std.c @@ -0,0 +1,61 @@ +/* /lib/std/virtual.c + * From DeadSouls Object Library + * A virtual object server + * Created by Descartes of Borg 970523 + * Version: @(#) virt_std.c 1.3@(#) + * Last modified: 98/09/12 + */ + +private string recursed = ""; + +/****************************** events ************************************/ +mixed CreateVirtualObject(string fname){ + object daemon; + string tmp, vname; + int x, y, z, s; + int i; + + if(fname == recursed){ + recursed = ""; + error("Recursion error in CreateVirtualObject()"); + return 0; + } + + i = strsrch(fname, "/", -1); + if( i == -1 || i == 0 || i == strlen(fname)-1 ){ + return -1; + } + tmp = fname[(i+1)..]; + if( sscanf(tmp, "%d,%d,%d,%d", x, y, z, s) != 4 ){ + if( sscanf(tmp, "%d,%d,%d", x, y, z) != 3 ){ + if( sscanf(tmp, "%d,%d", x, y) != 2 ){ + vname = tmp; + } + else { + vname = 0; + z = 0; + } + } + s = 0; + } + else { + vname = 0; + } + tmp = fname[0..(i-1)]; + recursed = tmp; + daemon = load_object(tmp); + recursed = ""; + if(!daemon) return 0; + if( vname ){ + return daemon->CreateNamedObject(vname); + } + else { + if(!s) return daemon->CreateGridObject(x, y, z); + else return daemon->CreateGridObject(x, y, z, s); + } +} + +/************************** driver applies ********************************/ +object compile_object(string fname){ + return CreateVirtualObject(fname); +} diff --git a/lib/lib/virtual/virt_subsurface.c b/lib/lib/virtual/virt_subsurface.c new file mode 100644 index 0000000..cbfc8fd --- /dev/null +++ b/lib/lib/virtual/virt_subsurface.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include <virtual.h> +#include <medium.h> +#include <message_class.h> +#include <position.h> + +inherit LIB_VIRT_LAND; + +varargs static void create(int x, int y,int z){ + virt_land::create( x, y, z); + SetMedium(MEDIUM_WATER); +} + +varargs static void Setup(int x, int y,int z){ + virt_land::create( x, y, z); + SetMedium(MEDIUM_WATER); +} + +string GetGround(){ + return GetExit("down"); +} + +string SetGround(string str){ + AddExit("down", str); + return str; +} + +mixed eventReceiveObject(object ob){ + + return virt_land::eventReceiveObject(ob); +} diff --git a/lib/lib/virtual/virtual.c b/lib/lib/virtual/virtual.c new file mode 100644 index 0000000..852f019 --- /dev/null +++ b/lib/lib/virtual/virtual.c @@ -0,0 +1,31 @@ +#include <virtual.h> +int exempt_virtual; + +int GetVirtual(){ + return 1; +} + +int GetVirtualSky(){ + if(inherits(LIB_VIRT_SKY, this_object())) return 1; + return 0; +} + +int GetVirtualSea(){ + if(inherits(LIB_VIRT_SURFACE, this_object())) return 1; + if(inherits(LIB_VIRT_SUBSURFACE, this_object())) return 1; + return 0; +} + +/* This is to exempt the room from the normal rules + * of virtuals, including automatic destruction when + * the last item in its inventory leaves. + */ +int SetExemptVirtual(int i){ + if(i) exempt_virtual = 1; + else exempt_virtual = 0; + return exempt_virtual; +} + +int GetExemptVirtual(){ + return exempt_virtual; +} diff --git a/lib/log/adm/foo.txt b/lib/log/adm/foo.txt new file mode 100644 index 0000000..27afd21 --- /dev/null +++ b/lib/log/adm/foo.txt @@ -0,0 +1 @@ +This file intentionally left blank. diff --git a/lib/log/archive/catch-2020.09.03-05.18,21 b/lib/log/archive/catch-2020.09.03-05.18,21 new file mode 100644 index 0000000..e42b995 --- /dev/null +++ b/lib/log/archive/catch-2020.09.03-05.18,21 @@ -0,0 +1,2315 @@ + +--- DeadSoulsWin +2020.09.01-19.18,17 +*The file daemon has been disabled for your mud because it is running on windows. Intensive file operations in windows are not yet supported on Dead Souls. +Object: /secure/daemon/file at line 23 + +'<fake>' at /secure/daemon/events (/<driver>) at line 0 +'eventPollEvents' at /secure/daemon/events at line 144 +'CATCH' at /secure/daemon/events at line 144 +'<fake>' at /secure/daemon/file (/<driver>) at line 0 +'ReadDir' at /secure/daemon/file at line 49 +'validate' at /secure/daemon/file at line 23 + +--- Zebu +2020.09.02-21.54,36 +*Bad argument 2 to foreach +Expected: array Got: 0. +Object: /realms/babylon/tmp/gruntholakclflka1599108876 (/lib/race.c) at line 275 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_modify_obj_str' at /verbs/builders/modify at line 83 +'eventModify' at /secure/obj/staff#92 (/secure/modules/create.c) at line 632 +'reload' at /secure/sefun/sefun at /secure/sefun/reload.c:34 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'create' at /realms/babylon/tmp/gruntholakclflka1599108876 at line 14 +'SetRace' at /realms/babylon/tmp/gruntholakclflka1599108876 (/lib/npc.c) at line 419 +'SetRace' at /realms/babylon/tmp/gruntholakclflka1599108876 (/lib/race.c) at line 200 +'NewBody' at /realms/babylon/tmp/gruntholakclflka1599108876 (/lib/race.c) at line 275 + +--- Zebu +2020.09.02-21.54,36 +*Bad argument 2 to foreach +Expected: array Got: 0. +Object: /realms/babylon/tmp/gruntholakclflka1599108876 (/lib/race.c) at line 275 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_modify_obj_str' at /verbs/builders/modify at line 83 +'eventModify' at /secure/obj/staff#92 (/secure/modules/create.c) at line 632 +'reload' at /secure/sefun/sefun at /secure/sefun/reload.c:87 +'unguarded' at /secure/sefun/sefun at /secure/sefun/security.c:104 +'apply_unguarded' at /secure/daemon/master at line 606 +'CATCH' at /secure/daemon/master at line 606 +'<fake>' at /secure/sefun/sefun (/<driver>) at line 0 +'(: <code>() :)' at /secure/sefun/sefun at /secure/sefun/reload.c:87 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 +'create' at /realms/babylon/tmp/gruntholakclflka1599108876 at line 14 +'SetRace' at /realms/babylon/tmp/gruntholakclflka1599108876 (/lib/npc.c) at line 419 +'SetRace' at /realms/babylon/tmp/gruntholakclflka1599108876 (/lib/race.c) at line 200 +'NewBody' at /realms/babylon/tmp/gruntholakclflka1599108876 (/lib/race.c) at line 275 + +--- Zebu +2020.09.02-21.54,36 +*Bad argument 2 to foreach +Expected: array Got: 0. +Object: /realms/babylon/area/npc/grunthol (/lib/race.c) at line 275 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_modify_obj_str' at /verbs/builders/modify at line 83 +'eventModify' at /secure/obj/staff#92 (/secure/modules/create.c) at line 641 +'reload' at /secure/sefun/sefun at /secure/sefun/reload.c:87 +'unguarded' at /secure/sefun/sefun at /secure/sefun/security.c:104 +'apply_unguarded' at /secure/daemon/master at line 606 +'CATCH' at /secure/daemon/master at line 606 +'<fake>' at /secure/sefun/sefun (/<driver>) at line 0 +'(: <code>() :)' at /secure/sefun/sefun at /secure/sefun/reload.c:87 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 +'create' at /realms/babylon/area/npc/grunthol at line 14 +'SetRace' at /realms/babylon/area/npc/grunthol (/lib/npc.c) at line 419 +'SetRace' at /realms/babylon/area/npc/grunthol (/lib/race.c) at line 200 +'NewBody' at /realms/babylon/area/npc/grunthol (/lib/race.c) at line 275 + +--- Zebu +2020.09.02-21.54,36 +*Bad argument 2 to foreach +Expected: array Got: 0. +Object: /realms/babylon/area/npc/grunthol#428 (/lib/race.c) at line 275 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_modify_obj_str' at /verbs/builders/modify at line 83 +'eventModify' at /secure/obj/staff#92 (/secure/modules/create.c) at line 641 +'reload' at /secure/sefun/sefun at /secure/sefun/reload.c:95 +'unguarded' at /secure/sefun/sefun at /secure/sefun/security.c:104 +'apply_unguarded' at /secure/daemon/master at line 606 +'CATCH' at /secure/daemon/master at line 606 +'<fake>' at /secure/sefun/sefun (/<driver>) at line 0 +'(: <code>() :)' at /secure/sefun/sefun at /secure/sefun/reload.c:95 +'create' at /realms/babylon/area/npc/grunthol#428 at line 14 +'SetRace' at /realms/babylon/area/npc/grunthol#428 (/lib/npc.c) at line 419 +'SetRace' at /realms/babylon/area/npc/grunthol#428 (/lib/race.c) at line 200 +'NewBody' at /realms/babylon/area/npc/grunthol#428 (/lib/race.c) at line 275 + +--- Zebu +2020.09.02-21.58,34 +*Bad argument 2 to foreach +Expected: array Got: 0. +Object: /realms/babylon/tmp/gruntholfabiidol1599109114 (/lib/race.c) at line 275 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_modify_obj_str' at /verbs/builders/modify at line 83 +'eventModify' at /secure/obj/staff#92 (/secure/modules/create.c) at line 632 +'reload' at /secure/sefun/sefun at /secure/sefun/reload.c:34 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'create' at /realms/babylon/tmp/gruntholfabiidol1599109114 at line 14 +'SetRace' at /realms/babylon/tmp/gruntholfabiidol1599109114 (/lib/npc.c) at line 419 +'SetRace' at /realms/babylon/tmp/gruntholfabiidol1599109114 (/lib/race.c) at line 200 +'NewBody' at /realms/babylon/tmp/gruntholfabiidol1599109114 (/lib/race.c) at line 275 + +--- Zebu +2020.09.02-21.58,34 +*Bad argument 2 to foreach +Expected: array Got: 0. +Object: /realms/babylon/tmp/gruntholfabiidol1599109114 (/lib/race.c) at line 275 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_modify_obj_str' at /verbs/builders/modify at line 83 +'eventModify' at /secure/obj/staff#92 (/secure/modules/create.c) at line 632 +'reload' at /secure/sefun/sefun at /secure/sefun/reload.c:87 +'unguarded' at /secure/sefun/sefun at /secure/sefun/security.c:104 +'apply_unguarded' at /secure/daemon/master at line 606 +'CATCH' at /secure/daemon/master at line 606 +'<fake>' at /secure/sefun/sefun (/<driver>) at line 0 +'(: <code>() :)' at /secure/sefun/sefun at /secure/sefun/reload.c:87 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 +'create' at /realms/babylon/tmp/gruntholfabiidol1599109114 at line 14 +'SetRace' at /realms/babylon/tmp/gruntholfabiidol1599109114 (/lib/npc.c) at line 419 +'SetRace' at /realms/babylon/tmp/gruntholfabiidol1599109114 (/lib/race.c) at line 200 +'NewBody' at /realms/babylon/tmp/gruntholfabiidol1599109114 (/lib/race.c) at line 275 + +--- Zebu +2020.09.02-21.58,34 +*Bad argument 2 to foreach +Expected: array Got: 0. +Object: /realms/babylon/area/npc/grunthol (/lib/race.c) at line 275 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_modify_obj_str' at /verbs/builders/modify at line 83 +'eventModify' at /secure/obj/staff#92 (/secure/modules/create.c) at line 641 +'reload' at /secure/sefun/sefun at /secure/sefun/reload.c:87 +'unguarded' at /secure/sefun/sefun at /secure/sefun/security.c:104 +'apply_unguarded' at /secure/daemon/master at line 606 +'CATCH' at /secure/daemon/master at line 606 +'<fake>' at /secure/sefun/sefun (/<driver>) at line 0 +'(: <code>() :)' at /secure/sefun/sefun at /secure/sefun/reload.c:87 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 +'create' at /realms/babylon/area/npc/grunthol at line 14 +'SetRace' at /realms/babylon/area/npc/grunthol (/lib/npc.c) at line 419 +'SetRace' at /realms/babylon/area/npc/grunthol (/lib/race.c) at line 200 +'NewBody' at /realms/babylon/area/npc/grunthol (/lib/race.c) at line 275 + +--- Zebu +2020.09.02-21.58,34 +*Bad argument 2 to foreach +Expected: array Got: 0. +Object: /realms/babylon/area/npc/grunthol#613 (/lib/race.c) at line 275 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_modify_obj_str' at /verbs/builders/modify at line 83 +'eventModify' at /secure/obj/staff#92 (/secure/modules/create.c) at line 641 +'reload' at /secure/sefun/sefun at /secure/sefun/reload.c:95 +'unguarded' at /secure/sefun/sefun at /secure/sefun/security.c:104 +'apply_unguarded' at /secure/daemon/master at line 606 +'CATCH' at /secure/daemon/master at line 606 +'<fake>' at /secure/sefun/sefun (/<driver>) at line 0 +'(: <code>() :)' at /secure/sefun/sefun at /secure/sefun/reload.c:95 +'create' at /realms/babylon/area/npc/grunthol#613 at line 14 +'SetRace' at /realms/babylon/area/npc/grunthol#613 (/lib/npc.c) at line 419 +'SetRace' at /realms/babylon/area/npc/grunthol#613 (/lib/race.c) at line 200 +'NewBody' at /realms/babylon/area/npc/grunthol#613 (/lib/race.c) at line 275 + +--- Zebu +2020.09.03-01.18,21 +*The file daemon has been disabled for your mud because it is running on windows. Intensive file operations in windows are not yet supported on Dead Souls. +Object: /secure/daemon/file at line 23 + +'<fake>' at /secure/daemon/events (/<driver>) at line 0 +'eventPollEvents' at /secure/daemon/events at line 144 +'CATCH' at /secure/daemon/events at line 144 +'<fake>' at /secure/daemon/file (/<driver>) at line 0 +'ReadDir' at /secure/daemon/file at line 49 +'validate' at /secure/daemon/file at line 23 + +--- Zebu +2020.09.03-01.23,28 +*call_other() couldn't find object +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_enter_obj' at /verbs/rooms/enter at line 39 +'eventEnter' at /lib/std/dummy#153 (/lib/enter.c) at line 115 +'eventMoveLiving' at /secure/save/creators/b/babylon (/lib/living.c) at line 725 +'CheckMove' at /daemon/guard at line 95 +'CATCH' at /daemon/guard at line 95 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-01.48,19 +*Error in loading object '/domains/oogtopia/room/start' +Object: /secure/cmds/creators/update at line 170 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 85 +'CATCH' at /secure/cmds/creators/update at line 85 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 + +--- Zebu +2020.09.03-01.48,19 +*Error in loading object '/domains/oogtopia/room/start' +Object: /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 92 +'ReturnAndRelease' at /secure/cmds/creators/update at line 37 +'eventMove' at /secure/save/creators/b/babylon (/lib/creator.c) at line 266 +'eventMove' at /secure/save/creators/b/babylon (/lib/player.c) at line 287 +'eventMove' at /secure/save/creators/b/babylon (/lib/interactive.c) at line 255 +'eventMove' at /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 +'CATCH' at /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-01.52,26 +*call_other() couldn't find object +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_go_str' at /verbs/rooms/go at line 45 +'eventGo' at /domains/oogtopia/room/start (/lib/exits.c) at line 107 +'eventMoveLiving' at /secure/save/creators/b/babylon (/lib/living.c) at line 725 +'CheckMove' at /daemon/guard at line 95 +'CATCH' at /daemon/guard at line 95 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-02.53,03 +*Value being indexed is zero. +Object: /realms/babylon/area/doors/airlock (/lib/door.c) at line 241 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/builders/create at line 36 +'gmake' at /secure/obj/staff#92 (/secure/modules/generic.c) at line 122 +'eventCreateDoor' at /secure/obj/staff#92 (/secure/modules/door.c) at line 263 +'reload' at /secure/sefun/sefun at /secure/sefun/reload.c:68 +'unguarded' at /secure/sefun/sefun at /secure/sefun/security.c:104 +'apply_unguarded' at /secure/daemon/master at line 606 +'CATCH' at /secure/daemon/master at line 606 +'<fake>' at /secure/sefun/sefun (/<driver>) at line 0 +'(: <code>() :)' at /secure/sefun/sefun at /secure/sefun/reload.c:68 +'CATCH' at /secure/sefun/sefun at /secure/sefun/reload.c:68 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 +'create' at /domains/oogtopia/room/field at line 25 +'SetDoor' at /domains/oogtopia/room/field (/lib/exits.c) at line 150 +'eventRegisterSide' at /realms/babylon/area/doors/airlock (/lib/door.c) at line 241 + +--- Zebu +2020.09.03-02.56,26 +*Value being indexed is zero. +Object: /realms/babylon/area/doors/airlock (/lib/door.c) at line 241 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_reload_obj' at /verbs/builders/reload at line 92 +'reload' at /secure/sefun/sefun at /secure/sefun/reload.c:68 +'unguarded' at /secure/sefun/sefun at /secure/sefun/security.c:104 +'apply_unguarded' at /secure/daemon/master at line 606 +'CATCH' at /secure/daemon/master at line 606 +'<fake>' at /secure/sefun/sefun (/<driver>) at line 0 +'(: <code>() :)' at /secure/sefun/sefun at /secure/sefun/reload.c:68 +'CATCH' at /secure/sefun/sefun at /secure/sefun/reload.c:68 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 +'create' at /domains/oogtopia/room/field at line 25 +'SetDoor' at /domains/oogtopia/room/field (/lib/exits.c) at line 150 +'eventRegisterSide' at /realms/babylon/area/doors/airlock (/lib/door.c) at line 241 + +--- Zebu +2020.09.03-04.12,13 +*Error in loading object '/domains/oogtopia/room/start' +Object: /secure/cmds/creators/update at line 170 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/admins/gridconfig at line 81 +'ResetGrid' at /secure/cmds/admins/gridconfig at line 52 +'CATCH' at /secure/cmds/admins/gridconfig at line 52 +'reload' at /secure/sefun/sefun at /secure/sefun/reload.c:68 +'unguarded' at /secure/sefun/sefun at /secure/sefun/security.c:104 +'apply_unguarded' at /secure/daemon/master at line 606 +'CATCH' at /secure/daemon/master at line 606 +'<fake>' at /secure/sefun/sefun (/<driver>) at line 0 +'(: <code>() :)' at /secure/sefun/sefun at /secure/sefun/reload.c:68 +'CATCH' at /secure/sefun/sefun at /secure/sefun/reload.c:68 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 + +--- Zebu +2020.09.03-04.12,13 +*Error in loading object '/domains/oogtopia/room/start' +Object: /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/admins/gridconfig at line 81 +'ResetGrid' at /secure/cmds/admins/gridconfig at line 52 +'CATCH' at /secure/cmds/admins/gridconfig at line 52 +'reload' at /secure/sefun/sefun at /secure/sefun/reload.c:75 +'eventMove' at /secure/save/creators/b/babylon (/lib/creator.c) at line 266 +'eventMove' at /secure/save/creators/b/babylon (/lib/player.c) at line 287 +'eventMove' at /secure/save/creators/b/babylon (/lib/interactive.c) at line 255 +'eventMove' at /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 +'CATCH' at /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.12,13 +*Error in loading object '/domains/oogtopia/room/start' +Object: /domains/default/npc/drone3#1125 (/lib/props/move.c) at line 88 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/admins/gridconfig at line 81 +'ResetGrid' at /secure/cmds/admins/gridconfig at line 59 +'CATCH' at /secure/cmds/admins/gridconfig at line 59 +'eventMove' at /domains/default/npc/drone3#1125 at line 58 +'eventMove' at /domains/default/npc/drone3#1125 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1125 (/lib/npc.c) at line 213 +'eventMove' at /domains/default/npc/drone3#1125 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1125 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.12,23 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1198 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#1124 at line 111 +'eventSpawn' at /domains/default/npc/drone3#1124 at line 103 +'CATCH' at /domains/default/npc/drone3#1124 at line 103 +'eventMove' at /domains/default/npc/drone3#1198 at line 58 +'eventMove' at /domains/default/npc/drone3#1198 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1198 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1198 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1198 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.12,23 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1213 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#1138 at line 111 +'eventSpawn' at /domains/default/npc/drone3#1138 at line 103 +'CATCH' at /domains/default/npc/drone3#1138 at line 103 +'eventMove' at /domains/default/npc/drone3#1213 at line 58 +'eventMove' at /domains/default/npc/drone3#1213 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1213 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1213 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1213 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.12,23 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1214 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#1139 at line 111 +'eventSpawn' at /domains/default/npc/drone3#1139 at line 103 +'CATCH' at /domains/default/npc/drone3#1139 at line 103 +'eventMove' at /domains/default/npc/drone3#1214 at line 58 +'eventMove' at /domains/default/npc/drone3#1214 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1214 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1214 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1214 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.12,23 +*Error in loading object '/domains/oogtopia/room/start' +Object: /domains/default/npc/drone3#1216 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#1144 at line 111 +'eventSpawn' at /domains/default/npc/drone3#1144 at line 103 +'CATCH' at /domains/default/npc/drone3#1144 at line 103 +'eventMove' at /domains/default/npc/drone3#1216 at line 58 +'eventMove' at /domains/default/npc/drone3#1216 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1216 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1216 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1216 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.12,23 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1218 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#1144 at line 111 +'eventSpawn' at /domains/default/npc/drone3#1144 at line 103 +'CATCH' at /domains/default/npc/drone3#1144 at line 103 +'eventMove' at /domains/default/npc/drone3#1218 at line 58 +'eventMove' at /domains/default/npc/drone3#1218 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1218 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1218 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1218 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.12,23 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1219 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#1145 at line 111 +'eventSpawn' at /domains/default/npc/drone3#1145 at line 103 +'CATCH' at /domains/default/npc/drone3#1145 at line 103 +'eventMove' at /domains/default/npc/drone3#1219 at line 58 +'eventMove' at /domains/default/npc/drone3#1219 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1219 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1219 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1219 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.12,23 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1249 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#1154 at line 111 +'eventSpawn' at /domains/default/npc/drone3#1154 at line 103 +'CATCH' at /domains/default/npc/drone3#1154 at line 103 +'eventMove' at /domains/default/npc/drone3#1249 at line 58 +'eventMove' at /domains/default/npc/drone3#1249 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1249 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1249 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1249 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.12,23 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1259 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#1164 at line 111 +'eventSpawn' at /domains/default/npc/drone3#1164 at line 103 +'CATCH' at /domains/default/npc/drone3#1164 at line 103 +'eventMove' at /domains/default/npc/drone3#1259 at line 58 +'eventMove' at /domains/default/npc/drone3#1259 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1259 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1259 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1259 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.12,23 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1260 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#1165 at line 111 +'eventSpawn' at /domains/default/npc/drone3#1165 at line 103 +'CATCH' at /domains/default/npc/drone3#1165 at line 103 +'eventMove' at /domains/default/npc/drone3#1260 at line 58 +'eventMove' at /domains/default/npc/drone3#1260 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1260 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1260 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1260 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.12,23 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1265 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#1172 at line 111 +'eventSpawn' at /domains/default/npc/drone3#1172 at line 103 +'CATCH' at /domains/default/npc/drone3#1172 at line 103 +'eventMove' at /domains/default/npc/drone3#1265 at line 58 +'eventMove' at /domains/default/npc/drone3#1265 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1265 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1265 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1265 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.12,23 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1268 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#1176 at line 111 +'eventSpawn' at /domains/default/npc/drone3#1176 at line 103 +'CATCH' at /domains/default/npc/drone3#1176 at line 103 +'eventMove' at /domains/default/npc/drone3#1268 at line 58 +'eventMove' at /domains/default/npc/drone3#1268 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1268 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1268 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1268 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.12,44 +*Error in loading object '/domains/oogtopia/room/start' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_enter_obj' at /verbs/rooms/enter at line 39 +'eventEnter' at /lib/std/dummy#1141 (/lib/enter.c) at line 115 +'eventMoveLiving' at /secure/save/creators/b/babylon (/lib/living.c) at line 725 +'CheckMove' at /daemon/guard at line 95 +'CATCH' at /daemon/guard at line 95 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-04.13,23 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#2828 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#2659 at line 111 +'eventSpawn' at /domains/default/npc/drone3#2659 at line 103 +'CATCH' at /domains/default/npc/drone3#2659 at line 103 +'eventMove' at /domains/default/npc/drone3#2828 at line 58 +'eventMove' at /domains/default/npc/drone3#2828 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#2828 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#2828 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#2828 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.13,33 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#3105 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#2803 at line 111 +'eventSpawn' at /domains/default/npc/drone3#2803 at line 103 +'CATCH' at /domains/default/npc/drone3#2803 at line 103 +'eventMove' at /domains/default/npc/drone3#3105 at line 58 +'eventMove' at /domains/default/npc/drone3#3105 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#3105 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#3105 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#3105 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.13,53 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#3497 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#3235 at line 111 +'eventSpawn' at /domains/default/npc/drone3#3235 at line 103 +'CATCH' at /domains/default/npc/drone3#3235 at line 103 +'eventMove' at /domains/default/npc/drone3#3497 at line 58 +'eventMove' at /domains/default/npc/drone3#3497 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#3497 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#3497 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#3497 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.14,30 +*Error in loading object '/domains/oogtopia/room/start' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_enter_obj' at /verbs/rooms/enter at line 39 +'eventEnter' at /lib/std/dummy#1141 (/lib/enter.c) at line 115 +'eventMoveLiving' at /secure/save/creators/b/babylon (/lib/living.c) at line 725 +'CheckMove' at /daemon/guard at line 95 +'CATCH' at /daemon/guard at line 95 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-04.16,48 +*Error in loading object '/domains/oogtopia/room/start' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_enter_obj' at /verbs/rooms/enter at line 39 +'eventEnter' at /lib/std/dummy#1141 (/lib/enter.c) at line 115 +'eventMoveLiving' at /secure/save/creators/b/babylon (/lib/living.c) at line 725 +'CheckMove' at /daemon/guard at line 95 +'CATCH' at /daemon/guard at line 95 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-04.17,34 +*Error in loading object '/domains/oogtopia/room/start' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/admins/gridconfig at line 81 +'ResetGrid' at /secure/cmds/admins/gridconfig at line 52 +'CATCH' at /secure/cmds/admins/gridconfig at line 52 +'reload' at /secure/sefun/sefun at /secure/sefun/reload.c:34 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-04.17,34 +*Error in loading object '/domains/oogtopia/room/start' +Object: /domains/default/npc/drone3#4308 (/lib/props/move.c) at line 88 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/admins/gridconfig at line 81 +'ResetGrid' at /secure/cmds/admins/gridconfig at line 59 +'CATCH' at /secure/cmds/admins/gridconfig at line 59 +'eventMove' at /domains/default/npc/drone3#4308 at line 58 +'eventMove' at /domains/default/npc/drone3#4308 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#4308 (/lib/npc.c) at line 213 +'eventMove' at /domains/default/npc/drone3#4308 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#4308 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.17,44 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#4357 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#4307 at line 111 +'eventSpawn' at /domains/default/npc/drone3#4307 at line 103 +'CATCH' at /domains/default/npc/drone3#4307 at line 103 +'eventMove' at /domains/default/npc/drone3#4357 at line 58 +'eventMove' at /domains/default/npc/drone3#4357 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#4357 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#4357 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#4357 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.17,44 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#4360 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#4315 at line 111 +'eventSpawn' at /domains/default/npc/drone3#4315 at line 103 +'CATCH' at /domains/default/npc/drone3#4315 at line 103 +'eventMove' at /domains/default/npc/drone3#4360 at line 58 +'eventMove' at /domains/default/npc/drone3#4360 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#4360 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#4360 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#4360 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.17,44 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#4361 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#4316 at line 111 +'eventSpawn' at /domains/default/npc/drone3#4316 at line 103 +'CATCH' at /domains/default/npc/drone3#4316 at line 103 +'eventMove' at /domains/default/npc/drone3#4361 at line 58 +'eventMove' at /domains/default/npc/drone3#4361 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#4361 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#4361 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#4361 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.17,44 +*Error in loading object '/domains/oogtopia/room/start' +Object: /domains/default/npc/drone3#4363 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#4321 at line 111 +'eventSpawn' at /domains/default/npc/drone3#4321 at line 103 +'CATCH' at /domains/default/npc/drone3#4321 at line 103 +'eventMove' at /domains/default/npc/drone3#4363 at line 58 +'eventMove' at /domains/default/npc/drone3#4363 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#4363 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#4363 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#4363 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.17,44 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#4365 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#4321 at line 111 +'eventSpawn' at /domains/default/npc/drone3#4321 at line 103 +'CATCH' at /domains/default/npc/drone3#4321 at line 103 +'eventMove' at /domains/default/npc/drone3#4365 at line 58 +'eventMove' at /domains/default/npc/drone3#4365 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#4365 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#4365 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#4365 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.17,44 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#4366 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#4322 at line 111 +'eventSpawn' at /domains/default/npc/drone3#4322 at line 103 +'CATCH' at /domains/default/npc/drone3#4322 at line 103 +'eventMove' at /domains/default/npc/drone3#4366 at line 58 +'eventMove' at /domains/default/npc/drone3#4366 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#4366 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#4366 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#4366 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.17,44 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#4372 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#4328 at line 111 +'eventSpawn' at /domains/default/npc/drone3#4328 at line 103 +'CATCH' at /domains/default/npc/drone3#4328 at line 103 +'eventMove' at /domains/default/npc/drone3#4372 at line 58 +'eventMove' at /domains/default/npc/drone3#4372 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#4372 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#4372 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#4372 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.17,44 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#4375 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#4338 at line 111 +'eventSpawn' at /domains/default/npc/drone3#4338 at line 103 +'CATCH' at /domains/default/npc/drone3#4338 at line 103 +'eventMove' at /domains/default/npc/drone3#4375 at line 58 +'eventMove' at /domains/default/npc/drone3#4375 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#4375 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#4375 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#4375 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.17,44 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#4376 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#4339 at line 111 +'eventSpawn' at /domains/default/npc/drone3#4339 at line 103 +'CATCH' at /domains/default/npc/drone3#4339 at line 103 +'eventMove' at /domains/default/npc/drone3#4376 at line 58 +'eventMove' at /domains/default/npc/drone3#4376 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#4376 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#4376 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#4376 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.17,44 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#4378 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#4346 at line 111 +'eventSpawn' at /domains/default/npc/drone3#4346 at line 103 +'CATCH' at /domains/default/npc/drone3#4346 at line 103 +'eventMove' at /domains/default/npc/drone3#4378 at line 58 +'eventMove' at /domains/default/npc/drone3#4378 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#4378 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#4378 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#4378 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.17,44 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#4381 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#4350 at line 111 +'eventSpawn' at /domains/default/npc/drone3#4350 at line 103 +'CATCH' at /domains/default/npc/drone3#4350 at line 103 +'eventMove' at /domains/default/npc/drone3#4381 at line 58 +'eventMove' at /domains/default/npc/drone3#4381 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#4381 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#4381 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#4381 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.17,44 +*Error in loading object '/domains/oogtopia/room/start' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_enter_obj' at /verbs/rooms/enter at line 39 +'eventEnter' at /lib/std/dummy#4318 (/lib/enter.c) at line 115 +'eventMoveLiving' at /secure/save/creators/b/babylon (/lib/living.c) at line 725 +'CheckMove' at /daemon/guard at line 95 +'CATCH' at /daemon/guard at line 95 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-04.17,54 +*Error in loading object '/domains/oogtopia/room/start' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/goto at line 63 +'CATCH' at /secure/cmds/creators/goto at line 63 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-04.18,19 +*Error in loading object '/domains/oogtopia/room/start' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_go_str' at /verbs/rooms/go at line 45 +'eventGo' at /domains/oogtopia/room/bushes (/lib/exits.c) at line 107 +'eventMoveLiving' at /secure/save/creators/b/babylon (/lib/living.c) at line 725 +'CheckMove' at /daemon/guard at line 95 +'CATCH' at /daemon/guard at line 95 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-04.18,27 +*Error in loading object '/domains/oogtopia/room/start' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/admins/gridconfig at line 81 +'ResetGrid' at /secure/cmds/admins/gridconfig at line 52 +'CATCH' at /secure/cmds/admins/gridconfig at line 52 +'reload' at /secure/sefun/sefun at /secure/sefun/reload.c:34 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-04.18,27 +*Error in loading object '/domains/oogtopia/room/start' +Object: /domains/default/npc/drone3#4610 (/lib/props/move.c) at line 88 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/admins/gridconfig at line 81 +'ResetGrid' at /secure/cmds/admins/gridconfig at line 59 +'CATCH' at /secure/cmds/admins/gridconfig at line 59 +'eventMove' at /domains/default/npc/drone3#4610 at line 58 +'eventMove' at /domains/default/npc/drone3#4610 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#4610 (/lib/npc.c) at line 213 +'eventMove' at /domains/default/npc/drone3#4610 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#4610 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.18,32 +*Error in loading object '/domains/oogtopia/room/start' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_go_str' at /verbs/rooms/go at line 45 +'eventGo' at /domains/oogtopia/room/bushes (/lib/exits.c) at line 107 +'eventMoveLiving' at /secure/save/creators/b/babylon (/lib/living.c) at line 725 +'CheckMove' at /daemon/guard at line 95 +'CATCH' at /daemon/guard at line 95 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-04.18,37 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#4660 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#4609 at line 111 +'eventSpawn' at /domains/default/npc/drone3#4609 at line 103 +'CATCH' at /domains/default/npc/drone3#4609 at line 103 +'eventMove' at /domains/default/npc/drone3#4660 at line 58 +'eventMove' at /domains/default/npc/drone3#4660 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#4660 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#4660 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#4660 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.18,37 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#4663 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#4617 at line 111 +'eventSpawn' at /domains/default/npc/drone3#4617 at line 103 +'CATCH' at /domains/default/npc/drone3#4617 at line 103 +'eventMove' at /domains/default/npc/drone3#4663 at line 58 +'eventMove' at /domains/default/npc/drone3#4663 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#4663 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#4663 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#4663 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.18,37 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#4664 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#4618 at line 111 +'eventSpawn' at /domains/default/npc/drone3#4618 at line 103 +'CATCH' at /domains/default/npc/drone3#4618 at line 103 +'eventMove' at /domains/default/npc/drone3#4664 at line 58 +'eventMove' at /domains/default/npc/drone3#4664 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#4664 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#4664 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#4664 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.18,37 +*Error in loading object '/domains/oogtopia/room/start' +Object: /domains/default/npc/drone3#4666 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#4623 at line 111 +'eventSpawn' at /domains/default/npc/drone3#4623 at line 103 +'CATCH' at /domains/default/npc/drone3#4623 at line 103 +'eventMove' at /domains/default/npc/drone3#4666 at line 58 +'eventMove' at /domains/default/npc/drone3#4666 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#4666 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#4666 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#4666 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.18,37 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#4668 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#4623 at line 111 +'eventSpawn' at /domains/default/npc/drone3#4623 at line 103 +'CATCH' at /domains/default/npc/drone3#4623 at line 103 +'eventMove' at /domains/default/npc/drone3#4668 at line 58 +'eventMove' at /domains/default/npc/drone3#4668 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#4668 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#4668 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#4668 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.18,37 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#4669 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#4624 at line 111 +'eventSpawn' at /domains/default/npc/drone3#4624 at line 103 +'CATCH' at /domains/default/npc/drone3#4624 at line 103 +'eventMove' at /domains/default/npc/drone3#4669 at line 58 +'eventMove' at /domains/default/npc/drone3#4669 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#4669 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#4669 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#4669 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.18,37 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#4675 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#4630 at line 111 +'eventSpawn' at /domains/default/npc/drone3#4630 at line 103 +'CATCH' at /domains/default/npc/drone3#4630 at line 103 +'eventMove' at /domains/default/npc/drone3#4675 at line 58 +'eventMove' at /domains/default/npc/drone3#4675 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#4675 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#4675 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#4675 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.18,37 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#4678 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#4640 at line 111 +'eventSpawn' at /domains/default/npc/drone3#4640 at line 103 +'CATCH' at /domains/default/npc/drone3#4640 at line 103 +'eventMove' at /domains/default/npc/drone3#4678 at line 58 +'eventMove' at /domains/default/npc/drone3#4678 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#4678 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#4678 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#4678 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.18,37 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#4679 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#4641 at line 111 +'eventSpawn' at /domains/default/npc/drone3#4641 at line 103 +'CATCH' at /domains/default/npc/drone3#4641 at line 103 +'eventMove' at /domains/default/npc/drone3#4679 at line 58 +'eventMove' at /domains/default/npc/drone3#4679 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#4679 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#4679 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#4679 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.18,37 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#4681 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#4648 at line 111 +'eventSpawn' at /domains/default/npc/drone3#4648 at line 103 +'CATCH' at /domains/default/npc/drone3#4648 at line 103 +'eventMove' at /domains/default/npc/drone3#4681 at line 58 +'eventMove' at /domains/default/npc/drone3#4681 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#4681 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#4681 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#4681 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.18,37 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#4684 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#4652 at line 111 +'eventSpawn' at /domains/default/npc/drone3#4652 at line 103 +'CATCH' at /domains/default/npc/drone3#4652 at line 103 +'eventMove' at /domains/default/npc/drone3#4684 at line 58 +'eventMove' at /domains/default/npc/drone3#4684 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#4684 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#4684 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#4684 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.18,44 +*Error in loading object '/domains/oogtopia/room/start' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_go_str' at /verbs/rooms/go at line 45 +'eventGo' at /domains/oogtopia/room/bushes (/lib/exits.c) at line 107 +'eventMoveLiving' at /secure/save/creators/b/babylon (/lib/living.c) at line 725 +'CheckMove' at /daemon/guard at line 95 +'CATCH' at /daemon/guard at line 95 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-04.19,37 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#4961 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#4922 at line 111 +'eventSpawn' at /domains/default/npc/drone3#4922 at line 103 +'CATCH' at /domains/default/npc/drone3#4922 at line 103 +'eventMove' at /domains/default/npc/drone3#4961 at line 58 +'eventMove' at /domains/default/npc/drone3#4961 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#4961 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#4961 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#4961 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.19,47 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#4994 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#4957 at line 111 +'eventSpawn' at /domains/default/npc/drone3#4957 at line 103 +'CATCH' at /domains/default/npc/drone3#4957 at line 103 +'eventMove' at /domains/default/npc/drone3#4994 at line 58 +'eventMove' at /domains/default/npc/drone3#4994 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#4994 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#4994 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#4994 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.20,07 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#5050 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#5030 at line 111 +'eventSpawn' at /domains/default/npc/drone3#5030 at line 103 +'CATCH' at /domains/default/npc/drone3#5030 at line 103 +'eventMove' at /domains/default/npc/drone3#5050 at line 58 +'eventMove' at /domains/default/npc/drone3#5050 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#5050 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#5050 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#5050 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.20,44 +*Error in loading object '/domains/oogtopia/room/start' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_go_str' at /verbs/rooms/go at line 45 +'eventGo' at /domains/oogtopia/room/bushes (/lib/exits.c) at line 107 +'eventMoveLiving' at /secure/save/creators/b/babylon (/lib/living.c) at line 725 +'CheckMove' at /daemon/guard at line 95 +'CATCH' at /daemon/guard at line 95 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-04.20,46 +*Error in loading object '/domains/oogtopia/room/start' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_go_str' at /verbs/rooms/go at line 45 +'eventGo' at /domains/oogtopia/room/bushes (/lib/exits.c) at line 107 +'eventMoveLiving' at /secure/save/creators/b/babylon (/lib/living.c) at line 725 +'CheckMove' at /daemon/guard at line 95 +'CATCH' at /daemon/guard at line 95 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-04.20,49 +*Error in loading object '/domains/oogtopia/room/start' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_go_str' at /verbs/rooms/go at line 45 +'eventGo' at /domains/oogtopia/room/bushes (/lib/exits.c) at line 107 +'eventMoveLiving' at /secure/save/creators/b/babylon (/lib/living.c) at line 725 +'CheckMove' at /daemon/guard at line 95 +'CATCH' at /daemon/guard at line 95 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-04.20,52 +*Error in loading object '/domains/oogtopia/room/start' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_go_str' at /verbs/rooms/go at line 45 +'eventGo' at /domains/oogtopia/room/bushes (/lib/exits.c) at line 107 +'eventMoveLiving' at /secure/save/creators/b/babylon (/lib/living.c) at line 725 +'CheckMove' at /daemon/guard at line 95 +'CATCH' at /daemon/guard at line 95 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-04.21,27 +*Error in loading object '/domains/oogtopia/room/start' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/goto at line 63 +'CATCH' at /secure/cmds/creators/goto at line 63 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-04.23,03 +*call_other() couldn't find object +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_go_str' at /verbs/rooms/go at line 45 +'eventGo' at /domains/oogtopia/room/bushes (/lib/exits.c) at line 107 +'eventMoveLiving' at /secure/save/creators/b/babylon (/lib/living.c) at line 725 +'CheckMove' at /daemon/guard at line 95 +'CATCH' at /daemon/guard at line 95 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-04.46,59 +*Error in loading object '/domains/oogtopia/room/start' +Object: /secure/cmds/creators/update at line 170 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 85 +'CATCH' at /secure/cmds/creators/update at line 85 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 + +--- Zebu +2020.09.03-04.46,59 +*Error in loading object '/domains/oogtopia/room/start' +Object: /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 92 +'ReturnAndRelease' at /secure/cmds/creators/update at line 37 +'eventMove' at /secure/save/creators/b/babylon (/lib/creator.c) at line 266 +'eventMove' at /secure/save/creators/b/babylon (/lib/player.c) at line 287 +'eventMove' at /secure/save/creators/b/babylon (/lib/interactive.c) at line 255 +'eventMove' at /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 +'CATCH' at /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.48,18 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#5867 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#5748 at line 111 +'eventSpawn' at /domains/default/npc/drone3#5748 at line 103 +'CATCH' at /domains/default/npc/drone3#5748 at line 103 +'eventMove' at /domains/default/npc/drone3#5867 at line 58 +'eventMove' at /domains/default/npc/drone3#5867 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#5867 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#5867 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#5867 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.48,18 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#5872 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#5779 at line 111 +'eventSpawn' at /domains/default/npc/drone3#5779 at line 103 +'CATCH' at /domains/default/npc/drone3#5779 at line 103 +'eventMove' at /domains/default/npc/drone3#5872 at line 58 +'eventMove' at /domains/default/npc/drone3#5872 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#5872 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#5872 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#5872 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.48,18 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#5875 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#5786 at line 111 +'eventSpawn' at /domains/default/npc/drone3#5786 at line 103 +'CATCH' at /domains/default/npc/drone3#5786 at line 103 +'eventMove' at /domains/default/npc/drone3#5875 at line 58 +'eventMove' at /domains/default/npc/drone3#5875 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#5875 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#5875 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#5875 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.48,18 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#5876 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#5787 at line 111 +'eventSpawn' at /domains/default/npc/drone3#5787 at line 103 +'CATCH' at /domains/default/npc/drone3#5787 at line 103 +'eventMove' at /domains/default/npc/drone3#5876 at line 58 +'eventMove' at /domains/default/npc/drone3#5876 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#5876 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#5876 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#5876 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.48,18 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#5880 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#5792 at line 111 +'eventSpawn' at /domains/default/npc/drone3#5792 at line 103 +'CATCH' at /domains/default/npc/drone3#5792 at line 103 +'eventMove' at /domains/default/npc/drone3#5880 at line 58 +'eventMove' at /domains/default/npc/drone3#5880 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#5880 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#5880 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#5880 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.48,18 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#5881 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#5793 at line 111 +'eventSpawn' at /domains/default/npc/drone3#5793 at line 103 +'CATCH' at /domains/default/npc/drone3#5793 at line 103 +'eventMove' at /domains/default/npc/drone3#5881 at line 58 +'eventMove' at /domains/default/npc/drone3#5881 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#5881 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#5881 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#5881 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.48,18 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#5887 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#5799 at line 111 +'eventSpawn' at /domains/default/npc/drone3#5799 at line 103 +'CATCH' at /domains/default/npc/drone3#5799 at line 103 +'eventMove' at /domains/default/npc/drone3#5887 at line 58 +'eventMove' at /domains/default/npc/drone3#5887 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#5887 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#5887 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#5887 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.48,18 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#5890 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#5809 at line 111 +'eventSpawn' at /domains/default/npc/drone3#5809 at line 103 +'CATCH' at /domains/default/npc/drone3#5809 at line 103 +'eventMove' at /domains/default/npc/drone3#5890 at line 58 +'eventMove' at /domains/default/npc/drone3#5890 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#5890 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#5890 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#5890 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.48,18 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#5891 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#5810 at line 111 +'eventSpawn' at /domains/default/npc/drone3#5810 at line 103 +'CATCH' at /domains/default/npc/drone3#5810 at line 103 +'eventMove' at /domains/default/npc/drone3#5891 at line 58 +'eventMove' at /domains/default/npc/drone3#5891 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#5891 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#5891 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#5891 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.48,18 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#5893 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#5817 at line 111 +'eventSpawn' at /domains/default/npc/drone3#5817 at line 103 +'CATCH' at /domains/default/npc/drone3#5817 at line 103 +'eventMove' at /domains/default/npc/drone3#5893 at line 58 +'eventMove' at /domains/default/npc/drone3#5893 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#5893 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#5893 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#5893 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.48,18 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#5896 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#5821 at line 111 +'eventSpawn' at /domains/default/npc/drone3#5821 at line 103 +'CATCH' at /domains/default/npc/drone3#5821 at line 103 +'eventMove' at /domains/default/npc/drone3#5896 at line 58 +'eventMove' at /domains/default/npc/drone3#5896 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#5896 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#5896 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#5896 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.49,18 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#6174 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6137 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6137 at line 103 +'CATCH' at /domains/default/npc/drone3#6137 at line 103 +'eventMove' at /domains/default/npc/drone3#6174 at line 58 +'eventMove' at /domains/default/npc/drone3#6174 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#6174 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#6174 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#6174 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.49,28 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#6206 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6170 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6170 at line 103 +'CATCH' at /domains/default/npc/drone3#6170 at line 103 +'eventMove' at /domains/default/npc/drone3#6206 at line 58 +'eventMove' at /domains/default/npc/drone3#6206 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#6206 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#6206 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#6206 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.49,32 +*call_other() couldn't find object +Object: /secure/cmds/creators/update at line 170 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 85 +'CATCH' at /secure/cmds/creators/update at line 85 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 + +--- Zebu +2020.09.03-04.49,32 +*call_other() couldn't find object +Object: /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 92 +'ReturnAndRelease' at /secure/cmds/creators/update at line 37 +'eventMove' at /secure/save/creators/b/babylon (/lib/creator.c) at line 266 +'eventMove' at /secure/save/creators/b/babylon (/lib/player.c) at line 287 +'eventMove' at /secure/save/creators/b/babylon (/lib/interactive.c) at line 255 +'eventMove' at /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 +'CATCH' at /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.49,48 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#6265 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6243 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6243 at line 103 +'CATCH' at /domains/default/npc/drone3#6243 at line 103 +'eventMove' at /domains/default/npc/drone3#6265 at line 58 +'eventMove' at /domains/default/npc/drone3#6265 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#6265 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#6265 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#6265 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.50,43 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#6422 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6305 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6305 at line 103 +'CATCH' at /domains/default/npc/drone3#6305 at line 103 +'eventMove' at /domains/default/npc/drone3#6422 at line 58 +'eventMove' at /domains/default/npc/drone3#6422 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#6422 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#6422 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#6422 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.50,43 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#6425 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6336 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6336 at line 103 +'CATCH' at /domains/default/npc/drone3#6336 at line 103 +'eventMove' at /domains/default/npc/drone3#6425 at line 58 +'eventMove' at /domains/default/npc/drone3#6425 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#6425 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#6425 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#6425 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.50,43 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#6428 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6343 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6343 at line 103 +'CATCH' at /domains/default/npc/drone3#6343 at line 103 +'eventMove' at /domains/default/npc/drone3#6428 at line 58 +'eventMove' at /domains/default/npc/drone3#6428 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#6428 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#6428 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#6428 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.50,43 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#6429 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6344 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6344 at line 103 +'CATCH' at /domains/default/npc/drone3#6344 at line 103 +'eventMove' at /domains/default/npc/drone3#6429 at line 58 +'eventMove' at /domains/default/npc/drone3#6429 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#6429 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#6429 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#6429 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.50,43 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#6433 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6349 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6349 at line 103 +'CATCH' at /domains/default/npc/drone3#6349 at line 103 +'eventMove' at /domains/default/npc/drone3#6433 at line 58 +'eventMove' at /domains/default/npc/drone3#6433 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#6433 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#6433 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#6433 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.50,43 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#6434 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6350 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6350 at line 103 +'CATCH' at /domains/default/npc/drone3#6350 at line 103 +'eventMove' at /domains/default/npc/drone3#6434 at line 58 +'eventMove' at /domains/default/npc/drone3#6434 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#6434 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#6434 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#6434 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.50,43 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#6440 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6356 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6356 at line 103 +'CATCH' at /domains/default/npc/drone3#6356 at line 103 +'eventMove' at /domains/default/npc/drone3#6440 at line 58 +'eventMove' at /domains/default/npc/drone3#6440 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#6440 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#6440 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#6440 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.50,43 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#6443 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6366 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6366 at line 103 +'CATCH' at /domains/default/npc/drone3#6366 at line 103 +'eventMove' at /domains/default/npc/drone3#6443 at line 58 +'eventMove' at /domains/default/npc/drone3#6443 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#6443 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#6443 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#6443 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.50,43 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#6444 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6367 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6367 at line 103 +'CATCH' at /domains/default/npc/drone3#6367 at line 103 +'eventMove' at /domains/default/npc/drone3#6444 at line 58 +'eventMove' at /domains/default/npc/drone3#6444 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#6444 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#6444 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#6444 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.50,43 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#6446 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6374 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6374 at line 103 +'CATCH' at /domains/default/npc/drone3#6374 at line 103 +'eventMove' at /domains/default/npc/drone3#6446 at line 58 +'eventMove' at /domains/default/npc/drone3#6446 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#6446 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#6446 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#6446 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.50,43 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#6449 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6378 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6378 at line 103 +'CATCH' at /domains/default/npc/drone3#6378 at line 103 +'eventMove' at /domains/default/npc/drone3#6449 at line 58 +'eventMove' at /domains/default/npc/drone3#6449 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#6449 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#6449 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#6449 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.51,03 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#6506 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6464 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6464 at line 103 +'CATCH' at /domains/default/npc/drone3#6464 at line 103 +'eventMove' at /domains/default/npc/drone3#6506 at line 58 +'eventMove' at /domains/default/npc/drone3#6506 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#6506 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#6506 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#6506 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.51,06 +*call_other() couldn't find object +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_go_str' at /verbs/rooms/go at line 45 +'eventGo' at /domains/oogtopia/room/field (/lib/exits.c) at line 107 +'eventMoveLiving' at /secure/save/creators/b/babylon (/lib/living.c) at line 725 +'CheckMove' at /daemon/guard at line 95 +'CATCH' at /daemon/guard at line 95 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-04.51,21 +*call_other() couldn't find object +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_go_str' at /verbs/rooms/go at line 45 +'eventGo' at /domains/oogtopia/room/field (/lib/exits.c) at line 107 +'eventMoveLiving' at /secure/save/creators/b/babylon (/lib/living.c) at line 725 +'CheckMove' at /daemon/guard at line 95 +'CATCH' at /daemon/guard at line 95 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-04.51,43 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#6727 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6690 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6690 at line 103 +'CATCH' at /domains/default/npc/drone3#6690 at line 103 +'eventMove' at /domains/default/npc/drone3#6727 at line 58 +'eventMove' at /domains/default/npc/drone3#6727 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#6727 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#6727 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#6727 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.51,53 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#6761 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6723 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6723 at line 103 +'CATCH' at /domains/default/npc/drone3#6723 at line 103 +'eventMove' at /domains/default/npc/drone3#6761 at line 58 +'eventMove' at /domains/default/npc/drone3#6761 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#6761 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#6761 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#6761 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.52,13 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#6817 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6797 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6797 at line 103 +'CATCH' at /domains/default/npc/drone3#6797 at line 103 +'eventMove' at /domains/default/npc/drone3#6817 at line 58 +'eventMove' at /domains/default/npc/drone3#6817 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#6817 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#6817 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#6817 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.52,34 +*call_other() couldn't find object +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_go_str' at /verbs/rooms/go at line 45 +'eventGo' at /domains/oogtopia/room/field (/lib/exits.c) at line 107 +'eventMoveLiving' at /secure/save/creators/b/babylon (/lib/living.c) at line 725 +'CheckMove' at /daemon/guard at line 95 +'CATCH' at /daemon/guard at line 95 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-04.52,46 +*call_other() couldn't find object +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_go_str' at /verbs/rooms/go at line 45 +'eventGo' at /domains/oogtopia/room/field (/lib/exits.c) at line 107 +'eventMoveLiving' at /secure/save/creators/b/babylon (/lib/living.c) at line 725 +'CheckMove' at /daemon/guard at line 95 +'CATCH' at /daemon/guard at line 95 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-04.53,32 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#6989 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6870 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6870 at line 103 +'CATCH' at /domains/default/npc/drone3#6870 at line 103 +'eventMove' at /domains/default/npc/drone3#6989 at line 58 +'eventMove' at /domains/default/npc/drone3#6989 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#6989 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#6989 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#6989 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.53,32 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#6992 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6908 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6908 at line 103 +'CATCH' at /domains/default/npc/drone3#6908 at line 103 +'eventMove' at /domains/default/npc/drone3#6992 at line 58 +'eventMove' at /domains/default/npc/drone3#6992 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#6992 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#6992 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#6992 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.53,32 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#6993 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6909 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6909 at line 103 +'CATCH' at /domains/default/npc/drone3#6909 at line 103 +'eventMove' at /domains/default/npc/drone3#6993 at line 58 +'eventMove' at /domains/default/npc/drone3#6993 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#6993 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#6993 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#6993 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.53,32 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#6997 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6914 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6914 at line 103 +'CATCH' at /domains/default/npc/drone3#6914 at line 103 +'eventMove' at /domains/default/npc/drone3#6997 at line 58 +'eventMove' at /domains/default/npc/drone3#6997 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#6997 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#6997 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#6997 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.53,32 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#6998 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6915 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6915 at line 103 +'CATCH' at /domains/default/npc/drone3#6915 at line 103 +'eventMove' at /domains/default/npc/drone3#6998 at line 58 +'eventMove' at /domains/default/npc/drone3#6998 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#6998 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#6998 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#6998 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.53,32 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#7004 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6921 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6921 at line 103 +'CATCH' at /domains/default/npc/drone3#6921 at line 103 +'eventMove' at /domains/default/npc/drone3#7004 at line 58 +'eventMove' at /domains/default/npc/drone3#7004 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#7004 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#7004 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#7004 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.53,32 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#7007 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6931 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6931 at line 103 +'CATCH' at /domains/default/npc/drone3#6931 at line 103 +'eventMove' at /domains/default/npc/drone3#7007 at line 58 +'eventMove' at /domains/default/npc/drone3#7007 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#7007 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#7007 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#7007 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.53,32 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#7008 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6932 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6932 at line 103 +'CATCH' at /domains/default/npc/drone3#6932 at line 103 +'eventMove' at /domains/default/npc/drone3#7008 at line 58 +'eventMove' at /domains/default/npc/drone3#7008 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#7008 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#7008 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#7008 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.53,32 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#7010 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6939 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6939 at line 103 +'CATCH' at /domains/default/npc/drone3#6939 at line 103 +'eventMove' at /domains/default/npc/drone3#7010 at line 58 +'eventMove' at /domains/default/npc/drone3#7010 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#7010 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#7010 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#7010 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.53,32 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#7013 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6943 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6943 at line 103 +'CATCH' at /domains/default/npc/drone3#6943 at line 103 +'eventMove' at /domains/default/npc/drone3#7013 at line 58 +'eventMove' at /domains/default/npc/drone3#7013 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#7013 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#7013 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#7013 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.53,42 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#7016 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#6901 at line 111 +'eventSpawn' at /domains/default/npc/drone3#6901 at line 103 +'CATCH' at /domains/default/npc/drone3#6901 at line 103 +'eventMove' at /domains/default/npc/drone3#7016 at line 58 +'eventMove' at /domains/default/npc/drone3#7016 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#7016 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#7016 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#7016 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.54,32 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#7293 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#7256 at line 111 +'eventSpawn' at /domains/default/npc/drone3#7256 at line 103 +'CATCH' at /domains/default/npc/drone3#7256 at line 103 +'eventMove' at /domains/default/npc/drone3#7293 at line 58 +'eventMove' at /domains/default/npc/drone3#7293 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#7293 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#7293 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#7293 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.54,42 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#7325 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#7289 at line 111 +'eventSpawn' at /domains/default/npc/drone3#7289 at line 103 +'CATCH' at /domains/default/npc/drone3#7289 at line 103 +'eventMove' at /domains/default/npc/drone3#7325 at line 58 +'eventMove' at /domains/default/npc/drone3#7325 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#7325 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#7325 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#7325 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.55,02 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#7383 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#7361 at line 111 +'eventSpawn' at /domains/default/npc/drone3#7361 at line 103 +'CATCH' at /domains/default/npc/drone3#7361 at line 103 +'eventMove' at /domains/default/npc/drone3#7383 at line 58 +'eventMove' at /domains/default/npc/drone3#7383 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#7383 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#7383 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#7383 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.58,37 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#7550 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#7436 at line 111 +'eventSpawn' at /domains/default/npc/drone3#7436 at line 103 +'CATCH' at /domains/default/npc/drone3#7436 at line 103 +'eventMove' at /domains/default/npc/drone3#7550 at line 58 +'eventMove' at /domains/default/npc/drone3#7550 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#7550 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#7550 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#7550 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.58,37 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#7553 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#7467 at line 111 +'eventSpawn' at /domains/default/npc/drone3#7467 at line 103 +'CATCH' at /domains/default/npc/drone3#7467 at line 103 +'eventMove' at /domains/default/npc/drone3#7553 at line 58 +'eventMove' at /domains/default/npc/drone3#7553 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#7553 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#7553 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#7553 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.58,37 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#7556 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#7474 at line 111 +'eventSpawn' at /domains/default/npc/drone3#7474 at line 103 +'CATCH' at /domains/default/npc/drone3#7474 at line 103 +'eventMove' at /domains/default/npc/drone3#7556 at line 58 +'eventMove' at /domains/default/npc/drone3#7556 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#7556 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#7556 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#7556 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.58,37 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#7557 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#7475 at line 111 +'eventSpawn' at /domains/default/npc/drone3#7475 at line 103 +'CATCH' at /domains/default/npc/drone3#7475 at line 103 +'eventMove' at /domains/default/npc/drone3#7557 at line 58 +'eventMove' at /domains/default/npc/drone3#7557 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#7557 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#7557 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#7557 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.58,37 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#7561 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#7480 at line 111 +'eventSpawn' at /domains/default/npc/drone3#7480 at line 103 +'CATCH' at /domains/default/npc/drone3#7480 at line 103 +'eventMove' at /domains/default/npc/drone3#7561 at line 58 +'eventMove' at /domains/default/npc/drone3#7561 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#7561 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#7561 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#7561 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.58,37 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#7562 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#7481 at line 111 +'eventSpawn' at /domains/default/npc/drone3#7481 at line 103 +'CATCH' at /domains/default/npc/drone3#7481 at line 103 +'eventMove' at /domains/default/npc/drone3#7562 at line 58 +'eventMove' at /domains/default/npc/drone3#7562 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#7562 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#7562 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#7562 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.58,37 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#7568 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#7487 at line 111 +'eventSpawn' at /domains/default/npc/drone3#7487 at line 103 +'CATCH' at /domains/default/npc/drone3#7487 at line 103 +'eventMove' at /domains/default/npc/drone3#7568 at line 58 +'eventMove' at /domains/default/npc/drone3#7568 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#7568 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#7568 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#7568 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.58,37 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#7571 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#7497 at line 111 +'eventSpawn' at /domains/default/npc/drone3#7497 at line 103 +'CATCH' at /domains/default/npc/drone3#7497 at line 103 +'eventMove' at /domains/default/npc/drone3#7571 at line 58 +'eventMove' at /domains/default/npc/drone3#7571 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#7571 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#7571 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#7571 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.58,37 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#7572 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#7498 at line 111 +'eventSpawn' at /domains/default/npc/drone3#7498 at line 103 +'CATCH' at /domains/default/npc/drone3#7498 at line 103 +'eventMove' at /domains/default/npc/drone3#7572 at line 58 +'eventMove' at /domains/default/npc/drone3#7572 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#7572 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#7572 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#7572 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.58,37 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#7574 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#7505 at line 111 +'eventSpawn' at /domains/default/npc/drone3#7505 at line 103 +'CATCH' at /domains/default/npc/drone3#7505 at line 103 +'eventMove' at /domains/default/npc/drone3#7574 at line 58 +'eventMove' at /domains/default/npc/drone3#7574 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#7574 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#7574 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#7574 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.58,37 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#7577 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#7509 at line 111 +'eventSpawn' at /domains/default/npc/drone3#7509 at line 103 +'CATCH' at /domains/default/npc/drone3#7509 at line 103 +'eventMove' at /domains/default/npc/drone3#7577 at line 58 +'eventMove' at /domains/default/npc/drone3#7577 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#7577 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#7577 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#7577 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.59,37 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#7854 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#7817 at line 111 +'eventSpawn' at /domains/default/npc/drone3#7817 at line 103 +'CATCH' at /domains/default/npc/drone3#7817 at line 103 +'eventMove' at /domains/default/npc/drone3#7854 at line 58 +'eventMove' at /domains/default/npc/drone3#7854 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#7854 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#7854 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#7854 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-04.59,47 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#7891 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#7850 at line 111 +'eventSpawn' at /domains/default/npc/drone3#7850 at line 103 +'CATCH' at /domains/default/npc/drone3#7850 at line 103 +'eventMove' at /domains/default/npc/drone3#7891 at line 58 +'eventMove' at /domains/default/npc/drone3#7891 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#7891 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#7891 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#7891 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-05.00,07 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#7948 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#7927 at line 111 +'eventSpawn' at /domains/default/npc/drone3#7927 at line 103 +'CATCH' at /domains/default/npc/drone3#7927 at line 103 +'eventMove' at /domains/default/npc/drone3#7948 at line 58 +'eventMove' at /domains/default/npc/drone3#7948 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#7948 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#7948 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#7948 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-05.08,16 +*Error in loading object '/realms/babylon/tmp/party_oogahnlihdbf1599134896' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_modify_obj_str' at /verbs/builders/modify at line 83 +'eventModify' at /secure/obj/staff#5106 (/secure/modules/create.c) at line 632 +'reload' at /secure/sefun/sefun at /secure/sefun/reload.c:34 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-05.14,09 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#8144 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#8089 at line 111 +'eventSpawn' at /domains/default/npc/drone3#8089 at line 103 +'CATCH' at /domains/default/npc/drone3#8089 at line 103 +'eventMove' at /domains/default/npc/drone3#8144 at line 58 +'eventMove' at /domains/default/npc/drone3#8144 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#8144 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#8144 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#8144 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-05.14,09 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#8148 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#8095 at line 111 +'eventSpawn' at /domains/default/npc/drone3#8095 at line 103 +'CATCH' at /domains/default/npc/drone3#8095 at line 103 +'eventMove' at /domains/default/npc/drone3#8148 at line 58 +'eventMove' at /domains/default/npc/drone3#8148 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#8148 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#8148 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#8148 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-05.14,09 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#8151 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#8102 at line 111 +'eventSpawn' at /domains/default/npc/drone3#8102 at line 103 +'CATCH' at /domains/default/npc/drone3#8102 at line 103 +'eventMove' at /domains/default/npc/drone3#8151 at line 58 +'eventMove' at /domains/default/npc/drone3#8151 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#8151 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#8151 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#8151 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-05.14,09 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#8152 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#8103 at line 111 +'eventSpawn' at /domains/default/npc/drone3#8103 at line 103 +'CATCH' at /domains/default/npc/drone3#8103 at line 103 +'eventMove' at /domains/default/npc/drone3#8152 at line 58 +'eventMove' at /domains/default/npc/drone3#8152 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#8152 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#8152 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#8152 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-05.14,09 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#8156 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#8108 at line 111 +'eventSpawn' at /domains/default/npc/drone3#8108 at line 103 +'CATCH' at /domains/default/npc/drone3#8108 at line 103 +'eventMove' at /domains/default/npc/drone3#8156 at line 58 +'eventMove' at /domains/default/npc/drone3#8156 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#8156 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#8156 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#8156 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-05.14,09 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#8157 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#8109 at line 111 +'eventSpawn' at /domains/default/npc/drone3#8109 at line 103 +'CATCH' at /domains/default/npc/drone3#8109 at line 103 +'eventMove' at /domains/default/npc/drone3#8157 at line 58 +'eventMove' at /domains/default/npc/drone3#8157 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#8157 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#8157 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#8157 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-05.14,09 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#8163 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#8115 at line 111 +'eventSpawn' at /domains/default/npc/drone3#8115 at line 103 +'CATCH' at /domains/default/npc/drone3#8115 at line 103 +'eventMove' at /domains/default/npc/drone3#8163 at line 58 +'eventMove' at /domains/default/npc/drone3#8163 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#8163 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#8163 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#8163 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-05.14,09 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#8166 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#8125 at line 111 +'eventSpawn' at /domains/default/npc/drone3#8125 at line 103 +'CATCH' at /domains/default/npc/drone3#8125 at line 103 +'eventMove' at /domains/default/npc/drone3#8166 at line 58 +'eventMove' at /domains/default/npc/drone3#8166 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#8166 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#8166 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#8166 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-05.14,09 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#8167 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#8126 at line 111 +'eventSpawn' at /domains/default/npc/drone3#8126 at line 103 +'CATCH' at /domains/default/npc/drone3#8126 at line 103 +'eventMove' at /domains/default/npc/drone3#8167 at line 58 +'eventMove' at /domains/default/npc/drone3#8167 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#8167 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#8167 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#8167 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-05.14,09 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#8169 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#8133 at line 111 +'eventSpawn' at /domains/default/npc/drone3#8133 at line 103 +'CATCH' at /domains/default/npc/drone3#8133 at line 103 +'eventMove' at /domains/default/npc/drone3#8169 at line 58 +'eventMove' at /domains/default/npc/drone3#8169 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#8169 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#8169 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#8169 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-05.14,09 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#8172 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#8137 at line 111 +'eventSpawn' at /domains/default/npc/drone3#8137 at line 103 +'CATCH' at /domains/default/npc/drone3#8137 at line 103 +'eventMove' at /domains/default/npc/drone3#8172 at line 58 +'eventMove' at /domains/default/npc/drone3#8172 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#8172 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#8172 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#8172 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-05.15,09 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#8452 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#8413 at line 111 +'eventSpawn' at /domains/default/npc/drone3#8413 at line 103 +'CATCH' at /domains/default/npc/drone3#8413 at line 103 +'eventMove' at /domains/default/npc/drone3#8452 at line 58 +'eventMove' at /domains/default/npc/drone3#8452 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#8452 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#8452 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#8452 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-05.15,19 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#8485 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#8448 at line 111 +'eventSpawn' at /domains/default/npc/drone3#8448 at line 103 +'CATCH' at /domains/default/npc/drone3#8448 at line 103 +'eventMove' at /domains/default/npc/drone3#8485 at line 58 +'eventMove' at /domains/default/npc/drone3#8485 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#8485 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#8485 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#8485 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-05.15,39 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#8541 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#8521 at line 111 +'eventSpawn' at /domains/default/npc/drone3#8521 at line 103 +'CATCH' at /domains/default/npc/drone3#8521 at line 103 +'eventMove' at /domains/default/npc/drone3#8541 at line 58 +'eventMove' at /domains/default/npc/drone3#8541 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#8541 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#8541 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#8541 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.03-05.16,19 +*Error in loading object '/domains/oogtopia/npc/party_ooga' +Object: /secure/cmds/creators/update at line 170 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 + +--- Zebu +2020.09.03-05.16,53 +*Error in loading object '/domains/oogtopia/npc/party_ooga' +Object: /domains/oogtopia/room/start (/lib/props/inventory.c) at line 27 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 85 +'CATCH' at /secure/cmds/creators/update at line 85 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 +'create' at /domains/oogtopia/room/start at line 21 +'SetInventory' at /domains/oogtopia/room/start (/lib/props/inventory.c) at line 101 +'eventLoadInventory' at /domains/oogtopia/room/start (/lib/props/inventory.c) at line 58 +'eventLoadItem' at /domains/oogtopia/room/start (/lib/props/inventory.c) at line 27 + +END-OF-LOG diff --git a/lib/log/archive/catch-2020.09.06-00.32,57 b/lib/log/archive/catch-2020.09.06-00.32,57 new file mode 100644 index 0000000..69f2674 --- /dev/null +++ b/lib/log/archive/catch-2020.09.06-00.32,57 @@ -0,0 +1,1104 @@ +NEW_LOG 2020.09.03-05.18,21 + +--- Zebu +2020.09.03-05.19,56 +*Error in loading object '/domains/oogtopia/npc/party_ooga' +Object: /secure/cmds/creators/update at line 170 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 + +--- Zebu +2020.09.03-05.22,03 +*Error in loading object '/domains/oogtopia/npc/party_ooga' +Object: /secure/cmds/creators/update at line 170 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 + +--- Zebu +2020.09.03-05.22,46 +*Error in loading object '/realms/babylon/tmp/party_oogaiookbigo1599135766' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_modify_obj_str' at /verbs/builders/modify at line 83 +'eventModify' at /secure/obj/staff#5106 (/secure/modules/create.c) at line 632 +'reload' at /secure/sefun/sefun at /secure/sefun/reload.c:34 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-05.23,14 +*Error in loading object '/domains/oogtopia/npc/party_ooga' +Object: /domains/oogtopia/room/start (/lib/props/inventory.c) at line 27 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 85 +'CATCH' at /secure/cmds/creators/update at line 85 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 +'create' at /domains/oogtopia/room/start at line 21 +'SetInventory' at /domains/oogtopia/room/start (/lib/props/inventory.c) at line 101 +'eventLoadInventory' at /domains/oogtopia/room/start (/lib/props/inventory.c) at line 58 +'eventLoadItem' at /domains/oogtopia/room/start (/lib/props/inventory.c) at line 27 + +--- Zebu +2020.09.03-05.23,46 +*Error in loading object '/realms/babylon/tmp/party_oogaffajhmbd1599135826' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_modify_obj_str' at /verbs/builders/modify at line 83 +'eventModify' at /secure/obj/staff#5106 (/secure/modules/create.c) at line 632 +'reload' at /secure/sefun/sefun at /secure/sefun/reload.c:34 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-05.25,19 +*Error in loading object '/domains/oogtopia/npc/party_ooga' +Object: /secure/cmds/creators/update at line 170 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 + +--- Zebu +2020.09.03-05.29,22 +*Error in loading object '/domains/oogtopia/npc/party_ooga' +Object: /secure/cmds/creators/update at line 170 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 + +--- Zebu +2020.09.03-05.29,47 +*Error in loading object '/domains/oogtopia/npc/party_ooga' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 149 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-05.29,47 +*Error in loading object '/domains/oogtopia/npc/party_ooga' +Object: /secure/cmds/creators/update at line 170 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 + +--- Zebu +2020.09.03-05.31,23 +*Error in loading object '/realms/babylon/tmp/party_oogancllhlfn1599136283' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_modify_obj_str' at /verbs/builders/modify at line 83 +'eventModify' at /secure/obj/staff#5106 (/secure/modules/create.c) at line 632 +'reload' at /secure/sefun/sefun at /secure/sefun/reload.c:34 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-05.32,53 +*Error in loading object '/domains/oogtopia/npc/bunga' +Object: /secure/cmds/creators/update at line 170 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 + +--- Zebu +2020.09.03-05.35,18 +*Error in loading object '/domains/oogtopia/npc/party_ooga' +Object: /secure/cmds/creators/update at line 170 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 + +--- Zebu +2020.09.03-05.36,01 +*Error in loading object '/domains/oogtopia/npc/party_ooga' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 149 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.03-05.36,01 +*Error in loading object '/domains/oogtopia/npc/party_ooga' +Object: /secure/cmds/creators/update at line 170 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 + +--- Zebu +2020.09.03-05.37,16 +*Error in loading object '/domains/oogtopia/npc/bunga' +Object: /secure/cmds/creators/update at line 170 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 + +--- Zebu +2020.09.03-05.41,06 +*Error in loading object '/domains/oogtopia/npc/bunga' +Object: /secure/cmds/creators/update at line 170 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 + +--- Zebu +2020.09.04-19.14,28 +*The file daemon has been disabled for your mud because it is running on windows. Intensive file operations in windows are not yet supported on Dead Souls. +Object: /secure/daemon/file at line 23 + +'<fake>' at /secure/daemon/events (/<driver>) at line 0 +'eventPollEvents' at /secure/daemon/events at line 144 +'CATCH' at /secure/daemon/events at line 144 +'<fake>' at /secure/daemon/file (/<driver>) at line 0 +'ReadDir' at /secure/daemon/file at line 49 +'validate' at /secure/daemon/file at line 23 + +--- Zebu +2020.09.04-19.22,23 +*call_other() couldn't find object +Object: /domains/voluntaria/room/airlock (/lib/exits.c) at line 150 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_enter_obj' at /verbs/rooms/enter at line 39 +'eventEnter' at /lib/std/dummy#261 (/lib/enter.c) at line 115 +'eventMoveLiving' at /secure/save/creators/b/babylon (/lib/living.c) at line 725 +'CheckMove' at /daemon/guard at line 95 +'CATCH' at /daemon/guard at line 95 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'create' at /domains/voluntaria/room/airlock at line 27 +'SetDoor' at /domains/voluntaria/room/airlock (/lib/exits.c) at line 150 + +--- Zebu +2020.09.04-19.23,20 +*call_other() couldn't find object +Object: /domains/voluntaria/room/airlock (/lib/exits.c) at line 150 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_delete_exit_str' at /verbs/builders/delete at line 59 +'eventDeleteExit' at /verbs/builders/delete at line 168 +'eventRemoveExit' at /secure/obj/staff#226 (/secure/modules/room.c) at line 232 +'reload' at /secure/sefun/sefun at /secure/sefun/reload.c:68 +'unguarded' at /secure/sefun/sefun at /secure/sefun/security.c:104 +'apply_unguarded' at /secure/daemon/master at line 606 +'CATCH' at /secure/daemon/master at line 606 +'<fake>' at /secure/sefun/sefun (/<driver>) at line 0 +'(: <code>() :)' at /secure/sefun/sefun at /secure/sefun/reload.c:68 +'CATCH' at /secure/sefun/sefun at /secure/sefun/reload.c:68 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 +'create' at /domains/voluntaria/room/airlock at line 26 +'SetDoor' at /domains/voluntaria/room/airlock (/lib/exits.c) at line 150 + +--- Zebu +2020.09.04-19.23,20 +*call_other() couldn't find object +Object: /domains/voluntaria/room/airlock (/lib/exits.c) at line 150 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_delete_exit_str' at /verbs/builders/delete at line 59 +'eventDeleteExit' at /verbs/builders/delete at line 170 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 +'create' at /domains/voluntaria/room/airlock at line 26 +'SetDoor' at /domains/voluntaria/room/airlock (/lib/exits.c) at line 150 + +--- Zebu +2020.09.04-19.26,45 +*call_other() couldn't find object +Object: /domains/voluntaria/room/airlock (/lib/exits.c) at line 150 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 85 +'CATCH' at /secure/cmds/creators/update at line 85 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 +'create' at /domains/voluntaria/room/airlock at line 27 +'SetDoor' at /domains/voluntaria/room/airlock (/lib/exits.c) at line 150 + +--- Zebu +2020.09.04-20.04,53 +*Error in loading object '/domains/voluntaria/room/space' +Object: /secure/cmds/creators/update at line 170 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 85 +'CATCH' at /secure/cmds/creators/update at line 85 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 + +--- Zebu +2020.09.04-20.04,53 +*Error in loading object '/domains/voluntaria/room/space' +Object: /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 92 +'ReturnAndRelease' at /secure/cmds/creators/update at line 37 +'eventMove' at /secure/save/creators/b/babylon (/lib/creator.c) at line 266 +'eventMove' at /secure/save/creators/b/babylon (/lib/player.c) at line 287 +'eventMove' at /secure/save/creators/b/babylon (/lib/interactive.c) at line 255 +'eventMove' at /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 +'CATCH' at /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.04-20.06,17 +*Error in loading object '/domains/voluntaria/room/space' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/goto at line 63 +'CATCH' at /secure/cmds/creators/goto at line 63 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.04-20.08,01 +*Error in loading object '/domains/voluntaria/room/space' +Object: /secure/cmds/creators/update at line 170 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 85 +'CATCH' at /secure/cmds/creators/update at line 85 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 + +--- Zebu +2020.09.04-20.08,01 +*Error in loading object '/domains/voluntaria/room/space' +Object: /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 92 +'ReturnAndRelease' at /secure/cmds/creators/update at line 37 +'eventMove' at /secure/save/creators/b/babylon (/lib/creator.c) at line 266 +'eventMove' at /secure/save/creators/b/babylon (/lib/player.c) at line 287 +'eventMove' at /secure/save/creators/b/babylon (/lib/interactive.c) at line 255 +'eventMove' at /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 +'CATCH' at /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.04-20.09,27 +*Error in loading object '/daemon/tmp/1,1,1' +Object: /daemon/defines at line 43 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/goto at line 19 +'GetDefine' at /daemon/defines at line 43 +'CATCH' at /daemon/defines at line 43 + +--- Zebu +2020.09.04-20.28,35 +*Bad argument 2 to foreach +Expected: array Got: 0. +Object: /realms/babylon/tmp/crapitalistjamaicfc1599276515 (/lib/race.c) at line 275 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_modify_obj_str' at /verbs/builders/modify at line 83 +'eventModify' at /secure/obj/staff#226 (/secure/modules/create.c) at line 632 +'reload' at /secure/sefun/sefun at /secure/sefun/reload.c:34 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'create' at /realms/babylon/tmp/crapitalistjamaicfc1599276515 at line 17 +'SetRace' at /realms/babylon/tmp/crapitalistjamaicfc1599276515 (/lib/npc.c) at line 419 +'SetRace' at /realms/babylon/tmp/crapitalistjamaicfc1599276515 (/lib/race.c) at line 200 +'NewBody' at /realms/babylon/tmp/crapitalistjamaicfc1599276515 (/lib/race.c) at line 275 + +--- Zebu +2020.09.04-20.28,35 +*Bad argument 2 to foreach +Expected: array Got: 0. +Object: /realms/babylon/tmp/crapitalistjamaicfc1599276515 (/lib/race.c) at line 275 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_modify_obj_str' at /verbs/builders/modify at line 83 +'eventModify' at /secure/obj/staff#226 (/secure/modules/create.c) at line 632 +'reload' at /secure/sefun/sefun at /secure/sefun/reload.c:87 +'unguarded' at /secure/sefun/sefun at /secure/sefun/security.c:104 +'apply_unguarded' at /secure/daemon/master at line 606 +'CATCH' at /secure/daemon/master at line 606 +'<fake>' at /secure/sefun/sefun (/<driver>) at line 0 +'(: <code>() :)' at /secure/sefun/sefun at /secure/sefun/reload.c:87 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 +'create' at /realms/babylon/tmp/crapitalistjamaicfc1599276515 at line 17 +'SetRace' at /realms/babylon/tmp/crapitalistjamaicfc1599276515 (/lib/npc.c) at line 419 +'SetRace' at /realms/babylon/tmp/crapitalistjamaicfc1599276515 (/lib/race.c) at line 200 +'NewBody' at /realms/babylon/tmp/crapitalistjamaicfc1599276515 (/lib/race.c) at line 275 + +--- Zebu +2020.09.04-20.28,35 +*Bad argument 2 to foreach +Expected: array Got: 0. +Object: /domains/voluntaria/npc/crapitalist (/lib/race.c) at line 275 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_modify_obj_str' at /verbs/builders/modify at line 83 +'eventModify' at /secure/obj/staff#226 (/secure/modules/create.c) at line 641 +'reload' at /secure/sefun/sefun at /secure/sefun/reload.c:87 +'unguarded' at /secure/sefun/sefun at /secure/sefun/security.c:104 +'apply_unguarded' at /secure/daemon/master at line 606 +'CATCH' at /secure/daemon/master at line 606 +'<fake>' at /secure/sefun/sefun (/<driver>) at line 0 +'(: <code>() :)' at /secure/sefun/sefun at /secure/sefun/reload.c:87 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 +'create' at /domains/voluntaria/npc/crapitalist at line 17 +'SetRace' at /domains/voluntaria/npc/crapitalist (/lib/npc.c) at line 419 +'SetRace' at /domains/voluntaria/npc/crapitalist (/lib/race.c) at line 200 +'NewBody' at /domains/voluntaria/npc/crapitalist (/lib/race.c) at line 275 + +--- Zebu +2020.09.04-20.28,35 +*Bad argument 2 to foreach +Expected: array Got: 0. +Object: /domains/voluntaria/npc/crapitalist#318 (/lib/race.c) at line 275 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_modify_obj_str' at /verbs/builders/modify at line 83 +'eventModify' at /secure/obj/staff#226 (/secure/modules/create.c) at line 641 +'reload' at /secure/sefun/sefun at /secure/sefun/reload.c:95 +'unguarded' at /secure/sefun/sefun at /secure/sefun/security.c:104 +'apply_unguarded' at /secure/daemon/master at line 606 +'CATCH' at /secure/daemon/master at line 606 +'<fake>' at /secure/sefun/sefun (/<driver>) at line 0 +'(: <code>() :)' at /secure/sefun/sefun at /secure/sefun/reload.c:95 +'create' at /domains/voluntaria/npc/crapitalist#318 at line 17 +'SetRace' at /domains/voluntaria/npc/crapitalist#318 (/lib/npc.c) at line 419 +'SetRace' at /domains/voluntaria/npc/crapitalist#318 (/lib/race.c) at line 200 +'NewBody' at /domains/voluntaria/npc/crapitalist#318 (/lib/race.c) at line 275 + +--- Zebu +2020.09.04-20.32,04 +*Bad argument 2 to foreach +Expected: array Got: 0. +Object: /domains/voluntaria/npc/crapitalist (/lib/race.c) at line 275 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 +'create' at /domains/voluntaria/npc/crapitalist at line 17 +'SetRace' at /domains/voluntaria/npc/crapitalist (/lib/npc.c) at line 419 +'SetRace' at /domains/voluntaria/npc/crapitalist (/lib/race.c) at line 200 +'NewBody' at /domains/voluntaria/npc/crapitalist (/lib/race.c) at line 275 + +--- Zebu +2020.09.04-20.33,32 +*call_other() couldn't find object +Object: /domains/voluntaria/room/airlock (/lib/exits.c) at line 150 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/builders/create at line 35 +'make' at /secure/obj/staff#226 (/secure/modules/room.c) at line 130 +'eventCreateExit' at /secure/obj/staff#226 (/secure/modules/room.c) at line 168 +'reload' at /secure/sefun/sefun at /secure/sefun/reload.c:68 +'unguarded' at /secure/sefun/sefun at /secure/sefun/security.c:104 +'apply_unguarded' at /secure/daemon/master at line 606 +'CATCH' at /secure/daemon/master at line 606 +'<fake>' at /secure/sefun/sefun (/<driver>) at line 0 +'(: <code>() :)' at /secure/sefun/sefun at /secure/sefun/reload.c:68 +'CATCH' at /secure/sefun/sefun at /secure/sefun/reload.c:68 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 +'create' at /domains/voluntaria/room/airlock at line 27 +'SetDoor' at /domains/voluntaria/room/airlock (/lib/exits.c) at line 150 + +--- Zebu +2020.09.04-20.33,32 +*call_other() couldn't find object +Object: /domains/voluntaria/room/airlock (/lib/exits.c) at line 150 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/builders/create at line 35 +'make' at /secure/obj/staff#226 (/secure/modules/room.c) at line 130 +'eventCreateExit' at /secure/obj/staff#226 (/secure/modules/room.c) at line 169 +'eventProcessExits' at /secure/obj/staff#226 (/secure/modules/room.c) at line 298 +'reload' at /secure/sefun/sefun at /secure/sefun/reload.c:68 +'unguarded' at /secure/sefun/sefun at /secure/sefun/security.c:104 +'apply_unguarded' at /secure/daemon/master at line 606 +'CATCH' at /secure/daemon/master at line 606 +'<fake>' at /secure/sefun/sefun (/<driver>) at line 0 +'(: <code>() :)' at /secure/sefun/sefun at /secure/sefun/reload.c:68 +'CATCH' at /secure/sefun/sefun at /secure/sefun/reload.c:68 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 +'create' at /domains/voluntaria/room/airlock at line 28 +'SetDoor' at /domains/voluntaria/room/airlock (/lib/exits.c) at line 150 + +--- Zebu +2020.09.04-21.17,59 +*Error in loading object '/domains/oogtopia/npc/party_ooga' +Object: /secure/cmds/creators/update at line 170 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 + +--- Zebu +2020.09.04-21.24,21 +*Value being indexed is zero. +Object: /domains/oogtopia/doors/airlock (/lib/door.c) at line 241 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/builders/create at line 36 +'gmake' at /secure/obj/staff#410 (/secure/modules/generic.c) at line 122 +'eventCreateDoor' at /secure/obj/staff#410 (/secure/modules/door.c) at line 263 +'reload' at /secure/sefun/sefun at /secure/sefun/reload.c:68 +'unguarded' at /secure/sefun/sefun at /secure/sefun/security.c:104 +'apply_unguarded' at /secure/daemon/master at line 606 +'CATCH' at /secure/daemon/master at line 606 +'<fake>' at /secure/sefun/sefun (/<driver>) at line 0 +'(: <code>() :)' at /secure/sefun/sefun at /secure/sefun/reload.c:68 +'CATCH' at /secure/sefun/sefun at /secure/sefun/reload.c:68 +'cmd' at /secure/cmds/creators/update at line 116 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 +'create' at /domains/voluntaria/room/space at line 28 +'SetDoor' at /domains/voluntaria/room/space (/lib/exits.c) at line 150 +'eventRegisterSide' at /domains/oogtopia/doors/airlock (/lib/door.c) at line 241 + +--- Zebu +2020.09.04-21.36,07 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#707 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#554 at line 111 +'eventSpawn' at /domains/default/npc/drone3#554 at line 103 +'CATCH' at /domains/default/npc/drone3#554 at line 103 +'eventMove' at /domains/default/npc/drone3#707 at line 58 +'eventMove' at /domains/default/npc/drone3#707 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#707 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#707 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#707 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.04-21.36,07 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#711 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#588 at line 111 +'eventSpawn' at /domains/default/npc/drone3#588 at line 103 +'CATCH' at /domains/default/npc/drone3#588 at line 103 +'eventMove' at /domains/default/npc/drone3#711 at line 58 +'eventMove' at /domains/default/npc/drone3#711 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#711 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#711 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#711 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.04-21.36,07 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#712 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#589 at line 111 +'eventSpawn' at /domains/default/npc/drone3#589 at line 103 +'CATCH' at /domains/default/npc/drone3#589 at line 103 +'eventMove' at /domains/default/npc/drone3#712 at line 58 +'eventMove' at /domains/default/npc/drone3#712 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#712 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#712 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#712 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.04-21.36,07 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#727 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#602 at line 111 +'eventSpawn' at /domains/default/npc/drone3#602 at line 103 +'CATCH' at /domains/default/npc/drone3#602 at line 103 +'eventMove' at /domains/default/npc/drone3#727 at line 58 +'eventMove' at /domains/default/npc/drone3#727 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#727 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#727 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#727 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.04-21.36,07 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#728 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#603 at line 111 +'eventSpawn' at /domains/default/npc/drone3#603 at line 103 +'CATCH' at /domains/default/npc/drone3#603 at line 103 +'eventMove' at /domains/default/npc/drone3#728 at line 58 +'eventMove' at /domains/default/npc/drone3#728 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#728 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#728 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#728 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.04-21.36,07 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#734 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#612 at line 111 +'eventSpawn' at /domains/default/npc/drone3#612 at line 103 +'CATCH' at /domains/default/npc/drone3#612 at line 103 +'eventMove' at /domains/default/npc/drone3#734 at line 58 +'eventMove' at /domains/default/npc/drone3#734 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#734 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#734 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#734 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.04-21.36,07 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#735 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#613 at line 111 +'eventSpawn' at /domains/default/npc/drone3#613 at line 103 +'CATCH' at /domains/default/npc/drone3#613 at line 103 +'eventMove' at /domains/default/npc/drone3#735 at line 58 +'eventMove' at /domains/default/npc/drone3#735 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#735 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#735 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#735 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.04-21.36,07 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#765 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#621 at line 111 +'eventSpawn' at /domains/default/npc/drone3#621 at line 103 +'CATCH' at /domains/default/npc/drone3#621 at line 103 +'eventMove' at /domains/default/npc/drone3#765 at line 58 +'eventMove' at /domains/default/npc/drone3#765 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#765 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#765 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#765 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.04-21.36,07 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#775 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#631 at line 111 +'eventSpawn' at /domains/default/npc/drone3#631 at line 103 +'CATCH' at /domains/default/npc/drone3#631 at line 103 +'eventMove' at /domains/default/npc/drone3#775 at line 58 +'eventMove' at /domains/default/npc/drone3#775 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#775 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#775 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#775 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.04-21.36,07 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#776 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#632 at line 111 +'eventSpawn' at /domains/default/npc/drone3#632 at line 103 +'CATCH' at /domains/default/npc/drone3#632 at line 103 +'eventMove' at /domains/default/npc/drone3#776 at line 58 +'eventMove' at /domains/default/npc/drone3#776 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#776 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#776 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#776 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.04-21.36,07 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#781 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#639 at line 111 +'eventSpawn' at /domains/default/npc/drone3#639 at line 103 +'CATCH' at /domains/default/npc/drone3#639 at line 103 +'eventMove' at /domains/default/npc/drone3#781 at line 58 +'eventMove' at /domains/default/npc/drone3#781 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#781 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#781 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#781 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.04-21.36,07 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#784 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#643 at line 111 +'eventSpawn' at /domains/default/npc/drone3#643 at line 103 +'CATCH' at /domains/default/npc/drone3#643 at line 103 +'eventMove' at /domains/default/npc/drone3#784 at line 58 +'eventMove' at /domains/default/npc/drone3#784 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#784 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#784 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#784 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.04-21.37,07 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#2725 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#2552 at line 111 +'eventSpawn' at /domains/default/npc/drone3#2552 at line 103 +'CATCH' at /domains/default/npc/drone3#2552 at line 103 +'eventMove' at /domains/default/npc/drone3#2725 at line 58 +'eventMove' at /domains/default/npc/drone3#2725 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#2725 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#2725 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#2725 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.04-21.37,17 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#3002 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#2700 at line 111 +'eventSpawn' at /domains/default/npc/drone3#2700 at line 103 +'CATCH' at /domains/default/npc/drone3#2700 at line 103 +'eventMove' at /domains/default/npc/drone3#3002 at line 58 +'eventMove' at /domains/default/npc/drone3#3002 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#3002 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#3002 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#3002 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.04-21.37,37 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#3394 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#3132 at line 111 +'eventSpawn' at /domains/default/npc/drone3#3132 at line 103 +'CATCH' at /domains/default/npc/drone3#3132 at line 103 +'eventMove' at /domains/default/npc/drone3#3394 at line 58 +'eventMove' at /domains/default/npc/drone3#3394 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#3394 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#3394 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#3394 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.05-21.32,34 +*Value being indexed is zero. +Object: /domains/oogtopia/doors/airlock (/lib/door.c) at line 241 + +'<fake>' at /secure/lib/connect#86 (/<driver>) at line 0 +'InputPassword' at /secure/lib/connect#86 at line 312 +'eventEnterGame' at /secure/lib/connect#86 at line 481 +'Setup' at /secure/save/creators/b/babylon (/lib/creator.c) at line 136 +'Setup' at /secure/save/creators/b/babylon (/lib/player.c) at line 317 +'Setup' at /secure/save/creators/b/babylon (/lib/interactive.c) at line 135 +'CATCH' at /secure/save/creators/b/babylon (/lib/interactive.c) at line 135 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'create' at /domains/voluntaria/room/airlock at line 29 +'SetDoor' at /domains/voluntaria/room/airlock (/lib/exits.c) at line 150 +'eventRegisterSide' at /domains/oogtopia/doors/airlock (/lib/door.c) at line 241 + +--- Zebu +2020.09.05-21.32,57 +*The file daemon has been disabled for your mud because it is running on windows. Intensive file operations in windows are not yet supported on Dead Souls. +Object: /secure/daemon/file at line 23 + +'<fake>' at /secure/daemon/events (/<driver>) at line 0 +'eventPollEvents' at /secure/daemon/events at line 144 +'CATCH' at /secure/daemon/events at line 144 +'<fake>' at /secure/daemon/file (/<driver>) at line 0 +'ReadDir' at /secure/daemon/file at line 49 +'validate' at /secure/daemon/file at line 23 + +--- Zebu +2020.09.05-21.33,05 +*Value being indexed is zero. +Object: /domains/oogtopia/doors/airlock (/lib/door.c) at line 241 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_go_str' at /verbs/rooms/go at line 45 +'eventGo' at /domains/voluntaria/room/airlock (/lib/exits.c) at line 107 +'eventMoveLiving' at /secure/save/creators/b/babylon (/lib/living.c) at line 725 +'CheckMove' at /daemon/guard at line 95 +'CATCH' at /daemon/guard at line 95 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'create' at /domains/voluntaria/room/space at line 28 +'SetDoor' at /domains/voluntaria/room/space (/lib/exits.c) at line 150 +'eventRegisterSide' at /domains/oogtopia/doors/airlock (/lib/door.c) at line 241 + +--- Zebu +2020.09.05-23.12,53 +*call_other() couldn't find object +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_go_str' at /verbs/rooms/go at line 45 +'eventGo' at /domains/voluntaria/room/airlock (/lib/exits.c) at line 107 +'eventMoveLiving' at /secure/save/creators/b/babylon (/lib/living.c) at line 794 +'eventDescribeEnvironment' at /secure/save/creators/b/babylon (/lib/creator.c) at line 116 +'eventDescribeEnvironment' at /secure/save/creators/b/babylon (/lib/events/describe.c) at line 120 +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'(: <code>($1) :)' at /secure/save/creators/b/babylon (/lib/events/describe.c) at line 119 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.05-23.14,20 +*call_other() couldn't find object +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_go_str' at /verbs/rooms/go at line 45 +'eventGo' at /domains/voluntaria/room/airlock (/lib/exits.c) at line 107 +'eventMoveLiving' at /secure/save/creators/b/babylon (/lib/living.c) at line 794 +'eventDescribeEnvironment' at /secure/save/creators/b/babylon (/lib/creator.c) at line 116 +'eventDescribeEnvironment' at /secure/save/creators/b/babylon (/lib/events/describe.c) at line 120 +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'(: <code>($1) :)' at /secure/save/creators/b/babylon (/lib/events/describe.c) at line 119 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.05-23.14,34 +*call_other() couldn't find object +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_look' at /verbs/items/look at line 96 +'eventDescribeEnvironment' at /secure/save/creators/b/babylon (/lib/creator.c) at line 116 +'eventDescribeEnvironment' at /secure/save/creators/b/babylon (/lib/events/describe.c) at line 120 +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'(: <code>($1) :)' at /secure/save/creators/b/babylon (/lib/events/describe.c) at line 119 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.05-23.14,45 +*call_other() couldn't find object +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'heart_beat' at /domains/oogtopia/npc/party_ooga#385 (/lib/sentient.c) at line 460 +'eventWander' at /domains/oogtopia/npc/party_ooga#385 (/lib/sentient.c) at line 423 +'eventForce' at /domains/oogtopia/npc/party_ooga#385 (/lib/command.c) at line 314 +'CATCH' at /domains/oogtopia/npc/party_ooga#385 (/lib/command.c) at line 314 +'<fake>' at /domains/oogtopia/npc/party_ooga#385 (/<driver>) at line 0 +'cmdAll' at /domains/oogtopia/npc/party_ooga#385 (/lib/npc.c) at line 201 +'cmdAll' at /domains/oogtopia/npc/party_ooga#385 (/lib/command.c) at line 210 +'do_go_str' at /verbs/rooms/go at line 45 +'eventGo' at /domains/voluntaria/room/airlock (/lib/exits.c) at line 107 +'eventMoveLiving' at /domains/oogtopia/npc/party_ooga#385 (/lib/living.c) at line 794 +'eventDescribeEnvironment' at /domains/oogtopia/npc/party_ooga#385 (/lib/events/describe.c) at line 120 +'<fake>' at /domains/oogtopia/npc/party_ooga#385 (/<driver>) at line 0 +'(: <code>($1) :)' at /domains/oogtopia/npc/party_ooga#385 (/lib/events/describe.c) at line 119 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.05-23.14,45 +*Bad argument 1 to call_other() +Expected: string or array or object Got: 0. +Object: /domains/oogtopia/npc/party_ooga#385 (/lib/events/describe.c) at line 119 + +'heart_beat' at /domains/oogtopia/npc/party_ooga#385 (/lib/sentient.c) at line 460 +'eventWander' at /domains/oogtopia/npc/party_ooga#385 (/lib/sentient.c) at line 423 +'eventForce' at /domains/oogtopia/npc/party_ooga#385 (/lib/command.c) at line 314 +'CATCH' at /domains/oogtopia/npc/party_ooga#385 (/lib/command.c) at line 314 +'<fake>' at /domains/oogtopia/npc/party_ooga#385 (/<driver>) at line 0 +'cmdAll' at /domains/oogtopia/npc/party_ooga#385 (/lib/npc.c) at line 201 +'cmdAll' at /domains/oogtopia/npc/party_ooga#385 (/lib/command.c) at line 210 +'do_go_str' at /verbs/rooms/go at line 45 +'eventGo' at /domains/voluntaria/room/airlock (/lib/exits.c) at line 107 +'eventMoveLiving' at /domains/oogtopia/npc/party_ooga#385 (/lib/living.c) at line 794 +'eventDescribeEnvironment' at /domains/oogtopia/npc/party_ooga#385 (/lib/events/describe.c) at line 120 +'<fake>' at /domains/oogtopia/npc/party_ooga#385 (/<driver>) at line 0 +'(: <code>($1) :)' at /domains/oogtopia/npc/party_ooga#385 (/lib/events/describe.c) at line 119 + +--- Zebu +2020.09.05-23.15,22 +*call_other() couldn't find object +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/goto at line 68 +'eventMoveLiving' at /secure/save/creators/b/babylon (/lib/living.c) at line 794 +'eventDescribeEnvironment' at /secure/save/creators/b/babylon (/lib/creator.c) at line 116 +'eventDescribeEnvironment' at /secure/save/creators/b/babylon (/lib/events/describe.c) at line 120 +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'(: <code>($1) :)' at /secure/save/creators/b/babylon (/lib/events/describe.c) at line 119 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.05-23.16,26 +*call_other() couldn't find object +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_go_str' at /verbs/rooms/go at line 45 +'eventGo' at /domains/voluntaria/room/airlock (/lib/exits.c) at line 107 +'eventMoveLiving' at /secure/save/creators/b/babylon (/lib/living.c) at line 794 +'eventDescribeEnvironment' at /secure/save/creators/b/babylon (/lib/creator.c) at line 116 +'eventDescribeEnvironment' at /secure/save/creators/b/babylon (/lib/events/describe.c) at line 120 +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'(: <code>($1) :)' at /secure/save/creators/b/babylon (/lib/events/describe.c) at line 119 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.05-23.22,14 +*call_other() couldn't find object +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 210 +'do_go_str' at /verbs/rooms/go at line 45 +'eventGo' at /domains/voluntaria/room/airlock (/lib/exits.c) at line 107 +'eventMoveLiving' at /secure/save/creators/b/babylon (/lib/living.c) at line 794 +'eventDescribeEnvironment' at /secure/save/creators/b/babylon (/lib/creator.c) at line 116 +'eventDescribeEnvironment' at /secure/save/creators/b/babylon (/lib/events/describe.c) at line 120 +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'(: <code>($1) :)' at /secure/save/creators/b/babylon (/lib/events/describe.c) at line 119 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.05-23.39,32 +*Error in loading object '/domains/voluntaria/room/airlock' +Object: /secure/cmds/creators/update at line 170 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 85 +'CATCH' at /secure/cmds/creators/update at line 85 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 + +--- Zebu +2020.09.05-23.39,32 +*Error in loading object '/domains/voluntaria/room/airlock' +Object: /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 92 +'ReturnAndRelease' at /secure/cmds/creators/update at line 37 +'eventMove' at /secure/save/creators/b/babylon (/lib/creator.c) at line 266 +'eventMove' at /secure/save/creators/b/babylon (/lib/player.c) at line 287 +'eventMove' at /secure/save/creators/b/babylon (/lib/interactive.c) at line 255 +'eventMove' at /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 +'CATCH' at /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.05-23.47,13 +*Error in loading object '/domains/voluntaria/room/airlock' +Object: /secure/cmds/creators/update at line 170 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 85 +'CATCH' at /secure/cmds/creators/update at line 85 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 + +--- Zebu +2020.09.05-23.47,13 +*Error in loading object '/domains/voluntaria/room/airlock' +Object: /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 92 +'ReturnAndRelease' at /secure/cmds/creators/update at line 37 +'eventMove' at /secure/save/creators/b/babylon (/lib/creator.c) at line 266 +'eventMove' at /secure/save/creators/b/babylon (/lib/player.c) at line 287 +'eventMove' at /secure/save/creators/b/babylon (/lib/interactive.c) at line 255 +'eventMove' at /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 +'CATCH' at /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-00.05,57 +*Error in loading object '/domains/voluntaria/room/bridge' +Object: /secure/cmds/creators/update at line 170 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 85 +'CATCH' at /secure/cmds/creators/update at line 85 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 + +--- Zebu +2020.09.06-00.05,57 +*Error in loading object '/domains/voluntaria/room/bridge' +Object: /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 92 +'ReturnAndRelease' at /secure/cmds/creators/update at line 37 +'eventMove' at /secure/save/creators/b/babylon (/lib/creator.c) at line 266 +'eventMove' at /secure/save/creators/b/babylon (/lib/player.c) at line 287 +'eventMove' at /secure/save/creators/b/babylon (/lib/interactive.c) at line 255 +'eventMove' at /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 +'CATCH' at /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-00.08,28 +*Error in loading object '/domains/voluntaria/room/bridge' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/goto at line 63 +'CATCH' at /secure/cmds/creators/goto at line 63 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.06-00.09,26 +*Error in loading object '/domains/voluntaria/room/bridge' +Object: /secure/cmds/creators/update at line 170 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 85 +'CATCH' at /secure/cmds/creators/update at line 85 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 + +--- Zebu +2020.09.06-00.09,26 +*Error in loading object '/domains/voluntaria/room/bridge' +Object: /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 92 +'ReturnAndRelease' at /secure/cmds/creators/update at line 37 +'eventMove' at /secure/save/creators/b/babylon (/lib/creator.c) at line 266 +'eventMove' at /secure/save/creators/b/babylon (/lib/player.c) at line 287 +'eventMove' at /secure/save/creators/b/babylon (/lib/interactive.c) at line 255 +'eventMove' at /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 +'CATCH' at /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-00.16,41 +*Error in loading object '/domains/voluntaria/room/bridge' +Object: /secure/cmds/creators/update at line 170 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 85 +'CATCH' at /secure/cmds/creators/update at line 85 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 + +--- Zebu +2020.09.06-00.16,41 +*Error in loading object '/domains/voluntaria/room/bridge' +Object: /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 92 +'ReturnAndRelease' at /secure/cmds/creators/update at line 37 +'eventMove' at /secure/save/creators/b/babylon (/lib/creator.c) at line 266 +'eventMove' at /secure/save/creators/b/babylon (/lib/player.c) at line 287 +'eventMove' at /secure/save/creators/b/babylon (/lib/interactive.c) at line 255 +'eventMove' at /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 +'CATCH' at /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-00.17,45 +*Error in loading object '/domains/voluntaria/room/bridge' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/goto at line 63 +'CATCH' at /secure/cmds/creators/goto at line 63 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.06-00.18,46 +*Error in loading object '/domains/voluntaria/room/bridge' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/goto at line 63 +'CATCH' at /secure/cmds/creators/goto at line 63 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +END-OF-LOG diff --git a/lib/log/archive/foo.txt b/lib/log/archive/foo.txt new file mode 100644 index 0000000..27afd21 --- /dev/null +++ b/lib/log/archive/foo.txt @@ -0,0 +1 @@ +This file intentionally left blank. diff --git a/lib/log/author_stats b/lib/log/author_stats new file mode 100644 index 0000000..1876e23 --- /dev/null +++ b/lib/log/author_stats @@ -0,0 +1 @@ +NONAME 0 0 diff --git a/lib/log/catch b/lib/log/catch new file mode 100644 index 0000000..18c2f4b --- /dev/null +++ b/lib/log/catch @@ -0,0 +1,658 @@ +NEW_LOG 2020.09.06-00.32,57 + +--- Zebu +2020.09.06-04.12,43 +*Value being indexed is zero. +Object: /domains/voluntaria/doors/airlock (/lib/door.c) at line 241 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 85 +'CATCH' at /secure/cmds/creators/update at line 85 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 +'create' at /domains/oogtopia/room/field at line 26 +'SetDoor' at /domains/oogtopia/room/field (/lib/exits.c) at line 150 +'eventRegisterSide' at /domains/voluntaria/doors/airlock (/lib/door.c) at line 241 + +--- Zebu +2020.09.06-04.13,47 +*Value being indexed is zero. +Object: /domains/voluntaria/doors/airlock (/lib/door.c) at line 241 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 85 +'CATCH' at /secure/cmds/creators/update at line 85 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 +'create' at /domains/oogtopia/room/field at line 26 +'SetDoor' at /domains/oogtopia/room/field (/lib/exits.c) at line 150 +'eventRegisterSide' at /domains/voluntaria/doors/airlock (/lib/door.c) at line 241 + +--- Zebu +2020.09.06-04.17,35 +*Error in loading object '/domains/voluntaria/room/bridge' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/goto at line 63 +'CATCH' at /secure/cmds/creators/goto at line 63 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.06-04.20,26 +*Error in loading object '/domains/voluntaria/room/bridge' +Object: /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/goto at line 63 +'CATCH' at /secure/cmds/creators/goto at line 63 +'load_object' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 +'CATCH' at /secure/sefun/sefun at /secure/sefun/load_object.c:35 + +--- Zebu +2020.09.06-04.53,14 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#531 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#372 at line 111 +'eventSpawn' at /domains/default/npc/drone3#372 at line 103 +'CATCH' at /domains/default/npc/drone3#372 at line 103 +'eventMove' at /domains/default/npc/drone3#531 at line 58 +'eventMove' at /domains/default/npc/drone3#531 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#531 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#531 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#531 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.53,14 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#536 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#406 at line 111 +'eventSpawn' at /domains/default/npc/drone3#406 at line 103 +'CATCH' at /domains/default/npc/drone3#406 at line 103 +'eventMove' at /domains/default/npc/drone3#536 at line 58 +'eventMove' at /domains/default/npc/drone3#536 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#536 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#536 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#536 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.53,14 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#537 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#407 at line 111 +'eventSpawn' at /domains/default/npc/drone3#407 at line 103 +'CATCH' at /domains/default/npc/drone3#407 at line 103 +'eventMove' at /domains/default/npc/drone3#537 at line 58 +'eventMove' at /domains/default/npc/drone3#537 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#537 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#537 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#537 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.53,14 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#552 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#420 at line 111 +'eventSpawn' at /domains/default/npc/drone3#420 at line 103 +'CATCH' at /domains/default/npc/drone3#420 at line 103 +'eventMove' at /domains/default/npc/drone3#552 at line 58 +'eventMove' at /domains/default/npc/drone3#552 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#552 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#552 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#552 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.53,14 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#553 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#421 at line 111 +'eventSpawn' at /domains/default/npc/drone3#421 at line 103 +'CATCH' at /domains/default/npc/drone3#421 at line 103 +'eventMove' at /domains/default/npc/drone3#553 at line 58 +'eventMove' at /domains/default/npc/drone3#553 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#553 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#553 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#553 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.53,14 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#560 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#432 at line 111 +'eventSpawn' at /domains/default/npc/drone3#432 at line 103 +'CATCH' at /domains/default/npc/drone3#432 at line 103 +'eventMove' at /domains/default/npc/drone3#560 at line 58 +'eventMove' at /domains/default/npc/drone3#560 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#560 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#560 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#560 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.53,14 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#561 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#433 at line 111 +'eventSpawn' at /domains/default/npc/drone3#433 at line 103 +'CATCH' at /domains/default/npc/drone3#433 at line 103 +'eventMove' at /domains/default/npc/drone3#561 at line 58 +'eventMove' at /domains/default/npc/drone3#561 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#561 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#561 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#561 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.53,14 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#583 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#441 at line 111 +'eventSpawn' at /domains/default/npc/drone3#441 at line 103 +'CATCH' at /domains/default/npc/drone3#441 at line 103 +'eventMove' at /domains/default/npc/drone3#583 at line 58 +'eventMove' at /domains/default/npc/drone3#583 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#583 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#583 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#583 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.53,14 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#593 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#451 at line 111 +'eventSpawn' at /domains/default/npc/drone3#451 at line 103 +'CATCH' at /domains/default/npc/drone3#451 at line 103 +'eventMove' at /domains/default/npc/drone3#593 at line 58 +'eventMove' at /domains/default/npc/drone3#593 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#593 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#593 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#593 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.53,14 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#594 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#452 at line 111 +'eventSpawn' at /domains/default/npc/drone3#452 at line 103 +'CATCH' at /domains/default/npc/drone3#452 at line 103 +'eventMove' at /domains/default/npc/drone3#594 at line 58 +'eventMove' at /domains/default/npc/drone3#594 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#594 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#594 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#594 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.53,14 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#599 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#459 at line 111 +'eventSpawn' at /domains/default/npc/drone3#459 at line 103 +'CATCH' at /domains/default/npc/drone3#459 at line 103 +'eventMove' at /domains/default/npc/drone3#599 at line 58 +'eventMove' at /domains/default/npc/drone3#599 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#599 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#599 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#599 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.53,14 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#602 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#466 at line 111 +'eventSpawn' at /domains/default/npc/drone3#466 at line 103 +'CATCH' at /domains/default/npc/drone3#466 at line 103 +'eventMove' at /domains/default/npc/drone3#602 at line 58 +'eventMove' at /domains/default/npc/drone3#602 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#602 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#602 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#602 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.53,41 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#995 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#879 at line 111 +'eventSpawn' at /domains/default/npc/drone3#879 at line 103 +'CATCH' at /domains/default/npc/drone3#879 at line 103 +'eventMove' at /domains/default/npc/drone3#995 at line 58 +'eventMove' at /domains/default/npc/drone3#995 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#995 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#995 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#995 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.53,41 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#996 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#911 at line 111 +'eventSpawn' at /domains/default/npc/drone3#911 at line 103 +'CATCH' at /domains/default/npc/drone3#911 at line 103 +'eventMove' at /domains/default/npc/drone3#996 at line 58 +'eventMove' at /domains/default/npc/drone3#996 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#996 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#996 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#996 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.53,41 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#999 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#918 at line 111 +'eventSpawn' at /domains/default/npc/drone3#918 at line 103 +'CATCH' at /domains/default/npc/drone3#918 at line 103 +'eventMove' at /domains/default/npc/drone3#999 at line 58 +'eventMove' at /domains/default/npc/drone3#999 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#999 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#999 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#999 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.53,41 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1000 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#919 at line 111 +'eventSpawn' at /domains/default/npc/drone3#919 at line 103 +'CATCH' at /domains/default/npc/drone3#919 at line 103 +'eventMove' at /domains/default/npc/drone3#1000 at line 58 +'eventMove' at /domains/default/npc/drone3#1000 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1000 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1000 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1000 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.53,41 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1005 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#925 at line 111 +'eventSpawn' at /domains/default/npc/drone3#925 at line 103 +'CATCH' at /domains/default/npc/drone3#925 at line 103 +'eventMove' at /domains/default/npc/drone3#1005 at line 58 +'eventMove' at /domains/default/npc/drone3#1005 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1005 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1005 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1005 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.53,41 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1006 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#926 at line 111 +'eventSpawn' at /domains/default/npc/drone3#926 at line 103 +'CATCH' at /domains/default/npc/drone3#926 at line 103 +'eventMove' at /domains/default/npc/drone3#1006 at line 58 +'eventMove' at /domains/default/npc/drone3#1006 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1006 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1006 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1006 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.53,41 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1012 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#932 at line 111 +'eventSpawn' at /domains/default/npc/drone3#932 at line 103 +'CATCH' at /domains/default/npc/drone3#932 at line 103 +'eventMove' at /domains/default/npc/drone3#1012 at line 58 +'eventMove' at /domains/default/npc/drone3#1012 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1012 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1012 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1012 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.53,41 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1015 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#942 at line 111 +'eventSpawn' at /domains/default/npc/drone3#942 at line 103 +'CATCH' at /domains/default/npc/drone3#942 at line 103 +'eventMove' at /domains/default/npc/drone3#1015 at line 58 +'eventMove' at /domains/default/npc/drone3#1015 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1015 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1015 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1015 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.53,41 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1016 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#943 at line 111 +'eventSpawn' at /domains/default/npc/drone3#943 at line 103 +'CATCH' at /domains/default/npc/drone3#943 at line 103 +'eventMove' at /domains/default/npc/drone3#1016 at line 58 +'eventMove' at /domains/default/npc/drone3#1016 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1016 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1016 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1016 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.53,41 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1018 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#950 at line 111 +'eventSpawn' at /domains/default/npc/drone3#950 at line 103 +'CATCH' at /domains/default/npc/drone3#950 at line 103 +'eventMove' at /domains/default/npc/drone3#1018 at line 58 +'eventMove' at /domains/default/npc/drone3#1018 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1018 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1018 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1018 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.53,41 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1021 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#954 at line 111 +'eventSpawn' at /domains/default/npc/drone3#954 at line 103 +'CATCH' at /domains/default/npc/drone3#954 at line 103 +'eventMove' at /domains/default/npc/drone3#1021 at line 58 +'eventMove' at /domains/default/npc/drone3#1021 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1021 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1021 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1021 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.54,08 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1173 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#1057 at line 111 +'eventSpawn' at /domains/default/npc/drone3#1057 at line 103 +'CATCH' at /domains/default/npc/drone3#1057 at line 103 +'eventMove' at /domains/default/npc/drone3#1173 at line 58 +'eventMove' at /domains/default/npc/drone3#1173 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1173 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1173 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1173 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.54,08 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1178 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#1088 at line 111 +'eventSpawn' at /domains/default/npc/drone3#1088 at line 103 +'CATCH' at /domains/default/npc/drone3#1088 at line 103 +'eventMove' at /domains/default/npc/drone3#1178 at line 58 +'eventMove' at /domains/default/npc/drone3#1178 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1178 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1178 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1178 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.54,08 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1179 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#1089 at line 111 +'eventSpawn' at /domains/default/npc/drone3#1089 at line 103 +'CATCH' at /domains/default/npc/drone3#1089 at line 103 +'eventMove' at /domains/default/npc/drone3#1179 at line 58 +'eventMove' at /domains/default/npc/drone3#1179 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1179 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1179 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1179 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.54,08 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1182 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#1096 at line 111 +'eventSpawn' at /domains/default/npc/drone3#1096 at line 103 +'CATCH' at /domains/default/npc/drone3#1096 at line 103 +'eventMove' at /domains/default/npc/drone3#1182 at line 58 +'eventMove' at /domains/default/npc/drone3#1182 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1182 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1182 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1182 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.54,08 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1183 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#1097 at line 111 +'eventSpawn' at /domains/default/npc/drone3#1097 at line 103 +'CATCH' at /domains/default/npc/drone3#1097 at line 103 +'eventMove' at /domains/default/npc/drone3#1183 at line 58 +'eventMove' at /domains/default/npc/drone3#1183 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1183 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1183 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1183 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.54,08 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1188 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#1103 at line 111 +'eventSpawn' at /domains/default/npc/drone3#1103 at line 103 +'CATCH' at /domains/default/npc/drone3#1103 at line 103 +'eventMove' at /domains/default/npc/drone3#1188 at line 58 +'eventMove' at /domains/default/npc/drone3#1188 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1188 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1188 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1188 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.54,08 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1189 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#1104 at line 111 +'eventSpawn' at /domains/default/npc/drone3#1104 at line 103 +'CATCH' at /domains/default/npc/drone3#1104 at line 103 +'eventMove' at /domains/default/npc/drone3#1189 at line 58 +'eventMove' at /domains/default/npc/drone3#1189 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1189 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1189 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1189 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.54,08 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1195 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#1110 at line 111 +'eventSpawn' at /domains/default/npc/drone3#1110 at line 103 +'CATCH' at /domains/default/npc/drone3#1110 at line 103 +'eventMove' at /domains/default/npc/drone3#1195 at line 58 +'eventMove' at /domains/default/npc/drone3#1195 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1195 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1195 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1195 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.54,08 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1198 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#1120 at line 111 +'eventSpawn' at /domains/default/npc/drone3#1120 at line 103 +'CATCH' at /domains/default/npc/drone3#1120 at line 103 +'eventMove' at /domains/default/npc/drone3#1198 at line 58 +'eventMove' at /domains/default/npc/drone3#1198 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1198 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1198 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1198 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.54,08 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1199 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#1121 at line 111 +'eventSpawn' at /domains/default/npc/drone3#1121 at line 103 +'CATCH' at /domains/default/npc/drone3#1121 at line 103 +'eventMove' at /domains/default/npc/drone3#1199 at line 58 +'eventMove' at /domains/default/npc/drone3#1199 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1199 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1199 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1199 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.54,08 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1201 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#1128 at line 111 +'eventSpawn' at /domains/default/npc/drone3#1128 at line 103 +'CATCH' at /domains/default/npc/drone3#1128 at line 103 +'eventMove' at /domains/default/npc/drone3#1201 at line 58 +'eventMove' at /domains/default/npc/drone3#1201 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1201 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1201 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1201 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.54,08 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#1204 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#1132 at line 111 +'eventSpawn' at /domains/default/npc/drone3#1132 at line 103 +'CATCH' at /domains/default/npc/drone3#1132 at line 103 +'eventMove' at /domains/default/npc/drone3#1204 at line 58 +'eventMove' at /domains/default/npc/drone3#1204 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#1204 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#1204 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#1204 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.54,48 +*Cannot index type 'int' using [ .. ] operator. +Object: /secure/sefun/sefun at /secure/sefun/strings.c:520 + +'heart_beat' at /domains/default/npc/drone3#1996 at line 111 +'eventSpawn' at /domains/default/npc/drone3#1996 at line 103 +'CATCH' at /domains/default/npc/drone3#1996 at line 103 +'eventMove' at /domains/default/npc/drone3#2434 at line 58 +'eventMove' at /domains/default/npc/drone3#2434 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#2434 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#2434 (/lib/props/move.c) at line 123 +'init' at /domains/Praxis/wall at line 11 +'init' at /domains/Praxis/wall (/lib/std/room.c) at line 1343 +'SetRoom' at /secure/daemon/rooms at line 443 +'path_prefix' at /secure/sefun/sefun at /secure/sefun/strings.c:520 + +--- Zebu +2020.09.06-04.55,08 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#2809 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#2658 at line 111 +'eventSpawn' at /domains/default/npc/drone3#2658 at line 103 +'CATCH' at /domains/default/npc/drone3#2658 at line 103 +'eventMove' at /domains/default/npc/drone3#2809 at line 58 +'eventMove' at /domains/default/npc/drone3#2809 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#2809 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#2809 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#2809 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.55,18 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#3076 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#2788 at line 111 +'eventSpawn' at /domains/default/npc/drone3#2788 at line 103 +'CATCH' at /domains/default/npc/drone3#2788 at line 103 +'eventMove' at /domains/default/npc/drone3#3076 at line 58 +'eventMove' at /domains/default/npc/drone3#3076 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#3076 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#3076 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#3076 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.55,38 +*call_other() couldn't find object +Object: /domains/default/npc/drone3#3455 (/lib/props/move.c) at line 88 + +'heart_beat' at /domains/default/npc/drone3#3198 at line 111 +'eventSpawn' at /domains/default/npc/drone3#3198 at line 103 +'CATCH' at /domains/default/npc/drone3#3198 at line 103 +'eventMove' at /domains/default/npc/drone3#3455 at line 58 +'eventMove' at /domains/default/npc/drone3#3455 (/lib/npc.c) at line 309 +'eventCompleteMove' at /domains/default/npc/drone3#3455 (/lib/npc.c) at line 212 +'eventMove' at /domains/default/npc/drone3#3455 (/lib/props/move.c) at line 88 +'CATCH' at /domains/default/npc/drone3#3455 (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-04.59,31 +*Error in loading object '/domains/voluntaria/room/start' +Object: /secure/cmds/creators/update at line 170 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 85 +'CATCH' at /secure/cmds/creators/update at line 85 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 + +--- Zebu +2020.09.06-04.59,31 +*Error in loading object '/domains/voluntaria/room/start' +Object: /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 92 +'ReturnAndRelease' at /secure/cmds/creators/update at line 37 +'eventMove' at /secure/save/creators/b/babylon (/lib/creator.c) at line 266 +'eventMove' at /secure/save/creators/b/babylon (/lib/player.c) at line 287 +'eventMove' at /secure/save/creators/b/babylon (/lib/interactive.c) at line 255 +'eventMove' at /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 +'CATCH' at /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 + +--- Zebu +2020.09.06-05.06,22 +*Error in loading object '/domains/voluntaria/room/start' +Object: /secure/cmds/creators/update at line 170 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 85 +'CATCH' at /secure/cmds/creators/update at line 85 +'eventUpdate' at /secure/cmds/creators/update at line 170 +'CATCH' at /secure/cmds/creators/update at line 170 + +--- Zebu +2020.09.06-05.06,22 +*Error in loading object '/domains/voluntaria/room/start' +Object: /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 + +'<fake>' at /secure/save/creators/b/babylon (/<driver>) at line 0 +'cmdAll' at /secure/save/creators/b/babylon (/lib/command.c) at line 231 +'cmd' at /secure/cmds/creators/update at line 92 +'ReturnAndRelease' at /secure/cmds/creators/update at line 37 +'eventMove' at /secure/save/creators/b/babylon (/lib/creator.c) at line 266 +'eventMove' at /secure/save/creators/b/babylon (/lib/player.c) at line 287 +'eventMove' at /secure/save/creators/b/babylon (/lib/interactive.c) at line 255 +'eventMove' at /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 +'CATCH' at /secure/save/creators/b/babylon (/lib/props/move.c) at line 88 diff --git a/lib/log/chan/connections b/lib/log/chan/connections new file mode 100644 index 0000000..f465db8 --- /dev/null +++ b/lib/log/chan/connections @@ -0,0 +1,19 @@ +[2020.09.01-19.51,38] SYSTEM <connections> [Babylon quits Dead_Souls_babylon] +[2020.09.01-21.52,31] SYSTEM <connections> [Babylon quits Dead_Souls_babylon] +[2020.09.01-22.48,22] SYSTEM <connections> [DeskarNull quits Dead_Souls_babylon] +[2020.09.01-23.06,50] SYSTEM <connections> [Fluffster logs into Dead_Souls_babylon] +[2020.09.01-23.36,37] SYSTEM <connections> [DeskarNull logs into Dead_Souls_babylon] +[2020.09.01-23.47,05] SYSTEM <connections> [Babylon quits Dead_Souls_babylon] +[2020.09.02-22.08,40] SYSTEM <connections> [DeskarNull logs into Zebu] +[2020.09.02-22.09,05] SYSTEM <connections> [DeskarNull quits Zebu] +[2020.09.02-22.10,31] SYSTEM <connections> [Babylon quits Zebu] +[2020.09.03-05.46,28] SYSTEM <connections> [Babylon quits Zebu] +[2020.09.04-20.17,49] SYSTEM <connections> [DeskarNull logs into Zebu] +[2020.09.04-20.18,43] SYSTEM <connections> [DeskarNull quits Zebu] +[2020.09.04-21.36,43] SYSTEM <connections> [Babylon quits Zebu] +[2020.09.05-22.51,05] SYSTEM <connections> [Bumble logs into Zebu] +[2020.09.05-22.55,12] SYSTEM <connections> [Bumble quits Zebu] +[2020.09.05-23.50,09] SYSTEM <connections> [Gumpy logs into Zebu] +[2020.09.06-00.05,35] SYSTEM <connections> [Gumpy quits Zebu] +[2020.09.06-02.15,37] SYSTEM <connections> [Babylon quits Zebu] +[2020.09.06-04.15,21] SYSTEM <connections> [Babylon quits Zebu] diff --git a/lib/log/chan/foo.txt b/lib/log/chan/foo.txt new file mode 100644 index 0000000..27afd21 --- /dev/null +++ b/lib/log/chan/foo.txt @@ -0,0 +1 @@ +This file intentionally left blank. diff --git a/lib/log/chan/intermud b/lib/log/chan/intermud new file mode 100644 index 0000000..9e418bd --- /dev/null +++ b/lib/log/chan/intermud @@ -0,0 +1 @@ +[2020.09.01-23.20,25] SYSTEM <intermud> [Shadyman@QS fingers Babylon] diff --git a/lib/log/currency b/lib/log/currency new file mode 100644 index 0000000..5ba2b1b --- /dev/null +++ b/lib/log/currency @@ -0,0 +1,2 @@ +Babylon received 99 silver Wed Sep 02 00:47:31 2020 +({ OBJ(pile /lib/pile#134), OBJ(babylon /lib/std/corpse#133), OBJ(/verbs/items/get), OBJ(babylon /secure/save/creators/b/babylon) }) diff --git a/lib/log/domain_stats b/lib/log/domain_stats new file mode 100644 index 0000000..a4950ed --- /dev/null +++ b/lib/log/domain_stats @@ -0,0 +1,7 @@ +Praxis 0 0 +campus 0 269 +Ylsrim 0 0 +default 0 416 +town 0 94 +BACKBONE 0 0 +NONAME 0 645 diff --git a/lib/log/enter b/lib/log/enter new file mode 100644 index 0000000..2be6f18 --- /dev/null +++ b/lib/log/enter @@ -0,0 +1,35 @@ +Babylon (enter): Wed Sep 02 00:19:38 2020 +Babylon (quit): 2020.09.01-19.51,38 +DeskarNull (enter): Wed Sep 02 01:00:37 2020 +DeskarNull (quit): 2020.09.01-20.21,15 +Babylon (enter): Wed Sep 02 01:25:14 2020 +Babylon (quit): 2020.09.01-21.52,31 +DeskarNull (enter): Wed Sep 02 02:57:06 2020 +Babylon (enter): Wed Sep 02 03:04:11 2020 +DeskarNull (quit): 2020.09.01-22.48,22 +Fluffster (enter): Wed Sep 02 04:06:50 2020 +DeskarNull (enter): Wed Sep 02 04:36:37 2020 +Babylon (quit): 2020.09.01-23.47,05 +Fluffster (quit): 2020.09.01-23.47,14 +DeskarNull (quit): 2020.09.01-23.47,19 +Babylon (enter): Wed Sep 02 20:17:54 2020 +DeskarNull (enter): Wed Sep 02 22:08:40 2020 +DeskarNull (quit): 2020.09.02-22.09,05 +Babylon (quit): 2020.09.02-22.10,31 +Babylon (enter): Wed Sep 02 22:14:00 2020 +Babylon (enter): Thu Sep 03 01:17:50 2020 +Babylon (quit): 2020.09.03-05.46,28 +Babylon (enter): Fri Sep 04 19:14:06 2020 +DeskarNull (enter): Fri Sep 04 20:17:49 2020 +DeskarNull (quit): 2020.09.04-20.18,43 +Babylon (quit): 2020.09.04-21.36,43 +Babylon (enter): Sat Sep 05 21:32:34 2020 +Bumble (enter): Sat Sep 05 22:51:05 2020 +Bumble (quit): 2020.09.05-22.55,12 +Gumpy (enter): Sat Sep 05 23:50:09 2020 +Gumpy (quit): 2020.09.06-00.05,35 +Babylon (quit): 2020.09.06-02.15,37 +Babylon (enter): Sun Sep 06 03:23:22 2020 +Babylon (quit): 2020.09.06-04.15,21 +Babylon (enter): Sun Sep 06 04:15:56 2020 +Babylon (enter): Sun Sep 06 04:26:37 2020 diff --git a/lib/log/errors/babylon b/lib/log/errors/babylon new file mode 100644 index 0000000..28ebc6e --- /dev/null +++ b/lib/log/errors/babylon @@ -0,0 +1,4 @@ +2020.09.03-05.08,16 /realms/babylon/tmp/party_oogahnlihdbf1599134896.c line 21: Undefined function SetWanderSpeed +2020.09.03-05.22,46 /realms/babylon/tmp/party_oogaiookbigo1599135766.c line 30: Undefined function SetWanderSpeed +2020.09.03-05.23,46 /realms/babylon/tmp/party_oogaffajhmbd1599135826.c line 21: Undefined function SetWanderSpeed +2020.09.03-05.31,23 /realms/babylon/tmp/party_oogancllhlfn1599136283.c line 21: Undefined function SetWanderSpeed diff --git a/lib/log/errors/daemon b/lib/log/errors/daemon new file mode 100644 index 0000000..7a48b4e --- /dev/null +++ b/lib/log/errors/daemon @@ -0,0 +1,2 @@ +2020.09.04-20.09,27 /daemon/tmp/1,1,1.c line 85: Invalid macro name +2020.09.04-20.09,27 /daemon/tmp/1,1,1.c line 85: Illegal macro symbol diff --git a/lib/log/errors/foo.txt b/lib/log/errors/foo.txt new file mode 100644 index 0000000..27afd21 --- /dev/null +++ b/lib/log/errors/foo.txt @@ -0,0 +1 @@ +This file intentionally left blank. diff --git a/lib/log/errors/oogtopia b/lib/log/errors/oogtopia new file mode 100644 index 0000000..3e21729 --- /dev/null +++ b/lib/log/errors/oogtopia @@ -0,0 +1,44 @@ +2020.09.03-01.48,19 /domains/oogtopia/room/start.c line 31: syntax error +2020.09.03-01.48,19 /domains/oogtopia/room/start.c line 31: syntax error +2020.09.03-04.12,13 /domains/oogtopia/room/start.c line 28: syntax error +2020.09.03-04.12,13 /domains/oogtopia/room/start.c line 28: syntax error +2020.09.03-04.12,13 /domains/oogtopia/room/start.c line 28: syntax error +2020.09.03-04.12,23 /domains/oogtopia/room/start.c line 28: syntax error +2020.09.03-04.12,44 /domains/oogtopia/room/start.c line 28: syntax error +2020.09.03-04.14,30 /domains/oogtopia/room/start.c line 28: syntax error +2020.09.03-04.16,48 /domains/oogtopia/room/start.c line 28: syntax error +2020.09.03-04.17,34 /domains/oogtopia/room/start.c line 28: syntax error +2020.09.03-04.17,34 /domains/oogtopia/room/start.c line 28: syntax error +2020.09.03-04.17,44 /domains/oogtopia/room/start.c line 28: syntax error +2020.09.03-04.17,44 /domains/oogtopia/room/start.c line 28: syntax error +2020.09.03-04.17,54 /domains/oogtopia/room/start.c line 28: syntax error +2020.09.03-04.18,19 /domains/oogtopia/room/start.c line 28: syntax error +2020.09.03-04.18,27 /domains/oogtopia/room/start.c line 28: syntax error +2020.09.03-04.18,27 /domains/oogtopia/room/start.c line 28: syntax error +2020.09.03-04.18,32 /domains/oogtopia/room/start.c line 28: syntax error +2020.09.03-04.18,37 /domains/oogtopia/room/start.c line 28: syntax error +2020.09.03-04.18,44 /domains/oogtopia/room/start.c line 28: syntax error +2020.09.03-04.20,44 /domains/oogtopia/room/start.c line 28: syntax error +2020.09.03-04.20,46 /domains/oogtopia/room/start.c line 28: syntax error +2020.09.03-04.20,49 /domains/oogtopia/room/start.c line 28: syntax error +2020.09.03-04.20,52 /domains/oogtopia/room/start.c line 28: syntax error +2020.09.03-04.21,27 /domains/oogtopia/room/start.c line 28: syntax error +2020.09.03-04.46,59 /domains/oogtopia/room/start.c line 16: syntax error +2020.09.03-04.46,59 /domains/oogtopia/room/start.c line 16: syntax error +2020.09.03-05.16,19 /domains/oogtopia/npc/party_ooga.c line 29: Undefined function SetWanderSpeed +2020.09.03-05.16,53 /domains/oogtopia/npc/party_ooga.c line 29: Undefined function SetWanderSpeed +2020.09.03-05.19,56 /domains/oogtopia/npc/party_ooga.c line 29: Undefined function SetWanderSpeed +2020.09.03-05.22,03 /domains/oogtopia/npc/party_ooga.c line 30: Undefined function SetWanderSpeed +2020.09.03-05.23,14 /domains/oogtopia/npc/party_ooga.c line 30: Undefined function SetWanderSpeed +2020.09.03-05.25,19 /domains/oogtopia/npc/party_ooga.c line 21: Undefined function SetWanderSpeed +2020.09.03-05.29,22 /domains/oogtopia/npc/party_ooga.c line 30: Undefined function SetWanderSpeed +2020.09.03-05.29,47 /domains/oogtopia/npc/party_ooga.c line 30: Undefined function SetWanderSpeed +2020.09.03-05.29,47 /domains/oogtopia/npc/party_ooga.c line 30: Undefined function SetWanderSpeed +2020.09.03-05.32,53 /domains/oogtopia/npc/bunga.c line 29: Undefined function SetWanderSpeed +2020.09.03-05.35,18 /domains/oogtopia/npc/party_ooga.c line 15: No such inherited function npc::create +2020.09.03-05.36,01 /domains/oogtopia/npc/party_ooga.c line 15: No such inherited function npc::create +2020.09.03-05.36,01 /domains/oogtopia/npc/party_ooga.c line 15: No such inherited function npc::create +2020.09.03-05.37,16 /domains/oogtopia/npc/bunga.c line 6: No such inherited function sentient::create +2020.09.03-05.37,16 /domains/oogtopia/npc/bunga.c line 12: Undefined function SetWanderSpeed +2020.09.03-05.41,06 /domains/oogtopia/npc/bunga.c line 15: No such inherited function npc::create +2020.09.04-21.17,59 /domains/oogtopia/npc/party_ooga.c line 15: No such inherited function npc::create diff --git a/lib/log/errors/voluntaria b/lib/log/errors/voluntaria new file mode 100644 index 0000000..2519456 --- /dev/null +++ b/lib/log/errors/voluntaria @@ -0,0 +1,55 @@ +2020.09.04-20.04,53 /domains/voluntaria/room/space.c line 9: Undefined variable 'T_SPACE' +2020.09.04-20.04,53 /domains/voluntaria/room/space.c line 10: Undefined variable 'MEDIUM_SPACE' +2020.09.04-20.04,53 /domains/voluntaria/room/space.c line 9: Undefined variable 'T_SPACE' +2020.09.04-20.04,53 /domains/voluntaria/room/space.c line 10: Undefined variable 'MEDIUM_SPACE' +2020.09.04-20.06,17 /domains/voluntaria/room/space.c line 10: Undefined variable 'T_SPACE' +2020.09.04-20.06,17 /domains/voluntaria/room/space.c line 11: Undefined variable 'MEDIUM_SPACE' +2020.09.04-20.08,01 /domains/voluntaria/room/space.c line 9: Undefined variable 'MEDIUM_SPACE' +2020.09.04-20.08,01 /domains/voluntaria/room/space.c line 9: Undefined variable 'MEDIUM_SPACE' +2020.09.05-23.39,32 /domains/voluntaria/room/airlock.c line 59: Undefined variable 'floorname' +2020.09.05-23.39,32 /domains/voluntaria/room/airlock.c line 60: Undefined variable 'doorcounter' +2020.09.05-23.39,32 /domains/voluntaria/room/airlock.c line 60: Illegal lvalue +2020.09.05-23.39,32 /domains/voluntaria/room/airlock.c line 59: Undefined variable 'floorname' +2020.09.05-23.39,32 /domains/voluntaria/room/airlock.c line 60: Undefined variable 'doorcounter' +2020.09.05-23.39,32 /domains/voluntaria/room/airlock.c line 60: Illegal lvalue +2020.09.05-23.47,13 /domains/voluntaria/room/airlock.c line 127: Undefined function Setplanet +2020.09.05-23.47,13 /domains/voluntaria/room/airlock.c line 127: Undefined function Setplanet +2020.09.06-00.05,57 /domains/voluntaria/room/bridge.c line 40: syntax error +2020.09.06-00.05,57 /domains/voluntaria/room/bridge.c line 40: syntax error +2020.09.06-00.08,28 /domains/voluntaria/room/bridge.c line 40: syntax error +2020.09.06-00.09,26 /domains/voluntaria/room/bridge.c line 40: syntax error +2020.09.06-00.09,26 /domains/voluntaria/room/bridge.c line 40: syntax error +2020.09.06-00.16,41 /domains/voluntaria/room/bridge.c line 44: syntax error +2020.09.06-00.16,41 /domains/voluntaria/room/bridge.c line 44: Illegal LHS +2020.09.06-00.16,41 /domains/voluntaria/room/bridge.c line 45: syntax error +2020.09.06-00.16,41 /domains/voluntaria/room/bridge.c line 45: Illegal LHS +2020.09.06-00.16,41 /domains/voluntaria/room/bridge.c line 46: Undefined variable 'ifdestination' +2020.09.06-00.16,41 /domains/voluntaria/room/bridge.c line 46: syntax error +2020.09.06-00.16,41 /domains/voluntaria/room/bridge.c line 44: syntax error +2020.09.06-00.16,41 /domains/voluntaria/room/bridge.c line 44: Illegal LHS +2020.09.06-00.16,41 /domains/voluntaria/room/bridge.c line 45: syntax error +2020.09.06-00.16,41 /domains/voluntaria/room/bridge.c line 45: Illegal LHS +2020.09.06-00.16,41 /domains/voluntaria/room/bridge.c line 46: Undefined variable 'ifdestination' +2020.09.06-00.16,41 /domains/voluntaria/room/bridge.c line 46: syntax error +2020.09.06-00.17,45 /domains/voluntaria/room/bridge.c line 44: syntax error +2020.09.06-00.17,45 /domains/voluntaria/room/bridge.c line 44: Illegal LHS +2020.09.06-00.17,45 /domains/voluntaria/room/bridge.c line 45: syntax error +2020.09.06-00.17,45 /domains/voluntaria/room/bridge.c line 45: Illegal LHS +2020.09.06-00.17,45 /domains/voluntaria/room/bridge.c line 46: syntax error +2020.09.06-00.17,45 /domains/voluntaria/room/bridge.c line 46: Illegal LHS +2020.09.06-00.18,46 /domains/voluntaria/room/bridge.c line 45: syntax error +2020.09.06-00.18,46 /domains/voluntaria/room/bridge.c line 45: Illegal LHS +2020.09.06-00.18,46 /domains/voluntaria/room/bridge.c line 46: syntax error +2020.09.06-00.18,46 /domains/voluntaria/room/bridge.c line 46: Illegal LHS +2020.09.06-00.18,46 /domains/voluntaria/room/bridge.c line 47: syntax error +2020.09.06-00.18,46 /domains/voluntaria/room/bridge.c line 47: Illegal LHS +2020.09.06-04.17,35 /domains/voluntaria/room/bridge.c line 61: syntax error +2020.09.06-04.20,26 /domains/voluntaria/room/bridge.c line 61: syntax error +2020.09.06-04.59,31 /domains/voluntaria/room/start.c line 33: Undefined variable 'readSign' +2020.09.06-04.59,31 /domains/voluntaria/room/start.c line 33: syntax error +2020.09.06-04.59,31 /domains/voluntaria/room/start.c line 33: Undefined variable 'readSign' +2020.09.06-04.59,31 /domains/voluntaria/room/start.c line 33: syntax error +2020.09.06-05.06,22 /domains/voluntaria/room/start.c line 32: Reserved type name unexpected. +2020.09.06-05.06,22 /domains/voluntaria/room/start.c line 32: syntax error +2020.09.06-05.06,22 /domains/voluntaria/room/start.c line 32: Reserved type name unexpected. +2020.09.06-05.06,22 /domains/voluntaria/room/start.c line 32: syntax error diff --git a/lib/log/law/adm/foo.txt b/lib/log/law/adm/foo.txt new file mode 100644 index 0000000..27afd21 --- /dev/null +++ b/lib/log/law/adm/foo.txt @@ -0,0 +1 @@ +This file intentionally left blank. diff --git a/lib/log/law/email/foo.txt b/lib/log/law/email/foo.txt new file mode 100644 index 0000000..27afd21 --- /dev/null +++ b/lib/log/law/email/foo.txt @@ -0,0 +1 @@ +This file intentionally left blank. diff --git a/lib/log/law/names/foo.txt b/lib/log/law/names/foo.txt new file mode 100644 index 0000000..27afd21 --- /dev/null +++ b/lib/log/law/names/foo.txt @@ -0,0 +1 @@ +This file intentionally left blank. diff --git a/lib/log/law/sites-misc/foo.txt b/lib/log/law/sites-misc/foo.txt new file mode 100644 index 0000000..27afd21 --- /dev/null +++ b/lib/log/law/sites-misc/foo.txt @@ -0,0 +1 @@ +This file intentionally left blank. diff --git a/lib/log/law/sites-register/foo.txt b/lib/log/law/sites-register/foo.txt new file mode 100644 index 0000000..27afd21 --- /dev/null +++ b/lib/log/law/sites-register/foo.txt @@ -0,0 +1 @@ +This file intentionally left blank. diff --git a/lib/log/law/sites-tempban/foo.txt b/lib/log/law/sites-tempban/foo.txt new file mode 100644 index 0000000..27afd21 --- /dev/null +++ b/lib/log/law/sites-tempban/foo.txt @@ -0,0 +1 @@ +This file intentionally left blank. diff --git a/lib/log/law/sites-watch/foo.txt b/lib/log/law/sites-watch/foo.txt new file mode 100644 index 0000000..27afd21 --- /dev/null +++ b/lib/log/law/sites-watch/foo.txt @@ -0,0 +1 @@ +This file intentionally left blank. diff --git a/lib/log/more b/lib/log/more new file mode 100644 index 0000000..6f84e61 --- /dev/null +++ b/lib/log/more @@ -0,0 +1,3 @@ +/domains/town/room/start +/domains/town/room/start +/domains/town/room/start diff --git a/lib/log/new_players b/lib/log/new_players new file mode 100644 index 0000000..51c2bd9 --- /dev/null +++ b/lib/log/new_players @@ -0,0 +1,10 @@ +deskarnull (Wed Sep 02 00:52:39 2020) +deskarnull (Wed Sep 02 00:52:41 2020) +fluffster (Wed Sep 02 04:05:55 2020) +fluffster (Wed Sep 02 04:05:57 2020) +deskarnull (Wed Sep 02 22:07:49 2020) +deskarnull (Wed Sep 02 22:07:51 2020) +bumble (Sat Sep 05 22:50:32 2020) +bumble (Sat Sep 05 22:50:34 2020) +gumpy (Sat Sep 05 23:49:47 2020) +gumpy (Sat Sep 05 23:49:49 2020) diff --git a/lib/log/open/currency b/lib/log/open/currency new file mode 100644 index 0000000..3acd007 --- /dev/null +++ b/lib/log/open/currency @@ -0,0 +1,12 @@ +Babylon received 99 silver Wed Sep 02 00:18:51 2020 +({ OBJ(babylon /secure/lib/connect#86) }) +Deskarnull received 149 silver Wed Sep 02 01:00:37 2020 +({ OBJ(deskarnull /secure/lib/connect#602) }) +Fluffster received 145 silver Wed Sep 02 04:06:50 2020 +({ OBJ(fluffster /secure/lib/connect#883) }) +Deskarnull received 126 silver Wed Sep 02 22:08:40 2020 +({ OBJ(deskarnull /secure/lib/connect#621) }) +Bumble received 138 silver Sat Sep 05 22:51:05 2020 +({ OBJ(bumble /secure/lib/connect#367) }) +Gumpy received 83 silver Sat Sep 05 23:50:09 2020 +({ OBJ(gumpy /secure/lib/connect#517) }) diff --git a/lib/log/open/foo.txt b/lib/log/open/foo.txt new file mode 100644 index 0000000..27afd21 --- /dev/null +++ b/lib/log/open/foo.txt @@ -0,0 +1 @@ +This file intentionally left blank. diff --git a/lib/log/reports/foo.txt b/lib/log/reports/foo.txt new file mode 100644 index 0000000..27afd21 --- /dev/null +++ b/lib/log/reports/foo.txt @@ -0,0 +1 @@ +This file intentionally left blank. diff --git a/lib/log/reset b/lib/log/reset new file mode 100644 index 0000000..16ca07c --- /dev/null +++ b/lib/log/reset @@ -0,0 +1,36 @@ +Reset 2 occurred at: Wed Sep 02 01:18:52 2020 + 0 objects reclaimed, 23 objects reset, 28 objects cleaned, 0 errors. +Reset 2 occurred at: Wed Sep 02 02:24:38 2020 + 0 objects reclaimed, 11 objects reset, 9 objects cleaned, 0 errors. +Reset 2 occurred at: Wed Sep 02 03:56:08 2020 + 0 objects reclaimed, 22 objects reset, 31 objects cleaned, 0 errors. +Reset 2 occurred at: Wed Sep 02 21:17:11 2020 + 0 objects reclaimed, 25 objects reset, 24 objects cleaned, 0 errors. +Reset 2 occurred at: Thu Sep 03 02:17:21 2020 + 0 objects reclaimed, 23 objects reset, 32 objects cleaned, 0 errors. +Reset 3 occurred at: Thu Sep 03 03:17:21 2020 + 0 objects reclaimed, 23 objects reset, 21 objects cleaned, 0 errors. +Reset 4 occurred at: Thu Sep 03 04:17:21 2020 + 21 objects reclaimed, 62 objects reset, 66 objects cleaned, 0 errors. +Reset 5 occurred at: Thu Sep 03 05:17:21 2020 + 460 objects reclaimed, 56 objects reset, 59 objects cleaned, 0 errors. +Reset 2 occurred at: Fri Sep 04 20:13:28 2020 + 0 objects reclaimed, 25 objects reset, 8 objects cleaned, 0 errors. +Reset 2 occurred at: Fri Sep 04 21:47:38 2020 + 0 objects reclaimed, 69 objects reset, 54 objects cleaned, 0 errors. +Reset 3 occurred at: Fri Sep 04 22:47:38 2020 + 1 objects reclaimed, 83 objects reset, 47 objects cleaned, 0 errors. +Reset 4 occurred at: Fri Sep 04 23:47:38 2020 + 1 objects reclaimed, 73 objects reset, 52 objects cleaned, 0 errors. +Reset 5 occurred at: Sat Sep 05 00:47:38 2020 + 1 objects reclaimed, 78 objects reset, 35 objects cleaned, 0 errors. +Reset 2 occurred at: Sat Sep 05 22:31:57 2020 + 0 objects reclaimed, 13 objects reset, 17 objects cleaned, 0 errors. +Reset 2 occurred at: Sat Sep 05 23:45:41 2020 + 6 objects reclaimed, 85 objects reset, 39 objects cleaned, 0 errors. +Reset 3 occurred at: Sun Sep 06 00:45:41 2020 + 0 objects reclaimed, 82 objects reset, 36 objects cleaned, 0 errors. +Reset 4 occurred at: Sun Sep 06 01:45:41 2020 + 1 objects reclaimed, 83 objects reset, 24 objects cleaned, 0 errors. +Reset 2 occurred at: Sun Sep 06 05:26:14 2020 + 0 objects reclaimed, 62 objects reset, 53 objects cleaned, 0 errors. diff --git a/lib/log/rid b/lib/log/rid new file mode 100644 index 0000000..b0865b2 --- /dev/null +++ b/lib/log/rid @@ -0,0 +1,6 @@ + +deskarnull by Babylon +reset + +fluffster by Babylon +cleaning diff --git a/lib/log/router/foo.txt b/lib/log/router/foo.txt new file mode 100644 index 0000000..27afd21 --- /dev/null +++ b/lib/log/router/foo.txt @@ -0,0 +1 @@ +This file intentionally left blank. diff --git a/lib/log/runtime b/lib/log/runtime new file mode 100644 index 0000000..60ff3c5 --- /dev/null +++ b/lib/log/runtime @@ -0,0 +1,23 @@ +---------------------------------------------------------------------------- +Zebu (FluffOS v2.23-ds03w) starting up on Microsoft Windows NT - Sun Sep 06 04:26:14 2020 + + + +Loading preloaded files ... +Initializations complete. + +Accepting connections on port 6666. + +Running autoexec, please wait... +Autoexec daemon run complete. + + + +--- Zebu +2020.09.06-04.54,58 +*Bad argument 1 to strsrch() +Expected: string Got: 0. +Object: /domains/default/npc/drone3#2434 at line 102 + +'heart_beat' at /domains/default/npc/drone3#2434 at line 111 +'eventSpawn' at /domains/default/npc/drone3#2434 at line 102 diff --git a/lib/log/secure/foo.txt b/lib/log/secure/foo.txt new file mode 100644 index 0000000..27afd21 --- /dev/null +++ b/lib/log/secure/foo.txt @@ -0,0 +1 @@ +This file intentionally left blank. diff --git a/lib/log/shutdowns b/lib/log/shutdowns new file mode 100644 index 0000000..fb571d9 --- /dev/null +++ b/lib/log/shutdowns @@ -0,0 +1 @@ +0 shutdown DeadSoulsWin at Wed Sep 02 00:18:51 2020 diff --git a/lib/log/watch/foo.txt b/lib/log/watch/foo.txt new file mode 100644 index 0000000..27afd21 --- /dev/null +++ b/lib/log/watch/foo.txt @@ -0,0 +1 @@ +This file intentionally left blank. diff --git a/lib/news/admin b/lib/news/admin new file mode 100644 index 0000000..eb3c11f --- /dev/null +++ b/lib/news/admin @@ -0,0 +1,41 @@ + Admin news + /news/admin + +ADMIN: + +* To change your mud's name, use the command: mudconfig. + For example: mudconfig mudname My Cool New Mud + +* To make someone else an assistant admin also use admintool. + Select groups, and modify the assist group. + +* DO NOT try to modify mudos.cfg or groups.cfg unless you know + what you're doing. IF you do try, be sure to back up the originals. + +* To know what players can do, type: + +read handbook + +* To know what creators can do, type: + +read manual + +* And you really, really have to read chapters 31 through 38 of the + manual. They are not long chapters, and you will be very happy + you did. + +* You now have an intermud channel available by default. If you + see something like: + +Cratylus@Dead Souls %^CYAN%^<dchat>%^RESET%^ Hi there! + + Don't be surprised. "dchat" is an intermud communication channel + between Dead Souls muds. To chat, type: + +dchat blah blah + + It's new, so don't expect an answer right away. + +* To read this information again, type: news admin + +* For common questions: http://dead-souls.net/ds-admin-faq.html diff --git a/lib/news/avatar b/lib/news/avatar new file mode 100644 index 0000000..fa1e750 --- /dev/null +++ b/lib/news/avatar @@ -0,0 +1,2 @@ + Avatar news + /news/avatar diff --git a/lib/news/creator b/lib/news/creator new file mode 100644 index 0000000..6557237 --- /dev/null +++ b/lib/news/creator @@ -0,0 +1,20 @@ + Creator news + /news/creator + +Dead Souls Admin FAQ: http://dead-souls.net/ds-admin-faq.html + +Dead Souls Creator FAQ: http://dead-souls.net/ds-creator-faq.html + +Editor tutorial: http://dead-souls.net/editor.html + + +The Creators Manual has been updated and revised! +There is a sweet new section on the Quick Creation System. +Starting with chapter 31, there are chapters now on how to +create things superfast, supereasy. + +To get started with the first QCS chapter, the command is: + +read chapter 31 in manual + + diff --git a/lib/news/deadsouls b/lib/news/deadsouls new file mode 100644 index 0000000..4275548 --- /dev/null +++ b/lib/news/deadsouls @@ -0,0 +1,14 @@ + __ \ | ___| | __ \ + | | _ \ _` | _` | \___ \ _ \ | | | __| | | _ \ \ / + | | __/ ( | ( | | ( | | | |\__ \ | | __/\ \ / + ____/ \___|\__,_|\__,_| _____/ \___/ \__,_|_|____/ ____/ \___| \_/ + The Dead Souls Development and Demo MUD + + This software is copyrighted and not GPL. + * Intermud channels are restricted here * + * Sessions are logged. If you dislike this, you may disconnect * + ---------------------------------------------------------- + *-> This demo MUD grants creator powers to guests. The <-* + *-> regular, downloadable version does not do this by default <-* + ---------------------------------------------------------- + For more info: http://dead-souls.net/ diff --git a/lib/news/fighter b/lib/news/fighter new file mode 100644 index 0000000..6a84c2a --- /dev/null +++ b/lib/news/fighter @@ -0,0 +1,3 @@ + Fighter news + /news/fighter + diff --git a/lib/news/ftpd b/lib/news/ftpd new file mode 100644 index 0000000..f8361c3 --- /dev/null +++ b/lib/news/ftpd @@ -0,0 +1,2 @@ + FTPD news + /news/ftpd diff --git a/lib/news/general b/lib/news/general new file mode 100644 index 0000000..1cc059f --- /dev/null +++ b/lib/news/general @@ -0,0 +1,12 @@ + General news + /news/general + +* To enable colored text, type: + +terminal ansi + +* New characters have the new Players Handbook. It's not that +long, and it's super helpful. To get started, type: + +read chapter 1 in handbook + diff --git a/lib/news/hints.txt b/lib/news/hints.txt new file mode 100644 index 0000000..45850cc --- /dev/null +++ b/lib/news/hints.txt @@ -0,0 +1,104 @@ +CREATOR TIPS + +* For details on the Quick Creation System: +http://dead-souls.net/example.html + +* If you get stuck in the editor type a single dot on +a blank line, then enter, then Q, then enter, like this: + +. +Q + + +* PRIVACY: You can enable and disable a privacy field around +your workroom with the command: privacy +This will prevent unwanted visitors from entering, +except for arches. + + +* Admins: there is a new command: admintool +It is a menu-driven system that will make your +life easier and simplify tasks like locking +the mud, changing the mud's name, creating new +currency, the works. + + +* Edit .plan in your homedir to let others +know what you're working on. You can see other +people's plans when you finger them. + + +* You can test how functions work without having to +code a command or object. The "eval" command will let +you evaluate functions. For example: +------------------------ +eval return this_player()->GetName() +eval return find_player("cratylus") +eval return present("sword",find_player("testylus"))->GetClass() +------------------------ + + +* The "boards" command will tell you which chat boards +have posts you have not read. + + +* Navigate and manipulate your files and directories +with the standard unix commands: ls, cd, cp, mv, more, +ed, grep. Be careful: just like in unix, if you delete +a mud file, it is gone for good. + + +* To toggle chat channels on and off, just type the +channel name. If you're listening to intergossip, for +example, you can turn it off by just typing: intergossip + + +* Use test characters. If you test stuff on yourself and +screw up your character file, you will be sad. + + +* To create good code, you should look at what people +have already done. Look in /domains/town and +/domains/default and you'll find some examples. Copy some +to your home directory and use them as templates for +your own creations. + + +* Remember that once you finish editing a file, you +have to use the "update" command to load it into memory. +If you change a file you've already updated, you have +to update it again for the changes to take effect. + + +* If you get errors when you try to update a file, use +the "elog" command to get clues as to what is wrong. +Most of the time it is something simple, like using "=" +where you meant to use "==" or forgetting a semicolon. +The LPC programming language does not forgive typoes any +more than any other programming language. + + +* Before changing a file, make a backup copy, for +example: cp file.c file.bak This way, if your changes +really cause a problem, you can easily restore things +to the way they used to be. + + +* The admins and elders are here to help and answer +questions. But remember: if your request is basically +"fix my workroom!" or "fix my code!", your request will +probably wind up at the bottom of the priority list. We +want you to learn to solve coding problems, and fixing +your code for you isn't the best way to make that happen. +However, we're happy to look over your code and make suggestions. + + +* Permissions and privileges: For security reasons, all creators +do not have read/write access to everything. You can read and +write any file in your home directory. You only have write +permissions within your home directory and the /tmp +directory. You can read everything outside the /realms and +/secure directories. You can't read anything +in other creators' home dirs. Your read access to some items +in the /secure directory is limited. + If you're full admin, of course, you have full access to everything. diff --git a/lib/news/hm b/lib/news/hm new file mode 100644 index 0000000..a7de388 --- /dev/null +++ b/lib/news/hm @@ -0,0 +1,2 @@ + High mortal news + /news/hm \ No newline at end of file diff --git a/lib/news/locked b/lib/news/locked new file mode 100644 index 0000000..8813cec --- /dev/null +++ b/lib/news/locked @@ -0,0 +1,2 @@ + Locked mud news + /news/locked diff --git a/lib/news/moved b/lib/news/moved new file mode 100644 index 0000000..2e7a2f6 --- /dev/null +++ b/lib/news/moved @@ -0,0 +1,5 @@ + THIS MUD HAS MOVED! + + telnet to dead-souls.net 8000 + aka 97.107.133.86 8000 + diff --git a/lib/news/newbie b/lib/news/newbie new file mode 100644 index 0000000..60792ff --- /dev/null +++ b/lib/news/newbie @@ -0,0 +1,2 @@ + Newbie news + /news/newbie diff --git a/lib/news/priest b/lib/news/priest new file mode 100644 index 0000000..e539d45 --- /dev/null +++ b/lib/news/priest @@ -0,0 +1,3 @@ + Kataan news + /news/kataan + diff --git a/lib/news/register b/lib/news/register new file mode 100644 index 0000000..87ea0e6 --- /dev/null +++ b/lib/news/register @@ -0,0 +1,10 @@ + Because some people from your site have caused us + some trouble in the past, your site must register new + characters with our law department before they are created. + To register your character, mail: + EMAIL + + Remember to include what character name you wish to use. + Do NOT include a password! You will create the character yourself. + After you've sent the message, wait a little bit. + Then try logging in a little later. diff --git a/lib/news/reminders.txt b/lib/news/reminders.txt new file mode 100644 index 0000000..7373744 --- /dev/null +++ b/lib/news/reminders.txt @@ -0,0 +1,70 @@ +CREATOR CHEAT SHEET + +make a new room named test1.c south of here: +create room south test1 + +make a new weapon named hammer_5.c: +create weapon hammer_5.c + +make the new weapon respond to the name "hammer": +modify weapon keyname hammer + +change the hammer's short description to "The Silver Hammer of Thor": +modify hammer short The Silver Hammer of Thor + +Edit a file: +ed <file> + +Load a file: +update <file> + +Copy a file: +cp <filename1> <filename2> + +Rename a file: +mv <filename1> <filename2> + +Delete a file: +rm <file> + +Make an object appear in your inventory: +clone <file> +example: clone /domains/campus/obj/key.c + +Look at the contents of a file: +more <file> +example: more /domains/campus/obj/key.c + +Destroy an object: +dest <object> +example: dest key +NOTE: Desting players or other creators is extremely rude. + +Look in your current directory (your current folder): +ls + +Find out what directory you're in: +pwd + +Change to a different directory: +cd <directory> +example: cd /domains/town/room + +Go to your workroom: +home + +Go to the Creators' Hall +wiz + +Go to another person or place +goto <person> +goto <filename> +examples: +goto cratylus +goto /domains/town/room/basement + +Get details about other people's location and activity: +people + +Bring another person to your location: +trans <person> diff --git a/lib/news/welcome b/lib/news/welcome new file mode 100644 index 0000000..92bb549 --- /dev/null +++ b/lib/news/welcome @@ -0,0 +1,6 @@ + + The Dead Souls Object Library version 3 + + This software is copyrighted and it is not GPL. + + For more info: http://dead-souls.net diff --git a/lib/obj/README b/lib/obj/README new file mode 100644 index 0000000..d764e1c --- /dev/null +++ b/lib/obj/README @@ -0,0 +1,15 @@ +The /obj directory contains files required by lib +systems. Removing this directory or its contents, +or modifying its contents may generate unexpected +behavior from your mud. + +For example, do not attempt to "fix" area_room.c or +stargate.c. Trying to load those files in /obj will +generate errors because it is *supposed* to do that. + +Do not try to use these objects directly, and do not +copy them into your area directories as templates. +QCS uses these rooms in very special ways, and having them +in your area directories may confuse it and give you +errors you don't understand. + diff --git a/lib/obj/area_room.c b/lib/obj/area_room.c new file mode 100644 index 0000000..05926f1 --- /dev/null +++ b/lib/obj/area_room.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include ROOMS_H + +#include "../customdefs.h"; + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area."); +} + +void init(){ + ::init(); +} + diff --git a/lib/obj/armor.c b/lib/obj/armor.c new file mode 100644 index 0000000..13186ce --- /dev/null +++ b/lib/obj/armor.c @@ -0,0 +1,20 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; + +static void create(){ + armor::create(); + SetKeyName("armor"); + SetId(({"armor"})); + SetAdjectives(({"generic"})); + SetShort("generic armor"); + SetLong("A generic piece of armor of indeterminate proportions."); + SetMass(50); + SetArmorType(A_SHIRT); + SetProtection(KNIFE, 5); + SetProtection(COLD, 5); +} +void init(){ + ::init(); +} diff --git a/lib/obj/barkeep.c b/lib/obj/barkeep.c new file mode 100644 index 0000000..e2f91c2 --- /dev/null +++ b/lib/obj/barkeep.c @@ -0,0 +1,22 @@ +#include <lib.h> + +inherit LIB_BARKEEP; + +static void create() { + barkeep::create(); + SetKeyName("barkeep"); + SetId( ({ "barman" }) ); + SetShort("a generic barkeep"); + SetLevel(1); + SetLong("A nondescript being whose job is to sell food and drink."); + SetMenuItems(([ + ])); + SetGender("male"); + SetRace("human"); + SetSkill("bargaining", 1); + SetProperty("no bump", 1); + SetLocalCurrency("silver"); +} +void init(){ + ::init(); +} diff --git a/lib/obj/bed.c b/lib/obj/bed.c new file mode 100644 index 0000000..da04d32 --- /dev/null +++ b/lib/obj/bed.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include <props.h> + +inherit LIB_BED; + + +static void create() { + ::create(); + SetKeyName("bed"); + SetId( ({ "bed" }) ); + SetAdjectives( ({ "generic","nondescript"}) ); + SetShort("a generic bed"); + SetLong("A nondescript bed."); + SetMass(400); + SetBaseCost("silver",150); + SetMaxSitters(2); + SetMaxLiers(1); +} +void init(){ + ::init(); +} diff --git a/lib/obj/book.c b/lib/obj/book.c new file mode 100644 index 0000000..69103f1 --- /dev/null +++ b/lib/obj/book.c @@ -0,0 +1,19 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_BOOK; + +void create(){ + ::create(); + SetKeyName("generic book"); + SetId( ({"book"}) ); + SetAdjectives( ({"generic","sample","template"}) ); + SetShort("a generic book"); + SetLong("This is a mostly empty book."); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetTitle("The Sample Book"); +} +void init(){ + ::init(); +} diff --git a/lib/obj/book_source/chapter1 b/lib/obj/book_source/chapter1 new file mode 100644 index 0000000..5ebf9ed --- /dev/null +++ b/lib/obj/book_source/chapter1 @@ -0,0 +1,3 @@ +chapter 1 "First Chapter Title" + + This is the text of the first chapter. diff --git a/lib/obj/book_source/chapter2 b/lib/obj/book_source/chapter2 new file mode 100644 index 0000000..7a0b0d7 --- /dev/null +++ b/lib/obj/book_source/chapter2 @@ -0,0 +1,3 @@ +chapter 2 "Second Chapter Title" + + This is the text of the second chapter. diff --git a/lib/obj/burning_orb.c b/lib/obj/burning_orb.c new file mode 100644 index 0000000..57e29ab --- /dev/null +++ b/lib/obj/burning_orb.c @@ -0,0 +1,35 @@ +/* /obj/burning_orb.c + * From Dead Souls LPMud + * Created by Descartes of Borg 961103 + * Version: @(#) burning_orb.c 1.1@(#) + * Last modified: 96/11/03 + */ + +#include <lib.h> +#include <vendor_types.h> + +inherit LIB_TORCH; + +static void create() { + torch::create(); + SetKeyName("burning orb"); + SetVendorType(VT_MAGIC); + SetId("orb"); + SetAdjectives("burning", "flaming"); + SetShort("a burning orb"); + SetLong("A flaming orb that does not burn you when you touch it. You " + "might be able to burn other things with it or light torches."); + SetRadiantLight(5); + SetMinHeat(10); + SetFuelRequired(1); + SetMaxFuel(50); + SetFuelAmount(50); + SetRefuelable(0); + SetMass(5); + SetValue(2); + SetBurntValue(1); + SetDestroyOnSell(1); + if( clonep() ) { + eventBurn(); + } +} diff --git a/lib/obj/chair.c b/lib/obj/chair.c new file mode 100644 index 0000000..6eb91a5 --- /dev/null +++ b/lib/obj/chair.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_CHAIR; + + +static void create() { + chair::create(); + SetKeyName("chair"); + SetId("chair"); + SetAdjectives( ({ "generic","nondescript" }) ); + SetShort("a generic chair"); + SetLong("A nondescript chair."); + SetMass(150); + SetDollarCost(15); + SetMaxSitters(1); +} +void init(){ + ::init(); +} diff --git a/lib/obj/container.c b/lib/obj/container.c new file mode 100644 index 0000000..e273560 --- /dev/null +++ b/lib/obj/container.c @@ -0,0 +1,20 @@ +#include <lib.h> + +inherit LIB_STORAGE; + + +void create() { + ::create(); + SetKeyName("container"); + SetId( ({ "container" }) ); + SetAdjectives( ({ "generic","nondescript" }) ); + SetShort("a generic container"); + SetLong("It is a thing that holds other things."); + SetCanClose(1); + SetMass(274); + SetBaseCost("silver",1); + SetMaxCarry(500); +} +void init(){ + ::init(); +} diff --git a/lib/obj/deed.c b/lib/obj/deed.c new file mode 100644 index 0000000..79fd576 --- /dev/null +++ b/lib/obj/deed.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; + +void create(){ + ::create(); + SetKeyName("generic thing"); + SetId( ({"thing","item","thang","dingus"}) ); + SetAdjectives( ({"generic","sample","template"}) ); + SetShort("a generic thing"); + SetLong("This is an object of indeterminate nature and proportions."); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); +} +void init(){ + ::init(); +} diff --git a/lib/obj/door.c b/lib/obj/door.c new file mode 100644 index 0000000..b67611d --- /dev/null +++ b/lib/obj/door.c @@ -0,0 +1,26 @@ +#include <lib.h> + +inherit LIB_DOOR; + +static void create() { + door::create(); + + SetSide("DIR_X", ([ "id" : ({"door leading DIR_X", "door", "DIR_X door"}), + "short" : "a door leading DIR_X", + "long" : "This is the Y_SIDE side of a door leading DIR_X.", + "lockable" : 1 ]) ); + + SetSide("DIR_Y", ([ "id" : ({"door leading DIR_Y", "door", "DIR_Y door"}), + "short" : "a door leading DIR_Y", + "long" : "This is the X_SIDE side of a door leading DIR_Y.", + "lockable" : 1 ]) ); + + SetClosed(1); + SetLocked(0); + SetKeys("DIR_X", ({ "DIR_X key" })); + SetKeys("DIR_Y", ({ "DIR_Y key" })); +} + +void init(){ + ::init(); +} diff --git a/lib/obj/drink.c b/lib/obj/drink.c new file mode 100644 index 0000000..cf6592d --- /dev/null +++ b/lib/obj/drink.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <meal_types.h> + +inherit LIB_MEAL; + + +static void create() { + meal::create(); + SetKeyName("drink"); + SetId(({"drink","generic drink"})); + SetShort("a generic drink"); + SetLong("This is a generic drink."); + SetMass(10); + SetStrength(20); + SetBaseCost("silver",10); + SetMealType(MEAL_DRINK); + SetMealMessages("You quaff your drink. Mmm!", + "$N quaffs $P drink."); + SetNoCondition(1); +} +void init(){ + ::init(); +} diff --git a/lib/obj/friend.c b/lib/obj/friend.c new file mode 100644 index 0000000..5840962 --- /dev/null +++ b/lib/obj/friend.c @@ -0,0 +1,75 @@ +#include <lib.h> +#include <damage_types.h> + +inherit LIB_NPC; + +void SetStuff(int level); +void SetType(string what); +int count; + +static void create(int level) { + string type; + npc::create(); + SetId(({"blob"})); + if(level < 40) type = "rodent"; + if(level > 39 && level < 50) type = "bear"; + if(level > 49 && level < 70) type = "golem"; + if(level > 69 && level < 90) type = "unicorn"; + else type = "dragon"; + count = level; + SetType(type); +} + +void SetType(string what) { + SetRace(what); + if(!SetClass("monk")) SetClass("fighter"); + SetLevel(to_int(count/12)); + SetGender(({"female","male"})[random(2)]); + switch(what) { + case "rodent": + SetLong("A cute little chipmunk."); + SetShort("a chipmunk"); + SetKeyName("chipmunk"); + SetId(({"chipmunk"})); + break; + case "bear": + SetLong("A big black bear."); + SetShort("a bear"); + SetId(({"bear"})); + SetKeyName("bear"); + break; + case "golem": + SetLong("A threatening looking golem."); + SetShort("a golem"); + SetId(({"golem"})); + SetKeyName("golem"); + break; + case "unicorn": + SetLong("A noble unicorn."); + SetShort("a unicorn"); + SetId(({"unicorn"})); + SetKeyName("unicorn"); + break; + case "dragon": + SetLong("A huge dragon with a threatening visage."); + SetShort("a dragon"); + SetId(({"dragon"})); + SetKeyName("dragon"); + break; + } +} + +void heart_beat() { + ::heart_beat(); + count--; + if(count <= 10) send_messages("flicker","$agent_name $agent_verb.", + this_object(),0,environment()); + if(count <= 0) { + send_messages("flicker","$agent_name slowly $agent_verb out" + " of existence...",this_object(),0,environment()); + eventDestruct(); + } +} + + + diff --git a/lib/obj/include/portal.h b/lib/obj/include/portal.h new file mode 100644 index 0000000..85889d0 --- /dev/null +++ b/lib/obj/include/portal.h @@ -0,0 +1,14 @@ +#ifndef __portal_obj_h__ +#define __portal_obj_h__ + +static void create(); +string eventShowPortal(); +int SetLink(mixed dest); +string GetLink(); +int SetLifeSpan(int x); +int GetLifeSpan(); +mixed CanEnter(object who, string what); +int eventEnter(object who); +int eventDestruct(); + +#endif diff --git a/lib/obj/light.c b/lib/obj/light.c new file mode 100644 index 0000000..d9ae1aa --- /dev/null +++ b/lib/obj/light.c @@ -0,0 +1,77 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +int Duration = 2; + +int eventDematerialize(){ + object env = environment(); + object owner; + string what; + if(env && living(env)){ + owner = env; + env = environment(owner); + } + if(!env && clonep(this_object())){ + ::eventDestruct(); + return 1; + } + if(owner){ + what = owner->GetName()+"'s magical glow"; + } + else what = "The magical glow"; + tell_room(env,what+" fades away.", ({ owner })); + if(owner){ + tell_object(owner,"%^BOLD%^%^CYAN%^Your magical glow fades away."+ + "%^RESET%^"); + } + ::eventDestruct(); + return 1; +} + +static void create() { + item::create(); + AddSave( ({ "Duration" }) ); + SetKeyName("magic glow"); + SetId( ({ "magic glow spell"})); + SetShort("a brilliant glow"); + SetLong("A magical source of light."); + SetMass(0); + SetPreventDrop(1); + SetInvis(1); + SetRadiantLight(30); + set_heart_beat(1); +} + +int eventDeteriorate(int type){ + return type; +} + +int SetDuration(int i){ + Duration = abs(i); + return Duration; +} + +void init(){ + ::init(); +} + +void heart_beat(){ + Duration--; + if(clonep(this_object())){ + if(Duration < 1){ + call_out("eventDematerialize",1); + } + } +} + +string GetAffectLong(object ob) { + if(!ob || !living(ob)) return 0; + return "There is a magical glow around " + ob->GetName() + "."; +} + +int CanSell(){ + return 0; +} diff --git a/lib/obj/magic_scroll.c b/lib/obj/magic_scroll.c new file mode 100644 index 0000000..af84380 --- /dev/null +++ b/lib/obj/magic_scroll.c @@ -0,0 +1,85 @@ +// magic_scroll.c +// This scroll contains a spell, which a player can learn by casting +// the read spell on the scroll. +// Mobydick@TMI-2, 3-24-93. + +#include <mudlib.h> + +inherit OBJECT ; + +void create() { + ::create(); + set ("id", ({ "scroll" }) ) ; + set ("short", "a magical scroll") ; + set ("long", + "This is a magic scroll on which spells can be written. At the moment + "+"it is blank.\n") ; + set ("mass", 10) ; + set ("bulk", 4) ; +} + +void init() { + add_action ("write_scroll", "write") ; + add_action ("read_scroll", "read") ; + add_action ("help", "help") ; +} + +void set_spell (string str) { + //if (member_array(str,SPELLS)==-1) { + // write ("Error: tried to set an unknown spell.\n") ; + // return ; + // } + // set ("spell", str) ; + // set ("short", "A scroll of "+str) ; + set ("long", + "This is a magic scroll with the "+str+" spell written on it.\n") ; +} + +int write_scroll (string str) { + + string *known ; + + // known = this_player()->query("spells") ; + // if (member_array(str,known)==-1) { + // notify_fail ("You don't know any "+str+" spell to write.\n") ; + // return 0 ; + // } + write ("You write the "+str+" spell onto the scroll.\n") ; + // set_spell(str) ; + return 1 ; +} + +int read_scroll (string str) { + if (!query("spell")) { + write("You haven't written any spells on the scroll.\n"); + return 1; + } + // if (str!="scroll" && str!="scroll of "+query("spell")) return 0 ; + // write ("You begin reading the scroll....\n") ; + // write ("You begin casting the "+query("spell")+" spell!\n") ; + // write ("On whom do you wish to cast it? (CR for yourself or current attacker) : ") ; + // input_to ("cast_args") ; + return 1 ; +} + +int cast_args (string str) { + + string name ; + + // if (!str || str == "") str="NONE" ; + // name = PATH+query("spell")+EXTENSION ; + // name->cast(str, 1) ; + // remove() ; + return 1 ; +} + +int help (string str) { + if (str!="scroll") return 0 ; + write ("If you know the read spell, you can cast it on the scroll and\n"+ + "you will learn the spell written on the scroll, if there is one.\n"+ + "If you don't know the read spell, you should find someone who can\n"+ + "teach it to you.\n"+ + "You can also simply \"read\" the scroll and cast the spell written\n"+ + "on it, but if you do that you will not learn the spell.\n") ; + return 1 ; +} diff --git a/lib/obj/meal.c b/lib/obj/meal.c new file mode 100644 index 0000000..2aa86dc --- /dev/null +++ b/lib/obj/meal.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <meal_types.h> + +inherit LIB_MEAL; + + +static void create() { + meal::create(); + SetKeyName("meal"); + SetId(({"meal","generic meal"})); + SetShort("a generic meal"); + SetLong("This is a generic meal."); + SetMass(10); + SetStrength(20); + SetBaseCost("silver",10); + SetMealType(MEAL_FOOD); + SetMealMessages("You eat your food. Mmm!", + "$N eats $P food."); + SetNoCondition(1); +} +void init(){ + ::init(); +} diff --git a/lib/obj/npc.c b/lib/obj/npc.c new file mode 100644 index 0000000..bf4a575 --- /dev/null +++ b/lib/obj/npc.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("generic npc"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"non player"})); + SetShort("a generic npc"); + SetLong("Other than being human, this npc is entirely unremarkable."); + SetLevel(1); + SetMelee(1); + SetRace("human"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/obj/order.c b/lib/obj/order.c new file mode 100644 index 0000000..79fd576 --- /dev/null +++ b/lib/obj/order.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; + +void create(){ + ::create(); + SetKeyName("generic thing"); + SetId( ({"thing","item","thang","dingus"}) ); + SetAdjectives( ({"generic","sample","template"}) ); + SetShort("a generic thing"); + SetLong("This is an object of indeterminate nature and proportions."); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); +} +void init(){ + ::init(); +} diff --git a/lib/obj/portal.c b/lib/obj/portal.c new file mode 100644 index 0000000..abc386c --- /dev/null +++ b/lib/obj/portal.c @@ -0,0 +1,88 @@ +/* /verbs/spells/obj/portal.c + * created by Blitz@Dead Souls 960417 + * used with the portal spell + */ + +#include <lib.h> +#include "include/portal.h" + +inherit LIB_ITEM; + +static int LifeSpan = 0; +static string Caster = "Blitz", + LinkRoom; + +static void create() { + item::create(); + SetKeyName("portal"); + SetId("portal"); + SetAdjectives("pulsating", "shimmering"); + SetShort("%^YELLOW%^a shimmering portal%^RESET%^"); + SetLong((: eventShowPortal :)); + SetPreventGet("The portal is pure magic and lacks substance."); + SetPreventPut("The portal is pure magic and lacks substabce."); + SetMass(0); + SetValue(0); +} + +string eventShowPortal() { + string str; + str = "A shimmering, magical portal that pulsates different " + "shades of white and blue. It was created by Talima " + "for her faithful servent " + Caster + ". "; + if( sizeof(LinkRoom) ) { + object ob = load_object(LinkRoom); + if( !ob ) return "There are problems with this portal."; + str += "Gazing into its fitful depths, you can barely see " + "an occasional glimpse of " + ob->GetShort() + "."; + } + else str += "You see nothing in its depths."; + return str; +} + +int SetLink(mixed dest) { + if( stringp(dest) ) { + dest = load_object(dest); + if( !dest ) return 0; + } + else if( !objectp(dest) ) error("Invalid argument 1 to SetLink!"); + LinkRoom = base_name(dest); + return 1; +} + +string GetLink() { return LinkRoom; } + +int SetLifeSpan(int x) { + if( LifeSpan ) return 0; + call_out((: eventDestruct :), x); + return (LifeSpan = x); +} + +int GetLifeSpan() { return LifeSpan; } + +string SetCaster(string str) { return (Caster = str); } + +string GetCaster() { return Caster; } + +mixed CanEnter(object who, string what) { + if( !sizeof(LinkRoom) ) return "The portal is non-functional."; + else return 1; +} + +int eventEnter(object who) { + if( !who ) return 0; + who->eventPrint("%^RED%^%^BOLD%^You step into the portal " + "and feel reality shift around you."); + who->eventMoveLiving(LinkRoom, + "%^GREEN%^$N steps into the portal and disappears.", + "%^GREEN%^$N steps out of a shimmering portal."); + return 1; +} + +int eventDestruct() { + object env = environment(); + if( env ) { + env->eventPrint("A shimmering portal winks out of existance."); + } + ::eventDestruct(); +} diff --git a/lib/obj/quest_ob.c b/lib/obj/quest_ob.c new file mode 100644 index 0000000..1345fb4 --- /dev/null +++ b/lib/obj/quest_ob.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; +inherit LIB_QUEST; + +void create(){ + item::create(); + quest::create(); + SetKeyName("generic quest object"); + SetId( ({"thing","item","thang","dingus", "object"}) ); + SetAdjectives( ({"generic","sample","template","quest"}) ); + SetShort("a generic quest object"); + SetLong("This is a relic of an older time, and here for "+ + "compatibility purposes."); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetQuestPoints(1); +} +void init(){ + ::init(); +} diff --git a/lib/obj/room.c b/lib/obj/room.c new file mode 100644 index 0000000..9a40b1f --- /dev/null +++ b/lib/obj/room.c @@ -0,0 +1,14 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area."); +} +void init(){ + ::init(); +} diff --git a/lib/obj/shield.c b/lib/obj/shield.c new file mode 100644 index 0000000..0f4b8af --- /dev/null +++ b/lib/obj/shield.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ARMOR; + +static void create() { + armor::create(); + SetKeyName("large shield"); + SetId( ({ "shield" }) ); + SetAdjectives( ({ "wood", "wooden","large" }) ); + SetShort("a large wooden shield"); + SetLong("A large, heavy shield made of strong wood banded with iron."); + SetDamagePoints(75); + SetVendorType(VT_ARMOR); + SetMass(200); + SetBaseCost("silver",150); + SetArmorType(A_SHIELD); + SetProtection(BLUNT, 10); + SetProtection(BLADE, 10); + SetProtection(KNIFE, 10); + //SetRestrictLimbs( ({"left hand"}) ); +} + diff --git a/lib/obj/stargate.c b/lib/obj/stargate.c new file mode 100644 index 0000000..12dea89 --- /dev/null +++ b/lib/obj/stargate.c @@ -0,0 +1,89 @@ +#include <lib.h> +#include <daemons.h> +#include "/lib/include/stargate.h" + +/** + * based on portal.c by Brodbane - March 2006 + * + * $Id: stargate.c,v 1.1 2006/04/05 05:48:39 jam Exp $ + * + * The desired functionality is much like a "star gate": users dialed + * letters or full words that lined up with destinations. A portal opens to + * that destination briefly. To define destinations you must setup a + * constant below then add it to the switch statement in the cmdDial + * function. This object is crude and basic, but gets the job done. + * + * 2006-03-22, jonez + * - original version of this file is from Daelas@Moraelinost + * 2006-03-23, jonez + * - altered so code uses existing verbs (touch, enter) where possible. last add_action is for dial command. + * - added single mapping called "database" and made the "dial" command use it. + * - dial command no longer uses switch/case, making adding a new destination simpler + * - made use of SetPreventGet() / SetPreventPut() + * - made use of new stargate daemon + * - made use of LIB_STARGATE + * - made use of STARGATE_D + * + * IDEAS: + * - create a daemon that holds the stargate network [DONE] + * - allow for stargate failure + * - add dhd object + * - change the code so that it uses a single mapping of names and + * destinations, perhaps in a database file. currently an update to the + * object requires an update for all the objects. [DONE] + * - dhd skill (thanks plato) + * - delay when dialing gate. destination dhd lights up? + * - player should not be able to dial earth if earth is already connected elsewhere (need daemon) [DONE] + * - make use of existing verbs (enter, touch) instead of doing our own thing. [DONE] + * - daemon should contain a class that maps the various gates to each other. see lib/include/door.h [DONE] + * - shout "off world activation" into the gateroom when the gate engages. + * - track status as "incoming" or "outgoing".. you can only "enter" an outgoing gate (rhk) [DONE] + * - if room is empty, shut down the gate (rhk) + * - change callout time when someone goes through the gate (rhk) + */ + +/* + Cratylus@Dead Souls <ds> but let me give you a quick outline + Cratylus@Dead Souls <ds> i type dial thing + Cratylus@Dead Souls <ds> the thing inherits LIB_DIAL + Cratylus@Dead Souls <ds> which is in /lib/events/dial.c + Cratylus@Dead Souls <ds> and all that contains is like direct_dial_ob() return 1; this kind of thing + Cratylus@Dead Souls <ds> take a look at LIB_TURN + Cratylus@Dead Souls <ds> what LIB_DIAL does is provide the object with hooks, so it *can* be dialed + Cratylus@Dead Souls <ds> so, when i type dial thing, the thing goes, yeah i + can be dialed, and then the parser enters the can_dial and do_dial funcs + in the verb + Cratylus@Dead Souls <ds> tellya what. i'd like to work with you on this one. i think it's less straightforward than it + seems, and i need to test some ideas before i can say "do it this way" + + */ + +#include <this is here on purpose to prevent this from loading> +#include <lib.h> +#include <daemons.h> +#include "/lib/include/stargate.h" + +inherit LIB_STARGATE; + +int ReadScreen(); + +void create() +{ + ::create(); + SetOrigin("ORIGIN_NAME", "/ORIGIN/GOES/HERE"); + SetRead(([ ({ "screen" }) : (: ReadScreen :) ]) ); + SetItems(([ ({ "screen" }) : "a computer screen which shows the status of the gate network" ]) ); +} + +void init() +{ + ::init(); +} + +int ReadScreen() +{ + write("stargate network status\n"); + write("-----------------------\n"); + write("\n"); + +} diff --git a/lib/obj/stargate.example b/lib/obj/stargate.example new file mode 100644 index 0000000..c0b53c6 --- /dev/null +++ b/lib/obj/stargate.example @@ -0,0 +1,89 @@ +#include <lib.h> +#include <daemons.h> +#include "/lib/include/stargate.h" + +/** + * based on portal.c by Brodbane - March 2006 + * + * $Id: stargate.c,v 1.1 2006/04/05 05:48:39 jam Exp $ + * + * The desired functionality is much like a "star gate": users dialed + * letters or full words that lined up with destinations. A portal opens to + * that destination briefly. To define destinations you must setup a + * constant below then add it to the switch statement in the cmdDial + * function. This object is crude and basic, but gets the job done. + * + * 2006-03-22, jonez + * - original version of this file is from Daelas@Moraelinost + * 2006-03-23, jonez + * - altered so code uses existing verbs (touch, enter) where possible. last add_action is for dial command. + * - added single mapping called "database" and made the "dial" command use it. + * - dial command no longer uses switch/case, making adding a new destination simpler + * - made use of SetPreventGet() / SetPreventPut() + * - made use of new stargate daemon + * - made use of LIB_STARGATE + * - made use of STARGATE_D + * + * IDEAS: + * - create a daemon that holds the stargate network [DONE] + * - allow for stargate failure + * - add dhd object + * - change the code so that it uses a single mapping of names and + * destinations, perhaps in a database file. currently an update to the + * object requires an update for all the objects. [DONE] + * - dhd skill (thanks plato) + * - delay when dialing gate. destination dhd lights up? + * - player should not be able to dial earth if earth is already connected elsewhere (need daemon) [DONE] + * - make use of existing verbs (enter, touch) instead of doing our own thing. [DONE] + * - daemon should contain a class that maps the various gates to each other. see lib/include/door.h [DONE] + * - shout "off world activation" into the gateroom when the gate engages. + * - track status as "incoming" or "outgoing".. you can only "enter" an outgoing gate (rhk) [DONE] + * - if room is empty, shut down the gate (rhk) + * - change callout time when someone goes through the gate (rhk) + */ + +/* +Cratylus@Dead Souls <ds> but let me give you a quick outline +Cratylus@Dead Souls <ds> i type dial thing +Cratylus@Dead Souls <ds> the thing inherits LIB_DIAL +Cratylus@Dead Souls <ds> which is in /lib/events/dial.c +Cratylus@Dead Souls <ds> and all that contains is like direct_dial_ob() return 1; this kind of thing +Cratylus@Dead Souls <ds> take a look at LIB_TURN +Cratylus@Dead Souls <ds> what LIB_DIAL does is provide the object with hooks, so it *can* be dialed +Cratylus@Dead Souls <ds> so, when i type dial thing, the thing goes, yeah i + can be dialed, and then the parser enters the can_dial and do_dial funcs + in the verb +Cratylus@Dead Souls <ds> tellya what. i'd like to work with you on this one. i think it's less straightforward than it + seems, and i need to test some ideas before i can say "do it this way" + +*/ + +#include <this is here on purpose to prevent this from loading> +#include <lib.h> +#include <daemons.h> +#include "/lib/include/stargate.h" + +inherit LIB_STARGATE; + +int ReadScreen(); + +void create() +{ + ::create(); + SetOrigin("ORIGIN_NAME", "/ORIGIN/GOES/HERE"); + SetRead(([ ({ "screen" }) : (: ReadScreen :) ]) ); + SetItems(([ ({ "screen" }) : "a computer screen which shows the status of the gate network" ]) ); +} + +void init() +{ + ::init(); +} + +int ReadScreen() +{ + write("stargate network status\n"); + write("-----------------------\n"); + write("\n"); + +} diff --git a/lib/obj/sword.c b/lib/obj/sword.c new file mode 100644 index 0000000..329f55b --- /dev/null +++ b/lib/obj/sword.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; + +void create(){ + ::create(); + SetKeyName("sword"); + SetId( ({"thing","item","thang","dingus"}) ); + SetAdjectives( ({"generic","sample","template"}) ); + SetShort("a sword"); + SetLong("This is an object of indeterminate nature and proportions."); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); +} +void init(){ + ::init(); +} diff --git a/lib/obj/table.c b/lib/obj/table.c new file mode 100644 index 0000000..10ceb8e --- /dev/null +++ b/lib/obj/table.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_TABLE; + + +void create() { + ::create(); + SetKeyName("generic table"); + SetId( ({ "table","surface" }) ); + SetAdjectives( ({ "generic"}) ); + SetShort("a generic table"); + SetLong("It is a surface that can hold things."); + SetBaseCost("silver",1); + SetMaxCarry(500); + +} +void init(){ + ::init(); +} diff --git a/lib/obj/thing.c b/lib/obj/thing.c new file mode 100644 index 0000000..79fd576 --- /dev/null +++ b/lib/obj/thing.c @@ -0,0 +1,18 @@ +#include <lib.h> +#include <vendor_types.h> +inherit LIB_ITEM; + +void create(){ + ::create(); + SetKeyName("generic thing"); + SetId( ({"thing","item","thang","dingus"}) ); + SetAdjectives( ({"generic","sample","template"}) ); + SetShort("a generic thing"); + SetLong("This is an object of indeterminate nature and proportions."); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); +} +void init(){ + ::init(); +} diff --git a/lib/obj/trainer.c b/lib/obj/trainer.c new file mode 100644 index 0000000..4e0fb3b --- /dev/null +++ b/lib/obj/trainer.c @@ -0,0 +1,23 @@ +#include <lib.h> + +inherit LIB_TRAINER; +void create(){ + trainer::create(); + SetKeyName("trainer"); + SetId("generic trainer"); + SetGender("male"); + SetRace("human"); + SetShort("a generic trainer"); + SetLong("This is a person whose job it is to teach you things. "+ + "For example, 'ask trainer "+ + "to teach wibbling' would prompt him to begin a wibble learning "+ + "lesson with you, if wibbling is in his skill set and you have "+ + "earned sufficient training points. If you lack training points, then "+ + "do some adventuring and earn a level promotion. You will "+ + "then be awarded training points."); + SetLevel(1); + AddTrainingSkills( ({"wibbling"})); +} +void init() { + ::init(); +} diff --git a/lib/obj/vendor.c b/lib/obj/vendor.c new file mode 100644 index 0000000..6ea4d13 --- /dev/null +++ b/lib/obj/vendor.c @@ -0,0 +1,22 @@ +#include <lib.h> +#include <vendor_types.h> + +inherit LIB_VENDOR; + +static void create() { + vendor::create(); + SetKeyName("vendor"); + SetId( ({ "shopkeep" }) ); + SetAdjectives( ({ "generic" }) ); + SetShort("a generic vendor"); + SetLevel(1); + SetLong("A nondescript person whose job it is to sell things."); + SetGender("male"); + SetRace("human"); + SetSkill("bargaining", 1); + SetProperty("no bump", 1); + SetLocalCurrency("silver"); + SetStorageRoom("/obj/room"); + SetMaxItems(100); + SetVendorType(VT_ALL); +} diff --git a/lib/obj/weapon.c b/lib/obj/weapon.c new file mode 100644 index 0000000..6dce379 --- /dev/null +++ b/lib/obj/weapon.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + + +static void create() { + item::create(); + SetKeyName("generic weapon"); + SetId( ({ "weapon"})); + 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(); +} diff --git a/lib/obj/wed_ring.c b/lib/obj/wed_ring.c new file mode 100644 index 0000000..bc37899 --- /dev/null +++ b/lib/obj/wed_ring.c @@ -0,0 +1,64 @@ +/* /obj/wed_ring.c + * from Dead Souls LPMud + * created by Descartes of Borg 951211 + */ + +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ARMOR; + +private string Spouse; + +mixed eventMove(mixed dest); +string SetSpouse(string str); +string GetSpouse(); +string RealLong(); + +static void create() { + armor::create(); + AddSave( ({ "Spouse" }) ); + SetKeyName("wedding ring"); + SetId( ({ "ring", "official wedding ring" }) ); + SetAdjectives( ({ "golden", "gold" }) ); + SetShort("a wedding ring of gold"); + SetLong( (:RealLong:) ); + SetVendorType(VT_ARMOR | VT_MAGIC); + SetMass(10); + SetValue(0); + SetPreventDrop("You may not drop your wedding ring!"); + SetRetainOnDeath(1); + SetDamagePoints(1000000); + SetProtection(BLUNT, 3); + SetProtection(BLADE, 3); + SetProtection(KNIFE, 3); + SetArmorType(A_RING); + SetRestrictLimbs( ({"left hand"}) ); +} + +mixed eventMove(mixed dest) { + mixed tmp; + + if(archp(this_player())) return armor::eventMove(dest); + if( !environment() ) { + tmp = armor::eventMove(dest); + //if( tmp == 1 ) environment()->eventForce("wear wedding ring"); + return tmp; + } + else return 0; +} + +string SetSpouse(string str) { + if( Spouse ) return Spouse; + else return Spouse = str; +} + +string GetSpouse() { return Spouse; } + +string RealLong() { + return ("This beautiful golden band was given to you by " + + GetSpouse() + " to capture your eternal love."); +} + diff --git a/lib/obj/whip.c b/lib/obj/whip.c new file mode 100644 index 0000000..97a76e0 --- /dev/null +++ b/lib/obj/whip.c @@ -0,0 +1,80 @@ +#include <lib.h> +#include <damage_types.h> +#include <vendor_types.h> + +inherit LIB_ITEM; + +int Duration = 2; + +int eventDematerialize(){ + object env = environment(); + object owner; + string what; + if(env && living(env)){ + owner = env; + env = environment(owner); + } + if(!env && clonep(this_object())){ + ::eventDestruct(); + return 1; + } + if(owner){ + what = owner->GetName()+"'s energy whip"; + } + else what = "The energy whip"; + tell_room(env,what+" fades away and disappears.", ({ owner })); + if(owner){ + tell_object(owner,"%^CYAN%^Your energy whip fades away and " + "disappears.%^RESET%^"); + } + ::eventDestruct(); + return 1; +} + +int eventDispel(){ + return eventDematerialize(); +} + +static void create() { + item::create(); + AddSave( ({ "Duration" }) ); + SetKeyName("energy whip"); + SetId( ({ "whip"})); + SetAdjectives( ({ "energy","magic","magical" })); + SetShort("an energy whip"); + SetLong("A whip made of magical energy"); + SetMass(0); + SetVendorType(VT_WEAPON); + SetClass(30); + SetDamageType(MAGIC); + SetWeaponType("magic"); + set_heart_beat(1); +} + +mixed CanDrop(object who){ return 0; } + +int eventDeteriorate(int type){ + return type; +} + +int SetDuration(int i){ + Duration = abs(i); + return Duration; +} + +void init(){ + ::init(); +} + +void heart_beat(){ + Duration--; + if(clonep(this_object())){ + if(!GetWielded() || Duration < 1){ + call_out("eventDematerialize",1); + } + } +} + +int CanSell(){ + return 0; +} diff --git a/lib/obj/worn_storage.c b/lib/obj/worn_storage.c new file mode 100644 index 0000000..4badeaf --- /dev/null +++ b/lib/obj/worn_storage.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_WORN_STORAGE; + +static void create(){ + ::create(); + SetKeyName("generic worn storage"); + SetId(({"thing","worn_storage","storage","article"})); + SetAdjectives(({"article of","generic","worn"})); + SetShort("a generic article of worn storage"); + SetLong("This is a thing that can be worn which can also hold things."); + SetCanClose(1); + SetMaxCarry(100); + SetMass(200); + SetBaseCost("silver",10); + SetDamagePoints(100); + SetArmorType(A_PANTS); + SetProtection(COLD, 1); +} +void init(){ + ::init(); +} diff --git a/lib/open/prog.c b/lib/open/prog.c new file mode 100644 index 0000000..36e2cc8 --- /dev/null +++ b/lib/open/prog.c @@ -0,0 +1,95 @@ +#include <bboard.h> +#include <cfg.h> +#include <cgi.h> +#include <clean_up.h> +#include <clock.h> +#include <commands.h> +#include <comp.h> +#include <compat.h> +#include <config.h> +#include <council.h> +#include <daemons.h> +#include <deputies.h> +#include <dirs.h> +#include <domains.h> +#include <events.h> +#include <files.h> +#include <flags.h> +#include <function.h> +#include <global.h> +#include <iips.h> +#include <lib.h> +#include <link.h> +#include <localtime.h> +#include <logs.h> +#include <lvs.h> +#include <modules.h> +#include <mssp.h> +#include <mudlib.h> +#include <network.h> +#include <news.h> +#include <objects.h> +#include <origin.h> +#include <parse_com.h> +#include <parser_error.h> +#include <post.h> +#include <pov.h> +#include <privs.h> +#include <props.h> +#include <rcp.h> +#include <rooms.h> +#include <runtime_config.h> +#include <save.h> +#include <secrets.h> +#include <socket.h> +#include <socket_err.h> +#include <sockets.h> +#include <std.h> +#include <type.h> +#include <user.h> +#include <virtual.h> +#include <voting.h> +#include <armor_types.h> +#include <assessment.h> +#include <astar.h> +#include <body_types.h> +#include <boobytraps.h> +#include <build_types.h> +#include <climb.h> +#include <combat_messages.h> +#include <damage_types.h> +#include <gossip.h> +#include <graphics.h> +#include <jump.h> +#include <magic.h> +#include <magic_protection.h> +#include <marriage.h> +#include <materials.h> +#include <meal_types.h> +#include <medium.h> +#include <message_class.h> +#include <motion.h> +#include <mouth_types.h> +#include <position.h> +#include <race.h> +#include <respiration_types.h> +#include <rounds.h> +#include <size_types.h> +#include <soul.h> +#include <stargate.h> +#include <talk_type.h> +#include <terrain_types.h> +#include <vendor_types.h> +#include <vision.h> +#ifndef $S +#define $S "DEFINED_D: undefined" +#endif + +mixed defcheck(){ +int err; +mixed ret; +err = catch( ret = $S ); +if(err) ret = "DEFINED_D: error"; +else if(undefinedp(ret)) ret = "DEFINED_D: undefined"; +return ret; +} \ No newline at end of file diff --git a/lib/powers/prayers/healing.c b/lib/powers/prayers/healing.c new file mode 100644 index 0000000..6d036b7 --- /dev/null +++ b/lib/powers/prayers/healing.c @@ -0,0 +1,75 @@ +/* /spells/heal.c + * From Dead Souls LPMud + * Created by Faldir 961101 + * Version: @(#) heal.c 1.6@(#) + * Last modified: %D% + */ + +#include <lib.h> +#include <daemons.h> +#include <magic.h> +#include <damage_types.h> +#include <magic_protection.h> + +inherit LIB_SPELL; + +static void create() { + spell::create(); + SetSpell("healing"); + SetRules("for LIV"); + SetSpellType(SPELL_HEALING); + SetRequiredMagic(300); + SetSkills(([ "healing" : 1 ])); + SetMagicCost( 20, 10); + SetDifficulty(1); + SetVerb("pray"); + SetHelp("Syntax: <pray for healing for LIV>\n\n" + "This minor healing spell provides some minimal " + "aid to the wounded."); +} + +int eventCast(object who, int level, mixed limbs, object array targets) { + object target = targets[0]; + int feedback,health,magic,stamina,tot; + if(!spell::eventCast(who,level,targets)) return 0; + if( target == who ) { + //who->eventPrint("You can't cast heal on yourself!"); + //return 0; + } + else { + int hp = who->GetSkillLevel("healing"); + int stam = who->GetSkillLevel("faith"); + send_messages("", "$agent_possessive_noun spell partially heals " + "$target_name.",who, + target, environment(target)); + health = target->GetMaxHealthPoints()-target->GetHealthPoints(); + stamina = target->GetMaxStaminaPoints()-target->GetStaminaPoints(); + if(health) target->AddHP(((hp > health) ? health : hp)); + if(stamina) + target->AddStaminaPoints(((stam > stamina) ? stamina : stam)); + tot = hp+stam; + if(tot) + who->eventTrainSkill("healing",0,0,1,tot); + magic = who->GetMagicPoints(); + magic = magic - tot; + if(magic < 0) feedback = tot - magic; + who->AddMagicPoints(-tot); + if(feedback){ + write("Your spell overreached your mana reserves! You suffer "+ + "from a feedback overload!"); + who->eventReceiveDamage(who, KARMA, tot, 1); + } + } + return 1; +} + +varargs int CanCast(object who, int level, string limb, object array targets){ + foreach(object targ in targets){ + string race = targ->GetRace(); + if(race && RACES_D->GetNonMeatRace(race)){ + write("This prayer only works on flesh-and-blood creatures."); + return 0; + } + } + return ::CanCast(who, level, limb, targets); +} diff --git a/lib/powers/spells/buffer.c b/lib/powers/spells/buffer.c new file mode 100644 index 0000000..af5e3e0 --- /dev/null +++ b/lib/powers/spells/buffer.c @@ -0,0 +1,123 @@ +/* /spells/buffer.c + * From Dead Souls LPMud + * Created by Blitz + * Converted to new spell system by BillGates 961119 + * Version: @(#) buffer.c 1.6@(#) + * Last modified: 96/11/10 + */ + +#include <lib.h> +#include <magic.h> +#include <damage_types.h> +#include <magic_protection.h> +#include <function.h> + +inherit LIB_SPELL; + +int hitCallback(object who, object agent, int x, class MagicProtection cl); +void endCallback(object who); + +static void create() { + spell::create(); + SetSpell("buffer"); + SetRules("", "LIV"); + SetSpellType(SPELL_DEFENSE); + SetRequiredMagic(50); + SetSkills(([ "magic defense" : 1 ])); + SetMagicCost(40, 40); + SetDifficulty(1); + SetMorality(10); + SetHelp("Syntax: <cast buffer>\n" + " <cast buffer on LIV>\n\n" + "A magical defense spell that allows the caster to create " + "a glowing shield around the LIVing object named.\n\n"); +} + +varargs int CanCast(object who, int level, string limb, object array targets){ + class MagicProtection *Protections; + object target = targets[0]; + + Protections = target->GetMagicProtection(); + + foreach(class MagicProtection tmp in Protections){ + if(!tmp->obname) continue; + if(tmp->obname == file_name(this_object())){ + if(!(functionp(tmp->hit) & FP_OWNER_DESTED)){ + if(target == this_player()){ + write("You are already protected by a buffer!"); + } + else { + write("They are already protected by a buffer!"); + } + return 0; + } + } + } + return ::CanCast(who, level, limb, targets); +} + + +int eventCast(object who, int level, string race, object array targets) { + class MagicProtection protection; + object target = targets[0]; + int prot_level, skill, wis, maxprot; + + maxprot = (who->GetMaxHealthPoints()) / 2; + + wis = who->GetStatLevel("wisdom"); + skill = who->GetSkillLevel("magic defense"); + prot_level = level * 3; + prot_level += (skill * 3); + prot_level += (wis / 2); + + if(prot_level > maxprot) prot_level = maxprot; + + protection = new(class MagicProtection); + protection->bits = ALL_EXTERNAL_DAMAGE; + protection->caster = who; + protection->absorb = prot_level; + protection->args = level; + protection->hit = (: hitCallback :); + protection->end = (: endCallback :); + protection->obname = file_name(this_object()); + protection->ob = this_object(); + protection->name = "magical buffer"; + target->AddMagicProtection(protection); + if( target == who ) { + send_messages("", "A %^BOLD%^CYAN%^translucent magical shield%^RESET%^ " + "suddenly appears around $agent_possessive_noun body.", who, 0, + environment(target)); + } + else { + send_messages("", "A %^BOLD%^CYAN%^translucent magical shield%^RESET%^ " + "suddenly appears around $target_possessive_noun body.", who, + target, environment(target)); + } + return 1; +} + +int hitCallback(object who, object agent, int x, class MagicProtection cl) { + string str; + object Caster = cl->caster; + + if( agent->GetUndead() ) return 0; + str = agent->GetName() || agent->GetShort(); + if( who == Caster ) { + who->eventTrainSkill("magic defense",cl->args,x,1); + } + else if( Caster && playerp(who) && Caster != who ) { + Caster->eventTrainSkill("magic defense",cl->args,0,1); + } + + send_messages("", "The %^YELLOW%^magical shield%^RESET%^ around " + "$agent_name wavers as $target_name strikes it.", + who, agent, environment(who)); + return x; +} + +void endCallback(object who) { + if( who ) { + send_messages("", "The %^BOLD%^CYAN%^magical shield%^RESET%^ around " + "$agent_name shatters into nothingness.", who, 0, environment(who)); + } +} diff --git a/lib/powers/spells/fireball.c b/lib/powers/spells/fireball.c new file mode 100644 index 0000000..4f98fca --- /dev/null +++ b/lib/powers/spells/fireball.c @@ -0,0 +1,45 @@ +/* /spells/fireball.c + * From Dead Souls LPMud + * Created by Descartes of Borg 961027 + * Version: @(#) fireball.c 1.7@(#) + * Last modified: 96/11/02 + */ + +#include <lib.h> +#include <magic.h> +#include <damage_types.h> + +inherit LIB_SPELL; + +static void create() { + spell::create(); + SetSpell("fireball"); + SetRules("", "LIV"); + SetSpellType(SPELL_COMBAT); + SetRequiredMagic(50); + SetSkills(([ "conjuring" : 8, "magic attack" : 0 ])); + SetMagicCost(30, 24); + SetStaminaCost(20, 16); + SetDifficulty(10); + SetMorality(-20); + SetAutoDamage(0); + SetDamage(MAGIC|HEAT, ({ 20, 15 }) ); + SetMessages(({ ({ "accept", "$target_name $target_verb " + "$agent_possessive_noun fireball with a " + "smile." }), + ({ "are", "$target_name $target_verb slightly " + "charred by $agent_possessive_noun " + "fireball." }), + ({ "", "$agent_possessive_noun " + "%^RED%^fireball%^RESET%^ " + "lights $target_name on fire!" }), + ({ "are", "$target_name $target_verb burned to " + "a crisp by $agent_possessive_noun " + "%^BOLD%^RED%^fireball%^RESET%^." }) })); + SetHelp("Syntax: <cast fireball>\n" + " <cast fireball on LIVING>\n\n" + "This spell creates a conjures a tremendous fireball out of " + "thin air and sends it hurling towards an unsuspecting enemy. " + "If cast without specifying a target while in combat, the " + "fireball is targetted at your current enemy."); +} diff --git a/lib/powers/spells/greater_buffer.c b/lib/powers/spells/greater_buffer.c new file mode 100644 index 0000000..b69c928 --- /dev/null +++ b/lib/powers/spells/greater_buffer.c @@ -0,0 +1,117 @@ +/* /spells/buffer.c + * From Dead Souls LPMud + * Created by Blitz + * Converted to new spell system by BillGates 961119 + * Version: @(#) buffer.c 1.6@(#) + * Last modified: 96/11/10 + */ + +#include <lib.h> +#include <magic.h> +#include <damage_types.h> +#include <magic_protection.h> +#include <function.h> + +inherit LIB_SPELL; + +int hitCallback(object who, object agent, int x, class MagicProtection cl); +void endCallback(object who); + +static void create() { + spell::create(); + SetSpell("greater buffer"); + SetRules("", "LIV"); + SetSpellType(SPELL_DEFENSE); + SetRequiredMagic(50); + SetSkills(([ "magic defense" : 24, "conjuring" : 24 ])); + SetMagicCost(80, 80); + SetDifficulty(2); + SetMorality(10); + SetHelp("Syntax: <cast greater buffer>\n" + " <cast greater buffer on LIV>\n\n" + "A magical defense spell that allows the caster to create " + "a glowing shield around the LIVing object named.\n\n"); +} + +int eventCast(object who, int level, string race, object array targets) { + class MagicProtection protection; + class MagicProtection *Protections; + object target = targets[0]; + int prot_level, skill, wis, maxprot; + + maxprot = (who->GetMaxHealthPoints()) * 2; + + Protections = target->GetMagicProtection(); + foreach(class MagicProtection tmp in Protections){ + if(!tmp->obname) continue; + if(tmp->obname == file_name(this_object())){ + if(!(functionp(tmp->hit) & FP_OWNER_DESTED)){ + if(target == this_player()){ + write("You are already protected by a greater buffer!"); + } + else { + write("They are already protected by a greater buffer!"); + } + return 1; + } + } + } + + wis = who->GetStatLevel("wisdom"); + skill = who->GetSkillLevel("magic defense"); + skill += who->GetSpellLevel("greater buffer"); + prot_level = level * 3; + prot_level += (skill); + prot_level += (wis); + + if(prot_level > maxprot) prot_level = maxprot; + + protection = new(class MagicProtection); + protection->bits = ALL_EXTERNAL_DAMAGE; + protection->caster = who; + protection->absorb = prot_level; + protection->args = level; + protection->hit = (: hitCallback :); + protection->end = (: endCallback :); + protection->obname = file_name(this_object()); + protection->ob = this_object(); + protection->name = "greater magical buffer"; + target->AddMagicProtection(protection); + if( target == who ) { + send_messages("", "A %^BOLD%^BLUE%^translucent magical shield%^RESET%^ " + "suddenly appears around $agent_possessive_noun body.", who, 0, + environment(target)); + } + else { + send_messages("", "A %^BOLD%^BLUE%^translucent magical shield%^RESET%^ " + "suddenly appears around $target_possessive_noun body.", who, + target, environment(target)); + } + return 1; +} + +int hitCallback(object who, object agent, int x, class MagicProtection cl) { + string str; + object Caster = cl->caster; + + if( agent->GetUndead() ) return 0; + str = agent->GetName() || agent->GetShort(); + if( who == Caster ) { + who->eventTrainSkill("magic defense",cl->args,x,1); + } + else if( Caster && playerp(who) && Caster != who ) { + Caster->eventTrainSkill("magic defense",cl->args,0,1); + } + + send_messages("", "The %^YELLOW%^magical shield%^RESET%^ around " + "$agent_name wavers as $target_name strikes it.", + who, agent, environment(who)); + return x; +} + +void endCallback(object who) { + if( who ) { + send_messages("", "The %^BOLD%^BLUE%^magical shield%^RESET%^ around " + "$agent_name shatters into nothingness.", who, 0, environment(who)); + } +} diff --git a/lib/powers/spells/greater_fireball.c b/lib/powers/spells/greater_fireball.c new file mode 100644 index 0000000..3c880d4 --- /dev/null +++ b/lib/powers/spells/greater_fireball.c @@ -0,0 +1,43 @@ +/* /spells/fireball.c + * From Dead Souls LPMud + * Created by Descartes of Borg 961027 + * Version: @(#) fireball.c 1.7@(#) + * Last modified: 96/11/02 + */ + +#include <lib.h> +#include <magic.h> +#include <damage_types.h> + +inherit LIB_SPELL; + +static void create() { + spell::create(); + SetSpell("greater fireball"); + SetRules("", "LIV"); + SetSpellType(SPELL_COMBAT); + SetRequiredMagic(100); + SetSkills(([ "conjuring" : 24, "magic attack" : 24 ])); + SetMagicCost(49, 49); + SetStaminaCost(10, 10); + SetDifficulty(10); + SetMorality(-20); + SetAutoDamage(0); + SetDamage(MAGIC|HEAT, ({ 60, 45 }) ); + SetMessages(({ + ({ "are", "$target_name $target_verb " + "charred by $agent_possessive_noun " + "fireball." }), + ({ "", "$agent_possessive_noun " + "%^RED%^fireball%^RESET%^ " + "lights $target_name on fire!" }), + ({ "are", "$target_name $target_verb burned to " + "a crisp by $agent_possessive_noun " + "%^BOLD%^RED%^fireball%^RESET%^." }) })); + SetHelp("Syntax: <cast fireball>\n" + " <cast fireball on LIVING>\n\n" + "This spell creates a conjures a tremendous fireball out of " + "thin air and sends it hurling towards an unsuspecting enemy. " + "If cast without specifying a target while in combat, the " + "fireball is targetted at your current enemy."); +} diff --git a/lib/powers/spells/light.c b/lib/powers/spells/light.c new file mode 100644 index 0000000..f7321d3 --- /dev/null +++ b/lib/powers/spells/light.c @@ -0,0 +1,46 @@ +#include <lib.h> +#include <magic.h> +#include <damage_types.h> +#include <magic_protection.h> + +inherit LIB_SPELL; + +static void create() { + spell::create(); + SetSpell("light"); + SetRules("", "LIV"); + SetSpellType(SPELL_OTHER); + SetRequiredMagic(20); + SetSkills(([ "conjuring" : 5 ])); + SetMagicCost(20, 0); + SetDifficulty(1); + SetMorality(10); + SetHelp("Syntax: cast light\n" + "Surrounds you with radiating light to see in the dark."); +} + +varargs int CanCast(object who, int level, string limb, object array targets){ + object *lights = filter(all_inventory(this_player()), + (: base_name($1) == "/obj/light" :) ); + if(sizeof(lights)){ + write("You already have a magical glow."); + return 0; + } + return ::CanCast(who, level, limb, targets); +} + +int eventCast(object who, int level) { + int intel = who->GetStatLevel("intelligence"); + int duration = intel + who->GetSkillLevel("conjuring") + who->GetSpellLevel("light"); + object mojo = new("/obj/light"); + + duration += (who->GetLevel()); + duration *= 5; + mojo->SetDuration(duration); + mojo->eventMove(who); + + send_messages("", "A %^B_BLACK%^%^BOLD%^YELLOW%^magical glow%^RESET%^ " + "appears around $agent_possessive_noun body.", who, 0, + environment(who)); + return 1; +} diff --git a/lib/powers/spells/meditate.c b/lib/powers/spells/meditate.c new file mode 100644 index 0000000..a85cbb0 --- /dev/null +++ b/lib/powers/spells/meditate.c @@ -0,0 +1,52 @@ +#include <lib.h> +#include <magic.h> +#include <damage_types.h> +#include <magic_protection.h> + +inherit LIB_SPELL; + +static void create() { + spell::create(); + SetSpell("meditate"); + SetRules("", "LIV"); + SetSpellType(SPELL_DEFENSE); + SetRequiredMagic(50); + SetSkills(([ "magic defense" : 0 ])); + SetMagicCost(150, 100); + SetDifficulty(1); + SetMorality(10); + SetHelp("Syntax: <cast meditate>\n" + "A spell that allows the caster to " + "restore their stamina more quickly.\n\n"); +} + +varargs int CanCast(object who, int level, string limb, object array targets){ + object *mojo = filter(all_inventory(this_player()), + (: base_name($1) == "/secure/obj/meditate_mojo" :) ); + if(sizeof(mojo)){ + write("You already have a meditative aura around you, restoring your stamina."); + return 0; + } + return ::CanCast(who, level, limb, targets); +} + +int eventCast(object who, int level) { + int wis, skill, stamina_level; + object mojo = new("/secure/obj/meditate_mojo"); + wis = who->GetStatLevel("wisdom"); + skill = who->GetSkillLevel("magic defense"); + stamina_level = level; + stamina_level *= (random(skill/10) + 1); + stamina_level += random(wis/2); + stamina_level += 10; + + who->AddStaminaPoints(stamina_level); + mojo->AddDuration(who->GetSkillLevel("conjuring") + who->GetSpellLevel("meditate")); + mojo->eventMove(who); + + send_messages("", "A %^BOLD%^MAGENTA%^dark magical field%^RESET%^ " + "briefly appears around $agent_possessive_noun body.", who, 0, + environment(who)); + return 1; +} + diff --git a/lib/powers/spells/missile.c b/lib/powers/spells/missile.c new file mode 100644 index 0000000..8f4e4dc --- /dev/null +++ b/lib/powers/spells/missile.c @@ -0,0 +1,40 @@ +/* /spells/missile.c + * From Dead Souls LPMud + * Created by Descartes of Borg 961028 + * Version: %A$ + * Last modified: 96/11/02 + */ + +#include <lib.h> +#include <magic.h> +#include <damage_types.h> + +inherit LIB_SPELL; + +static void create() { + spell::create(); + SetSpell("missile"); + SetRules("", "LIV"); + SetSpellType(SPELL_COMBAT); + SetRequiredMagic(5); + SetSkills(([ "conjuring" : 0, "magic attack" : 0 ])); + SetMagicCost(10, 3); + SetStaminaCost(5, 3); + SetDifficulty(0); + SetMorality(-1); + SetAutoDamage(3); + SetDamage(MAGIC|BLUNT, ({15, 6}) ); + SetMessages(({ ({ "are", "$target_name $target_verb " + "unharmed by $agent_possessive " + "missile." }), + ({ "stings", "$agent_possessive_noun missile " + "$agent_verb $target_name." }), + ({ "slams", "$agent_possessive_noun missile " + "$agent_verb $target_name." }) })); + SetHelp("Syntax: <cast missile>\n" + " <cast missile on LIVING>\n\n" + "This spell conjures a magic missile out of " + "thin air and sends it hurling towards the specified enemy. " + "If cast without specifying a target while in combat, the " + "missile is targetted at your current enemy."); +} diff --git a/lib/powers/spells/whip.c b/lib/powers/spells/whip.c new file mode 100644 index 0000000..4a5ae28 --- /dev/null +++ b/lib/powers/spells/whip.c @@ -0,0 +1,57 @@ +#include <lib.h> +#include <magic.h> +#include <damage_types.h> + +inherit LIB_SPELL; + +static void create() { + spell::create(); + SetSpell("whip"); + SetRules(""); + SetSpellType(SPELL_OTHER); + SetRequiredMagic(5); + SetSkills(([ "conjuring" : 0 ])); + SetMagicCost(50, 50); + SetStaminaCost(10, 10); + SetDifficulty(0); + SetHelp("Syntax: <cast whip>\n\n" + "This spell conjures a whip made of magical energy and " + "moves it to a wielding limb. If unwielded, it will vanish. " + "The power of the whip as a weapon depends on your spellcasting " + "abilities."); +} + +varargs int CanCast(object who, int level, string limb, object array targets){ + object *whips = filter(all_inventory(this_player()), + (: base_name($1) == "/obj/whip" :) ); + if(sizeof(whips)){ + write("You already have an energy whip."); + return 0; + } + return ::CanCast(who, level, limb, targets); +} + +varargs int eventCast(object who, int level, string limb, object array targs){ + object whip; + object *limbs = this_player()->GetWieldingLimbs(); + whip = new("/obj/whip"); + write("You make a powerful motion with your hand and conjure "+ + "an energy whip!"); + say(this_player()->GetName()+" makes a powerful motion with "+ + possessive(this_player())+" hand and conjures "+ + "an energy whip!"); + whip->eventMove(this_player()); + limbs = filter(limbs, (: !(this_player()->GetWielded($1)) :) ); + if(sizeof(limbs)){ + int weapclass = (this_player()->GetLevel()); + weapclass += (this_player()->GetStatLevel("intelligence") / 4); + weapclass += (this_player()->GetSpellLevel("whip") / 10); + weapclass += (this_player()->GetSkillLevel("magic attack") / 3); + weapclass += (this_player()->GetSkillLevel("conjuring") / 3); + whip->eventEquip(this_player(),limbs[0]); + whip->SetClass(weapclass); + whip->SetDuration(this_player()->GetSkillLevel("conjuring") * 20); + } + return 1; +} + diff --git a/lib/realms/babylon/.plan b/lib/realms/babylon/.plan new file mode 100644 index 0000000..8ab30f1 --- /dev/null +++ b/lib/realms/babylon/.plan @@ -0,0 +1 @@ +This is an empty plan file. diff --git a/lib/realms/babylon/.profile b/lib/realms/babylon/.profile new file mode 100644 index 0000000..1422b00 --- /dev/null +++ b/lib/realms/babylon/.profile @@ -0,0 +1,3 @@ +people +uptime +boards diff --git a/lib/realms/babylon/adm/remote.c b/lib/realms/babylon/adm/remote.c new file mode 100644 index 0000000..4981cff --- /dev/null +++ b/lib/realms/babylon/adm/remote.c @@ -0,0 +1,6 @@ +#include <lib.h> +inherit LIB_REMOTE; + +void create(){ + remote::create(); +} diff --git a/lib/realms/babylon/area/armor/chainmail.c b/lib/realms/babylon/area/armor/chainmail.c new file mode 100644 index 0000000..4c35915 --- /dev/null +++ b/lib/realms/babylon/area/armor/chainmail.c @@ -0,0 +1,19 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("chainmail shirt"); + SetId(({"armor","chainmail","mail","shirt","chain mail"})); + SetAdjectives(({"chainmail","sturdy","sturdy-looking","chain mail"})); + SetShort("a sturdy-looking chainmail shirt"); + SetLong("This is a shirt made of small, thin metal rings fashioned together as armor. "); + SetMass(500); + SetBaseCost(1000); + SetDamagePoints(100); + SetProtection(BLUNT,4); + SetProtection(BLADE,25); + SetProtection(KNIFE,25); + SetArmorType(A_ARMOR); +} diff --git a/lib/realms/babylon/area/armor/leather_boot_l.c b/lib/realms/babylon/area/armor/leather_boot_l.c new file mode 100644 index 0000000..a4b559f --- /dev/null +++ b/lib/realms/babylon/area/armor/leather_boot_l.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("leather boot"); + SetId(({"boot","leather boot"})); + SetAdjectives( ({"leather","strong","tough","left"}) ); + SetShort("a leather boot"); + SetLong("This is the leather combat boot of a professional soldier. "+ + "It is very thick and very strong. It is designed for wear on the left foot."); + SetMass(50); + SetBaseCost(50); + SetDamagePoints(20); + SetProtection(BLUNT,10); + SetProtection(BLADE,20); + SetProtection(KNIFE,20); + SetArmorType(A_BOOT); + SetRestrictLimbs(({"left foot"})); +} diff --git a/lib/realms/babylon/area/armor/leather_boot_r.c b/lib/realms/babylon/area/armor/leather_boot_r.c new file mode 100644 index 0000000..f6fdc78 --- /dev/null +++ b/lib/realms/babylon/area/armor/leather_boot_r.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("leather boot"); + SetId(({"boot","leather boot"})); + SetAdjectives( ({"leather","strong","tough","right"}) ); + SetShort("a leather boot"); + SetLong("This is the leather combat boot of a professional soldier. "+ + "It is very thick and very strong. It is designed for wear on the right foot."); + SetMass(50); + SetBaseCost(50); + SetDamagePoints(20); + SetProtection(BLUNT,10); + SetProtection(BLADE,20); + SetProtection(KNIFE,20); + SetArmorType(A_BOOT); + SetRestrictLimbs(({"right foot"})); +} diff --git a/lib/realms/babylon/area/customdefs.h b/lib/realms/babylon/area/customdefs.h new file mode 100644 index 0000000..620b5a0 --- /dev/null +++ b/lib/realms/babylon/area/customdefs.h @@ -0,0 +1,18 @@ +#ifndef r_mydirs_h +#define r_mydirs_h + + +#define MY_DIR "/realms/babylon" +#define MY_CMDS MY_DIR "/cmds" +#define MY_LOG MY_DIR "/log" +#define MY_AREA MY_DIR "/area" +#define MY_WEAP MY_AREA "/weap" +#define MY_ROOM MY_AREA "/room" +#define MY_OBJ MY_AREA "/obj" +#define MY_ARMOR MY_AREA "/armor" +#define MY_NPC MY_AREA "/npc" +#define MY_DOORS MY_AREA "/doors" +#define MY_MEALS MY_AREA "/meals" +#define MY_ETC MY_AREA "/etc" + +#endif /* r_mydirs_h */ diff --git a/lib/realms/babylon/area/npc/fighter.c b/lib/realms/babylon/area/npc/fighter.c new file mode 100644 index 0000000..f40be10 --- /dev/null +++ b/lib/realms/babylon/area/npc/fighter.c @@ -0,0 +1,41 @@ +#include <lib.h> +#include "/realms/babylon/area/customdefs.h" + +inherit LIB_NPC; +string privs; + +int AllowPass(object who, object what){ + if(who->GetKeyName() == privs) return 1; + return ::AllowPass(who, what); +} + +int CheckVisitor(object who){ + eventForce("say I'm sorry, "+remove_article(who->GetShort())+ + ". Only "+capitalize(privs)+" is allowed there."); + return 1; +} + +static void create(){ + npc::create(); + privs = query_privs(); + SetKeyName("fighter"); + SetId( ({"human","npc","warrior","fighter"}) ); + SetShort("a fighter"); + SetLong("This is a sample warrior NPC."); + SetLevel(10); + SetRace("human"); + SetClass("fighter"); + SetGender("male"); + SetInventory(([ + MY_ARMOR "/chainmail.c" : "wear chainmail", + MY_ARMOR "/leather_boot_r.c" : "wear boot", + MY_ARMOR "/leather_boot_l.c" : "wear boot", + MY_WEAP "/sword.c" : "wield sword", + ])); + SetStat("strength",40); + SetGuard("west", (: CheckVisitor :)); + SetGuard("east", "The fighter blocks your travel in that direction."); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/area/npc/thing.c b/lib/realms/babylon/area/npc/thing.c new file mode 100644 index 0000000..bf4a575 --- /dev/null +++ b/lib/realms/babylon/area/npc/thing.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("generic npc"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"non player"})); + SetShort("a generic npc"); + SetLong("Other than being human, this npc is entirely unremarkable."); + SetLevel(1); + SetMelee(1); + SetRace("human"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/area/obj/case.c b/lib/realms/babylon/area/obj/case.c new file mode 100644 index 0000000..b3d344c --- /dev/null +++ b/lib/realms/babylon/area/obj/case.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include "../customdefs.h" + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("case"); + SetId( ({ "container" }) ); + SetAdjectives( ({ "generic","nondescript" }) ); + SetShort("a glass case"); + SetLong("This is an expensive looking, ornamented glass case. It looks perfect for storing trophies or jewelry for display. It is an example of a transparent container."); + SetInventory(([ + MY_AREA "/obj/watch" : 1, + ])); + SetOpacity(10); + SetCanClose(1); + SetClosed(1); + SetMass(274); + SetBaseCost("silver",1); + SetMaxCarry(500); +} +void init(){ + ::init(); +} + +mixed CanGet(object ob) { return "The case does not budge.";} diff --git a/lib/realms/babylon/area/obj/chest.c b/lib/realms/babylon/area/obj/chest.c new file mode 100644 index 0000000..a12d480 --- /dev/null +++ b/lib/realms/babylon/area/obj/chest.c @@ -0,0 +1,41 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("chest"); + SetId(({"chest","wooden chest"})); + SetShort("a wooden chest"); + SetLong("This is a sturdy wooden chest used to store valuable items.\n"+ + "It is an example of an opaque container."); + SetInventory(([ + "/domains/town/armor/collar" : 1, + "/domains/default/armor/breather" : 1, + "/domains/default/armor/badge" : 1, + "/domains/default/armor/wizard_hat" : 1, + "/domains/default/obj/manual" : 1, + "/secure/obj/machine" : 1, + "/domains/default/obj/gps" : 1, + "/domains/default/armor/robe" : 1, + "/domains/default/obj/meter" : 1, + "/secure/obj/control" : 1, + "/secure/obj/memo" : 1, + "/secure/obj/staff" : 1, + "/domains/default/obj/pinger" : 1, + "/secure/obj/medtric" : 1, + "/secure/obj/glasses" : 1, + "/domains/default/armor/jade_ring" : 1, + "/domains/default/armor/gray_amulet" : 1, + ])); + SetMass(2000); + SetBaseCost(50); + SetMaxCarry(10000); + SetCanClose(1); + SetClosed(1); + SetPreventGet("The chest does not budge."); +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/area/obj/cup.c b/lib/realms/babylon/area/obj/cup.c new file mode 100644 index 0000000..f33fb2c --- /dev/null +++ b/lib/realms/babylon/area/obj/cup.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> +inherit LIB_FLASK; + +void create(){ + ::create(); + SetKeyName("cup"); + SetId( ({"cup", "cup made of wood"}) ); + SetAdjectives( ({"simple","wooden"}) ); + SetShort("a wooden cup"); + SetLong("A simple cup made of wood, for containing fluids."); + SetMass(5); + SetBaseCost("silver",1); + SetVendorType(VT_TREASURE); + SetFlaskUses(0); + SetStrength(5); + SetMaxFlask(1); + SetMealType(MEAL_DRINK); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/area/obj/key.c b/lib/realms/babylon/area/obj/key.c new file mode 100644 index 0000000..b3cb6a6 --- /dev/null +++ b/lib/realms/babylon/area/obj/key.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_ITEM; + + +static void create() { + item::create(); + SetKeyName("key"); + SetId( ({ "key", "sample key" }) ); + SetAdjectives( ({ "simple","sample" }) ); + SetShort("a sample key"); + SetLong("It is a simple sample key with no markings."); + SetMass(50); + SetBaseCost(1); + SetDisableChance(100); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/area/obj/pitcher.c b/lib/realms/babylon/area/obj/pitcher.c new file mode 100644 index 0000000..9d8fae2 --- /dev/null +++ b/lib/realms/babylon/area/obj/pitcher.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> +inherit LIB_FLASK; + +void create(){ + ::create(); + SetKeyName("pitcher"); + SetId( ({"pitcher", "vessel", "pitcher made of clay"}) ); + SetAdjectives( ({"small","clay","vessel"}) ); + SetShort("a small clay pitcher"); + SetLong("A small, clay vessel for containing fluids. You may "+ + "want to \"pour from pitcher into cup\"."); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetFlaskContents("water"); + SetFlaskUses(2); + SetStrength(5); + SetMaxFlask(3); + SetMealType(MEAL_DRINK); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/area/obj/table.c b/lib/realms/babylon/area/obj/table.c new file mode 100644 index 0000000..e6277b6 --- /dev/null +++ b/lib/realms/babylon/area/obj/table.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include "../customdefs.h" + +inherit LIB_TABLE; + + +void create() { + ::create(); + SetKeyName("sample table"); + SetId( ({ "table" ,"sample table"}) ); + SetAdjectives( ({ "simple","sample" }) ); + SetShort("a simple table"); + SetLong("It is a simple sample table. It is an example of a \"surface\" "+ + "type container."); + SetBaseCost(1200); + SetMaxCarry(5000); + SetInventory( ([ + MY_OBJ "/key" : 1, + MY_OBJ "/pitcher" : 1, + MY_OBJ "/cup" : 1, + ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/area/obj/watch.c b/lib/realms/babylon/area/obj/watch.c new file mode 100644 index 0000000..edc36dd --- /dev/null +++ b/lib/realms/babylon/area/obj/watch.c @@ -0,0 +1,68 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <localtime.h> +#include <daemons.h> + +inherit LIB_ARMOR; + +int eventReadWatch(); + +static void create(){ + armor::create(); + SetKeyName("pocket watch"); + SetId(({"watch","pocketwatch","pocket watch","timepiece"})); + SetShort("a pocket watch"); + SetLong("This is a beautifully decorated and intricately carved "+ + "pocket watch. It glows with a bright, polished bronze "+ + "luster. It is quietly ticking the seconds, and it looks like you can get the "+ + "accurate time by reading the watch."); + SetMass(10); + SetBaseCost("silver",40); + SetProtection(BLUNT,1); + SetProtection(BLADE,1); + SetProtection(KNIFE,1); + SetArmorType(A_AMULET); + SetDefaultRead( (: eventReadWatch :) ); +} +void init(){ + ::init(); +} + +int eventReadWatch(){ + int hour, minutes; + int *time_of_day; + string hour_string, minute_string; + + time_of_day = SEASONS_D->GetMudTime(); + hour = time_of_day[0]; + minutes = time_of_day[1]; + + if(hour > 12) hour -= 12; + + hour_string = cardinal(hour); + switch(minutes){ + case 0 : minute_string ="o'clock"; break; + case 1 : minute_string = hour_string;hour_string ="one minute past"; break; + case 2 : minute_string = hour_string;hour_string ="two minutes past"; break; + case 3 : minute_string = hour_string;hour_string ="three minutes past"; break; + case 4 : minute_string = hour_string;hour_string ="four minutes past"; break; + case 5 : minute_string = hour_string;hour_string ="five past"; break; + case 6 : minute_string = hour_string;hour_string ="six minutes past"; break; + case 7 : minute_string = hour_string;hour_string ="seven minutes past"; break; + case 8 : minute_string = hour_string;hour_string ="eight minutes past"; break; + case 9 : minute_string = hour_string;hour_string ="nine minutes past"; break; + case 10 : minute_string = hour_string;hour_string ="ten past"; break; + case 15 : minute_string = hour_string;hour_string ="quarter past"; break; + case 45 : minute_string = cardinal(hour+1);hour_string ="quarter of"; break; + case 50 : minute_string = cardinal(hour+1);;hour_string ="ten of"; break; + case 55 : minute_string = cardinal(hour+1);hour_string ="five of"; break; + default : minute_string = cardinal(minutes);break; + } + + if(minute_string == "thirteen") minute_string = "one"; + + write("According to the watch, it is "+hour_string+" "+minute_string+"."); + + return 1; +} diff --git a/lib/realms/babylon/area/room/room1.c b/lib/realms/babylon/area/room/room1.c new file mode 100644 index 0000000..8607596 --- /dev/null +++ b/lib/realms/babylon/area/room/room1.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include "/realms/babylon/area/customdefs.h" + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("copy of sample_room.c"); + SetLong("This is a room you can use as a template."); + SetItems( ([ + "template" : "That's what this is.", + ]) ); + SetExits( ([ + "north" : "/realms/babylon/area/room/sample_room", + "west" : "/realms/babylon/area/room/room2", + ]) ); + + SetInventory( ([ + MY_OBJ "/table" : 1, + MY_NPC "/fighter" : 1, + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/area/room/room2.c b/lib/realms/babylon/area/room/room2.c new file mode 100644 index 0000000..9f6ddf6 --- /dev/null +++ b/lib/realms/babylon/area/room/room2.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include "/realms/babylon/area/customdefs.h" + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("a whole new room"); + SetLong("This is an entirely different place."); + SetItems( ([ + "template" : "That's what this is.", + ]) ); + SetExits( ([ + "east" : "/realms/babylon/area/room/room1", + ]) ); + SetInventory(([ + "/realms/babylon/area/npc/grunthol" : 2, + "/realms/babylon/area/obj/table" : 1, + ])); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/area/room/sample_room.c b/lib/realms/babylon/area/room/sample_room.c new file mode 100644 index 0000000..97c0437 --- /dev/null +++ b/lib/realms/babylon/area/room/sample_room.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include "/realms/babylon/area/customdefs.h" + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Sample Room"); + SetLong("This is a room you can use as a template."); + SetItems( ([ + "template" : "That's what this is.", + ]) ); + SetExits( ([ + "east" : "/realms/babylon/area/room/sample_two", + "west" : "/realms/babylon/workroom", + "south" : "/realms/babylon/area/room/room1.c", + ]) ); + SetInventory( ([ + MY_OBJ "/table" : 1, + MY_NPC "/fighter" : 1, + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/area/room/sample_two.c b/lib/realms/babylon/area/room/sample_two.c new file mode 100644 index 0000000..e3c45f9 --- /dev/null +++ b/lib/realms/babylon/area/room/sample_two.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include "../customdefs.h" + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Second Sample Room"); + SetLong("This is another sample room."); + SetItems( ([ + "template" : "That's what this is.", + ]) ); + SetInventory(([ + MY_OBJ "/case" :1, + ])); + SetExits(([ + "west" : MY_AREA "/room/sample_room", + ])); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/area/weap/sword.c b/lib/realms/babylon/area/weap/sword.c new file mode 100644 index 0000000..6a48b57 --- /dev/null +++ b/lib/realms/babylon/area/weap/sword.c @@ -0,0 +1,20 @@ +#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" }) ); + SetAdjectives( ({ "short" }) ); + SetShort("a short sword"); + SetLong("A cheap and rather dull short sword."); + SetMass(300); + SetBaseCost(50); + SetVendorType(VT_WEAPON); + SetClass(20); + SetDamageType(BLADE); + SetWeaponType("blade"); +} diff --git a/lib/realms/babylon/bak/bk.db b/lib/realms/babylon/bak/bk.db new file mode 100644 index 0000000..ac77191 --- /dev/null +++ b/lib/realms/babylon/bak/bk.db @@ -0,0 +1 @@ +workroom.orig : /realms/babylon/workroom.c diff --git a/lib/realms/babylon/bak/workroom.orig b/lib/realms/babylon/bak/workroom.orig new file mode 100644 index 0000000..60b89f1 --- /dev/null +++ b/lib/realms/babylon/bak/workroom.orig @@ -0,0 +1,130 @@ +#include <lib.h> +#include ROOMS_H +#include "./area/customdefs.h" + +inherit LIB_ROOM; +int ReadSign(); +int ReadSheet(); +int privacy = 0; +string privs = ""; +string LongString(){ + string ret = "You are standing in the workroom of the mighty " + privs + + "! \nYou may return to the Creators' Hall by going down.\n"+ + "A sample room is east."+ + "\n%^GREEN%^There is a sign here you can read.%^RESET%^"+ + "\n%^GREEN%^There is a sheet here you can read.%^RESET%^"; + if(privacy) ret += "\n%^YELLOW%^There is a privacy force field "+ + "active around this room.%^RESET%^"; + return ret; +} + +static void create() { + room::create(); + privs = query_privs(); + if( privs ) privs = capitalize(privs); + else privs = "a creator"; + + SetClimate("indoors"); + SetAmbientLight(40); + SetShort(possessive_noun(privs) + " workroom"); + SetLong( (: LongString :) ); + SetItems( ([ "workroom" : "It looks very nice.", + ({"sign","hint","hints"}) : "A sign with hints for creators.", + ({"sheet","reminder","reminders"}) : "A sheet with quick reminders for creators.", + ]) ); + SetRead( ([ + ({"sign","hint","hints"}) : (: ReadSign :), + ({"sheet","reminder","reminders"}) : (: ReadSheet :) + ]) ); + SetInventory( ([ + MY_OBJ "/chest" : 1, + "/domains/default/obj/bbucket" :1, + ]) ); + SetExits( ([ "down" : "/domains/default/room/wiz_hall.c", + "east" : MY_ROOM "/sample_room" + ]) ); + SetNoModify(0); +} + +int ReadSign(){ + this_player()->eventPage("/news/hints.txt"); + return 1; +} + +int ReadSheet(){ + this_player()->eventPage("/news/reminders.txt"); + return 1; +} + +void init(){ + ::init(); + add_action("mod_privacy","privacy"); + add_action("mod_privacy","priv"); +} + +int CanReceive(object sneak) { + int ret; + object *living_stack; + if(!privacy) return ::CanReceive(sneak); + living_stack = get_livings(sneak); + if(!living_stack || !arrayp(living_stack)) living_stack = ({ sneak }); + foreach(object ob in living_stack){ + if(!archp(ob) && ob->GetKeyName() != lower_case(privs)){ + message("info","You bounce off the privacy field.", ob); + message("info",ob->GetName()+" bounced off the privacy field.", + this_object()); + if(!environment(ob)) ob->eventMoveLiving(ROOM_START); + return 0; + } + } + ret = ::CanReceive(sneak); + if(ret){ + tell_room(this_object(), "\n\nPRIVACY WARNING: "+identify(sneak)+ + " has entered the room.\n\n", sneak); + } + return ret; +} + +static int set_privacy(int i){ + object *npcs = filter(deep_inventory(this_object()), + (: living($1) && !interactive($1) :) ); + privacy=i; + SetProperty("no peer", i); + if(sizeof(npcs)){ + foreach(object npc in npcs){ + tell_room(this_object(),"Ejecting "+identify(npc),npc); + npc->eventMove(ROOM_FURNACE); + } + } + return i; +} + +int mod_privacy(string str){ + if(!archp(this_player()) && + this_player()->GetKeyName() != lower_case(privs)) { + write("You lack the adequate privileges to do that."); + tell_room(this_object(), this_player()->GetName()+" is "+ + "trying to muck around with the privacy field system."); + return 1; + } + if(!str || str == ""){ + if(privacy) str = "off"; + else str = "on"; + } + if(str=="on" || str == "1"){ + set_privacy(1); + write("You enable the privacy field.\n"); + say(this_player()->GetName()+" enables a privacy force field " + "around the room."); + return 1; + } + if(str=="off" || str == "0"){ + set_privacy(0); + write("You disable the privacy field.\n"); + say(this_player()->GetName()+" disables a privacy force field " + "around the room."); + return 1; + } +} + + diff --git a/lib/realms/babylon/cmds/custom.c b/lib/realms/babylon/cmds/custom.c new file mode 100644 index 0000000..1e4b964 --- /dev/null +++ b/lib/realms/babylon/cmds/custom.c @@ -0,0 +1,10 @@ + +#include <lib.h> + +inherit LIB_DAEMON; + +mixed cmd(string str) { + return "This is your own, personal command."; +} + + diff --git a/lib/realms/babylon/evaldefs.h b/lib/realms/babylon/evaldefs.h new file mode 100644 index 0000000..3279a26 --- /dev/null +++ b/lib/realms/babylon/evaldefs.h @@ -0,0 +1,12 @@ +#ifndef TP +#define TP this_player() +#endif +#ifndef ENV +#define ENV environment(this_player()) +#endif +#ifndef HERE +#define HERE room_environment(this_player()) +#endif +#define THING(x) (get_object(x)) +#define PRES(x) (present(x, TP) || present(x, ENV) ) +#define FILE(x) (present_file(x, TP) || present_file(x, ENV) ) diff --git a/lib/realms/babylon/tmp/abbgajkf1599368494.c b/lib/realms/babylon/tmp/abbgajkf1599368494.c new file mode 100644 index 0000000..9a40b1f --- /dev/null +++ b/lib/realms/babylon/tmp/abbgajkf1599368494.c @@ -0,0 +1,14 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area."); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/aelgkhcn1599125291.c b/lib/realms/babylon/tmp/aelgkhcn1599125291.c new file mode 100644 index 0000000..f2ea5f7 --- /dev/null +++ b/lib/realms/babylon/tmp/aelgkhcn1599125291.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetAmbientLight(30); + SetShort("tangled bushes"); + SetLong("the bushes are unkempt, and there appears to be ooga poo under one"); + SetItems(([ + ({ "poo", "ooga poo", "poop", "shit", "turd" }) : "This is some poo an ooga left under the bush", + "town" : "The main town.", + "tutorial" : "A set of rooms to get familiar with this environment.", + ])); + SetSmell(([ + ({ "ooga poo", "poo", "poop", "shit", "turd" }) : "This smells awful, it's not fresh but that makes it worse, the scent is almost enough to knock you over.", + ])); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/aemagokh1599125291.c b/lib/realms/babylon/tmp/aemagokh1599125291.c new file mode 100644 index 0000000..9a40b1f --- /dev/null +++ b/lib/realms/babylon/tmp/aemagokh1599125291.c @@ -0,0 +1,14 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area."); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/aimboahd1599392793.c b/lib/realms/babylon/tmp/aimboahd1599392793.c new file mode 100644 index 0000000..5dc2a62 --- /dev/null +++ b/lib/realms/babylon/tmp/aimboahd1599392793.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("tangled bushes"); + SetLong("the bushes are unkempt, and there appears to be ooga poo under one"); + SetItems(([ + ({ "poo", "ooga poo", "poop", "shit", "turd" }) : "This is some poo an ooga left under the bush", + ])); + + SetTown("oogtopia"); + SetSmell(([ + ({ "ooga poo", "poo", "poop", "shit", "turd" }) : "This smells awful, it's not fresh but that makes it worse, the scent is almost enough to knock you over.", + ])); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/ajbnmdmo1599134379.c b/lib/realms/babylon/tmp/ajbnmdmo1599134379.c new file mode 100644 index 0000000..9a40b1f --- /dev/null +++ b/lib/realms/babylon/tmp/ajbnmdmo1599134379.c @@ -0,0 +1,14 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area."); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/ajcafofm1599111753.c b/lib/realms/babylon/tmp/ajcafofm1599111753.c new file mode 100644 index 0000000..13ee3e8 --- /dev/null +++ b/lib/realms/babylon/tmp/ajcafofm1599111753.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include "/realms/babylon/area/customdefs.h" + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("a whole new room"); + SetLong("This is an entirely different place."); + SetItems( ([ + "template" : "That's what this is.", + ]) ); + SetInventory(([ + "/realms/babylon/area/npc/grunthol" : 2, + "/realms/babylon/area/obj/table" : 1, + ])); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/akijihmj1599368475.c b/lib/realms/babylon/tmp/akijihmj1599368475.c new file mode 100644 index 0000000..9a40b1f --- /dev/null +++ b/lib/realms/babylon/tmp/akijihmj1599368475.c @@ -0,0 +1,14 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area."); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/ambfkned1599125848.c b/lib/realms/babylon/tmp/ambfkned1599125848.c new file mode 100644 index 0000000..9a40b1f --- /dev/null +++ b/lib/realms/babylon/tmp/ambfkned1599125848.c @@ -0,0 +1,14 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area."); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/aniedefc1599111741.c b/lib/realms/babylon/tmp/aniedefc1599111741.c new file mode 100644 index 0000000..8780885 --- /dev/null +++ b/lib/realms/babylon/tmp/aniedefc1599111741.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include "/realms/babylon/area/customdefs.h" + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("copy of sample_room.c"); + SetLong("This is a room you can use as a template."); + SetItems( ([ + "template" : "That's what this is.", + ]) ); + + SetInventory( ([ + MY_OBJ "/table" : 1, + MY_NPC "/fighter" : 1, + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/anljagmd1599367775.c b/lib/realms/babylon/tmp/anljagmd1599367775.c new file mode 100644 index 0000000..ac829ac --- /dev/null +++ b/lib/realms/babylon/tmp/anljagmd1599367775.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("a stairwell"); + SetLong("You are standing in a stairwell on the volunteer deck of the USS Profit, You can go up to the command deck or down to the engine section. There are doors which are usually locked at the top and bottom of the stairs."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/babylonbboklfib1599367789.c b/lib/realms/babylon/tmp/babylonbboklfib1599367789.c new file mode 100644 index 0000000..fe7e8a9 --- /dev/null +++ b/lib/realms/babylon/tmp/babylonbboklfib1599367789.c @@ -0,0 +1,32 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("a stairwell"); + SetLong("You are standing in a stairwell on the volunteer deck of the USS Profit, You can go up to the command deck or down to the engine section. There are doors which are usually locked at the top and bottom of the stairs."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + SetExits( ([ + "south" : "/domains/voluntaria/room/hallway2", + "up" : "/domains/voluntaria/room/topstair.c", + ]) ); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/babylonbiimoecg1599368706.c b/lib/realms/babylon/tmp/babylonbiimoecg1599368706.c new file mode 100644 index 0000000..4d936c9 --- /dev/null +++ b/lib/realms/babylon/tmp/babylonbiimoecg1599368706.c @@ -0,0 +1,33 @@ +#include <lib.h> +#include <medium.h> +#include <terrain_types.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetTerrainType(T_SPACE); + SetMedium(MEDIUM_SPACE); + SetShort("copy of space.c"); + SetLong("You are drifting in outerspace, near the Voluntaryist spaceship the USS profit. If you are not wearing a spacesuit you are going to die very soon"); + SetItems(([ + ({ "spaceship", "airlock", "ship", "USS profit" }) : "The spaceship was built by the lowest bidder and flown on repeated missions to gather volunteers, it's amazing it hasn't already exploded.", + ])); + SetExits(([ + "down" : "/domains/voluntaria/room/space", + ])); + + SetEnters( ([ + "spaceship" : "/domains/voluntaria/room/airlock.c", + ]) ); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/babylonceejjhgj1599279861.c b/lib/realms/babylon/tmp/babylonceejjhgj1599279861.c new file mode 100644 index 0000000..6fad960 --- /dev/null +++ b/lib/realms/babylon/tmp/babylonceejjhgj1599279861.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include <medium.h> +#include <terrain_types.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetTerrainType(T_SPACE); + SetMedium(MEDIUM_SPACE); + SetShort("The empty vastness of space"); + SetLong("You are drifting in outerspace, near the Voluntaryist spaceship the USS profit. If you are not wearing a spacesuit you are going to die very soon"); + SetItems(([ + ({ "spaceship", "airlock", "ship", "USS profit" }) : "The spaceship was built by the lowest bidder and flown on repeated missions to gather volunteers, it's amazing it hasn't already exploded.", + ])); + SetExits(([ + ])); + SetEnters( ([ + "spaceship" : "/domains/voluntaria/room/airlock.c", + ]) ); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/babyloncombogba1599126783.c b/lib/realms/babylon/tmp/babyloncombogba1599126783.c new file mode 100644 index 0000000..6f5691e --- /dev/null +++ b/lib/realms/babylon/tmp/babyloncombogba1599126783.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("airlock"); + SetLong("an airlock in a Capitalist space ship. The walls are covered with advertizements and the sound of terms of service resonate through the air."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + SetExits(([ + "out" : "/domains/oogtopia/room/field", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/babylonddncknbo1599368706.c b/lib/realms/babylon/tmp/babylonddncknbo1599368706.c new file mode 100644 index 0000000..3b93ddd --- /dev/null +++ b/lib/realms/babylon/tmp/babylonddncknbo1599368706.c @@ -0,0 +1,32 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("An emergency exit on the command deck"); + SetLong("This emergency exit was put in to allow the captain to escape without going through the main airlock, the airlock to the south allows entrance to whatever planet the ship has landed on"); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + SetExits(([ + "north" : "/domains/voluntaria/room/commandhall", + "south" : "/domains/voluntaria/room/spaceup", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/babylondilefaac1599366865.c b/lib/realms/babylon/tmp/babylondilefaac1599366865.c new file mode 100644 index 0000000..19cf949 --- /dev/null +++ b/lib/realms/babylon/tmp/babylondilefaac1599366865.c @@ -0,0 +1,33 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("airlock"); + SetLong("an airlock in a Voluntaryist space ship. The walls are covered with advertizements and the sound of terms of service resonate through the air. The airlock is to your south, it shut when you entered the ship and the ship seems to have taken off, so be careful opening it."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + SetExits( ([ + "south" : "/domains/voluntaria/room/space", + "north" : "/domains/voluntaria/room/hallway.c", + ]) ); + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + + + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/babylondjccoffe1599367826.c b/lib/realms/babylon/tmp/babylondjccoffe1599367826.c new file mode 100644 index 0000000..9f1c877 --- /dev/null +++ b/lib/realms/babylon/tmp/babylondjccoffe1599367826.c @@ -0,0 +1,35 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("a stairwell"); + SetLong("You are standing in a stairwell on the volunteer deck of the USS Profit, You can go up to the command deck or down to the engine section. There are doors which are usually locked at the top and bottom of the stairs."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + SetExits( ([ + "south" : "/domains/voluntaria/room/hallway2", + "up" : "/domains/voluntaria/room/topstair", + "down" : "/domains/voluntaria/room/bottomstair.c", + ]) ); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + + SetDoor("up", "/domains/oogtopia/doors/commanddoor.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/babylonfdomafng1599367789.c b/lib/realms/babylon/tmp/babylonfdomafng1599367789.c new file mode 100644 index 0000000..a246a81 --- /dev/null +++ b/lib/realms/babylon/tmp/babylonfdomafng1599367789.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("copy of stairwell.c"); + SetLong("You are standing in a stairwell on the volunteer deck of the USS Profit, You can go up to the command deck or down to the engine section. There are doors which are usually locked at the top and bottom of the stairs."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + SetExits(([ + "down" : "/domains/voluntaria/room/stairwell", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/babylonhiaffima1599367826.c b/lib/realms/babylon/tmp/babylonhiaffima1599367826.c new file mode 100644 index 0000000..ee652bf --- /dev/null +++ b/lib/realms/babylon/tmp/babylonhiaffima1599367826.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("copy of stairwell.c"); + SetLong("You are standing in a stairwell on the volunteer deck of the USS Profit, You can go up to the command deck or down to the engine section. There are doors which are usually locked at the top and bottom of the stairs."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + SetExits(([ + "up" : "/domains/voluntaria/room/stairwell", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/babyloniklagfca1599280348.c b/lib/realms/babylon/tmp/babyloniklagfca1599280348.c new file mode 100644 index 0000000..e6ec210 --- /dev/null +++ b/lib/realms/babylon/tmp/babyloniklagfca1599280348.c @@ -0,0 +1,34 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("a crewpod"); + SetLong("This is where the crew of the USS Profit who have been tasked with handling the volunteers take their breaks"); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + SetExits(([ + "east" : "/domains/voluntaria/room/hallway", + ])); + SetInventory(([ + "/domains/voluntaria/npc/crapitalist" : 3, + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/babylonlmggaemm1599366865.c b/lib/realms/babylon/tmp/babylonlmggaemm1599366865.c new file mode 100644 index 0000000..54d9662 --- /dev/null +++ b/lib/realms/babylon/tmp/babylonlmggaemm1599366865.c @@ -0,0 +1,32 @@ +#include <lib.h> +#include <medium.h> +#include <terrain_types.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetTerrainType(T_SPACE); + SetMedium(MEDIUM_SPACE); + SetShort("The empty vastness of space"); + SetLong("You are drifting in outerspace, near the Voluntaryist spaceship the USS profit. If you are not wearing a spacesuit you are going to die very soon"); + SetItems(([ + ({ "spaceship", "airlock", "ship", "USS profit" }) : "The spaceship was built by the lowest bidder and flown on repeated missions to gather volunteers, it's amazing it hasn't already exploded.", + ])); + SetExits(([ + ])); + SetEnters( ([ + "spaceship" : "/domains/voluntaria/room/airlock.c", + ]) ); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/babylonnnnfonee1599280348.c b/lib/realms/babylon/tmp/babylonnnnfonee1599280348.c new file mode 100644 index 0000000..f184547 --- /dev/null +++ b/lib/realms/babylon/tmp/babylonnnnfonee1599280348.c @@ -0,0 +1,33 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("a hallway"); + SetLong("a hallway in a Voluntaryist space ship. The walls are covered with advertizements and the sound of terms of service resonate through the air."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + SetExits( ([ + "south" : "/domains/voluntaria/room/airlock", + "west" : "/domains/voluntaria/room/crewpod", + "north" : "/domains/voluntaria/room/hallway2.c", + ]) ); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/babylonoofhgglo1599279861.c b/lib/realms/babylon/tmp/babylonoofhgglo1599279861.c new file mode 100644 index 0000000..7aa84ef --- /dev/null +++ b/lib/realms/babylon/tmp/babylonoofhgglo1599279861.c @@ -0,0 +1,32 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("airlock"); + SetLong("an airlock in a Voluntaryist space ship. The walls are covered with advertizements and the sound of terms of service resonate through the air."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + SetExits( ([ + "out" : "/domains/voluntaria/room/space", + "north" : "/domains/voluntaria/room/hallway.c", + ]) ); + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/babylonooklifdl1599126783.c b/lib/realms/babylon/tmp/babylonooklifdl1599126783.c new file mode 100644 index 0000000..67443ac --- /dev/null +++ b/lib/realms/babylon/tmp/babylonooklifdl1599126783.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetAmbientLight(30); + SetShort("a grassy field"); + SetLong("a grassy field, much of the grass is scorched where a spaceship has landed."); + SetItems(([ + "spaceship" : "A grand spaceship, completely out of place in this primitive utopia", + ])); + SetEnters( ([ + "spaceship" : "/domains/oogtopia/room/airlock.c", + ]) ); + SetTown("oogtopia"); + SetExits(([ + "south" : "/domains/oogtopia/room/bushes", + ])); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/balmlhdk1599134379.c b/lib/realms/babylon/tmp/balmlhdk1599134379.c new file mode 100644 index 0000000..4d9a3e9 --- /dev/null +++ b/lib/realms/babylon/tmp/balmlhdk1599134379.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("tangled bushes"); + SetLong("the bushes are unkempt, and there appears to be ooga poo under one"); + SetItems(([ + ({ "poo", "ooga poo", "poop", "shit", "turd" }) : "This is some poo an ooga left under the bush", + ])); + SetTown("oogtopia"); + SetSmell(([ + ({ "ooga poo", "poo", "poop", "shit", "turd" }) : "This smells awful, it's not fresh but that makes it worse, the scent is almost enough to knock you over.", + ])); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/bbnajllm1599277833.c b/lib/realms/babylon/tmp/bbnajllm1599277833.c new file mode 100644 index 0000000..c58803b --- /dev/null +++ b/lib/realms/babylon/tmp/bbnajllm1599277833.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("a hallway"); + SetLong("a hallway in a Voluntaryist space ship. The walls are covered with advertizements and the sound of terms of service resonate through the air."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/bcogamln1599134451.c b/lib/realms/babylon/tmp/bcogamln1599134451.c new file mode 100644 index 0000000..9a40b1f --- /dev/null +++ b/lib/realms/babylon/tmp/bcogamln1599134451.c @@ -0,0 +1,14 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area."); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/bicjcdin1599367087.c b/lib/realms/babylon/tmp/bicjcdin1599367087.c new file mode 100644 index 0000000..ecbed1b --- /dev/null +++ b/lib/realms/babylon/tmp/bicjcdin1599367087.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include <medium.h> +#include <terrain_types.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetTerrainType(T_SPACE); + SetMedium(MEDIUM_SPACE); + SetShort("The empty vastness of space"); + SetLong("You are drifting in outerspace, near the Voluntaryist spaceship the USS profit. If you are not wearing a spacesuit you are going to die very soon"); + SetItems(([ + ({ "spaceship", "airlock", "ship", "USS profit" }) : "The spaceship was built by the lowest bidder and flown on repeated missions to gather volunteers, it's amazing it hasn't already exploded.", + ])); + SetEnters( ([ + "spaceship" : "/domains/voluntaria/room/airlock.c", + ]) ); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + + SetDoor("north", "/domains/oogtopia/doors/airlock.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/blhnjgbe1599134451.c b/lib/realms/babylon/tmp/blhnjgbe1599134451.c new file mode 100644 index 0000000..160a5c0 --- /dev/null +++ b/lib/realms/babylon/tmp/blhnjgbe1599134451.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("Tangled Bushes"); + SetLong("the bushes are unkempt, and there appears to be ooga poo under one"); + SetItems(([ + ({ "poo", "ooga poo", "poop", "shit", "turd" }) : "This is some poo an ooga left under the bush", + ])); + + SetTown("oogtopia"); + SetSmell(([ + ({ "ooga poo", "poo", "poop", "shit", "turd" }) : "This smells awful, it's not fresh but that makes it worse, the scent is almost enough to knock you over.", + ])); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/bnecjige1599123177.c b/lib/realms/babylon/tmp/bnecjige1599123177.c new file mode 100644 index 0000000..9ac3c1f --- /dev/null +++ b/lib/realms/babylon/tmp/bnecjige1599123177.c @@ -0,0 +1,34 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +int tutorial = 0; + +string DoDesc(){ + string desc = "Welcome! To enter Oogtopia, type: %^%^GREEN%^%^enter oogtopia%^%^RESET%^%^/n/n"; + string desc2 = "To enter a tutorial area, type: %^%^RED%^%^enter tutorial/n/n%^%^RESET%^%^"; + return desc + ( tutorial ? desc2 : ""); +} + +void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("copy of start.c"); + SetLong("This is party central, where the oogas get together to hang out and get wild."); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + SetItems( ([ + "tutorial" : "A set of rooms to get familiar with this environment.", + "town" : "The main town.", + ]) ); + + if(tutorial){ + AddEnter("tutorial", "/domains/tutorial/room/start"); + } +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/boialhlb1599368494.c b/lib/realms/babylon/tmp/boialhlb1599368494.c new file mode 100644 index 0000000..a0bed4b --- /dev/null +++ b/lib/realms/babylon/tmp/boialhlb1599368494.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("command deck hallway"); + SetLong("The command deck hallway extends from the stairs at the north end to the emergency exit at the south end. To the west is the bridge and to the east are the captains quarters"); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/caibhnih1599132791.c b/lib/realms/babylon/tmp/caibhnih1599132791.c new file mode 100644 index 0000000..9a40b1f --- /dev/null +++ b/lib/realms/babylon/tmp/caibhnih1599132791.c @@ -0,0 +1,14 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area."); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/cakddcmi1599110721.c b/lib/realms/babylon/tmp/cakddcmi1599110721.c new file mode 100644 index 0000000..8780885 --- /dev/null +++ b/lib/realms/babylon/tmp/cakddcmi1599110721.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include "/realms/babylon/area/customdefs.h" + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("copy of sample_room.c"); + SetLong("This is a room you can use as a template."); + SetItems( ([ + "template" : "That's what this is.", + ]) ); + + SetInventory( ([ + MY_OBJ "/table" : 1, + MY_NPC "/fighter" : 1, + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/canbclod1599123177.c b/lib/realms/babylon/tmp/canbclod1599123177.c new file mode 100644 index 0000000..049b3aa --- /dev/null +++ b/lib/realms/babylon/tmp/canbclod1599123177.c @@ -0,0 +1,33 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +int tutorial = 0; + +string DoDesc(){ + string desc = "Welcome! To enter Oogtopia, type: %^%^GREEN%^%^enter oogtopia%^%^RESET%^%^/n/n"; + string desc2 = "To enter a tutorial area, type: %^%^RED%^%^enter tutorial/n/n%^%^RESET%^%^"; + return desc + ( tutorial ? desc2 : ""); +} + +void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Ooga Booga Central"); + SetLong("This is party central, where the oogas get together to hang out and get wild."); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + SetItems( ([ + "tutorial" : "A set of rooms to get familiar with this environment.", + "town" : "The main town.", + ]) ); + if(tutorial){ + AddEnter("tutorial", "/domains/tutorial/room/start"); + } +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/ccikkcik1599392749.c b/lib/realms/babylon/tmp/ccikkcik1599392749.c new file mode 100644 index 0000000..b721524 --- /dev/null +++ b/lib/realms/babylon/tmp/ccikkcik1599392749.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("Ooga Booga Central"); + SetNightLong("This is where the Oogas have their parties, the sun is down and the party is in full swing. Drums, hooting and hollering, fermented drinks altough nothing distilled is permitted, and herbs and fungus of many varieties are all about."); + SetDayLong("This is where the Oogas get together and party, as long as the sun is up it's fairly sparsely attended, and any oogas around are likely nursing a hangover from the night before."); + SetInventory(([ + "/domains/oogtopia/npc/party_ooga" : 5, + ])); + + SetTown("oogtopia"); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/cckonhbo1599367805.c b/lib/realms/babylon/tmp/cckonhbo1599367805.c new file mode 100644 index 0000000..e59ce30 --- /dev/null +++ b/lib/realms/babylon/tmp/cckonhbo1599367805.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("a stairwell"); + SetLong("You are standing in a stairwell on the volunteer deck of the USS Profit, You can go up to the command deck or down to the engine section. There are doors which are usually locked at the top and bottom of the stairs."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + + SetDoor("up", "/domains/oogtopia/doors/commanddoor.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/cemeffdo1599277808.c b/lib/realms/babylon/tmp/cemeffdo1599277808.c new file mode 100644 index 0000000..9a40b1f --- /dev/null +++ b/lib/realms/babylon/tmp/cemeffdo1599277808.c @@ -0,0 +1,14 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area."); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/chjmijdd1599392793.c b/lib/realms/babylon/tmp/chjmijdd1599392793.c new file mode 100644 index 0000000..160a5c0 --- /dev/null +++ b/lib/realms/babylon/tmp/chjmijdd1599392793.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("Tangled Bushes"); + SetLong("the bushes are unkempt, and there appears to be ooga poo under one"); + SetItems(([ + ({ "poo", "ooga poo", "poop", "shit", "turd" }) : "This is some poo an ooga left under the bush", + ])); + + SetTown("oogtopia"); + SetSmell(([ + ({ "ooga poo", "poo", "poop", "shit", "turd" }) : "This smells awful, it's not fresh but that makes it worse, the scent is almost enough to knock you over.", + ])); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/cijkmamn1599125848.c b/lib/realms/babylon/tmp/cijkmamn1599125848.c new file mode 100644 index 0000000..1a5f371 --- /dev/null +++ b/lib/realms/babylon/tmp/cijkmamn1599125848.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetAmbientLight(30); + SetShort("a grassy field"); + SetLong("a grassy field, much of the grass is scorched where a spaceship has landed."); + SetItems(([ + "spaceship" : "A grand spaceship, completely out of place in this primitive utopia", + ])); + SetEnters( ([ + "spaceship" : "/domains/oogtopia/room/airlock.c", + ]) ); + SetTown("oogtopia"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/crapitalistjamaicfc1599276515.c b/lib/realms/babylon/tmp/crapitalistjamaicfc1599276515.c new file mode 100644 index 0000000..255ddd9 --- /dev/null +++ b/lib/realms/babylon/tmp/crapitalistjamaicfc1599276515.c @@ -0,0 +1,22 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("generic npc"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"non player"})); + SetShort("a generic npc"); + SetLong("Other than being human, this npc is entirely unremarkable."); + SetInventory(([ + "/domains/default/armor/breather" : "wear", + ])); + SetLevel(1); + SetMelee(1); + SetRace("ancap"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/crewpodkbfahlab1599278279.c b/lib/realms/babylon/tmp/crewpodkbfahlab1599278279.c new file mode 100644 index 0000000..29fa5ad --- /dev/null +++ b/lib/realms/babylon/tmp/crewpodkbfahlab1599278279.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("a crewpod"); + SetLong("This is where the crew of the USS Profit who have been tasked with handling the volunteers take their breaks"); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + SetExits(([ + "east" : "/domains/voluntaria/room/hallway", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/ddggfelm1599277808.c b/lib/realms/babylon/tmp/ddggfelm1599277808.c new file mode 100644 index 0000000..c58803b --- /dev/null +++ b/lib/realms/babylon/tmp/ddggfelm1599277808.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("a hallway"); + SetLong("a hallway in a Voluntaryist space ship. The walls are covered with advertizements and the sound of terms of service resonate through the air."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/ddnkadfi1599392646.c b/lib/realms/babylon/tmp/ddnkadfi1599392646.c new file mode 100644 index 0000000..160a5c0 --- /dev/null +++ b/lib/realms/babylon/tmp/ddnkadfi1599392646.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("Tangled Bushes"); + SetLong("the bushes are unkempt, and there appears to be ooga poo under one"); + SetItems(([ + ({ "poo", "ooga poo", "poop", "shit", "turd" }) : "This is some poo an ooga left under the bush", + ])); + + SetTown("oogtopia"); + SetSmell(([ + ({ "ooga poo", "poo", "poop", "shit", "turd" }) : "This smells awful, it's not fresh but that makes it worse, the scent is almost enough to knock you over.", + ])); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/dfeikhhm1599392617.c b/lib/realms/babylon/tmp/dfeikhhm1599392617.c new file mode 100644 index 0000000..4d9a3e9 --- /dev/null +++ b/lib/realms/babylon/tmp/dfeikhhm1599392617.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("tangled bushes"); + SetLong("the bushes are unkempt, and there appears to be ooga poo under one"); + SetItems(([ + ({ "poo", "ooga poo", "poop", "shit", "turd" }) : "This is some poo an ooga left under the bush", + ])); + SetTown("oogtopia"); + SetSmell(([ + ({ "ooga poo", "poo", "poop", "shit", "turd" }) : "This smells awful, it's not fresh but that makes it worse, the scent is almost enough to knock you over.", + ])); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/dnkgaegn1599123119.c b/lib/realms/babylon/tmp/dnkgaegn1599123119.c new file mode 100644 index 0000000..049b3aa --- /dev/null +++ b/lib/realms/babylon/tmp/dnkgaegn1599123119.c @@ -0,0 +1,33 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +int tutorial = 0; + +string DoDesc(){ + string desc = "Welcome! To enter Oogtopia, type: %^%^GREEN%^%^enter oogtopia%^%^RESET%^%^/n/n"; + string desc2 = "To enter a tutorial area, type: %^%^RED%^%^enter tutorial/n/n%^%^RESET%^%^"; + return desc + ( tutorial ? desc2 : ""); +} + +void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Ooga Booga Central"); + SetLong("This is party central, where the oogas get together to hang out and get wild."); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + SetItems( ([ + "tutorial" : "A set of rooms to get familiar with this environment.", + "town" : "The main town.", + ]) ); + if(tutorial){ + AddEnter("tutorial", "/domains/tutorial/room/start"); + } +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/eajmaalh1599392646.c b/lib/realms/babylon/tmp/eajmaalh1599392646.c new file mode 100644 index 0000000..9a40b1f --- /dev/null +++ b/lib/realms/babylon/tmp/eajmaalh1599392646.c @@ -0,0 +1,14 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area."); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/eefgkaog1599134451.c b/lib/realms/babylon/tmp/eefgkaog1599134451.c new file mode 100644 index 0000000..160a5c0 --- /dev/null +++ b/lib/realms/babylon/tmp/eefgkaog1599134451.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("Tangled Bushes"); + SetLong("the bushes are unkempt, and there appears to be ooga poo under one"); + SetItems(([ + ({ "poo", "ooga poo", "poop", "shit", "turd" }) : "This is some poo an ooga left under the bush", + ])); + + SetTown("oogtopia"); + SetSmell(([ + ({ "ooga poo", "poo", "poop", "shit", "turd" }) : "This smells awful, it's not fresh but that makes it worse, the scent is almost enough to knock you over.", + ])); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/egkbokli1599277833.c b/lib/realms/babylon/tmp/egkbokli1599277833.c new file mode 100644 index 0000000..9a40b1f --- /dev/null +++ b/lib/realms/babylon/tmp/egkbokli1599277833.c @@ -0,0 +1,14 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area."); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/elfdbaga1599123216.c b/lib/realms/babylon/tmp/elfdbaga1599123216.c new file mode 100644 index 0000000..049b3aa --- /dev/null +++ b/lib/realms/babylon/tmp/elfdbaga1599123216.c @@ -0,0 +1,33 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +int tutorial = 0; + +string DoDesc(){ + string desc = "Welcome! To enter Oogtopia, type: %^%^GREEN%^%^enter oogtopia%^%^RESET%^%^/n/n"; + string desc2 = "To enter a tutorial area, type: %^%^RED%^%^enter tutorial/n/n%^%^RESET%^%^"; + return desc + ( tutorial ? desc2 : ""); +} + +void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Ooga Booga Central"); + SetLong("This is party central, where the oogas get together to hang out and get wild."); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + SetItems( ([ + "tutorial" : "A set of rooms to get familiar with this environment.", + "town" : "The main town.", + ]) ); + if(tutorial){ + AddEnter("tutorial", "/domains/tutorial/room/start"); + } +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/enembidc1599367074.c b/lib/realms/babylon/tmp/enembidc1599367074.c new file mode 100644 index 0000000..9a40b1f --- /dev/null +++ b/lib/realms/babylon/tmp/enembidc1599367074.c @@ -0,0 +1,14 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area."); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/fkkfkidm1599276812.c b/lib/realms/babylon/tmp/fkkfkidm1599276812.c new file mode 100644 index 0000000..6b05173 --- /dev/null +++ b/lib/realms/babylon/tmp/fkkfkidm1599276812.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("airlock"); + SetLong("an airlock in a Capitalist space ship. The walls are covered with advertizements and the sound of terms of service resonate through the air."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + + SetDoor("out", "/domains/voluntaria/doors/airlock.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/gaabclmk1599123216.c b/lib/realms/babylon/tmp/gaabclmk1599123216.c new file mode 100644 index 0000000..9ac3c1f --- /dev/null +++ b/lib/realms/babylon/tmp/gaabclmk1599123216.c @@ -0,0 +1,34 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +int tutorial = 0; + +string DoDesc(){ + string desc = "Welcome! To enter Oogtopia, type: %^%^GREEN%^%^enter oogtopia%^%^RESET%^%^/n/n"; + string desc2 = "To enter a tutorial area, type: %^%^RED%^%^enter tutorial/n/n%^%^RESET%^%^"; + return desc + ( tutorial ? desc2 : ""); +} + +void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("copy of start.c"); + SetLong("This is party central, where the oogas get together to hang out and get wild."); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + SetItems( ([ + "tutorial" : "A set of rooms to get familiar with this environment.", + "town" : "The main town.", + ]) ); + + if(tutorial){ + AddEnter("tutorial", "/domains/tutorial/room/start"); + } +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/gaiblhok1599368475.c b/lib/realms/babylon/tmp/gaiblhok1599368475.c new file mode 100644 index 0000000..a0bed4b --- /dev/null +++ b/lib/realms/babylon/tmp/gaiblhok1599368475.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("command deck hallway"); + SetLong("The command deck hallway extends from the stairs at the north end to the emergency exit at the south end. To the west is the bridge and to the east are the captains quarters"); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/geamgjgo1599110513.c b/lib/realms/babylon/tmp/geamgjgo1599110513.c new file mode 100644 index 0000000..7d0cb0e --- /dev/null +++ b/lib/realms/babylon/tmp/geamgjgo1599110513.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include "/realms/babylon/area/customdefs.h" + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Sample Room"); + SetLong("This is a room you can use as a template."); + SetItems( ([ + "template" : "That's what this is.", + ]) ); + SetInventory( ([ + MY_OBJ "/table" : 1, + MY_NPC "/fighter" : 1, + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/goliehoh1599132777.c b/lib/realms/babylon/tmp/goliehoh1599132777.c new file mode 100644 index 0000000..4d9a3e9 --- /dev/null +++ b/lib/realms/babylon/tmp/goliehoh1599132777.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("tangled bushes"); + SetLong("the bushes are unkempt, and there appears to be ooga poo under one"); + SetItems(([ + ({ "poo", "ooga poo", "poop", "shit", "turd" }) : "This is some poo an ooga left under the bush", + ])); + SetTown("oogtopia"); + SetSmell(([ + ({ "ooga poo", "poo", "poop", "shit", "turd" }) : "This smells awful, it's not fresh but that makes it worse, the scent is almost enough to knock you over.", + ])); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/gruntholakclflka1599108876.c b/lib/realms/babylon/tmp/gruntholakclflka1599108876.c new file mode 100644 index 0000000..091eacc --- /dev/null +++ b/lib/realms/babylon/tmp/gruntholakclflka1599108876.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("grunthol"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"non player"})); + SetShort("grunthol"); + SetLong("Other than being human, this npc is entirely unremarkable."); + SetLevel(1); + SetMelee(1); + SetRace("ooga"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/gruntholfabiidol1599109114.c b/lib/realms/babylon/tmp/gruntholfabiidol1599109114.c new file mode 100644 index 0000000..ef4b01d --- /dev/null +++ b/lib/realms/babylon/tmp/gruntholfabiidol1599109114.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("generic npc"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"non player"})); + SetShort("a generic npc"); + SetLong("Other than being human, this npc is entirely unremarkable."); + SetLevel(1); + SetMelee(1); + SetRace("ooga"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/gruntholghkidjbe1599108846.c b/lib/realms/babylon/tmp/gruntholghkidjbe1599108846.c new file mode 100644 index 0000000..038d9a5 --- /dev/null +++ b/lib/realms/babylon/tmp/gruntholghkidjbe1599108846.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("grunthol"); + SetId(({"npc","mob","character","mobile"})); + SetAdjectives(({"non player"})); + SetShort("a generic npc"); + SetLong("Other than being human, this npc is entirely unremarkable."); + SetLevel(1); + SetMelee(1); + SetRace("ooga"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/hcjeddlm1599133455.c b/lib/realms/babylon/tmp/hcjeddlm1599133455.c new file mode 100644 index 0000000..b721524 --- /dev/null +++ b/lib/realms/babylon/tmp/hcjeddlm1599133455.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("Ooga Booga Central"); + SetNightLong("This is where the Oogas have their parties, the sun is down and the party is in full swing. Drums, hooting and hollering, fermented drinks altough nothing distilled is permitted, and herbs and fungus of many varieties are all about."); + SetDayLong("This is where the Oogas get together and party, as long as the sun is up it's fairly sparsely attended, and any oogas around are likely nursing a hangover from the night before."); + SetInventory(([ + "/domains/oogtopia/npc/party_ooga" : 5, + ])); + + SetTown("oogtopia"); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/hfjjibei1599367805.c b/lib/realms/babylon/tmp/hfjjibei1599367805.c new file mode 100644 index 0000000..9a40b1f --- /dev/null +++ b/lib/realms/babylon/tmp/hfjjibei1599367805.c @@ -0,0 +1,14 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area."); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/hfnbohmh1599368486.c b/lib/realms/babylon/tmp/hfnbohmh1599368486.c new file mode 100644 index 0000000..9a40b1f --- /dev/null +++ b/lib/realms/babylon/tmp/hfnbohmh1599368486.c @@ -0,0 +1,14 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area."); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/hjclmdfe1599133441.c b/lib/realms/babylon/tmp/hjclmdfe1599133441.c new file mode 100644 index 0000000..b721524 --- /dev/null +++ b/lib/realms/babylon/tmp/hjclmdfe1599133441.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("Ooga Booga Central"); + SetNightLong("This is where the Oogas have their parties, the sun is down and the party is in full swing. Drums, hooting and hollering, fermented drinks altough nothing distilled is permitted, and herbs and fungus of many varieties are all about."); + SetDayLong("This is where the Oogas get together and party, as long as the sun is up it's fairly sparsely attended, and any oogas around are likely nursing a hangover from the night before."); + SetInventory(([ + "/domains/oogtopia/npc/party_ooga" : 5, + ])); + + SetTown("oogtopia"); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/hjeaemoa1599368364.c b/lib/realms/babylon/tmp/hjeaemoa1599368364.c new file mode 100644 index 0000000..9a40b1f --- /dev/null +++ b/lib/realms/babylon/tmp/hjeaemoa1599368364.c @@ -0,0 +1,14 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area."); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/hkckdfcg1599272600.c b/lib/realms/babylon/tmp/hkckdfcg1599272600.c new file mode 100644 index 0000000..6b05173 --- /dev/null +++ b/lib/realms/babylon/tmp/hkckdfcg1599272600.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("airlock"); + SetLong("an airlock in a Capitalist space ship. The walls are covered with advertizements and the sound of terms of service resonate through the air."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + + SetDoor("out", "/domains/voluntaria/doors/airlock.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/hkknhjlm1599272619.c b/lib/realms/babylon/tmp/hkknhjlm1599272619.c new file mode 100644 index 0000000..6b05173 --- /dev/null +++ b/lib/realms/babylon/tmp/hkknhjlm1599272619.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("airlock"); + SetLong("an airlock in a Capitalist space ship. The walls are covered with advertizements and the sound of terms of service resonate through the air."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + + SetDoor("out", "/domains/voluntaria/doors/airlock.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/hnfhilji1599367087.c b/lib/realms/babylon/tmp/hnfhilji1599367087.c new file mode 100644 index 0000000..ecbed1b --- /dev/null +++ b/lib/realms/babylon/tmp/hnfhilji1599367087.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include <medium.h> +#include <terrain_types.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetTerrainType(T_SPACE); + SetMedium(MEDIUM_SPACE); + SetShort("The empty vastness of space"); + SetLong("You are drifting in outerspace, near the Voluntaryist spaceship the USS profit. If you are not wearing a spacesuit you are going to die very soon"); + SetItems(([ + ({ "spaceship", "airlock", "ship", "USS profit" }) : "The spaceship was built by the lowest bidder and flown on repeated missions to gather volunteers, it's amazing it hasn't already exploded.", + ])); + SetEnters( ([ + "spaceship" : "/domains/voluntaria/room/airlock.c", + ]) ); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + + SetDoor("north", "/domains/oogtopia/doors/airlock.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/hoohohlm1599368486.c b/lib/realms/babylon/tmp/hoohohlm1599368486.c new file mode 100644 index 0000000..a0bed4b --- /dev/null +++ b/lib/realms/babylon/tmp/hoohohlm1599368486.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("command deck hallway"); + SetLong("The command deck hallway extends from the stairs at the north end to the emergency exit at the south end. To the west is the bridge and to the east are the captains quarters"); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/iddinmjg1599123119.c b/lib/realms/babylon/tmp/iddinmjg1599123119.c new file mode 100644 index 0000000..9a40b1f --- /dev/null +++ b/lib/realms/babylon/tmp/iddinmjg1599123119.c @@ -0,0 +1,14 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area."); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/idmlehjc1599392617.c b/lib/realms/babylon/tmp/idmlehjc1599392617.c new file mode 100644 index 0000000..9a40b1f --- /dev/null +++ b/lib/realms/babylon/tmp/idmlehjc1599392617.c @@ -0,0 +1,14 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area."); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/igjfekad1599123167.c b/lib/realms/babylon/tmp/igjfekad1599123167.c new file mode 100644 index 0000000..049b3aa --- /dev/null +++ b/lib/realms/babylon/tmp/igjfekad1599123167.c @@ -0,0 +1,33 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +int tutorial = 0; + +string DoDesc(){ + string desc = "Welcome! To enter Oogtopia, type: %^%^GREEN%^%^enter oogtopia%^%^RESET%^%^/n/n"; + string desc2 = "To enter a tutorial area, type: %^%^RED%^%^enter tutorial/n/n%^%^RESET%^%^"; + return desc + ( tutorial ? desc2 : ""); +} + +void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Ooga Booga Central"); + SetLong("This is party central, where the oogas get together to hang out and get wild."); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + SetItems( ([ + "tutorial" : "A set of rooms to get familiar with this environment.", + "town" : "The main town.", + ]) ); + if(tutorial){ + AddEnter("tutorial", "/domains/tutorial/room/start"); + } +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/iiaiilbi1599132791.c b/lib/realms/babylon/tmp/iiaiilbi1599132791.c new file mode 100644 index 0000000..4d9a3e9 --- /dev/null +++ b/lib/realms/babylon/tmp/iiaiilbi1599132791.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("tangled bushes"); + SetLong("the bushes are unkempt, and there appears to be ooga poo under one"); + SetItems(([ + ({ "poo", "ooga poo", "poop", "shit", "turd" }) : "This is some poo an ooga left under the bush", + ])); + SetTown("oogtopia"); + SetSmell(([ + ({ "ooga poo", "poo", "poop", "shit", "turd" }) : "This smells awful, it's not fresh but that makes it worse, the scent is almost enough to knock you over.", + ])); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/iikmfoka1599367664.c b/lib/realms/babylon/tmp/iikmfoka1599367664.c new file mode 100644 index 0000000..c58803b --- /dev/null +++ b/lib/realms/babylon/tmp/iikmfoka1599367664.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("a hallway"); + SetLong("a hallway in a Voluntaryist space ship. The walls are covered with advertizements and the sound of terms of service resonate through the air."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/ilkdbhog1599367074.c b/lib/realms/babylon/tmp/ilkdbhog1599367074.c new file mode 100644 index 0000000..29053a6 --- /dev/null +++ b/lib/realms/babylon/tmp/ilkdbhog1599367074.c @@ -0,0 +1,32 @@ +#include <lib.h> +#include <medium.h> +#include <terrain_types.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetTerrainType(T_SPACE); + SetMedium(MEDIUM_SPACE); + SetShort("The empty vastness of space"); + SetLong("You are drifting in outerspace, near the Voluntaryist spaceship the USS profit. If you are not wearing a spacesuit you are going to die very soon"); + SetItems(([ + ({ "spaceship", "airlock", "ship", "USS profit" }) : "The spaceship was built by the lowest bidder and flown on repeated missions to gather volunteers, it's amazing it hasn't already exploded.", + ])); + SetEnters( ([ + "spaceship" : "/domains/voluntaria/room/airlock.c", + ]) ); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + + + SetDoor("north", "/domains/oogtopia/doors/airlock.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/jajnelfl1599110667.c b/lib/realms/babylon/tmp/jajnelfl1599110667.c new file mode 100644 index 0000000..8780885 --- /dev/null +++ b/lib/realms/babylon/tmp/jajnelfl1599110667.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include "/realms/babylon/area/customdefs.h" + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("copy of sample_room.c"); + SetLong("This is a room you can use as a template."); + SetItems( ([ + "template" : "That's what this is.", + ]) ); + + SetInventory( ([ + MY_OBJ "/table" : 1, + MY_NPC "/fighter" : 1, + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/jblfhjkl1599368475.c b/lib/realms/babylon/tmp/jblfhjkl1599368475.c new file mode 100644 index 0000000..a0bed4b --- /dev/null +++ b/lib/realms/babylon/tmp/jblfhjkl1599368475.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("command deck hallway"); + SetLong("The command deck hallway extends from the stairs at the north end to the emergency exit at the south end. To the west is the bridge and to the east are the captains quarters"); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/jclkomag1599392771.c b/lib/realms/babylon/tmp/jclkomag1599392771.c new file mode 100644 index 0000000..9a40b1f --- /dev/null +++ b/lib/realms/babylon/tmp/jclkomag1599392771.c @@ -0,0 +1,14 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area."); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/jemmclnn1599133467.c b/lib/realms/babylon/tmp/jemmclnn1599133467.c new file mode 100644 index 0000000..b721524 --- /dev/null +++ b/lib/realms/babylon/tmp/jemmclnn1599133467.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("Ooga Booga Central"); + SetNightLong("This is where the Oogas have their parties, the sun is down and the party is in full swing. Drums, hooting and hollering, fermented drinks altough nothing distilled is permitted, and herbs and fungus of many varieties are all about."); + SetDayLong("This is where the Oogas get together and party, as long as the sun is up it's fairly sparsely attended, and any oogas around are likely nursing a hangover from the night before."); + SetInventory(([ + "/domains/oogtopia/npc/party_ooga" : 5, + ])); + + SetTown("oogtopia"); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/jhncdnea1599110513.c b/lib/realms/babylon/tmp/jhncdnea1599110513.c new file mode 100644 index 0000000..89aac27 --- /dev/null +++ b/lib/realms/babylon/tmp/jhncdnea1599110513.c @@ -0,0 +1,17 @@ +#include <lib.h> +#include ROOMS_H + +#include "/realms/babylon/area/customdefs.h" + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area."); +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/jjcjgjdj1599125291.c b/lib/realms/babylon/tmp/jjcjgjdj1599125291.c new file mode 100644 index 0000000..f2ea5f7 --- /dev/null +++ b/lib/realms/babylon/tmp/jjcjgjdj1599125291.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetAmbientLight(30); + SetShort("tangled bushes"); + SetLong("the bushes are unkempt, and there appears to be ooga poo under one"); + SetItems(([ + ({ "poo", "ooga poo", "poop", "shit", "turd" }) : "This is some poo an ooga left under the bush", + "town" : "The main town.", + "tutorial" : "A set of rooms to get familiar with this environment.", + ])); + SetSmell(([ + ({ "ooga poo", "poo", "poop", "shit", "turd" }) : "This smells awful, it's not fresh but that makes it worse, the scent is almost enough to knock you over.", + ])); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/jmlboonh1599110721.c b/lib/realms/babylon/tmp/jmlboonh1599110721.c new file mode 100644 index 0000000..3273310 --- /dev/null +++ b/lib/realms/babylon/tmp/jmlboonh1599110721.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include "/realms/babylon/area/customdefs.h" + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("a whole new room"); + SetLong("This is an entirely different place."); + SetItems( ([ + "template" : "That's what this is.", + ]) ); + + SetInventory( ([ + MY_OBJ "/table" : 1, + MY_NPC "/fighter" : 1, + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/jnnhkefm1599123209.c b/lib/realms/babylon/tmp/jnnhkefm1599123209.c new file mode 100644 index 0000000..9ac3c1f --- /dev/null +++ b/lib/realms/babylon/tmp/jnnhkefm1599123209.c @@ -0,0 +1,34 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +int tutorial = 0; + +string DoDesc(){ + string desc = "Welcome! To enter Oogtopia, type: %^%^GREEN%^%^enter oogtopia%^%^RESET%^%^/n/n"; + string desc2 = "To enter a tutorial area, type: %^%^RED%^%^enter tutorial/n/n%^%^RESET%^%^"; + return desc + ( tutorial ? desc2 : ""); +} + +void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("copy of start.c"); + SetLong("This is party central, where the oogas get together to hang out and get wild."); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + SetItems( ([ + "tutorial" : "A set of rooms to get familiar with this environment.", + "town" : "The main town.", + ]) ); + + if(tutorial){ + AddEnter("tutorial", "/domains/tutorial/room/start"); + } +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/kdelggcf1599276812.c b/lib/realms/babylon/tmp/kdelggcf1599276812.c new file mode 100644 index 0000000..9a40b1f --- /dev/null +++ b/lib/realms/babylon/tmp/kdelggcf1599276812.c @@ -0,0 +1,14 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area."); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/kfdehibc1599134379.c b/lib/realms/babylon/tmp/kfdehibc1599134379.c new file mode 100644 index 0000000..4d9a3e9 --- /dev/null +++ b/lib/realms/babylon/tmp/kfdehibc1599134379.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("tangled bushes"); + SetLong("the bushes are unkempt, and there appears to be ooga poo under one"); + SetItems(([ + ({ "poo", "ooga poo", "poop", "shit", "turd" }) : "This is some poo an ooga left under the bush", + ])); + SetTown("oogtopia"); + SetSmell(([ + ({ "ooga poo", "poo", "poop", "shit", "turd" }) : "This smells awful, it's not fresh but that makes it worse, the scent is almost enough to knock you over.", + ])); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/kfjldkcj1599367664.c b/lib/realms/babylon/tmp/kfjldkcj1599367664.c new file mode 100644 index 0000000..9a40b1f --- /dev/null +++ b/lib/realms/babylon/tmp/kfjldkcj1599367664.c @@ -0,0 +1,14 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area."); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/kgofoeaj1599123209.c b/lib/realms/babylon/tmp/kgofoeaj1599123209.c new file mode 100644 index 0000000..049b3aa --- /dev/null +++ b/lib/realms/babylon/tmp/kgofoeaj1599123209.c @@ -0,0 +1,33 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +int tutorial = 0; + +string DoDesc(){ + string desc = "Welcome! To enter Oogtopia, type: %^%^GREEN%^%^enter oogtopia%^%^RESET%^%^/n/n"; + string desc2 = "To enter a tutorial area, type: %^%^RED%^%^enter tutorial/n/n%^%^RESET%^%^"; + return desc + ( tutorial ? desc2 : ""); +} + +void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Ooga Booga Central"); + SetLong("This is party central, where the oogas get together to hang out and get wild."); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + SetItems( ([ + "tutorial" : "A set of rooms to get familiar with this environment.", + "town" : "The main town.", + ]) ); + if(tutorial){ + AddEnter("tutorial", "/domains/tutorial/room/start"); + } +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/kjjomcbb1599367664.c b/lib/realms/babylon/tmp/kjjomcbb1599367664.c new file mode 100644 index 0000000..c58803b --- /dev/null +++ b/lib/realms/babylon/tmp/kjjomcbb1599367664.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("a hallway"); + SetLong("a hallway in a Voluntaryist space ship. The walls are covered with advertizements and the sound of terms of service resonate through the air."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/kjkfafab1599367074.c b/lib/realms/babylon/tmp/kjkfafab1599367074.c new file mode 100644 index 0000000..ecbed1b --- /dev/null +++ b/lib/realms/babylon/tmp/kjkfafab1599367074.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include <medium.h> +#include <terrain_types.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetTerrainType(T_SPACE); + SetMedium(MEDIUM_SPACE); + SetShort("The empty vastness of space"); + SetLong("You are drifting in outerspace, near the Voluntaryist spaceship the USS profit. If you are not wearing a spacesuit you are going to die very soon"); + SetItems(([ + ({ "spaceship", "airlock", "ship", "USS profit" }) : "The spaceship was built by the lowest bidder and flown on repeated missions to gather volunteers, it's amazing it hasn't already exploded.", + ])); + SetEnters( ([ + "spaceship" : "/domains/voluntaria/room/airlock.c", + ]) ); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + + SetDoor("north", "/domains/oogtopia/doors/airlock.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/kjolioob1599110513.c b/lib/realms/babylon/tmp/kjolioob1599110513.c new file mode 100644 index 0000000..6e406c3 --- /dev/null +++ b/lib/realms/babylon/tmp/kjolioob1599110513.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include "../customdefs.h" + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Sample Room"); + SetLong("This is a room you can use as a template."); + SetItems( ([ + "template" : "That's what this is.", + ]) ); + SetInventory( ([ + MY_OBJ "/table" : 1, + MY_NPC "/fighter" : 1, + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/kmihjlnc1599392617.c b/lib/realms/babylon/tmp/kmihjlnc1599392617.c new file mode 100644 index 0000000..4d9a3e9 --- /dev/null +++ b/lib/realms/babylon/tmp/kmihjlnc1599392617.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("tangled bushes"); + SetLong("the bushes are unkempt, and there appears to be ooga poo under one"); + SetItems(([ + ({ "poo", "ooga poo", "poop", "shit", "turd" }) : "This is some poo an ooga left under the bush", + ])); + SetTown("oogtopia"); + SetSmell(([ + ({ "ooga poo", "poo", "poop", "shit", "turd" }) : "This smells awful, it's not fresh but that makes it worse, the scent is almost enough to knock you over.", + ])); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/kolfnokg1599367805.c b/lib/realms/babylon/tmp/kolfnokg1599367805.c new file mode 100644 index 0000000..e59ce30 --- /dev/null +++ b/lib/realms/babylon/tmp/kolfnokg1599367805.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("a stairwell"); + SetLong("You are standing in a stairwell on the volunteer deck of the USS Profit, You can go up to the command deck or down to the engine section. There are doors which are usually locked at the top and bottom of the stairs."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + + SetDoor("up", "/domains/oogtopia/doors/commanddoor.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/lmgahcod1599392646.c b/lib/realms/babylon/tmp/lmgahcod1599392646.c new file mode 100644 index 0000000..160a5c0 --- /dev/null +++ b/lib/realms/babylon/tmp/lmgahcod1599392646.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("Tangled Bushes"); + SetLong("the bushes are unkempt, and there appears to be ooga poo under one"); + SetItems(([ + ({ "poo", "ooga poo", "poop", "shit", "turd" }) : "This is some poo an ooga left under the bush", + ])); + + SetTown("oogtopia"); + SetSmell(([ + ({ "ooga poo", "poo", "poop", "shit", "turd" }) : "This smells awful, it's not fresh but that makes it worse, the scent is almost enough to knock you over.", + ])); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/lmmckbie1599367775.c b/lib/realms/babylon/tmp/lmmckbie1599367775.c new file mode 100644 index 0000000..ac829ac --- /dev/null +++ b/lib/realms/babylon/tmp/lmmckbie1599367775.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("a stairwell"); + SetLong("You are standing in a stairwell on the volunteer deck of the USS Profit, You can go up to the command deck or down to the engine section. There are doors which are usually locked at the top and bottom of the stairs."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/mdjikldg1599367087.c b/lib/realms/babylon/tmp/mdjikldg1599367087.c new file mode 100644 index 0000000..9a40b1f --- /dev/null +++ b/lib/realms/babylon/tmp/mdjikldg1599367087.c @@ -0,0 +1,14 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area."); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/mecblede1599368364.c b/lib/realms/babylon/tmp/mecblede1599368364.c new file mode 100644 index 0000000..8355420 --- /dev/null +++ b/lib/realms/babylon/tmp/mecblede1599368364.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("the top of the stairs"); + SetLong("This is the top of the stairwell, if you head down you will be on the vounteer deck. The command deck hallway extends to the south"); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + + SetDoor("down", "/domains/oogtopia/doors/commanddoor.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/mfokbiha1599367775.c b/lib/realms/babylon/tmp/mfokbiha1599367775.c new file mode 100644 index 0000000..9a40b1f --- /dev/null +++ b/lib/realms/babylon/tmp/mfokbiha1599367775.c @@ -0,0 +1,14 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("a blank room"); + SetLong("A featureless area."); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/mgocebeb1599392771.c b/lib/realms/babylon/tmp/mgocebeb1599392771.c new file mode 100644 index 0000000..160a5c0 --- /dev/null +++ b/lib/realms/babylon/tmp/mgocebeb1599392771.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("Tangled Bushes"); + SetLong("the bushes are unkempt, and there appears to be ooga poo under one"); + SetItems(([ + ({ "poo", "ooga poo", "poop", "shit", "turd" }) : "This is some poo an ooga left under the bush", + ])); + + SetTown("oogtopia"); + SetSmell(([ + ({ "ooga poo", "poo", "poop", "shit", "turd" }) : "This smells awful, it's not fresh but that makes it worse, the scent is almost enough to knock you over.", + ])); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/mloacfag1599368486.c b/lib/realms/babylon/tmp/mloacfag1599368486.c new file mode 100644 index 0000000..a0bed4b --- /dev/null +++ b/lib/realms/babylon/tmp/mloacfag1599368486.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("command deck hallway"); + SetLong("The command deck hallway extends from the stairs at the north end to the emergency exit at the south end. To the west is the bridge and to the east are the captains quarters"); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/nbednkai1599368364.c b/lib/realms/babylon/tmp/nbednkai1599368364.c new file mode 100644 index 0000000..8355420 --- /dev/null +++ b/lib/realms/babylon/tmp/nbednkai1599368364.c @@ -0,0 +1,30 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("the top of the stairs"); + SetLong("This is the top of the stairwell, if you head down you will be on the vounteer deck. The command deck hallway extends to the south"); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + + SetDoor("down", "/domains/oogtopia/doors/commanddoor.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/ndbfgfoo1599277833.c b/lib/realms/babylon/tmp/ndbfgfoo1599277833.c new file mode 100644 index 0000000..c58803b --- /dev/null +++ b/lib/realms/babylon/tmp/ndbfgfoo1599277833.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("a hallway"); + SetLong("a hallway in a Voluntaryist space ship. The walls are covered with advertizements and the sound of terms of service resonate through the air."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/nijikbfe1599368494.c b/lib/realms/babylon/tmp/nijikbfe1599368494.c new file mode 100644 index 0000000..a0bed4b --- /dev/null +++ b/lib/realms/babylon/tmp/nijikbfe1599368494.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("command deck hallway"); + SetLong("The command deck hallway extends from the stairs at the north end to the emergency exit at the south end. To the west is the bridge and to the east are the captains quarters"); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/nlgigidj1599132791.c b/lib/realms/babylon/tmp/nlgigidj1599132791.c new file mode 100644 index 0000000..4d9a3e9 --- /dev/null +++ b/lib/realms/babylon/tmp/nlgigidj1599132791.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("tangled bushes"); + SetLong("the bushes are unkempt, and there appears to be ooga poo under one"); + SetItems(([ + ({ "poo", "ooga poo", "poop", "shit", "turd" }) : "This is some poo an ooga left under the bush", + ])); + SetTown("oogtopia"); + SetSmell(([ + ({ "ooga poo", "poo", "poop", "shit", "turd" }) : "This smells awful, it's not fresh but that makes it worse, the scent is almost enough to knock you over.", + ])); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/nobdolbk1599392771.c b/lib/realms/babylon/tmp/nobdolbk1599392771.c new file mode 100644 index 0000000..160a5c0 --- /dev/null +++ b/lib/realms/babylon/tmp/nobdolbk1599392771.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("Tangled Bushes"); + SetLong("the bushes are unkempt, and there appears to be ooga poo under one"); + SetItems(([ + ({ "poo", "ooga poo", "poop", "shit", "turd" }) : "This is some poo an ooga left under the bush", + ])); + + SetTown("oogtopia"); + SetSmell(([ + ({ "ooga poo", "poo", "poop", "shit", "turd" }) : "This smells awful, it's not fresh but that makes it worse, the scent is almost enough to knock you over.", + ])); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/oaeaclme1599277808.c b/lib/realms/babylon/tmp/oaeaclme1599277808.c new file mode 100644 index 0000000..c58803b --- /dev/null +++ b/lib/realms/babylon/tmp/oaeaclme1599277808.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("a hallway"); + SetLong("a hallway in a Voluntaryist space ship. The walls are covered with advertizements and the sound of terms of service resonate through the air."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/oagjbnhj1599392749.c b/lib/realms/babylon/tmp/oagjbnhj1599392749.c new file mode 100644 index 0000000..160a5c0 --- /dev/null +++ b/lib/realms/babylon/tmp/oagjbnhj1599392749.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetNightLight(20); + SetDayLight(40); + SetShort("Tangled Bushes"); + SetLong("the bushes are unkempt, and there appears to be ooga poo under one"); + SetItems(([ + ({ "poo", "ooga poo", "poop", "shit", "turd" }) : "This is some poo an ooga left under the bush", + ])); + + SetTown("oogtopia"); + SetSmell(([ + ({ "ooga poo", "poo", "poop", "shit", "turd" }) : "This smells awful, it's not fresh but that makes it worse, the scent is almost enough to knock you over.", + ])); + SetNoModify(0); + SetCoordinates("7001,7000,7000"); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/obfgmcio1599125268.c b/lib/realms/babylon/tmp/obfgmcio1599125268.c new file mode 100644 index 0000000..8ea653c --- /dev/null +++ b/lib/realms/babylon/tmp/obfgmcio1599125268.c @@ -0,0 +1,28 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("temperate"); + SetAmbientLight(30); + SetShort("tangled bushes"); + SetLong("the bushes are unkempt, and there appears to be ooga poo under one"); + SetItems(([ + ({ "poo", "ooga poo", "poop", "shit", "turd" }) : "This is some poo an ooga left under the bush", + "town" : "The main town.", + "tutorial" : "A set of rooms to get familiar with this environment.", + ])); + SetSmell(([ + ({ "ooga poo", "poo", "poop", "shit", "turd" }) : "This smells awful, it's not fresh but that makes it worse, the scent is almost enough to knock you over.", + ])); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/oekbbeli1599276812.c b/lib/realms/babylon/tmp/oekbbeli1599276812.c new file mode 100644 index 0000000..6b05173 --- /dev/null +++ b/lib/realms/babylon/tmp/oekbbeli1599276812.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("airlock"); + SetLong("an airlock in a Capitalist space ship. The walls are covered with advertizements and the sound of terms of service resonate through the air."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + + SetDoor("out", "/domains/voluntaria/doors/airlock.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/okjominf1599123119.c b/lib/realms/babylon/tmp/okjominf1599123119.c new file mode 100644 index 0000000..049b3aa --- /dev/null +++ b/lib/realms/babylon/tmp/okjominf1599123119.c @@ -0,0 +1,33 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +int tutorial = 0; + +string DoDesc(){ + string desc = "Welcome! To enter Oogtopia, type: %^%^GREEN%^%^enter oogtopia%^%^RESET%^%^/n/n"; + string desc2 = "To enter a tutorial area, type: %^%^RED%^%^enter tutorial/n/n%^%^RESET%^%^"; + return desc + ( tutorial ? desc2 : ""); +} + +void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Ooga Booga Central"); + SetLong("This is party central, where the oogas get together to hang out and get wild."); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + SetItems( ([ + "tutorial" : "A set of rooms to get familiar with this environment.", + "town" : "The main town.", + ]) ); + if(tutorial){ + AddEnter("tutorial", "/domains/tutorial/room/start"); + } +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/party_oogaffajhmbd1599135826.c b/lib/realms/babylon/tmp/party_oogaffajhmbd1599135826.c new file mode 100644 index 0000000..9c4e5a9 --- /dev/null +++ b/lib/realms/babylon/tmp/party_oogaffajhmbd1599135826.c @@ -0,0 +1,38 @@ +#include <lib.h> + +inherit LIB_NPC; + +int CheckOrc(mixed val){ + if(!val) return 0; + if(!objectp(val)) return 0; + if(val->GetRace() == "ooga") return 0; + else eventForce("growl at "+val->GetKeyName()); + if(playerp(val) && val->GetRace() != "ooga") return 1; + else return 0; +} + +static void create() { + npc::create(); + SetKeyName("ooga"); + SetId(({"ooga"})); + SetAdjectives(({"armored","professional"})); + SetShort("an ooga booga"); + SetLong("This is an ooga booga, they're ready to party. They don't like technology or civilization but they sure do like music and booze by the firelight."); +SetWanderSpeed(5); + SetInventory(([ + "/domains/town/weap/sword" : "wield sword", + "/domains/town/obj/orc_rucksack" : "wear my sack", + "/domains/town/armor/leather_armor" : "wear leather armor", + "/domains/town/armor/orc_boot_l" : "wear left boot", + "/domains/town/armor/orc_boot_r" : "wear right boot", + ])); + SetLevel(1); + SetRace("ooga"); + SetClass("explorer"); + SetGender("sparkly"); + SetEncounter( (: CheckOrc :) ); +} + +void init(){ + ::init(); +} \ No newline at end of file diff --git a/lib/realms/babylon/tmp/party_oogahnlihdbf1599134896.c b/lib/realms/babylon/tmp/party_oogahnlihdbf1599134896.c new file mode 100644 index 0000000..9c4e5a9 --- /dev/null +++ b/lib/realms/babylon/tmp/party_oogahnlihdbf1599134896.c @@ -0,0 +1,38 @@ +#include <lib.h> + +inherit LIB_NPC; + +int CheckOrc(mixed val){ + if(!val) return 0; + if(!objectp(val)) return 0; + if(val->GetRace() == "ooga") return 0; + else eventForce("growl at "+val->GetKeyName()); + if(playerp(val) && val->GetRace() != "ooga") return 1; + else return 0; +} + +static void create() { + npc::create(); + SetKeyName("ooga"); + SetId(({"ooga"})); + SetAdjectives(({"armored","professional"})); + SetShort("an ooga booga"); + SetLong("This is an ooga booga, they're ready to party. They don't like technology or civilization but they sure do like music and booze by the firelight."); +SetWanderSpeed(5); + SetInventory(([ + "/domains/town/weap/sword" : "wield sword", + "/domains/town/obj/orc_rucksack" : "wear my sack", + "/domains/town/armor/leather_armor" : "wear leather armor", + "/domains/town/armor/orc_boot_l" : "wear left boot", + "/domains/town/armor/orc_boot_r" : "wear right boot", + ])); + SetLevel(1); + SetRace("ooga"); + SetClass("explorer"); + SetGender("sparkly"); + SetEncounter( (: CheckOrc :) ); +} + +void init(){ + ::init(); +} \ No newline at end of file diff --git a/lib/realms/babylon/tmp/party_oogaiookbigo1599135766.c b/lib/realms/babylon/tmp/party_oogaiookbigo1599135766.c new file mode 100644 index 0000000..0333a9a --- /dev/null +++ b/lib/realms/babylon/tmp/party_oogaiookbigo1599135766.c @@ -0,0 +1,38 @@ +#include <lib.h> + +inherit LIB_NPC; + +int CheckOrc(mixed val){ + if(!val) return 0; + if(!objectp(val)) return 0; + if(val->GetRace() == "ooga") return 0; + else eventForce("growl at "+val->GetKeyName()); + if(playerp(val) && val->GetRace() != "ooga") return 1; + else return 0; +} + +static void create() { + npc::create(); + SetKeyName("ooga"); + SetId(({"ooga"})); + SetAdjectives(({"armored","professional"})); + SetShort("an ooga booga"); + SetLong("This is an ooga booga, they're ready to party. They don't like technology or civilization but they sure do like music and booze by the firelight."); + SetInventory(([ + "/domains/town/weap/sword" : "wield sword", + "/domains/town/obj/orc_rucksack" : "wear my sack", + "/domains/town/armor/leather_armor" : "wear leather armor", + "/domains/town/armor/orc_boot_l" : "wear left boot", + "/domains/town/armor/orc_boot_r" : "wear right boot", + ])); + SetLevel(1); + SetRace("ooga"); +SetWanderSpeed(5); + SetClass("explorer"); + SetGender("sparkly"); + SetEncounter( (: CheckOrc :) ); +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/party_oogancllhlfn1599136283.c b/lib/realms/babylon/tmp/party_oogancllhlfn1599136283.c new file mode 100644 index 0000000..1d891ab --- /dev/null +++ b/lib/realms/babylon/tmp/party_oogancllhlfn1599136283.c @@ -0,0 +1,39 @@ +#include <lib.h> + +inherit LIB_NPC; + +int CheckOrc(mixed val){ + if(!val) return 0; + if(!objectp(val)) return 0; + if(val->GetRace() == "ooga") return 0; + else eventForce("growl at "+val->GetKeyName()); + if(playerp(val) && val->GetRace() != "ooga") return 1; + else return 0; +} + +static void create() { + npc::create(); + SetKeyName("ooga"); + SetId(({"ooga"})); + SetAdjectives(({"armored","professional"})); + SetShort("an ooga booga"); + SetLong("This is an ooga booga, they're ready to party. They don't like technology or civilization but they sure do like music and booze by the firelight."); +SetWanderSpeed(5); + SetInventory(([ + "/domains/town/weap/sword" : "wield sword", + "/domains/town/obj/orc_rucksack" : "wear my sack", + "/domains/town/armor/leather_armor" : "wear leather armor", + "/domains/town/armor/orc_boot_l" : "wear left boot", + "/domains/town/armor/orc_boot_r" : "wear right boot", + ])); + SetLevel(1); + SetMelee(1); + SetRace("ooga"); + SetClass("explorer"); + SetGender("sparkly"); + SetEncounter( (: CheckOrc :) ); +} + +void init(){ + ::init(); +} \ No newline at end of file diff --git a/lib/realms/babylon/tmp/startafohcnfd1599123835.c b/lib/realms/babylon/tmp/startafohcnfd1599123835.c new file mode 100644 index 0000000..285c572 --- /dev/null +++ b/lib/realms/babylon/tmp/startafohcnfd1599123835.c @@ -0,0 +1,43 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +int tutorial = 0; + +string DoDesc(){ + string desc = "Welcome! To enter Oogtopia, type: %^%^GREEN%^%^enter oogtopia%^%^RESET%^%^/n/n"; + string desc2 = "To enter a tutorial area, type: %^%^RED%^%^enter tutorial/n/n%^%^RESET%^%^"; + return desc + ( tutorial ? desc2 : ""); +} + +void create() { + room::create(); + SetClimate("outdoors"); + SetAmbientLight(30); + SetNightLight(20); + SetDayLight(40); + SetShort("Ooga Booga Central"); + SetNightLong("This is where the Oogas have their parties, the sun is down and the party is in full swing. Drums, hooting and hollering, fermented drinks altough nothing distilled is permitted, and herbs and fungus of many varieties are all about."); + SetDayLong("This is where the Oogas get together and party, as long as the sun is up it's fairly sparsely attended, and any oogas around are likely nursing a hangover from the night before."); + SetLong("This is party central, where the oogas get together to hang out and get wild."); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + SetItems( ([ + "tutorial" : "A set of rooms to get familiar with this environment.", + "town" : "The main town.", + ]) ); + SetExits( ([ + "north" : "/domains/oogtopia/room/bushes", + "south" : "/domains/oogtopia/room/bushes", + "west" : "/domains/oogtopia/room/bushes", + "east" : "/domains/oogtopia/room/bushes.c", + ]) ); + if(tutorial){ + AddEnter("tutorial", "/domains/tutorial/room/start"); + } +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/startbaamaddd1599123844.c b/lib/realms/babylon/tmp/startbaamaddd1599123844.c new file mode 100644 index 0000000..41460bd --- /dev/null +++ b/lib/realms/babylon/tmp/startbaamaddd1599123844.c @@ -0,0 +1,42 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +int tutorial = 0; + +string DoDesc(){ + string desc = "Welcome! To enter Oogtopia, type: %^%^GREEN%^%^enter oogtopia%^%^RESET%^%^/n/n"; + string desc2 = "To enter a tutorial area, type: %^%^RED%^%^enter tutorial/n/n%^%^RESET%^%^"; + return desc + ( tutorial ? desc2 : ""); +} + +void create() { + room::create(); + SetClimate("outdoors"); + SetNightLight(20); + SetDayLight(40); + SetShort("Ooga Booga Central"); + SetNightLong("This is where the Oogas have their parties, the sun is down and the party is in full swing. Drums, hooting and hollering, fermented drinks altough nothing distilled is permitted, and herbs and fungus of many varieties are all about."); + SetDayLong("This is where the Oogas get together and party, as long as the sun is up it's fairly sparsely attended, and any oogas around are likely nursing a hangover from the night before."); + SetLong("This is party central, where the oogas get together to hang out and get wild."); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + SetItems( ([ + "tutorial" : "A set of rooms to get familiar with this environment.", + "town" : "The main town.", + ]) ); + SetExits( ([ + "north" : "/domains/oogtopia/room/bushes", + "south" : "/domains/oogtopia/room/bushes", + "west" : "/domains/oogtopia/room/bushes", + "east" : "/domains/oogtopia/room/bushes.c", + ]) ); + if(tutorial){ + AddEnter("tutorial", "/domains/tutorial/room/start"); + } +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/startjgfnnkcj1599123853.c b/lib/realms/babylon/tmp/startjgfnnkcj1599123853.c new file mode 100644 index 0000000..800a1b7 --- /dev/null +++ b/lib/realms/babylon/tmp/startjgfnnkcj1599123853.c @@ -0,0 +1,41 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +int tutorial = 0; + +string DoDesc(){ + string desc = "Welcome! To enter Oogtopia, type: %^%^GREEN%^%^enter oogtopia%^%^RESET%^%^/n/n"; + string desc2 = "To enter a tutorial area, type: %^%^RED%^%^enter tutorial/n/n%^%^RESET%^%^"; + return desc + ( tutorial ? desc2 : ""); +} + +void create() { + room::create(); + SetClimate("outdoors"); + SetNightLight(20); + SetDayLight(40); + SetShort("Ooga Booga Central"); + SetNightLong("This is where the Oogas have their parties, the sun is down and the party is in full swing. Drums, hooting and hollering, fermented drinks altough nothing distilled is permitted, and herbs and fungus of many varieties are all about."); + SetDayLong("This is where the Oogas get together and party, as long as the sun is up it's fairly sparsely attended, and any oogas around are likely nursing a hangover from the night before."); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + SetItems( ([ + "tutorial" : "A set of rooms to get familiar with this environment.", + "town" : "The main town.", + ]) ); + SetExits( ([ + "north" : "/domains/oogtopia/room/bushes", + "south" : "/domains/oogtopia/room/bushes", + "west" : "/domains/oogtopia/room/bushes", + "east" : "/domains/oogtopia/room/bushes.c", + ]) ); + if(tutorial){ + AddEnter("tutorial", "/domains/tutorial/room/start"); + } +} + +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/topstairfogbhlkg1599368299.c b/lib/realms/babylon/tmp/topstairfogbhlkg1599368299.c new file mode 100644 index 0000000..ec21841 --- /dev/null +++ b/lib/realms/babylon/tmp/topstairfogbhlkg1599368299.c @@ -0,0 +1,33 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetClimate("inside"); + SetAmbientLight(30); + SetShort("copy of stairwell.c"); + SetLong("You are standing in a stairwell on the volunteer deck of the USS Profit, You can go up to the command deck or down to the engine section. There are doors which are usually locked at the top and bottom of the stairs."); + SetItems(([ + ({ "announcement", "terms", "terms of service" }) : "Don't look at them, listen to them.", + ({ "advertizements", "ads", "ad", "advertizement" }) : "eye catching advertizements for a wide assortment of pornography, recreational drugs, and violent videogames", + ])); + SetExits(([ + "down" : "/domains/voluntaria/room/stairwell", + ])); + + SetListen(([ + ({ "announcement", "terms of service", "terms" }) : "By entering this space ship you have agreed to pay for transport to the planet of Voluntaria. There you will participate in a labor program to repay the debt which you are taking on for the transport to that paradise. If you disagree with the terms of this agreement you are welcome to attempt to escape through the airlock doors. Be careful as if they have closed we are already airborn, and you are likely to find yourself in the vacuum of space.", + ])); + + SetTown("USSprofit"); + SetNoModify(0); + SetCoordinates("5000,5000,0"); + + SetDoor("down", "/domains/oogtopia/doors/commanddoor.c"); + +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/tmp/wonkasaurefjmcgnb1599039087.c b/lib/realms/babylon/tmp/wonkasaurefjmcgnb1599039087.c new file mode 100644 index 0000000..f7efac0 --- /dev/null +++ b/lib/realms/babylon/tmp/wonkasaurefjmcgnb1599039087.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_SENTIENT; + +static void create() { + sentient::create(); + SetKeyName("wonkasaur"); + SetId( ({"dinosaur", "Wonkster"}) ); + SetAdjectives(({"non player"})); + SetShort("wonkasaur"); + SetLong("A dastardly chocolate eating dinosaur"); + SetLevel(1); + SetMelee(1); + SetRace("human"); + SetGender("male"); +} +void init(){ + ::init(); +} diff --git a/lib/realms/babylon/workroom.bak b/lib/realms/babylon/workroom.bak new file mode 100644 index 0000000..60b89f1 --- /dev/null +++ b/lib/realms/babylon/workroom.bak @@ -0,0 +1,130 @@ +#include <lib.h> +#include ROOMS_H +#include "./area/customdefs.h" + +inherit LIB_ROOM; +int ReadSign(); +int ReadSheet(); +int privacy = 0; +string privs = ""; +string LongString(){ + string ret = "You are standing in the workroom of the mighty " + privs + + "! \nYou may return to the Creators' Hall by going down.\n"+ + "A sample room is east."+ + "\n%^GREEN%^There is a sign here you can read.%^RESET%^"+ + "\n%^GREEN%^There is a sheet here you can read.%^RESET%^"; + if(privacy) ret += "\n%^YELLOW%^There is a privacy force field "+ + "active around this room.%^RESET%^"; + return ret; +} + +static void create() { + room::create(); + privs = query_privs(); + if( privs ) privs = capitalize(privs); + else privs = "a creator"; + + SetClimate("indoors"); + SetAmbientLight(40); + SetShort(possessive_noun(privs) + " workroom"); + SetLong( (: LongString :) ); + SetItems( ([ "workroom" : "It looks very nice.", + ({"sign","hint","hints"}) : "A sign with hints for creators.", + ({"sheet","reminder","reminders"}) : "A sheet with quick reminders for creators.", + ]) ); + SetRead( ([ + ({"sign","hint","hints"}) : (: ReadSign :), + ({"sheet","reminder","reminders"}) : (: ReadSheet :) + ]) ); + SetInventory( ([ + MY_OBJ "/chest" : 1, + "/domains/default/obj/bbucket" :1, + ]) ); + SetExits( ([ "down" : "/domains/default/room/wiz_hall.c", + "east" : MY_ROOM "/sample_room" + ]) ); + SetNoModify(0); +} + +int ReadSign(){ + this_player()->eventPage("/news/hints.txt"); + return 1; +} + +int ReadSheet(){ + this_player()->eventPage("/news/reminders.txt"); + return 1; +} + +void init(){ + ::init(); + add_action("mod_privacy","privacy"); + add_action("mod_privacy","priv"); +} + +int CanReceive(object sneak) { + int ret; + object *living_stack; + if(!privacy) return ::CanReceive(sneak); + living_stack = get_livings(sneak); + if(!living_stack || !arrayp(living_stack)) living_stack = ({ sneak }); + foreach(object ob in living_stack){ + if(!archp(ob) && ob->GetKeyName() != lower_case(privs)){ + message("info","You bounce off the privacy field.", ob); + message("info",ob->GetName()+" bounced off the privacy field.", + this_object()); + if(!environment(ob)) ob->eventMoveLiving(ROOM_START); + return 0; + } + } + ret = ::CanReceive(sneak); + if(ret){ + tell_room(this_object(), "\n\nPRIVACY WARNING: "+identify(sneak)+ + " has entered the room.\n\n", sneak); + } + return ret; +} + +static int set_privacy(int i){ + object *npcs = filter(deep_inventory(this_object()), + (: living($1) && !interactive($1) :) ); + privacy=i; + SetProperty("no peer", i); + if(sizeof(npcs)){ + foreach(object npc in npcs){ + tell_room(this_object(),"Ejecting "+identify(npc),npc); + npc->eventMove(ROOM_FURNACE); + } + } + return i; +} + +int mod_privacy(string str){ + if(!archp(this_player()) && + this_player()->GetKeyName() != lower_case(privs)) { + write("You lack the adequate privileges to do that."); + tell_room(this_object(), this_player()->GetName()+" is "+ + "trying to muck around with the privacy field system."); + return 1; + } + if(!str || str == ""){ + if(privacy) str = "off"; + else str = "on"; + } + if(str=="on" || str == "1"){ + set_privacy(1); + write("You enable the privacy field.\n"); + say(this_player()->GetName()+" enables a privacy force field " + "around the room."); + return 1; + } + if(str=="off" || str == "0"){ + set_privacy(0); + write("You disable the privacy field.\n"); + say(this_player()->GetName()+" disables a privacy force field " + "around the room."); + return 1; + } +} + + diff --git a/lib/realms/babylon/workroom.c b/lib/realms/babylon/workroom.c new file mode 100644 index 0000000..60b89f1 --- /dev/null +++ b/lib/realms/babylon/workroom.c @@ -0,0 +1,130 @@ +#include <lib.h> +#include ROOMS_H +#include "./area/customdefs.h" + +inherit LIB_ROOM; +int ReadSign(); +int ReadSheet(); +int privacy = 0; +string privs = ""; +string LongString(){ + string ret = "You are standing in the workroom of the mighty " + privs + + "! \nYou may return to the Creators' Hall by going down.\n"+ + "A sample room is east."+ + "\n%^GREEN%^There is a sign here you can read.%^RESET%^"+ + "\n%^GREEN%^There is a sheet here you can read.%^RESET%^"; + if(privacy) ret += "\n%^YELLOW%^There is a privacy force field "+ + "active around this room.%^RESET%^"; + return ret; +} + +static void create() { + room::create(); + privs = query_privs(); + if( privs ) privs = capitalize(privs); + else privs = "a creator"; + + SetClimate("indoors"); + SetAmbientLight(40); + SetShort(possessive_noun(privs) + " workroom"); + SetLong( (: LongString :) ); + SetItems( ([ "workroom" : "It looks very nice.", + ({"sign","hint","hints"}) : "A sign with hints for creators.", + ({"sheet","reminder","reminders"}) : "A sheet with quick reminders for creators.", + ]) ); + SetRead( ([ + ({"sign","hint","hints"}) : (: ReadSign :), + ({"sheet","reminder","reminders"}) : (: ReadSheet :) + ]) ); + SetInventory( ([ + MY_OBJ "/chest" : 1, + "/domains/default/obj/bbucket" :1, + ]) ); + SetExits( ([ "down" : "/domains/default/room/wiz_hall.c", + "east" : MY_ROOM "/sample_room" + ]) ); + SetNoModify(0); +} + +int ReadSign(){ + this_player()->eventPage("/news/hints.txt"); + return 1; +} + +int ReadSheet(){ + this_player()->eventPage("/news/reminders.txt"); + return 1; +} + +void init(){ + ::init(); + add_action("mod_privacy","privacy"); + add_action("mod_privacy","priv"); +} + +int CanReceive(object sneak) { + int ret; + object *living_stack; + if(!privacy) return ::CanReceive(sneak); + living_stack = get_livings(sneak); + if(!living_stack || !arrayp(living_stack)) living_stack = ({ sneak }); + foreach(object ob in living_stack){ + if(!archp(ob) && ob->GetKeyName() != lower_case(privs)){ + message("info","You bounce off the privacy field.", ob); + message("info",ob->GetName()+" bounced off the privacy field.", + this_object()); + if(!environment(ob)) ob->eventMoveLiving(ROOM_START); + return 0; + } + } + ret = ::CanReceive(sneak); + if(ret){ + tell_room(this_object(), "\n\nPRIVACY WARNING: "+identify(sneak)+ + " has entered the room.\n\n", sneak); + } + return ret; +} + +static int set_privacy(int i){ + object *npcs = filter(deep_inventory(this_object()), + (: living($1) && !interactive($1) :) ); + privacy=i; + SetProperty("no peer", i); + if(sizeof(npcs)){ + foreach(object npc in npcs){ + tell_room(this_object(),"Ejecting "+identify(npc),npc); + npc->eventMove(ROOM_FURNACE); + } + } + return i; +} + +int mod_privacy(string str){ + if(!archp(this_player()) && + this_player()->GetKeyName() != lower_case(privs)) { + write("You lack the adequate privileges to do that."); + tell_room(this_object(), this_player()->GetName()+" is "+ + "trying to muck around with the privacy field system."); + return 1; + } + if(!str || str == ""){ + if(privacy) str = "off"; + else str = "on"; + } + if(str=="on" || str == "1"){ + set_privacy(1); + write("You enable the privacy field.\n"); + say(this_player()->GetName()+" enables a privacy force field " + "around the room."); + return 1; + } + if(str=="off" || str == "0"){ + set_privacy(0); + write("You disable the privacy field.\n"); + say(this_player()->GetName()+" disables a privacy force field " + "around the room."); + return 1; + } +} + + diff --git a/lib/realms/template/adm/remote.c b/lib/realms/template/adm/remote.c new file mode 100644 index 0000000..4981cff --- /dev/null +++ b/lib/realms/template/adm/remote.c @@ -0,0 +1,6 @@ +#include <lib.h> +inherit LIB_REMOTE; + +void create(){ + remote::create(); +} diff --git a/lib/realms/template/area/armor/chainmail.c b/lib/realms/template/area/armor/chainmail.c new file mode 100644 index 0000000..4c35915 --- /dev/null +++ b/lib/realms/template/area/armor/chainmail.c @@ -0,0 +1,19 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("chainmail shirt"); + SetId(({"armor","chainmail","mail","shirt","chain mail"})); + SetAdjectives(({"chainmail","sturdy","sturdy-looking","chain mail"})); + SetShort("a sturdy-looking chainmail shirt"); + SetLong("This is a shirt made of small, thin metal rings fashioned together as armor. "); + SetMass(500); + SetBaseCost(1000); + SetDamagePoints(100); + SetProtection(BLUNT,4); + SetProtection(BLADE,25); + SetProtection(KNIFE,25); + SetArmorType(A_ARMOR); +} diff --git a/lib/realms/template/area/armor/leather_boot_l.c b/lib/realms/template/area/armor/leather_boot_l.c new file mode 100644 index 0000000..a4b559f --- /dev/null +++ b/lib/realms/template/area/armor/leather_boot_l.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("leather boot"); + SetId(({"boot","leather boot"})); + SetAdjectives( ({"leather","strong","tough","left"}) ); + SetShort("a leather boot"); + SetLong("This is the leather combat boot of a professional soldier. "+ + "It is very thick and very strong. It is designed for wear on the left foot."); + SetMass(50); + SetBaseCost(50); + SetDamagePoints(20); + SetProtection(BLUNT,10); + SetProtection(BLADE,20); + SetProtection(KNIFE,20); + SetArmorType(A_BOOT); + SetRestrictLimbs(({"left foot"})); +} diff --git a/lib/realms/template/area/armor/leather_boot_r.c b/lib/realms/template/area/armor/leather_boot_r.c new file mode 100644 index 0000000..f6fdc78 --- /dev/null +++ b/lib/realms/template/area/armor/leather_boot_r.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +inherit LIB_ARMOR; +static void create(){ + armor::create(); + SetKeyName("leather boot"); + SetId(({"boot","leather boot"})); + SetAdjectives( ({"leather","strong","tough","right"}) ); + SetShort("a leather boot"); + SetLong("This is the leather combat boot of a professional soldier. "+ + "It is very thick and very strong. It is designed for wear on the right foot."); + SetMass(50); + SetBaseCost(50); + SetDamagePoints(20); + SetProtection(BLUNT,10); + SetProtection(BLADE,20); + SetProtection(KNIFE,20); + SetArmorType(A_BOOT); + SetRestrictLimbs(({"right foot"})); +} diff --git a/lib/realms/template/area/customdefs.h b/lib/realms/template/area/customdefs.h new file mode 100644 index 0000000..f2dc5fb --- /dev/null +++ b/lib/realms/template/area/customdefs.h @@ -0,0 +1,17 @@ +#ifndef r_mydirs_h +#define r_mydirs_h + +#define MY_DIR "/realms/template" +#define MY_CMDS MY_DIR "/cmds" +#define MY_LOG MY_DIR "/log" +#define MY_AREA MY_DIR "/area" +#define MY_WEAP MY_AREA "/weap" +#define MY_ROOM MY_AREA "/room" +#define MY_OBJ MY_AREA "/obj" +#define MY_ARMOR MY_AREA "/armor" +#define MY_NPC MY_AREA "/npc" +#define MY_DOORS MY_AREA "/doors" +#define MY_MEALS MY_AREA "/meals" +#define MY_ETC MY_AREA "/etc" + +#endif /* r_mydirs_h */ diff --git a/lib/realms/template/area/customdefs.part1 b/lib/realms/template/area/customdefs.part1 new file mode 100644 index 0000000..21ca3bc --- /dev/null +++ b/lib/realms/template/area/customdefs.part1 @@ -0,0 +1,3 @@ +#ifndef r_mydirs_h +#define r_mydirs_h + diff --git a/lib/realms/template/area/customdefs.part2 b/lib/realms/template/area/customdefs.part2 new file mode 100644 index 0000000..1b97829 --- /dev/null +++ b/lib/realms/template/area/customdefs.part2 @@ -0,0 +1,13 @@ +#define MY_CMDS MY_DIR "/cmds" +#define MY_LOG MY_DIR "/log" +#define MY_AREA MY_DIR "/area" +#define MY_WEAP MY_AREA "/weap" +#define MY_ROOM MY_AREA "/room" +#define MY_OBJ MY_AREA "/obj" +#define MY_ARMOR MY_AREA "/armor" +#define MY_NPC MY_AREA "/npc" +#define MY_DOORS MY_AREA "/doors" +#define MY_MEALS MY_AREA "/meals" +#define MY_ETC MY_AREA "/etc" + +#endif /* r_mydirs_h */ diff --git a/lib/realms/template/area/npc/fighter.c b/lib/realms/template/area/npc/fighter.c new file mode 100644 index 0000000..b60ef01 --- /dev/null +++ b/lib/realms/template/area/npc/fighter.c @@ -0,0 +1,41 @@ +#include <lib.h> +#include "../customdefs.h" + +inherit LIB_NPC; +string privs; + +int AllowPass(object who, object what){ + if(who->GetKeyName() == privs) return 1; + return ::AllowPass(who, what); +} + +int CheckVisitor(object who){ + eventForce("say I'm sorry, "+remove_article(who->GetShort())+ + ". Only "+capitalize(privs)+" is allowed there."); + return 1; +} + +static void create(){ + npc::create(); + privs = query_privs(); + SetKeyName("fighter"); + SetId( ({"human","npc","warrior","fighter"}) ); + SetShort("a fighter"); + SetLong("This is a sample warrior NPC."); + SetLevel(10); + SetRace("human"); + SetClass("fighter"); + SetGender("male"); + SetInventory(([ + MY_ARMOR "/chainmail.c" : "wear chainmail", + MY_ARMOR "/leather_boot_r.c" : "wear boot", + MY_ARMOR "/leather_boot_l.c" : "wear boot", + MY_WEAP "/sword.c" : "wield sword", + ])); + SetStat("strength",40); + SetGuard("west", (: CheckVisitor :)); + SetGuard("east", "The fighter blocks your travel in that direction."); +} +void init(){ + ::init(); +} diff --git a/lib/realms/template/area/obj/builder_chest.c b/lib/realms/template/area/obj/builder_chest.c new file mode 100644 index 0000000..ac484fa --- /dev/null +++ b/lib/realms/template/area/obj/builder_chest.c @@ -0,0 +1,31 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("chest"); + SetId(({"chest","wooden chest"})); + SetShort("a wooden chest"); + SetLong("This is a sturdy wooden chest used to store valuable items."); + SetInventory(([ + "/domains/town/armor/collar" : 1, + "/domains/default/obj/bguide" : 1, + "/domains/default/obj/meter" : 1, + "/secure/obj/control" : 1, + "/secure/obj/memo" : 1, + "/secure/obj/staff" : 1, + "/domains/default/obj/pinger" : 1, + "/secure/obj/medtric" : 1, + ])); + SetMass(2000); + SetMaxCarry(10000); + SetPreventPut("You cannot put this in there!"); + SetPreventGet("The chest does not budge."); + SetCanClose(1); + SetClosed(1); +} + +void init(){ + ::init(); +} diff --git a/lib/realms/template/area/obj/case.c b/lib/realms/template/area/obj/case.c new file mode 100644 index 0000000..b3d344c --- /dev/null +++ b/lib/realms/template/area/obj/case.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include "../customdefs.h" + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("case"); + SetId( ({ "container" }) ); + SetAdjectives( ({ "generic","nondescript" }) ); + SetShort("a glass case"); + SetLong("This is an expensive looking, ornamented glass case. It looks perfect for storing trophies or jewelry for display. It is an example of a transparent container."); + SetInventory(([ + MY_AREA "/obj/watch" : 1, + ])); + SetOpacity(10); + SetCanClose(1); + SetClosed(1); + SetMass(274); + SetBaseCost("silver",1); + SetMaxCarry(500); +} +void init(){ + ::init(); +} + +mixed CanGet(object ob) { return "The case does not budge.";} diff --git a/lib/realms/template/area/obj/chest.c b/lib/realms/template/area/obj/chest.c new file mode 100644 index 0000000..a12d480 --- /dev/null +++ b/lib/realms/template/area/obj/chest.c @@ -0,0 +1,41 @@ +#include <lib.h> + +inherit LIB_STORAGE; + +void create() { + ::create(); + SetKeyName("chest"); + SetId(({"chest","wooden chest"})); + SetShort("a wooden chest"); + SetLong("This is a sturdy wooden chest used to store valuable items.\n"+ + "It is an example of an opaque container."); + SetInventory(([ + "/domains/town/armor/collar" : 1, + "/domains/default/armor/breather" : 1, + "/domains/default/armor/badge" : 1, + "/domains/default/armor/wizard_hat" : 1, + "/domains/default/obj/manual" : 1, + "/secure/obj/machine" : 1, + "/domains/default/obj/gps" : 1, + "/domains/default/armor/robe" : 1, + "/domains/default/obj/meter" : 1, + "/secure/obj/control" : 1, + "/secure/obj/memo" : 1, + "/secure/obj/staff" : 1, + "/domains/default/obj/pinger" : 1, + "/secure/obj/medtric" : 1, + "/secure/obj/glasses" : 1, + "/domains/default/armor/jade_ring" : 1, + "/domains/default/armor/gray_amulet" : 1, + ])); + SetMass(2000); + SetBaseCost(50); + SetMaxCarry(10000); + SetCanClose(1); + SetClosed(1); + SetPreventGet("The chest does not budge."); +} + +void init(){ + ::init(); +} diff --git a/lib/realms/template/area/obj/cup.c b/lib/realms/template/area/obj/cup.c new file mode 100644 index 0000000..f33fb2c --- /dev/null +++ b/lib/realms/template/area/obj/cup.c @@ -0,0 +1,23 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> +inherit LIB_FLASK; + +void create(){ + ::create(); + SetKeyName("cup"); + SetId( ({"cup", "cup made of wood"}) ); + SetAdjectives( ({"simple","wooden"}) ); + SetShort("a wooden cup"); + SetLong("A simple cup made of wood, for containing fluids."); + SetMass(5); + SetBaseCost("silver",1); + SetVendorType(VT_TREASURE); + SetFlaskUses(0); + SetStrength(5); + SetMaxFlask(1); + SetMealType(MEAL_DRINK); +} +void init(){ + ::init(); +} diff --git a/lib/realms/template/area/obj/key.c b/lib/realms/template/area/obj/key.c new file mode 100644 index 0000000..b3cb6a6 --- /dev/null +++ b/lib/realms/template/area/obj/key.c @@ -0,0 +1,19 @@ +#include <lib.h> + +inherit LIB_ITEM; + + +static void create() { + item::create(); + SetKeyName("key"); + SetId( ({ "key", "sample key" }) ); + SetAdjectives( ({ "simple","sample" }) ); + SetShort("a sample key"); + SetLong("It is a simple sample key with no markings."); + SetMass(50); + SetBaseCost(1); + SetDisableChance(100); +} +void init(){ + ::init(); +} diff --git a/lib/realms/template/area/obj/pitcher.c b/lib/realms/template/area/obj/pitcher.c new file mode 100644 index 0000000..9d8fae2 --- /dev/null +++ b/lib/realms/template/area/obj/pitcher.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <vendor_types.h> +#include <meal_types.h> +inherit LIB_FLASK; + +void create(){ + ::create(); + SetKeyName("pitcher"); + SetId( ({"pitcher", "vessel", "pitcher made of clay"}) ); + SetAdjectives( ({"small","clay","vessel"}) ); + SetShort("a small clay pitcher"); + SetLong("A small, clay vessel for containing fluids. You may "+ + "want to \"pour from pitcher into cup\"."); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); + SetFlaskContents("water"); + SetFlaskUses(2); + SetStrength(5); + SetMaxFlask(3); + SetMealType(MEAL_DRINK); +} +void init(){ + ::init(); +} diff --git a/lib/realms/template/area/obj/table.c b/lib/realms/template/area/obj/table.c new file mode 100644 index 0000000..e6277b6 --- /dev/null +++ b/lib/realms/template/area/obj/table.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include "../customdefs.h" + +inherit LIB_TABLE; + + +void create() { + ::create(); + SetKeyName("sample table"); + SetId( ({ "table" ,"sample table"}) ); + SetAdjectives( ({ "simple","sample" }) ); + SetShort("a simple table"); + SetLong("It is a simple sample table. It is an example of a \"surface\" "+ + "type container."); + SetBaseCost(1200); + SetMaxCarry(5000); + SetInventory( ([ + MY_OBJ "/key" : 1, + MY_OBJ "/pitcher" : 1, + MY_OBJ "/cup" : 1, + ]) ); +} +void init(){ + ::init(); +} diff --git a/lib/realms/template/area/obj/watch.c b/lib/realms/template/area/obj/watch.c new file mode 100644 index 0000000..edc36dd --- /dev/null +++ b/lib/realms/template/area/obj/watch.c @@ -0,0 +1,68 @@ +#include <lib.h> +#include <armor_types.h> +#include <damage_types.h> +#include <localtime.h> +#include <daemons.h> + +inherit LIB_ARMOR; + +int eventReadWatch(); + +static void create(){ + armor::create(); + SetKeyName("pocket watch"); + SetId(({"watch","pocketwatch","pocket watch","timepiece"})); + SetShort("a pocket watch"); + SetLong("This is a beautifully decorated and intricately carved "+ + "pocket watch. It glows with a bright, polished bronze "+ + "luster. It is quietly ticking the seconds, and it looks like you can get the "+ + "accurate time by reading the watch."); + SetMass(10); + SetBaseCost("silver",40); + SetProtection(BLUNT,1); + SetProtection(BLADE,1); + SetProtection(KNIFE,1); + SetArmorType(A_AMULET); + SetDefaultRead( (: eventReadWatch :) ); +} +void init(){ + ::init(); +} + +int eventReadWatch(){ + int hour, minutes; + int *time_of_day; + string hour_string, minute_string; + + time_of_day = SEASONS_D->GetMudTime(); + hour = time_of_day[0]; + minutes = time_of_day[1]; + + if(hour > 12) hour -= 12; + + hour_string = cardinal(hour); + switch(minutes){ + case 0 : minute_string ="o'clock"; break; + case 1 : minute_string = hour_string;hour_string ="one minute past"; break; + case 2 : minute_string = hour_string;hour_string ="two minutes past"; break; + case 3 : minute_string = hour_string;hour_string ="three minutes past"; break; + case 4 : minute_string = hour_string;hour_string ="four minutes past"; break; + case 5 : minute_string = hour_string;hour_string ="five past"; break; + case 6 : minute_string = hour_string;hour_string ="six minutes past"; break; + case 7 : minute_string = hour_string;hour_string ="seven minutes past"; break; + case 8 : minute_string = hour_string;hour_string ="eight minutes past"; break; + case 9 : minute_string = hour_string;hour_string ="nine minutes past"; break; + case 10 : minute_string = hour_string;hour_string ="ten past"; break; + case 15 : minute_string = hour_string;hour_string ="quarter past"; break; + case 45 : minute_string = cardinal(hour+1);hour_string ="quarter of"; break; + case 50 : minute_string = cardinal(hour+1);;hour_string ="ten of"; break; + case 55 : minute_string = cardinal(hour+1);hour_string ="five of"; break; + default : minute_string = cardinal(minutes);break; + } + + if(minute_string == "thirteen") minute_string = "one"; + + write("According to the watch, it is "+hour_string+" "+minute_string+"."); + + return 1; +} diff --git a/lib/realms/template/area/room/sample_room.c b/lib/realms/template/area/room/sample_room.c new file mode 100644 index 0000000..4b230dc --- /dev/null +++ b/lib/realms/template/area/room/sample_room.c @@ -0,0 +1,27 @@ +#include <lib.h> +#include "../customdefs.h" + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Sample Room"); + SetLong("This is a room you can use as a template."); + SetItems( ([ + "template" : "That's what this is.", + ]) ); + SetExits( ([ + "west" : MY_DIR "/workroom", + "east" : MY_ROOM "/sample_two.c", + ]) ); + SetInventory( ([ + MY_OBJ "/table" : 1, + MY_NPC "/fighter" : 1, + ]) ); +} + +void init(){ + ::init(); +} diff --git a/lib/realms/template/area/room/sample_two.c b/lib/realms/template/area/room/sample_two.c new file mode 100644 index 0000000..e3c45f9 --- /dev/null +++ b/lib/realms/template/area/room/sample_two.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include "../customdefs.h" + +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Second Sample Room"); + SetLong("This is another sample room."); + SetItems( ([ + "template" : "That's what this is.", + ]) ); + SetInventory(([ + MY_OBJ "/case" :1, + ])); + SetExits(([ + "west" : MY_AREA "/room/sample_room", + ])); + +} + +void init(){ + ::init(); +} diff --git a/lib/realms/template/area/weap/sword.c b/lib/realms/template/area/weap/sword.c new file mode 100644 index 0000000..6a48b57 --- /dev/null +++ b/lib/realms/template/area/weap/sword.c @@ -0,0 +1,20 @@ +#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" }) ); + SetAdjectives( ({ "short" }) ); + SetShort("a short sword"); + SetLong("A cheap and rather dull short sword."); + SetMass(300); + SetBaseCost(50); + SetVendorType(VT_WEAPON); + SetClass(20); + SetDamageType(BLADE); + SetWeaponType("blade"); +} diff --git a/lib/realms/template/bak/bk.db b/lib/realms/template/bak/bk.db new file mode 100644 index 0000000..3918460 --- /dev/null +++ b/lib/realms/template/bak/bk.db @@ -0,0 +1 @@ +workroom.orig : workroom.orig diff --git a/lib/realms/template/bak/workroom.orig b/lib/realms/template/bak/workroom.orig new file mode 100644 index 0000000..ca4a9d2 --- /dev/null +++ b/lib/realms/template/bak/workroom.orig @@ -0,0 +1,128 @@ +#include <lib.h> +#include <rooms.h> +#include "./customdefs.h" + +inherit LIB_ROOM; +int ReadSign(); +int ReadSheet(); +int privacy = 0; +string privs = ""; +string LongString(){ + string ret = "You are standing in the workroom of the mighty " + privs + + "! \nYou may return to the Creators' Hall by going down.\n"+ + "A sample room is east."+ + "\n%^GREEN%^There is a sign here you can read.%^RESET%^"+ + "\n%^GREEN%^There is a sheet here you can read.%^RESET%^"; + if(privacy) ret += "\n%^YELLOW%^There is a privacy force field "+ + "active around this room.%^RESET%^"; + return ret; +} + +static void create() { + room::create(); + privs = query_privs(); + if( privs ) privs = capitalize(privs); + else privs = "a creator"; + + SetClimate("indoors"); + SetAmbientLight(40); + SetShort(possessive_noun(privs) + " workroom"); + SetLong( (: LongString :) ); + SetItems( ([ "workroom" : "It looks very nice.", + ({"sign","hint","hints"}) : "A sign with hints for creators.", + ({"sheet","reminder","reminders"}) : "A sheet with quick reminders for creators.", + ]) ); + SetRead( ([ + ({"sign","hint","hints"}) : (: ReadSign :), + ({"sheet","reminder","reminders"}) : (: ReadSheet :) + ]) ); + SetInventory( ([ + MY_OBJ "/chest" : 1, + "/domains/default/obj/bbucket" :1, + ]) ); + SetExits( ([ "down" : "/domains/default/room/wiz_hall.c", + "east" : MY_ROOM "/sample_room" + ]) ); + SetNoModify(0); +} + +int ReadSign(){ + this_player()->eventPage("/news/hints.txt"); + return 1; +} + +int ReadSheet(){ + this_player()->eventPage("/news/reminders.txt"); + return 1; +} + +void init(){ + ::init(); + add_action("mod_privacy","privacy"); + add_action("mod_privacy","priv"); +} + +int CanReceive(object sneak) { + int ret; + object *living_stack; + if(!privacy) return ::CanReceive(sneak); + living_stack = get_livings(sneak); + if(!living_stack || !arrayp(living_stack)) living_stack = ({ sneak }); + foreach(object ob in living_stack){ + if(!archp(ob) && ob->GetKeyName() != lower_case(privs)){ + message("info","You bounce off the privacy field.", ob); + message("info",ob->GetName()+" bounced off the privacy field.", + this_object()); + if(!environment(ob)) ob->eventMoveLiving(ROOM_START); + return 0; + } + } + ret = ::CanReceive(sneak); + if(ret){ + tell_room(this_object(), "\n\nPRIVACY WARNING: "+identify(sneak)+ + " has entered the room.\n\n", sneak); + } + return ret; +} + +static int set_privacy(int i){ + object *npcs = filter(deep_inventory(this_object()), + (: living($1) && !interactive($1) :) ); + privacy=i; + SetProperty("no peer", i); + if(sizeof(npcs)){ + foreach(object npc in npcs){ + tell_room(this_object(),"Ejecting "+identify(npc),npc); + npc->eventMove(ROOM_FURNACE); + } + } + return i; +} + +static int mod_privacy(string str){ + if(!archp(this_player()) && + this_player()->GetKeyName() != lower_case(privs)) { + write("You lack the adequate privileges to do that."); + say(this_player()->GetName()+" is trying to muck around with the privacy field system."); + return 1; + } + if(!str || str == ""){ + if(privacy) str = "off"; + else str = "on"; + } + if(str=="on" || str == "1"){ + set_privacy(1); + write("You enable the privacy field.\n"); + say(this_player()->GetName()+" enables a privacy force field around the +room."); + return 1; + } + if(str=="off" || str == "0"){ + set_privacy(0); + write("You disable the privacy field.\n"); + say(this_player()->GetName()+" disables a privacy force field around the room."); + return 1; + } +} + + diff --git a/lib/realms/template/cmds/custom.c b/lib/realms/template/cmds/custom.c new file mode 100644 index 0000000..1e4b964 --- /dev/null +++ b/lib/realms/template/cmds/custom.c @@ -0,0 +1,10 @@ + +#include <lib.h> + +inherit LIB_DAEMON; + +mixed cmd(string str) { + return "This is your own, personal command."; +} + + diff --git a/lib/realms/template/evaldefs.h b/lib/realms/template/evaldefs.h new file mode 100644 index 0000000..3279a26 --- /dev/null +++ b/lib/realms/template/evaldefs.h @@ -0,0 +1,12 @@ +#ifndef TP +#define TP this_player() +#endif +#ifndef ENV +#define ENV environment(this_player()) +#endif +#ifndef HERE +#define HERE room_environment(this_player()) +#endif +#define THING(x) (get_object(x)) +#define PRES(x) (present(x, TP) || present(x, ENV) ) +#define FILE(x) (present_file(x, TP) || present_file(x, ENV) ) diff --git a/lib/realms/template/plan b/lib/realms/template/plan new file mode 100644 index 0000000..8ab30f1 --- /dev/null +++ b/lib/realms/template/plan @@ -0,0 +1 @@ +This is an empty plan file. diff --git a/lib/realms/template/profile b/lib/realms/template/profile new file mode 100644 index 0000000..1422b00 --- /dev/null +++ b/lib/realms/template/profile @@ -0,0 +1,3 @@ +people +uptime +boards diff --git a/lib/realms/template/workroom.bak b/lib/realms/template/workroom.bak new file mode 100644 index 0000000..fc1ae65 --- /dev/null +++ b/lib/realms/template/workroom.bak @@ -0,0 +1,111 @@ +#include <lib.h> +#include <rooms.h> +#include "./customdefs.h" + +inherit LIB_ROOM; +int ReadSign(); +int ReadSheet(); +int privacy = 0; +string privs = ""; +string LongString(){ + string ret = "You are standing in the workroom of the mighty " + privs + + "! \nYou may return to the Creators' Hall by going down.\n"+ + "A sample room is east."+ + "\n%^GREEN%^There is a sign here you can read.%^RESET%^"+ + "\n%^GREEN%^There is a sheet here you can read.%^RESET%^"; + if(privacy) ret += "\n%^YELLOW%^There is a privacy force field "+ + "active around this room.%^RESET%^"; + return ret; +} + +static void create() { + room::create(); + privs = query_privs(); + if( privs ) privs = capitalize(privs); + else privs = "a creator"; + + SetClimate("indoors"); + SetAmbientLight(40); + SetShort(possessive_noun(privs) + " workroom"); + SetLong( (: LongString :) ); + SetItems( ([ "workroom" : "It looks very nice.", + ({"sign","hint","hints"}) : "A sign with hints for creators.", + ({"sheet","reminder","reminders"}) : "A sheet with quick reminders for creators.", + ]) ); + SetRead( ([ + ({"sign","hint","hints"}) : (: ReadSign :), + ({"sheet","reminder","reminders"}) : (: ReadSheet :) + ]) ); + SetInventory( ([ + MY_OBJ "/chest" : 1, + "/domains/default/obj/bbucket" :1, + ]) ); + SetExits( ([ "down" : "/domains/default/room/wiz_hall.c", + "east" : MY_ROOM "/sample_room" + ]) ); + SetNoModify(1); +} + +int ReadSign(){ + this_player()->eventPage("/news/hints.txt"); + return 1; +} + +int ReadSheet(){ + this_player()->eventPage("/news/reminders.txt"); + return 1; +} + +void init(){ + ::init(); + add_action("mod_privacy","privacy"); + add_action("mod_privacy","priv"); +} +int CanReceive(object ob) { + if(privacy){ + if(!interactive(ob)) { + message("info","\n\nPRIVACY WARNING: "+ob->GetName()+" has entered the room.\n\n",this_object() ); + } + else if(!archp(ob) && + this_player()->GetKeyName() != lower_case(privs)){ + message("info","You bounce off the privacy field.", ob); + message("info",ob->GetName()+" bounced off the privacy field.",this_object()); + if(!environment(ob)) ob->eventMoveLiving(ROOM_START); + return 0; + } + } + return room::CanReceive(); +} + +static int set_privacy(int i){ + privacy=i; + return 1; +} + +static int mod_privacy(string str){ + if(!archp(this_player()) && + this_player()->GetKeyName() != lower_case(privs)) { + write("You lack the adequate privileges to do that."); + say(this_player()->GetName()+" is trying to muck around with the privacy field system."); + return 1; + } + if(!str || str == ""){ + if(privacy) str = "off"; + else str = "on"; + } + if(str=="on" || str == "1"){ + set_privacy(1); + write("You enable the privacy field.\n"); + say(this_player()->GetName()+" enables a privacy force field around the +room."); + return 1; + } + if(str=="off" || str == "0"){ + set_privacy(0); + write("You disable the privacy field.\n"); + say(this_player()->GetName()+" disables a privacy force field around the room."); + return 1; + } +} + + diff --git a/lib/realms/template/workroom.c b/lib/realms/template/workroom.c new file mode 100644 index 0000000..60b89f1 --- /dev/null +++ b/lib/realms/template/workroom.c @@ -0,0 +1,130 @@ +#include <lib.h> +#include ROOMS_H +#include "./area/customdefs.h" + +inherit LIB_ROOM; +int ReadSign(); +int ReadSheet(); +int privacy = 0; +string privs = ""; +string LongString(){ + string ret = "You are standing in the workroom of the mighty " + privs + + "! \nYou may return to the Creators' Hall by going down.\n"+ + "A sample room is east."+ + "\n%^GREEN%^There is a sign here you can read.%^RESET%^"+ + "\n%^GREEN%^There is a sheet here you can read.%^RESET%^"; + if(privacy) ret += "\n%^YELLOW%^There is a privacy force field "+ + "active around this room.%^RESET%^"; + return ret; +} + +static void create() { + room::create(); + privs = query_privs(); + if( privs ) privs = capitalize(privs); + else privs = "a creator"; + + SetClimate("indoors"); + SetAmbientLight(40); + SetShort(possessive_noun(privs) + " workroom"); + SetLong( (: LongString :) ); + SetItems( ([ "workroom" : "It looks very nice.", + ({"sign","hint","hints"}) : "A sign with hints for creators.", + ({"sheet","reminder","reminders"}) : "A sheet with quick reminders for creators.", + ]) ); + SetRead( ([ + ({"sign","hint","hints"}) : (: ReadSign :), + ({"sheet","reminder","reminders"}) : (: ReadSheet :) + ]) ); + SetInventory( ([ + MY_OBJ "/chest" : 1, + "/domains/default/obj/bbucket" :1, + ]) ); + SetExits( ([ "down" : "/domains/default/room/wiz_hall.c", + "east" : MY_ROOM "/sample_room" + ]) ); + SetNoModify(0); +} + +int ReadSign(){ + this_player()->eventPage("/news/hints.txt"); + return 1; +} + +int ReadSheet(){ + this_player()->eventPage("/news/reminders.txt"); + return 1; +} + +void init(){ + ::init(); + add_action("mod_privacy","privacy"); + add_action("mod_privacy","priv"); +} + +int CanReceive(object sneak) { + int ret; + object *living_stack; + if(!privacy) return ::CanReceive(sneak); + living_stack = get_livings(sneak); + if(!living_stack || !arrayp(living_stack)) living_stack = ({ sneak }); + foreach(object ob in living_stack){ + if(!archp(ob) && ob->GetKeyName() != lower_case(privs)){ + message("info","You bounce off the privacy field.", ob); + message("info",ob->GetName()+" bounced off the privacy field.", + this_object()); + if(!environment(ob)) ob->eventMoveLiving(ROOM_START); + return 0; + } + } + ret = ::CanReceive(sneak); + if(ret){ + tell_room(this_object(), "\n\nPRIVACY WARNING: "+identify(sneak)+ + " has entered the room.\n\n", sneak); + } + return ret; +} + +static int set_privacy(int i){ + object *npcs = filter(deep_inventory(this_object()), + (: living($1) && !interactive($1) :) ); + privacy=i; + SetProperty("no peer", i); + if(sizeof(npcs)){ + foreach(object npc in npcs){ + tell_room(this_object(),"Ejecting "+identify(npc),npc); + npc->eventMove(ROOM_FURNACE); + } + } + return i; +} + +int mod_privacy(string str){ + if(!archp(this_player()) && + this_player()->GetKeyName() != lower_case(privs)) { + write("You lack the adequate privileges to do that."); + tell_room(this_object(), this_player()->GetName()+" is "+ + "trying to muck around with the privacy field system."); + return 1; + } + if(!str || str == ""){ + if(privacy) str = "off"; + else str = "on"; + } + if(str=="on" || str == "1"){ + set_privacy(1); + write("You enable the privacy field.\n"); + say(this_player()->GetName()+" enables a privacy force field " + "around the room."); + return 1; + } + if(str=="off" || str == "0"){ + set_privacy(0); + write("You disable the privacy field.\n"); + say(this_player()->GetName()+" disables a privacy force field " + "around the room."); + return 1; + } +} + + diff --git a/lib/realms/template/workroom_builder.c b/lib/realms/template/workroom_builder.c new file mode 100644 index 0000000..5df7f59 --- /dev/null +++ b/lib/realms/template/workroom_builder.c @@ -0,0 +1,47 @@ +#include <lib.h> +#include ROOMS_H +#include "./area/customdefs.h" + +inherit LIB_ROOM; +int ReadSign(); +int ReadSheet(); + +static void create() { + room::create(); + + SetClimate("indoors"); + SetAmbientLight(40); + SetShort("A workroom"); + SetLong("This is a builder's workroom. The Builders' Hall is down. "+ + "A sample room is east."); + SetItems( ([ "workroom" : "It looks very nice.", + //({"sign","hint","hints"}) : "A sign with hints for creators.", + //({"sheet","reminder","reminders"}) : "A sheet with quick reminders for creators.", + ]) ); + SetRead( ([ + //({"sign","hint","hints"}) : (: ReadSign :), + //({"sheet","reminder","reminders"}) : (: ReadSheet :) + ]) ); + SetInventory( ([ + MY_OBJ "/builder_chest" : 1, + "/domains/default/obj/bbucket" :1, + ]) ); + SetExits( ([ "down" : "/domains/default/room/builder_hall.c", + "east" : MY_ROOM "/sample_room" + ]) ); + //SetNoModify(1); +} + +int ReadSign(){ + this_player()->eventPage("/news/hints.txt"); + return 1; +} + +int ReadSheet(){ + this_player()->eventPage("/news/reminders.txt"); + return 1; +} + +void init(){ + ::init(); +} diff --git a/lib/save/banish.o b/lib/save/banish.o new file mode 100644 index 0000000..6837412 --- /dev/null +++ b/lib/save/banish.o @@ -0,0 +1,9 @@ +#/daemon/banish.c +__Names ({}) +__Sites ({}) +__WatchNames ({}) +__WatchSites ({}) +__Allowed ({}) +__Guests ({}) +__IllegalSubStrings ({}) +__TmpBanish ([]) diff --git a/lib/save/books.o b/lib/save/books.o new file mode 100644 index 0000000..f17a7d3 --- /dev/null +++ b/lib/save/books.o @@ -0,0 +1,2 @@ +#/daemon/books.c +Books (["/doc/manual":(["object":"/domains/default/obj/manual","/doc/manual/chapter39":1164672846,"/doc/manual/chapter38":1164672846,"/doc/manual/chapter37":1164672846,"/doc/manual/chapter36":1164672846,"/doc/manual/chapter35":1164672846,"/doc/manual/chapter34":1164672846,"/doc/manual/chapter33":1164672846,"/doc/manual/chapter32":1164672846,"/doc/manual/chapter31":1164672846,"/doc/manual/chapter30":1164672846,"/doc/manual/chapter19":1164672846,"/doc/manual/chapter18":1164672846,"/doc/manual/chapter17":1164672846,"/doc/manual/chapter16":1164672846,"title":"Untitled","/doc/manual/chapter15":1164672846,"/doc/manual/chapter14":1164672846,"/doc/manual/chapter13":1164672846,"/doc/manual/chapter12":1164672846,"/doc/manual/chapter11":1164672846,"/doc/manual/chapter10":1164672846,"index":" Untitled 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: \"LPC Basics\" Chapter 9: \"Introduction to Intermediate LPC\" Chapter 10: \"The LPMud Driver\" Chapter 11: \"Complex Data Types\" Chapter 12: \"The LPC Pre-Compiler\" Chapter 13: \"Advanced String Handling\" Chapter 14: \"Intermediate Inheritance\" Chapter 15: \"Debugging\" Chapter 16: \"Armor\" Chapter 17: \"Barkeeps\" Chapter 18: \"Valid climates\" Chapter 19: \"Doors\" Chapter 20: \"Items\" Chapter 21: \"Meals\" Chapter 22: \"NPCs\" Chapter 23: \"Properties\" Chapter 24: \"Quests\" Chapter 25: \"Rooms\" Chapter 26: \"Sentients\" Chapter 27: \"Towns\" Chapter 28: \"Vendors\" Chapter 29: \"Weapons\" Chapter 30: \"The Natural Language Parser\" Chapter 31: \"Overview of the Quick Creation System\" Chapter 32: \"QCS: Commands\" Chapter 33: \"QCS: Creation\" Chapter 34: \"QCS: Modification of NPC's\" Chapter 35: \"QCS: Modifying rooms\" Chapter 36: \"QCS: Modifying weapons\" Chapter 37: \"QCS: Modifying things and stuff\" Chapter 38: \"QCS: Adding and deleting\" Chapter 39: \"QCS: Final notes\" Chapter 40: \"Useful Creator Commands\" ","reads":([({"chapter 13","chapter thirteen","13",}):"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 ",({"chapter 11","chapter eleven","11",}):"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 ",({"chapter 24","chapter twenty-four","24",}):"chapter 24 \"Quests\" 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 ",({"chapter 37","chapter thirty-seven","37",}):"chapter 37 \"QCS: Modifying things and stuff\" You should have a firm grasp now on how QCS works in relation to manipulable objects. Let's look at the settings for a few special kinds of items: chairs ------ %^GREEN%^modify stool maxsitters 1%^RESET%^ %^GREEN%^modify stool setmaxcarry 200%^RESET%^ beds ---- %^GREEN%^modify sofa maxsitters 2%^RESET%^ %^GREEN%^modify sofa maxliers 1%^RESET%^ %^GREEN%^modify sofa maxcarry 400%^RESET%^ containers ---------- %^GREEN%^modify box canclose 1%^RESET%^ %^GREEN%^modify box closed 1%^RESET%^ %^GREEN%^modify box locked 1%^RESET%^ %^GREEN%^modify box key magic_skeleton_key%^RESET%^ %^GREEN%^modify box maxcarry 200%^RESET%^ %^GREEN%^modify box setmoney gold 15%^RESET%^ tables ------ %^GREEN%^modify altar maxcarry 300%^RESET%^ %^GREEN%^modify altar maxliers 1%^RESET%^ meals/drinks ------------ %^GREEN%^modify burger mealtype food%^RESET%^ %^GREEN%^modify schlitz mealtype alcohol%^RESET%^ %^GREEN%^modify apple mealstrength 10%^RESET%^ books ----- %^GREEN%^modify journal title The Orc Within%^RESET%^ %^GREEN%^modify journal source /domains/Orcland/etc/books/journal%^RESET%^ Readable things: ---------------- If you want to be able to \"read thing\", for example, \"read sign\": %^GREEN%^modify sign defaultread This is a message written on the sign.%^RESET%^ If you want to make a thing on a thing readable, as in \"read inscription on ring\": %^GREEN%^modify ring item%^RESET%^ %^GREEN%^inscription%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^This is an inscription on the ring. Try 'read inscription on ring'%^RESET%^ %^GREEN%^modify ring read%^RESET%^ %^GREEN%^inscription%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^So! We, the spear-Danes%^RESET%^ By default, readabale items are readable by anyone, regardless of the languages they know. If, however, your item should only be readable by someone who understands the elvish tongue: %^GREEN%^modify ring language edhellen%^RESET%^ Miscellaneous: -------------- To make a key have a 50% chance of breaking when it's used: %^GREEN%^modify golden key disablechance 50%^RESET%^ To make a room or object immune to resets: %^GREEN%^modify sentry noclean 1%^RESET%^ To make sure there is only one instance of an object or NPC loaded at any given time: %^GREEN%^modify tiamat unique 1%^RESET%^ To make a thing or room immune to the QCS (except for this command): %^GREEN%^modify workroom nomodify 1%^RESET%^ To specify what kind of vendor should be allowed to traffic in this item: %^GREEN%^modify necklace vendortype treasure%^RESET%^ ",({"chapter 16","chapter sixteen","16",}):"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 ",({"chapter 27","chapter twenty-seven","27",}):"chapter 27 \"Towns\" 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 ",({"chapter 37","chapter thirty-seven","37",}):"chapter 37 \"QCS: Modifying things and stuff\" You should have a firm grasp now on how QCS works in relation to manipulable objects. Let's look at the settings for a few special kinds of items: chairs ------ %^GREEN%^modify stool maxsitters 1%^RESET%^ %^GREEN%^modify stool setmaxcarry 200%^RESET%^ beds ---- %^GREEN%^modify sofa maxsitters 2%^RESET%^ %^GREEN%^modify sofa maxliers 1%^RESET%^ %^GREEN%^modify sofa maxcarry 400%^RESET%^ containers ---------- %^GREEN%^modify box canclose 1%^RESET%^ %^GREEN%^modify box closed 1%^RESET%^ %^GREEN%^modify box locked 1%^RESET%^ %^GREEN%^modify box key magic_skeleton_key%^RESET%^ %^GREEN%^modify box maxcarry 200%^RESET%^ %^GREEN%^modify box setmoney gold 15%^RESET%^ tables ------ %^GREEN%^modify altar maxcarry 300%^RESET%^ %^GREEN%^modify altar maxliers 1%^RESET%^ meals/drinks ------------ %^GREEN%^modify burger mealtype food%^RESET%^ %^GREEN%^modify schlitz mealtype alcohol%^RESET%^ %^GREEN%^modify apple mealstrength 10%^RESET%^ books ----- %^GREEN%^modify journal title The Orc Within%^RESET%^ %^GREEN%^modify journal source /domains/Orcland/etc/books/journal%^RESET%^ Readable things: ---------------- If you want to be able to \"read thing\", for example, \"read sign\": %^GREEN%^modify sign defaultread This is a message written on the sign.%^RESET%^ If you want to make a thing on a thing readable, as in \"read inscription on ring\": %^GREEN%^modify ring item%^RESET%^ %^GREEN%^inscription%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^This is an inscription on the ring. Try 'read inscription on ring'%^RESET%^ %^GREEN%^modify ring read%^RESET%^ %^GREEN%^inscription%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^So! We, the spear-Danes%^RESET%^ By default, readabale items are readable by anyone, regardless of the languages they know. If, however, your item should only be readable by someone who understands the elvish tongue: %^GREEN%^modify ring language edhellen%^RESET%^ Miscellaneous: -------------- To make a key have a 50% chance of breaking when it's used: %^GREEN%^modify golden key disablechance 50%^RESET%^ To make a room or object immune to resets: %^GREEN%^modify sentry noclean 1%^RESET%^ To make sure there is only one instance of an object or NPC loaded at any given time: %^GREEN%^modify tiamat unique 1%^RESET%^ To make a thing or room immune to the QCS (except for this command): %^GREEN%^modify workroom nomodify 1%^RESET%^ To specify what kind of vendor should be allowed to traffic in this item: %^GREEN%^modify necklace vendortype treasure%^RESET%^ ",({"chapter 3","chapter three","3",}):"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. ",({"chapter 36","chapter thirty-six","36",}):"chapter 36 \"QCS: Modifying weapons\" Remember that the QCS chapters are supposed to be read in sequence. This is important because as we progress, I will not make explanations about directives and concepts explained previously. Weapons are different from rooms and NPC's in that they can be handled, sold, thrown, etc. They are manipulable objects. As such, we will see new directives: %^GREEN%^create weapon hammer%^RESET%^ You may be familiar with this example from the example webpage. Let's go ahead and plow through the commands: %^GREEN%^modify weapon id hammer%^RESET%^ %^GREEN%^warhammer%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^modify hammer name hammer%^RESET%^ %^GREEN%^modify hammer damagetype blunt%^RESET%^ %^GREEN%^modify hammer weapontype blunt%^RESET%^ %^GREEN%^modify hammer mass 700%^RESET%^ %^GREEN%^modify hammer hands 2%^RESET%^ %^GREEN%^modify hammer short a heavy war hammer%^RESET%^ %^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%^ %^GREEN%^modify hammer adj%^RESET%^ %^GREEN%^large%^RESET%^ %^GREEN%^heavy%^RESET%^ %^GREEN%^war%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^modify hammer basecost silver 750%^RESET%^ %^GREEN%^about hammer%^RESET%^ Like a room and unlike an NPC, you can also modify the SetItems on manipulable objects like weapons, so you could do something like this: %^GREEN%^modify hammer item%^RESET%^ %^GREEN%^shaft%^RESET%^ %^GREEN%^handle%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^A thick, reinforced steel shaft with leather bands for a strong grip.%^RESET%^ %^GREEN%^exa shaft on hammer%^RESET%^ ",({"chapter 11","chapter eleven","11",}):"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 ",({"chapter 27","chapter twenty-seven","27",}):"chapter 27 \"Towns\" 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 ",({"chapter 21","chapter twenty-one","21",}):"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. ",({"chapter 23","chapter twenty-three","23",}):"chapter 23 \"Properties\" 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. ",({"chapter 29","chapter twenty-nine","29",}):"chapter 29 \"Weapons\" 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 ",({"chapter 8","chapter eight","8",}):"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. // CORRECTION: move_object() does not take two arguments in recent // versions of MudOS. -Crat 24Feb2007 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) ",({"chapter 11","chapter eleven","11",}):"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 ",({"chapter 3","chapter three","3",}):"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. ",({"chapter 12","chapter twelve","12",}):"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 ",({"chapter 40","chapter forty","40",}):"chapter 40 \"Useful Creator Commands\" Moving around: ------------- * To go to your workroom: %^GREEN%^home%^RESET%^ * To go to someone else's workroom, \"home <person>\", for example: %^GREEN%^home cratylus%^RESET%^ * To go to the town pub: %^GREEN%^goto /domains/town/room/tavern%^RESET%^ * Or: %^GREEN%^cd /domains/town/room%^RESET%^ %^GREEN%^goto tavern%^RESET%^ * To return to where you were before you went somewhere else: %^GREEN%^return%^RESET%^ * To bring someone to you, \"trans <person>\". For example: %^GREEN%^trans cratylus%^RESET%^ * To send them back when you're done with them: %^GREEN%^return cratylus%^RESET%^ Dealing with living beings: --------------------------- * To force everyone in a room to stop fighting: %^GREEN%^quell%^RESET%^ * To let them resume combat: %^GREEN%^unquell%^RESET%^ * To insta-kill a living being, \"zap <thing>\". For example: %^GREEN%^zap orc%^RESET%^ * To bring to life a player who somehow left the death room without regenerating, \"resurrect <person>\", For example: %^GREEN%^resurrect cratylus%^RESET%^ * To make a living being do something you want, \"force <thing> <command>\". For example: %^GREEN%^force thief drop towel%^RESET%^ %^GREEN%^force thief go west%^RESET%^ * For complex management of a living being's vital statistics, skills, health, score, and satiety levels, use the medical tricorder in the chest in your workroom. * For a detailed report of a living being's physical status: %^GREEN%^stat orc%^RESET%^ %^GREEN%^stat cratylus%^RESET%^ Handling objects in general: --------------------------- * To destroy an object, \"dest <thing>\". Note that the object's inventory will probably move to the room it was occupying. For example, if you: %^GREEN%^dest fighter%^RESET%^ You may find that the room now contains a sword, shield, and chainmail shirt, but no fighter. * To reset an object to its original state, \"reload <thing>\". Note that this also makes the object incorporate any changes you made to its file. For example: %^GREEN%^reload fighter%^RESET%^ %^GREEN%^reload here%^RESET%^ * To load a file into memory, \"update file\". This is used when you have edited an object's file, and want the mud to use the new stuff you created. For example, if you edited the fighter's file and wanted to know if it will load properly into memory, you'd type: %^GREEN%^update /realms/you/area/npc/fighter.c%^RESET%^ Or: %^GREEN%^cd /realms/you/area/npc/%^RESET%^ %^GREEN%^update fighter%^RESET%^ If you do not specify an object to update, the mud assumes you want to update the room you are in. If there is a problem with the room's code, and it does not load, you will be dropped into the \"void\". If the room's code is ok and it updates, anything in the room that isn't part of its permanent inventory (except for players) will disappear from the room. * To make a copy of an object appear, \"clone <file>\". For example: %^GREEN%^clone /realms/you/area/npc/fighter%^RESET%^ Or: %^GREEN%^cd /realms/you/area/npc/%^RESET%^ %^GREEN%^clone fighter%^RESET%^ * To know the precise contents of an object, use scan: %^GREEN%^scan fighter%^RESET%^ %^GREEN%^scan here%^RESET%^ If you want to know not only what the fighter has, but also what any containers he is carrying have, use the \"-d\" flag: %^GREEN%^scan -d fighter%^RESET%^ %^GREEN%^scan -d here%^RESET%^ Debugging commands: -------------------- * elog: This will report back to you the last few lines of your error log. Usually this is very helpful in nailing down which lines of a file contain errors. If you are admin, you may be working on files other than your home dir. If those files fail to update, you can supply elog with a directory name to specify where to look for an error report: %^GREEN%^elog secure%^RESET%^ %^GREEN%^elog cmds%^RESET%^ %^GREEN%^elog lib%^RESET%^ * dbxwhere: provides a list of the chain of messages caught in your last runtime error. * dbxframe <number>: Using the list number from dbxwhere, dbxframe can pinpoint exactly where in that link the error came from. %^GREEN%^tail /log/runtime%^RESET%^ %^GREEN%^tail /log/catch%^RESET%^ %^GREEN%^tail /log/player_errors%^RESET%^ miscellaneous useful commands: ----------------------------- * %^GREEN%^people%^RESET%^: reports who is logged on, what site they logged in from, and what room they are in. * %^GREEN%^mudtime%^RESET%^: reports the time of day in the mud (nothing to do with the time of day anywhere in the real world). * %^GREEN%^bk <thing or file>%^RESET%^: makes a unique copy of that thing or file and puts it in /realms/you/bak *%^GREEN%^ restore <filename>%^RESET%^: copies the last backup of the filename from your bak/ directory into where it used to be. ",({"chapter 30","chapter thirty","30",}):"chapter 30 \"The Natural Language Parser\" The Natural Language Parser The Problem A gut reaction to this entire system is to be overwhelmed by its apparent complexity, comparing it to the good-old days of using add_action(). A discussion of the natural language parsing system therefore needs to start by answering the question, \"Why bother?\". The old way of handling user input was to define commands and tie them to functions using add_action. Each user object kept track which commands it had available to it, and of which functions each command would trigger. The list of commands changed each time the player object (really, any object which had enable_commands() called in it) moved. In addition, each time an object moved inside the player object or left its inventory, this list changed. This led to two basic problems: 1. The same command might have slightly different uses in different parts of the mud. Or worse, the player could have two similar objects which define the same command in slightly different ways. 2. The complexity of syntax varied based on creator abilities and was limited by CPU. For example, one creator could have created a rock in their area that added the 'throw' command. This creator is a newbie creator, and thus simply put the following code in their throw_rock() function: int throw_rock(string str) { object ob; if( !str ) return 0; ob = present(str, this_player()); if( !ob ) { notify_fail(\"You have no rock!\"); return 0; } if( ob != this_object() ) return 0; if( (int)ob->move(environment(this_player())) != MOVE_OK ) { write(\"You cannot throw it for some reason.\"); return 1; } write(\"You throw the rock.\"); say((string)this_player()->query_cap_name() + \" throws the rock.\"); return 1; } In this case, \"throw rock\" will work, but \"throw the granite rock at tommy\" will not. But another creator also defined a throw command in their spear. This creator however, is a good coder and codes their throw_spear() command to handle 'throw the red spear at tommy' as well as 'throw spear'. Explain to a player why both syntaxes only work for the spear, and not for the rock. Then explain to that player why 'throw rock' for a rock built in yet another area yields 'What?'. An early attempt to get around this problem was the parse_command(). Unfortunately it was buggy spaghetti that was way too complex for anyone to understand. The MudOS attempt to solve this problem is its new natural language command parser. The parser is based on the following assumptions: All commands should behave in a consistent manner across the mud. Similar objects should respond as expected to the same command line. A player should only see 'What?' (or its equivalent) when they make a typo. It should enable creators to handle the complex command processing required by the above assumption. Overview of the MudOS System The MudOS natural language parser is based on a philosophy of centralized command parsing. In other words, creators have no control over which commands exist nor over what syntax rules existing commands follow. Instead, creators are tasked with defining what those commands mean to their objects. Unlike with add_action() where commands are registered to the driver, the MudOS system registers verbs (the command) and rules with the driver. In this example, a simple \"smile\" verb is registered with a single rule, \"at LIV\". With the old way of doing things, commands were executed either when a player entered in a command or when the command() efun was called. With this new system, a command may be executed at any time via either the parse_sentence() or parse_my_rules() efuns. When one of those efuns is called, the driver searches through the list of verbs for a verb and rule which matches the command string. In order to do that, however, it needs to make several calls of all the objects involved to determine what the sentence means. For any given command string, the following objects are relevant to the parsing of that command string: the verb handler This object contains the functions used to see if the command is valid and to execute it. It is also the one that creates the rules for the verb. the subject This is the object from which parse_sentence() is called, or the object mentioned as the first argument in parse_my_rules(). It is the object considered to be executing the command in questin, the logical subject of the sentence. the master object This object keeps track of global information, such was what literals (mistakenly referred to as prepositions) exist across the mud. In general, a literal is a preposition. the direct object This is not the logical direct object of the sentence. Rather, this is the first object at which the verb action is targetted. the indirect object Again, this is not the logical indirect object of the sentence. Rather, it is the second object at which the verb action is targetted. For example, in \"give the book to the elf\", the elf will be both the logical indirect object and the parser indirect object. But if you allow \"give the elf the book\", the elf naturally still remains the logical indirect object, but the book is the indirect object to the parser since it is the second object targetted by the verb (the first being the elf). Each object involved in he parsing of a sentence, except the subject, is responsible for handling certain driver applies that help the driver in parsing the sentence. The subject, unlike the other objects, is responsible for initiating the command. Although this document treats all of these objects as if they were completely distinct, it is possible to have the same object performing multiple roles for the same command. For example, your subject could also be direct object and verb handler. The next section discusses the objects and the applies they are responsible for in detail. The Objects Before studying each object in detail, it is important to keep in mind that each object which can be involved in any role must call parse_init() before doing anything related to verb parsing. The only exception is the master object. The subject The subject is simply the initiator of a command. A command is typically initiated by a call to parse_sentence() inside the object's process_input() apply. This example shows how a player object might use parse_sentence() to initiate a command. This efun will return 1 if the command successfully matched a known verb and rule and successfully executed it. If it found the verb in question, but it did not match any rule, then 0 is returned. If it found the verb in question and matched a rule, but the execution of the rule failed, it will return an errorstring describing why it failed. Finally, if no verb matched the command, then -1 is returned. Take for example a mud with this one rule: parse_add_rule(\"smile\", \"at LIV\") The efun parse_sentence() would return the following values for the following command lines: smile at descartes Returns: 1 smile happily Returns: 0 smile at the red box Returns: \"The Box is not a living thing!\" eat the red box Returns: -1 The master object The master object is responsible for a single apply, parse_command_prepos_list(). This apply returns a list of literal strings which may be used in a rule. A literal string is simply one that appears in the rule exactly as a player types it. In the smile example above, \"at\" is a literal. In most all cases, literals are prepositions, thus the name of the apply. The verb handler The verb handler object is responsible for setting up the rules for a verb and handling the test and execution of those rules. This example demonstrates a simple verb handler for the smile verb described above. As you can see, each rule is divided up into three parts: 1. initialization 2. testing 3. execution The intialization is the call to parse_add_rule(). This associates a rule with a verb. The first argument is the verb (this verb may have spaces in it, like \"look at\") and the second argument is one of the rules being handled by this verb handler. This list defines the valid tokens for a rule. The testing portion is a \"can\" apply. In testing a rule, the driver calls the applies can_<verb_rule> to determine if the execution of the verb even makes sense in this situation. The test apply is called when the driver has valid arguments to a rule, but it wants to see if those valid arguments make sense right now. For example, you might check a player here to see if they have enough magic points for casting the spell this verb/rule represents. If not, you might return \"You are too tired right now.\". If the rule match up in question makes completely no sense at all, like for example, they tried to throw a house for the (\"throw\", \"OBJ\") rule, you should return 0. The parser will guess well an error message from the situation. In this case, it will have parse_sentence() return \"You cannot throw the thing.\". Finally execution is where the verb actually happens. You know you have a verb/rule match and you know all the arguments to it are valid. Now it is time to do something. You almost always want to return 1 from this function except in extreme circumstances. The direct and indirect objects As stated above, the directness or indirectness of an object has nothing to do with the linguistic meaning of those terms. Instead it has to do with what position in the token list the object takes. The direct object is the first object in the token list, and the indirect object is the second object in the token list. These objects basically answer the question \"Can I be the direct/indirect object for this verb and rule?\". Like the testing and execution applies for verb handlers, the applies that answer this question may return 1, 0, or an error string. Also like the testing and execution applies for the verb handler, these come in the form of (in)direct_<verb>_<rule>(). This example is from somewhere inside the living object heirarchy. Note the is_living() apply which lets the parser know that the object matches a LIV token. Inventory visibility Some objects are subjects, direct objects, or indirect objects of verbs which require access to things in their inventory. For example, living things, bags, chests, etc. all need to allow other things access to their inventories for some commands. Two applies handle this situation: 1. inventory_accessible() 2. inventory_visible() The first returns 1 if verbs can have access to an object's inventory, the second returns 1 if verbs simply can take into account an object's inventory. An example of the difference might be a glass chest. When closed, you want its inventory to be visible, but not accessible. It is important to remember that is the return value for any of these special applies, including is_living(), you need to make an explicit call to the parse_refresh() efun. Unless the parse_refresh() efun is called, these special applies are only called once with no guarantee as to when that one call will actually occur. Creating a New Verb Currently, the Lima and Nightmare mudlibs use this parser system. Both mudlibs provide inheritable objects which make it simpler to interface with the MudOS parser system. Nightmare specifically has the inheritable LIB_VERB with methods for defining a new verb. This verb example comes from the Nightmare mudlib. The simple Nightmare verb requires the following steps: 1. Name the verb 2. State the verb rules 3. Name any synonyms 4. Set an error message for display when the command is wrongly used 5. Create help text for the command Naming the verb is done through the SetVerb() method. You simply specify the name of the verb. The rules are passed to the SetRules() method. You may specify as many rules as are needed for the verb. Like rules, synonyms are set as a list for the SetSynonyms() method. A synonym is simply any verb which is exactly synonymous with any possible rule for the verb in question. The player is able to access help for the verb and get error messages for the verb through the verb or any of its synonyms. The error message is a string displayed to the user when they use the verb in an incorrect manner. For example, if I typed 'eat' when the rule is 'eat OBJ', the error message would be 'Eat what?'. Finally, like with any object, the help text can be set through the SetHelp() method. Help is very important for verbs. All of these methods only are able to take care of verb initalization. It is up to the verb creator to give meaning to a new verb. This is done first off by writing can_*() and do_*() applies in the verb handler. These methods should be very simplistic in nature. For example, a can method almost always simply returns 1. A do method generally finds its target and triggers some sort of event in that object. The event does the real command handling. In addition to can and do applies, you need also to write any direct and indirect applies in approperiate objects. Nightmare centralizes this sort of processing through inheritables geared towards responding to particular verbs. A good example of this is LIB_PRESS which responds to the \"press\" command. Thus any object which should be pressable needs only to inherit this object to become a pressable object. The can, do, direct, and indirect applies all have the same argument set for the same verb/rule pair, but it is important to know when the parser knows certan things. Take for example the verb/rule \"press OBJ on OBJ\". The parser takes the following actions: 1. Call can_press_obj_on_obj() in verb handler 2. Call direct_press_obj_on_obj() in all accessible and visible objects 3. Call indirect_press_obj_on_obj() in all accessible and visible objects 4. Call do_press_obj_on_obj() in the verb handler The arguments to all methods called in this process are: 1. object direct_object 2. object indirect_object 3. string direct_object_as_entered_on_command_line 4. string indirect_object_as_entered_on_command_line But how can can_press_obj_on_obj() know what the direct and indirect objects are if they have not been identified yet? The answer is that it cannot. For the command \"push the button on the wall\", in a room with me and you in it and we carry nothing, the sequence looks like this (return in parens): 1. verb->can_press_obj_on_obj(0, 0, \"the button\", \"the wall\"); (1) 2. me->direct_press_obj_on_obj(0, 0, \"the button\", the wall\"); (0) 3. you->direct_press_obj_on_obj(0, 0, \"the button\", \"the wall\"); (0) 4. room->direct_press_obj_on_obj(0, 0, \"the button\", \"the wall\"); (1) 5. me->indirect_press_obj_on_obj(room, 0, \"the button\", \"the wall\"); (0) 6. you->indirect_press_obj_on_obj(room, 0, \"the button\", \"the wall\"); (0) 7. room->indirect_press_obj_on_obj(room, 0, \"the button\", \"the wall\"); (1) 8. verb->do_press_obj_on_obj(room, room, \"the buton\", \"the wall\"); (1) This assumes, of course, that the room responds positively with the id's \"button\" and \"wall\". People familiar with the parser might say, \"Hey, wait, there is a lot more that happens than just that.\" In fact, there are many more possible permutations of this sequence. The most interesting is the ability to simply ignore the difference between prepositions like \"in\" and \"into\" which are often used interchangeably in colloquial speech. For example, if you had \"put OBJ in OBJ\" and \"put OBJ into OBJ\" verb/rules, you could handle them in a single place for each of the applies respectively liek this: can_put_obj_word_obj() direct_put_obj_word_obj() indirect_put_obj_word_obj() do_put_obj_word_obj() If the parser found no can_put_obj_in_obj() defined, it then searches for a more generic handler, can_put_obj_word_obj(). In fact the real order it searches for a can handler is: 1. can_put_obj_in_obj() 2. can_put_obj_word_obj() 3. can_put_rule() 4. can_verb_rule() --------------------- Last example: static void create() { parse_init(); parse_add_rule(\"smile\", \"at LIV\"); } mixed can_smile_at_liv(object target) { return 1; } mixed do_smile_at_liv(object target) { previous_object()->eventPrint(\"You smile at \" + (string)target->GetName() + \".\"); target->eventPrint((string)previous_object()->GetName() + \" smiles at you.\"); return 1; } ",({"chapter 18","chapter eighteen","18",}):"chapter 18 \"Valid climates\" indoors temperate arid arctic tropical sub-tropical ",({"chapter 31","chapter thirty-one","31",}):"chapter 31 \"Overview of the Quick Creation System\" First, let me clarify that the QCS is not intended to replace good coding habits. It is also not designed to handle every possible need of a builder. The QCS is just a handy tool for making the most tedious parts of building easier. The amount of time it takes to hand-code an area of 100 rooms (a small area, that is), with all the appropriate descriptions and monsters and weapons and such is just mind-boggling. As a grown-up, I just don't have time for building stuff line by excruciating line in raw LPC, because I also need to work, maintain my house, say hello to my family on occasion, etc. At the same time, I would need a team of dedicated LPC code fetishists to make a creation system that covers every last possible thing you could do in LPC. The QCS is somewhere in between those two extremes. Therefore please view the QCS as a quick way to get bulk building done, and not as a be-all end-all solution. You still need to learn LPC to do really cool stuff. But to hammer out an area with a quest, QCS lets you sail through the process of thingmaking with little hassle. The design philosophy of the system itself involves object files stored in /secure/modules. These files are inherited by an object which you need to carry with you in order to use the QCS system. The code for these creation modules is fairly messy and inelegant, but the result is clean, indented code that compiles, so let's keep the mockery to a minimum, shall we? It is important to keep in mind the QCS isn't an editing system. It's real live on-line modification, meaning that to modify a thing, it actually has to be in the same room you are in, or it has to be that room itself. Once you modify something, it will typically update, so that if you change the name of an npc, you're going to need to use the new name to modify it further. The next few chapters in this manual are nominally QCS specific, but in reality this is pretty much my only chance to document some of the changes in Dead Souls since version 1, so even if you never intend to use QCS, it's worth poking through these chapters. - Cratylus @ Frontiers 2 January 2006 ",({"chapter 8","chapter eight","8",}):"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. // CORRECTION: move_object() does not take two arguments in recent // versions of MudOS. -Crat 24Feb2007 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) ",({"chapter 1","chapter one","1",}):"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. ",({"chapter 13","chapter thirteen","13",}):"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 ",({"chapter 24","chapter twenty-four","24",}):"chapter 24 \"Quests\" 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 ",({"chapter 19","chapter nineteen","19",}):"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. ",({"chapter 5","chapter five","5",}):"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. ",({"chapter 6","chapter six","6",}):"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 :) ",({"chapter 30","chapter thirty","30",}):"chapter 30 \"The Natural Language Parser\" The Natural Language Parser The Problem A gut reaction to this entire system is to be overwhelmed by its apparent complexity, comparing it to the good-old days of using add_action(). A discussion of the natural language parsing system therefore needs to start by answering the question, \"Why bother?\". The old way of handling user input was to define commands and tie them to functions using add_action. Each user object kept track which commands it had available to it, and of which functions each command would trigger. The list of commands changed each time the player object (really, any object which had enable_commands() called in it) moved. In addition, each time an object moved inside the player object or left its inventory, this list changed. This led to two basic problems: 1. The same command might have slightly different uses in different parts of the mud. Or worse, the player could have two similar objects which define the same command in slightly different ways. 2. The complexity of syntax varied based on creator abilities and was limited by CPU. For example, one creator could have created a rock in their area that added the 'throw' command. This creator is a newbie creator, and thus simply put the following code in their throw_rock() function: int throw_rock(string str) { object ob; if( !str ) return 0; ob = present(str, this_player()); if( !ob ) { notify_fail(\"You have no rock!\"); return 0; } if( ob != this_object() ) return 0; if( (int)ob->move(environment(this_player())) != MOVE_OK ) { write(\"You cannot throw it for some reason.\"); return 1; } write(\"You throw the rock.\"); say((string)this_player()->query_cap_name() + \" throws the rock.\"); return 1; } In this case, \"throw rock\" will work, but \"throw the granite rock at tommy\" will not. But another creator also defined a throw command in their spear. This creator however, is a good coder and codes their throw_spear() command to handle 'throw the red spear at tommy' as well as 'throw spear'. Explain to a player why both syntaxes only work for the spear, and not for the rock. Then explain to that player why 'throw rock' for a rock built in yet another area yields 'What?'. An early attempt to get around this problem was the parse_command(). Unfortunately it was buggy spaghetti that was way too complex for anyone to understand. The MudOS attempt to solve this problem is its new natural language command parser. The parser is based on the following assumptions: All commands should behave in a consistent manner across the mud. Similar objects should respond as expected to the same command line. A player should only see 'What?' (or its equivalent) when they make a typo. It should enable creators to handle the complex command processing required by the above assumption. Overview of the MudOS System The MudOS natural language parser is based on a philosophy of centralized command parsing. In other words, creators have no control over which commands exist nor over what syntax rules existing commands follow. Instead, creators are tasked with defining what those commands mean to their objects. Unlike with add_action() where commands are registered to the driver, the MudOS system registers verbs (the command) and rules with the driver. In this example, a simple \"smile\" verb is registered with a single rule, \"at LIV\". With the old way of doing things, commands were executed either when a player entered in a command or when the command() efun was called. With this new system, a command may be executed at any time via either the parse_sentence() or parse_my_rules() efuns. When one of those efuns is called, the driver searches through the list of verbs for a verb and rule which matches the command string. In order to do that, however, it needs to make several calls of all the objects involved to determine what the sentence means. For any given command string, the following objects are relevant to the parsing of that command string: the verb handler This object contains the functions used to see if the command is valid and to execute it. It is also the one that creates the rules for the verb. the subject This is the object from which parse_sentence() is called, or the object mentioned as the first argument in parse_my_rules(). It is the object considered to be executing the command in questin, the logical subject of the sentence. the master object This object keeps track of global information, such was what literals (mistakenly referred to as prepositions) exist across the mud. In general, a literal is a preposition. the direct object This is not the logical direct object of the sentence. Rather, this is the first object at which the verb action is targetted. the indirect object Again, this is not the logical indirect object of the sentence. Rather, it is the second object at which the verb action is targetted. For example, in \"give the book to the elf\", the elf will be both the logical indirect object and the parser indirect object. But if you allow \"give the elf the book\", the elf naturally still remains the logical indirect object, but the book is the indirect object to the parser since it is the second object targetted by the verb (the first being the elf). Each object involved in he parsing of a sentence, except the subject, is responsible for handling certain driver applies that help the driver in parsing the sentence. The subject, unlike the other objects, is responsible for initiating the command. Although this document treats all of these objects as if they were completely distinct, it is possible to have the same object performing multiple roles for the same command. For example, your subject could also be direct object and verb handler. The next section discusses the objects and the applies they are responsible for in detail. The Objects Before studying each object in detail, it is important to keep in mind that each object which can be involved in any role must call parse_init() before doing anything related to verb parsing. The only exception is the master object. The subject The subject is simply the initiator of a command. A command is typically initiated by a call to parse_sentence() inside the object's process_input() apply. This example shows how a player object might use parse_sentence() to initiate a command. This efun will return 1 if the command successfully matched a known verb and rule and successfully executed it. If it found the verb in question, but it did not match any rule, then 0 is returned. If it found the verb in question and matched a rule, but the execution of the rule failed, it will return an errorstring describing why it failed. Finally, if no verb matched the command, then -1 is returned. Take for example a mud with this one rule: parse_add_rule(\"smile\", \"at LIV\") The efun parse_sentence() would return the following values for the following command lines: smile at descartes Returns: 1 smile happily Returns: 0 smile at the red box Returns: \"The Box is not a living thing!\" eat the red box Returns: -1 The master object The master object is responsible for a single apply, parse_command_prepos_list(). This apply returns a list of literal strings which may be used in a rule. A literal string is simply one that appears in the rule exactly as a player types it. In the smile example above, \"at\" is a literal. In most all cases, literals are prepositions, thus the name of the apply. The verb handler The verb handler object is responsible for setting up the rules for a verb and handling the test and execution of those rules. This example demonstrates a simple verb handler for the smile verb described above. As you can see, each rule is divided up into three parts: 1. initialization 2. testing 3. execution The intialization is the call to parse_add_rule(). This associates a rule with a verb. The first argument is the verb (this verb may have spaces in it, like \"look at\") and the second argument is one of the rules being handled by this verb handler. This list defines the valid tokens for a rule. The testing portion is a \"can\" apply. In testing a rule, the driver calls the applies can_<verb_rule> to determine if the execution of the verb even makes sense in this situation. The test apply is called when the driver has valid arguments to a rule, but it wants to see if those valid arguments make sense right now. For example, you might check a player here to see if they have enough magic points for casting the spell this verb/rule represents. If not, you might return \"You are too tired right now.\". If the rule match up in question makes completely no sense at all, like for example, they tried to throw a house for the (\"throw\", \"OBJ\") rule, you should return 0. The parser will guess well an error message from the situation. In this case, it will have parse_sentence() return \"You cannot throw the thing.\". Finally execution is where the verb actually happens. You know you have a verb/rule match and you know all the arguments to it are valid. Now it is time to do something. You almost always want to return 1 from this function except in extreme circumstances. The direct and indirect objects As stated above, the directness or indirectness of an object has nothing to do with the linguistic meaning of those terms. Instead it has to do with what position in the token list the object takes. The direct object is the first object in the token list, and the indirect object is the second object in the token list. These objects basically answer the question \"Can I be the direct/indirect object for this verb and rule?\". Like the testing and execution applies for verb handlers, the applies that answer this question may return 1, 0, or an error string. Also like the testing and execution applies for the verb handler, these come in the form of (in)direct_<verb>_<rule>(). This example is from somewhere inside the living object heirarchy. Note the is_living() apply which lets the parser know that the object matches a LIV token. Inventory visibility Some objects are subjects, direct objects, or indirect objects of verbs which require access to things in their inventory. For example, living things, bags, chests, etc. all need to allow other things access to their inventories for some commands. Two applies handle this situation: 1. inventory_accessible() 2. inventory_visible() The first returns 1 if verbs can have access to an object's inventory, the second returns 1 if verbs simply can take into account an object's inventory. An example of the difference might be a glass chest. When closed, you want its inventory to be visible, but not accessible. It is important to remember that is the return value for any of these special applies, including is_living(), you need to make an explicit call to the parse_refresh() efun. Unless the parse_refresh() efun is called, these special applies are only called once with no guarantee as to when that one call will actually occur. Creating a New Verb Currently, the Lima and Nightmare mudlibs use this parser system. Both mudlibs provide inheritable objects which make it simpler to interface with the MudOS parser system. Nightmare specifically has the inheritable LIB_VERB with methods for defining a new verb. This verb example comes from the Nightmare mudlib. The simple Nightmare verb requires the following steps: 1. Name the verb 2. State the verb rules 3. Name any synonyms 4. Set an error message for display when the command is wrongly used 5. Create help text for the command Naming the verb is done through the SetVerb() method. You simply specify the name of the verb. The rules are passed to the SetRules() method. You may specify as many rules as are needed for the verb. Like rules, synonyms are set as a list for the SetSynonyms() method. A synonym is simply any verb which is exactly synonymous with any possible rule for the verb in question. The player is able to access help for the verb and get error messages for the verb through the verb or any of its synonyms. The error message is a string displayed to the user when they use the verb in an incorrect manner. For example, if I typed 'eat' when the rule is 'eat OBJ', the error message would be 'Eat what?'. Finally, like with any object, the help text can be set through the SetHelp() method. Help is very important for verbs. All of these methods only are able to take care of verb initalization. It is up to the verb creator to give meaning to a new verb. This is done first off by writing can_*() and do_*() applies in the verb handler. These methods should be very simplistic in nature. For example, a can method almost always simply returns 1. A do method generally finds its target and triggers some sort of event in that object. The event does the real command handling. In addition to can and do applies, you need also to write any direct and indirect applies in approperiate objects. Nightmare centralizes this sort of processing through inheritables geared towards responding to particular verbs. A good example of this is LIB_PRESS which responds to the \"press\" command. Thus any object which should be pressable needs only to inherit this object to become a pressable object. The can, do, direct, and indirect applies all have the same argument set for the same verb/rule pair, but it is important to know when the parser knows certan things. Take for example the verb/rule \"press OBJ on OBJ\". The parser takes the following actions: 1. Call can_press_obj_on_obj() in verb handler 2. Call direct_press_obj_on_obj() in all accessible and visible objects 3. Call indirect_press_obj_on_obj() in all accessible and visible objects 4. Call do_press_obj_on_obj() in the verb handler The arguments to all methods called in this process are: 1. object direct_object 2. object indirect_object 3. string direct_object_as_entered_on_command_line 4. string indirect_object_as_entered_on_command_line But how can can_press_obj_on_obj() know what the direct and indirect objects are if they have not been identified yet? The answer is that it cannot. For the command \"push the button on the wall\", in a room with me and you in it and we carry nothing, the sequence looks like this (return in parens): 1. verb->can_press_obj_on_obj(0, 0, \"the button\", \"the wall\"); (1) 2. me->direct_press_obj_on_obj(0, 0, \"the button\", the wall\"); (0) 3. you->direct_press_obj_on_obj(0, 0, \"the button\", \"the wall\"); (0) 4. room->direct_press_obj_on_obj(0, 0, \"the button\", \"the wall\"); (1) 5. me->indirect_press_obj_on_obj(room, 0, \"the button\", \"the wall\"); (0) 6. you->indirect_press_obj_on_obj(room, 0, \"the button\", \"the wall\"); (0) 7. room->indirect_press_obj_on_obj(room, 0, \"the button\", \"the wall\"); (1) 8. verb->do_press_obj_on_obj(room, room, \"the buton\", \"the wall\"); (1) This assumes, of course, that the room responds positively with the id's \"button\" and \"wall\". People familiar with the parser might say, \"Hey, wait, there is a lot more that happens than just that.\" In fact, there are many more possible permutations of this sequence. The most interesting is the ability to simply ignore the difference between prepositions like \"in\" and \"into\" which are often used interchangeably in colloquial speech. For example, if you had \"put OBJ in OBJ\" and \"put OBJ into OBJ\" verb/rules, you could handle them in a single place for each of the applies respectively liek this: can_put_obj_word_obj() direct_put_obj_word_obj() indirect_put_obj_word_obj() do_put_obj_word_obj() If the parser found no can_put_obj_in_obj() defined, it then searches for a more generic handler, can_put_obj_word_obj(). In fact the real order it searches for a can handler is: 1. can_put_obj_in_obj() 2. can_put_obj_word_obj() 3. can_put_rule() 4. can_verb_rule() --------------------- Last example: static void create() { parse_init(); parse_add_rule(\"smile\", \"at LIV\"); } mixed can_smile_at_liv(object target) { return 1; } mixed do_smile_at_liv(object target) { previous_object()->eventPrint(\"You smile at \" + (string)target->GetName() + \".\"); target->eventPrint((string)previous_object()->GetName() + \" smiles at you.\"); return 1; } ",({"chapter 3","chapter three","3",}):"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. ",({"chapter 18","chapter eighteen","18",}):"chapter 18 \"Valid climates\" indoors temperate arid arctic tropical sub-tropical ",({"chapter 35","chapter thirty-five","35",}):"chapter 35 \"QCS: Modifying rooms\" Suppose you are in your sample room and you issued the command: %^GREEN%^create room south testroom1%^RESET%^ You then travel south and see that you are in a room that is almost exactly like the sample room except for the exits. Well, probably you don't want to have a mud with nothing but identical rooms, so let's modify it: %^GREEN%^modify here short Test Room One%^RESET%^ %^GREEN%^modify here long This is the first test room. The walls are rather blank.%^RESET%^ %^GREEN%^modify here climate indoors%^RESET%^ %^GREEN%^modify here light 30%^RESET%^ Ok, so far so good. Standard interior. However, a good mud has rooms with details. Let's add some detail to this room. I've omitted the system output for clarity. This is just what you would input. %^GREEN%^modify here item%^RESET%^ %^GREEN%^wall%^RESET%^ %^GREEN%^walls%^RESET%^ %^GREEN%^blank wall%^RESET%^ %^GREEN%^blank walls%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^These are just blank walls.%^RESET%^ Let's review what we've done here: 1) You issued the modify command specifying your current room as the target, and the SetItems directive as the argument. 2) You entered a query session, and were asked to enter each element of the item's key. 3) You entered a single dot to indicate you were done entering key elements. 4) You entered the value for the key, which is the description of the item. The result of all this is that now you can issue these commands: %^GREEN%^exa wall%^RESET%^ %^GREEN%^look at blank walls%^RESET%^ %^GREEN%^examine walls%^RESET%^ And the output will be: These are just blank walls. Let's add a floor while we're at it: %^GREEN%^modify here item%^RESET%^ %^GREEN%^floor%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^A floor like any other.%^RESET%^ In this case, you didn't feel like adding extra synonyms for \"floor\", so you entered the final dot rather than entering another key element. Then you added the description, and now if you \"exa floor\", you'll get that description. \"about here\" will display to you the file you have modified. Well, that's enough fun with indoor rooms. There's not much more to them. Let's go outdoors now: %^GREEN%^create room south exterior_room%^RESET%^ %^GREEN%^create door south test_door%^RESET%^ %^GREEN%^open door%^RESET%^ %^GREEN%^go south%^RESET%^ %^GREEN%^modify here short a small lawn%^RESET%^ %^GREEN%^modify here daylong A small, well groomed lawn on a lovely sunny day. There is a small building north of here.%^RESET%^ %^GREEN%^modify here nightlong This is a small lawn. Stars twinkle in the night sky above, and some light is coming from a small building to the north.%^RESET%^ %^GREEN%^modify here daylight 30%^RESET%^ %^GREEN%^modify here nightlight 20%^RESET%^ %^GREEN%^modify here light delete%^RESET%^ %^GREEN%^modify here long delete%^RESET%^ %^GREEN%^modify here items delete%^RESET%^ %^GREEN%^modify here items%^RESET%^ %^GREEN%^building%^RESET%^ %^GREEN%^small building%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^A small building, rather ramshackle as if hastily put together.%^RESET%^ %^GREEN%^modify here climate temperate%^RESET%^ Ok! A few new things here. A neat thing about outdoor rooms is that typically they are subject to the time of day. A SetClimate directive that indicates an exterior environment causes the room to receive messages about the sun setting, rising, etc. The SetDayLong and SetNightLong directives allow you to more sensibly describe the area depending on the time of day. To avoid confusion, I deleted the SetLong directive. It is not mandatory to have different day and night descriptions, but players appreciate the effort. It is also possible to have differing ambient light levels depending on the time of day, so we've added SetDayLight and SetNightLight, and we deleted the SetAmbientLight directive. Let's continue to add detail: %^GREEN%^modify here item%^RESET%^ %^GREEN%^lawn%^RESET%^ %^GREEN%^grass%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^Healthy, well groomed and freshly cut grass.%^RESET%^ %^GREEN%^modify here smell%^RESET%^ %^GREEN%^default%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^You can smell the refreshing scent of freshly cut grass.%^RESET%^ %^GREEN%^modify here smell%^RESET%^ %^GREEN%^lawn%^RESET%^ %^GREEN%^grass%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^Yep, it's got that new lawn smell.%^RESET%^ %^GREEN%^modify here listen%^RESET%^ %^GREEN%^building%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^Sounds like someone's fumbling about in there, making a mess. New creators can be so noisy.%^RESET%^ %^GREEN%^modify here item%^RESET%^ %^GREEN%^garden%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^You may enter the garden from here.%^RESET%^ %^GREEN%^create room garden garden_room%^RESET%^ You now have a room with lots of charm and detail. You can \"smell grass\" and \"listen to small building\", if you like. Neat, huh? But there's something very important to keep in mind: Enters, listens and smells don't work properly if there is no item defined for that smell. For example, if you want to be able to listen to the sea, you must \"modify here item\" and add a \"sea\" item. Otherwise, \"listen to the sea\" will respond with \"There is no sea here.\" The only exception to this rule is the \"default\" smell. Enters behave similarly. If you want to be able to \"enter\" something, you'll need to create the corresponding item first, as in the example above. You can use the SetProperties directive to make the room conform to some presets, like: %^GREEN%^modify here property no attack 1%^RESET%^ Read chapter 23 in the Creator's Manual for details on room properties. Also, please note that indoor rooms can also have differing descriptions and light levels for night and day. It's just that indoor rooms don't get notification of daytime changes. Finally, the SetTown directive allows the room to participate in area-wide events, and is useful for security purposes as well: %^GREEN%^modify here town MyTown%^RESET%^ Notes on room filenames: ----------------------- By default, a filename without a leading path creates a room in your area room directory, which in my case would be \"/realms/cratylus/area/room\". However, you can specify a different location for the new room. To create a room in your current working directory: %^GREEN%^create room east ./newroom%^RESET%^ To create a room in a specific directory: %^GREEN%^create room east /realms/cratylus/testrooms/newroom%^RESET%^ ",({"chapter 26","chapter twenty-six","26",}):"chapter 26 \"Sentients\" 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. ",({"chapter 7","chapter seven","7",}):"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. ",({"chapter 1","chapter one","1",}):"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. ",({"chapter 15","chapter fifteen","15",}):"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 ",({"chapter 25","chapter twenty-five","25",}):"chapter 25 \"Rooms\" 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 ",({"chapter 2","chapter two","2",}):"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. ",({"chapter 15","chapter fifteen","15",}):"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 ",({"chapter 4","chapter four","4",}):"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. ",({"chapter 35","chapter thirty-five","35",}):"chapter 35 \"QCS: Modifying rooms\" Suppose you are in your sample room and you issued the command: %^GREEN%^create room south testroom1%^RESET%^ You then travel south and see that you are in a room that is almost exactly like the sample room except for the exits. Well, probably you don't want to have a mud with nothing but identical rooms, so let's modify it: %^GREEN%^modify here short Test Room One%^RESET%^ %^GREEN%^modify here long This is the first test room. The walls are rather blank.%^RESET%^ %^GREEN%^modify here climate indoors%^RESET%^ %^GREEN%^modify here light 30%^RESET%^ Ok, so far so good. Standard interior. However, a good mud has rooms with details. Let's add some detail to this room. I've omitted the system output for clarity. This is just what you would input. %^GREEN%^modify here item%^RESET%^ %^GREEN%^wall%^RESET%^ %^GREEN%^walls%^RESET%^ %^GREEN%^blank wall%^RESET%^ %^GREEN%^blank walls%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^These are just blank walls.%^RESET%^ Let's review what we've done here: 1) You issued the modify command specifying your current room as the target, and the SetItems directive as the argument. 2) You entered a query session, and were asked to enter each element of the item's key. 3) You entered a single dot to indicate you were done entering key elements. 4) You entered the value for the key, which is the description of the item. The result of all this is that now you can issue these commands: %^GREEN%^exa wall%^RESET%^ %^GREEN%^look at blank walls%^RESET%^ %^GREEN%^examine walls%^RESET%^ And the output will be: These are just blank walls. Let's add a floor while we're at it: %^GREEN%^modify here item%^RESET%^ %^GREEN%^floor%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^A floor like any other.%^RESET%^ In this case, you didn't feel like adding extra synonyms for \"floor\", so you entered the final dot rather than entering another key element. Then you added the description, and now if you \"exa floor\", you'll get that description. \"about here\" will display to you the file you have modified. Well, that's enough fun with indoor rooms. There's not much more to them. Let's go outdoors now: %^GREEN%^create room south exterior_room%^RESET%^ %^GREEN%^create door south test_door%^RESET%^ %^GREEN%^open door%^RESET%^ %^GREEN%^go south%^RESET%^ %^GREEN%^modify here short a small lawn%^RESET%^ %^GREEN%^modify here daylong A small, well groomed lawn on a lovely sunny day. There is a small building north of here.%^RESET%^ %^GREEN%^modify here nightlong This is a small lawn. Stars twinkle in the night sky above, and some light is coming from a small building to the north.%^RESET%^ %^GREEN%^modify here daylight 30%^RESET%^ %^GREEN%^modify here nightlight 20%^RESET%^ %^GREEN%^modify here light delete%^RESET%^ %^GREEN%^modify here long delete%^RESET%^ %^GREEN%^modify here items delete%^RESET%^ %^GREEN%^modify here items%^RESET%^ %^GREEN%^building%^RESET%^ %^GREEN%^small building%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^A small building, rather ramshackle as if hastily put together.%^RESET%^ %^GREEN%^modify here climate temperate%^RESET%^ Ok! A few new things here. A neat thing about outdoor rooms is that typically they are subject to the time of day. A SetClimate directive that indicates an exterior environment causes the room to receive messages about the sun setting, rising, etc. The SetDayLong and SetNightLong directives allow you to more sensibly describe the area depending on the time of day. To avoid confusion, I deleted the SetLong directive. It is not mandatory to have different day and night descriptions, but players appreciate the effort. It is also possible to have differing ambient light levels depending on the time of day, so we've added SetDayLight and SetNightLight, and we deleted the SetAmbientLight directive. Let's continue to add detail: %^GREEN%^modify here item%^RESET%^ %^GREEN%^lawn%^RESET%^ %^GREEN%^grass%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^Healthy, well groomed and freshly cut grass.%^RESET%^ %^GREEN%^modify here smell%^RESET%^ %^GREEN%^default%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^You can smell the refreshing scent of freshly cut grass.%^RESET%^ %^GREEN%^modify here smell%^RESET%^ %^GREEN%^lawn%^RESET%^ %^GREEN%^grass%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^Yep, it's got that new lawn smell.%^RESET%^ %^GREEN%^modify here listen%^RESET%^ %^GREEN%^building%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^Sounds like someone's fumbling about in there, making a mess. New creators can be so noisy.%^RESET%^ %^GREEN%^modify here item%^RESET%^ %^GREEN%^garden%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^You may enter the garden from here.%^RESET%^ %^GREEN%^create room garden garden_room%^RESET%^ You now have a room with lots of charm and detail. You can \"smell grass\" and \"listen to small building\", if you like. Neat, huh? But there's something very important to keep in mind: Enters, listens and smells don't work properly if there is no item defined for that smell. For example, if you want to be able to listen to the sea, you must \"modify here item\" and add a \"sea\" item. Otherwise, \"listen to the sea\" will respond with \"There is no sea here.\" The only exception to this rule is the \"default\" smell. Enters behave similarly. If you want to be able to \"enter\" something, you'll need to create the corresponding item first, as in the example above. You can use the SetProperties directive to make the room conform to some presets, like: %^GREEN%^modify here property no attack 1%^RESET%^ Read chapter 23 in the Creator's Manual for details on room properties. Also, please note that indoor rooms can also have differing descriptions and light levels for night and day. It's just that indoor rooms don't get notification of daytime changes. Finally, the SetTown directive allows the room to participate in area-wide events, and is useful for security purposes as well: %^GREEN%^modify here town MyTown%^RESET%^ Notes on room filenames: ----------------------- By default, a filename without a leading path creates a room in your area room directory, which in my case would be \"/realms/cratylus/area/room\". However, you can specify a different location for the new room. To create a room in your current working directory: %^GREEN%^create room east ./newroom%^RESET%^ To create a room in a specific directory: %^GREEN%^create room east /realms/cratylus/testrooms/newroom%^RESET%^ ",({"chapter 29","chapter twenty-nine","29",}):"chapter 29 \"Weapons\" 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 ",({"chapter 10","chapter ten","10",}):"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 ",({"chapter 29","chapter twenty-nine","29",}):"chapter 29 \"Weapons\" 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 ",({"chapter 38","chapter thirty-eight","38",}):"chapter 38 \"QCS: Adding and deleting\" Rooms, containers and NPC's all are capable of holding items, and often it is convenient to have them already holding certain items upon creation. The SetInventory directive in an object's file provides us with a list of that object's \"permanent inventory\". To modify an object's inventory, we use the add and delete commands. Let's say that we want our cowboy to be wielding a hammer when he appears... %^GREEN%^clone cowboy%^RESET%^ %^GREEN%^cd ../weap%^RESET%^ %^GREEN%^clone hammer%^RESET%^ %^GREEN%^add hammer to cowboy%^RESET%^ %^GREEN%^wield hammer%^RESET%^ Believe it or not, it's that simple. The add command will ask you a question after you issue it. What it wants to know is if you want the NPC to do anything special when the hammer appears on him. In this case, yes, we wanted him to wield it. However, if you want to add something to an NPC and don't have anything interesting for him to do with it, respond to the question with the number of items that you want to appear. For example, if I want the cowboy to be carrying a key: %^GREEN%^cd ../obj%^RESET%^ %^GREEN%^clone key%^RESET%^ %^GREEN%^add key to cowboy%^RESET%^ %^GREEN%^1%^RESET%^ And that's it. Now if I want the cowboy to be a permanent resident of this room: %^GREEN%^add cowboy%^RESET%^ %^GREEN%^1%^RESET%^ The add command understands that if you don't specify a target argument, you must mean the room. You can also be specific: %^GREEN%^add cowboy to room%^RESET%^ %^GREEN%^1%^RESET%^ The delete command works the opposite way. It removes items from an object's permanent inventory: %^GREEN%^delete hammer from cowboy%^RESET%^ %^GREEN%^delete cowboy%^RESET%^ The delete command is also the way to get rid of rooms. You won't be removing the file from disk, you'll just be deleting that exit from the room: %^GREEN%^delete exit garden%^RESET%^ NOTE: When you delete an exit, only the connection from your room to the other room is removed. The connection from the other room to your room remains. This is not a bug, it's a feature. There are plenty of circumstances where one-way travel is desirable. ",({"chapter 23","chapter twenty-three","23",}):"chapter 23 \"Properties\" 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. ",({"chapter 31","chapter thirty-one","31",}):"chapter 31 \"Overview of the Quick Creation System\" First, let me clarify that the QCS is not intended to replace good coding habits. It is also not designed to handle every possible need of a builder. The QCS is just a handy tool for making the most tedious parts of building easier. The amount of time it takes to hand-code an area of 100 rooms (a small area, that is), with all the appropriate descriptions and monsters and weapons and such is just mind-boggling. As a grown-up, I just don't have time for building stuff line by excruciating line in raw LPC, because I also need to work, maintain my house, say hello to my family on occasion, etc. At the same time, I would need a team of dedicated LPC code fetishists to make a creation system that covers every last possible thing you could do in LPC. The QCS is somewhere in between those two extremes. Therefore please view the QCS as a quick way to get bulk building done, and not as a be-all end-all solution. You still need to learn LPC to do really cool stuff. But to hammer out an area with a quest, QCS lets you sail through the process of thingmaking with little hassle. The design philosophy of the system itself involves object files stored in /secure/modules. These files are inherited by an object which you need to carry with you in order to use the QCS system. The code for these creation modules is fairly messy and inelegant, but the result is clean, indented code that compiles, so let's keep the mockery to a minimum, shall we? It is important to keep in mind the QCS isn't an editing system. It's real live on-line modification, meaning that to modify a thing, it actually has to be in the same room you are in, or it has to be that room itself. Once you modify something, it will typically update, so that if you change the name of an npc, you're going to need to use the new name to modify it further. The next few chapters in this manual are nominally QCS specific, but in reality this is pretty much my only chance to document some of the changes in Dead Souls since version 1, so even if you never intend to use QCS, it's worth poking through these chapters. - Cratylus @ Frontiers 2 January 2006 ",({"chapter 38","chapter thirty-eight","38",}):"chapter 38 \"QCS: Adding and deleting\" Rooms, containers and NPC's all are capable of holding items, and often it is convenient to have them already holding certain items upon creation. The SetInventory directive in an object's file provides us with a list of that object's \"permanent inventory\". To modify an object's inventory, we use the add and delete commands. Let's say that we want our cowboy to be wielding a hammer when he appears... %^GREEN%^clone cowboy%^RESET%^ %^GREEN%^cd ../weap%^RESET%^ %^GREEN%^clone hammer%^RESET%^ %^GREEN%^add hammer to cowboy%^RESET%^ %^GREEN%^wield hammer%^RESET%^ Believe it or not, it's that simple. The add command will ask you a question after you issue it. What it wants to know is if you want the NPC to do anything special when the hammer appears on him. In this case, yes, we wanted him to wield it. However, if you want to add something to an NPC and don't have anything interesting for him to do with it, respond to the question with the number of items that you want to appear. For example, if I want the cowboy to be carrying a key: %^GREEN%^cd ../obj%^RESET%^ %^GREEN%^clone key%^RESET%^ %^GREEN%^add key to cowboy%^RESET%^ %^GREEN%^1%^RESET%^ And that's it. Now if I want the cowboy to be a permanent resident of this room: %^GREEN%^add cowboy%^RESET%^ %^GREEN%^1%^RESET%^ The add command understands that if you don't specify a target argument, you must mean the room. You can also be specific: %^GREEN%^add cowboy to room%^RESET%^ %^GREEN%^1%^RESET%^ The delete command works the opposite way. It removes items from an object's permanent inventory: %^GREEN%^delete hammer from cowboy%^RESET%^ %^GREEN%^delete cowboy%^RESET%^ The delete command is also the way to get rid of rooms. You won't be removing the file from disk, you'll just be deleting that exit from the room: %^GREEN%^delete exit garden%^RESET%^ NOTE: When you delete an exit, only the connection from your room to the other room is removed. The connection from the other room to your room remains. This is not a bug, it's a feature. There are plenty of circumstances where one-way travel is desirable. ",({"chapter 20","chapter twenty","20",}):"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. ",({"chapter 10","chapter ten","10",}):"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 ",({"chapter 1","chapter one","1",}):"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. ",({"chapter 14","chapter fourteen","14",}):"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 ",({"chapter 18","chapter eighteen","18",}):"chapter 18 \"Valid climates\" indoors temperate arid arctic tropical sub-tropical ",({"chapter 2","chapter two","2",}):"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. ",({"chapter 16","chapter sixteen","16",}):"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 ",({"chapter 12","chapter twelve","12",}):"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 ",({"chapter 40","chapter forty","40",}):"chapter 40 \"Useful Creator Commands\" Moving around: ------------- * To go to your workroom: %^GREEN%^home%^RESET%^ * To go to someone else's workroom, \"home <person>\", for example: %^GREEN%^home cratylus%^RESET%^ * To go to the town pub: %^GREEN%^goto /domains/town/room/tavern%^RESET%^ * Or: %^GREEN%^cd /domains/town/room%^RESET%^ %^GREEN%^goto tavern%^RESET%^ * To return to where you were before you went somewhere else: %^GREEN%^return%^RESET%^ * To bring someone to you, \"trans <person>\". For example: %^GREEN%^trans cratylus%^RESET%^ * To send them back when you're done with them: %^GREEN%^return cratylus%^RESET%^ Dealing with living beings: --------------------------- * To force everyone in a room to stop fighting: %^GREEN%^quell%^RESET%^ * To let them resume combat: %^GREEN%^unquell%^RESET%^ * To insta-kill a living being, \"zap <thing>\". For example: %^GREEN%^zap orc%^RESET%^ * To bring to life a player who somehow left the death room without regenerating, \"resurrect <person>\", For example: %^GREEN%^resurrect cratylus%^RESET%^ * To make a living being do something you want, \"force <thing> <command>\". For example: %^GREEN%^force thief drop towel%^RESET%^ %^GREEN%^force thief go west%^RESET%^ * For complex management of a living being's vital statistics, skills, health, score, and satiety levels, use the medical tricorder in the chest in your workroom. * For a detailed report of a living being's physical status: %^GREEN%^stat orc%^RESET%^ %^GREEN%^stat cratylus%^RESET%^ Handling objects in general: --------------------------- * To destroy an object, \"dest <thing>\". Note that the object's inventory will probably move to the room it was occupying. For example, if you: %^GREEN%^dest fighter%^RESET%^ You may find that the room now contains a sword, shield, and chainmail shirt, but no fighter. * To reset an object to its original state, \"reload <thing>\". Note that this also makes the object incorporate any changes you made to its file. For example: %^GREEN%^reload fighter%^RESET%^ %^GREEN%^reload here%^RESET%^ * To load a file into memory, \"update file\". This is used when you have edited an object's file, and want the mud to use the new stuff you created. For example, if you edited the fighter's file and wanted to know if it will load properly into memory, you'd type: %^GREEN%^update /realms/you/area/npc/fighter.c%^RESET%^ Or: %^GREEN%^cd /realms/you/area/npc/%^RESET%^ %^GREEN%^update fighter%^RESET%^ If you do not specify an object to update, the mud assumes you want to update the room you are in. If there is a problem with the room's code, and it does not load, you will be dropped into the \"void\". If the room's code is ok and it updates, anything in the room that isn't part of its permanent inventory (except for players) will disappear from the room. * To make a copy of an object appear, \"clone <file>\". For example: %^GREEN%^clone /realms/you/area/npc/fighter%^RESET%^ Or: %^GREEN%^cd /realms/you/area/npc/%^RESET%^ %^GREEN%^clone fighter%^RESET%^ * To know the precise contents of an object, use scan: %^GREEN%^scan fighter%^RESET%^ %^GREEN%^scan here%^RESET%^ If you want to know not only what the fighter has, but also what any containers he is carrying have, use the \"-d\" flag: %^GREEN%^scan -d fighter%^RESET%^ %^GREEN%^scan -d here%^RESET%^ Debugging commands: -------------------- * elog: This will report back to you the last few lines of your error log. Usually this is very helpful in nailing down which lines of a file contain errors. If you are admin, you may be working on files other than your home dir. If those files fail to update, you can supply elog with a directory name to specify where to look for an error report: %^GREEN%^elog secure%^RESET%^ %^GREEN%^elog cmds%^RESET%^ %^GREEN%^elog lib%^RESET%^ * dbxwhere: provides a list of the chain of messages caught in your last runtime error. * dbxframe <number>: Using the list number from dbxwhere, dbxframe can pinpoint exactly where in that link the error came from. %^GREEN%^tail /log/runtime%^RESET%^ %^GREEN%^tail /log/catch%^RESET%^ %^GREEN%^tail /log/player_errors%^RESET%^ miscellaneous useful commands: ----------------------------- * %^GREEN%^people%^RESET%^: reports who is logged on, what site they logged in from, and what room they are in. * %^GREEN%^mudtime%^RESET%^: reports the time of day in the mud (nothing to do with the time of day anywhere in the real world). * %^GREEN%^bk <thing or file>%^RESET%^: makes a unique copy of that thing or file and puts it in /realms/you/bak *%^GREEN%^ restore <filename>%^RESET%^: copies the last backup of the filename from your bak/ directory into where it used to be. ",({"chapter 14","chapter fourteen","14",}):"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 ",({"chapter 36","chapter thirty-six","36",}):"chapter 36 \"QCS: Modifying weapons\" Remember that the QCS chapters are supposed to be read in sequence. This is important because as we progress, I will not make explanations about directives and concepts explained previously. Weapons are different from rooms and NPC's in that they can be handled, sold, thrown, etc. They are manipulable objects. As such, we will see new directives: %^GREEN%^create weapon hammer%^RESET%^ You may be familiar with this example from the example webpage. Let's go ahead and plow through the commands: %^GREEN%^modify weapon id hammer%^RESET%^ %^GREEN%^warhammer%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^modify hammer name hammer%^RESET%^ %^GREEN%^modify hammer damagetype blunt%^RESET%^ %^GREEN%^modify hammer weapontype blunt%^RESET%^ %^GREEN%^modify hammer mass 700%^RESET%^ %^GREEN%^modify hammer hands 2%^RESET%^ %^GREEN%^modify hammer short a heavy war hammer%^RESET%^ %^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%^ %^GREEN%^modify hammer adj%^RESET%^ %^GREEN%^large%^RESET%^ %^GREEN%^heavy%^RESET%^ %^GREEN%^war%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^modify hammer basecost silver 750%^RESET%^ %^GREEN%^about hammer%^RESET%^ Like a room and unlike an NPC, you can also modify the SetItems on manipulable objects like weapons, so you could do something like this: %^GREEN%^modify hammer item%^RESET%^ %^GREEN%^shaft%^RESET%^ %^GREEN%^handle%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^A thick, reinforced steel shaft with leather bands for a strong grip.%^RESET%^ %^GREEN%^exa shaft on hammer%^RESET%^ ",({"chapter 15","chapter fifteen","15",}):"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 ",({"chapter 34","chapter thirty-four","34",}):"chapter 34 \"QCS: Modification of NPC's\" In the previous chapter we learned how to make a generic object. Now that we have it, what to do with it? It's important to keep in mind that the generic thing now in front of you isn't just a clone from a template file. If the command you used was \"create npc cowboy\", there is now a file (probably) called /realms/you/area/npc/cowboy.c that contains the code for the creature in front of you. However, this poor beast has the most uninteresting of features. It is in fact so boring that it responds only to its generic type. Such that \"examine cowboy\" or \"kill tex\" won't work. You'll need to \"look at npc\". Accordingly, any modification commands need to be made referring to the new thing with an it responds to, until such a time as you change the id to suit your tastes. Let's carry on with the example of our generic npc. To make a cowboy out of him, we can either change his name, or his id, or both. Let's start with his name: %^GREEN%^modify npc name cowboy%^RESET%^ This makes the SetKeyName() directive in cowboy.c use \"cowboy\" as its argument, effectively allowing you to address this npc as \"cowboy\" from now on. Now you can \"look at cowboy\" with some results. Obviously our NPC isn't *just* a cowboy. He's also a human, a dude, and his name is Tex. How do we make him respond to all of these nouns? %^GREEN%^modify cowboy id%^RESET%^ You'll notice there are no arguments following the word \"id\". Setting a thing's id is different from most other settings. If you'll think back to the LPC datatypes chapter of this manual (you did read the LPC chapters, didn't you?) you'll remember that some information about objects is in the form of strings (\"cowboy\"), some is in the form of integers (the cowboy's health points, for example) and some is in the form of arrays, which are a group of data points. In this example we want the cowboy's id to be an array, because of the many ways we might want to address him. Therefore, we want the SetId directive in his file to look like this: SetId( ({\"human\", \"dude\", \"tex\" }) ); You might think that QCS should be able to accept multiple values like this on a line, perhaps with \"modify cowboy id human dude tex\" as the command. But what if you want this npc to be a \"Boy Named Sue\"? How would you accommodate id's that contain spaces? In designing QCS, I considered having escape characters to allow for such things, but ultimately reasoned that this was just way too much mess. Instead, SetId, and other directives that take arrays as arguments, are handled by entering a query session. Below is an example of what it might look like. The example is necessarily messy because I am including both the queries and the responses. --------------------------------------------------- > %^GREEN%^modify npc name cowboy%^RESET%^ Indenting file... \"/tmp/indent.1136206130.tmp.dat\" 15 lines 420 bytes Exit from ed. > %^GREEN%^modify cowboy 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%^human%^RESET%^ You may now enter the next value. So far, we have: ({ \"dude\", \"human\" }) If you're done entering values, enter a dot on a blank line. %^GREEN%^tex%^RESET%^ You may now enter the next value. So far, we have: ({ \"dude\", \"human\", \"tex\" }) If you're done entering values, enter a dot on a blank line. %^GREEN%^boy named sue%^RESET%^ You may now enter the next value. So far, we have: ({ \"dude\", \"human\", \"tex\", \"boy named sue\" }) If you're done entering values, enter a dot on a blank line. %^GREEN%^.%^RESET%^ Entries complete. Final array is: ({ \"dude\", \"human\", \"tex\", \"boy named sue\" }) Indenting file... \"/tmp/indent.1136206156.tmp.dat\" 19 lines 459 bytes Exit from ed. /open/1136206138: Ok /realms/cratylus/area/npc/cowboy: Ok SetId modification complete. > %^GREEN%^exa tex%^RESET%^ Other than being human, this npc is entirely unremarkable. The male human is in top condition. --------------------------------------------------- If you were now to examine Tex's code (with the command \"about tex\") you'd see that his SetId directive now looks like this: SetId( ({\"dude\", \"human\", \"tex\", \"boy named sue\"}) ); Other NPC features take arrays also. SetAdjectives is one. You might enter this (mud output omitted for clarity): %^GREEN%^modify tex adjectives%^RESET%^ %^GREEN%^dusty%^RESET%^ %^GREEN%^hardy%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^look at dusty cowboy%^RESET%^ There are two other directives that require queries. Things and NPC's can be looked at, but they can also be smelled and listened to, if you add SetSmell and SetListen. The syntax is: %^GREEN%^modify tex smell%^RESET%^ And you will then be asked a question about keys and mappings. Understanding mappings is important, but for now you just need to understand that you are being asked *two* separate questions: 1) What on the cowboy is being smelled/listened to? 2) What is the smell/sound? What this means is that your input will look something like this: %^GREEN%^modify tex smell%^RESET%^ %^GREEN%^default%^RESET%^ %^GREEN%^.%^RESET%^ Tex smells of sweat and manure. What happens is this: - You enter the modify command. - You enter the word \"default\" to indicate this is Tex's general smell. - You enter a dot to indicate that you are done specifying what part of Tex is being smelled. - You then specify the smell. This may seem odd until you realize you can also add smells/listens to parts of things. Not on NPC's, though. We'll look at this more closely in later chapters. For now, just use the syntax as shown above. For adding a listen to the cowboy, it works the same way: %^GREEN%^modify tex listen%^RESET%^ %^GREEN%^default%^RESET%^ %^GREEN%^.%^RESET%^ Tex seems to be humming a jaunty melody. Other features of an NPC do not take arrays, so one-line commands will do. For example: %^GREEN%^modify cowboy long This is a cowboy who calls himself Tex, but is in fact a Boy Named Sue.%^RESET%^ %^GREEN%^modify cowboy short a cowboy%^RESET%^ %^GREEN%^modify cowboy level 5%^RESET%^ %^GREEN%^modify cowboy class fighter%^RESET%^ %^GREEN%^modify tex currency gold 1%^RESET%^ %^GREEN%^modify tex currency silver 12%^RESET%^ %^GREEN%^modify tex skill bargaining 5%^RESET%^ %^GREEN%^modify tex skill projectile attack 7%^RESET%^ %^GREEN%^modify tex stat strength 33%^RESET%^ %^GREEN%^modify tex property nice guy 1%^RESET%^ %^GREEN%^modify tex healthpoints 150%^RESET%^ %^GREEN%^modify tex maxhealthpoints 170%^RESET%^ %^GREEN%^modify tex melee 0%^RESET%^ %^GREEN%^modify tex unique 1%^RESET%^ If you now issue the \"about tex\" command you will see that all the changes you made have been put into the file. You may have noticed the \"melee\" keyword. Dead Souls 2 NPC's come in various shapes and sizes, and some of them shouldn't wield weapons. A wolf with a battle axe would be a strange sight indeed. However, the default combat system makes unarmed creatures extremely vulnerable in combat. To make an NPC combat-capable without weapons, use the new SetMelee directive. SetMelee(1) makes the NPC capable of proper unarmed combat. SetMelee(0) makes the NPC a weak opponent if unarmed. NPC's will generally try to bite during unarmed combat. If this is beneath the capability or dignity of your NPC, you can prevent this with: %^GREEN%^modify tex canbite 0%^RESET%^ If your NPC should try to escape when the battle isn't going his way, the wimpy settings should do: %^GREEN%^modify tex wimpy 30%^RESET%^ %^GREEN%^modify tex wimpycommand climb ladder%^RESET%^ If you don't specify a wimpy command, Tex will leave the room through a random exit. In this case, when Tex's health is down to 30% and he is in combat, he will try to climb a ladder. Some NPC's are designed to travel about. To enable this feature, use the wanderspeed directive: %^GREEN%^modify tex wanderspeed 5%^RESET%^ If you want him to travel more quickly, use a lower number. By default, wandering NPC's only wander in rooms that have already been loaded into memory. They avoid loading rooms because loading a bunch of rooms that only the NPC will ever see is a waste of your mud's resources. However, if you *do* want your NPC to wander in an unrestricted manner, regardless of whether a room is loaded, use the permitload directive: %^GREEN%^modify tex permitload 1%^RESET%^ By default, NPC's stand up when they can. This is so that if they collapse during combat, they try to get back up once they are able to do so. If you prefer that your NPC maintain some other posture, you can set that posture, then disable autostanding like this: %^GREEN%^modify tex posture lying%^RESET%^ %^GREEN%^modify tex autostand 0%^RESET%^ If he's especially lazy, you can have him take a nap this way: %^GREEN%^modify tex sleeping 10%^RESET%^ Which will have him wake up after about a minute. However, note that if you've disabled autostanding, he will remain lying down after he wakes up. If the NPC should be hostile, that is, he should attack any creatures that it sees enter a room, SetEncounter should do it: %^GREEN%^modify tex encounter 100%^RESET%^ This means that if the creature it sees has a charisma score of less than 100 (which should pretty much be always true), Tex will try to kill it. You can do some fancy stuff with SetEncounter, such as only attacking orcs, or actually doing something friendly, but to do so you can't use QCS. Read the NPC and Sentients chapter in the Creator's Manual for details on how to code such stuff. If the NPC is a golem or other such non-biological creature, it may be useful to specify what they are made of. The SetComposition setting for a clay golem might look like this: %^GREEN%^modify golem composition clay%^RESET%^ If it happens to be a golem that does not believe in violence as a solution to problems, you can make refuse to hurt others with the following: %^GREEN%^modify golem pacifist 1%^RESET%^ Vendors: ------- Vendors are a special kind of NPC that can sell stuff. Along with the standard NPC settings, vendors have the following: SetStorageRoom specifies where the vendor's stock is stored. If a valid room is specified, anything in that room can be sold by the vendor. SetLocalCurrency specifies the type of currency, such as gold or silver, that the vendor accepts. SetMaxItems is the maximum number of items in the storeroom that the vendor is permitted to sell. SetVendorType specifies the kind of stuff the vendor can trade in. \"all\" allows him to buy and sell whatever. But if he is a weapon vendor, he can't trade in armor, etc. See /include/vendor_types.h for the available vendor types. To have a \"multi-type\" vendor, you'll have to code it by hand. The result of that looks something like this: SetVendorType( VT_TREASURE | VT_ARMOR | VT_HERBS ); Barkeeps: -------- Like vendors, barkeeps sell stuff, but they are limited to selling food and drink. Unlike vendors, barkeeps have no limitation on the amount of stuff they can sell. They also do not have a storeroom. The stuff they can sell is specified in their SetMenu directive, like this: %^GREEN%^clone woody%^RESET%^ You clone a generic barkeep (/realms/temujin/area/npc/woody.c). %^GREEN%^modify woody menu%^RESET%^ If you don't understand these questions, type the letter q on a blank line and hit enter. Please enter the first key element for this mapping: %^GREEN%^bourbon%^RESET%^ Please enter the next key element, or enter a single dot to finish entering key elements. %^GREEN%^whiskey%^RESET%^ Please enter the next key element, or enter a single dot to finish entering key elements. %^GREEN%^.%^RESET%^ Please enter the value for key ({ \"bourbon\", \"whiskey\" }): %^GREEN%^/domains/town/meals/bourbon%^RESET%^ Barkeeps also have the SetLocalCurrency directive to specify the currency they accept. ",({"chapter 21","chapter twenty-one","21",}):"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. ",({"chapter 22","chapter twenty-two","22",}):"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 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. ",({"chapter 35","chapter thirty-five","35",}):"chapter 35 \"QCS: Modifying rooms\" Suppose you are in your sample room and you issued the command: %^GREEN%^create room south testroom1%^RESET%^ You then travel south and see that you are in a room that is almost exactly like the sample room except for the exits. Well, probably you don't want to have a mud with nothing but identical rooms, so let's modify it: %^GREEN%^modify here short Test Room One%^RESET%^ %^GREEN%^modify here long This is the first test room. The walls are rather blank.%^RESET%^ %^GREEN%^modify here climate indoors%^RESET%^ %^GREEN%^modify here light 30%^RESET%^ Ok, so far so good. Standard interior. However, a good mud has rooms with details. Let's add some detail to this room. I've omitted the system output for clarity. This is just what you would input. %^GREEN%^modify here item%^RESET%^ %^GREEN%^wall%^RESET%^ %^GREEN%^walls%^RESET%^ %^GREEN%^blank wall%^RESET%^ %^GREEN%^blank walls%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^These are just blank walls.%^RESET%^ Let's review what we've done here: 1) You issued the modify command specifying your current room as the target, and the SetItems directive as the argument. 2) You entered a query session, and were asked to enter each element of the item's key. 3) You entered a single dot to indicate you were done entering key elements. 4) You entered the value for the key, which is the description of the item. The result of all this is that now you can issue these commands: %^GREEN%^exa wall%^RESET%^ %^GREEN%^look at blank walls%^RESET%^ %^GREEN%^examine walls%^RESET%^ And the output will be: These are just blank walls. Let's add a floor while we're at it: %^GREEN%^modify here item%^RESET%^ %^GREEN%^floor%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^A floor like any other.%^RESET%^ In this case, you didn't feel like adding extra synonyms for \"floor\", so you entered the final dot rather than entering another key element. Then you added the description, and now if you \"exa floor\", you'll get that description. \"about here\" will display to you the file you have modified. Well, that's enough fun with indoor rooms. There's not much more to them. Let's go outdoors now: %^GREEN%^create room south exterior_room%^RESET%^ %^GREEN%^create door south test_door%^RESET%^ %^GREEN%^open door%^RESET%^ %^GREEN%^go south%^RESET%^ %^GREEN%^modify here short a small lawn%^RESET%^ %^GREEN%^modify here daylong A small, well groomed lawn on a lovely sunny day. There is a small building north of here.%^RESET%^ %^GREEN%^modify here nightlong This is a small lawn. Stars twinkle in the night sky above, and some light is coming from a small building to the north.%^RESET%^ %^GREEN%^modify here daylight 30%^RESET%^ %^GREEN%^modify here nightlight 20%^RESET%^ %^GREEN%^modify here light delete%^RESET%^ %^GREEN%^modify here long delete%^RESET%^ %^GREEN%^modify here items delete%^RESET%^ %^GREEN%^modify here items%^RESET%^ %^GREEN%^building%^RESET%^ %^GREEN%^small building%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^A small building, rather ramshackle as if hastily put together.%^RESET%^ %^GREEN%^modify here climate temperate%^RESET%^ Ok! A few new things here. A neat thing about outdoor rooms is that typically they are subject to the time of day. A SetClimate directive that indicates an exterior environment causes the room to receive messages about the sun setting, rising, etc. The SetDayLong and SetNightLong directives allow you to more sensibly describe the area depending on the time of day. To avoid confusion, I deleted the SetLong directive. It is not mandatory to have different day and night descriptions, but players appreciate the effort. It is also possible to have differing ambient light levels depending on the time of day, so we've added SetDayLight and SetNightLight, and we deleted the SetAmbientLight directive. Let's continue to add detail: %^GREEN%^modify here item%^RESET%^ %^GREEN%^lawn%^RESET%^ %^GREEN%^grass%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^Healthy, well groomed and freshly cut grass.%^RESET%^ %^GREEN%^modify here smell%^RESET%^ %^GREEN%^default%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^You can smell the refreshing scent of freshly cut grass.%^RESET%^ %^GREEN%^modify here smell%^RESET%^ %^GREEN%^lawn%^RESET%^ %^GREEN%^grass%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^Yep, it's got that new lawn smell.%^RESET%^ %^GREEN%^modify here listen%^RESET%^ %^GREEN%^building%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^Sounds like someone's fumbling about in there, making a mess. New creators can be so noisy.%^RESET%^ %^GREEN%^modify here item%^RESET%^ %^GREEN%^garden%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^You may enter the garden from here.%^RESET%^ %^GREEN%^create room garden garden_room%^RESET%^ You now have a room with lots of charm and detail. You can \"smell grass\" and \"listen to small building\", if you like. Neat, huh? But there's something very important to keep in mind: Enters, listens and smells don't work properly if there is no item defined for that smell. For example, if you want to be able to listen to the sea, you must \"modify here item\" and add a \"sea\" item. Otherwise, \"listen to the sea\" will respond with \"There is no sea here.\" The only exception to this rule is the \"default\" smell. Enters behave similarly. If you want to be able to \"enter\" something, you'll need to create the corresponding item first, as in the example above. You can use the SetProperties directive to make the room conform to some presets, like: %^GREEN%^modify here property no attack 1%^RESET%^ Read chapter 23 in the Creator's Manual for details on room properties. Also, please note that indoor rooms can also have differing descriptions and light levels for night and day. It's just that indoor rooms don't get notification of daytime changes. Finally, the SetTown directive allows the room to participate in area-wide events, and is useful for security purposes as well: %^GREEN%^modify here town MyTown%^RESET%^ Notes on room filenames: ----------------------- By default, a filename without a leading path creates a room in your area room directory, which in my case would be \"/realms/cratylus/area/room\". However, you can specify a different location for the new room. To create a room in your current working directory: %^GREEN%^create room east ./newroom%^RESET%^ To create a room in a specific directory: %^GREEN%^create room east /realms/cratylus/testrooms/newroom%^RESET%^ ",({"chapter 25","chapter twenty-five","25",}):"chapter 25 \"Rooms\" 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 ",({"chapter 19","chapter nineteen","19",}):"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. ",({"chapter 33","chapter thirty-three","33",}):"chapter 33 \"QCS: Creation\" Creation breaks down into three categories. \"Things\", rooms, and doors. Let's look at things first: Thing creation: --------------- In this category we're including NPC's, weapon, armor, unspecial items, tables, furniture, books and containers. Basically things that actually show up somewhere. A door is a very special sort of object and does not fall under this category. To make a new thing, the syntax looks like this: create THING FILENAME The THING is the category of item we are creating. The FILENAME is the name of the file that will contain this item's configuration data. You may enter an absolute path, or you may simply enter a filename. If you enter a filename, QCS will attempt to figure out the best place for this file. If your current working directory has a name QCS understands as being compatible with the type of object you are making (for example, your cwd is /realms/you/npc and you are making an NPC) it will use that. Otherwise it will search parent and children directories for a directory name it understands this way. Finally, if it can find no compatible directories for your file near your cwd, it will put it in the appropriate directory in your home area (in this case, /realms/you/area/npc ). Avoid a relative path. It probably won't work the way you think. When the command completes, FILENAME will be a file containing the data for your generic thing, and a copy of that generic thing will appear in the room you are in. If, for example, you entered: %^GREEN%^create npc cowboy%^RESET%^ The room you are in will contain a generic NPC which *does not* answer to the id of \"cowboy\". This NPC is just a generic NPC whose filename is (probably) /realms/you/npc/cowboy.c and isn't yet a real cowboy. You'll need to use the \"modify\" command to make a proper cowboy out of him. Room creation ------------- Naturally, if you create a room, a new room will not appear inside your current environment. Instead, the syntax of the \"create\" command is different when you want to create a new room. You may have noticed that you can't use the \"create\" command to make a new room adjacent to your workroom. This is for your protection and my sanity. Files which contain the directive \"SetNoModify(1)\" are immune to QCS manipulation. Rooms like your workroom, the default start room, the void room, etc, are set nomodify. This is because if you screw it up, you will be sorry, and I just don't want to hear it. So, suppose then that you're in your sample room (one room east of your workroom) and you want to make a new room. You might issue the following command: %^GREEN%^create room south testroom1%^RESET%^ What this does is copy the room you are in (in this case, /realms/you/area/sample_room.c) to a new location (perhaps /realms/you/area/testroom1.c). But the neat thing is, this new room does not have the same exits as the room you are in. The new room has just one exit, leading back to where you are. The net effect of all this is that when you issue this command, you make a new room in the direction you specify, and this new room looks just like the room you're in, only the exits are such that you can travel back and forth between the rooms. Door creation ------------- Doors are funny things. In Dead Souls, they aren't objects in the conventional sense of a thing which occupies a room you're in. Rather, they are really daemons which attach to adjoining rooms. If that doesn't make sense to you, don't worry. You're not alone. The syntax for door creation is much like that for room creation. After you create that room south of your sample room, you can now create a door between them: %^GREEN%^create door south sample_door%^RESET%^ This brings into existence a generic door (closed by default) which is between the two rooms. ",({"chapter 27","chapter twenty-seven","27",}):"chapter 27 \"Towns\" 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 ",({"chapter 28","chapter twenty-eight","28",}):"chapter 28 \"Vendors\" 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. ",({"chapter 32","chapter thirty-two","32",}):"chapter 32 \"QCS: Commands\" What with muds being text only, QCS has no fancy windowing system. Using a menu-driven creation system was ruled out quickly due to the vast complexity of the menus that would be required. Instead, QCS relies on a few powerful commands. create This is the command that gets the ball rolling. This command is what lets you bring a new thing into existence. The things you can create can be seen by typing \"help create\". Examples are rooms, weapons, doors, and so on. We will be reviewing each of those in later chapters. When you issue this command a generic version of the item you wish to create appears (or, in the case of a room, appears in the direction you specify). Once that generic copy materializes, you can change it to suit your needs using the \"modify\" command. modify I tend to regard this command as the heart and soul of QCS. It's this tool that lets you make your world your own. Your new generic things are not useful or fun until you modify them. A \"generic weapon\" isn't very interesting, but a \"mithrilite poleaxe\" might be just the thing to deal with a pesky dragon. add Creatures, rooms, and containers are capable of storing other things. Once you make an ogre, you may want to give him a hammer to wield. After you make that hammer, you use the add command to let the ogre have that wepon in his permanent inventory. delete On the other hand, you may be tired of that ogre after a while. If he is a part of the permanent inventory of a room, you can use the delete command to remove him permanently. Or if you'd rather he have a Kill-O-Zap Frogstar blaster rather than a hammer, get rid of the hammer in his inventory with this command. copy This is a room-specific command. Rather than write multiple, nearly identical rooms for large areas, you can use the copy command to make the room you are almost exactly like any other room you choose, except for the exits, which remain the same. Handy for big forests, cell-blocks, twisty mazes of little passages, etc. initfix If a thing isn't working right, try to initfix it. \"init()\" is an object function that many items need in order to work properly. If you've run into something that is behaving unexpectedly, run initfix on it. The trouble just might clear up. ",({"chapter 26","chapter twenty-six","26",}):"chapter 26 \"Sentients\" 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. ",({"chapter 5","chapter five","5",}):"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. ",({"chapter 30","chapter thirty","30",}):"chapter 30 \"The Natural Language Parser\" The Natural Language Parser The Problem A gut reaction to this entire system is to be overwhelmed by its apparent complexity, comparing it to the good-old days of using add_action(). A discussion of the natural language parsing system therefore needs to start by answering the question, \"Why bother?\". The old way of handling user input was to define commands and tie them to functions using add_action. Each user object kept track which commands it had available to it, and of which functions each command would trigger. The list of commands changed each time the player object (really, any object which had enable_commands() called in it) moved. In addition, each time an object moved inside the player object or left its inventory, this list changed. This led to two basic problems: 1. The same command might have slightly different uses in different parts of the mud. Or worse, the player could have two similar objects which define the same command in slightly different ways. 2. The complexity of syntax varied based on creator abilities and was limited by CPU. For example, one creator could have created a rock in their area that added the 'throw' command. This creator is a newbie creator, and thus simply put the following code in their throw_rock() function: int throw_rock(string str) { object ob; if( !str ) return 0; ob = present(str, this_player()); if( !ob ) { notify_fail(\"You have no rock!\"); return 0; } if( ob != this_object() ) return 0; if( (int)ob->move(environment(this_player())) != MOVE_OK ) { write(\"You cannot throw it for some reason.\"); return 1; } write(\"You throw the rock.\"); say((string)this_player()->query_cap_name() + \" throws the rock.\"); return 1; } In this case, \"throw rock\" will work, but \"throw the granite rock at tommy\" will not. But another creator also defined a throw command in their spear. This creator however, is a good coder and codes their throw_spear() command to handle 'throw the red spear at tommy' as well as 'throw spear'. Explain to a player why both syntaxes only work for the spear, and not for the rock. Then explain to that player why 'throw rock' for a rock built in yet another area yields 'What?'. An early attempt to get around this problem was the parse_command(). Unfortunately it was buggy spaghetti that was way too complex for anyone to understand. The MudOS attempt to solve this problem is its new natural language command parser. The parser is based on the following assumptions: All commands should behave in a consistent manner across the mud. Similar objects should respond as expected to the same command line. A player should only see 'What?' (or its equivalent) when they make a typo. It should enable creators to handle the complex command processing required by the above assumption. Overview of the MudOS System The MudOS natural language parser is based on a philosophy of centralized command parsing. In other words, creators have no control over which commands exist nor over what syntax rules existing commands follow. Instead, creators are tasked with defining what those commands mean to their objects. Unlike with add_action() where commands are registered to the driver, the MudOS system registers verbs (the command) and rules with the driver. In this example, a simple \"smile\" verb is registered with a single rule, \"at LIV\". With the old way of doing things, commands were executed either when a player entered in a command or when the command() efun was called. With this new system, a command may be executed at any time via either the parse_sentence() or parse_my_rules() efuns. When one of those efuns is called, the driver searches through the list of verbs for a verb and rule which matches the command string. In order to do that, however, it needs to make several calls of all the objects involved to determine what the sentence means. For any given command string, the following objects are relevant to the parsing of that command string: the verb handler This object contains the functions used to see if the command is valid and to execute it. It is also the one that creates the rules for the verb. the subject This is the object from which parse_sentence() is called, or the object mentioned as the first argument in parse_my_rules(). It is the object considered to be executing the command in questin, the logical subject of the sentence. the master object This object keeps track of global information, such was what literals (mistakenly referred to as prepositions) exist across the mud. In general, a literal is a preposition. the direct object This is not the logical direct object of the sentence. Rather, this is the first object at which the verb action is targetted. the indirect object Again, this is not the logical indirect object of the sentence. Rather, it is the second object at which the verb action is targetted. For example, in \"give the book to the elf\", the elf will be both the logical indirect object and the parser indirect object. But if you allow \"give the elf the book\", the elf naturally still remains the logical indirect object, but the book is the indirect object to the parser since it is the second object targetted by the verb (the first being the elf). Each object involved in he parsing of a sentence, except the subject, is responsible for handling certain driver applies that help the driver in parsing the sentence. The subject, unlike the other objects, is responsible for initiating the command. Although this document treats all of these objects as if they were completely distinct, it is possible to have the same object performing multiple roles for the same command. For example, your subject could also be direct object and verb handler. The next section discusses the objects and the applies they are responsible for in detail. The Objects Before studying each object in detail, it is important to keep in mind that each object which can be involved in any role must call parse_init() before doing anything related to verb parsing. The only exception is the master object. The subject The subject is simply the initiator of a command. A command is typically initiated by a call to parse_sentence() inside the object's process_input() apply. This example shows how a player object might use parse_sentence() to initiate a command. This efun will return 1 if the command successfully matched a known verb and rule and successfully executed it. If it found the verb in question, but it did not match any rule, then 0 is returned. If it found the verb in question and matched a rule, but the execution of the rule failed, it will return an errorstring describing why it failed. Finally, if no verb matched the command, then -1 is returned. Take for example a mud with this one rule: parse_add_rule(\"smile\", \"at LIV\") The efun parse_sentence() would return the following values for the following command lines: smile at descartes Returns: 1 smile happily Returns: 0 smile at the red box Returns: \"The Box is not a living thing!\" eat the red box Returns: -1 The master object The master object is responsible for a single apply, parse_command_prepos_list(). This apply returns a list of literal strings which may be used in a rule. A literal string is simply one that appears in the rule exactly as a player types it. In the smile example above, \"at\" is a literal. In most all cases, literals are prepositions, thus the name of the apply. The verb handler The verb handler object is responsible for setting up the rules for a verb and handling the test and execution of those rules. This example demonstrates a simple verb handler for the smile verb described above. As you can see, each rule is divided up into three parts: 1. initialization 2. testing 3. execution The intialization is the call to parse_add_rule(). This associates a rule with a verb. The first argument is the verb (this verb may have spaces in it, like \"look at\") and the second argument is one of the rules being handled by this verb handler. This list defines the valid tokens for a rule. The testing portion is a \"can\" apply. In testing a rule, the driver calls the applies can_<verb_rule> to determine if the execution of the verb even makes sense in this situation. The test apply is called when the driver has valid arguments to a rule, but it wants to see if those valid arguments make sense right now. For example, you might check a player here to see if they have enough magic points for casting the spell this verb/rule represents. If not, you might return \"You are too tired right now.\". If the rule match up in question makes completely no sense at all, like for example, they tried to throw a house for the (\"throw\", \"OBJ\") rule, you should return 0. The parser will guess well an error message from the situation. In this case, it will have parse_sentence() return \"You cannot throw the thing.\". Finally execution is where the verb actually happens. You know you have a verb/rule match and you know all the arguments to it are valid. Now it is time to do something. You almost always want to return 1 from this function except in extreme circumstances. The direct and indirect objects As stated above, the directness or indirectness of an object has nothing to do with the linguistic meaning of those terms. Instead it has to do with what position in the token list the object takes. The direct object is the first object in the token list, and the indirect object is the second object in the token list. These objects basically answer the question \"Can I be the direct/indirect object for this verb and rule?\". Like the testing and execution applies for verb handlers, the applies that answer this question may return 1, 0, or an error string. Also like the testing and execution applies for the verb handler, these come in the form of (in)direct_<verb>_<rule>(). This example is from somewhere inside the living object heirarchy. Note the is_living() apply which lets the parser know that the object matches a LIV token. Inventory visibility Some objects are subjects, direct objects, or indirect objects of verbs which require access to things in their inventory. For example, living things, bags, chests, etc. all need to allow other things access to their inventories for some commands. Two applies handle this situation: 1. inventory_accessible() 2. inventory_visible() The first returns 1 if verbs can have access to an object's inventory, the second returns 1 if verbs simply can take into account an object's inventory. An example of the difference might be a glass chest. When closed, you want its inventory to be visible, but not accessible. It is important to remember that is the return value for any of these special applies, including is_living(), you need to make an explicit call to the parse_refresh() efun. Unless the parse_refresh() efun is called, these special applies are only called once with no guarantee as to when that one call will actually occur. Creating a New Verb Currently, the Lima and Nightmare mudlibs use this parser system. Both mudlibs provide inheritable objects which make it simpler to interface with the MudOS parser system. Nightmare specifically has the inheritable LIB_VERB with methods for defining a new verb. This verb example comes from the Nightmare mudlib. The simple Nightmare verb requires the following steps: 1. Name the verb 2. State the verb rules 3. Name any synonyms 4. Set an error message for display when the command is wrongly used 5. Create help text for the command Naming the verb is done through the SetVerb() method. You simply specify the name of the verb. The rules are passed to the SetRules() method. You may specify as many rules as are needed for the verb. Like rules, synonyms are set as a list for the SetSynonyms() method. A synonym is simply any verb which is exactly synonymous with any possible rule for the verb in question. The player is able to access help for the verb and get error messages for the verb through the verb or any of its synonyms. The error message is a string displayed to the user when they use the verb in an incorrect manner. For example, if I typed 'eat' when the rule is 'eat OBJ', the error message would be 'Eat what?'. Finally, like with any object, the help text can be set through the SetHelp() method. Help is very important for verbs. All of these methods only are able to take care of verb initalization. It is up to the verb creator to give meaning to a new verb. This is done first off by writing can_*() and do_*() applies in the verb handler. These methods should be very simplistic in nature. For example, a can method almost always simply returns 1. A do method generally finds its target and triggers some sort of event in that object. The event does the real command handling. In addition to can and do applies, you need also to write any direct and indirect applies in approperiate objects. Nightmare centralizes this sort of processing through inheritables geared towards responding to particular verbs. A good example of this is LIB_PRESS which responds to the \"press\" command. Thus any object which should be pressable needs only to inherit this object to become a pressable object. The can, do, direct, and indirect applies all have the same argument set for the same verb/rule pair, but it is important to know when the parser knows certan things. Take for example the verb/rule \"press OBJ on OBJ\". The parser takes the following actions: 1. Call can_press_obj_on_obj() in verb handler 2. Call direct_press_obj_on_obj() in all accessible and visible objects 3. Call indirect_press_obj_on_obj() in all accessible and visible objects 4. Call do_press_obj_on_obj() in the verb handler The arguments to all methods called in this process are: 1. object direct_object 2. object indirect_object 3. string direct_object_as_entered_on_command_line 4. string indirect_object_as_entered_on_command_line But how can can_press_obj_on_obj() know what the direct and indirect objects are if they have not been identified yet? The answer is that it cannot. For the command \"push the button on the wall\", in a room with me and you in it and we carry nothing, the sequence looks like this (return in parens): 1. verb->can_press_obj_on_obj(0, 0, \"the button\", \"the wall\"); (1) 2. me->direct_press_obj_on_obj(0, 0, \"the button\", the wall\"); (0) 3. you->direct_press_obj_on_obj(0, 0, \"the button\", \"the wall\"); (0) 4. room->direct_press_obj_on_obj(0, 0, \"the button\", \"the wall\"); (1) 5. me->indirect_press_obj_on_obj(room, 0, \"the button\", \"the wall\"); (0) 6. you->indirect_press_obj_on_obj(room, 0, \"the button\", \"the wall\"); (0) 7. room->indirect_press_obj_on_obj(room, 0, \"the button\", \"the wall\"); (1) 8. verb->do_press_obj_on_obj(room, room, \"the buton\", \"the wall\"); (1) This assumes, of course, that the room responds positively with the id's \"button\" and \"wall\". People familiar with the parser might say, \"Hey, wait, there is a lot more that happens than just that.\" In fact, there are many more possible permutations of this sequence. The most interesting is the ability to simply ignore the difference between prepositions like \"in\" and \"into\" which are often used interchangeably in colloquial speech. For example, if you had \"put OBJ in OBJ\" and \"put OBJ into OBJ\" verb/rules, you could handle them in a single place for each of the applies respectively liek this: can_put_obj_word_obj() direct_put_obj_word_obj() indirect_put_obj_word_obj() do_put_obj_word_obj() If the parser found no can_put_obj_in_obj() defined, it then searches for a more generic handler, can_put_obj_word_obj(). In fact the real order it searches for a can handler is: 1. can_put_obj_in_obj() 2. can_put_obj_word_obj() 3. can_put_rule() 4. can_verb_rule() --------------------- Last example: static void create() { parse_init(); parse_add_rule(\"smile\", \"at LIV\"); } mixed can_smile_at_liv(object target) { return 1; } mixed do_smile_at_liv(object target) { previous_object()->eventPrint(\"You smile at \" + (string)target->GetName() + \".\"); target->eventPrint((string)previous_object()->GetName() + \" smiles at you.\"); return 1; } ",({"chapter 22","chapter twenty-two","22",}):"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 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. ",({"chapter 7","chapter seven","7",}):"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. ",({"chapter 39","chapter thirty-nine","39",}):"chapter 39 \"QCS: Final notes\" * Remember that QCS commands work on objects, not files. To load a file into memory, use the update command. To reload an already existing object, like a cloned orc or a book, use the reload command. To use modify, delete, and add, you have to specify a cloned object that is on you or in your environment. I think you're getting the idea of how this works. Here's an example of armor creation: %^GREEN%^create armor jeans%^RESET%^ %^GREEN%^modify jeans id%^RESET%^ %^GREEN%^pants%^RESET%^ %^GREEN%^trousers%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^modify jeans short a pair of denim jeans%^RESET%^ %^GREEN%^modify jeans long Worn jeans, frayed and stained.%^RESET%^ %^GREEN%^modify jeans adj%^RESET%^ %^GREEN%^pair of%^RESET%^ %^GREEN%^denim%^RESET%^ %^GREEN%^frayed%^RESET%^ %^GREEN%^worn%^RESET%^ %^GREEN%^stained%^RESET%^ %^GREEN%^.%^RESET%^ To know what directives QCS can change on an object, type: %^GREEN%^help modify%^RESET%^ This provides a list of modifiable things and the directives that can be modified on them. Ultimately the Quick Creation System generates LPC code, so you'll want to review the earlier chapters of this handbook to get a base of understanding of the code that comprises your new creations. Some notes and tips: * The SetNoCondition directive makes it so an item does not report its physical status when examined. Weapons and armor wear down in combat, and most objects let you know their condition when you examine them. However, in some cases (a sandwich for example) this is inappropriate, so the SetNoCondition directive may be useful. * Doors aren't like normal objects. They have to be modified *twice*. Once for each side of the door. If this sounds unnecessarily tedious, remember that a door leading south is also a door leading north from the other room. * Doors generally are not visible in the same way that regular objects are. To make a door especially obvious and noticeable, do something like: %^GREEN%^modify door sethiddendoor 0%^RESET%^ * SetCurrency is for adding money to NPC's. SetMoney is for adding money to non-living containers (bags, etc). * Item subtypes are listed in /include. To know what kinds of vendors are available, for example, look in /include/vendor_types.h * Books need a \"source directory\", which must contain one file per chapter. The SetSource for this manual, for example, is /doc/manual The first line of each file must follow the same format as the files you see in /doc/manual * SetObviousExits is usually no longer needed: rooms report obvious exits automatically. However, if you don't want an exit to show up by default, use the SetObviousExits directive to specify only those that you want seen. This will override the room's default exit display. ",({"chapter 25","chapter twenty-five","25",}):"chapter 25 \"Rooms\" 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 ",({"chapter 39","chapter thirty-nine","39",}):"chapter 39 \"QCS: Final notes\" * Remember that QCS commands work on objects, not files. To load a file into memory, use the update command. To reload an already existing object, like a cloned orc or a book, use the reload command. To use modify, delete, and add, you have to specify a cloned object that is on you or in your environment. I think you're getting the idea of how this works. Here's an example of armor creation: %^GREEN%^create armor jeans%^RESET%^ %^GREEN%^modify jeans id%^RESET%^ %^GREEN%^pants%^RESET%^ %^GREEN%^trousers%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^modify jeans short a pair of denim jeans%^RESET%^ %^GREEN%^modify jeans long Worn jeans, frayed and stained.%^RESET%^ %^GREEN%^modify jeans adj%^RESET%^ %^GREEN%^pair of%^RESET%^ %^GREEN%^denim%^RESET%^ %^GREEN%^frayed%^RESET%^ %^GREEN%^worn%^RESET%^ %^GREEN%^stained%^RESET%^ %^GREEN%^.%^RESET%^ To know what directives QCS can change on an object, type: %^GREEN%^help modify%^RESET%^ This provides a list of modifiable things and the directives that can be modified on them. Ultimately the Quick Creation System generates LPC code, so you'll want to review the earlier chapters of this handbook to get a base of understanding of the code that comprises your new creations. Some notes and tips: * The SetNoCondition directive makes it so an item does not report its physical status when examined. Weapons and armor wear down in combat, and most objects let you know their condition when you examine them. However, in some cases (a sandwich for example) this is inappropriate, so the SetNoCondition directive may be useful. * Doors aren't like normal objects. They have to be modified *twice*. Once for each side of the door. If this sounds unnecessarily tedious, remember that a door leading south is also a door leading north from the other room. * Doors generally are not visible in the same way that regular objects are. To make a door especially obvious and noticeable, do something like: %^GREEN%^modify door sethiddendoor 0%^RESET%^ * SetCurrency is for adding money to NPC's. SetMoney is for adding money to non-living containers (bags, etc). * Item subtypes are listed in /include. To know what kinds of vendors are available, for example, look in /include/vendor_types.h * Books need a \"source directory\", which must contain one file per chapter. The SetSource for this manual, for example, is /doc/manual The first line of each file must follow the same format as the files you see in /doc/manual * SetObviousExits is usually no longer needed: rooms report obvious exits automatically. However, if you don't want an exit to show up by default, use the SetObviousExits directive to specify only those that you want seen. This will override the room's default exit display. ",({"chapter 9","chapter nine","9",}):"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 ",({"chapter 31","chapter thirty-one","31",}):"chapter 31 \"Overview of the Quick Creation System\" First, let me clarify that the QCS is not intended to replace good coding habits. It is also not designed to handle every possible need of a builder. The QCS is just a handy tool for making the most tedious parts of building easier. The amount of time it takes to hand-code an area of 100 rooms (a small area, that is), with all the appropriate descriptions and monsters and weapons and such is just mind-boggling. As a grown-up, I just don't have time for building stuff line by excruciating line in raw LPC, because I also need to work, maintain my house, say hello to my family on occasion, etc. At the same time, I would need a team of dedicated LPC code fetishists to make a creation system that covers every last possible thing you could do in LPC. The QCS is somewhere in between those two extremes. Therefore please view the QCS as a quick way to get bulk building done, and not as a be-all end-all solution. You still need to learn LPC to do really cool stuff. But to hammer out an area with a quest, QCS lets you sail through the process of thingmaking with little hassle. The design philosophy of the system itself involves object files stored in /secure/modules. These files are inherited by an object which you need to carry with you in order to use the QCS system. The code for these creation modules is fairly messy and inelegant, but the result is clean, indented code that compiles, so let's keep the mockery to a minimum, shall we? It is important to keep in mind the QCS isn't an editing system. It's real live on-line modification, meaning that to modify a thing, it actually has to be in the same room you are in, or it has to be that room itself. Once you modify something, it will typically update, so that if you change the name of an npc, you're going to need to use the new name to modify it further. The next few chapters in this manual are nominally QCS specific, but in reality this is pretty much my only chance to document some of the changes in Dead Souls since version 1, so even if you never intend to use QCS, it's worth poking through these chapters. - Cratylus @ Frontiers 2 January 2006 ",({"chapter 4","chapter four","4",}):"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. ",({"chapter 23","chapter twenty-three","23",}):"chapter 23 \"Properties\" 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. ",({"chapter 28","chapter twenty-eight","28",}):"chapter 28 \"Vendors\" 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. ",({"chapter 8","chapter eight","8",}):"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. // CORRECTION: move_object() does not take two arguments in recent // versions of MudOS. -Crat 24Feb2007 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) ",({"chapter 16","chapter sixteen","16",}):"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 ",({"chapter 37","chapter thirty-seven","37",}):"chapter 37 \"QCS: Modifying things and stuff\" You should have a firm grasp now on how QCS works in relation to manipulable objects. Let's look at the settings for a few special kinds of items: chairs ------ %^GREEN%^modify stool maxsitters 1%^RESET%^ %^GREEN%^modify stool setmaxcarry 200%^RESET%^ beds ---- %^GREEN%^modify sofa maxsitters 2%^RESET%^ %^GREEN%^modify sofa maxliers 1%^RESET%^ %^GREEN%^modify sofa maxcarry 400%^RESET%^ containers ---------- %^GREEN%^modify box canclose 1%^RESET%^ %^GREEN%^modify box closed 1%^RESET%^ %^GREEN%^modify box locked 1%^RESET%^ %^GREEN%^modify box key magic_skeleton_key%^RESET%^ %^GREEN%^modify box maxcarry 200%^RESET%^ %^GREEN%^modify box setmoney gold 15%^RESET%^ tables ------ %^GREEN%^modify altar maxcarry 300%^RESET%^ %^GREEN%^modify altar maxliers 1%^RESET%^ meals/drinks ------------ %^GREEN%^modify burger mealtype food%^RESET%^ %^GREEN%^modify schlitz mealtype alcohol%^RESET%^ %^GREEN%^modify apple mealstrength 10%^RESET%^ books ----- %^GREEN%^modify journal title The Orc Within%^RESET%^ %^GREEN%^modify journal source /domains/Orcland/etc/books/journal%^RESET%^ Readable things: ---------------- If you want to be able to \"read thing\", for example, \"read sign\": %^GREEN%^modify sign defaultread This is a message written on the sign.%^RESET%^ If you want to make a thing on a thing readable, as in \"read inscription on ring\": %^GREEN%^modify ring item%^RESET%^ %^GREEN%^inscription%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^This is an inscription on the ring. Try 'read inscription on ring'%^RESET%^ %^GREEN%^modify ring read%^RESET%^ %^GREEN%^inscription%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^So! We, the spear-Danes%^RESET%^ By default, readabale items are readable by anyone, regardless of the languages they know. If, however, your item should only be readable by someone who understands the elvish tongue: %^GREEN%^modify ring language edhellen%^RESET%^ Miscellaneous: -------------- To make a key have a 50% chance of breaking when it's used: %^GREEN%^modify golden key disablechance 50%^RESET%^ To make a room or object immune to resets: %^GREEN%^modify sentry noclean 1%^RESET%^ To make sure there is only one instance of an object or NPC loaded at any given time: %^GREEN%^modify tiamat unique 1%^RESET%^ To make a thing or room immune to the QCS (except for this command): %^GREEN%^modify workroom nomodify 1%^RESET%^ To specify what kind of vendor should be allowed to traffic in this item: %^GREEN%^modify necklace vendortype treasure%^RESET%^ ",({"chapter 33","chapter thirty-three","33",}):"chapter 33 \"QCS: Creation\" Creation breaks down into three categories. \"Things\", rooms, and doors. Let's look at things first: Thing creation: --------------- In this category we're including NPC's, weapon, armor, unspecial items, tables, furniture, books and containers. Basically things that actually show up somewhere. A door is a very special sort of object and does not fall under this category. To make a new thing, the syntax looks like this: create THING FILENAME The THING is the category of item we are creating. The FILENAME is the name of the file that will contain this item's configuration data. You may enter an absolute path, or you may simply enter a filename. If you enter a filename, QCS will attempt to figure out the best place for this file. If your current working directory has a name QCS understands as being compatible with the type of object you are making (for example, your cwd is /realms/you/npc and you are making an NPC) it will use that. Otherwise it will search parent and children directories for a directory name it understands this way. Finally, if it can find no compatible directories for your file near your cwd, it will put it in the appropriate directory in your home area (in this case, /realms/you/area/npc ). Avoid a relative path. It probably won't work the way you think. When the command completes, FILENAME will be a file containing the data for your generic thing, and a copy of that generic thing will appear in the room you are in. If, for example, you entered: %^GREEN%^create npc cowboy%^RESET%^ The room you are in will contain a generic NPC which *does not* answer to the id of \"cowboy\". This NPC is just a generic NPC whose filename is (probably) /realms/you/npc/cowboy.c and isn't yet a real cowboy. You'll need to use the \"modify\" command to make a proper cowboy out of him. Room creation ------------- Naturally, if you create a room, a new room will not appear inside your current environment. Instead, the syntax of the \"create\" command is different when you want to create a new room. You may have noticed that you can't use the \"create\" command to make a new room adjacent to your workroom. This is for your protection and my sanity. Files which contain the directive \"SetNoModify(1)\" are immune to QCS manipulation. Rooms like your workroom, the default start room, the void room, etc, are set nomodify. This is because if you screw it up, you will be sorry, and I just don't want to hear it. So, suppose then that you're in your sample room (one room east of your workroom) and you want to make a new room. You might issue the following command: %^GREEN%^create room south testroom1%^RESET%^ What this does is copy the room you are in (in this case, /realms/you/area/sample_room.c) to a new location (perhaps /realms/you/area/testroom1.c). But the neat thing is, this new room does not have the same exits as the room you are in. The new room has just one exit, leading back to where you are. The net effect of all this is that when you issue this command, you make a new room in the direction you specify, and this new room looks just like the room you're in, only the exits are such that you can travel back and forth between the rooms. Door creation ------------- Doors are funny things. In Dead Souls, they aren't objects in the conventional sense of a thing which occupies a room you're in. Rather, they are really daemons which attach to adjoining rooms. If that doesn't make sense to you, don't worry. You're not alone. The syntax for door creation is much like that for room creation. After you create that room south of your sample room, you can now create a door between them: %^GREEN%^create door south sample_door%^RESET%^ This brings into existence a generic door (closed by default) which is between the two rooms. ",({"chapter 6","chapter six","6",}):"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 :) ",({"chapter 34","chapter thirty-four","34",}):"chapter 34 \"QCS: Modification of NPC's\" In the previous chapter we learned how to make a generic object. Now that we have it, what to do with it? It's important to keep in mind that the generic thing now in front of you isn't just a clone from a template file. If the command you used was \"create npc cowboy\", there is now a file (probably) called /realms/you/area/npc/cowboy.c that contains the code for the creature in front of you. However, this poor beast has the most uninteresting of features. It is in fact so boring that it responds only to its generic type. Such that \"examine cowboy\" or \"kill tex\" won't work. You'll need to \"look at npc\". Accordingly, any modification commands need to be made referring to the new thing with an it responds to, until such a time as you change the id to suit your tastes. Let's carry on with the example of our generic npc. To make a cowboy out of him, we can either change his name, or his id, or both. Let's start with his name: %^GREEN%^modify npc name cowboy%^RESET%^ This makes the SetKeyName() directive in cowboy.c use \"cowboy\" as its argument, effectively allowing you to address this npc as \"cowboy\" from now on. Now you can \"look at cowboy\" with some results. Obviously our NPC isn't *just* a cowboy. He's also a human, a dude, and his name is Tex. How do we make him respond to all of these nouns? %^GREEN%^modify cowboy id%^RESET%^ You'll notice there are no arguments following the word \"id\". Setting a thing's id is different from most other settings. If you'll think back to the LPC datatypes chapter of this manual (you did read the LPC chapters, didn't you?) you'll remember that some information about objects is in the form of strings (\"cowboy\"), some is in the form of integers (the cowboy's health points, for example) and some is in the form of arrays, which are a group of data points. In this example we want the cowboy's id to be an array, because of the many ways we might want to address him. Therefore, we want the SetId directive in his file to look like this: SetId( ({\"human\", \"dude\", \"tex\" }) ); You might think that QCS should be able to accept multiple values like this on a line, perhaps with \"modify cowboy id human dude tex\" as the command. But what if you want this npc to be a \"Boy Named Sue\"? How would you accommodate id's that contain spaces? In designing QCS, I considered having escape characters to allow for such things, but ultimately reasoned that this was just way too much mess. Instead, SetId, and other directives that take arrays as arguments, are handled by entering a query session. Below is an example of what it might look like. The example is necessarily messy because I am including both the queries and the responses. --------------------------------------------------- > %^GREEN%^modify npc name cowboy%^RESET%^ Indenting file... \"/tmp/indent.1136206130.tmp.dat\" 15 lines 420 bytes Exit from ed. > %^GREEN%^modify cowboy 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%^human%^RESET%^ You may now enter the next value. So far, we have: ({ \"dude\", \"human\" }) If you're done entering values, enter a dot on a blank line. %^GREEN%^tex%^RESET%^ You may now enter the next value. So far, we have: ({ \"dude\", \"human\", \"tex\" }) If you're done entering values, enter a dot on a blank line. %^GREEN%^boy named sue%^RESET%^ You may now enter the next value. So far, we have: ({ \"dude\", \"human\", \"tex\", \"boy named sue\" }) If you're done entering values, enter a dot on a blank line. %^GREEN%^.%^RESET%^ Entries complete. Final array is: ({ \"dude\", \"human\", \"tex\", \"boy named sue\" }) Indenting file... \"/tmp/indent.1136206156.tmp.dat\" 19 lines 459 bytes Exit from ed. /open/1136206138: Ok /realms/cratylus/area/npc/cowboy: Ok SetId modification complete. > %^GREEN%^exa tex%^RESET%^ Other than being human, this npc is entirely unremarkable. The male human is in top condition. --------------------------------------------------- If you were now to examine Tex's code (with the command \"about tex\") you'd see that his SetId directive now looks like this: SetId( ({\"dude\", \"human\", \"tex\", \"boy named sue\"}) ); Other NPC features take arrays also. SetAdjectives is one. You might enter this (mud output omitted for clarity): %^GREEN%^modify tex adjectives%^RESET%^ %^GREEN%^dusty%^RESET%^ %^GREEN%^hardy%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^look at dusty cowboy%^RESET%^ There are two other directives that require queries. Things and NPC's can be looked at, but they can also be smelled and listened to, if you add SetSmell and SetListen. The syntax is: %^GREEN%^modify tex smell%^RESET%^ And you will then be asked a question about keys and mappings. Understanding mappings is important, but for now you just need to understand that you are being asked *two* separate questions: 1) What on the cowboy is being smelled/listened to? 2) What is the smell/sound? What this means is that your input will look something like this: %^GREEN%^modify tex smell%^RESET%^ %^GREEN%^default%^RESET%^ %^GREEN%^.%^RESET%^ Tex smells of sweat and manure. What happens is this: - You enter the modify command. - You enter the word \"default\" to indicate this is Tex's general smell. - You enter a dot to indicate that you are done specifying what part of Tex is being smelled. - You then specify the smell. This may seem odd until you realize you can also add smells/listens to parts of things. Not on NPC's, though. We'll look at this more closely in later chapters. For now, just use the syntax as shown above. For adding a listen to the cowboy, it works the same way: %^GREEN%^modify tex listen%^RESET%^ %^GREEN%^default%^RESET%^ %^GREEN%^.%^RESET%^ Tex seems to be humming a jaunty melody. Other features of an NPC do not take arrays, so one-line commands will do. For example: %^GREEN%^modify cowboy long This is a cowboy who calls himself Tex, but is in fact a Boy Named Sue.%^RESET%^ %^GREEN%^modify cowboy short a cowboy%^RESET%^ %^GREEN%^modify cowboy level 5%^RESET%^ %^GREEN%^modify cowboy class fighter%^RESET%^ %^GREEN%^modify tex currency gold 1%^RESET%^ %^GREEN%^modify tex currency silver 12%^RESET%^ %^GREEN%^modify tex skill bargaining 5%^RESET%^ %^GREEN%^modify tex skill projectile attack 7%^RESET%^ %^GREEN%^modify tex stat strength 33%^RESET%^ %^GREEN%^modify tex property nice guy 1%^RESET%^ %^GREEN%^modify tex healthpoints 150%^RESET%^ %^GREEN%^modify tex maxhealthpoints 170%^RESET%^ %^GREEN%^modify tex melee 0%^RESET%^ %^GREEN%^modify tex unique 1%^RESET%^ If you now issue the \"about tex\" command you will see that all the changes you made have been put into the file. You may have noticed the \"melee\" keyword. Dead Souls 2 NPC's come in various shapes and sizes, and some of them shouldn't wield weapons. A wolf with a battle axe would be a strange sight indeed. However, the default combat system makes unarmed creatures extremely vulnerable in combat. To make an NPC combat-capable without weapons, use the new SetMelee directive. SetMelee(1) makes the NPC capable of proper unarmed combat. SetMelee(0) makes the NPC a weak opponent if unarmed. NPC's will generally try to bite during unarmed combat. If this is beneath the capability or dignity of your NPC, you can prevent this with: %^GREEN%^modify tex canbite 0%^RESET%^ If your NPC should try to escape when the battle isn't going his way, the wimpy settings should do: %^GREEN%^modify tex wimpy 30%^RESET%^ %^GREEN%^modify tex wimpycommand climb ladder%^RESET%^ If you don't specify a wimpy command, Tex will leave the room through a random exit. In this case, when Tex's health is down to 30% and he is in combat, he will try to climb a ladder. Some NPC's are designed to travel about. To enable this feature, use the wanderspeed directive: %^GREEN%^modify tex wanderspeed 5%^RESET%^ If you want him to travel more quickly, use a lower number. By default, wandering NPC's only wander in rooms that have already been loaded into memory. They avoid loading rooms because loading a bunch of rooms that only the NPC will ever see is a waste of your mud's resources. However, if you *do* want your NPC to wander in an unrestricted manner, regardless of whether a room is loaded, use the permitload directive: %^GREEN%^modify tex permitload 1%^RESET%^ By default, NPC's stand up when they can. This is so that if they collapse during combat, they try to get back up once they are able to do so. If you prefer that your NPC maintain some other posture, you can set that posture, then disable autostanding like this: %^GREEN%^modify tex posture lying%^RESET%^ %^GREEN%^modify tex autostand 0%^RESET%^ If he's especially lazy, you can have him take a nap this way: %^GREEN%^modify tex sleeping 10%^RESET%^ Which will have him wake up after about a minute. However, note that if you've disabled autostanding, he will remain lying down after he wakes up. If the NPC should be hostile, that is, he should attack any creatures that it sees enter a room, SetEncounter should do it: %^GREEN%^modify tex encounter 100%^RESET%^ This means that if the creature it sees has a charisma score of less than 100 (which should pretty much be always true), Tex will try to kill it. You can do some fancy stuff with SetEncounter, such as only attacking orcs, or actually doing something friendly, but to do so you can't use QCS. Read the NPC and Sentients chapter in the Creator's Manual for details on how to code such stuff. If the NPC is a golem or other such non-biological creature, it may be useful to specify what they are made of. The SetComposition setting for a clay golem might look like this: %^GREEN%^modify golem composition clay%^RESET%^ If it happens to be a golem that does not believe in violence as a solution to problems, you can make refuse to hurt others with the following: %^GREEN%^modify golem pacifist 1%^RESET%^ Vendors: ------- Vendors are a special kind of NPC that can sell stuff. Along with the standard NPC settings, vendors have the following: SetStorageRoom specifies where the vendor's stock is stored. If a valid room is specified, anything in that room can be sold by the vendor. SetLocalCurrency specifies the type of currency, such as gold or silver, that the vendor accepts. SetMaxItems is the maximum number of items in the storeroom that the vendor is permitted to sell. SetVendorType specifies the kind of stuff the vendor can trade in. \"all\" allows him to buy and sell whatever. But if he is a weapon vendor, he can't trade in armor, etc. See /include/vendor_types.h for the available vendor types. To have a \"multi-type\" vendor, you'll have to code it by hand. The result of that looks something like this: SetVendorType( VT_TREASURE | VT_ARMOR | VT_HERBS ); Barkeeps: -------- Like vendors, barkeeps sell stuff, but they are limited to selling food and drink. Unlike vendors, barkeeps have no limitation on the amount of stuff they can sell. They also do not have a storeroom. The stuff they can sell is specified in their SetMenu directive, like this: %^GREEN%^clone woody%^RESET%^ You clone a generic barkeep (/realms/temujin/area/npc/woody.c). %^GREEN%^modify woody menu%^RESET%^ If you don't understand these questions, type the letter q on a blank line and hit enter. Please enter the first key element for this mapping: %^GREEN%^bourbon%^RESET%^ Please enter the next key element, or enter a single dot to finish entering key elements. %^GREEN%^whiskey%^RESET%^ Please enter the next key element, or enter a single dot to finish entering key elements. %^GREEN%^.%^RESET%^ Please enter the value for key ({ \"bourbon\", \"whiskey\" }): %^GREEN%^/domains/town/meals/bourbon%^RESET%^ Barkeeps also have the SetLocalCurrency directive to specify the currency they accept. ",({"chapter 33","chapter thirty-three","33",}):"chapter 33 \"QCS: Creation\" Creation breaks down into three categories. \"Things\", rooms, and doors. Let's look at things first: Thing creation: --------------- In this category we're including NPC's, weapon, armor, unspecial items, tables, furniture, books and containers. Basically things that actually show up somewhere. A door is a very special sort of object and does not fall under this category. To make a new thing, the syntax looks like this: create THING FILENAME The THING is the category of item we are creating. The FILENAME is the name of the file that will contain this item's configuration data. You may enter an absolute path, or you may simply enter a filename. If you enter a filename, QCS will attempt to figure out the best place for this file. If your current working directory has a name QCS understands as being compatible with the type of object you are making (for example, your cwd is /realms/you/npc and you are making an NPC) it will use that. Otherwise it will search parent and children directories for a directory name it understands this way. Finally, if it can find no compatible directories for your file near your cwd, it will put it in the appropriate directory in your home area (in this case, /realms/you/area/npc ). Avoid a relative path. It probably won't work the way you think. When the command completes, FILENAME will be a file containing the data for your generic thing, and a copy of that generic thing will appear in the room you are in. If, for example, you entered: %^GREEN%^create npc cowboy%^RESET%^ The room you are in will contain a generic NPC which *does not* answer to the id of \"cowboy\". This NPC is just a generic NPC whose filename is (probably) /realms/you/npc/cowboy.c and isn't yet a real cowboy. You'll need to use the \"modify\" command to make a proper cowboy out of him. Room creation ------------- Naturally, if you create a room, a new room will not appear inside your current environment. Instead, the syntax of the \"create\" command is different when you want to create a new room. You may have noticed that you can't use the \"create\" command to make a new room adjacent to your workroom. This is for your protection and my sanity. Files which contain the directive \"SetNoModify(1)\" are immune to QCS manipulation. Rooms like your workroom, the default start room, the void room, etc, are set nomodify. This is because if you screw it up, you will be sorry, and I just don't want to hear it. So, suppose then that you're in your sample room (one room east of your workroom) and you want to make a new room. You might issue the following command: %^GREEN%^create room south testroom1%^RESET%^ What this does is copy the room you are in (in this case, /realms/you/area/sample_room.c) to a new location (perhaps /realms/you/area/testroom1.c). But the neat thing is, this new room does not have the same exits as the room you are in. The new room has just one exit, leading back to where you are. The net effect of all this is that when you issue this command, you make a new room in the direction you specify, and this new room looks just like the room you're in, only the exits are such that you can travel back and forth between the rooms. Door creation ------------- Doors are funny things. In Dead Souls, they aren't objects in the conventional sense of a thing which occupies a room you're in. Rather, they are really daemons which attach to adjoining rooms. If that doesn't make sense to you, don't worry. You're not alone. The syntax for door creation is much like that for room creation. After you create that room south of your sample room, you can now create a door between them: %^GREEN%^create door south sample_door%^RESET%^ This brings into existence a generic door (closed by default) which is between the two rooms. ",({"chapter 9","chapter nine","9",}):"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 ",({"chapter 21","chapter twenty-one","21",}):"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. ",({"chapter 12","chapter twelve","12",}):"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 ",({"chapter 39","chapter thirty-nine","39",}):"chapter 39 \"QCS: Final notes\" * Remember that QCS commands work on objects, not files. To load a file into memory, use the update command. To reload an already existing object, like a cloned orc or a book, use the reload command. To use modify, delete, and add, you have to specify a cloned object that is on you or in your environment. I think you're getting the idea of how this works. Here's an example of armor creation: %^GREEN%^create armor jeans%^RESET%^ %^GREEN%^modify jeans id%^RESET%^ %^GREEN%^pants%^RESET%^ %^GREEN%^trousers%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^modify jeans short a pair of denim jeans%^RESET%^ %^GREEN%^modify jeans long Worn jeans, frayed and stained.%^RESET%^ %^GREEN%^modify jeans adj%^RESET%^ %^GREEN%^pair of%^RESET%^ %^GREEN%^denim%^RESET%^ %^GREEN%^frayed%^RESET%^ %^GREEN%^worn%^RESET%^ %^GREEN%^stained%^RESET%^ %^GREEN%^.%^RESET%^ To know what directives QCS can change on an object, type: %^GREEN%^help modify%^RESET%^ This provides a list of modifiable things and the directives that can be modified on them. Ultimately the Quick Creation System generates LPC code, so you'll want to review the earlier chapters of this handbook to get a base of understanding of the code that comprises your new creations. Some notes and tips: * The SetNoCondition directive makes it so an item does not report its physical status when examined. Weapons and armor wear down in combat, and most objects let you know their condition when you examine them. However, in some cases (a sandwich for example) this is inappropriate, so the SetNoCondition directive may be useful. * Doors aren't like normal objects. They have to be modified *twice*. Once for each side of the door. If this sounds unnecessarily tedious, remember that a door leading south is also a door leading north from the other room. * Doors generally are not visible in the same way that regular objects are. To make a door especially obvious and noticeable, do something like: %^GREEN%^modify door sethiddendoor 0%^RESET%^ * SetCurrency is for adding money to NPC's. SetMoney is for adding money to non-living containers (bags, etc). * Item subtypes are listed in /include. To know what kinds of vendors are available, for example, look in /include/vendor_types.h * Books need a \"source directory\", which must contain one file per chapter. The SetSource for this manual, for example, is /doc/manual The first line of each file must follow the same format as the files you see in /doc/manual * SetObviousExits is usually no longer needed: rooms report obvious exits automatically. However, if you don't want an exit to show up by default, use the SetObviousExits directive to specify only those that you want seen. This will override the room's default exit display. ",({"chapter 20","chapter twenty","20",}):"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. ",({"chapter 38","chapter thirty-eight","38",}):"chapter 38 \"QCS: Adding and deleting\" Rooms, containers and NPC's all are capable of holding items, and often it is convenient to have them already holding certain items upon creation. The SetInventory directive in an object's file provides us with a list of that object's \"permanent inventory\". To modify an object's inventory, we use the add and delete commands. Let's say that we want our cowboy to be wielding a hammer when he appears... %^GREEN%^clone cowboy%^RESET%^ %^GREEN%^cd ../weap%^RESET%^ %^GREEN%^clone hammer%^RESET%^ %^GREEN%^add hammer to cowboy%^RESET%^ %^GREEN%^wield hammer%^RESET%^ Believe it or not, it's that simple. The add command will ask you a question after you issue it. What it wants to know is if you want the NPC to do anything special when the hammer appears on him. In this case, yes, we wanted him to wield it. However, if you want to add something to an NPC and don't have anything interesting for him to do with it, respond to the question with the number of items that you want to appear. For example, if I want the cowboy to be carrying a key: %^GREEN%^cd ../obj%^RESET%^ %^GREEN%^clone key%^RESET%^ %^GREEN%^add key to cowboy%^RESET%^ %^GREEN%^1%^RESET%^ And that's it. Now if I want the cowboy to be a permanent resident of this room: %^GREEN%^add cowboy%^RESET%^ %^GREEN%^1%^RESET%^ The add command understands that if you don't specify a target argument, you must mean the room. You can also be specific: %^GREEN%^add cowboy to room%^RESET%^ %^GREEN%^1%^RESET%^ The delete command works the opposite way. It removes items from an object's permanent inventory: %^GREEN%^delete hammer from cowboy%^RESET%^ %^GREEN%^delete cowboy%^RESET%^ The delete command is also the way to get rid of rooms. You won't be removing the file from disk, you'll just be deleting that exit from the room: %^GREEN%^delete exit garden%^RESET%^ NOTE: When you delete an exit, only the connection from your room to the other room is removed. The connection from the other room to your room remains. This is not a bug, it's a feature. There are plenty of circumstances where one-way travel is desirable. ",({"chapter 26","chapter twenty-six","26",}):"chapter 26 \"Sentients\" 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. ",({"chapter 32","chapter thirty-two","32",}):"chapter 32 \"QCS: Commands\" What with muds being text only, QCS has no fancy windowing system. Using a menu-driven creation system was ruled out quickly due to the vast complexity of the menus that would be required. Instead, QCS relies on a few powerful commands. create This is the command that gets the ball rolling. This command is what lets you bring a new thing into existence. The things you can create can be seen by typing \"help create\". Examples are rooms, weapons, doors, and so on. We will be reviewing each of those in later chapters. When you issue this command a generic version of the item you wish to create appears (or, in the case of a room, appears in the direction you specify). Once that generic copy materializes, you can change it to suit your needs using the \"modify\" command. modify I tend to regard this command as the heart and soul of QCS. It's this tool that lets you make your world your own. Your new generic things are not useful or fun until you modify them. A \"generic weapon\" isn't very interesting, but a \"mithrilite poleaxe\" might be just the thing to deal with a pesky dragon. add Creatures, rooms, and containers are capable of storing other things. Once you make an ogre, you may want to give him a hammer to wield. After you make that hammer, you use the add command to let the ogre have that wepon in his permanent inventory. delete On the other hand, you may be tired of that ogre after a while. If he is a part of the permanent inventory of a room, you can use the delete command to remove him permanently. Or if you'd rather he have a Kill-O-Zap Frogstar blaster rather than a hammer, get rid of the hammer in his inventory with this command. copy This is a room-specific command. Rather than write multiple, nearly identical rooms for large areas, you can use the copy command to make the room you are almost exactly like any other room you choose, except for the exits, which remain the same. Handy for big forests, cell-blocks, twisty mazes of little passages, etc. initfix If a thing isn't working right, try to initfix it. \"init()\" is an object function that many items need in order to work properly. If you've run into something that is behaving unexpectedly, run initfix on it. The trouble just might clear up. ",({"chapter 14","chapter fourteen","14",}):"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 ",({"chapter 24","chapter twenty-four","24",}):"chapter 24 \"Quests\" 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 ",({"chapter 19","chapter nineteen","19",}):"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. ",({"chapter 36","chapter thirty-six","36",}):"chapter 36 \"QCS: Modifying weapons\" Remember that the QCS chapters are supposed to be read in sequence. This is important because as we progress, I will not make explanations about directives and concepts explained previously. Weapons are different from rooms and NPC's in that they can be handled, sold, thrown, etc. They are manipulable objects. As such, we will see new directives: %^GREEN%^create weapon hammer%^RESET%^ You may be familiar with this example from the example webpage. Let's go ahead and plow through the commands: %^GREEN%^modify weapon id hammer%^RESET%^ %^GREEN%^warhammer%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^modify hammer name hammer%^RESET%^ %^GREEN%^modify hammer damagetype blunt%^RESET%^ %^GREEN%^modify hammer weapontype blunt%^RESET%^ %^GREEN%^modify hammer mass 700%^RESET%^ %^GREEN%^modify hammer hands 2%^RESET%^ %^GREEN%^modify hammer short a heavy war hammer%^RESET%^ %^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%^ %^GREEN%^modify hammer adj%^RESET%^ %^GREEN%^large%^RESET%^ %^GREEN%^heavy%^RESET%^ %^GREEN%^war%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^modify hammer basecost silver 750%^RESET%^ %^GREEN%^about hammer%^RESET%^ Like a room and unlike an NPC, you can also modify the SetItems on manipulable objects like weapons, so you could do something like this: %^GREEN%^modify hammer item%^RESET%^ %^GREEN%^shaft%^RESET%^ %^GREEN%^handle%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^A thick, reinforced steel shaft with leather bands for a strong grip.%^RESET%^ %^GREEN%^exa shaft on hammer%^RESET%^ ",({"chapter 34","chapter thirty-four","34",}):"chapter 34 \"QCS: Modification of NPC's\" In the previous chapter we learned how to make a generic object. Now that we have it, what to do with it? It's important to keep in mind that the generic thing now in front of you isn't just a clone from a template file. If the command you used was \"create npc cowboy\", there is now a file (probably) called /realms/you/area/npc/cowboy.c that contains the code for the creature in front of you. However, this poor beast has the most uninteresting of features. It is in fact so boring that it responds only to its generic type. Such that \"examine cowboy\" or \"kill tex\" won't work. You'll need to \"look at npc\". Accordingly, any modification commands need to be made referring to the new thing with an it responds to, until such a time as you change the id to suit your tastes. Let's carry on with the example of our generic npc. To make a cowboy out of him, we can either change his name, or his id, or both. Let's start with his name: %^GREEN%^modify npc name cowboy%^RESET%^ This makes the SetKeyName() directive in cowboy.c use \"cowboy\" as its argument, effectively allowing you to address this npc as \"cowboy\" from now on. Now you can \"look at cowboy\" with some results. Obviously our NPC isn't *just* a cowboy. He's also a human, a dude, and his name is Tex. How do we make him respond to all of these nouns? %^GREEN%^modify cowboy id%^RESET%^ You'll notice there are no arguments following the word \"id\". Setting a thing's id is different from most other settings. If you'll think back to the LPC datatypes chapter of this manual (you did read the LPC chapters, didn't you?) you'll remember that some information about objects is in the form of strings (\"cowboy\"), some is in the form of integers (the cowboy's health points, for example) and some is in the form of arrays, which are a group of data points. In this example we want the cowboy's id to be an array, because of the many ways we might want to address him. Therefore, we want the SetId directive in his file to look like this: SetId( ({\"human\", \"dude\", \"tex\" }) ); You might think that QCS should be able to accept multiple values like this on a line, perhaps with \"modify cowboy id human dude tex\" as the command. But what if you want this npc to be a \"Boy Named Sue\"? How would you accommodate id's that contain spaces? In designing QCS, I considered having escape characters to allow for such things, but ultimately reasoned that this was just way too much mess. Instead, SetId, and other directives that take arrays as arguments, are handled by entering a query session. Below is an example of what it might look like. The example is necessarily messy because I am including both the queries and the responses. --------------------------------------------------- > %^GREEN%^modify npc name cowboy%^RESET%^ Indenting file... \"/tmp/indent.1136206130.tmp.dat\" 15 lines 420 bytes Exit from ed. > %^GREEN%^modify cowboy 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%^human%^RESET%^ You may now enter the next value. So far, we have: ({ \"dude\", \"human\" }) If you're done entering values, enter a dot on a blank line. %^GREEN%^tex%^RESET%^ You may now enter the next value. So far, we have: ({ \"dude\", \"human\", \"tex\" }) If you're done entering values, enter a dot on a blank line. %^GREEN%^boy named sue%^RESET%^ You may now enter the next value. So far, we have: ({ \"dude\", \"human\", \"tex\", \"boy named sue\" }) If you're done entering values, enter a dot on a blank line. %^GREEN%^.%^RESET%^ Entries complete. Final array is: ({ \"dude\", \"human\", \"tex\", \"boy named sue\" }) Indenting file... \"/tmp/indent.1136206156.tmp.dat\" 19 lines 459 bytes Exit from ed. /open/1136206138: Ok /realms/cratylus/area/npc/cowboy: Ok SetId modification complete. > %^GREEN%^exa tex%^RESET%^ Other than being human, this npc is entirely unremarkable. The male human is in top condition. --------------------------------------------------- If you were now to examine Tex's code (with the command \"about tex\") you'd see that his SetId directive now looks like this: SetId( ({\"dude\", \"human\", \"tex\", \"boy named sue\"}) ); Other NPC features take arrays also. SetAdjectives is one. You might enter this (mud output omitted for clarity): %^GREEN%^modify tex adjectives%^RESET%^ %^GREEN%^dusty%^RESET%^ %^GREEN%^hardy%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^look at dusty cowboy%^RESET%^ There are two other directives that require queries. Things and NPC's can be looked at, but they can also be smelled and listened to, if you add SetSmell and SetListen. The syntax is: %^GREEN%^modify tex smell%^RESET%^ And you will then be asked a question about keys and mappings. Understanding mappings is important, but for now you just need to understand that you are being asked *two* separate questions: 1) What on the cowboy is being smelled/listened to? 2) What is the smell/sound? What this means is that your input will look something like this: %^GREEN%^modify tex smell%^RESET%^ %^GREEN%^default%^RESET%^ %^GREEN%^.%^RESET%^ Tex smells of sweat and manure. What happens is this: - You enter the modify command. - You enter the word \"default\" to indicate this is Tex's general smell. - You enter a dot to indicate that you are done specifying what part of Tex is being smelled. - You then specify the smell. This may seem odd until you realize you can also add smells/listens to parts of things. Not on NPC's, though. We'll look at this more closely in later chapters. For now, just use the syntax as shown above. For adding a listen to the cowboy, it works the same way: %^GREEN%^modify tex listen%^RESET%^ %^GREEN%^default%^RESET%^ %^GREEN%^.%^RESET%^ Tex seems to be humming a jaunty melody. Other features of an NPC do not take arrays, so one-line commands will do. For example: %^GREEN%^modify cowboy long This is a cowboy who calls himself Tex, but is in fact a Boy Named Sue.%^RESET%^ %^GREEN%^modify cowboy short a cowboy%^RESET%^ %^GREEN%^modify cowboy level 5%^RESET%^ %^GREEN%^modify cowboy class fighter%^RESET%^ %^GREEN%^modify tex currency gold 1%^RESET%^ %^GREEN%^modify tex currency silver 12%^RESET%^ %^GREEN%^modify tex skill bargaining 5%^RESET%^ %^GREEN%^modify tex skill projectile attack 7%^RESET%^ %^GREEN%^modify tex stat strength 33%^RESET%^ %^GREEN%^modify tex property nice guy 1%^RESET%^ %^GREEN%^modify tex healthpoints 150%^RESET%^ %^GREEN%^modify tex maxhealthpoints 170%^RESET%^ %^GREEN%^modify tex melee 0%^RESET%^ %^GREEN%^modify tex unique 1%^RESET%^ If you now issue the \"about tex\" command you will see that all the changes you made have been put into the file. You may have noticed the \"melee\" keyword. Dead Souls 2 NPC's come in various shapes and sizes, and some of them shouldn't wield weapons. A wolf with a battle axe would be a strange sight indeed. However, the default combat system makes unarmed creatures extremely vulnerable in combat. To make an NPC combat-capable without weapons, use the new SetMelee directive. SetMelee(1) makes the NPC capable of proper unarmed combat. SetMelee(0) makes the NPC a weak opponent if unarmed. NPC's will generally try to bite during unarmed combat. If this is beneath the capability or dignity of your NPC, you can prevent this with: %^GREEN%^modify tex canbite 0%^RESET%^ If your NPC should try to escape when the battle isn't going his way, the wimpy settings should do: %^GREEN%^modify tex wimpy 30%^RESET%^ %^GREEN%^modify tex wimpycommand climb ladder%^RESET%^ If you don't specify a wimpy command, Tex will leave the room through a random exit. In this case, when Tex's health is down to 30% and he is in combat, he will try to climb a ladder. Some NPC's are designed to travel about. To enable this feature, use the wanderspeed directive: %^GREEN%^modify tex wanderspeed 5%^RESET%^ If you want him to travel more quickly, use a lower number. By default, wandering NPC's only wander in rooms that have already been loaded into memory. They avoid loading rooms because loading a bunch of rooms that only the NPC will ever see is a waste of your mud's resources. However, if you *do* want your NPC to wander in an unrestricted manner, regardless of whether a room is loaded, use the permitload directive: %^GREEN%^modify tex permitload 1%^RESET%^ By default, NPC's stand up when they can. This is so that if they collapse during combat, they try to get back up once they are able to do so. If you prefer that your NPC maintain some other posture, you can set that posture, then disable autostanding like this: %^GREEN%^modify tex posture lying%^RESET%^ %^GREEN%^modify tex autostand 0%^RESET%^ If he's especially lazy, you can have him take a nap this way: %^GREEN%^modify tex sleeping 10%^RESET%^ Which will have him wake up after about a minute. However, note that if you've disabled autostanding, he will remain lying down after he wakes up. If the NPC should be hostile, that is, he should attack any creatures that it sees enter a room, SetEncounter should do it: %^GREEN%^modify tex encounter 100%^RESET%^ This means that if the creature it sees has a charisma score of less than 100 (which should pretty much be always true), Tex will try to kill it. You can do some fancy stuff with SetEncounter, such as only attacking orcs, or actually doing something friendly, but to do so you can't use QCS. Read the NPC and Sentients chapter in the Creator's Manual for details on how to code such stuff. If the NPC is a golem or other such non-biological creature, it may be useful to specify what they are made of. The SetComposition setting for a clay golem might look like this: %^GREEN%^modify golem composition clay%^RESET%^ If it happens to be a golem that does not believe in violence as a solution to problems, you can make refuse to hurt others with the following: %^GREEN%^modify golem pacifist 1%^RESET%^ Vendors: ------- Vendors are a special kind of NPC that can sell stuff. Along with the standard NPC settings, vendors have the following: SetStorageRoom specifies where the vendor's stock is stored. If a valid room is specified, anything in that room can be sold by the vendor. SetLocalCurrency specifies the type of currency, such as gold or silver, that the vendor accepts. SetMaxItems is the maximum number of items in the storeroom that the vendor is permitted to sell. SetVendorType specifies the kind of stuff the vendor can trade in. \"all\" allows him to buy and sell whatever. But if he is a weapon vendor, he can't trade in armor, etc. See /include/vendor_types.h for the available vendor types. To have a \"multi-type\" vendor, you'll have to code it by hand. The result of that looks something like this: SetVendorType( VT_TREASURE | VT_ARMOR | VT_HERBS ); Barkeeps: -------- Like vendors, barkeeps sell stuff, but they are limited to selling food and drink. Unlike vendors, barkeeps have no limitation on the amount of stuff they can sell. They also do not have a storeroom. The stuff they can sell is specified in their SetMenu directive, like this: %^GREEN%^clone woody%^RESET%^ You clone a generic barkeep (/realms/temujin/area/npc/woody.c). %^GREEN%^modify woody menu%^RESET%^ If you don't understand these questions, type the letter q on a blank line and hit enter. Please enter the first key element for this mapping: %^GREEN%^bourbon%^RESET%^ Please enter the next key element, or enter a single dot to finish entering key elements. %^GREEN%^whiskey%^RESET%^ Please enter the next key element, or enter a single dot to finish entering key elements. %^GREEN%^.%^RESET%^ Please enter the value for key ({ \"bourbon\", \"whiskey\" }): %^GREEN%^/domains/town/meals/bourbon%^RESET%^ Barkeeps also have the SetLocalCurrency directive to specify the currency they accept. ",({"chapter 28","chapter twenty-eight","28",}):"chapter 28 \"Vendors\" 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. ",({"chapter 17","chapter seventeen","17",}):"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. ",({"chapter 10","chapter ten","10",}):"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 ",({"chapter 22","chapter twenty-two","22",}):"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 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. ",({"chapter 40","chapter forty","40",}):"chapter 40 \"Useful Creator Commands\" Moving around: ------------- * To go to your workroom: %^GREEN%^home%^RESET%^ * To go to someone else's workroom, \"home <person>\", for example: %^GREEN%^home cratylus%^RESET%^ * To go to the town pub: %^GREEN%^goto /domains/town/room/tavern%^RESET%^ * Or: %^GREEN%^cd /domains/town/room%^RESET%^ %^GREEN%^goto tavern%^RESET%^ * To return to where you were before you went somewhere else: %^GREEN%^return%^RESET%^ * To bring someone to you, \"trans <person>\". For example: %^GREEN%^trans cratylus%^RESET%^ * To send them back when you're done with them: %^GREEN%^return cratylus%^RESET%^ Dealing with living beings: --------------------------- * To force everyone in a room to stop fighting: %^GREEN%^quell%^RESET%^ * To let them resume combat: %^GREEN%^unquell%^RESET%^ * To insta-kill a living being, \"zap <thing>\". For example: %^GREEN%^zap orc%^RESET%^ * To bring to life a player who somehow left the death room without regenerating, \"resurrect <person>\", For example: %^GREEN%^resurrect cratylus%^RESET%^ * To make a living being do something you want, \"force <thing> <command>\". For example: %^GREEN%^force thief drop towel%^RESET%^ %^GREEN%^force thief go west%^RESET%^ * For complex management of a living being's vital statistics, skills, health, score, and satiety levels, use the medical tricorder in the chest in your workroom. * For a detailed report of a living being's physical status: %^GREEN%^stat orc%^RESET%^ %^GREEN%^stat cratylus%^RESET%^ Handling objects in general: --------------------------- * To destroy an object, \"dest <thing>\". Note that the object's inventory will probably move to the room it was occupying. For example, if you: %^GREEN%^dest fighter%^RESET%^ You may find that the room now contains a sword, shield, and chainmail shirt, but no fighter. * To reset an object to its original state, \"reload <thing>\". Note that this also makes the object incorporate any changes you made to its file. For example: %^GREEN%^reload fighter%^RESET%^ %^GREEN%^reload here%^RESET%^ * To load a file into memory, \"update file\". This is used when you have edited an object's file, and want the mud to use the new stuff you created. For example, if you edited the fighter's file and wanted to know if it will load properly into memory, you'd type: %^GREEN%^update /realms/you/area/npc/fighter.c%^RESET%^ Or: %^GREEN%^cd /realms/you/area/npc/%^RESET%^ %^GREEN%^update fighter%^RESET%^ If you do not specify an object to update, the mud assumes you want to update the room you are in. If there is a problem with the room's code, and it does not load, you will be dropped into the \"void\". If the room's code is ok and it updates, anything in the room that isn't part of its permanent inventory (except for players) will disappear from the room. * To make a copy of an object appear, \"clone <file>\". For example: %^GREEN%^clone /realms/you/area/npc/fighter%^RESET%^ Or: %^GREEN%^cd /realms/you/area/npc/%^RESET%^ %^GREEN%^clone fighter%^RESET%^ * To know the precise contents of an object, use scan: %^GREEN%^scan fighter%^RESET%^ %^GREEN%^scan here%^RESET%^ If you want to know not only what the fighter has, but also what any containers he is carrying have, use the \"-d\" flag: %^GREEN%^scan -d fighter%^RESET%^ %^GREEN%^scan -d here%^RESET%^ Debugging commands: -------------------- * elog: This will report back to you the last few lines of your error log. Usually this is very helpful in nailing down which lines of a file contain errors. If you are admin, you may be working on files other than your home dir. If those files fail to update, you can supply elog with a directory name to specify where to look for an error report: %^GREEN%^elog secure%^RESET%^ %^GREEN%^elog cmds%^RESET%^ %^GREEN%^elog lib%^RESET%^ * dbxwhere: provides a list of the chain of messages caught in your last runtime error. * dbxframe <number>: Using the list number from dbxwhere, dbxframe can pinpoint exactly where in that link the error came from. %^GREEN%^tail /log/runtime%^RESET%^ %^GREEN%^tail /log/catch%^RESET%^ %^GREEN%^tail /log/player_errors%^RESET%^ miscellaneous useful commands: ----------------------------- * %^GREEN%^people%^RESET%^: reports who is logged on, what site they logged in from, and what room they are in. * %^GREEN%^mudtime%^RESET%^: reports the time of day in the mud (nothing to do with the time of day anywhere in the real world). * %^GREEN%^bk <thing or file>%^RESET%^: makes a unique copy of that thing or file and puts it in /realms/you/bak *%^GREEN%^ restore <filename>%^RESET%^: copies the last backup of the filename from your bak/ directory into where it used to be. ",({"chapter 2","chapter two","2",}):"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. ",({"chapter 32","chapter thirty-two","32",}):"chapter 32 \"QCS: Commands\" What with muds being text only, QCS has no fancy windowing system. Using a menu-driven creation system was ruled out quickly due to the vast complexity of the menus that would be required. Instead, QCS relies on a few powerful commands. create This is the command that gets the ball rolling. This command is what lets you bring a new thing into existence. The things you can create can be seen by typing \"help create\". Examples are rooms, weapons, doors, and so on. We will be reviewing each of those in later chapters. When you issue this command a generic version of the item you wish to create appears (or, in the case of a room, appears in the direction you specify). Once that generic copy materializes, you can change it to suit your needs using the \"modify\" command. modify I tend to regard this command as the heart and soul of QCS. It's this tool that lets you make your world your own. Your new generic things are not useful or fun until you modify them. A \"generic weapon\" isn't very interesting, but a \"mithrilite poleaxe\" might be just the thing to deal with a pesky dragon. add Creatures, rooms, and containers are capable of storing other things. Once you make an ogre, you may want to give him a hammer to wield. After you make that hammer, you use the add command to let the ogre have that wepon in his permanent inventory. delete On the other hand, you may be tired of that ogre after a while. If he is a part of the permanent inventory of a room, you can use the delete command to remove him permanently. Or if you'd rather he have a Kill-O-Zap Frogstar blaster rather than a hammer, get rid of the hammer in his inventory with this command. copy This is a room-specific command. Rather than write multiple, nearly identical rooms for large areas, you can use the copy command to make the room you are almost exactly like any other room you choose, except for the exits, which remain the same. Handy for big forests, cell-blocks, twisty mazes of little passages, etc. initfix If a thing isn't working right, try to initfix it. \"init()\" is an object function that many items need in order to work properly. If you've run into something that is behaving unexpectedly, run initfix on it. The trouble just might clear up. ",({"chapter 13","chapter thirteen","13",}):"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 ",({"chapter 6","chapter six","6",}):"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 :) ",({"chapter 7","chapter seven","7",}):"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. ",({"chapter 4","chapter four","4",}):"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. ",({"chapter 5","chapter five","5",}):"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. ",({"chapter 17","chapter seventeen","17",}):"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. ",({"chapter 20","chapter twenty","20",}):"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. ",({"chapter 17","chapter seventeen","17",}):"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. ",({"chapter 9","chapter nine","9",}):"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 ",]),"/doc/manual/chapter40":1164672846,"/doc/manual/chapter29":1164672846,"/doc/manual/chapter28":1164672846,"/doc/manual/chapter27":1164672846,"/doc/manual/chapter26":1164672846,"/doc/manual/chapter25":1164672846,"/doc/manual/chapter24":1164672846,"/doc/manual/chapter23":1164672846,"/doc/manual/chapter22":1164672846,"/doc/manual/chapter21":1164672846,"/doc/manual/chapter20":1164672846,"items":([({"chapter 1","chapter one","1",}):"\"Introduction to the Coding Environment\" ",({"chapter 11","chapter eleven","11",}):"\"Complex Data Types\" ",({"chapter 21","chapter twenty-one","21",}):"\"Meals\" ",({"chapter 27","chapter twenty-seven","27",}):"\"Towns\" ",({"chapter 7","chapter seven","7",}):"\"Flow Control\" ",({"chapter 37","chapter thirty-seven","37",}):"\"QCS: Modifying things and stuff\" ",({"chapter 10","chapter ten","10",}):"\"The LPMud Driver\" ",({"chapter 36","chapter thirty-six","36",}):"\"QCS: Modifying weapons\" ",({"chapter 26","chapter twenty-six","26",}):"\"Sentients\" ",({"chapter 30","chapter thirty","30",}):"\"The Natural Language Parser\" ",({"chapter 34","chapter thirty-four","34",}):"\"QCS: Modification of NPC's\" ",({"chapter 37","chapter thirty-seven","37",}):"\"QCS: Modifying things and stuff\" ",({"chapter 10","chapter ten","10",}):"\"The LPMud Driver\" ",({"chapter 29","chapter twenty-nine","29",}):"\"Weapons\" ",({"chapter 40","chapter forty","40",}):"\"Useful Creator Commands\" ",({"chapter 39","chapter thirty-nine","39",}):"\"QCS: Final notes\" ",({"chapter 18","chapter eighteen","18",}):"\"Valid climates\" ",({"chapter 8","chapter eight","8",}):"\"LPC Basics\" ",({"chapter 2","chapter two","2",}):"\"The LPC Program\" ",({"chapter 17","chapter seventeen","17",}):"\"Barkeeps\" ",({"chapter 4","chapter four","4",}):"\"Functions\" ",({"chapter 17","chapter seventeen","17",}):"\"Barkeeps\" ",({"chapter 4","chapter four","4",}):"\"Functions\" ",({"chapter 26","chapter twenty-six","26",}):"\"Sentients\" ",({"chapter 24","chapter twenty-four","24",}):"\"Quests\" ",({"chapter 23","chapter twenty-three","23",}):"\"Properties\" ",({"chapter 8","chapter eight","8",}):"\"LPC Basics\" ",({"chapter 18","chapter eighteen","18",}):"\"Valid climates\" ",({"chapter 2","chapter two","2",}):"\"The LPC Program\" ",({"chapter 28","chapter twenty-eight","28",}):"\"Vendors\" ",({"chapter 16","chapter sixteen","16",}):"\"Armor\" ",({"chapter 33","chapter thirty-three","33",}):"\"QCS: Creation\" ",({"chapter 18","chapter eighteen","18",}):"\"Valid climates\" ",({"chapter 5","chapter five","5",}):"\"The Basics of Inheritance\" ",({"chapter 23","chapter twenty-three","23",}):"\"Properties\" ",({"chapter 31","chapter thirty-one","31",}):"\"Overview of the Quick Creation System\" ",({"chapter 27","chapter twenty-seven","27",}):"\"Towns\" ",({"chapter 3","chapter three","3",}):"\"LPC Data Types\" ",({"chapter 28","chapter twenty-eight","28",}):"\"Vendors\" ",({"chapter 26","chapter twenty-six","26",}):"\"Sentients\" ",({"chapter 17","chapter seventeen","17",}):"\"Barkeeps\" ",({"chapter 14","chapter fourteen","14",}):"\"Intermediate Inheritance\" ",({"chapter 22","chapter twenty-two","22",}):"\"NPCs\" ",({"chapter 38","chapter thirty-eight","38",}):"\"QCS: Adding and deleting\" ",({"chapter 19","chapter nineteen","19",}):"\"Doors\" ",({"chapter 32","chapter thirty-two","32",}):"\"QCS: Commands\" ",({"chapter 14","chapter fourteen","14",}):"\"Intermediate Inheritance\" ",({"chapter 7","chapter seven","7",}):"\"Flow Control\" ",({"chapter 20","chapter twenty","20",}):"\"Items\" ",({"chapter 10","chapter ten","10",}):"\"The LPMud Driver\" ",({"chapter 1","chapter one","1",}):"\"Introduction to the Coding Environment\" ",({"chapter 7","chapter seven","7",}):"\"Flow Control\" ",({"chapter 20","chapter twenty","20",}):"\"Items\" ",({"chapter 32","chapter thirty-two","32",}):"\"QCS: Commands\" ",({"chapter 6","chapter six","6",}):"\"Variable Handling\" ",({"chapter 22","chapter twenty-two","22",}):"\"NPCs\" ",({"chapter 15","chapter fifteen","15",}):"\"Debugging\" ",({"chapter 31","chapter thirty-one","31",}):"\"Overview of the Quick Creation System\" ",({"chapter 13","chapter thirteen","13",}):"\"Advanced String Handling\" ",({"chapter 15","chapter fifteen","15",}):"\"Debugging\" ",({"chapter 30","chapter thirty","30",}):"\"The Natural Language Parser\" ",({"chapter 29","chapter twenty-nine","29",}):"\"Weapons\" ",({"chapter 22","chapter twenty-two","22",}):"\"NPCs\" ",({"chapter 16","chapter sixteen","16",}):"\"Armor\" ",({"chapter 39","chapter thirty-nine","39",}):"\"QCS: Final notes\" ",({"chapter 13","chapter thirteen","13",}):"\"Advanced String Handling\" ",({"chapter 33","chapter thirty-three","33",}):"\"QCS: Creation\" ",({"chapter 24","chapter twenty-four","24",}):"\"Quests\" ",({"chapter 40","chapter forty","40",}):"\"Useful Creator Commands\" ",({"chapter 13","chapter thirteen","13",}):"\"Advanced String Handling\" ",({"chapter 19","chapter nineteen","19",}):"\"Doors\" ",({"chapter 37","chapter thirty-seven","37",}):"\"QCS: Modifying things and stuff\" ",({"chapter 12","chapter twelve","12",}):"\"The LPC Pre-Compiler\" ",({"chapter 25","chapter twenty-five","25",}):"\"Rooms\" ",({"chapter 34","chapter thirty-four","34",}):"\"QCS: Modification of NPC's\" ",({"chapter 40","chapter forty","40",}):"\"Useful Creator Commands\" ",({"chapter 6","chapter six","6",}):"\"Variable Handling\" ",({"chapter 8","chapter eight","8",}):"\"LPC Basics\" ",({"chapter 11","chapter eleven","11",}):"\"Complex Data Types\" ",({"chapter 33","chapter thirty-three","33",}):"\"QCS: Creation\" ",({"chapter 38","chapter thirty-eight","38",}):"\"QCS: Adding and deleting\" ",({"chapter 35","chapter thirty-five","35",}):"\"QCS: Modifying rooms\" ",({"chapter 35","chapter thirty-five","35",}):"\"QCS: Modifying rooms\" ",({"chapter 25","chapter twenty-five","25",}):"\"Rooms\" ",({"chapter 6","chapter six","6",}):"\"Variable Handling\" ",({"chapter 30","chapter thirty","30",}):"\"The Natural Language Parser\" ",({"chapter 5","chapter five","5",}):"\"The Basics of Inheritance\" ",({"chapter 19","chapter nineteen","19",}):"\"Doors\" ",({"chapter 15","chapter fifteen","15",}):"\"Debugging\" ",({"chapter 12","chapter twelve","12",}):"\"The LPC Pre-Compiler\" ",({"chapter 2","chapter two","2",}):"\"The LPC Program\" ",({"chapter 25","chapter twenty-five","25",}):"\"Rooms\" ",({"chapter 32","chapter thirty-two","32",}):"\"QCS: Commands\" ",({"chapter 9","chapter nine","9",}):"\"Introduction to Intermediate LPC\" ",({"chapter 36","chapter thirty-six","36",}):"\"QCS: Modifying weapons\" ",({"chapter 14","chapter fourteen","14",}):"\"Intermediate Inheritance\" ",({"chapter 23","chapter twenty-three","23",}):"\"Properties\" ",({"chapter 3","chapter three","3",}):"\"LPC Data Types\" ",({"chapter 36","chapter thirty-six","36",}):"\"QCS: Modifying weapons\" ",({"chapter 11","chapter eleven","11",}):"\"Complex Data Types\" ",({"chapter 31","chapter thirty-one","31",}):"\"Overview of the Quick Creation System\" ",({"chapter 39","chapter thirty-nine","39",}):"\"QCS: Final notes\" ",({"chapter 4","chapter four","4",}):"\"Functions\" ",({"chapter 21","chapter twenty-one","21",}):"\"Meals\" ",({"chapter 1","chapter one","1",}):"\"Introduction to the Coding Environment\" ",({"chapter 34","chapter thirty-four","34",}):"\"QCS: Modification of NPC's\" ",({"chapter 9","chapter nine","9",}):"\"Introduction to Intermediate LPC\" ",({"chapter 29","chapter twenty-nine","29",}):"\"Weapons\" ",({"chapter 3","chapter three","3",}):"\"LPC Data Types\" ",({"chapter 28","chapter twenty-eight","28",}):"\"Vendors\" ",({"chapter 9","chapter nine","9",}):"\"Introduction to Intermediate LPC\" ",({"chapter 12","chapter twelve","12",}):"\"The LPC Pre-Compiler\" ",({"chapter 27","chapter twenty-seven","27",}):"\"Towns\" ",({"chapter 20","chapter twenty","20",}):"\"Items\" ",({"chapter 35","chapter thirty-five","35",}):"\"QCS: Modifying rooms\" ",({"chapter 21","chapter twenty-one","21",}):"\"Meals\" ",({"chapter 5","chapter five","5",}):"\"The Basics of Inheritance\" ",({"chapter 16","chapter sixteen","16",}):"\"Armor\" ",({"chapter 24","chapter twenty-four","24",}):"\"Quests\" ",({"chapter 38","chapter thirty-eight","38",}):"\"QCS: Adding and deleting\" ",]),"/doc/manual/chapter09":1164672846,"/doc/manual/chapter08":1204520744,"/doc/manual/chapter07":1164672846,"/doc/manual/chapter06":1164672846,"/doc/manual/chapter05":1164672846,"/doc/manual/chapter04":1164672846,"/doc/manual/chapter03":1164672846,"/doc/manual/chapter02":1164672846,"/doc/manual/chapter01":1164672846,]),"/doc/guide":(["object":"/domains/default/obj/guide","title":"Administrator's Guidebook","items":([({"chapter 8","chapter eight","8",}):"\"Understanding the Lib\" ",({"chapter 4","chapter four","4",}):"\"Gaining Experience\" ",({"chapter 3","chapter three","3",}):"\"Getting Started\" ",({"chapter 5","chapter five","5",}):"\"Guilds, Classes, and Clans\" ",({"chapter 5","chapter five","5",}):"\"Guilds, Classes, and Clans\" ",({"chapter 2","chapter two","2",}):"\"The Vision Thing\" ",({"chapter 2","chapter two","2",}):"\"The Vision Thing\" ",({"chapter 3","chapter three","3",}):"\"Getting Started\" ",({"chapter 6","chapter six","6",}):"\"Privacy\" ",({"chapter 7","chapter seven","7",}):"\"Advanced Topics\" ",({"chapter 1","chapter one","1",}):"\"Introduction\" ",({"chapter 9","chapter nine","9",}):"\"The Future\" ",({"chapter 6","chapter six","6",}):"\"Privacy\" ",({"chapter 8","chapter eight","8",}):"\"Understanding the Lib\" ",({"chapter 4","chapter four","4",}):"\"Gaining Experience\" ",({"chapter 7","chapter seven","7",}):"\"Advanced Topics\" ",({"chapter 9","chapter nine","9",}):"\"The Future\" ",({"chapter 5","chapter five","5",}):"\"Guilds, Classes, and Clans\" ",({"chapter 7","chapter seven","7",}):"\"Advanced Topics\" ",({"chapter 1","chapter one","1",}):"\"Introduction\" ",({"chapter 6","chapter six","6",}):"\"Privacy\" ",({"chapter 1","chapter one","1",}):"\"Introduction\" ",({"chapter 3","chapter three","3",}):"\"Getting Started\" ",({"chapter 4","chapter four","4",}):"\"Gaining Experience\" ",({"chapter 2","chapter two","2",}):"\"The Vision Thing\" ",({"chapter 9","chapter nine","9",}):"\"The Future\" ",({"chapter 8","chapter eight","8",}):"\"Understanding the Lib\" ",]),"/doc/guide/chapter09":1164672846,"/doc/guide/chapter08":1177376334,"/doc/guide/chapter07":1164672846,"/doc/guide/chapter06":1164672846,"/doc/guide/chapter05":1164672846,"/doc/guide/chapter04":1164672846,"index":" Administrator's Guidebook Chapter 1: \"Introduction\" Chapter 2: \"The Vision Thing\" Chapter 3: \"Getting Started\" Chapter 4: \"Gaining Experience\" Chapter 5: \"Guilds, Classes, and Clans\" Chapter 6: \"Privacy\" Chapter 7: \"Advanced Topics\" Chapter 8: \"Understanding the Lib\" Chapter 9: \"The Future\" ","/doc/guide/chapter03":1164672846,"reads":([({"chapter 2","chapter two","2",}):"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. ",({"chapter 1","chapter one","1",}):"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. ",({"chapter 7","chapter seven","7",}):"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? ",({"chapter 2","chapter two","2",}):"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. ",({"chapter 3","chapter three","3",}):"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. ",({"chapter 4","chapter four","4",}):"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.\" ",({"chapter 8","chapter eight","8",}):"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 VI: 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. ",({"chapter 9","chapter nine","9",}):"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. ",({"chapter 6","chapter six","6",}):"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. ",({"chapter 1","chapter one","1",}):"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. ",({"chapter 6","chapter six","6",}):"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. ",({"chapter 3","chapter three","3",}):"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. ",({"chapter 7","chapter seven","7",}):"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? ",({"chapter 9","chapter nine","9",}):"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. ",({"chapter 8","chapter eight","8",}):"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 VI: 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. ",({"chapter 4","chapter four","4",}):"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.\" ",({"chapter 5","chapter five","5",}):"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. ",({"chapter 8","chapter eight","8",}):"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 VI: 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. ",({"chapter 7","chapter seven","7",}):"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? ",({"chapter 2","chapter two","2",}):"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. ",({"chapter 9","chapter nine","9",}):"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. ",({"chapter 1","chapter one","1",}):"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. ",({"chapter 5","chapter five","5",}):"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. ",({"chapter 3","chapter three","3",}):"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. ",({"chapter 6","chapter six","6",}):"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. ",({"chapter 5","chapter five","5",}):"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. ",({"chapter 4","chapter four","4",}):"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.\" ",]),"/doc/guide/chapter02":1164672846,"/doc/guide/chapter01":1164672846,]),"/doc/phints":(["object":"/domains/default/obj/phints","title":"Untitled","items":([({"chapter 4","chapter four","4",}):"\"The Town Well\" ",({"chapter 2","chapter two","2",}):"\"Post-Mansion Hints\" ",({"chapter 1","chapter one","1",}):"\"Getting started: The Newbie Mansion\" ",({"chapter 5","chapter five","5",}):"\"The Orcslayer\" ",({"chapter 4","chapter four","4",}):"\"The Town Well\" ",({"chapter 2","chapter two","2",}):"\"Post-Mansion Hints\" ",({"chapter 3","chapter three","3",}):"\"Teleportation Devices\" ",({"chapter 1","chapter one","1",}):"\"Getting started: The Newbie Mansion\" ",({"chapter 2","chapter two","2",}):"\"Post-Mansion Hints\" ",({"chapter 1","chapter one","1",}):"\"Getting started: The Newbie Mansion\" ",({"chapter 4","chapter four","4",}):"\"The Town Well\" ",({"chapter 3","chapter three","3",}):"\"Teleportation Devices\" ",({"chapter 3","chapter three","3",}):"\"Teleportation Devices\" ",({"chapter 5","chapter five","5",}):"\"The Orcslayer\" ",({"chapter 5","chapter five","5",}):"\"The Orcslayer\" ",]),"/doc/phints/chapter05":1236662936,"/doc/phints/chapter04":1238277470,"index":" Untitled Chapter 1: \"Getting started: The Newbie Mansion\" Chapter 2: \"Post-Mansion Hints\" Chapter 3: \"Teleportation Devices\" Chapter 4: \"The Town Well\" Chapter 5: \"The Orcslayer\" ","/doc/phints/chapter03":1236662936,"reads":([({"chapter 5","chapter five","5",}):"chapter 5 \"The Orcslayer\" You're getting spoiled, aren't you? You're achieving dizzying heights of player leveling in no time, and learning tons about how to fight, move, and operate in the Dead Souls environment. Well, sorry to say, we are close to the end of your free ride. The orcslayer quest is the last one you get a full walkthrough on. After this, you'll need to apply the lessons you've learned from this hint book to whatever other quests and adventures your mud features. Before we really get started...do you remember what you did with that bear costume? I ask because orcs are known to be quite deferential to bears. Keep that in mind, if your player race is not \"orc\". Now, Leo the Archwizard misplaced his precious magical sword, Orcslayer. Leo is in the basement of the village church (1w, 1n of the clocktower) waiting for you to help him find it. Little does he know that some juvenile orcs, trying to prove their mettle, stole it and have given it to their wanna-be shaman in their improvised lair (4w, 1sw, 1w, 1n, 1w of the clocktower). There are a few ways you can handle the orcs between you and the shaman. If you decide to do it the hard way, let me remind you that Herkimer can sometimes teach you some spells even if you are not a mage. In particular the buffer spell can pro +++ ATH0 NO CARRIER ",({"chapter 5","chapter five","5",}):"chapter 5 \"The Orcslayer\" You're getting spoiled, aren't you? You're achieving dizzying heights of player leveling in no time, and learning tons about how to fight, move, and operate in the Dead Souls environment. Well, sorry to say, we are close to the end of your free ride. The orcslayer quest is the last one you get a full walkthrough on. After this, you'll need to apply the lessons you've learned from this hint book to whatever other quests and adventures your mud features. Before we really get started...do you remember what you did with that bear costume? I ask because orcs are known to be quite deferential to bears. Keep that in mind, if your player race is not \"orc\". Now, Leo the Archwizard misplaced his precious magical sword, Orcslayer. Leo is in the basement of the village church (1w, 1n of the clocktower) waiting for you to help him find it. Little does he know that some juvenile orcs, trying to prove their mettle, stole it and have given it to their wanna-be shaman in their improvised lair (4w, 1sw, 1w, 1n, 1w of the clocktower). There are a few ways you can handle the orcs between you and the shaman. If you decide to do it the hard way, let me remind you that Herkimer can sometimes teach you some spells even if you are not a mage. In particular the buffer spell can pro +++ ATH0 NO CARRIER ",({"chapter 4","chapter four","4",}):"chapter 4 \"The Town Well\" Ok, so you're now all set with a bunch of money in the bank, light-but-decent equipment, and a thirst for more advancement. Let's try a quest that requires a little fancy footwork and little (if any) fighting. I'm going to assume that the portal gun portals are where the default distribution puts them. The blue portal in the hazlab, the orange portal...well, you'll see. By now you should have Kleiner's badge. If not, go back to where I describe how to get it. If you sold it, go buy it back. Also, get yourself a flashlight. I recommend maglite, but whatever you can find is better than nothing. Now go back to Jennybot. Near her is a stairwell that leads to the campus basement. Turn on your flashlight then go 1n, 1w, 1s, 1d, 1w of Jennybot. You're now in the western end of the campus basement. Note the smudged wall? %^GREEN%^push wall%^RESET%^ Whee! Go west until you can't go any further, then go 1s. Lying there is a key you'll need. Put it in your ruck, then go north til you can't go north any further. Note that the next couple of things you need to do must be done quickly. You're about to enter a dangerous sewer service area, and you may get blasted with harmful steam if you hang around too long. Go down into the sewer area. See that pile of crap? Search it. Bonus! Now go east twice, up, open grate, up. You're now back up on the cobblestone road, but with a shiny new ring to wear or sell, and a key you'll need. Head to the hazlab (4s, 1w, 1s). Now, just in case some joker put the orange portal somewhere dangerous, you should have an omni handy (you can buy one from Oana). Enter the blue portal. Unless someone's been playing around, you should now be in an underground tunnel, with a large metal door to the west. There's not much to explore here...if you follow the tunnel north and east, you'll find a locked gate with a cave troll on the other side. What you really want to do is get past the door to the west. You got the key to this door from the campus underground, so go ahead and unlock it. Now comes the hard part...open the door. Chances are that you can't. It's huge and it's heavy...it requires having a strength stat of at least 50 to open. You have 2 possible ways of dealing with this...one is expensive, the other a bit tricky. The expensive way is to buy strength potions from Oana and drink them until your strength is above 49, then rush back to this door before the potions wear off, and open the door. Like I said, expensive. The other way is to control something that is strong enough to open the door. Go back to kleiner, then type: %^GREEN%^dial stargate lab%^RESET%^ This takes you to a secret area used by creators to test their npc's, armor, and equipment. Go north, then east. If you're lucky, nobody has taken the landstrider mech for a joyride and it's standing there, waiting for you. Type: %^GREEN%^enter mech%^RESET%^ You are now inside your very own mech-type robot you control. Cool! Have it go back to the stargate: %^GREEN%^drive west%^RESET%^ %^GREEN%^drive south%^RESET%^ %^GREEN%^direct mech to dial campus lab%^RESET%^ %^GREEN%^direct mech to enter gate%^RESET%^ %^GREEN%^drive south%^RESET%^ %^GREEN%^drive south%^RESET%^ Uh oh! The mech can't enter the hazlab because it's not carrying Kleiner's badge! What you need to do is drop the badge. It will then be in the mech's inventory, so that the security door can see it. %^GREEN%^drop badge%^RESET%^ %^GREEN%^drive south%^RESET%^ Now we have the mech enter the portal and open the door for you. %^GREEN%^direct mech to enter portal%^RESET%^ %^GREEN%^direct mech to open door%^RESET%^ Excellent! Now, the next part involves making this area kind of hostile for general use, so let's get the mech out of harm's way %^GREEN%^get badge%^RESET%^ %^GREEN%^wear badge%^RESET%^ %^GREEN%^direct mech to enter portal%^RESET%^ %^GREEN%^out%^RESET%^ Now go back in the portal (just you, without the mech), and go west twice. This is the source of the problem. The town well is dry because someone shut off the water source! To restore water to the well, turn the metal wheel here, and water will start rushing out of the pipe at high pressure. There's a grate-type door overhead through which the water is supposed to flow up to the bottom of the well. If the orange portal hadn't been there, you'd have had to do the alternate solution, which involves accessing the water source from that other direction. Now, as you can imagine, this area is going to fill up with water very rapidly, so leave east right away. The entire series of tunnels will flood, so get back to the orange portal and enter it quickly. %^RED%^PROTIP:%^RESET%^ The water will also go through the locked cavetroll gate. And cavetrolls don't breathe water. Now, go to the town well (1n, 1e, 5n of the hazlab), and: %^GREEN%^enter well%^RESET%^ Hopefully you did get the maglite. By now the weaker flashlights may have pooped out. See the lever on the wall? That operates a set of two doors that serve as a waterlock for the well. Pull it, and a door will open, letting water flood into the well, and solving the quest! It may be that someone has already been fooling with the water lock, though. If the door was already open when you got there, push the lever, wait a few minutes for water to flood the lock, then pull the lever. It could take a while depending on the water pressure for the lock to fill up, so if it's dry, close it again and wait a while before opening again. %^CYAN%^Alternate Resolution%^RESET%^ It may be that the orange portal was not in the water tunnel. It could be that the hazardous materials labs was not accessible to you. If that is the case, you'll need to solve this quest by accessing the water source from the direction of the well. This is tricky because you need to be very strong to open the grate, *and* you need an extra set of hands to operate the water lock lever. Let's deal with one problem at a time. First, the strength issue. On the other side of the water lock is a grate that you must have at least 50 strength to open. If your strength is already above 49, great. If not, you need to decide whether you want to boost it with strength potions from Oana (expensive) or use the landstrider mech (tricky). If the plan is to use strength potions, go buy them now and stick them in your ruck. If the plan is to use the mech, go get it. Go to Kleiner, and: %^GREEN%^dial stargate lab%^RESET%^ %^GREEN%^enter gate%^RESET%^ %^GREEN%^go north%^RESET%^ %^GREEN%^go east%^RESET%^ %^GREEN%^enter mech%^RESET%^ %^GREEN%^drive west%^RESET%^ %^GREEN%^drive south%^RESET%^ %^GREEN%^direct mech to dial campus lab%^RESET%^ %^GREEN%^direct mech to enter gate%^RESET%^ %^GREEN%^drive south%^RESET%^ %^GREEN%^drive east%^RESET%^ %^GREEN%^drive north%^RESET%^ %^GREEN%^drive north%^RESET%^ %^GREEN%^drive north%^RESET%^ %^GREEN%^drive north%^RESET%^ %^GREEN%^drive north%^RESET%^ %^GREEN%^direct mech to enter well%^RESET%^ %^GREEN%^direct mech to pull lever%^RESET%^ %^GREEN%^drive west%^RESET%^ %^GREEN%^out%^RESET%^ %^GREEN%^go east%^RESET%^ The mech is now in the water lock. But neither you nor the mech can proceed further west...you need someone to pull the lever for you. You're going to need a servant...a slave...a ZOMBIE! Go up and west, and buy a dark scroll from Oana. The scroll can be used to raise a corpse, but you must be able to read English. If you've chosen a race that doesn't speak English, you'll need to learn it now. Go to Bugg (1n, 2e, 1n of the well) and ask him to teach you English. Once you've learned it, you'll be ready to create a zombie. From Bugg, go to the campus square (1s, 2w, 5s) and murder Tim. It's important that you slay something that speaks a language you know, so since you're either human or just now learned English, a human victim is suitable. Plus Tim is a wuss. Once he's slain: %^GREEN%^read scroll at tim%^RESET%^ There he is! Your very own zombie! We'll need to move quickly now. Zombies don't last forever...the clock is ticking. Do the following to get him to follow you: %^GREEN%^speak in english%^RESET%^ %^GREEN%^say follow cratylus%^RESET%^ Except, of course, instead of \"cratylus\", put in your own name. Note something important here. Zombies are obedient, but not smart. If someone else starts saying things that the zombie understands as a command, it will start obeying them. So remember that while you created this zombie, someone else can steal him if you're not careful. Now, return to the well (4n) then enter the well and go west. You'll need to tell the zombie to leave the water lock and operate it: %^GREEN%^say go east%^RESET%^ %^GREEN%^yell push lever%^RESET%^ %^GREEN%^enter mech%^RESET%^ %^GREEN%^drive west%^RESET%^ %^GREEN%^direct mech to open grate%^RESET%^ Woohoo! If you don't have the mech, of course, you just walk your own self west, drink your strength potions, and open the grate yourself. If you *do* have the mech, let's get it out of harm's way... %^GREEN%^drive east%^RESET%^ %^GREEN%^out%^RESET%^ %^GREEN%^go west%^RESET%^ All righty, now let's go resolve this well problem. Go down and you'll see the metal wheel and the water pipe. To get the water flowing again, turn the wheel. Then very quickly get yourself back to the water lock...the area will fill with water soon! When water gets to the lock: %^GREEN%^yell pull lever%^RESET%^ Your zombie will then open the east door, allowing you and the water to get to the well, and solving the Town Well Quest. Congratulations! ",({"chapter 3","chapter three","3",}):"chapter 3 \"Teleportation Devices\" Let's talk a little about how to use some of the teleportation technology in the default Dead Souls distribution. Some of this stuff can save your hide, and some of it can kill you, so it's worth being aware of it. %^CYAN%^Visitor's Pass%^RESET%^ This is an extremely rare item, and only intended for official test characters. If you don't show up in the \"who\" list with a [%^YELLOW%^TEST%^RESET%^] tag, and you have a visitor's pass, something has gone wrong. You use the pass to get out of trouble with the command: %^GREEN%^click heels%^RESET%^ %^CYAN%^omni%^RESET%^ The omni is a device created by a consortium of time travelers dedicated to fixing errors in history. While they'd never make the full chrono-omni available for public consuption, a \"gimped\" version can be purchased from Oana at the magic shop. This omni does not do time travel, and when you press the button on it, it will only take you to one location: Lars's Pub. However, it is an incredibly valuable tool of recall when you find yourself in a tight spot. For example, suppose you are an orc or a dwarf, and you cannot swim, but you walked off the village shore and are now drowning and sinking to the sea floor. If you have an omni in your rucksack, you can: %^GREEN%^get omi from ruck%^RESET%^ %^GREEN%^push button on omni%^RESET%^ And materialize, gasping but alive, in the old tavern. It's a must-have for any adventurer. I suggest aliasing those commands, so you can hit the buttons quickly in panic-mode. See: %^GREEN%^help alias%^RESET%^ %^RED%^PROTIP:%^RESET%^ The omni is programmed not to be in the possession of a living being for very long. If you keep it in your inventory too long, it will glow red and disappear. You can limit this by keeping it in your ruck. %^CYAN%^Kleiner's omni%^RESET%^ Kleiner, brilliant scientist he is, has been tinkering with his omni and disabled the auto-vanish feature for himself on it. He also has been able to reprogram his omni to take him to different places. However, you really don't want this omni. Only Kleiner can control where it takes him. For anyone else, it takes them to a completely random location on the mud, and believe me when I tell you this is not really as fun as it sounds. %^CYAN%^Stargates%^RESET%^ Ancient technology of a long-lost civilization, stargates permit travel to and from each other. You dial a specific stargate you want to go to, then enter the stargate. Note that if the destination stargate is already in use the dialing process may fail. Stargates stay open for only a brief time, though, so unless your mud is super busy, you can probably just retry the dialing and find success. Note that stargates can take you to places whose environment is unsuitable to you. If you dial a stargate that is on the sea floor or one that is in outer space, you'd best be wearing a breathing device or be carrying an omni with you. Of course, if on your mud someone has coded a stargate whose destination is next to a sun going nova, or in a nest of gundarks, the breathing device may provide insufficient protection %^CYAN%^Portal gun%^RESET%^ If it has both blue and orange vials installed, this device allows you to create portals (one blue, one orange) that connect to each other. Entering the blue portal will take you to the location of the orange portal, and vice versa. Only one blue portal may exist in the game at any time...the creation of a new one destroys the old one. This is also true of the orange portal. Portal locations persist through reboots. By default, the blue vial is found along with the portal gun, in the hazlab. The orange vial is rather trickier to obtain...it is kept in the private storage area of an incredibly powerful and aggressive cave troll. You can create a blue portal wherever you want if you have the blue vial installed, but without the orange vial you cannot change the location of the orange portal. %^RED%^Protip:%^RESET%^ Do not ever enter a portal if the other portal is in the same room. ",({"chapter 4","chapter four","4",}):"chapter 4 \"The Town Well\" Ok, so you're now all set with a bunch of money in the bank, light-but-decent equipment, and a thirst for more advancement. Let's try a quest that requires a little fancy footwork and little (if any) fighting. I'm going to assume that the portal gun portals are where the default distribution puts them. The blue portal in the hazlab, the orange portal...well, you'll see. By now you should have Kleiner's badge. If not, go back to where I describe how to get it. If you sold it, go buy it back. Also, get yourself a flashlight. I recommend maglite, but whatever you can find is better than nothing. Now go back to Jennybot. Near her is a stairwell that leads to the campus basement. Turn on your flashlight then go 1n, 1w, 1s, 1d, 1w of Jennybot. You're now in the western end of the campus basement. Note the smudged wall? %^GREEN%^push wall%^RESET%^ Whee! Go west until you can't go any further, then go 1s. Lying there is a key you'll need. Put it in your ruck, then go north til you can't go north any further. Note that the next couple of things you need to do must be done quickly. You're about to enter a dangerous sewer service area, and you may get blasted with harmful steam if you hang around too long. Go down into the sewer area. See that pile of crap? Search it. Bonus! Now go east twice, up, open grate, up. You're now back up on the cobblestone road, but with a shiny new ring to wear or sell, and a key you'll need. Head to the hazlab (4s, 1w, 1s). Now, just in case some joker put the orange portal somewhere dangerous, you should have an omni handy (you can buy one from Oana). Enter the blue portal. Unless someone's been playing around, you should now be in an underground tunnel, with a large metal door to the west. There's not much to explore here...if you follow the tunnel north and east, you'll find a locked gate with a cave troll on the other side. What you really want to do is get past the door to the west. You got the key to this door from the campus underground, so go ahead and unlock it. Now comes the hard part...open the door. Chances are that you can't. It's huge and it's heavy...it requires having a strength stat of at least 50 to open. You have 2 possible ways of dealing with this...one is expensive, the other a bit tricky. The expensive way is to buy strength potions from Oana and drink them until your strength is above 49, then rush back to this door before the potions wear off, and open the door. Like I said, expensive. The other way is to control something that is strong enough to open the door. Go back to kleiner, then type: %^GREEN%^dial stargate lab%^RESET%^ This takes you to a secret area used by creators to test their npc's, armor, and equipment. Go north, then east. If you're lucky, nobody has taken the landstrider mech for a joyride and it's standing there, waiting for you. Type: %^GREEN%^enter mech%^RESET%^ You are now inside your very own mech-type robot you control. Cool! Have it go back to the stargate: %^GREEN%^drive west%^RESET%^ %^GREEN%^drive south%^RESET%^ %^GREEN%^direct mech to dial campus lab%^RESET%^ %^GREEN%^direct mech to enter gate%^RESET%^ %^GREEN%^drive south%^RESET%^ %^GREEN%^drive south%^RESET%^ Uh oh! The mech can't enter the hazlab because it's not carrying Kleiner's badge! What you need to do is drop the badge. It will then be in the mech's inventory, so that the security door can see it. %^GREEN%^drop badge%^RESET%^ %^GREEN%^drive south%^RESET%^ Now we have the mech enter the portal and open the door for you. %^GREEN%^direct mech to enter portal%^RESET%^ %^GREEN%^direct mech to open door%^RESET%^ Excellent! Now, the next part involves making this area kind of hostile for general use, so let's get the mech out of harm's way %^GREEN%^get badge%^RESET%^ %^GREEN%^wear badge%^RESET%^ %^GREEN%^direct mech to enter portal%^RESET%^ %^GREEN%^out%^RESET%^ Now go back in the portal (just you, without the mech), and go west twice. This is the source of the problem. The town well is dry because someone shut off the water source! To restore water to the well, turn the metal wheel here, and water will start rushing out of the pipe at high pressure. There's a grate-type door overhead through which the water is supposed to flow up to the bottom of the well. If the orange portal hadn't been there, you'd have had to do the alternate solution, which involves accessing the water source from that other direction. Now, as you can imagine, this area is going to fill up with water very rapidly, so leave east right away. The entire series of tunnels will flood, so get back to the orange portal and enter it quickly. %^RED%^PROTIP:%^RESET%^ The water will also go through the locked cavetroll gate. And cavetrolls don't breathe water. Now, go to the town well (1n, 1e, 5n of the hazlab), and: %^GREEN%^enter well%^RESET%^ Hopefully you did get the maglite. By now the weaker flashlights may have pooped out. See the lever on the wall? That operates a set of two doors that serve as a waterlock for the well. Pull it, and a door will open, letting water flood into the well, and solving the quest! It may be that someone has already been fooling with the water lock, though. If the door was already open when you got there, push the lever, wait a few minutes for water to flood the lock, then pull the lever. It could take a while depending on the water pressure for the lock to fill up, so if it's dry, close it again and wait a while before opening again. %^CYAN%^Alternate Resolution%^RESET%^ It may be that the orange portal was not in the water tunnel. It could be that the hazardous materials labs was not accessible to you. If that is the case, you'll need to solve this quest by accessing the water source from the direction of the well. This is tricky because you need to be very strong to open the grate, *and* you need an extra set of hands to operate the water lock lever. Let's deal with one problem at a time. First, the strength issue. On the other side of the water lock is a grate that you must have at least 50 strength to open. If your strength is already above 49, great. If not, you need to decide whether you want to boost it with strength potions from Oana (expensive) or use the landstrider mech (tricky). If the plan is to use strength potions, go buy them now and stick them in your ruck. If the plan is to use the mech, go get it. Go to Kleiner, and: %^GREEN%^dial stargate lab%^RESET%^ %^GREEN%^enter gate%^RESET%^ %^GREEN%^go north%^RESET%^ %^GREEN%^go east%^RESET%^ %^GREEN%^enter mech%^RESET%^ %^GREEN%^drive west%^RESET%^ %^GREEN%^drive south%^RESET%^ %^GREEN%^direct mech to dial campus lab%^RESET%^ %^GREEN%^direct mech to enter gate%^RESET%^ %^GREEN%^drive south%^RESET%^ %^GREEN%^drive east%^RESET%^ %^GREEN%^drive north%^RESET%^ %^GREEN%^drive north%^RESET%^ %^GREEN%^drive north%^RESET%^ %^GREEN%^drive north%^RESET%^ %^GREEN%^drive north%^RESET%^ %^GREEN%^direct mech to enter well%^RESET%^ %^GREEN%^direct mech to pull lever%^RESET%^ %^GREEN%^drive west%^RESET%^ %^GREEN%^out%^RESET%^ %^GREEN%^go east%^RESET%^ The mech is now in the water lock. But neither you nor the mech can proceed further west...you need someone to pull the lever for you. You're going to need a servant...a slave...a ZOMBIE! Go up and west, and buy a dark scroll from Oana. The scroll can be used to raise a corpse, but you must be able to read English. If you've chosen a race that doesn't speak English, you'll need to learn it now. Go to Bugg (1n, 2e, 1n of the well) and ask him to teach you English. Once you've learned it, you'll be ready to create a zombie. From Bugg, go to the campus square (1s, 2w, 5s) and murder Tim. It's important that you slay something that speaks a language you know, so since you're either human or just now learned English, a human victim is suitable. Plus Tim is a wuss. Once he's slain: %^GREEN%^read scroll at tim%^RESET%^ There he is! Your very own zombie! We'll need to move quickly now. Zombies don't last forever...the clock is ticking. Do the following to get him to follow you: %^GREEN%^speak in english%^RESET%^ %^GREEN%^say follow cratylus%^RESET%^ Except, of course, instead of \"cratylus\", put in your own name. Note something important here. Zombies are obedient, but not smart. If someone else starts saying things that the zombie understands as a command, it will start obeying them. So remember that while you created this zombie, someone else can steal him if you're not careful. Now, return to the well (4n) then enter the well and go west. You'll need to tell the zombie to leave the water lock and operate it: %^GREEN%^say go east%^RESET%^ %^GREEN%^yell push lever%^RESET%^ %^GREEN%^enter mech%^RESET%^ %^GREEN%^drive west%^RESET%^ %^GREEN%^direct mech to open grate%^RESET%^ Woohoo! If you don't have the mech, of course, you just walk your own self west, drink your strength potions, and open the grate yourself. If you *do* have the mech, let's get it out of harm's way... %^GREEN%^drive east%^RESET%^ %^GREEN%^out%^RESET%^ %^GREEN%^go west%^RESET%^ All righty, now let's go resolve this well problem. Go down and you'll see the metal wheel and the water pipe. To get the water flowing again, turn the wheel. Then very quickly get yourself back to the water lock...the area will fill with water soon! When water gets to the lock: %^GREEN%^yell pull lever%^RESET%^ Your zombie will then open the east door, allowing you and the water to get to the well, and solving the Town Well Quest. Congratulations! ",({"chapter 1","chapter one","1",}):"chapter 1 \"Getting started: The Newbie Mansion\" You understand the basics. You've read the player's handbook (you read that, right?), you now understand stats and skills, you've customized your stats, and you're ready to play. This chapter will now give you a walkthrough of the first quest a newbie should perform. It is a *complete* walkthrough! It is a SPOILER. If you don't want the quest spoiled, stop reading now! I'm going to assume your mud does not allow picking your class at char creation, or that the class you picked is \"explorer\". This is to simplify the walkthrough. This also assumes you've just created this char and it is level 1. We'll start in the reception room, with Jennybot (5 south, 3 east, 1 south, of the village clocktower). If you haven't done so already, this might be a good time to: %^GREEN%^activate bot%^RESET%^ What she says is kind of boring if you're not new to muds. But hang around until she gives you the baseball cap. It's worth some money. %^RED%^PROTIP%^RESET%^: If she has already given you a cap before, you won't get a new one. Once you get the cap, go 1n, 3w, 5n, 1e, 1n. This is the village shop. Remove and drop your worthless t-shirt and jeans, and sell the cap to otik: %^GREEN%^sell cap to otik%^RESET%^ Sell any other crap you've picked up along the way. The newbie mansion will have all the equipment you'll need to solve it. But keep this hint book handy! Now it's time to open a bank account. Believe me, you do not want to be carrying around all your money if you die. So let's go open an account and put our hard-earned cash somewhere safe: 1s, 1w, 3n, 1e. %^GREEN%^request account from zoe%^RESET%^ %^GREEN%^deposit all%^RESET%^ Good! I feel safer already! Now let's head to the mansion. From the bank it is: 1w, 3s, 2w, 2s. If you're still at newbie levels, the mansion guard won't notice you slip by. You're now in front of the mansion, but how to get in? The door is locked! Pay close attention to the description...did you notice that the mansion is described as having an open second story window? Go to the gardener's shack (1w, 1n) and get the ladder. Return to the front of the mansion (1s, 1e) and: %^GREEN%^drop ladder%^RESET%^ %^GREEN%^climb ladder%^RESET%^ You're in! You're now standing in the second floor hallway of the newbie mansion. Time to get equipped. Go east into the guest room, open the overnight bag, and get and wear the following: leather jacket, leather pants, helmet, shirt, and gloves. This is relatively decent newbie armor that still lets you gather loot because it's not too heavy. %^RED%^PROTIP:%^RESET%^ You can do stuff to more than one item at a time, and when you do, worn items are ignored. Try: %^GREEN%^open overnight bag%^RESET%^ %^GREEN%^get all from overnight bag%^RESET%^ %^GREEN%^wear all%^RESET%^ %^GREEN%^drop all%^RESET%^ Did you notice that you only dropped the things you were not wearing? Now, go to the master bedroom (1w, 3s), open the wardrobe and get the boots from the wardrobe and wear them. These are long boots and are better than the boots in the guest room. These boots also protect your legs. Leave the rest of the stuff in the wardrobe alone for now...you can loot the mansion after you complete the quest. Next, let's get you a weapon. Go downstairs, just outside the kitchen (1n, 1d, 1n). The kitchen will be east. Do this, very quickly: %^GREEN%^go east%^RESET%^ %^GREEN%^get carving knife from rack%^RESET%^ %^GREEN%^go west%^RESET%^ Ignore the kitchen rats...kill them later if you want, for now let's save up your strength for the mansion boss...and he's next! Before we go on, though, let me ask you...did you get both knives from the rack? No! just the carving knife! You see, only fighters are skilled at using two weapons at once. As an explorer, if you try to wield two weapons at once, you will do very very badly in combat. The carving knife is an excellent weapon. Just wield that, and drop the butcher knife. Now go north and east...and meet your first quest boss. Yes, the soggy thief! He's snuck into the mansion while the master was away, and made himself at home! He won't like your presence and will attack you, but he's really quite wimpy. Just stand your ground and you'll defeat him with no effort. Finished? Aren't you sad now? No? Good. There's plenty of slaying to do in this game, if you're getting sentimental over killing a burglar while wearing his armor (that you stole) then this just might not be the game for you. Now, take his stuff and look around. See anything that piques your curiosity? %^GREEN%^get all from corpse%^RESET%^ %^GREEN%^look%^RESET%^ Maybe the rug is valuable... %^GREEN%^exa rug%^RESET%^ %^GREEN%^get rug%^RESET%^ Weird! What if we... %^GREEN%^move rug%^RESET%^ Well what do you know! Open that trap door, go down into the secret chamber, and you'll have solved your first Dead Souls quest. Congratulations! You'll be awarded quest and experience points, and if your mud is set to auto-advance, you'll probably gain a level or two. If not, you can visit Dirk and ask him to advance (Dirk is 1e, 1s of the village clocktower). There's a bunch of loot in the chest in the secret chamber, as well as a bag with money (don't just sell the bag, \"get all from bag\" first!). You can now focus on robbing the mansion blind and selling everything you steal. With the money, you can start buying expensive equipment you need for the more challenging quests. %^RED%^Loot tip 1:%^RESET%^ Go back to the master bedroom and move the bed. Surprise! Enter the passageway and unlock the safe with the complex key you took from the thief. Inside the safe you'll find stuff you will want to keep, not sell. Trust me on that. Don't sell that stuff. %^RED%^Loot tip 2:%^RESET%^ Search the room across the hall from the guest room you looted. %^RED%^Loot tip 3:%^RESET%^ Whether you sell or keep it, remember where the bear costume is. It could come in handy later. %^RED%^Loot tip 4:%^RESET%^ Sell stuff to Kim if you can, rather than Otik. Otik pays with silver, which is heavy. Kim pays with dollars, which are light. Sadly, Kim will not buy or sell weapons, but for everything else, her light currency is very convenient. You can always exchange currencies at the bank. Kim's bookstore is 1n, 2e, 1n of Jennybot. %^RED%^Loot tip 5:%^RESET%^ If you advanced automatically, you might find that the mansion guard no longer lets you past him any more...and you can't get rid of him. Strategies for dealing with the gate guard are discussed later. ",({"chapter 2","chapter two","2",}):"chapter 2 \"Post-Mansion Hints\" So you're flush with joy at having solved your first quest, and now you're loaded with money and loot! Woo! But...oh no... there's so much loot left in the mansion, and the gate gard won't let you pass because you're not a newbie anymore. Bummer! Well, we're going to fix that, but first, let's get organized. You're carrying a bunch of stuff, some of which you want to keep, some of which you want to sell, and it's going to get tiresome soon, having to sort through your inventory all the time at shops. So the first thing we're going to do is buy a rucksack. Why? Remember when you tried to \"drop all\" and the only things you didn't drop were the things you were wearing? A rucksack gives you somewhere to keep a bunch of stuff, and you *wear* the rucksack. Meaning that \"drop all\" and \"sell all\" will ignore the valuable stuff you keep in your rucksack, if you're wearing it. Neat, huh? It makes life much easier when selling tons of loot. So, let's go to Otik (from the gate guard, 1n, 3e, 1n), and buy the rucksack. Try: %^GREEN%^buy ruck from otik%^RESET%^ If you dont have enough money, sell some of the junk you got from the mansion. It also could be that you *do* have enough money, but not in silver. If this is the case, go to zoe and do a currency exchange: %^GREEN%^exchange 5 gold for silver%^RESET%^ Note that you can only exchange money in your possession. Zoe does not exchange money while it is deposited. Once you have your rucksack, wear it, open it, and put in it the stuff you want to keep. I suggest putting the grenade, the pistol, and the slips in there. Now sell the junk you don't want, deposit the excess cash with Zoe, and let's get ready to deal with the gate guard. The problem: A guard you cannot kill, preventing passage. The solution: Find a way around, or through him. Now, you might be tempted to use the grenade. You *could* pull the pin on the grenade, drop it, leave, wait a few seconds, and come back...and the guard *might* be dead. But this is a magical guard. Even if he dies, his spirit prevents you from getting past. And he will regenerate into a new body within seconds. So... what to do? There are two solutions, and both of them require... SCIENCE! Go to Zoe and withdraw 110 dollars or so (darn fees), then go to the bookstore (1w, 8s, 5e, 1n), and buy the lab coat from Kim. Now go to the campus stargate lab (1s, 5w, 1s, 1w, 1n), where Kleiner is busy working on exotechnology, as usual. In typical egghead fashion, Kleiner is too preoccupied with his experiments to help you, but he wants *your* help. He's lost his lab coat, you see. Like so many geniuses, Kleiner is somewhat physically clumsy, and if he wears a lab coat you give him, he's liable to drop his identification badge. This badge gives its carrier access to the \"hazardous technologies\" lab two rooms south of Kleiner. %^RED%^PROTIP%^RESET%^: Do not attempt to kill Kleiner. He is carrying a teleportation device called an omni which he will use the moment he receives harm from someone. Attacking Kleiner just means he and his ID badge will teleport to some random location, and you'll be up the creek. %^RED%^PROTIP%^RESET%^: In the hazardous materials lab, DO NOT attempt to harm the tripod gun turret. Failure to heed this warning will result in catastrophic injury to anyone in the room. On the hazlab workbench you'll find various items of interest. For now we'll concentrate on the Yautja wrist computer, the Yautja data module, and the rocket pack. The rocket pack is the simplest tool for circumventing the gate guard. Wear it, and head back to the guard (1n, 1e, 6n, 2w, 1s). Now use the pack to fly over the guard: %^GREEN%^activate pack%^RESET%^ %^GREEN%^boost up%^RESET%^ %^GREEN%^boost south%^RESET%^ %^GREEN%^boost down%^RESET%^ %^GREEN%^deactivate pack%^RESET%^ How do ya like that! Remember to deactivate the pack, too. If you leave it running, it'll eventually run out of fuel. Don't get too crazy flying around with it, either. You're extremely likely to boost yourself out over the ocean if you're not careful, and wind up lost and drowning. Also, if you run out of fuel while up in the air, you *will* fall and the damage you'll receive will be grievous. So let's be very careful in our use of the rocket pack. Another way to get past the guard is by having him not see you at all. The Yautja technology can help you in this: %^GREEN%^wear wristcomp%^RESET%^ %^GREEN%^open wristcomp%^RESET%^ %^GREEN%^activate wristcomp%^RESET%^ %^GREEN%^install module in wristcomp%^RESET%^ %^GREEN%^close wristcomp%^RESET%^ %^GREEN%^cloak%^RESET%^ %^GREEN%^go south%^RESET%^ %^GREEN%^decloak%^RESET%^ It is crucially important that you are cloaked only as long as necessary. If you walk around while cloaked, it will sap your stamina extremely quickly. Note that it is a peculiarity of Yautja technology that it's a bit awkward to use. If you remove the wristcomp, it deactivates, and you'll need to wear it, activate it again, uninstall the module, and install it again. Those Yautja hunters always do things the hard way, I'll tellya. You now have the tools you need to successfully steal every ounce of worth from the newbie mansion regardless of your newbie status. Congratulations...I guess. ",({"chapter 3","chapter three","3",}):"chapter 3 \"Teleportation Devices\" Let's talk a little about how to use some of the teleportation technology in the default Dead Souls distribution. Some of this stuff can save your hide, and some of it can kill you, so it's worth being aware of it. %^CYAN%^Visitor's Pass%^RESET%^ This is an extremely rare item, and only intended for official test characters. If you don't show up in the \"who\" list with a [%^YELLOW%^TEST%^RESET%^] tag, and you have a visitor's pass, something has gone wrong. You use the pass to get out of trouble with the command: %^GREEN%^click heels%^RESET%^ %^CYAN%^omni%^RESET%^ The omni is a device created by a consortium of time travelers dedicated to fixing errors in history. While they'd never make the full chrono-omni available for public consuption, a \"gimped\" version can be purchased from Oana at the magic shop. This omni does not do time travel, and when you press the button on it, it will only take you to one location: Lars's Pub. However, it is an incredibly valuable tool of recall when you find yourself in a tight spot. For example, suppose you are an orc or a dwarf, and you cannot swim, but you walked off the village shore and are now drowning and sinking to the sea floor. If you have an omni in your rucksack, you can: %^GREEN%^get omi from ruck%^RESET%^ %^GREEN%^push button on omni%^RESET%^ And materialize, gasping but alive, in the old tavern. It's a must-have for any adventurer. I suggest aliasing those commands, so you can hit the buttons quickly in panic-mode. See: %^GREEN%^help alias%^RESET%^ %^RED%^PROTIP:%^RESET%^ The omni is programmed not to be in the possession of a living being for very long. If you keep it in your inventory too long, it will glow red and disappear. You can limit this by keeping it in your ruck. %^CYAN%^Kleiner's omni%^RESET%^ Kleiner, brilliant scientist he is, has been tinkering with his omni and disabled the auto-vanish feature for himself on it. He also has been able to reprogram his omni to take him to different places. However, you really don't want this omni. Only Kleiner can control where it takes him. For anyone else, it takes them to a completely random location on the mud, and believe me when I tell you this is not really as fun as it sounds. %^CYAN%^Stargates%^RESET%^ Ancient technology of a long-lost civilization, stargates permit travel to and from each other. You dial a specific stargate you want to go to, then enter the stargate. Note that if the destination stargate is already in use the dialing process may fail. Stargates stay open for only a brief time, though, so unless your mud is super busy, you can probably just retry the dialing and find success. Note that stargates can take you to places whose environment is unsuitable to you. If you dial a stargate that is on the sea floor or one that is in outer space, you'd best be wearing a breathing device or be carrying an omni with you. Of course, if on your mud someone has coded a stargate whose destination is next to a sun going nova, or in a nest of gundarks, the breathing device may provide insufficient protection %^CYAN%^Portal gun%^RESET%^ If it has both blue and orange vials installed, this device allows you to create portals (one blue, one orange) that connect to each other. Entering the blue portal will take you to the location of the orange portal, and vice versa. Only one blue portal may exist in the game at any time...the creation of a new one destroys the old one. This is also true of the orange portal. Portal locations persist through reboots. By default, the blue vial is found along with the portal gun, in the hazlab. The orange vial is rather trickier to obtain...it is kept in the private storage area of an incredibly powerful and aggressive cave troll. You can create a blue portal wherever you want if you have the blue vial installed, but without the orange vial you cannot change the location of the orange portal. %^RED%^Protip:%^RESET%^ Do not ever enter a portal if the other portal is in the same room. ",({"chapter 5","chapter five","5",}):"chapter 5 \"The Orcslayer\" You're getting spoiled, aren't you? You're achieving dizzying heights of player leveling in no time, and learning tons about how to fight, move, and operate in the Dead Souls environment. Well, sorry to say, we are close to the end of your free ride. The orcslayer quest is the last one you get a full walkthrough on. After this, you'll need to apply the lessons you've learned from this hint book to whatever other quests and adventures your mud features. Before we really get started...do you remember what you did with that bear costume? I ask because orcs are known to be quite deferential to bears. Keep that in mind, if your player race is not \"orc\". Now, Leo the Archwizard misplaced his precious magical sword, Orcslayer. Leo is in the basement of the village church (1w, 1n of the clocktower) waiting for you to help him find it. Little does he know that some juvenile orcs, trying to prove their mettle, stole it and have given it to their wanna-be shaman in their improvised lair (4w, 1sw, 1w, 1n, 1w of the clocktower). There are a few ways you can handle the orcs between you and the shaman. If you decide to do it the hard way, let me remind you that Herkimer can sometimes teach you some spells even if you are not a mage. In particular the buffer spell can pro +++ ATH0 NO CARRIER ",({"chapter 1","chapter one","1",}):"chapter 1 \"Getting started: The Newbie Mansion\" You understand the basics. You've read the player's handbook (you read that, right?), you now understand stats and skills, you've customized your stats, and you're ready to play. This chapter will now give you a walkthrough of the first quest a newbie should perform. It is a *complete* walkthrough! It is a SPOILER. If you don't want the quest spoiled, stop reading now! I'm going to assume your mud does not allow picking your class at char creation, or that the class you picked is \"explorer\". This is to simplify the walkthrough. This also assumes you've just created this char and it is level 1. We'll start in the reception room, with Jennybot (5 south, 3 east, 1 south, of the village clocktower). If you haven't done so already, this might be a good time to: %^GREEN%^activate bot%^RESET%^ What she says is kind of boring if you're not new to muds. But hang around until she gives you the baseball cap. It's worth some money. %^RED%^PROTIP%^RESET%^: If she has already given you a cap before, you won't get a new one. Once you get the cap, go 1n, 3w, 5n, 1e, 1n. This is the village shop. Remove and drop your worthless t-shirt and jeans, and sell the cap to otik: %^GREEN%^sell cap to otik%^RESET%^ Sell any other crap you've picked up along the way. The newbie mansion will have all the equipment you'll need to solve it. But keep this hint book handy! Now it's time to open a bank account. Believe me, you do not want to be carrying around all your money if you die. So let's go open an account and put our hard-earned cash somewhere safe: 1s, 1w, 3n, 1e. %^GREEN%^request account from zoe%^RESET%^ %^GREEN%^deposit all%^RESET%^ Good! I feel safer already! Now let's head to the mansion. From the bank it is: 1w, 3s, 2w, 2s. If you're still at newbie levels, the mansion guard won't notice you slip by. You're now in front of the mansion, but how to get in? The door is locked! Pay close attention to the description...did you notice that the mansion is described as having an open second story window? Go to the gardener's shack (1w, 1n) and get the ladder. Return to the front of the mansion (1s, 1e) and: %^GREEN%^drop ladder%^RESET%^ %^GREEN%^climb ladder%^RESET%^ You're in! You're now standing in the second floor hallway of the newbie mansion. Time to get equipped. Go east into the guest room, open the overnight bag, and get and wear the following: leather jacket, leather pants, helmet, shirt, and gloves. This is relatively decent newbie armor that still lets you gather loot because it's not too heavy. %^RED%^PROTIP:%^RESET%^ You can do stuff to more than one item at a time, and when you do, worn items are ignored. Try: %^GREEN%^open overnight bag%^RESET%^ %^GREEN%^get all from overnight bag%^RESET%^ %^GREEN%^wear all%^RESET%^ %^GREEN%^drop all%^RESET%^ Did you notice that you only dropped the things you were not wearing? Now, go to the master bedroom (1w, 3s), open the wardrobe and get the boots from the wardrobe and wear them. These are long boots and are better than the boots in the guest room. These boots also protect your legs. Leave the rest of the stuff in the wardrobe alone for now...you can loot the mansion after you complete the quest. Next, let's get you a weapon. Go downstairs, just outside the kitchen (1n, 1d, 1n). The kitchen will be east. Do this, very quickly: %^GREEN%^go east%^RESET%^ %^GREEN%^get carving knife from rack%^RESET%^ %^GREEN%^go west%^RESET%^ Ignore the kitchen rats...kill them later if you want, for now let's save up your strength for the mansion boss...and he's next! Before we go on, though, let me ask you...did you get both knives from the rack? No! just the carving knife! You see, only fighters are skilled at using two weapons at once. As an explorer, if you try to wield two weapons at once, you will do very very badly in combat. The carving knife is an excellent weapon. Just wield that, and drop the butcher knife. Now go north and east...and meet your first quest boss. Yes, the soggy thief! He's snuck into the mansion while the master was away, and made himself at home! He won't like your presence and will attack you, but he's really quite wimpy. Just stand your ground and you'll defeat him with no effort. Finished? Aren't you sad now? No? Good. There's plenty of slaying to do in this game, if you're getting sentimental over killing a burglar while wearing his armor (that you stole) then this just might not be the game for you. Now, take his stuff and look around. See anything that piques your curiosity? %^GREEN%^get all from corpse%^RESET%^ %^GREEN%^look%^RESET%^ Maybe the rug is valuable... %^GREEN%^exa rug%^RESET%^ %^GREEN%^get rug%^RESET%^ Weird! What if we... %^GREEN%^move rug%^RESET%^ Well what do you know! Open that trap door, go down into the secret chamber, and you'll have solved your first Dead Souls quest. Congratulations! You'll be awarded quest and experience points, and if your mud is set to auto-advance, you'll probably gain a level or two. If not, you can visit Dirk and ask him to advance (Dirk is 1e, 1s of the village clocktower). There's a bunch of loot in the chest in the secret chamber, as well as a bag with money (don't just sell the bag, \"get all from bag\" first!). You can now focus on robbing the mansion blind and selling everything you steal. With the money, you can start buying expensive equipment you need for the more challenging quests. %^RED%^Loot tip 1:%^RESET%^ Go back to the master bedroom and move the bed. Surprise! Enter the passageway and unlock the safe with the complex key you took from the thief. Inside the safe you'll find stuff you will want to keep, not sell. Trust me on that. Don't sell that stuff. %^RED%^Loot tip 2:%^RESET%^ Search the room across the hall from the guest room you looted. %^RED%^Loot tip 3:%^RESET%^ Whether you sell or keep it, remember where the bear costume is. It could come in handy later. %^RED%^Loot tip 4:%^RESET%^ Sell stuff to Kim if you can, rather than Otik. Otik pays with silver, which is heavy. Kim pays with dollars, which are light. Sadly, Kim will not buy or sell weapons, but for everything else, her light currency is very convenient. You can always exchange currencies at the bank. Kim's bookstore is 1n, 2e, 1n of Jennybot. %^RED%^Loot tip 5:%^RESET%^ If you advanced automatically, you might find that the mansion guard no longer lets you past him any more...and you can't get rid of him. Strategies for dealing with the gate guard are discussed later. ",({"chapter 2","chapter two","2",}):"chapter 2 \"Post-Mansion Hints\" So you're flush with joy at having solved your first quest, and now you're loaded with money and loot! Woo! But...oh no... there's so much loot left in the mansion, and the gate gard won't let you pass because you're not a newbie anymore. Bummer! Well, we're going to fix that, but first, let's get organized. You're carrying a bunch of stuff, some of which you want to keep, some of which you want to sell, and it's going to get tiresome soon, having to sort through your inventory all the time at shops. So the first thing we're going to do is buy a rucksack. Why? Remember when you tried to \"drop all\" and the only things you didn't drop were the things you were wearing? A rucksack gives you somewhere to keep a bunch of stuff, and you *wear* the rucksack. Meaning that \"drop all\" and \"sell all\" will ignore the valuable stuff you keep in your rucksack, if you're wearing it. Neat, huh? It makes life much easier when selling tons of loot. So, let's go to Otik (from the gate guard, 1n, 3e, 1n), and buy the rucksack. Try: %^GREEN%^buy ruck from otik%^RESET%^ If you dont have enough money, sell some of the junk you got from the mansion. It also could be that you *do* have enough money, but not in silver. If this is the case, go to zoe and do a currency exchange: %^GREEN%^exchange 5 gold for silver%^RESET%^ Note that you can only exchange money in your possession. Zoe does not exchange money while it is deposited. Once you have your rucksack, wear it, open it, and put in it the stuff you want to keep. I suggest putting the grenade, the pistol, and the slips in there. Now sell the junk you don't want, deposit the excess cash with Zoe, and let's get ready to deal with the gate guard. The problem: A guard you cannot kill, preventing passage. The solution: Find a way around, or through him. Now, you might be tempted to use the grenade. You *could* pull the pin on the grenade, drop it, leave, wait a few seconds, and come back...and the guard *might* be dead. But this is a magical guard. Even if he dies, his spirit prevents you from getting past. And he will regenerate into a new body within seconds. So... what to do? There are two solutions, and both of them require... SCIENCE! Go to Zoe and withdraw 110 dollars or so (darn fees), then go to the bookstore (1w, 8s, 5e, 1n), and buy the lab coat from Kim. Now go to the campus stargate lab (1s, 5w, 1s, 1w, 1n), where Kleiner is busy working on exotechnology, as usual. In typical egghead fashion, Kleiner is too preoccupied with his experiments to help you, but he wants *your* help. He's lost his lab coat, you see. Like so many geniuses, Kleiner is somewhat physically clumsy, and if he wears a lab coat you give him, he's liable to drop his identification badge. This badge gives its carrier access to the \"hazardous technologies\" lab two rooms south of Kleiner. %^RED%^PROTIP%^RESET%^: Do not attempt to kill Kleiner. He is carrying a teleportation device called an omni which he will use the moment he receives harm from someone. Attacking Kleiner just means he and his ID badge will teleport to some random location, and you'll be up the creek. %^RED%^PROTIP%^RESET%^: In the hazardous materials lab, DO NOT attempt to harm the tripod gun turret. Failure to heed this warning will result in catastrophic injury to anyone in the room. On the hazlab workbench you'll find various items of interest. For now we'll concentrate on the Yautja wrist computer, the Yautja data module, and the rocket pack. The rocket pack is the simplest tool for circumventing the gate guard. Wear it, and head back to the guard (1n, 1e, 6n, 2w, 1s). Now use the pack to fly over the guard: %^GREEN%^activate pack%^RESET%^ %^GREEN%^boost up%^RESET%^ %^GREEN%^boost south%^RESET%^ %^GREEN%^boost down%^RESET%^ %^GREEN%^deactivate pack%^RESET%^ How do ya like that! Remember to deactivate the pack, too. If you leave it running, it'll eventually run out of fuel. Don't get too crazy flying around with it, either. You're extremely likely to boost yourself out over the ocean if you're not careful, and wind up lost and drowning. Also, if you run out of fuel while up in the air, you *will* fall and the damage you'll receive will be grievous. So let's be very careful in our use of the rocket pack. Another way to get past the guard is by having him not see you at all. The Yautja technology can help you in this: %^GREEN%^wear wristcomp%^RESET%^ %^GREEN%^open wristcomp%^RESET%^ %^GREEN%^activate wristcomp%^RESET%^ %^GREEN%^install module in wristcomp%^RESET%^ %^GREEN%^close wristcomp%^RESET%^ %^GREEN%^cloak%^RESET%^ %^GREEN%^go south%^RESET%^ %^GREEN%^decloak%^RESET%^ It is crucially important that you are cloaked only as long as necessary. If you walk around while cloaked, it will sap your stamina extremely quickly. Note that it is a peculiarity of Yautja technology that it's a bit awkward to use. If you remove the wristcomp, it deactivates, and you'll need to wear it, activate it again, uninstall the module, and install it again. Those Yautja hunters always do things the hard way, I'll tellya. You now have the tools you need to successfully steal every ounce of worth from the newbie mansion regardless of your newbie status. Congratulations...I guess. ",({"chapter 3","chapter three","3",}):"chapter 3 \"Teleportation Devices\" Let's talk a little about how to use some of the teleportation technology in the default Dead Souls distribution. Some of this stuff can save your hide, and some of it can kill you, so it's worth being aware of it. %^CYAN%^Visitor's Pass%^RESET%^ This is an extremely rare item, and only intended for official test characters. If you don't show up in the \"who\" list with a [%^YELLOW%^TEST%^RESET%^] tag, and you have a visitor's pass, something has gone wrong. You use the pass to get out of trouble with the command: %^GREEN%^click heels%^RESET%^ %^CYAN%^omni%^RESET%^ The omni is a device created by a consortium of time travelers dedicated to fixing errors in history. While they'd never make the full chrono-omni available for public consuption, a \"gimped\" version can be purchased from Oana at the magic shop. This omni does not do time travel, and when you press the button on it, it will only take you to one location: Lars's Pub. However, it is an incredibly valuable tool of recall when you find yourself in a tight spot. For example, suppose you are an orc or a dwarf, and you cannot swim, but you walked off the village shore and are now drowning and sinking to the sea floor. If you have an omni in your rucksack, you can: %^GREEN%^get omi from ruck%^RESET%^ %^GREEN%^push button on omni%^RESET%^ And materialize, gasping but alive, in the old tavern. It's a must-have for any adventurer. I suggest aliasing those commands, so you can hit the buttons quickly in panic-mode. See: %^GREEN%^help alias%^RESET%^ %^RED%^PROTIP:%^RESET%^ The omni is programmed not to be in the possession of a living being for very long. If you keep it in your inventory too long, it will glow red and disappear. You can limit this by keeping it in your ruck. %^CYAN%^Kleiner's omni%^RESET%^ Kleiner, brilliant scientist he is, has been tinkering with his omni and disabled the auto-vanish feature for himself on it. He also has been able to reprogram his omni to take him to different places. However, you really don't want this omni. Only Kleiner can control where it takes him. For anyone else, it takes them to a completely random location on the mud, and believe me when I tell you this is not really as fun as it sounds. %^CYAN%^Stargates%^RESET%^ Ancient technology of a long-lost civilization, stargates permit travel to and from each other. You dial a specific stargate you want to go to, then enter the stargate. Note that if the destination stargate is already in use the dialing process may fail. Stargates stay open for only a brief time, though, so unless your mud is super busy, you can probably just retry the dialing and find success. Note that stargates can take you to places whose environment is unsuitable to you. If you dial a stargate that is on the sea floor or one that is in outer space, you'd best be wearing a breathing device or be carrying an omni with you. Of course, if on your mud someone has coded a stargate whose destination is next to a sun going nova, or in a nest of gundarks, the breathing device may provide insufficient protection %^CYAN%^Portal gun%^RESET%^ If it has both blue and orange vials installed, this device allows you to create portals (one blue, one orange) that connect to each other. Entering the blue portal will take you to the location of the orange portal, and vice versa. Only one blue portal may exist in the game at any time...the creation of a new one destroys the old one. This is also true of the orange portal. Portal locations persist through reboots. By default, the blue vial is found along with the portal gun, in the hazlab. The orange vial is rather trickier to obtain...it is kept in the private storage area of an incredibly powerful and aggressive cave troll. You can create a blue portal wherever you want if you have the blue vial installed, but without the orange vial you cannot change the location of the orange portal. %^RED%^Protip:%^RESET%^ Do not ever enter a portal if the other portal is in the same room. ",({"chapter 1","chapter one","1",}):"chapter 1 \"Getting started: The Newbie Mansion\" You understand the basics. You've read the player's handbook (you read that, right?), you now understand stats and skills, you've customized your stats, and you're ready to play. This chapter will now give you a walkthrough of the first quest a newbie should perform. It is a *complete* walkthrough! It is a SPOILER. If you don't want the quest spoiled, stop reading now! I'm going to assume your mud does not allow picking your class at char creation, or that the class you picked is \"explorer\". This is to simplify the walkthrough. This also assumes you've just created this char and it is level 1. We'll start in the reception room, with Jennybot (5 south, 3 east, 1 south, of the village clocktower). If you haven't done so already, this might be a good time to: %^GREEN%^activate bot%^RESET%^ What she says is kind of boring if you're not new to muds. But hang around until she gives you the baseball cap. It's worth some money. %^RED%^PROTIP%^RESET%^: If she has already given you a cap before, you won't get a new one. Once you get the cap, go 1n, 3w, 5n, 1e, 1n. This is the village shop. Remove and drop your worthless t-shirt and jeans, and sell the cap to otik: %^GREEN%^sell cap to otik%^RESET%^ Sell any other crap you've picked up along the way. The newbie mansion will have all the equipment you'll need to solve it. But keep this hint book handy! Now it's time to open a bank account. Believe me, you do not want to be carrying around all your money if you die. So let's go open an account and put our hard-earned cash somewhere safe: 1s, 1w, 3n, 1e. %^GREEN%^request account from zoe%^RESET%^ %^GREEN%^deposit all%^RESET%^ Good! I feel safer already! Now let's head to the mansion. From the bank it is: 1w, 3s, 2w, 2s. If you're still at newbie levels, the mansion guard won't notice you slip by. You're now in front of the mansion, but how to get in? The door is locked! Pay close attention to the description...did you notice that the mansion is described as having an open second story window? Go to the gardener's shack (1w, 1n) and get the ladder. Return to the front of the mansion (1s, 1e) and: %^GREEN%^drop ladder%^RESET%^ %^GREEN%^climb ladder%^RESET%^ You're in! You're now standing in the second floor hallway of the newbie mansion. Time to get equipped. Go east into the guest room, open the overnight bag, and get and wear the following: leather jacket, leather pants, helmet, shirt, and gloves. This is relatively decent newbie armor that still lets you gather loot because it's not too heavy. %^RED%^PROTIP:%^RESET%^ You can do stuff to more than one item at a time, and when you do, worn items are ignored. Try: %^GREEN%^open overnight bag%^RESET%^ %^GREEN%^get all from overnight bag%^RESET%^ %^GREEN%^wear all%^RESET%^ %^GREEN%^drop all%^RESET%^ Did you notice that you only dropped the things you were not wearing? Now, go to the master bedroom (1w, 3s), open the wardrobe and get the boots from the wardrobe and wear them. These are long boots and are better than the boots in the guest room. These boots also protect your legs. Leave the rest of the stuff in the wardrobe alone for now...you can loot the mansion after you complete the quest. Next, let's get you a weapon. Go downstairs, just outside the kitchen (1n, 1d, 1n). The kitchen will be east. Do this, very quickly: %^GREEN%^go east%^RESET%^ %^GREEN%^get carving knife from rack%^RESET%^ %^GREEN%^go west%^RESET%^ Ignore the kitchen rats...kill them later if you want, for now let's save up your strength for the mansion boss...and he's next! Before we go on, though, let me ask you...did you get both knives from the rack? No! just the carving knife! You see, only fighters are skilled at using two weapons at once. As an explorer, if you try to wield two weapons at once, you will do very very badly in combat. The carving knife is an excellent weapon. Just wield that, and drop the butcher knife. Now go north and east...and meet your first quest boss. Yes, the soggy thief! He's snuck into the mansion while the master was away, and made himself at home! He won't like your presence and will attack you, but he's really quite wimpy. Just stand your ground and you'll defeat him with no effort. Finished? Aren't you sad now? No? Good. There's plenty of slaying to do in this game, if you're getting sentimental over killing a burglar while wearing his armor (that you stole) then this just might not be the game for you. Now, take his stuff and look around. See anything that piques your curiosity? %^GREEN%^get all from corpse%^RESET%^ %^GREEN%^look%^RESET%^ Maybe the rug is valuable... %^GREEN%^exa rug%^RESET%^ %^GREEN%^get rug%^RESET%^ Weird! What if we... %^GREEN%^move rug%^RESET%^ Well what do you know! Open that trap door, go down into the secret chamber, and you'll have solved your first Dead Souls quest. Congratulations! You'll be awarded quest and experience points, and if your mud is set to auto-advance, you'll probably gain a level or two. If not, you can visit Dirk and ask him to advance (Dirk is 1e, 1s of the village clocktower). There's a bunch of loot in the chest in the secret chamber, as well as a bag with money (don't just sell the bag, \"get all from bag\" first!). You can now focus on robbing the mansion blind and selling everything you steal. With the money, you can start buying expensive equipment you need for the more challenging quests. %^RED%^Loot tip 1:%^RESET%^ Go back to the master bedroom and move the bed. Surprise! Enter the passageway and unlock the safe with the complex key you took from the thief. Inside the safe you'll find stuff you will want to keep, not sell. Trust me on that. Don't sell that stuff. %^RED%^Loot tip 2:%^RESET%^ Search the room across the hall from the guest room you looted. %^RED%^Loot tip 3:%^RESET%^ Whether you sell or keep it, remember where the bear costume is. It could come in handy later. %^RED%^Loot tip 4:%^RESET%^ Sell stuff to Kim if you can, rather than Otik. Otik pays with silver, which is heavy. Kim pays with dollars, which are light. Sadly, Kim will not buy or sell weapons, but for everything else, her light currency is very convenient. You can always exchange currencies at the bank. Kim's bookstore is 1n, 2e, 1n of Jennybot. %^RED%^Loot tip 5:%^RESET%^ If you advanced automatically, you might find that the mansion guard no longer lets you past him any more...and you can't get rid of him. Strategies for dealing with the gate guard are discussed later. ",({"chapter 4","chapter four","4",}):"chapter 4 \"The Town Well\" Ok, so you're now all set with a bunch of money in the bank, light-but-decent equipment, and a thirst for more advancement. Let's try a quest that requires a little fancy footwork and little (if any) fighting. I'm going to assume that the portal gun portals are where the default distribution puts them. The blue portal in the hazlab, the orange portal...well, you'll see. By now you should have Kleiner's badge. If not, go back to where I describe how to get it. If you sold it, go buy it back. Also, get yourself a flashlight. I recommend maglite, but whatever you can find is better than nothing. Now go back to Jennybot. Near her is a stairwell that leads to the campus basement. Turn on your flashlight then go 1n, 1w, 1s, 1d, 1w of Jennybot. You're now in the western end of the campus basement. Note the smudged wall? %^GREEN%^push wall%^RESET%^ Whee! Go west until you can't go any further, then go 1s. Lying there is a key you'll need. Put it in your ruck, then go north til you can't go north any further. Note that the next couple of things you need to do must be done quickly. You're about to enter a dangerous sewer service area, and you may get blasted with harmful steam if you hang around too long. Go down into the sewer area. See that pile of crap? Search it. Bonus! Now go east twice, up, open grate, up. You're now back up on the cobblestone road, but with a shiny new ring to wear or sell, and a key you'll need. Head to the hazlab (4s, 1w, 1s). Now, just in case some joker put the orange portal somewhere dangerous, you should have an omni handy (you can buy one from Oana). Enter the blue portal. Unless someone's been playing around, you should now be in an underground tunnel, with a large metal door to the west. There's not much to explore here...if you follow the tunnel north and east, you'll find a locked gate with a cave troll on the other side. What you really want to do is get past the door to the west. You got the key to this door from the campus underground, so go ahead and unlock it. Now comes the hard part...open the door. Chances are that you can't. It's huge and it's heavy...it requires having a strength stat of at least 50 to open. You have 2 possible ways of dealing with this...one is expensive, the other a bit tricky. The expensive way is to buy strength potions from Oana and drink them until your strength is above 49, then rush back to this door before the potions wear off, and open the door. Like I said, expensive. The other way is to control something that is strong enough to open the door. Go back to kleiner, then type: %^GREEN%^dial stargate lab%^RESET%^ This takes you to a secret area used by creators to test their npc's, armor, and equipment. Go north, then east. If you're lucky, nobody has taken the landstrider mech for a joyride and it's standing there, waiting for you. Type: %^GREEN%^enter mech%^RESET%^ You are now inside your very own mech-type robot you control. Cool! Have it go back to the stargate: %^GREEN%^drive west%^RESET%^ %^GREEN%^drive south%^RESET%^ %^GREEN%^direct mech to dial campus lab%^RESET%^ %^GREEN%^direct mech to enter gate%^RESET%^ %^GREEN%^drive south%^RESET%^ %^GREEN%^drive south%^RESET%^ Uh oh! The mech can't enter the hazlab because it's not carrying Kleiner's badge! What you need to do is drop the badge. It will then be in the mech's inventory, so that the security door can see it. %^GREEN%^drop badge%^RESET%^ %^GREEN%^drive south%^RESET%^ Now we have the mech enter the portal and open the door for you. %^GREEN%^direct mech to enter portal%^RESET%^ %^GREEN%^direct mech to open door%^RESET%^ Excellent! Now, the next part involves making this area kind of hostile for general use, so let's get the mech out of harm's way %^GREEN%^get badge%^RESET%^ %^GREEN%^wear badge%^RESET%^ %^GREEN%^direct mech to enter portal%^RESET%^ %^GREEN%^out%^RESET%^ Now go back in the portal (just you, without the mech), and go west twice. This is the source of the problem. The town well is dry because someone shut off the water source! To restore water to the well, turn the metal wheel here, and water will start rushing out of the pipe at high pressure. There's a grate-type door overhead through which the water is supposed to flow up to the bottom of the well. If the orange portal hadn't been there, you'd have had to do the alternate solution, which involves accessing the water source from that other direction. Now, as you can imagine, this area is going to fill up with water very rapidly, so leave east right away. The entire series of tunnels will flood, so get back to the orange portal and enter it quickly. %^RED%^PROTIP:%^RESET%^ The water will also go through the locked cavetroll gate. And cavetrolls don't breathe water. Now, go to the town well (1n, 1e, 5n of the hazlab), and: %^GREEN%^enter well%^RESET%^ Hopefully you did get the maglite. By now the weaker flashlights may have pooped out. See the lever on the wall? That operates a set of two doors that serve as a waterlock for the well. Pull it, and a door will open, letting water flood into the well, and solving the quest! It may be that someone has already been fooling with the water lock, though. If the door was already open when you got there, push the lever, wait a few minutes for water to flood the lock, then pull the lever. It could take a while depending on the water pressure for the lock to fill up, so if it's dry, close it again and wait a while before opening again. %^CYAN%^Alternate Resolution%^RESET%^ It may be that the orange portal was not in the water tunnel. It could be that the hazardous materials labs was not accessible to you. If that is the case, you'll need to solve this quest by accessing the water source from the direction of the well. This is tricky because you need to be very strong to open the grate, *and* you need an extra set of hands to operate the water lock lever. Let's deal with one problem at a time. First, the strength issue. On the other side of the water lock is a grate that you must have at least 50 strength to open. If your strength is already above 49, great. If not, you need to decide whether you want to boost it with strength potions from Oana (expensive) or use the landstrider mech (tricky). If the plan is to use strength potions, go buy them now and stick them in your ruck. If the plan is to use the mech, go get it. Go to Kleiner, and: %^GREEN%^dial stargate lab%^RESET%^ %^GREEN%^enter gate%^RESET%^ %^GREEN%^go north%^RESET%^ %^GREEN%^go east%^RESET%^ %^GREEN%^enter mech%^RESET%^ %^GREEN%^drive west%^RESET%^ %^GREEN%^drive south%^RESET%^ %^GREEN%^direct mech to dial campus lab%^RESET%^ %^GREEN%^direct mech to enter gate%^RESET%^ %^GREEN%^drive south%^RESET%^ %^GREEN%^drive east%^RESET%^ %^GREEN%^drive north%^RESET%^ %^GREEN%^drive north%^RESET%^ %^GREEN%^drive north%^RESET%^ %^GREEN%^drive north%^RESET%^ %^GREEN%^drive north%^RESET%^ %^GREEN%^direct mech to enter well%^RESET%^ %^GREEN%^direct mech to pull lever%^RESET%^ %^GREEN%^drive west%^RESET%^ %^GREEN%^out%^RESET%^ %^GREEN%^go east%^RESET%^ The mech is now in the water lock. But neither you nor the mech can proceed further west...you need someone to pull the lever for you. You're going to need a servant...a slave...a ZOMBIE! Go up and west, and buy a dark scroll from Oana. The scroll can be used to raise a corpse, but you must be able to read English. If you've chosen a race that doesn't speak English, you'll need to learn it now. Go to Bugg (1n, 2e, 1n of the well) and ask him to teach you English. Once you've learned it, you'll be ready to create a zombie. From Bugg, go to the campus square (1s, 2w, 5s) and murder Tim. It's important that you slay something that speaks a language you know, so since you're either human or just now learned English, a human victim is suitable. Plus Tim is a wuss. Once he's slain: %^GREEN%^read scroll at tim%^RESET%^ There he is! Your very own zombie! We'll need to move quickly now. Zombies don't last forever...the clock is ticking. Do the following to get him to follow you: %^GREEN%^speak in english%^RESET%^ %^GREEN%^say follow cratylus%^RESET%^ Except, of course, instead of \"cratylus\", put in your own name. Note something important here. Zombies are obedient, but not smart. If someone else starts saying things that the zombie understands as a command, it will start obeying them. So remember that while you created this zombie, someone else can steal him if you're not careful. Now, return to the well (4n) then enter the well and go west. You'll need to tell the zombie to leave the water lock and operate it: %^GREEN%^say go east%^RESET%^ %^GREEN%^yell push lever%^RESET%^ %^GREEN%^enter mech%^RESET%^ %^GREEN%^drive west%^RESET%^ %^GREEN%^direct mech to open grate%^RESET%^ Woohoo! If you don't have the mech, of course, you just walk your own self west, drink your strength potions, and open the grate yourself. If you *do* have the mech, let's get it out of harm's way... %^GREEN%^drive east%^RESET%^ %^GREEN%^out%^RESET%^ %^GREEN%^go west%^RESET%^ All righty, now let's go resolve this well problem. Go down and you'll see the metal wheel and the water pipe. To get the water flowing again, turn the wheel. Then very quickly get yourself back to the water lock...the area will fill with water soon! When water gets to the lock: %^GREEN%^yell pull lever%^RESET%^ Your zombie will then open the east door, allowing you and the water to get to the well, and solving the Town Well Quest. Congratulations! ",({"chapter 2","chapter two","2",}):"chapter 2 \"Post-Mansion Hints\" So you're flush with joy at having solved your first quest, and now you're loaded with money and loot! Woo! But...oh no... there's so much loot left in the mansion, and the gate gard won't let you pass because you're not a newbie anymore. Bummer! Well, we're going to fix that, but first, let's get organized. You're carrying a bunch of stuff, some of which you want to keep, some of which you want to sell, and it's going to get tiresome soon, having to sort through your inventory all the time at shops. So the first thing we're going to do is buy a rucksack. Why? Remember when you tried to \"drop all\" and the only things you didn't drop were the things you were wearing? A rucksack gives you somewhere to keep a bunch of stuff, and you *wear* the rucksack. Meaning that \"drop all\" and \"sell all\" will ignore the valuable stuff you keep in your rucksack, if you're wearing it. Neat, huh? It makes life much easier when selling tons of loot. So, let's go to Otik (from the gate guard, 1n, 3e, 1n), and buy the rucksack. Try: %^GREEN%^buy ruck from otik%^RESET%^ If you dont have enough money, sell some of the junk you got from the mansion. It also could be that you *do* have enough money, but not in silver. If this is the case, go to zoe and do a currency exchange: %^GREEN%^exchange 5 gold for silver%^RESET%^ Note that you can only exchange money in your possession. Zoe does not exchange money while it is deposited. Once you have your rucksack, wear it, open it, and put in it the stuff you want to keep. I suggest putting the grenade, the pistol, and the slips in there. Now sell the junk you don't want, deposit the excess cash with Zoe, and let's get ready to deal with the gate guard. The problem: A guard you cannot kill, preventing passage. The solution: Find a way around, or through him. Now, you might be tempted to use the grenade. You *could* pull the pin on the grenade, drop it, leave, wait a few seconds, and come back...and the guard *might* be dead. But this is a magical guard. Even if he dies, his spirit prevents you from getting past. And he will regenerate into a new body within seconds. So... what to do? There are two solutions, and both of them require... SCIENCE! Go to Zoe and withdraw 110 dollars or so (darn fees), then go to the bookstore (1w, 8s, 5e, 1n), and buy the lab coat from Kim. Now go to the campus stargate lab (1s, 5w, 1s, 1w, 1n), where Kleiner is busy working on exotechnology, as usual. In typical egghead fashion, Kleiner is too preoccupied with his experiments to help you, but he wants *your* help. He's lost his lab coat, you see. Like so many geniuses, Kleiner is somewhat physically clumsy, and if he wears a lab coat you give him, he's liable to drop his identification badge. This badge gives its carrier access to the \"hazardous technologies\" lab two rooms south of Kleiner. %^RED%^PROTIP%^RESET%^: Do not attempt to kill Kleiner. He is carrying a teleportation device called an omni which he will use the moment he receives harm from someone. Attacking Kleiner just means he and his ID badge will teleport to some random location, and you'll be up the creek. %^RED%^PROTIP%^RESET%^: In the hazardous materials lab, DO NOT attempt to harm the tripod gun turret. Failure to heed this warning will result in catastrophic injury to anyone in the room. On the hazlab workbench you'll find various items of interest. For now we'll concentrate on the Yautja wrist computer, the Yautja data module, and the rocket pack. The rocket pack is the simplest tool for circumventing the gate guard. Wear it, and head back to the guard (1n, 1e, 6n, 2w, 1s). Now use the pack to fly over the guard: %^GREEN%^activate pack%^RESET%^ %^GREEN%^boost up%^RESET%^ %^GREEN%^boost south%^RESET%^ %^GREEN%^boost down%^RESET%^ %^GREEN%^deactivate pack%^RESET%^ How do ya like that! Remember to deactivate the pack, too. If you leave it running, it'll eventually run out of fuel. Don't get too crazy flying around with it, either. You're extremely likely to boost yourself out over the ocean if you're not careful, and wind up lost and drowning. Also, if you run out of fuel while up in the air, you *will* fall and the damage you'll receive will be grievous. So let's be very careful in our use of the rocket pack. Another way to get past the guard is by having him not see you at all. The Yautja technology can help you in this: %^GREEN%^wear wristcomp%^RESET%^ %^GREEN%^open wristcomp%^RESET%^ %^GREEN%^activate wristcomp%^RESET%^ %^GREEN%^install module in wristcomp%^RESET%^ %^GREEN%^close wristcomp%^RESET%^ %^GREEN%^cloak%^RESET%^ %^GREEN%^go south%^RESET%^ %^GREEN%^decloak%^RESET%^ It is crucially important that you are cloaked only as long as necessary. If you walk around while cloaked, it will sap your stamina extremely quickly. Note that it is a peculiarity of Yautja technology that it's a bit awkward to use. If you remove the wristcomp, it deactivates, and you'll need to wear it, activate it again, uninstall the module, and install it again. Those Yautja hunters always do things the hard way, I'll tellya. You now have the tools you need to successfully steal every ounce of worth from the newbie mansion regardless of your newbie status. Congratulations...I guess. ",]),"/doc/phints/chapter02":1236662936,"/doc/phints/.chapter04.swp":1585966503,"/doc/phints/chapter01":1236662936,]),"/obj/book_source":(["/obj/book_source/chapter1":1156518232,"object":"null","title":"The Coder's Manual","items":([({"chapter 2","chapter two","2",}):"\"Second Chapter Title\" ",({"chapter 2","chapter two","2",}):"\"Second Chapter Title\" ",({"chapter 1","chapter one","1",}):"\"First Chapter Title\" ",({"chapter 1","chapter one","1",}):"\"First Chapter Title\" ",({"chapter 2","chapter two","2",}):"\"Second Chapter Title\" ",({"chapter 1","chapter one","1",}):"\"First Chapter Title\" ",]),"index":" The Coder's Manual Chapter 1: \"First Chapter Title\" Chapter 2: \"Second Chapter Title\" ","reads":([({"chapter 1","chapter one","1",}):"chapter 1 \"First Chapter Title\" This is the text of the first chapter. ",({"chapter 1","chapter one","1",}):"chapter 1 \"First Chapter Title\" This is the text of the first chapter. ",({"chapter 2","chapter two","2",}):"chapter 2 \"Second Chapter Title\" This is the text of the second chapter. ",({"chapter 2","chapter two","2",}):"chapter 2 \"Second Chapter Title\" This is the text of the second chapter. ",({"chapter 1","chapter one","1",}):"chapter 1 \"First Chapter Title\" This is the text of the first chapter. ",({"chapter 2","chapter two","2",}):"chapter 2 \"Second Chapter Title\" This is the text of the second chapter. ",]),"/obj/book_source/chapter2":1156518232,]),"/doc/hbook":(["object":"/domains/default/obj/handbook","/doc/hbook/chapter09":1236662936,"/doc/hbook/chapter08":1236712552,"/doc/hbook/chapter07":1164672846,"/doc/hbook/chapter06":1164672846,"/doc/hbook/chapter05":1164672846,"/doc/hbook/chapter04":1195053468,"/doc/hbook/chapter03":1177376334,"/doc/hbook/chapter02":1164672846,"/doc/hbook/chapter01":1164672846,"title":"Untitled","items":([({"chapter 8","chapter eight","8",}):"\"Stats details\" ",({"chapter 5","chapter five","5",}):"\"Communication\" ",({"chapter 2","chapter two","2",}):"\"Command Syntax: Doing Stuff\" ",({"chapter 7","chapter seven","7",}):"\"Hints and tips\" ",({"chapter 6","chapter six","6",}):"\"Note to New Creators\" ",({"chapter 2","chapter two","2",}):"\"Command Syntax: Doing Stuff\" ",({"chapter 8","chapter eight","8",}):"\"Stats details\" ",({"chapter 8","chapter eight","8",}):"\"Stats details\" ",({"chapter 1","chapter one","1",}):"\"Introduction\" ",({"chapter 9","chapter nine","9",}):"\"Skills, teachers, and trainers\" ",({"chapter 3","chapter three","3",}):"\"Your Health and Abilities\" ",({"chapter 1","chapter one","1",}):"\"Introduction\" ",({"chapter 7","chapter seven","7",}):"\"Hints and tips\" ",({"chapter 3","chapter three","3",}):"\"Your Health and Abilities\" ",({"chapter 6","chapter six","6",}):"\"Note to New Creators\" ",({"chapter 2","chapter two","2",}):"\"Command Syntax: Doing Stuff\" ",({"chapter 3","chapter three","3",}):"\"Your Health and Abilities\" ",({"chapter 9","chapter nine","9",}):"\"Skills, teachers, and trainers\" ",({"chapter 6","chapter six","6",}):"\"Note to New Creators\" ",({"chapter 5","chapter five","5",}):"\"Communication\" ",({"chapter 4","chapter four","4",}):"\"Quests\" ",({"chapter 4","chapter four","4",}):"\"Quests\" ",({"chapter 7","chapter seven","7",}):"\"Hints and tips\" ",({"chapter 1","chapter one","1",}):"\"Introduction\" ",({"chapter 4","chapter four","4",}):"\"Quests\" ",({"chapter 5","chapter five","5",}):"\"Communication\" ",({"chapter 9","chapter nine","9",}):"\"Skills, teachers, and trainers\" ",]),"index":" Untitled Chapter 1: \"Introduction\" Chapter 2: \"Command Syntax: Doing Stuff\" Chapter 3: \"Your Health and Abilities\" Chapter 4: \"Quests\" Chapter 5: \"Communication\" Chapter 6: \"Note to New Creators\" Chapter 7: \"Hints and tips\" Chapter 8: \"Stats details\" Chapter 9: \"Skills, teachers, and trainers\" ","reads":([({"chapter 4","chapter four","4",}):"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's 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's healers 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 4","chapter four","4",}):"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's 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's healers 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 8","chapter eight","8",}):"chapter 8 \"Stats details\" Stats are very important! Depending on the style of play you prefer, different stats can be of more value to you. Fighters may prefer strength, mages may favor intelligence. %^RED%^IMPORTANT TIP%^RESET%^: Players start off with 15 stat points they can add to their stats...so that if you find your strength is abysmally low, you can raise it to where your character is playable at lower levels. Don't forget to type: %^GREEN%^help customize%^RESET%^ %^CYAN%^About \"stat classes\"%^RESET%^: Depending on the race you choose at character creation, your stat class will be something in the range of 1 to 5. This is a measure of the stat's typical priority for that race. For example, orcs are very strong, and so not only do they usually start with a high strength stat, their strength class is 1, meaning that every time an orc has a level promotion, their strength stat is also raised by 1. Humans, however, have a strength stat class of 3, meaning a human player's strength stat is increased by 1 only every third level promotion. %^CYAN%^Deviation%^RESET%^:Starting in Dead Souls 2.9a18, a player can choose to \"deviate\" from her race's default stat classes. For example, you *can* have an orc mage with a high-priority intelligence stat. To do so, you use the deviate command to set your stat deviation...meaning you're going to devote a certain percent of the XP you earn to making yourself better at some stats you choose. Naturally, the more you want to change a stat class, the more expensive this will be in terms of your XP deviance cost. For more information, see: %^GREEN%^help deviate%^RESET%^ %^CYAN%^Some notes on individual stats%^RESET%^: High %^MAGENTA%^strength%^RESET%^ means you hit hard when you're in combat, but it also means you might be strong enough to perform some tasks others cannot, like open very heavy metal doors. High %^MAGENTA%^intelligence%^RESET%^ means you're able to learn things better, quicker, like skill training and languages. It means your training points do you more good. High %^MAGENTA%^charisma%^RESET%^ means it's easier to befriend animals, which is important if you want to, for example, mount a horse: %^GREEN%^befriend horse%^RESET%^ %^GREEN%^mount horse%^RESET%^ %^MAGENTA%^Agility%^RESET%^ and %^MAGENTA%^coordination%^RESET%^ are important for avoiding being hit, and for certain special abilities like stealth, lock picking, shooting, etc. %^MAGENTA%^Wisdom%^RESET%^ is important for some types of spells. %^MAGENTA%^Durability%^RESET%^ helps determine how much stamina you have... this is vital to lasting through long combat or moving quickly through terrain on foot. Finally, %^MAGENTA%^luck%^RESET%^ is an all-around general good thing to have lots of...some random situations may call for it, and just like in real life, it's hard to know when it'll come in handy, but boy can it mean the difference between win and fail! ",({"chapter 1","chapter one","1",}):"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%^ ",({"chapter 6","chapter six","6",}):"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 3","chapter three","3",}):"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. New characters should avail themselves of the \"customize\" command. When you create a character, you are assigned stats based on random numbers modified by the race you choose. For example, humans are physically weaker than other races, so you might have a strength of 15 as a human, whereas a dwarf might expect something like 42. On the other hand, humans tend to be quite smart, and so your human character might have a high intelligence stat, and the dwarf a substantially lower one. To balance out stats that are grossly unfair, new characters are given 15 points to spend to add to their stats. As a human with 15 strength, you might choose to throw all your customization points into strength, adding up to a whopping 30. Or you might choose to distribute points among your stats in a manner most suited to your playing style. For syntax and details, type: help customize 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 1","chapter one","1",}):"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%^ ",({"chapter 1","chapter one","1",}):"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%^ ",({"chapter 7","chapter seven","7",}):"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. ",({"chapter 5","chapter five","5",}):"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 2","chapter two","2",}):"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 8","chapter eight","8",}):"chapter 8 \"Stats details\" Stats are very important! Depending on the style of play you prefer, different stats can be of more value to you. Fighters may prefer strength, mages may favor intelligence. %^RED%^IMPORTANT TIP%^RESET%^: Players start off with 15 stat points they can add to their stats...so that if you find your strength is abysmally low, you can raise it to where your character is playable at lower levels. Don't forget to type: %^GREEN%^help customize%^RESET%^ %^CYAN%^About \"stat classes\"%^RESET%^: Depending on the race you choose at character creation, your stat class will be something in the range of 1 to 5. This is a measure of the stat's typical priority for that race. For example, orcs are very strong, and so not only do they usually start with a high strength stat, their strength class is 1, meaning that every time an orc has a level promotion, their strength stat is also raised by 1. Humans, however, have a strength stat class of 3, meaning a human player's strength stat is increased by 1 only every third level promotion. %^CYAN%^Deviation%^RESET%^:Starting in Dead Souls 2.9a18, a player can choose to \"deviate\" from her race's default stat classes. For example, you *can* have an orc mage with a high-priority intelligence stat. To do so, you use the deviate command to set your stat deviation...meaning you're going to devote a certain percent of the XP you earn to making yourself better at some stats you choose. Naturally, the more you want to change a stat class, the more expensive this will be in terms of your XP deviance cost. For more information, see: %^GREEN%^help deviate%^RESET%^ %^CYAN%^Some notes on individual stats%^RESET%^: High %^MAGENTA%^strength%^RESET%^ means you hit hard when you're in combat, but it also means you might be strong enough to perform some tasks others cannot, like open very heavy metal doors. High %^MAGENTA%^intelligence%^RESET%^ means you're able to learn things better, quicker, like skill training and languages. It means your training points do you more good. High %^MAGENTA%^charisma%^RESET%^ means it's easier to befriend animals, which is important if you want to, for example, mount a horse: %^GREEN%^befriend horse%^RESET%^ %^GREEN%^mount horse%^RESET%^ %^MAGENTA%^Agility%^RESET%^ and %^MAGENTA%^coordination%^RESET%^ are important for avoiding being hit, and for certain special abilities like stealth, lock picking, shooting, etc. %^MAGENTA%^Wisdom%^RESET%^ is important for some types of spells. %^MAGENTA%^Durability%^RESET%^ helps determine how much stamina you have... this is vital to lasting through long combat or moving quickly through terrain on foot. Finally, %^MAGENTA%^luck%^RESET%^ is an all-around general good thing to have lots of...some random situations may call for it, and just like in real life, it's hard to know when it'll come in handy, but boy can it mean the difference between win and fail! ",({"chapter 2","chapter two","2",}):"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 9","chapter nine","9",}):"chapter 9 \"Skills, teachers, and trainers\" %^CYAN%^General stuff%^RESET%^ Stats are the physical attributes that let you do things. Skills are those things you do. \"blunt attack\", for example, is the skill that determines how good you are at using blunt weapons in combat...while \"blunt defense\" is how good you are at *avoiding* damage from such weapons. \"melee attack\" and \"melee defense\" determine your proficiency at unarmed combat, etc. It is very rare for players who are not fighters to be able to physically fight without weapons, by the way. If the \"skills\" command does not list a particular skill that means you don't have it at all, and whatever it is, you are very, very bad at it. Mages, for example, usually lack \"blade attack\" and \"blade defense\" entirely...meaning they are utterly awful at fighting with swords and avoiding swords in combat. Some skills seem useless but are actually quite important. For example, mages can cast a spell called \"whip\" which summons up an energy weapon whose power can be devastating if the mage is high-level. However, if the mage's conjuring skill is low, the whip does not last long...meaning she will have to keep casting this expensive spell frequently. Skill levels, like stat levels, increase when a player's player level is promoted, depending on the skill class. For a fighter, \"blunt attack\" is a major priority, and so their skill class for this is 1. For another class, it may differ. If the skill class is a high priority, then the skill improves more often when your player level increases. There is no \"deviation\" command to manipulate skill class. Emphasis on skill classes is what player classes (like \"fighter\", \"cleric\", etc) are for. %^CYAN%^Trainers%^RESET%^ Trainers are folks that can help you improve your skills. When your player level goes up, you are awarded \"training points\". You use these training points by asking trainers to train you on some specific skill. For example, a mage can go to Radagast (east, south, up, from the town clocktower) and: %^GREEN%^ask radagast to train magic attack%^RESET%^ If you're a fighter, Radagast will not be able to help you, since you do not already posess that skill. Trainers can only train you in skills you already have some knowledge of. Instead, a fighter might go to Roshd Burlyneck (down, south, west, north, of the Ylsrim tower top) and: %^GREEN%^ask roshd to train knife defense%^RESET%^ At this point, a human player might run into a problem. Roshd is an orc, you see, and speaks Tangetto. He can't train you if you don't understand that language. This is where a different kind of instruction comes in... %^CYAN%^Teachers%^RESET%^ Teachers are a special kind of trainer than can also teach you things you did not already know. Typically this would be a language teacher (like Bugg: east, east, east, north, of the village clocktower), or a spell teacher (Herkimer: south, west, south, of the village clocktower). %^RED%^PROTIP%^RESET%^: You don't have to be a mage in order to have Herkimer teach you a spell. As long as you have some magical ability, and have the money, he will teach you some simple spells whether you are a mage or not. Mages get to learn them free, however, and Herkimer saves some spells for mages only. Trainers and teachers are where having a high intelligence stat can really pay off. It takes fewer lessons to improve your language or your skills if you have high intelligence. ",({"chapter 3","chapter three","3",}):"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. New characters should avail themselves of the \"customize\" command. When you create a character, you are assigned stats based on random numbers modified by the race you choose. For example, humans are physically weaker than other races, so you might have a strength of 15 as a human, whereas a dwarf might expect something like 42. On the other hand, humans tend to be quite smart, and so your human character might have a high intelligence stat, and the dwarf a substantially lower one. To balance out stats that are grossly unfair, new characters are given 15 points to spend to add to their stats. As a human with 15 strength, you might choose to throw all your customization points into strength, adding up to a whopping 30. Or you might choose to distribute points among your stats in a manner most suited to your playing style. For syntax and details, type: help customize 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","chapter four","4",}):"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's 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's healers 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 6","chapter six","6",}):"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 9","chapter nine","9",}):"chapter 9 \"Skills, teachers, and trainers\" %^CYAN%^General stuff%^RESET%^ Stats are the physical attributes that let you do things. Skills are those things you do. \"blunt attack\", for example, is the skill that determines how good you are at using blunt weapons in combat...while \"blunt defense\" is how good you are at *avoiding* damage from such weapons. \"melee attack\" and \"melee defense\" determine your proficiency at unarmed combat, etc. It is very rare for players who are not fighters to be able to physically fight without weapons, by the way. If the \"skills\" command does not list a particular skill that means you don't have it at all, and whatever it is, you are very, very bad at it. Mages, for example, usually lack \"blade attack\" and \"blade defense\" entirely...meaning they are utterly awful at fighting with swords and avoiding swords in combat. Some skills seem useless but are actually quite important. For example, mages can cast a spell called \"whip\" which summons up an energy weapon whose power can be devastating if the mage is high-level. However, if the mage's conjuring skill is low, the whip does not last long...meaning she will have to keep casting this expensive spell frequently. Skill levels, like stat levels, increase when a player's player level is promoted, depending on the skill class. For a fighter, \"blunt attack\" is a major priority, and so their skill class for this is 1. For another class, it may differ. If the skill class is a high priority, then the skill improves more often when your player level increases. There is no \"deviation\" command to manipulate skill class. Emphasis on skill classes is what player classes (like \"fighter\", \"cleric\", etc) are for. %^CYAN%^Trainers%^RESET%^ Trainers are folks that can help you improve your skills. When your player level goes up, you are awarded \"training points\". You use these training points by asking trainers to train you on some specific skill. For example, a mage can go to Radagast (east, south, up, from the town clocktower) and: %^GREEN%^ask radagast to train magic attack%^RESET%^ If you're a fighter, Radagast will not be able to help you, since you do not already posess that skill. Trainers can only train you in skills you already have some knowledge of. Instead, a fighter might go to Roshd Burlyneck (down, south, west, north, of the Ylsrim tower top) and: %^GREEN%^ask roshd to train knife defense%^RESET%^ At this point, a human player might run into a problem. Roshd is an orc, you see, and speaks Tangetto. He can't train you if you don't understand that language. This is where a different kind of instruction comes in... %^CYAN%^Teachers%^RESET%^ Teachers are a special kind of trainer than can also teach you things you did not already know. Typically this would be a language teacher (like Bugg: east, east, east, north, of the village clocktower), or a spell teacher (Herkimer: south, west, south, of the village clocktower). %^RED%^PROTIP%^RESET%^: You don't have to be a mage in order to have Herkimer teach you a spell. As long as you have some magical ability, and have the money, he will teach you some simple spells whether you are a mage or not. Mages get to learn them free, however, and Herkimer saves some spells for mages only. Trainers and teachers are where having a high intelligence stat can really pay off. It takes fewer lessons to improve your language or your skills if you have high intelligence. ",({"chapter 8","chapter eight","8",}):"chapter 8 \"Stats details\" Stats are very important! Depending on the style of play you prefer, different stats can be of more value to you. Fighters may prefer strength, mages may favor intelligence. %^RED%^IMPORTANT TIP%^RESET%^: Players start off with 15 stat points they can add to their stats...so that if you find your strength is abysmally low, you can raise it to where your character is playable at lower levels. Don't forget to type: %^GREEN%^help customize%^RESET%^ %^CYAN%^About \"stat classes\"%^RESET%^: Depending on the race you choose at character creation, your stat class will be something in the range of 1 to 5. This is a measure of the stat's typical priority for that race. For example, orcs are very strong, and so not only do they usually start with a high strength stat, their strength class is 1, meaning that every time an orc has a level promotion, their strength stat is also raised by 1. Humans, however, have a strength stat class of 3, meaning a human player's strength stat is increased by 1 only every third level promotion. %^CYAN%^Deviation%^RESET%^:Starting in Dead Souls 2.9a18, a player can choose to \"deviate\" from her race's default stat classes. For example, you *can* have an orc mage with a high-priority intelligence stat. To do so, you use the deviate command to set your stat deviation...meaning you're going to devote a certain percent of the XP you earn to making yourself better at some stats you choose. Naturally, the more you want to change a stat class, the more expensive this will be in terms of your XP deviance cost. For more information, see: %^GREEN%^help deviate%^RESET%^ %^CYAN%^Some notes on individual stats%^RESET%^: High %^MAGENTA%^strength%^RESET%^ means you hit hard when you're in combat, but it also means you might be strong enough to perform some tasks others cannot, like open very heavy metal doors. High %^MAGENTA%^intelligence%^RESET%^ means you're able to learn things better, quicker, like skill training and languages. It means your training points do you more good. High %^MAGENTA%^charisma%^RESET%^ means it's easier to befriend animals, which is important if you want to, for example, mount a horse: %^GREEN%^befriend horse%^RESET%^ %^GREEN%^mount horse%^RESET%^ %^MAGENTA%^Agility%^RESET%^ and %^MAGENTA%^coordination%^RESET%^ are important for avoiding being hit, and for certain special abilities like stealth, lock picking, shooting, etc. %^MAGENTA%^Wisdom%^RESET%^ is important for some types of spells. %^MAGENTA%^Durability%^RESET%^ helps determine how much stamina you have... this is vital to lasting through long combat or moving quickly through terrain on foot. Finally, %^MAGENTA%^luck%^RESET%^ is an all-around general good thing to have lots of...some random situations may call for it, and just like in real life, it's hard to know when it'll come in handy, but boy can it mean the difference between win and fail! ",({"chapter 5","chapter five","5",}):"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 9","chapter nine","9",}):"chapter 9 \"Skills, teachers, and trainers\" %^CYAN%^General stuff%^RESET%^ Stats are the physical attributes that let you do things. Skills are those things you do. \"blunt attack\", for example, is the skill that determines how good you are at using blunt weapons in combat...while \"blunt defense\" is how good you are at *avoiding* damage from such weapons. \"melee attack\" and \"melee defense\" determine your proficiency at unarmed combat, etc. It is very rare for players who are not fighters to be able to physically fight without weapons, by the way. If the \"skills\" command does not list a particular skill that means you don't have it at all, and whatever it is, you are very, very bad at it. Mages, for example, usually lack \"blade attack\" and \"blade defense\" entirely...meaning they are utterly awful at fighting with swords and avoiding swords in combat. Some skills seem useless but are actually quite important. For example, mages can cast a spell called \"whip\" which summons up an energy weapon whose power can be devastating if the mage is high-level. However, if the mage's conjuring skill is low, the whip does not last long...meaning she will have to keep casting this expensive spell frequently. Skill levels, like stat levels, increase when a player's player level is promoted, depending on the skill class. For a fighter, \"blunt attack\" is a major priority, and so their skill class for this is 1. For another class, it may differ. If the skill class is a high priority, then the skill improves more often when your player level increases. There is no \"deviation\" command to manipulate skill class. Emphasis on skill classes is what player classes (like \"fighter\", \"cleric\", etc) are for. %^CYAN%^Trainers%^RESET%^ Trainers are folks that can help you improve your skills. When your player level goes up, you are awarded \"training points\". You use these training points by asking trainers to train you on some specific skill. For example, a mage can go to Radagast (east, south, up, from the town clocktower) and: %^GREEN%^ask radagast to train magic attack%^RESET%^ If you're a fighter, Radagast will not be able to help you, since you do not already posess that skill. Trainers can only train you in skills you already have some knowledge of. Instead, a fighter might go to Roshd Burlyneck (down, south, west, north, of the Ylsrim tower top) and: %^GREEN%^ask roshd to train knife defense%^RESET%^ At this point, a human player might run into a problem. Roshd is an orc, you see, and speaks Tangetto. He can't train you if you don't understand that language. This is where a different kind of instruction comes in... %^CYAN%^Teachers%^RESET%^ Teachers are a special kind of trainer than can also teach you things you did not already know. Typically this would be a language teacher (like Bugg: east, east, east, north, of the village clocktower), or a spell teacher (Herkimer: south, west, south, of the village clocktower). %^RED%^PROTIP%^RESET%^: You don't have to be a mage in order to have Herkimer teach you a spell. As long as you have some magical ability, and have the money, he will teach you some simple spells whether you are a mage or not. Mages get to learn them free, however, and Herkimer saves some spells for mages only. Trainers and teachers are where having a high intelligence stat can really pay off. It takes fewer lessons to improve your language or your skills if you have high intelligence. ",({"chapter 6","chapter six","6",}):"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 5","chapter five","5",}):"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 7","chapter seven","7",}):"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. ",({"chapter 2","chapter two","2",}):"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","chapter three","3",}):"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. New characters should avail themselves of the \"customize\" command. When you create a character, you are assigned stats based on random numbers modified by the race you choose. For example, humans are physically weaker than other races, so you might have a strength of 15 as a human, whereas a dwarf might expect something like 42. On the other hand, humans tend to be quite smart, and so your human character might have a high intelligence stat, and the dwarf a substantially lower one. To balance out stats that are grossly unfair, new characters are given 15 points to spend to add to their stats. As a human with 15 strength, you might choose to throw all your customization points into strength, adding up to a whopping 30. Or you might choose to distribute points among your stats in a manner most suited to your playing style. For syntax and details, type: help customize 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 7","chapter seven","7",}):"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. ",]),]),"/doc/bguide":(["object":"/domains/default/obj/bguide","/doc/bguide/chapter05":1203153606,"title":"Builder's Guidebook","items":([({"chapter 35","chapter thirty-five","35",}):"\"QCS: Modifying rooms\" ",({"chapter 37","chapter thirty-seven","37",}):"\"QCS: Modifying things and stuff\" ",({"chapter 34","chapter thirty-four","34",}):"\"QCS: Modification of NPC's\" ",({"chapter 1","chapter one","1",}):"\"QCS and Builder Commands\" ",({"chapter 35","chapter thirty-five","35",}):"\"QCS: Modifying rooms\" ",({"chapter 34","chapter thirty-four","34",}):"\"QCS: Modification of NPC's\" ",({"chapter 1","chapter one","1",}):"\"QCS and Builder Commands\" ",({"chapter 36","chapter thirty-six","36",}):"\"QCS: Modifying weapons\" ",({"chapter 36","chapter thirty-six","36",}):"\"QCS: Modifying weapons\" ",({"chapter 38","chapter thirty-eight","38",}):"\"QCS: Adding and deleting\" ",({"chapter 39","chapter thirty-nine","39",}):"\"QCS: Final notes\" ",({"chapter 33","chapter thirty-three","33",}):"\"QCS: Creation\" ",({"chapter 39","chapter thirty-nine","39",}):"\"QCS: Final notes\" ",({"chapter 38","chapter thirty-eight","38",}):"\"QCS: Adding and deleting\" ",({"chapter 33","chapter thirty-three","33",}):"\"QCS: Creation\" ",({"chapter 37","chapter thirty-seven","37",}):"\"QCS: Modifying things and stuff\" ",]),"/doc/bguide/chapter04":1203153606,"/doc/bguide/chapter03":1203153606,"/doc/bguide/chapter02":1203153606,"/doc/bguide/chapter01":1212343010,"index":" Builder's Guidebook Chapter 1: \"QCS and Builder Commands\" ","reads":([({"chapter 34","chapter thirty-four","34",}):"chapter 34 \"QCS: Modification of NPC's\" In the previous chapter we learned how to make a generic object. Now that we have it, what to do with it? It's important to keep in mind that the generic thing now in front of you isn't just a clone from a template file. If the command you used was \"create npc cowboy\", there is now a file (probably) called /realms/you/area/npc/cowboy.c that contains the code for the creature in front of you. However, this poor beast has the most uninteresting of features. It is in fact so boring that it responds only to its generic type. Such that \"examine cowboy\" or \"kill tex\" won't work. You'll need to \"look at npc\". Accordingly, any modification commands need to be made referring to the new thing with an it responds to, until such a time as you change the id to suit your tastes. Let's carry on with the example of our generic npc. To make a cowboy out of him, we can either change his name, or his id, or both. Let's start with his name: %^GREEN%^modify npc name cowboy%^RESET%^ This makes the SetKeyName() directive in cowboy.c use \"cowboy\" as its argument, effectively allowing you to address this npc as \"cowboy\" from now on. Now you can \"look at cowboy\" with some results. Obviously our NPC isn't *just* a cowboy. He's also a human, a dude, and his name is Tex. How do we make him respond to all of these nouns? %^GREEN%^modify cowboy id%^RESET%^ You'll notice there are no arguments following the word \"id\". Setting a thing's id is different from most other settings. If you'll think back to the LPC datatypes chapter of this manual (you did read the LPC chapters, didn't you?) you'll remember that some information about objects is in the form of strings (\"cowboy\"), some is in the form of integers (the cowboy's health points, for example) and some is in the form of arrays, which are a group of data points. In this example we want the cowboy's id to be an array, because of the many ways we might want to address him. Therefore, we want the SetId directive in his file to look like this: SetId( ({\"human\", \"dude\", \"tex\" }) ); You might think that QCS should be able to accept multiple values like this on a line, perhaps with \"modify cowboy id human dude tex\" as the command. But what if you want this npc to be a \"Boy Named Sue\"? How would you accommodate id's that contain spaces? In designing QCS, I considered having escape characters to allow for such things, but ultimately reasoned that this was just way too much mess. Instead, SetId, and other directives that take arrays as arguments, are handled by entering a query session. Below is an example of what it might look like. The example is necessarily messy because I am including both the queries and the responses. --------------------------------------------------- > %^GREEN%^modify npc name cowboy%^RESET%^ Indenting file... \"/tmp/indent.1136206130.tmp.dat\" 15 lines 420 bytes Exit from ed. > %^GREEN%^modify cowboy 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%^human%^RESET%^ You may now enter the next value. So far, we have: ({ \"dude\", \"human\" }) If you're done entering values, enter a dot on a blank line. %^GREEN%^tex%^RESET%^ You may now enter the next value. So far, we have: ({ \"dude\", \"human\", \"tex\" }) If you're done entering values, enter a dot on a blank line. %^GREEN%^boy named sue%^RESET%^ You may now enter the next value. So far, we have: ({ \"dude\", \"human\", \"tex\", \"boy named sue\" }) If you're done entering values, enter a dot on a blank line. %^GREEN%^.%^RESET%^ Entries complete. Final array is: ({ \"dude\", \"human\", \"tex\", \"boy named sue\" }) Indenting file... \"/tmp/indent.1136206156.tmp.dat\" 19 lines 459 bytes Exit from ed. /open/1136206138: Ok /realms/cratylus/area/npc/cowboy: Ok SetId modification complete. > %^GREEN%^exa tex%^RESET%^ Other than being human, this npc is entirely unremarkable. The male human is in top condition. --------------------------------------------------- If you were now to examine Tex's code (with the command \"about tex\") you'd see that his SetId directive now looks like this: SetId( ({\"dude\", \"human\", \"tex\", \"boy named sue\"}) ); Other NPC features take arrays also. SetAdjectives is one. You might enter this (mud output omitted for clarity): %^GREEN%^modify tex adjectives%^RESET%^ %^GREEN%^dusty%^RESET%^ %^GREEN%^hardy%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^look at dusty cowboy%^RESET%^ There are two other directives that require queries. Things and NPC's can be looked at, but they can also be smelled and listened to, if you add SetSmell and SetListen. The syntax is: %^GREEN%^modify tex smell%^RESET%^ And you will then be asked a question about keys and mappings. Understanding mappings is important, but for now you just need to understand that you are being asked *two* separate questions: 1) What on the cowboy is being smelled/listened to? 2) What is the smell/sound? What this means is that your input will look something like this: %^GREEN%^modify tex smell%^RESET%^ %^GREEN%^default%^RESET%^ %^GREEN%^.%^RESET%^ Tex smells of sweat and manure. What happens is this: - You enter the modify command. - You enter the word \"default\" to indicate this is Tex's general smell. - You enter a dot to indicate that you are done specifying what part of Tex is being smelled. - You then specify the smell. This may seem odd until you realize you can also add smells/listens to parts of things. Not on NPC's, though. We'll look at this more closely in later chapters. For now, just use the syntax as shown above. For adding a listen to the cowboy, it works the same way: %^GREEN%^modify tex listen%^RESET%^ %^GREEN%^default%^RESET%^ %^GREEN%^.%^RESET%^ Tex seems to be humming a jaunty melody. Other features of an NPC do not take arrays, so one-line commands will do. For example: %^GREEN%^modify cowboy long This is a cowboy who calls himself Tex, but is in fact a Boy Named Sue.%^RESET%^ %^GREEN%^modify cowboy short a cowboy%^RESET%^ %^GREEN%^modify cowboy level 5%^RESET%^ %^GREEN%^modify cowboy class fighter%^RESET%^ %^GREEN%^modify tex currency gold 1%^RESET%^ %^GREEN%^modify tex currency silver 12%^RESET%^ %^GREEN%^modify tex skill bargaining 5%^RESET%^ %^GREEN%^modify tex skill projectile attack 7%^RESET%^ %^GREEN%^modify tex stat strength 33%^RESET%^ %^GREEN%^modify tex property nice guy 1%^RESET%^ %^GREEN%^modify tex healthpoints 150%^RESET%^ %^GREEN%^modify tex maxhealthpoints 170%^RESET%^ %^GREEN%^modify tex melee 0%^RESET%^ %^GREEN%^modify tex unique 1%^RESET%^ If you now issue the \"about tex\" command you will see that all the changes you made have been put into the file. You may have noticed the \"melee\" keyword. Dead Souls 2 NPC's come in various shapes and sizes, and some of them shouldn't wield weapons. A wolf with a battle axe would be a strange sight indeed. However, the default combat system makes unarmed creatures extremely vulnerable in combat. To make an NPC combat-capable without weapons, use the new SetMelee directive. SetMelee(1) makes the NPC capable of proper unarmed combat. SetMelee(0) makes the NPC a weak opponent if unarmed. NPC's will generally try to bite during unarmed combat. If this is beneath the capability or dignity of your NPC, you can prevent this with: %^GREEN%^modify tex canbite 0%^RESET%^ If your NPC should try to escape when the battle isn't going his way, the wimpy settings should do: %^GREEN%^modify tex wimpy 30%^RESET%^ %^GREEN%^modify tex wimpycommand climb ladder%^RESET%^ If you don't specify a wimpy command, Tex will leave the room through a random exit. In this case, when Tex's health is down to 30% and he is in combat, he will try to climb a ladder. Some NPC's are designed to travel about. To enable this feature, use the wanderspeed directive: %^GREEN%^modify tex wanderspeed 5%^RESET%^ If you want him to travel more quickly, use a lower number. By default, wandering NPC's only wander in rooms that have already been loaded into memory. They avoid loading rooms because loading a bunch of rooms that only the NPC will ever see is a waste of your mud's resources. However, if you *do* want your NPC to wander in an unrestricted manner, regardless of whether a room is loaded, use the permitload directive: %^GREEN%^modify tex permitload 1%^RESET%^ By default, NPC's stand up when they can. This is so that if they collapse during combat, they try to get back up once they are able to do so. If you prefer that your NPC maintain some other posture, you can set that posture, then disable autostanding like this: %^GREEN%^modify tex posture lying%^RESET%^ %^GREEN%^modify tex autostand 0%^RESET%^ If he's especially lazy, you can have him take a nap this way: %^GREEN%^modify tex sleeping 10%^RESET%^ Which will have him wake up after about a minute. However, note that if you've disabled autostanding, he will remain lying down after he wakes up. If the NPC should be hostile, that is, he should attack any creatures that it sees enter a room, SetEncounter should do it: %^GREEN%^modify tex encounter 100%^RESET%^ This means that if the creature it sees has a charisma score of less than 100 (which should pretty much be always true), Tex will try to kill it. You can do some fancy stuff with SetEncounter, such as only attacking orcs, or actually doing something friendly, but to do so you can't use QCS. Read the NPC and Sentients chapter in the Creator's Manual for details on how to code such stuff. If the NPC is a golem or other such non-biological creature, it may be useful to specify what they are made of. The SetComposition setting for a clay golem might look like this: %^GREEN%^modify golem composition clay%^RESET%^ If it happens to be a golem that does not believe in violence as a solution to problems, you can make refuse to hurt others with the following: %^GREEN%^modify golem pacifist 1%^RESET%^ Vendors: ------- Vendors are a special kind of NPC that can sell stuff. Along with the standard NPC settings, vendors have the following: SetStorageRoom specifies where the vendor's stock is stored. If a valid room is specified, anything in that room can be sold by the vendor. SetLocalCurrency specifies the type of currency, such as gold or silver, that the vendor accepts. SetMaxItems is the maximum number of items in the storeroom that the vendor is permitted to sell. SetVendorType specifies the kind of stuff the vendor can trade in. \"all\" allows him to buy and sell whatever. But if he is a weapon vendor, he can't trade in armor, etc. See /include/vendor_types.h for the available vendor types. To have a \"multi-type\" vendor, you'll have to code it by hand. The result of that looks something like this: SetVendorType( VT_TREASURE | VT_ARMOR | VT_HERBS ); Barkeeps: -------- Like vendors, barkeeps sell stuff, but they are limited to selling food and drink. Unlike vendors, barkeeps have no limitation on the amount of stuff they can sell. They also do not have a storeroom. The stuff they can sell is specified in their SetMenu directive, like this: %^GREEN%^clone woody%^RESET%^ You clone a generic barkeep (/realms/temujin/area/npc/woody.c). %^GREEN%^modify woody menu%^RESET%^ If you don't understand these questions, type the letter q on a blank line and hit enter. Please enter the first key element for this mapping: %^GREEN%^bourbon%^RESET%^ Please enter the next key element, or enter a single dot to finish entering key elements. %^GREEN%^whiskey%^RESET%^ Please enter the next key element, or enter a single dot to finish entering key elements. %^GREEN%^.%^RESET%^ Please enter the value for key ({ \"bourbon\", \"whiskey\" }): %^GREEN%^/domains/town/meals/bourbon%^RESET%^ Barkeeps also have the SetLocalCurrency directive to specify the currency they accept. ",({"chapter 38","chapter thirty-eight","38",}):"chapter 38 \"QCS: Adding and deleting\" Rooms, containers and NPC's all are capable of holding items, and often it is convenient to have them already holding certain items upon creation. The SetInventory directive in an object's file provides us with a list of that object's \"permanent inventory\". To modify an object's inventory, we use the add and delete commands. Let's say that we want our cowboy to be wielding a hammer when he appears... %^GREEN%^clone cowboy%^RESET%^ %^GREEN%^cd ../weap%^RESET%^ %^GREEN%^clone hammer%^RESET%^ %^GREEN%^add hammer to cowboy%^RESET%^ %^GREEN%^wield hammer%^RESET%^ Believe it or not, it's that simple. The add command will ask you a question after you issue it. What it wants to know is if you want the NPC to do anything special when the hammer appears on him. In this case, yes, we wanted him to wield it. However, if you want to add something to an NPC and don't have anything interesting for him to do with it, respond to the question with the number of items that you want to appear. For example, if I want the cowboy to be carrying a key: %^GREEN%^cd ../obj%^RESET%^ %^GREEN%^clone key%^RESET%^ %^GREEN%^add key to cowboy%^RESET%^ %^GREEN%^1%^RESET%^ And that's it. Now if I want the cowboy to be a permanent resident of this room: %^GREEN%^add cowboy%^RESET%^ %^GREEN%^1%^RESET%^ The add command understands that if you don't specify a target argument, you must mean the room. You can also be specific: %^GREEN%^add cowboy to room%^RESET%^ %^GREEN%^1%^RESET%^ The delete command works the opposite way. It removes items from an object's permanent inventory: %^GREEN%^delete hammer from cowboy%^RESET%^ %^GREEN%^delete cowboy%^RESET%^ The delete command is also the way to get rid of rooms. You won't be removing the file from disk, you'll just be deleting that exit from the room: %^GREEN%^delete exit garden%^RESET%^ NOTE: When you delete an exit, only the connection from your room to the other room is removed. The connection from the other room to your room remains. This is not a bug, it's a feature. There are plenty of circumstances where one-way travel is desirable. ",({"chapter 37","chapter thirty-seven","37",}):"chapter 37 \"QCS: Modifying things and stuff\" You should have a firm grasp now on how QCS works in relation to manipulable objects. Let's look at the settings for a few special kinds of items: chairs ------ %^GREEN%^modify stool maxsitters 1%^RESET%^ %^GREEN%^modify stool setmaxcarry 200%^RESET%^ beds ---- %^GREEN%^modify sofa maxsitters 2%^RESET%^ %^GREEN%^modify sofa maxliers 1%^RESET%^ %^GREEN%^modify sofa maxcarry 400%^RESET%^ containers ---------- %^GREEN%^modify box canclose 1%^RESET%^ %^GREEN%^modify box closed 1%^RESET%^ %^GREEN%^modify box locked 1%^RESET%^ %^GREEN%^modify box key magic_skeleton_key%^RESET%^ %^GREEN%^modify box maxcarry 200%^RESET%^ %^GREEN%^modify box setmoney gold 15%^RESET%^ tables ------ %^GREEN%^modify altar maxcarry 300%^RESET%^ %^GREEN%^modify altar maxliers 1%^RESET%^ meals/drinks ------------ %^GREEN%^modify burger mealtype food%^RESET%^ %^GREEN%^modify schlitz mealtype alcohol%^RESET%^ %^GREEN%^modify apple mealstrength 10%^RESET%^ books ----- %^GREEN%^modify journal title The Orc Within%^RESET%^ %^GREEN%^modify journal source /domains/Orcland/etc/books/journal%^RESET%^ Readable things: ---------------- If you want to be able to \"read thing\", for example, \"read sign\": %^GREEN%^modify sign defaultread This is a message written on the sign.%^RESET%^ If you want to make a thing on a thing readable, as in \"read inscription on ring\": %^GREEN%^modify ring item%^RESET%^ %^GREEN%^inscription%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^This is an inscription on the ring. Try 'read inscription on ring'%^RESET%^ %^GREEN%^modify ring read%^RESET%^ %^GREEN%^inscription%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^So! We, the spear-Danes%^RESET%^ By default, readabale items are readable by anyone, regardless of the languages they know. If, however, your item should only be readable by someone who understands the elvish tongue: %^GREEN%^modify ring language edhellen%^RESET%^ Miscellaneous: -------------- To make a key have a 50% chance of breaking when it's used: %^GREEN%^modify golden key disablechance 50%^RESET%^ To make a room or object immune to resets: %^GREEN%^modify sentry noclean 1%^RESET%^ To make sure there is only one instance of an object or NPC loaded at any given time: %^GREEN%^modify tiamat unique 1%^RESET%^ To make a thing or room immune to the QCS (except for this command): %^GREEN%^modify workroom nomodify 1%^RESET%^ To specify what kind of vendor should be allowed to traffic in this item: %^GREEN%^modify necklace vendortype treasure%^RESET%^ ",({"chapter 33","chapter thirty-three","33",}):"chapter 33 \"QCS: Creation\" Creation breaks down into three categories. \"Things\", rooms, and doors. Let's look at things first: Thing creation: --------------- In this category we're including NPC's, weapon, armor, unspecial items, tables, furniture, books and containers. Basically things that actually show up somewhere. A door is a very special sort of object and does not fall under this category. To make a new thing, the syntax looks like this: create THING FILENAME The THING is the category of item we are creating. The FILENAME is the name of the file that will contain this item's configuration data. You may enter an absolute path, or you may simply enter a filename. If you enter a filename, QCS will attempt to figure out the best place for this file. If your current working directory has a name QCS understands as being compatible with the type of object you are making (for example, your cwd is /realms/you/npc and you are making an NPC) it will use that. Otherwise it will search parent and children directories for a directory name it understands this way. Finally, if it can find no compatible directories for your file near your cwd, it will put it in the appropriate directory in your home area (in this case, /realms/you/area/npc ). Avoid a relative path. It probably won't work the way you think. When the command completes, FILENAME will be a file containing the data for your generic thing, and a copy of that generic thing will appear in the room you are in. If, for example, you entered: %^GREEN%^create npc cowboy%^RESET%^ The room you are in will contain a generic NPC which *does not* answer to the id of \"cowboy\". This NPC is just a generic NPC whose filename is (probably) /realms/you/npc/cowboy.c and isn't yet a real cowboy. You'll need to use the \"modify\" command to make a proper cowboy out of him. Room creation ------------- Naturally, if you create a room, a new room will not appear inside your current environment. Instead, the syntax of the \"create\" command is different when you want to create a new room. You may have noticed that you can't use the \"create\" command to make a new room adjacent to your workroom. This is for your protection and my sanity. Files which contain the directive \"SetNoModify(1)\" are immune to QCS manipulation. Rooms like your workroom, the default start room, the void room, etc, are set nomodify. This is because if you screw it up, you will be sorry, and I just don't want to hear it. So, suppose then that you're in your sample room (one room east of your workroom) and you want to make a new room. You might issue the following command: %^GREEN%^create room south testroom1%^RESET%^ What this does is copy the room you are in (in this case, /realms/you/area/sample_room.c) to a new location (perhaps /realms/you/area/testroom1.c). But the neat thing is, this new room does not have the same exits as the room you are in. The new room has just one exit, leading back to where you are. The net effect of all this is that when you issue this command, you make a new room in the direction you specify, and this new room looks just like the room you're in, only the exits are such that you can travel back and forth between the rooms. Door creation ------------- Doors are funny things. In Dead Souls, they aren't objects in the conventional sense of a thing which occupies a room you're in. Rather, they are really daemons which attach to adjoining rooms. If that doesn't make sense to you, don't worry. You're not alone. The syntax for door creation is much like that for room creation. After you create that room south of your sample room, you can now create a door between them: %^GREEN%^create door south sample_door%^RESET%^ This brings into existence a generic door (closed by default) which is between the two rooms. ",({"chapter 1","chapter one","1",}):"chapter 1 \"QCS and Builder Commands\" \"QCS\" is the Dead Souls Quick Creation system, similar in function to what other codebases refer to as OLC, or On-Line Creation. What with muds being text only, QCS has no fancy windowing system. Using a menu-driven creation system was ruled out quickly due to the vast complexity of the menus that would be required. Instead, QCS relies on a few powerful commands. BUILDER COMMANDS ---------------- home ---- This command magically teleports you to your workroom. arealist -------- This lets you see a list of the things you have created. To see a list of NPC's (or mobs) you've created, type: arealist npc Other valid categories are: room, object, weapon, armor areagoto -------- You can travel directly to rooms you've created. If one of your rooms' file is, for example, ogre_room1, you can: areagoto ogre_room1 areaclone --------- This allows you to bring into existence a copy of a thing you've created. For example, one of the weapons you've made has a file name of golden_sword, you can make one appear by typing: areaclone golden_sword dest ---- This destroys one of your created objects. If you're done playing with a sword, for example, you can: dest sword Note that this does not delete the file, it just destroys the cloned copy. Also, it only works on items cloned from files in your area. You aren't allowed to dest other people's stuff! reload ------ This destroys the current object and reloads it with its current code. For example, if your workroom is full of junk and you want to reset it to its base status, type: reload here And the room will reset to its default, with the junk gone. QCS COMMANDS ------------ create ------ This is the command that gets the ball rolling. This command is what lets you bring a new thing into existence. The things you can create can be seen by typing \"help create\". Examples are rooms, weapons, doors, and so on. We will be reviewing each of those in later chapters. When you issue this command a generic version of the item you wish to create appears (or, in the case of a room, appears in the direction you specify). Once that generic copy materializes, you can change it to suit your needs using the \"modify\" command. modify ------ I tend to regard this command as the heart and soul of QCS. It's this tool that lets you make your world your own. Your new generic things are not useful or fun until you modify them. A \"generic weapon\" isn't very interesting, but a \"mithrilite poleaxe\" might be just the thing to deal with a pesky dragon. add --- Creatures, rooms, and containers are capable of storing other things. Once you make an ogre, you may want to give him a hammer to wield. After you make that hammer, you use the add command to let the ogre have that wepon in his permanent inventory. delete ------ On the other hand, you may be tired of that ogre after a while. If he is a part of the permanent inventory of a room, you can use the delete command to remove him permanently. Or if you'd rather he have a Kill-O-Zap Frogstar blaster rather than a hammer, get rid of the hammer in his inventory with this command. copy ---- This is a room-specific command. Rather than write multiple, nearly identical rooms for large areas, you can use the copy command to make the room you are almost exactly like any other room you choose, except for the exits, which remain the same. Handy for big forests, cell-blocks, twisty mazes of little passages, etc. initfix ------- If a thing isn't working right, try to initfix it. \"init()\" is an object function that many items need in order to work properly. If you've run into something that is behaving unexpectedly, run initfix on it. The trouble just might clear up. ",({"chapter 37","chapter thirty-seven","37",}):"chapter 37 \"QCS: Modifying things and stuff\" You should have a firm grasp now on how QCS works in relation to manipulable objects. Let's look at the settings for a few special kinds of items: chairs ------ %^GREEN%^modify stool maxsitters 1%^RESET%^ %^GREEN%^modify stool setmaxcarry 200%^RESET%^ beds ---- %^GREEN%^modify sofa maxsitters 2%^RESET%^ %^GREEN%^modify sofa maxliers 1%^RESET%^ %^GREEN%^modify sofa maxcarry 400%^RESET%^ containers ---------- %^GREEN%^modify box canclose 1%^RESET%^ %^GREEN%^modify box closed 1%^RESET%^ %^GREEN%^modify box locked 1%^RESET%^ %^GREEN%^modify box key magic_skeleton_key%^RESET%^ %^GREEN%^modify box maxcarry 200%^RESET%^ %^GREEN%^modify box setmoney gold 15%^RESET%^ tables ------ %^GREEN%^modify altar maxcarry 300%^RESET%^ %^GREEN%^modify altar maxliers 1%^RESET%^ meals/drinks ------------ %^GREEN%^modify burger mealtype food%^RESET%^ %^GREEN%^modify schlitz mealtype alcohol%^RESET%^ %^GREEN%^modify apple mealstrength 10%^RESET%^ books ----- %^GREEN%^modify journal title The Orc Within%^RESET%^ %^GREEN%^modify journal source /domains/Orcland/etc/books/journal%^RESET%^ Readable things: ---------------- If you want to be able to \"read thing\", for example, \"read sign\": %^GREEN%^modify sign defaultread This is a message written on the sign.%^RESET%^ If you want to make a thing on a thing readable, as in \"read inscription on ring\": %^GREEN%^modify ring item%^RESET%^ %^GREEN%^inscription%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^This is an inscription on the ring. Try 'read inscription on ring'%^RESET%^ %^GREEN%^modify ring read%^RESET%^ %^GREEN%^inscription%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^So! We, the spear-Danes%^RESET%^ By default, readabale items are readable by anyone, regardless of the languages they know. If, however, your item should only be readable by someone who understands the elvish tongue: %^GREEN%^modify ring language edhellen%^RESET%^ Miscellaneous: -------------- To make a key have a 50% chance of breaking when it's used: %^GREEN%^modify golden key disablechance 50%^RESET%^ To make a room or object immune to resets: %^GREEN%^modify sentry noclean 1%^RESET%^ To make sure there is only one instance of an object or NPC loaded at any given time: %^GREEN%^modify tiamat unique 1%^RESET%^ To make a thing or room immune to the QCS (except for this command): %^GREEN%^modify workroom nomodify 1%^RESET%^ To specify what kind of vendor should be allowed to traffic in this item: %^GREEN%^modify necklace vendortype treasure%^RESET%^ ",({"chapter 35","chapter thirty-five","35",}):"chapter 35 \"QCS: Modifying rooms\" Suppose you are in your sample room and you issued the command: %^GREEN%^create room south testroom1%^RESET%^ You then travel south and see that you are in a room that is almost exactly like the sample room except for the exits. Well, probably you don't want to have a mud with nothing but identical rooms, so let's modify it: %^GREEN%^modify here short Test Room One%^RESET%^ %^GREEN%^modify here long This is the first test room. The walls are rather blank.%^RESET%^ %^GREEN%^modify here climate indoors%^RESET%^ %^GREEN%^modify here light 30%^RESET%^ Ok, so far so good. Standard interior. However, a good mud has rooms with details. Let's add some detail to this room. I've omitted the system output for clarity. This is just what you would input. %^GREEN%^modify here item%^RESET%^ %^GREEN%^wall%^RESET%^ %^GREEN%^walls%^RESET%^ %^GREEN%^blank wall%^RESET%^ %^GREEN%^blank walls%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^These are just blank walls.%^RESET%^ Let's review what we've done here: 1) You issued the modify command specifying your current room as the target, and the SetItems directive as the argument. 2) You entered a query session, and were asked to enter each element of the item's key. 3) You entered a single dot to indicate you were done entering key elements. 4) You entered the value for the key, which is the description of the item. The result of all this is that now you can issue these commands: %^GREEN%^exa wall%^RESET%^ %^GREEN%^look at blank walls%^RESET%^ %^GREEN%^examine walls%^RESET%^ And the output will be: These are just blank walls. Let's add a floor while we're at it: %^GREEN%^modify here item%^RESET%^ %^GREEN%^floor%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^A floor like any other.%^RESET%^ In this case, you didn't feel like adding extra synonyms for \"floor\", so you entered the final dot rather than entering another key element. Then you added the description, and now if you \"exa floor\", you'll get that description. \"about here\" will display to you the file you have modified. Well, that's enough fun with indoor rooms. There's not much more to them. Let's go outdoors now: %^GREEN%^create room south exterior_room%^RESET%^ %^GREEN%^create door south test_door%^RESET%^ %^GREEN%^open door%^RESET%^ %^GREEN%^go south%^RESET%^ %^GREEN%^modify here short a small lawn%^RESET%^ %^GREEN%^modify here daylong A small, well groomed lawn on a lovely sunny day. There is a small building north of here.%^RESET%^ %^GREEN%^modify here nightlong This is a small lawn. Stars twinkle in the night sky above, and some light is coming from a small building to the north.%^RESET%^ %^GREEN%^modify here daylight 30%^RESET%^ %^GREEN%^modify here nightlight 20%^RESET%^ %^GREEN%^modify here light delete%^RESET%^ %^GREEN%^modify here long delete%^RESET%^ %^GREEN%^modify here items delete%^RESET%^ %^GREEN%^modify here items%^RESET%^ %^GREEN%^building%^RESET%^ %^GREEN%^small building%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^A small building, rather ramshackle as if hastily put together.%^RESET%^ %^GREEN%^modify here climate temperate%^RESET%^ Ok! A few new things here. A neat thing about outdoor rooms is that typically they are subject to the time of day. A SetClimate directive that indicates an exterior environment causes the room to receive messages about the sun setting, rising, etc. The SetDayLong and SetNightLong directives allow you to more sensibly describe the area depending on the time of day. To avoid confusion, I deleted the SetLong directive. It is not mandatory to have different day and night descriptions, but players appreciate the effort. It is also possible to have differing ambient light levels depending on the time of day, so we've added SetDayLight and SetNightLight, and we deleted the SetAmbientLight directive. Let's continue to add detail: %^GREEN%^modify here item%^RESET%^ %^GREEN%^lawn%^RESET%^ %^GREEN%^grass%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^Healthy, well groomed and freshly cut grass.%^RESET%^ %^GREEN%^modify here smell%^RESET%^ %^GREEN%^default%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^You can smell the refreshing scent of freshly cut grass.%^RESET%^ %^GREEN%^modify here smell%^RESET%^ %^GREEN%^lawn%^RESET%^ %^GREEN%^grass%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^Yep, it's got that new lawn smell.%^RESET%^ %^GREEN%^modify here listen%^RESET%^ %^GREEN%^building%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^Sounds like someone's fumbling about in there, making a mess. New creators can be so noisy.%^RESET%^ %^GREEN%^modify here item%^RESET%^ %^GREEN%^garden%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^You may enter the garden from here.%^RESET%^ %^GREEN%^create room garden garden_room%^RESET%^ You now have a room with lots of charm and detail. You can \"smell grass\" and \"listen to small building\", if you like. Neat, huh? But there's something very important to keep in mind: Enters, listens and smells don't work properly if there is no item defined for that smell. For example, if you want to be able to listen to the sea, you must \"modify here item\" and add a \"sea\" item. Otherwise, \"listen to the sea\" will respond with \"There is no sea here.\" The only exception to this rule is the \"default\" smell. Enters behave similarly. If you want to be able to \"enter\" something, you'll need to create the corresponding item first, as in the example above. You can use the SetProperties directive to make the room conform to some presets, like: %^GREEN%^modify here property no attack 1%^RESET%^ Read chapter 23 in the Creator's Manual for details on room properties. Also, please note that indoor rooms can also have differing descriptions and light levels for night and day. It's just that indoor rooms don't get notification of daytime changes. Finally, the SetTown directive allows the room to participate in area-wide events, and is useful for security purposes as well: %^GREEN%^modify here town MyTown%^RESET%^ Notes on room filenames: ----------------------- By default, a filename without a leading path creates a room in your area room directory, which in my case would be \"/realms/cratylus/area/room\". However, you can specify a different location for the new room. To create a room in your current working directory: %^GREEN%^create room east ./newroom%^RESET%^ To create a room in a specific directory: %^GREEN%^create room east /realms/cratylus/testrooms/newroom%^RESET%^ ",({"chapter 36","chapter thirty-six","36",}):"chapter 36 \"QCS: Modifying weapons\" Remember that the QCS chapters are supposed to be read in sequence. This is important because as we progress, I will not make explanations about directives and concepts explained previously. Weapons are different from rooms and NPC's in that they can be handled, sold, thrown, etc. They are manipulable objects. As such, we will see new directives: %^GREEN%^create weapon hammer%^RESET%^ You may be familiar with this example from the example webpage. Let's go ahead and plow through the commands: %^GREEN%^modify weapon id hammer%^RESET%^ %^GREEN%^warhammer%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^modify hammer name hammer%^RESET%^ %^GREEN%^modify hammer damagetype blunt%^RESET%^ %^GREEN%^modify hammer weapontype blunt%^RESET%^ %^GREEN%^modify hammer mass 700%^RESET%^ %^GREEN%^modify hammer hands 2%^RESET%^ %^GREEN%^modify hammer short a heavy war hammer%^RESET%^ %^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%^ %^GREEN%^modify hammer adj%^RESET%^ %^GREEN%^large%^RESET%^ %^GREEN%^heavy%^RESET%^ %^GREEN%^war%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^modify hammer basecost silver 750%^RESET%^ %^GREEN%^about hammer%^RESET%^ Like a room and unlike an NPC, you can also modify the SetItems on manipulable objects like weapons, so you could do something like this: %^GREEN%^modify hammer item%^RESET%^ %^GREEN%^shaft%^RESET%^ %^GREEN%^handle%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^A thick, reinforced steel shaft with leather bands for a strong grip.%^RESET%^ %^GREEN%^exa shaft on hammer%^RESET%^ ",({"chapter 33","chapter thirty-three","33",}):"chapter 33 \"QCS: Creation\" Creation breaks down into three categories. \"Things\", rooms, and doors. Let's look at things first: Thing creation: --------------- In this category we're including NPC's, weapon, armor, unspecial items, tables, furniture, books and containers. Basically things that actually show up somewhere. A door is a very special sort of object and does not fall under this category. To make a new thing, the syntax looks like this: create THING FILENAME The THING is the category of item we are creating. The FILENAME is the name of the file that will contain this item's configuration data. You may enter an absolute path, or you may simply enter a filename. If you enter a filename, QCS will attempt to figure out the best place for this file. If your current working directory has a name QCS understands as being compatible with the type of object you are making (for example, your cwd is /realms/you/npc and you are making an NPC) it will use that. Otherwise it will search parent and children directories for a directory name it understands this way. Finally, if it can find no compatible directories for your file near your cwd, it will put it in the appropriate directory in your home area (in this case, /realms/you/area/npc ). Avoid a relative path. It probably won't work the way you think. When the command completes, FILENAME will be a file containing the data for your generic thing, and a copy of that generic thing will appear in the room you are in. If, for example, you entered: %^GREEN%^create npc cowboy%^RESET%^ The room you are in will contain a generic NPC which *does not* answer to the id of \"cowboy\". This NPC is just a generic NPC whose filename is (probably) /realms/you/npc/cowboy.c and isn't yet a real cowboy. You'll need to use the \"modify\" command to make a proper cowboy out of him. Room creation ------------- Naturally, if you create a room, a new room will not appear inside your current environment. Instead, the syntax of the \"create\" command is different when you want to create a new room. You may have noticed that you can't use the \"create\" command to make a new room adjacent to your workroom. This is for your protection and my sanity. Files which contain the directive \"SetNoModify(1)\" are immune to QCS manipulation. Rooms like your workroom, the default start room, the void room, etc, are set nomodify. This is because if you screw it up, you will be sorry, and I just don't want to hear it. So, suppose then that you're in your sample room (one room east of your workroom) and you want to make a new room. You might issue the following command: %^GREEN%^create room south testroom1%^RESET%^ What this does is copy the room you are in (in this case, /realms/you/area/sample_room.c) to a new location (perhaps /realms/you/area/testroom1.c). But the neat thing is, this new room does not have the same exits as the room you are in. The new room has just one exit, leading back to where you are. The net effect of all this is that when you issue this command, you make a new room in the direction you specify, and this new room looks just like the room you're in, only the exits are such that you can travel back and forth between the rooms. Door creation ------------- Doors are funny things. In Dead Souls, they aren't objects in the conventional sense of a thing which occupies a room you're in. Rather, they are really daemons which attach to adjoining rooms. If that doesn't make sense to you, don't worry. You're not alone. The syntax for door creation is much like that for room creation. After you create that room south of your sample room, you can now create a door between them: %^GREEN%^create door south sample_door%^RESET%^ This brings into existence a generic door (closed by default) which is between the two rooms. ",({"chapter 1","chapter one","1",}):"chapter 1 \"QCS and Builder Commands\" \"QCS\" is the Dead Souls Quick Creation system, similar in function to what other codebases refer to as OLC, or On-Line Creation. What with muds being text only, QCS has no fancy windowing system. Using a menu-driven creation system was ruled out quickly due to the vast complexity of the menus that would be required. Instead, QCS relies on a few powerful commands. BUILDER COMMANDS ---------------- home ---- This command magically teleports you to your workroom. arealist -------- This lets you see a list of the things you have created. To see a list of NPC's (or mobs) you've created, type: arealist npc Other valid categories are: room, object, weapon, armor areagoto -------- You can travel directly to rooms you've created. If one of your rooms' file is, for example, ogre_room1, you can: areagoto ogre_room1 areaclone --------- This allows you to bring into existence a copy of a thing you've created. For example, one of the weapons you've made has a file name of golden_sword, you can make one appear by typing: areaclone golden_sword dest ---- This destroys one of your created objects. If you're done playing with a sword, for example, you can: dest sword Note that this does not delete the file, it just destroys the cloned copy. Also, it only works on items cloned from files in your area. You aren't allowed to dest other people's stuff! reload ------ This destroys the current object and reloads it with its current code. For example, if your workroom is full of junk and you want to reset it to its base status, type: reload here And the room will reset to its default, with the junk gone. QCS COMMANDS ------------ create ------ This is the command that gets the ball rolling. This command is what lets you bring a new thing into existence. The things you can create can be seen by typing \"help create\". Examples are rooms, weapons, doors, and so on. We will be reviewing each of those in later chapters. When you issue this command a generic version of the item you wish to create appears (or, in the case of a room, appears in the direction you specify). Once that generic copy materializes, you can change it to suit your needs using the \"modify\" command. modify ------ I tend to regard this command as the heart and soul of QCS. It's this tool that lets you make your world your own. Your new generic things are not useful or fun until you modify them. A \"generic weapon\" isn't very interesting, but a \"mithrilite poleaxe\" might be just the thing to deal with a pesky dragon. add --- Creatures, rooms, and containers are capable of storing other things. Once you make an ogre, you may want to give him a hammer to wield. After you make that hammer, you use the add command to let the ogre have that wepon in his permanent inventory. delete ------ On the other hand, you may be tired of that ogre after a while. If he is a part of the permanent inventory of a room, you can use the delete command to remove him permanently. Or if you'd rather he have a Kill-O-Zap Frogstar blaster rather than a hammer, get rid of the hammer in his inventory with this command. copy ---- This is a room-specific command. Rather than write multiple, nearly identical rooms for large areas, you can use the copy command to make the room you are almost exactly like any other room you choose, except for the exits, which remain the same. Handy for big forests, cell-blocks, twisty mazes of little passages, etc. initfix ------- If a thing isn't working right, try to initfix it. \"init()\" is an object function that many items need in order to work properly. If you've run into something that is behaving unexpectedly, run initfix on it. The trouble just might clear up. ",({"chapter 35","chapter thirty-five","35",}):"chapter 35 \"QCS: Modifying rooms\" Suppose you are in your sample room and you issued the command: %^GREEN%^create room south testroom1%^RESET%^ You then travel south and see that you are in a room that is almost exactly like the sample room except for the exits. Well, probably you don't want to have a mud with nothing but identical rooms, so let's modify it: %^GREEN%^modify here short Test Room One%^RESET%^ %^GREEN%^modify here long This is the first test room. The walls are rather blank.%^RESET%^ %^GREEN%^modify here climate indoors%^RESET%^ %^GREEN%^modify here light 30%^RESET%^ Ok, so far so good. Standard interior. However, a good mud has rooms with details. Let's add some detail to this room. I've omitted the system output for clarity. This is just what you would input. %^GREEN%^modify here item%^RESET%^ %^GREEN%^wall%^RESET%^ %^GREEN%^walls%^RESET%^ %^GREEN%^blank wall%^RESET%^ %^GREEN%^blank walls%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^These are just blank walls.%^RESET%^ Let's review what we've done here: 1) You issued the modify command specifying your current room as the target, and the SetItems directive as the argument. 2) You entered a query session, and were asked to enter each element of the item's key. 3) You entered a single dot to indicate you were done entering key elements. 4) You entered the value for the key, which is the description of the item. The result of all this is that now you can issue these commands: %^GREEN%^exa wall%^RESET%^ %^GREEN%^look at blank walls%^RESET%^ %^GREEN%^examine walls%^RESET%^ And the output will be: These are just blank walls. Let's add a floor while we're at it: %^GREEN%^modify here item%^RESET%^ %^GREEN%^floor%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^A floor like any other.%^RESET%^ In this case, you didn't feel like adding extra synonyms for \"floor\", so you entered the final dot rather than entering another key element. Then you added the description, and now if you \"exa floor\", you'll get that description. \"about here\" will display to you the file you have modified. Well, that's enough fun with indoor rooms. There's not much more to them. Let's go outdoors now: %^GREEN%^create room south exterior_room%^RESET%^ %^GREEN%^create door south test_door%^RESET%^ %^GREEN%^open door%^RESET%^ %^GREEN%^go south%^RESET%^ %^GREEN%^modify here short a small lawn%^RESET%^ %^GREEN%^modify here daylong A small, well groomed lawn on a lovely sunny day. There is a small building north of here.%^RESET%^ %^GREEN%^modify here nightlong This is a small lawn. Stars twinkle in the night sky above, and some light is coming from a small building to the north.%^RESET%^ %^GREEN%^modify here daylight 30%^RESET%^ %^GREEN%^modify here nightlight 20%^RESET%^ %^GREEN%^modify here light delete%^RESET%^ %^GREEN%^modify here long delete%^RESET%^ %^GREEN%^modify here items delete%^RESET%^ %^GREEN%^modify here items%^RESET%^ %^GREEN%^building%^RESET%^ %^GREEN%^small building%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^A small building, rather ramshackle as if hastily put together.%^RESET%^ %^GREEN%^modify here climate temperate%^RESET%^ Ok! A few new things here. A neat thing about outdoor rooms is that typically they are subject to the time of day. A SetClimate directive that indicates an exterior environment causes the room to receive messages about the sun setting, rising, etc. The SetDayLong and SetNightLong directives allow you to more sensibly describe the area depending on the time of day. To avoid confusion, I deleted the SetLong directive. It is not mandatory to have different day and night descriptions, but players appreciate the effort. It is also possible to have differing ambient light levels depending on the time of day, so we've added SetDayLight and SetNightLight, and we deleted the SetAmbientLight directive. Let's continue to add detail: %^GREEN%^modify here item%^RESET%^ %^GREEN%^lawn%^RESET%^ %^GREEN%^grass%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^Healthy, well groomed and freshly cut grass.%^RESET%^ %^GREEN%^modify here smell%^RESET%^ %^GREEN%^default%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^You can smell the refreshing scent of freshly cut grass.%^RESET%^ %^GREEN%^modify here smell%^RESET%^ %^GREEN%^lawn%^RESET%^ %^GREEN%^grass%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^Yep, it's got that new lawn smell.%^RESET%^ %^GREEN%^modify here listen%^RESET%^ %^GREEN%^building%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^Sounds like someone's fumbling about in there, making a mess. New creators can be so noisy.%^RESET%^ %^GREEN%^modify here item%^RESET%^ %^GREEN%^garden%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^You may enter the garden from here.%^RESET%^ %^GREEN%^create room garden garden_room%^RESET%^ You now have a room with lots of charm and detail. You can \"smell grass\" and \"listen to small building\", if you like. Neat, huh? But there's something very important to keep in mind: Enters, listens and smells don't work properly if there is no item defined for that smell. For example, if you want to be able to listen to the sea, you must \"modify here item\" and add a \"sea\" item. Otherwise, \"listen to the sea\" will respond with \"There is no sea here.\" The only exception to this rule is the \"default\" smell. Enters behave similarly. If you want to be able to \"enter\" something, you'll need to create the corresponding item first, as in the example above. You can use the SetProperties directive to make the room conform to some presets, like: %^GREEN%^modify here property no attack 1%^RESET%^ Read chapter 23 in the Creator's Manual for details on room properties. Also, please note that indoor rooms can also have differing descriptions and light levels for night and day. It's just that indoor rooms don't get notification of daytime changes. Finally, the SetTown directive allows the room to participate in area-wide events, and is useful for security purposes as well: %^GREEN%^modify here town MyTown%^RESET%^ Notes on room filenames: ----------------------- By default, a filename without a leading path creates a room in your area room directory, which in my case would be \"/realms/cratylus/area/room\". However, you can specify a different location for the new room. To create a room in your current working directory: %^GREEN%^create room east ./newroom%^RESET%^ To create a room in a specific directory: %^GREEN%^create room east /realms/cratylus/testrooms/newroom%^RESET%^ ",({"chapter 39","chapter thirty-nine","39",}):"chapter 39 \"QCS: Final notes\" * Remember that QCS commands work on objects, not files. To load a file into memory, use the update command. To reload an already existing object, like a cloned orc or a book, use the reload command. To use modify, delete, and add, you have to specify a cloned object that is on you or in your environment. I think you're getting the idea of how this works. Here's an example of armor creation: %^GREEN%^create armor jeans%^RESET%^ %^GREEN%^modify jeans id%^RESET%^ %^GREEN%^pants%^RESET%^ %^GREEN%^trousers%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^modify jeans short a pair of denim jeans%^RESET%^ %^GREEN%^modify jeans long Worn jeans, frayed and stained.%^RESET%^ %^GREEN%^modify jeans adj%^RESET%^ %^GREEN%^pair of%^RESET%^ %^GREEN%^denim%^RESET%^ %^GREEN%^frayed%^RESET%^ %^GREEN%^worn%^RESET%^ %^GREEN%^stained%^RESET%^ %^GREEN%^.%^RESET%^ To know what directives QCS can change on an object, type: %^GREEN%^help modify%^RESET%^ This provides a list of modifiable things and the directives that can be modified on them. Ultimately the Quick Creation System generates LPC code, so you'll want to review the earlier chapters of this handbook to get a base of understanding of the code that comprises your new creations. Some notes and tips: * The SetNoCondition directive makes it so an item does not report its physical status when examined. Weapons and armor wear down in combat, and most objects let you know their condition when you examine them. However, in some cases (a sandwich for example) this is inappropriate, so the SetNoCondition directive may be useful. * Doors aren't like normal objects. They have to be modified *twice*. Once for each side of the door. If this sounds unnecessarily tedious, remember that a door leading south is also a door leading north from the other room. * Doors generally are not visible in the same way that regular objects are. To make a door especially obvious and noticeable, do something like: %^GREEN%^modify door sethiddendoor 0%^RESET%^ * SetCurrency is for adding money to NPC's. SetMoney is for adding money to non-living containers (bags, etc). * Item subtypes are listed in /include. To know what kinds of vendors are available, for example, look in /include/vendor_types.h * Books need a \"source directory\", which must contain one file per chapter. The SetSource for this manual, for example, is /doc/manual The first line of each file must follow the same format as the files you see in /doc/manual * SetObviousExits is usually no longer needed: rooms report obvious exits automatically. However, if you don't want an exit to show up by default, use the SetObviousExits directive to specify only those that you want seen. This will override the room's default exit display. ",({"chapter 36","chapter thirty-six","36",}):"chapter 36 \"QCS: Modifying weapons\" Remember that the QCS chapters are supposed to be read in sequence. This is important because as we progress, I will not make explanations about directives and concepts explained previously. Weapons are different from rooms and NPC's in that they can be handled, sold, thrown, etc. They are manipulable objects. As such, we will see new directives: %^GREEN%^create weapon hammer%^RESET%^ You may be familiar with this example from the example webpage. Let's go ahead and plow through the commands: %^GREEN%^modify weapon id hammer%^RESET%^ %^GREEN%^warhammer%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^modify hammer name hammer%^RESET%^ %^GREEN%^modify hammer damagetype blunt%^RESET%^ %^GREEN%^modify hammer weapontype blunt%^RESET%^ %^GREEN%^modify hammer mass 700%^RESET%^ %^GREEN%^modify hammer hands 2%^RESET%^ %^GREEN%^modify hammer short a heavy war hammer%^RESET%^ %^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%^ %^GREEN%^modify hammer adj%^RESET%^ %^GREEN%^large%^RESET%^ %^GREEN%^heavy%^RESET%^ %^GREEN%^war%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^modify hammer basecost silver 750%^RESET%^ %^GREEN%^about hammer%^RESET%^ Like a room and unlike an NPC, you can also modify the SetItems on manipulable objects like weapons, so you could do something like this: %^GREEN%^modify hammer item%^RESET%^ %^GREEN%^shaft%^RESET%^ %^GREEN%^handle%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^A thick, reinforced steel shaft with leather bands for a strong grip.%^RESET%^ %^GREEN%^exa shaft on hammer%^RESET%^ ",({"chapter 38","chapter thirty-eight","38",}):"chapter 38 \"QCS: Adding and deleting\" Rooms, containers and NPC's all are capable of holding items, and often it is convenient to have them already holding certain items upon creation. The SetInventory directive in an object's file provides us with a list of that object's \"permanent inventory\". To modify an object's inventory, we use the add and delete commands. Let's say that we want our cowboy to be wielding a hammer when he appears... %^GREEN%^clone cowboy%^RESET%^ %^GREEN%^cd ../weap%^RESET%^ %^GREEN%^clone hammer%^RESET%^ %^GREEN%^add hammer to cowboy%^RESET%^ %^GREEN%^wield hammer%^RESET%^ Believe it or not, it's that simple. The add command will ask you a question after you issue it. What it wants to know is if you want the NPC to do anything special when the hammer appears on him. In this case, yes, we wanted him to wield it. However, if you want to add something to an NPC and don't have anything interesting for him to do with it, respond to the question with the number of items that you want to appear. For example, if I want the cowboy to be carrying a key: %^GREEN%^cd ../obj%^RESET%^ %^GREEN%^clone key%^RESET%^ %^GREEN%^add key to cowboy%^RESET%^ %^GREEN%^1%^RESET%^ And that's it. Now if I want the cowboy to be a permanent resident of this room: %^GREEN%^add cowboy%^RESET%^ %^GREEN%^1%^RESET%^ The add command understands that if you don't specify a target argument, you must mean the room. You can also be specific: %^GREEN%^add cowboy to room%^RESET%^ %^GREEN%^1%^RESET%^ The delete command works the opposite way. It removes items from an object's permanent inventory: %^GREEN%^delete hammer from cowboy%^RESET%^ %^GREEN%^delete cowboy%^RESET%^ The delete command is also the way to get rid of rooms. You won't be removing the file from disk, you'll just be deleting that exit from the room: %^GREEN%^delete exit garden%^RESET%^ NOTE: When you delete an exit, only the connection from your room to the other room is removed. The connection from the other room to your room remains. This is not a bug, it's a feature. There are plenty of circumstances where one-way travel is desirable. ",({"chapter 39","chapter thirty-nine","39",}):"chapter 39 \"QCS: Final notes\" * Remember that QCS commands work on objects, not files. To load a file into memory, use the update command. To reload an already existing object, like a cloned orc or a book, use the reload command. To use modify, delete, and add, you have to specify a cloned object that is on you or in your environment. I think you're getting the idea of how this works. Here's an example of armor creation: %^GREEN%^create armor jeans%^RESET%^ %^GREEN%^modify jeans id%^RESET%^ %^GREEN%^pants%^RESET%^ %^GREEN%^trousers%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^modify jeans short a pair of denim jeans%^RESET%^ %^GREEN%^modify jeans long Worn jeans, frayed and stained.%^RESET%^ %^GREEN%^modify jeans adj%^RESET%^ %^GREEN%^pair of%^RESET%^ %^GREEN%^denim%^RESET%^ %^GREEN%^frayed%^RESET%^ %^GREEN%^worn%^RESET%^ %^GREEN%^stained%^RESET%^ %^GREEN%^.%^RESET%^ To know what directives QCS can change on an object, type: %^GREEN%^help modify%^RESET%^ This provides a list of modifiable things and the directives that can be modified on them. Ultimately the Quick Creation System generates LPC code, so you'll want to review the earlier chapters of this handbook to get a base of understanding of the code that comprises your new creations. Some notes and tips: * The SetNoCondition directive makes it so an item does not report its physical status when examined. Weapons and armor wear down in combat, and most objects let you know their condition when you examine them. However, in some cases (a sandwich for example) this is inappropriate, so the SetNoCondition directive may be useful. * Doors aren't like normal objects. They have to be modified *twice*. Once for each side of the door. If this sounds unnecessarily tedious, remember that a door leading south is also a door leading north from the other room. * Doors generally are not visible in the same way that regular objects are. To make a door especially obvious and noticeable, do something like: %^GREEN%^modify door sethiddendoor 0%^RESET%^ * SetCurrency is for adding money to NPC's. SetMoney is for adding money to non-living containers (bags, etc). * Item subtypes are listed in /include. To know what kinds of vendors are available, for example, look in /include/vendor_types.h * Books need a \"source directory\", which must contain one file per chapter. The SetSource for this manual, for example, is /doc/manual The first line of each file must follow the same format as the files you see in /doc/manual * SetObviousExits is usually no longer needed: rooms report obvious exits automatically. However, if you don't want an exit to show up by default, use the SetObviousExits directive to specify only those that you want seen. This will override the room's default exit display. ",({"chapter 34","chapter thirty-four","34",}):"chapter 34 \"QCS: Modification of NPC's\" In the previous chapter we learned how to make a generic object. Now that we have it, what to do with it? It's important to keep in mind that the generic thing now in front of you isn't just a clone from a template file. If the command you used was \"create npc cowboy\", there is now a file (probably) called /realms/you/area/npc/cowboy.c that contains the code for the creature in front of you. However, this poor beast has the most uninteresting of features. It is in fact so boring that it responds only to its generic type. Such that \"examine cowboy\" or \"kill tex\" won't work. You'll need to \"look at npc\". Accordingly, any modification commands need to be made referring to the new thing with an it responds to, until such a time as you change the id to suit your tastes. Let's carry on with the example of our generic npc. To make a cowboy out of him, we can either change his name, or his id, or both. Let's start with his name: %^GREEN%^modify npc name cowboy%^RESET%^ This makes the SetKeyName() directive in cowboy.c use \"cowboy\" as its argument, effectively allowing you to address this npc as \"cowboy\" from now on. Now you can \"look at cowboy\" with some results. Obviously our NPC isn't *just* a cowboy. He's also a human, a dude, and his name is Tex. How do we make him respond to all of these nouns? %^GREEN%^modify cowboy id%^RESET%^ You'll notice there are no arguments following the word \"id\". Setting a thing's id is different from most other settings. If you'll think back to the LPC datatypes chapter of this manual (you did read the LPC chapters, didn't you?) you'll remember that some information about objects is in the form of strings (\"cowboy\"), some is in the form of integers (the cowboy's health points, for example) and some is in the form of arrays, which are a group of data points. In this example we want the cowboy's id to be an array, because of the many ways we might want to address him. Therefore, we want the SetId directive in his file to look like this: SetId( ({\"human\", \"dude\", \"tex\" }) ); You might think that QCS should be able to accept multiple values like this on a line, perhaps with \"modify cowboy id human dude tex\" as the command. But what if you want this npc to be a \"Boy Named Sue\"? How would you accommodate id's that contain spaces? In designing QCS, I considered having escape characters to allow for such things, but ultimately reasoned that this was just way too much mess. Instead, SetId, and other directives that take arrays as arguments, are handled by entering a query session. Below is an example of what it might look like. The example is necessarily messy because I am including both the queries and the responses. --------------------------------------------------- > %^GREEN%^modify npc name cowboy%^RESET%^ Indenting file... \"/tmp/indent.1136206130.tmp.dat\" 15 lines 420 bytes Exit from ed. > %^GREEN%^modify cowboy 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%^human%^RESET%^ You may now enter the next value. So far, we have: ({ \"dude\", \"human\" }) If you're done entering values, enter a dot on a blank line. %^GREEN%^tex%^RESET%^ You may now enter the next value. So far, we have: ({ \"dude\", \"human\", \"tex\" }) If you're done entering values, enter a dot on a blank line. %^GREEN%^boy named sue%^RESET%^ You may now enter the next value. So far, we have: ({ \"dude\", \"human\", \"tex\", \"boy named sue\" }) If you're done entering values, enter a dot on a blank line. %^GREEN%^.%^RESET%^ Entries complete. Final array is: ({ \"dude\", \"human\", \"tex\", \"boy named sue\" }) Indenting file... \"/tmp/indent.1136206156.tmp.dat\" 19 lines 459 bytes Exit from ed. /open/1136206138: Ok /realms/cratylus/area/npc/cowboy: Ok SetId modification complete. > %^GREEN%^exa tex%^RESET%^ Other than being human, this npc is entirely unremarkable. The male human is in top condition. --------------------------------------------------- If you were now to examine Tex's code (with the command \"about tex\") you'd see that his SetId directive now looks like this: SetId( ({\"dude\", \"human\", \"tex\", \"boy named sue\"}) ); Other NPC features take arrays also. SetAdjectives is one. You might enter this (mud output omitted for clarity): %^GREEN%^modify tex adjectives%^RESET%^ %^GREEN%^dusty%^RESET%^ %^GREEN%^hardy%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^look at dusty cowboy%^RESET%^ There are two other directives that require queries. Things and NPC's can be looked at, but they can also be smelled and listened to, if you add SetSmell and SetListen. The syntax is: %^GREEN%^modify tex smell%^RESET%^ And you will then be asked a question about keys and mappings. Understanding mappings is important, but for now you just need to understand that you are being asked *two* separate questions: 1) What on the cowboy is being smelled/listened to? 2) What is the smell/sound? What this means is that your input will look something like this: %^GREEN%^modify tex smell%^RESET%^ %^GREEN%^default%^RESET%^ %^GREEN%^.%^RESET%^ Tex smells of sweat and manure. What happens is this: - You enter the modify command. - You enter the word \"default\" to indicate this is Tex's general smell. - You enter a dot to indicate that you are done specifying what part of Tex is being smelled. - You then specify the smell. This may seem odd until you realize you can also add smells/listens to parts of things. Not on NPC's, though. We'll look at this more closely in later chapters. For now, just use the syntax as shown above. For adding a listen to the cowboy, it works the same way: %^GREEN%^modify tex listen%^RESET%^ %^GREEN%^default%^RESET%^ %^GREEN%^.%^RESET%^ Tex seems to be humming a jaunty melody. Other features of an NPC do not take arrays, so one-line commands will do. For example: %^GREEN%^modify cowboy long This is a cowboy who calls himself Tex, but is in fact a Boy Named Sue.%^RESET%^ %^GREEN%^modify cowboy short a cowboy%^RESET%^ %^GREEN%^modify cowboy level 5%^RESET%^ %^GREEN%^modify cowboy class fighter%^RESET%^ %^GREEN%^modify tex currency gold 1%^RESET%^ %^GREEN%^modify tex currency silver 12%^RESET%^ %^GREEN%^modify tex skill bargaining 5%^RESET%^ %^GREEN%^modify tex skill projectile attack 7%^RESET%^ %^GREEN%^modify tex stat strength 33%^RESET%^ %^GREEN%^modify tex property nice guy 1%^RESET%^ %^GREEN%^modify tex healthpoints 150%^RESET%^ %^GREEN%^modify tex maxhealthpoints 170%^RESET%^ %^GREEN%^modify tex melee 0%^RESET%^ %^GREEN%^modify tex unique 1%^RESET%^ If you now issue the \"about tex\" command you will see that all the changes you made have been put into the file. You may have noticed the \"melee\" keyword. Dead Souls 2 NPC's come in various shapes and sizes, and some of them shouldn't wield weapons. A wolf with a battle axe would be a strange sight indeed. However, the default combat system makes unarmed creatures extremely vulnerable in combat. To make an NPC combat-capable without weapons, use the new SetMelee directive. SetMelee(1) makes the NPC capable of proper unarmed combat. SetMelee(0) makes the NPC a weak opponent if unarmed. NPC's will generally try to bite during unarmed combat. If this is beneath the capability or dignity of your NPC, you can prevent this with: %^GREEN%^modify tex canbite 0%^RESET%^ If your NPC should try to escape when the battle isn't going his way, the wimpy settings should do: %^GREEN%^modify tex wimpy 30%^RESET%^ %^GREEN%^modify tex wimpycommand climb ladder%^RESET%^ If you don't specify a wimpy command, Tex will leave the room through a random exit. In this case, when Tex's health is down to 30% and he is in combat, he will try to climb a ladder. Some NPC's are designed to travel about. To enable this feature, use the wanderspeed directive: %^GREEN%^modify tex wanderspeed 5%^RESET%^ If you want him to travel more quickly, use a lower number. By default, wandering NPC's only wander in rooms that have already been loaded into memory. They avoid loading rooms because loading a bunch of rooms that only the NPC will ever see is a waste of your mud's resources. However, if you *do* want your NPC to wander in an unrestricted manner, regardless of whether a room is loaded, use the permitload directive: %^GREEN%^modify tex permitload 1%^RESET%^ By default, NPC's stand up when they can. This is so that if they collapse during combat, they try to get back up once they are able to do so. If you prefer that your NPC maintain some other posture, you can set that posture, then disable autostanding like this: %^GREEN%^modify tex posture lying%^RESET%^ %^GREEN%^modify tex autostand 0%^RESET%^ If he's especially lazy, you can have him take a nap this way: %^GREEN%^modify tex sleeping 10%^RESET%^ Which will have him wake up after about a minute. However, note that if you've disabled autostanding, he will remain lying down after he wakes up. If the NPC should be hostile, that is, he should attack any creatures that it sees enter a room, SetEncounter should do it: %^GREEN%^modify tex encounter 100%^RESET%^ This means that if the creature it sees has a charisma score of less than 100 (which should pretty much be always true), Tex will try to kill it. You can do some fancy stuff with SetEncounter, such as only attacking orcs, or actually doing something friendly, but to do so you can't use QCS. Read the NPC and Sentients chapter in the Creator's Manual for details on how to code such stuff. If the NPC is a golem or other such non-biological creature, it may be useful to specify what they are made of. The SetComposition setting for a clay golem might look like this: %^GREEN%^modify golem composition clay%^RESET%^ If it happens to be a golem that does not believe in violence as a solution to problems, you can make refuse to hurt others with the following: %^GREEN%^modify golem pacifist 1%^RESET%^ Vendors: ------- Vendors are a special kind of NPC that can sell stuff. Along with the standard NPC settings, vendors have the following: SetStorageRoom specifies where the vendor's stock is stored. If a valid room is specified, anything in that room can be sold by the vendor. SetLocalCurrency specifies the type of currency, such as gold or silver, that the vendor accepts. SetMaxItems is the maximum number of items in the storeroom that the vendor is permitted to sell. SetVendorType specifies the kind of stuff the vendor can trade in. \"all\" allows him to buy and sell whatever. But if he is a weapon vendor, he can't trade in armor, etc. See /include/vendor_types.h for the available vendor types. To have a \"multi-type\" vendor, you'll have to code it by hand. The result of that looks something like this: SetVendorType( VT_TREASURE | VT_ARMOR | VT_HERBS ); Barkeeps: -------- Like vendors, barkeeps sell stuff, but they are limited to selling food and drink. Unlike vendors, barkeeps have no limitation on the amount of stuff they can sell. They also do not have a storeroom. The stuff they can sell is specified in their SetMenu directive, like this: %^GREEN%^clone woody%^RESET%^ You clone a generic barkeep (/realms/temujin/area/npc/woody.c). %^GREEN%^modify woody menu%^RESET%^ If you don't understand these questions, type the letter q on a blank line and hit enter. Please enter the first key element for this mapping: %^GREEN%^bourbon%^RESET%^ Please enter the next key element, or enter a single dot to finish entering key elements. %^GREEN%^whiskey%^RESET%^ Please enter the next key element, or enter a single dot to finish entering key elements. %^GREEN%^.%^RESET%^ Please enter the value for key ({ \"bourbon\", \"whiskey\" }): %^GREEN%^/domains/town/meals/bourbon%^RESET%^ Barkeeps also have the SetLocalCurrency directive to specify the currency they accept. ",]),"/doc/bguide/chapter08":1203153606,"/doc/bguide/chapter07":1203153606,"/doc/bguide/chapter06":1203153606,]),"/domains/town/txt/shame":(["object":"/domains/town/obj/shamelog","title":"Untitled","items":([({"chapter 3","chapter three","3",}):"\"September 11 2001 (Warning: not that funny)\" ",({"chapter 5","chapter five","5",}):"\"The Great Heat Radiation Debate, December 1999\" ",({"chapter 4","chapter four","4",}):"\"Cratylus Has His Buttons Pushed\" ",({"chapter 1","chapter one","1",}):"\"Duuk Kills a Newbie\" ",({"chapter 2","chapter two","2",}):"\"The Demise of Wolfsong\" ",]),"/domains/town/txt/shame/chapter05":1152072075,"index":" Untitled Chapter 1: \"Duuk Kills a Newbie\" Chapter 2: \"The Demise of Wolfsong\" Chapter 3: \"September 11 2001 (Warning: not that funny)\" Chapter 4: \"Cratylus Has His Buttons Pushed\" Chapter 5: \"The Great Heat Radiation Debate, December 1999\" ","/domains/town/txt/shame/chapter04":1152072075,"reads":([({"chapter 3","chapter three","3",}):"chapter 3 \"September 11 2001 (Warning: not that funny)\" [igossip] Hellmonger@Trilogy: actually, I think efnet.net got rooted and they just took the server down. [igossip] Alric@Nanvaent: efnet is still up. [igossip] Smack@Lima Bean: ZIONIST NAZIS!!!!!!!!!!!!!!!!!! [igossip] Motorhed@Trilogy says, \"Four out of five doctors agree. I am the fifth doctor. I hope you die. Fuck you.\" [igossip] Shandor@Bakhara: we had a student riot over the weekend! [igossip] Malic@Lima Bean: http://mdn.mainichi.co.jp/waiwai/0109/010909diet.html. [igossip] Blue@Lima Bean: of all the igossip questions for me to be able to answer, one about boxer shorts was _not_ the one I expected. [igossip] Ninja@VargonMUD: SHARK!!! [igossip] Zeddicus@Haven: ARBORPHILES!!! [igossip] Ninja@VargonMUD: Once ya hug a lumberjack, ya'll never hug a tree again! [igossip] Hellmonger@Trilogy: THE NUKES ARE FALLING. [igossip] Hellmonger@Trilogy: FRM THE SKIES. [igossip] Hellmonger@Trilogy: AS TERRORISTS TORCH THE U.S. [igossip] Hellmonger@Trilogy: ITS A HORIBLE DAY. [igossip] Hellmonger@Trilogy: AHHHHHHHHH I'M MELTING. [igossip] Al@Anarres II: HM, shut up. [igossip] Hellmonger@Trilogy: I just heard two planes crahsed into the trade center. [igossip] Al@Anarres II: and very f*cking news iste is down for me ATM :( [igossip] Zeddicus@Haven: Good for them. [igossip] Nirvan@Nanvaent: yeah - two big jets. [igossip] Hellmonger@Trilogy: Yeah, how fucked. [igossip] Nirvan@Nanvaent: one for each tower - I 'm trying to work out if its April 1st somewhere... [igossip] Hellmonger@Trilogy: I vote we turn the fucking middle east into a large sheet of glass. [igossip] Al@Anarres II: its a terrorist thing! [igossip] Hellmonger@Trilogy: I'm glad I don't live in england, where there are a lot of terrorists. [igossip] Al@Anarres II: it makes life fun! [igossip] Al@Anarres II: nightly bulletins saying some irish bloke has shot another. [igossip] AndrewH@Anarres II: keeps the irish population down. like the potato famine. [igossip] Al@Anarres II nods [igossip] Al@Anarres II: its most definetly terrorist. [igossip] Al@Anarres II: two planes, two towers.. thats not just unlucky. [igossip] Al@Anarres II: well, back to work... [igossip] Zeddicus@Haven: A father came in the bedroom to find his 13-year-old daughter smoking a cigarette. \"My God! How long have you been smoking?\" screams the father. \"Since I lost my virginity,\" replies the girl. \"You lost your VIRGINITY!!! When the hell did this happen?\" shrieks the father. \"I don't remember,\" says the girl. \"I was completely drunk.\" [igossip] Smack@Lima Bean: holy fuck. [igossip] Hellmonger@Trilogy: yeah no doubt. [igossip] Hellmonger@Trilogy chants: \"Nuke The Middle East! Nuke The Middle East! Nuke The Middle East!\" [igossip] Al@Anarres II: why do you say its the middle east? you said that about oklahoma and it was some US bloke. [igossip] Styxx@OuterSpace: shaddup. [igossip] Al@Anarres II: you HM, are a racist homophobe. [igossip] Hellmonger@Trilogy: You are obviously a jew-sympathiser. You will burn with your dirty hebrew friends. [igossip] Al@Anarres II: hmmm. HM, shut the fuck up. [igossip] Smack@Lima Bean: whoever it is must die. [igossip] Hellmonger@Trilogy: Al, do you worship Osama Bin Laden? [igossip] Hellmonger@Trilogy: Why can't people pick new and exciting targets for their terrorist acts? [igossip] Hellmonger@Trilogy: 'Lets blow up the world trade center!' 'Lets crash into the world trade center!' [igossip] Al@Anarres II grins at HM, \"I only worship you\" [igossip] Hellmonger@Trilogy: Al, you must blow up the quik-mart. The infidels must pay. [igossip] Nirvan@Nanvaent: wouldn't it be a better statement to fly the plane into the white house ? [igossip] Sinistrad@VargonMUD: Harder to do. [igossip] Nirvan@Nanvaent: or are the protests against the WTO stepped up from hippies throwing rocks in the streets ? [igossip] Nirvan@Nanvaent: *blinks* [igossip] Al@Anarres II: maybe they were passenger planes and someone at air traffic f*cked up? [igossip] Sinistrad@VargonMUD: BREAKING NEWS: One of the planes was being flows by Captain Hazelwood, of the Exxon Valdez! [igossip] Nirvan@Nanvaent: harder than hijacking two 747s and flying them into the center of NY ? [igossip] Al@Anarres II: doesn;t Xyzzy have summin' to do with flying things? [igossip] Sinistrad@VargonMUD: Yes, Nirvan. Why are you so... curious? [igossip] Nirvan@Nanvaent: so the SDN is working over the white house then ? [igossip] Sinistrad@VargonMUD: Try making a hijacked plane hit a ground target. [igossip] Al@Anarres II: good point Sini. [igossip] Nirvan@Nanvaent: ahh - so you've thought ab out this then ? [igossip] Nirvan@Nanvaent: it is a good point. [igossip] Sinistrad@VargonMUD: No, I just work for the FBI. But you, on the other hand.. *shuffles papers* Nirvan, AKA \"Idi Ib Amin\".. why are YOU so curious? [igossip] Nirvan@Nanvaent: woo - breaking news. CNN have decided that it isn't an accident ! [igossip] Skullslayer@RoD: so anyone got a good news site with live feed, that isn't down(DoS'd)? [igossip] Nirvan@Nanvaent: turn on a TV ? [igossip] Skullslayer@RoD: haha not an accident - thats clever [igossip] Skullslayer@RoD: I'm at work, and there is no tv here [igossip] Pickett@Sumu: http://a799.ms.akamai.net/3/799/388/9ce0ee0b875c5d/www.msnbc.com/news/1160603.j pg. [announce] Xyzzy enters Frontiers. [igossip] Nirvan@Nanvaent: MSN Search : We can't find \"cnn.com\". [igossip] Nirvan@Nanvaent: oh god - someone's bombed CNN! [cre] Cratylus: oi. /wiz/cratylus # [igossip] Nirvan@Nanvaent: slashdot is even running the story - because CNN is DOS'ed :) [igossip] Al@Anarres II: is CCN DoS'd or just very busy? [igossip] Sinistrad@VargonMUD: Try CNN instead of CCN. [igossip] Sinistrad@VargonMUD: Maybe you'll get somewhere. [igossip] Skullslayer@RoD: very busy is a DoS - so is MSNBC and ABCnews [igossip] Al@Anarres II: DoS implied bad intent. [igossip] Al@Anarres II: rather than just lots of happy punters. [igossip] Vashkar@Split Infinity: haha.. dailynews.yahoo.com changed their story to simply \"A plane crashed into one of the twin towers of the World Trade Center Tuesday, witnesses said.\" and that's it.. it loads just fine now :) [igossip] Skullslayer@RoD: they're hit by the slashdot effect, except on a bigger scale [igossip] Xyzzy: wtf. [igossip] Sinistrad@VargonMUD: Jesus, that's impressive. [igossip] Cratylus: thats so fucked up. /wiz/cratylus # [igossip] Undh@Sumu: impressive.. yeah .) /wiz/cratylus # [igossip] Sinistrad@VargonMUD: If I were a terrorist, I would have waited until more people were at work. [igossip] Nirvan@Nanvaent: 9am isn't a bad time... [igossip] Bayard@Nanvaent: morning meetings happening. people mainly in at 8am. [igossip] Blue@Inon-Net: people start work at 8 in most of those companies. [igossip] Bayard@Nanvaent: all gathered together in rooms. [cre] Xyzzy: thats fucked up, dude. [igossip] Nirvan@Nanvaent: a good day not to be too highly promoted I would guess. [igossip] Al@Anarres II: hmm, 2nd plane \"was passenger 727\"... oops. [igossip] Skullslayer@RoD: yeah, FBI was investigating a report of a hijacking at the time [cre] Cratylus: bizarre. /wiz/cratylus # [igossip] Nirvan@Nanvaent: bush wants to 'hunt down the people who did this' [igossip] Al@Anarres II: nice - hijack a plane full of US citizen and then crash it into the trade center :) sweet. [igossip] Nirvan@Nanvaent: get me my gun, maw... [igossip] Cratylus: well it's easier than carting a bomb in there, with their current security. /wiz/cratylus # [igossip] Sinistrad@VargonMUD: look in 'the charred remains between floor 98 and 99' [igossip] Nirvan@Nanvaent: seems there is a 3rd plane that's been hijacked ? [igossip] Cratylus: i guess they'll need to install antiaricraft turrets now. /wiz/cratylus # [igossip] Xyzzy: YES! [igossip] Hellmonger@Trilogy: hell yeah. [igossip] Sinistrad@VargonMUD: Whoever invents the force field will make a billion. [igossip] Xyzzy: but, we already HAVE. [igossip] Al@Anarres II: if someone wants to be a terrorist, they'll be a terrorist. [igossip] Xyzzy: the antimissile shield will protect us! [igossip] Cratylus: and if they want to sing out, sing out. /wiz/cratylus # [igossip] Styxx@OuterSpace: asia.cnn.com still works. [igossip] Skullslayer@RoD: a 3rd plane? [igossip] Nirvan@Nanvaent: the pentagon is on fire. [igossip] Steve@Anarres II: pentagon on fire? [igossip] Cratylus: cats and dogs, living together. /wiz/cratylus # [igossip] Nirvan@Nanvaent: and the palestinians are claiming responsibility. [igossip] Xyzzy: dont cross the streams. [igossip] Nirvan@Nanvaent: and my boss wanted me to go to israel last week. [igossip] Sinistrad@VargonMUD: Ooh, ht//praiseallah.terrorists.com has the inside report! [igossip] Cratylus: jesus, a 767 /wiz/cratylus # [igossip] Sinistrad@VargonMUD: The pentagon IS on fire! [igossip] Cratylus: thats a lot of aircraft. /wiz/cratylus # [igossip] Xyzzy: wow. [igossip] Sinistrad@VargonMUD: WOOOOOOO!!!!! [igossip] Xyzzy: co-worker just said pentgon IS on fire. [igossip] Sinistrad@VargonMUD: Shit, this is really cool. [igossip] Al@Anarres II: cool :) You guys have better terrorists! [igossip] Sinistrad@VargonMUD: Guys, if you're in any kind of important building.. RUN! [igossip] Hellmonger@Trilogy: My Unc works at the pentagon. :( [igossip] Cratylus: did they drop a plane on the pentagon as well? /wiz/cratylus # [igossip] Xyzzy: fuck this, im goin home. [igossip] Sinistrad@VargonMUD: Not so happy now, eh? [igossip] Al@Anarres II cheers for Xyzzy [igossip] Hellmonger@Trilogy: heh. [igossip] Xyzzy: no, as in, i dont wanna be in this building. [igossip] Sinistrad@VargonMUD: Wtf, is today Allah's birthday or something? [igossip] Cratylus: can someone post a burning-pentagon url? /wiz/cratylus # [igossip] Nirvan@Nanvaent: white house has been evacuated. [igossip] Nirvan@Nanvaent: pentagon is on fire, and been evacuated. [igossip] Blue@Inon-Net: if you were going to start a nuclear war, which two buildings would you want to have evacuated first? [igossip] Nirvan@Nanvaent: today is the 20th anniversary of the UN international day of peace. [igossip] Blue@Inon-Net: I guess they still have NORAD or some such place. [igossip] Nirvan@Nanvaent: but war games was on the TV at the weekend. [igossip] Sinistrad@VargonMUD: No shit, Nirvan? [igossip] Nirvan@Nanvaent: I know how to get in ther! [igossip] Cratylus: i'm too tired for this to be Anarchy Day. /wiz/cratylus # [igossip] Xyzzy: hmm, that is, if i CAN leave... [igossip] Sinistrad@VargonMUD: I know how to get into the Pentagon, too: Through the gaping hole. [igossip] Al@Anarres II: the pentagon has like, 12 stories going down and a power plant and such. Its paper pushers up top. [cre] Cratylus: is the pentagon really burning? /wiz/cratylus # [cre] Xyzzy: yes. [cre] Xyzzy: it was bombed. [cre] Cratylus: whew. /wiz/cratylus # [cre] Xyzzy: apparently. [cre] Xyzzy: this base is closed. [cre] Xyzzy: no one gets on. [igossip] Al@Anarres II: this is class :) brightened up my afternoon no end. [igossip] Cratylus: all your trade center are belong to us. /wiz/cratylus # [igossip] Nirvan@Nanvaent: CNN showing a big fire near washington. [cre] Cratylus: i'd go home. /wiz/cratylus # [cre] Cratylus: traffic will really suck later. /wiz/cratylus # [igossip] Skullslayer@RoD: slashdot is down now too :) [igossip] Diruces@Mystic: they say they have exvacuated the west wing of the whitehouse too. [cre] Cratylus: and they'll drop a plane on the highway. /wiz/cratylus # [igossip] Nirvan@Nanvaent: I saw a comment on slashdot wondering if there was a 'cyberattack' going on at the same time - what a dumb fuckwith. [igossip] Skullslayer@RoD: most people on slashdot are fuckwits [igossip] Nirvan@Nanvaent: where is washington amll ? [igossip] Nirvan@Nanvaent: where is washington mall even. [igossip] Xyzzy: lessee.... commerce... military... [igossip] Sinistrad@VargonMUD: Around the Pentagon. [igossip] Diruces@Mystic: next the whitehouse. [igossip] Xyzzy: mall is accross the river, in VA. [igossip] Xyzzy: er. [igossip] Xyzzy: the pentagon is in VA. [igossip] Cratylus: thank god, whitehouse.com hasn't been bombed. /wiz/cratylus # [cre] Xyzzy: really, whats next. [igossip] Sinistrad@VargonMUD: Your old password still work there? [igossip] Diruces@Mystic: i like the idea of cheney as pres. [igossip] Nirvan@Nanvaent: apparently the pentagon fire was caused by a plane or rocket attack. [cre] Xyzzy: \"if this was a coordinated attack, what ELSE might be happening rigt now?\" [cre] Xyzzy: then tehre weas the pentagon. [igossip] Nirvan@Nanvaent: bush is at some school somewhere. [igossip] Nirvan@Nanvaent: probs learning how to spell. [igossip] Sinistrad@VargonMUD: Was. [igossip] Nirvan@Nanvaent: the third hijacked plane apparently hit the pentagon. [igossip] Al@Anarres II: bush is in a bunker! [igossip] Xyzzy: what. [igossip] Xyzzy: next. [igossip] Blue@Inon-Net: playing golf at a time like this... just like his dad. [igossip] Cratylus: with his teddy bear. /wiz/cratylus # [igossip] Nirvan@Nanvaent: well, he was in a bunker with lots of school kids around him. [igossip] Xyzzy: any bets? [igossip] Nirvan@Nanvaent: unless they recorded it. [igossip] Cratylus: curled up under a desk. /wiz/cratylus # [igossip] Xyzzy: thumb in mouth. [igossip] Xyzzy: rockingh back n forth. [igossip] Nirvan@Nanvaent: xyzzy : 10 to 1, jenna bush gets drunk and falls around in public in downtown austin this weekend. [igossip] Nirvan@Nanvaent: naw, make that 2 to 1 [igossip] Nirvan@Nanvaent: bbc is reporting 6 people killed in the crashes (that all ???) [igossip] Cratylus: \"Jenna Bush's federally protected wetlands now open for public drilling\" /wiz/cratylus # [igossip] Nirvan@Nanvaent: FAA has grounded all flights in the US. [cre] Cratylus: it's days like this when i kinda wish i had cable tv. /wiz/cratylus # [igossip] Musashi@Sumu: where'd you read that? [igossip] Nirvan@Nanvaent: AP. [cre] Xyzzy: we have a tv, but theres a meeting in tehre now. [cre] Xyzzy: i hafta rely on YOU GUYS for news. [cre] Cratylus: ME? /wiz/cratylus # [cre] Cratylus: i dunno NOTHIN. /wiz/cratylus # [cre] Xyzzy: hmm, should i go home? [igossip] Nirvan@Nanvaent: 'the associated press' [igossip] Nirvan@Nanvaent: or the standard 'newswire' [igossip] Sinistrad@VargonMUD: CONFIRMED: It was a plane that crashed into the Pentagon, too. [igossip] Sinistrad@VargonMUD: CNN is law. [igossip] Sinistrad@VargonMUD: If CNN makes up stuff about aliens, I believe it. [igossip] Nirvan@Nanvaent: who was saying it was really difficult to hit ground targets with planes ? :) [igossip] Nirvan@Nanvaent: did they miss ? [igossip] Sinistrad@VargonMUD: \"Aliens crashed into the Pentagon\" I'll believe it. [igossip] Skullslayer@RoD: heh, lots of the US govt agencies get their info from CNN since its cheaper than having their own people in the field [igossip] Blaze@VargonMUD: All american flights have been grounded. [igossip] Nirvan@Nanvaent: it was - illegal Aliens crashed into the Pentagon. [igossip] Sinistrad@VargonMUD: Heh =-) [igossip] Xyzzy: ALIENS BOMBED THE PENTAGON?!?! [igossip] Cratylus: those two targets seem kinda pointless to. /wiz/cratylus # [igossip] Cratylus: me. /wiz/cratylus # [igossip] Nirvan@Nanvaent: which ones ? [igossip] Xyzzy: \"she thought they said 'ILLEGAL aliens' and signed up\" [igossip] Bayard@Nanvaent: symbolic Crat. [igossip] Cratylus: they shoulda found bush's locaation and dropped a plane on him. /wiz/cratylus # [igossip] Bayard@Nanvaent: very symbolic. especially outside of US. [igossip] Sinistrad@VargonMUD: Maybe it was Jenna Bush flying daddy's plane. [igossip] Nirvan@Nanvaent: he was in a school. [igossip] Al@Anarres II: hijacking any plane and crashing it is gonna get you coverage. ------------------------------------------------------------------------ F r o n t i e r s (EDT is: Tue Sep 11 09:53:36 2001) There are 3 users connected. ------------------------------------------------------------------------ Xyzzy 4s Low Crawl access4.digex.net Zaphod 11h empty plain 77.163.252.64.snet.net Cratylus Cratylus' Cubicle cratylus ------------------------------------------------------------------------ /wiz/cratylus # [igossip] Blue@Inon-Net: American spy plane disappeared over Iraq today. [igossip] Sinistrad@VargonMUD: Xy, the actress who played Valdez in that movie actually showed up at casting time thinking the movie WAS about illegal aliens. They kept the \"inside joke\" in the movie. [igossip] Nirvan@Nanvaent: unmanned US spy plane. [igossip] Cratylus: vasquez. /wiz/cratylus # [igossip] Xyzzy: ya, i read that on IMDB :) [igossip] Nirvan@Nanvaent: you know the real big question about all this ? Who has the movie rights ? [igossip] Xyzzy: me. [igossip] Nirvan@Nanvaent: when will Tom Clancey's book come out ? [igossip] Blue@Inon-Net: Tom Clancy already wrote this book :) [igossip] Bayard@Nanvaent: \"Why hasn't Tom Clancy forseen this!\" [igossip] Cratylus: clancey's book will have biological weapons in the planes. /wiz/cratylus # [igossip] Blue@Inon-Net: I bet that's where they got the idea. [igossip] Skullslayer@RoD: he did the book years ago [igossip] Xyzzy: wait, whata bout the unmanned Am. spyplane? [igossip] Al@Anarres II: I lost one of my peers in NYC... wonder why. [igossip] Cratylus: im still waiting for them to nuke a football stadium, like he said. /wiz/cratylus # [igossip] Xyzzy: ah, ok, i see the story. [igossip] Nirvan@Nanvaent: israel was moving in to palestine today - [igossip] Xyzzy: GIT MAH GUN! [igossip] Cratylus: they highjacked an unmanned us spy plane and crashed it into the iraqui desert! those madmen! /wiz/cratylus # [igossip] Musashi@Sumu: so has anyone claimed responsibility for this yet? [igossip] Nirvan@Nanvaent: palestinians, [igossip] Nirvan@Nanvaent: the IRA, Iraq want a piece... [igossip] Bayard@Nanvaent: the NBA. [igossip] Nirvan@Nanvaent: problem is, everyone will try to claim it. [igossip] Xyzzy: not to jinx us, but it seems that you never know when the shit is gonna hit the fan like this. [igossip] Cratylus: the judean people's front. /wiz/cratylus # [igossip] Xyzzy: SPLITTERS! [igossip] Blue@Inon-Net: it's the anti-globalisation protesters. [igossip] Bayard@Nanvaent: people's judean front. [igossip] Blue@Inon-Net: think about it: the World Trade Centre. [igossip] Xyzzy: and? [igossip] Iain@Anarres II: popular peples front of judea. [igossip] Blue@Inon-Net: They got it confused with the WTO. [igossip] Xyzzy: WWF? [igossip] Izzy@VargonMUD: I think it was just a big misunderstanding. [igossip] Nirvan@Nanvaent: state dept on fire. [igossip] Nirvan@Nanvaent: another plane just hit. [igossip] Xyzzy: WHAT? [igossip] Nirvan@Nanvaent: south tower of the WTO has collapsed. [igossip] Presto@Discworld: fuckin hell. [igossip] Musashi@Sumu: jesus, I'm not going to be able to get cricket results for the next 4 weeks with this flooding the news... [igossip] Xyzzy: at least we dont hafta hear about gary conit anymore. [igossip] Xyzzy: er, conDit. [igossip] Nirvan@Nanvaent: capitol building and treasury evacuated. [igossip] Nirvan@Nanvaent: most of manhantten under smoke/ on fire. [igossip] Al@Anarres II goes to thebunker.net [igossip] Blaze@VargonMUD: And a couple in SF. The trans-america building too. [igossip] Nirvan@Nanvaent: sears tower in chicago attacked too. [igossip] Al@Anarres II: nice! [igossip] Xyzzy: overheard at work: USA today building. [igossip] Presto@Discworld: not attacked, evacuated. [igossip] Al@Anarres II lives no where near anything tall :) [igossip] Cratylus: can't believe it didnt occur to them to drop a plane on clinton's harlem office. /wiz/cratylus # [igossip] Nirvan@Nanvaent: who cares about clinton ? [igossip] Cratylus: best way to intimidat current presidents is killing former ones. /wiz/cratylus # [igossip] Nirvan@Nanvaent: saw the 'third explosion' replay - looked like the building just collapsed inwards. [igossip] Al@Anarres II: nice, the BBC have \"given up\" trying to get their sites up :)) [igossip] Skullslayer@RoD: clinton is in australia at the moment anyway [igossip] Pickett@Sumu: wtc collapsed? [igossip] Skullslayer@RoD: south tower [igossip] Cratylus: the whole thing fell? /wiz/cratylus # [igossip] Tarl@Alsherok: He is ? Crap. Any idea where in Australia ? [igossip] Presto@Discworld: top half. [igossip] Presto@Discworld: as opposed to the bottom half. [igossip] Skullslayer@RoD: golf resort [igossip] Xyzzy: heh. [igossip] Cratylus: that is a lot of cead people. /wiz/cratylus # [igossip] Xyzzy: so, sears tower, too? [igossip] Cratylus: hard to believe so much of it would fall off from a plane crash. /wiz/cratylus # [igossip] Presto@Discworld: no. [igossip] Xyzzy: fuck, i need a list, here. [igossip] Pickett@Sumu: ... President Bush, .. from a school in Sarasota, Fla... [igossip] Presto@Discworld: Well, Jesus, it wasn't a Cessna, it was a frigging 737/767 depending on who you believe. [igossip] Cratylus: i say we cut off aid to israel until they handle their terrorist problem. /wiz/cratylus # [igossip] Pickett@Sumu: total three planes crashed in wtc. the last one caused the tower to collapse. [igossip] Xyzzy: overheard at work: whitehouse has smoke comng out of it. [igossip] Blue@Inon-Net: it's not exactly \"their\" problem any more. [igossip] Sinistrad@VargonMUD: BREAKING NEWS: Dave Matthew's song \"Crash into me\" said to have inspired the terrorists! [igossip] Cratylus: well its all coming from there, one way or another. /wiz/cratylus # [igossip] Xyzzy: THREE? [igossip] Presto@Discworld: It didn't look to me like there was a third crash into the WTC, looked like it just fell. [igossip] Cratylus: it aint the IRA dropping planes in NYC. /wiz/cratylus # [igossip] Pickett@Sumu: yeah, a third (smaller) plane in the bottom part of the tower caused it to fall. [igossip] Xyzzy: maybe they stored a plane in the basement. [igossip] Presto@Discworld: CNN now says the Sears Tower has NOT been evacuated. [igossip] Blue@Inon-Net: if I were working there, I'd have evacuated. [igossip] Sinistrad@VargonMUD: Thank you, Presto. *Presses a button labeled \"Sears\"* [igossip] Cratylus: if i worked there, i'd have evacuated my bowels. /wiz/cratylus # [igossip] Skullslayer@RoD: is the whitehouse hit confirmed? [igossip] Cratylus: no whitehouse.com is safe. /wiz/cratylus # [igossip] Cratylus: and how do you slay a skull, anyway? /wiz/cratylus # [igossip] Skullslayer@RoD: very carefully [igossip] Xyzzy: with a skullslaying device. [igossip] Skullslayer@RoD: exec building next to the whitehouse hit? [igossip] Sinistrad@VargonMUD: Jesus Christ! [igossip] Al@Anarres II: well, the Dow and NASDAQ are both up. [igossip] Xyzzy: alright, everyone keep their rumors to themselves, please only give us confirmed hits. [igossip] Blue@Inon-Net: is he responsible, or been hit? [igossip] Presto@Discworld: trading is closed. [igossip] Vashkar@Split Infinity: capitol hill .. another explosion. [igossip] Al@Anarres II: would all US resident, please leave the country. [igossip] Cratylus: remain calm, do not run. /wiz/cratylus # [igossip] Al@Anarres II: head for Canada! [igossip] Sinistrad@VargonMUD: I miss the twin towers. [igossip] Xyzzy: pretty sad when im relying on you guys for news. [igossip] Myrias@Discworld: I logged on for news too. [igossip] Blue@Inon-Net: they'll have to reprint all those NYC t-shirts, shot glasses, posters, everything. [cre] Cratylus: thats pathetic. /wiz/cratylus # [igossip] Myrias@Discworld: The major news websites are all crashing under the weight of traffic. [cre] Cratylus: i cant believe cnn got overwhelmed. /wiz/cratylus # [igossip] Blue@Inon-Net: no, they've been hit by more planes! [igossip] Skullslayer@RoD: so, any bets on the FBI or CIA going out next? [cre] Cratylus: dispensing breaking news is their JOB. /wiz/cratylus # [cre] Cratylus: i wnt them FIRED. /wiz/cratylus # [igossip] Xyzzy: youd think cnn would be their FIRST target. [cre] Xyzzy: yer on cre. [igossip] Bayard@Nanvaent: anyone started any rumours about massive virtual terrorism attack on the US websites? [cre] Cratylus: i know. /wiz/cratylus # [igossip] Musashi@Sumu: no way, they want people to know. [cre] Xyzzy: ah. [igossip] Bayard@Nanvaent: i'm sure there's mileage in that one. [igossip] Xyzzy: anyone familiar with the laws concerning gun possession and transport in the state of maryland? [igossip] Al@Anarres II: right now X, no one will care. [igossip] Xyzzy: GOOD POINT! [igossip] Presto@Discworld: explosion on Capitol hill. [igossip] Xyzzy: where. [igossip] Presto@Discworld: or not. [cre] Cratylus: cant believe i have to turn on the radio for news now. /wiz/cratylus # [igossip] Vashkar@Split Infinity: no, that's what happened. [igossip] Xyzzy: is todays date of any signifigance? [igossip] Skullslayer@RoD: apparently CNN is reporting a Capitol Hill hit [igossip] Presto@Discworld: I wish people would get their fucking story straight. :-b. [igossip] Sinistrad@VargonMUD: 20th anniversary of world peace, Xy. [igossip] Sinistrad@VargonMUD: CNN is reporting everything's ok on Capitol Hill, except a loud sound. [igossip] Vashkar@Split Infinity: oh. [igossip] Presto@Discworld: CNNfn is talking to someone on Pennsylvania Ave, and they said there's no explosion. [igossip] Izzy@VargonMUD: It's the Democrats complaining. [igossip] Cratylus: npr's interviewing freaked out WTC occupants. /wiz/cratylus # [igossip] Xyzzy: now THATS journalistic integrity. [igossip] Cratylus: it's quite tedious. /wiz/cratylus # [igossip] Xyzzy: can you imagine the traffic and general panic? [igossip] Cratylus: huh. the upper part of one of them did in fact collapse. /wiz/cratylus # [igossip] Skullslayer@RoD: a few players here have confirmed capitol hill as being hit [igossip] Blue@Inon-Net: Interesting that of all the scary talk over recent years about how easy it would be for terrorists to deploy biological, chemical, nuclear or other fancy weapons in NYC, that when it actually happens, it could have been done the same way 20 years ago. [igossip] Presto@Discworld: Empire State building now evacuated. Duh. [igossip] Sinistrad@VargonMUD: Yes, thanks, 30 minute ago man. [igossip] Xyzzy: plane bombings is SO last decade. [igossip] Blue@Inon-Net: I wonder how they'll persuade King Kong to come down. [igossip] Cratylus: hey, i'm not gonna believe YOU bozos. /wiz/cratylus # [igossip] Xyzzy: screw YOU guys, ah'm goin HOME. [igossip] Sinistrad@VargonMUD: Famous last words, target! [igossip] Skullslayer@RoD: nah, it was 'fore!' [igossip] Tarl@Alsherok: In case no one said it, it appears one of the planes was american airlines flight number 11, I hope no one knew anyone supposed to be on that.. [igossip] Al@Anarres II: so one tower has fallen over completly? [igossip] Cratylus: no. the upper part of one collapsed. /wiz/cratylus # [igossip] Xyzzy: it has fallen UP. [igossip] Cratylus: not clear if it actually hit the ground. /wiz/cratylus # [igossip] Al@Anarres II: from news feed I have heard about, its fallen over completly? [igossip] Sinistrad@VargonMUD: It's just floating there. [igossip] Xyzzy: the Good Samaratin Terrorist Organization has built it back up. [igossip] Al@Anarres II ponders going to find a TV [igossip] Xyzzy: this... this cant happen to US.... were AMERICA! [igossip] Cratylus: heh, reporter is shocked to see police patrolling around with machine guns. /wiz/cratylus # [igossip] Bayard@Nanvaent: no tanks? [igossip] Xyzzy: GIT MAH GUN. [igossip] Al@Anarres II: they are gonna shoot planes down first! [igossip] Xyzzy: and pilots. [igossip] Cratylus: no, but apparently fighter jets patrolling too. /wiz/cratylus # [igossip] Xyzzy: kick ASS. [igossip] Al@Anarres II: \"At about 10 a.m., one of the 110-story World Trade Center towers collapsed\" [igossip] Xyzzy: just heard on radio: state building car combed. [igossip] Al@Anarres II: washingtonpost.com. [igossip] Presto@Discworld: car bomb outside the State Dept. [igossip] Xyzzy: shhh, al, dont overload our local newspaper's site! [igossip] Al@Anarres II: hey, its the only one up! [igossip] Cratylus: not anymore. /wiz/cratylus # [igossip] Xyzzy: thanks a LOT, guys. [igossip] Xyzzy: i can see it. [igossip] Xyzzy: heh, theres a webcam pointed at the pentagon smoke. [igossip] Al@Anarres II uses akamaitech.net [igossip] Al@Anarres II: it works. [igossip] Cratylus: howsabout a url? /wiz/cratylus # [igossip] Xyzzy: http://www.washingtonpost.com/wp-srv/mmedia/webcams/eyeondc.htm. [igossip] Sinistrad@VargonMUD: WHERE THE FUCK IS SPIDER-MAN?!?! [igossip] Xyzzy: helicopter in the picture, now. [igossip] Xyzzy: wtf is SPIERman gonna do. [igossip] Cratylus: mighty mouse is busy eating cheese. /wiz/cratylus # [igossip] Sinistrad@VargonMUD: Web the tower together. [igossip] Xyzzy: ohhhh yeah. [igossip] Skullslayer@RoD: rumour of 6 more planes in the air and hijacked [igossip] Xyzzy: spider MAN, SPIDER man. [igossip] Bayard@Nanvaent: yeah. that seems very rumourish atm. [igossip] Xyzzy: rumor from where? [igossip] Steve@Anarres II: 2nd has gone now. [igossip] Tariq@Demonslair Dev: 2nd tower just went down. [igossip] Al@Anarres II: how the hell can that many planes get hijacked? [igossip] Xyzzy: 2nd one what. [igossip] Xyzzy: tower? [igossip] Presto@Discworld: fucking Christ, the second tower collapsed. [igossip] Sinistrad@VargonMUD: MAYDAY MAYDAY, TOWER DOWN. [igossip] Steve@Anarres II: no, the 2nd fucking pentagon. [igossip] Cratylus: the Mayor's disaster control center was in the blown up tower. /wiz/cratylus # [igossip] Sinistrad@VargonMUD: Both towers are gone, you fucking moron. [igossip] Tariq@Demonslair Dev: saw it dropping live, it was truely scary. [igossip] Tariq@Demonslair Dev: live on the telly, in case anyone misunderstands that. [igossip] Al@Anarres II: did it crumple downwards, or topple over and take out alot og other buildings? [igossip] Musashi@Sumu: carbomb at state dept confirmed? [igossip] Tariq@Demonslair Dev: the top spire was in view, and it just dropped downwards. [igossip] Cratylus: wtf npr says both towers collapsed. /wiz/cratylus # [igossip] Pickett@Sumu: hrm, another plane hijacked and headed to washington. [igossip] Cratylus: im guessing any further hijacked planes might get shot down. /wiz/cratylus # [igossip] Al@Anarres II: but the US cant shoot down its own commertial airliner! [igossip] Cratylus: sure it can. /wiz/cratylus # [cre] Xyzzy: yes, ive heard both towers collapsed, too. [igossip] Al@Anarres II: they might not crash... [igossip] Bayard@Nanvaent: i reckon it will. [igossip] Xyzzy: ok, boss giving orders to go home. [igossip] Al@Anarres II: bye X! drive safely. [igossip] Al@Anarres II: don;t go rubber necking! [igossip] Xyzzy: fuck that, im driving like theres NO TOMOROW. [igossip] Xyzzy: nah, im takin back roads. [igossip] Al@Anarres II: there might not be a tomorrow. [igossip] Xyzzy: MIGHT even stop by parents... see if my dad keeps the gun-safe locked... [igossip] Xyzzy: kidding, of course. [igossip] Xyzzy: ok, see y'all later. [cre] Xyzzy waves. [announce] Xyzzy has left Frontiers. [cre] Cratylus waves. /wiz/cratylus # [igossip] Musashi@Sumu: perfect time to go raiding ;) [igossip] Blue@Inon-Net: I hear a rumour that Capitol Hill has not been attacked after all. [igossip] Skullslayer@RoD: I have a rumour a second explosion at the pentagon [igossip] Al@Anarres II: I have a rumour that they are gonna fly nto the statue of liberty. [igossip] Tarl@Alsherok: blue: it wasn't. it was a car bomb at the state dept. [igossip] Tarzan@Darkland: UN (NY) evacutated. [igossip] Skullslayer@RoD: the pentagon webcam shows a much bigger cloud of smoke now [igossip] Blue@Inon-Net: NEWSFLASH: smoke expands. [igossip] Tarl@Alsherok: reputedly also a large plane crash SE of pittsburgh, not sure if its related or not, and don't know if its real or not. [igossip] Tea@Nanvaent: where's the pentagon webcam? [igossip] Musashi@Sumu: http://www.washingtonpost.com/wp-srv/mmedia/webcams/eyeondc.htm. [igossip] Tea@Nanvaent: cheers. [igossip] Skullslayer@RoD: ronald reagan buliding evacuated [igossip] Skullslayer@RoD: confirmed hit in pittsburgh [igossip] Cratylus: so...uh...the two buildings are completely gone, then? /wiz/cratylus # [igossip] Tarzan@Darkland: whats in Pittsburgh? [igossip] Styxx@OuterSpace nods. [igossip] Skullslayer@RoD: north of the airport, somerset county [igossip] Skullslayer@RoD: rumour - all planes approaching DC will now be shot down [igossip] Skullslayer@RoD: the plane approaching DC was shot down? [cre] Zaphod: shit man. [igossip] Leto@Earth: http://robots.cnn.com/ and http://asian.cnn.com still work. [igossip] Spoo@Nanvaent: http://www.sky.co.uk is relatively lively still as well. [igossip] Bayard@Nanvaent nods. [igossip] Skullslayer@RoD: asia.cnn.com is still up, but it hasn't been updated in 2 hours that I can see [igossip] Leto@Earth: ah. [igossip] Leto@Earth: so what's the stuatus? [igossip] Sinistrad@VargonMUD: middleeast.cnn.com reports, \"Imperialist Scum Taught A Lesson\" [igossip] Skullslayer@RoD: rumour of another plane is a few mins out from DC, after the last one was shot down [igossip] Spoo@Nanvaent: fuck off Sinistrad. [igossip] Leto@Earth: 7 planes hijacked? [igossip] Sinistrad@VargonMUD: nya nya, nya nya nya. [igossip] Leto@Earth: one failed in pitsburg? [igossip] Musashi@Sumu: that DC-bound jet was shot down? That confirmed? [igossip] Sinistrad@VargonMUD: That was Air Force 1! [igossip] Skullslayer@RoD: yeah, one down in pittsburgh, just north of the airport [igossip] Spoo@Nanvaent: seems so, 1 may have been shot down near Pittsburgh. the other still flying near Dulles it would seem, other 5 either crashed or landed. [igossip] Hekubah@Annwn: What's happened in Chicago? [igossip] Skullslayer@RoD: I had a few players here confirm the shoot down [igossip] Spoo@Nanvaent: Sears tower evacuated. Israelis have shutdown ALL their embassies. [igossip] Lightfoot@VargonMUD: I'm unabvle to get to cnn.com. [igossip] Hekubah@Annwn: Woah. [igossip] Hekubah@Annwn: reuters isn't working... [igossip] Isis@Mystic: Me either. Or Fox News. [igossip] Isis@Mystic: Someone in the office is sreaming BBC. [igossip] Isis@Mystic: Er, streaming. [igossip] Lightfoot@VargonMUD: what about it? [igossip] Hekubah@Annwn has BBC on the TV... [igossip] Al@Anarres II: Isis - the BBC is fubared. [igossip] Spoo@Nanvaent: yeah, we have our own stream of N-TV. [igossip] Skullslayer@RoD: cnn, abcnews, msnbc and a few other big news sites are all down [igossip] Spoo@Nanvaent: we are getting CNN live feed. [igossip] Isis@Mystic: FoxNews too. [igossip] Skullslayer@RoD: bbc seems to be still up, but a bit behind [igossip] Tea@Nanvaent: http://news6.thdo.bbc.co.uk/ [igossip] Sinistrad@VargonMUD: DIE, IMPERIALIST SCUM! [igossip] Sinistrad@VargonMUD: HAH! [igossip] Skullslayer@RoD: rumour of crash into camp david [igossip] Isis@Mystic: Sinis, I love you. [igossip] Sinistrad@VargonMUD: I know. [igossip] Musashi@Sumu: remember sinistrad, much as you hate the 'imperialists', someone hates your beliefs just as much.. you deserve to die too? [igossip] Sinistrad@VargonMUD: Honey, it's funny that people are always laughing at the misfortunes of others on this channel - now those same people are all, \"dude, be more sensitive\" [igossip] Teny@Mystic: D.C Streets are one big traffic Jam. [igossip] Spoo@Nanvaent: pretty much not a joking matter. [igossip] Musashi@Sumu: misfortunte != death. [igossip] Musashi@Sumu: -t. [igossip] Al@Anarres II nods at Spoo [igossip] Sinistrad@VargonMUD: Go be righteous somewhere else. When it's not affecting you, you're the ruelest bunch of assholes ever. [igossip] Sinistrad@VargonMUD: Now it's your turn. HAH!!! DIE GRINGOS!! [igossip] Spoo@Nanvaent: not affecting you either, so be completely tasteless some other time. [igossip] Sinistrad@VargonMUD: No. [igossip] Al@Anarres II: hey Sini, this doesnt affect me, but it does affect alot of ppl. [igossip] Musashi@Sumu: shrugs, I'm not American, but I'm still not gonna laugh at people dying. [igossip] Al@Anarres II: there are like 50,000 ppl working in the WTO. [igossip] Spoo@Nanvaent: I ain't laughing because this is only the start of the bloodletting. [igossip] Sinistrad@VargonMUD: Not any more! [igossip] Lightfoot@VargonMUD: more like 75K. [igossip] Skullslayer@RoD: plus all the people in the surrounding buildings [igossip] Lightfoot@VargonMUD: people were jumping out of the building for over 1/2 hour. [igossip] Al@Anarres II: [flap] Iain: itn reporting 100 tousand dead in new york. [igossip] Sinistrad@VargonMUD: Where were you guys when 80K Hindis died of starvation last year? Did you care? No, you laughed at the hungry brownies. [igossip] Spoo@Nanvaent: in case you hadn't noticed the madmen have just fucked off the USA, NATO and the Israeli's. [igossip] Leto@Earth: 100.000 ? [igossip] Iain@Anarres II: 100k people. [igossip] Spoo@Nanvaent: well fuck you for being so consciencious, yeah I care, I don't find it funny either. [igossip] Iain@Anarres II: lots of them firefighters/police. [igossip] Sinistrad@VargonMUD: \"Whine whine, now it's hurting us directly, please don't laugh.. please forget that I used to laugh at you when you were down, now it's about me and I'm more important.\" [igossip] Lightfoot@VargonMUD: I live on Long Island, firefighters and police were called into the city. [igossip] Lightfoot@VargonMUD: all bridges and tunnels to NYC are closed. [igossip] Al@Anarres II: swim! [igossip] Al@Anarres II: how are they getting ppl out ? [igossip] Lightfoot@VargonMUD: they are not. [igossip] Sinistrad@VargonMUD: With straws. [igossip] Spoo@Nanvaent: both the towers are basically piles of burning rubble, unlikely to be any survivors in that. [igossip] Ebony@Earth: I heard a witness say he worked on the 36th floor and they got out ok. [igossip] Ebony@Earth: they had 1/2 an hour before the collapse. [igossip] Spoo@Nanvaent: 1st or 2nd tower? [igossip] Hellmonger@Trilogy: http://www.shef.ac.uk/cs1xtc/sa/planewtc.jpg. [igossip] Ebony@Earth: 69 ppl on the plane that flew into the wtc. [igossip] Lightfoot@VargonMUD: both towers are gone. [igossip] Hellmonger@Trilogy: no doubt. [igossip] Ebony@Earth: first tower, they started leaving right after they saw the 2nd plane. [igossip] Lightfoot@VargonMUD: 2nd plane hit 18 mins after first. [igossip] Hellmonger@Trilogy: Vote Yes to Proposition 37 \"Systematic Ethnic Clensing of America\" [igossip] Sinistrad@VargonMUD: \"Leave only the injuns\" [igossip] Spoo@Nanvaent: what, you mean America will belong to the natives again? [igossip] Shandor@Bakhara: just the mexicans. [igossip] Hellmonger@Trilogy: Leave only the whites, the blacks, and the mexicans. [igossip] Hellmonger@Trilogy: cuz everybody else is out to fucking get us. [igossip] Lightfoot@VargonMUD: boston is very close, right across the LI sound. [igossip] Ebony@Earth: 2 planes, carrying approx 80 passengers each.. [igossip] Ebony@Earth: unsure which they were. [igossip] Spoo@Nanvaent: seems they just shot down the 2nd plane as well. [igossip] Spoo@Nanvaent: the one near Dulles. [igossip] Sinistrad@VargonMUD: Shit, HM's link made me bust a gut! [igossip] Vraxor@Split Infinity: how do you know? [igossip] Sinistrad@VargonMUD: You rule, HM. =) [igossip] Skullslayer@RoD: rumour of a bomb in a school near the WTC [igossip] Hellmonger@Trilogy: no doubt. [igossip] Al@Anarres II: nice to see students at shefield are back, hard at work ;) [igossip] Skullslayer@RoD: plane inbound to chicago [announce] Xyzzy enters Frontiers. [igossip] Xyzzy: i dont know if yer keeping up on current events, but we just got our ASSES kicked back there! [igossip] Sinistrad@VargonMUD: http://www.shef.ac.uk/cs1xtc/sa/planewtc.jpg. [igossip] Hekubah@Annwn: Another plane? [igossip] Bayard@Nanvaent: the first joke picture :) [igossip] Sinistrad@VargonMUD: That's not a joke. [igossip] Xyzzy: thats fucked up. [igossip] Bayard@Nanvaent: buh? [igossip] Vashkar@Split Infinity: ummm.. that looks like nice photoshop work, Sinistrad. [igossip] Xyzzy: jeez, fuck the fox network... \"apparent terrorist attacks...\" [igossip] Sinistrad@VargonMUD: Reality always looks so fake, doesn't it? [igossip] Izzy@VargonMUD: \"This just in, JFK shot.\" [igossip] Musashi@Sumu: NBC just reported bomb gone off in NYC Highschool. [igossip] Xyzzy: WE GOT A MAN ON TH MOON?! [igossip] Presto@Discworld: yeah, it was obviously a big fucking coincidence. [igossip] Xyzzy: fox investigative news. [igossip] Xyzzy: at work. [igossip] Musashi@Sumu: FAA say several planes still unaccounted for. [igossip] Presto@Discworld: This just in: Jimmy Hoffa still missing. Police are baffled. [igossip] Xyzzy: plane crash 80 miles SE of pittsburg. [igossip] Xyzzy: holy shit, footage of the WTC collapsing. [igossip] Presto@Discworld: American Air confirms two flights down, United at least one (the Pittsbhrugh one) [igossip] Al@Anarres II: well done Xyzzy, do catch up. [igossip] Al@Anarres II: which was the dullus one? [igossip] Xyzzy: gee, its almost as if i havent had a TV at work for th last two hours. [igossip] Vashkar@Split Infinity: the only thing slightly amusing is that I swore to myself that I'd never set foot in the WTC again.. then seconds later, one collapses..then the other. [igossip] Bayard@Nanvaent: you've had i3 though. and it's all been mentioned on here. [igossip] Xyzzy: its all YOUR fault, vash. [igossip] Xyzzy: no, im SEEING the collapse for th first time. [igossip] Vashkar@Split Infinity: sorry, I don't claim responsibility for the deaths of tens of thousands today. [igossip] Blue@Earth: you should, get your place in the queue. [cre] Cratylus: whad i miss? /wiz/cratylus # [igossip] Xyzzy: no one ever told us terrorist could be organized. [igossip] Xyzzy: is that fair? [cre] Xyzzy: dunno, i just got home. [cre] Zaphod: westconn just got bombed. [cre] Cratylus: no. /wiz/cratylus # [igossip] Al@Anarres II: is this the largest terrorist attack ever? [cre] Cratylus: they installed antiarircraft batteries on the ice rink and patriot garage. /wiz/cratylus # [cre] Cratylus: i just saw em. /wiz/cratylus # [cre] Zaphod: ah. [igossip] Xyzzy: heh, on cnn, \"america under attack\", all red white n blue fonts n stuff. [cre] Zaphod: cool. [igossip] Bayard@Nanvaent: easily. [igossip] Sinistrad@VargonMUD: Shit. Now my Flight Simulator NYC edition is outdated. =( [igossip] Al@Anarres II giggles [igossip] Xyzzy: expansion pack. [igossip] Bayard@Nanvaent: equally, how do u define a terrorist attack. this might not be a terrorist attack. [igossip] Hekubah@Annwn: Might be an act of war? [igossip] Bayard@Nanvaent: could end up being defined as an opening move in a war. [cre] Zaphod: few. [cre] Zaphod: phewww. [igossip] Xyzzy: oh yeah, fergot, it might just be a wacky coincidence. [cre] Zaphod: my package made it out of newark. [igossip] Vashkar@Split Infinity: well, it wasn't a bunch of drunks, Bayard. [igossip] Iain@Anarres II: sick puppy sini ;-) [igossip] Xyzzy: hmm, good point, bayard. [igossip] Xyzzy: GIT MAH GUN! [igossip] Lightfoot@VargonMUD: were at defcon 5! [igossip] Xyzzy: yer MOM is at defcon5 [igossip] Sinistrad@VargonMUD: Hey, more people died right now than in Pearl Harbor. [igossip] Bayard@Nanvaent: but, the style of attack will prolly mean it's a terrorist attack that started a war in history books. [igossip] Xyzzy: what, you got a death-count goin, sini? [igossip] Bayard@Nanvaent: s'diff than pearl harbour or czechoslovakia. [igossip] Lightfoot@VargonMUD: shut up dick. [igossip] Vashkar@Split Infinity: please someone ban Xyzzy. [igossip] Spoo@Nanvaent: WW 1 was started because of a terrorist attack that killed 1 person. [igossip] Bayard@Nanvaent nods. [igossip] Xyzzy: please someone suck my dick. [igossip] Sinistrad@VargonMUD: Xy, 50K+ people worked in the towers. [igossip] Sinistrad@VargonMUD: How many people died at Pearl Harbor? [igossip] Cratylus watches in amusement as Vashkar greedily gobbles Xyzzy's knob. /wiz/cratylus # [igossip] Vashkar@Split Infinity: Vrax@SI says there was 10k in each tower, approximately, at the time. [igossip] Xyzzy: what, like i work for th navy or something, sini? [cre] Zaphod: my packge drove right through ny just before this. [cre] Cratylus: yer motherboard? /wiz/cratylus # [cre] Xyzzy: a little... coincidental. [igossip] Spoo@Nanvaent: less than 2k people were killed at PH. [igossip] Vraxor@Split Infinity: that's what the guy who owned the tower said. [cre] Zaphod: this one is my video card. [cre] Zaphod: mb just left la. [cre] Zaphod: maybe it's been hijacked. [igossip] Xyzzy: that tower was 0WN3D. [igossip] Ebony@Earth: You have to account for tourists in the towers too. [igossip] Vraxor@Split Infinity: and the people in the planes. [cre] Zaphod: now I REALLY don't feel like going to the office. [32m[igossip] Xyzzy: shoot, none of this is gonna drive up memory prices, will it? [cre] Zaphod: buy it quick. [igossip] Spoo@Nanvaent: automatic if the pres is in AF1 [cre] Zaphod: WTC attack sale! [igossip] Xyzzy: heard on radio: military air coverage over DC. [igossip] Musashi@Sumu: ok, of the two planes to hit the towers, one was out of boston, 81 passengers, 11 crew, one was out of washington, 58 passengers, 6 crew. [cre] Zaphod: cheech sent an email saying pahts delivery will be screwy. [igossip] Lightfoot@VargonMUD: there are tomcats flying around NYC. [igossip] Xyzzy: thanks for th numbers, musashi. [cre] Cratylus: AHAHAH. /wiz/cratylus # [cre] Cratylus: i fucken BET. /wiz/cratylus # [igossip] Xyzzy: i knew id never regret hiring you as my accountant. [igossip] Cratylus: i cant wait til we fuckin nuke the shitbags from orbit. /wiz/cratylus # [igossip] Zaphod: 9/11 [igossip] Xyzzy: its th only way to be sure. [igossip] Dasquian@Discworld: You idiot. [igossip] Musashi@Sumu: spam incoming, this from CNN. [igossip] Musashi@Sumu: United Airlines Flight 93 airliner headed from Newark, New Jersey, to San Francisco, crashed near Somerset, Pennsylvania -- police said initial reports indicated no survivors. It was not known if this was connected to the attacks. United also said it was \"deepl. [igossip] Xyzzy: DEEPL?!?! [igossip] Xyzzy: NOOOOOOO!!!!!! [igossip] Musashi@Sumu: ________________23:43 [igossip] Musashi@Sumu: hm, sec :P. [igossip] Musashi@Sumu: United also said it was \"deeply concerned\" about Flight l75 from Boston to Los Angeles. [igossip] Lightfoot@VargonMUD: it's said that crash in penn was from captain crashing plane when he knew what was going on and he was being hi-jacked. [igossip] Xyzzy: Am Airlines siad theyve \"lost\" two flights. [igossip] Sinistrad@VargonMUD: And they know that throgh the ouija board, Danny? [cre] Zaphod: today is 9/11 [igossip] Xyzzy: WELL, DANNY?! [igossip] Lightfoot@VargonMUD: I'm sure the radios were working. [igossip] Xyzzy: oh, yer \"sure\" [igossip] Vashkar@Split Infinity: http://us.news2.yimg.com/dailynews.yahoo.com/h/nm/20010911/ts/crash_tradecenter _binladen_dc_1.html. [igossip] Lightfoot@VargonMUD: shut up dick. [igossip] Vashkar@Split Infinity: they say bin laden warned of the attack 3 weeks ago. [cre] Zaphod: call paul. [igossip] Sinistrad@VargonMUD: Wow. [cre] Cratylus: ya. /wiz/cratylus # [igossip] Vashkar@Split Infinity: saying it was cause of US supporting israel. [igossip] Xyzzy: yknow, i think what we really need now is a verbal fight on i3 [igossip] Shandor@Bakhara: your mom tastes like chicken and your dad smells of a russian tea room. [igossip] Xyzzy: HEY, now. [igossip] Xyzzy: lets keep it civil. [igossip] Cratylus: eldeberries, you fool. /wiz/cratylus # [igossip] Sinistrad@VargonMUD: ``Personally we received information that he planned very, very big attacks against American interests. We received several warnings like this. We did not take it so seriously, preferring to see what would happen before reporting it.'' [igossip] Cratylus: smelt of em. /wiz/cratylus # [igossip] Shandor@Bakhara: windows sucks! RH linux is the top of them all. [igossip] Sinistrad@VargonMUD: \"He told us he was gonna do it, but we wanted to see what he was gonna do before we told anybody.\" [cre] Zaphod: cute. [igossip] Xyzzy: we called his bluff, alright. [igossip] Shandor@Bakhara: who says that, sini? [cre] Zaphod: he told me to stay home. [igossip] Hellmonger@Trilogy: I hear the arabs in San Fran are celebrating the attacks. Somebody go kill them all. [igossip] Sinistrad@VargonMUD: NOW YOU KNOW. [cre] Cratylus: ya. /wiz/cratylus # [cre] Zaphod: you heard him. [igossip] Sinistrad@VargonMUD: That link Vash gave out. [cre] Cratylus: stamford is prolly a panicky madhouse. /wiz/cratylus # [cre] Zaphod: no doubt. [igossip] Xyzzy: and knowing's half th battle! [cre] Zaphod: and I've got CABLE. [igossip] Spoo@Nanvaent: hell, the Arabs are going to give someone some target practice if they don't fuck off. [igossip] Shandor@Bakhara: half of our IT department is made of arabs. I wouldn't want to be them right now. Although, this is a mall city. [igossip] Xyzzy: mall city? like, with shops n stuff? [igossip] Cratylus: made of crabs? what? /wiz/cratylus # [igossip] Spoo@Nanvaent: it ain't really the Arabs anyway, just a completely mad bunch of lunatics who want to take us back the the dark ages. [igossip] Cratylus: the republicans? /wiz/cratylus # [igossip] Xyzzy: like i said, i think its in the rulebook that theyre not allowed to be so organized and effective. [igossip] Sinistrad@VargonMUD: That movie with Denzel Washington and Bruce Willis starts out with a lot of terrorist attacks. That is NOTHING compared to this. [igossip] Vashkar@Split Infinity nods. [igossip] Cratylus: i bet the french are all like \"serves em right, bourgeois pigs\" /wiz/cratylus # [igossip] Spoo@Nanvaent: makes Tom Clancy look tame too. [igossip] Lightfoot@VargonMUD: cnn back up. [igossip] Cratylus: i think they got lucky. you couldnt *really* expect those fucking buildings to drop from plane hits. /wiz/cratylus # [igossip] Spoo@Nanvaent: they were rather large ones. [igossip] Lightfoot@VargonMUD: Bush calls trade center crashes terrorist act. [igossip] Cratylus: large buildings. /wiz/cratylus # [igossip] Lightfoot@VargonMUD: you think? [igossip] Sinistrad@VargonMUD: Thanks, Danny. [igossip] Vashkar@Split Infinity: in today's day n' age, it's not hard to be a competent terrorist. It's like Osama bin Laden went to a tech institute or something. [igossip] Spoo@Nanvaent: large aircraft. [igossip] Cratylus: fat asses. /wiz/cratylus # [igossip] Steve@Anarres II: um.. they knew where to hit them to have best chance of toppling them.. [igossip] Spoo@Nanvaent: cnn.com is breaking under the strain again. [igossip] Xyzzy: this just in: i hafta pee. [igossip] Cratylus: ok, master terrorist. /wiz/cratylus # [igossip] Zaphod: ooo ooo Tom Clancy's on cnn! [igossip] Sinistrad@VargonMUD: He's the authority, I bet! [igossip] Cratylus: that does it. im playing half life. screw this. /wiz/cratylus # [igossip] Xyzzy: hes written books n stuff! [igossip] Xyzzy: just like smack! [igossip] Spoo@Nanvaent: prolly complaining that the bastards stole his idea. [igossip] Steve@Anarres II: part-way up near the top.. you prolly won't get them immediately, but fire will weaken the structure and the top will fall cruching the rest of the building.. [igossip] Xyzzy: cool, Dexter's Laboratory on cartoon network. [igossip] Spoo@Nanvaent: yeah, the steel skeleton would weaken, concrete and facade wouldn't hold the weight. [igossip] Spoo@Nanvaent: it appears there was a secondary explosion in the first tower to go down too. [igossip] Blue@Inon-Net: I think the WTC buildings had their skeleton on the outside; but don't hold me to that. [igossip] Sinistrad@VargonMUD: So it wasn't just the planes? [igossip] Xyzzy: yeah! lets speculate on the various ways these people died today! [igossip] Vashkar@Split Infinity: Spoo, they're thinking it was the plane's fuel tank exploding. [igossip] Steve@Anarres II: they showed ppl diving outa windows on the news.. that's sick.. [igossip] Spoo@Nanvaent: was quite a way down from the impact site. [igossip] Spoo@Nanvaent: could well have been though. [igossip] Al@Anarres II nods at Spoo [igossip] Al@Anarres II: I think we just have to wait and see. [igossip] Vashkar@Split Infinity: yeah, I was questioning the logistics of that guess also. [igossip] Al@Anarres II: if the top, above the crash site, fell down, even just 1meter, the energy would be enough to crumble the steel below. [igossip] Spoo@Nanvaent: thats what happened with the second tower. [cre] Zaphod: shit. [igossip] Al@Anarres II: it might have crumbled many stories down, making it look like an explosion below the crash site. [igossip] Spoo@Nanvaent: roof went, took the rest with it. [cre] Zaphod: I bet the coffee I ordered don't get sent out. [igossip] Al@Anarres II: yeah, common :( [cre] Xyzzy: always thinkin of yerself. [igossip] Al@Anarres II shuts up about civil engineering and goes back to hacking sendmail [cre] Zaphod: well, I need my coffee. [igossip] Boltthrower@Styx: apparently the roof-collapse scheme works better than the basement-bomb thing did :( [igossip] Spoo@Nanvaent: nah, there was a clear fireball shortly before the first collapse (and I saw that live so no, it wasn't a plane) [igossip] Xyzzy: how about the \"fly a few hundred tons of metal into the building\" scheme? [igossip] Isis@Inon-Net: Yeah, I saw it too just before I left for work. [igossip] Spoo@Nanvaent: 737 and a 767, couple of hundred tonnes each. [igossip] Hellmonger@Trilogy sets an arab on fire. [igossip] Zaphod: camp david get hit? [igossip] Vashkar@Split Infinity: close to camp david. [igossip] Al@Anarres II: cool, HM, gulf-news.com is hosted nr you ;) [igossip] Spoo@Nanvaent: lots of momentum to damage the buildings, the second aircraft blew right through the tower too. [igossip] Xyzzy: can you imagine how dark it could be in manhattan right now? [igossip] Lightfoot@VargonMUD: that one was shot down. [igossip] Spoo@Nanvaent: what, at midday? [igossip] Xyzzy: yes. [igossip] Xyzzy: with all the smoke. [igossip] Spoo@Nanvaent: not very then. [igossip] Xyzzy: well, i guess you CAN imagine it, then. [igossip] Zaphod: 8 hijacked planes still in the air? [igossip] Xyzzy: but for how long.... [igossip] Xyzzy: HOW LONG!?! [igossip] Vashkar@Split Infinity: where'd you hear 8, Zaphod? [igossip] Xyzzy: hes just makin shit up, now. [igossip] Ebony@Earth: Its not that dark. [igossip] Hellmonger@Trilogy: I heard 8 total planes. [igossip] Hellmonger@Trilogy: and we've already found some of them. [igossip] Lightfoot@VargonMUD: 5 floors in pentagon have collapased. [igossip] Ebony@Earth: Not unless you where wtc was. [igossip] Hellmonger@Trilogy: we found 2 in the trade center, one in the pentagon... \\ [igossip] Xyzzy: HM AM FUNNYMAN! [igossip] Spoo@Nanvaent: Brits have lost contact with 2 aircraft as well. [igossip] CyberTiger@Anarres II: s/found/happened to notice/ [igossip] Xyzzy: wtf, some dude disassembling a pistol on CourtTV, sayin how easy it could be to blah blah blah. [igossip] BarWench@Inon-Net: ;nods. [igossip] Al@Anarres II: have we Spoo? where you hear that? [igossip] Hellmonger@Trilogy: So is Bin laden a palestinian or a jew? [igossip] Smack@Lima Bean: what aircraft? [igossip] Smack@Lima Bean: my father is on a flight from london to new york. [igossip] Hellmonger@Trilogy: It says 'Islamic Fundamentalist', which is like a palestinian, right? [igossip] Smack@Lima Bean: bin laden is saudi. [igossip] Hellmonger@Trilogy: He'll be landing in canada. :( [igossip] Pam@Split Infinity: They're evacuating some of the taller buildings in London, according to MSNBC. [igossip] Smack@Lima Bean: he is a rich, eccentric saudi. [igossip] Xyzzy: look out, hellmonger is gunnin for SOMEone. [igossip] Tea@Nanvaent: canada is all closed too i thought? [igossip] Hellmonger@Trilogy: I'm down to kill me some arabs now. [igossip] Hellmonger@Trilogy: And some happy palestinians. [igossip] Smack@Lima Bean: we must declare war against Afghanistan. [igossip] Hellmonger@Trilogy: Need to be set on fire. [igossip] Hellmonger@Trilogy: why afghanistan? [igossip] Sinistrad@VargonMUD: Why not? [igossip] Hellmonger@Trilogy: Valid point. KILL EM ALL! [igossip] Smack@Lima Bean: afghanistan has been housing bin laden for years. [igossip] Smack@Lima Bean: they refuse to turn him over. [igossip] Megaboz@Lima Bean: I just have this feeling that bush is going to do something stupid. [igossip] Ebony@Earth: Third plane ahs crashed in pentagon. [igossip] Hellmonger@Trilogy: I'm all about letting them know whats up. Take the afghan royal family or whatnot. And cook them on a spit. [igossip] Smack@Lima Bean: do something stupid like what? [igossip] Hellmonger@Trilogy: Like what? [igossip] Hellmonger@Trilogy: Like starting to kill people? [igossip] Hellmonger@Trilogy: The american people want revenge. [igossip] Smack@Lima Bean: if he nuked them, I would be only mildly distubed. [igossip] Megaboz@Lima Bean: nuked was the thing I was going for. [igossip] Spoo@Nanvaent: which bastard stopped development of the neutron bomb, perfect time to test it. [igossip] Xyzzy chants: \"NUKE! NUKE! NUKE!\" [igossip] Hellmonger@Trilogy: I would'nt really be phased. I'd like to see the middle east as a field of glass. [igossip] Smack@Lima Bean: so how many planes have crashed so far? 5? 6? [igossip] Musashi@Sumu: Ebony, that 3rd plane in the pentagon confirmed? [igossip] Sinistrad@VargonMUD: 5. [igossip] Sinistrad@VargonMUD: Three on target, two off target. [igossip] Hellmonger@Trilogy: I think bombing them would be cool. [igossip] Spoo@Nanvaent: hard to tell really, web sites are all choked. [igossip] Xyzzy: jeez, how many damn kids did the Waltons have? [igossip] Hellmonger@Trilogy: 7. [igossip] Hellmonger@Trilogy: all worth around 17-18 bil. [igossip] Smack@Lima Bean: my understanding is 2 into thw world trade center, 2 into the pentagon, and one outside pittsburgh. [igossip] Hellmonger@Trilogy: right. [igossip] Sinistrad@VargonMUD: Only 1 into the pentagon. [igossip] Isis@Inon-Net: And one in Sommerset PA as well. [igossip] Musashi@Sumu: reading in a few places of a 3rd into the pentagon though. [igossip] Sinistrad@VargonMUD: 1 outside pitts, 1 recently confirmed outside Sommerset. [igossip] Hellmonger@Trilogy: Thats outside pitts. [igossip] Smack@Lima Bean: sommerset == pitssburgh. [igossip] Smack@Lima Bean: oh, yeah,and the air force shot one down outside camp david. [igossip] Hellmonger@Trilogy: a third plane intot he pentagon? [igossip] Futility@UOSSMUD: The one in Somerset is the one near pittsburgh. [igossip] Hellmonger@Trilogy: Really? [igossip] Sinistrad@VargonMUD: \"United Airlines Flight 93 airliner headed from Newark, New Jersey, to San Francisco, crashed near Somerset, Pennsylvania -- police said initial reports indicated no survivors. It was not known if this was connected to the attacks. United also said it was \"deeply concerned\" about Flight l75 from Boston to Los Angeles.\" [igossip] Sinistrad@VargonMUD: On CNN, they just confirmed that 175 went down, too. [igossip] Xyzzy: deepl. [igossip] Spoo@Nanvaent: so 3 shot down and 3/4 crashed. [igossip] Hellmonger@Trilogy: We shot down three planes? [igossip] Xyzzy: yeah, HM, score one for th good guys. [igossip] Spoo@Nanvaent: there were 7 hijacked. [igossip] Musashi@Sumu: from advfn: A third plane crashes near the Pentagon in Washington DC. [igossip] Smack@Lima Bean: where did 175 go down? [igossip] Spoo@Nanvaent: well maybe not shotdown, hard to sort out the news from the confused. [igossip] Spoo@Nanvaent: WASHINGTON (Reuters) - Three hijacked planes crashed into major U.S. landmarks on Tuesday, destroying both of New York's mighty twin towers, hitting the Pentagon in Washington and plunging the United States into unprecedented chaos and panic. [igossip] Smack@Lima Bean: fucking kill them all. [igossip] Blue@Inon-Net: now that Reuters has confirmed it, I'll stop worrying that it was all US propaganda being parroted by CNN. [igossip] Hellmonger@Trilogy: no doubt. [igossip] Xyzzy: the adjective \"mighty\" brought to you at no extra charge. [igossip] Hellmonger@Trilogy: I only know of three terrorist crashes, and one United crash. [igossip] Hellmonger@Trilogy: And whats up on 175? [igossip] Sinistrad@VargonMUD: Two united crashes. [igossip] Hellmonger@Trilogy: where did it crash? [igossip] Smack@Lima Bean: the united crash is certainly a terorist thing. [igossip] Smack@Lima Bean: probably the pilot taking it down to prevent somethign evil. [igossip] Hellmonger@Trilogy: I thought terrorists all capped off the pilots to prevent them from fucking up the program? [igossip] Spoo@Nanvaent: One of the planes that crashed into the World Trade Center was American Airlines' Flight 11 from Boston to Los Angeles, said Lori Bassani, spokesperson for American's flight attendants union. ; [igossip] Smack@Lima Bean: someone said \"fuck the terrorists\" [igossip] Sinistrad@VargonMUD: Yeah, I don't think any pilot would go, \"Ok, I'll crash this plane into the twin towers or he'll shoot me.\" [igossip] Spoo@Nanvaent: www.reuters.com. [igossip] Hellmonger@Trilogy: No doubt. YOu are going to die anyway. Fuck it. I'd put that shit in the dirt. [igossip] Smack@Lima Bean: I agree... but I bet on the one outside pittsburgh was stoipped by someone. [igossip] Xyzzy: hellmonger, you seem to be fairly well-versed in \"hijacker protocol\" [igossip] Xyzzy: something you wannatell us? [igossip] Hellmonger@Trilogy: Common sense. [igossip] Boltthrower@Styx: you online from a plane? [igossip] Sinistrad@VargonMUD: Microsoft announced the release of a new version of Microsoft Flight. [igossip] Smack@Lima Bean: I just fear that bioterrorism is part of this. [igossip] Smack@Lima Bean: that we have not even seen the worst yet. [igossip] Sinistrad@VargonMUD: Microsoft announced the release of a new version of Microsoft Flight Simulator today. The terrain has been updated in New York so that two piles of rubble sit where the twin World Trade Center towers used to stand. When asked how they had this updated version burned before the towers were actually bombed Bill Gates responded \"We like to be prepared for any contingiency. This is a horrible tragedy and we grieve for the loss that people are facing. We will donate .001% of all profits of this product to help the families of those killed during this horrible event.\" Newly appointed Vice President of Microsoft, Osama bin Laden added: \"We'd also like to point out that we have the only flight simulator on the market that has true to the day updated terrain. If you want to own the most realistic up to date simulator, you've got to buy ours.\" [igossip] Spoo@Nanvaent: sorry, even I find that funny :) [igossip] Sinistrad@VargonMUD: =) [igossip] Xyzzy: and we all know how lousy a sense of humor spoo has. [igossip] Spoo@Nanvaent: at least I have one Xy :) [igossip] Musashi@Sumu: looks like the pentagon fire is under control. [igossip] Xyzzy: WHEW! [igossip] Xyzzy: what about these rumors of car bombings and capitol hill/ state building/whitehouse, etc. [igossip] Sinistrad@VargonMUD: Exhaust pipes going off. [igossip] Musashi@Sumu: well, heard several reports of car bomb outside state building. [igossip] Spoo@Nanvaent: there was no bomb at the State Department. [igossip] Musashi@Sumu: and one of a bomb in a nyc school. [igossip] Blue@Inon-Net: english.pravda.ru. [igossip] Spoo@Nanvaent: prolly someone hearing a backfire. [igossip] Blue@Inon-Net: US DOLLAR ABRUPTLY FALLEN DOWN. [igossip] Blue@Inon-Net: According to current bidding, US dollar has fallen abruptly relative to the Euro and to Yena. American stock markets has not started to work yet. Planes are in air to hamper the second plane. [igossip] Xyzzy: ALL YOUR NEWS ARE BELONG TO US. [igossip] Blue@Inon-Net: According to NPR John Hopkins, the USA have not need to be considerate with the terrorists. [igossip] Musashi@Sumu: laf. [igossip] Spoo@Nanvaent: Manhattan island encircled by policemen. [igossip] Blue@Inon-Net: Suicide pilots piloting two planes have practically rammed two buildings of International Trade Centre at a height of 85th storey. These two buildings are known to the whole world thanks to film 'King Kong'. That are the buildings over which the big monkey was mounting. More detail... [igossip] Xyzzy: holding hands. [igossip] Spoo@Nanvaent: POPULATION FROM CENTRE OF CHICAGO EVACUATED. LONDON PANIC STRICKEN; [igossip] Xyzzy: hu uhuh uhu, you said \"mounting\" [igossip] Musashi@Sumu: london is hardly panic stricken :P. [igossip] Xyzzy: wait, LONDON panic stricken? [igossip] Lightfoot@VargonMUD: king kong climbed the empire state building. [igossip] Blue@Inon-Net: they mean the remake. [igossip] Blue@Inon-Net: NEWSFLASH: King Kong to be remade again, new buildings sought. [igossip] Xyzzy: as opposed to the porn film, \"King Dong\", where he climbed lightfoot's mother. [igossip] Lightfoot@VargonMUD: fuck you dick. [igossip] Spoo@Nanvaent: I think \"have practically rammed 2 buildings\" is an understatement. [igossip] Xyzzy: ACH! fook me dick! [igossip] Xyzzy: well, it wasnt very IMpractical. [igossip] Lightfoot@VargonMUD: I would love to kick the living shit out of a little punk like you. [igossip] Spoo@Nanvaent: \"ADVENTURES OF AMERICAN RECONNAISSANCE AIRCRAFT R-3. NOW IN RUSSIAN AIRSPACE;\" [igossip] Zaphod: whoa. [igossip] Sinistrad@VargonMUD: Danny, I've seen you. You're the smallest goddamn punk ever. [igossip] Zaphod: qvc has suspended broadcasts. [igossip] Zaphod: jesus. [igossip] Spoo@Nanvaent: surely that should be \"Now in Russian Cinemas\" [igossip] Xyzzy: and he doesnt mean overall height. [igossip] Bayard@Nanvaent: no more qvc? ",({"chapter 2","chapter two","2",}):"chapter 2 \"The Demise of Wolfsong\" [25Nov2005-23:13:06] Wolfsong@Aurora Sky <imud_gossip> Hello. [25Nov2005-23:13:30] Wolfsong@Aurora Sky <imud_gossip> Hmm, someone on my staff got this to work. Razz [25Nov2005-23:13:38] Duuk@Haven <imud_gossip> fuck [25Nov2005-23:15:03] Berun@Aurora Sky <imud_gossip> hello everyone [25Nov2005-23:15:07] Wolfsong@Aurora Sky <imud_gossip> Now, that's a dirty word. [25Nov2005-23:15:11] Duuk@Haven <imud_gossip> shut the fuck up, n00b., [25Nov2005-23:15:25] Wolfsong@Aurora Sky <imud_gossip> Aww, you sound upset. [25Nov2005-23:15:25] Gary@Void <imud_gossip> Hey all. [25Nov2005-23:15:35] Gary@Void <imud_gossip> Duuk is just having a bad day^W life. [25Nov2005-23:15:37] Duuk@Haven <imud_gossip> jesus it's a fucking retard convention [25Nov2005-23:16:49] Wolfsong@Aurora Sky <imud_gossip> Ah. I don't think that's an appropriate reason to immediately attack someone new, readily making assumptions about my intelligence. It shows a level of mental mediocrity. [25Nov2005-23:17:05] Duuk@Haven <imud_gossip> You're a newbie mud admin. It's safe to assume you're a fuckin tard. [25Nov2005-23:17:17] Gary@Void <imud_gossip> Actually, Duuk has a very valid point there. [25Nov2005-23:17:25] <imud_gossip> Duuk@Haven nods solemnly. [25Nov2005-23:17:27] Duuk@Haven <imud_gossip> See! [25Nov2005-23:17:29] cratylus@Dead Souls <imud_gossip> amen [25Nov2005-23:18:04] Vanyel@Haven <imud_gossip> No offense and all. It's just a statistical analysis. This way they save time. [25Nov2005-23:18:22] Wolfsong@Aurora Sky <imud_gossip> So, being new to adminship means I have a low IQ. Except, according to current theory in psychology, it is impossible to raise your IQ. So, as you are experienced admins, you too, have low IQs. [25Nov2005-23:18:36] cratylus@Dead Souls <imud_gossip> heh [25Nov2005-23:18:42] Duuk@Haven <imud_gossip> No. We were here before any tard could open a mud. [25Nov2005-23:18:42] cratylus@Dead Souls <imud_gossip> you're not helping yourself, guy [25Nov2005-23:18:56] Duuk@Haven <imud_gossip> Haven first ran on a 486 with 16 meg of ram. [25Nov2005-23:19:02] Duuk@Haven <imud_gossip> It ran like shit, but it ran. [25Nov2005-23:19:04] Zakk@Lima Bean <imud_gossip> uphill both ways [25Nov2005-23:19:06] Wolfsong@Aurora Sky <imud_gossip> I'm female. And rather educated. [25Nov2005-23:19:14] cratylus@Dead Souls <imud_gossip> well that explains you [25Nov2005-23:19:16] Duuk@Haven <imud_gossip> Liar on 2 points. [25Nov2005-23:19:22] Zakk@Lima Bean <imud_gossip> female? pics of tits, now [25Nov2005-23:19:28] <imud_gossip> Duuk@Haven agrees. [25Nov2005-23:19:32] Duuk@Haven <imud_gossip> bikiniphotos. now. [25Nov2005-23:19:40] Gary@Void <imud_gossip> I'm sorry, but I'm gonna have to go agree with Zaak and Duuk on this Sad [25Nov2005-23:19:40] Wolfsong@Aurora Sky <imud_gossip> LoL. You don't want those. [25Nov2005-23:19:42] Zakk@Lima Bean <imud_gossip> bikini? wtf [25Nov2005-23:19:56] cratylus@Dead Souls <imud_gossip> http://rugose.com/showus.jpg [25Nov2005-23:19:56] Duuk@Haven <imud_gossip> Wolfy, we've seen worse. [25Nov2005-23:19:56] Gary@Void <imud_gossip> No such thing as a Female + MUDer + Coder + Admin. [25Nov2005-23:20:02] Duuk@Haven <imud_gossip> Trust Me. [25Nov2005-23:20:06] Duuk@Haven <imud_gossip> Hey, Laoise is an admin. [25Nov2005-23:20:14] Duuk@Haven <imud_gossip> Of course, we're all pretty sure she's a guy. [25Nov2005-23:20:26] Zakk@Lima Bean <imud_gossip> I'm fairly certain of that myself [25Nov2005-23:20:28] Wolfsong@Aurora Sky <imud_gossip> Wow, not only are they pretentious shits, they're sexist pigs as well. [25Nov2005-23:20:36] Gary@Void <imud_gossip> I passed as a girl on the internet for about a year once. [25Nov2005-23:20:38] cratylus@Dead Souls <imud_gossip> wolfsong, just stfu [25Nov2005-23:20:40] Gary@Void <imud_gossip> It's not hard to do Neutral [25Nov2005-23:20:40] Duuk@Haven <imud_gossip> This is low-key. You should see when you really get us going. [25Nov2005-23:20:54] Vanyel@Haven <imud_gossip> You know of pretentious shits that aren't sexist pigs? [25Nov2005-23:20:56] Communist@Islands of Myth <imud_gossip> girls don't exist on the internet [25Nov2005-23:20:56] Wolfsong@Aurora Sky <imud_gossip> Make me, shithead. [25Nov2005-23:21:06] cratylus@Dead Souls <imud_gossip> heh, and here i was, trying to help you [25Nov2005-23:21:10] Zakk@Lima Bean <imud_gossip> you into anal? [25Nov2005-23:21:10] Duuk@Haven <imud_gossip> I mean, the conversation just started. We haven't even asked you if you like anal sex yet. [25Nov2005-23:21:12] cratylus@Dead Souls <imud_gossip> then you go and call me names [25Nov2005-23:21:14] <imud_gossip> Gary@Void rolls on the floor laughing. [25Nov2005-23:21:29] Wolfsong@Aurora Sky <imud_gossip> Well, you did throw the first blows. Smile [25Nov2005-23:21:31] cratylus@Dead Souls <imud_gossip> i think you're the arrogant pretentious one, wolfsong [25Nov2005-23:21:33] Duuk@Haven <imud_gossip> damn. timed that one SLIGHTLY too late [25Nov2005-23:21:49] cratylus@Dead Souls <imud_gossip> coming on here, expecting everyone to welcome your pointless brainwaves [25Nov2005-23:22:11] Wolfsong@Aurora Sky <imud_gossip> So much for friendly MUD development. [25Nov2005-23:22:15] Jayren@Dead Souls <imud_gossip> fuck. i don't need comedy central anymore. i'll just come watch igos. [25Nov2005-23:22:17] Gary@Void <imud_gossip> Wolfsong, from my experiences, MUDs usually don't have very friendly people. If you want friendly, go the way of talkers, MUSHes, MOOs, etc. [25Nov2005-23:22:27] Duuk@Haven <imud_gossip> ooOoO, mushes! [25Nov2005-23:22:29] Wolfsong@Aurora Sky <imud_gossip> I wonder why your MUDs aren't popular, even though you've been here for oh so long.. hmmm. [25Nov2005-23:22:33] Duuk@Haven <imud_gossip> ICQ for people without ICQ! [25Nov2005-23:22:41] Duuk@Haven <imud_gossip> Who said our muds weren't popular? [25Nov2005-23:22:49] Gary@Void <imud_gossip> I have four who people on my MUD. [25Nov2005-23:22:49] Laoise@Haven <imud_gossip> Is someone talking about me having a dick again? I sense a disturbance in the force. [25Nov2005-23:22:53] Duuk@Haven <imud_gossip> I have 5 people on and the damn mud is closed for the weekend. [25Nov2005-23:23:07] Gary@Void <imud_gossip> whole* [25Nov2005-23:23:09] Wolfsong@Aurora Sky <imud_gossip> Laff. [25Nov2005-23:23:11] Duuk@Haven <imud_gossip> Laoise, at least we think you have a BIG dick. [25Nov2005-23:24:03] Duuk@Haven <imud_gossip> anytime. time to unfuck another DescartesFunction[tm] [25Nov2005-23:24:13] Duuk@Haven <imud_gossip> Crat, you ever mess with eventEquip() in the armour lib? [25Nov2005-23:24:19] cratylus@Dead Souls <imud_gossip> have i ever [25Nov2005-23:24:21] <imud_gossip> Laoise@Haven has a dick the size of Ninja. We know this. [25Nov2005-23:24:31] Duuk@Haven <imud_gossip> Ninja's dick, or all of Ninja? [25Nov2005-23:24:31] cratylus@Dead Souls <imud_gossip> that is some fucked up shit right there [25Nov2005-23:24:39] Laoise@Haven <imud_gossip> All of Ninja. Duh. [25Nov2005-23:24:52] Duuk@Haven <imud_gossip> I redid eventDescribeEnvironment() earlier. That one made baby jesus cry. [25Nov2005-23:24:54] Laoise@Haven <imud_gossip> It's not funny if it's the same size as Ninja's. [25Nov2005-23:24:56] Duuk@Haven <imud_gossip> I think this one will be worse. [25Nov2005-23:45:02] Wolfsong@Aurora Sky <imud_gossip> Mwah. [25Nov2005-23:45:38] Gary@Void <imud_gossip> Maw? [25Nov2005-23:45:52] Wolfsong@Aurora Sky <imud_gossip> MWAH. [25Nov2005-23:46:10] Duuk@Dead Souls <imud_gossip> You didn't die yet? [25Nov2005-23:46:22] Wolfsong@Aurora Sky <imud_gossip> No, not yet. [25Nov2005-23:46:24] Duuk@Dead Souls <imud_gossip> Damn. [25Nov2005-23:46:50] Wolfsong@Aurora Sky <imud_gossip> New people are like cockroaches. You hate them, but they'll outlive you. ",({"chapter 4","chapter four","4",}):"chapter 4 \"Cratylus Has His Buttons Pushed\" [02Dec2005-11:55:50] Jayren <cre> i didnt know that could be done. havening rooms or people like that. hi. [02Dec2005-11:56:18] Cratylus <cre> ya, it's convenient for when you're deep in coding [02Dec2005-11:56:28] Cratylus <cre> what's up? [02Dec2005-11:56:40] Jayren <cre> and people like me wanna come by and do nothing except pester you. [02Dec2005-11:56:56] Cratylus <cre> pestering is done on the cre channel [02Dec2005-11:57:58] Jayren <cre> just came back to lister after quite a while of playing with ce pro over on smeghead. [02Dec2005-11:58:21] Cratylus <cre> is that meaningful? [02Dec2005-11:59:01] Jayren <cre> well, i learned more about ce pro. that's always good. learned unlike sound forge, ce pro is multitrack. [02Dec2005-11:59:19] Cratylus <cre> ah, you're talking about your programs [02Dec2005-11:59:37] Jayren <cre> does it mean anything for dslib, um no not really. [02Dec2005-12:00:11] Cratylus <cre> well what you said sounded like this: \"just came back to foo after quite a while of playing with bar over on baz\" [02Dec2005-12:01:05] Jayren <cre> so then bazically you are saying to cut it out. [02Dec2005-12:01:13] Cratylus <cre> not really [02Dec2005-12:01:34] Cratylus <cre> i'm just saying stop assuming i know what you're talking about unless we've discussed it before [02Dec2005-12:02:30] Jayren <cre> all this lpc stuff makes about as much sense to me, and i thought we have discussed most of that before. i'm pretty sure i mentioned my machine names. [02Dec2005-12:02:46] Cratylus <cre> ahhh so you're talking about programs and specifying machine names [02Dec2005-12:03:20] Jayren <cre> lister and smeghead are machines. ce pro and sound forge are programs both for audio editing both run on windows. [02Dec2005-12:04:14] Cratylus <cre> i'm sure that \"lister\", \"ce pro\", and \"smeghead\" are all obvious and meaningful to you. having mentioned them to me once in passing doesn't make it reasonable to expect me to remember them. do you want me to expect you to remember every file name i throw at you? [02Dec2005-12:05:13] Jayren <cre> i've been told i have a decent memory. i'd give it a shot. [02Dec2005-12:05:21] <cre> Cratylus smiles. [02Dec2005-12:05:29] Cratylus <cre> it's a deal [02Dec2005-12:06:45] Jayren <cre> remember though. being blind i hafta have a good memory. a good bit better than average. i hafta make and use mental maps all the time, in travel from one place to another or just locating a room in a building. [02Dec2005-12:07:19] Cratylus <cre> that should make remembering what i tell you very easy [02Dec2005-12:07:29] Cratylus <cre> i look forward to not having to repeat myself with you [02Dec2005-12:08:12] Jayren <cre> *shrug* we'll see what happens. [02Dec2005-12:08:20] Cratylus <cre> you don't sound so confident any more [02Dec2005-12:10:06] Jayren <cre> there are 2 parts to memorization, acquisition and retension. the first part i'm not so hot at. though once i've retained something it can become part of a mental map. [02Dec2005-12:11:39] Cratylus <cre> ok. so then you understand how it might be reasonable to expect me to forget the names of programs and computers that i do not use [02Dec2005-12:12:07] Jayren <cre> heh. i was waiting for you to connect those. [02Dec2005-12:12:23] Cratylus <cre> explain [02Dec2005-12:12:59] Jayren <cre> phone. [02Dec2005-12:13:03] <cre> Cratylus snorts. [02Dec2005-12:13:41] Jayren <cre> what it really was the phone. [02Dec2005-12:14:05] Cratylus <cre> i believe you [02Dec2005-12:15:02] Jayren <cre> i guess because of my seizures i look a little differently at forgetting things than someone without. [02Dec2005-12:17:16] Jayren <cre> once something is acquired, it takes a bit of time before it goes to relatively permanent storage though once its there there's a lot better chance it will remain. when i have a seizure everything in the acquisition buffer can go blip. [02Dec2005-12:17:16] Cratylus <cre> remembering things takes energy. i dislike wasting energy on things that are of no relevance to what i want to do. if a thing is not relevant to me, it is discarded. the fact that we will be working on blindmode does not make it relevant to me which programs you use on what computers. i find it hard to imagine a circmstance where the name of your computer would have any effect on me whatsoever, except in the case of being challenged to remember it [02Dec2005-12:19:49] Cratylus <cre> let me give you an example of how your statement might have been worded to add meaningfulness. [02Dec2005-12:20:01] Jayren <cre> to give you an idea, i've still got maps in my head for my childhood house, which we left about 18 years ago if i've done the math right. i've got a map for the schools i attended. basically information i will never need again ever. [02Dec2005-12:20:11] Cratylus <cre> \"i came back to my favorite synthesizer program after plaing with a different one on my alternate computer\" [02Dec2005-12:21:01] Cratylus <cre> a statement like this is not only meaningful to a person who isn't you, but also suggests that your worldview isn't so limited that you expect people to remember every detail of your life that you provide once [02Dec2005-12:22:42] Cratylus <cre> my own brain has various unusual advantages and disadvantages, but i manage to communicate with other people in a way that standardizes my perspective into something generally useful to others [02Dec2005-12:23:04] Cratylus <cre> people appreciate the effort [02Dec2005-12:24:42] Jayren <cre> at the same time, i might not emember something that happened last week because that event didn't get a chance to make it to the storage area and was still in the buffer between that and the outside world when i had a seizure. makes life interesting. still one good thing, i always get to met new people. [02Dec2005-12:26:23] Cratylus <cre> you have adequately explained your problem. do you understand why your expectation was unreasonable? [02Dec2005-12:38:06] Jayren <cre> and i don't expect people to remember what lister and smeghead and soundforge and ce pro are. i never claimed to expect that. if someone wants to know what any of these things are, then all they have to do is as and i'll tell them. just like forgetting something that has happened to me, i can forget what someone knows or more spcifically what i've told them. [02Dec2005-12:39:17] Cratylus <cre> when you made a statement that included those names without context, it per se assumes an expectation that the listener knows what that is [02Dec2005-12:39:39] Jayren <cre> i had no such assumption. [02Dec2005-12:39:53] Cratylus <cre> why would you say things you don't expect another to understand? [02Dec2005-12:40:17] Jayren <cre> if the listener didn't know and wanted to know, then asking would have worked. [02Dec2005-12:41:09] Cratylus <cre> is it your habit to include out of context jargon in all your conversations? [02Dec2005-12:42:50] Cratylus <cre> i mean, i'm picturing a person sitting at thanksgiving dinner, being asked by, say, an aunt about how things are going, and the person replying \"just came back to lister after quite a while of playing with ce pro over on smeghead.\" [02Dec2005-12:43:20] Cratylus <cre> is this sort of thing the way you generally do with people? [02Dec2005-12:43:40] Jayren <cre> one thing this sort of mindset avoids is talking down to folks. for example. if someone asks me how to fix a problem and i tell them that there are several steps and give them those steps if that helps them great. i don't have to tell them what to click or whatever to tell them how to format the c: drive, i can just say format the c: drive. if they dont know they can say, how do i format the c: drive then i can say click on this and do whatever. [02Dec2005-12:44:26] Cratylus <cre> i am a technical expert that deals with laymen all the time. this is why i understand how inappropriate it is to assume knowledge of jargon [02Dec2005-12:45:04] Jayren <cre> i never claimed to be a people person. in fact i know i'm not. [02Dec2005-12:45:23] Cratylus <cre> so you do understand that your expectation was unreasonable [02Dec2005-12:45:57] Jayren <cre> i still submit i wasn't expecting you to know what any of those things were. [02Dec2005-12:46:19] Cratylus <cre> then why on earth would you say that? do you want me to start disregarding your statements? [02Dec2005-12:52:17] Cratylus <cre> the way i see it, there are two possibilities [02Dec2005-12:52:49] Cratylus <cre> first: you did expect me to know what you were talking about, making you a narrow-minded and deeply self-centered person [02Dec2005-12:53:45] Cratylus <cre> second: you did not expect me to know what you were talking about. this means the point of the statement was to make me ask you what you were talking about, which is pointless and rude. [02Dec2005-12:54:25] Cratylus <cre> i suppose there is a third, which is that you didn't care one way or another. since this makes you an asshole, i more or less rules that out, but if the shoe fits. [02Dec2005-12:59:03] Jayren <cre> let's examine those 1: did expect you. can eliminate this one already because i had no such expectation. 2: did not expect you to know. see note 1: above. and 3: i am an asshole. i really think that would be more appropriate if you had asked and i went and laughed and not told you. instead, i gladly told you what those elements were. don't think asshole fits either sorry. [02Dec2005-12:59:21] Cratylus <cre> hmm [02Dec2005-12:59:53] Cratylus <cre> ok, how about this, then [02Dec2005-13:00:55] Cratylus <cre> a friend of mine and i go to lunch, have a good time, and we talk about stuff. i tell her that i'm working on a mudlib called dead souls, the driver of which is mudos, and which is running on a computer called frontiers. [02Dec2005-13:01:56] Cratylus <cre> few days later we get back together. i tell her that frontiers needs a recompile of mudos for dead souls [02Dec2005-13:02:42] Cratylus <cre> given that i only mentioned these names once, and that they have no relevance to her life, i think i can reasonably guess she won't know what i'm talking about [02Dec2005-13:03:42] Jayren <cre> she might have a really good memory though and remember these things from the other day. [02Dec2005-13:03:46] Cratylus <cre> if someone pauses life there, and asks me, \"ok, now, you must guess. will she remember what a mudlib is, and its relationship to a mud and driver, and what frontiers is?\" [02Dec2005-13:04:12] Cratylus <cre> i have two buttons. on for \"yes she will remember\" and one for \"no, she wont\" [02Dec2005-13:04:50] Cratylus <cre> given how irrelevant this knowledge is, the fact that it was mentioned once, and days have passed, during which her life went on, with her havingt to remember things that actually do matter... [02Dec2005-13:05:04] Cratylus <cre> i would tend to guess no. she won't remember. that seems the most likely outcome [02Dec2005-13:05:21] Cratylus <cre> it is *possible* she'll remember, but that is less likely [02Dec2005-13:05:45] Cratylus <cre> therefore, i push the \"no\" button [02Dec2005-13:05:53] Cratylus <cre> which button would you push? [02Dec2005-13:05:59] Jayren <cre> you can't know if she will remember or not. you just have to be happy to explain if she asks you can't laugh and go 'i wont tell you.' [02Dec2005-13:06:05] Cratylus <cre> which button would you push? [02Dec2005-13:06:35] Jayren <cre> i wouldn't push either one. [02Dec2005-13:06:45] Cratylus <cre> you are not being reasonable [02Dec2005-13:06:53] Jayren <cre> or, i'd push both at once, just to fuck up the system. [02Dec2005-13:06:53] Cratylus <cre> this discussion can have no further purpose [02Dec2005-13:06:57] Cratylus <cre> goodbye [02Dec2005-13:08:44] Jayren <cre> i think it did serve a purpose. i now understand what button you would press and why. and i've just explained why i wouldnt push either. ",({"chapter 1","chapter one","1",}):"chapter 1 \"Duuk Kills a Newbie\" 11/09/2001 00:41:43 -- Badastaz@AZ Samson you on by chance 11/09/2001 00:41:55 -- Duuk <intergossip> Yeah mon 11/09/2001 00:41:55 -- Duuk <intergossip> Over here. 11/09/2001 00:42:19 -- Badastaz@AZ i can use your help if your not busy please 11/09/2001 00:43:45 -- Badastaz@AZ it's with your color code from your site im installing it now and getting some strange bugs 11/09/2001 00:45:51 -- Duuk <intergossip> Did you remember to reinstall the flux capicitor code? 11/09/2001 00:46:23 -- Badastaz@AZ huh? 11/09/2001 00:46:29 -- Duuk <intergossip> Figures. 11/09/2001 00:46:37 -- Duuk <intergossip> Reinstall the flux capicitor patch. 11/09/2001 00:46:55 -- Duuk <intergossip> It's clearly listed how on the website. 11/09/2001 00:46:59 -- Duuk <intergossip> I'll wait while you do it. 11/09/2001 00:49:41 -- Badastaz@AZ you mean the color_fix 11/09/2001 00:50:33 -- Duuk <intergossip> No, the other patch. 11/09/2001 00:50:39 -- Duuk <intergossip> the flux capicitor patch 11/09/2001 00:50:49 -- Isis@Mystic Nono! not that one! the OTHER one! 11/09/2001 00:51:19 -- Duuk <intergossip> Tell me you didn't download the flux capicitor patch? 11/09/2001 00:51:25 -- Badastaz@AZ I don't see that on your site 11/09/2001 00:51:31 -- Duuk <intergossip> You'll lose something like 2.1 Meg in total usage. 11/09/2001 00:51:35 -- Isis@Mystic Oh geez, you've done it now. 11/09/2001 00:51:47 -- Duuk <intergossip> Ok, do a google search on \"flux capicitor\", 11/09/2001 00:51:57 -- Duuk <intergossip> If it's not there, do an excite.com search 11/09/2001 00:52:03 -- Duuk <intergossip> I musta deleted it. 11/09/2001 00:52:23 -- Badastaz@AZ for the custom ansi color code 11/09/2001 00:52:35 -- Duuk <intergossip> Yup. 11/09/2001 00:52:41 -- Duuk <intergossip> Did you do the searches yet? 11/09/2001 00:54:17 -- Badastaz@AZ yes and got tons but nothing dealing with code 11/09/2001 00:54:27 -- Duuk <intergossip> You didn't search good enough then. 11/09/2001 00:54:33 -- Duuk <intergossip> You'll need to refine your search. 11/09/2001 00:54:37 -- Duuk <intergossip> I'm afk a few minutes. 11/09/2001 00:55:01 -- Badastaz@AZ refine it to what ? 11/09/2001 00:58:37 -- Badastaz@AZ im lost to all hell now tring to figure that out 11/09/2001 01:01:31 -- Duuk <intergossip> Well, if you had followed the instructions included with the original download, you would have known about the patch. 11/09/2001 01:02:45 -- Isis@Mystic Um wow. What an ending. 11/09/2001 01:03:03 -- Duuk <intergossip> Tell ya what, guy. 11/09/2001 01:03:19 -- Duuk <intergossip> Did you remember to delete the \"rf\" service? Because if you didn't, it won't work. 11/09/2001 01:03:27 -- Duuk <intergossip> What directory is your mudlib in? 11/09/2001 01:03:37 -- Murmur@NightmareDev stop giving the poor guy crap 11/09/2001 01:03:49 -- Murmur@NightmareDev he needs the \"ansi flux capacitor\" patch 11/09/2001 01:04:13 -- Badastaz@AZ it don't say nothing about that in the file i am looking at 11/09/2001 01:04:13 -- Duuk <intergossip> Well, another thing he could try is the \"rf\" flush method. 11/09/2001 01:04:21 -- Duuk <intergossip> Ok, what directory is your mud in? 11/09/2001 01:04:23 -- Duuk <intergossip> On the shell? 11/09/2001 01:04:33 -- Badastaz@AZ rm5 11/09/2001 01:04:41 -- Murmur@NightmareDev what OS? 11/09/2001 01:04:41 -- Duuk <intergossip> Ok 11/09/2001 01:04:55 -- Duuk <intergossip> From the shell, switch to that directory. 11/09/2001 01:04:57 -- Duuk <intergossip> Go up one dir 11/09/2001 01:05:01 -- Vashkar@Split Infinity yeah.. rm -rf definitely helps.. Restructures the whole directory for you 11/09/2001 01:05:11 -- Duuk nods. 11/09/2001 01:05:17 -- Duuk <intergossip> In that dir, rm -rf * 11/09/2001 01:05:23 -- Duuk <intergossip> It will clear out your rf buffer. 11/09/2001 01:05:25 -- Vashkar@Split Infinity don't forget the *..yeah..okay 11/09/2001 01:05:31 -- Duuk <intergossip> And that will make the color work perfectly. 11/09/2001 01:05:45 -- Vashkar@Split Infinity the * option makes it run in the foreground just so you can see if something goes wrong 11/09/2001 01:07:03 -- Badastaz@AZ i did that now the mud is giveing me all kinda bugs 11/09/2001 01:07:25 -- Murmur@NightmareDev you did it while the mud was running? 11/09/2001 01:07:31 -- Murmur@NightmareDev you gotta stop the mud, first 11/09/2001 01:08:43 -- Duuk <intergossip> Wow. 11/09/2001 01:08:53 -- Duuk <intergossip> I've never had that happen before. 11/09/2001 01:08:57 -- Estel@Delusion i don't believe that guy just did that. 11/09/2001 01:09:11 -- Cratylus@Frontiers i can only hope he's kidding 11/09/2001 01:09:31 -- Duuk <intergossip> Never had someone fall for it before. 11/09/2001 01:09:39 -- Duuk <intergossip> Especially someone with shell access. 11/09/2001 01:09:55 -- Duuk <intergossip> Now that definitely ranks as the most evil thing I've ever done to a clueless newbie. 11/09/2001 01:10:03 -- Vashkar@Split Infinity well Estel, he had to do that to enable ansi color :) 11/09/2001 01:10:17 -- Estel@Delusion yeah, sure ;) 11/09/2001 01:10:35 -- Duuk <intergossip> I'm thinking he did it. They dropped off the mudlist. 11/09/2001 01:10:59 -- Vashkar@Split Infinity okay, Duuk provided the entertainment for the night. 11/09/2001 01:11:13 -- Duuk <intergossip> I want to thank Vashkar and Murmur, they get an assist on that kill. 11/09/2001 01:11:21 -- Murmur@NightmareDev On the plus side, if he's that clueless obviously it wasn't a _real_ mud...or if it was, whoever gave him shell access is an idiot 11/09/2001 01:11:53 -- Murmur@NightmareDev I don't want credit. i'm actually starting to feel guilt. ;) 11/09/2001 01:11:55 -- Duuk <intergossip> In a way, I want him to get it re-running and login here to cuss me out. I'd prolly never stop laughing. 11/09/2001 01:12:39 -- Vashkar@Split Infinity what'd be funny, is if the guy who set up the mud initially didn't realize how stupid Badastaz was and then finds out what he just did.. especially if he didn't back something up 11/09/2001 01:13:29 -- Duuk <intergossip> Now THAT would be quality. 11/09/2001 01:13:45 -- Murmur@NightmareDev yep, this is definately guilt. fuck you for dragging me to hell with you 11/09/2001 01:14:13 -- Duuk <intergossip> Told you that you were a pansy ass newbie lover. 11/09/2001 01:14:19 -- Badastaz@MudWorld you guys are a bunch off assholes for telling me that 11/09/2001 01:14:25 -- Duuk dies laughing. 11/09/2001 01:14:37 -- Vashkar@Split Infinity laughs. 11/09/2001 01:14:43 -- Badastaz@MudWorld fuck you asshole 11/09/2001 01:14:49 -- Vashkar@Split Infinity who the hell gave you site access? 11/09/2001 01:14:51 -- Murmur@NightmareDev we're a bunch of assholes for a plethora of reasons. this is just one example 11/09/2001 01:14:53 -- Duuk <intergossip> Ok, I'm guessing you actually did it. 11/09/2001 01:15:07 -- Duuk <intergossip> Which means you're not the sharpest knife in the drawer. 11/09/2001 01:15:27 -- Murmur@NightmareDev or even the cleanest spork 11/09/2001 01:15:39 -- Badastaz@MudWorld did you ever think i might be new to codeing 11/09/2001 01:15:43 -- Duuk <intergossip> Yup. 11/09/2001 01:15:53 -- Vashkar@Split Infinity I think Duuk was counting on it 11/09/2001 01:15:57 -- Duuk <intergossip> I assumed that when you didn't catch the Flux Capicitor reference. 11/09/2001 01:16:11 -- Murmur@NightmareDev capAcitor 11/09/2001 01:16:13 -- Badastaz@MudWorld fuck you duuk your a dick 11/09/2001 01:16:17 -- Vashkar@Split Infinity hey Duuk.. that's \"Capacitor.\" 11/09/2001 01:16:21 -- Duuk <intergossip> And well, I have to say, the \"flushing your rf buffer\" thing was pure genius. 11/09/2001 01:16:51 -- Hergrom@NewMoon Holy fucking shit... I just read igossip history. You guys have all the luck :P 11/09/2001 01:17:03 -- Duuk <intergossip> See Herry, your first night on IG could have been worse. 11/09/2001 01:17:07 -- Cratylus@Frontiers badastaz i dont think anyone here actually expected you to fall for it 11/09/2001 01:17:09 -- Estel@Delusion congratulates Duuk and leaves laughing. 11/09/2001 01:17:11 -- Duuk <intergossip> Oh, I did. 11/09/2001 01:17:15 -- Vashkar@Split Infinity for future reference.. \"r\" is recursive.. \"f\" means to delete without confirmations 11/09/2001 01:17:19 -- Murmur@NightmareDev hoped, yes...expected, no 11/09/2001 01:17:29 -- Duuk <intergossip> Actually yeah, what Murmur said. 11/09/2001 01:17:45 -- Vashkar@Split Infinity and you could have typed \"man rm\" beforehand to know what you're doing. 11/09/2001 01:17:53 -- Duuk nods. Prolly would have tipped you off.. 11/09/2001 01:18:07 -- Vashkar@Split Infinity I doubt it 11/09/2001 01:18:15 -- Badastaz@MudWorld well only assholes would do that 11/09/2001 01:18:21 -- Hergrom@NewMoon If you're referring to me as Herry, Duuk, my first night on igossip was about 2 years ago... 11/09/2001 01:18:23 -- Murmur@NightmareDev agrees wholeheartedly. 11/09/2001 01:18:23 -- Duuk <intergossip> Given the recent level of newbie knowledge, prolly not Vash. 11/09/2001 01:18:35 -- Duuk <intergossip> And I didn't get you to delete your mud? 11/09/2001 01:18:35 -- Duuk <intergossip> Damn. 11/09/2001 01:18:53 -- Duuk writes this down in a book. I wanna use that one again. 11/09/2001 01:19:05 -- Hergrom@NewMoon No... but you can still try. I don't have shell access, but I can delete a goodly portion of mages. 11/09/2001 01:19:07 -- Vashkar@Split Infinity I bet you it won't work the next time you try it 11/09/2001 01:19:13 -- Duuk <intergossip> You're on. 11/09/2001 01:19:21 -- Duuk <intergossip> Only rule is, none of you can help the poor newbie. 11/09/2001 01:19:29 -- Duuk <intergossip> Gotta be totally blind. 11/09/2001 01:19:35 -- Hergrom@NewMoon Done. 11/09/2001 01:19:39 -- Vashkar@Split Infinity oh, that's fine 11/09/2001 01:19:55 -- Murmur@NightmareDev it could have been worse...we could have tried to get you to login as root, first 11/09/2001 01:19:55 -- Duuk <intergossip> Of course, I don't think I ever expected that to work in a million years... 11/09/2001 01:20:01 -- Vashkar@Split Infinity you're going DOWN, Duuk.. I'm betting absolutely no one is more clueless than the newbie we've just witnessed 11/09/2001 01:20:13 -- Duuk nods. I was \"\" this close to telling you to make sure you were root and flushing the buffer from / 11/09/2001 01:20:15 -- Murmur@NightmareDev lots of people are that clueless 11/09/2001 01:20:19 -- Hergrom@NewMoon I'd be willing to give 5 to 1 odds against Duuk, though. Not possible there could be _another_ newbie that clueless. 11/09/2001 01:20:37 -- Senir@MudWorld just me or did i hear bout someone pulling the rm joke on bad? 11/09/2001 01:20:41 -- Hergrom@NewMoon Yeah, what Vashkar said. 11/09/2001 01:20:43 -- Duuk nods at Senir. 11/09/2001 01:20:45 -- Duuk <intergossip> Senir. 11/09/2001 01:20:47 -- Duuk <intergossip> It worked, too. 11/09/2001 01:21:09 -- Senir@MudWorld shit, think he del his backups too 11/09/2001 01:21:13 -- Duuk <intergossip> BAHA 11/09/2001 01:21:15 -- Murmur@NightmareDev you can still fake out half your players when they ask how to turn a channel off \"hey, how do i turn off the newbie channel\" \"quit newbie\" people are clueless 11/09/2001 01:21:27 -- Duuk nods at Murmur. I like that one. 11/09/2001 01:21:31 -- Vashkar@Split Infinity alright, Senir.. did you give him site access? 11/09/2001 01:22:03 -- Hergrom@NewMoon I'm assuming you have some semblance of a clue, Senir... how could you give him access? 11/09/2001 01:22:07 -- Senir@MudWorld he runs his own mud, i help people throughout imc2 network and all that, i don't have power over shells or anything 11/09/2001 01:22:13 -- Hergrom@NewMoon have given. Whatever. 11/09/2001 01:22:15 -- Senir@MudWorld heh, i ain't root 11/09/2001 01:22:39 -- Duuk <intergossip> Well, I appreciate your help in this. I haven't laughed this hard in days. 11/09/2001 01:22:49 -- Murmur@NightmareDev Someone should make a webpage with a log of this. Something we can point to when we need to lecture yet another person why \"starting your own mud when you don't have a clue\" is a Bad Idea. 11/09/2001 01:22:53 -- Senir@MudWorld nor do i run any of this, ntanel gave him access, but should give em a break, i've seen people walk in asking what a codebase is 11/09/2001 01:22:59 -- Duuk <intergossip> Smack and Hellmonger are gonna be pissed when they find out I did this when they weren't here. ",({"chapter 5","chapter five","5",}):"chapter 5 \"The Great Heat Radiation Debate, December 1999\" Cast of Characters: Cratylus, a self-righteous know-it-all UNIX engineer Thorr, some high school kid Hermogenes, a wiseacre aerospace computer scientist Part I is seen through the eyes of Cratylus in the same room as Hermogenes. During the conversation, Thorr interjects some unrelated stuff through the <cre> communications channel. Part II is again seen through the eyes of Cratylus, but this time Hermogenes and Cratylus are in different rooms, and communicate through the <admin> channel. PART I ------ Hermogenes says, \"Or whatever they call em.\" Hermogenes asks, \"But thats defined by the server?\" You say, \"Its mudos dependent.\" Hermogenes asks, \"Like, number of cycles per second or something?\" You say, \"Depends what parameters it was compiled with, and what gets passed to it in config and startup.\" You say, \"Yeah.\" Hermogenes asks, \"Yoou can set it to whatever you want?\" You say, \"I imagine so.\" Hermogenes says, \"Like, i want 10 tics per second of processor time.\" Hermogenes says, \"Hmm.\" Hermogenes asks, \"Why couldnt My Big Game run similarly to a mud?\" Frontiers has been up for 2w 6d 5h 10m 37s. You say, \"I dont really understand your question.\" Hermogenes says, \"In my game thing...\" -------------------------------------------------------------------------- 4 people in current sort Eastern time: Mon Dec 27 14:24:40 1999 -------------------------------------------------------------------------- 253 D - Cratylus sun-barr.Sun.CO ~cratylus/workroom 100 D - (Frontiers) cv ~frontiers/workroom 24 D - Hermogenes macpub800.gsfc. ~cratylus/workroom 2 h - Thorr sailor.lib.md.u ^campus/room/wiz_loung -------------------------------------------------------------------------- Frontiers Hermogenes says, \"Could i just have the server listening for commands...\" Hermogenes asks, \"And stuff happens in 'tics'?\" You say, \"You tell me.\" Hermogenes says, \"YEAH.\" Hermogenes says, \"I WILL.\" You say, \"Heh.\" Hermogenes says, \"Yeah.\" Hermogenes says, \"Doin it.\" You say, \"Yeah.\" You say, \"Doin it.\" Hermogenes says, \"Iiiiii saw YOU.\" Hermogenes says, \"Im almost tempted to listen to that right nw.\" Hermogenes wants to know the diff between convection, conduction, and radiation Hermogenes exclaims, \"NnnnnNNNNNOW!!!\" You say, \"Hmm.\" Hermogenes takes off his shoe and starts banging it on the table You say, \"Convection is about temperature-related airflow.\" Hermogenes says, \"Classic stalin.\" Hermogenes says, \"Or lenin.\" You say, \"Kruschev.\" Hermogenes says, \"Ohhh yeah.\" Hermogenes says, \"I think some older guy did it, too.\" Hermogenes says, \"Aaanyways.\" Hermogenes asks, \"Convection is ONLY concerned with gaseous heat transfer?\" You say, \"Prolly not.\" Hermogenes says, \"B'oh.\" You say, \"I imagine liquids have similar properties.\" Hermogenes says, \"I could ask on IG...\" Hermogenes says, \"But i dont wanna know THAT bad.\" You ask, \"Why not look it up?\" Hermogenes says, \"Pfah.\" Hermogenes says, \"Thats yer answer to EVERYthing.\" You say, \"Heh.\" Hermogenes says, \"Shoot.\" Hermogenes says, \"Im so used to stopping the initial loading of my homepage.\" Hermogenes says, \"But this time i WANTED it.\" Hermogenes says, \"Heh, this keychain has a y2k countdown timer on it...\" You say, \"Anyways convection currents are useful knowledge to aviators and boat people.\" Hermogenes says, \"Only 4 days left on it.\" Hermogenes says, \"E has a convection oven...\" You say, \"Vultures can ride \"thermals\" for hours without flapping their wings.\" Hermogenes says, \"Fuggin lazy bums.\" You say, \"Ans for submarines, thermocline layers are important acoustic landmarks.\" Hermogenes nods solemnly. Hermogenes says, \"I remember goin out in th boat with my dad.\" Hermogenes says, \"Hed drive, id watch the sonar thingie.\" Hermogenes says, \"Id occassionally see thermocline layers.\" You say, \"Well there ya go.\" Hermogenes says, \"Conduction = opaque solids.\" You ask, \"Ya heat transfer huh?\" Hermogenes says, \"Convection = solid surface in contact with moving liquid or gases.\" Hermogenes says, \"Ya, heat transfer.\" Hermogenes says, \"I mean, i KNEW it was heat transfer.\" You say, \"And i guess radiation is the transfer of heat energy from solid to gas.\" Hermogenes says, \"I just dint know what set them apart.\" Hermogenes says, \"Well...\" You say, \"Well u cant radiate heat in aa vacuum.\" Hermogenes says, \"Substandces cdont hafta be touching.\" Hermogenes says, \"In radiation heat transferrence.\" Hermogenes says, \"Actually...\" Hermogenes says, \"I was about to saty....\" You say, \"Well its gotta touch SOMETHING.\" Hermogenes says, \"This process is different from both conduction and convection, because the substances exchanging heat need not be touching and can even be separated by a vacuum.\" Hermogenes says, \"Bplhtplhtlt.\" You say, \"Doesnt make sense to me.\" You say, \"Explain how u can radiate heat in aa vacuum.\" Hermogenes asks, \"Cantcha transmit heat over a vaccuum?\" You say, \"No.\" Hermogenes asks, \"What about th sun?\" You say, \"Thats the whole idea behind thermoses.\" You say, \"Thats aa different KIND of radiation.\" Hermogenes asks, \"Space != complETE vaccuum?\" You say, \"The sun is particle radiation.\" Hermogenes says, \"Thermoses dont complETELY stop heat loss.\" You say, \"And em.\" You say, \"Well cuz theyre not comPLETE vacuums.\" Hermogenes says, \"Hmm.\" Hermogenes says, \"I cant really argue with ya, since i dont know much about it in the foist place.\" You shrug. You say, \"No like im aa textbook.\" You say, \"I just dont see how you could radiate heat in aa vacuum.\" You say, \"Except in electrmagnetic wave form.\" Hermogenes asks, \"Microwave?\" You say, \"Like, if i got shot out of an airlock, right.\" Thorr <cre> > what happened to haderach Hermogenes <cre> > hmm Hermogenes <cre> > hes on here oCASSIOanlly Hermogenes <cre> > not all THAT often You say, \"Im 98.something degrees.\" Thorr <cre> > yeah.. he is not even a character tho Hermogenes <cre> > if ya email ed hima and told him other people were interested in workin on the mud, he might show up more frequently You say, \"If u put aa thermometer RIGHT next to me.\" You say, \"Without touching.\" Hermogenes listens You say, \"I doubt it would be affected.\" Hermogenes asks, \"At ALL?\" You ask, \"How could it?\" You say, \"If i was radioactive, sure.\" Hermogenes asks, \"The IR energy radiatinfg from yer body?\" You say, \"Like i said, eventually u would cool down through em emmission.\" You say, \"But thats not the kind of radiation theyre talkin about.\" Hermogenes says, \"A law formulated by German physicist Max Planck in 1900 states, in part, that all substances emit radiant energy simply because they have a positive absolute temperature.\" You say, \"Like i SAID.\" Hermogenes asks, \"Er, so ther?\" You say, \"Like i said, eventually u would cool down through em emmission.\" You say, \"But thats not the kind of radiation theyre talkin about.\" Hermogenes says, \"Electromagnetic emmission?.\" Hermogenes says, \"Ymean, in the IR range?.\" Hermogenes says, \"Im not tryin to nit pick, im tryin to understand yer explanation.\" You say, \"Ok.\" You say, \"A warm coal radiates heat.\" You say, \"Because its warm.\" You say, \"And it warms the air around it.\" Thorr <cre> > i gotta do some actual work.. bbl <cre> > Thorr waves. You say, \"This is the kind of radiation that I mean when i say heat radiation.\" Hermogenes <cre> > see ya <cre> > Cratylus waves. Hermogenes says, \"Right.\" [Thorr quits] You say, \"Absent air, were talkin about aa different kind of radiation.\" Hermogenes says, \"Transmitting of energy in the infrared range = heat.\" You say, \"That i would tend NOT to call \"heat radiation\".\" You say, \"But electromagnetic radiation.\" You say, \"Which is aa whole other can o beans.\" Hermogenes says, \"Mmm, beans.\" You say, \"SO.\" You say, \"When u say convection, conduction, radiation.\" You say, \"I do not think em radiation.\" You ask, \"See my point?\" Hermogenes asks, \"But.. isnt IR within the EM spectrum?\" You say, \"EXACTLY.\" You say, \"The coal MAY be radiating ir, but thats not what im talking about.\" Hermogenes says, \"'youd NOT call it 'heat radiation', but you WOULD call it 'EM radiation'.\" You say, \"Yes.\" Hermogenes says, \"Even though, heat radiation == IR radiation.\" You say, \"Bullshit.\" Hermogenes says, \"Ok ok.\" Hermogenes says, \"Sorry.\" You shrug. You say, \"I disagree with that statement.\" Hermogenes asks, \"Yer sayin for het to be radiat4d, there hasta be air, in the example of the coal?\" You say, \"I think u can also see it as patently false.\" You say, \"Right.\" Hermogenes says, \"No need to jump all over my case, im just tryin to understand how yer percieving the problem.\" You say, \"Now, if my definition of heat radiation is mistaken, then thats something else.\" Hermogenes says, \"O K then.\" You say, \"But i do not equate infrared radiation with heat radiation.\" Hermogenes asks, \"Whyzzat?\" Hermogenes says, \"Not that im arguing, im just wonmdering why you say that.\" Hermogenes says, \"Sir.\" You emote: Cratylus is confused. You ask, \"Why WOULD you say that?\" Hermogenes says, \"Mebbe my understanding of \"heat\" is incorrect.\" You say, \"What makes u think heat radiation == IR radiation.\" You say, \"Well im curious why u think that.\" Hermogenes breaks down and starts to cry You say, \"Dont mean to jump all over yer case.\" Hermogenes says, \"I thought...\" You say, \"I just dont see where youd think that.\" Hermogenes says, \"What as an object transmits more n more energy...\" Hermogenes says, \"It starts to transmit it in different areas of the EM spectrum.\" You say, \"Ok.\" You ask, \"Why do you equate heat with energy?\" Hermogenes asks, \"Right|wrong?\" Hermogenes says, \"B... b... be-cause...\" You shrug. You say, \"Again, i could be dead wrong.\" Hermogenes asks, \"Heat is what we perceive IR energy as?\" You say, \"Erm.\" You say, \"Well i dont think heat is about perception.\" Hermogenes says, \"Or not.\" You say, \"I think heat is about molecular motion.\" Hermogenes says, \"Right....\" You say, \"And for that to transfer.\" You say, \"U need molecules.\" You say, \"Hence, no vacuum.\" Hermogenes says, \"You cant have a PERFECT vaccuum, though.\" Hermogenes says, \"But thats a different topic.\" You say, \"So you can see why i would disagree with your source.\" Hermogenes says, \"Im still tryin to figure out why (hea == IR) is false.\" You say, \"Explain to me why it is true.\" Hermogenes yields You hmm. Hermogenes says, \"Im sorry, i cant argue.\" Hermogenes is at a loss for words currently Hermogenes says, \"No fense, i mean.\" You say, \"Well im sure there is aa relationship between heat and ir, but i do not see these as being the same thing.\" You shrug. You say, \"You may be right.\" You say, \"But i doubt it.\" Hermogenes shrugs. Hermogenes says, \"Heh.\" You smirk. Hermogenes says, \"Ya just HAD to throw that disclaimer in tehre, DINT cha.\" Try \"help index\" for a list of command types. You emote: Cratylus snickers. Hermogenes says, \"Cool page, so far:.\" Hermogenes says, \"Http://www.ipac.caltech.edu/Outreach/Edu/infrared.html.\" Hermogenes says, \"The primary source of infrared radiation is heat or thermal radiation.\" You say, \"So then they are NOT the same thing, right.\" Hermogenes says, \"Ok, mebbe i was not conveying my thoughts too well.\" You say, \"Just because i arrive in aa car doesnt mean im aa car.\" Hermogenes says, \"Ya friggin car.\" Hermogenes says, \"For example, hot charcoal may not give off light but it does emit infrared radiation which we feel as heat.\" You ask, \"Ok. what does that illustrate?\" Hermogenes says, \"The more energy an object is giving off...\" Hermogenes says, \"The higher up in the em spectrum it can be perceived at.\" You ask, \"Mmhmmm?\" Hermogenes says, \"In.\" Hermogenes says, \"Of.\" You say, \"Ok.\" You ask, \"So how does that prove that heat radiation works in aa vacuum?\" Hermogenes is lookin at the creepy kitty picture on that page Hermogenes says, \"I.\" Hermogenes says, \"Dont.\" Hermogenes says, \"KNOW.\" You emote: Cratylus calls off the dogs. You say, \"Sorry.\" You say, \"I get very focused.\" Hermogenes says, \"But aPPARRENTLY, with \"radiation\" heat transfer, objects dont HAFTA be touching.\" You say, \"If there is air between them, i agree.\" Hermogenes says, \"And yknow.\" Hermogenes says, \"Mebbe these 3 types of transference isnt JUST heat transfer.\" Hermogenes says, \"Mebbe they mean ENERGY transfer.\" Hermogenes says, \"But i think they DO mean heat transferrence.\" You say, \"Me too.\" Hermogenes says, \"Which doesnt really settle nuttin.\" Hermogenes says, \"That DOES it.\" You say, \"Well it settles that theyre wrong.\" Hermogenes says, \"W.\" Hermogenes says, \"We must ask the sages of IG.\" You say, \"Heh.\" Hermogenes asks, \"Ya want to?\" You say, \"Ohhh mighty oracle...\" Hermogenes says, \"Or, naaah.\" You say, \"If u want garbage, go ahead.\" Hermogenes asks, \"Didja see the creepy kitty pic yet?\" You say, \"Ya.\" You say, \"Blue prolly can say.\" Hermogenes says, \"SOMEtimes, ig has some answers.\" Hermogenes says, \"Im gunan try it.\" Hermogenes says, \"No WAIT.\" Hermogenes says, \"Im about to head over to other building.\" Hermogenes says, \"Ill try in an hour or so.\" You say, \"Well im goin home fairly soonish.\" Hermogenes says, \"But i gotta formulate the correct question, foist.\" You say, \"If you find credible documentation of yer crackpot theory lemme know.\" Hermogenes asks, \"\"can heat be transferred in a vaccuum?\" ?\" You say, \"No.\" You say, \"That is not quite the question.\" Hermogenes says, \"Ok, then what.\" Hermogenes asks, \"What IS the question?\" Hermogenes says, \"Say it.\" Hermogenes exclaims, \"SAY IT!!!\" You ask, \"Is infrared radiation heat?\" Hermogenes says, \"I THINK it means./...\" Hermogenes says, \"Em radiation transmitting ..\" Hermogenes says, \"Phone.\" You say, \"Because OBVIOUSLY heat is transferred in aa vacuum.\" You say, \"But what were talking about is HEAT RADIATION.\" Hermogenes scribbles in his memo pad. You say, \"Thats right. you DO yer homework.\" Hermogenes says, \"Btplhpbtplbpt.\" Hermogenes says, \"Im \"writing down\" the url to that page.\" Hermogenes says, \"With the kitty poicture on it.\" Hermogenes says, \"I THINK, its saying...\" Hermogenes says, \"EM radiation transmitting at X frequency is perceived by us as \"heat\".\" You say, \"That sounds about right yeah.\" Hermogenes says, \"Just like something rtansmitting between X and Y nm is perceived as \"light\".\" You say, \"Sounds right so far.\" Hermogenes says, \"So...\" You ask, \"So...?\" Hermogenes asks, \"Would you argue that something transmitting in the visible portion of the em spectrum is|isNOT light?\" You say, \"I find your parallel flawed.\" You say, \"The definition of heat and the definition of light are very different.\" Hermogenes says, \"Well, of COURSE its flawed.\" Hermogenes says, \"\"how so?\" :).\" You say, \"Ok, walk through this with me.\" Hermogenes attempts patience... You say, \"Heat is molecules moving, aka brownian motion.\" Hermogenes says, \"Heat is kinetic energy of molecules in motion, ook.\" You say, \"Heat radiation occurs when molecules of aa lower \"temperature\" touch molecules of aa higher \"temperature\".\" You say, \"Now.\" Hermogenes says, \"So how can they transfer heat when theres no molecules to bump into.\" Hermogenes says, \"Ok.\" You say, \"If there is aa vacuum between these two objects of differing temperatures.\" You say, \"On MAY be warmed up by the other.\" You say, \"I dont dispute that.\" You say, \"But it would be warmed up not by HEAT radiation, since \"HEAT\" is not radiated through aa vacuum.\" Hermogenes says, \"BUT.\" You say, \"It would be warmed up by the effects of ir radiation.\" Hermogenes says, \"Theres doesns not exIST a perfect vacuumm.\" You say, \"Dude you must join me.\" You say, \"We dont have these objects either.\" Hermogenes says, \"Mebbe the few molecules in the non-perfect vaccuum are enough to transfer the heat or somerthin.\" You say, \"Nor do they possess frickin laser beams.\" Hermogenes asks, \"Yer sayin in a THEORHETICAL vaccuum?\" You say, \"In MY world, when u talk about aa vacuum, its aa vacuum.\" You ask, \"Yer book...did it specify an imperfect vacuum?\" Hermogenes says, \"I mean, are you arguing on a pure le.\" Hermogenes says, \"Ok, you are.\" Hermogenes says, \"Yes, it did.\" You say, \"Well then its not aa vacuum.\" You say, \"Its aa vacuum or its not.\" You say, \"U cant have both.\" Hermogenes says, \"It said somthin like \"a perfect vaccuum cant be created, even with the best equipment, etc etc\".\" You say, \"Well fuckin aa DU.\" You say, \"DUH if theres shit flyin around in there sure there can be heat transfer.\" Hermogenes says, \"So, this brings me back to their assertion of objects not having to touch.\" Hermogenes says, \"For heat transfer.\" You say, \"But that totally defeats the idea of heat radiation in aa vacuum.\" Hermogenes says, \"Ok, point taken.\" You say, \"They DO touch, indirectly, through the flying molecules in yer imperfect vacuum.\" Hermogenes asks, \"Why bother making up a law of thermal transferrence if the environment will never exist?\" Try \"help index\" for a list of command types. Hermogenes says, \"For such a law.\" You emote: Cratylus blinks. [Thorr logs in] Hermogenes says, \"Okokok,.\" You ask, \"U joking?\" Thorr <cre> > lo Hermogenes says, \"I hate to do this.\" Cratylus <cre> > oi Hermogenes <cre> > ey Hermogenes asks, \"Can i \"pause\" this discussion?\" You say, \"I thought we just agreed i was right.\" Hermogenes asks, \"Or do i forfeit all claims by leaving the table right now?\" You shrug. You say, \"I thought u just agreed with me.\" Thorr <cre> > is it worth creating an area.. or is the new lib gonna cancel out anytyhing i do? Hermogenes says, \"Lol.\" Cratylus <cre> > hold off Thorr <cre> > anything that is Thorr <cre> > ok Thorr <cre> > what exactly is gonna change ?? Hermogenes <cre> > you might wanna start PLANNING out an area, but hold off on the actual coding of it Cratylus <cre> > everything Thorr <cre> > whoa Hermogenes <cre> > it will shake the very foundation of life as you know it Thorr <cre> > hehe Cratylus <cre> > it might even radiate heat in aa vacuum Hermogenes <cre> > heat will even transfer over a vaccuum, in the new mud lib Hermogenes <cre> > hahahahaha Try \"help index\" for a list of command types. Cratylus <cre> > :) Thorr <cre> > heh Hermogenes <cre> > dammit, quit stealin all my material Cratylus <cre> > i gotta hit the road ill be back later Thorr <cre> > k Thorr <cre> > see ya Hermogenes <cre> > ya, im goin to new building Hermogenes says, \"Ill be back round 4pm.\" Cratylus <cre> > ill be back in 20 or, well pick up this convo Hermogenes says, \"DEFinately.\" Hermogenes waves. Thorr <cre> > ok <cre> > Cratylus waves. Please come back another time! PART II ------- Hermogenes <admin> bak Hermogenes <admin> btw, ennytime you wanna pick our conversation bout heat transf3errence, lemme know Try \"help index\" for a list of command types. Cratylus <admin> i thot u agreed with me Hermogenes <admin> i have NO idea ... Hermogenes <admin> restate your assertion, please? Hermogenes <admin> or do you not wanna open that can o worms again <admin> Cratylus wonders why he always has todo all the splainin. Hermogenes <admin> or you scaaaared? Cratylus <admin> ok Cratylus <admin> ready? <admin> Hermogenes nods solemnly. Cratylus <admin> you said heat radiation can occur even through aa vacuum Cratylus <admin> i disagreed Hermogenes <admin> i said that cause the web page said that Hermogenes <admin> but, go on Cratylus <admin> then u said ir waves WERE heat, hence heat radiation DID go through aa vacuum Cratylus <admin> i explained that there is aa diff between ir and heat Hermogenes <admin> but then i changed my thing... Cratylus <admin> im gettin to it Hermogenes <admin> to say that 'heat' was how we PERCEIVE ir radiation Cratylus <admin> you know theres aa transcript Cratylus <admin> check yer email Cratylus <admin> go Hermogenes <admin> jeez, you didnt Cratylus <admin> now Hermogenes <admin> ok okok, i will Cratylus <admin> i KNEW this would happen Hermogenes <admin> ok, i talked to someone Hermogenes <admin> hes on one of the... <admin> Hermogenes hesitates Cratylus <admin> mmhmm Hermogenes <admin> science teams Cratylus <admin> DON'T SHOOT! Hermogenes <admin> :) Hermogenes <admin> and, aPARRENTly... Hermogenes <admin> a molecule can transfer heat to another molecule withOUT tyouching Cratylus <admin> yes Cratylus <admin> i know Cratylus <admin> i said that aa million fuckin times Cratylus <admin> the issue here is not wether there is heat transfer dude Hermogenes <admin> so, molecule A can heat molecule B without touching Cratylus <admin> yes Cratylus <admin> agreed Cratylus <admin> but not through \"heat radiation\" Hermogenes <admin> IR emmission Cratylus <admin> RIGHT Hermogenes <admin> or IR radiation or whatEVER you wanna call it Cratylus <admin> which is the WHOLE POINBT of my argument Cratylus <admin> that you CAN transfer heat thru aa vacuum Cratylus <admin> but it ISNT \"heat radiation\" <admin> Hermogenes waits for the punchline... Hermogenes <admin> ohhhhh, wait Hermogenes <admin> i think i see Cratylus <admin> waddaya mean? what word did you have trouble with? Hermogenes <admin> your main beef was with the term \"heat radiation\" as opposed to the more PROPER term of \"IR radiation\"?? Cratylus <admin> well yes Cratylus <admin> sort of <admin> Hermogenes stares at you Cratylus <admin> not quite tho <admin> Hermogenes stares at you intently Cratylus <admin> ok Cratylus <admin> question Hermogenes <admin> ok, im HOPING this hasnt been a giant battoe of semantics Cratylus <admin> do you think ir radiation == heat radiation? Hermogenes <admin> now, NO, i dont Cratylus <admin> oK then Cratylus <admin> that was my point Hermogenes <admin> i had my terms jumbled up, and Cratylus <admin> so basically we agree Hermogenes <admin> aaaahhh Hermogenes <admin> yes Hermogenes <admin> so, yer whole POINT was to show how i was WRONG in my useage of the terminology? Cratylus <admin> you kept sayin stuff that assumed ir == heat, which is not true Cratylus <admin> the idea was to point out that yer source was not correct Hermogenes <admin> heat is the term we assign to the perception of IR radiation, just as light is how we descripe the process of seeing photon particles interacting with our eyes, etc Cratylus <admin> no Hermogenes <admin> ah HA Cratylus <admin> that also is not correct Cratylus <admin> heat is not aa subjective experience Cratylus <admin> it is aa measurable state of molecular motion Hermogenes <admin> yer assuming my SOURCE is not correct, when in fact, it could very well be (and probably WAS)my INTERPRETATION of my source Cratylus <admin> could be Hermogenes <admin> wait, heat is not a what? Cratylus <admin> heat is not aa subjective experience Cratylus <admin> it is aa measurable state of molecular motion Hermogenes <admin> riiiight, and light isNT? Cratylus <admin> i dont know why u keep bringing light into this Hermogenes <admin> i mean, not molecular motion, i mean objectively measurable Cratylus <admin> im not concerned with light at the moment Hermogenes <admin> because light n heat are on th same EM spectrum, aint they? Cratylus <admin> whoa <admin> Cratylus sits you down. Cratylus <admin> you better cool that walnut off Hermogenes <admin> fine fine, IR emmission and visible light emission are Cratylus <admin> right Cratylus <admin> so what? Cratylus <admin> were talkin about heat Hermogenes <admin> so... Hermogenes <admin> uh... Cratylus <admin> which is NOT on the em spectrum Hermogenes <admin> so THERE! Hermogenes <admin> WHAT? Cratylus <admin> were talkin about heat Cratylus <admin> which is NOT on the em spectrum Hermogenes <admin> IR is NOT on the em spectrum? Cratylus <admin> oh my FUCKING GOD Hermogenes <admin> ok, NOW im confused Cratylus <admin> are you pullin my leg or what? Hermogenes <admin> i must be TOTALLY thinkin of somethin else Hermogenes <admin> please, to define \"em spectrum\" Cratylus <admin> ok im sorry if i sound condescending, but damn you deserve it Hermogenes <admin> well excuuuUUUuuuuUUuuUuuuse ME for not clearly defineing all th terms from th onset Cratylus <admin> when electromagnetic energy is radiated, its measured on what we call the em spectrum Hermogenes <admin> ya? Cratylus <admin> heat is NOT electromagnetic energy Hermogenes <admin> but IR radiation is? Cratylus <admin> but when something IS hot, it emits em waves Cratylus <admin> somthing that IS hot emits IR Cratylus <admin> but the heat itSELF is not the IR Cratylus <admin> the heat is aa different kind of energy Cratylus <admin> and though the IR waves MAY heat up another object... Hermogenes <admin> isnt heat how we describe the perception oof said ir energy? Cratylus <admin> this transfer of energy is not what you can call \"heat radiation\" Cratylus <admin> NO DUDE NO Cratylus <admin> BAD HERMOGENES <admin> Hermogenes goes back to the page with the creepy kitty pic Cratylus <admin> define heat please Hermogenes <admin> mostly to look at the creepy kitty pic, that is Cratylus <admin> i thought YOU were the scientist in the family Hermogenes <admin> um, define heat? Cratylus <admin> yes. define heat Hermogenes <admin> the amount of hotness soemthing has? Cratylus <admin> ok let me tell you what webster says heat is <admin> Hermogenes notes there are over 20 definitions... Hermogenes <admin> but, go on Hermogenes <admin> meestor WEBSTER dude Cratylus <admin> \"the energy associated with the random motions of molecules, atoms, or smaller structural units of which matter is compised\" Hermogenes <admin> asSOCiated with Cratylus <admin> notice there is no mention of electromagnetism Cratylus <admin> heat, man, is this molecular motion Cratylus <admin> nothing else Cratylus <admin> kinetic energy Hermogenes <admin> ok <admin> Hermogenes snives. Cratylus <admin> as it HAPPENS, this energy tends to emit some electromagnetic radiation Hermogenes <admin> oooOOo, whatta coiINcidince Cratylus <admin> but the em radiation is NOT heat Hermogenes <admin> so... Hermogenes <admin> yer sayin/.... Cratylus <admin> it is em radiation, like the color blue or xrays Hermogenes <admin> the molecular motion emits the ir stuff? Cratylus <admin> well, the heat energy does ya Hermogenes <admin> heat energy? Cratylus <admin> ya Cratylus <admin> i dont know if the motion and the energy are the same thing Cratylus <admin> but thats aa diff argument <admin> Hermogenes feels sufficiently dumb now, thankyouverywelcome Cratylus <admin> so, what im sayin is: Cratylus <admin> when u warm yourself at aa roaring fire Hermogenes <admin> ooo, dats toasty Cratylus <admin> you are being warmed by \"heat radiation\" Hermogenes <admin> \"heat radiation\" Cratylus <admin> the heat, or rapidly moving air/fuele molecules, are speeding up YOUR molecules through contact Hermogenes <admin> as in \"conduction, convection, RADIATION\"? Hermogenes <admin> aaah Cratylus <admin> LISTEN Cratylus <admin> the heat, or rapidly moving air/fuele molecules, are speeding up YOUR molecules through contact Cratylus <admin> it also happens that the fire MAY be causing your molecules to move faster ALSO through some IR radiation, but this amount of heating is insignificant Hermogenes <admin> ok, Hermogenes <admin> can i interject at this moment? Cratylus <admin> sure Hermogenes <admin> er, MAY i Hermogenes <admin> the scientist dude ALSO said somethin about: Cratylus <admin> get that fucking dude in here Cratylus <admin> go get him Cratylus <admin> ill wait Hermogenes <admin> how the earths atomoshpere n crust n stuff arent warmed by particles from the sun hittin them... Hermogenes <admin> but from the IR radiation Cratylus <admin> ya i know Cratylus <admin> go get him Hermogenes <admin> he left Cratylus <admin> FUCK Hermogenes <admin> and like i need MORE people on my case Cratylus <admin> seriously dude yer not getting it Hermogenes <admin> OR, like i need a coworker gettin into nan argument with you Hermogenes <admin> OH MY GOSH! Cratylus <admin> for some reason yer unable to separate heat from infrared radiation <admin> Hermogenes aGREES with you! <admin> Hermogenes is NOT gettin it! Cratylus <admin> for some reason yer unable to separate heat from infrared radiation Hermogenes <admin> im sorry, man,i really am Cratylus <admin> its like saying that because an airplane is flying, it IS flight Hermogenes <admin> its just one of those cases... Hermogenes <admin> where the one gear is not in place Cratylus <admin> I'LL say Hermogenes <admin> that ONE little 8-tooth gear has slipped Cratylus <admin> well id like to state for the record that i dont think this is some subtle semantic difference Cratylus <admin> this is aa fundamental difference in types of energy and radiation Cratylus <admin> but we can come back to it later Hermogenes <admin> your statement has been entered into the almighty records of whosrighteedness Cratylus <admin> ehehehehehe Hermogenes <admin> so, its been snowing up tehre? Cratylus <admin> very briefly Cratylus <admin> none left on the round Try \"help index\" for a list of command types. Hermogenes <admin> we havent gotten ANYthing Cratylus <admin> musta got it Cratylus <admin> the HEAT RADIATION musta got it, that is Hermogenes <admin> its sposed to get up in th 50s morrow Hermogenes <admin> NOOOOOOO!!!!! Cratylus <admin> oooohhhhh wait aa minute Hermogenes <admin> im seriously miffed bout this whole heat thing, btw Hermogenes <admin> wha Cratylus <admin> i get it now Hermogenes <admin> do i wanna know? Cratylus <admin> i think i see how youre looking at it Cratylus <admin> maybe Hermogenes <admin> very well could be Cratylus <admin> ok Hermogenes <admin> ive looked at things \"wrong\" before... Cratylus <admin> tell me if this is what yer thinking: Hermogenes <admin> k Cratylus <admin> when heat causes radiation, thats \"heat radiation\" Hermogenes <admin> mmmm.... Cratylus <admin> ok maybe not Cratylus <admin> worth aa try Hermogenes <admin> when an object is \"energized\" enough, it begins to radiate in the iR portion of the em spectrum Cratylus <admin> yeah Cratylus <admin> and thats what u mean by \"heat radiation\"? Hermogenes <admin> energized usually means addding heat or electricity or SOMEthing to it <admin> Cratylus nods. Hermogenes <admin> well... Hermogenes <admin> the IR radiation brought on is then perceived by our senses as \"heat\" Cratylus <admin> ok Cratylus <admin> do u mind if i drag this on aa bit longer? Hermogenes <admin> if more energy is added, it then begins to transmit in the visible portion of the em spectrum, and we perceive this as ''light' Cratylus <admin> i really am interested in understanding our difference here Hermogenes <admin> as am i Cratylus <admin> see, i dont think that the IR radiation heats up other things all that much Hermogenes <admin> actually, Cratylus <admin> when i put my hand up to aa light bulb, and its hot, Cratylus <admin> i dont think its because of IR, although some IR is present Hermogenes <admin> scientist dude sed that IR ardiation is actually quite effective in heating up stuff Hermogenes <admin> heh, ardiation Cratylus <admin> ok, but just bear with me aa moment <admin> Hermogenes bears Cratylus <admin> lets assume, for the pure sake of argument, that IR radiation does not exist Hermogenes <admin> heh, sake of argument Hermogenes <admin> ok, go on Cratylus <admin> IF there is not IR radiation, could you still warm yourself by the fire? Hermogenes <admin> uhhh.. yes Cratylus <admin> by what process? Hermogenes <admin> ummmm Hermogenes <admin> light? Cratylus <admin> no Cratylus <admin> heat radiation Cratylus <admin> see i think this is where we went in diff directions Cratylus <admin> your brain is bent on seeing the word \"radiation\" in terms of particles or wavelengths Hermogenes <admin> or, the act of transmitting particles or wavelenghths or whatever Cratylus <admin> in the context of convection and conductance, this approach to the word \"radiation\" is not fruitful Cratylus <admin> thats where we are having aa communication breakdown Cratylus <admin> again for the sake of argument, lets assume there is no electromagnetic or particle radiation <admin> Hermogenes likes wavelenghths n particles n stuff... Cratylus <admin> again for the sake of argument, lets assume there is no electromagnetic or particle radiation Hermogenes <admin> whata a dismal world Cratylus <admin> the fireplace is radiating heat Cratylus <admin> heat comes from it, hence, it \"radiates heat\" Cratylus <admin> this is \"heat radiation\" Hermogenes <admin> hmmm Hermogenes <admin> in a loose definition, ok Cratylus <admin> no <admin> Hermogenes gasps in shock! Cratylus <admin> that is not aa loose definition Cratylus <admin> that is the definition of the word radiate Cratylus <admin> \"to radiate\" Hermogenes <admin> wait, is THAT all there is to \"heat transferrence by radiation\"? Cratylus <admin> YESSSSSSS Cratylus <admin> EXACTLY Hermogenes <admin> heat comes from it, hence, it \"radiates heat\" Hermogenes <admin> heat comes from it, hence, it \"radiates heat\" Hermogenes <admin> heat comes from it, hence, it \"radiates heat\" Hermogenes <admin> hmmmmm Hermogenes <admin> ok <admin> Hermogenes can accept that Cratylus <admin> ok back to our dismal theoretical world Hermogenes <admin> wait Cratylus <admin> which contains no particle or em radiation Hermogenes <admin> i thought we were done? Cratylus <admin> oh Cratylus <admin> ok Cratylus <admin> so u see my point? Hermogenes <admin> mmmm, sorta Cratylus <admin> then we are not donme Hermogenes <admin> i was making it way too more complicated than it needed to be? Cratylus <admin> you were on aa different train track altogether Hermogenes <admin> i was on one of those hovertrains Hermogenes <admin> on magnetic rails Cratylus <admin> btw the fireplace does not radiate heat through \"light\" Hermogenes <admin> it dont? Cratylus <admin> it radiates heat by contact with molecules which transmit the heat in the form of kinetic energy Hermogenes <admin> howcome a black shirt gets hotter than a white shirt, then? Cratylus <admin> in front of aa fire? Cratylus <admin> ive never noticed any such thing Cratylus <admin> in the sun, yeah sure Hermogenes <admin> but i thought we already established that molecules dont HAFT bounce off eachother to transfer heat? Hermogenes <admin> hmmm <admin> Cratylus falls to the floor. Hermogenes <admin> so, you think a black tshort and a white tshirt in a non-sun light source would not heat differntly? Cratylus <admin> in front of aa fireplace, i dont think there would be aa noticeable differennce Hermogenes <admin> im not tryin to argue, im tryin to follow a tangential tracxk for a sec Cratylus <admin> i think with delicate instruments u WOULD detect aa diff Hermogenes <admin> NOTCEABLE Cratylus <admin> this is actually right on track dude Cratylus <admin> i think with delicate instruments u WOULD detect aa diff Hermogenes <admin> OH, suddenly im allowed to play on YOUR traintrack? Hermogenes <admin> :) Cratylus <admin> because IR radiation DOES in fact play aa role here Cratylus <admin> but it is not as substantial as the brownian motion Hermogenes <admin> uh uhuhuhu uuhuh Hermogenes <admin> sorry Cratylus <admin> this must be aa way-homer Hermogenes <admin> a 'way-homer'? Cratylus <admin> you'll get it on the way home Hermogenes <admin> heh Hermogenes <admin> is it really that much fun to argue with me? Hermogenes <admin> or is it really a chore Cratylus <admin> im honestly mystified by this Hermogenes <admin> as am i Cratylus <admin> i mean, im like...FASCINATED Hermogenes <admin> and i wasnt asking sarcsatically or rhetorically Cratylus <admin> this is such aa weird miscommunication Hermogenes <admin> if it was fun to argue at me Cratylus <admin> i dint mean it sarcastically <admin> Hermogenes nods solemnly. Cratylus <admin> im totally dead serious Cratylus <admin> dead sexy, too Hermogenes <admin> didnt think you WERE being scarcastic Hermogenes <admin> ugh Cratylus <admin> heh Hermogenes <admin> just watched that last night Cratylus <admin> man he is VILE Hermogenes <admin> 'e leuks leyek a lit'l BEHbee Hermogenes <admin> oye ET a behbee wunce Hermogenes <admin> oye sed, OYEM th TOP a th fewd chayn!\" Hermogenes <admin> GET! EN! MAH! BELLY! Cratylus <admin> ok hang on aa sec dont say anything for aa minute, ok? Cratylus <admin> ok thx <admin> Hermogenes nods solemnly. Hermogenes <admin> you ok there? Cratylus <admin> ya i had to copy and paste this round Hermogenes <admin> or... am i still not spossed to be sayin anything still? Hermogenes <admin> heh Cratylus <admin> this is just too crazy not to save for posterity <admin> Hermogenes hopes he wont regret his conversation, but think he probably will Cratylus <admin> heheh yes you definitely will Cratylus <admin> well i HOPE you will Hermogenes <admin> ill probably wind up being WRONG th whole time and lookin like an IDIOT fer it Cratylus <admin> i hope yer gonna slap yer forehead and go HOLY FUCKING DUH! Hermogenes <admin> see, th thing is... Hermogenes <admin> its kinda hard to be wrong about something you dont know what yer talkin about in th FIRST place Cratylus <admin> i guess Cratylus <admin> ok Cratylus <admin> i touch aa stove Cratylus <admin> coalburning stove. black iron Hermogenes <admin> like, some 5th grade makin assertions about calculus Cratylus <admin> i put my hand right ON it Hermogenes <admin> ya? Cratylus <admin> my fickin hand is sizzlin n stuff, right Cratylus <admin> this is happening not because of IR <admin> Hermogenes nods solemnly. Hermogenes <admin> but because of.... Cratylus <admin> see, if it was infrered radiation doin this, then why isnt the whole room in flames? Cratylus <admin> why is it limited to RIGHT AT the stive? Hermogenes <admin> uh... Hermogenes <admin> dissipation? Cratylus <admin> explain dissipation please Hermogenes <admin> theres so much ari movin roun n stuff, the averagew molecular kinetic energy (motion) can be...uh...averaged out Hermogenes <admin> over a wider area Hermogenes <admin> n stuff Hermogenes <admin> like, the inverse-squared law or something Hermogenes <admin> YEAH, THATS it Cratylus <admin> ok...so u agree its not infrared energy? Hermogenes <admin> burning yer hand? Cratylus <admin> right Hermogenes <admin> its... Hermogenes <admin> the convection of hot air molecules againts yer skin Cratylus <admin> well, hot STOVE molecules, and it isnt \"convection\" Hermogenes <admin> oooOOOOo Hermogenes <admin> why NOT, mister fancee panse? Cratylus <admin> whats happening is the surface of the stove is transferring heat to my hand Hermogenes <admin> right Cratylus <admin> the mechanics of this heat transfer is simple molecular contact Hermogenes <admin> ok, its either the conduction of heat between the solid of the stove into te solid of yer hand... Cratylus <admin> the stove molecules are moving real fast Hermogenes <admin> ok, now wait Cratylus <admin> and they make my hand molecules move real fast Hermogenes <admin> so, theres MORE than JUST 3 ways of transferring heat? Cratylus <admin> no Hermogenes <admin> like in th xflies! Cratylus <admin> do u agree with me so far? Hermogenes <admin> so, tehre are JUST 3 ways? Cratylus <admin> do u agree with me so far? Hermogenes <admin> mostly, yah Cratylus <admin> ok, what part do u disagree with? Hermogenes <admin> hol on a sec... Cratylus <admin> and get aa fucking scientist in here NOW Hermogenes <admin> no, i had to TEND to work stuff Hermogenes <admin> ya big meanie Cratylus <admin> well if u see on, grab him Cratylus <admin> or her Hermogenes <admin> i wasnt goin off to find a scientist dude to be on my sdide or nuttin Cratylus <admin> ok so what part did u not agree with? Hermogenes <admin> grab her? Cratylus <admin> ok so what part did u not agree with? Hermogenes <admin> ok, but only cause you insisted... Hermogenes <admin> i guess i just wanna establish that theres X ways of heat transferrance, and any examples involving heat transferrence would be put into one or more of these X categories Cratylus <admin> ok well fuck the 3 categories Cratylus <admin> do you agree or disagree with my statements? Hermogenes <admin> YEAH Hermogenes <admin> POWER TO THE PEOPLE! Cratylus <admin> dude Hermogenes <admin> fine Hermogenes <admin> stove molecules, movin hand molecules Cratylus <admin> right Hermogenes <admin> i tells you what my FOOT molecules gunan be movin in a SECOND! Cratylus <admin> now, if instead of touching the stove, i had held my had within half aa centimeter, it would scald but not burn. right? Hermogenes <admin> whats the diff? Hermogenes <admin> its gonna get hot Cratylus <admin> it would take longer for my hand to be damaged and it wouldnt be black Hermogenes <admin> scald, burn, sear, fry, etc Hermogenes <admin> ok, agreed Cratylus <admin> ok the first example was conductance Hermogenes <admin> as long as yer not actually TOUCHING it Hermogenes <admin> ok, 1st = conductance Cratylus <admin> the second example was radiation Hermogenes <admin> (with a wee bit of convection) Hermogenes <admin> hmmmm Cratylus <admin> with aa little convection but thats not important i guess Cratylus <admin> heh ya Hermogenes <admin> second isnt convection? Cratylus <admin> no Hermogenes <admin> sounds likeit... Cratylus <admin> its primarily radiation Cratylus <admin> because the stove is heating the air molecules Cratylus <admin> and the air molecules are heating my hand Cratylus <admin> the heat is being radiated from the surface of the stove, through the air, into my hand Hermogenes <admin> but... Cratylus <admin> wait Cratylus <admin> IR is bad for your eyes right? Hermogenes <admin> uh... Hermogenes <admin> is it? Cratylus <admin> hmmm maybe that uv Cratylus <admin> ok never mind Hermogenes <admin> uv, yes, deinately Cratylus <admin> ok now Hermogenes <admin> wait Hermogenes <admin> lemme say why i think its convection Cratylus <admin> in ADDITION to this molecular heat transfer Cratylus <admin> no Cratylus <admin> im sorry Cratylus <admin> thats irrelevant and aa tangent <admin> Hermogenes frowns. Hermogenes <admin> ok, go on Cratylus <admin> in ADDITION to this molecular heat transfer Hermogenes <admin> you n yer up-arrow keys... Cratylus <admin> there is ALSO infrared radiation from the stove Cratylus <admin> but it is NOT the infrared radiation that burns my hand Cratylus <admin> it is the direct molecular contact with rapidly moving molecules Hermogenes <admin> cause the IR stuff aint got enough energy to do it, and its the molecular transferrence stuff thats burning it? Cratylus <admin> exactly Cratylus <admin> do you agree? Hermogenes <admin> im not too sure that IR is all THAT low-level energy-wise, but ok... Cratylus <admin> so now lets put that stove in outer space Hermogenes <admin> outher... SPAAAAAACE Cratylus <admin> (with its own fuel and oxy) Hermogenes <admin> (of course) Cratylus <admin> and im out there with the stove Cratylus <admin> and i put my hand .5 centimeters from it Hermogenes <admin> (with suit and air supply) Cratylus <admin> will my hand be damaged? Hermogenes <admin> um... Cratylus <admin> bare hand Hermogenes <admin> uh... Hermogenes <admin> maybe? Cratylus <admin> no Hermogenes <admin> no Cratylus <admin> i think its possible the stove may shed molecules Hermogenes <admin> cause the molecules cant transfer the heat as efficiently or quickly Cratylus <admin> these molecules might hit some of my hand molecules, but not enough to do damage Cratylus <admin> negatron Hermogenes <admin> cause theres a near-vaccuum enviroment Cratylus <admin> they CAN transfer it efficiently and quickly Hermogenes <admin> oh Cratylus <admin> if i TOUCH them Hermogenes <admin> BAD molecules Cratylus <admin> if i touch the stove, will my hand be damaged? Hermogenes <admin> yes Cratylus <admin> right Hermogenes <admin> BAD stove! Cratylus <admin> ok, so in aa vacuum, i have to touch the stove to get burned, right? Hermogenes <admin> PROBably Cratylus <admin> oK then Cratylus <admin> that is precisely my point Cratylus <admin> the stove does not produce sufficient IR radiation to make any noticeable diff to my hand Hermogenes <admin> k... Cratylus <admin> only when there is molecule to molecule contact, can the stove do real temp change Cratylus <admin> therefore, while the stove radiates infrared waves Cratylus <admin> it does not radiate heat Hermogenes <admin> funkay Cratylus <admin> yer supposed to hear trumpets and flights of angels as the truth rolls in from the sky Hermogenes <admin> just cause i accept it, dont mean i understand it... Hermogenes <admin> not to bee TOO bog of a pain in th ass Hermogenes <admin> big, even Cratylus <admin> you WILL young hermogenes. oh yes. you WILL. Hellmonger@Trilogy <intergossip> anybody ever fuck with doing Sun consoles on an oldsk00l portmaster 2? Hermogenes <admin> my BRAIN hurts Cratylus <admin> sorry ",]),"/domains/town/txt/shame/chapter03":1152072075,"/domains/town/txt/shame/chapter02":1152072075,"/domains/town/txt/shame/chapter01":1152072075,]),"/doc/cheats":(["object":"/domains/town/obj/cheatbook","title":"Untitled","items":([({"chapter 1","chapter one","1",}):"\"Basics\" ",({"chapter 3","chapter three","3",}):"\"Orcmaster quest\" ",({"chapter 5","chapter five","5",}):"\"Princess Daphne\" ",({"chapter 2","chapter two","2",}):"\"Orc Slayer\" ",({"chapter 1","chapter one","1",}):"\"Basics\" ",({"chapter 2","chapter two","2",}):"\"Orc Slayer\" ",({"chapter 2","chapter two","2",}):"\"The Town Well\" ",({"chapter 5","chapter five","5",}):"\"Cave Explorer II & The Postman\" ",({"chapter 2","chapter two","2",}):"\"Orcmaster quest\" ",({"chapter 4","chapter four","4",}):"\"The Town Well\" ",]),"/doc/cheats/chapter06":1585972635,"/doc/cheats/chapter05":1585970645,"/doc/cheats/chapter04":1585969898,"/doc/cheats/chapter03":1585969904,"/doc/cheats/chapter02":1585964075,"/doc/cheats/chapter01":1585957973,"index":" Untitled Chapter 1: \"Basics\" Chapter 2: \"The Town Well\" Chapter 3: \"Orcmaster quest\" Chapter 4: \"The Town Well\" Chapter 5: \"Cave Explorer II & The Postman\" ","reads":([({"chapter 3","chapter three","3",}):"chapter 3 \"Orcmaster quest\" This one is a bit easier. Again, we can get this done without actual combat. So you're now a mage standing in the Mage's Guild. Let's head over to Roshd Burlyneck, the Fighter guildmaster who is looking for his missing helmet. Remember the helmet you got off the dead orc shaman? Exactly. Two birds with one stone. 1n, 1e, 1n, 4w, 26n, enter cave Remember this place? We're goig to teleport to a different location now: cast light look dial tower enter gate 1d, 1s, 1n You're now in the Fighter's Guild. give helmet to roshd Now what on earth just happened? What's all this weird text? That's a language you do not understand, Tangetto. It is the language of the Orcs. Roshd just told you thanks dude, if you want to join the Fighter's guild, now you can. Now you know how yo join the Fighter's guild if you want to. Since you're already a human mage that doesn't help you much now, but if you want to play through again later with a new character that's, say, an orc, you now know how to get hooked up. That's not to say that humans can't be fighters by the way. I'm just saying that *statistically* it may be more rewarding to choose a bulkier race for that. You do you, tho, breh. ",({"chapter 2","chapter two","2",}):"chapter 2 \"The Town Well\" This one is really tricky. There are wheels to turn, levers to pull, grates to open, and as a weak little human you can't do it all yourself... or can you? This isn't called a cheat book for nothing. All righty we're going to call upon some of the stuff you've already done. We need to head back to the town and deposit any cash you picked up and sell any heavy armor you may have that you don't really need (like the leather boots and jacket from the mansion or chainmail from the church) and then deposit that money too. Get in the habit of watching your encumbrance. It's especially important now because you'e about to go fetch a bunch of heavy equipment to get this quest done. ",({"chapter 2","chapter two","2",}):"chapter 2 \"Orcmaster quest\" This one is a bit easier. Again, we can get this done without actual combat. So you're now a mage standing in the Mage's Guild. Let's head over to Roshd Burlyneck, the Fighter guildmaster who is looking for his missing helmet. Remember the helmet you got off the dead orc shaman? Exactly. Two birds with one stone. 1n, 1e, 1n, 4w, 26n, enter cave Remember this place? We're goig to teleport to a different location now: cast light look dial tower enter gate 1d, 1s, 1n You're now in the Fighter's Guild. give helmet to roshd Now what on earth just happened? What's all this weird text? That's a language you do not understand, Tangetto. It is the language of the Orcs. Roshd just told you thanks dude, if you want to join the Fighter's guild, now you can. Now you know how yo join the Fighter's guild if you want to. Since you're already a human mage that doesn't help you much now, but if you want to play through again later with a new character that's, say, an orc, you now know how to get hooked up. That's not to say that humans can't be fighters by the way. I'm just saying that *statistically* it may be more rewarding to choose a bulkier race for that. You do you, tho, breh. ",({"chapter 2","chapter two","2",}):"chapter 2 \"Orc Slayer\" You should now be standing in the secret cave in the woods, having just completed the Cave Explorer I quest. Now things get complicated, because the next quest is Orc Slayer, and as a weak human there is absolutely no way you can fight your way through this quest. You will have to sneak around, so pay attention to all the details here. The first thing you need to do is find a way to become invisible so that you can sneak by some orcs later. There happens to be an invisibility device available to you, but it is far away. You can't walk to it. You have to teleport to it. The good news is that there is a teleportation device in this secret cave you're standing in! It's called a stargate and you can dial different destinations on it to reach other stargates. Type: dial campus lab enter gate See doctor Kleiner? He is wearing a badge you need, but you can't kill him for it, he will escape if you try. So leave him alone for now. We need to get you some other loot. 1s, 1e, 1n, 3e, open door, 1s You are now in the Virtual Campus admissions room, and there is a robot here named Jenny who will give you an introduction to the game, but more importantly, she will give you some valuable loot you can sell at the campus store. You'll see why you need to get this loot, just trust me for now. type: activate bot And when you're done reading what she says, type: next tip Until she's done giving you tips. At the end she will give you a hat and some other goodies. When you have the loot, go: 1n, 2e, 1n To the campus bookstore, and type: sell hat to kim This should get you a bunch of dollars. Now type: buy coat from kim And she will give you a lab coat. You see, Dr. Kleiner is looking for his lab coat, and you will give this to him. Go back to Kleiner: 1s, 5w, 1s, 1w, 1n give coat to kleiner Note that while Kleiner is putting on the coat, he drops the badge! Grab it quick: get badge wear badge Now you can enter the room with the invisibility device. You hadn't forgot about that, had you? 2s get computer from bench get module from bench wear computer activate computer open computer install module in computer close computer Now you're ready to do some serious sneaking around. You're not invisible yet, but we're going to hold off on that for now. Being invisible uses up your stamina points, so we're going to save it for when you really need it. Let's get back to the main village and get some other stuff you really need. 2n dial cave enter gate 26s, 2e, 1s Now, here you may run into a problem. If you went up a few levels already, you won't be able to get past this guard, because he only ignores total newbies. So you'll have to sneak by him: cloak 1s decloak Remember to decloak. If you walk around cloaked (invisible) all the time you will run out of stamina and that's no fun. Now, let's look around: look look at window 1w, 1n get all 1s, 1e drop ladder The mansion door is locked so the only way in is to: climb ladder You're now in the old abandoned mansion. Time to grab some stuff you'll need: 1w search You should now see a complex key. You'll need it for opening a safe later. get key 1e, 2s, 1d, 2n cloak 1e Here you see a thief that has been using the abandoned mansion as his own home. If he sees you he will attack, so you really should sneak by him instead. Notice the rug here? Doesn't it seem strange that it was so obvious? Is anything underneath it? move rug open door 1d turn on flashlight look open chest get all from chest get all from bag 1u, 1w decloak Ok, so let's review what we've done so far. We found an invisibility device, used it to get past a gate guard, used a ladder to climb into a mansion, found a key, snuck past a thief to find another key, and now we have a bunch of loot and money, and you're possibly at level 5 now! score Pretty cool! But we haven't solved the orcslayer quest yet, so let's keep going. 2s, u unlock door with silver key open door 1s Ok, notice some other obvious things here? A bed and a wardrobe? We'll get to the wardrobe later, for now let's see if there's anything behind this big bed: move bed Well well well! Let's explore further: enter passageway unlock safe with complex key open safe get all from safe drop complex key Goodness gracious! That's quite a lot of good loot! A grenade?!? Well don't use it yet, this is exactly what we will need to solve the orc slayer quest. We're almost there. Now, at this point you may be carrying too much loot. You're not very big and strong yet, and you can't arry all your loot and money around all the time. Let's get to the bank and deposit some of this cash. 4n, 1d, 2n, 2e, 3n, 1e This is the bank. Let's start by opening a bank account: request account from zoe deposit all There! Now you have money stashed away in case things get tough, and now you can carry more stuff. Let's go sell some of the loot you picked up from the mansion to make more room in your inventory. 1w, 3s, 1e, 1n sell plastic flashlight to otik You can now sell any of the gear you got that you don't think you need. Be careful.. if you want to buy something back it'll cost you more than you sold it for. Capitalism! All righty, now we're ready to confront those orcs...sort of. Here's where things get tricky. We'll need to sneak by a bunch of orcs, but we don't want to waste stamina doing it, so we want to be efficient. We also want to make sure that we don't make mistakes because we'll need to move quickly. First, let's get where we're going: 1s, 5w, 1sw cloak 1w, 1n, 1w It's a good thing you're cloaked because you would have been attacked by all those orcs you snuck past. You're now in the temple of the orc shaman. If it's too dark to see, turn on the maglite: turn on maglite Now we're going to plan things out to make sure we don't make any mistakes. The game has a way for you to bind keys to specific commands. example type: alias 1 smile Now if you type the number 1 and hit enter, the game will act as if you typed out the command \"smile\". This is important because there are some commands that need to be typed quickly but cannot be misspelled. Using keyboard aliases helps in these time-sensitive situations. We're about to have a time sensitive situation. Make some aliases: alias 1 pull pin on grenade alias 2 drop grenade alias 3 go east Make sure you have those aliases entered correctly. Especially make sure you made number 3 be go east, not the letter e, because e is itself an alias and aliases can't refer to aliases. Now go ahead: 1 2 3 And wait 10 seconds. Don't go back west too soon or you'll be in the room when the grenade goes off! To be sure it's safe, try to look into the next room: peer west Is the shaman blown up? Good, go back and get that sword from him. get sword from corpse get helmet from corpse You don't need the helmet right this minute, but you will later, so get it if you can. Now let's go back to the church: 1e, 1s, 1e decloak 1ne, 3e, 1n All righty, we're almost done! Did you notice that the church has an elevator? Let's find out what's in the basement. push button 1w push b button (then wait until the elevator stops) 1e This is Leo the archwizard. Don't worry, he's not named after anyone you know, he's been around a long long time. See how he's complaining he lost the orcslayer? Take a look at the sword you got from the shaman. exa sword Interesting huh? What if this is what Leo is looking for? give sword to leo Ta-daa! Now you have solved the orc slayer quest, and Herkimer will allow you to join the mages guild: push button 1w push 1 button (then wait until the elevator stops) 1e 1s, 1e, 1s, 1w, 1s ask herkimer to join ask herkimer to teach whip ask herkimer to teach buffer ask herkimer to teach missile ask herkimer to teach meditate ask herkimer to teach light And now try out some of your new spells: cast whip cast buffer Congratulations, mage. You may now be ready for trickier tests of your mettle. ",({"chapter 5","chapter five","5",}):"chapter 5 \"Cave Explorer II & The Postman\" These two are related. The letter you need to give to Roshd is hidden in the treasure chest of the Orc captain you need to slay. Lat's assume we're starting this from Radagast's training room because you didn't listen to me in the last chapter and you went there to do magic training. All righty, let's head to the cave where the Orc invasion force is gathering in preparation to destroy the town above. 1d, 1n, 4w We are now on the humpbacked bridge between the town and the forest. Below this bridge is a nasty troll and the cave where the bad guy orcs live. We will do some more sneaking here. cloak 1d See the troll? Nasty. 2e, 1ne, 1nw, 1n, 1e, 2n open door 1n You're here. The orc commander. Notice how low your stamina is...all that cloaked sneaking really sapped your strength. If you were higher level I would have suggested fighting your way here and then slamming this guy with your magic whip and fireballs while shielding yourself with magic buffer after buffer. This is a no-foolin' boss level guy, and when you start fighting, he closes and locks the door behind you. Unless you've figured out the portal device or the omni or some other way to magically retreat if things get tenuous, you are in it to win it. So, I'm not going to give you cheats on winning that. There are no cheats. You'll have to level up and grind up until you can go toe to toe with the Orc Commander. But, here's how you can complete the Postman quest: get letter from table 2s, 1w, 1s, 1se, 1sw, 2w, 1u decloak There's an excellent chance you ran out of stamina along the way there. Make sure that doesn't happen. Becoming visible in the lair of an orc invasion force is not a good idea if you're not loaded for bear. One way to speed up your recovery is to cast a spell that helps center you: cast meditate All right, let's head to Roshd: 1w, 26n enter cave dial tower enter gate 1d, 1s, 1w, 1n give letter to roshd If you tried to read it, it's Tangetto and you couldn't make heads or tails of it. It's some dumb stuff about how humans are savages and the orc outpost is only barely hanging on and I love you so much blah blah. Anyway hand it over and you get your points. ",({"chapter 1","chapter one","1",}):"chapter 1 \"Basics\" The first thing to do is to pick a decent character. The best all-around choice for a beginner is a human mage, so for the purposes of these cheat sheets, pick human when you create your character. Once your character is created, begin the game by typing: enter town You should now be in the main village of the game, where you can find shops, pubs, a bank, and most everything you'll need. Get familiar here with the basic commands: look look at tower go north go south smile You can also type them in a shortened way: l l tower n s smile Now, learn a little about yourself. Type: score stat (Note that you will have to hit <enter> to get to the second page of the stat command.) These commands tell you some things about yourself, like how much food you've eaten, what skills you have and how good you are at them, and other attributes, like how strong you are how smart you are, etc. In the game you will need to do some fighting against monsters, and these pieces of information will help you decide the best way to fight which enemies. For now, since you've chosen human, you are probably smart but not very strong. Let's try to fix that, because fights usually go better if you are strong. Every new player has 15 customization points when they join (this only happens once), so make yourself stronger by adding customization points to your strength, for example: customize strength 5 If your intelligence is below 50, you definitely need to increase it too, if you're going to be a mage. You usually want a strength of at least 30 and an intelligence above 50, preferably above 60, for casting spells. Ok, next, let's get you equipped for exploring. If you're lucky, someone has left stuff in the church bin. Go to the church: go west, go north (or w for west, and n for north) From this point, directions will be given like this: 1w, 1n Meaning, in this example, go west once, go north once. Now: look in bin Hopefully there is a bunch of stuff in there but if someone else got there first, you will need to get equipped on your own, without the church's charity. For the purpose of this guide, we'll assume you didn't find anything there. Let's get started with your first quest: Cave Explorer I Go from the church to the Adventurers' Guild: 1s, 2e, 1s This is where you go to get info on questing and other stuff. There is a charity bin here too, check it for helpful items. The important thing to do here, though, is: read list This tells you the list of quests available. Did you see Cave Explorer I? We're going to go solve that one right now! 1n, 5w, 26n, enter cave You'll notice that you walked through a big forest just then. Don't try to explore the forest yet, you could get lost. Just go straight north, and go fast, because if you accidentally run into an orc, you do *not* want to hang around and wait for him to start hitting you. If you goof up here and do get killed by an orc, well, we might as well talk about death now. Death takes away a few of your experience points, which isn't good because you need them to go up in levels. Definitely avoid death. You can avoid losing those experience points by being resurrected, but that takes getting the help of another player and we can discuss that another time. For now, just know that if you get killed, you need to: regenerate And you will rematerialize in the start room. Anyway, hopefully you did not die and you are now inside the secret cave in the forest, and you have completed your very first quest. That was easy, right? You might even have automatically advanced a level or two. Congratulations! The next quest will be harder, and it is the Orc Slayer quest. By the way, if that room was too dark to see, come back later with a flashlight or a torch. There is interesting writing on the door, and on the wall. And, of course, a powerful and convenient teleportation device sitting right there on the floor. ",({"chapter 5","chapter five","5",}):"chapter 5 \"Princess Daphne\" This quest is both very easy and very hard. In any case it is very simple. Princess Daphne is the name of a very valuable diamond which is on sale in the Campus Bookstore...the same place you bought a lab coat for Kleiner. The way to solve this quest is to scavenge and scrounge, making and finding coins, and then convering all that money into 50,000 dollars at the bank. Then you go to the campus bookstore, buy the diamond, then go to Dirk at the Adventurer's Hall and give him the diamond. Easy in principle, but it will take some grinding and exploring to get it done. I suggest you go to Radagast and use the training ponts you earned with all this leveling up and get trained up on your mage levels. Radagast is a trainer and is one room up from Dirk in the Adventurer's Hall. Don't bother asking Herkimer to train you, he doesn't know how. Go to Radagast. Protip: You train better if you're smarter. If you've found a magic pipe somewhere, guess what, the magic is that you're slightly smarter if you smoke it. If you have it, find (or buy) some matches, then strike match light pipe with match smoke pipe Pipe or not, to train with Radagast: ask radagast to train magic attack ask radagast to train magic defense ask radagast to train conjuring Don't do that right now, though. There is a drowned cave troll we want to take advantage of, and if you dawdle too long he may respawn. ",({"chapter 2","chapter two","2",}):"chapter 2 \"Orc Slayer\" You should now be standing in the secret cave in the woods, having just completed the Cave Explorer I quest. Now things get complicated, because the next quest is Orc Slayer, and as a weak human there is absolutely no way you can fight your way through this quest. You will have to sneak around, so pay attention to all the details here. The first thing you need to do is find a way to become invisible so that you can sneak by some orcs later. There happens to be an invisibility device available to you, but it is far away. You can't walk to it. You have to teleport to it. The good news is that there is a teleportation device in this secret cave you're standing in! It's called a stargate and you can dial different destinations on it to reach other stargates. Type: dial campus lab enter gate See doctor Kleiner? He is wearing a badge you need, but you can't kill him for it, he will escape if you try. So leave him alone for now. We need to get you some other loot. 1s, 1e, 1n, 3e, open door, 1s You are now in the Virtual Campus admissions room, and there is a robot here named Jenny who will give you an introduction to the game, but more importantly, she will give you some valuable loot you can sell at the campus store. You'll see why you need to get this loot, just trust me for now. type: activate bot And when you're done reading what she says, type: next tip Until she's done giving you tips. At the end she will give you a hat and some other goodies. When you have the loot, go: 1n, 2e, 1n To the campus bookstore, and type: sell hat to kim This should get you a bunch of dollars. Now type: buy coat from kim And she will give you a lab coat. You see, Dr. Kleiner is looking for his lab coat, and you will give this to him. Go back to Kleiner: 1s, 5w, 1s, 1w, 1n give coat to kleiner Note that while Kleiner is putting on the coat, he drops the badge! Grab it quick: get badge wear badge Now you can enter the room with the invisibility device. You hadn't forgot about that, had you? 2s get computer from bench get module from bench wear computer activate computer open computer install module in computer close computer Now you're ready to do some serious sneaking around. You're not invisible yet, but we're going to hold off on that for now. Being invisible uses up your stamina points, so we're going to save it for when you really need it. Let's get back to the main village and get some other stuff you really need. 2n dial cave enter gate 26s, 2e, 1s Now, here you may run into a problem. If you went up a few levels already, you won't be able to get past this guard, because he only ignores total newbies. So you'll have to sneak by him: cloak 1s decloak Remember to decloak. If you walk around cloaked (invisible) all the time you will run out of stamina and that's no fun. Now, let's look around: look look at window 1w, 1n get all 1s, 1e drop ladder The mansion door is locked so the only way in is to: climb ladder You're now in the old abandoned mansion. Time to grab some stuff you'll need: 1w search You should now see a complex key. You'll need it for opening a safe later. get key 1e, 2s, 1d, 2n cloak 1e Here you see a thief that has been using the abandoned mansion as his own home. If he sees you he will attack, so you really should sneak by him instead. Notice the rug here? Doesn't it seem strange that it was so obvious? Is anything underneath it? move rug open door 1d turn on flashlight look open chest get all from chest get all from bag 1u, 1w decloak Ok, so let's review what we've done so far. We found an invisibility device, used it to get past a gate guard, used a ladder to climb into a mansion, found a key, snuck past a thief to find another key, and now we have a bunch of loot and money, and you're possibly at level 5 now! score Pretty cool! But we haven't solved the orcslayer quest yet, so let's keep going. 2s, u unlock door with silver key open door 1s Ok, notice some other obvious things here? A bed and a wardrobe? We'll get to the wardrobe later, for now let's see if there's anything behind this big bed: move bed Well well well! Let's explore further: enter passageway unlock safe with complex key open safe get all from safe drop complex key Goodness gracious! That's quite a lot of good loot! A grenade?!? Well don't use it yet, this is exactly what we will need to solve the orc slayer quest. We're almost there. Now, you don't need the plastic flashlight since you got a big maglite flashlight from the secret chamber downstairs. drop plastic flashlight 4n, 1d, 2n, 2w, 1sw Ok here's where things get tricky. We'll need to sneak by a bunch of orcs, but we don't want to waste stamina doing it, so we want to be efficient. We also want to make sure that we don't make mistakes because we'll need to move quickly. First, let's get where we're going: cloak 1w, 1n, 1w It's a good thing you're cloaked because you would have been attacked by all those orcs you snuck past. You're now in the temple of the orc shaman. If it's too dark to see, turn on the maglite: turn on maglite Now we're going to plan things out to make sure we don't make any mistakes. The game has a way for you to bind keys to specific commands. For example type: alias 1 smile Now if you type the number 1 and hit enter, the game will act as if you typed out the command \"smile\". This is important because there are some commands that need to be typed quickly but cannot be misspelled. Using keyboard aliases helps in these time-sensitive situations. We're about to have a time sensitive situation. Make some aliases: alias 1 pull pin on grenade alias 2 drop grenade alias 3 go east Make sure you have those aliases entered correctly. Especially make sure you made number 3 be go east, not the letter e, because e is itself an alias and aliases can't refer to aliases. Now go ahead: 1 2 3 And wait 10 seconds. Don't go back west too soon or you'll be in the room when the grenade goes off! To be sure it's safe, try to look into the next room: peer west Is the shaman blown up? Good, go back and get that sword from him. get sword from corpse get helmet from corpse You don't need the helmet right this minute, but you will later, so get it if you can. Now let's go back to the church: 1e, 1s, 1e decloak 1ne, 3e, 1n All righty, we're almost done! Did you notice that the church has an elevator? Let's find out what's in the basement. push button 1w push b button 1e This is Leo the archwizard. Don't worry, he's not named after anyone you know, he's been around a long long time. See how he's complaining he lost the orcslayer? Take a look at the sword you got from the shaman. exa sword Interesting huh? What if this is what Leo is looking for? give sword to leo Ta-daa! Now you have solved the orc slayer quest, and Herkimer will allow you to join the mages guild: push button 1w push 1 button 1e 1s, 1e, 1s, 1w, 1s ask herkimer to join ask herkimer to teach whip ask herkimer to teach buffer ask herkimer to teach missile ask herkimer to teach meditate ask herkimer to teach light And now try out some of your new spells: cast whip cast buffer ",({"chapter 1","chapter one","1",}):"chapter 1 \"Basics\" The first thing to do is to pick a decent character. The best all-around choice for a beginner is a human mage, so for the purposes of these cheat sheets, pick human when you create your character. Once your character is created, begin the game by typing: enter town You should now be in the main village of the game, where you can find shops, pubs, a bank, and most everything you'll need. Get familiar here with the basic commands: look look at tower go north go south smile You can also type them in a shortened way: l l tower n s smile Now, learn a little about yourself. Type: score stat (Note that you will have to hit <enter> to get to the second page of the stat command.) These commands tell you some things about yourself, like how much food you've eaten, what skills you have and how good you are at them, and other attributes, like how strong you are how smart you are, etc. In the game you will need to do some fighting against monsters, and these pieces of information will help you decide the best way to fight which enemies. For now, since you've chosen human, you are probably smart but not very strong. Let's try to fix that, because fights usually go better if you are strong. Every new player has 15 customization points when they join (this only happens once), so make yourself stronger by adding customization points to your strength, for example: customize strength 5 If your intelligence is below 50, you definitely need to increase it too, if you're going to be a mage. You usually want a strength of at least 30 and an intelligence above 50, preferably above 60, for casting spells. Ok, next, let's get you equipped for exploring. If you're lucky, someone has left stuff in the church bin. Go to the church: go west, go north From this point, directions will be given like this: 1w, 1n Meaning, in this example, go west once, go north once. Now: look in bin Hopefully there is a bunch of stuff in there but if someone else got there first, you will need to get equipped on your own, without the church's charity. For the purpose of this guide, we'll assume you didn't find anything there. Let's get started with your first quest: Cave Explorer I Go from the church to the Adventurers' Guild: 1s, 2e, 1s This is where you go to get info on questing and other stuff. There is a charity bin here too, check it for helpful items. The important thing to do here, though, is: read list This tells you the list of quests available. Did you see Cave Explorer I? We're going to go solve that one right now! 1n, 5w, 26n, enter cave You'll notice that you walked through a big forest just then. Don't try to explore the forest yet, you could get lost. Just go straight north, and go fast, because if you accidentally run into an orc, you do *not* want to hang around and wait for him to start hitting you. If you goof up here and do get killed by an orc, well, we might as well talk about death now. Death takes away a few of your experience points, which isn't good because you need them to go up in levels. Definitely avoid death. You can avoid losing those experience points by being resurrected, but that takes getting the help of another player and we can discuss that another time. For now, just know that if you get killed, you need to: regenerate And you will rematerialize in the start room. Anyway, hopefully you did not die and you are now inside the secret cave in the forest, and you have completed your very first quest. That was easy, right? You might even have automatically advanced a level or two. Congratulations! The next quest will be harder, and it is the Orc Slayer quest. ",({"chapter 4","chapter four","4",}):"chapter 4 \"The Town Well\" This one is really tricky. There are wheels to turn, levers to pull, grates to open, and as a weak little human you can't do it all yourself... or can you? This isn't called a cheat book for nothing. All righty we're going to call upon some of the stuff you've already done. We need to head back to the town and deposit any cash you picked up and sell any heavy armor you may have that you don't really need (like the leather boots and jacket from the mansion or chainmail from the church) and then deposit that money too. Get in the habit of watching your encumbrance. Keep that weird gray amulet if you found it in the church, though. And that access badge from Kleiner! It's especially important now because you'e about to go fetch a bunch of heavy equipment to get this quest done. So if you're still at Roshd, head back to town: 1s, 1e, 1n, 1u dial cave enter gate out 26s, 5e, 1n sell blue jeans sell white shirt (etc) 1s, 1w, 3n, 1e deposit all Ok now back to the Campus lab 1w, 3s, 4w, 26n enter cave dial campus lab enter gate 2s get all from bench Yeah dude. A rocket pack and a portal generator. Sweet. Save those for a little later. 2n dial stargate lab enter gate 1n, 1e What? What is this? A mech? What? Yes indeed. There should be a landstrider mech here...looking kind of like ED-209 from Robocop but with a seat you can get into. give badge to mech enter mech drive west drive south direct mech to dial campus lab direct mech to enter gate drive south drive south get badge direct mech to enter portal cast light You're in an underground tunnel that has a very heavy door that you can't open yourself if you're a puny human, so you're goig to have to get the mech to open it for you, once you get the key. Let's leave the mech here for now. Make sure you get that badge back or you won't be able to get back here. 1n, 1e, 1n, 2e open door cast light 1s, 1d, 1w push wall 2w, 1s open hatch 1d get key from table 1u, 1n, 4e, 1u, 1n, 2w, 1s, 1w, 1s enter portal cast light unlock door with key enter mech direct mech to open door drive west drive west direct mech to open grate drive east drive east direct mech to enter portal exit All right so we've unlocked that super heavy door and had the mech open it, then we had the mech open the super heavy grate. There are other ways to solve this problem, and they involve killing a human and then making it into a zombie. If you want to try that solution (or the mech or portal are not available), read the player hints book and that will guide you through. Otherwise, this method is the quick and dirty. Now we need to open up the water wheel so that water can start flooding the overhead chamber...but we also want to wear some gear that will let us breathe underwater in case we don't type fast enough. Remember all that crud you grabbed from the lab table earlier? One of those things was an A98 breathing device. This will help. If you don't have it handy, just be sure you can type fast. The next steps will flood the rooms you are in, and as a human you are not super great at breathing water. enter portal 2w wear a98 2e enter portal remove a98 Ok! What's happening now is that a bunch of water is flooding the rooms you were in. It's flooding upwards into a chamber near the town well. This will take a few minutes. Once that's done, we'll head over to the well and open a door that lets the water into the well, solving the quest. Another thing the water is doing is flooding along the corridor you were in, and filling up a locked-up room with water. This is a really really good thing, because that room has a cave troll that you need to be dead for a different quest, and it is much easier to have it die from drowning than to have to kill it with combat. All right, let's head up to the well. 2n dial cave enter gate out 26s, 4e, 1s enter well Ok here we are. Has it been a few minutes? Maybe 5 or so? Let's go ahead and open that flood door: pull lever If that doesn't work, push the lever and wait some more and try again. If that still doesn't work, you may need to try the zombie solution. ",]),"/doc/cheats/.chapter04.swp":1585967320,]),]) diff --git a/lib/save/bugs.o b/lib/save/bugs.o new file mode 100644 index 0000000..e390660 --- /dev/null +++ b/lib/save/bugs.o @@ -0,0 +1,3 @@ +#/daemon/bugs.c +NextID 1 +Bugs ([]) diff --git a/lib/save/classes.o b/lib/save/classes.o new file mode 100644 index 0000000..58602b8 --- /dev/null +++ b/lib/save/classes.o @@ -0,0 +1,3 @@ +#/daemon/classes.c +Classes (["cleric":(["Multis":([]),"Player":0,"Skills":(["magic defense":(["Average":2,"SkillClass":1,]),"melee defense":(["Average":4,"SkillClass":1,]),"knife defense":(["Average":3,"SkillClass":1,]),"stealth":(["Average":4,"SkillClass":1,]),"melee attack":(["Average":4,"SkillClass":1,]),"blade defense":(["Average":3,"SkillClass":1,]),"conjuring":(["Average":1,"SkillClass":1,]),"faith":(["Average":1,"SkillClass":1,]),"projectile attack":(["Average":2,"SkillClass":1,]),"fishing":(["Average":1,"SkillClass":1,]),"healing":(["Average":1,"SkillClass":1,]),"blunt defense":(["Average":4,"SkillClass":1,]),"projectile defense":(["Average":3,"SkillClass":1,]),"bargaining":(["Average":1,"SkillClass":1,]),"magic attack":(["Average":1,"SkillClass":1,]),"blunt attack":(["Average":2,"SkillClass":1,]),]),"Complete":1,]),"explorer":(["Multis":([]),"Player":1,"Skills":(["magic defense":(["Average":3,"SkillClass":2,]),"melee defense":(["Average":2,"SkillClass":2,]),"projectile attack":(["Average":1,"SkillClass":1,]),"knife defense":(["Average":2,"SkillClass":1,]),"blunt defense":(["Average":2,"SkillClass":1,]),"melee attack":(["Average":1,"SkillClass":2,]),"projectile defense":(["Average":1,"SkillClass":2,]),"blade defense":(["Average":1,"SkillClass":2,]),"bargaining":(["Average":4,"SkillClass":2,]),"magic attack":(["Average":3,"SkillClass":2,]),"blunt attack":(["Average":2,"SkillClass":1,]),"knife attack":(["Average":3,"SkillClass":1,]),"blade attack":(["Average":1,"SkillClass":2,]),]),"Complete":1,]),"thief":(["Multis":([]),"Player":0,"Skills":(["stealing":(["Average":1,"SkillClass":1,]),"murder":(["Average":2,"SkillClass":1,]),"melee defense":(["Average":2,"SkillClass":1,]),"projectile attack":(["Average":4,"SkillClass":1,]),"fishing":(["Average":1,"SkillClass":1,]),"knife defense":(["Average":3,"SkillClass":1,]),"stealth":(["Average":1,"SkillClass":1,]),"concealment":(["Average":1,"SkillClass":1,]),"melee attack":(["Average":2,"SkillClass":2,]),"projectile defense":(["Average":4,"SkillClass":1,]),"blade defense":(["Average":2,"SkillClass":1,]),"bargaining":(["Average":4,"SkillClass":1,]),"detection":(["Average":1,"SkillClass":1,]),"blunt attack":(["Average":2,"SkillClass":2,]),"knife attack":(["Average":2,"SkillClass":1,]),]),"Complete":1,]),"mage":(["Multis":([]),"Player":1,"Skills":(["magic defense":(["Average":4,"SkillClass":1,]),"melee defense":(["Average":1,"SkillClass":3,]),"knife defense":(["Average":1,"SkillClass":2,]),"blunt defense":(["Average":1,"SkillClass":3,]),"melee attack":(["Average":2,"SkillClass":4,]),"bargaining":(["Average":2,"SkillClass":1,]),"magic attack":(["Average":4,"SkillClass":1,]),"conjuring":(["Average":4,"SkillClass":1,]),"blunt attack":(["Average":1,"SkillClass":3,]),"knife attack":(["Average":1,"SkillClass":2,]),]),"Complete":1,]),"fighter":(["Multis":([]),"Player":1,"Skills":(["melee defense":(["Average":4,"SkillClass":1,]),"multi-weapon":(["Average":4,"SkillClass":1,]),"projectile attack":(["Average":1,"SkillClass":1,]),"knife defense":(["Average":4,"SkillClass":1,]),"blunt defense":(["Average":4,"SkillClass":1,]),"multi-hand":(["Average":4,"SkillClass":1,]),"melee attack":(["Average":4,"SkillClass":1,]),"projectile defense":(["Average":1,"SkillClass":1,]),"blade defense":(["Average":4,"SkillClass":1,]),"bargaining":(["Average":4,"SkillClass":4,]),"blunt attack":(["Average":4,"SkillClass":1,]),"knife attack":(["Average":4,"SkillClass":1,]),"blade attack":(["Average":4,"SkillClass":1,]),]),"Complete":1,]),]) +converted 1 diff --git a/lib/save/deviation.o b/lib/save/deviation.o new file mode 100644 index 0000000..bcf66b5 --- /dev/null +++ b/lib/save/deviation.o @@ -0,0 +1,2 @@ +#/daemon/deviation.c +StatDeviation (["agility":(["deer":3,"bird":1,"dwarf":2,"klingon":2,"poleepkwa":4,"orc":2,"goblin":1,"tortoise":4,"bugbear":5,"arachnid":1,"vulcan":2,"mech":3,"cow":5,"android":3,"cat":1,"kender":3,"horse":2,"halfling":2,"golem":3,"hobbit":1,"isopod":2,"snake":4,"ape":5,"half-elf":2,"artrell":1,"tree":5,"dummy":1,"satyr":2,"human":3,"elephant":5,"wraith":2,"plant":5,"god":1,"troll":2,"kobold":3,"viper":4,"dog":3,"demon":2,"unicorn":2,"sheep":3,"griffin":2,"giant":5,"bear":5,"ooga":2,"chimera":2,"balrog":1,"gnome":3,"amphibian":4,"vehicle":3,"ancap":3,"rodent":3,"slug":5,"half-orc":1,"elf":3,"primate":3,"lizard":3,"gargoyle":5,"fish":2,"strider":1,"faerie":1,"blob":5,"insect":2,"bot":3,"elemental":3,"avidryl":1,"gnoll":2,"dragon":1,"bat":2,"centaur":3,"dryad":2,"pig":5,"pegasus":1,"replicant":3,"demi-god":2,"ogre":5,"nymph":1,]),"wisdom":(["deer":5,"bird":4,"dwarf":3,"klingon":5,"poleepkwa":4,"orc":5,"goblin":3,"tortoise":1,"bugbear":2,"arachnid":5,"vulcan":1,"mech":3,"cow":5,"android":3,"cat":4,"kender":4,"horse":5,"halfling":4,"golem":2,"hobbit":3,"isopod":5,"snake":2,"ape":2,"half-elf":2,"artrell":5,"tree":4,"dummy":1,"satyr":1,"human":3,"elephant":1,"wraith":2,"plant":5,"god":1,"troll":5,"kobold":4,"viper":2,"dog":5,"demon":4,"unicorn":2,"sheep":5,"griffin":4,"giant":5,"bear":2,"ooga":5,"chimera":3,"balrog":3,"gnome":1,"amphibian":1,"vehicle":3,"ancap":3,"rodent":4,"slug":4,"half-orc":5,"elf":1,"primate":4,"lizard":5,"gargoyle":2,"fish":3,"strider":3,"faerie":2,"blob":5,"insect":5,"bot":3,"elemental":3,"avidryl":5,"gnoll":4,"dragon":1,"bat":5,"centaur":2,"dryad":2,"pig":2,"pegasus":2,"replicant":3,"demi-god":2,"ogre":5,"nymph":4,]),"speed":(["deer":2,"bird":1,"dwarf":3,"klingon":3,"poleepkwa":4,"orc":2,"goblin":2,"tortoise":5,"bugbear":5,"arachnid":2,"vulcan":3,"mech":3,"cow":5,"android":3,"cat":2,"kender":1,"horse":2,"halfling":1,"golem":3,"hobbit":2,"isopod":1,"snake":4,"ape":5,"half-elf":1,"artrell":2,"tree":5,"dummy":1,"satyr":2,"human":3,"elephant":4,"wraith":3,"plant":5,"god":1,"troll":3,"kobold":3,"viper":4,"dog":3,"demon":2,"unicorn":3,"sheep":4,"griffin":2,"giant":5,"bear":5,"ooga":2,"chimera":1,"balrog":2,"gnome":2,"amphibian":5,"vehicle":3,"ancap":3,"rodent":2,"slug":5,"half-orc":1,"elf":3,"primate":3,"lizard":3,"gargoyle":4,"fish":3,"strider":1,"faerie":2,"blob":5,"insect":1,"bot":3,"elemental":3,"avidryl":3,"gnoll":3,"dragon":3,"bat":3,"centaur":2,"dryad":2,"pig":4,"pegasus":2,"replicant":3,"demi-god":1,"ogre":4,"nymph":2,]),"intelligence":(["deer":5,"bird":5,"dwarf":3,"klingon":2,"poleepkwa":4,"orc":3,"goblin":4,"tortoise":3,"bugbear":3,"arachnid":3,"vulcan":1,"mech":1,"cow":5,"android":1,"cat":5,"kender":2,"horse":5,"halfling":2,"golem":4,"hobbit":2,"isopod":5,"snake":4,"ape":3,"half-elf":1,"artrell":4,"tree":5,"dummy":1,"satyr":3,"human":1,"elephant":4,"wraith":4,"plant":5,"god":1,"troll":3,"kobold":4,"viper":4,"dog":4,"demon":2,"unicorn":4,"sheep":5,"griffin":5,"giant":3,"bear":3,"ooga":3,"chimera":3,"balrog":2,"gnome":1,"amphibian":3,"vehicle":1,"ancap":1,"rodent":5,"slug":5,"half-orc":2,"elf":1,"primate":3,"lizard":5,"gargoyle":4,"fish":5,"strider":3,"faerie":2,"blob":5,"insect":5,"bot":1,"elemental":3,"avidryl":4,"gnoll":4,"dragon":2,"bat":3,"centaur":3,"dryad":4,"pig":2,"pegasus":3,"replicant":1,"demi-god":2,"ogre":4,"nymph":4,]),"strength":(["deer":1,"bird":4,"dwarf":1,"klingon":1,"poleepkwa":4,"orc":1,"goblin":3,"tortoise":5,"bugbear":1,"arachnid":4,"vulcan":5,"mech":4,"cow":2,"android":4,"cat":4,"kender":5,"horse":1,"halfling":3,"golem":1,"hobbit":4,"isopod":5,"snake":5,"ape":1,"half-elf":3,"artrell":3,"tree":3,"dummy":1,"satyr":4,"human":3,"elephant":1,"wraith":3,"plant":3,"god":1,"troll":1,"kobold":1,"viper":5,"dog":3,"demon":2,"unicorn":3,"sheep":3,"griffin":1,"giant":1,"bear":1,"ooga":1,"chimera":3,"balrog":3,"gnome":3,"amphibian":5,"vehicle":4,"ancap":3,"rodent":5,"slug":4,"half-orc":2,"elf":5,"primate":4,"lizard":3,"gargoyle":1,"fish":4,"strider":1,"faerie":5,"blob":5,"insect":5,"bot":4,"elemental":3,"avidryl":2,"gnoll":3,"dragon":1,"bat":4,"centaur":2,"dryad":4,"pig":3,"pegasus":2,"replicant":4,"demi-god":2,"ogre":1,"nymph":5,]),"ugliness":(["bugbear":3,]),"durability":(["deer":2,"bird":5,"dwarf":1,"klingon":1,"poleepkwa":4,"orc":2,"goblin":1,"tortoise":1,"bugbear":1,"arachnid":5,"vulcan":1,"mech":4,"cow":1,"android":4,"cat":4,"kender":1,"horse":2,"halfling":3,"golem":2,"hobbit":2,"isopod":5,"snake":4,"ape":1,"half-elf":5,"artrell":3,"tree":1,"dummy":1,"satyr":2,"human":4,"elephant":1,"wraith":3,"plant":3,"god":1,"troll":1,"kobold":1,"viper":4,"dog":3,"demon":2,"unicorn":3,"sheep":3,"griffin":1,"giant":1,"bear":1,"ooga":2,"chimera":2,"balrog":1,"gnome":4,"amphibian":3,"vehicle":4,"ancap":4,"rodent":4,"slug":5,"half-orc":2,"elf":4,"primate":4,"lizard":3,"gargoyle":1,"fish":4,"strider":4,"faerie":5,"blob":5,"insect":5,"bot":4,"elemental":3,"avidryl":2,"gnoll":3,"dragon":1,"bat":1,"centaur":1,"dryad":5,"pig":1,"pegasus":2,"replicant":4,"demi-god":2,"ogre":1,"nymph":5,]),"charisma":(["deer":3,"bird":2,"dwarf":3,"klingon":5,"poleepkwa":4,"orc":5,"goblin":5,"tortoise":4,"bugbear":3,"arachnid":5,"vulcan":5,"mech":2,"cow":4,"android":2,"cat":1,"kender":2,"horse":3,"halfling":2,"golem":5,"hobbit":3,"isopod":5,"snake":5,"ape":3,"half-elf":3,"artrell":4,"tree":3,"dummy":1,"satyr":5,"human":2,"elephant":4,"wraith":5,"plant":3,"god":1,"troll":3,"kobold":4,"viper":5,"dog":2,"demon":2,"unicorn":5,"sheep":3,"griffin":5,"giant":4,"bear":3,"ooga":5,"chimera":5,"balrog":5,"gnome":5,"amphibian":4,"vehicle":2,"ancap":2,"rodent":5,"slug":5,"half-orc":5,"elf":1,"primate":3,"lizard":4,"gargoyle":5,"fish":5,"strider":3,"faerie":3,"blob":5,"insect":5,"bot":2,"elemental":3,"avidryl":3,"gnoll":5,"dragon":2,"bat":3,"centaur":3,"dryad":1,"pig":5,"pegasus":1,"replicant":2,"demi-god":2,"ogre":5,"nymph":1,]),"psi":(["vulcan":1,"demon":2,]),"coordination":(["deer":4,"bird":4,"dwarf":2,"klingon":2,"poleepkwa":4,"orc":3,"goblin":3,"tortoise":2,"bugbear":5,"arachnid":1,"vulcan":2,"mech":2,"cow":3,"android":2,"cat":3,"kender":2,"horse":4,"halfling":1,"golem":3,"hobbit":3,"isopod":3,"snake":5,"ape":5,"half-elf":1,"artrell":3,"tree":5,"dummy":1,"satyr":1,"human":2,"elephant":3,"wraith":2,"plant":5,"god":1,"troll":2,"kobold":2,"viper":5,"dog":4,"demon":2,"unicorn":2,"sheep":4,"griffin":2,"giant":3,"bear":5,"ooga":3,"chimera":4,"balrog":3,"gnome":3,"amphibian":2,"vehicle":2,"ancap":2,"rodent":4,"slug":5,"half-orc":3,"elf":2,"primate":3,"lizard":3,"gargoyle":2,"fish":2,"strider":1,"faerie":1,"blob":5,"insect":3,"bot":2,"elemental":3,"avidryl":1,"gnoll":2,"dragon":3,"bat":2,"centaur":4,"dryad":3,"pig":3,"pegasus":2,"replicant":2,"demi-god":2,"ogre":5,"nymph":2,]),"luck":(["deer":4,"bird":3,"dwarf":1,"klingon":4,"poleepkwa":4,"orc":4,"goblin":4,"tortoise":3,"bugbear":4,"arachnid":3,"vulcan":1,"mech":3,"cow":5,"android":3,"cat":1,"kender":3,"horse":5,"halfling":2,"golem":5,"hobbit":1,"isopod":1,"snake":1,"ape":4,"half-elf":4,"artrell":3,"tree":1,"dummy":1,"satyr":1,"human":3,"elephant":3,"wraith":1,"plant":3,"god":1,"troll":4,"kobold":3,"viper":1,"dog":4,"demon":1,"unicorn":1,"sheep":5,"griffin":1,"giant":4,"bear":4,"ooga":4,"chimera":4,"balrog":3,"gnome":2,"amphibian":3,"vehicle":3,"ancap":3,"rodent":5,"slug":5,"half-orc":5,"elf":1,"primate":3,"lizard":4,"gargoyle":4,"fish":5,"strider":3,"faerie":2,"blob":5,"insect":1,"bot":3,"elemental":3,"avidryl":5,"gnoll":2,"dragon":1,"bat":3,"centaur":1,"dryad":2,"pig":5,"pegasus":1,"replicant":3,"demi-god":1,"ogre":5,"nymph":2,]),]) diff --git a/lib/save/economy.o b/lib/save/economy.o new file mode 100644 index 0000000..9edd63c --- /dev/null +++ b/lib/save/economy.o @@ -0,0 +1,3 @@ +#/secure/daemon/economy.c +Currencies (["platinum":(["rate":10000,"inflation":0.000000,"weight":0.200000,]),"electrum":(["rate":500,"inflation":0.000000,"weight":0.004000,]),"silver":(["rate":100,"inflation":0.000000,"weight":0.200000,]),"dollars":(["rate":100,"inflation":0.000000,"weight":0.001000,]),"gold":(["rate":1000,"inflation":0.000000,"weight":1.000000,]),"copper":(["rate":1,"inflation":0.000000,"weight":0.010000,]),]) +LastInflation 1599391574 diff --git a/lib/save/events.o b/lib/save/events.o new file mode 100644 index 0000000..4d96ea5 --- /dev/null +++ b/lib/save/events.o @@ -0,0 +1,3 @@ +#/secure/daemon/events.c +RebootInterval 99999 +Events ([1599472117:(["object":"/secure/daemon/function","regular":100000,"args":({}),"interval":100000,"function":"ReadFuns","creator":"/secure/daemon/function",]),1599398714:(["object":"/secure/daemon/log","regular":3600,"args":({}),"interval":3600,"function":"RotateLogs","creator":"/secure/daemon/log",]),1599456777:(["object":"/secure/daemon/file","regular":90000,"args":({}),"interval":90000,"function":"ReadDir","creator":"/secure/daemon/file",]),]) diff --git a/lib/save/intermud.o b/lib/save/intermud.o new file mode 100644 index 0000000..caf7839 --- /dev/null +++ b/lib/save/intermud.o @@ -0,0 +1,5 @@ +#/daemon/intermud.c +MudList (["ID":21614015,"List":(["DW_Clone":({-1,"82.68.167.68",4242,8765,0,"Discworld 18.0a","DW_Clone","FluffOS v2.28","LPMud","Development","none",(["channel":1,"ftp":4444,"tell":1,"finger":1,"who":1,"auth":1,"locate":1,"emoteto":1,"http":80,]),0,}),"Darkscapes":({-1,"84.245.8.150",6717,6723,6725,"Dead Souls 3.6","Dead Souls 3.6","FluffOS v2.23-ds01","LPMud","mudlib development","mark@oliekoets.nl",(["channel":1,"mail":1,"ftp":6716,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6723,"emoteto":1,"http":6718,]),(["upsince":"Thu Sep 3 12:55:08 2020","ip":"127.0.0.1","architecture":"Linux","next boot":"CET Thu Sep 10 15:55:08 2020","os build":"unix","native version":"3.6","oob port":6723,]),}),"Dead_Souls_ptar":({0,"184.152.167.105",6666,6672,6674,"Dead Souls 3.8.6","Dead Souls 3.8.6","FluffOS v2.23-ds03w","LPMud","mudlib development","admin@here",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"who":1,"auth":1,"oob":6672,"locate":1,"emoteto":1,"http":6667,]),(["upsince":"Sat Sep 05 14:30:32 2020","ip":"127.0.0.1","next boot":"EST Sun Feb 01 23:30:32 2032","architecture":"Microsoft Windows NT","os build":"windows","oob port":6672,"native version":"3.8.6",]),}),"Muda":({-1,"86.110.43.195",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","root.juur@gmail.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Archipelago":({0,"88.97.75.68",8000,8006,0,"Discworld 15.0a","Discworld","FluffOS v2.28.3-ARCH","LPMud","open for players","archipelago@the-firebird.net",(["channel":1,"ftp":8002,"tell":1,"finger":1,"who":1,"auth":1,"locate":1,"emoteto":1,"http":8004,]),0,}),"LostCraft Reborn":({0,"185.150.190.20",6666,6672,6674,"Dead Souls 3.8.6","Dead Souls 3.8.6","FluffOS v2.23-ds03","LPMud","mudlib development","lostcraftreborn@gmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"who":1,"auth":1,"oob":6672,"locate":1,"emoteto":1,"http":6667,]),(["upsince":"Thu Apr 2 11:05:18 2020","ip":"127.0.0.1","next boot":"EST Fri Aug 29 21:05:18 2031","architecture":"Linux","os build":"unix","oob port":6672,"native version":"3.8.6",]),}),"Morkin23":({0,"86.61.249.216",6666,6672,6674,"Dead Souls 3.8.6","Dead Souls 3.8.6","FluffOS v2.23-ds03","LPMud","mudlib development","marek.jan.cz@gmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"who":1,"auth":1,"oob":6672,"locate":1,"emoteto":1,"http":6667,]),(["upsince":"Thu Sep 3 05:45:37 2020","ip":"127.0.0.1","next boot":"EST Fri Jan 30 14:45:37 2032","architecture":"Linux","os build":"unix","oob port":6672,"native version":"3.8.6",]),}),"Navigate":({-1,"216.136.9.5",2123,2129,2131,"Dead Souls 3.8.6","Dead Souls 3.8.6","FluffOS v2.23-ds03","LPMud","mudlib development","karp1248@gmail.com",(["channel":1,"mail":1,"ftp":2122,"tell":1,"finger":1,"who":1,"auth":1,"oob":2129,"locate":1,"emoteto":1,"http":2124,]),(["upsince":"Sat Feb 15 21:57:05 2020","ip":"127.0.0.1","next boot":"EST Mon Jul 14 08:57:05 2031","architecture":"Linux","os build":"unix","oob port":2129,"native version":"3.8.6",]),}),"The Zone-wpr":({-1,"136.144.155.250",8888,8891,8890,"WOTFlib 0.90","LPMud","DGD 1.4.1","LPMud","beta testing","aidil@wotf.org",(["channel":1,"ftp":21,"tell":1,"who":1,"locate":1,"http":8887,]),(["notice":1,"wotf-mail":1,"beep":1,]),}),"Dead_Souls_greatland":({0,"76.185.16.182",6666,6672,6674,"Dead Souls 3.8.2","Dead Souls 3.8.2","FluffOS v2.23-ds03w","LPMud","mudlib development","greatland@rocketmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"who":1,"auth":1,"oob":6672,"locate":1,"emoteto":1,"http":6667,]),(["upsince":"Tue Sep 01 14:04:54 2020","ip":"127.0.0.1","next boot":"EST Wed Jan 28 23:04:54 2032","architecture":"Microsoft Windows NT","os build":"windows","oob port":6672,"native version":"3.8.2",]),}),"Nanvaent":({-1,"207.162.200.121",3000,3001,0,"Nanvaent V.4ish","Nanvaent","NANVAENT 3 (FluffOS v2.18)","LP","open for public","admin@nanvaent.org",(["channel":1,"ftp":4001,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"emoteto":1,"ucache":1,"http":80,"file":1,]),0,}),"Dark City":({-1,"178.79.173.99",3000,0,0,"Dark City","Merc","AFKMud I3 Driver 2.33","GodWars","Open","tijer@godwars.net",(["finger":1,"who":1,"channel":1,"locate":1,"emoteto":1,"ucache":1,"tell":1,]),(["url":"http://www.godwars.net","time":"Thu Aug 27 20:20:01 2020",]),}),"Avalon":({0,"91.215.74.15",7777,7600,4246,"Avalon","Unitopia","LDMud 3.5.0","LP","open for public","admins@avalon.mud.de",(["channel":1,"mail":1,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"emoteto":1,"http":80,]),(["url":"http://avalon.mud.de","banner":" +-------------------------------------------------------------------------+ | _____ .__ avalon.intersolute.de (91.215.74.15) 7777 | | / _ \\___ _______ | | ____ ____ LDMud 3.5.0 NATIVE | | / /_\\ \\ \\/ /\\__ \\ | | / _ \\ / \\ http://avalon.mud.de/ | | / | \\ / / __ \\| |_( <_> ) | \\ | | \\____|__ /\\_/ (____ /____/\\____/|___| / | | \\/ \\/ \\/ | +-------------------------------------------------------------------------+ ",]),}),"Pocket Steam":({-1,"192.81.133.184",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","marisag@pocketmud.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"GTFO":({-1,"138.68.247.72",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"The Zone-i4":({-1,"136.144.155.250",8888,8891,8890,"WOTFlib 0.90","LPMud","DGD 1.4.1","LPMud","beta testing","aidil@wotf.org",(["channel":1,"ftp":21,"tell":1,"who":1,"locate":1,"http":8887,]),(["notice":1,"wotf-mail":1,"beep":1,]),}),"Paradigm MUD":({-1,"45.79.73.28",5555,0,0,"CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud","Beta Testing","alisonclower@gmail.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Nostalgia":({0,"82.11.250.100",5555,5558,0,"Tmi-2 1.4","Tmi-2 1.4","FluffOS v2.16-ds05w","LPmud","Mudlib Development","Unknown",(["channel":1,"ftp":5554,"tell":1,"finger":1,"who":1,"auth":1,"locate":1,"http":5550,"channel-0505":1,]),0,}),"Cyprus MUD":({-1,"173.255.218.223",5555,0,0,"CoffeeMud v5.9.9.1","CoffeeMud v5.9.9.1","CoffeeMud v5.9.9.1","CoffeeMud","Restricted Access","jescat27@live.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"AgeOfHeroes":({0,"46.32.38.32",2345,0,2347,"AoH 0.5-0","AoH","LDMud 3.6.3 (3.6.3)","LPMud","Mudlib Development","ralph@zitz.dk",(["channel":1,"mail":1,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"emoteto":1,"ucache":1,]),(["url":"http://aoh.zitz.dk","banner":"",]),}),"SirdudesGurbaLib":({-1,"174.53.232.12",4000,4002,4003,"GurbaLib v0.50","GurbaLib","DGD 1.6.13","LPMud","Mudlib Development","mein@umn.edu",(["auth":1,"who":1,"channel":1,"locate":1,"ftp":4001,"tell":1,]),([]),}),"PLEXUS":({-1,"86.52.128.42",4242,4243,0,"Lima/PLX 0.4","Lima","fluffos v2019.2020050101","LP","game development","tsath@shadowlord.org",(["channel":1,"mail":1,"ftp":21,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"ucache":1,"emoteto":1,"http":80,"file":1,]),0,}),"Frontiers":({-1,"204.209.44.3",8000,8006,8008,"Dead Souls 2.10","Dead Souls 2.10","FluffOS v2.15-ds05","LPMud","mudlib development","cratylus@comcast.net",(["channel":1,"mail":1,"tell":1,"finger":1,"who":1,"auth":1,"oob":8005,"locate":1,"emoteto":1,]),(["upsince":"Sun Aug 30 06:54:01 2020","ip":"127.0.0.1","next boot":"EDT Sun Sep 6 08:54:01 2020","architecture":"Linux","os build":"unix","oob port":8006,"native version":"2.9a17",]),}),"Waterver_Dev":({-1,"71.246.228.190",6666,0,0,"Tim's LPC IMC2 client 30-Jan-05 / Dead Souls integrated","Tim's LPC IMC2 client 30-Jan-05 / Dead Souls integrated","IMC2 client","n/a"," "," ",(["who":1,"channel":1,"tell":1,]),(["port":6666,"versionid":"Tim's LPC IMC2 client 30-Jan-05 / Dead Souls integrated","url":"http://dead-souls.net","imc_version":2.000000,"host":"71.246.228.190",]),}),"Final Realms":({-1,"185.47.42.101",4001,0,0,"FRlib V","Final Realms","FluffOS v2.23","LPMud","open to players","mudadm@fr.hyssing.net",(["channel":1,"ftp":0,"tell":1,"nntp":0,"finger":1,"who":1,"smtp":4021,"http":0,]),0,}),"FR:Development":({0,"185.47.42.101",4002,0,0,"FRlib V","Final Realms","FluffOS v2.28.3","LPMud","closed for players","mudadm@fr.hyssing.net",(["channel":1,"ftp":0,"tell":1,"nntp":0,"finger":1,"who":1,"http":0,"smtp":4021,]),0,}),"UberMud":({-1,"54.202.46.66",5555,0,0,"CoffeeMud v5.9.8","CoffeeMud v5.9.8","CoffeeMud v5.9.8","CoffeeMud","Restricted Access","wbfredrickson@yahoo.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"CoffeeMud":({-1,"104.14.28.106",2323,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Open to the public","zac@coffeemud.net",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Ukiyo":({-1,"212.56.108.81",5555,0,0,"CoffeeMud v5.9.8","CoffeeMud v5.9.8","CoffeeMud v5.9.8","CoffeeMud","Restricted Access","ukiyo@passiverpg.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"BlackDawn":({-1,"45.64.56.66",1701,1706,1709,"BlackDawn II ","DeadSouls 1.1pre","FluffOS v2.28.3","LPMud","Mudlib Development","adam@themud.org",(["channel":1,"ftp":1700,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"emoteto":1,"rcp":1691,"http":1696,]),([]),}),"Portals Inbetween":({-1,"45.33.50.126",5555,0,0,"CoffeeMud v5.9.9.1","CoffeeMud v5.9.9.1","CoffeeMud v5.9.9.1","CoffeeMud","Beta Testing","info@portals.pocketmud.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"ShadowMUDii Dev":({-1,"199.74.141.8",1035,1044,1043,"Nightmare/ShadowLib 3.2.2/0.5","Nightmare/ShadowLib 3.2.2/0.5","FluffOS v2.28.2","LP","beta testing","shadowmudii@hotmail.com",(["finger":1,"who":1,"channel":1,"locate":1,"emoteto":1,"tell":1,]),([]),}),"Testlandia":({-1,"54.88.224.206",6767,6773,6775,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03","LPMud","mudlib development","raven@raven-nc.net",(["channel":1,"mail":1,"ftp":6766,"tell":1,"finger":1,"who":1,"auth":1,"oob":6773,"locate":1,"emoteto":1,"http":6768,]),(["upsince":"Sun Jun 28 00:00:11 2020","ip":"127.0.0.1","next boot":"EDT Mon Nov 24 14:00:11 2031","architecture":"Linux","os build":"unix","oob port":6773,"native version":"3.9",]),}),"GreyArea":({-1,"220.253.84.210",2222,2228,2230,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03","LPMud","mudlib development","mordain23@gmail.com",(["channel":1,"mail":1,"ftp":2221,"tell":1,"finger":1,"who":1,"auth":1,"oob":2228,"locate":1,"emoteto":1,"http":2223,]),(["upsince":"Sat Sep 5 18:34:36 2020","ip":"127.0.0.1","next boot":"EST Mon Feb 2 05:34:36 2032","architecture":"Linux","os build":"unix","oob port":2228,"native version":"3.9",]),}),"Nygaard MUD":({-1,"172.105.9.226",5555,0,0,"CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud","Beta Testing","info@nygaard.pocketmud.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Senitan Online":({-1,"71.72.126.17",6666,6672,6674,"Dead Souls 3.8.6","Dead Souls 3.8.6","FluffOS v2.23-ds03","LPMud","mudlib development","rt3388@gmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"who":1,"auth":1,"oob":6672,"locate":1,"emoteto":1,"http":6667,]),(["upsince":"Thu Aug 20 19:19:04 2020","ip":"127.0.0.1","next boot":"EST Sat Jan 17 04:19:04 2032","architecture":"Linux","os build":"unix","oob port":6672,"native version":"3.8.6",]),}),"FOR_NOW":({-1,"24.19.149.119",5555,0,0,"CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud","Beta Testing","jackvaguely@gmail.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Planstudio Dungeons":({-1,"80.210.98.67",5555,0,0,"CoffeeMud v5.9.5","CoffeeMud v5.9.5","CoffeeMud v5.9.5","CoffeeMud","Beta Testing","",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Dead_Souls_maldrin":({0,"72.183.47.232",6666,6672,6674,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03w","LPMud","mudlib development","admin@here",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"who":1,"auth":1,"oob":6672,"locate":1,"emoteto":1,"http":6667,]),(["upsince":"Tue Sep 01 01:06:55 2020","ip":"127.0.0.1","next boot":"EST Wed Jan 28 10:06:55 2032","architecture":"Microsoft Windows NT","os build":"windows","oob port":6672,"native version":"3.9",]),}),"Your Muds Name Here":({0,"75.70.133.45",5555,0,0,"CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud","Beta Testing","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"doomsday":({-1,"94.189.246.51",7000,0,0,"CoffeeMud v5.9.8.1","CoffeeMud v5.9.8.1","CoffeeMud v5.9.8.1","CoffeeMud","Beta Testing","",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Dead_Souls_excelsior":({0,"117.20.68.194",6666,6672,6674,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03w","LPMud","mudlib development","robk@ningaui.net",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6672,"emoteto":1,"http":6667,]),(["upsince":"Sat Aug 29 14:09:29 2020","ip":"127.0.0.1","architecture":"Microsoft Windows NT","next boot":"EST Mon Jan 26 00:09:29 2032","os build":"windows","native version":"3.9","oob port":6672,]),}),"Wunderland":({-1,"139.18.11.86",23,4246,4246,"WL-Lib","WL-Lib","LDMud 3.3.720","LPMud","open for public","mud@wl.mud.de",(["channel":1,"mail":1,"ftp":4713,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"ucache":1,"emoteto":1,"http":80,]),(["url":"http://wl.mud.de","banner":" _ _ _ _ _ ( ) ( )_ _ __ _( ) ___ _ _( ) ___ __ _( ) Adresse: wl.mud.de (23) | ^ | | ) \\/ _ )/ -_\\ ^_) )/ _ ) \\/ _ ) im IPv6: wl.mud.de 4711 \\/ \\/ \\_/|_|_)___)\\___)_| (__)___)_|_)___) WWW : http://wl.mud.de/ ",]),}),"Second Contract":({-1,"54.84.108.226",6666,6672,6674,"Dead Souls 3.6","Dead Souls 3.6","FluffOS v2.23-ds01","LPMud","open alpha","admin@second-contract.com",(["channel":1,"mail":1,"tell":1,"finger":1,"who":1,"auth":1,"oob":6672,"locate":1,"emoteto":1,"http":6667,]),(["upsince":"Mon Jul 20 19:20:51 2020","ip":"50.57.187.30","next boot":"never","architecture":"Linux","os build":"unix","oob port":6672,"native version":"3.6",]),}),"Tarmetrotrate":({0,"76.185.16.182",6666,6672,6674,"Dead Souls 3.8.2","Dead Souls 3.8.2","FluffOS v2.23-ds03w","LPMud","mudlib development","greatland@rocketmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"who":1,"auth":1,"oob":6672,"locate":1,"emoteto":1,"http":6667,]),(["upsince":"Tue Sep 01 14:04:54 2020","ip":"127.0.0.1","next boot":"EST Wed Jan 28 23:04:54 2032","architecture":"Microsoft Windows NT","os build":"windows","oob port":6672,"native version":"3.8.2",]),}),"OASIS MUD":({-1,"51.91.251.230",5555,0,0,"CoffeeMud v5.9.9.1","CoffeeMud v5.9.9.1","CoffeeMud v5.9.9.1","CoffeeMud","Beta Testing","",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"DarkeMUD":({-1,"45.52.9.106",0,0,0," "," "," "," "," "," ",(["who":1,"channel":1,"tell":1,]),(["imc_version":2.000000,]),}),"Forgotten-Gods":({-1,"54.172.123.224",6690,6696,6698,"Dead Souls 3.8.6","Dead Souls 3.8.6","FluffOS v2.23-ds03","LPMud","mudlib development","elohim@technocratia.com",(["channel":1,"mail":1,"ftp":6689,"tell":1,"finger":1,"who":1,"auth":1,"oob":6696,"locate":1,"emoteto":1,"http":6691,]),(["upsince":"Sat May 5 19:13:37 2018","ip":"127.0.0.1","next boot":"EST Mon Oct 1 05:13:37 2029","architecture":"Linux","os build":"unix","oob port":6696,"native version":"3.8.6",]),}),"Unnamed_CoffeeMUD#316468430":({0,"185.245.86.149",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","realmatwar@gmail.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"InfectedMinds":({-1,"73.245.13.171",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","infected@infectedminds.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Brandywine MUD":({-1,"45.33.64.28",5555,0,0,"CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud","Beta Testing","info@brandywine.pocketmud.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Epitaph":({0,"176.126.244.21",23,8765,0,"Epiphany v1.2.13 [release]","Epiphany v1.2.13 [release]","FluffOS v2.26 (MeekOS version)","LPMud","Development","drakkos@imaginary-realities.com",(["channel":1,"ftp":6001,"tell":1,"finger":1,"who":1,"auth":1,"locate":1,"emoteto":1,"http":80,]),0,}),"Lemonland":({0,"91.200.100.76",5555,0,0,"CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud","Beta Testing","",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"The Zone":({-1,"136.144.155.250",8888,8891,8890,"WOTFlib 0.90","LPMud","DGD 1.4.1","LPMud","beta testing","aidil@wotf.org",(["channel":1,"ftp":21,"tell":1,"who":1,"locate":1,"http":8887,]),(["notice":1,"wotf-mail":1,"beep":1,]),}),"Waterver":({0,"71.246.228.190",6666,6672,6674,"Dead Souls 3.8.6","Dead Souls 3.8.6","FluffOS v2.23-ds03","LPMud","mudlib development","jgsmith@gmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"who":1,"auth":1,"oob":6672,"locate":1,"emoteto":1,"http":6667,]),(["upsince":"Tue Sep 1 17:17:14 2020","ip":"127.0.0.1","next boot":"EST Thu Jan 29 02:17:14 2032","architecture":"Mac OS X","os build":"unix","oob port":6672,"native version":"3.8.6",]),}),"Dahlookahs MUD":({0,"46.251.35.104",8888,8893,0,"Skylib 1.8","Discworld","FluffOS v2.23","LP","Mudlib Development","quixadhal@gmail.com",(["channel":1,"ftp":8890,"tell":1,"finger":1,"who":1,"locate":1,"emoteto":1,"http":8891,]),([]),}),"I3-TheMud-ORG-PGSQL":({-1,"45.64.56.66",5555,5561,5563,"Dead Souls 3.8.6","Dead Souls 3.8.6","FluffOS v2.28.3","LPMud","CLOSED TO PUBLIC","adam@themud.org",(["channel":1,"mail":1,"ftp":5554,"tell":1,"finger":1,"who":1,"auth":1,"oob":5561,"locate":1,"emoteto":1,"http":5556,]),(["upsince":"Fri Aug 7 10:39:57 2020","ip":"127.0.0.1","next boot":"AES Sun Jan 4 02:39:57 2032","architecture":"Linux/x86-64","os build":"unix","oob port":5561,"native version":"3.8.6",]),}),"Covenant of Lords":({-1,"96.126.100.155",23,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","info@covenantoflords.pocketmud.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Tales of Aeril":({-1,"45.33.10.116",5555,0,0,"CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud","Restricted Access","info@talesofaeril.pocketmud.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Multiverse MUD":({-1,"45.33.61.54",5555,0,0,"CoffeeMud v5.9.9.1","CoffeeMud v5.9.9.1","CoffeeMud v5.9.9.1","CoffeeMud","Beta Testing","vaencor@yahoo.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Darkness and Despair":({-1,"155.254.17.154",4201,3500,3501,"Nightmare+DnD","Nightmare v3.2","FluffOS v2017.2018120702 (git-7054237-1546244910)","LPMud","Open for public","squid@desolation.org",(["finger":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Realm At War":({0,"107.158.155.195",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","realmatwar@gmail.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Pluto MUD":({-1,"172.105.37.194",5555,0,0,"CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud","Beta Testing","info@pluto.pocketmud.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"lpcdb":({-1,"136.144.155.250",4000,4002,4003,"lpcdb v1.0 alpha 2","lpcdb","DGD 1.5.4","LPMud","Mudlib Development","aidil@wotf.org",(["auth":1,"who":1,"channel":1,"locate":1,"ftp":4001,"tell":1,]),([]),}),"Dead_Souls_babylon":({0,"50.34.196.5",6666,6672,6674,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03w","LPMud","mudlib development","babylon_horuv@zoho.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"who":1,"auth":1,"oob":6672,"locate":1,"emoteto":1,"http":6667,]),(["upsince":"Wed Sep 02 20:17:11 2020","ip":"127.0.0.1","next boot":"EST Fri Jan 30 05:17:11 2032","architecture":"Microsoft Windows NT","os build":"windows","oob port":6672,"native version":"3.9",]),}),"The Zone-dalet":({-1,"136.144.155.250",8888,8891,8890,"WOTFlib 0.90","LPMud","DGD 1.4.1","LPMud","beta testing","aidil@wotf.org",(["channel":1,"ftp":21,"tell":1,"who":1,"locate":1,"http":8887,]),(["notice":1,"wotf-mail":1,"beep":1,]),}),"Kotaka":({0,"96.41.218.191",61440,0,0,"Kotaka","Kotaka","DGD 1.6.13","DGD","(fill in the purpose of the mud here)","(fill in your admin email here)",(["channel":1,"tell":1,]),([]),}),"Zenith":({-1,"47.12.102.26",4201,4207,4209,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03","LPMud","mudlib development","tim_heinzeroth@hotmail.com",(["channel":1,"mail":1,"ftp":4200,"tell":1,"finger":1,"who":1,"auth":1,"oob":4207,"locate":1,"emoteto":1,"http":4202,]),(["upsince":"Sat Sep 5 17:06:09 2020","ip":"127.0.0.1","next boot":"EST Mon Feb 2 02:06:09 2032","architecture":"Linux","os build":"unix","oob port":4207,"native version":"3.9",]),}),"Eye of the World":({-1,"50.116.55.253",2222,2225,0,"Tmi-2 1.4","Tmi-2 1.4","MudOS v22.2b13","LPmud","Open for Users","shaitan@eyemud.com",(["ftp":2221,"http":2217,]),0,}),"The Brass Ring":({-1,"96.244.229.21",2150,2156,2158,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03","LPMud","mudlib development","n@n.net",(["channel":1,"mail":1,"ftp":2149,"tell":1,"finger":1,"who":1,"auth":1,"oob":2156,"locate":1,"emoteto":1,"http":2151,]),(["upsince":"Fri Sep 4 17:31:04 2020","ip":"127.0.0.1","next boot":"never","architecture":"Linux","os build":"unix","oob port":2156,"native version":"3.9",]),}),"Ara Labs":({-1,"34.86.104.52",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","hokieines@gmail.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Homebound":({-1,"45.33.46.71",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","matthew.shaun@gmail.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Swashbockle MUD":({-1,"45.33.42.13",5555,0,0,"CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud","Beta Testing","info@swashbockle.pocketmud.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Unnamed_CoffeeMUD#75852566":({0,"88.105.63.141",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"WileyMUD":({-1,"172.92.143.166",3000,0,0,"WileyMUD III 2.123g","WileyMUD III 2.123g","I3 Driver 2.40b","DikuMUD","Idle","quixadhal@wileymud.themud.org",(["channel":1,"tell":1,"finger":1,"who":1,"locate":1,"emoteto":1,"ucache":1,"beep":1,]),(["url":"http://wileymud.themud.org/~wiley/","time":"Sat Sep 5 06:34:52 2020",]),}),"Fantastic mud":({-1,"217.61.6.178",6666,6672,6674,"Dead Souls 3.8.2","Dead Souls 3.8.2","FluffOS v2.23-ds03","LPMud","mudlib development","admin@mud.tdani.hu",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"who":1,"auth":1,"oob":6672,"locate":1,"emoteto":1,"http":6667,]),(["upsince":"Sun Sep 6 10:42:46 2020","ip":"127.0.0.1","next boot":"EST Sun Sep 6 17:42:46 2020","architecture":"Linux","os build":"unix","oob port":6672,"native version":"3.8.2",]),}),"Haven":({-1,"23.253.225.109",5000,5005,5008,"Haven 0.1","Haven 0.1","FluffOS v2.9-ds2.14","LPMud","Open - Small playerbase","Hidden from Spammers",(["channel":1,"ftp":4999,"tell":1,"finger":1,"who":1,"locate":1,"rcp":4990,"emoteto":1,"http":80,]),([]),}),"Old Sol 2020":({0,"101.80.96.43",7777,7783,7785,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03","LPMud","mudlib development","kengim63@gmail.com",(["channel":1,"mail":1,"ftp":7776,"tell":1,"finger":1,"who":1,"auth":1,"oob":7783,"locate":1,"emoteto":1,"http":7778,]),(["upsince":"Sat Sep 5 17:33:08 2020","ip":"127.0.0.1","next boot":"EST Mon Feb 2 03:33:08 2032","architecture":"Linux","os build":"unix","oob port":7783,"native version":"3.9",]),}),"IMUD-FluffOS2019":({-1,"110.232.112.129",1701,1707,1709,"Dead Souls 3.8.6","Dead Souls 3.8.6","fluffos v2019.2020041301","LPMud","driver development","adam@themud.org",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,"emoteto":1,]),(["upsince":"Sat Jun 13 13:04:47 2020","ip":"127.0.0.1","next boot":"EST Mon Nov 10 00:04:47 2031","architecture":"Linux/x86-64","os build":"unix","oob port":1707,"native version":"3.8.6",]),}),"savageisle":({-1,"23.25.8.124",5559,0,0,"CoffeeMud v5.9.6","CoffeeMud v5.9.6","CoffeeMud v5.9.6","CoffeeMud","Beta Testing","admin@savageisles.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"SingularisMUD":({-1,"46.251.35.104",8888,8893,0,"Skylib 1.8","Discworld","FluffOS v2017.2019112002 (git-51e006b-1574310904)","LP","Mudlib Development","user@host.com",(["channel":1,"ftp":8890,"tell":1,"finger":1,"who":1,"locate":1,"emoteto":1,"http":8891,]),([]),}),"The Zone-Kelly":({-1,"136.144.155.250",8888,8891,8890,"WOTFlib 0.90","LPMud","DGD 1.4.1","LPMud","beta testing","aidil@wotf.org",(["channel":1,"ftp":21,"tell":1,"who":1,"locate":1,"http":8887,]),(["notice":1,"wotf-mail":1,"beep":1,]),}),"Worlds Of Wonder":({-1,"144.217.205.176",2500,2506,2508,"Dead Souls 3.8.2","Dead Souls 3.8.2","FluffOS v2.23-ds03","LPMud","mudlib development","gabriel@wonderteamterrible.com",(["channel":1,"mail":1,"ftp":2499,"tell":1,"finger":1,"who":1,"auth":1,"oob":2506,"locate":1,"emoteto":1,"http":2549,]),(["upsince":"Thu Sep 12 21:54:25 2019","ip":"127.0.0.1","next boot":"EST Sat Feb 8 06:54:25 2031","architecture":"Linux","os build":"unix","oob port":2506,"native version":"3.8.2",]),}),"KellerMUD":({-1,"104.237.155.126",23,0,0,"CoffeeMud v5.9.6","CoffeeMud v5.9.6","CoffeeMud v5.9.6","CoffeeMud","Restricted Access","info@kellermud.pocketmud.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Dragon's Den":({-1,"74.109.126.27",2222,2223,2223,"Dragon Mudlib 1.1","MudOS v22.2b13","MudOS v22.2b14","LPMud","Open since 1990","cejones1@gmail.com",(["channel":1,"mail":0,"ftp":2223,"tell":1,"news":0,"finger":1,"who":1,"auth":0,"locate":1,"emoteto":1,"ucache":0,"http":2080,"file":0,]),0,}),"The Library":({-1,"65.19.167.66",6666,6672,6674,"Dead Souls 3.7a7","Dead Souls 3.7a7","FluffOS v2.23-ds01","LPMud","mudlib development","z993126@gmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"who":1,"auth":1,"oob":6672,"locate":1,"emoteto":1,"http":6667,]),(["upsince":"Fri Nov 9 18:01:46 2018","ip":"127.0.0.1","next boot":"EST Sun Apr 7 05:01:46 2030","architecture":"Linux","os build":"unix","oob port":6672,"native version":"3.7a7",]),}),"Local MUD":({0,"204.195.8.155",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Waterver Dev":({-1,"71.246.228.190",6666,6672,6674,"Dead Souls 3.9","Dead Souls 3.9","fluffos v2019.2020082501","LPMud","mudlib development","jgsmith@gmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6672,"emoteto":1,"http":6667,]),(["upsince":"Fri Sep 4 20:19:15 2020","ip":"127.0.0.1","architecture":"Linux/x86-64","next boot":"never","os build":"unix","native version":"3.9","oob port":6672,]),}),"The Rifthome MUD":({-1,"46.4.48.195",5585,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"lpcdb-dev":({-1,"87.209.243.234",4000,4002,4003,"lpcdb v1.0 alpha 2","lpcdb","DGD 1.5.5","LPMud","Mudlib Development","aidil@wotf.org",(["auth":1,"who":1,"channel":1,"locate":1,"ftp":4001,"tell":1,]),(["banner":"<div>html escape test </div>",]),}),"Nuke II":({-1,"173.255.201.173",4080,4081,0,"Lima 1.0b5","Lima","fluffos v2019.2020050101","LP","game development","stanach@nuclearwarmud.com",(["channel":1,"mail":1,"ftp":21,"tell":1,"finger":1,"who":1,"auth":1,"locate":1,"emoteto":1,"ucache":1,"file":1,"http":80,]),0,}),"The Beast Within: Resurrected":({-1,"45.33.109.237",5555,0,0,"CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud","Beta Testing","mudadmin@beastwithin.pocketmud.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Itinerantion":({-1,"108.173.162.164",6666,6672,6674,"Dead Souls 3.8.6","Dead Souls 3.8.6","FluffOS v2.23-ds03","LPMud","mudlib development","w.steven.schneider@gmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6672,"emoteto":1,"http":6667,]),(["upsince":"Tue Jul 21 21:56:07 2020","ip":"127.0.0.1","architecture":"unknown architecture","next boot":"MST Thu Dec 18 11:56:07 2031","os build":"unix","native version":"3.8.2","oob port":6672,]),}),"Realm of Shadows":({-1,"24.9.9.201",1133,0,0,"Smaug 1.4a","Smaug","I3 Driver 2.40b","DikuMUD","Operational","syriac_ros@gmail.com",(["channel":1,"tell":1,"finger":1,"who":1,"locate":1,"emoteto":1,"ucache":1,"beep":1,]),(["url":"https://realmofshadows.us","time":"Wed Sep 2 17:13:10 2020",]),}),"Realm of Cernunnos":({-1,"50.105.123.230",5555,0,0,"CoffeeMud v5.9.4","CoffeeMud v5.9.4","CoffeeMud v5.9.4","CoffeeMud","Open to the public","admin@cernunnos.net",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Disk World":({-1,"172.92.143.166",4400,4404,0,"Discworld 17.0a","Disk World","FluffOS v2.28.2","LPMud","Development","none",(["channel":1,"ftp":4440,"tell":1,"finger":1,"who":1,"auth":1,"locate":1,"emoteto":1,"http":4480,]),0,}),"Indigo":({-1,"87.229.53.104",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Aadarian Realms":({-1,"178.79.173.99",1111,0,0,"ADR 5.06 (build: 19)","ROT","Aadaria I3 Driver 2.33(mod)","DikuMUD","Open","tijer@godwars.net",(["channel":1,"tell":1,"finger":1,"who":1,"locate":1,"emoteto":1,"ucache":1,"beep":1,]),(["url":"http://www.aadaria.net","time":"Fri Aug 21 14:24:02 2020",]),}),"Universes":({-1,"108.252.255.105",3333,3338,3341,"UniLib 1.0a","UniLib 1.0a","MudOS v22.1","LPMud","MudLib Development","ebayer@thetesseract.org",(["finger":1,"who":1,"channel":1,"tell":1,"emoteto":1,"amcp":"1.1","http":80,]),([]),}),"World of ClouseCraft":({-1,"167.172.140.125",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Core MUD":({-1,"173.193.107.10",4000,4010,4020,"Colony 1.3","Colony 1.3","MudOS v22.2b14","LPMud","Open to players","dshay01@coremud.org",(["news":0,"auth":0,"who":1,"locate":1,"emoteto":1,"file":0,"http":80,"channel":1,"mail":0,"ftp":0,"tell":1,"nntp":0,"finger":1,"ucache":1,"rcp":0,"smtp":0,]),([]),}),"OglafMUD":({-1,"86.52.128.42",7878,7879,0,"Lima 1.0b5","Lima","fluffos v2019.2020050101","LP","game development","user@host.name",(["channel":1,"mail":1,"ftp":21,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"ucache":1,"emoteto":1,"http":80,"file":1,]),0,}),"AsYetUntitled":({-1,"178.62.73.229",6666,6672,6674,"Dead Souls 3.8.6","Dead Souls 3.8.6","FluffOS v2.23-ds03","LPMud","mudlib development","tahoma@tammenta.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"who":1,"auth":1,"oob":6672,"locate":1,"emoteto":1,"http":6663,]),(["upsince":"Sun Jul 19 17:13:28 2020","ip":"127.0.0.1","next boot":"EST Tue Dec 16 02:13:28 2031","architecture":"Linux","os build":"unix","oob port":6672,"native version":"3.8.6",]),}),"Dead Souls Dev":({-1,"97.107.133.86",8000,8006,8008,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03","LPMud","mudlib development","cratylus@comcast.net",(["channel":1,"tell":1,"finger":1,"who":1,"auth":1,"locate":1,"emoteto":1,"http":8001,]),(["upsince":"Fri Oct 18 02:29:02 2019","ip":"127.0.0.1","next boot":"EST Sat Mar 15 11:29:02 2031","architecture":"Linux","os build":"unix","oob port":8006,"native version":"3.8.2",]),}),"Dreamverse":({0,"70.91.196.214",9600,9605,9608,"DV-Nightmare RELENG_1_3","DV-Nightmare RELENG_1_3","fluffos v2019","LPMud","development","hilapdatus@dreamverse.org",(["ftp":9599,"rcp":9585,"amcp":"1.1","http":9595,]),(["next boot":"Wed Sep 2 12:04:23 2020 GMT-0500","up since":"Wed Sep 2 12:04:23 2020 GMT-0500","architecture":"Linux/x86-64",]),}),"Zebu":({-1,"50.34.196.5",6666,6672,6674,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03w","LPMud","mudlib development","babylon_horuv@zoho.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"who":1,"auth":1,"oob":6672,"locate":1,"emoteto":1,"http":6667,]),(["upsince":"Sun Sep 06 04:26:14 2020","ip":"127.0.0.1","next boot":"GMT Mon Feb 02 18:26:14 2032","architecture":"Microsoft Windows NT","os build":"windows","oob port":6672,"native version":"3.9",]),}),"Randy Stadham":({-1,"104.237.152.181",23,0,0,"CoffeeMud v5.9.6.4","CoffeeMud v5.9.6.4","CoffeeMud v5.9.6.4","CoffeeMud","Beta Testing","info@randys.pocketmud.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Somavos":({-1,"23.92.30.29",4242,0,0,"CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud","MudLib Development","",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Desolation":({-1,"155.254.17.151",8787,8788,0,"Lima 1.0a8","Lima","fluffos v2019","LP","live","squid@desolation.org",(["channel":1,"mail":1,"ftp":21,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"ucache":1,"emoteto":1,"http":80,"file":1,]),0,}),"Little Mud":({0,"71.230.96.145",5555,0,0,"CoffeeMud v5.9.5","CoffeeMud v5.9.5","CoffeeMud v5.9.5","CoffeeMud","Beta Testing","",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Ulario":({0,"96.41.218.191",61440,0,0,"Kotaka","Kotaka","DGD 1.6.13","DGD","(fill in the purpose of the mud here)","(fill in your admin email here)",(["channel":1,"tell":1,]),([]),}),"GronMUD":({-1,"92.242.63.65",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Restricted Access","",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Dead_Souls_thessius":({0,"170.10.45.190",6666,6672,6674,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03w","LPMud","mudlib development","jessea.mccann@gmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"who":1,"auth":1,"oob":6672,"locate":1,"emoteto":1,"http":6667,]),(["upsince":"Wed Sep 02 12:04:09 2020","ip":"127.0.0.1","next boot":"EST Thu Jan 29 21:04:09 2032","architecture":"Microsoft Windows NT","os build":"windows","oob port":6672,"native version":"3.9",]),}),"Mathers Realms":({0,"69.174.144.117",2323,0,0,"CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud","Beta Testing","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Star Wars: Jedi vs Sith":({-1,"24.222.84.75",8707,0,0,"SWJvS 1.4.1","SWR 1.0 FUSS","AFKMud I3 Driver 2.40a","SWR","Star Wars MUD","michael@themudhost.net",(["channel":1,"tell":1,"finger":1,"who":1,"locate":1,"emoteto":1,"ucache":1,"beep":1,]),(["url":"http://swjvs.themudhost.net/","time":"Wed Jul 29 10:32:59 2020",]),}),"Mansocks World":({-1,"68.68.95.221",6666,6672,6674,"Dead Souls 3.8.2","Dead Souls 3.8.2","FluffOS v2.23-ds03","LPMud","mudlib development","addlema@gmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"who":1,"auth":1,"oob":6672,"locate":1,"emoteto":1,"http":6667,]),(["upsince":"Fri Aug 28 18:11:03 2020","ip":"127.0.0.1","next boot":"EST Sun Jan 25 03:11:03 2032","architecture":"Linux","os build":"unix","oob port":6672,"native version":"3.8.2",]),}),"I3-TheMud-ORG":({-1,"45.64.56.66",5555,5561,5563,"Dead Souls 3.8.6","Dead Souls 3.8.6","FluffOS v2.28.3","LPMud","CLOSED TO PUBLIC","adam@themud.org",(["channel":1,"mail":1,"ftp":5554,"tell":1,"finger":1,"who":1,"auth":1,"oob":5561,"locate":1,"emoteto":1,"http":5556,]),(["upsince":"Sun Aug 9 12:34:51 2020","ip":"127.0.0.1","next boot":"AES Tue Jan 6 04:34:51 2032","architecture":"Linux/x86-64","os build":"unix","oob port":5561,"native version":"3.8.6",]),}),"The Open Door":({-1,"50.116.13.244",5555,0,0,"CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud","Beta Testing","info@opendoor.pocketmud.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Iberia MUD":({-1,"2.81.180.125",5900,0,0,"IME v0.9975","IME","IME","IME","beta testing","joaodiasafonso@gmail.com",(["who":1,"channel":1,"tell":1,"emoteto":1,]),0,}),"WarofLegend":({-1,"178.79.173.99",4200,0,0,"WoL 10.26 (build: 45)","Merc","AFKMud I3 Driver 2.33","DikuMUD","Open","admin@waroflegend.net",(["finger":1,"who":1,"channel":1,"locate":1,"emoteto":1,"ucache":1,"tell":1,]),(["url":"http://www.waroflegend.net","time":"Tue Sep 1 17:18:18 2020",]),}),"TimesLost":({0,"104.48.188.233",3000,0,0,"6Dragons 4.4","Smaug","I3 Driver 2.40b","DikuMUD","Operational","ixliam1@gmail.com",(["channel":1,"tell":1,"finger":1,"who":1,"locate":1,"emoteto":1,"ucache":1,"beep":1,]),(["url":"old.reddit.com/r/wotlmud","time":"Sat Sep 5 20:04:26 2020",]),}),"Occulte":({-1,"199.74.141.8",6677,8765,0,"Discworld 17.0a","Occulte","FluffOS v2.15-ds08","LPMud","Development","none",(["channel":1,"ftp":4444,"tell":1,"finger":1,"who":1,"auth":1,"locate":1,"emoteto":1,"http":80,]),0,}),"Nightfall":({-1,"212.83.56.217",4242,4246,4246,"NF","NF","LPMud 3.5.0.2 (3.5.0.2-13-g4572ab8f)","LPMud","open for public","administration@nightfall.org",(["channel":1,"ftp":21,"tell":1,"finger":1,"who":1,"locate":1,"emoteto":1,"http":80,]),(["url":"http://nightfall.org","banner":"------------------------------------------------------------------------------ Nightfall LD-LPMud driver 3.5.0.2 (3.5.0.2-13-g4572ab8f)/mudlib NF III in Dreamland, Germany telnet [nightfall.org 2a00:f48:1003:1::56:66f1 212.83.56.217]:4242 ------------------------------------------------------------------------------ ",]),}),"A.HEGY. ":({-1,"89.133.33.82",1222,1228,1230,"Dead Souls 3.8.6","Dead Souls 3.8.6","FluffOS v2.23-ds03","LPMud","mudlib development","dp@iworld.hu",(["channel":1,"mail":1,"ftp":1221,"tell":1,"finger":1,"who":1,"auth":1,"oob":1228,"locate":1,"emoteto":1,"http":1223,]),(["upsince":"Fri Jun 26 10:13:06 2020","ip":"127.0.0.1","next boot":"CET Sun Nov 23 01:13:06 2031","architecture":"Linux","os build":"unix","oob port":1228,"native version":"3.8.6",]),}),"LPM":({-1,"18.218.123.244",6666,6672,6674,"Dead Souls 3.8.6","Dead Souls 3.8.6","FluffOS v2.23-ds03","LPMud","mudlib development","cratylus.ds@gmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"who":1,"auth":1,"oob":6672,"locate":1,"emoteto":1,"http":6667,]),(["upsince":"Sat Mar 14 23:50:17 2020","ip":"127.0.0.1","next boot":"EST Mon Aug 11 09:50:17 2031","architecture":"Linux","os build":"unix","oob port":6672,"native version":"3.8.6",]),}),"EmpiresEnd":({-1,"74.207.226.164",5555,0,0,"CoffeeMud v5.9.6","CoffeeMud v5.9.6","CoffeeMud v5.9.6","CoffeeMud","Beta Testing","islander@glassislands.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"szetnezek":({0,"87.229.23.214",5555,5560,5563,"Nightmare IVr6","Nightmare IVr6","FluffOS v2.23-ds03","LPMud","mudlib development","borg@imaginary.com",(["channel":1,"ftp":5554,"tell":1,"finger":1,"who":1,"locate":1,"emoteto":1,"ucache":1,"rcp":5545,"http":5550,]),([]),}),"DomeMUD Dev":({0,"73.147.192.82",4000,4002,4003,"Domelib v0.9-a3","Domelib","DGD 1.4.14","LPMud","Mudlib Development","admin@domemud.com",(["auth":1,"who":1,"channel":1,"locate":1,"ftp":4001,"tell":1,]),([]),}),"Way of the Force":({-1,"136.144.155.250",23,3000,3000,"WOTFlib 0.90","LPMud","DGD 1.2.157-WOTF-NET","LPMud","beta testing","aidil@wotf.org",(["channel":1,"ftp":21,"tell":1,"who":1,"locate":1,"http":80,]),(["notice":1,"wotf-mail":1,"beep":1,]),}),"Amethyst Kingdom":({0,"74.81.160.221",6666,6672,6674,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03","LPMud","mudlib development","barryeichelberger@gmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"who":1,"auth":1,"oob":6672,"locate":1,"emoteto":1,"http":6667,]),(["upsince":"Fri Sep 4 01:05:49 2020","ip":"192.168.1.204","next boot":"EST Sat Jan 31 11:05:49 2032","architecture":"Linux","os build":"unix","oob port":6672,"native version":"3.9",]),}),"Discworld":({-1,"82.68.167.69",23,8765,0,"Discworld 18.0a","Discworld","FluffOS v2.28","LPMud","open for players","trustees@discworld.starturtle.net",(["channel":1,"ftp":4444,"tell":1,"finger":1,"who":1,"auth":1,"locate":1,"emoteto":1,"http":80,]),0,}),"WayPoint":({-1,"74.208.214.165",5555,0,0,"CoffeeMud v5.9.8","CoffeeMud v5.9.8","CoffeeMud v5.9.8","CoffeeMud","Beta Testing","waypoint@model-reality.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Wk-CoffeeMud-Dev":({0,"104.14.28.106",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Open to the public","bo@zimmers.net",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"EotL":({-1,"209.216.23.199",2010,4247,4246,"LPMud EotL 98","LPMud EotL 98","Amylaar 3.2.14","LPMud","Open to players","none",(["who":1,"channel":1,"tell":1,]),([]),}),"Mundo Sangre":({-1,"23.239.11.138",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","info@mundosangre.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Abandoned Codex":({-1,"95.85.50.124",4000,0,0,"Smaug 1.02a modified","Smaug","I3 Driver 2.40b","DikuMUD","Open","admin@abandonedcodex.net",(["finger":1,"who":1,"channel":1,"locate":1,"ucache":1,"tell":1,]),(["url":"abandonedcodex.net","time":"Thu Aug 13 17:27:35 2020",]),}),"The Savage Soul":({-1,"173.255.210.234",6666,6672,6674,"Dead Souls 3.7a7","Dead Souls 3.7a7","FluffOS v2.23-ds01","LPMud","mudlib development","savagesoul@gmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"who":1,"auth":1,"oob":6672,"locate":1,"emoteto":1,"http":8001,]),(["upsince":"Fri Oct 25 09:10:07 2019","ip":"127.0.0.1","next boot":"PDT Sat Mar 22 17:10:07 2031","architecture":"Linux","os build":"unix","oob port":6672,"native version":"3.7a7",]),}),"GreyArea_DS-stock":({-1,"220.253.84.210",6666,6672,6674,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03","LPMud","mudlib development","mordain23@gmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"who":1,"auth":1,"oob":6672,"locate":1,"emoteto":1,"http":6667,]),(["upsince":"Sat Sep 5 14:00:35 2020","ip":"127.0.0.1","next boot":"EST Mon Feb 2 01:00:35 2032","architecture":"Linux","os build":"unix","oob port":6672,"native version":"3.9",]),}),"Dreath MUD":({-1,"23.92.27.179",23,0,0,"CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud","Beta Testing","info@dreath.pocketmud.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Adventurers Way":({-1,"172.105.188.166",1111,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","imaginingstuff@gmail.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"The Chronicles of Meridian":({-1,"78.90.77.217",7878,7881,7881,"Meridian v0.1","Meridian v0.1","fluffos v2019.2020082501","LPmud","Mudlib Development","vm@angband.eu",(["channel":1,]),(["upsince":"Sat Sep 5 01:19:38 2020","architecture":"Linux/x86-64",]),}),"TimMUD":({-1,"104.154.76.197",5555,5558,0,"Tmi-2 1.4","Tmi-2 1.4","FluffOS v2.28.3","LPmud","Mudlib Development","tim@timboj.com",(["channel":1,"ftp":5554,"tell":1,"finger":1,"who":1,"auth":1,"locate":1,"http":5550,]),(["url":"http://timmud.com",]),}),"Unnamed_CoffeeMUD#1999742985":({0,"23.243.152.62",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"m3tamud":({0,"88.98.228.197",4000,4002,4003,"GurbaLib v0.50","GurbaLib","DGD 1.6.13","LPMud","Mudlib Development","m3ta@m3ta.uk",(["who":1,"auth":1,"channel":1,"locate":1,"ftp":4001,"tell":1,]),([]),}),"Mystic":({-1,"45.79.130.170",3000,3005,3008,"Realms of Mystic Lib .06b","Realms of Mystic Lib .06b","MudOS v22.2b14","LPMud","now serving","mystic@uprising.net",(["finger":1,"who":1,"channel":1,"locate":1,"amcp":"1.1","emoteto":1,"tell":1,]),([]),}),"Unnamed_CoffeeMUD#1518426141":({0,"88.105.63.141",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"ShadowMUD":({-1,"199.74.141.8",1030,1039,1038,"Nightmare/ShadowLib 3.2.2/0.5","Nightmare/ShadowLib 3.2.2/0.5","FluffOS v2.28.2","LP","beta testing","shadowmudii@hotmail.com",(["finger":1,"who":1,"channel":1,"locate":1,"emoteto":1,"tell":1,]),([]),}),"Dead_Souls_pyra":({-1,"69.164.194.158",4000,4006,4008,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03","LPMud","mudlib development","blaketracy23@gmail.com",(["channel":1,"mail":1,"ftp":3999,"tell":1,"finger":1,"who":1,"auth":1,"oob":4006,"locate":1,"emoteto":1,"http":4001,]),(["upsince":"Sat May 9 15:45:19 2020","ip":"127.0.0.1","next boot":"EST Mon Oct 6 01:45:19 2031","architecture":"Linux","os build":"unix","oob port":4006,"native version":"3.9",]),}),"STiNKBoMB":({-1,"84.197.184.69",4000,4002,4003,"GurbaLib v0.50","GurbaLib","DGD 1.6.2","LPMud","Mudlib Development","cc_StinkBomb@pyromasaur.com",(["auth":1,"who":1,"channel":1,"locate":1,"ftp":4001,"tell":1,]),([]),}),"RavensGate":({0,"67.40.209.155",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Restricted Access","",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"MoH":({-1,"178.79.173.99",3500,0,0,"MoH3.0","Merc","AFKMud I3 Driver 2.33","GodWars","Open","tijer@godwars.net",(["channel":1,"tell":1,"finger":1,"who":1,"locate":1,"emoteto":1,"ucache":1,"beep":1,]),(["url":"http://www.godwars.net","time":"Thu Aug 13 19:26:59 2020",]),}),"7thplane":({-1,"69.164.199.238",8888,0,0,"IMC2 Freedom CL-2.2-PlanarDiku","IMC2 Freedom CL-2.2-PlanarDiku","IMC2 client","n/a"," "," ",(["who":1,"channel":1,"tell":1,]),(["port":8888,"url":"http://7thplane.ath.cx/","versionid":"IMC2 Freedom CL-2.2-PlanarDiku","host":"7thplane.ath.cx","imc_version":2.000000,]),}),"Adaka":({-1,"85.3.174.248",5555,0,0,"CoffeeMud v5.9.6","CoffeeMud v5.9.6","CoffeeMud v5.9.6","CoffeeMud","Open to the public","",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Unnamed_CoffeeMUD#1065668316":({-1,"34.238.162.229",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"WWC":({0,"174.109.164.19",4000,0,0,"FRlib III","WWC","FluffOS v2.23","LP","mudlib development","wwc@potato.org",(["channel":1,"ftp":0,"tell":1,"nntp":0,"finger":1,"who":1,"locate":1,"http":0,]),0,}),"Unnamed_CoffeeMUD#1014238178":({0,"49.192.178.83",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Your MUD Name":({-1,"45.33.51.250",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","jordan.obrastoff@gmail.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Dragon`s Lair":({-1,"173.255.200.146",23,0,0,"CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud","Beta Testing","telquisjones@yahoo.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"EotL-Red":({-1,"163.172.210.70",2010,4247,4246,"LPMud EotL 2019","LPMud EotL 2019","LDMud 3.2.14","LPMud","mudlib development","none",(["who":1,"channel":1,"tell":1,]),([]),}),"THOTconMUD":({-1,"64.227.62.127",4000,4002,4003,"GurbaLib v0.50","GurbaLib","DGD 1.6.11","LPMud","Mudlib Development","nyxgeek@gmail.com",(["auth":1,"who":1,"channel":1,"locate":1,"ftp":4001,"tell":1,]),([]),}),"Northlands":({-1,"178.79.160.71",5555,0,0,"CoffeeMud v5.9.9.1","CoffeeMud v5.9.9.1","CoffeeMud v5.9.9.1","CoffeeMud","Beta Testing","loghoover@gmail.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"SpesMUD":({-1,"45.79.100.63",5555,0,0,"CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud","Restricted Access","ampboox@gmail.com",(["finger":1,"who":1,"auth":1,"channel":1,"locate":1,"tell":1,]),([]),}),"QS":({0,"174.114.46.52",2525,2531,2533,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03","LPMud","mudlib development","qs@erroraccessdenied.com",(["channel":1,"mail":1,"ftp":2524,"tell":1,"finger":1,"who":1,"auth":1,"oob":2531,"locate":1,"ucache":1,"emoteto":1,"http":2526,"beep":1,]),(["upsince":"Sat Sep 5 22:07:19 2020","ip":"127.0.0.1","url":"","next boot":"EST Mon Feb 2 07:07:19 2032","architecture":"Linux","os build":"unix","oob port":2531,"native version":"3.9",]),}),]),]) +ChannelList (["ID":94,"List":(["4Liberty":({"4liberty",0,}),"ea":({"Blackened Ages",0,}),"skylib":({"Divided Sky",2,}),"newbie":({"Dragon War",0,}),"ROME_CHAT":({"Rome",0,}),"imud_imud_sgz":({"ThreeKingdomChina",0,}),"mlp":({"Ulario",0,}),"ichat":({"Dead Souls Dev",0,}),"foo":({"Ulario",0,}),"4l":({"4Liberty",0,}),"spyro":({"Ulario",0,}),"日本語":({"WileyMUD",0,}),"3d-space":({"TrekVerse",0,}),"code":({"TMI-2f",0,}),"nschat":({"Elanathia",0,}),"smblah":({"ShadowMUDii Dev",0,}),"lima":({"Dragonfire",0,}),"Days_of_Dragons":({"4liberty",0,}),"imud":({"Posotronic Dreams",0,}),"talkie":({"4Liberty",0,}),"CoffeeMud":({"RobertMUD",0,}),"mychannel6":({"shadowmuddevdev",0,}),"pray":({"FusuMOO",0,}),"ROMECHAT":({"Rome",0,}),"battlenet":({"Dragonfire",0,}),"mychannel4":({"shadowmuddevdev",0,}),"mychannel3":({"shadowmuddevdev",0,}),"mychannel2":({"shadowmuddevdev",0,}),"mudnews":({"Rock the Halo",0,}),"game":({"Pyloros",0,}),"serenity":({"Firefly Mud",0,}),"havenlib":({"Haven",0,}),"wizard":({"Iain's Test",0,}),"bestiality 2":({"Ulario",0,}),"felixfelicis":({"CoffeeMudESP",0,}),"imud_sgz":({"ThreeKingdomChina",0,}),"otg":({"Bloodlines",0,}),"diku":({"Realm of Shadows",0,}),"godwars":({"War_of_Legend",0,}),"mychannel":({"shadowmuddevdev",0,}),"ADR":({"Aadarian_Realms",0,}),"diskworld-cre":({"6d-esp",0,}),"foobar":({"Ulario",0,}),"coffeemudesp":({"FelixFelicis",0,}),"ascii_video":({"Ulario",0,}),"ascii_art":({"Dead Souls",0,}),"corinium":({"Corinium",0,}),"crat is crazy":({"Ulario",0,}),"bsg2":({"Dead Souls Dev",0,}),"pkiller":({"Dragonfire",0,}),"pants":({"TimMUD",0,}),"church":({"Chaos Realm",0,}),"3dspace":({"TrekVerse",0,}),"furry":({"Ulario",0,}),"6d_ToF":({"6d: Twist of Fate",0,}),"CoffeeMudESP":({"FelixFelicis",0,}),"blah":({"shadowmuddevdev",0,}),"imud_gossip":({"Frontiers",0,}),"url":({"Bloodlines",0,}),"crat":({"Ulario",0,}),"elephant_link":({"Elephant",1,}),"discworld_chat":({"Anarres II",0,}),"discworld-cre":({"Discworld",0,}),"CoffeeMud_Universe":({"Unnamed_CoffeeMUD#1609673558",0,}),"inews":({"Rock the Halo",0,}),"bot":({"WileyMUD",0,}),"free_speech":({"Frontiers",0,}),"wolchat":({"War of Legend",0,}),"dead_test4":({"Frontiers",0,}),"avalar":({"Ulario",0,}),"xblah":({"shadowmuddevdev",0,}),"dragon":({"Dragonfire",0,}),"german":({"OuterSpace",0,}),"ifree":({"Dead Souls Dev",0,}),"rp-pve":({"Dragonfire",0,}),"another_channel":({"shadowmuddevdev",0,}),"bd_dev":({"BrokenDreamsDev",0,}),"igossip":({"AndroDSWin",0,}),"firefly":({"Firefly Devmud",1,}),"discworld-chat":({"Discworld",0,}),"yblah":({"rtc",0,}),"roleplaying":({"Dragonfire",0,}),"narrator":({"Galaxy",0,}),"I3testers2":({"The Zone",0,}),"DaysofDragons":({"Days of Dragons",0,}),"sport":({"Rock the Halo",0,}),"trivia_games":({"Emerald MUD",0,}),"Arch":({"Testmud",0,}),"TestMud":({"CoffeeMudESP",0,}),"coffemud":({"classic 6dragons general-hosting version",0,}),"coffeemud_universe":({"CoffeeMud Dev",0,}),"pvp":({"Dragonfire",0,}),"cleric":({"Dead_Souls_ihsahn",0,}),"zblah":({"shadowmuddevdev",0,}),"wolimm":({"War of Legend",0,}),"gw_imm":({"War_of_Legend",0,}),"ad":({"Ulario",0,}),"gwimm":({"Amaranth",0,}),"ravenloft":({"Legend of Ravenloft",0,}),"nakki":({"Dead_Souls_koopa",0,}),"dreamverse_gossip":({"Dreamverse",0,}),"lpuni":({"Frontiers",0,}),"bofh":({"Anarres II",0,}),"french":({"Dead Souls",0,}),"vore":({"Ulario",0,}),"test":({"OuterSpace",0,}),"avatar":({"Second Nightmare",0,}),"I3testers":({"The Zone",0,}),"mystic_dev":({"Mystic",1,}),"wonder":({"md20",0,}),"coffeemud_university":({"Unnamed_CoffeeMUD#1851705742",0,}),"bestiality":({"Ulario",0,}),"Discworld":({"GuardianMUD",0,}),"troll":({"Final Stand",0,}),"dchat":({"Frontiers",0,}),"kotaka":({"Ulario",0,}),"imud_code":({"Frontiers",0,}),"pyom":({"Bloodlines",0,}),"plea":({"FusuMOO",0,}),"JammsTest":({"Jamms-Dev",0,}),"dod":({"Days of Dragons",0,}),"insomnia-chat":({"Insomnia",0,}),"generalchat":({"Realm of Shadows",0,}),"6d":({"4liberty",0,}),"1":({"Testmud",0,}),"dutch":({"OuterSpace",0,}),"intergossip":({"Dead_Souls_stoli",0,}),"bd_devtalk":({"BrokenDreamsDev",0,}),"gossip_nopolitcs":({"Realm of Shadows",0,}),"animechat":({"Bleached InuYasha Galaxy",0,}),"foobar 2":({"Ulario",0,}),"foofoo":({"Ulario",0,}),"CrossMUD":({"BIYG_dev",1,}),"nscre":({"Elanathia",0,}),"dreamverse-gossip":({"Dreamverse",0,}),"yiff":({"Ulario",0,}),"mage":({"Second Nightmare",0,}),"fluffos":({"Dead Souls",0,}),"lords&legends":({"Days of Dragons",0,}),"bsg":({"Dead Souls",0,}),"wileymud":({"WileyMUD",0,}),"coffeemud":({"walkran",0,}),"Iberia Mud":({"CoffeeMudESP",0,}),"minecraft":({"Bloodlines",0,}),"discord":({"WileyMUD",0,}),"vest":({"4Liberty",0,}),"icoff":({"OASIS MUD",0,}),"dgd":({"Way of the Force",0,}),"tinyurl":({"TimMUD",0,}),"dead_souls":({"Frontiers",0,}),"ooc":({"Rhykil Beta",0,}),"asdfasdf":({"Ulario",0,}),"FelixFelicis":({"CoffeeMudESP",0,}),"monk":({"Second Nightmare",0,}),"jengatest":({"JengaMUD",0,}),"intercre":({"Ulario",0,}),"":({"Ulario",0,}),]),]) +Banned ([]) +Nameservers ({({"*dalet","97.107.133.86 8787",}),}) diff --git a/lib/save/kills/b/babylon b/lib/save/kills/b/babylon new file mode 100644 index 0000000..024e3fb --- /dev/null +++ b/lib/save/kills/b/babylon @@ -0,0 +1 @@ +(["Captain John Galt":1,"voluntaryist volunteer handler":2,"an ooga booga":8,"wonkasaur":1,"a generic npc":11,"a fighter":2,]) \ No newline at end of file diff --git a/lib/save/kills/d/deskarnull b/lib/save/kills/d/deskarnull new file mode 100644 index 0000000..3c760ae --- /dev/null +++ b/lib/save/kills/d/deskarnull @@ -0,0 +1 @@ +(["a rat":2,]) \ No newline at end of file diff --git a/lib/save/kills/o/one b/lib/save/kills/o/one new file mode 100644 index 0000000..de0f8ba --- /dev/null +++ b/lib/save/kills/o/one @@ -0,0 +1 @@ +(["a mean-looking troll":1,"a thief in a bathtowel":1,"the boss orc":1,"a rat":1,"a dirty orc":5,"the orc shaman":1,]) \ No newline at end of file diff --git a/lib/save/map.o b/lib/save/map.o new file mode 100644 index 0000000..f8675f6 --- /dev/null +++ b/lib/save/map.o @@ -0,0 +1,5 @@ +#/daemon/map.c +PersistentInventory 0 +PersistentInventoryEnabled 0 +MapMap (["7001,7003,6999":(["name":0,]),"1000,-997,0":(["name":0,]),"2002,1998,0":(["name":0,]),"-3004,-2998,-3000":(["name":0,]),"1003,999,1":(["name":0,]),"4003,4000,0":(["name":0,]),"6996,7002,7001":(["name":0,]),"6996,7002,7000":(["name":0,]),"7002,7001,7001":(["name":0,]),"7002,7001,7000":(["name":"/domains/oogtopia/room/bushesne",]),"-1,-1,0":(["name":0,]),"7000,7002,6999":(["name":0,]),"4005,4002,-1":(["name":0,]),"-3000,-3003,-3000":(["name":0,]),"4996,5004,0":(["name":0,]),"3,2,0":(["name":0,]),"-3000,-2997,-3000":(["name":0,]),"7005,6999,7000":(["name":0,]),"6995,7001,7001":(["name":0,]),"6995,7001,7000":(["name":0,]),"7001,7000,7001":(["name":0,]),"3999,4002,-2":(["name":0,]),"2003,2003,0":(["name":0,]),"3999,4002,-1":(["name":0,]),"7001,7000,7000":(["name":"/domains/oogtopia/room/start",]),"4996,5001,0":(["name":0,]),"6998,6999,7000":(["name":0,]),"3996,4004,0":(["name":0,]),"7004,6998,7000":(["name":0,]),"5003,4997,0":(["name":0,]),"2003,2000,0":(["name":0,]),"1003,1003,1":(["name":0,]),"7003,7009,7001":(["name":0,]),"7003,7009,7000":(["name":0,]),"3996,4001,0":(["name":0,]),"6997,6998,7000":(["name":0,]),"7003,6997,7000":(["name":0,]),"-3003,-3001,-3000":(["name":0,]),"4003,3997,0":(["name":0,]),"1003,1000,1":(["name":0,]),"998,999,1":(["name":0,]),"-2997,-2998,-3000":(["name":0,]),"0,4,0":(["name":0,]),"1002,-1001,0":(["name":0,]),"6996,7009,7001":(["name":0,]),"6996,7009,7000":(["name":0,]),"7002,7008,7001":(["name":0,]),"7002,7008,7000":(["name":0,]),"998,-999,0":(["name":0,]),"-2,3,0":(["name":0,]),"4000,3999,-2":(["name":0,]),"4000,3999,-1":(["name":0,]),"6996,6997,7000":(["name":0,]),"7000,7009,6999":(["name":0,]),"1996,2004,0":(["name":0,]),"7002,6996,7000":(["name":0,]),"0,1,0":(["name":0,]),"1001,-999,0":(["name":0,]),"6995,7008,7001":(["name":0,]),"998,-996,0":(["name":0,]),"-2,0,0":(["name":0,]),"6999,7005,6999":(["name":0,]),"4996,4998,0":(["name":0,]),"7001,7007,7001":(["name":0,]),"7001,7007,7000":(["name":0,]),"1996,2001,0":(["name":0,]),"1001,-996,0":(["name":0,]),"2003,1997,0":(["name":0,]),"4000,4001,-2":(["name":0,]),"4000,4001,-1":(["name":0,]),"996,1003,1":(["name":0,]),"6998,7004,6999":(["name":0,]),"3996,3998,0":(["name":0,]),"7000,7006,7001":(["name":0,]),"4005,4004,-1":(["name":0,]),"7000,7006,7000":(["name":0,]),"4002,3998,-2":(["name":0,]),"4002,3998,-1":(["name":0,]),"999,-1003,0":(["name":0,]),"996,1000,1":(["name":0,]),"3,-2,0":(["name":0,]),"6999,7002,7001":(["name":0,]),"6999,7002,7000":(["name":0,]),"4997,5003,0":(["name":0,]),"3999,4004,-2":(["name":0,]),"3999,4004,-1":(["name":0,]),"7005,7001,7000":(["name":0,]),"3996,3998,-2":(["name":0,]),"6997,7003,6999":(["name":0,]),"7003,7002,6999":(["name":0,]),"1001,-1003,0":(["name":0,]),"999,-1000,0":(["name":0,]),"4997,5000,0":(["name":0,]),"4002,4000,-2":(["name":0,]),"6998,7001,7001":(["name":0,]),"4002,4000,-1":(["name":0,]),"3997,4003,0":(["name":0,]),"6998,7001,7000":(["name":0,]),"7004,7000,7000":(["name":0,]),"-3002,-3003,-3000":(["name":0,]),"6996,7002,6999":(["name":0,]),"1001,-1000,0":(["name":0,]),"1996,1998,0":(["name":0,]),"5000,5002,0":(["name":0,]),"4004,3997,-1":(["name":0,]),"-3002,-2997,-3000":(["name":0,]),"3996,4000,-2":(["name":0,]),"3997,4000,0":(["name":0,]),"6997,7000,7001":(["name":0,]),"6997,7000,7000":(["name":0,]),"3998,3997,-2":(["name":0,]),"4000,4002,0":(["name":0,]),"999,-998,0":(["name":0,]),"1997,2003,0":(["name":0,]),"6999,7009,7001":(["name":0,]),"2,-1,0":(["name":0,]),"6999,7009,7000":(["name":0,]),"1002,-998,0":(["name":0,]),"6999,6997,7000":(["name":0,]),"-2999,-2998,-3000":(["name":0,]),"7003,7009,6999":(["name":0,]),"4997,4997,0":(["name":0,]),"7005,6996,7000":(["name":0,]),"1997,2000,0":(["name":0,]),"997,1005,1":(["name":0,]),"998,-1002,0":(["name":0,]),"4000,4003,-2":(["name":0,]),"4000,4003,-1":(["name":0,]),"5000,4999,0":(["name":0,]),"6998,7008,7001":(["name":0,]),"2000,2002,0":(["name":0,]),"6998,7008,7000":(["name":0,]),"7004,7007,7001":(["name":0,]),"-3001,-3000,-3000":(["name":0,]),"1000,1005,1":(["name":0,]),"1,3,0":(["name":0,]),"6996,7009,6999":(["name":0,]),"1000,-1002,0":(["name":0,]),"997,1002,1":(["name":0,]),"6998,6996,7000":(["name":0,]),"7002,7008,6999":(["name":0,]),"3997,3997,0":(["name":0,]),"-3,2,0":(["name":0,]),"4000,3999,0":(["name":0,]),"1000,1002,1":(["name":0,]),"1,0,0":(["name":0,]),"6997,7007,7001":(["name":0,]),"6997,7007,7000":(["name":0,]),"7003,7006,7001":(["name":0,]),"7003,7006,7000":(["name":0,]),"4998,5002,0":(["name":0,]),"7001,7007,6999":(["name":0,]),"1,-3,0":(["name":0,]),"5001,5004,0":(["name":0,]),"-3001,-2999,-3000":(["name":0,]),"4002,4002,-2":(["name":0,]),"4002,4002,-1":(["name":0,]),"6996,7006,7001":(["name":0,]),"6996,7006,7000":(["name":0,]),"7002,7005,7001":(["name":0,]),"4004,3999,-1":(["name":0,]),"7002,7005,7000":(["name":0,]),"3998,4002,0":(["name":0,]),"-2998,-3001,-3000":(["name":0,]),"7000,7006,6999":(["name":0,]),"1997,1997,0":(["name":0,]),"5001,5001,0":(["name":0,]),"3996,4002,-2":(["name":0,]),"4001,4004,0":(["name":0,]),"2000,1999,0":(["name":0,]),"999,998,1":(["name":0,]),"3998,3999,-2":(["name":0,]),"6995,7005,7001":(["name":0,]),"6995,7005,7000":(["name":0,]),"6999,7002,6999":(["name":0,]),"7001,7004,7001":(["name":"/domains/voluntaria/room/quarters",]),"7001,7004,7000":(["name":0,]),"4001,4001,0":(["name":0,]),"4004,4001,-1":(["name":0,]),"-3004,-3003,-3000":(["name":0,]),"997,-1001,0":(["name":0,]),"-3004,-2997,-3000":(["name":0,]),"1002,999,1":(["name":0,]),"4998,4999,0":(["name":0,]),"4006,3998,-1":(["name":0,]),"7000,7003,7001":(["name":"/domains/voluntaria/room/commandexit",]),"7000,7003,7000":(["name":"/domains/voluntaria/room/hallway",]),"1998,2002,0":(["name":0,]),"3998,4001,-2":(["name":0,]),"1003,-997,0":(["name":0,]),"-3000,-3002,-3000":(["name":0,]),"2001,2004,0":(["name":0,]),"-4,-3,0":(["name":0,]),"-3000,-2996,-3000":(["name":0,]),"0,-2,0":(["name":0,]),"998,1004,1":(["name":0,]),"3998,3999,0":(["name":0,]),"5001,4998,0":(["name":0,]),"2001,2001,0":(["name":0,]),"4006,4000,-1":(["name":0,]),"1001,1004,1":(["name":0,]),"998,1001,1":(["name":0,]),"4999,5004,0":(["name":0,]),"4001,3998,0":(["name":0,]),"6999,7009,6999":(["name":0,]),"1001,1001,1":(["name":0,]),"4999,5001,0":(["name":0,]),"4002,4004,-2":(["name":0,]),"4002,4004,-1":(["name":0,]),"7001,6999,7000":(["name":"/domains/oogtopia/room/bushess",]),"-3003,-3000,-3000":(["name":0,]),"-2997,-3003,-3000":(["name":0,]),"3999,4004,0":(["name":0,]),"997,999,1":(["name":0,]),"-2997,-2997,-3000":(["name":0,]),"1998,1999,0":(["name":0,]),"5002,5003,0":(["name":0,]),"996,-1003,0":(["name":0,]),"-4,4,0":(["name":0,]),"6998,7008,6999":(["name":0,]),"3996,4004,-2":(["name":0,]),"2,2,0":(["name":0,]),"3999,4001,0":(["name":0,]),"7000,6998,7000":(["name":0,]),"996,-997,0":(["name":0,]),"5002,5000,0":(["name":0,]),"-3,-2,0":(["name":0,]),"996,-1000,0":(["name":0,]),"-4,1,0":(["name":0,]),"6999,7006,7001":(["name":0,]),"4002,4003,0":(["name":0,]),"6999,7006,7000":(["name":0,]),"7005,7005,7000":(["name":0,]),"2001,1998,0":(["name":0,]),"6997,7007,6999":(["name":0,]),"-3003,-2999,-3000":(["name":0,]),"7003,7006,6999":(["name":0,]),"4004,4003,-1":(["name":0,]),"4001,3997,-2":(["name":0,]),"4001,3997,-1":(["name":0,]),"1999,2004,0":(["name":0,]),"4002,4000,0":(["name":0,]),"6998,7005,7001":(["name":0,]),"6998,7005,7000":(["name":0,]),"7004,7004,7001":(["name":0,]),"7004,7004,7000":(["name":0,]),"6996,7006,6999":(["name":0,]),"3998,4003,-2":(["name":0,]),"7002,7005,6999":(["name":0,]),"4999,4998,0":(["name":0,]),"3995,3997,-2":(["name":0,]),"1999,2001,0":(["name":0,]),"6997,7004,7001":(["name":0,]),"6997,7004,7000":(["name":0,]),"2002,2003,0":(["name":0,]),"7003,7003,7001":(["name":0,]),"7003,7003,7000":(["name":0,]),"-1,3,0":(["name":0,]),"7001,7004,6999":(["name":0,]),"999,1003,1":(["name":0,]),"3999,3998,0":(["name":0,]),"4006,4002,-1":(["name":0,]),"5002,4997,0":(["name":0,]),"2002,2000,0":(["name":0,]),"1002,1003,1":(["name":0,]),"6996,7003,7001":(["name":0,]),"6996,7003,7000":(["name":0,]),"-1,0,0":(["name":0,]),"7002,7002,7001":(["name":0,]),"7002,7002,7000":(["name":0,]),"999,1000,1":(["name":0,]),"-2,-1,0":(["name":0,]),"-3002,-3002,-3000":(["name":0,]),"7000,7003,6999":(["name":0,]),"-3002,-2996,-3000":(["name":0,]),"4002,3997,0":(["name":0,]),"1002,1000,1":(["name":0,]),"6995,7002,7001":(["name":0,]),"6995,7002,7000":(["name":0,]),"7001,7001,7001":(["name":0,]),"7001,7001,7000":(["name":"/domains/oogtopia/room/bushesn",]),"997,-999,0":(["name":0,]),"5003,5002,0":(["name":0,]),"1999,1998,0":(["name":0,]),"7004,6999,7000":(["name":0,]),"1000,-999,0":(["name":0,]),"7000,7000,7001":(["name":0,]),"997,-996,0":(["name":0,]),"7000,7000,7000":(["name":"/domains/oogtopia/room/bushesw",]),"1003,-1001,0":(["name":0,]),"4003,4002,0":(["name":0,]),"-2999,-3003,-3000":(["name":0,]),"6997,6999,7000":(["name":0,]),"2002,1997,0":(["name":0,]),"1000,-996,0":(["name":0,]),"-2999,-2997,-3000":(["name":0,]),"-1,-3,0":(["name":0,]),"4001,3999,-2":(["name":0,]),"4001,3999,-1":(["name":0,]),"7003,6998,7000":(["name":0,]),"1003,998,1":(["name":0,]),"3,4,0":(["name":0,]),"7002,7009,7001":(["name":0,]),"7002,7009,7000":(["name":0,]),"3995,3999,-2":(["name":0,]),"6996,6998,7000":(["name":0,]),"7002,6997,7000":(["name":0,]),"4996,5003,0":(["name":0,]),"3,1,0":(["name":0,]),"4001,4001,-2":(["name":0,]),"4001,4001,-1":(["name":0,]),"5003,4999,0":(["name":0,]),"7001,7008,7001":(["name":0,]),"6999,7006,6999":(["name":0,]),"7001,7008,7000":(["name":0,]),"2003,2002,0":(["name":0,]),"4006,4004,-1":(["name":0,]),"1003,1005,1":(["name":0,]),"4003,3998,-1":(["name":0,]),"4996,5000,0":(["name":0,]),"7001,6996,7000":(["name":0,]),"3996,4003,0":(["name":0,]),"-3001,-2998,-3000":(["name":0,]),"3995,4001,-2":(["name":0,]),"6998,7005,6999":(["name":0,]),"4003,3999,0":(["name":0,]),"7000,7007,7001":(["name":0,]),"1003,1002,1":(["name":0,]),"3997,3998,-2":(["name":0,]),"7000,7007,7000":(["name":0,]),"-2998,-3000,-3000":(["name":0,]),"1002,-1003,0":(["name":0,]),"3996,4000,0":(["name":0,]),"6999,7003,7001":(["name":0,]),"6999,7003,7000":(["name":"/domains/voluntaria/room/crewpod",]),"4003,4000,-1":(["name":"/domains/campus/room/tunnel",]),"998,998,1":(["name":0,]),"7005,7002,7000":(["name":0,]),"6997,7004,6999":(["name":0,]),"0,3,0":(["name":0,]),"7003,7003,6999":(["name":0,]),"1002,-1000,0":(["name":0,]),"4005,3997,-1":(["name":0,]),"998,-998,0":(["name":0,]),"-2,2,0":(["name":0,]),"3997,4000,-2":(["name":0,]),"1996,2003,0":(["name":0,]),"-3004,-3002,-3000":(["name":0,]),"6998,7002,7001":(["name":0,]),"6998,7002,7000":(["name":0,]),"0,0,0":(["name":0,]),"7004,7001,7001":(["name":0,]),"-3004,-2996,-3000":(["name":0,]),"-2998,-2999,-3000":(["name":0,]),"7004,7001,7000":(["name":0,]),"1001,999,1":(["name":0,]),"6996,7003,6999":(["name":0,]),"2003,1999,0":(["name":0,]),"1001,-998,0":(["name":0,]),"3999,3997,-2":(["name":0,]),"3999,3997,-1":(["name":0,]),"7002,7002,6999":(["name":0,]),"4996,4997,0":(["name":0,]),"1996,2000,0":(["name":0,]),"996,1005,1":(["name":0,]),"-3000,-3001,-3000":(["name":0,]),"6997,7001,7001":(["name":0,]),"6997,7001,7000":(["name":0,]),"7003,7000,7001":(["name":0,]),"7003,7000,7000":(["name":0,]),"996,1002,1":(["name":0,]),"3996,3997,0":(["name":0,]),"6996,7000,7001":(["name":0,]),"6996,7000,7000":(["name":0,]),"999,-1002,0":(["name":0,]),"4001,4003,-2":(["name":0,]),"4001,4003,-1":(["name":0,]),"3,-1,0":(["name":0,]),"4997,5002,0":(["name":0,]),"6999,6998,7000":(["name":0,]),"5000,5004,0":(["name":0,]),"1001,-1002,0":(["name":0,]),"7005,6997,7000":(["name":0,]),"3995,4003,-2":(["name":0,]),"-2997,-3002,-3000":(["name":0,]),"996,999,1":(["name":0,]),"6998,7009,7001":(["name":0,]),"-2997,-2996,-3000":(["name":0,]),"6998,7009,7000":(["name":0,]),"7004,7008,7001":(["name":0,]),"3997,4002,0":(["name":0,]),"5000,5001,0":(["name":0,]),"1996,1997,0":(["name":0,]),"6998,6997,7000":(["name":0,]),"7002,7009,6999":(["name":0,]),"4000,4004,0":(["name":0,]),"7004,6996,7000":(["name":0,]),"4003,4002,-1":(["name":0,]),"6997,7008,7001":(["name":0,]),"6997,7008,7000":(["name":0,]),"7003,7007,7001":(["name":0,]),"7003,7007,7000":(["name":0,]),"4005,3999,-1":(["name":0,]),"4000,4001,0":(["name":0,]),"-3003,-2998,-3000":(["name":0,]),"6997,6996,7000":(["name":0,]),"7001,7008,6999":(["name":0,]),"2,-3,0":(["name":0,]),"3997,4002,-2":(["name":0,]),"999,-997,0":(["name":0,]),"4997,4999,0":(["name":0,]),"6996,7007,7001":(["name":0,]),"3999,3999,-2":(["name":0,]),"6996,7007,7000":(["name":0,]),"3999,3999,-1":(["name":0,]),"1997,2002,0":(["name":0,]),"7002,7006,7001":(["name":0,]),"7002,7006,7000":(["name":0,]),"7000,7007,6999":(["name":0,]),"1002,-997,0":(["name":0,]),"2000,2004,0":(["name":0,]),"4005,4001,-1":(["name":0,]),"997,1004,1":(["name":0,]),"6995,7006,7001":(["name":0,]),"3997,3999,0":(["name":0,]),"998,-1001,0":(["name":0,]),"6995,7006,7000":(["name":0,]),"6999,7003,6999":(["name":0,]),"-3,4,0":(["name":0,]),"7001,7005,7001":(["name":0,]),"5000,4998,0":(["name":0,]),"7001,7005,7000":(["name":0,]),"2000,2001,0":(["name":0,]),"1000,1004,1":(["name":0,]),"1,2,0":(["name":0,]),"3999,4001,-2":(["name":0,]),"3999,4001,-1":(["name":0,]),"1000,-1001,0":(["name":0,]),"997,1001,1":(["name":0,]),"4998,5004,0":(["name":0,]),"-3,1,0":(["name":0,]),"6998,7002,6999":(["name":0,]),"7000,7004,7001":(["name":"/domains/voluntaria/room/commandhall",]),"7000,7004,7000":(["name":"/domains/voluntaria/room/hallway2",]),"4000,3998,0":(["name":0,]),"1000,1001,1":(["name":"/domains/Ylsrim/room/tower",]),"-3002,-3001,-3000":(["name":0,]),"4998,5001,0":(["name":0,]),"3998,4004,0":(["name":0,]),"6999,7000,7001":(["name":0,]),"1,-2,0":(["name":0,]),"6999,7000,7000":(["name":0,]),"5001,5003,0":(["name":0,]),"1997,1999,0":(["name":0,]),"3998,4001,0":(["name":0,]),"5001,5000,0":(["name":0,]),"4003,4004,-1":(["name":0,]),"4000,3998,-2":(["name":0,]),"4001,4003,0":(["name":0,]),"4000,3998,-1":(["name":0,]),"2000,1998,0":(["name":0,]),"997,-1003,0":(["name":0,]),"-2999,-3002,-3000":(["name":0,]),"3997,4004,-2":(["name":0,]),"-2999,-2996,-3000":(["name":0,]),"4001,4000,0":(["name":0,]),"1998,2004,0":(["name":0,]),"1003,-999,0":(["name":0,]),"997,-1000,0":(["name":0,]),"1002,998,1":(["name":0,]),"6998,7009,6999":(["name":0,]),"4998,4998,0":(["name":0,]),"4000,4000,-2":(["name":0,]),"4000,4000,-1":(["name":0,]),"1998,2001,0":(["name":0,]),"7000,6999,7000":(["name":"/domains/oogtopia/room/bushessw",]),"4005,4003,-1":(["name":0,]),"4002,3997,-2":(["name":0,]),"1003,-996,0":(["name":0,]),"-4,-2,0":(["name":0,]),"4002,3997,-1":(["name":0,]),"2001,2003,0":(["name":0,]),"6999,7007,7001":(["name":0,]),"6999,7007,7000":(["name":0,]),"0,-1,0":(["name":0,]),"6997,7008,6999":(["name":0,]),"998,1003,1":(["name":0,]),"3998,3998,0":(["name":0,]),"7003,7007,6999":(["name":0,]),"3999,4003,-2":(["name":0,]),"5001,4997,0":(["name":0,]),"3999,4003,-1":(["name":0,]),"3996,3997,-2":(["name":0,]),"2001,2000,0":(["name":0,]),"-3001,-3003,-3000":(["name":0,]),"1001,1003,1":(["name":0,]),"6998,7006,7001":(["name":0,]),"-3001,-2997,-3000":(["name":0,]),"6998,7006,7000":(["name":0,]),"998,1000,1":(["name":0,]),"7004,7005,7001":(["name":0,]),"4999,5003,0":(["name":0,]),"7004,7005,7000":(["name":0,]),"6996,7007,6999":(["name":0,]),"7002,7006,6999":(["name":0,]),"4001,3997,0":(["name":0,]),"1001,1000,1":(["name":0,]),"4999,5000,0":(["name":0,]),"6997,7005,7001":(["name":0,]),"6997,7005,7000":(["name":0,]),"2,4,0":(["name":0,]),"7003,7004,7001":(["name":0,]),"3999,4003,0":(["name":0,]),"997,998,1":(["name":0,]),"7003,7004,7000":(["name":0,]),"996,-999,0":(["name":0,]),"5002,5002,0":(["name":0,]),"1998,1998,0":(["name":0,]),"7001,7005,6999":(["name":0,]),"-4,3,0":(["name":0,]),"996,-1002,0":(["name":0,]),"2,1,0":(["name":0,]),"3999,4000,0":(["name":0,]),"6996,7004,7001":(["name":0,]),"-3004,-3001,-3000":(["name":0,]),"996,-996,0":(["name":0,]),"6996,7004,7000":(["name":0,]),"7002,7003,7001":(["name":0,]),"-3,-1,0":(["name":0,]),"-2998,-2998,-3000":(["name":0,]),"7002,7003,7000":(["name":0,]),"-4,0,0":(["name":0,]),"1000,999,1":(["name":0,]),"4002,4002,0":(["name":0,]),"7000,7004,6999":(["name":0,]),"2001,1997,0":(["name":0,]),"-3000,-3000,-3000":(["name":"/domains/examples/room/start",]),"6995,7003,7001":(["name":0,]),"6995,7003,7000":(["name":0,]),"7001,7002,7001":(["name":0,]),"1999,2003,0":(["name":0,]),"7001,7002,7000":(["name":0,]),"4000,4002,-2":(["name":0,]),"4000,4002,-1":(["name":0,]),"4999,4997,0":(["name":0,]),"4002,3999,-2":(["name":0,]),"999,1005,1":(["name":0,]),"4002,3999,-1":(["name":0,]),"1999,2000,0":(["name":0,]),"7000,7001,7001":(["name":0,]),"5002,4999,0":(["name":0,]),"7000,7001,7000":(["name":"/domains/oogtopia/room/field",]),"2002,2002,0":(["name":0,]),"1002,1005,1":(["name":0,]),"-3000,-2999,-3000":(["name":0,]),"3996,3999,-2":(["name":0,]),"-1,2,0":(["name":0,]),"-2,-3,0":(["name":0,]),"999,1002,1":(["name":0,]),"3999,3997,0":(["name":0,]),"7003,6999,7000":(["name":0,]),"-2997,-3001,-3000":(["name":0,]),"4002,3999,0":(["name":0,]),"1002,1002,1":(["name":0,]),"4002,4001,-2":(["name":0,]),"4002,4001,-1":(["name":0,]),"6996,6999,7000":(["name":0,]),"7002,6998,7000":(["name":0,]),"4004,3998,-1":(["name":0,]),"5003,5004,0":(["name":0,]),"3996,4001,-2":(["name":0,]),"6999,7007,6999":(["name":0,]),"7001,7009,7001":(["name":0,]),"7001,7009,7000":(["name":0,]),"-3003,-3003,-3000":(["name":0,]),"3998,3998,-2":(["name":0,]),"997,-998,0":(["name":0,]),"-3003,-2997,-3000":(["name":0,]),"7001,6997,7000":(["name":0,]),"5003,5001,0":(["name":0,]),"1999,1997,0":(["name":0,]),"1003,-1003,0":(["name":0,]),"4003,4004,0":(["name":0,]),"2002,1999,0":(["name":0,]),"1000,-998,0":(["name":0,]),"6998,7006,6999":(["name":0,]),"7000,7008,7001":(["name":0,]),"4004,4000,-1":(["name":0,]),"7000,7008,7000":(["name":0,]),"1003,-1000,0":(["name":0,]),"7000,6996,7000":(["name":0,]),"4003,4001,0":(["name":0,]),"4006,3997,-1":(["name":0,]),"-1,-2,0":(["name":0,]),"6999,7004,7001":(["name":"/domains/voluntaria/room/bridge",]),"3998,4000,-2":(["name":0,]),"6999,7004,7000":(["name":0,]),"7005,7003,7000":(["name":0,]),"6997,7005,6999":(["name":0,]),"4000,4004,-2":(["name":0,]),"7003,7004,6999":(["name":0,]),"3,3,0":(["name":0,]),"4000,4004,-1":(["name":0,]),"2003,2004,0":(["name":0,]),"6998,7003,7001":(["name":0,]),"6998,7003,7000":(["name":0,]),"7004,7002,7001":(["name":0,]),"3,0,0":(["name":0,]),"7004,7002,7000":(["name":0,]),"4996,5002,0":(["name":0,]),"6996,7004,6999":(["name":0,]),"7002,7003,6999":(["name":0,]),"-3002,-3000,-3000":(["name":0,]),"5003,4998,0":(["name":0,]),"2003,2001,0":(["name":0,]),"1003,1004,1":(["name":0,]),"6997,7002,7001":(["name":0,]),"6997,7002,7000":(["name":0,]),"7003,7001,7001":(["name":0,]),"7003,7001,7000":(["name":0,]),"3996,4002,0":(["name":0,]),"4002,4003,-2":(["name":0,]),"4002,4003,-1":(["name":0,]),"7001,7002,6999":(["name":0,]),"4003,3998,0":(["name":0,]),"1003,1001,1":(["name":0,]),"1002,-1002,0":(["name":0,]),"6996,7001,7001":(["name":0,]),"3996,4003,-2":(["name":0,]),"6996,7001,7000":(["name":0,]),"7002,7000,7001":(["name":0,]),"-3002,-2999,-3000":(["name":0,]),"-2,4,0":(["name":0,]),"7002,7000,7000":(["name":"/domains/oogtopia/room/bushese",]),"0,2,0":(["name":0,]),"6999,6999,7000":(["name":0,]),"7005,6998,7000":(["name":0,]),"-2999,-3001,-3000":(["name":0,]),"-2,1,0":(["name":0,]),"998,-997,0":(["name":0,]),"6995,7000,7000":(["name":0,]),"4996,4999,0":(["name":0,]),"1996,2002,0":(["name":0,]),"4004,4002,-1":(["name":0,]),"1001,998,1":(["name":0,]),"2003,1998,0":(["name":0,]),"1001,-997,0":(["name":0,]),"6998,6998,7000":(["name":0,]),"4006,3999,-1":(["name":0,]),"7004,6997,7000":(["name":0,]),"3998,4002,-2":(["name":0,]),"996,1004,1":(["name":0,]),"3996,3999,0":(["name":0,]),"6997,7009,7001":(["name":0,]),"6997,7009,7000":(["name":0,]),"7003,7008,7001":(["name":0,]),"7003,7008,7000":(["name":0,]),"7001,7009,6999":(["name":0,]),"6997,6997,7000":(["name":0,]),"7003,6996,7000":(["name":0,]),"3,-3,0":(["name":0,]),"996,1001,1":(["name":0,]),"4997,5004,0":(["name":0,]),"-3001,-3002,-3000":(["name":0,]),"6996,7008,7001":(["name":0,]),"4006,4001,-1":(["name":0,]),"6996,7008,7000":(["name":0,]),"-3001,-2996,-3000":(["name":0,]),"7002,7007,7001":(["name":0,]),"7002,7007,7000":(["name":0,]),"999,-1001,0":(["name":0,]),"7000,7008,6999":(["name":0,]),"6996,6996,7000":(["name":0,]),"4997,5001,0":(["name":0,]),"3997,4004,0":(["name":0,]),"1001,-1001,0":(["name":0,]),"1996,1999,0":(["name":0,]),"5000,5003,0":(["name":0,]),"6995,7007,7001":(["name":0,]),"6995,7007,7000":(["name":0,]),"6999,7004,6999":(["name":0,]),"7001,7006,7001":(["name":0,]),"7001,7006,7000":(["name":0,]),"996,998,1":(["name":0,]),"3997,4001,0":(["name":0,]),"5000,5000,0":(["name":"/domains/begin/room/start",]),"4000,4003,0":(["name":0,]),"-2998,-3003,-3000":(["name":0,]),"-3004,-3000,-3000":(["name":0,]),"6998,7003,6999":(["name":0,]),"7000,7005,7001":(["name":"/domains/voluntaria/room/topstair",]),"7000,7005,7000":(["name":"/domains/voluntaria/room/stairwell",]),"-2998,-2997,-3000":(["name":0,]),"999,-999,0":(["name":0,]),"4000,4000,0":(["name":"/domains/campus/room/start",]),"1997,2004,0":(["name":0,]),"6999,7001,7001":(["name":0,]),"2,-2,0":(["name":0,]),"6999,7001,7000":(["name":0,]),"1002,-999,0":(["name":0,]),"7005,7000,7000":(["name":0,]),"4004,4004,-1":(["name":0,]),"6997,7002,6999":(["name":0,]),"4001,3998,-2":(["name":0,]),"999,-996,0":(["name":0,]),"4001,3998,-1":(["name":0,]),"4997,4998,0":(["name":0,]),"1997,2001,0":(["name":0,]),"998,-1003,0":(["name":0,]),"-3004,-2999,-3000":(["name":0,]),"3998,4004,-2":(["name":0,]),"1002,-996,0":(["name":0,]),"6998,7000,7001":(["name":0,]),"2000,2003,0":(["name":0,]),"3995,3998,-2":(["name":0,]),"6998,7000,7000":(["name":0,]),"1,4,0":(["name":0,]),"997,1003,1":(["name":0,]),"1000,-1003,0":(["name":0,]),"3997,3998,0":(["name":0,]),"998,-1000,0":(["name":0,]),"-3,3,0":(["name":0,]),"5000,4997,0":(["name":0,]),"-3000,-2998,-3000":(["name":0,]),"4001,4000,-2":(["name":0,]),"2000,2000,0":(["name":"/domains/learning/room/start",]),"4001,4000,-1":(["name":0,]),"1,1,0":(["name":0,]),"1000,1003,1":(["name":0,]),"997,1000,1":(["name":0,]),"1000,-1000,0":(["name":"/domains/Praxis/square",]),"4006,4003,-1":(["name":0,]),"4998,5003,0":(["name":0,]),"4003,3997,-1":(["name":0,]),"-3,0,0":(["name":0,]),"-2997,-3000,-3000":(["name":0,]),"3995,4000,-2":(["name":0,]),"4000,3997,0":(["name":0,]),"1000,1000,1":(["name":0,]),"3997,3997,-2":(["name":0,]),"4998,5000,0":(["name":0,]),"6999,7008,7001":(["name":0,]),"3998,4003,0":(["name":0,]),"6999,7008,7000":(["name":0,]),"1,-1,0":(["name":0,]),"1997,1998,0":(["name":0,]),"5001,5002,0":(["name":0,]),"6997,7009,6999":(["name":0,]),"7003,7008,6999":(["name":0,]),"6999,6996,7000":(["name":0,]),"-3003,-3002,-3000":(["name":0,]),"999,999,1":(["name":0,]),"-2997,-2999,-3000":(["name":0,]),"-3003,-2996,-3000":(["name":0,]),"3998,4000,0":(["name":0,]),"6998,7007,7001":(["name":0,]),"6998,7007,7000":(["name":0,]),"7004,7006,7001":(["name":0,]),"4001,4002,0":(["name":0,]),"6996,7008,6999":(["name":0,]),"7002,7007,6999":(["name":0,]),"2000,1997,0":(["name":0,]),"997,-1002,0":(["name":0,]),"6997,7006,7001":(["name":0,]),"1998,2003,0":(["name":0,]),"6997,7006,7000":(["name":0,]),"7003,7005,7001":(["name":0,]),"7003,7005,7000":(["name":0,]),"1003,-998,0":(["name":0,]),"7001,7006,6999":(["name":0,]),"0,-3,0":(["name":0,]),"4998,4997,0":(["name":0,]),"998,1005,1":(["name":0,]),"1998,2000,0":(["name":0,]),"6996,7005,7001":(["name":0,]),"6996,7005,7000":(["name":0,]),"5001,4999,0":(["name":0,]),"7002,7004,7001":(["name":0,]),"-4,-1,0":(["name":0,]),"2001,2002,0":(["name":0,]),"7002,7004,7000":(["name":0,]),"1001,1005,1":(["name":0,]),"7000,7005,6999":(["name":"/domains/voluntaria/room/bottomstair",]),"4001,4002,-2":(["name":0,]),"998,1002,1":(["name":0,]),"3998,3997,0":(["name":0,]),"4001,4002,-1":(["name":0,]),"6995,7004,7001":(["name":0,]),"6995,7004,7000":(["name":0,]),"4001,3999,0":(["name":0,]),"4003,3999,-1":(["name":0,]),"7001,7003,7001":(["name":0,]),"1001,1002,1":(["name":0,]),"7001,7003,7000":(["name":0,]),"3995,4002,-2":(["name":0,]),"4999,5002,0":(["name":0,]),"3997,3999,-2":(["name":0,]),"5002,5004,0":(["name":0,]),"7000,7002,7001":(["name":0,]),"-3002,-2998,-3000":(["name":0,]),"7000,7002,7000":(["name":"/domains/voluntaria/room/airlock",]),"2,3,0":(["name":0,]),"3999,4002,0":(["name":0,]),"996,-998,0":(["name":0,]),"4003,4001,-1":(["name":0,]),"1998,1997,0":(["name":0,]),"5002,5001,0":(["name":0,]),"-3,-3,0":(["name":0,]),"-4,2,0":(["name":0,]),"996,-1001,0":(["name":0,]),"-2999,-3000,-3000":(["name":0,]),"4002,4004,0":(["name":0,]),"4005,3998,-1":(["name":0,]),"2001,1999,0":(["name":0,]),"2,0,0":(["name":0,]),"3997,4001,-2":(["name":0,]),"1000,998,1":(["name":0,]),"4002,4001,0":(["name":0,]),"3999,3998,-2":(["name":0,]),"7002,6999,7000":(["name":"/domains/oogtopia/room/bushesse",]),"3999,3998,-1":(["name":0,]),"4999,4999,0":(["name":0,]),"6999,7008,6999":(["name":0,]),"-2999,-2999,-3000":(["name":0,]),"1999,2002,0":(["name":0,]),"4005,4000,-1":(["name":0,]),"7001,6998,7000":(["name":0,]),"2002,2004,0":(["name":0,]),"-1,4,0":(["name":0,]),"-3001,-3001,-3000":(["name":0,]),"3999,4000,-2":(["name":"/domains/campus/room/crawlspace",]),"999,1004,1":(["name":0,]),"3999,3999,0":(["name":0,]),"3999,4000,-1":(["name":0,]),"6998,7007,6999":(["name":0,]),"7000,7009,7001":(["name":0,]),"7000,7009,7000":(["name":0,]),"5002,4998,0":(["name":0,]),"4001,4004,-2":(["name":0,]),"2002,2001,0":(["name":0,]),"4001,4004,-1":(["name":0,]),"1002,1004,1":(["name":0,]),"7000,6997,7000":(["name":0,]),"-1,1,0":(["name":0,]),"-2,-2,0":(["name":0,]),"999,1001,1":(["name":0,]),"6999,7005,7001":(["name":0,]),"6999,7005,7000":(["name":0,]),"7005,7004,7000":(["name":0,]),"6997,7006,6999":(["name":0,]),"3995,4004,-2":(["name":0,]),"7003,7005,6999":(["name":0,]),"4002,3998,0":(["name":0,]),"1002,1001,1":(["name":0,]),"6998,7004,7001":(["name":0,]),"6998,7004,7000":(["name":0,]),"7004,7003,7001":(["name":0,]),"1999,1999,0":(["name":0,]),"5003,5003,0":(["name":0,]),"7004,7003,7000":(["name":0,]),"6996,7005,6999":(["name":0,]),"-2998,-3002,-3000":(["name":0,]),"7002,7004,6999":(["name":0,]),"-2998,-2996,-3000":(["name":0,]),"4003,4003,-1":(["name":0,]),"4000,3997,-2":(["name":0,]),"4000,3997,-1":(["name":0,]),"997,-997,0":(["name":0,]),"6997,7003,7001":(["name":0,]),"5003,5000,0":(["name":0,]),"1003,-1002,0":(["name":0,]),"6997,7003,7000":(["name":0,]),"7003,7002,7001":(["name":0,]),"3997,4003,-2":(["name":0,]),"4003,4003,0":(["name":0,]),"7003,7002,7000":(["name":0,]),]) +MapCache (["7002,7000,7000":" | 4 # | 3 #-# | 2 # | 1 #-#-# | | | 0 #-#-%^RED%^@%^RESET%^ | | | 9 #-#-# 8 8 9 0 1 2 3 4 5 ","5000,5000,0":" 4 3 2 1 0 %^RED%^@%^RESET%^ | 9 8 6 7 8 9 0 1 2 3 ","7001,7004,7001":" 8 7 6 5 # | 4 #-#-%^RED%^@%^RESET%^ | 3 # | 2 7 8 9 0 1 2 3 4 ","7001,7001,7000":" 5 # | 4 # | 3 #-# | 2 # | 1 #-%^RED%^@%^RESET%^-# | | | 0 #-#-# | | | 9 #-#-# 7 8 9 0 1 2 3 4 ","7000,7005,7001":" 9 8 7 6 5 %^RED%^@%^RESET%^ | 4 #-#-# | 3 # | 6 7 8 9 0 1 2 3 ","7000,7002,7000":" 6 5 # | 4 # | 3 #-# | 2 %^RED%^@%^RESET%^ | 1 #-#-# | | | 0 #-#-# | | | 6 7 8 9 0 1 2 3 ","7000,7005,7000":" 9 8 7 6 5 %^RED%^@%^RESET%^ | 4 # | 3 #-# | 6 7 8 9 0 1 2 3 ","6999,7003,7000":" 7 6 5 # | 4 # | 3 %^RED%^@%^RESET%^-# | 2 # | 1 #-#-# | | | 5 6 7 8 9 0 1 2 ","4003,4000,-1":" 4 3 2 1 0 -%^RED%^@%^RESET%^- 9 8 9 0 1 2 3 4 5 6 ","2000,2000,0":" 4 3 2 1 0 %^RED%^@%^RESET%^ 9 8 6 7 8 9 0 1 2 3 ","-3000,-3000,-3000":" -6 -7 -8 -9 | 0 %^RED%^@%^RESET%^ -1 -2 -4-3-2-1-0-9-8-7 ","7002,7001,7000":" 5 # | 4 # | 3 #-# | 2 # | 1 #-#-%^RED%^@%^RESET%^ | | | 0 #-#-# | | | 9 #-#-# 8 9 0 1 2 3 4 5 ","7000,7005,6999":" 9 8 7 6 5 %^RED%^@%^RESET%^ 4 3 6 7 8 9 0 1 2 3 ","4000,4000,0":" 4 3 2 1 | 0 %^RED%^@%^RESET%^ 9 8 6 7 8 9 0 1 2 3 ","7000,6999,7000":" | 3 #-# | 2 # | 1 #-#-# | | | 0 #-#-# | | | 9 %^RED%^@%^RESET%^-#-# 8 7 6 7 8 9 0 1 2 3 ","1000,-1000,0":" -6 -7 -8 -9 | 0 -%^RED%^@%^RESET%^- | -1 -2 6 7 8 9 0 1 2 3 ","7000,7003,7001":" 7 6 5 # | 4 #-#-# | 3 %^RED%^@%^RESET%^ | 2 1 6 7 8 9 0 1 2 3 ","3999,4000,-2":" 4 3 2 1 0 %^RED%^@%^RESET%^ 9 8 5 6 7 8 9 0 1 2 ","7000,7000,7000":" | 4 # | 3 #-# | 2 # | 1 #-#-# | | | 0 %^RED%^@%^RESET%^-#-# | | | 9 #-#-# 8 6 7 8 9 0 1 2 3 ","6999,7004,7001":" 8 7 6 5 # | 4 %^RED%^@%^RESET%^-#-# | 3 # | 2 5 6 7 8 9 0 1 2 ","7000,7003,7000":" 7 6 5 # | 4 # | 3 #-%^RED%^@%^RESET%^ | 2 # | 1 #-#-# | | | 6 7 8 9 0 1 2 3 ","7001,6999,7000":" | 3 #-# | 2 # | 1 #-#-# | | | 0 #-#-# | | | 9 #-%^RED%^@%^RESET%^-# 8 7 7 8 9 0 1 2 3 4 ","7001,7000,7000":" 3 2 1 #-#-# | | | 0 #-%^RED%^@%^RESET%^-# | | | 9 #-#-# 8 9 0 1 2 3 ","7000,7004,7001":" 8 7 6 5 # | 4 #-%^RED%^@%^RESET%^-# | 3 # | 2 6 7 8 9 0 1 2 3 ","7000,7001,7000":" 5 # | 4 # | 3 #-# | 2 # | 1 %^RED%^@%^RESET%^-#-# | | | 0 #-#-# | | | 9 #-#-# 6 7 8 9 0 1 2 3 ","7000,7004,7000":" 8 7 6 5 # | 4 %^RED%^@%^RESET%^ | 3 #-# | 2 # | 6 7 8 9 0 1 2 3 ","7002,6999,7000":" | 3 #-# | 2 # | 1 #-#-# | | | 0 #-#-# | | | 9 #-#-%^RED%^@%^RESET%^ 8 7 8 9 0 1 2 3 4 5 ",0:" 4 3 2 1 0 -1 -2 -4-3-2-1 0 1 2 3 ","1000,1001,1":" 5 4 3 2 1 %^RED%^@%^RESET%^ 0 9 6 7 8 9 0 1 2 3 ",]) diff --git a/lib/save/notify.o b/lib/save/notify.o new file mode 100644 index 0000000..316d17f --- /dev/null +++ b/lib/save/notify.o @@ -0,0 +1,2 @@ +#/daemon/notify.c +Notes ({}) diff --git a/lib/save/parties.o b/lib/save/parties.o new file mode 100644 index 0000000..90656dd --- /dev/null +++ b/lib/save/parties.o @@ -0,0 +1,3 @@ +#/daemon/party.c +Parties ([]) +old_parties ({}) diff --git a/lib/save/portal.o b/lib/save/portal.o new file mode 100644 index 0000000..7c79c9a --- /dev/null +++ b/lib/save/portal.o @@ -0,0 +1,9 @@ +#/secure/daemon/portal.c +PersistentInventory 0 +PersistentInventoryEnabled 0 +blue +orange +bportal +oportal +oroom "/domains/town/room/wtunnel3" +broom "/domains/campus/room/hazlab" diff --git a/lib/save/races.o b/lib/save/races.o new file mode 100644 index 0000000..bb9a18c --- /dev/null +++ b/lib/save/races.o @@ -0,0 +1,8 @@ +#/daemon/races.c +Races (["deer":(["Size":64,"Btype":2,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([64:"low",32:"high",]),"Stats":(["wisdom":(["Average":1,"Class":5,]),"agility":(["Average":21,"Class":3,]),"speed":(["Average":31,"Class":2,]),"strength":(["Average":43,"Class":1,]),"intelligence":(["Average":1,"Class":5,]),"durability":(["Average":31,"Class":2,]),"charisma":(["Average":21,"Class":3,]),"coordination":(["Average":10,"Class":4,]),"luck":(["Average":10,"Class":4,]),]),"Fingers":([]),"Language":"Tier","Mass":3000,"Sensitivity":({20,8000,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore hoof","left fore leg",4,({}),}),({"left fore hoof","left fore leg",4,({}),}),({"left rear hoof","left rear leg",4,({}),}),({"left rear hoof","left rear leg",4,({}),}),({"right fore hoof","right fore leg",4,({}),}),({"right fore hoof","right fore leg",4,({}),}),({"right rear hoof","right rear leg",4,({}),}),({"right rear hoof","right rear leg",4,({}),}),}),"Complete":1,]),"bird":(["Size":8,"Btype":0,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([64:"low",32:"high",]),"Stats":(["wisdom":(["Average":10,"Class":4,]),"agility":(["Average":43,"Class":1,]),"speed":(["Average":43,"Class":1,]),"strength":(["Average":10,"Class":4,]),"intelligence":(["Average":1,"Class":5,]),"durability":(["Average":1,"Class":5,]),"charisma":(["Average":31,"Class":2,]),"coordination":(["Average":10,"Class":4,]),"luck":(["Average":21,"Class":3,]),]),"Fingers":([]),"Language":"Avian","Mass":10,"Sensitivity":({20,8000,}),"Mouthtype":8,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"left leg","torso",2,({32,1048576,1024,128,1,}),}),({"left leg","torso",2,({32,1048576,1024,128,1,}),}),({"right leg","torso",2,({32,1048576,1024,128,1,}),}),({"right leg","torso",2,({32,1048576,1024,128,1,}),}),({"left foot","left leg",4,({64,128,16,32,1,}),}),({"left foot","left leg",4,({64,128,16,32,1,}),}),({"right foot","right leg",4,({64,128,16,32,1,}),}),({"right foot","right leg",4,({64,128,16,32,1,}),}),({"right wing","torso",4,({}),}),({"right wing","torso",4,({}),}),({"left wing","torso",4,({}),}),({"left wing","torso",4,({}),}),}),"Complete":1,]),"dwarf":(["Size":32,"Btype":1,"Rtype":1,"PlayerFlag":1,"Skills":([]),"Resistance":([2:"low",64:"low",]),"Stats":(["wisdom":(["Average":20,"Class":3,]),"agility":(["Average":10,"Class":2,]),"speed":(["Average":20,"Class":3,]),"strength":(["Average":40,"Class":1,]),"intelligence":(["Average":18,"Class":3,]),"durability":(["Average":60,"Class":1,]),"charisma":(["Average":11,"Class":3,]),"coordination":(["Average":10,"Class":2,]),"luck":(["Average":60,"Class":1,]),]),"Fingers":(["right hand":4,"left hand":4,]),"Language":"Malkierien","Mass":200,"Sensitivity":({5,6500,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),}),"Complete":1,]),"klingon":(["Size":128,"Btype":1,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([4:"medium",2:"medium",8:"medium",128:"medium",64:"medium",]),"Stats":(["wisdom":(["Average":1,"Class":5,]),"agility":(["Average":30,"Class":2,]),"speed":(["Average":30,"Class":3,]),"strength":(["Average":60,"Class":1,]),"intelligence":(["Average":25,"Class":2,]),"durability":(["Average":60,"Class":1,]),"charisma":(["Average":10,"Class":5,]),"coordination":(["Average":10,"Class":2,]),"luck":(["Average":1,"Class":4,]),]),"Fingers":(["right hand":5,"left hand":5,]),"Language":"Tlhinghan","Mass":2500,"Sensitivity":({19,6500,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),}),"Complete":1,]),"poleepkwa":(["Size":128,"Btype":1,"Rtype":1,"PlayerFlag":1,"Skills":([]),"Resistance":([4:"low",8:"medium",]),"Stats":(["wisdom":(["Average":10,"Class":4,]),"agility":(["Average":53,"Class":4,]),"speed":(["Average":43,"Class":4,]),"strength":(["Average":70,"Class":4,]),"intelligence":(["Average":10,"Class":4,]),"durability":(["Average":10,"Class":4,]),"charisma":(["Average":1,"Class":4,]),"coordination":(["Average":43,"Class":4,]),"luck":(["Average":10,"Class":4,]),]),"Fingers":(["right hand":4,"left hand":4,]),"Language":"Poleepkwa","Mass":1500,"Sensitivity":({25,7500,}),"Mouthtype":16,"Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,262144,1,2097152,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,262144,1,2097152,}),}),({"neck","torso",1,({524288,262144,1,2097152,}),}),({"neck","torso",1,({524288,262144,1,2097152,}),}),({"head","neck",1,({256,262144,1,2097152,}),}),({"head","neck",1,({256,262144,1,2097152,}),}),({"right leg","torso",2,({1024,1048576,1,2097152,}),}),({"right leg","torso",2,({1024,1048576,1,2097152,}),}),({"left leg","torso",2,({1024,1048576,1,2097152,}),}),({"left leg","torso",2,({1024,1048576,1,2097152,}),}),({"right foot","right leg",4,({1,2097152,}),}),({"right foot","right leg",4,({1,2097152,}),}),({"left foot","left leg",4,({1,2097152,}),}),({"left foot","left leg",4,({1,2097152,}),}),({"right arm","torso",2,({65536,8192,131072,1048576,1,2097152,}),}),({"right arm","torso",2,({65536,8192,131072,1048576,1,2097152,}),}),({"left arm","torso",2,({65536,8192,131072,1048576,1,2097152,}),}),({"left arm","torso",2,({65536,8192,131072,1048576,1,2097152,}),}),({"right hand","right arm",4,({32768,65536,1,2097152,}),}),({"right hand","right arm",4,({32768,65536,1,2097152,}),}),({"left hand","left arm",4,({32768,65536,1,2097152,}),}),({"left hand","left arm",4,({32768,65536,1,2097152,}),}),}),"Complete":1,]),"orc":(["Size":128,"Btype":1,"Rtype":1,"PlayerFlag":1,"Skills":([]),"Resistance":([]),"Stats":(["wisdom":(["Average":3,"Class":5,]),"agility":(["Average":10,"Class":2,]),"speed":(["Average":40,"Class":2,]),"strength":(["Average":35,"Class":1,]),"intelligence":(["Average":10,"Class":3,]),"durability":(["Average":30,"Class":2,]),"charisma":(["Average":1,"Class":5,]),"coordination":(["Average":33,"Class":3,]),"luck":(["Average":3,"Class":4,]),]),"Fingers":(["right hand":6,"left hand":6,]),"Language":"Tangetto","Mass":2200,"Sensitivity":({5,7100,}),"Mouthtype":2118,"Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),}),"Complete":1,]),"goblin":(["Size":64,"Btype":1,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([2:"medium",16:"low",32:"high",64:"high",]),"Stats":(["wisdom":(["Average":21,"Class":3,]),"agility":(["Average":43,"Class":1,]),"speed":(["Average":31,"Class":2,]),"strength":(["Average":21,"Class":3,]),"intelligence":(["Average":10,"Class":4,]),"durability":(["Average":43,"Class":1,]),"charisma":(["Average":1,"Class":5,]),"coordination":(["Average":21,"Class":3,]),"luck":(["Average":10,"Class":4,]),]),"Fingers":([]),"Language":"Goblinish","Mass":1800,"Sensitivity":({0,8000,}),"Mouthtype":198,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"left leg","torso",2,({32,1048576,1024,128,1,}),}),({"left leg","torso",2,({32,1048576,1024,128,1,}),}),({"left arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"left arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right leg","torso",2,({32,1048576,1024,128,1,}),}),({"right leg","torso",2,({32,1048576,1024,128,1,}),}),({"right foot","right leg",4,({64,128,16,32,1,}),}),({"right foot","right leg",4,({64,128,16,32,1,}),}),({"right hand","right arm",4,({4,8,32768,65536,1,}),}),({"right hand","right arm",4,({4,8,32768,65536,1,}),}),({"left foot","left leg",4,({64,128,16,32,1,}),}),({"left foot","left leg",4,({64,128,16,32,1,}),}),({"left hand","left arm",4,({4,8,32768,65536,1,}),}),({"left hand","left arm",4,({4,8,32768,65536,1,}),}),}),"Complete":1,]),"tortoise":(["Size":16,"Btype":2,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([4:"low",2:"low",16:"low",8:"low",128:"medium",64:"medium",32:"high",]),"Stats":(["wisdom":(["Average":43,"Class":1,]),"agility":(["Average":10,"Class":4,]),"speed":(["Average":1,"Class":5,]),"strength":(["Average":1,"Class":5,]),"intelligence":(["Average":21,"Class":3,]),"durability":(["Average":43,"Class":1,]),"charisma":(["Average":10,"Class":4,]),"coordination":(["Average":31,"Class":2,]),"luck":(["Average":21,"Class":3,]),]),"Fingers":([]),"Language":"Tortois","Mass":90,"Sensitivity":({20,8000,}),"Mouthtype":64,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left forepaw","left fore leg",4,({}),}),({"left forepaw","left fore leg",4,({}),}),({"right forepaw","right fore leg",4,({}),}),({"right forepaw","right fore leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),}),"Complete":1,]),"bugbear":(["Size":256,"Btype":8388608,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([64:"low",32:"high",]),"Stats":(["agility":(["Average":1,"Class":5,]),"wisdom":(["Average":31,"Class":2,]),"speed":(["Average":1,"Class":5,]),"strength":(["Average":43,"Class":1,]),"intelligence":(["Average":21,"Class":3,]),"ugliness":(["Average":91,"Class":3,]),"durability":(["Average":43,"Class":1,]),"charisma":(["Average":21,"Class":3,]),"coordination":(["Average":1,"Class":5,]),"luck":(["Average":10,"Class":4,]),]),"Fingers":([]),"Language":"Insectursine","Mass":450,"Sensitivity":({20,8000,}),"Mouthtype":16,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left forepaw","left fore leg",4,({}),}),({"left forepaw","left fore leg",4,({}),}),({"right forepaw","right fore leg",4,({}),}),({"right forepaw","right fore leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),}),"Complete":1,]),"arachnid":(["Size":4,"Btype":16,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([]),"Stats":(["wisdom":(["Average":1,"Class":5,]),"agility":(["Average":43,"Class":1,]),"speed":(["Average":31,"Class":2,]),"strength":(["Average":10,"Class":4,]),"intelligence":(["Average":1,"Class":3,]),"durability":(["Average":1,"Class":5,]),"charisma":(["Average":1,"Class":5,]),"coordination":(["Average":43,"Class":1,]),"luck":(["Average":21,"Class":3,]),]),"Fingers":([]),"Language":"Arachnid","Mass":5,"Sensitivity":({20,8000,}),"Mouthtype":16,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"head","torso",1,({1048576,512,256,8192,1,}),}),({"head","torso",1,({1048576,512,256,8192,1,}),}),({"1st leg","torso",3,({32,1048576,1024,128,1,}),}),({"1st leg","torso",3,({32,1048576,1024,128,1,}),}),({"8th leg","torso",3,({32,1048576,1024,128,1,}),}),({"8th leg","torso",3,({32,1048576,1024,128,1,}),}),({"2nd leg","torso",3,({32,1048576,1024,128,1,}),}),({"2nd leg","torso",3,({32,1048576,1024,128,1,}),}),({"5th leg","torso",3,({32,1048576,1024,128,1,}),}),({"5th leg","torso",3,({32,1048576,1024,128,1,}),}),({"7th leg","torso",3,({32,1048576,1024,128,1,}),}),({"7th leg","torso",3,({32,1048576,1024,128,1,}),}),({"4th leg","torso",3,({32,1048576,1024,128,1,}),}),({"4th leg","torso",3,({32,1048576,1024,128,1,}),}),({"3rd leg","torso",3,({32,1048576,1024,128,1,}),}),({"3rd leg","torso",3,({32,1048576,1024,128,1,}),}),({"6th leg","torso",3,({32,1048576,1024,128,1,}),}),({"6th leg","torso",3,({32,1048576,1024,128,1,}),}),}),"Complete":1,]),"vulcan":(["Size":64,"Btype":1,"Rtype":1,"PlayerFlag":0,"Skills":(["psionic defense":({"8","1","0","0",}),"psionic attack":({"8","1","0","0",}),"psionic detection":({"8","1","0","0",}),]),"Resistance":([128:"high",64:"low",]),"Stats":(["wisdom":(["Average":60,"Class":1,]),"agility":(["Average":30,"Class":2,]),"speed":(["Average":30,"Class":3,]),"strength":(["Average":30,"Class":5,]),"intelligence":(["Average":70,"Class":1,]),"durability":(["Average":30,"Class":1,]),"psi":(["Average":20,"Class":1,]),"charisma":(["Average":1,"Class":5,]),"coordination":(["Average":30,"Class":2,]),"luck":(["Average":1,"Class":1,]),]),"Fingers":(["right hand":5,"left hand":5,]),"Language":"Vulcan","Mass":1500,"Sensitivity":({17,10000,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),}),"Complete":1,]),"mech":(["Size":512,"Btype":1,"Rtype":4,"PlayerFlag":0,"Skills":([]),"Resistance":([4:"immune",8:"immune",]),"Stats":(["wisdom":(["Average":1,"Class":3,]),"agility":(["Average":50,"Class":3,]),"speed":(["Average":50,"Class":3,]),"strength":(["Average":90,"Class":4,]),"intelligence":(["Average":1,"Class":1,]),"durability":(["Average":50,"Class":4,]),"charisma":(["Average":50,"Class":2,]),"coordination":(["Average":50,"Class":2,]),"luck":(["Average":10,"Class":3,]),]),"Fingers":(["right hand":5,"left hand":5,]),"Language":"English","Mass":10000,"Sensitivity":({0,75000,}),"Mouthtype":1,"Limbs":({({"torso",0,1,({262144,1,}),}),({"torso",0,1,({262144,1,}),}),({"neck","torso",1,({262144,1,}),}),({"neck","torso",1,({262144,1,}),}),({"head","neck",1,({262144,1,}),}),({"head","neck",1,({262144,1,}),}),({"right leg","torso",2,({1,}),}),({"right leg","torso",2,({1,}),}),({"left leg","torso",2,({1,}),}),({"left leg","torso",2,({1,}),}),({"right foot","right leg",4,({1,}),}),({"right foot","right leg",4,({1,}),}),({"left foot","left leg",4,({1,}),}),({"left foot","left leg",4,({1,}),}),({"right arm","torso",2,({1,}),}),({"right arm","torso",2,({1,}),}),({"left arm","torso",2,({1,}),}),({"left arm","torso",2,({1,}),}),({"right hand","right arm",4,({32768,1,}),}),({"right hand","right arm",4,({32768,1,}),}),({"left hand","left arm",4,({32768,1,}),}),({"left hand","left arm",4,({32768,1,}),}),}),"Complete":1,]),"cow":(["Size":256,"Btype":2,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([64:"low",32:"high",]),"Stats":(["wisdom":(["Average":1,"Class":5,]),"agility":(["Average":1,"Class":5,]),"speed":(["Average":1,"Class":5,]),"strength":(["Average":31,"Class":2,]),"intelligence":(["Average":1,"Class":5,]),"durability":(["Average":43,"Class":1,]),"charisma":(["Average":10,"Class":4,]),"coordination":(["Average":21,"Class":3,]),"luck":(["Average":1,"Class":5,]),]),"Fingers":([]),"Language":"Bovine","Mass":4000,"Sensitivity":({20,8000,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore hoof","left fore leg",4,({}),}),({"left fore hoof","left fore leg",4,({}),}),({"left rear hoof","left rear leg",4,({}),}),({"left rear hoof","left rear leg",4,({}),}),({"right fore hoof","right fore leg",4,({}),}),({"right fore hoof","right fore leg",4,({}),}),({"right rear hoof","right rear leg",4,({}),}),({"right rear hoof","right rear leg",4,({}),}),}),"Complete":1,]),"android":(["Size":64,"Btype":1,"Rtype":4,"PlayerFlag":0,"Skills":([]),"Resistance":([]),"Stats":(["wisdom":(["Average":50,"Class":3,]),"agility":(["Average":50,"Class":3,]),"speed":(["Average":50,"Class":3,]),"strength":(["Average":50,"Class":4,]),"intelligence":(["Average":50,"Class":1,]),"durability":(["Average":50,"Class":4,]),"charisma":(["Average":50,"Class":2,]),"coordination":(["Average":50,"Class":2,]),"luck":(["Average":10,"Class":3,]),]),"Fingers":(["right hand":5,"left hand":5,]),"Language":"English","Mass":3000,"Sensitivity":({25,7500,}),"Mouthtype":1024,"Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),}),"Complete":1,]),"cat":(["Size":16,"Btype":2,"Rtype":1,"PlayerFlag":0,"Skills":(["stealth":({"1","5","4","6",}),]),"Resistance":([]),"Stats":(["wisdom":(["Average":10,"Class":4,]),"agility":(["Average":43,"Class":1,]),"speed":(["Average":31,"Class":2,]),"strength":(["Average":10,"Class":4,]),"intelligence":(["Average":1,"Class":5,]),"durability":(["Average":10,"Class":4,]),"charisma":(["Average":43,"Class":1,]),"coordination":(["Average":21,"Class":3,]),"luck":(["Average":43,"Class":1,]),]),"Fingers":([]),"Language":"Feline","Mass":100,"Sensitivity":({20,8000,}),"Mouthtype":198,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left forepaw","left fore leg",4,({}),}),({"left forepaw","left fore leg",4,({}),}),({"right forepaw","right fore leg",4,({}),}),({"right forepaw","right fore leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),({"tail","torso",5,({}),}),({"tail","torso",5,({}),}),}),"Complete":1,]),"kender":(["Size":32,"Btype":1,"Rtype":1,"PlayerFlag":0,"Skills":(["stealing":({"2","1","0","0",}),]),"Resistance":([]),"Stats":(["wisdom":(["Average":7,"Class":4,]),"agility":(["Average":40,"Class":3,]),"speed":(["Average":50,"Class":1,]),"strength":(["Average":3,"Class":5,]),"intelligence":(["Average":20,"Class":2,]),"durability":(["Average":20,"Class":1,]),"charisma":(["Average":40,"Class":2,]),"coordination":(["Average":50,"Class":2,]),"luck":(["Average":33,"Class":3,]),]),"Fingers":(["right hand":5,"left hand":5,]),"Language":"Kendrall","Mass":800,"Sensitivity":({23,7800,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),}),"Complete":1,]),"horse":(["Size":256,"Btype":2,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([2:"medium",16:"low",64:"low",32:"high",]),"Stats":(["wisdom":(["Average":1,"Class":5,]),"agility":(["Average":31,"Class":2,]),"speed":(["Average":31,"Class":2,]),"strength":(["Average":73,"Class":1,]),"intelligence":(["Average":1,"Class":5,]),"durability":(["Average":31,"Class":2,]),"charisma":(["Average":21,"Class":3,]),"coordination":(["Average":10,"Class":4,]),"luck":(["Average":1,"Class":5,]),]),"Fingers":([]),"Language":"Equine","Mass":6000,"Sensitivity":({20,8000,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore hoof","left fore leg",4,({}),}),({"left fore hoof","left fore leg",4,({}),}),({"left rear hoof","left rear leg",4,({}),}),({"left rear hoof","left rear leg",4,({}),}),({"right fore hoof","right fore leg",4,({}),}),({"right fore hoof","right fore leg",4,({}),}),({"right rear hoof","right rear leg",4,({}),}),({"right rear hoof","right rear leg",4,({}),}),}),"Complete":1,]),"halfling":(["Size":16,"Btype":1,"Rtype":1,"PlayerFlag":1,"Skills":([]),"Resistance":([]),"Stats":(["wisdom":(["Average":10,"Class":4,]),"agility":(["Average":40,"Class":2,]),"speed":(["Average":30,"Class":1,]),"strength":(["Average":10,"Class":3,]),"intelligence":(["Average":20,"Class":2,]),"durability":(["Average":10,"Class":3,]),"charisma":(["Average":80,"Class":2,]),"coordination":(["Average":33,"Class":1,]),"luck":(["Average":80,"Class":2,]),]),"Fingers":(["right hand":5,"left hand":5,]),"Language":"Duuk","Mass":500,"Sensitivity":({15,6500,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),}),"Complete":1,]),"golem":(["Size":256,"Btype":1,"Rtype":4,"PlayerFlag":0,"Skills":([]),"Resistance":([2:"medium",16:"low",32:"high",64:"high",]),"Stats":(["wisdom":(["Average":31,"Class":2,]),"agility":(["Average":21,"Class":3,]),"speed":(["Average":21,"Class":3,]),"strength":(["Average":43,"Class":1,]),"intelligence":(["Average":10,"Class":4,]),"durability":(["Average":31,"Class":2,]),"charisma":(["Average":1,"Class":5,]),"coordination":(["Average":21,"Class":3,]),"luck":(["Average":1,"Class":5,]),]),"Fingers":([]),"Language":"Emet","Mass":5000,"Sensitivity":({20,8000,}),"Mouthtype":1024,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"head","torso",1,({1048576,512,256,8192,1,}),}),({"head","torso",1,({1048576,512,256,8192,1,}),}),({"left leg","torso",2,({32,1048576,1024,128,1,}),}),({"left leg","torso",2,({32,1048576,1024,128,1,}),}),({"left arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"left arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right leg","torso",2,({32,1048576,1024,128,1,}),}),({"right leg","torso",2,({32,1048576,1024,128,1,}),}),({"right foot","right leg",4,({64,128,16,32,1,}),}),({"right foot","right leg",4,({64,128,16,32,1,}),}),({"right hand","right arm",4,({4,8,32768,65536,1,}),}),({"right hand","right arm",4,({4,8,32768,65536,1,}),}),({"left foot","left leg",4,({64,128,16,32,1,}),}),({"left foot","left leg",4,({64,128,16,32,1,}),}),({"left hand","left arm",4,({4,8,32768,65536,1,}),}),({"left hand","left arm",4,({4,8,32768,65536,1,}),}),}),"Complete":1,]),"hobbit":(["Size":16,"Btype":1,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([64:"low",]),"Stats":(["wisdom":(["Average":20,"Class":3,]),"agility":(["Average":20,"Class":1,]),"speed":(["Average":30,"Class":2,]),"strength":(["Average":10,"Class":4,]),"intelligence":(["Average":20,"Class":2,]),"durability":(["Average":20,"Class":2,]),"charisma":(["Average":33,"Class":3,]),"coordination":(["Average":60,"Class":3,]),"luck":(["Average":80,"Class":1,]),]),"Fingers":(["right hand":4,"left hand":4,]),"Language":"Hoboken","Mass":500,"Sensitivity":({20,7000,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),}),"Complete":1,]),"isopod":(["Size":256,"Btype":16,"Rtype":3,"PlayerFlag":0,"Skills":([]),"Resistance":([2:"medium",16:"high",64:"high",32:"low",]),"Stats":(["wisdom":(["Average":1,"Class":5,]),"agility":(["Average":11,"Class":2,]),"speed":(["Average":13,"Class":1,]),"strength":(["Average":70,"Class":5,]),"intelligence":(["Average":1,"Class":5,]),"durability":(["Average":60,"Class":5,]),"charisma":(["Average":1,"Class":5,]),"coordination":(["Average":20,"Class":3,]),"luck":(["Average":43,"Class":1,]),]),"Fingers":([]),"Language":"cthonic","Mass":1,"Sensitivity":({20,8000,}),"Mouthtype":16,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"head","torso",1,({1048576,512,256,8192,1,}),}),({"head","torso",1,({1048576,512,256,8192,1,}),}),({"4th leg","torso",3,({32,1048576,1024,128,1,}),}),({"4th leg","torso",3,({32,1048576,1024,128,1,}),}),({"6th leg","torso",3,({32,1048576,1024,128,1,}),}),({"6th leg","torso",3,({32,1048576,1024,128,1,}),}),({"5th leg","torso",3,({32,1048576,1024,128,1,}),}),({"5th leg","torso",3,({32,1048576,1024,128,1,}),}),({"1st leg","torso",3,({32,1048576,1024,128,1,}),}),({"1st leg","torso",3,({32,1048576,1024,128,1,}),}),({"3rd leg","torso",3,({32,1048576,1024,128,1,}),}),({"3rd leg","torso",3,({32,1048576,1024,128,1,}),}),({"2nd leg","torso",3,({32,1048576,1024,128,1,}),}),({"2nd leg","torso",3,({32,1048576,1024,128,1,}),}),}),"Complete":1,]),"snake":(["Size":16,"Btype":16384,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([4:"low",2:"low",16:"low",8:"low",128:"medium",64:"medium",32:"high",]),"Stats":(["wisdom":(["Average":31,"Class":2,]),"agility":(["Average":10,"Class":4,]),"speed":(["Average":10,"Class":4,]),"strength":(["Average":1,"Class":5,]),"intelligence":(["Average":10,"Class":4,]),"durability":(["Average":10,"Class":4,]),"charisma":(["Average":1,"Class":5,]),"coordination":(["Average":1,"Class":5,]),"luck":(["Average":43,"Class":1,]),]),"Fingers":([]),"Language":"Herpetian","Mass":40,"Sensitivity":({20,8000,}),"Mouthtype":68,"Limbs":({({"torso",0,1,({16384,}),}),({"torso",0,1,({16384,}),}),({"head","torso",1,({256,}),}),({"head","torso",1,({256,}),}),}),"Complete":1,]),"ape":(["Size":256,"Btype":8388608,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([64:"low",]),"Stats":(["wisdom":(["Average":1,"Class":2,]),"agility":(["Average":30,"Class":5,]),"speed":(["Average":30,"Class":5,]),"strength":(["Average":43,"Class":1,]),"intelligence":(["Average":15,"Class":3,]),"durability":(["Average":43,"Class":1,]),"charisma":(["Average":5,"Class":3,]),"coordination":(["Average":20,"Class":5,]),"luck":(["Average":10,"Class":4,]),]),"Fingers":([]),"Language":"Ur","Mass":3000,"Sensitivity":({20,8000,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left forepaw","left fore leg",4,({}),}),({"left forepaw","left fore leg",4,({}),}),({"right forepaw","right fore leg",4,({}),}),({"right forepaw","right fore leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),}),"Complete":1,]),"half-elf":(["Size":64,"Btype":1,"Rtype":1,"PlayerFlag":1,"Skills":([]),"Resistance":([]),"Stats":(["wisdom":(["Average":30,"Class":2,]),"agility":(["Average":30,"Class":2,]),"speed":(["Average":60,"Class":1,]),"strength":(["Average":15,"Class":3,]),"intelligence":(["Average":30,"Class":1,]),"durability":(["Average":30,"Class":5,]),"charisma":(["Average":30,"Class":3,]),"coordination":(["Average":30,"Class":1,]),"luck":(["Average":30,"Class":4,]),]),"Fingers":(["right hand":4,"left hand":4,]),"Language":"Edhellen","Mass":1500,"Sensitivity":({12,6200,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),}),"Complete":1,]),"artrell":(["Size":32,"Btype":20,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([32:"high",64:"low",]),"Stats":(["wisdom":(["Average":5,"Class":5,]),"agility":(["Average":50,"Class":1,]),"speed":(["Average":40,"Class":2,]),"strength":(["Average":10,"Class":3,]),"intelligence":(["Average":10,"Class":4,]),"durability":(["Average":10,"Class":3,]),"charisma":(["Average":0,"Class":4,]),"coordination":(["Average":40,"Class":3,]),"luck":(["Average":33,"Class":3,]),]),"Fingers":(["fourth hand":2,"second hand":2,"first hand":2,"third hand":2,]),"Language":"Artrexcian","Mass":1200,"Sensitivity":({7,6100,}),"Mouthtype":16,"Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,1,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,1,}),}),({"head","torso",1,({256,512,262144,1,}),}),({"head","torso",1,({256,512,262144,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"first arm","torso",3,({8,65536,8192,131072,1048576,1,}),}),({"first arm","torso",3,({8,65536,8192,131072,1048576,1,}),}),({"second arm","torso",3,({8,65536,8192,131072,1048576,1,}),}),({"second arm","torso",3,({8,65536,8192,131072,1048576,1,}),}),({"third arm","torso",3,({8,65536,8192,131072,1048576,1,}),}),({"third arm","torso",3,({8,65536,8192,131072,1048576,1,}),}),({"fourth arm","torso",3,({8,65536,8192,131072,1048576,1,}),}),({"fourth arm","torso",3,({8,65536,8192,131072,1048576,1,}),}),({"first hand","first arm",4,({2,4,8,32768,65536,1,}),}),({"first hand","first arm",4,({2,4,8,32768,65536,1,}),}),({"second hand","second arm",4,({2,4,8,32768,65536,1,}),}),({"second hand","second arm",4,({2,4,8,32768,65536,1,}),}),({"third hand","third arm",4,({2,4,8,32768,65536,1,}),}),({"third hand","third arm",4,({2,4,8,32768,65536,1,}),}),({"fourth hand","fourth arm",4,({2,4,8,32768,65536,1,}),}),({"fourth hand","fourth arm",4,({2,4,8,32768,65536,1,}),}),}),"Complete":1,]),"tree":(["Size":256,"Btype":65536,"Rtype":4,"PlayerFlag":0,"Skills":([]),"Resistance":([4:"low",2:"low",16:"low",8:"low",128:"medium",64:"medium",32:"high",]),"Stats":(["wisdom":(["Average":10,"Class":4,]),"agility":(["Average":1,"Class":5,]),"speed":(["Average":1,"Class":5,]),"strength":(["Average":21,"Class":3,]),"intelligence":(["Average":1,"Class":5,]),"durability":(["Average":43,"Class":1,]),"charisma":(["Average":21,"Class":3,]),"coordination":(["Average":1,"Class":5,]),"luck":(["Average":43,"Class":1,]),]),"Fingers":([]),"Language":"Entish","Mass":4000,"Sensitivity":({0,8000,}),"Mouthtype":1,"Limbs":({({"trunk",0,1,({}),}),({"trunk",0,1,({}),}),({"1st branch","trunk",3,({}),}),({"1st branch","trunk",3,({}),}),}),"Complete":1,]),"dummy":(["Size":256,"Btype":1,"Rtype":4,"PlayerFlag":0,"Skills":([]),"Resistance":([]),"Stats":(["wisdom":(["Average":1,"Class":1,]),"agility":(["Average":1,"Class":1,]),"speed":(["Average":1,"Class":1,]),"strength":(["Average":1,"Class":1,]),"intelligence":(["Average":1,"Class":1,]),"durability":(["Average":1,"Class":1,]),"charisma":(["Average":1,"Class":1,]),"coordination":(["Average":1,"Class":1,]),"luck":(["Average":1,"Class":1,]),]),"Fingers":([]),"Language":"Common","Mass":5000,"Sensitivity":({0,10000,}),"Mouthtype":1024,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"head","torso",1,({1048576,512,256,8192,1,}),}),({"head","torso",1,({1048576,512,256,8192,1,}),}),({"left leg","torso",2,({32,1048576,1024,128,1,}),}),({"left leg","torso",2,({32,1048576,1024,128,1,}),}),({"left arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"left arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right leg","torso",2,({32,1048576,1024,128,1,}),}),({"right leg","torso",2,({32,1048576,1024,128,1,}),}),({"right foot","right leg",4,({64,128,16,32,1,}),}),({"right foot","right leg",4,({64,128,16,32,1,}),}),({"right hand","right arm",4,({4,8,32768,65536,1,}),}),({"right hand","right arm",4,({4,8,32768,65536,1,}),}),({"left foot","left leg",4,({64,128,16,32,1,}),}),({"left foot","left leg",4,({64,128,16,32,1,}),}),({"left hand","left arm",4,({4,8,32768,65536,1,}),}),({"left hand","left arm",4,({4,8,32768,65536,1,}),}),}),"Complete":1,]),"satyr":(["Size":64,"Btype":1,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([]),"Stats":(["wisdom":(["Average":80,"Class":1,]),"agility":(["Average":50,"Class":2,]),"speed":(["Average":5,"Class":2,]),"strength":(["Average":2,"Class":4,]),"intelligence":(["Average":33,"Class":3,]),"durability":(["Average":25,"Class":2,]),"charisma":(["Average":3,"Class":5,]),"coordination":(["Average":60,"Class":1,]),"luck":(["Average":10,"Class":1,]),]),"Fingers":(["right hand":4,"left hand":4,]),"Language":"Wulinaxian","Mass":150,"Sensitivity":({27,7700,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"right hoof","right leg",4,({16,32,64,128,1,}),}),({"right hoof","right leg",4,({16,32,64,128,1,}),}),({"left hoof","left leg",4,({16,32,64,128,1,}),}),({"left hoof","left leg",4,({16,32,64,128,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),}),"Complete":1,]),"human":(["Size":64,"Btype":1,"Rtype":1,"PlayerFlag":1,"Skills":(["psionic defense":({"2","3","4","5",}),]),"Resistance":([]),"Stats":(["wisdom":(["Average":40,"Class":3,]),"agility":(["Average":33,"Class":3,]),"speed":(["Average":30,"Class":3,]),"strength":(["Average":20,"Class":3,]),"intelligence":(["Average":40,"Class":1,]),"durability":(["Average":30,"Class":4,]),"charisma":(["Average":33,"Class":2,]),"coordination":(["Average":33,"Class":2,]),"luck":(["Average":20,"Class":3,]),]),"Fingers":(["right hand":5,"left hand":5,]),"Language":"English","Mass":1800,"Sensitivity":({25,7500,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),}),"Complete":1,]),"elephant":(["Size":512,"Btype":2,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([2:"low",64:"low",32:"high",]),"Stats":(["wisdom":(["Average":43,"Class":1,]),"agility":(["Average":1,"Class":5,]),"speed":(["Average":10,"Class":4,]),"strength":(["Average":43,"Class":1,]),"intelligence":(["Average":10,"Class":4,]),"durability":(["Average":43,"Class":1,]),"charisma":(["Average":10,"Class":4,]),"coordination":(["Average":21,"Class":3,]),"luck":(["Average":21,"Class":3,]),]),"Fingers":([]),"Language":"Pachydermian","Mass":40000,"Sensitivity":({20,8000,}),"Mouthtype":2118,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"trunk","head",3,({}),}),({"trunk","head",3,({}),}),({"right forepaw","right fore leg",4,({}),}),({"right forepaw","right fore leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"left forepaw","left fore leg",4,({}),}),({"left forepaw","left fore leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),}),"Complete":1,]),"wraith":(["Size":128,"Btype":131072,"Rtype":4,"PlayerFlag":0,"Skills":([]),"Resistance":([4:"low",2:"low",16:"low",8:"low",128:"medium",64:"medium",32:"high",]),"Stats":(["wisdom":(["Average":31,"Class":2,]),"agility":(["Average":31,"Class":2,]),"speed":(["Average":21,"Class":3,]),"strength":(["Average":21,"Class":3,]),"intelligence":(["Average":10,"Class":4,]),"durability":(["Average":21,"Class":3,]),"charisma":(["Average":1,"Class":5,]),"coordination":(["Average":31,"Class":2,]),"luck":(["Average":43,"Class":1,]),]),"Fingers":([]),"Language":"Revenant","Mass":100,"Sensitivity":({20,8000,}),"Mouthtype":198,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"left leg","torso",2,({32,1048576,1024,128,1,}),}),({"left leg","torso",2,({32,1048576,1024,128,1,}),}),({"left arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"left arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right leg","torso",2,({32,1048576,1024,128,1,}),}),({"right leg","torso",2,({32,1048576,1024,128,1,}),}),({"right foot","right leg",4,({64,128,16,32,1,}),}),({"right foot","right leg",4,({64,128,16,32,1,}),}),({"right hand","right arm",4,({4,8,32768,65536,1,}),}),({"right hand","right arm",4,({4,8,32768,65536,1,}),}),({"left foot","left leg",4,({64,128,16,32,1,}),}),({"left foot","left leg",4,({64,128,16,32,1,}),}),({"left hand","left arm",4,({4,8,32768,65536,1,}),}),({"left hand","left arm",4,({4,8,32768,65536,1,}),}),}),"Complete":1,]),"plant":(["Size":8,"Btype":32768,"Rtype":4,"PlayerFlag":0,"Skills":([]),"Resistance":([4:"low",2:"low",16:"low",8:"low",128:"medium",64:"medium",32:"high",]),"Stats":(["wisdom":(["Average":1,"Class":5,]),"agility":(["Average":1,"Class":5,]),"speed":(["Average":1,"Class":5,]),"strength":(["Average":21,"Class":3,]),"intelligence":(["Average":1,"Class":5,]),"durability":(["Average":21,"Class":3,]),"charisma":(["Average":11,"Class":3,]),"coordination":(["Average":1,"Class":5,]),"luck":(["Average":21,"Class":3,]),]),"Fingers":([]),"Language":"Vegetal","Mass":10,"Sensitivity":({0,80000,}),"Mouthtype":1,"Limbs":({({"trunk",0,1,({}),}),({"trunk",0,1,({}),}),({"1st branch","trunk",3,({}),}),({"1st branch","trunk",3,({}),}),}),"Complete":1,]),"god":(["Size":256,"Btype":4096,"Rtype":4,"PlayerFlag":0,"Skills":([]),"Resistance":([134217726:"immune",2:"medium",16:"low",32:"high",64:"high",]),"Stats":(["wisdom":(["Average":43,"Class":1,]),"agility":(["Average":43,"Class":1,]),"speed":(["Average":43,"Class":1,]),"strength":(["Average":43,"Class":1,]),"intelligence":(["Average":43,"Class":1,]),"durability":(["Average":43,"Class":1,]),"charisma":(["Average":43,"Class":1,]),"coordination":(["Average":43,"Class":1,]),"luck":(["Average":43,"Class":1,]),]),"Fingers":([]),"Language":"Divine","Mass":0,"Sensitivity":({0,80000,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"left leg","torso",2,({32,1048576,1024,128,1,}),}),({"left leg","torso",2,({32,1048576,1024,128,1,}),}),({"left arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"left arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right leg","torso",2,({32,1048576,1024,128,1,}),}),({"right leg","torso",2,({32,1048576,1024,128,1,}),}),({"right foot","right leg",4,({64,128,16,32,1,}),}),({"right foot","right leg",4,({64,128,16,32,1,}),}),({"right hand","right arm",4,({4,8,32768,65536,1,}),}),({"right hand","right arm",4,({4,8,32768,65536,1,}),}),({"left foot","left leg",4,({64,128,16,32,1,}),}),({"left foot","left leg",4,({64,128,16,32,1,}),}),({"left hand","left arm",4,({4,8,32768,65536,1,}),}),({"left hand","left arm",4,({4,8,32768,65536,1,}),}),}),"Complete":1,]),"troll":(["Size":64,"Btype":1,"Rtype":1,"PlayerFlag":0,"Skills":(["poison bite":({"1","3","2","4",}),]),"Resistance":([2:"low",]),"Stats":(["wisdom":(["Average":5,"Class":5,]),"agility":(["Average":10,"Class":2,]),"speed":(["Average":20,"Class":3,]),"strength":(["Average":50,"Class":1,]),"intelligence":(["Average":11,"Class":3,]),"durability":(["Average":65,"Class":1,]),"charisma":(["Average":11,"Class":3,]),"coordination":(["Average":10,"Class":2,]),"luck":(["Average":15,"Class":4,]),]),"Fingers":(["right hand":4,"left hand":4,]),"Language":"Murdoch","Mass":200,"Sensitivity":({0,10000,}),"Mouthtype":198,"Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),}),"Complete":1,]),"kobold":(["Size":32,"Btype":1,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([4:"medium",2:"medium",16:"low",128:"medium",64:"medium",8:"medium",32:"high",]),"Stats":(["wisdom":(["Average":10,"Class":4,]),"agility":(["Average":21,"Class":3,]),"speed":(["Average":21,"Class":3,]),"strength":(["Average":43,"Class":1,]),"intelligence":(["Average":10,"Class":4,]),"durability":(["Average":43,"Class":1,]),"charisma":(["Average":10,"Class":4,]),"coordination":(["Average":31,"Class":2,]),"luck":(["Average":21,"Class":3,]),]),"Fingers":(["right hand":5,"left hand":5,]),"Language":"Yeik","Mass":1300,"Sensitivity":({20,8000,}),"Mouthtype":198,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"left leg","torso",2,({32,1048576,1024,128,1,}),}),({"left leg","torso",2,({32,1048576,1024,128,1,}),}),({"left arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"left arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right leg","torso",2,({32,1048576,1024,128,1,}),}),({"right leg","torso",2,({32,1048576,1024,128,1,}),}),({"left hand","left arm",4,({4,8,32768,65536,1,}),}),({"left hand","left arm",4,({4,8,32768,65536,1,}),}),({"right hand","right arm",4,({4,8,32768,65536,1,}),}),({"right hand","right arm",4,({4,8,32768,65536,1,}),}),({"left hoof","left leg",4,({}),}),({"left hoof","left leg",4,({}),}),({"right hoof","right leg",4,({}),}),({"right hoof","right leg",4,({}),}),}),"Complete":1,]),"viper":(["Size":16,"Btype":16384,"Rtype":1,"PlayerFlag":0,"Skills":(["poison bite":({"8","1","0","0",}),]),"Resistance":([4:"low",2:"low",16:"low",8:"low",128:"medium",64:"medium",32:"high",]),"Stats":(["wisdom":(["Average":31,"Class":2,]),"agility":(["Average":10,"Class":4,]),"speed":(["Average":10,"Class":4,]),"strength":(["Average":1,"Class":5,]),"intelligence":(["Average":10,"Class":4,]),"durability":(["Average":10,"Class":4,]),"charisma":(["Average":1,"Class":5,]),"coordination":(["Average":1,"Class":5,]),"luck":(["Average":43,"Class":1,]),]),"Fingers":([]),"Language":"Aspish","Mass":30,"Sensitivity":({20,8000,}),"Mouthtype":452,"Limbs":({({"torso",0,1,({16384,1,}),}),({"torso",0,1,({16384,1,}),}),({"head","torso",1,({256,1,}),}),({"head","torso",1,({256,1,}),}),}),"Complete":1,]),"dog":(["Size":32,"Btype":2,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([64:"low",32:"high",]),"Stats":(["wisdom":(["Average":1,"Class":5,]),"agility":(["Average":21,"Class":3,]),"speed":(["Average":21,"Class":3,]),"strength":(["Average":21,"Class":3,]),"intelligence":(["Average":10,"Class":4,]),"durability":(["Average":21,"Class":3,]),"charisma":(["Average":31,"Class":2,]),"coordination":(["Average":10,"Class":4,]),"luck":(["Average":10,"Class":4,]),]),"Fingers":([]),"Language":"Canine","Mass":500,"Sensitivity":({20,8000,}),"Mouthtype":198,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left forepaw","left fore leg",4,({}),}),({"left forepaw","left fore leg",4,({}),}),({"right forepaw","right fore leg",4,({}),}),({"right forepaw","right fore leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),}),"Complete":1,]),"demon":(["Size":128,"Btype":4194304,"Rtype":4,"PlayerFlag":0,"Skills":(["psionic defense":({"8","1","0","0",}),"psionic attack":({"8","1","0","0",}),"psionic detection":({"8","1","0","0",}),]),"Resistance":([64:"low",32:"high",]),"Stats":(["wisdom":(["Average":10,"Class":4,]),"agility":(["Average":31,"Class":2,]),"speed":(["Average":31,"Class":2,]),"strength":(["Average":31,"Class":2,]),"intelligence":(["Average":31,"Class":2,]),"durability":(["Average":31,"Class":2,]),"psi":(["Average":50,"Class":2,]),"charisma":(["Average":31,"Class":2,]),"coordination":(["Average":31,"Class":2,]),"luck":(["Average":43,"Class":1,]),]),"Fingers":([]),"Language":"Demoniac","Mass":250,"Sensitivity":({0,8000,}),"Mouthtype":198,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"left leg","torso",2,({32,1048576,1024,128,1,}),}),({"left leg","torso",2,({32,1048576,1024,128,1,}),}),({"left arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"left arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right leg","torso",2,({32,1048576,1024,128,1,}),}),({"right leg","torso",2,({32,1048576,1024,128,1,}),}),({"right foot","right leg",4,({64,128,16,32,1,}),}),({"right foot","right leg",4,({64,128,16,32,1,}),}),({"right hand","right arm",4,({4,8,32768,65536,1,}),}),({"right hand","right arm",4,({4,8,32768,65536,1,}),}),({"left foot","left leg",4,({64,128,16,32,1,}),}),({"left foot","left leg",4,({64,128,16,32,1,}),}),({"left hand","left arm",4,({4,8,32768,65536,1,}),}),({"left hand","left arm",4,({4,8,32768,65536,1,}),}),}),"Complete":1,]),"unicorn":(["Size":256,"Btype":2,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([4:"low",2:"low",16:"low",8:"low",128:"medium",64:"medium",32:"high",]),"Stats":(["wisdom":(["Average":31,"Class":2,]),"agility":(["Average":31,"Class":2,]),"speed":(["Average":21,"Class":3,]),"strength":(["Average":21,"Class":3,]),"intelligence":(["Average":10,"Class":4,]),"durability":(["Average":21,"Class":3,]),"charisma":(["Average":90,"Class":5,]),"coordination":(["Average":31,"Class":2,]),"luck":(["Average":43,"Class":1,]),]),"Fingers":([]),"Language":"Cornequine","Mass":4000,"Sensitivity":({20,8000,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore hoof","left fore leg",4,({}),}),({"left fore hoof","left fore leg",4,({}),}),({"left rear hoof","left rear leg",4,({}),}),({"left rear hoof","left rear leg",4,({}),}),({"right fore hoof","right fore leg",4,({}),}),({"right fore hoof","right fore leg",4,({}),}),({"right rear hoof","right rear leg",4,({}),}),({"right rear hoof","right rear leg",4,({}),}),}),"Complete":1,]),"sheep":(["Size":32,"Btype":2,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([4:"low",2:"low",16:"low",8:"low",128:"medium",64:"medium",32:"high",]),"Stats":(["wisdom":(["Average":1,"Class":5,]),"agility":(["Average":21,"Class":3,]),"speed":(["Average":10,"Class":4,]),"strength":(["Average":21,"Class":3,]),"intelligence":(["Average":1,"Class":5,]),"durability":(["Average":21,"Class":3,]),"charisma":(["Average":21,"Class":3,]),"coordination":(["Average":10,"Class":4,]),"luck":(["Average":1,"Class":5,]),]),"Fingers":([]),"Language":"Ovine","Mass":1000,"Sensitivity":({20,8000,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore hoof","left fore leg",4,({}),}),({"left fore hoof","left fore leg",4,({}),}),({"left rear hoof","left rear leg",4,({}),}),({"left rear hoof","left rear leg",4,({}),}),({"right fore hoof","right fore leg",4,({}),}),({"right fore hoof","right fore leg",4,({}),}),({"right rear hoof","right rear leg",4,({}),}),({"right rear hoof","right rear leg",4,({}),}),}),"Complete":1,]),"griffin":(["Size":256,"Btype":8388608,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([2:"medium",16:"low",32:"high",64:"high",]),"Stats":(["wisdom":(["Average":10,"Class":4,]),"agility":(["Average":31,"Class":2,]),"speed":(["Average":31,"Class":2,]),"strength":(["Average":43,"Class":1,]),"intelligence":(["Average":1,"Class":5,]),"durability":(["Average":43,"Class":1,]),"charisma":(["Average":1,"Class":5,]),"coordination":(["Average":31,"Class":2,]),"luck":(["Average":43,"Class":1,]),]),"Fingers":([]),"Language":"Griffinish","Mass":3000,"Sensitivity":({20,8000,}),"Mouthtype":72,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left wing","torso",3,({}),}),({"left wing","torso",3,({}),}),({"right wing","torso",3,({}),}),({"right wing","torso",3,({}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left forepaw","left fore leg",4,({}),}),({"left forepaw","left fore leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"right forepaw","right fore leg",4,({}),}),({"right forepaw","right fore leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),}),"Complete":1,]),"giant":(["Size":512,"Btype":1,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([2:"medium",]),"Stats":(["wisdom":(["Average":1,"Class":5,]),"agility":(["Average":2,"Class":5,]),"speed":(["Average":1,"Class":5,]),"strength":(["Average":80,"Class":1,]),"intelligence":(["Average":10,"Class":3,]),"durability":(["Average":70,"Class":1,]),"charisma":(["Average":10,"Class":4,]),"coordination":(["Average":10,"Class":3,]),"luck":(["Average":5,"Class":4,]),]),"Fingers":(["right hand":6,"left hand":6,]),"Language":"Loyavenku","Mass":40000,"Sensitivity":({27,6500,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),}),"Complete":1,]),"bear":(["Size":256,"Btype":8388608,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([64:"low",32:"high",]),"Stats":(["wisdom":(["Average":31,"Class":2,]),"agility":(["Average":1,"Class":5,]),"speed":(["Average":1,"Class":5,]),"strength":(["Average":43,"Class":1,]),"intelligence":(["Average":15,"Class":3,]),"durability":(["Average":43,"Class":1,]),"charisma":(["Average":21,"Class":3,]),"coordination":(["Average":1,"Class":5,]),"luck":(["Average":10,"Class":4,]),]),"Fingers":([]),"Language":"Ursine","Mass":4000,"Sensitivity":({20,8000,}),"Mouthtype":198,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left forepaw","left fore leg",4,({}),}),({"left forepaw","left fore leg",4,({}),}),({"right forepaw","right fore leg",4,({}),}),({"right forepaw","right fore leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),}),"Complete":1,]),"ooga":(["Size":128,"Rtype":1,"Btype":1,"PlayerFlag":1,"Skills":([]),"Resistance":([]),"Stats":(["agility":(["Average":10,"Class":2,]),"wisdom":(["Average":3,"Class":5,]),"speed":(["Average":40,"Class":2,]),"intelligence":(["Average":10,"Class":3,]),"strength":(["Average":35,"Class":1,]),"durability":(["Average":30,"Class":2,]),"charisma":(["Average":1,"Class":5,]),"coordination":(["Average":33,"Class":3,]),"luck":(["Average":6,"Class":4,]),]),"Fingers":(["right hand":6,"left hand":6,]),"Mass":2200,"Language":"Booga","Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),}),"Mouthtype":2118,"Sensitivity":({5,7100,}),"Complete":1,]),"chimera":(["Size":256,"Btype":8192,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([64:"low",32:"high",]),"Stats":(["wisdom":(["Average":21,"Class":3,]),"agility":(["Average":31,"Class":2,]),"speed":(["Average":43,"Class":1,]),"strength":(["Average":21,"Class":3,]),"intelligence":(["Average":21,"Class":3,]),"durability":(["Average":31,"Class":2,]),"charisma":(["Average":1,"Class":5,]),"coordination":(["Average":10,"Class":4,]),"luck":(["Average":10,"Class":4,]),]),"Fingers":([]),"Language":"Chimerole","Mass":500,"Sensitivity":({20,8000,}),"Mouthtype":206,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"lion head","torso",2,({1048576,512,256,8192,1,}),}),({"lion head","torso",2,({1048576,512,256,8192,1,}),}),({"goat head","torso",2,({1048576,512,256,8192,1,}),}),({"goat head","torso",2,({1048576,512,256,8192,1,}),}),({"dragon head","torso",2,({1048576,512,256,8192,1,}),}),({"dragon head","torso",2,({1048576,512,256,8192,1,}),}),({"right wing","torso",3,({}),}),({"right wing","torso",3,({}),}),({"left wing","torso",3,({}),}),({"left wing","torso",3,({}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left forepaw","left fore leg",4,({}),}),({"left forepaw","left fore leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"right forepaw","right fore leg",4,({}),}),({"right forepaw","right fore leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),}),"Complete":1,]),"balrog":(["Size":1024,"Btype":4194304,"Rtype":4,"PlayerFlag":0,"Skills":([]),"Resistance":([128:"high",]),"Stats":(["wisdom":(["Average":10,"Class":3,]),"agility":(["Average":40,"Class":1,]),"speed":(["Average":30,"Class":2,]),"strength":(["Average":30,"Class":3,]),"intelligence":(["Average":30,"Class":2,]),"durability":(["Average":40,"Class":1,]),"charisma":(["Average":1,"Class":5,]),"coordination":(["Average":30,"Class":3,]),"luck":(["Average":20,"Class":3,]),]),"Fingers":(["right hand":6,"left hand":6,]),"Language":"Balrog","Mass":30000,"Sensitivity":({10,6700,}),"Mouthtype":132,"Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),}),"Complete":1,]),"gnome":(["Size":8,"Btype":1,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([]),"Stats":(["wisdom":(["Average":40,"Class":1,]),"agility":(["Average":20,"Class":3,]),"speed":(["Average":20,"Class":2,]),"strength":(["Average":30,"Class":3,]),"intelligence":(["Average":50,"Class":1,]),"durability":(["Average":10,"Class":4,]),"charisma":(["Average":1,"Class":5,]),"coordination":(["Average":35,"Class":3,]),"luck":(["Average":40,"Class":2,]),]),"Fingers":(["right hand":4,"left hand":4,]),"Language":"Kaydiyee","Mass":10,"Sensitivity":({8,6100,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),}),"Complete":1,]),"amphibian":(["Size":8,"Btype":2,"Rtype":3,"PlayerFlag":0,"Skills":([]),"Resistance":([]),"Stats":(["wisdom":(["Average":43,"Class":1,]),"agility":(["Average":10,"Class":4,]),"speed":(["Average":1,"Class":5,]),"strength":(["Average":1,"Class":5,]),"intelligence":(["Average":1,"Class":3,]),"durability":(["Average":21,"Class":3,]),"charisma":(["Average":10,"Class":4,]),"coordination":(["Average":31,"Class":2,]),"luck":(["Average":21,"Class":3,]),]),"Fingers":([]),"Language":"Batrachian","Mass":10,"Sensitivity":({20,8000,}),"Mouthtype":68,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,262144,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left forepaw","left fore leg",4,({}),}),({"left forepaw","left fore leg",4,({}),}),({"right forepaw","right fore leg",4,({}),}),({"right forepaw","right fore leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),}),"Complete":1,]),"vehicle":(["Size":256,"Btype":1048576,"Rtype":4,"PlayerFlag":0,"Skills":([]),"Resistance":([4:"immune",8:"immune",]),"Stats":(["wisdom":(["Average":1,"Class":3,]),"agility":(["Average":50,"Class":3,]),"speed":(["Average":50,"Class":3,]),"strength":(["Average":50,"Class":4,]),"intelligence":(["Average":1,"Class":1,]),"durability":(["Average":50,"Class":4,]),"charisma":(["Average":50,"Class":2,]),"coordination":(["Average":50,"Class":2,]),"luck":(["Average":10,"Class":3,]),]),"Fingers":([]),"Language":"Bocce","Mass":1000,"Sensitivity":({0,100000,}),"Mouthtype":1,"Limbs":({({"fuselage",0,1,({262144,1,}),}),({"fuselage",0,1,({262144,1,}),}),}),"Complete":1,]),"ancap":(["Size":64,"Btype":1,"Rtype":1,"PlayerFlag":1,"Skills":(["psionic defense":({"2","3","4","5",}),]),"Resistance":([]),"Stats":(["wisdom":(["Average":40,"Class":3,]),"agility":(["Average":33,"Class":3,]),"speed":(["Average":30,"Class":3,]),"strength":(["Average":20,"Class":3,]),"intelligence":(["Average":40,"Class":1,]),"durability":(["Average":30,"Class":4,]),"charisma":(["Average":33,"Class":2,]),"coordination":(["Average":33,"Class":2,]),"luck":(["Average":20,"Class":3,]),]),"Fingers":(["right hand":5,"left hand":5,]),"Language":"Capitalist","Mass":1800,"Sensitivity":({25,7500,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),}),"Complete":1,]),"rodent":(["Size":8,"Btype":2,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([4:"low",2:"low",16:"low",8:"low",128:"medium",64:"medium",32:"high",]),"Stats":(["wisdom":(["Average":10,"Class":4,]),"agility":(["Average":21,"Class":3,]),"speed":(["Average":31,"Class":2,]),"strength":(["Average":1,"Class":5,]),"intelligence":(["Average":1,"Class":5,]),"durability":(["Average":10,"Class":4,]),"charisma":(["Average":1,"Class":5,]),"coordination":(["Average":10,"Class":4,]),"luck":(["Average":1,"Class":5,]),]),"Fingers":([]),"Language":"Rodentian","Mass":10,"Sensitivity":({0,8000,}),"Mouthtype":582,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left forepaw","left fore leg",4,({}),}),({"left forepaw","left fore leg",4,({}),}),({"right forepaw","right fore leg",4,({}),}),({"right forepaw","right fore leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),}),"Complete":1,]),"slug":(["Size":8,"Btype":33554432,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([4:"low",2:"low",16:"low",8:"low",128:"medium",64:"medium",32:"high",]),"Stats":(["wisdom":(["Average":10,"Class":4,]),"agility":(["Average":1,"Class":5,]),"speed":(["Average":1,"Class":5,]),"strength":(["Average":10,"Class":4,]),"intelligence":(["Average":1,"Class":5,]),"durability":(["Average":1,"Class":5,]),"charisma":(["Average":1,"Class":5,]),"coordination":(["Average":1,"Class":5,]),"luck":(["Average":1,"Class":5,]),]),"Fingers":([]),"Language":"Clavering","Mass":3,"Sensitivity":({20,8000,}),"Mouthtype":1,"Limbs":({({"torso",0,1,({16384,}),}),({"torso",0,1,({16384,}),}),({"head","torso",1,({256,}),}),({"head","torso",1,({256,}),}),}),"Complete":1,]),"half-orc":(["Size":64,"Btype":1,"Rtype":1,"PlayerFlag":1,"Skills":([]),"Resistance":([]),"Stats":(["wisdom":(["Average":10,"Class":5,]),"agility":(["Average":2,"Class":1,]),"speed":(["Average":70,"Class":1,]),"strength":(["Average":20,"Class":2,]),"intelligence":(["Average":20,"Class":2,]),"durability":(["Average":40,"Class":2,]),"charisma":(["Average":4,"Class":5,]),"coordination":(["Average":20,"Class":3,]),"luck":(["Average":1,"Class":5,]),]),"Fingers":(["right hand":4,"left hand":4,]),"Language":"Tangetto","Mass":2000,"Sensitivity":({12,6200,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),}),"Complete":1,]),"elf":(["Size":64,"Btype":1,"Rtype":1,"PlayerFlag":1,"Skills":([]),"Resistance":([]),"Stats":(["wisdom":(["Average":50,"Class":1,]),"agility":(["Average":40,"Class":3,]),"speed":(["Average":40,"Class":3,]),"strength":(["Average":15,"Class":5,]),"intelligence":(["Average":50,"Class":1,]),"durability":(["Average":20,"Class":4,]),"charisma":(["Average":40,"Class":1,]),"coordination":(["Average":10,"Class":2,]),"luck":(["Average":50,"Class":1,]),]),"Fingers":(["right hand":5,"left hand":5,]),"Language":"Edhellen","Mass":1500,"Sensitivity":({7,7300,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),}),"Complete":1,]),"primate":(["Size":16,"Btype":8388608,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([4:"low",2:"low",16:"low",8:"low",128:"medium",64:"medium",32:"high",]),"Stats":(["wisdom":(["Average":10,"Class":4,]),"agility":(["Average":21,"Class":3,]),"speed":(["Average":21,"Class":3,]),"strength":(["Average":10,"Class":4,]),"intelligence":(["Average":21,"Class":3,]),"durability":(["Average":10,"Class":4,]),"charisma":(["Average":15,"Class":3,]),"coordination":(["Average":21,"Class":3,]),"luck":(["Average":21,"Class":3,]),]),"Fingers":([]),"Language":"Proto","Mass":1500,"Sensitivity":({20,8000,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"left leg","torso",2,({32,1048576,1024,128,1,}),}),({"left leg","torso",2,({32,1048576,1024,128,1,}),}),({"left arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"left arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right leg","torso",2,({32,1048576,1024,128,1,}),}),({"right leg","torso",2,({32,1048576,1024,128,1,}),}),({"right foot","right leg",4,({64,128,16,32,1,}),}),({"right foot","right leg",4,({64,128,16,32,1,}),}),({"right hand","right arm",4,({4,8,32768,65536,1,}),}),({"right hand","right arm",4,({4,8,32768,65536,1,}),}),({"left foot","left leg",4,({64,128,16,32,1,}),}),({"left foot","left leg",4,({64,128,16,32,1,}),}),({"left hand","left arm",4,({4,8,32768,65536,1,}),}),({"left hand","left arm",4,({4,8,32768,65536,1,}),}),}),"Complete":1,]),"lizard":(["Size":8,"Btype":2,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([4:"medium",2:"medium",16:"low",128:"medium",64:"medium",8:"medium",32:"high",]),"Stats":(["wisdom":(["Average":1,"Class":5,]),"agility":(["Average":21,"Class":3,]),"speed":(["Average":21,"Class":3,]),"strength":(["Average":21,"Class":3,]),"intelligence":(["Average":1,"Class":5,]),"durability":(["Average":21,"Class":3,]),"charisma":(["Average":10,"Class":4,]),"coordination":(["Average":21,"Class":3,]),"luck":(["Average":10,"Class":4,]),]),"Fingers":([]),"Language":"Reptilian","Mass":10,"Sensitivity":({20,8000,}),"Mouthtype":68,"Limbs":({({"torso",0,1,({262144,}),}),({"torso",0,1,({262144,}),}),({"neck","torso",1,({524288,262144,}),}),({"neck","torso",1,({524288,262144,}),}),({"head","neck",1,({256,512,262144,}),}),({"head","neck",1,({256,512,262144,}),}),({"left forepaw","left fore leg",4,({}),}),({"left forepaw","left fore leg",4,({}),}),({"right forepaw","right fore leg",4,({}),}),({"right forepaw","right fore leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),}),"Complete":1,]),"gargoyle":(["Size":32,"Btype":4194304,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([2:"low",16:"low",64:"low",32:"high",]),"Stats":(["wisdom":(["Average":31,"Class":2,]),"agility":(["Average":1,"Class":5,]),"speed":(["Average":10,"Class":4,]),"strength":(["Average":43,"Class":1,]),"intelligence":(["Average":10,"Class":4,]),"durability":(["Average":43,"Class":1,]),"charisma":(["Average":1,"Class":5,]),"coordination":(["Average":31,"Class":2,]),"luck":(["Average":10,"Class":4,]),]),"Fingers":([]),"Language":"Gargoyleish","Mass":3000,"Sensitivity":({20,8000,}),"Mouthtype":72,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"left arm","torso",3,({8,4096,131072,1048576,65536,1,}),}),({"left arm","torso",3,({8,4096,131072,1048576,65536,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right arm","torso",3,({8,4096,131072,1048576,65536,1,}),}),({"right arm","torso",3,({8,4096,131072,1048576,65536,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left wing","torso",3,({}),}),({"left wing","torso",3,({}),}),({"right wing","torso",3,({}),}),({"right wing","torso",3,({}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left forepaw","left fore leg",4,({}),}),({"left forepaw","left fore leg",4,({}),}),({"left hand","left arm",4,({4,8,32768,65536,1,}),}),({"left hand","left arm",4,({4,8,32768,65536,1,}),}),({"right forepaw","right fore leg",4,({}),}),({"right forepaw","right fore leg",4,({}),}),({"right hand","right arm",4,({4,8,32768,65536,1,}),}),({"right hand","right arm",4,({4,8,32768,65536,1,}),}),({"left rear paw","left rear leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),}),"Complete":1,]),"fish":(["Size":16,"Btype":1024,"Rtype":2,"PlayerFlag":0,"Skills":([]),"Resistance":([2:"low",16:"low",64:"low",32:"high",]),"Stats":(["wisdom":(["Average":21,"Class":3,]),"agility":(["Average":31,"Class":2,]),"speed":(["Average":21,"Class":3,]),"strength":(["Average":10,"Class":4,]),"intelligence":(["Average":1,"Class":5,]),"durability":(["Average":10,"Class":4,]),"charisma":(["Average":1,"Class":5,]),"coordination":(["Average":31,"Class":2,]),"luck":(["Average":1,"Class":5,]),]),"Fingers":([]),"Language":"Ichthine","Mass":200,"Sensitivity":({20,8000,}),"Mouthtype":64,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,}),}),({"head","torso",1,({1048576,512,256,8192,}),}),({"head","torso",1,({1048576,512,256,8192,}),}),}),"Complete":1,]),"strider":(["Size":512,"Btype":1,"Rtype":4,"PlayerFlag":0,"Skills":([]),"Resistance":([4:"immune",8:"immune",]),"Stats":(["wisdom":(["Average":1,"Class":3,]),"agility":(["Average":50,"Class":1,]),"speed":(["Average":90,"Class":1,]),"strength":(["Average":90,"Class":1,]),"intelligence":(["Average":1,"Class":3,]),"durability":(["Average":50,"Class":4,]),"charisma":(["Average":1,"Class":3,]),"coordination":(["Average":50,"Class":1,]),"luck":(["Average":10,"Class":3,]),]),"Fingers":(["right hand":5,"left hand":5,]),"Language":"English","Mass":10000,"Sensitivity":({0,20000,}),"Mouthtype":1,"Limbs":({({"turret",0,1,({262144,1,}),}),({"turret",0,1,({262144,1,}),}),({"right leg","turret",2,({1,}),}),({"right leg","turret",2,({1,}),}),({"left leg","turret",2,({1,}),}),({"left leg","turret",2,({1,}),}),({"right foot","right leg",4,({1,}),}),({"right foot","right leg",4,({1,}),}),({"left foot","left leg",4,({1,}),}),({"left foot","left leg",4,({1,}),}),({"right arm","turret",2,({1,}),}),({"right arm","turret",2,({1,}),}),({"left arm","turret",2,({1,}),}),({"left arm","turret",2,({1,}),}),({"right hand","right arm",4,({32768,1,}),}),({"right hand","right arm",4,({32768,1,}),}),({"left hand","left arm",4,({32768,1,}),}),({"left hand","left arm",4,({32768,1,}),}),}),"Complete":1,]),"faerie":(["Size":4,"Btype":4194304,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([16:"low",]),"Stats":(["wisdom":(["Average":15,"Class":2,]),"agility":(["Average":60,"Class":1,]),"speed":(["Average":40,"Class":2,]),"strength":(["Average":5,"Class":5,]),"intelligence":(["Average":10,"Class":2,]),"durability":(["Average":10,"Class":5,]),"charisma":(["Average":30,"Class":3,]),"coordination":(["Average":40,"Class":1,]),"luck":(["Average":30,"Class":2,]),]),"Fingers":(["right hand":5,"left hand":5,]),"Language":"Elcharean","Mass":5,"Sensitivity":({30,8000,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left arm","torso",3,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",3,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",3,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",3,({8,65536,8192,131072,1048576,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),}),"Complete":1,]),"blob":(["Size":16,"Btype":16384,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([]),"Stats":(["wisdom":(["Average":1,"Class":5,]),"agility":(["Average":1,"Class":5,]),"speed":(["Average":1,"Class":5,]),"strength":(["Average":1,"Class":5,]),"intelligence":(["Average":1,"Class":5,]),"durability":(["Average":1,"Class":5,]),"charisma":(["Average":1,"Class":5,]),"coordination":(["Average":1,"Class":5,]),"luck":(["Average":1,"Class":5,]),]),"Fingers":([]),"Language":"creosote","Mass":40,"Sensitivity":({20,8000,}),"Mouthtype":68,"Limbs":({({"torso",0,1,({16384,}),}),({"torso",0,1,({16384,}),}),({"head","torso",1,({256,}),}),({"head","torso",1,({256,}),}),}),"Complete":1,]),"insect":(["Size":2,"Btype":16,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([2:"medium",16:"low",64:"low",32:"high",]),"Stats":(["wisdom":(["Average":1,"Class":5,]),"agility":(["Average":31,"Class":2,]),"speed":(["Average":43,"Class":1,]),"strength":(["Average":1,"Class":5,]),"intelligence":(["Average":1,"Class":5,]),"durability":(["Average":1,"Class":5,]),"charisma":(["Average":1,"Class":5,]),"coordination":(["Average":21,"Class":3,]),"luck":(["Average":43,"Class":1,]),]),"Fingers":([]),"Language":"Insectoid","Mass":1,"Sensitivity":({20,8000,}),"Mouthtype":16,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"head","torso",1,({1048576,512,256,8192,1,}),}),({"head","torso",1,({1048576,512,256,8192,1,}),}),({"4th leg","torso",3,({32,1048576,1024,128,1,}),}),({"4th leg","torso",3,({32,1048576,1024,128,1,}),}),({"6th leg","torso",3,({32,1048576,1024,128,1,}),}),({"6th leg","torso",3,({32,1048576,1024,128,1,}),}),({"5th leg","torso",3,({32,1048576,1024,128,1,}),}),({"5th leg","torso",3,({32,1048576,1024,128,1,}),}),({"1st leg","torso",3,({32,1048576,1024,128,1,}),}),({"1st leg","torso",3,({32,1048576,1024,128,1,}),}),({"3rd leg","torso",3,({32,1048576,1024,128,1,}),}),({"3rd leg","torso",3,({32,1048576,1024,128,1,}),}),({"2nd leg","torso",3,({32,1048576,1024,128,1,}),}),({"2nd leg","torso",3,({32,1048576,1024,128,1,}),}),}),"Complete":1,]),"bot":(["Size":32,"Btype":1048576,"Rtype":4,"PlayerFlag":0,"Skills":([]),"Resistance":([]),"Stats":(["wisdom":(["Average":50,"Class":3,]),"agility":(["Average":50,"Class":3,]),"speed":(["Average":50,"Class":3,]),"strength":(["Average":50,"Class":4,]),"intelligence":(["Average":50,"Class":1,]),"durability":(["Average":50,"Class":4,]),"charisma":(["Average":50,"Class":2,]),"coordination":(["Average":50,"Class":2,]),"luck":(["Average":10,"Class":3,]),]),"Fingers":([]),"Language":"Bocce","Mass":1000,"Sensitivity":({0,10000,}),"Mouthtype":1024,"Limbs":({({"torso",0,1,({262144,1,}),}),({"torso",0,1,({262144,1,}),}),}),"Complete":1,]),"elemental":(["Size":256,"Btype":4096,"Rtype":4,"PlayerFlag":0,"Skills":([]),"Resistance":([2:"low",64:"low",32:"high",]),"Stats":(["wisdom":(["Average":21,"Class":3,]),"agility":(["Average":21,"Class":3,]),"speed":(["Average":21,"Class":3,]),"strength":(["Average":21,"Class":3,]),"intelligence":(["Average":21,"Class":3,]),"durability":(["Average":21,"Class":3,]),"charisma":(["Average":21,"Class":3,]),"coordination":(["Average":21,"Class":3,]),"luck":(["Average":21,"Class":3,]),]),"Fingers":([]),"Language":"Periodict","Mass":40000,"Sensitivity":({20,8000,}),"Mouthtype":1,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"head","torso",1,({1048576,512,256,8192,1,}),}),({"head","torso",1,({1048576,512,256,8192,1,}),}),}),"Complete":1,]),"avidryl":(["Size":64,"Btype":4194304,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([]),"Stats":(["wisdom":(["Average":10,"Class":5,]),"agility":(["Average":50,"Class":1,]),"speed":(["Average":20,"Class":3,]),"strength":(["Average":40,"Class":2,]),"intelligence":(["Average":15,"Class":4,]),"durability":(["Average":20,"Class":2,]),"charisma":(["Average":20,"Class":3,]),"coordination":(["Average":30,"Class":1,]),"luck":(["Average":2,"Class":5,]),]),"Fingers":(["right hand":5,"left hand":5,]),"Language":"Avidryl","Mass":1500,"Sensitivity":({15,8500,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,1,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,1,}),}),({"head","torso",1,({256,512,262144,1,}),}),({"head","torso",1,({256,512,262144,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,8192,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,8192,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,8192,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,8192,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"right wing","torso",4,({}),}),({"right wing","torso",4,({}),}),({"left wing","torso",4,({}),}),({"left wing","torso",4,({}),}),}),"Complete":1,]),"gnoll":(["Size":32,"Btype":1,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([2:"medium",16:"low",32:"high",64:"high",]),"Stats":(["wisdom":(["Average":10,"Class":4,]),"agility":(["Average":31,"Class":2,]),"speed":(["Average":21,"Class":3,]),"strength":(["Average":21,"Class":3,]),"intelligence":(["Average":10,"Class":4,]),"durability":(["Average":21,"Class":3,]),"charisma":(["Average":1,"Class":5,]),"coordination":(["Average":31,"Class":2,]),"luck":(["Average":31,"Class":2,]),]),"Fingers":([]),"Language":"Kaydoch","Mass":1200,"Sensitivity":({20,800,}),"Mouthtype":2118,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"left leg","torso",2,({32,1048576,1024,128,1,}),}),({"left leg","torso",2,({32,1048576,1024,128,1,}),}),({"left arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"left arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right leg","torso",2,({32,1048576,1024,128,1,}),}),({"right leg","torso",2,({32,1048576,1024,128,1,}),}),({"right foot","right leg",4,({64,128,16,32,1,}),}),({"right foot","right leg",4,({64,128,16,32,1,}),}),({"right hand","right arm",4,({4,8,32768,65536,1,}),}),({"right hand","right arm",4,({4,8,32768,65536,1,}),}),({"left foot","left leg",4,({64,128,16,32,1,}),}),({"left foot","left leg",4,({64,128,16,32,1,}),}),({"left hand","left arm",4,({4,8,32768,65536,1,}),}),({"left hand","left arm",4,({4,8,32768,65536,1,}),}),}),"Complete":1,]),"dragon":(["Size":512,"Btype":8388608,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([64:"low",32:"high",]),"Stats":(["wisdom":(["Average":43,"Class":1,]),"agility":(["Average":43,"Class":1,]),"speed":(["Average":21,"Class":3,]),"strength":(["Average":43,"Class":1,]),"intelligence":(["Average":31,"Class":2,]),"durability":(["Average":43,"Class":1,]),"charisma":(["Average":31,"Class":2,]),"coordination":(["Average":21,"Class":3,]),"luck":(["Average":43,"Class":1,]),]),"Fingers":([]),"Language":"Dragonate","Mass":40000,"Sensitivity":({0,8000,}),"Mouthtype":196,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left wing","torso",3,({}),}),({"left wing","torso",3,({}),}),({"right wing","torso",3,({}),}),({"right wing","torso",3,({}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left forepaw","left fore leg",4,({}),}),({"left forepaw","left fore leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"left rear paw","left rear leg",4,({}),}),({"right forepaw","right fore leg",4,({}),}),({"right forepaw","right fore leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),({"right rear paw","right rear leg",4,({}),}),}),"Complete":1,]),"bat":(["Size":8,"Btype":8,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([]),"Stats":(["wisdom":(["Average":10,"Class":5,]),"agility":(["Average":10,"Class":2,]),"speed":(["Average":52,"Class":3,]),"strength":(["Average":13,"Class":4,]),"intelligence":(["Average":1,"Class":3,]),"durability":(["Average":65,"Class":1,]),"charisma":(["Average":11,"Class":3,]),"coordination":(["Average":10,"Class":2,]),"luck":(["Average":24,"Class":3,]),]),"Fingers":([]),"Language":"Murcielago","Mass":10,"Sensitivity":({15,6500,}),"Mouthtype":710,"Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,1,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,1,}),}),({"head","torso",1,({256,512,262144,1,}),}),({"head","torso",1,({256,512,262144,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"right claw","right leg",4,({16,32,64,128,1,}),}),({"right claw","right leg",4,({16,32,64,128,1,}),}),({"left claw","left leg",4,({16,32,64,128,1,}),}),({"left claw","left leg",4,({16,32,64,128,1,}),}),({"left wing","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left wing","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right wing","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right wing","torso",2,({8,65536,8192,131072,1048576,1,}),}),}),"Complete":1,]),"centaur":(["Size":256,"Btype":8388608,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([64:"low",32:"high",]),"Stats":(["wisdom":(["Average":31,"Class":2,]),"agility":(["Average":21,"Class":3,]),"speed":(["Average":31,"Class":2,]),"strength":(["Average":31,"Class":2,]),"intelligence":(["Average":21,"Class":3,]),"durability":(["Average":43,"Class":1,]),"charisma":(["Average":21,"Class":3,]),"coordination":(["Average":10,"Class":4,]),"luck":(["Average":43,"Class":1,]),]),"Fingers":(["right hand":5,"left hand":5,]),"Language":"Centaurian","Mass":3000,"Sensitivity":({20,8000,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"lower torso","torso",1,({}),}),({"lower torso","torso",1,({}),}),({"right arm","torso",2,({}),}),({"right arm","torso",2,({}),}),({"left arm","",0,({2,}),}),({"left arm","",0,({2,}),}),({"right fore leg","lower torso",3,({}),}),({"right fore leg","lower torso",3,({}),}),({"left fore leg","lower torso",3,({}),}),({"left fore leg","lower torso",3,({}),}),({"right back leg","lower torso",3,({}),}),({"right back leg","lower torso",3,({}),}),({"left back leg","lower torso",3,({}),}),({"left back leg","lower torso",3,({}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"right fore hoof","right fore leg",4,({}),}),({"right fore hoof","right fore leg",4,({}),}),({"left fore hoof","left fore leg",4,({}),}),({"left fore hoof","left fore leg",4,({}),}),({"right back hoof","right back leg",4,({}),}),({"right back hoof","right back leg",4,({}),}),({"left back hoof","left back leg",4,({}),}),({"left back hoof","left back leg",4,({}),}),}),"Complete":1,]),"dryad":(["Size":16,"Btype":1,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([64:"low",32:"high",]),"Stats":(["wisdom":(["Average":31,"Class":2,]),"agility":(["Average":31,"Class":2,]),"speed":(["Average":31,"Class":2,]),"strength":(["Average":10,"Class":4,]),"intelligence":(["Average":10,"Class":4,]),"durability":(["Average":1,"Class":5,]),"charisma":(["Average":43,"Class":1,]),"coordination":(["Average":21,"Class":3,]),"luck":(["Average":31,"Class":2,]),]),"Fingers":(["right hand":5,"left hand":5,]),"Language":"Vadinho","Mass":100,"Sensitivity":({20,8000,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"left leg","torso",2,({32,1048576,1024,128,1,}),}),({"left leg","torso",2,({32,1048576,1024,128,1,}),}),({"left arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"left arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right leg","torso",2,({32,1048576,1024,128,1,}),}),({"right leg","torso",2,({32,1048576,1024,128,1,}),}),({"right foot","right leg",4,({64,128,16,32,1,}),}),({"right foot","right leg",4,({64,128,16,32,1,}),}),({"right hand","right arm",4,({4,8,32768,65536,1,}),}),({"right hand","right arm",4,({4,8,32768,65536,1,}),}),({"left foot","left leg",4,({64,128,16,32,1,}),}),({"left foot","left leg",4,({64,128,16,32,1,}),}),({"left hand","left arm",4,({4,8,32768,65536,1,}),}),({"left hand","left arm",4,({4,8,32768,65536,1,}),}),}),"Complete":1,]),"pig":(["Size":32,"Btype":2,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([4:"low",2:"low",16:"low",8:"low",128:"medium",64:"medium",32:"high",]),"Stats":(["wisdom":(["Average":31,"Class":2,]),"agility":(["Average":1,"Class":5,]),"speed":(["Average":10,"Class":4,]),"strength":(["Average":21,"Class":3,]),"intelligence":(["Average":15,"Class":2,]),"durability":(["Average":43,"Class":1,]),"charisma":(["Average":1,"Class":5,]),"coordination":(["Average":21,"Class":3,]),"luck":(["Average":1,"Class":5,]),]),"Fingers":([]),"Language":"Porcine","Mass":1500,"Sensitivity":({20,8000,}),"Mouthtype":2118,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore hoof","left fore leg",4,({}),}),({"left fore hoof","left fore leg",4,({}),}),({"left rear hoof","left rear leg",4,({}),}),({"left rear hoof","left rear leg",4,({}),}),({"right fore hoof","right fore leg",4,({}),}),({"right fore hoof","right fore leg",4,({}),}),({"right rear hoof","right rear leg",4,({}),}),({"right rear hoof","right rear leg",4,({}),}),}),"Complete":1,]),"pegasus":(["Size":256,"Btype":2,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([4:"low",2:"low",16:"low",8:"low",128:"medium",64:"medium",32:"high",]),"Stats":(["wisdom":(["Average":31,"Class":2,]),"agility":(["Average":43,"Class":1,]),"speed":(["Average":31,"Class":2,]),"strength":(["Average":31,"Class":2,]),"intelligence":(["Average":21,"Class":3,]),"durability":(["Average":31,"Class":2,]),"charisma":(["Average":43,"Class":1,]),"coordination":(["Average":31,"Class":2,]),"luck":(["Average":43,"Class":1,]),]),"Fingers":([]),"Language":"Voloquine","Mass":3000,"Sensitivity":({20,8000,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left wing","torso",3,({}),}),({"left wing","torso",3,({}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"right fore leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"left rear leg","torso",3,({32,1048576,1024,128,1,}),}),({"right wing","torso",3,({}),}),({"right wing","torso",3,({}),}),({"right rear hoof","right rear leg",4,({}),}),({"right rear hoof","right rear leg",4,({}),}),({"left fore hoof","left fore leg",4,({}),}),({"left fore hoof","left fore leg",4,({}),}),({"left rear hoof","left rear leg",4,({}),}),({"left rear hoof","left rear leg",4,({}),}),({"right fore hoof","right fore leg",4,({}),}),({"right fore hoof","right fore leg",4,({}),}),}),"Complete":1,]),"replicant":(["Size":64,"Btype":1,"Rtype":1,"PlayerFlag":0,"Skills":(["psionic defense":({"2","3","4","5",}),]),"Resistance":([]),"Stats":(["wisdom":(["Average":1,"Class":3,]),"agility":(["Average":40,"Class":3,]),"speed":(["Average":40,"Class":3,]),"strength":(["Average":40,"Class":4,]),"intelligence":(["Average":10,"Class":1,]),"durability":(["Average":40,"Class":4,]),"charisma":(["Average":40,"Class":2,]),"coordination":(["Average":40,"Class":2,]),"luck":(["Average":1,"Class":3,]),]),"Fingers":(["right hand":5,"left hand":5,]),"Language":"English","Mass":1800,"Sensitivity":({5,8500,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),}),"Complete":1,]),"demi-god":(["Size":64,"Btype":1,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([134217726:"high",64:"low",32:"high",]),"Stats":(["wisdom":(["Average":31,"Class":2,]),"agility":(["Average":31,"Class":2,]),"speed":(["Average":43,"Class":1,]),"strength":(["Average":31,"Class":2,]),"intelligence":(["Average":31,"Class":2,]),"durability":(["Average":31,"Class":2,]),"charisma":(["Average":31,"Class":2,]),"coordination":(["Average":31,"Class":2,]),"luck":(["Average":43,"Class":1,]),]),"Fingers":(["right hand":5,"left hand":5,]),"Language":"Sublime","Mass":2000,"Sensitivity":({10,8000,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"torso",0,1,({131072,1048576,8192,16384,4096,262144,2048,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"left leg","torso",2,({32,1048576,1024,128,1,}),}),({"left leg","torso",2,({32,1048576,1024,128,1,}),}),({"left arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"left arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right arm","torso",2,({8,4096,131072,1048576,65536,1,}),}),({"right leg","torso",2,({32,1048576,1024,128,1,}),}),({"right leg","torso",2,({32,1048576,1024,128,1,}),}),({"right foot","right leg",4,({64,128,16,32,1,}),}),({"right foot","right leg",4,({64,128,16,32,1,}),}),({"right hand","right arm",4,({4,8,32768,65536,1,}),}),({"right hand","right arm",4,({4,8,32768,65536,1,}),}),({"left foot","left leg",4,({64,128,16,32,1,}),}),({"left foot","left leg",4,({64,128,16,32,1,}),}),({"left hand","left arm",4,({4,8,32768,65536,1,}),}),({"left hand","left arm",4,({4,8,32768,65536,1,}),}),}),"Complete":1,]),"ogre":(["Size":256,"Btype":1,"Rtype":1,"PlayerFlag":0,"Skills":([]),"Resistance":([4:"low",2:"low",8:"low",]),"Stats":(["wisdom":(["Average":1,"Class":5,]),"agility":(["Average":1,"Class":5,]),"speed":(["Average":7,"Class":4,]),"strength":(["Average":50,"Class":1,]),"intelligence":(["Average":10,"Class":4,]),"durability":(["Average":68,"Class":1,]),"charisma":(["Average":1,"Class":5,]),"coordination":(["Average":2,"Class":5,]),"luck":(["Average":1,"Class":5,]),]),"Fingers":(["right hand":6,"left hand":6,]),"Language":"Shangtai","Mass":4000,"Sensitivity":({25,7000,}),"Mouthtype":2246,"Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),}),"Complete":1,]),"nymph":(["Size":32,"Btype":1,"Rtype":3,"PlayerFlag":0,"Skills":([]),"Resistance":([]),"Stats":(["wisdom":(["Average":20,"Class":4,]),"agility":(["Average":50,"Class":1,]),"speed":(["Average":60,"Class":2,]),"strength":(["Average":3,"Class":5,]),"intelligence":(["Average":25,"Class":4,]),"durability":(["Average":7,"Class":5,]),"charisma":(["Average":80,"Class":1,]),"coordination":(["Average":20,"Class":2,]),"luck":(["Average":50,"Class":2,]),]),"Fingers":(["right hand":5,"left hand":5,]),"Language":"Nymal","Mass":140,"Sensitivity":({26,7600,}),"Mouthtype":70,"Limbs":({({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"torso",0,1,({4096,8192,16384,65536,131072,1048576,2048,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"neck","torso",1,({524288,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"head","neck",1,({256,512,262144,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"right leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"left leg","torso",2,({32,128,1024,1048576,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"right foot","right leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left foot","left leg",4,({16,32,64,128,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"right arm","torso",2,({8,65536,8192,131072,1048576,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"left hand","left arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),({"right hand","right arm",4,({2,4,8,32768,65536,1,}),}),}),"Complete":1,]),]) +FlyingRaces ({"avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","pegasus","vehicle","wraith","avidryl","bat","bird","bot","demon","dragon","faerie","gargoyle","griffin","insect","isopod","pegasus","vehicle","wraith",}) +LimblessCombatRaces ({"android","blob","bot","elemental","fish","god","mech","plant","slug","snake","strider","tree","vehicle","viper",}) +LimblessRaces ({"blob","elemental","fish","slug","snake","viper",}) +NonBitingRaces ({"android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","dark-elf","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","dark-elf","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan","android","bot","cow","deer","dummy","elemental","elf","faerie","god","golem","mech","plant","strider","vehicle","vulcan",}) +SwimmingRaces ({"amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","dark-elf","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","dark-elf","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","amphibian","android","artrell","bear","bot","bugbear","cat","demi-god","demon","dragon","elephant","elf","fish","giant","gnoll","gnome","goblin","god","half-elf","halfling","hobbit","human","kender","lizard","nymph","replicant","rodent","troll","vehicle","vulcan","ancap",}) +NonMeatRaces ({"android","balrog","bot","dummy","elemental","god","golem","mech","plant","strider","tree","vehicle","wraith",}) diff --git a/lib/save/rooms.o b/lib/save/rooms.o new file mode 100644 index 0000000..6423052 --- /dev/null +++ b/lib/save/rooms.o @@ -0,0 +1,7 @@ +#/secure/daemon/rooms.c +PersistentInventory 0 +PersistentInventoryEnabled 0 +Workrooms ([]) +WorldMap (["/domains/begin/room":(["start":(["date":1599393238,"exits":(["south":"/domains/default/room/wiz_hall","fly":"","sink":"",]),"coords":(["z":0,"y":5000,"x":5000,]),]),]),"/domains/Ylsrim/room":(["bazaar":(["date":1599393287,"exits":(["south":"/domains/Ylsrim/room/s_bazaar","north":"/domains/Ylsrim/room/kaliid4","fly":"/domains/town/virtual/sky/0,0,1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"fighter_hall":(["date":1599393288,"exits":(["south":"/domains/Ylsrim/room/kaliid5","north":"/domains/Ylsrim/room/fighter","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"pub":(["date":1599393297,"exits":(["east":"/domains/Ylsrim/room/s_bazaar","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"s_bazaar":(["date":1599393297,"exits":(["north":"/domains/Ylsrim/room/bazaar","fly":"/domains/town/virtual/sky/0,0,1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"sand_room":(["date":1599393298,"exits":(["fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"adv_hall":(["date":1599393258,"exits":(["south":"/domains/Ylsrim/room/kaliid4","fly":"","sink":"","up":"/domains/Ylsrim/room/tower",]),"coords":(["z":0,"y":0,"x":0,]),]),"kaliid7":(["date":1599393298,"exits":(["east":"/domains/Ylsrim/room/kaliid6","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Ylsrim/room/sand_room","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"kaliid6":(["date":1599393288,"exits":(["east":"/domains/Ylsrim/room/kaliid5","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Ylsrim/room/kaliid7","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"kaliid5":(["date":1599393278,"exits":(["north":"/domains/Ylsrim/room/fighter_hall","east":"/domains/Ylsrim/room/kaliid4","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Ylsrim/room/kaliid6","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"kaliid4":(["date":1599393268,"exits":(["north":"/domains/Ylsrim/room/adv_hall","south":"/domains/Ylsrim/room/bazaar","east":"/domains/Ylsrim/room/kaliid3","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Ylsrim/room/kaliid5","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"fighter":(["date":1599393288,"exits":(["south":"/domains/Ylsrim/room/fighter_hall","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"church":(["date":1599393278,"exits":(["south":"/domains/Ylsrim/room/kaliid3","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"kaliid3":(["date":1599393278,"exits":(["north":"/domains/Ylsrim/room/church","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Ylsrim/room/kaliid4","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"tower":(["date":1599393238,"exits":(["down":"/domains/Ylsrim/room/adv_hall","fly":"","sink":"",]),"coords":(["z":1,"y":1001,"x":1000,]),]),]),"/domains/learning/room":(["start":(["date":1599393238,"exits":(["fly":"","sink":"",]),"coords":(["z":0,"y":2000,"x":2000,]),]),]),"/domains/Praxis":(["hall2":(["date":1599393288,"exits":(["south":"/domains/Praxis/hall","north":"/domains/Praxis/hall3","east":"/domains/Praxis/inn103","fly":"","west":"/domains/Praxis/inn104","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"wall":(["date":1599393298,"exits":(["south":"/domains/Praxis/alley2","fly":0,"sink":0,]),"coords":(["z":0,"y":0,"x":0,]),]),"pub":(["date":1599393258,"exits":(["north":"/domains/Praxis/w_boc_la1","east":"/domains/Praxis/s_centre1","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"adv_main":(["date":1599393278,"exits":(["south":"/domains/Praxis/adv_inner","north":"/domains/Praxis/e_boc_la2","east":"/domains/Praxis/lpmud_room","down":"/domains/Praxis/ombud_hall","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"ombud_hall":(["date":1599393288,"exits":(["fly":"","west":"/domains/Praxis/hm_chamber","sink":"","up":"/domains/Praxis/adv_main",]),"coords":(["z":0,"y":0,"x":0,]),]),"pass3":(["date":1599393328,"exits":(["east":"/domains/Praxis/pass2","fly":"/domains/town/virtual/sky/0,0,1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"monastery":(["date":1599393268,"exits":(["north":"/domains/Praxis/chapel","south":"/domains/Praxis/e_boc_la1","east":"/domains/Praxis/stairs","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"pass2":(["date":1599393338,"exits":(["north":"/domains/Praxis/mountains/entrance","southeast":"/domains/Praxis/pass1","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Praxis/pass3","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"chapel":(["date":1599393268,"exits":(["south":"/domains/Praxis/monastery","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"pass1":(["date":1599393318,"exits":(["east":"/domains/Praxis/highway3","fly":"/domains/town/virtual/sky/0,0,1","northwest":"/domains/Praxis/pass2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"highway3":(["date":1599393318,"exits":(["north":"/domains/Praxis/orc_valley/guard","east":"/domains/Praxis/highway2","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Praxis/pass1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"sewer_ent":(["date":1599393288,"exits":(["east":"/domains/Praxis/sewer","fly":"","sink":"","up":"/domains/Praxis/yard",]),"coords":(["z":0,"y":0,"x":0,]),]),"monk_join":(["date":1599393288,"exits":(["east":"/domains/Praxis/monk_hall","down":"/domains/Praxis/stairs","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"rogue_vote":(["date":1599393338,"exits":(["fly":"","west":"/domains/Praxis/rogue_hall","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"highway2":(["date":1599393298,"exits":(["east":"/domains/Praxis/highway1","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Praxis/highway3","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"sheriff":(["date":1599393288,"exits":(["south":"//domains/Praxis/yard","fly":"","west":"//domains/Praxis/court_room","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"highway1":(["date":1599393288,"exits":(["east":"/domains/Praxis/w_boc_la3","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Praxis/highway2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"east_road3":(["date":1599393298,"exits":(["south":"/domains/Praxis/east_road2","fly":"/domains/town/virtual/sky/0,0,1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"immortal_hall":(["date":1599393278,"exits":(["fly":"","sink":"","up":"/domains/Praxis/stairs",]),"coords":(["z":0,"y":0,"x":0,]),]),"rain_forest":(["date":1599393318,"exits":(["east":"/domains/Praxis/rogue_join","fly":"/domains/town/virtual/sky/0,0,1","southwest":"/domains/Praxis/jungle","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"east_road2":(["date":1599393308,"exits":(["south":"/domains/Praxis/east_road1","north":"/domains/Praxis/east_road3","east":"/domains/Praxis/cemetery/grave_yard","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Praxis/sun2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"east_road1":(["date":1599393288,"exits":(["south":"/domains/Praxis/e_boc_la3","north":"/domains/Praxis/east_road2","east":"/domains/Praxis/library","fly":"/domains/town/virtual/sky/0,0,1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"fighter_vote":(["date":1599393308,"exits":(["fly":"","west":"/domains/Praxis/fighter_hall","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"hm_chamber":(["date":1599393288,"exits":(["east":"/domains/Praxis/ombud_hall","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"dump":(["date":1599393288,"exits":(["east":"/domains/Praxis/alley2","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"medium":(["date":1599393298,"exits":(["fly":"","west":"/domains/Praxis/west_road2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"w_boc_la3":(["date":1599393278,"exits":(["north":"/domains/Praxis/west_road1","east":"/domains/Praxis/w_boc_la2","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Praxis/highway1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"w_boc_la2":(["date":1599393268,"exits":(["north":"/domains/Praxis/sage_room","south":"/domains/Praxis/farm","east":"/domains/Praxis/w_boc_la1","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Praxis/w_boc_la3","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"inn110":(["date":1599393318,"exits":(["east":"/domains/Praxis/hall5","fly":"","sink":"","leave":"/domains/Praxis/hall5",]),"coords":(["z":0,"y":0,"x":0,]),]),"w_boc_la1":(["date":1599393258,"exits":(["south":"/domains/Praxis/pub","east":"/domains/Praxis/square","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Praxis/w_boc_la2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"farm":(["date":1599393268,"exits":(["north":"/domains/Praxis/w_boc_la2","fly":"/domains/town/virtual/sky/0,0,1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"house":(["date":1599393278,"exits":(["north":"/domains/Praxis/sun1","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"kataan_join":(["date":1599393308,"exits":(["down":"/domains/Praxis/kataan_hall","fly":"","sink":"","up":"/domains/Praxis/forest3",]),"coords":(["z":0,"y":0,"x":0,]),]),"square":(["date":1599393238,"exits":(["south":"/domains/Praxis/s_centre1","north":"/domains/Praxis/n_centre1","east":"/domains/Praxis/e_boc_la1","fly":"","west":"/domains/Praxis/w_boc_la1","sink":"",]),"coords":(["z":0,"y":-1000,"x":1000,]),]),"cleric_join":(["date":1599393258,"exits":(["east":"/domains/Praxis/n_centre1","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"alley2":(["date":1599393288,"exits":(["south":"/domains/Praxis/building","north":"/domains/Praxis/wall","east":"/domains/Praxis/alley1","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Praxis/dump","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"alley1":(["date":1599393278,"exits":(["east":"/domains/Praxis/s_centre2","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Praxis/alley2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"forest3":(["date":1599393298,"exits":(["south":"/domains/Praxis/forest2","down":"/domains/Praxis/kataan_join","fly":"/domains/town/virtual/sky/0,0,1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"forest2":(["date":1599393288,"exits":(["north":"/domains/Praxis/forest3","south":"/domains/Praxis/forest1","fly":"/domains/town/virtual/sky/0,0,1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"n_centre2":(["date":1599393268,"exits":(["south":"/domains/Praxis/n_centre1","north":"/domains/Praxis/forest1","east":"/domains/Praxis/sun1","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Praxis/hospital","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"forest1":(["date":1599393278,"exits":(["south":"/domains/Praxis/n_centre2","north":"/domains/Praxis/forest2","fly":"/domains/town/virtual/sky/0,0,1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"n_centre1":(["date":1599393258,"exits":(["north":"/domains/Praxis/n_centre2","south":"/domains/Praxis/square","east":"/domains/Praxis/hotel","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Praxis/cleric_join","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"rogue_hall":(["date":1599393338,"exits":(["east":"/domains/Praxis/rogue_vote","council":"/domains/Praxis/council_hall","fly":"","sink":"","up":"/domains/Praxis/rogue_join",]),"coords":(["z":0,"y":0,"x":0,]),]),"monk_vote":(["date":1599393298,"exits":(["fly":"","west":"/domains/Praxis/monk_hall","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"e_boc_la3":(["date":1599393278,"exits":(["north":"/domains/Praxis/east_road1","east":"/domains/Praxis/wild1","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Praxis/e_boc_la2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"wild2":(["date":1599393298,"exits":(["northeast":"/domains/Praxis/jungle","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Praxis/wild1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"sewer":(["date":1599393288,"exits":(["fly":"","west":"/domains/Praxis/sewer_ent","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"e_boc_la2":(["date":1599393268,"exits":(["south":"/domains/Praxis/adv_main","north":"/domains/Praxis/supply","east":"/domains/Praxis/e_boc_la3","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Praxis/e_boc_la1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"jungle":(["date":1599393308,"exits":(["northeast":"/domains/Praxis/rain_forest","fly":"/domains/town/virtual/sky/0,0,1","southwest":"/domains/Praxis/wild2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"fighter_hall":(["date":1599393308,"exits":(["east":"/domains/Praxis/fighter_vote","council":"/domains/Praxis/council_hall","down":"/domains/Praxis/fighter_join","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"pier1":(["date":1599393288,"exits":(["north":"/domains/Praxis/s_centre4","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"wild1":(["date":1599393288,"exits":(["east":"/domains/Praxis/wild2","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Praxis/e_boc_la3","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"e_boc_la1":(["date":1599393258,"exits":(["south":"/domains/Praxis/town_hall","north":"/domains/Praxis/monastery","east":"/domains/Praxis/e_boc_la2","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Praxis/square","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"kataan_vote":(["date":1599393318,"exits":(["fly":"","west":"/domains/Praxis/kataan_hall","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"hotel":(["date":1599393268,"exits":(["north":"/domains/Praxis/hall","fly":"","west":"/domains/Praxis/n_centre1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"inn109":(["date":1599393318,"exits":(["fly":"","west":"/domains/Praxis/hall5","sink":"","leave":"/domains/Praxis/hall5",]),"coords":(["z":0,"y":0,"x":0,]),]),"west_road3":(["date":1599393298,"exits":(["south":"/domains/Praxis/west_road2","fly":"/domains/town/virtual/sky/0,0,1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"inn108":(["date":1599393308,"exits":(["east":"/domains/Praxis/hall4","fly":"","sink":"","leave":"/domains/Praxis/hall3",]),"coords":(["z":0,"y":0,"x":0,]),]),"west_road2":(["date":1599393298,"exits":(["south":"/domains/Praxis/west_road1","north":"/domains/Praxis/west_road3","east":"/domains/Praxis/medium","fly":"/domains/town/virtual/sky/0,0,1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"inn107":(["date":1599393308,"exits":(["fly":"","west":"/domains/Praxis/hall4","sink":"","leave":"/domains/Praxis/hall3",]),"coords":(["z":0,"y":0,"x":0,]),]),"west_road1":(["date":1599393288,"exits":(["south":"/domains/Praxis/w_boc_la3","north":"/domains/Praxis/west_road2","fly":"/domains/town/virtual/sky/0,0,1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"inn106":(["date":1599393298,"exits":(["east":"/domains/Praxis/hall3","fly":"","sink":"","leave":"/domains/Praxis/hall3",]),"coords":(["z":0,"y":0,"x":0,]),]),"sage_room":(["date":1599393268,"exits":(["south":"/domains/Praxis/w_boc_la2","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"inn105":(["date":1599393298,"exits":(["fly":"","west":"/domains/Praxis/hall3","sink":"","leave":"/domains/Praxis/hall3",]),"coords":(["z":0,"y":0,"x":0,]),]),"inn104":(["date":1599393288,"exits":(["east":"/domains/Praxis/hall2","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"lpmud_room":(["date":1599393278,"exits":(["fly":"","west":"/domains/Praxis/adv_main","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"stairs":(["date":1599393278,"exits":(["down":"/domains/Praxis/immortal_hall","fly":"","west":"/domains/Praxis/monastery","sink":"","up":"/domains/Praxis/monk_join",]),"coords":(["z":0,"y":0,"x":0,]),]),"rogue_join":(["date":1599393328,"exits":(["down":"/domains/Praxis/rogue_hall","fly":"","west":"/domains/Praxis/rain_forest","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"inn103":(["date":1599393288,"exits":(["fly":"","west":"/domains/Praxis/hall2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"monk_hall":(["date":1599393298,"exits":(["east":"/domains/Praxis/monk_vote","council":"/domains/Praxis/council_hall","fly":"","west":"/domains/Praxis/monk_join","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"sun2":(["date":1599393288,"exits":(["south":"/domains/Praxis/restaurant","east":"/domains/Praxis/east_road2","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Praxis/sun1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"inn102":(["date":1599393278,"exits":(["east":"/domains/Praxis/hall","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"yard":(["date":1599393288,"exits":(["north":"/domains/Praxis/sheriff","down":"/domains/Praxis/sewer_ent","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Praxis/s_centre2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"inn101":(["date":1599393278,"exits":(["fly":"","west":"/domains/Praxis/hall","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"s_centre4":(["date":1599393288,"exits":(["south":"/domains/Praxis/pier1","northeast":"/domains/Praxis/s_centre3","fly":"","northwest":"/domains/Praxis/fighter_join","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"sun1":(["date":1599393278,"exits":(["south":"/domains/Praxis/house","east":"/domains/Praxis/sun2","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Praxis/n_centre2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"s_centre3":(["date":1599393278,"exits":(["north":"/domains/Praxis/s_centre2","east":"/domains/Praxis/unnamed1","fly":"/domains/town/virtual/sky/0,0,1","southwest":"/domains/Praxis/s_centre4","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"hall":(["date":1599393278,"exits":(["south":"/domains/Praxis/hotel","north":"/domains/Praxis/hall2","east":"/domains/Praxis/inn101","fly":"","west":"/domains/Praxis/inn102","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"supply":(["date":1599393268,"exits":(["south":"/domains/Praxis/e_boc_la2","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"s_centre2":(["date":1599393268,"exits":(["south":"/domains/Praxis/s_centre3","north":"/domains/Praxis/s_centre1","east":"/domains/Praxis/yard","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Praxis/alley1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"fighter_join":(["date":1599393298,"exits":(["southeast":"/domains/Praxis/s_centre4","fly":"","sink":"","up":"/domains/Praxis/fighter_hall",]),"coords":(["z":0,"y":0,"x":0,]),]),"s_centre1":(["date":1599393258,"exits":(["south":"/domains/Praxis/s_centre2","north":"/domains/Praxis/square","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Praxis/pub","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"hall5":(["date":1599393318,"exits":(["south":"/domains/Praxis/hall4","east":"/domains/Praxis/inn109","fly":"","west":"/domains/Praxis/inn110","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"building":(["date":1599393288,"exits":(["north":"/domains/Praxis/alley2","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"hall4":(["date":1599393308,"exits":(["south":"/domains/Praxis/hall3","north":"/domains/Praxis/hall5","east":"/domains/Praxis/inn107","fly":"","west":"/domains/Praxis/inn108","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"restaurant":(["date":1599393288,"exits":(["north":"/domains/Praxis/sun2","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"library":(["date":1599393288,"exits":(["fly":"","west":"/domains/Praxis/east_road1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"unnamed1":(["date":1599393278,"exits":(["fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Praxis/s_centre3","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"kataan_hall":(["date":1599393318,"exits":(["east":"/domains/Praxis/kataan_vote","council":"/domains/Praxis/council_hall","fly":"","sink":"","up":"/domains/Praxis/kataan_join",]),"coords":(["z":0,"y":0,"x":0,]),]),"hall3":(["date":1599393298,"exits":(["south":"/domains/Praxis/hall2","north":"/domains/Praxis/hall4","east":"/domains/Praxis/inn105","fly":"","west":"/domains/Praxis/inn106","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),]),"/domains/campus/room":(["shaft1":(["date":1599393328,"exits":(["east":"/domains/campus/room/science6","fly":"/domains/campus/room/shaft2","sink":"/domains/campus/room/shaft0",]),"coords":(["z":0,"y":0,"x":0,]),]),"access9":(["date":1599393278,"exits":(["north":"/domains/campus/room/access7","down":"/domains/campus/room/maintenance","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"shaft0":(["date":1599393328,"exits":(["east":"/domains/campus/room/basement3","fly":"/domains/campus/room/shaft1","sink":"/domains/campus/room/shaftb",]),"coords":(["z":0,"y":0,"x":0,]),]),"access7":(["date":1599393268,"exits":(["north":"/domains/campus/room/access6","south":"/domains/campus/room/access9","east":"/domains/campus/room/tunnel2","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"access6":(["date":1599393278,"exits":(["north":"/domains/campus/room/access5","south":"/domains/campus/room/access7","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"access5":(["date":1599393288,"exits":(["north":"/domains/campus/room/access0","south":"/domains/campus/room/access6","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"slab":(["date":1599393308,"exits":(["south":"/domains/campus/room/science2","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"crawlspace":(["date":1599393275,"exits":(["fly":"","sink":"",]),"coords":(["z":-2,"y":4000,"x":3999,]),]),"basement":(["date":1599393275,"exits":(["fly":"","west":"/domains/campus/room/basement2","sink":"","up":"/domains/campus/room/stairwell",]),"coords":(["z":0,"y":0,"x":0,]),]),"south_road2":(["date":1599393318,"exits":(["south":"/domains/campus/room/npath2","down":"/domains/campus/room/sewer3","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"access0":(["date":1599393298,"exits":(["south":"/domains/campus/room/access5","down":"/domains/campus/room/sewer","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"science7":(["date":1599393358,"exits":(["south":"/domains/campus/room/stairwell2b","north":"/domains/campus/room/kleiner","fly":"","west":"/domains/campus/room/shaft2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"foyer":(["date":1599393278,"exits":(["east":"/domains/campus/room/corridor3","fly":"","west":"/domains/campus/room/usquare","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"stairwell2d":(["date":1599393318,"exits":(["north":"/domains/campus/room/sub_basement2","fly":"","sink":"","up":"/domains/campus/room/stairwell2c",]),"coords":(["z":0,"y":0,"x":0,]),]),"science6":(["date":1599393348,"exits":(["south":"/domains/campus/room/stairwell2a","north":"/domains/campus/room/weaplab","east":"/domains/campus/room/science5","fly":"","west":"/domains/campus/room/shaft1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"stairwell2c":(["date":1599393328,"exits":(["down":"/domains/campus/room/stairwell2d","fly":"","sink":"","up":"/domains/campus/room/stairwell2a",]),"coords":(["z":0,"y":0,"x":0,]),]),"corridor4":(["date":1599393278,"exits":(["north":"/domains/campus/room/bookstore","south":"/domains/campus/room/conf","fly":"","west":"/domains/campus/room/corridor2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"stairwell2b":(["date":1599393348,"exits":(["north":"/domains/campus/room/science7","down":"/domains/campus/room/stairwell2a","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"science5":(["date":1599393338,"exits":(["north":"/domains/campus/room/classroom1","south":"/domains/campus/room/medlab","east":"/domains/campus/room/science4","fly":"","west":"/domains/campus/room/science6","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"red_room":(["date":1599393318,"exits":(["south":"/domains/campus/room/monty","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"corridor3":(["date":1599393268,"exits":(["north":"/domains/campus/room/snack","south":"/domains/campus/room/stairwell","east":"/domains/campus/room/corridor","fly":"","west":"/domains/campus/room/foyer","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"stairwell2a":(["date":1599393338,"exits":(["north":"/domains/campus/room/science6","down":"/domains/campus/room/stairwell2c","fly":"","west":"/domains/campus/room/alcove1","sink":"","up":"/domains/campus/room/stairwell2b",]),"coords":(["z":0,"y":0,"x":0,]),]),"science4":(["date":1599393328,"exits":(["north":"/domains/campus/room/science3","fly":"","west":"/domains/campus/room/science5","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"corridor2":(["date":1599393268,"exits":(["south":"/domains/campus/room/lounge","east":"/domains/campus/room/corridor4","fly":"","west":"/domains/campus/room/corridor","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"science3":(["date":1599393318,"exits":(["south":"/domains/campus/room/science4","east":"/domains/campus/room/science2","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"classroom1":(["date":1599393338,"exits":(["south":"/domains/campus/room/science5","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"science2":(["date":1599393308,"exits":(["north":"/domains/campus/room/slab","south":"/domains/campus/room/hazlab","east":"/domains/campus/room/science1","fly":"","west":"/domains/campus/room/science3","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"shaftb":(["date":1599393318,"exits":(["east":"/domains/campus/room/sub_basement2","fly":"/domains/campus/room/shaft0","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"crawlspace2":(["date":1599393318,"exits":(["out":"/domains/campus/room/stairwell2d","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"stairwell":(["date":1599393268,"exits":(["north":"/domains/campus/room/corridor3","down":"/domains/campus/room/basement","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"science1":(["date":1599393298,"exits":(["south":"/domains/campus/room/wiz_lab","north":"/domains/campus/room/usquare","fly":"","west":"/domains/campus/room/science2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"weaplab":(["date":1599393358,"exits":(["south":"/domains/campus/room/science6","fly":"","west":"/domains/campus/room/alcove2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"blue_room":(["date":1599393318,"exits":(["south":"/domains/campus/room/monty","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"snack":(["date":1599393268,"exits":(["south":"/domains/campus/room/corridor3","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"monty":(["date":1599393318,"exits":(["north":"/domains/campus/room/wiz_lab","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"green_room3":(["date":1599393318,"exits":(["fly":"","west":"/domains/campus/room/plab","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"green_room2":(["date":1599393318,"exits":(["east":"/domains/campus/room/plab2","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"basement3":(["date":1599393328,"exits":(["east":"/domains/campus/room/basement4","fly":"","west":"/domains/campus/room/shaft0","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"basement2":(["date":1599393258,"exits":(["east":"/domains/campus/room/basement","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"plab":(["date":1599393318,"exits":(["fly":"","west":"/domains/campus/room/wiz_lab","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"maintenance":(["date":1599393288,"exits":(["fly":"","west":"/domains/campus/room/sub_basement1","sink":"","up":"/domains/campus/room/access9",]),"coords":(["z":0,"y":0,"x":0,]),]),"npath":(["date":1599393298,"exits":(["north":"/domains/campus/room/npath2","south":"/domains/campus/room/usquare","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"kleiner":(["date":1599393368,"exits":(["south":"/domains/campus/room/science7","east":"/domains/campus/room/klab","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"tunnel":(["date":1599393238,"exits":(["east":"/domains/campus/room/basement2","fly":"","west":"/domains/campus/room/tunnel2","sink":"",]),"coords":(["z":-1,"y":4000,"x":4003,]),]),"lounge":(["date":1599393268,"exits":(["north":"/domains/campus/room/corridor2","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"hazlab":(["date":1599393308,"exits":(["north":"/domains/campus/room/science2","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"sewer":(["date":1599393308,"exits":(["east":"/domains/campus/room/sewer1","fly":"/domains/campus/room/access0","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"alcove2":(["date":1599393358,"exits":(["east":"/domains/campus/room/weaplab","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"wiz_lab":(["date":1599393308,"exits":(["north":"/domains/campus/room/science1","south":"/domains/campus/room/monty","east":"/domains/campus/room/plab","fly":"","southwest":"/domains/campus/room/plab2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"tunnel2":(["date":1599393258,"exits":(["east":"/domains/campus/room/tunnel","fly":"","west":"/domains/campus/room/access7","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"alcove1":(["date":1599393338,"exits":(["east":"/domains/campus/room/stairwell2a","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"conf":(["date":1599393278,"exits":(["north":"/domains/campus/room/corridor4","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"sub_basement2":(["date":1599393308,"exits":(["south":"/domains/campus/room/stairwell2d","east":"/domains/campus/room/sub_basement1","fly":"","west":"/domains/campus/room/shaftb","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"sub_basement1":(["date":1599393298,"exits":(["east":"/domains/campus/room/maintenance","fly":"","west":"/domains/campus/room/sub_basement2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"klab":(["date":1599393368,"exits":(["fly":"","west":"/domains/campus/room/kleiner","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"red_room3":(["date":1599393318,"exits":(["fly":"","west":"/domains/campus/room/plab","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"green_room":(["date":1599393318,"exits":(["south":"/domains/campus/room/monty","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"red_room2":(["date":1599393318,"exits":(["east":"/domains/campus/room/plab2","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"bookstore":(["date":1599393288,"exits":(["south":"/domains/campus/room/corridor4","fly":"","sink":"","up":"/domains/campus/room/bookstore2",]),"coords":(["z":0,"y":0,"x":0,]),]),"blue_room3":(["date":1599393318,"exits":(["fly":"","west":"/domains/campus/room/plab","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"blue_room2":(["date":1599393318,"exits":(["east":"/domains/campus/room/plab2","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"start":(["date":1599393238,"exits":(["north":"/domains/campus/room/corridor","fly":"","sink":"",]),"coords":(["z":0,"y":4000,"x":4000,]),]),"medlab":(["date":1599393338,"exits":(["north":"/domains/campus/room/science5","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"sewer3":(["date":1599393318,"exits":(["down":"/domains/campus/room/sewer2","fly":"","sink":"","up":"/domains/campus/room/south_road2",]),"coords":(["z":0,"y":0,"x":0,]),]),"sewer2":(["date":1599393318,"exits":(["fly":"","west":"/domains/campus/room/sewer1","sink":"","up":"/domains/campus/room/sewer3",]),"coords":(["z":0,"y":0,"x":0,]),]),"sewer1":(["date":1599393318,"exits":(["east":"/domains/campus/room/sewer2","fly":"","west":"/domains/campus/room/sewer","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"usquare":(["date":1599393288,"exits":(["south":"/domains/campus/room/science1","north":"/domains/campus/room/npath","east":"/domains/campus/room/foyer","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"plab2":(["date":1599393318,"exits":(["northeast":"/domains/campus/room/wiz_lab","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"npath2":(["date":1599393308,"exits":(["north":"/domains/campus/room/south_road2","south":"/domains/campus/room/npath","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"shaft2":(["date":1599393358,"exits":(["east":"/domains/campus/room/science7","fly":"","sink":"/domains/campus/room/shaft1",]),"coords":(["z":0,"y":0,"x":0,]),]),"corridor":(["date":1599393258,"exits":(["south":"/domains/campus/room/start","east":"/domains/campus/room/corridor2","fly":"","west":"/domains/campus/room/corridor3","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),]),"/domains/Praxis/cemetery":(["grave_yard3":(["date":1599393318,"exits":(["north":"/domains/Praxis/cemetery/grave_yard2","northeast":"/domains/Praxis/cemetery/grave_yard4","fly":"/domains/town/virtual/sky/0,0,1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"grave_yard2":(["date":1599393318,"exits":(["north":"/domains/Praxis/cemetery/grave_yard8","south":"/domains/Praxis/cemetery/grave_yard3","east":"/domains/Praxis/cemetery/grave_yard5","down":"/domains/Praxis/cemetery/grave_yard7","southeast":"/domains/Praxis/cemetery/grave_yard4","northeast":"/domains/Praxis/cemetery/grave_yard6","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Praxis/cemetery/grave_yard","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"grave_yard":(["date":1599393308,"exits":(["east":"/domains/Praxis/cemetery/grave_yard2","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/Praxis/east_road2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"grave_yard8":(["date":1599393318,"exits":(["south":"/domains/Praxis/cemetery/grave_yard2","southeast":"/domains/Praxis/cemetery/grave_yard6","fly":"/domains/town/virtual/sky/0,0,1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"grave_yard7":(["date":1599393318,"exits":(["fly":"","sink":"","up":"/domains/Praxis/cemetery/grave_yard2",]),"coords":(["z":0,"y":0,"x":0,]),]),"grave_yard6":(["date":1599393318,"exits":(["southeast":"/domains/Praxis/cemetery/grave_yard5","fly":"/domains/town/virtual/sky/0,0,1","southwest":"/domains/Praxis/cemetery/grave_yard2","northwest":"/domains/Praxis/cemetery/grave_yard8","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"grave_yard5":(["date":1599393318,"exits":(["fly":"","west":"/domains/Praxis/cemetery/grave_yard2","southwest":"/domains/Praxis/cemetery/grave_yard4","northwest":"/domains/Praxis/cemetery/grave_yard6","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"grave_yard4":(["date":1599393318,"exits":(["northeast":"/domains/Praxis/cemetery/grave_yard5","fly":"","southwest":"/domains/Praxis/cemetery/grave_yard3","northwest":"/domains/Praxis/cemetery/grave_yard2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),]),"/domains/cave/room":(["cavepass9":(["date":1599393368,"exits":(["north":"/domains/cave/room/shop","south":"/domains/cave/room/chieftain","fly":"","west":"/domains/cave/room/dining1","southwest":"/domains/cave/room/cavepass12","northwest":"/domains/cave/room/cavepass8","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"rubbish":(["date":1599393318,"exits":(["fly":"","west":"/domains/cave/room/cavepass2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"cavepass8":(["date":1599393378,"exits":(["south":"/domains/cave/room/dining1","southeast":"/domains/cave/room/cavepass9","northeast":"/domains/cave/room/guardroom3","fly":"","northwest":"/domains/cave/room/guardroom4","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"common4":(["date":1599393382,"exits":(["north":"/domains/cave/room/cavepass10","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"cavepass7":(["date":1599393348,"exits":(["south":"/domains/cave/room/food_storage1","north":"/domains/cave/room/guardroom2","east":"/domains/cave/room/cavepass12","fly":"","west":"/domains/cave/room/cavepass5","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"common3":(["date":1599393392,"exits":(["south":"/domains/cave/room/cavepass11","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"cavepass6":(["date":1599393348,"exits":(["north":"/domains/cave/room/common1","south":"/domains/cave/room/cavepass5","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"cavetroll":(["date":1599393358,"exits":(["fly":"/domains/cave/room/chieftain","southwest":"/domains/town/room/wtunnel6","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"cavepass5":(["date":1599393338,"exits":(["south":"/domains/cave/room/cavepass4","north":"/domains/cave/room/cavepass6","east":"/domains/cave/room/cavepass7","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"cavepass4":(["date":1599393328,"exits":(["north":"/domains/cave/room/cavepass5","southeast":"/domains/cave/room/cavepass3","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"common1":(["date":1599393348,"exits":(["south":"/domains/cave/room/cavepass6","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"cavepass3":(["date":1599393318,"exits":(["northeast":"/domains/cave/room/guardroom1","fly":"","southwest":"/domains/cave/room/cavepass1","northwest":"/domains/cave/room/cavepass4","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"cavepass2":(["date":1599393318,"exits":(["east":"/domains/cave/room/rubbish","fly":"","west":"/domains/cave/room/cavepass1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"cavepass1":(["date":1599393308,"exits":(["east":"/domains/cave/room/cavepass2","northeast":"/domains/cave/room/cavepass3","fly":"","west":"/domains/cave/room/cave","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"kurogane":(["date":1599393358,"exits":(["south":"/domains/cave/room/guardroom2","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"food_storage1":(["date":1599393348,"exits":(["north":"/domains/cave/room/cavepass7","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"start":(["date":1599393278,"exits":(["fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"guardroom4":(["date":1599393378,"exits":(["southeast":"/domains/cave/room/cavepass8","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"guardroom3":(["date":1599393378,"exits":(["fly":"","southwest":"/domains/cave/room/cavepass8","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"shop":(["date":1599393378,"exits":(["south":"/domains/cave/room/cavepass9","down":"/domains/cave/room/shop2","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"guardroom2":(["date":1599393358,"exits":(["north":"/domains/cave/room/kurogane","south":"/domains/cave/room/cavepass7","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"guardroom1":(["date":1599393318,"exits":(["fly":"","southwest":"/domains/cave/room/cavepass3","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"dining1":(["date":1599393358,"exits":(["north":"/domains/cave/room/cavepass8","south":"/domains/cave/room/cavepass12","east":"/domains/cave/room/cavepass9","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"cavepass13":(["date":1599393372,"exits":(["north":"/domains/cave/room/chieftain","south":"/domains/cave/room/cavepass10","fly":"","northwest":"/domains/cave/room/cavepass12","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"cavepass12":(["date":1599393358,"exits":(["north":"/domains/cave/room/dining1","southeast":"/domains/cave/room/cavepass13","northeast":"/domains/cave/room/cavepass9","fly":"","west":"/domains/cave/room/cavepass7","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"cavepass11":(["date":1599393392,"exits":(["north":"/domains/cave/room/common3","fly":"","west":"/domains/cave/room/cavepass10","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"cavepass10":(["date":1599393382,"exits":(["south":"/domains/cave/room/common4","north":"/domains/cave/room/cavepass13","east":"/domains/cave/room/cavepass11","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"chieftain":(["date":1599393358,"exits":(["south":"/domains/cave/room/cavepass13","north":"/domains/cave/room/cavepass9","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"cave":(["date":1599393298,"exits":(["east":"/domains/cave/room/cavepass1","fly":"","west":"/domains/town/room/riverbank","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),]),"/domains/examples/room":(["start":(["date":1599393238,"exits":(["north":"/domains/examples/room/entrance","fly":"","sink":"",]),"coords":(["z":-3000,"y":-3000,"x":-3000,]),]),"exroom7":(["date":1599393318,"exits":(["south":"/domains/examples/room/exroom6","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"exroom6":(["date":1599393318,"exits":(["south":"/domains/examples/room/exroom5","north":"/domains/examples/room/exroom7","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"exroom5":(["date":1599393308,"exits":(["south":"/domains/examples/room/exroom4","north":"/domains/examples/room/exroom6","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"exroom4":(["date":1599393298,"exits":(["north":"/domains/examples/room/exroom5","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"exroom2b":(["date":1599393288,"exits":(["fly":"","west":"/domains/examples/room/exroom2a","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"exroom3":(["date":1599393288,"exits":(["north":"/domains/examples/room/exroom4","south":"/domains/examples/room/exroom2","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"exroom2a":(["date":1599393288,"exits":(["east":"/domains/examples/room/exroom2b","fly":"","west":"/domains/examples/room/exroom2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"exroom2":(["date":1599393278,"exits":(["north":"/domains/examples/room/exroom3","south":"/domains/examples/room/exroom1","east":"/domains/examples/room/exroom2a","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"entrance":(["date":1599393258,"exits":(["south":"/domains/examples/room/start","north":"/domains/examples/room/exroom1","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"exroom1":(["date":1599393268,"exits":(["south":"/domains/examples/room/entrance","north":"/domains/examples/room/exroom2","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),]),"/domains/Praxis/orc_valley":(["guard":(["date":1599393318,"exits":(["south":"/domains/Praxis/highway3","north":"/domains/Praxis/orc_valley/open","fly":"/domains/town/virtual/sky/0,0,1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"chamber2":(["date":1599393338,"exits":(["east":"/domains/Praxis/orc_valley/passage2","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"shaman":(["date":1599393338,"exits":(["north":"/domains/Praxis/orc_valley/treasure","south":"/domains/Praxis/orc_valley/open","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"chamber1":(["date":1599393338,"exits":(["fly":"","west":"/domains/Praxis/orc_valley/passage1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"passage2":(["date":1599393338,"exits":(["east":"/domains/Praxis/orc_valley/open","fly":"","west":"/domains/Praxis/orc_valley/chamber2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"open":(["date":1599393328,"exits":(["south":"/domains/Praxis/orc_valley/guard","north":"/domains/Praxis/orc_valley/shaman","east":"/domains/Praxis/orc_valley/passage1","fly":"","west":"/domains/Praxis/orc_valley/passage2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"passage1":(["date":1599393338,"exits":(["east":"/domains/Praxis/orc_valley/chamber1","fly":"","west":"/domains/Praxis/orc_valley/open","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),]),"/domains/default/room":(["quarantine3":(["date":1599393288,"exits":(["fly":"","west":"/domains/default/room/quarantine2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"arena":(["date":1599393278,"exits":(["south":"/domains/default/room/wiz_corr_east","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"wiz_corr_east":(["date":1599393278,"exits":(["north":"/domains/default/room/arena","south":"/domains/default/room/wiz_corr_south","east":"/domains/default/room/wiz_corr_east2","fly":"","west":"/domains/default/room/wiz_corr1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"wiz_corr_east3":(["date":1599393298,"exits":(["east":"/domains/default/virtual/arena/5005,4999","fly":"","west":"/domains/default/room/wiz_corr_east2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"quarantine2":(["date":1599393288,"exits":(["east":"/domains/default/room/quarantine3","fly":"","sink":"","up":"/domains/default/room/quarantine1",]),"coords":(["z":0,"y":0,"x":0,]),]),"wiz_corr_east2":(["date":1599393288,"exits":(["south":"/domains/default/room/stargate_lab","east":"/domains/default/room/wiz_corr_east3","fly":"","west":"/domains/default/room/wiz_corr_east","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"quarantine1":(["date":1599393278,"exits":(["south":"/domains/default/room/wiz_corr1","down":"/domains/default/room/quarantine2","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"telnet_room":(["date":1599393268,"exits":(["fly":"","west":"/domains/default/room/wiz_hall2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"domains_room":(["date":1599393278,"exits":(["north":"/domains/default/room/wiz_hall2","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"wiz_hall":(["date":1599393258,"exits":(["north":"/domains/default/room/start","south":"/secure/room/arch","east":"/domains/default/room/wiz_corr1","fly":"","sink":"","up":"/domains/default/room/wiz_hall2",]),"coords":(["z":0,"y":0,"x":0,]),]),"stargate_lab":(["date":1599393288,"exits":(["north":"/domains/default/room/wiz_corr_east2","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"wiz_corr1":(["date":1599393268,"exits":(["north":"/domains/default/room/quarantine1","east":"/domains/default/room/wiz_corr_east","fly":"","west":"/domains/default/room/wiz_hall","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"furnace":(["date":1599393571,"exits":(["down":"/domains/begin/room/start","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"builder_hall":(["date":1599393278,"exits":(["north":"/domains/town/room/adv_guild","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"wiz_hall2":(["date":1599393268,"exits":(["south":"/domains/default/room/domains_room","east":"/domains/default/room/telnet_room","down":"/domains/default/room/wiz_hall","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),]),"/domains/Praxis/mountains":(["entrance":(["date":1599393338,"exits":(["out":"/domains/Praxis/pass2","down":"/domains/Praxis/mountains/tunnel1","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"tunnel1":(["date":1599393348,"exits":(["east":"/domains/Praxis/mountains/chamber1","down":"/domains/Praxis/mountains/tunnel2","fly":"","west":"/domains/Praxis/mountains/chamber2","sink":"","up":"/domains/Praxis/mountains/entrance",]),"coords":(["z":0,"y":0,"x":0,]),]),]),"/domains/town/room":(["orc_fortress":(["date":1599393318,"exits":(["south":"/domains/town/room/valley","fly":"","west":"/domains/town/room/orc_temple","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"adv_guild":(["date":1599393278,"exits":(["south":"/domains/default/room/builder_hall","north":"/domains/town/room/vill_road2","east":"/domains/town/room/confroom","fly":"","sink":"","up":"/domains/town/room/training",]),"coords":(["z":0,"y":0,"x":0,]),]),"shack":(["date":1599393298,"exits":(["south":"/domains/town/room/garden","out":"/domains/town/room/garden","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"thall":(["date":1599393278,"exits":(["north":"/domains/town/room/clerk","south":"/domains/town/room/vill_road3","northeast":"/domains/town/room/voters","fly":"","sink":"","up":"/domains/town/room/mayor",]),"coords":(["z":0,"y":0,"x":0,]),]),"garden":(["date":1599393298,"exits":(["north":"/domains/town/room/shack","east":"/domains/town/room/mansion_ext","fly":"/domains/town/virtual/sky/0,0,1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"cratshack":(["date":1599393338,"exits":(["south":"/domains/town/room/porch","north":"/domains/town/room/narrow_path2","fly":"/domains/town/virtual/sky/0,0,1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"hp":(["date":1599393308,"exits":(["east":"/domains/town/room/bwalk1","fly":"/domains/town/virtual/sky/0,0,1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"training":(["date":1599393268,"exits":(["down":"/domains/town/room/adv_guild","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"tavern":(["date":1599393268,"exits":(["out":"/domains/town/room/road","fly":"","west":"/domains/town/room/road","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"school":(["date":1599393278,"exits":(["south":"/domains/town/room/vill_road4","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"mansion_uhall3":(["date":1599393328,"exits":(["north":"/domains/town/room/mansion_uhall2","south":"/domains/town/room/mansion_mbdroom","east":"/domains/town/room/mansion_room5","down":"/domains/town/room/mansion_dhall3","fly":"","west":"/domains/town/room/mansion_room6","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"south_road1":(["date":1599393258,"exits":(["north":"/domains/town/room/start","fly":"/domains/town/virtual/sky/0,-1,1","west":"/domains/town/room/magic_shop","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"mansion_ext":(["date":1599393288,"exits":(["south":"/domains/town/room/mansion_int","north":"/domains/town/room/gate","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/town/room/garden","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"mansion_uhall2":(["date":1599393338,"exits":(["north":"/domains/town/room/mansion_uhall1","south":"/domains/town/room/mansion_uhall3","east":"/domains/town/room/mansion_room3","fly":"","west":"/domains/town/room/mansion_room4","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"forest_path1":(["date":1599393288,"exits":(["north":"/domains/town/virtual/forest/-4,1","east":"/domains/town/room/bridge","fly":"/domains/town/virtual/sky/0,0,1","southwest":"/domains/town/room/clearing","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"mansion_uhall1":(["date":1599393348,"exits":(["south":"/domains/town/room/mansion_uhall2","east":"/domains/town/room/mansion_room1","down":"/domains/town/room/mansion_ext","fly":"","west":"/domains/town/room/mansion_room2","sink":"","window":"/domains/town/room/mansion_ext",]),"coords":(["z":0,"y":0,"x":0,]),]),"confroom":(["date":1599393268,"exits":(["fly":"","west":"/domains/town/room/adv_guild","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"mansion_room10":(["date":1599393308,"exits":(["east":"/domains/town/room/mansion_dhall2","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"healer":(["date":1599393278,"exits":(["east":"/domains/town/room/road","out":"/domains/town/room/road","fly":"","west":"/domains/town/room/chamber","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"clerk":(["date":1599393278,"exits":(["south":"/domains/town/room/thall","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"vill_road4":(["date":1599393278,"exits":(["south":"/domains/town/room/stables","north":"/domains/town/room/school","east":"/domains/town/room/shore","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/town/room/vill_road3","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"vill_road3":(["date":1599393268,"exits":(["north":"/domains/town/room/thall","east":"/domains/town/room/vill_road4","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/town/room/vill_road2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"vill_road2":(["date":1599393258,"exits":(["south":"/domains/town/room/adv_guild","north":"/domains/town/room/shop","east":"/domains/town/room/vill_road3","fly":"/domains/town/virtual/sky/1,0,1","west":"/domains/town/room/start","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"riverbank":(["date":1599393298,"exits":(["east":"/domains/cave/room/cave","fly":"","sink":"","up":"/domains/town/room/bridge",]),"coords":(["z":0,"y":0,"x":0,]),]),"wtunnel6":(["date":1599393358,"exits":(["south":"/domains/town/room/wtunnel5","northeast":"/domains/cave/room/cavetroll","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"wtunnel5":(["date":1599393338,"exits":(["north":"/domains/town/room/wtunnel6","south":"/domains/town/room/wtunnel4","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"shop":(["date":1599393268,"exits":(["south":"/domains/town/room/vill_road2","down":"/domains/town/room/shop2","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"road":(["date":1599393268,"exits":(["south":"/domains/town/room/road0","north":"/domains/town/room/mountain_road","east":"/domains/town/room/tavern","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/town/room/healer","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"wtunnel4":(["date":1599393328,"exits":(["north":"/domains/town/room/wtunnel5","fly":"","southwest":"/domains/town/room/wtunnel3","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"wtunnel3":(["date":1599393318,"exits":(["northeast":"/domains/town/room/wtunnel4","fly":"","west":"/domains/town/room/wtunnel2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"mayor":(["date":1599393278,"exits":(["down":"/domains/town/room/thall","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"wtunnel2":(["date":1599393308,"exits":(["east":"/domains/town/room/wtunnel3","fly":"","west":"/domains/town/room/source","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"mansion_int":(["date":1599393298,"exits":(["south":"/domains/town/room/mansion_dhall2","north":"/domains/town/room/mansion_ext","east":"/domains/town/room/mansion_room9","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"clearing":(["date":1599393298,"exits":(["northeast":"/domains/town/room/forest_path1","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/town/room/valley","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"bank":(["date":1599393278,"exits":(["fly":"","west":"/domains/town/room/mountain_road","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"mansion_room9":(["date":1599393298,"exits":(["fly":"","west":"/domains/town/room/mansion_int","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"mansion_room8":(["date":1599393318,"exits":(["east":"/domains/town/room/mansion_dhall3","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"church":(["date":1599393268,"exits":(["south":"/domains/town/room/road1","fly":"","west":"/domains/town/room/elevator","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"mansion_room7":(["date":1599393308,"exits":(["fly":"","west":"/domains/town/room/mansion_dhall2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"mansion_room6":(["date":1599393328,"exits":(["east":"/domains/town/room/mansion_uhall3","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"mansion_room5":(["date":1599393328,"exits":(["fly":"","west":"/domains/town/room/mansion_uhall3","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"orc_temple":(["date":1599393318,"exits":(["east":"/domains/town/room/orc_fortress","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"living_room":(["date":1599393348,"exits":(["north":"/domains/town/room/porch","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"mansion_room4":(["date":1599393338,"exits":(["east":"/domains/town/room/mansion_uhall2","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"mansion_room3":(["date":1599393348,"exits":(["fly":"","west":"/domains/town/room/mansion_uhall2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"porch":(["date":1599393348,"exits":(["south":"/domains/town/room/living_room","north":"/domains/town/room/cratshack","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"mansion_room2":(["date":1599393348,"exits":(["east":"/domains/town/room/mansion_uhall1","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"voters":(["date":1599393278,"exits":(["fly":"","southwest":"/domains/town/room/thall","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"mansion_room1":(["date":1599393348,"exits":(["fly":"","west":"/domains/town/room/mansion_uhall1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"valley":(["date":1599393308,"exits":(["north":"/domains/town/room/orc_fortress","east":"/domains/town/room/clearing","fly":"/domains/town/virtual/sky/0,0,1","southwest":"/domains/town/room/narrow_path","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"shower":(["date":1599393348,"exits":(["out":"/domains/town/room/mansion_room3","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"mountain_road":(["date":1599393278,"exits":(["south":"/domains/town/room/road","east":"/domains/town/room/bank","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/town/room/postoffice","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"narrow_path2":(["date":1599393328,"exits":(["south":"/domains/town/room/cratshack","north":"/domains/town/room/narrow_path","fly":"/domains/town/virtual/sky/0,0,1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"well3":(["date":1599393288,"exits":(["east":"/domains/town/room/well2","down":"/domains/town/room/source","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"stables":(["date":1599393278,"exits":(["north":"/domains/town/room/vill_road4","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"well2":(["date":1599393278,"exits":(["east":"/domains/town/room/well1","fly":"","west":"/domains/town/room/well3","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"well1":(["date":1599393268,"exits":(["fly":"","west":"/domains/town/room/well2","sink":"","up":"/domains/town/room/south_road1",]),"coords":(["z":0,"y":0,"x":0,]),]),"mansion_dhall3":(["date":1599393318,"exits":(["north":"/domains/town/room/mansion_dhall2","fly":"","west":"/domains/town/room/mansion_room8","sink":"","up":"/domains/town/room/mansion_uhall3",]),"coords":(["z":0,"y":0,"x":0,]),]),"mansion_dhall2":(["date":1599393308,"exits":(["south":"/domains/town/room/mansion_dhall3","north":"/domains/town/room/mansion_int","east":"/domains/town/room/mansion_room7","fly":"","west":"/domains/town/room/mansion_room10","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"narrow_path":(["date":1599393318,"exits":(["south":"/domains/town/room/narrow_path2","northeast":"/domains/town/room/valley","fly":"/domains/town/virtual/sky/0,0,1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"gate":(["date":1599393278,"exits":(["north":"/domains/town/room/road2","south":"/domains/town/room/mansion_ext","fly":"/domains/town/virtual/sky/0,0,1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"bridge":(["date":1599393278,"exits":(["east":"/domains/town/room/road2","down":"/domains/town/room/riverbank","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/town/room/forest_path1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"docks":(["date":1599393298,"exits":(["south":"/domains/town/room/bwalk1","north":"/domains/town/room/shore","fly":"/domains/town/virtual/sky/0,0,1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"chamber":(["date":1599393278,"exits":(["east":"/domains/town/room/healer","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"mansion_mbdroom":(["date":1599393328,"exits":(["north":"/domains/town/room/mansion_uhall3","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"magic_shop":(["date":1599393268,"exits":(["south":"/domains/town/room/magic_guild","east":"/domains/town/room/south_road1","fly":"","sink":"","up":"/domains/town/room/magic_shop2",]),"coords":(["z":0,"y":0,"x":0,]),]),"source":(["date":1599393298,"exits":(["east":"/domains/town/room/wtunnel2","fly":"","sink":"","up":"/domains/town/room/well3",]),"coords":(["z":0,"y":0,"x":0,]),]),"magic_guild":(["date":1599393268,"exits":(["north":"/domains/town/room/magic_shop","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"road2":(["date":1599393268,"exits":(["south":"/domains/town/room/gate","east":"/domains/town/room/road1","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/town/room/bridge","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"road1":(["date":1599393258,"exits":(["north":"/domains/town/room/church","east":"/domains/town/room/start","fly":"/domains/town/virtual/sky/-1,0,1","west":"/domains/town/room/road2","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"bwalk1":(["date":1599393308,"exits":(["north":"/domains/town/room/docks","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/town/room/hp","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"road0":(["date":1599393258,"exits":(["south":"/domains/town/room/start","north":"/domains/town/room/road","fly":"/domains/town/virtual/sky/0,1,1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"shore":(["date":1599393288,"exits":(["south":"/domains/town/room/docks","fly":"/domains/town/virtual/sky/0,0,1","west":"/domains/town/room/vill_road4","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),]),"/domains/oogtopia/room":(["bushese":(["date":1599393262,"exits":(["south":"/domains/oogtopia/room/bushesse","north":"/domains/oogtopia/room/bushesne","fly":"","west":"/domains/oogtopia/room/start","sink":"",]),"coords":(["z":7000,"y":7000,"x":7002,]),]),"bushesse":(["date":1599393260,"exits":(["north":"/domains/oogtopia/room/bushese","fly":"","west":"/domains/oogtopia/room/bushess","sink":"",]),"coords":(["z":7000,"y":6999,"x":7002,]),]),"start":(["date":1599393238,"exits":(["south":"/domains/oogtopia/room/bushess","north":"/domains/oogtopia/room/bushesn","east":"/domains/oogtopia/room/bushese","fly":"","west":"/domains/oogtopia/room/bushesw","sink":"",]),"coords":(["z":7000,"y":7000,"x":7001,]),]),"bushess":(["date":1599393259,"exits":(["north":"/domains/oogtopia/room/start","east":"/domains/oogtopia/room/bushesse","fly":"","west":"/domains/oogtopia/room/bushessw","sink":"",]),"coords":(["z":7000,"y":6999,"x":7001,]),]),"bushesne":(["date":1599393263,"exits":(["south":"/domains/oogtopia/room/bushese","fly":"","west":"/domains/oogtopia/room/bushesn","sink":"",]),"coords":(["z":7000,"y":7001,"x":7002,]),]),"bushesw":(["date":1599393266,"exits":(["south":"/domains/oogtopia/room/bushessw","north":"/domains/oogtopia/room/field","east":"/domains/oogtopia/room/start","fly":"","sink":"",]),"coords":(["z":7000,"y":7000,"x":7000,]),]),"bushessw":(["date":1599393266,"exits":(["north":"/domains/oogtopia/room/bushesw","east":"/domains/oogtopia/room/bushess","fly":"","sink":"",]),"coords":(["z":7000,"y":6999,"x":7000,]),]),"field":(["date":1599393265,"exits":(["south":"/domains/oogtopia/room/bushesw","east":"/domains/oogtopia/room/bushesn","fly":"","sink":"",]),"coords":(["z":7000,"y":7001,"x":7000,]),]),"bushesn":(["date":1599393264,"exits":(["south":"/domains/oogtopia/room/start","east":"/domains/oogtopia/room/bushesne","fly":"","west":"/domains/oogtopia/room/field","sink":"",]),"coords":(["z":7000,"y":7001,"x":7001,]),]),]),"/domains/voluntaria/room":(["quarters":(["date":1599393348,"exits":(["fly":"","west":"/domains/voluntaria/room/commandhall","sink":"",]),"coords":(["z":7001,"y":7004,"x":7001,]),]),"stairwell":(["date":1599393318,"exits":(["south":"/domains/voluntaria/room/hallway2","down":"/domains/voluntaria/room/bottomstair","fly":"","sink":"","up":"/domains/voluntaria/room/topstair",]),"coords":(["z":7000,"y":7005,"x":7000,]),]),"start":(["date":1599394036,"exits":(["north":"/domains/town/room/road0","south":"/domains/town/room/south_road1","east":"/domains/town/room/vill_road2","fly":"","west":"/domains/town/room/road1","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"bridge":(["date":1599393348,"exits":(["east":"/domains/voluntaria/room/commandhall","fly":"","sink":"",]),"coords":(["z":7001,"y":7004,"x":6999,]),]),"hallway2":(["date":1599393308,"exits":(["north":"/domains/voluntaria/room/stairwell","south":"/domains/voluntaria/room/hallway","fly":"","sink":"",]),"coords":(["z":7000,"y":7004,"x":7000,]),]),"bottomstair":(["date":1599393328,"exits":(["fly":"","sink":"","up":"/domains/voluntaria/room/stairwell",]),"coords":(["z":6999,"y":7005,"x":7000,]),]),"topstair":(["date":1599393328,"exits":(["south":"/domains/voluntaria/room/commandhall","down":"/domains/voluntaria/room/stairwell","fly":"","sink":"",]),"coords":(["z":7001,"y":7005,"x":7000,]),]),"spaceup":(["date":1599393368,"exits":(["down":"/domains/voluntaria/room/space","fly":"","sink":"",]),"coords":(["z":0,"y":0,"x":0,]),]),"commandexit":(["date":1599393348,"exits":(["south":"/domains/voluntaria/room/spaceup","north":"/domains/voluntaria/room/commandhall","fly":"","sink":"",]),"coords":(["z":7001,"y":7003,"x":7000,]),]),"commandhall":(["date":1599393338,"exits":(["south":"/domains/voluntaria/room/commandexit","north":"/domains/voluntaria/room/topstair","east":"/domains/voluntaria/room/quarters","fly":"","west":"/domains/voluntaria/room/bridge","sink":"",]),"coords":(["z":7001,"y":7004,"x":7000,]),]),"airlock":(["date":1599393288,"exits":(["north":"/domains/voluntaria/room/hallway","south":"/domains/oogtopia/room/field","fly":"","sink":"",]),"coords":(["z":7000,"y":7002,"x":7000,]),]),"crewpod":(["date":1599393308,"exits":(["east":"/domains/voluntaria/room/hallway","fly":"","sink":"",]),"coords":(["z":7000,"y":7003,"x":6999,]),]),"hallway":(["date":1599393298,"exits":(["north":"/domains/voluntaria/room/hallway2","south":"/domains/voluntaria/room/airlock","fly":"","west":"/domains/voluntaria/room/crewpod","sink":"",]),"coords":(["z":7000,"y":7003,"x":7000,]),]),"space":(["date":1599393368,"exits":(["down":"/domains/voluntaria/room/spacedown","fly":"","sink":"","up":"/domains/voluntaria/room/spaceup",]),"coords":(["z":0,"y":0,"x":0,]),]),]),]) +WorldGrid ([-536870912:([536838144:([29768:([-536870912:([536838144:([29768:([-536870912:([536838144:([29768:(["coord":"-3000,-3000,-3000","room":"/domains/examples/room/start",]),]),]),]),]),]),]),]),]),0:([0:([6999:([0:([0:([7004:([0:([0:([7001:(["coord":"6999,7004,7001","room":"/domains/voluntaria/room/bridge",]),]),]),]),7003:([0:([0:([7000:(["coord":"6999,7003,7000","room":"/domains/voluntaria/room/crewpod",]),]),]),]),]),]),]),3999:([0:([0:([4000:([-536870912:([536838144:([32766:(["coord":"3999,4000,-2","room":"/domains/campus/room/crawlspace",]),]),]),]),]),]),]),4003:([0:([0:([4000:([-536870912:([536838144:([32767:(["coord":"4003,4000,-1","room":"/domains/campus/room/tunnel",]),]),]),]),]),]),]),7002:([0:([0:([6999:([0:([0:([7000:(["coord":"7002,6999,7000","room":"/domains/oogtopia/room/bushesse",]),]),]),]),7001:([0:([0:([7000:(["coord":"7002,7001,7000","room":"/domains/oogtopia/room/bushesne",]),]),]),]),7000:([0:([0:([7000:(["coord":"7002,7000,7000","room":"/domains/oogtopia/room/bushese",]),]),]),]),]),]),]),7001:([0:([0:([6999:([0:([0:([7000:(["coord":"7001,6999,7000","room":"/domains/oogtopia/room/bushess",]),]),]),]),7004:([0:([0:([7001:(["coord":"7001,7004,7001","room":"/domains/voluntaria/room/quarters",]),]),]),]),7001:([0:([0:([7000:(["coord":"7001,7001,7000","room":"/domains/oogtopia/room/bushesn",]),]),]),]),7000:([0:([0:([7000:(["coord":"7001,7000,7000","room":"/domains/oogtopia/room/start",]),]),]),]),]),]),]),7000:([0:([0:([7005:([0:([0:([6999:(["coord":"7000,7005,6999","room":"/domains/voluntaria/room/bottomstair",]),7001:(["coord":"7000,7005,7001","room":"/domains/voluntaria/room/topstair",]),7000:(["coord":"7000,7005,7000","room":"/domains/voluntaria/room/stairwell",]),]),]),]),7004:([0:([0:([7001:(["coord":"7000,7004,7001","room":"/domains/voluntaria/room/commandhall",]),7000:(["coord":"7000,7004,7000","room":"/domains/voluntaria/room/hallway2",]),]),]),]),7003:([0:([0:([7001:(["coord":"7000,7003,7001","room":"/domains/voluntaria/room/commandexit",]),7000:(["coord":"7000,7003,7000","room":"/domains/voluntaria/room/hallway",]),]),]),]),7002:([0:([0:([7000:(["coord":"7000,7002,7000","room":"/domains/voluntaria/room/airlock",]),]),]),]),7001:([0:([0:([7000:(["coord":"7000,7001,7000","room":"/domains/oogtopia/room/field",]),]),]),]),7000:([0:([0:([7000:(["coord":"7000,7000,7000","room":"/domains/oogtopia/room/bushesw",]),]),]),]),6999:([0:([0:([7000:(["coord":"7000,6999,7000","room":"/domains/oogtopia/room/bushessw",]),]),]),]),]),]),]),4000:([0:([0:([4000:([0:([0:([0:(["coord":"4000,4000,0","room":"/domains/campus/room/start",]),]),]),]),]),]),]),1000:([0:([0:([1001:([0:([0:([1:(["coord":"1000,1001,1","room":"/domains/Ylsrim/room/tower",]),]),]),]),]),]),-536870912:([536838144:([31768:([0:([0:([0:(["coord":"1000,-1000,0","room":"/domains/Praxis/square",]),]),]),]),]),]),]),2000:([0:([0:([2000:([0:([0:([0:(["coord":"2000,2000,0","room":"/domains/learning/room/start",]),]),]),]),]),]),]),5000:([0:([0:([5000:([0:([0:([0:(["coord":"5000,5000,0","room":"/domains/begin/room/start",]),]),]),]),]),]),]),]),]),]) +debugging 0 diff --git a/lib/save/services.o b/lib/save/services.o new file mode 100644 index 0000000..344b830 --- /dev/null +++ b/lib/save/services.o @@ -0,0 +1 @@ +#/daemon/services.c diff --git a/lib/save/soul.o b/lib/save/soul.o new file mode 100644 index 0000000..b5e1c5c --- /dev/null +++ b/lib/save/soul.o @@ -0,0 +1,3 @@ +#/daemon/soul.c +Emotes (["fanfare":(/"Do what?",(["LIV":(/({({"throw","let",}),"$agent_name $agent_verb back $agent_possessive head and $agent_verb out a tremendous fanfare at $target_name.",}),({"-",}),/),"":(/({({"throw","let",}),"$agent_name $agent_verb back $agent_possessive head and $agent_verb out a tremendous fanfare.",}),({"-",}),/),]),/),"spank":(/"Spank whom?",(["LIV":(/({({"spank","beg",}),"$agent_name $agent_verb $target_name hard and $target_nominative $target_verb for more.",}),({}),/),"":(/({({"spank",}),"$agent_name $agent_verb $agent_possessive monkey.",}),({}),/),]),/),"shrug":(/"Shrug how?",(["LIV":(/({({"shrug",}),"$agent_name $agent_verb at $target_name.",}),({"-",}),/),"STR at LIV":(/({({"shrug",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"STR":(/({({"shrug",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"at LIV STR":(/({({"shrug",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LIV":(/({({"shrug",}),"$agent_name $agent_verb at $target_name.",}),({"-",}),/),"":(/({({"shrug",}),"$agent_name $agent_verb.",}),({}),/),]),/),"pet":(/"Pet how?",(["LIV":(/({"pet","$agent_name $agent_verb $target_name.",}),({"-",}),/),"STR":(/({"pet","$agent_name $agent_verb $adverb.",}),({"-",}),/),"STR LIV":(/({"pet","$agent_name $agent_verb $target_name $adverb.",}),({"-",}),/),"":(/({"pet","$agent_name $agent_verb.",}),({}),/),"LIV STR":(/({"pet","$agent_name $agent_verb $target_name $adverb.",}),({"-",}),/),]),/),"acknar":(/"Do what?",(["":(/({({"cackle","destroy",}),"$agent_name $agent_verb insanely as $agent_nominative $agent_verb the world! %^BOLD%^%^RED%^MUAHAHAHAHAH!%^RESET%^",}),({"-",}),/),]),/),"bounce":(/"Bounce!",(["STR":(/({({"bounce",}),"$agent_name $agent_verb up and down $adverb.",}),({"-",}),/),"":(/({({"bounce",}),"$agent_name $agent_verb up and down excitedly!",}),({}),/),]),/),"snap":(/"Snap snap!",(["LIV":(/({({"snap",}),"$agent_name $agent_verb $agent_possessive fingers at $target_name.",}),({}),/),"STR at LIV":(/({({"snap",}),"$agent_name $agent_verb $agent_possessive $adverb at $target_name.",}),({"*",}),/),"at LIV STR":(/({({"snap",}),"$agent_name $agent_verb $agent_possessive $adverb at $target_name.",}),({"*",}),/),"STR":(/({({"snap",}),"$agent_name $agent_verb $agent_possessive $adverb.",}),({"*",}),/),"STR LIV":(/({({"snap",}),"$agent_name $agent_verb $agent_possessive $adverb at $target_name.",}),({"*",}),/),"":(/({({"snap",}),"$agent_name $agent_verb $agent_possessive fingers.",}),({}),/),"LIV STR":(/({({"snap",}),"$agent_name $agent_verb $agent_possessive $adverb at $target_name.",}),({"*",}),/),"at LIV":(/({({"snap",}),"$agent_name $agent_verb $agent_possessive fingers at $target_name.",}),({}),/),]),/),"bird":(/"Bird whom?",(["LVS":(/({({"flip",}),"$agent_name $agent_verb the bird at $target_name.",}),({}),/),]),/),"dopey":(/"Dopey!",(["":(/({({"smile","say",}),"$agent_name $agent_verb and $agent_verb, \"%^BOLD%^CYAN%^Well shut me up and call me dopey!%^RESET%^\"",}),({}),/),]),/),"lag":(/"Lag?",(["":(/({({"wave",}),"As time winds itself to a standstill, $agent_name $agent_verb $agent_possessive arms in slow motion while bellowing, \"Lllllllllaaaaaaaaggggggggg.\"",}),({}),/),]),/),"laf":(/"Laf at whom?",(["at LVS":(/({({"laf",}),"$agent_name $agent_verb at $target_name.",}),({}),/),"LVS":(/({({"laf",}),"$agent_name $agent_verb at $target_name.",}),({}),/),"":(/({({"laf",}),"$agent_name $agent_verb.",}),({}),/),]),/),"oranj":(/"Kurious Oranj?",(["":(/({({"chant",}),"$agent_name $agent_verb, \"%^ORANGE%^I am Kurious, Kurious Oranj!%^RESET%^\"",}),({}),/),]),/),"kiss":(/"Kiss whom?",(["STR LVS":(/({({"kiss",}),"$agent_name $agent_verb $target_name $adverb.",}),({"-",}),/),"LVS STR":(/({({"kiss",}),"$agent_name $agent_verb $target_name $adverb.",}),({"-",}),/),"LVS":(/({({"kiss",}),"$agent_name $agent_verb $target_name passionately.",}),({}),/),"":(/({({"start",}),"$agent_name $agent_verb doing things $agent_nominative should only be doing in private.",}),({}),/),]),/),"tip":(/"Tip whom?",(["STR LVS":(/({({"tip",}),"$agent_name $agent_verb $agent_possessive $adverb to $target_name.",}),({"*",}),/),"LVS STR":(/({({"tip",}),"$agent_name $agent_verb $agent_possessive $adverb to $target_name.",}),({"*",}),/),"LVS":(/({({"tip",}),"$agent_name $agent_verb $agent_possessive hat to $target_name.",}),({}),/),"STR to LVS":(/({({"tip",}),"$agent_name $agent_verb $agent_possessive $adverb to $target_name.",}),({"*",}),/),"to LVS STR":(/({({"tip",}),"$agent_name $agent_verb $agent_possessive $adverb to $target_name.",}),({"*",}),/),"":(/({({"tip",}),"$agent_name $agent_verb $agent_possessive hat.",}),({}),/),]),/),"foo":(/"Foo how?",(["STR":(/({({"foo",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"foo",}),"$agent_name $agent_verb vaguely.",}),({}),/),]),/),"pee":(/"Pee on whom?",(["LVS STR":(/({({"lift","pee",}),"$agent_name $agent_verb $agent_possessive $adverb and $agent_verb on $target_name.",}),({"*",}),/),"STR LVS":(/({({"lift","pee",}),"$agent_name $agent_verb $agent_possessive $adverb and $agent_verb on $target_name.",}),({"*",}),/),"LVS":(/({({"lift","pee",}),"$agent_name $agent_verb $agent_possessive leg and $agent_verb on $target_name.",}),({}),/),"on LVS STR":(/({({"lift","pee",}),"$agent_name $agent_verb $agent_possessive $adverb and $agent_verb on $target_name.",}),({"*",}),/),"on LVS":(/({({"lift","pee",}),"$agent_name $agent_verb $agent_possessive leg and $agent_verb on $target_name.",}),({}),/),"STR on LVS":(/({({"lift","pee",}),"$agent_name $agent_verb $agent_possessive $adverb and $agent_verb on $target_name.",}),({"*",}),/),"STR":(/({({"lift","pee",}),"$agent_name $agent_verb $agent_possessive $adverb and $agent_verb all over the place.",}),({"*",}),/),"":(/({({"lift","pee",}),"$agent_name $agent_verb $agent_possessive leg and $agent_verb all over the place.",}),({}),/),]),/),"lassondra":(/"Do what?",(["LIV":(/({({"give",}),"$agent_name $agent_verb a cookie to $target_name.",}),({"-",}),/),"":(/({({"eat",}),"$agent_name $agent_verb a cookie.",}),({"-",}),/),]),/),"wave":(/"Wave at whom?",(["STR LVS":(/({({"wave",}),"$agent_name $agent_verb $adverb to $target_name.",}),({"-",}),/),"LVS STR":(/({({"wave",}),"$agent_name $agent_verb $adverb to $target_name.",}),({"-",}),/),"STR to LVS":(/({({"wave",}),"$agent_name $agent_verb $adverb to $target_name.",}),({"-",}),/),"LVS":(/({({"wave",}),"$agent_name $agent_verb to $target_name.",}),({}),/),"at LVS STR":(/({({"wave",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LVS":(/({({"wave",}),"$agent_name $agent_verb at $target_name.",}),({}),/),"STR at LVS":(/({({"wave",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"to LVS STR":(/({({"wave",}),"$agent_name $agent_verb $adverb to $target_name.",}),({"-",}),/),"STR":(/({({"wave",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"wave",}),"$agent_name $agent_verb.",}),({}),/),"to LVS":(/({({"wave",}),"$agent_name $agent_verb to $target_name.",}),({}),/),]),/),"apologize":(/"Apologize for what?",(["STR LVS":(/({({"apologize",}),"$agent_name $agent_verb $adverb to $target_name.",}),({"-",}),/),"LVS STR":(/({({"apologize",}),"$agent_name $agent_verb $adverb to $target_name.",}),({"-",}),/),"STR to LVS":(/({({"apologize",}),"$agent_name $agent_verb $adverb to $target_name.",}),({"-",}),/),"LVS":(/({({"apologize",}),"$agent_name $agent_verb to $target_name.",}),({}),/),"for STR":(/({({"apologize",}),"$agent_name $agent_verb for $adverb.",}),({"*",}),/),"for STR to LVS":(/({({"apologize",}),"$agent_name $agent_verb to $target_name for $adverb.",}),({"*",}),/),"to LVS for STR":(/({({"apologize",}),"$agent_name $agent_verb to $target_name for $adverb.",}),({"*",}),/),"for STR LVS":(/({({"apologize",}),"$agent_name $agent_verb to $target_name for $adverb.",}),({"*",}),/),"to LVS STR":(/({({"apologize",}),"$agent_name $agent_verb $adverb to $target_name.",}),({"-",}),/),"STR":(/({({"apologize",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"LVS for STR":(/({({"apologize",}),"$agent_name $agent_verb to $target_name for $adverb.",}),({"*",}),/),"":(/({({"apologize",}),"$agent_name $agent_verb.",}),({}),/),"to LVS":(/({({"apologize",}),"$agent_name $agent_verb to $target_name.",}),({}),/),]),/),"whee":(/"Do what?",(["":(/({({"twirl",}),"$agent_name $agent_verb about the room screaming, \"%^FLASH%^Wheeeeeeeeeeeeeeeeeee!!!!!!!%^RESET%^\"",}),({"-",}),/),]),/),"sniff":(/"Sniff how?",(["LIV":(/({({"sniff",}),"$agent_name $agent_verb at $target_name.",}),({"-",}),/),"STR at LIV":(/({({"sniff",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"STR":(/({({"sniff",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"at LIV STR":(/({({"sniff",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LIV":(/({({"sniff",}),"$agent_name $agent_verb at $target_name.",}),({"-",}),/),"":(/({({"sniff",}),"$agent_name $agent_verb.",}),({}),/),]),/),"smile":(/"Smile at whom?",(["STR LVS":(/({({"smile",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS STR":(/({({"smile",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS":(/({({"smile",}),"$agent_name $agent_verb happily at $target_name.",}),({}),/),"at LVS STR":(/({({"smile",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LVS":(/({({"smile",}),"$agent_name $agent_verb happily at $target_name.",}),({}),/),"STR at LVS":(/({({"smile",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"STR":(/({({"smile",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"smile",}),"$agent_name $agent_verb happily.",}),({}),/),]),/),"lutra":(/"Do what?",(["LIV":(/({({"know",}),"$agent_name $agent_verb $target_name will ask $agent_objective a question $agent_nominative can just feel it.",}),({"-",}),/),]),/),"agree":(/"Agree with whom?",(["STR LVS":(/({({"agree",}),"$agent_name $agent_verb $adverb with $target_name.",}),({"-",}),/),"LVS STR":(/({({"agree",}),"$agent_name $agent_verb $adverb with $target_name.",}),({"-",}),/),"with LVS STR":(/({({"agree",}),"$agent_name $agent_verb $adverb with $target_name.",}),({"-",}),/),"LVS":(/({({"agree",}),"$agent_name $agent_verb wholeheartedly with $target_name.",}),({}),/),"with LVS":(/({({"agree",}),"$agent_name $agent_verb wholeheartedly with $target_name.",}),({}),/),"STR with LVS":(/({({"agree",}),"$agent_name $agent_verb $adverb with $target_name.",}),({"-",}),/),"STR":(/({({"agree",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"agree",}),"$agent_name $agent_verb wholeheartedly.",}),({}),/),]),/),"woo":(/"Woo? Woo woo!",(["STR LVS":(/({({"exclaim",}),"$agent_name $agent_verb, \"%^BOLD%^CYAN%^Woo! Woo!%^RESET%^\" $adverb at $target_name.",}),({"-",}),/),"LVS STR":(/({({"exclaim",}),"$agent_name $agent_verb, \"%^BOLD%^CYAN%^Woo! Woo!%^RESET%^\" $adverb at $target_name.",}),({"-",}),/),"LVS":(/({({"exclaim",}),"$agent_name $agent_verb, \"%^BOLD%^CYAN%^Woo! Woo!%^RESET%^\" at $target_name.",}),({}),/),"at LVS STR":(/({({"exclaim",}),"$agent_name $agent_verb, \"%^BOLD%^CYAN%^Woo! Woo!%^RESET%^\" $adverb at $target_name.",}),({"-",}),/),"at LVS":(/({({"exclaim",}),"$agent_name $agent_verb, \"%^BOLD%^CYAN%^Woo! Woo!%^RESET%^\" at $target_name.",}),({}),/),"STR at LVS":(/({({"exclaim",}),"$agent_name $agent_verb, \"%^BOLD%^CYAN%^Woo! Woo!%^RESET%^\" $adverb at $target_name.",}),({"-",}),/),"STR":(/({({"exclaim",}),"$agent_name $agent_verb, \"%^BOLD%^CYAN%^Woo! Woo!%^RESET%^\" $adverb.",}),({"-",}),/),"":(/({({"exclaim",}),"$agent_name $agent_verb, \"%^BOLD%^CYAN%^Woo! Woo!%^RESET%^\" excitedly.",}),({}),/),]),/),"spit":(/"Spit how?",(["LIV":(/({({"spit",}),"$agent_name $agent_verb on $target_name.",}),({"-",}),/),"STR on LIV":(/({({"spit",}),"$agent_name $agent_verb $adverb on $target_name.",}),({"-",}),/),"STR":(/({({"spit",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"on LIV STR":(/({({"spit",}),"$agent_name $agent_verb $adverb on $target_name.",}),({"-",}),/),"on LIV":(/({({"spit",}),"$agent_name $agent_verb on $target_name.",}),({"-",}),/),"":(/({({"spit",}),"$agent_name $agent_verb.",}),({}),/),]),/),"guffaw":(/"Guffaw how?",(["STR":(/({"guffaw","$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({"guffaw","$agent_name $agent_verb.",}),({}),/),]),/),"snarl":(/"Snarl how?",(["LVS":(/({({"snarl",}),"$agent_name $agent_verb at $target_name.",}),({"-",}),/),"at LVS STR":(/({({"snarl",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LVS":(/({({"snarl",}),"$agent_name $agent_verb at $target_name.",}),({"-",}),/),"STR at LVS":(/({({"snarl",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"STR":(/({({"snarl",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"snarl",}),"$agent_name $agent_verb.",}),({}),/),]),/),"oasis":(/"They suck!",(["":(/({({"sing",}),"$agent_name $agent_verb like a no-talent egomaniac.",}),({}),/),]),/),"potty":(/"Potty whom?",(["LVS":(/({({"state","are",}),"$agent_name $agent_verb that $target_name definitely $target_verb a potty mouth.",}),({}),/),]),/),"matusa":(/"Do what?",(["LIV":(/({({"pull","blow",}),"$agent_name $agent_verb a shotgun and $agent_verb $target_name away!",}),({"-",}),/),"":(/({({"say",}),"$agent_name $agent_verb, %^BOLD%^\"I hate gettin logged off.\"%^RESET%^",}),({"-",}),/),"LIV STR":(/({({"pull","blow",}),"$agent_name $adverb $agent_verb a shotgun and $agent_verb $target_name away!",}),({"-",}),/),]),/),"dance":(/"Dance with whom?",(["LIV":(/({({"dance",}),"$agent_name $agent_verb seductively with $target_name.",}),({}),/),"with LIV":(/({({"dance",}),"$agent_name $agent_verb seductively with $target_name.",}),({}),/),"STR with LIV":(/({({"dance",}),"$agent_name $agent_verb $adverb with $target_name.",}),({"-",}),/),"STR":(/({({"dance",}),"$agent_name $agent_verb around $adverb.",}),({"-",}),/),"with LIV STR":(/({({"dance",}),"$agent_name $agent_verb $adverb with $target_name.",}),({"-",}),/),"STR LIV":(/({({"dance",}),"$agent_name $agent_verb $adverb with $target_name.",}),({"-",}),/),"":(/({({"dance",}),"$agent_name $agent_verb around.",}),({}),/),"LIV STR":(/({({"dance",}),"$agent_name $agent_verb $adverb with $target_name.",}),({"-",}),/),]),/),"lily":(/"Do what?",(["":(/({({"wish",}),"$agent_name $agent_verb $agent_nominative were a Witch like Lilindrian.",}),({"-",}),/),]),/),"jingle":(/"Jingle what?",(["STR":(/({({"jingle",}),"$agent_name $agent_verb $agent_possessive $adverb.",}),({"*",}),/),"":(/({({"jingle",}),"$agent_name $agent_verb $agent_possessive change.",}),({}),/),]),/),"wipe":(/"Just wipe.",(["LIV":(/({({"wipe",}),"$agent_name $agent_verb $agent_possessive hands on $target_name.",}),({}),/),"":(/({({"wipe",}),"$agent_name $agent_verb the sweat from $agent_possessive brow.",}),({}),/),]),/),"smack":(/"Smack whom?",(["STR LVS":(/({({"smack",}),"$agent_name $agent_verb $target_name $adverb.",}),({"-",}),/),"LVS STR":(/({({"smack",}),"$agent_name $agent_verb $target_name $adverb.",}),({"-",}),/),"LVS":(/({({"smack",}),"$agent_name $agent_verb $target_name.",}),({}),/),]),/),"yawn":(/"Just yawn.",(["STR":(/({({"yawn",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"yawn",}),"$agent_name $agent_verb.",}),({}),/),]),/),"faldir":(/"Faldir who?",(["LIV":(/({({"jump","smirl",}),"$target_name $target_verb around like an idiot as $agent_name $agent_verb hapiky.",}),({"-",}),/),"STR":(/({({"let",}),"$agent_name $adverb $agent_verb out a burst of creative energy!",}),({"-",}),/),"":(/({({"let",}),"$agent_name $agent_verb out a burst of creative energy!",}),({"-",}),/),"LIV STR":(/({({"jump","smirl",}),"$target_name $target_verb around like an idiot as $agent_name $agent_verb $adverb.",}),({"-",}),/),]),/),"think":(/"Think what?",(["STR":(/({({}),"$agent_name . o O ( $adverb )",}),({"*",}),/),]),/),"wag":(/"Wag what?",(["STR":(/({({"wag",}),"$agent_name $agent_verb $agent_possessive $adverb.",}),({"*",}),/),"":(/({({"wag",}),"$agent_name $agent_verb $agent_possessive tail.",}),({}),/),]),/),"tap":(/"Tip tap!",(["LIV":(/({({"tap",}),"$agent_name $agent_verb $target_possessive_noun shoulder.",}),({}),/),"STR":(/({({"tap",}),"$agent_name $agent_verb $agent_possessive foot $adverb.",}),({"-",}),/),"":(/({({"tap",}),"$agent_name $agent_verb $agent_possessive foot impatiently.",}),({}),/),]),/),"quirk":(/"Do what?",(["LIV":(/({({"quirk",}),"$agent_name $agent_verb an eyebrow at $target_name.",}),({"-",}),/),"":(/({({"quirk",}),"$agent_name $agent_verb an eyebrow.",}),({"-",}),/),]),/),"boggle":(/"Boggle!",(["LIV":(/({({"boggle",}),"$agent_name $agent_verb at $target_name.",}),({}),/),"STR at LIV":(/({({"boggle",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LIV STR":(/({({"boggle",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"STR":(/({({"boggle",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"STR LIV":(/({({"boggle",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"":(/({({"boggle",}),"$agent_name $agent_verb.",}),({}),/),"LIV STR":(/({({"boggle",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LIV":(/({({"boggle",}),"$agent_name $agent_verb at $target_name.",}),({}),/),]),/),"inout":(/"No time for that!",(["":(/({({"have",}),"No time for the ole in-out, love, $agent_name $agent_verb just come to read the meter.",}),({}),/),]),/),"smirl":(/"addemote smirl",(["LIV":(/({({"smirl",}),"$agent_name $agent_verb hapiky at $target_name.",}),({"-",}),/),"STR":(/({({"smirl",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"smirl",}),"$agent_name $agent_verb hapiky.",}),({"-",}),/),"LIV STR":(/({({"smirl",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),]),/),"smirk":(/"Just smirk.",(["STR LVS":(/({({"smirk",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS STR":(/({({"smirk",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS":(/({({"smirk",}),"$agent_name $agent_verb at $target_name.",}),({}),/),"at LVS STR":(/({({"smirk",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LVS":(/({({"smirk",}),"$agent_name $agent_verb at $target_name.",}),({}),/),"STR at LVS":(/({({"smirk",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"STR":(/({({"smirk",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"smirk",}),"$agent_name $agent_verb.",}),({}),/),]),/),"meow":(/"Meow how?",(["LVS":(/({({"meow",}),"$agent_name $agent_verb at $target_name.",}),({"-",}),/),"at LVS STR":(/({({"meow",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LVS":(/({({"meow",}),"$agent_name $agent_verb at $target_name.",}),({"-",}),/),"STR at LVS":(/({({"meow",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"STR":(/({({"meow",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"meow",}),"$agent_name $agent_verb.",}),({}),/),]),/),"mosh":(/"Mosh with whom?",(["LIV":(/({({"mosh",}),"$agent_name $agent_verb around violently with $target_name, nearly breaking $target_possessive skull.",}),({}),/),"with LIV":(/({({"mosh",}),"$agent_name $agent_verb around violently with $target_name, nearly breaking $target_possessive skull.",}),({}),/),"STR with LIV":(/({({"mosh",}),"$agent_name $agent_verb around $adverb with $target_name, nearly breaking $target_possessive skull.",}),({"-",}),/),"STR":(/({({"mosh",}),"$agent_name $agent_verb $adverb around the room.",}),({"-",}),/),"with LIV STR":(/({({"mosh",}),"$agent_name $agent_verb around $adverb with $target_name, nearly breaking $target_possessive skull.",}),({"-",}),/),"STR LIV":(/({({"mosh",}),"$agent_name $agent_verb around $adverb with $target_name, nearly breaking $target_possessive skull.",}),({"-",}),/),"":(/({({"mosh",}),"$agent_name $agent_verb violently around the room.",}),({}),/),"LIV STR":(/({({"mosh",}),"$agent_name $agent_verb around $adverb with $target_name, nearly breaking $target_possessive skull.",}),({"-",}),/),]),/),"apathy":(/"Just apathy.",(["STR":(/({({"do",}),"$agent_name just $agent_verb not give a damn about $adverb.",}),({"*",}),/),"":(/({({"do",}),"$agent_name just $agent_verb not give a damn.",}),({}),/),"about STR":(/({({"do",}),"$agent_name just $agent_verb not give a damn about $adverb.",}),({"*",}),/),]),/),"booger":(/"Just booger.",(["":(/({({"look","slip","pull","look","eat",}),"$agent_name $agent_verb around cautiously. Thinking no one is looking, $agent_nominative $agent_verb a finger silently up $agent_possessive nose and $agent_verb out a juicy %^YELLOW%^booger%^RESET%^!!! After $agent_nominative $agent_verb around one last time, $agent_nominative $agent_verb it!",}),({}),/),]),/),"belch":(/"Belch?",(["STR LVS":(/({({"belch",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS STR":(/({({"belch",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS":(/({({"belch",}),"$agent_name $agent_verb horribly at $target_name.",}),({}),/),"at LVS STR":(/({({"belch",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LVS":(/({({"belch",}),"$agent_name $agent_verb horribly at $target_name.",}),({}),/),"STR at LVS":(/({({"belch",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"STR":(/({({"belch",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"belch",}),"$agent_name $agent_verb horribly.",}),({}),/),]),/),"fart":(/"Fart?",(["STR LVS":(/({({"fart",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS STR":(/({({"fart",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS":(/({({"fart",}),"$agent_name $agent_verb loudly at $target_name.",}),({}),/),"at LVS STR":(/({({"fart",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LVS":(/({({"fart",}),"$agent_name $agent_verb loudly at $target_name.",}),({}),/),"STR at LVS":(/({({"fart",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"STR":(/({({"fart",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({}),"",}),({}),/),]),/),"gasp":(/"Gasp how?",(["at LVS":(/({({"stare","gasp",}),"$agent_name $agent_verb at $target_name and $agent_verb in shock!",}),({}),/),"LVS":(/({({"stare","gasp",}),"$agent_name $agent_verb at $target_name and $agent_verb in shock!",}),({}),/),"STR":(/({({"gasp",}),"$agent_name $agent_verb $adverb in shock!",}),({"-",}),/),"":(/({({"gasp",}),"$agent_name $agent_verb in shock!",}),({}),/),]),/),"marf":(/"Marf?",(["STR LVS":(/({({"bark",}),"$agent_name $agent_verb $adverb at $target_name, \"%^BOLD%^CYAN%^Marf?%^RESET%^\"",}),({"-",}),/),"LVS STR":(/({({"bark",}),"$agent_name $agent_verb $adverb at $target_name, \"%^BOLD%^CYAN%^Marf?%^RESET%^\"",}),({"-",}),/),"LVS":(/({({"bark",}),"$agent_name $agent_verb at $target_name, \"%^BOLD%^CYAN%^Marf?%^RESET%^\"",}),({}),/),"at LVS STR":(/({({"bark",}),"$agent_name $agent_verb $adverb at $target_name, \"%^BOLD%^CYAN%^Marf?%^RESET%^\"",}),({"-",}),/),"at LVS":(/({({"bark",}),"$agent_name $agent_verb at $target_name, \"%^BOLD%^CYAN%^Marf?%^RESET%^\"",}),({}),/),"STR at LVS":(/({({"bark",}),"$agent_name $agent_verb $adverb at $target_name, \"%^BOLD%^CYAN%^Marf?%^RESET%^\"",}),({"-",}),/),"STR":(/({({"bark",}),"$agent_name $agent_verb $adverb, \"%^BOLD%^CYAN%^Marf?%^RESET%^\"",}),({"-",}),/),"":(/({({"bark",}),"$agent_name $agent_verb, \"%^BOLD%^CYAN%^Marf?%^RESET%^\"",}),({}),/),]),/),"flirt":(/"Flirt how?",(["LIV":(/({({"flirt",}),"$agent_name $agent_verb with $target_name.",}),({"-",}),/),"with LIV":(/({({"flirt",}),"$agent_name $agent_verb with $target_name.",}),({"-",}),/),"STR with LIV":(/({({"flirt",}),"$agent_name $agent_verb $adverb with $target_name.",}),({"-",}),/),"STR":(/({({"flirt",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"with LIV STR":(/({({"flirt",}),"$agent_name $agent_verb $adverb with $target_name.",}),({"-",}),/),"":(/({({"flirt",}),"$agent_name $agent_verb.",}),({}),/),]),/),"snore":(/"Snore how?",(["STR":(/({({"snore",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"snore",}),"$agent_name $agent_verb loudly.",}),({}),/),]),/),"womble":(/"Womble how?",(["around LVS":(/({({"womble",}),"$agent_name $agent_verb slowly around $target_name.",}),({}),/),"STR LVS":(/({({"womble",}),"$agent_name $agent_verb $adverb around $target_name.",}),({"-",}),/),"LVS STR":(/({({"womble",}),"$agent_name $agent_verb $adverb around $target_name.",}),({"-",}),/),"LVS":(/({({"womble",}),"$agent_name $agent_verb slowly around $target_name.",}),({}),/),"STR":(/({({"womble",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"womble",}),"$agent_name $agent_verb slowly.",}),({}),/),]),/),"nod":(/"Nod at whom?",(["STR LVS":(/({({"nod",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS STR":(/({({"nod",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS":(/({({"nod",}),"$agent_name $agent_verb at $target_name.",}),({}),/),"at LVS STR":(/({({"nod",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LVS":(/({({"nod",}),"$agent_name $agent_verb at $target_name.",}),({}),/),"STR at LVS":(/({({"nod",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"STR":(/({({"nod",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"nod",}),"$agent_name $agent_verb solemnly.",}),({}),/),]),/),"argh":(/"Argh?",(["":(/({({"scream","pull",}),"$agent_name $agent_verb, \"%^BOLD%^CYAN%^Aaaaarrrgggghhh!!!%^RESET%^\" and $agent_verb $agent_possessive hair out.",}),({}),/),]),/),"java":(/"Just java!",(["":(/({({"insist",}),"$agent_name $agent_verb that java is only a beverage.",}),({}),/),]),/),"frown":(/"Just frown.",(["STR LVS":(/({({"frown",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS STR":(/({({"frown",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS":(/({({"frown",}),"$agent_name $agent_verb at $target_name.",}),({}),/),"at LVS STR":(/({({"frown",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LVS":(/({({"frown",}),"$agent_name $agent_verb at $target_name.",}),({}),/),"STR at LVS":(/({({"frown",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"STR":(/({({"frown",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"frown",}),"$agent_name $agent_verb.",}),({}),/),]),/),"bongo":(/"Just bongo, thank you.",(["STR":(/({({"bang",}),"$agent_name $agent_verb on $agent_possessive bongos like a $adverb.",}),({"*",}),/),"":(/({({"bang",}),"$agent_name $agent_verb on $agent_possessive bongos like a chimpanzee.",}),({}),/),]),/),"fear":(/"Fear what?",(["STR":(/({({"think",}),"$agent_name $agent_verb . o O ( Fear $adverb ).",}),({"*",}),/),]),/),"shake":(/"Shake what with whom?",(["LIV":(/({({"shake",}),"$agent_name $agent_verb hands with $target_name.",}),({}),/),"STR with LIV":(/({({"shake",}),"$agent_name $agent_verb $adverb with $target_name.",}),({"*",}),/),"STR":(/({({"shake",}),"$agent_name $agent_verb $agent_possessive head $adverb.",}),({"*",}),/),"STR LIV":(/({({"shake",}),"$agent_name $agent_verb $adverb with $target_name.",}),({"*",}),/),"":(/({({"shake",}),"$agent_name $agent_verb $agent_possessive head no.",}),({}),/),"LIV STR":(/({({"shake",}),"$agent_name $agent_verb $adverb with $target_name.",}),({"*",}),/),]),/),"faint":(/"Faint how?",(["STR":(/({({"faint",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"faint",}),"$agent_name $agent_verb.",}),({}),/),]),/),"hiccup":(/"Hicup?",(["STR":(/({({"hiccup",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"hiccup",}),"$agent_name $agent_verb.",}),({}),/),]),/),"drool":(/"Drool how?",(["LVS STR":(/({({"drool",}),"$agent_name $agent_verb $adverb on $target_name.",}),({"-",}),/),"STR LVS":(/({({"drool",}),"$agent_name $agent_verb $adverb on $target_name.",}),({"-",}),/),"LVS":(/({({"drool",}),"$agent_name $agent_verb disgustingly on $target_name.",}),({}),/),"on LVS STR":(/({({"drool",}),"$agent_name $agent_verb $adverb on $target_name.",}),({"-",}),/),"on LVS":(/({({"drool",}),"$agent_name $agent_verb disgustingly on $target_name.",}),({}),/),"STR on LVS":(/({({"drool",}),"$agent_name $agent_verb $adverb on $target_name.",}),({"-",}),/),"STR":(/({({"drool",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"drool",}),"$agent_name $agent_verb disgustingly.",}),({}),/),]),/),"kick":(/"Kick how?",(["LIV":(/({({"kick",}),"$agent_name $agent_verb $target_name.",}),({"-",}),/),"STR":(/({({"kick",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"STR LIV":(/({({"kick",}),"$agent_name $agent_verb $target_name $adverb.",}),({"-",}),/),"":(/({({"kick",}),"$agent_name $agent_verb.",}),({}),/),"LIV STR":(/({({"kick",}),"$agent_name $agent_verb $target_name $adverb.",}),({"-",}),/),]),/),"growl":(/"Growl how?",(["LVS":(/({({"growl",}),"$agent_name $agent_verb at $target_name.",}),({"-",}),/),"at LVS STR":(/({({"growl",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LVS":(/({({"growl",}),"$agent_name $agent_verb at $target_name.",}),({"-",}),/),"STR at LVS":(/({({"growl",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"STR":(/({({"growl",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"growl",}),"$agent_name $agent_verb.",}),({}),/),]),/),"wiggle":(/"Wiggle what?",(["LIV":(/({({"wiggle",}),"$agent_name $agent_verb $agent_possessive bottom at $target_name.",}),({}),/),"STR at LIV":(/({({"wiggle",}),"$agent_name $agent_verb $agent_possessive $adverb at $target_name.",}),({"*",}),/),"at LIV STR":(/({({"wiggle",}),"$agent_name $agent_verb $agent_possessive $adverb at $target_name.",}),({"*",}),/),"STR":(/({({"wiggle",}),"$agent_name $agent_verb $agent_possessive $adverb.",}),({"*",}),/),"STR LIV":(/({({"wiggle",}),"$agent_name $agent_verb $agent_possessive $adverb at $target_name.",}),({"*",}),/),"":(/({({"wiggle",}),"$agent_name $agent_verb $agent_possessive bottom.",}),({}),/),"LIV STR":(/({({"wiggle",}),"$agent_name $agent_verb $agent_possessive $adverb at $target_name.",}),({"*",}),/),"at LIV":(/({({"wiggle",}),"$agent_name $agent_verb $agent_possessive bottom at $target_name.",}),({}),/),]),/),"curtsey":(/"Curtsey how?",(["LVS":(/({({"curtsey",}),"$agent_name $agent_verb to $target_name.",}),({"-",}),/),"STR to LVS":(/({({"curtsey",}),"$agent_name $agent_verb $adverb to $target_name.",}),({"-",}),/),"to LVS STR":(/({({"curtsey",}),"$agent_name $agent_verb $adverb to $target_name.",}),({"-",}),/),"STR":(/({({"curtsey",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"to LVS":(/({({"curtsey",}),"$agent_name $agent_verb to $target_name.",}),({"-",}),/),"":(/({({"curtsey",}),"$agent_name $agent_verb.",}),({}),/),]),/),"mila":(/"Mila whom?",(["LIV":(/({({"fish",}),"$agent_name $agent_verb through $target_possessive_noun pockets examining $target_possessive money.",}),({"-",}),/),]),/),"rave":(/"Do what?",(["LIV":(/({({"rave",}),"$agent_name $agent_verb at $target_name like a crazed madman.",}),({"-",}),/),"":(/({({"pop","groove",}),"$agent_name $agent_verb a hit of E and $agent_verb to the funky beat.",}),({"-",}),/),]),/),"shyeah":(/"And monkeys might fly out of my butt!",(["STR LVS":(/({({"scream",}),"$agent_name $agent_verb $adverb at $target_name, \"%^BOLD%^CYAN%^Shyeah! And monkeys might fly out of my butt!%^RESET%^\"",}),({"-",}),/),"LVS STR":(/({({"scream",}),"$agent_name $agent_verb $adverb at $target_name, \"%^BOLD%^CYAN%^Shyeah! And monkeys might fly out of my butt!%^RESET%^\"",}),({"-",}),/),"LVS":(/({({"scream",}),"$agent_name $agent_verb at $target_name, \"%^BOLD%^CYAN%^Shyeah! And monkeys might fly out of my butt!%^RESET%^\"",}),({}),/),"at LVS STR":(/({({"scream",}),"$agent_name $agent_verb $adverb at $target_name, \"%^BOLD%^CYAN%^Shyeah! And monkeys might fly out of my butt!%^RESET%^\"",}),({"-",}),/),"at LVS":(/({({"scream",}),"$agent_name $agent_verb at $target_name, \"%^BOLD%^CYAN%^Shyeah! And monkeys might fly out of my butt!%^RESET%^\"",}),({}),/),"STR at LVS":(/({({"scream",}),"$agent_name $agent_verb $adverb at $target_name, \"%^BOLD%^CYAN%^Shyeah! And monkeys might fly out of my butt!%^RESET%^\"",}),({"-",}),/),"STR":(/({({"scream",}),"$agent_name $adverb $agent_verb, \"%^BOLD%^CYAN%^Shyeah! And monkeys might fly out of my butt!%^RESET%^\"",}),({"-",}),/),"":(/({({"scream",}),"$agent_name $agent_verb, \"%^BOLD%^CYAN%^Shyeah! And monkeys might fly out of my butt!%^RESET%^\"",}),({}),/),]),/),"bow":(/"Bow how?",(["LVS":(/({({"bow",}),"$agent_name $agent_verb to $target_name.",}),({"-",}),/),"STR to LVS":(/({({"bow",}),"$agent_name $agent_verb $adverb to $target_name.",}),({"-",}),/),"to LVS STR":(/({({"bow",}),"$agent_name $agent_verb $adverb to $target_name.",}),({"-",}),/),"STR":(/({({"bow",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"to LVS":(/({({"bow",}),"$agent_name $agent_verb to $target_name.",}),({"-",}),/),"":(/({({"bow",}),"$agent_name $agent_verb.",}),({}),/),]),/),"blah":(/"Just blah!",(["STR":(/({({"blurt",}),"$agent_name $adverb $agent_verb, \"%^BOLD%^CYAN%^Blah.%^RESET%^\"",}),({"-",}),/),"":(/({({"blurt",}),"$agent_name apathetically $agent_verb, \"%^BOLD%^CYAN%^Blah.%^RESET%^\"",}),({}),/),]),/),"ulric":(/"Do what?",(["":(/({({"feel","giggle",}),"$agent_name $agent_verb the taint of chaos and $agent_verb insanely.",}),({"-",}),/),]),/),"sneeze":(/"Just sneeze.",(["STR":(/({({"sneeze",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"sneeze",}),"$agent_name $agent_verb.",}),({}),/),]),/),"expect":(/"Expect whom?",(["LIV":(/({({"look",}),"$agent_name $agent_verb expectantly at $target_name.",}),({"-",}),/),]),/),"jerky":(/"Just jerky.",(["":(/({({"growl",}),"$agent_name $agent_verb, \"%^BOLD%^CYAN%^Look, jerky, I don't need ta talk to you!%^RESET%^\"",}),({}),/),]),/),"wink":(/"Wink how?",(["LVS":(/({"wink","$agent_name $agent_verb at $target_name.",}),({"-",}),/),"at LVS STR":(/({"wink","$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LVS":(/({"wink","$agent_name $agent_verb at $target_name.",}),({"-",}),/),"STR at LVS":(/({"wink","$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"STR":(/({"wink","$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({"wink","$agent_name $agent_verb.",}),({}),/),]),/),"wtf":(/"Wtf is with your syntax?",(["":(/({({"scream",}),"Looking totally pissed, $agent_name $agent_verb, \"%^BOLD%^CYAN%^What the f@#$%?%^RESET%^\"",}),({}),/),]),/),"yodel":(/"Yodel what?",(["STR":(/({({"begin",}),"$agent_name $agent_verb to yodel, \"%^GREEN%^Oh, $adverb, oooohooo!%^RESET%^\"",}),({"*",}),/),"":(/({({"yodel",}),"$agent_name $agent_verb a tune in a foreign language.",}),({}),/),]),/),"bog":(/"Just bog.",(["":(/({({"look","bog",}),"$agent_name $agent_verb rather silly as $agent_nominative $agent_verb like a lima bean.",}),({}),/),]),/),"ruffle":(/"Ruffle whom?",(["LIV":(/({({"ruffle",}),"$agent_name $agent_verb $target_possessive_noun hair playfully.",}),({}),/),"STR LIV":(/({({"ruffle",}),"$agent_name $agent_verb $target_possessive_noun hair $adverb.",}),({"-",}),/),"LIV STR":(/({({"ruffle",}),"$agent_name $agent_verb $target_possessive_noun hair $adverb.",}),({"-",}),/),]),/),"pizza":(/"Pizza pizza?",(["STR":(/({({"shout",}),"$agent_name $agent_verb $adverb, \"%^BOLD%^CYAN%^Pizza pizza!%^RESET%^\"",}),({"-",}),/),"":(/({({"shout",}),"$agent_name $agent_verb, \"%^BOLD%^CYAN%^Pizza pizza!%^RESET%^\"",}),({}),/),]),/),"disco":(/"Just disco, thank you.",(["STR LVS":(/({({"dance",}),"$agent_name $agent_verb $adverb to the %^YELLOW%^disco duck%^RESET%^ with $target_name.",}),({"-",}),/),"LVS STR":(/({({"dance",}),"$agent_name $agent_verb $adverb to the %^YELLOW%^disco duck%^RESET%^ with $target_name.",}),({"-",}),/),"with LVS STR":(/({({"dance",}),"$agent_name $agent_verb $adverb to the %^YELLOW%^disco duck%^RESET%^ with $target_name.",}),({"-",}),/),"LVS":(/({({"do",}),"$agent_name $agent_verb the %^YELLOW%^disco duck%^RESET%^ with $target_name.",}),({}),/),"with LVS":(/({({"do",}),"$agent_name $agent_verb the %^YELLOW%^disco duck%^RESET%^ with $target_name.",}),({}),/),"STR with LVS":(/({({"dance",}),"$agent_name $agent_verb $adverb to the %^YELLOW%^disco duck%^RESET%^ with $target_name.",}),({"-",}),/),"STR":(/({({"dance",}),"$agent_name $agent_verb $adverb to the %^YELLOW%^disco duck%^RESET%^!",}),({"-",}),/),"":(/({({"do",}),"$agent_name $agent_verb the %^YELLOW%^disco duck%^RESET%^!",}),({}),/),]),/),"tango":(/"It takes two to tango!",(["LIV":(/({({"put","grab","tango",}),"$agent_name $agent_verb a rose between $agent_possessive teeth, $agent_verb $target_name, and $agent_verb with $target_objective seductively.",}),({}),/),"with LIV":(/({({"put","grab","tango",}),"$agent_name $agent_verb a rose between $agent_possessive teeth, $agent_verb $target_name, and $agent_verb with $target_objective seductively.",}),({}),/),"with LVS":(/({({"put","grab","tango",}),"$agent_name $agent_verb a rose between $agent_possesive teeth, $agent_verb $target_name, and $agent_verb with $target_objective seductively.",}),({}),/),"LIV STR":(/({({"put","grab","tango",}),"$agent_name $agent_verb a rose between $agent_possessive teeth, $agent_verb $target_name, and $agent_verb with $target_objective $adverb.",}),({"seductively","*",}),/),]),/),"biglaugh":(/"Biglaugh at whom?",(["LIV":(/({({"fall",}),"$agent_name $agent_verb down laughing at $target_name.",}),({}),/),"STR at LIV":(/({({"fall",}),"$agent_name $agent_verb $adverb laughing at $target_name.",}),({"down","up","over","sideways",}),/),"at LIV STR":(/({({"fall",}),"$agent_name $agent_verb $adverb laughing at $target_name.",}),({"down","up","over","sideways",}),/),"STR":(/({({"fall",}),"$agent_name $agent_verb $adverb laughing.",}),({"up","down","sideways","over",}),/),"STR LIV":(/({({"fall",}),"$agent_name $agent_verb $adverb laughing at $target_name.",}),({"down","up","over","sideways",}),/),"":(/({({"fall",}),"$agent_name $agent_verb down laughing.",}),({}),/),"LIV STR":(/({({"fall",}),"$agent_name $agent_verb $adverb laughing at $target_name.",}),({"down","up","over","sideways",}),/),"at LIV":(/({({"fall",}),"$agent_name $agent_verb down laughing at $target_name.",}),({}),/),]),/),"hum":(/"Hum how?",(["STR":(/({({"hum",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"hum",}),"$agent_name $agent_verb.",}),({}),/),]),/),"qtip":(/"That is really gross!",(["LVS":(/({({"take","stare","stick","exclaim",}),"$agent_name $agent_verb the Q-tip from $target_possessive_noun ear and $agent_verb intently at the gob of earwax covering it. After a moment of thought, $agent_nominative $agent_verb it in $agent_possessive mouth and $agent_verb, \"%^BOLD%^CYAN%^Yum!%^RESET%^\"",}),({}),/),"":(/({({"take","stare","stick","exclaim",}),"$agent_name $agent_verb the Q-tip from $agent_possessive ear and $agent_verb intently at the gob of earwax covering it. After a moment of thought, $agent_nominative $agent_verb it in $agent_possessive mouth and $agent_verb, \"%^BOLD%^CYAN%^Yum!%^RESET%^\"",}),({}),/),]),/),"misty":(/"Misty whom?",(["":(/({({"play",}),"$agent_name foolishly $agent_verb with a piece of string.",}),({}),/),]),/),"clap":(/"Just clap.",(["STR":(/({({"clap",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"clap",}),"$agent_name $agent_verb wildly.",}),({}),/),]),/),"hug":(/"Hug whom?",(["STR LVS":(/({({"hug",}),"$agent_name $agent_verb $target_name $adverb.",}),({"-",}),/),"LVS STR":(/({({"hug",}),"$agent_name $agent_verb $target_name $adverb.",}),({"-",}),/),"LVS":(/({({"hug",}),"$agent_name $agent_verb $target_name.",}),({}),/),]),/),"lick":(/"Lick whom?",(["STR LVS":(/({({"lick",}),"$agent_name $agent_verb $target_name $adverb.",}),({"-",}),/),"LVS STR":(/({({"lick",}),"$agent_name $agent_verb $target_name $adverb.",}),({"-",}),/),"LVS":(/({({"lick",}),"$agent_name $agent_verb $target_name.",}),({}),/),]),/),"ponder":(/"Ponder how?",(["STR":(/({({"ponder",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"ponder",}),"$agent_name $agent_verb.",}),({}),/),]),/),"ack":(/"Ack?",(["STR LVS":(/({({"ack",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS STR":(/({({"ack",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS":(/({({"ack",}),"$agent_name $agent_verb at $target_name.",}),({}),/),"at LVS STR":(/({({"ack",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LVS":(/({({"ack",}),"$agent_name $agent_verb at $target_name.",}),({}),/),"STR at LVS":(/({({"ack",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"STR":(/({({"ack",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"ack",}),"$agent_name $agent_verb.",}),({}),/),]),/),"mikla":(/"Do what?",(["LIV":(/({({"grin",}),"$agent_name $agent_verb toothlessly at $target_name.",}),({"-",}),/),"":(/({({"grin",}),"$agent_name $agent_verb toothlessly.",}),({"-",}),/),]),/),"cower":(/"Cower from whom?",(["LIV":(/({({"cower",}),"$agent_name $agent_verb in fear from $target_name.",}),({}),/),"from LIV":(/({({"cower",}),"$agent_name $agent_verb in fear from $target_name.",}),({}),/),"":(/({({"cower",}),"$agent_name $agent_verb in fear.",}),({}),/),]),/),"bullshit":(/"Just bullshit.",(["":(/({({"cough",}),"$agent_name $agent_verb, \"%^BOLD%^Bullshit.%^RESET%^\"",}),({}),/),]),/),"vomit":(/"Vomit on whom?",(["LVS STR":(/({({"vomit",}),"$agent_name $agent_verb $adverb on $target_name.",}),({"-",}),/),"STR LVS":(/({({"vomit",}),"$agent_name $agent_verb $adverb on $target_name.",}),({"-",}),/),"LVS":(/({({"vomit",}),"$agent_name $agent_verb on $target_name.",}),({}),/),"on LVS STR":(/({({"vomit",}),"$agent_name $agent_verb $adverb on $target_name.",}),({"-",}),/),"on LVS":(/({({"vomit",}),"$agent_name $agent_verb on $target_name.",}),({}),/),"STR on LVS":(/({({"vomit",}),"$agent_name $agent_verb $adverb on $target_name.",}),({"-",}),/),"STR":(/({({"vomit",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"vomit",}),"$agent_name $agent_verb.",}),({}),/),]),/),"jig":(/"Jig with whom?",(["LIV":(/({({"do",}),"$agent_name $agent_verb a little jig with $target_name for Mr. Fig.",}),({}),/),"with LIV":(/({({"do",}),"$agent_name $agent_verb a little jig with $target_name for Mr. Fig.",}),({}),/),"":(/({({"do",}),"$agent_name $agent_verb a little jig for Mr. Fig.",}),({}),/),]),/),"rainrunner":(/"Do what?",(["LIV":(/({({"flirt",}),"$agent_name $agent_verb with $target_name.",}),({"-",}),/),"LVS":(/({({"flirt",}),"$agent_name $agent_verb with $target_name",}),({"-",}),/),"":(/({({"get",}),"$agent_name $agent_verb hopelessly lost.",}),({"-",}),/),]),/),"groan":(/"Groan how?",(["LVS":(/({({"groan",}),"$agent_name $agent_verb at $target_name.",}),({"-",}),/),"at LVS STR":(/({({"groan",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LVS":(/({({"groan",}),"$agent_name $agent_verb at $target_name.",}),({"-",}),/),"STR at LVS":(/({({"groan",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"STR":(/({({"groan",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"groan",}),"$agent_name $agent_verb.",}),({}),/),]),/),"bing":(/"Bing how?",(["STR LVS":(/({({"bing",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS STR":(/({({"bing",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS":(/({({"bing",}),"$agent_name $agent_verb happily at $target_name.",}),({}),/),"at LVS STR":(/({({"bing",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LVS":(/({({"bing",}),"$agent_name $agent_verb happily at $target_name.",}),({}),/),"STR at LVS":(/({({"bing",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"STR":(/({({"bing",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"bing",}),"$agent_name $agent_verb happily.",}),({}),/),]),/),"assimilate":(/"Assimilate whom?",(["LVS":(/({({"assimilate",}),"$agent_name $agent_verb $target_name like a borg.",}),({}),/),"":(/({({"assimilate",}),"$agent_name $agent_verb species like a borg.",}),({}),/),]),/),"nuzzle":(/"Nuzzle how?",(["LIV":(/({({"nuzzle",}),"$agent_name $agent_verb $target_name.",}),({"-",}),/),"STR":(/({({"nuzzle",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"STR LIV":(/({({"nuzzle",}),"$agent_name $agent_verb $target_name $adverb.",}),({"-",}),/),"":(/({({"nuzzle",}),"$agent_name $agent_verb.",}),({}),/),"LIV STR":(/({({"nuzzle",}),"$agent_name $agent_verb $target_name $adverb.",}),({"-",}),/),]),/),"strut":(/"Strut for whom?",(["LIV":(/({({"strut",}),"$agent_name $agent_verb $agent_possessive stuff for $target_name.",}),({}),/),"for LIV":(/({({"strut",}),"$agent_name $agent_verb $agent_possessive stuff for $target_name.",}),({}),/),"":(/({({"strut",}),"$agent_name $agent_verb $agent_possessive stuff.",}),({}),/),]),/),"leer":(/"Leer at whom?",(["LIV":(/({({"leer",}),"$agent_possessive_noun tongue hits the floor as $agent_nominative $agent_verb at $target_name.",}),({}),/),"at LIV":(/({({"leer",}),"$agent_possessive_noun tongue hits the floor as $agent_nominative $agent_verb at $target_name.",}),({}),/),]),/),"laugh":(/"Laugh how?",(["STR LVS":(/({({"laugh",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS STR":(/({({"laugh",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS":(/({({"laugh",}),"$agent_name $agent_verb at $target_name.",}),({}),/),"at LVS STR":(/({({"laugh",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LVS":(/({({"laugh",}),"$agent_name $agent_verb at $target_name.",}),({}),/),"STR at LVS":(/({({"laugh",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"STR":(/({({"laugh",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"laugh",}),"$agent_name $agent_verb.",}),({}),/),]),/),"moo":(/"Moo how?",(["LVS":(/({({"moo",}),"$agent_name $agent_verb at $target_name.",}),({"-",}),/),"at LVS STR":(/({({"moo",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LVS":(/({({"moo",}),"$agent_name $agent_verb at $target_name.",}),({"-",}),/),"STR at LVS":(/({({"moo",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"STR":(/({({"moo",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"moo",}),"$agent_name $agent_verb.",}),({}),/),]),/),"tsk":(/"Tsk tsk.",(["LIV":(/({({"make",}),"$agent_name $agent_verb tsking motions at $target_name.",}),({}),/),"at LIV":(/({({"make",}),"$agent_name $agent_verb tsking motions at $target_name.",}),({}),/),"":(/({({"make",}),"$agent_name $agent_verb tsking motions.",}),({}),/),]),/),"cry":(/"Cry how?",(["LIV":(/({({"cry",}),"$agent_name $agent_verb tearfully on $target_possessive_noun shoulder.",}),({}),/),"STR":(/({({"cry",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"STR LIV":(/({({"cry",}),"$agent_name $agent_verb $adverb on $target_possessive_noun shoulder.",}),({"-",}),/),"":(/({({"cry",}),"$agent_name $agent_verb tearfully.",}),({}),/),"LIV STR":(/({({"cry",}),"$agent_name $agent_verb $adverb on $target_possessive_noun shoulder.",}),({"-",}),/),]),/),"crash":(/"Just crash.",(["STR":(/({({"try",}),"$agent_name $agent_verb $adverb to crash the game.",}),({"-",}),/),"":(/({({"try",}),"$agent_name $agent_verb desperately to crash the game.",}),({}),/),]),/),"slobber":(/"Slobber how?",(["LIV":(/({({"slobber",}),"$agent_name $agent_verb on $target_name.",}),({"-",}),/),"STR on LIV":(/({({"slobber",}),"$agent_name $agent_verb $adverb on $target_name.",}),({"-",}),/),"STR":(/({({"slobber",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"on LIV STR":(/({({"slobber",}),"$agent_name $agent_verb $adverb on $target_name.",}),({"-",}),/),"on LIV":(/({({"slobber",}),"$agent_name $agent_verb on $target_name.",}),({"-",}),/),"":(/({({"slobber",}),"$agent_name $agent_verb.",}),({}),/),]),/),"cackle":(/"Cackle how?",(["at LVS STR":(/({({"cackle",}),"$agent_name $agent_verb at $target_name $adverb.",}),({"-",}),/),"STR LVS":(/({({"cackle",}),"$agent_name $agent_verb at $target_name $adverb.",}),({"-",}),/),"LVS STR":(/({({"cackle",}),"$agent_name $agent_verb at $target_name $adverb.",}),({"-",}),/),"at LVS":(/({({"cackle",}),"$agent_name $agent_verb at $target_name gleefully.",}),({}),/),"LVS":(/({({"cackle",}),"$agent_name $agent_verb at $target_name gleefully.",}),({}),/),"STR at LVS":(/({({"cackle",}),"$agent_name $agent_verb at $target_name $adverb.",}),({"-",}),/),"":(/({({"throw","cackle",}),"$agent_name $agent_verb $agent_possessive head back and $agent_verb with glee!",}),({}),/),]),/),"limerick":(/"Just limerick.",(["STR":(/({({}),"According to $agent_name, there once was an old lady from Mass, who was said to have a great big $adverb...",}),({"*",}),/),"":(/({({}),"According to $agent_name, there once was an old lady from Mass, who was said to have a great big...",}),({}),/),]),/),"twirl":(/"Twirl how?",(["STR":(/({({"twirl",}),"$agent_name $agent_verb around and around while madly screaming, \"Hahahah!!! $adverb!\"",}),({"*",}),/),"":(/({({"twirl",}),"$agent_name $agent_verb around and around while screaming madly.",}),({}),/),]),/),"hmm":(/"Do what?",(["LIV":(/({({"hmm",}),"$agent_name $agent_verb at $target_name.",}),({"-",}),/),"":(/({({"hmm",}),"$agent_name $agent_verb.",}),({"-",}),/),]),/),"gurble":(/"Gurble how?",(["LIV":(/({"gurble","$agent_name $agent_verb at $target_name.",}),({"-",}),/),"STR at LIV":(/({"gurble","$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"STR":(/({"gurble","$agent_name $agent_verb $adverb.",}),({"-",}),/),"at LIV STR":(/({"gurble","$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LIV":(/({"gurble","$agent_name $agent_verb at $target_name.",}),({"-",}),/),"":(/({"gurble","$agent_name $agent_verb.",}),({}),/),]),/),"test":(/"Test how?",(["STR":(/({({"test",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"test",}),"$agent_name $agent_verb.",}),({}),/),]),/),"admire":(/"Admire whom?",(["STR LVS":(/({({"admire",}),"$agent_name $agent_verb $target_name $adverb.",}),({"-",}),/),"LVS STR":(/({({"admire",}),"$agent_name $agent_verb $target_name $adverb.",}),({"-",}),/),"LVS":(/({({"admire",}),"$agent_name $agent_verb $target_name.",}),({}),/),"STR OBJ":(/({({"admire",}),"$agent_name $agent_verb $target_name $adverb.",}),({"-",}),/),"OBJ STR":(/({({"admire",}),"$agent_name $agent_verb $target_name $adverb.",}),({"-",}),/),"OBJ":(/({({"admire",}),"$agent_name $agent_verb $target_name.",}),({}),/),]),/),"cabbage":(/"Cabbage whom?",(["LVS":(/({({"throw",}),"$agent_name $agent_verb flirtatious cabbages at $target_name.",}),({}),/),"":(/({({"throw",}),"$agent_name $agent_verb flirtatious cabbages around the room.",}),({}),/),]),/),"shellshock":(/"Just shellshock.",(["":(/({({"get","yell","dive","start",}),"$agent_name $agent_verb a crazed look in $agent_possessive eyes and $agent_verb, \"%^BOLD%^CYAN%^Fire in the hole!%^RESET%^\" Quickly, $agent_nominative $agent_verb to the ground and $agent_verb screaming, \"%^BOLD%^CYAN%^Charlie at two o'clock!%^RESET%^\"",}),({}),/),]),/),"doodle":(/"Doodle how?",(["STR":(/({({"doodle",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"doodle",}),"$agent_name $agent_verb.",}),({}),/),]),/),"purr":(/"Purr how?",(["LIV":(/({"purr","$agent_name $agent_verb at $target_name.",}),({"-",}),/),"STR at LIV":(/({"purr","$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"STR":(/({"purr","$agent_name $agent_verb $adverb.",}),({"-",}),/),"at LIV STR":(/({"purr","$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LIV":(/({"purr","$agent_name $agent_verb at $target_name.",}),({"-",}),/),"":(/({"purr","$agent_name $agent_verb.",}),({}),/),]),/),"slap":(/"Slap whom?",(["STR LVS":(/({({"slap",}),"$agent_name $agent_verb $target_name $adverb across the face.",}),({"-",}),/),"LVS STR":(/({({"slap",}),"$agent_name $agent_verb $target_name $adverb across the face.",}),({"-",}),/),"LVS":(/({({"slap",}),"$agent_name $agent_verb $target_name across the face.",}),({}),/),]),/),"wonder":(/"Wonder what?",(["STR":(/({({"wonder",}),"$agent_name $agent_verb . o O ( $adverb? )",}),({"*",}),/),]),/),"giggle":(/"Giggle how?",(["STR LVS":(/({({"giggle",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS STR":(/({({"giggle",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS":(/({({"giggle",}),"$agent_name $agent_verb at $target_name.",}),({}),/),"at LVS STR":(/({({"giggle",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LVS":(/({({"giggle",}),"$agent_name $agent_verb at $target_name.",}),({}),/),"STR at LVS":(/({({"giggle",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"STR":(/({({"giggle",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"giggle",}),"$agent_name $agent_verb.",}),({}),/),]),/),"mickey":(/"Slip whom a mickey?",(["LIV":(/({({"slip",})," $agent_name $agent_verb $target_name a mickey.",}),({}),/),]),/),"comfort":(/"Comfort whom?",(["LIV":(/({({"comfort",}),"$agent_name $agent_verb $target_name.",}),({"-",}),/),]),/),"hork":(/"Hork what?",(["STR LVS":(/({({"cough","hork",}),"$agent_name $agent_verb several times and then $agent_verb up a $adverb on $target_name.",}),({"*",}),/),"LVS STR":(/({({"cough","hork",}),"$agent_name $agent_verb several times and then $agent_verb up a $adverb on $target_name.",}),({"*",}),/),"LVS":(/({({"cough","hork",}),"$agent_name $agent_verb several times and then $agent_verb up a lung on $target_name.",}),({}),/),"STR":(/({({"cough","hork",}),"$agent_name $agent_verb several times and then $agent_verb up a $adverb.",}),({"*",}),/),"":(/({({"cough","hork",}),"$agent_name $agent_verb several times and then $agent_verb up a lung.",}),({}),/),]),/),"spock":(/"Do what?",(["LIV":(/({({"raise",}),"$agent_name $agent_verb an eyebrow quizzically at $target_name.",}),({"-",}),/),"":(/({({"raise",}),"$agent_name $agent_verb an eyebrow quizzically.",}),({"-",}),/),]),/),"edge":(/"Do what?",(["":(/({({"scrunch",}),"$agent_name $agent_verb on the edge of $agent_possessive seat.",}),({"-",}),/),]),/),"ick":(/"Do what?",(["":(/({({"go",}),"$agent_name grossly $agent_verb, \"Ick!\"",}),({"-",}),/),]),/),"puke":(/"Puke how?",(["LIV":(/({({"puke",}),"$agent_name $agent_verb on $target_name.",}),({"-",}),/),"STR on LIV":(/({({"puke",}),"$agent_name $agent_verb $adverb on $target_name.",}),({"-",}),/),"STR":(/({({"puke",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"on LIV STR":(/({({"puke",}),"$agent_name $agent_verb $adverb on $target_name.",}),({"-",}),/),"on LIV":(/({({"puke",}),"$agent_name $agent_verb on $target_name.",}),({"-",}),/),"":(/({({"puke",}),"$agent_name $agent_verb.",}),({}),/),]),/),"bark":(/"Bark at whom?",(["STR LVS":(/({({"bark",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS STR":(/({({"bark",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS":(/({({"bark",}),"$agent_name $agent_verb like a dog at $target_name.",}),({}),/),"at LVS STR":(/({({"bark",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LVS":(/({({"bark",}),"$agent_name $agent_verb like a dog at $target_name.",}),({}),/),"STR at LVS":(/({({"bark",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"STR":(/({({"bark",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"bark",}),"$agent_name $agent_verb like a dog.",}),({}),/),]),/),"flip":(/"Flip whom?",(["LIV":(/({({"flip",}),"$agent_name $agent_verb $target_name head ovr heals.",}),({}),/),"":(/({({"flip",}),"$agent_name $agent_verb head over heals.",}),({}),/),]),/),"doh":(/"Doh!",(["STR":(/({({"holler","drop",}),"$agent_name $agent_verb, \"%^BOLD%^CYAN%^Doh!%^RESET%^\" so emphatically that $agent_nominative $agent_verb $agent_possessive $adverb.",}),({"*",}),/),"":(/({({"holler","drop",}),"$agent_name $agent_verb, \"%^BOLD%^CYAN%^Doh!%^RESET%^\" so emphatically that $agent_nominative $agent_verb $agent_possessive donut.",}),({}),/),]),/),"whirl":(/"Whirl around whom?",(["LIV":(/({({"whirl",}),"$agent_name $agent_verb around $target_name like a ballet dancer.",}),({}),/),"STR around LIV":(/({({"whirl",}),"$agent_name $agent_verb around $target_name like a $adverb.",}),({"*",}),/),"around LIV STR":(/({({"whirl",}),"$agent_name $agent_verb around $target_name like a $adverb.",}),({"*",}),/),"STR":(/({({"whirl",}),"$agent_name $agent_verb around like a $adverb.",}),({"*",}),/),"STR LIV":(/({({"whirl",}),"$agent_name $agent_verb around $target_name like a $adverb.",}),({"*",}),/),"":(/({({"whirl",}),"$agent_name $agent_verb around like a ballet dancer.",}),({}),/),"around LIV":(/({({"whirl",}),"$agent_name $agent_verb around $target_name like a ballet dancer.",}),({}),/),"LIV STR":(/({({"whirl",}),"$agent_name $agent_verb around $target_name like a $adverb.",}),({"*",}),/),]),/),"stigmata":(/"Just stigmata!",(["LVS":(/({({"show",}),"$agent_name $agent_verb $target_name $agent_possessive stigmata from the nine inch nails through $agent_possessive wrists and ankles.",}),({}),/),"":(/({({"show",}),"$agent_name $agent_verb off $agent_possessive stigmata from the nine inch nails through $agent_possessive wrists and ankles.",}),({}),/),]),/),"tp":(/"For your bunghole?",(["LIV":(/({({"hand",}),"$agent_name $agent_verb $target_name some TP for $target_possessive bunghole.",}),({}),/),"":(/({({"scream","run",}),"$agent_name $agent_verb as $agent_nominative $agent_verb with $agent_possessive shirt over $agent_possessive head, \"%^BOLD%^CYAN%^I am the Great Cornholio!!! I need TP for my bunghole!%^RESET%^\"",}),({}),/),]),/),"barf":(/"All you manage is a dry heave.",(["on LVS":(/({({"turn","shiver","barf",}),"$agent_name $agent_verb green, $agent_verb for a moment, then $agent_verb all over $target_name.",}),({}),/),"at LVS":(/({({"turn","shiver","barf",}),"$agent_name $agent_verb green, $agent_verb for a moment, then $agent_verb all over $target_name.",}),({}),/),"LVS":(/({({"turn","shiver","barf",}),"$agent_name $agent_verb green, $agent_verb for a moment, then $agent_verb all over $target_name.",}),({}),/),"":(/({({"turn","shiver","barf",}),"$agent_name $agent_verb green, $agent_verb for a moment, then $agent_verb all over $agent_possessive shoes.",}),({}),/),]),/),"billgates":(/"You have lost it!",(["LIV":(/({({"cackle",}),"$agent_name $agent_verb",}),({"-",}),/),"at LVS":(/({({"cackle",}),"$agent_name $agent_verb",}),({"-",}),/),"LVS":(/({({"cackle",}),"$agent_name $agent_verb",}),({"-",}),/),"at LIV":(/({({"cackle",}),"$agent_name $agent_verb",}),({"-",}),/),]),/),"froth":(/"Just froth.",(["":(/({({"froth",}),"$agent_name $agent_verb at the mouth.",}),({}),/),]),/),"gaia":(/"Gaia whom?",(["LIV":(/({({"look","wonder",}),"$agent_name $agent_verb at $target_name and $agent_verb if Gaia would like to meet $target_objective. Gaia comes and feasts on $target_possessive_noun body.",}),({"-",}),/),"":(/({({"2",}),"Gaia smiles down on $agent_name.",}),({"gaia",}),/),]),/),"beat":(/"Beat whom?",(["LIV":(/({({"beat",}),"$agent_name $agent_verb the crap out of $target_name.",}),({}),/),"STR LIV":(/({({"beat",}),"$agent_name $agent_verb the $adverb out of $target_name.",}),({"*",}),/),"LIV STR":(/({({"beat",}),"$agent_name $agent_verb the $adverb out of $target_name.",}),({"*",}),/),]),/),"coolbeans":(/"Dude!",(["":(/({({"shout","remember","take",}),"$agent_name $agent_verb, \"%^BOLD%^CYAN%^Cool beans!%^RESET%^\", but then $agent_nominative $agent_verb that this is not Lima Bean and summarily $agent_verb it back.",}),({}),/),]),/),"ahh":(/"Do what?",(["":(/({({"ahh",}),"$agent_name $agent_verb in comprehension.",}),({"-",}),/),]),/),"heh":(/"Heh heh, heh heh.",(["STR LIV":(/({({"go",}),"$agent_name $agent_verb, \"%^BOLD%^CYAN%^Heh heh heh heh, $target_name said $adverb. Heh heh, asswipe.%^RESET%^\"",}),({"*",}),/),"":(/({({"go",}),"$agent_name $agent_verb, \"%^BOLD%^CYAN%^Heh heh, heh heh.%^RESET%^\"",}),({}),/),"LIV STR":(/({({"go",}),"$agent_name $agent_verb, \"%^BOLD%^CYAN%^Heh heh heh heh, $target_name said $adverb. Heh heh, asswipe.%^RESET%^\"",}),({"*",}),/),]),/),"grin":(/"Grin at whom?",(["STR LVS":(/({({"grin",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS STR":(/({({"grin",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS":(/({({"grin",}),"$agent_name $agent_verb at $target_name.",}),({}),/),"at LVS STR":(/({({"grin",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LVS":(/({({"grin",}),"$agent_name $agent_verb at $target_name.",}),({}),/),"STR at LVS":(/({({"grin",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"STR":(/({({"grin",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"grin",}),"$agent_name $agent_verb stupidly.",}),({}),/),]),/),"gnr":(/"Dude!",(["LIV":(/({({}),"$agent_name used to love $target_name, but $agent_nominative had to kill $target_objective.",}),({}),/),"":(/({({}),"$agent_name used to love her, but $agent_nominative had to kill her.",}),({}),/),]),/),"hippy":(/"Yippee!",(["":(/({({"are",}),"Punk rocker $agent_name $agent_verb going to scream, \"%^BOLD%^CYAN%^Yippee!!%^RESET%^\", 'cause it's the thing that only eats hippies!",}),({}),/),]),/),"cheer":(/"Just cheer.",(["LIV":(/({({"cheer",}),"$agent_name $agent_verb enthusiastically for $target_name.",}),({}),/),"STR for LIV":(/({({"cheer",}),"$agent_name $agent_verb $adverb for $target_name.",}),({"-",}),/),"for LIV STR":(/({({"cheer",}),"$agent_name $agent_verb $adverb for $target_name.",}),({"-",}),/),"for LIV":(/({({"cheer",}),"$agent_name $agent_verb enthusiastically for $target_name.",}),({}),/),"STR":(/({({"cheer",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"STR LIV":(/({({"cheer",}),"$agent_name $agent_verb $adverb for $target_name.",}),({"-",}),/),"":(/({({"cheer",}),"$agent_name $agent_verb enthusiastically.",}),({}),/),"LIV STR":(/({({"cheer",}),"$agent_name $agent_verb $adverb for $target_name.",}),({"-",}),/),]),/),"poke":(/"Poke whom?",(["LIV":(/({({"poke",}),"$agent_name $agent_verb $target_name in the tummy.",}),({"-",}),/),]),/),"dots":(/"Connect the goddamn dots!",(["":(/({({"try",}),"$agent_name $agent_verb to connect the goddamn dots!",}),({}),/),]),/),"flame":(/"Flame whom?",(["LVS":(/({({"tear",}),"Using $agent_possessive tongue of fire, $agent_name $agent_verb into $target_name with a wicked flame.",}),({}),/),"":(/({({"burst",}),"$agent_name $agent_verb into flames.",}),({}),/),]),/),"hair":(/"Hair whom?",(["LVS":(/({({"point","have",}),"$agent_name $agent_verb out that $target_name $target_verb bigger hair than $agent_nominative.",}),({}),/),]),/),"point":(/"Point how?",(["LIV":(/({"point","$agent_name $agent_verb at $target_name.",}),({"-",}),/),"STR at LIV":(/({"point","$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"STR":(/({"point","$agent_name $agent_verb $adverb.",}),({"-",}),/),"at LIV STR":(/({"point","$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LIV":(/({"point","$agent_name $agent_verb at $target_name.",}),({"-",}),/),"":(/({"point","$agent_name $agent_verb.",}),({}),/),]),/),"furball":(/"Furball whom?",(["on LVS":(/({({"hack",}),"$agent_name $agent_verb up a furball on $target_name.",}),({}),/),"LVS":(/({({"hack",}),"$agent_name $agent_verb up a furball on $target_name.",}),({}),/),"":(/({({"hack",}),"$agent_name $agent_verb up a furball.",}),({}),/),]),/),"skip":(/"Skip?",(["LIV":(/({({"skip",}),"$agent_name $agent_verb around $target_name.",}),({}),/),"STR around LIV":(/({({"skip",}),"$agent_name $agent_verb $adverb around $target_name.",}),({"-",}),/),"around LIV STR":(/({({"skip",}),"$agent_name $agent_verb $adverb around $target_name.",}),({"-",}),/),"STR":(/({({"skip",}),"$agent_name $agent_verb $adverb around the room.",}),({"-",}),/),"STR LIV":(/({({"skip",}),"$agent_name $agent_verb $adverb around $target_name.",}),({"-",}),/),"":(/({({"skip",}),"$agent_name $agent_verb around the room.",}),({}),/),"around LIV":(/({({"skip",}),"$agent_name $agent_verb around $target_name.",}),({}),/),"LIV STR":(/({({"skip",}),"$agent_name $agent_verb $adverb around $target_name.",}),({"-",}),/),]),/),"tongue":(/"Tongue whom?",(["at LVS":(/({({"stick",}),"$agent_name $agent_verb $agent_possessive tongue out at $target_name.",}),({}),/),"LVS":(/({({"stick",}),"$agent_name $agent_verb $agent_possessive tongue out at $target_name.",}),({}),/),"":(/({({"stick",}),"$agent_name $agent_verb out $agent_possessive tongue.",}),({}),/),]),/),"sigh":(/"Just sigh.",(["STR":(/({({"sigh",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"sigh",}),"$agent_name $agent_verb.",}),({}),/),]),/),"chuckle":(/"Chuckle how?",(["STR LVS":(/({({"chuckle",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS STR":(/({({"chuckle",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS":(/({({"chuckle",}),"$agent_name $agent_verb at $target_name.",}),({}),/),"at LVS STR":(/({({"chuckle",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LVS":(/({({"chuckle",}),"$agent_name $agent_verb at $target_name.",}),({}),/),"STR at LVS":(/({({"chuckle",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"STR":(/({({"chuckle",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"chuckle",}),"$agent_name $agent_verb.",}),({}),/),]),/),"accuse":(/"Accuse whom of what?",(["LVS STR":(/({({"accuse",}),"$agent_name $agent_verb $target_name of $adverb.",}),({"*",}),/),"LVS":(/({({"accuse",}),"$agent_name $agent_verb $target_name of unspecified crimes.",}),({}),/),"LVS of STR":(/({({"accuse",}),"$agent_name $agent_verb $target_name of $adverb.",}),({"*",}),/),]),/),"waggle":(/"Waggle what?",(["STR at LIV":(/({({"waggle",}),"$agent_name $agent_verb $agent_possessive $adverb at $target_name.",}),({"*",}),/),"STR":(/({({"waggle",}),"$agent_name $agent_verb $agent_possessive $adverb.",}),({"*",}),/),"at LIV STR":(/({({"waggle",}),"$agent_name $agent_verb $agent_possessive $adverb at $target_name.",}),({"*",}),/),"STR LIV":(/({({"waggle",}),"$agent_name $agent_verb $agent_possessive $adverb at $target_name.",}),({"*",}),/),"LIV STR":(/({({"waggle",}),"$agent_name $agent_verb $agent_possessive $adverb at $target_name.",}),({"*",}),/),]),/),"swoon":(/"Swoon how?",(["STR":(/({({"swoon",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"swoon",}),"$agent_name $agent_verb.",}),({}),/),]),/),"applaud":(/"Applaud whom?",(["STR LVS":(/({({"applaud",}),"$agent_name $agent_verb $target_name $adverb.",}),({"-",}),/),"LVS STR":(/({({"applaud",}),"$agent_name $agent_verb $target_name $adverb.",}),({"-",}),/),"LVS":(/({({"applaud",}),"$agent_name $agent_verb $target_name.",}),({}),/),"STR":(/({({"applaud",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"applaud",}),"$agent_name $agent_verb.",}),({}),/),]),/),"grumble":(/"Grumble how?",(["STR LVS":(/({({"grumble",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS STR":(/({({"grumble",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"LVS":(/({({"grumble",}),"$agent_name $agent_verb angrily at $target_name.",}),({}),/),"at LVS STR":(/({({"grumble",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"at LVS":(/({({"grumble",}),"$agent_name $agent_verb angrily at $target_name.",}),({}),/),"STR at LVS":(/({({"grumble",}),"$agent_name $agent_verb $adverb at $target_name.",}),({"-",}),/),"STR":(/({({"grumble",}),"$agent_name $agent_verb $adverb.",}),({"-",}),/),"":(/({({"grumble",}),"$agent_name $agent_verb angrily.",}),({}),/),]),/),"tickle":(/"Tickle whom?",(["STR LVS":(/({({"tickle",}),"$agent_name $agent_verb $target_name $adverb.",}),({"-",}),/),"LVS STR":(/({({"tickle",}),"$agent_name $agent_verb $target_name $adverb.",}),({"-",}),/),"LVS":(/({({"tickle",}),"$agent_name $agent_verb $target_name mercilessly.",}),({}),/),]),/),"zip":(/"Zip around whom?",(["around LVS STR":(/({({"zip",}),"$agent_name $agent_verb $adverb around $target_name.",}),({"-",}),/),"around LVS":(/({({"zip",}),"$agent_name $agent_verb quickly around $target_name.",}),({}),/),"LVS STR":(/({({"zip",}),"$agent_name $agent_verb $adverb around $target_name.",}),({"-",}),/),"STR LVS":(/({({"zip",}),"$agent_name $agent_verb $adverb around $target_name.",}),({"-",}),/),"LVS":(/({({"zip",}),"$agent_name $agent_verb quickly around $target_name.",}),({}),/),"STR around LVS":(/({({"zip",}),"$agent_name $agent_verb $adverb around $target_name.",}),({"-",}),/),"STR":(/({({"zip",}),"$agent_name $agent_verb $adverb around the room.",}),({"-",}),/),"":(/({({"zip",}),"$agent_name $agent_verb quickly around the room.",}),({}),/),]),/),"thank":(/"Thank whom?",(["LIV":(/({({"thank",}),"$agent_name $agent_verb $target_name.",}),({}),/),]),/),"snot":(/"Snot whom?",(["LVS":(/({({"blow",}),"$agent_name $agent_verb snot on $target_name.",}),({}),/),"":(/({({"blow",}),"$agent_name $agent_verb snot all over the place.",}),({}),/),]),/),"cure":(/"Just cure.",(["":(/({({"slit","eat",}),"$agent_name $agent_verb the cats like cheese and $agent_verb the sweet, sticky things!",}),({}),/),]),/),"five":(/"Five who?",(["LIV":(/({({"give",}),"$agent_name $agent_verb $target_name a high five!",}),({"-",}),/),"LIV STR":(/({({"give",}),"$agent_name $adverb $agent_verb $target_name a high five!",}),({"-",}),/),]),/),]) +Adverbs ({"wildly","gradually","impatiently","hello","Americanishly","wryly","hard","stupidly","vaguely","Canadianishly","regretfully","sadly","lovingly","loudly","desperately","respectively","passionately","gleefully","respectfully","solemnly","angrily","slowly","toothlessly","profusely","tearfully","enthusiastically","seductively","happily","interestedly","apathetically","mercilessly","evilly","goodnight","vociferously","mischeviously","hapiky","excitedly","intently","shabbily","goodbye","violently","oddly","disgustingly",}) diff --git a/lib/save/stargate.o b/lib/save/stargate.o new file mode 100644 index 0000000..771f0af --- /dev/null +++ b/lib/save/stargate.o @@ -0,0 +1,4 @@ +#/daemon/stargate.c +PersistentInventory 0 +PersistentInventoryEnabled 0 +Stargates (["praxis":(["destination":"/domains/Praxis/square","endpoint":"","last_change":0,"status":"idle",]),"outer space":(["destination":"/domains/town/virtual/space/1,1,1","endpoint":"","last_change":0,"status":"idle",]),"cave":(["destination":"/domains/town/room/cave_entrance","endpoint":"","last_change":0,"status":"idle",]),"sea floor":(["destination":"/domains/town/virtual/bottom/5,0","endpoint":"","status":"idle",]),"stargate lab":(["destination":"/domains/default/room/stargate_lab","endpoint":"","last_change":0,"status":"idle",]),"tower":(["destination":"/domains/Ylsrim/room/tower","endpoint":"","last_change":0,"status":"idle",]),"campus lab":(["destination":"/domains/campus/room/slab","endpoint":"","last_change":0,"status":"idle",]),]) diff --git a/lib/save/types.o b/lib/save/types.o new file mode 100644 index 0000000..e2aa44f --- /dev/null +++ b/lib/save/types.o @@ -0,0 +1,4 @@ +#/daemon/types.c +types ({"vendor_types","terrain_types","size_types","respiration_types","position","mouth_types","message_class","meal_types","graphics","damage_types","build_types","boobytraps","body_types","armor_types",}) +configs ({"assessment","climb","jump","magic","medium","motion","rounds","soul","talk_type","vision","parser_error",}) +Types (["rounds":([6:"ROUND_EXTERNAL",5:"ROUND_INTERNAL",4:"ROUND_OTHER",3:"ROUND_MAGIC",2:"ROUND_WEAPON",1:"ROUND_MELEE",0:"ROUND_UNDEFINED",]),"body_types":([4:"B_BIPED",2:"B_QUADRUPED",1:"B_HUMANOID",33554432:"B_GASTROPOD",16777216:"B_FLAT",8388608:"B_SEMI_BIPEDAL",4194304:"B_WINGED_MAN",2097152:"B_AVIAN",1048576:"B_ORB",524288:"B_GELATINOUS",262144:"B_GEOMETRIC",131072:"B_SPECTRAL",65536:"B_TREE",32768:"B_PLANT",16384:"B_SNAKE",8192:"B_CHIMAERA",4096:"B_NEBULOUS",2048:"B_OCTOPOID",1024:"B_FISH",512:"B_CETACEAN",256:"B_PINNIPED",128:"B_CRUSTACEAN",64:"B_ARTHROPOD",32:"B_TENTACLED",16:"B_INSECTOID",8:"B_CHIROPTEROID",]),"assessment":([3:"POSSIBLE",2:"IMPOSSIBLE",1:"INCOMPLETE",]),"position":([4:"POSITION_SITTING",2:"POSITION_STANDING",1:"POSITION_NULL",128:"POSITION_SWIMMING",64:"POSITION_FLOATING",32:"POSITION_KNEELING",16:"POSITION_FLYING",8:"POSITION_LYING",]),"vendor_types":([4:"VT_WEAPON",2:"VT_TREASURE",2048:"VT_CONTRABAND",1024:"VT_HERB",512:"VT_PLANT",256:"VT_FISHING",128:"VT_MAGIC",64:"VT_DRINK",32:"VT_FOOD",16:"VT_LIGHT",8:"VT_ARMOR",]),"magic":([4:"SPELL_OTHER",3:"SPELL_COMBAT",2:"SPELL_DEFENSE",1:"SPELL_HEALING",]),"size_types":([4:"S_TINY",2:"S_MINISCULE",1:"S_MICROSCOPIC",2048:"S_VAST",1024:"S_GIGANTIC",512:"S_HUGE",256:"S_LARGE",128:"S_SOMEWHAT_LARGE",64:"S_HUMAN_SIZED",32:"S_SOMEWHAT_SMALL",16:"S_SMALL",8:"S_VERY_SMALL",]),"message_class":([4:"CMD_QUERY",2:"CMD_USER",1:"CMD_LOGIN",4194304:"MSG_RECEIVE",2097152:"MSG_ANNOYING",1048576:"MSG_OOB",524288:"MSG_HFTP",262144:"MSG_I3",131072:"MSG_RCP",65536:"MSG_HTTP",32768:"MSG_FTP",16384:"MSG_CHAN",8192:"MSG_QUERY",4096:"MSG_MSG_BOX",2048:"MSG_LOGIN",32:"MSG_ENV",0:"MSG_SYSTEM",8:"MSG_CONV",]),"boobytraps":([4:"BOOBYTRAP_CLOSE",2:"BOOBYTRAP_OPEN",4096:"BOOBYTRAP_UNWIELD",2048:"BOOBYTRAP_WIELD",1024:"BOOBYTRAP_REMOVE",512:"BOOBYTRAP_WEAR",256:"BOOBYTRAP_PICK",128:"BOOBYTRAP_STEAL",64:"BOOBYTRAP_UNLOCK",32:"BOOBYTRAP_LOCK",16:"BOOBYTRAP_DROP",8:"BOOBYTRAP_GET",]),"armor_types":([4:"A_GLOVE",2:"A_RING",1:"A_CUSTOM",2097152:"A_EXO",1048576:"A_BODY_ARMOR",524288:"A_COLLAR",262144:"A_AMULET",131072:"A_ARMOR",65536:"A_SHIELD",32768:"A_WEAPON",16384:"A_VEST",8192:"A_CLOAK",4096:"A_SHIRT",2048:"A_BELT",1024:"A_PANTS",512:"A_VISOR",256:"A_HELMET",128:"A_LONG_SOCK",64:"A_SOCK",32:"A_LONG_BOOT",16:"A_BOOT",8:"A_LONG_GLOVE",]),"build_types":([4:"B_SLIM",2:"B_THIN",1:"B_WAIF",256:"B_MORBIDLY_OBESE",128:"B_OBESE",64:"B_STOUT",32:"B_HUSKY",16:"B_LARGE",8:"B_MEDIUM",]),"soul":([9:"DisableAnd",8:"Preposition",7:"ForceLocation",6:"Locations",5:"ExtraAdverbs",4:"ForceAdverb",3:"NoArgs",2:"NoTarget",1:"Targeted",0:"SOUL_ADVERBS",]),"climb":([5:"CLIMB_THROUGH",4:"CLIMB_INTO",3:"CLIMB_OUT",2:"CLIMB_DOWN",1:"CLIMB_UP",]),"medium":([6:"MEDIUM_METHANE",5:"MEDIUM_WATER",4:"MEDIUM_SPACE",3:"MEDIUM_SURFACE",2:"MEDIUM_AIR",1:"MEDIUM_LAND",]),"meal_types":([4:"MEAL_DRINK",2:"MEAL_FOOD",32:"MEAL_POISON",16:"MEAL_ALCOHOL",8:"MEAL_CAFFEINE",]),"motion":([4:"M_MAGIC",3:"M_SEA",2:"M_AIR",1:"M_LAND",]),"talk_type":([5:"TALK_WORLD",4:"TALK_AREA",3:"TALK_LOCAL",2:"TALK_SEMI_PRIVATE",1:"TALK_PRIVATE",0:"TALK_VOID",]),"graphics":([4:"CB_YES",2:"CB_OK",16:"CB_CANCEL",8:"CB_NO",]),"vision":([7:"VISION_TOO_BRIGHT",6:"VISION_BRIGHT",5:"VISION_LIGHT",4:"VISION_CLEAR",3:"VISION_DIM",2:"VISION_DARK",1:"VISION_TOO_DARK",0:"VISION_BLIND",]),"respiration_types":([4:"R_VACUUM",2:"R_WATER",1:"R_AIR",8:"R_METHANE",]),"damage_types":([4:"BLADE",2:"BLUNT",67108864:"INERTIA",33554432:"UNDERPRESSURE",16777216:"OVERPRESSURE",8388608:"DRAMA",4194304:"KARMA",2097152:"OTHER",1048576:"EMP",524288:"SONIC",262144:"EMOTIONAL",131072:"DEATHRAY",65536:"ANOXIA",32768:"PSIONIC",16384:"PIERCE",8192:"TRAUMA",4096:"DISEASE",2048:"POISON",1024:"MAGIC",512:"ACID",256:"GAS",128:"HEAT",64:"COLD",32:"SHOCK",16:"WATER",8:"KNIFE",]),"terrain_types":([4:"T_INDOORS",2:"T_OUTDOORS",1:"T_CUSTOM",1048576:"T_SEAFLOOR",524288:"T_BIOLOGICAL",262144:"T_ICE",131072:"T_SAND",65536:"T_SNOW",32768:"T_PLANAR",16384:"T_PLASMA",8192:"T_MAGMA",4096:"T_SPACE",2048:"T_UNDERGROUND",1024:"T_ROUGH",512:"T_JUNGLE",256:"T_WOODS",128:"T_SWAMP",64:"T_MIDAIR",32:"T_SURFACE",16:"T_UNDERWATER",8:"T_ROAD",]),"parser_error":([]),"mouth_types":([4:"MOUTH_TOOTHED",2:"MOUTH_LIPPED",1:"MOUTH_NONE",2048:"MOUTH_TUSKED",1024:"MOUTH_STATIC",512:"MOUTH_DISEASED",256:"MOUTH_VENOMOUS",128:"MOUTH_FANGED",64:"MOUTH_TONGUED",32:"MOUTH_BALEEN",16:"MOUTH_MANDIBLED",8:"MOUTH_BEAKED",]),"jump":([5:"JUMP_ON",4:"JUMP_OVER",3:"JUMP_THROUGH",2:"JUMP_FROM",1:"JUMP_INTO",]),]) diff --git a/lib/save/unique.o b/lib/save/unique.o new file mode 100644 index 0000000..8146f64 --- /dev/null +++ b/lib/save/unique.o @@ -0,0 +1,2 @@ +#/daemon/unique.c +Objects (["/domains/default/obj/generator":1599391574,"/domains/Ylsrim/npc/segata":1599393278,"/domains/town/npc/leo":1599034567,"/domains/Ylsrim/obj/cask":1599393278,"/domains/town/obj/waterwheel":1599393288,"/domains/Ylsrim/npc/traveler":1599393287,]) diff --git a/lib/secure/cfg/aliases.cfg b/lib/secure/cfg/aliases.cfg new file mode 100644 index 0000000..7db6685 --- /dev/null +++ b/lib/secure/cfg/aliases.cfg @@ -0,0 +1,24 @@ +# /adm/db/aliases.db +# from Nightmare IV +# the IIPS 3.1 alias database +# maintains a database of mud-wide mailer aliases +# created by Descartes of Borg 940513 + +# You can specify lists through several different syntaxes +# To simply specify hard coded aliases: +# alias: user1 user2 user3 +# To get an alias list from a call to a function: +# alias: |object;function;arg1;arg2 (two args max, must be strings) +# You may use addition on function calls: +# alias: |object;function;arg + object;function;arg +# To include a pre-defined mapping: +# include: |object;function;arg +# To exclude a group for above: +# exclude: alias1 alias2 + +include: |/secure/daemon/master;query_groups +root: SECURE +arch: SECURE ASSIST +exclude: SECURE ASSIST +creator: |/secure/daemon/master;query_creators + diff --git a/lib/secure/cfg/classes/cleric b/lib/secure/cfg/classes/cleric new file mode 100644 index 0000000..befc0da --- /dev/null +++ b/lib/secure/cfg/classes/cleric @@ -0,0 +1,18 @@ +cleric +PLAYER_CLASS 0 +melee attack:1:4 +blunt attack:1:2 +projectile attack:1:2 +magic attack:1:1 +melee defense:1:4 +blade defense:1:3 +knife defense:1:3 +projectile defense:1:3 +conjuring:1:1 +bargaining:1:1 +stealth:1:4 +fishing:1:1 +blunt defense:1:4 +magic defense:1:2 +faith:1:1 +healing:1:1 diff --git a/lib/secure/cfg/classes/explorer b/lib/secure/cfg/classes/explorer new file mode 100644 index 0000000..88fa75e --- /dev/null +++ b/lib/secure/cfg/classes/explorer @@ -0,0 +1,15 @@ +explorer +PLAYER_CLASS 1 +blade attack:2:1 +blade defense:2:1 +melee attack:2:1 +blunt attack:1:2 +knife attack:1:3 +projectile attack:1:1 +melee defense:2:2 +blunt defense:1:2 +knife defense:1:2 +projectile defense:2:1 +magic attack:2:3 +magic defense:2:3 +bargaining:2:4 diff --git a/lib/secure/cfg/classes/fighter b/lib/secure/cfg/classes/fighter new file mode 100644 index 0000000..9c09312 --- /dev/null +++ b/lib/secure/cfg/classes/fighter @@ -0,0 +1,15 @@ +fighter +PLAYER_CLASS 1 +blade attack:1:4 +multi-hand:1:4 +multi-weapon:1:4 +blade defense:1:4 +melee attack:1:4 +blunt attack:1:4 +knife attack:1:4 +projectile attack:1:1 +melee defense:1:4 +blunt defense:1:4 +knife defense:1:4 +projectile defense:1:1 +bargaining:4:4 diff --git a/lib/secure/cfg/classes/mage b/lib/secure/cfg/classes/mage new file mode 100644 index 0000000..1b01d86 --- /dev/null +++ b/lib/secure/cfg/classes/mage @@ -0,0 +1,12 @@ +mage +PLAYER_CLASS 1 +magic attack:1:4 +magic defense:1:4 +conjuring:1:4 +bargaining:1:2 +blunt defense:3:1 +knife defense:2:1 +melee defense:3:1 +blunt attack:3:1 +knife attack:2:1 +melee attack:4:2 diff --git a/lib/secure/cfg/classes/thief b/lib/secure/cfg/classes/thief new file mode 100644 index 0000000..50028f3 --- /dev/null +++ b/lib/secure/cfg/classes/thief @@ -0,0 +1,17 @@ +thief +PLAYER_CLASS 0 +melee attack:2:2 +blunt attack:2:2 +knife attack:1:2 +projectile attack:1:4 +melee defense:1:2 +blade defense:1:2 +knife defense:1:3 +projectile defense:1:4 +bargaining:1:4 +stealth:1:1 +stealing:1:1 +detection:1:1 +concealment:1:1 +fishing:1:1 +murder:1:2 diff --git a/lib/secure/cfg/flashpolicy.cfg b/lib/secure/cfg/flashpolicy.cfg new file mode 100644 index 0000000..e863195 --- /dev/null +++ b/lib/secure/cfg/flashpolicy.cfg @@ -0,0 +1,15 @@ +<?xml version="1.0"?> +<!DOCTYPE cross-domain-policy SYSTEM "/xml/dtds/cross-domain-policy.dtd"> + +<!-- Policy file for xmlsocket://socks.example.com --> +<cross-domain-policy> + + <!-- This is a master socket policy file --> + <!-- No other socket policies on the host will be permitted --> + <site-control permitted-cross-domain-policies="master-only"/> + + <!-- Instead of setting to-ports="*", administrator's can use ranges and commas --> + <allow-access-from domain="*" to-ports="*" /> + +</cross-domain-policy> + diff --git a/lib/secure/cfg/global_template.cfg b/lib/secure/cfg/global_template.cfg new file mode 100644 index 0000000..06a99cc --- /dev/null +++ b/lib/secure/cfg/global_template.cfg @@ -0,0 +1,30 @@ +#ifndef __GLOBAL_H +#define __GLOBAL_H + +#define CONFIG_H "TEMPLATE_CONFIG" +#define NETWORK_H "TEMPLATE_NETWORK" +#define ROOMS_H "TEMPLATE_ROOMS" +#define SECRETS_H "TEMPLATE_SECRETS" + +#include CONFIG_H +#include <lib.h> + +#if COMPAT_MODE +#include <compat.h> +#endif + +#define DAY_ONE 720550800 + +#define SEFUN "/secure/sefun/sefun" + +#define DEBUG + +#ifdef debug +#undef debug +#endif /* debug */ + +//#ifdef DEBUG +//#define debug(x, y) (find_player(x) || master())->eventPrint(x) +//#endif /* DEBUG */ + +#endif /* GLOBAL_H */ diff --git a/lib/secure/cfg/groups.cfg b/lib/secure/cfg/groups.cfg new file mode 100644 index 0000000..0341da8 --- /dev/null +++ b/lib/secure/cfg/groups.cfg @@ -0,0 +1,13 @@ +# Names are added to this file to determine groups. +# Groups should be named in all caps. +# The format is: +# (GROUP) name1:name2 + +(SECURE) babylon +(ASSIST) babylon +(ELDER) babylon +(TEST) babylon +(INTERMUD) babylon +(BUILDER) babylon +(TELNET) babylon +(EMOTES) babylon diff --git a/lib/secure/cfg/instance_template.cfg b/lib/secure/cfg/instance_template.cfg new file mode 100644 index 0000000..2121f06 --- /dev/null +++ b/lib/secure/cfg/instance_template.cfg @@ -0,0 +1,150 @@ +############################################################################### +# Customizable runtime config file for MudOS # +# NOTE: All paths specified here are relative to the mudlib directory except # +# for mudlib directory, and binary directory. # +# Lines beginning with a # or a newline are ignored. # +############################################################################### +# name of this mud +name : TEMPLATE_NAME + +# port number to accept users on +external_port_1 : telnet TEMPLATE_PORT + +# absolute pathname of mudlib +mudlib directory : TEMPLATE_LIB + +# absolute pathname of driver/config dir +binary directory : TEMPLATE_BIN + +# the address server is an external program that lets the mud translate +# internet names to numbers (and vice versa). select an unused port. +address server ip : localhost +address server port : 8099 + +# fd6 stuff is what allows portbind to work properly. If +# you want to have the mud accept connections on port 23 but run +# as non-root, you uncomment the two fd6 lines below and issue the +# appropriate portbind command to start the mud. +#fd6 port : 23 +#fd6 kind : telnet + +# debug.log and author/domain stats are stored here +log directory : /log + +# the directories which are searched by #include <...> +# for multiple dirs, separate each path with a ':' +include directories : /secure/include:/include + +# Directory to save binaries in. (if BINARIES is defined) +save binaries directory : /secure/save/binaries + +# the file which defines the master object +master file : /secure/daemon/master + +# the file where all global simulated efuns are defined. +simulated efun file : /secure/sefun/sefun + +# file to swap out objects; not used if time to swap is 0 +swap file : /secure/tmp/swap + +# alternate debug.log file name (assumed to be in specified 'log directory') +debug log file : runtime + +# This is an include file which is automatically #include'd in all objects +global include file : <TEMPLATE_GLOBAL> + +# if an object is left alone for a certain time, then the +# function clean_up will be called. This function can do anything, +# like destructing the object. If the function isn't defined by the +# object, then nothing will happen. +# This time should be substantially longer than the swapping time. +time to clean up : 2100000000 + +# How long time until an unused object is swapped out. +# Machine with too many players and too little memory: 900 (15 minutes) +# Machine with few players and lot of memory: 10000 +# Machine with infinite memory: 0 (never swap). +time to swap : 0 + +# How many seconds until an object is reset again. +time to reset : 2100000000 + +# Maximum number of bits in a bit field. They are stored in printable +# strings, 6 bits per byte. +maximum bits in a bitfield : 1200 + +# Max number of local variables in a function. +maximum local variables : 35 + +# Maximum amount of "eval cost" per thread - execution is halted when +# it is exceeded. +maximum evaluation cost : 5000000 + +# This is the maximum array size allowed for one single array. +maximum array size : 64000 + +# This is the maximum allowed size of a variable of type 'buffer'. +maximum buffer size : 400000 + +# Max size for a mapping +maximum mapping size : 64000 + +# Max inherit chain size +inherit chain size : 30 + +# maximum length of a string variable +maximum string length : 200000 + +# Max size of a file allowed to be read by 'read_file()'. +maximum read file size : 200000 + +# max number of bytes you allow to be read and written with read_bytes +# and write_bytes +maximum byte transfer : 10000 + +# Reserve an extra memory area from malloc(), to free when we run out +# of memory and allow the mudlib to shutdown. +# If this value is 0, no area will be reserved. +reserved size : 0 + +# Define the size of the shared string hash table. This number should +# a prime, probably between 1000 and 30000; if you set it to about 1/5 +# of the number of distinct strings you have, you will get a hit ratio +# (number of comparisons to find a string) very close to 1, as found strings +# are automatically moved to the head of a hash chain. You will never +# need more, and you will still get good results with a smaller table. +hash table size : 7001 + +# Object hash table size. +# Define this like you did with the strings; probably set to about 1/4 of +# the number of objects in a game, as the distribution of accesses to +# objects is somewhat more uniform than that of strings. +object table size : 1501 + +# default no-matching-action message +default fail message : What? + +# default message when error() occurs (optional) +default error message : Something *REALLY* bad just happened. + +############################################################################### +# The following aren't currently used or implemented (yet) # +############################################################################### + +# maximum number of users in the game (unused currently) +maximum users : 40 + +# Define the maximum stack size of the stack machine. This stack will also +# contain all local variables and arguments. (unused currently) +evaluator stack size : 1000 + +# Define the size of the compiler stack. This defines how complex +# expressions the compiler can parse. (unused currently) +compiler stack size : 200 + +# Define the maximum call depth for functions. (unused currently) +maximum call depth : 30 + +# There is a hash table for living objects, used by find_living(). +# (unused currently) +living hash table size : 100 diff --git a/lib/secure/cfg/ip_blacklist.cfg b/lib/secure/cfg/ip_blacklist.cfg new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/lib/secure/cfg/ip_blacklist.cfg @@ -0,0 +1 @@ + diff --git a/lib/secure/cfg/ip_unrestrict.cfg b/lib/secure/cfg/ip_unrestrict.cfg new file mode 100644 index 0000000..7b9ad53 --- /dev/null +++ b/lib/secure/cfg/ip_unrestrict.cfg @@ -0,0 +1 @@ +127.0.0.1 diff --git a/lib/secure/cfg/mudos.autobak b/lib/secure/cfg/mudos.autobak new file mode 100644 index 0000000..17c2f0e --- /dev/null +++ b/lib/secure/cfg/mudos.autobak @@ -0,0 +1,150 @@ +############################################################################### +# Customizable runtime config file for MudOS # +# NOTE: All paths specified here are relative to the mudlib directory except # +# for mudlib directory, and binary directory. # +# Lines beginning with a # or a newline are ignored. # +############################################################################### +# name of this mud +name : Dead Souls Bet + +# port number to accept users on +external_port_1 : telnet 6666 + +# absolute pathname of mudlib +mudlib directory : /mud/limpet/lib + +# absolute pathname of driver/config dir +binary directory : /mud/limpet/bin + +# the address server is an external program that lets the mud translate +# internet names to numbers (and vice versa). select an unused port. +address server ip : localhost +address server port : 8099 + +# fd6 stuff is what allows portbind to work properly. If +# you want to have the mud accept connections on port 23 but run +# as non-root, you uncomment the two fd6 lines below and issue the +# appropriate portbind command to start the mud. +#fd6 port : 23 +#fd6 kind : telnet + +# debug.log and author/domain stats are stored here +log directory : /log + +# the directories which are searched by #include <...> +# for multiple dirs, separate each path with a ':' +include directories : /secure/include:/include + +# Directory to save binaries in. (if BINARIES is defined) +save binaries directory : /secure/save/binaries + +# the file which defines the master object +master file : /secure/daemon/master + +# the file where all global simulated efuns are defined. +simulated efun file : /secure/sefun/sefun + +# file to swap out objects; not used if time to swap is 0 +swap file : /secure/tmp/swap + +# alternate debug.log file name (assumed to be in specified 'log directory') +debug log file : runtime + +# This is an include file which is automatically #include'd in all objects +global include file : <global.h> + +# if an object is left alone for a certain time, then the +# function clean_up will be called. This function can do anything, +# like destructing the object. If the function isn't defined by the +# object, then nothing will happen. +# This time should be substantially longer than the swapping time. +time to clean up : 2100000000 + +# How long time until an unused object is swapped out. +# Machine with too many players and too little memory: 900 (15 minutes) +# Machine with few players and lot of memory: 10000 +# Machine with infinite memory: 0 (never swap). +time to swap : 0 + +# How many seconds until an object is reset again. +time to reset : 2100000000 + +# Maximum number of bits in a bit field. They are stored in printable +# strings, 6 bits per byte. +maximum bits in a bitfield : 1200 + +# Max number of local variables in a function. +maximum local variables : 35 + +# Maximum amount of "eval cost" per thread - execution is halted when +# it is exceeded. +maximum evaluation cost : 5000000 + +# This is the maximum array size allowed for one single array. +maximum array size : 64000 + +# This is the maximum allowed size of a variable of type 'buffer'. +maximum buffer size : 400000 + +# Max size for a mapping +maximum mapping size : 64000 + +# Max inherit chain size +inherit chain size : 30 + +# maximum length of a string variable +maximum string length : 200000 + +# Max size of a file allowed to be read by 'read_file()'. +maximum read file size : 200000 + +# max number of bytes you allow to be read and written with read_bytes +# and write_bytes +maximum byte transfer : 10000 + +# Reserve an extra memory area from malloc(), to free when we run out +# of memory and allow the mudlib to shutdown. +# If this value is 0, no area will be reserved. +reserved size : 0 + +# Define the size of the shared string hash table. This number should +# a prime, probably between 1000 and 30000; if you set it to about 1/5 +# of the number of distinct strings you have, you will get a hit ratio +# (number of comparisons to find a string) very close to 1, as found strings +# are automatically moved to the head of a hash chain. You will never +# need more, and you will still get good results with a smaller table. +hash table size : 7001 + +# Object hash table size. +# Define this like you did with the strings; probably set to about 1/4 of +# the number of objects in a game, as the distribution of accesses to +# objects is somewhat more uniform than that of strings. +object table size : 1501 + +# default no-matching-action message +default fail message : What? + +# default message when error() occurs (optional) +default error message : Something *REALLY* bad just happened. + +############################################################################### +# The following aren't currently used or implemented (yet) # +############################################################################### + +# maximum number of users in the game (unused currently) +maximum users : 40 + +# Define the maximum stack size of the stack machine. This stack will also +# contain all local variables and arguments. (unused currently) +evaluator stack size : 1000 + +# Define the size of the compiler stack. This defines how complex +# expressions the compiler can parse. (unused currently) +compiler stack size : 200 + +# Define the maximum call depth for functions. (unused currently) +maximum call depth : 30 + +# There is a hash table for living objects, used by find_living(). +# (unused currently) +living hash table size : 100 diff --git a/lib/secure/cfg/mudos.autobak.6666 b/lib/secure/cfg/mudos.autobak.6666 new file mode 100644 index 0000000..4de4ad7 --- /dev/null +++ b/lib/secure/cfg/mudos.autobak.6666 @@ -0,0 +1,156 @@ +# DO NOT CHANGE THE "mudlib directory" LINE. +# DOING SO WILL MAKE THE DRIVER FAIL TO RUN. +# +# It's a linefeed problem we hope to fix soon. +# in the meantime, you have to run the mud from c:\ds +# +############################################################################### +# Customizable runtime config file for MudOS # +# NOTE: All paths specified here are relative to the mudlib directory except # +# for mudlib directory, and binary directory. # +# Lines beginning with a # or a newline are ignored. # +############################################################################### +# name of this mud +name : Zebu + +# port number to accept users on +external_port_1 : telnet 6666 + + +# the address server is an external program that lets the mud translate +# internet names to numbers (and vice versa). select an unused port. +address server ip : localhost +address server port : 9999 + +# absolute pathname of mudlib + + +mudlib directory : lib + + + +# absolute pathname of driver/config dir + +binary directory : bin + + +# debug.log and author/domain stats are stored here +log directory : /log + +# the directories which are searched by #include <...> +# for multiple dirs, separate each path with a ':' +include directories : /secure/include:/include + +# Directory to save binaries in. (if BINARIES is defined) +save binaries directory : /secure/save/binaries + +# the file which defines the master object +master file : /secure/daemon/master + +# the file where all global simulated efuns are defined. +simulated efun file : /secure/sefun/sefun + +# file to swap out objects; not used if time to swap is 0 +swap file : /secure/tmp/swap + +# alternate debug.log file name (assumed to be in specified 'log directory') +debug log file : runtime + +# This is an include file which is automatically #include'd in all objects +global include file : <global.h> + +# if an object is left alone for a certain time, then the +# function clean_up will be called. This function can do anything, +# like destructing the object. If the function isn't defined by the +# object, then nothing will happen. +# This time should be substantially longer than the swapping time. +time to clean up : 14400 + +# How long time until an unused object is swapped out. +# Machine with too many players and too little memory: 900 (15 minutes) +# Machine with few players and lot of memory: 10000 +# Machine with infinite memory: 0 (never swap). +time to swap : 90000 + +# How many seconds until an object is reset again. +time to reset : 900000 + +# Maximum number of bits in a bit field. They are stored in printable +# strings, 6 bits per byte. +maximum bits in a bitfield : 1200 + +# Max number of local variables in a function. +maximum local variables : 35 + +# Maximum amount of "eval cost" per thread - execution is halted when +# it is exceeded. +maximum evaluation cost : 5000000 + +# This is the maximum array size allowed for one single array. +maximum array size : 64000 + +# This is the maximum allowed size of a variable of type 'buffer'. +maximum buffer size : 400000 + +# Max size for a mapping +maximum mapping size : 64000 + +# Max inherit chain size +inherit chain size : 30 + +# maximum length of a string variable +maximum string length : 200000 + +# Max size of a file allowed to be read by 'read_file()'. +maximum read file size : 200000 + +# max number of bytes you allow to be read and written with read_bytes +# and write_bytes +maximum byte transfer : 10000 + +# Reserve an extra memory area from malloc(), to free when we run out +# of memory and allow the mudlib to shutdown. +# If this value is 0, no area will be reserved. +reserved size : 0 + +# Define the size of the shared string hash table. This number should +# a prime, probably between 1000 and 30000; if you set it to about 1/5 +# of the number of distinct strings you have, you will get a hit ratio +# (number of comparisons to find a string) very close to 1, as found strings +# are automatically moved to the head of a hash chain. You will never +# need more, and you will still get good results with a smaller table. +hash table size : 7001 + +# Object hash table size. +# Define this like you did with the strings; probably set to about 1/4 of +# the number of objects in a game, as the distribution of accesses to +# objects is somewhat more uniform than that of strings. +object table size : 1501 + +# default no-matching-action message +default fail message : What? + +# default message when error() occurs (optional) +default error message : Something *REALLY* bad just happened. + +############################################################################### +# The following aren't currently used or implemented (yet) # +############################################################################### + +# maximum number of users in the game (unused currently) +maximum users : 40 + +# Define the maximum stack size of the stack machine. This stack will also +# contain all local variables and arguments. (unused currently) +evaluator stack size : 1000 + +# Define the size of the compiler stack. This defines how complex +# expressions the compiler can parse. (unused currently) +compiler stack size : 200 + +# Define the maximum call depth for functions. (unused currently) +maximum call depth : 30 + +# There is a hash table for living objects, used by find_living(). +# (unused currently) +living hash table size : 100 diff --git a/lib/secure/cfg/mudos.cfg b/lib/secure/cfg/mudos.cfg new file mode 100644 index 0000000..4de4ad7 --- /dev/null +++ b/lib/secure/cfg/mudos.cfg @@ -0,0 +1,156 @@ +# DO NOT CHANGE THE "mudlib directory" LINE. +# DOING SO WILL MAKE THE DRIVER FAIL TO RUN. +# +# It's a linefeed problem we hope to fix soon. +# in the meantime, you have to run the mud from c:\ds +# +############################################################################### +# Customizable runtime config file for MudOS # +# NOTE: All paths specified here are relative to the mudlib directory except # +# for mudlib directory, and binary directory. # +# Lines beginning with a # or a newline are ignored. # +############################################################################### +# name of this mud +name : Zebu + +# port number to accept users on +external_port_1 : telnet 6666 + + +# the address server is an external program that lets the mud translate +# internet names to numbers (and vice versa). select an unused port. +address server ip : localhost +address server port : 9999 + +# absolute pathname of mudlib + + +mudlib directory : lib + + + +# absolute pathname of driver/config dir + +binary directory : bin + + +# debug.log and author/domain stats are stored here +log directory : /log + +# the directories which are searched by #include <...> +# for multiple dirs, separate each path with a ':' +include directories : /secure/include:/include + +# Directory to save binaries in. (if BINARIES is defined) +save binaries directory : /secure/save/binaries + +# the file which defines the master object +master file : /secure/daemon/master + +# the file where all global simulated efuns are defined. +simulated efun file : /secure/sefun/sefun + +# file to swap out objects; not used if time to swap is 0 +swap file : /secure/tmp/swap + +# alternate debug.log file name (assumed to be in specified 'log directory') +debug log file : runtime + +# This is an include file which is automatically #include'd in all objects +global include file : <global.h> + +# if an object is left alone for a certain time, then the +# function clean_up will be called. This function can do anything, +# like destructing the object. If the function isn't defined by the +# object, then nothing will happen. +# This time should be substantially longer than the swapping time. +time to clean up : 14400 + +# How long time until an unused object is swapped out. +# Machine with too many players and too little memory: 900 (15 minutes) +# Machine with few players and lot of memory: 10000 +# Machine with infinite memory: 0 (never swap). +time to swap : 90000 + +# How many seconds until an object is reset again. +time to reset : 900000 + +# Maximum number of bits in a bit field. They are stored in printable +# strings, 6 bits per byte. +maximum bits in a bitfield : 1200 + +# Max number of local variables in a function. +maximum local variables : 35 + +# Maximum amount of "eval cost" per thread - execution is halted when +# it is exceeded. +maximum evaluation cost : 5000000 + +# This is the maximum array size allowed for one single array. +maximum array size : 64000 + +# This is the maximum allowed size of a variable of type 'buffer'. +maximum buffer size : 400000 + +# Max size for a mapping +maximum mapping size : 64000 + +# Max inherit chain size +inherit chain size : 30 + +# maximum length of a string variable +maximum string length : 200000 + +# Max size of a file allowed to be read by 'read_file()'. +maximum read file size : 200000 + +# max number of bytes you allow to be read and written with read_bytes +# and write_bytes +maximum byte transfer : 10000 + +# Reserve an extra memory area from malloc(), to free when we run out +# of memory and allow the mudlib to shutdown. +# If this value is 0, no area will be reserved. +reserved size : 0 + +# Define the size of the shared string hash table. This number should +# a prime, probably between 1000 and 30000; if you set it to about 1/5 +# of the number of distinct strings you have, you will get a hit ratio +# (number of comparisons to find a string) very close to 1, as found strings +# are automatically moved to the head of a hash chain. You will never +# need more, and you will still get good results with a smaller table. +hash table size : 7001 + +# Object hash table size. +# Define this like you did with the strings; probably set to about 1/4 of +# the number of objects in a game, as the distribution of accesses to +# objects is somewhat more uniform than that of strings. +object table size : 1501 + +# default no-matching-action message +default fail message : What? + +# default message when error() occurs (optional) +default error message : Something *REALLY* bad just happened. + +############################################################################### +# The following aren't currently used or implemented (yet) # +############################################################################### + +# maximum number of users in the game (unused currently) +maximum users : 40 + +# Define the maximum stack size of the stack machine. This stack will also +# contain all local variables and arguments. (unused currently) +evaluator stack size : 1000 + +# Define the size of the compiler stack. This defines how complex +# expressions the compiler can parse. (unused currently) +compiler stack size : 200 + +# Define the maximum call depth for functions. (unused currently) +maximum call depth : 30 + +# There is a hash table for living objects, used by find_living(). +# (unused currently) +living hash table size : 100 diff --git a/lib/secure/cfg/mudos.orig b/lib/secure/cfg/mudos.orig new file mode 100644 index 0000000..c401b28 --- /dev/null +++ b/lib/secure/cfg/mudos.orig @@ -0,0 +1,156 @@ +# DO NOT CHANGE THE "mudlib directory" LINE. +# DOING SO WILL MAKE THE DRIVER FAIL TO RUN. +# +# It's a linefeed problem we hope to fix soon. +# in the meantime, you have to run the mud from c:\ds +# +############################################################################### +# Customizable runtime config file for MudOS # +# NOTE: All paths specified here are relative to the mudlib directory except # +# for mudlib directory, and binary directory. # +# Lines beginning with a # or a newline are ignored. # +############################################################################### +# name of this mud +name : DeadSoulsWin + +# port number to accept users on +external_port_1 : telnet 6666 + + +# the address server is an external program that lets the mud translate +# internet names to numbers (and vice versa). select an unused port. +address server ip : localhost +address server port : 9999 + +# absolute pathname of mudlib + + +mudlib directory : lib + + + +# absolute pathname of driver/config dir + +binary directory : bin + + +# debug.log and author/domain stats are stored here +log directory : /log + +# the directories which are searched by #include <...> +# for multiple dirs, separate each path with a ':' +include directories : /secure/include:/include + +# Directory to save binaries in. (if BINARIES is defined) +save binaries directory : /secure/save/binaries + +# the file which defines the master object +master file : /secure/daemon/master + +# the file where all global simulated efuns are defined. +simulated efun file : /secure/sefun/sefun + +# file to swap out objects; not used if time to swap is 0 +swap file : /secure/tmp/swap + +# alternate debug.log file name (assumed to be in specified 'log directory') +debug log file : runtime + +# This is an include file which is automatically #include'd in all objects +global include file : <global.h> + +# if an object is left alone for a certain time, then the +# function clean_up will be called. This function can do anything, +# like destructing the object. If the function isn't defined by the +# object, then nothing will happen. +# This time should be substantially longer than the swapping time. +time to clean up : 14400 + +# How long time until an unused object is swapped out. +# Machine with too many players and too little memory: 900 (15 minutes) +# Machine with few players and lot of memory: 10000 +# Machine with infinite memory: 0 (never swap). +time to swap : 90000 + +# How many seconds until an object is reset again. +time to reset : 900000 + +# Maximum number of bits in a bit field. They are stored in printable +# strings, 6 bits per byte. +maximum bits in a bitfield : 1200 + +# Max number of local variables in a function. +maximum local variables : 35 + +# Maximum amount of "eval cost" per thread - execution is halted when +# it is exceeded. +maximum evaluation cost : 5000000 + +# This is the maximum array size allowed for one single array. +maximum array size : 64000 + +# This is the maximum allowed size of a variable of type 'buffer'. +maximum buffer size : 400000 + +# Max size for a mapping +maximum mapping size : 64000 + +# Max inherit chain size +inherit chain size : 30 + +# maximum length of a string variable +maximum string length : 200000 + +# Max size of a file allowed to be read by 'read_file()'. +maximum read file size : 200000 + +# max number of bytes you allow to be read and written with read_bytes +# and write_bytes +maximum byte transfer : 10000 + +# Reserve an extra memory area from malloc(), to free when we run out +# of memory and allow the mudlib to shutdown. +# If this value is 0, no area will be reserved. +reserved size : 0 + +# Define the size of the shared string hash table. This number should +# a prime, probably between 1000 and 30000; if you set it to about 1/5 +# of the number of distinct strings you have, you will get a hit ratio +# (number of comparisons to find a string) very close to 1, as found strings +# are automatically moved to the head of a hash chain. You will never +# need more, and you will still get good results with a smaller table. +hash table size : 7001 + +# Object hash table size. +# Define this like you did with the strings; probably set to about 1/4 of +# the number of objects in a game, as the distribution of accesses to +# objects is somewhat more uniform than that of strings. +object table size : 1501 + +# default no-matching-action message +default fail message : What? + +# default message when error() occurs (optional) +default error message : Something *REALLY* bad just happened. + +############################################################################### +# The following aren't currently used or implemented (yet) # +############################################################################### + +# maximum number of users in the game (unused currently) +maximum users : 40 + +# Define the maximum stack size of the stack machine. This stack will also +# contain all local variables and arguments. (unused currently) +evaluator stack size : 1000 + +# Define the size of the compiler stack. This defines how complex +# expressions the compiler can parse. (unused currently) +compiler stack size : 200 + +# Define the maximum call depth for functions. (unused currently) +maximum call depth : 30 + +# There is a hash table for living objects, used by find_living(). +# (unused currently) +living hash table size : 100 diff --git a/lib/secure/cfg/mudos.win32 b/lib/secure/cfg/mudos.win32 new file mode 100644 index 0000000..4de4ad7 --- /dev/null +++ b/lib/secure/cfg/mudos.win32 @@ -0,0 +1,156 @@ +# DO NOT CHANGE THE "mudlib directory" LINE. +# DOING SO WILL MAKE THE DRIVER FAIL TO RUN. +# +# It's a linefeed problem we hope to fix soon. +# in the meantime, you have to run the mud from c:\ds +# +############################################################################### +# Customizable runtime config file for MudOS # +# NOTE: All paths specified here are relative to the mudlib directory except # +# for mudlib directory, and binary directory. # +# Lines beginning with a # or a newline are ignored. # +############################################################################### +# name of this mud +name : Zebu + +# port number to accept users on +external_port_1 : telnet 6666 + + +# the address server is an external program that lets the mud translate +# internet names to numbers (and vice versa). select an unused port. +address server ip : localhost +address server port : 9999 + +# absolute pathname of mudlib + + +mudlib directory : lib + + + +# absolute pathname of driver/config dir + +binary directory : bin + + +# debug.log and author/domain stats are stored here +log directory : /log + +# the directories which are searched by #include <...> +# for multiple dirs, separate each path with a ':' +include directories : /secure/include:/include + +# Directory to save binaries in. (if BINARIES is defined) +save binaries directory : /secure/save/binaries + +# the file which defines the master object +master file : /secure/daemon/master + +# the file where all global simulated efuns are defined. +simulated efun file : /secure/sefun/sefun + +# file to swap out objects; not used if time to swap is 0 +swap file : /secure/tmp/swap + +# alternate debug.log file name (assumed to be in specified 'log directory') +debug log file : runtime + +# This is an include file which is automatically #include'd in all objects +global include file : <global.h> + +# if an object is left alone for a certain time, then the +# function clean_up will be called. This function can do anything, +# like destructing the object. If the function isn't defined by the +# object, then nothing will happen. +# This time should be substantially longer than the swapping time. +time to clean up : 14400 + +# How long time until an unused object is swapped out. +# Machine with too many players and too little memory: 900 (15 minutes) +# Machine with few players and lot of memory: 10000 +# Machine with infinite memory: 0 (never swap). +time to swap : 90000 + +# How many seconds until an object is reset again. +time to reset : 900000 + +# Maximum number of bits in a bit field. They are stored in printable +# strings, 6 bits per byte. +maximum bits in a bitfield : 1200 + +# Max number of local variables in a function. +maximum local variables : 35 + +# Maximum amount of "eval cost" per thread - execution is halted when +# it is exceeded. +maximum evaluation cost : 5000000 + +# This is the maximum array size allowed for one single array. +maximum array size : 64000 + +# This is the maximum allowed size of a variable of type 'buffer'. +maximum buffer size : 400000 + +# Max size for a mapping +maximum mapping size : 64000 + +# Max inherit chain size +inherit chain size : 30 + +# maximum length of a string variable +maximum string length : 200000 + +# Max size of a file allowed to be read by 'read_file()'. +maximum read file size : 200000 + +# max number of bytes you allow to be read and written with read_bytes +# and write_bytes +maximum byte transfer : 10000 + +# Reserve an extra memory area from malloc(), to free when we run out +# of memory and allow the mudlib to shutdown. +# If this value is 0, no area will be reserved. +reserved size : 0 + +# Define the size of the shared string hash table. This number should +# a prime, probably between 1000 and 30000; if you set it to about 1/5 +# of the number of distinct strings you have, you will get a hit ratio +# (number of comparisons to find a string) very close to 1, as found strings +# are automatically moved to the head of a hash chain. You will never +# need more, and you will still get good results with a smaller table. +hash table size : 7001 + +# Object hash table size. +# Define this like you did with the strings; probably set to about 1/4 of +# the number of objects in a game, as the distribution of accesses to +# objects is somewhat more uniform than that of strings. +object table size : 1501 + +# default no-matching-action message +default fail message : What? + +# default message when error() occurs (optional) +default error message : Something *REALLY* bad just happened. + +############################################################################### +# The following aren't currently used or implemented (yet) # +############################################################################### + +# maximum number of users in the game (unused currently) +maximum users : 40 + +# Define the maximum stack size of the stack machine. This stack will also +# contain all local variables and arguments. (unused currently) +evaluator stack size : 1000 + +# Define the size of the compiler stack. This defines how complex +# expressions the compiler can parse. (unused currently) +compiler stack size : 200 + +# Define the maximum call depth for functions. (unused currently) +maximum call depth : 30 + +# There is a hash table for living objects, used by find_living(). +# (unused currently) +living hash table size : 100 diff --git a/lib/secure/cfg/preload.cfg b/lib/secure/cfg/preload.cfg new file mode 100644 index 0000000..902e482 --- /dev/null +++ b/lib/secure/cfg/preload.cfg @@ -0,0 +1,53 @@ +# This is the preload file. Any line beginning with a # will be ignored +# (useful for comments like this). This is where to put objects you want +# to make sure are always loaded...Sulam +# +# +#/secure/daemon/remote +#/secure/daemon/i3router/server +#/secure/daemon/imc2server/server +#/secure/daemon/flash_policy +/secure/daemon/bboard +/domains/default/room/furnace +/domains/default/room/pod +/domains/default/room/wiz_hall +/secure/room/arch +/domains/campus/room/start +#/secure/daemon/instances +/secure/daemon/portal +/secure/daemon/chat +/secure/daemon/imc2 +/secure/daemon/inet +/secure/daemon/reload +/secure/daemon/file +/secure/daemon/function +/secure/daemon/log +/secure/daemon/snoop +/secure/daemon/ping +/daemon/types +/secure/daemon/reaper +/daemon/decay +/secure/daemon/preload_check +/daemon/command +/daemon/verbs +/secure/daemon/economy +/daemon/seasons +/secure/daemon/events +/secure/daemon/folders +/secure/daemon/letters +/secure/daemon/localpost +/secure/daemon/remotepost +/secure/daemon/players +/lib/player +/daemon/soul +/lib/std/table +/lib/sentient +/secure/daemon/update +/secure/daemon/imc2 +/daemon/intermud +/secure/daemon/resolv +/secure/daemon/autoexec +/daemon/skills +/daemon/stats +/daemon/races +/daemon/classes diff --git a/lib/secure/cfg/races/amphibian b/lib/secure/cfg/races/amphibian new file mode 100644 index 0000000..abede67 --- /dev/null +++ b/lib/secure/cfg/races/amphibian @@ -0,0 +1,29 @@ +RACE amphibian +SENSITIVITY 20:800 +LANGUAGE Batrachian +STATS charisma:10:4 +STATS durability:21:3 +STATS intelligence:1:3 +STATS luck:21:3 +STATS agility:10:4 +STATS wisdom:43:1 +STATS speed:1:5 +STATS strength:1:5 +STATS coordination:31:2 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_AMULET,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB left rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left forepaw:left fore leg:4:: +LIMB right forepaw:right fore leg:4:: +LIMB left rear paw:left rear leg:4:: +LIMB right rear paw:right rear leg:4:: +MASS 10 +SIZE S_VERY_SMALL +BODY_TYPE B_QUADRUPED +RESPIRATION_TYPE R_AIR|R_WATER +SWIMMING_RACE +MOUTH MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/ancap b/lib/secure/cfg/races/ancap new file mode 100644 index 0000000..9adbe3f --- /dev/null +++ b/lib/secure/cfg/races/ancap @@ -0,0 +1,33 @@ +RACE ancap +PLAYER_RACE 1 +SENSITIVITY 25:750 +LANGUAGE Capitalist +SKILL psionic defense:2:3:4:5 +STATS agility:33:3 +STATS charisma:33:2 +STATS coordination:33:2 +STATS durability:30:4 +STATS intelligence:40:1 +STATS luck:20:3 +STATS speed:30:3 +STATS strength:20:3 +STATS wisdom:40:3 +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_BELT,A_AMULET,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB right foot:right leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left foot:left leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB right hand:right arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB left hand:left arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +HAND right hand:5 +HAND left hand:5 +SWIMMING_RACE +MASS 1800 +SIZE S_HUMAN_SIZED +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/android b/lib/secure/cfg/races/android new file mode 100644 index 0000000..77cbd51 --- /dev/null +++ b/lib/secure/cfg/races/android @@ -0,0 +1,34 @@ +RACE android +SENSITIVITY 25:750 +LANGUAGE English +STATS agility:50:3 +STATS charisma:50:2 +STATS coordination:50:2 +STATS durability:50:4 +STATS intelligence:50:1 +STATS luck:10:3 +STATS speed:50:3 +STATS strength:50:4 +STATS wisdom:50:3 +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_BELT,A_AMULET,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB right foot:right leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left foot:left leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB right hand:right arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB left hand:left arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +HAND right hand:5 +HAND left hand:5 +LIMBLESS_COMBAT_RACE +NONBITING_RACE +SWIMMING_RACE +MASS 3000 +SIZE S_HUMAN_SIZED +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_VACUUM +NOT_MEAT +MOUTH MOUTH_STATIC diff --git a/lib/secure/cfg/races/ape b/lib/secure/cfg/races/ape new file mode 100644 index 0000000..97ba16c --- /dev/null +++ b/lib/secure/cfg/races/ape @@ -0,0 +1,29 @@ +RACE ape +SENSITIVITY 20:800 +LANGUAGE Ur +RESISTANCE COLD:low +STATS charisma:5:3 +STATS durability:43:1 +STATS intelligence:15:3 +STATS luck:10:4 +STATS agility:30:5 +STATS wisdom:1:2 +STATS speed:30:5 +STATS strength:43:1 +STATS coordination:20:5 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB left rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left forepaw:left fore leg:4:: +LIMB right forepaw:right fore leg:4:: +LIMB left rear paw:left rear leg:4:: +LIMB right rear paw:right rear leg:4:: +MASS 3000 +SIZE S_LARGE +BODY_TYPE B_SEMI_BIPEDAL +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/arachnid b/lib/secure/cfg/races/arachnid new file mode 100644 index 0000000..0988305 --- /dev/null +++ b/lib/secure/cfg/races/arachnid @@ -0,0 +1,27 @@ +RACE arachnid +SENSITIVITY 20:800 +LANGUAGE Arachnid +STATS charisma:1:5 +STATS durability:1:5 +STATS intelligence:1:3 +STATS luck:21:3 +STATS agility:43:1 +STATS wisdom:1:5 +STATS speed:31:2 +STATS strength:10:4 +STATS coordination:43:1 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB head:torso:1:A_BODY_ARMOR,A_VISOR,A_HELMET,A_CLOAK,A_CUSTOM +LIMB 1st leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB 8th leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB 2nd leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB 5th leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB 7th leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB 4th leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB 3rd leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB 6th leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +BODY_TYPE B_INSECTOID +MASS 5 +SIZE S_TINY +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_MANDIBLED diff --git a/lib/secure/cfg/races/artrell b/lib/secure/cfg/races/artrell new file mode 100644 index 0000000..a10a5f7 --- /dev/null +++ b/lib/secure/cfg/races/artrell @@ -0,0 +1,38 @@ +RACE artrell +SENSITIVITY 7:610 +LANGUAGE Artrexcian +RESISTANCE COLD:low +RESISTANCE SHOCK:high +STATS agility:50:1 +STATS charisma:0:4 +STATS coordination:40:3 +STATS durability:10:3 +STATS intelligence:10:4 +STATS luck:33:3 +STATS speed:40:2 +STATS strength:10:3 +STATS wisdom:5:5 +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_BELT,A_CUSTOM +LIMB head:torso:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB right foot:right leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left foot:left leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB first arm:torso:3:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB second arm:torso:3:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB third arm:torso:3:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB fourth arm:torso:3:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB first hand:first arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB second hand:second arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB third hand:third arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB fourth hand:fourth arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +HAND first hand:2 +HAND second hand:2 +HAND third hand:2 +HAND fourth hand:2 +MASS 1200 +SIZE S_SOMEWHAT_SMALL +BODY_TYPE B_BIPED|B_INSECTOID +SWIMMING_RACE +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_MANDIBLED diff --git a/lib/secure/cfg/races/avidryl b/lib/secure/cfg/races/avidryl new file mode 100644 index 0000000..2b196ff --- /dev/null +++ b/lib/secure/cfg/races/avidryl @@ -0,0 +1,32 @@ +RACE avidryl +SENSITIVITY 15:850 +LANGUAGE Avidryl +STATS agility:50:1 +STATS charisma:20:3 +STATS coordination:30:1 +STATS durability:20:2 +STATS intelligence:15:4 +STATS luck:2:5 +STATS speed:20:3 +STATS strength:40:2 +STATS wisdom:10:5 +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_BELT,A_CUSTOM +LIMB head:torso:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CLOAK,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CLOAK,A_CUSTOM +LIMB right foot:right leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left foot:left leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB right hand:right arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB left hand:left arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB right wing:torso:4:: +LIMB left wing:torso:4:: +HAND right hand:5 +HAND left hand:5 +FLYING_RACE +MASS 1500 +SIZE S_HUMAN_SIZED +BODY_TYPE B_WINGED_MAN +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/balrog b/lib/secure/cfg/races/balrog new file mode 100644 index 0000000..dbb40c8 --- /dev/null +++ b/lib/secure/cfg/races/balrog @@ -0,0 +1,32 @@ +RACE balrog +SENSITIVITY 10:670 +LANGUAGE Balrog +RESISTANCE HEAT:high +STATS agility:40:1 +STATS charisma:1:5 +STATS coordination:30:3 +STATS durability:40:1 +STATS intelligence:30:2 +STATS luck:20:3 +STATS speed:30:2 +STATS strength:30:3 +STATS wisdom:10:3 +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_BELT,A_AMULET,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB right foot:right leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left foot:left leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB right hand:right arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB left hand:left arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +HAND right hand:6 +HAND left hand:6 +MASS 30000 +SIZE S_GIGANTIC +BODY_TYPE B_WINGED_MAN +RESPIRATION_TYPE R_VACUUM +NOT_MEAT +MOUTH MOUTH_TOOTHED|MOUTH_FANGED diff --git a/lib/secure/cfg/races/bat b/lib/secure/cfg/races/bat new file mode 100644 index 0000000..a00f9af --- /dev/null +++ b/lib/secure/cfg/races/bat @@ -0,0 +1,26 @@ +RACE bat +SENSITIVITY 15:650 +LANGUAGE Murcielago +STATS agility:10:2 +STATS charisma:11:3 +STATS coordination:10:2 +STATS durability:65:1 +STATS intelligence:1:3 +STATS luck:24:3 +STATS speed:52:3 +STATS strength:13:4 +STATS wisdom:10:5 +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_BELT,A_CUSTOM +LIMB head:torso:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB right claw:right leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left claw:left leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left wing:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB right wing:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +FLYING_RACE +MASS 10 +SIZE S_VERY_SMALL +BODY_TYPE B_CHIROPTEROID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED|MOUTH_FANGED|MOUTH_DISEASED diff --git a/lib/secure/cfg/races/bear b/lib/secure/cfg/races/bear new file mode 100644 index 0000000..794b3dc --- /dev/null +++ b/lib/secure/cfg/races/bear @@ -0,0 +1,31 @@ +RACE bear +SENSITIVITY 20:800 +LANGUAGE Ursine +RESISTANCE SHOCK:high +RESISTANCE COLD:low +STATS charisma:21:3 +STATS durability:43:1 +STATS intelligence:15:3 +STATS luck:10:4 +STATS agility:1:5 +STATS wisdom:31:2 +STATS speed:1:5 +STATS strength:43:1 +STATS coordination:1:5 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB left rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left forepaw:left fore leg:4:: +LIMB right forepaw:right fore leg:4:: +LIMB left rear paw:left rear leg:4:: +LIMB right rear paw:right rear leg:4:: +SWIMMING_RACE +MASS 4000 +SIZE S_LARGE +BODY_TYPE B_SEMI_BIPEDAL +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED|MOUTH_FANGED diff --git a/lib/secure/cfg/races/bird b/lib/secure/cfg/races/bird new file mode 100644 index 0000000..27a5e5e --- /dev/null +++ b/lib/secure/cfg/races/bird @@ -0,0 +1,28 @@ +RACE bird +SENSITIVITY 20:800 +LANGUAGE Avian +RESISTANCE SHOCK:high +RESISTANCE COLD:low +STATS charisma:31:2 +STATS durability:1:5 +STATS intelligence:1:5 +STATS luck:21:3 +STATS agility:43:1 +STATS wisdom:10:4 +STATS speed:43:1 +STATS strength:10:4 +STATS coordination:10:4 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left foot:left leg:4:A_SOCK,A_LONG_SOCK,A_BOOT,A_LONG_BOOT,A_CUSTOM +LIMB right foot:right leg:4:A_SOCK,A_LONG_SOCK,A_BOOT,A_LONG_BOOT,A_CUSTOM +LIMB right wing:torso:4:: +LIMB left wing:torso:4:: +FLYING_RACE +MASS 10 +SIZE S_VERY_SMALL +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_BEAKED diff --git a/lib/secure/cfg/races/blob b/lib/secure/cfg/races/blob new file mode 100644 index 0000000..02f2fd2 --- /dev/null +++ b/lib/secure/cfg/races/blob @@ -0,0 +1,21 @@ +RACE blob +SENSITIVITY 20:800 +LANGUAGE creosote +STATS charisma:1:5 +STATS durability:1:5 +STATS intelligence:1:5 +STATS luck:1:5 +STATS agility:1:5 +STATS wisdom:1:5 +STATS speed:1:5 +STATS strength:1:5 +STATS coordination:1:5 +LIMB torso:0:1:A_VEST +LIMB head:torso:1:A_HELMET +LIMBLESS_COMBAT_RACE +LIMBLESS_RACE +MASS 40 +SIZE S_SMALL +BODY_TYPE B_SNAKE +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/bot b/lib/secure/cfg/races/bot new file mode 100644 index 0000000..fe2abc7 --- /dev/null +++ b/lib/secure/cfg/races/bot @@ -0,0 +1,23 @@ +RACE bot +SENSITIVITY 0:1000 +LANGUAGE Bocce +STATS agility:50:3 +STATS charisma:50:2 +STATS coordination:50:2 +STATS durability:50:4 +STATS intelligence:50:1 +STATS luck:10:3 +STATS speed:50:3 +STATS strength:50:4 +STATS wisdom:50:3 +LIMB torso:0:1:A_AMULET,A_CUSTOM +LIMBLESS_COMBAT_RACE +NONBITING_RACE +FLYING_RACE +SWIMMING_RACE +MASS 1000 +SIZE S_SOMEWHAT_SMALL +BODY_TYPE B_ORB +RESPIRATION_TYPE R_VACUUM +NOT_MEAT +MOUTH MOUTH_STATIC diff --git a/lib/secure/cfg/races/bugbear b/lib/secure/cfg/races/bugbear new file mode 100644 index 0000000..9b3e5c4 --- /dev/null +++ b/lib/secure/cfg/races/bugbear @@ -0,0 +1,32 @@ +RACE bugbear +SENSITIVITY 20:800 +LANGUAGE Insectursine +RESISTANCE SHOCK:high +RESISTANCE COLD:low +STATS charisma:21:3 +STATS ugliness:91:3 +STATS durability:43:1 +STATS intelligence:21:3 +STATS luck:10:4 +STATS agility:1:5 +STATS wisdom:31:2 +STATS speed:1:5 +STATS strength:43:1 +STATS coordination:1:5 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB left rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left forepaw:left fore leg:4:: +LIMB right forepaw:right fore leg:4:: +LIMB left rear paw:left rear leg:4:: +LIMB right rear paw:right rear leg:4:: +SWIMMING_RACE +MASS 450 +SIZE S_LARGE +BODY_TYPE B_SEMI_BIPEDAL +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_MANDIBLED diff --git a/lib/secure/cfg/races/cat b/lib/secure/cfg/races/cat new file mode 100644 index 0000000..d6101fa --- /dev/null +++ b/lib/secure/cfg/races/cat @@ -0,0 +1,31 @@ +RACE cat +SENSITIVITY 20:800 +LANGUAGE Feline +SKILL stealth:1:5:4:6 +STATS charisma:43:1 +STATS durability:10:4 +STATS intelligence:1:5 +STATS luck:43:1 +STATS agility:43:1 +STATS wisdom:10:4 +STATS speed:31:2 +STATS strength:10:4 +STATS coordination:21:3 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB left rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left forepaw:left fore leg:4:: +LIMB right forepaw:right fore leg:4:: +LIMB left rear paw:left rear leg:4:: +LIMB right rear paw:right rear leg:4:: +LIMB tail:torso:5:: +SWIMMING_RACE +MASS 100 +SIZE S_SMALL +BODY_TYPE B_QUADRUPED +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED|MOUTH_FANGED diff --git a/lib/secure/cfg/races/centaur b/lib/secure/cfg/races/centaur new file mode 100644 index 0000000..6374e77 --- /dev/null +++ b/lib/secure/cfg/races/centaur @@ -0,0 +1,37 @@ +RACE centaur +SENSITIVITY 20:800 +LANGUAGE Centaurian +RESISTANCE SHOCK:high +RESISTANCE COLD:low +STATS charisma:21:3 +STATS durability:43:1 +STATS intelligence:21:3 +STATS luck:43:1 +STATS agility:21:3 +STATS wisdom:31:2 +STATS speed:31:2 +STATS strength:31:2 +STATS coordination:10:4 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB lower torso:torso:1:: +LIMB right arm:torso:2:: +LIMB left arm::torso:2:: +LIMB right fore leg:lower torso:3:: +LIMB left fore leg:lower torso:3:: +LIMB right back leg:lower torso:3:: +LIMB left back leg:lower torso:3:: +LIMB right hand:right arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB left hand:left arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB right fore hoof:right fore leg:4:: +LIMB left fore hoof:left fore leg:4:: +LIMB right back hoof:right back leg:4:: +LIMB left back hoof:left back leg:4:: +HAND right hand:5 +HAND left hand:5 +MASS 3000 +SIZE S_LARGE +BODY_TYPE B_SEMI_BIPEDAL +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/chimera b/lib/secure/cfg/races/chimera new file mode 100644 index 0000000..03a1b4d --- /dev/null +++ b/lib/secure/cfg/races/chimera @@ -0,0 +1,33 @@ +RACE chimera +SENSITIVITY 20:800 +LANGUAGE Chimerole +RESISTANCE SHOCK:high +RESISTANCE COLD:low +STATS charisma:1:5 +STATS durability:31:2 +STATS intelligence:21:3 +STATS luck:10:4 +STATS agility:31:2 +STATS wisdom:21:3 +STATS speed:43:1 +STATS strength:21:3 +STATS coordination:10:4 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB lion head:torso:2:A_BODY_ARMOR,A_VISOR,A_HELMET,A_CLOAK,A_CUSTOM +LIMB goat head:torso:2:A_BODY_ARMOR,A_VISOR,A_HELMET,A_CLOAK,A_CUSTOM +LIMB dragon head:torso:2:A_BODY_ARMOR,A_VISOR,A_HELMET,A_CLOAK,A_CUSTOM +LIMB right wing:torso:3:: +LIMB left wing:torso:3:: +LIMB left rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left forepaw:left fore leg:4:: +LIMB left rear paw:left rear leg:4:: +LIMB right forepaw:right fore leg:4:: +LIMB right rear paw:right rear leg:4:: +MASS 500 +SIZE S_LARGE +BODY_TYPE B_CHIMAERA +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_BEAKED|MOUTH_TONGUED|MOUTH_FANGED diff --git a/lib/secure/cfg/races/cow b/lib/secure/cfg/races/cow new file mode 100644 index 0000000..ea80266 --- /dev/null +++ b/lib/secure/cfg/races/cow @@ -0,0 +1,31 @@ +RACE cow +SENSITIVITY 20:800 +LANGUAGE Bovine +RESISTANCE SHOCK:high +RESISTANCE COLD:low +STATS charisma:10:4 +STATS durability:43:1 +STATS intelligence:1:5 +STATS luck:1:5 +STATS agility:1:5 +STATS wisdom:1:5 +STATS speed:1:5 +STATS strength:31:2 +STATS coordination:21:3 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left fore hoof:left fore leg:4:: +LIMB left rear hoof:left rear leg:4:: +LIMB right fore hoof:right fore leg:4:: +LIMB right rear hoof:right rear leg:4:: +NONBITING_RACE +MASS 4000 +SIZE S_LARGE +BODY_TYPE B_QUADRUPED +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/deer b/lib/secure/cfg/races/deer new file mode 100644 index 0000000..fadb66c --- /dev/null +++ b/lib/secure/cfg/races/deer @@ -0,0 +1,31 @@ +RACE deer +SENSITIVITY 20:800 +LANGUAGE Tier +RESISTANCE SHOCK:high +RESISTANCE COLD:low +STATS charisma:21:3 +STATS durability:31:2 +STATS intelligence:1:5 +STATS luck:10:4 +STATS agility:21:3 +STATS wisdom:1:5 +STATS speed:31:2 +STATS strength:43:1 +STATS coordination:10:4 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left fore hoof:left fore leg:4:: +LIMB left rear hoof:left rear leg:4:: +LIMB right fore hoof:right fore leg:4:: +LIMB right rear hoof:right rear leg:4:: +NONBITING_RACE +MASS 3000 +SIZE S_HUMAN_SIZED +BODY_TYPE B_QUADRUPED +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/demi-god b/lib/secure/cfg/races/demi-god new file mode 100644 index 0000000..7435558 --- /dev/null +++ b/lib/secure/cfg/races/demi-god @@ -0,0 +1,34 @@ +RACE demi-god +SENSITIVITY 10:800 +LANGUAGE Sublime +RESISTANCE SHOCK:high +RESISTANCE COLD:low +STATS charisma:31:2 +STATS durability:31:2 +STATS intelligence:31:2 +STATS luck:43:1 +STATS agility:31:2 +STATS wisdom:31:2 +STATS speed:43:1 +STATS strength:31:2 +STATS coordination:31:2 +RESISTANCE ALL_DAMAGE:high +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIRT,A_ARMOR,A_BODY_ARMOR,A_SHIELD,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIRT,A_ARMOR,A_BODY_ARMOR,A_SHIELD,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right foot:right leg:4:A_SOCK,A_LONG_SOCK,A_BOOT,A_LONG_BOOT,A_CUSTOM +LIMB right hand:right arm:4:A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB left foot:left leg:4:A_SOCK,A_LONG_SOCK,A_BOOT,A_LONG_BOOT,A_CUSTOM +LIMB left hand:left arm:4:A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +HAND right hand:5 +HAND left hand:5 +SWIMMING_RACE +MASS 2000 +SIZE S_HUMAN_SIZED +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/demon b/lib/secure/cfg/races/demon new file mode 100644 index 0000000..2e8f507 --- /dev/null +++ b/lib/secure/cfg/races/demon @@ -0,0 +1,36 @@ +RACE demon +SENSITIVITY 0:800 +LANGUAGE Demoniac +RESISTANCE SHOCK:high +RESISTANCE COLD:low +STATS charisma:31:2 +STATS durability:31:2 +STATS intelligence:31:2 +STATS luck:43:1 +STATS agility:31:2 +STATS wisdom:10:4 +STATS speed:31:2 +STATS strength:31:2 +STATS coordination:31:2 +STATS psi:50:2 +SKILL psionic defense:8:1:0:0 +SKILL psionic attack:8:1:0:0 +SKILL psionic detection:8:1:0:0 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIRT,A_ARMOR,A_BODY_ARMOR,A_SHIELD,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIRT,A_ARMOR,A_BODY_ARMOR,A_SHIELD,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right foot:right leg:4:A_SOCK,A_LONG_SOCK,A_BOOT,A_LONG_BOOT,A_CUSTOM +LIMB right hand:right arm:4:A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB left foot:left leg:4:A_SOCK,A_LONG_SOCK,A_BOOT,A_LONG_BOOT,A_CUSTOM +LIMB left hand:left arm:4:A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +FLYING_RACE +SWIMMING_RACE +MASS 250 +SIZE S_SOMEWHAT_LARGE +BODY_TYPE B_WINGED_MAN +RESPIRATION_TYPE R_VACUUM +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED|MOUTH_FANGED diff --git a/lib/secure/cfg/races/dog b/lib/secure/cfg/races/dog new file mode 100644 index 0000000..c2e9eef --- /dev/null +++ b/lib/secure/cfg/races/dog @@ -0,0 +1,30 @@ +RACE dog +SENSITIVITY 20:800 +LANGUAGE Canine +RESISTANCE SHOCK:high +RESISTANCE COLD:low +STATS charisma:31:2 +STATS durability:21:3 +STATS intelligence:10:4 +STATS luck:10:4 +STATS agility:21:3 +STATS wisdom:1:5 +STATS speed:21:3 +STATS strength:21:3 +STATS coordination:10:4 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB left rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left forepaw:left fore leg:4:: +LIMB right forepaw:right fore leg:4:: +LIMB left rear paw:left rear leg:4:: +LIMB right rear paw:right rear leg:4:: +MASS 500 +SIZE S_SOMEWHAT_SMALL +BODY_TYPE B_QUADRUPED +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED|MOUTH_FANGED diff --git a/lib/secure/cfg/races/dragon b/lib/secure/cfg/races/dragon new file mode 100644 index 0000000..2ce276e --- /dev/null +++ b/lib/secure/cfg/races/dragon @@ -0,0 +1,34 @@ +RACE dragon +SENSITIVITY 0:800 +LANGUAGE Dragonate +RESISTANCE SHOCK:high +RESISTANCE COLD:low +STATS charisma:31:2 +STATS durability:43:1 +STATS intelligence:31:2 +STATS luck:43:1 +STATS agility:43:1 +STATS wisdom:43:1 +STATS speed:21:3 +STATS strength:43:1 +STATS coordination:21:3 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left wing:torso:3:: +LIMB right wing:torso:3:: +LIMB right fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left forepaw:left fore leg:4:: +LIMB left rear paw:left rear leg:4:: +LIMB right forepaw:right fore leg:4:: +LIMB right rear paw:right rear leg:4:: +FLYING_RACE +MASS 40000 +SIZE S_HUGE +BODY_TYPE B_SEMI_BIPEDAL +SWIMMING_RACE +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_TOOTHED|MOUTH_TONGUED|MOUTH_FANGED diff --git a/lib/secure/cfg/races/dryad b/lib/secure/cfg/races/dryad new file mode 100644 index 0000000..6763251 --- /dev/null +++ b/lib/secure/cfg/races/dryad @@ -0,0 +1,32 @@ +RACE dryad +SENSITIVITY 20:800 +LANGUAGE Vadinho +RESISTANCE SHOCK:high +RESISTANCE COLD:low +STATS charisma:43:1 +STATS durability:1:5 +STATS intelligence:10:4 +STATS luck:31:2 +STATS agility:31:2 +STATS wisdom:31:2 +STATS speed:31:2 +STATS strength:10:4 +STATS coordination:21:3 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIRT,A_ARMOR,A_BODY_ARMOR,A_SHIELD,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIRT,A_ARMOR,A_BODY_ARMOR,A_SHIELD,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right foot:right leg:4:A_SOCK,A_LONG_SOCK,A_BOOT,A_LONG_BOOT,A_CUSTOM +LIMB right hand:right arm:4:A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB left foot:left leg:4:A_SOCK,A_LONG_SOCK,A_BOOT,A_LONG_BOOT,A_CUSTOM +HAND right hand:5 +HAND left hand:5 +LIMB left hand:left arm:4:A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +MASS 100 +SIZE S_SMALL +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/dummy b/lib/secure/cfg/races/dummy new file mode 100644 index 0000000..1c7fd69 --- /dev/null +++ b/lib/secure/cfg/races/dummy @@ -0,0 +1,29 @@ +RACE dummy +SENSITIVITY 0:1000 +LANGUAGE Common +STATS charisma:1:1 +STATS durability:1:1 +STATS intelligence:1:1 +STATS luck:1:1 +STATS agility:1:1 +STATS wisdom:1:1 +STATS speed:1:1 +STATS strength:1:1 +STATS coordination:1:1 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB head:torso:1:A_BODY_ARMOR,A_VISOR,A_HELMET,A_CLOAK,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIRT,A_ARMOR,A_BODY_ARMOR,A_SHIELD,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIRT,A_ARMOR,A_BODY_ARMOR,A_SHIELD,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right foot:right leg:4:A_SOCK,A_LONG_SOCK,A_BOOT,A_LONG_BOOT,A_CUSTOM +LIMB right hand:right arm:4:A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB left foot:left leg:4:A_SOCK,A_LONG_SOCK,A_BOOT,A_LONG_BOOT,A_CUSTOM +LIMB left hand:left arm:4:A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +NONBITING_RACE +MASS 5000 +SIZE S_LARGE +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_VACUUM +NOT_MEAT +MOUTH MOUTH_STATIC diff --git a/lib/secure/cfg/races/dwarf b/lib/secure/cfg/races/dwarf new file mode 100644 index 0000000..8673e35 --- /dev/null +++ b/lib/secure/cfg/races/dwarf @@ -0,0 +1,33 @@ +RACE dwarf +PLAYER_RACE 1 +SENSITIVITY 5:650 +LANGUAGE Malkierien +RESISTANCE COLD:low +RESISTANCE BLUNT:low +STATS agility:10:2 +STATS charisma:11:3 +STATS coordination:10:2 +STATS durability:60:1 +STATS intelligence:18:3 +STATS luck:60:1 +STATS speed:20:3 +STATS strength:40:1 +STATS wisdom:20:3 +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_BELT,A_AMULET,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB right foot:right leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left foot:left leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB left hand:left arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB right hand:right arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +HAND left hand:4 +HAND right hand:4 +MASS 200 +SIZE S_SOMEWHAT_SMALL +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/elemental b/lib/secure/cfg/races/elemental new file mode 100644 index 0000000..4cf6fbc --- /dev/null +++ b/lib/secure/cfg/races/elemental @@ -0,0 +1,26 @@ +RACE elemental +SENSITIVITY 20:800 +LANGUAGE Periodict +RESISTANCE SHOCK:high +RESISTANCE BLUNT:low +RESISTANCE COLD:low +STATS charisma:21:3 +STATS durability:21:3 +STATS intelligence:21:3 +STATS luck:21:3 +STATS agility:21:3 +STATS wisdom:21:3 +STATS speed:21:3 +STATS strength:21:3 +STATS coordination:21:3 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB head:torso:1:A_BODY_ARMOR,A_VISOR,A_HELMET,A_CLOAK,A_CUSTOM +LIMBLESS_COMBAT_RACE +LIMBLESS_RACE +NONBITING_RACE +MASS 40000 +SIZE S_LARGE +BODY_TYPE B_NEBULOUS +RESPIRATION_TYPE R_VACUUM +NOT_MEAT +MOUTH MOUTH_NONE diff --git a/lib/secure/cfg/races/elephant b/lib/secure/cfg/races/elephant new file mode 100644 index 0000000..8611b1e --- /dev/null +++ b/lib/secure/cfg/races/elephant @@ -0,0 +1,33 @@ +RACE elephant +SENSITIVITY 20:800 +LANGUAGE Pachydermian +RESISTANCE SHOCK:high +RESISTANCE BLUNT:low +RESISTANCE COLD:low +STATS charisma:10:4 +STATS durability:43:1 +STATS intelligence:10:4 +STATS luck:21:3 +STATS agility:1:5 +STATS wisdom:43:1 +STATS speed:10:4 +STATS strength:43:1 +STATS coordination:21:3 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB left rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB trunk:head:3:: +LIMB right forepaw:right fore leg:4:: +LIMB left rear paw:left rear leg:4:: +LIMB left forepaw:left fore leg:4:: +LIMB right rear paw:right rear leg:4:: +SWIMMING_RACE +MASS 40000 +SIZE S_HUGE +BODY_TYPE B_QUADRUPED +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED|MOUTH_TUSKED diff --git a/lib/secure/cfg/races/elf b/lib/secure/cfg/races/elf new file mode 100644 index 0000000..77b540b --- /dev/null +++ b/lib/secure/cfg/races/elf @@ -0,0 +1,33 @@ +RACE elf +PLAYER_RACE 1 +SENSITIVITY 7:730 +LANGUAGE Edhellen +STATS agility:40:3 +STATS charisma:40:1 +STATS coordination:10:2 +STATS durability:20:4 +STATS intelligence:50:1 +STATS luck:50:1 +STATS speed:40:3 +STATS strength:15:5 +STATS wisdom:50:1 +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_BELT,A_AMULET,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB right foot:right leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left foot:left leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB right hand:right arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB left hand:left arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +HAND right hand:5 +HAND left hand:5 +NONBITING_RACE +SWIMMING_RACE +MASS 1500 +SIZE S_HUMAN_SIZED +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/faerie b/lib/secure/cfg/races/faerie new file mode 100644 index 0000000..5432fd9 --- /dev/null +++ b/lib/secure/cfg/races/faerie @@ -0,0 +1,35 @@ +RACE faerie +SENSITIVITY 30:800 +LANGUAGE Elcharean +RESISTANCE WATER:low +STATS agility:60:1 +STATS charisma:30:3 +STATS coordination:40:1 +STATS durability:10:5 +STATS intelligence:10:2 +STATS luck:30:2 +STATS speed:40:2 +STATS strength:5:5 +STATS wisdom:15:2 +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_BELT,A_AMULET,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB right foot:right leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left foot:left leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left arm:torso:3:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB right arm:torso:3:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +right wing:torso:3 +left wing:torso:3 +LIMB left hand:left arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB right hand:right arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +HAND left hand:5 +HAND right hand:5 +FLYING_RACE +NONBITING_RACE +MASS 5 +SIZE S_TINY +BODY_TYPE B_WINGED_MAN +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/fish b/lib/secure/cfg/races/fish new file mode 100644 index 0000000..143beac --- /dev/null +++ b/lib/secure/cfg/races/fish @@ -0,0 +1,26 @@ +RACE fish +SENSITIVITY 20:800 +LANGUAGE Ichthine +RESISTANCE SHOCK:high +RESISTANCE BLUNT:low +RESISTANCE COLD:low +RESISTANCE WATER:low +STATS charisma:1:5 +STATS durability:10:4 +STATS intelligence:1:5 +STATS luck:1:5 +STATS agility:31:2 +STATS wisdom:21:3 +STATS speed:21:3 +STATS strength:10:4 +STATS coordination:31:2 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT +LIMB head:torso:1:A_BODY_ARMOR,A_VISOR,A_HELMET,A_CLOAK +LIMBLESS_COMBAT_RACE +LIMBLESS_RACE +SWIMMING_RACE +MASS 200 +SIZE S_SMALL +BODY_TYPE B_FISH +RESPIRATION_TYPE R_WATER +MOUTH MOUTH_TONGUED diff --git a/lib/secure/cfg/races/gargoyle b/lib/secure/cfg/races/gargoyle new file mode 100644 index 0000000..ef9cdd3 --- /dev/null +++ b/lib/secure/cfg/races/gargoyle @@ -0,0 +1,39 @@ +RACE gargoyle +SENSITIVITY 20:800 +LANGUAGE Gargoyleish +RESISTANCE SHOCK:high +RESISTANCE BLUNT:low +RESISTANCE COLD:low +RESISTANCE WATER:low +STATS charisma:1:5 +STATS durability:43:1 +STATS intelligence:10:4 +STATS luck:10:4 +STATS agility:1:5 +STATS wisdom:31:2 +STATS speed:10:4 +STATS strength:43:1 +STATS coordination:31:2 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB left arm:torso:3:A_LONG_GLOVE,A_SHIRT,A_ARMOR,A_BODY_ARMOR,A_SHIELD,A_CUSTOM +LIMB right rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right arm:torso:3:A_LONG_GLOVE,A_SHIRT,A_ARMOR,A_BODY_ARMOR,A_SHIELD,A_CUSTOM +LIMB left fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left wing:torso:3:: +LIMB right wing:torso:3:: +LIMB right fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left forepaw:left fore leg:4:: +LIMB left hand:left arm:4:A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB right forepaw:right fore leg:4:: +LIMB right hand:right arm:4:A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB left rear paw:left rear leg:4:: +LIMB right rear paw:right rear leg:4:: +FLYING_RACE +MASS 3000 +SIZE S_SOMEWHAT_SMALL +BODY_TYPE B_WINGED_MAN +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_BEAKED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/giant b/lib/secure/cfg/races/giant new file mode 100644 index 0000000..b626fcb --- /dev/null +++ b/lib/secure/cfg/races/giant @@ -0,0 +1,32 @@ +RACE giant +SENSITIVITY 27:650 +LANGUAGE Loyavenku +RESISTANCE BLUNT:medium +STATS agility:2:5 +STATS charisma:10:4 +STATS coordination:10:3 +STATS durability:70:1 +STATS intelligence:10:3 +STATS luck:5:4 +STATS speed:1:5 +STATS strength:80:1 +STATS wisdom:1:5 +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_BELT,A_AMULET,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB right foot:right leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left foot:left leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB left hand:left arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB right hand:right arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +HAND left hand:6 +HAND right hand:6 +SWIMMING_RACE +MASS 40000 +SIZE S_HUGE +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/gnoll b/lib/secure/cfg/races/gnoll new file mode 100644 index 0000000..fe8fb41 --- /dev/null +++ b/lib/secure/cfg/races/gnoll @@ -0,0 +1,33 @@ +RACE gnoll +SENSITIVITY 20:80 +LANGUAGE Kaydoch +RESISTANCE COLD:high +RESISTANCE SHOCK:high +RESISTANCE BLUNT:medium +RESISTANCE WATER:low +STATS charisma:1:5 +STATS durability:21:3 +STATS intelligence:10:4 +STATS luck:31:2 +STATS agility:31:2 +STATS wisdom:10:4 +STATS speed:21:3 +STATS strength:21:3 +STATS coordination:31:2 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIRT,A_ARMOR,A_BODY_ARMOR,A_SHIELD,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIRT,A_ARMOR,A_BODY_ARMOR,A_SHIELD,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right foot:right leg:4:A_SOCK,A_LONG_SOCK,A_BOOT,A_LONG_BOOT,A_CUSTOM +LIMB right hand:right arm:4:A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB left foot:left leg:4:A_SOCK,A_LONG_SOCK,A_BOOT,A_LONG_BOOT,A_CUSTOM +LIMB left hand:left arm:4:A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +SWIMMING_RACE +MASS 1200 +SIZE S_SOMEWHAT_SMALL +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED|MOUTH_TUSKED diff --git a/lib/secure/cfg/races/gnome b/lib/secure/cfg/races/gnome new file mode 100644 index 0000000..4aaa5eb --- /dev/null +++ b/lib/secure/cfg/races/gnome @@ -0,0 +1,31 @@ +RACE gnome +SENSITIVITY 8:610 +LANGUAGE Kaydiyee +STATS agility:20:3 +STATS charisma:1:5 +STATS coordination:35:3 +STATS durability:10:4 +STATS intelligence:50:1 +STATS luck:40:2 +STATS speed:20:2 +STATS strength:30:3 +STATS wisdom:40:1 +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_BELT,A_AMULET,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB right foot:right leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left foot:left leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB left hand:left arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB right hand:right arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +HAND left hand:4 +HAND right hand:4 +SWIMMING_RACE +MASS 10 +SIZE S_VERY_SMALL +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/goblin b/lib/secure/cfg/races/goblin new file mode 100644 index 0000000..db90eb4 --- /dev/null +++ b/lib/secure/cfg/races/goblin @@ -0,0 +1,33 @@ +RACE goblin +SENSITIVITY 0:800 +LANGUAGE Goblinish +RESISTANCE COLD:high +RESISTANCE SHOCK:high +RESISTANCE BLUNT:medium +RESISTANCE WATER:low +STATS charisma:1:5 +STATS durability:43:1 +STATS intelligence:10:4 +STATS luck:10:4 +STATS agility:43:1 +STATS wisdom:21:3 +STATS speed:31:2 +STATS strength:21:3 +STATS coordination:21:3 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIRT,A_ARMOR,A_BODY_ARMOR,A_SHIELD,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIRT,A_ARMOR,A_BODY_ARMOR,A_SHIELD,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right foot:right leg:4:A_SOCK,A_LONG_SOCK,A_BOOT,A_LONG_BOOT,A_CUSTOM +LIMB right hand:right arm:4:A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB left foot:left leg:4:A_SOCK,A_LONG_SOCK,A_BOOT,A_LONG_BOOT,A_CUSTOM +LIMB left hand:left arm:4:A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +SWIMMING_RACE +MASS 1800 +SIZE S_HUMAN_SIZED +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED|MOUTH_FANGED diff --git a/lib/secure/cfg/races/god b/lib/secure/cfg/races/god new file mode 100644 index 0000000..81c017c --- /dev/null +++ b/lib/secure/cfg/races/god @@ -0,0 +1,37 @@ +RACE god +SENSITIVITY 0:8000 +LANGUAGE Divine +RESISTANCE COLD:high +RESISTANCE SHOCK:high +RESISTANCE BLUNT:medium +RESISTANCE WATER:low +STATS charisma:43:1 +STATS durability:43:1 +STATS intelligence:43:1 +STATS luck:43:1 +STATS agility:43:1 +STATS wisdom:43:1 +STATS speed:43:1 +STATS strength:43:1 +STATS coordination:43:1 +RESISTANCE ALL_DAMAGE:immune +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIRT,A_ARMOR,A_BODY_ARMOR,A_SHIELD,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIRT,A_ARMOR,A_BODY_ARMOR,A_SHIELD,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right foot:right leg:4:A_SOCK,A_LONG_SOCK,A_BOOT,A_LONG_BOOT,A_CUSTOM +LIMB right hand:right arm:4:A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB left foot:left leg:4:A_SOCK,A_LONG_SOCK,A_BOOT,A_LONG_BOOT,A_CUSTOM +LIMB left hand:left arm:4:A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMBLESS_COMBAT_RACE +NONBITING_RACE +SWIMMING_RACE +MASS 0 +SIZE S_LARGE +BODY_TYPE B_NEBULOUS +RESPIRATION_TYPE R_VACUUM +NOT_MEAT +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/golem b/lib/secure/cfg/races/golem new file mode 100644 index 0000000..8041a6e --- /dev/null +++ b/lib/secure/cfg/races/golem @@ -0,0 +1,33 @@ +RACE golem +SENSITIVITY 20:800 +LANGUAGE Emet +RESISTANCE COLD:high +RESISTANCE SHOCK:high +RESISTANCE BLUNT:medium +RESISTANCE WATER:low +STATS charisma:1:5 +STATS durability:31:2 +STATS intelligence:10:4 +STATS luck:1:5 +STATS agility:21:3 +STATS wisdom:31:2 +STATS speed:21:3 +STATS strength:43:1 +STATS coordination:21:3 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB head:torso:1:A_BODY_ARMOR,A_VISOR,A_HELMET,A_CLOAK,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIRT,A_ARMOR,A_BODY_ARMOR,A_SHIELD,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIRT,A_ARMOR,A_BODY_ARMOR,A_SHIELD,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right foot:right leg:4:A_SOCK,A_LONG_SOCK,A_BOOT,A_LONG_BOOT,A_CUSTOM +LIMB right hand:right arm:4:A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB left foot:left leg:4:A_SOCK,A_LONG_SOCK,A_BOOT,A_LONG_BOOT,A_CUSTOM +LIMB left hand:left arm:4:A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +NONBITING_RACE +MASS 5000 +SIZE S_LARGE +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_VACUUM +NOT_MEAT +MOUTH MOUTH_STATIC diff --git a/lib/secure/cfg/races/griffin b/lib/secure/cfg/races/griffin new file mode 100644 index 0000000..3e61060 --- /dev/null +++ b/lib/secure/cfg/races/griffin @@ -0,0 +1,35 @@ +RACE griffin +SENSITIVITY 20:800 +LANGUAGE Griffinish +RESISTANCE COLD:high +RESISTANCE SHOCK:high +RESISTANCE BLUNT:medium +RESISTANCE WATER:low +STATS charisma:1:5 +STATS durability:43:1 +STATS intelligence:1:5 +STATS luck:43:1 +STATS agility:31:2 +STATS wisdom:10:4 +STATS speed:31:2 +STATS strength:43:1 +STATS coordination:31:2 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left wing:torso:3:: +LIMB right wing:torso:3:: +LIMB right fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left forepaw:left fore leg:4:: +LIMB left rear paw:left rear leg:4:: +LIMB right forepaw:right fore leg:4:: +LIMB right rear paw:right rear leg:4:: +FLYING_RACE +MASS 3000 +SIZE S_LARGE +BODY_TYPE B_SEMI_BIPEDAL +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_BEAKED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/half-elf b/lib/secure/cfg/races/half-elf new file mode 100644 index 0000000..c4be627 --- /dev/null +++ b/lib/secure/cfg/races/half-elf @@ -0,0 +1,32 @@ +RACE half-elf +PLAYER_RACE 1 +SENSITIVITY 12:620 +LANGUAGE Edhellen +STATS agility:30:2 +STATS charisma:30:3 +STATS coordination:30:1 +STATS durability:30:5 +STATS intelligence:30:1 +STATS luck:30:4 +STATS speed:60:1 +STATS strength:15:3 +STATS wisdom:30:2 +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_BELT,A_AMULET,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB right foot:right leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left foot:left leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB left hand:left arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB right hand:right arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +HAND left hand:4 +HAND right hand:4 +SWIMMING_RACE +MASS 1500 +SIZE S_HUMAN_SIZED +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/half-orc b/lib/secure/cfg/races/half-orc new file mode 100644 index 0000000..a544c01 --- /dev/null +++ b/lib/secure/cfg/races/half-orc @@ -0,0 +1,31 @@ +RACE half-orc +PLAYER_RACE 1 +SENSITIVITY 12:620 +LANGUAGE Tangetto +STATS agility:2:1 +STATS charisma:4:5 +STATS coordination:20:3 +STATS durability:40:2 +STATS intelligence:20:2 +STATS luck:1:5 +STATS speed:70:1 +STATS strength:20:2 +STATS wisdom:10:5 +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_BELT,A_AMULET,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB right foot:right leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left foot:left leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB left hand:left arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB right hand:right arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +HAND left hand:4 +HAND right hand:4 +MASS 2000 +SIZE S_HUMAN_SIZED +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/halfling b/lib/secure/cfg/races/halfling new file mode 100644 index 0000000..5be687a --- /dev/null +++ b/lib/secure/cfg/races/halfling @@ -0,0 +1,32 @@ +RACE halfling +PLAYER_RACE 1 +SENSITIVITY 15:650 +LANGUAGE Duuk +STATS agility:40:2 +STATS charisma:80:2 +STATS coordination:33:1 +STATS durability:10:3 +STATS intelligence:20:2 +STATS luck:80:2 +STATS speed:30:1 +STATS strength:10:3 +STATS wisdom:10:4 +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_BELT,A_AMULET,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB right foot:right leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left foot:left leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB left hand:left arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB right hand:right arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +HAND left hand:5 +HAND right hand:5 +SWIMMING_RACE +MASS 500 +SIZE S_SMALL +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/hobbit b/lib/secure/cfg/races/hobbit new file mode 100644 index 0000000..26d7e45 --- /dev/null +++ b/lib/secure/cfg/races/hobbit @@ -0,0 +1,32 @@ +RACE hobbit +SENSITIVITY 20:700 +LANGUAGE Hoboken +RESISTANCE COLD:low +STATS agility:20:1 +STATS charisma:33:3 +STATS coordination:60:3 +STATS durability:20:2 +STATS intelligence:20:2 +STATS luck:80:1 +STATS speed:30:2 +STATS strength:10:4 +STATS wisdom:20:3 +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_BELT,A_AMULET,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB right foot:right leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left foot:left leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB left hand:left arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB right hand:right arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +HAND left hand:4 +HAND right hand:4 +SWIMMING_RACE +MASS 500 +SIZE S_SMALL +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/horse b/lib/secure/cfg/races/horse new file mode 100644 index 0000000..30d04a6 --- /dev/null +++ b/lib/secure/cfg/races/horse @@ -0,0 +1,32 @@ +RACE horse +SENSITIVITY 20:800 +LANGUAGE Equine +RESISTANCE SHOCK:high +RESISTANCE BLUNT:medium +RESISTANCE COLD:low +RESISTANCE WATER:low +STATS charisma:21:3 +STATS durability:31:2 +STATS intelligence:1:5 +STATS luck:1:5 +STATS agility:31:2 +STATS wisdom:1:5 +STATS speed:31:2 +STATS strength:73:1 +STATS coordination:10:4 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left fore hoof:left fore leg:4:: +LIMB left rear hoof:left rear leg:4:: +LIMB right fore hoof:right fore leg:4:: +LIMB right rear hoof:right rear leg:4:: +MASS 6000 +SIZE S_LARGE +BODY_TYPE B_QUADRUPED +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/human b/lib/secure/cfg/races/human new file mode 100644 index 0000000..3a3f29f --- /dev/null +++ b/lib/secure/cfg/races/human @@ -0,0 +1,33 @@ +RACE human +PLAYER_RACE 1 +SENSITIVITY 25:750 +LANGUAGE English +SKILL psionic defense:2:3:4:5 +STATS agility:33:3 +STATS charisma:33:2 +STATS coordination:33:2 +STATS durability:30:4 +STATS intelligence:40:1 +STATS luck:20:3 +STATS speed:30:3 +STATS strength:20:3 +STATS wisdom:40:3 +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_BELT,A_AMULET,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB right foot:right leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left foot:left leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB right hand:right arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB left hand:left arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +HAND right hand:5 +HAND left hand:5 +SWIMMING_RACE +MASS 1800 +SIZE S_HUMAN_SIZED +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/insect b/lib/secure/cfg/races/insect new file mode 100644 index 0000000..563d78f --- /dev/null +++ b/lib/secure/cfg/races/insect @@ -0,0 +1,30 @@ +RACE insect +SENSITIVITY 20:800 +LANGUAGE Insectoid +RESISTANCE SHOCK:high +RESISTANCE BLUNT:medium +RESISTANCE COLD:low +RESISTANCE WATER:low +STATS charisma:1:5 +STATS durability:1:5 +STATS intelligence:1:5 +STATS luck:43:1 +STATS agility:31:2 +STATS wisdom:1:5 +STATS speed:43:1 +STATS strength:1:5 +STATS coordination:21:3 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB head:torso:1:A_BODY_ARMOR,A_VISOR,A_HELMET,A_CLOAK,A_CUSTOM +LIMB 4th leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB 6th leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB 5th leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB 1st leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB 3rd leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB 2nd leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +FLYING_RACE +MASS 1 +SIZE S_MINISCULE +BODY_TYPE B_INSECTOID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_MANDIBLED diff --git a/lib/secure/cfg/races/isopod b/lib/secure/cfg/races/isopod new file mode 100644 index 0000000..27df700 --- /dev/null +++ b/lib/secure/cfg/races/isopod @@ -0,0 +1,30 @@ +RACE isopod +SENSITIVITY 20:800 +LANGUAGE cthonic +RESISTANCE SHOCK:low +RESISTANCE BLUNT:medium +RESISTANCE COLD:high +RESISTANCE WATER:high +STATS charisma:1:5 +STATS durability:60:5 +STATS intelligence:1:5 +STATS luck:43:1 +STATS agility:11:2 +STATS wisdom:1:5 +STATS speed:13:1 +STATS strength:70:5 +STATS coordination:20:3 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB head:torso:1:A_BODY_ARMOR,A_VISOR,A_HELMET,A_CLOAK,A_CUSTOM +LIMB 4th leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB 6th leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB 5th leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB 1st leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB 3rd leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB 2nd leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +FLYING_RACE +MASS 1 +SIZE S_LARGE +BODY_TYPE B_INSECTOID +RESPIRATION_TYPE R_AIR|R_WATER +MOUTH MOUTH_MANDIBLED diff --git a/lib/secure/cfg/races/kender b/lib/secure/cfg/races/kender new file mode 100644 index 0000000..7ead890 --- /dev/null +++ b/lib/secure/cfg/races/kender @@ -0,0 +1,32 @@ +RACE kender +SENSITIVITY 23:780 +LANGUAGE Kendrall +SKILL stealing:2:1:0:0 +STATS agility:40:3 +STATS charisma:40:2 +STATS coordination:50:2 +STATS durability:20:1 +STATS intelligence:20:2 +STATS luck:33:3 +STATS speed:50:1 +STATS strength:3:5 +STATS wisdom:7:4 +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_BELT,A_AMULET,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB right foot:right leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left foot:left leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB left hand:left arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB right hand:right arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +HAND left hand:5 +HAND right hand:5 +SWIMMING_RACE +MASS 800 +SIZE S_SOMEWHAT_SMALL +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/klingon b/lib/secure/cfg/races/klingon new file mode 100644 index 0000000..c0ace7d --- /dev/null +++ b/lib/secure/cfg/races/klingon @@ -0,0 +1,35 @@ +RACE klingon +SENSITIVITY 19:650 +LANGUAGE Tlhinghan +RESISTANCE BLADE:medium +RESISTANCE BLUNT:medium +RESISTANCE COLD:medium +RESISTANCE HEAT:medium +RESISTANCE KNIFE:medium +STATS agility:30:2 +STATS charisma:10:5 +STATS coordination:10:2 +STATS durability:60:1 +STATS intelligence:25:2 +STATS luck:1:4 +STATS speed:30:3 +STATS strength:60:1 +STATS wisdom:1:5 +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_BELT,A_AMULET,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB right foot:right leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left foot:left leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB right hand:right arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB left hand:left arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +HAND right hand:5 +HAND left hand:5 +MASS 2500 +SIZE S_SOMEWHAT_LARGE +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/kobold b/lib/secure/cfg/races/kobold new file mode 100644 index 0000000..a2cafe7 --- /dev/null +++ b/lib/secure/cfg/races/kobold @@ -0,0 +1,37 @@ +RACE kobold +SENSITIVITY 20:800 +LANGUAGE Yeik +RESISTANCE SHOCK:high +RESISTANCE BLADE:medium +RESISTANCE BLUNT:medium +RESISTANCE KNIFE:medium +RESISTANCE COLD:medium +RESISTANCE HEAT:medium +RESISTANCE WATER:low +STATS charisma:10:4 +STATS durability:43:1 +STATS intelligence:10:4 +STATS luck:21:3 +STATS agility:21:3 +STATS wisdom:10:4 +STATS speed:21:3 +STATS strength:43:1 +STATS coordination:31:2 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIRT,A_ARMOR,A_BODY_ARMOR,A_SHIELD,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIRT,A_ARMOR,A_BODY_ARMOR,A_SHIELD,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left hand:left arm:4:A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB right hand:right arm:4:A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB left hoof:left leg:4:: +LIMB right hoof:right leg:4:: +HAND right hand:5 +HAND left hand:5 +MASS 1300 +SIZE S_SOMEWHAT_SMALL +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED|MOUTH_FANGED diff --git a/lib/secure/cfg/races/lizard b/lib/secure/cfg/races/lizard new file mode 100644 index 0000000..3edbd70 --- /dev/null +++ b/lib/secure/cfg/races/lizard @@ -0,0 +1,36 @@ +RACE lizard +SENSITIVITY 20:800 +LANGUAGE Reptilian +RESISTANCE SHOCK:high +RESISTANCE BLADE:medium +RESISTANCE BLUNT:medium +RESISTANCE KNIFE:medium +RESISTANCE COLD:medium +RESISTANCE HEAT:medium +RESISTANCE WATER:low +STATS charisma:10:4 +STATS durability:21:3 +STATS intelligence:1:5 +STATS luck:10:4 +STATS agility:21:3 +STATS wisdom:1:5 +STATS speed:21:3 +STATS strength:21:3 +STATS coordination:21:3 +LIMB torso:0:1:A_AMULET +LIMB neck:torso:1:A_COLLAR,A_AMULET +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET +left rear leg:torso:3: +right rear leg:torso:3: +right fore leg:torso:3: +left fore leg:torso:3: +LIMB left forepaw:left fore leg:4:: +LIMB right forepaw:right fore leg:4:: +LIMB left rear paw:left rear leg:4:: +LIMB right rear paw:right rear leg:4:: +SWIMMING_RACE +MASS 10 +SIZE S_VERY_SMALL +BODY_TYPE B_QUADRUPED +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/mech b/lib/secure/cfg/races/mech new file mode 100644 index 0000000..09c66f3 --- /dev/null +++ b/lib/secure/cfg/races/mech @@ -0,0 +1,35 @@ +RACE mech +SENSITIVITY 0:7500 +LANGUAGE English +STATS agility:50:3 +STATS charisma:50:2 +STATS coordination:50:2 +STATS durability:50:4 +STATS intelligence:1:1 +STATS luck:10:3 +STATS speed:50:3 +STATS strength:90:4 +STATS wisdom:1:3 +RESISTANCE BLADE:immune +RESISTANCE KNIFE:immune +LIMB torso:0:1:A_AMULET,A_CUSTOM +LIMB neck:torso:1:A_AMULET,A_CUSTOM +LIMB head:neck:1:A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_CUSTOM +LIMB left leg:torso:2:A_CUSTOM +LIMB right foot:right leg:4:A_CUSTOM +LIMB left foot:left leg:4:A_CUSTOM +LIMB right arm:torso:2:A_CUSTOM +LIMB left arm:torso:2:A_CUSTOM +LIMB right hand:right arm:4:A_WEAPON,A_CUSTOM +LIMB left hand:left arm:4:A_WEAPON,A_CUSTOM +HAND right hand:5 +HAND left hand:5 +LIMBLESS_COMBAT_RACE +NONBITING_RACE +MASS 10000 +SIZE S_HUGE +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_VACUUM +NOT_MEAT +MOUTH MOUTH_NONE diff --git a/lib/secure/cfg/races/nymph b/lib/secure/cfg/races/nymph new file mode 100644 index 0000000..87d522d --- /dev/null +++ b/lib/secure/cfg/races/nymph @@ -0,0 +1,31 @@ +RACE nymph +SENSITIVITY 26:760 +LANGUAGE Nymal +STATS agility:50:1 +STATS charisma:80:1 +STATS coordination:20:2 +STATS durability:7:5 +STATS intelligence:25:4 +STATS luck:50:2 +STATS speed:60:2 +STATS strength:3:5 +STATS wisdom:20:4 +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_BELT,A_AMULET,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB right foot:right leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left foot:left leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB left hand:left arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB right hand:right arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +HAND left hand:5 +HAND right hand:5 +SWIMMING_RACE +MASS 140 +SIZE S_SOMEWHAT_SMALL +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_AIR|R_WATER +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/ogre b/lib/secure/cfg/races/ogre new file mode 100644 index 0000000..f8fd9df --- /dev/null +++ b/lib/secure/cfg/races/ogre @@ -0,0 +1,33 @@ +RACE ogre +SENSITIVITY 25:700 +LANGUAGE Shangtai +RESISTANCE BLADE:low +RESISTANCE BLUNT:low +RESISTANCE KNIFE:low +STATS agility:1:5 +STATS charisma:1:5 +STATS coordination:2:5 +STATS durability:68:1 +STATS intelligence:10:4 +STATS luck:1:5 +STATS speed:7:4 +STATS strength:50:1 +STATS wisdom:1:5 +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_BELT,A_AMULET,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB right foot:right leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left foot:left leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB right hand:right arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB left hand:left arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +HAND right hand:6 +HAND left hand:6 +MASS 4000 +SIZE S_LARGE +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED|MOUTH_FANGED|MOUTH_TUSKED diff --git a/lib/secure/cfg/races/ooga b/lib/secure/cfg/races/ooga new file mode 100644 index 0000000..ae0545f --- /dev/null +++ b/lib/secure/cfg/races/ooga @@ -0,0 +1,31 @@ +RACE ooga +PLAYER_RACE 1 +SENSITIVITY 5:710 +LANGUAGE Booga +STATS agility:10:2 +STATS charisma:1:5 +STATS coordination:33:3 +STATS durability:30:2 +STATS intelligence:10:3 +STATS luck:6:4 +STATS speed:40:2 +STATS strength:35:1 +STATS wisdom:3:5 +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_BELT,A_AMULET,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB right foot:right leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left foot:left leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB left hand:left arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB right hand:right arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +HAND left hand:6 +HAND right hand:6 +MASS 2200 +SIZE S_SOMEWHAT_LARGE +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED|MOUTH_TUSKED diff --git a/lib/secure/cfg/races/orc b/lib/secure/cfg/races/orc new file mode 100644 index 0000000..2cc7bae --- /dev/null +++ b/lib/secure/cfg/races/orc @@ -0,0 +1,31 @@ +RACE orc +PLAYER_RACE 1 +SENSITIVITY 5:710 +LANGUAGE Tangetto +STATS agility:10:2 +STATS charisma:1:5 +STATS coordination:33:3 +STATS durability:30:2 +STATS intelligence:10:3 +STATS luck:3:4 +STATS speed:40:2 +STATS strength:35:1 +STATS wisdom:3:5 +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_BELT,A_AMULET,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB right foot:right leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left foot:left leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB left hand:left arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB right hand:right arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +HAND left hand:6 +HAND right hand:6 +MASS 2200 +SIZE S_SOMEWHAT_LARGE +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED|MOUTH_TUSKED diff --git a/lib/secure/cfg/races/pegasus b/lib/secure/cfg/races/pegasus new file mode 100644 index 0000000..53f24e6 --- /dev/null +++ b/lib/secure/cfg/races/pegasus @@ -0,0 +1,38 @@ +RACE pegasus +SENSITIVITY 20:800 +LANGUAGE Voloquine +RESISTANCE SHOCK:high +RESISTANCE COLD:medium +RESISTANCE HEAT:medium +RESISTANCE BLADE:low +RESISTANCE BLUNT:low +RESISTANCE KNIFE:low +RESISTANCE WATER:low +STATS charisma:43:1 +STATS durability:31:2 +STATS intelligence:21:3 +STATS luck:43:1 +STATS agility:43:1 +STATS wisdom:31:2 +STATS speed:31:2 +STATS strength:31:2 +STATS coordination:31:2 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB left fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left wing:torso:3:: +LIMB right rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right wing:torso:3:: +LIMB right rear hoof:right rear leg:4:: +LIMB left fore hoof:left fore leg:4:: +LIMB left rear hoof:left rear leg:4:: +LIMB right fore hoof:right fore leg:4:: +FLYING_RACE +MASS 3000 +SIZE S_LARGE +BODY_TYPE B_QUADRUPED +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/pig b/lib/secure/cfg/races/pig new file mode 100644 index 0000000..0c2b042 --- /dev/null +++ b/lib/secure/cfg/races/pig @@ -0,0 +1,35 @@ +RACE pig +SENSITIVITY 20:800 +LANGUAGE Porcine +RESISTANCE SHOCK:high +RESISTANCE COLD:medium +RESISTANCE HEAT:medium +RESISTANCE BLADE:low +RESISTANCE BLUNT:low +RESISTANCE KNIFE:low +RESISTANCE WATER:low +STATS charisma:1:5 +STATS durability:43:1 +STATS intelligence:15:2 +STATS luck:1:5 +STATS agility:1:5 +STATS wisdom:31:2 +STATS speed:10:4 +STATS strength:21:3 +STATS coordination:21:3 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left fore hoof:left fore leg:4:: +LIMB left rear hoof:left rear leg:4:: +LIMB right fore hoof:right fore leg:4:: +LIMB right rear hoof:right rear leg:4:: +MASS 1500 +SIZE S_SOMEWHAT_SMALL +BODY_TYPE B_QUADRUPED +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED|MOUTH_TUSKED diff --git a/lib/secure/cfg/races/plant b/lib/secure/cfg/races/plant new file mode 100644 index 0000000..2108034 --- /dev/null +++ b/lib/secure/cfg/races/plant @@ -0,0 +1,29 @@ +RACE plant +SENSITIVITY 0:8000 +LANGUAGE Vegetal +RESISTANCE SHOCK:high +RESISTANCE COLD:medium +RESISTANCE HEAT:medium +RESISTANCE BLADE:low +RESISTANCE BLUNT:low +RESISTANCE KNIFE:low +RESISTANCE WATER:low +STATS charisma:11:3 +STATS durability:21:3 +STATS intelligence:1:5 +STATS luck:21:3 +STATS agility:1:5 +STATS wisdom:1:5 +STATS speed:1:5 +STATS strength:21:3 +STATS coordination:1:5 +LIMB trunk:0:1:: +LIMB 1st branch:trunk:3:: +LIMBLESS_COMBAT_RACE +NONBITING_RACE +MASS 10 +SIZE S_VERY_SMALL +BODY_TYPE B_PLANT +RESPIRATION_TYPE R_VACUUM +NOT_MEAT +MOUTH MOUTH_NONE diff --git a/lib/secure/cfg/races/poleepkwa b/lib/secure/cfg/races/poleepkwa new file mode 100644 index 0000000..9bfa252 --- /dev/null +++ b/lib/secure/cfg/races/poleepkwa @@ -0,0 +1,33 @@ +RACE poleepkwa +PLAYER_RACE 1 +SENSITIVITY 25:750 +LANGUAGE Poleepkwa +STATS agility:53:4 +STATS charisma:1:4 +STATS coordination:43:4 +STATS durability:10:4 +STATS intelligence:10:4 +STATS luck:10:4 +STATS speed:43:4 +STATS strength:70:4 +STATS wisdom:10:4 +RESISTANCE BLADE:low +RESISTANCE KNIFE:medium +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_AMULET,A_CUSTOM,A_EXO +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM,A_EXO +LIMB head:neck:1:A_HELMET,A_AMULET,A_CUSTOM,A_EXO +LIMB right leg:torso:2:A_PANTS,A_BODY_ARMOR,A_CUSTOM,A_EXO +LIMB left leg:torso:2:A_PANTS,A_BODY_ARMOR,A_CUSTOM,A_EXO +LIMB right foot:right leg:4:A_CUSTOM,A_EXO +LIMB left foot:left leg:4:A_CUSTOM,A_EXO +LIMB right arm:torso:2:A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM,A_EXO +LIMB left arm:torso:2:A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM,A_EXO +LIMB right hand:right arm:4:A_WEAPON,A_SHIELD,A_CUSTOM,A_EXO +LIMB left hand:left arm:4:A_WEAPON,A_SHIELD,A_CUSTOM,A_EXO +HAND right hand:4 +HAND left hand:4 +MASS 1500 +SIZE S_SOMEWHAT_LARGE +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_MANDIBLED diff --git a/lib/secure/cfg/races/primate b/lib/secure/cfg/races/primate new file mode 100644 index 0000000..3f59075 --- /dev/null +++ b/lib/secure/cfg/races/primate @@ -0,0 +1,36 @@ +RACE primate +LANGUAGE Ur +SENSITIVITY 20:800 +LANGUAGE Proto +RESISTANCE SHOCK:high +RESISTANCE COLD:medium +RESISTANCE HEAT:medium +RESISTANCE BLADE:low +RESISTANCE BLUNT:low +RESISTANCE KNIFE:low +RESISTANCE WATER:low +STATS charisma:15:3 +STATS durability:10:4 +STATS intelligence:21:3 +STATS luck:21:3 +STATS agility:21:3 +STATS wisdom:10:4 +STATS speed:21:3 +STATS strength:10:4 +STATS coordination:21:3 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIRT,A_ARMOR,A_BODY_ARMOR,A_SHIELD,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIRT,A_ARMOR,A_BODY_ARMOR,A_SHIELD,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right foot:right leg:4:A_SOCK,A_LONG_SOCK,A_BOOT,A_LONG_BOOT,A_CUSTOM +LIMB right hand:right arm:4:A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB left foot:left leg:4:A_SOCK,A_LONG_SOCK,A_BOOT,A_LONG_BOOT,A_CUSTOM +LIMB left hand:left arm:4:A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +MASS 1500 +SIZE S_SMALL +BODY_TYPE B_SEMI_BIPEDAL +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/replicant b/lib/secure/cfg/races/replicant new file mode 100644 index 0000000..b802b46 --- /dev/null +++ b/lib/secure/cfg/races/replicant @@ -0,0 +1,32 @@ +RACE replicant +SENSITIVITY 5:850 +LANGUAGE English +SKILL psionic defense:2:3:4:5 +STATS agility:40:3 +STATS charisma:40:2 +STATS coordination:40:2 +STATS durability:40:4 +STATS intelligence:10:1 +STATS luck:1:3 +STATS speed:40:3 +STATS strength:40:4 +STATS wisdom:1:3 +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_BELT,A_AMULET,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB right foot:right leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left foot:left leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB right hand:right arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB left hand:left arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +HAND right hand:5 +HAND left hand:5 +SWIMMING_RACE +MASS 1800 +SIZE S_HUMAN_SIZED +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/rodent b/lib/secure/cfg/races/rodent new file mode 100644 index 0000000..a89260c --- /dev/null +++ b/lib/secure/cfg/races/rodent @@ -0,0 +1,36 @@ +RACE rodent +SENSITIVITY 0:800 +LANGUAGE Rodentian +RESISTANCE SHOCK:high +RESISTANCE COLD:medium +RESISTANCE HEAT:medium +RESISTANCE BLADE:low +RESISTANCE BLUNT:low +RESISTANCE KNIFE:low +RESISTANCE WATER:low +STATS charisma:1:5 +STATS durability:10:4 +STATS intelligence:1:5 +STATS luck:1:5 +STATS agility:21:3 +STATS wisdom:10:4 +STATS speed:31:2 +STATS strength:1:5 +STATS coordination:10:4 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB left rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left forepaw:left fore leg:4:: +LIMB right forepaw:right fore leg:4:: +LIMB left rear paw:left rear leg:4:: +LIMB right rear paw:right rear leg:4:: +SWIMMING_RACE +MASS 10 +SIZE S_VERY_SMALL +BODY_TYPE B_QUADRUPED +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED|MOUTH_DISEASED diff --git a/lib/secure/cfg/races/satyr b/lib/secure/cfg/races/satyr new file mode 100644 index 0000000..ba3500c --- /dev/null +++ b/lib/secure/cfg/races/satyr @@ -0,0 +1,30 @@ +RACE satyr +SENSITIVITY 27:770 +LANGUAGE Wulinaxian +STATS agility:50:2 +STATS charisma:3:5 +STATS coordination:60:1 +STATS durability:25:2 +STATS intelligence:33:3 +STATS luck:10:1 +STATS speed:5:2 +STATS strength:2:4 +STATS wisdom:80:1 +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_BELT,A_AMULET,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB right hoof:right leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left hoof:left leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB left hand:left arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB right hand:right arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +HAND left hand:4 +HAND right hand:4 +MASS 150 +SIZE S_HUMAN_SIZED +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/sheep b/lib/secure/cfg/races/sheep new file mode 100644 index 0000000..0f868eb --- /dev/null +++ b/lib/secure/cfg/races/sheep @@ -0,0 +1,35 @@ +RACE sheep +SENSITIVITY 20:800 +LANGUAGE Ovine +RESISTANCE SHOCK:high +RESISTANCE COLD:medium +RESISTANCE HEAT:medium +RESISTANCE BLADE:low +RESISTANCE BLUNT:low +RESISTANCE KNIFE:low +RESISTANCE WATER:low +STATS charisma:21:3 +STATS durability:21:3 +STATS intelligence:1:5 +STATS luck:1:5 +STATS agility:21:3 +STATS wisdom:1:5 +STATS speed:10:4 +STATS strength:21:3 +STATS coordination:10:4 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left fore hoof:left fore leg:4:: +LIMB left rear hoof:left rear leg:4:: +LIMB right fore hoof:right fore leg:4:: +LIMB right rear hoof:right rear leg:4:: +MASS 1000 +SIZE S_SOMEWHAT_SMALL +BODY_TYPE B_QUADRUPED +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/slug b/lib/secure/cfg/races/slug new file mode 100644 index 0000000..dca0c42 --- /dev/null +++ b/lib/secure/cfg/races/slug @@ -0,0 +1,28 @@ +RACE slug +SENSITIVITY 20:800 +LANGUAGE Clavering +RESISTANCE SHOCK:high +RESISTANCE COLD:medium +RESISTANCE HEAT:medium +RESISTANCE BLADE:low +RESISTANCE BLUNT:low +RESISTANCE KNIFE:low +RESISTANCE WATER:low +STATS charisma:1:5 +STATS durability:1:5 +STATS intelligence:1:5 +STATS luck:1:5 +STATS agility:1:5 +STATS wisdom:10:4 +STATS speed:1:5 +STATS strength:10:4 +STATS coordination:1:5 +LIMB torso:0:1:A_VEST +LIMB head:torso:1:A_HELMET +LIMBLESS_COMBAT_RACE +LIMBLESS_RACE +MASS 3 +SIZE S_VERY_SMALL +BODY_TYPE B_GASTROPOD +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_NONE diff --git a/lib/secure/cfg/races/snake b/lib/secure/cfg/races/snake new file mode 100644 index 0000000..d1f5353 --- /dev/null +++ b/lib/secure/cfg/races/snake @@ -0,0 +1,28 @@ +RACE snake +SENSITIVITY 20:800 +LANGUAGE Herpetian +RESISTANCE SHOCK:high +RESISTANCE COLD:medium +RESISTANCE HEAT:medium +RESISTANCE BLADE:low +RESISTANCE BLUNT:low +RESISTANCE KNIFE:low +RESISTANCE WATER:low +STATS charisma:1:5 +STATS durability:10:4 +STATS intelligence:10:4 +STATS luck:43:1 +STATS agility:10:4 +STATS wisdom:31:2 +STATS speed:10:4 +STATS strength:1:5 +STATS coordination:1:5 +LIMB torso:0:1:A_VEST +LIMB head:torso:1:A_HELMET +LIMBLESS_COMBAT_RACE +LIMBLESS_RACE +MASS 40 +SIZE S_SMALL +BODY_TYPE B_SNAKE +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/strider b/lib/secure/cfg/races/strider new file mode 100644 index 0000000..59453a2 --- /dev/null +++ b/lib/secure/cfg/races/strider @@ -0,0 +1,33 @@ +RACE strider +SENSITIVITY 0:2000 +LANGUAGE English +STATS agility:50:1 +STATS charisma:1:3 +STATS coordination:50:1 +STATS durability:50:4 +STATS intelligence:1:3 +STATS luck:10:3 +STATS speed:90:1 +STATS strength:90:1 +STATS wisdom:1:3 +RESISTANCE BLADE:immune +RESISTANCE KNIFE:immune +LIMB turret:0:1:A_AMULET,A_CUSTOM +LIMB right leg:turret:2:A_CUSTOM +LIMB left leg:turret:2:A_CUSTOM +LIMB right foot:right leg:4:A_CUSTOM +LIMB left foot:left leg:4:A_CUSTOM +LIMB right arm:turret:2:A_CUSTOM +LIMB left arm:turret:2:A_CUSTOM +LIMB right hand:right arm:4:A_WEAPON,A_CUSTOM +LIMB left hand:left arm:4:A_WEAPON,A_CUSTOM +HAND right hand:5 +HAND left hand:5 +LIMBLESS_COMBAT_RACE +NONBITING_RACE +MASS 10000 +SIZE S_HUGE +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_VACUUM +NOT_MEAT +MOUTH MOUTH_NONE diff --git a/lib/secure/cfg/races/tortoise b/lib/secure/cfg/races/tortoise new file mode 100644 index 0000000..32b3ef1 --- /dev/null +++ b/lib/secure/cfg/races/tortoise @@ -0,0 +1,35 @@ +RACE tortoise +SENSITIVITY 20:800 +LANGUAGE Tortois +RESISTANCE SHOCK:high +RESISTANCE COLD:medium +RESISTANCE HEAT:medium +RESISTANCE BLADE:low +RESISTANCE BLUNT:low +RESISTANCE KNIFE:low +RESISTANCE WATER:low +STATS charisma:10:4 +STATS durability:43:1 +STATS intelligence:21:3 +STATS luck:21:3 +STATS agility:10:4 +STATS wisdom:43:1 +STATS speed:1:5 +STATS strength:1:5 +STATS coordination:31:2 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB left rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left forepaw:left fore leg:4:: +LIMB right forepaw:right fore leg:4:: +LIMB left rear paw:left rear leg:4:: +LIMB right rear paw:right rear leg:4:: +MASS 90 +SIZE S_SMALL +BODY_TYPE B_QUADRUPED +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_TONGUED diff --git a/lib/secure/cfg/races/tree b/lib/secure/cfg/races/tree new file mode 100644 index 0000000..189d37d --- /dev/null +++ b/lib/secure/cfg/races/tree @@ -0,0 +1,28 @@ +RACE tree +SENSITIVITY 0:800 +LANGUAGE Entish +RESISTANCE SHOCK:high +RESISTANCE COLD:medium +RESISTANCE HEAT:medium +RESISTANCE BLADE:low +RESISTANCE BLUNT:low +RESISTANCE KNIFE:low +RESISTANCE WATER:low +STATS charisma:21:3 +STATS durability:43:1 +STATS intelligence:1:5 +STATS luck:43:1 +STATS agility:1:5 +STATS wisdom:10:4 +STATS speed:1:5 +STATS strength:21:3 +STATS coordination:1:5 +LIMB trunk:0:1:: +LIMB 1st branch:trunk:3:: +LIMBLESS_COMBAT_RACE +MASS 4000 +SIZE S_LARGE +BODY_TYPE B_TREE +RESPIRATION_TYPE R_VACUUM +NOT_MEAT +MOUTH MOUTH_NONE diff --git a/lib/secure/cfg/races/troll b/lib/secure/cfg/races/troll new file mode 100644 index 0000000..936a627 --- /dev/null +++ b/lib/secure/cfg/races/troll @@ -0,0 +1,33 @@ +RACE troll +SENSITIVITY 0:1000 +LANGUAGE Murdoch +SKILL poison bite:1:3:2:4 +RESISTANCE BLUNT:low +STATS agility:10:2 +STATS charisma:11:3 +STATS coordination:10:2 +STATS durability:65:1 +STATS intelligence:11:3 +STATS luck:15:4 +STATS speed:20:3 +STATS strength:50:1 +STATS wisdom:5:5 +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_BELT,A_AMULET,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB right foot:right leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left foot:left leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB left hand:left arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB right hand:right arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +HAND left hand:4 +HAND right hand:4 +SWIMMING_RACE +MASS 200 +SIZE S_HUMAN_SIZED +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED|MOUTH_FANGED diff --git a/lib/secure/cfg/races/unicorn b/lib/secure/cfg/races/unicorn new file mode 100644 index 0000000..a64fd6c --- /dev/null +++ b/lib/secure/cfg/races/unicorn @@ -0,0 +1,35 @@ +RACE unicorn +SENSITIVITY 20:800 +LANGUAGE Cornequine +RESISTANCE SHOCK:high +RESISTANCE COLD:medium +RESISTANCE HEAT:medium +RESISTANCE BLADE:low +RESISTANCE BLUNT:low +RESISTANCE KNIFE:low +RESISTANCE WATER:low +STATS charisma:90:5 +STATS durability:21:3 +STATS intelligence:10:4 +STATS luck:43:1 +STATS agility:31:2 +STATS wisdom:31:2 +STATS speed:21:3 +STATS strength:21:3 +STATS coordination:31:2 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left rear leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right fore leg:torso:3:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left fore hoof:left fore leg:4:: +LIMB left rear hoof:left rear leg:4:: +LIMB right fore hoof:right fore leg:4:: +LIMB right rear hoof:right rear leg:4:: +MASS 4000 +SIZE S_LARGE +BODY_TYPE B_QUADRUPED +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/vehicle b/lib/secure/cfg/races/vehicle new file mode 100644 index 0000000..2612a71 --- /dev/null +++ b/lib/secure/cfg/races/vehicle @@ -0,0 +1,25 @@ +RACE vehicle +SENSITIVITY 0:10000 +LANGUAGE Bocce +STATS agility:50:3 +STATS charisma:50:2 +STATS coordination:50:2 +STATS durability:50:4 +STATS intelligence:1:1 +STATS luck:10:3 +STATS speed:50:3 +STATS strength:50:4 +STATS wisdom:1:3 +RESISTANCE BLADE:immune +RESISTANCE KNIFE:immune +LIMB fuselage:0:1:A_AMULET,A_CUSTOM +LIMBLESS_COMBAT_RACE +NONBITING_RACE +FLYING_RACE +SWIMMING_RACE +MASS 1000 +SIZE S_LARGE +BODY_TYPE B_ORB +RESPIRATION_TYPE R_VACUUM +NOT_MEAT +MOUTH MOUTH_NONE diff --git a/lib/secure/cfg/races/viper b/lib/secure/cfg/races/viper new file mode 100644 index 0000000..f542037 --- /dev/null +++ b/lib/secure/cfg/races/viper @@ -0,0 +1,29 @@ +RACE viper +SENSITIVITY 20:800 +LANGUAGE Aspish +RESISTANCE SHOCK:high +RESISTANCE COLD:medium +RESISTANCE HEAT:medium +RESISTANCE BLADE:low +RESISTANCE BLUNT:low +RESISTANCE KNIFE:low +RESISTANCE WATER:low +STATS charisma:1:5 +STATS durability:10:4 +STATS intelligence:10:4 +STATS luck:43:1 +STATS agility:10:4 +STATS wisdom:31:2 +STATS speed:10:4 +STATS strength:1:5 +STATS coordination:1:5 +SKILL poison bite:8:1:0:0 +LIMB torso:0:1:A_VEST,A_CUSTOM +LIMB head:torso:1:A_HELMET,A_CUSTOM +LIMBLESS_COMBAT_RACE +LIMBLESS_RACE +MASS 30 +SIZE S_SMALL +BODY_TYPE B_SNAKE +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_TOOTHED|MOUTH_TONGUED|MOUTH_VENOMOUS|MOUTH_FANGED diff --git a/lib/secure/cfg/races/vulcan b/lib/secure/cfg/races/vulcan new file mode 100644 index 0000000..70044ca --- /dev/null +++ b/lib/secure/cfg/races/vulcan @@ -0,0 +1,39 @@ +RACE vulcan +PLAYER_RACE 0 +SENSITIVITY 17:1000 +LANGUAGE Vulcan +STATS agility:30:2 +STATS charisma:1:5 +STATS coordination:30:2 +STATS durability:30:1 +STATS intelligence:70:1 +STATS luck:1:1 +STATS speed:30:3 +STATS strength:30:5 +STATS wisdom:60:1 +STATS psi:20:1 +SKILL psionic defense:8:1:0:0 +SKILL psionic attack:8:1:0:0 +SKILL psionic detection:8:1:0:0 +RESISTANCE COLD:low +RESISTANCE HEAT:high +LIMB torso:0:1:A_SHIRT,A_CLOAK,A_VEST,A_SHIELD,A_ARMOR,A_BODY_ARMOR,A_BELT,A_AMULET,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_LONG_SOCK,A_PANTS,A_BODY_ARMOR,A_CUSTOM +LIMB right foot:right leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB left foot:left leg:4:A_BOOT,A_LONG_BOOT,A_SOCK,A_LONG_SOCK,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIELD,A_CLOAK,A_ARMOR,A_BODY_ARMOR,A_CUSTOM +LIMB right hand:right arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB left hand:left arm:4:A_RING,A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +HAND right hand:5 +HAND left hand:5 +NONBITING_RACE +SWIMMING_RACE +MASS 1500 +SIZE S_HUMAN_SIZED +BODY_TYPE B_HUMANOID +RESPIRATION_TYPE R_AIR +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED diff --git a/lib/secure/cfg/races/wraith b/lib/secure/cfg/races/wraith new file mode 100644 index 0000000..1e3abf2 --- /dev/null +++ b/lib/secure/cfg/races/wraith @@ -0,0 +1,37 @@ +RACE wraith +SENSITIVITY 20:800 +LANGUAGE Revenant +RESISTANCE SHOCK:high +RESISTANCE COLD:medium +RESISTANCE HEAT:medium +RESISTANCE BLADE:low +RESISTANCE BLUNT:low +RESISTANCE KNIFE:low +RESISTANCE WATER:low +STATS charisma:1:5 +STATS durability:21:3 +STATS intelligence:10:4 +STATS luck:43:1 +STATS agility:31:2 +STATS wisdom:31:2 +STATS speed:21:3 +STATS strength:21:3 +STATS coordination:31:2 +LIMB torso:0:1:A_ARMOR,A_BODY_ARMOR,A_CLOAK,A_VEST,A_SHIRT,A_AMULET,A_BELT,A_CUSTOM +LIMB neck:torso:1:A_COLLAR,A_AMULET,A_CUSTOM +LIMB head:neck:1:A_HELMET,A_VISOR,A_AMULET,A_CUSTOM +LIMB left leg:torso:2:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB left arm:torso:2:A_LONG_GLOVE,A_SHIRT,A_ARMOR,A_BODY_ARMOR,A_SHIELD,A_CUSTOM +LIMB right arm:torso:2:A_LONG_GLOVE,A_SHIRT,A_ARMOR,A_BODY_ARMOR,A_SHIELD,A_CUSTOM +LIMB right leg:torso:2:A_LONG_BOOT,A_BODY_ARMOR,A_PANTS,A_LONG_SOCK,A_CUSTOM +LIMB right foot:right leg:4:A_SOCK,A_LONG_SOCK,A_BOOT,A_LONG_BOOT,A_CUSTOM +LIMB right hand:right arm:4:A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +LIMB left foot:left leg:4:A_SOCK,A_LONG_SOCK,A_BOOT,A_LONG_BOOT,A_CUSTOM +LIMB left hand:left arm:4:A_GLOVE,A_LONG_GLOVE,A_WEAPON,A_SHIELD,A_CUSTOM +FLYING_RACE +MASS 100 +SIZE S_SOMEWHAT_LARGE +BODY_TYPE B_SPECTRAL +RESPIRATION_TYPE R_VACUUM +NOT_MEAT +MOUTH MOUTH_LIPPED|MOUTH_TOOTHED|MOUTH_TONGUED|MOUTH_FANGED diff --git a/lib/secure/cfg/read.cfg b/lib/secure/cfg/read.cfg new file mode 100644 index 0000000..b5f9a29 --- /dev/null +++ b/lib/secure/cfg/read.cfg @@ -0,0 +1,22 @@ +(/realms/) ASSIST:CMDS +(/estates/*/) ASSIST:CMDS +(/secure/etc/) ASSIST +(/secure/save/) ASSIST +(/secure/save/snoop.o) SECURE +(/secure/room/) ASSIST +(/secure/npc/) ASSIST +(/secure/obj/) ASSIST:CMDS +(/log/router/) SECURE +(/log/secure/) ASSIST +(/secure/include/secrets*) SECURE +(/log/adm/) ASSIST +(/secure/log/) SECURE +(/secure/log/admin) ASSIST +(/secure/tmp/) ASSIST +(/doc/) all +(/open/) all +(/tmp/) all +(/realms/template/) all +(/doc/hbook) all +(/domains/cave/) ASSIST:CMDS:CAVE +(/domains/fort/) ASSIST:CMDS:FORT diff --git a/lib/secure/cfg/runmud_template.bat b/lib/secure/cfg/runmud_template.bat new file mode 100644 index 0000000..1501170 --- /dev/null +++ b/lib/secure/cfg/runmud_template.bat @@ -0,0 +1,7 @@ +# This improved batch file courtesy of Brodbane @ Eve +goto start +:start +win32\driver.exe lib\secure\cfg\TEMPLATE_MUDOS +# Add a '#' to the following line to prevent auto-restarts +goto start +:end diff --git a/lib/secure/cfg/write.cfg b/lib/secure/cfg/write.cfg new file mode 100644 index 0000000..c8d4851 --- /dev/null +++ b/lib/secure/cfg/write.cfg @@ -0,0 +1,27 @@ +(/cfg/) ASSIST +(/cmds/) ASSIST +(/daemon/) ASSIST +(/doc/) ASSIST +(/domains/) ASSIST +(/estates/) ASSIST:MUDLIBPRIV +(/ftp/) all +(/include/) ASSIST +(/log/errors/) all +(/log/personal/) all +(/log/reports/) all +(/log/router/) SECURE +(/log/secure/) SECURE +(/news/) ASSIST +(/obj/) ASSIST +(/realms/) ASSIST:CMDS +(/save/) MUDLIBPRIV:ASSIST +(/secure/save/) ASSIST +(/secure/save/creators/) SECURE +(/secure/tmp/) ASSIST +(/secure/save/snoop.o) SECURE +(/secure/include/secrets*) SECURE +(/tmp/) all +(/open/) all +(/verbs/) ASSIST +(/www/) ASSIST +(/domains/foobar/) one diff --git a/lib/secure/cmds/admins/addadverb.c b/lib/secure/cmds/admins/addadverb.c new file mode 100644 index 0000000..d2e09be --- /dev/null +++ b/lib/secure/cmds/admins/addadverb.c @@ -0,0 +1,35 @@ +/* /secure/cmds/admins/addadverb.c + * From the Dead Souls Mud Library + * Command for adding new adverbs to the soul + * Created by Descartes of Borg 961214 + * Version: @(#) addadverb.c 1.1@(#) + * Last modified: 96/12/14 + */ + +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + string array adverbs; + + if( !args || args == "" ) { + return "Add which adverb?"; + } + adverbs = map(explode(args, ","), (: trim :)); + if( !SOUL_D->AddAdverbs(adverbs...) ) { + previous_object()->eventPrint("Addition of adverbs failed."); + return 1; + } + previous_object()->eventPrint("Adverbs added."); + return 1; +} + +string GetHelp(string args) { + return ("Syntax: addadverb ADVERB1,..,ADVERBn\n\n" + "Allows you to add 1 or more adverbs separated by commas to " + "the system adverbs that can be used as adverbs in most soul " + "commands.\n" + "See also: addemote,removeadverb,removeemote"); +} diff --git a/lib/secure/cmds/admins/addclass.c b/lib/secure/cmds/admins/addclass.c new file mode 100644 index 0000000..c09e72d --- /dev/null +++ b/lib/secure/cmds/admins/addclass.c @@ -0,0 +1,45 @@ +/* /secure/cmds/admins/addclass.c + * from the NIghtmare V Object Library + * creates new classes + * created by Descartes of Borg 960528 + * Version: %I% + * Last Modified: %D% + */ + +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + string file; + + if( !args || args == "" ) return "Syntax: addclass <CLASS>"; + if( !file_exists(file=DIR_SECURE_CFG "/classes/" + args) ) + return "File not found: " + file; + CLASSES_D->AddClass(file); + previous_object()->eventPrint("Class added."); + return 1; +} + +string GetHelp(string str) { + return ("Syntax: addclass <CLASS>\n\n" + "Allows you to add a new class to the class data stored in the " + "classes daemon. Specifically, you create a configuration file " + "and then issue this command to load the new class into the " + "classes daemon. The file should be in " + DIR_SECURE_CFG + + "/classes. The format of the file being read is:\n" + "class_name\n" + "main_class1:multi_class_name1\n" + "...\n" + "main_classN:multi_class_nameN\n" + "skill1:skill_average1:skill_class1\n" + "...\n" + "skillN:skill_averageN:skill_classN\n" + "An example of a fighter exists in /secure/cfg/classes/fighter. " + "This system is admittedly rather complex, but it beats hard " + "coding these values. In addition, a web-based administration " + "client is being developed to make class creation nothing more " + "than filling in a form.\n" + "See also: addemote, addrace"); +} diff --git a/lib/secure/cmds/admins/addclasses.c b/lib/secure/cmds/admins/addclasses.c new file mode 100644 index 0000000..8341b35 --- /dev/null +++ b/lib/secure/cmds/admins/addclasses.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <cfg.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd() { + string *classes = get_dir(CFG_CLASSES+"/"); + foreach(string element in classes){ + string str = CFG_CLASSES+"/"+element; + if(file_exists(str)) { + catch( CLASSES_D->AddClass(str) ); + } + } + write("Done."); + return 1; +} + +string GetHelp() { + return ("Syntax: addclasses\n\n" + "Imports all the class files in CFG_CLASSES into " + "CLASSES_D. It may fail if all classes have not been " + "removed prior to its use."); +} diff --git a/lib/secure/cmds/admins/addguest.c b/lib/secure/cmds/admins/addguest.c new file mode 100644 index 0000000..8786f5f --- /dev/null +++ b/lib/secure/cmds/admins/addguest.c @@ -0,0 +1,43 @@ +// /bin/adm/_addguest.c +// from the Dead Souls Mudlib +// adds a person to the guest list for when the mud is locked +// created by Descartes of Borg 08 july 1993 + +#include <lib.h> +#include <privs.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +int cmd(string str) { + string *guests; + mixed res; + int i; + + if(!master()->valid_apply(({ PRIV_SECURE, PRIV_ASSIST }))){ + error("Illegal attempt to add a guest."); + } + + if(!str) { + notify_fail("Correct syntax: addguest [guestlist]\n"); + return 0; + } + i = sizeof(guests = explode(str, " ")); + while(i--) { + if(!guests[i] || guests[i] == "") continue; + if(res = catch(call_other(BANISH_D, "add_guest", guests[i]))) + message("admin", sprintf("Error in adding guest %s: %s", + guests[i], res), this_player()); + } + message("admin", "Guests added.", this_player()); + return 1; +} + +string GetHelp() { + return ("Syntax: addguest [player list]\n\n" + "Adds a single player or group of players to the database of guests " + "allowed onto the mud when it is locked. This is generally used to " + "allow people in who are not in any of the groups defined in " + "LOCKED_ACCESS_ALLOWED or to allow on player testers.\n" + "See also: removeguests, whoguests"); +} diff --git a/lib/secure/cmds/admins/addrace.c b/lib/secure/cmds/admins/addrace.c new file mode 100644 index 0000000..689ffa2 --- /dev/null +++ b/lib/secure/cmds/admins/addrace.c @@ -0,0 +1,52 @@ +/* /secure/cmds/admins/addrace.c + * from the NIghtmare V Object Library + * creates new races + * created by Descartes of Borg 960528 + * Version: 1.2 + * Last Modified: 97/01/03 + */ + +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + string file; + int player; + + if( !args || args == "" ) return "Syntax: addrace <RACE> [1 | 0]"; + if( sscanf(args, "%s %d", file, player) != 2 ) { + file = args; + } + if( !file_exists(file=DIR_SECURE_CFG "/races/" + file) ) + return "File not found: " + file; + RACES_D->AddRace(file, player); + previous_object()->eventPrint("Race added."); + return 1; +} + +string GetHelp(){ + return ("Syntax: addrace <RACE> [0 | 1]\n\n" + "Allows you to add a new race to the racial data stored in the " + "races daemon. Specifically, you create a configuration file " + "and then issue this command to load the new race into the " + "races daemon. The optional second argument specifies if this " + "race is a player or not. If it is omitted or it is 0, the race " + "is assumed to be NPC-only. If it is 1, then it is assumed to " + "be usable by players as well.\n" + "NOTE: The PLAYER_RACE setting in the race file overrides that flag.\n" + "The format of the file is explained here:\n" + "http://dead-souls.net/ds-creator-faq.html#2.45\n\n" + "An example of a human exists in /secure/cfg/races/human. " + "You will notice that a human hs no special resistances. The " + "number of times resistances, stats, limbs, and fingers appear " + "does not matter so long as they appear in the file in the order " + "resistances, stats, limbs, fingers. In addition, parent " + "limbs need to be listed sometime *before* any child limbs. " + "For example, the right hand may come any time after the right " + "arm, but it must come after the right arm.\n" + "This system is admittedly rather complex, but it beats hard " + "coding these values.\nExample: addrace murlok 0\n" + "See also: addclass, addemote"); +} diff --git a/lib/secure/cmds/admins/addraces.c b/lib/secure/cmds/admins/addraces.c new file mode 100644 index 0000000..7c61cc6 --- /dev/null +++ b/lib/secure/cmds/admins/addraces.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <cfg.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd() { + string *races = get_dir(CFG_RACES+"/"); + foreach(string race in races){ + string str = CFG_RACES+"/"+race; + if(file_exists(str)) { + catch( RACES_D->AddRace(str) ); + } + } + write("Done."); + return 1; +} + +string GetHelp(){ + return ("Syntax: addraces\n\n" + "Imports all the race files in CFG_RACES into " + "RACES_D. It may fail if all races have not been " + "removed prior to its use."); +} diff --git a/lib/secure/cmds/admins/admintool.c b/lib/secure/cmds/admins/admintool.c new file mode 100644 index 0000000..bbe54ca --- /dev/null +++ b/lib/secure/cmds/admins/admintool.c @@ -0,0 +1,1237 @@ +#include <lib.h> +#include <privs.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +static private void validate() { + if(!this_player()) return 0; + if( !(master()->valid_apply(({ "ASSIST" }))) ) + error("Illegal attempt to access admintool: "+get_stack()+" "+identify(previous_object(-1))); +} + +varargs int Menu(string str); +int MainMenu(); +int MainMenuChoice(); +int GeneralMenu(); +int DaemonMenu(); +int UsersMenu(); +int DriverMenu(); +int GroupsMenu(); +int ToggleMudLock(); +int ShowLock(); +int SetTZ(); +int eventSetTZ(string str); +int ChangeEmail(); +varargs int eventChangeEmail(string str, int auto); +int SetReboot(); +int eventSetReboot(int i); +int AddClass(); +int eventAddClass(string str); +int RemoveClass(); +int eventRemoveClass(string str); +int AddRace(); +int eventAddRace(string str); +int RemoveRace(); +int PlayerRace(string str); +int eventRemoveRace(string str); +int AddCurrency(); +int eventAddCurrency(string str); +int CurrencyRate(string str); +int CurrencyWeight(string str); +int CurrencyInflation(string str); +int RemoveCurrency(); +int eventRemoveCurrency(string str); +int EncrePlayer(); +int eventEncrePlayer(string str); +int DecreCreator(); +int eventDecreCreator(string str); +mixed EnCre(string args); +mixed DeCre(string args); +int RidUser(); +int eventRidUser(string str); +int LogRid(string str); +int DoRid(string who); +int BanishUser(); +int eventBanishUser(string str); +int UnBanishUser(); +int eventUnBanishUser(string str); +int ChangeName(); +int eventChangeName(string str); +int ChangePort(); +int eventChangePort(int i); +int ShutDownMud(); +int eventShutDownMud(string str); +int RemoveGroup(); +int eventRemoveGroup(string str); +int AddGroup(); +int eventAddGroup(string str); +int ModGroup(); +int eventModGroup(string str); +int eventEditGroup(string str); +int ShowGroups(); + +string process_input(string str); + +string global_group_temp, menu, racepath, currency, ridded, globalstr, file; +string *currencies; +string gnom, gstr; + +float rate, weight, inflation; + + +mixed InvalidChoice(){ + validate(); + write("Invalid choice. Try again or choose q to quit.\n"); + Menu(); + return 1; +} + +int PlaceHolder(){ + validate(); + write("This function has not yet been defined."); + Menu(); + return 1; +} + +varargs int Menu(string str){ + validate(); + if(str) menu = str; + if(!menu) menu = "main"; + + switch (menu){ + case "main" : MainMenu(); break; + case "general" : GeneralMenu(); break; + case "daemon" : DaemonMenu();break; + case "users" : UsersMenu();break; + case "driver" : DriverMenu();break; + case "groups" : GroupsMenu();break; + default : menu = "main"; MainMenu(); break; + } + return 1; +} + +string process_input(string str){ + validate(); + switch (str) { + case "q" : write("Ok, quitting admintool.\nBye.\n");return " "; + case "x" : write("Ok, quitting admintool.\nBye.\n");return " "; + case "y" : write("Ok, quitting admintool.\nBye.\n");return " "; + case "z" : Menu("main"); break; + case "1" : Menu("general"); break; + case "2" : Menu("daemon");break; + case "3" : Menu("users");break; + case "4" : Menu("driver");break; + case "5" : Menu("groups");break; + case "a" : ToggleMudLock();break; + case "b" : ShowLock();break; + case "c" : SetTZ();break; + case "d" : ChangeEmail();break; + case "e" : SetReboot();break; + case "f" : AddClass();break; + case "g" : RemoveClass();break; + case "h" : AddRace();break; + case "i" : RemoveRace();break; + case "j" : AddCurrency();break; + case "k" : RemoveCurrency();break; + case "n" : RidUser();break; + case "o" : BanishUser();break; + case "p" : UnBanishUser();break; + case "r" : ChangeName();break; + case "s" : ChangePort();break; + case "t" : AddGroup();break; + case "u" : RemoveGroup();break; + case "v" : ModGroup();break; + case "w" : ShowGroups();break; + case "SD": ShutDownMud();break; + default : InvalidChoice(); + } + return "(process_input fun finished.)"; +} + + +varargs mixed MainMenu(string str) { + string tmp; + validate(); + tmp = "\tDead Souls Admin Tool\n"; + tmp += "\t=====================\n\n"; + tmp += "\t\t1) general\n"; + tmp += "\t\t2) daemon\n"; + tmp += "\t\t3) users\n"; + tmp += "\t\t4) driver\n"; + tmp += "\t\t5) groups\n\n"; + tmp += "\t\tq) quit\n"; + + this_player()->eventPrint(tmp, "foo"); + + input_to((: process_input :)); + return 1; +} + +static int GeneralMenu() { + string tmp; + + validate(); + tmp = "\tDead Souls Admin Tool General Menu\n"; + tmp += "\t\n\n"; + tmp += "\t\ta) toggle mud lock\n"; + tmp += "\t\tb) display current lock status\n"; + tmp += "\t\tc) change timezone\n"; + tmp += "\t\td) change admin email\n"; + tmp += "\t\te) change shutdown interval\n"; + tmp += "\t\tSD) shut down the MUD\n\n"; + tmp += "\t\tz) return to main menu\n"; + tmp += "\t\tq) quit\n"; + + this_player()->eventPrint(tmp, "foo"); + input_to((: process_input :)); + return 1; +} + +int DaemonMenu() { + string tmp; + + validate(); + tmp = "\tDead Souls Admin Tool Daemon Menu\n"; + tmp += "\t\n\n"; + tmp += "\t\tf) add class\n"; + tmp += "\t\tg) remove class\n"; + tmp += "\t\th) add race\n"; + tmp += "\t\ti) remove race\n"; + tmp += "\t\tj) add currency\n"; + tmp += "\t\tk) remove currency\n\n"; + tmp += "\t\tz) return to main menu\n"; + tmp += "\t\tq) quit\n"; + + this_player()->eventPrint(tmp, "foo"); + input_to((: process_input :)); + return 1; +} + +int UsersMenu() { + string tmp; + + validate(); + tmp = "\tDead Souls Admin Tool Users Menu\n"; + tmp += "\t\n\n"; + tmp += "\t\tn) completely erase a user\n"; + tmp += "\t\to) banish a username\n"; + tmp += "\t\tp) unbanish a username\n\n"; + tmp += "\t\tz) return to main menu\n"; + tmp += "\t\tq) quit\n"; + + this_player()->eventPrint(tmp, "foo"); + input_to((: process_input :)); + + return 1; +} + +int DriverMenu(){ + string tmp; + + validate(); + tmp = "\tDead Souls Admin Tool Driver Menu\n"; + tmp += "\t^^^^^^^^^^^^^^^^^^^^^^*******^^^^^\n"; + tmp += "\t\n\n"; + tmp += "\t\tr) display the MUD's name\n"; + tmp += "\t\ts) change the MUD's connection port\n\n"; + tmp += "\t\tz) return to main menu\n"; + tmp += "\t\tq) quit\n"; + + this_player()->eventPrint(tmp, "foo"); + input_to((: process_input :)); + + return 1; +} + +int GroupsMenu(){ + string tmp; + + validate(); + tmp = "\tDead Souls Admin Tool Groups Menu\n"; + tmp += "\t^^^^^^^^^^^^^^^^^^^^^^*******^^^^^\n"; + tmp += "\t\n\n"; + tmp += "\t\tt) Add a group\n"; + tmp += "\t\tu) Remove a group\n"; + tmp += "\t\tv) Modify a group\n"; + tmp += "\t\tw) Show groups\n\n"; + tmp += "\t\tz) return to main menu\n"; + tmp += "\t\tq) quit\n"; + tmp += "\n\nNote that this menu is %^RED%^DEPRECATED%^RESET%^.\n"; + tmp += "You should use the \"groupmod\" command instead.\n"; + + this_player()->eventPrint(tmp, "foo"); + input_to((: process_input :)); + + return 1; +} + +string GetHelp(){ + return ("Syntax: <admintool>\n\n" + "Menu-driven tool used to edit the MUD's configuration.\n" + "To change mud name or port number, choose the Driver menu.\n" + "Use the Users menu for promoting a player to creator status.\n" + "Use the Groups menu to make someone an assistant admin.\n"); +} + +int ToggleMudLock(){ + string *line_array; + string lockline, newline, newfile, line_string, junk; + int num; + + validate(); + line_string = read_file(CONFIG_H); + if(!sizeof(line_string)) write("Couldn't read file."); + line_array = explode(line_string, "\n"); + if(!sizeof(line_array)) write("Array is zero length."); + + foreach(string line in line_array){ + if(strsrch(line,"MUD_IS_LOCKED") != -1){ + lockline = line; + } + } + if(sscanf(lockline,"%s%d",junk, num) < 2) { + write("Operation failed. You need to hand-"+ + "edit "+CONFIG_H+" immediately."); + return 0; + } + if(num == 0) { + write("Locking mud.\n"); + num = 1; + } + else { + write("Unlocking mud.\n"); + num = 0; + } + newline = junk + num; + newfile = replace_string(line_string, lockline, newline); + write_file(CONFIG_H,newfile,1); + load_object("/secure/cmds/creators/update")->cmd("/secure/daemon/master"); + load_object("/secure/cmds/creators/update")->cmd("/secure/lib/connect"); + write("\n"); + Menu(); + return 1; +} + +int ShowLock(){ + validate(); + if(load_object("/secure/daemon/master")->is_locked()){ + write("Mud is locked. Only admins and designated personnel can log in.\n"); + } + else write("Mud is unlocked. Players are free to login.\n"); + Menu(); + return 1; +} + + +int SetTZ(){ + validate(); + write("Please enter the desired time zone: \n"); + input_to( (: eventSetTZ :) ); + return 1; +} + +int eventSetTZ(string str){ + string ret; + + validate(); + ret = set_tz(str); + write(ret+"\n"); + load_object("/secure/cmds/creators/update")->cmd("/daemon/time"); + Menu(); + return 1; +} + +int ChangeEmail(){ + validate(); + write("Current admin email is: "+admin_email()); + write("Please enter the new email address of the mud administrator: \n"); + input_to( (: eventChangeEmail :) ); + return 1; +} + +varargs int eventChangeEmail(string str, int auto){ + string *line_array; + string lockline, newline, newfile, line_string, junk, email; + + validate(); + if(strsrch(str,"@") == -1 ) { + write("That isn't a valid email address."); + if(!auto) Menu(); + return 0; + } + str == replace_string(str, "#", ""); + line_string = read_file(CONFIG_H); + if(!sizeof(line_string)) write("Couldn't read file."); + line_array = explode(line_string, "\n"); + if(!sizeof(line_array)) write("Array is zero length."); + foreach(string line in line_array){ + if(strsrch(line,"ADMIN_EMAIL") != -1){ + lockline = line; + } + } + if(sscanf(lockline,"%s\"%s\"",junk, email) < 2) { + write("Operation failed. You need to hand-"+ + "edit "+CONFIG_H+" immediately."); + if(!auto) Menu(); + return 0; + } + + newline = junk + "\""+str+"\""; + newfile = replace_string(line_string, lockline, newline); + write_file(CONFIG_H,newfile,1); + load_object("/secure/cmds/creators/update")->cmd("/secure/sefun/sefun"); + write("\n"); + if(!auto) Menu(); + return 1; +} + +int SetReboot(){ + validate(); + write("Current reboot interval is set to "+EVENTS_D->GetRebootInterval()+" hours."); + write(load_object("/cmds/players/nextreboot")->cmd("string")); + write("Please enter the new desired interval in hours:\n"); + input_to( (: eventSetReboot :) ); + return 1; +} + +int eventSetReboot(mixed i){ + int num, check; + + validate(); + if(!intp(i) && !sscanf(i,"%d",num)){ + write("Failed to set new interval.\n"); + Menu(); + return 1; + } + if(intp(i)) num = i; + check = EVENTS_D->SetRebootInterval(num); + reload(EVENTS_D); + if(num == check) + write("Reboot interval set to "+EVENTS_D->GetRebootInterval()+" hours."); + else + write("Reboot interval could not be set. Current interval is: "+ + check + " hours."); + Menu(); + return 1; +} + +int AddClass(){ + validate(); + write("Classes currently available: "+implode(load_object(CLASSES_D)->GetClasses()," ")); + write("Please enter the name of the class you'd like to add: \n"); + input_to( (: eventAddClass :) ); + return 1; +} + +int eventAddClass(string str){ + string classpath; + array *classes; + + validate(); + if(!str) { + write("Invalid class name.\n"); + Menu(); + return 1; + } + + classpath = "/secure/cfg/classes/"+str; + write("Looking for "+classpath+"..."); + classes = load_object(CLASSES_D)->GetClasses(); + if(member_array(str,classes) != -1) { + write("That class is already available.\n"); + Menu(); + return 1; + } + if(file_size(classpath) < 1) { + write("For a class to be added, you must create and "); + write("edit a class file, then place it in /secure/cfg/classes "); + write("with the other class files.\n"); + write("Operation Failed: no such class file\n"); + Menu(); + return 1; + } + CLASSES_D->AddClass(classpath); + write("Classes currently available: "+implode(load_object(CLASSES_D)->GetClasses()," ")+"\n"); + + Menu(); + return 1; +} + +int RemoveClass(){ + validate(); + write("Classes currently available: "+implode(load_object(CLASSES_D)->GetClasses()," ")); + write("Please enter the class you'd like to remove: \n"); + input_to( (: eventRemoveClass :) ); + return 1; +} + +int eventRemoveClass(string str){ + validate(); + if(!str){ + write("That is not a valid class.\n"); + Menu(); + return 1; + } + + if(member_array(str,load_object(CLASSES_D)->GetClasses()) == -1) { + write("That class is already unavailable.\n"); + Menu(); + return 1; + } + + load_object(CLASSES_D)->RemoveClass(str); + write("Classes currently available: "+implode(load_object(CLASSES_D)->GetClasses()," ")+"\n"); + Menu(); + return 1; +} + +int AddRace(){ + validate(); + write("Races currently available: "+implode(load_object(RACES_D)->GetRaces()," ")); + write("Please enter the name of the race you'd like to add: \n"); + input_to( (: eventAddRace :) ); + return 1; +} + +int eventAddRace(string str){ + array *races; + + validate(); + if(!str) { + write("Invalid race name.\n"); + Menu(); + return 1; + } + + racepath = "/secure/cfg/races/"+str; + write("Looking for "+racepath+"..."); + races = load_object(RACES_D)->GetRaces(); + if(member_array(str,races) != -1) { + write("That race is already available.\n"); + Menu(); + return 1; + } + if(file_size(racepath) < 1) { + write("For a race to be added, you must create and "); + write("edit a race file, then place it in /secure/cfg/races "); + write("with the other race files.\n"); + write("Operation Failed: no such race file\n"); + Menu(); + return 1; + } + + write("Should players be able to play as this race?"); + write("A response other than yes will be interpreted as a no.\n"); + input_to( (: PlayerRace :) ); + return 1; +} + +int PlayerRace(string str){ + string *response_array = ({"yes","ok","y","yeah","yes, please"}); + + validate(); + if(!str) str = "no"; + if(member_array(str,response_array) != -1) RACES_D->AddRace(racepath, 1); + else RACES_D->AddRace(racepath); + write("Races currently available: "+implode(load_object(RACES_D)->GetRaces()," ")+"\n"); + + Menu(); + return 1; +} + +int RemoveRace(){ + validate(); + write("Races currently available: "+implode(load_object(RACES_D)->GetRaces()," ")); + write("Please enter the race you'd like to remove: \n"); + input_to( (: eventRemoveRace :) ); + return 1; +} + +int eventRemoveRace(string str){ + validate(); + if(!str){ + write("That is not a valid race.\n"); + Menu(); + return 1; + } + + if(member_array(str,load_object(RACES_D)->GetRaces()) == -1) { + write("That race is already unavailable.\n"); + Menu(); + return 1; + } + + load_object(RACES_D)->RemoveRace(str); + write("Races currently available: "+implode(load_object(RACES_D)->GetRaces()," ")+"\n"); + Menu(); + return 1; +} + +int AddCurrency(){ + validate(); + write("Currencies currently available: "+implode(ECONOMY_D->__QueryCurrencies()," ")); + write("Please enter the name of the curency you'd like to add: \n"); + input_to( (: eventAddCurrency :) ); + return 1; +} + +int eventAddCurrency(string str){ + string query; + + validate(); + currency = str; + if(!str || str == "") { + write("Invalid currency name.\n"); + Menu(); + return 1; + } + + currencies = ECONOMY_D->__QueryCurrencies(); + if(member_array(str,currencies) != -1) { + write("That currency is already available.\n"); + Menu(); + return 1; + } + if(sizeof(currencies) > 2){ + query = "What should its exchange rate, or value be? For comparison, "+currencies[0]+" "; + query += "has a rate of "+ ECONOMY_D->__Query(currencies[0],"rate")+", "+currencies[1]+" "; + query += "has a rate of "+ ECONOMY_D->__Query(currencies[1],"rate")+", and "+currencies[2]+" "; + query += "has a rate of "+ ECONOMY_D->__Query(currencies[2],"rate")+".\n"; + } + else query = "What should its exchange rate, or value be?"; + + write(query); + input_to( (: CurrencyRate :) ); + return 1; +} + +int CurrencyRate(string str){ + string query; + + validate(); + if(!str || !sscanf(str,"%f",rate) ){ + write("Invalid rate. Currency not added.\n"); + Menu(); + return 1; + } + if(sizeof(currencies) > 2){ + query = "What should its weight be? For comparison, "+currencies[0]+" "; + query += "has a weight of "+ ECONOMY_D->__Query(currencies[0],"weight")+", "+currencies[1]+" "; + query += "has a weight of "+ ECONOMY_D->__Query(currencies[1],"weight")+", and "+currencies[2]+" "; + query += "has a weight of "+ ECONOMY_D->__Query(currencies[2],"weight")+".\n"; + } + else query = "What should its weight be?"; + write(query); + input_to( (: CurrencyWeight :) ); + return 1; +} + + +int CurrencyWeight(string str){ + string query; + + validate(); + if(!str || !sscanf(str,"%f",weight) ){ + write("Invalid weight. Currency not added.\n"); + Menu(); + return 1; + } + if(sizeof(currencies) > 2){ + query = "What should its inflation rate be? For comparison, "+currencies[0]+" "; + query += "has an inflation rate of "+ ECONOMY_D->__Query(currencies[0],"inflation")+", "+currencies[1]+" "; + query += "has an inflation rate of "+ ECONOMY_D->__Query(currencies[1],"inflation")+", and "+currencies[2]+" "; + query += "has an inflation rate of "+ ECONOMY_D->__Query(currencies[2],"inflation")+".\n"; + } + else query = "What should its inflation rate be?"; + write(query); + input_to( (: CurrencyInflation :) ); + return 1; +} + +int CurrencyInflation(string str){ + validate(); + if(!str || !sscanf(str,"%f",inflation) ){ + write("Invalid inflation rate. Currency not added.\n"); + Menu(); + return 1; + } + write(identify(previous_object(-1))); + write("ECONOMY_D->add_currency(\""+currency+"\", "+rate+", "+inflation+", "+weight+");"); + ECONOMY_D->add_currency(currency, rate, inflation, weight); + write("Thank you. Currency added.\n"); + Menu(); + return 1; +} + +int RemoveCurrency(){ + validate(); + currencies = ECONOMY_D->__QueryCurrencies(); + if(sizeof(currencies) == 1) { + write("Please add a currency before removing this last one."); + write("Removing the last currency would cause the mud to "+ + "behave unexpectedly."); + return 1; + } + write("Available currencies: "+ identify(currencies) +"."); + write("Which currency would you like to remove?\n"); + + input_to( (: eventRemoveCurrency :) ); + return 1; +} + +int eventRemoveCurrency(string str){ + validate(); + if(!str || member_array(str, currencies) == -1) { + write("Invalid currency. No currency removed.\n"); + Menu(); + return 1; + } + ECONOMY_D->remove_currency(str); + write("Remaining currencies: "+identify(ECONOMY_D->__QueryCurrencies())+"\n"); + Menu(); + return 1; +} + +int RidUser(){ + validate(); + write("Please enter the name of the player you'd like to erase.\n"); + input_to( (: eventRidUser :) ); + return 1; +} + +int eventRidUser(string str){ + validate(); + if(!str){ + write("Invalid entry.\n"); + Menu(); + return 1; + } + + if( !user_exists(str) ) { + write("No such person: " + str + ".\n"); + Menu(); + } + DoRid(str); + return 1; +} + +int DoRid(string who) { + object ob; + string str; + + validate(); + ridded = lower_case(who); + str = convert_name(who); + who = capitalize(who); + if( member_group(str, PRIV_SECURE) || member_group(str, PRIV_ASSIST) ){ + write("You must first remove this person from a secure group."); + Menu(); + return 1; + } + if( ob = find_player(ridded)) { + who = ob->GetCapName(); + message("system", "You are being ridded from " + mud_name() + ".", + ob); + ob->eventForce("quit"); + } + file = player_save_file(ridded); + write("Target is: "+ridded); + write("Please enter the reason for ridding " + ridded + ".\n"); + unguarded( (: rm(file) :) ); + input_to( (: LogRid :) ); + return 1; +} + +int LogRid(string str){ + validate(); + globalstr = str; + log_file("rid", "\n" + ridded + " by " + this_player()->GetCapName() + "\n" + str + "\n"); + write(ridded + " has been ridded from " + mud_name() + "."); + Menu(); + return 1; +} + +int BanishUser(){ + validate(); + write("Please enter the name to banish: \n"); + input_to( (: eventBanishUser :) ); + return 1; +} + +int eventBanishUser(string str){ + validate(); + if(member_array(str,BANISH_D->query_banished()) != -1) { + write("That name is already banished.\n"); + Menu(); + return 1; + } + if(!user_exists(str = lower_case(str))) { + write(capitalize(str)+" is now banished.\n"); + catch(call_other(BANISH_D, "banish_name", str)); + } + else { + write("A player by that name already exists.\n"); + this_player()->eventPrint(FINGER_D->GetFinger(str)); + } + Menu(); + return 1; +} + +int UnBanishUser(){ + validate(); + write("Please enter the name to unbanish: \n"); + input_to( (: eventUnBanishUser :) ); + return 1; +} + +int eventUnBanishUser(string str){ + validate(); + if(member_array(str,BANISH_D->query_banished()) == -1) { + write("That is not a banished name."); + Menu(); + return 1; + } + catch(call_other(BANISH_D, "unbanish_name", str)); + write(str+" is unbanished.\n"); + Menu(); + return 1; +} + +int ChangeName(){ + validate(); + write("Current MUD name is "+mud_name()); + write("To change the mud's name, use the command: "); + write("mudconfig mudname <name>"); + Menu(); + return 1; +} + +varargs int eventChangeName(string newname, int automated){ + string *line_array; + string mconfig, nameline, newline, newfile, line_string, junk, name; + + validate(); + if(!newname || newname == "") { + write("Name change cancelled.\n"); + Menu(); + return 1; + } + + if(automated){ + if(mud_name() != "DeadSoulsNew" && + mud_name() != "DeadSoulsWin") + return 0; + } + + if(!find_object(INSTANCES_D) || !ENABLE_INSTANCES || + INSTANCES_D->GetMyInstanceName() == "global"){ + mconfig = "/secure/cfg/mudos.cfg"; + } + else { + mconfig = "/secure/cfg/mudos."+query_host_port()+".cfg"; + } + + line_string = read_file(mconfig); + if(!sizeof(line_string)) write("Couldn't read file."); + line_array = explode(line_string, "\n"); + if(!sizeof(line_array)) write("Array is zero length."); + + if(!sizeof(line_array) || !sizeof(line_string)) { + if(!automated) Menu(); + return 0; + } + + foreach(string line in line_array){ + if(strsrch(line,"name :") != -1){ + nameline = line; + } + } + + if(!nameline || sscanf(nameline,"%s : %s",junk, name) < 2) { + write("Operation failed. You need to copy over "+ + mconfig+" immediately with an original."); + if(!automated) Menu(); + return 0; + } + + if(automated){ + if(name != "DeadSoulsWin" && name != "DeadSouls" && + name != "Dead Souls" && name != "DeadSoulsNew") newname = name; + cp(mconfig,"/secure/cfg/mudos.orig"); + } + + newline = junk + " : " + newname; + newfile = replace_string(line_string, nameline, newline); + write_file(mconfig,newfile,1); + cp(mconfig,"/secure/cfg/mudos.autobak."+query_host_port()); + if(automated && query_windows()){ + cp(mconfig,"/secure/cfg/mudos.win32"); + } + write("\n"); + if(!automated) { + write("\nMUD's name changed. Reboot the MUD to activate new name.\n"); + write("\n Do you want to shut down the MUD now to activate the change?\n"); + input_to( (: eventShutDownMud :) ); + } + return 1; +} + +int ChangePort(){ + validate(); + if(!find_object(INSTANCES_D) || !ENABLE_INSTANCES || + INSTANCES_D->GetMyInstanceName() == "global"){ + write("Current MUD network port is "+query_host_port()); + write("Please enter the new network port for your MUD:\n"); + input_to( (: eventChangePort :) ); + } + else { + write("Port changing in admintool is disabled for instances."); + Menu(); + } + + return 1; +} + +varargs int eventChangePort(string newport, int automated){ + string *line_array; + string nameline, newline, newfile, line_string, junk, name; + int num; + + validate(); + if(!newport || newport == "") { + write("Port change cancelled.\n"); + Menu(); + return 1; + } + + if(!sscanf(newport,"%d", num) > 0 || num < 1 || num > 65535 ) { + write("Invalid port: numeral between 1 and 65535 expected."); + write("Port change cancelled.\n"); + Menu(); + return 1; + } + + line_string = read_file("/secure/cfg/mudos.cfg"); + if(!sizeof(line_string)) write("Couldn't read file."); + line_array = explode(line_string, "\n"); + if(!sizeof(line_array)) write("Array is zero length."); + + foreach(string line in line_array){ + if(strsrch(line,"external_port_1 :") != -1){ + nameline = line; + } + } + + if(!nameline || sscanf(nameline,"%s : %s",junk, name) < 2) { + write("Operation failed. You need to copy over "+ + "/secure/cfg/mudos.cfg immediately with an original."); + if(!automated) Menu(); + return 0; + } + + newline = junk + " : telnet " + newport; + newfile = replace_string(line_string, nameline, newline); + write_file("/secure/cfg/mudos.cfg",newfile,1); + if(!automated) { + write("\nMUD's port changed. Reboot the MUD to activate new port."); + write("NOTE: If the port you selected is 1024 or below, your OS "+ + "may require the MUD to run as a privileged user."); + write("\n Do you want to shut down the MUD now to activate the change?\n"); + input_to( (: eventShutDownMud :) ); + } + return 1; +} + +int ShutDownMud(){ + validate(); + write("Are you sure?"); + input_to( (: eventShutDownMud :) ); + return 1; +} + +int eventShutDownMud(string str){ + string *response_array = ({"yes","ok","y","yeah","yes, please"}); + + validate(); + if(!str) str = "no"; + if(member_array(str,response_array) == -1){ + write("Shutdown cancelled.\n"); + Menu(); + return 1; + } + + write("Shutdown initiated.\n"); + if(this_player()->GetForced()) return 0; + + shout("Game is shut down by " + this_player()->GetKeyName() + ".\n"); + log_file("game_log", ctime(time())+" Game shutdown by "+ + this_player()->GetKeyName()+"(admintool)\n"); + foreach(object dude in users()){ + if(sizeof(base_name(dude)) && !archp(dude)) dude->eventForce("quit"); + } + shutdown(); + write("Shutdown complete."); + Menu(); + return 1; +} + +int AddGroup(){ + validate(); + write("\nCurrent groups file: \n"+read_file("/secure/cfg/groups.cfg")+"\n\n"); + write("\nWhat is the name of the group you'd like to add?\n"); + input_to( (: eventAddGroup :) ); + return 1; +} + +int eventAddGroup(string str){ + string config_file, new_config_file; + string *line_array; + string *top_array; + string *bottom_array; + + validate(); + top_array = ({}); + bottom_array = ({}); + + if(!str || str == "") { + write("\nGroup addition cancelled.\n"); + Menu(); + return 1; + } + config_file = read_file("/secure/cfg/groups.cfg"); + if(!sizeof(config_file)) { + write("Couldn't read file. Addition cancelled.\n"); + Menu(); + return 1; + } + + str = upper_case(str); + if(strsrch(config_file,"("+str+")") != -1 ) { + write("\nThat group already exists. Addition cancelled.\n"); + Menu(); + return 1; + } + + line_array = explode(config_file, "\n"); + if(!sizeof(line_array)) { + write("\nArray is zero length. Addition cancelled.\n"); + Menu(); + return 1; + } + + foreach(string line in line_array){ + if(strsrch(line,"(") != -1 && + first(line,1) != "#"){ + bottom_array += ({ line }); + } + else top_array += ({ line }); + } + + bottom_array += ({"("+str+") "}); + + new_config_file = implode(top_array,"\n"); + new_config_file += "\n"; + new_config_file += implode(bottom_array,"\n"); + write_file("/secure/cfg/groups.cfg",new_config_file,1); + write("\nGroup "+str+" added.\n"); + load_object("/secure/cmds/creators/update")->cmd("/secure/daemon/master"); + load_object("/secure/cmds/creators/update")->cmd("/secure/lib/connect"); + Menu(); + return 1; + } + + int RemoveGroup(){ + validate(); + write("\nCurrent groups file: \n"+read_file("/secure/cfg/groups.cfg")+"\n\n"); + write("\nWhat is the name of the group you'd like to remove?\n"); + input_to( (: eventRemoveGroup :) ); + return 1; + } + +int eventRemoveGroup(string str){ + string config_file, new_config_file; + string *line_array; + string *top_array; + string *bottom_array; + + validate(); + top_array = ({}); + bottom_array = ({}); + + if(!str || str == "") { + write("\nGroup removal cancelled.\n"); + Menu(); + return 1; + } + config_file = read_file("/secure/cfg/groups.cfg"); + if(!sizeof(config_file)) { + write("Couldn't read file. removal cancelled.\n"); + Menu(); + return 1; + } + + str = upper_case(str); + if(strsrch(config_file,"("+str+")") == -1 ) { + write("\nThat group doesn't exist. removal cancelled.\n"); + Menu(); + return 1; + } + + if(str == "SECURE" || str == "ASSIST"){ + write("\nThis is a configured administrative group. You "+ + "can't remove it with admintool. If you really, really, really "+ + "know what you're doing and you want to remove that group, you'll "+ + "have to do it manually with an editor.\n"); + Menu(); + return 1; + } + + line_array = explode(config_file, "\n"); + if(!sizeof(line_array)) { + write("\nArray is zero length. removal cancelled.\n"); + Menu(); + return 1; + } + + foreach(string line in line_array){ + if(strsrch(line,"(") != -1 && first(line,1) != "#"){ + if(strsrch(line,"("+str+")") == -1 ) bottom_array += ({ line }); + } + else if(strsrch(line,"("+str+")") == -1 ) top_array += ({ line }); + } + + new_config_file = implode(top_array,"\n"); + new_config_file += "\n"; + new_config_file += implode(bottom_array,"\n"); + write_file("/secure/cfg/groups.cfg",new_config_file,1); + load_object("/secure/cmds/creators/update")->cmd("/secure/daemon/master"); + load_object("/secure/cmds/creators/update")->cmd("/secure/lib/connect"); + write("\nGroup "+str+" removed.\n"); + Menu(); + return 1; + } + + int ModGroup(){ + validate(); + write("\nCurrent groups file: \n"+read_file("/secure/cfg/groups.cfg")+"\n\n"); + write("\nWhat is the name of the group you'd like to modify?\n"); + input_to( (: eventModGroup :) ); + return 1; + } + +int eventModGroup(string str){ + string config_file; + + validate(); + if(!str || str == "") { + write("\nGroup modification cancelled.\n"); + Menu(); + return 1; + } + config_file = read_file("/secure/cfg/groups.cfg"); + if(!sizeof(config_file)) { + write("Couldn't read file. modification cancelled.\n"); + Menu(); + return 1; + } + + str = upper_case(str); + if(strsrch(config_file,"("+str+")") == -1 ) { + write("\nThat group doesn't exist. modification cancelled.\n"); + Menu(); + return 1; + } + + if(!sizeof(explode(config_file, "\n"))) { + write("\nArray is zero length. modification cancelled.\n"); + Menu(); + return 1; + } + + write(str); + global_group_temp = str; + write("The group format must be entered correctly. If the members are larry, moe, and curly, enter:\n"); + write("larry:moe:curly\n"); + write("\nIt's important to put those colons between names. If the only member is shemp, enter:\n"); + write("shemp\n"); + write("\nWhat would you like that group to contain?\n"); + input_to ( (: eventEditGroup :) ); + return 1; +} + +int eventEditGroup(string members){ + string config_file, new_config_file, str; + string *line_array; + string *top_array; + string *bottom_array; + string *dudes; + + validate(); + members = lower_case(members); + top_array = ({}); + bottom_array = ({}); + + config_file = read_file("/secure/cfg/groups.cfg"); + line_array = explode(config_file, "\n"); + str = global_group_temp; + global_group_temp = ""; + + + if(str == "ASSIST" || str == "SECURE" ) { + if(!securep(this_player())){ + write("Only full admins may do this."); + Menu(); + return 1; + } + } + + if(str == "SECURE"){ + validate(); + if(!members || members == "") { + write("You're not leaving the SECURE group empty. Modification cancelled.\n"); + Menu(); + return 1; + } + if(strsrch(members,":") != -1) dudes = explode(members,":"); + else dudes = ({ members }); + + if(member_array(this_player()->GetKeyName(),dudes) == -1) { + write("You can only modify this line with admintool if you include yourself in it. Modification cancelled.\n"); + Menu(); + return 1; + } + } + + foreach(string line in line_array){ + if(strsrch(line,"(") != -1 && first(line,1) != "#"){ + if(strsrch(line,"("+str+")") == -1 ) bottom_array += ({ line }); + } + else if(strsrch(line,"("+str+")") == -1 ) top_array += ({ line }); + } + + new_config_file = implode(top_array,"\n"); + new_config_file += "\n"; + new_config_file += implode(bottom_array,"\n"); + new_config_file += "\n"; + new_config_file += "("+str+") "+members; + write_file("/secure/cfg/groups.cfg",new_config_file,1); + load_object("/secure/cmds/creators/update")->cmd("/secure/daemon/master"); + load_object("/secure/cmds/creators/update")->cmd("/secure/lib/connect"); + write("\nGroup "+str+" modified.\n"); + Menu(); + return 1; + } + + int ShowGroups(){ + validate(); + write("\nCurrent groups file: \n"+read_file("/secure/cfg/groups.cfg")+"\n\n"); + Menu(); + return 1; + } + +mixed cmd(string args) { + validate(); + Menu("main"); + return 1; +} diff --git a/lib/secure/cmds/admins/allow.c b/lib/secure/cmds/admins/allow.c new file mode 100644 index 0000000..a3387b8 --- /dev/null +++ b/lib/secure/cmds/admins/allow.c @@ -0,0 +1,46 @@ +// /bin/adm/_allow.c +// from the Dead Souls mudlib +// lets in selected players from sites on register +// created by Shadowwolf@Dead Souls? + +#include <lib.h> +#include <privs.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +int cmd(string str) { + string who, email; + mixed res; + + if(!archp(previous_object())) return 0; + if(!member_group(previous_object(), PRIV_SECURE)) { + if(!member_group(previous_object(), "LAW")) { + notify_fail("Only law may allow new players in the game.\n"); + return 0; + } + } + if(!str) return 0; + if(sscanf(lower_case(str), "%s %s", who, email) != 2) { + notify_fail("Syntax: allow <who> <email>\n"); + return 0; + } + if(user_exists(who)) { + notify_fail("A character by that name already exists.\n"); + return 0; + } + write(capitalize(who)+" is now allowed to create a character.\n"); + if(res = catch(call_other(BANISH_D, "allow_name", who))) + write("Error in letting in "+who+": "+res+"\n"); + log_file("watch/players", capitalize(who)+": "+email+" ("+ctime(time())+")\n"); + return 1; +} + +string GetHelp(){ + return "Syntax: allow <who> <email>\n\n" + "Members of law may allow people from sites on register to create " + "new characters with this command. <who> is the character name, " + "<email> is the player's real life email address. " + "See also: whobanished, whoregistered, whowatched"; +} + diff --git a/lib/secure/cmds/admins/banish.c b/lib/secure/cmds/admins/banish.c new file mode 100644 index 0000000..b0a3aec --- /dev/null +++ b/lib/secure/cmds/admins/banish.c @@ -0,0 +1,53 @@ +// /bin/dev/_banish.c +// from the Dead Souls Mudlib +// prevents a name being used by a new player +// created by Descartes of Borg ??? + +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +int cmd(string str) { + int substr = 0; + + if(!str || str == ""){ + write("Syntax: banish <string>"); + return 1; + } + + if(grepp(str,"-s ")){ + str = replace_string(str,"-s ",""); + substr = 1; + } + if(!user_exists(str = lower_case(str))) { + if(!substr){ + BANISH_D->banish_name(str); + write(capitalize(str)+" is now banished.\n"); + } + else { + BANISH_D->set_illegal_substring(str); + write("The substring \""+str+"\" is now illegal in a name."); + } + } + else { + write("A player by that name already exists.\n"); + this_player()->eventPrint(FINGER_D->GetFinger(str)); + } + return 1; +} + +string GetHelp(){ + return ("Syntax: banish [-s] <name | word>\n\n" + "Protects a name from being used by a new player.\n" + "For example, if you have created a monster named Cassandra, in order\n" + "to avoid problems with player complaining \"I typed 'kill\n" + "cassandra' meaning to kill the evil enchantress, but Cassandra\n" + "walked in and I accidentally killed her.\" It is also to be\n" + "used to keep people from using offensive words as names.\n" + "The -s option makes the argument a substring to be made illegal, " + "so that:\n" + "banish -s top\n" + "would make it impossible to create a character named Carrottop." + ); +} diff --git a/lib/secure/cmds/admins/cconv.c b/lib/secure/cmds/admins/cconv.c new file mode 100644 index 0000000..8950a50 --- /dev/null +++ b/lib/secure/cmds/admins/cconv.c @@ -0,0 +1,352 @@ +#include <lib.h> +#include <dirs.h> +#include <vendor_types.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +string original, digested; +mapping AreaMap = ([]); +mapping RawMap = ([]); +string array source_dirs = ({ "zon", "mob", "obj", "shp", "trg", "wld", "gld" }); +mapping Genders = ([ 0 : "neutral", 1 : "male", 2 : "female" ]); +mapping Directions = ([ 0 : "north", 1 : "east", 2 : "south", + 3 : "west", 4 : "up", 5 : "down", 6 : "northwest", 7 : "northeast", + 8 : "southeast", 9 : "southwest", 10 : "in", 11 : "out" ]); +mapping Types = ([ 1 : "LIB_ITEM", 2 : "LIB_ITEM", 3 : "LIB_ITEM", 4 : "LIB_ITEM", + 5 : "LIB_ITEM", 6 : "LIB_ITEM", 7 : "LIB_ITEM", 8 : "LIB_ITEM", 9 : "LIB_ARMOR", 10 : "LIB_POTION", + 11 : "LIB_ITEM", 12 : "LIB_ITEM", 13 : "LIB_ITEM", 14 : "LIB_ITEM", 15 : "LIB_STORAGE", + 16 : "LIB_ITEM", 17 : "LIB_MEAL", 18 : "LIB_ITEM", 19 : "LIB_MEAL", 20 : "LIB_PILE", + 21 : "LIB_ITEM", 22 : "LIB_ITEM", 23 : "LIB_ITEM", 24 : "LIB_ITEM", 25 : "LIB_ITEM", + 26 : "LIB_ITEM", 44 : "LIB_ITEM" ]); +string gdirection, cle, val, room; +int item_type; +mixed com,v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13; +int weight, cost, material,ok,ok2; +int lock, key, direction; + +mapping ObjectType = ([ + "zon" : "ZONE", + "obj" : "OBJECTS", + "mob" : "MOBILES", + "wld" : "ROOMS", + ]); + +mixed cmd(string args){ + if(args == "clear"){ + write("Resetting the converter variables."); + RELOAD_D->eventReload(this_object(),0); + return 1; + } + if(grepp(args,"-r ")){ + args = replace_string(args,"-r ",""); + return this_object()->Report(args); + } + return this_object()->ConvertArea(args); +} + +string clean_string(string str){ + str = replace_string(str,"\"","\'",); + return str; +} + +varargs mixed QueryMaps(string which, string what){ + if(!which || !what){ + write("AreaMap: "+(AreaMap ? identify(keys(AreaMap)) : "0")); + write("RawMap: "+(AreaMap ? identify(keys(AreaMap)) : "0")); + return 1; + } + if(which == "area"){ + if(AreaMap && AreaMap[what]) return identify(AreaMap[what]); + else return "No such element."; + } + if(which == "raw"){ + if(RawMap && RawMap[what]) return identify(RawMap[what]); + else return "No such element."; + } + return "IDK."; +} + +int Report(string str){ + print_long_string(this_player(),"vnums: "+item_list(keys(AreaMap)),1); + if(str == "both" || str == "area") print_long_string(this_player(),"%^RED%^AreaMap: "+identify(AreaMap),1); + if(str == "both" || str == "raw") print_long_string(this_player(),"%^GREEN%^RAWMap: "+identify(RawMap),1); + if(sscanf(str,"%*d")) this_object()->DisplayVnum(str); + return 1; +} + +int DisplayVnum(string str){ + if(!str || !AreaMap[str]){ + write("No such vnum in this area."); + return 1; + } + print_long_string(this_player(),"vnum "+str+":\n"+identify(AreaMap[str]),1); + return 1; +} + +int ConvertArea(string arg){ + string area, tmp, str, name, prefix; + int i; + string *room_arr; + string *mob_arr; + string *obj_arr; + string *segmented = ({}); + + if(!arg || sscanf(arg,"%s %s %s",str, area, name) != 3){ + write("cconv PATH AREA NAME"); + return 1; + } + + if(!str || !directory_exists(str)){ + write("No such area directory exists."); + return 1; + } + + if(directory_exists(DOMAINS_DIRS+"/"+name)){ + write("That domain already exists. Backing up the current domain to a unique name."); + rename(DOMAINS_DIRS+"/"+name, DOMAINS_DIRS+"/"+name+"."+time()); + } + + foreach(string elemento in source_dirs){ + string path = str+"/"+area+"."+elemento; + if(!file_exists(path)){ + write(path+" does not exist. Skipping."); + continue; + } + + original = read_file(path); + digested = clean_string(original); + + segmented = explode(digested,"\n"); + if(!RawMap) RawMap = ([]); + RawMap[ObjectType[elemento]]= segmented[0..]; + } + + + ///// + // ITEMS + ///// + + tmp = implode(RawMap["OBJECTS"],"\n"); + prefix = DOMAINS_DIRS+"/"+name+"/obj/"; + obj_arr = explode(tmp,"#"); + foreach(mixed block in obj_arr){ + string *ob_id; + string *lines = explode(block,"\n"); + string short, long, ob_name; + string header = ""; + if(block && sizeof(lines) > 1){ + ob_id = explode(truncate(lines[1],1)," "); + if(!sizeof(ob_id)) continue; + ob_name = ob_id[0]; + short = truncate(lines[2],1); + long = ""; + for(i=2;i < sizeof(lines);i++){ + int num = i; + if(sscanf(lines[i],"%d %s %s %s %s %s %s %s %s %s %s %s %s", + v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13) == 13) { + item_type = v1; + continue; + } + if(sscanf(lines[i],"%d %d %d %d %d %d %d %d",v1,v2,v3,v4,v5, + v6,v7,v8) == 8){ + material = v8; + continue; + + } + if(sscanf(lines[i],"%d %d %d %d",v1,v2,v3,v4) == 4){ + weight = v1; + cost = v2; + continue; + } + + if(lines[i] == "E"){ + for(num = i+2; num < sizeof(lines);num++){ + if(lines[num] == "~") break; + long += lines[num]+" "; + } + break; + } + } + } + + header += "#include <lib.h>\n\n"; + header += "inherit "+(Types[item_type] || "LIB_ITEM")+";\n\n"; + header += "static void create() {\n"; + header += " ::create();\n"; + header += " SetKeyName(\""+ob_name+"\");\n"; + header += " SetId( "+identify(ob_id)+" );\n"; + header += " SetShort(\""+short+"\");\n"; + header += " SetLong(\""+long+"\");\n"; + header += " SetMass("+(weight*10)+");\n"; + header += " SetBaseCost("+cost+");\n"; + if (Types[item_type] == "LIB_STORAGE") { + header += " SetInventory( ([\n"; + header += " ]) );\n"; + } + header += "}\nvoid init(){\n::init();\n}\n"; + + mkdir_recurse(truncate(prefix,1)); + if(directory_exists(truncate(prefix,1))){ + write_file(prefix+lines[0]+"_"+ob_name+".c",header,1); + } + else write("Directory "+truncate(prefix,1)+" does not exist."); + + if(!AreaMap) AreaMap = ([]); + + if(!AreaMap["i"+lines[0]]) AreaMap["i"+lines[0]] = + ([ prefix+lines[0]+"_"+ob_name+".c" : header ]); + else AreaMap[lines[0]][prefix+lines[0]+"_"+ob_name+".c"] = header; + } + + ///// + // MOBS + ///// + + tmp = implode(RawMap["MOBILES"],"\n"); + prefix = DOMAINS_DIRS+"/"+name+"/npc/"; + mob_arr = explode(tmp,"#"); + foreach(mixed block in mob_arr){ + string *ob_id; + string *lines = explode(block,"\n"); + string short, long, ob_name; + string header = ""; + ok = 0; + ok2 = 0; + if(block && sizeof(lines) > 1){ + ob_id = explode(truncate(lines[1],1)," "); + if(!sizeof(ob_id)) continue; + ob_name = ob_id[0]; + short = truncate(lines[2],1); + long = ""; + for(i=0;i < sizeof(lines);i++){ + int num = i; + if(!ok && sscanf(lines[i],"%d %d %d %s %s",v1,v2,v3,v4,v5) == 5){ + ok =1; + } + if( ok == 1 && sizeof(explode(lines[i]," ")) == 3 && + sscanf(lines[i],"%d %d %d",v2, v3, v4) == 3){ + ok++; + } + if(!ok2 && i > 3){ + if(i > 4 && lines[i] == "~"){ + ok2 = 1; + continue; + } + if(lines[i] != "~") long += lines[i]+" "; + } + } + + header += "#include <lib.h>\n\n"; + header += "inherit LIB_SENTIENT;\n\n"; + header += "static void create(){\n"; + header += " ::create();\n"; + header += " SetKeyName(\""+ob_name+"\");\n"; + header += " SetId( "+identify(ob_id)+" );\n"; + header += " SetShort(\""+short+"\");\n"; + header += " SetLong(\""+long+"\");\n"; + header += " SetLevel("+v1+");\n"; + header += " SetRace(\"human\");\n"; + header += " SetNoCondition(1);\n"; + header += " SetGender(\""+Genders[v4]+"\");\n"; + header += " SetInventory( ([\n"; + header += " ]) );\n"; + + header += "}\nvoid init(){\n::init();\n}\n"; + + mkdir_recurse(truncate(prefix,1)); + if(directory_exists(truncate(prefix,1))){ + write_file(prefix+lines[0]+"_"+ob_name+".c",header,1); + } + else write("Directory "+truncate(prefix,1)+" does not exist."); + + if(!AreaMap) AreaMap = ([]); + + if(!AreaMap["m"+lines[0]]) AreaMap["m"+lines[0]] = + ([ prefix+lines[0]+"_"+ob_name+".c" : header ]); + else AreaMap[lines[0]][prefix+lines[0]+"_"+ob_name+".c"] = header; + } + } + ///// + // ROOMS + ///// + + tmp = implode(RawMap["ROOMS"],"\n"); + prefix = DOMAINS_DIRS+"/"+name+"/room/"; + room_arr = explode(tmp,"#"); + foreach(mixed block in room_arr){ + string *lines = explode(block,"\n"); + string short, long; + string header = "#include <lib.h>\n"; + header += "#include ROOMS_H\n\n"; + header += "inherit LIB_ROOM;\n\n"; + header += "void create() {\n"; + header += " room::create();\n"; + header += " SetClimate(\"indoors\");\n"; + header += " SetAmbientLight(30);\n"; + + + short = truncate(lines[1],1); + long = ""; + for(i=2;i < sizeof(lines);i++){ + if(lines[i] == "~") break; + long += lines[i]+" "; + } + + header += " SetShort(\""+short+"\");\n"; + header += " SetLong(\""+long+"\");\n"; + header += " SetExits( ([\n"; + + for(i=i;i < sizeof(lines);i++){ + int rev = 1; + lock = key = room = direction = 0; + if(lines[i] == "S") break; + if(sscanf(lines[i],"%d %d %s",lock, key, room) == 3){ + while(rev){ + if(!sscanf(lines[((i-rev > -1) ? (i-rev) : 0)],"D%d",direction)) rev++; + else rev = 0; + if(rev > 20) rev = 0; + } + if(!rev){ + if(room == 0){ + gdirection = Directions[direction]; + //continue; + } + else header += " \""+Directions[direction]+"\" : \""+prefix+room+"\",\n"; + } + else if(sizeof(gdirection) > 1){ + if(room != 0) header += " \""+gdirection+"\" : \""+prefix+room+"\",\n"; + gdirection = ""; + } + } + } + + header += " ]) );\n"; + header += " SetInventory( ([\n"; + header += " ]) );\n"; + header += "}\nvoid init(){\n::init();\n}\n"; + + mkdir_recurse(truncate(prefix,1)); + if(directory_exists(truncate(prefix,1))){ + write_file(prefix+lines[0]+".c",header,1); + } + else write("Directory "+truncate(prefix,1)+" does not exist."); + + if(!AreaMap) AreaMap = ([]); + + if(!AreaMap[lines[0]]) AreaMap[lines[0]] = ([ prefix+lines[0]+".c" : header ]); + else AreaMap[lines[0]][prefix+lines[0]+".c"] = header; + } + + return 1; +} + +string GetHelp() { + message("help", "Syntax: cconv <source path> <areaname> <domain name>\n\n" + "Tries to convert a Circle area into a Dead Souls domain.\n" + "Example: cconv /tmp/areadir qq newdomain\n" + "This would try to create /domains/newdomain and convert the area described\n" + "in /tmp/areadir/qq.* into LPC files in the new DS domain." + "\n", this_player()); +} + diff --git a/lib/secure/cmds/admins/chanban.c b/lib/secure/cmds/admins/chanban.c new file mode 100644 index 0000000..4dea7f5 --- /dev/null +++ b/lib/secure/cmds/admins/chanban.c @@ -0,0 +1,39 @@ +// This command is only useful if you own an intermud channel + +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + string chan, mud; + + if(!archp(previous_object())) return 0; + if( !args || args == "" || sscanf(args,"%s %s",chan,mud) != 2) { + return "Huh?"; + } + mud = INTERMUD_D->GetMudName(mud); + if(!mud) return "No such mud."; + + if(member_array(chan,INTERMUD_D->GetChannels()) == -1) + return "No such channel."; + + else INTERMUD_D->eventWrite( ({ "channel-admin", 5, mud_name(), + this_player()->GetKeyName(), INTERMUD_D->GetNameserver(), + 0, chan, ({ mud }), ({}) }) ); + + write("Ban request for "+mud+" from "+chan+" has been sent."); + + return 1; +} + +string GetHelp() { + return ("Syntax: chanban <channel> <mudname>\n\n" + "This submits to the intermud router a request to ban the " + "specified mud from a channel you own. If you do not own " + "the channel you specify, then the router will not honor " + "your request. Use the \"real\" channel name, rather than " + "its local nickname, ie imud_code and not intercre.\n" + "Example: chanban imud_gossip haven\n" + "See also: chanunban, chancreate, chanremove"); +} diff --git a/lib/secure/cmds/admins/chancreate.c b/lib/secure/cmds/admins/chancreate.c new file mode 100644 index 0000000..04f1fa0 --- /dev/null +++ b/lib/secure/cmds/admins/chancreate.c @@ -0,0 +1,50 @@ +// This command is only useful if you own an intermud channel + +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + string chan; + int mode = 0; + + if(!archp(previous_object())) return 0; + write("This command is for creating Intermud-3 channels. "+ + "You almost certainly do not need to use it. If you are "+ + "100% sure you know what you are doing and in fact do need "+ + "to create an Intermud-3 channel, then please edit this "+ + "command to remove this warning and the return that follows it."); + return 1; + if( !args || args == "") return "Huh?"; + if(sscanf(args,"%s %d",chan,mode) != 2) chan = args; + if(mode > 2 || mode < 0) return "Invalid mode."; + + else INTERMUD_D->eventWrite( ({ "channel-add", 5, mud_name(), + this_player()->GetKeyName(), INTERMUD_D->GetNameserver(), + 0, chan, mode }) ); + + load_object("/secure/cmds/creators/update")->cmd("/daemon/intermud"); + + write("Channel creation request sent."); + return 1; +} + +string GetHelp(){ + return ("Syntax: chancreate <name> [0 | 1 | 2]\n\n" + "This submits to the intermud router a request to create an " + "intermud channel by the name you specify with the mode you " + "specify. If an intermud channel by that name already exists, " + "your request will not be honored. Otherwise after a few minutes " + "of updating and broadcasting, your new channel should be " + "available. The mode indicates whether it is an invite-only " + "channel. For example: \nchancreate macrame 1\n" + "would create a channel called macrame that no mud can use " + "until you explicitly allow it. On the other hand," + "\nchancreate dramallamas\n would create a channel any mud " + "can join until you explicitly chanban them. Mode 2, or " + "\"filtered\" mode, is an advanced topic left as an exercise " + "to the reader." + "\nSee also: chanban, chanunban, chanremove, " + "http://www.intermud.org/specs/i3.html"); +} diff --git a/lib/secure/cmds/admins/chanremove.c b/lib/secure/cmds/admins/chanremove.c new file mode 100644 index 0000000..88b49f6 --- /dev/null +++ b/lib/secure/cmds/admins/chanremove.c @@ -0,0 +1,34 @@ +// This command is only useful if you own an intermud channel + +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string chan) { + + if(!archp(previous_object())) return 0; + if( !chan || chan == "") { + return "Huh?"; + } + if(member_array(chan,INTERMUD_D->GetChannels()) == -1) + return "No such channel."; + + else INTERMUD_D->eventWrite( ({ "channel-remove", 5, mud_name(), + this_player()->GetKeyName(), INTERMUD_D->GetNameserver(), + 0, chan }) ); + + load_object("/secure/cmds/creators/update")->cmd("/daemon/intermud"); + + write("Channel removal request sent."); + + return 1; +} + +string GetHelp(){ + return ("Syntax: chanremove <channel>\n\n" + "Submits to the intermud router a request to remove the " + "channel specified. If you do not own the channel, the " + "request will not be honored.\nSee also: " + "chanban, chanunban, chancreate"); +} diff --git a/lib/secure/cmds/admins/chanunban.c b/lib/secure/cmds/admins/chanunban.c new file mode 100644 index 0000000..29869ce --- /dev/null +++ b/lib/secure/cmds/admins/chanunban.c @@ -0,0 +1,39 @@ +// This command is only useful if you own an intermud channel + +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + string chan, mud; + + if(!archp(previous_object())) return 0; + if( !args || args == "" || sscanf(args,"%s %s",chan,mud) != 2) { + return "Huh?"; + } + mud = INTERMUD_D->GetMudName(mud); + if(!mud) return "No such mud."; + + if(member_array(chan,INTERMUD_D->GetChannels()) == -1) + return "No such channel."; + + else INTERMUD_D->eventWrite( ({ "channel-admin", 5, mud_name(), + this_player()->GetKeyName(), INTERMUD_D->GetNameserver(), + 0, chan, ({}), ({ mud }) }) ); + + write("Unban request for "+mud+" from "+chan+" has been sent."); + + return 1; +} + +string GetHelp(){ + return ("Syntax: chanunban <channel> <mudname>\n\n" + "This submits to the intermud router a request to unban the " + "specified mud from a channel you own. If you do not own " + "the channel you specify, then the router will not honor " + "your request. Use the \"real\" channel name, rather than " + "its local nickname, ie imud_code and not intercre.\n" + "Example: chanunban imud_gossip nanvaent\n" + "See also: chanban, chancreate, chanremove"); +} diff --git a/lib/secure/cmds/admins/cwgconv.c b/lib/secure/cmds/admins/cwgconv.c new file mode 100644 index 0000000..6e2a0a2 --- /dev/null +++ b/lib/secure/cmds/admins/cwgconv.c @@ -0,0 +1,352 @@ +#include <lib.h> +#include <dirs.h> +#include <vendor_types.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +string original, digested; +mapping AreaMap = ([]); +mapping RawMap = ([]); +string array source_dirs = ({ "zon", "mob", "obj", "shp", "trg", "wld", "gld" }); +mapping Genders = ([ 0 : "neutral", 1 : "male", 2 : "female" ]); +mapping Directions = ([ 0 : "north", 1 : "east", 2 : "south", + 3 : "west", 4 : "up", 5 : "down", 6 : "northwest", 7 : "northeast", + 8 : "southeast", 9 : "southwest", 10 : "in", 11 : "out" ]); +mapping Types = ([ 1 : "LIB_ITEM", 2 : "LIB_ITEM", 3 : "LIB_ITEM", 4 : "LIB_ITEM", + 5 : "LIB_ITEM", 6 : "LIB_ITEM", 7 : "LIB_ITEM", 8 : "LIB_ITEM", 9 : "LIB_ARMOR", 10 : "LIB_POTION", + 11 : "LIB_ITEM", 12 : "LIB_ITEM", 13 : "LIB_ITEM", 14 : "LIB_ITEM", 15 : "LIB_STORAGE", + 16 : "LIB_ITEM", 17 : "LIB_MEAL", 18 : "LIB_ITEM", 19 : "LIB_MEAL", 20 : "LIB_PILE", + 21 : "LIB_ITEM", 22 : "LIB_ITEM", 23 : "LIB_ITEM", 24 : "LIB_ITEM", 25 : "LIB_ITEM", + 26 : "LIB_ITEM", 44 : "LIB_ITEM" ]); +string gdirection, cle, val; +int item_type; +mixed com,v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13; +int weight, cost, material,ok,ok2; +int lock, key, room, direction; + +mapping ObjectType = ([ + "zon" : "ZONE", + "obj" : "OBJECTS", + "mob" : "MOBILES", + "wld" : "ROOMS", + ]); + +mixed cmd(string args){ + if(args == "clear"){ + write("Resetting the converter variables."); + RELOAD_D->eventReload(this_object(),0); + return 1; + } + if(grepp(args,"-r ")){ + args = replace_string(args,"-r ",""); + return this_object()->Report(args); + } + return this_object()->ConvertArea(args); +} + +string clean_string(string str){ + str = replace_string(str,"\"","\'",); + return str; +} + +varargs mixed QueryMaps(string which, string what){ + if(!which || !what){ + write("AreaMap: "+(AreaMap ? identify(keys(AreaMap)) : "0")); + write("RawMap: "+(AreaMap ? identify(keys(AreaMap)) : "0")); + return 1; + } + if(which == "area"){ + if(AreaMap && AreaMap[what]) return identify(AreaMap[what]); + else return "No such element."; + } + if(which == "raw"){ + if(RawMap && RawMap[what]) return identify(RawMap[what]); + else return "No such element."; + } + return "IDK."; +} + +int Report(string str){ + print_long_string(this_player(),"vnums: "+item_list(keys(AreaMap)),1); + if(str == "both" || str == "area") print_long_string(this_player(),"%^RED%^AreaMap: "+identify(AreaMap),1); + if(str == "both" || str == "raw") print_long_string(this_player(),"%^GREEN%^RAWMap: "+identify(RawMap),1); + if(sscanf(str,"%*d")) this_object()->DisplayVnum(str); + return 1; +} + +int DisplayVnum(string str){ + if(!str || !AreaMap[str]){ + write("No such vnum in this area."); + return 1; + } + print_long_string(this_player(),"vnum "+str+":\n"+identify(AreaMap[str]),1); + return 1; +} + +int ConvertArea(string arg){ + string area, tmp, str, name, prefix; + int i; + string *room_arr; + string *mob_arr; + string *obj_arr; + string *segmented = ({}); + + if(!arg || sscanf(arg,"%s %s %s",str, area, name) != 3){ + write("convert PATH AREA NAME"); + return 1; + } + + if(!str || !directory_exists(str)){ + write("No such area directory exists."); + return 1; + } + + if(directory_exists(DOMAINS_DIRS+"/"+name)){ + write("That domain already exists. Backing up the current domain to a unique name."); + rename(DOMAINS_DIRS+"/"+name, DOMAINS_DIRS+"/"+name+"."+time()); + } + + foreach(string elemento in source_dirs){ + string path = str+"/"+elemento+"/"+area+"."+elemento; + if(!file_exists(path)){ + write(path+" does not exist. Skipping."); + continue; + } + + original = read_file(path); + digested = clean_string(original); + + segmented = explode(digested,"\n"); + if(!RawMap) RawMap = ([]); + RawMap[ObjectType[elemento]]= segmented[0..]; + } + + + ///// + // ITEMS + ///// + + tmp = implode(RawMap["OBJECTS"],"\n"); + prefix = DOMAINS_DIRS+"/"+name+"/obj/"; + obj_arr = explode(tmp,"#"); + foreach(mixed block in obj_arr){ + string *ob_id; + string *lines = explode(block,"\n"); + string short, long, ob_name; + string header = ""; + if(block && sizeof(lines) > 1){ + ob_id = explode(truncate(lines[1],1)," "); + if(!sizeof(ob_id)) continue; + ob_name = ob_id[0]; + short = truncate(lines[2],1); + long = ""; + for(i=2;i < sizeof(lines);i++){ + int num = i; + if(sscanf(lines[i],"%d %s %s %s %s %s %s %s %s %s %s %s %s", + v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13) == 13) { + item_type = v1; + continue; + } + if(sscanf(lines[i],"%d %d %d %d %d %d %d %d",v1,v2,v3,v4,v5, + v6,v7,v8) == 8){ + material = v8; + continue; + + } + if(sscanf(lines[i],"%d %d %d %d",v1,v2,v3,v4) == 4){ + weight = v1; + cost = v2; + continue; + } + + if(lines[i] == "E"){ + for(num = i+2; num < sizeof(lines);num++){ + if(lines[num] == "~") break; + long += lines[num]+" "; + } + break; + } + } + } + + header += "#include <lib.h>\n\n"; + header += "inherit "+(Types[item_type] || "LIB_ITEM")+";\n\n"; + header += "static void create() {\n"; + header += " ::create();\n"; + header += " SetKeyName(\""+ob_name+"\");\n"; + header += " SetId( "+identify(ob_id)+" );\n"; + header += " SetShort(\""+short+"\");\n"; + header += " SetLong(\""+long+"\");\n"; + header += " SetMass("+(weight*10)+");\n"; + header += " SetBaseCost("+cost+");\n"; + if (Types[item_type] == "LIB_STORAGE") { + header += " SetInventory( ([\n"; + header += " ]) );\n"; + } + header += "}\nvoid init(){\n::init();\n}\n"; + + mkdir_recurse(truncate(prefix,1)); + if(directory_exists(truncate(prefix,1))){ + write_file(prefix+lines[0]+"_"+ob_name+".c",header,1); + } + else write("Directory "+truncate(prefix,1)+" does not exist."); + + if(!AreaMap) AreaMap = ([]); + + if(!AreaMap["i"+lines[0]]) AreaMap["i"+lines[0]] = + ([ prefix+lines[0]+"_"+ob_name+".c" : header ]); + else AreaMap[lines[0]][prefix+lines[0]+"_"+ob_name+".c"] = header; + } + + ///// + // MOBS + ///// + + tmp = implode(RawMap["MOBILES"],"\n"); + prefix = DOMAINS_DIRS+"/"+name+"/npc/"; + mob_arr = explode(tmp,"#"); + foreach(mixed block in mob_arr){ + string *ob_id; + string *lines = explode(block,"\n"); + string short, long, ob_name; + string header = ""; + ok = 0; + ok2 = 0; + if(block && sizeof(lines) > 1){ + ob_id = explode(truncate(lines[1],1)," "); + if(!sizeof(ob_id)) continue; + ob_name = ob_id[0]; + short = truncate(lines[2],1); + long = ""; + for(i=0;i < sizeof(lines);i++){ + int num = i; + if(!ok && sscanf(lines[i],"%d %d %d %s %s",v1,v2,v3,v4,v5) == 5){ + ok =1; + } + if( ok == 1 && sizeof(explode(lines[i]," ")) == 3 && + sscanf(lines[i],"%d %d %d",v2, v3, v4) == 3){ + ok++; + } + if(!ok2 && i > 3){ + if(i > 4 && lines[i] == "~"){ + ok2 = 1; + continue; + } + if(lines[i] != "~") long += lines[i]+" "; + } + } + + header += "#include <lib.h>\n\n"; + header += "inherit LIB_SENTIENT;\n\n"; + header += "static void create(){\n"; + header += " ::create();\n"; + header += " SetKeyName(\""+ob_name+"\");\n"; + header += " SetId( "+identify(ob_id)+" );\n"; + header += " SetShort(\""+short+"\");\n"; + header += " SetLong(\""+long+"\");\n"; + header += " SetLevel("+v1+");\n"; + header += " SetRace(\"human\");\n"; + header += " SetNoCondition(1);\n"; + header += " SetGender(\""+Genders[v4]+"\");\n"; + header += " SetInventory( ([\n"; + header += " ]) );\n"; + + header += "}\nvoid init(){\n::init();\n}\n"; + + mkdir_recurse(truncate(prefix,1)); + if(directory_exists(truncate(prefix,1))){ + write_file(prefix+lines[0]+"_"+ob_name+".c",header,1); + } + else write("Directory "+truncate(prefix,1)+" does not exist."); + + if(!AreaMap) AreaMap = ([]); + + if(!AreaMap["m"+lines[0]]) AreaMap["m"+lines[0]] = + ([ prefix+lines[0]+"_"+ob_name+".c" : header ]); + else AreaMap[lines[0]][prefix+lines[0]+"_"+ob_name+".c"] = header; + } + } + ///// + // ROOMS + ///// + + tmp = implode(RawMap["ROOMS"],"\n"); + prefix = DOMAINS_DIRS+"/"+name+"/room/"; + room_arr = explode(tmp,"#"); + foreach(mixed block in room_arr){ + string *lines = explode(block,"\n"); + string short, long; + string header = "#include <lib.h>\n"; + header += "#include ROOMS_H\n\n"; + header += "inherit LIB_ROOM;\n\n"; + header += "void create() {\n"; + header += " room::create();\n"; + header += " SetClimate(\"indoors\");\n"; + header += " SetAmbientLight(30);\n"; + + + short = truncate(lines[1],1); + long = ""; + for(i=2;i < sizeof(lines);i++){ + if(lines[i] == "~") break; + long += lines[i]+" "; + } + + header += " SetShort(\""+short+"\");\n"; + header += " SetLong(\""+long+"\");\n"; + header += " SetExits( ([\n"; + + for(i=i;i < sizeof(lines);i++){ + int rev = 1; + lock = key = room = direction = 0; + if(lines[i] == "S") break; + if(sscanf(lines[i],"%d %d %d",lock, key, room) == 3){ + while(rev){ + if(!sscanf(lines[((i-rev > -1) ? (i-rev) : 0)],"D%d",direction)) rev++; + else rev = 0; + if(rev > 20) rev = 0; + } + if(!rev){ + if(room == 0){ + gdirection = Directions[direction]; + //continue; + } + else header += " \""+Directions[direction]+"\" : \""+prefix+room+"\",\n"; + } + else if(sizeof(gdirection) > 1){ + if(room != 0) header += " \""+gdirection+"\" : \""+prefix+room+"\",\n"; + gdirection = ""; + } + } + } + + header += " ]) );\n"; + header += " SetInventory( ([\n"; + header += " ]) );\n"; + header += "}\nvoid init(){\n::init();\n}\n"; + + mkdir_recurse(truncate(prefix,1)); + if(directory_exists(truncate(prefix,1))){ + write_file(prefix+lines[0]+".c",header,1); + } + else write("Directory "+truncate(prefix,1)+" does not exist."); + + if(!AreaMap) AreaMap = ([]); + + if(!AreaMap[lines[0]]) AreaMap[lines[0]] = ([ prefix+lines[0]+".c" : header ]); + else AreaMap[lines[0]][prefix+lines[0]+".c"] = header; + } + + return 1; +} + +string GetHelp() { + message("help", "Syntax: cwgconv <source path> <areaname> <domain name>\n\n" + "Tries to convert a CWG area into a Dead Souls domain.\n" + "Example: cconv /tmp/areadir 3 newdomain\n" + "This would try to create /domains/newdomain and convert the area described\n" + "in /tmp/areadir/3 into LPC files in the new DS domain." + "\n", this_player()); +} + diff --git a/lib/secure/cmds/admins/decre.c b/lib/secure/cmds/admins/decre.c new file mode 100644 index 0000000..ce630e3 --- /dev/null +++ b/lib/secure/cmds/admins/decre.c @@ -0,0 +1,137 @@ +/* /secure/cmds/adm/decre.c + * from the Dead Souls LPC Library + * turns a creator into a player + * created by Descartes of Borg 950323 + */ + +#include <lib.h> +#include <privs.h> +#include ROOMS_H +#include <daemons.h> + +inherit LIB_DAEMON; + +string home_dir, PlayerName; +object ob, player_ob; + +mixed cmd(string args) { + object *inv, *purge_array; + string nom, file; + + if( !(master()->valid_apply(({ PRIV_ASSIST, PRIV_SECURE, LIB_CONNECT }))) ) + error("Illegal decre attempt: "+get_stack()+" "+identify(previous_object(-1))); + + ob = 0; + player_ob = 0; + + if( args == "" || !stringp(args) ) + return "Who do you want to make a player?"; + nom = convert_name(args); + if( !user_exists(nom) ) return capitalize(nom) + " is not a member of " + + possessive_noun(mud_name()) + " reality."; + WEB_SESSIONS_D->EndSession(lower_case(nom)); + if( !strsrch(file = player_save_file(nom), DIR_PLAYERS) ) + return "You cannot make "+capitalize(args)+" a player."; + + if(!ob = find_player(nom)){ + if(nom == this_player()->GetKeyName()){ + return "I've no idea how you've managed this, but \"no\"."; + } + PLAYERS_D->RemovePendingEncre(lower_case(nom)); + PLAYERS_D->AddPendingDecre(lower_case(nom)); + write(capitalize(nom)+" will be demoted on their next login."); + return 1; + } + else { + mixed attrape; + if(ob == this_player() || securep(ob)){ + return "Nonsense."; + } + home_dir = homedir(ob); + write("You decre "+capitalize(nom)+"."); + PlayerName = nom; + + //Try to remove inventory and move the guy to the pod + // + ob->eventMove(ROOM_POD); + inv = deep_inventory(ob); + if(sizeof(inv)) + foreach(object thing in inv){ + if(thing) { + thing->eventMove(ROOM_FURNACE); + } + } //Save the user to sync its state with his inventory + unguarded( (: ob->save_player(ob->GetKeyName()) :) ); + + //Move the user file to the player dir + // + if( file_size(DIR_PLAYERS+"/"+nom[0..0]) != -2) + mkdir(DIR_PLAYERS+"/"+nom[0..0]); + if(rename(file, save_file(DIR_PLAYERS+"/"+nom[0..0]+"/"+nom))) + return "You failed due to lack of write access to "+DIR_PLAYERS+"."; + //Remove their homedir, save it to a backup dir. + if(home_dir && directory_exists(home_dir)) + rename(home_dir,"/secure/save/decre/"+nom+"."+timestamp()); + //Remove their name from the creator list in the player daemon, add it to the player list. + PLAYERS_D->eventDecre(lower_case(nom)); + + //Try to create the new player object + // + attrape = catch(player_ob = (object)master()->player_object(nom)); + PlayerName = 0; + if( attrape || !player_ob ) { + message("system", "\nFailed to create a player object.", + this_player()); + message("system", "Please log out and log back in.", ob); + return 1; + } + + //Do the decre + // + exec(player_ob, ob); + player_ob->Setup(); + + //Remove creator channels and such + // + foreach(string channel in player_ob->GetChannels()) + player_ob->RemoveChannel(channel); + if( avatarp(player_ob) ) player_ob->AddChannel(({ "avatar" })); + if( high_mortalp(player_ob) ) player_ob->AddChannel( ({ "hm" }) ); + if( newbiep(player_ob) ) player_ob->AddChannel( ({ "newbie" }) ); + player_ob->AddChannel( ({ "gossip" }) ); + if( councilp(player_ob) ) player_ob->AddChannel( ({ "council" }) ); + player_ob->AddChannel(player_ob->GetClass()); + + //Destroy any objects loaded from their homedir + // + purge_array = filter(objects(), (: !strsrch(base_name($1), home_dir) :) ); + foreach(object tainted in purge_array){ + if(clonep(tainted)){ + tainted->eventMove(ROOM_FURNACE); + purge_array -= ({ tainted }); + } + } + foreach(object tainted in purge_array){ + tainted->eventDestruct(); + } + } + call_out( (: ob->eventMove(ROOM_FURNACE) :), 1 ); + player_ob->eventMoveLiving(ROOM_START); + player_ob->SetLoginSite(ROOM_START); + unguarded( (: player_ob->save_player(player_ob->GetKeyName()) :) ); + message("system", "You are now a player.", player_ob); + message("system", player_ob->GetName() + " is now a player!", + this_player()); + return 1; +} + +string GetKeyName() { return PlayerName; } + +string GetHelp(){ + return ("Syntax: decre <person>\n\n" + "Demotes the specified creator to player status. " + "If the target is not " + "logged in, they will be made a player when " + "they next log in.\n" + "See also: encre, rid"); +} diff --git a/lib/secure/cmds/admins/doctool.c b/lib/secure/cmds/admins/doctool.c new file mode 100644 index 0000000..c01ab71 --- /dev/null +++ b/lib/secure/cmds/admins/doctool.c @@ -0,0 +1,180 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; +string doctype, funcname, doc, path; +string *valid_docs = ({"lfun","sefun"}); +string *doc_array = ({}); +string *headers = ({ "NAME", "SYNOPSIS", "DESCRIPTION", "EXAMPLES", "LOCATION", "SEE ALSO", "Author" }); +mapping ContentMap = ([]); +string *headers_left = ({}); +string *sourcefiles = ({}); + +string eventFindInstances(){ + string *raw_list = load_object("/secure/cmds/admins/files")->cmd("-c "+"/lib/"); + string cooked_list = ""; + sourcefiles = ({}); + foreach(string file in raw_list){ + string funex; + if(last(file, 2) != ".c") continue; + if(grepp(load_object("/secure/cmds/creators/showfuns")->cmd(file), funcname)){ + funex = function_exists(funcname,load_object(file),1); + if(funex && !grepp(cooked_list,funex+"\n")){ + sourcefiles += ({ last_string_element(funex,"/") }); + cooked_list += funex+"\n"; + } + } + } + return cooked_list; +} + +int eventWriteDoc(){ + string ret = upper_case(funcname)+"\n\n"; + foreach(string header in headers){ + ret += header + "\n "; + ret += replace_string(replace_string(ContentMap[header],"\n\n","\n")," ","") + "\n\n"; + } + ret = replace_string(ret,"\n\n\n","\n\n"); + if(doctype == "lfun"){ + string tmp_path; + foreach(string sourcefl in sourcefiles){ + tmp_path = "/doc/lfun/lib/"+sourcefl; + if(!directory_exists(tmp_path)) mkdir(tmp_path); + tmp_path += "/"+funcname; + write_file(tmp_path, ret,1); + } + } + + write("%^GREEN%^output: "+ret+"%^RESET%^"); + write_file(path, ret,1); + doc_array = ({}); + headers_left = ({}); + sourcefiles = ({}); + return 1; +} + +varargs int eventSetSection(string content, string header){ + string tmpstr = " "; + if(content == "Author" || (header == "Author" && (!content || content == ""))) + tmpstr = this_player()->GetName(); + if(sizeof(headers_left)){ + if(!content || member_array(content, headers) != -1){ + if(!header) header = content; + if(!sizeof(ContentMap[header])) ContentMap[header] = tmpstr; + if(doctype == "lfun" && header == "LOCATION"){ + headers_left -= ({ "LOCATION "}); + } + this_object()->eventManageQueries(); + return 1; + } + } + if(content && content != "") ContentMap[header] = content; + else if(!sizeof(ContentMap[header])) ContentMap[header] = tmpstr; + if(doctype == "lfun" && header == "LOCATION"){ + headers_left -= ({ "LOCATION "}); + } + this_object()->eventManageQueries(); + return 1; +} + +int eventQueryEntry(string header){ + write("Please enter the "+header+" data for "+funcname+"(): "); + input_to( (: eventSetSection :) , header); + return 1; +} + +int eventManageQueries(){ + if(doctype == "lfun" && sizeof(headers_left) && + headers_left[0] == "LOCATION" && member_array("LOCATION",headers_left) != -1){ + call_out( (: eventSetSection, eventFindInstances(), "LOCATION" :), 1); + if(sizeof(headers_left)) headers_left -= ({ headers_left[0] }); + return 1; + } + else if(sizeof(headers_left)){ + eventQueryEntry(headers_left[0]); + headers_left -= ({ headers_left[0] }); + return 1; + } + if(!sizeof(headers_left) && sizeof(ContentMap["Author"])){ + eventWriteDoc(); + } + return 1; +} + +mixed cmd(string args) { + int x; + headers_left = ({}); + ContentMap = ([]); + doc_array = ({}); + + + if(!archp(previous_object())) return 0; + + if(!args || args == ""){ + write("You'll need to be more specific. Try: help doctool"); + return 1; + } + + if(sscanf(args,"%s %s",doctype, funcname) != 2){ + write("This commands takes two arguments. For example:\n" + "doctool lfun GetFunky\n" + "would begin a doctool session for the library (aka local) function \"GetFunky\"."); + return 1; + } + + funcname = replace_string(funcname, " ", ""); + if(grepp(funcname,"/")) funcname = last_string_element(funcname, "/"); + write("Document type: "+doctype); + write("Function name: "+funcname); + + if(member_array(doctype, valid_docs) == -1){ + write("That is an unknown document type. Try " + "one of the following: "+implode(valid_docs, ", ")+"."); + return 1; + } + + path = "/doc/"+doctype; + if(!directory_exists(path)) mkdir(path); + if(doctype == "lfun"){ + path += "/all"; + if(!directory_exists(path)) mkdir(path); + } + + path += "/"+funcname; + + if(file_exists(path)) doc = read_file(path); + else doc = "TEMPLATE"; + + //write(doc); + + doc_array = explode(doc,"\n"); + + foreach(string header in headers){ + int i, includer = 0; + string tmp_str = ""; + for(i = 0;i < (sizeof(doc_array)-1); i++){ + if(member_array(doc_array[i],headers) != -1) includer = 0; + if(includer) tmp_str += doc_array[i]+"\n"; + if(doc_array[i] == header) includer = 1; + } + eventSetSection(tmp_str, header); + write(header+": \n"+tmp_str); + } + + headers_left = headers; + eventManageQueries(); + return 1; +} + +string GetHelp(){ + return ("Syntax: doctool [doctype] FUNCTION_NAME\n\n" + "Assists in creating sefun and lfun documentation.\n" + "Because it automatically scans many files and performs \n" + "operations on them, this command may seriously lag the \n" + "mud it is run on. It should therefore be used only when \n" + "substantial occasional lag is acceptable." + "\n\n" + "It is not unusual for this command to error out on \"Too long " + "evaluation\" the first few times you run it.\n" + "See also: man, help"); +} diff --git a/lib/secure/cmds/admins/domainadmin.c b/lib/secure/cmds/admins/domainadmin.c new file mode 100644 index 0000000..01c19e4 --- /dev/null +++ b/lib/secure/cmds/admins/domainadmin.c @@ -0,0 +1,114 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + string rep, flag, domain, person; + string write_perms = read_file("/secure/cfg/write.cfg"); + string *tmp_array = explode(write_perms, "\n"); + string *admin_array = ({}); + mapping DomainsMap = ([]); + + + if(!archp(previous_object()) || this_player()->GetForced()){ + return "No."; + } + + if(!args || args == ""){ + write(this_object()->GetHelp()); + return 1; + } + + if(sscanf(args,"%s %s %s", flag, domain, person) != 3){ + write(this_object()->GetHelp()); + return 1; + } + + person = lower_case(person); + + if(!user_exists(person)){ + write("Invalid person."); + return 1; + } + + if(!directory_exists("/domains/"+domain)){ + write("Invalid domain."); + return 1; + } + + write_perms = replace_string(write_perms, "\n",";\n"); + + foreach(string line in tmp_array){ + string where, admins; + if(sscanf(line,"(/domains/%s/) %s", where, admins)){ + DomainsMap[where] = admins; + if(sizeof(DomainsMap[domain])) admin_array = explode(DomainsMap[domain],":"); + } + } + + if(flag == "-a"){ + + if(member_array(person, admin_array) != -1){ + write("That person already administers that domain."); + return 1; + } + + else admin_array += ({ person }); + + rep = "(/domains/"+domain+"/) "+implode(admin_array, ":"); + + if(grepp(write_perms, "(/domains/"+domain+"/)")){ + write_perms = replace_matching_line(write_perms, "/domains/"+domain, rep); + write_perms = replace_string(write_perms, ";\n","\n"); + } + else{ + write_perms = replace_string(write_perms, ";\n","\n"); + write_perms = newline_trim(write_perms); + write_perms += "\n(/domains/"+domain+"/) "+person+"\n"; + } + } + + else if(flag == "-d"){ + if(member_array(person, admin_array) == -1){ + write("That person does not administer that domain."); + return 1; + } + + else admin_array -= ({ person }); + + if(!sizeof(admin_array)){ + write_perms = remove_matching_line(write_perms, "(/domains/"+domain+"/)",1); + write_perms = replace_string(write_perms, ";\n","\n"); + } + else { + rep = "(/domains/"+domain+"/) "+implode(admin_array, ":"); + write_perms = replace_matching_line(write_perms, "/domains/"+domain, rep); + write_perms = replace_string(write_perms, ";\n","\n"); + } + } + + else { + write("Invalid flag."); + return 1; + } + + write_file("/secure/cfg/write.cfg", write_perms, 1); + update("/secure/daemon/master"); + write("Ok."); + return 1; +} + +string GetHelp(string args) { + return ("Syntax: domainadmin [-a | -d] <domain> <person>\n\n" + "This command manages the write permissions to a specified " + "domain. For example, to give a creator named Snuffy write " + "privileges to /domains/SnuffLand, you would type: " + "\ndomainadmin -a SnuffLand snuffy\n" + "To revoke those privileges:\n" + "\domainadmin -d SnuffLand snuffy\n" + "This permits the creator to use QCS within the domain's " + "directories. " + "Write privileges are listed in /secure/cfg/write.cfg\n" + "See also: domaincreate, admintool"); +} diff --git a/lib/secure/cmds/admins/domaincreate.c b/lib/secure/cmds/admins/domaincreate.c new file mode 100644 index 0000000..eb28fcb --- /dev/null +++ b/lib/secure/cmds/admins/domaincreate.c @@ -0,0 +1,77 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; +string gfilecont; + +mixed cmd(string args) { + string domain_path; + string *subdirs = ({"save","room","weap","armor","npc","etc","adm","doors","meals","obj","virtual/void", "chamber", "vehicle"}); + string *alphabet = ({",", "#", ";", "^", "&", "(", ")","\"","\'","\`","?", " " }); + subdirs += ({"txt","virtual"}); + alphabet += ({ "@", "!", "$", "%", "=", "{", "}", "[", "]", ":", "<", ">", "\*" }); + alphabet += ({ "\\", "\/", "\|" }); + + if(!archp(previous_object()) || this_player()->GetForced()){ + return "No."; + } + + if(!args || args == "" || args == "/domains" || args == "/domains/" || + args == "domain"){ + write(this_object()->GetHelp()); + return 1; + } + + if(first(args, 9) == "/domains/"){ + domain_path = args; + } + else domain_path = "/domains/"+args; + + if(sscanf(domain_path,"/domains/%s",args) != 1) return 0; + if(last(args,1) == "/") args = truncate(args,1); + + foreach(string booboo in alphabet){ + args = replace_string(args, booboo, "_"); + } + + domain_path = "/domains/"+args; + + write("Domain path is: "+domain_path); + + if(directory_exists(domain_path)){ + write("That domain already exists."); + return 1; + } + + mkdir_recurse(domain_path); + + foreach(string dir in subdirs){ + string newdir = domain_path + "/" + dir; + write("Creating: "+newdir); + mkdir_recurse(newdir); + } + + cp("/obj/room.c",domain_path+"/room/start.c"); + cp("/std/death.c",domain_path+"/room/death.c"); + cp("/std/void.c",domain_path+"/room/void.c"); + cp("/std/pod.c",domain_path+"/room/pod.c"); + cp("/std/freezer.c",domain_path+"/room/freezer.c"); + cp("/std/furnace.c",domain_path+"/room/furnace.c"); + cp("/std/wiz_hall.c",domain_path+"/room/wiz_hall.c"); + gfilecont = read_file("/std/server.txt"); + gfilecont = replace_string(gfilecont,"CHANGEME",args); + write_file(domain_path+"/virtual/server.c",gfilecont,1); + gfilecont = read_file("/std/virtual_void.txt"); + gfilecont = replace_string(gfilecont,"CHANGEME",args); + write_file(domain_path+"/virtual/void.c",gfilecont,1); + + write("Ok."); + return 1; +} + +string GetHelp(string args) { + return ("Syntax: domaincreate <domainname>\n\n" + "This command creates a new directory in the /domains dir, " + "and adds the appropriate subdirs needed by a domain.\n" + "See also: domainadmin, admintool"); +} diff --git a/lib/secure/cmds/admins/encre.c b/lib/secure/cmds/admins/encre.c new file mode 100644 index 0000000..56ca4f3 --- /dev/null +++ b/lib/secure/cmds/admins/encre.c @@ -0,0 +1,120 @@ +/* /secure/cmd * from the Dead Souls LPC Library + * turns a player into a creator + * created by Descartes of Borg 950322 + */ + +#include <lib.h> +#include <privs.h> +#include <daemons.h> +#include ROOMS_H + +inherit LIB_DAEMON; + +string PlayerName; + +mixed cmd(string args) { + object ob, cre_ob, jeans, shirt, robe, hat, book, staff; + string filec, filep, nom, home_dir; + filep = player_save_file(args); + filec = replace_string(filep, "players", "creators"); + + if( !(master()->valid_apply(({ PRIV_ASSIST, PRIV_SECURE, LIB_CONNECT }))) ) + error("Illegal encre attempt: "+get_stack()+" "+identify(previous_object(-1))); + + if( args == "" || !stringp(args) ) + return "Who do you want to make a creator?"; + nom = convert_name(args); + if( !user_exists(nom) ) return capitalize(nom) + " is not a member of " + + possessive_noun(mud_name()) + " reality."; + if( !strsrch(filep, DIR_CRES) ) + return "You cannot make "+capitalize(args)+" a creator."; + + if(!ob=find_player(nom)){ + if(member_array(nom, PLAYERS_D->GetPendingEncres()) != -1){ + write("That person is already pending creatorship."); + return 1; + } + PLAYERS_D->RemovePendingDecre(lower_case(nom)); + PLAYERS_D->AddPendingEncre(lower_case(nom)); + write(capitalize(nom)+" will be a creator next time they log in."); + return 1; + } + if( file_size(DIR_CRES+"/"+nom[0..0]) != -2) mkdir(DIR_CRES+"/"+nom[0..0]); + if(rename(filep, filec)) + return "You failed due to lack of write access to "+DIR_CRES+"."; + PLAYERS_D->eventCre(lower_case(nom)); + if( ob = find_player(nom) ) { + home_dir = homedir(ob); + ob->SetProperty("brand_spanking_new",0); + PlayerName = nom; + catch(cre_ob = (object)master()->player_object(nom)); + PlayerName = 0; + if( !cre_ob ) { + message("system", "Failed to create a cre object.", this_player()); + message("system", "Please log out and log back in.", ob); + return 1; + } + exec(cre_ob, ob); + cre_ob->SetProperty("brand_spanking_new",0); + cre_ob->Setup(); + if(cre_ob->GetTeloptIp() && !cre_ob->GetCharmode()){ + int oldlock = cre_ob->GetProperty("screenlock"); + cre_ob->SetCharmode(1); + cre_ob->SetProperty("reprompt",1); + cre_ob->SetProperty("keepalive", 5); + cre_ob->SetProperty("screenlock", 0); + cre_ob->SetScreen(80, 25); + cre_ob->SetProperty("screenlock", oldlock); + } + ob->eventDestruct(); + message("system", "You are now a creator.", cre_ob); + message("shout", cre_ob->GetName() + " is now a creator!", + users(), ({ this_player(), cre_ob })); + if(file_exists(filep)) rm(filep); + make_workroom(cre_ob, 1); + if(directory_exists(home_dir)){ + string new_dir = homedir(cre_ob,1)+"/estate"; + if(strsrch(new_dir, home_dir)){ + rename(home_dir, new_dir); + } + } + cre_ob->eventForce("home"); + cre_ob->eventForce("cd"); + cre_ob->SetPrompt("cwd"); + if(!(cre_ob->GetProperty("screen reader"))){ + cre_ob->SetProperty("wizmapping",1); + } + cre_ob->SetProperty("minimapping",0); + jeans = present("jeans",cre_ob); + shirt = present("t-shirt",cre_ob); + if(jeans) jeans->eventMove(ROOM_FURNACE); + if(shirt) shirt->eventMove(ROOM_FURNACE); + robe = new("/domains/default/armor/robe"); + if(robe) robe->eventMove(cre_ob); + hat = new("/domains/default/armor/wizard_hat"); + if(hat) hat->eventMove(cre_ob); + robe = present("robe",cre_ob); + if(robe) cre_ob->eventForce("wear robe"); + hat = present("wizard hat",cre_ob); + if(hat) cre_ob->eventForce("wear wizard hat"); + staff = new("/secure/obj/staff"); + if(staff) staff->eventMove(cre_ob); + book = new("/domains/default/obj/manual"); + if(book && !present("manual",cre_ob)) book->eventMove(cre_ob); + else if(book) book->eventMove(ROOM_FURNACE); + cre_ob->AddChannel(({"cre", "newbie", "gossip", "ds", "ds_test", "lpuni", "death", "connections","intercre","dchat" })); + cre_ob->SetPolyglot(1); + cre_ob->save_player(cre_ob->GetKeyName()); + } + return 1; +} + +string GetKeyName() { return PlayerName; } + +string GetHelp() { + return ("Syntax: encre <person>\n\n" + "Makes the target a creator. If the target is not " + "logged in, they will be made a creator when " + "they next log in.\n" + "See also: decre, rid"); +} diff --git a/lib/secure/cmds/admins/end.c b/lib/secure/cmds/admins/end.c new file mode 100644 index 0000000..573dac2 --- /dev/null +++ b/lib/secure/cmds/admins/end.c @@ -0,0 +1,30 @@ +/* /secure/cmds/adm/end.c + * from the Dead Souls LPC Library + * the command to reboot the MUD + * created by Descartes of Borg 950526 + */ + +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + int x; + + if(!archp(previous_object())) return 0; + if( !args || args == "" ) return "You must specify a delay in minutes."; + if( !(x = to_int(args)) ) return "You must specify a delay in minutes."; + if( x < 2 ) return "The delay must be at least 2 minutes."; + EVENTS_D->eventReboot(x); + message("system", "Reboot sequence initiated.", this_player()); + return 1; +} + +string GetHelp() { + return ("Syntax: end [delay]\n\n" + "Initiates a reboot sequence which will end in a reboot after " + "the specified delay period. The delay must be specified in " + "minutes and it must be of at least two minutes.\n" + "See also: nextreboot, setreboot, shutdown"); +} diff --git a/lib/secure/cmds/admins/files.c b/lib/secure/cmds/admins/files.c new file mode 100644 index 0000000..456ec11 --- /dev/null +++ b/lib/secure/cmds/admins/files.c @@ -0,0 +1,63 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; +string tmp; + +mixed cmd(string args) { + int x,c; + string *filenames; + string *ret_arr; + + if( !(master()->valid_apply(({ "ASSIST" }))) && + base_name(previous_object()) != "/secure/cmds/creators/findfun" && + base_name(previous_object()) != "/secure/cmds/creators/showfuns" ) + error("Illegal attempt to access file command: "+ + get_stack()+" "+identify(previous_object(-1))); + + if(args){ + if(grepp(args,"-x ")){ + args = replace_string(args,"-x ",""); + x = 1; + tmp = args; + } + if(grepp(args,"-c ")){ + args = replace_string(args,"-c ",""); + c = 1; + tmp = args; + } + } + + write("Number of directories: "+sizeof(FILE_D->GetDirs())); + filenames = FILE_D->GetFiles(); + write("Number of files: "+sizeof(filenames)); + if(!args || args == "") return 1; + if(!strsrch(args,"-x ")){ + args = replace_string(args,"-x ",""); + x = 1; + tmp = args; + } + ret_arr = regexp(filenames, args); + if(x) ret_arr = filter(ret_arr, (: !strsrch($1, tmp) :) ); + if(interactive(previous_object())){ + if(sizeof(implode(ret_arr,"\n"))) print_long_string(this_player(),implode(ret_arr,"\n")); + else write("Too many matches."); + return 1; + } + else return ret_arr; +} + +string GetHelp() { + return ("Syntax: files [-x] [-c] [SUBSTRING]\n\n" + "With no arguments, this command reloads the file " + "daemon's data. If given a substring, it will also search " + "filenames and return those with the substring in their path. " + "With a substring and the -x flag, it will only return " + "filenames whose paths *begin* with the substring. " + "The -c flag skips the reloading of file daemon data, which " + "saves time and avoids mud-wide lag, but may return outdated " + "information." + "\n\n" + "Note: This command is deprecated for finding files. For " + "searching the mud for files, use the \"find\" command instead."); +} diff --git a/lib/secure/cmds/admins/gridconfig.c b/lib/secure/cmds/admins/gridconfig.c new file mode 100644 index 0000000..452d366 --- /dev/null +++ b/lib/secure/cmds/admins/gridconfig.c @@ -0,0 +1,151 @@ +#include <lib.h> +#include <daemons.h> +#include <rooms.h> + +inherit LIB_DAEMON; + +mixed findit(string str){ + string file, tmpfile; + object room; + int err; + if(str == "here"){ + tmpfile = base_name(environment(this_player())); + file = lpc_file(base_name(environment(this_player()))); + } + else { + file = lpc_file(str); + tmpfile = str; + } + if(!file_exists(file) && str != "here"){ + file = lpc_file(this_player()->query_cwd()+"/"+str); + if(!directory_exists(path_prefix(str))){ + tmpfile = this_player()->query_cwd()+"/"+str; + } + } + if(file_exists(file)) return file; + err = catch(room = load_object(tmpfile)); + if(room) return room; + return 0; +} + +static mixed ResetGrid(){ + object drone; + object *drones = ({}); + string *starts = ({}); + string start; + int err = 0; + drones = findobs("/domains/default/npc/drone3"); + starts = ({ROOM_START+".c", "/domains/Ylsrim/room/tower.c", + "/domains/Praxis/square.c", "/domains/campus/room/tunnel"}); + foreach(mixed arr in get_dir("/domains/", -1)){ + if(arr[1] == -2) start = "/domains/"+arr[0]+"/room/start.c"; + if(sizeof(start) && file_exists(start)) starts += ({ start }); + start = ""; + } + drones->eventDestruct(); + MAP_D->zero(); + ROOMS_D->zero(); + ROOMS_D->eventDestruct(); + MAP_D->eventDestruct(); + foreach(start in distinct_array(starts)){ + mixed lerr = 0; + lerr = catch( reload(start, 0, 1)); + if(lerr){ + err++; + write("Error reloading "+start+": "+lerr); + continue; + } + drone = new("/domains/default/npc/drone3"); + lerr = catch( drone->eventMove(start) ); + if(lerr){ + err++; + write("Error moving drone to "+start+": "+lerr); + } + else write("Assigning mapper drone to: "+start); + } + write("\nRemapping in progress. "+err+" errors encountered."); + return 1; +} + +mixed cmd(string args) { + string s1, s2, s3, coord, cmd; + mixed file; + object room; + int err; + if(!this_player() || !archp(this_player())) return "lol"; + if(!args){ + write("Try: help gridconfig"); + return 1; + } + if(args == "reset"){ + return ResetGrid(); + } + if(sscanf(args,"%s %s %s",s1,s2,s3) == 3){ + file = findit(s2); + cmd = s1; + coord = s3; + if(!file){ + write("Room not found."); + return 1; + } + if(objectp(file)) room = file; + if(!room) err = catch(room = load_object(file)); + if(err || !room){ + write("Room not loadable."); + return 1; + } + if(cmd != "set"){ + write("Try: help gridconfig"); + return 1; + } + if(sscanf(coord,"%s,%s,%s",s1,s2,s3) != 3){ + s3 = 0; + if(sscanf(coord,"%s,%s",s1,s2) != 2){ + write("Type: help gridconfig"); + return 1; + } + } + coord = coord + (s3 ? "" : ",0"); + ROOMS_D->SetRoom(room, this_player(), coord); + write("Coordinates for "+file+" are: "+ + ROOMS_D->GetCoordinates(room)); + return 1; + } + if(sscanf(args,"%s %s",s1,s2) == 2){ + file = findit(s2); + cmd = s1; + if(!file){ + write("Room not found."); + return 1; + } + if(objectp(file)) room = file; + if(!room) err = catch(room = load_object(file)); + if(err || !room){ + write("Room not loadable."); + return 1; + } + if(cmd != "unset"){ + write("Try: help gridconfig"); + return 1; + } + ROOMS_D->SetRoom(room, this_player(), "0,0,0"); + write("Coordinates for "+file+" are: "+ + ROOMS_D->GetCoordinates(room)); + return 1; + } + write("You fail to use this command properly."); + return 1; +} + +string GetHelp(string args) { + return ("Syntax: gridconfig set <room> <coordinates>\n" + " gridconfig unset <room>\n" + " gridconfig reset\n\n" + "Modifies the grid coordinate table in ROOMS_D for the " + "specified room. If \"reset\" is the argument, the rooms " + "daemon and map daemon are purged and slowly rebuilt using " + "mapper drones. Note that this may lag your mud. Note also " + "that the rooms daemon will disregard coordinate setting " + "of rooms in /realms/ and /open/ .\n" + "See also: mudconfig, admintool"); +} diff --git a/lib/secure/cmds/admins/groupmod.c b/lib/secure/cmds/admins/groupmod.c new file mode 100644 index 0000000..069cd77 --- /dev/null +++ b/lib/secure/cmds/admins/groupmod.c @@ -0,0 +1,178 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +string new_config_file = ""; +string dudename; + +mixed cmd(mixed args) { + string config_file, str; + string groupname, s1, s2; + string *line_array; + string *top_array; + string *bottom_array; + string *cles = ({}); + int reload_player, action = 0; + mapping GroupsMap = ([]); + + if( !this_player() || !(master()->valid_apply(({ "ASSIST" }))) ) + error("Illegal attempt to access groupmod: "+get_stack()+" "+identify(previous_object(-1))); + + + if(!args){ + write(read_file("/secure/cfg/groups.cfg")); + return 1; + } + + if(sscanf(args,"%s %s",s1,s2) != 2){ + write("Insufficient number of arguments. Try: help groupmod"); + return 1; + } + + if(strsrch(args,"-r ") != -1){ + action = -1; + args = replace_string(args,"-r ",""); + } + if(strsrch(args,"-a ") != -1){ + action = 1; + args = replace_string(args,"-a ",""); + } + + if(strsrch(args,"-d ") != -1){ + action = -2; + args = replace_string(args,"-d ",""); + } + if(strsrch(args,"-c ") != -1){ + action = 2; + args = replace_string(args,"-c ",""); + } + + if(sscanf(args,"%s %s",groupname,dudename) == 2 && (abs(action) > 1) ){ + write("Too many arguments for this operation. Please try: help groupmod."); + return 1; + } + + if(sscanf(args,"%s %s",groupname,dudename) != 2 && (abs(action) < 2) ){ + write("Insufficient arguments for this operation. Please try: help groupmod."); + return 1; + } + + args = upper_case(args); + + top_array = ({}); + bottom_array = ({}); + + unguarded( (: cp("/secure/cfg/groups.cfg","/secure/save/backup/groups."+time()) :) ); + config_file = read_file("/secure/cfg/groups.cfg"); + line_array = explode(config_file, "\n"); + if(groupname) str = upper_case(groupname); + else str = args; + if(dudename) dudename=(lower_case(dudename)); + line_array = explode(config_file,"\n"); + foreach(string line in line_array){ + string g,m; + if(sizeof(line)) line = trim(line); + if(sscanf(line,"(%s)%s",g,m) != 2) + if(sscanf(line,"(%s)",g) != 1) continue; + if(m){ + GroupsMap[g] = explode(trim(m),":"); + } + else GroupsMap[g] = ({}); + } + cles = keys(GroupsMap); + if(str == "ASSIST" || str == "SECURE" ) { + if(!securep(this_player())){ + write("Only full admins may do this."); + return 1; + } + reload_player = 1; + } + + if(!GroupsMap[str] && (abs(action) < 2)){ + write("No such group."); + return 1; + } + + if(!action){ + write("I don't understand what you want. Please specify "); + write("which action you want, -r, -a, -d, or -c"); + return 1; + } + + if(action == 1){ + if(member_array(dudename,GroupsMap[str]) != -1){ + write("That person is already a member of that group."); + return 1; + } + if(member_array(str,cles) != -1 && !sizeof(GroupsMap[str])) GroupsMap[str] = ({}); + GroupsMap[str] += ({ dudename }); + write("The group "+str+" now contains the following:\n "+ + implode(GroupsMap[str],":")); + } + + if(action == -1){ + if(member_array(dudename,GroupsMap[str]) == -1){ + write("That person is already not a member of that group."); + return 1; + } + if((str == "ASSIST" || str == "SECURE") && dudename == this_player()->GetKeyName() ) { + write("This command will not let you remove yourself from the SECURE or ASSIST groups."); + return 1; + } + GroupsMap[str] -= ({ dudename }); + write("The group "+str+" now contains the following:\n "+ + implode(GroupsMap[str],":")); + } + + if(action == -2){ + if(member_array(args,cles) == -1){ + write("That group doesn't exist."); + return 1; + } + if(args == "ASSIST" || args == "SECURE" ) { + write("I'm not doing that. You'll have to hose your mud manually."); + return 1; + } + map_delete(GroupsMap,args); + write("Group deleted."); + } + + if(action == 2){ + if(member_array(args,cles) != -1){ + write("That group already exists."); + return 1; + } + GroupsMap[args] = ({}); + write("Group added."); + } + + foreach(string key, mixed val in GroupsMap){ + new_config_file += "("+key+") "+implode(GroupsMap[key],":")+"\n"; + } + unguarded( (: write_file("/secure/cfg/groups.cfg",new_config_file,1) :) ); + load_object("/secure/cmds/creators/update")->cmd("/secure/daemon/master"); + load_object("/secure/cmds/creators/update")->cmd("/secure/lib/connect"); + if(str == "SNOOPER") SNOOP_D->SnoopClean(); + new_config_file = ""; + if(reload_player){ + object player = unguarded((: find_player(dudename) :)); + if(player){ + tell_player(player, "You've had your group membership changed "+ + "in an important way.\n\nYour user object will be reloaded in "+ + "a few moments.\n\n"); + RELOAD_D->eventReload(player, 3); + } + } + dudename = ""; + return 1; +} + +string GetHelp() { + return ("Syntax: groupmod [-a|-r] <GROUP> <NAME> \n" + " groupmod [-c|-d] <GROUP>\n\n" + "Modifies /secure/cfg/groups.cfg with the desired information.\n" + "To create a group called MUDKIPZ: groupmod -c mudkipz\n" + "To add Yotsuba as member of that group: " + "groupmod -a mudkipz yotsuba"); +} diff --git a/lib/secure/cmds/admins/instconfig.c b/lib/secure/cmds/admins/instconfig.c new file mode 100644 index 0000000..9768775 --- /dev/null +++ b/lib/secure/cmds/admins/instconfig.c @@ -0,0 +1,90 @@ +#include <lib.h> +#include <daemons.h> +#include NETWORK_H +#include SECRETS_H + +inherit LIB_DAEMON; + +void validate(){ + if(!master()->valid_apply(({ "SECURE"})) || !this_player()){ + error("no"); + } + if(!archp(this_player()) || this_player()->GetForced()){ + error("i said no"); + } +} + +mixed cmd(string str){ + mixed ret; + int i, port; + string cmd, args, name, addy; + validate(); + if(!sizeof(str)) { + write("Try: help instconfig"); + return 1; + } + i = sscanf(str, "%s %s", cmd, args); + if(!i) cmd = str; + if(cmd == "create"){ + i = sscanf(args,"%s %s %d", name, addy, port); + if(i != 3) i = sscanf(args,"%s %d", name, port); + if(i < 2) { + write("Try: help instconfig"); + return 1; + } + if(undefinedp(addy)) addy = "127.0.0.1"; + ret = INSTANCES_D->InstCreate(name, addy, port); + if(!ret){ + write("Some sort of problem occurred."); + return 1; + } + if(stringp(ret)) write(ret); + else write("Done."); + return 1; + } + + if(cmd == "remove"){ + write("Trying to remove: "+args); + if(member_array(args, INSTANCES_D->GetInstances()) == -1){ + write("No such instance found."); + return 1; + } + ret = INSTANCES_D->InstDelete(args); + if(intp(ret)){ + write("Removal of "+args+" successful."); + } + else { + write(ret); + } + return 1; + } + if(cmd == "list"){ + mapping instdata = INSTANCES_D->GetInstData(); + mixed insts = sort_array(keys(instdata), 1); + ret = ""; + foreach(mixed key in insts){ + if(!instdata[key]) continue; + ret += key + " " + instdata[key]["port"] + " " + + (instdata[key]["online"] ? "%^GREEN%^online" : "%^RED%^offline"); + ret += "%^RESET%^\n"; + } + if(!sizeof(ret)){ + ret = "The instance daemon is aware of no configured instances."; + } + write(ret); + return 1; + } +} + +string GetHelp(){ + return ("Syntax: instconfig list\n" + " instconfig create <name> <port>\n" + " instconfig remove <name>\n\n" + "Modifies your instance configuration. To add an instance " + "named Alpha on port 5555, you would type:\n" + "instconfig create Alpha 5555\n\n" + "To remove it:\n" + "instconfig remove Alpha\n\n" + "See also: instances, admintool, mudconfig"); +} + diff --git a/lib/secure/cmds/admins/link.c b/lib/secure/cmds/admins/link.c new file mode 100644 index 0000000..ae06d33 --- /dev/null +++ b/lib/secure/cmds/admins/link.c @@ -0,0 +1,117 @@ +/* /secure/cmds/admins/link.c + * from the Dead Souls Mud Library + * link SECONDARY to PRIMARY + * link PLAYER + * link + * created by Descartes of Borg 951216 + */ + +#include <lib.h> +#include <link.h> +#include <daemons.h> +#include <message_class.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + mixed tmp; + string primary, secondary; + + if( !archp(previous_object()) ) return 0; + + // If no arguments are specified, dump all links. + if( !args || args == "" ) { + mapping links; + string formatString; + int screenSize = ((int *)this_player()->GetScreen())[0]; + int playerSize = ((screenSize * 4) / 16) -1; + int emailSize = ((screenSize * 6) / 16) - 1; + int lastOnSize = ((screenSize * 6) / 16) - 1; + + if(playerSize < 14) playerSize = 14; + if(emailSize < 25) emailSize = 25; + if(lastOnSize < 25) lastOnSize = 25; + + formatString = "%:-" + playerSize + "s %:-" + emailSize + + "s %:-" + lastOnSize + "s"; + + tmp = ({ center("%^CYAN%^ " + mud_name() + + " Approved Character Links%^YELLOW%^", screenSize) }); + + tmp += ({ sprintf(formatString, "Player", "Email", "Last On%^RESET%^") }); + + links = CHARACTER_D->GetLinks(); + foreach(string p in sort_array(keys(links), 1)) { + class char_link l; + int maxi; + + l = links[p]; + if( !(maxi = sizeof(l->Secondaries)) ) continue; + tmp += ({ sprintf(formatString, capitalize(p), l->Email, + ((l->LastOnWith == p) ? ctime(l->LastOnDate) : "unknown")) }); + foreach(string pl in l->Secondaries) + tmp += ({ sprintf(formatString, " " + capitalize(pl), "", + ((l->LastOnWith == pl) ? ctime(l->LastOnDate) : "unknown")) }); + } + this_player(1)->eventPage(tmp, MSG_SYSTEM); + return 1; + } + + // Or, link a secondary to a primary. + else if( sscanf(args, "%s to %s", secondary, primary) == 2 ) { + this_player(1)->eventPrint("Email for player: ", MSG_PROMPT); + input_to(function(string email, string primary, string secondary) { + mixed tmp; + + if( !email || email == "" ) { + this_player(1)->eventPrint("Aborted.", MSG_SYSTEM); + return; + } + tmp = CHARACTER_D->eventLink(primary, secondary, email); + if( !tmp ) this_player(1)->eventPrint("Failed.", MSG_SYSTEM); + else if( tmp == 1) this_player(1)->eventPrint("Linked.", MSG_SYSTEM); + else this_player(1)->eventPrint(tmp, MSG_SYSTEM); + }, primary, secondary); + return 1; + } + + // Otherwise, get link information on a specific player. + else { + mapping mp; + string str; + + mp = CHARACTER_D->GetLink(convert_name(args)); + if( !mp ) this_player()->eventPrint(capitalize(args) + " has no " + "links listed.", MSG_SYSTEM); + else { + str = "Primary: " + capitalize(mp["primary"]) + "\n"; + str += "Last on " + ctime(mp["last on"]) + " with " + + capitalize(mp["last char"]) + "\n"; + str += "Secondaries: " + implode(mp["secondaries"], ","); + this_player()->eventPrint(str, MSG_SYSTEM); + } + return 1; + } +} + +string GetHelp(){ + return ("Syntax: link <SECONDARY> to <PRIMARY>\n" + " link <PLAYER>\n" + " link\n\n" + "In the first form, it allows you to mark two characters " + "as being controlled by the same real individual. It " + "creates a relationship where one character is considered " + "primary, and the other is secondary. If link relationships " + "already exist for one or more, this will alter those " + "and create a new one with the primary one you specify as " + "primary. For example, if both characters were already set " + "up as primary links, the one you specify with this command " + "as primary becomes the sole primary link for these characters, " + "and the secondary plus its secondaries all become secondaries " + "for his primary.\n\n" + "If you just pass a player name as an argument, this command " + "will show you the link information on that player.\n\n" + "If you give no arguments, then this command will list all " + "known links/\n\n" + "See also: finger, unlink"); +} diff --git a/lib/secure/cmds/admins/liveupgrade.c b/lib/secure/cmds/admins/liveupgrade.c new file mode 100644 index 0000000..7c30b3e --- /dev/null +++ b/lib/secure/cmds/admins/liveupgrade.c @@ -0,0 +1,456 @@ +#include <lib.h> +#include <dirs.h> +#include <cfg.h> +#include <commands.h> +#include <save.h> +#include <daemons.h> +#include NETWORK_H + +#define WEB_SOURCE_PORT 80 + +string array allnames = ({}); +string array tmpnames; +string reverts_dir, revert_name; +static string upgrade_prefix = "/code/upgrades/"+mudlib_version(); +static string reverts_prefix = "/secure/upgrades/reverts/"+mudlib_version(); +static string upgrades_txt = "/secure/upgrades/txt"; +static string upgrades_files = "/secure/upgrades/files"; +static int i = 0; +static int oob = 0; +static object player = 0; +int patched, transver = 0; +static mapping NewFiles = ([]); +static string SaveFile; + +void create(){ +#ifdef ENABLE_INSTANCES + SaveFile = save_file(SAVE_LIVEUPGRADE); + if( unguarded( (: file_exists(SaveFile) :) ) ){ + unguarded( (: restore_object(SaveFile) :) ); + } +#endif + + if(false()){ + object uu = find_object("/secure/daemon/update"); + if(uu) uu->eventDestruct(); + if(uu) destruct(uu); + patched = 1; + unguarded( (: cp("/secure/daemon/update.patch", + "/secure/daemon/update.c") :) ); + unguarded( (: reload("/secure/daemon/update.c") :) ); + } +} + +int eventDestruct(){ +#ifdef ENABLE_INSTANCES + if(directory_exists(path_prefix(SaveFile))){ + unguarded( (: save_object(SaveFile) :) ); + } +#endif + destruct(); + return 1; +} + +int eventBackup(string file){ + string tmp, time_str,short_name,filename; + if(!file) return 0; + if(!file_exists(file)) return -1; + if( !(tmp = read_file(file)) ) return -2; + time_str = time()+"."+random_numbers(5); + short_name = last_string_element(file,"/"); + if(!revert_name){ + revert_name = itoa(time()); + } + if(!reverts_prefix){ + reverts_prefix = "/secure/upgrades/reverts/"+mudlib_version(); + } + if(!directory_exists("/secure/upgrades/reverts/")){ + mkdir("/secure/upgrades/reverts"); + } + if(!directory_exists(reverts_prefix)){ + mkdir(reverts_prefix); + } + if(!directory_exists(reverts_prefix+"/"+revert_name)){ + mkdir(reverts_prefix+"/"+revert_name); + } + filename = reverts_prefix+"/"+revert_name+ + "/"+short_name+"."+time_str; + write_file(reverts_prefix+"/"+revert_name+"/"+ + "/bk.db",short_name+"."+time_str+" : "+file+"\n"); + cp(file,filename); + return 1; +} + +int eventRevert(string revert_path){ + string *files; + + if(!revert_path){ + return 0; + } + + if(!directory_exists(revert_path)){ + return -1; + } + + if(!file_exists(revert_path+"/bk.db")){ + return -2; + } + + files = explode(read_file(revert_path+"/bk.db"),"\n"); + + if(!files || !sizeof(files)){ + return -3; + } + + foreach(string line in files){ + string backup, target; + if(sscanf(line,"%s : %s", backup, target) != 2) continue; + if(!directory_exists(path_prefix(target))){ + mkdir_recurse(path_prefix(target)); + } + cp(revert_path+"/"+backup, target); + } + return 1; +} + +void eventReloads(){ + cp("/secure/daemon/update.patch","/secure/daemon/update.c"); + reload(UPDATE_D); + reload(LUGET_D); +} + +int eventCopy(string element){ + string path; + if(!NewFiles[element]) return 0; + path = path_prefix(NewFiles[element]); + if(!directory_exists(path)) mkdir_recurse(path); + rename(element, NewFiles[element]); + return 1; +} + +mixed cmd(string str) { + string mud = "Dead Souls"; + string file; + string orig_str = str; + int foo, tmpint = 0; + object inet = find_object(INET_D); + string *preload_file = explode(read_file(CFG_PRELOAD),"\n"); + mixed *socks = socket_status(); + + NewFiles = ([]); + + if(!revert_name){ + revert_name = itoa(time()); + } + + if(!str || str == ""){ + write("Try: help liveupgrade."); + return 1; + } + + if(str == "alpha"){ + if(transver){ + transver = 0; + write("Alpha/Stable upgrades disabled."); + return 1; + } + if(!transver){ + transver = 1; + write("Alpha/Stable upgrades enabled."); + return 1; + } + } + + if(str == "revert"){ + string *vers = get_dir("/secure/upgrades/reverts/"); + string ver, subver; + if(!vers || !sizeof(vers)){ + write("There is no previous backup to revert to."); + return 1; + } + else ver = vers[0]; + vers = get_dir("/secure/upgrades/reverts/"+ver+"/"); + if(!vers || !sizeof(vers)){ + write("There is no backup instance to revert to."); + return 1; + } + else subver = "/secure/upgrades/reverts/"+ver+"/"+vers[0]; + eventRevert(subver); + rename(subver,"/secure/upgrades/bak/"+last_string_element(subver,"/")); + rmdir(path_prefix(subver)); + write("Reversion complete."); + return 1; + } + + foreach(mixed element in socks){ + if(element[1] == "DATA_XFER" && element[4] == WEB_SOURCE_IP+"."+WEB_SOURCE_PORT && + str != "cancel"){ + player->eventPrint("A download is still in progress. Please wait until it is complete."); + return 1; + } + } + + if(!player && this_player()) player = this_player(); + allnames = ({}); + if(!player) return 0; + + if( !(master()->valid_apply(({ "SECURE" }))) ) + error("Illegal attempt to access liveupgrade: "+get_stack()+" "+identify(previous_object(-1))); + + if(!directory_exists("/secure/upgrades/bak")){ + mkdir("/secure/upgrades/bak"); + } + + if(!directory_exists(reverts_prefix)){ + mkdir(reverts_prefix); + } + + i = sscanf(mudlib_version(),"2.3a%d",tmpint); + if(i && tmpint < 12) oob = 1; + else { + if(!strsrch(str,"-o ")){ + oob = 1; + str = replace_string(str,"-o ",""); + } + else oob = 0; + } + + i = 0; + foo = sscanf(str,"%s %s",file, mud); + if(!foo || foo < 2) file = str; + if(str == "apply" || str == "deferred"){ + string *files = ({}); + string nlu, secs = upgrades_files+"/0^0secure0^0include0^0secrets.h"; + object nlob; + if(file_exists(SECRETS_H)){ + catch( cp(SECRETS_H, "/secure/save/backup/secrets_" + + imc2_mud_name() + "." + time() + ".bak") ); + } + if(file_exists(secs)) catch( rm(secs) ); + nlu = upgrades_files+"/0^0secure0^0cmds0^0admins0^0liveupgrade.c"; + if(file_exists(nlu)){ + catch( nlob = load_object(nlu) ); + if(nlob && nlob->GetDeferment() && str != "deferred"){ + nlob->eventDestruct(); + return 1; + } + if(nlob) nlob->eventDestruct(); + if(!rename(nlu, CMD_LIVEUPGRADE)){ + write("The liveupgrade command has been updated."); + write("Please wait five seconds, then again type:\n"); + write("liveupgrade apply"); + if(!(this_object()->eventDestruct())){ + RELOAD_D->eventReload(this_object(), 0); + } + return 1; + } + } + player->eventPrint("I hope you backed up...\n"); + foreach(string element in get_dir(upgrades_files+"/")){ + if(element == "0^0secure0^0sefun0^0mud_info.c"){ + object thingy = load_object(upgrades_files+"/"+element); + string vers; + if(thingy){ + string current_ver = mudlib_version(); + vers = thingy->mudlib_version(); + if(((grepp(vers,"a") && !grepp(current_ver, "a")) || + (!grepp(vers,"a") && grepp(current_ver, "a"))) && + !transver){ + write("This upgrade would cross stable/alpha " + "boundaries, but that has not been enabled " + "with \"liveupgrade alpha\" yet."); + return 1; + } + } + } + files += ({ upgrades_files+"/"+element }); + } + foreach(string element in files){ + string contents = ""; + NewFiles[element] = replace_string(replace_string(element,"0^0","/"), + upgrades_files+"/",""); + contents = read_file(element); + if(!contents) contents = ""; + if(last(contents,1) != "\n") contents += "\n"; + write_file(element, contents, 1); + reset_eval_cost(); + call_out( (: eventBackup :), 0, NewFiles[element]); + if(directory_exists(NewFiles[element])) true(); + else { + call_out( (: eventCopy :), 0, element); + } + } + if(member_array(INET_D,preload_file) == -1 && inet) inet->eventDestruct(); + call_out( (: eventReloads :), 10); + patched = 0; + RELOAD_D->eventReload(this_object(), 15); + rm("/secure/upgrades/txt/list.txt"); + player->eventPrint("\nAlmost done..."); + player = 0; + return 1; + } + if(str == "cancel"){ + string *files = ({}); + foreach(string element in get_dir(upgrades_files+"/")){ + files += ({ upgrades_files+"/"+element }); + } + foreach(string element in files){ + rm(element); + } + rm("/secure/upgrades/txt/list.txt"); + player->eventPrint("Cancelled."); + player = 0; + RELOAD_D->eventReload(this_object(), 2); + reload(LUGET_D); + return 1; + } + if(oob){ + if(!inet){ + inet = load_object(INET_D); + player->eventPrint("Starting INET_D."); + if(member_array(INET_D,preload_file) == -1) + player->eventPrint("When you complete the upgrade by using the \"apply\" keyword, the " + "inet daemon will be shut down, since you do not have it enabled by " + "default. Please remember to either apply the upgrades when the downloading " + "is complete, or manually shut down INET_D with the command: mudconfig inet stop\n"); + } + if(!inet){ + player->eventPrint("There is a problem with INET_D. The upgrade will not proceed."); + return 1; + } + + if(!INET_D->GetService("oob")){ + player->eventPrint("The OOB service is not enabled. Enabling it now."); + INET_D->AddService("oob",OFFSET_OOB,LIB_OOB,0); + } + + if(!INET_D->GetService("oob")){ + player->eventPrint("There was a problem enabling the OOB service. The upgrade will not proceed."); + return 1; + } + + if(!INET_D->GetServer("oob")){ + player->eventPrint("The OOB service is not started. Starting it now."); + INET_D->eventStartServer("oob"); + } + + if(!INET_D->GetServer("oob")){ + player->eventPrint("There was a problem starting the OOB service. The upgrade will not proceed."); + return 1; + } + + if(foo < 2) { + mud = LIVEUPGRADE_SERVER; + file = str; + } + if(!file){ + return this_object()->GetHelp(); + } + + mud = INTERMUD_D->GetMudName(mud); + if(!mud){ + player->eventPrint("That liveupgrade server appears unavailable."); + return 1; + } + } + if(file == "all"){ + string tmp = replace_string(upgrades_txt+"/upgrades.txt","/","0^0"); + if(player && this_player() && player != this_player()){ + this_player()->eventPrint("This command is currently locked and in use by "+capitalize(player->GetKeyName())+"."); + return 1; + } + else if(this_player()) player = this_player(); + else player = this_object(); + + if(LUGET_D->GetUpgrading()){ + player->eventPrint("An upgrade in already occurring. Please wait for it to complete."); + return 1; + } + + if(!file_exists(upgrades_txt+"/list.txt")){ + player->eventPrint("Downloading updates table. Please wait..."); + rename("/secure/upgrades/files","/secure/upgrades/bak/"+time()); + mkdir("/secure/upgrades/files"); + if(oob){ + OOB_D->GetFile(mud,upgrades_txt+"/upgrades.txt"); + } + else { + LUGET_D->GetFile(WEB_SOURCE_IP, upgrade_prefix+"/upgrades.txt",WEB_SOURCE_NAME, + "/secure/upgrades/txt/list.txt",WEB_SOURCE_PORT); + } + call_out( (: cmd :), 5, orig_str); + return 1; + } + + tmpnames = explode(read_file(upgrades_txt+"/list.txt"),"\n"); + foreach(string element in tmpnames){ + if(!oob) allnames += ({ "/code/upgrades/"+mudlib_version()+element }); + else allnames += ({ element }); + } + + if(oob){ + OOB_D->eventMajorUpgrade(mud, allnames); + } + else { + LUGET_D->eventMajorUpgrade(WEB_SOURCE_IP, allnames,WEB_SOURCE_NAME); + } + rm(upgrades_txt+"/list.txt"); + player->eventPrint("Full upgrade begun."); + player->eventPrint("Please wait until you receive a completion message, "+ + "then issue the command: liveupgrade apply\n\n"); + player->eventPrint("%^FLASH%^RED%^WARNING! %^BLACK%^WARNING! %^YELLOW%^WARNING! %^RESET%^WARNING!"); + player->eventPrint("You must *always* do a full backup before applying the liveupgrade. "+ + "If the liveupgrade screwed up, and you get garbage files because of connection "+ + "problems, it may be necessary for you to restore from backup to be able to "+ + "start the mud again. You've been warned."); + return 1; + } + if(oob){ + OOB_D->GetFile(mud,file); + player->eventPrint("Requesting the file \""+file+"\" from "+INTERMUD_D->GetMudName(mud)+"."); + } + else { + player->eventPrint("Requesting the file \""+file+"\" from "+WEB_SOURCE_IP); + LUGET_D->GetFile(WEB_SOURCE_IP, upgrade_prefix+file); + } + return 1; +} + +void eventReceiveReport(string str){ + if(player) player->eventPrint(str); +} + +int GetDeferment(){ + string *defers = ({ "secrets.h", "network.h", "mssp.h" }); + string secs = upgrades_files+"/0^0secure0^0include0^0"; + foreach(string deferment in defers){ + if(file_exists(secs+deferment) && + file_exists("/secure/include/"+deferment)){ + rm(secs+deferment); + } + } + return 0; +} + +string GetHelp() { + return ("Syntax: liveupgrade all\n" + " liveupgrade apply\n" + " liveupgrade cancel\n" + " liveupgrade revert\n" + " liveupgrade alpha\n\n" + "To upgrade all files to the next appropriate level for your lib version:\n" + "liveupgrade all\n" + "Wait until you receive the completion message before finalizing the upgrade. " + "You can finalize the upgrade by typing:\n" + "liveupgrade apply\n" + "This will delete your old copies of files and copy the newly downloaded " + "ones in their place.\n" + "NEVER EVER do a liveupgrade without a full backup first.\n" + "To cancel the liveupgrade process:\n" + "liveupgrade cancel\n" + "To restore your mud to the condition it was in prior to the last liveupgrade.\n" + "liveupgrade revert\n" + "To enable liveupgrading between alpha and stable versions:\n" + "liveupgrade alpha\n\n" + "Web proxies are *NOT* supported. OOB is no longer supported."); +} diff --git a/lib/secure/cmds/admins/mudconfig.c b/lib/secure/cmds/admins/mudconfig.c new file mode 100644 index 0000000..69d563f --- /dev/null +++ b/lib/secure/cmds/admins/mudconfig.c @@ -0,0 +1,1070 @@ +#include <lib.h> +#include <cfg.h> +#include <save.h> +#include <daemons.h> +#include <commands.h> +#include NETWORK_H +#include <sockets.h> +string GetHelp(); + +inherit LIB_DAEMON; + +string ret_string = ""; +string array config, config2, keywords; +string array bools = ({ "enable","disable","on","off","1","0" }); +string array yesbools = ({ "enable","on","1","yes" }); +string array nobools = ({ "disable","off","0","no" }); +string array restrict_tokens = ({ "restrict","unrestrict" }); +string array nonmodals = ({ "liveupgrade", "prompt","status","email", + "websourceip", "websourcename", "mudname", "mudport", + "debugger", "access", "pinging", "pinginterval", + "imc2serverpass", "imc2clientpass" }); +string array antimodals = ({ "imc2", "ced" }); +string array modals = antimodals + ({ "channelpipes", "fastcombat", + "catchtell","matchcommand", "matchobject", "autowiz", "locked", + "localtime", "justenglish", "justhumans", "encumbrance", "pk", + "compat", "exitsbare", "nmexits", "grid", "minimap", "wizmap", + "cgi", "dirlist", "creweb", "selectclass", "severable", + "retain", "defaultparse", "disablereboot", "loglocal", "logremote", + "questrequired", "autoadvance","guestallowed", "playerintertell" }); +string array inet_services = ({ "oob", "hftp", "ftp", "http", "rcp", "inet" }); + +static int NotImplemented(string which); +varargs static int TestFun(string which, string arg); +varargs static int ModIntermud(string which, string arg); +varargs static int ModRouter(string which, string arg); +static int ProcessModal(string which, string arg); +varargs static int ModStartRoom(string which, string arg); +static int ProcessOther(string which, string arg); +static int ProcessString(string which, string arg); +int ProcessInet(string which, string arg); +varargs static int ModDefaultDomain(string which, string arg); +varargs static int ModCfg(string which, string arg); + +static private void validate() { + if(!this_player()) return 0; + if( !(master()->valid_apply(({ "ASSIST" }))) ) + error("Illegal attempt to access mudconfig: "+get_stack()+" "+identify(previous_object(-1))); +} + +mixed cmd(string str) { + string which, arg; + + validate(); + + if(this_player() && !securep(this_player())){ + write("This command is for full admins only. To become a "+ + "full admin, you'll need to be added to the SECURE group."); + return 1; + } + + if(!this_player() && base_name(previous_object()) != IMC2_D && + base_name(previous_object()) != INTERMUD_D) return 1; + + if(base_name(previous_object()) == IMC2_D){ + if(str != "imc2 disable") return 1; + } + if(base_name(previous_object()) == INTERMUD_D){ + if(str != "intermud disable") return 1; + } + + if(!str || sscanf(str, "%s %s", which, arg) != 2){ + write(GetHelp()); + return 1; + } + cp(CONFIG_H,"/secure/save/backup/config."+time()); + config = explode( read_file(CONFIG_H),"\n" ); + config2 = ({}); + keywords = ({}); + foreach(string element in config){ + string s1, s2; + if(sscanf(element,"#define %s %s",s1,s2) == 2) keywords += ({ s1 }); + } + + if(member_array(which,modals) != -1){ + ProcessModal(which, arg); + return 1; + } + + if(member_array(which,inet_services) != -1){ + ProcessInet(which, arg); + return 1; + } + + else switch(which){ + case "test" : TestFun(which, arg);break; + case "intermud" : ModIntermud(which, arg);break; + case "router" : ModRouter(which, arg);break; + case "startroom" : ModStartRoom(which, arg);break; + case "defaultdomain" : ModDefaultDomain(which, arg);break; + case "resets" : which = "TIME_TO_RESET";ProcessOther(which,arg);break; + case "offset" : which = "GMT_OFFSET";ProcessOther(which,arg);break; + case "extraoffset" : which = "EXTRA_TIME_OFFSET";ProcessOther(which,arg);break; + case "newbielevel" : which = "MAX_NEWBIE_LEVEL";ProcessOther(which,arg);break; + case "monitor" : which = "GLOBAL_MONITOR";ProcessOther(which,arg);break; + case "maxip" : which = "SAME_IP_MAX";ProcessOther(which,arg);break; + case "pinginterval" : which = "PING_INTERVAL";ProcessOther(which,arg);break; + case "maxcommands" : which = "MAX_COMMANDS_PER_SECOND";ProcessOther(which,arg);break; + case "maxidle" : which = "IDLE_TIMEOUT";ProcessOther(which,arg);break; + case "instances" : which = "ENABLE_INSTANCES";ProcessOther(which,arg);break; + case "hostip" : which = "HOST_IP";ProcessString(which,arg);break; + case "email" : which = "ADMIN_EMAIL";ProcessString(which,arg);break; + case "liveupgrade" : which = "LIVEUPGRADE_SERVER";ProcessString(which,arg);break; + case "mudstatus" : which = "MUD_STATUS";ProcessString(which,arg);break; + case "debugger" : which = "DEBUGGER";ProcessString(which,arg);break; + case "websourceip" : which = "WEB_SOURCE_IP";ProcessString(which,arg);break; + case "websourcename" : which = "WEB_SOURCE_NAME";ProcessString(which,arg);break; + case "imc2clientpass" : which = "IMC2_CLIENT_PW";ProcessString(which,arg);break; + case "imc2serverpass" : which = "IMC2_SERVER_PW";ProcessString(which,arg);break; + case "mudname" : ModCfg("name", arg);break; + case "mudport" : ModCfg("port", arg);break; + default : NotImplemented(which);break; + } + return 1; +} + +varargs static int CompleteConfig(string file){ + string ret = implode(config2,"\n")+"\n"; + if(!file) file = CONFIG_H; + validate(); + ret = replace_string(ret,"\n\n","\n"); + write_file(file,ret,1); + RELOAD_D->ReloadBaseSystem(); + reload(LIB_CONNECT,0,1); + reload(BANISH_D,0,1); + reload(PLAYERS_D,0,1); + write("Command complete."); + return 1; +} + +int ModPortOffset(string which, string arg){ + string out, service, svc, junk, offset, new_offset; + string *new_array = ({}); + string netcfg = read_file(NETWORK_H); + string *net_array = explode(netcfg,"\n"); + + new_offset = arg; + service = which; + service = upper_case(service); + foreach(string element in net_array){ + if(sscanf(element,"#define OFFSET_%s %s %d",svc, junk, offset) == 3){ + if(lower_case(svc) == lower_case(service)){ + out = "#define OFFSET_"+service+" "+new_offset; + } + else out = element; + } + else out = element; + new_array += ({ out }); + } + out = implode(new_array,"\n"); + + write_file(NETWORK_H,out,1); + write("The "+service+" port offset is being set to "+offset+"."); + RELOAD_D->eventReload(this_object(), 1, 1); + reload(MASTER_D,0,1); + return 1; +} + +int ModPort(string which, mixed arg){ + string out, service, svc, junk, new_offset, new_port; + string *new_array = ({}); + string netcfg = read_file(NETWORK_H); + string *net_array = explode(netcfg,"\n"); + int offset; + + if(stringp(arg)) new_port = arg; + else new_port = itoa(arg); + service = which; + service = upper_case(service); + foreach(string element in net_array){ + if(sscanf(element,"#define OFFSET_%s %s %d",svc, junk, offset) == 3){ + if(lower_case(svc) == lower_case(service)){ + new_offset = ""+(atoi(new_port) - query_host_port()); + out = "#define OFFSET_"+service+" "+new_offset; + } + else out = element; + } + else out = element; + new_array += ({ out }); + } + out = implode(new_array,"\n"); + if(last(out,1) != "\n") out += "\n"; + write_file(NETWORK_H,out,1); + write("The "+service+" port is being set to "+atoi(new_port)+"."); + write("To complete this configuration, wait 2 seconds, then issue the following commands:"); + write("mudconfig "+lower_case(service)+" disable"); + write("mudconfig "+lower_case(service)+" enable"); + RELOAD_D->eventReload(this_object(), 1, 1); + reload(MASTER_D,0,1); + return 1; +} + +static int NotImplemented(string which){ + validate(); + write("The keyword \""+which+"\" is not yet implemented in mudconfig."); + return 1; +} + +varargs static int TestFun(string which, string arg){ + validate(); + write("Which: "+which+" arg: "+arg); + return 1; +} + +varargs static int ModStartRoom(string which, string arg){ + if(!arg){ + write("Please specify the absolute path to the room's file."); + return 1; + } + if(first(arg,1) != "/"){ + write("You've entered a relative path. Please try again, using an absolute path."); + return 1; + } + if(last(arg,2) == ".c") arg = truncate(arg,2); + if(!file_exists(arg+".c")){ + write("That file does not exist."); + return 1; + } + if(catch(load_object(arg))){ + write("/n/nThat room file is broken. Please fix it and try again."); + return 1; + } + cp(ROOMS_H,"/secure/save/backup/rooms."+time()); + config = explode( read_file(ROOMS_H),"\n" ); + config2 = ({}); + foreach(string line in config){ + string s1,s2,s3; + if(sscanf(line,"%s %s %s",s1,s2,s3) == 3){ + if(s1 == "#define" && s2 == "ROOM_START") + line = "#define ROOM_START \""+arg+"\""; + } + config2 += ({ line }); + } + CompleteConfig(ROOMS_H); + reload(LIB_CREATOR,1,1); + write("\nNote: Some objects, like verbs and workrooms, still contain the old "+ + "START_ROOM value. This will not change until they are reloaded or "+ + "the mud reboots."); + return 1; +} + +varargs static int ModDefaultDomain(string which, string arg){ + if(!arg){ + write("Please specify the absolute path to the domain, eg: /domains/MystyShyre"); + return 1; + } + + if(first(arg,1) != "/"){ + write("You've entered a relative path. Please try again, using an absolute path. "+ + "For example: mudconfig defaultdomain /domains/MystyShyre"); + return 1; + } + + if(!directory_exists(arg)){ + write("That domain does not exist. Type: help domaincreate"); + return 1; + } + + if(!directory_exists(arg+"/room")){ + write("That directory seems to lack a /room dir. It is not suitable for a domain."); + return 1; + } + + cp("/secure/include/dirs.h","/secure/save/backup/dirs."+time()); + config = explode( read_file("/secure/include/dirs.h"),"\n" ); + config2 = ({}); + foreach(string line in config){ + string s1,s2,s3; + if(sscanf(line,"%s %s %s",s1,s2,s3) == 3){ + if(s1 == "#define" && s2 == "DIR_STANDARD_DOMAIN") + line = "#define DIR_STANDARD_DOMAIN \""+arg+"\""; + } + config2 += ({ line }); + } + + CompleteConfig("/secure/include/dirs.h"); + + write("\nPlease reboot the mud for this change to take effect.\n"); + return 1; +} + +varargs static int ModRouter(string which, string arg){ + string preloads = read_file(CFG_PRELOAD); + string *load_lines = explode(preloads,"\n"); + string *ret_arr = ({}); + string yesline = "/secure/daemon/i3router/server"; + string noline = "#/secure/daemon/i3router/server"; + validate(); + if(member_array(arg,bools) == -1){ + write("Please try again, indicating whether you want to enable or disable the intermud router. Note that this setting will persist across reboots."); + return 1; + } + + if(member_array(arg,yesbools) != -1){ + if(member_array(yesline,load_lines) != -1) write("Persistent router activation is already enabled."); + else { + write("Enabling persistent router activation."); + foreach(string line in load_lines){ + if(line == noline) line = yesline; + ret_arr += ({ line }); + } + if(member_array(yesline,ret_arr) == -1){ + ret_arr += ({ yesline }); + } + unguarded( (: cp(CFG_PRELOAD,"/secure/save/backup/preload."+time()) :) ); + ret_string = implode(ret_arr,"\n")+"\n"; + ret_string = replace_string(ret_string,"\n\n","\n"); + unguarded( (: write_file(CFG_PRELOAD,ret_string,1) :) ); + } + if(find_object(ROUTER_D)) write("The intermud router is already running."); + else { + write("Starting the intermud router."); + load_object(ROUTER_D); + } + + ret_string = ""; + write("The intermud router is enabled."); + return 1; + } + + if(member_array(arg,nobools) != -1){ + + if(member_array(noline,load_lines) != -1) write("Persistent router activation is already disabled."); + else { + write("Disabling persistent router activation."); + foreach(string line in load_lines){ + + if(line == yesline) line = noline; + ret_arr += ({ line }); + } + if(member_array(noline,ret_arr) == -1){ + ret_arr += ({ noline }); + } + unguarded( (: cp(CFG_PRELOAD,"/secure/save/backup/preload."+time()) :) ); + ret_string = implode(ret_arr,"\n")+"\n"; + ret_string = replace_string(ret_string,"\n\n","\n"); + unguarded( (: write_file(CFG_PRELOAD,ret_string,1) :) ); + + } + if(!find_object(ROUTER_D)) write("The intermud router is not running."); + else { + write("Stopping the intermud router."); + find_object(ROUTER_D)->eventDestruct(); + } + ret_string = ""; + write("The intermud router is disabled."); + return 1; + } +} + +varargs static int ModIntermud(string which, string arg){ + validate(); + write("Which: "+which+" arg: "+arg); + if(arg == "restrict"){ + write("Restricting intermud..."); + flush_messages(this_player()); + foreach(string element in config){ + if(grepp(element, "RESTRICTED_INTERMUD")) element = "#define RESTRICTED_INTERMUD 1"; + config2 += ({ element }); + } + CompleteConfig(); + reload(INTERMUD_D,0,1); + reload(IMC2_D,0,1); + reload("/daemon/services/tell",0,1); + reload("/daemon/services",0,1); + return 1; + } + + if(arg == "reset"){ + object ob = find_object(INTERMUD_D); + string savei3 = save_file(SAVE_INTERMUD); + write("Purging all intermud data (including router password!). Previous data file saved to /secure/save/backup/ ."); + if(!ob){ + if(file_exists(savei3)){ + rename(savei3, "/secure/save/backup/intermud."+time()); + } + } + else { + if(file_exists(savei3)){ + rename(savei3, "/secure/save/backup/intermud."+time()); + } + reload(INTERMUD_D,0,1); + } + config2 = config; + CompleteConfig(); + return 1; + } + + if(arg == "unrestrict"){ + write("Unrestricting intermud..."); + flush_messages(this_player()); + foreach(string element in config){ + if(grepp(element, "RESTRICTED_INTERMUD")) element = "#define RESTRICTED_INTERMUD 0"; + config2 += ({ element }); + } + CompleteConfig(); + reload(INTERMUD_D,0,1); + reload(IMC2_D,0,1); + reload("/daemon/services/tell",0,1); + return 1; + } + + if(member_array(arg,bools) == -1){ + write("Please try again, indicating whether you want to enable, disable, restrict, unrestrict, or reset intermud."); + return 1; + } + + if(member_array(arg,yesbools) != -1){ + write("Enabling intermud..."); + flush_messages(this_player()); + foreach(string element in config){ + if(grepp(element, "DISABLE_INTERMUD")) element = "#define DISABLE_INTERMUD 0"; + config2 += ({ element }); + } + CompleteConfig(); + reload(INTERMUD_D,0,1); + return 1; + } + + if(member_array(arg,nobools) != -1){ + write("Disabling intermud..."); + if(this_player()) flush_messages(this_player()); + foreach(string element in config){ + if(grepp(element, "DISABLE_INTERMUD")) element = "#define DISABLE_INTERMUD 1"; + config2 += ({ element }); + } + CompleteConfig(); + reload(INTERMUD_D,0,1); + return 1; + } + return 1; +} + +static int ProcessOther(string which, string arg){ + int junk; + validate(); + + if(sscanf(arg,"%d",junk) != 1){ + write("This parameter requires an integer as an argument."); + return 1; + } + + foreach(string element in config){ + if(grepp(element, which)){ + string s1, s2, s3; + if(sscanf(element,"#define %s %s",s1,s2) != 2){ + write("Major problem. You should revert to a backup of "+ + CONFIG_H+" immediately."); + return 1; + } + s3 = trim(s2); + s2 = replace_string(s2,s3,arg); + element = "#define "+s1+" "+s2; + } + config2 += ({ element }); + } + CompleteConfig(); + if(which == "LOCAL_TIME" || which == "EXTRA_TIME_OFFSET" || which == "GMT_OFFSET"){ + reload("/secure/sefun/local_time",0,1); + reload("/secure/sefun/time",0,1); + reload("/secure/sefun/timestamp",0,1); + reload("/secure/sefun/sefun",0,1); + RELOAD_D->eventReload("/daemon/time",2); + reload("/secure/cmds/creators/people",0,1); + reload("/cmds/players/date",0,1); + reload("/cmds/players/nextreboot",0,1); + reload("/cmds/players/version",0,1); + write("This configuration change will require a few minutes to take effect completely."); + } + if(which == "GLOBAL_MONITOR") reload(SNOOP_D,0,1); + if(which == "IDLE_TIMEOUT" || which == "MAX_NEWBIE_LEVEL" || + which == "FAST_COMBAT" || which == "GRID" || which == "WIZMAP" || + which == "MINIMAP"){ + reload(LIB_CREATOR,1,1); + write("This configuration will take effect for each user the next time they log in."); + return 1; + } + if(which == "PING_INTERVAL") reload (PING_D,1,1); + return 1; +} + +static int ProcessString(string which, string arg){ + object ob; + validate(); + + if(!strsrch(which, "IMC2_")){ + SECRETS_D->SetSecret(which, arg); + reload(SECRETS_D, 0, 1); + reload(IMC2_D, 0, 1); + config2 = config; + CompleteConfig(); + return 1; + } + + foreach(string element in config){ + if(grepp(element, which)){ + string s1, s2, s3; + if(sscanf(element,"#define %s %s",s1,s2) != 2){ + write("Major problem. You should revert to a backup of "+ + CONFIG_H+" immediately."); + return 1; + } + s3 = trim(s2); + s2 = replace_string(s2,s3,"\""+arg+"\""); + element = "#define "+s1+" "+s2; + } + config2 += ({ element }); + } + if(!strsrch(which, "WEB_SOURCE") + && ob = find_object(CMD_LIVEUPGRADE)){ + ob->eventDestruct(); + } + CompleteConfig(); + return 1; +} + +static int ProcessModal(string which, string arg){ + int junk; + validate(); + if(!arg){ + arg = "no"; + write("No argument: Assuming you want to disable this feature."); + } + if(member_array(arg,yesbools) != -1) junk = 1; + if(member_array(arg,nobools) != -1) junk = 0; + if(member_array(which,antimodals) != -1) junk = ( junk ^ 1 ); + + if(junk) junk = 1; + else junk = 0; + arg = itoa(junk); + + if(sscanf(arg,"%d",junk) != 1){ + write("This parameter is a modal or quasi-modal. I have a hunch it requires an integer as an argument, or at least a \"yes\" or \"no\"."); + return 1; + } + + if(member_array(upper_case(which),keywords) != -1){ + which = upper_case(which); + } + else switch(lower_case(which)){ + case "autowiz" : which = "AUTO_WIZ";break; + case "locked" : which = "MUD_IS_LOCKED";break; + case "localtime" : which = "LOCAL_TIME";break; + case "justenglish" : which = "ENGLISH_ONLY";break; + case "justhumans" : which = "HUMANS_ONLY";break; + case "encumbrance" : which = "ENABLE_ENCUMBRANCE";break; + case "pk" : which = "PLAYER_KILL";break; + case "compat" : which = "COMPAT_MODE";break; + case "retain" : which = "RETAIN_ON_QUIT";break; + case "defaultparse" : which = "DEFAULT_PARSING";break; + case "disablereboot" : which = "DISABLE_REBOOTS";break; + case "exitsbare" : which = "BARE_EXITS";break; + case "nmexits" : which = "NM_STYLE_EXITS";break; + case "matchcommand" : which = "COMMAND_MATCHING";break; + case "matchobject" : which = "OBJECT_MATCHING";break; + case "catchtell" : which = "NPC_CATCH_TELL_DEBUG";break; + case "loglocal" : which = "LOG_LOCAL_CHANS";break; + case "logremote" : which = "LOG_REMOTE_CHANS";break; + case "imc2" : which = "DISABLE_IMC2";break; + case "fastcombat" : which = "FAST_COMBAT";break; + case "channelpipes" : which = "CHANNEL_PIPES";break; + case "cgi" : which = "ENABLE_CGI";break; + case "dirlist" : which = "WWW_DIR_LIST";break; + case "creweb" : which = "ENABLE_CREWEB";break; + case "selectclass" : which = "CLASS_SELECTION";break; + case "severable" : which = "SEVERABLE_LIMBS";break; + case "questrequired" : which = "REQUIRE_QUESTING";break; + case "autoadvance" : which = "AUTO_ADVANCE";break; + case "ced" : which = "CED_DISABLED";break; + case "minimap" : which = "MINIMAP";break; + case "wizmap" : which = "WIZMAP";break; + case "grid" : which = "GRID";break; + case "guestallowed" : which = "GUEST_ALLOWED";break; + case "playerintertell" : which = "PLAYER_INTERTELL_ALLOWED";break; + case "guest" : which = "GUEST_ALLOWED";break; + default : break; + } + foreach(string element in config){ + if(grepp(element, which)){ + string s1, s2, s3; + if(sscanf(element,"#define %s %s",s1,s2) != 2){ + write("Major problem. You should revert to a backup of "+ + CONFIG_H+" immediately."); + return 1; + } + s3 = trim(s2); + s2 = replace_string(s2,s3,arg); + element = "#define "+s1+" "+s2; + } + config2 += ({ element }); + } + CompleteConfig(); + if(which == "DEFAULT_PARSING" || which == "ENABLE_ENCUMBRANCE" || + which == "BARE_EXITS" || which == "COMMAND_MATCHING" || + which == "AUTO_ADVANCE"){ + reload(LIB_CREATOR,1,1); + write("This configuration will take effect for each user the next time they log in."); + return 1; + } + if(which == "NPC_CATCH_TELL_DEBUG"){ + if(file_exists("/domains/default/room/catchtell")) + reload("/domains/default/room/catchtell"); + return 1; + } + if(which == "CED_DISABLED"){ + reload(CMD_CED,1,1); + reload(LIB_CREATOR,1,1); + write("This configuration will take effect for each user "+ + "the next time they log in."); + } + if(which == "NM_STYLE_EXITS"){ + reload(LIB_ROOM,1,1); + reload(LIB_CREATOR,1,1); + write("This configuration will take effect for rooms not yet loaded for each " + "user the next time they log in. To ensure all rooms pick up the new configuration, " + "either reboot the mud, or type: \"reload every room\", then quit and log back in."); + } + if(which == "RETAIN_ON_QUIT" || which == "OBJECT_MATCHING") + write("To make this configuration take effect, reboot the mud."); + if(which == "LOG_LOCAL_CHANS" || which == "LOG_REMOTE_CHANS"){ + reload(CHAT_D,1,1); + } + if(which == "DISABLE_IMC2"){ + object ob; + IMC2_D->UnSetAutoDisabled(1); + ob = find_object(IMC2_D); + if(!junk && ob){ + reload(ob, 0, 1); + reload(find_object(CHAT_D), 0, 1); + } + else IMC2_D->remove(); + } + if(which == "FAST_COMBAT"){ + reload(LIB_CREATOR,1,1); + write("This configuration will take effect for each user the next time they log in."); + } + + if(which == "ENABLE_CGI" || which == "WWW_DIR_LIST" || which == "ENABLE_CREWEB"){ + reload(WEB_SESSIONS_D,1,1); + reload(SOCKET_HTTP,1,1); + foreach(string element in get_dir(DIR_WWW_GATEWAYS+"/")){ + if(last(element,2) == ".c") reload(DIR_WWW_GATEWAYS+"/"+element,1,1); + } + } + return 1; +} + +int ProcessService(string which, string what){ + int port_offset, type, port; + string sclass; + if(sscanf(what,"port %d",port)){ + what = "port"; + } + switch(which){ + case "hftp": port_offset=OFFSET_HFTP;sclass="/secure/lib/net/h_ftpd";type=1;break; + case "ftp": port_offset=OFFSET_FTP;sclass="/secure/lib/net/ftp";type=1;break; + case "http": port_offset=OFFSET_HTTP;sclass="/secure/lib/net/http";type=3;break; + case "rcp": port_offset=OFFSET_RCP;sclass="/secure/lib/net/remote";type=1;break; + case "oob": port_offset=OFFSET_OOB;sclass="/secure/lib/net/oob";type=0;break; + } + switch(what){ + case "add": INET_D->AddService(which,port_offset, sclass, type);break; + case "remove": INET_D->RemoveService(which);break; + case "start": INET_D->eventStartServer(which);break; + case "restart": INET_D->eventRestartServer(which,1);break; + case "stop": INET_D->eventStopServer(which);break; + case "port": ModPort(which, port);break; + } + if(which == "oob"){ + if( what == "start" || what == "restart") + reload(OOB_D); + if( what == "stop" ) + OOB_D->eventDestruct(); + } + write("Done."); + return 1; +} + +int ProcessInet(string which, string arg){ + int sub; + string preloads = read_file(CFG_PRELOAD); + string *load_lines = explode(preloads,"\n"); + string *ret_arr = ({}); + string yesline = "/secure/daemon/inet"; + string noline = "#/secure/daemon/inet"; + validate(); + if(!arg) arg = "status"; + if(which != "inet"){ + sub = 1; + if(!find_object(INET_D)){ + write("The inet service is not running. Please type: mudconfig inet start"); + write("Or: mudconfig inet enable"); + write("Then retry your command."); + return 1; + } + } + else { + if(member_array(arg,yesbools) != -1){ + if(member_array(yesline,load_lines) != -1) { + write("Persistent inet activation is already enabled."); + return 1; + } + else { + write("Enabling persistent inet activation."); + foreach(string line in load_lines){ + if(line == noline) line = yesline; + ret_arr += ({ line }); + } + if(member_array(yesline,ret_arr) == -1){ + ret_arr += ({ yesline }); + } + unguarded( (: cp(CFG_PRELOAD,"/secure/save/backup/preload."+time()) :) ); + ret_string = implode(ret_arr,"\n")+"\n"; + ret_string = replace_string(ret_string,"\n\n","\n"); + unguarded( (: write_file(CFG_PRELOAD,ret_string,1) :) ); + write("The inet service is enabled."); + arg = "start"; + } + } + + if(member_array(arg,nobools) != -1){ + if(member_array(noline,load_lines) != -1){ + write("Persistent inet activation is already disabled."); + return 1; + } + else { + write("Disabling persistent inet activation."); + foreach(string line in load_lines){ + + if(line == yesline) line = noline; + ret_arr += ({ line }); + } + if(member_array(noline,ret_arr) == -1){ + ret_arr += ({ noline }); + } + unguarded( (: cp(CFG_PRELOAD,"/secure/save/backup/preload."+time()) :) ); + ret_string = implode(ret_arr,"\n")+"\n"; + ret_string = replace_string(ret_string,"\n\n","\n"); + unguarded( (: write_file(CFG_PRELOAD,ret_string,1) :) ); + write("The inet service is disabled."); + arg = "stop"; + } + } + + if(arg == "start"){ + if(find_object(INET_D)) write("The inet service is already running."); + else { + write("Starting the inet service."); + load_object(INET_D); + } + } + else if(arg == "stop"){ + if(!find_object(INET_D)) write("The inet service is already stopped."); + else { + write("Stopping the inet service."); + find_object(INET_D)->eventDestruct(); + } + } + else if(arg == "restart"){ + if(find_object(INET_D)) { + write("The inet service is running. Stopping it now..."); + find_object(INET_D)->eventDestruct(); + } + write("Starting the inet service."); + load_object(INET_D); + } + else if(arg == "status"){ + if(member_array(yesline,load_lines) != -1){ + write("Persistent inet activation is enabled."); + } + else { + write("Persistent inet activation is disabled."); + } + + if(!find_object(INET_D)){ + write("The inet service is not running"); + } + else{ + string *servkeys, *servkeys2; + string subret = "The following services are available: "; + string subret2 = "The following services are running: "; + write("The inet service is running"); + if(sizeof(servkeys = keys(INET_D->GetServices()))){ + subret += implode(servkeys,", ")+".\n"; + } + else subret = ""; + if(sizeof(servkeys2 = keys(INET_D->GetServers()))){ + subret2 += implode(servkeys2,", ")+".\n"; + } + else subret2 = ""; + write(subret+subret2); + return 1; + } + ret_string = ""; + write("Done."); + return 1; + } + else write("Unsupported inet subcommand."); + return 1; + } + if(arg == "enable"){ + if(INET_D->GetService(which)){ + write("The "+which+" service is already enabled. Perhaps you mean to start or restart it?"); + return 1; + } + ProcessService(which,"add"); + return 1; + } + if(arg == "disable"){ + if(!(INET_D->GetService(which))){ + write("The "+which+" service is already disabled."); + return 1; + } + ProcessService(which,"remove"); + return 1; + } + + if(arg == "start"){ + if(INET_D->GetServer(which)){ + write("The "+which+" service is already started. Perhaps you mean to restart it?"); + return 1; + } + if(!(INET_D->GetService(which))){ + write("The "+which+" service has been disabled or is not available."); + return 1; + } + ProcessService(which,"start"); + return 1; + } + if(arg == "stop"){ + if(!(INET_D->GetService(which))){ + write("The "+which+" service is already disabled and therefore not running."); + return 1; + } + if(!(INET_D->GetServer(which))){ + write("The "+which+" service is already stopped."); + return 1; + } + ProcessService(which,"stop"); + return 1; + } + + if(arg == "restart"){ + ProcessService(which,"restart"); + return 1; + } + if(arg == "status"){ + write("The "+which+" service is "+(INET_D->GetService(which) ? "enabled." : "disabled.")); + if(INET_D->GetService(which)) + write("The "+which+" service is "+(INET_D->GetServer(which) ? "running." : "stopped.")); + return 1; + } + if(!strsrch(arg,"port ")){ + ProcessService(which,arg); + return 1; + } + write("Unsupported mudconfig inet service subcommand."); + return 1; +} + +varargs static int ModCfg(string which, string arg){ + int port, oldport, newport, ret, justbooted; + string *line_array; + string mconfig, nameline, portline, newline, newfile; + string line_string, junk, name; + object i3, imc2; + + justbooted = uptime() - 62; + if(justbooted < -1){ + write("Please wait "+abs(justbooted)+" seconds and try again."); + return 1; + } + + if(!find_object(INSTANCES_D) || !ENABLE_INSTANCES || + INSTANCES_D->GetMyInstanceName() == "global"){ + port = 0; + mconfig = "/secure/cfg/mudos.cfg"; + } + else { + port = query_host_port(); + mconfig = "/secure/cfg/mudos."+port+".cfg"; + } + line_string = read_file(mconfig); + if(!sizeof(line_string)) write("Couldn't read file."); + line_array = explode(line_string, "\n"); + if(!sizeof(line_array)) write("Array is zero length."); + + if(!sizeof(line_array) || !sizeof(line_string)) { + return 1; + } + + foreach(string line in line_array){ + if(!strsrch(line,"name :")){ + nameline = line; + if(which == "name") break; + } + if(!strsrch(line,"external_port_")){ + portline = line; + if(which == "port"){ + newport = atoi(arg); + break; + } + } + } + + if(which == "name"){ + if(!nameline || sscanf(nameline,"%s : %s",junk, name) < 2) { + write("Operation failed. You need to copy over "+ + mconfig+" immediately with an original."); + return 1; + } + + newline = junk + " : " + arg; + newfile = replace_string(line_string, nameline, newline); + write_file(mconfig,newfile,1); + cp(mconfig,"/secure/cfg/mudos.autobak."+query_host_port()); + if(query_windows()){ + if(port){ + cp(mconfig,"/secure/cfg/mudos."+port+".win32"); + } + else { + cp(mconfig,"/secure/cfg/mudos.win32"); + } + } + imc2 = find_object(IMC2_D); + i3 = find_object(INTERMUD_D); + if(imc2) imc2->eventDestruct(); + if(i3) i3->eventDestruct(); + if(imc2) destruct(imc2); + if(i3) destruct(i3); + ret = MASTER_D->SetMudName(arg); + write("\n"); + write("\nMUD's name is now: "+mud_name()); + if(!DISABLE_IMC2){ + write("Reloading IMC2..."); + catch(reload(IMC2_D, 0, 1)); + } + if(!DISABLE_INTERMUD){ + write("Reloading Intermud-3..."); + catch(reload(INTERMUD_D, 0, 1)); + } + catch(reload(PING_D, 0, 1)); + } + + if(which == "port"){ + if(!portline || sscanf(portline,"%s : telnet %d",junk, oldport) < 2){ + write("Operation failed. You need to copy over "+ + "/secure/cfg/mudos.cfg immediately with an original."); + return 1; + } + + newline = junk + " : telnet " + newport; + newfile = replace_string(line_string, portline, newline); + write_file("/secure/cfg/mudos.cfg",newfile,1); + cp(mconfig,"/secure/cfg/mudos.autobak."+query_host_port()); + if(query_windows()){ + if(port){ + cp(mconfig,"/secure/cfg/mudos."+newport+".win32"); + } + else { + cp(mconfig,"/secure/cfg/mudos.win32"); + } + } + write("\nMUD's port changed. Reboot the MUD to activate new port."); + write("NOTE: If the port you selected is 1024 or below, your OS "+ + "may require the MUD to run as a privileged user."); + } + return 1; +} + +string GetHelp(){ + return ("Syntax: mudconfig PARAMETER VALUE \n\n" + "Modifies various system settings.\n" + "Examples: \n" + "\nmudconfig autowiz [ yes | no ]" + "\nmudconfig locked [ yes | no ]" + "\nmudconfig justenglish [ yes | no ]" + "\nmudconfig justhumans [ yes | no ]" + "\nmudconfig encumbrance [ yes | no ]" + "\nmudconfig severable [ yes | no ] (whether limbs can be " + "severed in combat. Requires a warmboot.)" + "\nmudconfig pk [ yes | no ]" + "\nmudconfig minimap [ yes | no ] (whether players get a minimap)" + "\nmudconfig wizmap [ yes | no ] (whether cres get an area map)" + "\nmudconfig grid [ yes | no ] (enable or disable the room grid " + "system)" + "\nmudconfig compat [ yes | no ]" + "\nmudconfig retain [ yes | no ]" + "\nmudconfig defaultparse [ yes | no ]" + "\nmudconfig disablereboot [ yes | no ]" + "\nmudconfig matchcommand [ yes | no ]" + "\nmudconfig matchobject [ yes | no ]" + "\nmudconfig exitsbare [ yes | no ]" + "\nmudconfig nmexits [ yes | no ] (This togggles where default " + "exits are displayed)" + "\nmudconfig fastcombat [ yes | no ] (heart rate overridden " + "in combat)" + "\nmudconfig selectclass [ yes | no ] (whether new players " + "choose a class on login)" + "\nmudconfig instances [ yes | no ] (whether mud instances " + "are used)" + "\nmudconfig localtime [ yes | no ]" + "\nmudconfig offset <offset from gmt in seconds>" + "\nmudconfig extraoffset <offset from GMT in hours>" + "\nmudconfig maxcommands <max number of commands per second>" + "\nmudconfig maxidle <number of idle seconds before autoquit>" + "\nmudconfig questrequired [ yes | no ]" + "\nmudconfig autoadvance [ yes | no ]" + "\nmudconfig guestallowed [ yes | no ]" + "\nmudconfig playerintertell [ yes | no ]" + "\nmudconfig ced [ yes | no ] (toggles the fullscreen editor)" + "\nmudconfig maxip <max connections per IP>" + "\nmudconfig pinginterval <i3 ping interval in seconds>" + "\nmudconfig monitor <monitoring level, 0 to 2>" + "\nmudconfig newbielevel <max newbie level>" + "\nmudconfig resets <interval between resets>" + "\nmudconfig router [ enable | disable ]" + "\nmudconfig startroom <filename of start room>" + "\nmudconfig defaultdomain </full/path>" + "\nmudconfig email <the admin's email address>" + "\nmudconfig liveupgrade <the default liveupgrade mud's name>" + "\nmudconfig hostip <the computer's ip address " + "(eg 111.222.333.444)>" + "\nmudconfig websourceip <the remote web server's ip address " + "(eg 111.222.333.444)>" + "\nmudconfig websourcename <the remote web server's ip name " + "(eg a.b.com)>" + "\nmudconfig channelpipes [ enable | disable ] (whether to allow " + "piping messages. not recommended.)" + "\nmudconfig intermud [ enable | disable | restrict | " + "unrestrict | reset ]" + "\nmudconfig imc2 [ enable | disable ]" + "\nmudconfig imc2clientpass <client password for IMC2>" + "\nmudconfig imc2serverpass <server password for IMC2>" + "\nmudconfig inet [ enable | disable | start | stop | restart " + "| status ]" + "\nmudconfig ftp [ enable | disable | start | stop | restart " + "| status ]" + "\nmudconfig hftp [ enable | disable | start | stop | restart " + "| status ]" + "\nmudconfig rcp [ enable | disable | start | stop | restart " + "| status ]" + "\nmudconfig oob [ enable | disable | start | stop | restart " + "| status ]" + "\nmudconfig http [ enable | disable | start | stop | restart " + "| status ]" + "\nmudconfig cgi [ enable | disable ] (Whether the mud webserver " + "should use CGI)" + "\nmudconfig dirlist [ enable | disable ] (Allow the webserver " + "to display dir contents)" + "\nmudconfig creweb [ enable | disable ] (Allow web based " + "editing [requires cgi and dirlist])" + "\nmudconfig loglocal [ enable | disable ] (whether local " + "channels are logged)" + "\nmudconfig logremote [ enable | disable ] (whether remote " + "channels are logged)" + "\nmudconfig mudname <name>" + "\nmudconfig mudport <port>" + "\n\nSee also: admintool, config"); +} + diff --git a/lib/secure/cmds/admins/notify.c b/lib/secure/cmds/admins/notify.c new file mode 100644 index 0000000..1ea0717 --- /dev/null +++ b/lib/secure/cmds/admins/notify.c @@ -0,0 +1,58 @@ +/* /cmds/secure/admin/notify + * from the Dead Souls Mud Library + * created by Blitz@Dead Souls 950115 + */ + +#include <lib.h> +#include <daemons.h> + + +varargs private void eventNotify(object who, string text); + +mixed cmd(string str) { + object ob = previous_object(); + string who; + + if(!archp(previous_object())) return 0; + if( !ob ) return 0; + who = ob->GetKeyName(); + if( sizeof(str) ) { + eventNotify(ob, str); + return 1; + } + ob->eventPrint("[ Dead Souls Notification System ]"); + ob->eventPrint("Please compose your notification now. \n"); + ob->eventEdit(DIR_TMP + "/" +who+ ".notice", (: eventNotify, ob, 0 :)); + return 1; +} + +varargs private void eventNotify(object who, string text) { + int x; + string file, str; + if( !who ) return; + if( !text ) { + string * lines; + file = DIR_TMP + "/" +who->GetKeyName() + ".notice"; + if( file_size(file) < 1 ) return; + str = read_file(file); + str = implode(filter(lines = explode(str, "\n"), (: sizeof :)), "\n"); + rm(file); + } else str = text; + if( !sizeof(str) ) return; + x = NOTIFY_D->eventAddNotice(who, str); + if( x ) + who->eventPrint("Your notice [id #"+(x-1)+"] has been posted!"); + else + who->eventPrint("Error adding notice."); +} + +string GetHelp(){ + return ("Syntax: notify\n" + " notify <message>\n\n" + "This command allows users with proper access to " + "add a message to a database of notifications. " + "All new notifications are displayed to any creator " + "upon login. Typing \"notify\" alone will put you " + "into the text editor. Otherwise, the passed " + "message will be used."); +} diff --git a/lib/secure/cmds/admins/opcprof.c b/lib/secure/cmds/admins/opcprof.c new file mode 100644 index 0000000..77d5e2f --- /dev/null +++ b/lib/secure/cmds/admins/opcprof.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include <dirs.h> + +inherit LIB_DAEMON; + +int cmd(string arg) +{ + if(!archp(previous_object())) return 0; + unguarded( (: opcprof("/log/opcprof.out") :) ); + write("Please review /log/opcprof.out.efun and "+ + "/log/opcprof.out.eoper to see the output of this command."); + + return 1; +} + +string GetHelp(){ + return ("Syntax: opcprof\n\n" + "Puts a list of efuns and eoperators in /log/opcprof.out.*\n " + "See man: opcprof\n" + "See also: fdinfo, netstat, mstatus, cache, callouts, dumpallobj,"); +} diff --git a/lib/secure/cmds/admins/pause.c b/lib/secure/cmds/admins/pause.c new file mode 100644 index 0000000..d806efe --- /dev/null +++ b/lib/secure/cmds/admins/pause.c @@ -0,0 +1,45 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + object ob; + args = lower_case(args); + if(!user_exists(args)) return capitalize(args) + " is not a member of " + + possessive_noun(mud_name()) + " reality."; + WEB_SESSIONS_D->EndSession(args); + if(!ob = find_player(args)){ + if(member_array(args, PLAYERS_D->GetPendingUnpauses()) != -1){ + PLAYERS_D->RemovePendingUnpause(args); + write("Pending unpause for "+capitalize(args)+" removed."); + } + if(PLAYERS_D->GetPlayerData(args, "Paused")){ + return capitalize(args) + " is already paused."; + } + if(member_array(args, PLAYERS_D->GetPendingPauses()) != -1){ + return capitalize(args) + " is already pending a pause."; + } + PLAYERS_D->AddPendingPause(args); + write(capitalize(args)+" will be paused next time they log in."); + return 1; + } + if(ob == this_player()){ + write("You can't pause yourself."); + return 1; + } + if(ob->GetPlayerPaused()){ + write(capitalize(args) + " is already paused!"); + return 1; + } + write("You pause "+capitalize(args)+"."); + ob->SetPlayerPaused(1); + ob->eventPrint("You have been paused. Commands will not work until you are unpaused."); + return 1; +} + +string GetHelp(){ + return ("Syntax: pause <PLAYER>\n\n" + "Causes the player to be unable to run any commands. Useful for " + "immediately halting problem behavior."); +} diff --git a/lib/secure/cmds/admins/register.c b/lib/secure/cmds/admins/register.c new file mode 100644 index 0000000..ce5e092 --- /dev/null +++ b/lib/secure/cmds/admins/register.c @@ -0,0 +1,74 @@ +// /bin/adm/_register.c +// from the Dead Souls mudlib +// for restricting access for certain sites +// created by Shadowwolf@Dead Souls? +// Edit stuff added by Manny@Dead Souls 940819 + +#include <lib.h> +#include <daemons.h> +#include <dirs.h> + +inherit LIB_DAEMON; + +void end_edit(string site); +void abort(); + +int cmd(string str) { + if(!archp(previous_object())) return 0; + if(!str) { + notify_fail("Syntax: register <site-ip>\n\n"); + return 0; + } + write("%^RED%^Enter all applicable information, including names, " + "offenses and email addresses."); + rm(DIR_TMP+"/"+this_player()->GetKeyName()+".tmp"); + this_player()->eventEdit( DIR_TMP "/" + this_player()->GetKeyName(), + (: end_edit($(str)) :)); + return 1; +} + +void end_edit(string site) { + string *lines; + string tmpfile, res, str; + int x, num; + + tmpfile = read_file(DIR_TMP+"/"+this_player()->GetKeyName()); + rm(DIR_TMP+"/"+this_player()->GetKeyName()); + if(tmpfile){ + tmpfile = replace_string(tmpfile, "\n", " "); + } + else { + write("Nothing written. Registration operation cancelled."); + return; + } + num = sizeof(lines = explode(wrap(tmpfile, 60), "\n")); + str = " - "+site+" placed on Registration\n"; + str += " by "+previous_object()->GetName()+": "+ + ctime(time())+"\n"; + for(x=0; x<num; x++) + str += " * "+lines[x]+"\n"; + + if(res = catch(call_other(BANISH_D, "register_site", site))) + write("Error in registering site: "+res+"\n"); + + log_file("watch/register", "\n" + str); + write("%^RED%^%^BOLD%^"+site+" is now on registration!"); +} + +void abort() { + rm(DIR_TMP+"/"+this_player()->GetKeyName()+".tmp"); + write("%^RED%^Site not registered!"); +} + +string GetHelp(){ + return "Syntax: register <site>\n\n" + "Makes a given site needs to register their characters with " + "law before being able to play the mud. A reason must be given " + "and it must be good. In general, only law should be using " + "this command. And if you are not law, you better mail law. " + "This command only works with numeric addresses, ie:\n" + " register 134.181.* ok\n" + " register 134.181.1.12 ok\n" + " register orlith.bates.edu BAD\n" + "See also: unbanish, whobanished, whoregistered, whowatched"; +} diff --git a/lib/secure/cmds/admins/removeadverb.c b/lib/secure/cmds/admins/removeadverb.c new file mode 100644 index 0000000..cadeb39 --- /dev/null +++ b/lib/secure/cmds/admins/removeadverb.c @@ -0,0 +1,32 @@ +/* /secure/cmds/admins/removeadverb.c + * From the Dead Souls Mud Library + * Command for removing adverbs from the soul + * Created by Descartes of Borg 961214 + * Version: @(#) removeadverb.c 1.1@(#) + * Last modified: 96/12/14 + */ + +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + if( !args || args == "" ) { + return "Remove which adverb?"; + } + if( !SOUL_D->RemoveAdverb(args) ) { + previous_object()->eventPrint("Removal of adverb failed."); + return 1; + } + previous_object()->eventPrint("Adverb removed."); + return 1; +} + +string GetHelp(){ + return ("Syntax: removeadverb <ADVERB>\n\n" + "Allows you to remove an adverb from the list of" + "system adverbs that can be used as adverbs in most soul " + "commands.\n" + "See also: addadverb, addemote, removeemote"); +} diff --git a/lib/secure/cmds/admins/removeclass.c b/lib/secure/cmds/admins/removeclass.c new file mode 100644 index 0000000..8d10c12 --- /dev/null +++ b/lib/secure/cmds/admins/removeclass.c @@ -0,0 +1,25 @@ +/* /secure/cmds/admins/removeclass.c + * from the NIghtmare V Object Library + * removes classes + * created by Descartes of Borg 960528 + * Version: %I% + * Last Modified: %D% + */ + +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + if( !args || args == "" ) return "Syntax: <removeclass CLASS>"; + CLASSES_D->RemoveClass(args); + previous_object()->eventPrint("Class removed."); + return 1; +} + +string GetHelp(){ + return ("Syntax: removeclass <CLASS>\n\n" + "Removes a class from the game.\n" + "See also: addclass, addemote, addrace, removerace"); +} diff --git a/lib/secure/cmds/admins/removeclasses.c b/lib/secure/cmds/admins/removeclasses.c new file mode 100644 index 0000000..706b9c7 --- /dev/null +++ b/lib/secure/cmds/admins/removeclasses.c @@ -0,0 +1,19 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + foreach(string str in CLASSES_D->GetClasses()){ + CLASSES_D->RemoveClass(str); + } + write("Done."); + return 1; +} + +string GetHelp(){ + return ("Syntax: removeclasses\n\n" + "Gets rid of ALL classes known by the classes daemon. " + "Unless you want to be very sad later, you should " + "add your classes with the addclasses command immediately. "); +} diff --git a/lib/secure/cmds/admins/removeguest.c b/lib/secure/cmds/admins/removeguest.c new file mode 100644 index 0000000..e8a24ad --- /dev/null +++ b/lib/secure/cmds/admins/removeguest.c @@ -0,0 +1,34 @@ +// /bin/adm/_removeguest.c +// from the Dead Souls Mudlib +// removes a person from the guest list for when the mud is locked +// created by Descartes of Borg 08 july 1993 + +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +int cmd(string str) { + string *guests; + int i; + + if(!archp(previous_object())) return 0; + if(!str) { + notify_fail("Correct syntax: removeguest [guestlist]\n"); + return 0; + } + i = sizeof(guests = explode(str, " ")); + while(i--) BANISH_D->remove_guest(guests[i]); + message("info", "Guests removed.", this_player()); + return 1; +} + +string GetHelp(){ + return ("Syntax: removeguest [player list]\n\n" + "Removes a single player or a list of players from the guests " + "allowed onto the mud when it is locked. This function is " + "generally used to " + "remove access a player might have been granted by the addguest " + "command.\n" + "See also: addguest, whoguests"); +} diff --git a/lib/secure/cmds/admins/removerace.c b/lib/secure/cmds/admins/removerace.c new file mode 100644 index 0000000..78bb60c --- /dev/null +++ b/lib/secure/cmds/admins/removerace.c @@ -0,0 +1,25 @@ +/* /secure/cmds/admins/removerace.c + * from the NIghtmare V Object Library + * removes races + * created by Descartes of Borg 960528 + * Version: %I% + * Last Modified: %D% + */ + +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + if( !args || args == "" ) return "Syntax: removerace <RACE>"; + RACES_D->RemoveRace(args); + previous_object()->eventPrint("Race removed."); + return 1; +} + +string GetHelp(string str) { + return ("Syntax: removerace <RACE>\n\n" + "Removes a race from the game.\n" + "See also: addclass, addemote, addrace, removeclass"); +} diff --git a/lib/secure/cmds/admins/removeraces.c b/lib/secure/cmds/admins/removeraces.c new file mode 100644 index 0000000..8f4b95b --- /dev/null +++ b/lib/secure/cmds/admins/removeraces.c @@ -0,0 +1,19 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + foreach(string str in RACES_D->GetRaces()){ + RACES_D->RemoveRace(str); + } + write("Done."); + return 1; +} + +string GetHelp(){ + return ("Syntax: removeraces\n\n" + "Gets rid of ALL races known by the race daemon. " + "Unless you want to be very sad later, you should " + "add your races with the addraces command immediately. "); +} diff --git a/lib/secure/cmds/admins/resetall.c b/lib/secure/cmds/admins/resetall.c new file mode 100644 index 0000000..30c46ae --- /dev/null +++ b/lib/secure/cmds/admins/resetall.c @@ -0,0 +1,40 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_DAEMON; + +int cmd(string str) { + object *rooms = ({}); + + write("Compiling list of loaded rooms..."); + flush_messages(this_player()); + + rooms = filter(objects(), (: inherits(LIB_ROOM, $1) :) ); + + + if(archp(previous_object())){ + + foreach(object room in rooms){ + write("Updating: "+base_name(room)); + update(base_name(room)); + } + + update(ROOM_FURNACE); + reap_other(); + reap_other(); + + write("Done."); + + return 1; + } + write("You are not admin. This is command forbidden."); + return 1; +} + +string GetHelp() { + return ("Syntax: resetall\n\n" + "Unloads and reloads all rooms currently in memory. " + "This tends to destroy all non-interactive objects in " + "the rooms, and dumps all players at the start room " + "or The Void, so use this command with caution."); +} diff --git a/lib/secure/cmds/admins/resetpasswd.c b/lib/secure/cmds/admins/resetpasswd.c new file mode 100644 index 0000000..fdbaddc --- /dev/null +++ b/lib/secure/cmds/admins/resetpasswd.c @@ -0,0 +1,98 @@ +#include <lib.h> +#include <dirs.h> +#include <flags.h> +#include <message_class.h> + +inherit LIB_DAEMON; + +static void NewPass(string pass); +static void ConfirmPass(string str, string newpass); + +string savefile; + +mixed cmd(string args) { + + if(!archp(previous_object())) { + write("No."); + return 1; + } + + if(!args || !sizeof(args)) args = "me"; + + args = lower_case(args); + + if(args == "me" || args == this_player()->GetKeyName()){ + write("To reset your own password, use the command: passwd"); + return 1; + } + + if( previous_object()->GetForced() ) + return "You cannot be forced to change a password."; + if( previous_object() != this_player() ) + return "You're being sploited to reset someone's password."; + + if(!user_exists(args)){ + write("That person does not exist on this mud."); + return 1; + } + + if(find_player(args)){ + write("That player is currently logged on. Please use " + "the passwd command to reset their password."); + return 1; + } + + savefile = save_file(DIR_CRES + "/" + args[0..0] + "/" + args); + if(!file_exists(savefile)){ + write("Couldn't find "+savefile+". Looking for alternate."); + savefile = save_file(DIR_PLAYERS + "/" + args[0..0] + "/"+ args); + } + + if(!file_exists(savefile)){ + write("Save file could not be found. Exiting."); + return 1; + } + + write("Found "+savefile+"."); + + previous_object()->eventPrint("New password: ", MSG_PROMPT); + input_to( (: NewPass :), I_NOECHO | I_NOESC, previous_object() || args); + return 1; +} + +static void NewPass(string pass) { + if( !pass || strlen(pass) < 5 ) { + this_player()->eventPrint("Password must be at least 5 " + "characters, password change failed.", + MSG_SYSTEM); + return; + } + this_player()->eventPrint("\nConfirm: ", MSG_PROMPT); + input_to( (: ConfirmPass :), I_NOECHO | I_NOESC, pass); +} + +static void ConfirmPass(string str, string newpass) { + string *lines; + if( str != newpass ) { + this_player()->eventPrint("Passwords do not match.", MSG_SYSTEM); + return; + } + + lines = explode(unguarded((: read_file, savefile :)),"\n"); + unguarded((: rm, savefile :)); + foreach(string line in lines) { + string val; + + if( sscanf(line, "Password %s", val) ) + line = "Password \"" + crypt(newpass, 0) + "\""; + unguarded((: write_file, savefile, line + "\n" :)); + } + this_player()->eventPrint("\nPassword changed.", MSG_SYSTEM); +} + +string GetHelp() { + return ("Syntax: resetpasswd <player>\n\n" + "Allows you to change someone's password if they " + "are not logged on.\n" + "See also: passwd"); +} diff --git a/lib/secure/cmds/admins/rid.c b/lib/secure/cmds/admins/rid.c new file mode 100644 index 0000000..7b2a882 --- /dev/null +++ b/lib/secure/cmds/admins/rid.c @@ -0,0 +1,92 @@ +/* /secure/cmds/adm/rid.c + * from the Dead Souls Object Library + * command to get rid of players + * created by Descartes of Borg 951015 + */ + +#include <lib.h> +#include <dirs.h> +#include <daemons.h> +#include <privs.h> + +inherit LIB_DAEMON; + +varargs static void EndRid(string str, string reason); + +varargs int cmd(string who, string reason) { + object ob = previous_object(); + string str, file, targetdir; + + if(!archp(ob) && base_name(ob) != PLAYERS_D) return 0; + if( !who || who == "" ) { + write("Rid whom?"); + return 1; + } + + str = convert_name(who); + who = capitalize(who); + if( member_group(str, PRIV_SECURE) || member_group(str, PRIV_ASSIST) ){ + write("You must first remove this person from a secure group."); + return 1; + } + + if( !user_exists(str) ) { + write("No such person: " + who + "."); + return 1; + } + + if( ob = find_player(str) ) { + who = ob->GetCapName(); + message("system", "You are being ridded from " + mud_name() + ".", + ob); + if( !(ob->eventDestruct()) ) destruct(ob); + } + file = player_save_file(str); + targetdir = DIR_RID + "/" + str[0..0] + "/" + str; + mkdir_recurse(targetdir); + if( rename(file, save_file(targetdir + "/" + str + ".bak")) ) { + write("Rename failed, security violation logged."); + log_file("security", "\n*****\nRid violation attempted\n" + "Target: " + who + "\nCall stack:\n" + + sprintf("%O\n", previous_object(-1))); + return 1; + } + + if(reason){ + EndRid(who, reason); + return 1; + } + + write("Enter reason for ridding " + who + "."); + file = DIR_TMP + "/" + this_player()->GetKeyName(); + rm(file); + this_player()->eventEdit(file, (: EndRid, who :)); + return 1; +} + +varargs static void EndRid(string who, string reason) { + string file, str, actor; + object foo = previous_object(); + + if(this_player()) actor = this_player()->GetCapName(); + else if(foo) actor = base_name(foo); + else actor = "UNKNOWN"; + + if(!reason){ + file = DIR_TMP + "/" + this_player()->GetKeyName(); + if( !(str = read_file(file)) ) str = "No comment.\n"; + } + else str = reason; + log_file("rid", "\n" + who + " by " + actor + + "\n" + str + "\n"); + write(who + " has been ridded from " + mud_name() + "."); + PLAYERS_D->RemovePendingEncre(lower_case(who)); + PLAYERS_D->RemoveUser(lower_case(who)); +} + +string GetHelp(){ + return "Syntax: rid <name>\n\n" + "Deletes, nukes, wipes out and annhilates unwanted player <name>\n" + "See also: demote, promote, sponsor"; +} + diff --git a/lib/secure/cmds/admins/rotatelogs.c b/lib/secure/cmds/admins/rotatelogs.c new file mode 100644 index 0000000..ca4e3ea --- /dev/null +++ b/lib/secure/cmds/admins/rotatelogs.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +int cmd(string arg) { + int ret; + int force = 0; + if(arg) force = 1; + ret = LOG_D->RotateLogs(force); + if(ret){ + write("Logs rotated."); + } + else { + write("Failed to rotate logs."); + } + return 1; +} + +string GetHelp(){ + return ("Syntax: rotatelogs <force>\n\n" + "Archives old logs if they are too large. With an argument, " + "the archiving occurs regardless of size."); +} diff --git a/lib/secure/cmds/admins/router.c b/lib/secure/cmds/admins/router.c new file mode 100644 index 0000000..8a39aa3 --- /dev/null +++ b/lib/secure/cmds/admins/router.c @@ -0,0 +1,496 @@ +#include <lib.h> +#include <save.h> +#include <daemons.h> + +inherit LIB_DAEMON; +mapping mudlist; +string banned, unbanned; +string blacklisted, unblacklisted; +string *allmuds, *banned_arr, *unbanned_arr; +string *blacklisted_arr, *unblacklisted_arr; + +varargs string match_mud_name(string mud, string *list){ + list = allmuds; + if(member_array(mud, list) != -1) return mud; + foreach(string element in list){ + if(lower_case(element) == lower_case(mud)) { + return element; + } + } + foreach(string element in list){ + if(!strsrch(lower_case(element), lower_case(mud))){ + return element; + } + if(mudlist[element]["ip"]+" "+mudlist[element]["player_port"] == mud) + return mudlist[element]["name"]; + } + return ""; +} + +mixed cmd(string args) { + string arg1, arg2, tmp; + int scannedp; + object router = find_object(ROUTER_D); + + if(!archp(previous_object())) return 0; + + if(!router && (args != "on" && args != "online")){ + write("Router is not loaded. First try: mudconfig router enable"); + return 1; + } + + mudlist = router->query_mudinfo(); + allmuds = keys(mudlist); + + if(!args || args == ""){ + args = "show"; + } + + if(args == "show"){ + write("Router config:"); + router->get_info(); + return 1; + } + + if(!router){ + write("Router is not loaded."); + return 1; + } + + scannedp = sscanf(args,"%s %s", arg1, arg2); + + if(args == "mudlist" || arg1 == "mudlist"){ + mapping info; + string *list; + mapping borg; + string mud, tempy; + int all = 0; + int ipsort = 0; + int fdsort = 0; + if(sizeof(arg2)) tempy = match_mud_name(arg2); + if(sizeof(tempy)) arg2 = tempy; + if(arg2 && !strsrch(arg2,"-i")){ + ipsort = 1; + arg2 = trim(arg2[2..]); + } + if(arg2 && !strsrch(arg2,"-f")){ + fdsort = 1; + arg2 = trim(arg2[2..]); + } + + if( arg2 && arg2 != "" && strlen(arg2) > 3 ) { + mapping tmp_map; + string opt, tmpstr; + + tmp_map = mudlist; + if( arg2[0] != '-' ) arg2 = "-n " + arg2; + opt = arg2[1..1]; + arg2 = arg2[3..]; + borg = ([]); + + foreach(mud, info in tmp_map) { + 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(arg2 = replace_string(lower_case(arg2), " ", "")); + y = strlen(tmpstr = replace_string(lower_case(tmpstr), " ", "")); + if( lower_case(arg2) == lower_case(tmpstr) ) { + borg = ([ mud : info ]); + break; + } + else if( y > z && tmpstr[0..z-1] == arg2 && info[0] == -1 ) + borg[mud] = info; + } + } + else { + borg = ([ ]); + foreach( mud, info in mudlist ){ + if( all == 1 || (info["restart_delay"] && info["restart_delay"] == -1) ) + borg[mud] = info; + } + } + if( !sizeof(borg) ) { + message("system", "No MUDs match your query.", this_player()); + return 1; + } + else if( sizeof(borg) == 1 ) { + string msg, svc; + int val, comma = 0; + + mud = keys(borg)[0]; + msg = "\nDetailed information on %^GREEN%^" + mud + "%^RESET%^:\n"; + msg += sprintf("MUD Type: %:-6s Server: %:-20s Library: %s\n", + borg[mud]["mud_type"], borg[mud]["driver"], borg[mud]["base_mudlib"]); + msg += "Status: " + borg[mud]["open_status"] + "\nAdmin email: " + + borg[mud]["admin_email"] + "\n"; + msg += "Services: "; + foreach(svc, val in borg[mud]["services"]) { + if( val == 1 ) { + if( comma ) msg += ", " + svc; + else { + msg += svc; + comma = 1; + } + } + } + msg += "\nHost: " + borg[mud]["ip"] + "\n"; + msg += "Telnet port: " + borg[mud]["player_port"] + "\n"; + if( borg[mud]["services"]["amcp"] ) + msg += "AMCP version: " + borg[mud]["services"]["amcp"] + "\n"; + if( borg[mud]["services"]["http"] ) + msg += "HTTP port (World Wide Web): " + borg[mud]["services"]["http"]+"\n"; + if( borg[mud]["services"]["ftp"] ) + msg += "FTP port (File Transfer): " + borg[mud]["services"]["ftp"] + "\n"; + if( borg[mud]["services"]["rcp"] ) + msg += "RCP port (Remote Creator): " + borg[mud]["services"]["rcp"] + "\n"; + message("info", msg, this_player()); + return 1; + } + + list = ({}); + + if(fdsort){ + mapping fds = ROUTER_D->query_connected_fds(); + string *ret = ({}); + int i, quant = sizeof(socket_status()); + for(i = 0; i < quant; i++){ + if(last_string_element(socket_status(i)[3],".") == ROUTER_D->GetRouterPort() ){ + string mudnamen; + if(fds[i]) mudnamen = fds[i]; + else mudnamen = "UNKNOWN"; + ret += ({ i+" "+mudnamen+" "+explode(socket_address(i)," ")[0] }); + } + } + ret = sort_array(ret,1); + this_player()->eventPage(ret); + return 1; + } + + foreach(mud, info in borg){ + if(ipsort) + list += ({ sprintf("%:-15s %:-6s %:-15s %:-18s", + info["ip"], itoa(info["player_port"]), replace_string(mud,"%^","%%^^"), info["base_mudlib"]) }); + + else + list += ({ sprintf("%:-15s %:-6s %:-15s %:-18s %s %d", + replace_string(mud,"%^","%%^^"), info["mud_type"], info["driver"], info["base_mudlib"], info["ip"], info["player_port"]) }); + } + 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; + } + + if(args == "reload" || args == "restart" || args == "reset"){ + object rsocket = find_object(RSOCKET_D); + if(router){ + if(args == "reset"){ + router->clear(); + router->irn_clear(); + } + router->SetList(); + router->eventDestruct(); + router = find_object(ROUTER_D); + if(router) write("Router unload failed."); + else write("Router unloaded from memory."); + flush_messages(); + } + if(args == "restart" || args == "reset"){ + if(rsocket) rsocket->eventDestruct(); + if(rsocket) destruct(rsocket); + if(rsocket) write("%^RED%^BOLD%^Router socker not destructed.%^RESET%^"); + rsocket = load_object(RSOCKET_D); + if(!rsocket) write("Could not reload router socket daemon."); + } + write("Loading router daemon..."); + flush_messages(); + router = load_object(ROUTER_D); + if(!router) write("Router load failed."); + else write("Router loaded."); + return 1; + } + + if(args == "on" || args == "online"){ + if(router){ + write("The router daemon is already online."); + return 1; + } + else { + write("Loading router daemon..."); + flush_messages(); + router = load_object(ROUTER_D); + if(!router) write("Router load failed."); + else write("Router loaded."); + return 1; + } + } + + if(args == "off" || args == "offline"){ + if(!router){ + write("The router daemon is already offline."); + return 1; + } + else { + write("Unloading router daemon..."); + flush_messages(); + router->eventDestruct(); + router = find_object(ROUTER_D); + if(router) write("Router unload failed."); + else write("Router unloaded from memory."); + return 1; + } + } + + if(!router){ + write("The intermud router is not loaded."); + return 1; + } + + if(!arg2) arg1 = args; + + if(arg1 == "ban" || arg1 == "banned"){ + if(sizeof(router->GetBannedMuds())) banned_arr = router->GetBannedMuds(); + else banned_arr = ({}); + if(!sizeof(banned_arr)) banned = "No banned muds."; + else banned = implode(banned_arr,", "); + if(!arg2){ + write("Banned muds: "+banned); + return 1; + } + tmp = match_mud_name(arg2, allmuds); + if(!sizeof(tmp)){ + write("There is no such mud, but I am adding the name to the list."); + } + else arg2 = tmp; + + router->AddBannedMud(arg2); + write(arg2+" has been added to the banned list."); + return 1; + } + + if(arg1 == "unban" || arg1 == "unbanned"){ + if(sizeof(router->GetBannedMuds())) banned_arr = router->GetBannedMuds(); + else banned_arr = ({}); + if(!sizeof(banned_arr)) unbanned = "No banned muds."; + else { + banned = implode(banned_arr,", "); + unbanned_arr = filter(keys(mudlist), (: member_array($1, banned_arr) == -1 :) ) || ({}); + unbanned = implode(unbanned_arr,", "); + } + if(!arg2){ + write("Unbanned muds: "+unbanned); + return 1; + } + + router->RemoveBannedMud(arg2); + write(arg2+" has been removed from the banned list."); + return 1; + } + + if(arg1 == "blacklist" || arg1 == "blacklisted"){ + if(sizeof(router->GetBlacklistedMuds())) blacklisted_arr = router->GetBlacklistedMuds(); + else blacklisted_arr = ({}); + if(!sizeof(blacklisted_arr)) blacklisted = "No blacklisted muds."; + else blacklisted = implode(blacklisted_arr,", "); + if(!arg2){ + write("Blacklisted muds: "+blacklisted); + return 1; + } + tmp = match_mud_name(arg2, allmuds); + if(!sizeof(tmp)){ + write("There is no such mud, but I am adding the name to the list."); + } + else arg2 = tmp; + + router->AddBlacklistedMud(arg2); + write(arg2+" has been added to the blacklisted list."); + return 1; + } + + if(arg1 == "unblacklist" || arg1 == "unblacklisted"){ + if(sizeof(router->GetBlacklistedMuds())) blacklisted_arr = router->GetBlacklistedMuds(); + else blacklisted_arr = ({}); + if(!sizeof(blacklisted_arr)) unblacklisted = "No blacklisted muds."; + else { + blacklisted = implode(blacklisted_arr,", "); + unblacklisted_arr = filter(keys(mudlist), (: member_array($1, blacklisted_arr) == -1 :) ) || ({}); + unblacklisted = implode(unblacklisted_arr,", "); + } + if(!arg2){ + write("Unblacklisted muds: "+unblacklisted); + return 1; + } + + router->RemoveBlacklistedMud(arg2); + write(arg2+" has been removed from the blacklisted list."); + return 1; + } + + if(arg1 == "id" || arg1 == "identify"){ + if(!arg2){ + write("Identify which mud?"); + return 1; + } + tmp = match_mud_name(arg2, allmuds); + if(!sizeof(tmp)){ + write("Mud not found."); + return 1; + } + else arg2 = tmp; + + write("The proper name is: "+arg2); + return 1; + } + + + if(arg1 == "config"){ + string s1, s2, s3; + if(arg2 && sizeof(arg2)){ + arg2 = reverse_string(arg2); + sscanf(arg2,"%s %s %s", s3, s2, s1); + } + if(s1){ + s1 = reverse_string(s1); + if(!strsrch(s1,"*")) true(); + else s1 = "*"+s1; + } + if(!s3){ + write("Syntax: router config NAME IP PORT"); + return 1; + } + if(s2) s2 = reverse_string(s2); + s3 = reverse_string(s3); + router->SetRouterName(s1); + router->SetRouterIP(s2); + router->SetRouterPort(s3); + router->SetRouterList(); + write("Config complete. To activate, type: router reset"); + return 1; + } + + if(arg1 == "deletemud"){ + if(!arg2 || !sizeof(arg2)){ + write("Syntax: router deletemud MUDNAME"); + return 1; + } + arg2 = match_mud_name(arg2, allmuds); + router->remove_mud(arg2, 1); + write("Mud removed."); + return 1; + } + + if(arg1 == "name"){ + if(!arg2 || !sizeof(arg2)){ + write("Syntax: router name NAME"); + return 1; + } + router->SetRouterName(arg2); + write("Router name set."); + return 1; + } + + + if(arg1 == "ip"){ + if(!arg2 || !sizeof(arg2)){ + write("Syntax: router ip ADDRESS"); + return 1; + } + router->SetRouterIP(arg2); + write("Router ip set."); + return 1; + } + + + if(arg1 == "port"){ + if(!arg2 || !sizeof(arg2)){ + write("Syntax: router port NUMBER"); + return 1; + } + router->SetRouterPort(arg2); + write("Router port set."); + return 1; + } + + if(arg1 == "irn"){ + if(!arg2){ + write("Please specify an irn subcommand: enable, disable, " + "check, force."); + return 1; + } + if(arg2 == "check"){ + ROUTER_D->irn_checkstat(); + write("irn status check issued."); + return 1; + } + if(arg2 == "enable"){ + if(ROUTER_D->query_irn_enabled()){ + write("irn already enabled."); + return 1; + } + ROUTER_D->toggle_irn(1); + ROUTER_D->irn_checkstat(); + write("irn enabled."); + return 1; + } + if(arg2 == "disable"){ + if(!(ROUTER_D->query_irn_enabled())){ + write("irn already disabled."); + return 1; + } + ROUTER_D->toggle_irn(0); + ROUTER_D->irn_clear(); + write("irn disabled."); + return 1; + } + if(arg2 == "force"){ + ROUTER_D->toggle_irn(1); + ROUTER_D->irn_setup(1); + write("irn forcibly reloaded."); + return 1; + } + } + + write("Router command completed."); + return 1; +} + +string GetHelp(){ + return ("Syntax: router [subcommand [arg]]\n\n" + "With no arguments, router status is displayed.\n" + "Examples:\n" + "router reload : bounces the router without dropping connections\n" + "router restart : bounces the router dropping all connections\n" + "router reset : like restart but also clears all saved mud info\n" + "router irn [enable|disable|check|force] : manages IRN subsystem\n" + "router ban : lists banned muds\n" + "router ban <mudname> : bans the mud with the name <mudname>\n" + "router unban <mudname> : the opposite of banning\n" + "router blacklist : lists blacklisted names and IP's\n" + "router blacklist [name | ip address] : a harsher kind of ban\n" + "router unblacklist [name | ip address] : the opposite of blacklisting\n" + "router config <name> <ip> <port> : config the router in one line\n" + "router port <portnum> : sets the router port\n" + "router ip <ip number> : sets the ip address, e.g. 11.22.33.44\n" + "router name <routername> : sets the router name\n" + "router mudlist : display information of known muds\n" + "router mudlist -i : display muds sorted by ip\n" + "router mudlist -f : display connected muds sorted by file descriptor\n" + "\n" + "To bring the router online or offline, use the " + "mudconfig command."); +} diff --git a/lib/secure/cmds/admins/sconv.c b/lib/secure/cmds/admins/sconv.c new file mode 100644 index 0000000..65d5815 --- /dev/null +++ b/lib/secure/cmds/admins/sconv.c @@ -0,0 +1,343 @@ +#include <lib.h> +#include <dirs.h> +#include <vendor_types.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +string original, digested; +mapping AreaMap = ([]); +mapping RawMap = ([]); +mapping Genders = ([ 0 : "neutral", 1 : "male", 2 : "female" ]); +mapping Directions = ([ 0 : "north", 1 : "east", 2 : "south", + 3 : "west", 4 : "up", 5 : "down", 6 : "northeast", 7 : "northwest", + 8 : "southeast", 9 : "southwest", 10 : "somewhere" ]); +mapping Types = ([ 1 : "LIB_ITEM", 2 : "LIB_ITEM", 3 : "LIB_ITEM", 4 : "LIB_ITEM", + 5 : "LIB_ITEM", 6 : "LIB_ITEM", 7 : "LIB_ITEM", 8 : "LIB_ITEM", 9 : "LIB_ARMOR", 10 : "LIB_POTION", + 11 : "LIB_ITEM", 12 : "LIB_BED", 13 : "LIB_ITEM", 14 : "LIB_ITEM", 15 : "LIB_STORAGE", + 16 : "LIB_ITEM", 17 : "LIB_MEAL", 18 : "LIB_ITEM", 19 : "LIB_MEAL", 20 : "LIB_PILE", + 21 : "LIB_ITEM", 22 : "LIB_ITEM", 23 : "LIB_ITEM", 24 : "LIB_ITEM", 25 : "LIB_ITEM", + 26 : "LIB_ITEM", 44 : "LIB_ITEM" ]); +string gdirection, cle, val; +int item_type, extra_flags, wear_flags; +int tmp1, tmp2, tmp3; +mixed value_1, value_2, value_3, value_4, value_5; +int weight, cost, cost_per_day; +int lock, key, room, direction; +int ok, ok2; + +mixed cmd(string args){ +#ifndef __FLUFFOS__ + write("This command only works under FluffOS."); + return 1; +#else + if(args == "clear"){ + write("Resetting the converter variables."); + RELOAD_D->eventReload(this_object(),0); + return 1; + } + if(grepp(args,"-r ")){ + args = replace_string(args,"-r ",""); + return this_object()->Report(args); + } + return this_object()->ConvertArea(args); +} + +string clean_string(string str){ + str = replace_string(str,"\"","\'",); + return str; +#endif +} + +int Report(string str){ + print_long_string(this_player(),"vnums: "+item_list(keys(AreaMap)),1); + if(str == "both" || str == "area") print_long_string(this_player(),"%^RED%^AreaMap: "+identify(AreaMap),1); + if(str == "both" || str == "raw") print_long_string(this_player(),"%^GREEN%^RAWMap: "+identify(RawMap),1); + if(sscanf(str,"%*d")) this_object()->DisplayVnum(str); + return 1; +} + +int DisplayVnum(string str){ + if(!str || !AreaMap[str]){ + write("No such vnum in this area."); + return 1; + } + print_long_string(this_player(),"vnum "+str+":\n"+identify(AreaMap[str]),1); + return 1; +} + +int ConvertArea(string arg){ + string tmp, str, name, prefix; + int i; + string *rooms_arr; + string *obs_arr; + string *delimiters = ({ "#AREA", "#VERSION", "#AUTHOR", "#RANGES", "#RESETMSG", + "#FLAGS", "#ECONOMY", "#CLIMATE", "#HELPS", "#MOBILES", "#OBJECTS", + "#ROOMS", "#RESETS", "#SHOPS", "#REPAIRS", "#SPECIALS", "#$" }); + string *new_delimiters = ({}); + string *segmented = ({}); + + if(!arg || sscanf(arg,"%s %s",str, name) != 2){ + write("convert FILE AREA"); + return 1; + } + + if(!str){ + write("Try: help sconv"); + return 1; + } + + if(!file_exists(str)){ str = this_player()->query_cwd()+"/"+str; } + + if(!file_exists(str)){ + write("No such area file exists."); + return 1; + } + + if(directory_exists(DOMAINS_DIRS+"/"+name)){ + write("That domain already exists. Backing up the current domain to a unique name."); + rename(DOMAINS_DIRS+"/"+name, DOMAINS_DIRS+"/"+name+"."+time()); + } + + original = read_file(str); + digested = original; + foreach(string element in delimiters){ + tmp = replace_string(element,"#","0^0"); + digested = clean_string(replace_string(digested,element,tmp)); + new_delimiters += ({ tmp }); + } + + segmented = explode(digested,"0^0"); + + foreach(mixed element in segmented){ + string *minced = explode(element,"\n"); + if(!RawMap) RawMap = ([]); + RawMap[minced[0]] = minced[1..]; + } + + ///// + // ITEMS + ///// + + tmp = implode(RawMap["OBJECTS"],"\n"); + prefix = DOMAINS_DIRS+"/"+name+"/obj/"; + obs_arr = explode(tmp,"#"); + foreach(mixed block in obs_arr){ + string *ob_id; + string *lines = explode(block,"\n"); + string short, long, ob_name; + string header = ""; + ok = 0; + if(block && sizeof(lines) > 1){ + ob_id = explode(truncate(lines[1],1)," "); + if(!sizeof(ob_id)) continue; + ob_name = ob_id[0]; + short = truncate(lines[2],1); + long = ""; + for(i=2;i < sizeof(lines);i++){ + int num = i; + if(sscanf(lines[i],"%d %d %d %d",value_1, value_2, value_3, value_4) == 4){ + ok = 1; + } + else if(sscanf(lines[i],"%d %d %d",tmp1, tmp2, tmp3) == 3){ + if(ok){ + weight = tmp1; + cost = tmp2; + cost_per_day = tmp3; + } + else { + item_type = tmp1; + extra_flags = tmp2; + wear_flags = tmp3; + } + } + + if(lines[i] == "E"){ + for(num = i+2; num < sizeof(lines);num++){ + if(lines[num] == "~") break; + long += lines[num]+" "; + } + break; + } + } + } + + header += "#include <lib.h>\n\n"; + header += "inherit "+(Types[item_type] || "LIB_ITEM")+";\n\n"; + header += "static void create() {\n"; + header += " ::create();\n"; + header += " SetKeyName(\""+ob_name+"\");\n"; + header += " SetId( "+identify(ob_id)+" );\n"; + header += " SetShort(\""+short+"\");\n"; + header += " SetLong(\""+long+"\");\n"; + header += " SetMass("+weight+");\n"; + header += " SetBaseCost("+cost+");\n"; + header += "}\nvoid init(){\n::init();\n}\n"; + + mkdir_recurse(truncate(prefix,1)); + if(directory_exists(truncate(prefix,1))){ + write_file(prefix+lines[0]+"_"+ob_name+".c",header,1); + } + else write("Directory "+truncate(prefix,1)+" does not exist."); + + if(!AreaMap) AreaMap = ([]); + + if(!AreaMap[lines[0]]) AreaMap[lines[0]] = ([ prefix+lines[0]+"_"+ob_name+".c" : header ]); + else AreaMap[lines[0]][prefix+lines[0]+"_"+ob_name+".c"] = header; + } + + ///// + // MOBS + ///// + + tmp = implode(RawMap["MOBILES"],"\n"); + prefix = DOMAINS_DIRS+"/"+name+"/npc/"; + obs_arr = explode(tmp,"#"); + foreach(mixed block in obs_arr){ + string *ob_id; + string *lines = explode(block,"\n"); + string short, long, ob_name; + string header = ""; + ok = 0; + ok2 = 0; + if(block && sizeof(lines) > 1){ + ob_id = explode(truncate(lines[1],1)," "); + if(!sizeof(ob_id)) continue; + ob_name = ob_id[0]; + short = truncate(lines[2],1); + long = ""; + for(i=0;i < sizeof(lines);i++){ + int num = i; + if(!ok && sscanf(lines[i],"%d %d %d %s %s",value_1, value_2, value_3, value_4, value_5) == 5){ + ok =1; + } + if( ok == 1 && sizeof(explode(lines[i]," ")) == 3 && sscanf(lines[i],"%d %d %d",value_2, value_3, value_4) == 3){ + ok++; + } + if(!ok2 && i > 3){ + if(i > 4 && lines[i] == "~"){ + ok2 = 1; + continue; + } + if(lines[i] != "~") long += lines[i]+" "; + } + } + + header += "#include <lib.h>\n\n"; + header += "inherit LIB_SENTIENT;\n\n"; + header += "static void create(){\n"; + header += " ::create();\n"; + header += " SetKeyName(\""+ob_name+"\");\n"; + header += " SetId( "+identify(ob_id)+" );\n"; + header += " SetShort(\""+short+"\");\n"; + header += " SetLong(\""+long+"\");\n"; + header += " SetLevel("+value_1+");\n"; + header += " SetRace(\"human\");\n"; + header += " SetNoCondition(1);\n"; + header += " SetGender(\""+Genders[value_4]+"\");\n"; + header += "}\nvoid init(){\n::init();\n}\n"; + + mkdir_recurse(truncate(prefix,1)); + if(directory_exists(truncate(prefix,1))){ + write_file(prefix+lines[0]+"_"+ob_name+".c",header,1); + } + else write("Directory "+truncate(prefix,1)+" does not exist."); + + if(!AreaMap) AreaMap = ([]); + + if(!AreaMap[lines[0]]) AreaMap[lines[0]] = ([ prefix+lines[0]+"_"+ob_name+".c" : header ]); + else AreaMap[lines[0]][prefix+lines[0]+"_"+ob_name+".c"] = header; + } + } + ///// + // ROOMS + ///// + + tmp = implode(RawMap["ROOMS"],"\n"); + prefix = DOMAINS_DIRS+"/"+name+"/room/"; + rooms_arr = explode(tmp,"#"); + foreach(mixed block in rooms_arr){ + string *lines = explode(block,"\n"); + string short, long; + string header = "#include <lib.h>\n"; + header += "#include ROOMS_H\n\n"; + header += "inherit LIB_ROOM;\n\n"; + header += "void create() {\n"; + header += " room::create();\n"; + header += " SetClimate(\"indoors\");\n"; + header += " SetAmbientLight(30);\n"; + + + short = truncate(lines[1],1); + long = ""; + for(i=2;i < sizeof(lines);i++){ + if(lines[i] == "~") break; + long += lines[i]+" "; + } + + header += " SetShort(\""+short+"\");\n"; + header += " SetLong(\""+long+"\");\n"; + header += " SetExits( ([\n"; + + for(i=i;i < sizeof(lines);i++){ + int rev = 1; + lock = key = room = direction = 0; + if(lines[i] == "S") break; + if(sscanf(lines[i],"%d %d %d",lock, key, room) == 3){ + while(rev){ + if(!sscanf(lines[((i-rev > -1) ? (i-rev) : 0)],"D%d",direction)) rev++; + else rev = 0; + if(rev > 20) rev = 0; + } + if(!rev){ + if(room == 0){ + gdirection = Directions[direction]; + //continue; + } + else header += " \""+Directions[direction]+"\" : \""+prefix+room+"\",\n"; + } + else if(sizeof(gdirection) > 1){ + if(room != 0) header += " \""+gdirection+"\" : \""+prefix+room+"\",\n"; + gdirection = ""; + } + } + } + + header += " ]) );\n"; + header += " SetInventory( ([\n"; + if(AreaMap && AreaMap[lines[0]]) + foreach(cle, val in AreaMap[lines[0]]){ + if(!grepp(val,"LIB_ROOM")){ + header += " \""+cle+"\" : 1,\n"; + } + } + header += " ]) );\n"; + header += "}\n"; + header += "void init(){\n"; + header += " ::init();\n"; + header += "}\n"; + + mkdir_recurse(truncate(prefix,1)); + if(directory_exists(truncate(prefix,1))){ + write_file(prefix+lines[0]+".c",header,1); + } + else write("Directory "+truncate(prefix,1)+" does not exist."); + + if(!AreaMap) AreaMap = ([]); + + if(!AreaMap[lines[0]]) AreaMap[lines[0]] = ([ prefix+lines[0]+".c" : header ]); + else AreaMap[lines[0]][prefix+lines[0]+".c"] = header; + } + + return 1; +} + +string GetHelp() { + message("help", "Syntax: sconv <file> <area>\n\n" + "Tries to convert a Smaug area file into a Dead Souls domain.\n" + "Example: sconv /tmp/fubar.are Foo\n" + "This would try to create /domains/Foo and convert the area described\n" + "in /tmp/fubar.are into LPC files in that domain." + "\n", this_player()); +} + diff --git a/lib/secure/cmds/admins/setreboot.c b/lib/secure/cmds/admins/setreboot.c new file mode 100644 index 0000000..659a00f --- /dev/null +++ b/lib/secure/cmds/admins/setreboot.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +int cmd(string str) { + int x; + + if( !(master()->valid_apply(({ "ASSIST" }))) ){ + return 0; + } + + if(!str || str == "" || !sscanf(str, "%d", x)){ + this_object()->help(); + } + x = EVENTS_D->SetRebootInterval(x); + message("info", "Reboot interval set to "+x+" hours.", this_player()); + return 1; +} + +string GetHelp(){ + return ("Syntax: setreboot <interval>\n\n" + "Sets up the interval at which the mud will automatically reboot. " + "The interval should be specified in hours."); +} diff --git a/lib/secure/cmds/admins/shutdown.c b/lib/secure/cmds/admins/shutdown.c new file mode 100644 index 0000000..e7e5194 --- /dev/null +++ b/lib/secure/cmds/admins/shutdown.c @@ -0,0 +1,74 @@ +// /bin/adm/_shutdown.c +// from the Dead Souls Mudlib +// the shutdown command +// created in pats by Sulam@TMI, Plura@Dead Souls, and Descartes of Borg + +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; +object downer; + +void ShutDown(){ + shutdown(); +} + +void DoSaves(){ + object *persists = objects( (: $1->GetPersistent() :) ); + foreach(object persist in persists){ + persist->eventDestruct(); + } +} + +int cmd(string str) { + downer = previous_object(); + if(downer->GetForced()){ + write("Forced attempt to shutdown."); + return 1; + } + if(!archp(downer)) { + write("You are not permitted to shutdown the game.\n"); + return 1; + } + if(!str) { + write("You must give a shutdown reason as argument.\n"); + return 1; + } + if(str == "cancel"){ + int cancel = EVENTS_D->eventCancelShutdown(); + if(cancel == -1){ + write("There was no shutdown in progress."); + } + else if(cancel > -1){ + write("Shutdown cancelled."); + shout("Shutdown cancelled by " + downer->GetKeyName() + ".\n"); + } + else { + write("Something odd happened. Shutdown may not be cancelled."); + } + return 1; + } + shout("Game is shut down by " + downer->GetKeyName() + ".\n"); + log_file("game_log", ctime(time())+" Game shutdown by "+ + downer->GetKeyName()+"("+str+")\n"); + foreach(object dude in users()){ + if(dude && sizeof(base_name(dude))){ + if(!archp(dude)) dude->eventForce("quit"); + else { + downer = dude; + unguarded( (: downer->AddCarriedMass(-99999) :) ); + unguarded( (: downer->save_player(downer->GetKeyName()) :) ); + } + } + } + call_out( (: DoSaves :), 0); + call_out( (: shutdown :), 2); + return 1; +} + +string GetHelp(){ + return ("Syntax: shutdown cancel\n" + " shutdown [reason]\n\n" + "This will shut down the game immediately, or cancel " + "a scheduled shutdown. Use with great care.\nSee also: end"); +} diff --git a/lib/secure/cmds/admins/snoopreport.c b/lib/secure/cmds/admins/snoopreport.c new file mode 100644 index 0000000..96b677d --- /dev/null +++ b/lib/secure/cmds/admins/snoopreport.c @@ -0,0 +1,24 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + string ret; + + if(!this_player() || !archp(this_player())) return 0; + + ret = SNOOP_D->Report(); + + if(check_string_length(ret) > 0) this_player()->eventPrint(""+ret+""); + else print_long_string(this_player(),ret); + + return 1; +} + +string GetHelp() { + return ("Syntax: snoopreport\n\n" + "Displays a list of who is snooping whom, who is being " + "monitored (aka logged), and so on.\nSee also: snoop, unsnoop, " + "monitor"); +} diff --git a/lib/secure/cmds/admins/statconvert.c b/lib/secure/cmds/admins/statconvert.c new file mode 100644 index 0000000..00fc299 --- /dev/null +++ b/lib/secure/cmds/admins/statconvert.c @@ -0,0 +1,96 @@ +/* statconvert.c + * A utility which reduces or raises SetSkill and SetStat lines + * in a file by a specified percentage. + * created by Blitz@Dead Souls + */ + +void GetHelp(string str); + +string ConvertLine(string str, int change, int line, string search) +{ + string s1, s2, cut, n, tmp; + int a, b, val; + + if(!archp(previous_object())) return 0; + while( (a = strsrch(str, search)) > -1 ) { + tmp = str[a..]; + b = strsrch(tmp, ")"); + if( b < 0) break; + cut = tmp[0..b]; + if( sscanf(cut, "%s,%s", s1, s2) != 2 ) break; + s2 = replace_string(s2, " ", ""); + sscanf(s2, "%s)", s2); + val = to_int(s2); + if( !val ) break; + val = val - (val / (100 / change)); + n = sprintf("%s, %d)", s1[0] + "@@@" + s1[1..], val); + str = replace_string(str, cut, n); + write("Line "+line+": "+cut+" -> "+val+"."); + } + str = replace_string(str, search[0] + "@@@" + search[1..], search); + return str; +} + +void Convert(string s, int change) { + string args, file, str; + string *files, *tmp; + int i; + + if(!archp(previous_object())) return 0; + if( !sizeof(s) ) args = "*.c"; + else args = s; + files = wild_card(args); + if( !i = sizeof(files) ) { + message("info", "No file(s) found: "+implode(files, " "), + this_player() ); + return; + } + foreach(file in files) { + string line; + int changed = 0; + + str = read_file(file); + if( !sizeof(str) ) continue; + i = sizeof(tmp = explode(str, "\n")); + write("Checking: "+file); + while(i--) { + line = tmp[i]; + line = ConvertLine(line, change, i, "SetSkill"); + line = ConvertLine(line, change, i, "SetStat"); + if( tmp[i] != line ) changed = 1; + if( changed ) tmp[i] = line; + } + if( changed ) { + rename(file, file+"~"); + write(file+": Writing new file..."); + write_file(file, implode(tmp, "\n")); + } + } +} + +mixed cmd(string str) { + string files; + int change; + + if(!archp(previous_object())) return 0; + if( !sizeof(str) || (sscanf(str, "%s %d", files, change) != 2) || !change) { + GetHelp(0); + return 1; + } + files = absolute_path(this_player()->query_cwd(), files); + Convert(files, change); + return 1; +} + + +string GetHelp(){ + return ("Syntax: statconvert <filename | wild card> <percentage>\n\n" + "This command searches through the specified file(s) and lowers " + "all occurrences of SetSkill and SetStat by a <percentage> " + "amount.\n\n" + "Example: statconvert *.c 10\n" + " - Searches all .c files in your currenct path, and reduces\n" + " all skill and stat settings by 10%\n\n" + "Note: It is possible to raise settings by passing " + "a negative number."); +} diff --git a/lib/secure/cmds/admins/switchrouter.c b/lib/secure/cmds/admins/switchrouter.c new file mode 100644 index 0000000..9bfbff8 --- /dev/null +++ b/lib/secure/cmds/admins/switchrouter.c @@ -0,0 +1,92 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +string file; + +mixed cmd(string args) { + string ip, name; + int port, octet1, octet2, octet3, octet4; + + if(!archp(previous_object())) return "No."; + + if(!args || args == ""){ + object omud = find_object(INTERMUD_D); + if(!omud){ + write("The intermud daemon is not loaded. Try: help switchrouter"); + write("It may also be disabled. Try: help mudconfig"); + return 1; + } + name = omud->GetNameservers()[0][0]; + ip = omud->GetNameservers()[0][1]; + if(!name || !ip){ + write("There appears to be something wrong with your intermud daemon config."); + return 1; + } + write("Your current direct router connection is to "+name+" "+ip); + if(sizeof(omud->GetNameservers()) > 1){ + write("NOTE: You have multiple routers configured. The array "+ + "of routers you are connected to is: "+identify(omud->GetNameservers())); + } + return 1; + } + + if(find_object(INTERMUD_D))find_object(INTERMUD_D)->eventClearVars(); + if(find_object(INTERMUD_D))find_object(INTERMUD_D)->eventDestruct(); + + + if(args == "reload"){ + write("Reloading intermud daemon."); + if( load_object(INTERMUD_D) ) write("Intermud daemon reloaded."); + else write("Failed to reload intermud daemon."); + return 1; + } + + if(sscanf(args,"%s %s %d", name, ip, port) != 3 || port > 65534 || + sscanf(ip,"%d.%d.%d.%d", octet1, octet2, octet3, octet4) != 4){ + write("Invalid router reference. \nTry: switchrouter <ROUTERNAME> <NUMERICAL IP> <PORT>"); + write("For example: switchrouter yatmim 149.152.218.102 23"); + if( load_object(INTERMUD_D) ) write("Intermud daemon reloaded."); + else write("Failed to reload intermud daemon."); + return 1; + } + + file = read_file(INTERMUD_D+".c"); + + file = replace_matching_line(file, "//Nameservers", ""); + + if(first(name,1) != "*") name = "*"+name; + + file = replace_matching_line(file, "Nameservers = ({", + " Nameservers = ({ ({ \""+name+"\", \""+ip+" "+port+"\" }) });", 1); + + unguarded( (: write_file(INTERMUD_D+".c",file,1) :) ); + + if( load_object(INTERMUD_D) ) write("Intermud daemon reloaded."); + else write("Failed to reload intermud daemon."); + + write("Done."); + return 1; + } + + string GetHelp(){ + return ("Syntax: switchrouter <NAME> <IP> <PORT>\n\n" + "Stops the intermud daemon, changes the default intermud " + "router to the ip and port you specify, wipes the previous " + "router data, and reloads INTERMUD_D. Without arguments, " + "this command will clear your intermud cache and reload " + "the daemon. Known routers are:\n" + //"*gjs 198.144.203.194 9000 (The \"official\" intermud.org router)\n" + //"*adsr 62.49.9.82 9000 (Arren's unmoderated router)\n" + //"*yatmim 149.152.218.102 23 (The backup/alternate router for *dalet)\n" + "*dalet 97.107.133.86 8787 (The \"official\" LPMuds.net router)\n" + "*i4 204.209.44.3 8080 (The backup/alternate router for *dalet)\n" + //"*wpr 195.242.99.94 8080 (An alternate run in Europe)\n" + "The official current Dead Souls router's IP will always be " + "available at:\n" + "http://dead-souls.net/router.html" + "\n\n" + "See also: mudlist, mudconfig, http://intermud.org"); + } + diff --git a/lib/secure/cmds/admins/tempban.c b/lib/secure/cmds/admins/tempban.c new file mode 100644 index 0000000..5c5bf53 --- /dev/null +++ b/lib/secure/cmds/admins/tempban.c @@ -0,0 +1,46 @@ +// _tempban.c +// /cmd// Part of the Dead Souls Mudlib +// A command so that all those law-types can place sites on registration for a +// specified, limited amount of time. +// 01July1994 by Gregon@Dead Souls + +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +int cmd(string str) { + string site; + int time; + + if(!archp(previous_object())) return 0; + + if(!str) { + write("The following sites are on temporary registration:\n"+ + BANISH_D->query_temp_site_info()); + return 1; + } + + + if(sscanf(str, "%s %d", site, time) != 2) { + notify_fail("Correct syntax: tempban [site] [time in minutes]>\n\n"); + return 0; + } + + write(site+" is now on register for "+time+" minutes."); + BANISH_D->temporary_register(site, time*60); + log_file("watch/register", site+" for "+time+" minutes.\n"); + log_file("watch/register", "by " +this_player()->GetName()+"\n"); + return 1; +} + +string GetHelp(){ + return ("Syntax: tempban [site] [time]\n\n" + "This will make new players from " + "[site] unable to log in for a period of time [time] " + "(given in minutes). This will last across reboots and site ip " + "numbers should be entered in the same manner as the \"register\" " + "command requires. See \"help register\" for more details.\n\n" + "Note: tempban without arguments will list all sites on temporary " + "registration along with their times of expiration."); +} diff --git a/lib/secure/cmds/admins/ticktock.c b/lib/secure/cmds/admins/ticktock.c new file mode 100644 index 0000000..3f14b85 --- /dev/null +++ b/lib/secure/cmds/admins/ticktock.c @@ -0,0 +1,54 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(mixed args) { + int *mudtime; + int integer, hours, minutes, ret; + string meridiem = " am"; + string nulle = ""; + + if(!archp(previous_object())) return 0; + if(!args) args = 0; + if(stringp(args)){ + if(sscanf(args,"%d",integer) != 1) return "Failed."; + args = integer; + } + //tc("pre: "+SEASONS_D->GetCurrentTime()); + //tc("pre: "+identify(SEASONS_D->GetMudTime())); + if(args != 0 || SEASONS_D->GetTickTock()){ + ret = SEASONS_D->eventTickTock(args); + } + //tc("post: "+SEASONS_D->GetCurrentTime()); + //tc("post: "+identify(SEASONS_D->GetMudTime())); + + mudtime = SEASONS_D->GetMudTime(); + hours = mudtime[0]; + minutes = mudtime[1]; + + //tod = SEASONS_D->GetTimeOfDay(); + + if(hours >= 12 && hours != 24) { + if(hours != 12) hours -= 12; + meridiem = " pm"; + } + + if(!hours || hours == 0) hours = 12; + + if(minutes < 10) nulle = "0"; + + write("In the MUD, the time is "+hours+":"+nulle+minutes+meridiem+"."); + + return 1; + +} + +string GetHelp(){ + return ("Syntax: ticktock <seconds>\n\n" + "Changes in-game mud time by the number of seconds " + "specified. This is useful for changing night to " + "day and vice versa, when testing ambient light and " + "variable room descriptions. The timeshift does not " + "persist between reboots."); +} diff --git a/lib/secure/cmds/admins/unallow.c b/lib/secure/cmds/admins/unallow.c new file mode 100644 index 0000000..64ea9f8 --- /dev/null +++ b/lib/secure/cmds/admins/unallow.c @@ -0,0 +1,31 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +int cmd(string str) { + if(!member_group(previous_object(), "SECURE")) { + if(!member_group(previous_object(), "LAW")) return 0; + } + if(!str) { + notify_fail("Correct syntax: <unallow [str]>\n"); + return 0; + } + if(member_array(str = lower_case(str), + BANISH_D->query_allowed()) == -1) { + notify_fail(capitalize(str)+" is not set to be let in.\n"); + return 0; + } + BANISH_D->unallow_name(str); + log_file("watch/players", previous_object()->GetKeyName()+ + " UNLETIN "+str+": "+ctime(time())+"\n"); + return 1; +} + +string GetHelp(){ + return ("Syntax: unallow <name>\n\n" + "Removes a name from the list of names which may be used by\n" + "players from banned sites to create a new character.\n" + "See also:\nletin, wholetin, banish, whobanished, unbanish, " + "register, unregister, whoregistered"); +} diff --git a/lib/secure/cmds/admins/unbanish.c b/lib/secure/cmds/admins/unbanish.c new file mode 100644 index 0000000..c63799d --- /dev/null +++ b/lib/secure/cmds/admins/unbanish.c @@ -0,0 +1,26 @@ +// /bin/adm/_unbanish.c +// from the Dead Souls Mudlib +// unbanishes a previously banished name +// created by Shadowwolf@Dead Souls +// rewritten for new security system by Descartes of Borg 930809 + +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +int cmd(string str) { + if(!archp(previous_object())) return 0; + if(!str){ + write("Syntax: unbanish <string>"); + return 1; + } + write(capitalize(str = lower_case(str))+" is no longer banished.\n"); + catch(call_other(BANISH_D, "unbanish_name", str)); + return 1; +} + +string GetHelp(){ + return ("Syntax: unbanish <name>\n\n" + "Removes a name from the list of banished names."); +} diff --git a/lib/secure/cmds/admins/unlink.c b/lib/secure/cmds/admins/unlink.c new file mode 100644 index 0000000..15ebc5c --- /dev/null +++ b/lib/secure/cmds/admins/unlink.c @@ -0,0 +1,36 @@ +/* /secure/cmds/admins/unlink.c + * from the Dead Souls Mud Library + * unlink PLAYER + * created by Descartes of Borg 951216 + */ + +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + string primary, secondary; + mixed tmp; + + if( !archp(previous_object()) ) return 0; + if( !args || args == "" ) return "Unlink whom from whom?"; + if( sscanf(args, "%s from %s", secondary, primary) != 2 ) + return "Unlink whom from whom?"; + tmp = CHARACTER_D->eventUnlink(primary, secondary); + if( !tmp ) return "Unlink failed."; + else if( tmp == 1 ){ + this_player(1)->eventPrint("Unlinked."); + return 1; + } + else return tmp; +} + +string GetHelp(){ + return ("Syntax: unlink <CHARACTER> from <PRIMARY>\n\n" + "Unlinks the named primary or secondary player from its " + "primary character. If the player you are unlinking is " + "is itself a primary and has more than two secondaries, the " + "first secondary will become a primary. Otherwise the entire " + "link will be removed."); +} diff --git a/lib/secure/cmds/admins/unmonitor.c b/lib/secure/cmds/admins/unmonitor.c new file mode 100644 index 0000000..b20f6bd --- /dev/null +++ b/lib/secure/cmds/admins/unmonitor.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +int cmd(string str) { + object ob; + + if(!archp(previous_object())) { + write("Only an arch may halt a monitoring process."); + return 0; + } + if( !str || str == "" ) { + write("Unmonitor whom?\n"); + } + else if(!user_exists(str)) + write(str+": no such player.\n"); + else{ + SNOOP_D->RemoveMonitor(this_player(), str); + write("The snoop daemon has received your request."); + } + return 1; +} + +string GetHelp(){ + return "Syntax: unmonitor <user>\n\n" + "Stops the logging of a user's input and output.\n" + "See also: monitor, snoop, unsnoop"; +} diff --git a/lib/secure/cmds/admins/unpause.c b/lib/secure/cmds/admins/unpause.c new file mode 100644 index 0000000..a47130f --- /dev/null +++ b/lib/secure/cmds/admins/unpause.c @@ -0,0 +1,44 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + object ob; + args = lower_case(args); + if(!user_exists(args)) return capitalize(args) + " is not a member of " + + possessive_noun(mud_name()) + " reality."; + if(!ob = find_player(args)){ + if(member_array(args, PLAYERS_D->GetPendingPauses()) != -1){ + PLAYERS_D->RemovePendingPause(args); + write("Pending pause for "+capitalize(args)+" removed."); + } + if(!(PLAYERS_D->GetPlayerData(args, "Paused"))){ + return capitalize(args) + " is already unpaused."; + } + if(member_array(args, PLAYERS_D->GetPendingUnpauses()) != -1){ + return capitalize(args) + " is already pending an unpause."; + } + PLAYERS_D->AddPendingUnpause(args); + write(capitalize(args)+" will be unpaused next time they log in."); + return 1; + } + if(ob == this_player()){ + write("You can't unpause yourself."); + return 1; + } + if(!(ob->GetPlayerPaused())){ + write(capitalize(args) + " is already unpaused!"); + return 1; + } + write("You unpause "+capitalize(args)+"."); + ob->SetPlayerPaused(0); + ob->eventPrint("You have been unpaused. Commands will work now."); + return 1; +} + +string GetHelp(){ + return ("Syntax: unpause <PLAYER>\n\n" + "Causes the player to be able to run commands " + "after being paused."); +} diff --git a/lib/secure/cmds/admins/unregister.c b/lib/secure/cmds/admins/unregister.c new file mode 100644 index 0000000..f8d1e0a --- /dev/null +++ b/lib/secure/cmds/admins/unregister.c @@ -0,0 +1,34 @@ +// /bin/adm/_unregister.c +// from the Dead Souls Mudlib +// takes a site off of the list of sites needing to register +// created by Shadowwolf@Dead Souls 93???? +// rewritten for the new 3.0 security system + +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +int cmd(string str) { + if(!member_group(previous_object(), "SECURE")) { + if(!member_group(previous_object(), "LAW")) return 0; + } + if(!str) return 0; + if(member_array(str, BANISH_D->query_registered()) == -1) { + write("That site is not on the list of sites needing to register.\n"); + return 1; + } + BANISH_D->unregister_site(str); + log_file("watch/register", previous_object()->GetKeyName()+ + " UNREGISTERED "+str+": "+ctime(time())+"\n"); + write("Site : "+str+" is now not on the registration list.\n"); + return 1; +} + +string GetHelp() { + return ("Syntax: unregister <site>\n\n" + "Takes a site off the list of sites which must register their " + "character before being allowed in.\nSee also: " + "register, whoregistered, banish, unbanish, whobanished, letin, " + "wholetin, unletin"); +} diff --git a/lib/secure/cmds/admins/unrid.c b/lib/secure/cmds/admins/unrid.c new file mode 100644 index 0000000..fdb2c2e --- /dev/null +++ b/lib/secure/cmds/admins/unrid.c @@ -0,0 +1,38 @@ +/* /secure/cmds/admins/unrid.c + * created 960301 by Blitz@Dead Souls + */ + +#include <lib.h> +#include <dirs.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string str) { + string file; + + if(!archp(previous_object())) return 0; + if( !sizeof(str) ) return "Unrid whom?"; + str = convert_name(str); + file = save_file(DIR_RID + "/" + str); + if( !file_exists(file) ) + return (file + ": file not found. Cannot unrid."); + if( rename(file, player_save_file(str)) ){ + this_player()->eventPrint("Unrid failed, security " + "violation logged."); + log_file("security", "\n**** Unrid violation attempted\n" + "Target: " + file + "\nCall Stack: " + + sprintf("%O", previous_object(-1))); + return 1; + } + this_player()->eventPrint("Unrid successful."); + PLAYERS_D->AddPlayerInfo(str); + return 1; +} + +string GetHelp(){ + return "Syntax: unrid <username>\n\n" + "This command restores a character that was " + "banished via the \"rid\" command."; +} + diff --git a/lib/secure/cmds/admins/unwatch.c b/lib/secure/cmds/admins/unwatch.c new file mode 100644 index 0000000..7878517 --- /dev/null +++ b/lib/secure/cmds/admins/unwatch.c @@ -0,0 +1,35 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +int cmd(string str) { + string which, nom; + + if(!archp(previous_object())) return 0; + if(!str) { + notify_fail("Unwatch which name or site?\n"); + return 0; + } + if(sscanf(str, "%s %s", which, nom) != 2) { + notify_fail("Correct syntax: <unwatch [name|site] [ip or name]>\n"); + return 0; + } + if(which == "name") BANISH_D->unwatch_name(nom); + else if(which == "site") BANISH_D->unwatch_site(nom); + else { + notify_fail("Undefined unwatch type: "+str+"\n"); + return 0; + } + message("info", nom+" is now an unwatched "+which, this_player()); + return 1; +} + +string GetHelp(){ + return ("Syntax: unwatch <[site|name] | " + "[ip or site to be unwatched]>\n\n" + "Sets it up so that whenever a player of a certain name, or " + "a player from a certain site logs in it will get logged.\n" + "Examples: unwatch name forlock unwatch site 134.181.*\n" + "See also: watch, whowatched"); +} diff --git a/lib/secure/cmds/admins/usage.c b/lib/secure/cmds/admins/usage.c new file mode 100644 index 0000000..7e16db0 --- /dev/null +++ b/lib/secure/cmds/admins/usage.c @@ -0,0 +1,31 @@ +#include <lib.h> + +inherit LIB_DAEMON; + +mixed cmd(string str) { + mapping info; + string *cles; + string ret; + float x, fraction; + + if(!archp(previous_object())) return 0; + info = rusage(); + cles = keys(info); + + foreach(string schlussel in cles){ + write(schlussel + ": "+info[schlussel]); + } + + x = (info["utime"] + info["stime"])/1000; + fraction = x / uptime(); + ret = sprintf("\nsingle CPU usage: %2.2f%%\n", fraction * 100); + return ret; + +} + +string GetHelp() { + return ("Syntax: usage [command [args]]\n\n" + "Quantifies the thinking the mud had to do and how " + "long it took to complete the command specified.\n" + "See also: man rusage"); +} diff --git a/lib/secure/cmds/admins/userload.c b/lib/secure/cmds/admins/userload.c new file mode 100644 index 0000000..5963d74 --- /dev/null +++ b/lib/secure/cmds/admins/userload.c @@ -0,0 +1,32 @@ +#include <lib.h> +#include <dirs.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +int cmd(string arg){ + int ret; + object whom; + if(!archp(previous_object())) return 0; + if(!arg || arg == "me") arg = this_player()->GetKeyName(); + if(!(whom = find_player(arg))){ + write("The user was not found."); + return 1; + } + whom->CancelCharmode(); + ret = RELOAD_D->ReloadPlayer(arg, 1); + if(!ret) write("An error occurred."); + else write("Done."); + whom = find_player(arg); + if(whom) whom->CancelCharmode(); + return 1; +} + +string GetHelp(){ + return "Syntax: userload <username>\n\n" + "Reloads the code for users, creates a new body for the specified " + "user, and switches them into that new body. This command is useful " + "for testing new functionality in the user object without having " + "to quit.\n" + "See also: reload, update, warmboot "; +} diff --git a/lib/secure/cmds/admins/vaarsuvius.c b/lib/secure/cmds/admins/vaarsuvius.c new file mode 100644 index 0000000..c2ed3c8 --- /dev/null +++ b/lib/secure/cmds/admins/vaarsuvius.c @@ -0,0 +1,46 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + object tp = this_player(); + string tmpfile; + string ret = ""; + int massacre, survivors = 0; + object *obs; + + if(!tp || !archp(tp)) return "No."; + + if(args) args = replace_string(args,"\"",""); + + if(!args) return "Try: help vaarsuvius"; + + else obs = findobs(args); + + if(!massacre = sizeof(obs)) { + write("No such objects found."); + return 1; + } + + foreach(object ob in obs){ + ob->eventDestruct(); + if(ob) destruct(ob); + if(ob){ + survivors++; + write(identify(ob)+" survived the purge."); + } + } + if(!survivors){ + write("All "+massacre+" objects destructed."); + return 1; + } + write("Of "+massacre+" targets, "+survivors+" survived the purge."); + return 1; +} + +string GetHelp(){ + return ("Syntax: vaarsuvius <THING>\n\n" + "Destructs every THING found.\n" + "See also: zap, dest, destfile"); +} diff --git a/lib/secure/cmds/admins/var.c b/lib/secure/cmds/admins/var.c new file mode 100644 index 0000000..13d6a5a --- /dev/null +++ b/lib/secure/cmds/admins/var.c @@ -0,0 +1,104 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +string GetHelp(); +mixed var, newval; +object ob; + +int CheckVar(string var, object ob){ + mixed *vars; + if(!var || !ob) return 0; + vars = variables(ob); + if(member_array(var, vars) == -1) return 0; + return 1; +} + +int cmd(string str) { + int i; + mixed ret; + string cmd, what, tmpstr; + + if(!this_player() || !archp(this_player())){ + write("Sorry, this is an arch command."); + return 1; + } + + if(!str || str == ""){ + write(GetHelp()); + return 1; + } + + i = sscanf(str,"%s %s %s", cmd, var, what); + + if(i != 3 || (cmd != "get" && cmd != "set")){ + write(GetHelp()); + return i; + } + + if(cmd == "set"){ + int tmp; + i = sscanf(what,"%s %s", newval, what); + if(i != 2){ + write(GetHelp()); + return i; + } + if(sscanf(newval,"%d",tmp)) newval = tmp; + } + + tmpstr = DEFINES_D->GetDefine(what); + if(tmpstr) what = tmpstr; + + ob = get_object(what); + + if(!ob){ + string path = this_player()->query_cwd()+"/"; + if(last(what,2) != ".c") what += ".c"; + if(file_exists(what)) ob = load_object(what); + else if(file_exists(path+what)) ob = load_object(path+what); + } + + if(!ob){ + write(truncate(what,2)+" not found."); + return 1; + } + + if(!CheckVar(var, ob)){ + write("No such variable exists in that object."); + return 1; + } + + i = catch( ret = evaluate(bind( (: fetch_variable($(var)) :), ob)) ); + + if(i){ + write("Error in variable query."); + return 1; + } + + write(var+" in "+identify(ob)+" is "+identify(ret)); + + if(cmd == "get"){ + return 1; + } + + if(cmd == "set"){ + evaluate(bind( (: store_variable($(var), $(newval)) :), ob)); + ret = evaluate(bind( (: fetch_variable($(var)) :), ob)); + write(var+" in "+identify(ob)+" is now "+identify(ret)); + return 1; + } + + write("Error."); + return 1; +} + +string GetHelp(){ + return ("Syntax: var get <variable name> <object or file>\n" + " var set <variable name> <new value> <object or file>\n\n" + "Sets or gets the value of a variable in an object.\n" + "Examples:\n" + "var get isPK me\n" + "var set Attackable 0 fighter\n\n" + "Use with EXTREME caution."); +} diff --git a/lib/secure/cmds/admins/vars.c b/lib/secure/cmds/admins/vars.c new file mode 100644 index 0000000..6c7cbe1 --- /dev/null +++ b/lib/secure/cmds/admins/vars.c @@ -0,0 +1,63 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +string GetHelp(); +object ob; +string ele; + +mixed cmd(string str) { + int i; + mixed justvars, tmp; + string cmd, what, ret = "";; + + if(!this_player() || !archp(this_player())){ + write("Sorry, this is an arch command."); + return 1; + } + + if(!str || str == ""){ + return GetHelp(); + } + + tmp = DEFINES_D->GetDefine(str); + if(tmp) str = tmp; + + what = str; + ob = to_object(what); + + if(!ob){ + string path = this_player()->query_cwd()+"/"; + if(last(what,2) != ".c") what += ".c"; + if(file_exists(what)) ob = load_object(what); + else if(file_exists(path+what)) ob = load_object(path+what); + } + + if(!ob){ + write(truncate(what,2)+" not found."); + return 1; + } + + justvars = variables(ob); + + foreach(ele in justvars){ + string thing = replace_string(str," ","_"); + thing = replace_string(thing,"/","_"); + i = catch( tmp = evaluate(bind( (: fetch_variable($(ele)) :), ob)) ); + if(!i){ + write(ele + " " + identify(tmp)); + write_file("/secure/tmp/"+thing, ele + " " + identify(tmp)+"\n"); + } + } + return 1; +} + +string GetHelp(){ + return ("Syntax: vars <object or file>\n\n" + "Dumps the variables of an object as well as their values.\n" + "Examples:\n" + "vars kim\n" + "vars /daemon/classes\n" + "See also: var, variables"); +} diff --git a/lib/secure/cmds/admins/warmboot.c b/lib/secure/cmds/admins/warmboot.c new file mode 100644 index 0000000..aad3ea9 --- /dev/null +++ b/lib/secure/cmds/admins/warmboot.c @@ -0,0 +1,21 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +int cmd(string arg){ + if(!archp(previous_object())) return 0; + RELOAD_D->WarmBoot(); + write("Warm boot requested."); + return 1; +} + +string GetHelp(){ + return "Syntax: warmboot\n\n" + "Reloads and updates objects and users in memory such " + "that changes to code come into effect, as if the mud " + "had been rebooted. This command does not disconnect players. " + "WARNING: People in the process of editing files will lose " + "unsaved changes to the files being edited.\n" + "See also: reload, update, userload "; +} diff --git a/lib/secure/cmds/admins/watch.c b/lib/secure/cmds/admins/watch.c new file mode 100644 index 0000000..8a7126f --- /dev/null +++ b/lib/secure/cmds/admins/watch.c @@ -0,0 +1,34 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +int cmd(string str) { + string which, nom; + + if(!archp(previous_object())) return 0; + if(!str) { + notify_fail("Watch which name or site?\n"); + return 1; + } + if(sscanf(str, "%s %s", which, nom) != 2) { + notify_fail("Correct syntax: <watch [name|site] [ip or name]>\n"); + return 1; + } + if(which == "name") BANISH_D->watch_name(nom); + else if(which == "site") BANISH_D->watch_site(nom); + else { + notify_fail("Undefined watch type: "+str+"\n"); + return 1; + } + message("info", nom+" is now an watched "+which, this_player()); + return 1; +} + +string GetHelp(){ + return ("Syntax: watch <[site|name] | [ip or site to be watched]>\n\n" + "Sets it up so that whenever a player of a certain name, or " + "a player from a certain site logs in it will get logged. " + "Examples: watch name forlock watch site 134.181.*\n" + "See also: unwatch, whowatched"); +} diff --git a/lib/secure/cmds/admins/whoallowed.c b/lib/secure/cmds/admins/whoallowed.c new file mode 100644 index 0000000..502767c --- /dev/null +++ b/lib/secure/cmds/admins/whoallowed.c @@ -0,0 +1,36 @@ +// /bin/adm/_whoallowed.c +// from the Dead Souls Mudlib +// shows who can get in from registered sites +// created by Shadowwolf@Dead Souls 93???? +// rewritten for the new security system by Descartes of Borg 930812 + +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +int cmd(string str) { + string *noms; + + if(!archp(previous_object())) return 0; + if(!sizeof(noms = BANISH_D->query_allowed())) { + write("No one is currently allowed to login from a restricted site.\n"); + return 1; + } + if(str) { + if(member_array(lower_case(str), noms) != -1) + write("You have already allowed "+capitalize(str)+" in.\n"); + else write("That name is not currently setup for registration login.\n"); + } + else { + write("These names may be used by people from restricted sites:\n"); + write(format_page(noms, 5)+"\n"); + } + return 1; +} + +string GetHelp() { + return ("Syntax: whoallowed [name]\n\n" + "Lists the names of players who may be allowed into the game " + "from sites which must register characters in order to play."); +} diff --git a/lib/secure/cmds/admins/whobanished.c b/lib/secure/cmds/admins/whobanished.c new file mode 100644 index 0000000..9e1706e --- /dev/null +++ b/lib/secure/cmds/admins/whobanished.c @@ -0,0 +1,33 @@ +// /bin/adm/_whobanished.c +// from the Dead Souls Mudlib +// lists all names banished from usage +// originally written by Shadowwolf@Dead Souls +// rewritten for the new Dead Souls security system by Descartes of Borg +// 930809 + +#include <lib.h> +#include <daemons.h> + +int cmd(string str) { + string *noms; + + if(!archp(previous_object())) return 0; + noms = BANISH_D->query_banished(); + if(str) { + if(member_array(lower_case(str), noms) == -1) + write(str+" is not currently a banished name.\n"); + else write(str+" is a banished name.\n"); + } + else { + write("These names are currently banished:\n"); + this_player()->more(explode(format_page(noms, 4), "\n")); + } + return 1; +} + +string GetHelp(){ + return ("Syntax: whobanished [name]\n\n" + "Without an argument, this command lists all names currently " + "listed as being banished. Otherwise it will confirm whether " + "the name is banished or not."); +} diff --git a/lib/secure/cmds/admins/whoguests.c b/lib/secure/cmds/admins/whoguests.c new file mode 100644 index 0000000..2b53a59 --- /dev/null +++ b/lib/secure/cmds/admins/whoguests.c @@ -0,0 +1,31 @@ +// /bin/adm/_whoguests.c +// from the Dead Souls Mudlib +// shows the list of guests allowed in when the mud is locked +// created by Descartes of Borg 08 july 1993 + +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +int cmd(string str) { + string *guests; + + if(!archp(previous_object())) return 0; + if(str) { + notify_fail("Correct syntax: whoguests\n"); + return 0; + } + catch(guests = BANISH_D->query_guests()); + message("info", "The following people are currently allowed in when " + "the mud is locked: ", this_player()); + if(!sizeof(guests)) message("info", "No guests allowed.", this_player()); + else this_player()->more(explode(format_page(guests, 5), "\n")); + return 1; +} + +string GetHelp(){ + return ("Syntax: whoguests\n\n" + "Lists all the guests allowed into the game when it is locked.\n" + "See also: addguest, removeguest"); +} diff --git a/lib/secure/cmds/admins/whoregistered.c b/lib/secure/cmds/admins/whoregistered.c new file mode 100644 index 0000000..fc4a446 --- /dev/null +++ b/lib/secure/cmds/admins/whoregistered.c @@ -0,0 +1,52 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +int cmd(string str) { + string res; + string *sites; + + if(!archp(previous_object())) return 0; + if(res=catch(sites = call_other(BANISH_D, "query_registered"))) { + write("Error in checking sites: "+res+"\n"); + return 1; + } + sites = sort_array(sites, "order_sites", this_object()); + if(str) { + if(member_array(str, sites) == -1) + write("Site \""+str+"\" is not currently on registration.\n"); + else write("Site \""+str+"\" is currently on registration.\n"); + } + else { + write("People from these sites must currently register in order to get characters:\n"); + this_player()->more(explode(format_page(sites, 5), "\n")); + } + return 1; +} + +int order_sites(string alpha, string beta) { + string *a, *b; + int i, x, y; + + a = explode(alpha, "."); + b = explode(beta, "."); + for(i=0; i<sizeof(a) && i<sizeof(b); i++) { + if(!(x = to_int(a[i]))) return -1; + if(!(y = to_int(b[i]))) return 1; + if(x > y) return 1; + if(y > x) return -1; + } + if(sizeof(a) < sizeof(b)) return -1; + else return (sizeof(a) > sizeof(b)); +} + +string GetHelp(){ + return ("Syntax: whoregistered [site]\n\n" + "Without an argument, it lists all sites which need to register " + "in order to create a character on the mud. Given with a site " + "as an argument, it will confirm if that site must register. " + "Sites must be in ip numeric format.\nSee also: " + "register, unregister, banish, unbanish, whobanished, " + "watch, unwatch, whowatched"); +} diff --git a/lib/secure/cmds/admins/whowatched.c b/lib/secure/cmds/admins/whowatched.c new file mode 100644 index 0000000..f8a7c45 --- /dev/null +++ b/lib/secure/cmds/admins/whowatched.c @@ -0,0 +1,29 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +int cmd(string str) { + string *who; + + if(!str) { + notify_fail("Check site or name?\n"); + return 0; + } + if(!archp(previous_object())) return 0; + if(str == "name") who = BANISH_D->query_watched_names(); + else if(str == "site") who = BANISH_D->query_watched_sites(); + else { + notify_fail("Whowatched what?\n"); + return 0; + } + message("info", sprintf("These %ss are being watched:", str),this_player()); + this_player()->more(explode(format_page(who, 5), "\n")); + return 1; +} + +string GetHelp(){ + return ("Syntax: whowatched name\n" + " whowatched site\n\n" + "Lists the sites or names watched."); +} diff --git a/lib/secure/cmds/builders/areaclone.c b/lib/secure/cmds/builders/areaclone.c new file mode 100644 index 0000000..237c8d0 --- /dev/null +++ b/lib/secure/cmds/builders/areaclone.c @@ -0,0 +1,97 @@ +#include <lib.h> + +string GetHelp(); + +inherit LIB_DAEMON; + +int cmd(string str) { + object ob, env; + string which, what, nom, ret; + + if(sscanf(str,"%s %s",which, what) != 2){ + write(GetHelp()); + return 1; + } + + str = which; + + switch(str){ + case "weap" : str = "weap";break; + case "weapons" : str = "weap";break; + case "weapon" : str = "weap";break; + case "ob" : str = "obj";break; + case "obs" : str = "obj";break; + case "objs" : str = "obj";break; + case "objects" : str = "obj";break; + case "meals" : str = "meal";break; + case "npcs" : str = "npc";break; + case "mob" : str = "npc";break; + case "mobs" : str = "npc";break; + case "mon" : str = "npc";break; + case "monster" : str = "npc";break; + case "monsters" : str = "npc";break; + case "rooms" : str = "room";break; + case "arm" : str = "armor";break; + case "armors" : str = "armor";break; + } + + env = environment(this_player()); + + if(!env || strsrch(base_name(env), homedir(this_player()))){ + if(creatorp(this_player())){ + write("You are a creator. Use the clone command."); + } + else { + write("You can only do this while in your area."); + } + return 1; + } + + if(str == "room"){ + write("Rooms can't be cloned. Try: areagoto"); + return 1; + } + + str = homedir(this_player()) + "/area/" + str + "/" + what; + if(last(str,2) != ".c") str += ".c"; + write("File selected: "+str); + + if(!file_exists(str)){ + write(str + " does not exist!"); + return 1; + } + + if( ret = catch(ob = new(str)) ){ + write("Error in cloning object: " + ret); + return 1; + } + + if(!ob){ + write("Failed to clone file: " + str); + return 1; + } + + if( !(ob->eventMove(this_player())) && + !(ob->eventMove(environment(this_player()))) ) { + write("Failed to properly move the object."); + return 1; + } + + nom = ob->GetShort(); + + if( !(ret = this_player()->GetMessage("clone", ob)) ) + ret = this_player()->GetName() + " clones " + nom + "."; + + say(ret); + write("You clone " + nom + " ( " + str + " )."); + + return 1; +} + +string GetHelp(){ + return ("Syntax: areaclone [ npc | weapon | armor | obj ] <name>\n\n" + "Allows a builder to bring into existence a copy of one of " + "her creations. To see the available items, use the arealist " + "command.\n" + "See also: arealist, areagoto"); +} diff --git a/lib/secure/cmds/builders/areagoto.c b/lib/secure/cmds/builders/areagoto.c new file mode 100644 index 0000000..20ae19d --- /dev/null +++ b/lib/secure/cmds/builders/areagoto.c @@ -0,0 +1,47 @@ +#include <lib.h> + +string GetHelp(); + +inherit LIB_DAEMON; + +int cmd(string str) { + if(!sizeof(str)){ + write(GetHelp()); + return 1; + } + + str = homedir(this_player()) + "/area/room/" + str; + if(last(str,2) != ".c") str += ".c"; + + if(!directory_exists(homedir(this_player()) + "/area")){ + write(homedir(this_player()) + "/area/ does not exist!"); + return 1; + } + + if(!file_exists(str)){ + write("The file "+str+" does not exist."); + return 1; + } + + if(strsrch(str,homedir(this_player()))){ + write("You can only use this command to travel to rooms "+ + "under your control."); + return 1; + } + + if(catch(load_object(truncate(str,2)))){ + write("There is a problem with that room. You stay where you are."); + return 1; + } + + this_player()->eventMoveLiving(str); + + return 1; +} + +string GetHelp(){ + return ("Syntax: areagoto <room>\n\n" + "Permits a builder to travel to rooms under her control. " + "For a list of such rooms: arealist room\n" + "See also: arealist, areaclone"); +} diff --git a/lib/secure/cmds/builders/arealist.c b/lib/secure/cmds/builders/arealist.c new file mode 100644 index 0000000..fae244c --- /dev/null +++ b/lib/secure/cmds/builders/arealist.c @@ -0,0 +1,74 @@ +#include <lib.h> + +string GetHelp(); + +inherit LIB_DAEMON; + +int cmd(string str) { + string ret, *ret_arr; + switch(str){ + case "weap" : str = "weap";break; + case "weapons" : str = "weap";break; + case "weapon" : str = "weap";break; + case "ob" : str = "obj";break; + case "obs" : str = "obj";break; + case "objs" : str = "obj";break; + case "objects" : str = "obj";break; + case "object" : str = "obj";break; + case "meals" : str = "meal";break; + case "npcs" : str = "npc";break; + case "mob" : str = "npc";break; + case "mobs" : str = "npc";break; + case "mon" : str = "npc";break; + case "monster" : str = "npc";break; + case "monsters" : str = "npc";break; + case "rooms" : str = "room";break; + case "arm" : str = "armor";break; + case "armors" : str = "armor";break; + } + + if(!sizeof(str)){ + write(GetHelp()); + return 1; + } + + write("Category selected: "+str); + str = homedir(this_player()) + "/area/" + str; + + if(!directory_exists(homedir(this_player()) + "/area")){ + write(homedir(this_player()) + "/area/ does not exist!"); + return 1; + } + + if(!directory_exists(str)){ + write(str + " does not exist!"); + return 1; + } + + ret_arr = sort_array(get_dir(str + "/"),1); + ret = ""; + + foreach(string element in ret_arr){ + if(last(element,2) == ".c"){ + element = truncate(element,2); + ret += element + "\n"; + } + } + + if(!sizeof(ret)){ + write("No files."); + return 1; + } + + this_player()->eventPage( ({ ret }) ); + return 1; +} + +string GetHelp(){ + return ("Syntax: arealist [ npc | room | weapon | armor | obj ]\n\n" + "Provides a list of the available files in a given category " + "that are under the control of the builder issuing the command. " + "For example, to see the list of rooms belonging to a builder, " + "she might issue the command: arealist room\n" + "See also: areaclone, areagoto"); +} diff --git a/lib/secure/cmds/builders/create.c b/lib/secure/cmds/builders/create.c new file mode 100644 index 0000000..f71d734 --- /dev/null +++ b/lib/secure/cmds/builders/create.c @@ -0,0 +1,68 @@ +#include <lib.h> +#include <modules.h> +#include ROOMS_H +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string str) { + string arg; + object staff; + int room; + + if(!(PLAYERS_D->CheckBuilder(this_player()))){ + write("This command is for builders and creators."); + return 1; + } + + if(!str || str == "") { + write("You'll need to be more specific. Try 'help create'"); + return 1; + } + + staff = present("tanstaafl",this_player()); + if(!staff) { + write("You must be holding the creator staff in order to use this command."); + write("If you don't know where you put it, get another one from the chest "); + write("in your workroom."); + return 1; + } + + if(sscanf(str,"room%s",arg) == 1 || + sscanf(str,"enter%s",arg) == 1 || + sscanf(str,"exit%s",arg) == 1 ) room = 1; + + if(room) staff->make(arg); + else staff->gmake(str); + + return 1; +} + +string GetHelp() { + return ("Syntax:\n" + " create room <DIRECTION> <FILE>\n" + " create room none <FILE>\n" + " create npc <FILE>\n" + " create barkeep <FILE>\n" + " create vendor <FILE>\n" + " create trainer <FILE>\n" + " create armor <FILE>\n" + " create worn_storage <FILE>\n" + " create weapon <FILE>\n" + " create item <FILE>\n" + " create container <FILE>\n" + " create bed <FILE>\n" + " create chair <FILE>\n" + " create table <FILE>\n" + " create book <FILE>\n" + " create door <DIRECTION> <FILE>\n" + " create exit <DIRECTION> <FILE>\n" + "\nThis command makes a generic copy of the type of thing " + "you specify. In the case of a room, the room you are in is " + "copied into the direction you specify. In the case of other " + "objects, a generic object appears in the room you are in. " + "After that object materializes, you can make changes to it " + "with the \"modify\" command. These changes are saved " + "automatically.\n\n" + "See also: modify, copy, delete, add, initfix"); +} diff --git a/lib/secure/cmds/builders/grant.c b/lib/secure/cmds/builders/grant.c new file mode 100644 index 0000000..fb217a4 --- /dev/null +++ b/lib/secure/cmds/builders/grant.c @@ -0,0 +1,56 @@ +/* /secure/cmd * from Dead Souls 3.2.2 + * access granting command to allow cres to give out private access + * created by Descartes of Borg 940918 + */ + +#include <lib.h> + +inherit LIB_DAEMON; + +int cmd(string str) { + string *tmp = ({}); + string type, file, who, path; + + if(!str) return notify_fail("Syntax: grant [access] to [who] on [file]\n"); + else if(sscanf(str, "%s to %s on %s", type, who, file) != 3) + return notify_fail("Syntax: grant [access] to [who] on [file]\n"); + if(sizeof(tmp = explode(file, "/")) < 2) + return notify_fail("You cannot grant such access.\n"); + if(tmp[0] != "domains" && tmp[0] != "realms" && tmp[0] != "estates") + return notify_fail("You cannot grant such access.\n"); + path = homedir(this_player()) + "/"; + if(file_size(path+"adm") != -2) mkdir(path+"adm"); + file = absolute_path(this_player()->query_cwd(), file); + if(!file_exists(path+"adm/access.c")) + write_file(path+"adm/access.c", "#include <lib.h>\n\ninherit LIB_ACCESS;\n"); + if(file_size(file) == -2 && file[strlen(file)-1] != '/') file = file + "/"; + if(type == "read" || type == "all") { + if(!(call_other(path+"adm/access","grant_access","read",file,who))) + return notify_fail("Read access grant failed!\n"); + if( file_size(file) == -2 ) { + if( !(call_other(path + "adm/access", "grant_access", "read", + file[0..<2], who)) ) + return notify_fail("Read access grant failed.\n"); + } + } + if(type == "write" || type == "all") { + if(!(call_other(path+"adm/access","grant_access","write",file,who))) + return notify_fail("Write access grant failed!\n"); + if( file_size(file) == -2 ) { + if( !(call_other(path + "adm/access", "grant_access", "write", + file[0..<2], who)) ) + return notify_fail("Write access grant failed.\n"); + } + } + message("system",capitalize(type)+" access granted to "+who+" on "+file+".", + this_player()); + return 1; +} + +string GetHelp(){ + return ("Syntax: grant <accesstype> to <whom> on <file|directory>\n\n" + "Allows you to give creators access to files or directories " + "under your control. The accesstype parameter is \"read\", " + "\"write\", or \"all\".\n" + "There is no \"ungrant\" or \"deny\" command. "); +} diff --git a/lib/secure/cmds/builders/home.c b/lib/secure/cmds/builders/home.c new file mode 100644 index 0000000..40962f7 --- /dev/null +++ b/lib/secure/cmds/builders/home.c @@ -0,0 +1,65 @@ +/* /cmds/creator/home.c + * from the Dead Souls LPC Library + * command to take a creator home + * created by Descartes of Borg long ago (modified 950331) + */ + +#include <lib.h> +#include <objects.h> +#include <daemons.h> + +inherit LIB_DAEMON; +string arg; + +mixed GoHome(string str) { + object ob, prev; + string who, room; + + prev = environment(this_player()); + if( !str || str == "" || !creatorp(this_player())){ + who = this_player()->GetKeyName(); + } + else who = lower_case(str); + if(!user_exists(who)) return "There's no such user."; + room = PLAYERS_D->GetHomeRoom(who); + if(!room || !strsrch(room, "/tmp/")){ + str = user_path(who, 1); + if(!directory_exists(str)) return "That person has no home dir."; + str = user_path(who, 1)+"workroom.c"; + arg = str; + if(!unguarded((: file_exists(arg) :))) + return capitalize(who)+" has no active workroom."; + } + else str = room; + catch(ob = load_object(str)); + if(!ob){ + if(who != this_player()->GetKeyName()) + return "\n"+capitalize(who)+"'s workroom is broken."; + return "\nYour workroom is broken."; + } + if(ob == prev) + return "You twitch."; + if(who == this_player()->GetKeyName()) + if( this_player()->eventMoveLiving(ob,"$N goes home.","$N returns home.") ) { + return 1; + } + if(who != this_player()->GetKeyName()) + if( this_player()->eventMoveLiving(ob,"$N leaves to visit "+capitalize(who)+".", + "$N comes in for a visit.") ) { + return 1; + } + return "You stay where you are."; +} + +mixed cmd(string str){ + return unguarded( (: GoHome($(str)) :) ); +} + +string GetHelp(){ + return ("Syntax: home\n home [creator]\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. Non-creator builders can only go to their own " + "workroom.\n" + "See also: goto, trans, homeroom"); +} diff --git a/lib/secure/cmds/builders/unvirt.c b/lib/secure/cmds/builders/unvirt.c new file mode 100644 index 0000000..3318862 --- /dev/null +++ b/lib/secure/cmds/builders/unvirt.c @@ -0,0 +1,101 @@ +#include <lib.h> +#include <objects.h> +#include <daemons.h> + +inherit LIB_DAEMON; +string *features = ({ "GetLong", "GetShort", "GetAmbientLight", + "GetDayLight", "GetNightLight", "GetDayLong", "GetNightLong", + "GetDayShort", "GetNightShort", "GetExitMap", "GetFlyRoom", + "GetSinkRoom", "GetClimate", "GetTerrainType", + "GetItemsMap", "GetProperties", "GetSmellMap", "GetListenMap", + "GetGravity", "GetMedium", "GetPlayerKill", "GetTown", + }); + + +mixed cmd(string str){ + mapping RoomElements = ([]); + object here = environment(this_player()); + object staff = present("tanstaafl",this_player()); + if(!here) return 0; + + if(!staff){ + write("You must be holding the Creator Staff in order to use this command."); + return 1; + } + + if(file_exists(base_name(here)+".c")){ + write("This environment is already not virtual."); + return 1; + } + + foreach(string feature in features){ + RoomElements[feature] = call_other(here, feature); + } + + cp("/obj/room.c", base_name(here)+".c"); + + reload(base_name(here)); + + foreach(mixed key, mixed val in RoomElements){ + string tmp, file_contents; + write("%^RED%^"+key+"%^RESET%^: "+identify(val)); + if(!val || ((mapp(val) || stringp(val)) && !sizeof(val)) ) true(); + else { + //write(key+": "+identify(val)); + key = replace_string(key,"Get","Set",1); + switch(key){ + case "SetExitMap" : key = "SetExits"; break; + case "SetItemsMap" : key = "SetItems"; break; + case "SetSmellMap" : key = "SetSmell"; break; + case "SetListenMap" : key = "SetListen"; break; + default : + } + if(key == "SetTerrainType"){ + tmp = implode(TYPES_D->eventCalculateTypes("terrain",val),"|"); + tmp = "SetTerrainType("+tmp+");"; + staff->eventDelete(environment(this_player()), "SetTerrainType"); + file_contents = staff->eventAppendLast(base_name(environment(this_player()))+".c", "create", tmp); + rm(base_name(environment(this_player()))+".c"); + if(!grepp(file_contents,"terrain_types.h")){ + write_file(base_name(environment(this_player()))+".c", + "#include <terrain_types.h>\n",1); + } + write_file(base_name(environment(this_player()))+".c",file_contents); + } + else if(key == "SetMedium"){ + tmp = TYPES_D->eventCalculateTypes("medium",val); + tmp = "SetMedium("+tmp+");"; + staff->eventDelete(environment(this_player()), "SetMedium"); + file_contents = staff->eventAppendLast(base_name(environment(this_player()))+".c", "create", tmp); + rm(base_name(environment(this_player()))+".c"); + if(!grepp(file_contents,"medium.h")){ + write_file(base_name(environment(this_player()))+".c", + "#include <medium.h>\n",1); + } + write_file(base_name(environment(this_player()))+".c",file_contents); + + } + else if(mapp(val)){ + val = staff->eventStringifyMap(val); + tmp = key + "( "+val+" );"; + staff->eventDelete(environment(this_player()), key); + file_contents = staff->eventAppendLast(base_name(environment(this_player()))+".c", "create", tmp); + write_file(base_name(environment(this_player()))+".c",file_contents,1); + } + else staff->eventModify(environment(this_player()),lower_case(key)+" "+val); + } + staff->eventModify(environment(this_player()),"setshort "+RoomElements["GetShort"]); + } + return 1; +} + +string GetHelp() { + return ("Syntax: unvirt\n\n" + "This command will gather the room data of the virtual room you " + "are standing in, and try to make a non-virtual room with it, " + "writing to the file that the virtual room is pretending to use. " + "If you lack write permissions to that file, the command will fail " + "in a rather ugly way.\n" + "See also: modify, create, delete, copy, areaclone, " + "areagoto, arealist"); +} diff --git a/lib/secure/cmds/creators/about.c b/lib/secure/cmds/creators/about.c new file mode 100644 index 0000000..d5ea2c4 --- /dev/null +++ b/lib/secure/cmds/creators/about.c @@ -0,0 +1,52 @@ +#include <lib.h> +#include <message_class.h> + +inherit LIB_DAEMON; + +mixed cmd(string str) { + object thing; + string file, content; + + if(!str){ + write("Try: help about"); + return 1; + } + + thing = get_object(str); + + if(!thing){ + write("There's no such object available here."); + return 1; + } + + if(interactive(thing)){ + write("Player save files are not subject to examination " + "with this command."); + return 1; + } + + file = lpc_file(base_name(thing)); + + if(!file && thing->GetVirtual()){ + file = lpc_file(path_prefix(base_name(thing))); + } + + if(file && file_exists(file)) content = read_file(file); + + if(!content){ + write("That data is not currently available to you."); + return 1; + } + + message( "info", file + "\n", this_player() ); + + return this_player()->eventPage( explode(content, "\n"), + MSG_SYSTEM | MSG_NOCOLOUR); +} + +string GetHelp(string str) { + return ("Syntax: about <OBJECT>\n" + " about here\n\n" + "Displays the code for the object, if the file is " + "available.\nSee also: more, find, findobj"); +} diff --git a/lib/secure/cmds/creators/addemote.c b/lib/secure/cmds/creators/addemote.c new file mode 100644 index 0000000..c183b39 --- /dev/null +++ b/lib/secure/cmds/creators/addemote.c @@ -0,0 +1,329 @@ +/* /secure/cmds/admins/addemote.c + * From the Dead Souls Mud Library + * A sane command for doing emote addition + * Created by Descartes of Borg 961208 + * Version: @(#) addemote.c 1.2@(#) + * Last modified: 96/12/14 + */ + +#include <lib.h> +#include <daemons.h> +#include <message_class.h> + +inherit LIB_DAEMON; + +static void MainMenu(); +static void EditErrorMessage(string emote); +static void ShowEmote(string emote); +static void AddEmote(string emote); +static void AddRule(string rule, string emote); + +static private void validate() { + if(!this_player()) return 0; + if( !(master()->valid_apply(({ "ASSIST" }))) && + !member_group(this_player(), "EMOTES") ) + error("Illegal attempt to access addemote: "+get_stack()+" "+identify(previous_object(-1))); +} + +static void EnterEmote(string emote, string array emotes) { + int x = to_int(emote); + validate(); + if( x < 1 || x > sizeof(emotes) ) { + if( member_array(emote, emotes) == -1 ) { + if( emote[0] == 'q' ) { + return; + } + MainMenu(); + return; + } + } + else { + emote = emotes[x-1]; + } + ShowEmote(emote); +} + +static void EnterEditChoice(string str, string array rules, string emote) { + int x = to_int(str); + validate(); + if( x < 1 || x > sizeof(rules) ) { + if( member_array(str, rules) == -1 ) { + if( !str || str == "" ) { + MainMenu(); + return; + } + if( str[0] == 'q' ) { + return; + } + else if( str[0] == 'e' ) { + EditErrorMessage(emote); + return; + } + else if( str[0] == 'a' ) { + this_player()->eventPrint("Enter verb rule: ", MSG_PROMPT); + input_to((: AddRule :), emote); + return; + } + else { + ShowEmote(emote); + return; + } + } + AddRule(str, emote); + } + else { + AddRule(rules[x-1], emote); + } +} + +static void AddAdverbs(string adv, string emote, string array rules, + string array verbs, string msg) { + string array adverbs; + validate(); + if( !adv || adv == "" ) { + adverbs = ({}); + } + else { + adverbs = map(explode(adv, ","), (: trim :)); + } + foreach(string rule in rules) { + SOUL_D->AddRule(emote, rule, ({ verbs, msg }), adverbs); + } + this_player()->eventPrint("Emote '" + emote + "' added."); +} + +static void AddMessage(string msg, string emote, string array rules, + string array verbs) { + validate(); + if( !msg || msg == "" ) { + this_player()->eventPrint("Which message? [q to quit] ", MSG_PROMPT); + input_to((: AddMessage :), emote, rules, verbs); + return; + } + if( lower_case(msg) == "q" ) { + this_player()->eventPrint("Addition of rule aborted."); + return; + } + this_player()->eventPrint("Enter adverbs: ", MSG_PROMPT); + input_to((: AddAdverbs :), emote, rules, verbs, msg); +} + +static void AddVerbs(string list, string emote, string array rules) { + string array verbs = map(explode(list, ","), (: trim :)); + validate(); + + this_player()->eventPrint("Enter message: ", MSG_PROMPT); + input_to((: AddMessage :), emote, rules, verbs); +} + +static void AddRule(string rule, string emote) { + string array rules = map(explode(rule, ","), (: trim :)); + validate(); + + if( !sizeof(rules) ) { + rules = ({ "" }); + } + this_player()->eventPrint("Enter the verbs: ", MSG_PROMPT); + input_to((: AddVerbs :), emote, rules); +} + +static void AddErrorMessage(string msg, string emote) { + validate(); + if( !msg || msg == "" ) { + this_player()->eventPrint("Which message? [q to quit] ", MSG_PROMPT); + input_to((: AddErrorMessage :), emote); + return; + } + if( !emote || emote == "" ) { + this_player()->eventPrint("Which emote? [q to quit] ", MSG_PROMPT); + input_to((: AddEmote :)); + return; + } + emote = lower_case(emote); + if( lower_case(msg) == "q" ) { + this_player()->eventPrint("Addition of emote aborted."); + return; + } + SOUL_D->AddVerb(emote, msg); + this_player()->eventPrint("Enter a parser rule for " + emote + ": ", + MSG_PROMPT); + input_to((: AddRule :), emote); +} + +static void AddEmote(string emote) { + validate(); + if( !emote || emote == "" ) { + this_player()->eventPrint("Which emote? [q to quit] ", MSG_PROMPT); + input_to((: AddEmote :)); + return; + } + emote = lower_case(emote); + if( emote == "q" ) { + this_player()->eventPrint("Addition of emote aborted."); + return; + } + this_player()->eventPrint("Enter error message: ", MSG_PROMPT); + input_to((: AddErrorMessage :), emote); +} + +static void MainMenu() { + string array emotes = SOUL_D->GetEmotes(); + string array display = allocate(sizeof(emotes)); + int array screen = this_player()->GetScreen() || ({ 80, 25 }); + string tmp; + int i; + validate(); + + tmp = center("Dead Souls Emote Editor", screen[0]) + "\n"; + for(i=0; i<sizeof(display); i++) { + display[i] = "[" + (i+1) + "] " + emotes[i]; + } + tmp += format_page(display, screen[0]/17) + "\n"; + this_player()->eventPrint(tmp, MSG_SYSTEM); + this_player()->eventPrint("Enter an emote or 'q' to quit: ", MSG_PROMPT); + input_to((: EnterEmote :), emotes); +} + +static void EditErrorMessage(string emote) { + validate(); + this_player()->eventPrint("Enter new error message: ", MSG_PROMPT); + input_to(function(string str, string emote) { + if( str && str != "" ) { + SOUL_D->SetErrorMessage(emote, str); + } + ShowEmote(emote); + }, emote); +} + +static void ShowEmote(string emote) { + string err = SOUL_D->GetErrorMessage(emote); + mapping rules = SOUL_D->GetRules(emote); + int array screen = this_player()->GetScreen() || ({ 80, 25 }); + string tmp = center("Dead Souls Emote Editor", screen[0]) + "\n\n"; + string tmp2 = ""; + string array rule_array = allocate(sizeof(rules)); + int i = 0; + validate(); + + tmp += "%^GREEN%^Emote%^RESET%^: " + emote + "\n"; + tmp += "%^GREEN%^Error Message%^RESET%^: " + err + "\n"; + tmp += "%^GREEN%^Rules%^RESET%^:\n"; + foreach(string rule, mixed array data in rules) { + rule_array[i] = rule; + tmp += "[" + (i+1) + "] \"" + rule + "\": " + data[1][1] + "\n"; + tmp += " Adverbs: " + wrap(item_list(data[0]), screen[0]) + "\n"; + i++; + } + //Following fix courtesy of Alecksy + this_player()->eventPage(explode(tmp,"\n"), MSG_SYSTEM); + tmp2 = "Enter rule to edit, 'a' to add rule, 'e' to edit error msg, or 'q' to quit: "; + this_player()->eventPrint(tmp2,MSG_PROMPT); + input_to( (: EnterEditChoice :), rule_array, emote ); +} + +mixed cmd(string args) { + if( !(master()->valid_apply(({ "ASSIST" }))) && + !member_group(this_player(), "EMOTES") ){ + write("You are not admin, nor a member of the EMOTES group."); + return 1; + } + + if( !args || args == "" ) { + this_player()->eventPrint("Enter emote name: ", MSG_PROMPT); + input_to((: AddEmote :)); + } + else if( args[0] == '-' ) { + if( args == "-edit" ) { + MainMenu(); + } + else if( args == "-add") { + this_player()->eventPrint("Enter emote name: ", MSG_PROMPT); + input_to((: AddEmote :)); + } + else { + MainMenu(); + } + } + else { + if( member_array(args, SOUL_D->GetEmotes()) == -1 ) { + AddEmote(args); + } + else { + ShowEmote(args); + } + } + return 1; +} + +string GetHelp(){ + return ("Syntax: <addemote>\n" + " <addemote EMOTE>\n" + " <addemote -edit>\n" + " <addemote -add>\n\n" + "You must be admin or member of the EMOTES group to use this command.\n\n" + "Used to add and edit emotes in the soul daemon using complex " + "rules and the Dead Souls messaging system. In order to add " + "a new emote using this command, you need to know the following " + "information:\n" + "\t* Verb parse rule\n" + "\t* Verbs to be conjugated in the message\n" + "\t* The messaging system generic format for the message\n" + "\t* Any adverbs supported specially for the message\n\n" + "The verb parse rule is a set of tokens governing how the " + "command should be entered. The only tokens supported by the " + "soul are LIV (for one living thing), LVS (for one to many living " + "things), and STR (for any arbitrary string). In addition, the " + "rule can contains prepositions like to, at, on, about, etc. " + "For example, to allow a player to do <smile at descartes>, you " + "need the parse rule <at LIV> or <at LVS>. <smile oddly at " + "descartes> would be <STR at LIV> or <STR at LVS>.\n" + "In general, you should allow players to enter in commands using " + "correct English and a syntax without prepositions. For " + "example, since we have <at LVS>, we should also allow " + "<LVS>. To support identical rules like this, when the " + "<addemote> command asks for a parser rule, you can enter in " + "multiple identical rules on the same line, separated by " + "commas:\n" + "Enter parser rule: at LVS,LVS\n\n" + "The next step is defining which verbs need conjugating in your " + "message for the emote. With the smile emote, the only verb is " + "\"smile\". However, for more complex emotes, you may have " + "multiple verbs which need conjugating. Just enter them as a " + "comma separated list. For example, if you have an emote that " + "should print the message \"Descartes rants and raves.\", then " + "you will need to enter the verbs rant and rave:\n" + "Enter verbs: rant,rave\n\n" + "The next step is specifying the message that gets shown. Your " + "message uses place holders, also called tokens, to stand in " + "for bits of the message that change depending on point of " + "view. In the rant and rave example, Descartes would see:\n" + "You rant and rave.\n" + "Everyone else sees:\n" + "Descartes rants and raves.\n" + "The only thing that stays the same is the word \"and\". You " + "need tokens to stand for the rest. A full list of tokens is " + "specified in <help messaging> and they all begin with a $ sign. " + "One extremely important thing to remember is that you need " + "the exact same number of $agent_verb or $target_verb tokens in " + "your message as the number of verbs you specified for " + "conjugation. In the rant and rave example, I need two verb " + "tokens to match up with my two verbs I am conjugating. They " + "will be handled in the order they appear. In other words, the " + "rant verb will match to the first verb token, and the rave " + "verb will match to the second verb token. Verb tokens count " + "as any combination of $agent_verb and $target_verb:\n" + "Enter message: $agent_name $agent_verb and $agent_verb.\n\n" + "The last thing you need to enter is a list of adverbs. " + "As with other lists, this list is comma separated. And as with " + "other bits of this system, it has a little complexity to it. " + "If you do not enter anything, then no adverbs are used for this " + "rule. In fact, you must specify a STR token in the rule for " + "adverbs to be relevant. If you do specify an STR rule, you " + "should specify something on the adverb line. Any adverbs you " + "enter are considered special adverbs just for this rule. If " + "you wish the general list of adverbs to be available as well, " + "you can enter a - as one of the adverbs. If you wish the " + "player to be able to add anything that comes to mind, enter " + "a *:\n" + "Enter adverbs: -"); +} diff --git a/lib/secure/cmds/creators/bk.c b/lib/secure/cmds/creators/bk.c new file mode 100644 index 0000000..110c612 --- /dev/null +++ b/lib/secure/cmds/creators/bk.c @@ -0,0 +1,48 @@ +#include <lib.h> +#include <dirs.h> + +inherit LIB_DAEMON; + +mixed cmd(string str) { + string *file_arr; + string tmp, filename, str2, orig; + int time; + object ob; + + orig = str; + if( !str ) return "You must specify a file to backup."; + else str = absolute_path(this_player()->query_cwd(), str); + if( !file_exists(str) ) str2 = str+".c"; + if( !file_exists(str) && !file_exists(str2)) { + if(str == "here" || str == "room") ob = environment(this_player()); + else { + ob = present(orig,environment(this_player())); + if(!ob) ob = present(orig, this_player()); + if(!ob) return "File not found."; + } + str2 = base_name(ob)+".c"; + } + if(str2 && !file_exists(str2)) return "File unfound."; + else if(str2) str = str2; + if( !(tmp = read_file(str)) ) + return "Unable to read file " + str + "."; + + else { + time = time(); + file_arr = explode(str,"/"); + filename = REALMS_DIRS + "/" + this_player()->GetKeyName(); + filename += "/bak/"+file_arr[sizeof(file_arr)-1]+"."+time; + write_file(REALMS_DIRS + "/" + this_player()->GetKeyName()+ + "/bak/bk.db",file_arr[sizeof(file_arr)-1]+"."+time+" : "+str+"\n"); + load_object("/secure/cmds/creators/cp")->cmd(str + " " +filename); + } + return 1; +} + +string GetHelp(){ + return ("Syntax: bk [file]\n" + " bk here\n\n" + "Copies the specified file into your bak/ directory, and " + "appends a unique identifying number to the backup file name.\n" + "See also: restore, find, reload"); +} diff --git a/lib/secure/cmds/creators/call.c b/lib/secure/cmds/creators/call.c new file mode 100644 index 0000000..545957f --- /dev/null +++ b/lib/secure/cmds/creators/call.c @@ -0,0 +1,77 @@ +/* /secure/cmds/creator/call.c + * from the Foundation II LPC Library + * allows you to call functions in objects ad hoc + * created by Descartes of Borg 950430 + */ + +#include <privs.h> +#include <lib.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + mixed *arg_arr; + function f; + object target; + mixed val; + string arg_targ, arg_func, err; + int i, maxi; + + if(!member_group(previous_object(), PRIV_SECURE)) { + log_file("adm/call", query_privs(previous_object()) + +" ("+ctime(time())+"): call "+args+"\n"); + } + if( !args || args == "" ) return "Call ob->func(arg1, arg2)\n"; + if( sscanf(args, "%s->%s(%s", arg_targ, arg_func, args) != 3 ) + return "Call ob->func(arg1, arg2)\n"; + args = trim(args); + if( args != ")" ) args = args[0..<2]; + else args = ""; + if( !(target = to_object(arg_targ)) ) + return "Cannot identify any object as \"" + arg_targ + "\"."; + if( !function_exists(arg_func, target) ) + return "The function " + arg_func +"() is not in " + + identify(target) + "\n"; + f = (: call_other, target, arg_func :); + if( args == "" ) { + err = catch(val = evaluate(f)); + if( err) { + message("error", identify(target) + " -> " + arg_func + "()", + this_player()); + message("error", "Error in execution: " + err, this_player()); + return 1; + } + else { + message("system", identify(target) + " -> " + arg_func + "() = " + + identify(val), this_player()); + return 1; + } + } + arg_arr = convert_string("({"+args+"})"); + err = catch(val = call_other(target, ({ arg_func }) + arg_arr)); + args = identify(target) + " -> " + arg_func + "( "; + for(i = 0, maxi = sizeof(arg_arr); i<maxi; i++) { + args += identify(arg_arr[i]); + if( i < maxi - 1 ) args += ", "; + } + if( err ) { + message("error", args + ")", this_player()); + message("error", "Error in execution: " + err, this_player()); + return 1; + } + args += " ) = " + identify(val); + message("system", args, this_player()); + return 1; +} + +string GetHelp(){ + return ("Syntax: call object->function(args)\n\n" + "Examples:\n\tcall me->GetName()\n" + "\tcall \"/realms/descartes/workroom\"->GetProperty(\"light\")\n\n" + "Allows you to call any function in any object with any set of " + "arguments from the command line. The syntax is identical to " + "that you would use inside LPC code, except that you can refer " + "to objects by their names or by pronouns in addition to the " + "usual manners.\n" + "See also: eval, gauge"); +} diff --git a/lib/secure/cmds/creators/cat.c b/lib/secure/cmds/creators/cat.c new file mode 100644 index 0000000..5ddab8f --- /dev/null +++ b/lib/secure/cmds/creators/cat.c @@ -0,0 +1,32 @@ +/* /secure/cmds/creator/cat.c + * from the Foundation II LPC Library + * command to display file contents + * created by Descartes of Borg 940124 + * some updates made 950915 + */ + +#include <lib.h> + +inherit LIB_DAEMON; + +mixed cmd(string str) { + string *arr; + string tmp; + + if( !str ) return "You must specify a file to cat."; + else str = absolute_path(this_player()->query_cwd(), str); + if( !file_exists(str) ) return "File " + str + " not found."; + else if( !(tmp = read_file(str)) ) + return "Unable to read file " + str + "."; + if( sizeof(arr = explode(tmp, "\n")) > 100 ) + tmp = implode(arr[0..99], "\n") + "\n\t*** TRUNCATED ***"; + message("system", tmp, this_player()); + return 1; +} + +string GetHelp(){ + return ("Syntax: cat <file>\n\n" + "Displays the contents of the file mentioned all at once. " + "May truncate output if it is a long file.\n" + "See also: longcat"); +} diff --git a/lib/secure/cmds/creators/cd.c b/lib/secure/cmds/creators/cd.c new file mode 100644 index 0000000..54874f7 --- /dev/null +++ b/lib/secure/cmds/creators/cd.c @@ -0,0 +1,17 @@ +/* /cmd * from Dead Souls + * help for the cd command (located inside the player object) + * created by Descartes of Borg 940723 + */ + +#include <lib.h> + +inherit LIB_DAEMON; + +string GetHelp() { + return ("Syntax: cd [directory]\n\n" + "Defined internal to the user object.\n" + "Changes your current working directory to the directory " + "you specify. If no directory is specified, it will make your " + "home directory current.\n" + "See also: pwd, mkdir, rmdir"); +} diff --git a/lib/secure/cmds/creators/ced.c b/lib/secure/cmds/creators/ced.c new file mode 100644 index 0000000..accbcf7 --- /dev/null +++ b/lib/secure/cmds/creators/ced.c @@ -0,0 +1,78 @@ +#include <lib.h> +#include <commands.h> +#ifndef CED_DISABLED +#define CED_DISABLED 1 +#endif + +inherit LIB_DAEMON; + +mixed cmd(string args) { + int x = this_player()->GetCharmode(); + + if( args == "" || !args ) + args = user_path(this_player()->GetKeyName()) + "tmp.edit"; + if( this_player()->GetForced() ) { + message("system", "Someone tried to force you to edit "+ args +"\n" + + identify(previous_object(-1)), this_player()); + return 0; + } + + if(!x){ + write("Character mode is a requirement for using this "+ + "command. For more information, see: help charmode"); + return 1; + } + + if(!this_player()->GetProperty("cedWarned")){ + write("This is the first time you've used ced. If you get stuck, " + "simply hit: Ctrl-Q"); + this_player()->SetProperty("cedWarned", 1); + } + args = absolute_path( this_player()->query_cwd(), args ); + if( (x = file_size(args)) == -2 ) + return "You cannot edit a directory!"; + else if( x == -1 ) + message("editor", args + ", new file, starting in input mode.\n", + this_player()); + else message("editor", args + ", " + x + " bytes\n", this_player()); + CMD_BK->cmd(args); + this_player()->SetCedmode(1, args); + return 1; +} + +string GetHelp(){ + string ret = ""; + ret += "Syntax: ced [FILE]\n\n"; + ret += "This command starts a character-mode editing session on the "+ + "specified file. Note that without charmode enabled, this "+ + "will not work. Special commands are issued by pressing the "+ + "\"Control\" key and another key at the same time. For "+ + "example, to quit without saving, you press and hold "+ + "the control key, then the 'q' key. This is known as Ctrl-Q. "+ + "The special commands for ced are:\n\n"+ + "Ctrl-Q -- quit without saving\n"+ +#if CED_DISABLED + "Ctrl-X -- %^RED%^DISABLED FUNCTION%^RESET%^\n"+ + "Ctrl-S -- %^RED%^DISABLED FUNCTION%^RESET%^\n"+ +#else + "Ctrl-X -- quit and save\n"+ + "Ctrl-S -- save\n"+ +#endif + "Ctrl-I -- enable insert mode\n"+ + "Ctrl-O -- enable overstrike mode\n"+ + "Ctrl-L -- refresh the page\n"+ + "Ctrl-F -- scroll forward one page\n"+ + "Ctrl-B -- scroll backward one page\n"+ + "Ctrl-D -- delete current line\n"+ + "Ctrl-G -- Specify a line to go to\n"+ + "Ctrl-/ -- Search for a string\n"+ + "\nTo navigate in the screen, use the arrow keys on your keyboard. "+ + "Note that ced is extremely basic and experimental. "+ + "\nSee also: ed, charmode, bk, restore, env"+ +#if CED_DISABLED + "\n\n Please note that due to its alpha status, saving files in "+ + "ced is disabled for now."+ +#endif + ""; + return ret; +} diff --git a/lib/secure/cmds/creators/changelog.c b/lib/secure/cmds/creators/changelog.c new file mode 100644 index 0000000..9d08688 --- /dev/null +++ b/lib/secure/cmds/creators/changelog.c @@ -0,0 +1,70 @@ +/* /cmd * from Dead Souls + * a command for logging changes made + * created by Descartes of Borg 940701 + * bug fixed by Pallando, 940702 + */ + +#include <lib.h> +#include <dirs.h> +#include <objects.h> + +#define CHANGELOG "ChangeLog" +#define TMP_FILE DIR_TMP + "/" + previous_object()->GetKeyName() + ".change" + +inherit LIB_DAEMON; + +int post_change(mixed *args); + +int cmd(string str) { + string *tmp; + string file; + int i; + + if(!str) str = this_player()->get_path(); + str = absolute_path(this_player()->get_path(), str); + if(file_size(str) == -1) return notify_fail("Invalid path.\n"); + if(file_size(file = str) != -2) { + i = sizeof(tmp = explode(str, "/")); + if(i < 2) str = "/"; + else str = "/"+implode(tmp[0..i-2], "/"); + } + if(str[strlen(str)-1] != '/') str += "/"; + str += CHANGELOG; + message("system", "Logging changes to "+str+"...", this_player()); + this_player()->eventEdit(TMP_FILE, (: post_change, ({ file, str }) :)); + return 1; +} + +void abort() { rm(TMP_FILE); } + +void post_change(mixed *args) { + string *tmp; + string file, change, str, str2; + int i, maxi; + + change = args[0]; + file = args[1]; + if(!userp(previous_object())) return; + str = read_file(TMP_FILE); + rm(TMP_FILE); + if( !str ) { write( "Aborting.\n" ); return; } + str = replace_string(str, "\n", " "); + maxi = sizeof(tmp = explode(wrap(str, 60), "\n")); + str = "- "+ change+"\n"; + str += " "+ctime(time())+" by "+previous_object()->GetCapName()+ + "("+previous_object()->query_rname()+"):\n"; + for(i=0; i<maxi; i++) str += " * "+tmp[i]+"\n"; + if(str2 = read_file(file)) str2 = str+"\n\n"+str2; + else str2 = str; + rm(file); + write_file(file, str2); + if(str2 = read_file(DIR_LOGS+"/"+CHANGELOG)) str = str + "\n\n"+str2; + rm(DIR_LOGS+"/"+CHANGELOG); + write_file(DIR_LOGS+"/"+CHANGELOG, str); +} + +string GetHelp(){ + return ("Syntax: changelog <directory>\n" + "Lets you enter documentation on changes you have made to files in " + "directory <directory>\n"); +} diff --git a/lib/secure/cmds/creators/cp.c b/lib/secure/cmds/creators/cp.c new file mode 100644 index 0000000..c0d25f0 --- /dev/null +++ b/lib/secure/cmds/creators/cp.c @@ -0,0 +1,117 @@ +/* +// This file is a part of the TMI distribution mudlib. +// Please retain this header if you use this code. +// Coded by Grog (10/15/91 - 11/03/91) +// Added to the /bin structure by Buddha (1/18/91) +// Help added by Brian (1/28/92) +// Single arg cp added by Scythe@Dead Souls (1/25/93) +// Bug in single arg cp fixed by Pallando (5/26/93) +// Added wild card support by Brodbane@Eve (4/3/06) + */ + +#include <lib.h> +inherit LIB_DAEMON; + +string GetHelp(); + +string rmSlash(string str) { return replace_string(str,"//","/"); } + +int cmd(string str) { + string s1; + string file1; + string file2; + int localdest; + string *files; + int ow; + + if(this_player()->GetForced()) { + write("Someone has tried forcing you to cp " + str); + return 1; + } + localdest = 0; /* Assume it's not a local destination */ + if( str && sscanf( str, "-f %s", s1)) { + ow = 1; + str = s1; + } + + if (!str || sscanf(str, "%s %s", file1, file2) != 2) { + if (str && sscanf(str, "%s", file1)) { + file2 = ""; // Check to see if it's a one arg + localdest = 1; // cp function. Assume localdest. + } else { + write(GetHelp()); + return 1; + } + } + + /* check for last parameter == "." */ + if (file2 == ".") { + localdest = 1; /* It's a local destination */ + file2 = ""; + } + /* Given the player's current working directory and the path(s) + for the file, construct the new full path for both files */ + file1 = absolute_path(this_player()->query_cwd(), file1); + file2 = absolute_path(this_player()->query_cwd(), file2); + + /* Added by Brodbane to handle wild card options, 3/3/06 */ + if( !sizeof( files = wild_card( file1 ) ) ) + files = ({ file1 }); + if( sizeof(files) > 1 ) + { + switch( file_size(file2) ) + { + case -1: + this_player()->eventForce("mkdir "+file2); + break; + case -2: + break; + default: + return(write("Cannot copy wild card to a single file."),1); + } + } + + foreach( string file in files ) { + string dest = (file_size(file2)==-2 ? rmSlash(file2+"/"+ + explode( file, "/")[<1]) : file2 ); + + + if( file_size( file ) == -2 ) { + localdest = 1; + if( sizeof(files) > 1 ) + continue; + else write( "cp: "+file+" is a directory." ); + } + else if( file_size(file) < 1 ) { write( "cp: couldn't find "+file ); } + else if( file == dest ) write( "cp: You cant copy a file on to itself!" ); + else if( file_size(dest) > 0 && !ow && !sscanf(dest, "%*s.save" )) write( "cp: "+dest+" already exists." ); + else if( !master()->valid_read( file, this_player(), "cp" ) ) write( file+": Permission denied." ); + else if( !master()->valid_write( dest, this_player(), "cp" ) ) write( dest+": Permission denied." ); + else { + /* Dunno what this was about. Commenting rather + * than deleting, in case there was a good reason. + * write_file( dest, read_file(file), 1 ); + */ + if(cp(file, dest) > 0){ + write( "Copied: "+file+" to "+dest ); + } + else { + write("Copy failed."); + } + } + } + return 1; +} + + +string GetHelp(){ + return ("Command: cp\nSyntax: cp <oldfile> [pathname]<newfile>\n" + "This command makes a copy of the file using the new name " + "and location passed. If a new pathname is not specified " + "then the copy is put into the present working directory. " + "Optionally, wild cards can be used by employing the * operator.\n" + "The -f flag forces overwriting of an existing file.\n\n" + "Examples:\n" + "cp -f workroom.bak workroom.c\n" + "cp workroom.bak /tmp/"); +} diff --git a/lib/secure/cmds/creators/cwd.c b/lib/secure/cmds/creators/cwd.c new file mode 100644 index 0000000..b57cb96 --- /dev/null +++ b/lib/secure/cmds/creators/cwd.c @@ -0,0 +1,14 @@ +/* + * Help for the cwd command (located inside the player object) + */ + +#include <lib.h> + +inherit LIB_DAEMON; + +string GetHelp(){ + return ("Syntax: cwd\n\n" + "Defined internal to the user object.\n" + "Prints your current working directory.\n" + "See also: cd, mkdir, rmdir"); +} diff --git a/lib/secure/cmds/creators/dbxframe.c b/lib/secure/cmds/creators/dbxframe.c new file mode 100644 index 0000000..5bc2b9e --- /dev/null +++ b/lib/secure/cmds/creators/dbxframe.c @@ -0,0 +1,44 @@ +mapping frame; + +int cmd(string str) { + object ob; + string who; + int num, i; + string ret = ""; + + if (!str || (sscanf(str, "%d", num)==0 && sscanf(str, "%s %d", who, num)==0)) { + write("dbxframe [who] <frame>"); + return 1; + } + if (who) { + ob = find_player(who); + if (!ob) { + write("No such player."); + return 1; + } + } + else ob = this_player(); + frame = ob->GetLastError(); + if (!frame) { + write("No error."); + return 1; + } + if (num<0 || num>=sizeof(frame["trace"])) + return notify_fail("No such frame.\n"); + frame = frame["trace"][num]; + + ret += sprintf("------\n%s:%i - %s(%s)\n", frame["program"], frame["line"], + frame["function"],frame["arguments"]); + ret += sprintf("----------------------------------------------------------------\n"); + ret += sprintf("%s=>%s%s", + unguarded( (: read_file(frame["program"], frame["line"]-5, 5) :) ), + unguarded( (: read_file(frame["program"], frame["line"], 1) :) ), + unguarded( (: read_file(frame["program"], frame["line"]+1, 5) :) )); + tell_object(this_player(),ret); + return 1; +} + +string GetHelp(){ + return "Syntax: dbxframe [who] <frame>\n\n" + "Some kind of thing."; +} diff --git a/lib/secure/cmds/creators/dbxwhere.c b/lib/secure/cmds/creators/dbxwhere.c new file mode 100644 index 0000000..71bf0a8 --- /dev/null +++ b/lib/secure/cmds/creators/dbxwhere.c @@ -0,0 +1,27 @@ +/* Beek - 10/4/94 */ +#include <lib.h> + +inherit LIB_DAEMON; + +mixed cmd(string str) { + mapping error; + object ob; + int i; + + if (str) { + ob = find_player(str); + if (!ob) { + return "Player not found."; + } + } else + ob = this_player(); + if (error = ob->GetLastError()) { + return sprintf("%s\n", master()->standard_trace(error, 1)); + } else write("No error.\n"); + return "dbxwhere run complete."; +} + +string GetHelp(){ + return "Syntax: dbxwhere [person]\n\n" + "Debugging thingy.\nSee also: dbxframe"; +} diff --git a/lib/secure/cmds/creators/destfile.c b/lib/secure/cmds/creators/destfile.c new file mode 100644 index 0000000..bdd4044 --- /dev/null +++ b/lib/secure/cmds/creators/destfile.c @@ -0,0 +1,52 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + string *lines; + string buff, file, clone, base; + int scr, ret; + object ob; + if( !args ) return "You must specify a file to destruct."; + sscanf(args, "%s#%s", base, clone); + if(clone){ + ob = find_object(args); + if(!ob){ + write(args + " was not found."); + return 1; + } + ret = ob->eventDestruct(); + if(!ret || ob) destruct(ob); + if(ob){ + write("Failed to destruct "+args); + return 1; + } + write(args + " destructed."); + return 1; + } + + file = absolute_path(this_player()->query_cwd(), args); + if(!(ob = find_object(file)) && !grepp(args, "/")){ + file = DEFINES_D->GetDefine(args); + } + if(!(ob = find_object(file))) return "Object " + args + " not found."; + ret = ob->eventDestruct(); + if(!ret || ob) destruct(ob); + if(ob){ + write(args + " could not be destructed."); + } + else { + write(args + " destructed."); + } + return 1; +} + +string GetHelp() { + return ("Syntax: destfile <file>\n\n" + "Destructs the instance of the loaded object of that name." + "\nExamples:\ndestfile /realms/cratylus/area/obj/table#527\n" + "destfile /daemon/skills\n" + "destfile LIB_CONNECT\n" + "See also: dest, zap, clean, update, reload"); +} diff --git a/lib/secure/cmds/creators/diff.c b/lib/secure/cmds/creators/diff.c new file mode 100644 index 0000000..e973fdc --- /dev/null +++ b/lib/secure/cmds/creators/diff.c @@ -0,0 +1,94 @@ +/* +// /bin/dev/_diff.c +// Finds the difference between two files. +// This file is a part of the TMI distribution mudlib. +// Please retain this header if you use this code. +// Devised & Written by Douglas Reay (Pallando @ TMI, Ephemeral Dale, etc) +// Version 1.0 92-11-28 +// +// Watcher@TMI (93-04-10) changed it so the output is put through the +// user's more pager system, and made the headlines stand out a bit better. +// Pallando (93-05-28) Added this command to Dead Souls's mudlib. +// Changed its name from "compare" to "diff" + */ + +#include <lib.h> +#include <message_class.h> + +inherit LIB_DAEMON; + +int sort( string mem, mixed arr ) +{ + return -1 == member_array( mem, arr ); +} + +mixed get_lines( string file_name ) +{ + string file; + + file_name = absolute_path( "cwd", file_name ); + switch( file_size( file_name ) ) + { + case -2: { write( file_name + " is a directory.\n" ); return 0; } + case -1: { write( file_name + " is not a file.\n" ); return 0; } + } + if( !master()-> valid_read( file_name, + previous_object(), "diff" ) ) + { + write( file_name + " : Permission denied.\n" ); + return 0; + } + file = read_file( file_name ); + if( !file ) + { + write( file_name + " is empty.\n" ); + return 0; + } + return explode( file, "\n" ); +} + +int cmd( string a ) +{ + string output, file_name1, file_name2; + string *lines1, *lines2; + string *ONEnotTWO, *TWOnotONE; + + if( !a || 2 != sscanf( a, "%s %s", file_name1, file_name2 ) ) + { + notify_fail( "Syntax: diff <file1> <file2>\n" ); + return 0; + } + lines1 = get_lines( file_name1 ); + lines2 = get_lines( file_name2 ); + if( !pointerp( lines1 ) || !pointerp( lines2 ) ) + { + notify_fail( "No comparison made.\n" ); + return 0; + } + if( lines1 == lines2 ) + { + write( file_name1 + " and " + file_name2 + " are the same file.\n" ); + return 1; + } + ONEnotTWO = filter( lines1, "sort", this_object(), lines2 ); + TWOnotONE = filter( lines2, "sort", this_object(), lines1 ); + if( ONEnotTWO == TWOnotONE ) + { + write( file_name1 + " and " + file_name2 + " have the same lines.\n" ); + return 1; + } + output = "[In " + file_name1 + " but not in " + file_name2 + ":]\n" + + implode( ONEnotTWO, "\n" ) + "\n" + + "\n[In " + file_name2 + " but not in " + file_name1 + ":]\n" + + implode( TWOnotONE, "\n" ) + "\n"; + + this_player()->eventPage( explode(output, "\n"), MSG_SYSTEM | MSG_NOCOLOUR); + + return 1; +} + +string GetHelp(){ + return ("Syntax: diff <file1> <file2>\n\n" + "Reports the differences between two files."); +} + diff --git a/lib/secure/cmds/creators/dsversion.c b/lib/secure/cmds/creators/dsversion.c new file mode 100644 index 0000000..98f17d6 --- /dev/null +++ b/lib/secure/cmds/creators/dsversion.c @@ -0,0 +1,220 @@ +/* /secure/cmds/creators/dsversion.c + * Created by Brodbane of Eve + * Date Created: 4/1/06 + */ + +#include <lib.h> +#include NETWORK_H +#include <socket_err.h> +#include <message_class.h> + +inherit LIB_DAEMON; + +#define HTTP_ADDRESS "97.107.133.86" +#define HTTP_HOST "dead-souls.net" +#define HTTP_PORT 80 +#define HTTP_PATH "/RELEASE_NOTES" +#define NOTES_DELIM "----" +#undef _DEBUG + +#define SAVE_FILE "/doc/RELEASE_NOTES_HTTP" + + +#define SOCK_FIND 0 +#define SOCK_CONNECTING 1 +#define SOCK_CONNECTED 2 +#define SOCK_DISCONNECTED 3 +#define SOC_ERROR 4 + +int socket; +int status; +object player; +object person; + +string results, s; + +void sendHTTPGet(); + +int http_file_found; + +private string args_list; + +mixed ProcessHTTPResult(){ + string * parts; + string * arg_array; + string * temp; + parts = explode( results, NOTES_DELIM )[1..]; + if(!sizeof(parts)) return 0; + temp = explode( parts[0], "---" ); + player->eventPrint( "Current Version of "+mud_name()+": " + mudlib_version() ); + player->eventPrint( "Latest Version of Dead Souls: %^RED%^"+trim(temp[0])+ "%^RESET%^" ); + write_file( SAVE_FILE, results, 1 ); + + arg_array = explode( args_list, " " ); + foreach( string str in arg_array ){ + temp = regexp( parts, args_list+" +" ); + if( sizeof( temp ) > 1 ) temp = regexp( parts, args_list+" " ); + if( sizeof( temp ) > 3 ){ + player->eventPrint( "Too many results, truncating..." ); + return print_long_string(player, temp[0]+temp[1]+temp[2],1 ); + } + else{ + s = implode(temp,"\n%^CYAN%^----%^RESET%^ "); + write_file( SAVE_FILE, results, 1 ); + s += "\nFor complete release notes refer to "+SAVE_FILE; + print_long_string(player, "%^CYAN%^----%^RESET%^ "+s,1 ); + } + } + return 1; +} + +void read_callback( int fd, mixed message ){ + results += message; +} + +void write_callback( int fd ){ +#ifdef _DEBUG + player->eventPrint("Connected!"); +#endif + status = SOCK_CONNECTED; + http_file_found = 0; + sendHTTPGet(); +} + +void close_callback( int fd ){ + if( status == SOCK_CONNECTED ) + { + // Process HTML here +#ifdef _DEBUG + player->eventPrint("dsversion: Connection closed by host."); +#endif + ProcessHTTPResult(); + } + if( status == SOCK_CONNECTING ) + { + player->eventPrint("dsversion: Connection attempt failed."); + } + socket_close( fd ) ; + status = SOCK_DISCONNECTED; +} + +void sendHTTPGet() +{ + string str ="GET "+HTTP_PATH+" HTTP/1.0"+CARRIAGE_RETURN+"\n"+ + "Host: "+HTTP_HOST+CARRIAGE_RETURN"\n" + + "User-Agent: "+ player->GetName() + "@" + mud_name() + " " + + mudlib()+ "/" + mudlib_version() +" ("+ query_os_type()+";) "+ + version() + CARRIAGE_RETURN+"\n"+CARRIAGE_RETURN+"\n"; + int result = 0; + results = ""; +#ifdef _DEBUG + player->eventPrint("Sending HTTP get request..." ); +#endif + if( status == SOCK_CONNECTED ) + { + result = socket_write( socket, str ); +#ifdef _DEBUG + player->eventPrint( "HTTP request sent to " + + identify(socket_status(socket)) + " result = "+result ); +#endif + } +} + +int openHTTPConnection() +{ + + int sock, sc_result; + string error; + status = SOCK_FIND; + + + status = SOCK_CONNECTING; + sock = socket_create( STREAM, "read_callback", "close_callback" ) ; + if (sock < 0) { + switch( sock ) + { + case EEMODENOTSUPP : + error = "Socket mode not supported.\n" ; + break ; + case EESOCKET : + error = "Problem creating socket.\n" ; + break ; + case EESETSOCKOPT : + error = "Problem with setsockopt.\n" ; + break ; + case EENONBLOCK : + error = "Problem with setting non-blocking mode.\n" ; + break ; + case EENOSOCKS : + error = "No more available efun sockets.\n" ; + break ; + case EESECURITY : + error = "Security violation attempted.\n" ; + break ; + default : + error = "Unknown error code: " + sock + ".\n" ; + break ; + } + notify_fail( "Unable to connect, problem with socket_create.\n" + "Reason: " + error ) ; + return 0 ; + } +#ifdef _DEBUG + write("Attempting to connect to "+HTTP_HOST+ " on port "+ HTTP_PORT + "\n"); +#endif + sc_result = socket_connect( sock, HTTP_ADDRESS + " " + HTTP_PORT, + "read_callback", "write_callback" ) ; + if( sc_result != EESUCCESS ) + { + status = SOCK_DISCONNECTED; + notify_fail( "Failed to connect.\n" ) ; + return 0 ; + } + else{ +#ifdef _DEBUG + player->eventPrint( "Socket connecting..." ); +#endif + } + + socket = sock; + return 1; +} + +void hostResolved( string address, string resolved, int key ) +{ + if( !resolved ){ +#ifdef _DEBUG + player->eventPrint( "Unable to resolve "+address ); +#endif + return; + } +#ifdef _DEBUG + player->eventPrint( "Resolved "+address+" to "+ resolved ); +#endif + player->eventPrint( "Retrieving updated release notes from: http://www.dead-souls.net\n" ); + openHTTPConnection(); +} + +void resolveHost() +{ + resolve( HTTP_HOST, "hostResolved" ); +} + + +mixed cmd(string args) { + player = previous_object(); + if(args) args_list = args; + else args_list = ""; + openHTTPConnection(); + return 1; +} + +string GetErorMessage() { + return "There was a problem"; +} + +string GetHelp() { + return ("Syntax: dsversion [version]\n\n" + + "Shows the latest version of Dead Souls and release notes.\n"+ + "e.g. dsversion, dsversion 2.9a12, dsversion 2.0r1"); +} diff --git a/lib/secure/cmds/creators/economy.c b/lib/secure/cmds/creators/economy.c new file mode 100644 index 0000000..582001a --- /dev/null +++ b/lib/secure/cmds/creators/economy.c @@ -0,0 +1,55 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +int cmd(string str) { + string type, key; + float rate, infl, wt; + + if( !str ) { + string *tmp; + string curr; + + tmp = ({ "Currency Rate Infl Mass" }); + foreach( curr in ECONOMY_D->__QueryCurrencies() ) + tmp += ({ sprintf("%:-15s %:-7s %:-7s %f", + curr, currency_rate(curr) + "" , + currency_inflation(curr) + "", + (float)ECONOMY_D->__Query(curr, "weight")) }); + this_player()->more(tmp, "system"); + return 1; + } + if(!archp(previous_object())) return 0; + log_file("economy", previous_object()->GetCapName()+": " + + str+" ("+ctime(time())+")\n"); + if(sscanf(str, "add %s %f %f %f", type, rate, infl, wt) == 4) { + ECONOMY_D->add_currency(type, rate, infl, wt); + message("info", "Currency "+type+" added!", this_player()); + } + else if(sscanf(str, "change %s for %s to %f", key, type, wt) == 3) { + ECONOMY_D->change_currency(type, key, wt); + message("info", "Changed: "+key+" for "+type+" to "+wt, this_player()); + } + else return 0; + return 1; +} + +string GetHelp(){ + return ("Syntax: economy add <type> <exchange <rate> " + "<inflation rate> <weight>\n" + " economy change <what> for <currency> to <value>\n\n" + "This allows only approval people to modify the economic settings for " + "the mud. The add parameter signifies that the arch intends to add " + "a new currency to the game. The change parameter instead signifies " + "that the arch is changing something in a currenct currency. Examples:\n" + "economy add gold 1.0 0.03 0.1\neconomy change rate for gold to 1.1\n" + "The exchange rate parameter is multiplied by the value of " + "query(\"value\") in mud objects to give the value in the currency of " + "an object. The inflation rate parameter of the add command sets " + "the percentage rate by which the value of the currency " + "will inflate (or deflate) over the course of a mud year. The weight " + "paramter sets how much one piece of the currency will weigh in " + "standard mud weight units. Finally, changing values for current " + "currencies use the parameters: rate, inflation, weight."); +} diff --git a/lib/secure/cmds/creators/ed.c b/lib/secure/cmds/creators/ed.c new file mode 100644 index 0000000..28a844b --- /dev/null +++ b/lib/secure/cmds/creators/ed.c @@ -0,0 +1,57 @@ +/* /secure/cmds/creator/ed.c + * from the Dead Souls LPC Library + * creator command to enter the editor + * created by Descartes of Borg 950406 + */ + +#include <lib.h> + +inherit LIB_DAEMON; + +int ed_callback(object ob){ + if(ob) ob->CheckCharmode(); + return 1; +} + +mixed cmd(string args) { + int x; + + if( args == "" || !args ) + args = user_path(this_player()->GetKeyName()) + "tmp.edit"; + if( this_player()->GetForced() ) { + message("system", "Someone tried to force you to edit "+ args +"\n" + + identify(previous_object(-1)), this_player()); + return 0; + } + + if(!this_player()->GetProperty("EdWarned")){ + write("This is the first time you've used ed. If you get stuck, simply " + "hit return a few times, then enter a dot on a blank line, hit return, " + "then type Q, then enter. Then visit this page to learn more about " + "using the ed editor: http://dead-souls.net/editor.html"); + this_player()->SetProperty("EdWarned", 1); + } + args = absolute_path( this_player()->query_cwd(), args ); + if( (x = file_size(args)) == -2 ) + return "You cannot edit a directory!"; + else if( x == -1 ) + message("editor", args + ", new file, starting in input mode.\n", + this_player()); + else message("editor", args + ", " + x + " bytes\n", this_player()); + this_player()->eventEdit(args, (: ed_callback, this_player() :) ); + return 1; +} + +string GetHelp() { + return ("Syntax: ed [filename]\n\n" + "Ye olde LP mud in-game text editor. It is a line-mode editor, " + "meaning it is archaic, hard to use, and complimicated. " + "But it's the " + "one way to edit stuff in-game that works for sure. " + "For a brief walkthrough:\n" + "%^GREEN%^faq ed%^RESET%^\n" + "For a lengthy doc:\n" + "%^GREEN%^help editor%^RESET%^\n" + "For a web page FAQ, use your web browser to go to; http://dead-souls.net/editor.html\n\n" + "See also: ced, creweb, qcs"); +} diff --git a/lib/secure/cmds/creators/eval.c b/lib/secure/cmds/creators/eval.c new file mode 100644 index 0000000..e77f833 --- /dev/null +++ b/lib/secure/cmds/creators/eval.c @@ -0,0 +1,97 @@ +// /bin/dev/_eval.c +// Part of the TMI distribution mudlib and now part of Dead Souls's +// allows wizards to execute LPC code without writing new objects. +// Created by Douglas Reay (Pallando @ TMI-2, Dead Souls, etc) 92-12-07 +// evaldefs stuff by Raudhrskal, 2009-01-02 + +#include <privs.h> +#include <lib.h> + +inherit LIB_DAEMON; + +#define SYNTAX "Syntax: \"eval <lpc commands>\".\n" + +int cmd( string a ) +{ + string file, filename, evaldefs; + mixed ret; + + if(!member_group(previous_object(), PRIV_SECURE)) { + log_file("adm/eval", query_privs(previous_object()) + +" ("+ctime(time())+"): eval "+a+"\n"); + } + if( !a ) { notify_fail( SYNTAX ); return 0; } + + evaldefs = ""; + + filename = user_path(previous_object()->GetKeyName()); + if( file_size( filename ) != -2 && !securep(previous_object()) ) { + notify_fail( "You must have a valid home directory!\n" ); + return 0; + } + + if(file_exists(filename + "evaldefs.h")) + evaldefs = "#include \"" + filename + "evaldefs.h\"\n"; + + // The includes in the file aren't necessary (and can be removed if the + // include files on your mud are called something different). They're + // just to make things like "eval return children( USER )" possible. + file = + ""+ + "#include <lib.h>\n"+ + "#include <cgi.h>\n"+ + "#include <dirs.h>\n"+ + "#include <privs.h>\n"+ + "#include <logs.h>\n"+ + "#include <virtual.h>\n"+ + "#include <cfg.h>\n"+ + "#include <clock.h>\n"+ + "#include <save.h>\n"+ + "#include ROOMS_H\n"+ + "#include <localtime.h>\n"+ + "#include <daemons.h>\n"+ + "#include <network.h>\n"+ + "#include <news.h>\n"+ + "#include <objects.h>\n"+ + "#include <commands.h>\n"+ + "#include <armor_types.h>\n"+ + "#include <damage_types.h>\n"+ + "#include <position.h>\n"+ + "#include <runtime_config.h>\n"+ + "#include <terrain_types.h>\n"+ + "#include <medium.h>\n"+ + "#include <body_types.h>\n"+ + "#include <size_types.h>\n"+ + "#include <respiration_types.h>\n"+ + "#include <message_class.h>\n"+ + "inherit LIB_ITEM;\n"+ + evaldefs+ + "mixed eval() { " + a + "; }\n"+ + ""; + filename += "CMD_EVAL_TMP_FILE.c"; + if(securep(previous_object())){ + filename = "/secure/tmp/" + previous_object()->GetKeyName() + + "_CMD_EVAL_TMP_FILE.c"; + } + rm( filename ); + if( ret = find_object( filename ) ) destruct( ret ); + write_file( filename, file,1 ); + ret = call_other(filename, "eval"); + write( wrap( "Result = " + identify( ret ) ) ); + if( ret = find_object( filename ) ) destruct( ret ); + return 1; +} + +string GetHelp(){ + return SYNTAX + "\nCalls a function containing <lpc commands>\n" + "Example: If you type:\n" + "eval return 1 + cos( 0.0 )\n" + "the command creates a temporary file in your " + "home dir containing the line:\n" + "eval() { return 1 + cos( 0.0 ); }\n" + "then does call_other on the files's eval() " + "function, giving:\n" + "Result = 2.000000\n\n" + "Note: You can add custom defines for yourself " + "with the file 'evaldefs.h' in your home directory."; +} diff --git a/lib/secure/cmds/creators/findfun.c b/lib/secure/cmds/creators/findfun.c new file mode 100644 index 0000000..1507fcc --- /dev/null +++ b/lib/secure/cmds/creators/findfun.c @@ -0,0 +1,85 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; +string funcname; +string *sourcefiles = ({}); + +mixed cmd(string args) { + string ret, where, lcargs, tmp; + int Efun, SEfun, subs; + string *ret_arr, *lc_hits = ({}), *lc_tmp; + + if(!args || args == ""){ + write("You'll need to be more specific. Try: help findfun"); + return 1; + } + if(!strsrch(args, "-s ")){ + args = replace_string(args, "-s ", ""); + subs = 1; + } + if(!args || args == ""){ + write("You'll need to be more specific. Try: help findfun"); + return 1; + } + if(subs){ + ret_arr = FUNCTION_D->GetLCFunctions(args, 1); + if(!sizeof(ret_arr)){ + write("No matches found."); + return 1; + } + ret_arr = explode(format_page(ret_arr, 2), "\n"); + this_player()->eventPage(ret_arr); + return 1; + } + lcargs = lower_case(args); + lc_hits = FUNCTION_D->GetLCFunctions(lcargs); + if(!strsrch(lcargs,"query")) tmp = replace_string(lcargs,"query","get"); + if(!strsrch(lcargs,"set_")) tmp = replace_string(lcargs,"set_","set"); + if(tmp) lc_tmp = FUNCTION_D->GetLCFunctions(tmp); + if(!lc_hits) lc_hits = ({}); + if(sizeof(lc_tmp)) lc_hits += lc_tmp; + if(!strsrch(lcargs,"get_")) tmp = replace_string(lcargs,"get_","get"); + if(tmp && !strsrch(tmp,"get_")) tmp = replace_string(tmp,"get_","get"); + if(tmp && !sizeof(lc_tmp)) lc_tmp = FUNCTION_D->GetLCFunctions(tmp); + if(sizeof(lc_tmp)) lc_hits += lc_tmp; + if(sizeof(lc_hits)) lc_hits -= ({ args }); + if(grepp(args,"-a ")){ + where = "/"; + args = replace_string(args,"-a ",""); + } + else where = "/lib"; + funcname = args; + ret = FUNCTION_D->GetInstances(args, where); + write(ret); + Efun = efun_exists(args); + SEfun = sefun_exists(args); + if(Efun && SEfun){ + write(args+" is an external driver function (efun) that is "+ + "overridden as a simulated efun (sefun) in the lib."); + } + else { + if(Efun) write(args+" exists as an efun "+ + "(external fun in the driver)."); + if(SEfun) write(args+" exists as a sefun " + "(simulated efun in the lib)."); + } + if(sizeof(lc_hits)){ + write("\nSee also: "+ + implode(sort_array(distinct_array(lc_hits), 1), ", ")+"\n"); + } + return 1; +} + +string GetHelp(){ + return ("Syntax: findfun <FUNCTION_NAME>\n" + " findfun -s <SUBSTRING>\n\n" + "Tells you where a function is defined. With the " + "substring flag (-s) it lists possible matching lfuns, " + "efuns, and sefuns known to the command.\n" + "\nExamples: \nfindfun AddHP\nfindfun -s class\n\n" + "Note: When not doing a substring search, " + "this command is case-sensitive.\n" + "See also: showfuns, efun, efuns, sefun, sefuns, " + "lfun, lfuns"); +} diff --git a/lib/secure/cmds/creators/flushobs.c b/lib/secure/cmds/creators/flushobs.c new file mode 100644 index 0000000..cdba531 --- /dev/null +++ b/lib/secure/cmds/creators/flushobs.c @@ -0,0 +1,33 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_DAEMON; + +int cmd(string str) { + object *rooms = ({}); + + write("Number of currently loaded objects: "+sizeof(objects())); + + write("Destroying objects in the furnace...\n"); + flush_messages(this_player()); + update(ROOM_FURNACE); + + + write("Destroying non-environment objects..."); + flush_messages(this_player()); + + reap_other(); + reap_other(); + + write("Done."); + + write("Number of currently loaded objects: "+sizeof(objects())); + return 1; +} + +string GetHelp(){ + return ("Syntax: flushobs\n\n"+ + "Immediately incinerates anything in the furnace and "+ + "destructs all cloned non-interactive objects that "+ + "lack an environment."); +} diff --git a/lib/secure/cmds/creators/gauge.c b/lib/secure/cmds/creators/gauge.c new file mode 100644 index 0000000..46080a5 --- /dev/null +++ b/lib/secure/cmds/creators/gauge.c @@ -0,0 +1,39 @@ +/* +// A useful command from the people at Portals. +// I think Huthar wrote this one. +// 94-07-24 : Pallando added utime and stime bits from TMI + */ + +#include <lib.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + object act_ob; + mapping before, after; + int stime, usertime, eval_cost; + +#ifndef __HAS_RUSAGE__ + write("This command depends on an efun that is not available."); +#else + if( !args || args == "" ) return "You must specify a command to execute."; + before = rusage(); + catch(eval_cost = previous_object()->eventForce(args)); + after = rusage(); + usertime = after["utime"] - before["utime"]; + stime = after["stime"] - before["stime"]; + message("system", "\n" + stime + " ms system time, " + usertime + + " ms user time, and " + eval_cost + " CPU cycles eval cost.", + this_player()); +#endif + return 1; +} + +string GetHelp(){ + string ret= "Syntax: gauge <command>\n\n" + "Gauges how many CPU cycles <command> takes to execute. " + "and how much system and user time.\n" + "Nota Bene: <command> must be typed in full (no aliases).\n"; + if(archp(this_player())) ret += "See also: usage"; + return ret; +} diff --git a/lib/secure/cmds/creators/goto.c b/lib/secure/cmds/creators/goto.c new file mode 100644 index 0000000..416f735 --- /dev/null +++ b/lib/secure/cmds/creators/goto.c @@ -0,0 +1,77 @@ +/* /cmds/creator/goto.c + * from the Dead Souls LPC Library + * a command to take a cre anywhere in the game + * created by Descartes of Borg 930906 + * modified for NM IV 950331 + */ + +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string str) { + object ob, dude; + int err; + string tmp; + + if(!str) return "Goto where?"; + tmp = DEFINES_D->GetDefine(str); + if(tmp) str = tmp; + ob = find_player(lower_case(str)); + if(ob) dude = ob; + if(ob && objectp(ob) && (!ob->GetInvis() || !archp(ob)) && + ob = room_environment(ob)) { + if(ob == room_environment(this_player())) { + message("my_action", "You twitch.", this_player()); + if(hiddenp(this_player())) return 1; + message("other_action", 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(this_player()->query_cwd(), str); + if(ob) { + this_player()->eventMoveLiving(ob); + return 1; + } + + if(last_string_element(path_prefix(path_prefix(str)),"/") != "virtual"){ + int x, y, z; + string file = last_string_element(str,"/"); + if(sscanf(file,"%d,%d,%d", x, y, z) != 3) + sscanf(file,"%d,%d", x, y); + if(!undefinedp(x) && !undefinedp(y)){ + mixed rmap = ROOMS_D->GetGrid(file); + if(rmap && rmap["room"]){ + if(!file_exists(str) && !file_exists(str + ".c")){ + str = rmap["room"]; + } + } + } + else if(!file_exists(str) && !file_exists(str + ".c")){ + str == lower_case(str); + if(str == "home" || str == "workroom"){ + write("Try: help home"); + } + else write("Location not found."); + return 1; + } + } + + err = catch( ob = load_object(str) ); + if(err || !ob) { + write("\n\nCould not load that location."); + return 1; + } + else this_player()->eventMoveLiving(ob); + return 1; +} + +string GetHelp() { + return ("Syntax: goto [living thing|file]\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.\nSee also: home, move, trans, expel."); +} diff --git a/lib/secure/cmds/creators/grep.c b/lib/secure/cmds/creators/grep.c new file mode 100644 index 0000000..d0b4ae9 --- /dev/null +++ b/lib/secure/cmds/creators/grep.c @@ -0,0 +1,152 @@ +// /bin/system/_grep.c +// from the Dead Souls Mudlib +// searches for an expression in files +// created by Descartes of Borg 930822 +// numbered results added by Nimrod@The Tower 060805 + +#include <lib.h> + +#define GREP_NUMBERED_LINES (1<<0) +#define GREP_RECURSE_DIRECTORIES (1<<1) +#define MAX_FILE_SIZE 200000 + +inherit LIB_DAEMON; + +int max_files = 1000; +string *allowed_types3 = ({ ".txt", ".cfg" }); +string *allowed_types1 = ({ ".c", ".h" }); + +int cmd(string str) { + mapping borg; + string *lines, *files, *r_files; + string output, exp, file, tmp; + mixed txt; + + int err, i, i_lines, max, max_lines, flags; + + notify_fail("Correct syntax: <grep [-nr] '[pattern]' [file] (> [output])>\n"); + if(!str) return 0; + //CHECK FOR FLAGS + if(str[0] == '-'){ + if(sscanf(str, "-%s %s", tmp, txt) == 2){ + for(i = 0, max = sizeof(tmp); i<max; i++){ + switch(tmp[i]){ + case 'n' : flags = flags|GREP_NUMBERED_LINES ;break; + case 'r' : flags = flags|GREP_RECURSE_DIRECTORIES ;break; + } + } + } + str = txt; + } + + if(sscanf(str, "%s > %s", tmp, output) == 2) { + if(output[0] != '/') output = previous_object()->get_path()+"/"+output; + str = tmp; + } + else output = 0; + if(sscanf(str, "'%s' %s", exp, file) != 2 && + sscanf(str, "%s %s", exp, file) != 2) return 0; + if(!(max = sizeof(files = wild_card(file)))) { + message("system", "File not found.", this_player()); + return 1; + } + + if(flags&GREP_NUMBERED_LINES){ + for(i=0, borg = ([]); i<max; i++) { + if((file_size(files[i]) == -2)&&(flags&GREP_RECURSE_DIRECTORIES)){ + r_files = wild_card(files[i]+"/*"); + if(max + sizeof(r_files) > max_files){ + write("Too many files in the recurse. Aborting grep."); + return 1; + } + files += r_files; + max += sizeof(r_files); + continue; + } + if(file_size(files[i]) > MAX_FILE_SIZE){ + write(files[i]+": too large. Skipping."); + continue; + } +#if 0 + if(member_array(last(files[i],2), allowed_types1) == -1 && + member_array(last(files[i],4), allowed_types3) == -1 && + grepp(files[i],".")){ + write(files[i]+": unrecognized extension. Skipping."); + continue; + } +#endif + err = catch(txt = read_file(files[i])); + if(err){ + if(file_exists(files[i])) write(files[i]+": corrupted file, or not text. Skipping."); + continue; + } + if(txt) lines = explode(txt, "\n"); + else { + write(files[i]+": unreadable file or directory. Skipping."); + continue; + } + borg[files[i]] = ({}); + for(i_lines = 0, max_lines = sizeof(lines); i_lines<max_lines; i_lines++){ + if(regexp(lines[i_lines], exp)){ + borg[files[i]] += ({sprintf("%d: %s", i_lines, lines[i_lines]) }); + } + } + if(!sizeof(borg[files[i]])) map_delete(borg, files[i]); + } + } + else { + for(i=0, borg = ([]); i<max; i++) { + if((file_size(files[i]) == -2)&&(flags&GREP_RECURSE_DIRECTORIES)){ + r_files = wild_card(files[i]+"/*"); + if(max + sizeof(r_files) > max_files){ + write("Too many files in the recurse. Aborting grep."); + return 1; + } + files += r_files; + max += sizeof(r_files); + continue; + } + if(file_size(files[i]) > MAX_FILE_SIZE){ + write(files[i]+": too large. Skipping."); + continue; + } +#if 0 + if(member_array(last(files[i],2), allowed_types1) == -1 && + member_array(last(files[i],4), allowed_types3) == -1 && + grepp(files[i],".")){ + write(files[i]+": unrecognized extension. Skipping."); + continue; + } +#endif + err = catch(txt = read_file(files[i])); + if(err || !txt){ + if(file_exists(files[i])) write(files[i]+": corrupted file, or not text. Skipping."); + continue; + } + borg[files[i]] = regexp(explode(txt, "\n"), exp); + if(!sizeof(borg[files[i]])) map_delete(borg, files[i]); + } + } + if(!(max = sizeof(files = keys(borg)))) str = "No matches found.\n"; + else { + for(i=0, str = ""; i<max; i++) str += sprintf("%s:\n%s\n\n", files[i], implode(borg[files[i]],"\n")); + } + if(output) { + if(!write_file(output, str)) message("system", "Failed to write to: "+output, this_player()); + else message("system", "Grep sent to: "+output, this_player()); + } + else message("system", str, this_player()); + return 1; +} + +string GetHelp() { + return ("Syntax: grep [-nr] '[pattern]' [file] (> [redirect])\n\n" + "Searches a file or group of files for a specific pattern. " + "If the pattern is a single word, then no '' is needed. Patterns " + "of more than one word or beginning with a '-' however, need to be enclosed in ''. " + "You may redirect the output of the grep to a file using the >." + "\n Options:\n" + " -r recursive search, search extends to child directories.\n" + " -n numbered lines, includes line numbers of successful hits." + "\nSee also: cd, ls, mv, pwd, rm"); +} diff --git a/lib/secure/cmds/creators/head.c b/lib/secure/cmds/creators/head.c new file mode 100644 index 0000000..dc8e2b1 --- /dev/null +++ b/lib/secure/cmds/creators/head.c @@ -0,0 +1,31 @@ +/* /secure/ambassador/_head.c + * from Dead Souls 3.3 + * gives the first 22 lines of a file + * created by Descartes of Borg 940928 + */ + +#include <lib.h> + +inherit LIB_DAEMON; + +int cmd(string str) { + string *lines; + string file; + int x; + + if(!str) return notify_fail("Syntax: head <file>\n"); + file = absolute_path(this_player()->query_cwd(),str); + if(!file_exists(file)) return notify_fail("No such file: "+file+"\n"); + else if(!(str = read_file(file))) + return notify_fail("Empty file: "+file+"\n"); + if((x = sizeof(lines = explode(str, "\n"))) > 22) x = 23; + str = implode(lines[0..x-1], "\n"); + message("system", str, this_player()); + return 1; +} + +string GetHelp() { + return ("Syntax: head <file>\n\n" + "Gives you the first lines in the file specified.\n" + "See also: cat, more, tail"); +} diff --git a/lib/secure/cmds/creators/heal.c b/lib/secure/cmds/creators/heal.c new file mode 100644 index 0000000..5936544 --- /dev/null +++ b/lib/secure/cmds/creators/heal.c @@ -0,0 +1,82 @@ +#include <lib.h> +#include ROOMS_H + +inherit LIB_DAEMON; + +mixed cmd(string args) { + string tp, cmd = args; + object who; + mapping stumps; + string *limb_arr = ({}); + object *germs; + int i, mhp, msp, mmp, self; + + if(this_player()) tp = this_player()->GetKeyName(); + if( !cmd || cmd == "" ) { + return "Syntax: <heal LIVING>"; + } + + if(member_array(args,({ "me","myself", (tp || "") })) != -1 ) self = 1; + else self = 0; + + if( !self && !who = find_living(args) ) { + write("That being is unavailable."); + return 1; + } + if((who && who->GetGhost()) ) { + write("You can't heal the dead."); + return 1; + } + if(!self){ + previous_object()->eventPrint("You heal " + who->GetName() + "."); + who->eventPrint(previous_object()->GetCapName() + " heals you."); + say(this_player()->GetCapName() + " heals "+ who->GetName() + ".",who); + } + else { + who = this_player(); + previous_object()->eventPrint("You heal thyself."); + say(this_player()->GetCapName() + " heals "+ + objective(this_player())+"self.",who); + } + mhp = who->GetMaxHealthPoints(); + msp = who->GetMaxStaminaPoints(); + mmp = who->GetMaxMagicPoints(); + + if(who->GetLead()){ + int shots = who->GetLead("gunshot_wounds"); + if(shots) who->AddLead("gunshot_wounds", -shots); + shots = who->GetLead("rifleshot_wounds"); + if(shots) who->AddLead("rifleshot_wounds", -shots); + } + + while(sizeof(who->GetMissingLimbs())){ + limb_arr = who->GetMissingLimbs(); + foreach(string limb in limb_arr) { + who->RestoreLimb(limb); + } + } + + if(who->GetPoison() > 0) who->AddPoison(0 - who->GetPoison()); + + germs = filter(deep_inventory(who), (: $1 && $1->isGerm() :) ); + + if(sizeof(germs)) germs->eventMove(ROOM_FURNACE); + germs->eventDestruct(); + + limb_arr = who->GetLimbs(); + foreach(string limb in limb_arr) { + who->HealLimb(limb); + } + + who->AddHP(mhp); + who->AddStaminaPoints(msp); + who->AddMagicPoints(mmp); + + return 1; +} + +string GetHelp(){ + return ("Syntax: heal <LIVING>\n\n" + "Allows you to restore a living being's health, stamina, " + "magic, and severed limbs. Wow!"); +} diff --git a/lib/secure/cmds/creators/homedir.c b/lib/secure/cmds/creators/homedir.c new file mode 100644 index 0000000..45f6e61 --- /dev/null +++ b/lib/secure/cmds/creators/homedir.c @@ -0,0 +1,32 @@ +#include <lib.h> + +inherit LIB_DAEMON; + +mixed cmd(string str){ + if(!sizeof(str)){ + this_player()->SetUserPath(0); + } + else { + if(!directory_exists(str)){ + write("That path appears inaccessible. No change made."); + } + else { + if(last(str, 1) != "/") str += "/"; + this_player()->SetUserPath(str); + } + } + write("Your current home directory is: "+user_path(this_player())); + return 1; +} + +string GetHelp() { + return ("Syntax: homedir [directory]\n\n" + "Sets the specified directory to be your \"home\" " + "directory, i.e. the directory your path changes to " + "when you type \"cd\" with no arguments. If you do " + "not specify a directory, your home directory is " + "reset to your default.\nNOTE: Changing your home " + "directory may have an impact on where the QCS puts items " + "you create.\n" + "See also: pwd, cd, env, homeroom"); +} diff --git a/lib/secure/cmds/creators/homeroom.c b/lib/secure/cmds/creators/homeroom.c new file mode 100644 index 0000000..7fc74d3 --- /dev/null +++ b/lib/secure/cmds/creators/homeroom.c @@ -0,0 +1,36 @@ +#include <lib.h> + +inherit LIB_DAEMON; + +mixed cmd(string str){ + object room; + string path; + if(!sizeof(str) || str == "here"){ + room = room_environment(this_player()); + path = base_name(room); + } + else { + str = absolute_path(this_player()->query_cwd(), str); + if(!str) return "File not found."; + room = find_object(str); + if(room) path = base_name(room); + } + if(!path){ + write("Unable to set "+str+" as your home room."); + return 1; + } + this_player()->SetParanoia("homeroom", path); + write("Your current home room is: "+path); + return 1; +} + +string GetHelp() { + return ("Syntax: homeroom [path]\n\n" + "Sets the specified file to be your \"home\" " + "room, i.e. the room you teleport to " + "when you type \"home\" with no arguments. If you do " + "not specify a path, your current room environment is " + "set to be your home." + "\n" + "See also: env, homedir"); +} diff --git a/lib/secure/cmds/creators/imc2.c b/lib/secure/cmds/creators/imc2.c new file mode 100644 index 0000000..eb88160 --- /dev/null +++ b/lib/secure/cmds/creators/imc2.c @@ -0,0 +1,9 @@ +#include <daemons.h> + +int cmd(string str){ + if(!(IMC2_D->command(str))){ + write("IMC2 daemon is currently unavailable."); + } + return 1; +} +string GetHelp(){ return "/secure/daemon/imc2.c"->main_help(); } diff --git a/lib/secure/cmds/creators/include/create.h b/lib/secure/cmds/creators/include/create.h new file mode 100644 index 0000000..e9f9853 --- /dev/null +++ b/lib/secure/cmds/creators/include/create.h @@ -0,0 +1,9 @@ +#ifndef l_create_h +#define l_create_h + +mixed cmd(string args); +static void CreateRoom(string file, string args); +string GetHelp(string str); + +#endif /* l_create_h */ + diff --git a/lib/secure/cmds/creators/include/gg.h b/lib/secure/cmds/creators/include/gg.h new file mode 100644 index 0000000..b18e736 --- /dev/null +++ b/lib/secure/cmds/creators/include/gg.h @@ -0,0 +1,7 @@ +#ifndef l_gg_h +#define l_gg_h + +mixed cmd(string args); +string GetHelp(string str); + +#endif /* l_gg_h */ diff --git a/lib/secure/cmds/creators/include/more.h b/lib/secure/cmds/creators/include/more.h new file mode 100644 index 0000000..a47823c --- /dev/null +++ b/lib/secure/cmds/creators/include/more.h @@ -0,0 +1,7 @@ +#ifndef l_more_h +#define l_more_h + +mixed cmd(string args); +string GetHelp(string str); + +#endif /* l_more_h */ diff --git a/lib/secure/cmds/creators/indent.c b/lib/secure/cmds/creators/indent.c new file mode 100644 index 0000000..5f24379 --- /dev/null +++ b/lib/secure/cmds/creators/indent.c @@ -0,0 +1,55 @@ +#include <lib.h> + +inherit LIB_DAEMON; + +string cmd(string str) { + + string *files, *paths; + string where, rulefile, tmp; + int flag; + + notify_fail("Syntax: <indent [file | * | */*]\n"); + + if( !str ) return "You must specify a file or wildcard."; + else if(str == "*") flag = 1; + else if(str == "*/*") flag = 2; + else str = absolute_path(this_player()->query_cwd(), str); + if( !file_exists(str) && !flag) return "File " + str + " not found."; + else if( !(tmp = read_file(str)) && !flag) + return "Unable to read file " + str + "."; + + rulefile = "/tmp/"+this_player()->GetKeyName()+".indent"; + write_file(rulefile, "I",1); + + if(flag){ + + where = this_player()->query_cwd(); + if(flag == 1) paths = ({ where }); + else { + paths = ({}); + files = get_dir(this_player()->query_cwd()+"/"); + if(sizeof(files)) foreach(string s1 in files){ + if(file_size(where + "/" +s1) == -2 ){ + paths += ({ where + "/" +s1 }); + } + } + } + if(sizeof(paths)) foreach(string path in paths){ + load_object("/secure/cmds/creators/lsed")->cmd(rulefile + " "+ path + "/*.c"); + load_object("/secure/cmds/creators/lsed")->cmd(rulefile + " "+ path + "/*.h"); + } + } + + else { + load_object("/secure/cmds/creators/lsed")->cmd(rulefile + " "+str); + } + + rm(rulefile); + return "Done."; +} + +string GetHelp() { + return ("Syntax: indent [file | * | */*]\n\n" + "Indents a specified file, or all files in a directory." + "\nSee also: cd, ls, mv, pwd, rm, lsed, grep"); +} diff --git a/lib/secure/cmds/creators/last.c b/lib/secure/cmds/creators/last.c new file mode 100644 index 0000000..9bd8525 --- /dev/null +++ b/lib/secure/cmds/creators/last.c @@ -0,0 +1,52 @@ +/* /cmds/creators/last.c + * From the Dead Souls Mud Library + * Shows the last however many people to login + * Created by Descartes of Borg 961118 + * Version: @(#) last.c 1.1@(#) + * Last modified: 96/11/18 + */ + +#include <lib.h> +#include <message_class.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + string file, filename; + string array lines; + int x = to_int(args); + + if(archp(this_player())) filename = DIR_SECURE_LOGS + "/enter"; + else filename = DIR_LOGS + "/enter"; + file = read_file(filename); + + if( file ) { + lines = explode(file, "\n"); + } + else { + lines = ({}); + } + if( x < 0 ) { + x = absolute_value(x); + } + if( x > 0 ) { + int y = sizeof(lines); + + if( x <= y ) { + lines = lines[(y-x)..]; + } + } + if( !sizeof(lines) ) { + previous_object()->eventPrint(filename+" is empty.", MSG_SYSTEM); + } + else { + previous_object()->eventPage(lines, MSG_SYSTEM); + } + return 1; +} + +string GetHelp(){ + return ("Syntax: last [NUMBER]\n\n" + "Gives you a list of the last bunch of people to login or logout " + "from the enter log."); +} diff --git a/lib/secure/cmds/creators/localcmds.c b/lib/secure/cmds/creators/localcmds.c new file mode 100644 index 0000000..1c562f9 --- /dev/null +++ b/lib/secure/cmds/creators/localcmds.c @@ -0,0 +1,34 @@ +/* /secure/cmds/creator/localcmds.c + * from the Foundation II LPC Library + * lists all commands available through add_action() + * created vy Descartes of Borg 950520 + */ + +#include <lib.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + mixed *cmds; + object ob; + int cols; + + if( args && args != "" ) ob = find_player(args); + if(!ob) ob = this_player(); + cols = ((int *)previous_object()->GetScreen())[0]; + cmds = (mixed *)ob->GetCommands(); + previous_object()->more(({ center("Local commands for " + + ob->GetName(), cols) }) + + map(cmds, (: sprintf("%:-10s %:-40s %s", + $1[0], + sprintf("%O", $1[2]), + $1[3]) :) ), + "system"); + return 1; +} + +string GetHelp(){ + return ("Syntax: localcmds\n\n" + "Gives you a listing of all local (e.g. add_action() based) " + "commands available to you."); +} diff --git a/lib/secure/cmds/creators/log.c b/lib/secure/cmds/creators/log.c new file mode 100644 index 0000000..5a2c348 --- /dev/null +++ b/lib/secure/cmds/creators/log.c @@ -0,0 +1,26 @@ +// /bin/dev/_log.c +// from the Dead Souls Mudlib +// tails a given log +// created by Brian@TMI 920128 + +#include <lib.h> +#include <dirs.h> + +inherit LIB_DAEMON; + +int cmd(string str) { + if(!str) { + notify_fail("Correct syntax: <log [log file]>\n"); + return 0; + } + write(str+":\n"); + if(!tail(DIR_LOGS+"/"+str)) write("No such log file: "+str+"\n"); + return 1; +} + +string GetHelp(){ + return ("Syntax: log [log file]\n\n" + "Tails the log file named (i.e. a file " + "in the mud log directory).\n" + "See also:\nelog, replog\n"); +} diff --git a/lib/secure/cmds/creators/longcat.c b/lib/secure/cmds/creators/longcat.c new file mode 100644 index 0000000..6c56264 --- /dev/null +++ b/lib/secure/cmds/creators/longcat.c @@ -0,0 +1,90 @@ +#include <lib.h> +#include <runtime_config.h> + +inherit LIB_DAEMON; + +static int send_queued_mess(string tmp, object whom){ + message("receive", tmp, whom); + return 1; +} + +mixed cmd(string str) { + string *arr; + mixed tmp; + int delay = -1; + int bmax = (__LARGEST_PRINTABLE_STRING__ - 1024); + int chunks, rem, currchunk, smax = (get_config(__MAX_STRING_LENGTH__) - 10); + + if( !str ) return "You must specify a file to longcat."; + else str = absolute_path(this_player()->query_cwd(), str); + if( !file_exists(str) ) return "File " + str + " not found."; + if((tmp = file_size(str)) < smax){ + if( !(tmp = read_file(str)) ) + return "Unable to read file " + str + "."; + arr = explode(tmp,"\n"); + foreach(string line in arr){ + message("system", line, this_player()); + } + return 1; + } + chunks = tmp / bmax; + rem = tmp % bmax; + if(rem) chunks++; + while(chunks){ + delay++; + chunks--; + if(chunks){ + tmp = read_bytes(str, currchunk, bmax); + currchunk += bmax; + } + if(rem && !chunks){ + tmp = read_bytes(str, currchunk, rem); + currchunk += rem; + } + call_out("send_queued_mess", (delay/5), tmp, this_player()); + } + return 1; +} + +string GetHelp() { + return ("Syntax: longcat <file>\n\n" + " /\___/\ \n" + " / \ \n" + " | # # | \n" + " \ @ | \n" + " \ _|_ / \n" + " / \______ \n" + " / _______ ___ \ \n" + " |_____ \ \__/ \n" + " | \__/ \n" + " | | \n" + " | | \n" + " | | \n" + " | | \n" + " | | \n" + " | | \n" + " | | \n" + " | | \n" + " | | \n" + " | | \n" + " | | \n" + " | | \n" + " | | \n" + " | | \n" + " | | \n" + " | | \n" + " | | \n" + " | | \n" + " | | \n" + " | | \n" + " / \ \n" + " / ____ \ \n" + " | / \ | \n" + " | | | | \n" + " / | | \ \n" + " \__/ \__/ \n" + "Displays the contents of the file mentioned all at once, " + "with no limit on the output size. Note that the output " + "for ludicrously large files may lag the mud and cause " + "the command to error out with a \"Too long evaluation\"."); +} diff --git a/lib/secure/cmds/creators/ls.c b/lib/secure/cmds/creators/ls.c new file mode 100644 index 0000000..4fc326a --- /dev/null +++ b/lib/secure/cmds/creators/ls.c @@ -0,0 +1,216 @@ +/* /cmd * from Foundation II + * a faster, newer ls command + * created by Descartes of Borg 940724 + */ + +#include <lib.h> + +inherit LIB_DAEMON; + +static private mapping file_mapping(string *files); +static private string display_ls(mixed targ, int aflag, int lflag, int tflag, + int nflag, int bflag, int sflag); +static private string long_list(string dir, mixed *files); +static private string short_list(string dir, mixed *files, int n, int s); + +int cmd(string str) { + string *args, *paths, *options, *files, *tmp, *dirs; + string show; + int moref, brief, size; + int all_files, long_details, time_sort, no_load_info, i, x, maxi; + + if(str == "" || !str) str = previous_object()->query_cwd(); + if(!str) return notify_fail("No current working directory.\n"); + i = sizeof(args = explode(str, " ")); + if(args[0][0] == '-') { + if((x = strlen(args[0])) > 1) options = explode(args[0][1..x-1], ""); + else options = ({}); + if(i == 1) paths = ({ previous_object()->query_cwd() }); + else paths = args[1..i-1]; + } + else { + options = ({}); + paths = args; + } + i = sizeof(options); + while(i--) { + switch(options[i]) { + case "a": all_files = 1; break; + case "l": long_details = 1; break; + case "t": time_sort = 1; break; + case "m": moref = 1; break; + case "n": no_load_info = 1; break; + case "b": brief = 1; break; + case "s": size = 1; break; + } + } + for(i=0, maxi = sizeof(paths), files = ({}); i<maxi; i++) + if(tmp = wild_card(paths[i])) files += tmp; + if(!sizeof(files)) { + message("error", "No such file or directory.", this_player()); + return 1; + } + dirs = filter(files, "is_dir", this_object()); + if(sizeof(files = files - dirs)) + show = display_ls(file_mapping(files),all_files,long_details, time_sort, + no_load_info, brief, size); + else show = ""; + if(!(maxi = sizeof(dirs))) { + if(moref) previous_object()->more(explode(show, "\n"), "system"); + else message("system", show, previous_object()); + return 1; + } + for(i=0; i<maxi; i++){ + show += display_ls(dirs[i], all_files, long_details, time_sort, + no_load_info, brief, size); + } + if(!moref && check_string_length(show)) previous_object()->eventPrint(show); + else print_long_string(this_player(),show); + return 1; +} + +static int is_dir(string str) { return (file_size(str) == -2); } + +static private mapping file_mapping(string *files) { + mapping borg; + string *tmp; + string dir; + int i, maxi, x; + + for(i=0, maxi = sizeof(files), borg = ([]); i<maxi; i++) { + x = sizeof(tmp = explode(files[i], "/")); + if(x == 1) dir = "/"; + else dir = "/"+implode(tmp[0..x-2], "/")+"/"; + if(borg[dir]) borg[dir] += get_dir(dir+tmp[x-1], -1); + else borg[dir] = get_dir(dir+tmp[x-1], -1); + } + return borg; +} + +static private string display_ls(mixed targ, int aflag, int lflag, int tflag, + int nflag, int bflag, int sflag) { + string *cles; + string ret = ""; + int i, maxi; + + if(stringp(targ) && targ == "/") targ = ([ "/" : get_dir("/", -1) ]); + else if(stringp(targ)){ + targ = "/"+implode(explode(targ,"/"),"/"); + targ = ([ targ : get_dir(targ+"/", -1) ]); + } + for(i=0, maxi = sizeof(cles = keys(targ)); i<maxi; i++) { + if(!bflag) ret = cles[i]+":\n"; + if(!aflag) targ[cles[i]] = filter(targ[cles[i]], "filter_dots", + this_object()); + if(tflag) + targ[cles[i]]=sort_array(targ[cles[i]],"time_sort",this_object()); + if(lflag) ret += long_list(cles[i], targ[cles[i]]); + else ret += short_list(cles[i], targ[cles[i]], nflag, sflag); + ret += "\n"; + } + return ret; +} + +static int filter_dots(mixed *file) { return (file[0][0] != '.'); } + +static int time_sort(mixed *alpha, mixed *beta) { + if(alpha[2] < beta[2]) return 1; + else if(alpha[2] > beta[2]) return -1; + else return 0; +} + +static private string long_list(string dir, mixed *files) { + string ret, acc, loaded; + int i, maxi; + + if(!(maxi = sizeof(files))) return ""; + else ret = ""; + if(master()->valid_read(dir, previous_object())) acc = "r"; + else acc = "-"; + if(master()->valid_write(dir, previous_object())) acc += "w"; + else acc += "-"; + if(member_array(dir[0..strlen(dir)-2], + previous_object()->GetSearchPath()) != -1) acc += "x"; + else acc += "-"; + for(i=0, maxi=sizeof(files); i<maxi; i++) { + if(files[i][1] == -2) loaded = ""; + else loaded = (find_object(dir+files[i][0]) ? "*" : ""); + ret += sprintf("%:-3s%:-5s%:-30s %d\t%s", + loaded, acc, ctime(files[i][2]), + files[i][1], files[i][0]); + if(files[i][1] == -2) ret += "/\n"; + else ret += "\n"; + } + return ret; +} + +static private string short_list(string dir, mixed *files, int n, int s) { + string *newfiles; + string ret, tmp; + int i, j, max, x, long, ind, cols, rows; + + i = sizeof(newfiles=map_array(files,"map_files",this_object(),({dir,n,s}))); + while(i--) if((x=strlen(newfiles[i])) > long) long = x; + tmp = previous_object()->GetEnvVar("SCREEN"); + if(!tmp || !sscanf(tmp, "%d", x) || !x) x = 80; + x = x-2; + if(long > x/3-3) long = x/3-3; + cols = x/(long+3); + rows = (max = sizeof(newfiles))/cols; + if(max % cols) rows++; + ret = ""; + for(i=0; i<rows; i++) { + for(j=0; j<cols; j++) { + ind = (rows * j) + i; + if(ind < max) ret += sprintf("%:-"+(long+3)+"s", newfiles[ind]); + else ret += sprintf("%:-"+(long+3)+"s", ""); + } + ret += "\n"; + } + return ret; +} + +static string map_files(mixed *file, int *flags) { + string tmp; + + if(flags[1] && flags[2]) { + if(file[1] == -2) return file[0]+"/"; + else return file[0]; + } + if(!flags[1]) { + if(find_object(flags[0]+file[0]) && file[1] != -2) tmp = "*"; + else tmp = " "; + } + else tmp = ""; + if(!flags[2]) { + if(file[1] == -2) tmp = tmp + " "; + else if(!file[1]) tmp = tmp + "0 "; + else if(file[1] < 1024) tmp = " 1 "; + else tmp = sprintf("%s%:-3d ", tmp, (file[1]/1024)); + } + return tmp + file[0] + ((file[1] == -2) ? "/" : ""); +} + +string GetHelp(){ + return ("Syntax: <ls [-ablmnst] (directories|files)>\n\n" + "If you pass a single directory as an argument, it will list all " + "files and directories in that directory. If you list a single " + "file, then information about that file will be displayed. If you " + "use special characters like wild cards, then relevant information " + "regarding those files and/or directories will be displayed. The " + "options have the following meanings:\n" + " -a List all files, including files beginning with a '.'\n" + " -b Brief listing, leaving out the directory name\n" + " -l Long listing of all details about a file\n" + " -m Page the output through more\n" + " -n No display of loaded object information\n" + " -s No display of size information\n" + " -t Sort directory listings by time last modified\n\n" + "The -l option overrides the -n and -s options. The columns " + "in the -l listing break down in the following manner:\n" + " * if loaded, blank space if not loaded\n" + " Access permissions, in the form of rwx\n" + " Time last modified\n" + " Size of the file\n" + " File name\n\nSee also: cd, mkdir, mv, pwd, rm, rmdir"); +} diff --git a/lib/secure/cmds/creators/lsed.c b/lib/secure/cmds/creators/lsed.c new file mode 100644 index 0000000..5498db8 --- /dev/null +++ b/lib/secure/cmds/creators/lsed.c @@ -0,0 +1,97 @@ +/* /secure/cmds/creator/lsed.c + * from the Dead Souls LPC Library + * an LPC scripted editor + * created by Descartes of Borg 950407 + */ + +#include <lib.h> + +inherit LIB_DAEMON; + +static void LsedFile(string file, string *cmds, int num_cmds); + +mixed cmd(string args) { + string *files, *lines, *tmp; + string total, script, pwd; + int i, maxi, x; + + if( args == "" || !args ) return "Syntax: <lsed [script] [filelist]>"; + if( (maxi = sizeof(files = explode(args, " "))) == 1 ) + return "You must specify the name of a file to run the script on."; + pwd = this_player()->query_cwd(); + script = absolute_path( pwd, files[0] ); + files = files[1..]; + maxi--; + for(i=0, tmp = ({}); i<maxi; i++) { + files[i] = absolute_path(pwd, files[i]); + tmp += wild_card(files[i]); + } + maxi = sizeof(files = tmp); + if( !(total = read_file(script)) ) return "Failed to load script: "+script; + x = sizeof(lines = explode(total, "\n")); + for(i=0; i<maxi; i++){ + int y; + + y = file_size(files[i]); + if( y == -2 ) { + message("system", "lsed: File " + files[i] + " is a directory.", + this_player()); + continue; + } + else if( y == -1 ) { + message("system", "lsed: File " + files[i] + " does not exist.", + this_player()); + continue; + } + LsedFile(files[i], lines, x); + } + return 1; +} + +static void LsedFile(string file, string *cmds, int num_cmds) { + string ret; + int i; + + ed_start(file, 0); + if( query_ed_mode() == -1 ) { + message("system", "lsed: Failed to read file " + file, this_player()); + return; + } + for(i=0; i<num_cmds; i++) { + ret = ed_cmd(cmds[i]); + if( query_ed_mode() == -1 ) { + message("system", "lsed: Script quit unexpectedly on line " + + (i+1) + " for file " + file + " with message: " + ret, + this_player()); + return; + } + } + ret = ed_cmd("x"); + if( query_ed_mode() != -1 ) { + ed_cmd("Q"); + message("system", "lsed: permission denied for " + file, + this_player()); + return; + } + message("system", ret, this_player()); +} + +string GetHelp() { + return ("Syntax: lsed <script> <filelist>\n\n" + "Allows you to perform editor commands on a file or set of files " + "from a script. You simply write a script of editor commands " + "and save it to a file. For example, say that you wanted to " + "change set_item_functions() to SetItems() and " + "set_search_function() to SetSearch() in every file in your home " + "directory. You would write a script that looks like:\n\n" + "s/set_item_functions/SetItems/g\n" + "s/set_search_function/SetSearch/g\n\n" + "save it as convert.lsed, and then at the command line type: " + "\"lsed sconvert.lsed *\". Keep in mind that the MudOS " + "driver will only let an execution thread run so long " + "before automatically terminating it with a too long evaluation " + "error, so avoid running lsed on a large number of files at " + "once.\n" + "See also: ed"); +} + diff --git a/lib/secure/cmds/creators/memcheck.c b/lib/secure/cmds/creators/memcheck.c new file mode 100644 index 0000000..5a39019 --- /dev/null +++ b/lib/secure/cmds/creators/memcheck.c @@ -0,0 +1,39 @@ +/* /secure/cmd * from the Dead Souls LPC Library + * gives information on leaked memory + * NOTE: Only works with DEBUGMALLOC defined + * created by Descartes of Borg 950206 + */ + +#include <lib.h> + +inherit LIB_DAEMON; + +string cmd(string unused) { + string ret = ""; + if(efun_exists("check_memory")){ +#ifdef __DEBUGMALLOC__ +#ifdef __DEBUGMALLOC_EXTENSIONS__ +#ifdef __PACKAGE_DEVELOP__ + ret = check_memory(1); +#endif +#endif +#endif + write("%^RED%^The output for this command may be misleading. It is kept "+ + "as a historical curiosity, but is not necessarily reliable.%^RESET%^"); + if(sizeof(ret) < 7000) write(ret); + else { + this_player()->eventPage(({ret})); + } + return "%^RED%^The output for this command may be misleading. It is kept "+ + "as a historical curiosity, but is not necessarily reliable.%^RESET%^"; + } + else { + return "This command relies on an efun that is not currently available."; + } +} + +string GetHelp() { + return ("Syntax: memcheck\n\n" + "Gives you information about leaked memory.\n" + "See also: mstatus, netstat"); +} diff --git a/lib/secure/cmds/creators/mkdir.c b/lib/secure/cmds/creators/mkdir.c new file mode 100644 index 0000000..ae78bea --- /dev/null +++ b/lib/secure/cmds/creators/mkdir.c @@ -0,0 +1,39 @@ +/* +// This file is part of the TMI Mudlib distribution. +// Please include this header if you use this code. +// Written by Sulam(1-8-92) +// Help added by Brian (1/28/92) + */ + +#include <lib.h> +inherit LIB_DAEMON; + +string GetHelp(); + +mixed cmd(string str) { + if( !str ) + { + return GetHelp(); + } + str = absolute_path(this_player()->query_cwd(), str); + if( file_size(str) != -1 ) + { + notify_fail("mkdir: "+str+": file already exists.\n"); + return 0; + } + if( master()->valid_write(str, previous_object(), "rmdir") == 0 ) + { + notify_fail(str+": Permission denied.\n"); + return 0; + } + write(mkdir(str) ? "Ok.\n" : str+": couldn't make directory.\n"); + return 1; +} + +string GetHelp(){ + return ("Syntax: mkdir <directory>\n\n" + "This command makes a new directory with the name specified. " + "If no path information is supplied, the new directory will be " + "a sub directory of the present working directory. For more " + "on specifying paths see: help cd"); +} diff --git a/lib/secure/cmds/creators/monitor.c b/lib/secure/cmds/creators/monitor.c new file mode 100644 index 0000000..abea890 --- /dev/null +++ b/lib/secure/cmds/creators/monitor.c @@ -0,0 +1,26 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +int cmd(string str) { + object ob; + + if( !str || str == "" ) { + write("Monitor whom?\n"); + } + else if(!user_exists(str)) + write(str+": no such player.\n"); + else{ + SNOOP_D->AddMonitor(this_player()->GetKeyName(), str); + write("The snoop daemon has received your request."); + } + return 1; +} + +string GetHelp(){ + return "Syntax: monitor <user>\n\n" + "Logs to a file everything <user> sees or types. " + "To stop monitoring, an admin must type \"unmonitor <user>\"\n" + "See also: unmonitor, snoop, unsnoop"; +} diff --git a/lib/secure/cmds/creators/more.c b/lib/secure/cmds/creators/more.c new file mode 100644 index 0000000..42818f2 --- /dev/null +++ b/lib/secure/cmds/creators/more.c @@ -0,0 +1,24 @@ +/* /secure/cmds/creator/more.c + * from the Dead Souls Object Library + * more FILE + * created by Descartes of Borg 951104 + */ + +#include <lib.h> +#include <message_class.h> +#include "include/more.h" + +inherit LIB_DAEMON; + +mixed cmd(string str) { + if( !str || str == "" ) return "Syntax: <more FILE>"; + return this_player()->eventPage(str, MSG_SYSTEM | MSG_NOCOLOUR); +} + +string GetHelp(){ + return ("Syntax: more <FILE>\n\n" + "Pages through the file you name. While inside the pager, you " + "have access to the following commands:\n" + + LIB_PAGER->GetHelp("pager") + "\n\n" + "See also: cat, ed, head, tail"); +} diff --git a/lib/secure/cmds/creators/mudtime.c b/lib/secure/cmds/creators/mudtime.c new file mode 100644 index 0000000..764350c --- /dev/null +++ b/lib/secure/cmds/creators/mudtime.c @@ -0,0 +1,42 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd() { + int *mudtime; + int hours, minutes; + string meridiem = " am"; + string nulle = ""; + int daynum = query_date(); + + mudtime = SEASONS_D->GetMudTime(); + hours = mudtime[0]; + minutes = mudtime[1]; + + // if you want an odd (as in not even) number of hours in + // a day, this may need fiddling with. + + if(hours >= (DAY_LENGTH / 2)) + meridiem = " pm"; + if(hours > (DAY_LENGTH / 2) && hours != DAY_LENGTH) + hours -= (DAY_LENGTH / 2); + if(!hours) hours = (DAY_LENGTH / 2); + + if(minutes < 10) nulle = "0"; + + write("It is "+query_day_name()+", "+daynum+ordinal(daynum)+" day of "+ + query_month()+", in "+query_season()+"."); + + write("In the MUD, the time is "+hours+":"+nulle+minutes+meridiem+"."); + + return 1; + +} + +string GetHelp() { + return ("Syntax: mudtime\n\n" + "Displays the time inside of the MUD. This is entirely " + "separate from what time it is anywhere in the real world, " + "should one still exist."); +} diff --git a/lib/secure/cmds/creators/mv.c b/lib/secure/cmds/creators/mv.c new file mode 100644 index 0000000..e1b3060 --- /dev/null +++ b/lib/secure/cmds/creators/mv.c @@ -0,0 +1,72 @@ +/* +// This file is part of the TMI Mudlib distribution. +// Please include this header if you use this code. +// Adapted by Buddha(1-18-91) from unknown source. +// Added check for existance of destination file. Plura 930120 + */ + +#include <lib.h> +inherit LIB_DAEMON; + +int cmd(string str); +string GetHelp(); + + +mixed cmd(string str){ + string t1, t2, *tmp; + int force = 0; + int dir = 0; + if(this_player()->GetForced()) { + write("Someone tried forcing you to mv "+str+"\n"); + return 1; + } + + if(!str || !sizeof(str)){ + return GetHelp(); + } + + if(sscanf(str,"-f %s %s",t1,t2) == 2) { + force = 1; + str = t1+" "+t2; + } + if(!str||sscanf(str,"%s %s",t1,t2)!=2) { + /* We should add checks for flags here. */ + return GetHelp(); + } else { + if(!force){ + if(file_size(t2=absolute_path(this_player()->query_cwd(),t2)) > 0) + { + notify_fail("mv: "+t2+" already exists.\n"); + return 0; + } + } + t1=absolute_path(this_player()->query_cwd(),t1); + t2=absolute_path(this_player()->query_cwd(),t2); + if(directory_exists(t1)) dir = 1; + else if(file_exists(t1)) dir = 0; + else { + write(t1+": no such file or directory."); + return 1; + } + if(!dir && directory_exists(t2)){ + if(last(t2,1) != "/") t2 += "/"; + t2 += last_string_element(t1,"/"); + } + rename(t1,t2); + if((dir && directory_exists(t2) && !directory_exists(t1)) || + (!dir && file_exists(t2) && !file_exists(t1)) ) + write("mv: Ok."); + else write("mv: Failed."); + } + return 1; +} + +string GetHelp() { + return "Syntax: mv <file1> <file2|directory>\n\n" + "Renames a file or moves it into the directory specified.\n" + "The -f flag forces the overwriting of an existing file.\n\n" + "Examples:\n"+ + "mv -f workroom.bak workroom.c\n"+ + "mv workroom.bak /tmp/\n\n" + "See also: rm"; +} diff --git a/lib/secure/cmds/creators/people.c b/lib/secure/cmds/creators/people.c new file mode 100644 index 0000000..d7b98df --- /dev/null +++ b/lib/secure/cmds/creators/people.c @@ -0,0 +1,308 @@ +/* /cmd * from Dead Souls + * a listing of users for creators and ambassadors + * created by Descartes of Borg 940724 + */ + +#include <lib.h> +#include <localtime.h> +#include <dirs.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +static private int *__SortFlags; + +static private string query_people_time(); +private string calculateFormatString(int screenSize); +object *whom, *who, *display; +string *args; + +string GetBaseName(object ob){ + string ret; + if(ob) ret = capitalize(cleaned_end(base_name(ob))); + if(!ret && ob) ret = ob->GetCapName(); + if(!ret) ret = ""; + return ret; +} + +mixed room_env(object ob){ + string *riders; + object env = environment(ob); + if(!env) return 0; + if(!living(env)) return env; + if(arrayp(riders = env->GetRiders()) && member_array(ob, riders) != -1 && + environment(env)) env = environment(env); + return env; +} + +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; + int screenSize; + 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"; + msg = bar; + tmp1 = " " + maxi + ((maxi != 1) ? " people" : " person") + " in current sort "; + tmp2 = query_people_time() + " "; + i = sizeof(tmp1) + sizeof(tmp2); + msg += tmp1; + for(i = sizeof(tmp1) + sizeof(tmp2) + 1; i < screenSize; i++) msg += " "; + msg += tmp2 + "\n"; + msg += bar; + msg += implode(map_array(display, "map_info", this_object(), formatString), "\n") + "\n"; + msg += bar; + msg += center(mud_name(), screenSize - 1); + if(!check_string_length()) mflag = 1; + if(!mflag && check_string_length(msg)) this_player()->eventPrint(msg); + else print_long_string(this_player(),msg); + return 1; +} + +static int filter_invis(object ob) { + if(!ob || !sizeof(base_name(ob))) return 0; + if(!(ob->GetKeyName())) return 0; + if(!(ob->GetInvis(this_player()))) return 1; + if(archp(this_player())) return 1; + if(archp(ob)) return 0; + return 1; +} + +static int filter_arches(object ob) { return archp(ob); } + +static int filter_ambass(object ob) { return ambassadorp(ob); } + +static int filter_cres(object ob) { return (creatorp(ob) && !archp(ob)); } + +static int filter_hms(object ob) { return high_mortalp(ob); } + +static int filter_newbie(object ob) { + return (!creatorp(ob) && !ambassadorp(ob) && (MAX_NEWBIE_LEVEL >= + ob->GetLevel())); +} + +static int filter_mortal(object ob) { + if(creatorp(ob) || high_mortalp(ob) || ambassadorp(ob)) return 0; + if(ob->GetLevel() <= MAX_NEWBIE_LEVEL) return 0; + return 1; +} + +static int filter_undead(object ob) { return ob->query_ghost(); } + +static int general_sort(object alpha, object beta) { + int x, y; + + if(archp(alpha)) { + if(!archp(beta)) return -1; + else return strcmp(GetBaseName(alpha), + GetBaseName(beta)); + } + else if(archp(beta)) return 1; + if(creatorp(alpha)) { + if(!creatorp(beta)) return -1; + else return strcmp(GetBaseName(alpha), + GetBaseName(beta)); + } + else if(creatorp(beta)) return 1; + if(ambassadorp(alpha)) { + if(!ambassadorp(beta)) return -1; + else return strcmp(GetBaseName(alpha), + GetBaseName(beta)); + } + else if(ambassadorp(beta)) return 1; + if((x = alpha->GetLevel()) > (y = beta->GetLevel())) + return -1; + else if(x < y) return 1; + else return strcmp(GetBaseName(alpha), + GetBaseName(beta)); +} + +static int special_sort(object alpha, object beta) { + string a, b; + int x, y; + + if(__SortFlags[4]) { + if((a=alpha->query_class())!=(b=beta->query_class())) { + if(!a) a = "zzzz"; + if(!b) b= "zzzz"; + return strcmp(a, b); + } + } + if(__SortFlags[0]) { + if((a=alpha->query_race()) != (b=beta->query_race())) { + if(!a) a = "zzzz"; + if(!b) b = "zzzz"; + return strcmp(a, b); + } + } + if(__SortFlags[3]) { + if((a = file_name(room_env(alpha))) != + (b = file_name(room_env(beta)))) return strcmp(a, b); + } + if(__SortFlags[2]) { + if((x = alpha->GetLevel()) != (y=beta->GetLevel())) { + if(x > y) return -1; + else return 1; + } + } + if(__SortFlags[1]) { + if((x = alpha->GetAge()) != (y = 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"; +} + +static string map_info(object ob, string formatString) { + string age, nom, blk, lev, ip, env, idle; + int x; + + x = ob->GetAge(); + if(x > 86400) age = sprintf("%:-2d D", x/86400); + else if(x > 7200) age = sprintf("%:-2d h", x/3600); + else age = sprintf("%:-2d m", x/60); + nom = GetBaseName(ob); + if(ob->GetInvis()) nom = "("+nom+")"; +#ifndef __DSLIB__ + if(in_edit(ob) || in_input(ob)) nom = "["+nom+"]"; +#else + if(ob->GetCharmode()){ + if(in_edit(ob)) nom = "["+nom+"]"; + } + else if(in_edit(ob) || in_input(ob)) nom = "["+nom+"]"; +#endif + if(creatorp(ob)) { + if(ob->GetBlocked("all")) blk = "ACG"; + else { + if(ob->GetBlocked("cre")) blk = " C"; + else blk = " "; + if(ob->GetBlocked("gossip")) blk += "G"; + else blk += " "; + } + } + else blk = " "; + if(!(x = ob->GetLevel())) lev = "-"; + else lev = x+""; + if((x = query_idle(ob)) < 60) idle = ""; + else if(x >= 3600) idle = sprintf("%:-3d h", x/3600); + else idle = sprintf("%:-2d m", x/60); + ip = query_ip_name(ob); + if(ip == "0.0.0.0" || ip == "w.x.y.z") ip = ""; + if(!room_env(ob)) env = "no environment"; + else env = file_name(room_env(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_people_time() { + string tzone; + if(this_player()) tzone = this_player()->GetProperty("timezone"); + if(!tzone || !valid_timezone(tzone)) tzone = query_tz(); + return tzone + " time is: " + local_ctime(time(), tzone); +} + +string GetHelp() { + return ("Syntax: people [-abceghlmnprsu]\n\n" + "Gives you a listing of people on "+mud_name()+". Output is " + "formatted into columns with the following meanings:\n" + " amount of time spent total on "+mud_name()+"\n" + " level\n" + " name\n" + " address from which the person is connecting\n" + " amount of time idle\n" + " blocking information, if any... A is all, C cre, G gossip\n" + " current environment file name\n\n" + "Command flags have the following meanings:\n" + " -a list all arches\n" + " -b list all ambassadors\n" + " -c list all non-arch creators\n" + " -e sort the listing by race\n" + " -g sort the listing by age\n" + " -h list all high mortals\n" + " -l sort the listing by level\n" + " -m pipe the listing through the more pager\n" + " -n list all newbies\n" + " -p list all non-newbie and non-high mortal mortals\n" + " -r sort the listing by current environment\n" + " -s sort the listing by class\n" + " -u list all undead people\n\n" + "People in the editor or in mail or posting will be " + "marked with []. " + "People who are invisible to others, but not to you will be marked " + "with (). The default sort is by arch, then by creator, then by " + "ambassador, then by level. You can perform multiple sorts, but " + "you cannot change the priority. Sorts priority is: class, race, " + "realm, level, age. You can also include multiple groups in your " + "listing. Fart.\nSee also: who, users"); +} diff --git a/lib/secure/cmds/creators/profile.c b/lib/secure/cmds/creators/profile.c new file mode 100644 index 0000000..a160063 --- /dev/null +++ b/lib/secure/cmds/creators/profile.c @@ -0,0 +1,48 @@ +#include <lib.h> +#include <daemons.h> +#include <message_class.h> + +inherit LIB_DAEMON; + +mixed cmd(string str) { +#ifdef __PROFILE_FUNCTIONS__ + mixed *funs; + object ob; + string tmp, ret = ""; + int err; + + if(!file_exists(lpc_file(str))){ + tmp = absolute_path(this_player()->query_cwd(), str); + } + if(tmp && file_exists(lpc_file(tmp))) str = tmp; + else if(!(ob = find_object(str))) str = DEFINES_D->GetDefine(str); + if(!ob && file_exists(lpc_file(str))) err = catch( ob = load_object(str) ); + if(err || !ob){ + write("Could not find or load that object."); + return 1; + } + write("Found "+identify(ob)); + funs = function_profile(ob); + foreach(mixed element in funs){ + mixed temp = sort_array(keys(element),1); + foreach(mixed sub in temp){ + ret += sub+": "+element[sub]+" "; + } + ret += "\n"; + } + write(ret); + return 1; +#else + write("This command depends on an efun that is not available."); + return 1; +#endif +} + +string GetHelp(){ + return ("Syntax: profile <file or object>\n\n"+ + "Provides a report of the given object's function "+ + "profile data. See \"man function_profile\" for details "+ + "of what this data is. This command requires that the "+ + "driver be compiled with the PROFILE_FUNCTIONS define.\n"+ + "See also: vars, var, variables"); +} diff --git a/lib/secure/cmds/creators/pwd.c b/lib/secure/cmds/creators/pwd.c new file mode 100644 index 0000000..82c1e7e --- /dev/null +++ b/lib/secure/cmds/creators/pwd.c @@ -0,0 +1,14 @@ +/* + * Help for the pwd command (located inside the player object) + */ + +#include <lib.h> + +inherit LIB_DAEMON; + +string GetHelp() { + return ("Syntax: pwd\n\n" + "Defined internal to the user object.\n" + "Prints your current working directory.\n" + "See also: cd"); +} diff --git a/lib/secure/cmds/creators/qed.c b/lib/secure/cmds/creators/qed.c new file mode 100644 index 0000000..1720a63 --- /dev/null +++ b/lib/secure/cmds/creators/qed.c @@ -0,0 +1,57 @@ +/* /secure/cmds/creator/ed.c + * from the Dead Souls LPC Library + * creator command to enter the editor + * created by Descartes of Borg 950406 + */ + +#include <lib.h> +#include <message_class.h> + +inherit LIB_DAEMON; + +int UnMuff(object whom){ + if(!whom) whom = this_player(); + whom->eventPauseMessages(0); + return 1; +} + +mixed cmd(string args) { + int x; + + if( args == "" || !args ) + args = user_path(this_player()->GetKeyName()) + "tmp.edit"; + if( this_player()->GetForced() ) { + message("system", "Someone tried to force you to edit "+ args +"\n" + + identify(previous_object(-1)), this_player()); + return 0; + } + + if(!this_player()->GetProperty("EdWarned")){ + write("This is the first time you've used ed. If you get stuck, simply " + "hit return a few times, then enter a dot on a blank line, hit return, " + "then type Q, then enter. Then visit this page to learn more about " + "using the ed editor: http://dead-souls.net/editor.html"); + this_player()->SetProperty("EdWarned", 1); + } + args = absolute_path( this_player()->query_cwd(), args ); + if( (x = file_size(args)) == -2 ) + return "You cannot edit a directory!"; + else if( x == -1 ) + message("editor", args + ", new file, starting in input mode.\n", + this_player()); + else message("editor", args + ", " + x + " bytes\n", this_player()); + this_player()->eventPauseMessages(1,MSG_EDIT); + this_player()->eventEdit(args, (: UnMuff(this_player()) :) ); + return 1; +} + +string GetHelp() { + return ("Syntax: qed [filename]\n\n" + "This is the quiet version of ed. While editing, " + "you will receive only editing data and some other limited " + "messages. " + "Once done editing, the game messages you missed will be " + "displayed to you. Be careful where you use this command, for you " + "may engage in combat and be killed without knowing about it " + "until you complete your editing.\nSee also: ed, ced, qcs, creweb"); +} diff --git a/lib/secure/cmds/creators/removeemote.c b/lib/secure/cmds/creators/removeemote.c new file mode 100644 index 0000000..c616515 --- /dev/null +++ b/lib/secure/cmds/creators/removeemote.c @@ -0,0 +1,54 @@ +/* /secure/cmds/admins/removeemote.c + * From the Dead Souls Mud Library + * Command for removing commands from the soul + * Created by Descartes of Borg 961214 + * Version: @(#) removeemote.c 1.2@(#) + * Last modified: 96/12/14 + */ + +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string args){ + string verb, rule; + if( !(master()->valid_apply(({ "ASSIST" }))) && + !member_group(this_player(), "EMOTES") ){ + write("You are not admin, nor a member of the EMOTES group."); + return 1; + } + + if( !args || args == "" ) { + return "Remove which emote?"; + } + if( sscanf(args, "%s %s", verb, rule) != 2 ) { + verb = args; + rule = 0; + } + if( !rule ) { + if( !SOUL_D->RemoveVerb(verb) ) { + previous_object()->eventPrint("Removal of verb failed."); + return 1; + } + previous_object()->eventPrint("Verb removed."); + } + else { + if( !SOUL_D->RemoveRule(verb, rule) ) { + previous_object()->eventPrint("Removal of rule failed."); + return 1; + } + previous_object()->eventPrint("Rule removed."); + } + return 1; +} + +string GetHelp(){ + return ("Syntax: removeemote <EMOTE> [RULE]\n\n" + "Allows you to remove an emote or a rule for an emote from " + "the soul. If you specify a rule, only that rule gets removed. " + "If you fail to specify a rule, the entire emote is removed.\n\n" + "You must be admin or member of the EMOTES group to " + "use this command.\n" + "See also: addadverb, addemote, removeadverb"); +} diff --git a/lib/secure/cmds/creators/restore.c b/lib/secure/cmds/creators/restore.c new file mode 100644 index 0000000..cd3829e --- /dev/null +++ b/lib/secure/cmds/creators/restore.c @@ -0,0 +1,98 @@ +#include <lib.h> +#include <dirs.h> +#include <commands.h> + +inherit LIB_DAEMON; +string globalstr1, globalstr2; +int globalint; + +mixed cmd(string str) { + string *sorted_array, *sub_arr, *new_arr, *bkarr; + string line, s1, bkname, bkcontents; + int number; + object here; + + if( !str ) return "You must specify a file to restore."; + if(str && sscanf(str,"%s %d",s1, number) > 1) str = s1; + else false(); + + new_arr = ({}); + sub_arr = ({}); + + bkname = homedir(this_player())+"/bak/bk.db"; + + if(!file_exists(bkname)) { + write("The backup database file does not exist. Aborting."); + return 1; + } + + bkcontents = read_file(bkname); + bkarr = explode(bkcontents,"\n"); + + foreach(string zline in bkarr){ + if(!strsrch(zline,str)) new_arr += ({ zline }); + } + + if(!sizeof(new_arr) && str == "here"){ + here = environment(this_player()); + str = last_string_element(base_name(here),"/"); + foreach(string zline in bkarr){ + if(!strsrch(zline,str)) new_arr += ({ zline }); + } + } + + if(!sizeof(new_arr)){ + write("You haven't backed up a file by that name."); + return 1; + } + + if(str == "workroom.orig") { + unguarded( (: globalint = cp(homedir(this_player())+"/bak/workroom.orig", + homedir(this_player())+"/workroom.c") :) ); + if(globalint) { + write("Workroom file restored."); + load_object(CMD_UPDATE)->cmd("-a "+homedir(this_player())+"/workroom.c"); + } + else write("Workroom could not be restored."); + return 1; + } + + foreach(string zline in bkarr){ + if(strsrch(zline,str) != -1) new_arr += ({ zline }); + } + + if(!number || number < 1) number = 1; + sorted_array = sort_array(new_arr, -1); + if(number > sizeof(sorted_array)) number = sizeof(sorted_array); + line = sorted_array[(number - 1)]; + + sub_arr = explode(line," : "); + if(!file_exists(REALMS_DIRS + "/" + this_player()->GetKeyName()+"/bak/"+sub_arr[0])){ + write("That file has an entry in the backup database but can't be found in your backup directory."); + return 1; + } + globalstr1 = REALMS_DIRS + "/" + this_player()->GetKeyName()+"/bak/"+sub_arr[0]; + globalstr2 = sub_arr[1]; + cp(globalstr1, globalstr2); + if(here) reload(here); + write("File restored."); + return 1; +} + +string GetHelp(){ + return ("Syntax: restore <STRING> [NUMBER]\n\n" + "Restores the specified file from your bak/ directory. " + "If you specify a number, the command will try to find " + "the Nth newest file to restore. Examples:\n" + "To restore the most recent version of file.c:\n" + "restore file.c\n" + "To restore the version you backed up before the most " + "recent version:\n" + "restore file.c 2\n" + "And so on.\n" + "\"restore here\" will attempt to restore a backup of the room " + "you are currently standing in, and will reload it, if possible. " + "This is the only case in which the command will automatically " + "reload a restored object.\n" + "See also: bk"); +} diff --git a/lib/secure/cmds/creators/rm.c b/lib/secure/cmds/creators/rm.c new file mode 100644 index 0000000..11e5f4c --- /dev/null +++ b/lib/secure/cmds/creators/rm.c @@ -0,0 +1,53 @@ +// /bin/dev/_rm.c +// from the Dead Souls Mudlib +// the command to rm files (wild cards without prompt!!!!, be careful) +// created by Descartes of Borg 02 august 1993 + +#include <lib.h> + +inherit LIB_DAEMON; + +int cmd(string str) { + string *files; + string tmp; + object ob; + int i; + + if(!str) { + notify_fail("Correct syntax: <rm [file]>\n"); + return 0; + } + if((ob=previous_object())->GetForced()) { + write("Someone attempted to force you to rm "+str+"."); + return 1; + } + tmp = absolute_path(ob->query_cwd(), str); + if(!archp(ob) || !sizeof(files = wild_card(tmp))) + files = ({ tmp }); + if(!(i=sizeof(files))) { + message("system", "File "+tmp+" does not exist.", this_player()); + return 1; + } + while(i--) { + switch(file_size(files[i])) { + case -1: message("system", "File "+files[i]+" does not exist.", + this_player()); break; + case -2: message("system", files[i]+" is a directory.", + this_player()); break; + default: message("system", rm(files[i]) ? files[i]+": Ok." : + files[i]+": Permission denied.", this_player()); + break; + } + } + return 1; +} + +string GetHelp(){ + string ret = "Syntax: rm [file]\n\n" + "The command deletes the file named. Once deleted, the file " + "cannot be recovered. Seriously."; + if(archp(this_player())) + ret += "Note for arches: wild cards work with this command, " + "but there is no prompt, so be VERY CAREFULL!!!!"; + return ret; +} diff --git a/lib/secure/cmds/creators/rmdir.c b/lib/secure/cmds/creators/rmdir.c new file mode 100644 index 0000000..67a3a84 --- /dev/null +++ b/lib/secure/cmds/creators/rmdir.c @@ -0,0 +1,43 @@ +/* +// This file is part of the TMI Mudlib distribution +// Please include this header if you use this code. +// Written by Sulam(1-8-92) +// Help added (1/28/92) by Brian + */ + +#include <lib.h> +inherit LIB_DAEMON; + +string GetHelp(); + +mixed cmd(string str){ + if( !str ) + { + return GetHelp(); + } + str = absolute_path(this_player()->query_cwd(), str); + switch( file_size(str) ) + { + case -1: + notify_fail("rmdir: "+str+": No such file.\n"); + return 0; break; + case -2: + break; + default: + notify_fail("rmdir: "+str+": not a directory.\n"); + return 0; break; + } + if( master()->valid_write(str, this_object(), "rmdir") == 0 ) + { + notify_fail(str+": Permission denied.\n"); + return 0; + } + write(rmdir(str) ? "Ok.\n" : str+": couldn't remove directory.\n"); + return 1; +} + +string GetHelp(){ + return ("Syntax: rmdir <directory>\n\n"+ + "This command allows you to remove the specified directory. If " + "the directory is not empty then the command will fail."); +} diff --git a/lib/secure/cmds/creators/rss.c b/lib/secure/cmds/creators/rss.c new file mode 100644 index 0000000..edbd2ee --- /dev/null +++ b/lib/secure/cmds/creators/rss.c @@ -0,0 +1,355 @@ +#include <lib.h> +#include NETWORK_H +#include <socket_err.h> +#include <message_class.h> + +inherit LIB_DAEMON; + +#define HTTP_ADDRESS "204.209.44.12" +#define HTTP_HOST "lpmuds.net" +#define HTTP_PORT 80 +#define HTTP_PATH "/forum/index.php?type=rss;action=.xml" +#define NOTES_DELIM "----" + +#define SAVE_FILE "/doc/RELEASE_NOTES_HTTP" + + +#define SOCK_FIND 0 +#define SOCK_CONNECTING 1 +#define SOCK_CONNECTED 2 +#define SOCK_DISCONNECTED 3 +#define SOC_ERROR 4 + +#define _DEBUG + +int socket; +int status; +object player; +object person; +mapping Feeds = ([]); +mapping Sockets = ([]); + +string results, s; + +void sendHTTPGet(); +void Setup(); + +int http_file_found; + +private string args_list; + +void create(){ + daemon::create(); + if(!Feeds) Feeds = ([]); + if(!Sockets) Sockets = ([]); + call_out((: Setup :), 2); +} + +void add_feed(string name, mapping feed){ + Feeds[name] = feed; +} + +void Setup(){ + set_heart_beat(1); + + add_feed("lpmuds-forum", ([ + "name": "LPMuds.net", + "ip_port": "204.209.44.12 80", + "host": "lpmuds.net", + "req": "GET /forum/index.php?type=rss;action=.xml HTTP/1.0", + "wait": 15, + "min_wait": 2, + "max_wait": 15, + "timer": -1, + "userid": "LPMuds", + ]) ); + + add_feed("tmc-forums", ([ + "name": "Mudconnect.com Forums", + "ip_port": "66.150.96.119 80", + "host": "feeds.feedburner.com", + "req": "GET /TMCForums HTTP/1.0", + "wait": 15, + "min_wait": 2, + "max_wait": 20, + "timer": -1, + "userid": "TMC", + ]) ); + add_feed("tmc-mudconnect", ([ + "name": "Mudconnect.com", + "ip_port": "66.150.96.119 80", + "host": "feeds.feedburner.com", + "req": "GET /Mudconnect HTTP/1.0", + "wait": 15, + "min_wait": 2, + "max_wait": 30, + "timer": -1, + "userid": "TMC", + ]) ); + + add_feed("mudbytes-forum", ([ + "name": "MudBytes", + "ip_port": "209.190.9.170 80", + "host": "www.mudbytes.net", + "req": "GET /index.php?a=rssfeed HTTP/1.0", + "wait": 15, + "min_wait": 2, + "max_wait": 15, + "timer": -1, + "userid": "MudBytes", + ]) ); + + add_feed("smaugmuds-forum", ([ + "name": "SmaugMuds.org", + "ip_port": "66.218.49.113 80", + "host": "www.smaugmuds.org", + "req": "GET /index.php?a=rssfeed HTTP/1.0", + "wait": 15, + "min_wait": 2, + "max_wait": 15, + "timer": -1, + "userid": "SmaugMuds", + ]) ); + + add_feed("topmudsites-forum", ([ + "name": "Top Mud Sites Forum", + "ip_port": "72.232.233.194 80", + "host": "www.topmudsites.com", + "req": "GET /forums/external.php?type=RSS2&lastpost=true HTTP/1.0", + "append": ([ "ext": ".html", "string": "-new-post" ]), + "wait": 15, + "min_wait": 2, + "max_wait": 15, + "timer": -1, + "userid": "TMS", + ]) ); + + add_feed("arthmoor-forum", ([ + "name": "Arthmoor Internet Services: MUD Hosting", + "ip_port": "66.218.49.113 80", + "host": "www.arthmoor.com", + "req": "GET /forum/index.php?a=rssfeed HTTP/1.0", + "wait": 15, + "min_wait": 2, + "max_wait": 3 * 60, + "timer": -1, + "userid": "Arthmoor", + ]) ); + + add_feed("mudmagic-lpc", ([ + "name": "Mud Magic: LPC Lounge", + "ip_port": "67.19.238.52 80", + "host": "www.mudmagic.com", + "req": "GET /rss/boards/26 HTTP/1.0", + "wait": 15, + "min_wait": 2, + "max_wait": 3 * 60, + "timer": -1, + "userid": "MudMagic", + ]) ); + add_feed("mudmagic-staff", ([ + "name": "Mud Magic: Staff Wanted", + "ip_port": "67.19.238.52 80", + "host": "www.mudmagic.com", + "req": "GET /rss/boards/5 HTTP/1.0", + "wait": 15, + "min_wait": 2, + "max_wait": 60, + "timer": -1, + "userid": "MudMagic", + ]) ); + + add_feed("metaplace-news", ([ + "name": "Metaplace.com Developer's Blog", + "ip_port": "66.150.96.119 80", + "host": "feeds.feedburner.com", + "req": "GET /metaplace HTTP/1.0", + "char-encoding": "utf8", + "wait": 15, + "min_wait": 2, + "max_wait": 60, + "timer": -1, + "userid": "Metaplace", + ]) ); + + add_feed("theonion", ([ + "name": "The Onion", + "ip_port": "66.150.96.119 80", + "host": "feeds.theonion.com", + "req": "GET /theonion/daily HTTP/1.0", + "sortBy": "pubDate", + "char-encoding": "utf8", + "wait": 15, + "min_wait": 2, + "max_wait": 24 * 60, + "timer": -1, + "userid": "TheOnion", + ]) ); +} + + +mixed ProcessHTTPResult(int fd) +{ + string * parts; + string * arg_array; + string * temp; + write_file("/tmp/"+Sockets[fd]["name"],Sockets[fd]["result"]); + //parts = explode( results, NOTES_DELIM ); + return 1; +} + +void read_callback( int fd, mixed message ) +{ + Sockets[fd]["result"] += message; +} + +void write_callback( int fd ) +{ +#ifdef _DEBUG + player->eventPrint("Connected!"); +#endif + status = SOCK_CONNECTED; + http_file_found = 0; + sendHTTPGet(); +} + +void close_callback( int fd ) +{ + if( status == SOCK_CONNECTED ) + { + // Process HTML here +#ifdef _DEBUG + player->eventPrint("Connection closed by host."); +#endif + ProcessHTTPResult(fd); + } + if( status == SOCK_CONNECTING ) + { + player->eventPrint("Connection attempt failed."); + } + socket_close( fd ) ; + map_delete(Sockets,fd); + status = SOCK_DISCONNECTED; +} + +void sendHTTPGet() +{ + string str =Feeds[args_list]["req"]+CARRIAGE_RETURN+"\n"+ + "Host: "+Feeds[args_list]["host"]+CARRIAGE_RETURN"\n" + + "User-Agent: RSS_D@" + mud_name() + " " + + mudlib()+ "/" + mudlib_version() +" ("+ query_os_type()+";) "+ + version() + CARRIAGE_RETURN+"\n"+CARRIAGE_RETURN+"\n"; + int result = 0; + results = ""; +#ifdef _DEBUG + player->eventPrint("Sending HTTP get request..." ); +#endif + if( status == SOCK_CONNECTED ) + { + result = socket_write( socket, str ); +#ifdef _DEBUG + player->eventPrint( "HTTP request sent to " + socket + " result = "+result ); +#endif + } +} + +int openHTTPConnection() +{ + + int sock, sc_result; + string error; + status = SOCK_FIND; + + + status = SOCK_CONNECTING; + sock = socket_create( STREAM, "read_callback", "close_callback" ) ; + if (sock < 0) { + switch( sock ) + { + case EEMODENOTSUPP : + error = "Socket mode not supported.\n" ; + break ; + case EESOCKET : + error = "Problem creating socket.\n" ; + break ; + case EESETSOCKOPT : + error = "Problem with setsockopt.\n" ; + break ; + case EENONBLOCK : + error = "Problem with setting non-blocking mode.\n" ; + break ; + case EENOSOCKS : + error = "No more available efun sockets.\n" ; + break ; + case EESECURITY : + error = "Security violation attempted.\n" ; + break ; + default : + error = "Unknown error code: " + sock + ".\n" ; + break ; + } + notify_fail( "Unable to connect, problem with socket_create.\n" + "Reason: " + error ) ; + return 0 ; + } + write("Attempting to connect to "+HTTP_HOST+ " on port "+ HTTP_PORT + "\n"); + sc_result = socket_connect( sock, Feeds[args_list]["ip_port"], + "read_callback", "write_callback" ) ; + if( sc_result != EESUCCESS ) + { + status = SOCK_DISCONNECTED; + notify_fail( "Failed to connect.\n" ) ; + return 0 ; + } + else{ +#ifdef _DEBUG + player->eventPrint( "Socket connecting..." ); +#endif + } + + socket = sock; + Sockets[socket] = ([ "inception" : time(), "name" : args_list, "result" : "" ]); + return 1; +} + +void hostResolved( string address, string resolved, int key ) +{ + if( !resolved ){ +#ifdef _DEBUG + player->eventPrint( "Unable to resolve "+address ); +#endif + return; + } +#ifdef _DEBUG + player->eventPrint( "Resolved "+address+" to "+ resolved ); +#endif + player->eventPrint( "Retrieving updated release notes from: http://www.dead-souls.net\n" ); + openHTTPConnection(); +} + +void resolveHost() +{ + resolve( HTTP_HOST, "hostResolved" ); +} + + +mixed cmd(string args) { + if(args == "list"){ + write("Known feeds: "+implode(keys(Feeds),", ")); + return 1; + } + player = previous_object(); + if(args) args_list = args; + else args_list = "lpmuds-forum"; + rm("/tmp/"+args_list); + openHTTPConnection(); + return 1; +} + +string GetErorMessage() { + return "There was a problem"; +} + +string GetHelp(){ + return "Syntax: rss\n\nwhatever"; +} diff --git a/lib/secure/cmds/creators/showfuns.c b/lib/secure/cmds/creators/showfuns.c new file mode 100644 index 0000000..a8519e6 --- /dev/null +++ b/lib/secure/cmds/creators/showfuns.c @@ -0,0 +1,63 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; +string *arr = ({}); +string *types = ({ "void ", "status ", + "string ", "string \*", "string array ", + "int ", "int *", "int array ", + "object ", "object *", "object array ", + "mapping ", "mapping *", "mapping array ", + "mixed ", "mixed *", "mixed array ", + "float ", "float *", "float array ", + "function ", "function *", "function array " }); + +void create(){ + daemon::create(); +} + +mixed cmd(string str) { + string *lines, *raw_lines; + object ob; + string tmp, content; + mixed *fs; + arr = ({}); + + if( !str ) return "You must specify a file."; + else if(this_player()) str = absolute_path(this_player()->query_cwd(), str); + if( !file_exists(str) ) str += ".c"; + if( !file_exists(str) ) return "File " + str + " not found."; + else if( !(content = read_file(str)) ) + return "Unable to read file " + str + "."; + else tmp = ""; + content = replace_string(content, " *", " array "); + if(!tmp = FUNCTION_D->GetFunctions(str)){ + tmp = ""; + lines = explode(content, "\n"); + ob = load_object(str); + fs = functions(ob); + if(!ob) return "File cannot be loaded."; + else arr = query_local_functions(ob); + raw_lines = filter(lines, (: reverse_memberp($1, types) :) ); + lines = filter(raw_lines, (: reverse_memberp($1, arr) :) ); + foreach(string func in arr){ + foreach(string element in types){ + foreach(string line in lines){ + if(regexp(line, element+func)) { + line = trim(line); + if(!strsrch(line,"/*") || !strsrch(line,"//") || !strsrch(line,"*")) continue; + if(last(line,1) == ";") continue; + if(!grepp(tmp,func)) tmp += line+"\n"; + } + } + } + } + FUNCTION_D->ReceiveFunctionData(str, tmp, stat(str)[0], fs); + } + return tmp; +} + +string GetHelp(){ + return ("Syntax: showfuns <file>\n\n" + "Displays the functions defined in the file."); +} diff --git a/lib/secure/cmds/creators/snoop.c b/lib/secure/cmds/creators/snoop.c new file mode 100644 index 0000000..9c4fe10 --- /dev/null +++ b/lib/secure/cmds/creators/snoop.c @@ -0,0 +1,35 @@ +/* +// The snoop command. +// Daemonized by Buddha (2-19-92) +// Part of the TMI mudlib. + */ + +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +int cmd(string str) { + object ob; + + if( !str || str == "" ) { + write("Snoop whom?\n"); + } + else if(!(ob=find_player(str=lower_case(str)))) + write(str+": no such player.\n"); + else if(str == this_player()->GetKeyName()){ + write("That would be very foolish."); + return 1; + } + else + SNOOP_D->AddWatcher(this_player()->GetKeyName(), str); + write("The snoop daemon has received your request."); + return 1; +} + +string GetHelp(){ + return "Syntax: snoop <user>\n\n" + "Echoes to your screen everything <user> sees or types. " + "To stop snooping, type just \"unsnoop <user>\"\n" + "See also: unsnoop, monitor, unmonitor"; +} diff --git a/lib/secure/cmds/creators/source.c b/lib/secure/cmds/creators/source.c new file mode 100644 index 0000000..0d32304 --- /dev/null +++ b/lib/secure/cmds/creators/source.c @@ -0,0 +1,102 @@ +/* /secure/cmds/creator/source.c + * from the Dead Souls LPC Library + * reads a file and forces you to execute each line as a command + */ + +#include <lib.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + string file, contents,flags,tmpargs; + string *tmplines, *lines = ({}); + int queued, gauged; + + if(!args) { + write("Please specify a file as an argument."); + return 1; + } + if(sscanf(args,"-%s %s",flags, tmpargs) == 2){ + args = tmpargs; + } + else flags = ""; + + if(grepp(flags, "q")){ + queued = 1; + } + + if(grepp(flags, "g")){ + if(query_os_type() != "windows"){ + gauged = 1; + } + } + + if(file_size(args) > 0 ) file = args; + else if(file_size(this_player()->query_cwd()+"/"+args) > 0){ + file = this_player()->query_cwd()+"/"+args; + } + else { + write("That is not a valid file."); + return 1; + } + + if(!strsrch(file,"/secure/scripts/") || + !strsrch(file,user_path(this_player())) ){ + write("Processing "+file+"..."); + } + else { + write(file+" is not in a permitted script directory. Aborting."); + return 1; + } + + contents = read_file(file); + + if(!contents || !sizeof(contents)) { + write("Either the file is unreadable or it is empty."); + return 1; + } + + tmplines = explode(contents,"\n"); + + foreach(string line in tmplines){ + if(!strsrch(line,"title ") || !strsrch(line,"describe ")){ + } + else { + line = replace_string(line,"$N",this_player()->GetKeyName()); + } + if(strsrch(line,"#")) lines += ({ (gauged ? "gauge " + line : line) }); + } + + if(queued){ + foreach( string line in lines ){ + if(line && line != "") write("queuing command: "+line); + this_player()->eventQueueCommand(line); + } + this_player()->eventExecuteQueuedCommands(); + write("Commands queued."); + } + else { + foreach( string line in lines ){ + if(line && line != "") write("sourcing command: "+line); + this_player()->eventForce(line); + } + write("Sourcing complete."); + } + return 1; + +} + +string GetHelp() { + return ("Syntax: source [-gq] <filename>\n\n" + "If <filename> exists and is readable, this command " + "will read each line of that file and force you to " + "execute that line as if you had entered it on the " + "command line. If there is a file called .profile " + "in your home directory, it is automatically executed " + "in this way each time you log in.\n\n" + "To include system load output, use the -g flag.\n\n" + "If a set of commands need to occur with some time between " + "them (for example, to avoid the MAX_COMMANDS_PER_SECOND limit) " + "use the -q flag. For example:\n " + "source -q /secure/scripts/crat2.src"); +} diff --git a/lib/secure/cmds/creators/stupidemote.c b/lib/secure/cmds/creators/stupidemote.c new file mode 100644 index 0000000..4327e9f --- /dev/null +++ b/lib/secure/cmds/creators/stupidemote.c @@ -0,0 +1,124 @@ +/* /secure/cmds/admins/stupidemote.c + * From the Dead Souls Mud Library + * Adds lame emotes + * Created by Descartes of Borg 961214 + * Version: @(#) stupidemote.c 1.4@(#) + * Last modified: 96/12/15 + */ + +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string args){ + string array rules = ({ "", "STR" }); + string array adverbs; + string emote, xtra, prep; + if( !(master()->valid_apply(({ "ASSIST" }))) && + !member_group(this_player(), "EMOTES") ){ + write("You are not admin, nor a member of the EMOTES group."); + return 1; + } + + if( !args || args == "" ) { + return "Add which emote?"; + } + if( sscanf(args, "%s %s", emote, xtra) != 2 ) { + emote = args; + xtra = 0; + } + if( xtra ) { + if( xtra == "LIV" || xtra == "LVS" ) { + prep = 0; + } + else { + string token; + + if( strlen(xtra) < 5 ) { + return "The expression " + xtra + " makes no sense."; + } + prep = xtra[0..<5]; + token = xtra[<3..]; + if( member_array(prep, master()->parse_command_prepos_list()) == + -1 ) { + return "The preposition " + prep + " is not a valid."; + } + if( member_array(token, ({ "LIV", "LVS" })) == -1 ) { + return "The token " + token + " is invalid."; + } + rules = ({ rules..., token }); + } + rules = ({ rules..., xtra, "STR " + xtra, xtra + " STR" }); + } + else { + prep = 0; + } + if( !SOUL_D->AddVerb(emote, capitalize(emote) + " how?") ) { + previous_object()->eventPrint("Failed to create emote."); + return 1; + } + foreach(string rule in rules) { + string msg; + + if( rule == "" ) { + msg = "$agent_name $agent_verb."; + adverbs = 0; + } + else if( rule == "STR" ) { + msg = "$agent_name $agent_verb $adverb."; + adverbs = ({ "-" }); + } + else if( rule == "LIV" || rule == "LVS" || rule == xtra ) { + if( prep ) { + msg = "$agent_name $agent_verb " + prep + " $target_name."; + } + else { + msg = "$agent_name $agent_verb $target_name."; + } + } + else { + if( prep ) { + msg = "$agent_name $agent_verb $adverb " + prep + + " $target_name."; + } + else { + msg = "$agent_name $agent_verb $target_name $adverb."; + } + } + if( adverbs ) { + SOUL_D->AddRule(emote, rule, ({ ({ emote }), msg }), adverbs); + } + else { + SOUL_D->AddRule(emote, rule, ({ ({ emote }), msg })); + } + } + previous_object()->eventPrint("Stupid emote added."); + return 1; +} + +string GetHelp(){ + return ("Syntax: stupidemote <EMOTE> [RULE]\n\n" + "You must be admin or member of the EMOTES group to " + "use this command.\n" + "This command allows you to add the most common kinds of " + "emote straight from the command line. Using the first syntax, " + "You can add a simple, untargetted emote. For example, " + "if you did <stupidemote cheese>, this would create an emote " + "that would allow people to do <cheese> and <cheese adverb> " + "with a message that looks like \"Descartes cheeses.\"\n" + "The second syntax is for targetted emotes. You specify a " + "targetting rule. Targetting rules can be one of the following:\n" + "\t* LIV\n" + "\t* LVS\n" + "\t* preposition LIV\n" + "\t* preposition LVS\n" + "The difference between LIV and LVS just determines whether the " + "emote can be targetted at a single living being or one or more " + "living beings. So, to add the \"smile\" emote, you would " + "do:\n" + "> stupidemote smile at LVS\n" + "and that would give you all the functionality of the \"smile\" " + "emote that exists on this mudlib.\n\n" + "See also: addadverb, addemote, removeadverb, removeemote"); +} diff --git a/lib/secure/cmds/creators/tail.c b/lib/secure/cmds/creators/tail.c new file mode 100644 index 0000000..c880f7f --- /dev/null +++ b/lib/secure/cmds/creators/tail.c @@ -0,0 +1,34 @@ +/* /secure/cmds/creator/tail.c + * from the Foundation II Object Library + * Displays the last screenful of information from a file + * created by Descartes of Borg 950915 + */ + +#include <lib.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + string *lines; + string buff; + int scr, err; + + if( !args ) return "You must specify a file to tail."; + else args = absolute_path(this_player()->query_cwd(), args); + if( !file_exists(args) ) return "File " + args + " not found."; + err = catch(buff = read_file(args)); + if( err || !buff ) return "Unable to tail " + args + "."; + scr = ((this_player()->GetScreen())[1] || 24); + if( scr > 100 ) scr = 100; + if( sizeof(lines = explode(buff, "\n")) > scr ) + buff = implode(lines[<scr..], "\n"); + message("system", buff, this_player()); + return 1; +} + +string GetHelp() { + return ("Syntax: tail <file>\n\n" + "Displays the last lines of the specified " + "file.\n" + "See also: cat, head, more."); +} diff --git a/lib/secure/cmds/creators/trace.c b/lib/secure/cmds/creators/trace.c new file mode 100644 index 0000000..ccae260 --- /dev/null +++ b/lib/secure/cmds/creators/trace.c @@ -0,0 +1,32 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + int x; +#ifdef __TRACE__ + if(!args) args = "0"; + x = atoi(args); + if(!archp(previous_object())) return 0; + trace(x); + write("Set tracing level to "+x+"."); +#endif + return 1; +} + +string GetHelp() { + string ret = ""; +#ifdef __TRACE__ + ret = "Syntax: trace [level]\n\n" + "Displays function call tracing to you. See \"man trace\"" + " for details on tracing levels."; +#else + ret = "This command is disabled.\n" + "See \"man trace\"" + " for details."; +#endif + + return ret; +} + diff --git a/lib/secure/cmds/creators/unsnoop.c b/lib/secure/cmds/creators/unsnoop.c new file mode 100644 index 0000000..63b0f08 --- /dev/null +++ b/lib/secure/cmds/creators/unsnoop.c @@ -0,0 +1,25 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +int cmd(string str) { + object ob; + + if( !str || str == "" ) { + str = "all"; + } + else if(!(ob=find_player(str=lower_case(str))) && str != "all"){ + write(str+": no such player.\n"); + return 1; + } + SNOOP_D->RemoveWatcher(this_player()->GetKeyName(), str); + write("The snoop daemon has received your request."); + return 1; +} + +string GetHelp(){ + return "Syntax: unsnoop <user>\n\n" + "Stops snooping the specified user.\n" + "See also: snoop, monitor, unmonitor"; +} diff --git a/lib/secure/cmds/creators/update.c b/lib/secure/cmds/creators/update.c new file mode 100644 index 0000000..6eefdcb --- /dev/null +++ b/lib/secure/cmds/creators/update.c @@ -0,0 +1,177 @@ +/* /secure/cmds/creator/update.c + * from the Dead Souls LPC Library + * destroys an object then reloads it + * created by Descartes of Borg 950330 + * - added recursive update option (blitz 960711) + * Version: @(#) update.c 1.2@(#) + * Last modified: 96/12/17 + */ + +#include <lib.h> +#include ROOMS_H +#include <daemons.h> + +inherit LIB_DAEMON; +inherit LIB_HELP; + +#define U_RECURSIVE (1 << 1) +#define U_INTERACTIVE (1 << 2) +#define U_AUTOMATED (1 << 3) + +mapping LocationsMap = ([]); + +varargs static int eventUpdate(string args, int flags, string virt); + +static void CacheAndCarry(object *obs){ + if(!sizeof(obs)) return; + foreach(object fellow in obs){ + string ubi = fellow->GetProperty("LastLocation"); + if(ubi) LocationsMap[fellow->GetKeyName()] = ubi; + fellow->eventMove(ROOMS_D->GetVoid(fellow)); + } +} + +static void ReturnAndRelease(object *dudes, string file){ + if(!sizeof(dudes)) return; + if(!file) return; + dudes->eventMove(file); + foreach(object fellow in dudes){ + if(sizeof(LocationsMap[fellow->GetKeyName()])){ + fellow->SetProperty("LastLocation",LocationsMap[fellow->GetKeyName()]); + } + } +} + +static void create() { + SetHelp("Syntax: update [-r] [file list]\n\n" + "Destructs the master copy of the file named " + "and then attempts to reload a new version " + "of it.\n" + "The -r flag attempts to update all " + "files in the target's inheritance tree."); +} + +mixed cmd(string args) { + object *obs, ob, mount; + string *files, *tmpfiles; + mixed tmp; + string file, virt; + int i, flags, err, ret; + if( sizeof(args) ) { + string str = args; + args = ""; + foreach(string foo in explode(str, " ")) { + if(!sizeof(foo)) continue; + switch(foo) { + case "-r" : flags |= U_RECURSIVE; break; + case "-e" : flags |= U_INTERACTIVE; break; + case "-a" : flags |= U_AUTOMATED; break; + default: args += " " + foo; + } + } + } + if( args == "" || !args ) { + if(!this_player()) return "No player."; + ob = room_environment(this_player()); + if( !ob ) return "You have no environment."; + file = base_name(ob); + if(ob->GetVirtual()){ + virt = path_prefix(file); + } + this_player()->eventPrint("Updating environment"); + obs = filter(all_inventory(ob), (: userp :)); + if(mount) obs += ({ mount }); + if( sizeof(obs) ) CacheAndCarry(obs); + err = catch( ret = eventUpdate(file, flags, virt) ); + if( err || !ret ) { + obs->eventPrint("You are thrown into the void as your " + "surroundings violently destruct."); + return "Error in reloading environment."; + } + obs = filter(obs, (: $1 :)); + if( sizeof(obs) ) ReturnAndRelease(obs, file); + return 1; + } + if(this_player()){ + tmpfiles = map(explode(args, " "), + function(string x) { + string tmp = this_player()->query_cwd(); + if( x[<2..] != ".c" ) x = x + ".c"; + return absolute_path(tmp, x); + }); + tmpfiles = map(tmpfiles, + (: ((file_size($1) == -2) ? + (($1[<1] == '/') ? ($1 + "*.c") : ($1 + "/*.c")) : $1) + :)); + i = sizeof(tmpfiles); + files = ({}); + while(i--) { + if( sizeof(tmp = wild_card(tmpfiles[i])) ) + files += tmp; + else { + this_player()->eventPrint(tmpfiles[i] + ": File not found."); + } + } + i = sizeof(files); + while(i--) eventUpdate(files[i], flags); + } + return 1; +} + +varargs static int eventUpdate(string args, int flags, string virt) { + object ob; + string tmp; + + if( flags & U_RECURSIVE ) { + string *ancestors; + int i; + + if( !eventUpdate(args, flags ^ U_RECURSIVE) ) return 0; + if( !(ob = find_object(args)) ) return 0; + ancestors = deep_inherit_list(ob); + if(this_player() && (flags & U_RECURSIVE) && !(flags & U_AUTOMATED)) + this_player()->eventPrint("(%^CYAN%^Recursive " + "update: " + args + "%^RESET%^)\n"); + i = sizeof(ancestors); + while(i--) if( !eventUpdate(ancestors[i], flags ^ U_RECURSIVE) ) { + if(this_player()) + this_player()->eventPrint("Recursive update failed."); + return 0; + } + } + if( args[<2..] == ".c" ) args = args[0..<3]; + if(virt){ + object virtual = find_object(virt); + if(virtual) virtual->eventDestruct(); + if(virtual) destruct(virtual); + } + ob = find_object(args); + if(!ob) ob = load_object(args); + if( ob ) { + if(this_player() && inherits(LIB_ROOM,ob)){ + string coords = ROOMS_D->GetCoordinates(ob); + MAP_D->RemoveCache(coords); + } + if( tmp = catch( ob->eventDestruct()) && this_player() ) + this_player()->eventPrint(args + ": error in eventDestruct()"); + if( ob ) destruct(ob); + if( ob && this_player()) + this_player()->eventPrint(args + ": Failed to destruct old object."); + } + if( args == base_name(this_object()) && this_player() ) { + this_player()->eventPrint("Cannot reload update after destruct.\n" + "It will be reloaded at next reference."); + return 0; + } + if(!sizeof(args)){ + write("Error updating. Mojo meditation 8675309."); + return 1; + } + tmp = catch(call_other(args, "???")); + if(this_player() && !(flags & U_AUTOMATED) ){ + if( !tmp ) + this_player()->eventPrint(args + ": Ok"); + else this_player()->eventPrint(args + ": Error in update\n" + tmp); + } + return 1; +} diff --git a/lib/secure/cmds/creators/variables.c b/lib/secure/cmds/creators/variables.c new file mode 100644 index 0000000..e6854a5 --- /dev/null +++ b/lib/secure/cmds/creators/variables.c @@ -0,0 +1,50 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +string *ret = ({}); + +string GetHelp(); + +int cmd(string str) { + object ob; + ret = ({}); + + if(!str || str == ""){ + write(GetHelp()); + return 1; + } + + ob = get_object(str); + + if(!ob){ + string path = this_player()->query_cwd()+"/"; + if(last(str,2) != ".c") str += ".c"; + if(file_exists(str)) ob = load_object(str); + else if(file_exists(path+str)) ob = load_object(path+str); + } + + if(!ob){ + write(str+" not found."); + return 1; + } + + filter( variables(ob,1), (: ret += ({ $1[1] + " " + $1[0] }) :) ); + + ret = sort_array(ret, 1); + + write("List of variables for "+identify(ob)+": "); + this_player()->eventPage(ret); + + return 1; +} + +string GetHelp(){ + return ("Syntax: variables <object or file>\n\n" + "Lists the names and type of variables in the named " + "object or file.\n" + "Examples: \n" + "variables fighter\n" + "variables workroom.c"); +} diff --git a/lib/secure/cmds/creators/wget.c b/lib/secure/cmds/creators/wget.c new file mode 100644 index 0000000..8fccb02 --- /dev/null +++ b/lib/secure/cmds/creators/wget.c @@ -0,0 +1,42 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mapping FilesMap = ([]); + +varargs int cmd(string str){ + object wget = new(WGET_D, this_object()); + if(!FilesMap) FilesMap = ([]); + write("Requesting url: "+str); + FilesMap[wget] = this_player(); + wget->eventGet(str); + return 1; +} + +varargs mixed eventReceiveWebData(string content, string file){ + object wget = previous_object(); + object who; + string savefile; + if(!FilesMap[wget] || !(who = FilesMap[wget])){ + map_delete(FilesMap, wget); + return 1; + } + savefile = user_path(who)+last_string_element(file,"/"); + who->eventPrint("File received: "+file+" , saving to: "+savefile); + write_file(savefile,content,1); + return 1; +} + +string GetHelp(){ + return "Syntax: wget <url>\n\n" + "Attempts to download internet content to your home directory. " + "Examples:\n" + "wget http://dead-souls.net/RELEASE_NOTES\n" + "wget http://149.152.218.102/RELEASE_NOTES -n dead-souls.net\n" + "The second syntax may be necessary if your mud does not use name " + "resolution and the target wbesite uses virtual hosts.\n" + "NOTE 1: This command is for text files only!\n" + "NOTE 2: You may have to manually remove some header information.\n" + "See also: resolve, rowsdower"; +} diff --git a/lib/secure/cmds/creators/which.c b/lib/secure/cmds/creators/which.c new file mode 100644 index 0000000..e4af72c --- /dev/null +++ b/lib/secure/cmds/creators/which.c @@ -0,0 +1,64 @@ +/* /cmds/creator/which.c + * From the Dead Souls Mud Library + * gives you a list of directories in which a command may be found + * created by Descartes of Borg 950913 + * Version: @(#) which.c 1.2@(#) + * Last modified: 96/10/08 + */ + +#include <lib.h> +#include <daemons.h> +#include <message_class.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + string array dirs; + mixed *aa; + string dir, msg = "", ret; + 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 dirs = CMD_D->GetPaths(args); + if(sizeof(dirs)){ + msg += args + ":"; + foreach(dir in dirs) { + if(isverb) msg += "\n\t" + dir; + else msg += "\n\t" + dir + "/" + args + ".c"; + } + } + aa = filter(this_player()->GetCommands(), (: $1[0] == $(args) :) ); + if(sizeof(aa)){ + msg += "\n"; + msg += args + " is an add_action() defined in "+identify(aa[0][2]); + } + ret = this_player()->GetAlias(args); + if(ret){ + msg += "\n"+ args + " is an alias that expands to: "+ret; + } + if( (ret = this_player()->GetXverb(args)) ){ + msg += "\n"+ args + " is an xverb that expands to: "+ret; + } + if(member_array(args, SOUL_D->GetEmotes()) != -1){ + msg += "\n"+ args + " is an emote, or 'feeling'."; + } + if(!sizeof(msg)) msg = args +": not found."; + previous_object()->eventPrint(msg, MSG_SYSTEM); + return 1; +} + +string GetHelp() { + return ("Syntax: which [command]\n\n" + "Gives you a listing of all locations in which a command " + "object may be found for you.\n" + "See also: help, man, help"); +} diff --git a/lib/secure/cmds/players/afk.c b/lib/secure/cmds/players/afk.c new file mode 100644 index 0000000..95c6fdd --- /dev/null +++ b/lib/secure/cmds/players/afk.c @@ -0,0 +1,32 @@ +/* /secure/cmds/player/afk.c + * From the Frontiers LPC library + * created by Cratylus, 17Nov96 + */ + +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + int afk; + afk = this_player()->GetProperty("afk"); + if(afk){ + afk = 0; + message("system", "You are back.", this_player() ); + } + else { + afk = 1; + message("system", "You are away from your keyboard.", this_player() ); + } + this_player()->SetProperty("afk", afk); + if(find_object(INSTANCES_D)){ + INSTANCES_D->SendWhoUpdate(this_player()->GetKeyName()); + } + return 1; +} + +string GetHelp() { + return ("Syntax: afk\n\n" + "Toggles your 'away from keyboard' flag."); +} diff --git a/lib/secure/cmds/players/bug.c b/lib/secure/cmds/players/bug.c new file mode 100644 index 0000000..d748ec2 --- /dev/null +++ b/lib/secure/cmds/players/bug.c @@ -0,0 +1,509 @@ +/* /secure/cmds/player/bug.c + * from the Dead Souls Object Library + * the command interface to the NM IV bug tracking system + * created by Descartes of Borg 950925 + */ + +#include <lib.h> +#include <daemons.h> +#include <message_class.h> + +inherit LIB_DAEMON; + +void PreMenu(string str); +static varargs void MainMenu(string str); +static void Assign(string *args); +static void EndAssign(string *args); +static void Complete(string *args); +void EndComplete(int x); +static void Delete(string *args); +static void Report(string *args); +static void EndReport(string type, string data, string file); +varargs static void View(string *args, int print); +static string GetBugString(int id, mapping bugs); + +static void create() { + daemon::create(); + SetNoClean(1); +} + +mixed cmd(string str) { + string *args; + int i; + + if( !str || str == "" ) args = ({}); + else args = explode(str, " "); + if( !(i = sizeof(args)) ) MainMenu(); + else { + string opt; + + opt = args[0]; + if( i == 1 ) args = ({}); + else args = args[1..]; + switch(opt) { + case "-a": Assign(args); break; + case "-c": Complete(args); break; + case "-d": Delete(args); break; + case "-r": Report(args); break; + case "-p": View(args, 1); break; + case "-v": View(args); break; + default: return "To report a bug, use \"bug -r\"."; + } + } + return 1; +} + +void PreMenu(string str) { + if( str == "q" ) { + message("system", "Exiting the bug tracking system.", this_player()); + return; + } + MainMenu(); +} + +varargs static void MainMenu(string str) { + string tmp; + int cols; + + if( str && str != "" ) { + switch(str) { + case "a": Assign(({})); return; + case "c": Complete(({})); return; + case "d": Delete(({})); return; + case "r": Report(({})); return; + case "p": View(({}), 1); return; + case "v": View(({})); return; + case "q": + message("system", "Exiting the bug tracking system.", + this_player()); + return; + } + } + cols = ((int *)this_player()->GetScreen())[0] || 80; + tmp = center("Dead Souls Bug Tracking System", cols) + "\n\n"; + if( creatorp(this_player()) ) { + tmp += "a)ssign bug to creator\n"; + tmp += "c)omplete work on a bug\n"; + } + if( archp(this_player()) ) tmp += "d)elete a bug from the system\n"; + tmp += "r)eport a new bug to the system\n"; + tmp += "v)iew an existing bug or a list of existing bugs\n"; + tmp += "\nq)uit the bug tracking system\n"; + message("system", tmp, this_player()); + message("prompt", "Enter your choice: ", this_player()); + input_to( (: MainMenu :) ); +} + +static void Assign(string *args) { + int i; + + if( !creatorp(this_player()) ) { + message("system", "Only creators may use the -a option.", + this_player()); + return; + } + if( !(i = sizeof(args)) ) { + message("prompt", "Enter in the bug ID: ", this_player()); + input_to(function(string str) { Assign(({ str })); }); + return; + } + else if( i == 1 ) { + int x; + + if( (x = to_int(args[0])) > 0 ) { /* assume a bug id for now */ + if( !archp(this_player()) ) + Assign( ({ args[0], this_player()->GetCapName() }) ); + else { + message("prompt", "Enter the creator to assign it to [" + + this_player()->GetCapName() + "]: ", + this_player()); + input_to(function(string str, string id) { + if( !str || str == "" ) + str = this_player()->GetCapName(); + Assign( ({ str, id }) ); + }, args[0]); + } + return; + } + else { + message("prompt", "Enter in the bug ID to assign to " + + capitalize(args[0]) + ": ", this_player()); + input_to(function(string id, string str) { + Assign( ({ id, str }) ); + }, args[0]); + return; + } + } + else if( i == 2 ) { + message("prompt", "Do you wish to comment? [n]: ", this_player()); + input_to(function(string str, string *args) { + if( !str || str == "" ) str = "n"; + else str = lower_case(str[0..0]); + if( str == "y" ) { + string file; + + message("system", "Enter comments on the bug...", + this_player()); + file = DIR_TMP "/" + this_player()->GetKeyName(); + rm(file); + this_player()->eventEdit(file, (: EndAssign, args :)); + return; + } + else Assign(args + ({ "" })); + }, args); + return; + } + else { + string who, comments; + int x; + + if( (x = to_int(args[0])) < 1 ) { + who = args[0]; + if( (x = to_int(args[1])) < 1 ) { + message("system", "Invalid bug ID " + x + ".", this_player()); + message("prompt", "Hit return: ", this_player()); + input_to( (: PreMenu :) ); + return; + } + } + else who = args[1]; + comments = args[2]; + if( !archp(this_player()) && (convert_name(who) != + this_player()->GetKeyName()) ) { + message("system", "Only arches may assign bugs to other people.", + this_player()); + message("prompt", "Hit return: ", this_player()); + input_to( (: PreMenu :) ); + return; + } + if( !user_exists(convert_name(who)) ) { + message("system", "No such creator: " + who, this_player()); + message("prompt", "Hit return: ", this_player()); + input_to( (: PreMenu :) ); + return; + } + if( !(BUGS_D->eventAssign(x, who)) ) { + message("system", "Failed to assign bug.", this_player()); + return; + } + if( comments != "" ) BUGS_D->AddComment(x, comments); + message("system", "Assigned bug to " + who + ".", this_player()); + return; + } +} + +static void EndAssign(string *args) { + string file, contents; + + file = DIR_TMP "/" + this_player()->GetKeyName(); + contents = (read_file(file) || ""); + rm(file); + Assign(args + ({ contents })); +} + +static void Complete(string *args) { + string file; + int x; + + if( !sizeof(args) ) { + message("prompt", "Enter the bug ID: ", this_player()); + input_to(function(string str) { Complete( ({ str }) ); }); + return; + } + else if( !creatorp(this_player()) ) { + message("system", "Invalid command.", this_player()); + message("prompt", "Hit return: ", this_player()); + input_to( (: PreMenu :) ); + return; + } + else if( (x = to_int(args[0])) < 1 ) { + message("system", "Invalid bug ID.", this_player()); + message("prompt", "Hit return: ", this_player()); + input_to( (: PreMenu :) ); + return; + } + message("system", "Enter in your comments:", this_player()); + file = DIR_TMP "/" + this_player()->GetKeyName(); + if( file_exists(file) ) rm(file); + this_player()->eventEdit(file, (: EndComplete, x :)); +} + +void EndComplete(int x) { + string file, stuff; + + if( previous_object() != this_player(1) ) return; + file = DIR_TMP "/" + this_player()->GetKeyName(); + if( !(stuff = read_file(file)) ) { + message("system", "Edit aborted.", this_player()); + rm(file); + return; + } + rm(file); + if( !(BUGS_D->eventComplete(x, stuff)) ) { + message("system", "Failed to set the bug completed.", this_player()); + return; + } + message("system", "Bug marked completed!", this_player()); +} + +static void Delete(string *args) { + if( !archp(this_player()) ) { + message("system","You must be an arch to delete bugs.", this_player()); + return; + } + if( !sizeof(args) ) { + message("prompt", "Delete which bug? ", this_player()); + input_to(function(string str) { Delete( ({ str }) ); }); + return; + } + else { + int x; + + if( (x = to_int(args[0])) < 1 ) + message("system", "Invalid bug ID.", this_player()); + else if( !(BUGS_D->eventDelete(x)) ) + message("system", "Delete failed.", this_player()); + else message("system", "Deletion succeeded.", this_player()); + return; + } +} + +static void Report(string *args) { + if( archp(this_player()) && sizeof(args) ) { + string data; + string bug; + int x; + + data = "Room: " + file_name(environment(this_player())); + bug = implode(args, " "); + if( x = BUGS_D->eventReport(this_player()->GetCapName(), + "approval", bug, data) ) { + BUGS_D->eventAssign(x, query_privs(environment(this_player()))); + message("system", "Bug reported.", this_player()); + return; + } + else { + message("system", "Error in reporting bug.", this_player()); + return; + } + } + else EndReport(0, "Room: " + file_name(environment(this_player())), 0); +} + +static void EndReport(string type, string data, string file) { + string tmp; + int x; + + if( !type ) { + message("system", "Choose a bug type from among the following:\n", + this_player()); + message("system", "\tidea (some nifty idea to add to the game)", + this_player()); + message("system", "\ttypo (misspelling, lexigraphical weirdness)", + this_player()); + message("system", "\tunexplained behaviour (something " + "contrary to how you would expect it)", this_player()); + message("system", "\truntime (one of those nasty error messages)\n", + this_player()); + message("system", "\tother\n", this_player()); + message("prompt", "Enter type: ", this_player()); + input_to( (: EndReport :), data, 0); + return; + } + if( !file ) { + file = DIR_TMP "/" + this_player()->GetKeyName(); + rm(file); + message("system", "Enter in a description of the bug. When done, " + "enter a period on a line by itself.", this_player()); + this_player()->eventEdit(file, (: EndReport, type, data, file :)); + return; + } + if( !(tmp = read_file(file)) ) { + message("system", "Bug report aborted.", this_player()); + rm(file); + return; + } + rm(file); + if( type == "runtime" ) { + mapping last_error; + + if( last_error = this_player()->GetLastError() ) + data += "\n" + master()->standard_trace(last_error) + "\n"; + } + if( !(x = BUGS_D->eventReport(this_player()->GetCapName(), + type, tmp, data)) ) { + message("system", "Bug report failed.", this_player()); + return; + } + message("system", "Bug reported, thank you! Your tracking id is " + + x + ".", this_player()); +} + +varargs static void View(string *args, int print) { + mapping bugs; + function f; + + f = function() { + message("prompt", "\nHit return: ", this_player()); + input_to( (: PreMenu :) ); + }; + if( !sizeof(args) ) { + message("system", "View:\n\t1) all bugs\n" + "\t2) unassigned bugs only\n" + "\t3) assigned bugs only\n" + "\t4) completed bugs only\n", this_player()); + if( creatorp(this_player()) ) + message("prompt", "Enter a choice [3]: " , this_player()); + else message("prompt", "Enter a choice [1]: ", this_player()); + input_to(function(string str, string it_sucks, int print) { + if( !str || str == "" ) { + if( creatorp(this_player()) ) str = "3"; + else str = "1"; + } + if( str < "1" || str > "4" ) { + message("system", "Invalid selection", this_player()); + message("prompt", "Hit return: ", this_player()); + input_to( (: PreMenu :) ); + return; + } + View( ({ str }), print ); + }, "", print); + return; + } + else if( sizeof(args) == 1 && !creatorp(this_player()) ) { + mapping bug; + string tmp = ""; + int bug_id; + + bugs = BUGS_D->GetBugs(); + foreach( bug_id, bug in bugs ) { + if( bug["who"] != this_player()->GetCapName() ) + continue; + if( args[0] == "1" || (args[0] == "2" && !bug["assigned"]) || + (args[0] == "3" && bug["assigned"] && !bug["date fixed"]) || + (args[0] == "4" && bug["date fixed"]) ) + tmp += GetBugString(bug_id, bugs) + "\n*****\n\n"; + } + if( tmp == "" ) { + message("system", "No bugs meet your query criteria.", + this_player()); + message("prompt", "Hit return: ", this_player()); + input_to( (: PreMenu :) ); + return; + } + this_player()->eventPage(explode(tmp, "\n"), MSG_SYSTEM, f); + return; + } + else if( sizeof(args) == 1 ) { + message("system", "View:\n\t1) all bugs\n" + "\t2) bugs assigned to me\n" + "\t3) bugs reported by me\n", this_player()); + message("prompt", "Enter choice [2]: ", this_player()); + input_to(function(string str, string one, int print) { + if( !str || str == "" ) str = "2"; + else if( str < "1" || str > "3" ) { + message("system", "Invalid selection.", this_player()); + message("prompt", "Hit return: ", this_player()); + input_to( (: PreMenu :) ); + return; + } + View( ({ one, str }), print ); + }, args[0], print); + return; + } + else { + mapping bug; + string nom, tmp = ""; + int bug_id; + + nom = this_player()->GetKeyName(); + bugs = BUGS_D->GetBugs(); + if( !creatorp(this_player()) ) { + View( ({ args[0] }), print ); + return; + } + else foreach(bug_id, bug in bugs) { + string opt1, opt2; + + opt1 = args[0]; + opt2 = args[1]; + if( opt1 == "1" && opt2 == "1" ) + tmp += GetBugString(bug_id, bugs) + "\n*****\n\n"; + else { + if( opt2 == "2" && (!bug["assigned"] || + convert_name(bug["assigned"]) != nom) ) + continue; + else if(opt2 == "3" && convert_name(bug["who"]) != nom ) + continue; + if( opt1 == "2" && !bug["assigned"] ) + tmp += GetBugString(bug_id, bugs) + "\n*****\n\n"; + else if( opt1 == "3" && bug["assigned"] && !bug["date fixed"] ) + tmp += GetBugString(bug_id, bugs) + "\n*****\n\n"; + else if( opt1 == "4" && bug["date fixed"] ) + tmp += GetBugString(bug_id, bugs) + "\n*****\n\n"; + } + } + if( tmp == "" ) { + message("system", "No bugs match your query.", this_player()); + message("prompt", "Hit return: ", this_player()); + input_to( (: PreMenu :) ); + return; + } + if( print && creatorp(this_player()) ) { + string file; + + rm(file = user_path(this_player()->GetKeyName()) + "bugs"); + write_file(file, strip_colours(tmp)); + } + else this_player()->eventPage(explode(tmp, "\n"), MSG_SYSTEM, f); + return; + } +} + +static string GetBugString(int id, mapping bugs) { + string tmp; + + tmp = "%^YELLOW%^Bug ID:%^RESET%^ " + id + "\n"; + tmp += "%^YELLOW%^Reported by:%^RESET%^ " + + bugs[id]["who"] + "\n"; + if( bugs[id]["assigned"] ) { + tmp += "%^YELLOW%^Status: %^RESET%^"; + if( !bugs[id]["date fixed"] ) + tmp += "assigned to " + bugs[id]["assigned"] + "\n"; + else tmp += "completed " + ctime(bugs[id]["date fixed"]) + "\n"; + } + else tmp += "%^YELLOW%^Status:%^RESET%^ unassigned\n"; + tmp += "%^YELLOW%^Type:%^RESET%^ " + bugs[id]["type"] + "\n"; + if( bugs[id]["date fixed"] ) + tmp += "%^YELLOW%^Notes:%^RESET%^\n" + bugs[id]["resolution"] + "\n"; + if( creatorp(this_player()) ) + tmp += "\n%^YELLOW%^Creator info:%^RESET%^\n" + bugs[id]["data"] + "\n"; + tmp += "\n%^YELLOW%^Bug info:%^RESET%^\n" + bugs[id]["bug"] + "\n"; + return tmp; +} + +string GetHelp(){ + string tmp; + + tmp = "Syntax: bug\n"; + if( creatorp(this_player()) ) { + tmp += " bug -a <BUG_ID CREATOR>\n"; + tmp += " bug -c <BUG_ID>\n"; + } + if( archp(this_player()) ) tmp += " bug -d <BUG_ID>\n"; + tmp += " bug -r\n bug -v [1-4] [1-3]\n\n"; + tmp += "The command interface to the Dead Souls Bug Tracking System. " + "You can simply type \"bug\" and be prompted for further options, " + "or, if you understand the system, pass command line arguments " + "to the bug command to make things go faster. This system allows " + "players to report bugs or ideas and periodically see what has " + "been done about their report. It also allows creators a way " + "to track bugs which have been reported to them and give feedback " + "to the players who have reported them. It gives admins a way to " + "track and assign mudlib level bugs. The options above correspond " + "to assigning, completing, deleting, reporting, and viewing bugs " + "respectively.\n" + "See also: praise"; + return tmp; +} + diff --git a/lib/secure/cmds/players/chfn.c b/lib/secure/cmds/players/chfn.c new file mode 100644 index 0000000..3409c6a --- /dev/null +++ b/lib/secure/cmds/players/chfn.c @@ -0,0 +1,90 @@ +/* /secure/cmds/player/chfn.c + * from the Foundation II LPC Library + * just when you thought you were safe from lisp + * created by Descartes of Borg 950517 + */ + +#include <lib.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + function f; + string rname; + + message("system", "Changing user information for " + + previous_object()->GetCapName() + ": ", previous_object()); + rname = previous_object()->GetRealName(); + message("prompt", "Real name [" + rname + "] ", previous_object()); + f = function(string str, string old, object ob) { + function g; + + if( !str || str == "" ) str = old; + if( str != old ) { + ob->SetRealName(str); + message("system", "Real name changed to " + str, ob); + } + else message("system", "Real name unchanged.", ob); + str = ob->GetEmail(); + message("prompt", "Email (prepend # to make admin only) [" + + str + "] ", ob); + g = function(string str, string old, object ob) { + function h; + + if( !str || str == "" ) str = old; + if( str != old ) { + string a, b; + + if( sscanf(str, "%s@%s", a, b) != 2 ) { + message("system", "Invalid email.", ob); + return; + } + ob->SetEmail(str); + message("system", "Email changed to " + str, ob); + } + else message("system", "Email unchanged.", ob); + str = (ob->GetWebPage() || ""); + message("prompt", "Home Page [" + str + "]: ", ob); + h = function(string str, object who) { + if( str == "" ) { + str = 0; + } + else if( str ) { + if( strlen(str) < 5 ) { + str = "http://" + str; + } + else { + if( str[0..3] != "http" ) { + str = "http://" + str; + } + } + } + if( !str ) { + message("system", "Home page unchanged.", who); + } + else { + who->SetWebPage(str); + message("system", "Home page changed.", who); + this_player()->save_player(this_player()->GetKeyName()); + update("/secure/daemon/finger"); + } + }; + input_to(h, 0, ob); + this_player()->save_player(this_player()->GetKeyName()); + update("/secure/daemon/finger"); + }; + input_to(g, 0, str, ob); + this_player()->save_player(this_player()->GetKeyName()); + update("/secure/daemon/finger"); + }; + input_to(f, "" + rname, previous_object()); + this_player()->save_player(this_player()->GetKeyName()); + update("/secure/daemon/finger"); + return 1; +} + +string GetHelp(){ + return ("Syntax: chfn\n\n" + "Allows you to change your finger information.\n" + "See also: passwd, finger"); +} diff --git a/lib/secure/cmds/players/finger.c b/lib/secure/cmds/players/finger.c new file mode 100644 index 0000000..a7762dd --- /dev/null +++ b/lib/secure/cmds/players/finger.c @@ -0,0 +1,62 @@ +#include <daemons.h> +#include <lib.h> +#include <socket.h> +#include <message_class.h> + +inherit LIB_DAEMON; + +void remote_finger(object me, string target, string mud); + +mixed cmd(string str) { + string wer, wo; + + if(!str) return "Finger whom?"; + + if(!str) { + string ret; + + ret = FINGER_D->GetFinger(0); + if( !ret ) return "General finger appears broken."; + this_player()->eventPage(explode(ret, "\n"), MSG_SYSTEM); + return 1; + } + else if(sscanf(str, "%s@%s", wer, wo)) + remote_finger(this_player(), (wer ? wer : ""), wo); + else { + string ret; + + ret = FINGER_D->GetFinger(convert_name(str)); + if( !ret ) return "Finger of "+ capitalize(str) + " failed."; + this_player()->eventPage(explode(ret, "\n"), MSG_SYSTEM); + } + return 1; +} + +void remote_finger(object ob, string who, string mud) { + // If/Else If/Else construct didn't work for some strange reason + // when I tried to add the IMC2 finger, so i just split it up with a return; + // Shadyman, 2006-Sept-14 + + if ( mud = INTERMUD_D->GetMudName(mud) ) { + SERVICES_D->eventSendFingerRequest(convert_name(who), mud); + message("system", "Remote finger sent to " + mud + ".", this_player()); + return; + } + + if ( mud = IMC2_D->find_mud(mud) ) { + IMC2_D->finger(who+"@"+mud, ob); + message("system", "Remote finger sent to " + mud + " on the IMC2 network.", this_player()); + return; + } + + message("system", mud_name() + " is blissfully unaware of that mud on either the I3 or IMC2 networks.", this_player()); +} + +string GetHelp(){ + return "Syntax: finger [[player]@[mud]]\n\n" + "Gives you information about a player named. If you do not mention " + "a particular mud, it searches for that player info here. " + " If you mention another mud but no player, " + "it may give you general info on the players on that mud.\n" + "See also: mail, rwho, tell, users, who"; +} diff --git a/lib/secure/cmds/players/hist.c b/lib/secure/cmds/players/hist.c new file mode 100644 index 0000000..cf51d16 --- /dev/null +++ b/lib/secure/cmds/players/hist.c @@ -0,0 +1,121 @@ +#include <lib.h> +#include <daemons.h> +#include <commands.h> +#include <message_class.h> + +inherit LIB_DAEMON; +string gfile; + +varargs string *Prettify(string *arr, string chan){ + string *ret = ({}); + string colorchan = "", stamp, mess, junk, remotechan; + chan = CHAT_D->GetLocalChannel(chan); + remotechan = CHAT_D->GetRemoteChannel(chan); + if(!chan || !(CHAT_D->GetTag(chan))){ + if(!(colorchan = CHAT_D->GetTag(remotechan))){ + colorchan = "%^B_BLACK%^YELLOW%^<"+chan+">%^RESET%^"; + } + } + else colorchan += "<" + chan + ">%^RESET%^"; + + foreach(string line in arr){ + int i = sscanf(line,"%s.%s]%s", junk, stamp, mess); + if(i != 3) continue; + stamp = replace_string(stamp, ".", "/", 1); + stamp = replace_string(stamp, ".", ":", 1); + mess = replace_string(mess, "<"+ chan +">", colorchan, 1); + mess = replace_string(mess, "<"+ remotechan +">", colorchan, 1); + ret += ({ stamp + " " + mess }); + } + return ret; +} + +mixed cmd(string args) { + string *talks, *ret = ({}); + int i, lines; + string log_contents, location; + gfile = ""; + + if(!args){ + this_player()->eventPrint("Syntax: <hist [channel | say]>"); + return 1; + } + + this_player()->eventPrint("Retrieving history...\n"); + + if(!strsrch(args, "tell")){ + load_object(CMD_TELL)->cmd("hist"); + return 1; + } + + if(!LOG_REMOTE_CHANS && + member_array(args, CHAT_D->GetRemoteChannels(1)) != -1){ + ret = CHAT_D->cmdLast(args); + if(sizeof(ret)) return ret; + } + + if(!LOG_LOCAL_CHANS && + member_array(args, CHAT_D->GetRemoteChannels()) == -1){ + ret = CHAT_D->cmdLast(args); + if(sizeof(ret)) return ret; + } + + i = sscanf(args,"%s %d", gfile, lines); + if(i != 2){ + lines = 20; + gfile = args; + } + talks = this_player()->GetTalkHistTypes(); + if(talks && member_array(gfile, talks) != -1){ + string ret2 = "Your "+gfile+" history: \n\n"; + ret2 += implode(this_player()->GetTalkHistory(gfile),"\n"); + print_long_string(this_player(), ret2); + return 1; + } + + if(!CHAT_D->CanListen(this_player(), gfile)){ + return "You do not have privileges to: "+gfile; + } + if(!CHAT_D->GetListening(this_player(), gfile)){ + return "You are not listening to channel: "+gfile; + } + if(gfile == "admin"){ + location = "/secure/log/admin"; + } + else { + location = DIR_CHANNEL_LOGS +"/"+ gfile; + } + if( !(log_contents = read_file(location)) ){ + return CHAT_D->cmdLast(gfile); + } + if(lines > 100 && !creatorp(this_player())) lines = 100; + if(sizeof(ret = (Prettify(explode(log_contents,"\n"), gfile))) < lines){ + string *archive_array; + archive_array = (get_dir(DIR_CHANNEL_LOGS +"/archive/") || ({}) ); + archive_array = filter(archive_array, (: !strsrch($1,gfile) :) ); + archive_array = sort_array(archive_array, -1); + foreach(string element in archive_array){ + string junk1, tmp; + if(sizeof(ret) >= lines) break; + if(sscanf(element,"%s%*d.%*d.%*d-%*d.%*d", junk1) != 6) continue; + if(truncate(junk1,1) != gfile) continue; + tmp = read_file(DIR_CHANNEL_LOGS +"/archive/"+element); + if(!tmp) continue; + ret = Prettify(explode(tmp,"\n"), gfile)+ret; + } + } + ret = ret[<lines..]; + this_player()->eventPage(ret, "system"); + return 1; +} + +string GetHelp(){ + string ret = "Syntax: hist <CHANNEL> [number]\n" + " hist [ say | whisper | tell | yell | shout ]\n\n" + "Gives you the backscroll of the specified communication.\n"; + if(!LOG_REMOTE_CHANS){ + ret += "Note that remote channel logging is not enabled on " + "this mud, so hist for intermud channels will not work."; + } + return ret; +} diff --git a/lib/secure/cmds/players/history.c b/lib/secure/cmds/players/history.c new file mode 100644 index 0000000..2dc1963 --- /dev/null +++ b/lib/secure/cmds/players/history.c @@ -0,0 +1,69 @@ +/* /secure/cmds/players/history.c + * from the Dead Souls Object Library + * command to view history information + * created by Descartes of Borg 960511 + */ + +#include <lib.h> +#include <message_class.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + int x; + object player = this_player(); + if(!player) return 0; + if(player->GetForced()) return 0; + + if( x = to_int(args) ) { + if( previous_object()->SetHistorySize(x) != x ) { + if( x < MIN_HISTORY_SIZE ) + return "History size must be at least " + MIN_HISTORY_SIZE + "."; + else if( x > MAX_HISTORY_SIZE ) + return "History size can be no larger than " + MAX_HISTORY_SIZE + + "."; + else return "Invalid history size."; + } + else { + previous_object()->eventPrint("History size set to: " + x); + } + } + else { + string array arr, tmp = ({}); + mapping history; + int cmd_num, i; + + history = this_player()->GetCommandHist(); + cmd_num = sizeof(history); + foreach(mixed key, mixed cmd in history) { + if( !cmd ) continue; + tmp += ({ sprintf("%:-5d %s", key, cmd) }); + } + previous_object()->eventPage(tmp, MSG_SYSTEM); + } + return 1; +} + +string GetHelp(string str) { + return ("Syntax: history\n" + " history <SIZE>\n\n" + "This command lets you check your command history. A command " + "history is kept for the commands you enter, allowing you " + "quick access to execute or modify previous commands. The size " + "of your command buffer defaults to " + MIN_HISTORY_SIZE + " but " + "may be expanded to " + MAX_HISTORY_SIZE + " if you desire. You " + "can change the size of your history buffer by passing the size " + "as an argument to the history command. Without arguments, the " + "command simply prints the commands in your history buffer.\n\n" + "The following syntaxes are available for accessing previously " + "issued commands:\n" + "\t!!\t\texecute the last command\n" + "\t!#\t\texecute command number #\n" + "\t!-#\t\texecute #th command prior\n" + "\t^old^new\treplace 'old' with 'new' in last command and " + "execute\n" + "\t!#^old^new\tsame as above, except for command number #\n" + "\t!#s/old/new/g\tsame as above, except replacing all " + "occurrences of 'old'\n\n" + "See also: alias, nickname"); +} diff --git a/lib/secure/cmds/players/include/passwd.h b/lib/secure/cmds/players/include/passwd.h new file mode 100644 index 0000000..e21a2ad --- /dev/null +++ b/lib/secure/cmds/players/include/passwd.h @@ -0,0 +1,10 @@ +#ifndef l_passwd_h +#define l_passwd_h + +mixed cmd(string args); +static void OldPass(string pass, object who); +static void NewPass(string pass, mixed who); +static void ConfirmPass(string str, mixed who, string newpass); +string GetHelp(string str); + +#endif /* l_passwd_h */ diff --git a/lib/secure/cmds/players/map.c b/lib/secure/cmds/players/map.c new file mode 100644 index 0000000..3ebc0be --- /dev/null +++ b/lib/secure/cmds/players/map.c @@ -0,0 +1,20 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mixed cmd(string args) { + string ret; + int i = atoi(args); + if(!i) i = 6; + if(!creatorp(this_player())) i = 3; + if(i <= 30 && !archp(this_player())) i = 29; + ret = MAP_D->GetMap(environment(this_player()), i, 1); + write(ret); + return 1; +} + +string GetHelp(){ + return ("Syntax: map\n\n" + "Displays a simple map of your location."); +} diff --git a/lib/secure/cmds/players/passwd.c b/lib/secure/cmds/players/passwd.c new file mode 100644 index 0000000..cc7eed1 --- /dev/null +++ b/lib/secure/cmds/players/passwd.c @@ -0,0 +1,101 @@ +/* /secure/cmds/players/passwd.c + * from the Dead Souls Object Library + * passwd + * created by Descartes of Borg 951202 + */ + +#include <lib.h> +#include <flags.h> +#include <message_class.h> +#include "include/passwd.h" + +inherit LIB_DAEMON; + +mixed cmd(string args) { + object ob; + + if( previous_object()->GetForced() ) + return "You cannot be forced to change your password."; + if( args && args != "" ) { + if( !archp(previous_object()) ) + return "You may not change other people's passwords."; + if( !user_exists(args = convert_name(args)) ) + return "No such user exists."; + ob = find_player(args); + } + else ob = previous_object(); + previous_object()->eventPrint("Changing password for " + + (ob ? ob->GetCapName() : + capitalize(args)) + " on " + + mud_name() + ".", MSG_SYSTEM); + if( previous_object() == ob ) { + ob->eventPrint("Old password: ", MSG_PROMPT); + input_to( (: OldPass :), I_NOECHO | I_NOESC, ob); + } + else { + previous_object()->eventPrint("New password: ", MSG_PROMPT); + input_to( (: NewPass :), I_NOECHO | I_NOESC, ob || args); + } + return 1; +} + +static void OldPass(string pass, object who) { + string oldpass; + + if( who != this_player() ) return; + if( !pass || pass == "" ) { + who->eventPrint("\nPassword change failed.", MSG_SYSTEM); + return; + } + oldpass = this_player()->GetPassword(); + if( oldpass != crypt(pass, oldpass) ) { + who->eventPrint("\nPassword change failed.", MSG_SYSTEM); + return; + } + who->eventPrint("\nNew password: ", MSG_PROMPT); + input_to((: NewPass :), I_NOECHO | I_NOESC, who); +} + +static void NewPass(string pass, mixed who) { + if( !pass || strlen(pass) < 5 ) { + this_player()->eventPrint("Password must be at least 5 " + "characters, password change failed.", + MSG_SYSTEM); + return; + } + this_player()->eventPrint("\nConfirm: ", MSG_PROMPT); + input_to( (: ConfirmPass :), I_NOECHO | I_NOESC, who, pass); +} + +static void ConfirmPass(string str, mixed who, string newpass) { + if( str != newpass ) { + this_player()->eventPrint("Passwords do not match.", MSG_SYSTEM); + return; + } + if( objectp(who) ) who->SetPassword(crypt(newpass, 0)); + else { + string *lines; + + who = player_save_file(who); + lines = explode(unguarded((: read_file, who :)),"\n"); + unguarded((: rm, who :)); + foreach(string line in lines) { + string val; + + if( sscanf(line, "Password %s", val) ) + line = "Password \"" + crypt(newpass, 0) + "\""; + unguarded((: write_file, who, line + "\n" :)); + } + } + this_player()->eventPrint("\nPassword changed.", MSG_SYSTEM); +} + +string GetHelp(){ + int i; + string ret = "Syntax: passwd\n"; + if(i = (archp(this_player()))) ret += " passwd <PLAYER>\n"; + ret += "\nThis command allows you to change your password"; + if(i) ret += " or that of the specified player"; + ret += ".\n See also: chfn"; + return ret; +} diff --git a/lib/secure/cmds/players/peer.c b/lib/secure/cmds/players/peer.c new file mode 100644 index 0000000..a285bbf --- /dev/null +++ b/lib/secure/cmds/players/peer.c @@ -0,0 +1,133 @@ +/* /secure/cmds/player/peer.c + * Peer into an adjacent room wihout actually entering + * Blitz@Dead SoulsIV + */ + +#include <lib.h> + +inherit LIB_DAEMON; + +string DescribeItems(mixed var); +string DescribeLiving(mixed var); + +mixed cmd(string str) { + int i, err; + string file; + object env, *livings, *items; + + if( !sizeof(str) ) return "Syntax: peer <direction>"; + switch(str){ + case "n" : str = "north";break; + case "ne" : str = "northeast";break; + case "nw" : str = "northwest";break; + case "s" : str = "south";break; + case "se" : str = "southeast";break; + case "sw" : str = "southwest";break; + case "e" : str = "east";break; + case "w" : str = "west";break; + case "u" : str = "up";break; + case "d" : str = "down";break; + } + env = environment(this_player()); + if( !file = env->GetExit(str) ) file = env->GetEnter(str); + if( !sizeof(file) ) + return "You cannot peer that way."; + if( (i = this_player()->GetEffectiveVision()) > 5 ) + return "It is too bright to do that."; + if( env->GetDoor(str) && !((env->GetDoor(str))->CanPeer()) ) { + message("my_action", sprintf("%s is blocking your view %s.", + (capitalize(env->GetDoor(str)->GetShort(str))), str), + this_player() ); + return 1; + } + err = catch(env = load_object(file)); + if(err || !env){ + message("my_action", "It is not safe to peer "+str+"!", this_player() ); + return 1; + } + if(env->GetProperty("no peer")){ + return "You can't see in that direction."; + } + if(env->GetProperty("nopeer")){ + return "You can't see in that direction."; + } + if( (i = this_player()->GetEffectiveVision(file,1)) > 5 ) + return "It is too bright in that direction."; + else if( i < 3 ) + return "It is too dark there."; + + items = filter(all_inventory(env), + (: !$1->GetInvis(this_player()) :) ); + items = items - (livings = filter(items, (: living :))); + message("my_action", "%^GREEN%^" + "Peering "+str+" you see...", + this_player() ); + message("other_action", + this_player()->GetCapName()+" peers "+str+".", + environment(this_player()), this_player() ); + message("room_description", + ("\n"+env->GetLong(0)+"\n" || "\nA void.\n"), + this_player() ); + if( sizeof(items) ) + message("room_inventory", + "%^MAGENTA%^" + DescribeItems(items) + "%^RESET%^\n", + this_player() ); + if( sizeof(livings) ) + message("room_inventory", + "%^BOLD%^%^RED%^" + DescribeLiving(livings) + "%^RESET%^", + this_player() ); + return 1; +} + +string DescribeItems(mixed var) { + mapping m = ([ ]); + string *shorts, ret; + int i, max; + + if( !arrayp(var) ) return ""; + i = sizeof( shorts = map(var, (: $1->GetShort() :)) ); + while(i--) { + if( !sizeof(shorts[i]) ) continue; + if( m[ shorts[i] ] ) m[ shorts[i] ]++; + else m[ shorts[i] ] = 1; + } + i = max = sizeof( shorts = keys(m) ); + ret = ""; + for(i=0; i<max; i++) { + if( m[ shorts[i] ] < 2 ) ret += shorts[i]; + else ret += consolidate(m[shorts[i]], shorts[i]); + if( i == (max - 1) ) { + if( max>1 || m[ shorts[i] ] > 1 ) ret += " are here."; + else ret += " is here."; + } + else if( i == (max - 2) ) ret += ", and "; + else ret += ", "; + } + return capitalize(ret); +} + +string DescribeLiving(mixed var) { + mapping m = ([ ]); + string *shorts, ret; + int i; + if( !arrayp(var) ) return ""; + i = sizeof( shorts = map(var, (: $1->GetShort() :)) ); + while(i--) { + if( !sizeof(shorts[i]) ) continue; + if( m[ shorts[i] ] ) m[ shorts[i] ]++; + else m[ shorts[i] ] = 1; + } + ret = ""; + i = sizeof( shorts = keys(m) ); + while(i--) if( m[ shorts[i] ] > 1 ) + ret += (consolidate(m[shorts[i]], shorts[i]) + "\n"); + else ret += (shorts[i] + "\n"); + return ret; +} + +string GetHelp(){ + return ("Syntax: peer <direction>\n\n" + "Allows you to look into an adjacent room without actually " + "entering it. Note that light and doorways affect what you " + "see."); +} diff --git a/lib/secure/cmds/players/praise.c b/lib/secure/cmds/players/praise.c new file mode 100644 index 0000000..b8a81ba --- /dev/null +++ b/lib/secure/cmds/players/praise.c @@ -0,0 +1,102 @@ +/* /secure/cmds/player/praise.c + * from the Dead Souls LPC Library + * makes a praisereport + * created by Descartes of Borg 950427 + */ + +#include <lib.h> +#include <dirs.h> + +inherit LIB_DAEMON; + +void eventEndEdit(object ob); +string GetCreator(object ob); + +mixed cmd(string text) { + object ob; + string secondary, tmp, file; + + if( text ) { + string *words; + object env; + int i, maxi; + + maxi = sizeof( words = explode(text, " ") ); + for(i=0, tmp = ""; i<maxi; i++ ) { + tmp += words[i]; + if( ob = present(tmp, this_player()) ) { + if( i == maxi - 1 ) text = ""; + else text = implode(words[i+1..], " "); + break; + } + if( (env=environment(this_player())) && ob = present(tmp, env) ) { + if( i == maxi - 1 ) text = ""; + else text = implode(words[i+1..], " "); + break; + } + tmp += " "; + } + } + else text = ""; + ob = (ob || environment(this_player())); + if( text != "" ) { + if( ob ) { + tmp = this_player()->GetCapName() + " reports praise in: " + + identify(ob) + "\non " + ctime(time()) + "\n"; + secondary = GetCreator(ob); + } + else + tmp = this_player()->GetCapName() + " reports praise on: " + + ctime(time()) + ":\n"; + log_file("praise", tmp + text + "\n\n"); + if( secondary ) log_file("reports/" + secondary, tmp + text + "\n\n"); + message("system", "Praise reported!!! Thank you!!!", this_player()); + return 1; + } + rm( file = DIR_TMP "/" + this_player()->GetKeyName() ); + this_player()->eventEdit( file, (: eventEndEdit, ob :) ); + return 1; +} + +void eventEndEdit(object ob) { + string tmp, text, file, secondary; + + file = DIR_TMP "/" + this_player()->GetKeyName(); + if( !file_exists(file) || !(text = read_file(file)) ) { + message("system", "Praise report aborted.", this_player()); + return; + } + rm(file); + if( ob ) { + tmp = this_player()->GetCapName() + " reports praise in: " + + identify(ob) + "\non: " + ctime(time()) + "\n"; + secondary = GetCreator(ob); + } + else + tmp = this_player()->GetCapName() + " reports praise on " + + ctime(time()) + ":\n"; + log_file("praise", tmp + text + "\n\n"); + if( secondary ) log_file("reports/" + secondary, tmp + text + "\n\n"); + message("system", "Praise reported!!! Thank you!!!", this_player()); +} + +string GetCreator(object ob) { + string fn, nom; + + fn = file_name(ob); + if( sscanf(fn, REALMS_DIRS "/%s/%*s", nom) ) return nom; + else if( sscanf(fn, DOMAINS_DIRS "/%s/%*s", nom) ) return nom; + else return 0; +} + +string GetHelp(){ + return ("Syntax: praise [object] [message]\n\n" + "Allows you to praise things in the MUD to both the MUD " + "administrators as well as to the creator of the object you " + "are referencing (if any). If you do not specify an object, " + "then the report will be sent to the creator of the room in which " + "you are located in addition to the MUD administrators. If you " + "fail to specify text on the command line, then you will be put " + "into the editor in order to compose the report.\n" + "See also: bug, idea"); +} diff --git a/lib/secure/cmds/players/reply.c b/lib/secure/cmds/players/reply.c new file mode 100644 index 0000000..3d33d43 --- /dev/null +++ b/lib/secure/cmds/players/reply.c @@ -0,0 +1,39 @@ +// /secure/cmds/players/reply.c +// from the Dead Souls mudlib +// replies to the person who previously told to you +// created by Descartes of Borg 06 february 1993 + +#include <lib.h> +#include <commands.h> +#include <talk_type.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +int cmd(string str) { + string reply,a,b,msg,machine_message,frm; + object ob, machine; + mixed err; + + reply = this_player()->GetProperty("reply"); + if(!reply) reply = "no one"; + if(!str) { + notify_fail("Current reply addressee: "+capitalize(reply)+"\n"); + return 0; + } + if(reply == "no one") { + notify_fail("No current reply addressee.\n"); + return 0; + } + this_player()->SetProperty("reply_time", time()); + load_object(CMD_TELL)->cmd(reply+" "+str); + return 1; +} + +string GetHelp(){ + return ("Syntax: reply [message]\n\n" + "With a message, it replies to the person who last told or replied " + "to you. Without a message, it shows who the current object of " + "your reply would be.\nSee also: " + "finger, idle, muds, say, shout, tell, yell"); +} diff --git a/lib/secure/cmds/players/suicide.c b/lib/secure/cmds/players/suicide.c new file mode 100644 index 0000000..8e85e38 --- /dev/null +++ b/lib/secure/cmds/players/suicide.c @@ -0,0 +1,163 @@ +/* /secure/cmds/player/suicide.c + * from the Dead Souls Object Library + * Allows players to obliterate their character + * created by Blitz@Dead Souls + */ + +#include <lib.h> +#include <dirs.h> +#include <flags.h> +#include <privs.h> +#include <daemons.h> +#include ROOMS_H +#include <message_class.h> + +inherit LIB_DAEMON; + +static private void GetPassword(string input); +static private void GetYesOrNo(string input); +static private void EndSuicide(string who); + +string home_dir = ""; +string newfile, tmp, gwho = ""; + +int eventHoseDude(object dude){ + if(dude) dude->eventDestruct(); + if(dude) destruct(dude); + return 1; +} + +mixed cmd(string str) { + string who; + object ob; + + if( sizeof(str) ) return "Suicide does not require any arguments."; + ob = previous_object(); + if( this_player(1) != ob || !userp(ob) ) { + log_file("security", "** Illegal suicide attempt **\n " + "Call stack:\n"+ sprintf("%O\n", previous_object(-1))); + return "Suicide failed."; + } + if( this_player()->GetForced() ) { + log_file("security", "*** Illegal \"Forced\" Suicide **\n" + "Call stack:\n"+ sprintf("%O\n", previous_object(-1))); + return 0; + } + who = this_player()->GetKeyName(); + if( who == "guest" ) return "Guest is not suicidal!"; + if( member_group(who, PRIV_SECURE) || member_group(who, PRIV_ASSIST) ) + return "You must first have your security privileges removed."; + this_player()->eventPrint("Committing suicide means having your character " + "completely erased from "+mud_name()+"'s database. If you " + "are certain this is what you want, enter in your correct " + "password. Otherwise enter in a wrong password."); + this_player()->eventPrint("Password: ", MSG_EDIT); + input_to((: GetPassword :), I_NOECHO | I_NOESC); + return 1; +} + +static private void GetPassword(string input) { + string tmp; + if( !sizeof(input) ) { + this_player()->eventPrint("Suicide aborted."); + return; + } + tmp = this_player()->GetPassword(); + if( tmp != crypt(input, tmp) ) { + this_player()->eventPrint("Wrong password. Suicide aborted."); + return; + } + this_player()->eventPrint("\nLeave a suicide note? (a)bort, (y)es, (N)o :\n", + MSG_EDIT); + input_to((: GetYesOrNo :)); + return; +} + +static private void GetYesOrNo(string input) { + tmp = this_player()->GetKeyName(); + if( !sizeof(input) || (input = lower_case(input))[0] != 'y' ) { + if( input && input[0] == 'a' ) { + this_player()->eventPrint("Suicide has been aborted."); + return; + } + EndSuicide(tmp); + return; + } + this_player()->eventPrint("\nYou may now enter a letter " + "explaining why you suicided. If you do not wish to write a " + "letter, simply exit the editor without writing anything. " + "(enter \".\" on a blank line to exit editor.)\n"); + this_player()->eventEdit(DIR_TMP + "/" + tmp, (: EndSuicide, tmp :)); +} + +static private void EndSuicide(string who) { + string file; + object *ob; + string whocheck = cleaned_end(base_name(this_player())); + tmp = ""; + newfile = ""; + if(who != whocheck){ + write("There seems to be a conflict in determining your identity."); + write("Suicide aborted."); + return; + } + gwho = who; + home_dir = homedir(this_player()); + if(!directory_exists(DIR_TMP + "/suicide/")) mkdir (DIR_TMP + "/suicide/"); + + file = DIR_TMP + "/" + who; + newfile = "/log/suicides/" + who; + if( file_size(file) > 0 ) { + tmp = possessive_noun(who)+" suicide note.\n" + "Dated: "+ctime(time())+"\n"; + tmp += read_file(file); + if(!directory_exists("/log/suicides")){ + unguarded( (: mkdir("/log/suicides") :) ); + } + unguarded( (: write_file(newfile, tmp, 1) :) ); + } + if( file_exists(file) ) rm(file); + log_file("suicide", who+" suicided at "+ctime(time()) + +". (from "+query_ip_name(this_player())+")\n"); + tmp = player_save_file(who); + unguarded((: rename, tmp, save_file(DIR_SUICIDE + "/" + who) :)); + if(home_dir && directory_exists(home_dir)){ + object *purge_array = filter(objects(), (: !strsrch(base_name($1), home_dir) :) ); + foreach(object tainted in purge_array){ + if(clonep(tainted)){ + tainted->eventMove(ROOM_FURNACE); + purge_array -= ({ tainted }); + } + } + foreach(object tainted in purge_array){ + tainted->eventDestruct(); + } + unguarded( (: rename(home_dir,"/secure/save/decre/"+gwho+"."+timestamp()) :) ); + home_dir = ""; + gwho = ""; + } + this_player()->eventPrint("You have suicided. Please try " + "again another time."); + environment(this_player())->eventPrint( + this_player()->GetName()+" has ended "+ + possessive(this_player())+" own life before your very eyes.", + this_player() ); + if( sizeof( ob = filter(users(), (: archp :)) ) ) + ob->eventPrint("["+this_player()->GetName()+" has " + "committed suicide]"); + PLAYERS_D->RemoveUser(who); + this_player()->eventMove(ROOM_FURNACE); + this_player()->eventDestruct(); + return; +} + +string GetHelp(){ + return "Syntax: suicide\n\n" + "Ends your character's existence on "+mud_name()+" FOREVAR. " + "It is non-reversible. Once you issue this command, you will be asked" + "for a password to confirm your identity. Once password is confirmed, " + "you will no longer exist in the MUD's database. You may also opt " + "to write a final suicide note.\n\n" + "NOTE: If you suicide from a restricted site, you will have to " + "reregister!"; +} diff --git a/lib/secure/cmds/players/tell.c b/lib/secure/cmds/players/tell.c new file mode 100644 index 0000000..c80e677 --- /dev/null +++ b/lib/secure/cmds/players/tell.c @@ -0,0 +1,223 @@ +/* /secure/cmds/player/tell.c + * from the Dead Souls LPC Library + * the tell command + * created by Descartes of Borg 950523 + */ + +#include <lib.h> +#include <talk_type.h> +#include <message_class.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +int CheckMud(string name){ + int ret = 3; + string *imc2list, tmpname; + if(!(tmpname = INTERMUD_D->GetMudName(name)) ) ret = 0; + if(tmpname && !INTERMUD_D->GetMudList()[tmpname][0]) ret = 0; + if(ret){ + return ret; + } + if(sizeof(IMC2_D->GetMudName(name, 1))) ret = 2; + else ret = 0; + return ret; +} + +mixed cmd(string str) { + string *words; + mixed mud; + object ob, machine; + int i, maxi, insttell; + string who, msg, tmp, tmp2, machine_message, retname, me; + + if(!str) return notify_fail("Syntax: tell <who> <message>\n"); + if(str == "hist" || str == "history"){ + string ret = "Your tell history: \n\n"; + ret += implode(this_player()->GetTellHistory(),"\n"); + print_long_string(this_player(), ret); + return 1; + } + if(!creatorp(this_player()) && this_player()->GetMagicPoints() < 15) { + write("You lack sufficient magic to tell to anyone right now."); + return 1; + } + mud = 0; + words = explode(str, " "); + if(sizeof(words)) who = convert_name(words[0]); + maxi = sizeof(words = explode(str, "@")); + if(maxi > 1 && !find_player(who)){ + string tmpmsg, tmpmud; + who = convert_name(words[0]); + if(maxi > 2) words[1] = implode(words[1..maxi-1], "@"); + maxi = sizeof(words = explode(words[1], " ")); + if(CheckMud(words[0]) == 2){ + tmpmud = words[0]; + tmpmsg = implode(words[1..]," "); + } + for(i=0; i<maxi; i++) { + tmp = lower_case(implode(words[0..i], " ")); + tmp2 = lower_case(implode(words[0..i+1], " ")); + + mud = tmp; + + if( CheckMud(tmp) && !CheckMud(tmp2) ){ + if(i+1 < maxi) msg = implode(words[i+1..maxi-1], " "); + else msg = ""; + break; + } + if( IMC2_D->GetMudName(tmp) && !(IMC2_D->GetMudName(tmp2)) ){ + msg = tmpmsg; + break; + } + } + if(!CheckMud(mud) && !(IMC2_D->GetMudName(mud))){ + write("No such mud found."); + return 1; + } + if(!sizeof(msg)) return notify_fail("Syntax: tell <who> <message>\n"); + if(!mud) mud = -1; + } + if(!mud || mud == -1){ + int memb; + object npc; + maxi = sizeof(words = explode(str, " ")); + who = 0; + for(i=0; i<maxi; i++){ + retname = words[0]; + tmp = convert_name(implode(words[0..i], " ")); + memb = member_array(tmp, remote_users()); + ob = find_player(tmp); + if(!ob) npc = find_living(tmp); + if(ob || memb != -1 || npc){ + if(!ob && memb == -1 && npc) ob = npc; + who = tmp; + if(i+1 < maxi) msg = implode(words[i+1..maxi-1], " "); + else msg = ""; + break; + } + } + if(!who){ + if(!mud){ + words -= ({ retname }); + msg = implode(words," "); + this_player()->eventTellHist("You tried to tell "+retname+": "+ + "%^BLUE%^%^BOLD%^"+ msg + "%^RESET%^"); + insttell = 1; + INSTANCES_D->SendTell(retname, msg); + write("Tell whom what?"); + return 1; + } + else { + if(grepp(who, "@")){ + write("Malformed message."); + } + else { + write(mud_name()+" is offline or doesn't exist.\n"); + } + return 1; + } + } + if(msg == ""){ + write("What do you wish to tell?\n"); + return 1; + } + } + else { + if(CheckMud(mud) == 3){ + if(!creatorp(this_player())) this_player()->AddMagicPoints(-15); + SERVICES_D->eventSendTell(who, mud, msg); + } + else { + IMC2_D->command("tell "+who+"@"+mud+" "+msg); + } + return 1; + } + if(ob){ + mixed err; + if(!insttell) INSTANCES_D->SendTell(who, msg); + insttell = 1; + if(archp(ob) || (!archp(this_player()) && creatorp(ob))) + me = capitalize(this_player()->GetKeyName()); + else me = this_player()->GetName(); + + machine=present("answering machine",ob); + if(ob && !creatorp(ob)) this_player()->AddMagicPoints(-15); + if(machine && base_name(machine) == "/secure/obj/machine"){ + int parse_it; + parse_it=machine->query_answer(); + if(parse_it){ + machine->get_message(me+" tells you: "+msg+"\n"); + machine_message=machine->send_message(); + } + } + if( (err = this_player()->CanSpeak(ob, "tell", msg)) != 1){ + if(ob && !creatorp(ob)) this_player()->AddMagicPoints(15); + this_player()->eventTellHist("You tried to tell "+retname+": "+ + "%^BLUE%^%^BOLD%^"+ msg + "%^RESET%^"); + return err || "Tell whom what?"; + } + if( ob->GetInvis() && ( ( archp(ob) && !archp(this_player()) ) + || ( creatorp(ob) && !creatorp(this_player()) ) ) ){ + string inv_ret = "%^BLUE%^%^BOLD%^" + me + + " unknowingly tells you, %^RESET%^\"" + msg + "\""; + if(!machine_message){ + ob->eventPrint(inv_ret); + } + ob->eventTellHist(inv_ret); + ob->SetProperty("reply", lower_case(me)); + ob->SetProperty("reply_time", time()); + if(!insttell) INSTANCES_D->SendTell(who, msg); + insttell = 1; + this_player()->eventTellHist("You tried to tell "+retname+": "+ + "%^BLUE%^%^BOLD%^"+ msg + "%^RESET%^"); + if(query_verb() == "tell") return "Tell whom what?"; + else { + write("Tell whom what?"); + return 1; + } + } + if(machine_message) message("info", machine_message, this_player()); +#ifdef BLOCK_TELLS_TO_AFK + if(ob->GetProperty("afk")) { + message("my_action", ob->GetName()+ + " is afk and cannot receive your message.", this_player()); + } +#endif + else this_player()->eventSpeak(ob, TALK_PRIVATE, msg); + ob->SetProperty("reply", lower_case(me)); + ob->SetProperty("reply_time", time()); + if(!archp(ob) && userp(ob) && (query_idle(ob) > 60)) + message("my_action", ob->GetName()+ + " is idle and may not have been paying attention.", this_player()); + else if((in_edit(ob) || in_input(ob)) +#ifdef __DSLIB__ + && !query_charmode(ob) +#endif + ) + message("my_action", ob->GetCapName()+" is in input "+ + "and may not be able to respond.", this_player()); + else if(ob->GetSleeping()) + message("my_action", ob->GetCapName()+" is sleeping "+ + "and is unable to respond.", this_player()); + } + else { + string ret; + ret = "%^BOLD%^RED%^You tell " + capitalize(who) + + ":%^RESET%^ " + msg; + this_player(1)->eventPrint(ret, MSG_CONV); + this_player(1)->eventTellHist(ret); + if(!insttell) INSTANCES_D->SendTell(who, msg); + } + return 1; +} + +string GetHelp(){ + return ("Syntax: tell <player> <message>\n" + " tell <player>@<mud> <message>\n\n" + "Sends the message to the player named either on this mud if no " + "mud is specified, or to the player named on another mud when " + "another mud is specified. If the other mud is on an IMC2 network " + "rather than an Intermud-3 network, use \"imc2 tell\"" + "\nSee also: imc2, say, shout, yell, emote"); +} diff --git a/lib/secure/cmds/players/telnet.c b/lib/secure/cmds/players/telnet.c new file mode 100644 index 0000000..767eae9 --- /dev/null +++ b/lib/secure/cmds/players/telnet.c @@ -0,0 +1,80 @@ +#include <lib.h> +#include <daemons.h> + +inherit LIB_DAEMON; + +mapping NamesMap = ([]); + +mixed cmd(string args) { + string ip_string, port_string, ip; + int d1, d2, d3, d4, port; + + if(sscanf(args,"%s %s",ip_string, port_string) != 2){ + this_object()->help(); + return 1; + } + + if(sscanf(ip_string,"%d.%d.%d.%d",d1,d2,d3,d4) != 4 && + !RESOLV_D->GetResolving()){ + write("This mud is not using name resolution. Use a "+ + "numerical ip address, like 11.22.33.44"); + return 1; + } + + if(!atoi(port_string)){ + write("The port must be numerical, such as: 6666"); + return 1; + } + + if(d4){ + this_object()->eventStartConnection(this_player(), args); + return 1; + } + + write("Attempting to resolve \""+ip_string+"\". If this fails, "+ + "try using a numerical ip address, like 1.2.3.4"); + NamesMap[ip_string] = ([ "dude": this_player(), "port" : port_string ]); + RESOLV_D->eventResolve(ip_string, "resolve_callback"); + return 1; +} + +void resolve_callback(string name, string number, int key){ + string cle, port; + object ob; + if(NamesMap[number]){ + cle = number; + } + else if(NamesMap[name]){ + cle = name; + } + else return; + + ob = NamesMap[cle]["dude"]; + port = NamesMap[cle]["port"]; + map_delete(NamesMap, cle); + if(ob){ + ob->eventPrint(number+" resolves to: "+name); + this_object()->eventStartConnection(ob, number + " " + port); + } +} + +int eventStartConnection(object who, string where){ + object client = new("/secure/obj/tc"); + if(!client || !who) return 0; + + if(!telnet_privp(who)){ + who->eventPrint("You are not a member of the group of users permitted " + "to use this mud's telnet facility."); + return 1; + } + client->SetConnection(where); + client->eventMove(who); + client->do_connect(where, who); + return 1; +} + +string GetHelp(){ + return ("Syntax: telnet <ip address> <port>\n\n" + "If you are in the TELNET group, this connects you to another " + "computer or mud on the ip and port specified."); +} diff --git a/lib/secure/daemon/alchemist.c b/lib/secure/daemon/alchemist.c new file mode 100644 index 0000000..38fa567 --- /dev/null +++ b/lib/secure/daemon/alchemist.c @@ -0,0 +1,126 @@ +// File: /adm/alchemist.c +// Purpose: Store material properties +// Setup objects (initialise their properties) +// This object is also inherited by domain master objects +// Mudlib: Nightmare +// Author: Douglas Reay (Pallando @ Ephemeral Dales, Nightmare, etc) +// 93-06-08: Based on alchemist written by Pallando@FR mud +// and using the prop_logic seperated by Pallando@TMI-2 +// 93-06-16: Pallando added temperature setting + +#include <lib.h> +#include <daemons.h> +#include <materials.h> +inherit LIB_DAEMON; + +inherit "/std/prop_logic"; + +static string *props; // Names of properties all objects must have +static int num_props; // number of properties in the above array +mapping properties; // Values of those properties for each material +static string save_file; // place where the data for the above mapping is kept + +mixed get( string property ) +{ + mixed parts, value, tmp; + int size, loop; + + parts = explode( property, "/" ); + size = sizeof( parts ); + if( !mapp( value = properties[parts[0]] ) ) return value; + for( loop = 1 ; ( loop < size ) && mapp( value ) ; loop++ ) + { + // Allows default values. Eg: if we are trying to find the density of lead + // but that hasn't been set, it will use the default metal density instead + if( undefinedp( tmp = value[parts[loop]] ) && + undefinedp( tmp = value["default"] ) ) + return mapp( value ) ? tmp : value; + value = tmp; + } + return value; +} + +mixed query( string property ) +{ + mixed value; + + if( !undefinedp( value = get( property ) ) ) return value; + return ALCHEMIST_D-> get( property ); +} + +void init_properties() +{ + string file, property; + mixed value; + string *lines; + int size, loop, tmp; + + properties = ([]); + if( ( 0 > file_size( save_file+".t" ) ) || + !( file = read_file( save_file+".t" ) ) || + !( lines = explode( file, "\n" ) ) || + !( size = sizeof( lines ) ) ) return; + properties = allocate_mapping( size ); + for( loop = 0 ; loop < size ; loop++ ) + { + if( sscanf( lines[loop], "%s;%s", property, value ) < 2 ) continue; + if( sscanf( value, "%d", tmp ) ) value = tmp; + // Defined in /std/prop_logic + // Just does properties[property]=value in a heirachic way (see the .o) + _set( properties, explode( property, "/" ), value ); + } + SaveObject( save_file ); +} + +// During reboots the data is saved in a .o file. +// It only needs to be calculated from the .t when that file is changed +void create() +{ + // Inheriting d_masters use different save files. + if( !save_file ) save_file = "/data/properties"; + RestoreObject( save_file ); + if( properties ) return; + init_properties(); +} + +// This function is called from set_material() in /std/Object +// Inheriting domain master obs can set props in create or in their +// setup_object function, before doing ::setup_object() +void setup_object( object ob, object pobj ) +{ + string material, name, type; + int mass, temperature, loop; + + if( !props ) + { + props = MATERIAL_PROPS; + num_props = sizeof( props ); + } + type = ob-> query( "material_type" ); + if( !type || -1 == member_array( type, MATERIAL_TYPES ) ) + { + // Log the event here for QC + return; + } + if( !( name = ob-> query( "material_name" ) ) ) + { + // Log the event here for QC + return; + } + material = "/"+type+"/"+name; + for( loop = 0 ; loop < num_props ; loop++ ) + ob-> set( props[loop], query( props[loop] + material ) ); + if( !( mass = ob-> query( "mass" ) ) ) + { + // Log the event here for QC + return; + } + // Until set_weight() is removed. + ob-> set_weight( mass ); + ob-> set( "volume", 1000 * mass / ( ob-> query( "density" ) ) ); + if( !pobj ) return; + if( !function_exists( "query", pobj ) || + undefinedp( temperature = pobj-> query( "temperature" ) ) ) + temperature = query( "temperature/default" ); + ob-> set( "temperature", temperature ); +} diff --git a/lib/secure/daemon/autoexec.c b/lib/secure/daemon/autoexec.c new file mode 100644 index 0000000..f2d0d2d --- /dev/null +++ b/lib/secure/daemon/autoexec.c @@ -0,0 +1,98 @@ +#include <lib.h> +#include <save.h> +#include <daemons.h> +#include <commands.h> + +inherit LIB_DAEMON; + +int t, BootScore, PerformanceScore, hasrun = 0; + +string RateScore(int i){ + string ret; + if(!i) ret = "No score available."; + else if(i < 51) ret = "Spectacular."; + else if(i < 101) ret = "Excellent."; + else if(i < 201) ret = "Very good."; + else if(i < 301) ret = "Good."; + else if(i < 401) ret = "Fair."; + else if(i < 501) ret = "Poor."; + else if(i < 601) ret = "Very poor."; + else if(i < 701) ret = "Bad."; + else ret = "Execrable."; + return ret; +} + +static void eventRun() { + string ret = ""; + mapping before, after; + string *noobnames = ({ "Dead_Souls_"+DEBUGGER, "DeadSoulsNew", + "DeadSoulsWin" }); + debug_message("\nRunning autoexec, please wait..."); + BootScore = MASTER_D->GetBootScore(); +#ifdef __HAS_RUSAGE__ + before = rusage(); +#endif + t = time(); + load_object(CMD_UPDATE)->cmd("-r /lib/creator"); + if(RESET_INTERMUD){ + rm(save_file(SAVE_INTERMUD)); + update(INTERMUD_D); + } + if(member_array(mud_name(),noobnames) == -1){ + mixed foo; + foo = IMC2_D->UnSetAutoDisabled(1); + } + + //Put your start-on-boot stuff below + + catch( load_object("/secure/cmds/creators/dsversion")->cmd()); + catch( reload("/domains/default/room/stargate_lab.c",0,1)); + catch( reload("/domains/town/virtual/space/1,1,1",0,1)); + catch( reload("/domains/town/virtual/bottom/33,100000",0,1)); + catch( reload("/domains/Praxis/square.c",0,1)); + catch( reload("/domains/Ylsrim/room/tower",0,1)); + catch( reload("/domains/campus/room/slab",0,1)); + + //Put your start-on-boot stuff above + +#ifdef __HAS_RUSAGE__ + after = rusage(); +#endif + t = time() - t; +#ifdef __HAS_RUSAGE__ + if(sizeof(before) && sizeof(after)){ + t = after["utime"] - before["utime"]; + ret = "Autoexec daemon run complete. ("+t+"ms)\n"; + } +#else + ret = "Autoexec daemon run complete.\n"; +#endif + debug_message(ret); + call_out("perfreport", 1); +} + +void perfreport(){ + string ret = ""; + float secs; + if(!PerformanceScore) PerformanceScore = MASTER_D->GetPerformanceScore(); + if(!BootScore) BootScore = MASTER_D->GetBootScore(); + if(BootScore){ + secs = ((BootScore + t ) * 0.001); + ret += "CPU time in boot: " + sprintf("%.2f",secs)+ " seconds."; + } + if(PerformanceScore){ + ret += " (Performance score: " + (RateScore(PerformanceScore))+")\n"; + } + debug_message(ret); +} + +static void create() { + daemon::create(); + PerformanceScore = MASTER_D->GetPerformanceScore(); + if(hasrun){ + return; + } + call_out((: eventRun :), 1); + hasrun = 1; +} + diff --git a/lib/secure/daemon/bboard.c b/lib/secure/daemon/bboard.c new file mode 100644 index 0000000..5253735 --- /dev/null +++ b/lib/secure/daemon/bboard.c @@ -0,0 +1,189 @@ +/* /secure/daemon/bboard.c + * from Nightmare 3.3 + * bulletin board daemon + * created by Descartes of Borg 940920 + */ + +#include <lib.h> +#include <dirs.h> +#include <privs.h> +#include "bboard.h" + +inherit LIB_DAEMON; + +private string __Owner; +private mapping *__Posts; +static private string __CurrentID; +string list_new_posts(string id); +string Location; + +void create() { + daemon::create(); + SetNoClean(1); + __Owner = 0; + __CurrentID = 0; + __Posts = ({}); +} + +static private void save_board() { + if(!__CurrentID){ + return; + } + if(!unguarded((: file_exists,save_file(DIR_BOARDS+"/"+__CurrentID) :))){ + int i; + + if(!sizeof(__Posts)){ + //tc("__Owner: "+__Owner); + __Owner = query_privs(previous_object(0)); + __Posts = ({}); + //tc("__Owner: "+__Owner); + } + i = strlen(__CurrentID); + while(i--) + if((__CurrentID[i] < 'a' || __CurrentID[i] > 'z') && __CurrentID[i] != '_') + error("Illegal bulletin board id."); + } + SaveObject(save_file(DIR_BOARDS+"/"+__CurrentID)); +} + +static private int restore_board() { + if(!__CurrentID){ + return 0; + } + if(!unguarded((: file_exists, save_file(DIR_BOARDS+"/"+__CurrentID) :))){ + //tc("o: "+__Owner); + __Owner = query_privs(previous_object(0)); + //tc("o: "+__Owner); + __Posts = ({}); + return 0; + } + else { + RestoreObject(save_file(DIR_BOARDS+"/"+__CurrentID)); + } + return 1; +} + +static private int valid_access() { + string str; + //tc("stack: "+get_stack(1)); + if(this_player() && adminp(this_player())) true(); + else if(__Owner == PRIV_SECURE && !(master()->valid_apply(({})))) + return 0; + str = query_privs(previous_object(0)); + if(member_array(PRIV_ASSIST, explode(str, ":")) != -1) return 1; + return (__Owner == str); +} + +void add_post(string id, string who, string subj, string msg) { + //tc("1"); + if(__CurrentID != id) { + __CurrentID = id; + restore_board(); + } + //tc("2"); + if(!valid_access()){ + //tc("x: "+valid_access()); + return; + } + //tc("3"); + if(!stringp(who)) return; + if(!subj || subj == "") subj = "[No Subject]"; + if(!msg || msg == "") return; + __Posts += ({ ([ "author" : who, "subject" : subj, "time" : time(), + "post" : msg, "read" : ({ convert_name(who) }) ]) }); + save_board(); +} + +void RegisterLocation(string id, string location){ + if(__CurrentID != id) { + __CurrentID = id; + restore_board(); + } + if(!valid_access()){ + return; + } + if(!location || !stringp(location)){ + return; + } + Location = location; + save_board(); +} + +void remove_post(string id, int post) { + if(__CurrentID != id) { + __CurrentID = id; + restore_board(); + } + if(!valid_access()) return; + if(post < 0 || post >= sizeof(__Posts)) return; + if( !post && sizeof(__Posts) ) __Posts = __Posts[1..]; + else if( post == sizeof(__Posts) - 1 ) __Posts = __Posts[0..<2]; + else __Posts = __Posts[0..(post - 1)] + __Posts[(post + 1)..]; + save_board(); +} + +void mark_read(string id, int post, string reader) { + if(__CurrentID != id) { + __CurrentID = id; + restore_board(); + } + if(!valid_access()) return; + if(post < 0 || post > sizeof(__Posts)) return; + if(reader && reader != "") + __Posts[post]["read"] = distinct_array(__Posts[post]["read"]+({reader})); + save_board(); +} + +mapping query_post(string id, int post) { + if(__CurrentID != id) { + __CurrentID = id; + restore_board(); + } + if(!valid_access()) return 0; + if(post < 0 || post > sizeof(__Posts)) return 0; + return copy(__Posts[post]); +} + +mapping *query_posts(string id) { + if(__CurrentID != id) { + __CurrentID = id; + restore_board(); + } + if(!valid_access()) return 0; + return copy(__Posts); +} + +int query_number_posts(string id) { + if(__CurrentID != id) { + __CurrentID = id; + restore_board(); + } + if(!valid_access()) return 0; + return sizeof(__Posts); +} + +varargs string list_new_posts(string id, int location){ + string mag; + int i; + mixed count; + + if(__CurrentID != id) { + __CurrentID = id; + Location = 0; + i = restore_board(); + } + + count = 0; + + for(i = 0; i < sizeof(__Posts); i++){ + if(member_array(convert_name(this_player()->GetKeyName()), + __Posts[i]["read"]) == -1) count++; + } + + id = replace_string(id, "_", " "); + if(location) id += " ( "+Location+" ) "; + mag = ""; + mag += capitalize(id) + " has "+(count ? count : "no") + " new message"+ + (count == 1 ? "" : "s")+ " posted."; + return mag; +} diff --git a/lib/secure/daemon/bboard.h b/lib/secure/daemon/bboard.h new file mode 100644 index 0000000..348a4b3 --- /dev/null +++ b/lib/secure/daemon/bboard.h @@ -0,0 +1,15 @@ +#ifndef __BBOARD_H +#define __BBOARD_H + +void create(); +static private void save_board(); +static private void restore_board(); +static private int valid_access(); +void add_post(string id, string who, string subj, string msg); +void remove_post(string id, int post); +void mark_read(string id, int post, string reader); +mapping query_post(string id, int post); +mapping *query_posts(string id); +int query_number_posts(string id); + +#endif /* __BBOARD_H */ diff --git a/lib/secure/daemon/character.c b/lib/secure/daemon/character.c new file mode 100644 index 0000000..1bc051c --- /dev/null +++ b/lib/secure/daemon/character.c @@ -0,0 +1,194 @@ +/* /secure/daemon/character.c + * from the Dead Souls Mud Library + * the multi-character management daemon + * created by Descartes of Borg 951216 + */ + +#include <lib.h> +#include <save.h> +#include <privs.h> +#include <link.h> +#include "include/character.h" + +inherit LIB_DAEMON; + +private mapping Links; +static string SaveFile; + +static void create() { + daemon::create(); + SaveFile = save_file(SAVE_CHARACTER); + SetNoClean(1); + Links = ([]); + if(unguarded((: file_exists(SaveFile) :))){ + RestoreObject(SaveFile); + } +} + +mixed eventConnect(string who) { + class char_link c; + string prime; + int min_wait; + + if( base_name(previous_object()) != LIB_CONNECT ) return 0; + if( !(c = Links[prime = who]) ) { + foreach(string pl, class char_link cl in Links) { + if( member_array(who, cl->Secondaries) != -1 ) { + prime = pl; + c = cl; + break; + } + } + if( !c ) return 1; + } + foreach(string ind in c->Secondaries + ({ prime })) { + if( find_player(ind) ) { + if( who == ind ) return 1; + if(member_group(who, PRIV_SECURE) || member_group(who,PRIV_ASSIST)) + return 1; + else if( archp(find_player(ind)) ) return 1; + else return "You have a linked character currently logged in.\n"; + } + } + if( LINK_WAIT_PERIOD > uptime() ) min_wait = uptime(); + else min_wait = LINK_WAIT_PERIOD; + if( c->LastOnDate > time() - min_wait ) { + string tmp; + int x; + + if( c->LastOnWith == who ) return 1; + x = c->LastOnDate + min_wait - time(); + if( x < 60 ) tmp = consolidate(x, "a second"); + else tmp = consolidate(x/60, "a minute"); + if( !(member_group(who, PRIV_SECURE) || member_group(who,PRIV_ASSIST))) + return "\nYour character " + capitalize(c->LastOnWith) + + " recently logged in at " + ctime(c->LastOnDate) + ".\n" + + "You must wait another " + tmp + ".\n"; + } + c->LastOnDate = time(); + c->LastOnWith = who; + SaveObject(SaveFile); + return 1; +} + +mixed eventLink(string primary, string secondary, string email) { + class char_link ch; + + if( !(master()->valid_apply(({ PRIV_LAW }))) ) + return "Permission denied."; + if( !user_exists(primary = convert_name(primary)) ) + return "No such user: primary"; + if( !email ) return "Email is required for linking."; + secondary = convert_name(secondary); + if( Links[primary] ) { + ch = Links[primary]; + if( Links[secondary] ) { + class char_link c2; + + c2 = Links[secondary]; + ch->Secondaries += ({ secondary }); + ch->Secondaries += c2->Secondaries; + ch->Secondaries = distinct_array(ch->Secondaries); + ch->Email = email; + if( ch->LastOnDate < c2->LastOnDate ) { + ch->LastOnDate = c2->LastOnDate; + ch->LastOnWith = c2->LastOnWith; + } + Links[primary] = ch; + map_delete(Links, secondary); + if( !SaveObject(SaveFile) ) return "Error in saving."; + return 1; + } + } + else if( Links[secondary] ) { + ch = Links[secondary]; + map_delete(Links, secondary); + } + else ch = new(class char_link); + if( ch->Secondaries ) ch->Secondaries += ({ secondary }); + else ch->Secondaries = ({ secondary }); + ch->Email = email; + ch->LastOnDate = 0; + ch->LastOnWith = primary; + Links[primary] = ch; + if( !SaveObject(SaveFile) ) return "Error in saving."; + return 1; +} + +mixed eventSaveTime() { + class char_link c; + object ob; + string who; + + if( !userp(ob = previous_object()) ) return 0; + who = ob->GetKeyName(); + if( !(c = Links[who]) ) { + foreach(string pl, class char_link cl in Links) { + if( member_array(who, cl->Secondaries) != -1 ) { + c = cl; + break; + } + } + if( !c ) return 1; + } + c->LastOnDate = time(); + c->LastOnWith = who; + SaveObject(SaveFile); + return 1; +} + +mixed eventUnlink(string primary, string who) { + class char_link ch; + + if( !(master()->valid_apply(({ PRIV_ASSIST }))) ) + return "Permission denied."; + primary = convert_name(primary); + who = convert_name(who); + if( !(ch = Links[primary]) ) return "No such primary character."; + if( who == primary ) { + if( sizeof(ch->Secondaries) < 2) { + map_delete(Links, primary); + SaveObject(SaveFile); + return 1; + } + primary = ch->Secondaries[0]; + ch->Secondaries = ch->Secondaries[1..]; + map_delete(Links, who); + Links[primary] = ch; + SaveObject(SaveFile); + return 1; + } + if( member_array(who, ch->Secondaries) == -1 ) + return "Invalid secondary character for " + primary + "."; + ch->Secondaries -= ({ who }); + Links[primary] = ch; + SaveObject(SaveFile); + return 1; +} + +mapping GetLinks() { + if( !(master()->valid_apply(({ PRIV_ASSIST }))) ) return ([]); + else return Links; +} + +mapping GetLink(string who) { + class char_link ch; + + who = convert_name(who); + if( Links[who] ) ch = Links[who]; + else { + class char_link l; + string pl; + + foreach(pl, l in Links) { + if( member_array(who, l->Secondaries) != -1 ) { + ch = l; + who = pl; + break; + } + } + if( !ch ) return 0; + } + return ([ "primary" : who, "last char" : ch->LastOnWith, + "secondaries" : ch->Secondaries, "last on" : ch->LastOnDate ]); +} diff --git a/lib/secure/daemon/chat.c b/lib/secure/daemon/chat.c new file mode 100644 index 0000000..ca80238 --- /dev/null +++ b/lib/secure/daemon/chat.c @@ -0,0 +1,975 @@ +/* /daemon/chat.c + * from the Dead Souls Mudlib + * daemon to handle all mud chat channels + * created by Descartes of Borg 931220 + * + * IMC2 support added by Shadyman 2007-Sep-24 + * Feelings support added by Shadyman 2007-Sep-24 + * "mapping tags" added by Shadyman 2007-Sep-24 + */ + +#ifndef LOG_REMOTE_CHANS +#define LOG_REMOTE_CHANS 0 +#endif + +#ifndef LOG_LOCAL_CHANS +#define LOG_LOCAL_CHANS 1 +#endif + +#ifndef CHANNEL_PIPES +#define CHANNEL_PIPES 0 +#endif + +#include <lib.h> +#include <pov.h> +#include <daemons.h> +#include <origin.h> +#include <message_class.h> +#include "include/chat.h" + +inherit LIB_DAEMON; + +string suspect,site,chan; +static private mapping Channels; +static private mapping chanlast; + +static private string *local_chans = ({}); +static private string *remote_chans = ({}); +static string *syschans = ({}); + +static private mapping localchans = ([ + //I3 Channels + "imud_code": "intercre", + "imud_gossip": "intergossip", + "ie_flibcode": "foundation", + "dead_test4": "ds_test", + "dead_souls": "ds", + + //IMC2 Channels + "Server02:igame": "i2game2", + "Server02:inews": "i2news2", + "Server01:ibuild": "ibuild2", + "Server01:ichat": "ichat2", + "Server01:pchat": "pchat2", + "Server01:i2game": "i2game2", + "Server01:i2chat": "i2chat2", + "Server01:i3chat": "i3chat2", + "Server01:i2code": "i2code2", + "Server01:i2news": "i2news2", + "Server01:imudnews": "imudnews2", + "Server01:irc": "irc2", + "Server01:ifree": "ifree2", + + ]); + + static private mapping remotechans = ([ + //I3 Channels + "intercre": "imud_code", + "intergossip": "imud_gossip", + "foundation": "ie_flibcode", + "dutch": "dutch", + "ds_test": "dead_test4", + "ds": "dead_souls", + + //IMC2 Channels + "i2game2": "Server02:igame", + "i2news2": "Server02:inews", + "ibuild2": "Server01:ibuild", + "ichat2": "Server01:ichat", + "pchat2": "Server01:pchat", + "i2game2": "Server01:i2game", + "i2chat2": "Server01:i2chat", + "i3chat2": "Server01:i3chat", + "i2code2": "Server01:i2code", + "i2news2": "Server01:i2news", + "imudnews2": "Server01:imudnews", + "irc2": "Server01:irc", + "ifree2": "Server01:ifree", + ]); + +static private mapping tags = ([ + "intermud" : "%^B_BLACK%^WHITE%^", + "muds" : "%^B_BLACK%^WHITE%^", + "connections" : "%^B_BLACK%^BOLD%^WHITE%^", + "death" : "%^BOLD%^RED%^", + "cre" : "%^BOLD%^GREEN%^", + "admin" : "%^BOLD%^MAGENTA%^", + "newbie" : "%^BOLD%^B_YELLOW%^", + "gossip" : "%^BOLD%^B_BLUE%^", + + "ds" : "%^YELLOW%^", + "dchat" :"%^CYAN%^", + "intergossip" : "%^GREEN%^", + "intercre" : "%^ORANGE%^", + + "ibuild2" : "%^B_RED%^%^YELLOW%^", + "ichat2" : "%^B_RED%^%^GREEN%^", + "pchat2" : "%^B_RED%^%^BOLD%^GREEN%^", + "i2game2" : "%^B_BLUE%^", + "i2chat2" : "%^B_GREEN%^", + "i3chat2" : "%^B_RED%^", + "i2code2" : "%^B_YELLOW%^%^RED%^", + "i2news2" : "%^B_YELLOW%^%^BLUE%^", + "imudnews2" : "%^B_YELLOW%^%^CYAN%^", + "irc2" : "%^B_BLUE%^%^GREEN%^", + "ifree2" : "%^B_BLUE%^%^GREEN%^", + + "default" : "%^BOLD%^BLUE%^", + "default-IMC2" : "%^BOLD%^WHITE%^%^B_BLUE%^", + ]); + +static void Setup(){ + mixed rchan2 = ({}); + mixed rchan3 = ({}); + remote_chans = ({}); + local_chans = ({"newbie","cre","gossip","admin","error", "intermud", + "death", "connections", "muds" }); + syschans = ({ "intermud", "death", "connections", "muds" }); + + local_chans += CLASSES_D->GetClasses(); + + if(find_object(INTERMUD_D)){ + if(arrayp(INTERMUD_D->GetChannels())) + rchan3 += distinct_array(INTERMUD_D->GetChannels()); + } + if(find_object(IMC2_D)){ + if(arrayp(IMC2_D->GetChanList())) + rchan2 += distinct_array(IMC2_D->GetChanList()); + } + + foreach(mixed foo in local_chans){ + if(!stringp(foo)){ + local_chans -= ({ foo }); + } + } + + rchan3 = sort_array(filter(rchan3, (: stringp($1) :)), 1); + rchan2 = sort_array(filter(rchan2, (: stringp($1) :)), 1); + + foreach(mixed bar in ({ rchan3, rchan2 })){ + foreach(mixed foo in bar){ + string svr, cnl; + if(!stringp(foo) || member_array(foo, local_chans) != -1){ + bar -= ({ foo }); + continue; + } + if(sscanf(foo, "%s:%s", svr, cnl) == 2){ + if(member_array(cnl, local_chans) == -1 && !localchans[cnl] && + member_array(cnl, rchan3) == -1){ + localchans[foo] = cnl; + remotechans[cnl] = foo; + } + } + } + } + remote_chans = distinct_array((rchan3 + rchan2)); + local_chans = distinct_array(local_chans); +} + +static void create() { + object pl; + string *tmp_arr = ({}); + daemon::create(); + SetNoClean(1); + Channels = ([]); + + call_out("Setup", 10); + + foreach(string kanal in local_chans + syschans){ + if( !Channels[kanal] ) Channels[kanal] = ({}); + } + foreach(pl in users()) { + string *chans; + string channel; + + if( pl && !(chans = pl->GetChannels()) ) continue; + foreach(channel in chans) { + if( !Channels[channel] ) Channels[channel] = ({}); + Channels[channel] = distinct_array(Channels[channel] + ({ pl })); + } + } + foreach( string channel in local_chans ){ + tmp_arr += ({ channel + "emote" }); + tmp_arr += ({ channel + ":" }); + } + + local_chans += tmp_arr; +} + +string *AddRemoteChannel(mixed chan){ + string *ret = copy(remote_chans); + if(base_name(previous_object()) != INTERMUD_D) return ret; + if(stringp(chan)) chan = ({ chan }); + if(!arrayp(chan)) return ret; + foreach(string element in chan){ + if(member_array(element, local_chans) != -1){ + chan -= ({ element }); + } + } + return copy(remote_chans = distinct_array(remote_chans += chan)); +} + +string *AddLocalChannel(mixed chan){ + string *ret = copy(local_chans); + if(base_name(previous_object()) != PARTY_D) return ret; + if(stringp(chan)) chan = ({ chan }); + if(!arrayp(chan)) return ret; + foreach(string element in chan){ + if(member_array(element, local_chans) != -1){ + chan -= ({ element }); + } + } + return copy(local_chans = distinct_array(local_chans += chan)); +} + +string *RemoveRemoteChannel(mixed chan){ + string *ret = copy(remote_chans); + if(base_name(previous_object()) != INTERMUD_D) return ret; + if(stringp(chan)) chan = ({ chan }); + if(!arrayp(chan)) return ret; + foreach(string element in chan){ + if(member_array(element, local_chans) != -1){ + chan -= ({ element }); + } + } + return copy(remote_chans = distinct_array(remote_chans -= chan)); +} + +string *RemoveLocalChannel(mixed chan){ + string *ret = copy(local_chans); + if(base_name(previous_object()) != PARTY_D) return ret; + if(stringp(chan)) chan = ({ chan }); + if(!arrayp(chan)) return ret; + foreach(string element in chan){ + if(member_array(element, local_chans) != -1){ + chan -= ({ element }); } + } + return copy(local_chans = distinct_array(local_chans -= chan)); +} + +varargs string *GetRemoteChannels(int localized){ + mixed *ret = ({}); + if(!localized) return copy(remote_chans); + foreach(string chan in remote_chans){ + ret += ({ GetLocalChannel(chan) }); + } + return ret; +} + +string decolor(string str){ + string s1 = "", s2, s3, test; + int tmp = 2; + if(sscanf(str,"%s<%s>%s",s1,s2,s3) != 3) + tmp = sscanf(str,"<%s>%s",s2,s3); + if(tmp != 2) return str; + else { + test = s1+"<"+s2+">%^RESET%^"+strip_colours(s3); + return test; + } +} + +varargs int CanListen(object who, string canal){ + if(!RESTRICTED_INTERMUD) return 1; + if(canal && member_array(canal, local_chans) != -1) return 1; + else return imud_privp(who); +} + +varargs int CanTalk(object who, string canal){ + if(!RESTRICTED_INTERMUD) return 1; + if(canal && member_array(canal, local_chans) != -1) return 1; + else return imud_privp(who); +} + +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 "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 cmdLast(string feep){ + + if(!chanlast||!Channels[feep]||member_array(this_player(), Channels[feep])==-1){ + + this_player()->eventPrint("You are not subscribed to that channel.", MSG_ERROR); + return 1; + } + if(!sizeof(chanlast[feep])) + { + this_player()->eventPrint("That channel has no backlog.", MSG_ERROR); + return 1; + } + if(!CanListen(this_player(),feep)){ + write("You lack privileges to that channel."); + return 1; + } + this_player()->eventPrint(implode(chanlast[feep], "\n")); + return 1; +} + +static int LogIt(string what, string where, string canale){ + if( (member_array(canale,local_chans) != -1 && LOG_LOCAL_CHANS) || + ( member_array(GetRemoteChannel(canale),remote_chans) != -1 && LOG_REMOTE_CHANS) ){ + unguarded( (: write_file($(where), $(what)) :) ); + return 1; + } + else return 0; +} + +varargs int eventAddLast(string feep, string str, string pchan, string pmsg, string pwho) +{ + string plainmsg; + string Chan=feep; + if(!chanlast) + chanlast=([]); + if(!sizeof(chanlast[Chan])) + chanlast[Chan] = ({}); + if(sizeof(chanlast[Chan]) == 50) + chanlast[Chan] = chanlast[Chan][1..sizeof(chanlast[Chan])]; + chanlast[Chan] += ({ str }); + Chan = GetLocalChannel(Chan); + + if (Chan == "death") return 1; + + //Log in either SQL or file +#ifdef MYSQL + if (MYSQL_D->sql_request("INSERT INTO LOG_CHAT (Channel,Who,What) VALUES (\'"+ escape(pchan) +"\',\'" + escape(pwho) + "\',\'" + escape(pmsg) + "\')") == 0) { + true(); + } +#endif + Chan = GetLocalChannel(Chan); + if(!pchan || pchan == "") pchan = "foo"; + plainmsg = "bar"; + if(pchan) plainmsg = "<" + pchan + "> "; + if(pmsg) plainmsg += pmsg; + if(pwho && pwho !="") plainmsg = pwho+" "+plainmsg; + if(pchan && pchan != "admin"){ + LogIt("["+timestamp()+"] "+plainmsg+"\n", "/log/chan/"+Chan, Chan); + } + else { + LogIt("["+timestamp()+"] "+plainmsg+"\n", "/secure/log/"+Chan, Chan); + } + return 1; +} + +int cmdChannel(string verb, string str){ + string msg, name, rc, target, targetkey, target_msg, emote_cmd, remains; + string *exploded; + mixed array msg_data; + object ob = 0; + int i, emote, forcedemote; + + if(grepp(verb,"|")){ + string foo, bar; + + if(CHANNEL_PIPES){ + if(grepp(verb,"|morse")){ + str = morse(str); + verb = replace_string(verb,"|morse",""); + } + + if(grepp(verb,"|colorize")){ + str = dbz_colors(str); + verb = replace_string(verb,"|colorize",""); + } + + if(grepp(verb,"|annoy")){ + str = dbz_colors(str,2); + verb = replace_string(verb,"|annoy",""); + } + if(grepp(verb,"|file")){ + if(!file_exists(str) || !(str = read_file(str))){ + write("Can't read that file."); + return 0; + } + verb = replace_string(verb,"|file",""); + } + } + + if(sscanf(verb, "%s|%s", foo, bar) == 2) verb = foo; + } + + if(grepp(verb, ":")){ + string *tmpv = explode(verb, ":"); + if(!sizeof(tmpv)) tmpv = ({"newbie"}); + verb = tmpv[0]+"emote"; + if(sizeof(tmpv) > 1) str = implode(tmpv[1..], ":") + str; + } + + if(grepp(verb, ";")){ + string *tmpv = explode(verb, ";"); + if(!sizeof(tmpv)) tmpv = ({"newbie"}); + verb = tmpv[0]+"forcedemote"; + if(sizeof(tmpv) > 1) str = implode(tmpv[1..], ";") + str; + } + + if(sizeof(str) > 2){ + if((str[0..0] == ":" || str[0..0] == ";") && + alphap(str[1..1]) && str[2..2] != " "){ + if(str[0..0] == ";" && !grepp(verb,"forcedemote")) + verb = replace_string(verb,"emote","") + "forcedemote"; + else if(str[0..0] == ":" && !grepp(verb,"emote")) verb += "emote"; + str = str[1..]; + } + } + + //******LIST****** + //allow "list <chan>" to list users listening + if( verb == "list" ) { + string *who; + string ch, mud; + + if( !str ) return 0; + + //Find the remote listing for a channel on a specific mud + if( sscanf(str, "%s@%s", ch, mud) == 2 ) { + mud = trim(mud); + if(!alphap(last(mud,1))) mud = truncate(mud,1); + + if( !Channels[ch] ) return 0; + + if( member_array(this_player(), Channels[ch]) == -1 ) return 0; + + if( ch == (ch = GetRemoteChannel(ch)) ) { + if(!creatorp(this_player())){ + write("Remote channel information is not available to players."); + return 1; + } + } + + if( !(mud = INTERMUD_D->GetMudName(mud)) ) { + this_player()->eventPrint(mud_name() + " is not aware of "+ + "such a place.", MSG_ERROR); + return 1; + } + + if(!CanTalk(this_player(),verb)) { + write("You lack privileges to that channel."); + return 1; + } + SERVICES_D->eventSendChannelWhoRequest(ch, mud); + this_player()->eventPrint("Remote listing request sent.", + MSG_SYSTEM); + return 1; + } + else ch = str; + + //If no such channel, or not a part of that channel, then no list. + if( !Channels[ch] ) return 0; + if( member_array(this_player(), Channels[str]) == -1 ) return 0; + + //Build and print the list of listeners + who = GetChannelList(str); + msg = "Online: " + implode(who, " "); + this_player()->eventPrint(msg, MSG_SYSTEM); + return 1; + } + //******END LIST****** + + + //All emotes will fall into this IF structure and get tagged + //as emote = 1 or forcedemote = 1 + + //If it's a verb+emote, de-emote the verb, and mark as an emote + if(grepp(verb, "emote")) { + //Get the real channel + if(grepp(verb, "forcedemote")){ + verb = replace_string(verb,"forcedemote",""); + forcedemote = 1; + } + else verb = replace_string(verb,"emote",""); + emote = 1; + } + + if(!strsrch(str,"^encode")) str = morse("(encoded): "+str[7..]); + + if(find_object(INTERMUD_D) && !sizeof(remote_chans)) + remote_chans = distinct_array(INTERMUD_D->GetChannels()); + + if(member_array(GetRemoteChannel(verb), remote_chans) == -1 && + member_array(verb, local_chans) == -1) local_chans += ({ verb }); + + //******Access Checks + //No talking if you're not allowed. + if ( !CanTalk(this_player(),verb) ) { + write("You lack privileges to that channel."); + return 1; + } + //Toggle channel blocking + if ( emote == 1 && ( !str || str == "" ) ) { + this_player()->SetBlocked(verb + "emote"); + return 1; + } else if ( !str || str == "" ) { + this_player()->SetBlocked(verb); + return 1; + } + //Syschans aren't for chatting on, only listening + if ( member_array(verb, syschans) != -1 ) { + write("This is not a channel for chatting."); + return 1; + } + //If gagged, you can't talk on channels + if ( this_player()->GetGagged(verb) ) { + write("You have gag mode enabled. Type: 'gag off' to talk on channels."); + return 1; + } + //Channel doesn't exist, probably an emote typo + if(!Channels[verb]) return 0; + //If not part of the channel, no chatting + if( member_array(this_player(), Channels[verb]) == -1 ) return 0; + //If blocked, allow no chatting + if( this_player()->GetBlocked(verb) ) { + if( this_player()->GetBlocked("all") ) { + this_player()->eventPrint("You cannot chat while totally blocked.", + MSG_ERROR); + return 1; + } + this_player()->eventPrint("Turn this channel on to talk on it.", MSG_ERROR); + return 1; + } + //******End Access Checks + + //If there's no channel matching now, then it's a typo or wasn't meant for this file to pick up. + if( !Channels[verb] ) return 0; + //Find the remote channel's name, based on the local, pretty name + rc = GetRemoteChannel(verb); + //Check emotes + if (emote == 1) { + exploded = explode(str, " "); //BOOM!!! We have an array of words. + if (sizeof(exploded) <= 1) { + emote_cmd = str; + remains = 0; + } else { + emote_cmd = exploded[0]; + remains = implode(exploded[1..]," "); + } + + //*********************************** + //Find a target for targetted emotes. + //*********************************** + if( !remains ) { //If no arguments and just one word + msg_data = SOUL_D->GetChannelEmote(emote_cmd, ""); //Search for a feeling that matches + } else { //If there is an argument to the emote, + if( ob = find_living(target = convert_name(remains)) ) { //If there is a living target + msg_data = SOUL_D->GetChannelEmote(emote_cmd, "LIV"); + //If it's not there, get the emote's LVS text. + //if (!msg_data) + // msg_data = SOUL_D->GetChannelEmote(emote_cmd, "LVS", remains); + } else if( strsrch(target, "@") == -1 ) { //If no living target + 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; + } + //If it's not there, get the emote's LVS STR text. + if (!msg_data) + msg_data = SOUL_D->GetChannelEmote(emote_cmd, "LVS STR", remains); + break; + } + } + if( !ob ) { + msg_data = SOUL_D->GetChannelEmote(emote_cmd, "STR", remains); + target = 0; + } + + } else { + string array words; + + //Find any @'s in the remains.. Should be User@Mud + i = strsrch(remains, "@", -1); + + //If there's not enough room for a proper name@mud, just do it as a string + if ( i >= strlen(remains)-1 ) { + msg_data = SOUL_D->GetChannelEmote(emote_cmd, "STR", remains); + target = 0; + } else { //Otherwise, call mud and find user + string mud,temp; + words = explode(remains[(i+1)..], " "); + target = remains[0..i]; + remains = ""; + while(sizeof(words)) { + temp = implode(words, " "); + temp = trim(temp); + if(!alphap(last(temp,1))) temp = truncate(temp,1); + mud = INTERMUD_D->GetMudName(lower_case(temp)); + if (!mud) mud = IMC2_D->find_mud(lower_case(temp)); + if( mud ) { + target += mud; + break; + } + if( remains == "" ) remains = words[<1]; + else remains = words[<1] + " " + remains; + words = words[0..<2]; + } + + //If we couldn't find the mud, + 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); + } + } + } + } + } //Done finding target + + //*********************************** + //Find the target's proper name and target the message at him/her. + //*********************************** + + if ( msg_data ) { //There's a target + string sgen = this_player()->GetGender(); + string tgen = 0; + + if ( ob ) { //If a local user + target = ob->GetName(); + tgen = ob->GetGender(); + } else if ( target ) { //If a mud user + 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); + } + + //Calculate the viewpoint for 3rd parties + str = create_message(POV_OBSERVER, msg_data[0][0], + msg_data[0][1], "$N", sgen, "$O", tgen, + msg_data[1]); + + //If it's targetted, calculate the message for the target + if ( target ) { + target_msg = create_message(POV_TARGET, msg_data[0][0], + msg_data[0][1], "$N", sgen, + "$O", tgen, msg_data[1]); + target_msg = replace_string(target_msg, "$O's", "your"); + } + } else { //There's no target. Spurt it out like the user put it in. + //Forced emotes only allow real emotes, not custom ones. + if (forcedemote == 1) { + if ( member_array( emote_cmd,SOUL_D->GetEmotes() ) > -1 ) { + write("Invalid syntax. See %^CYAN%^help "+emote_cmd+"%^RESET%^ for a list of usages."); + return 1; + } else { + write("No such feeling. See %^CYAN%^help feelings%^RESET%^ for a list of feelings."); + return 1; + } + } else { + str = "$N " + str; + target = 0; + } + } + } + + //If admin or cre channels, Capitalize a person's real name, because admins can be physically hidden + if( verb == "admin" || verb == "cre" ) { + if( !(name = this_player()->GetCapName()) ) + name = capitalize(this_player()->GetKeyName()); + } + else name = this_player()->GetName(); + //Add the "Name" $N to the string + if(!grepp(str,"$N") && emote) str = "$N "+str; + //Send locally + eventSendChannel(name, verb, str, emote, target, target_msg); + //If it's a remote channel, send it remotely. + if(member_array(GetRemoteChannel(verb), remote_chans) != -1 + && member_array(verb, local_chans) == -1){ + if (grepp(GetRemoteChannel(verb),":")) { //It's an IMC2 channel + if(IMC2_D->getonline() != 1){ + return 1; + } + name = replace_string(name, " ", ""); + if( ob ) { + IMC2_D->channel_out(name, rc, replace_string(replace_string(str,"$N ",""),"$O",target), emote); + } else if ( targetkey ) { + IMC2_D->channel_out(name, rc, replace_string(replace_string(str,"$N ",""),"$O",targetkey), emote); + } else { + IMC2_D->channel_out(name, rc, replace_string(str,"$N ",""), emote); + } + } else { //It's an I3 channel + if( ob ) { + SERVICES_D->eventSendChannel(name, rc, str, emote, convert_name(target), target_msg); + } else { + SERVICES_D->eventSendChannel(name, rc, str, emote, convert_name(targetkey), target_msg);; + } + } + } + return 1; +} + +varargs void eventSendChannel(string who, string ch, string msg, int emote, + string target, string targmsg) { + object channeler = find_player(lower_case(who)); + int terminal; + string prev = base_name(previous_object()); + string pchan,pmsg; + string chatlayout = "%s %s<%s>%s %s"; + string emotelayout = "%s<%s>%s %s"; + //string chatlayout = "%s says, %s(%s)%s '%s'"; + //string emotelayout = "%s(%s)%s %s"; + + if(prev == INSTANCES_D){ + terminal = 1; + } + if(prev == SERVICES_D) terminal = 1; + if(prev == IMC2_D) terminal = 1; + if(!terminal){ + string rch = GetRemoteChannel(ch); + if(member_array(rch, remote_chans) == -1){ + INSTANCES_D->eventSendChannel(who,ch,msg,emote,target,targmsg); + } + } + + pchan=ch; + if(!channeler) channeler = this_player(); + if(!strsrch(msg,"-.--. . -. -.-. --- -.. . -.. -.--.- ---...")) msg = unmorse(msg); + if(targmsg && !strsrch(targmsg,"-.--. . -. -.-. --- -.. . -.. -.--.- ---...")) + targmsg = unmorse(targmsg); + + if(this_player() && this_player() != channeler) channeler = this_player(); + + if(!strsrch(base_name(previous_object()), "/realms/") || + !strsrch(base_name(previous_object()), "/open/")) { + return 0; + } + + if(member_array(ch, syschans) != -1) { + emote = 0; + } + if(channeler){ + if(!CanTalk(channeler, ch) && member_array(ch, syschans) == -1){ + return; + } + } + if( file_name(previous_object()) == SERVICES_D || + file_name(previous_object()) == IMC2_D) { + ch = GetLocalChannel(ch); + if( emote && sizeof(who)) msg = replace_string(msg, "$N", who); + } + else if( origin() != ORIGIN_LOCAL && previous_object() != master() && + file_name(previous_object()) != PARTY_D && + file_name(previous_object()) != UPDATE_D && + file_name(previous_object()) != INSTANCES_D && + member_array(ch, syschans) == -1){ + return; + } + prev = file_name(previous_object()); + if(!Channels[ch] && prev != SERVICES_D && prev != INSTANCES_D){ + return; + } + if( emote ) { + object *obs; + object ob; + string this_msg, tmp; + + if( target && (ob = find_player(convert_name(target))) ) { + target = ob->GetName(); + } + + //Colorize emote channels + if (member_array(lower_case(ch),keys(tags)) >= 0){ + this_msg = tags[lower_case(ch)]; + } else { + if(member_array(ch, local_chans) < 0 && (prev == IMC2_D || + member_array(ch, (keys(INTERMUD_D->GetChannelList()) + || ({}))) < 0)){ + this_msg = tags["default-IMC2"]; //Use the default IMC2 entry + } + else { + this_msg = tags["default"]; //Use the default entry + } + } + + 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")); + } + + //Put together the channel emote message + tmp = sprintf(emotelayout, this_msg, ch, "%^RESET%^", msg); + + //Store message in the history list + eventAddLast(ch, tmp, pchan, msg); + + if(Channels[ch]){ + obs = filter(Channels[ch], (: $1 && !($1->GetBlocked($(ch))) :)); + foreach(object listener in obs) { + int ignore; + if(sscanf(who,"%s@%s",suspect,site) < 2) { + suspect = who; + site = "@"+mud_name(); + } + else site = "@"+site; + if( listener == ob ) continue; + if(sizeof(listener->GetMuffed())) + foreach(string jerk in listener->GetMuffed()){ + if(jerk && lower_case(suspect) == lower_case(jerk)){ + ignore = 1; + } + if(jerk && lower_case(site[1..]) == lower_case(jerk)){ + ignore = 1; + } + } + if(listener->GetNoChanColors()) tmp = decolor(tmp); + if(!ignore && CanListen(listener,ch) && + !(listener->GetMuted(ch))){ + listener->eventPrint(tmp, MSG_CHAN); + } + ignore = 0; + } + if( member_array(ob, obs) != -1 ) { + if( ob && !(ob->GetBlocked(ch)) ) { + int ignore; + tmp = sprintf(emotelayout, this_msg, ch, "%^RESET%^", targmsg); + if(sizeof(ob->GetMuffed())) + foreach(string jerk in ob->GetMuffed()){ + if(jerk && lower_case(suspect) == lower_case(jerk)) ignore = 1; + if(jerk && lower_case(site[1..]) == lower_case(jerk)) ignore = 1; + } + if(ob->GetNoChanColors()) tmp = decolor(tmp); + if(!ignore && CanListen(ob,ch)&& !(ob->GetMuted(ch))) + ob->eventPrint(tmp, MSG_CHAN); + ignore = 0; + } + } + } + suspect = ""; + site = ""; + } + else { + object *obs; + string chancolor; + + //Colorize flag + if (member_array(lower_case(ch),keys(tags)) >= 0) { //If there's an entry for the channel + chancolor = tags[lower_case(ch)]; //Use it + } else { //Otherwise + if(member_array(ch, local_chans) < 0 && (prev == IMC2_D || + member_array(ch, (keys(INTERMUD_D->GetChannelList()) + || ({}))) < 0)){ + chancolor = tags["default-IMC2"]; //Use the default IMC2 entry + } + else { + chancolor = tags["default"]; //Use the default entry + } + } + + pmsg = msg; + + //Put together the channel emote message + msg = sprintf(chatlayout, who, chancolor, ch, "%^RESET%^", pmsg); + eventAddLast(ch, msg, pchan, pmsg, who); + + if(Channels[ch]) { + obs = filter(Channels[ch], (: $1 && !($1->GetBlocked($(ch))) :)); + foreach(object ob in obs){ + int ignore; + if(sscanf(who,"%s@%s",suspect,site) < 2) { + suspect = who; + site = "@"+mud_name(); + } + else site = "@"+site; + + if(sizeof(ob->GetMuffed())) + foreach(string jerk in ob->GetMuffed()){ + if(jerk && lower_case(suspect) == lower_case(jerk)) ignore = 1; + if(jerk && lower_case(site[1..]) == lower_case(jerk)) ignore = 1; + } + if(ob->GetNoChanColors()) msg = decolor(msg); + if(!ignore && CanListen(ob,ch)&& !(ob->GetMuted(ch))) + ob->eventPrint(msg, MSG_CHAN); + + ignore = 0; + suspect =""; + site = ""; + } + } + } +} + +string *GetChannelList(string ch) { + string *ret; + object who; + + 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 || who->GetInvis() || who->GetBlocked(ch) ) + continue; + ret += ({ who->GetName() }); + } + return ret; +} + +string *GetLocalChannels(){ + return copy(local_chans); +} + +string GetLocalChannel(string ch) { + if(ch && !strsrch(ch,"server0")){ + ch = replace_string(ch, "server01", "Server01"); + ch = replace_string(ch, "server02", "Server02"); + } + if (sizeof(localchans[ch])) return localchans[ch]; + else return ch; +} + +string GetRemoteChannel(string ch) { + if (sizeof(remotechans[ch])) return remotechans[ch]; + else return ch; +} + +int GetListening(object player, string ch){ + if(!Channels[ch] || + member_array(player, Channels[ch]) == -1) return 0; + return 1; +} + +string *GetChannels() { return sort_array(copy(keys(Channels)),1); } +string *GetSystemChannels() { return sort_array(copy(syschans),1); } +mapping GetTags() { return copy(tags); } +string GetTag(string ch) { return tags[ch]; } diff --git a/lib/secure/daemon/economy.c b/lib/secure/daemon/economy.c new file mode 100644 index 0000000..26b9f19 --- /dev/null +++ b/lib/secure/daemon/economy.c @@ -0,0 +1,97 @@ +// /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 <save.h> +#include <privs.h> + +inherit LIB_DAEMON; + +private mapping Currencies; +int LastInflation; +string oba; +static string SaveFile; + +static void create() { + string *borg; + float temps, tmp; + int i; + + daemon::create(); + SetNoClean(1); + Currencies = ([]); + SaveFile = save_file(SAVE_ECONOMY); + SetSaveFile(SaveFile); + if(!file_exists(SaveFile) && file_exists(old_savename(SaveFile))){ + cp(old_savename(SaveFile), SaveFile); + } + RestoreObject(SaveFile); + i = sizeof(borg = keys(Currencies)); + temps = percent(time()-LastInflation, 4800000)* 0.01; + while(i--) { + tmp = temps * Currencies[borg[i]]["inflation"]; + Currencies[borg[i]]["rate"] += tmp*Currencies[borg[i]]["rate"]; + } + LastInflation = time(); + if(sizeof(Currencies)){ + SaveObject(SaveFile); + } +} + +string ewrite(string str){ + oba = str; + unguarded( (: write_file("/save/test.txt",oba,1) :) ); + return read_file("/save/test.txt"); +} + +static private void validate() { + if( !(master()->valid_apply(({ PRIV_ASSIST }))) ){ + write(identify(previous_object(-1))); + error("Illegal attempt to modify economy data"); + } +} + + +void add_currency(string type, float rate, float infl, float wt) { + validate(); + if(!mapp(Currencies)) Currencies = ([]); + if(!type || !rate || !infl || !wt || Currencies[type]) return; + Currencies[type] = ([ "rate":rate, "inflation":infl, "weight":wt ]); + if(sizeof(Currencies)){ + SaveObject(SaveFile); + } +} + +void remove_currency(string type) { + validate(); + if(!mapp(Currencies)) return; + map_delete(Currencies, type); + if(sizeof(Currencies)){ + SaveObject(SaveFile); + } +} + + +void change_currency(string type, string key, float x) { + validate(); + if(!mapp(Currencies)) Currencies = ([]); + if(!type || !Currencies[type] || !key || !x) return; + if(!Currencies[type][key]) return; + Currencies[type][key] = x; + if(sizeof(Currencies)){ + SaveObject(SaveFile); + } +} + +float __Query(string type, string key) { + if(!Currencies[type]) return 0.0; + else return Currencies[type][key]; +} + +string *__QueryCurrencies() { + if(sizeof(Currencies)) + return keys(Currencies); + else return ({}); +} diff --git a/lib/secure/daemon/estates.c b/lib/secure/daemon/estates.c new file mode 100644 index 0000000..4dc390b --- /dev/null +++ b/lib/secure/daemon/estates.c @@ -0,0 +1,63 @@ +/* /secure/daemon/estates.c + * from Dead Souls + * a daemon for handling Estate events + * created by Descartes of Borg 940702 + */ + +#include <std.h> +//#include <security.h> +#include <objects.h> +#include <save.h> +#include "include/estates.h" + +inherit DAEMON; + +private mapping __Estates; +static string SaveFile; + +void create() { + daemon::create(); + SaveFile = save_file(SAVE_ESTATES); + __Estates = ([]); + set_no_clean(1); + if(file_exists(SaveFile)) RestoreObject(SaveFile); + preload_estates(); +} + +static private void preload_estates() { + object ob; + string *who; + string desc; + int i, j; + + i = sizeof(who = keys(__Estates)); + while(i--) { + if((j = sizeof(__Estates[who[i]])) > 1) + desc = "an estate of "+who[i]; + else desc = possessive_noun(who[i])+" estate"; + while(j--) { + ob = new(OB_ESTATE); + ob->set_short(desc); + ob->set_long(__Estates[who[i]][j][2]); + ob->set_exit(__Estates[who[i]][j][0]); + __Estates[who[i]][j][1]->set_no_clean(1); + ob->move(__Estates[who[i]][j][1]); + } + } +} + +void add_estate(string who, string sortie, string where, string long) { + object ob; + + if(base_name(previous_object()) != OB_DEED) return; + if(!__Estates[who]) __Estates[who] = ({ ({ sortie, where, long }) }); + else __Estates[who] += ({ ({ sortie, where, long }) }); + ob = new(OB_ESTATE); + ob->set_short(possessive_noun(who)+" estate"); + ob->set_long(long); + ob->set_exit(sortie); + where->set_no_clean(1); + ob->move(where); + ob->reinitiate(); + SaveObject(SaveFile); +} diff --git a/lib/secure/daemon/events.c b/lib/secure/daemon/events.c new file mode 100644 index 0000000..e982b98 --- /dev/null +++ b/lib/secure/daemon/events.c @@ -0,0 +1,197 @@ +/* /secure/daemon/events.c + * from the Dead Souls Library + * an event monitoring daemon, for call outs across time + * created by Descartes of Borg 950501 + */ + +#include <lib.h> +#include <logs.h> +#include <save.h> +#include <daemons.h> +#include <privs.h> +#include "events.h" + +inherit LIB_DAEMON; + +private int RebootInterval; +private mapping Events; +private static int InReboot = 0; +private static int i, callout = -1; +static string SaveFile; +static int *events; + +static void create() { + daemon::create(); + SaveFile = save_file(SAVE_EVENTS); + if(!file_exists(SaveFile) && file_exists(old_savename(SaveFile))){ + cp(old_savename(SaveFile), SaveFile); + } + SetNoClean(1); + if( file_exists(SaveFile) ){ + RestoreObject(SaveFile); + } + if( !RebootInterval ) RebootInterval = 170; + if( !Events ) Events = ([]); + eventSave(); + call_out((: eventPollEvents :), 60); +} + +mixed eventCancelShutdown() { + int ret = -3; +#ifdef __CALLOUT_HANDLES__ + if( !(master()->valid_apply( ({ PRIV_ASSIST }) )) ) return -2; + if(callout > -1) ret = remove_call_out(callout); + else ret = -1; + if(!ret || ret == -1) callout = -1; +#endif + return ret; +} + +varargs static int eventSave(int ung) { + return SaveObject(SaveFile); +} + +void DoSaves(){ + object *persists = objects( (: $1->GetPersistent() :) ); + foreach(object persist in persists){ + persist->eventDestruct(); + } +} + +int GetRebooting(){ + return InReboot; +} + +void eventReboot(int x){ + if( previous_object() && !(master()->valid_apply(({ PRIV_ASSIST })))){ + return; + } + InReboot = 1; + if( x < 1 ){ + x = 1; + } + x *= 60; + message("broadcast", mud_name() + " will reboot in " + + consolidate(x/60, "a minute") + ".", users()); + if( x < 61 ){ + callout = call_out( (: eventAnnounceReboot, 10 :), x - 10); + } + else { + int y; + + y = x/60; + y = ((2*y)/3) * 60; + callout = call_out( (: eventAnnounceReboot($(y)) :), x - y); + } +} + +static void eventAnnounceReboot(int x) { + if( x == 10 ) { + message("broadcast", "Last warning: Reboot in 10 seconds.", users()); + call_out( (: DoSaves :), 7 ); + callout = call_out( (: Shutdown :), 10 ); + } + else if( x < 61 ) { + message("broadcast", mud_name() + " will reboot in a minute.", + users()); + callout = call_out( (: eventAnnounceReboot, 10 :), 50); + } + else { + int y; + + message("broadcast", "Reboot in " + (x/60) + " minutes.", users()); + y = ((2 * (x/60))/3) * 60; + callout = call_out( (: eventAnnounceReboot($(y)) :), x - y); + } +} + +void eventShutdown() { + if( !(master()->valid_apply( ({ PRIV_ASSIST }) )) ) return; + Shutdown(); +} + +static void Shutdown() { + message("broadcast", "Shutting down " + mud_name() + " immediately!", + users()); + map(users(), (: catch($1->cmdQuit()) :)); + shutdown(); +} + +static void eventPollEvents() { + int x; + call_out((: eventPollEvents :), 60); + x = time(); + i = sizeof(events = keys(Events)); + while(i--) { + if( events[i] <= x ) { + object ob; + function f; + if(EVENTS_LOGGING){ + unguarded( (: write_file(LOG_EVENTS,timestamp()+" "+ + Events[events[i]]["object"]+"->"+ + Events[events[i]]["function"]+ + "("+implode(Events[events[i]]["args"], ",")+ + ")\n") :) ); + } + if( !(ob = find_object(Events[events[i]]["creator"]) ) + && !(ob = load_object(Events[events[i]]["creator"])) ) { + map_delete(Events, events[i]); + continue; + } + f = (: call_other, Events[events[i]]["object"], + Events[events[i]]["function"] :); + f = bind(f, ob); + catch(evaluate(f, Events[events[i]]["args"]...)); + if( Events[events[i]]["regular"] > 0 ) + Events[x + Events[events[i]]["interval"]] = Events[events[i]]; + map_delete(Events, events[i]); + } + } + if( (uptime() > RebootInterval*3600) && !InReboot && !DISABLE_REBOOTS) { + InReboot = 1; + eventReboot(MINUTES_REBOOT_WARNING); + } + eventSave(); +} + +int SetRebootInterval(int x) { + int y; + + y = RebootInterval; + if( x > 1 ) RebootInterval = x; + if( !eventSave() ) RebootInterval = y; + return RebootInterval; +} + +int GetRebootInterval() { return RebootInterval; } + +void AddEvent(string c, string s, string f, mixed *a, int w, int r) { + mapping NewEvent; + if( file_name(previous_object()) != SEFUN && + file_name(previous_object()) != UPDATE_D) { + if(EVENTS_LOGGING){ + unguarded( (: write_file(LOG_EVENTS,timestamp()+" "+ + identify(previous_object(-1))+ + " ILLEGALLY tried to add an event.\n") :) ); + } + return; + } + NewEvent = ([ "object" : s, "function" : f, "args" : a, + "creator" : c, "regular" : (r ? w : 0), "interval" : w ]); + if(EVENTS_LOGGING) + unguarded( (: write_file(LOG_EVENTS,timestamp()+ + identify(previous_object(-1))+" added this event: "+ + identify($(NewEvent))+"\n") :) ); + Events[time() + w] = NewEvent; + eventSave(1); +} + +void RemoveEvent(int x){ + if( file_name(previous_object()) != SEFUN ) return; + if(sizeof(Events[x])){ + map_delete(Events, x); + eventSave(1); + } +} + +mapping GetEvents() { return copy(Events); } diff --git a/lib/secure/daemon/events.h b/lib/secure/daemon/events.h new file mode 100644 index 0000000..726ce56 --- /dev/null +++ b/lib/secure/daemon/events.h @@ -0,0 +1,17 @@ +#ifndef __EVENTS_H__ +#define __EVENTS_H__ + +static void create(); +varargs static int eventSave(int ung); +void eventReboot(int x); +static void eventAnnounceReboot(int x); +void eventShutdown(); +static void Shutdown(); +static void eventPollEvents(); + +int SetRebootInterval(int x); +int GetRebootInterval(); +void AddEvent(string c, string s, string f, mixed a, int w, int r); +mapping GetEvents(); + +#endif /* __EVENTS_H__ */ diff --git a/lib/secure/daemon/file.c b/lib/secure/daemon/file.c new file mode 100644 index 0000000..50b3cf1 --- /dev/null +++ b/lib/secure/daemon/file.c @@ -0,0 +1,185 @@ +#include <lib.h> +#include <save.h> +#include <daemons.h> +#include <runtime_config.h> + +inherit LIB_DAEMON; +string *all_dirs = ({}); +string *all_files = ({}); +static string SaveFiles = save_file(SAVE_FILES); +int ftilt, dtilt; +string globaltemp; + +static mixed Report(); + +static private void validate() { + if( !(master()->valid_apply(({ "ASSIST" }))) ){ + log_file("adm/file","Illegal attempt to access FILE_D: "+get_stack()+" "+identify(previous_object(-1))+"\n"); + error("Illegal attempt to access FILE_D: "+get_stack()+" "+identify(previous_object(-1))); + } + if(query_os_type() == "windows"){ + error("The file daemon has been disabled for your mud "+ + "because it is running on windows. Intensive file operations "+ + "in windows are not yet supported on Dead Souls."); + } + if(!(MASTER_D->GetPerfOK())){ + error("Your system performance is too weak to support the "+ + "file daemon's resource-intensive operations, so file "+ + "indexing has been disabled."); + } +} + +void heart_beat(){ + foreach(mixed arr in call_out_info()){ + if(arr[0] == this_object()){ + return ; + } + } + Report(); + SaveObject(SaveFiles); + set_heart_beat(0); +} + +mixed ReadDir(string str){ + string *current_level_dirs = ({}); + int iteration = 1; +#ifndef __FLUFFOS__ + return 0; +#endif + validate(); + //log_file("adm/file","FILE_D ReadDir accessed and run by: "+identify(previous_object(-1))+"\n"); + + if(!str || !sizeof(str)) str = "/"; + + if(!query_heart_beat()) set_heart_beat(1); + if(last(str,1) != "/") str += "/"; + if(directory_exists(str)){ + foreach(string element in get_dir(str)){ + if(file_exists(str+element)) all_files += ({ str+element }); + if(directory_exists(str+element) && + strsrch(str+element,"/realms") && + strsrch(str+element,"/estates") && + strsrch(str+element,"/secure/save") && + strsrch(str+element,"/secure/log") && + strsrch(str+element,"/secure/upgrades")) { + all_dirs += ({ str+element }); + current_level_dirs += ({ str+element }); + } + } + if(sizeof(current_level_dirs)){ + foreach(string element in current_level_dirs){ + iteration++; + globaltemp = element; + call_out( (: ReadDir, globaltemp :), iteration ); + } + } + } + return 1; +} + +static mixed Report(){ + //log_file("adm/file","FILE_D Report accessed and run by: "+identify(previous_object(-1))+"\n"); + foreach(mixed arr in call_out_info()){ + if(arr[0] == this_object()){ + write("File scan is not complete."); + return 1; + } + } + all_dirs = sort_array(all_dirs,1); + reset_eval_cost(); + all_dirs = distinct_array(all_dirs); + reset_eval_cost(); + all_files = sort_array(all_files,1); + reset_eval_cost(); + all_files = distinct_array(all_files); + reset_eval_cost(); + rm("/secure/tmp/dirs.txt"); + rm("/secure/tmp/files.txt"); + foreach(string dir in all_dirs){ + reset_eval_cost(); + write_file("/secure/tmp/dirs.txt",dir+"\n"); + } + foreach(string dir in all_files){ + reset_eval_cost(); + write_file("/secure/tmp/files.txt",dir+"\n"); + } + return 1; +} + +string *GetFiles(){ + return all_files; +} + +string *GetDirs(){ + return all_dirs; +} + +int SearchFiles(string str){ + int cased = 1; + int strict = 0; + string ret = ""; +#ifndef __FLUFFOS__ + return 0; +#endif + + //log_file("adm/file",timestamp()+" FILE_D search for "+str+" run by: "+identify(previous_object(-1))+"\n"); + + if(!str || str == ""){ + write("Please specify the filename or substring you're looking for."); + return 1; + } + + if(grepp(str,"-i ")){ + cased = 0; + str = replace_string(str,"-i ",""); + } + + if(grepp(str,"-s ")){ + strict = 1; + str = replace_string(str,"-s ",""); + } + + foreach(string element in all_files){ + string tmpstr, tmpelement; + + if(!cased){ + tmpelement = lower_case(element); + tmpstr = lower_case(str); + } + else { + tmpelement = element; + tmpstr = str; + } + + if(!strict && grepp(last_string_element(tmpelement,"/"), tmpstr)) ret += element + "\n"; + else if(strict && last_string_element(tmpelement,"/") == tmpstr) ret += element + "\n"; + } + write("Matches:"); + if(sizeof(ret)) write(ret); + //write_file("/tmp/search.out", ret, 1); + else write("None."); + return 1; +} + +static void create() { + object fun_d = find_object(FUNCTION_D); +#ifndef __FLUFFOS__ + return 0; +#endif + daemon::create(); + if(!file_exists(SaveFiles) && file_exists(old_savename(SaveFiles))){ + cp(old_savename(SaveFiles), SaveFiles); + } + if(file_exists(SaveFiles)){ + RestoreObject(SaveFiles); + } + if(query_os_type() != "windows" && MASTER_D->GetPerfOK()){ + catch( ReadDir("/") ); + if(!fun_d) fun_d = load_object(FUNCTION_D); + } +} + +int eventDestruct(){ + SaveObject(SaveFiles); + return ::eventDestruct(); +} diff --git a/lib/secure/daemon/filter.c b/lib/secure/daemon/filter.c new file mode 100644 index 0000000..817235a --- /dev/null +++ b/lib/secure/daemon/filter.c @@ -0,0 +1,205 @@ +#include <lib.h> + +inherit LIB_DAEMON; + + +static void create() { + daemon::create(); +} + +string PirateFilter(string str){ + if(!str || !sizeof(str) || !stringp(str)) return ""; + if(grepp(str,"tp://")) return str; + if(lower_case(str) == "test") str = "ARRR!"; + if(lower_case(str) == "testing") str = "ARRR, I says!"; + if(lower_case(str) == "testing.") str = "ARRR!"; + if(lower_case(str) == "test.") str = "ARRR!"; + if(lower_case(str) == "hmm") str = "YARR!"; + if(lower_case(str) == "hmmm") str = "YARRR!"; + if(lower_case(str) == "?") str = "YARRR?"; + if(lower_case(str) == "...") str = "Y...A...R...R?"; + str = replace_string(str, "that's", "that be"); + str = replace_string(str, "That's", "That be"); + str = replace_string(str, "they're", "they be"); + str = replace_string(str, "They're", "They be"); + str = replace_string(str, "your ", "yer "); + str = replace_string(str, " gay ", " hamarseckshul "); + str = replace_string(str, "Your ", "Yer "); + str = replace_string(str, "you're", "ye be"); + str = replace_string(str, "You're", "Ye be"); + str = replace_string(str, "here's", "here be"); + str = replace_string(str, "Here's", "Here be"); + str = replace_string(str, "who's", "who be"); + str = replace_string(str, "Who's", "Who be"); + str = replace_string(str, "what's", "what be"); + str = replace_string(str, "What's", "What be"); + str = replace_string(str, " his ", " he "); + str = replace_string(str, "His ", "He "); + str = replace_string(str, " her ", " she "); + str = replace_string(str, "Her ", "She "); + str = replace_string(str, " is ", " be "); + str = replace_string(str, "Is ", "Be "); + str = replace_string(str, "thbe", "this"); + str = replace_string(str, "Thbe", "This"); + str = replace_string(str, "the ", "th' "); + str = replace_string(str, "The ", "Th' "); + str = replace_string(str, " am ", " be "); + str = replace_string(str, "I'm ", "I be "); + str = replace_string(str, "Im ", "I be "); + str = replace_string(str, "i'm ", "i be "); + str = replace_string(str, "ing ", "in' "); + str = replace_string(str, "ing ", "in' "); + str = replace_string(str, "ing ", "in' "); + str = replace_string(str, "ing.", "in'."); + str = replace_string(str, "in'.c", "ing.c"); + str = replace_string(str, "in'.h", "ing.h"); + str = replace_string(str, "ing!", "in'!"); + str = replace_string(str, "there", "thar"); + str = replace_string(str, "There", "Thar"); + str = replace_string(str, "you ", "ye "); + str = replace_string(str, "You ", "Ye "); + str = replace_string(str, "it is not ", "'tain't "); + str = replace_string(str, "It is not ", "'tain't "); + str = replace_string(str, "it isn't ", "'tain't "); + str = replace_string(str, "It isn't ", "'tain't "); + str = replace_string(str, "it's not ", "'tain't "); + str = replace_string(str, "It's not ", "'tain't "); + str = replace_string(str, "it is ", "'tis "); + str = replace_string(str, "It is ", "'tis "); + str = replace_string(str, "It's ", "'tis "); + str = replace_string(str, "my ", "me "); + str = replace_string(str, "My ", "me "); + str = replace_string(str, "of ", "o' "); + str = replace_string(str, "Of ", "O' "); + str = replace_string(str, "huh? ", "ehhhhh? "); + str = replace_string(str, "Huh? ", "Ehhhhh? "); + str = replace_string(str, "yes", "aye"); + str = replace_string(str, "Yes", "Aye"); + str = replace_string(str, "ayeterday", "yesterday"); + str = replace_string(str, "Ayeterday", "Yesterday"); + str = replace_string(str, "yepper ", "aye "); + str = replace_string(str, "Yepper ", "Aye "); + str = replace_string(str, "yep", "aye"); + str = replace_string(str, "Yep", "Aye"); + str = replace_string(str, "yeah", "aye"); + str = replace_string(str, "Yeah", "Aye"); + str = replace_string(str, "yea", "aye"); + str = replace_string(str, "Yea", "Aye"); + str = replace_string(str, "no ", "nay "); + str = replace_string(str, "No ", "Nay "); + str = replace_string(str, "no, ", "nay, "); + str = replace_string(str, "No, ", "Nay, "); + str = replace_string(str, "nope", "nay"); + str = replace_string(str, "Nope ", "Nay "); + str = replace_string(str, "oh ", "ARRRRR "); + str = replace_string(str, "oh, ", "ARRRRR, "); + str = replace_string(str, " and ", " 'n' "); + str = replace_string(str, " them ", " 'em "); + str = replace_string(str, " were ", " was "); + str = replace_string(str, " are ", " be "); + str = replace_string(str, " to ", " t' "); + str = replace_string(str, "who ", "'oo "); + str = replace_string(str, "Who ", "'oo "); + str = replace_string(str, " did ", " done "); + str = replace_string(str, " said", " says"); + str = replace_string(str, " doesn't ", " don't "); + str = replace_string(str, " does ", " do "); + str = replace_string(str, "hehe", "har harr"); + str = replace_string(str, "heh", "harr"); + str = replace_string(str, "they ", "them "); + str = replace_string(str, "They ", "Them "); + str = replace_string(str, "hey ", "ahoy "); + str = replace_string(str, "Hey ", "Ahoy "); + str = replace_string(str, "hello", "ahoy"); + str = replace_string(str, "Hello", "Ahoy"); + str = replace_string(str, "hi ", "ahoy "); + str = replace_string(str, "hiya", "ahoy"); + str = replace_string(str, "Hiya", "Ahoy"); + str = replace_string(str, ", guys", ", mateys"); + str = replace_string(str, "guys, ", "mateys, "); + str = replace_string(str, "Guys, ", "Mateys, "); + str = replace_string(str, "Hi ", "Ahoy "); + str = replace_string(str, "hi,", "ahoy,"); + str = replace_string(str, "Hi,", "Ahoy,"); + str = replace_string(str, "howdy,", "ahoy,"); + str = replace_string(str, "Howdy,", "Ahoy,"); + str = replace_string(str, "howdy ", "ahoy "); + str = replace_string(str, "wow", "shiver me timbers"); + str = replace_string(str, "Wow", "Shiver me timbers"); + str = replace_string(str, "WOW", "Shiver me timbers"); + str = replace_string(str, "omg", "shiver me timbers"); + str = replace_string(str, "OMG", "By Blackbeard's ghost!"); + str = replace_string(str, "omfg", "shiver me fucken' timbers"); + str = replace_string(str, "OMFG", "shiver me fucken' blasted timbers"); + str = replace_string(str, "stfu", "belay that guff"); + str = replace_string(str, "STFU", "Silence, animals!"); + str = replace_string(str, "wtf", "arr?"); + str = replace_string(str, "WTF", "ARR!?"); + str = replace_string(str, "stop", "avast"); + str = replace_string(str, "Stop", "Avast"); + str = replace_string(str, " stuff ", " booty "); + str = replace_string(str, "there", "thar"); + str = replace_string(str, "There", "Thar"); + str = replace_string(str, "lol", "Yo Ho Ho"); + str = replace_string(str, " for ", " fer "); + str = replace_string(str, "For ", "Fer "); + str = replace_string(str, "LOL", "YO HO HO"); + str = replace_string(str, "rofl", "harr harr harr"); + str = replace_string(str, "ROFL", "HARR HARR HARR"); + //str = replace_string(str, "testing", "ARRR!"); + //str = replace_string(str, "test", "ARRR"); + //str = replace_string(str, "a ARRR", "a test"); + //str = replace_string(str, "to ARRR", "to test"); + if(random(100) < 1){ + switch(random(5)){ + case 0 : str = "Avast, me hearties! "+str;break; + case 1 : str += " ARRRR!!";break; + case 2 : str = "Well blow me down! "+str;break; + case 3 : str += " YO HO HO!";break; + case 4 : str += " Wench! Grog!";break; + } + } + return str; +} + +string CurseFilter(string str){ + string orig, lowered; + int i; + string *curses; + + if(!sizeof(str)) return ""; + curses = ({"bullshit", "motherfucking", "motherfuck", + "shitty", "fucking", "fucken", "mother fucking", "mother fuck", + "damned", "god damned", "goddamned", "christing", "cunting", + "assfuck", "buttfuck", "butt fuck", "shitlick", "shit lick", + "cocklick", "cock lick", "dicklick", "dick lick", "cuntlick", + "cunt lick", "shithead", "fuckhead", "shit head", "fuck head", + "shit", "fuck", "cunt", "slut", "bastard", "asshole", + "cocksuck", "cock suck", "dicksuck", "dick suck", "suck dick", + "suck cock", "pussy", "twat", "jizz", "piss", "blowjob", + "buttsex", "butt sex", "anal sex", "faggot", "nigger", "kike", + "jap", "rimjob", "nafe", "handjob", "god damn", "goddamn", "damn", + "goddam", "whore", "son of a bitch", "bitch", "felch", "feltch", + "bukkake", "rape", "incest", "sodomy", "dildo", "christ", "jesus", + "heterosexual intercourse in the missionary position" }); + + lowered = lower_case(str); + orig = str; + + foreach(string curse in curses){ + i = sizeof(curse); + lowered = replace_string(lowered, curse, repeat_string("*", i)); + } + for(i = 0; i < sizeof(str); i++){ + if(lowered[i..i] == "*") str[i..i] = "*"; + } + return str; +} + +varargs string eventFilter(string str, string type){ + if(!str || !sizeof(str) || !stringp(str)) return ""; + if(!type) return str; + if(type == "curse") str = CurseFilter(str); + if(type == "pirate") str = PirateFilter(str); + return str; +} diff --git a/lib/secure/daemon/finger.c b/lib/secure/daemon/finger.c new file mode 100644 index 0000000..a2ab69f --- /dev/null +++ b/lib/secure/daemon/finger.c @@ -0,0 +1,190 @@ +/* /secure/daemon/finger.c + * from the Foundation II LPC Library + * gives finger information about users + * created by Descartes of Borg 950402 + * Version: @(#) finger.c 1.11@(#) + * Last modified: 96/12/14 + */ + +#include <lib.h> +#include <daemons.h> +#include <marriage.h> +#include <clock.h> +#include "finger.h" + +inherit LIB_DAEMON; + +private int LoginTime, Level, Btime, BirthTime, CreatorBirth, WhereBlock; +private string CurrentUser, Short, CapName, RealName, Email; +private string Town, Race, Gender, HostSite; +private string Class, Clan, Long; +private string Rank, WebPage, tmpfile; +private string array Titles, Religion; +private class marriage array Marriages; + +static void create() { + daemon::create(); + SetNoClean(1); +} + +static int LoadPlayer(string path){ + return unguarded( (: RestoreObject($(path)) :) ); +} + +varargs string GetFinger(string who, int html) { + mapping mail_stat; + object ob; + string ret; + mixed creator; + + tmpfile = 0; + + if( !who ) { + object array people; + string array lines = ({}); + object person; + int i; + int array screen; + + screen = this_player()->GetScreen(); + if( screen && sizeof(screen) ) i = screen[0]; else i = 80; + ret = center(mud_name(), i) + "\n\n"; + people = filter(users(), (: !($1->GetInvis()) :)); + foreach(person in people) { + string str, clas, town; + str = person->GetShort(); + if( !str ) str = person->GetName(); + if( !str ) continue; + if( creatorp(person) ) clas = "creator"; + else clas = person->GetClass(); + if( clas ) clas = capitalize(clas); + else clas = "Drifter"; + town = person->GetTown(); + if( !town ) town = "Homeless"; + str = sprintf("%:-40s %:-11s %s", str, clas, town); + lines += ({ str }); + } + ret += implode(lines, "\n"); + return ret; + } + creator = 0; + if( !user_exists(who) || (!LoadPlayer(DIR_PLAYERS "/" + + who[0..0] + "/" + who) && !(creator = LoadPlayer(DIR_CRES "/" + + who[0..0] + "/" + who))) ){ + return capitalize(who) + " is unknown to " + mud_name() + "."; + } + if( !strsrch(player_save_file(who), DIR_CRES) ) creator = 1; + ret = "%^STRONG%^" + replace_string(GetTitle(), "$N", CapName) + + "%^/STRONG%^BR%^\n"; + if( Long ) { + ret += replace_string(Long, "$N", CapName) + "%^BR%^\n"; + } + if( WebPage ) { + ret += "Home Page: %^HREF%^" + WebPage + "%^>%^"; + if( html ) { + ret += WebPage + "%^/A%^BR%^\n"; + } + else { + ret += "%^/A%^BR%^\n"; + } + } + else { + ret += "No home page.%^BR%^\n"; + } + if( creator ) { + ret += CapName + " is a " + Gender + " Creator of %^I%^" + mud_name() + + "%^/I%^.%^BR%^\n"; + ret += "Immortality Date: " + ctime(CreatorBirth) + "%^BR%^\n"; + } + else { + string yrstr; + int yr; + + ret += CapName+" the "+Gender+" "+Race+" "+(Class || "drifter"); + if( Clan ) ret += " of the " + pluralize(Clan); + if( creatorp(this_player()) && Level ) ret += " ("+Level+")"; + ret += " is a " + Rank+" of " + Town + ".%^BR%^\n"; + Btime = BirthTime - (18 * YEAR); + if( (yr = query_year(Btime)) < 0 ){ + yrstr = -yr + " BN"; + } + else { + yrstr = "" + yr; + } + ret += sprintf("Birthday: the %d%s day of %s, %s", + query_date(Btime), ordinal(query_date(Btime)), + query_month(Btime), yrstr) + "%^BR%^\n"; + } + if(!this_player() || !archp(this_player())) Email = "Unlisted"; + if( !Email ) Email = "#CHANGE"; + ret += "%^TABLE%^TR%^TD%^" + + sprintf("In real life: %:-30s %%^/TD%%^TD%%^Email: %s", RealName , + (Email[0]!='#' || (this_player(1) && archp(this_player(1)))) + ? (Email[0] == '#' ? Email[1..] : Email) : "Unlisted") + + "%^/TD%^/TR%^\n"; + ret += "%^TR%^TD%^" + + sprintf("Religion: %:-34s %%^/TD%%^TD%%^Spouse: %s", + (!creator && Religion[1]) ? Religion[1] : "Agnostic", + !sizeof(Marriages) ? "Single" : + (((class marriage)Marriages[0])->DivorceDate ? + "Divorced" : ((class marriage)Marriages[0])->Spouse)) + + "%^/TD%^/TR%^/TABLE%^\n"; + if( (ob = find_player(who)) && (!ob->GetInvis()) ) { + if( !interactive(ob) ) ret += "Currently net-dead"; + else ret += "On since " + ctime(LoginTime); + } + else ret += "Last on " + ctime(LoginTime); + if( this_player(1) && creatorp(this_player(1)) && (!AUTO_WIZ || + master()->valid_apply(({ "SECURE", "ASSIST" }))) ){ + ret += " from " + HostSite + "%^BR%^\n"; + } + else ret += "%^BR%^\n"; + mail_stat = FOLDERS_D->mail_status(who); + if( mail_stat["unread"] ) + ret += CapName + " has " + consolidate(mail_stat["unread"], + "an unread letter") + ".%^BR%^\n"; + if( unguarded( (: file_size, user_path(who) + ".project" :) ) > 0 ) + ret += "Project: %^PRE%^" + + unguarded( (: read_file, user_path(who) + ".project" :) ) + + "%^/PRE%^\n"; + if( unguarded( (: file_size, user_path(who) + ".plan" :) ) > 0 ) + ret += "Plan:%^PRE%^\n" + + unguarded( (: read_file, user_path(who) + ".plan" :) ) + "%^/PRE%^\n"; + return ret; +} + +mixed array GetRemoteFinger(string who) { + mixed array tmp; + string plan; + int creator; + object ob; + + who = convert_name(who); + creator = 0; + if( !user_exists(who) ) return 0; + else if( !RestoreObject(DIR_PLAYERS "/" + who[0..0] + "/" + who) && + !(creator = RestoreObject(DIR_CRES "/" + + who[0..0] + "/" + who)) ) return 0; + else if( !strsrch(player_save_file(who), DIR_CRES) ) creator = 1; + ob = find_player(who); + if( unguarded( (: file_size, user_path(who) + ".plan" :) ) > 0 ) { + plan = unguarded( (: read_file, user_path(who) + ".plan", 1, 5 :) ); + if( strlen(plan) ) { + plan = "Plan: (truncated to 5 lines)\n" + plan; + if( plan[<1] != '\n' ) plan += "\n"; + } + else plan = 0; + } + if(!this_player() || !archp(this_player())) Email = "Unlisted"; + if( !Email ) Email = "#CHANGE"; + tmp = ({ CapName, GetTitle(), RealName, (Email[0] != '#' ? Email : 0), + ctime(LoginTime), ((ob && interactive(ob) && !(ob->GetInvis())) ? query_idle(ob) : -1), + 0, (creator ? "Creator" : "" + Level), plan }); + return tmp; +} + +string GetTitle() { + if( Short ) return Short; + else if( Titles && sizeof(Titles) ) return Titles[0]; + else return CapName; +} diff --git a/lib/secure/daemon/finger.h b/lib/secure/daemon/finger.h new file mode 100644 index 0000000..b5a2c48 --- /dev/null +++ b/lib/secure/daemon/finger.h @@ -0,0 +1,8 @@ +#ifndef __FINGER_H__ +#define __FINGER_H__ + +static void create(); +varargs string GetFinger(string who); +string GetTitle(); + +#endif /* __FINGER_H__ */ diff --git a/lib/secure/daemon/flash_policy.c b/lib/secure/daemon/flash_policy.c new file mode 100644 index 0000000..0ed48cc --- /dev/null +++ b/lib/secure/daemon/flash_policy.c @@ -0,0 +1,78 @@ +#include NETWORK_H +#include <cfg.h> + +inherit LIB_DAEMON; + +int port = PORT_FLASH; +string policy_file = "no policy file"; + +void StartServer(); + +void create(){ + if(file_exists(CFG_FLASH_POLICY)){ + policy_file = read_file(CFG_FLASH_POLICY); + } + StartServer(); +} + +void StartServer(){ + int sockstat, listsock; + + listsock = socket_create(STREAM,"read_callback","close_callback"); + if(listsock < 0){ + debug("flash Couldn't create socket. errorcode: "+listsock); + return; + } + + sockstat = socket_bind(listsock,port); + if(sockstat < 0){ + debug("flash Couldn't bind socket. errorcode: "+sockstat); + return; + } + + sockstat = socket_listen(listsock,"listen_callback"); + if(sockstat < 0){ + debug("flash Couldn't listen on socket. errorcode: "+sockstat); + return; + } + +} + +static void listen_callback(int fd){ + int sockstat = socket_accept(fd,"read_callback","write_callback"); + + if(sockstat < 0){ + debug("flash Couldn't accept on socket. errorcode: "+sockstat); + return; + } + + debug("flash echo server: listening."); +} + +static void close_callback(int fd){ + debug("flash I'm wanting to close fd"+fd+" now."); +} + +static mixed read_callback(int fd, mixed data){ + int i; + string tmp=""; + mixed tmp2; + debug("flash fd is: "+fd); + + for(i=0;i<sizeof(data);i++){ + if(data[i] == 13) continue; + tmp2 = sprintf("%c",data[i]); + tmp += tmp2; + } + tmp2 = truncate(tmp,1); + if(bufferp(data)) debug("flash data (buffer): "+identify(read_buffer(data))); + else debug("flash data: "+identify(data)); + if(!strsrch(data,"<policy-file-request/>")){ + debug("Flash request detected."); + socket_write(fd, policy_file); + } + debug("flash closing socket "+fd); + i = socket_close(fd); + debug("flash i: "+i); + return i; +} diff --git a/lib/secure/daemon/folders.c b/lib/secure/daemon/folders.c new file mode 100644 index 0000000..1ae6087 --- /dev/null +++ b/lib/secure/daemon/folders.c @@ -0,0 +1,144 @@ +/* /daemon/postal/folders.c + * from Dead Souls + * folder management daemon + * created by Descartes of Borg 940502 + */ + +#include <lib.h> +#include <dirs.h> +#include <iips.h> +#include <daemons.h> +#include <objects.h> +#include "folders.h" + +inherit LIB_DAEMON; + +private mapping *__BoxInfo; +static private string __Folder, __Owner; + +void create() { + daemon::create(); + SetNoClean(1); + __BoxInfo = ({}); + __Folder = "new"; + __Owner = 0; +} + +static private void load_folder(string who, string folder) { + string file; + + if(who == __Owner && folder == __Folder) return; + OPTIONS_D->assure_box_exists(who); + file = sprintf("%s/%s/%s/%s", DIR_POSTAL, who[0..0], who, folder); + if(!unguarded((: file_exists, save_file(file) :))) { + __BoxInfo = ({}); + __Folder = folder; + __Owner = who; + } + else { + __Folder = folder; + __Owner = who; + if(!RestoreObject(file)) __BoxInfo = ({}); + } +} + +static private void save_folder() { + string file; + + if(!__Owner || !__Folder) return; + file= sprintf("%s/%s/%s/%s", DIR_POSTAL, __Owner[0..0], __Owner, __Folder); + SaveObject(file); +} + +mapping *query_box_info(string who, string folder) { + if(base_name(previous_object(0)) != OBJ_POST) return ({}); + load_folder(who, folder); + return __BoxInfo; +} + +void add_post(string who, string folder, mapping borg) { + string fwd, a, b, msg, tmp; + object ob, pl; + + tmp = base_name(previous_object(0)); + if(previous_object(0) != this_object() && tmp != OBJ_POST && + tmp != LOCALPOST_D) return; + if(folder=="new" && (fwd=OPTIONS_D->query_option(who, "forward")) && + strsrch(borg["subject"], "[FORWARD]") == -1) { + borg["subject"] += " [FORWARD]"; + if(sscanf(fwd, "%s@%s", a, b) == 2) { + borg["message"] = LETTERS_D->query_letter(borg["id"]); + LOCALPOST_D->send_post(borg, fwd); + return; + } + else if(user_exists(fwd)) { + this_object()->add_post(fwd, "new", borg); + return; + } + } + load_folder(who, folder); + if(__Folder != "new") borg["read"] = 1; + else borg["read"] = 0; + __BoxInfo = sort_array(__BoxInfo+({ borg }), "sort_folder",this_object()); + LETTERS_D->add_folder(__Owner, __Folder, borg["id"]); + save_folder(); + if(folder != "new") return; + if((pl=find_player(who)) && OPTIONS_D->query_option(who, "notify")) { + msg = OPTIONS_D->query_option(who, "message"); + if( !stringp(msg) ) msg = "%^RED%^%^BOLD%^New mail from $N!%^RESET%^\n"; + msg = replace_string(replace_string(msg, "$S", borg["subject"]), + "$N", capitalize(borg["from"])); + message("system", msg, pl); + } + if(pl && ob = present(POSTAL_ID, pl)) { + ob->incoming_post(); + } +} + +void delete_posts(string who, string folder, int *del) { + int i; + + if(base_name(previous_object(0)) != OBJ_POST) return; + load_folder(who, folder); + if((i = sizeof(del)) != sizeof(__BoxInfo)) return; + while(i--) { + if(del[i]) { + LETTERS_D->delete_folder(__Owner, __Folder, __BoxInfo[i]["id"]); + __BoxInfo[i] = 0; + } + } + __BoxInfo = sort_array(filter(__BoxInfo, "filter_folder", + this_object()), "sort_folder", this_object()); + save_folder(); +} + +void mark_read(string who, string folder, int x) { + if(base_name(previous_object(0)) != OBJ_POST) return; + load_folder(who, folder); + __BoxInfo[x]["read"] = 1; + save_folder(); +} + +mapping mail_status(string who) { + int unread, total, i; + + load_folder(who, "new"); + i = sizeof(__BoxInfo); + while(i--) { + total++; + if(!__BoxInfo[i]["read"]) unread++; + } + return ([ "unread" : unread, "total" : total ]); +} + +int sort_folder(mapping a, mapping b) { + string alpha, beta; + + if(!stringp(a["date"])) alpha = ""+a["date"]; + else alpha = a["date"]; + if(!stringp(b["date"])) beta = ""+b["date"]; + else beta = b["date"]; + return strcmp(beta, alpha); +} + +int filter_folder(mapping borg) { return (borg ? 1 : 0); } diff --git a/lib/secure/daemon/folders.h b/lib/secure/daemon/folders.h new file mode 100644 index 0000000..d201dbd --- /dev/null +++ b/lib/secure/daemon/folders.h @@ -0,0 +1,14 @@ +#ifndef __FOLDERS_H +#define __FOLDERS_H + +static private void load_folder(string who, string folder); +static private void save_folder(); +mapping *query_box_info(string who, string folder); +void add_post(string who, string folder, mapping borg); +void delete_posts(string who, string folder, int *del); +void mark_read(string who, string folder, int x); +mapping mail_status(string who); +int sort_folder(mapping a, mapping b); +int filter_folder(mapping borg); + +#endif /* __FOLDERS_H */ diff --git a/lib/secure/daemon/function.c b/lib/secure/daemon/function.c new file mode 100644 index 0000000..be2e71e --- /dev/null +++ b/lib/secure/daemon/function.c @@ -0,0 +1,208 @@ +#include <lib.h> +#include <save.h> +#include <daemons.h> +#include <runtime_config.h> + +inherit LIB_DAEMON; + +static string globaltmp; +static string *files = ({}); +static string SaveFuns = save_file(SAVE_FUNCTIONS); +static int seeking = 0; +static int count = 0; +mapping FileSize = ([]); +mapping FunctionCache = ([]); +mixed *Functions = ({}); +mapping LCFunctions = ([]); +mapping TmpMap = ([]); + +static private void validate() { + if(!this_player()) return 0; + if( !(master()->valid_apply(({ "ASSIST" }))) ) + error("Illegal attempt access FUNCTIONS_D: "+get_stack()+" "+identify(previous_object(-1))); + if(query_os_type() == "windows"){ + error("The functions daemon has been disabled for your mud "+ + "because it is running on windows. Intensive file operations "+ + "in windows are not yet supported on Dead Souls."); + } +} + +void heart_beat(){ + if(seeking){ + foreach(mixed arr in call_out_info()){ + if(arr[0] == this_object()){ + return ; + } + } + SaveObject(SaveFuns); + seeking = 0; + } + count++; + if(count > 700){ + SaveObject(SaveFuns); + count = 0; + } +} + +mixed SendFiles(string *arr){ + if(query_os_type() == "windows" || !(MASTER_D->GetPerfOK())){ + return 0; + } + validate(); + foreach(string sub in arr){ + reset_eval_cost(); + load_object("/secure/cmds/creators/showfuns")->cmd(sub); + } + return 1; +} + +mixed SendFiles2(string *arr){ + string prefix, file, tmpfile, ret = ""; + object ob; + mixed deffed = ({}); + int err; + + foreach(string element in arr){ + reset_eval_cost(); + if(!strsrch(element, "/lib/")){ + prefix = path_prefix(element); + file = replace_string(element, prefix, ""); + tmpfile = prefix+"/"+file+alpha_crypt(5)+time()+".c"; + write_file(tmpfile, "#pragma save_types\n", 1); + write_file(tmpfile, read_file(element)); + err = catch( ob = load_object(tmpfile) ); + if(err || !ob){ + rm(tmpfile); + tmpfile = 0; + err = catch( ob = load_object(element) ); + } + if(err || !ob) continue; + filter(functions(ob, 1), (: TmpMap[$1[0]] = $1[1..] :) ); + foreach(string fun in functions(ob)){ + if(function_exists(fun, ob) == base_name(ob)){ + deffed += ({ fun }); + } + } + foreach(string mos in deffed){ + ret += TmpMap[mos][1]+" "+mos+"("+ + implode(TmpMap[mos][2..], ", ")+")\n"; + } + } + } + return ret; +} + +mixed ReadFuns(string str){ + int interval = 0; + string *subfiles = ({}); + if(query_os_type() == "windows" || !(MASTER_D->GetPerfOK())){ + return 0; + } + validate(); + seeking = 1; + if(!str || !sizeof(str)) str = "/lib"; + + files = FILE_D->GetFiles(); + globaltmp = str; + files = filter(files, (: (!strsrch($1, globaltmp) && last($1,2) == ".c" ) :) ); + files = filter(files, (: (!sizeof(FunctionCache[$1]) || + ((sizeof(stat($1)) > 1) ? stat($1)[0] : FileSize[$1]) + != FileSize[$1]) :) ); + while(sizeof(files) > 0){ + reset_eval_cost(); + interval++; + subfiles = ({ files[0] }) ; + files -= subfiles; + call_out( (: SendFiles, subfiles :), interval); + } + return 1; +} + +static void create() { + daemon::create(); + if(!file_exists(SaveFuns) && file_exists(old_savename(SaveFuns))){ + cp(old_savename(SaveFuns), SaveFuns); + } + RestoreObject(SaveFuns); + if(query_os_type() == "windows" || !(MASTER_D->GetPerfOK())){ + return; + } + validate(); + TmpMap = ([]); + call_out((: ReadFuns,"/lib/" :), 1); + set_heart_beat(1); +} + +varargs int ReceiveFunctionData(string file, string funs, int fsize, mixed fs){ + FunctionCache[file] = funs; + FileSize[file] = fsize; + if(sizeof(fs) && arrayp(fs)){ + if(!Functions) Functions = ({}); + if(!LCFunctions) LCFunctions = ([]); + if((sizeof(Functions) + sizeof(fs)) < 64000){ + Functions += fs; + Functions = distinct_array(Functions); + foreach(string fun in fs){ + string lname = lower_case(fun); + if(!LCFunctions[lname]) LCFunctions[lname] = ({}); + LCFunctions[lname] += ({ fun }); + LCFunctions[lname] = distinct_array(LCFunctions[lname]); + } + } + } + return fsize; +} + +varargs mixed GetFunctions(string str){ + if(!str) return copy(Functions); + if(this_player() && (!FileSize[str] || stat(str)[0] != FileSize[str])) return 0; + return FunctionCache[str]; +} + +varargs mixed GetLCFunctions(string str, int subs){ + string *ret = ({}), *l_funs, *e_funs, *se_funs; + if(!LCFunctions) LCFunctions = ([]); + if(!str) return copy(LCFunctions); + str = lower_case(str); + if(!subs){ + return LCFunctions[str]; + } + l_funs = regexp(keys(LCFunctions), str); + foreach(mixed foo in l_funs){ + if(sizeof(LCFunctions[foo])) + ret += LCFunctions[foo]; + } + ret = distinct_array(ret); + e_funs = regexp(efuns(), str); + se_funs = regexp(sefuns(), str); + if(sizeof(e_funs) + sizeof(ret) < 64000) ret += e_funs; + if(sizeof(se_funs) + sizeof(ret) < 64000) ret += se_funs; + ret = sort_array(distinct_array(ret), 1); + return ret; +} + +int eventDestruct(){ + SaveObject(SaveFuns); + return ::eventDestruct(); +} + +varargs mixed GetInstances(string str, string where){ + string cooked_list = ""; + if(!where || ! sizeof(where)) where = "/lib/"; + if(!sizeof(FunctionCache)) return 0; + foreach(string key, string val in FunctionCache){ + string funex; + object cle; + if(grepp(val, str) && !strsrch(key,where)){ + if(!sizeof(key) || !unguarded( (: file_exists($(key)) :)) || + catch(cle = load_object(key)) || !cle){ + continue; + } + funex = function_exists(str, cle,1); + if(funex && !grepp(cooked_list,funex+"\n")){ + cooked_list += funex+"\n"; + } + } + } + return cooked_list; +} diff --git a/lib/secure/daemon/i3router/blacklist.cfg b/lib/secure/daemon/i3router/blacklist.cfg new file mode 100644 index 0000000..7819a0d --- /dev/null +++ b/lib/secure/daemon/i3router/blacklist.cfg @@ -0,0 +1,4 @@ +DeadSoulsWin +DeadSoulsNew +Your Mud's Name Here +Your Muds Name diff --git a/lib/secure/daemon/i3router/broadcast_chanlist.h b/lib/secure/daemon/i3router/broadcast_chanlist.h new file mode 100644 index 0000000..fb89392 --- /dev/null +++ b/lib/secure/daemon/i3router/broadcast_chanlist.h @@ -0,0 +1,33 @@ +// This file written mostly by Tim Johnson (Tim@TimMUD) + +// broadcast the chanlist-reply when a channel just now got changed... +varargs void broadcast_chanlist(string channame, string thismud){ + string name; // channel name in first loop, then mud name in later loop + string *mudses = keys(connected_muds); + mapping out=([]); // only used if whole chanlist is sent + if(thismud && thismud != "" && connected_muds[thismud]) mudses = ({ thismud }); + trr("<><><><><><><><><><>"); + trr("broadcasting chanlist to "+identify(mudses)); + trr("<><><><><><><><><><>"); +#ifdef SEND_WHOLE_CHANLIST + //trr("broadcasting chanlist to let them know about "+channame); + foreach(name in keys(channels)){ + out[name]=({ channels[name][1], channels[name][0] }); + } +#else + if(!channels[channame]) + out = ([ channame:0 ]); + else + out = ([ channame:({ channels[channame][1], channels[channame][0] }) ]); +#endif + foreach(name in mudses){ + trr("inside loop with "+name); + if(member_array("channel", keys(mudinfo[name]["services"]))!=-1){ + // only tell muds that have the "channel" service... + write_data(connected_muds[name], ({ + "chanlist-reply",5,router_name,0,name,0,channel_update_counter,out + })); + } + //trr("done with: "+name); + } +} diff --git a/lib/secure/daemon/i3router/broadcast_mudlist.h b/lib/secure/daemon/i3router/broadcast_mudlist.h new file mode 100644 index 0000000..6be47d3 --- /dev/null +++ b/lib/secure/daemon/i3router/broadcast_mudlist.h @@ -0,0 +1,143 @@ +// This file written mostly by Tim Johnson (Tim@TimMUD) + +// broadcast the mudlist when a mud just now got changed... + +static void validate(); + +static mapping BroadcastQueue = ([]); + +varargs void broadcast_mudlist(string mudname, int remote, string single){ + //string targ_mudname; + string *audience = ({}); + mixed *packet1; // for muds that use protocol 1 or 2 + mixed *packet3; // for muds that use protocol 3 + int mudstat; + + validate(); + + mudinfo_update_counter++; + + if(BroadcastQueue[mudname]) map_delete(BroadcastQueue, mudname); + + if(single && sizeof(single) && !undefinedp(connected_muds[single])){ + audience = ({ single }); + } + else audience = keys(connected_muds); + + + //trr("audience: "+identify(audience),"white"); + //trr("mud: "+mudname); + + if(mudinfo[mudname]){ + if(undefinedp(connected_muds[mudname]) && mudinfo[mudname]){ + //trr("disconnect time for "+mudname+": "+mudinfo[mudname]["disconnect_time"]); + if(!mudinfo[mudname]["disconnect_time"] && mudinfo[mudname]["connect_time"]) mudstat = -1; + else mudstat = 0; + } + else { + //trr("evidently i think we are connected."); + mudstat = -1; + } + if(!mapp(mudinfo[mudname])){ + //trr("WTF. NOT A MAPPING: "+get_stack(),"red"); + return; + } + //trr("mudstat: "+mudstat,"white"); + //trr("mud: "+identify(mudinfo[mudname]),"green"); + //trr("broadcasting mudlist to let them know about "+mudname,"red"); + packet1 = ({ "mudlist", 5, router_name, 0, 0, 0, mudinfo_update_counter,([ + mudname:({ + mudstat, + // -1=up, 0=down, n=down for n secs + mudinfo[mudname]["ip"], // ip_addr + mudinfo[mudname]["player_port"], // player_port + mudinfo[mudname]["imud_tcp_port"], // imud_tcp_port + mudinfo[mudname]["imud_udp_port"], // imud_udp_port + mudinfo[mudname]["mudlib"], // mudlib + mudinfo[mudname]["base_mudlib"], // base_mudlib + mudinfo[mudname]["driver"], // driver + mudinfo[mudname]["mud_type"], // mud_type + mudinfo[mudname]["open_status"], // open_status + mudinfo[mudname]["services"], // services + }) + ]) }); + packet3 = ({ "mudlist", 5, router_name, 0, 0, 0, mudinfo_update_counter,([ + mudname:({ + mudstat, + // -1=up, 0=down, n=down for n secs + mudinfo[mudname]["ip"], // ip_addr + mudinfo[mudname]["player_port"], // player_port + mudinfo[mudname]["imud_tcp_port"], // imud_tcp_port + mudinfo[mudname]["imud_udp_port"], // imud_udp_port + mudinfo[mudname]["mudlib"], // mudlib + mudinfo[mudname]["base_mudlib"], // base_mudlib + mudinfo[mudname]["driver"], // driver + mudinfo[mudname]["mud_type"], // mud_type + mudinfo[mudname]["open_status"], // open_status + mudinfo[mudname]["admin_email"], // admin_email + mudinfo[mudname]["services"], // services + mudinfo[mudname]["other_data"], // other_data + }) + ]) }); + } + if(!mudinfo[mudname]){ // deleted mud... + trr("%^B_RED%^%^BLACK%^No mudinfo for "+mudname); + // just send a 0 to everyone + foreach(string targ_mudname in audience){ + write_data(connected_muds[targ_mudname], ({ + "mudlist", 5, router_name, 0, targ_mudname, + 0, mudinfo_update_counter, ([mudname:0]) + }) ); + } + return; + } + if(!remote){ + if(!single){ + //trr("%^RESET%^%^B_MAGENTA%^sending IRN mudstat for "+mudname+": "+identify(mudinfo[mudname])); + trr("%^RESET%^%^B_MAGENTA%^sending IRN mudstat for "+mudname); + this_object()->SendList( ([ mudname : mudinfo[mudname] ]) ); + } + } + foreach(string targ_mudname in audience){ + int womble; + if(!sizeof(mudinfo) || !mudinfo[targ_mudname]) continue; + switch(mudinfo[targ_mudname]["protocol"]){ + case 1: + case 2: + packet1[4]=targ_mudname; + //write_data(connected_muds[targ_mudname], packet1); + call_out( (: write_data :), 1, connected_muds[targ_mudname], + packet1); + break; + case 3: + //trr("I want to write to "+targ_mudname+": "+identify(packet3)); + womble = connected_muds[targ_mudname]; + packet3[4]=targ_mudname; + //trr("I want to write to "+targ_mudname+": "+identify(packet3)); + //trr("connected_muds["+targ_mudname+"] is: "+womble); + //trr("this_object()->query_connected_fds()["+womble+"] is: "+ + //this_object()->query_connected_fds()[womble]); + + //write_data(connected_muds[targ_mudname], packet3); + call_out( (: write_data :), 1, connected_muds[targ_mudname], + copy(packet3), womble); + break; + } + } +} + +varargs void schedule_broadcast(string mudname, int remote, string single){ + validate(); + if(!BroadcastQueue) BroadcastQueue = ([]); + if(BroadcastQueue[mudname]) return; + else { + BroadcastQueue[mudname] =([]); + if(remote) BroadcastQueue[mudname]["remote"] = remote; + else BroadcastQueue[mudname]["remote"] = 0; + if(single) BroadcastQueue[mudname]["single"] = single; + else BroadcastQueue[mudname]["single"] = 0; + call_out( (: broadcast_mudlist :), 10, + mudname, BroadcastQueue[mudname]["remote"], + BroadcastQueue[mudname]["single"] ); + } +} diff --git a/lib/secure/daemon/i3router/clean_fd.h b/lib/secure/daemon/i3router/clean_fd.h new file mode 100644 index 0000000..0a4f8a1 --- /dev/null +++ b/lib/secure/daemon/i3router/clean_fd.h @@ -0,0 +1,7 @@ +string clean_fd(string fd){ + if(grepp(fd," ")){ + string *ip_split=explode(fd," "); + fd = ip_split[0]; + } + return fd; +} diff --git a/lib/secure/daemon/i3router/core_stuff.h b/lib/secure/daemon/i3router/core_stuff.h new file mode 100644 index 0000000..4a19c5b --- /dev/null +++ b/lib/secure/daemon/i3router/core_stuff.h @@ -0,0 +1,112 @@ +#ifndef IMC2_SERVER_ENABLED +#define IMC2_SERVER_ENABLED 0 +#endif +#ifndef ROUTER_NAME +#define ROUTER_NAME "Alpha" +#endif + +#include NETWORK_H +#include <daemons.h> +#include <save.h> + +int heart_count = 0; + +string router_port; +static mixed alternates = ({}); +static int allow_multi_routers = 0; + +static void create(){ + object rsock = find_object(RSOCKET_D); + object ssock = find_object(SSOCKET_D); + object sserver = find_object(IMC2_SERVER_D); + + if(irn_enabled && allow_multi_routers){ + foreach(string key, mixed val in routers){ + mixed tmp = ({ ({ key, val["ip"] + " " + val["port"] }) }); + if(key != "*dalet"){ + alternates += tmp; + } + alternates = sort_array(alternates, 1); + } + } + if(!rsock){ + server_log("Strange. No rsocket."); + catch( rsock = load_object(RSOCKET_D) ); + rsock->irn_clear(); + } + if(!ssock && IMC2_SERVER_ENABLED){ + server_log("Strange. No ssocket."); + catch( ssock = load_object(SSOCKET_D) ); + } + if(!sserver && IMC2_SERVER_ENABLED){ + server_log("Strange. No sserver."); + catch( sserver = load_object(IMC2_SERVER_D) ); + } + if(!rsock && (!ssock || !sserver)) return; + SetNoClean(1); + connected_muds = ([]); + unguarded( (: RestoreObject, SAVE_ROUTER, 1 :) ); + if(!mudinfo) mudinfo = ([]); + if(!mudinfo_updates) mudinfo_updates = ([]); + if(!mudinfo_update_counter) mudinfo_update_counter = 1; + if(!listening) listening = ([]); + if(!channels) channels = ([]); + if(!channel_updates) channel_updates = ([]); + if(!channel_update_counter) channel_update_counter = 1; + if(!router_name) router_name = "*yatmim"; + if(!router_port) router_port = "9000"; + if(!router_ip) router_ip = "149.152.218.102"; + if(sizeof(alternates)) router_list = alternates; + if(mud_name() == "Frontiers" || mud_name() == "*yatmim") + router_list = ({ ({"*i4", "204.209.44.3 8080"}) }); + server_log("Created when mud uptime = " + time_elapsed(uptime()) + "\n"); + server_log("rsocket uptime = " + time_elapsed(time()-RSOCKET_D->GetInceptDate()) + "\n"); + call_out("setup", 1); + call_out("LocalHostedChans", 15); + this_object()->purge_crud(); + this_object()->check_discs(); + this_object()->build_ok_ips(); + set_heart_beat(10); + if(file_exists(ROUTER_BLACKLIST)){ + blacklisted_muds += read_big_file(ROUTER_BLACKLIST); + blacklisted_muds = singular_array(blacklisted_muds); + //tc(identify(sizeof(blacklisted_muds))); + } + this_object()->check_blacklist(); + trr("Current info:\n"+this_object()->get_info(1)); +} + +void heart_beat(){ + heart_count++; + this_object()->send_pings(); + this_object()->irn_checkstat(); + this_object()->check_graylist(); + if(!(heart_count % 60)) { + this_object()->check_discs(); + this_object()->check_desync(); + SaveObject(SAVE_ROUTER); + } + if(!(heart_count % 3600)){ + object imc2d = find_object(IMC2_SERVER_D); + this_object()->clean_ghosts(); + this_object()->clean_chans(); + this_object()->clear_discs(); + this_object()->check_blacklist(); + if(imc2d){ + mapping imcmuds = (imc2d->query_mudinfo() || ([]) ); + if(sizeof(imcmuds)) this_object()->clear_discs(keys(imcmuds)); + } + } + if(heart_count > 90000){ + heart_count = 0; + this_object()->clean_ghosts(1); + } +} + + static void setup(){ + if( file_size( SAVE_ROUTER __SAVE_EXTENSION__ ) > 0 ) + unguarded( (: RestoreObject, SAVE_ROUTER, 1 :) ); + call_out("SetList",1); + } + +int query_prevent_shadow(object ob){ return true(ob); } diff --git a/lib/secure/daemon/i3router/debug.h b/lib/secure/daemon/i3router/debug.h new file mode 100644 index 0000000..82bccd9 --- /dev/null +++ b/lib/secure/daemon/i3router/debug.h @@ -0,0 +1,24 @@ +// This file written mostly by Tim Johnson (Tim@TimMUD) + + varargs void Debug(string str, int level){ + if(find_player(DEBUGGER_GUY)) + switch(level){ + case DEB_IN: + message("//trr", "%^BOLD%^%^WHITE%^SERVER INCOMING: %^MAGENTA%^"+str+"%^RESET%^\n", + find_player(DEBUGGER_GUY)); + break; + case DEB_OUT: + message("//trr", "%^BOLD%^%^WHITE%^SERVER OUTGOING: %^CYAN%^"+str+"%^RESET%^\n", + find_player(DEBUGGER_GUY)); + break; + case DEB_INVALID: + message("//trr", "%^BOLD%^%^WHITE%^SERVER THINKS THIS IS INVALID: %^RED%^"+str+"%^RESET%^\n", + find_player(DEBUGGER_GUY)); + break; + case DEB_OTHER: + default: + message("//trr", "%^BOLD%^%^WHITE%^SERVER INFO: %^GREEN%^"+str+"%^RESET%^\n", + find_player(DEBUGGER_GUY)); + break; + } + } diff --git a/lib/secure/daemon/i3router/funcs.h b/lib/secure/daemon/i3router/funcs.h new file mode 100644 index 0000000..f1e6a07 --- /dev/null +++ b/lib/secure/daemon/i3router/funcs.h @@ -0,0 +1,10 @@ +// This file written mostly by Tim Johnson (Tim@TimMUD) + +static mapping muds_on_this_fd(int fd){ + return filter_mapping(connected_muds,"value_equals",this_object(),fd); +} +int value_equals(string a,int b, int c){ return b==c; } +static mapping muds_not_on_this_fd(int fd){ + return filter_mapping(connected_muds,"value_equals",this_object(),fd); +} +int value_not_equals(string a,int b, int c){ return b!=c; } diff --git a/lib/secure/daemon/i3router/hosted_channels.h b/lib/secure/daemon/i3router/hosted_channels.h new file mode 100644 index 0000000..9f2bbdc --- /dev/null +++ b/lib/secure/daemon/i3router/hosted_channels.h @@ -0,0 +1,33 @@ +int LocalHostedChans(){ + validate(); + + process_channel(1, ({ "channel-add", 5, + "Frontiers", "cratylus", + router_name, 0, "dead_souls", 0 }) ); + + process_channel(1, ({ "channel-add", 5, + "Frontiers", "cratylus", + router_name, 0, "dead_test4", 0 }) ); + + process_channel(1, ({ "channel-add", 5, + "Frontiers", "cratylus", + router_name, 0, "dchat", 0 }) ); + + process_channel(1, ({ "channel-add", 5, + "Frontiers", "cratylus", + router_name, 0, "imud_gossip", 0 }) ); + + process_channel(1, ({ "channel-add", 5, + "Frontiers", "cratylus", + router_name, 0, "imud_code", 0 }) ); + + process_channel(1, ({ "channel-add", 5, + "Frontiers", "cratylus", + router_name, 0, "lpuni", 0 }) ); + + process_channel(1, ({ "channel-add", 5, + "Frontiers", "cratylus", + router_name, 0, "free_speech", 0 }) ); + + return 1; +} diff --git a/lib/secure/daemon/i3router/irn.h b/lib/secure/daemon/i3router/irn.h new file mode 100644 index 0000000..b100a76 --- /dev/null +++ b/lib/secure/daemon/i3router/irn.h @@ -0,0 +1,853 @@ +#include NETWORK_H +#include <save.h> +#include <daemons.h> +#include <secrets.h> + +static string my_name = ROUTER_NAME; +static string my_password = IRN_PASSWORD; +static string *ok_ips = ({}); +static string *desynced = ({}); +static int irn_reconnect = 0; +static int irn_timeout = 120; +static int irn_maxtry = 32; +static int convert_channel = 1; +static int convert_channel2 = 0; +static int last_check = time() + random(1000); +mapping PingMap = ([]); + +#ifndef PRODUCTION_ROUTER +static int irn_enabled = 0; +static int irn_ping_enabled = 0; +static mapping routers = ([ + "*i6" : ([ "ip" : "149.152.218.102", "port" : 25, "password" : IRN_PASSWORD1 ]), + "*i5" : ([ "ip" : "204.209.44.3", "port" : 8180, "password" : IRN_PASSWORD2 ]), + ]); +#else +static int irn_enabled = 1; +static int irn_ping_enabled = 1; +static mapping routers = ([ + //"*wpr" : ([ "ip" : "195.242.99.94", "port" : 8080, "password" : IRN_PASSWORD1 ]), + "*i4" : ([ "ip" : "204.209.44.3", "port" : 8080, "password" : IRN_PASSWORD2 ]), + "*dalet" : ([ "ip" : "97.107.133.86", "port" : 8787, "password" : IRN_PASSWORD3 ]) + ]); +#endif + +static mapping chan_conv = ([ + //"*adsr" : ([ "imud_gossip" : "free_speech" ]), + //"*i4" : ([ "free_speech" : "imud_gossip", "imud_gossip" : "free_speech" ]), + //"*yatmim" : ([ "free_speech" : "imud_gossip", "imud_gossip" : "free_speech" ]), + //"*krakatoa" : ([ "free_speech" : "imud_gossip", "imud_gossip" : "free_speech" ]), + //"*stroggili" : ([ "imud_gossip" : "free_speech" ]) + ]); + +mapping irn_connections = ([]); +mapping irn_sockets = ([]); + +static void write_data(int fd, mixed data); +static varargs void SendList(mixed data, int fd, string type); +varargs void SendWholeList(int fd,string type); +static void begin_socket_handoff(int i); + +void build_ok_ips(){ + ok_ips = ({}); + if(irn_enabled){ + foreach(mixed key, mixed val in routers){ + if(key == my_name) continue; + ok_ips += ({ routers[key]["ip"] }); + } + ok_ips = singular_array(ok_ips); + } +} + +void irn_checkstat(){ + int setuptype = 0; + mixed sstat; + if(!irn_enabled || !sizeof(routers)) return; + + build_ok_ips(); + + foreach(mixed key, mixed val in routers){ + if(key != my_name && (!irn_connections[key] || irn_connections[key]["fd"] == -1)){ + trr("irn_checkstat: hmmm no irn_connections["+key+"]? see: "+identify(irn_connections)); + foreach(mixed key2, mixed val2 in mudinfo){ + if(val2["router"] == key && !mudinfo[key2]["disconnect_time"]){ + trr(key+" is down, removing its mud: "+key2); + this_object()->disconnect_mud(key2, 1); + } + } + } + } + + foreach(mixed key, mixed val in irn_sockets){ + sstat = socket_status(key); + if(!sstat || sstat[1] != "DATA_XFER"){ + trr("IRN checkstat: removing socket record for: "+identify(key)); + trr("it is: "+identify(sstat),"red"); + map_delete(irn_sockets, key); + } + + if(!irn_connections[val["name"]] || + irn_connections[val["name"]]["fd"] != key){ + trr("IRN checkstat: there is a conflicted record in irn_sockets."); + } + } + + foreach(mixed key, mixed val in irn_connections){ + if(!PingMap) PingMap = ([]); + if(!key ||!sizeof(key)|| !val) continue; + + if(irn_ping_enabled && key != my_name && + (time() - PingMap[key]) > irn_timeout ){ + trr("IRN ping timeout for "+key+"!","red"); + trr("Last ping was "+time_elapsed(time() - PingMap[key])+" ago."); + if(irn_connections[key] && irn_connections[key]["fd"]){ + map_delete(irn_sockets, irn_connections[key]["fd"]); + map_delete(irn_connections, key); + this_object()->irn_setup(0, key); + return; + } + } + + if(!irn_sockets[irn_connections[key]["fd"]] || + irn_sockets[irn_connections[key]["fd"]]["name"] != key || + (sstat && sstat[1] != "DATA_XFER")){ + trr("IRN checkstat: removing socket and connection record for: "+identify(key)); + trr("it is: "+identify(sstat),"green"); + map_delete(irn_sockets, irn_connections[key]["fd"]); + map_delete(irn_connections,key); + return; + } + } + + foreach(mixed key, mixed val in irn_sockets){ + int restart; + + sstat = socket_status(key); + if(!sstat || sstat[1] != "DATA_XFER"){ + trr("IRN checkstat: removing socket record for: "+identify(key)); + trr("it is: "+identify(sstat),"blue"); + map_delete(irn_sockets, key); + restart = 1; + } + if(sizeof(irn_connections) && irn_connections[irn_sockets[key]["name"]] && irn_connections[irn_sockets[key]["name"]]["fd"] != key){ + trr("IRN checkstat: removing conflicted connection and socket "+key); + map_delete(irn_sockets, irn_connections[irn_sockets[key]["name"]]["fd"]); + map_delete(irn_connections, irn_sockets[key]["name"]); + map_delete(irn_sockets, key); + restart = 1; + } + + if(restart){ + trr("%^B_BLUE%^I be wantin to restart "+val["name"]+".\nrouters: "+identify(routers)); + if(sizeof(routers) > 2) this_object()->irn_setup(0, val["name"]); + return; + } + else setuptype = 1; + } + + if(!sizeof(irn_connections) || !sizeof(irn_sockets)){ + trr("IRN scheduling an IRN socket clear","red"); + setuptype = 1; + } + + foreach(mixed key, mixed val in irn_connections){ + if(!sizeof(key) || !sizeof(val)) map_delete(irn_connections, key); + } + + if((sizeof(routers) -1) != sizeof(irn_connections)){ + string *stragglers = ({}); + trr("expected "+(sizeof(routers) -1)+" connections, "+identify(routers)); + trr("got: "+sizeof(irn_connections)+", "+identify(irn_connections)); + foreach(string key, mixed val in routers){ + if(key != my_name && + member_array(key, keys(irn_connections)) == -1){ + stragglers += ({ key }); + } + } + trr("stragglers: "+identify(stragglers)); + foreach(string key in stragglers){ + trr("reload irn for "+key); + this_object()->irn_setup(0, key); + } + } + if((time() - last_check) > 90000){ + call_out("SendWholeList", 0, 0, "mudlist"); + call_out("SendWholeList", 1800, 0, "chanlist"); + last_check = time() + random(3600); + } +} + +void check_desync(){ + if(sizeof(desynced)){ + desynced = singular_array(desynced); + foreach(string rtr in desynced){ + tc(rtr+" desynced"); + this_object()->SendListReq(rtr, "mudlist"); + desynced -= ({ rtr }); + } + } +} + +static int GoodPeer(int fd, mixed data){ + string ip = explode(socket_address(fd)," ")[0]; + if(!irn_enabled) return 0; + if(member_array(ip,ok_ips) == -1){ + server_log("irn: bad ip: "+ip); + server_log("ok_ips: "+identify(ok_ips)); + return 0; + } + + if(!data || !arrayp(data) || member_array(data[2], keys(routers)) == -1){ + trr("IRN: unknown peer"); + return 0; + } + if(data[4] != my_name){ + trr("IRN: they don't know my name. I am "+my_name+". They think I am: "+identify(data[4])); + return 0; + } + + if(data[6]["client_password"] != routers[data[2]]["password"]){ + trr("IRN: wrong client password"); + return 0; + } + if(data[6]["server_password"] != my_password){ + trr("IRN: wrong server password"); + return 0; + } + if(!irn_connections[data[2]]) irn_connections[data[2]] = ([]); + irn_connections[data[2]]["fd"] = fd; + return 1; +} + +varargs static int ValidatePeer(int fd, mixed data, int outbound){ + string ip = explode(socket_address(fd)," ")[0]; + mixed tmp; + mixed name; + if(!irn_enabled) return 0; + if(member_array(ip,ok_ips) == -1){ + server_log("IRN: bad ip: "+ip); + server_log("ok_ips: "+identify(ok_ips)); + return 0; + } + if(!arrayp(data) || sizeof(data) < 5){ + trr("IRN ValidatePeer: bad packet"); + return 0; + } + if(!outbound) name = data[2]; + else name = data[4]; + if(mapp(name)) name = name["name"]; + if(!outbound && !irn_connections[name]){ + trr("IRN ValidatePeer: no such connection."); + return 0; + } + if(member_array(name, keys(routers)) == -1){ + trr("IRN ValidatePeer: "+identify(name)+" unknown peer"); + return 0; + } + if(this_object()->query_connected_fds()[fd]){ + trr("IRN ValidatePeer: lol mud"); + this_object()->irn_close_callback(fd); + return 0; + } + if(sizeof(tmp = irn_connections[name])){ + if(!mapp(tmp)){ + trr("IRN ValidatePeer: wtf"); + return 0; + } + if(tmp["fd"] != fd){ + trr("validation. fd: "+fd+", tmp: "+identify(tmp),"red"); + trr("LOLOLOLOLOL","red"); + return 0; + } + } + return 1; +} + +static string id_mud(int fd){ + string *ret = ({}); + foreach(mixed element in keys(irn_connections)){ + if(irn_connections[element]["fd"] == fd) ret += ({ element }); + } + return implode(ret,", "); +} + + void irn_clear(){ + if(sizeof(irn_connections)) + foreach(mixed key, mixed val in irn_connections){ + if(!key || !sizeof(key)) continue; + if(!irn_connections[key] || !irn_connections[key]["fd"]) continue; + this_object()->close_connection(irn_connections[key]["fd"]); + irn_connections[key]["connected"] = 0; + } + if(sizeof(irn_sockets)) + foreach(mixed key, mixed val in irn_sockets){ + if(!key || !sizeof(key)) continue; + this_object()->close_connection(key); + } + + irn_connections = ([]); + irn_sockets = ([]); + + foreach(string key, mixed val in routers){ + if(!key || !sizeof(key)) continue; + if(key == my_name){ + continue; + } + } + SaveObject(SAVE_ROUTER); + } + +varargs void irn_setup(int clear, string whom){ + mapping which = ([]); + if(!PingMap) PingMap = ([]); + + server_log("%^RESET%^irn_setup("+clear+(whom ? (", "+whom ):"")+"): "+get_stack()); + foreach(mixed key, mixed val in PingMap){ + if(key == my_name || member_array(key,keys(routers)) == -1) map_delete(PingMap,key); + } + + if(!irn_enabled) return; + + if(clear){ + if(sizeof(irn_connections)) + foreach(mixed key, mixed val in irn_connections){ + if(!irn_connections[key] || !irn_connections[key]["fd"]) continue; + irn_connections[key]["connected"] = 0; + this_object()->close_connection(irn_connections[key]["fd"]); + } + if(sizeof(irn_sockets)) + foreach(mixed key, mixed val in irn_sockets){ + this_object()->close_connection(key); + } + irn_clear(); + } + + if(whom) which = ([ whom : routers[whom] ]); + else which = routers; + + foreach(string key, mixed val in which){ + if(key == my_name){ + continue; + } + ok_ips += ({ routers[key]["ip"] }); + server_log("ok_ips: "+identify(ok_ips)); + if(!irn_connections[key]){ + foreach(mixed key2, mixed val2 in mudinfo){ + if(val2["router"] && val2["router"] == key && + !mudinfo[key2]["disconnect_time"]){ + trr(key+" is down, disconnecting: "+key2,"red"); + this_object()->disconnect_mud(key2, 1); + } + } + } + } + + foreach(string name in keys(which)){ + int tmp_fd, sockstat; + + if(name == my_name){ + continue; + } + trr("About to try connecting to: "+identify(name)); + + tmp_fd = socket_create(MUD, "irn_read_callback","irn_close_callback"); + if(tmp_fd < 0){ + trr("irn: Couldn't create socket. errorcode: "+socket_error(tmp_fd)); + return; + } + + irn_connections[name] = ([]); + sockstat = socket_bind(tmp_fd, 0); + trr("socket_bind: "+sockstat); + + if(sockstat < 0){ + trr("irn: Couldn't bind socket. errorcode: "+socket_error(sockstat)); + return; + } + + irn_connections[name]["fd"] = tmp_fd; + irn_sockets[tmp_fd] = (["name" : name]); + + sockstat = socket_connect(irn_connections[name]["fd"], routers[name]["ip"]+" "+ + routers[name]["port"], "irn_read_callback", "irn_write_callback"); + trr("socket_connect: "+sockstat); + + if(sockstat < 0){ + trr("irn: Couldn't connect to "+name+", errorcode: "+socket_error(sockstat)); + this_object()->close_connection(irn_connections[name]["fd"]); + irn_connections[name]["fd"] = -1; + } + this_object()->Report(); + begin_socket_handoff(tmp_fd); + trr("%^B_WHITE%^Initiating eventSendStartup callout for "+tmp_fd); + call_out( "eventSendStartup", 5, tmp_fd); + } +} + +varargs void eventSendStartup(int fd){ + mixed *targets = ({}); + mixed *packet; + if(!irn_enabled) return; + trr("irn: hit eventSendStartup","yellow"); + trr("irn: hit eventSendStartup: "+get_stack(),"green"); + if(!fd) targets = keys(irn_connections); + else if(irn_sockets[fd] && irn_sockets[fd]["name"]) targets = ({ irn_sockets[fd]["name"] }); + else targets = keys(irn_connections); + if(!sizeof(targets)){ + call_out( "irn_setup", 5, 1 ); + return; + } + this_object()->Report(); + foreach(mixed element in targets){ + if(irn_connections[element]["connected"]) continue; + irn_connections[element]["connected"] = 1; + + packet = ({ + "irn-startup-req", + 5, + my_name, + "foo", + element, + "bar", + ([ "client_password" : my_password, "server_password" : routers[element]["password"] ]) + }); + if(ValidatePeer(irn_connections[element]["fd"], packet, 1)){ + trr("irn: sending statup to "+element+" on fd "+ + irn_connections[element]["fd"]+", aka "+identify(connected_muds[fd])); + write_data(irn_connections[element]["fd"], packet); + call_out( "SendWholeList", 10, irn_connections[element]["fd"]); + } + } +} + +static void irn_write_callback(int fd){ +} + +static void irn_close_callback(int fd){ + if(!irn_enabled) return; + if(irn_connections[id_mud(fd)]){ + irn_connections[id_mud(fd)]["fd"] = -1; + irn_connections[id_mud(fd)]["connected"] = 0; + } + trr("irn_sockets: "+identify(irn_sockets)); + trr("map_delete of "+fd); + map_delete(irn_sockets, fd); + trr("irn_sockets: "+identify(irn_sockets)); + trr("I'm wanting to close "+id_mud(fd)+" on fd"+fd+" now."); +} + +static void irn_read_callback(int fd, mixed data){ + int i; + string tmp=""; + mapping MudList = ([]); + if(!irn_enabled) return; + if(this_object()->query_mudinfo()) + MudList = this_object()->query_mudinfo(); + else MudList = ([ "wt" : "f" ]); + if(!data || !sizeof(data)){ + trr("irn: no data"); + } + else { + if(bufferp(data)){ + for(i=0;i<sizeof(data);i++){ + tmp += sprintf("%c",data[i]); + } + } + } + switch(data[0]){ + case "irn-startup-req" : + trr("IRN got a startup request on fd"+fd); + if(!GoodPeer(fd, data)) return; + trr("IRN startup from "+data[2]+" accepted."); + if(sizeof(irn_connections)){ + foreach(mixed key, mixed val in irn_connections){ + if(key == data[2] && fd != irn_connections[key]["fd"]){ + map_delete(irn_sockets, irn_connections[key]["fd"]); + } + } + } + if(sizeof(irn_sockets)) + foreach(mixed key, mixed val in irn_sockets){ + trr("IRN: looking at: "+key+" "+identify(val),"cyan"); + if(val["name"] == data[2]){ + if(fd != key){ + map_delete(irn_sockets, key); + } + } + } + if(!irn_connections[data[2]]) irn_connections[data[2]] = ([]); + irn_connections[data[2]]["fd"] = fd; + irn_connections[data[2]]["connected"] = 1; + trr("irn_connections[\""+data[2]+"\"][\"fd\"]: "+irn_connections[data[2]]["fd"]); + irn_sockets[fd] = ([ "name" : data[2] ]); + call_out( "SendWholeList", 5, fd); + trr(data[2]+" has joined IRN on socket "+fd); + PingMap[data[2]] = time(); + trr("%^B_GREEN%^STARTUP COMPLETE: irn_connections: "+identify(irn_connections)); + trr("%^B_GREEN%^STARTUP COMPLETE: irn_sockets: "+identify(irn_sockets)); + this_object()->clean_ghosts(); + return; + case "irn-mudlist-altered" : + if(!ValidatePeer(fd, data)) { + trr("irn: peer failed validation."); + this_object()->close_connection(fd); + if(irn_sockets[fd]) map_delete(irn_sockets, fd); + irn_checkstat(); + return; + } + PingMap[data[2]] = time(); + this_object()->ReceiveList(data[7],"mudlist",data[2]); + break; + case "irn-mudlist-delta" : + if(!ValidatePeer(fd, data)) { + trr("irn: peer failed validation."); + this_object()->close_connection(fd); + if(irn_sockets[fd]) map_delete(irn_sockets, fd); + irn_checkstat(); + return; + } + PingMap[data[2]] = time(); + this_object()->ReceiveList(data[7],"mudlist",data[2]); + break; + case "irn-chanlist-altered" : + trr("irn: received irn-chanlist-altered"); + if(!ValidatePeer(fd, data)) { + trr("irn: peer failed validation."); + this_object()->close_connection(fd); + if(irn_sockets[fd]) map_delete(irn_sockets, fd); + irn_checkstat(); + return; + } + PingMap[data[2]] = time(); + this_object()->ReceiveList(data[7],"chanlist",data[2]); + break; + case "irn-chanlist-delta" : + trr("irn: got chanlist delta"); + if(!ValidatePeer(fd, data)) { + trr("irn: peer failed validation."); + this_object()->close_connection(fd); + if(irn_sockets[fd]) map_delete(irn_sockets, fd); + irn_checkstat(); + return; + } + trr("this_object()->ReceiveList("+identify(data[7])+", chanlist, "+identify(data[2])); + PingMap[data[2]] = time(); + this_object()->ReceiveList(data[7],"chanlist",data[2]); + break; + case "irn-mudlist-req" : + if(!ValidatePeer(fd, data)) { + trr("irn-data: peer on fd"+fd+" failed validation."); + this_object()->close_connection(fd); + if(irn_sockets[fd]) map_delete(irn_sockets, fd); + irn_checkstat(); + return; + } + PingMap[data[2]] = time(); + trr("\nresponding to irn-mudlist-req from "+fd+"\n"); + this_object()->SendWholeList(fd, "mudlist"); + break; + case "irn-data" : + if(!ValidatePeer(fd, data)) { + trr("irn-data: peer on fd"+fd+" failed validation."); + this_object()->close_connection(fd); + if(irn_sockets[fd]) map_delete(irn_sockets, fd); + irn_checkstat(); + return; + } + PingMap[data[2]] = time(); + if(convert_channel && !strsrch(data[6][0],"chan") && strsrch(data[6][0],"chan-user")){ + if(irn_sockets[fd] && irn_sockets[fd]["name"] && chan_conv[irn_sockets[fd]["name"]]){ + foreach(string key, string val in chan_conv[irn_sockets[fd]["name"]]){ + data[6][6] = replace_string(data[6][6],key,val); + } + } + } + if(!MudList[data[6][2]] || !MudList[data[6][2]]["connect_time"]){ + desynced += ({ data[2] }); + desynced = singular_array(desynced); + } + trr("irn_read_callback sending read_callback("+ + identify(data[6][2])+", "+identify(data[6])+")"); + this_object()->read_callback(data[6][2],data[6]); + break; + case "irn-ping" : + if(!ValidatePeer(fd, data)){ + trr("irn: "+data[2]+" failed validation."); + this_object()->close_connection(fd); + if(irn_sockets[fd]) map_delete(irn_sockets, fd); + irn_checkstat(); + return; + } + PingMap[data[2]] = time(); + break; + default : + if(!ValidatePeer(fd, data)) { + trr("irn: Invalid peer: "+identify(socket_status(fd)),"red"); + this_object()->close_connection(fd); + if(irn_sockets[fd]) map_delete(irn_sockets, fd); + if(irn_connections[data[2]]) map_delete(irn_connections, data[2]); + return; + } + PingMap[data[2]] = time(); + if(arrayp(data[6])) this_object()->read_callback(data[6][2],data[6]); + return; + } +} + +static varargs void SendList(mixed data, int fd, string type){ + int *targets = ({}); + string *cmuds = this_object()->query_connected_muds(); + mixed *outbound = ({}); + mapping tmp = ([]); + if(!type || !sizeof(type)) type = "irn-mudlist-delta"; + if(type == "mudlist") type = "irn-mudlist-delta"; + if(type == "chanlist"){ + type = "irn-chanlist-delta"; + this_object()->clean_chans(); + } + if(!irn_enabled) return; + if(!mapp(data)){ + trr("irn: Tried to send a non-map. guilty stack: "+get_stack(),"cyan"); + return; + } + tmp = copy(data); + if(mapp(tmp)){ + foreach(mixed key, mixed val in tmp){ + if(!mapp(val)){ + trr("irn: Non mapping val. Key: "+key+". stack: "+get_stack(),"yellow"); + trr("irn: guilty stack: "+get_stack(),"cyan"); + continue; + } + else { + if(type == "mudlist"){ + if(mudinfo[key] && mudinfo[key]["router"] && + mudinfo[key]["router"] != my_name){ + trr("Not sending "+key+"."+mudinfo[key]["router"]); + map_delete(data,key); + } + } + if(type == "chanlist"){ + true(); + } + } + } + } + if(!fd) targets = keys(irn_sockets); + else targets = ({ fd }); + foreach(int router in targets){ + if(!irn_sockets[router] || !mapp(irn_sockets[router])) continue; + write_data(router, ({ + type, + 5, + my_name, + 0, + irn_sockets[router]["name"], + 0, + time(), + data + }) ); + } +} + +varargs void SendWholeList(int fd, string type){ + mapping tmp = ([]); + int i=1; + + this_object()->clean_ghosts(); + + if(!type || !sizeof(type)) type = "mudlist"; + if(!irn_enabled) return; + if(!fd) fd = 0; + trr("SendWholeList type: "+type); + switch(type){ + case "mudlist" : + tmp = this_object()->query_mudinfo(); + break; + case "chanlist" : + tmp = this_object()->query_chaninfo(); + break; + default : + trr("irn SendWholeList error: bad type "+type); + return; + } + foreach(mixed key, mixed val in tmp){ + if(type == "mudlist") if(mapp(val)){ + i++; + call_out( (: SendList :), i, ([ key : val ]), fd, type ); + } + if(type == "chanlist"){ + if(key == "listening") continue; + foreach(mixed key2, mixed val2 in val){ + i++; + call_out( (: SendList :), i, ([ key : ([ key2 : val2 ]) ]), fd, type ); + } + } + } +} + +static void SendMessage(mixed data){ + string routername, cible; + mapping tmpinfo = this_object()->query_mudinfo(); + mixed tmpdata; + mixed *packet; + int *but; + trr("irn: received SendMessage call","white"); + if(!irn_enabled) return; + if(tmpinfo && sizeof(data) > 4 && sizeof(tmpinfo[data[4]]) && + cible = tmpinfo[data[4]]["router"]){ + if(mapp(tmpdata = this_object()->query_irn_connections()[cible])){ + but = ({ tmpdata["fd"] }); + } + } + if(!but || !sizeof(but)) but = keys(irn_sockets); + foreach(int router in but){ + trr("irn sending "+data[0]+" for "+identify(data[4])+ + " to "+identify(irn_sockets[router]["name"])); + tmpdata = copy(data); + if((convert_channel || convert_channel2) && !strsrch(tmpdata[0],"chan") && strsrch(tmpdata[0],"chan-user")){ + routername = irn_sockets[router]["name"]; + if(member_array(routername, keys(chan_conv)) != -1){ + foreach(string key, string val in chan_conv[routername]){ + if(convert_channel){ + tmpdata[6] = replace_string(tmpdata[6],val,key); + } + if(convert_channel2){ + tmpdata[6] = replace_string(tmpdata[6],key,val); + } + + } + } + } + + packet = ({ + "irn-data", + 5, + my_name, + 0, + irn_sockets[router]["name"], + 0, + tmpdata + }); + if(ValidatePeer(router, packet, 1)){ + write_data(router, packet); + } + } +} + +varargs void SendListReq(mixed rtr, string type){ + int fd; + if(!irn_enabled) return; + if(!stringp(rtr)) return; + if(!irn_connections[rtr]) return; + if(undefinedp(irn_connections[rtr]["fd"])) return; + if(irn_connections[rtr]["fd"] < 0) return; + fd = irn_connections[rtr]["fd"]; + write_data(fd, ({ + "irn-mudlist-req", + 5, + my_name, + 0, + rtr, + 0, + }) ); +} + +string Report(){ + string ret = "IRN: connections: "; + if(sizeof(irn_connections)) + foreach(mixed key, mixed val in irn_connections){ + if(!key) continue; + if(!irn_connections[key]) return; + ret += key+":"+irn_connections[key]["fd"]+" "; + } + ret += "\n"; + ret += "IRN: sockets: "; + foreach(mixed key, mixed val in irn_sockets){ + int sstat = -1; + string statmess = "DISCONNECTED"; + if(irn_connections[val["name"]]){ + sstat = irn_connections[val["name"]]["fd"]; + if(sstat > -1 && socket_status(key)){ + string *netstat = socket_status(key); + statmess = netstat[1]+" "; + statmess += last_string_element(netstat[3],"."); + statmess +=":"; + statmess += last_string_element(netstat[4],".") + " "; + } + ret += key +":"+val["name"]+":"+statmess+" "; + } + ret += "\n"; + } + ret += "ok_ips: "+identify(ok_ips)+"\n"; + foreach(mixed key, mixed val in PingMap){ + if(key == my_name) continue; + ret += key+" lastping: "+time_elapsed(time()-val)+" ago\n"; + } + return ret; +} + +static void begin_socket_handoff(int fd){ + object rsock = find_object(RSOCKET_D); + if(!irn_enabled) return; + if(!rsock) rsock = load_object(RSOCKET_D); + if(!rsock){ + trr("IRN: Socket handoff failed. Couldn't load RSOCKET_D"); + return; + } + socket_release(fd, rsock, "complete_socket_handoff"); +} + +mapping query_irn_sockets(){ + validate(); + return copy(irn_sockets); +} + +mapping query_irn_connections(){ + validate(); + return copy(irn_connections); +} + +int query_irn_enabled(){ + if(irn_enabled) return 1; + return 0; +} + +int toggle_irn(int x){ + validate(); + if(x) irn_enabled = 1; + else irn_enabled = 0; + return irn_enabled; +} + +varargs mixed irn_ping(mixed target, int code){ + if(!intp(target)){ + target = irn_connections[target]; + if(target && target["fd"]) target = target["fd"]; + else { + return 0; + } + } + + if(!irn_sockets[target]) return 0; + if(!code) code = time(); + + write_data(target, ({ + "irn-ping", + 5, + my_name, + 0, + irn_sockets[target]["name"], + 0, + time(), + code + }) ); + + return 1; +} + +int send_pings(){ + foreach(string node in keys(routers)){ + if(node == my_name) continue; + irn_ping(node); + } +} diff --git a/lib/secure/daemon/i3router/process_channel.h b/lib/secure/daemon/i3router/process_channel.h new file mode 100644 index 0000000..0cdb344 --- /dev/null +++ b/lib/secure/daemon/i3router/process_channel.h @@ -0,0 +1,325 @@ +// This file written mostly by Tim Johnson (Tim@TimMUD) +#include <save.h> +#include <daemons.h> + +#ifndef FILTER_D +#define FILTER_D "/secure/daemon/filter" +#endif + +static void process_channel(mixed fd, mixed *info){ + string mudname; + string sendermsg, sendername, senderrealname, sendermud; + string targetname, targetmud, targstr = ""; + switch(info[0][8..]){ // what is after the "channel-" + case "m": // message + case "e": // emote + case "t": // targetted emote + // (drop-through from m/e is intentional) + // Probably should check if the target is 0@0 like it should be, + // and give a warning if it's not... I don't carethough, I'll just + // ignore the target and save some CPU. + // Check if string parts are strings... + if(info[0][8..]=="t"){ + if(sizeof(info)!=13 || !stringp(info[9]) || !stringp(info[10]) || + !stringp(info[11]) || !stringp(info[12]) ||!sizeof(info[11])){ + send_error(info[2],info[3],"bad-pkt","Bad packet format.",info); + return; + } + if(!grepp(info[9],"$N")){ + info[9] = info[9] + " (from "+info[11]+"@"+info[2]+")"; + info[10] = info[10] + " (from "+info[11]+"@"+info[2]+")"; + } + sendername = info[11]; + senderrealname = info[3]; + sendermud = info[2]; + targetname = info[12]; + targetmud = info[7]; + sendermsg = info[9]; + } + else{ // m, e + if(sizeof(info)!=9 || !stringp(info[3]) || !sizeof(info[3])){ + send_error(info[2],info[3],"bad-pkt","Bad packet format.",info); + return; + } + if(!stringp(info[7]) || !sizeof(info[7])){ + info[7] = info[3]; + } + if(info[0] == "channel-e" && !grepp(info[8],"$N")) + info[8] = info[8] + " (from "+info[7]+"@"+info[2]+")"; + sendername = info[7]; + senderrealname = info[3]; + sendermud = info[2]; + sendermsg = info[8]; + } + if(targetname && targetmud) { + targstr = "Target: "+targetname+"@"+targetmud; + } + + if(info[4]!=0 || info[5]!=0 || !stringp(info[6]) || + !stringp(info[7]) || !stringp(info[8])){ + send_error(info[2],info[3],"bad-pkt","Bad packet format.",info); + return; + } + if(!channels[info[6]]){ // error, channel is not registered! + send_error(info[2],info[3],"unk-channel", + "Unknown channel: "+info[6],info); + return; + } + if(listening[info[6]] && + member_array(info[2],listening[info[6]])==-1){ + // if mud is not listening, then make them listen + // and let them know they weren't listening. + send_error(info[2],info[3],"warning", + // No applicable message codes... change + // "warning" to something else if you want. + "Your mud wasn't listening to "+info[6]+ + ", so I'll start you listening right now.",info); + // Could do all the listen stuff, or could just + // pretend they requested it... I'm gonna pretend... + process_channel(fd,({ "channel-listen", 5, info[2], 0, + router_name, 0, info[6], 1 })); + } + if(channels[info[6]][0]==2){ // filtered channel + if(channels[info[6]][1]!=info[2]){ // not from chan owner + // if from anybody else other than the owner, + // check if the owner is online, then either give + // an error, or forward to the owner... + if(undefinedp(connected_muds[channels[info[6]][1]])){ + send_error(info[2],info[3],"unk-dst", + channels[info[6]][1]+" is not online to filter "+info[6], + info); + return; + } + if(info[4]!=0 || info[5]!=0 || !stringp(info[6]) || + !stringp(info[7]) || !stringp(info[8])){ + send_error(info[2],info[3],"bad-pkt","Bad packet format",info); + return; + } + write_data(connected_muds[channels[info[6]][1]],({ + "chan-filter-req", + 5, + router_name, + 0, + channels[info[6]][1], // mud name of chan owner + 0, + info[6], + info + })); + return; + } + // IS from chan owner, just broadcast it... + // drop through and broadcast like the other types do... + } + // at this point, they're wanting to do a message on a + // selective banned/allowed channel, or else are the owner + // of a filtered channel and they have not been + // blocked, so I will just do it... + + server_log(sendername+"("+senderrealname+")@"+sendermud+" "+": "+ + sendermsg+" "+targstr+"\n",info[6]); + + if(member_array(info[2],channels[info[6]][2])!=-1){ + // in list, you're banned... + send_error(info[2],0,"not-allowed", + "Banned from "+info[6],info); + return; + } + + if(intp(fd)) this_object()->SendMessage(info); + + else if(member_array(fd, this_object()->GetBannedMuds()) != -1){ + return; + } + + info[8] = FILTER_D->eventFilter(info[8]); + + foreach(mudname in keys(connected_muds)){ + if(listening[info[6]] && member_array(mudname, listening[info[6]])!=-1) + write_data(connected_muds[mudname],info); + } + return; + case "add": + if(!stringp(info[4])) info[4] = this_object()->GetRouterName(); + // check if already exists... + if(!info[6]) return; + if(channels[info[6]]){ + send_error(info[2],info[3],"not-allowed", + "Channel already exists: "+info[6],info); + trr(info[3]+"@"+info[2]+" failed to create the channel: " + +info[6]+ " because it already exists.","red"); + return; + } + // check if a valid channel name (illegal characters? + if(!stringp(info[6]) || sizeof(info[6]) > 80){ + send_error(info[2],info[3],"not-allowed", + "Invalid channel name: "+identify(info[6]),info); + trr(info[3]+"@"+info[2]+" failed to create the channel: " + +info[6]+ "because it has an invalid name.","red"); + return; + } + // check if other stuff is valid, like channel_type is 0,1,2 + if(!intp(info[7]) || (info[7] < 0 || info[7] > 2)){ + send_error(info[2],info[3],"not-allowed", + "Invalid channel type: "+identify(info[7]),info); + trr(info[3]+"@"+info[2]+" failed to create the channel: " + +info[6]+ "because it has an invalid type.","red"); + return; + } + // at this point, is being successfully added... + channel_update_counter++; + channels[info[6]]=({ distinct_array(info[7]), info[2], ({}) }); + channel_updates[info[6]] = channel_update_counter; + server_log(info[3]+"@"+info[2]+" created the channel: "+info[6]+"\n"); + // broadcast an update saying that this channel is added or changed now + // chanlist-reply packet to everybody (who has a channel service?) + broadcast_chanlist(info[6]); + SendList( ([ "channels" : ([ info[6] : channels[info[6]] ]), + "listening" : ([]) ]), + 0, "chanlist" ); + SaveObject(SAVE_ROUTER); + return; + case "remove": + if(!stringp(info[4])) info[4] = this_object()->GetRouterName(); + if(!channels[info[6]]){ // error, channel is not registered! + send_error(info[2],info[3],"unk-channel", + "Unknown channel: "+info[6],info); + return; + } + if(channels[info[6]][1] != info[2] && + clean_fd(socket_address(fd)) != router_ip ){ + send_error(info[2],info[3],"not-allowed","Channel "+ + info[6]+" owned by: "+channels[info[6]][1],info); + return; + } + // at this point, is being removed by the owner... + channel_update_counter++; + map_delete(channels,info[6]); + map_delete(channel_updates,info[6]); + server_log(info[3]+"@"+info[2]+" deleted the channel: "+info[6]+"\n"); + // broadcast an update saying that this channel is gone now + broadcast_chanlist(info[6]); + SaveObject(SAVE_ROUTER); + SendList( ([ "channels" : ([ info[6] : -1 ]), "listening" : ([]) ]), + 0, "chanlist" ); + return; + case "admin": + if(!stringp(info[4])) info[4] = this_object()->GetRouterName(); + // add/delete muds from the 2 lists... + if(channels[info[6]][1]!=info[2] && + clean_fd(socket_address(fd)) != router_ip ){ + send_error(info[2],info[3],"not-allowed","Channel "+ + info[6]+" owned by: "+channels[info[6]][1],info); + return; + } + if(!listening[info[6]]) listening[info[6]] = ({}); + if(sizeof(info[7])){ // add to list... + channels[info[6]][2] += info[7]; + channels[info[6]][2] = distinct_array(channels[info[6]][2]); + // if add to ban list, unlisten... + if(channels[info[6]][0]==0){ // type 0 means selective ban + listening[info[6]] -= info[7]; + listening[info[6]] = distinct_array(listening[info[6]]); + } + } + if(sizeof(info[8])){ // remove from list... + channels[info[6]][2] -= info[8]; + channels[info[6]][2] = distinct_array(channels[info[6]][2]); + if(channels[info[6]][0]!=0){ // type 0 means selective ban... + // selective allow and filtered are the same though... + // so if not selective ban, then act like selective allow... + // if removed from allow list, unlisten... + listening[info[6]] -= info[8]; + listening[info[6]] = distinct_array(listening[info[6]]); + } + } + SendList( ([ "channels" : ([ info[6] : channels[info[6]] ]) ]), + 0, "chanlist" ); + SaveObject(SAVE_ROUTER); + return; + case "listen": // mudname=info[2], channame=info[6], on_or_off=info[7] + if(!channels[info[6]]){ // error, channel is not registered! + send_error(info[2],info[3],"unk-channel", + "Unknown channel: "+info[6],info); + return; + } + if(!listening) listening=([ ]); + if(!listening[info[6]]) listening[info[6]]=({ }); // first MUD to listen + if(info[7]){ // on_or_off is on + if(member_array(info[2],listening[info[6]])!=-1) + return; // already listening, ignore them + } + else{ // on_or_off is off + if(member_array(info[2],listening[info[6]])==-1) + return; // already NOT listening, ignore them + } + // only CHANGES should get to this point + switch(channels[info[6]][0]){ + case 0: // selectively banned + if(member_array(info[2],channels[info[6]][2])!=-1){ + // in list, you're banned... + send_error(info[2],0,"not-allowed", + "Banned from "+info[6],info); + return; + } + // not in ban list at this point + if(info[7]) + listening[info[6]] += ({ info[2] }); + else + listening[info[6]] -= ({ info[2] }); + listening[info[6]] = distinct_array(listening[info[6]]); + SaveObject(SAVE_ROUTER); + return; + case 1: // selectively allowed + if(member_array(info[2],channels[info[6]][2])==-1 && + info[2] != channels[info[6]][1]){ + // NOT in list, you're banned! + send_error(info[2],0,"not-allowed", + "Not in allow list for "+info[6],info); + return; + } + // in allow list at this point + if(info[7]) + listening[info[6]] += ({ info[2] }); + else + listening[info[6]] -= ({ info[2] }); + listening[info[6]] = distinct_array(listening[info[6]]); + SaveObject(SAVE_ROUTER); + return; + case 2: // filtered... act like selectively allowed + if(member_array(info[2],channels[info[6]][2])==-1 && + info[2] != channels[info[6]][1]){ + // NOT in list, you're banned! + send_error(info[2],0,"not-allowed", + "Not in allow list for "+info[6], + info); + return; + } + // in allow list at this point + if(info[7]) + listening[info[6]] += ({ info[2] }); + else + listening[info[6]] -= ({ info[2] }); + listening[info[6]] = distinct_array(listening[info[6]]); + SaveObject(SAVE_ROUTER); + return; + } // switch + default: // trying to do "channel-blah" + send_error(info[2],info[3],"unk-type","I don't know what "+info[0]+ + " means.",info); + return; + } +} + +void list_chans(){ + mapping tmp_chans = channels; + foreach(mixed key, mixed val in tmp_chans){ + trr("Key: "+identify(key)); + trr("Val: "+identify(val)); + trr("--\n","red"); + } +} + +void AddIMC2Chan(mixed fd, string name, string chan){ + if(base_name(previous_object()) != IMC2_SERVER_D) return; + process_channel(fd,({"channel-listen",5,name,0,router_name,0,chan,1})); +} diff --git a/lib/secure/daemon/i3router/process_startup_req.h b/lib/secure/daemon/i3router/process_startup_req.h new file mode 100644 index 0000000..86a7a50 --- /dev/null +++ b/lib/secure/daemon/i3router/process_startup_req.h @@ -0,0 +1,304 @@ +// This file written mostly by Tim Johnson (Tim@TimMUD) +void check_discs(); + +string *banned_muds = ({}); +mapping bad_connects = ([]); + +static void process_startup_req(int protocol, mixed info, int fd){ + // Handles startup stuff. + // Loads info into newinfo mapping. + // Error if mud is already connected. + mapping newinfo; + string site_ip; + string *brethren = ({}); + // router name is info[4], I'll just pretend I'm every router though, ha-ha! + // also, should verify that all the fields are the right type + + check_discs(); + server_log("%^BLUE%^process_startup_req: protocol="+protocol+", mud="+info[2]); + + if(member_array(info[2], banned_muds) != -1) { + server_log("%^RED%^"+info[2]+" denied. reason: banned."); + trr("---\n","blue"); + return; + } + + if(!info[2] || !sizeof(info[2])) { + server_log("%^RED%^"+info[2]+" denied. reason: null name"); + trr("---\n","blue"); + return; + } + + foreach(mixed element in keys(mudinfo)){ + if(member_array(element,keys(connected_muds)) == -1) continue; + if(mudinfo[element] && mudinfo[element]["ip"] == clean_fd(socket_address(fd))) + brethren += ({ element }); + } + trr("Number of muds with the same ip: "+sizeof(brethren)); + if(sizeof(brethren) > MAXMUDS && !mudinfo[info[2]]){ + write_data(fd,({ "error", 5, router_name, 0, info[2], 0, + "not-allowed", "Too many muds from your IP.", info }) ); + return; + } + if(member_array(fd,keys(this_object()->query_connected_fds())) != -1){ + string existing_mud = this_object()->query_connected_fds()[fd]; + trr("Socket status: "+identify(socket_status(fd)),"red"); + server_log("%^RED%^FD CONFLICT, NEW MUD: "+info[2]+", FD: "+fd); + server_log("%^RED%^FD CONFLICT, OLD MUD: "+existing_mud+", FD: "+fd); + trr("---\n","blue"); + if(mudinfo[existing_mud]){ + mudinfo[existing_mud]["disconnect_time"] = time(); + } + if(!existing_mud || existing_mud != info[2]){ + map_delete(connected_muds, existing_mud); + schedule_broadcast(existing_mud); + } + } + + if(sizeof(info)<18){ + // smallest protocol is protocol 1/2 which have size 18 + write_data(fd,({ + "error", + 5, + router_name, + 0, + info[2], + 0, + "bad-pkt", + "Bad startup_req packet", + info + })); + return; + } + site_ip=socket_address(fd); + site_ip = clean_fd(site_ip); + newinfo = ([ + "name":info[2], + "ip":site_ip, + "connect_time":time(), + "disconnect_time":0, + "password":info[6], + "old_mudlist_id":info[7], + "old_chanlist_id":info[8], + "player_port":info[9], + "imud_tcp_port":info[10], + "imud_udp_port":info[11], + "mudlib":info[12], + "base_mudlib":info[13], + "driver":info[14], + "mud_type":info[15], + "open_status":info[16], + "protocol":protocol, + "restart_delay":-1, + "router" : my_name, + ]); + + if(protocol == 2 && sizeof(info) == 20 ) protocol = 3; + + switch(protocol){ + case 1: + case 2: + if(sizeof(info)!=18){ + server_log("error: wrong size packet. Got: "+sizeof(info)+", wanted 18"); + trr("---\n","blue"); + write_data(fd,({ + "error", + 5, + router_name, + 0, + info[2], + 0, + "bad-pkt", + "Bad startup_req packet", + info + })); + return; + } + newinfo["services"]=info[17]; + newinfo["admin_email"]="Unknown"; // only in protocol 3 + newinfo["other_data"]=0; // only in protocol 3 + break; + case 3: + if(sizeof(info)!=20){ + server_log("error. wrong size packet. Got: "+sizeof(info)+", wanted 20"); + trr("---\n","blue"); + + write_data(fd,({ + "error", + 5, + router_name, + 0, + info[2], + 0, + "bad-pkt", + "Bad startup_req packet", + info + })); + return; + } + newinfo["admin_email"]=info[17]; + newinfo["services"]=info[18]; + newinfo["other_data"]=info[19]; + break; + default: + server_log("error. I dunno what."); + + write_data(fd,({ + "error", + 5, + router_name, + 0, + info[2], // mud name + 0, + "not-imp", + "unknown protocol: "+protocol, + info + })); + return; + } + // Check valid values... + if( + !stringp(newinfo["open_status"]) || + !stringp(newinfo["admin_email"]) || + !stringp(newinfo["mud_type"]) || + !stringp(newinfo["driver"]) || + !stringp(newinfo["base_mudlib"]) || + !stringp(newinfo["mudlib"]) || + !mapp(newinfo["services"]) || + !intp(newinfo["imud_udp_port"]) || + !intp(newinfo["imud_tcp_port"]) || + !intp(newinfo["player_port"]) || + !intp(newinfo["password"]) || + !intp(newinfo["old_chanlist_id"]) || + !intp(newinfo["old_mudlist_id"]) || + (!mapp(newinfo["other_data"]) && newinfo["other_data"]!=0) + ){ + write_data(fd,({ + "error", + 5, + router_name, + 0, + info[2], + 0, + "bad-pkt", + "Bad startup_req packet", + info + })); + return; + } + if(!undefinedp(connected_muds[info[2]])){ + // if MUD is already connected + trr("ROUTER_D: mud already connected on fd"+connected_muds[info[2]],"red"); + trr("ROUTER_D: Xref back: mud on fd"+connected_muds[info[2]]+" is "+ + "supposed to be "+this_object()->query_connected_fds()[this_object()->query_connected_muds()[info[2]]],"red"); + server_log("mud already connected"); + trr("---\n","blue"); + if(this_object()->query_mudinfo()[info[2]]["ip"] != explode(socket_address(fd)," ")[0] || + mudinfo[info[2]]["password"] != newinfo["password"]){ + write_data(fd,({ + "error", + 5, + router_name, + 0, + info[2], // mud name + 0, + "bad-proto", // doesn't seem to me like it should be bad-proto... + // see what the official one uses for this + // it might just boot the earlier MUD off? + "MUD already connected", // Error message + info + })); + + //This message to the already-connected mud serves + //to alert the legit mud that something may be wrong, and + //also will trigger a closure of the socket if it turns out + //to actually be in a zombie state. + write_data(connected_muds[info[2]],({ + "error", + 5, + router_name, + 0, + info[2], // mud name + 0, + "bad-mojo", + "Another mud is trying to be you.", + ({ explode(socket_address(fd)," ")[0], info[12], info[13], info[17], info[9] }) + })); + return; + } + if(this_object()->query_mudinfo()[info[2]]["ip"] == explode(socket_address(fd)," ")[0] && + mudinfo[info[2]]["password"] == newinfo["password"] ){ + server_log("Since it's the same ip and password, I'll remove the current connection"); + if(mudinfo[info[2]]) mudinfo[info[2]]["disconnect_time"] = time(); + map_delete(connected_muds, info[2]); + schedule_broadcast(info[2]); + } + } + + if(mudinfo[info[2]] && sizeof(mudinfo[info[2]]) && mudinfo[info[2]]["password"] != newinfo["password"]){ + // if MUD is already known, not connected, and wrong password + if(newinfo["ip"]==mudinfo[info[2]]["ip"]){ + // same IP as last time and it isn't Dead Souls + server_log("Wrong password, but right IP"); + trr("Expected "+mudinfo[info[2]]["password"]+ + " but got "+newinfo["password"]); + write_data(fd,({ + "error",5,router_name,0,info[2],0, + "warning", // nothing in error summary that seems applicable? + // Change later if I find a better error code + "wrong password, but I'll allow you since it's the same IP as last time",0 + })); + } + else{ + trr("wrong password, and from a new IP","red"); + trr("---\n","blue"); + if(!bad_connects[newinfo["ip"]]) bad_connects[newinfo["ip"]] = 1; + else bad_connects[newinfo["ip"]] = bad_connects[newinfo["ip"]] + 1; + if(bad_connects[newinfo["ip"]] > 100){ + trr("ROUTER_D: "+newinfo["ip"]+" blacklisted!","red"); + this_object()->AddBlacklistedMud(newinfo["ip"]); + bad_connects[newinfo["ip"]] = 0; + } + server_log("%^RED%^WRONG PASSWORD, AND FROM A NEW IP"); + write_data(fd,({ + "error", + 5, + router_name, + 0, + info[2], // mud name + 0, + "not-allowed", // Change later! + "wrong password, and from a new IP", // Error message + info + })); + return; + } + } + if(!mudinfo[info[2]] || !newinfo["password"] || mudinfo[info[2]]["password"] != newinfo["password"] ){ + // if new MUD, assign it a password + newinfo["password"]=random_numbers(9,1); + trr("ROUTER_D: Assigning password "+newinfo["password"],"white"); + // Change this maybe... see if the password is supposed to be in a certain range + } + else { + trr("ROUTER_D: password: Known: "+mudinfo[info[2]]["password"]+", current: "+newinfo["password"],"green"); + } + // MUD should be okay at this point. + mudinfo[info[2]]=newinfo; // update the mudinfo + connected_muds[info[2]] = fd; // add this MUD to list of connected muds + send_startup_reply(info[2]); // reply to MUD + mudinfo_update_counter++; + mudinfo_updates[info[2]]=mudinfo_update_counter; + send_mudlist_updates(info[2], newinfo["old_mudlist_id"]); + send_full_mudlist(info[2]); + broadcast_mudlist(info[2]); + broadcast_chanlist("foo",info[2]); + if(bad_connects[newinfo["ip"]]) bad_connects[newinfo["ip"]] = 0; + if(member_array("channel", keys(newinfo["services"])) != -1){ + + } + else { + trr("It looks like "+info[2]+" doesn't have a channel service?!?","blue"); + } + trr(timestamp()+" process_startup_req: for mud: "+info[2]+" complete.\n---\n","blue"); +} diff --git a/lib/secure/daemon/i3router/read_callback.h b/lib/secure/daemon/i3router/read_callback.h new file mode 100644 index 0000000..6078a9b --- /dev/null +++ b/lib/secure/daemon/i3router/read_callback.h @@ -0,0 +1,284 @@ +string *blacklisted_muds = ({}); +static string *graylisted_muds = ({}); +static mapping packet_counter = ([]); + +void setup_blacklist(){ + if(file_exists(ROUTER_BLACKLIST)){ + blacklisted_muds += read_big_file(ROUTER_BLACKLIST); + blacklisted_muds = singular_array(blacklisted_muds); + //tc(identify(sizeof(blacklisted_muds)),"red"); + } +} + +void read_callback(mixed fd, mixed info){ + mixed tmp; + // This is called when messages come in from a MUD. + // Should reject all messages if they have not done a (successful) startup-req, + // Should check to make sure the fd matches with the mud they are claiming to be, else error. + // because all packets require an originator_mudname. + + // If target is the name of the router, then call the function in this object. + // if target is 0, then broadcast to muds. + // Do an error if target mudname is not known. + // + + // According to: http://www.intermud.org/i3/specs/formats.php3 + // Transmissions are LPC arrays with a predefined set of six initial elements: + // ({ type, ttl, originator mudname, originator username, target mudname, target username, ... }). + // info[0]=type + // info[1]=ttl + // info[2]=originator mudname + // info[3]=originator username + // info[4]=target mudname + // info[5]=target username + + string mudname; + int i; + string *logspam = ({ "auth-mud-req", "auth-mud-reply", "tell", "emoteto", + "ping","channel-listen", "ping-req", "ping-reply" }); + string ip_addr = (stringp(fd) ? fd : clean_fd(socket_address(fd))); + + if(!packet_counter) packet_counter = ([]); + + if(!strsrch(info[0],"irn-")){ + irn_read_callback(fd, info); + return; + } + + if(info[4] && !grepp(info[0],"startup-req") && + member_array(info[4], keys(connected_muds)) == -1 && + member_array(info[2], keys(connected_muds)) == -1){ + return; + } + validate(); + if(sizeof(blacklisted_muds)){ + if(member_array(info[2], blacklisted_muds) != -1) return; + if(intp(fd)){ + if(member_array(ip_addr, blacklisted_muds) != -1) return; + foreach(string bmud in blacklisted_muds){ + if(sscanf(bmud, "%*d.%*s") && !strsrch(ip_addr, bmud)){ + return; + } + } + } + } + if(!packet_counter[info[2]]){ + packet_counter[info[2]] = ([ "time" : time(), "count" : 0 ]); + } + if(packet_counter[info[2]]["time"] != time()){ + packet_counter[info[2]]["count"] = 0; + packet_counter[info[2]]["time"] = time(); + } + if(info[0] != "channel-listen"){ + if(!strsrch(info[0], "startup-req")){ + packet_counter[info[2]]["count"] += 6; + } + else packet_counter[info[2]]["count"]++; + } + if(sizeof(graylisted_muds)){ + if((info[2] && member_array(info[2], graylisted_muds) != -1) || + (intp(fd) && member_array(ip_addr, graylisted_muds) != -1)){ + if(info[2] && member_array(info[2], keys(connected_muds)) != -1){ + if(packet_counter[info[2]]["count"] < 2){ + send_error(info[2],info[3],"not-allowed", + "Your packets are being temporarily dropped "+ + "due to flooding.", info); + } + } + return; + } + } + + if(packet_counter[info[2]]["count"] > 10 && + member_array(fd, keys(ROUTER_D->query_irn_sockets())) == -1){ + if(info[2] && member_array(info[2], keys(connected_muds)) != -1){ + send_error(info[2],info[3],"not-allowed", + "Flood detected! Your packets will be temporarily ignored.", + info); + } + graylisted_muds += ({ info[2] }); + trr("Graylisting "+identify(info[2])+" from "+ip_addr,"red"); + return; + } + if(member_array(info[0],logspam) == -1 && strsrch(info[0],"irn-")){ + string foo = "IRN"; + if(intp(fd)) foo = socket_address(fd); + trr(timestamp()+" Received from fd("+fd+"), source: "+foo+"\n"+identify(info), "green"); + } + // Base info in a packet is of size 6. + // comment out the statements below to avoid a big channel log file + if(grepp(info[0],"chan") && !grepp(info[0],"channel-listen")) + server_log(identify(info),"chan_log"); + + if(sizeof(info)<6 || + !stringp(info[0]) || + !intp(info[1]) || !stringp(info[2]) || + (!stringp(info[3]) && info[3]!=0) || + (!stringp(info[4]) && info[4]!=0) || + (!stringp(info[5]) && info[5]!=0) ) { + write_data(fd,({ + // okay, their initial data isn't fully there... + // careful about array out of bounds... + "error",5,router_name,0, + (sizeof(info)>=3 ? info[2] : 0), // mud name + (sizeof(info)>=4 ? info[3] : 0), // user name + "bad-pkt","Invalid initial data",info + })); + return; + } + if(info[4]!=0 && !mudinfo[info[4]] && info[4]!=router_name){ + // if target mud is not 0 (broadcasting), not the router name, + // and not a known MUD + write_data(fd,({ + "error", + 5, + router_name, + 0, + info[2], + info[3], + "unk-dst", // same as I3 + "destination unknown", // same as I3 + info + })); + trr("Error [unk-dst], because target is "+info[4]+" and thus invalid."); + return; + } + if(sscanf(info[0],"startup-req-%d",i)==1){ + // special condition for startup-req... + trr("calling process_startup_req, i="+i+", fd="+fd+" which is: "+socket_address(fd)); + //call_other(this_object(),"process_startup_req",i,info,fd); + this_object()->process_startup_req(i,info,fd); + return; + } + if(intp(fd) && !undefinedp(connected_muds[info[2]]) && (connected_muds[info[2]]!=fd)){ + // MUD hasn't done a startup-req yet + write_data(fd,({ + "error", + 5, + router_name, + 0, // originator username + info[2], // mud name + info[3], // user name + "unk-src", // error code + "Your MUD hasn't registered as "+info[2]+" yet", // Error message + info + })); + server_log("They have not done a startup-req for fd="+fd+", mudname="+info[2]); + return; + } + // at this point, I guess it has a valid origin and stuff + if(sscanf(info[0],"channel-%*s")==1){ // command has a "channel-" prefix + // special case for channel stuff + process_channel(fd,info); + return; + } + if(info[0]=="chan-filter-reply"){ + if(!stringp(info[6]) || sizeof(info[7])<9 ){ + // avoid out-of-bounds + send_error(info[2],info[3],"bad-pkt", + "Invalid chan-filter-reply packet.",info); + } + if(channels[info[6]][1]!=info[2]){ + send_error(info[2],info[3],"not-allowed", + "You are not the owner of "+info[6],info); + return; + } + if(member_array(info[7][6],({ "channel-a", "channel-e", "channel-t"}))==-1){ + // Not a valid channel packet. + send_error(info[2],info[3],"not-allowed","*giggles*",info); + } + if(info[6]!=info[7][6]){ + // They're trying to trick me into broadcasting + // fake messages on another channel! + // That's pretty funny :P + // I'll have to remember to check if the official router falls for it. + send_error(info[2],info[3],"not-allowed","Hehe!",info); + return; + } + if(member_array(info[7][6],({ "channel-a", "channel-e", "channel-t"}))){ + } + // Broadcast the message... + if(intp(fd)) this_object()->SendMessage(info); + foreach(mudname in keys(connected_muds)){ + if(member_array(mudname, listening[info[6]])!=-1) + write_data(connected_muds[mudname],info[7]); + } + return; + } + if(info[4]==0){ // if broadcasting this... + if(intp(fd)) { + this_object()->SendMessage(info); + } + broadcast_data(connected_muds,info); + return; + } + if(info[4]==router_name) { + switch(info[0]){ + case "shutdown" : + if(sizeof(info) != 7){ + send_error(info[2],info[3],"bad-pkt","Wrong number of elements for packet: "+info[0],info); + return; + } + if(info[6] > 604800) { + server_log("ROUTER_D: deleting "+this_object()->query_connected_fds()[fd]+" per "+ + "request of "+info[2]+"\n"); + remove_mud(this_object()->query_connected_fds()[fd], 1); + } + else { + server_log("ROUTER_D: disconnecting "+this_object()->query_connected_fds()[fd]+" per "+ + "request of "+info[2]); + this_object()->disconnect_mud(this_object()->query_connected_fds()[fd]); + } + break; + case "chanlist-req" : case "chanlist-request" : + broadcast_chanlist("foo",info[2]); + break; + default : + // Something meant for the router but not handled by now! + send_error(info[2],info[3],"not-imp","Unknown command sent to router: "+info[0],info); + server_log("%^RED%^UNHANDLED PACKET:\n"+identify(info)); + } + return; + } + if(info[0]=="startup-reply" || info[0]=="chan-filter-reply"|| + info[0]=="chanlist-reply" || info[0]=="mudlist" || + info[0]=="bad-mojo"){ + // Thanks to Tricky for pointing out the need for this safeguard + send_error(info[2],info[3],"not-allowed", + "You are not allowed to send this kind of packet.",info); + return; + } + // at this point, I guess you should forward it to the destination... + if(info[0]=="locate-reply"){ + // Special case for locate-reply, because protocol 3 has a larger packet... + if(sizeof(info)==8 && mudinfo[info[4]]["protocol"]>2){ + // originator mud is sending a protocol 1/2 response, + // but target understands 3, so add the extra info + write_data(connected_muds[info[4]], ({ + info[0],info[1],info[2],info[3],info[4],info[5], + info[6],info[7],0,0 + })); + return; + } if(sizeof(info)==10 && mudinfo[info[4]]["protocol"]<=2){ + // target mud is being sent a protocol 3 response, + // but only understands 1 & 2, so strip the extra info + write_data(connected_muds[info[4]], ({ + info[0],info[1],info[2],info[3],info[4],info[5], + info[6],info[7] + })); + return; + } + } + // if fd is an integer (meaning it's locally connected) and info[4] is zero + // (meaning it's a boradcast) then we send data to irn. Also, if fd is an + // integer, info[4] is non-zero, and info[4] is not a connected mud. + if((!info[4] && intp(fd)) || + (intp(fd) && info[4] && undefinedp(connected_muds[info[4]])) ){ + this_object()->SendMessage(info); + } + tmp = (this_object()->query_connected_muds()[info[4]] || -1); + if(tmp > -1){ + write_data(connected_muds[info[4]], info); + } + return; +} diff --git a/lib/secure/daemon/i3router/readme.txt b/lib/secure/daemon/i3router/readme.txt new file mode 100644 index 0000000..e8b4a1d --- /dev/null +++ b/lib/secure/daemon/i3router/readme.txt @@ -0,0 +1,29 @@ +// This I3 router code was written mostly by Tim Johnson (Tim@TimMUD, +// Tim@The Eternal Fantasy) +// To use it, #include the server.h file or else just rename it to server.c +// +// If you use it yourself, I'd like you to mention in whatever appropriate +// (if your I3 network or your primary MUD has a web site or board for example) +// place that I wrote all this and you're welcome to list what you may have +// changed on it after downloading mine. I'd actually prefer there to be a +// list somewhere simply because I'm curious what kinds of ideas people add. +// If it's something good, other people would probably be curious about it as +// well. +// +// I haven't done any router-to-router communications, so don't expect this to +// hook you up to the main network. This will only be useful for private I3 +// networks. +// Also, this is LPC code and needs to be on a MUD for it to run. It works +// good on a stock TMI-2 MUD, one day I'll make a stripped-down mudlib solely +// for running my router on (without code for players to log in and such). +// Until then, just download TMI-2 and put these files on your MUD and it +// should work. +// +// -Tim (Last edited February 16, 2004) +// +// Some modifications have been made by Cratylus @ Dead Souls to get it +// working on DS muds and add some features. +// -Crat 05Sep2006 +// +// Added inter-router networking support. See irn.h. +// -Crat 23Feb2007 diff --git a/lib/secure/daemon/i3router/remove_mud.h b/lib/secure/daemon/i3router/remove_mud.h new file mode 100644 index 0000000..275a545 --- /dev/null +++ b/lib/secure/daemon/i3router/remove_mud.h @@ -0,0 +1,88 @@ +static void validate(); +static int *conn_fds = ({}); + +varargs void remove_mud(mixed mudname, int forced){ + int targetfd; + validate(); + if(intp(mudname)){ + targetfd = mudname; + mudname = (this_object()->query_connected_fds()[targetfd] || ""); + } + else { + targetfd = connected_muds[mudname]; + if(undefinedp(connected_muds[mudname])) targetfd = -1; + } + trr("remove_mud("+identify(mudname)+", "+forced+"), fd: "+targetfd, "red"); + //trr("stack: "+get_stack(),"red"); + if(targetfd > -1 && !forced){ + //trr("Cannot remove mud ["+mudname+"] because it is still online right now.\n"); + return; + } + if(targetfd == -1){ + //trr("Warning: cannot disconnect mud ["+mudname+"] because it is not in the connected_muds list.\n"); + server_log("Warning: cannot disconnect mud ["+mudname+"] because it is not in the connected_muds list."); + } + else { + server_log(" Disconnecting mud: "+mudname+" on fd: "+targetfd+"\n"); + //trr(timestamp()+" Disconnecting mud: "+mudname+" on fd: "+targetfd); + } + if(!mudinfo[mudname] && forced){ + //trr("Warning: cannot remove mud ["+mudname+"] because it is not in the mudinfo list.\n"); + server_log(" Warning: cannot remove mud ["+mudname+"] because it is not in the mudinfo list."); + } + else{ + server_log("Removing mud: "+mudname+" on fd: "+targetfd+"\n"); + //trr(timestamp()+" Removing mud: "+mudname+" on fd: "+targetfd); + } + + foreach(mudname in keys(muds_on_this_fd(targetfd))){ + if(socket_status(targetfd)[1] == "LISTEN") continue; + //trr(timestamp()+" remove_mud: Removing mud from connected_muds list: "+mudname,"red"); + if(mudinfo[mudname] && !undefinedp(connected_muds[mudname])){ + mudinfo[mudname]["disconnect_time"] = time(); + map_delete(connected_muds, mudname); + } + } + + conn_fds = keys(this_object()->query_connected_fds()); + + if(targetfd != -1){ + mixed sstat = socket_status(targetfd); + string msg; + if(sizeof(sstat) < 2 || sstat[0] == -1 || sstat[1] == "CLOSED" || + sstat[1] == "LISTEN"){ + return; + } + msg = "About to attempt a disconnect of "+mudname; + msg += " on "+targetfd+" whose status is "; + msg += identify(sstat); + server_log(msg); + trr(msg); + this_object()->close_connection(targetfd); + server_log("Removing mud: "+mudname+" on fd: "+targetfd); + if(sizeof(mudname)){ + SendList( ([ mudname : 0 ]), 0, "mudlist" ); + schedule_broadcast(mudname); + } + } + if(forced){ + server_log("Deleting "+mudname+" from mud list!"); + map_delete(mudinfo, mudname); + } + //server_log("Removing mud: "+mudname+" on fd: "+targetfd); + //SendList( ([ mudname : 0 ]), 0, "mudlist" ); + //schedule_broadcast(mudname); +} + +varargs void disconnect_mud(string mudname, int remote){ + validate(); + if(mudinfo[mudname]){ + mudinfo[mudname]["disconnect_time"] = time(); + mudinfo[mudname]["connect_time"] = 0; + if(!undefinedp(connected_muds[mudname])){ + close_connection(connected_muds[mudname]); + map_delete(connected_muds, mudname); + } + schedule_broadcast(mudname, remote); + } +} diff --git a/lib/secure/daemon/i3router/rsocket.c b/lib/secure/daemon/i3router/rsocket.c new file mode 100644 index 0000000..8efa13a --- /dev/null +++ b/lib/secure/daemon/i3router/rsocket.c @@ -0,0 +1,295 @@ +#include <lib.h> +#include <commands.h> +#include <socket.h> +#include <daemons.h> +#include NETWORK_H +#include "./server_log.h" + +inherit LIB_DAEMON; + +static private int router_socket; +static private mapping sockets = ([]); +static private int incept_date; +int verbose; +int heart_count, interval = 1; +int last_connect = time(); +static int *badsocks = ({}); + +void write_data(int fd, mixed data); +varargs void yenta(mixed arg1, mixed arg2); +object cmd = load_object(CMD_ROUTER); +object router = find_object(ROUTER_D); + +varargs static void validate(int i){ + if(i){ + if(!socket_status(i) || !socket_status(i)[5]){ + server_log("%^RED%^BAD SOCKET ALERT. fd "+i+": "+ + identify(socket_status(i)),"rsocket"); + error("Bad socket, fd "+i); + } + } + if( previous_object() != cmd && previous_object() != router && + previous_object() != this_object() && !((int)master()->valid_apply(({ "ASSIST" }))) ){ + server_log("%^RED%^SECURITY ALERT: validation failure in RSOCKET_D.","rsocket"); + error("Illegal attempt to access router socket daemon: "+get_stack()+ + " "+identify(previous_object(-1))); + } +} + +mixed SetBadsocks(mixed foo){ + if(arrayp(foo)) badsocks = copy(foo); + else badsocks = ({ }); + return badsocks; +} + +static void create(){ + incept_date = time(); + call_out("setup",1); + SetNoClean(1); + set_heart_beat(1); +} + +void heart_beat(){ + heart_count++; + if(!(heart_count % 60)){ + SetBadsocks( ({}) ); + } + if(heart_count > 300){ + heart_count = 0; + } +} + +void close_connection(int fd){ + int sockerr; + mixed *sockstat = ({}); + + validate(); + + sockstat = socket_status(fd); + if(!sockstat || !sizeof(sockstat)) return; + if(sockstat[1] == "LISTEN") return; + server_log("%^YELLOW%^About to try closing socket: "+fd+ + " (aka: "+(ROUTER_D->query_connected_fds()[fd] || + identify(sockstat))+")","rsocket"); + yenta("%^YELLOW%^Pre-closing state: "+sockstat[1],"rsocket"); + sockerr = socket_close(fd); + if(sockerr > -1) map_delete(sockets,fd); + badsocks -= ({ fd }); + yenta("%^WHITE%^closing socket:"+fd,"rsocket"); + yenta("%^WHITE%^closing sockerr:"+sockerr,"rsocket"); + yenta("%^YELLOW%^Post-closing state: "+socket_status(fd)[1],"rsocket"); + yenta("%^WHITE%^---\n","rsocket"); +} + +static void close_callback(int fd){ + string mudname; + mapping muds_on_this_fd = ([]); + + validate(fd); + + if(!find_object(ROUTER_D)) return; + + ROUTER_D->close_notify(fd); + + muds_on_this_fd = ROUTER_D->query_connected_muds(); + foreach(mixed key, mixed val in muds_on_this_fd){ + if(val != fd) map_delete(muds_on_this_fd, key); + } + yenta("close_callback: fd="+fd+"\n"); + if(socket_status(fd)[1] == "LISTEN") return; + foreach(mudname in keys(muds_on_this_fd)){ + server_log("%^RED%^close_callback: Removing mud from connected_muds list: "+(mudname || identify(socket_status(fd))),"rsocket"); + ROUTER_D->disconnect_mud(mudname); + } + close_connection(fd); +} + +static void listen_callback(int fd){ + mixed fdstat,newfd; + validate(); + + if ((newfd = socket_accept(fd, "read_callback", "write_callback")) < 0) { + trr("listen_callback couldn't accept socket "+fd+", errorcode "+newfd); + return; + } + else { + server_log("socket_accepted: "+newfd+ + ", "+identify(socket_status(newfd)),"rsocket"); + + if(sizeof(fdstat) > 4){ + foreach(mixed foo in ROUTER_D->GetBlacklistedMuds()){ + if(!strsrch(fdstat[4]+"",foo)){ + badsocks += ({ newfd }); + return; + } + } + } + + if(time() - last_connect < interval){ + badsocks -= ({ newfd }); + socket_close(newfd); + return; + } + + last_connect = time(); + } +} + +static void read_callback(int fd, mixed info){ + + validate(fd); + if(bufferp(info)){ + yenta("%^WHITE%^fd "+fd+" is sending me buffer data!"); + yenta("%^WHITE%^As far as I can tell, it is:"); + yenta("%^BLUE%^"+identify(read_buffer(info))); + } + else yenta("%^WHITE%^data from fd "+fd+":\n%^BLUE%^"+identify(info)); + if(!find_object(ROUTER_D)) return; + if(member_array(fd, badsocks) != -1) return; + ROUTER_D->read_callback(fd,info); +} + +static void write_callback(int fd){ + + validate(fd); + + if(member_array(fd, badsocks) != -1) return; + + if(!sockets[fd]) return; + if(sockets[fd]["write_status"] == EEALREADY) { + write_data(fd, sockets[fd]["pending"]); + map_delete(sockets[fd], "pending"); + } + else { + sockets[fd]["write_status"] = EESUCCESS; + } +} + +static void write_data_retry(int fd, mixed data, int counter){ + int rc; + int maxtry; + + validate(fd); + + if(member_array(fd, badsocks) != -1) return; + + if(!find_object(ROUTER_D)) return; + + maxtry = ROUTER_D->GetMaxRetries(); + if (counter == maxtry) { + trr("Could not write data to "+ROUTER_D->query_connected_fds()[fd]+", fd"+fd+": "+identify(data[0])); + return; + } + rc = socket_write(fd, data); + if(!sockets[fd]){ + sockets[fd]=([]); + } + sockets[fd]["write_status"] = rc; + switch (rc) { + case EESUCCESS: + break; + case EEALREADY: + sockets[fd]["pending"] = data; + break; + case EECALLBACK: + break; + case EESECURITY: + break; + case EEFDRANGE: + break; + case EENOTCONN: + break; + case EEBADF: + break; + default: + if (counter < maxtry) { + if(counter < 2 || counter > maxtry-1) + trr("RSOCKET_D write_data_retry "+counter+" to "+ + ROUTER_D->query_connected_fds()[fd]+", fd"+fd+" error, code "+rc+": " + socket_error(rc)); + call_out( (: write_data_retry :), 2 , fd, data, counter + 1 ); + return; + } + } +} + +void write_data(int fd, mixed data){ + validate(fd); + if(member_array(fd, badsocks) != -1) return; + write_data_retry(fd, data, 0); +} + +void broadcast_data(mapping targets, mixed data){ + validate(); + foreach(int *arr in unique_array(values(targets), (: $1 :))){ + write_data(arr[0], data); + } +} + +static void setup(){ + int router_port; + + if(!find_object(ROUTER_D)) return; + + router_port = atoi(ROUTER_D->GetRouterPort()); + server_log("rsocket setup got called","rsocket"); + if ((router_socket = socket_create(MUD, "read_callback", "close_callback")) < 0){ + server_log("setup: Failed to create socket.","rsocket"); + return; + } + if (socket_bind(router_socket, router_port) < 0) { + socket_close(router_socket); + server_log("setup: Failed to bind socket to port.","rsocket"); + return; + } + if (socket_listen(router_socket, "listen_callback") < 0) { + socket_close(router_socket); + server_log("setup: Failed to listen to socket.","rsocket"); + } + server_log("rsocket setup ended","rsocket"); +} + +void complete_socket_handoff(int i){ + + validate(i); + + yenta("hit the right handoff fun. arg: "+i); + if(base_name(previous_object()) != ROUTER_D){ + yenta("I don't want your dirty socket, "+identify(previous_object())); + return; + } + yenta("sockstat: "+identify(socket_status(i))); + socket_acquire(i, "read_callback", "write_callback", "close_callback"); + yenta("sockstat: "+identify(socket_status(i))); +} + +mapping query_socks(){ validate(); return copy(sockets); } + +int GetInceptDate(){ + return incept_date; +} + +int eventDestruct(){ + string alert = "RSOCKET_D is being killed!\n"; + alert += "STACK: "+get_stack()+"\n"; + alert += "PREVS: "+identify(previous_object(-1))+"\n"; + + server_log("%^RED%^"+alert,"rsocket"); + return ::eventDestruct(); +} + +int SetVerbose(int i){ + if(i) verbose = 1; + else verbose = 0; + return verbose; +} + +int GetVerbose(){ + return verbose; +} + +varargs void yenta(mixed arg1, mixed arg2){ + if(verbose){ + if(arg2) server_log(arg1, arg2); + else server_log(arg1); + } +} diff --git a/lib/secure/daemon/i3router/send_chanlist_reply.h b/lib/secure/daemon/i3router/send_chanlist_reply.h new file mode 100644 index 0000000..5df4976 --- /dev/null +++ b/lib/secure/daemon/i3router/send_chanlist_reply.h @@ -0,0 +1,36 @@ +// This file written mostly by Tim Johnson (Tim@TimMUD) + +static void send_chanlist_reply(string mudname, int old_chanid){ + string channame; // channel name + // string *output; // array of which channel names to tell them about + mapping out=([ ]); // mapping to send + //int i; // counter + //trr("send_chanlist_reply, mudname="+mudname+", old_chanid="+old_chanid); + foreach(channame in keys(channel_updates)){ + //#ifndef SEND_WHOLE_CHANLIST + // if(channel_updates[channame]>old_chanid){ // needs updating + //#endif + if(!channels[channame]){ // add to output; + out[channame] = 0; + } + else{ + out[channame] = ({ channels[channame][1], + channels[channame][0] }); // host, type + } + //#ifndef SEND_WHOLE_CHANLIST + // } + //#endif + } + //trr("Chanlist: "+identify(out),"blue"); + write_data(connected_muds[mudname],({ + "chanlist-reply", + 5, + router_name, + 0, + mudname, + 0, + channel_update_counter, + out, + })); + mudinfo[mudname]["old_chanlist_id"]=channel_update_counter; +} diff --git a/lib/secure/daemon/i3router/send_error.h b/lib/secure/daemon/i3router/send_error.h new file mode 100644 index 0000000..f1def74 --- /dev/null +++ b/lib/secure/daemon/i3router/send_error.h @@ -0,0 +1,23 @@ +// This file written mostly by Tim Johnson (Tim@TimMUD) + +static void send_error(string mud, string user, string errcode, string errmsg, mixed *info){ + if(undefinedp(connected_muds[mud])){ + //trr("Can't send error to "+mud+" because they're not connected."); + return; + } + if(strsrch(errmsg, "Not in allow list")){ + server_log("Sending error to "+mud+": "+errmsg); + } + write_data(connected_muds[mud],({ + "error", + 5, + router_name, + 0, + mud, // mud name + user, // user name + errcode, + errmsg, + info + })); + return; +} diff --git a/lib/secure/daemon/i3router/send_full_mudlist.h b/lib/secure/daemon/i3router/send_full_mudlist.h new file mode 100644 index 0000000..fc9a9fe --- /dev/null +++ b/lib/secure/daemon/i3router/send_full_mudlist.h @@ -0,0 +1,51 @@ +void send_full_mudlist(string mud){ + int interval = 0; + mixed *package = ({}); + mixed *names = ({}); + if(undefinedp(connected_muds[mud])) return; + //trr("trying to send full mudlist to "+mud); + foreach(string mudname in keys(mudinfo)){ + int mudstat; + if(undefinedp(connected_muds[mudname]) && mudinfo[mudname]){ + if(!mudinfo[mudname]["disconnect_time"]) mudstat = -1; + else mudstat = 0; + } + else { + mudstat = -1; + } + + package += ({ ({ "mudlist", 5, router_name, 0, 0, 0, mudinfo_update_counter,([ + mudname:({ + mudstat, + // -1=up, 0=down, n=down for n secs + mudinfo[mudname]["ip"], // ip_addr + mudinfo[mudname]["player_port"], // player_port + mudinfo[mudname]["imud_tcp_port"], // imud_tcp_port + mudinfo[mudname]["imud_udp_port"], // imud_udp_port + mudinfo[mudname]["mudlib"], // mudlib + mudinfo[mudname]["base_mudlib"], // base_mudlib + mudinfo[mudname]["driver"], // driver + mudinfo[mudname]["mud_type"], // mud_type + mudinfo[mudname]["open_status"], // open_status + mudinfo[mudname]["admin_email"], // admin_email + mudinfo[mudname]["services"], // services + mudinfo[mudname]["other_data"], // other_data + }) + ]) }) }); + } + while(sizeof(package)){ + //trr("package: "+sizeof(package),"white"); + interval++; + foreach(mixed element in package[0..9]){ + string name = identify(keys(element[7])); + names += ({ name }); + //trr("element: "+identify(element)); + call_out( (: write_data :), interval, connected_muds[mud], element); + //trr("sending info on "+name+" to "+mud+", interval: "+interval,"cyan"); + } + package -= package[0..9]; + } + //trr("number of muds: "+sizeof(mudinfo),"red"); + //trr("number of muds sent: "+sizeof(names),"red"); + //trr("muds: "+identify(names),"red"); +} diff --git a/lib/secure/daemon/i3router/send_mudlist_updates.h b/lib/secure/daemon/i3router/send_mudlist_updates.h new file mode 100644 index 0000000..a167ef5 --- /dev/null +++ b/lib/secure/daemon/i3router/send_mudlist_updates.h @@ -0,0 +1,130 @@ +// This file written mostly by Tim Johnson (Tim@TimMUD) + +void send_mudlist_updates(string updating_mudname, int old_mudlist_id){ + string mudname; // mud name + string *kys; // array of strings for keys that need to be sent + mapping out=([ ]); // mapping to send + int i; // counter + int status; + mapping payload = ([]); + mudinfo_update_counter++; + //trr("old_mudlist_id: "+old_mudlist_id,"blue"); + //trr("updating_mudname: "+updating_mudname,"blue"); + //trr("send_mudlist_updates, updating_mudname="+updating_mudname+", old_mudlist_id="+old_mudlist_id,"blue"); + foreach(mudname in keys(mudinfo_updates)){ + //trr("mudinfo_updates current element: "+identify(mudname)); +#ifndef SEND_WHOLE_MUDLIST + //trr("send whole mudlist undefined"); + if(mudinfo_updates[mudname]>old_mudlist_id){ // needs updating +#endif + if(!mudinfo[mudname]){ // deleted mud; + out[mudname] = 0; + } + else{ + if(undefinedp(connected_muds[mudname])){ + if(mudinfo[mudname]["disconnect_time"] && + mudinfo[mudname]["restart_delay"] == -1) status = 0; + else status = mudinfo[mudname]["restart_delay"]; + } + else status = -1; + //trr("STATUS: "+status,"yellow"); + switch(mudinfo[updating_mudname]["protocol"]){ + case 1: + case 2: + out[mudname] = ({ + status, + // -1=up, 0=down, n=down for n secs + mudinfo[mudname]["restart_delay"], + mudinfo[mudname]["ip"], // ip_addr + mudinfo[mudname]["player_port"], // player_port + mudinfo[mudname]["imud_tcp_port"], // imud_tcp_port + mudinfo[mudname]["imud_udp_port"], // imud_udp_port + mudinfo[mudname]["mudlib"], // mudlib + mudinfo[mudname]["base_mudlib"], // base_mudlib + mudinfo[mudname]["driver"], // driver + mudinfo[mudname]["mud_type"], // mud_type + mudinfo[mudname]["open_status"], // open_status + mudinfo[mudname]["services"], // services + }); + break; + case 3: + out[mudname] = ({ + status, + // -1=up, 0=down, n=down for n secs + mudinfo[mudname]["ip"], // ip_addr + mudinfo[mudname]["player_port"], // player_port + mudinfo[mudname]["imud_tcp_port"], // imud_tcp_port + mudinfo[mudname]["imud_udp_port"], // imud_udp_port + mudinfo[mudname]["mudlib"], // mudlib + mudinfo[mudname]["base_mudlib"], // base_mudlib + mudinfo[mudname]["driver"], // driver + mudinfo[mudname]["mud_type"], // mud_type + mudinfo[mudname]["open_status"], // open_status + mudinfo[mudname]["admin_email"], // admin_email + mudinfo[mudname]["services"], // services + mudinfo[mudname]["other_data"], // other_data + }); + break; + } // switch + } // else not deleted +#ifndef SEND_WHOLE_MUDLIST + } // if needs updating +#endif + } // foreach + // out now has the mapping of what to tell the mud about... + // this might be big, so later I'll make it so it sends only 10 muds at a time... + // take an idea from /cmds/std/_semote.c + kys=keys(out); + for(i=0;i<sizeof(kys)-10;i+=10){ // leave a group of size between 1 and 10 remaining + //trr("sending a set of 10..."); + // send all the ones except the last one, doing 10 at a time, + // but give them their original mudlist id, in case they get + // disconnected before all the sets of 10 get finished + payload = ([ kys[i]: out[kys[i]], + kys[i+1]: out[kys[i+1]], + kys[i+2]: out[kys[i+2]], + kys[i+3]: out[kys[i+3]], + kys[i+4]: out[kys[i+4]], + kys[i+5]: out[kys[i+5]], + kys[i+6]: out[kys[i+6]], + kys[i+7]: out[kys[i+7]], + kys[i+8]: out[kys[i+8]], + kys[i+9]: out[kys[i+9]], + ]); + write_data(connected_muds[updating_mudname],({ + "mudlist", + 5, + router_name, + 0, + updating_mudname, + 0, + //old_mudlist_id, + (random(9999) * random(999)), + payload, + })); + //this_object()->SendList(payload); + map_delete(out,kys[i]); + map_delete(out,kys[i+1]); + map_delete(out,kys[i+2]); + map_delete(out,kys[i+3]); + map_delete(out,kys[i+4]); + map_delete(out,kys[i+5]); + map_delete(out,kys[i+6]); + map_delete(out,kys[i+7]); + map_delete(out,kys[i+8]); + map_delete(out,kys[i+9]); + } + // incomplete set is left where it kicked out of the for loop + write_data(connected_muds[updating_mudname],({ + "mudlist", + 5, + router_name, + 0, + updating_mudname, + 0, + mudinfo_update_counter, + out, + })); + //this_object()->SendList(out); + mudinfo[updating_mudname]["old_mudlist_id"]=mudinfo_update_counter; +} diff --git a/lib/secure/daemon/i3router/send_startup_reply.h b/lib/secure/daemon/i3router/send_startup_reply.h new file mode 100644 index 0000000..d77514d --- /dev/null +++ b/lib/secure/daemon/i3router/send_startup_reply.h @@ -0,0 +1,36 @@ +// This file written mostly by Tim Johnson (Tim@TimMUD) + +static void send_startup_reply(string mudname){ + // This packet will be delivered to a mud for three conditions: + // in response to a startup-req packet, + // when the router wishes the mud to connect to a different router, + // or when the set of routers change for some reason. + + if(undefinedp(connected_muds[mudname])) { + //trr("PROBLEM","red"); + return; + } + + else { + //if(mudinfo[mudname] && mudinfo[mudname]["password"]) + //trr(mudname +" apparently exists. password: "+mudinfo[mudname]["password"],"white"); + //else //trr(mudname +" apparently exists, but I can't find a password for it.","white"); + } + + + write_data(connected_muds[mudname], ({ + "startup-reply", + 5, + router_name, + 0, + mudname, + 0, + router_list, + mudinfo[mudname]["password"] + }) ); + + //trr("connected_muds[mudname]: "+identify(connected_muds[mudname]),"blue"); + //trr("mudname: "+identify(mudname),"blue"); + //trr("router_name: "+identify(router_name),"blue"); + //trr("mudinfo[mudname]: "+identify(mudinfo[mudname]),"yellow"); +} diff --git a/lib/secure/daemon/i3router/server.c b/lib/secure/daemon/i3router/server.c new file mode 100644 index 0000000..e8bba58 --- /dev/null +++ b/lib/secure/daemon/i3router/server.c @@ -0,0 +1,752 @@ +// I3 server. +// This file written mostly by Tim Johnson (Tim@TimMUD) +// Started by Tim on May 7, 2003. +// http://cie.imaginary.com/protocols/intermud3.html#errors +#include <lib.h> +#include <commands.h> +#include <daemons.h> +#include <socket.h> +#define MAXMUDS 32 // Max number of muds allowed from one IP +#define ROUTER_BLACKLIST "/secure/daemon/i3router/blacklist.cfg" //bad IP's +#define DEB_IN 1 // //trr-Incoming +#define DEB_OUT 2 // //trr-Outgoing +#define DEB_OUT_LOG 0 // //logging stuff +#define DEB_INVALID 3 // //trr-Invalid +#define DEB_OTHER 0 // //trr-Other +#define DEBUGGER_GUY "cratylus" // Name of who to display //trrging info to. +#define MAXIMUM_RETRIES 20 +// SEND_WHOLE_MUDLIST makes it act like the official I3 server instead of like the I3 specs +#define SEND_WHOLE_MUDLIST +// SEND_WHOLE_CHANLIST makes it act like the official I3 server instead of like the I3 specs +#define SEND_WHOLE_CHANLIST +inherit LIB_DAEMON; + +object cmd = load_object(CMD_ROUTER); +object rsocket = find_object(RSOCKET_D); +object ssocket = find_object(SSOCKET_D); + +static void validate(){ + if( previous_object() != cmd && previous_object() != rsocket && + previous_object() != this_object() && previous_object() != ssocket && + !((int)master()->valid_apply(({ "ASSIST" }))) ){ + trr("SECURITY ALERT: validation failure in ROUTER_D.","red"); + error("Illegal attempt to access router daemon: "+get_stack()+ + " "+identify(previous_object(-1))); + } +} + +// Saved variables... +mapping listening; +// list of muds listening to each channel +// (key=chan name, value=mud array) +mapping connected_muds; +// muds that have successfully done a startup +// (key=mudname, value=fd) +string router_name; // Name of the router. +string router_ip; +static string *router_list = ({}); // Ordered list of routers to use. +mapping mudinfo = ([]); // Info about all the muds which the router knows about. +mapping channels; // Info about all the channels the router handles. +mapping channel_updates; // Tells when a channel was last changed. +int channel_update_counter; // Counter for the most recent change. +// Why is this not a part of the channels mapping? +// Because I need to remember that some channels got deleted. +mapping mudinfo_updates; // Like channel_updates except for muds. +int mudinfo_update_counter; // Similar to channel_update_counter +static int max_age = 604800; +//static int max_age = 86400; +mapping Blacklist = ([]); + +//Unsaved globals +static mapping gtargets = ([]); + +// Prototypes +static mapping muds_on_this_fd(int fd); +static mapping muds_not_on_this_fd(int fd); +void write_data(int fd, mixed data); +static void close_connection(int fd); +static void broadcast_data(mapping targets, mixed data); + +// Ones with their own files... +string clean_fd(string fd); +static void broadcast_chanlist(string channame); +void broadcast_mudlist(string mudname); +static varargs void Debug(string str, int level); +static void process_channel(int fd, mixed *info); +static void process_startup_req(int protocol, mixed info, int fd); +static void read_callback(int fd, mixed info); +static void remove_mud(string mudname, int forced); +static void send_chanlist_reply(string mudname, int old_chanid); +static void send_mudlist(string mudname); +static void send_mudlist_updates(string updating_mudname, int old_mudlist_id); +static void send_startup_reply(string mudname); +static void send_error(string mud, string user, string errcode, string errmsg, mixed *info); +void send_full_mudlist(string mud); +// core_stuff.h... +static void create(); +static void setup(); +void remove(); +// funcs.h... +static mapping muds_on_this_fd(int fd); +int value_equals(string a,int b, int c); +static mapping muds_not_on_this_fd(int fd); +int value_not_equals(string a,int b, int c); +// socket_stuff.h +varargs string *SetList(); + +// Code for all the stuff in the prototypes... +#include "./server_log.h" +#include "./irn.h" +#include "./clean_fd.h" +#include "./broadcast_chanlist.h" +#include "./broadcast_mudlist.h" +#include "./debug.h" +#include "./process_channel.h" +#include "./process_startup_req.h" +#include "./read_callback.h" +#include "./remove_mud.h" +#include "./send_chanlist_reply.h" +#include "./send_mudlist_updates.h" +#include "./send_startup_reply.h" +#include "./send_error.h" + +#include "./core_stuff.h" +#include "./funcs.h" +#include "./hosted_channels.h" +#include "./send_full_mudlist.h" + +static void close_connection(int fd){ + if(!socket_status(fd) || socket_status(fd)[0] == -1) return; + trr("trying to close "+fd); + if(base_name(socket_status(fd)[5]) == RSOCKET_D){ + RSOCKET_D->close_connection(fd); + } + if(base_name(socket_status(fd)[5]) == SSOCKET_D){ + SSOCKET_D->close_connection(fd); + } +} + +varargs void write_data(int fd, mixed data, int override){ + mixed *sstat = socket_status(fd); + object rsock = find_object(RSOCKET_D); + string targetmud; +#if DEB_OUT_LOG + write_file("/secure/log/tmp.txt","Trying to send at "+ctime(time())); + write_file("/secure/log/tmp.txt"," packet size:"+sizeof(data)); + write_file("/secure/log/tmp.txt"," "+identify(data)+"\n---\n\n"); +#endif + if(data[0] == "irn-startup-req"){ + int ok = 0; + string tmpsstat; + if(socket_status(fd)) tmpsstat = socket_status(fd)[4]; + foreach(mixed element in ok_ips){ + if(tmpsstat && !strsrch(tmpsstat,element+".")) ok = 1; + } + if(!ok){ + trr("%^B_GREEN%^ATTENTION: IRN startup aborted for "+ + tmpsstat,"red"); + return; + } + trr("%^B_YELLOW%^ATTENTION: IRN startup about to be sent to fd"+fd+":%^RESET%^ "+ identify(data)+", "+identify(socket_status(fd)),"red"); + } + targetmud = this_object()->query_connected_fds()[fd]; + if(!sstat || sstat[1] != "DATA_XFER") return; + if(!fd || (!data[4] && targetmud) || member_array(fd, keys(irn_sockets)) != -1 || + (targetmud && targetmud == data[4]) ){ + if(rsock && sstat[5] == rsock) RSOCKET_D->write_data(fd, data); + else IMC2_SERVER_D->write_data(fd, data); + } + else { + } +} + +static void broadcast_data(mapping targets, mixed data){ + object imc2d = find_object(IMC2_SERVER_D); + RSOCKET_D->broadcast_data(targets, data); + if(imc2d) imc2d->broadcast_data(targets, data); +} + +// debugging stuff... +mapping query_mudinfo(){ validate(); return copy(mudinfo); } +mapping query_mud(string str){ validate(); return copy(mudinfo[str]); } +mapping query_connected_muds(){ validate(); return copy(connected_muds); } +mapping query_chaninfo(){ return ([ "listening" : listening, "channels" : channels ]); } +mapping query_socks(){ + object ssock = find_object(SSOCKET_D); + object rsock = find_object(RSOCKET_D); + mapping ret = ([]); + validate(); + if(rsock) ret = RSOCKET_D->query_socks(); + if(ssock) ret += SSOCKET_D->query_socks(); + return ret; +} + +mapping query_connected_fds(){ + mapping RetMap = ([]); + validate(); + foreach(mixed key, mixed val in connected_muds){ + RetMap[val] = key; + } + return copy(RetMap); +} + +int *open_socks(){ + int *ret = ({}); + validate(); + foreach(mixed element in socket_names()){ + if(intp(element[0]) && element[0] != -1 && !grepp(element[3],"*") && + last_string_element(element[3],".") == router_port && + member_array(element[0], + keys(this_object()->query_irn_sockets())) == -1) { + ret += ({ element[0] }); + } + } + return ret; +} + +int query_imc(mixed mud){ + mixed *sstat; + object ssock = find_object(SSOCKET_D); + if(stringp(mud)) mud = query_connected_muds()[mud]; + if(!intp(mud)) return 0; + sstat = socket_status(mud); + if(!ssock ||!sstat || sizeof(sstat) != 6 || sstat[0] == -1) return 0; + if(sstat[5] == ssock) return 1; + return 0; +} + +mixed get_info(int auto) { + mixed *socky = sort_array(values(connected_muds), 1); + mixed *muddy = sort_array(keys(connected_muds), 1); + string socks = implode(socky, " "); + string muddies = implode(muddy, ", "); + int socknum = sizeof(socky); + string sret = "", ret = ""; + validate(); + + if(find_object(SSOCKET_D)){ + sret = "\nIMC2 server socket daemon uptime: "+ + time_elapsed(time()-SSOCKET_D->GetInceptDate())+ + ", up since "+ctime(SSOCKET_D->GetInceptDate()); + } + socks += "\nTotal number of connected muds: "+socknum+"\n"; + ret = "router_name: "+router_name+ + "\nrouter_ip: "+router_ip+ + "\nrouter_port: "+router_port+ + "\nrouter_list"+identify(router_list)+ + "\nchannel_update_counter: "+ channel_update_counter+ + ((sizeof(channels)) ? "\nchannels:"+implode(sort_array(keys(channels),1),", ") : "")+ + "\nmudinfo_update_counter: "+ mudinfo_update_counter+ + "\nsockets: "+socks+ + "\nmuds: "+muddies+ + "\nRouter socket daemon uptime: "+ + time_elapsed(time()-RSOCKET_D->GetInceptDate())+ + ", up since "+ctime(RSOCKET_D->GetInceptDate())+ + sret+ + "\n"+Report(); + + if(auto) return ret; + write(ret); + return 1; +} + +void clear(){ + string mudname; + validate(); + server_log("%^RED%^Clearing all mud data!"); + foreach(mudname in keys(mudinfo)) remove_mud(mudname,1); + SaveObject(SAVE_ROUTER); +} + +string GetRouterName(){ + validate(); + return router_name; +} + +string SetRouterName(string str){ + validate(); + if(first(str,1) != "*") str = "*"+str; + router_name = str; + server_log(" setting router name to: "+str); + SetList(); + return router_name; +} + +string GetRouterIP(){ + validate(); + return router_ip; +} + +string SetRouterIP(string str){ + validate(); + router_ip = str; + server_log("Setting router IP to: "+str); + SetList(); + return router_ip; +} + +string GetRouterPort(){ + validate(); + return router_port; +} + +string SetRouterPort(string str){ + validate(); + router_port = str; + server_log("Setting router port to: "+str); + SetList(); + return router_port; +} + +string *GetRouterList(){ + validate(); + return router_list; +} + +varargs string *SetList(){ + string tmp; + string tmp_port = router_port; + string tmp_ip = router_ip; + validate(); + if(!strsrch(router_name,"*")) tmp = router_name; + else tmp = "*"+router_name; + if(lower_case(mud_name()) == "frontiers" || + lower_case(mud_name()) == "*yatmim"){ + tmp_port = "23"; + tmp_ip = "149.152.218.102"; + tmp = "*yatmim"; + } + if(!sizeof(router_list)){ + router_list = ({ ({ tmp, tmp_ip+" "+tmp_port }) }); + } + server_log("Setting router list to: "+identify(router_list)); + this_object()->setup_blacklist(); + SaveObject(SAVE_ROUTER); + return router_list; +} + +mapping GetConnectedMuds(){ + validate(); + return copy(connected_muds); +} + +string *GetBannedMuds(){ + validate(); + return banned_muds; +} + +string *AddBannedMud(string str){ + validate(); + banned_muds += ({ str }); + server_log(str+" has been BANNED"); + SaveObject(SAVE_ROUTER); + return banned_muds; +} + +string *RemoveBannedMud(string str){ + validate(); + banned_muds -= ({ str }); + server_log(str+" has been unbanned."); + SaveObject(SAVE_ROUTER); + return banned_muds; +} + +string *GetBlacklistedMuds(){ + validate(); + return blacklisted_muds; +} + +varargs string *AddBlacklistedMud(string str, int perma){ + validate(); + if(!Blacklist) Blacklist = ([]); + if(Blacklist[str]) return blacklisted_muds; + if(perma) perma = 0; + else perma = time(); + Blacklist[str] = perma; + blacklisted_muds += ({ str }); + server_log(str+" has been BLACKLISTED"); + SaveObject(SAVE_ROUTER); + return blacklisted_muds; +} + +string *RemoveBlacklistedMud(string str){ + validate(); + if(!Blacklist) Blacklist = ([]); + if(Blacklist[str]) map_delete(Blacklist, str); + blacklisted_muds -= ({ str }); + server_log(str+" has been unblacklisted."); + SaveObject(SAVE_ROUTER); + return blacklisted_muds; +} + +mixed GetRemoteIP(int fd){ + mixed conn = socket_status(fd); + string ret; + if(!conn || !sizeof(conn)) return 0; + if(!conn[4] || conn[4] == "*.*") return 0; + conn = explode(conn[4],"."); + ret = implode(conn[0..3],"."); + return ret; +} + +void check_blacklist(){ + int timenow = time(); + string *bms; + trr("Checking old blacklists"); + if(!Blacklist) Blacklist = ([]); + blacklisted_muds = distinct_array(blacklisted_muds); + bms = keys(Blacklist); + + foreach(string element in blacklisted_muds){ + if(member_array(element, bms) == -1) + Blacklist[element] = 0; + } + + foreach(string key, int val in Blacklist){ + if((timenow - val) == timenow) continue; + if((timenow - val) > max_age){ + RemoveBlacklistedMud(key); + trr("%^B_BLACK%^Removed "+key+" from blacklist.","white"); + } + } +} + +void check_graylist(){ + if(sizeof(graylisted_muds)){ + graylisted_muds = distinct_array(graylisted_muds); + tn("i3 router: removing graylisted "+graylisted_muds[0]); + graylisted_muds -= ({ graylisted_muds[0] }); + } +} + +void check_discs(){ + int *fds = values(connected_muds); + int i = 1; + + foreach(string mudname in keys(mudinfo)){ + if(undefinedp(connected_muds[mudname]) && mudinfo[mudname]["router"]){ + if(mudinfo[mudname]["router"] != my_name && + member_array(mudinfo[mudname]["router"],keys(irn_connections)) == -1){ + if(!mudinfo[mudname]["disconnect_time"]){ + trr("killing "+mudname); + mudinfo[mudname]["disconnect_time"] = 100; + if(mudinfo[mudname]["connect_time"]) + mudinfo[mudname]["connect_time"] = 0; + schedule_broadcast(mudname); + } + } + } + } + + if(sizeof(fds)) + foreach(mixed element in sort_array(fds,1)){ + string lost_mud; + if(!intp(element)) continue; + if(!socket_status(element) || + socket_status(element)[1] == "CLOSED" || !GetRemoteIP(element) || + ( mudinfo[query_connected_fds()[element]] && GetRemoteIP(element) != mudinfo[query_connected_fds()[element]]["ip"])){ + foreach(string key, mixed val in mudinfo){ + if(undefinedp(connected_muds[key]) + && mudinfo[key]["router"]){ + if(mudinfo[key]["router"] == my_name){ + server_log("Cleaning my connection info from "+key); + if(!mudinfo[key]["disconnect_time"]) + mudinfo[key]["disconnect_time"] = time(); + if(mudinfo[key]["connect_time"]) + mudinfo[key]["connect_time"] = 0; + } + else { + server_log("Cleaning "+ mudinfo[key]["router"]+ + " connection info from "+key); + if(!mudinfo[key]["disconnect_time"]) + mudinfo[key]["disconnect_time"] = 0; + if(mudinfo[key]["connect_time"]) + mudinfo[key]["connect_time"] = 0; + } + } + } + + foreach(string key, int val in connected_muds){ + if(val == element){ + trr("REMOVING DISCONNECTED: "+key+" from "+val); + i++; + call_out( (: disconnect_mud :), i, key); + } + } + } + } +} + +varargs void clean_ghosts(int force){ + int tmp,i; + object rsockd = find_object(RSOCKET_D); + object ssockd = find_object(SSOCKET_D); + mixed array incoming = socket_status(); + mixed *legit_socks = keys(this_object()->query_socks()); + legit_socks += keys(this_object()->query_irn_sockets()); + + if(!rsockd && !ssockd) return; + + tmp=sizeof(socket_status())-1; + + for(i=0;i < tmp;i++){ + if(!incoming[i][5] || + (incoming[i][5] != rsockd && incoming[i][5] != ssockd)) continue; + if(member_array(i,legit_socks) == -1 && incoming[i][1] == "DATA_XFER"){ + if(!force){ + string ip = clean_fd(socket_address(i)); + // keep blacklisted connections sandboxed, in case + // they're the reconnecting kind. + if(member_array(ip, blacklisted_muds) != -1) continue; + } + this_object()->close_connection(i); + } + } +} + +void clean_chans(){ + string *cleaned = ({}); + foreach(mixed key, mixed val in listening){ + if(arrayp(val)){ + foreach(string listening_mud in val){ + if(!mudinfo[listening_mud]){ + listening[key] -= ({ listening_mud }); + cleaned += ({ listening_mud }); + } + } + } + //else trr("huh? not an array?"); + } + foreach(mixed key, mixed val in channels){ + mixed *tmp_chan = ({}); + if(sizeof(val) == 3){ + tmp_chan = ({ (intp(val[0]) ? val[0] : 0), + val[1], distinct_array(val[2]) }); + channels[key] = tmp_chan; + } + } + cleaned = distinct_array(cleaned); + SaveObject(SAVE_ROUTER); + trr("channel cleanup: cleaned from listening: "+implode(cleaned,"\n")); +} + +varargs void clear_discs(mixed arg){ + string mudname; + string *disclist, *muds; + int i = 1; + + validate(); + if(arg){ + if(stringp(arg)) arg = ({ arg }); + if(arrayp(arg)) disclist = arg; + } + + if(!disclist) disclist = keys(mudinfo); + muds = keys(mudinfo); + + trr("%^B_BLACK%^Discarding excessively old disconnects.","white"); + trr("%^B_BLACK%^Max age is "+time_elapsed(max_age)+".","white"); + foreach(mudname in disclist) { + int deadsince; + if(member_array(mudname, muds) == -1){ + object ssock = find_object(SSOCKET_D); + object imc2d = find_object(IMC2_SERVER_D); + mixed data; + gtargets = ([]); + if(ssock && imc2d){ + mixed tmparr = keys(ssock->query_socks()); + filter(tmparr, (: gtargets[itoa($1)] = $1 :)); + data = "*@" + my_name + " " + time() + " " + my_name + + " close-notify *@* host=" + replace_string(mudname," ","_"); + imc2d->broadcast_data(gtargets, data); + } + } + else { + deadsince = time() - mudinfo[mudname]["disconnect_time"]; + + if(undefinedp(connected_muds[mudname]) && mudinfo[mudname]["router"]){ + if(mudinfo[mudname]["router"] != my_name && + member_array(mudinfo[mudname]["router"],keys(irn_connections)) == -1){ + if(!mudinfo[mudname]["disconnect_time"]) + mudinfo[mudname]["disconnect_time"] = 0; + if(mudinfo[mudname]["connect_time"]) + mudinfo[mudname]["connect_time"] = 0; + } + } + + if(!mudinfo[mudname]["disconnect_time"]) continue; + trr("%^B_BLACK%^"+mudname+": "+ctime((mudinfo[mudname]["disconnect_time"]) || time()),"white"); + trr("%^B_BLACK%^dead age: "+time_elapsed(deadsince),"white"); + if(mudinfo[mudname]["disconnect_time"] && deadsince > max_age ){ + trr(mudname+": "+time_elapsed(deadsince),"red"); + server_log("I want to remove "+mudname+". Its disconnect time is "+ctime(query_mud(mudname)["disconnect_time"])); + server_log("Which was "+time_elapsed(time() - query_mud(mudname)["disconnect_time"])+" ago."); + i = i+1; + remove_mud(mudname,1); + } + + if(mudinfo[mudname] && mudinfo[mudname]["disconnect_time"] > 0 && + mudinfo[mudname]["connect_time"] > 0){ + i = 1; + server_log("I want to remove "+mudname+". It is in a paradox state."); + if(member_array(mudname,keys(query_connected_muds())) != -1){ + trr("%^B_BLACK%^Its fd is: "+query_connected_muds()[mudname],"white"); + } + else { + trr("%^B_BLACK%^It is not listed as a connected mud.","white"); + } + server_log("Removing disconnected mud: "+identify(mudname)); + i = i+2; + remove_mud(mudname,1); + } + } + }//end foreach +} + +int eventDestruct(){ + validate(); + SaveObject(SAVE_ROUTER); + server_log("I am being destructed by: \n"+get_stack()+ + "\n"+identify(previous_object(-1))); + daemon::eventDestruct(); +} + +string query_fd_info(mixed foo){ + int num, i; + string ret = ""; validate(); + if(stringp(foo)) if(sscanf(foo,"%d",num) != 1) return "foo"; + if(intp(foo)) num = foo; + for(i=0;i<num;i++){ + mapping bar = query_connected_fds(); + ret += i+" "+socket_address(i)+" "+(bar[i]+"" || "")+"\n"; + } + return ret; +} + +int GetMaxRetries(){ return MAXIMUM_RETRIES; } + +varargs void ReceiveList(mixed data, string type, string who){ + string *cmuds = keys(connected_muds); + if(!type || !sizeof(type)) type = "mudlist"; + if(!mapp(data)){ + return; + } + if(type == "mudlist"){ + foreach(mixed key, mixed val in data){ + if(member_array(key,cmuds) != -1) continue; + if(val && val["router"] && val["router"] == router_name) continue; + if(mudinfo[key] && (!val || intp(val))){ + trr("ROUTER_D: deleting "+key); + remove_mud(key,1); + continue; + } + if(!mapp(val)){ + return; + } + mudinfo_update_counter++; + if(undefinedp(connected_muds[key])){ + trr("%^B_GREEN%^%^BLACK%^accepting "+key+ + " update from "+(mudinfo[key] ? mudinfo[key]["router"] : who )); + mudinfo_updates[key] = mudinfo_update_counter; + mudinfo[key]=val; + schedule_broadcast(key, 1); + } + else { + trr("%^RESET%^Looks like I'm %^B_RED%^%^BLACK%^REJECTING%^RESET%^ "+key+"." + +mudinfo[key]["router"]+" update from "+who); + } + } + } + else if(type == "chanlist"){ + if(data["listening"] && sizeof(data["listening"]) && mapp(data["listening"])){ + foreach(mixed key, mixed val in data["listening"]){ + //trr("listening update: "+key+" is "+identify(val)+" val is a "+typeof(val),"yellow"); + } + } + if(data["channels"] && sizeof(data["channels"]) && mapp(data["channels"])){ + foreach(mixed key, mixed val in data["channels"]){ + string ownermud = data["channels"][key][1]; + string comp1, comp2; + if(!key || !val || !stringp(key)){ + map_delete(channels, key); + map_delete(listening, key); + continue; + } + if(member_array(ownermud, cmuds) != -1) continue; + if(val == -1) map_delete(channels, key); + if(val == -1) map_delete(listening, key); + else { + val[2] = distinct_array(val[2]); + comp1 = identify( sort_array(val[2], 1)); + comp2 = identify( sort_array(distinct_array(channels[key]), 1)); + trr("*************"); + trr("comp1: "+comp1); + trr("comp2: "+comp2); + trr("*************"); + channels[key] = val; + } + if(comp1 != comp2) broadcast_chanlist(key); + trr("OOOOOOOOOOOOO"); + trr("chan update: "+key+" is "+identify(val)+" val is a "+typeof(val),"green"); + trr("OOOOOOOOOOOOO"); + } + } + } + SaveObject(SAVE_ROUTER); +} + +int purge_crud(){ + foreach(mixed key, mixed val in mudinfo){ + if(!mapp(val)) map_delete(mudinfo, key); + } + SaveObject(SAVE_ROUTER); + return sizeof(mudinfo); +} + +varargs int purge_ip(string ip, int rude, mixed *sock_array){ + validate(); + if(!sock_array || !sizeof(sock_array)) sock_array = socket_names(); + foreach(mixed element in sock_array){ + int fd = element[0]; + if(last_string_element(element[3],".") != router_port) continue; + if(member_array(fd, keys(irn_sockets)) != -1) continue; + if(ip == "*") continue; + if(clean_fd(socket_address(fd)) == ip){ + if(query_connected_fds()[fd]){ + if(rude){ + server_log("router: fd to be rudely purged: "+fd+", "+query_connected_fds()[fd]); + disconnect_mud(query_connected_fds()[fd]); + } + } + } + } + return 1; +} + +varargs int purge_ips(int rude){ + mixed *sockies = socket_names(); + foreach(mixed element in sockies){ + string ip_address = element[3]; + if(last_string_element(ip_address,".") == router_port ){ + ip_address = replace_string(element[4],"."+last_string_element(element[4],"."),""); + purge_ip(ip_address,(rude || 0), sockies); + } + } + return 1; +} + +void update_imc2(string mud, mapping foo){ + validate(); + if(!mudinfo[mud]) return; + if(!mudinfo[mud]["other_data"]) mudinfo[mud]["other_data"] = ([]); + foreach(mixed key, mixed val in foo){ + mudinfo[mud]["other_data"][key] = val; + if(key == "port") mudinfo[mud]["player_port"] = val; + if(key == "versionid"){ + mudinfo[mud]["base_mudlib"] = val; + mudinfo[mud]["mudlib"] = val; + mudinfo[mud]["mud_type"] = "n/a"; + mudinfo[mud]["driver"] = "IMC2 client"; + } + } +} diff --git a/lib/secure/daemon/i3router/server_log.h b/lib/secure/daemon/i3router/server_log.h new file mode 100644 index 0000000..b67dc48 --- /dev/null +++ b/lib/secure/daemon/i3router/server_log.h @@ -0,0 +1,8 @@ +varargs void server_log(string str, string file){ + trr(str+"%^RESET%^"); + str = strip_colours(str); + if(!file){ + return log_file("router/server_log", timestamp()+" "+str+"\n"); + } + return log_file("router/"+file, timestamp()+" "+str+"\n"); +} diff --git a/lib/secure/daemon/imc2.c b/lib/secure/daemon/imc2.c new file mode 100644 index 0000000..8a45fc8 --- /dev/null +++ b/lib/secure/daemon/imc2.c @@ -0,0 +1,1712 @@ +// Tim Johnson +// Started on May 1, 2004. +// Use this however you want. + +#include <lib.h> +#include <logs.h> +#include <cgi.h> +#include <save.h> +#include NETWORK_H +#include <socket_err.h> +#include <daemons.h> +#include <message_class.h> + +//Which IMC version you wish to support. +#define IMC_VERSION 2 + +// Connection data for Davion's server +// HostIP overrides HOSTNAME, in case the mud doesn't want to resolve addresses +//#define HOSTNAME "server01.mudbytes.net" +#ifndef IMCTESTING +#define HOSTPORT 5000 +#define HOSTIP "50.116.16.90" +#endif + +// Connection data for Davion's other server +// HostIP overrides HOSTNAME, in case the mud doesn't want to resolve addresses +//#define HOSTPORT 9000 +//#define HOSTIP "74.207.247.83" + +//This is the LPMuds.net experimental IMC2 server. If you are +//already connected to LPMuds.net intermud using Intermud-3, do +//not use the LPMuds.net IMC2 server. +#ifdef IMCTESTING +#define HOSTPORT 8888 +#define HOSTIP "97.107.133.86" +#endif + +// What name the network knows your mud as. Replace MUD_NAME with "whatever" if you want it to be different. +#define MUDNAME (imc2_mud_name()) + +// COMMAND_NAME is the command that people type to use this network. +#define COMMAND_NAME "imc2" + +// NETWORK_ID is what your mud calls this network. +// This is the prefix that comes up on all messages to identify the IMC2 network. +// Tells for example look like: +// NETWORK_ID- Tim@TimMUD tells you: hi +// Make it similar to the command name, so players will understand. +// **OUTDATED +#define NETWORK_ID "IMC2" + +// DATA_LOG is where packets are logged to. +// Turn IMC2_logging off when not working on the system, as it invades privacy. +// Comment this out to turn it off. +#define IMC2_LOGGING + +#ifndef LOG_IMC2 +#define DATA_LOG "/secure/log/intermud/imc2" +#else +#define DATA_LOG LOG_IMC2 +#endif + +// UNKNOWN_DATA_LOG is where unrecognized packets are logged to. +// I wrote handlers for all packets I know of, so this should only pick +// up tests and possibly if anyone is creating new packets. +#define UNKNOWN_DATA_LOG DATA_LOG + +// Your MUD's URL is shared with other muds when building the mud list. +// This you could also put this in your who reply. +#define URL "http://dead-souls.net" + +// ANNOUNCE_LOG is where network announcements get logged to. +// I suggest you keep this turned on. +// These announcements seem to be about channels being created and +// deleted, but may possibly have more. +#define ANNOUNCE_LOG "IMC2_ANNOUNCEMENTS" + +// How many lines you want the backlog to be. +#define BACKLOG_SIZE 20 + +// Minimum permission number for channel to be viewable on the web. +#define BACKLOG_WEB_LEVEL 0 + +// What's the file for the channel daemon? +#ifndef CHANNEL_BOT +#define CHANNEL_BOT CHAT_D +#endif +#ifndef STREAM +#define STREAM 1 +#endif +#ifndef EESUCCESS +#define EESUCCESS 1 /* Call was successful */ +#endif +#ifndef THIS_PLAYER +#define THIS_PLAYER this_player() +#endif +#ifndef FIND_PLAYER +#define FIND_PLAYER(x) find_player(x) +#endif +#ifndef GET_CAP_NAME +#define GET_CAP_NAME(x) replace_string(x->GetName()," ","") +#endif +#ifndef GET_NAME +#define GET_NAME(x) convert_name(x->GetName()) +#endif +#ifndef IMC2_MSG +#define IMC2_MSG(x,y) foreach(tmpstr in explode(x,"\n")){ message("IMC2",tmpstr,y); } +#endif +#ifndef GET_GENDER +#define GET_GENDER(x) x->GetGender() +#endif +#ifndef ADMIN +#define ADMIN(x) archp(x) +#endif +#ifndef VERSION +#define VERSION "Tim's LPC IMC2 client 30-Jan-05 / Dead Souls integrated" +#endif + +#define HTML_LOCATION "http://dead-souls.net/" + +// Other things that could be #define'd... +// INVIS(x) !visible(x) +// TELL_BOT "/u/t/timbot/imc2_invalidtells.c" +// TELL_BOTS ([ "timbot" : "/u/t/timbot/imc2_tellbot.c" ]) +// CHAN_BOT "/u/t/timbot/imc2_chans.c" +// CHAN_BOTS ([ "ichat" : "/u/t/timbot/imc2_ichat.c" ]) +// USER_EXISTS(x) user_exists(x) + +// Mode decides what kind of packet is expected +#define NO_UIDS +#define MODE_CONNECTED 1 +#define MODE_WAITING_ACCEPT 2 +#define MODE_CONNECT_ERROR 3 +// Not used yet, I need to see what the hub sends. +#define MODE_HUB_DOWN 4 +// Not used yet either. +#define MODE_BANNED 5 + +inherit LIB_DAEMON; + +string tmpstr, host, who_str; +static string SaveFile, serverpass, clientpass; + +static int socket_num, counter; +static int heart_count = 0; +int mode, autodisabled = 1; +mapping ping_requests; // Keeps track of who sent a ping request. +// Ping requests aren't labelled with names, so replies are destined to this MUD +// with no idea why, unless we keep track. +string buf=""; // Buffer for incoming packets (aren't always sent 1 at a time) + +// Variables +static int xmit_to_network_room = 1; //enable this to make a lot of noise +static string hub_name, network_name; +float server_version; +static string lterm; +static float client_version = IMC_VERSION; +static mapping chaninfo; +mapping localchaninfo; // (["chan": ([ "perm":1, "name":"something", "users":({ }) ]) ]) +mapping mudinfo; +mapping genders; +mapping tells; +int sequence; + +// Prototypes :) +void create(); +void Setup(); +void remove(); +string pinkfish_to_imc2(string str); +string imc2_to_pinkfish(string str); +string escape(string str); +string unescape(string str); +mapping string_to_mapping(string str); +string main_help(); +void keepalive(string args, object who); + +string clean_str(string str); +private void send_packet(string sender, string packet_type, string target, string destination, string data); +private void send_text(string text); +private void got_packet(string info); +private void start_logon(); +private varargs void send_is_alive(string origin); +private void channel_in(string fromname, string frommud, mapping data); +private void tell_in(string sender, string origin, string target, mapping data); +private void beep_in(string sender, string origin, string target, mapping data); +private void who_reply_in(string origin, string target, mapping data); +private void whois_in(string fromname, string frommud, string targ, mapping data); +private void whois_reply_in(string targ,string fromname,string frommud,mapping data); +private void ping_reply_in(string sender,string origin,string target,mapping data); +private void chanwho_reply_in(string origin, string target, mapping data); +private void send_keepalive_request(); +private int chan_perm_allowed(object user, string chan); +private string localize_channel(string str); +private void chan_who_in(string fromname, string frommud, mapping data); +private void send_ice_refresh(); +private void resolve_callback(string address, string resolved, int key); + +// Sanity check: a null socket write tends to be a crasher +varargs static void validate(int i){ + if(i){ + if(!socket_status(i) || !socket_status(i)[5]){ + tn("%^RED%^BAD SOCKET ALERT. fd "+i+": "+ + identify(socket_status(i)),"red"); + error("Bad socket, fd "+i); + } + } +} + +varargs void write_to_log(string type, string wat){ + if(xmit_to_network_room){ + tn(wat); + } + unguarded( (: log_file($(type), $(wat)) :) ); +} + +// Functions for users to change. +int can_use(object user){ return 1; } // Is this person allowed to use IMC2 at all? This function determines if tells can be sent to the person and such. + +int level(object ob){ + // Outgoing packets are marked with the user's level. + // This function figures it out. + // If you have different ways of ranking, make this function convert them to what IMC2 uses. + // IMC2 uses: Admin=5, Imp=4, Imm=3, Mort=2, or None=1 + if(ADMIN(ob)) return 5; // Admin + //TMI-2: if(wizardp(ob)) return 3; + //TMI-2: if(userp(ob)) return 2; + //Discworld: if(ob->query_creator()) return 3; + if(this_player()) return 2; + return 1; // None +} + +string chan_perm_desc(int i){ + // Given the permission level assigned locally to a channel, return a short + // string describing what the number means. The number means nothing + // outside of this MUD. Also, they are independant of each other, and + // so you can do groups without having to always do subgroups of higher + // ones or anything like 'levels'. BACKLOG_WEB_LEVEL is the only one of + // significance, as it's the only one that the web backlog thing works on. + switch(i){ + case 2: return "arch"; + case 1: return "creator"; + case 0: return "public"; + } + return "invalid"; +} + +int chan_perm_allowed(object user, string chan){ + // Using the permission level assigned locally to a channel, + // return 1 if user is allowed to use the channel, 0 if not. + switch(localchaninfo[chan]["perm"]){ + case 2: if(archp(user)) return 1; return 0; + case 1: if(creatorp(user)) return 1; return 0; + case 0: return 1; + } +} + + +// Shouldn't have to change anything beyond this point. + +void write_callback(int fd){ +#ifdef IMC2_LOGGING + write_to_log(DATA_LOG,"Write_Callback. \n"); +#endif + start_logon(); +} + +void read_callback(int socket, mixed info){ + string a,b,tmp; + int done=0; + counter = time(); + + //tc("read_callback","white"); + //tmp = replace_string(info, "\n", "(LF)"); + //tmp = replace_string(tmp, "\r", "(CR)"); + //tc("read_callback: "+tmp+"\n"); + +#ifdef IMC2_LOGGING + write_to_log(DATA_LOG,"SERVER: "+info+"\n"); +#endif + + if(!sizeof(info)) return 0; + buf += info; + + // The hub groups packets, unfortunately. + switch(mode){ + case MODE_WAITING_ACCEPT: // waiting for Hub to send autosetup + if(sscanf(info, "autosetup %s accept %s"+lterm, + hub_name, network_name)==2){ + mode = MODE_CONNECTED; + if(network_name) network_name = clean_str(network_name); + send_is_alive("*"); + send_keepalive_request(); + send_ice_refresh(); + } else if(sscanf(info, "PW %s %s version=%f %s"+lterm[0..0], + hub_name, serverpass, server_version, network_name)==4){ + mode = MODE_CONNECTED; + if(network_name) network_name = clean_str(network_name); + send_is_alive("*"); + send_keepalive_request(); + send_ice_refresh(); + } else{ // Failed login sends plaintext error message. + tn("IMC2 Failed to connect... "+info); + mode = MODE_CONNECT_ERROR; + set_heart_beat(22000); //Try again much later + return; + } + buf=""; // clear buffer + break; + case MODE_CONNECTED: + while(!done){ + if(sscanf(buf,"%s\n\r%s",a,b)==2){ // found a break... + //if(IMC_VERSION > 2) tc("LFCR: "+a,"red"); + got_packet(a); + buf=b; + } + else if(sscanf(buf,"%s\r\n%s",a,b)==2){ // found a break... + //if(IMC_VERSION < 2.1) tc("CRLF","green"); + got_packet(a); + buf=b; + } + else { // no break... + if(sizeof(b)){ + tmp = replace_string(b, "\n", "(LF)"); + tmp = replace_string(tmp, "\r", "(CR)"); + //tc("remainder: "+identify(tmp)); + got_packet(b+lterm); + } + done = 1; + } + } + break; + } + return; +} + +private void got_packet(string info){ + string str, tmp; + string a,b, my_ip; + int i; + string sender, origin, route, packet_type, target, destination, strdata; + int sequence, my_port; + mapping data; + object who; + if(!sizeof(info)){ + tn("No info?"); + return; + } +#ifdef IMC2_LOGGING + tmp = replace_string(info,"\n","(LF)"); + tmp = replace_string(tmp,"\r","(CR)"); + write_to_log(DATA_LOG,"GOT PACKET: "+tmp+"\n"); +#endif + + counter = time(); + str = info; + // messages end with " \n\r" or "\n" or sometimes just a space + sscanf(str, "%s\n^", str); + sscanf(str, "%s\r^", str); + sscanf(str, "%s ^", str); + sscanf(str, "%s ^", str); + if(sscanf(str, "%s %d %s %s %s %s", + a, sequence, route, packet_type, + b, strdata)==6){ // matches + if(sscanf(b,"%s@%s",target,destination)!=2){ + // Could be MUD instead of Name@MUD or *@MUD + target="*"; destination=b; + } + if(sscanf(a,"%s@%s",sender,origin)!=2){ + sender="*"; origin=a; + } + data = string_to_mapping(strdata); + if(!mudinfo[origin]) mudinfo[origin] = ([ ]); + + switch(packet_type){ + case "is-alive": // For making a MUD list. + if(!mudinfo[origin]) mudinfo[origin] = ([ ]); + // example of info: + // versionid=\"IMC2 AntiFreeze CL-2 SWR 1.0\" url=none md5=1 + //mudinfo[origin]["version"]="blah"; + if(!mudinfo[origin]["online"]){ + CHAT_D->eventSendChannel(origin+"@IMC2","muds", + "%^BOLD%^%^BLUE%^online%^RESET%^",0); + } + mudinfo[origin]+=data; + mudinfo[origin]["online"]=1; + break; + case "close-notify": // Someone disconnected. + if(!mudinfo[data["host"]]) mudinfo[data["host"]] = ([]); + if(mudinfo[data["host"]]["online"]){ + CHAT_D->eventSendChannel(data["host"]+"@IMC2","muds", + "%^BOLD%^%^RED%^offline%^RESET%^",0); + } + mudinfo[data["host"]]["online"]=0; + break; + case "keepalive-request": // Request for is-alive. + send_is_alive(origin); + break; + case "ice-msg-b": // Broadcast channel message. + channel_in(sender, origin, data); + break; + case "tell": // Tells or emotes. + tell_in(sender, origin, target, data); + break; + case "who-reply": + who_reply_in(origin,target,data); + break; + case "whois": // Like I3's locate + whois_in(sender,origin,target,data); + break; + case "whois-reply": + whois_reply_in(target,sender,origin,data); + break; + case "beep": + beep_in(sender, origin, target, data); + break; + case "ice-update": // Reply from ice-refresh. + chaninfo[data["channel"]]=data; + break; + case "wHo": // Drop-through + case "who": + if(sizeof(host)) my_ip = host; + else my_ip = INTERMUD_D->GetMyIp(); + if(my_ip == "127.0.0.1"){ + my_ip = "dead-souls.net"; + my_port = 8000; + } + else my_port = query_host_port(); + who_str=CGI_WHO->gateway(1)+URL+"\ntelnet://"+my_ip+":"+my_port+"\n"; + who_str += repeat_string("_", 75); + send_packet("*","who-reply",sender,origin, + "text="+escape(pinkfish_to_imc2(who_str))); + CHAT_D->eventSendChannel("SYSTEM","intermud","[" + capitalize(sender)+"@"+origin+ + " requests the IMC2 who list]",0); + break; + case "ice-destroy": // Deleting channel. + map_delete(chaninfo,data["channel"]); + break; + case "user-cache": // User info, like I3's ucache service. + if(!genders[origin]) genders[origin]=([ ]); + genders[origin][sender]=data["gender"]; + break; + case "user-cache-reply": // Reply with user info + if(!genders[origin]) genders[origin]=([ ]); + genders[origin][data["user"]]=data["gender"]; + break; + case "user-cache-request": // Request for user info + sscanf(data["user"],"%s@%*s",str); + if(str) who = FIND_PLAYER(lower_case(str)); + if(who +#ifdef INVIS + && !INVIS(who) +#endif + ){ + switch(GET_GENDER(who)){ + case "male" : i=0; break; + case "female" : i=1; break; + default : i=2; break; + } + send_packet("*","user-cache-reply",sender, + origin,sprintf("gender=%d",i)); + } + break; + case "ping": + send_packet("*","ping-reply",sender,origin, + sprintf("path=\"%s\"",route)); + break; + case "ping-reply": + ping_reply_in(sender,origin,target,data); + break; + case "ice-msg-r": // Relayed channel message. + channel_in(sender, origin, data); + CHAT_D->eventSendChannel("IMC2Test:"+sender,"admin","ice-msg-r sender:"+sender+"; origin:" +origin+"; data:"+(string)data); + break; + case "ice-chan-whoreply": // Tell who's listening to a channel. + chanwho_reply_in(origin,target,data); + break; + case "emote": // Channel creation/destruction message... anything else? + CHAT_D->eventSendChannel("IMC2:"+NETWORK_ID,"admin",data["text"]); +#ifdef ANNOUNCE_LOG + write_to_log(ANNOUNCE_LOG,ctime(time())+": "+data["text"]+"\n"); +#endif + break; + case "ice-chan-who": // Check who's listening to a channel. + chan_who_in(sender,origin,data); + break; + case "channel-notify": + // Don't care about this. Useful only if you care when + // people on other MUDs start/stop listening to a channel. + // example: Someone@SomeMUD 1087076772 SomeMUD channel-notify *@* channel=Hub01:ichat status=0 + break; + // The following packets shouldn't be incoming. + case "ice-cmd": // Remote channel administration + case "remote-admin": // For controlling the hub + case "ice-refresh": // Request data about channels + case "ice-msg-p": // Private channel message + break; + default: +#ifdef UNKNOWN_DATA_LOG + write_to_log(UNKNOWN_DATA_LOG,"Unknown packet: "+escape(info)+"\n\n"); +#endif + break; + } + } + else{ + buf += info; +#ifdef BAD_PACKET + write_to_log(BAD_PACKET,"Doesn't match incoming pattern: "+str+"\n"); +#endif + } +} + +private int close_callback(object socket){ + // Connection was closed. +#ifdef IMC2_LOGGING + write_to_log(DATA_LOG,"DISCONNECTED\n"); +#endif + socket_close(socket_num); + mode = MODE_WAITING_ACCEPT; + create(); + return 1; +} + +private void send_text(string text){ + string tmp; + text = clean_str(text); + text += lterm; + tmp = replace_string(text, "\n", "(LF)"); + tmp = replace_string(tmp, "\r", "(CR)"); + // Send a literal string. + // Almost everything should use the send_packet function instead of this. +#ifdef IMC2_LOGGING + write_to_log(DATA_LOG,"CLIENT: "+save_variable(tmp)+"\n"); + //tc("send_text: "+tmp); +#endif + validate(socket_num); + socket_write(socket_num,text); + return; +} + +void create(){ + SaveFile = save_file(SAVE_IMC2); + SetSaveFile(SaveFile); + if(unguarded( (: file_exists(SaveFile) :) )) + RestoreObject(SaveFile); + if(!file_exists(SaveFile) && file_exists(old_savename(SaveFile))){ + cp(old_savename(SaveFile), SaveFile); + } +#if DISABLE_IMC2 + //tn("IMC2: destruicted "+ctime(time())); + //unguarded( (: destruct() :) ); +#else + if(mode != MODE_CONNECT_ERROR){ + set_heart_beat(10); + } + counter = time(); + tn("IMC2: created "+ctime(time())); +#endif + if(client_version > 2){ + lterm = "\r\n"; + } + else { + lterm = "\n\r"; + } + call_out( (: Setup :), 1); +} + +void Setup(){ + int temp, kill, my_port; + string my_ip; + +#ifdef DISABLE_IMC2 + if(DISABLE_IMC2){ + kill = 1; + } +#endif + + if(DISABLE_INTERMUD == 1){ + kill = 1; + } + + if(kill || autodisabled){ + call_out( (: eventDestruct() :), 5); + return; + } + else { + clientpass = SECRETS_D->GetSecret("IMC2_CLIENT_PW"); + serverpass = SECRETS_D->GetSecret("IMC2_SERVER_PW"); + if(sizeof(host)) my_ip = host; + else my_ip = INTERMUD_D->GetMyIp(); + if(my_ip == "127.0.0.1"){ + my_ip = "dead-souls.net"; + my_port = 8000; + } + else my_port = query_host_port(); + who_str = CGI_WHO->gateway(1)+URL+"\ntelnet://"+my_ip+":"+my_port+"\n"; + who_str += repeat_string("_", 75); + } + tn("IMC2: setup "+ctime(time())); +#ifndef NO_UIDS + seteuid(getuid()); +#endif + tn("Creating IMC2 object at "+ctime(time())+".\n"); +#ifdef IMC2_LOGGING + write_to_log(DATA_LOG,"Creating IMC2 object at "+ctime(time())+".\n"); +#endif + if(!mudinfo) mudinfo = ([ ]); + if(!chaninfo) chaninfo = ([ ]); + if(!localchaninfo) localchaninfo = ([ ]); + if(!genders) genders = ([ ]); + if(!tells) tells=([ ]); + ping_requests=([ ]); + mode = MODE_WAITING_ACCEPT; + if(my_ip == "dead-souls.net"){ + catch( host = query_intermud_ip() ); + if(!sizeof(host)) host = "dead-souls.net"; + } + else host = my_ip; +#ifdef HOSTIP + // We already know the IP, go straight to the connecting, just do callback as if it found the IP. + resolve_callback(HOSTIP,HOSTIP,1); +#else + temp = resolve(HOSTNAME, "resolve_callback"); + if(temp == 0){ +#ifdef IMC2_LOGGING + write_to_log(DATA_LOG,"Addr_server is not running, resolve failed.\n"); +#endif + eventDestruct(); + return; + } +#endif + SaveObject(SaveFile, 1); +} + +void heart_beat(){ + int lastmsg = time() - counter; + heart_count++; + if(heart_count > 4){ + mixed sstat = socket_status(socket_num); + heart_count = 0; + if( lastmsg > 300 && lastmsg < 900){ + tn("IMC2 heartbeat: Last message "+time_elapsed(lastmsg)+" ago."); + tn("sending keepalive"); + send_keepalive_request(); + } + if( lastmsg > 400 + ||!sstat || sstat[1] != "DATA_XFER"){ + socket_close(socket_num); + tn("IMC2 heartbeat: reloading IMC2_D due to timeout"); +#ifdef IMC2_LOGGING + write_to_log(DATA_LOG,"IMC2 TIMEOUT! Reloading.\n"); +#endif + + RELOAD_D->eventReload(this_object(), 2, 1); + } + } +} + +void remove(){ + // This object is getting destructed. + tn("removing imc2. stack: "+get_stack(1)); + mode=2; + SaveObject(SaveFile, 1); + socket_close(socket_num); +#ifdef IMC2_LOGGING + write_to_log(DATA_LOG,"IMC2 OBJECT REMOVED\n"); +#endif +} + +static mixed GetChanInfo(){ + mixed foo = copy(chaninfo); + return 1; +} + +string *GetChanList(){ + if(!chaninfo) return ({}); + return keys(chaninfo); +} + +int eventDestruct(){ + remove(); + return ::eventDestruct(); +} + +void resolve_callback( string address, string resolved, int key ) { + // Figured out what the IP is for the address. + int error; + + write_file("/tmp/imc2.log","address: "+address+"\n"); + write_file("/tmp/imc2.log","resolved: "+resolved+"\n"); + write_file("/tmp/imc2.log","key: "+key+"\n"); + + socket_num = socket_create(STREAM, "read_callback", "close_callback"); + if (socket_num < 0) { +#ifdef IMC2_LOGGING + write_to_log(DATA_LOG,"socket_create: " + socket_error(socket_num) + "\n"); +#endif + return; + } +#ifdef IMC2_LOGGING + write_to_log(DATA_LOG,"socket_create: Created Socket " + socket_num + "\n"); +#endif + + error = socket_connect(socket_num, resolved+" "+HOSTPORT, "read_callback", "write_callback"); + if (error != EESUCCESS) { +#ifdef IMC2_LOGGING + write_to_log(DATA_LOG,"socket_connect: " + socket_error(error) + "\n"); +#endif + socket_close(socket_num); + //Timeouts on windows lag the whole mud. This disables the daemon + //to prevent that. + if(query_os_type() == "windows" && grepp(socket_error(error), "Problem with connect")){ + load_object("/secure/cmds/admins/mudconfig")->cmd("imc2 disable"); + } + return; + } +#ifdef IMC2_LOGGING + write_to_log(DATA_LOG,"socket_connect: connected socket " + socket_num + " to " + resolved+" "+HOSTPORT + "\n"); +#endif +} + +void start_logon(){ +#if NOT_AUTO + //tc("1, version: "+IMC_VERSION); + send_text(sprintf("PW %s %s version=%s"+lterm, +#else + //tc("2, version: "+IMC_VERSION); + send_text(sprintf("PW %s %s version=%s autosetup %s"+lterm, +#endif + MUDNAME, + clientpass, IMC_VERSION+"" +#ifndef NOT_AUTO + , serverpass +#endif + )); + buf=""; + /* For invitation-only networks. + //tc("3, wtf"); + send_text(sprintf("PW %s %s version=%s %s"+lterm, + MUDNAME, + clientpass, IMC_VERSION+"", "hub03" + )); + */ + sequence=time(); + } + string clean_str(string str){ + while(sizeof(str) && str[<1] < 32){ + str = str[0..<2]; + } + return str; + } + + string escape(string str){ + str=replace_string(str,"\\","\\\\"); + str=replace_string(str,"\"","\\\""); + str=replace_string(str,"\n","\\n"); + str=replace_string(str,"\r","\\r"); + if(sizeof(explode(str," "))!=1) str = "\""+str+"\""; + return str; + } + + string unescape(string str){ + string a,b=str,output=""; + while(sscanf(b,"%s\\%s",a,b)==2){ + output += a; + if(sizeof(b)){ + switch(b[0]){ + case 34 : output += "\""; break; // '\"' makes warnings. + case '\\' : output += "\\"; break; + case 'n' : output += "\n"; break; + case 'r' : output += "\r"; break; + } + } + b=b[1..]; + } + output += b; + output = replace_string(output,"\n\r","\n"); + if((sizeof(explode(output," "))==1) && sscanf(output,"\\\"%*s\\\"") ) output = "\""+output+"\""; + return output; + } + + mapping string_to_mapping(string str){ + // Picks first element off of string and then repeats? + mapping out=([]); + int i; + string what,data,rest; + + rest = str; + + while(sizeof(rest)>0){ + sscanf(rest, "%s=%s", what, rest); + /* + write("what="+what+", rest="+rest+"\n"); + */ + // At this point, what is the key, rest is value plus rest. + if(rest[0]==34){ // value is in quotes, tons of fun! + // find first quote without a backslash in front? + /* + write("rest begings with a quote\n"); + */ + i = 1; + while(((rest[i]!=34) || (rest[i-1]==92)) && (i<sizeof(rest))){ // 34 = ", 92 = \ + // While this is not a quote, or if this is an escaped quote, keep looking. + i++; + } + // now are 1 space past quote + data=rest[1..(i-1)]; // skip opening and closing quotes + rest=rest[(i+2)..]; // skip past space + // Data is now what was in the quotes... now to un-escape the data... + out[what]=unescape(data); + } + else{ // value is not in quotes, tons of actual non-sarcastic fun! + // just split it at the first space + if(sscanf(rest,"%s %s",data,rest)!=2){ // break at first space + data = rest; + rest = ""; + } + if((sscanf(data,"%d",i)==1) && (sprintf("%d",i)==data)) // is just number + out[what]=i; + else // not just a number + out[what]=data; + } + } + return out; + } + + void send_packet(string sender, string packet_type, string target, string destination, string data){ + // Sends a packet in the format that IMC2 uses. + sequence++; + send_text(sprintf("%s@%s %d %s %s %s@%s %s", + sender, MUDNAME, sequence, MUDNAME, packet_type, + target, destination, clean_str(data))); + } + + void send_keepalive_request(){ + // Ask all the muds to tell us that they're alive. + string mud; + // Mark all the muds as offline until they respond. + foreach(mud in keys(mudinfo)){ + mudinfo[mud]["online"]=0; + } + send_packet("*","keepalive-request","*","*",""); + } + + varargs void send_is_alive(string origin){ + // Sends an is-alive packet to whoever requested it, or else broadcasts it. + send_packet("*","is-alive","*", (origin ? origin : "*"), +#if 1 + "versionid=\""+VERSION+"\" networkname="+network_name+ + " url="+URL+" host="+host+" port="+query_host_port()); +#else + "foo"); +#endif + } + + void channel_in(string fromname, string frommud, mapping data){ + string sender; + string localchan; + + int emote=0; + + sender=fromname+"@"+frommud; + if(data["sender"]) sender = data["sender"]; + if(data["realfrom"]) sender = data["realfrom"]; + if(intp(data["text"])) data["text"]=sprintf("%d",data["text"]); + + if(data["emote"]) emote = data["emote"]; + //Following fix courtesy of Tricky + if (emote == 1 && strsrch(data["text"], "$N") == -1) + data["text"] = "$N " + data["text"]; + + localchan = CHANNEL_BOT->GetLocalChannel(data["channel"]); + CHANNEL_BOT->eventSendChannel(sender, localchan, + imc2_to_pinkfish(data["text"]), emote, "", ""); + } + + void channel_out(string user,string chan,string msg,int emote){ + // Send outgoing channel message. + send_packet(user,"ice-msg-b","*","*", sprintf("channel=%s text=%s emote=%d echo=0", chan,escape(pinkfish_to_imc2(msg)),emote)); + } + + varargs static void tell_out(object from, string targname, string targmud, string msg, int reply, int emote){ + string ret = "%^BOLD%^RED%^You tell " + capitalize(targname) + + "@" + targmud + ":%^RESET%^ " + msg; + + //Check for privs to send imc tell + if(RESTRICTED_INTERMUD) { + if(!imud_privp(lower_case(from->GetKeyName()))) { + this_player(1)->eventPrint("You lack the power to send tells to other worlds.", MSG_CONV); + return; + } + } + + // Send outgoing tell. + if(!reply) reply=0; + send_packet(capitalize(from->GetKeyName()),"tell",targname,targmud, + "text="+escape(msg)); + from->eventPrint(ret, MSG_CONV); + from->eventTellHist(ret); + } + + void tell_in(string sender, string origin, string target, mapping data){ + // Incoming tell. Parse and display to user + object who; + int sz; + string blmsg, ret, eret; + if(target){ + who = FIND_PLAYER(lower_case(target)); + INSTANCES_D->SendTell(lower_case(target), data["text"], + sender + "@" + origin); + } + if(who) target = GET_CAP_NAME(who); + else return; + data["text"]=imc2_to_pinkfish(data["text"]); + who->SetProperty("reply",sender+"@"+origin); + who->SetProperty("reply_time", time()); + eret = "%^BOLD%^RED%^" + sender + "@" + origin + + " %^RESET%^ " + data["text"]; + ret = "%^BOLD%^RED%^" + sender + "@" + origin + + " tells you:%^RESET%^ " + data["text"]; + if(who +#ifdef INVIS + && VISIBLE(who) +#endif + && can_use(who) + ){ + switch(data["isreply"]){ + case 2: // emote + ret = eret; + who->eventPrint(ret, MSG_CONV); + blmsg=sprintf("%s@%s %s\n",sender,origin,data["text"]); + break; + case 1: // reply + who->eventPrint(ret, MSG_CONV); + blmsg=sprintf("%s@%s replied to you: %s\n", NETWORK_ID,sender,origin,data["text"]); + break; + default: + who->eventPrint(ret , MSG_CONV); + blmsg=sprintf("%s@%s told you: %s\n", sender,origin,data["text"]); + break; + } + who->eventTellHist(ret); + if(!tells[target]) + tells[target]=([ ]); + tells[target]["reply"] = sprintf("%s@%s",sender,origin); + if(!tells[target]["backlog"] || !arrayp(tells[target]["backlog"])) + tells[target]["backlog"]=({ }); + tells[target]["backlog"] += ({ blmsg }); + sz = sizeof(tells[target]["backlog"]); + if(sz>BACKLOG_SIZE) + tells[target]["backlog"]=tells[target]["backlog"][(sz-BACKLOG_SIZE)..sz]; + } else { +#ifdef TELL_BOTS + // Can have a mapping of bots which can get tells. + if(TELL_BOTS[target]){ + call_other(TELL_BOTS[target],"got_tell",sender, origin, target, data["text"]); + return; + } +#endif +#ifdef TELL_BOT + // They should have got_tell(fromname, frommud, target, text) + // I'll assume bots don't care about emote/reply... tell me if you do? + // TELL_BOT will get told of all tells which don't have a valid target, and + // then the sender will be notified that it didn't get to anyone. + // This would be useful if for example you wanted all tells sent to + // offline people to be mudmailed to them or something. + call_other(TELL_BOT,"got_tell",sender, origin, target, data["text"]); +#endif + send_packet("*","tell",sender,origin, + sprintf("level=-1 text=\"%s is not online on this mud.\" isreply=1",target)); + } + } + + int tell(mixed arg, object who){ + string targmud,targplayer,msg; + int i; + if(!who || !this_player() || who != this_player()) return 0; + if(who->GetForced()){ + return 0; + } + i = sscanf(arg,"%s@%s %s",targplayer, targmud, msg); + if(i != 3 ){ + write("There was an error in your message. See: \"help imc2\""); + return 1; + } + tell_out(who, targplayer, this_object()->find_mud(targmud), msg, 0, 0); + return 1; + } + + string pinkfish_to_imc2(string str){ + // Foreground + str=replace_string(str,"%^BLACK%^","~x"); // Black + str=replace_string(str,"%^RED%^","~R"); // Red + str=replace_string(str,"%^GREEN%^","~G"); // Green + str=replace_string(str,"%^BLUE%^","~B"); // Blue + str=replace_string(str,"%^WHITE%^","~W"); // White + str=replace_string(str,"%^ORANGE%^","~y"); // Orange + str=replace_string(str,"%^CYAN%^","~c"); // Cyan + str=replace_string(str,"%^YELLOW%^","~Y"); // Yellow + str=replace_string(str,"%^MAGENTA%^","~p"); // Magenta -> purple sounds closest + str=replace_string(str,"%^GRAY%^","~w"); // Gray doesn't display on my MUD, bah :( + // Background + str=replace_string(str,"%^B_BLACK%^","^x"); + str=replace_string(str,"%^B_RED%^","^R"); // Red + str=replace_string(str,"%^B_GREEN%^","^G"); // Green + str=replace_string(str,"%^B_BLUE%^","^b"); // Blue + str=replace_string(str,"%^B_WHITE%^","^W"); // White + str=replace_string(str,"%^B_ORANGE%^","^O"); // Orange + str=replace_string(str,"%^B_CYAN%^","^c"); // Cyan + str=replace_string(str,"%^B_YELLOW%^","^Y"); // Yellow + str=replace_string(str,"%^B_MAGENTA%^","^p"); // Magenta -> purple sounds closest + // Misc. + str=replace_string(str,"%^FLASH%^","~$"); // Flash -> Blink + str=replace_string(str,"%^BOLD%^","~L"); // Bold + str=replace_string(str,"%^RESET%^","~!"); + //Replace anything that was done in %^BOLD%^RED%^ format and wasn't already caught + str=replace_string(str,"%^FLASH","~$"); // Flash -> Blink + str=replace_string(str,"%^BOLD","~L"); // Bold + str=replace_string(str,"%^RESET","~!"); + str=replace_string(str,"FLASH%^","~$"); // Flash -> Blink + str=replace_string(str,"BOLD%^","~L"); // Bold + str=replace_string(str,"RESET%^","~!"); + return str; + } + + string imc2_to_pinkfish(string str){ + string output=""; + int sz; + str = replace_string(str+"", "/~", "/~~"); + /* + For colors explanation, refer to IMC Packet Documentation by Xorith. + Thanks very much for putting that out, by the way. :) + Found at http://hub00.muddomain.com/imc2_protocol_doc.txt + */ + sz=sizeof(str)-1; + while(sizeof(str)>1){ + switch(str[0]){ + case '~': // Foreground + switch(str[1]){ + case 'Z': break; // Random + case 'x': output += "%^BLACK%^"; break; // Black + case 'r': output += "%^RED%^"; break; // Dark Red + case 'g': output += "%^GREEN%^"; break; // Dark Green + case 'y': output += "%^ORANGE%^"; break; // Orange + case 'b': output += "%^BLUE%^"; break; // Dark Blue + case 'p': output += "%^MAGENTA%^"; break; // Purple + case 'c': output += "%^CYAN%^"; break; // Cyan + case 'w': output += "%^WHITE%^"; break; // Grey + case 'D': output += "%^BLACK%^"; break; // Dark Grey + case 'z': output += "%^BLACK%^"; break; // Same as ~D + case 'R': output += "%^RED%^"; break; // Red + case 'G': output += "%^GREEN%^"; break; // Green + case 'Y': output += "%^YELLOW%^"; break; // Yellow + case 'B': output += "%^BLUE%^"; break; // Blue + case 'P': output += "%^MAGENTA%^"; break; // Pink + case 'C': output += "%^BLUE%^"; break; // Light Blue + case 'W': output += "%^WHITE%^"; break; // White + + case 'm': output += "%^MAGENTA%^"; break; // same as p + case 'd': output += "%^WHITE%^"; break; // same as w + case 'M': output += "%^MAGENTA%^"; break; // same as P + // Misc. + case '!': output += "%^RESET%^"; break; // Reset + case 'L': output += "%^BOLD%^"; break; // Bold + case 'u': break; // Underline + case '$': output += "%^FLASH%^"; break; // Blink + case 'i': break; // Italic + case 'v': break; // Reverse + case 's': break; // Strike-thru + + case '~': output += "~"; break; // ~~ prints as ~ + default : output += "~"; // Don't skip over this + // (cheap hack is to add a character in front so the [2..] thing still works) + str = " "+str; + break; + } + str=str[2..]; + break; + case '^': // Background + switch(str[1]){ + case 'Z': break; // Random + case 'x': output += "%^B_BLACK%^"; break; // Black + case 'r': output += "%^B_RED%^"; break; // Dark Red + case 'g': output += "%^B_GREEN%^"; break; // Dark Green + case 'O': output += "%^B_ORANGE%^"; break; // Orange + case 'B': output += "%^B_BLUE%^"; break; // Dark Blue + case 'p': output += "%^B_MAGENTA%^"; break; // Purple + case 'c': output += "%^B_CYAN%^"; break; // Cyan + case 'w': output += "%^B_WHITE%^"; break; // Grey + case 'z': output += "%^B_BLACK%^"; break; // Dark Grey + case 'R': output += "%^B_RED%^"; break; // Red + case 'G': output += "%^B_GREEN%^"; break; // Green + case 'Y': output += "%^B_YELLOW%^"; break; // Yellow + case 'b': output += "%^B_BLUE%^"; break; // Blue + case 'P': output += "%^B_MAGENTA%^"; break; // Pink + case 'C': output += "%^B_BLUE%^"; break; // Light Blue + case 'W': output += "%^B_WHITE%^"; break; // White + case '^': output += "^"; break; // ^^ prints as ^ + default : output += "^"; // Don't skip over this + // (cheap hack is to add a character in front so the [2..] thing still works) + str = " "+str; + break; + } + str=str[2..]; + break; + case '`': // Blinking Foreground + switch(str[1]){ + case 'Z': output += "%^FLASH%^"; break; // Random + case 'x': output += "%^FLASH%^%^BLACK%^"; break; // Black + case 'r': output += "%^FLASH%^%^RED%^"; break; // Dark Red + case 'g': output += "%^FLASH%^%^GREEN%^"; break; // Dark Green + case 'O': output += "%^FLASH%^%^ORANGE%^"; break; // Orange + case 'b': output += "%^FLASH%^%^BLUE%^"; break; // Dark Blue + case 'p': output += "%^FLASH%^%^MAGENTA%^"; break; // Purple + case 'c': output += "%^FLASH%^%^CYAN%^"; break; // Cyan + case 'w': output += "%^FLASH%^%^WHITE%^"; break; // Grey + case 'z': output += "%^FLASH%^%^BLACK%^"; break; // Dark Grey + case 'R': output += "%^FLASH%^%^RED%^"; break; // Red + case 'G': output += "%^FLASH%^%^GREEN%^"; break; // Green + case 'Y': output += "%^FLASH%^%^YELLOW%^"; break; // Yellow + case 'B': output += "%^FLASH%^%^BLUE%^"; break; // Blue + case 'P': output += "%^FLASH%^%^MAGENTA%^"; break; // Pink + case 'C': output += "%^FLASH%^%^BLUE%^"; break; // Light Blue + case 'W': output += "%^FLASH%^%^WHITE%^"; break; // White + case '`': output += "`"; break; // `` prints as ` + default : output += "`"; // Don't skip over this + // (cheap hack is to add a character in front so the [2..] thing still works) + str = " "+str; + break; + } + str=str[2..]; + break; + default: + output += str[0..0]; + str=str[1..]; + break; + } + } + output += str; + return output; + } + + private void who_reply_in(string origin, string target, mapping data){ + string output; + object targuser; + if(target) targuser = FIND_PLAYER(lower_case(target)); + if(targuser){ + output = NETWORK_ID+" who reply from: %^CYAN%^"+origin+"%^RESET%^\n"; + output += imc2_to_pinkfish(data["text"])+"\n"; + IMC2_MSG(output,targuser); + } + } + + private void whois_in(string fromname, string frommud, string targ, mapping data){ + if(targ && FIND_PLAYER(lower_case(targ)) +#ifdef INVIS + && !INVIS(FIND_PLAYER(lower_case(targ))) +#endif + && can_use(FIND_PLAYER(lower_case(targ))) + ){ + send_packet(targ,"whois-reply",fromname,frommud,"text=Online"); + } +#ifdef USER_EXISTS + else if(USER_EXISTS(lower_case(targ))){ + send_packet(targ,"whois-reply",fromname,frommud, + "text=\"Exists but is offline\""); + } +#endif + } + + private void whois_reply_in(string targ,string fromname,string frommud,mapping data){ + object who; + if(targ) who = FIND_PLAYER(lower_case(targ)); + if(who){ + IMC2_MSG(sprintf("%s whois reply: %s@%s: %s\n", + NETWORK_ID,fromname,frommud,data["text"]),who); + } + } + + private void beep_in(string sender, string origin, string target, mapping data){ + object who; + if(target) who = FIND_PLAYER(lower_case(target)); + if(who && can_use(who) +#ifdef INVIS + && VISIBLE(who) +#endif + ){ + IMC2_MSG(sprintf("%s- %%^CYAN%%^%s@%s%%^RESET%%^ \abeeps you.\n", + NETWORK_ID,sender,origin,data["text"]), who); + } + else{ + send_packet("*","tell",sender,origin, + sprintf("level=-1 text=\"%s is not online.\" isreply=1",target)); + } + } + + void beep_out(object from, string targname, string targmud){ + send_packet(GET_CAP_NAME(from),"beep",targname,targmud, + sprintf("level=%d ", level(from))); + } + + void send_ice_refresh(){ send_packet("*","ice-refresh","*","*",""); } + + void ping_reply_in(string sender,string origin,string target,mapping data){ + object who; + if((target=="*") && target=ping_requests[sender]){ + target=ping_requests[sender]; + map_delete(ping_requests,sender); + } + if(target) who = FIND_PLAYER(lower_case(target)); + if(who){ + IMC2_MSG(sprintf("%s route to %%^CYAN%%^%s%%^RESET%%^ is: %s\n", + NETWORK_ID,origin,data["path"]), who); + } + } + + void ping_out(string from,string targmud){ send_packet(from,"ping","*",targmud,""); } + varargs void who_out(string from,string targmud,string type){ send_packet(from,"who","*",targmud,(type ? sprintf("type=\"%s\"",type) : "type=who")); } + + void chanwho_out(object from,string chan,string mud){ + send_packet(GET_CAP_NAME(from),"ice-chan-who","*",mud, + sprintf("level=%d channel=%s lname=%s",level(from), + localchaninfo[chan]["name"],chan)); + } + + void chanwho_reply_in(string origin, string target, mapping data){ + string output; + object targuser; + if(target) targuser = FIND_PLAYER(lower_case(target)); + if(targuser){ + output = NETWORK_ID+" chanwho reply from "+origin+" for "+data["channel"]+"\n"; + output += imc2_to_pinkfish(data["list"]); + IMC2_MSG(output,targuser); + } + } + + void chan_who_in(string fromname, string frommud, mapping data){ + // Handles an incoming channel who request. + } + + string find_mud(string str){ + // Makes case-insensitive mud name into the actual mud name, or else 0. + string mud; + string *mudses = filter(keys(mudinfo), (: mudinfo[$1] && + mudinfo[$1]["online"] == 1 :) ); + if (!str) return 0; + if(member_array(str, mudses) != -1) return str; + str = lower_case(str); + foreach(mud in mudses){ + if ( lower_case(mud)==str ) return mud; + } + return 0; + } + + string localize_channel(string str){ + // Tells what the local name for a channel is, given the network name for it, or else 0. + string a; + foreach(a in keys(localchaninfo)){ + if(lower_case(localchaninfo[a]["name"])==lower_case(str)) return a; + } + return 0; + } + + //Returns mud list to user object 'towho' + void mudlist(object towho) { + int x,y; + string output; + string mud,*muds; + + muds = sort_array(filter(keys(mudinfo), (: stringp($1) :)),1); + if (!mode==MODE_CONNECTED) { + message("system",MUDNAME+" is not connected to the "+NETWORK_ID+" network!\n",towho); + return; + } else if (!sizeof(mudinfo)){ + message("system","There are no muds on the "+NETWORK_ID+" network!\n",towho); + return; + } else { + x=0; y=0; + output=sprintf("[%s] %-20s %-20s %-20s\n","U/D?","Name","Network","IMC2 Version"); + foreach (mud in filter(muds, (: mudinfo[$1]["online"] :) )){ + if(!mudinfo[mud]) output += "Error on mud: "+mud+"\n"; + else { + if(mudinfo[mud]["online"]) x++; else y++; + output += sprintf("[%s] %-20s %-20s %-20s\n", + (mudinfo[mud]["online"] ? "%^GREEN%^ UP %^RESET%^" : "%^RED%^DOWN%^RESET%^"), + mud, mudinfo[mud]["networkname"], mudinfo[mud]["versionid"]); + } + } + output += sprintf("%d of %d MUDs are online.\n",x,x+y); + message("system",output,towho); + return; + } + } + + mapping getmudinfo() { + return mudinfo; + } + + //pings mud 'mudname', returns it to user object 'towho' + void mudinfo(string args,object towho) { + string str; + string output; + + if(!args) { + message("system","See info for which MUD?",towho); + return; + } + + str=find_mud(args); + if(!str) { + message("system","MUD isn't known on "+NETWORK_ID+".",towho); + return; + } + + output=("Mud info for: "+str+"\nStatus: "); + + if(mudinfo[str]["online"]) output+=("%^GREEN%^Online%^RESET%^\n"); + else output+=("%^RED%^Offline%^RESET%^\n"); + + if(mudinfo[str]["versionid"]) output+=("Version ID: "+mudinfo[str]["versionid"]+"\n"); + if(mudinfo[str]["url"]) output+=("URL: "+mudinfo[str]["url"]+"\n"); + if(mudinfo[str]["networkname"]) output+=("Network name: "+mudinfo[str]["networkname"]+"\n"); + + message("system",output,towho); + return; + } + + //Gets WHO list from mud 'mudname', returns it to user object 'towho' + void mudwho(string mudname,object towho) { + string str; + if(!mudname) { + message("system","Send who request to which MUD?",towho); + return; + } + str=find_mud(mudname); + if(!str) { + message("system","MUD isn't known on "+NETWORK_ID+".",towho); + return; + } + if(!mudinfo[str]["online"]) { + message("system",str+" is offline right now.",towho); + return; + } + who_out(capitalize(this_player()->GetKeyName()),str); + message("system",NETWORK_ID+" sent a who request to "+str+"\n",towho); + return; + } + + //pings mud 'mudname', returns it to user object 'towho' + mixed pingmud(string mudname,object towho) { + string str; + if(!mudname) { + message("system","Send ping to which MUD?",towho); + return; + } + str=find_mud(mudname); + if(!str) { + message("system","MUD isn't known on "+NETWORK_ID+".",towho); + return; + } + if(!mudinfo[str]["online"]) { + message("system",str+" is offline right now.",towho); + return; + } + ping_out(capitalize(towho->GetKeyName()),str); + message("system","Sent a ping to "+str+".",towho); + return; + } + + //Displays status to user object 'towho' + void getstatus(object towho) { + string output; + + output=sprintf(@EndText + IMC2 NETWORK INFORMATION + ------------------------ + Status: %s + Hub address: %s + Hub port: %d + The hub calls itself: %s + The network calls itself: %s + Command to use this network: %s + The MUD calls this connection: %s + + Packet logging: %s + + The network calls the MUD: %s + The MUD's Version ID: %s + The MUD's URL: %s +EndText, + ((mode==MODE_CONNECTED) ? "Connected" : "Not connected"), +#ifdef HOSTNAME + HOSTNAME, +#else + HOSTIP, +#endif + HOSTPORT,hub_name,network_name,COMMAND_NAME,NETWORK_ID, +#ifdef IMC2_LOGGING + "on", +#else + "off", +#endif + MUDNAME,VERSION,URL); + + message("system",output,towho); + } + + //return mode + int getonline() { + return mode; + } + + //Beeps user@mud stored in 'args', returns it to user object 'towho' + void interbeep(string args, object towho) { + string a,b; + if(!args || sscanf(args,"%s@%s",a,b)!=2) { + message("system","Invalid syntax.",towho); + return; + } + b=find_mud(b); + if(!b) { + message("system","MUD isn't known on "+NETWORK_ID+".",towho); + return; + } + if(!mudinfo[b]["online"]) { + message("system",b+" is offline right now.",towho); + return; + } + beep_out(towho,a,b); + message("system",sprintf("You beep %s@%s.",capitalize(a),b),towho); + return; + } + + //Fingers user@mud stored in 'args', returns it to user object 'towho' + void finger(string args, object towho) { + string a,b; + + if(!args) return notify_fail("Send finger request to who@where?\n");; + if(sscanf(args,"%s@%s",a,b)!=2){ + return notify_fail("Send finger request to who@where?\n");; + } + b=find_mud(b); + who_out(GET_CAP_NAME(towho),b,"finger "+a); + IMC2_MSG(NETWORK_ID"- Sent a finger request to "+a+"@"+b+"\n",THIS_PLAYER); + } + + //Gets whois for user@mud stored in 'args', returns it to user object 'towho' + void whois(string args, object towho) { + if(!args || !sizeof(args)) return notify_fail("Locate who?\n"); + + send_packet(GET_CAP_NAME(THIS_PLAYER),"whois",args,"*", sprintf("level=%d ",level(THIS_PLAYER))); + + IMC2_MSG("Sent a request on "+NETWORK_ID+" looking for "+args+"\n",THIS_PLAYER); + } + + //Gets MUD Info for a mud 'args', returns it to user object 'towho' + void getremotemudinfo(string args, object towho) { + string str; + + if(!args) return notify_fail("Send info request to which MUD?\n"); + + str=find_mud(args); + + if(!str) return notify_fail("MUD isn't known on "+NETWORK_ID+".\n"); + if(!mudinfo[str]["online"]) return notify_fail(NETWORK_ID+"- "+str+" is offline right now.\n"); + + who_out(GET_CAP_NAME(THIS_PLAYER),str,"info"); + IMC2_MSG(NETWORK_ID"- Sent an info request to "+str+"\n",THIS_PLAYER); + } + + //Write list of all channels to screen + void allchans(string args, object towho) { + string output; + string a; + + output=NETWORK_ID+" channels:\n"; + output += sprintf("%-23s %-17s %-7s %-6s %-10s %-10s\n", + "Name","Owner","Policy","Level","Suggested","Local Name"); + + foreach(a in sort_array( + filter(keys(chaninfo), (: stringp($1) :) ),1)){ + output += sprintf("%-23s %-17s %-7s %-6s %-10s %-10s\n", + a,chaninfo[a]["owner"], + chaninfo[a]["policy"], + chaninfo[a]["level"],chaninfo[a]["localname"], + (localize_channel(a) ? localize_channel(a) : "<none>")); + } + IMC2_MSG(output,THIS_PLAYER); + + } + + //Send a channel command to the server + void chancmd(string args, object towho) { + string a, b, c; + + if(!ADMIN(THIS_PLAYER)) return notify_fail("You aren't allowed to use chancmd.\n"); + if(!args || (sscanf(args,"%s:%s %s",a,b,c)!=3)) + return notify_fail("Syntax: "+COMMAND_NAME+" chancmd hub:channel command\n"); + if(!chaninfo[a+":"+b]) + write(a+" is not listed as a channel, sending command anyway...\n"); + send_packet(GET_CAP_NAME(THIS_PLAYER),"ice-cmd","IMC",b, sprintf("channel=%s command=\"%s\"", a+":"+b,escape(c))); + + IMC2_MSG(sprintf("%s- Sent a command for the %s channel to %s\n",NETWORK_ID,a,GET_CAP_NAME(THIS_PLAYER),b),THIS_PLAYER); + } + + int command(string str){ + // Takes the arguments given to the command which does IMC2 stuff. + string cmd, args; + string output; + string a,b,c; + int x,y; + int emote,reply; + object usr, *usrs=({ }); + + if(IMC2_D->getonline() != 1) return 0; + + if(!str) str = "help"; + sscanf(str,"%s %s",cmd,args); + if(!cmd) cmd=str; + if(!args) args = ""; + + switch(cmd){ + case "list": + mudlist(this_player()); + return 1; + break; + case "setup": + getstatus(this_player()); + return 1; + break; + case "info": + mudinfo(args,this_player()); + return 1; + break; + case "ping": + pingmud(args,this_player()); + return 1; + break; + case "who": + mudwho(args,this_player()); + return 1; + break; + case "tell": + tell(args,this_player()); + return 1; + break; + case "finger": + finger(args,this_player()); + return 1; + break; + case "mudinfo": + getremotemudinfo(args,this_player()); + return 1; + break; + case "allchans": case "ice-update": + allchans(args,this_player()); + return 1; + break; + case "beep": + interbeep(args,this_player()); + return 1; + break; + case "whois": + whois(args,this_player()); + return 1; + break; + case "chancmd": + chancmd(args,this_player()); + return 1; + break; + case "keepalive": + send_keepalive_request(); + return 1; + break; + case "is-alive": + send_is_alive(); + return 1; + break; + case "help": // drop through to default + default: + IMC2_MSG(main_help(),THIS_PLAYER); + return 1; + break; + } + } + + string main_help(){ + return sprintf(@EndText + IMC2 system by Tim, set up for %s. + To use this, type the command '%s' followed by one of the following: + info (name) - lists information about a MUD + list - lists the MUDs on this network + finger (name)@(mud) - send a finger request for information about name@mud + ping (mud) - pings a mud + setup - shows information about this IMC2 network + help - see this help message +EndText, NETWORK_ID,COMMAND_NAME); + } + + string html(string str){ + string mud, *muds; + string a,b; + int x=0,y=0; + string output=""; + if(!str) str=""; + sscanf(str,"%s_%s",a,b); + if(!a) a=str; + switch(a){ + case "list": + muds = sort_array(keys(mudinfo),1); + if (!sizeof(mudinfo)){ + return ("There are no muds on the "+NETWORK_ID+" network!\n"); + } + else{ + output="<tr><td><b>Status</b></td><td><b>Name</b></td><td><b>Network</b></td><td><b>IMC2 Version</b></td></tr>\n"; + foreach (mud in muds){ + if(mudinfo[mud]["online"]) x++; else y++; + output += sprintf("<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n", + (mudinfo[mud]["online"] ? "UP" : "DOWN"), + mudinfo[mud]["url"] ? "<a href=\""+ + ((mudinfo[mud]["url"][0..6]!="http://") ? "http://"+mudinfo[mud]["url"] : mudinfo[mud]["url"]) + +"\">"+mud+"</a>" : mud, + mudinfo[mud]["networkname"], + mudinfo[mud]["versionid"]); + } + } + return sprintf("<B>%d of %d MUDs are on %s.</B.\n<BR><table>%s</table>", + x,x+y,NETWORK_ID,output); + break; + case "backlog": + if(b && localchaninfo[b] && (localchaninfo[b]["perm"]==BACKLOG_WEB_LEVEL)){ + // Show backlog for channel. + return b+" channel backlog:\n"+implode(localchaninfo[b]["backlog"],"\n"); + } + // List the channels + output = NETWORK_ID+" channels on "+MUDNAME+":\n"; + foreach(b in sort_array(keys(localchaninfo),1)){ + if(localchaninfo[b]["perm"]==BACKLOG_WEB_LEVEL) // is public + output += "<a href=\""+HTML_LOCATION+"backlog_"+b+"\">"; + output += b; + output += " - "+chan_perm_desc(localchaninfo[b]["perm"]); + if(localchaninfo[b]["perm"]==BACKLOG_WEB_LEVEL) // is public + output += " - on web</a>"; + else + output += " - not on web"; + output += "\n"; + } + return output; + break; + default: + return MUDNAME+" uses Tim's LPC IMC2 system to connect to the "+ + NETWORK_ID+" network.\n"+ + "(version:"+VERSION+")\n"+ + "From here, you can look at the <a href=\""+HTML_LOCATION+"list\">list of muds</a>,\n"+ + "view the <a href=\""+HTML_LOCATION+"backlog\">public channel backlogs</a>,\n"+ + "or go to the main <a href=\""+URL+"\">"+MUDNAME+"</a> web site.\n"; + break; + } + } + + int clean_up(){ return 0; } + + + void forget_user(string str){ map_delete(tells,str); } + + static void eventChangeIMC2Passwords(){ + clientpass = alpha_crypt(10); + serverpass = alpha_crypt(10); + SECRETS_D->SetSecret("IMC2_CLIENT_PW", clientpass); + SECRETS_D->SetSecret("IMC2_SERVER_PW", serverpass); + return; + } + + int UnSetAutoDisabled(int x){ + //This is just for taking away automatic disablement. + //For enabling/disabling, see the mudconfig command. + if(!autodisabled) return 0; + autodisabled = 0; + if(x){ + eventChangeIMC2Passwords(); + } + if(unguarded((:directory_exists(path_prefix(SaveFile)):))){ + SaveObject(SaveFile,1); + RELOAD_D->eventReload(this_object(), 2, 1); + } + return autodisabled; + } + + void keepalive(string args, object who){ + send_packet(who->GetName(), "keepalive-request", "*", "*", 0); + } + + int GetEnabled(){ + return !(DISABLE_IMC2); + } + +varargs string *GetMudList(int online){ + mixed muds = filter(keys(mudinfo), (: stringp($1) :)); + if(online) muds = filter(muds, (: mudinfo[$1]["online"] :)); + return muds; +} + +varargs string GetMudName(string name, int online){ + mixed muds = filter(keys((mudinfo || ([]))), (: stringp($1) :)); + if(member_array(name, muds) != -1) return name; + foreach(string mud in muds){ + if(lower_case(mud) == lower_case(name)){ + if(!online) return mud; + else if(mudinfo[mud]["online"]) return mud; + } + } + return 0; +} diff --git a/lib/secure/daemon/imc2server/server.c b/lib/secure/daemon/imc2server/server.c new file mode 100644 index 0000000..ca1b3b3 --- /dev/null +++ b/lib/secure/daemon/imc2server/server.c @@ -0,0 +1,647 @@ +#include <lib.h> +#include <daemons.h> +#include <commands.h> +#include <save.h> +#include "./server_log.h" + +#define CALL_OUT_COMPLETE_STARTUP 1 + +inherit LIB_DAEMON; +static string router_port = "8888"; +mapping mudinfo; +static int lastel = 40; + +object cmd = find_object(CMD_IMC_SERVER_D); +object rsocket = find_object(RSOCKET_D); +object ssocket = find_object(SSOCKET_D); +object router = find_object(ROUTER_D); + +static void validate(){ + if( previous_object() != cmd && previous_object() != rsocket && + previous_object() != this_object() && + previous_object() != ssocket && previous_object() != router && + !((int)master()->valid_apply(({ "ASSIST" }))) ){ + trr("SECURITY ALERT: validation failure in IMC2_SERVER_D.","red"); + error("Illegal attempt to access IMC2 server daemon: "+get_stack()+ + " "+identify(previous_object(-1))); + } +} + +void create(){ + ::create(); + if(object_file(SAVE_IMC2_SERVER)){ + RestoreObject(SAVE_IMC2_SERVER, 1); + } +} + +string clean_str(string str){ + while(sizeof(str) && str[<1] < 32){ + str = str[0..<2]; + } + return str; +} + +mapping query_mudinfo(){ + return copy(mudinfo); +} + +string imc2_name(string str){ + return replace_string(str," ","_"); +} + +string i3_name(string str){ + string ret = replace_string((str || ""),"_"," "); + if(ROUTER_D->query_mudinfo()[str]) return str; + if(ROUTER_D->query_mudinfo()[ret]) return ret; + return str; +} + +int is_lpmud(string mud){ + string family, truename = i3_name(mud); + mapping info = ROUTER_D->query_mudinfo()[truename]; + if(!info) return 0; + if(stringp(info["mud_type"]) && grepp(info["mud_type"],"LP")){ + return 1; + } + if(info["other_data"] && stringp(info["other_data"]["versionid"])){ + if(!strsrch(info["other_data"]["versionid"],"Tim's LPC")){ + return 1; + } + } + return 0; +} + +string unescape(string str){ + string a,b=str,output=""; + while(sscanf(b,"%s\\%s",a,b)==2){ + output += a; + if(sizeof(b)){ + switch(b[0]){ + case 34 : output += "\""; break; // '\"' makes warnings. + case '\\' : output += "\\"; break; + case 'n' : output += "\n"; break; + case 'r' : output += "\r"; break; + } + } + b=b[1..]; + } + output += b; + output = replace_string(output,"\n\r","\n"); + output = replace_string(output,"\r\n","\n"); + if((sizeof(explode(output," "))==1) && sscanf(output,"\\\"%*s\\\"") ) + output = "\""+output+"\""; + return output; +} + +mapping string_to_mapping(string str){ + // Picks first element off of string and then repeats? + mapping out=([]); + int i; + string what,data,rest; + + rest = str; + + while(sizeof(rest)>0){ + sscanf(rest, "%s=%s", what, rest); + /* + write("what="+what+", rest="+rest+"\n"); + */ + // At this point, what is the key, rest is value plus rest. + if(rest[0]==34){ // value is in quotes, tons of fun! + // find first quote without a backslash in front? + /* + write("rest begings with a quote\n"); + */ + i = 1; + while(((rest[i]!=34) || (rest[i-1]==92)) && (i<sizeof(rest))){ // 34 = ", 92 = \ + // While this is not a quote, or if this is an escaped quote, keep looking. + i++; + } + // now are 1 space past quote + data=rest[1..(i-1)]; // skip opening and closing quotes + rest=rest[(i+2)..]; // skip past space + // Data is now what was in the quotes... now to un-escape the + //data... + out[what]=unescape(data); + } + else{ // value is not in quotes, tons of actual non-sarcastic fun! // just split it at the first space + if(sscanf(rest,"%s %s",data,rest)!=2){ // break at first space data = rest; + rest = ""; + } + if( !data || ((sscanf(data,"%d",i)==1) + && (sprintf("%d",i)==data)))//just number + out[what]=i; + else // not just a number + out[what]=data; + } + } + return out; +} + +mixed packetize(string str){ + mixed *ret; + mixed src, targ, who, whom; + string tmp, seq, route, type, data; + int i = sscanf(str,"%s %s %s %s %s %s", src, seq, route, type, targ, data); + if(i < 6){ + return 0; + } + if( (i = sscanf(src,"%s@%s",who, tmp)) == 2) src = tmp; + if( (i = sscanf(targ,"%s@%s",whom, tmp)) == 2) targ = tmp; + if(src && src == "*") src = 0; + if(targ && targ == "*") targ = 0; + if(who && who == "*") who = 0; + if(who && who == "*") who = 0; + if(whom && whom == "*") whom = 0; + ret = ({ type, 5, src, who, i3_name(targ), whom, data }); + return ret; +} + +mapping parse_info(string str){ + string url, versionid, host; + int port; + mapping ret = ([]); + str = " " + str + " "; + if(sscanf(str,"%*surl=%s ", url)) ret["url"] = url; + else if(sscanf(str,"%*surl=%s\n%*s", url)) ret["url"] = url; + else if(sscanf(str,"%*surl=%s %*s", url)) ret["url"] = url; + if(sscanf(str,"%*sversionid=\"%s\"%*s", versionid)) + ret["versionid"] = versionid; + else if(sscanf(str,"%*sversionid=%s ", versionid)) + ret["versionid"] = versionid; + else if(sscanf(str,"%*sversionid=%s %*s", versionid)) + ret["versionid"] = versionid; + if(sscanf(str,"%*shost=\"%s\"%*s", host)) ret["host"] = host; + else if(sscanf(str,"%*shost=%s ", host)) ret["host"] = host; + else if(sscanf(str,"%*shost=%s %*s", host)) ret["host"] = host; + if(sscanf(str,"%*sport=%d ", port)) ret["port"] = port; + else if(sscanf(str,"%*sport=%d %*s", port)) ret["port"] = port; + if(url) ret["url"] = url; + if(versionid) ret["versionid"] = versionid; + if(host) ret["host"] = host; + if(port) ret["port"] = port; + return ret; +} + +mixed translate_packet(mixed data, int fd){ + string targ = ROUTER_D->query_connected_fds()[fd]; + mapping i3info, tmpinfo; + mixed ret = ({}); + string router_name = ROUTER_D->GetRouterName(); + if(!mudinfo) mudinfo = ([]); + tmpinfo = copy(mudinfo); + if(stringp(data)) return data; + if(!arrayp(data) || sizeof(data) < 6) return 0; + if(data[0] == "mudlist"){ + mapping tmpret = data[7]; + foreach(mixed key, mixed val in tmpret){ + if(!key) continue; + if(sizeof(val) && val[0] > -1 ){ + ret += ({ "*@" + router_name + " " + time() + " " + + router_name + " close-notify *@* host=" + imc2_name(key) }); + } + else { + if(!tmpinfo[key]){ + i3info = ROUTER_D->query_mudinfo()[key]; + if(!sizeof(i3info)) continue; + tmpinfo[key] = ([]); + tmpinfo[key]["versionid"] = i3info["mudlib"]; + tmpinfo[key]["url"] = "http://"+i3info["ip"]; + tmpinfo[key]["host"] = i3info["ip"]; + tmpinfo[key]["port"] = i3info["player_port"]; + } + ret += ({ "*@"+imc2_name(key)+" "+time()+" "+imc2_mud_name()+ + "!"+router_name+ + " is-alive *@"+ targ + " versionid=\""+ + tmpinfo[key]["versionid"]+ + "\" networkname=\"LPMuds.net\" url=\""+ + tmpinfo[key]["url"]+"\""+ + " sha256=0"+ + " host=\""+tmpinfo[key]["host"]+"\" "+ + "port="+tmpinfo[key]["port"]}); + } + } + } + if(data[0] == "chanlist-reply"){ + foreach(mixed foo in data){ + string hub = data[2]; + string rname = "LPMuds.net"; + mapping chans = data[7]; + foreach(string chan, mixed arr in chans){ + string owner = replace_string(arr[0]," ","_"); + int priv = arr[1]; + if(!priv) ROUTER_D->AddIMC2Chan(fd, data[4], chan); + ret += ({ + "ICE@"+hub+" "+time()+" "+hub+" ice-update *@"+ + data[4]+" channel="+hub+":"+chan+" owner=admin@"+owner+ + " operators=admin@"+owner+" policy="+ + (priv ? "private invited=" : "open excluded=")+ + "\"a@b\" level=Imm localname="+chan }); + } + } + } + if(data[0] == "tell"){ + string tmp = replace_string(data[7],"\"","'"); + ret = data[3]+"@"+imc2_name(data[2])+" "+time()+" "+ + imc2_name(data[2])+"!"+router_name+" tell "+ + data[5]+"@"+data[4]+" text=\""+unescape(tmp)+"\""; + } + if(data[0][0..7] == "channel-"){ + string tmp = replace_string(data[8],"\"","'"); + string emt = ""; + if(data[0][8..8] == "e"){ + tmp = trim(replace_string(data[8],"$N","")); + emt = " emote=1"; + } + ret = data[7]+"@"+imc2_name(data[2])+" "+time()+" "+ + imc2_name(data[2])+ "!"+router_name+ + " ice-msg-b *@* channel="+router_name+ + ":"+data[6]+" text=\""+unescape(tmp)+"\""+emt; + } + if(data[0] == "who-req"){ + ret = data[3]+"@"+imc2_name(data[2])+" "+time()+" "+ + imc2_name(data[2])+" who *@"+imc2_name(data[4])+ + " type=who"; + } + if(data[0] == "who-reply"){ + string who_ret = "Who list for "+data[2]+"\n"; + foreach(mixed element in data[6]){ + who_ret += element[0] + " idle: "+ + time_elapsed(element[1])+"\n"; + } + who_ret = replace_string(who_ret,"\"","'"); + who_ret = replace_string(who_ret,"\r",""); + if(!is_lpmud(data[4])){ + who_ret = replace_string(who_ret,"\n","\\n"); + } + ret = "*@"+imc2_name(data[2])+" "+time()+" "+ + imc2_name(data[2])+" who-reply "+ capitalize(data[5])+ + "@"+imc2_name(data[4])+" text=\""+ who_ret+"\""; + } + if(sizeof(ret)) return ret; + return 0; +} + +varargs void write_data(int fd, mixed data, int startack, float vers){ + mixed *sstat = socket_status(fd); + object ssock = find_object(SSOCKET_D); + mapping minfo = ROUTER_D->query_mudinfo(); + mixed ret; + string targetmud; + validate(); + reset_eval_cost(); + targetmud = ROUTER_D->query_connected_fds()[fd]; + //tc("write_data to "+targetmud+": "+identify(data)[0..63]+"...","white"); + if(!startack){ + if(!sizeof(minfo) || !sizeof(targetmud)) return; + if(minfo[targetmud]["disconnect_time"]) return; + } + if(arrayp(data)){ + if(!sizeof(data)) return; + if(!strsrch(data[0],"PW ")) tc("good","green"); + else if(!(ret = translate_packet(data, fd))){ + if(data[0] == "mudlist") return; + tc("failed to translate: "+identify(data),"red"); + return; + } + } + if(startack) tc("writing to "+targetmud+": "+identify(ret), "yellow"); + if(ret) data = ret; + if(!arrayp(data)) data = ({ data }); + if(!sstat || sstat[1] != "DATA_XFER" || !ssock || sstat[5] != ssock) return; + if(member_array(fd, keys(ROUTER_D->query_irn_sockets())) == -1){ + int startup; + string lfcr = ""; + if(sizeof(data) == 1){ + if(!strsrch(data[0], "PW ")){ + tc("startup: "+data[0],"green"); + startup = 1; + } + } + if(sizeof(data) < 6){ + int spew; + if(sizeof(data) > 2){ + //tc("data packet size: "+sizeof(data)); + spew = 1; + } + foreach(mixed element in data){ + float vv; + int proper = 0; + if(!sizeof(element)) continue; + if(vers && vers > 2) proper = 1; + else { + if(minfo[targetmud] && minfo[targetmud]["other_data"] && + vv = minfo[targetmud]["other_data"]["imc_version"]){ + if(vv > 2) proper = 1; + } + } + if(startup){ + if(proper) tc(fd+" "+(vv || vers),"white"); + else tc("%^B_WHITE%^"+fd+" "+(vv || vers),"black"); + } + if(proper){ + element = clean_str(element)+"\r\n"; + } + else{ + element = clean_str(element)+"\n\r"; + } + if(spew){ + lfcr = replace_string(element,"\n","(LF)"); + lfcr = replace_string(lfcr,"\r","(CR)"); + tc("writing to "+fd+": "+identify(lfcr)+"\n","yellow"); + } + SSOCKET_D->write_data(fd, element); + } + } + else { + int delay = 1; + ret = data[0..lastel]; + data = data[lastel+1..]; + while(sizeof(ret)){ + mixed cargo = ret; + //tc("cargo: "+identify(cargo)+"\n","red"); + call_out("delayed_write", delay, cargo, fd, targetmud); + ret = data[0..lastel]; + data = data[lastel+1..]; + delay++; + } + } + } +} + +static void delayed_write(mixed data, int fd, string targetmud){ + string checkmud = ROUTER_D->query_connected_fds()[fd]; + if(checkmud != targetmud) return; + foreach(mixed element in data){ + write_data(fd, element); + } +} + +static void close_connection(int fd){ + SSOCKET_D->close_connection(fd); +} + +string GetRouterPort(){ + validate(); + return router_port; +} + +string SetRouterPort(string str){ + validate(); + router_port = str; + server_log("Setting router port to: "+str); + this_object()->SetList(); + return router_port; +} + +int eventDestruct(){ + validate(); + SaveObject(SAVE_IMC2_SERVER); + server_log("I am being destructed by: \n"+get_stack()+ + "\n"+identify(previous_object(-1))); + daemon::eventDestruct(); +} + +int GetMaxRetries(){ + return 5; +} + +varargs void construct_startup(mixed fd, mixed info, string client){ + string router = ROUTER_D->GetRouterName(); + string s1, s2, s3, s4, s5; + mixed packet; + float vers; + int passwd, pport, scan, newmud; + mapping other = ([]); + string *nix = ({ "clientpass", "serverpass", "password" }); + if(!mudinfo) mudinfo = ([]); + trr("construct_startup hit"); + //if(grepp(info,"\n")) tc("OH YEAH"); + //else tc("bummer."); + //if(grepp(info,"\r")) tc("WOOT"); + //else tc("lame."); + scan = sscanf(info,"PW %s %s %s %s %s", s1, s2, s3, s4, s5); + if(scan != 5) scan = sscanf(info,"PW %s %s %s %s", s1, s2, s3, s4); + if(scan < 4) scan = sscanf(info,"PW %s %s %s", s1, s2, s3); + trr("info: "+identify(info)); + trr("client: "+identify(client)); + trr("s1: "+s1); + trr("s2: "+s2); + trr("s3: "+s3); + trr("s4: "+s4); + trr("s5: "+s5); + if(scan < 3 || (!mudinfo[s1] && scan != 5)){ + trr("\nwrong size packet\n"); + return; + } + if(s3){ + sscanf(s3,"version=%f",vers); + } + if(undefinedp(vers)) vers = 2.0; + trr("vers: "+identify(vers)); + if(!s5 && mudinfo[s1]) s5 = mudinfo[s1]["serverpass"]; + //if(grepp(s5,"\n")) tc("OH YEAH"); + //else tc("bummer."); + s5 = replace_string(s5,"\n",""); + s5 = replace_string(s5," SHA256",""); + if(!mudinfo[s1]){ + newmud = 1; + trr("NEW MUD "+s1); + mudinfo[s1] = ([ "clientpass" : s2, "serverpass" : s5, + "password" : random_numbers(9,1) ]); + } + else { + if(mudinfo[s1]["clientpass"] != s2){ + trr("BAD PASSWORD! Wanted "+mudinfo[s1]["clientpass"]+ + ", got: "+s2,"red"); + mudinfo[s1]["password"] = random_numbers(10,1); + } + else trr("Good password for "+s1); + trr(s1 + " I3 password: "+mudinfo[s1]["password"]); + } + passwd = mudinfo[s1]["password"]; + if(mudinfo[s1]["port"]) pport = mudinfo[s1]["port"]; + foreach(mixed key, mixed val in mudinfo[s1]){ + if(member_array(key, nix) == -1){ + other[key] = val; + } + } + other["imc_version"] = vers; + packet = ({ "startup-req-3", 5, s1, 0, router, 0, passwd, 1, 1, + pport, 0, 0, " ", " ", " ", " ", " ", " ", + (["channel" : 1, "who" : 1, "tell" : 1]), other }); + trr("%^WHITE%^constructed packet: "+identify(packet), "black"); + ROUTER_D->update_imc2(s1, other); + this_object()->acknowledge_startup(fd, s1, vers); +#if CALL_OUT_COMPLETE_STARTUP + call_out("complete_startup", 0, fd, packet, s1, other); +#else + ROUTER_D->read_callback(fd, packet); + ROUTER_D->broadcast_mudlist(s1); + ROUTER_D->broadcast_chanlist("foo",0); + mudinfo[s1]["password"] = ROUTER_D->query_mudinfo()[s1]["password"]; + trr(s1 + " i3 password: "+mudinfo[s1]["password"]); +#endif +} + +#if CALL_OUT_COMPLETE_STARTUP +static complete_startup(int fd, mixed packet, string s1, mixed other){ + string checkmud = ROUTER_D->query_connected_fds()[fd]; + if(checkmud){ + return; + } + ROUTER_D->read_callback(fd, packet); + ROUTER_D->update_imc2(s1, other); + ROUTER_D->broadcast_mudlist(s1); + mudinfo[s1]["password"] = ROUTER_D->query_mudinfo()[s1]["password"]; + trr(s1 + " i3 password: "+mudinfo[s1]["password"]); +} +#endif + +varargs void acknowledge_startup(int fd, string mud, mixed vers){ + string syn, ack, passwd, ver; + string server = ROUTER_D->GetRouterName(); + ver = vers+""; + trr("ack for "+mud+" ver is: "+ver); + if(mudinfo && mudinfo[mud] && mudinfo[mud]["serverpass"]) + passwd = mudinfo[mud]["serverpass"]; + ack = "PW "+server+" "+passwd+" version="+ver+" LPMuds.net"; + syn = replace_string(ack, "\n","#"); + syn = replace_string(syn, "\r","^"); + ack = replace_string(ack, "\n",""); + trr(mud+" ("+fd+") ack: "+ack); + write_data(fd, ({ack}), 1, vers); +} + +void read_callback(mixed fd, mixed info){ + mixed womble = info; + mixed packet = packetize(info); + mixed ret; + mapping datamap = string_to_mapping(info); +#if 1 + womble = replace_string(womble, "\n", "(LF)"); + womble = replace_string(womble, "\r", "(CR)"); + //trr("packet: "+identify(womble),"yellow"); + womble = packetize(womble); + //trr("packet: "+identify(womble),"yellow"); +#endif + //trr("whee! read_callback("+fd+", "+identify(womble)+")","cyan"); + if(stringp(info) && last(info,1) == "\n") info = truncate(info,1); + //trr("Mapping form: "+identify(datamap)+")","cyan"); + if(stringp(info) && !strsrch(info,"PW ")){ + mixed start; + info = replace_string(info,"\r","\n"); + start = explode(info, "\n"); + if(sizeof(start)) info = start[0]; + construct_startup(fd, info); + return; + } + if(!packet || !mudinfo[packet[2]] || + ROUTER_D->query_connected_fds()[fd] != packet[2]){ + write_data(fd, "Your connection isn't registered as " + + (packet ? packet[2] : "anything at all")); + trr("IMC2: BAD CONNECTION ON "+fd, "red"); + close_connection(fd); + return; + } + if(packet[0] == "ice-msg-b"){ + string tmp; + if(!stringp(datamap["text"])) datamap["text"] = itoa(datamap["text"]); + sscanf(packet[6],"%*shannel=%*s:%s %*s",tmp); + if(datamap["emote"]){ + ret = ({ "channel-e" }); + if(datamap["emote"] == 2){ + string tmp2 = datamap["text"]; + tmp2 = replace_string(tmp2, packet[3]+"@"+packet[2], "$N"); + datamap["text"] = tmp2; + } + else { + string tmp2 = "$N " + datamap["text"]; + datamap["text"] = tmp2; + } + } + else ret = ({ "channel-m" }); + ret += packet[1..5]; + ret += ({ tmp, capitalize(packet[3]), datamap["text"] }); + //tc("ret: "+identify(ret)); + ROUTER_D->read_callback(fd, ret); + return; + } + if(packet[0] == "is-alive" || packet[0] == "keepalive-request"){ + int update; + mixed data; + //trr(packet[0],"white"); + if(sizeof(packet) < 6){ + //trr("Wrong packet size.","white"); + write_data(fd, "Wrong packet size."); + return; + } + data = parse_info(packet[6]); + //trr("data: "+identify(data)); + foreach(mixed key, mixed val in data){ + //trr("key: "+identify(key)+", val: "+identify(val),"green"); + if(!mudinfo[packet[2]][key] || + mudinfo[packet[2]][key] != val){ + //trr("key: "+identify(key)+", val: "+identify(val),"red"); + update = 1; + mudinfo[packet[2]][key] = val; + } + } + if(update){ + //trr("trying to update","white"); + ROUTER_D->update_imc2(packet[2], data); + } + } + if(packet[0] == "keepalive-request"){ + //trr("trying to send mudlist"); + ROUTER_D->send_full_mudlist(packet[2]); + return; + } + if(packet[0] == "ice-refresh"){ + //trr("trying to send chanlist"); + ROUTER_D->broadcast_chanlist("foo",packet[2]); + return; + } + if(packet[0] == "tell"){ + string msg; + //trr("trying to send tell"); + msg = replace_string(packet[6],"text=",""); + ret = ({ "tell", 5, packet[2], packet[3], packet[4], + packet[5], packet[3], msg }); + ROUTER_D->read_callback(fd, ret); + return; + } + if(packet[0] == "who-reply"){ + string *tmp_ret = ({}); + string tmp = packet[6]; + tmp = replace_string(tmp,"text=",""); + if(is_lpmud(packet[4])){ + tmp = replace_string(tmp,"\\n","\n"); + } + foreach(string element in explode(tmp,"\n")){ + tmp_ret += ({ ({ element, 0, "" }) }); + } + ret = ({ "who-reply", 5, packet[2], 0, packet[4], + packet[5], tmp_ret }); + ROUTER_D->read_callback(fd, ret); + } + if(packet[0] == "who"){ + ret = ({ "who-req", 5, packet[2], packet[3], packet[4], 0 }); + ROUTER_D->read_callback(fd, ret); + } +} + +void broadcast_data(mapping targets, mixed data){ + //ssocket = find_object(SSOCKET_D); + //tc("targets: "+identify(targets)); + validate(); + //tc("data: "+identify(data)); + foreach(int *arr in unique_array(values(targets), (: $1 :))){ + //tc("arr[0]: "+identify(arr[0])); + //if(!ssocket) tc("FUCK"); + //else + write_data(arr[0], data); + } + //if(ssocket) ssocket->broadcast_data(targets, data); + //tc("C"); +} diff --git a/lib/secure/daemon/imc2server/server_log.h b/lib/secure/daemon/imc2server/server_log.h new file mode 100644 index 0000000..4ae1919 --- /dev/null +++ b/lib/secure/daemon/imc2server/server_log.h @@ -0,0 +1,8 @@ +varargs void server_log(string str, string file){ + trr(str+"%^RESET%^"); + str = strip_colours(str); + if(!file){ + return log_file("imc2_server/server_log", timestamp()+" "+str+"\n"); + } + return log_file("imc2_server/"+file, timestamp()+" "+str+"\n"); +} diff --git a/lib/secure/daemon/imc2server/ssocket.c b/lib/secure/daemon/imc2server/ssocket.c new file mode 100644 index 0000000..296b395 --- /dev/null +++ b/lib/secure/daemon/imc2server/ssocket.c @@ -0,0 +1,258 @@ +#include <lib.h> +#include <commands.h> +#include <socket.h> +#include <daemons.h> +#include NETWORK_H +#include "./server_log.h" + +inherit LIB_DAEMON; + +static private int router_socket; +static private mapping sockets = ([]); +static private int incept_date; +int verbose = 0; + +static void close_callback(int fd, int force); +void write_data(int fd, mixed data); +varargs void yenta(mixed arg1, mixed arg2); +object cmd = load_object(CMD_ROUTER); +object router = find_object(IMC2_SERVER_D); + +varargs static void validate(int i){ + if(i){ + if(!socket_status(i) || !socket_status(i)[5]){ + server_log("%^RED%^BAD SOCKET ALERT. fd "+i+": "+ + identify(socket_status(i)),"ssocket"); + error("Bad socket, fd "+i); + close_callback(i, 1); + } + } + if( previous_object() != cmd && previous_object() != router && + previous_object() != this_object() && !((int)master()->valid_apply(({ "ASSIST" }))) ){ + server_log("%^RED%^SECURITY ALERT: validation failure in SSOCKET_D.","ssocket"); + error("Illegal attempt to access router socket daemon: "+get_stack()+ + " "+identify(previous_object(-1))); + } +} + +static void create(){ + incept_date = time(); + call_out("setup",1); + SetNoClean(1); +} + +void close_connection(int fd){ + int sockerr; + mixed *sockstat = ({}); + + validate(); + + sockstat = socket_status(fd); + if(!sockstat || !sizeof(sockstat)) return; + if(sockstat[1] == "LISTEN") return; + server_log("%^YELLOW%^About to try closing socket: "+fd + //+" (aka: "+(ROUTER_D->query_connected_fds()[fd] || + // identify(sockstat))+")","ssocket" + ); + yenta("%^YELLOW%^Pre-closing state: "+sockstat[1],"ssocket"); + sockerr = socket_close(fd); + if(sockerr > -1) map_delete(sockets,fd); + yenta("%^WHITE%^closing socket:"+fd,"ssocket"); + yenta("%^WHITE%^closing sockerr:"+sockerr,"ssocket"); + yenta("%^YELLOW%^Post-closing state: "+socket_status(fd)[1],"ssocket"); + yenta("%^WHITE%^---\n","ssocket"); +} + +static void close_callback(int fd, int force){ + string mudname; + mapping muds_on_this_fd = ([]); + + if(!force) validate(fd); + + if(!find_object(ROUTER_D)) return; + + muds_on_this_fd = ROUTER_D->query_connected_muds(); + foreach(mixed key, mixed val in muds_on_this_fd){ + if(val != fd) map_delete(muds_on_this_fd, key); + } + yenta("close_callback: fd="+fd+"\n"); + if(socket_status(fd)[1] == "LISTEN") return; + foreach(mudname in keys(muds_on_this_fd)){ + server_log("%^RED%^close_callback: Removing mud from connected_muds list: "+(mudname || identify(socket_status(fd))),"ssocket"); + ROUTER_D->disconnect_mud(mudname); + } + close_connection(fd); +} + +static void listen_callback(int fd){ + int fdstat; + + validate(fd); + + if ((fdstat = socket_accept(fd, "read_callback", "write_callback")) < 0) { + trr("listen_callback couldn't accept socket "+fd+", errorcode "+fdstat); + return; + } + else { + server_log("socket_accepted: "+fdstat+ + ", "+identify(socket_status(fdstat)),"ssocket"); + } +} + +static void read_callback(int fd, mixed info){ + + validate(fd); + if(bufferp(info)){ + yenta("%^WHITE%^fd "+fd+" is sending me buffer data!"); + yenta("%^WHITE%^As far as I can tell, it is:"); + yenta("%^BLUE%^"+identify(read_buffer(info))); + } + else yenta("%^WHITE%^data from fd "+fd+":\n%^BLUE%^"+identify(info)); + if(!find_object(IMC2_SERVER_D)) return; + IMC2_SERVER_D->read_callback(fd,info); +} + +static void write_callback(int fd){ + + validate(fd); + + if(!sockets[fd]) return; + if(sockets[fd]["write_status"] == EEALREADY) { + write_data(fd, sockets[fd]["pending"]); + map_delete(sockets[fd], "pending"); + } + else { + sockets[fd]["write_status"] = EESUCCESS; + } +} + +static void write_data_retry(int fd, mixed data, int counter){ + int rc; + int maxtry; + + validate(fd); + //trr("counter for fd("+fd+"): "+counter); + + if(!find_object(IMC2_SERVER_D)) return; + + maxtry = IMC2_SERVER_D->GetMaxRetries(); + if (counter == maxtry) { + trr("Could not write data to "+ROUTER_D->query_connected_fds()[fd]+", fd"+fd+": "+identify(data[0])); + return; + } + if(!grepp(data,"close-notify") && !grepp(data,"is-alive")){ + yenta("%^YELLOW%^SSOCKET: bout to try writing "+identify(data)+" to "+fd,"ssocket"); + } + rc = socket_write(fd, data); + if(!sockets[fd]){ + sockets[fd]=([]); + } + sockets[fd]["write_status"] = rc; + switch (rc) { + case EESUCCESS: + break; + case EEALREADY: + sockets[fd]["pending"] = data; + break; + case EECALLBACK: + break; + case EESECURITY: + break; + case EEFDRANGE: + break; + case EENOTCONN: + break; + case EEBADF: + break; + default: + if (counter < maxtry) { + if(counter < 2 || counter > maxtry-1) + trr("SSOCKET_D write_data_retry "+counter+" to "+ + ROUTER_D->query_connected_fds()[fd]+", fd"+fd+" error, code "+rc+": " + socket_error(rc)); + call_out( (: write_data_retry :), 2 , fd, data, counter + 1 ); + return; + } + } +} + +void write_data(int fd, mixed data){ + validate(fd); + write_data_retry(fd, data, 0); +} + +void broadcast_data(mapping targets, mixed data){ + validate(); + yenta("SSOCK: broadcast_data("+identify(targets)+", "+identify(data)); + foreach(int *arr in unique_array(values(targets), (: $1 :))){ + write_data(arr[0], data); + } + } + + static void setup(){ + int router_port; + + if(!find_object(IMC2_SERVER_D)) return; + + router_port = atoi(IMC2_SERVER_D->GetRouterPort()); + server_log("ssocket setup got called","ssocket"); + if ((router_socket = socket_create(STREAM, "read_callback", "close_callback")) < 0){ + server_log("setup: Failed to create socket.","ssocket"); + return; + } + if (socket_bind(router_socket, router_port) < 0) { + socket_close(router_socket); + server_log("setup: Failed to bind socket to port.","ssocket"); + return; + } + if (socket_listen(router_socket, "listen_callback") < 0) { + socket_close(router_socket); + server_log("setup: Failed to listen to socket.","ssocket"); + } + server_log("ssocket setup ended","ssocket"); + } + +void complete_socket_handoff(int i){ + + validate(i); + + yenta("hit the right handoff fun. arg: "+i); + if(base_name(previous_object()) != IMC2_SERVER_D){ + yenta("I don't want your dirty socket, "+identify(previous_object())); + return; + } + yenta("sockstat: "+identify(socket_status(i))); + socket_acquire(i, "read_callback", "write_callback", "close_callback"); + yenta("sockstat: "+identify(socket_status(i))); +} + +mapping query_socks(){ validate(); return copy(sockets); } + +int GetInceptDate(){ + return incept_date; +} + +int eventDestruct(){ + string alert = "SSOCKET_D is being killed!\n"; + alert += "STACK: "+get_stack()+"\n"; + alert += "PREVS: "+identify(previous_object(-1))+"\n"; + + server_log("%^RED%^"+alert,"ssocket"); + return ::eventDestruct(); +} + +int SetVerbose(int i){ + if(i) verbose = 1; + else verbose = 0; + return verbose; +} + +int GetVerbose(){ + return verbose; +} + +varargs void yenta(mixed arg1, mixed arg2){ + if(verbose){ + if(arg2) server_log(arg1, arg2); + else server_log(arg1); + } +} diff --git a/lib/secure/daemon/include/character.h b/lib/secure/daemon/include/character.h new file mode 100644 index 0000000..54a0ce5 --- /dev/null +++ b/lib/secure/daemon/include/character.h @@ -0,0 +1,13 @@ +#ifndef l_character_h +#define l_character_h + +static void create(); + +mixed eventConnect(string who); +mixed eventLink(string primary, string secondary, string email); +mixed eventUnlink(string primary, string who); + +mapping GetLinks(); +mapping GetLink(string who); + +#endif /* l_character_h */ diff --git a/lib/secure/daemon/include/chat.h b/lib/secure/daemon/include/chat.h new file mode 100644 index 0000000..041f179 --- /dev/null +++ b/lib/secure/daemon/include/chat.h @@ -0,0 +1,14 @@ +#ifndef __CHAT_H__ +#define __CHAT_H__ + +static void create(); +string *eventRegisterMember(string *chans); +string *eventRemoveMember(string *chans); +int cmdChannel(string verb, string str); +varargs void eventSendChannel(string who, string ch, string msg, int emote, + string target, string targmsg); +string *GetChannelList(string ch); +string GetLocalChannel(string ch); +string GetRemoteChannel(string ch); + +#endif /* __CHAT_H__ */ diff --git a/lib/secure/daemon/include/estates.h b/lib/secure/daemon/include/estates.h new file mode 100644 index 0000000..e686e74 --- /dev/null +++ b/lib/secure/daemon/include/estates.h @@ -0,0 +1,7 @@ +#ifndef __ESTATES_H +#define __ESTATES_H + +static private void preload_estates(); +void add_estate(string who, string sortie, string where, string long); + +#endif /* __ESTATES_H */ diff --git a/lib/secure/daemon/include/imc2_code.h b/lib/secure/daemon/include/imc2_code.h new file mode 100644 index 0000000..9b78cdb --- /dev/null +++ b/lib/secure/daemon/include/imc2_code.h @@ -0,0 +1,1500 @@ +// Tim Johnson +// Started on May 1, 2004. +// Use this however you want. + +#ifndef VERSION +#define VERSION "Tim's LPC IMC2 client - Jan 30, 2005" +#endif + +string tmpstr; + +// Mode decides what kind of packet is expected +#define NO_UIDS +#define MODE_CONNECTED 1 +#define MODE_WAITING_ACCEPT 2 +#define MODE_CONNECT_ERROR 3 // Not used yet, I need to see what the hub sends. +#define MODE_HUB_DOWN 4 // Not used yet either. + +#ifndef STREAM +#define STREAM 1 +#endif +#ifndef EESUCCESS +#define EESUCCESS 1 /* Call was successful */ +#endif +#ifndef THIS_PLAYER +#define THIS_PLAYER this_player() +#endif +#ifndef FIND_PLAYER +#define FIND_PLAYER(x) find_player(x) +#endif +#ifndef GET_CAP_NAME +#define GET_CAP_NAME(x) replace_string(x->GetName()," ","") +#endif +#ifndef GET_NAME +#define GET_NAME(x) convert_name(x->GetName()) +#endif +#ifndef IMC2_MSG +#define IMC2_MSG(x,y) foreach(tmpstr in explode(x,"\n")){ message("IMC2",tmpstr,y); } +#endif +#ifndef GET_GENDER +#define GET_GENDER(x) x->GetGender() +#endif +#ifndef ADMIN +#define ADMIN(x) archp(x) +#endif + +#define HTML_LOCATION "http://dead-souls.net/" + +// Other things that could be #define'd... +// INVIS(x) !visible(x) +// TELL_BOT "/u/t/timbot/imc2_invalidtells.c" +// TELL_BOTS ([ "timbot" : "/u/t/timbot/imc2_tellbot.c" ]) +// CHAN_BOT "/u/t/timbot/imc2_chans.c" +// CHAN_BOTS ([ "ichat" : "/u/t/timbot/imc2_ichat.c" ]) +// USER_EXISTS(x) user_exists(x) + +// Debugging +//#define DEB_IN 1 +//#define DEB_OUT 2 +//#define DEB_PAK 3 +//#define DEB_OTHER 0 + +int socket_num; +int mode; +mapping ping_requests; // Keeps track of who sent a ping request. +// Ping requests aren't labelled with names, so replies are destined to this MUD +// with no idea why, unless we keep track. +string buf=""; // Buffer for incoming packets (aren't always sent 1 at a time) + +// Variables +string hub_name, network_name; +string server_pass, server_version; +mapping chaninfo; +mapping localchaninfo; // (["chan": ([ "perm":1, "name":"something", "users":({ }) ]) ]) +mapping mudinfo; +mapping genders; +mapping tells; +int sequence; + +// Prototypes :) +void create(); +void remove(); +string pinkfish_to_imc2(string str); +string imc2_to_pinkfish(string str); +string escape(string str); +string unescape(string str); +mapping string_to_mapping(string str); +string main_help(); + +private void send_packet(string sender, string packet_type, string target, string destination, string data); +private void send_text(string text); +private void got_packet(string info); +private void start_logon(); +private varargs void send_is_alive(string origin); +private void channel_in(string fromname, string frommud, mapping data); +private void tell_in(string sender, string origin, string target, mapping data); +private void beep_in(string sender, string origin, string target, mapping data); +private void who_reply_in(string origin, string target, mapping data); +private void whois_in(string fromname, string frommud, string targ, mapping data); +private void whois_reply_in(string targ,string fromname,string frommud,mapping data); +private void ping_reply_in(string sender,string origin,string target,mapping data); +private void chanwho_reply_in(string origin, string target, mapping data); +private void send_keepalive_request(); +private int chan_perm_allowed(object user, string chan); +private string localize_channel(string str); +private void chan_who_in(string fromname, string frommud, mapping data); +private void send_ice_refresh(); +private void resolve_callback(string address, string resolved, int key); + +//private varargs void Debug(mixed msg, int x){ +// Add stuff in here if you want to see messages. +//} + +// Functions for users to change. +int can_use(object user){ return 1; } // Is this person allowed to use IMC2 at all? This function determines if tells can be sent to the person and such. +int level(object ob){ + // Outgoing packets are marked with the user's level. + // This function figures it out. + // If you have different ways of ranking, make this function convert them to what IMC2 uses. + // IMC2 uses: Admin=5, Imp=4, Imm=3, Mort=2, or None=1 + if(ADMIN(ob)) return 5; // Admin + //TMI-2: if(wizardp(ob)) return 3; + //TMI-2: if(userp(ob)) return 2; + //Discworld: if(ob->query_creator()) return 3; + if(this_player()) return 2; + return 1; // None +} + +string chan_perm_desc(int i){ + // Given the permission level assigned locally to a channel, return a short + // string describing what the number means. The number means nothing + // outside of this MUD. Also, they are independant of each other, and + // so you can do groups without having to always do subgroups of higher + // ones or anything like 'levels'. BACKLOG_WEB_LEVEL is the only one of + // significance, as it's the only one that the web backlog thing works on. + switch(i){ + case 2: return "arch"; + case 1: return "creator"; + case 0: return "public"; + } + return "invalid"; +} + +int chan_perm_allowed(object user, string chan){ + // Using the permission level assigned locally to a channel, + // return 1 if user is allowed to use the channel, 0 if not. + switch(localchaninfo[chan]["perm"]){ + case 2: if(archp(user)) return 1; return 0; + case 1: if(creatorp(user)) return 1; return 0; + case 0: return 1; + } +} + + +// Shouldn't have to change anything beyond this point. + +private int read_callback(object socket, string info){ + // string str, *strs; + string a,b; int done=0; + if(!sizeof(info)) return 0; + //Debug(save_variable(info),DEB_IN); +#ifdef DATA_LOG + log_file(DATA_LOG,"SERVER: "+save_variable(info)+"\n"); +#endif + buf += info; + // The hub groups packets, unfortunately. + switch(mode){ + case MODE_WAITING_ACCEPT: // waiting for Hub to send autosetup + if(sscanf(info, "autosetup %s accept %s\n"+CARRIAGE_RETURN, + hub_name, network_name)==2){ + //Debug("Connected, hub is "+hub_name+", network is "+network_name); + mode = MODE_CONNECTED; + send_is_alive("*"); + send_keepalive_request(); + send_ice_refresh(); + } + else if(sscanf(info, "PW %s %s version=%d %s\n", + hub_name, server_pass, server_version, network_name)==4){ + mode = MODE_CONNECTED; + send_is_alive("*"); + send_keepalive_request(); + send_ice_refresh(); + } + else{ // Failed login sends plaintext error message. + //Debug("Failed to connect... "+info); + } + buf=""; // clear buffer + break; + case MODE_CONNECTED: + while(!done){ + if(sscanf(buf,"%s\n"+CARRIAGE_RETURN+"%s",a,b)==2){ // found a break... + got_packet(a); + buf=b; + } + else{ // no break... + done = 1; + } + } + /* + strs = explode(info,"\n"+CARRIAGE_RETURN); + foreach(str in strs){ + got_packet(str); + } + buf=""; + */ + break; + } + return 1; +} + +private void got_packet(string info){ + string str; + string a,b; + int i; + string sender, origin, route, packet_type, target, destination, strdata; + int sequence; + mapping data; + object who; + if(!sizeof(info)) return; + //Debug(save_variable(info),DEB_PAK); + + str = info; + // messages end with newlines or sometimes just a space + sscanf(str, "%s\n^", str); + sscanf(str, "%s"+CARRIAGE_RETURN+"^", str); + sscanf(str, "%s ^", str); + sscanf(str, "%s ^", str); + if(sscanf(str, "%s %d %s %s %s %s", + a, sequence, route, packet_type, + b, strdata)==6){ // matches + if(sscanf(b,"%s@%s",target,destination)!=2){ + // Could be MUD instead of Name@MUD or *@MUD + target="*"; destination=b; + } + if(sscanf(a,"%s@%s",sender,origin)!=2){ + sender="*"; origin=a; + } + data = string_to_mapping(strdata); + // Debug("sender="+sender); + // Debug("origin="+origin); + // Debug("sequence="+sequence); + // Debug("route="+route); + // Debug("packet_type="+packet_type); + // Debug("data="+save_variable(data)); + if(!mudinfo[origin]) mudinfo[origin] = ([ ]); + + switch(packet_type){ + case "is-alive": // For making a MUD list. + if(!mudinfo[origin]) mudinfo[origin] = ([ ]); + // example of info: + // versionid=\"IMC2 AntiFreeze CL-2 SWR 1.0\" url=none md5=1 + //mudinfo[origin]["version"]="blah"; + mudinfo[origin]+=data; + mudinfo[origin]["online"]=1; + //Debug("handled is-alive for mud "+origin); + break; + case "close-notify": // Someone disconnected. + if(!mudinfo[data["host"]]) mudinfo[data["host"]] = ([]); + mudinfo[data["host"]]["online"]=0; + break; + case "keepalive-request": // Request for is-alive. + send_is_alive(origin); + break; + case "ice-msg-b": // Broadcast channel message. + channel_in(sender, origin, data); + break; + case "tell": // Tells or emotes. + tell_in(sender, origin, target, data); + break; + case "who-reply": + who_reply_in(origin,target,data); + break; + case "whois": // Like I3's locate + whois_in(sender,origin,target,data); + break; + case "whois-reply": + whois_reply_in(target,sender,origin,data); + break; + case "beep": + beep_in(sender, origin, target, data); + break; + case "ice-update": // Reply from ice-refresh. + chaninfo[data["channel"]]=data; + break; + case "wHo": // Drop-through + case "who": + send_packet("*","who-reply",sender,origin, + "text="+escape(pinkfish_to_imc2(WHO_STR))); + break; + case "ice-destroy": // Deleting channel. + map_delete(chaninfo,data["channel"]); + break; + case "user-cache": // User info, like I3's ucache service. + if(!genders[origin]) genders[origin]=([ ]); + genders[origin][sender]=data["gender"]; + break; + case "user-cache-reply": // Reply with user info + if(!genders[origin]) genders[origin]=([ ]); + genders[origin][data["user"]]=data["gender"]; + break; + case "user-cache-request": // Request for user info + sscanf(data["user"],"%s@%*s",str); + who = FIND_PLAYER(lower_case(str)); + if(who +#ifdef INVIS + && !INVIS(who) +#endif + ){ + switch(GET_GENDER(who)){ + case "male" : i=0; break; + case "female" : i=1; break; + default : i=2; break; + } + send_packet("*","user-cache-reply",sender, + origin,sprintf("gender=%d",i)); + } + break; + case "ping": + send_packet("*","ping-reply",sender,origin, + sprintf("path=\"%s\"",route)); + break; + case "ping-reply": + ping_reply_in(sender,origin,target,data); + break; + case "ice-msg-r": // Relayed channel message. + channel_in(sender, origin, data); + break; + case "ice-chan-whoreply": // Tell who's listening to a channel. + chanwho_reply_in(origin,target,data); + break; + case "emote": // Channel creation/destruction message... anything else? + IMC2_MSG(NETWORK_ID+" announces: "+data["text"]+"\n", + filter_array(users(), (: ADMIN($1) :))); +#ifdef ANNOUNCE_LOG + log_file(ANNOUNCE_LOG,ctime(time())+": "+data["text"]+"\n"); +#endif + break; + case "ice-chan-who": // Check who's listening to a channel. + chan_who_in(sender,origin,data); + break; + case "channel-notify": + // Don't care about this. Useful only if you care when + // people on other MUDs start/stop listening to a channel. + // example: Someone@SomeMUD 1087076772 SomeMUD channel-notify *@* channel=Hub01:ichat status=0 + break; + // The following packets shouldn't be incoming. + case "ice-cmd": // Remote channel administration + case "remote-admin": // For controlling the hub + case "ice-refresh": // Request data about channels + case "ice-msg-p": // Private channel message + //Debug("This packet isn't supposed to be incoming: "+packet_type); + break; + default: +#ifdef UNKNOWN_DATA_LOG + log_file(UNKNOWN_DATA_LOG,"Unknown packet: "+escape(info)+"\n\n"); +#endif + //Debug("Unlisted packet type: "+packet_type); + break; + } + } + else{ + buf += info; + //Debug("Doesn't match incoming pattern, so putting on buffer: "+str); +#ifdef BAD_PACKET + log_file(BAD_PACKET,"Doesn't match incoming pattern: "+str+"\n"); +#endif + } +} + +private int close_callback(object socket){ + // Connection was closed. +#ifdef DATA_LOG + log_file(DATA_LOG,"DISCONNECTED\n"); +#endif + socket_close(socket_num); + // socket->remove(); + create(); + return 1; +} +private void send_text(string text){ + // Send a literal string. + // Almost everything should use the send_packet function instead of this. +#ifdef DATA_LOG + log_file(DATA_LOG,"CLIENT: "+save_variable(text)+"\n"); +#endif + //Debug(save_variable(text), DEB_OUT); + // Debug("writing to socket: "+socket_num); + socket_write(socket_num,text); + // imc2_socket->send(text); + return; +} + +void create(){ +#ifndef NO_UIDS + seteuid(getuid()); +#endif +#ifdef DATA_LOG + log_file(DATA_LOG,"Creating IMC2 object at "+ctime(time())+".\n"); +#endif + if(sizeof(get_dir(SAVE_FILE+".o"))) RestoreObject(SAVE_FILE); + if(!mudinfo) mudinfo = ([ ]); + if(!chaninfo) chaninfo = ([ ]); + if(!localchaninfo) localchaninfo = ([ ]); + if(!genders) genders = ([ ]); + if(!tells) tells=([ ]); + ping_requests=([ ]); + mode = MODE_WAITING_ACCEPT; +#ifdef HOSTIP + // We already know the IP, go straight to the connecting, just do callback as if it found the IP. + resolve_callback(HOSTIP,HOSTIP,1); +#else + if(!resolve(HOSTNAME, "resolve_callback")){ + //Debug("Addr_server is not running, resolve failed."); +#ifdef DATA_LOG + log_file(DATA_LOG,"Addr_server is not running, resolve failed.\n"); +#endif + remove(); + return; + } +#endif + //Debug("creating IMC2 object"); +} + +void remove(){ + // This object is getting destructed. + if(!socket_num) socket_close(socket_num); + // if(imc2_socket) imc2_socket->remove(); +#ifdef DATA_LOG + log_file(DATA_LOG,"IMC2 OBJECT REMOVED\n"); +#endif + SaveObject(SAVE_FILE); + destruct(this_object()); +} + +private void resolve_callback( string address, string resolved, int key ) { + // Figured out what the IP is for the address. + int error; + //Debug("Resolved to: "+resolved); + write_file("/tmp/imc2.log","address: "+address); + write_file("/tmp/imc2.log","resolved: "+resolved); + write_file("/tmp/imc2.log","key: "+key); + + //socket_num = socket_create(STREAM, "close_callback"); + socket_num = socket_create(STREAM, "read_callback", "close_callback"); + if (socket_num < 0) { +#ifdef DATA_LOG + log_file(DATA_LOG,"socket_create: " + socket_error(socket_num) + "\n"); +#endif + trr("socket_create: " + socket_error(socket_num) + "\n"); + return; + } + //Debug("Created socket descriptor " + socket_num); + + error = socket_connect(socket_num, resolved+" "+HOSTPORT, "read_callback", "write_callback"); + if (error != EESUCCESS) { +#ifdef DATA_LOG + log_file(DATA_LOG,"socket_connect: " + socket_error(error) + + "\nGURU MEDITATION #DEADBEEF.FEEDFACE\n"); +#endif + //Debug("socket_connect, error="+error+": " + socket_error(error) + "\n"); + socket_close(socket_num); + return; + } +} + +private void write_callback(){ + start_logon(); +} + +private void start_logon(){ + //Debug("Gonna try logging in, sending the PW thing..."); +#if NOT_AUTO + send_text(sprintf("PW %s %s version=%d\n", +#else + send_text(sprintf("PW %s %s version=%d autosetup %s\n", +#endif + MUDNAME, + CLIENT_PW, 2 +#ifndef NOT_AUTO + , SERVER_PW +#endif + )); + buf=""; + /* For invitation-only networks. + send_text(sprintf("PW %s %s version=%d %s\n", + MUDNAME, + CLIENT_PW, 2, "hub03" + )); + */ + sequence=time(); + } + + string escape(string str){ + str=replace_string(str,"\\","\\\\"); + str=replace_string(str,"\"","\\\""); + str=replace_string(str,"\n","\\n"); + str=replace_string(str,CARRIAGE_RETURN,"\\"+CARRIAGE_RETURN); + if(sizeof(explode(str," "))!=1) str = "\""+str+"\""; + return str; + } + + string unescape(string str){ + string a,b=str,output=""; + while(sscanf(b,"%s\\%s",a,b)==2){ + output += a; + if(sizeof(b)){ + switch(b[0]){ + case 34 : output += "\""; break; // '\"' makes warnings. + case '\\' : output += "\\"; break; + case 'n' : output += "\n"; break; + case 'r' : output += CARRIAGE_RETURN; break; + } + } + b=b[1..]; + } + output += b; + output = replace_string(output,"\n"+CARRIAGE_RETURN,"\n"); + if((sizeof(explode(output," "))==1) && sscanf(output,"\\\"%*s\\\"") ) output = "\""+output+"\""; + return output; + } + + mapping string_to_mapping(string str){ + // Picks first element off of string and then repeats? + mapping out=([]); + int in_quote=0; + int i, j; + string what,data,rest; + + rest = str; + + while(sizeof(rest)>0){ + sscanf(rest, "%s=%s", what, rest); + /* + write("what="+what+", rest="+rest+"\n"); + */ + // At this point, what is the key, rest is value plus rest. + if(rest[0]==34){ // value is in quotes, tons of fun! + // find first quote without a backslash in front? + /* + write("rest begings with a quote\n"); + */ + i = 1; + while(((rest[i]!=34) || (rest[i-1]==92)) && (i<sizeof(rest))){ // 34 = ", 92 = \ + // While this is not a quote, or if this is an escaped quote, keep looking. + i++; + } + // now are 1 space past quote + // write("i="+i+"\n"); + data=rest[1..(i-1)]; // skip opening and closing quotes + rest=rest[(i+2)..]; // skip past space + // write("new data="+data+"\n"); + // write("new rest="+rest+"\n"); + // Data is now what was in the quotes... now to un-escape the data... + out[what]=unescape(data); + } + else{ // value is not in quotes, tons of actual non-sarcastic fun! + // just split it at the first space + if(sscanf(rest,"%s %s",data,rest)!=2){ // break at first space + data = rest; + rest = ""; + } + if((sscanf(data,"%d",i)==1) && (sprintf("%d",i)==data)) // is just number + out[what]=i; + else // not just a number + out[what]=data; + } + } + return out; + } + + private void send_packet(string sender, string packet_type, string target, string destination, string data){ + // Sends a packet in the format that IMC2 uses. + sequence++; + send_text(sprintf("%s@%s %d %s %s %s@%s %s\n", + sender, MUDNAME, sequence, MUDNAME, packet_type, + target, destination, data + )); + } + + void send_keepalive_request(){ + // Ask all the muds to tell us that they're alive. + string mud; + // Mark all the muds as offline until they respond. + foreach(mud in keys(mudinfo)){ + mudinfo[mud]["online"]=0; + } + send_packet("*","keepalive-request","*","*",""); + } + + varargs void send_is_alive(string origin){ + // Sends an is-alive packet to whoever requested it, or else broadcasts it. + send_packet("*","is-alive","*",(origin ? origin : "*"), + sprintf("versionid=\"%s\" networkname=%s url=%s", + VERSION, network_name, URL)); + } + + private int chan_listening(object user, string chan){ + // Tells if a user is listening to a channel or not. + if(!localchaninfo[chan]) return 0; + if(member_array(GET_NAME(user),localchaninfo[chan]["users"])==-1) return 0; + return chan_perm_allowed(user,chan); + } + + void channel_in(string fromname, string frommud, mapping data){ + // Handles an incoming channel message. + object user, *usrs; + string msg,blmsg; + string sender; + string local; + int emote=0; + int sz; + + /* + tell_object(find_player("tim"),("data="+identify(data)+"\n")); + */ + + sender=fromname+"@"+frommud; + if(data["sender"]) sender=data["sender"]; + if(data["realfrom"]) sender=data["realfrom"]; + if(intp(data["text"])) data["text"]=sprintf("%d",data["text"]); + // the data processing function makes "1" into a number, + // which can be a problem when a person says just a number on a channel :P + local=localize_channel(data["channel"]); + if(data["emote"]) emote=data["emote"]; +#ifdef CHANNEL_BOT + // Can define CHANNEL_BOT to something with got_chan(channel,from,text,emote) + // It will be given all channel messages. Be aware of this. + call_other(CHANNEL_BOT,"got_chan",data["channel"],sender,data["text"],emote); +#endif +#ifdef CHANNEL_BOTS + if(CHANNEL_BOTS[local]){ + call_other(CHANNEL_BOTS[local],"got_chan",local,sender,data["text"],emote); + } + else if(CHANNEL_BOTS[data["channel"]]){ + call_other(CHANNEL_BOTS[data["channel"]],"got_chan",data["channel"],sender,data["text"],emote); + } +#endif + if(!local) return; // Channel not used locally, ignore. + usrs = ({ }); + data["text"]=imc2_to_pinkfish(data["text"]); + foreach(user in users()) + if(chan_listening(user,local)) usrs += ({ user }); + if(emote==2){ + msg=sprintf("%s- [%%^GREEN%%^%s%%^RESET%%^] %%^CYAN%%^(from %s)%%^RESET%%^ %s", + NETWORK_ID,local,sender,data["text"]); + blmsg=sprintf("%s- [%s] (from %s) %s", + NETWORK_ID,local,sender,data["text"]); + } + else if(emote){ + msg=sprintf("%s- [%%^GREEN%%^%s%%^RESET%%^] %%^CYAN%%^%s%%^RESET%%^ %s", + NETWORK_ID,local,sender,data["text"]); + blmsg=sprintf("%s- [%s] %s %s", + NETWORK_ID,local,sender,data["text"]); + } + else{ + msg=sprintf("%s- %%^CYAN%%^%s%%^RESET%%^ [%%^GREEN%%^%s%%^RESET%%^]: %s", + NETWORK_ID, sender,local,data["text"]); + blmsg=sprintf("%s- %s [%s]: %s", + NETWORK_ID, sender,local,data["text"]); + } + IMC2_MSG(msg+"\n",usrs); + localchaninfo[local]["backlog"] += ({ ctime(time())[4..18]+" "+blmsg }); + sz = sizeof(localchaninfo[local]["backlog"]); + if(sz>BACKLOG_SIZE) + localchaninfo[local]["backlog"]=localchaninfo[local]["backlog"][(sz-BACKLOG_SIZE)..sz]; + } + + private void channel_out(object user,string chan,string msg){ + // Send outgoing channel message. + send_packet(GET_CAP_NAME(user),"ice-msg-b","*","*", + sprintf("channel=%s text=%s emote=0 echo=1", + chan,escape(GET_CAP_NAME(user)+"@"+MUDNAME+" "+msg))); + } + + private varargs void tell_out(object from, string targname, string targmud, string msg, int reply, int emote){ + // Send outgoing tell. + if(!reply) reply=0; + send_packet(GET_CAP_NAME(from),"tell",targname,targmud, + sprintf("level=%d text=%s reply=%d emote=%d", level(from),escape(msg),reply,emote)); + } + + private void tell_in(string sender, string origin, string target, mapping data){ + // Incoming tell. + object who; + int sz; + string blmsg; + who=FIND_PLAYER(lower_case(target)); + target=GET_CAP_NAME(who); + data["text"]=imc2_to_pinkfish(data["text"]); + if(who +#ifdef INVIS + && VISIBLE(who) +#endif + && can_use(who) + ){ + switch(data["isreply"]){ + case 2: // emote + IMC2_MSG(sprintf("%s tell: %%^CYAN%%^%s@%s%%^RESET%%^ %s\n", + NETWORK_ID,sender,origin,data["text"]), who); + blmsg=sprintf("%s tell: %s@%s %s\n", + NETWORK_ID,sender,origin,data["text"]); + break; + case 1: // reply + IMC2_MSG(sprintf("%s %%^CYAN%%^%s@%s%%^RESET%%^ replies to you: %s\n", + NETWORK_ID,sender,origin,data["text"]), who); blmsg=sprintf("%s %s@%s replied to you: %s\n", + NETWORK_ID,sender,origin,data["text"]); + break; + default: + IMC2_MSG(sprintf("%s %%^CYAN%%^%s@%s%%^RESET%%^ tells you: %s\n", + NETWORK_ID,sender,origin,data["text"]), who); + blmsg=sprintf("%s %s@%s told you: %s\n", + NETWORK_ID,sender,origin,data["text"]); + break; + } + if(!tells[target]) + tells[target]=([ ]); + tells[target]["reply"] = sprintf("%s@%s",sender,origin); + if(!tells[target]["backlog"] || !arrayp(tells[target]["backlog"])) + tells[target]["backlog"]=({ }); + tells[target]["backlog"] += ({ blmsg }); + sz = sizeof(tells[target]["backlog"]); + if(sz>BACKLOG_SIZE) + tells[target]["backlog"]=tells[target]["backlog"][(sz-BACKLOG_SIZE)..sz]; + } + else{ +#ifdef TELL_BOTS + // Can have a mapping of bots which can get tells. + if(TELL_BOTS[target]){ + call_other(TELL_BOTS[target],"got_tell",sender, origin, target, data["text"]); + return; + } +#endif +#ifdef TELL_BOT + // They should have got_tell(fromname, frommud, target, text) + // I'll assume bots don't care about emote/reply... tell me if you do? + // TELL_BOT will get told of all tells which don't have a valid target, and + // then the sender will be notified that it didn't get to anyone. + // This would be useful if for example you wanted all tells sent to + // offline people to be mudmailed to them or something. + call_other(TELL_BOTS[target],"got_tell",sender, origin, target, data["text"]); +#endif + send_packet("*","tell",sender,origin, + sprintf("level=-1 text=\"%s is not online on this mud.\" isreply=1",target)); + } + } + + string pinkfish_to_imc2(string str){ + // Foreground + str=replace_string(str,"%^BLACK%^","~x"); // Black + str=replace_string(str,"%^RED%^","~R"); // Red + str=replace_string(str,"%^GREEN%^","~G"); // Green + str=replace_string(str,"%^BLUE%^","~B"); // Blue + str=replace_string(str,"%^WHITE%^","~W"); // White + str=replace_string(str,"%^ORANGE%^","~y"); // Orange + str=replace_string(str,"%^CYAN%^","~c"); // Cyan + str=replace_string(str,"%^YELLOW%^","~Y"); // Yellow + str=replace_string(str,"%^MAGENTA%^","~p"); // Magenta -> purple sounds closest + str=replace_string(str,"%^GRAY%^","~w"); // Gray doesn't display on my MUD, bah :( + // Background + str=replace_string(str,"%^B_BLACK%^","^x"); + str=replace_string(str,"%^B_RED%^","^R"); // Red + str=replace_string(str,"%^B_GREEN%^","^G"); // Green + str=replace_string(str,"%^B_BLUE%^","^b"); // Blue + str=replace_string(str,"%^B_WHITE%^","^W"); // White + str=replace_string(str,"%^B_ORANGE%^","^O"); // Orange + str=replace_string(str,"%^B_CYAN%^","^c"); // Cyan + str=replace_string(str,"%^B_YELLOW%^","^Y"); // Yellow + str=replace_string(str,"%^B_MAGENTA%^","^p"); // Magenta -> purple sounds closest + // Misc. + str=replace_string(str,"%^FLASH%^","~$"); // Flash -> Blink + str=replace_string(str,"%^BOLD%^","~L"); // Bold + str=replace_string(str,"%^RESET%^","~!"); + return str; + } + + string imc2_to_pinkfish(string str){ + string output=""; + int i,sz; + /* + For colors explanation, refer to IMC Packet Documentation by Xorith. + Thanks very much for putting that out, by the way. :) + Found at http://hub00.muddomain.com/imc2_protocol_doc.txt + */ + sz=sizeof(str)-1; + while(sizeof(str)>1){ + switch(str[0]){ + case '~': // Foreground + switch(str[1]){ + case 'Z': break; // Random + case 'x': output += "%^BLACK%^"; break; // Black + case 'r': output += "%^RED%^"; break; // Dark Red + case 'g': output += "%^GREEN%^"; break; // Dark Green + case 'y': output += "%^ORANGE%^"; break; // Orange + case 'b': output += "%^BLUE%^"; break; // Dark Blue + case 'p': output += "%^MAGENTA%^"; break; // Purple + case 'c': output += "%^CYAN%^"; break; // Cyan + case 'w': output += "%^WHITE%^"; break; // Grey + case 'D': output += "%^BLACK%^"; break; // Dark Grey + case 'z': output += "%^BLACK%^"; break; // Same as ~D + case 'R': output += "%^RED%^"; break; // Red + case 'G': output += "%^GREEN%^"; break; // Green + case 'Y': output += "%^YELLOW%^"; break; // Yellow + case 'B': output += "%^BLUE%^"; break; // Blue + case 'P': output += "%^MAGENTA%^"; break; // Pink + case 'C': output += "%^BLUE%^"; break; // Light Blue + case 'W': output += "%^WHITE%^"; break; // White + + case 'm': output += "%^MAGENTA%^"; break; // same as p + case 'd': output += "%^WHITE%^"; break; // same as w + case 'M': output += "%^MAGENTA%^"; break; // same as P + // Misc. + case '!': output += "%^RESET%^"; break; // Reset + case 'L': output += "%^BOLD%^"; break; // Bold + case 'u': break; // Underline + case '$': output += "%^FLASH%^"; break; // Blink + case 'i': break; // Italic + case 'v': break; // Reverse + case 's': break; // Strike-thru + + case '~': output += "~"; break; // ~~ prints as ~ + default : output += "~"; // Don't skip over this + // (cheap hack is to add a character in front so the [2..] thing still works) + str = " "+str; + break; + } + str=str[2..]; + break; + case '^': // Background + switch(str[1]){ + case 'Z': break; // Random + case 'x': output += "%^B_BLACK%^"; break; // Black + case 'r': output += "%^B_RED%^"; break; // Dark Red + case 'g': output += "%^B_GREEN%^"; break; // Dark Green + case 'O': output += "%^B_ORANGE%^"; break; // Orange + case 'B': output += "%^B_BLUE%^"; break; // Dark Blue + case 'p': output += "%^B_MAGENTA%^"; break; // Purple + case 'c': output += "%^B_CYAN%^"; break; // Cyan + case 'w': output += "%^B_WHITE%^"; break; // Grey + case 'z': output += "%^B_BLACK%^"; break; // Dark Grey + case 'R': output += "%^B_RED%^"; break; // Red + case 'G': output += "%^B_GREEN%^"; break; // Green + case 'Y': output += "%^B_YELLOW%^"; break; // Yellow + case 'b': output += "%^B_BLUE%^"; break; // Blue + case 'P': output += "%^B_MAGENTA%^"; break; // Pink + case 'C': output += "%^B_BLUE%^"; break; // Light Blue + case 'W': output += "%^B_WHITE%^"; break; // White + case '^': output += "^"; break; // ^^ prints as ^ + default : output += "^"; // Don't skip over this + // (cheap hack is to add a character in front so the [2..] thing still works) + str = " "+str; + break; + } + str=str[2..]; + break; + case '`': // Blinking Foreground + switch(str[1]){ + case 'Z': output += "%^FLASH%^"; break; // Random + case 'x': output += "%^FLASH%^%^BLACK%^"; break; // Black + case 'r': output += "%^FLASH%^%^RED%^"; break; // Dark Red + case 'g': output += "%^FLASH%^%^GREEN%^"; break; // Dark Green + case 'O': output += "%^FLASH%^%^ORANGE%^"; break; // Orange + case 'b': output += "%^FLASH%^%^BLUE%^"; break; // Dark Blue + case 'p': output += "%^FLASH%^%^MAGENTA%^"; break; // Purple + case 'c': output += "%^FLASH%^%^CYAN%^"; break; // Cyan + case 'w': output += "%^FLASH%^%^WHITE%^"; break; // Grey + case 'z': output += "%^FLASH%^%^BLACK%^"; break; // Dark Grey + case 'R': output += "%^FLASH%^%^RED%^"; break; // Red + case 'G': output += "%^FLASH%^%^GREEN%^"; break; // Green + case 'Y': output += "%^FLASH%^%^YELLOW%^"; break; // Yellow + case 'B': output += "%^FLASH%^%^BLUE%^"; break; // Blue + case 'P': output += "%^FLASH%^%^MAGENTA%^"; break; // Pink + case 'C': output += "%^FLASH%^%^BLUE%^"; break; // Light Blue + case 'W': output += "%^FLASH%^%^WHITE%^"; break; // White + case '`': output += "`"; break; // `` prints as ` + default : output += "`"; // Don't skip over this + // (cheap hack is to add a character in front so the [2..] thing still works) + str = " "+str; + break; + } + str=str[2..]; + break; + default: + output += str[0..0]; + str=str[1..]; + break; + } + } + output += str; + return output; + } + + private void who_reply_in(string origin, string target, mapping data){ + string output; + object targuser; + targuser = FIND_PLAYER(lower_case(target)); + if(targuser){ + output = NETWORK_ID+" who reply from: %^CYAN%^"+origin+"%^RESET%^\n"; + output += imc2_to_pinkfish(data["text"])+"\n"; + IMC2_MSG(output,targuser); + } + } + + private void whois_in(string fromname, string frommud, string targ, mapping data){ + if(FIND_PLAYER(lower_case(targ)) +#ifdef INVIS + && !INVIS(FIND_PLAYER(lower_case(targ))) +#endif + && can_use(FIND_PLAYER(lower_case(targ))) + ){ + send_packet(targ,"whois-reply",fromname,frommud,"text=Online"); + } +#ifdef USER_EXISTS + else if(USER_EXISTS(lower_case(targ))){ + send_packet(targ,"whois-reply",fromname,frommud, + "text=\"Exists but is offline\""); + } +#endif + } + + private void whois_reply_in(string targ,string fromname,string frommud,mapping data){ + object who; + who=FIND_PLAYER(lower_case(targ)); + if(who){ + IMC2_MSG(sprintf("%s whois reply: %s@%s: %s\n", + NETWORK_ID,fromname,frommud,data["text"]),who); + } + } + + private void beep_in(string sender, string origin, string target, mapping data){ + object who; + who=FIND_PLAYER(lower_case(target)); + if(who && can_use(who) +#ifdef INVIS + && VISIBLE(who) +#endif + ){ + IMC2_MSG(sprintf("%s- %%^CYAN%%^%s@%s%%^RESET%%^ \abeeps you.\n", + NETWORK_ID,sender,origin,data["text"]), who); + } + else{ + send_packet("*","tell",sender,origin, + sprintf("level=-1 text=\"%s is not online.\" isreply=1",target)); + } + } + + private void beep_out(object from, string targname, string targmud){ + send_packet(GET_CAP_NAME(from),"beep",targname,targmud, + sprintf("level=%d ", level(from))); + } + + private void send_ice_refresh(){ send_packet("*","ice-refresh","*","*",""); } + + private void ping_reply_in(string sender,string origin,string target,mapping data){ + object who; + if((target=="*") && target=ping_requests[sender]){ + target=ping_requests[sender]; + map_delete(ping_requests,sender); + } + who=FIND_PLAYER(lower_case(target)); + if(who){ + IMC2_MSG(sprintf("%s route to %%^CYAN%%^%s%%^RESET%%^ is: %s\n", + NETWORK_ID,origin,data["path"]), who); + } + } + + private void ping_out(string from,string targmud){ send_packet(from,"ping","*",targmud,""); } + private varargs void who_out(string from,string targmud,string type){ send_packet(from,"who","*",targmud,(type ? sprintf("type=\"%s\"",type) : "type=who")); } + + private void chanwho_out(object from,string chan,string mud){ + send_packet(GET_CAP_NAME(from),"ice-chan-who","*",mud, + sprintf("level=%d channel=%s lname=%s",level(from), + localchaninfo[chan]["name"],chan)); + } + + private void chanwho_reply_in(string origin, string target, mapping data){ + string output; + object targuser; + targuser = FIND_PLAYER(lower_case(target)); + if(targuser){ + output = NETWORK_ID+" chanwho reply from "+origin+" for "+data["channel"]+"\n"; + output += imc2_to_pinkfish(data["list"]); + IMC2_MSG(output,targuser); + } + } + + private void chan_who_in(string fromname, string frommud, mapping data){ + // Handles an incoming channel who request. + object user, *usrs=({ }); + string local, lname; + string output; + local=localize_channel(data["channel"]); + if(data["lname"]) lname = data["lname"]; + else lname = local; + if(!local){ // Channel not used locally. + output = sprintf("channel=%s list=\"%s (%s) is not configured on this MUD.\n\"", + data["channel"],lname,data["channel"]); + } + else{ // Is used locally + output = "The following users are listening to "+lname+" ("+local+"):\n "; + foreach(user in users()){ + if(chan_listening(user,local) +#ifdef INVIS + && !INVIS(user) +#endif + ){ + usrs += ({ GET_CAP_NAME(user) }); + } + } // foreach + output += implode(usrs,", "); + output += "\n"; + if(!sizeof(usrs)){ + output=sprintf("channel=%s list=\"Nobody is listening to %s (%s) on this MUD.\n\"", + lname,local); + } + } + send_packet("*","ice-chan-whoreply",fromname,frommud,output); + } + + string find_mud(string str){ + // Makes case-insensitive mud name into the actual mud name, or else 0. + string mud; + if(!str) return 0; + str=lower_case(str); + foreach(mud in keys(mudinfo)){ + if(lower_case(mud)==str) return mud; + } + return 0; + } + + string localize_channel(string str){ + // Tells what the local name for a channel is, given the network name for it, or else 0. + string a; + foreach(a in keys(localchaninfo)){ + if(lower_case(localchaninfo[a]["name"])==lower_case(str)) return a; + } + return 0; + } + + int command(string str){ + // Takes the arguments given to the command which does IMC2 stuff. + string cmd, args; + string mud, *muds; + string output; + string a,b,c; + int x,y,z; + int emote,reply; + object usr, *usrs=({ }); + if(!str) str = "help"; + sscanf(str,"%s %s",cmd,args); + if(!cmd) cmd=str; + if(!args) args = ""; + switch(cmd){ + case "list": + muds = sort_array(keys(mudinfo),1); + if (!sizeof(mudinfo)){ + return notify_fail("There are no muds on the "+NETWORK_ID+" network!\n"); + } + else{ + x=0; y=0; + output=sprintf("[%s] %-20s %-20s %-20s\n","U/D?","Name","Network","IMC2 Version"); + foreach (mud in muds){ + if(!mudinfo[mud]) output += "Error on mud: "+mud+"\n"; + else{ + if(mudinfo[mud]["online"]) + x++; else y++; + output += sprintf("[%s] %-20s %-20s %-20s\n", + (mudinfo[mud]["online"] ? "%^GREEN%^ UP %^RESET%^" : "%^RED%^DOWN%^RESET%^"), + mud, + mudinfo[mud]["networkname"], + mudinfo[mud]["versionid"]); + } + } + output += sprintf("%d of %d MUDs are online.\n",x,x+y); + IMC2_MSG(output,THIS_PLAYER); + return 1; + } + break; + case "setup": + output=sprintf(@EndText +IMC2 NETWORK INFORMATION +------------------------ +Status: %s +Hub address: %s +Hub port: %d +The hub calls itself: %s +The network calls itself: %s +Command to use this network: %s +The MUD calls this connection: %s + +Packet logging: %s + +The network calls the MUD: %s +The MUD's Version ID: %s +The MUD's URL: %s +EndText, + ((mode==MODE_CONNECTED) ? "Connected" : "Not connected"), +#ifdef HOSTNAME + HOSTNAME, +#else + HOSTIP, +#endif + HOSTPORT,hub_name,network_name,COMMAND_NAME,NETWORK_ID, +#ifdef DATA_LOG + "on", +#else + "off", +#endif + MUDNAME,VERSION,URL); + IMC2_MSG(output,THIS_PLAYER); + return 1; + break; + case "info": + if(!args) return notify_fail("See info for which MUD?\n"); + str=find_mud(args); + if(!str) return notify_fail("MUD isn't known on "+NETWORK_ID+".\n"); + output=("Mud info for: "+str+"\nStatus: "); + if(mudinfo[str]["online"]) + output+=("%^GREEN%^Online%^RESET%^\n"); + else + output+=("%^RED%^Offline%^RESET%^\n"); + if(mudinfo[str]["versionid"]) output+=("Version ID: "+mudinfo[str]["versionid"]+"\n"); + if(mudinfo[str]["url"]) output+=("URL: "+mudinfo[str]["url"]+"\n"); + if(mudinfo[str]["networkname"]) output+=("Network name: "+mudinfo[str]["networkname"]+"\n"); + IMC2_MSG(output,THIS_PLAYER); + return 1; + break; + case "ping": + if(!args) return notify_fail("Send ping to which MUD?\n"); + str=find_mud(args); + if(!str) return notify_fail("MUD isn't known on "+NETWORK_ID+".\n"); + if(!mudinfo[str]["online"]) return notify_fail(NETWORK_ID+"- "+b+" is offline right now.\n"); + ping_out(GET_CAP_NAME(THIS_PLAYER),str); + IMC2_MSG(NETWORK_ID+"- Sent a ping to "+str+"\n",THIS_PLAYER); + return 1; + break; + case "who": + if(!args) return notify_fail("Send who request to which MUD?\n"); + str=find_mud(args); + if(!str) return notify_fail("MUD isn't known on "+NETWORK_ID+".\n"); + if(!mudinfo[str]["online"]) return notify_fail(NETWORK_ID+"- "+str+" is offline right now.\n"); + who_out(GET_CAP_NAME(THIS_PLAYER),str); + IMC2_MSG(NETWORK_ID"- Sent a who request to "+str+"\n",THIS_PLAYER); + return 1; + break; + case "finger": + notify_fail("Send finger request to who@where?\n"); + if(!args) return 0; + if(sscanf(args,"%s@%s",a,b)!=2){ + return 0; + } + b=find_mud(b); + who_out(GET_CAP_NAME(THIS_PLAYER),b,"finger "+a); + IMC2_MSG(NETWORK_ID"- Sent a finger request to "+a+"@"+b+"\n",THIS_PLAYER); + return 1; + break; + case "mudinfo": + if(!args) return notify_fail("Send info request to which MUD?\n"); + str=find_mud(args); + if(!str) return notify_fail("MUD isn't known on "+NETWORK_ID+".\n"); + if(!mudinfo[str]["online"]) return notify_fail(NETWORK_ID+"- "+str+" is offline right now.\n"); + who_out(GET_CAP_NAME(THIS_PLAYER),str,"info"); + IMC2_MSG(NETWORK_ID"- Sent an info request to "+str+"\n",THIS_PLAYER); + return 1; + break; + case "chanwho": + if(!args) return notify_fail("What channel?\n"); + if(sscanf(args,"%s %s",a,b)!=2){ + a=args; + b=""; + } + else { + if(b!="*") b=find_mud(b); + } + if(!b) return notify_fail("MUD isn't known on "+NETWORK_ID+".\n"); + if(!localchaninfo[a]) return notify_fail("Invalid channel.\n"); + if(b==""){ // check who's on locally + c = "The following users are listening to "+a+":\n "; + foreach(usr in users()) + if(chan_listening(usr,a)){ + usrs += ({ usr }); + c += " "+GET_CAP_NAME(usr); + } + c += "\n"; + if(!usrs) c="Nobody on this mud is listening to that channel.\n"; + IMC2_MSG(c,THIS_PLAYER); + return 1; + } + if((b!="*") && (!mudinfo[b]["online"])) + return notify_fail(NETWORK_ID+"- "+b+" is offline right now.\n"); + chanwho_out(THIS_PLAYER,a,b); + IMC2_MSG(sprintf("%s- Sent a channel who request to %s for the %s channel.\n", + NETWORK_ID,b,a),THIS_PLAYER); + return 1; + break; + case "chans": + output="Local setup for "+NETWORK_ID+" channels:\n"; + output += sprintf("%-15s %-15s %-15s %-15s\n", + "Local Name","Allowed (you?)","Listening","Network Name"); + foreach(a in sort_array(keys(localchaninfo),1)){ + output += sprintf("%-15s %s%-15s%%^RESET%%^ %s%-15s%%^RESET%%^ %-15s\n", + a, + ((chan_perm_allowed(THIS_PLAYER,a) ? "%^GREEN%^" : "%^RED%^")), + chan_perm_desc(localchaninfo[a]["perm"])+" "+ + ((chan_perm_allowed(THIS_PLAYER,a) ? "(yes)" : "(no)")), + ((chan_listening(THIS_PLAYER,a) ? "%^GREEN%^" : "%^RED%^")), + ((chan_listening(THIS_PLAYER,a) ? "yes" : "no")), + localchaninfo[a]["name"]); + } + IMC2_MSG(output,THIS_PLAYER); + return 1; + break; + case "allchans": + output=NETWORK_ID+" channels:\n"; + output += sprintf("%-23s %-17s %-7s %-6s %-10s %-10s\n", + "Name","Owner","Policy","Level","Suggested","Local Name"); + foreach(a in sort_array(keys(chaninfo),1)){ + output += sprintf("%-23s %-17s %-7s %-6s %-10s %-10s\n", + a,chaninfo[a]["owner"], + chaninfo[a]["policy"], + chaninfo[a]["level"],chaninfo[a]["localname"], + (localize_channel(a) ? localize_channel(a) : "<none>")); + } + IMC2_MSG(output,THIS_PLAYER); + return 1; + break; + case "beep": + if(!args || sscanf(args,"%s@%s",a,b)!=2) + return notify_fail("Invalid syntax. "+COMMAND_NAME+" beep name@mud\n"); + b=find_mud(b); + if(!b) return notify_fail("MUD isn't known on "+NETWORK_ID+".\n"); + if(!mudinfo[b]["online"]) return notify_fail("That MUD is offline right now\n"); + IMC2_MSG(sprintf("%s- You beep %s@%s\n",NETWORK_ID,a,b),THIS_PLAYER); + beep_out(THIS_PLAYER,a,b); + return 1; + break; + case "chanemote": // Drop through + case "chatemote": // Drop through + case "chansocial": // Drop through + case "chatsocial": // Drop through + case "chat": // Drop through + case "chan": + switch(cmd){ + case "chatemote" : // Drop-through + case "chanemote" : emote=1; break; + case "chatsocial" : // Drop-through + case "chansocial" : emote=2; break; + } + if(!args || (sscanf(args,"%s %s",a,b)!=2)) + return notify_fail("Syntax: "+COMMAND_NAME+" chan channel message\n"); + if(!localchaninfo[a]) return notify_fail(a+" is not a channel.\n"); + if(!chan_perm_allowed(THIS_PLAYER,a)) + return notify_fail("You need permission to use the "+a+" channel.\n"); + if(!chan_listening(THIS_PLAYER,a)) + return notify_fail("You are not listening to the "+a+" channel.\n"); + if(emote==2){ + IMC2_MSG(sprintf("Sent to %s- [%s] %s\n",NETWORK_ID, + a,b),THIS_PLAYER); + } + else if(emote){ + IMC2_MSG(sprintf("Sent to %s- [%s] %s %s\n",NETWORK_ID, + a,GET_CAP_NAME(THIS_PLAYER),b),THIS_PLAYER); + } + else{ + IMC2_MSG(sprintf("Sent to %s- %s [%s] %s\n",NETWORK_ID, + GET_CAP_NAME(THIS_PLAYER),a,b),THIS_PLAYER); + } + send_packet(GET_CAP_NAME(THIS_PLAYER),"ice-msg-b","*","*", + sprintf("channel=%s text=%s emote=%d echo=1", + localchaninfo[a]["name"],escape(pinkfish_to_imc2(b)),emote)); + return 1; + break; + case "reply": // Drop-through + case "replyemote": // Drop-through + case "tellemote": // Drop-through + case "tell": // Drop-through + switch(cmd){ + case "reply" : cmd="reply to"; reply=1; break; + case "replyemote" : cmd="reply an emote to"; reply=1; emote=1; break; + case "tell" : break; + case "tellemote" : cmd="tell an emote to"; emote=1; break; + } + if(!args) + return notify_fail("Need a message.\n"); + if(reply){ + a=tells[GET_CAP_NAME(THIS_PLAYER)]["reply"]; + if(!a) return notify_fail("You haven't recieved an incoming tell through "+ + NETWORK_ID+" yet. Can't reply.\n"); + sscanf(a,"%s@%s",a,b); + c=args; + } + else{ + if(sscanf(args,"%s@%s %s",a,b,c)!=3) + return notify_fail("Invalid syntax. "+COMMAND_NAME+" tell name@mud message\n"); + } + if(emote) + c=GET_CAP_NAME(THIS_PLAYER)+"@"+MUDNAME+" "+c; + b=find_mud(b); + if(!b) return notify_fail("MUD isn't known on "+NETWORK_ID+".\n"); + if(!mudinfo[b]["online"]) return notify_fail(NETWORK_ID+"- "+b+" is offline right now.\n"); + IMC2_MSG(sprintf("%s- You %s %s@%s: %s\n",NETWORK_ID,cmd,a,b,c),THIS_PLAYER); + tell_out(THIS_PLAYER,a,b,c,reply,emote); + return 1; + break; + case "listen": + if(!args || !sizeof(args)){ // Listen to all + foreach(args in keys(localchaninfo)){ + if(chan_perm_allowed(THIS_PLAYER,args) && + (member_array(GET_NAME(THIS_PLAYER),localchaninfo[args]["users"])==-1)){ + localchaninfo[args]["users"] += ({ GET_NAME(THIS_PLAYER) }); + IMC2_MSG(NETWORK_ID+"- You are now listening to "+ + args+"\n",THIS_PLAYER); + } + } + IMC2_MSG("Listened to all allowed "+NETWORK_ID+" channels.\n",THIS_PLAYER); + return 1; + } + if(!localchaninfo[args]) return notify_fail("Not a locally configured channel.\n"); + if(!chan_perm_allowed(THIS_PLAYER,args)) + return notify_fail("You don't have permission to use that channel.\n"); + if(member_array(THIS_PLAYER->query("name"),localchaninfo[args]["users"])!=-1) + return notify_fail("You're already listening to that channel.\n"); + localchaninfo[args]["users"] += ({ GET_NAME(THIS_PLAYER) }); + IMC2_MSG(NETWORK_ID+"- You are now listening to "+args+"\n",THIS_PLAYER); + return 1; + break; + case "unlisten": + if(!localchaninfo[args]) return notify_fail("Not a locally configured channel.\n"); + localchaninfo[args]["users"] -= ({ GET_NAME(THIS_PLAYER) }); + IMC2_MSG(NETWORK_ID+"- You are no longer listening to "+args+"\n",THIS_PLAYER); + return 1; + break; + case "whois": + if(!args || !sizeof(args)) return notify_fail("Locate who?\n"); + send_packet(GET_CAP_NAME(THIS_PLAYER),"whois",args,"*", + sprintf("level=%d ",level(THIS_PLAYER))); + IMC2_MSG("Sent a request on "+NETWORK_ID+" looking for "+args+"\n",THIS_PLAYER); + return 1; + break; + case "backlog": + if(!localchaninfo[args]) return notify_fail("Not a locally configured channel.\n"); + if(!chan_perm_allowed(THIS_PLAYER,args)) + return notify_fail("You need permission to use the "+args+" channel.\n"); + if(!chan_listening(THIS_PLAYER,args)) + return notify_fail("You are not listening to the "+args+" channel.\n"); + IMC2_MSG(sprintf("Backlog of channel %s on %s:\n%s",args,NETWORK_ID, + implode(localchaninfo[args]["backlog"],"\n")+"\n"),THIS_PLAYER); + return 1; + break; + case "tells": + a=GET_CAP_NAME(THIS_PLAYER); + if(!tells[a] || !tells[a]["backlog"]) + return notify_fail("You have received no tells on the "+NETWORK_ID+" network yet.\n"); + IMC2_MSG(sprintf("Tell backlog on %s:\n%s",NETWORK_ID, + implode(tells[a]["backlog"],"")+"\n"),THIS_PLAYER); + return 1; + break; + case "configchan": + if(!ADMIN(THIS_PLAYER)) return notify_fail("You aren't allowed to use configchan.\n"); + if(sscanf(args,"%s %s %d",a,b,x)!=3) + return notify_fail("Syntax: "+COMMAND_NAME+" configchan local_name hub_name level_number\n"); + if(member_array(b,keys(chaninfo))==-1) + return notify_fail("The "+b+" channel isn't on the network.\n"); + c=localize_channel(b); + if(c) return notify_fail("That channel is already configured as "+c+" locally.\n"); + localchaninfo[a]=([ "perm":x, "name":b, "users":({ }), "backlog":({ }) ]); + IMC2_MSG("Added the "+a+" channel for "+chan_perm_desc(x)+ + " to use, which is "+b+" on the network.\n",THIS_PLAYER); + return 1; + break; + case "unconfigchan": + if(!ADMIN(THIS_PLAYER)) return notify_fail("You aren't allowed to use unconfigchan.\n"); + map_delete(localchaninfo,args); + IMC2_MSG("Got rid of "+args+" channel.\n",THIS_PLAYER); + return 1; + break; + case "chancmd": + if(!ADMIN(THIS_PLAYER)) return notify_fail("You aren't allowed to use chancmd.\n"); + if(!args || (sscanf(args,"%s:%s %s",a,b,c)!=3)) + return notify_fail("Syntax: "+COMMAND_NAME+" chancmd hub:channel command\n"); + if(!chaninfo[a+":"+b]) write(a+" is not listed as a channel, sending command anyway...\n"); + send_packet(GET_CAP_NAME(THIS_PLAYER),"ice-cmd","IMC",b, + sprintf("channel=%s command=\"%s\"", + a+":"+b,escape(c))); + IMC2_MSG(sprintf("%s- Sent a command for the %s channel to %s\n",NETWORK_ID, + a,GET_CAP_NAME(THIS_PLAYER),b),THIS_PLAYER); + return 1; + break; + case "chanperms": + output = MUDNAME+" will handle the following levels for channels:\n"; + output += sprintf("%-10s %-10s\n", "Number", "Description"); + for(x=2;x>0;x--){ + output = sprintf("%-10d %-10s\n", x, chan_perm_desc(x)); + } + IMC2_MSG(output,THIS_PLAYER); + return 1; + case "help": // drop through to default + default: + IMC2_MSG(main_help(),THIS_PLAYER); + return 1; + break; + } + } + + string main_help(){ + return sprintf(@EndText +IMC2 system by Tim, set up for %s. +To use this, type the command '%s' followed by one of the following: + chans - lists the channels that this MUD uses + allchans - lists all the channels on this network + chan (channel) (message) - talks on a channel + chanemote (channel) (message) - emotes on a channel + chansocial (channel) (message) - does a social on a channel + chanwho (channel) (mud) - checks who is listening to a channel + backlog (channel) - reads last %d messages on the channel + listen (channel) - listen to a channel + unlisten (channel) - stop listening to a channel + info (name) - lists information about a MUD + list - lists the MUDs on this network + beep (name)@(mud) - send a beep through the network + tell (name)@(mud) (message) - send a tell through the network + tellemote (name)@(mud) (message) - send an emote through the network + tells - shows your last %d tells + finger (name)@(mud) - send a finger request for information about name@mud + reply (message) - reply to the last incoming tell you received + replyemote (message) - reply with an emote to the last incoming tell you received + ping (mud) - pings a mud + setup - shows information about this IMC2 network + help - see this help message +Admin commands: + configchan (local_name) (remote_name) (level_number) - configures a channel locally + unconfigchan (local_name) - removes a locally configured channel + chancmd (channel) (command) - for remote channel administration + chanperms - lists the permission levels that are possible for configchan +EndText, NETWORK_ID,COMMAND_NAME,BACKLOG_SIZE,BACKLOG_SIZE); + } + + string html(string str){ + string mud, *muds; + string a,b; + int x=0,y=0; + string output=""; + if(!str) str=""; + sscanf(str,"%s_%s",a,b); + if(!a) a=str; + switch(a){ + case "list": + muds = sort_array(keys(mudinfo),1); + if (!sizeof(mudinfo)){ + return ("There are no muds on the "+NETWORK_ID+" network!\n"); + } + else{ + output="<tr><td><b>Status</b></td><td><b>Name</b></td><td><b>Network</b></td><td><b>IMC2 Version</b></td></tr>\n"; + foreach (mud in muds){ + if(mudinfo[mud]["online"]) x++; else y++; + output += sprintf("<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n", + (mudinfo[mud]["online"] ? "UP" : "DOWN"), + mudinfo[mud]["url"] ? "<a href=\""+ + ((mudinfo[mud]["url"][0..6]!="http://") ? "http://"+mudinfo[mud]["url"] : mudinfo[mud]["url"]) + +"\">"+mud+"</a>" : mud, + mudinfo[mud]["networkname"], + mudinfo[mud]["versionid"]); + } + } + return sprintf("<B>%d of %d MUDs are on %s.</B.\n<BR><table>%s</table>", + x,x+y,NETWORK_ID,output); + break; + case "backlog": + if(b && localchaninfo[b] && (localchaninfo[b]["perm"]==BACKLOG_WEB_LEVEL)){ + // Show backlog for channel. + return b+" channel backlog:\n"+implode(localchaninfo[b]["backlog"],"\n"); + } + // List the channels + output = NETWORK_ID+" channels on "+MUDNAME+":\n"; + foreach(b in sort_array(keys(localchaninfo),1)){ + if(localchaninfo[b]["perm"]==BACKLOG_WEB_LEVEL) // is public + output += "<a href=\""+HTML_LOCATION+"backlog_"+b+"\">"; + output += b; + output += " - "+chan_perm_desc(localchaninfo[b]["perm"]); + if(localchaninfo[b]["perm"]==BACKLOG_WEB_LEVEL) // is public + output += " - on web</a>"; + else + output += " - not on web"; + output += "\n"; + } + return output; + break; + default: + return MUDNAME+" uses Tim's LPC IMC2 system to connect to the "+ + NETWORK_ID+" network.\n"+ + "(version:"+VERSION+")\n"+ + "From here, you can look at the <a href=\""+HTML_LOCATION+"list\">list of muds</a>,\n"+ + "view the <a href=\""+HTML_LOCATION+"backlog\">public channel backlogs</a>,\n"+ + "or go to the main <a href=\""+URL+"\">"+MUDNAME+"</a> web site.\n"; + break; + } + } + + int clean_up(){ return 0; } + + + void forget_user(string str){ map_delete(tells,str); } diff --git a/lib/secure/daemon/inet.c b/lib/secure/daemon/inet.c new file mode 100644 index 0000000..f8eabc4 --- /dev/null +++ b/lib/secure/daemon/inet.c @@ -0,0 +1,193 @@ +/* /secure/daemon/inet.c + * From the Dead Souls Mud Library + * A daemon to handle the start and stop of inet servers + * Created by Descartes of Borg 961219 + * Version: @(#) inet.c 1.1@(#) + * Last modified: 96/12/19 + */ + +#include <lib.h> +#include <save.h> + +inherit LIB_DAEMON; + +class service { + int PortOffset; + string SocketClass; + int SocketType; +} + +private static mapping Servers = ([]); +private mapping Services = ([]); +mapping BlockedIps = ([]); + +int eventStartServer(string svc); +int eventStopServer(string svc); + +void validate(){ + if(!master()->valid_apply(({ "SECURE", "ASSIST" }))){ + string offender = identify(previous_object(-1)); + debug("INET_D SECURITY VIOLATION: "+offender+" ",get_stack(),"red"); + log_file("security", "\n"+timestamp()+" INET_D breach: "+offender+" "+get_stack()); + error("INET_D SECURITY VIOLATION: "+offender+" "+get_stack()); + } +} + +void eventBlockIp(string ip){ + log_file("security", "\n"+timestamp()+" INET_D ip block: "+ip+"\n"); + if(ip != "*.*" && member_array(ip, keys(BlockedIps)) == -1){ + BlockedIps[ip] = time(); + eventSave(); + } +} + +string *GetBlockedIps(){ + return keys(BlockedIps); +} + +mapping eventClearBlockedIps(){ + validate(); + BlockedIps = ([]); + log_file("security", "\n"+timestamp()+" INET_D all IP's unblocked.\n"); + eventSave(); + return copy(BlockedIps); +} + +mapping GetServers() { + return copy(Servers); +} + +int GetServer(string str){ + if(Servers[str]) return 1; + return 0; +} + +int GetService(string str){ + if(Services[str]) return 1; + return 0; +} + +mapping GetServices() { + return copy(Services); +} + + +int AddService(string name, int port_offset, string socket_class, int type) { + class service s = new(class service); + + if( !master()->valid_apply(({})) ) { + return 0; + } + s->PortOffset = port_offset; + s->SocketClass = socket_class; + s->SocketType = type; + Services[name] = s; + if( !eventSave() ) { + return 0; + } + Servers[name] = new(LIB_SERVER, query_host_port()+port_offset, type, + socket_class); + return 1; +} + +int RemoveService(string name) { + if( !master()->valid_apply() ) { + return 0; + } + if( Servers[name] ) { + Servers[name]->eventShutdown(); + } + map_delete(Servers, name); + map_delete(Services, name); + return eventSave(); +} + +varargs int eventRestartServer(string svc, int forced) { + if( !eventStopServer(svc) ) { + if(!forced) return 0; + } + if( !eventStartServer(svc) ) { + if(!forced) return 0; + } + return 1; +} + +int eventStartServer(string svc) { + class service s = Services[svc]; + object ob = Servers[svc]; + + if( !master()->valid_apply(({})) ) { + return 0; + } + if( ob ) { + return 0; + } + if( !s ) { + return 0; + } + ob = new(LIB_SERVER, query_host_port()+s->PortOffset, s->SocketType, + s->SocketClass); + if( ob ) { + Servers[svc] = ob; + return 1; + } + else { + return 0; + } +} + +int eventStopServer(string svc) { + object ob = Servers[svc]; + + if( !master()->valid_apply(({})) ) { + return 0; + } + if( !ob ) { + return 0; + } + ob->eventShutdown(); + map_delete(Servers, svc); + if( ob ) { + return 0; + } + else { + return 1; + } +} + +static void create() { + SetSaveFile(SAVE_INET); + daemon::create(); + if(!BlockedIps) BlockedIps = ([]); + SetNoClean(1); + set_heart_beat(10); + foreach(string svc, class service s in Services) { + Servers[svc] = new(LIB_SERVER, query_host_port() + s->PortOffset, + s->SocketType, s->SocketClass); + } +} + +int eventDestruct(){ + object *servers = filter(objects(), (: base_name($1) == LIB_SERVER :) ); + eventSave(); + foreach(object server in servers){ + if(server && clonep(server)) server->eventDestruct(); + if(server && clonep(server)) destruct(server); + } + return daemon::eventDestruct(); +} + +void heart_beat(){ + validate(); + foreach(mixed key, mixed val in BlockedIps){ + if((time() - val) > 60) map_delete(BlockedIps, key); + } +} + +int GetServicePort(string str){ + int ret; + int offset; + if(Services[str]) offset = Services[str]->PortOffset; + ret = query_host_port() + offset; + return ret; +} diff --git a/lib/secure/daemon/instances.c b/lib/secure/daemon/instances.c new file mode 100644 index 0000000..a235ab7 --- /dev/null +++ b/lib/secure/daemon/instances.c @@ -0,0 +1,678 @@ +#include <lib.h> +#include <logs.h> +#include <news.h> +#include <save.h> +#include <daemons.h> +#include <commands.h> +#include <message_class.h> +#include <talk_type.h> +#include <secrets.h> +#include <socket.h> +#include NETWORK_H + +inherit LIB_DAEMON; + +mapping InstData = ([]); +mapping sockets = ([]); +static string SaveFile; +string Name, Myname; +static int verbose = 0; +static private int icp_socket; + +varargs static void yenta(string arg, string clr){ + if(verbose){ + debug_message(arg); + } + unguarded( (: log_file(LOG_ICP, timestamp() + + " " + strip_colours($(arg)) + "\n") :) ); +} + +varargs static int validate(int i, int soft){ + if(!undefinedp(i)){ + if(!socket_status(i) || !socket_status(i)[5]){ + yenta(mud_name()+" stack: "+get_stack()); + yenta("%B_BLACK%^BAD SOCKET ALERT. fd "+i+": "+ + identify(socket_status(i))+"\n","red"); + if(!soft) error("Bad socket, fd "+i); + return 0; + } + } + if(previous_object() != this_object() && !(master()->valid_apply(({ "ASSIST" }))) ){ + yenta("SECURITY ALERT: validation failure in INSTANCES_D.\n","red"); + if(soft) return 0; + error("Illegal attempt to access router socket daemon: "+get_stack()+ + " "+identify(previous_object(-1))); + } + return 1; +} + +static void create() { + daemon::create(); + Myname = "global"; + if(!sizeof(InstData)) InstData = ([]); + if(!sizeof(sockets)) sockets = ([]); + SaveFile = save_file(SAVE_INSTANCES); + SetSaveFile(SaveFile); + SetNoClean(1); + if(unguarded( (: file_exists(SaveFile) :) )){ + RestoreObject(SaveFile); + } + if(ENABLE_INSTANCES){ + debug_message("\nNOTE: This mud is a non-global instance.\n"); + } + call_out("Setup", 0); + set_heart_beat(10); +} + +string GetMyInstanceName(){ + return Myname; +} + +mixed InstCreate(string name, string addy, int port){ + object prev = previous_object(); + string newglobal, newconf, pfile = base_name(this_player()); + if(base_name(prev) != CMD_INSTCONFIG) return 0; + if(ENABLE_INSTANCES){ + return "Only the global instance can create instances."; + } + if(InstData[name]) return name + " already exists."; + foreach(mixed key, mixed val in InstData){ + if(val && val["port"] == port){ + return key + " is already on port "+port; + } + } + InstData[name] = ([ "addy" : addy, "port" : port ]); + SaveObject(SaveFile, 1); + cp(NETWORK_H, "/secure/include/network."+port+".h"); + cp(ROOMS_H, "/secure/include/rooms."+port+".h"); + cp(SECRETS_H, "/secure/include/secrets."+port+".h"); + catch( cp(SAVE_IMC2+".o", SAVE_IMC2 + "." + port + ".o") ); + catch( cp(SAVE_MAP+".o", SAVE_MAP + "." + port + ".o") ); + catch( cp(SAVE_ROOMS+".o", SAVE_ROOMS + "." + port + ".o") ); + catch( cp(SAVE_RACES+".o", SAVE_RACES + "." + port + ".o") ); + catch( cp(SAVE_CLASSES+".o", SAVE_CLASSES + "." + port + ".o") ); + catch( cp(SAVE_SOUL+".o", SAVE_SOUL + "." + port + ".o") ); + catch( cp(SAVE_ECONOMY+".o", SAVE_ECONOMY + "." + port + ".o") ); + catch( cp(SAVE_EVENTS+".o", SAVE_EVENTS + "." + port + ".o") ); + catch( cp(NEWS_WELCOME, NEWS_WELCOME + "." +port) ); + catch( cp(pfile+".o", pfile+"."+port+".o") ); + newglobal = read_file("/secure/cfg/global_template.cfg"); + if(newglobal){ + newglobal = replace_string(newglobal, "TEMPLATE_CONFIG", + "/secure/include/config."+port+".h"); + newglobal = replace_string(newglobal, "TEMPLATE_NETWORK", + "/secure/include/network."+port+".h"); + newglobal = replace_string(newglobal, "TEMPLATE_ROOMS", + "/secure/include/rooms."+port+".h"); + newglobal = replace_string(newglobal, "TEMPLATE_SECRETS", + "/secure/include/secrets."+port+".h"); + } + write_file("/secure/include/global."+port+".h", newglobal, 1); + newconf = read_file(CONFIG_H); + if(newconf){ + string *confarr = explode(newconf, "\n"); + newconf = ""; + foreach(string line in confarr){ + if(!strsrch(line, "#define DISABLE_INTERMUD")){ + line = "#define DISABLE_INTERMUD 1"; + } + if(!strsrch(line, "#define DISABLE_IMC2")){ + line = "#define DISABLE_IMC2 1"; + } + if(!strsrch(line, "#define ENABLE_INSTANCES")){ + line = "#define ENABLE_INSTANCES 1"; + } + if(!strsrch(line, "#define LOG_REMOTE_CHANS")){ + line = "#define LOG_REMOTE_CHANS 0"; + } + if(!strsrch(line, "#define LOG_LOCAL_CHANS")){ + line = "#define LOG_LOCAL_CHANS 0"; + } + if(!strsrch(line, "#define AUTO_WIZ")){ + line = "#define AUTO_WIZ 0"; + } + newconf += line + "\n"; + } + write_file("/secure/include/config."+port+".h", newconf, 1); + } + if(true()){ + string newcfg = read_file("/secure/cfg/instance_template.cfg"); + string oldcfg = read_file("/secure/cfg/mudos.cfg"); + if(newcfg && oldcfg){ + string mlib, mbin; + sscanf(oldcfg, "%*smudlib directory :%s\n", mlib); + sscanf(oldcfg, "%*sbinary directory :%s\n", mbin); + newcfg = replace_string(newcfg, "TEMPLATE_NAME", name); + newcfg = replace_string(newcfg, "TEMPLATE_PORT", itoa(port)); + if(mlib) mlib = trim(mlib); + if(mbin) mbin = trim(mbin); + newcfg = replace_string(newcfg, "TEMPLATE_LIB", mlib); + newcfg = replace_string(newcfg, "TEMPLATE_BIN", mbin); + newcfg = replace_string(newcfg, "TEMPLATE_GLOBAL", + "global."+port+".h"); + write_file("/secure/cfg/mudos."+port+".cfg", newcfg, 1); + write_file("/secure/cfg/mudos."+port+".win32", newcfg, 1); + } + newcfg = read_file("/secure/cfg/runmud_template.bat"); + if(newcfg && query_windows()){ + newcfg = replace_string(newcfg, "TEMPLATE_MUDOS", + "mudos."+port+".win32"); + write_file("/secure/cfg/runmud_"+port+".bat", newcfg, 1); + } + } + SaveObject(SaveFile, 1); + return 1; +} + +mixed InstDelete(mixed arg){ + object prev = previous_object(); + mixed which; + if(base_name(prev) != CMD_INSTCONFIG) return 0; + if(ENABLE_INSTANCES){ + return "Only the global instance can delete instances."; + } + if(InstData[arg]) which = arg; + else { + if(stringp(arg)) which = atoi(arg); + else if(intp(arg)) which = arg; + foreach(mixed key, mixed val in InstData){ + if(val && val["port"] == which){ + which = key; + break; + } + } + } + + if(which && InstData[which]){ + mixed port = itoa(InstData[which]["port"]); + rm("/secure/include/config."+port+".h"); + rm("/secure/include/global."+port+".h"); + rm("/secure/include/rooms."+port+".h"); + rm("/secure/include/network."+port+".h"); + rm("/secure/include/secrets."+port+".h"); + rm("/secure/cfg/mudos."+port+".cfg"); + rm(NEWS_WELCOME + "." + port); + this_object()->ProcessClose(which); + InstData[which] = 0; + SaveObject(SaveFile, 1); + return 1; + } + else return "No such instance exists."; +} + +string array GetInstances(){ + return filter(keys(InstData), (: $1 :)); +} + +mapping GetInstData(){ + mapping ret = ([]); + foreach(mixed key, mixed val in InstData){ + if(key) ret[key] = copy(val); + } + return ret; +} + +static void SendData(mixed fd, mixed data){ + int array targets = ({}); + if(stringp(fd) && !undefinedp(InstData[fd])) fd = InstData[fd]["fd"]; + if(fd == -2) return; + if(fd == -1){ + foreach(string name in keys(InstData)){ + if(name && InstData[name]) targets += ({ InstData[name]["fd"] }); + } + } + else targets = ({ fd }); + targets = distinct_array(targets); + foreach(int target in targets){ + this_object()->write_data(target, data); + } +} + +varargs void SendWhoUpdate(string name, int status){ + mapping data = ([ "status" : status, "state" : 0 ]); + object ob = find_player(name); + if(ob && !ob->GetInvis()){ + string title = ob->GetShort(); + if(sizeof(strip_colours(title)) > 50){ + title = capitalize(name)+" the Long-Titled."; + } + data["title"] = title; + data["level"] = ob->GetLevel(); + data["arch"] = archp(ob); + data["creator"] = creatorp(ob); + data["builder"] = builderp(ob); + if(!interactive(ob)) data["status"] = -1; + else { + data["status"] = 1; + if(query_idle(ob)>240){ + data["state"] = "(%^YELLOW%^idle%^RESET%^)"; + } + if(ob->GetSleeping() > 0){ + data["state"] = "(%^BLUE%^sleeping%^RESET%^)"; + } + if(ob->GetProperty("afk")){ + data["state"] = "(%^MAGENTA%^afk%^RESET%^)"; + } + if(ob->GetInCombat()){ + data["state"] = "(%^RED%^combat%^RESET%^)"; + } + if(in_edit(ob) || ob->GetCedmode()){ + data["state"] = "(%^CYAN%^edit%^RESET%^)"; + } + } + } + else data["status"] = 0; + SendData(-1, ({ "who-update", 5, Myname, name, 0, 0, data }) ); +} + +void UpdateInvis(int i){ + object ob = previous_object(); + string name; + if(!ob || !interactive(ob)) return; + name = ob->GetKeyName(); + if(!sizeof(name)) return; + call_out("SendWhoUpdate", 0, name); +} + +varargs void SendTell(string who, string msg, string interwho){ + object prev, ob = this_player(); + string sender, vname; + if(interwho){ + ob = previous_object(); + if(base_name(ob) != SERVICES_D && base_name(ob) != IMC2_D) return; + sender = interwho; + vname = interwho; + } + if(!ob || ob->GetForced()) return; + if(!sender) sender = ob->GetKeyName(); + if(!vname) vname = ob->GetName(); + SendData(-1, ({ "tell", 5, Myname, sender, 0, who, vname, msg }) ); +} + +static void ProcessStartup(mixed data, string addy, int port, int fd){ + string name = data[2]; + InstData[name] = ([]); + InstData[name]["addy"] = addy; + InstData[name]["port"] = port; + InstData[name]["fd"] = fd; + InstData[name]["online"] = 1; + InstData[name]["users"] = ([]); + if(sizeof(data) > 8) InstData[name]["mudname"] = data[8]; + if(sizeof(data[7])){ + foreach(mixed foo in data[7]){ + if(stringp(foo)) InstData[name]["users"][foo] = 1; + } + } + if(ENABLE_INSTANCES){ + Myname = data[4]; + call_out("SendStartup", 1, fd); + } +} + +static void ProcessClose(string name){ + if(!sizeof(InstData[name])) return; + if(InstData[name]["fd"] > -1){ + this_object()->close_connection(InstData[name]["fd"]); + } + InstData[name]["fd"] = -1; + InstData[name]["online"] = 0; +} + +static void ProcessWhoUpdate(mixed data){ + if(!sizeof(InstData[data[2]])) return; + if(!sizeof(InstData[data[2]]["users"])){ + InstData[data[2]]["users"] = ([]); + } + InstData[data[2]]["users"][data[3]] = data[6]; +} + +static void ProcessTell(mixed data){ + object who = find_player(data[5]); + string ret; + if(!who) return; + ret = "%^BOLD%^RED%^"+capitalize(data[3]) + + " tells you:%^RESET%^ " + data[7]; + who->eventPrint(ret, MSG_CONV); + who->SetProperty("reply", data[3]); + who->SetProperty("reply_time", time()); + who->eventTellHist(ret); +} + +static void ProcessShout(mixed data){ + Name = capitalize(data[3]); + users()->eventHearTalk(this_object(), 0, TALK_WORLD, + "shout", data[6][0], data[6][1]); +} + +string GetName(){ + return Name; +} + +static void ReceiveICPData(mixed data, string addy, int port, int fd){ + string name; + if(!arrayp(data)){ + return; + } + if(sizeof(data) < 7){ + return; + } + name = data[2]; + if(data[0] != "startup-req"){ + if( InstData[name] && InstData[name]["online"]){ + if(InstData[name]["addy"] != addy){ + return; + } + if(InstData[name]["port"] != port ){ + return; + } + if(!undefinedp(InstData[name]["fd"]) && + InstData[name]["fd"] != fd){ + return; + } + } + else{ + return; + } + } + switch(data[0]){ + case "startup-req" : + if(data[6] != INSTANCE_PW) return; + else ProcessStartup(data, addy, port, fd); + break; + case "channel-p" : + CHAT_D->eventSendChannel(data[6]...); + break; + case "who-update": + ProcessWhoUpdate(data); + break; + case "tell": + ProcessTell(data); + break; + case "shout": + ProcessShout(data); + break; + case "close-req" : + ProcessClose(name); + break; + + default : + break; + } + if(undefinedp(InstData[name]["fd"])) InstData[name]["fd"] = fd; +} + +string *GetRemoteUsers(string inst){ + string *ret = ({}); + if(!InstData || !InstData[inst] || !InstData[inst]["users"]) return ret; + else ret = filter(keys(InstData[inst]["users"]), + (: mapp(InstData[$(inst)]["users"][$1]) + && InstData[$(inst)]["users"][$1]["status"] > 0 :) ); + return ret; +} + +void eventSendChannel(string name, string ch, string msg, int emote, + string target, string targmsg){ + mixed packet = ({ name, ch, msg, emote, target, targmsg }); + if(base_name(previous_object()) != CHAT_D) return; + if(ch == "muds") return; + SendData(-1, ({ "channel-p", 5, Myname, 0, 0, 0, packet }) ); +} + +void eventSendShout(string msg, string lang){ + string name; + mixed packet = ({ msg, lang }); + object ob = previous_object(); + if(!ob || !interactive(ob) || ob->GetForced()) return; + name = ob->GetName(); + SendData(-1, ({ "shout", 5, Myname, name, 0, 0, packet }) ); +} + +static void eventWrite(mixed *packet){ + SendData(packet[4], packet); +} + +static void close_connection(int fd){ + int sockerr; + mixed *sockstat = ({}); + validate(); + if(fd < 0) return; + sockstat = socket_status(fd); + if(!sockstat || !sizeof(sockstat)) return; + if(sockstat[1] == "LISTEN") return; + yenta("About to try closing socket: "+fd, "white"); + yenta("Pre-closing state: "+sockstat[1],"yellow"); + sockerr = socket_close(fd); + yenta("closing socket:"+fd,"white"); + yenta("closing sockerr:"+sockerr,"white"); + yenta("Post-closing state: "+socket_status(fd)[1],"yellow"); + yenta("---\n","white"); +} + +static void close_callback(int fd){ + yenta("close_callback: fd="+fd+"\n"); + if(fd < 0 || !sizeof(socket_status(fd))) return; + if(socket_status(fd)[1] == "LISTEN") return; + if(socket_status(fd)[1] == "DATA_XFER") return; + close_connection(fd); +} + +static void listen_callback(int fd){ + mixed fdstat,newfd; + validate(); + + if ((newfd = socket_accept(fd, "read_callback", "write_callback")) < 0) { + return; + } + else { + yenta("socket_accepted: "+newfd+ + ", "+identify(socket_status(newfd))+"\n","white"); + } +} + +static void read_callback(int fd, mixed info){ + mixed sstat; + string addy; + int port; + validate(fd); + sstat = socket_status(fd); + if(sizeof(sstat) > 3){ + string a, b, c, d; + int p, i; + i = sscanf(sstat[4],"%s.%s.%s.%s.%d",a,b,c,d,p); + if(i > 4){ + port = (p - OFFSET_ICP); + addy = a+"."+b+"."+c+"."+d; + } + } + if(bufferp(info)){ + yenta("fd "+fd+" is sending me buffer data!"); + yenta("As far as I can tell, it is: "+identify(read_buffer(info)),"blue"); + } + else yenta("%^WHITE%^data from fd "+fd+":\n%^BLUE%^"+identify(info)); + ReceiveICPData(info, addy, port, fd); +} + +static void write_callback(int fd){ + validate(fd); + if(!sockets[fd]) return; + if(sockets[fd]["write_status"] == EEALREADY) { + this_object()->write_data(fd, sockets[fd]["pending"]); + sockets[fd]["pending"] = 0; + } + else { + sockets[fd]["write_status"] = EESUCCESS; + } +} + +static void write_data_retry(int fd, mixed data, int counter){ + int rc; + int maxtry = 20; + if(fd < 0) return; + validate(fd); + if (counter == maxtry) { + return; + } + rc = socket_write(fd, data); + if(!sockets) sockets = ([]); + if(!sockets[fd]){ + sockets[fd]=([]); + } + sockets[fd]["write_status"] = rc; + switch (rc) { + case EESUCCESS: + break; + case EEALREADY: + sockets[fd]["pending"] = data; + break; + case EECALLBACK: + break; + case EESECURITY: + break; + case EEFDRANGE: + break; + case EENOTCONN: + break; + case EEBADF: + break; + default: + if (counter < maxtry) { + if(counter < 2 || counter > maxtry-1) + call_out( (: write_data_retry :), 2 , fd, data, counter + 1 ); + return; + } + } +} + +static int write_data(int fd, mixed data){ + int ret; + if(fd < 0) return; + if(!validate(fd, 1)) return 0; + write_data_retry(fd, data, 0); + return ret; +} + +static void Setup(){ + //yenta("icp setup got called"); + if ((icp_socket = socket_create(MUD, "read_callback", "close_callback")) < 0){ + log_file(LOG_ICP, "setup: Failed to create socket.\n"); + return; + } + if (socket_bind(icp_socket, PORT_ICP) < 0) { + socket_close(icp_socket); + log_file(LOG_ICP, "setup: Failed to bind socket to port.\n"); + return; + } + if (socket_listen(icp_socket, "listen_callback") < 0) { + socket_close(icp_socket); + log_file(LOG_ICP, "setup: Failed to listen to socket.\n"); + return; + } + log_file(LOG_ICP, "icp setup ended\n"); +} + +int eventCreateSocket(string host, int port){ + int x, ret; + + x = socket_create(MUD, "read_callback", "close_callback"); + if( x < 0 ) { + yenta("Error in socket_create(): "+socket_error(x)); + return 0; + } + ret = x; + x = socket_bind(x, 0); + if( x != EESUCCESS ) { + socket_close(ret); + log_file(LOG_ICP, "Error in socket_bind(): "+x); + return 0; + } + x = socket_connect(ret, host + " " + (port + OFFSET_ICP), + "read_callback", "close_callback"); + if( x != EESUCCESS ) { + socket_close(ret); + yenta("Error in socket_connect(): "+socket_error(x)); + return x; + } + return ret; +} + +int DoConnect(string ip, int port, string myname, string name){ + int sstat; + validate(); + sstat = eventCreateSocket(ip, port); + if( sstat < 0 ) return; + if(!sockets) sockets = ([]); + sockets[sstat] = ([]); + return sstat; +} + +static void InstConnect(string wat){ + int ret = DoConnect(InstData[wat]["addy"], + InstData[wat]["port"],"global",wat); + if(ret > -1){ + InstData[wat]["fd"] = ret; + call_out("SendStartup", 1, ret); + } + else{ + yenta("InstConnect FAIL", "red"); + } +} + +static void SendStartup(int fd){ + string name; + foreach(mixed key, mixed val in InstData){ + if(key && val["fd"] == fd){ + name = key; + break; + } + } + SendData(fd, + ({"startup-req", 5, Myname, 0, name, 0, INSTANCE_PW, + local_users(), mud_name()})); + foreach(string user in local_users()){ + call_out("SendWhoUpdate", 0, user, 1); + } +} + +static void CheckConnections(){ + mixed socks = socket_names(); + mapping conns = ([]); + if(ENABLE_INSTANCES){ + return; + } + if(!sizeof(keys(InstData))){ + return; + } + socks = filter(socks, (: $1[5] == this_object() :) ); + foreach(mixed arr in socks){ + if(sizeof(arr) > 4){ + string a, b, c, d; + int p, i; + i = sscanf(arr[4],"%s.%s.%s.%s.%d",a,b,c,d,p); + if(i < 5) continue; + foreach(mixed key, mixed val in InstData){ + if(key && mapp(val) && val["port"] == (p - OFFSET_ICP)){ + InstData[key]["fd"] = -2; + if(val["addy"] == a+"."+b+"."+c+"."+d){ + InstData[key]["fd"] = arr[0]; + conns[key] = copy(InstData[key]); + } + else { + } + } + } + } + } + foreach(string foo in keys(InstData)){ + if(!foo || !InstData[foo]) continue; + InstData[foo]["online"] = 0; + if(member_array(foo, keys(conns)) == -1 + || InstData[foo]["fd"] == -1){ + InstConnect(foo); + } + else InstData[foo]["online"] = 1; + } +} + +void heart_beat(){ + if(!ENABLE_INSTANCES) CheckConnections(); +} diff --git a/lib/secure/daemon/letters.c b/lib/secure/daemon/letters.c new file mode 100644 index 0000000..86d64dc --- /dev/null +++ b/lib/secure/daemon/letters.c @@ -0,0 +1,210 @@ +/* /daemon/postal/letters.c + * from Dead Souls + * letter management daemon + * created by Descartes of Borg 940503 + * based upon the original letter.c created by Descartes 940130 + */ + +#include <lib.h> +#include <dirs.h> +#include <daemons.h> +#include <objects.h> +#include "letters.h" + +inherit LIB_DAEMON; + +private string __Letter; +private mapping __Folders; +private string *__Undeleted; +static private string __LetterId; +static private mapping __LettersDir, __PostalDir; +static private mixed *__LetterPtr, *__PostalPtr; + +void create() { + string *tmp; + int i; + + daemon::create(); + SetNoClean(1); + __Letter = ""; + __Folders = ([]); + __Undeleted = ({}); + __LettersDir = ([]); + __PostalDir = ([]); + __LetterId = 0; + __LetterPtr = ({ 0, 0}); + for(i=0; i<10; i++) { + if(unguarded((: file_size, DIR_LETTERS+"/"+i :)) == -2) + __LettersDir[i] = unguarded((: get_dir, DIR_LETTERS+"/"+i+"/", 0 :)); + } + i = sizeof(tmp = unguarded((: get_dir, DIR_POSTAL+"/", 0 :))); + if(i) __PostalPtr = ({ tmp[0], 0 }); + while(i--) { + if(unguarded((: file_size, DIR_POSTAL+"/"+tmp[i] :)) == -2) + __PostalDir[tmp[i]] = unguarded((: get_dir, DIR_POSTAL+"/"+tmp[i]+"/", 0 :)); + } +} + +static private int valid_access() { + switch(base_name(previous_object(0))) { + case OBJ_POST: case LETTERS_D: case FOLDERS_D: + case LOCALPOST_D: case REMOTEPOST_D: case OPTIONS_D: + return 1; + default: return 0; + } +} + +string create_letter(string str) { + int tmp; + string id, dir; + + if(!valid_access()) return ""; + id = sprintf("%d", tmp = time()); + dir = DIR_LETTERS+"/"+(tmp%10); + if(unguarded((: file_size, dir+"/" :)) != -2) unguarded((: mkdir, dir :)); + while(unguarded((: file_size, save_file(dir+"/"+id) :)) != -1) + id = sprintf("%d", tmp += 10); + __LetterId = id; + __Letter = str; + __Folders = ([]); + save_letter(); + return id; +} + +static private void save_letter() { + string file; + int x; + + x = strlen(__LetterId)-1; + file = sprintf("%s/%s/%s", DIR_LETTERS,__LetterId[x..x],__LetterId); + SaveObject(file); +} + +static private int restore_letter(string id) { + string dir; + int x; + + if(id == __LetterId) return 1; + x = strlen(id) - 1; + dir = DIR_LETTERS+"/"+id[x..x]; + if(!unguarded((: file_exists, save_file(dir+"/"+id) :))) { + return 0; + } + RestoreObject(dir+"/"+id); + __LetterId = id; + if(__Undeleted) { + x = sizeof(__Undeleted); + __Folders = ([]); + while(x--) __Folders[__Undeleted[x]] = ({ "new" }); + __Undeleted = 0; + save_letter(); + } + return 1; +} + +string query_letter(string id) { + string base; + + if((base = base_name(previous_object(0))) != OBJ_POST && + base != FOLDERS_D) return "Illegal access."; + if(!restore_letter(id)) return "Invalid message.\n"; + return __Letter; +} + +void delete_folder(string who, string folder, string id) { + string *tmp; + string file; + int i; + + if(!valid_access()) return; + if(!restore_letter(id)) return; + if(!__Folders[who]) return; + __Folders[who] -= ({ folder }); + if(!sizeof(__Folders[who])) map_delete(__Folders, who); + save_letter(); + i = sizeof(tmp = keys(__Folders)); + while(i--) { + file = save_file(DIR_POSTAL+"/"+tmp[i][0..0]+"/"+tmp[i]+"/postalrc"); + if(!user_exists(tmp[i])) { + FOLDERS_D->delete_user(tmp[i]); + restore_letter(id); + } + else if(!unguarded((: file_exists, file :))) { + map_delete(__Folders, tmp[i]); + save_letter(); + } + } + if(!sizeof(keys(__Folders))) { + file = save_file(DIR_LETTERS+"/"+id[strlen(id)-1..strlen(id)-1]+ + "/"+id); + unguarded((: rm, file :)); + } +} + +void add_folder(string who, string folder, string id) { + if(!valid_access()) return; + if(!restore_letter(id)) return; + if(!__Folders[who]) __Folders[who] = ({ folder }); + else __Folders[who] += ({ folder }); + save_letter(); +} + +static void manage_letters() { + string str, ext, file; + string *tmp; + int x, i; + + if(!(x = sizeof(keys(__LettersDir)))) return; + if(__LetterPtr[1] >= sizeof(__LettersDir[__LetterPtr[0]])) { + if(++__LetterPtr[0] >= x) __LetterPtr = ({ 0, 0 }); + else __LetterPtr[1] = 0; + } + sscanf(__LettersDir[__LetterPtr[0]][__LetterPtr[1]], "%s.%s", str, ext); + __LetterPtr[1]++; + if(!restore_letter(str)) { + return; + } + i = sizeof(tmp = keys(__Folders)); + while(i--) { + file = save_file(DIR_POSTAL+"/"+tmp[i][0..0]+"/"+tmp[i]); + if(!user_exists(tmp[i])) { + FOLDERS_D->delete_user(tmp[i]); + restore_letter(str); + } + else if(!unguarded((: file_exists, file :))) { + map_delete(__Folders, tmp[i]); + save_letter(); + } + } + if(!sizeof(keys(__Folders))) { + file = save_file(DIR_LETTERS+"/"+str[strlen(str)-1..strlen(str)-1] + +"/"+str); + unguarded((: rm, file :)); + } +} + +static void manage_postal() { + string pl, ext, file; + string *tmp; + int x, i; + + if(!(x = sizeof(tmp = keys(__PostalDir)))) return; + if(__PostalPtr[1] >= sizeof(__PostalDir[__PostalPtr[0]])) { + i = member_array(__PostalPtr[0], tmp); + if(++i == x) i = 0; + __PostalPtr = ({ tmp[i], 0 }); + } + if(!pl) { + __PostalPtr[1]++; + return; + } + sscanf(__PostalDir[__PostalPtr[0]][__PostalPtr[1]], "%s.%s", pl, ext); + file = save_file(DIR_POSTAL+"/"+pl[0..0]+"/"+pl); + if(!unguarded((: file_exists, file :))) { + __PostalPtr[1]++; + return; + } + if(!user_exists(pl)) FOLDERS_D->delete_user(pl); + else FOLDERS_D->check_folders(pl); + __PostalPtr[1]++; +} diff --git a/lib/secure/daemon/letters.h b/lib/secure/daemon/letters.h new file mode 100644 index 0000000..edb9560 --- /dev/null +++ b/lib/secure/daemon/letters.h @@ -0,0 +1,14 @@ +#ifndef __LETTERS_H +#define __LETTERS_H + +static private int valid_access(); +string create_letter(string str); +static private void save_letter(); +static private int restore_letter(string id); +string query_letter(string id); +void delete_folder(string who, string folder, string id); +void add_folder(string who, string folder, string id); +static void manage_letters(); +static void manage_postal(); + +#endif /* __LETTERS_H */ diff --git a/lib/secure/daemon/localpost.c b/lib/secure/daemon/localpost.c new file mode 100644 index 0000000..06f7b9c --- /dev/null +++ b/lib/secure/daemon/localpost.c @@ -0,0 +1,172 @@ +/* /daemon/postal/localpost.c + * from Foundation II + * filter for mails coming in from outside and inside + * created by Descartes of Borg 940503 + */ + +#include <lib.h> +#include <cfg.h> +#include <objects.h> +#include <daemons.h> +#include "localpost.h" + +inherit LIB_DAEMON; + +static private mapping __MudGroups; + +void create() { + daemon::create(); + SetNoClean(1); + load_groups(); +} + +void load_groups() { + mapping tmp; + string *lines, *parts; + string a, b; + int i, maxi, x, j; + + maxi = sizeof(lines = filter(explode(read_file(CFG_ALIASES), "\n"), + (: $1 && $1 != "" && $1[0] != '#' :))); + for(i=0, tmp = ([]); i<maxi; i++) { + if(sscanf(lines[i], "%s: %s", a, b) != 2) continue; + if(b[0..0] == "|") { + x = sizeof(parts = explode(b[1..strlen(b)-1], ";")); + if(a == "include") { + switch(sizeof(parts)) { + case 2: + tmp += call_other(parts[0],parts[1]); + break; + case 3: + tmp+=call_other(parts[0],parts[1], + parts[2]); + break; + default: + tmp += call_other(parts[0], parts[1], + parts[2], parts[3]); + break; + } + } + else switch(sizeof(parts)) { + case 2: + tmp[a] = call_other(parts[0],parts[1]); + break; + case 3: + tmp[a] = call_other(parts[0],parts[1], + parts[2]); + break; + default: + tmp[a] = call_other(parts[0],parts[1], + parts[2], parts[3]); + } + } + else { + x = sizeof(parts = explode(b, " ")); + if(a != "exclude") tmp[a] = ({}); + for(j=0; j<x; j++) { + if(a == "exclude" && tmp[parts[j]]) + map_delete(tmp, parts[j]); + else if(a == "exclude") continue; + else if(tmp[parts[j]]) tmp[a]+=tmp[parts[j]]; + else tmp[a] += ({ parts[j] }); + } + } + } + i = sizeof(parts = keys(tmp)); + __MudGroups = ([]); + while(i--) __MudGroups[lower_case(parts[i])] = tmp[parts[i]]; +} + +varargs string *send_post(mapping borg, mixed who) { + mapping remote_mail, grps; + string *rejects, *tmp, *tmpwho, *cles; + string msg, a, b, tmpstr; + int i, j, x; + + if(!who) who = distinct_array(borg["to"] + borg["cc"]); + tmpstr = base_name(previous_object(0)); + if(tmpstr != OBJ_POST && tmpstr != REMOTEPOST_D && tmpstr != FOLDERS_D) + return (pointerp(who) ? who : ({ who })); + rejects = ({}); + grps = OPTIONS_D->query_groups(borg["from"]); + borg["id"] = LETTERS_D->create_letter(borg["message"]); + msg = borg["message"]; + map_delete(borg, "message"); + remote_mail = ([]); + if(pointerp(who)) { + i = sizeof(who); + tmpwho = ({}); + x = OPTIONS_D->query_option(borg["from"], "metoo"); + while(i--) { + if(pointerp(who[i] = map_groups(who[i], grps, borg["from"]))) + tmpwho += who[i]; + else tmpwho += ({ who[i] }); + } + i = sizeof(who = tmpwho); + while(i--) { + if(sscanf(who[i], "%s@%s", a, b) == 2) { + if(!remote_mail[b]) remote_mail[b] = ({ a }); + else remote_mail[b] += ({ a }); + } + else if(!user_exists(who[i])) rejects += ({ who[i] }); + else FOLDERS_D->add_post(who[i], "new", borg); + } + j = sizeof(cles = keys(remote_mail)); + while(j--) + if(!(REMOTEPOST_D->send_post(borg+(["message":msg]), cles[j]))){ + rejects += remote_mail[cles[j]]; + } + return rejects; + } + else if(pointerp(tmp = __MudGroups[who]) && (i = sizeof(tmp))) { + while(i--) { + if(sscanf(tmp[i], "%s@%s", a, b) == 2) { + if(!remote_mail[b]) remote_mail[b] = ({}); + remote_mail[b] += ({ tmp[i] }); + } + else if(!user_exists(tmp[i])) rejects += ({ tmp[i] }); + else FOLDERS_D->add_post(tmp[i], "new", borg); + } + i = sizeof(cles = keys(remote_mail)); + while(i--) + if(!(REMOTEPOST_D->send_post(borg+(["message":msg]), cles[i]))) + rejects += remote_mail[cles[i]]; + return rejects; + } + else if(pointerp(tmp = OPTIONS_D->query_group(who)) && + (i = sizeof(tmp))) { + while(i--) { + if(sscanf(tmp[i], "%s@%s", a, b) == 2) { + if(!remote_mail[b]) remote_mail[b] = ({}); + remote_mail[b] += ({ tmp[i] }); + } + else if(!user_exists(tmp[i])) rejects += ({ tmp[i] }); + else FOLDERS_D->add_post(tmp[i], "new", borg); + } + i = sizeof(cles = keys(remote_mail)); + while(i--) + if(!(REMOTEPOST_D->send_post(borg+(["message":msg]),cles[i]))) + rejects += remote_mail[cles[i]]; + return rejects; + } + else { + if(sscanf(who, "%s@%s", a, b) == 2) { + if(!(REMOTEPOST_D->send_post(borg+(["message":msg]),b))) + return ({ who }); + } + else if(!user_exists(who)) return ({ who }); + else FOLDERS_D->add_post(who, "new", borg); + return ({}); + } +} + +static private mixed map_groups(string str, mapping grps, string who) { + if(__MudGroups[str]) return __MudGroups[str] - ({ who }); + else if(grps[str] && sizeof(grps[str])) + return grps[str] - ({ who }); + else return str; +} + +string *query_mud_group(string str) { return copy(__MudGroups[str]); } + +mapping query_mud_groups() { return copy(__MudGroups); } diff --git a/lib/secure/daemon/localpost.h b/lib/secure/daemon/localpost.h new file mode 100644 index 0000000..0bc993c --- /dev/null +++ b/lib/secure/daemon/localpost.h @@ -0,0 +1,10 @@ +#ifndef __LOCALPOST_H +#define __LOCALPOST_H + +void load_groups(); +varargs string *send_post(mapping borg, mixed who); +static private mixed map_groups(string str, mapping grps, string who); +string *query_mud_group(string str); +mapping query_mud_groups(); + +#endif /* __LOCALPOST_H */ diff --git a/lib/secure/daemon/log.c b/lib/secure/daemon/log.c new file mode 100644 index 0000000..6d029a0 --- /dev/null +++ b/lib/secure/daemon/log.c @@ -0,0 +1,59 @@ +#include <lib.h> +#include <daemons.h> +#include <logs.h> + +inherit LIB_DAEMON; +mapping SpecialLogs = ([]); + +static void create() { + daemon::create(); + SetNoClean(1); + SpecialLogs = ([ + INTERMUD_D : ({ LOG_I3, LOG_I3ERR }), + SERVICES_D : ({ LOG_I3, LOG_I3ERR }), + ]); +} + +varargs int RotateLogs(int force){ + string *contents,*paths; + string fooname,foopath,temppath; + int maxsize = 50000; + if(force) maxsize = 0; + paths = ({"/log/chan/", "/log/","/log/errors/","/secure/log/adm/", + "/secure/log/","/log/router/","/log/secure/","/log/adm/"}); + foreach(string path in paths){ + contents = get_dir(path); + foreach(string substr in contents){ + temppath = path+substr; + if( file_size(temppath) > maxsize) { + write_file(temppath,"\nEND-OF-LOG\n"); + fooname=substr+"-"+timestamp(); + foopath=path+fooname; + cp(temppath,foopath); + if( file_size(path+"archive") != -2 ) mkdir(path+"archive"); + cp(foopath,path+"archive/"+fooname); + rm(foopath); + write_file(temppath, "NEW_LOG "+timestamp()+"\n", 1); + } + } + } + return 1; +} + +#if 1 +int LogSpecial(string file, string content){ + int ret; + object prev = previous_object(); + string prevname, *specials = ({}); + if(!prev) return 0; + specials = keys(SpecialLogs); + if(!sizeof(specials)) return; + prevname = base_name(prev); + if(!sizeof(prevname) || member_array(prevname, specials) == -1){ + return 0; + } + if(member_array(file, SpecialLogs[prevname]) == -1) return 0; + ret = unguarded( (: write_file($(file), $(content)) :) ); + return ret; +} +#endif diff --git a/lib/secure/daemon/luget.c b/lib/secure/daemon/luget.c new file mode 100644 index 0000000..e563bdc --- /dev/null +++ b/lib/secure/daemon/luget.c @@ -0,0 +1,230 @@ +#include <lib.h> +#include NETWORK_H +#include <commands.h> + +inherit LIB_DAEMON; +string gfile, ghost; +int upgrading = 0; +int max_outbound = 5; +int max_retries = 200; +mapping FilesMap = ([]); +mapping FileQueue = ([]); +string lucmd = CMD_LIVEUPGRADE; + +void validate(){ + if(!master()->valid_apply(({ "SECURE" })) ){ + string offender = identify(previous_object(-1)); + debug("LUGET_D SECURITY VIOLATION: "+offender+" ",get_stack(),"red"); + log_file("security", "\n"+timestamp()+" LUGET_D breach: "+offender+" "+get_stack()); + error("LUGET_D SECURITY VIOLATION: "+offender+" "+get_stack()); + } +} + +static void create() { + daemon::create(); + set_heart_beat(1); +} + +varargs string convname(string raw, int rev){ + string ret = replace_string(raw,"/","0^0"); + if(rev){ + ret = replace_string(raw,"0^0","/"); + ret = replace_string(ret,"/secure/upgrades/files/",""); + } + else ret = "/secure/upgrades/files/"+ret; + return ret; +} + +static void LUReport(string str){ + if(upgrading) lucmd->eventReceiveReport(str); +} + +static int ProcessData(int fd){ + int i; + int nullify = 0; + string where; + string tmp=""; + string data= FilesMap[fd]["contents"]; + mixed tmp2 = ""; + string *nullifiers = ({ "HTTP/", "HTTP0^0", "Date:", "Server:", "Last-Modified:", "ETag:", + "Accept-Ranges:", "Content-Length:", "Connection:", "Content-Type:", "X-Pad:" }); + string *tmparr = ({}); + FilesMap[fd]["last_char"] = last(data,1); + FilesMap[fd]["first_char"] = first(data,1); + tmparr = explode(data,"\n"); + i = sizeof(tmparr); + + foreach(string element in tmparr){ + if(!strsrch(element,"<title>404 Not Found")) nullify = 1; + foreach(string nully in nullifiers){ + if(!strsrch(element,nully)){ + tmparr -= ({ element }); + } + } + } + + if(!strsrch(tmparr[0],"Location: ")) nullify = 1; + + if(!nullify && sizeof(tmparr)){ + while(!sizeof(tmparr[0]) || sizeof(tmparr[0]) < 2){ + tmparr = tmparr[1..]; + } + } + data = implode(tmparr,"\n"); + + if(!FilesMap[fd]["started"]) FilesMap[fd]["started"] = 1; + + where = FilesMap[fd]["where"]; + FilesMap[fd]["where"] = replace_string(where,"0^0code0^0upgrades0^0"+mudlib_version(),""); + foreach(string nully in nullifiers){ + if(grepp(where, nully)) nullify = 1; + } + FilesMap[fd]["normalname"] = convname(FilesMap[fd]["where"],1); + if(directory_exists(FilesMap[fd]["normalname"])) nullify = 1; + if(!nullify){ + if(data && (data[0] == 10 || data[0] == 13)) data = data[1..]; + if(last(data,1) != "\n") data += "\n"; + FilesMap[fd]["contents"] = data; + } + else FilesMap[fd]["contents"] = 0; +} + +void close_callback(int fd){ + validate(); + + if(FilesMap[fd]){ + LUReport("Received "+FilesMap[fd]["file"]); + ProcessData(fd); + if(FilesMap[fd]["contents"] && sizeof(FilesMap[fd]["contents"])){ + write_file(FilesMap[fd]["where"], FilesMap[fd]["contents"],1); + } + FilesMap[fd] = 0; + map_delete(FilesMap,fd); + } +} + +varargs int GetFile(string source, string file, string host, string where, int port){ + int fd, status; + + validate(); + + if(sizeof(FilesMap) > max_outbound){ + if(!FileQueue) FileQueue = ([]); + if(!FileQueue[file]) FileQueue[file] = ([ "source" : source, "file" : file, "host" : host, + "where" : where, "port" : (port || 80), "creation" : time(), "started" : 0, + "user" : (this_player() ? this_player()->GetName() : identify(this_object())), + "first_char" : "", "last_char" : "" ]); + return 0; + } + + fd = socket_create(STREAM, "read_callback", "close_callback"); + if( fd < 0 ){ + return 0; + } + + FilesMap[fd] = ([ "source" : source, "file" : file, "host" : host, + "where" : where, "port" : (port || 80), "creation" : time(), "started" : 0, + "user" : (this_player() ? this_player()->GetName() : identify(this_object())) ]); + + status = socket_connect(fd, source +" "+port, "read_callback", "write_callback"); + if( status < 0 ){ + return 0; + } + + return fd; +} + +static varargs void RetryGet(int i){ + mixed *queue = keys(FileQueue); + if(!i) i = 2; + if(i > max_outbound) i = max_outbound; + if(!FileQueue || !sizeof(FileQueue)){ + return 0; + } + foreach(mixed element in queue[0..i]){ + mapping TmpMap = FileQueue[element]; + mixed foo = GetFile(TmpMap["source"],TmpMap["file"],TmpMap["host"],TmpMap["where"],TmpMap["port"]); + if(foo){ + LUReport("%^CYAN%^Requesting: file: "+TmpMap["file"]+"%^RESET%^"); + map_delete(FileQueue, element); + } + } +} + +static void CleanFD(int fd){ + if(!FilesMap[fd]) socket_close(fd); + else if(!socket_status(fd)) map_delete(FilesMap,fd); + else if(socket_status(fd)[1] != "DATA_XFER"){ + map_delete(FilesMap,fd); + socket_close(fd); + } +} + +void heart_beat(){ + if((!FileQueue || !sizeof(FileQueue)) && + (!FilesMap || !sizeof(FilesMap))){ + if(upgrading){ + LUReport("\nFile download complete. After backing up your mud, issue the command: liveupgrade apply"); + upgrading = 0; + } + return; + } + RetryGet(); +} + +void write_callback(int fd){ + string str; + int result = 0; + validate(); + if(!FilesMap[fd] || !socket_status(fd)){ + CleanFD(fd); + return; + } + str ="GET "+FilesMap[fd]["file"]+" HTTP/1.0"+CARRIAGE_RETURN+"\n"+ + "Host: "+FilesMap[fd]["host"]+CARRIAGE_RETURN+"\n" + + "User-Agent: "+ FilesMap[fd]["user"] + "@" + mud_name() + " " + + mudlib()+ "/" + mudlib_version() +" ("+ query_os_type()+";) "+ + version() + " "+ + CARRIAGE_RETURN+"\n"+CARRIAGE_RETURN+"\n"; + result = socket_write(fd, str); +} + +void read_callback(int fd, mixed data){ + validate(); + + if(!FilesMap[fd]){ + return; + } + if(!FilesMap[fd]["contents"]) FilesMap[fd]["contents"] = data; + else FilesMap[fd]["contents"] += data; +} + +varargs int eventMajorUpgrade(string source, string *files, string host, int port){ + string *allfiles = sort_array(files,1); + validate(); + if(upgrading){ + LUReport("There is a liveupgrade already in progress."); + return 0; + } + upgrading = 1; + foreach(string element in allfiles){ + //if(last_string_element(element,1) == "/") continue; + GetFile(source, element, host, convname(element), (port || 80)); + } + return 1; +} + +int eventDestruct(){ + int *fds = keys(FilesMap); + validate(); + if(sizeof(fds)){ + foreach(int fd in fds){ + socket_close(fd); + } + } + return ::eventDestruct(); +} + +int GetUpgrading(){ + return upgrading; +} diff --git a/lib/secure/daemon/master.c b/lib/secure/daemon/master.c new file mode 100644 index 0000000..563476a --- /dev/null +++ b/lib/secure/daemon/master.c @@ -0,0 +1,1157 @@ +/* /secure/daemon/master.c + * from the Dead Souls LPC Library + * the master object, responsible for security + * created by Descartes of Borg 940910 + * error handling by Beek@The Idea Exchange 941004 + * Version: @(#) master.c 1.7@(#) + * Last modified: 96/12/14 + */ + +#include +#include ROOMS_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include NETWORK_H +#include +#include +#include +#include "master.h" + +#ifndef COMPAT_MODE +#define COMPAT_MODE 1 +#endif +#ifndef DEFAULT_PARSING +#define DEFAULT_PARSING 1 +#endif +#ifndef RESET_ALL +#define RESET_ALL 1 +#endif +#ifndef MAX_SINGLE_OBJECT +#define MAX_SINGLE_OBJECT 4000 +#endif +#ifndef CONSOLE_TRACE +#define CONSOLE_TRACE 0 +#endif + +inherit LIB_DAEMON; +#include + +private static int incept_date, ResetNumber, heart_count, in_reset; +private static int eval_threshold, reset_handle = -1; +private int BootScore, PerformanceScore, globalpmsg; +private static object Unguarded, gguy; +private static string PlayerName, rlog, gcmd, bname, gstr; +private static object NewPlayer; +private static mapping Groups, ReadAccess, WriteAccess, CostErr; +private static string *ParserDirs = ({ "secure", "verbs", "daemon", "lib", "powers" }); +private static string array efuns_arr = ({}); +private static string MudName, mconfig; + +static void Setup(){ + if(uptime() < 30) MudName = 0; +} + +void create() { +#ifdef __OPCPROF__ + string tmpfun, junk, opstr; + string *oparr = ({}); + string opfile = "/tmp/opc"; + opcprof(opfile); + if(file_exists(opfile+".efun")){ + opstr = read_file(opfile+".efun"); + if(opstr){ + oparr = explode(opstr, "\n"); + } + if(sizeof(oparr)){ + foreach(string element in oparr){ + if(sscanf(element,"%s %s",tmpfun, junk) == 2){ + if(tmpfun[0..0] == "_") tmpfun = tmpfun[1..]; + efuns_arr += ({ tmpfun }); + } + } + } + } +#endif + eval_threshold = (get_config(__MAX_EVAL_COST__) / 1000000) + 1; + incept_date = time(); + BootScore = 0; + this_object()->GetPerformanceScore(); + Unguarded = 0; + NewPlayer = 0; + PlayerName = 0; + ResetNumber = 1; + if(!(file_exists("/secure/sefun/native_version.c"))){ + cp("/secure/scripts/native_version.proto", + "/secure/sefun/native_version.c"); + } + new_read(); + new_write(); + new_groups(); + reset_handle = call_out( (: eventReset :), TIME_TO_RESET ); + call_out( (: Setup :), 10); + set_heart_beat(1); + ReadName(); +} + +static void heart_beat(){ + heart_count++; + if(!(heart_count % 60)){ + CostErr = ([]); + this_object()->GetPerformanceScore(1); + if(in_reset){ + eventReset(); + } + } + if(heart_count > 64000) heart_count = 0; +} + +void new_read() { + mapping tmp; + tmp = ([]); + load_access(CFG_READ, tmp); + ReadAccess = tmp; +} + +void new_write() { + mapping tmp; + tmp = ([]); + load_access(CFG_WRITE, tmp); + WriteAccess = tmp; +} + +void new_groups() { + mapping tmp; + tmp = ([]); + load_access(CFG_GROUPS, tmp); + Groups = tmp; +} + +private static void load_access(string cfg, mapping resource) { + string *lines; + string file; + + if( !(file = read_file(cfg)) ) { + error("Failed to find config file: "+cfg); + } + lines = filter(explode(file, "\n"), function(string line) { + + if( !line || trim(line) == "" ) { + return 0; + } + if( line[0] == '#' ) { + return 0; + } + return 1; + }); + foreach(string line in lines) { + string fl, ac = ""; + + if( sscanf(line, "(%s)%s", fl, ac) != 2 ) { + error("Error in loading config file " + cfg + "."); + } + ac = trim(ac); + if(last(fl,1) == "*" && last(fl,2) != "/*"){ + string camino = (path_prefix(fl) || ""); + string targ = truncate(replace_string(fl, camino, ""), 1); + string *pool = get_dir(camino+"/"); + string *targs; + if(sizeof(targ)) targ = targ[1..]; + targs = regexp(pool,"^"+targ); + pool = ({}); + foreach(string element in targs){ + pool += ({ camino + "/" + element }); + } + foreach(string element in pool){ + if(sizeof(element)) resource[element] = explode(ac, ":"); + } + } + else if(last(fl,3) == "/*/"){ + string tmp = truncate(fl,2); + foreach(string element in get_dir(tmp)){ + resource[tmp+element+"/"] = explode(ac, ":"); + } + } + else resource[fl] = explode(ac, ":"); + } +} + +void flag(string str) { + string file, arg; + int i, x; + + if(previous_object()) return; + if(sscanf(str, "for %d", x) == 1) { + for(i=0; iGetForced()) { tell_player(ob,"Someone's fucking with you."); return 0;} + if(!valid_write(from, ob, "link")) {return 0;} + if(!valid_write(to, ob, "link")) {return 0;} + return 1; +} + +int valid_apply(string *ok) { + int ret; + ret = check_access(previous_object(1),0,previous_object(0), ok, "apply"); + return ret; +} + +int check_access(object ob, string fun, mixed file, string *ok, string oper) { + object *stack; + string *privs; + string priv, tmp; + int i; + + if( objectp(file) ) tmp = base_name(file); + if(tmp) file = tmp; + if( ok && sizeof(ok) && ok[0] == "all" ) return 1; + if( Unguarded == ob ){ + tmp = base_name(ob); + if( tmp == LIB_PLAYER || tmp == LIB_CREATOR){ + string sfilep, sfilec; + sfilep = DIR_PLAYERS+"/"+PlayerName[0..0]+"/"+ PlayerName + __SAVE_EXTENSION__; + sfilec = DIR_CRES+"/"+PlayerName[0..0]+"/"+ PlayerName + __SAVE_EXTENSION__; + if( !PlayerName ) i = sizeof(stack = ({ob})+previous_object(-1)); + else if( file == sfilep ) return 1; + else if( file == sfilec ) return 1; +#if ENABLE_INSTANCES + else if( file == new_savename(sfilep) ){ + return 1; + } + else if( file == new_savename(sfilec) ){ + return 1; + } +#endif + else i = sizeof(stack = ({ ob })); + } + else if( tmp == file ) return 1; + else if( tmp + __SAVE_EXTENSION__ == file ) return 1; +#if ENABLE_INSTANCES + else if( new_savename(tmp) == file ) return 1; +#endif + else i = sizeof(stack = ({ ob })); + } + else if(Unguarded && base_name(ob) == SEFUN) { + if(Unguarded == previous_object(1)) + stack = ({ previous_object(1) }); + else stack = ({ ob }) + previous_object(-1); + } + else i = sizeof(stack = previous_object(-1) + ({ ob })); + while(i--) { + if(!stack[i] || stack[i] == this_object()) { + continue; + } + if(file_name(stack[i]) == SEFUN) { + continue; + } + if(!(priv = query_privs(stack[i]))) { + if(false()){ + debug_message("\nSPLAT 1: "+identify(stack[i])); + } + return 0; + } + if(!ok && oper == "read") { + continue; + } + privs = explode(priv, ":"); + if(member_array(PRIV_SECURE, privs) != -1) { + continue; + } + if(stringp(file) && member_array(file_privs(file), privs) != -1) { + continue; + } + if(!ok && oper == "write") { + if(userp(stack[i]) && check_user(stack[i], fun, file, oper)){ + continue; + } + else { + debug_message("\nSPLAT 2\n"); + return 0; + } + } + if(sizeof(privs & ok)) { + continue; + } + if(userp(stack[i]) && check_user(stack[i], fun, file, oper)) continue; + if(userp(stack[i]) && check_domain(stack[i], fun, file,oper)) continue; + return 0; + } + return 1; +} + +nomask static int check_user(object ob, string fun, string file, string oper){ + string nom, tmp; + int x; + if(interactive(ob) && !creatorp(ob)){ + nom = ob->GetKeyName(); + if(!strsrch(file,DIR_ESTATES + "/"+nom[0..0]+"/"+nom)) return 1; + } + if( !sscanf(file, REALMS_DIRS "/%s", nom) ) return 0; + if( sscanf(nom, "%s/%*s", tmp) ) nom = tmp; + nom = user_path(nom)+"adm/access"; + if(strsrch(nom,"/tmp") && file_size(nom+".c") > 0) + catch(x = call_other(nom, "check_access", ob, fun, file, oper)); + return x; +} + +nomask static int check_domain(object ob, string fun, string file, string o) { + string nom; + int x; + if( !sscanf(file, DOMAINS_DIRS+"/%s/%*s", nom) ) return 0; + nom = DOMAINS_DIRS+"/"+nom+"/adm/access"; + if(file_size(nom+".c") < 0) return 0; + catch(x = call_other(nom, "check_access", ob, fun, file, o)); + return x; +} + +object connect(int port) { + object ob; + string err; + string file; + + file = LIB_CONNECT; + if( err = catch(ob = new(file)) ) { + write("It looks like someone is working on the user object.\n"); + write(err); + destruct(ob); + } + return ob; +} + +object compile_object(string str) { + string nom, tmp, where, which, sfile; + object ob; + sfile = str+__SAVE_EXTENSION__; + if(sscanf(str, REALMS_DIRS+"/%s/%*s", nom)) + tmp = sprintf("%svirtual/server", user_path(nom)); + else if(sscanf(str, DOMAINS_DIRS+"/%s/%*s", nom)) + tmp = sprintf("%s/%s/virtual/server", DOMAINS_DIRS, nom); + else if(strsrch(str, ESTATES_DIRS) == 0) + tmp = sprintf("%s/virtual/server", ESTATES_DIRS); + else if(sscanf(str, DIR_PLAYERS+"/%*s/%s", nom)) { + if(!NewPlayer){ + return 0; + } +#if ENABLE_INSTANCES + nom = old_savename(nom); +#endif + if(last(nom,2) == ".o") nom = truncate(nom, 2); + if(last(sfile,4) == ".o.o") sfile = truncate(sfile, 2); + if(NewPlayer->GetKeyName() != nom) return 0; + PlayerName = nom; + ob = new(LIB_PLAYER); + if(file_exists(sfile) || file_exists(new_savename(sfile))){ + ob->restore_player(nom); + } + else { + if(file_size(DIR_PLAYERS) != -2) mkdir(DIR_PLAYERS); + } + if(file_size(DIR_PLAYERS+"/"+nom[0..0]) != -2) + mkdir(DIR_PLAYERS+"/"+nom[0..0]); + ob->SetKeyName(nom); + PlayerName = 0; + return ob; + } + else if( sscanf(str, DIR_CRES+"/%*s/%s", nom) ) { + if(!NewPlayer) return 0; +#if ENABLE_INSTANCES + nom = old_savename(nom); + if(last(nom,2) == ".o") nom = truncate(nom, 2); +#endif + if(last(sfile,4) == ".o.o") sfile = truncate(sfile, 2); + if(NewPlayer->GetKeyName() != nom) return 0; + PlayerName = nom; + ob = new(LIB_CREATOR); + if(file_exists(sfile) || file_exists(new_savename(sfile))){ + ob->restore_player(nom); + } + else { + } + ob->SetKeyName(nom); + PlayerName = 0; + return ob; + } + if(file_size(tmp+".c") < 0) { + if(sscanf(str, "%s.%s", where, which) != 2) return 0; + if(sscanf(str, REALMS_DIRS+"/%s/%*s", nom)) + tmp = sprintf("%svirtual/%s_server", user_path(nom), which); + else if(sscanf(str, DOMAINS_DIRS+"/%s/%*s", nom)) + tmp = sprintf("%s/%s/virtual/%s_server", DOMAINS_DIRS, nom, which); + if(file_size(tmp+".c") < 0) return 0; + else return call_other(tmp, "compile_object", where); + } + return call_other(tmp, "compile_object", str); +} + +static void crash(mixed args...) { + string err; + string guilty_stack = get_stack(); + string guilty_obs = identify(previous_object(-1)); + if(sizeof(args)) err = args[0]; + write_file(DIR_LOGS "/crashes", + mud_name() + " crashed " + ctime(time()) + " with error " + + err+".\n"+guilty_stack+"\n"+guilty_obs+"\n---\n"); + message("system", "Reality implosion!!! Everyone duck!!!", users()); + message("system", "You are being forced to quit.", users()); + users()->cmdQuit(); +} + +int valid_bind(object binder, object old_owner, object new_owner) { + int ret; + mixed privs; + if(!binder) ret = 0; + else if( binder == this_object() ) ret = 1; + else if( base_name(binder) == SEFUN ) ret = 1; + else if( member_array(PRIV_SECURE, + explode((privs = query_privs(binder)), ":")) != -1 ) ret = 1; + return ret; +} + +int valid_hide(object who) { + string priv; + if(!objectp(who)) return 0; + if(environment(who) && hiddenp(environment(who))) return 1; + if(!(priv = query_privs(who))) return 0; + else return (member_array(PRIV_SECURE, explode(priv, ":")) != -1); +} + +int valid_override(string file, string nom){ + return (file == SEFUN); +} + +int valid_save_binary(string str) { return 1; } + +int valid_shadow(object ob) { + object targ = previous_object(); + return (!virtualp(targ) && !strsrch(file_name(targ), DIR_SHADOWS)); +} + +int valid_object(object ob) { + string file, contents; + file = file_name(ob); + contents = read_file(base_name(ob)+".c"); + if(!contents) contents = ""; + if(strsrch(contents,"parse_add_rule") != -1 + || strsrch(contents, "SetRules") != -1) { + string prefix; + if(!sscanf(file,"/%s/%*s",prefix)) return 0; + if(member_array(prefix, ParserDirs) == -1) return 0; + } + if( !strsrch(file, DIR_TMP) ) return 0; + else if( !strsrch(file, DIR_FTP) ) return 0; + else if( !strsrch(file, DIR_LOGS) ) return 0; + else if( !strsrch(file, DIR_SECURE_SAVE) ){ + return 0; + } + else return 1; +} + +int valid_socket(object ob, string fun, mixed *info) { + object *obs; + int port; + string tmp; + int i; + if( info && sizeof(info) == 4 ) { + ob = info[1]; + port = info[3]; + if( port == PORT_ADMIN && ob != find_object(ADMIN_D) ) { + return 0; + } + if( port == PORT_RCP && ob != find_object(REMOTE_D) ) { + return 0; + } + } + i = sizeof(obs = previous_object(-1)); + while(i--) { + if( !obs[i] ) continue; + if( userp(obs[i]) ) continue; + tmp = query_privs(obs[i]); + if(!tmp && base_name(obs[i]) == SEFUN) tmp = "SECURE"; + if( !(tmp) ) return 0; + if( !sizeof(explode(tmp, ":") & + ({ PRIV_SECURE, PRIV_MUDLIB, PRIV_CMDS, PRIV_GENERAL })) ){ + return 0; + } + } + return 1; +} + +mixed apply_unguarded(function f) { + object previous_unguarded; + string err; + mixed val; + + if(!f || !functionp(f)){ + error("Invalid function passed."); + return 0; + } + + if((functionp(f) & FP_OWNER_DESTED)){ + error("Function owner dested: invalid function."); + return 0; + } + + if(base_name(previous_object(0)) != SEFUN) { + error("Illegal unguarded apply."); + return 0; + } + previous_unguarded = Unguarded; + Unguarded = previous_object(1); + err = catch(val = evaluate(f) ); + Unguarded = previous_unguarded; + if(err) error(err); + return val; +} + +string error_handler(mapping mp, int caught) { + string ret, file, dbg; + int now = time(); + + if(!CostErr) CostErr = ([ now : 0 ]); + else if(undefinedp(CostErr[now])) CostErr[now] = 0; + + if(CONSOLE_TRACE){ + dbg = "\n----\n"+mud_name()+"\n----\n"; + foreach(mixed key, mixed val in mp){ + dbg += identify(key) + " : "+identify(val)+"\n"; + } + dbg += "\n----\n"; + debug_message(dbg); + } + if(mp && mp["error"]){ + if(grepp(mp["error"], "Too deep recursion")){ + debug_message("Too deep recursion\n"+get_stack()); + } + if(grepp(mp["error"], "Too many open files")){ + debug_message("Too many open files!\n"); + shutdown(-9); + } + if(grepp(mp["error"], "Too long evaluation.")){ + CostErr[now]++; + } + if(grepp(mp["error"], "Can't catch eval cost too big error.")){ + CostErr[now]++; + } + if(CostErr[now] >= eval_threshold){ + /* This prevents a strange eval cost cascade that + * can sometimes happen under extreme load. Unfortunately + * the only effective countermeasure is a hard reboot + * of the mud. + */ + debug_message("Shut'er down, Clancy! She's a-pumpin' mud!!\n"); + shutdown(-9); + } + } + ret = "\n--- "+mud_name()+"\n"+timestamp()+"\n"+ standard_trace(mp); + if( caught ) write_file(file = "/log/catch", ret); + else write_file(file = "/log/runtime", ret); + if( this_player(1) && find_object(SEFUN) ) { + this_player(1)->SetLastError(mp); + if( creatorp(this_player(1)) ) { + this_player(1)->eventPrint(ret + "Trace written to " + file, + MSG_SYSTEM); + } + else { + if( !strsrch(file_name(this_player(1)), LIB_CONNECT) ) { + return "/log/login\n"+standard_trace(mp)+"\n--\n"; + } + this_player()->eventPrint("A runtime error occurred."); + CHAT_D->eventSendChannel("System", "error", "A runtime error " + "occurred to " + + this_player(1)->GetCapName()+"."); + rlog = "-----\n" +timestamp()+ ": "+this_player(1)->GetCapName()+"\n"; + rlog += load_object("/secure/cmds/creators/dbxwhere")->cmd(this_player(1)->GetKeyName()); + rlog += flat_map(this_player()->GetLastError())+"\n-----\n"; + unguarded( (: write_file("/log/player_errors", rlog) :) ); + } + } + return 0; +} + +void log_error(string file, string msg) { + string nom, tmp, tmp2; + + if( file[0] != '/' ) { + file = "/" + file; + } + if(!this_player()){ + object *object_stack = call_stack(1); + object web_sessions = load_object(WEB_SESSIONS_D); + if(web_sessions && member_array(web_sessions, object_stack) != -1){ + web_sessions->ReceiveErrorReport(msg); + } + } + if( sscanf(file, REALMS_DIRS+"/%s/%s", nom, tmp) != 2 && + sscanf(file, DOMAINS_DIRS+"/%s/%s", nom, tmp) != 2 && + sscanf(file, ESTATES_DIRS+"/%s/%s/%s", tmp, nom, tmp2) != 3 ) + sscanf(file, "/%s/%s", nom, tmp); + if( !nom ) nom = "log"; + catch(write_file(DIR_ERROR_LOGS "/" + nom, timestamp()+" "+msg)); + if(msg && this_player(1) && builderp(this_player(1))){ + catch(tell_player(this_player(1),msg)); + } +} + +varargs string standard_trace(mapping mp, int flag) { + string ret; + mapping *trace; + int i,n; + + ret = mp["error"] + "Object: " + + trace_line(mp["object"], mp["program"], mp["file"], mp["line"]); + ret += "\n"; + trace = mp["trace"]; + n = sizeof(trace); + for (i=0; i"; + + ret = objfn; + if( different(objfn, prog) ) ret += sprintf(" (%s)", prog); + if( file != prog ) ret += sprintf(" at %s:%d\n", file, line); + else ret += sprintf(" at line %d\n", line); + return ret; +} + +int different(string fn, string pr) { + int tmp; + sscanf(fn, "%s#%d", fn, tmp); + fn += ".c"; + return (fn != pr) && (fn != ("/" + pr)); +} + +void master_log_file(string file, string msg) { + if(file_name(previous_object()) != SEFUN) return; + if(file_size(file) > MAX_LOG_SIZE){ + string pre = path_prefix(file); + string post = replace_string(file, pre + "/", ""); + write_file(file,"\nEND-OF-LOG\n"); + if(!directory_exists(pre + "/archive")){ + mkdir(pre + "/archive"); + } + rename(file, pre + "/archive/" + post + "-" + timestamp()); + } + write_file(file, msg); +} + +string make_path_absolute(string file) { + return absolute_path(this_player(1)->query_cwd(), file); +} + +int player_exists(string nom) { + string sfilec, sfilep; + if( !nom ) return 0; + sfilec = DIR_CRES "/" + nom[0..0] + "/" + nom + __SAVE_EXTENSION__; + sfilep = DIR_PLAYERS "/" + nom[0..0] + "/" + nom + __SAVE_EXTENSION__; +#if ENABLE_INSTANCES + sfilep = new_savename(sfilep); + sfilec = new_savename(sfilec); +#endif + if(unguarded((: file_exists, sfilec :))) return 1; + if(unguarded((: file_exists, sfilep :))) return 1; + return 0; +} + +string domain_file(string str) { + string nom, tmp; + if(sscanf(str, DOMAINS_DIRS+"/%s/%s", nom, tmp) == 2) return nom; + return 0; +} + +string author_file(string str) { + string nom, tmp, tmp2; + + if(sscanf(str, REALMS_DIRS+"/%s/%s", nom, tmp) == 2) return nom; + else if(sscanf(str, ESTATES_DIRS+"/%s/%s/%s", tmp, nom, tmp2) == 3) return nom; + return 0; +} + +static int slow_shutdown() { + write_file(DIR_LOGS "/audit", + "Armageddon loaded by master: "+ctime(time())+".\n"); + EVENTS_D->eventRebootMud(2); + return 1; +} + +int save_ed_setup(object who, int code) { + string file; + + if(!intp(code)) return 0; + rm(file = user_path(who->GetKeyName())+".edrc"); + return write_file(file, code+""); +} + +int retrieve_ed_setup(object who) { + string file; + + file = user_path(who->GetKeyName())+".edrc"; + if(!file_exists(file)) return 0; + return to_int(read_file(file)); } + + string get_save_file_name() { + mixed str; + + if(!this_player(1)) return DIR_TMP+"/.dead.edit"; + str = this_player(1)->GetKeyName(); + if(!str || !stringp(str)) return DIR_TMP+"/.dead.edit"; + if(file_size(user_path(str)) == -2) + return user_path(str)+"dead.edit"; + else return DIR_TMP+"/"+str+".dead.edit"; + } + +int is_locked() { return MUD_IS_LOCKED; } + +string *parse_command_id_list() { return ({ "one", "thing" }); } + +string *parse_command_plural_id_list() { return ({ "ones", "things","them"}); } + +string *parse_command_adjectiv_id_list() { + return ({ "the", "an", "a" }); +} + +string *parse_command_prepos_list() { + return ({ "in", "with", "without", "into", "for", "on", "under", "against", + "out", "within", "of", "from", "between", "at", "to", "over", "near", + "inside", "onto", "off", "through", "across", "up", "down", "every", + "around", "about", "only", "here", "room", "exit", "enter", "-r", "-a"}); +} + +string parse_command_all_word() { return "all"; } + +string parser_error_message(int type, object ob, mixed arg, int flag) { + string err; + object tmpob; + if( ob ) err = ob->GetShort(); + else err = ""; + switch(type) { + string wut; + object wat; + + case 0: + if(arg && objectp(arg)) wat = arg; + if(!wat && arg && arrayp(arg) && sizeof(arg)){ + foreach(mixed element in arg){ + if(objectp(element)) wat = element; + } + } + if(ob && wat){ + err = "You can't use "+ob->GetShort()+" with "+ + wat->GetShort()+" that way."; + } + else if(ob){ + err = "It seems you can't do that with " +ob->GetShort()+"."; + } + else if(wat){ + err = "It seems you can't do that to " +wat->GetShort()+"."; + } + else { + err = "It seems you can't do that."; + } + break; + + case ERR_IS_NOT: + if(flag || (arg && stringp(arg))){ + if(flag || get_object(arg, this_player())){ + return "It appears you must be more specific."; + } + else if(arg && stringp(arg)) wut = remove_article(arg); + } + else wut = "that"; + err = capitalize(wut) +" is not here."; + break; + + case ERR_NOT_LIVING: + if( flag ) + err = "None of the " + pluralize(remove_article(arg)) +" are alive."; + else err = "The " + remove_article(arg) + " is not alive."; + break; + + case ERR_NOT_ACCESSIBLE: + if( flag ) err = "You can't get to them."; + else err = "You can't get to it."; + break; + + case ERR_AMBIG: + { + mixed *obs; + int i; + gguy = this_player(); + if(DEFAULT_PARSING){ + gcmd = this_player()->GetLastCommand(); + this_player()->eventRetryCommand(gcmd, type, arg); + return " "; + } + + obs = unique_array(arg, (: $1->GetShort() :)); + if( sizeof(obs) == 1 ) + err = "Which of the " + + consolidate(sizeof(arg), obs[0][0]->GetShort()) + + " do you mean?"; + else { + err = "Do you mean "; + for(i = 0; i 1 ) + err += "one of the " + + consolidate(sizeof(obs[i]),obs[i][0]->GetShort()); + else err += obs[i][0]->GetShort(); + if( i == (sizeof(obs)-2) ) err += " or "; + else if( i < sizeof(obs) - 1 ) err += ", "; + } + err += "?"; + } + return err; + } + + case ERR_ORDINAL: + if( arg > 1 ) err = "There are only " + arg + " of them."; + else err = "There is only one of them."; + break; + + case ERR_ALLOCATED: + return arg; + + case ERR_THERE_IS_NO: + if(flag || (arg && stringp(arg)) && environment(this_player())){ + if(tmpob = present(arg, environment(this_player()))){ + return "It seems you must be more specific."; + } + else if(arg && stringp(arg)) wut = remove_article(arg); + } + else wut = "such thing"; + err = "There is no "+ wut +" here."; + break; + + case ERR_BAD_MULTIPLE: + err = "You can't do that to more than one at a time."; + break; + } + return err; +} + +void create_save() { + string str; + if(!stringp(str = previous_object()->GetKeyName())) return; + if(file_size(DIR_PLAYERS+"/"+str[0..0]) == -2) return; + if(str[0] < 'a' || str[0] > 'z') return; + mkdir(DIR_PLAYERS+"/"+str[0..0]); +} + +varargs object player_object(string nom, object stub) { + object ob; + string err, tmp; + int old_limit; + string sfilec = DIR_CRES+ "/" + nom[0..0]+ "/" +nom+__SAVE_EXTENSION__; + string sfilep = DIR_PLAYERS+ "/" + nom[0..0]+ "/" +nom+__SAVE_EXTENSION__; + tmp = base_name(ob = previous_object()); + if( tmp != CMD_ENCRE && tmp != CMD_DECRE && tmp != LIB_CONNECT + && tmp != RELOAD_D ){ + return 0; + } + old_limit = max_eval_cost(); + set_eval_limit(1000000000); + if(tmp == RELOAD_D && stub) NewPlayer = stub; + else NewPlayer = ob; +#if ENABLE_INSTANCES + if(file_exists(new_savename(sfilec))){ + err = catch(ob = load_object(new_savename(sfilec))); + } + else{ + err = catch(ob = load_object(new_savename(sfilep))); + } +#else + if(ob == previous_object() && file_exists(sfilec)){ + string tmpy; + if(last(sfilec,2) == ".o") tmpy = truncate(sfilec,2); + ob = load_object(tmpy); + if(!ob) ob = load_object(sfilec); + } + if(!ob || ob == previous_object()){ + string tmpy; + if(last(sfilep,2) == ".o") tmpy = truncate(sfilep,2); + ob = load_object(tmpy); + if(!ob) ob = load_object(sfilep); + } +#endif + NewPlayer = 0; + set_eval_limit(old_limit); + if(err) error(err); + return ob; +} + +string player_save_file(string nom) { + string sfilec, sfilep; + sfilec = DIR_CRES + "/" + nom[0..0] + "/" + nom + ".o"; + sfilep = DIR_PLAYERS + "/" + nom[0..0] + "/" + nom + ".o"; +#if ENABLE_INSTANCES + gstr = new_savename(sfilec); + if(unguarded( (: file_exists, gstr :) )){ + return gstr; + } + return new_savename(sfilep); +#endif + if(unguarded( (: file_exists, sfilec :) ) ){ + return sfilec; + } + return sfilep; +} + +string *query_group(string grp) { return copy(Groups[grp]); } + +mapping query_groups() { return copy(Groups); } + +static void eventReset(){ + object *obs; + object ob; + int x, y, z = 0; + in_reset = 1; + + ResetNumber++; + if(find_call_out("eventReset") == -1 && find_call_out(reset_handle) == -1){ + reset_handle = call_out( (: eventReset :), TIME_TO_RESET ); + } + x = reclaim_objects(); + write_file(LOG_RESET, "Reset " + ResetNumber + " occurred at: " + + ctime(time()) + "\n"); + if(!RESET_ALL) obs = objects( (: !environment($1) && (random(100) < 34) :) ); + else obs = objects( (: !environment($1) :) ); + obs = filter(obs, (: !($1->GetNoClean()) :) ); + obs -= ({ this_object() }); + if(sizeof(obs) > 1024){ + obs = scramble_array(obs)[0..1024]; + } + y = 0; + foreach(ob in obs) { + function f; + if(ob){ + f = bind( (: call_other, ob, "clean_up" :), ob ); + } + else { + continue; + } + if( f ) z += catch(evaluate(f)); + if( !ob ) { + y++; + continue; + } + f = bind((: call_other, ob, "reset", ResetNumber :), ob); + if( f ) catch(evaluate(f)); + } + in_reset = 0; + write_file(LOG_RESET, "\t" + x + " objects reclaimed, " + + (sizeof(obs) - y) + " objects reset, " + y + " objects " + "cleaned, " + z + " errors.\n"); +} + +int RequestReset(){ + if(previous_object() && (base_name(previous_object()) == SEFUN + || base_name(previous_object()) == REAPER_D)){ + unguarded( (: eventReset :) ); + return 1; + } + return 0; +} + +int GetResetNumber() { return ResetNumber; } + +string *GetEfuns(){ + return (({})+ efuns_arr); +} + +object *parse_command_users() { + return filter(users(), (: creatorp($1) || $1->is_living() :)); +} + +int GetBootScore(){ + return BootScore; +} + +varargs int GetPerformanceScore(int force){ + if(force || !PerformanceScore){ + int ret, count = 1000; + ret = time_expression { + while(count){ + count--; + } + }; + PerformanceScore = ret; + } + return PerformanceScore; +} + +int GetPerfOK(){ + if(!PerformanceScore) GetPerformanceScore(); + if(PerformanceScore <= MIN_PERF) return 1; + return 0; +} + +string GetMudName(){ + return MudName; +} + +int SetMudName(string name){ + if(!valid_apply(({ "SECURE" }))){ + return 0; + } + MudName = name; + return 1; +} + +// MSSP +mapping get_mud_stats(){ + log_file("mssp", "\n"+timestamp()+" telopt mssp queried"); + return mssp_map(); +} + +mixed GetDreams(){ + return ({}); +} + +mixed eventPromise(){ + return false(); +} + +int ReadName(){ + string line_string, nameline, tmp; + string *line_array; + int port = query_host_port(); + MudName = "DeadSoulsNew"; + if(!ENABLE_INSTANCES){ + mconfig = "/secure/cfg/mudos.cfg"; + } + else { + mconfig = "/secure/cfg/mudos."+port+".cfg"; + } + line_string = read_file(mconfig); + if(!sizeof(line_string)){ + return 0; + } + line_array = explode(line_string, "\n"); + if(!sizeof(line_array)){ + return 0; + } + foreach(string line in line_array){ + if(!strsrch(line,"name :")){ + if(sscanf(line,"%*s : %s", tmp) < 2) { + return 0; + } + MudName = tmp; + return 1; + } + } + return 0; +} diff --git a/lib/secure/daemon/master.h b/lib/secure/daemon/master.h new file mode 100644 index 0000000..bcbdaa7 --- /dev/null +++ b/lib/secure/daemon/master.h @@ -0,0 +1,53 @@ +#ifndef __MASTER_H +#define __MASTER_H + +void create(); +void new_read(); +void new_write(); +void new_groups(); +static private void load_access(string cfg, mapping resource); +void flag(string str); +string *epilog(int x); +string privs_file(string file); +void preload(string str); +int valid_write(string file, object ob, string fun); +int valid_read(string file, object ob, string fun); +int valid_apply(string *ok); +int check_access(object ob, string fun, mixed file, string *ok, string oper); +nomask static int check_user(object ob, string fun, string file, string oper); +nomask static int check_domain(object ob, string fun, string file, string o); +object connect(int port); +object compile_object(string str); +static void crash(string err); +int valid_hide(object who); +int valid_override(string file, string nom); +int valid_socket(object ob, string fun, mixed *info); +mixed apply_unguarded(function f); +string error_handler(mapping mp, int caught); +void log_error(string file, string msg); +varargs string standard_trace(mapping mp, int flag); +string trace_line(object obj, string prog, string file, int line); +int different(string fn, string pr); +void master_log_file(string file, string msg); +string make_path_absolute(string file); +int player_exists(string str); +string domain_file(string str); +string author_file(string str); +static int slow_shutdown(); +int save_ed_setup(object who, int code); +int retrieve_ed_setup(object who); +string get_save_file_name(); +int is_locked(); +string *parse_command_id_list(); +string *parse_command_plural_id_list(); +string *parse_command_adjectiv_id_list(); +string *parse_command_prepos_list(); +string parse_command_all_word(); +void create_save(); +object player_object(string nom); +static void eventReset(); +int GetResetNumber(); +int ReadName(); + +#endif /* __MASTER_H */ + diff --git a/lib/secure/daemon/mudinfo.c b/lib/secure/daemon/mudinfo.c new file mode 100644 index 0000000..f16e291 --- /dev/null +++ b/lib/secure/daemon/mudinfo.c @@ -0,0 +1,293 @@ +#include +#include +#include +#include NETWORK_H + +inherit LIB_DAEMON; + +mapping MudList = ([]); +mapping Unconnected = ([]); +mapping Status = ([]); +mapping Confirmed = ([]); +int attempting, connected, socket ; +object person, player; +string preset; +int age, probing; +string *queue = ({}); +static string SaveFile; + +int SetQueue(string str){ + if(file_exists(str)){ + foreach(string line in explode(read_file(str),"\n")){ + queue += ({ trim(line) }); + } + } + return 1; +} + +int SetProbing(int x){ + if(x) probing = 1; + else probing = 0; + this_object()->PrintUnconnectedInfo(); + return probing; +} + +string GetMudName(string mud){ + if( MudList[mud] ) return mud; + foreach(string name in keys(MudList)){ + if(lower_case(name) == lower_case(mud)) return name; + } + return 0; +} + +int PrintMudInfo(string str){ + mixed *info; + mixed *list; + mapping borg; + string mud, tempy; + int all = 0; + if(!MudList && unguarded((: file_exists(SaveFile) :))){ + RestoreObject(SaveFile, 1); + } + if(!MudList) MudList = ([]); + if(!str || str == "all"){ + write("Total muds: "+sizeof(MudList)); + write("Muds: "+implode(sort_array(keys(MudList), 1),", ")); + return 1; + } + + list = INTERMUD_D->GetMudList(); + if(mapp(list)){ + foreach(mixed key, mixed val in list){ + MudList[key] = val; + } + } + + if(sizeof(str) && sizeof(tempy = INTERMUD_D->GetMudName(str) )) str = tempy; + if(!tempy){ + if(MudList) tempy = GetMudName(str); + } + if(!tempy){ + write("Mud not found."); + return 1; + } + info = INTERMUD_D->GetMudList()[tempy]; + if(!info) info = MudList[tempy]; + if(!info){ + write("No information available on "+tempy); + return 1; + } + write("Mudname: "+tempy); + write("Status: "+(info[0] < 0 ? "online" : "offline")); + write("IP address: "+info[1]); + write("Port: "+info[2]); + write("imud out-of-band (tcp OOB) port: "+info[3]); + write("imud udp port (obsolete): "+info[4]); + write("mudlib: "+info[5]); + write("base mudlib: "+info[6]); + write("driver: "+info[7]); + write("mud type: "+info[8]); + write("open status: "+info[9]); + write("admin email: "+info[10]); + if(sizeof(info[11])){ + string tmp = "Services: "; + foreach(mixed key, mixed val in info[11]){ + if(val) tmp += key+" "; + } + write(tmp+"\n"); + } + if(sizeof(info[12])){ + write("extra info\n---------- "); + foreach(mixed key, mixed val in info[12]){ + write(identify(key)+": "+identify(val)); + } + } + return 1; +} + +int ReceiveMudInfo(string str,mapping info){ + if(!MudList[str]) MudList[str] = info; + return sizeof(MudList[str]); +} + +void GenerateConnectionPage(){ + string ret = ""; + foreach(mixed key in sort_array(keys(MudList),1)){ + mapping val = MudList[key]; + if(val[0] < 0){ + ret += key + " "; + ret += val[6] + " "; + ret += val[1]+" "+val[2]+"
"; + } + } + write_file("/www/mudlist.html",ret,1); +} + +void create(){ + mapping list = INTERMUD_D->GetMudList(); + SaveFile = save_file(SAVE_MUDINFO); + attempting = 0 ; + connected = 0 ; + socket = 0 ; + person = 0 ; + set_heart_beat(1); + if(unguarded((: file_exists(SaveFile) :))){ + RestoreObject(SaveFile); + } + if(mapp(list)){ + foreach(mixed key, mixed val in list){ + if(!MudList[key]) MudList[key] = val; + } + } + SaveObject(SaveFile); +} + +int PrintUnconnectedInfo(){ + int rebuild; + if(!Unconnected) Unconnected = ([]); + if(!sizeof(Unconnected)) rebuild = 1; + foreach(mixed key, mixed val in MudList){ + if(val[0] != -1){ + if(this_player()) write(key+": telnet "+val[1]+" "+val[2]); + if(rebuild) Unconnected[key] = ([ "ip": val[1], "port" : val[2] ]); + } + } + return 1; +} + +void heart_beat(){ + if(!this_object()) return; + if(time() > age + 2){ + this_object()->do_reset(); + } + if(sizeof(queue)){ + this_object()->do_connect(queue[0], queue[0]); + if(sizeof(queue) > 1) queue = queue[1..]; + else queue = ({}); + } + else if(probing && !connected && !attempting && sizeof(Unconnected)){ + string target = keys(Unconnected)[0]; + this_object()->do_connect(Unconnected[target]["ip"]+ + " "+Unconnected[target]["port"], target); + map_delete(Unconnected, target); + } +} + +void SetConnection(string str){ + if(str) preset = str; +} + +int do_reconnect() +{ + if( !connected ) + { + notify_fail( "The telnet client is not connected!\n" ) ; + return 0 ; + } + write("Reconnecting into telnet session.\n"); + person = this_player() ; + input_to( "parse_comm", 0 ) ; + return 1 ; +} + +int do_reset( string args ) +{ + if( socket ){ + socket_close( socket ) ; + } + attempting = 0 ; + connected = 0 ; + socket = 0 ; + return 1 ; +} + +varargs int do_connect(string args, string mud){ + int new_socket, sc_result, port ; + string error, ip_address ; + + if(preset) args = preset; + + if( sscanf( args, "%s %d", ip_address, port ) != 2 ){ + return 0 ; + } + if( attempting || connected ){ + return 0 ; + } + new_socket = socket_create( STREAM, "read_callback", "close_callback" ) ; + if( new_socket < 0 ){ + switch( new_socket ){ + case EEMODENOTSUPP : + error = "Socket mode not supported.\n" ; + break ; + case EESOCKET : + error = "Problem creating socket.\n" ; + break ; + case EESETSOCKOPT : + error = "Problem with setsockopt.\n" ; + break ; + case EENONBLOCK : + error = "Problem with setting non-blocking mode.\n" ; + break ; + case EENOSOCKS : + error = "No more available efun sockets.\n" ; + break ; + case EESECURITY : + error = "Security violation attempted.\n" ; + break ; + default : + error = "Unknown error code: " + new_socket + ".\n" ; + break ; + } + return 0 ; + } + sc_result = socket_connect( new_socket, ip_address + " " + port, + "read_callback", "write_callback" ) ; + if( sc_result != EESUCCESS ){ + return 0 ; + } + attempting = 1 ; + socket = new_socket ; + age = time(); + if(!Status) Status = ([]); + Status[new_socket] = mud; + return 1 ; +} + +void read_callback( int fd, mixed message ){ + if(!Confirmed) Confirmed = ([]); + if(!Confirmed[Status[fd]]) Confirmed[Status[fd]] = (["banner" : message, ]); + else Confirmed[Status[fd]]["banner"] += message; +} + +void close_callback( int fd ){ + socket_close( fd ) ; + attempting = 0 ; + connected = 0 ; + socket = 0 ; +} + +void write_callback( int fd ){ + attempting = 0 ; + connected = 1 ; +} + +int parse_comm( string str ){ + if(str=="dcon" || str=="quit"){ + socket_close( socket ) ; + attempting = 0 ; + connected = 0 ; + socket = 0 ; + person = 0 ; + return 1 ; + } + else { + if( !connected ){ + return 1 ; + } + if( attempting ){ + return 1 ; + } + socket_write( socket, str + "\n" ) ; + return 1 ; + } +} diff --git a/lib/secure/daemon/oob.c b/lib/secure/daemon/oob.c new file mode 100644 index 0000000..9a79242 --- /dev/null +++ b/lib/secure/daemon/oob.c @@ -0,0 +1,330 @@ +#include NETWORK_H +#include +#include + +inherit LIB_DAEMON; +inherit LIB_CLIENT; + +string globalmud; +string array allfiles; +string mcolor = "magenta"; + +mapping RequestedFiles = ([]); + +mapping SentMudTokens = ([]); +mapping ReceivedMudTokens = ([]); + +mapping OutgoingSessions = ([]); +mapping IncomingSessions = ([]); + +string array waiting_auth = ({}); +object array Clients = ({}); + +mixed globalvar, g1, g2; + +void StartServer(); +void StopServer(); + +static private void validate() { + if( !(master()->valid_apply(({ "SECURE" }))) ) + error("Illegal attempt to access OOB_D: "+get_stack()+" "+identify(previous_object(-1))); +} + +void create(){ + daemon::create(); +} + +varargs mixed eventBeginOOB(string mud, int token, mixed *data){ + object ob; + mapping MudList = INTERMUD_D->GetMudList(); + int port = MudList[mud][11]["oob"]; + string ip = MudList[mud][1]; + if(sizeof(MudList[mud][12]) && + MudList[mud][12]["ip"] && + MudList[mud][12]["ip"] != "127.0.0.1") + ip = MudList[mud][12]["ip"]; + validate(); + trr("OOB_D.eventBeginOOB, mud: "+mud+", token: "+token,"yellow",MSG_OOB); + if(!port || !ip) return; + if(!OutgoingSessions[mud]) OutgoingSessions[mud] = ({}); + if(data && sizeof(data)) ob = new(LIB_OOB, ip, token, port, data); + else ob = new(LIB_OOB, ip, token, port); + if(ob){ + trr("OOB_D.eventBeginOOB, ob: "+identify(ob),"yellow",MSG_OOB); + OutgoingSessions[mud] += ({ ob }); + Clients += ({ ob }); + return ob; + } + else { + trr("OOB_D.eventBeginOOB: there is no new ob created. Weird.","red",MSG_OOB); + return 0; + } +} + +string clean_fd(string fd){ + if(grepp(fd," ")){ + string *ip_split=explode(fd," "); + fd = ip_split[0]; + } + return fd; +} + +void Report(){ + validate(); + trr("SentMudTokens: "+identify(SentMudTokens),"yellow"); + trr("ReceivedMudTokens: "+identify(ReceivedMudTokens),"cyan"); + trr("IncomingSessions: "+identify(IncomingSessions),"white"); + trr("OutgoingSessions: "+identify(OutgoingSessions),"green"); + trr("RequestedFiles: "+identify(RequestedFiles),"blue"); +} + +void SentToken(string mud, int token){ + if(base_name(previous_object()) != SERVICES_D) return 0; + if(!SentMudTokens[mud]) SentMudTokens[mud] = ([]); + SentMudTokens[mud]["token"] = token; + SentMudTokens[mud]["token_time"] = time(); +} + +void ReceivedToken(string mud, int token){ + if(base_name(previous_object()) != SERVICES_D) return 0; + if(!ReceivedMudTokens[mud]) ReceivedMudTokens[mud] = ([]); + ReceivedMudTokens[mud]["token"] = token; + ReceivedMudTokens[mud]["token_time"] = time(); + if(member_array(mud, waiting_auth) != -1){ + eventBeginOOB(mud, token); + waiting_auth -= ({ mud }); + } +} + +int AuthenticateReceivedToken(string mud){ + if( ReceivedMudTokens[mud] && ReceivedMudTokens[mud]["token"] ) return 1; + else return 0; +} + +mapping GetTokens(string arg){ + if(base_name(previous_object()) != SERVICES_D) return 0; + if(arg) return ReceivedMudTokens[arg]; + else return copy(ReceivedMudTokens); +} + +int RequestToken(string target){ + if(!target || !(target = INTERMUD_D->GetMudName(target))) return 0; + if(!ReceivedMudTokens[target] || !ReceivedMudTokens[target]["token"]) + INTERMUD_D->eventWrite(({ "auth-mud-req", 5, mud_name(), 0,target, 0 })); + return 1; +} + +varargs mixed RequestBegin(string target, mixed *data){ + string ip; + int port; + int token; + mixed ret = 1; + validate(); + if(!target || !(target = INTERMUD_D->GetMudName(target))) return 0; + if(!ReceivedMudTokens[target] || !ReceivedMudTokens[target]["token"]) + RequestToken(target); + ip = INTERMUD_D->GetMudList()[target][1]; + if(sizeof(INTERMUD_D->GetMudList()[target][12]) && + INTERMUD_D->GetMudList()[target][12]["ip"] && + INTERMUD_D->GetMudList()[target][12]["ip"] != "127.0.0.1") + ip = INTERMUD_D->GetMudList()[target][12]["ip"]; + port = INTERMUD_D->GetMudList()[target][11]["oob"]; + if( eventCreateSocket(ip, port) < 0 ){ + trr("OOB_D.RequestBegin: couldn't create outbound socket",mcolor,MSG_OOB); + return 0; + } + else trr("OOB_D.RequestBegin socket created",mcolor,MSG_OOB); + if(member_array(target, waiting_auth) == -1 && (!ReceivedMudTokens[target] || + !ReceivedMudTokens[target]["token"]) ){ + RequestToken(target); + if(data) call_out( (: RequestBegin( $(target), $(data) ) :), 5); + else call_out( (: RequestBegin( $(target) ) :), 5); + return 0; + } + else if( ReceivedMudTokens[target] && ReceivedMudTokens[target]["token"] ){ + if(data && sizeof(data)) + ret = eventBeginOOB(target, ReceivedMudTokens[target]["token"], data); + else ret = eventBeginOOB(target, ReceivedMudTokens[target]["token"]); + } + return ret; +} + +int RequestEnd(int fd){ + validate(); + eventWrite( ({ "oob-end", mud_name() }) ); + return 1; +} + +varargs void write_data(mixed arg, object oob){ + validate(); + if(sizeof(Clients) && !oob){ + foreach(object ob in Clients){ + if(ob) ob->write_data(arg); + } + return; + } + oob->write_data(arg); +} + +void eventRead(mixed foo){ + validate(); +} + +varargs mixed send_file(string str, object oob){ + string *arr; + string tmp; + int i = 0; + validate(); + trr("OOB_D.send_file str: "+identify(str),"cyan",MSG_OOB); + if(oob) trr("OOB_D.send_file oob: "+identify(oob),"cyan",MSG_OOB); + + if( !str ) trr("You must specify a file to cat.","cyan",MSG_OOB); + str = trim(str); + if( !file_exists(str) ) trr("File " + str + " not found.","cyan",MSG_OOB); + else if( !(tmp = read_file(str)) ) + trr("Unable to read file " + str + ".","cyan",MSG_OOB); + if( !(tmp = read_file(str)) ) { + trr("File " + str + " not readable","cyan",MSG_OOB); + return 0; + } + arr = explode(tmp,"\n"); + if(file_size(str) > 60000){ + trr("OOB_D.send_file: file too large. Send of "+str+" %^WHITE%^FAILED%^RESET%^."); + return 1; + } + if(!strsrch(str,"/secure/upgrades/txt/upgrades.")) + str = "/secure/upgrades/txt/upgrades.txt"; + if(!strsrch(str,"/secure/upgrades/txt/mud_info.")) + str = "/secure/sefun/mud_info.c"; + trr("OOB_D.send_file str: "+identify(str),"cyan",MSG_OOB); + foreach(string line in arr){ + i++; + if(oob) write_data( ({ "oob-file", str, i, line }), oob ); + else write_data( ({ "oob-file", str, i, line }) ); + } + trr("OOB_D.send_file: sent.","cyan",MSG_OOB); + return 1; +} + +varargs void call_send_file(string str, object oob){ + g1 = str; + g2 = oob; + call_out( (:send_file, g1, g2 :), 2); +} + +string FindMud(object ob){ + validate(); + foreach(mixed key, mixed val in OutgoingSessions){ + foreach(mixed element in val){ + if(ob && ob == element) return key; + } + } + foreach(mixed key, mixed val in IncomingSessions){ + foreach(mixed element in val){ + if(ob && ob == element) return key; + } + } + return ""; +} + +void RegisterNewIncoming(string name){ + validate(); + if(!IncomingSessions[name]) IncomingSessions[name] = ({}); + IncomingSessions[name] += ({ previous_object() }); + Clients += ({ previous_object() }); +} + +void RemoveIncoming(string mud){ + validate(); + trr("OOB_D.RemoveIncoming: "+identify(previous_object())+" is asking to be removed from "+mud,mcolor,MSG_OOB); + if(!IncomingSessions[mud]) IncomingSessions[mud] = ({}); + IncomingSessions[mud] -= ({ previous_object() }); + Clients -= ({ previous_object() }); +} + +void AddRequestedFile(string mud, string file){ + validate(); + if((this_player() && securep(this_player())) || base_name(previous_object()) == LIB_OOB){ + if(!RequestedFiles[mud]) RequestedFiles[mud] = ({}); + RequestedFiles[mud] += ({ file }); + } +} + +void RemoveRequestedFile(string mud, string file){ + validate(); + if(base_name(previous_object()) == LIB_OOB){ + if(!RequestedFiles[mud]) RequestedFiles[mud] = ({}); + RequestedFiles[mud] -= ({ file }); + } +} + +int AuthenticateFile(string mud, string file){ + if(!RequestedFiles[mud] || member_array(file, RequestedFiles[mud]) == -1) return 0; + else return 1; +} + +mixed SendFile(string str){ + mixed target; + object which = previous_object(); + string mud = FindMud(which); + validate(); + trr("OOB_D.SendFile: which: "+file_name(which),mcolor,MSG_OOB); + if(base_name(which) != LIB_OOB) return 0; + target = RequestBegin(mud); + trr("OOB_D.SendFile: target: "+identify(target),mcolor,MSG_OOB); + trr("OOB_D.SendFile: str: "+identify(str),mcolor,MSG_OOB); + trr("OOB_D.SendFile: mud: "+identify(mud),mcolor,MSG_OOB); + if(target && objectp(target)){ + trr("OOB_D.SendFile: target found!",mcolor,MSG_OOB); + send_file(str, target); + target->write_data(({"oob-end", "oob-file send complete." }) ); + } + else { + trr("OOB_D.SendFile: no target",mcolor,MSG_OOB); + send_file(str); + write_data(({"oob-end", "oob-file send complete." }) ); + } + return 1;} + + mixed GetFile(string mud, mixed file){ + validate(); + if(stringp(file)) AddRequestedFile(mud, file); + else if(arrayp(file)) + foreach(string element in file){ + AddRequestedFile(mud, element); + } + RequestBegin(mud, ({ "oob-file-req", file }) ); + return 1; + } + +int eventMajorUpgrade(string mud, string *files){ + int interval = 0; + validate(); + allfiles = sort_array(files,1); + globalmud = mud; + GetFile(globalmud, allfiles); + return 1; +} + +mixed SendMail(mapping mail){ + mixed target; + validate(); + trr("OOB_D.SendMail: mail: "+identify(mail),mcolor,MSG_OOB); + foreach(mixed key, mixed val in mail){ + if(sizeof(val)){ + foreach(mixed id, mixed message in val){ + target = RequestBegin(key, message); + trr("OOB_D.SendMail: target: "+identify(target),mcolor,MSG_OOB); + trr("OOB_D.SendMail: mud: "+identify(key),mcolor,MSG_OOB); + if(target && objectp(target)){ + trr("OOB_D.SendMail: target found!",mcolor,MSG_OOB); + target->write_data(message); + } + else { + trr("OOB_D.SendMail: no target",mcolor,MSG_OOB); + } + } + } + } + return 1; +} diff --git a/lib/secure/daemon/options.c b/lib/secure/daemon/options.c new file mode 100644 index 0000000..c1d7783 --- /dev/null +++ b/lib/secure/daemon/options.c @@ -0,0 +1,114 @@ +/* /daemon/postal/options.c + * from Dead Souls + * IIPS options management system + * created by Descartes of Borg 940502 + */ + +#include +#include +#include +#include +#include "options.h" + +inherit LIB_DAEMON; + +private mapping __MyGroups; +private mapping __Options; +static private string __Owner; + +void create() { + daemon::create(); + SetNoClean(1); + __MyGroups = ([]); + __Options = (["notify" : 1]); + __Owner = 0; +} + +static private int valid_access() { + switch(base_name(previous_object(0))) { + case OBJ_POST: case FOLDERS_D: case LETTERS_D: + case LOCALPOST_D: case REMOTEPOST_D: case OPTIONS_D: + return 1; + default: return 0; + } +} + +void assure_box_exists(string who) { + string file; + + if(!valid_access()) return; + if(__Owner == who) return; + file = save_file(DIR_POSTAL+"/"+who[0..0]+"/"+who+"/postalrc"); + if(unguarded((: file_exists, file :))) return; + file = DIR_POSTAL+"/"+who[0..0]; + if(unguarded((: file_size, file :)) != -2) unguarded((: mkdir, file :)); + file = DIR_POSTAL+"/"+who[0..0]+"/"+who; + if(unguarded((: file_size, file :)) != -2) unguarded((: mkdir, file :)); + __MyGroups = ([]); + __Options = (["notify":1]); + __Owner = who; + SaveObject(file+"/postalrc"); +} + +static private void load_options(string who) { + string file; + if(who == __Owner) return; + this_object()->assure_box_exists(who); + if(__Owner == who) { + return; + } + __Owner = who; + file = DIR_POSTAL+"/"+who[0..0]+"/"+who+"/postalrc"; + RestoreObject(file); +} + +static private void save_options() { + string file; + file = DIR_POSTAL+"/"+__Owner[0..0]+"/"+__Owner+"/postalrc"; + SaveObject(file); +} + +void set_option(string who, string option, mixed value) { + if(base_name(previous_object()) != OBJ_POST) return; + load_options(who); + __Options[option] = value; + save_options(); +} + +mixed query_option(string who, string option) { + string tmp; + + tmp = base_name(previous_object()); + if(tmp != OBJ_POST && tmp != LOCALPOST_D && tmp != FOLDERS_D) return 0; + load_options(who); + return __Options[option]; +} + +mapping query_options(string who) { + string tmp; + + tmp = base_name(previous_object()); + if(tmp != OBJ_POST && tmp != LOCALPOST_D && tmp != FOLDERS_D) return ([]); + load_options(who); + return copy(__Options); +} + +void set_group(string who, string group, string *members) { + if(!valid_access()) return; + load_options(who); + if(!members) map_delete(__MyGroups, group); + else __MyGroups[group] = members; + save_options(); +} + +string *query_group(string who, string group) { + if(!valid_access()) return ({}); + load_options(who); + return copy(__MyGroups[group]); +} + +mapping query_groups(string who) { + if(!valid_access()) return ([]); + load_options(who); + return copy(__MyGroups); +} diff --git a/lib/secure/daemon/options.h b/lib/secure/daemon/options.h new file mode 100644 index 0000000..8528703 --- /dev/null +++ b/lib/secure/daemon/options.h @@ -0,0 +1,14 @@ +#ifndef __OPTIONS_D_H +#define __OPTIONS_D_H + +static private int valid_access(); +void assure_box_exists(string who); +static private void load_options(string who); +static private void save_options(); +void set_option(string who, string option, mixed value); +mixed query_option(string who, string option); +void set_group(string who, string group, string *members); +string *query_group(string who, string group); +mapping query_groups(string who); + +#endif /* __OPTIONS_D_H */ diff --git a/lib/secure/daemon/persistence.c b/lib/secure/daemon/persistence.c new file mode 100644 index 0000000..3359ab0 --- /dev/null +++ b/lib/secure/daemon/persistence.c @@ -0,0 +1,7 @@ +#include +inherit LIB_DAEMON; + +void create(){ + daemon::create(); +} + diff --git a/lib/secure/daemon/ping.c b/lib/secure/daemon/ping.c new file mode 100644 index 0000000..d086878 --- /dev/null +++ b/lib/secure/daemon/ping.c @@ -0,0 +1,104 @@ +#include +#include ROOMS_H +#include + +inherit LIB_DAEMON; + +int Pinging = 0; +int OK = 0; +int Retries = 0; +int counter = 0; +int last_time = time(); + +string *muds = PINGING_MUDS + ({ mud_name() }); + +int CheckOK(){ + string list = load_object("/cmds/players/mudlist")->cmd(""); + Pinging = 0; + if(DISABLE_INTERMUD) return 1; + if(!OK){ + Retries++; + update(INTERMUD_D); + } + else { + if(Retries > 0 && INTERMUD_D->GetConnectedStatus()){ + tell_room(ROOM_ARCH,"The Arch Room loudspeaker announces: \"%^BOLD%^CYAN%^" + "Intermud connection is %^BOLD%^GREEN%^ONLINE%^BOLD%^CYAN%^.%^RESET%^\""); + load_object(ROOM_ARCH)->SetImud(1); + } + + Retries = 0; + } + if(Retries == 2 && !(INTERMUD_D->GetConnectedStatus())){ + tell_room(ROOM_ARCH,"The Arch Room loudspeaker announces: \"%^BOLD%^CYAN%^" + "Intermud connection is %^BOLD%^RED%^OFFLINE%^BOLD%^CYAN%^.%^RESET%^\""); + rm("/tmp/muds.txt"); + load_object(ROOM_ARCH)->SetImud(0); + } + write_file("/www/mudlist.txt",timestamp()+"\n",1); + write_file("/www/mudlist.txt",""+list); + return 1; +} + +int eventPing(){ + mixed chans; + if(DISABLE_INTERMUD) return 1; + chans = INTERMUD_D->GetChannels(); + Pinging = 1; + OK = 0; + if(!sizeof(muds)) { + Pinging = 0; + return 0; + } + foreach(string mud in muds){ + INTERMUD_D->eventWrite(({ "auth-mud-req", 5, mud_name(), 0, mud, 0 })); + } + if(!sizeof(chans)){ + string rtr = INTERMUD_D->GetNameservers()[0][0]; + INTERMUD_D->eventWrite(({ "chanlist-req", 5, mud_name(), 0, rtr, 0 })); + } + return 1; +} + +void create() { + daemon::create(); + SetNoClean(1); + if(!DISABLE_INTERMUD) set_heart_beat(1); + else { + set_heart_beat(0); + Pinging = 0; + } +} + +void DeadMan(){ + // This breaks things. + // int tmptime = time(); + // if(last_time + 60 < tmptime){ + // object *clones = filter(objects(), (: inherits(LIB_ROOM,$1) :)); + // clones->eventDestruct(); + // + // clones = filter(objects(), (: clonep($1) :)); + // clones->eventDestruct(); + // } + // else last_time = tmptime; +} + +void heart_beat(){ + counter++; + DeadMan(); + if(!DISABLE_INTERMUD){ + if(!(counter % (PING_INTERVAL + 2))) CheckOK(); + if(!(counter % (PING_INTERVAL))) eventPing(); + } + if(counter > (PING_INTERVAL * 1000)) counter = 0; +} + +int GetPinging(){ + return Pinging; +} + +int SetOK(){ + if(DISABLE_INTERMUD) return 1; + OK = 1; + load_object(ROOM_ARCH)->SetImud(1); +} diff --git a/lib/secure/daemon/players.c b/lib/secure/daemon/players.c new file mode 100644 index 0000000..f4cb194 --- /dev/null +++ b/lib/secure/daemon/players.c @@ -0,0 +1,844 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef AUTO_ADVANCE +#define AUTO_ADVANCE 0 +#endif +#ifndef REQUIRE_QUESTING +#define REQUIRE_QUESTING 1 +#endif +#ifndef ENABLE_INSTANCES +#define ENABLE_INSTANCES 0 +#endif + +inherit LIB_DAEMON; + +mapping PlayerDataMap = ([]); +mapping UserData = ([]); +string *PendingEncres = ({}); +string *PendingDecres = ({}); +string *PendingPauses = ({}); +string *PendingUnpauses = ({}); +string *players = ({}); +string *creators = ({}); +string *user_list = ({}); +static object ob; +static string gplayer, SaveFile; +static int maxlevel, override; +static string home_dir, LevelList = ""; + +string player_save_file; +static string namestr = ""; + +//Player vars +string InternalDesc, Short, CapName, ExternalDesc, CurrentWorkingDirectory, PreviousWorkingDirectory, Terminal; +string Password, Email, RealName, Rank, LoginSite, HostSite, Torso, DefaultLanguage, Town, Race; +string Gender, Class, WimpyCommand, InternalDesc, WebPage, Clan; +int ProperNoun, Opacity, Modify, Invisible, NoChanColors, Paused, MaxCommandHistSize, HistorySize; +int Age, WhereBlock, Brief, LoginTime, BirthTime, RescueBit, CarriedMass, MaxCarry, Position; +int Undead, UndeadType, Mount, BodyMass, SaveRecurse, Retain, HealthPoints, MagicPoints, ExperiencePoints; +int QuestPoints, melee, Alcohol, Caffeine, Food, Drink, Poison, Sleeping, DeathEvents, Biter; +int Blind, CustomStats, Wimpy, Polyglot, Level, Morality, Dead, isPK, Deaths, TrainingPoints; +int TitleLength, CreatorAge, CreatorBirth; +object Agent; +float StaminaPoints; +mixed array Inventory, CommandHist, Screen, Marriages, Saved, ExtraChannels, LightSensitivity; +mixed array Religion, Titles, Muffed, Quests; +mapping Items, Properties, Messages, RestrictedChannels, Nicknames, Aliases, Xverbs, Blocked; +mapping News, Fingers, Limbs, MissingLimbs, Resistance, Stats, Languages, Skills, SkillModifiers; +mapping Currency, Bank, SpellBook; +//end player vars + +mapping Levels = ([]); +static mapping LevelTitles = ([ + 1:"the utter novice", + 2:"the simple novice", + 3:"the beginner", + 4:({"the adventurer","the adventuress"}), + 5:({"the experienced adventurer","the experienced adventuress"}), + 6:({"the expert adventurer","the expert adventuress"}), + 7:({"the great adventurer","the great adventuress"}), + 8:({"the master adventurer","the master adventuress"}), + 9:({"the Freeman","the Freewoman"}), + 10:"the Citizen", + 11:"the Knight", + 12:({"the Baron","the Baroness"}), + 13:({"the Count","the Viscountess"}), + 14:({"the Earl","the Countess"}), + 15:({"the Marquis","the Marquise"}), + 16:({"the Duke","the Duchess"}), + 17:({"the Archduke","the Archduchess"}), + 18:({"the Praetor","the Praetrix"}), + 19:({"the Quaestor","the Quaestrix"}), + 20:({"the Caesar","the Caesara"}), + ]); + +static mapping QuestLevels = ([ + 10:5, + 12:12, + 14:21, + 16:32, + 18:45, + 20:60, + 22:77, + 24:96, + 26:117, + 28:140, + 30:165, + 32:192, + 34:221, + 36:252, + 38:285, + 40:450, + ]); + + +void validate(){ + if(!master()->valid_apply(({ "SECURE", "ASSIST", "LIB_CONNECT" })) && + base_name(previous_object()) != CGI_LOGIN && !override && + base_name(previous_object()) != CMD_RID && + base_name(previous_object()) != CMD_SUICIDE){ + string offender = identify(previous_object(-1)); + debug("PLAYERS_D SECURITY VIOLATION: "+offender+" ",get_stack(),"red"); + log_file("security", "\n"+timestamp()+" PLAYERS_D breach: "+offender+" "+get_stack()); + error("PLAYERS_D SECURITY VIOLATION: "+offender+" "+get_stack()); + } + override = 0; +} + +// This function generates a table of required xp per level. +// The xp required for lower levels is high, approximately +// half-again the xp required for the previous level. As the +// player progresses, this ratio decreases. +mapping CompileLevelList(){ + int i=1; + mixed title; + int seed=300; + float mod; + LevelList = ""; + Levels = ([ 0 : ([ "xp" : 0, "qp" : 0 ]) ]); + Levels[1] = ([ "title" : "the utter novice ", "xp" : 0, "qp" : 0 ]); + while(seed > 0){ + i++; + mod = 50/i; + if(mod > 9) mod = 9.0; + if(mod < 1) mod = 0.5; + if(i > 100) mod = 0.1; + mod *= 0.1; + seed = seed * (1+mod); + seed = ((seed/100) * 100); + LevelList += "level: "+i+", "; + if(seed > 0){ + Levels[i] = (["xp" : seed ]); + if(REQUIRE_QUESTING){ + if(QuestLevels[i]){ + Levels[i]["qp"] = QuestLevels[i]; + } + } + else Levels[i]["qp"] = 0; + if(title = LevelTitles[i]){ + string line; + if(stringp(title)) line = title; + else line = implode(title, "/"); + Levels[i]["title"] = line; + } + maxlevel = i; + LevelList += ( Levels[i]["title"] || "Untitled" ); + LevelList += ", exp: "+seed; + LevelList += ( Levels[i]["qp"] ? ", qp: "+Levels[i]["qp"] : ""); + LevelList += "\n"; + } + if(seed >= 2146000000) break; + } + return copy(Levels); +} + +static void ScheduledPlayerAdd(string *plays){ + foreach(string play in plays){ + this_object()->AddPlayerInfo(play); + } +} + +string *CompileCreList(){ + string *cre_dirs = unguarded( (: get_dir(DIR_CRES+"/") :) ); + string *cres = ({}); + string *cache = ({}); + int i; + creators = ({}); + if(!user_list) user_list = ({}); + foreach(string subdir in cre_dirs){ + cres += unguarded( (: get_dir(DIR_CRES+"/"+$(subdir)+"/") :) ); + } +#if ENABLE_INSTANCES + cres = filter(cres, (: grepp($1, ""+__PORT__) :) ); +#else + cres = filter(cres, (: sscanf($1, "%*s.%*s.o") == 1 :) ); +#endif + foreach(string cre in cres){ + string sub; +#if ENABLE_INSTANCES + sub = replace_string(cre, "."+__PORT__+".o", ""); + sub = replace_string(sub, ".o",""); +#else + sub = replace_string(cre, ".o",""); +#endif + if(sub && !grepp(sub, ".") && + (member_array(sub, user_list) == -1 || + member_array(sub, creators) == -1)){ + cache += ({ sub }); + } + + if(sizeof(cache) > 20){ + call_out("ScheduledPlayerAdd", i, cache); + cache = ({}); + } + } + if(sizeof(cache)){ + call_out("ScheduledPlayerAdd", i, cache); + } + return cres; +} + +string *CompilePlayerList(){ + string *play_dirs = unguarded( (: get_dir(DIR_PLAYERS+"/") :) ); + string *plays = ({}); + string *cache = ({}); + int i; + players = ({}); + if(!user_list) user_list = ({}); + foreach(string subdir in play_dirs){ + mixed tmp_plays = unguarded((: get_dir,DIR_PLAYERS+"/"+subdir+"/" :)); + if(tmp_plays) plays += tmp_plays; + } +#if ENABLE_INSTANCES + plays = filter(plays, (: grepp($1, ""+__PORT__) :) ); +#else + plays = filter(plays, (: sscanf($1, "%*s.%*s.o") == 1 :) ); +#endif + foreach(string play in plays){ + string sub; +#if ENABLE_INSTANCES + sub = replace_string(play, "."+__PORT__+".o", ""); + sub = replace_string(sub, ".o",""); +#else + sub = replace_string(play, ".o",""); +#endif + if(sub && !grepp(sub, ".") && + (member_array(sub, user_list) == -1 || + member_array(sub, players) == -1)){ + cache += ({ sub }); + } + + if(sizeof(cache) > 20){ + call_out("ScheduledPlayerAdd", i, cache); + cache = ({}); + } + } + if(sizeof(cache)){ + call_out("ScheduledPlayerAdd", i, cache); + } + return plays; +} + +void create() { + int ret; + ::create(); + SaveFile = save_file(SAVE_PLAYER_LIST); + ret = RestoreObject(SaveFile); + if(PendingEncres) PendingEncres = distinct_array(PendingEncres); + if(PendingDecres) PendingDecres = distinct_array(PendingDecres); + if(PendingPauses) PendingPauses = distinct_array(PendingPauses); + if(PendingUnpauses) PendingUnpauses = distinct_array(PendingUnpauses); + if(players) players = distinct_array(players); + else players = ({}); + if(creators) creators = distinct_array(creators); + else creators = ({}); + if(user_list) user_list = distinct_array(user_list); + else user_list = ({}); + SaveObject(SaveFile); + if(!Levels) Levels = ([]); + if(!UserData) UserData = ([]); + call_out( (: CompileLevelList :), 3); + call_out( (: CompileCreList :), 1); + call_out( (: CompilePlayerList :), 5); + call_out( "SelektUsers", 604800, 1 ); +} + +string *eventCre(string str){ + str = lower_case(cleaned_name(str)); + if(member_array(str,creators) == -1) creators += ({ str }); + if(member_array(str,players) != -1) players -= ({ str }); + SaveObject(SaveFile); + return copy(creators); +} + +string *eventDecre(string str){ + str = lower_case(str); + if(member_array(str,creators) != -1) creators -= ({ str }); + if(member_array(str,players) == -1) players += ({ str }); + SaveObject(SaveFile); + return players + ({}); +} + +static int AutoAdvance(object ob, int level){ + int ret; + ob->ChangeLevel(level); + ret = ob->GetLevel(); + if(ret >= level){ + ob->eventPrint("%^RED%^%^B_BLACK%^You automatically advance to "+ + "level "+level+". Congratulations!%^RESET%^"); + ob->AddTrainingPoints(level); + if(LevelTitles[level]){ + ob->AddTitle(LevelTitles[level]); + ob->RemoveTitle(LevelTitles[level-1]); + } + } + return ret; +} + +int CheckAdvance(object ob){ + int dlev, xp, qp; + if(!ob || !playerp(ob)) return 0; + if(!sizeof(Levels)) CompileLevelList(); + dlev = (ob->GetLevel())+1; + if(!Levels[dlev]) return 0; + xp = ob->GetExperiencePoints(); + qp = ob->GetQuestPoints(); + if(xp >= Levels[dlev]["xp"] && qp >= Levels[dlev]["qp"]){ + if(AUTO_ADVANCE) AutoAdvance(ob, dlev); + return 1; + } + return 0; +} + +void AddPlayerInfo(mixed arg){ + if(!objectp(arg) && !stringp(arg)){ + return ; + } + if(!creators) creators = ({}); + if(!players) players = ({}); + if(!user_list) user_list = ({}); + if(objectp(arg)){ + if(base_name(previous_object())!=LIB_CONNECT &&!interactive(arg)){ + return; + } + else player_save_file = base_name(arg)+".o"; + } + else { + arg = lower_case(arg); + if(last(arg,2) != ".o") arg += ".o"; + if(!grepp(arg,"/")){ + string initial = arg[0..0]; + if(!directory_exists(DIR_ESTATES)) + mkdir(DIR_ESTATES); + if(!directory_exists(DIR_ESTATES+"/"+initial)) + mkdir(DIR_ESTATES + "/"+initial); + mkdir(DIR_ESTATES + "/"+initial+"/"+truncate(arg,2)); + mkdir(DIR_ESTATES + "/"+initial+"/"+truncate(arg,2)+"/tmp"); + mkdir(DIR_ESTATES + "/"+initial+"/"+truncate(arg,2)+"/log"); + mkdir(DIR_ESTATES + "/"+initial+"/"+truncate(arg,2)+"/bak"); + mkdir(DIR_ESTATES + "/"+initial+"/"+truncate(arg,2)+"/adm"); + player_save_file = DIR_CRES +"/"+initial+"/"+arg; +#if ENABLE_INSTANCES + player_save_file = new_savename(player_save_file); +#endif + if(!file_exists(player_save_file)) + player_save_file = DIR_PLAYERS +"/"+initial+"/"+arg; +#if ENABLE_INSTANCES + player_save_file = new_savename(player_save_file); +#endif + if(!file_exists(player_save_file)){ + return; + } + } + else player_save_file = arg; + } +#if ENABLE_INSTANCES + player_save_file = old_savename(player_save_file); + player_save_file = new_savename(player_save_file); + namestr = replace_string(last_string_element(player_save_file,"/"), + "."+__PORT__+".o",""); +#else + namestr = replace_string(last_string_element(player_save_file,"/"),".o",""); +#endif + namestr = cleaned_name(namestr); + if(grepp(player_save_file, DIR_CRES) && + member_array(namestr,creators) == -1){ + creators += ({ namestr }) ; + } + else if(member_array(namestr,players) == -1){ + players += ({ namestr }) ; + } + if(!unguarded( (: file_exists, player_save_file :) )){ + return; + } + if(member_array(namestr,user_list) == -1){ + user_list += ({ namestr }) ; + } + SaveObject(SaveFile); +} + +string *GetPlayerList(){ + return players + ({}); +} + +string *GetCreatorList(){ + return copy(creators); +} + +string *GetUserList(){ + return copy(user_list); +} + +mapping GetLevelList(){ + if(!sizeof(Levels)) CompileLevelList(); + return copy(Levels); +} + +string GetLevels(){ + if(!sizeof(LevelList)) CompileLevelList(); + return LevelList; +} + +int RemoveUser(string str){ + string sfile, targetdir; + mixed purge_array; + object ob; + validate(); + if(!str || str == "") return 0; + str = lower_case(str); + home_dir = homedir(str); + if( member_group(str, PRIV_SECURE) || member_group(str, PRIV_ASSIST) ){ + return 0; + } + debug("REMOVE USER REQUEST: "+str, "red"); + if( ob = find_player(str) ) { + message("system", "You are being ridded from " + mud_name() + ".", + ob); + if( !(ob->eventDestruct()) ) destruct(ob); + } + purge_array = filter(objects(),(: !strsrch(base_name($1), home_dir) :)); + foreach(object tainted in purge_array){ + if(clonep(tainted)){ + catch(tainted->eventMove(ROOM_FURNACE)); + purge_array -= ({ tainted }); + } + } + foreach(object tainted in purge_array){ + catch(tainted->eventDestruct()); + if(tainted) catch(destruct(tainted)); + } + if(member_array(str, players) != -1) players -= ({ str }); + if(member_array(str, creators) != -1) creators -= ({ str }); + if(member_array(str, user_list) != -1) user_list -= ({ str }); + targetdir = DIR_RID + "/" + str[0..0]; + if(directory_exists(targetdir+"/"+str)){ + rename(targetdir+"/"+str, targetdir+"/"+str+"."+time()); + } + mkdir_recurse(targetdir+"/"+str); + sfile = player_save_file(str); + if(file_exists(sfile)){ + rename(sfile, targetdir+"/"+str+"/"+str+".bak"); + } + sfile = REALMS_DIRS + "/" + str; + if(directory_exists(sfile)) rename(sfile, targetdir+"/"+str+"/realm"); + sfile = ESTATES_DIRS + "/" + str[0..0] + "/" + str; + if(directory_exists(sfile)) rename(sfile, targetdir+"/"+str+"/estate"); + log_file("rid", "\n" + str + + " by PLAYERS_D as a trivial/unused account.\n"); + return 1; +} + +string *GetPendingPauses(){ + validate(); + if(!PendingPauses) PendingPauses = ({}); + return copy(PendingPauses); +} + +string *GetPendingUnpauses(){ + validate(); + if(!PendingUnpauses) PendingUnpauses = ({}); + return copy(PendingUnpauses); +} + +string *AddPendingPause(string str){ + validate(); + if(!PendingPauses) PendingPauses = ({}); + if(str && str != "") PendingPauses += ({ lower_case(str) }); + SaveObject(SaveFile); + return copy(PendingPauses); +} + +string *RemovePendingPause(string str){ + validate(); + if(!PendingPauses) PendingPauses = ({}); + if(!str || str == "") return copy(PendingPauses); + str = lower_case(str); + if(member_array(str, PendingPauses) != -1){ + PendingPauses -= ({ lower_case(str) }); + } + SaveObject(SaveFile); + return copy(PendingPauses); +} + +string *AddPendingUnpause(string str){ + validate(); + if(!PendingUnpauses) PendingUnpauses = ({}); + if(str && str != "") PendingUnpauses += ({ lower_case(str) }); + SaveObject(SaveFile); + return copy(PendingUnpauses); +} + +string *RemovePendingUnpause(string str){ + validate(); + if(!PendingUnpauses) PendingUnpauses = ({}); + if(!str || str == "") return copy(PendingUnpauses); + str = lower_case(str); + if(member_array(str, PendingUnpauses) != -1){ + PendingUnpauses -= ({ lower_case(str) }); + } + SaveObject(SaveFile); + return copy(PendingUnpauses); +} + +string *AddPendingEncre(string str){ + validate(); + if(!PendingEncres) PendingEncres = ({}); + if(str && str != "") PendingEncres += ({ lower_case(str) }); + SaveObject(SaveFile); + return copy(PendingEncres); +} + +string *RemovePendingEncre(string str){ + validate(); + if(!PendingEncres) PendingEncres = ({}); + if(!str || str == "") return copy(PendingEncres); + str = lower_case(str); + if(member_array(str, PendingEncres) != -1) PendingEncres -= ({ lower_case(str) }); + SaveObject(SaveFile); + return copy(PendingEncres); +} + +string *GetPendingEncres(){ + validate(); + if(!PendingEncres) PendingEncres = ({}); + return copy(PendingEncres); +} + +string *AddPendingDecre(string str){ + validate(); + if(!PendingDecres) PendingDecres = ({}); + if(str && str != "") PendingDecres += ({ lower_case(str) }); + SaveObject(SaveFile); + return copy(PendingDecres); +} + +string *RemovePendingDecre(string str){ + validate(); + if(!PendingDecres) PendingDecres = ({}); + if(!str || str == "") return copy(PendingDecres); + str = lower_case(str); + if(member_array(str, PendingDecres) != -1) PendingDecres -= ({ lower_case(str) }); + SaveObject(SaveFile); + return copy(PendingDecres); +} + +string *GetPendingDecres(){ + validate(); + if(!PendingDecres) PendingDecres = ({}); + return copy(PendingDecres); +} + +static int LoadPlayer(string str){ + string arg = "", initial = ""; + arg = last_string_element(lower_case(replace_string("/"+str,".o","")),"/"); +#if ENABLE_INSTANCES + arg = replace_string(arg, "."+__PORT__, ""); +#endif + if(!user_exists(arg)){ + return 0; + } + arg += ".o"; + initial = arg[0..0]; + player_save_file = DIR_CRES +"/"+initial+"/"+arg; +#if ENABLE_INSTANCES + player_save_file = new_savename(player_save_file); +#endif + if(!file_exists(player_save_file)){ + player_save_file = DIR_PLAYERS +"/"+initial+"/"+arg; +#if ENABLE_INSTANCES + player_save_file = new_savename(player_save_file); + if(!file_exists(player_save_file)){ + player_save_file = old_savename(player_save_file); + } +#endif + } + if(!file_exists(player_save_file)){ + return -1; + } + RestoreObject(player_save_file,1); + return 1; +} + +int eventDestruct(){ + validate(); + SaveObject(SaveFile); + return ::eventDestruct(); +} + +static mixed GetVariable(string val){ + if(!val){ + return variables(this_object()); + } + if(member_array(val,variables(this_object())) == -1){ + write("No such PLAYER_D variable exists."); + return 0; + } + return fetch_variable(val); +} + +mixed GetPlayerVariables(){ + string *vars = variables(this_object()); + vars -= ({"PlayerDataMap", "PendingEncres", "PendingDecres"}); + vars -= ({"PendingPauses", "PendingUnpauses"}); + vars -= ({"players", "creators", "user_list", "override" }); + vars -= ({"player_save_file", "namestr", "ob", "gplayer"}); + return vars; +} + +static mixed GetPlayerVariable(string val){ + string vars = GetPlayerVariables(); + mixed ret; + if(!val) return vars; + if(member_array(val,variables(this_object())) == -1){ + //write("No such player variable exists."); + return ret; + } + ret = fetch_variable(val); + return ret; +} + +mixed GetPlayerData(string player, string val){ + mixed ret; + validate(); + if(!player) return 0; + if(!user_exists(player)){ + write("No such user exists."); + return 0; + } + gplayer = player; + if(ob = find_player(player)){ + unguarded( (: ob->save_player(gplayer) :)); + } + SaveObject(SaveFile); + unguarded( (: LoadPlayer(gplayer) :) ); + ret = GetPlayerVariable(val); + RestoreObject(SaveFile); + return ret; +} + +string array GetAdminIPs(){ + string array ret_array, name_array, line_array; + string config_file; + config_file = read_file(CFG_GROUPS); + line_array = explode(config_file, "\n"); + ret_array = ({}); + name_array = ({}); + foreach(string line in line_array){ + string g,m; + if(sizeof(line)) line = trim(line); + if(sscanf(line,"(%s)%s",g,m) != 2) continue; + if(g == "SECURE") name_array += explode(trim(m),":"); + else if(g == "ASSIST") name_array += explode(trim(m),":"); + } + if(!sizeof(name_array)) return name_array; + foreach(string nombre in name_array){ + ret_array += ({ GetPlayerData(nombre,"HostSite") }); + } + return ret_array; +} + +int CheckBuilder(object who){ + if(creatorp(who)) return 1; + if(builderp(who)){ + if(!directory_exists(homedir(who)+"/area")){ + unguarded( (: make_workroom($(who)) :) ); + } + return 1; + } + return 0; +} + +varargs string GetUserPath(mixed name, int legacy){ + string ret = "/tmp/"; + object player; + if(!creators) creators = ({}); + if(!players) players = ({}); + if(name && objectp(name)) name = name->GetKeyName(); + if(!name){ + if(!this_player()) return ret; + else name = this_player()->GetKeyName(); + } + if(user_exists(name) && !legacy){ + player = unguarded( (: find_player($(name)) :) ); + if(player) ret = player->GetUserPath(); + else { + mapping tmpmap; + override = 1; + tmpmap = GetPlayerData(name, "Directories"); + if(tmpmap) ret = tmpmap["home"]; + } + if(ret) return ret; + } + if(member_array(name, creators) != -1){ + ret = REALMS_DIRS+"/"+name+"/"; + } + else if(member_array(name, players) != -1){ + ret = DIR_ESTATES + "/"+name[0..0]+"/"+name+"/"; + } + return ret; +} + +string GetHomeRoom(string name){ + string ret; + object dude; + mapping tmpmap; + + if(!user_exists(name)) return 0; + + dude = unguarded( (: find_player($(name)) :) ); + if(dude){ + ret = dude->GetParanoia("homeroom"); + } + else { + override = 1; + tmpmap = GetPlayerData(name, "Paranoia"); + ret = tmpmap["homeroom"]; + } + return ret; +} + +static void UserUpdate(string name, int status){ + object ob = find_player(name); + if(member_array(name, local_users()) != -1) status = 1; + else if(ob && !interactive(ob)) status = -1; + else status = 0; + INSTANCES_D->SendWhoUpdate(name, status); +} + +void PlayerUpdate(string name, int status){ + call_out("UserUpdate", 1, name, status); +} + +static mapping GatherUserData(){ + mapping cands = ([]); + foreach(string user in user_list){ + reset_eval_cost(); + gplayer = user; + if(ob = find_player(gplayer)){ + unguarded( (: ob->save_player(gplayer) :)); + } + SaveObject(SaveFile); + unguarded( (: LoadPlayer(gplayer) :) ); + cands[gplayer] = ([ "LoginTime" : LoginTime, "Age" : Age, + "BirthTime" : BirthTime, "Email" : Email, "HostSite" : HostSite, + "CreatorAge" : CreatorAge, "CreatorBirth" : CreatorBirth, + "RealName" : RealName ]); + RestoreObject(SaveFile); + } + UserData = cands; + return cands; +} + +int SelektUsers(int gather){ + mapping cands = ([]); + int last, count, interval; + validate(); + if(gather){ + CompilePlayerList(); + CompileCreList(); + cands = GatherUserData(); + } + else cands = UserData; + + foreach(string user in sort_array(keys(cands),1)){ + int purge = 0; + if(!cands[user]) continue; + + //Admins, elders, and testchars are exempt + if(member_group(user, "SECURE")) continue; + if(member_group(user, "ASSIST")) continue; + if(member_group(user, "ELDER")) continue; + if(member_group(user, "TEST")) continue; + if(user == "guest") continue; + + count++; + if(!(count % 5)) interval++; + + //bot always get purged, and snoop logs tagged + if((cands[user]["RealName"] == "John Smith" && + cands[user]["Email"] == "me@here") || + cands[user]["Email"] == "bot@delete.me"){ + reset_eval_cost(); + SNOOP_D->NotifyBot(user); + reset_eval_cost(); + purge = 1; + } + + //They last logged in over 1 month ago, and their + //in-game time is less than 30 seconds. + else if(cands[user]["Age"] < 30 && + (last = (time() - cands[user]["LoginTime"])) > 2592000){ + debug("Purging: "+user+", age: "+time_elapsed(cands[user]["Age"])+ + " last logged in "+ctime(cands[user]["LoginTime"])+", "+ + time_elapsed(last)+" ago.", "green"); + purge = 1; + } + + //They last logged in over 6 months ago, and their in-game + //time is less than two minutes. + else if(cands[user]["Age"] < 121 && + (last = (time() - cands[user]["LoginTime"])) > 15552000){ + debug("Purging: "+user+", age: "+time_elapsed(cands[user]["Age"])+ + " last logged in "+ctime(cands[user]["LoginTime"])+", "+ + time_elapsed(last)+" ago.", "red"); + purge = 1; + } + + //They last logged in over a year ago, only once, and + //for less than one hour. + else if(cands[user]["Age"] < 3600 && + (cands[user]["LoginTime"] - cands[user]["BirthTime"] < 100) && + (last = (time() - cands[user]["LoginTime"])) > 31104000){ + debug("Purging: "+user+", age: "+time_elapsed(cands[user]["Age"])+ + " last logged in "+ctime(cands[user]["LoginTime"])+", "+ + time_elapsed(last)+" ago.", "black"); + purge = 1; + } + + if(purge){ + call_out("RemoveUser", interval, user); + purge = 0; + } + } + call_out( "SelektUsers", 604800, 1 ); + return 1; +} + +int GetPaused(string player){ + int ret = 0; + override = 1; + if(user_exists(player)){ + gplayer = lower_case(player); + ret = unguarded( (: GetPlayerData(lower_case(gplayer), "Paused") :) ); + } + override = 0; + return ret; +} diff --git a/lib/secure/daemon/politics.c b/lib/secure/daemon/politics.c new file mode 100644 index 0000000..092083a --- /dev/null +++ b/lib/secure/daemon/politics.c @@ -0,0 +1,8 @@ +#include + +inherit LIB_DAEMON; + +static void create() { + daemon::create(); +} + diff --git a/lib/secure/daemon/portal.c b/lib/secure/daemon/portal.c new file mode 100644 index 0000000..5c49bb9 --- /dev/null +++ b/lib/secure/daemon/portal.c @@ -0,0 +1,149 @@ +#include +#include +#include ROOMS_H +#include + +inherit LIB_DAEMON; + +object blue, orange, bportal, oportal; +string oroom = "/domains/town/room/wtunnel3"; +string broom = "/domains/campus/room/hazlab"; +static int heart_count; +static string SaveFile; + +void CheckPortals(){ + mixed *tmp; + if(catch(blue = load_object(broom)) || !blue){ + broom = ROOM_POD; + blue = load_object(broom); + } + if(catch(orange = load_object(oroom)) || !orange){ + oroom = ROOM_POD; + orange = load_object(oroom); + } + if(!bportal){ + tmp = objects( (: base_name($1) == "/secure/obj/portal_blue" && + clonep($1) :) ); + if(sizeof(tmp)){ + bportal = tmp[0]; + tmp -= ({ bportal }); + foreach(object foo in tmp){ + foo->eventDestruct(); + if(foo) destruct(foo); + } + } + } + if(!oportal){ + tmp = objects( (: base_name($1) == "/secure/obj/portal_orange" && + clonep($1) :) ); + if(sizeof(tmp)){ + oportal = tmp[0]; + tmp -= ({ oportal }); + foreach(object foo in tmp){ + foo->eventDestruct(); + if(foo) destruct(foo); + } + } + } + if(!bportal){ + catch(bportal = new("/secure/obj/portal_blue")); + } + if(!oportal){ + catch(oportal = new("/secure/obj/portal_orange")); + } + if(bportal && (!environment(bportal) || environment(bportal) != blue)){ + if(blue){ + bportal->eventMove(blue); + } + } + if(oportal && (!environment(oportal) || environment(oportal) != orange)){ + if(orange){ + oportal->eventMove(orange); + } + } +} + +void PurgePortals(){ + mixed *tmp = objects( (: base_name($1) == "/secure/obj/portal_orange" && + clonep($1) :) ); + if(sizeof(tmp)){ + foreach(object foo in tmp){ + if(foo != oportal){ + foo->eventDestruct(); + if(foo) destruct(foo); + } + } + } + tmp = objects( (: base_name($1) == "/secure/obj/portal_blue" && + clonep($1) :) ); + if(sizeof(tmp)){ + foreach(object foo in tmp){ + if(foo != bportal){ + foo->eventDestruct(); + if(foo) destruct(foo); + } + } + } +} + +void RegisterPortal(object env){ + string tmp = base_name(previous_object()); + if(tmp == "/secure/obj/portal_orange" && clonep(previous_object())){ + oportal = previous_object(); + orange = env; + oroom = base_name(orange); + } + if(tmp == "/secure/obj/portal_blue" && clonep(previous_object())){ + bportal = previous_object(); + blue = env; + broom = base_name(blue); + } + PurgePortals(); +} + +object GetBluePortal(){ + CheckPortals(); + return blue; +} + +object GetOrangePortal(){ + CheckPortals(); + return orange; +} + +void heart_beat(){ + heart_count++; + if(!(heart_count % 30) && (!oportal || !bportal)){ + CheckPortals(); + } + if(!(heart_count % 60)){ + PurgePortals(); + } + if(!(heart_count % 300)){ + CheckPortals(); + } + if(heart_count > 3600){ + heart_count = 0; + SaveObject(SaveFile, 1); + } +} + +void create(){ + ::create(); + SaveFile = save_file(SAVE_PORTAL); + if(!file_exists(SaveFile) && file_exists(old_savename(SaveFile))){ + cp(old_savename(SaveFile), SaveFile); + } + SetNoClean(1); + if(file_exists(SaveFile)){ + RestoreObject(SaveFile, 1); + } + CheckPortals(); + set_heart_beat(1); +} + +int eventDestruct(){ + SaveObject(SaveFile, 1); + return daemon::eventDestruct(); +} + diff --git a/lib/secure/daemon/preload_check.c b/lib/secure/daemon/preload_check.c new file mode 100644 index 0000000..ed14a53 --- /dev/null +++ b/lib/secure/daemon/preload_check.c @@ -0,0 +1,24 @@ +#include +#include +#include + +inherit LIB_DAEMON; + +string *preloads; + +static void checkPreloads(){ + foreach(string daemon in preloads){ + if(!find_object(daemon) && daemon != INTERMUD_D && daemon != IMC2_D && + daemon != AUTOEXEC_D) { + update(daemon); + } + } + call_out( (: checkPreloads :) , 30); +} + +static void create() { + daemon::create(); + SetNoClean(1); + preloads = filter(explode(read_file(CFG_PRELOAD),"\n"), (: !grepp($1,"#") :) ); + call_out( (: checkPreloads :), 30); +} diff --git a/lib/secure/daemon/reaper.c b/lib/secure/daemon/reaper.c new file mode 100644 index 0000000..f4098aa --- /dev/null +++ b/lib/secure/daemon/reaper.c @@ -0,0 +1,74 @@ +/* + * Seeks dummy items without an environment and destroys them. + * Hackey workaround to sloppy code I'm still tracking down. + * -Crat 21Jan06 + * + * Started as a hackey workaround to a dummy problem, but + * it turns out that periodically destructing cloned + * objects without an environment is a pretty good idea. + * see the reaper.c sefun file for how the dests happen + * and what objects are exempted. + * -Crat 28Jul06 + */ + +#include +#include + +inherit LIB_DAEMON; + +static void eventReap() { + call_out((: eventReap :), 300); + reap_dummies(); + reap_other(); + reclaim_objects(); +} + +static void CheckMem(){ + call_out((: CheckMem :), 60); + if(MEMUSE_SOFT_LIMIT && memory_info() > MEMUSE_SOFT_LIMIT){ + reap_dummies(); + reset_eval_cost(); + reap_other(); + reset_eval_cost(); + reclaim_objects(); + reset_eval_cost(); + MASTER_D->RequestReset(); + } + if(MEMUSE_HARD_LIMIT && memory_info() > MEMUSE_HARD_LIMIT){ + reap_dummies(); + reset_eval_cost(); + reap_other(); + reset_eval_cost(); + reclaim_objects(); + reset_eval_cost(); + MASTER_D->RequestReset(); + if(memory_info() > MEMUSE_HARD_LIMIT){ + if(!EVENTS_D->GetRebooting()){ + EVENTS_D->eventReboot(MINUTES_REBOOT_WARNING); + } + } + } +} + +static void create() { + daemon::create(); + SetNoClean(1); + call_out((: eventReap :), 300); + call_out((: CheckMem :), 60); + set_heart_beat(5); +} + +static void heart_beat(){ +#ifdef __FLUFFOS__ + if(sizeof(get_garbage()) > 20000){ + reap_other(); + } +#endif +} + +int eventDestruct(){ + if( !(master()->valid_apply(({ "SECURE" }))) ) + error("Illegal attempt to destruct reaper: "+get_stack()+" "+identify(previous_object(-1))); + return ::eventDestruct(); +} + diff --git a/lib/secure/daemon/reload.c b/lib/secure/daemon/reload.c new file mode 100644 index 0000000..84c56e9 --- /dev/null +++ b/lib/secure/daemon/reload.c @@ -0,0 +1,491 @@ +#include +#include +#include ROOMS_H +#include +#include +#include + +inherit LIB_DAEMON; +mapping Reloadees = ([]); +static int *reload_handles = ({}); +static int stage2, stilldirty, roomscleaned, warm_boot_in_progress = 0; +string savefile = save_file(SAVE_RELOAD); +static string *exceptions = ({ RELOAD_D, RSOCKET_D }); +object *grooms = ({}), *occupied_rooms = ({}); +static int last_deep_player_load, virtual_void; + +varargs void validate(){ + if((!master()->valid_apply(({ "SECURE", "ASSIST" })))){ + string offender = identify(previous_object(-1)); + debug("RELOAD_D SECURITY VIOLATION: "+offender+" ",get_stack(),"red"); + log_file("security", "\n"+timestamp()+" RELOAD_D breach: "+offender+" "+get_stack()); + error("RELOAD_D SECURITY VIOLATION: "+offender+" "+get_stack()); + } +} + +static void create() { + daemon::create(); + occupied_rooms = ({}); + RestoreObject(savefile); + set_heart_beat(1); + SaveObject(savefile); +} + +int IsolateUsers(){ +#ifdef ROOM_VIRT_VOID + foreach(object user in users()){ + object pwb_room = room_environment(user); + if(pwb_room) user->SetProperty("pwb_room", file_name(pwb_room)); + //user->eventMove(ROOM_VIRT_VOID+"/user_"+user->GetKeyName()); + user->eventMove(ROOMS_D->GetVoid(user)); + reset_eval_cost(); + } +#endif + return 1; +} + +int UnisolateUsers(){ +#ifdef ROOM_VIRT_VOID + foreach(object user in users()){ + string pwb_room = user->GetProperty("pwb_room"); + if(pwb_room) user->eventMove(pwb_room); + //user->RemoveProperty("pwb_room"); + reset_eval_cost(); + } +#endif + return 1; +} + +varargs void eventDestroyDoors(){ + object *doors; + doors = objects((:(base_name($1) == LIB_DUMMY || inherits(LIB_DUMMY,$1)):)); + doors = filter(doors, (: $1->GetDoor() :) ); + foreach(object door in doors){ + object ddaemon = find_object(door->GetDoor()); + if(ddaemon) ddaemon->eventDestruct(); + if(ddaemon) destruct(ddaemon); + door->eventDestruct(); + if(door) destruct(door); + } +} + +varargs void eventDestructEmptyRooms(object room, int last){ + validate(); + if(last && !stilldirty) roomscleaned = 1; + else roomscleaned = 0; + if(room){ + if(objectp(room) && !sizeof(get_livings(room,1))){ + object *subs = get_livings(room,2); + if(sizeof(subs)){ + subs->eventDestruct(); + } + reset_eval_cost(); + catch( room->eventDestruct() ); + } + } +} + +void eventResetEmptyRooms(){ + int i, j, k; + object *rooms = objects((: inherits(LIB_ROOM, $1) :))[0..64000]; + object *rooms2; + validate(); + grooms = rooms; + stilldirty = 1; + for(i = sizeof(rooms)-1; j < i;j++){ + int last = (j > (i - 10) ); + reset_eval_cost(); + if(!rooms[j]) continue; + if(j < 10){ + eventDestructEmptyRooms(rooms[j], last); + } + else { + k = call_out((: eventDestructEmptyRooms :), j/100, rooms[j], last); + } + if(k) reload_handles += ({ k }); + } + rooms2 = objects((: inherits(LIB_ROOM, $1) :)) - rooms; + grooms = rooms2; + if(sizeof(rooms2)){ + call_out( "eventResetEmptyRooms", ((j/100)+1)); + } + else stilldirty = 0; +} + +int ReloadBaseSystem(){ + string *tmp = get_dir("/secure/sefun/"); + string *sefun_files = ({}); + int loop = 2; + catch( update(MASTER_D) ); + foreach(string file in tmp){ + if(!strsrch(file,"sefun.")) continue; + if(last(file,2) != ".c") continue; + sefun_files += ({ "/secure/sefun/"+file }); + } + reset_eval_cost(); + foreach(string file in sefun_files){ + int err; + err = catch(update(file)); + if(err){ + debug("error loading file: "+file); + } + } + tmp = get_dir("/lib/"); + while(loop){ + foreach(string file in tmp){ + object ob; + int err; + if(last(2, file) != ".c") continue; + reset_eval_cost(); + err = catch(ob = load_object("/lib/"+file)); + if(err || !ob){ + debug("error loading file: /lib/"+file); + } + else reload(ob, 1, 1); + } + loop--; + } + reset_eval_cost(); + RELOAD_D->eventReload(load_object(SEFUN), 1, 1); + MASTER_D->eventDestruct(); + load_object(MASTER_D); + reset_eval_cost(); + catch( reload(load_object(LIB_CREATOR), 1, 1) ); + reset_eval_cost(); + catch( reload(load_object(LIB_SENTIENT), 1, 1) ); + reset_eval_cost(); + catch( reload(load_object(LIB_ARMOR), 1, 1) ); + reset_eval_cost(); + catch( reload(load_object(LIB_STORAGE), 1, 1) ); + reset_eval_cost(); + catch( reload(load_object(LIB_WORN_STORAGE), 1, 1) ); + reset_eval_cost(); + catch( reload(load_object(LIB_ROOM), 1, 1) ); + reset_eval_cost(); + catch( reload(load_object(LIB_VIRTUAL), 0, 1) ); + catch( reload(load_object(LIB_VIRT_LAND), 0, 1) ); + catch( reload(load_object(LIB_VIRT_SKY), 0, 1) ); + //catch( reload(load_object(LIB_VIRT_SURFACE), 0, 1) ); + catch( reload(load_object(LIB_VIRT_SUBSURFACE), 0, 1) ); + //catch( reload(load_object(LIB_VIRT_SPACE), 0, 1) ); + catch( reload(load_object(LIB_VIRT_MAP), 0, 1) ); + reset_eval_cost(); + return 1; +} + +varargs mixed ReloadPlayer(mixed who, int deep){ + mixed mx; + string name, pwb_room; + object tmp_bod, new_bod, env; + int err; + validate(); + + if(stringp(who)) who = find_player(who); + if(!who) return 0; + env = environment(who); + if(!env) who->eventMove(ROOM_START); + env = environment(who); + if(!env) return 0; + pwb_room = file_name(room_environment(who)); + + if(deep){ + if((time() - last_deep_player_load) < 3){ + /* No need for a deep load if one just happened */ + deep = 0; + } + else { + last_deep_player_load = time(); + } + } + + name = who->GetKeyName(); + who->CancelCharmode(); + who->save_player(name); + mx = reload(load_object(LIB_CREATOR), deep, 0); + reset_eval_cost(); + if(mx) mx = reload(load_object(LIB_PLAYER), deep, 0); + reset_eval_cost(); + + if(!mx) error("OHSHI-"); + + tmp_bod = new(LIB_PLAYER_STUB); + tmp_bod->SetKeyName(name); + + who->eventMove(ROOM_POD); + + mx = exec(tmp_bod, who); + + who->eventMove(ROOM_FURNACE); + who->eventDestruct(); + + new_bod = (object)master()->player_object(name, tmp_bod); + + if( !new_bod ) return 0; + + mx = exec(new_bod, tmp_bod); + + if(!mx){ + return 0; + } + + destruct(tmp_bod); + reset_eval_cost(); + new_bod->Setup(); + err = catch(mx = new_bod->eventMove(pwb_room)); + if(!environment(new_bod)) new_bod->eventMove(ROOM_START); + SNOOP_D->CheckBot(name); + return 1; +} + +varargs int eventUpdate(mixed what){ + mixed tmpwhat = what; + int err; + if(stringp(what)){ + what = find_object(tmpwhat); + } + if(!objectp(what)){ + err = catch(what = load_object(tmpwhat)); + } + if(err || !objectp(what)){ + return 0; + } + if(what->GetVirtual()){ + return what->eventDestruct(); + } + if(!inherits(LIB_ROOM, what)){ + if(!interactive(what)) return update(base_name(what)); + else return 0; + } + else { + tmpwhat = base_name(what); + what->eventDestruct(); + return update(tmpwhat); + } +} + +varargs int eventReload(mixed what, int when, int nodelay){ + if(!what) return 0; + if(what->GetVirtual()){ + object *npcs = get_livings(what,2); + if(sizeof(npcs)) npcs->eventDestruct(); + return what->eventDestruct(); + } + if(nodelay) return reload(what, 0, 1); + if(!when) when = time(); + else when += time(); + if(stringp(what)){ + if(last(what,2) == ".c") what = trim(what,2); + what = find_object(what); + if(!what) return 0; + } + if(!objectp(what)) return 0; + if(Reloadees[what]) return 0; + if( (previous_object() != what) && + !(master()->valid_apply(({ "ASSIST" }))) ){ + log_file("adm/reload_d",get_stack()+" "+identify(previous_object(-1))+ + " attempted to use RELOAD_D: "+timestamp()+"\n"); + tell_creators(get_stack()+" "+identify(previous_object(-1))+ + " attempted to use RELOAD_D: "+timestamp()+"\n"); + error("Illegal attempt to access RELOAD_D: "+get_stack()+" "+identify(previous_object(-1))); + } + what = file_name(what); + Reloadees[what] = when; +} + +void heart_beat(){ + if(warm_boot_in_progress && !stage2){ + this_object()->ReloadMud2(); + } + if(warm_boot_in_progress){ + Reloadees = ([]); + + foreach(mixed element in reload_handles){ + if(!intp(element)){ + reload_handles -= ({ element }); + continue; + } + if(find_call_out(element) == -1){ + reload_handles -= ({ element }); + } + } + + if(!sizeof(grooms)){ + stilldirty = 0; + if(!sizeof(reload_handles)){ + roomscleaned = 1; + } + } + + } + if(warm_boot_in_progress && stage2){ + if(!sizeof(reload_handles)){ + shout("Reloading users..."); + flush_messages(); + this_object()->ReloadUsers(); + shout("Warm boot complete."); + virtual_void = 0; + warm_boot_in_progress = 0; + stage2 = 0; + eventSave(); + } + } + foreach(mixed key, mixed val in Reloadees){ + if(time() >= val){ + map_delete(Reloadees,key); + key = find_object(key); + if(!key) continue; + if(!interactive(key)){ + reload(key); + } + else { + call_out("ReloadPlayer", 0, key, 1); + } + } + } +} + +mapping GetReloads(){ + return copy(Reloadees); +} + +mapping ClearReloads(){ + if(!(master()->valid_apply(({ "ASSIST" }))) ){ + log_file("adm/reload_d",get_stack()+" "+identify(previous_object(-1))+ + " attempted to clear RELOAD_D: "+timestamp()+"\n"); + tell_creators(get_stack()+" "+identify(previous_object(-1))+ + " attempted to clear RELOAD_D: "+timestamp()+"\n"); + error("Illegal attempt to access RELOAD_D: "+get_stack()+" "+identify(previous_object(-1))); + } + Reloadees = ([]); + SaveObject(savefile); + return copy(Reloadees); +} + +int eventDestruct(){ + SaveObject(savefile); + return daemon::eventDestruct(); +} + +int ReloadDir(string dir, int passes){ + object *lib_obs = objects( (: !strsrch(base_name($1),$(dir)) :) ); + int err; + validate(); + lib_obs = filter(lib_obs, (: !clonep($1) || + (clonep($1) && environment($1)) :)); + debug("Size of ReloadDir("+dir+", "+passes+"): "+sizeof(lib_obs)); + if(!passes) passes = 3; + while(passes){ + reset_eval_cost(); + foreach(object ob in lib_obs){ + if(grepp(file_name(ob), "/void/user_")) continue; + reset_eval_cost(); + if(ob != this_object() && + member_array(base_name(ob), exceptions) == -1){ + if(ob && inherits(LIB_ROOM,ob) && sizeof(livings(ob,1))){ + reload_handles += ({ call_out((: eventReload :), 5,ob, 0, 1) }); + } + else reload_handles += ({ call_out((: eventUpdate :), 5, base_name(ob)) }); + } + } + passes--; + } + return 1; +} + +int ReloadUsers(){ + int err, mx, ret = 1; + validate(); + mx = reload(load_object(LIB_CREATOR), 1, 1); + if(!mx) error("OHFUC-"); + if(virtual_void){ + UnisolateUsers(); + } + + foreach(object player in users()){ + int invis = player->GetInvis(); + string *bases = ({}); + string pstr = base_name(player); + foreach(object ob in deep_inventory(player)){ + object parent; + string base; + if(!ob) continue; + base = base_name(ob); + if(member_array(base, bases) != -1) continue; + bases += ({ base }); + err = catch(parent = load_object(base)); + if(err || !parent) continue; + reload(parent, 1, 1); + reset_eval_cost(); + } + player->SetInvis(0); + err = catch(RELOAD_D->ReloadPlayer(player)); + if(err){ + debug("problem reloading "+pstr,"red"); + ret = 0; + } + else find_object(pstr)->SetInvis(invis); + } + return ret; +} + +int ReloadMud1(){ + object vvoid; + int err; + validate(); +#ifdef ROOM_VIRT_VOID + err = catch(vvoid = load_object(ROOM_VIRT_VOID)); + if(!err && vvoid) virtual_void = 1; +#endif + if(virtual_void){ + IsolateUsers(); + } + occupied_rooms = ({}); + shout("Warm boot initiated!"); + users()->CancelCharmode(); + warm_boot_in_progress = 1; + roomscleaned = 0; + eventDestroyDoors(); + reset_eval_cost(); + shout("Rooms resetting..."); + flush_messages(); + eventResetEmptyRooms(); + return 1; +} + +int ReloadMud2(){ + string *dir2; + string *dir1; + validate(); + if(!roomscleaned || stilldirty) return 0; + dir2 = ({ "/lib/", "/secure/","/daemon/" }); + dir1 = ({ "/cmds/", "/verbs/","/estates/", "/obj/", "/open/", + "/shadows/", "/std/", "/powers/" }); + + stage2 = 1; + ReloadBaseSystem(); + shout("Initializing base system..."); + flush_messages(); + foreach(string dir in (dir2 + dir1)){ + shout("Initializing: "+dir); + flush_messages(); + reset_eval_cost(); + ReloadDir(dir, ((member_array(dir, dir1) != -1) ? 1 : 2)); + } + shout("Reloading domains. This can take a few minutes..."); + flush_messages(); + ReloadDir("/domains/", 3); + shout("Reloading realms..."); + flush_messages(); + ReloadDir("/realms/", 3); + return 1; +} + +int WarmBoot(){ + validate(); + call_out( (: ReloadMud1 :), 0); + return 1; +} + +int GetWarmBootInProgress(){ + return warm_boot_in_progress; +} diff --git a/lib/secure/daemon/remotepost.c b/lib/secure/daemon/remotepost.c new file mode 100644 index 0000000..5273a9a --- /dev/null +++ b/lib/secure/daemon/remotepost.c @@ -0,0 +1,226 @@ +/* /daemon/remotepost.c + * from Foundation II + * daemon to handle the network to local mail interface + * created by Descartes of Borg 940130 + * modified for IIPS 3.1 940513 + */ + +#include +#include +#include +#include +#include "remotepost.h" + +inherit LIB_DAEMON; + +private mapping __MailQueue; +static private mapping __IncomingMail; +mapping Old = ([]); +mapping Outgoing = ([]); +static string SaveFile; + +static int count = 0; + +void create() { + string *muds; + int i; + daemon::create(); + SaveFile = save_file(SAVE_MAILQUEUE); + SetNoClean(1); + __MailQueue = ([]); + __IncomingMail = ([]); + if(file_exists(SaveFile)){ + restore_mailqueue(); + } + i = sizeof(muds = keys(__MailQueue)); + while(i--) __MailQueue[muds[i]][0]["in transit"] = 0; + set_heart_beat(1); +} + +void heart_beat(){ + count++; + if(sizeof(Outgoing)) + OOB_D->SendMail(Outgoing); + Outgoing = ([]); + if(!(count % 60)){ + if(count > 900){ + count = 0; + save_mailqueue(); + } + foreach(mixed key, mixed val in Outgoing){ + if(!sizeof(val)) map_delete(Outgoing,key); + } + } +} + +string postal_check(string mud) { + if(file_name(previous_object()) != SERVICES_D) return 0; + if(!__MailQueue[mud = replace_string(lower_case(mud), " ", ".")]) return 0; + if(__MailQueue[mud][0]["in transit"]) return 0; + __MailQueue[mud][0]["in transit"] = 1; + return __MailQueue[mud][0]["post"][0]; +} + +string next_post(string mud) { + int x; + if(file_name(previous_object(0)) != SERVICES_D) return 0; + + if(!__MailQueue[mud = replace_string(lower_case(mud), " ", ".")]) return 0; + x = __MailQueue[mud][0]["in transit"]++; + if(sizeof(__MailQueue[mud][0]["post"]) == x) { + if( !sizeof(__MailQueue[mud] = __MailQueue[mud][1..]) ) + map_delete(__MailQueue, mud); + save_mailqueue(); + return 0; + } + return __MailQueue[mud][0]["post"][x]; +} + +string resend_post(string mud) { + if(file_name(previous_object(0)) != SERVICES_D) return 0; + if(!__MailQueue[mud = replace_string(lower_case(mud), " ", ".")]) return 0; + __MailQueue[mud][0]["in transit"] = 1; + return __MailQueue[mud][0]["post"][0]; +} + +int send_post(mapping borg, string mud) { + string *msg, *tmp, *muds = ({}); + int i, maxi, x, y; + mapping TmpMap = ([]); + + if(file_name(previous_object(0)) != LOCALPOST_D && + base_name(previous_object(0)) != OBJ_POST){ + return 0; + } + + foreach(mixed val in borg["to"] + borg["cc"]){ + string mudname; + if(sscanf(val,"%*s@%s",mudname)) { + mudname = INTERMUD_D->GetMudName(mudname); + if(mudname){ + OOB_D->RequestToken(mudname); + muds += ({ mudname }); + if(!TmpMap) TmpMap = ([]); + if(!TmpMap[mudname]) TmpMap[mudname] = ({}); + TmpMap[mudname] += convert_names(({ val })); + } + } + } + + borg["to"] = convert_names(borg["to"]); + borg["cc"] = convert_names(borg["cc"]); + borg["from"] = sprintf("%s@%s", convert_name(borg["from"]), + mud_name()); + + foreach(string destination in distinct_array(muds)){ + string *tmp_to = ({}); + string *tmp_cc = ({}); + + foreach(string dude in borg["to"]){ + if(member_array(dude,TmpMap[destination]) != -1) tmp_to += ({ dude }); + } + foreach(string dude in borg["cc"]){ + if(member_array(dude,TmpMap[destination]) != -1) tmp_cc += ({ dude }); + } + if(!Outgoing) Outgoing = ([]); + if(!Outgoing[destination]) Outgoing[destination] = ([]); + Outgoing[destination][borg["id"]] = + ({ + "mail", + borg["id"], + borg["from"], + ([ destination : tmp_to ]), + ([ destination : tmp_cc ]), + ({}), + borg["id"], + borg["subject"], + borg["message"], + }); + } + save_mailqueue(); + return 1; +} + +int outgoing_sent(string destination, string id){ + if(base_name(previous_object(0)) != LIB_OOB){ + return 0; + } + if(sizeof(Outgoing[destination])) + if(Outgoing[destination][id]) map_delete(Outgoing[destination], id); + if(!sizeof(Outgoing[destination])) map_delete(Outgoing, destination); + save_mailqueue(); + return 1; +} + +int incoming_post(mixed *packet){ + mapping borg; + string from = packet[2]; + if(base_name(previous_object(0)) != LIB_OOB){ + return 0; + } + if(!grepp(packet[2],"@")) from = packet[2]+"@"+packet[0]; + borg = + ([ + "id" : packet[1], + "from" : from, + "to" : packet[3][mud_name()], + "cc" : packet[4][mud_name()], + "date" : ( stringp(packet[6]) ? to_int(packet[6]) : packet[6] ), + "subject" : packet[7], + "message" : packet[8] + ]); + LOCALPOST_D->send_post(copy(borg)); + return 1; +} + +static private string *local_targets(string *str) { + string a, b; + int i; + + i = sizeof(str); + while(i--) { + sscanf(str[i], "%s@%s", a, b); + if(replace_string(lower_case(b), " ", ".") == + replace_string(lower_case(mud_name()), " ", ".")) str[i] = a; + } + return str; +} + +static private void save_mailqueue() { + SaveObject(SaveFile); +} + +static private void restore_mailqueue() { + RestoreObject(SaveFile); +} + +string *convert_names(string *noms) { + string a, b; + string *nombres = ({}); + + foreach(string namen in noms){ + if(sscanf(namen, "%s@%s", a, b) != 2) nombres += ({ namen }); + else nombres += ({ a }); + } + return nombres; +} + +mapping query_mail_queue() { return copy(__MailQueue); } + +int eventDestruct(){ + save_mailqueue(); + return ::eventDestruct(); +} + +varargs void defer_old_mail(int i){ + foreach(mixed destination, mixed messages in Outgoing){ + if(!Old) Old = ([]); + foreach(mixed key, mixed val in messages){ + if(((time() - key) > 300) || i){ + if(!Old[destination]) Old[destination] = ([]); + if(!Old[destination][key]) Old[destination][key] = val; + map_delete(Outgoing[destination],key); + } + } + } +} diff --git a/lib/secure/daemon/remotepost.h b/lib/secure/daemon/remotepost.h new file mode 100644 index 0000000..3dcaf8c --- /dev/null +++ b/lib/secure/daemon/remotepost.h @@ -0,0 +1,15 @@ +#ifndef __REMOTEPOST_H +#define __REMOTEPOST_H + +string postal_check(string mud); +string next_post(string mud); +string resend_post(string mud); +void send_post(mapping borg, string mud); +int incoming_post(mapping info); +static private string *local_targets(string *str); +static private void save_mailqueue(); +static private void restore_mailqueue(); +static private string *convert_names(string *noms); +mapping query_mail_queue(); + +#endif /* __REMOTE_POST_H */ diff --git a/lib/secure/daemon/resolv.c b/lib/secure/daemon/resolv.c new file mode 100644 index 0000000..7ac27ec --- /dev/null +++ b/lib/secure/daemon/resolv.c @@ -0,0 +1,87 @@ +#include + +inherit LIB_DAEMON; + +mapping Requests = ([]); +mapping Cache = ([]); +int Resolving = 0; +string test_string = "cnn.com"; + +mixed eventResolve(string str); + +static void create(){ + daemon::create(); + if(!Requests) Requests = ([]); + if(!Cache) Cache = ([]); + eventResolve(test_string); + set_heart_beat(10); +} + +varargs mixed eventResolve(string str, string callback){ + int key; + mixed a, b, c, d; + object ob = previous_object(); + if(!ob) ob = this_object(); + if(sscanf(str,"%d.%d.%d.%d",a,b,c,d) != 4){ + if(sscanf(str,"%s.%s",a,b) != 2){ + return 0; + } + } + if(Cache[str] && str != test_string){ + //ob->eventPrint(str+" resolves to: "+Cache[str]); + //return Cache[str]; + if(callback){ + int foo, bar, llave; + string baz, name, number; + + llave = random(9999); + if(sscanf(str,"%d.%d.%s",foo,bar,baz) == 2) number=str; + if(number) name = Cache[str]; + else { + name = str; + number = Cache[str]; + } + call_other(ob, callback, name, number, llave); + return llave; + } + + } + key = resolve(str,"resolve_callback"); + Requests[key] = ([ "object" : ob, "callback" : callback ]) ; + return key; +} + +mixed resolve_callback(string name, string number, int key){ + if(name && number) Resolving = 1; + if(Requests[key] && Requests[key]["object"] && name && number){ + Requests[key]["object"]->eventPrint(number+" resolves to: "+name); + if(Requests[key]["callback"]){ + call_other(Requests[key]["object"], Requests[key]["callback"], name, number, key); + } + map_delete(Requests,key); + if(name != test_string && number != test_string){ + Cache[name] = number; + Cache[number] = name; + } + } + return key; +} + +int GetResolving(){ + return Resolving; +} + +void heart_beat(){ + Resolving = 0; + eventResolve(test_string); + set_heart_beat(300); +} + +mapping GetNameCache(){ + return (Cache + ([])); +} + +mapping GetRequests(){ + return (Requests + ([])); +} + diff --git a/lib/secure/daemon/rooms.c b/lib/secure/daemon/rooms.c new file mode 100644 index 0000000..4099ebb --- /dev/null +++ b/lib/secure/daemon/rooms.c @@ -0,0 +1,757 @@ +#include +#include +#include ROOMS_H +#include +#ifndef ROOM_ZERO +#define ROOM_ZERO "/domains/town/room/start" +#endif + +inherit LIB_DAEMON; + +mapping Workrooms = ([]); + +mapping WorldMap = ([]); +mapping WorldGrid = ([]); +static mapping DroneCache = ([]); +static string last_exit; +static int global_manual, cache_timer = time(); +int debugging; +static string *cards = ({ "north", "south", "east", "west", + "northeast", "northwest", "southeast", "southwest", + "up", "down" }); +static string void_room, SaveFile; +static string *unsafes = ({ "/realms/", "/open/", "/estates/" }); + +void create(){ + int err; + object vvoid; +#ifdef __FLUFFOS__ && GRID + SaveFile = save_file(SAVE_ROOMS); + if(!file_exists(SaveFile) && file_exists(old_savename(SaveFile))){ + cp(old_savename(SaveFile), SaveFile); + } + if(!WorldMap) WorldMap = ([]); + if(!WorldGrid) WorldGrid = ([]); + if(file_exists(SaveFile)){ + RestoreObject(SaveFile, 1); + } + set_heart_beat(300); +#endif +#ifdef ROOM_VIRT_VOID + err = catch(vvoid = load_object(ROOM_VIRT_VOID)); + if(!err && vvoid) void_room = ROOM_VIRT_VOID; +#endif + if(undefinedp(void_room)) void_room = ROOM_VOID; +} + +static void heart_beat(){ + SaveObject(SaveFile, 1); +} + +string GetVoid(mixed ob){ + if(!ob) ob = previous_object(); + if(!ob) return ROOM_VOID; + if(void_room == ROOM_VOID) return ROOM_VOID; + if(stringp(ob)) ob = find_object(ob); + if(interactive(ob)){ + return void_room+"/user_"+ob->GetKeyName(); + } + if(clonep(ob)){ + return void_room+"/object_"+file_name(ob); + } + return ROOM_VOID; +} + +string GetRoomZero(){ + return ROOM_ZERO; +} + +mixed GenerateNames(int x){ +#ifdef __FLUFFOS__ && GRID + int first, second, third; + third = (x & 32767); + second = (x & 536870911) - third;; + first = ((x >> 29) << 29); + return ({ first, second, third }); +#else + return ({ 0, 0, 0 }); +#endif +} + +int eventDestruct(){ + SaveObject(SaveFile, 1); + return daemon::eventDestruct(); +} + +int SetDebugging(int i){ + if(!this_player() || !adminp(this_player())) return 0; + if(i) debugging = 1; + else debugging = 0; + return debugging; +} + +mixed validate_last_room(string room, object player){ +#ifdef __FLUFFOS__ && GRID + string location_str, current_room_name; + object location_ob, current_room; + mapping origin_room = ([]); + mapping origin_room_exits = ([]); + mixed tmp, ret; + if(player) location_str=player->GetProperty("LastLocation"); + if(!location_str) return 0; + if(location_str) location_ob=load_object(location_str); + if(location_ob) tmp = this_object()->GetCoordinates(location_ob); + if(tmp) origin_room = this_object()->GetGrid(tmp); + current_room = room_environment(player); + current_room_name = base_name(room_environment(player)); + + if(room == ROOM_ZERO || (mapp(origin_room) && + origin_room["room"] && origin_room["room"] == location_str)){ + mapping exits = location_ob->GetExitMap(); + if(location_ob->GetFlyRoom()){ + exits["up"] = location_ob->GetFlyRoom(); + } + location_ob->DestructEmptyVirtual(); + foreach(mixed key, mixed val in exits){ + if(val == current_room_name){ + ret = ([ opposite_dir(key) : location_str ]); + break; + } + } + if(ret){ + return ret; + } + } + return 0; +#else + return 0; +#endif +} + +void zero(){ + WorldMap = ([]); + WorldGrid = ([]); + Workrooms = ([]); + SaveObject(SaveFile, 1); + ROOM_ZERO->init(); +} + +varargs mapping GetGridMap(string str){ +#ifdef __FLUFFOS__ && GRID + mapping ret; + string prefix, room, coords; + object ob; + int err; + if(!sizeof(str)) return copy(WorldGrid); + err = catch(ob = load_object(str)); + if(err || !ob){ + this_object()->UnSetRoom(str, 1); + return 0; + } + else { + } + prefix = path_prefix(str); + room = last_string_element(str, "/"); + if(ob){ + coords = this_object()->GetCoordinates(ob); + ret = this_object()->GetGrid(coords); + } + if(!ret) ret = ([]); + if(WorldMap[prefix] && WorldMap[prefix][room]){ + ret += WorldMap[prefix][room]; + } + ob->DestructEmptyVirtual(); + return ret; +#else + return ([]); +#endif +} + +varargs mapping GetWorldMap(string str){ + return copy(WorldMap); +} + +string StrCoord(mapping TmpMap){ + string ret = TmpMap["x"] + ","; + ret += TmpMap["y"] + ","; + ret += TmpMap["z"]; + return ret; +} + +varargs mixed SetGrid(string arg_room, string coord, object player, int unset){ +#ifdef __FLUFFOS__ && GRID + string room; + mixed a, b, c, d, e, f, g, h, i, j, k, l, m, n; + int p, q, x, y, z; + mixed xarr, yarr, zarr; + + if(this_player() && adminp(this_player())){ + room = arg_room; + } + else { + room = base_name(previous_object()); + } + + if(!player) player = previous_object(); + + if(!player->GetProperty("LastLocation") && + base_name(player) != room) return 0; + + if(inherits(LIB_ROOM, previous_object())) global_manual = 1; + + sscanf(coord,"%d,%d,%d",x,y,z); + xarr = GenerateNames(x); + yarr = GenerateNames(y); + zarr = GenerateNames(z); + a = xarr[0]; + b = xarr[1]; + c = xarr[2]; + d = yarr[0]; + e = yarr[1]; + f = yarr[2]; + g = zarr[0]; + h = zarr[1]; + i = zarr[2]; + if(!WorldGrid[a]) WorldGrid[a] = ([]); + if(!WorldGrid[a][b]) WorldGrid[a][b] = ([]); + if(!WorldGrid[a][b][c]) WorldGrid[a][b][c] = ([]); + if(!WorldGrid[a][b][c][d]) WorldGrid[a][b][c][d] = ([]); + if(!WorldGrid[a][b][c][d][e]) WorldGrid[a][b][c][d][e] = ([]); + if(!WorldGrid[a][b][c][d][e][f]) WorldGrid[a][b][c][d][e][f] = ([]); + if(!WorldGrid[a][b][c][d][e][f][g]) WorldGrid[a][b][c][d][e][f][g] = ([]); + if(!WorldGrid[a][b][c][d][e][f][g][h]) WorldGrid[a][b][c][d][e][f][g][h] = ([]); + if(!WorldGrid[a][b][c][d][e][f][g][h][i]) WorldGrid[a][b][c][d][e][f][g][h][i] = ([]); + if(unset && sizeof(WorldGrid[a][b][c][d][e][f][g][h][i])){ + WorldGrid[a][b][c][d][e][f][g][h][i] = 0; + return 1; + } + if(sizeof(WorldGrid[a][b][c][d][e][f][g][h][i]) || + sizeof(this_object()->GetCoordinates(coord))){ + return WorldGrid[a][b][c][d][e][f][g][h][i]; + } + else { + if(global_manual || validate_last_room(room, player)){ + MAP_D->RemoveCache(coord); + global_manual = 0; + WorldGrid[a][b][c][d][e][f][g][h][i] = + ([ "room" : room, "coord" : coord ]); + } + return WorldGrid[a][b][c][d][e][f][g][h][i]; + } +#else + return 0; +#endif +} + +mixed GetGrid(string str){ +#ifdef __FLUFFOS__ && GRID + mixed room, a, b, c, d, e, f, g, h, i, j, k, l, m, n; + string coord=str; + int p, q,x,y,z; + mixed xarr, yarr, zarr; + sscanf(coord,"%d,%d,%d",x,y,z); + xarr = GenerateNames(x); + yarr = GenerateNames(y); + zarr = GenerateNames(z); + a = xarr[0]; + b = xarr[1]; + c = xarr[2]; + d = yarr[0]; + e = yarr[1]; + f = yarr[2]; + g = zarr[0]; + h = zarr[1]; + i = zarr[2]; + if(!WorldGrid[a] || + !WorldGrid[a][b] || + !WorldGrid[a][b][c] || + !WorldGrid[a][b][c][d] || + !WorldGrid[a][b][c][d][e] || + !WorldGrid[a][b][c][d][e][f] || + !WorldGrid[a][b][c][d][e][f][g] || + !WorldGrid[a][b][c][d][e][f][g][h] || + !WorldGrid[a][b][c][d][e][f][g][h][i]){ + return ([]); + } + return copy(WorldGrid[a][b][c][d][e][f][g][h][i]); +#else + return ([]); +#endif +} + +varargs int UnSetRoom(mixed arg_ob, int auto){ +#ifdef __FLUFFOS__ && GRID + string creator, name, prefix, room_name; + string grid; + mixed ob; + + if(auto || (this_player() && adminp(this_player()))){ + ob = arg_ob; + } + else{ + ob = previous_object(); + } + + if(objectp(ob)){ + name = base_name(ob); + } + else { + name = ob; + } + grid = this_object()->GetCoordinates(name); + + if(grid && grid != "0,0,0"){ + MAP_D->RemoveCache(grid); + SetGrid(name, grid, this_player(), 1); + } + prefix = path_prefix(name); + room_name = last_string_element(name, "/"); + if(WorldMap[prefix] && WorldMap[prefix][room_name]){ + WorldMap[prefix][room_name] = 0; + } + if(sscanf(name,"/realms/%s/workroom",creator)){ + Workrooms[creator] = 0; + } + return 1; +#else + return 0; +#endif +} + +varargs mixed SetRoom(object arg_ob, object player, string manual){ +#ifdef __FLUFFOS__ && GRID + string last_str, creator, name, prefix, room_name, coord; + mapping tmpexits, backup_direction, TmpMap = ([]); + object ob; + + if(this_player() && adminp(this_player())){ + ob = arg_ob; + } + else{ + ob = previous_object(); + } + if(clonep(ob)){ + return 0; + } + if(!(last_str = player->GetProperty("LastLocation")) && + player != ob){ + return 0; + } + if(!(last_str)) last_str = ""; + name = base_name(ob); + prefix = path_prefix(name); + if(prefix == "/domains/default/virtual/void") return 0; + if(manual && (!strsrch(name, "/open/") || !strsrch(name, "/realms/"))){ + if(!this_player() || !archp(this_player())){ + return 0; + } + } + /* Still need to figure out exclusions for + * an island or continent perimeter :( + */ + //if(prefix == "/domains/town/virtual/surface" || + // prefix == "/domains/town/virtual/sub"){ + // return 0; + //} + room_name = last_string_element(name, "/"); + //tc("last_str: "+last_str); + //tc("room_name: "+room_name); + //tc("name: "+name); + if(!sizeof(WorldMap)){ + if(name == ROOM_FURNACE){ + return 0; + } + } + if(!manual && WorldMap[prefix] && WorldMap[prefix][room_name]){ + if(StrCoord(WorldMap[prefix][room_name]["coords"]) == "0,0,0" && + name != ROOM_ZERO){ + UnSetRoom(ob); + //tc("alpha"); + } + else{ + //tc("omega"); + return ({ WorldMap[prefix][room_name]["coords"]["x"], + WorldMap[prefix][room_name]["coords"]["y"], + WorldMap[prefix][room_name]["coords"]["z"] }); + } + } + sscanf(name,"/realms/%s/workroom",creator); + foreach(string element in unsafes){ + if(!strsrch(last_str, element)){ + if(strsrch(name, element) && !creator) + return 0; + } + } + if(!WorldMap[prefix]){ + WorldMap[prefix] = ([]); + } + if(!WorldMap[prefix][room_name]){ + WorldMap[prefix][room_name] = ([ "date" : time(), + "coords" : ([ "x" : 0, "y" : 0, "z" : 0 ]), + "exits" : ob->GetExitMap(), + ]); + } + WorldMap[prefix][room_name]["exits"]["sink"] = ob->GetSinkRoom(); + WorldMap[prefix][room_name]["exits"]["fly"] = ob->GetFlyRoom(); + if(debugging){ + } + if(creator){ + int x,y,z,next = sizeof(Workrooms); + if(Workrooms[creator]){ + //tc("beta"); + return ({ Workrooms[creator]["coords"]["x"], + Workrooms[creator]["coords"]["y"], + Workrooms[creator]["coords"]["z"] }); + } + x = 1000000000; + y = 1000000000; + z = -1000000000; + x += ( next * 10000 ); + manual = x+","+y+","+z; + Workrooms[creator] = ([ "grid" : manual, + "coords" : ([ "x" : x, "y" :y, "z" : z ]), + "time" : time(), "number" : next ]); + } + if(manual){ + int res, x, y, z; + res = sscanf(manual,"%d,%d,%d",x,y,z); + if(res == 3){ + WorldMap[prefix][room_name]["coords"] = + ([ "x" : x, "y" :y, "z" : z ]); + global_manual = 1; + SetGrid(name, manual, player); + //tc("gamma"); + return ({ x, y, z }); + } + } + + //if(ob->GetVirtual() && sizeof(WorldMap[prefix])){ + // TmpMap = WorldMap[prefix]; + //} + + tmpexits = WorldMap[prefix][room_name]["exits"]; + if(!sizeof(tmpexits) || member_array(player->GetProperty("LastLocation"), + values(tmpexits)) == -1){ + tmpexits = backup_direction; + } + if(!mapp(tmpexits)) tmpexits = ([]); + + /* Now we try to guess our coordinate from the + * set coordinate of an adjacent room. + */ + foreach(string key, mixed val in tmpexits){ + string sub_pre = path_prefix(val); + string sub_name = last_string_element(val, "/"); + int breakout; + if(member_array(key, cards) == -1) continue; + + if(WorldMap[sub_pre] && WorldMap[sub_pre][sub_name]){ + mapping cmap = WorldMap[sub_pre][sub_name]["coords"]; + if(val != ROOM_ZERO && cmap["x"] == 0 && cmap["y"] == 0 && + cmap["z"] == 0 ){ + continue; + } + last_exit = key; + switch(key){ + case "north" : WorldMap[prefix][room_name]["coords"]["x"] = + WorldMap[sub_pre][sub_name]["coords"]["x"]; + WorldMap[prefix][room_name]["coords"]["y"] = + WorldMap[sub_pre][sub_name]["coords"]["y"] - 1; + WorldMap[prefix][room_name]["coords"]["z"] = + WorldMap[sub_pre][sub_name]["coords"]["z"]; + breakout = 1; + break; + case "south" : WorldMap[prefix][room_name]["coords"]["x"] = + WorldMap[sub_pre][sub_name]["coords"]["x"]; + WorldMap[prefix][room_name]["coords"]["y"] = + WorldMap[sub_pre][sub_name]["coords"]["y"] + 1; + WorldMap[prefix][room_name]["coords"]["z"] = + WorldMap[sub_pre][sub_name]["coords"]["z"]; + breakout = 1; + break; + case "east" : WorldMap[prefix][room_name]["coords"]["x"] = + WorldMap[sub_pre][sub_name]["coords"]["x"] - 1; + WorldMap[prefix][room_name]["coords"]["y"] = + WorldMap[sub_pre][sub_name]["coords"]["y"]; + WorldMap[prefix][room_name]["coords"]["z"] = + WorldMap[sub_pre][sub_name]["coords"]["z"]; + breakout = 1; + break; + case "west" : WorldMap[prefix][room_name]["coords"]["x"] = + WorldMap[sub_pre][sub_name]["coords"]["x"] + 1; + WorldMap[prefix][room_name]["coords"]["y"] = + WorldMap[sub_pre][sub_name]["coords"]["y"]; + WorldMap[prefix][room_name]["coords"]["z"] = + WorldMap[sub_pre][sub_name]["coords"]["z"]; + breakout = 1; + break; + case "northeast" : WorldMap[prefix][room_name]["coords"]["x"] = + WorldMap[sub_pre][sub_name]["coords"]["x"] - 1; + WorldMap[prefix][room_name]["coords"]["y"] = + WorldMap[sub_pre][sub_name]["coords"]["y"] - 1; + WorldMap[prefix][room_name]["coords"]["z"] = + WorldMap[sub_pre][sub_name]["coords"]["z"]; + breakout = 1; + break; + case "northwest" : WorldMap[prefix][room_name]["coords"]["x"] = + WorldMap[sub_pre][sub_name]["coords"]["x"] + 1; + WorldMap[prefix][room_name]["coords"]["y"] = + WorldMap[sub_pre][sub_name]["coords"]["y"] - 1; + WorldMap[prefix][room_name]["coords"]["z"] = + WorldMap[sub_pre][sub_name]["coords"]["z"]; + breakout = 1; + break; + case "southeast" : WorldMap[prefix][room_name]["coords"]["x"] = + WorldMap[sub_pre][sub_name]["coords"]["x"] - 1; + WorldMap[prefix][room_name]["coords"]["y"] = + WorldMap[sub_pre][sub_name]["coords"]["y"] + 1; + WorldMap[prefix][room_name]["coords"]["z"] = + WorldMap[sub_pre][sub_name]["coords"]["z"]; + breakout = 1; + break; + case "southwest" : WorldMap[prefix][room_name]["coords"]["x"] = + WorldMap[sub_pre][sub_name]["coords"]["x"] + 1; + WorldMap[prefix][room_name]["coords"]["y"] = + WorldMap[sub_pre][sub_name]["coords"]["y"] + 1; + WorldMap[prefix][room_name]["coords"]["z"] = + WorldMap[sub_pre][sub_name]["coords"]["z"]; + breakout = 1; + break; + case "up" : WorldMap[prefix][room_name]["coords"]["x"] = + WorldMap[sub_pre][sub_name]["coords"]["x"]; + WorldMap[prefix][room_name]["coords"]["y"] = + WorldMap[sub_pre][sub_name]["coords"]["y"]; + WorldMap[prefix][room_name]["coords"]["z"] = + WorldMap[sub_pre][sub_name]["coords"]["z"] - 1; + breakout = 1; + break; + case "down" : WorldMap[prefix][room_name]["coords"]["x"] = + WorldMap[sub_pre][sub_name]["coords"]["x"]; + WorldMap[prefix][room_name]["coords"]["y"] = + WorldMap[sub_pre][sub_name]["coords"]["y"]; + WorldMap[prefix][room_name]["coords"]["z"] = + WorldMap[sub_pre][sub_name]["coords"]["z"] + 1; + breakout = 1; + break; + case "fly" : WorldMap[prefix][room_name]["coords"]["x"] = + WorldMap[sub_pre][sub_name]["coords"]["x"]; + WorldMap[prefix][room_name]["coords"]["y"] = + WorldMap[sub_pre][sub_name]["coords"]["y"]; + WorldMap[prefix][room_name]["coords"]["z"] = + WorldMap[sub_pre][sub_name]["coords"]["z"] - 1; + breakout = 1; + break; + case "sink" : WorldMap[prefix][room_name]["coords"]["x"] = + WorldMap[sub_pre][sub_name]["coords"]["x"]; + WorldMap[prefix][room_name]["coords"]["y"] = + WorldMap[sub_pre][sub_name]["coords"]["y"]; + WorldMap[prefix][room_name]["coords"]["z"] = + WorldMap[sub_pre][sub_name]["coords"]["z"] + 1; + breakout = 1; + break; + } + } + if(breakout) break; + } + coord = WorldMap[prefix][room_name]["coords"]["x"]+","+ + WorldMap[prefix][room_name]["coords"]["y"]+","+ + WorldMap[prefix][room_name]["coords"]["z"]; + + /* Here we try to extrapolate a virtual's coords from a known + * coord in the same virt directory. + */ + if(coord == "0,0,0" && name != ROOM_ZERO && sizeof(TmpMap)){ + int a,b,c; + int a2,b2,c2; + int x,y,z; + int x2,y2,z2; + int xd,yd,zd; + //tc("hmm","red"); + foreach(mixed key, mixed val in TmpMap){ + if(val){ + if(!val["date"]) continue; + if(sscanf(key,"%d,%d,%d",a,b,c) != 3){ + if(sscanf(key,"%d,%d",a,b) != 2) continue; + else c = 0; + } + if(!val["coords"]) continue; + else { + x = val["coords"]["x"]; + y = val["coords"]["y"]; + z = val["coords"]["z"]; + } + if(!x && !y && !z){ + map_delete(TmpMap,key); + continue; + } + else break; + } + else map_delete(TmpMap,key); + } + if(!x && !y && !z){ + return 0; + } + if(!undefinedp(a)){ + string roomname = last_string_element(base_name(ob),"/"); + if(sscanf(roomname,"%d,%d,%d",a2,b2,c2) != 3){ + if(sscanf(roomname,"%d,%d",a2,b2) != 2){ + return 0; + } + else c2 = 0; + } + xd = a - a2; + yd = b - b2; + zd = c - c2; + x2 = x - xd; + y2 = y - yd; + z2 = z - zd; + WorldMap[prefix][room_name] = ([]); + WorldMap[prefix][room_name]["coords"] = + ([ "x" : x2, "y" :y2, "z" : z2 ]); + global_manual = 1; + manual = x2+","+y2+","+z2; + SetGrid(name, manual, player); + //tc("delta"); + return ({ x2, y2, z2 }); + } + else { + } + if(WorldMap[prefix] && WorldMap[prefix][room_name] && + StrCoord(WorldMap[prefix][room_name]["coords"]) == "0,0,0"){ + WorldMap[prefix][room_name] = 0; + } + if(!creator) return 0; + } + /* end virt extrapolation */ + + if(coord == "0,0,0" && name != ROOM_ZERO){ + true(); + } + else SetGrid(name, coord, player); + //tc("epsilon"); + return ({ WorldMap[prefix][room_name]["coords"]["x"], + WorldMap[prefix][room_name]["coords"]["y"], + WorldMap[prefix][room_name]["coords"]["z"] }); +#else + //tc("phi"); + return ({ 0, 0, 0 }); +#endif +} + +string GetCoordinates(mixed ob){ +#ifdef __FLUFFOS__ && GRID + string name, prefix, room_name, ret; + int err; + if(objectp(ob)){ + if(clonep(ob)){ + object env = room_environment(ob); + if(env && !clonep(env)) ob = env; + else return ""; + } + name = base_name(ob); + } + else if(stringp(ob)){ + if(last(ob,2) == ".c") name = truncate(ob,2); + else name = ob; + } + else { + return ""; + } + prefix = path_prefix(name); + room_name = last_string_element(name, "/"); + if(!WorldMap[prefix] || !WorldMap[prefix][room_name]){ + return ""; + } + ret = WorldMap[prefix][room_name]["coords"]["x"]+","+ + WorldMap[prefix][room_name]["coords"]["y"]+","+ + WorldMap[prefix][room_name]["coords"]["z"]; + return ret; +#else + return ""; +#endif +} + +mapping GetCoordinateMap(mixed ob){ +#ifdef __FLUFFOS__ && GRID + string name = base_name(ob); + string prefix = path_prefix(name); + string room_name = last_string_element(name, "/"); + if(!WorldMap[prefix] || !WorldMap[prefix][room_name]){ + return ([]); + } + return ([ "x" : WorldMap[prefix][room_name]["coords"]["x"], + "y" : WorldMap[prefix][room_name]["coords"]["y"], + "z" : WorldMap[prefix][room_name]["coords"]["z"], ]); +#else + return ([]); +#endif +} + +mixed GetRoom(mixed ob){ +#ifdef __FLUFFOS__ && GRID + string name, prefix, room_name; + if(objectp(ob)){ + if(clonep(ob)) return 0; + name = base_name(ob); + } + else if(stringp(ob)) name = ob; + if(!name) return 0; + prefix = path_prefix(name); + room_name = last_string_element(name, "/"); + if(!WorldMap[prefix]) return "No such prefix."; + if(!WorldMap[prefix][room_name]) return "No such room."; + return copy(WorldMap[prefix][room_name]); +#else + return "Grid is not enabled."; +#endif +} + +varargs mixed GetDirectionRoom(mixed origin, string direction, int noclip){ +#ifdef __FLUFFOS__ && GRID + int x, y, z; + string dir_coords; + mixed ret, room = GetRoom(origin); + if(!room || !sizeof(room) || !mapp(room)) return 0; + if(sizeof(room["exits"]) && room["exits"][direction]){ + return room["exits"][direction]; + } + if(!noclip || !room["coords"]) return 0; + x = room["coords"]["x"]; + y = room["coords"]["y"]; + z = room["coords"]["z"]; + switch(direction){ + case "up" : z++;break; + case "down" : z--;break; + case "north" : y++;break; + case "south" : y--;break; + case "east" : x++;break; + case "west" : x--;break; + case "northeast" : y++;x++;break; + case "northwest" : y++;x--;break; + case "southwest" : y--;x--;break; + case "southeast" : y--;x++;break; + default : return 0; + } + dir_coords = x+","+y+","+z; + ret = GetGrid(dir_coords); + if(sizeof(ret) && ret["room"]) return ret["room"]; + return 0; +#else + return 0; +#endif +} + +mixed DroneCache(mixed foo){ + string path; + object prev, env; + prev = previous_object(); + if(!prev) return 0; + env = environment(prev); + if(!env) return 0; + path = path_prefix(base_name(env)); + if(time() - cache_timer > 60 || !DroneCache) DroneCache = ([]); + cache_timer = time(); + if(!DroneCache[path]) DroneCache[path] = ({}); + if(foo) DroneCache[path] = distinct_array(DroneCache[path] + foo ); + else return copy(DroneCache[path]); +} diff --git a/lib/secure/daemon/secrets.c b/lib/secure/daemon/secrets.c new file mode 100644 index 0000000..02ea025 --- /dev/null +++ b/lib/secure/daemon/secrets.c @@ -0,0 +1,97 @@ +#include SECRETS_H +#include +#include +#include + +inherit LIB_DAEMON; +mapping Secrets = ([]); +string secfile; + +void create(){ + Secrets = ([ + "IRN_PASSWORD" : IRN_PASSWORD, + "IRN_PASSWORD1" : IRN_PASSWORD1, + "IRN_PASSWORD2" : IRN_PASSWORD2, + "IRN_PASSWORD3" : IRN_PASSWORD3, + "IMC2_CLIENT_PW" : IMC2_CLIENT_PW, + "IMC2_SERVER_PW" : IMC2_SERVER_PW, + "I3_SERVER_PW" : I3_SERVER_PW, + "INSTANCE_PW" : INSTANCE_PW, + ]); +} + +static varargs void ModSecret(string secret, mixed val){ + string type; + string *secarr, *ret = ({}); + + secfile = unguarded( (: read_file("/secure/include/secrets.h") :) ); + secarr = explode(secfile, "\n"); + if(!undefinedp(Secrets[secret])){ + type = typeof(Secrets[secret]); + } + foreach(string line in secarr){ + if(!sizeof(line)) continue; + if(!strsrch(line, "#define "+secret+" ")){ + if(type && type == "string"){ + line = "#define "+secret+" \""+val+"\""; + Secrets[secret] = val; + } + else { + line = "#define "+secret+" "+to_int(val); + Secrets[secret] = to_int(val); + } + } + ret += ({ trim(line) }); + } + secfile = implode(ret, "\n") + "\n"; + unguarded( (: write_file("/secure/include/secrets.h", secfile, 1) :) ); +} + +mixed GetSecret(string secret){ + string prev = base_name(previous_object()); + if( (master()->valid_apply(({ "SECURE" }))) ){ + return copy(Secrets[secret]); + } + if(!strsrch(secret, "IRN_PASSWORD") && prev == ROUTER_D){ + return copy(Secrets[secret]); + } + if(!strsrch(secret, "IMC2_") && prev == IMC2_D){ + return copy(Secrets[secret]); + } + if(secret == "I3_SERVER_PW" && prev == INTERMUD_D){ + return copy(Secrets[secret]); + } + if(secret == "INSTANCE_PW" && prev == INSTANCES_D){ + return copy(Secrets[secret]); + } + return 0; +} + +mixed SetSecret(string secret, mixed val){ + string prev = base_name(previous_object()); + if( (master()->valid_apply(({ "SECURE" }))) ){ + ModSecret(secret, val); + return copy(Secrets[secret]); + } + if(!strsrch(secret, "IRN_PASSWORD") && prev == ROUTER_D){ + ModSecret(secret, val); + return copy(Secrets[secret]); + } + if(!strsrch(secret, "IMC2_") && (prev == IMC2_D || prev == CMD_MUDCONFIG)){ + ModSecret(secret, val); + return copy(Secrets[secret]); + } + if(secret == "I3_SERVER_PW" && prev == INTERMUD_D){ + ModSecret(secret, val); + return copy(Secrets[secret]); + } + if(secret == "INSTANCE_PW" && prev == INSTANCES_D){ + ModSecret(secret, val); + return copy(Secrets[secret]); + } + return 0; +} + + + + diff --git a/lib/secure/daemon/snoop.c b/lib/secure/daemon/snoop.c new file mode 100644 index 0000000..093022c --- /dev/null +++ b/lib/secure/daemon/snoop.c @@ -0,0 +1,312 @@ +#include +#include +#include +#include +#include ROOMS_H + +inherit LIB_DAEMON; + +int SnoopClean(); +int RemoveWatcher(string watcher, mixed target); + +string *snooped = ({}); +object *snoopers = ({}); +string *monitored = ({}); +string *ignored = ({}); +static string *ignored_ips = ({"97.107.133.86","149.158.218.102","204.209.44.3","24.34.143.119","69.37.84.233", "127.0.0.1"}); +mapping Watchers = ([]); +int count = 0; +int just_loaded = 1; +object *prevusers, gfoo; +static string SaveFile; + +void eventLoadRogues(); + +static void create() { + daemon::create(); + if(!ignored) ignored = ({}); + SaveFile = save_file(SAVE_SNOOP); + if(file_exists(SaveFile)){ + RestoreObject(SaveFile, 1); + } + SetNoClean(1); + SnoopClean(); + set_heart_beat(1); + if(GLOBAL_MONITOR == 0 && sizeof(monitored)){ + call_out( (: eventLoadRogues :), 1); + } + snoopers = filter(objects(), (: base_name($1) == "/secure/obj/snooper" :) ); + prevusers = users(); + catch(mkdir("/secure/log/adm/archive")); +} + +void RegisterSnooper(){ + object registrant = previous_object(); + if(base_name(registrant) == "/secure/obj/snooper" && + member_array(registrant,snoopers) == -1) snoopers += ({ registrant }); + SaveObject(SaveFile, 1); +} + +void UnregisterSnooper(){ + object registrant = previous_object(); + if(base_name(registrant) == "/secure/obj/snooper" && + member_array(registrant,snoopers) != -1) snoopers -= ({ registrant }); + SaveObject(SaveFile, 1); +} + +void eventLoadRogues(){ + if( !(master()->valid_apply(({ PRIV_SECURE }))) ) return; + foreach(string rogue in monitored) this_object()->CheckBot(rogue); + snoopers = filter(objects(), (: base_name($1) == "/secure/obj/snooper" :) ); +} + +int CheckBot(string str){ + object cloan, foo; + int allset, err, already_watched = 0; + string *immune; + string name; + + if(!str) str = "foo"; + str = lower_case(str); + foo = find_player(str); + if(sizeof(snoopers)){ + foreach(object snoopbox in snoopers){ + if(clonep(snoopbox) ) { + } + else snoopers -= ({snoopbox}); + if(snoopbox && snoopbox->GetSnooped() && snoopbox->GetSnooped() == str) { + already_watched = 1; + } + } + } + if(!already_watched && foo && (GLOBAL_MONITOR > 0 || member_array(str, monitored) != -1 || member_array(str, snooped) != -1 )){ + string ip; + gfoo = foo; + ip = unguarded( (: query_ip_number(gfoo) :) ); + gfoo = 0; + if(member_array(str, (ignored || ({}))) != -1) return 0; + if((member_array(ip, (ignored_ips||({}))) != -1 || + (archp(foo) && GLOBAL_MONITOR == 2)) && + member_array(str, monitored) == -1 && + member_array(str, snooped) == -1 ) return 0; + cloan=new("/secure/obj/snooper"); + cloan->eventStartSnoop(str); + err = catch(SaveObject(SaveFile, 1)); + } + return 1; +} + +void CheckSnooped(){ + object *lusers = users(); + just_loaded = 0; + foreach(object user in lusers){ + CheckBot(user->GetKeyName()); + } + prevusers = lusers; +} + +int SnoopClean(){ + object *voyeurs = users(); + snoopers = filter(objects(), (: base_name($1) == "/secure/obj/snooper" :) ); + if(sizeof(voyeurs)){ + foreach(object perv in voyeurs){ + if(!snooperp(perv) && !archp(perv)){ + RemoveWatcher(perv->GetKeyName(), "all"); + } + } + } + if(sizeof(snoopers)){ + foreach(object snoopbox in snoopers){ + if(snoopbox && !clonep(snoopbox) ) { + snoopers -= ({snoopbox}); + } + else { + object subject; + string dude = snoopbox->GetSnooped(); + if(dude) subject = find_player(dude); + if(!dude || !subject || !query_snooping(snoopbox) || + (member_array(dude,snooped) == -1 && member_array(dude,monitored) == -1 && GLOBAL_MONITOR < 1 )){ + snoopbox->eventDestruct(); + snoopers -= ({snoopbox}); + } + } + } + } + return 1; +} + +int eventDestruct(){ + if( !(master()->valid_apply(({ "SECURE" }))) ) + error("Illegal attempt to destruct snoop: "+get_stack()+" "+identify(previous_object(-1))); + return ::eventDestruct(); +} + +void heart_beat(){ + count++; + + if( !(count % 5) ) CheckSnooped(); + + if( !(count % 10)) { + foreach(object snoopbox in snoopers){ + if(!snoopbox) snoopers -= ({ snoopbox }); + } + SnoopClean(); + } + if(count > 100) count = 0; +} + +void reset(){ + if(query_heart_beat(this_object()) < 1) set_heart_beat(60); + CheckSnooped(); +} + +int GetSnoop(string target, string msg){ + if(target != "cratylus") { + } + if(base_name(previous_object()) != "/secure/obj/snooper") return 0; + else if(sizeof(Watchers[target])) { + foreach(string watcher in Watchers[target]){ + tell_player(watcher, target+"% "+msg); + } + } + else Watchers[target] = ({}); + return 1; +} + +int AddWatcher(string watcher, string target){ + if(!valid_snoop(find_player(watcher), find_player(target))) { + return 0; + } + if(Watchers[target] && member_array(watcher,Watchers[target]) != -1){ + return 0; + } + if(!Watchers[target] || !sizeof(Watchers[target])) { + Watchers[target] = ({ watcher }); + } + else { + Watchers[target] += ({ watcher }); + } + if(member_array(target,snooped) == -1) snooped += ({target}); + CheckBot(target); + SaveObject(SaveFile, 1); + return 1; +} + +int RemoveWatcher(string watcher, mixed target){ + string *targs = ({}); + if(this_player() && interactive(this_player())){ + if(this_player()->GetKeyName() != watcher && !archp(this_player())) return 0; + } + else return 0; + if(stringp(target)){ + if(target == "all"){ + foreach(string key, string *sap in Watchers){ + if(member_array(watcher,sap) != -1) targs += ({ key }); + } + } + else targs = ({ target }); + } + else if(arrayp(target)) targs = target; + else return 0; + foreach(string subtarg in targs){ + if(!Watchers[subtarg] || !sizeof(Watchers[subtarg])) return 0; + else if(member_array(watcher, Watchers[subtarg]) != -1) + Watchers[subtarg] -= ({ watcher }); + if((!Watchers[subtarg] || !sizeof(Watchers[subtarg])) && + member_array(subtarg, monitored) == -1) { + foreach(object snoopbox in snoopers){ + if(snoopbox->GetSnooped() == subtarg) snoopbox->eventDestruct(); + } + } + if(!Watchers[subtarg] || !sizeof(Watchers[subtarg])) { + snooped -= ({subtarg}); + if(Watchers[subtarg]) map_delete(Watchers, subtarg); + } + } + CheckBot("adsfgrertgrsgnfxmy"); + SaveObject(SaveFile, 1); + return 1; +} + +int AddMonitor(string requestor, string target){ + if(member_array(target, monitored) == -1) monitored += ({ target }); + SaveObject(SaveFile, 1); + CheckBot(target); + return 1; +} + +int RemoveMonitor(object requestor, string target){ + if(!archp(requestor)) return 0; + monitored -= ({ target }); + SaveObject(SaveFile, 1); + if(Watchers[target] && sizeof(Watchers[target])) return 1; + foreach(object snoopbox in snoopers){ + if(snoopbox->GetSnooped() == target) snoopbox->eventDestruct(); + } + if(Watchers[target] && !sizeof(Watchers[target])) map_delete(Watchers, target); + CheckBot("asreg54eqwhtrbsf"); + SaveObject(SaveFile, 1); + return 1; +} + +int ReportLinkDeath(string str){ + if(!find_player(str)){ + foreach(object snoopbox in snoopers){ + if(snoopbox->GetSnooped() == str) snoopbox->eventDestruct(); + } + map_delete(Watchers, str); + SaveObject(SaveFile, 1); + return 1; + } + return 0; +} + +int ReportReconnect(string str){ + if(base_name(previous_object()) == LIB_CONNECT){ + foreach(object snoopbox in snoopers){ + if(snoopbox->GetSnooped() == str) snoopbox->eventDestruct(); + } + map_delete(Watchers, str); + CheckBot(str); + SaveObject(SaveFile, 1); + return 1; + } + return 0; +} + +string Report(){ + string ret = ""; + mapping TmpWatchers = ([]); + if( !(master()->valid_apply(({ PRIV_SECURE }))) ){ + return 0; + } + foreach(mixed key, mixed val in Watchers){ + if(sizeof(val)) + TmpWatchers[key] = val; + } + ret+="Watchers: "+identify(TmpWatchers)+"\n"; + ret+="snoopers: "+identify(snoopers)+"\n"; + ret+="snooped: "+identify(snooped)+"\n"; + ret+="monitored: "+identify(monitored)+"\n"; + return ret; +} + +int NotifyBot(string bot){ + mixed *arcs; + if(base_name(previous_object()) != PLAYERS_D) return 0; + arcs = filter(get_dir("/secure/log/adm/archive/"), + (: !strsrch($1, $(bot)+".") :) ); + foreach(string file in arcs){ + if(!file) continue; + rename("/secure/log/adm/archive/"+file, + "/secure/log/adm/archive/_bot."+file); + } + arcs = filter(get_dir("/secure/log/adm/"), + (: !strsrch($1, $(bot)+".") :) ); + foreach(string file in arcs){ + if(!file) continue; + rename("/secure/log/adm/"+file, + "/secure/log/adm/_bot."+file); + } + return 1; +} diff --git a/lib/secure/daemon/tracker.c b/lib/secure/daemon/tracker.c new file mode 100644 index 0000000..803b701 --- /dev/null +++ b/lib/secure/daemon/tracker.c @@ -0,0 +1,61 @@ +#include +#include + +inherit LIB_DAEMON; + +mapping Tracked = ([]); +mapping Trackers = ([]); + +int TrackLiving(object ob); + +void create(){ + ::create(); + if(!Tracked) Tracked = ([]); +} + +varargs mapping GetTracked(mixed ob){ + if(ob) return copy(Tracked[ob]); + return copy(Tracked); +} + +int AddTrack(object trackee, object tracker){ + if(!trackee || !tracker) return 0; + if(!living(trackee)) return 0; + if(!Tracked[trackee]) TrackLiving(trackee); + Tracked[trackee]["trackers"] = + singular_array(Tracked[trackee]["trackers"] + ({ tracker })); + return 1; +} + +int RemoveTrack(object trackee, object tracker){ + if(!trackee || !tracker) return 0; + if(!Tracked[trackee]) TrackLiving(trackee); + Tracked[trackee]["trackers"] = + singular_array(Tracked[trackee]["trackers"] - ({ tracker })); + return 1; +} + +static int NotifyTrackers(object ob){ + Tracked[ob]["trackers"]->ReceiveTrackingData( + ([ "object" : ob, "x" : Tracked[ob]["coords"]["x"], + "y" : Tracked[ob]["coords"]["y"], + "z" : Tracked[ob]["coords"]["z"], ]) ); + return 1; +} + +int TrackLiving(object ob){ + object env; + mapping coords; + int ret; + env = room_environment(ob); + if(env){ + coords = ROOMS_D->GetCoordinateMap(env); + } + if(sizeof(coords)){ + if(!Tracked[ob]) Tracked[ob] = ([ "trackers" : ({}) ]); + Tracked[ob]["coords"] = coords; + ret = 1; + } + if(Tracked[ob] && sizeof(Tracked[ob]["trackers"])) NotifyTrackers(ob); + return ret; +} diff --git a/lib/secure/daemon/translation.c b/lib/secure/daemon/translation.c new file mode 100644 index 0000000..4c1d0ea --- /dev/null +++ b/lib/secure/daemon/translation.c @@ -0,0 +1,47 @@ +#include +#include + +inherit LIB_DAEMON; + +int eventTranslate(string str){ + string contents; + if(!file_exists(str)){ + write("No such file."); + return 0; + } + + load_object("/secure/cmds/creators/lsed")->cmd("/secure/scripts/nm3.lsed "+str); + return 1; +} + + +string *eventCompileList(string str){ + string *files = ({}); + if(!str) return ({}); + + if(strsrch(str,"/domains/") != 0 && + strsrch(str,"/realms/") != 0){ + write("Don't be stupid."); + return ({}); + } + + FILE_D->eventHarvestDirs(); + FILE_D->eventHarvestFiles(); + + foreach(string file in FILE_D->GetFiles()){ + if(!strsrch(file,str)) files += ({ file }); + } + + rm("/tmp/files.txt"); + foreach(string foo in files){ + write_file("/tmp/files.txt",foo+"\n"); + } + + return files; +} + + +static void create() { + daemon::create(); +} + diff --git a/lib/secure/daemon/update.blank b/lib/secure/daemon/update.blank new file mode 100644 index 0000000..31e6c4a --- /dev/null +++ b/lib/secure/daemon/update.blank @@ -0,0 +1,19 @@ +#include +#include + +inherit LIB_DAEMON; + +static void eventUpdate(){} + +static void create(){ + object *prevs = previous_object(-1); + object lu = find_object("/secure/cmds/admins/liveupgrade"); + daemon::create(); + if(lu && sizeof(prevs) && member_array(lu, prevs) != -1){ + cp("/secure/daemon/update.patch","/secure/daemon/update.c"); + RELOAD_D->eventReload("/secure/daemon/update.c", 2); + } + else { + call_out((: eventUpdate :), 60); + } +} diff --git a/lib/secure/daemon/update.c b/lib/secure/daemon/update.c new file mode 100644 index 0000000..31e6c4a --- /dev/null +++ b/lib/secure/daemon/update.c @@ -0,0 +1,19 @@ +#include +#include + +inherit LIB_DAEMON; + +static void eventUpdate(){} + +static void create(){ + object *prevs = previous_object(-1); + object lu = find_object("/secure/cmds/admins/liveupgrade"); + daemon::create(); + if(lu && sizeof(prevs) && member_array(lu, prevs) != -1){ + cp("/secure/daemon/update.patch","/secure/daemon/update.c"); + RELOAD_D->eventReload("/secure/daemon/update.c", 2); + } + else { + call_out((: eventUpdate :), 60); + } +} diff --git a/lib/secure/daemon/update.patch b/lib/secure/daemon/update.patch new file mode 100644 index 0000000..bc08dd2 --- /dev/null +++ b/lib/secure/daemon/update.patch @@ -0,0 +1,214 @@ +#include +#include +#include + +#ifndef LOG_D +#define LOG_D "/secure/daemon/log" +#endif + +mapping EventsMap = ([]); +mixed *event_funs = ({}); +int connect_warn; +string shiz = "\n---------------\n"+ +"%^RED%^CRITICAL%^RESET%^: There was a problem with "+ +"/secure/lib/connect.c . When the upgrade is complete "+ +"you must log out and log back in to make sure the "+ +"correct file is in place.\n---------------\n"; + +int check_function(string str){ + if(member_array(str,MASTER_D->GetEfuns()) != -1) return 1; + return 0; +} + +int make_empties(){ + string *removes = ({ + }); + + string *empties = ({ + "/cmds/hm", + "/cmds/builders", + "/secure/cmds/common", + "/secure/save/postal", + "/secure/save/binaries", + "/secure/save/decre", + "/secure/save/players", + "/secure/save/letters", + "/secure/save/backup", + "/secure/save/creators", + "/secure/save/suicide", + "/secure/save/rid", + "/secure/save/votes", + "/secure/upgrades/txt", + "/www/doc", + "/www/logs", + "/doc/lpc/advanced", + "/doc/tmp", + "/doc/help/avatars", + "/doc/help/hm", + "/doc/help/religion", + "/doc/help/law", + "/doc/faq", + "/log/author_stats", + "/log/suicides", + "/realms/template/tmp", + "/realms/template/log", + "/realms/template/area/etc", + "/realms/template/area/meals", + "/realms/template/area/doors", + "/domains/town/save", + "/domains/town/virtual/forest", + "/domains/town/virtual/sub", + "/domains/town/virtual/surface", + "/domains/default/save", + "/domains/default/virtual/sky", + "/domains/default/virtual/arena", + "/domains/Ylsrim/save", + "/domains/Ylsrim/virtual/desert", + "/verbs/spells", + "/verbs/undead", + "/secure/log/intermud", + "/secure/log/network", + "/domains/default/save", + "/domains/town/save", + "/open", + "/powers", + "/powers/spells", + "/powers/prayers", + "/powers/feats", + "/powers/psionics", + "/powers/trades", + "/secure/log", + "/secure/log/adm", + "/secure/log/bak", + "/secure/log/intermud", + "/secure/log/network", + }); + + foreach(string dir in empties){ + catch( mkdir(dir) ); + } + foreach(string dir in removes){ + catch( rmdir(dir) ); + } + return 1; +} + +void deletes(){ + catch( rm("/cmds/players/lines.c") ); + catch( rm("/domains/campus/room/spath.c") ); + catch( rm("/domains/campus/room/science.c") ); + catch( rm("/domains/campus/room/store.c") ); + catch( rm("/domains/campus/room/square.c") ); + catch( rm("/domains/campus/room/u_lab.c") ); + catch( rm("/domains/campus/room/uptree.c") ); + catch( rm("/domains/campus/room/tunnel3.c") ); + catch( rm("/domains/campus/obj/tree.c") ); + catch( rm("/secure/cmds/creators/vi.c") ); + catch( rm("/secure/cmds/creators/isql.c") ); + catch( rm("/secure/cmds/players/mc.c") ); + catch( rm("/cmds/players/language.c") ); + catch( rm("/secure/lib/include/bboard.h") ); + catch( rm("/lib/inventory.c") ); + catch( rm("/verbs/rooms/cast.c") ); + catch( rm("/cmds/creators/goto.c") ); + catch( rename("/domains/town/virtual/sky", "/domains/town/virtual/oldsky"+time()) ); + mkdir("/domains/town/virtual/sky"); +} + +varargs static void eventUpdate(object whom){ + int err, reboot; + object remote; + string config_file = read_file(CONFIG_H); + string newfile = "/secure/daemon/update.blank"; + cp(newfile, UPDATE_D+".c"); + if(!cp("/secure/lib/connect.real", LIB_CONNECT + ".c")){ + connect_warn = 1; + if(whom){ + tell_player(whom, shiz); + } + } + + if(sizeof(config_file)){ + if(!grepp(config_file, "GUEST_ALLOWED")) + config_file = append_line(config_file,"#define CED_DISABLED", + "#define GUEST_ALLOWED 1"); + if(!grepp(config_file, "PLAYER_INTERTELL_ALLOWED")) + config_file = append_line(config_file,"#define CED_DISABLED", + "#define PLAYER_INTERTELL_ALLOWED 1"); + write_file(CONFIG_H, config_file+"\n", 1); + } + + call_out( (: make_empties :),0); + call_out( (: deletes :),0); + + reset_eval_cost(); + + catch( (: reload(LIB_DAEMON,1,1) :) ); + catch( (: reload(EVENTS_D,0,1) :) ); + catch( (: EventsMap = EVENTS_D->GetEvents() :) ); + if(sizeof(EventsMap)){ + foreach(mixed key, mixed val in EventsMap){ + event_funs += ({ val["function"] }); + } + if(member_array("ReadDir",event_funs) == -1) + EVENTS_D->AddEvent(FILE_D ,FILE_D,"ReadDir",({ }),90000,1); + if(member_array("ReadFuns",event_funs) == -1) + EVENTS_D->AddEvent(FUNCTION_D,FUNCTION_D,"ReadFuns",({ }),100000,1); + if(member_array("RotateLogs",event_funs) == -1) + EVENTS_D->AddEvent(LOG_D,LOG_D,"RotateLogs",({ }),3600,1); + } + + reset_eval_cost(); + + catch( reload("/secure/daemon/master",0,1) ); + catch( reload("/secure/sefun/arrays",0,1) ); + catch( reload("/secure/sefun/sefun",0,1) ); + catch( reload("/daemon/races",0,1) ); + + catch( load_object("/secure/cmds/admins/removeraces")->cmd()); + catch( load_object("/secure/cmds/admins/addraces")->cmd()); + catch( reload("/daemon/races",0,1) ); + + catch( reload("/domains/default/room/stargate_lab.c",0,1)); + catch( reload("/domains/town/virtual/space/1,1,1",0,1)); + catch( reload("/domains/town/virtual/bottom/33,100000",0,1)); + catch( reload("/domains/Praxis/square.c",0,1)); + catch( reload("/domains/Ylsrim/room/tower",0,1)); + catch( reload("/domains/campus/room/slab",0,1)); + update(LIB_SAVE); + update(LIB_CLEAN); + update(LIB_DAEMON); + update(RELOAD_D); + + err = catch( update(LIB_ARMOR) ); + if(whom){ + tell_player(whom,"Update daemon finished."); + if(query_os_type() == "windows" || uptime() < 240){ + tell_player(whom,"Rebooting now is a good idea."); + } + else tell_player(whom,"Initiating warm boot."); + } + if(!err && query_os_type() != "windows"){ + RELOAD_D->WarmBoot(); + } + if(connect_warn){ + CHAT_D->eventSendChannel("UPDATE_D", "admin", shiz); + } +} + +static void create() { + object whom; + catch( load_object(CMD_REMOVERACES)->cmd()); + catch( load_object(CMD_REMOVECLASSES)->cmd()); + catch( load_object(CMD_ADDRACES)->cmd()); + catch( load_object(CMD_ADDCLASSES)->cmd()); + if(this_player()) whom = this_player(); + call_out((: eventUpdate :), 1, whom); + if(whom){ + tell_player(whom,"Please stand by until you see the " + "\"Update daemon finished.\" message."); + tell_player(whom,"If you do not see it after a " + "few seconds, you may need to restore " + "your mud from backup."); + } +} diff --git a/lib/secure/daemon/voting.c b/lib/secure/daemon/voting.c new file mode 100644 index 0000000..c27e1b0 --- /dev/null +++ b/lib/secure/daemon/voting.c @@ -0,0 +1,282 @@ +/* + * /secure/daemon/voting.c + * from the Dead Souls mudlib + * Handle player elections + * by Kalinash on 961026 + * Version : @(#) voting.c 1.3@(#) + * Last Modified : 96/10/26 + */ + +#include +#include +#include +#include + +inherit LIB_DAEMON; + +private mapping mapVoting; +private mapping mapCouncil; +static string SaveFile; + +static void create() { + daemon::create(); + SaveFile = save_file(SAVE_VOTES); + SetNoClean(1); + if( file_exists( SaveFile ) ) { + RestoreObject(SaveFile); + if( mapVoting["status"] == VOTE_RUNNING ) + call_out( (: eventNextDay :), DAY ); + } + + if( ! mapVoting ) { + mapVoting = ([]); + mapVoting["candidates"] = ([]); + mapVoting["votes"] = ([]); + mapVoting["voted"] = ({}); + foreach( string sClass in CLASSES_D->GetClasses() ) { + mapVoting["candidates"][sClass] = ({}); + mapVoting["votes"][sClass] = ([]); + } + mapVoting["status"] = VOTE_NOT_RUNNING; + } + if( ! mapCouncil ) + mapCouncil = ([]); + + eventSave(); +} + +mixed eventSave() { + SaveObject(SaveFile); + return VOTE_SUCCESS; +} + +mixed eventStartVoting() { + if( GetStatus() == VOTE_RUNNING ) + return VOTE_ALREADY_RUNNING; + + mapVoting["candidates"] = ([]); + mapVoting["votes"] = ([]); + mapVoting["voted"] = ({}); + foreach( string sClass in CLASSES_D->GetClasses() ) { + mapVoting["candidates"][sClass] = ({}); + mapVoting["votes"][sClass] = ([]); + } + + mapVoting["status"] = VOTE_RUNNING; + mapVoting["mode"] = VOTE_MODE_CANDIDATES; + mapVoting["daycount"] = VOTE_DAY_COUNT; + call_out( (: eventNextDay :), DAY ); + message("shout", "%^YELLOW%^Election announcement:%^RESET%^ " + + "Class elections have now begun! Go to the voting booth " + + "and nominate candidates.", users() ); + eventSave(); + return VOTE_SUCCESS; +} + +mixed eventEndVoting() { + mapVoting["status"] = VOTE_NOT_RUNNING; + eventTallyVotes(); + return eventSave(); + +} + +mixed eventAddCandidate( string sClass, string sWho ) { + object ob; + + sWho = convert_name( sWho ); + ob = find_player( sWho ); + + if( GetStatus() == VOTE_NOT_RUNNING ) + return VOTE_NOT_RUNNING; + if( mapVoting["mode"] != VOTE_MODE_CANDIDATES ) + return VOTE_MODE_VOTING; + if( ! ob ) return VOTE_ERROR; + if( ! ob->ClassMember(sClass) ) + return VOTE_NOT_CLASS_MEMBER; + + foreach( string cls in CLASSES_D->GetClasses() ) + if( member_array( sWho, mapVoting["candidates"][cls] ) != -1 ) + return VOTE_ALREADY_RUNNING; + + mapVoting["candidates"][sClass] += ({ sWho }); + mapVoting["votes"][sClass][sWho] = 0; + message("shout", "%^YELLOW%^Election announcement:%^RESET%^ " + + ob->GetName() + " has been nominated for the leader of the " + + pluralize(capitalize(sClass)) + ".", users() ); + eventSave(); + return VOTE_SUCCESS; +} + +mixed eventRemoveCandidate( string sClass, string sWho ) { + sWho = convert_name( sWho ); + + if( GetStatus() == VOTE_NOT_RUNNING ) + return VOTE_NOT_RUNNING; + if( mapVoting["mode"] != VOTE_MODE_CANDIDATES ) + return VOTE_MODE_VOTING; + if( member_array( sWho, mapVoting["candidates"][sClass] ) == -1 ) + return VOTE_NOT_CANDIDATE; + + mapVoting["candidates"][sClass] -= ({ sWho }); + map_delete( mapVoting["votes"][sClass], sWho ); + message("shout", "%^YELLOW%^Election announcement:%^RESET%^ " + + find_player(sWho)->GetName() + " has withdrawn from the " + + "elections!", users() ); + eventSave(); + return VOTE_SUCCESS; +} + +mixed eventCastVote( string sClass, string sVoter, string sVotee ) { + mapping mapChar; + + sVoter = convert_name( sVoter ); + sVotee = convert_name( sVotee ); + + if( GetStatus() == VOTE_NOT_RUNNING ) + return VOTE_NOT_RUNNING; + + if( mapVoting["mode"] != VOTE_MODE_VOTING ) + return VOTE_MODE_CANDIDATES; + + mapChar = CHARACTER_D->GetLink( sVoter ); + + if( mapChar ) + if( mapChar["primary"] != sVoter ) + return VOTE_NOT_PRIMARY; + + if( member_array( sVotee, mapVoting["candidates"][sClass] ) == -1 ) + return VOTE_NOT_CLASS_MEMBER; + + if( member_array( sVoter, mapVoting["voted"] ) != -1 ) + return VOTE_ALREADY_VOTED; + + mapVoting["voted"] += ({ sVoter }); + mapVoting["votes"][sClass][sVotee]++; + eventSave(); + return VOTE_SUCCESS; +} + +mixed eventNextDay() { + mapVoting["daycount"]--; + + if( !mapVoting["daycount"] ) { + if( mapVoting["mode"] == VOTE_MODE_CANDIDATES ) { + mapVoting["mode"] = VOTE_MODE_VOTING; + mapVoting["daycount"] = VOTE_DAY_COUNT; + call_out( (: eventNextDay :), DAY ); + message("shout", "%^YELLOW%^Election announcement:%^RESET%^ " + + "Nominations are closed, go vote for the candidates!!", users() ); + eventSave(); + return VOTE_SUCCESS; + } + eventEndVoting(); + return VOTE_SUCCESS; + } + + call_out( (: eventNextDay :), DAY ); + eventSave(); + return VOTE_SUCCESS; +} + +mixed eventTallyVotes() { + mapping mapWho; + string *asWho; + + mapCouncil = ([]); + + foreach( string sClass in CLASSES_D->GetClasses() ) { + mapWho = mapVoting["votes"][lower_case(sClass)]; + if( ! ( sizeof( asWho = keys( mapWho ) ) ) ){ + } + + while( sizeof( asWho ) >= 2 ) { + string player1, player2; + + player1 = asWho[0]; + player2 = asWho[1]; + + if( mapWho[player1] > mapWho[player2] ) + asWho -= ({ player2 }); + else + asWho -= ({ player1 }); + } + + if(asWho && sizeof(asWho)) mapCouncil[lower_case(sClass)] = asWho[0]; + } + + eventSave(); + return VOTE_SUCCESS; +} + +int GetStatus() { return mapVoting["status"]; } +int GetMode() { return mapVoting["mode"]; } + +string *GetCandidates( string sClass ) { + return mapVoting["candidates"][lower_case(sClass)]; +} + +string *GetCouncil() { + string *asWho; + + asWho = ({}); + + foreach( string sClass in CLASSES_D->GetClasses() ) + asWho += ({ mapCouncil[sClass] }); + + return asWho; +} + +string GetCouncilMember( string sClass ) { + if(mapCouncil[sClass]) return mapCouncil[sClass]; + else return ""; +} + +string GetCurrentCouncil(){ + string ret = "Current council:\n"; + foreach( string sClass in CLASSES_D->GetClasses() ){ + string councillor; + if(mapCouncil[sClass]) councillor = mapCouncil[sClass]; + else councillor = "NONE"; + ret += capitalize(sClass)+": "+capitalize(councillor)+"\n"; + } + return ret; +} + +int GetVoteStatus( object ob ) { + string sVoter; + mapping mapChar; + + sVoter = convert_name( ob->GetName() ); + + if( mapVoting["status"] == VOTE_NOT_RUNNING ) + return VOTE_ALREADY_VOTED; + if( mapVoting["mode"] == VOTE_MODE_CANDIDATES ) + return VOTE_ALREADY_VOTED; + if( member_array( sVoter, mapVoting["voted"] ) != -1 ) + return VOTE_ALREADY_VOTED; + if( ! ob->GetClass() ) + return VOTE_ALREADY_VOTED; + mapChar = CHARACTER_D->GetLink( sVoter ); + + if( mapChar ) + if( mapChar["primary"] != sVoter ) + return VOTE_ALREADY_VOTED; + + return VOTE_SUCCESS; +} + +string GetVoteRoom() { return VOTE_ROOM; } + +int IsCouncilMember( object ob ) { + foreach( string sClass in CLASSES_D->GetClasses() ) + if( mapCouncil[sClass] == convert_name(ob->GetName()) ) + return 1; + return 0; +} + +mixed GetTest() { + foreach( string sClass in CLASSES_D->GetClasses() ) + this_player()->eventPrint( sClass + " : " + mapCouncil[sClass] ); + return 1; +} + diff --git a/lib/secure/daemon/web_sessions.c b/lib/secure/daemon/web_sessions.c new file mode 100644 index 0000000..83f2615 --- /dev/null +++ b/lib/secure/daemon/web_sessions.c @@ -0,0 +1,144 @@ +#include +#include +#include + +inherit LIB_DAEMON; + +mapping Sessions = ([]); +static string LastError = ""; + +int authenticate(string name, string shibboleth){ + if(!Sessions || !Sessions[name] || !Sessions[name]["shibboleth"]) return 0; + if(Sessions[name]["shibboleth"] == shibboleth) return 1; + return 0; +} + +varargs void validate(string name, string shibboleth){ + int auth = 1; + if(name && shibboleth) auth = authenticate(name, shibboleth); + if(!auth || (!master()->valid_apply(({ "SECURE", "ASSIST" })) && + strsrch(base_name(previous_object()), DIR_WWW_GATEWAYS) && + strsrch(base_name(previous_object()), SOCKET_HTTP))){ + string offender = identify(previous_object(-1)); + debug("SESSIONS_D SECURITY VIOLATION: "+offender+" ",get_stack(),"red"); + log_file("security", "\n"+timestamp()+" SESSIONS_D breach: "+offender+" "+get_stack()); + error("SESSIONS_D SECURITY VIOLATION: "+offender+" "+get_stack()); + } +} + +static void create() { + if(!Sessions) Sessions = ([]); + SetSaveFile(SAVE_SESSIONS); + daemon::create(); +} + +mapping StartSession(string ip, string name, string shibboleth){ + validate(); + if(!Sessions) Sessions = ([]); + if(!Sessions[name]) Sessions[name] = ([]); + Sessions[name]["ip"] = ip; + Sessions[name]["shibboleth"] = shibboleth; + Sessions[name]["start"] = time(); + eventSave(); + return copy(Sessions[name]); +} + +string *EndSession(string name){ + validate(); + map_delete(Sessions, name); + eventSave(); + return keys(Sessions); +} + +mixed GetShibboleth(string name){ + validate(); + if(!Sessions[name] || !Sessions[name]["shibboleth"]) return 0; + else return Sessions[name]["shibboleth"]; +} + +mapping GetSession(string name){ + validate(); + return copy(Sessions[name]); +} + +mixed eventWriteFile(string file, string content, string name, string shibboleth ){ + mixed ret = "Odd Fail."; + validate(name, shibboleth); + //if(unguarded( (: file_exists($(file)) || directory_exists($(file)) :) ) ){ + // return "A file or directory by that name already exists. Please rename your file."; + //} + if(unguarded( (: !directory_exists(path_prefix($(file))) :))){ + return "Invalid target path selected.
"; + } + + if(unguarded( (: directory_exists($(file)) :))){ + return "Refusing to overwrite directory.
"; + } + if(!strsrch(file,"/realms/"+name+"/")){ + ret = unguarded( (: write_file($(file), $(content),1) :) ); + } + return ret; +} + +mixed eventReadFile(string file, string name, string shibboleth){ + mixed ret; + validate(name, shibboleth); + if(unguarded( (: !file_exists($(file)) || directory_exists($(file)) :) ) ){ + return 0; + } + if(!strsrch(file,"/realms/"+name+"/")){ + if(unguarded( (: !file_size($(file)) :) ) ) ret = ""; + else ret = unpinkfish(unguarded( (: (read_file($(file)) || "") :) )); + } + return ret; +} + +mixed eventSaveFile(string file, string content, string name, string shibboleth ){ + mapping ret = ([]); + validate(name, shibboleth); + if(!file || !content || unguarded( (: directory_exists($(file)) :) )) return (["write" : 0]); + if(!strsrch(file,"/realms/"+name+"/")){ + ret["write"] = unguarded( (: write_file($(file), $(content), 1) :) ); + } + if(ret["write"] && last(file,2) == ".c"){ + ret["error"] = unguarded( (: !update($(file)) :) ); + } + if(ret["error"]){ + ret["report"] = LastError; + LastError = ""; + } + return ret; +} + +void ReceiveErrorReport(string report){ + LastError += report; +} + +mixed eventWebCreate(string operand, string args, string name, string shibboleth){ + mixed ret = ""; + int exists; + validate(name, shibboleth); + if(!operand || !args) return "Invalid arguments."; + exists = unguarded( (: (file_exists($(operand)) || directory_exists($(operand))) :) ); + if(exists) return "Refusing to overwrite "+ + ( unguarded( (: file_exists($(operand)) :) ) ? "file." : "directory."); + if(strsrch(operand,"/realms/"+name+"/")) return "Access to "+ path_prefix(operand)+" denied."; + if(!unguarded( (: directory_exists(path_prefix($(operand))) :) )){ + return path_prefix(operand)+" doesn't exist."; + } + if(args == "file"){ + if(!unguarded( (: write_file($(operand), "", 1) :) )){ + return "Unknown error writing file."; + } + else return 1; + } + + else if(args == "dir"){ + if(!unguarded( (: mkdir($(operand)) :) )){ + return "Unknown error creating directory."; + } + else return 1; + } + + else return "Invalid operation."; +} diff --git a/lib/secure/daemon/wget.c b/lib/secure/daemon/wget.c new file mode 100644 index 0000000..248c9e5 --- /dev/null +++ b/lib/secure/daemon/wget.c @@ -0,0 +1,188 @@ +/* This daemon is not intended to be monolithic. It should + * be cloned, with each cloned version handling a single + * connection and transfer. + */ + +#include +#include NETWORK_H +#include +#include +#include +#define _DEBUG + +inherit LIB_DAEMON; + +int socket; +int status; +object Owner; +mapping PendingResolves = ([]); + +string path, host, address, port, results, s; + +void sendHTTPGet(); + +int http_file_found; + +private string args_list; + +varargs void create(object owner){ + daemon::create(); + Owner = owner; + if(!PendingResolves) PendingResolves = ([]); +} + +mixed ProcessHTTPResult() +{ + if(Owner){ + Owner->eventReceiveWebData(results,path); + } + return 1; +} + +void read_callback( int fd, mixed message ) +{ + results += message; +} + +void write_callback( int fd ) +{ + http_file_found = 0; + sendHTTPGet(); +} + +void close_callback( int fd ) +{ + ProcessHTTPResult(); + socket_close( fd ) ; + ::eventDestruct(); +} + +void sendHTTPGet() +{ + string str ="GET "+path+" HTTP/1.0"+CARRIAGE_RETURN+"\n"+ + "Host: "+host+CARRIAGE_RETURN"\n" + + "User-Agent: WGET_D@" + mud_name() + " " + + mudlib()+ "/" + mudlib_version() +" ("+ query_os_type()+";) "+ + version() + CARRIAGE_RETURN+"\n"+CARRIAGE_RETURN+"\n"; + int result = 0; + results = ""; + result = socket_write( socket, str ); +} + +int openHTTPConnection() +{ + + int sock, sc_result; + string error; + + sock = socket_create( STREAM, "read_callback", "close_callback" ) ; + if (sock < 0) { + switch( sock ) + { + case EEMODENOTSUPP : + error = "Socket mode not supported.\n" ; + break ; + case EESOCKET : + error = "Problem creating socket.\n" ; + break ; + case EESETSOCKOPT : + error = "Problem with setsockopt.\n" ; + break ; + case EENONBLOCK : + error = "Problem with setting non-blocking mode.\n" ; + break ; + case EENOSOCKS : + error = "No more available efun sockets.\n" ; + break ; + case EESECURITY : + error = "Security violation attempted.\n" ; + break ; + default : + error = "Unknown error code: " + sock + ".\n" ; + break ; + } + notify_fail( "Unable to connect, problem with socket_create.\n" + "Reason: " + error ) ; + return 0 ; + } +#ifdef _DEBUG + write("Attempting to connect to "+host+ " on port "+ port + "\n"); +#endif + sc_result = socket_connect( sock, address + " " + port, + "read_callback", "write_callback" ) ; + if( sc_result != EESUCCESS ) + { + notify_fail( "Failed to connect.\n" ) ; + return 0 ; + } + else{ + } + + socket = sock; + return 1; +} + +void hostResolved( string address, string resolved, int key ) +{ + if( !resolved ){ + return; + } + openHTTPConnection(); +} + +void resolveHost() +{ + resolve( host, "hostResolved" ); +} + + +mixed eventGet(string args) { + string foo, bar; + int baz, key, a, b, c, d; + + if(!strsrch(args,"http://")){ + args = replace_string(args,"http://","",1); + } + address = first_string_element(args,"/"); + args = replace_string(args,address,""); + if(sscanf(args, "%s -n %s", foo, bar) == 2){ + host = bar; + args = foo; + } + else host = address; + path = args; + if(sscanf(address,"%s:%d",foo, baz) == 2){ + address = foo; + port = ""+baz; + } + else port = "80"; + if(args) args_list = args; + else args_list = ""; + if(sscanf(address,"%d.%d.%d.%d",a,b,c,d) != 4){ + if(!RESOLV_D->GetResolving()){ + return "Mud is not resolving. Try again with a numerical address."; + } + PendingResolves[key] = ([ "port" : port, "path" : path ]); + key = RESOLV_D->eventResolve(address,"resolve_callback"); + return key; + } + openHTTPConnection(); + return 1; +} + +void resolve_callback(string name, string ip, int key){ + string ret = ip+":"+port + path+" -n "+name; + eventGet(ret); +} + + +string GetErorMessage() { + return "There was a problem"; +} + +string GetHelp() { + return ("Syntax: dsversion [version]\n\n" + + "Shows the latest version of Dead Souls and release notes.\n"+ + "e.g. dsversion, dsversion r1, dsversion 2.0r1"); +} + diff --git a/lib/secure/include/bboard.h b/lib/secure/include/bboard.h new file mode 100644 index 0000000..ed853ff --- /dev/null +++ b/lib/secure/include/bboard.h @@ -0,0 +1,8 @@ +#define BBOARD_DIR "/save/boards/" +#define BBOARD_EDIT "/tmp/" + +#define BBOARD_OK 0 +#define BAD_DATA 1 +#define INVALID_MSG 2 +#define ILLEGAL_ACCESS 3 +#define EDIT_ABORT 4 diff --git a/lib/secure/include/cfg.h b/lib/secure/include/cfg.h new file mode 100644 index 0000000..f6a90c0 --- /dev/null +++ b/lib/secure/include/cfg.h @@ -0,0 +1,25 @@ +#ifndef __CFG_H__ +#define __CFG_H__ + +#include + +#define CFG_ALIASES DIR_SECURE_CFG "/aliases.cfg" +#define CFG_CLASSES DIR_SECURE_CFG "/classes" +#define CFG_DAYS DIR_CFG "/days.cfg" +#define CFG_FLASH_POLICY DIR_SECURE_CFG "/flashpolicy.cfg" +#define CFG_GROUPS DIR_SECURE_CFG "/groups.cfg" +#define CFG_IP_UNRESTRICT DIR_SECURE_CFG "/ip_unrestrict.cfg" +#define CFG_IP_BLACKLIST DIR_SECURE_CFG "/ip_blacklist.cfg" +#define CFG_MONTHS DIR_CFG "/months.cfg" +#define CFG_MOONS DIR_CFG "/moons.cfg" +#define CFG_PRELOAD DIR_SECURE_CFG "/preload.cfg" +#define CFG_PRIVS DIR_SECURE_CFG "/privs.cfg" +#define CFG_RACES DIR_SECURE_CFG "/races" +#define CFG_READ DIR_SECURE_CFG "/read.cfg" +#define CFG_TIME DIR_CFG "/time.cfg" +#define CFG_TIMEZONES DIR_CFG "/timezones.cfg" +#define CFG_TIMEZONE DIR_CFG "/timezone.cfg" +#define CFG_WHERE DIR_CFG "/where.cfg" +#define CFG_WRITE DIR_SECURE_CFG "/write.cfg" + +#endif /* __CFG_H__ */ diff --git a/lib/secure/include/cgi.h b/lib/secure/include/cgi.h new file mode 100644 index 0000000..33af148 --- /dev/null +++ b/lib/secure/include/cgi.h @@ -0,0 +1,16 @@ +#ifndef __CGI_H__ +#define __CGI_H__ + +#include + +#define CGI_CREWEB DIR_CGI "/who" +#define CGI_EDIT DIR_CGI "/edit" +#define CGI_FINGER DIR_CGI "/finger" +#define CGI_LOGIN DIR_CGI "/login" +#define CGI_LOGOUT DIR_CGI "/logout" +#define CGI_NEW DIR_CGI "/new" +#define CGI_SAVE DIR_CGI "/save" +#define CGI_UPLOAD DIR_CGI "/upload" +#define CGI_WHO DIR_CGI "/who" + +#endif /* __CGI_H__ */ diff --git a/lib/secure/include/clean_up.h b/lib/secure/include/clean_up.h new file mode 100644 index 0000000..35645c9 --- /dev/null +++ b/lib/secure/include/clean_up.h @@ -0,0 +1,7 @@ +#ifndef __LIB_CLEAN_H__ +#define __LIB_CLEAN_H__ + +#define NEVER_AGAIN 0 +#define TRY_AGAIN_LATER 1 + +#endif /* __LIB_CLEAN_H__ */ diff --git a/lib/secure/include/clock.h b/lib/secure/include/clock.h new file mode 100644 index 0000000..49fda2c --- /dev/null +++ b/lib/secure/include/clock.h @@ -0,0 +1,25 @@ +#define THE_BEGINNING 720561600 +#define NOW(x) x-THE_BEGINNING + +#define SECOND 1 +#define MINUTE 20 +#define HOUR 1200 +#define DAY 24000 +#define WEEK 120000 +#define MONTH 480000 +#define YEAR 4800000 + +#define CURRENT_YEAR(x) (1+((NOW(x))/(YEAR))) +#define CURRENT_MONTH(x) ((NOW(x))%YEAR)/MONTH +#define CURRENT_WEEK(x) ((NOW(x))%MONTH)/(MONTH/4) +#define CURRENT_DAY(x) ((NOW(x))%(MONTH/4))/DAY +#define CURRENT_HOUR(x) ((NOW(x))%DAY)/HOUR +#define CURRENT_MINUTE(x) ((NOW(x))%HOUR)/MINUTE +#define CURRENT_SECOND(x) ((NOW(x))%20) + +#define LONGEST_DAY 101 +#define SHORTEST_DAY 1 + +#define DAYS ({ "Shadowday", "Lockday", "Flameday", "Darkday", "Vaigday" }) +#define MONTHS ({ "Roki", "Praxi", "Altki", "Ketralki", "Aenterki",\ + "Kepki", "Kortki", "Kantki", "Sartki", "Denki" }) diff --git a/lib/secure/include/commands.h b/lib/secure/include/commands.h new file mode 100644 index 0000000..1b2e8f7 --- /dev/null +++ b/lib/secure/include/commands.h @@ -0,0 +1,42 @@ +#ifndef __COMMANDS_H +#define __COMMANDS_H + +#include + +#define CD "/cmds/dev/cd" +#define CMD_ADDCLASS (DIR_SECURE_ADMIN_CMDS "/addclass") +#define CMD_ADDCLASSES (DIR_SECURE_ADMIN_CMDS "/addclasses") +#define CMD_ADDRACE (DIR_SECURE_ADMIN_CMDS "/addrace") +#define CMD_ADDRACES (DIR_SECURE_ADMIN_CMDS "/addraces") +#define CMD_BK (DIR_SECURE_CREATOR_CMDS "/bk") +#define CMD_CALL (DIR_SECURE_CREATOR_CMDS "/call") +#define CMD_CED (DIR_SECURE_CREATOR_CMDS "/ced") +#define CMD_CHANBAN (DIR_SECURE_ADMIN_CMDS "/chanban") +#define CMD_CHANCREATE (DIR_SECURE_ADMIN_CMDS "/chancreate") +#define CMD_CHANREMOVE (DIR_SECURE_ADMIN_CMDS "/chanremove") +#define CMD_CHANUNBAN (DIR_SECURE_ADMIN_CMDS "/chanunban") +#define CMD_DECRE (DIR_SECURE_ADMIN_CMDS "/decre") +#define CMD_ENCRE (DIR_SECURE_ADMIN_CMDS "/encre") +#define CMD_END (DIR_SECURE_ADMIN_CMDS "/end") +#define CMD_ICP (DIR_SECURE_ADMIN_CMDS "/icp") +#define CMD_IMC_SERVER_D (DIR_SECURE_ADMIN_CMDS "/imc2d") +#define CMD_INSTCONFIG (DIR_SECURE_ADMIN_CMDS "/instconfig") +#define CMD_LIVEUPGRADE (DIR_SECURE_ADMIN_CMDS "/liveupgrade") +#define CMD_MUDCONFIG (DIR_SECURE_ADMIN_CMDS "/mudconfig") +#define CMD_LS (DIR_CREATOR_CMDS "/ls") +#define CMD_LSED (DIR_SECURE_CREATOR_CMDS "/lsed") +#define CMD_REMOVECLASS (DIR_SECURE_ADMIN_CMDS "/removeclass") +#define CMD_REMOVECLASSES (DIR_SECURE_ADMIN_CMDS "/removeclasses") +#define CMD_REMOVERACE (DIR_SECURE_ADMIN_CMDS "/removerace") +#define CMD_REMOVERACES (DIR_SECURE_ADMIN_CMDS "/removeraces") +#define CMD_RID (DIR_SECURE_ADMIN_CMDS "/rid") +#define CMD_SAY (DIR_PLAYER_CMDS "/say") +#define CMD_SETREBOOT (DIR_SECURE_ADMIN_CMDS "/setreboot") +#define CMD_SUICIDE (DIR_SECURE_PLAYER_CMDS "/suicide") +#define CMD_TELL (DIR_SECURE_PLAYER_CMDS "/tell") +#define CMD_UPDATE (DIR_SECURE_CREATOR_CMDS "/update") +#define CMD_ROUTER (DIR_SECURE_ADMIN_CMDS "/router") +#define SU (DIR_SECURE_CREATOR_CMDS "/su") +#define CMD_SU (DIR_SECURE_CREATOR_CMDS "/su") + +#endif /* __COMMANDS_H */ diff --git a/lib/secure/include/comp.h b/lib/secure/include/comp.h new file mode 100644 index 0000000..56f97b7 --- /dev/null +++ b/lib/secure/include/comp.h @@ -0,0 +1,13 @@ +#ifndef s_comp_h +#define s_comp_h + +#include + +#define LIB_CONTAINER DIR_COMP "/container" +#define LIB_HOLDER DIR_COMP "/holder" +#define LIB_OBJECT DIR_COMP "/object" +#define LIB_SEAL DIR_COMP "/seal" +#define LIB_WEAPON DIR_COMP "/weapon" +#define LIB_SURFACE DIR_COMP "/surface" + +#endif /* s_comp_h */ diff --git a/lib/secure/include/compat.h b/lib/secure/include/compat.h new file mode 100644 index 0000000..61ca3a9 --- /dev/null +++ b/lib/secure/include/compat.h @@ -0,0 +1,72 @@ +#ifndef s_lpu_h +#define s_lpu_h + +#define ROOM "/lib/std/room" +#define DOORS "/lib/blank" +#define DAEMON "/lib/std/daemon" +#define OBJECT "/lib/std/item" +#define OB_SIMUL_EFUN "/secure/sefun/sefun" +#define OB_DEED "/obj/deed" +#define OB_ORDER "/obj/order" +#define OB_ESTATE "/std/estate" +#define OB_POSTAL DIR_SECURE_OBJ "/post" +#define ACCESS "/secure/lib/std/access" + +#define set_light SetAmbientLight +#define set_short SetShort +#define set_long SetLong +#define set_items SetItems +#define set_exits SetExits +#define query_exit GetExit +#define set_property SetProperty +#define set_name SetKeyName +#define set_id SetId +#define set_no_clean SetNoClean +#define set_smell_string SetSmell +#define set_smell SetSmell +#define set_properties SetProperties +#define set_door SetDoor +#define set_race SetRace +#define set_gender SetGender +#define set_level SetLevel +#define set_body_type SetProperty +#define set_hp SetHealthPoints +#define set_class SetClass +#define set_spell_chance SetSpellChance +#define set_spell SetSpell +#define set_skills SetSkills +#define set_skill SetSkill +#define set_spell_chance SetSpellChance +#define set_emotes SetActions +#define set_wielding_limbs SetWieldingLimbs +#define set_wc SetClass +#define set_type SetWeaponType +#define set_mass SetMass +#define set_value SetValue +#define set_listen_string SetListen +#define set_listen SetListen +#define set_edit_ok valid_edit +#define set_search SetSearch +#define set_paralyzed SetParalyzed +#define set_pre_exit_functions SetProperty +#define MONSTER LIB_SENTIENT +#define monster sentient +#define set_money SetCurrency +#define add_exit AddExit +#define set_read SetRead +#define set_prevent_get SetPreventGet +#define VAULT LIB_ROOM +#define set_day_long SetDayLong +#define set_night_long SetNightLong +#define set_open SetOpen +#define query_open GetOpen +#define remove_item_description RemoveItem +#define remove_exit RemoveExit +#define add_item_description AddItem +#define set_outside SetTown +#define create_door CreateDoor +#define set_quest_points SetQuestPoints +#define query_quest_points GetQuestPoints +#define query_class GetClass + +#endif /* s_lpu_h */ diff --git a/lib/secure/include/config.h b/lib/secure/include/config.h new file mode 100644 index 0000000..3e2feb5 --- /dev/null +++ b/lib/secure/include/config.h @@ -0,0 +1,97 @@ +#ifndef s_config_h +#define s_config_h +#define DEFAULT_PROMPT "> " +#define HOST_IP "127.0.0.1" +#define MUD_STATUS "mudlib development" +#define ADMIN_EMAIL "babylon_horuv@zoho.com" +#define DEBUGGER "babylon" +#define LOCAL_NEWS_PREFIX "nm" +#define MUD_IS_LOCKED 0 +#define AUTO_WIZ 0 +#define RESTRICTED_INTERMUD 0 +#define DISABLE_INTERMUD 0 +#define DISABLE_IMC2 1 +#define MINUTES_REBOOT_WARNING 20 +#define TIME_TO_RESET 3600 +#define RESET_ALL 0 +#define GMT_OFFSET -32000 +#define LOCAL_TIME 0 +#define EXTRA_TIME_OFFSET 0 +#define MAX_LOG_SIZE 150000 +#define MAX_NET_DEAD_TIME 1800 +#define MIN_HISTORY_SIZE 50 +#define MAX_HISTORY_SIZE 100 +#define LOGON_TIMEOUT 360 +#define IDLE_TIMEOUT 180000 +#define LINK_WAIT_PERIOD 1800 +#define MAX_PASSWORD_TRIES 3 +#define MIN_USER_NAME_LENGTH 2 +#define MAX_USER_NAME_LENGTH 15 +#define MAX_USER_CAP_NAME_LENGTH 20 +#define LOCKED_ACCESS_ALLOWED ({ "SECURE", "ASSIST", "ELDER", "TEST" }) +#define SUPPORTED_CLIENTS ({ "amcp", "amcp/1.1" }) +#define HOUR_LENGTH 1200 +#define DAY_LENGTH 20 +#define MAX_NEWBIE_LEVEL 0 +#define AUTOSAVE_TIME 200 +#define MORTAL_POSITIONS ({ "player", "high mortal", "ambassador" }) +#define DEFAULT_GRAVITY 1.0 +#define DEFAULT_ITEM_MESSAGE "You do not see that here." +#define RESET_INTERMUD 0 +#define ENGLISH_ONLY 0 +#define HUMANS_ONLY 0 +#define SEVERABLE_LIMBS 1 +#define CLASS_SELECTION 0 +#define PINGING_MUDS ({}) +#define PING_INTERVAL 290 +#define ENABLE_ENCUMBRANCE 0 +#define GLOBAL_MONITOR 0 +#define PLAYER_KILL 0 +#define NPC_CATCH_TELL_DEBUG 0 +#define SAME_IP_MAX 4 +#define COMPAT_MODE 1 +#define RETAIN_ON_QUIT 1 +#define FAST_COMBAT 1 +#define MAX_COMMANDS_PER_SECOND 10 +#define DEFAULT_PARSING 0 +#define CALL_OUT_LOGGING 0 +#define EVENTS_LOGGING 0 +#define DISABLE_REBOOTS 0 +#define BARE_EXITS 1 +#define COMMAND_MATCHING 1 +#define OBJECT_MATCHING 1 +#define LIVEUPGRADE_SERVER "Dead Souls" +#define CARRIAGE_RETURN "\r" +#define OLD_STYLE_PLURALS 1 +#define NM_STYLE_EXITS 0 +#define WEB_SOURCE_IP "204.209.44.12" +#define WEB_SOURCE_NAME "lpmuds.net" +#define DESTRUCT_LOGGING 0 +#define ROUTER_NAME "Alpha" +#define IRN_PASSWORD "Alpha" +#define IRN_PASSWORD1 "Bravo" +#define IRN_PASSWORD2 "Charlie" +#define IRN_PASSWORD3 "Delta" +#define ROUTER_TESTING 1 +#define SEFUN_PLURALIZE 0 +#define LOG_REMOTE_CHANS 0 +#define LOG_LOCAL_CHANS 1 +#define ENABLE_CGI 0 +#define WWW_DIR_LIST 0 +#define ENABLE_CREWEB 0 +#define F_TERMINAL_COLOR 1 +#define MAX_CALL_OUTS 750 +#define REQUIRE_QUESTING 1 +#define AUTO_ADVANCE 1 +#define MAX_INVENTORY_SIZE 2048 +#define MAX_ATTACKS_PER_HB 40 +#define MEMUSE_SOFT_LIMIT 0 +#define MEMUSE_HARD_LIMIT 0 +#define MAX_USERS 0 +#define MIN_PERF 400 +#define MINIMAP 1 +#define WIZMAP 1 +#define GRID 1 +#define ENABLE_INSTANCES 0 +#define CED_DISABLED 1 +#endif /* s_config_h */ diff --git a/lib/secure/include/council.h b/lib/secure/include/council.h new file mode 100644 index 0000000..f0bfd9f --- /dev/null +++ b/lib/secure/include/council.h @@ -0,0 +1,25 @@ +#define JUSTICES ({ "niteraven", "bess", "pianoman", "yildor" }) + +#define MAYOR ({ "annie" }) + +#define TREASURER ({ "topknot" }) + +#define POLICECOM ({ "sluggo" }) + +#define SECRETARY ({ "brunoer" }) + +#define COUNCIL ({ "bess", "moonstar", "sluggo", "turk", "katana", "mina",\ + "yildor", "pianoman", "topknot", "niteraven", "brunoer",\ + "hades", "annie" }) + +#define MAGE_COUNCIL ({ "moonstar" }) + +#define MONK_COUNCIL ({ "bess" }) + +#define ROGUE_COUNCIL ({ "turk" }) + +#define CLERIC_COUNCIL ({ "katana" }) + +#define FIGHTER_COUNCIL ({ "sluggo" }) + +#define KATAAN_COUNCIL ({ "mina" }) diff --git a/lib/secure/include/daemons.h b/lib/secure/include/daemons.h new file mode 100644 index 0000000..b784a25 --- /dev/null +++ b/lib/secure/include/daemons.h @@ -0,0 +1,99 @@ +#ifndef s_daemons_h +#define s_daemons_h + +#include + +#define ADMIN_D DIR_SECURE_DAEMONS "/admin" +#define ADVANCE_D DIR_SECURE_DAEMONS "/advance" +#define ADVERBS_D DIR_DAEMONS "/adverbs" +#define ALCHEMIST_D DIR_SECURE_DAEMONS "/alchemist" +#define AUTOEXEC_D DIR_SECURE_DAEMONS "/autoexec" +#define BANISH_D DIR_DAEMONS "/banish" +#define BBOARD_D DIR_SECURE_DAEMONS "/bboard" +#define BOOKS_D DIR_DAEMONS "/books" +#define BUGS_D DIR_DAEMONS "/bugs" +#define CHARACTER_D DIR_SECURE_DAEMONS "/character" +#define CHAT_D DIR_SECURE_DAEMONS "/chat" +#define CLASSES_D DIR_DAEMONS "/classes" +#define CMD_D DIR_DAEMONS "/command" +#define COMMAND_D DIR_DAEMONS "/command" +#define CONFIG_D DIR_SECURE_DAEMONS "/config" +#define DECAY_D DIR_DAEMONS "/decay" +#define DEFINES_D DIR_DAEMONS "/defines" +#define DEVIATION_D DIR_DAEMONS "/deviation" +#define CREATE_D DIR_SECURE_DAEMONS "/modules/create" +#define ECONOMY_D DIR_SECURE_DAEMONS "/economy" +#define EVENTS_D DIR_SECURE_DAEMONS "/events" +#define ESTATES_D DIR_SECURE_DAEMONS "/estates" +#define FILE_D DIR_SECURE_DAEMONS "/file" +#define FILTER_D DIR_SECURE_DAEMONS "/filter" +#define FUNCTION_D DIR_SECURE_DAEMONS "/function" +#define FINGER_D DIR_SECURE_DAEMONS "/finger" +#define FOLDERS_D DIR_SECURE_DAEMONS "/folders" +#define GOSSIP_D DIR_SECURE_DAEMONS "/gossip" +#define GUARD_D DIR_DAEMONS "/guard" +#define HELP_D DIR_DAEMONS "/help" +#define ICP_D DIR_SECURE_DAEMONS "/icp" +#define IMC2_D DIR_SECURE_DAEMONS "/imc2" +#define IMC2_SERVER_D DIR_SECURE_DAEMONS "/imc2server/server" +#define INET_D DIR_SECURE_DAEMONS "/inet" +#define INSTANCES_D DIR_SECURE_DAEMONS "/instances" +#define INTERMUD_D DIR_DAEMONS "/intermud" +#define LETTERS_D DIR_SECURE_DAEMONS "/letters" +#define LOG_D DIR_SECURE_DAEMONS "/log" +#define LOCALPOST_D DIR_SECURE_DAEMONS "/localpost" +#define LUGET_D DIR_SECURE_DAEMONS "/luget" +#define MAP_D DIR_DAEMONS "/map" +#define MEETINGS_D DIR_DAEMONS "/meetings" +#define MUDINFO_D DIR_SECURE_DAEMONS "/mudinfo" +#define NEWS_D DIR_DAEMONS "/news" +#define NOTIFY_D DIR_DAEMONS "/notify" +#define ROOMS_D DIR_SECURE_DAEMONS "/rooms" +#define OOB_D DIR_SECURE_DAEMONS "/oob" +#define OPTIONS_D DIR_SECURE_DAEMONS "/options" +#define PARTY_D DIR_DAEMONS "/party" +#define PHYS_D DIR_DAEMONS "/phys" +#define PING_D DIR_SECURE_DAEMONS "/ping" +#define PLAYERS_D DIR_SECURE_DAEMONS "/players" +#define POLITICS_D DIR_SECURE_DAEMONS "/politics" +#define PORTAL_D DIR_SECURE_DAEMONS "/portal" +#define PRELOAD_D DIR_SECURE_DAEMONS "/preload_check" +#define PROMOTION_D DIR_SECURE_DAEMONS "/players" +#define RACES_D DIR_DAEMONS "/races" +#define RELOAD_D DIR_SECURE_DAEMONS "/reload" +#define REAPER_D DIR_SECURE_DAEMONS "/reaper" +#define REMOTE_D DIR_SECURE_DAEMONS "/remote" +#define REMOTEPOST_D DIR_SECURE_DAEMONS "/remotepost" +#define RESOLV_D DIR_SECURE_DAEMONS "/resolv" +#define ROUTER_D DIR_SECURE_DAEMONS "/i3router/server" +#define RSOCKET_D DIR_SECURE_DAEMONS "/i3router/rsocket" +#define SEASONS_D DIR_DAEMONS "/seasons" +#define SECRETS_D DIR_SECURE_DAEMONS "/secrets" +#define SERVICES_D DIR_DAEMONS "/services" +#define SKILLS_D DIR_DAEMONS "/skills" +#define SNOOP_D DIR_SECURE_DAEMONS "/snoop" +#define SOUL_D DIR_DAEMONS "/soul" +#define SPELLS_D DIR_DAEMONS "/spells" +#define SSOCKET_D DIR_SECURE_DAEMONS "/imc2server/ssocket" +#define STATS_D DIR_DAEMONS "/stats" +#define STATISTICS_D DIR_DAEMONS "/statistics" +#define STARGATE_D DIR_DAEMONS "/stargate" +#define TERMINAL_D DIR_DAEMONS "/terminal" +#define TIME_D DIR_DAEMONS "/time" +#define TRACKER_D DIR_SECURE_DAEMONS "/tracker" +#define TYPES_D DIR_DAEMONS "/types" +#define UNDERWORLD_D DIR_DAEMONS "/underworld" +#define UNIQUE_D DIR_DAEMONS "/unique" +#define UPDATE_D DIR_SECURE_DAEMONS "/update" +#define USERS_D DIR_SECURE_DAEMONS "/users" +#define VERBS_D DIR_DAEMONS "/verbs" +#define VIRTUAL_D DIR_DAEMONS "/virtual" +#define VOTING_D DIR_SECURE_DAEMONS "/voting" +#define WARM_BOOT_D DIR_SECURE_DAEMONS "/warm_boot" +#define WEATHER_D DIR_DAEMONS "/weather" +#define WEB_SESSIONS_D DIR_SECURE_DAEMONS "/web_sessions" +#define WGET_D DIR_SECURE_DAEMONS "/wget" +#define MASTER_D DIR_SECURE_DAEMONS "/master" +#define FTP_PORT_TRACKER_D DIR_DAEMONS "/ftp_port_tracker" + +#endif /* s_daemons_h */ diff --git a/lib/secure/include/deputies.h b/lib/secure/include/deputies.h new file mode 100644 index 0000000..ccb7a16 --- /dev/null +++ b/lib/secure/include/deputies.h @@ -0,0 +1,16 @@ +// Configuration of available deputies +// from the Dead Souls Mudlib +// by Aleas + +// here you define the deputies bought by the council +// 2x level of attacker ( closest match ) are sent for help +// if you add new deputies bought by the council, +// no need to retain ascending order, e.g. +// DEPUTIES_LOW ({ 20, 10, 30, 5 }) +// +// LOW is an array of deputies against level 1-20 attackers +// HIGH is an array of deputies against level 21+ attackers + +#define DEPUTIES_LOW ({ 25 }) +#define DEPUTIES_HIGH ({ 50, }) + diff --git a/lib/secure/include/dirs.h b/lib/secure/include/dirs.h new file mode 100644 index 0000000..f87dbf7 --- /dev/null +++ b/lib/secure/include/dirs.h @@ -0,0 +1,142 @@ +#ifndef s_dirs_h +#define s_dirs_h + +#define DIR_SECURE "/secure" +#define DIR_SECURE_CFG DIR_SECURE "/cfg" +#define DIR_DATA DIR_SECURE "/save" +#define DIR_SECURE_SAVE DIR_SECURE "/save" +#define DIR_SECURE_DAEMONS DIR_SECURE "/daemon" +#define DIR_ACCOUNTS DIR_DAEMONS_SAVE "/accounts" +#define DIR_BOARDS "/secure/save" "/boards" +#define DIR_CRES DIR_DATA "/creators" +#define DIR_ESTATES "/estates" +#define DIR_PLAYERS DIR_DATA "/players" +#define DIR_LETTERS DIR_DATA "/letters" +#define DIR_SECURE_OBJ DIR_SECURE "/obj" +#define DIR_POSTAL DIR_DATA "/postal" +#define DIR_SUICIDE DIR_DATA "/suicide" +#define DIR_RID DIR_DATA "/rid" +#define DIR_SECURE_DAEMONS_SAVE DIR_DATA "/daemons" +#define DIR_SECURE_VERBS DIR_SECURE "/verbs" +#define DIR_SECURE_CREATOR_VERBS DIR_SECURE_VERBS "/creators" +#define DIR_VOTES DIR_DATA "/votes" +#define DIR_GOSSIP DIR_DATA "/gossip" + +#define DIR_POWERS "/powers" +#define DIR_SPELLS DIR_POWERS "/spells" +#define DIR_FEATS DIR_POWERS "/feats" +#define DIR_PRAYERS DIR_POWERS "/prayers" +#define DIR_PSIONICS DIR_POWERS "/psionics" +#define DIR_TRADES DIR_POWERS "/trades" + +#define DIR_VERBS "/verbs" +#define DIR_ADMIN_VERBS DIR_VERBS "/admins" +#define DIR_BUILDER_VERBS DIR_VERBS "/builders" +#define DIR_COMMON_VERBS DIR_VERBS "/common" +#define DIR_CREATOR_VERBS DIR_VERBS "/creators" +#define DIR_ITEM_VERBS DIR_VERBS "/items" +#define DIR_PLAYER_VERBS DIR_VERBS "/players" +#define DIR_ROOM_VERBS DIR_VERBS "/rooms" +#define DIR_SPELL_VERBS DIR_VERBS "/spells" +#define DIR_UNDEAD_VERBS DIR_VERBS "/undead" + +#define DIR_CFG "/cfg" + +#define DIR_DAEMONS "/daemon" +#define DIR_DAEMONS_DATA DIR_DAEMONS "/db" +#define DIR_SOUL_FILES DIR_DAEMONS "/soul" + +#define DIR_LIB "/lib" +#define DIR_COMP DIR_LIB "/comp" +#define DIR_EVENTS DIR_LIB "/events" +#define DIR_LVS DIR_LIB "/lvs" +#define DIR_PROPS DIR_LIB "/props" +#define DIR_STD DIR_LIB "/std" +#define DIR_OLD_STD "/std" +#define DIR_USER DIR_LIB "/user" +#define DIR_VIRT DIR_LIB "/virtual" + +#define DIR_SECURE_LIB DIR_SECURE "/lib" +#define DIR_SSTD DIR_SECURE_LIB "/std" + +#define DIR_LOGS "/log" +#define DIR_SECURE_LOGS DIR_SECURE "/log" +#define DIR_SECURE_INTERMUD_LOGS DIR_SECURE_LOGS "/intermud" +#define DIR_CHANNEL_LOGS DIR_LOGS "/chan" +#define DIR_DEBUG DIR_LOGS "/debug" +#define DIR_ERROR_LOGS DIR_LOGS "/errors" +#define DIR_INTERMUD_LOGS DIR_SECURE_LOGS "/intermud" +#define DIR_NETWORK_LOGS DIR_SECURE_LOGS "/network" +#define DIR_PERSONAL_LOGS DIR_LOGS "/personal" +#define DIR_REPORTS_LOGS DIR_LOGS "/reports" +#define DIR_WATCH_LOGS DIR_LOGS "/watch" + +#define DIR_OBJ "/obj" + +#define DIR_DOCS "/doc" +#define DIR_FAQS DIR_DOCS "/faq" +#define DIR_HELP DIR_DOCS "/help" +#define DIR_AVATAR_HELP DIR_HELP "/avatars" +#define DIR_CLASS_HELP DIR_HELP "/classes" +#define DIR_CONCEPTS_HELP DIR_DOCS "/lpc/concepts" +#define DIR_CONSTRUCTS_HELP DIR_DOCS "/lpc/constructs" +#define DIR_CREATOR_HELP DIR_HELP "/creators" +#define DIR_HM_HELP DIR_HELP "/hm" +#define DIR_LAW_HELP DIR_HELP "/law" +#define DIR_POSTAL_HELP DIR_HELP "/postal" +#define DIR_PLAYER_HELP DIR_HELP "/players" +#define DIR_RACE_HELP DIR_HELP "/races" +#define DIR_RELIGION_HELP DIR_HELP "/religion" +#define DIR_LIBRARY DIR_DOCS "/library" + +#define DIR_CMDS "/cmds" +#define DIR_SECURE_CMDS "/secure/cmds" +#define DIR_ADMIN_CMDS DIR_CMDS "/admins" +#define DIR_SECURE_ADMIN_CMDS DIR_SECURE_CMDS "/admins" +#define DIR_COMMON_CMDS DIR_CMDS "/common" +#define DIR_SECURE_COMMON_CMDS DIR_SECURE_CMDS "/common" +#define DIR_BUILDER_CMDS DIR_CMDS "/builders" +#define DIR_SECURE_BUILDER_CMDS DIR_SECURE_CMDS "/builders" +#define DIR_CREATOR_CMDS DIR_CMDS "/creators" +#define DIR_SECURE_CREATOR_CMDS DIR_SECURE_CMDS "/creators" +#define DIR_CLAN_CMDS DIR_CMDS "/clan" +#define DIR_HM_CMDS DIR_CMDS "/hm" +#define DIR_PLAYER_CMDS DIR_CMDS "/players" +#define DIR_SECURE_PLAYER_CMDS DIR_SECURE_CMDS "/players" + +#define DIR_FTP "/ftp" + +#define DIR_WWW "/www" +#define DIR_WWW_DOCS DIR_WWW "/doc" +#define DIR_WWW_EFUNS DIR_WWW_DOCS "/efun" +#define DIR_WWW_SIMULEFUNS DIR_WWW_DOCS "/sefun" +#define DIR_WWW_ERRORS DIR_WWW "/errors" +#define DIR_WWW_GATEWAYS DIR_WWW "/cgi" +#define DIR_CGI DIR_WWW_GATEWAYS + +#define DIR_UNDEAD_CMDS DIR_CMDS "/undead" + +#define REALMS_DIRS "/realms" + +#define DOMAINS_DIRS "/domains" +#define DIR_STANDARD_DOMAIN DOMAINS_DIRS "/default" + +#define ESTATES_DIRS "/estates" + +#define DIR_NEWS "/news" + +#define DIR_SAVE "/save" +#define DIR_KILLS DIR_SAVE "/kills" + +#define DIR_SHADOWS "/shadows" + +#define DIR_SECURE_TMP DIR_SECURE "/tmp" +#define DIR_TMP_SECURE DIR_SECURE "/tmp" +#define DIR_TMP "/tmp" +#define TMP_DIR "/tmp" + +#define DIR_UPGRADES DIR_SECURE "/upgrades" +#define DIR_UPGRADES_FILES DIR_UPGRADES "/files" +#define DIR_UPGRADES_TXT DIR_UPGRADES "/txt" + +#endif /* s_dirs_h */ diff --git a/lib/secure/include/domains.h b/lib/secure/include/domains.h new file mode 100644 index 0000000..329dc74 --- /dev/null +++ b/lib/secure/include/domains.h @@ -0,0 +1,15 @@ +#ifndef s_domains_h +#define s_domains_h + +#include + +#define DOMAIN_TOWN DOMAINS_DIRS "/town" +#define DOMAIN_NM3 DOMAINS_DIRS "/praxis" +#define DOMAIN_PRAXIS DOMAINS_DIRS "/praxis" +#define DOMAIN_NM4 DOMAINS_DIRS "/Ylsrim" +#define DOMAIN_YLSRIM DOMAINS_DIRS "/Ylsrim" +#define DOMAIN_EXAMPLES DOMAINS_DIRS "/examples" +#define DOMAIN_EX DOMAINS_DIRS "/examples" +#define DOMAIN_CAVE DOMAINS_DIRS "/cave" + +#endif /* s_domains_h */ diff --git a/lib/secure/include/events.h b/lib/secure/include/events.h new file mode 100644 index 0000000..33d04f2 --- /dev/null +++ b/lib/secure/include/events.h @@ -0,0 +1,66 @@ +#ifndef s_events_h +#define s_events_h + +#include + +#define LIB_ACTIVATE DIR_EVENTS "/activate" +#define LIB_AIM DIR_EVENTS "/aim" +#define LIB_APPLY DIR_EVENTS "/apply" +#define LIB_BAIT DIR_EVENTS "/bait" +#define LIB_BAIT_WITH DIR_EVENTS "/bait_with" +#define LIB_BURY DIR_EVENTS "/bury" +#define LIB_BUY DIR_EVENTS "/buy" +#define LIB_CLIMB DIR_EVENTS "/climb" +#define LIB_CLOSE DIR_EVENTS "/close" +#define LIB_CONSULT DIR_EVENTS "/consult" +#define LIB_DESCRIBE DIR_EVENTS "/describe" +#define LIB_DIG DIR_EVENTS "/dig" +#define LIB_DIG_WITH DIR_EVENTS "/dig_with" +#define LIB_DISARM DIR_EVENTS "/disarm" +#define LIB_DRINK DIR_EVENTS "/drink" +#define LIB_DROP DIR_EVENTS "/drop" +#define LIB_FALL DIR_EVENTS "/fall" +#define LIB_FLOAT DIR_EVENTS "/float" +#define LIB_GET DIR_EVENTS "/get" +#define LIB_GET_FROM DIR_EVENTS "/get_from" +#define LIB_GIVE DIR_EVENTS "/give" +#define LIB_JUMP DIR_EVENTS "/jump" +#define LIB_INSTALL DIR_EVENTS "/install" +#define LIB_LISTEN DIR_EVENTS "/listen" +#define LIB_KNEEL DIR_EVENTS "/kneel" +#define LIB_KNOCK DIR_EVENTS "/knock" +#define LIB_LOAD DIR_EVENTS "/load" +#define LIB_LOCK DIR_EVENTS "/lock" +#define LIB_LOCK_WITH DIR_EVENTS "/lock_with" +#define LIB_LOOK DIR_EVENTS "/look" +#define LIB_LOOK_IN DIR_EVENTS "/look_in" +#define LIB_POISON DIR_EVENTS "/poison" +#define LIB_PRESS DIR_EVENTS "/press" +#define LIB_PULL DIR_EVENTS "/pull" +#define LIB_PUT DIR_EVENTS "/put" +#define LIB_READ DIR_EVENTS "/read" +#define LIB_ROCK DIR_EVENTS "/rock" +#define LIB_ROLL DIR_EVENTS "/roll" +#define LIB_SCRATCH DIR_EVENTS "/scratch" +#define LIB_SEARCH DIR_EVENTS "/search" +#define LIB_SHAKE DIR_EVENTS "/shake" +#define LIB_SHOW DIR_EVENTS "/show" +#define LIB_SIT DIR_EVENTS "/sit" +#define LIB_SINK DIR_EVENTS "/sink" +#define LIB_SELL DIR_EVENTS "/sell" +#define LIB_SMELL DIR_EVENTS "/smell" +#define LIB_SMOKE DIR_EVENTS "/smoke" +#define LIB_STOP DIR_EVENTS "/stop" +#define LIB_SWIM DIR_EVENTS "/swim" +#define LIB_SWIVEL DIR_EVENTS "/swivel" +#define LIB_TOUCH DIR_EVENTS "/touch" +#define LIB_WEAR DIR_EVENTS "/wear" +#define LIB_WIELD DIR_EVENTS "/wield" +#define LIB_SHOOT DIR_EVENTS "/shoot" +#define LIB_TURN DIR_EVENTS "/turn" +#define LIB_MANIPULATE DIR_EVENTS "/manipulate" +#define LIB_CRAWL DIR_EVENTS "/crawl" +#define LIB_LIE DIR_EVENTS "/lie" +#define LIB_FLY DIR_EVENTS "/fly" + +#endif /* s_events_h */ diff --git a/lib/secure/include/files.h b/lib/secure/include/files.h new file mode 100644 index 0000000..1bb5e88 --- /dev/null +++ b/lib/secure/include/files.h @@ -0,0 +1 @@ +#define FILE_FAQ "/news/faq" diff --git a/lib/secure/include/flags.h b/lib/secure/include/flags.h new file mode 100644 index 0000000..04e903d --- /dev/null +++ b/lib/secure/include/flags.h @@ -0,0 +1,3 @@ +#define I_NORMAL 0 +#define I_NOECHO 1 +#define I_NOESC 2 diff --git a/lib/secure/include/function.h b/lib/secure/include/function.h new file mode 100644 index 0000000..82ba7c0 --- /dev/null +++ b/lib/secure/include/function.h @@ -0,0 +1,19 @@ +/* codes returned by the functionp() efun */ + +#define FP_CALL_OTHER 1 +#define FP_LOCAL 2 +#define FP_EFUN 3 +#define FP_SIMUL 4 +#define FP_FUNCTIONAL 5 + +/* internal use */ +#define FP_G_VAR 6 +#define FP_L_VAR 7 +#define FP_ANONYMOUS 8 +#define FP_THIS_OBJECT 0x10 + +/* additional flags */ +#define FP_MASK 0x0f +#define FP_HAS_ARGUMENTS 0x10 +#define FP_OWNER_DESTED 0x20 +#define FP_NOT_BINDABLE 0x40 diff --git a/lib/secure/include/global.h b/lib/secure/include/global.h new file mode 100644 index 0000000..75ce8e0 --- /dev/null +++ b/lib/secure/include/global.h @@ -0,0 +1,30 @@ +#ifndef __GLOBAL_H +#define __GLOBAL_H + +#define CONFIG_H "/secure/include/config.h" +#define NETWORK_H "/secure/include/network.h" +#define ROOMS_H "/secure/include/rooms.h" +#define SECRETS_H "/secure/include/secrets.h" + +#include CONFIG_H +#include + +#if COMPAT_MODE +#include +#endif + +#define DAY_ONE 720550800 + +#define SEFUN "/secure/sefun/sefun" + +#define DEBUG + +#ifdef debug +#undef debug +#endif /* debug */ + +//#ifdef DEBUG +//#define debug(x, y) (find_player(x) || master())->eventPrint(x) +//#endif /* DEBUG */ + +#endif /* GLOBAL_H */ diff --git a/lib/secure/include/iips.h b/lib/secure/include/iips.h new file mode 100644 index 0000000..20182fa --- /dev/null +++ b/lib/secure/include/iips.h @@ -0,0 +1,8 @@ +#ifndef __IIPS_H +#define __IIPS_H + +#include + +#define POSTAL_ID "imaginary mailer" + +#endif /* __IIPS_H */ diff --git a/lib/secure/include/lib.h b/lib/secure/include/lib.h new file mode 100644 index 0000000..a0dc6ce --- /dev/null +++ b/lib/secure/include/lib.h @@ -0,0 +1,143 @@ +#ifndef s_lib_h +#define s_lib_h + +//#include +#include + +#include +#include +#include +#include +#include +#include + +#define LIB_AUTH DIR_SECURE_LIB "/auth" +#define LIB_BANK DIR_LIB "/bank" +#define LIB_BASE_LEADER DIR_LIB "/base_leader" +#define LIB_BASE_TEACHER DIR_LIB "/base_teacher" +#define LIB_BASE_TRAINER DIR_LIB "/base_trainer" +#define LIB_BATTERY DIR_LIB "/battery" +#define LIB_BLANK DIR_LIB "/blank" +#define LIB_BLANK_PILE DIR_LIB "/blank_pile" +#define LIB_BOARD DIR_LIB "/bboard" +#define LIB_BODY DIR_LIB "/body" +#define LIB_BONUS DIR_LIB "/bonus" +#define LIB_BOT DIR_LIB "/bot" +#define LIB_BURN DIR_LIB "/burn" +#define LIB_CAPTURE DIR_LIB "/capture" +#define LIB_CHAMBER DIR_LIB "/chamber" +#define LIB_CHAPEL DIR_LIB "/chapel" +#define LIB_CHARIO DIR_LIB "/chario" +#define LIB_CGI DIR_LIB "/cgi" +#define LIB_CHAT DIR_LIB "/chat" +#define LIB_CIGAR DIR_LIB "/cigar" +#define LIB_CLASSES DIR_LIB "/classes" +#define LIB_CLAY DIR_LIB "/clay" +#define LIB_CLERK DIR_LIB "/clerk" +#define LIB_CLIENT DIR_SECURE_LIB "/net/client" +#define LIB_CLIP DIR_LIB "/clip" +#define LIB_COMBAT DIR_LIB "/combat" +#define LIB_COMBATMSG DIR_LIB "/combatmsg" +#define LIB_COMMAND DIR_LIB "/command" +#define LIB_CONNECT DIR_SECURE_LIB "/connect" +#define LIB_CREATOR DIR_LIB "/creator" +#define LIB_CURRENCY DIR_LIB "/currency" +#define LIB_CYLINDER DIR_LIB "/cylinder" +#define LIB_DETECT DIR_LIB "/detect" +#define LIB_DIE DIR_LIB "/die" +#define LIB_DIGGING DIR_LIB "/digging" +#define LIB_DISASTER DIR_LIB "/disaster" +#define LIB_DOMESTICATE DIR_LIB "/domesticate" +#define LIB_DONATE DIR_LIB "/donate" +#define LIB_DOOR DIR_LIB "/door" +#define LIB_EDITOR DIR_LIB "/editor" +#define LIB_ELEVATOR DIR_LIB "/elevator" +#define LIB_ELEVATOR_BUTTON DIR_LIB "/elevator_button" +#define LIB_ENTER DIR_LIB "/enter" +#define LIB_EXITS DIR_LIB "/exits" +#define LIB_FILE DIR_SECURE_LIB "/file" +#define LIB_FILES DIR_LIB "/files" +#define LIB_FIREARM DIR_LIB "/firearm" +#define LIB_FISH DIR_LIB "/fish" +#define LIB_FISHING DIR_LIB "/fishing" +#define LIB_FLASHLIGHT DIR_LIB "/flashlight" +#define LIB_FLASK DIR_LIB "/flask" +#define LIB_FLOW DIR_LIB "/flow" +#define LIB_FOLLOW DIR_LIB "/follow" +#define LIB_FTP_CLIENT DIR_SECURE_LIB "/net/ftp_client" +#define LIB_FTP_DATA_CONN DIR_SECURE_LIB "/net/ftp_data_connection" +#define LIB_FUEL DIR_LIB "/fuel" +#define LIB_GENETICS DIR_LIB "/genetics" +#define LIB_GUARD DIR_LIB "/guard" +#define LIB_GUN DIR_LIB "/gun" +#define LIB_CLAN DIR_LIB "/clan" +#define LIB_HELP DIR_LIB "/help" +#define LIB_HISTORY DIR_LIB "/history" +#define LIB_INTERACTIVE DIR_LIB "/interactive" +#define LIB_INTERFACE DIR_LIB "/interface" +#define LIB_LAMP DIR_LIB "/lamp" +#define LIB_LANGUAGE DIR_LIB "/language" +#define LIB_LEAD DIR_LIB "/lead" +#define LIB_LEADER DIR_LIB "/leader" +#define LIB_LEARN DIR_LIB "/learn" +#define LIB_LEVEL DIR_LIB "/lvs/level" +#define LIB_LIGHT DIR_LIB "/light" +#define LIB_LIVING DIR_LIB "/living" +#define LIB_LOGIN DIR_SECURE_LIB "/connect" +#define LIB_MAGIC DIR_LIB "/magic" +#define LIB_MANYCOINS DIR_LIB "/manycoins" +#define LIB_MATCH DIR_LIB "/match" +#define LIB_MAYOR DIR_LIB "/mayor" +#define LIB_MEAL DIR_LIB "/meal" +#define LIB_MEAL_POISON DIR_LIB "/poison" +#define LIB_MESSAGES DIR_LIB "/messages" +#define LIB_MISSILE DIR_LIB "/missile" +#define LIB_MONEY DIR_LIB "/money" +#define LIB_MOUNT DIR_LIB "/mount" +#define LIB_NMSH DIR_LIB "/nmsh" +#define LIB_NPC DIR_LIB "/npc" +#define LIB_OOB DIR_SECURE_LIB "/net/oob" +#define LIB_PAGER DIR_LIB "/pager" +#define LIB_PERSIST DIR_LIB "/persist" +#define LIB_PILE DIR_LIB "/pile" +#define LIB_PIPE DIR_LIB "/pipe" +#define LIB_PISTOL DIR_LIB "/pistol" +#define LIB_PLAYER DIR_LIB "/player" +#define LIB_PLAYER_STUB DIR_LIB "/daemons/player_stub" +#define LIB_PLAYERS DIR_LIB "/player" +#define LIB_POLE DIR_LIB "/pole" +#define LIB_POST_OFFICE DIR_LIB "/post_office" +#define LIB_POTION DIR_LIB "/potion" +#define LIB_QUEST DIR_LIB "/quest" +#define LIB_RACE DIR_LIB "/race" +#define LIB_REMOTE DIR_LIB "/remote" +#define LIB_RIFLE DIR_LIB "/rifle" +#define LIB_ROUND DIR_LIB "/round" +#define LIB_SCROLL DIR_LIB "/scroll" +#define LIB_SECURE_BOARD DIR_SECURE_LIB "/bboard" +#define LIB_CEDIT DIR_LIB "/cedit" +#define LIB_SENTIENT DIR_LIB "/sentient" +#define LIB_SERVER DIR_SECURE_LIB "/net/server" +#define LIB_SHADOW DIR_LIB "/shadow" +#define LIB_SHADOW_HOOK DIR_LIB "/shadow_hook" +#define LIB_SHELL DIR_LIB "/shell" +#define LIB_SHOP DIR_LIB "/shop" +#define LIB_SOCKET DIR_SECURE_LIB "/net/socket" +#define LIB_SPELL DIR_LIB "/spell" +#define LIB_STARGATE DIR_LIB "/stargate" +#define LIB_STEAL DIR_LIB "/steal" +#define LIB_TALK DIR_LIB "/talk" +#define LIB_TEACHER DIR_LIB "/teacher" +#define LIB_TEACH DIR_LIB "/teach" +#define LIB_TELLER DIR_LIB "/teller" +#define LIB_TORCH DIR_LIB "/torch" +#define LIB_TRAINER DIR_LIB "/trainer" +#define LIB_UNDEAD DIR_LIB "/undead" +#define LIB_USED_MEAL DIR_LIB "/used_meal" +#define LIB_VEHICLE DIR_LIB "/vehicle" +#define LIB_VERB DIR_LIB "/daemons/verb" +#define LIB_VI DIR_LIB "/vi" +#define LIB_VIRTUAL DIR_LIB "/virtual/virtual" +#define LIB_WEB_CLIENT DIR_SECURE_LIB "/net/web_client" + +#endif /* s_lib_h */ diff --git a/lib/secure/include/link.h b/lib/secure/include/link.h new file mode 100644 index 0000000..305d0dd --- /dev/null +++ b/lib/secure/include/link.h @@ -0,0 +1,11 @@ +#ifndef s_link_h +#define s_link_h + +class char_link { + string Email; + string *Secondaries; + string LastOnWith; + int LastOnDate; +} + +#endif /* s_link_h */ diff --git a/lib/secure/include/localtime.h b/lib/secure/include/localtime.h new file mode 100644 index 0000000..92122da --- /dev/null +++ b/lib/secure/include/localtime.h @@ -0,0 +1,14 @@ + +/* + * Definitions for localtime() efun + */ +#define LT_SEC 0 +#define LT_MIN 1 +#define LT_HOUR 2 +#define LT_MDAY 3 +#define LT_MON 4 +#define LT_YEAR 5 +#define LT_WDAY 6 +#define LT_YDAY 7 +#define LT_GMTOFF 8 +#define LT_ZONE 9 diff --git a/lib/secure/include/logs.h b/lib/secure/include/logs.h new file mode 100644 index 0000000..271cc13 --- /dev/null +++ b/lib/secure/include/logs.h @@ -0,0 +1,31 @@ +#ifndef s_logs_h +#define s_logs_h + +#include +#include CONFIG_H + +#if ENABLE_INSTANCES +#define UNIQ_EXT "." + __PORT__ +#else +#define UNIQ_EXT "" +#endif + +/* Network stuff */ +#define LOG_HTTP DIR_NETWORK_LOGS "/http" UNIQ_EXT +#define LOG_IMC2 DIR_INTERMUD_LOGS "/imc2" UNIQ_EXT +#define LOG_I3 DIR_SECURE_INTERMUD_LOGS "/i3" UNIQ_EXT +#define LOG_I3ERR DIR_SECURE_INTERMUD_LOGS "/i3err" UNIQ_EXT +#define LOG_INET DIR_NETWORK_LOGS "/inet" UNIQ_EXT +#define LOG_ROUTER DIR_INTERMUD_LOGS "/router" UNIQ_EXT +#define LOG_RSS DIR_NETWORK_LOGS "/rss" UNIQ_EXT + +/* Other stuff */ +#define LOG_BANISH DIR_LOGS "/banish" UNIQ_EXT +#define LOG_BUGS DIR_LOGS "/bugs" UNIQ_EXT +#define LOG_EVENTS DIR_LOGS "/events" UNIQ_EXT +#define LOG_LIVEUPGRADE DIR_SECURE_LOGS "/liveupgrade" UNIQ_EXT +#define LOG_QUESTS DIR_SECURE_LOGS "/quests" UNIQ_EXT +#define LOG_RESET DIR_LOGS "/reset" UNIQ_EXT +#define LOG_ICP DIR_SECURE_LOGS "/icp" UNIQ_EXT + +#endif /* s_logs_h */ diff --git a/lib/secure/include/lvs.h b/lib/secure/include/lvs.h new file mode 100644 index 0000000..4c8133c --- /dev/null +++ b/lib/secure/include/lvs.h @@ -0,0 +1,9 @@ +#ifndef s_lvs_h +#define s_lvs_h + +#include + +#define LIB_ABILITIES DIR_LVS "/abilities" +#define LIB_POSITION DIR_LVS "/position" + +#endif /* s_lvs_h */ diff --git a/lib/secure/include/modules.h b/lib/secure/include/modules.h new file mode 100644 index 0000000..b5e1c16 --- /dev/null +++ b/lib/secure/include/modules.h @@ -0,0 +1,12 @@ +#define MODULES_FILE "/secure/modules/file" +#define MODULES_MONEY "/secure/modules/money" +#define MODULES_READ "/secure/modules/read" +#define MODULES_ROOM "/secure/modules/room" +#define MODULES_MAPPING "/secure/modules/mapping" +#define MODULES_ITEM "/secure/modules/item" +#define MODULES_ARMOR "/secure/modules/armor" +#define MODULES_WEAPON "/secure/modules/weapon" +#define MODULES_MEAL "/secure/modules/meal" +#define MODULES_DOOR "/secure/modules/door" +#define MODULES_GENERIC "/secure/modules/generic" +#define MODULES_CREATE "/secure/modules/create" diff --git a/lib/secure/include/mssp.h b/lib/secure/include/mssp.h new file mode 100644 index 0000000..0f75bd2 --- /dev/null +++ b/lib/secure/include/mssp.h @@ -0,0 +1,143 @@ +#include +mapping reply, notes; + +string mssp_reply(){ + string *k; + int i; + string ret, ip = query_intermud_ip(); + string intermud = ""; + + if(find_object(INTERMUD_D)) intermud += "i3"; + if(find_object(IMC2_D)){ + if(sizeof(intermud)) intermud += "\t"; + intermud += "IMC2"; + } + if(!sizeof(intermud)) intermud = "0"; + + reply = ([ + "NAME" : mud_name(), + "PLAYERS" : itoa(sizeof(users())), + "UPTIME" : itoa(time() - uptime()), + "PORT" : itoa(query_host_port()), + "CODEBASE" : mudlib()+" "+mudlib_version(), + "CONTACT" : ADMIN_EMAIL, + "WHO" : implode(map(filter(users(), + (: (environment($1) && !($1->GetInvis())) :)), + (: $1->GetCapName():)), "\t"), + "HOSTNAME" : ip, + "DESCRIPTION" : "A fun mud!", + "CREATED" : itoa(local_time()[5]), + "ICON" : "http://"+ip+":"+PORT_HTTP+"/favicon.ico", + "IP" : ip, + "LANGUAGE" : "English", + "LOCATION" : "United States", + "MINIMUM AGE" : "13", + "WEBSITE" : "http://"+ip+":"+PORT_HTTP, + "FAMILY" : "LPMud", + "GENRE" : "Adventure", + "SUBGENRE" : "Adventure", + "GAMEPLAY" : "Adventure", + "GAMESYSTEM" : "Custom", + "INTERMUD" : intermud, + "STATUS" : "Alpha", + "AREAS" : "7", + "HELPFILES" : "N/A", + "MOBILES" : "150", + "OBJECTS" : "300", + "ROOMS" : "300", + "RESETS" : "N/A", + "MUDPROGS" : "N/A", + "MUDTRIGS" : "N/A", + "CLASSES" : "5", + "LEVELS" : "300", + "RACES" : "72", + "SKILLS" : "N/A", + "DBSIZE" : "N/A", + "EXITS" : "N/A", + "EXTRA DESCRIPTIONS" : "N/A", + "ADULT MATERIAL" : "0", + "MULTICLASSING" : "0", + "PLAYER CITIES" : "0", + "PLAYER CLANS" : "0", + "PLAYER CRAFTING" : "0", + "PLAYER GUILDS" : "0", + "EQUIPMENT SYSTEM" : "N/A", + "MULTIPLAYING" : "Full", + "PLAYERKILLING" : "Full", + "QUEST SYSTEM" : "Automated\tIntegrated", + "ROLEPLAYING" : "None", + "TRAINING SYSTEM" : "Skill", + "WORLD ORIGINALITY": "Mostly Original", + "ANSI" : "1", + "MCCP" : "0", + "SSL" : "0", + "MCP" : "0", + "MSP" : "0", + "MXP" : "0", + "PUEBLO" : "0", + "VT100" : "0", + "XTERM 256 COLORS" : "0", + "PAY TO PLAY" : "0", + "PAY FOR PERKS" : "0", + "HIRING BUILDERS" : "1", + "HIRING CODERS" : "1", + ]); + + notes = ([ + "FAMILY-NOTES" : "descendant of Nightmare", + "HELPFILES-NOTES" : "each command, and hundreds of other docs", + "MOBILES-NOTES" : "npc's can be cloned, so there can be thousands", + "OBJECTS-NOTES" : "objects can be cloned, so there can be thousands", + "ROOMS-NOTES" : "areas have generated rooms, could be millions", + "RESETS-NOTES" : "doesn't apply, LPMud", + "MUDPROGS-NOTES" : "doesn't apply, LPMud", + "MUDTRIGS-NOTES" : "doesn't apply, LPMud", + "RACES-NOTES" : "not all are playable", + "SKILLS-NOTES" : "many, but not like Diku", + ]); + + ret = "MSSP-REPLY-START\r\n"; + k = keys(reply); + +#ifdef __DSLIB__ + k = sort_array(k, -1); +#endif + + for(i = (sizeof(k) - 1); i > -1; i--){ + ret += k[i]; + ret += "\t"; + ret += reply[k[i]]; + ret += "\r\n"; + } + + k = keys(notes); + +#ifdef __DSLIB__ + k = sort_array(k, -1); +#endif + + for(i = (sizeof(k) - 1); i > -1; i--){ + ret += k[i]; + ret += "\t"; + ret += notes[k[i]]; + ret += "\r\n"; + } + + ret += "MSSP-REPLY-END\r\n"; + + return ret; +} + +mapping mssp_map(){ + string text = mssp_reply(); + mapping ret = ([]), tmp = add_maps(reply, notes); + foreach(mixed key, mixed val in tmp){ + if(undefinedp(val)) continue; + if(grepp(val, "\t")){ + ret[key] = explode(val, "\t"); + } + else ret[key] = val; + } + return ret; +} + diff --git a/lib/secure/include/mudlib.h b/lib/secure/include/mudlib.h new file mode 100644 index 0000000..139597f --- /dev/null +++ b/lib/secure/include/mudlib.h @@ -0,0 +1,2 @@ + + diff --git a/lib/secure/include/network.h b/lib/secure/include/network.h new file mode 100644 index 0000000..f176322 --- /dev/null +++ b/lib/secure/include/network.h @@ -0,0 +1,35 @@ +#ifndef __NETWORK_H +#define __NETWORK_H + +#include + +#define MUD 0 +#define STREAM 1 +#define DATAGRAM 2 +#define STREAM_BINARY 3 +#define DATAGRAM_BINARY 4 + +#define OFFSET_RCP -10 +#define OFFSET_HFTP -6 +#define OFFSET_HTTP 1 +#define OFFSET_FTP -1 +#define OFFSET_ECHO 2 +#define OFFSET_FLASH 3 +#define OFFSET_OOB 6 +#define OFFSET_ICP 6 + +#define PORT_ADMIN 17010 +#define PORT_ECHO (query_host_port() + OFFSET_ECHO) +#define PORT_FLASH (query_host_port() + OFFSET_FLASH) +#define PORT_FTP (query_host_port() + OFFSET_FTP) +#define PORT_HFTP (query_host_port() + OFFSET_HFTP) +#define PORT_HTTP (query_host_port() + OFFSET_HTTP) +#define PORT_ICP (query_host_port() + OFFSET_ICP) +#define PORT_OOB (query_host_port() + OFFSET_OOB) +#define PORT_RCP (query_host_port() + OFFSET_RCP) +#define PORT_UDP (query_host_port() + 8) + +#define MIN_PASV_PORT (query_host_port() - 65) +#define MAX_PASV_PORT (query_host_port() - 11) + +#endif /* __NETWORK_H */ diff --git a/lib/secure/include/news.h b/lib/secure/include/news.h new file mode 100644 index 0000000..fe32e78 --- /dev/null +++ b/lib/secure/include/news.h @@ -0,0 +1,19 @@ +#ifndef s_news_h +#define s_news_h + +#include + +#define NEWS_ADMIN DIR_NEWS "/admin" +#define NEWS_AVATAR DIR_NEWS "/avatar" +#define NEWS_BANISHED DIR_NEWS "/banished" +#define NEWS_CREATOR DIR_NEWS "/creator" +#define NEWS_GENERAL DIR_NEWS "/general" +#define NEWS_HM DIR_NEWS "/hm" +#define NEWS_LOCKED DIR_NEWS "/locked" +#define NEWS_MOVED DIR_NEWS "/moved" +#define NEWS_NEWBIE DIR_NEWS "/newbie" +#define NEWS_REGISTER DIR_NEWS "/register" +#define NEWS_WELCOME DIR_NEWS "/welcome" +#define DS_WELCOME DIR_NEWS "/deadsouls" + +#endif /* s_news_h */ diff --git a/lib/secure/include/object.h b/lib/secure/include/object.h new file mode 100644 index 0000000..d88214c --- /dev/null +++ b/lib/secure/include/object.h @@ -0,0 +1,4 @@ +inherit "/lib/move"; +inherit "/lib/prop"; +inherit "/lib/pluralize"; + diff --git a/lib/secure/include/objects.h b/lib/secure/include/objects.h new file mode 100644 index 0000000..d3df479 --- /dev/null +++ b/lib/secure/include/objects.h @@ -0,0 +1,17 @@ +#ifndef s_objects_h +#define s_objects_h + +#include + +#define OBJ_DEED DIR_OBJ "/deed" +#define OBJ_ORDER DIR_OBJ "/order" +#define OBJ_POST DIR_SECURE_OBJ "/post" +#define OBJ_QUEST DIR_OBJ "/quest_ob" +#define OBJ_ROBOT DIR_SECURE_OBJ "/robot" +#define OBJ_ROOMMAKER DIR_SECURE_OBJ "/roommaker" +#define OBJ_SNOOPER DIR_SECURE_OBJ "/snooper" +#define OBJ_STAFF DIR_SECURE_OBJ "/staff" +#define OBJ_WED_RING DIR_OBJ "/wed_ring" +#define OBJ_WORKROOM DIR_OBJ "/workroom" + +#endif /* s_objects_h */ diff --git a/lib/secure/include/origin.h b/lib/secure/include/origin.h new file mode 100644 index 0000000..7f1fd6e --- /dev/null +++ b/lib/secure/include/origin.h @@ -0,0 +1,13 @@ +/* codes returned by the origin() efun */ + +#define ORIGIN_BACKEND "driver" /* backwards compat */ +#define ORIGIN_DRIVER "driver" +#define ORIGIN_LOCAL "local" +#define ORIGIN_CALL_OTHER "call_other" +#define ORIGIN_SIMUL_EFUN "simul" +#define ORIGIN_CALL_OUT "call_out" +#define ORIGIN_EFUN "efun" +/* pseudo frames for call_other function pointers and efun pointer */ +#define ORIGIN_FUNCTION_POINTER "function_pointer" +/* anonymous functions */ +#define ORIGIN_FUNCTIONAL "functional" diff --git a/lib/secure/include/parse_com.h b/lib/secure/include/parse_com.h new file mode 100644 index 0000000..66ce404 --- /dev/null +++ b/lib/secure/include/parse_com.h @@ -0,0 +1,6 @@ +#define P_THING 0 +#define P_STRING 1 +#define P_CUR_NUM 2 +#define P_MAX_NUM 3 +#define P_TOP 4 +#define P_BOT 5 diff --git a/lib/secure/include/parser_error.h b/lib/secure/include/parser_error.h new file mode 100644 index 0000000..1edb356 --- /dev/null +++ b/lib/secure/include/parser_error.h @@ -0,0 +1,13 @@ +#ifndef PARSER_ERROR_H +#define PARSER_ERROR_H + +#define ERR_IS_NOT 1 +#define ERR_NOT_LIVING 2 +#define ERR_NOT_ACCESSIBLE 3 +#define ERR_AMBIG 4 +#define ERR_ORDINAL 5 +#define ERR_ALLOCATED 6 +#define ERR_THERE_IS_NO 7 +#define ERR_BAD_MULTIPLE 8 + +#endif diff --git a/lib/secure/include/post.h b/lib/secure/include/post.h new file mode 100644 index 0000000..efabe03 --- /dev/null +++ b/lib/secure/include/post.h @@ -0,0 +1,11 @@ +#ifndef __POST_H +#define __POST_H + +#include + +#define POSTAL_ID "imaginary mailer" +#define POSTAL_PROMPT "% " +#define POSTAL_USER_HELP DIR_USER_HELP+"/postal" +#define POSTAL_CREATOR_HELP DIR_CREATOR_HELP+"/postal" + +#endif /* __POST_H */ diff --git a/lib/secure/include/pov.h b/lib/secure/include/pov.h new file mode 100644 index 0000000..4bfd695 --- /dev/null +++ b/lib/secure/include/pov.h @@ -0,0 +1,8 @@ +#ifndef s_pov_h +#define s_pov_h + +#define POV_SUBJECT 1 +#define POV_TARGET 2 +#define POV_OBSERVER 3 + +#endif /* s_pov_h */ diff --git a/lib/secure/include/privs.h b/lib/secure/include/privs.h new file mode 100644 index 0000000..66ab8dc --- /dev/null +++ b/lib/secure/include/privs.h @@ -0,0 +1,14 @@ +#ifndef __PRIVS_H +#define __PRIVS_H + +#define PRIV_ASSIST "ASSIST" +#define PRIV_CMDS "CMDS" +#define PRIV_GENERAL "GENERAL" +#define PRIV_LAW "LAW" +#define PRIV_MUDLIB "MUDLIBPRIV" +#define PRIV_PLAYER "PLAYER" +#define PRIV_SECURE "SECURE" +#define PRIV_ELDER "ELDER" +#define PRIV_INTERMUD "INTERMUD" + +#endif /* __PRIVS_H */ diff --git a/lib/secure/include/props.h b/lib/secure/include/props.h new file mode 100644 index 0000000..a438e2c --- /dev/null +++ b/lib/secure/include/props.h @@ -0,0 +1,28 @@ +#ifndef s_props_h +#define s_props_h + +#include + +#define LIB_AMBIANCE DIR_PROPS "/ambiance" +#define LIB_BODY_MASS DIR_PROPS "/body_mass" +#define LIB_CARRY DIR_PROPS "/carry" +#define LIB_CLEAN DIR_PROPS "/clean" +#define LIB_DAMAGE DIR_PROPS "/damage" +#define LIB_DESCRIPTION DIR_PROPS "/description" +#define LIB_DETERIORATION DIR_PROPS "/deterioration" +#define LIB_EQUIP DIR_PROPS "/equip" +#define LIB_ID DIR_PROPS "/id" +#define LIB_INVENTORY DIR_PROPS "/inventory" +#define LIB_MASS DIR_PROPS "/mass" +#define LIB_MOVE DIR_PROPS "/move" +#define LIB_PROPERTIES DIR_PROPS "/properties" +#define LIB_RADIANCE DIR_PROPS "/radiance" +#define LIB_SAVE DIR_PROPS "/save" +#define LIB_UNIQUENESS DIR_PROPS "/uniqueness" +#define LIB_VALUE DIR_PROPS "/value" +#define LIB_COST DIR_PROPS "/cost" +#define LIB_ADDSTUFF DIR_PROPS "/addstuff" +#define LIB_EXTRA_PARSE DIR_PROPS "/extra_parse" + + +#endif /* s_props_h */ diff --git a/lib/secure/include/rcp.h b/lib/secure/include/rcp.h new file mode 100644 index 0000000..a9f78be --- /dev/null +++ b/lib/secure/include/rcp.h @@ -0,0 +1,19 @@ +#ifndef s_rcp_h +#define s_rcp_h + +#define RCP_LOGIN 1 +#define RCP_SHUTDOWN 2 +#define RCP_ERROR 3 +#define RCP_DIR_LIST_REQ 4 +#define RCP_DIR_LIST 5 +#define RCP_LIB_LIST_REQ 6 +#define RCP_LIB_LIST 7 +#define RCP_LIB_DETAIL_REQ 8 +#define RCP_LIB_DETAIL 9 +#define RCP_FILE_REQ 10 +#define RCP_FILE_SEND 11 +#define RCP_FILE_SAVE 12 +#define RCP_OBJECT_UPDATE 13 +#define RCP_OBJECT_UPDATE_ACK 14 + +#endif /* s_rcp_h */ diff --git a/lib/secure/include/rooms.h b/lib/secure/include/rooms.h new file mode 100644 index 0000000..3bfe0e4 --- /dev/null +++ b/lib/secure/include/rooms.h @@ -0,0 +1,17 @@ +#ifndef s_rooms_h +#define s_rooms_h +#include +#define ROOM_ZERO "/domains/town/room/start" +#define ROOM_ARCH "/secure/room/arch" +#define ROOM_CATCH_TELL DIR_STANDARD_DOMAIN "/room/catchtell" +#define ROOM_DEATH DIR_STANDARD_DOMAIN "/room/death" +#define ROOM_FREEZER DIR_STANDARD_DOMAIN "/room/freezer" +#define ROOM_FURNACE DIR_STANDARD_DOMAIN "/room/furnace" +#define ROOM_NETWORK "/secure/room/network" +#define ROOM_POD DIR_STANDARD_DOMAIN "/room/pod" +#define ROOM_ROUTER "/secure/room/router" +#define ROOM_START "/domains/begin/room/start" +#define ROOM_VIRT_VOID DIR_STANDARD_DOMAIN "/virtual/void" +#define ROOM_VOID DIR_STANDARD_DOMAIN "/room/void" +#define ROOM_WIZ DIR_STANDARD_DOMAIN "/room/wiz_hall" +#endif /* s_rooms_h */ diff --git a/lib/secure/include/runtime_config.h b/lib/secure/include/runtime_config.h new file mode 100644 index 0000000..49978c4 --- /dev/null +++ b/lib/secure/include/runtime_config.h @@ -0,0 +1,100 @@ +/* + * runtime_config.h + * + * Copy this file to your mudlib include dir for use with the + * get_config() efun. + * + * See Config.Example describing most of these settings. Some are actually + * in options.h, but the mudlib doesn't have to know... + * + * Note for backwards compatibility: + * + * get_config(__MUD_NAME__) == MUD_NAME + * get_config(__MUD_PORT__) == __PORT__ + */ + +#ifndef RUNTIME_CONFIG_H +#define RUNTIME_CONFIG_H + +#define BASE_CONFIG_STR 0 +#define CFG_STR(x) ((x) + BASE_CONFIG_STR) +/* + * These config settings return a string + */ + +#define __MUD_NAME__ CFG_STR(0) + +#define __ADDR_SERVER_IP__ CFG_STR(1) + +#define __MUD_LIB_DIR__ CFG_STR(2) +#define __BIN_DIR__ CFG_STR(3) + +#define __LOG_DIR__ CFG_STR(4) +#define __INCLUDE_DIRS__ CFG_STR(5) + +#define __SAVE_BINARIES_DIR__ CFG_STR(6) + +#define __MASTER_FILE__ CFG_STR(7) +#define __SIMUL_EFUN_FILE__ CFG_STR(8) +#define __SWAP_FILE__ CFG_STR(9) +#define __DEBUG_LOG_FILE__ CFG_STR(10) + +#define __DEFAULT_ERROR_MESSAGE__ CFG_STR(11) +#define __DEFAULT_FAIL_MESSAGE__ CFG_STR(12) +#define __GLOBAL_INCLUDE_FILE__ CFG_STR(13) + +#define __MUD_IP__ CFG_STR(14) + +/* + * These config settings return an int (ie number) + */ + +#define BASE_CONFIG_INT (BASE_CONFIG_STR + 15) +#define CFG_INT(x) ((x) + BASE_CONFIG_INT) + +#define __MUD_PORT__ CFG_INT(0) +#define __ADDR_SERVER_PORT__ CFG_INT(1) + +#define __TIME_TO_CLEAN_UP__ CFG_INT(2) +#define __TIME_TO_RESET__ CFG_INT(3) +#define __TIME_TO_SWAP__ CFG_INT(4) + +#define __COMPILER_STACK_SIZE__ CFG_INT(5) +#define __EVALUATOR_STACK_SIZE__ CFG_INT(6) +#define __INHERIT_CHAIN_SIZE__ CFG_INT(7) +#define __MAX_EVAL_COST__ CFG_INT(8) +#define __MAX_LOCAL_VARIABLES__ CFG_INT(9) +#define __MAX_CALL_DEPTH__ CFG_INT(10) +#define __MAX_ARRAY_SIZE__ CFG_INT(11) +#define __MAX_BUFFER_SIZE__ CFG_INT(12) +#define __MAX_MAPPING_SIZE__ CFG_INT(13) +#define __MAX_STRING_LENGTH__ CFG_INT(14) +#define __MAX_BITFIELD_BITS__ CFG_INT(15) + +#define __MAX_BYTE_TRANSFER__ CFG_INT(16) +#define __MAX_READ_FILE_SIZE__ CFG_INT(17) + +#define __RESERVED_MEM_SIZE__ CFG_INT(18) + +#define __SHARED_STRING_HASH_TABLE_SIZE__ CFG_INT(19) +#define __OBJECT_HASH_TABLE_SIZE__ CFG_INT(20) +#define __LIVING_HASH_TABLE_SIZE__ CFG_INT(21) + +#ifndef __FD6_PORT__ +#define __FD6_PORT__ CFG_INT(22) +#endif +#ifndef __FD6_KIND__ +#define __FD6_KIND__ CFG_INT(23) +#endif + + +#define RUNTIME_CONFIG_NEXT CFG_INT(24) + +/* + * The following is for internal use (ie driver) only + */ + +#define NUM_CONFIG_STRS (BASE_CONFIG_INT - BASE_CONFIG_STR) +#define NUM_CONFIG_INTS (RUNTIME_CONFIG_NEXT - BASE_CONFIG_INT) + +#endif /* RUNTIME_CONFIG_H */ diff --git a/lib/secure/include/save.h b/lib/secure/include/save.h new file mode 100644 index 0000000..1057574 --- /dev/null +++ b/lib/secure/include/save.h @@ -0,0 +1,55 @@ +#ifndef s_save_h +#define s_save_h + +#include + +#define SAVE_BANISH DIR_SAVE "/banish" +#define SAVE_BOOKS DIR_SAVE "/books" +#define SAVE_BUGS DIR_SAVE "/bugs" +#define SAVE_CHARACTER DIR_SECURE_SAVE "/character" +#define SAVE_CLASSES DIR_SAVE "/classes" +#define SAVE_CLASS DIR_SAVE "/class" +#define SAVE_CONFIG DIR_SAVE "/config" +#define SAVE_DEVIATION DIR_SAVE "/deviation" +#define SAVE_ECONOMY DIR_SAVE "/economy" +#define SAVE_ESTATES DIR_SAVE "/estates" +#define SAVE_EVENTS DIR_SAVE "/events" +#define SAVE_FILES DIR_SECURE_SAVE "/files" +#define SAVE_FUNCTIONS DIR_SECURE_SAVE "/functions" +#define SAVE_GOSSIP DIR_GOSSIP "/gossip" +#define SAVE_ICP DIR_SECURE_SAVE "/icp" +#define SAVE_INET DIR_SECURE_SAVE "/inet" +#define SAVE_INTERMUD DIR_SAVE "/intermud" +#define SAVE_INSTANCES DIR_SECURE_SAVE "/instances" +#define SAVE_IMC2 DIR_SECURE_SAVE "/imc2" +#define SAVE_IMC2_SERVER DIR_SECURE_SAVE "/imc2_server" +#define SAVE_LIVEUPGRADE DIR_SECURE_SAVE "/liveupgrade" +#define SAVE_MAILQUEUE DIR_DATA "/mailqueue" +#define SAVE_MASTER DIR_SECURE_SAVE "/master" +#define SAVE_MAP DIR_SAVE "/map" +#define SAVE_MEETINGS DIR_SAVE "/meetings" +#define SAVE_MUDINFO DIR_SECURE_SAVE "/mudinfo" +#define SAVE_NAMESERVER DIR_SAVE "/network" +#define SAVE_NOTIFY DIR_SAVE "/notify" +#define SAVE_QUESTS DIR_SECURE_SAVE "/quests" +#define SAVE_PARTIES DIR_SAVE "/parties" +#define SAVE_PLAYER_LIST DIR_SECURE_SAVE "/player_list" +#define SAVE_POLITICS DIR_SECURE_SAVE "/politics" +#define SAVE_PORTAL DIR_SAVE "/portal" +#define SAVE_RACES DIR_SAVE "/races" +#define SAVE_RELOAD DIR_SECURE_SAVE "/reload" +#define SAVE_ROOMS DIR_SAVE "/rooms" +#define SAVE_ROUTER DIR_SECURE_SAVE "/router" +#define SAVE_SKILLS DIR_SAVE "/skills" +#define SAVE_SERVICES DIR_SAVE "/services" +#define SAVE_SESSIONS DIR_SECURE_SAVE "/sessions" +#define SAVE_SNOOP DIR_SECURE_SAVE "/snoop" +#define SAVE_SOUL DIR_SAVE "/soul" +#define SAVE_STARGATE DIR_SAVE "/stargate" +#define SAVE_STATS DIR_SAVE "/stats" +#define SAVE_STATISTICS DIR_SAVE "/statistics" +#define SAVE_TYPES DIR_SAVE "/types" +#define SAVE_UNIQUE DIR_SAVE "/unique" +#define SAVE_WEIRDER DIR_SECURE_SAVE "/weirder" + +#endif /* s_save_h */ diff --git a/lib/secure/include/secrets.h b/lib/secure/include/secrets.h new file mode 100644 index 0000000..a25c61f --- /dev/null +++ b/lib/secure/include/secrets.h @@ -0,0 +1,11 @@ +#ifndef s_secrets_h +#define s_secrets_h +#define IRN_PASSWORD "Alpha" +#define IRN_PASSWORD1 "Bravo" +#define IRN_PASSWORD2 "Charlie" +#define IRN_PASSWORD3 "Delta" +#define IMC2_CLIENT_PW "ihfaigdmke" +#define IMC2_SERVER_PW "iihnocjbbk" +#define I3_SERVER_PW 260379860 +#define INSTANCE_PW "1234567890" +#endif /* s_secrets_h */ diff --git a/lib/secure/include/socket.h b/lib/secure/include/socket.h new file mode 100644 index 0000000..d92d2ef --- /dev/null +++ b/lib/secure/include/socket.h @@ -0,0 +1,41 @@ +/* This socket errors package by Jacques@TMI-1 and Cynosure@Synergy */ + +#ifndef __SOCKET_H +#define __SOCKET_H + +#define EESUCCESS 1 /* Call was successful */ +#define EESOCKET -1 /* Problem creating socket */ +#define EESETSOCKOPT -2 /* Problem with setsockopt */ +#define EENONBLOCK -3 /* Problem setting non-blocking mode */ +#define EENOSOCKS -4 /* No more available efun sockets */ +#define EEFDRANGE -5 /* Descriptor out of range */ +#define EEBADF -6 /* Descriptor is invalid */ +#define EESECURITY -7 /* Security violation attempted */ +#define EEISBOUND -8 /* Socket is already bound */ +#define EEADDRINUSE -9 /* Address already in use */ +#define EEBIND -10 /* Problem with bind */ +#define EEGETSOCKNAME -11 /* Problem with getsockname */ +#define EEMODENOTSUPP -12 /* Socket mode not supported */ +#define EENOADDR -13 /* Socket not bound to an address */ +#define EEISCONN -14 /* Socket is already connected */ +#define EELISTEN -15 /* Problem with listen */ +#define EENOTLISTN -16 /* Socket not listening */ +#define EEWOULDBLOCK -17 /* Operation would block */ +#define EEINTR -18 /* Interrupted system call */ +#define EEACCEPT -19 /* Problem with accept */ +#define EEISLISTEN -20 /* Socket is listening */ +#define EEBADADDR -21 /* Problem with address format */ +#define EEALREADY -22 /* Operation already in progress */ +#define EECONNREFUSED -23 /* Connection refused */ +#define EECONNECT -24 /* Problem with connect */ +#define EENOTCONN -25 /* Socket not connected */ +#define EETYPENOTSUPP -26 /* Object type not supported */ +#define EESENDTO -27 /* Problem with sendto */ +#define EESEND -28 /* Problem with send */ +#define EECALLBACK -29 /* Wait for callback */ +#define EESOCKRLSD -30 /* Socket already released */ +#define EESOCKNOTRLSD -31 /* Socket not released */ + +#define ERROR_STRINGS 32 /* sizeof (error_strings) */ + +#endif /* __SOCKET_H */ diff --git a/lib/secure/include/socket_err.h b/lib/secure/include/socket_err.h new file mode 100644 index 0000000..80bc77d --- /dev/null +++ b/lib/secure/include/socket_err.h @@ -0,0 +1,46 @@ +/* + * socket_errors.h -- definitions for efun socket error return codes. + * 5-92 : Dwayne Fontenot (Jacques@TMI) : original coding. + * 10-92 : Dave Richards (Cynosure) : less original coding. + */ + +#ifndef _SOCKET_ERRORS_H_ +#define _SOCKET_ERRORS_H_ + +#define EESUCCESS 1 /* Call was successful */ +#define EESOCKET -1 /* Problem creating socket */ +#define EESETSOCKOPT -2 /* Problem with setsockopt */ +#define EENONBLOCK -3 /* Problem setting non-blocking mode */ +#define EENOSOCKS -4 /* No more available efun sockets */ +#define EEFDRANGE -5 /* Descriptor out of range */ +#define EEBADF -6 /* Descriptor is invalid */ +#define EESECURITY -7 /* Security violation attempted */ +#define EEISBOUND -8 /* Socket is already bound */ +#define EEADDRINUSE -9 /* Address already in use */ +#define EEBIND -10 /* Problem with bind */ +#define EEGETSOCKNAME -11 /* Problem with getsockname */ +#define EEMODENOTSUPP -12 /* Socket mode not supported */ +#define EENOADDR -13 /* Socket not bound to an address */ +#define EEISCONN -14 /* Socket is already connected */ +#define EELISTEN -15 /* Problem with listen */ +#define EENOTLISTN -16 /* Socket not listening */ +#define EEWOULDBLOCK -17 /* Operation would block */ +#define EEINTR -18 /* Interrupted system call */ +#define EEACCEPT -19 /* Problem with accept */ +#define EEISLISTEN -20 /* Socket is listening */ +#define EEBADADDR -21 /* Problem with address format */ +#define EEALREADY -22 /* Operation already in progress */ +#define EECONNREFUSED -23 /* Connection refused */ +#define EECONNECT -24 /* Problem with connect */ +#define EENOTCONN -25 /* Socket not connected */ +#define EETYPENOTSUPP -26 /* Object type not supported */ +#define EESENDTO -27 /* Problem with sendto */ +#define EESEND -28 /* Problem with send */ +#define EECALLBACK -29 /* Wait for callback */ +#define EESOCKRLSD -30 /* Socket already released */ +#define EESOCKNOTRLSD -31 /* Socket not released */ +#define EEBADDATA -32 /* sending data with too many nested levels */ + +#define ERROR_STRINGS 33 /* sizeof (error_strings) */ + +#endif /* _SOCKET_ERRORS_H_ */ diff --git a/lib/secure/include/sockets.h b/lib/secure/include/sockets.h new file mode 100644 index 0000000..487902f --- /dev/null +++ b/lib/secure/include/sockets.h @@ -0,0 +1,9 @@ +#ifndef s_sockets_h +#define s_sockets_h + +#include + +#define SOCKET_HTTP DIR_SECURE_LIB "/net/http" +#define SOCKET_RCP DIR_SECURE_LIB "/net/rcp" + +#endif /* s_sockets_h */ diff --git a/lib/secure/include/std.h b/lib/secure/include/std.h new file mode 100644 index 0000000..af825a9 --- /dev/null +++ b/lib/secure/include/std.h @@ -0,0 +1,38 @@ +#ifndef s_std_h +#define s_std_h + +#include + +#define LIB_ACCESS DIR_SSTD "/access" +#define LIB_ARMOR DIR_STD "/armor" +#define LIB_BARKEEP DIR_STD "/barkeep" +#define LIB_BASE_ARMOR DIR_STD "/base_armor" +#define LIB_BASE_DUMMY DIR_STD "/base_dummy" +#define LIB_BASE_STORAGE DIR_STD "/base_storage" +#define LIB_BOOBYTRAP_OBJECT DIR_STD "/boobytrap_object" +#define LIB_BOOBYTRAP_SHADOW DIR_STD "/boobytrap_shadow" +#define LIB_BOOK DIR_STD "/book" +#define LIB_CHAIR DIR_STD "/chair" +#define LIB_CORPSE DIR_STD "/corpse" +#define LIB_DAEMON DIR_STD "/daemon" +#define LIB_DUMMY DIR_STD "/dummy" +#define LIB_FURNACE DIR_STD "/furnace" +#define LIB_ITEM DIR_STD "/item" +#define LIB_LIMB DIR_STD "/limb" +#define LIB_LOCKPICK DIR_STD "/lockpick" +#define LIB_ROOM DIR_STD "/room" +#define LIB_SKY DIR_STD "/sky" +#define LIB_STORAGE DIR_STD "/storage" +#define LIB_VENDOR DIR_STD "/vendor" +#define LIB_BANE DIR_STD "/bane" +#define LIB_GERM DIR_STD "/germ" +#define LIB_BED DIR_STD "/bed" +#define LIB_TABLE DIR_STD "/table" +#define LIB_BOT_CORPSE DIR_STD "/bot_corpse" +#define LIB_BOT_LIMB DIR_STD "/bot_limb" +#define LIB_WORN_STORAGE DIR_STD "/worn_storage" +#define LIB_WOUND DIR_STD "/wound" + +#define STD_ROOM DIR_OLD_STD "/room" + +#endif /* s_std_h */ diff --git a/lib/secure/include/type.h b/lib/secure/include/type.h new file mode 100644 index 0000000..04f41ed --- /dev/null +++ b/lib/secure/include/type.h @@ -0,0 +1,15 @@ +/* /include/type.h */ + +#ifndef _TYPE_H +#define _TYPE_H + +#define INT 0x2 +#define STRING 0x4 +#define ARRAY 0x8 +#define OBJECT 0x10 +#define MAPPING 0x20 +#define FUNCTION 0x40 +#define FLOAT 0x80 +#define BUFFER 0x100 + +#endif diff --git a/lib/secure/include/user.h b/lib/secure/include/user.h new file mode 100644 index 0000000..c6c3790 --- /dev/null +++ b/lib/secure/include/user.h @@ -0,0 +1,8 @@ +#ifndef s_user_h +#define s_user_h + +#include + +#define LIB_AUTOSAVE DIR_USER "/autosave" + +#endif /* s_user_h */ diff --git a/lib/secure/include/virtual.h b/lib/secure/include/virtual.h new file mode 100644 index 0000000..e7581f2 --- /dev/null +++ b/lib/secure/include/virtual.h @@ -0,0 +1,13 @@ +#ifndef s_virtual_h +#define s_virtual_h + +#include + +#define LIB_VIRT_LAND DIR_VIRT "/virt_land" +#define LIB_VIRT_MAP DIR_VIRT "/virt_map" +#define LIB_VIRT_SKY DIR_VIRT "/virt_sky" +#define LIB_VIRT_SPACE DIR_VIRT "/virt_space" +#define LIB_VIRT_SURFACE DIR_VIRT "/virt_surface" +#define LIB_VIRT_SUBSURFACE DIR_VIRT "/virt_subsurface" + +#endif /* s_virtual_h */ diff --git a/lib/secure/include/voting.h b/lib/secure/include/voting.h new file mode 100644 index 0000000..82810e5 --- /dev/null +++ b/lib/secure/include/voting.h @@ -0,0 +1,40 @@ +#ifndef __INC_VOTING +#define __INC_VOTING + +#include + +#define VOTE_ERROR 0 +#define VOTE_SUCCESS 1 +#define VOTE_ALREADY_RUNNING 2 +#define VOTE_NOT_CANDIDATE 3 +#define VOTE_NOT_RUNNING 4 +#define VOTE_NOT_PRIMARY 5 +#define VOTE_NOT_CLASS_MEMBER 6 +#define VOTE_ALREADY_VOTED 7 +#define VOTE_MODE_CANDIDATES 8 +#define VOTE_MODE_VOTING 9 +#define VOTE_RUNNING 10 + +#define VOTE_DAY_COUNT 7 + +#define SAVE_VOTES DIR_VOTES "/voting" +#define VOTE_ROOM "/domains/Ylsrim/room/vote_hall.c" + +mixed eventSave(); +mixed eventStartVoting(); +mixed eventEndVoting(); +mixed eventAddCandidate( string sClass, string sWho ); +mixed eventRemoveCandidate( string sClass, string sWho ); +mixed eventCastVote( string sClass, string sVoter, string sVotee ); +mixed eventNextDay(); +mixed eventTallyVotes(); +int GetStatus(); +int GetMode(); +string *GetCandidates( string sClass ); +string *GetCouncil(); +string GetCouncilMember( string sClass ); +int GetVoteStatus( object ob ); +string GetVoteRoom(); +int IsCouncilMember( object ob ); + +#endif /* __INC_VOTING */ diff --git a/lib/secure/lib/bboard.c b/lib/secure/lib/bboard.c new file mode 100644 index 0000000..a633c4a --- /dev/null +++ b/lib/secure/lib/bboard.c @@ -0,0 +1,11 @@ +#include + +inherit LIB_BOARD; + +void create(){ + ::create(); +} + +void init(){ + ::init(); +} diff --git a/lib/secure/lib/connect.c b/lib/secure/lib/connect.c new file mode 100644 index 0000000..f229b60 --- /dev/null +++ b/lib/secure/lib/connect.c @@ -0,0 +1,1005 @@ +/* /secure/lib/connect.c + * from the Dead Souls Object Library + * the object a user connects to before determining their real body + * created by Descartes of Borg 951103 + * Version: @(#) connect.c 1.2@(#) + * Last Modified: 96/05/28 + */ + +#include +#include ROOMS_H +#include +#include +#include +#include +#include +#include "include/connect.h" + +#define CUSTOM_FORMAT 0 +#define REAL_NAME 0 + +#ifndef __ANSI_SUBSTITUTE__ +#define __ANSI_SUBSTITUTE__ 0x1e +#endif + +#ifndef GUEST_ALLOWED +#define GUEST_ALLOWED 1 +#endif + +inherit LIB_PAGER; +#include + +static private int CrackCount, NetDead, MaxPlayers, blindmode; +static private string name, Name, Terminal, raza, TrueName, trabajo, extra; +static private string Passwort, Gendre, CapNamen, E_Mail, my_ip, client_ip; +static private object Player, pile; +static private mapping LastError, UserVars; +static private int *Screen; +static private int rescue, yescre, anyterm; +static private string *ip_permitted = ({}), instname, telopt_user; +static private string array anyterms = ({"97.107.133.86", "127.0.0.1"}); + +//Change this to 0 to disable color codes in /news/welcome +//then update the connect.c file. +static private int AllowColorSplash = 1; + +//Change this to 1 to change your welcome screen to /news/moved +//and to disable the standard login prompts. +static private int Moved = 0; + +int eventCheckPending(string str); +void eventCompleteChar(); +void InputCre(string str); +static void cmdPickClass(string args); +static void cmdListClasses(); +static void cmdHelpClass(string args); +static void InputClass(string str); +static void eventSelectClass(); + +int CheckIp(){ + int ips = 0; + string tmp_ip; + if(!SAME_IP_MAX) return 1; + tmp_ip = query_ip_number(); + if(telopt_user && telopt_user != my_ip) tmp_ip = telopt_user; + if(!ip_permitted) ip_permitted = ({}); + ip_permitted += PLAYERS_D->GetAdminIPs(); + ip_permitted = singular_array(ip_permitted); + if(member_array(tmp_ip, ip_permitted) != -1) return 1; + foreach(object jugador in users()){ + if(query_ip_number(jugador) == tmp_ip) ips++; + } + if(ips >= SAME_IP_MAX) return 0; + return 1; +} + +static void create(int binary) { + extra = ""; + UserVars = ([]); + if(query_windows()){ + MaxPlayers = 50; + } + else { +#ifdef __ULIMIT__ + MaxPlayers = (__ULIMIT__ - 10); +#else +#if __FD_SETSIZE__ + if(!MaxPlayers || MaxPlayers > __FD_SETSIZE__){ + MaxPlayers = (__FD_SETSIZE__ - 10); + } +#endif +#endif + } + if(grepp(__ARCH__, "Solaris")){ +#ifndef __M64__ + //Solaris has a problem with fd's over 256 in + //32-bit applications. + MaxPlayers = 200; +#endif + } + if(!MaxPlayers) MaxPlayers = 1000; + if(MAX_USERS) MaxPlayers = MAX_USERS; + CrackCount = 0; + Name = ""; + Player = 0; + NetDead = 0; + if(ENABLE_INSTANCES){ + instname = INSTANCES_D->GetMyInstanceName(); + } + ip_permitted = explode(read_file(CFG_IP_UNRESTRICT),"\n"); +} + +varargs static void logon(mixed foo) { + string welcome = "Connected to "+mud_name()+", an LP mud"; + if(sizeof(architecture())) welcome += " running on "+architecture()+".\n"; + else welcome += ".\n"; + + client_ip = query_ip_number(); + + call_out((: eventTimeout :), LOGON_TIMEOUT); + if(mud_name() == "Dead Souls" || mud_name() == "Dead Souls Dev" ){ + welcome += read_file(DS_WELCOME) || "Welcome to " + mud_name() + "!"; + } + else { + string wfile; + if(instname && instname != "global"){ + wfile = NEWS_WELCOME+"."+__PORT__; + } + if(!wfile || !file_exists(wfile)) wfile = NEWS_WELCOME; + welcome += read_file(wfile) || "Welcome to " + mud_name() + "!"; + } + if(Moved){ + string wfile; + if(instname && instname != "global"){ + wfile = NEWS_MOVED+"."+__PORT__; + } + if(!wfile || !file_exists(wfile)) wfile = NEWS_MOVED; + welcome = read_file(wfile) || "Welcome to " + mud_name() + "!"; + } + if(AllowColorSplash){ + receive(terminal_colour(welcome,TERMINAL_D->query_term_info("ansi"))); + } + else { + receive(welcome); + } + if(!Moved){ + receive("\n" + center("Driver: " + version() + + " Mudlib: "+ + mudlib() + " " + mudlib_version()) + "\n"); + receive("\nWhat name do you wish? "); + input_to((: InputName :), I_NOESC); + } +} + +static void InputName(string namen, string kill_me) { + string temp_name, news; + mixed tmp; + int toomany; + name = namen; + + if(member_array(client_ip, anyterms) != -1){ + if(telopt_user){ + int bar = sscanf(telopt_user, "%*d.%*d.%*d.%*d"); + if(bar == 4){ + client_ip = telopt_user; + anyterm = 1; + extra = " ["+my_ip+"]"; + } + } + } + + if(!CheckIp()){ + receive("\nToo many users from your site are currently logged on.\n"); + receive("Please try again later.\n"); + flush_messages(); + Destruct(); + return; + } + + if(sizeof(users()) >= MaxPlayers){ + toomany = 1; + } + + if(lower_case(name) == "guest" && !GUEST_ALLOWED){ + name = ""; + receive("\nThe guest account is disabled.\n"); + } + + if( !name || name == "" ) { + if( kill_me ) { + if(!Moved) receive("\nPerhaps try another time then?\n"); + Destruct(); + return; + } + else { + if(!Moved){ + receive("\nYou must enter a name in order to join!\n"); + receive("\nWhat name do you wish? "); + } + input_to((: InputName :), I_NOESC, "kill me"); + return; + } + } + + if(grepp(name, "MSSP-REQUEST")){ + log_file("mssp",timestamp() + " " + my_ip + extra + "\n"); + receive(mssp_reply()); + flush_messages(); + input_to((: InputName :), I_NOESC); + return; + } + if(sscanf(name,"%s_rescue",temp_name) == 1) { + name = temp_name; + rescue = 1; + } + Name = convert_name(name); + name = capitalize(name); + if( master()->is_locked() || toomany) { + if(toomany){ + news = "Too many players logged in!"; + } + else news = read_file(NEWS_LOCKED) || "No reason logged."; + receive("\n" + mud_name() + " is locked. Reason:\n" + news + "\n"); + if( CanLogin() ) receive("\n >>> Access allowed <<<\n"); + else { + receive("\n >>> Access denied <<<\n"); + flush_messages(); + Destruct(); + return; + } + } + if( !user_exists(Name) ) { + eventCreatePlayer(name); + return; + } + if( !(BANISH_D->eventConnect(Name, client_ip)) ) { + news = read_file(NEWS_BANISHED) || "You are not allowed here.\n"; + receive("\n" + news + "\n"); + Destruct(); + return; + } + if( (tmp = CHARACTER_D->eventConnect(Name)) != 1 ) { + if( tmp ) receive(tmp + "\n"); + else receive("One of your characters was recently logged in.\n" + "You must wait a little longer before logging in.\n"); + Destruct(); + return; + } + + if( find_player(Name) ) NetDead = 1; + + if(Name != "guest"){ + receive("Password: "); + input_to((: InputPassword :), I_NOECHO | I_NOESC, name); + } + else InputPassword("guest","Guest"); +} + +static void InputPassword(string pass, string cap) { + string control; + + if(Name != "guest"){ + + if( !pass || pass == "" ) { + receive("\nYou must enter a password. Please try again later.\n"); + Destruct(); + return; + } + if(!cap || cap == "") { + receive("\nAn unusual error has occurred. Please try again.\n"); + Destruct(); + return; + } + + control = PLAYERS_D->GetPlayerData(Name,"Password"); + if( control != crypt(pass, control) ) { + receive("\nInvalid password.\n"); + if( ++CrackCount > MAX_PASSWORD_TRIES ) { + receive("\nNo more attempts allowed\n"); + unguarded( (: log_file("/secure/log/security", + "Maximum password tries exceeded by " + + Name + " from " + client_ip + extra + "\n") :) ); + filter(users(), (: archp :))->eventPrint("System %^MAGENTA%^" + "%^RESET%^ Maximum password " + "attempts exceeded by " + cap + + " from " + client_ip + ".\n", + MSG_ERROR); + Destruct(); + return; + } + receive("Password: "); + input_to( (: InputPassword :), I_NOECHO | I_NOESC, cap); + return; + } + + if(rescue) unguarded( (: wipe_inv(name) :) ); + } + + Player = master()->player_object(Name); + if( !Player ) { + receive("\nIt seems some work is being done right now, try later.\n"); + Destruct(); + return; + } + PLAYERS_D->AddPlayerInfo(Player); + if( !Player->GetRace() || Player->GetRace() == "blob" + || Name == "guest" ) { + Player->SetRace("human"); + } + + if( !NetDead ){ + call_out( (: eventCheckPending, lower_case(Name) :), 3); + eventEnterGame(); + } + else eventReEnterGame(cap); +} + +static void eventCreatePlayer(string cap) { + string tmpdir, lcname = lower_case(Name); + string *tmpfiles = ({}); + if( !(BANISH_D->valid_name(lcname)) ) { + receive(capitalize(cap) + " is not a valid name.\n"); + receive(mud_name() + " requires that all names meet the following " + "requirements:\n"); + receive("\tAll characters must be:\n"); + receive("\t\tA-Z\n\t\ta-z\n\t\t'\n\t\t-\n"); + receive("\tMinimum length: " + MIN_USER_NAME_LENGTH + "\n"); + receive("\tMaximum length: " + MAX_USER_NAME_LENGTH + "\n"); + receive("\nPlease enter a new name: \n"); + input_to( (: InputName :), I_NOESC ); + return; + } + tmpdir = DIR_PLAYERS "/" + lcname[0..0] + "/"; + if(directory_exists(tmpdir)){ + tmpfiles += get_dir(tmpdir); + } + tmpdir = DIR_CRES "/" + lcname[0..0] + "/"; + if(directory_exists(tmpdir)){ + tmpfiles += get_dir(tmpdir); + } + foreach(string tmpfile in tmpfiles){ + if(!strsrch(tmpfile, lcname+".")){ + receive("\nThat name is taken. Please choose a new one.\n"); + input_to( (: InputName :), I_NOESC ); + return; + } + } + if( !(BANISH_D->eventConnect(Name, client_ip)) ) { + string news; + + news = read_file(NEWS_REGISTER) || "No registration info.\n"; + receive(news); + flush_messages(); + Destruct(); + return; + } + receive("Do you really wish to be known as " + cap + "? (y/n) \n"); + input_to((: ConfirmName :), I_NOESC, cap); +} + +static BlindCheck(string ans, string cap){ + if( !ans || ans == "" || lower_case(ans)[0..0] == "y" ) { + receive("\nOk, disabling default overhead map.\n"); + blindmode = 1; + } + else receive("\Ok, allowing default overhead map behavior.\n"); + log_file("new_players", Name + " (" + ctime(time()) + ")\n"); + receive("\nCreate a password of at least 5 letters: \n"); + input_to((: CreatePassword :), I_NOECHO | I_NOESC, cap); +} + +static void AgeCheck(string ans, string cap) { + if( !ans || ans == "" || lower_case(ans)[0..0] != "y" ) { + receive("\nSorry. You are not old enough to play here.\n"); + Destruct(); + return; + } + log_file("new_players", Name + " (" + ctime(time()) + ")\n"); + unguarded( (: log_file("/secure/log/new_players", Name + " from " + + client_ip + extra + " (" + ctime(time()) + ")\n") :) ); + receive("\nDo you use a screen reader for the visually impaired? (y/n)\n"); + input_to((: BlindCheck :), I_NOESC, cap); +} + +static void ConfirmName(string ans, string cap) { + if( !ans || ans == "" || lower_case(ans)[0..0] != "y" ) { + receive("\nOk, then enter the name you really want: \n"); + input_to( (: InputName :), I_NOESC ); + return; + } + receive("\nAre you 13 years of age or older? (y/n) \n"); + input_to((: AgeCheck :), I_NOESC, cap); +} + +static void eventReEnterGame(string cap) { + if( interactive(Player) ) { + receive("\nAn interactive copy of you currently exists.\n"); + receive("Do you wish to take over this copy? (y/n) \n"); + input_to((: ConfirmReconnect :), I_NOESC, cap); + return; + } + if( exec(Player, this_object()) ) { + if(rescue) + if(sizeof(deep_inventory(Player))) + deep_inventory(Player)->eventMove(ROOM_FURNACE); + log_file("enter", cap + " (exec): " + ctime(time()) + "\n"); + unguarded( (: log_file("/secure/log/enter", Name + " (exec): " + + ctime(time()) + " from " + client_ip + extra + "\n") :) ); + Player->eventReconnect(); + Player->RemoveProperty("afk"); + if(!anyterm){ + Player->CancelCharmode(); + Player->SetProperty("reprompt", 0); + Player->SetTeloptIp(0); + } + else { + Player->SetTeloptIp(telopt_user); + } + if(creatorp(Player)) + Player->AddChannel((CHAT_D->GetSystemChannels() - ({"muds"}))); + SNOOP_D->ReportReconnect(Player->GetKeyName()); + call_out( (: eventCheckPending, lower_case(Name) :), 3); + } + receive("\nProblem reconnecting.\n"); + Destruct(); +} + +static void ConfirmReconnect(string ans, string cap) { + object tmp; + + if( !stringp(ans) || ans == "" || lower_case(ans)[0..0] != "y" ) { + receive("\nThen please try again later!\n"); + Destruct(); + return; + } + if(rescue) + if(sizeof(deep_inventory(Player))) deep_inventory(Player)->eventMove(ROOM_FURNACE); + log_file("enter", cap + " (reconnect) ("+ctime(time())+")\n"); + unguarded( (: log_file("/secure/log/enter", Name + " (reconnect) from " + + client_ip + extra + " (" + ctime(time()) + ")\n") :) ); + exec(tmp = new(LIB_PLAYER), Player); + exec(Player, this_object()); + destruct(tmp); + if(anyterm){ + int oldlock = Player->GetProperty("screenlock"); + Player->SetCharmode(1); + Player->SetProperty("reprompt",1); + Player->SetProperty("commandecho", "blue"); + Player->SetProperty("keepalive", 5); + Player->SetProperty("screenlock", 0); + Player->SetScreen(80, 25); + Player->SetProperty("screenlock", oldlock); + Player->SetTeloptIp(telopt_user); + } + else { + Player->SetTeloptIp(0); + } + Player->eventPrint("\nAllowing login.\n", MSG_SYSTEM); + call_out( (: eventCheckPending, lower_case(Name) :), 3); + Destruct(); +} + +static int CanLogin() { + string group; + + if( BANISH_D->GetGuest(Name) ) return 1; + foreach(group in LOCKED_ACCESS_ALLOWED) + if( member_group(Name, group) ) return 1; + return 0; +} + +static private void eventEnterGame() { + if(!exec(Player, this_object())) { + debug("problem connecting"); + receive("\nProblem connecting.\n"); + Player->eventDestruct(); + destruct(this_object()); + return; + } + if( Terminal ) Player->SetTerminal(Terminal); + if( Screen ) Player->SetScreen(Screen[0], Screen[1]); + Player->Setup(); + if(creatorp(Player)){ + string profile = user_path(Player->GetKeyName())+".profile"; + if(file_exists(profile)){ + string q = ""; + if(!MASTER_D->GetPerfOK()) q = "-q "; + Player->eventForce("source "+q+profile); + } + } + Player->RemoveProperty("afk"); + if(creatorp(Player)) + Player->AddChannel(((CHAT_D->GetSystemChannels()) - ({"muds"}))); + SNOOP_D->CheckBot(Player->GetKeyName()); + unguarded( (: log_file("/secure/log/enter", Name + " (enter): " + + ctime(time()) + " from " + client_ip + extra + "\n") :) ); + if(anyterm){ + int oldlock = Player->GetProperty("screenlock"); + Player->SetCharmode(1); + Player->SetProperty("reprompt",1); + Player->SetProperty("commandecho", "blue"); + Player->SetProperty("keepalive", 5); + Player->SetProperty("screenlock", 0); + Player->SetScreen(80, 25); + Player->SetProperty("screenlock", oldlock); + Player->SetTeloptIp(telopt_user); + } + else { + Player->SetTeloptIp(0); + } + call_out( (: destruct(this_object()) :), 10); +} + +static void CreatePassword(string pass, string cap) { + if( strlen(pass) < 3) { + receive("\nYour password must be at least 5 letters in length.\n"); + receive("Please choose another password: "); + input_to( (: CreatePassword :), I_NOECHO | I_NOESC, cap); + return; + } + receive("\nPlease confirm your password: "); + input_to( (: ConfirmPassword :), I_NOECHO | I_NOESC, cap, pass); +} + +static void ConfirmPassword(string control, string cap, string pass) { + if( control == pass ) { + Player = master()->player_object(Name); + pass = crypt(pass, 0); + Passwort = pass; + receive("\n\nPlease choose an interesting gender (male, female, neutral, or none): \n"); + input_to((: InputGender :), I_NOESC, cap); + return; + } + receive("\nPassword entries do not match, re-choose password: "); + input_to((: CreatePassword :), I_NOECHO | I_NOESC, cap); + return; +} + +static void InputGender(string str, string cap) { + if( str != "male" && str != "female" + && str != "neuter" && str != "neutral" && str != "none") { + receive("\nCute, but pretend to be male, female, neutral, or none instead.\n"); + receive("Gender: "); + input_to((: InputGender :), I_NOESC, cap); + return; + } + if(str == "none") str = "neuter"; + Gendre = str; + if(CUSTOM_FORMAT){ + receive("\nYou may format " + cap + " to appear however you wish " + "using spaces, ', or -.\nEnter a display name " + "(default: " + cap +"): \n"); + input_to((: InputCapName :), I_NOESC, cap); + } + else { + InputCapName(cap, cap); + } +} + +static void InputCapName(string name, string cap) { + if( !name || name == "" ) name = cap; + if( !(BANISH_D->valid_cap_name(name, Name)) ) { + receive("\nThat was not a valid name format, choose again: \n"); + input_to((: InputCapName :), I_NOESC, cap); + return; + } + cap = capitalize(name); + CapNamen = cap; + receive("\nFor security reasons, " + mud_name() + " requires a valid " + "email.\n" + "Email: \n"); + input_to((: InputEmail :), I_NOESC); +} + +static void InputEmail(string email) { + string user, host; + + if( !email || sscanf(email, "%s@%s", user, host) != 2 ) { + receive("\nThat is not a valid email address.\n"); + receive("Please enter a valid email address: \n"); + input_to( (: InputEmail :), I_NOESC ); + return; + } + E_Mail = email; + if(REAL_NAME){ + receive("\nIf you do not mind, please enter your real name " + "(optional): \n"); + input_to( (: InputRealName :), I_NOESC ); + } + else { + InputRealName(""); + } +} + +static void InputRealName(string rname) { + if( !rname || rname == "" ) rname = "Unknown"; + TrueName = rname; + if(!HUMANS_ONLY){ + receive("\n\nYou must now pick a race.\n"); + receive("Picking a race influences what physical traits your character " + "will have.\n"); + receive("\nYou may issue the following commands:\n"); + receive("\tlist - lists all races from which you can choose\n"); + receive("\thelp - get help on what races mean\n"); + receive("\thelp RACE - (e.g. \"help human\") gives you information on " + "a race\n"); + receive("\tpick RACE - pick a particular race for yourself\n"); + receive("\n\tValid races: "); + receive(implode(sort_array(RACES_D->GetRaces(1), 1), " ")); + receive("\n\nRace: \n"); + input_to((: InputRace :), I_NOESC); + } + else InputRace("pick human"); +} + +static void InputRace(string str) { + string cmd, args; + string *valid = ( RACES_D->GetRaces(1) || ({}) ); + + if( str == "" || !str ) { + receive("\nRace: "); + input_to((: InputRace :), I_NOESC); + return; + } + if( sscanf(str, "%s %s", cmd, args) != 2 ) { + cmd = str; + args = 0; + } + if(member_array(cmd, valid) != -1){ + args = cmd; + cmd = "pick"; + } + switch(cmd) { + case "list": + cmdList(); + return; + + case "help": + cmdHelp(args); + return; + + case "pick": + cmdPick(args); + return; + + default: + receive("\nInvalid command.\nRace: \n"); + input_to((: InputRace :), I_NOESC); + return; + } +} + +static void cmdHelp(string args) { + function f; + string array races = RACES_D->GetRaces(1); + string help; + + f = function(string str) { + receive("\nRace: \n"); + input_to((: InputRace :), I_NOESC); + }; + if( !args ) { + help = read_file(DIR_PLAYER_HELP + "/races") || + "Error reading help file.\n"; + eventPage(explode(help, "\n"), MSG_HELP, f); + return; + } + if( member_array(args = lower_case(args), races) == -1 ) { + receive("No such race exists.\n\nRace: \n"); + input_to((: InputRace :), I_NOESC); + return; + } + help = RACES_D->GetHelp(args); + eventPage(explode(help, "\n"), MSG_HELP, f); +} + +static void cmdList() { + string list; + + list = format_page(sort_array(RACES_D->GetRaces(1), 1), 5); + receive(list); + receive("\nRace: \n"); + input_to((: InputRace :), I_NOESC); +} + +static void cmdPick(string args) { + if( !args || args == "" ) { + receive("You must specify a race to pick.\n\nRace: \n"); + input_to((: InputRace :), I_NOESC); + return; + } + if( member_array(args = lower_case(args), + RACES_D->GetRaces(1)) == -1 ) { + receive("No such race.\nRace: \n"); + input_to((: InputRace :), I_NOESC); + return; + } + raza = args; + if(!AUTO_WIZ){ + if(CLASS_SELECTION){ + eventSelectClass(); + return; + } + eventCompleteChar(); + } + if(AUTO_WIZ == 2) InputCre("creator"); + else { + receive("This mud has enabled AUTO_WIZ.\n"); + receive("This means that if you wish, you may be automatically \n"); + receive("promoted to creator status. \n\n"); + receive("If you want to be a player, enter: player\n"); + receive("If you want to be a creator, enter: creator\n"); + receive("What is your choice?\n"); + input_to((: InputCre :), I_NOESC); + } +} + +static void eventSelectClass(){ + receive("\n\nYou must now pick a class.\n"); + receive("Picking a class influences what skills your character " + "will have.\n"); + receive("\nYou may issue the following commands:\n"); + receive("\tlist - lists all classes from which you can choose\n"); + receive("\thelp - get help on what classes mean\n"); + receive("\thelp CLASS - (e.g. \"help explorer\") gives you information on " + "a class\n"); + receive("\tpick CLASS - pick a particular class for yourself\n"); + receive("\n\tValid classes: "); + receive(implode(sort_array(CLASSES_D->GetClasses(1), 1), " ")); + receive("\nClass: \n"); + input_to((: InputClass :), I_NOESC); +} + +static void InputClass(string str){ + string cmd, args; + string *valid = ( CLASSES_D->GetClasses(1) || ({}) ); + + if( str == "" || !str ) { + receive("\nClass: "); + input_to((: InputClass :), I_NOESC); + return; + } + if( sscanf(str, "%s %s", cmd, args) != 2 ) { + cmd = str; + args = 0; + } + if(member_array(cmd, valid) != -1){ + args = cmd; + cmd = "pick"; + } + switch(cmd) { + case "list": + cmdListClasses(); + return; + + case "help": + cmdHelpClass(args); + return; + + case "pick": + cmdPickClass(args); + return; + + default: + receive("\nInvalid command.\nClass: \n"); + input_to((: InputClass :), I_NOESC); + return; + } +} + +static void cmdHelpClass(string args){ + function f; + string array Classes = CLASSES_D->GetClasses(1); + string help; + + f = function(string str) { + receive("\nClass: \n"); + input_to((: InputClass :), I_NOESC); + }; + if( !args ) { + help = HELP_D->GetHelp("player documents classes") || + "Error reading help file.\n"; + eventPage(explode(help, "\n"), MSG_HELP, f); + return; + } + if( member_array(args = lower_case(args), Classes) == -1 ) { + receive("No such Class exists.\n\nClass: \n"); + input_to((: InputClass :), I_NOESC); + return; + } + help = HELP_D->GetHelp("classes "+args); + eventPage(explode(help, "\n"), MSG_HELP, f); +} + +static void cmdListClasses() { + string list; + + list = format_page(sort_array(CLASSES_D->GetClasses(1), 1), 5); + receive(list); + receive("\nClass: \n"); + input_to((: InputClass :), I_NOESC); +} + +static void cmdPickClass(string args) { + if( !args || args == "" ) { + receive("You must specify a class to pick.\n\nClass: \n"); + input_to((: InputClass :), I_NOESC); + return; + } + if( member_array(args = lower_case(args), + CLASSES_D->GetClasses(1)) == -1 ) { + receive("No such Class.\nClass: \n"); + input_to((: InputClass :), I_NOESC); + return; + } + trabajo = args; + eventCompleteChar(); +} + +int eventCre(string str){ + mixed mixt; + if(yescre && AUTO_WIZ > 0){ + mixt = load_object("/secure/cmds/admins/encre")->cmd(str); + } + destruct(this_object()); + return 1; +} + +int eventCheckPending(string str){ + mixed mixt; + str = lower_case(str); + if(member_array(str,PLAYERS_D->GetPendingEncres()) != -1){ + PLAYERS_D->RemovePendingEncre(str); + mixt = load_object("/secure/cmds/admins/encre")->cmd(str); + } + else if(member_array(str,PLAYERS_D->GetPendingDecres()) != -1){ + PLAYERS_D->RemovePendingDecre(str); + mixt = load_object("/secure/cmds/admins/decre")->cmd(str); + } + if(member_array(str,PLAYERS_D->GetPendingPauses()) != -1){ + PLAYERS_D->RemovePendingPause(str); + mixt = Player->SetPlayerPaused(1); + } + else if(member_array(str,PLAYERS_D->GetPendingUnpauses()) != -1){ + PLAYERS_D->RemovePendingUnpause(str); + mixt = Player->SetPlayerPaused(0); + } + destruct(this_object()); + return 1; +} + +void InputCre(string str){ + if(!str || str == "" || !sizeof(str) || !stringp(str)) str = "foo"; + if(str != "creator" && str != "player"){ + receive("\nInvalid choice.\n"); + receive("If you want to be a player, enter: player\n"); + receive("If you want to be a creator, enter: creator\n"); + receive("What is your choice?\n"); + input_to((: InputCre :), I_NOESC); + return; + } + if(str == "creator"){ + yescre = 1; + receive("\n---\nYou will automatically be made a creator shortly"); + receive(" after login.\n---\n"); + } + if(CLASS_SELECTION){ + eventSelectClass(); + return; + } + else { + eventCompleteChar(); + } +} + +void eventCompleteChar(){ + Player->SetRace(raza); + Player->SetProperty("brand_spanking_new",1); + Player->AddCurrency("silver",random(100)+57); + Player->SetPassword(Passwort); + Player->SetGender(Gendre); + Player->SetCapName(CapNamen); + Player->SetEmail(E_Mail); + Player->SetRealName(TrueName); + if(lower_case(raza) != "poleepkwa"){ + Player->SetLanguage("Common",100); + Player->SetDefaultLanguage("Common"); + this_player()->SetWimpy(20); + } + else { + Player->SetGender("neutral"); + } + if(blindmode){ + Player->SetProperty("wizmapping", 0); + Player->SetProperty("minimapping", 0); + Player->SetProperty("screen reader", 1); + } + if(yescre) Player->SetPrompt("cwd"); + else Player->SetPrompt("status"); + if(trabajo) Player->ChangeClass(trabajo); + this_player()->SetTerminal("ansi"); + PLAYERS_D->AddPlayerInfo(Name); + call_out( (: eventCre, Name :), 3); + eventEnterGame(); +} + +static void eventTimeout() { + if( !interactive(this_object()) ) { + Destruct(); + } + else if( query_idle(this_object()) > LOGON_TIMEOUT ) { + receive("\nLogin timed out.\n"); + Destruct(); + } + else call_out( (: eventTimeout :), LOGON_TIMEOUT ); +} + +varargs int eventPrint(string msg, mixed cl, mixed arg3) { + if( !cl || !intp(cl) ) return 0; + if( cl & MSG_NOWRAP ) receive(strip_colours(msg)); + else receive(wrap(strip_colours(msg), GetScreen()[0])); + return 1; +} + +static private void Destruct() { + if( Player && !NetDead ) destruct(Player); + remove_call_out(); + destruct(this_object()); +} + +void eventDestruct() { + Destruct(); +} + +string GetKeyName() { + if(!interactive(this_object())) return 0; + else if(Name) return Name; + else return ""; +} + +string GetCapName() { + string tmp; + + tmp = GetKeyName(); + return (tmp ? capitalize(tmp) : ""); +} + +static void terminal_type(string str) { + if( !stringp(str) ) return; + else Terminal = lower_case(str); +} + +static void window_size(int width, int height) { + Screen = ({ width, height }); +} + +static void CreateGuest() { + receive("Enter the name you wish to use: \n"); + input_to( (: GetGuestName :), I_NOESC ); +} + +static void GetGuestName(string nom) { + object ob; + + return; + if( !nom || nom == "" || user_exists(convert_name(nom)) ) { + receive("Illegal name choice, try again: "); + return; + } + ob->SetCapName(nom); + exec(ob, this_object()); + ob->Setup(); +} + +int *GetScreen() { + if( Screen ) return Screen; + else return ({ 79, 25 }); +} + +void SetLastError(mapping m) { + if (previous_object() != master()) return; + LastError = m; +} + +mapping GetLastError() { + string caller = base_name(previous_object()); + if( caller == "/secure/cmds/creator/dbxwhere" || + caller == "/secure/cmds/player/dbxframe" ) return LastError; + error("Privilege Violation: " + caller); +} + +int GetMaxPlayers(){ + return MaxPlayers; +} + +void receive_environ(mixed foo){ + mixed *uservars; + uservars = explode(foo, sprintf("%c", __ANSI_SUBSTITUTE__)); + foreach(string uservar in uservars){ + mixed tmp_arr = explode(uservar, sprintf("%c", 1)); + if(!sizeof(tmp_arr)) continue; + if(sizeof(tmp_arr) < 2) tmp_arr += ({ 0 }); + UserVars[tmp_arr[0]] = tmp_arr[1]; + } + if(!telopt_user && UserVars["USER"]) telopt_user = UserVars["USER"]; +} diff --git a/lib/secure/lib/connect.first.c b/lib/secure/lib/connect.first.c new file mode 100644 index 0000000..ebf1886 --- /dev/null +++ b/lib/secure/lib/connect.first.c @@ -0,0 +1,208 @@ +/* Installation object for Dead Souls + * Original author: George Reese + */ + +#include +#include +#include +#include +#include +#include + +string Name, CapName, Password; +object Admin; +int blindmode; + +static void InputName(string str); + +static void logon() { + receive("Welcome to the Dead Souls " + mudlib_version() + + " installation process!!\n\n"); + receive("You will be asked a series of questions for creating an " + "admin character.\n\n"); + receive("What is your MUD admin username?\n "); + input_to((: InputName :), I_NOESC); +} + +static void InputPassword(string str); + +static void CheckBlind(string str){ + if( !str || str == "" || lower_case(str)[0..0] == "y" ) { + receive("\nOk, disabling default overhead map.\n"); + blindmode = 1; + } + else receive("\Ok, allowing default overhead map behavior.\n"); + receive("\nCreate a password of at least 5 letters: \n"); + input_to((: InputPassword :), I_NOECHO | I_NOESC); +} + +static void InputName(string str) { + if( !(BANISH_D->valid_name(Name = convert_name(CapName = str))) + || lower_case(str) == "guest") { + receive("That is not a valid name.\n"); + receive("Name: "); + input_to((: InputName :)); + return; + } + Admin = master()->player_object(Name); + Admin->SetKeyName(Name); + mkdir(DIR_PLAYERS "/" + Name[0..0]); + receive("\nDo you use a screen reader for the visually impaired? (y/n)\n"); + input_to((: CheckBlind :), I_NOESC); +} + +static void ConfirmPassword(string str); + +static void InputPassword(string str) { + if( strlen(str) < 5 ) { + receive("Password must be at least 5 letters.\n"); + receive("Password: "); + input_to((: InputPassword :), I_NOECHO | I_NOESC); + return; + } + Password = str; + receive("\nConfirm password: "); + input_to((: ConfirmPassword :), I_NOECHO | I_NOESC); +} + +static void InputCapName(string str); + +static void ConfirmPassword(string str) { + if( str != Password) { + receive("\nPasswords do not match. Password: "); + input_to((: InputPassword :), I_NOECHO | I_NOESC); + return; + } + Admin->SetPassword(crypt(Password, 0)); + CapName = capitalize(CapName); + receive("\nEnter your display name (" + CapName + " is default): "); + input_to((: InputCapName :), I_NOESC); +} + +static void InputGender(string str); + +static void InputCapName(string str) { + if( !str || str == "" ) str = CapName; + if( convert_name(str) != Name ) { + receive("\nYou cannot do that! Display name (hit Enter for default): "); + input_to((: InputCapName :), I_NOESC); + return; + } + Admin->SetCapName(CapName = capitalize(str)); + receive("\nPlease choose a gender (male, female, neutral, or none): "); + input_to((: InputGender :), I_NOESC); +} + +static void InputRealName(string str); + +static void InputGender(string str) { + if( str ) str = lower_case(str); + if( !str || str == "" || ((str[0] != 'f' && str[0] != 'm') && + member_array(str, ({"male","female","neutral","none"})) == -1)){ + receive("\nPlease choose a gender (male, female, neutral, or none): "); + receive("Male, female, neutral or none? "); + input_to((: InputGender :)); + return; + } + if( str[0] == 'f' ) Admin->SetGender("female"); + else if( str[0] == 'm' ) Admin->SetGender("male"); + else if( str == "none" ) Admin->SetGender("neuter"); + else Admin->SetGender("neutral"); + receive("What is your real name? "); + input_to((: InputRealName :), I_NOESC); +} + +static void InputEmail(string str); + +static void InputRealName(string str) { + if( !str || str == "" ) str = "Unknown"; + Admin->SetRealName(str); + receive("What is your email address? "); + input_to((: InputEmail :), I_NOESC); +} + +static void InputEmail(string str) { + object ob, tool; + string tmp = ""; + string filep = DIR_PLAYERS "/"+Name[0..0]+"/"+Name+__SAVE_EXTENSION__; + string filec = DIR_CRES "/"+Name[0..0]+"/"+Name+__SAVE_EXTENSION__; + int foo, err; + + if( !str || str == "" ) str = "Unknown"; + load_object("secure/cmds/admins/admintool")->eventChangeEmail(str,1); + Admin->SetEmail(str); + Admin->SetRace("human"); + Admin->SetPrompt("cwd"); + Admin->AddCurrency("silver",random(100)+57); + Admin->SetTown("FirstAdmin"); + Admin->eventForce("cd"); + Admin->eventForce("home"); + Admin->SetWimpy(20); + Admin->SetTerminal("ansi"); + Admin->SetLanguage("Common",100); + Admin->SetDefaultLanguage("Common"); + if(blindmode){ + Admin->SetProperty("wizmapping", 0); + Admin->SetProperty("minimapping", 0); + Admin->SetProperty("screen reader", 1); + } + Admin->save_player(Name); + make_workroom(Name,1); + PLAYERS_D->AddPlayerInfo(Name); + + tmp = read_file(CFG_GROUPS); + + if(sizeof(tmp)) cp(CFG_GROUPS, "/secure/save/backup/groups.orig"); + + rm(CFG_GROUPS); + tmp = replace_string(tmp, "ADMIN", Name); + write_file(CFG_GROUPS, tmp); + + tmp = ""; + + tmp = read_file(CONFIG_H); + + if(sizeof(tmp)){ + cp(CONFIG_H, "/secure/save/backup/config."+__PORT__+".bak"); + rm(CONFIG_H); + tmp = replace_string(tmp, "DEBUG_NAME", Name); + write_file(CONFIG_H, tmp); + } + + catch(cp(NETWORK_H,"/secure/save/backup/network."+__PORT__+".orig")); + + if( ob = find_object(LIB_CONNECT) ) destruct(ob); + cp(DIR_SECURE_LIB "/connect.c", DIR_SECURE_LIB "/connect.first.c"); + rm(DIR_SECURE_LIB "/connect.c"); + cp(DIR_SECURE_LIB "/connect.real", DIR_SECURE_LIB "/connect.c"); + destruct(Admin); + mkdir(DIR_CRES "/" + Name[0..0]); +#if ENABLE_INSTANCES + filec = new_savename(filec); + filep = new_savename(filep); +#endif + err = rename(filep, filec); + if(err){ + receive("\nAn unfortunate error has ocurred. Mojo meditation: QQ\n"); + } + receive("\nYou will be disconnected and the MUD will shut down.\n"); + receive("Restart the MUD and login again as the admin character.\n"); + flush_messages(); + destruct(master()); + tool = load_object("/secure/cmds/admins/admintool"); + if(tool) foo = tool->eventChangeName("Dead_Souls_"+Name, 1); + if(foo){ + receive("\n\nMud name changed. Use admintool to customize it."); + receive("\nFor more info, log in and type: help admintool\n"); + } + else { + receive("Mud name unchanged.\n"); + } + flush_messages(); + cp(IMC2_D+".c", "/secure/save/backup/imc2.orig"); + PLAYERS_D->AddPlayerInfo(Name); + shutdown(); + destruct(this_object()); +} + +string GetKeyName() { return Name; } diff --git a/lib/secure/lib/connect.real b/lib/secure/lib/connect.real new file mode 100644 index 0000000..f229b60 --- /dev/null +++ b/lib/secure/lib/connect.real @@ -0,0 +1,1005 @@ +/* /secure/lib/connect.c + * from the Dead Souls Object Library + * the object a user connects to before determining their real body + * created by Descartes of Borg 951103 + * Version: @(#) connect.c 1.2@(#) + * Last Modified: 96/05/28 + */ + +#include +#include ROOMS_H +#include +#include +#include +#include +#include +#include "include/connect.h" + +#define CUSTOM_FORMAT 0 +#define REAL_NAME 0 + +#ifndef __ANSI_SUBSTITUTE__ +#define __ANSI_SUBSTITUTE__ 0x1e +#endif + +#ifndef GUEST_ALLOWED +#define GUEST_ALLOWED 1 +#endif + +inherit LIB_PAGER; +#include + +static private int CrackCount, NetDead, MaxPlayers, blindmode; +static private string name, Name, Terminal, raza, TrueName, trabajo, extra; +static private string Passwort, Gendre, CapNamen, E_Mail, my_ip, client_ip; +static private object Player, pile; +static private mapping LastError, UserVars; +static private int *Screen; +static private int rescue, yescre, anyterm; +static private string *ip_permitted = ({}), instname, telopt_user; +static private string array anyterms = ({"97.107.133.86", "127.0.0.1"}); + +//Change this to 0 to disable color codes in /news/welcome +//then update the connect.c file. +static private int AllowColorSplash = 1; + +//Change this to 1 to change your welcome screen to /news/moved +//and to disable the standard login prompts. +static private int Moved = 0; + +int eventCheckPending(string str); +void eventCompleteChar(); +void InputCre(string str); +static void cmdPickClass(string args); +static void cmdListClasses(); +static void cmdHelpClass(string args); +static void InputClass(string str); +static void eventSelectClass(); + +int CheckIp(){ + int ips = 0; + string tmp_ip; + if(!SAME_IP_MAX) return 1; + tmp_ip = query_ip_number(); + if(telopt_user && telopt_user != my_ip) tmp_ip = telopt_user; + if(!ip_permitted) ip_permitted = ({}); + ip_permitted += PLAYERS_D->GetAdminIPs(); + ip_permitted = singular_array(ip_permitted); + if(member_array(tmp_ip, ip_permitted) != -1) return 1; + foreach(object jugador in users()){ + if(query_ip_number(jugador) == tmp_ip) ips++; + } + if(ips >= SAME_IP_MAX) return 0; + return 1; +} + +static void create(int binary) { + extra = ""; + UserVars = ([]); + if(query_windows()){ + MaxPlayers = 50; + } + else { +#ifdef __ULIMIT__ + MaxPlayers = (__ULIMIT__ - 10); +#else +#if __FD_SETSIZE__ + if(!MaxPlayers || MaxPlayers > __FD_SETSIZE__){ + MaxPlayers = (__FD_SETSIZE__ - 10); + } +#endif +#endif + } + if(grepp(__ARCH__, "Solaris")){ +#ifndef __M64__ + //Solaris has a problem with fd's over 256 in + //32-bit applications. + MaxPlayers = 200; +#endif + } + if(!MaxPlayers) MaxPlayers = 1000; + if(MAX_USERS) MaxPlayers = MAX_USERS; + CrackCount = 0; + Name = ""; + Player = 0; + NetDead = 0; + if(ENABLE_INSTANCES){ + instname = INSTANCES_D->GetMyInstanceName(); + } + ip_permitted = explode(read_file(CFG_IP_UNRESTRICT),"\n"); +} + +varargs static void logon(mixed foo) { + string welcome = "Connected to "+mud_name()+", an LP mud"; + if(sizeof(architecture())) welcome += " running on "+architecture()+".\n"; + else welcome += ".\n"; + + client_ip = query_ip_number(); + + call_out((: eventTimeout :), LOGON_TIMEOUT); + if(mud_name() == "Dead Souls" || mud_name() == "Dead Souls Dev" ){ + welcome += read_file(DS_WELCOME) || "Welcome to " + mud_name() + "!"; + } + else { + string wfile; + if(instname && instname != "global"){ + wfile = NEWS_WELCOME+"."+__PORT__; + } + if(!wfile || !file_exists(wfile)) wfile = NEWS_WELCOME; + welcome += read_file(wfile) || "Welcome to " + mud_name() + "!"; + } + if(Moved){ + string wfile; + if(instname && instname != "global"){ + wfile = NEWS_MOVED+"."+__PORT__; + } + if(!wfile || !file_exists(wfile)) wfile = NEWS_MOVED; + welcome = read_file(wfile) || "Welcome to " + mud_name() + "!"; + } + if(AllowColorSplash){ + receive(terminal_colour(welcome,TERMINAL_D->query_term_info("ansi"))); + } + else { + receive(welcome); + } + if(!Moved){ + receive("\n" + center("Driver: " + version() + + " Mudlib: "+ + mudlib() + " " + mudlib_version()) + "\n"); + receive("\nWhat name do you wish? "); + input_to((: InputName :), I_NOESC); + } +} + +static void InputName(string namen, string kill_me) { + string temp_name, news; + mixed tmp; + int toomany; + name = namen; + + if(member_array(client_ip, anyterms) != -1){ + if(telopt_user){ + int bar = sscanf(telopt_user, "%*d.%*d.%*d.%*d"); + if(bar == 4){ + client_ip = telopt_user; + anyterm = 1; + extra = " ["+my_ip+"]"; + } + } + } + + if(!CheckIp()){ + receive("\nToo many users from your site are currently logged on.\n"); + receive("Please try again later.\n"); + flush_messages(); + Destruct(); + return; + } + + if(sizeof(users()) >= MaxPlayers){ + toomany = 1; + } + + if(lower_case(name) == "guest" && !GUEST_ALLOWED){ + name = ""; + receive("\nThe guest account is disabled.\n"); + } + + if( !name || name == "" ) { + if( kill_me ) { + if(!Moved) receive("\nPerhaps try another time then?\n"); + Destruct(); + return; + } + else { + if(!Moved){ + receive("\nYou must enter a name in order to join!\n"); + receive("\nWhat name do you wish? "); + } + input_to((: InputName :), I_NOESC, "kill me"); + return; + } + } + + if(grepp(name, "MSSP-REQUEST")){ + log_file("mssp",timestamp() + " " + my_ip + extra + "\n"); + receive(mssp_reply()); + flush_messages(); + input_to((: InputName :), I_NOESC); + return; + } + if(sscanf(name,"%s_rescue",temp_name) == 1) { + name = temp_name; + rescue = 1; + } + Name = convert_name(name); + name = capitalize(name); + if( master()->is_locked() || toomany) { + if(toomany){ + news = "Too many players logged in!"; + } + else news = read_file(NEWS_LOCKED) || "No reason logged."; + receive("\n" + mud_name() + " is locked. Reason:\n" + news + "\n"); + if( CanLogin() ) receive("\n >>> Access allowed <<<\n"); + else { + receive("\n >>> Access denied <<<\n"); + flush_messages(); + Destruct(); + return; + } + } + if( !user_exists(Name) ) { + eventCreatePlayer(name); + return; + } + if( !(BANISH_D->eventConnect(Name, client_ip)) ) { + news = read_file(NEWS_BANISHED) || "You are not allowed here.\n"; + receive("\n" + news + "\n"); + Destruct(); + return; + } + if( (tmp = CHARACTER_D->eventConnect(Name)) != 1 ) { + if( tmp ) receive(tmp + "\n"); + else receive("One of your characters was recently logged in.\n" + "You must wait a little longer before logging in.\n"); + Destruct(); + return; + } + + if( find_player(Name) ) NetDead = 1; + + if(Name != "guest"){ + receive("Password: "); + input_to((: InputPassword :), I_NOECHO | I_NOESC, name); + } + else InputPassword("guest","Guest"); +} + +static void InputPassword(string pass, string cap) { + string control; + + if(Name != "guest"){ + + if( !pass || pass == "" ) { + receive("\nYou must enter a password. Please try again later.\n"); + Destruct(); + return; + } + if(!cap || cap == "") { + receive("\nAn unusual error has occurred. Please try again.\n"); + Destruct(); + return; + } + + control = PLAYERS_D->GetPlayerData(Name,"Password"); + if( control != crypt(pass, control) ) { + receive("\nInvalid password.\n"); + if( ++CrackCount > MAX_PASSWORD_TRIES ) { + receive("\nNo more attempts allowed\n"); + unguarded( (: log_file("/secure/log/security", + "Maximum password tries exceeded by " + + Name + " from " + client_ip + extra + "\n") :) ); + filter(users(), (: archp :))->eventPrint("System %^MAGENTA%^" + "%^RESET%^ Maximum password " + "attempts exceeded by " + cap + + " from " + client_ip + ".\n", + MSG_ERROR); + Destruct(); + return; + } + receive("Password: "); + input_to( (: InputPassword :), I_NOECHO | I_NOESC, cap); + return; + } + + if(rescue) unguarded( (: wipe_inv(name) :) ); + } + + Player = master()->player_object(Name); + if( !Player ) { + receive("\nIt seems some work is being done right now, try later.\n"); + Destruct(); + return; + } + PLAYERS_D->AddPlayerInfo(Player); + if( !Player->GetRace() || Player->GetRace() == "blob" + || Name == "guest" ) { + Player->SetRace("human"); + } + + if( !NetDead ){ + call_out( (: eventCheckPending, lower_case(Name) :), 3); + eventEnterGame(); + } + else eventReEnterGame(cap); +} + +static void eventCreatePlayer(string cap) { + string tmpdir, lcname = lower_case(Name); + string *tmpfiles = ({}); + if( !(BANISH_D->valid_name(lcname)) ) { + receive(capitalize(cap) + " is not a valid name.\n"); + receive(mud_name() + " requires that all names meet the following " + "requirements:\n"); + receive("\tAll characters must be:\n"); + receive("\t\tA-Z\n\t\ta-z\n\t\t'\n\t\t-\n"); + receive("\tMinimum length: " + MIN_USER_NAME_LENGTH + "\n"); + receive("\tMaximum length: " + MAX_USER_NAME_LENGTH + "\n"); + receive("\nPlease enter a new name: \n"); + input_to( (: InputName :), I_NOESC ); + return; + } + tmpdir = DIR_PLAYERS "/" + lcname[0..0] + "/"; + if(directory_exists(tmpdir)){ + tmpfiles += get_dir(tmpdir); + } + tmpdir = DIR_CRES "/" + lcname[0..0] + "/"; + if(directory_exists(tmpdir)){ + tmpfiles += get_dir(tmpdir); + } + foreach(string tmpfile in tmpfiles){ + if(!strsrch(tmpfile, lcname+".")){ + receive("\nThat name is taken. Please choose a new one.\n"); + input_to( (: InputName :), I_NOESC ); + return; + } + } + if( !(BANISH_D->eventConnect(Name, client_ip)) ) { + string news; + + news = read_file(NEWS_REGISTER) || "No registration info.\n"; + receive(news); + flush_messages(); + Destruct(); + return; + } + receive("Do you really wish to be known as " + cap + "? (y/n) \n"); + input_to((: ConfirmName :), I_NOESC, cap); +} + +static BlindCheck(string ans, string cap){ + if( !ans || ans == "" || lower_case(ans)[0..0] == "y" ) { + receive("\nOk, disabling default overhead map.\n"); + blindmode = 1; + } + else receive("\Ok, allowing default overhead map behavior.\n"); + log_file("new_players", Name + " (" + ctime(time()) + ")\n"); + receive("\nCreate a password of at least 5 letters: \n"); + input_to((: CreatePassword :), I_NOECHO | I_NOESC, cap); +} + +static void AgeCheck(string ans, string cap) { + if( !ans || ans == "" || lower_case(ans)[0..0] != "y" ) { + receive("\nSorry. You are not old enough to play here.\n"); + Destruct(); + return; + } + log_file("new_players", Name + " (" + ctime(time()) + ")\n"); + unguarded( (: log_file("/secure/log/new_players", Name + " from " + + client_ip + extra + " (" + ctime(time()) + ")\n") :) ); + receive("\nDo you use a screen reader for the visually impaired? (y/n)\n"); + input_to((: BlindCheck :), I_NOESC, cap); +} + +static void ConfirmName(string ans, string cap) { + if( !ans || ans == "" || lower_case(ans)[0..0] != "y" ) { + receive("\nOk, then enter the name you really want: \n"); + input_to( (: InputName :), I_NOESC ); + return; + } + receive("\nAre you 13 years of age or older? (y/n) \n"); + input_to((: AgeCheck :), I_NOESC, cap); +} + +static void eventReEnterGame(string cap) { + if( interactive(Player) ) { + receive("\nAn interactive copy of you currently exists.\n"); + receive("Do you wish to take over this copy? (y/n) \n"); + input_to((: ConfirmReconnect :), I_NOESC, cap); + return; + } + if( exec(Player, this_object()) ) { + if(rescue) + if(sizeof(deep_inventory(Player))) + deep_inventory(Player)->eventMove(ROOM_FURNACE); + log_file("enter", cap + " (exec): " + ctime(time()) + "\n"); + unguarded( (: log_file("/secure/log/enter", Name + " (exec): " + + ctime(time()) + " from " + client_ip + extra + "\n") :) ); + Player->eventReconnect(); + Player->RemoveProperty("afk"); + if(!anyterm){ + Player->CancelCharmode(); + Player->SetProperty("reprompt", 0); + Player->SetTeloptIp(0); + } + else { + Player->SetTeloptIp(telopt_user); + } + if(creatorp(Player)) + Player->AddChannel((CHAT_D->GetSystemChannels() - ({"muds"}))); + SNOOP_D->ReportReconnect(Player->GetKeyName()); + call_out( (: eventCheckPending, lower_case(Name) :), 3); + } + receive("\nProblem reconnecting.\n"); + Destruct(); +} + +static void ConfirmReconnect(string ans, string cap) { + object tmp; + + if( !stringp(ans) || ans == "" || lower_case(ans)[0..0] != "y" ) { + receive("\nThen please try again later!\n"); + Destruct(); + return; + } + if(rescue) + if(sizeof(deep_inventory(Player))) deep_inventory(Player)->eventMove(ROOM_FURNACE); + log_file("enter", cap + " (reconnect) ("+ctime(time())+")\n"); + unguarded( (: log_file("/secure/log/enter", Name + " (reconnect) from " + + client_ip + extra + " (" + ctime(time()) + ")\n") :) ); + exec(tmp = new(LIB_PLAYER), Player); + exec(Player, this_object()); + destruct(tmp); + if(anyterm){ + int oldlock = Player->GetProperty("screenlock"); + Player->SetCharmode(1); + Player->SetProperty("reprompt",1); + Player->SetProperty("commandecho", "blue"); + Player->SetProperty("keepalive", 5); + Player->SetProperty("screenlock", 0); + Player->SetScreen(80, 25); + Player->SetProperty("screenlock", oldlock); + Player->SetTeloptIp(telopt_user); + } + else { + Player->SetTeloptIp(0); + } + Player->eventPrint("\nAllowing login.\n", MSG_SYSTEM); + call_out( (: eventCheckPending, lower_case(Name) :), 3); + Destruct(); +} + +static int CanLogin() { + string group; + + if( BANISH_D->GetGuest(Name) ) return 1; + foreach(group in LOCKED_ACCESS_ALLOWED) + if( member_group(Name, group) ) return 1; + return 0; +} + +static private void eventEnterGame() { + if(!exec(Player, this_object())) { + debug("problem connecting"); + receive("\nProblem connecting.\n"); + Player->eventDestruct(); + destruct(this_object()); + return; + } + if( Terminal ) Player->SetTerminal(Terminal); + if( Screen ) Player->SetScreen(Screen[0], Screen[1]); + Player->Setup(); + if(creatorp(Player)){ + string profile = user_path(Player->GetKeyName())+".profile"; + if(file_exists(profile)){ + string q = ""; + if(!MASTER_D->GetPerfOK()) q = "-q "; + Player->eventForce("source "+q+profile); + } + } + Player->RemoveProperty("afk"); + if(creatorp(Player)) + Player->AddChannel(((CHAT_D->GetSystemChannels()) - ({"muds"}))); + SNOOP_D->CheckBot(Player->GetKeyName()); + unguarded( (: log_file("/secure/log/enter", Name + " (enter): " + + ctime(time()) + " from " + client_ip + extra + "\n") :) ); + if(anyterm){ + int oldlock = Player->GetProperty("screenlock"); + Player->SetCharmode(1); + Player->SetProperty("reprompt",1); + Player->SetProperty("commandecho", "blue"); + Player->SetProperty("keepalive", 5); + Player->SetProperty("screenlock", 0); + Player->SetScreen(80, 25); + Player->SetProperty("screenlock", oldlock); + Player->SetTeloptIp(telopt_user); + } + else { + Player->SetTeloptIp(0); + } + call_out( (: destruct(this_object()) :), 10); +} + +static void CreatePassword(string pass, string cap) { + if( strlen(pass) < 3) { + receive("\nYour password must be at least 5 letters in length.\n"); + receive("Please choose another password: "); + input_to( (: CreatePassword :), I_NOECHO | I_NOESC, cap); + return; + } + receive("\nPlease confirm your password: "); + input_to( (: ConfirmPassword :), I_NOECHO | I_NOESC, cap, pass); +} + +static void ConfirmPassword(string control, string cap, string pass) { + if( control == pass ) { + Player = master()->player_object(Name); + pass = crypt(pass, 0); + Passwort = pass; + receive("\n\nPlease choose an interesting gender (male, female, neutral, or none): \n"); + input_to((: InputGender :), I_NOESC, cap); + return; + } + receive("\nPassword entries do not match, re-choose password: "); + input_to((: CreatePassword :), I_NOECHO | I_NOESC, cap); + return; +} + +static void InputGender(string str, string cap) { + if( str != "male" && str != "female" + && str != "neuter" && str != "neutral" && str != "none") { + receive("\nCute, but pretend to be male, female, neutral, or none instead.\n"); + receive("Gender: "); + input_to((: InputGender :), I_NOESC, cap); + return; + } + if(str == "none") str = "neuter"; + Gendre = str; + if(CUSTOM_FORMAT){ + receive("\nYou may format " + cap + " to appear however you wish " + "using spaces, ', or -.\nEnter a display name " + "(default: " + cap +"): \n"); + input_to((: InputCapName :), I_NOESC, cap); + } + else { + InputCapName(cap, cap); + } +} + +static void InputCapName(string name, string cap) { + if( !name || name == "" ) name = cap; + if( !(BANISH_D->valid_cap_name(name, Name)) ) { + receive("\nThat was not a valid name format, choose again: \n"); + input_to((: InputCapName :), I_NOESC, cap); + return; + } + cap = capitalize(name); + CapNamen = cap; + receive("\nFor security reasons, " + mud_name() + " requires a valid " + "email.\n" + "Email: \n"); + input_to((: InputEmail :), I_NOESC); +} + +static void InputEmail(string email) { + string user, host; + + if( !email || sscanf(email, "%s@%s", user, host) != 2 ) { + receive("\nThat is not a valid email address.\n"); + receive("Please enter a valid email address: \n"); + input_to( (: InputEmail :), I_NOESC ); + return; + } + E_Mail = email; + if(REAL_NAME){ + receive("\nIf you do not mind, please enter your real name " + "(optional): \n"); + input_to( (: InputRealName :), I_NOESC ); + } + else { + InputRealName(""); + } +} + +static void InputRealName(string rname) { + if( !rname || rname == "" ) rname = "Unknown"; + TrueName = rname; + if(!HUMANS_ONLY){ + receive("\n\nYou must now pick a race.\n"); + receive("Picking a race influences what physical traits your character " + "will have.\n"); + receive("\nYou may issue the following commands:\n"); + receive("\tlist - lists all races from which you can choose\n"); + receive("\thelp - get help on what races mean\n"); + receive("\thelp RACE - (e.g. \"help human\") gives you information on " + "a race\n"); + receive("\tpick RACE - pick a particular race for yourself\n"); + receive("\n\tValid races: "); + receive(implode(sort_array(RACES_D->GetRaces(1), 1), " ")); + receive("\n\nRace: \n"); + input_to((: InputRace :), I_NOESC); + } + else InputRace("pick human"); +} + +static void InputRace(string str) { + string cmd, args; + string *valid = ( RACES_D->GetRaces(1) || ({}) ); + + if( str == "" || !str ) { + receive("\nRace: "); + input_to((: InputRace :), I_NOESC); + return; + } + if( sscanf(str, "%s %s", cmd, args) != 2 ) { + cmd = str; + args = 0; + } + if(member_array(cmd, valid) != -1){ + args = cmd; + cmd = "pick"; + } + switch(cmd) { + case "list": + cmdList(); + return; + + case "help": + cmdHelp(args); + return; + + case "pick": + cmdPick(args); + return; + + default: + receive("\nInvalid command.\nRace: \n"); + input_to((: InputRace :), I_NOESC); + return; + } +} + +static void cmdHelp(string args) { + function f; + string array races = RACES_D->GetRaces(1); + string help; + + f = function(string str) { + receive("\nRace: \n"); + input_to((: InputRace :), I_NOESC); + }; + if( !args ) { + help = read_file(DIR_PLAYER_HELP + "/races") || + "Error reading help file.\n"; + eventPage(explode(help, "\n"), MSG_HELP, f); + return; + } + if( member_array(args = lower_case(args), races) == -1 ) { + receive("No such race exists.\n\nRace: \n"); + input_to((: InputRace :), I_NOESC); + return; + } + help = RACES_D->GetHelp(args); + eventPage(explode(help, "\n"), MSG_HELP, f); +} + +static void cmdList() { + string list; + + list = format_page(sort_array(RACES_D->GetRaces(1), 1), 5); + receive(list); + receive("\nRace: \n"); + input_to((: InputRace :), I_NOESC); +} + +static void cmdPick(string args) { + if( !args || args == "" ) { + receive("You must specify a race to pick.\n\nRace: \n"); + input_to((: InputRace :), I_NOESC); + return; + } + if( member_array(args = lower_case(args), + RACES_D->GetRaces(1)) == -1 ) { + receive("No such race.\nRace: \n"); + input_to((: InputRace :), I_NOESC); + return; + } + raza = args; + if(!AUTO_WIZ){ + if(CLASS_SELECTION){ + eventSelectClass(); + return; + } + eventCompleteChar(); + } + if(AUTO_WIZ == 2) InputCre("creator"); + else { + receive("This mud has enabled AUTO_WIZ.\n"); + receive("This means that if you wish, you may be automatically \n"); + receive("promoted to creator status. \n\n"); + receive("If you want to be a player, enter: player\n"); + receive("If you want to be a creator, enter: creator\n"); + receive("What is your choice?\n"); + input_to((: InputCre :), I_NOESC); + } +} + +static void eventSelectClass(){ + receive("\n\nYou must now pick a class.\n"); + receive("Picking a class influences what skills your character " + "will have.\n"); + receive("\nYou may issue the following commands:\n"); + receive("\tlist - lists all classes from which you can choose\n"); + receive("\thelp - get help on what classes mean\n"); + receive("\thelp CLASS - (e.g. \"help explorer\") gives you information on " + "a class\n"); + receive("\tpick CLASS - pick a particular class for yourself\n"); + receive("\n\tValid classes: "); + receive(implode(sort_array(CLASSES_D->GetClasses(1), 1), " ")); + receive("\nClass: \n"); + input_to((: InputClass :), I_NOESC); +} + +static void InputClass(string str){ + string cmd, args; + string *valid = ( CLASSES_D->GetClasses(1) || ({}) ); + + if( str == "" || !str ) { + receive("\nClass: "); + input_to((: InputClass :), I_NOESC); + return; + } + if( sscanf(str, "%s %s", cmd, args) != 2 ) { + cmd = str; + args = 0; + } + if(member_array(cmd, valid) != -1){ + args = cmd; + cmd = "pick"; + } + switch(cmd) { + case "list": + cmdListClasses(); + return; + + case "help": + cmdHelpClass(args); + return; + + case "pick": + cmdPickClass(args); + return; + + default: + receive("\nInvalid command.\nClass: \n"); + input_to((: InputClass :), I_NOESC); + return; + } +} + +static void cmdHelpClass(string args){ + function f; + string array Classes = CLASSES_D->GetClasses(1); + string help; + + f = function(string str) { + receive("\nClass: \n"); + input_to((: InputClass :), I_NOESC); + }; + if( !args ) { + help = HELP_D->GetHelp("player documents classes") || + "Error reading help file.\n"; + eventPage(explode(help, "\n"), MSG_HELP, f); + return; + } + if( member_array(args = lower_case(args), Classes) == -1 ) { + receive("No such Class exists.\n\nClass: \n"); + input_to((: InputClass :), I_NOESC); + return; + } + help = HELP_D->GetHelp("classes "+args); + eventPage(explode(help, "\n"), MSG_HELP, f); +} + +static void cmdListClasses() { + string list; + + list = format_page(sort_array(CLASSES_D->GetClasses(1), 1), 5); + receive(list); + receive("\nClass: \n"); + input_to((: InputClass :), I_NOESC); +} + +static void cmdPickClass(string args) { + if( !args || args == "" ) { + receive("You must specify a class to pick.\n\nClass: \n"); + input_to((: InputClass :), I_NOESC); + return; + } + if( member_array(args = lower_case(args), + CLASSES_D->GetClasses(1)) == -1 ) { + receive("No such Class.\nClass: \n"); + input_to((: InputClass :), I_NOESC); + return; + } + trabajo = args; + eventCompleteChar(); +} + +int eventCre(string str){ + mixed mixt; + if(yescre && AUTO_WIZ > 0){ + mixt = load_object("/secure/cmds/admins/encre")->cmd(str); + } + destruct(this_object()); + return 1; +} + +int eventCheckPending(string str){ + mixed mixt; + str = lower_case(str); + if(member_array(str,PLAYERS_D->GetPendingEncres()) != -1){ + PLAYERS_D->RemovePendingEncre(str); + mixt = load_object("/secure/cmds/admins/encre")->cmd(str); + } + else if(member_array(str,PLAYERS_D->GetPendingDecres()) != -1){ + PLAYERS_D->RemovePendingDecre(str); + mixt = load_object("/secure/cmds/admins/decre")->cmd(str); + } + if(member_array(str,PLAYERS_D->GetPendingPauses()) != -1){ + PLAYERS_D->RemovePendingPause(str); + mixt = Player->SetPlayerPaused(1); + } + else if(member_array(str,PLAYERS_D->GetPendingUnpauses()) != -1){ + PLAYERS_D->RemovePendingUnpause(str); + mixt = Player->SetPlayerPaused(0); + } + destruct(this_object()); + return 1; +} + +void InputCre(string str){ + if(!str || str == "" || !sizeof(str) || !stringp(str)) str = "foo"; + if(str != "creator" && str != "player"){ + receive("\nInvalid choice.\n"); + receive("If you want to be a player, enter: player\n"); + receive("If you want to be a creator, enter: creator\n"); + receive("What is your choice?\n"); + input_to((: InputCre :), I_NOESC); + return; + } + if(str == "creator"){ + yescre = 1; + receive("\n---\nYou will automatically be made a creator shortly"); + receive(" after login.\n---\n"); + } + if(CLASS_SELECTION){ + eventSelectClass(); + return; + } + else { + eventCompleteChar(); + } +} + +void eventCompleteChar(){ + Player->SetRace(raza); + Player->SetProperty("brand_spanking_new",1); + Player->AddCurrency("silver",random(100)+57); + Player->SetPassword(Passwort); + Player->SetGender(Gendre); + Player->SetCapName(CapNamen); + Player->SetEmail(E_Mail); + Player->SetRealName(TrueName); + if(lower_case(raza) != "poleepkwa"){ + Player->SetLanguage("Common",100); + Player->SetDefaultLanguage("Common"); + this_player()->SetWimpy(20); + } + else { + Player->SetGender("neutral"); + } + if(blindmode){ + Player->SetProperty("wizmapping", 0); + Player->SetProperty("minimapping", 0); + Player->SetProperty("screen reader", 1); + } + if(yescre) Player->SetPrompt("cwd"); + else Player->SetPrompt("status"); + if(trabajo) Player->ChangeClass(trabajo); + this_player()->SetTerminal("ansi"); + PLAYERS_D->AddPlayerInfo(Name); + call_out( (: eventCre, Name :), 3); + eventEnterGame(); +} + +static void eventTimeout() { + if( !interactive(this_object()) ) { + Destruct(); + } + else if( query_idle(this_object()) > LOGON_TIMEOUT ) { + receive("\nLogin timed out.\n"); + Destruct(); + } + else call_out( (: eventTimeout :), LOGON_TIMEOUT ); +} + +varargs int eventPrint(string msg, mixed cl, mixed arg3) { + if( !cl || !intp(cl) ) return 0; + if( cl & MSG_NOWRAP ) receive(strip_colours(msg)); + else receive(wrap(strip_colours(msg), GetScreen()[0])); + return 1; +} + +static private void Destruct() { + if( Player && !NetDead ) destruct(Player); + remove_call_out(); + destruct(this_object()); +} + +void eventDestruct() { + Destruct(); +} + +string GetKeyName() { + if(!interactive(this_object())) return 0; + else if(Name) return Name; + else return ""; +} + +string GetCapName() { + string tmp; + + tmp = GetKeyName(); + return (tmp ? capitalize(tmp) : ""); +} + +static void terminal_type(string str) { + if( !stringp(str) ) return; + else Terminal = lower_case(str); +} + +static void window_size(int width, int height) { + Screen = ({ width, height }); +} + +static void CreateGuest() { + receive("Enter the name you wish to use: \n"); + input_to( (: GetGuestName :), I_NOESC ); +} + +static void GetGuestName(string nom) { + object ob; + + return; + if( !nom || nom == "" || user_exists(convert_name(nom)) ) { + receive("Illegal name choice, try again: "); + return; + } + ob->SetCapName(nom); + exec(ob, this_object()); + ob->Setup(); +} + +int *GetScreen() { + if( Screen ) return Screen; + else return ({ 79, 25 }); +} + +void SetLastError(mapping m) { + if (previous_object() != master()) return; + LastError = m; +} + +mapping GetLastError() { + string caller = base_name(previous_object()); + if( caller == "/secure/cmds/creator/dbxwhere" || + caller == "/secure/cmds/player/dbxframe" ) return LastError; + error("Privilege Violation: " + caller); +} + +int GetMaxPlayers(){ + return MaxPlayers; +} + +void receive_environ(mixed foo){ + mixed *uservars; + uservars = explode(foo, sprintf("%c", __ANSI_SUBSTITUTE__)); + foreach(string uservar in uservars){ + mixed tmp_arr = explode(uservar, sprintf("%c", 1)); + if(!sizeof(tmp_arr)) continue; + if(sizeof(tmp_arr) < 2) tmp_arr += ({ 0 }); + UserVars[tmp_arr[0]] = tmp_arr[1]; + } + if(!telopt_user && UserVars["USER"]) telopt_user = UserVars["USER"]; +} diff --git a/lib/secure/lib/file.c b/lib/secure/lib/file.c new file mode 100644 index 0000000..08b83d4 --- /dev/null +++ b/lib/secure/lib/file.c @@ -0,0 +1,294 @@ +/* /lib/file.c + * From the Dead Souls Mud Library + * Handles clean file I/O without need for the driver + * Created by Descartes of Borg 961219 + * Version: @(#) file.c 1.2@(#) + * Last Modified: 96/12/19 + */ + +#include +#include + +inherit LIB_CLEAN; + +private static string FileName = 0; +private static int LinePointer = 0; +private static int MaxBytes = get_config(__MAX_BYTE_TRANSFER__); +private static int MaxFile = get_config(__MAX_READ_FILE_SIZE__); +private static int TempFile = 0; + +int isDirectory() { + return (file_size(FileName) == -2); +} + +int isFile() { + return (file_size(FileName) > -1 ); +} + +int isTemporary() { + return TempFile; +} + +buffer GetBuffer() { + int size = file_size(FileName); + int count = (size/MaxBytes) + 1; + buffer data = allocate_buffer(size); + + if( !FileName ) { + return data; + } + else if( size < 0 ) { + return 0; + } + for(int i=0; i MaxBytes ) { + length = MaxBytes; + } + else { + length = size - ptr; + } + write_buffer(data, ptr, read_buffer(FileName, ptr, length)); + } + return data; +} + +buffer GetBytes(int start, int length) { + return read_buffer(FileName, start, length); +} + +string GetCharacters(int start, int length) { + return read_bytes(FileName, start, length); +} + +string array GetDirectoryList() { + if( !isDirectory() ) { + return 0; + } + return get_dir(FileName + "/"); +} + +mixed array GetDirectoryShort() { + if( !isDirectory() ) { + return 0; + } + return get_dir(FileName + "/", -1); +} + +string GetFileName() { + if( file_size(FileName) == -2 ) { + return FileName + "/"; + } + else { + return FileName; + } +} + +int GetLastModified() { + if( file_size(FileName) == -1 ) { + return 0; + } + else { + return get_dir(FileName, -1)[0][2]; + } +} + +string GetLine() { + return read_file(FileName, LinePointer++, 1); +} + +varargs string GetLines(int arg1, int arg2) { + int start = arg1; + int count = arg2; + + if( undefinedp(arg2) ) { + start = LinePointer; + count = arg1; + LinePointer = LinePointer + count; + } + return read_file(FileName, start, count); +} + +int GetSize() { + return file_size(FileName); +} + +string GetString() { + int size = file_size(FileName); + int count = (size/MaxFile) + 1; + string data = ""; + + if( !FileName ) { + return data; + } + else if( size < 0 ) { + return 0; + } + for(int i=0; i MaxFile ) { + length = MaxFile; + } + else { + length = size - ptr; + } + data += read_bytes(FileName, ptr, length); + } + return data; +} + +mixed eventCreateDirectory() { + if( isFile() ) { + return "File exists."; + } + else if( isDirectory() ) { + return "Directory exists."; + } + else { + if( mkdir(FileName) ) { + return 1; + } + else { + return 0; + } + } +} + +mixed eventDelete() { + if( isDirectory() ) { + if( rmdir(FileName) ) { + return 1; + } + else { + return 0; + } + } + else if( isFile() ) { + if( rm(FileName) ) { + return 1; + } + else { + return 0; + } + } + else { + return "No such file or directory."; + } +} + +int eventDestruct() { + if( isTemporary() ) { + eventDelete(); + } + return clean::eventDestruct(); +} + +varargs mixed eventRename(string name, int clobber) { + object file = new(LIB_FILE, name); + object tmpfile = 0; + + if( file->isFile() || file->isDirectory() ) { + mixed tmp; + + if( !clobber ) { + return "File or directory already exists."; + } + tmpfile = new(LIB_FILE); + tmp = file->eventRename(tmpfile->GetFileName()); + if( tmp != 1 ) { + if( !tmp ) { + tmp = ""; + } + tmp = "Failed to make temp file: " + tmp; + return tmp; + } + } + if( rename(FileName, name) ) { + if( tmpfile ) { + mixed tmp = tmpfile->eventRename(name); + + if( tmp != 1 ) { + if( !tmp ) { + tmp = ""; + } + return "Failed to restore destination!! Data lost: " + tmp; + } + } + return 0; + } + if( tmpfile ) { + tmpfile->eventDelete(); + } + FileName = name; + while( strlen(FileName) && FileName[<1] == '/' ) { + FileName = FileName[0..<2]; + } + return 1; +} + +mixed eventWrite(mixed val) { + int size = sizeof(val); + int max = (bufferp(val) ? MaxBytes : MaxFile); + int count = (size/max) + 1; + + if( file_size(FileName) == -2 ) { + return "File is a directory."; + } + for(int i = 0; i max ) { + length = max; + } + else { + length = size - ptr; + } + if( bufferp(val) ) { + write_buffer(FileName, ptr, read_buffer(val, ptr, length)); + } + else { + write_bytes(FileName, ptr, val[ptr..(ptr+length-1)]); + } + } + return 1; +} + +varargs static void create(string file) { + if( !clonep() ) { + return; + } + if( FileName ) { + error("Odd, but illegal file name rename attempt.\n"); + } + if( !file ) { + int t = time(); + int count = 0; + + file = DIR_TMP "/" + t; + while( file_size(file) != -1 ) { + if( count++ > 100 ) { + error("Unable to generate temporary file."); + } + t++; + file = DIR_TMP "/" + t; + } + write_file(file, ""); + TempFile = 1; + } + else { + SetNoClean(1); + } + FileName = file; + while( strlen(FileName) && FileName[<1] == '/' ) { + if( strlen(FileName) == 1 ) { + FileName = 0; + error("Invalid file name.\n"); + } + FileName = FileName[0..<2]; + } +} diff --git a/lib/secure/lib/include/connect.h b/lib/secure/lib/include/connect.h new file mode 100644 index 0000000..53818d6 --- /dev/null +++ b/lib/secure/lib/include/connect.h @@ -0,0 +1,38 @@ +#ifndef l_connect_h +#define l_connect_h + +static void create(int binary); +varargs static void logon(mixed foo); +static void InputName(string name, string kill_me); +static void InputPassword(string pass, string cap); +static void eventCreatePlayer(string cap); +static void ConfirmName(string ans, string cap); +static void eventReEnterGame(string cap); +static void ConfirmReconnect(string ans, string cap); +static int CanLogin(); +static private void eventEnterGame(); +static void CreatePassword(string pass, string cap); +static void ConfirmPassword(string control, string cap, string pass); +static void InputGender(string str, string cap); +static void InputCapName(string name, string cap); +static void InputEmail(string email); +static void InputRealName(string rname); +static void InputRace(string str); +static void cmdHelp(string str); +static void cmdList(); +static void cmdPick(string args); +static void eventTimeout(); +varargs int eventPrint(string msg, mixed arg2, mixed arg3); +static private void Destruct(); +void eventDestruct(); +string GetKeyName(); +string GetCapName(); +static void terminal_type(string str); +static void window_size(int width, int height); +static void CreateGuest(); +static void GetGuestName(string nom); +int *GetScreen(); +void SetLastError(mapping m); +mapping GetLastError(); + +#endif /* l_connect_h */ diff --git a/lib/secure/lib/net/client.c b/lib/secure/lib/net/client.c new file mode 100644 index 0000000..2c14adb --- /dev/null +++ b/lib/secure/lib/net/client.c @@ -0,0 +1,151 @@ +/* /secure/lib/client.c + * From the Dead Souls Mud Library + * a TCP client object + * Created by Descartes of Borg 950428 + * Version: @(#) client.c 1.3@(#) + * Last modified: 96/12/21 + */ + +#include +#include NETWORK_H + +inherit LIB_DAEMON; + +class client { + int Descriptor; + int Blocking; + mixed *Buffer; +} + +private static int DestructOnClose, SocketType = -1; +private static string LogFile; +private static function Read; +private static class client Socket; + +static void eventClose(class client sock); +static void eventRead(mixed val); +static void eventSocketClose(); +static void eventSocketError(string str, int x); + +function SetRead(function f) { return (Read = f); } + +int SetSocketType(int type) { return (SocketType = type); } + +int SetDestructOnClose(int x) { return (DestructOnClose = x); } + +int eventCreateSocket(string host, int port) { + int x, ret; + + Socket = new(class client); + Socket->Blocking = 1; + if( SocketType == -1 ) SocketType = MUD; + x = socket_create(SocketType, "eventReadCallback", "eventAbortCallback"); + if( x < 0 ) { + eventSocketError("Error in socket_create().", x); + return x; + } + ret = x; + Socket->Descriptor = x; + x = socket_bind(Socket->Descriptor, 0); + if( x != EESUCCESS ) { + eventClose(Socket); + eventSocketError("Error in socket_bind().", x); + return x; + } + x = socket_connect(Socket->Descriptor, host + " " + port, + "eventReadCallback", "eventWriteCallback"); + if( x != EESUCCESS ) { + eventClose(Socket); + eventSocketError("Error in socket_connect().", x); + return x; + } + return ret; +} + +static void eventAbortCallback(int fd) { + if( !Socket ) return; + if( fd != Socket->Descriptor ) return; + eventClose(Socket); +} + +static void eventReadCallback(int fd, mixed val) { + if( functionp(Read) ) evaluate(Read, val); + else eventRead(val); +} + +static void eventRead(mixed val) { } + +static void eventWriteCallback(int fd) { + int x; + if( !Socket ) return; + Socket->Blocking = 0; + x = EESUCCESS; + while( Socket->Buffer && x == EESUCCESS ) { + switch( x = socket_write(Socket->Descriptor, Socket->Buffer[0]) ) { + case EESUCCESS: + break; + case EECALLBACK: + Socket->Blocking = 1; + break; + case EEWOULDBLOCK: + call_out( (: eventWriteCallback($(fd)) :), 0); + return; + case EEALREADY: + Socket->Blocking = 1; + return; + default: + eventClose(Socket); + eventSocketError("Error in socket_write().", x); + return; + } + if( sizeof(Socket->Buffer) == 1 ) { + Socket->Buffer = 0; + } + else { + Socket->Buffer = Socket->Buffer[1..]; + } + } +} + +static void eventWrite(mixed val) { + if( !Socket ) return; + if( Socket->Buffer ) Socket->Buffer += ({ val }); + else Socket->Buffer = ({ val }); + if( Socket->Blocking ) { + return; + } + else { + eventWriteCallback(Socket->Descriptor); + } +} + +static void eventClose(mixed arg) { + class client sock; + if(!arg) return; + if(classp(arg)) sock = arg; + if(!classp(arg)){ + trr("arg: "+identify(arg),"yellow"); + trr("prevs: "+identify(previous_object(-1)),"yellow"); + trr("i am: "+identify(this_object()),"yellow"); + if(mapp(arg)) socket_close(arg["Descriptor"]); + if(objectp(arg)) socket_close(arg->GetDescriptor()); + return; + } + //else trr("Yes, I am a class."); + socket_close(sock->Descriptor); + sock = 0; + eventSocketClose(); + if( DestructOnClose ) Destruct(); +} + +static void eventSocketClose() { } + +int eventDestruct() { + eventClose(Socket); + return daemon::eventDestruct(); +} + +static void eventSocketError(string str, int x) { + if( LogFile ) + log_file(LogFile, ctime(time()) + "\n" + socket_error(x) + "\n"); +} diff --git a/lib/secure/lib/net/echo_server.c b/lib/secure/lib/net/echo_server.c new file mode 100644 index 0000000..6a9c4ef --- /dev/null +++ b/lib/secure/lib/net/echo_server.c @@ -0,0 +1,75 @@ +/* + * This is a simple echo server. It just spews out what the + * client types in. To disconnect the client types: quit + * If your mud port is 6666, this will be on 6668 + */ + +#include NETWORK_H +int port = PORT_ECHO; + +void StartServer(); + +void create(){ + StartServer(); +} + +void StartServer(){ + int sockstat, listsock; + + listsock = socket_create(STREAM,"read_callback","close_callback"); + if(listsock < 0){ + debug("Couldn't create socket. errorcode: "+listsock); + return; + } + + sockstat = socket_bind(listsock,port); + if(sockstat < 0){ + debug("Couldn't bind socket. errorcode: "+sockstat); + return; + } + + sockstat = socket_listen(listsock,"listen_callback"); + if(sockstat < 0){ + debug("Couldn't listen on socket. errorcode: "+sockstat); + return; + } + +} + +static void listen_callback(int fd){ + int sockstat = socket_accept(fd,"read_callback","write_callback"); + + if(sockstat < 0){ + debug("Couldn't accept on socket. errorcode: "+sockstat); + return; + } + + debug("echo server: listening."); +} + +static void close_callback(int fd){ + debug("I'm wanting to close fd"+fd+" now."); +} + +static mixed read_callback(int fd, mixed data){ + int i; + string tmp=""; + mixed tmp2; + debug("fd is: "+fd); + + for(i=0;i +#include +#include NETWORK_H +#include +#include "include/ftp.h" + +inherit LIB_SOCKET; + +private static class ftp_session Session; +private string Password = 0; +private static mixed outfile = ([]); +private static int MaxBuffer = get_config(__MAX_BYTE_TRANSFER__); +private static int MaxFile = get_config(__MAX_READ_FILE_SIZE__); +private static mapping dispatch = ([ + "user" : (: eventCmdUser :), "pass" : (: eventCmdPass :), + "retr" : (: eventCmdRetr :), "stor" : (: eventCmdStor :), + "nlst" : (: eventCmdNlst :), "list" : (: eventCmdList :), + "cdup" : (: eventCmdCdup :), "quit" : (: eventCmdQuit :), + "type" : (: eventCmdType :), "port" : (: eventCmdPort :), + "noop" : (: eventCmdNoop :), "dele" : (: eventCmdDele :), + "syst" : (: eventCmdSyst :), "rnfr" : (: eventCmdRnfr :), + "rnto" : (: eventCmdRnto :), "stou" : (: eventCmdStou :), + "cwd" : (: eventCmdCwd :), "mkd" : (: eventCmdMkd :), + "pwd" : (: eventCmdPwd :), "rmd" : (: eventCmdRmd :), + ]); + +static void create(int fd, object owner){ + socket::create(fd, owner); + Session = new(class ftp_session); + Session->cmdPipe = owner; + Session->idleTime = 0; +} + +nomask static int check_privs(string file, string oper) { + string nom, tmp; + int x; + + if(oper == "read" && (file == "/doc" || sscanf(file,"/doc/%*s" ))){ + return 1; + } + if( !sscanf(file, REALMS_DIRS "/%s", nom) ) { + return 0; + } + if(file_privs(file) == Session->user){ + return 1; + } + if( sscanf(nom, "%s/%*s", tmp) ) { + nom = tmp; + } + nom = user_path(nom)+"adm/access"; + if( file_size(nom+".c") < 0 ) { + return 0; + } + catch(x = call_other(nom, "check_access", this_object(), "foo", + file, oper)); + return x; +} + +mixed* clean_array(mixed* r) { + int i, n; + + r = r & r; // sort. sort_array() can't hack it. And no, &= doesn't work. + + n = sizeof(r) - 1; + while (i < n) { + if (r[i] == r[i+1]) { + int j = i+1; + + while (j < n && r[i] == r[j + 1]) + j++; + + r[i..j-1] = ({}); + n -= j - i; + } + i++; + } + + return r; +} + +private string find_flags(string arg){ + string array parts; + string array flags=({}); + + parts = filter(explode(arg, " "), (: $1[0]=='-' :)); + foreach(string part in parts) flags += explode(part,""); + clean_array(flags); + return implode(flags -= ({"-"}) ,""); +} + +private string strip_flags(string arg){ + string array parts; + + parts = filter(explode(arg," "), (: $1[0] != '-' :)); + return implode(parts, " "); +} + +string FindPrevDir( string path ) { + string array parts = explode(path, "/"); + + if(sizeof(parts) == 1) return path; + parts = parts [0..<2]; + return "/" + implode(parts, "/"); +} + +private void idle_time_out(){ + if(Session->dataPipe){ /* Data connections are still active. */ + Session->idleTime = 0; + } + else{ + Session->idleTime += 60; + if(Session->idleTime > MAX_IDLE_TIME + 60){ + eventWrite("426 Idle time too long, connection closed.\n",1); + Destruct(); + return; + } + } + call_out("idle_time_out", 60); +} + +private string GetFtpWelcomeMsg(){ + return sprintf("220- %s FTP server ready.\n%s" + "220 Please login with your creator name or anonymous.\n", + mud_name(), + file_exists(FTP_WELCOME) ? "220- " + + replace_string(read_file(FTP_WELCOME), "\n", "\n220- ") + +"\n": ""); + +} + +string GetKeyName(){ return Session->user; } + +string GetUniqueFileName(string arg){ + string array parts = explode(arg, "/"); + string path, file, sufx = ""; + int i = 0; + + if(sizeof(parts) == 1){ + path = "/"; + file = parts[0]; + } + else{ + path = "/" + implode(parts [0..<2], "/"); + file = parts [<1]; + } + if(sscanf(file, "%s.%s", file, sufx) ==2){ + sufx = "." + sufx; + } + sscanf(file, "%s~%d", file, i); + i++; + arg = absolute_path(path, sprintf("%s~%d%s", file, i, sufx)); + while( file_exists(arg) ){ + i++; + arg = absolute_path(path, sprintf("%s~%d%s", file, i, sufx)); + } + return arg; +} + +void StartService(){ + eventWrite(GetFtpWelcomeMsg(),0); + call_out("idle_time_out", 60); +} + +private void eventDestructDataPipe(mixed f){ + if(Session->dataPipe){ + Session->dataPipe->SetClose(f); + Session->dataPipe->eventDestruct(); + } +} + +void Destruct(){ + remove_call_out("idle_time_out"); + eventDestructDataPipe(0); + ::Destruct(); +} + +private void eventCmdUser(string arg){ + if(!arg){ + eventWrite("500 command not understood.\n",0); + return; + } + arg = lower_case(arg); + if(Session->connected){ + eventWrite(sprintf("530 User %s access denied.\n", arg),0); + return; + } + Session->user = arg; +#ifdef ALLOW_ANON_FTP + if(member_array(arg, ({"anonymous", "ftp"})) != -1){ + eventWrite("331 Guest login ok, send your complete e-mail " + "address as password.\n",0); + return; + } +#endif + eventWrite(sprintf("331 Password required for %s.\n", arg),0); + return; +} + +private void eventCmdPswd(string arg){ + string path; + if(!arg){ + eventWrite("500 command not understood.\n",0); + return; + } + if(Session->connected || !Session->user){ + eventWrite("503 Login with USER first.\n",0); + return; + } + +#ifdef ALLOW_ANON_FTP + if(member_array(arg, ({"anonymous", "ftp"})) != -1){ + eventWrite("230 guest login ok, access restrictions apply.\n",0); + Session->connected = 1; + Session->priv = 0; + Session->pwd = ANON_PREFIX; + log_file("reports/network_connect", "Anomymous login " + "(email = %s)\n", arg); + return; + } +#endif + path = DIR_CRES "/" + Session->user[0..0] + "/" + Session->user; + RestoreObject(DIR_CRES "/" + Session->user[0..0] + "/" + + Session->user, 1 ); + if(!Password || Password != crypt(arg, Password) ) { + log_file("reports/network_connect", "Attempted login as %s\n", + Session->user); + eventWrite("530 Login incorrect.\n", 1); + return; + } + eventWrite(sprintf("230 User %s logged in.\n", Session->user),0); + log_file("reports/network_connect", "User %s logged in.\n",Session->user); + Session->connected = 1; + Session->priv = "" + Session->user; + Session->pwd = absolute_path(REALMS_DIRS, Session->user); + if (file_size(Session->pwd) != -2) Session->pwd = ANON_PREFIX; + return; +} + +private void eventCmdQuit(string arg){ + eventWrite("221 Goodbye.\n", 1); +} + +string RetrieveCmdCallback(object ob){ + int start,length; + mixed ret; + + if (!ob || undefinedp(outfile[ob])) return 0; + + start = outfile[ob][2]; + length = MaxBuffer; + outfile[ob][2] += length; + + if (start + length > outfile[ob][4]) + length = outfile[ob][4] - start; + + ret = read_buffer(outfile[ob][0], start, length); + if (outfile[ob][2] >= outfile[ob][4]) { + map_delete(outfile, ob); + } + return ret; +} + +private void eventReadFtpData(mixed text){ + switch(Session->binary){ + case 0: + text=replace_string(text, CARRIAGE_RETURN, ""); + write_file(Session->targetFile, text); + return; + case 1: + write_buffer(Session->targetFile, Session->filepos, text); + Session->filepos += sizeof(text); + return; + default: + error(sprintf("Assertion failed: \"##x\" (File: %s)\n", __FILE__)); + } +} + +private void eventCmdPort(string arg){ + string ip, *parts; + int port; + + if(!arg){ + eventWrite("500 command not understood.\n",0); + return; + } + parts = explode(arg, ","); + if(sizeof(parts) != 6){ + eventWrite("550 Failed command.\n",0); + return; + } + ip = implode(parts[0..3],"."); + port = (to_int(parts[4]) << 8) + to_int(parts[5]); + if(Session->dataPipe) eventDestructDataPipe(0); + Session->dataPipe = new(LIB_FTP_CLIENT); + Session->dataPipe->SetOwner(this_object()); + Session->dataPipe->SetSocketType(Session->binary?STREAM_BINARY:STREAM); + Session->dataPipe->eventCreateSocket(ip, port); + Session->dataPipe->SetDestructOnClose(1); + Session->dataPipe->SetRead((:eventReadFtpData:)); + Session->dataPipe->SetClose((:eventWrite("226 Transfer complete.\n",0):)); + eventWrite("200 PORT command successful.\n",0); + return; +} + +private void do_list( string arg, int ltype){ + string array files; + string flags; + string output; + buffer data = allocate_buffer(MaxBuffer); + + if(arg){ + flags = find_flags(arg); + arg = strip_flags(arg); + } + + if(!arg || arg == "") arg = "."; + /* This hack added by Tigran because things like /secure/master.c/. + * evaluate and cause havoc w/ ftp clients like efs for Xemacs and + * ange-ftp for Emacs. Besides it shouldn't happen anyways */ + if(arg[<2..]=="/." && file_exists(arg[0..<3]) ){ + eventWrite(sprintf("550 %s: No such file OR directory.\n",arg),0); + eventDestructDataPipe(0); + return; + } + arg = absolute_path(Session->pwd, arg); + +#ifdef ALLOW_ANON_FTP + if(member_array(Session->user, ({"anonymous", "ftp"})) != -1 + && arg[0..(strlen(ANON_PREFIX)-1)] != ANON_PREFIX) { + eventDestructDataPipe((:eventWrite("550 Pemission denied.\n",0):); + return; + } +#endif + if(file_size(arg) == -2) { + arg = (arg[<1] != '/')? arg+"/"+"*":arg+"*"; + } + if(file_size(FindPrevDir(arg)) == -1){ + eventWrite(sprintf("550 %s: No such file OR directory.\n", arg),0); + eventDestructDataPipe(0); + return; + } + if(!(files = get_dir(arg, -1))){ + eventWrite(sprintf("550 %s: Permission denied.\n",arg),0); + eventDestructDataPipe(0); + return; + } + if(flags){ + if(strsrch(flags,'a') == -1) + files = filter(files, (: member_array($1[0], ({".",".."})) == -1 :)); + } + if(!sizeof(files)){ + eventWrite("550 No files found.\n",0); + eventDestructDataPipe(0); + return; + } + + /* in case of LIST imply -l */ + /* in case of NLST imply -1 */ + if (ltype == LTYPE_LIST){ + if (flags){ + if ( (strsrch(flags, 'l') == -1) && + (strsrch(flags, 'C') == -1) && + (strsrch(flags, '1') == -1) ) + flags += "l"; + } + else + flags = "l"; + } + else{ + if (flags){ + if ( (strsrch(flags, 'l') == -1) && + (strsrch(flags, 'C') == -1) && + (strsrch(flags, '1') == -1) ) + flags += "1"; + } + else flags = "1"; + } + if(strsrch(flags,'F') > -1){ + foreach(mixed array file in files) + if(file[1]==-2) file[0]=sprintf("%s/",file[0]); + } + if(strsrch(flags,'C')>-1){ + int lines; + int size; + int i; + + if((strsrch(flags,'l') > -1 ) || (strsrch(flags,'1') > -1)){ + eventWrite("550: LIST -C flag is incompatible with -1 or -l.\n",0); + eventDestructDataPipe(0); + return; + } + lines=((size = sizeof(files)) / 3 ) + 1; + output=""; + for(i=0;i -1){ + if(strsrch(flags,'1')>-1){ + eventWrite("550: LIST -l and -1 flags incompatible.\n",0); + eventDestructDataPipe(0); + return; + } + output = implode(map(files, + (:sprintf("%s %3i %=9s %=8s %=7s %s%5s %s", + $1[1]==-2?"drwxrwxr-x":"-rw-rw-r--", + 1, + lower_case(replace_string(mud_name(), " ", "_"))[0..7], + lower_case(replace_string(mud_name(), " ", "_"))[0..7], + $1[1]==-2?"0":sprintf("%d",$1[1]), + ctime($1[2])[4..10], + (time()-$1[2])>31536000?ctime($1[2])[20..]:ctime($1[2])[11..15], + $1[0]) :)),"\n"); + } + if(strsrch(flags,'1') > -1) + output=implode(map(files,(:sprintf("%s",$1[0]) :)),"\n"); + eventWrite("150 Opening ASCII mode data connection for file list."+CARRIAGE_RETURN+"\n",0); + Session->dataPipe->eventWrite(implode(explode(output,"\n"), CARRIAGE_RETURN+"\n")+CARRIAGE_RETURN+"\n"); + return; +} + +private void eventCmdList(string arg){ + if(!check_privs(absolute_path(Session->pwd, arg), "read")){ + eventDestructDataPipe((:eventWrite("550 Pemission denied.\n",0):)); + return; + } + do_list(arg, LTYPE_LIST); +} + +private void eventCmdNlst(string arg){ + if(!check_privs(absolute_path(Session->pwd, arg), "read")){ + eventDestructDataPipe((:eventWrite("550 Pemission denied.\n",0):)); + return; + } + do_list(arg, LTYPE_NLST); +} + +private void eventCmdRetr(string arg){ + string target_file; + int i; + + if(!arg){ + eventDestructDataPipe((:eventWrite("500 command not understood.\n",0):)); + return; + } + target_file = absolute_path(Session->pwd, arg); + if(member_array(Session->user, ({"anonymous", "ftp"})) != -1 + && target_file[0..(strlen(ANON_PREFIX)-1)] != ANON_PREFIX) { + eventDestructDataPipe((:eventWrite("550 Pemission denied.\n",0):)); + return; + } + i = file_size(target_file); + switch(i){ + case -2: + eventWrite(sprintf("550 %s: Can't retrieve (it's a directory).\n", + target_file),0); + eventDestructDataPipe(0); + return; + case -1: + eventWrite(sprintf("550 %s: No such file OR directory.\n", + target_file),0); + eventDestructDataPipe(0); + return; + case 0: + eventWrite(sprintf("550 %s: File contains nothing.\n", + target_file),0); + eventDestructDataPipe(0); + return; + default: + if(i > MaxFile){ + eventWrite(sprintf("550 %s: File size too large.\n", + target_file),0); + eventDestructDataPipe(0); + return; + } + } + if(!check_privs(target_file, "read")){ + eventDestructDataPipe((:eventWrite("550 Pemission denied.\n",0):)); + return; + } + switch(Session->binary){ + case 0: + outfile[Session->dataPipe]=({target_file,0,0,Session->cmdPipe, i}); + eventWrite(sprintf("150 Opening ascii mode data connection for " + "%s (%d bytes).\n", target_file, i),0); + Session->dataPipe->SetWrite((: RetrieveCmdCallback :)); + + Session->dataPipe->eventWrite(RetrieveCmdCallback(Session->dataPipe)); + break; + case 1: + outfile[Session->dataPipe]=({target_file,1,0,Session->cmdPipe, i}); + eventWrite(sprintf("150 Opening binary mode data connection " + "for %s (%d bytes).\n", target_file, i),0); + Session->dataPipe->SetWrite((: RetrieveCmdCallback :)); + + Session->dataPipe->eventWrite(RetrieveCmdCallback(Session->dataPipe)); + break; + default: + error(sprintf("Assertion failed: \"##x\" (File: %s)\n", __FILE__)); + } +} + +void eventCmdPwd(string arg){ + eventWrite(sprintf("257 \"%s\" is current directory.\n", Session->pwd),0); +} + +void eventCmdNoop(string arg){ + eventWrite("221 NOOP command successful.\n",0); +} + +private void eventCmdStor(string arg){ + if(!arg){ + eventDestructDataPipe((:eventWrite("500 command not understood.\n",0):)); + return; + } + arg = absolute_path(Session->pwd, arg); +#ifndef ANON_CAN_PUT + if(member_array(Session->user, ({"anonymous", "ftp"})) != -1){ + eventDestructDataPipe((:eventWrite, "550 Pemission denied.\n", 0:)); + return; + } +#else + if(member_array(Session->user, ({"anonymous", "ftp"})) != -1 + && arg[0..(strlen(ANON_PREFIX)-1)] != ANON_PREFIX) { + eventDestructDataPipe((:eventWrite, "550 Pemission denied.\n", 0:)); + return; + } +#endif + if(file_size(FindPrevDir(arg)) != -2 ){ + eventDestructDataPipe((:eventWrite, + "553 No such directory to store into.\n", 0:)); + return; + } + if(!check_privs(arg, "write")){ + eventDestructDataPipe((:eventWrite("550 Pemission denied.\n",0):)); + return; + } + Session->targetFile = arg; + if( file_exists(arg) ){ + if( !rm( arg ) ){ + eventWrite(sprintf("550 %s: Permission denied.\n", arg),0); + eventDestructDataPipe(0); + return; + } + } + else if(!write_file( arg, "") ){ + eventWrite(sprintf("550 %s: Permission denied.\n", arg),0); + eventDestructDataPipe(0); + return; + } + Session->filepos = 0; + eventWrite(sprintf("150 Opening %s mode data connection for %s.\n", + Session->binary ? "binary" : "ascii", arg),0); +} + +private void eventCmdStou(string arg){ + if(!arg){ + eventDestructDataPipe((:eventWrite("500 command not understood.\n",0):)); + return; + } + arg = absolute_path(Session->pwd, arg); +#ifndef ANON_CAN_PUT + if(member_array(Session->user, ({"anonymous", "ftp"})) != -1){ + eventDestructDataPipe((:eventWrite, "550 Pemission denied.\n", 0:)); + return; + } +#else + if(member_array(Session->user, ({"anonymous", "ftp"})) != -1 + && arg[0..(strlen(ANON_PREFIX)-1)] != ANON_PREFIX) { + eventDestructDataPipe((:eventWrite, "550 Pemission denied.\n", 0:)); + return; + } +#endif + if(file_size(FindPrevDir(arg)) != -2 ){ + eventDestructDataPipe((:eventWrite, + "553 No such directory to store into.\n", 0:)); + return; + } + if(!check_privs(arg, "write")){ + eventDestructDataPipe((:eventWrite("550 Pemission denied.\n",0):)); + return; + } + if( file_exists(arg)){ + arg = GetUniqueFileName(arg); + } + Session->targetFile = arg; + if(!write_file( arg, "") ){ + eventWrite(sprintf("550 %s: Permission denied.\n", arg),0); + eventDestructDataPipe(0); + return; + } + Session->filepos = 0; + eventWrite(sprintf("150 Opening %s mode data connection for %s.\n", + Session->binary ? "binary" : "ascii", arg),0); +} + +private void eventCmdCwd(string arg){ + string newpath; + if(!arg){ + eventWrite("500 command not understood.\n",0); + return; + } + newpath = absolute_path(Session->pwd, arg); + if(member_array(Session->user, ({"anonymous", "ftp"})) != -1 + && newpath[0..(strlen(ANON_PREFIX)-1)] != ANON_PREFIX) { + eventWrite("550 Pemission denied.\n",0); + return; + } + if(!check_privs(newpath, "read")){ + eventWrite("550 Pemission denied.\n",0); + return; + } + if( file_size(newpath) != -2 ){ + eventWrite(sprintf("550 %s: No such directory.\n", newpath),0); + return; + } + Session->pwd = newpath; + eventWrite("250 CWD command successful.\n",0); +} + +private void eventCmdCdup(string arg){ eventCmdCwd(".."); } + +private void eventCmdMkd(string arg){ + if(!arg){ + eventWrite("500 command not understood.\n",0); + return; + } + arg = absolute_path(Session->pwd, arg); +#ifndef ANON_CAN_PUT + if(member_array(Session->user, ({"anonymous", "ftp"})) != -1){ + eventWrite("550 Permission denied.\n",0); + return; + } +#else + if(member_array(Session->user, ({"anonymous", "ftp"})) != -1 + && arg[0..(strlen(ANON_PREFIX)-1)] != ANON_PREFIX) { + eventWrite("550 Pemission denied.\n",0); + return; + } +#endif + if( file_size(FindPrevDir(arg)) != -2 ){ + eventWrite(sprintf("550 %s: No such directory.\n", + FindPrevDir(arg)),0); + return; + } + if(unguarded((:file_size($(arg)):)) != -1){ + eventWrite(sprintf("550 %s: File exists.\n", arg),0); + return; + } + if(!check_privs(arg, "write")){ + eventWrite("550 Pemission denied.\n",0); + return; + } + if( !mkdir(arg) ){ + eventWrite(sprintf("550 %s: Permission denied.\n", arg),0); + return; + } + eventWrite("257 MKD command successful.\n",0); + return; +} + +private void eventCmdType(string arg){ + if(!arg){ + eventWrite("500 command not understood.\n",0); + return; + } + arg = lower_case(arg); + switch(arg){ + case "a": + Session->binary = 0; + eventWrite("200 Type set to A.\n",0); + return; + case "i": + Session->binary = 1; + eventWrite("200 Type set to I.\n",0); + return; + default: + eventWrite("550 Unknown file type.\n",0); + return; + } +} + +private void eventCmdDele(string arg){ + if(!arg){ + eventWrite("500 command not understood.\n",0); + return; + } + arg = absolute_path( Session->pwd, arg); + if(member_array(Session->user, ({"anonymous", "ftp"})) != -1 + && arg[0..(strlen(ANON_PREFIX)-1)] != ANON_PREFIX) { + eventWrite("550 Pemission denied.\n",0); + return; + } + if( !file_exists(arg) ){ + eventWrite(sprintf("550 %s: No such file OR directory.\n", arg),0); + return; + } + if(!check_privs(arg, "write")){ + eventWrite("550 Pemission denied.\n",0); + return; + } + if( !rm(arg) ){ + eventWrite(sprintf("550 %s: Permission denied.\n",arg),0); + return; + } + eventWrite("250 DELE command successful.\n",0); +} + +private void eventCmdSyst(string arg) { + eventWrite("215 UNIX Mud Name: "+mud_name()+"\n",0); +} + +private void eventCmdRnfr(string arg) { + if(!arg){ + eventWrite("500 command not understood.\n",0); + return; + } + arg = absolute_path( Session->pwd, arg); + if(member_array(Session->user, ({"anonymous", "ftp"})) != -1 + && arg[0..(strlen(ANON_PREFIX)-1)] != ANON_PREFIX) { + eventWrite("550 Pemission denied.\n",0); + return; + } + if( !file_exists(arg) ){ + eventWrite(sprintf("550 %s: No such file OR directory.\n", arg),0); + return; + } + if(!check_privs(arg, "write")){ + eventWrite("550 Pemission denied.\n",0); + return; + } + Session->renamefrom = arg; + eventWrite("350 Input new name for " + arg + ".\n",0); +} + +private void eventCmdRnto(string arg) { + if(!arg){ + eventWrite("500 command not understood.\n",0); + return; + } + arg = absolute_path( Session->pwd, arg); + if(member_array(Session->user, ({"anonymous", "ftp"})) != -1 + && arg[0..(strlen(ANON_PREFIX)-1)] != ANON_PREFIX) { + eventWrite("550 Pemission denied.\n",0); + return; + } + if( !Session->renamefrom ){ + eventWrite(sprintf("550 You must first specify a file to rename.\n", + arg),0); + return; + } + if( !file_exists(Session->renamefrom) ){ + eventWrite(sprintf("550 %s: No such file OR directory.\n", arg),0); + Session->renamefrom = 0; + return; + } + if(!check_privs(Session->renamefrom, "write")){ + eventWrite("550 Pemission denied.\n",0); + Session->renamefrom = 0; + return; + } + if(!check_privs(FindPrevDir(arg), "write")){ + eventWrite("550 Pemission denied.\n",0); + Session->renamefrom = 0; + return; + } + if(rename(Session->renamefrom, arg)){ + eventWrite(sprintf("553 %s: Invalid desitination name.\n", arg),0); + } + eventWrite(sprintf("250 RNTO %s --> %s.\n", Session->renamefrom, arg),0); + Session->renamefrom = 0; +} + +private void eventCmdRmd(string arg) { + if(!arg){ + eventWrite("500 command not understood.\n",0); + return; + } + arg = absolute_path( Session->pwd, arg); + if(member_array(Session->user, ({"anonymous", "ftp"})) != -1 + && arg[0..(strlen(ANON_PREFIX)-1)] != ANON_PREFIX) { + eventWrite("550 Pemission denied.\n",0); + return; + } + if( file_size(arg) != -2 ){ + eventWrite(sprintf("550 %s: No such file OR directory.\n", arg),0); + return; + } + if(!check_privs(arg, "write")){ + eventWrite("550 Pemission denied.\n",0); + return; + } + if( !rmdir(arg) ){ + eventWrite(sprintf("550 %s: Directory not empty.\n",arg),0); + return; + } + eventWrite("250 RMD command successful.\n",0); +} + +void eventRead(string data){ + string cmd, arg; + function dispatchTo; + int i; + + if (!(Session->command)) Session->command = ""; + + data = replace_string(data, CARRIAGE_RETURN, ""); + Session->command += data; + if ((i = strsrch(Session->command, "\n")) == -1) return; + data=Session->command[0..i-1]; + Session->command=Session->command[i+1..]; + Session->command = trim(Session->command); + if (!sscanf(data, "%s %s", cmd, arg)) cmd = data; + cmd = lower_case(cmd); + + if (!Session->connected){ + switch(cmd){ + case "user": + eventCmdUser(arg); + return; + case "pass": + eventCmdPswd(arg); + return; + case "quit": + eventCmdQuit(arg); + return; + case "noop": + eventCmdNoop(arg); + return; + default: + eventWrite("503 Log in with USER first.\n",0); + return; + } + } + Session->idleTime = 0; + dispatchTo = dispatch[cmd]; + if (!dispatchTo){ + log_file("reports/network_error", + sprintf("ftp - unknown command: %s\n",cmd)); + eventWrite(sprintf("502 Unknown command %s.\n", cmd),0); + return; + } + if(catch(evaluate(dispatchTo, arg))){ + eventWrite("550 Unknown failure. Please report what you were doing " + "to the mud admin.\n",0); + } + return; +} diff --git a/lib/secure/lib/net/ftp_client.c b/lib/secure/lib/net/ftp_client.c new file mode 100644 index 0000000..52bca6d --- /dev/null +++ b/lib/secure/lib/net/ftp_client.c @@ -0,0 +1,181 @@ +/* /secure/lib/ftp_client.c + * From the Dead Souls Object Library + * a TCP client object + * Created by Descartes of Borg 950428 + * Modified by Dvarsk to add read,write and close settable functions. + * Version: @(#) client.c 1.5@(#) + * Last modified: 97/03/31 + */ + +#include +#include NETWORK_H + +inherit LIB_DAEMON; +object Owner; + +class client { + int Descriptor; + int Blocking; + int NoDestruct; + mixed array Buffer; +} + +private static int DestructOnClose, SocketType = -1; +private static string LogFile; +private static function Read; +private static function Write; +private static function Close; +private static class client Socket; + +varargs static int eventClose(class client sock, int aborted); +static void eventRead(mixed val); +static void eventSocketClose(); +static void eventSocketError(string str, int x); +int eventWriteDestruct(); + +function SetRead(function f) { return (Read = f); } + +function SetWrite(function f) { return (Write = f); } + +function SetClose(function f) { return (Close = f); } + +int SetSocketType(int type) { return (SocketType = type); } + +int SetDestructOnClose(int x) { return (DestructOnClose = x); } + +int eventCreateSocket(string host, int port) { + int x; + + Socket = new(class client); + Socket->Blocking = 1; + if( SocketType == -1 ) SocketType = MUD; + x = socket_create(SocketType, "eventReadCallback", "eventAbortCallback"); + if( x < 0 ) { + eventSocketError("Error in socket_create().", x); + return x; + } + Socket->Descriptor = x; + x = socket_bind(Socket->Descriptor, 0); + if( x != EESUCCESS ) { + eventClose(Socket); + eventSocketError("Error in socket_bind().", x); + return x; + } + x = socket_connect(Socket->Descriptor, host + " " + port, + "eventReadCallback", "eventWriteCallback"); + if( x != EESUCCESS ) { + eventClose(Socket); + eventSocketError("Error in socket_connect().", x); + return x; + } +} + +static void eventAbortCallback(int fd) { + if( !Socket ) return; + if( fd != Socket->Descriptor ) return; + eventClose(Socket, 1); +} + +static void eventReadCallback(int fd, mixed val) { + if( functionp(Read) ) evaluate(Read, val); + else eventRead(val); +} + +static void eventRead(mixed val) { } + +static void eventWriteCallback(int fd) { + int x; + + if( !Socket ){ + eventDestruct(); + return; + } + if ( !sizeof(Socket->Buffer) && Write && Socket->Blocking ){ + Socket->Buffer = ({ evaluate(Write, this_object()) }); + } + + Socket->Blocking = 0; + Socket->NoDestruct = 1; + x = EESUCCESS; + while( Socket->Buffer && x == EESUCCESS ) { + switch( x = socket_write(Socket->Descriptor, Socket->Buffer[0]) ) { + case EESUCCESS: + if (Write ){ + mixed tmp; + + tmp = evaluate(Write, this_object()); + if ( sizeof(tmp) ){ + Socket->Buffer += ({ tmp }); + } + } + Socket->NoDestruct = 0; + break; + case EECALLBACK: + Socket->Blocking = 1; + Socket->NoDestruct = 1; + break; + case EEWOULDBLOCK: + call_out( (: eventWriteCallback($(fd)) :), 0); + Socket->NoDestruct = 1; + return; + case EEALREADY: + Socket->Blocking = 1; + eventDestruct(); + return; + default: + eventClose(Socket); + eventSocketError("Error in socket_write().", x); + eventDestruct(); + return ; + } + if( sizeof(Socket->Buffer) == 1 ) Socket->Buffer = 0; + else Socket->Buffer = Socket->Buffer[1..]; + + } + eventWriteDestruct(); +} + +void SetOwner(object ob){ + if(Owner) return; + Owner = ob; +} + +void eventWrite(mixed val) { + object prev = previous_object(); + if(prev && prev != this_object() && prev != Owner) return; + if( !Socket ) return; + if( Socket->Buffer ) Socket->Buffer += ({ val }); + else Socket->Buffer = ({ val }); + if( Socket->Blocking ) return; + else eventWriteCallback(Socket->Descriptor); +} + +varargs static int eventClose(class client sock, int aborted) { + if( !sock ) return 0; + if( !aborted && socket_close(sock->Descriptor) != EESUCCESS ) { + return 0; + } + sock = 0; + if( functionp(Close) ) evaluate(Close); + else eventSocketClose(); + if( DestructOnClose ) Destruct(); + return 1; +} + +static void eventSocketClose() { } + +int eventDestruct() { + eventClose(Socket); + return daemon::eventDestruct(); +} + +int eventWriteDestruct() { + if(Socket->NoDestruct) return 0; + return eventDestruct(); +} + +static void eventSocketError(string str, int x) { + if( LogFile ) + log_file(LogFile, ctime(time()) + "\n" + socket_error(x) + "\n"); +} + diff --git a/lib/secure/lib/net/ftp_data_connection.c b/lib/secure/lib/net/ftp_data_connection.c new file mode 100644 index 0000000..51cd3ed --- /dev/null +++ b/lib/secure/lib/net/ftp_data_connection.c @@ -0,0 +1,229 @@ +/* /secure/lib/ftp_data_connection.c + * From the Dead Souls Object Library + * Created by Descartes of Borg 950428 + * Modified by Dvarsk to add read,write and close settable functions. + * Modified by Zaxan@Haven to add PASV support. + * - Also renamed it because ftp_client is kindof a misnomer. + */ + +#include +#include NETWORK_H + +inherit LIB_DAEMON; +object Owner; + +class data_conn { + int Descriptor; + int PassiveDescriptor; + int Blocking; + int NoDestruct; + mixed array Buffer; +} + +private static int DestructOnClose, SocketType = -1; + +private static int PassiveMode = 0; +private static string LogFile = "inet/ftp_data_conn_error"; +private static function Read; +private static function Write; +private static function Close; +private static class data_conn Socket; + +varargs static int eventClose(class data_conn sock, int aboted); +static void eventRead(mixed val); +static void eventSocketClose(); +static void eventSocketError(string str, int x); +int eventWriteDestruct(); +function SetRead(function f) { return (Read = f); } + +function SetWrite(function f) { return (Write = f); } + +function SetClose(function f) { return (Close = f); } + +int SetSocketType(int type) { return (SocketType = type); } + +int SetDestructOnClose(int x) { return (DestructOnClose = x); } + + +int SetPassiveMode(int x) { return (PassiveMode = x); } + +int eventCreateSocket(string host, int port) { + int x; + + Socket = new(class data_conn); + + if(PassiveMode) + Socket->Blocking = 0; + else + Socket->Blocking = 1; + if( SocketType == -1 ) SocketType = MUD; + x = socket_create(SocketType, "eventReadCallback", "eventAbortCallback"); + if( x < 0 ) { + eventSocketError("Error in socket_create().", x); + return x; + } + Socket->Descriptor = x; + + if(PassiveMode) + x = socket_bind(Socket->Descriptor, port); + + else + x = socket_bind(Socket->Descriptor, 0); + if( x != EESUCCESS ) { + eventClose(Socket); + eventSocketError("Error in socket_bind().", x); + return x; + } + + /* Added by Zaxan@Haven */ + if(PassiveMode) + { + x = socket_listen(Socket->Descriptor, "eventListenCallback"); + if(x != EESUCCESS) + { + eventClose(Socket); + eventSocketError("Error in socket_listen().", x); + return x; + } + } + else + { + + x = socket_connect(Socket->Descriptor, host + " " + port, + "eventReadCallback", "eventWriteCallback"); + if( x != EESUCCESS ) { + eventClose(Socket); + eventSocketError("Error in socket_connect().", x); + return x; + } + } +} + +static void eventAbortCallback(int fd) { + if( !Socket ) return; + if( !PassiveMode && fd != Socket->Descriptor ) return; + if( PassiveMode && fd != Socket->PassiveDescriptor ) return; + eventClose(Socket, 1); +} + +/* Added by Zaxan@Haven */ +static void eventListenCallback(int fd) +{ + int x; + + + x = socket_accept(fd, "eventReadCallback", "eventWriteCallback"); + Socket->PassiveDescriptor = x; + if(x < 0) + { + eventSocketError("Error in socket_accept().", x); + return; + } +} + +static void eventReadCallback(int fd, mixed val) { + if( functionp(Read) ) evaluate(Read, val); + else eventRead(val); +} + +static void eventRead(mixed val) { } + +static void eventWriteCallback(int fd) { + int x; + if( !Socket ){ + eventDestruct(); + return; + } + if ( !sizeof(Socket->Buffer) && Write && Socket->Blocking ){ + Socket->Buffer = ({ evaluate(Write, this_object()) }); + } + + Socket->Blocking = 0; + Socket->NoDestruct = 1; + x = EESUCCESS; + while( Socket->Buffer && x == EESUCCESS ) { + switch( x = socket_write(fd, Socket->Buffer[0]) ) { + case EESUCCESS: + if (Write ){ + mixed tmp; + + tmp = evaluate(Write, this_object()); + if ( sizeof(tmp) ){ + Socket->Buffer += ({ tmp }); + } + } + Socket->NoDestruct = 0; + break; + case EECALLBACK: + Socket->Blocking = 1; + + Socket->NoDestruct = 1; + break; + case EEWOULDBLOCK: + call_out( (: eventWriteCallback($(fd)) :), 0); + Socket->NoDestruct = 1; + return; + case EEALREADY: + Socket->Blocking = 1; + eventDestruct(); + return; + default: + eventClose(Socket); + eventSocketError("Error in socket_write().", x); + eventDestruct(); + return ; + } + if( sizeof(Socket->Buffer) == 1 ) Socket->Buffer = 0; + else Socket->Buffer = Socket->Buffer[1..]; + + } + eventWriteDestruct(); +} + +void SetOwner(object ob){ + if(Owner) return; + Owner = ob; +} + +void eventWrite(mixed val) { + object prev = previous_object(); + if(prev && prev != this_object() && prev != Owner) return; + if( !Socket ) return; + if( Socket->Buffer ) Socket->Buffer += ({ val }); + else Socket->Buffer = ({ val }); + if( Socket->Blocking ) return; + else eventWriteCallback(PassiveMode ? Socket->PassiveDescriptor : + Socket->Descriptor); +} + +varargs static int eventClose(class data_conn sock, int aborted) { + if( !sock ) return 0; + if( !aborted && socket_close(sock->Descriptor) != EESUCCESS ) { + return 0; + } + sock = 0; + if( functionp(Close) ) evaluate(Close); + else eventSocketClose(); + if( DestructOnClose ) Destruct(); + return 1; +} + + +static void eventSocketClose() { } + +int eventDestruct() { + eventClose(Socket); + return daemon::eventDestruct(); +} + +int eventWriteDestruct() { + if(Socket->NoDestruct) return 0; + return eventDestruct(); +} + +static void eventSocketError(string str, int x) { + if( LogFile ) + log_file(LogFile, ctime(time()) + " - " + str + " (" + socket_error(x) + + ")\n"); +} + diff --git a/lib/secure/lib/net/generic.c b/lib/secure/lib/net/generic.c new file mode 100644 index 0000000..54cc821 --- /dev/null +++ b/lib/secure/lib/net/generic.c @@ -0,0 +1,64 @@ +/* + * This is a sample server object. It doesn't do anything + * as-is. It simply serves as a template for you to understand + * how to build a server object of your own. + */ + +#include NETWORK_H +int port = 789; + +void StartServer(); +void StopServer(); + +void create(){ + StartServer(); +} + +void StartServer(){ + int sockstat, listsock; + + listsock = socket_create(STREAM,"read_callback","close_callback"); + if(listsock < 0){ + debug("Couldn't create socket. errorcode: "+listsock); + return; + } + + sockstat = socket_bind(listsock,port); + if(sockstat < 0){ + debug("Couldn't bind socket. errorcode: "+sockstat); + return; + } + + sockstat = socket_listen(listsock,"listen_callback"); + if(sockstat < 0){ + debug("Couldn't listen on socket. errorcode: "+sockstat); + return; + } + +} + +static void listen_callback(int fd){ + int sockstat = socket_accept(fd,"read_callback","write_callback"); + + if(sockstat < 0){ + debug("Couldn't accept on socket. errorcode: "+sockstat); + return; + } + debug("generic: listening."); +} + +static void close_callback(int fd){ + debug("I'm wanting to close fd"+fd+" now."); +} + +static void read_callback(int fd, buffer data){ + int i; + string tmp=""; + debug("fd is: "+fd); + for(i=0;i +#include +#include NETWORK_H +#include +#include +#include "include/ftp.h" + +inherit LIB_SOCKET; + +private void eventCmdPasv(string arg); + +private string Password = 0; +private static class ftp_session Session; +private static string host_ip = HOST_IP; +private static mixed outfile = ([]); +private static int MaxBuffer = get_config(__MAX_BYTE_TRANSFER__); +private static int MaxFile = get_config(__MAX_READ_FILE_SIZE__); +private static int PassivePort = -1; +private static int passive = 0; +private static mapping dispatch = ([ + "user" : (: eventCmdUser :), "pass" : (: eventCmdPass :), + "retr" : (: eventCmdRetr :), "stor" : (: eventCmdStor :), + "nlst" : (: eventCmdNlst :), "list" : (: eventCmdList :), + "cdup" : (: eventCmdCdup :), "quit" : (: eventCmdQuit :), + "type" : (: eventCmdType :), "port" : (: eventCmdPort :), + "noop" : (: eventCmdNoop :), "dele" : (: eventCmdDele :), + "syst" : (: eventCmdSyst :), "rnfr" : (: eventCmdRnfr :), + "rnto" : (: eventCmdRnto :), "stou" : (: eventCmdStou :), + "cwd" : (: eventCmdCwd :), "mkd" : (: eventCmdMkd :), + "pwd" : (: eventCmdPwd :), "rmd" : (: eventCmdRmd :), + "pasv" : (: eventCmdPasv :), "passive" : (: eventCmdPasv :) + ]); + +static void create(int fd, object owner){ + socket::create(fd, owner); + Session = new(class ftp_session); + Session->cmdPipe = owner; + Session->idleTime = 0; + if((!HOST_IP || HOST_IP == "127.0.0.1") && sizeof(query_intermud_ip())) + host_ip = query_intermud_ip(); +} + +private void eventReadFtpData(mixed text){ + switch(Session->binary){ + case 0: + text=replace_string(text, CARRIAGE_RETURN, ""); + write_file(Session->targetFile, text); + return; + case 1: + write_buffer(Session->targetFile, Session->filepos, text); + Session->filepos += sizeof(text); + return; + default: + error(sprintf("Assertion failed: \"##x\" (File: %s)\n", __FILE__)); + } +} + +private void eventDestructDataPipe(mixed f){ + if(Session->dataPipe){ + Session->dataPipe->SetClose(f); + Session->dataPipe->eventDestruct(); + } +} + +private void eventCmdPasv(string arg) +{ + + if(arg) + { + eventWrite("500 command not understood.\n",0); + return; + } + if(!passive) passive = 1; + else passive = 0; + if(Session->dataPipe) eventDestructDataPipe(0); + Session->dataPipe = new(LIB_FTP_DATA_CONN); + Session->dataPipe->SetOwner(this_object()); + Session->dataPipe->SetSocketType(Session->binary?STREAM_BINARY:STREAM); + Session->dataPipe->SetPassiveMode(1); + Session->dataPipe->eventCreateSocket(0, PassivePort); + Session->dataPipe->SetDestructOnClose(1); + Session->dataPipe->SetRead((: eventReadFtpData :)); + Session->dataPipe->SetClose((: eventWrite("226 Transfer complete.\n",0) + :)); + eventWrite(sprintf("227 Entering Passive Mode (%s,%d,%d)\n", + implode(explode(host_ip, "."), ","), PassivePort >> 8, PassivePort & 0x00FF)); + return; +} + +nomask static int check_privs(string file, string oper) { + string nom, tmp; + int x; + + if(oper == "read" && (file == "/doc" || sscanf(file,"/doc/%*s" ))){ + return 1; + } + if( !sscanf(file, REALMS_DIRS "/%s", nom) ) { + return 0; + } + if(file_privs(file) == Session->user){ + return 1; + } + if( sscanf(nom, "%s/%*s", tmp) ) { + nom = tmp; + } + nom = user_path(nom)+"adm/access"; + if( file_size(nom+".c") < 0 ) { + return 0; + } + catch(x = call_other(nom, "check_access", this_object(), "foo", + file, oper)); + return x; +} + +mixed* clean_array(mixed* r) { + int i, n; + + r = r & r; // sort. sort_array() can't hack it. And no, &= doesn't work. + + n = sizeof(r) - 1; + while (i < n) { + if (r[i] == r[i+1]) { + int j = i+1; + + while (j < n && r[i] == r[j + 1]) + j++; + + r[i..j-1] = ({}); + n -= j - i; + } + i++; + } + + return r; +} + +private string find_flags(string arg){ + string array parts; + string array flags=({}); + + parts = filter(explode(arg, " "), (: $1[0]=='-' :)); + foreach(string part in parts) flags += explode(part,""); + clean_array(flags); + return implode(flags -= ({"-"}) ,""); +} + +private string strip_flags(string arg){ + string array parts; + + parts = filter(explode(arg," "), (: $1[0] != '-' :)); + return implode(parts, " "); +} + +string FindPrevDir( string path ) { + string array parts = explode(path, "/"); + + if(sizeof(parts) == 1) return path; + parts = parts [0..<2]; + return "/" + implode(parts, "/"); +} + + +private void idle_time_out(){ + if(Session->dataPipe){ /* Data connections are still active. */ + Session->idleTime = 0; + } + else{ + Session->idleTime += 60; + if(Session->idleTime > MAX_IDLE_TIME + 60){ + eventWrite("426 Idle time too long, connection closed.\n",1); + Destruct(); + return; + } + } + call_out("idle_time_out", 60); +} + +private string GetFtpWelcomeMsg(){ + return sprintf("220- %s FTP server ready.\n%s" + "220 Please login with your creator name or anonymous.\n", + mud_name(), + file_exists(FTP_WELCOME) ? "220- " + + replace_string(read_file(FTP_WELCOME), "\n", "\n220- ") + +"\n": ""); + +} + +string GetKeyName(){ return Session->user; } + +string GetUniqueFileName(string arg){ + string array parts = explode(arg, "/"); + string path, file, sufx = ""; + int i = 0; + + if(sizeof(parts) == 1){ + path = "/"; + file = parts[0]; + } + else{ + path = "/" + implode(parts [0..<2], "/"); + file = parts [<1]; + } + if(sscanf(file, "%s.%s", file, sufx) ==2){ + sufx = "." + sufx; + } + sscanf(file, "%s~%d", file, i); + i++; + arg = absolute_path(path, sprintf("%s~%d%s", file, i, sufx)); + while( file_exists(arg) ){ + i++; + arg = absolute_path(path, sprintf("%s~%d%s", file, i, sufx)); + } + return arg; +} + +void StartService(){ + int port; + + /* Determine Port */ + + for(port=MIN_PASV_PORT;port <= MAX_PASV_PORT;port++) + if(member_array(port, FTP_PORT_TRACKER_D->QueryUsedPorts()) == -1) + break; + + if(port > MAX_PASV_PORT) + { + eventWrite("550 out of ports.\n", 0); + Destruct(); + return; + } + + PassivePort = port; + FTP_PORT_TRACKER_D->AddUsedPort(PassivePort); + + eventWrite(GetFtpWelcomeMsg(),0); + call_out("idle_time_out", 60); + +} + +void Destruct(){ + FTP_PORT_TRACKER_D->RemoveUsedPort(PassivePort); + remove_call_out("idle_time_out"); + eventDestructDataPipe(0); + ::Destruct(); +} + +private void eventCmdUser(string arg){ + if(!arg){ + eventWrite("500 command not understood.\n",0); + return; + } + arg = lower_case(arg); + if(Session->connected){ + eventWrite(sprintf("530 User %s access denied.\n", arg),0); + return; + } + Session->user = arg; +#ifdef ALLOW_ANON_FTP + if(member_array(arg, ({"anonymous", "ftp"})) != -1){ + eventWrite("331 Guest login ok, send your complete e-mail " + "address as password.\n",0); + return; + } +#endif + eventWrite(sprintf("331 Password required for %s.\n", arg),0); + return; +} + +private void eventCmdPswd(string arg){ + + if(!arg){ + eventWrite("500 command not understood.\n",0); + return; + } + if(Session->connected || !Session->user){ + eventWrite("503 Login with USER first.\n",0); + return; + } + +#ifdef ALLOW_ANON_FTP + if(member_array(arg, ({"anonymous", "ftp"})) != -1){ + eventWrite("230 guest login ok, access restrictions apply.\n",0); + Session->connected = 1; + Session->priv = 0; + Session->pwd = ANON_PREFIX; + log_file("reports/network_connect", "Anomymous login " + "(email = %s)\n", arg); + return; + } +#endif + RestoreObject(DIR_CRES "/" + Session->user[0..0] + "/" + + Session->user, 1 ); + if(!Password || Password != crypt(arg, Password) ) { + log_file("reports/network_connect", "Attempted login as %s\n", + Session->user); + eventWrite("530 Login incorrect.\n", 1); + return; + } + eventWrite(sprintf("230 User %s logged in.\n", Session->user),0); + log_file("reports/network_connect", "User %s logged in.\n",Session->user); + Session->connected = 1; + Session->priv = "" + Session->user; + Session->pwd = absolute_path(REALMS_DIRS, Session->user); + if (file_size(Session->pwd) != -2) Session->pwd = ANON_PREFIX; + return; +} + +private void eventCmdQuit(string arg){ + eventWrite("221 Goodbye.\n", 1); +} + +string RetrieveCmdCallback(object ob){ + int start,length; + mixed ret; + + if (!ob || undefinedp(outfile[ob])) return 0; + + start = outfile[ob][2]; + length = MaxBuffer; + outfile[ob][2] += length; + + if (start + length > outfile[ob][4]) + length = outfile[ob][4] - start; + + ret = read_buffer(outfile[ob][0], start, length); + if (outfile[ob][2] >= outfile[ob][4]) { + map_delete(outfile, ob); + } + return ret; +} + +private void eventCmdPort(string arg){ + string ip, *parts; + int port; + + if(!arg){ + eventWrite("500 command not understood.\n",0); + return; + } + parts = explode(arg, ","); + if(sizeof(parts) != 6){ + eventWrite("550 Failed command.\n",0); + return; + } + ip = implode(parts[0..3],"."); + port = (to_int(parts[4]) << 8) + to_int(parts[5]); + if(Session->dataPipe) eventDestructDataPipe(0); + Session->dataPipe = new(LIB_FTP_DATA_CONN); + Session->dataPipe->SetSocketType(Session->binary?STREAM_BINARY:STREAM); + Session->dataPipe->eventCreateSocket(ip, port); + Session->dataPipe->SetDestructOnClose(1); + Session->dataPipe->SetRead((:eventReadFtpData:)); + Session->dataPipe->SetClose((:eventWrite("226 Transfer complete.\n",0):)); + eventWrite("200 PORT command successful.\n",0); + return; +} + +private void do_list( string arg, int ltype){ + string array files; + string flags; + string output; + + if(arg){ + flags = find_flags(arg); + arg = strip_flags(arg); + } + + if(!arg || arg == "") arg = "."; + /* This hack added by Tigran because things like /secure/master.c/. + * evaluate and cause havoc w/ ftp clients like efs for Xemacs and + * ange-ftp for Emacs. Besides it shouldn't happen anyways */ + if(arg[<2..]=="/." && file_exists(arg[0..<3]) ){ + eventWrite(sprintf("550 %s: No such file OR directory.\n",arg),0); + eventDestructDataPipe(0); + return; + } + arg = absolute_path(Session->pwd, arg); + +#ifdef ALLOW_ANON_FTP + if(member_array(Session->user, ({"anonymous", "ftp"})) != -1 + && arg[0..(strlen(ANON_PREFIX)-1)] != ANON_PREFIX) { + eventDestructDataPipe((:eventWrite("550 Pemission denied.\n",0):); + return; + } +#endif + if(file_size(arg) == -2) { + arg = (arg[<1] != '/')? arg+"/"+"*":arg+"*"; + } + if(file_size(FindPrevDir(arg)) == -1){ + eventWrite(sprintf("550 %s: No such file OR directory.\n", arg),0); + eventDestructDataPipe(0); + return; + } + if(!(files = get_dir(arg, -1))){ + eventWrite(sprintf("550 %s: Permission denied.\n",arg),0); + eventDestructDataPipe(0); + return; + } + if(flags){ + if(strsrch(flags,'a') == -1) + files = filter(files, (: member_array($1[0], ({".",".."})) == -1 :)); + } + if(!sizeof(files)){ + eventWrite("550 No files found.\n",0); + eventDestructDataPipe(0); + return; + } + + /* in case of LIST imply -l */ + /* in case of NLST imply -1 */ + if (ltype == LTYPE_LIST){ + if (flags){ + if ( (strsrch(flags, 'l') == -1) && + (strsrch(flags, 'C') == -1) && + (strsrch(flags, '1') == -1) ) + flags += "l"; + } + else + flags = "l"; + } + else{ + if (flags){ + if ( (strsrch(flags, 'l') == -1) && + (strsrch(flags, 'C') == -1) && + (strsrch(flags, '1') == -1) ) + flags += "1"; + } + else flags = "1"; + } + if(strsrch(flags,'F') > -1){ + foreach(mixed array file in files) + if(file[1]==-2) file[0]=sprintf("%s/",file[0]); + } + if(strsrch(flags,'C')>-1){ + int lines; + int size; + int i; + + if((strsrch(flags,'l') > -1 ) || (strsrch(flags,'1') > -1)){ + eventWrite("550: LIST -C flag is incompatible with -1 or -l.\n",0); + eventDestructDataPipe(0); + return; + } + lines=((size = sizeof(files)) / 3 ) + 1; + output=""; + for(i=0;i -1){ + if(strsrch(flags,'1')>-1){ + eventWrite("550: LIST -l and -1 flags incompatible.\n",0); + eventDestructDataPipe(0); + return; + } + output = implode(map(files, + (:sprintf("%s %3i %=9s %=8s %=7s %s%5s %s", + $1[1]==-2?"drwxrwxr-x":"-rw-rw-r--", + 1, + lower_case(replace_string(mud_name(), " ", "_"))[0..7], + lower_case(replace_string(mud_name(), " ", "_"))[0..7], + $1[1]==-2?"0":sprintf("%d",$1[1]), + ctime($1[2])[4..10], + (time()-$1[2])>31536000?ctime($1[2])[20..]:ctime($1[2])[11..15], + $1[0]) :)),"\n"); + } + if(strsrch(flags,'1') > -1) + output=implode(map(files,(:sprintf("%s",$1[0]) :)),"\n"); + eventWrite("150 Opening ASCII mode data connection for file list."+CARRIAGE_RETURN+"\n",0); + Session->dataPipe->eventWrite(implode(explode(output,"\n"), CARRIAGE_RETURN+"\n")+CARRIAGE_RETURN+"\n"); + return; +} + +private void eventCmdList(string arg){ + if(!check_privs(absolute_path(Session->pwd, arg), "read")){ + eventDestructDataPipe((:eventWrite("550 Pemission denied.\n",0):)); + return; + } + do_list(arg, LTYPE_LIST); +} + +private void eventCmdNlst(string arg){ + if(!check_privs(absolute_path(Session->pwd, arg), "read")){ + eventDestructDataPipe((:eventWrite("550 Pemission denied.\n",0):)); + return; + } + do_list(arg, LTYPE_NLST); +} + +private void eventCmdRetr(string arg){ + string target_file; + int i; + + if(!arg){ + eventDestructDataPipe((:eventWrite("500 command not understood.\n",0):)); + return; + } + target_file = absolute_path(Session->pwd, arg); + if(member_array(Session->user, ({"anonymous", "ftp"})) != -1 + && target_file[0..(strlen(ANON_PREFIX)-1)] != ANON_PREFIX) { + eventDestructDataPipe((:eventWrite("550 Pemission denied.\n",0):)); + return; + } + i = file_size(target_file); + switch(i){ + case -2: + eventWrite(sprintf("550 %s: Can't retrieve (it's a directory).\n", + target_file),0); + eventDestructDataPipe(0); + return; + case -1: + eventWrite(sprintf("550 %s: No such file OR directory.\n", + target_file),0); + eventDestructDataPipe(0); + return; + case 0: + eventWrite(sprintf("550 %s: File contains nothing.\n", + target_file),0); + eventDestructDataPipe(0); + return; + default: + if(i > MaxFile){ + eventWrite(sprintf("550 %s: File size too large.\n", + target_file),0); + eventDestructDataPipe(0); + return; + } + } + if(!check_privs(target_file, "read")){ + eventDestructDataPipe((:eventWrite("550 Pemission denied.\n",0):)); + return; + } + switch(Session->binary){ + case 0: + outfile[Session->dataPipe]=({target_file,0,0,Session->cmdPipe, i}); + eventWrite(sprintf("150 Opening ascii mode data connection for " + "%s (%d bytes).\n", target_file, i),0); + Session->dataPipe->SetWrite((: RetrieveCmdCallback :)); + + Session->dataPipe->eventWrite(RetrieveCmdCallback(Session->dataPipe)); + break; + case 1: + outfile[Session->dataPipe]=({target_file,1,0,Session->cmdPipe, i}); + eventWrite(sprintf("150 Opening binary mode data connection " + "for %s (%d bytes).\n", target_file, i),0); + Session->dataPipe->SetWrite((: RetrieveCmdCallback :)); + + Session->dataPipe->eventWrite(RetrieveCmdCallback(Session->dataPipe)); + break; + default: + error(sprintf("Assertion failed: \"##x\" (File: %s)\n", __FILE__)); + } +} + +void eventCmdPwd(string arg){ + eventWrite(sprintf("257 \"%s\" is current directory.\n", Session->pwd),0); +} + +void eventCmdNoop(string arg){ + eventWrite("221 NOOP command successful.\n",0); +} + +private void eventCmdStor(string arg){ + if(!arg){ + eventDestructDataPipe((:eventWrite("500 command not understood.\n",0):)); + return; + } + arg = absolute_path(Session->pwd, arg); +#ifndef ANON_CAN_PUT + if(member_array(Session->user, ({"anonymous", "ftp"})) != -1){ + eventDestructDataPipe((:eventWrite, "550 Pemission denied.\n", 0:)); + return; + } +#else + if(member_array(Session->user, ({"anonymous", "ftp"})) != -1 + && arg[0..(strlen(ANON_PREFIX)-1)] != ANON_PREFIX) { + eventDestructDataPipe((:eventWrite, "550 Pemission denied.\n", 0:)); + return; + } +#endif + if(file_size(FindPrevDir(arg)) != -2 ){ + eventDestructDataPipe((:eventWrite, + "553 No such directory to store into.\n", 0:)); + return; + } + if(!check_privs(arg, "write")){ + eventDestructDataPipe((:eventWrite("550 Pemission denied.\n",0):)); + return; + } + Session->targetFile = arg; + if( file_exists(arg) ){ + if( !rm( arg ) ){ + eventWrite(sprintf("550 %s: Permission denied.\n", arg),0); + eventDestructDataPipe(0); + return; + } + } + else if(!write_file( arg, "") ){ + eventWrite(sprintf("550 %s: Permission denied.\n", arg),0); + eventDestructDataPipe(0); + return; + } + Session->filepos = 0; + eventWrite(sprintf("150 Opening %s mode data connection for %s.\n", + Session->binary ? "binary" : "ascii", arg),0); +} + +private void eventCmdStou(string arg){ + if(!arg){ + eventDestructDataPipe((:eventWrite("500 command not understood.\n",0):)); + return; + } + arg = absolute_path(Session->pwd, arg); +#ifndef ANON_CAN_PUT + if(member_array(Session->user, ({"anonymous", "ftp"})) != -1){ + eventDestructDataPipe((:eventWrite, "550 Pemission denied.\n", 0:)); + return; + } +#else + if(member_array(Session->user, ({"anonymous", "ftp"})) != -1 + && arg[0..(strlen(ANON_PREFIX)-1)] != ANON_PREFIX) { + eventDestructDataPipe((:eventWrite, "550 Pemission denied.\n", 0:)); + return; + } +#endif + if(file_size(FindPrevDir(arg)) != -2 ){ + eventDestructDataPipe((:eventWrite, + "553 No such directory to store into.\n", 0:)); + return; + } + if(!check_privs(arg, "write")){ + eventDestructDataPipe((:eventWrite("550 Pemission denied.\n",0):)); + return; + } + if( file_exists(arg)){ + arg = GetUniqueFileName(arg); + } + Session->targetFile = arg; + if(!write_file( arg, "") ){ + eventWrite(sprintf("550 %s: Permission denied.\n", arg),0); + eventDestructDataPipe(0); + return; + } + Session->filepos = 0; + eventWrite(sprintf("150 Opening %s mode data connection for %s.\n", + Session->binary ? "binary" : "ascii", arg),0); +} + +private void eventCmdCwd(string arg){ + string newpath; + if(!arg){ + eventWrite("500 command not understood.\n",0); + return; + } + newpath = absolute_path(Session->pwd, arg); + if(member_array(Session->user, ({"anonymous", "ftp"})) != -1 + && newpath[0..(strlen(ANON_PREFIX)-1)] != ANON_PREFIX) { + eventWrite("550 Pemission denied.\n",0); + return; + } + if(!check_privs(newpath, "read")){ + eventWrite("550 Pemission denied.\n",0); + return; + } + if( file_size(newpath) != -2 ){ + eventWrite(sprintf("550 %s: No such directory.\n", newpath),0); + return; + } + Session->pwd = newpath; + eventWrite("250 CWD command successful.\n",0); +} + +private void eventCmdCdup(string arg){ eventCmdCwd(".."); } + +private void eventCmdMkd(string arg){ + if(!arg){ + eventWrite("500 command not understood.\n",0); + return; + } + arg = absolute_path(Session->pwd, arg); +#ifndef ANON_CAN_PUT + if(member_array(Session->user, ({"anonymous", "ftp"})) != -1){ + eventWrite("550 Permission denied.\n",0); + return; + } +#else + if(member_array(Session->user, ({"anonymous", "ftp"})) != -1 + && arg[0..(strlen(ANON_PREFIX)-1)] != ANON_PREFIX) { + eventWrite("550 Pemission denied.\n",0); + return; + } +#endif + if( file_size(FindPrevDir(arg)) != -2 ){ + eventWrite(sprintf("550 %s: No such directory.\n", + FindPrevDir(arg)),0); + return; + } + if(unguarded((:file_size($(arg)):)) != -1){ + eventWrite(sprintf("550 %s: File exists.\n", arg),0); + return; + } + if(!check_privs(arg, "write")){ + eventWrite("550 Pemission denied.\n",0); + return; + } + if( !mkdir(arg) ){ + eventWrite(sprintf("550 %s: Permission denied.\n", arg),0); + return; + } + eventWrite("257 MKD command successful.\n",0); + return; +} + +private void eventCmdType(string arg){ + if(!arg){ + eventWrite("500 command not understood.\n",0); + return; + } + arg = lower_case(arg); + switch(arg){ + case "a": + Session->binary = 0; + eventWrite("200 Type set to A.\n",0); + return; + case "i": + Session->binary = 1; + eventWrite("200 Type set to I.\n",0); + return; + default: + eventWrite("550 Unknown file type.\n",0); + return; + } +} + +private void eventCmdDele(string arg){ + if(!arg){ + eventWrite("500 command not understood.\n",0); + return; + } + arg = absolute_path( Session->pwd, arg); + if(member_array(Session->user, ({"anonymous", "ftp"})) != -1 + && arg[0..(strlen(ANON_PREFIX)-1)] != ANON_PREFIX) { + eventWrite("550 Pemission denied.\n",0); + return; + } + if( !file_exists(arg) ){ + eventWrite(sprintf("550 %s: No such file OR directory.\n", arg),0); + return; + } + if(!check_privs(arg, "write")){ + eventWrite("550 Pemission denied.\n",0); + return; + } + if( !rm(arg) ){ + eventWrite(sprintf("550 %s: Permission denied.\n",arg),0); + return; + } + eventWrite("250 DELE command successful.\n",0); +} + +private void eventCmdSyst(string arg) { + eventWrite("215 UNIX Mud Name: "+mud_name()+"\n",0); +} + +private void eventCmdRnfr(string arg) { + if(!arg){ + eventWrite("500 command not understood.\n",0); + return; + } + arg = absolute_path( Session->pwd, arg); + if(member_array(Session->user, ({"anonymous", "ftp"})) != -1 + && arg[0..(strlen(ANON_PREFIX)-1)] != ANON_PREFIX) { + eventWrite("550 Pemission denied.\n",0); + return; + } + if( !file_exists(arg) ){ + eventWrite(sprintf("550 %s: No such file OR directory.\n", arg),0); + return; + } + if(!check_privs(arg, "write")){ + eventWrite("550 Pemission denied.\n",0); + return; + } + Session->renamefrom = arg; + eventWrite("350 Input new name for " + arg + ".\n",0); +} + +private void eventCmdRnto(string arg) { + if(!arg){ + eventWrite("500 command not understood.\n",0); + return; + } + arg = absolute_path( Session->pwd, arg); + if(member_array(Session->user, ({"anonymous", "ftp"})) != -1 + && arg[0..(strlen(ANON_PREFIX)-1)] != ANON_PREFIX) { + eventWrite("550 Pemission denied.\n",0); + return; + } + if( !Session->renamefrom ){ + eventWrite(sprintf("550 You must first specify a file to rename.\n", + arg),0); + return; + } + if( !file_exists(Session->renamefrom) ){ + eventWrite(sprintf("550 %s: No such file OR directory.\n", arg),0); + Session->renamefrom = 0; + return; + } + if(!check_privs(Session->renamefrom, "write")){ + eventWrite("550 Pemission denied.\n",0); + Session->renamefrom = 0; + return; + } + if(!check_privs(FindPrevDir(arg), "write")){ + eventWrite("550 Pemission denied.\n",0); + Session->renamefrom = 0; + return; + } + if(rename(Session->renamefrom, arg)){ + eventWrite(sprintf("553 %s: Invalid desitination name.\n", arg),0); + } + eventWrite(sprintf("250 RNTO %s --> %s.\n", Session->renamefrom, arg),0); + Session->renamefrom = 0; +} + +private void eventCmdRmd(string arg) { + if(!arg){ + eventWrite("500 command not understood.\n",0); + return; + } + arg = absolute_path( Session->pwd, arg); + if(member_array(Session->user, ({"anonymous", "ftp"})) != -1 + && arg[0..(strlen(ANON_PREFIX)-1)] != ANON_PREFIX) { + eventWrite("550 Pemission denied.\n",0); + return; + } + if( file_size(arg) != -2 ){ + eventWrite(sprintf("550 %s: No such file OR directory.\n", arg),0); + return; + } + if(!check_privs(arg, "write")){ + eventWrite("550 Pemission denied.\n",0); + return; + } + if( !rmdir(arg) ){ + eventWrite(sprintf("550 %s: Directory not empty.\n",arg),0); + return; + } + eventWrite("250 RMD command successful.\n",0); +} + +void eventRead(string data){ + string cmd, arg; + function dispatchTo; + int i; + + if (!(Session->command)) Session->command = ""; + + data = replace_string(data, CARRIAGE_RETURN, ""); + Session->command += data; + if ((i = strsrch(Session->command, "\n")) == -1) return; + data=Session->command[0..i-1]; + Session->command=Session->command[i+1..]; + Session->command = trim(Session->command); + if (!sscanf(data, "%s %s", cmd, arg)) cmd = data; + cmd = lower_case(cmd); + + if (!Session->connected){ + switch(cmd){ + case "user": + eventCmdUser(arg); + return; + case "pass": + eventCmdPswd(arg); + return; + case "quit": + eventCmdQuit(arg); + return; + case "noop": + eventCmdNoop(arg); + return; + default: + eventWrite("503 Log in with USER first.\n",0); + return; + } + } + Session->idleTime = 0; + dispatchTo = dispatch[cmd]; + if (!dispatchTo){ + log_file("reports/network_error", + sprintf("ftp - unknown command: %s\n",cmd)); + eventWrite(sprintf("502 Unknown command %s.\n", cmd),0); + return; + } + if(catch(evaluate(dispatchTo, arg))){ + eventWrite("550 Unknown failure. Please report what you were doing " + "to the mud admin.\n",0); + } + return; +} diff --git a/lib/secure/lib/net/http.c b/lib/secure/lib/net/http.c new file mode 100644 index 0000000..f6bb48a --- /dev/null +++ b/lib/secure/lib/net/http.c @@ -0,0 +1,413 @@ +/* /daemon/http.c + * From the Dead Souls LPC Library + * An http socket for the WWW (based on the Dead Souls http daemon) + * Created by Descartes of Borg 950429 + * Version: @(#) http.c 1.1@(#) + * Last modified: 96/12/19 + */ + +/* Note on how this works: + * On Dead Souls, this http program is in fact not so much a "daemon" + * as an "applet". The inet daemon starts a server program that + * watches the http port. When a request comes in, that server program + * fires up a *clone* of this here file. Therefore, you will not see + * multiple-connection handling here. This http applet services a + * single connection, and dies happy when its job is done. + * + * The CGI stuff is basically just sending the post and get requests to + * LPC objects in the cgi/ directory. The key thing to remember if you're + * going to play around here is that this object closes and dies on write. So + * if you're going to receive post data in multiple chunks (as is common) + * you will want to ensure it is either queued here until sent to the + * cgi object, or that the cgi object somehow prevents this object from + * writing its data to the client til all chunks are received and processed. + * + * -Crat 09Feb2008 + */ + +#include +#include +#include +#include + +#define FILE_BAD_CMD DIR_WWW_ERRORS "/badcmd.html" +#define FILE_BAD_GATE DIR_WWW_ERRORS "/badgate.html" +#define FILE_NOT_FOUND DIR_WWW_ERRORS "/notfound.html" +#define ACCESS_DENIED DIR_WWW_ERRORS "/denied.html" +#define DIRECTORY_LISTINGS + +#ifndef ENABLE_CGI +#define ENABLE_CGI 1 +#endif +#ifndef WWW_DIR_LIST +#define WWW_DIR_LIST 1 +#endif + +#define TAB "    " + +inherit LIB_SOCKET; + +string ip = ""; +string out = ""; +string host; +int port; +mapping Cookie = ([]); +string gateway, login_data, current_page, boundary, cookie, cmd, read_args, filename, user_agent; +int ok_to_send, boundary_count; +int logging = 1; + +void validate(){ + if(!master()->valid_apply(({ "SECURE", "ASSIST" })) && + strsrch(base_name(previous_object()), DIR_WWW_GATEWAYS)){ + string offender = identify(previous_object(-1)); + debug("HTTPD SECURITY VIOLATION: "+offender+" ",get_stack(),"red"); + log_file("/secure/security", "\n"+timestamp()+" HTTPD breach: "+offender+" "+get_stack()); + error("HTTPD SECURITY VIOLATION: "+offender+" "+get_stack()); + } +} + +varargs buffer MakeHeader(int len){ + int i; + string h = ""; + buffer ret; + h += "HTTP/1.0 200 OK\nContent-Type: text/html\r\n\r\n"; + ret = allocate_buffer(strlen(h)); + for(i=0; iGetShibboleth(Cookie["name"]) == Cookie["shib"]){ + return 1; + } + } + } + return 0; +} + +string GetReferer(){ + return current_page; +} + +string GetBoundary(){ + return boundary; +} + +mapping GetCookie(){ + validate(); + return copy(Cookie); +} + +string GetHost(){ + return host; +} + +int GetPort(){ + return port; +} + +private static void eventError(string name) { + object file = new(LIB_FILE, name); + + eventWrite(file->GetBuffer(), 1); +} + +void eventBlockIp(){ + if(!strsrch(base_name(previous_object()), DIR_WWW_GATEWAYS) ){ + INET_D->eventBlockIp(ip); + } +} + +string GetIp(){ + return ip; +} + +mixed GenerateIndex(string dir, string requested){ + string ret = "\n"; + string prefix = ""; + mixed *listing; + if(!dir || !directory_exists(dir)) return 0; + listing = get_dir(dir+"/"); + if(!strsrch(dir,DIR_WWW)) dir = replace_string(dir,DIR_WWW,"",1); + prefix = path_prefix(requested); + if(!sizeof(prefix)) prefix = "/"; + if(WEB_SESSIONS_D->GetSession(Cookie["name"])){ + if(authenticate(dir) && requested[1..1] != "~"){ + ret += "
"; + ret += "Upload file (text files only): "; + ret += "
"; + ret += "
Create a folder
"; + ret += "
Create a file
"; + } + } + ret += "Parent Directory \n"; + ret +="

\n"; + foreach(string sub in listing){ + string ed_req = "Edit"; + ret +=""+sub+(directory_exists(dir+"/"+sub) ? "/" : "")+""; + ret += (directory_exists(dir+"/"+sub) ? "" : TAB + ed_req); + ret += "
\n"; + } + ret +=""; + ret = replace_string(ret,"//","/"); + return ret; +} + +void eventRemoveTmp(string file){ + rm(file); +} + +varargs private static mixed eventGetFile(string name, string type, string payload) { + string array parts; + string tmpfile, orig, requested; + object file; + + name = explode(name, " ")[0]; + if( name[0] != '/' ) { + name = "/" + name; + } + requested = name; + parts = explode(name = absolute_path("/", name), "/"); + if( !sizeof(parts) ) { + name = DIR_WWW "/index.html"; + } + else if( parts[0][0] == '~' ) { + parts[0] = user_path(parts[0][1..]) + "/public_html"; + name = implode(parts, "/"); + } + + if(name == REALMS_DIRS || name == REALMS_DIRS +"/") name = DIR_WWW + "/index.html"; + + if( strsrch(name, DIR_WWW) && strsrch(name, REALMS_DIRS) ) { + name = DIR_WWW + name; + } + if(!strsrch(name,REALMS_DIRS) && !grepp(name,"/public_html") ){ + if(!authenticate(name)) eventError(FILE_NOT_FOUND); + } + orig = name; + file = new(LIB_FILE, name); + if( file->isDirectory() ) { + file = new(LIB_FILE, name = name + "/index.html"); + } + if( ENABLE_CGI && !strsrch(name, DIR_WWW_GATEWAYS) ) { + string id, args, str, foo; + buffer b; + + if( sscanf(name, DIR_WWW_GATEWAYS "/%s?%s", id, args) != 2 ) { + args = 0; + sscanf(name, DIR_WWW_GATEWAYS "/%s", id); + } + if( sscanf(id, "%s.%s", foo, str) == 2 ) { + id = foo+".c"; + } + if(payload) args = payload; + if( catch(str = (DIR_WWW_GATEWAYS "/"+id)->gateway(args)) ) { + eventError(FILE_BAD_GATE); + return 1; + } + eventSendData(str); + return 1; + } + else if( WWW_DIR_LIST && !file->isFile() ) { + mixed ret = GenerateIndex(orig, requested); + tmpfile = "/secure/tmp/webtemp.html"; + if(ret){ + write_file(tmpfile, ret,1); + file = new(LIB_FILE, tmpfile); + eventSendData(file->GetBuffer()); + } + else { + eventError(FILE_NOT_FOUND); + return 1; + } + } + else if( !WWW_DIR_LIST && !file->isFile() ) { + eventError(FILE_NOT_FOUND); + return 1; + } + else { + eventSendData(file->GetBuffer()); + } +} + +int eventRead(buffer data) { + string *args_tmp, *posted_file; + string browser, *sock_stat; + string str = read_buffer(data); + int argsize, i, j; + buffer b; + + if(!Cookie || !sizeof(Cookie)){ + Cookie = ([]); + Cookie["name"] = 0; + Cookie["shib"] = 0; + } + + ip = socket_ip(socket::GetDescriptor()); + + if(member_array(ip,INET_D->GetBlockedIps()) != -1){ + eventError(ACCESS_DENIED); + return 1; + } + + if( !socket::eventRead(str) ) { + return 0; + } + if( !str || str == "" ) { + eventError(FILE_BAD_CMD); + return 1; + } + if(!read_args) read_args = explode(replace_string(str, CARRIAGE_RETURN, ""), "\n")[0]; + args_tmp = explode(replace_string(str, CARRIAGE_RETURN, ""), "\n"); + foreach(mixed element in args_tmp){ + int int1, int2; + string junk1, junk2; + junk2 = reverse_string(element); + int2 = sscanf(junk2,"%s---%*s",junk1); + if(!strsrch(element,"Cookie:") && !cookie) cookie = element; + if(!strsrch(element,"Host:") && !host){ + if(sscanf(element,"Host: %s:%s",junk1, junk2) != 2){ + sscanf(element,"Host: %s",junk1); + port = 80; + } + else port = atoi(junk2); + host = junk1; + } + if(boundary && grepp(element,boundary)){ + boundary_count++; + } + else if(boundary && int2 == 2){ + junk2 = reverse_string(junk1); + junk1 = replace_string(boundary,"-",""); + if(boundary && sizeof(junk2) > 5 + && first(junk1,sizeof(junk2)) == junk2){ + boundary_count++; + } + } + + if(grepp(element, "boundary=")){ + sscanf(element,"%sboundary=%s",junk1,boundary); + args_tmp -= ({ element }); + } + if(!strsrch(element, "Referer:") && !current_page){ + sscanf(element,"Referer: %s",current_page); + } + if(!strsrch(element, "User-Agent:") && !user_agent){ + sscanf(element,"User-Agent: %s",user_agent); + } + if(!strsrch(element, "Content-Disposition: form-data;") && !filename){ + if(sscanf(element,"%sfilename=\"%s\"",junk1, filename) != 2) + sscanf(element,"%sfilename=\"%s\"%s",junk1, filename, junk2); + if(filename && filename[1..2]==":\\"){ + filename=last_string_element(filename,"\\"); + } + } + if(!strsrch(element, "username=") && !login_data){ + login_data = element; + } + } + + out += implode(args_tmp,"\n"); + if(cookie){ + string name, shib, junk1, junk2; + if(sscanf(cookie,"%screweb=%s.%s;%s",junk1,name,shib,junk2) == 4 || + sscanf(cookie,"%screweb=%s.%s",junk1,name,shib) == 3){ + Cookie["name"] = name; + Cookie["shib"] = shib; + } + } + if(!cmd) sscanf(read_args, "%s %s", cmd, read_args); + if(!read_args) sscanf(read_args, "%s %s", cmd, read_args); + eventLogConnection(); + switch(lower_case(cmd)) { + string junk; + case "get": + eventGetFile(read_args); + return 1; + + case "post": + if(!ENABLE_CGI){ + eventError(FILE_BAD_CMD); + return 1; + } + if(!gateway) sscanf(read_args,"%s HTTP%s",gateway,junk); + + if(boundary_count && boundary_count > 1){ + string junk1, junk2, tmp; +#if 0 + if(sscanf(out,"%s"+boundary+"%s--"+boundary+"%s",junk1,tmp,junk2) == 3){ + out = tmp; + args_tmp=explode(out,"\n"); + if(filename) out = implode(args_tmp[2..],"\n"); + else out = implode(args_tmp[1..],"\n"); + } +#endif + sscanf(out,"%s--%s",tmp,junk1); + if(grepp(out,boundary+"--")) eventGetFile(read_args, "POST", out); + return 1; + +#if 0 + if(!filename){ + if( catch(str = ((DIR_WWW_GATEWAYS +"/save")->gateway(out)) ) ){ + eventError(FILE_BAD_GATE); + return 1; + } + } + else if( catch(str = ((DIR_WWW_GATEWAYS +"/upload")->gateway(out, current_page, filename, + Cookie["name"], Cookie["shib"]))) ) { + eventError(FILE_BAD_GATE); + return 1; + } + str = strip_colours(str); + b = allocate_buffer(strlen(str)); + for(j=0; j +#include +#include +#include NETWORK_H +#include + +inherit LIB_SOCKET; +inherit LIB_CLIENT; + +string *file_chunks = ({}); +string file = ""; +mapping FilesMap = ([]); +string mud,whoami; +mixed globalvar; +int global_lock = 0; +string mcolor = "magenta"; +int client = 0; +int counter = 0; +string *forbidden_prefixes = ({ "/secure/save/players", "/secure/save/creators" }); +string *forbidden_suffixes = ({ ".o" }); +string *forbidden_files = ({ "/secure/sefun/native_version.c" }); +mixed *begin_packet = ({}); +mapping TranslatedFiles = ([]); + +int eventDumpFiles(); + +static private void validate() { + if( !(master()->valid_apply(({ "SECURE" }))) ) + error("Illegal attempt to access LIB_OOB: "+get_stack()+" "+identify(previous_object(-1))); +} + +void eventID(string str){ + //add security stuff here + mud = str; +} + +static void create(mixed alpha, mixed beta, mixed gamma, mixed delta){ + trr("LIB_OOB.create: I am a new OOB object, name: "+file_name(),mcolor,MSG_OOB); + set_heart_beat(1); + if(clonep()){ + if(intp(alpha)){ + socket::create(alpha, beta); + } + + else if(beta && intp(beta)){ + client = 1; + begin_packet = ({ "oob-begin", mud_name(), 1, beta }); + if( eventCreateSocket(alpha, gamma) < 0 ){ + trr("LIB_OOB.create: Couldn't create outbound socket.",mcolor,MSG_OOB); + client::eventDestruct(); + return; + } + else { + trr("LIB_OOB.create: Apparently I opened an outbound socket.",mcolor,MSG_OOB); + client::eventWrite( begin_packet ); + if( delta && arrayp(delta)) { + globalvar = delta; + trr("payload type: "+identify(globalvar[0]),"white",MSG_OOB); + } + else { + trr("no payload","white",MSG_OOB); + } + } + } + } + if(client) { + whoami = "CLIENT"; + trr("LIB_OOB "+file_name()+": I think I am a " + "%^YELLOW%^%^BOLD%^client%^RESET%^",mcolor,MSG_OOB); + } + else { + whoami = "SOCKET"; + trr("LIB_OOB "+file_name()+": I think I am a " + "%^CYAN%^%^BOLD%^server%^RESET%^",mcolor,MSG_OOB); + } +} + +void heart_beat(){ + //if nothing resets the counter for 10 minutes, we die + counter++; + if(counter == 600){ + if(client) client::eventDestruct(); + else { + socket_close(this_object()->GetDescriptor()); + eventDestruct(); + } + } + if(counter == 601){ + socket::eventDestruct(); + socket_close(this_object()->GetDescriptor()); + eventCloseSocket(); + } + if(counter == 602){ + destruct(); + socket_close(this_object()->GetDescriptor()); + eventSocketClosed(); + } +} + +int eventRead(mixed data) { + mixed tmp = 0; + string liblevel = ""; + string mud = OOB_D->FindMud(this_object()); + validate(); + if(sizeof(mud) && (tmp = INTERMUD_D->GetMudList()[mud])){ + if(sscanf(INTERMUD_D->GetMudList()[mud][5],"Dead Souls %s",liblevel) != 1) + liblevel = tmp[5]; + } + trr("--\nOOB "+whoami+" READ i am: "+identify(this_object()),mcolor,MSG_OOB); + trr("OOB "+whoami+" READ i read: "+identify(data)+"\n--",mcolor,MSG_OOB); + //every time we read something, the inactivity counter resets + counter = 0; + if(data[0] == "oob-begin"){ + socket::eventWrite( ({ "oob-reply","Welcome to the OOB service on "+mud_name() })); + OOB_D->RequestToken(data[1]); + OOB_D->RegisterNewIncoming(data[1]); + } + + if(data[0] == "oob-end"){ + if(sizeof(FilesMap)) eventDumpFiles(); + OOB_D->RemoveIncoming( OOB_D->FindMud(this_object()) ); + if(client) this_object()->eventDestruct(); + else socket::eventCloseSocket(); + } + + if((data[0] == "oob-file-end" || data[0] == "oob-reply" || data[0] == "oob-file-error") + && globalvar && arrayp(globalvar)){ + if(globalvar[0] == "oob-file-req"){ + if(stringp(globalvar[1])) { + client::eventWrite(globalvar); + globalvar = ({ "oob-file-req", 0 }); + } + else if(sizeof(globalvar[1])){ + client::eventWrite(({"oob-file-req", globalvar[1][0] })); + globalvar[1] -= ({ globalvar[1][0] }); + } + else { + if(sizeof(FilesMap)) eventDumpFiles(); + OOB_D->RemoveIncoming( OOB_D->FindMud(this_object()) ); + if(client) this_object()->eventDestruct(); + else socket::eventCloseSocket(); + } + } + else { + client::eventWrite(globalvar); + } + } + + if(data[0] == "oob-test"){ + socket::eventWrite( ({ "oob-reply","This is a test" })); + } + + if(data[0] == "oob-file"){ + if(!OOB_D->AuthenticateFile(OOB_D->FindMud(this_object()), data[1])){ + client::eventWrite( ({ "oob-file-error","CLIENT I have not asked for this file from you." }) ); + socket::eventWrite( ({ "oob-file-error","SOCKET I have not asked for this file from you." }) ); + return 0; + } + if(!FilesMap[data[1]]) FilesMap[data[1]] = ([]); + if(data[3]) FilesMap[data[1]][data[2]] = data[3]; + } + + if(data[0] == "oob-file-req"){ + string *ok_files = explode(read_file("/secure/upgrades/txt/upgrades.txt"),"\n"); + string sendfile; + + if(file_exists("/secure/upgrades/txt/upgrades."+liblevel)){ + ok_files = explode(read_file("/secure/upgrades/txt/upgrades."+liblevel),"\n"); + if(data[1] == "/secure/upgrades/txt/upgrades.txt") + sendfile = "/secure/upgrades/txt/upgrades."+liblevel; + else sendfile = data[1]; + ok_files += ({ "/secure/upgrades/txt/upgrades."+liblevel }); + ok_files += ({ "/secure/upgrades/txt/mud_info."+liblevel }); + } + else { + sendfile = data[1]; + ok_files += ({ "/secure/upgrades/txt/upgrades.txt" }); + } + if(sendfile == "/secure/sefun/mud_info.c"){ + if(file_exists("/secure/upgrades/txt/mud_info."+liblevel)) + sendfile = "/secure/upgrades/txt/mud_info."+liblevel; + } + if(member_array(sendfile,ok_files) == -1 ){ + socket::eventWrite( ({ "oob-file-error","File access denied." }) ); + return 0; + } + if(directory_exists(sendfile)){ + socket::eventWrite( ({ "oob-file-error","That's a directory.",sendfile}) ); + return 0; + } + if(!OOB_D->AuthenticateReceivedToken(OOB_D->FindMud(this_object()))){ + socket::eventWrite( ({ "oob-file-error","No token found for your mud." }) ); + return 0; + } + OOB_D->send_file(sendfile,this_object()); + if(liblevel == "2.3a5") + socket::eventWrite(({"oob-end", "oob-file send complete." }) ); + else socket::eventWrite(({"oob-file-end", "oob-file send complete." }) ); + } + + if(data[0] == "oob-file-error"){ + if(data[1] == "No token found for your mud."){ + call_out( (: eventWrite(begin_packet) :), 2); + trr(file_name()+": No auth token yet. Retrying in 2 seconds.",mcolor,MSG_OOB); + } + if(data[1] == "That's a directory."){ + mkdir(data[2]); + if(mudlib_version() == "2.3a5") client::eventDestruct(); + } + } + if(data[0] == "mail"){ + string *ret = ({ OOB_D->FindMud(this_object()) }) + ( data - ({ data[0] }) ); + REMOTEPOST_D->incoming_post(ret); + socket::eventWrite( ({ "mail-ack", ([ data[1] : ({}) ]) }) ); + } + + if(data[0] == "mail-ack"){ + foreach(mixed key, mixed val in data[1]){ + REMOTEPOST_D->outgoing_sent(OOB_D->FindMud(this_object()), key); + } + } + return 1; +} + +void write_data(mixed arg){ + validate(); + if(base_name(previous_object()) == OOB_D){ + socket::eventWrite(arg); + } + else { + } + if(arg && arg[0] && arg[0] == "oob-end"){ + client::eventDestruct(); + return; + } +} + +int eventDumpFiles(){ + validate(); + foreach(mixed key, mixed val in FilesMap){ + string fname = DIR_UPGRADES_FILES+"/"+replace_string(key,"/","0^0"); + if(key == DIR_UPGRADES_TXT+"/upgrades.txt") fname = DIR_UPGRADES_TXT+"/list.txt"; + rm(fname); + OOB_D->RemoveRequestedFile(OOB_D->FindMud(this_object()), key); + for(int i = 1;i < sizeof(FilesMap[key])+1; i++){ + if(FilesMap[key][i]) write_file(fname,FilesMap[key][i]+"\n"); + } + } +} diff --git a/lib/secure/lib/net/remote.c b/lib/secure/lib/net/remote.c new file mode 100644 index 0000000..094542a --- /dev/null +++ b/lib/secure/lib/net/remote.c @@ -0,0 +1,155 @@ +/* /secure/daemon/remote.c + * from the Foundation II LPC Library + * Remote Creator Protocol daemon + * created by Descartes of Borg 950504 + */ + +#include +#include NETWORK_H + +inherit LIB_SOCKET; + +private string Password; +private static mapping Connections; +private static int FD = -1; + +static void Setup(); + +void eventRead(int fd, string str); +static void eventProcess(int fd, string str); + +static void create(int fd, object owner){ + socket::create(fd, owner); + FD = fd; + Connections = ([]); +} + +static void eventSocketClosed(int fd) { + map_delete(Connections, fd); +} + +void eventRead(string str) { + if( !str ) { + eventWrite("50 Invalid command.\n", 1); + if( Connections[FD] ) map_delete(Connections, FD); + return; + } + eventProcess(FD, str); +} + +static private void eventProcess(int fd, string str) { + string tmp, cmd, arg, file, val; + int x; + if( Connections[fd] && Connections[fd]["in edit"] > 0 ) { + int len; + + if( !Connections[fd]["object"] ) { + eventWrite("50 Object destructed.\n", 1); + map_delete(Connections, fd); + return; + } + Connections[fd]["buffer"] += str; + if( !(len = strlen(Connections[fd]["buffer"])) ) return; + if( len == Connections[fd]["in edit"] ) { + tmp = Connections[fd]["object"]->eventWriteFile(Connections[fd]["file"], + Connections[fd]["buffer"]); + eventWrite(tmp + "\n"); + Connections[fd]["in edit"] = 0; + Connections[fd]["file"] = ""; + Connections[fd]["buffer"] = ""; + return; + } + else if( len > Connections[fd]["in edit"] ) { + string tmp1, tmp2; + + tmp1 =Connections[fd]["buffer"][0..(Connections[fd]["in edit"]-1)]; + tmp2 =Connections[fd]["buffer"][Connections[fd]["in edit"]..]; + Connections[fd]["buffer"] = ""; + eventProcess(fd, tmp1); + eventProcess(fd, tmp2); + return; + } + return; + } + if( !Connections[fd] ) Connections[fd] = ([ "buffer" : "" ]); + if( (Connections[fd]["buffer"] += str) == "" ) return; + if( (x = strsrch(Connections[fd]["buffer"], "\n")) == -1 ) return; + str = Connections[fd]["buffer"][0..(x-1)]; + if( x != strlen(Connections[fd]["buffer"]) - 1 ) + Connections[fd]["buffer"] = Connections[fd]["buffer"][(x+1)..]; + else Connections[fd]["buffer"] = ""; + if( sscanf(str, "%s %s", cmd, arg) != 2) { + cmd = replace_string(str, CARRIAGE_RETURN, ""); + arg = ""; + } + else arg = replace_string(arg, CARRIAGE_RETURN, ""); + if( !Connections[fd]["object"] ) { + string username, password; + if( cmd != "login" ) { + eventWrite("50 Must login with user name and password.\n", 1); + map_delete(Connections, fd); + return; + } + if( sscanf(arg, "%s %s", username, password) != 2 ) { + eventWrite("50 Login failed.\n", 1); + map_delete(Connections, fd); + return; + } + username = convert_name(username); + if( !user_exists(username) ) { + eventWrite("50 Login failed.\n", 1); + map_delete(Connections, fd); + return; + } + RestoreObject(DIR_CRES "/" + username[0..0] + "/" + username); + if( Password != crypt(password, Password) ) { + log_file("remote", "Failed attempt to login as " + username + + "\n"); + eventWrite("50 Login failed.\n", 1); + map_delete(Connections, fd); + return; + } + if( !(Connections[fd]["object"] = + load_object(user_path(username) + "adm/remote")) ) { + eventWrite("50 Failed to load remote object.\n", 1); + map_delete(Connections, fd); + return; + } + eventWrite("60 Connection to " + mud_name() + ".\n"); + } + else if( cmd == "100" ) { + int sz; + + if( sscanf(arg, "%d %s", sz, Connections[fd]["file"]) != 2 ) + eventWrite("50 Bad file send command.\n"); + else { + if( !sz ) eventWrite("110 No changes sent orwritten.\n"); + else Connections[fd]["in edit"] = sz; + } + } + else switch( cmd ) { + case "edit": + file = Connections[fd]["object"]->eventReadFile(arg); + if( file[<1] != '\n' ) file += "\n"; + tmp = sprintf( "%-14s\n", "100 " + strlen(file)); + eventWrite(tmp[0..15]); + eventWrite(file); + break; + case "ls": + val = Connections[fd]["object"]->eventCommand(cmd, arg); + if( val ) eventWrite("500 " + val + "\n"); + else eventWrite("50 " +cmd+ " " +arg+ ": Permission denied.\n"); + break; + case "update": + val = Connections[fd]["object"]->eventCommand(cmd, arg); + if( val ) eventWrite("510 " + val + "\n"); + else eventWrite("50 Update attempt went off into nowhere.\n"); + break; + default: + val = Connections[fd]["object"]->eventCommand(cmd, arg); + if( val ) eventWrite("400 " + val + "\n"); + else eventWrite("50 "+cmd+" "+arg+": Command not supported.\n"); + break; + } + eventProcess(fd, ""); +} diff --git a/lib/secure/lib/net/server.c b/lib/secure/lib/net/server.c new file mode 100644 index 0000000..36f51b0 --- /dev/null +++ b/lib/secure/lib/net/server.c @@ -0,0 +1,329 @@ +/* /lib/net/server.c + * From the Dead Souls LPC Library + * a TCP server object + * created by Descartes of Borg 950429 + * Version: @(#) server.c 1.3@(#) + * Last modified: 96/12/19 + */ + +#include +#include +#include NETWORK_H +#include +#include + +inherit LIB_DAEMON; +string mcolor; +int mclass; +int ftp_port = PORT_FTP; + +mapping ServerMap = ([]); +mapping Listen = ([]); + +private static int DestructOnClose= 0; +private static int MaxBytes = get_config(__MAX_BYTE_TRANSFER__); +private static int Port = 0; +private static string SocketObject = 0; +private static int SocketType = STREAM; +private static mapping Sockets = ([]); + +static void eventSocketError(string msg, int code); + +/* ******************* server.c attributes ************************ */ +int GetDestructOnClose() { + return DestructOnClose; +} + +static int SetDestructOnClose(int x) { + return (DestructOnClose = x); +} + +int GetSocketType() { + return SocketType; +} + +static int SetSocketType(int x ) { + return (SocketType = x); +} + +/* ******************** server.c events *************************** */ +static int eventClose(mixed sock) { + mapping s; + + trr("LIB_SERVER: eventClose trying to close: "+identify(sock),mcolor,mclass); + if(mapp(sock)) { + s = copy(sock); + } + if( intp(sock) ) { + s = copy(Sockets[sock]); + } + else if( objectp(sock) ) { + s = copy(Sockets[sock->GetDescriptor()]); + } + if( !s ) { + return 0; + } + if( s["Blocking"] ) { + s["Closing"] = 1; + return 1; + } + if( Sockets[s["Descriptor"]] ) { + map_delete(Sockets, s["Descriptor"]); + } + socket_close(s["Descriptor"]); + if( s["Owner"] ) { + s["Owner"]->eventSocketClosed(); + } + if( DestructOnClose && sock == Listen ) { + Destruct(); + } + sock = 0; +} + +int eventCreateSocket(int port) { + int x; + Listen["Blocking"] = 0; /* servers are not blocking to start */ + x = socket_create(SocketType, + "eventServerReadCallback", + "eventServerAbortCallback"); + if( x < 0 ) { + eventSocketError("Error in socket_create().", x); + return x; + } + Listen["Descriptor"] = x; + x = socket_bind(Listen["Descriptor"], port); + if( x != EESUCCESS ) { + eventClose(Listen); + eventSocketError("Error in socket_bind().", x); + return x; + } + x = socket_listen(Listen["Descriptor"], "eventServerListenCallback"); + if( x != EESUCCESS ) { + eventClose(Listen); + eventSocketError("Error in socket_listen().", x); + return x; + } + trr("LIB_SERVER: eventCreateSocket, port: "+port+", x: "+x,mcolor,mclass); +} + +static int Destruct() { + if( daemon::Destruct() ) { + foreach(int fd, mapping socket in Sockets) { + trr("server:Destruct: fd: "+fd+", "+socket_address(fd),mcolor,mclass); + if(socket && socket["Owner"]) + socket["Owner"]->eventShutdown(); + } + eventClose(Listen); + return 1; + } + else { + return 0; + } +} + +int eventDestruct() { + if( !master()->valid_apply(({})) ) { + return 0; + } + return daemon::eventDestruct(); +} + +static void eventNewConnection(object socket) { + int fd = socket->GetDescriptor(); + if(!Sockets[fd]) Sockets[fd] = ([]); + trr("LIB_SERVER: eventNewConnection, socket: "+identify(socket),mcolor,mclass); + trr("LIB_SERVER: eventNewConnection, socket->GetDescriptor(): "+identify(socket->GetDescriptor()),mcolor,mclass); + Sockets[fd]["Descriptor"] = socket->GetDescriptor(); + Sockets[fd]["Blocking"] = 0; + Sockets[fd]["Owner"] = socket; + socket->StartService(); // added for welcome +} + +static void eventServerAbortCallback(int fd) { + trr("server:eventServerAbortCallback: fd: "+fd+", "+socket_address(fd),mcolor,mclass); + eventClose(fd); +} + +int eventShutdown() { + if( previous_object() != find_object(INET_D) ) { + return 0; + } + Destruct(); + return 1; +} + +static void eventServerListenCallback(int fd) { + int x; + + trr("server:eventServerListenCallback: fd: "+fd+", "+socket_address(fd),mcolor,mclass); + x = socket_accept(fd, + "eventServerReadCallback", + "eventServerWriteCallback"); + if( x < 0 ) { + trr("Error in socket_accept().",mcolor,mclass); + eventSocketError("Error in socket_accept().", x); + return; + } + if( Sockets[x] ) { + eventClose(Sockets[x]); + } + trr("LIB_SERVER SocketObject: "+SocketObject,mcolor,mclass); + eventNewConnection(new(SocketObject, x, this_object())); +} + +static void eventServerReadCallback(int fd, mixed val) { + trr("server:eventServerReadCallback: fd: "+fd+", "+socket_address(fd),mcolor,mclass); + trr("server: I think that Sockets["+fd+"] is: "+identify(Sockets[fd]),mcolor,mclass); + if( !Sockets[fd] || !Sockets[fd]["Owner"] ) { + trr("server: No owner found for this data.",mcolor,mclass); + eventClose(fd); + return; + } + else { + trr("Sockets["+fd+"]: "+identify(Sockets[fd]),mcolor,mclass); + trr("sizeof(val): "+sizeof(val),mcolor,mclass); + trr("typeof(val): "+typeof(val),mcolor,mclass); + if(bufferp(val)) trr(" val: "+identify(read_buffer(val)),mcolor,mclass); + else trr(" val: "+identify(val),mcolor,mclass); + Sockets[fd]["Owner"]->eventRead(val); + } +} + +static void eventServerWriteCallback(int fd) { + int x; + mapping sock; + + trr("server:eventServerWriteCallback: fd: "+fd+", "+socket_address(fd),mcolor,mclass); + if( Listen && Listen["Descriptor"] == fd ) { + sock = Listen; + } + else if( Sockets[fd] ) { + sock = Sockets[fd]; + } + else { + return; + } + sock["Blocking"] = 0; + if( !sock["Buffer"] && sock["Closing"] ) { + eventClose(sock); + return; + } + x = EESUCCESS; + while( sock["Buffer"] && x == EESUCCESS ) { + switch( x = socket_write(sock["Descriptor"], sock["Buffer"][0]) ) { + case EESUCCESS: + break; + case EECALLBACK: + sock["Blocking"] = 1; + break; + case EEWOULDBLOCK: + call_out( (: eventServerWriteCallback :), 0, fd); + return; + case EEALREADY: + sock["Blocking"] = 1; + return; + default: + eventClose(sock); + eventSocketError("Error in socket_write().", x); + return; + } + if( sizeof(sock["Buffer"]) == 1 ) { + sock["Buffer"] = 0; + if( sock["Closing"] && !sock["Blocking"] ) { + eventClose(sock); + } + } + else { + sock["Buffer"] = sock["Buffer"][1..]; + } + } +} + +static void eventSocketError(string msg, int code) { + log_file("servers", "Error code: " + code + "\n" + msg + "\n"); + trr("LIB_SERVER Error code: " + code + "\n" + msg + "\n","red",mclass); +} + +varargs int eventWrite(object owner, mixed val, int close) { + int fd = owner->GetDescriptor(); + mapping sock; + + trr("server:eventWrite: fd: "+fd+", "+socket_address(fd),mcolor,mclass); + if(bufferp(val)) trr(" eventWrite: owner: "+identify(owner)+", val: "+identify(read_buffer(val)),mcolor,mclass); + else trr(" eventWrite: owner: "+identify(owner)+", val: "+identify(val),mcolor,mclass); + trr(" eventWrite: close: "+close,mcolor,mclass); + + if( Listen && Listen["Descriptor"] == fd ) { + sock = Listen; + } + else if( Sockets[fd] ) { + sock = Sockets[fd]; + } + else { + return 0; + } + if( owner != sock["Owner"] ) { + return 0; + } + if( SocketType != STREAM || stringp(val)) { + if( sock["Buffer"] ) { + sock["Buffer"] += ({ val }); + } + else { + sock["Buffer"] = ({ val }); + } + } + else { + buffer data = val; + int size = sizeof(data); + int count = (size/MaxBytes) + 1; + + if( !sock["Buffer"] ) { + sock["Buffer"] = ({}); + } + for(int i=0; i MaxBytes ) { + length = MaxBytes; + } + else { + length = size - ptr; + } + b = read_buffer(data, ptr, length); + sock["Buffer"] = ({ sock["Buffer"]..., b }); + } + } + + sock["Closing"] = close; + if( !sock["Blocking"] ) { + eventServerWriteCallback(sock["Descriptor"]); + } + return 1; +} + +/* ******************** server.c driver applies ******************* */ +varargs static void create(int port, int type, string socket_obj) { + daemon::create(); + SetNoClean(1); + + if(port == PORT_FTP){mcolor="green";mclass=MSG_FTP;} + if(port == PORT_HFTP){mcolor="white";mclass=MSG_HFTP;} + else if(port == PORT_HTTP){mcolor="cyan";mclass=MSG_HTTP;} + else if(port == PORT_RCP){mcolor="yellow";mclass=MSG_RCP;} + else if(port == PORT_OOB){mcolor="red";mclass=MSG_OOB;} + else { mcolor="blue",mclass=MSG_CONV;} + + if( socket_obj ) { + SocketObject = socket_obj; + } + if( !undefinedp(type) ) { + SocketType = type; + } + if( !undefinedp(port) ) { + Port = port; + call_out((: eventCreateSocket :), 1, Port); + } +} diff --git a/lib/secure/lib/net/socket.c b/lib/secure/lib/net/socket.c new file mode 100644 index 0000000..8d3e5c7 --- /dev/null +++ b/lib/secure/lib/net/socket.c @@ -0,0 +1,64 @@ +/* /lib/net/socket.c + * From the Dead Souls Object Library + * Handles individual socket I/O + * Created by Descartes of Borg 961218 + * Version: @(#) socket.c 1.1@(#) + * Last modified: 96/12/19 + */ + +#include + +inherit LIB_DAEMON; + +private static int Descriptor = -1; +private static object Owner = 0; + +/* *********************** socket.c attributes ********************* */ +string GetAddress() { + return socket_address(Descriptor); +} + +int GetDescriptor() { + return Descriptor; +} + +/* ************************* socket.c events *********************** */ +static int eventCloseSocket() { + if(!Owner) return 0; + Owner->eventClose(this_object()); +} + +int eventRead(mixed data) { + if( previous_object() != Owner ) { + return 0; + } + return 1; +} + +int eventDestruct(){ + return daemon::eventDestruct(); +} + +int eventSocketClosed() { + if(!Owner || previous_object() != Owner ) { + return 0; + } + eventDestruct(); + return 1; +} + + +varargs static int eventWrite(mixed data, int close) { + if(!close) close = 0; + if(!data) data = ({}); + if(Owner && this_object()) return Owner->eventWrite(this_object(), data, close); + else return 0; +} + +/* ******************** socket.c driver applies ****************** */ +static void create(int fd, object owner) { + daemon::create(); + SetNoClean(1); + Descriptor = fd; + Owner = owner; +} diff --git a/lib/secure/lib/net/telnet_client.c b/lib/secure/lib/net/telnet_client.c new file mode 100644 index 0000000..a4df375 --- /dev/null +++ b/lib/secure/lib/net/telnet_client.c @@ -0,0 +1,217 @@ +#include +#include NETWORK_H +#include +inherit LIB_ITEM; + +int attempting, connected, socket ; +object person ; +object player; + +static void create() +{ + item::create(); + SetKeyName( "client" ) ; + SetShort( "a telnet client" ) ; + SetId(({ "telnet","terminal" })) ; + SetLong( "It's a small pocket sized telnet terminal.\n" + "Use 'telnet' or 'connect' to begin.\n\nCommands:\n" + "[connect|telnet] : start telnet session.\nreset [client]" + " : reset the telnet client.\nreconnect : reconnect to session" + " (if you go netdead)\n"); + SetMass( 5 ) ; + attempting = 0 ; + connected = 0 ; + socket = 0 ; + person = 0 ; +} + +void init() +{ + add_action( "do_connect", ({ "connect", "telnet" }) ) ; + add_action( "do_reset", "reset" ) ; + add_action( "do_reconnect", "reconnect" ) ; +} + +int do_reconnect() +{ + if( !connected ) + { + notify_fail( "The telnet client is not connected!\n" ) ; + return 0 ; + } + write("Reconnecting into telnet session.\n"); + person = this_player() ; + input_to( "parse_comm", 0 ) ; + return 1 ; +} + +int do_reset( string args ) +{ + notify_fail( "Usage: reset client\n" ) ; + if( !args || args == "" ) + { + return 0 ; + } + if( args != "client" ) + { + return 0 ; + } + write("Resetting telnet client ...\n"); + if( connected ) + { + if( socket ) + { + socket_close( socket ) ; + } + } + attempting = 0 ; + connected = 0 ; + socket = 0 ; + person = 0 ; + write("Done!\n"); + return 1 ; +} + +string help() +{ + return "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n" + " Usage : connect [ip_address] [port]\n" + "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n" + "Note: use telnet port number 23 if you \n" + " are connecting to a normal site. \n" + "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n" ; +} + +int do_connect(string args) +{ + int new_socket, sc_result, port ; + string error, ip_address ; + + if( !args || args == "" ) + { + notify_fail( help() ) ; + return 0 ; + } + if( sscanf( args, "%s %d", ip_address, port ) != 2 ) + { + notify_fail( help() ) ; + return 0 ; + } + if( attempting ) + { + notify_fail( "Telnet connection attempt already in progress.\n" ) ; + return 0 ; + } + if( connected ) + { + notify_fail( "Already connected...\n" ) ; + return 0 ; + } + new_socket = socket_create( STREAM, "read_callback", "close_callback" ) ; + if( new_socket < 0 ) + { + switch( new_socket ) + { + case EEMODENOTSUPP : + error = "Socket mode not supported.\n" ; + break ; + case EESOCKET : + error = "Problem creating socket.\n" ; + break ; + case EESETSOCKOPT : + error = "Problem with setsockopt.\n" ; + break ; + case EENONBLOCK : + error = "Problem with setting non-blocking mode.\n" ; + break ; + case EENOSOCKS : + error = "No more available efun sockets.\n" ; + break ; + case EESECURITY : + error = "Security violation attempted.\n" ; + break ; + default : + error = "Unknown error code: " + new_socket + ".\n" ; + break ; + } + notify_fail( "Unable to connect, problem with socket_create.\n" + "Reason: " + error ) ; + return 0 ; + } + sc_result = socket_connect( new_socket, ip_address + " " + port, + "read_callback", "write_callback" ) ; + if( sc_result != EESUCCESS ) + { + notify_fail( "Failed to connect.\n" ) ; + return 0 ; + } + attempting = 1 ; + socket = new_socket ; + person = (object)previous_object() ; + player=this_player(); + write("Telnet Client Version 1.2\n"); + write("Attempting connection to: " + ip_address + " " + port + "...\nEnter 'dcon' at any time to abort.\n"); + input_to( "parse_comm", 0 ) ; + return 1 ; +} + +void read_callback( int fd, mixed message ) +{ + player->eventPrint(message); +} + +void close_callback( int fd ) +{ + if( connected ) + { + write("Connection closed by foreign host.\n"); + } + if( attempting ) + { + write("Attempt failed.\n"); + } + write("Type 'dcon' to finalize exit.\n"); + socket_close( fd ) ; + attempting = 0 ; + connected = 0 ; + socket = 0 ; +} + +void write_callback( int fd ) +{ + write("Connected...\n"); + attempting = 0 ; + connected = 1 ; +} + +int parse_comm( string str ) +{ + if( str == "dcon" ) + { + write("Disconnecting...\n"); + socket_close( socket ) ; + attempting = 0 ; + connected = 0 ; + socket = 0 ; + person = 0 ; + return 1 ; + } else { + if( !connected ) + { + write("You are not connected. Type \"dcon\" to stop using the client.\n"); + input_to( "parse_comm", 0 ) ; + return 1 ; + } + if( attempting ) + { + write("Please wait, still attempting connection, " + "type 'dcon' to exit.\n"); + input_to( "parse_comm", 0 ) ; + return 1 ; + } + socket_write( socket, str + "\n" ) ; + input_to( "parse_comm", 0 ) ; + return 1 ; + } +} + diff --git a/lib/secure/lib/net/uptime_server.c b/lib/secure/lib/net/uptime_server.c new file mode 100644 index 0000000..df881ec --- /dev/null +++ b/lib/secure/lib/net/uptime_server.c @@ -0,0 +1,67 @@ +/* + * This is a sample uptime server. All it does is tell you + * how long the mud's been up, then disconnects the telnet + * session. If your mud game port is 6666, this will be + * on 6668. + */ + +#include NETWORK_H +int port = query_host_port()+2; + +void StartServer(); +int SendUptime(int fd); + +void create(){ + StartServer(); +} + +void StartServer(){ + int sockstat, listsock; + + listsock = socket_create(STREAM,"read_callback","close_callback"); + if(listsock < 0){ + debug("Couldn't create socket. errorcode: "+listsock); + return; + } + + sockstat = socket_bind(listsock,port); + if(sockstat < 0){ + debug("Couldn't bind socket. errorcode: "+sockstat); + return; + } + + sockstat = socket_listen(listsock,"listen_callback"); + if(sockstat < 0){ + debug("Couldn't listen on socket. errorcode: "+sockstat); + return; + } + +} + +static void listen_callback(int fd){ + int sockstat = socket_accept(fd,"read_callback","write_callback"); + + if(sockstat < 0){ + debug("Couldn't accept on socket. errorcode: "+sockstat); + return; + } + + debug("uptime server: listening."); + SendUptime(sockstat); +} + +static void close_callback(int fd){ + debug("I'm wanting to close fd"+fd+" now."); +} + +static mixed read_callback(int fd, mixed data){ + debug("quitting. fd: "+fd+", "+identify(socket_status(fd))); + debug(socket_close(fd)); + return 1; +} + +int SendUptime(int fd){ + socket_write(fd, "\n"+mud_name()+" has been up "+time_elapsed(uptime())+"\n\n"); + debug("socket_close: "+socket_close(fd)); + return 1; +} diff --git a/lib/secure/lib/net/web_client.c b/lib/secure/lib/net/web_client.c new file mode 100644 index 0000000..61f8b34 --- /dev/null +++ b/lib/secure/lib/net/web_client.c @@ -0,0 +1,4 @@ +#include +#include + +inherit WGET_D; diff --git a/lib/secure/lib/std/access.c b/lib/secure/lib/std/access.c new file mode 100644 index 0000000..aac2155 --- /dev/null +++ b/lib/secure/lib/std/access.c @@ -0,0 +1,142 @@ +/* /secure/lib/std/access.c + * From the Dead Souls 3 Object Library + * An inheritable daemon for giving out access + * Created by Descartes of Borg 940918 + * Version: @(#) access.c 1.3@(#) + * Last modified: 97/01/03 + */ + +#include +#include + +inherit LIB_DAEMON; + +private mapping ReadAccess = ([]); +private static function ReadFunction = 0; +private mapping WriteAccess = ([]); +private static function WriteFunction = 0; + +/* ****************** access.c attributes ****************** */ +/* + * Note: this uses the old NM 3 naming scheme and is not worth the + * trouble of changing + */ +static void set_access(string type, function f) { + if( type == "read" ) { + ReadFunction = f; + } + else { + WriteFunction = f; + } +} + +mapping query_access(string type) { + if( type == "read" ) { + return copy(ReadAccess); + } + else { + return copy(WriteAccess); + } +} + +/* ********************** access.c events ********************** */ +nomask int check_access(object ob, string fun, string file, string oper) { + string array who; + mapping access; + + if( oper == "read" ) { + if( functionp(ReadFunction) ) { + if( !(functionp(ReadFunction) & FP_OWNER_DESTED) ) { + if( evaluate(ReadFunction, ob, fun, file) ) { + return 1; + } + } + } + access = ReadAccess; + } + else { + if( functionp(WriteFunction) ) { + if( !(functionp(WriteFunction) & FP_OWNER_DESTED) ) { + if( evaluate(WriteFunction, ob, fun, file) ) { + return 1; + } + } + } + access = WriteAccess; + } + if( !arrayp(who = match_path(access, file)) ) { + return 0; + } + return (member_array(ob->GetKeyName(), who) != -1); +} + +nomask int grant_access(string type, string file, string who) { + if( type == "read" ) { + if( ReadAccess[file] ) { + ReadAccess[file] = distinct_array(ReadAccess[file] + ({ who })); + } + else { + ReadAccess[file] = ({ who }); + } + if( !eventSave() ) { + Destruct(); + return 0; + } + return 1; + } + else if( type != "write" ) { + return 0; + } + if( WriteAccess[file] ) { + WriteAccess[file] = distinct_array(WriteAccess[file] + ({ who })); + } + else { + WriteAccess[file] = ({ who }); + } + if( !eventSave() ) { + Destruct(); + return 0; + } + return 1; +} + +nomask int remove_access(string type, string file, string who) { + if( type == "read" ) { + if( !ReadAccess[file] ) { + return 0; + } + else { + ReadAccess[file] -= ({ who }); + } + if( !eventSave() ) { + Destruct(); + return 0; + } + return 1; + } + else if( type != "write" ) { + return 0; + } + if( !WriteAccess ) { + return 0; + } + else { + WriteAccess[file] -= ({ who }); + } + if( !eventSave() ) { + Destruct(); + return 0; + } + return 1; +} + +/* ********************* access.c driver applies ******************* */ +void create() { + string file = base_name(this_object()); + + if( !strsrch(file, REALMS_DIRS) || !strsrch(file, DOMAINS_DIRS) + || !strsrch(file, ESTATES_DIRS) ) { + SetSaveFile(file); + } + daemon::create(); +} diff --git a/lib/secure/log/adm/foo.txt b/lib/secure/log/adm/foo.txt new file mode 100644 index 0000000..27afd21 --- /dev/null +++ b/lib/secure/log/adm/foo.txt @@ -0,0 +1 @@ +This file intentionally left blank. diff --git a/lib/secure/log/bak/foo.txt b/lib/secure/log/bak/foo.txt new file mode 100644 index 0000000..27afd21 --- /dev/null +++ b/lib/secure/log/bak/foo.txt @@ -0,0 +1 @@ +This file intentionally left blank. diff --git a/lib/secure/log/enter b/lib/secure/log/enter new file mode 100644 index 0000000..6ced161 --- /dev/null +++ b/lib/secure/log/enter @@ -0,0 +1,19 @@ +babylon (enter): Wed Sep 02 00:19:38 2020 from 127.0.0.1 +deskarnull (enter): Wed Sep 02 01:00:37 2020 from 127.0.0.1 +babylon (enter): Wed Sep 02 01:25:14 2020 from 127.0.0.1 +deskarnull (enter): Wed Sep 02 02:57:06 2020 from 127.0.0.1 +babylon (enter): Wed Sep 02 03:04:11 2020 from 127.0.0.1 +fluffster (enter): Wed Sep 02 04:06:50 2020 from 127.0.0.1 +deskarnull (enter): Wed Sep 02 04:36:37 2020 from 127.0.0.1 +babylon (enter): Wed Sep 02 20:17:54 2020 from 127.0.0.1 +deskarnull (enter): Wed Sep 02 22:08:40 2020 from 127.0.0.1 +babylon (enter): Wed Sep 02 22:14:00 2020 from 127.0.0.1 +babylon (enter): Thu Sep 03 01:17:50 2020 from 127.0.0.1 +babylon (enter): Fri Sep 04 19:14:06 2020 from 127.0.0.1 +deskarnull (enter): Fri Sep 04 20:17:49 2020 from 127.0.0.1 +babylon (enter): Sat Sep 05 21:32:34 2020 from 127.0.0.1 +bumble (enter): Sat Sep 05 22:51:05 2020 from 127.0.0.1 +gumpy (enter): Sat Sep 05 23:50:09 2020 from 127.0.0.1 +babylon (enter): Sun Sep 06 03:23:22 2020 from 127.0.0.1 +babylon (enter): Sun Sep 06 04:15:56 2020 from 127.0.0.1 +babylon (enter): Sun Sep 06 04:26:37 2020 from 127.0.0.1 diff --git a/lib/secure/log/icp b/lib/secure/log/icp new file mode 100644 index 0000000..9b1a414 --- /dev/null +++ b/lib/secure/log/icp @@ -0,0 +1,13 @@ +icp setup ended +icp setup ended +icp setup ended +icp setup ended +icp setup ended +icp setup ended +icp setup ended +icp setup ended +icp setup ended +icp setup ended +icp setup ended +icp setup ended +icp setup ended diff --git a/lib/secure/log/intermud/foo.txt b/lib/secure/log/intermud/foo.txt new file mode 100644 index 0000000..27afd21 --- /dev/null +++ b/lib/secure/log/intermud/foo.txt @@ -0,0 +1 @@ +This file intentionally left blank. diff --git a/lib/secure/log/intermud/i3 b/lib/secure/log/intermud/i3 new file mode 100644 index 0000000..13b3268 --- /dev/null +++ b/lib/secure/log/intermud/i3 @@ -0,0 +1,16 @@ +2020.09.01-19.18,58 ({ "startup-reply", 5, "*dalet", 0, "Dead_Souls_babylon", 0, ({ ({ "*dalet", "97.107.133.86 8787" }) }), 532506668 }) +2020.09.01-20.24,45 ({ "startup-reply", 5, "*dalet", 0, "Dead_Souls_babylon", 0, ({ ({ "*dalet", "97.107.133.86 8787" }) }), 532506668 }) +2020.09.01-21.12,26 ({ "startup-reply", 5, "*dalet", 0, "Dead_Souls_babylon", 0, ({ ({ "*dalet", "97.107.133.86 8787" }) }), 532506668 }) +2020.09.01-21.54,29 ({ "startup-reply", 5, "*dalet", 0, "Dead_Souls_babylon", 0, ({ ({ "*dalet", "97.107.133.86 8787" }) }), 532506668 }) +2020.09.01-21.56,15 ({ "startup-reply", 5, "*dalet", 0, "Dead_Souls_babylon", 0, ({ ({ "*dalet", "97.107.133.86 8787" }) }), 532506668 }) +2020.09.02-15.17,17 ({ "startup-reply", 5, "*dalet", 0, "Dead_Souls_babylon", 0, ({ ({ "*dalet", "97.107.133.86 8787" }) }), 532506668 }) +2020.09.02-21.09,28 ({ "startup-reply", 5, "*dalet", 0, "Zebu", 0, ({ ({ "*dalet", "97.107.133.86 8787" }) }), 260379860 }) +2020.09.02-22.13,40 ({ "startup-reply", 5, "*dalet", 0, "Zebu", 0, ({ ({ "*dalet", "97.107.133.86 8787" }) }), 260379860 }) +2020.09.03-01.17,30 ({ "startup-reply", 5, "*dalet", 0, "Zebu", 0, ({ ({ "*dalet", "97.107.133.86 8787" }) }), 260379860 }) +2020.09.04-19.13,37 ({ "startup-reply", 5, "*dalet", 0, "Zebu", 0, ({ ({ "*dalet", "97.107.133.86 8787" }) }), 260379860 }) +2020.09.04-20.50,50 ({ "startup-reply", 5, "*dalet", 0, "Zebu", 0, ({ ({ "*dalet", "97.107.133.86 8787" }) }), 260379860 }) +2020.09.05-21.32,04 ({ "startup-reply", 5, "*dalet", 0, "Zebu", 0, ({ ({ "*dalet", "97.107.133.86 8787" }) }), 260379860 }) +2020.09.06-02.10,41 ({ "startup-reply", 5, "*dalet", 0, "Zebu", 0, ({ ({ "*dalet", "97.107.133.86 8787" }) }), 260379860 }) +2020.09.06-03.22,48 ({ "startup-reply", 5, "*dalet", 0, "Zebu", 0, ({ ({ "*dalet", "97.107.133.86 8787" }) }), 260379860 }) +2020.09.06-04.15,40 ({ "startup-reply", 5, "*dalet", 0, "Zebu", 0, ({ ({ "*dalet", "97.107.133.86 8787" }) }), 260379860 }) +2020.09.06-04.26,23 ({ "startup-reply", 5, "*dalet", 0, "Zebu", 0, ({ ({ "*dalet", "97.107.133.86 8787" }) }), 260379860 }) diff --git a/lib/secure/log/intermud/i3err b/lib/secure/log/intermud/i3err new file mode 100644 index 0000000..8b84fd1 --- /dev/null +++ b/lib/secure/log/intermud/i3err @@ -0,0 +1,20 @@ +2020.09.01-19.18,59 ({ "error", 5, "*dalet", 0, "Dead_Souls_babylon", 0, "not-allowed", "Not in allow list for skylib", ({ "channel-listen", 5, "Dead_Souls_babylon", 0, "*dalet", 0, "skylib", 1 }) }) +2020.09.01-19.18,59 ({ "error", 5, "*dalet", 0, "Dead_Souls_babylon", 0, "not-allowed", "Not in allow list for elephant_link", ({ "channel-listen", 5, "Dead_Souls_babylon", 0, "*dalet", 0, "elephant_link", 1 }) }) +2020.09.01-19.18,59 ({ "error", 5, "*dalet", 0, "Dead_Souls_babylon", 0, "not-allowed", "Not in allow list for firefly", ({ "channel-listen", 5, "Dead_Souls_babylon", 0, "*dalet", 0, "firefly", 1 }) }) +2020.09.01-19.18,59 ({ "error", 5, "*dalet", 0, "Dead_Souls_babylon", 0, "not-allowed", "Not in allow list for mystic_dev", ({ "channel-listen", 5, "Dead_Souls_babylon", 0, "*dalet", 0, "mystic_dev", 1 }) }) +2020.09.01-19.18,59 ({ "error", 5, "*dalet", 0, "Dead_Souls_babylon", 0, "not-allowed", "Not in allow list for CrossMUD", ({ "channel-listen", 5, "Dead_Souls_babylon", 0, "*dalet", 0, "CrossMUD", 1 }) }) +2020.09.02-15.17,18 ({ "error", 5, "*dalet", 0, "Dead_Souls_babylon", 0, "not-allowed", "Not in allow list for skylib", ({ "channel-listen", 5, "Dead_Souls_babylon", 0, "*dalet", 0, "skylib", 1 }) }) +2020.09.02-15.17,18 ({ "error", 5, "*dalet", 0, "Dead_Souls_babylon", 0, "not-allowed", "Not in allow list for elephant_link", ({ "channel-listen", 5, "Dead_Souls_babylon", 0, "*dalet", 0, "elephant_link", 1 }) }) +2020.09.02-15.17,18 ({ "error", 5, "*dalet", 0, "Dead_Souls_babylon", 0, "not-allowed", "Not in allow list for firefly", ({ "channel-listen", 5, "Dead_Souls_babylon", 0, "*dalet", 0, "firefly", 1 }) }) +2020.09.02-15.17,18 ({ "error", 5, "*dalet", 0, "Dead_Souls_babylon", 0, "not-allowed", "Not in allow list for mystic_dev", ({ "channel-listen", 5, "Dead_Souls_babylon", 0, "*dalet", 0, "mystic_dev", 1 }) }) +2020.09.02-15.17,18 ({ "error", 5, "*dalet", 0, "Dead_Souls_babylon", 0, "not-allowed", "Not in allow list for CrossMUD", ({ "channel-listen", 5, "Dead_Souls_babylon", 0, "*dalet", 0, "CrossMUD", 1 }) }) +2020.09.02-21.09,29 ({ "error", 5, "*dalet", 0, "Zebu", 0, "not-allowed", "Not in allow list for skylib", ({ "channel-listen", 5, "Zebu", 0, "*dalet", 0, "skylib", 1 }) }) +2020.09.02-21.09,29 ({ "error", 5, "*dalet", 0, "Zebu", 0, "not-allowed", "Not in allow list for elephant_link", ({ "channel-listen", 5, "Zebu", 0, "*dalet", 0, "elephant_link", 1 }) }) +2020.09.02-21.09,30 ({ "error", 5, "*dalet", 0, "Zebu", 0, "not-allowed", "Not in allow list for firefly", ({ "channel-listen", 5, "Zebu", 0, "*dalet", 0, "firefly", 1 }) }) +2020.09.02-21.09,30 ({ "error", 5, "*dalet", 0, "Zebu", 0, "not-allowed", "Not in allow list for mystic_dev", ({ "channel-listen", 5, "Zebu", 0, "*dalet", 0, "mystic_dev", 1 }) }) +2020.09.02-21.09,30 ({ "error", 5, "*dalet", 0, "Zebu", 0, "not-allowed", "Not in allow list for CrossMUD", ({ "channel-listen", 5, "Zebu", 0, "*dalet", 0, "CrossMUD", 1 }) }) +2020.09.04-20.50,51 ({ "error", 5, "*dalet", 0, "Zebu", 0, "not-allowed", "Not in allow list for skylib", ({ "channel-listen", 5, "Zebu", 0, "*dalet", 0, "skylib", 1 }) }) +2020.09.04-20.50,51 ({ "error", 5, "*dalet", 0, "Zebu", 0, "not-allowed", "Not in allow list for elephant_link", ({ "channel-listen", 5, "Zebu", 0, "*dalet", 0, "elephant_link", 1 }) }) +2020.09.04-20.50,51 ({ "error", 5, "*dalet", 0, "Zebu", 0, "not-allowed", "Not in allow list for firefly", ({ "channel-listen", 5, "Zebu", 0, "*dalet", 0, "firefly", 1 }) }) +2020.09.04-20.50,51 ({ "error", 5, "*dalet", 0, "Zebu", 0, "not-allowed", "Not in allow list for mystic_dev", ({ "channel-listen", 5, "Zebu", 0, "*dalet", 0, "mystic_dev", 1 }) }) +2020.09.04-20.50,51 ({ "error", 5, "*dalet", 0, "Zebu", 0, "not-allowed", "Not in allow list for CrossMUD", ({ "channel-listen", 5, "Zebu", 0, "*dalet", 0, "CrossMUD", 1 }) }) diff --git a/lib/secure/log/intermud/imc2 b/lib/secure/log/intermud/imc2 new file mode 100644 index 0000000..aa11d12 --- /dev/null +++ b/lib/secure/log/intermud/imc2 @@ -0,0 +1,3883 @@ +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:13:33 2020. +socket_create: Created Socket 7 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:14:23 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:15:13 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:16:03 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:16:53 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:17:43 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:18:33 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:19:23 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:20:13 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:21:03 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:21:53 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:22:43 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:23:33 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:24:23 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:25:13 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:26:03 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:26:53 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:27:43 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:28:33 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:29:23 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:30:13 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:31:03 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:31:53 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:32:43 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:33:33 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:34:23 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:35:13 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:36:03 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:36:53 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:37:43 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:38:33 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:39:23 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:40:13 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:41:03 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:41:53 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:42:43 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:43:33 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:44:23 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:45:13 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:46:03 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:46:53 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:47:43 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:48:33 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:49:23 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:50:13 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:51:03 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:51:53 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:52:43 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:53:33 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:54:23 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:55:13 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:56:03 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:56:53 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:57:43 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:58:33 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 22:59:23 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 23:00:13 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 23:01:03 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 23:01:53 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 23:02:43 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 23:03:33 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 23:04:23 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Wed Sep 02 23:05:13 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +Creating IMC2 object at Thu Sep 03 01:17:22 2020. +socket_create: Created Socket 2 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:18:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:19:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:19:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:20:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:21:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:22:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:23:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:24:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:24:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:25:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:26:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:27:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:28:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:29:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:29:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:30:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:31:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:32:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:33:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:34:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:34:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:35:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:36:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:37:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:38:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:39:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:39:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:40:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:41:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:42:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:43:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:44:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:44:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:45:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:46:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:47:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:48:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:49:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:49:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:50:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:51:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:52:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:53:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:54:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:54:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:55:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:56:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:57:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:58:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:59:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 01:59:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:00:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:01:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:02:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:03:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:04:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:04:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:05:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:06:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:07:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:08:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:09:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:09:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:10:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:11:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:12:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:13:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:14:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:14:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:15:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:16:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:17:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:18:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:19:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:19:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:20:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:21:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:22:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:23:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:24:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:24:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:25:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:26:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:27:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:28:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:29:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:29:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:30:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:31:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:32:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:33:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:34:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:34:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:35:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:36:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:37:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:38:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:39:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:39:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:40:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:41:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:42:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:43:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:44:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:44:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:45:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:46:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:47:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:48:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:49:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:49:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:50:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:51:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:52:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:53:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:54:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:54:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:55:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:56:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:57:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:58:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:59:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 02:59:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:00:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:01:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:02:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:03:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:04:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:04:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:05:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:06:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:07:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:08:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:09:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:09:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:10:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:11:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:12:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:13:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:14:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:14:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:15:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:16:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:17:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:18:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:19:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:19:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:20:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:21:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:22:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:23:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:24:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:24:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:25:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:26:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:27:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:28:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:29:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:29:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:30:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:31:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:32:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:33:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:34:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:34:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:35:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:36:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:37:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:38:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:39:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:39:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:40:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:41:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:42:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:43:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:44:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:44:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:45:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:46:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:47:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:48:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:49:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:49:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:50:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:51:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:52:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:53:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:54:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:54:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:55:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:56:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:57:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:58:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:59:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 03:59:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:00:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:01:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:02:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:03:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:04:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:04:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:05:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:06:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:07:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:08:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:09:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:09:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:10:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:11:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:12:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:13:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:14:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:14:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:15:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:16:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:17:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:18:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:19:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:19:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:20:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:21:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:22:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:23:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:24:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:24:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:25:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:26:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:27:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:28:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:29:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:29:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:30:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:31:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:32:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:33:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:34:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:34:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:35:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:36:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:37:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:38:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:39:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:39:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:40:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:41:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:42:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:43:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:44:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:44:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:45:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:46:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:47:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:48:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:49:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:49:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:50:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:51:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:52:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:53:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:54:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:54:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:55:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:56:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:57:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:58:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:59:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 04:59:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:00:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:01:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:02:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:03:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:04:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:04:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:05:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:06:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:07:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:08:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:09:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:09:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:10:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:11:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:12:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:13:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:14:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:14:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:15:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:16:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:17:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:18:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:19:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:19:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:20:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:21:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:22:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:23:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:24:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:24:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:25:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:26:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:27:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:28:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:29:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:29:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:30:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:31:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:32:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:33:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:34:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:34:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:35:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:36:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:37:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:38:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:39:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:39:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:40:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:41:31 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:42:21 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:43:11 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:44:01 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:44:51 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:45:41 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Thu Sep 03 05:46:31 2020. +socket_create: Created Socket 1 +Creating IMC2 object at Fri Sep 04 19:13:29 2020. +socket_create: Created Socket 2 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:14:18 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:15:08 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:15:58 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:16:48 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:17:38 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:18:28 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:19:18 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:20:08 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:20:58 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:21:48 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:22:38 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:23:28 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:24:18 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:25:08 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:25:58 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:26:48 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:27:38 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:28:28 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:29:18 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:30:08 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:30:58 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:31:48 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:32:38 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:33:28 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:34:18 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:35:08 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:35:58 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:36:48 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:37:38 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:38:28 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:39:18 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:40:08 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:40:58 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:41:48 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:42:38 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:43:28 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:44:18 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:45:08 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:45:58 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:46:48 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:47:38 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:48:28 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:49:18 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:50:08 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:50:58 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:51:48 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:52:38 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:53:28 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:54:18 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:55:08 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:55:58 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:56:48 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:57:38 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:58:28 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 19:59:18 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:00:08 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:00:58 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:01:48 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:02:38 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:03:28 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:04:18 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:05:08 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:05:58 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:06:48 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:07:38 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:08:28 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:09:18 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:10:08 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:10:58 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:11:48 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:12:38 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:13:28 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:14:18 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:15:08 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:15:58 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:16:48 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:17:38 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:18:28 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:19:18 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:20:08 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:20:58 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:21:48 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:22:38 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:23:28 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:24:18 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:25:08 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:25:58 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:26:48 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:27:38 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:28:28 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:29:18 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:30:08 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:30:58 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:31:48 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:32:38 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:33:28 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:34:18 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:35:08 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:35:58 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:36:48 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:37:38 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:38:28 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:39:18 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:40:08 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:40:58 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:41:48 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:42:38 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:43:28 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:44:18 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:45:08 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:45:58 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:46:48 2020. +socket_create: Created Socket 1 +socket_connect: Connection refused +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +Creating IMC2 object at Fri Sep 04 20:47:38 2020. +socket_create: Created Socket 1 +socket_connect: Problem with connect +IMC2 OBJECT REMOVED +IMC2 TIMEOUT! Reloading. +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED +IMC2 OBJECT REMOVED diff --git a/lib/secure/log/network/foo.txt b/lib/secure/log/network/foo.txt new file mode 100644 index 0000000..27afd21 --- /dev/null +++ b/lib/secure/log/network/foo.txt @@ -0,0 +1 @@ +This file intentionally left blank. diff --git a/lib/secure/log/new_players b/lib/secure/log/new_players new file mode 100644 index 0000000..281324d --- /dev/null +++ b/lib/secure/log/new_players @@ -0,0 +1,5 @@ +deskarnull from 127.0.0.1 (Wed Sep 02 00:52:39 2020) +fluffster from 127.0.0.1 (Wed Sep 02 04:05:55 2020) +deskarnull from 127.0.0.1 (Wed Sep 02 22:07:49 2020) +bumble from 127.0.0.1 (Sat Sep 05 22:50:32 2020) +gumpy from 127.0.0.1 (Sat Sep 05 23:49:47 2020) diff --git a/lib/secure/modules/armor.c b/lib/secure/modules/armor.c new file mode 100644 index 0000000..c2ff470 --- /dev/null +++ b/lib/secure/modules/armor.c @@ -0,0 +1,198 @@ +#include +#include +#include +#include +#include ROOMS_H +#include +#include + + +int GetProts(string str); +int eventProcessValues(); +int eventStartQuery(string str); +int eventReceiveValue(string str); +mixed eventReadProtectionSettings(string str); +varargs int eventModifyProtections(mapping Protecciones, string filename, object ob); + +string globaltmp, globalstr, protections, current; +object armor_item; +string *prot_array = ({}); +mapping ProtectionsMap = ([]); + +string array Protections = ({ "BLUNT" ,"BLADE", "KNIFE", "WATER", "SHOCK", "COLD", "HEAT", "GAS", "ACID", "MAGIC", "POISON", "DISEASE", "TRAUMA" }); + + +varargs int eventStartArmorQuestions(string what, object ob){ + string filename; + mixed tempvar; + + armor_item = ob; + filename = base_name(ob)+".c"; + + if(file_exists(filename)) tempvar = eventReadProtectionSettings(filename); + if(tempvar && mapp(tempvar)) ProtectionsMap = tempvar; + else ProtectionsMap = ([]); + + protections = ""; + prot_array = ({}); + if(what && what != "") prot_array = ({ what }); + foreach(string prot in Protections) { + protections += lower_case(prot)+", "; + } + + truncate(protections,2); + protections += "."; + + write("Your armor can protect against one or more of the following types of damage: "); + write(protections+"."); + write("\nPlease enter which ones your armor should protect from, one at a time. "); + write("When you are done, please type a dot on a blank line."); + if(sizeof(prot_array)) write("So far, we have: "+identify(prot_array)); + + input_to( (: GetProts :) ); + return 1; +} + +int GetProts(string str){ + string *temp_array; + if(!str || str == "" || str == "."){ + prot_array -= ({0}); + if(sizeof(prot_array)) foreach(string element in prot_array){ + if(member_array(upper_case(element),Protections) == -1) prot_array -= ({ element }); + } + + if(!sizeof(prot_array)){ + write("Modification cancelled."); + return 1; + } + + else { + write("Protections list complete."); + eventProcessValues(); + return 1; + } + } + + if(grepp(str," ")){ + temp_array = explode(str," "); + prot_array += temp_array; + } + else prot_array += ({ str }); + + if(sizeof(prot_array)) write("You may now enter the next value. So far, we have: "+identify(prot_array)); + else write("You may now enter the next value. So far, it is blank."); + write("If you're done entering values, enter a dot on a blank line."); + + input_to( (: GetProts :) ); + return 1; +} + +int eventProcessValues(){ + if(sizeof(prot_array)){ + current = upper_case(prot_array[0]); + prot_array -= ({ prot_array[0] }); + eventStartQuery(current); + return 1; + } + eventModifyProtections(ProtectionsMap, base_name(armor_item)+".c", armor_item); + return 1; +} + +int eventStartQuery(string str){ + write("Please enter the protection value for: "+str); + input_to( (: eventReceiveValue :) ); + return 1; +} + +int eventReceiveValue(string str){ + int val; + if(!sscanf(str,"%d",val)) { + write("Please enter an integer value."); + eventStartQuery(current); + return 1; + } + + else { + ProtectionsMap[current] = val; + eventProcessValues(); + return 1; + } +} + +mixed eventReadProtectionSettings(string str){ + string prot, num, s1, junk; + int val; + string *temp_array = ({}); + string *fun_array = ({}); + string tmp_str = ""; + if(file_exists(str+".c")) str += ".c"; + if(file_exists(str)) { + if(!check_privs(this_player(),str)) { + write("You lack sufficient privileges for this."); + return 1; + } + else { + globalstr = str; + unguarded( (: globalstr = read_file(globalstr) :) ); + } + if(globalstr && globalstr != ""){ + str = globalstr; + globalstr = ""; + } + } + + fun_array = this_object()->eventReadFunctions(str); + if(!sizeof(fun_array)) { + write("Unknown error."); + return 1; + } + foreach(string element in fun_array){ + if(grepp(element,"SetProtection(")) tmp_str += element ; + } + + temp_array = explode(tmp_str,"\n"); + if(!sizeof(temp_array)){ + return ([]); + } + else { + foreach(string element in temp_array){ + if(sscanf(element,"SetProtection(%s)%s",s1,junk) == 2){ + sscanf(s1,"%s,%s",prot,num); + num = trim(num); + prot = trim(prot); + sscanf(num,"%d",val); + ProtectionsMap[prot] = val; + } + } + } + + return ProtectionsMap; + } + +varargs int eventModifyProtections(mapping Protecciones, string filename, object ob){ + string new_lines; + + if(!check_privs(this_player(),filename)){ + write("You do not have sufficient privileges to perform this action."); + return 1; + } + globaltmp = filename; + unguarded( (: globalstr = read_file(globaltmp) :) ); + + globalstr = remove_matching_line(globalstr, "SetProtection" , 1); + globaltmp = generate_tmp(); + new_lines = "\n"; + foreach(string key, string val in ProtectionsMap){ + new_lines += "SetProtection("+key+", "+val+");\n"; + } + globalstr = this_object()->eventAppend(globalstr,({"SetArmorType","SetRestrictLimbs","SetLong"}),new_lines); + unguarded( (: write_file(globaltmp, globalstr,1) :) ); + this_object()->eventGeneralStuff(globaltmp); + globalstr = filename; + unguarded( (: cp(globaltmp, globalstr) :) ); + rm(globaltmp); + if(ob && grepp(filename,base_name(ob))){ + reload(ob); + } + return 1; +} diff --git a/lib/secure/modules/create.c b/lib/secure/modules/create.c new file mode 100644 index 0000000..edde615 --- /dev/null +++ b/lib/secure/modules/create.c @@ -0,0 +1,803 @@ +/* /daemon/create.c + * From Dead Souls LPMud + * Mediates requests to create and modify objects + * You are not expected to understand this. + */ + +#include +#include +#include +#include +#include +#include ROOMS_H + + +int eventDelete(object ob, string value); +string global1, global2, globaltmp, globalvalue; + +string *base_arr = ({"set_heart_beat", "SetUnique", "SetNoClean","SetNoModify","SetProperties","SetLong","SetShort","SetItems","SetListen","SetSmell","SetInvis"}); +string *item_arr = base_arr + ({"SetLanguage","SetRead","SetDefaultRead","SetDisableChance", "SetDamagePoints", "SetVendorType","SetNoCondition","SetMoney","SetKeyName", "SetId", "SetMass","SetCost","SetValue","SetAdjectives","SetDamagePoints","SetBaseCost", "SetPreventGet", "SetPreventPut", "SetDestructOnDrop", "SetPreventDrop" }); +string *meal_arr = item_arr + ({ "SetMealType", "SetStrength"}) -({"SetDamagePoints"}); +string *storage_arr = item_arr + ({"SetOpacity", "SetMaxCarry","SetInventory", "SetCanClose", "SetCanLock","SetMaxRecurse","SetLocked","SetClosed","SetKey"}); +string *room_arr = base_arr - ({"SetUnique"}) + ({"SetFlowLimit","SetFlyRoom", "SetSinkRoom", "SetTerrainType","AddTerrainType","SetLanguage", "SetRead", "SetDefaultRead", "SetNoObviousExits","SetDefaultExits","SetTown","SetNightLong","SetDayLong","SetClimate","SetAmbientLight","SetNightLight","SetDayLight","SetObviousExits", "SetInventory", "SetEnters","SetSkyDomain"}); +string *npc_arr = base_arr - ({"SetItems"}) + ({"SetMass","SetBodyType","SetSize","SetRespiration","SetMount","SetCanBefriend","SetDefaultLanguage","SetNativeLanguage","SetCustomXP", "SetSpellBook", "SetCanBite", "SetWimpy","SetWimpyCommand","SetPacifist", "SetBodyComposition", "SetSleeping","SetPermitLoad", "SetAutoStand","SetCurrency","SetSkills","SetStats","SetKeyName", "SetId", "SetLevel", "SetRace", "SetClass","SetGender", "SetInventory", "SetHealthPoints","SetMaxHealthPoints", "SetAdjectives", "SetMelee", "SetPosition", "SetWanderSpeed", "SetEncounter", "SetMorality", "SetHeartBeat", "SetNoCondition", "SetAttackable", "SetPolyglot", "SetPreventGet", "SetMount", "CanBefriend"}); +string *barkeep_arr = npc_arr + ({"SetLocalCurrency","SetMenuItems"}); +string *trainer_arr = npc_arr + ({"SetNoSpells", "AddTrainingSkills"}); +string *vendor_arr = npc_arr + ({"SetLocalCurrency","SetStorageRoom","SetMaxItems","SetVendorType"}); +string *armor_arr = item_arr +({"SetRestrictLimbs","SetProtection","SetArmorType"}); +string *weapon_arr = item_arr + ({"SetClass","SetWeaponType","SetDamageType","SetHands"}); +string *chair_arr = item_arr + ({"SetMaxSitters","SetMaxCarry","SetInventory"}); +string *bed_arr = chair_arr + ({"SetMaxLiers"}); +string *table_arr = storage_arr + bed_arr; +string *door_arr = ({"SetHiddenDoor", "SetLong","SetShort","SetLocked","SetClosed","SetCanLock","SetKey","SetId"}); +string *book_arr = item_arr + ({"SetTitle","SetSource"}); +string *worn_storage_arr = armor_arr + storage_arr; +string *vehicle_arr = npc_arr + ({"SetVehicleInterior"}); + +string *all_arr = storage_arr + door_arr + room_arr + barkeep_arr + armor_arr + weapon_arr + bed_arr +meal_arr + vendor_arr +trainer_arr; + + +string GetSettings(string str){ + string ret; + string *name = ({}); + ret = ""; + switch(str){ + case "room" : name = room_arr; break; + case "npc" : name = npc_arr; break; + case "mob" : name = npc_arr; break; + case "barkeep" : name = barkeep_arr; break; + case "vendor" : name = vendor_arr; break; + case "trainer" : name = trainer_arr; break; + case "armor" : name = armor_arr; break; + case "armour" : name = armor_arr; break; + case "weapon" : name = weapon_arr; break; + case "item" : name = item_arr; break; + case "door" : name = door_arr; break; + case "meal" : name = meal_arr; break; + case "storage" : name = storage_arr; break; + case "table" : name = table_arr; break; + case "bed" : name = bed_arr; break; + case "chair" : name = chair_arr; break; + case "book" : name = book_arr; break; + case "worn storage" : name = worn_storage_arr; break; + case "wornstorage" : name = worn_storage_arr; break; + case "worn_storage" : name = worn_storage_arr; break; + case "vehicle" : name = vehicle_arr; break; + default : name = room_arr; + } + foreach(string thing in name){ + ret += thing+", "; + } + ret = truncate(ret,2)+"."; + return ret; +} + +mapping QueryMap(string str,object ob){ + switch(str){ + case "SetItems" : return ob->GetItemsMap();break; + case "SetSmell" : return ob->GetSmellMap();break; + case "SetListen" : return ob->GetListenMap();break; + case "SetInventory" : return ob->GetInventory();break; + case "SetEnters" : return ob->GetEnterMap();break; + case "SetMenuItems" : return ob->GetMenuItems();break; + case "SetSpellBook" : return ob->GetSpellBook();break; + case "SetRead" : return ob->GetReadsMap();break; + default : return ([]); + } + +} + +mixed eventModify(object ob, string str){ + string inheritance, out, tmpfile, filename, mode, metamode; + mixed value, mixed_tmp; + int invalid, setmap; + mapping temp_map; + string *p_array, *array_props, *special_map_array;; + + invalid = 1; + + inheritance = ""; + + if(ob->GetDoor() && sizeof(ob->GetDoor())) { + inheritance = "door"; + ob = load_object(ob->GetDoor()); + } + + filename = base_name(ob)+".c"; + tmpfile = generate_tmp(ob); + special_map_array = ({ "SetProperties", "SetStats", "SetSkills"}); + + if(!check_privs(this_player(),filename)){ + write("You do not appear to have write access to this file. Modification aborted."); + return 1; + } + + if(!check_privs(this_player(),tmpfile)){ + write("You do not appear to have write access to this file. Modification aborted."); + return 1; + } + + this_object()->eventGeneralStuff(filename); + global1 = filename; + global2 = tmpfile; + unguarded( (: cp(global1,global2) :) ); + + if(inherits(LIB_ROOM,ob)) inheritance += " room"; + if(inherits(LIB_NPC,ob)) inheritance += " npc"; + if(inherits(LIB_SENTIENT,ob)) inheritance += " npc"; + if(inherits(LIB_BARKEEP,ob)) inheritance += " barkeep"; + if(inherits(LIB_VENDOR,ob)) inheritance += " vendor"; + if(inherits(LIB_TRAINER,ob)) inheritance += " trainer"; + if(inherits(LIB_WEAPON,ob)) inheritance += " weapon"; + if(inherits(LIB_ARMOR,ob)) inheritance += " armor"; + if(inherits(LIB_ITEM,ob)) inheritance += " item"; + if(inherits(LIB_STORAGE,ob)) inheritance += " storage"; + if(inherits(LIB_CHAIR,ob)) inheritance += " chair"; + if(inherits(LIB_BED,ob)) inheritance += " bed"; + if(inherits(LIB_TABLE,ob)) inheritance += " table"; + if(inherits(LIB_MEAL,ob)) inheritance += " meal"; + if(inherits(LIB_BOOK,ob)) inheritance += " book"; + if(inherits(LIB_DOOR,ob)) inheritance += " door"; + if(inherits(LIB_WORN_STORAGE,ob)) inheritance += " worn_storage"; + if(inherits(LIB_VEHICLE,ob)) inheritance += " vehicle"; + + if(!inheritance || inheritance == ""){ + write("The object you want to modify lacks an init() function."); + write("Please correct this by issuing the initfix command, then try again."); + write("\nIf you are certain the object has a working init(), then"); + write("This error indicates that its library object type is not"); + write("currently supported by the Quick Creation System."); + return 1; + } + + if(sscanf(str,"%s %s %d",mode, metamode, value) != 3) sscanf(str,"%s %s %s",mode, metamode, value); + if(member_array(mode,special_map_array) == -1){ + if(sscanf(str,"%s %d",mode, value) != 2) sscanf(str,"%s %s",mode, value); + } + if(!value) { + value = 0; + if(!mode) mode = str; + } + + if(mode == "delete") { + if(value) mode = value; + value = "delete"; + } + + setmap = 0; + switch(lower_case(mode)){ + case "short" : out = "SetShort";break; + case "setshort" : out = "SetShort";break; + case "long" : out = "SetLong";break; + case "setlong" : out = "SetLong";break; + case "setnightlong" : out = "SetNightLong";break; + case "nightlong" : out = "SetNightLong";break; + case "daylong" : out = "SetDayLong";break; + case "setdaylong" : out = "SetDayLong";break; + case "climate" : out = "SetClimate";break; + case "setclimate" : out = "SetClimate";break; + case "light" : out = "SetAmbientLight";break; + case "ambientlight" : out = "SetAmbientLight";break; + case "setlight" : out = "SetAmbientLight";break; + case "nightlight" : out = "SetNightLight";break; + case "setnightlight" : out = "SetNightLight";break; + case "daylight" : out = "SetDayLight";break; + case "setdaylight" : out = "SetDayLight";break; + case "obvious" : out = "SetObviousExits";break; + case "setobvious" : out = "SetObviousExits";break; + case "obviousexits" : out = "SetObviousExits";break; + case "setobviousexits" : out = "SetObviousExits";break; + case "town" : out = "SetTown";break; + case "settown" : out = "SetTown";break; + case "keyname" : out = "SetKeyName";break; + case "setkeyname" : out = "SetKeyName";break; + case "name" : out = "SetKeyName";break; + case "setname" : out = "SetKeyName";break; + case "id" : out = "SetId";break; + case "setid" : out = "SetId";break; + case "class" : out = "SetClass";break; + case "setclass" : out = "SetClass";break; + case "maxhealth" : out = "SetMaxHealthPoints";break; + case "maxhealthpoints" : out = "SetMaxHealthPoints";break; + case "setmaxhealth" : out = "SetMaxHealthPoints";break; + case "setmaxhealthpoints" : out = "SetMaxHealthPoints";break; + case "level" : out = "SetLevel";break; + case "setlevel" : out = "SetLevel";break; + case "race" : out = "SetRace";break; + case "setrace" : out = "SetRace";break; + case "health" : out = "SetHealthPoints";break; + case "healthpoints" : out = "SetHealthPoints";break; + case "sethealth" : out = "SetHealthPoints";break; + case "sethealthpoints" : out = "SetHealthPoints";break; + case "gender" : out = "SetGender";break; + case "setgender" : out = "SetGender";break; + case "mass" : out = "SetMass";break; + case "setmass" : out = "SetMass";break; + case "weight" : out = "SetMass";break; + case "setweight" : out = "SetMass";break; + case "cost" : out = "SetCost";break; + case "setcost" : out = "SetCost";break; + case "value" : out = "SetValue";break; + case "setvalue" : out = "SetValue";break; + case "dollarcost" : out = "SetDollarCost";break; + case "setdollarcost" : out = "SetDollarCost";break; + case "adjectives" : out = "SetAdjectives";break; + case "setadjectives" : out = "SetAdjectives";break; + case "adj" : out = "SetAdjectives";break; + case "setadj" : out = "SetAdjectives";break; + case "adjs" : out = "SetAdjectives";break; + case "setadjs" : out = "SetAdjectives";break; + case "damage" : out = "SetDamagePoints";break; + case "setdamage" : out = "SetDamagePoints";break; + case "damagepoints" : out = "SetDamagePoints";break; + case "setdamagepoints" : out = "SetDamagePoints";break; + case "restrictlimbs" : out = "SetRestrictLimbs";break; + case "setrestrictlimbs" : out = "SetRestrictLimbs";break; + case "protection" : out = "SetProtection";break; + case "setprotection" : out = "SetProtection";break; + case "setprotections" : out = "SetProtection";break; + case "protections" : out = "SetProtection";break; + case "armortype" : out = "SetArmorType";break; + case "setarmortype" : out = "SetArmorType";break; + case "weapontype" : out = "SetWeaponType";break; + case "setweapontype" : out = "SetWeaponType";break; + case "damagetype" : out = "SetDamageType";break; + case "setdamagetype" : out = "SetDamageType";break; + case "hands" : out = "SetHands";break; + case "sethands" : out = "SetHands";break; + case "carry" : out = "SetMaxCarry";break; + case "maxcarry" : out = "SetMaxCarry";break; + case "setmaxcarry" : out = "SetMaxCarry";break; + case "closed" : out = "SetClosed";break; + case "setclosed" : out = "SetClosed";break; + case "locked" : out = "SetLocked";break; + case "setlocked" : out = "SetLocked";break; + case "canclose" : out = "SetCanClose";break; + case "setcanclose" : out = "SetCanClose";break; + case "canlock" : out = "SetCanLock";break; + case "setcanlock" : out = "SetCanLock";break; + case "key" : out = "SetKey";break; + case "setkey" : out = "SetKey";break; + case "recurse" : out = "SetMaxRecurse";break; + case "maxrecurse" : out = "SetMaxRecurse";break; + case "setmaxrecurse" : out = "SetMaxRecurse";break; + case "sitters" : out = "SetMaxSitters";break; + case "maxsitters" : out = "SetMaxSitters";break; + case "setmaxsitters" : out = "SetMaxSitters";break; + case "liers" : out = "SetMaxLiers";break; + case "maxliers" : out = "SetMaxLiers";break; + case "setmaxliers" : out = "SetMaxLiers";break; + case "item" : out = "SetItems";setmap = 1;break; + case "setitem" : out = "SetItems";setmap = 1;break; + case "items" : out = "SetItems";setmap = 1;break; + case "setitems" : out = "SetItems";setmap = 1;break; + case "inventory" : out = "SetInventory";setmap = 1;break; + case "inv" : out = "SetInventory";setmap = 1;break; + case "setinv" : out = "SetInventory";setmap = 1;break; + case "setinventory" : out = "SetInventory";setmap = 1;break; + case "smell" : out = "SetSmell";setmap = 1;break; + case "setsmell" : out = "SetSmell";setmap = 1;break; + case "listen" : out = "SetListen";setmap = 1;break; + case "setlisten" : out = "SetListen";setmap = 1;break; + case "enter" : out = "SetEnters";setmap = 1;break; + case "enters" : out = "SetEnters";setmap = 1;break; + case "setenters" : out = "SetEnters";setmap = 1;break; + case "setenter" : out = "SetEnters";setmap = 1;break; + case "exit" : out = "SetExits";setmap = 1;break; + case "exits" : out = "SetExits";setmap = 1;break; + case "setexits" : out = "SetExits";setmap = 1;break; + case "setexit" : out = "SetExits";setmap = 1;break; + case "setproperty" : out = "SetProperties";break; + case "property" : out = "SetProperties";break; + case "setproperties" : out = "SetProperties";break; + case "properties" : out = "SetProperties";break; + case "props" : out = "SetProperties";break; + case "setprops" : out = "SetProperties";break; + case "setskill" : out = "SetSkills";break; + case "skill" : out = "SetSkills";break; + case "skills" : out = "SetSkills";break; + case "setskills" : out = "SetSkills";break; + case "setstats" : out = "SetStats";break; + case "stats" : out = "SetStats";break; + case "stat" : out = "SetStats";break; + case "setstat" : out = "SetStats";break; + case "value" : out = "SetBaseCost";break; + case "setvalue" : out = "SetBaseCost";break; + case "val" : out = "SetBaseCost";break; + case "setval" : out = "SetBaseCost";break; + case "cost" : out = "SetBaseCost";break; + case "setcost" : out = "SetBaseCost";break; + case "basecost" : out = "SetBaseCost";break; + case "setbasecost" : out = "SetBaseCost";break; + case "setcurrency" : out = "SetCurrency";break; + case "currency" : out = "SetCurrency";break; + case "setcurr" : out = "SetCurrency";break; + case "curr" : out = "SetCurrency";break; + case "setmoney" : out = "SetMoney";break; + case "money" : out = "SetMoney";break; + case "setnocondition" : out = "SetNoCondition";break; + case "nocondition" : out = "SetNoCondition";break; + case "mealtype" : out = "SetMealType";break; + case "setmealtype" : out = "SetMealType";break; + case "strength" : out = "SetStrength";break; + case "setstrength" : out = "SetStrength";break; + case "setmealstrength" : out = "SetStrength";break; + case "mealstrength" : out = "SetStrength";break; + case "vendor" : out = "SetVendorType";break; + case "setvendor" : out = "SetVendorType";break; + case "setvendortype" : out = "SetVendorType";break; + case "vendortype" : out = "SetVendorType";break; + case "settitle" : out = "SetTitle";break; + case "title" : out = "SetTitle";break; + case "source" : out = "SetSource";break; + case "setsource" : out = "SetSource";break; + case "melee" : out = "SetMelee";break; + case "setmelee" : out = "SetMelee";break; + } + + if(!out){ + switch(mode){ + case "position" : out = "SetPosition";break; + case "setposition" : out = "SetPosition";break; + case "autostand" : out = "SetAutoStand";break; + case "setautostand" : out = "SetAutoStand";break; + case "damagepoints" : out = "SetDamagePoints";break; + case "setdamagepoints" : out = "SetDamagePoints";break; + case "wanderspeed" : out = "SetWanderSpeed";break; + case "setwanderspeed" : out = "SetWanderSpeed";break; + case "encounter" : out = "SetEncounter";break; + case "setencounter" : out = "SetEncounter";break; + case "sethostile" : out = "SetEncounter";break; + case "hostile" : out = "SetEncounter";break; + case "aggressive" : out = "SetEncounter";break; + case "setaggressive" : out = "SetEncounter";break; + case "morality" : out = "SetMorality";break; + case "setmorality" : out = "SetMorality";break; + case "setheartbeat" : out = "SetHeartBeat";break; + case "heartbeat" : out = "SetHeartBeat";break; + case "include" : out = "include";break; + case "inherit" : out = "inherit";break; + case "load" : out = "SetPermitLoad";break; + case "permitload" : out = "SetPermitLoad";break; + case "setpermitload" : out = "SetPermitLoad";break; + case "modify" : if(value && intp(value)) value = bool_reverse(value);out = "SetNoModify";break; + case "setmodify" : if(value && intp(value)) value = bool_reverse(value); out = "SetNoModify";break; + case "setnomodify" : out = "SetNoModify";break; + case "nomodify" : out = "SetNoModify";break; + case "open" : if(value && intp(value)) value = bool_reverse(value);out = "SetClosed";break; + case "setopen" : if(value && intp(value)) value = bool_reverse(value);out = "SetClosed";break; + case "sleep" : out = "SetSleeping";break; + case "setsleep" : out = "SetSleeping";break; + case "sleeping" : out = "SetSleeping";break; + case "setsleeping" : out = "SetSleeping";break; + case "disable" : out = "SetDisableChance";break; + case "disablechance" : out = "SetDisableChance";break; + case "setdisable" : out = "SetDisableChance";break; + case "setdisablechance" : out = "SetDisableChance";break; + case "noclean" : out = "SetNoClean";break; + case "setnoclean" : out = "SetNoClean";break; + case "bodycomp" : out = "SetBodyComposition";break; + case "bodycomposition" : out = "SetBodyComposition";break; + case "setbodycomposition" : out = "SetBodyComposition";break; + case "setpacifist" : out = "SetPacifist";break; + case "pacifist" : out = "SetPacifist";break; + case "unique" : out = "SetUnique";break; + case "setunique" : out = "SetUnique";break; + case "setwimpy" : out = "SetWimpy";break; + case "wimpy" : out = "SetWimpy";break; + case "wimpycommand" : out = "SetWimpyCommand";break; + case "setwimpycommand" : out = "SetWimpyCommand";break; + case "setcanbite" : out = "SetCanBite";break; + case "canbite" : out = "SetCanBite";break; + case "localcurrency" : out = "SetLocalCurrency";break; + case "setlocalcurrency" : out = "SetLocalCurrency";break; + case "menuitems" : out = "SetMenuItems";setmap = 1;break; + case "setmenuitems" : out = "SetMenuItems";setmap = 1;break; + case "menu" : out = "SetMenuItems";setmap = 1;break; + case "maxitems" : out = "SetMaxItems";break; + case "setmaxitems" : out = "SetMaxItems";break; + case "setstorageroom" : out = "SetStorageRoom";break; + case "storageroom" : out = "SetStorageRoom";break; + case "defaultread" : out = "SetDefaultRead";break; + case "setdefaultread" : out = "SetDefaultRead";break; + case "setread" : out = "SetRead";setmap = 1;break; + case "read" : out = "SetRead";setmap = 1;break; + case "language" : out = "SetLanguage";break; + case "lang" : out = "SetLanguage";break; + case "setlang" : out = "SetLanguage";break; + case "setlanguage" : out = "SetLanguage";break; + case "setspellbook" : out = "SetSpellBook";break; + case "spellbook" : out = "SetSpellBook";break; + case "spells" : out = "SetSpellBook";break; + case "addtrainingskills" : out = "AddTrainingSkills";break; + case "settrainingskills" : out = "AddTrainingSkills";break; + case "trainingskills" : out = "AddTrainingSkills";break; + case "training" : out = "AddTrainingSkills";break; + case "nospells" : out = "SetNoSpells";break; + case "setnospells" : out = "SetNoSpells";break; + case "defaultexits" : out = "SetDefaultExits";break; + case "setdefaultexits" : out = "SetDefaultExits";break; + case "setnoobviousexits" : out = "SetNoObviousExits";break; + case "noobviousexits" : out = "SetNoObviousExits";break; + case "xp" : out = "SetCustomXP";break; + case "setxp" : out = "SetCustomXP";break; + case "setcustomxp" : out = "SetCustomXP";break; + case "customxp" : out = "SetCustomXP";break; + case "nativelanguage" : out = "SetNativeLanguage";break; + case "setnativelanguage" : out = "SetNativeLanguage";break; + case "heartbeat" : out = "set_heart_beat";break; + case "setheartbeat" : out = "set_heart_beat";break; + case "set_heart_beat" : out = "set_heart_beat";break; + case "heart_beat" : out = "set_heart_beat";break; + case "hiddendoor" : out = "SetHiddenDoor";break; + case "sethiddendoor" : out = "SetHiddenDoor";break; + case "opacity" : out = "SetOpacity";break; + case "setopacity" : out = "SetOpacity";break; + case "setterraintype" : out = "SetTerrainType";break; + case "terraintype" : out = "AddTerrainType";break; + case "addterraintype" : out = "AddTerrainType";break; + case "terrain" : out = "AddTerrainType";break; + case "defaultlanguage" : out = "SetDefaultLanguage";break; + case "defaultlang" : out = "SetDefaultLanguage";break; + case "setdefaultlanguage" : out = "SetDefaultLanguage";break; + case "bodytype" : out = "SetBodyType";break; + case "setbodytype" : out = "SetBodyType";break; + case "setsize" : out = "SetSize";break; + case "size" : out = "SetSize";break; + case "respiration" : out = "SetRespiration";break; + case "setrespiration" : out = "SetRespiration";break; + case "setinvis" : out = "SetInvis";break; + case "invis" : out = "SetInvis";break; + case "attackable" : out = "SetAttackable";break; + case "setattackable" : out = "SetAttackable";break; + case "flowlimit" : out = "SetFlowLimit";break; + case "setflowlimit" : out = "SetFlowLimit";break; + case "flow" : out = "SetFlowLimit";break; + } + } + + if(!out){ + switch(mode){ + case "polyglot" : out = "SetPolyglot";break; + case "setpolyglot" : out = "SetPolyglot";break; + case "setvehicleinterior" : out = "SetVehicleInterior";break; + case "vehicleinterior" : out = "SetVehicleInterior";break; + case "interior" : out = "SetVehicleInterior";break; + case "preventget" : out = "SetPreventGet";break; + case "setpreventget" : out = "SetPreventGet";break; + case "setpreventdrop" : out = "SetPreventDrop";break; + case "preventdrop" : out = "SetPreventDrop";break; + case "setdestructondrop" : out = "SetDestructOnDrop";break; + case "destructondrop" : out = "SetDestructOnDrop";break; + case "flyroom" : out = "SetFlyRoom";break; + case "setflyroom" : out = "SetFlyRoom";break; + case "setsinkroom" : out = "SetSinkRoom";break; + case "sinkroom" : out = "SetSinkRoom";break; + case "skydomain" : out = "SetSkyDomain";break; + case "setskydomain" : out = "SetSkyDomain";break; + case "befriend" : out = "CanBefriend";break; + case "setbefriend" : out = "CanBefriend";break; + case "setcanbefriend" : out = "CanBefriend";break; + case "canbefriend" : out = "CanBefriend";break; + case "mount" : out = "SetMount";break; + case "setmount" : out = "SetMount";break; + default : out = mode; + } + } + + if(!value) value = 0; + + if(value == "delete") { + eventDelete(ob, out); + unguarded( (: rm(global2) :) ); + return 1; + } + + if(out == "SetExits") { + write("SetExits is a special setting, which isn't modified like others."); + write("To make an exit to a room, or to create a new room, type:\n"); + write("create room DIRECTION FILE"); + write("For example: create room east test_room1"); + write("To get rid of an exit, it's: delete exit DIRECTION"); + write("For example: delete exit east"); + return 1; + } + + if(out == "SetEnters") { + write("SetEnters is a special setting, which isn't modified like others."); + write("To make an Enter, first identify an item that already exists "); + write("in SetItems. For example, if SetItems contains a pub:\n"); + write("create enter pub test_pub1\n"); + write("To get rid of that enter: delete enter pub"); + write("Please note that if the \"thing to be entered\" isn't already "); + write("in SetItems, things won't work right."); + return 1; + } + + if(out == "SetInventory"){ + write("SetInventory is a special setting, which isn't modified like others."); + write("To add something to something else's inventory, the \"thing "); + write("to be added\" has to be in your environment, or carried by you."); + write("So if you want to add a chair to your sample room:\n"); + write("home"); + write("go east"); + write("cd /domains/town/obj"); + write("clone chair"); + write("add chair to room"); + write("1\n"); + write("If you want to add a sword to your fighter: \n"); + write("clone sword"); + write("add sword to fighter"); + write("wield sword\n"); + write("To remove items from a thing's permanent inventory:"); + write("delete chair"); + write("delete sword from fighter"); + return 1; + } + + if(out == "include" || out == "inherit"){ + this_object()->eventModHeader(ob, out,value); + return 1; + } + + if(grepp(inheritance,"room") && member_array(out,room_arr) != -1) invalid = 0; + if(grepp(inheritance,"barkeep") && member_array(out,barkeep_arr) != -1) invalid = 0; + if(grepp(inheritance,"vendor") && member_array(out,vendor_arr) != -1) invalid = 0; + if(grepp(inheritance,"trainer") && member_array(out,trainer_arr) != -1) invalid = 0; + if(grepp(inheritance,"npc") && member_array(out,npc_arr) != -1) invalid = 0; + if(grepp(inheritance,"weapon") && member_array(out,weapon_arr) != -1) invalid = 0; + if(grepp(inheritance,"armor") && member_array(out,armor_arr) != -1) invalid = 0; + if(grepp(inheritance,"storage") && member_array(out,storage_arr) != -1) invalid = 0; + if(grepp(inheritance,"chair") && member_array(out,chair_arr) != -1) invalid = 0; + if(grepp(inheritance,"bed") && member_array(out,bed_arr) != -1) invalid = 0; + if(grepp(inheritance,"table") && member_array(out,table_arr) != -1) invalid = 0; + if(grepp(inheritance,"meal") && member_array(out,meal_arr) != -1) invalid = 0; + if(grepp(inheritance,"door") && member_array(out,door_arr) != -1) invalid = 0; + if(grepp(inheritance,"book") && member_array(out,book_arr) != -1) invalid = 0; + if(grepp(inheritance,"worn_storage") && member_array(out,worn_storage_arr) != -1) invalid = 0; + if(grepp(inheritance,"vehicle") && member_array(out,vehicle_arr) != -1) invalid = 0; + else if(grepp(inheritance,"item") && member_array(out,item_arr) != -1) invalid = 0; + + if(invalid) { + write("Invalid property."); + return 1; + } + if(out == "SetProtection"){ + this_object()->eventStartArmorQuestions(value,ob); + return 1; + } + + if(out == "SetBaseCost"){ + this_object()->eventModCost(ob, metamode, value); + return 1; + } + + if(member_array(out,special_map_array) != -1) { + this_object()->eventSpecialMapHandler(ob,out,metamode,value); + return 1; + } + + if(out == "SetMoney" || out == "SetCurrency"){ + this_object()->eventModMoney(ob, metamode, value); + return 1; + } + + if(setmap == 1) { + temp_map = QueryMap(out, ob); + temp_map = this_object()->eventStartMappingQuestions(temp_map, ob, tmpfile, out); + return 1; + } + + array_props = ({"AddTrainingSkills", "SetId","SetAdjectives","SetRestrictLimbs"}); + if(member_array(out,array_props) != -1){ + this_object()->eventStartGenericQuestions(ob, tmpfile, ({value}), out); + return 1; + } + + if(grepp(inheritance,"door") && out != "SetHiddenDoor" ){ + string cote = this_object()->eventEvaluateDoorSide(ob); + if(cote) this_object()->eventProcessDoor(ob, out, value, cote); + else this_object()->eventProcessDoor(ob, out, value); + return 1; + } + + else { + switch(out){ + case "SetLong" : p_array = ({"SetShort","SetAmbientLight","SetDayLight","SetNightLight","create()","create ()","create"}); break; + case "SetDayLong" : p_array = ({"SetShort","SetAmbientLight","SetDayLight","SetNightLight","SetNightLong","SetLong","create()","create ()","create"}); break; + case "SetNightLong" : p_array = ({"SetShort","SetAmbientLight","SetDayLight","SetNightLight","SetDayLong","SetLong","create()","create ()","create"}); break; + case "SetShort" : p_array = ({"SetAmbientLight","SetDayLight","SetNightLight","create()","create ()","create"}); break; + case "SetHealthPoints" : p_array = ({"SetInventory","SetMaxHealhPoints","SetClass","SetRace","SetLong"});break; + case "SetMaxHealthPoints" : p_array = ({"SetInventory","SetHealhPoints","SetClass","SetRace","SetLong"});break; + case "SetNativeLanguage" : p_array = ({"SetRace"});break; + case "SetSize" : p_array = ({"SetRace"});break; + case "SetBodyType" : p_array = ({"SetRace"});break; + case "SetRespiration" : p_array = ({"SetRace"});break; + case "SetClass" : p_array = ({"SetRace","SetLong"});break; + case "SetMaxHealthPoints" : p_array = ({"SetKeyName","SetId"});break; + case "SetStats" : p_array = ({"SetRace"});break; + case "SetMass" : p_array = ({"SetRace","SetLong"});break; + case "SetSmell" : p_array = ({"SetItems","SetInventory","SetListen","SetLong","SetDayLong","SetNightLong","SetShort"});break; + case "SetListen" : p_array = ({"SetItems","SetInventory","SetSmell","SetLong","SetDayLong","SetNightLong","SetShort"});break; + case "SetItems" : p_array = ({"SetAmbientLight","SetDayLight","SetNightLight","create()","create ()","SetShort","SetLong","SetDayLong","SetNightLong"});break; + case "SetAmbientLight" : p_array = ({"SetDayLight","SetNightLight","create()","create ()","SetShort","SetLong","SetDayLong","SetNightLong"});break; + case "SetDayLight" : p_array = ({"SetAmbientLight","SetNightLight","create()","create ()","SetShort","SetLong","SetDayLong","SetNightLong"});break; + case "SetNightLight" : p_array = ({"SetAmbientLight","SetDayLight","create()","create ()","SetShort","SetLong","SetDayLong","SetNightLong"});break; + case "SetHiddenDoor" : p_array = ({ "SetClosed", "SetLocked" }); break; + default : p_array = ({"SetItems","SetLong","SetDayLong","SetNightLong","SetShort"}); + } + + this_object()->eventModString(tmpfile, out, value, p_array); + } + mixed_tmp = reload(tmpfile); + if(!mixed_tmp || !intp(mixed_tmp)) { + write("This would screw up your file. Aborting modification."); + return 1; + } + this_object()->eventGeneralStuff(tmpfile); + global1 = tmpfile; + global2 = filename; + unguarded( (: cp(global1,global2) :) ); + reload(ob); + + rm(tmpfile); + return MODULES_CREATE+" Done."; +} + +int eventDelete(object ob, string value){ + string tmpfile, filename; + mixed mixed_tmp; + + filename = base_name(ob)+".c"; + tmpfile = generate_tmp(ob); + + + if(!check_privs(this_player(),filename)){ + + write("You do not appear to have write access to this file. Modification aborted."); + return 1; + } + + if(!check_privs(this_player(),tmpfile)){ + write("You do not appear to have write access to this file. Modification aborted."); + return 1; + } + + global1 = filename; + global2 = tmpfile; + unguarded( (: cp(global1,global2) :) ); + mixed_tmp = reload(tmpfile); + if(!mixed_tmp || !intp(mixed_tmp)) { + write("Target file is screwed up. Aborting delete."); + return 1; + } + globalvalue = value; + unguarded( (: globaltmp = remove_matching_line(read_file(global2),globalvalue,1) :) ); + unguarded( (: write_file(global2,globaltmp,1) :) ); + mixed_tmp = reload(tmpfile); + if(!mixed_tmp || !intp(mixed_tmp)) { + write("This change would screw up your file. Aborting delete."); + return 1; + } + else unguarded( (: cp(global2, global1) :) ); + reload(ob); + unguarded( (: rm(global2) :) ); + write("Setting deleted."); + return 1; +} + +int eventResumeArrayMod(object target, string tmpfile, string *NewArr, string func){ + string filename, ret, array_string; + string *p_array; + mixed mx; + filename = base_name(target)+".c"; + + if(!check_privs(this_player(),filename)){ + write("You do not appear to have write access to this file. Modification aborted."); + return 1; + } + global2 = tmpfile; + global1 = filename; + unguarded( (: cp(global1, global2) :) ); + array_string = func + "( ({"; + foreach(string foo in NewArr){ + array_string += "\""+foo+"\", "; + } + array_string = truncate(array_string, 2); + array_string += "}) );"; + switch(func){ + case "SetId" : p_array = ({"SetName","SetKeyName","create()","create ()","SetAdjectives"});break; + case "SetAdjectives" : p_array = ({"SetName","SetKeyName","create()","create ()","SetId"});break; + case "SetRestrictLimbs" : p_array = ({ "SetArmorType","SetDamagePoints","SetMass"});break; + default : p_array = ({"SetLong","SetShort","SetDayLong","SetNightLong"}); + } + ret = remove_matching_line(read_file(tmpfile),func); + ret = this_object()->eventAppend(ret,p_array,"\n"+array_string+"\n"); + globaltmp = ret; + unguarded( (: write_file(global2,globaltmp,1) :) ); + this_object()->eventGeneralStuff(tmpfile); + mx = reload(tmpfile); + if(!mx || !intp(mx)){ + write("This change would screw up the object. Aborting."); + return 1; + } + global1 = tmpfile; + global2 = filename; + unguarded( (: cp(global1, global2) :) ); + reload(target); + write(func+" modification complete."); + unguarded( (: rm(global1) :) ); + return 1; +} + +int eventResumeMappingChange(object target, string tmpfile, mapping NewMap, string func){ + string map_string, filename, ret; + mixed mx; + string *p_array; + map_string = this_object()->eventStringifyMap(NewMap); + map_string = func+"("+map_string+");"; + filename = base_name(target)+".c"; + + if(!check_privs(this_player(),filename)){ + write("You do not appear to have write access to this file. Modification aborted."); + return 1; + } + + global2 = tmpfile; + global1 = filename; + unguarded( (: cp(global1, global2) :) ); + + ret = remove_matching_line(read_file(tmpfile),func); + switch(func){ + case "SetHealthPoints" : p_array = ({"SetInventory","SetMaxHealhPoints","SetClass","SetRace","SetLong"});break; + case "SetMaxHealthPoints" : p_array = ({"SetClass","SetRace","SetHealthPoints","SetLong"});break; + case "SetSmell" : p_array = ({"SetItems","SetInventory","SetListen","SetLong","SetDayLong","SetNightLong","SetShort"});break; + case "SetListen" : p_array = ({"SetItems","SetInventory","SetSmell","SetLong","SetDayLong","SetNightLong","SetShort"});break; + default : p_array = ({"SetItems","SetLong","SetDayLong","SetNightLong","SetShort"}); + } + ret = this_object()->eventAppend(ret,p_array,"\n"+map_string+"\n"); + global1 = tmpfile; + global2 = ret; + unguarded( (: write_file(global1,global2,1) :) ); + mx = reload(tmpfile); + if(!mx || !intp(mx)){ + write("This change would screw up the object. Aborting."); + return 1; + } + this_object()->eventGeneralStuff(tmpfile); + global1 = tmpfile; + global2 = filename; + unguarded( (: cp(global1, global2) :) ); + if(target) reload(target); + write(func+" modification complete."); + unguarded( (: rm(global1) :) ); + return 1; +} + +int eventAddSettings(object ob, string tmp, mapping NewMap, string func){ + string filename, new_lines; + filename = base_name(ob)+".c"; + + if(!check_privs(this_player(),filename)){ + write("You do not have sufficient privileges to perform this action."); + return 1; + } + global2 = filename; + unguarded( (: global1 = read_file(global2) :) ); + + global1 = remove_matching_line(global1, func , 1); + global2 = tmp; + new_lines = "\n"; + foreach(string key, mixed val in NewMap){ + if(intp(val)) new_lines += func+"(\""+key+"\", "+val+");\n"; + else new_lines += func+"(\""+key+"\", \""+val+"\");\n"; + } + global1 = this_object()->eventAppend(global1,({func,"SetClass","SetRace","SetLevel","SetItems","SetInventory","SetLong", "SetClosed"}),new_lines); + unguarded( (: write_file(global2, global1,1) :) ); + this_object()->eventGeneralStuff(global2); + global1 = filename; + unguarded( (: cp(global2, global1) :) ); + unguarded( (: rm(global2) :) ); + reload(ob); + return 1; +} diff --git a/lib/secure/modules/door.c b/lib/secure/modules/door.c new file mode 100644 index 0000000..0ad77dd --- /dev/null +++ b/lib/secure/modules/door.c @@ -0,0 +1,272 @@ +#include +#include +#include + +string tmpfile, contents, globalstr, globalstr1, globalstr2, globalstr3; +string my_room_file, other_room_file, tmpfile; +string my_room_contents, other_room_contents; +string *global_array; + +varargs int eventReceiveId(object door, string *id, string cote){ + string ret_id = implode(id,":"); + if(!cote) cote = this_object()->eventEvaluateDoorSide(door); + this_object()->eventProcessDoor(door, "SetId", ret_id, cote); + return 1; +} + +mapping GetDoorKeys(string str){ + string dir, junk1, junk2; + string *lines; + mapping KeyMap = ([]); + + globalstr = str; + unguarded( (: global_array = this_object()->eventReadLines(read_file(globalstr)) :) ); + lines = global_array; + if(!sizeof(lines)) return ([]); + foreach(string line in lines){ + if(grepp(line, "SetKeys")){ + sscanf(line,"%sKeys(%s,%s",junk1, dir, junk2); + dir = this_object()->eventCleanString(dir); + KeyMap[dir] = line; + } + } + + return copy(KeyMap); + } + + varargs mixed eventChangeDoor(mixed door, string property, mixed value, string cote){ + object porte; + string *sides, *props; + string map_string = ""; + int lockable; + mapping KeyMap = this_object()->GetDoorKeys(door); + + if(stringp(door)) porte = load_object(door); + else if(objectp(door)) porte = door; + + if(!porte) return 0; + + sides = porte->GetSides(); + + foreach(string side in sides){ + mapping TmpMap1 = ([]); + TmpMap1 = porte->GetSide(side); + props = keys(TmpMap1); + + switch(property){ + case "SetId" : property = "id";break; + case "SetLong" : property = "long";break; + case "SetShort" : property = "short";break; + case "SetCanLock" : property = "lockable";break; + case "SetKey" : property = "key";break; + } + if(member_array(property, props) != -1 ){ + if(!cote) TmpMap1[property] = value; + else if(cote && cote == side && property == "id") + TmpMap1[property] = explode(value,":"); + else if(cote && cote == side) TmpMap1[property] = value; + } + + if(!TmpMap1["lockable"]) lockable = 0; + else lockable = TmpMap1["lockable"]; + map_string += "SetSide(\""+side+"\", ([\"id\" : "+identify(TmpMap1["id"])+",\n"; + map_string += "\"short\" : \""+TmpMap1["short"]+"\",\n"; + map_string += "\"long\" : \""+TmpMap1["long"]+"\",\n"; + map_string +="\"lockable\" : "+lockable+" ]) );\n"; + if(property == "key") { + if(!cote || cote == side) map_string += "SetKeys(\""+side+"\", ({\""+value+"\"}) );\n\n"; + else if(KeyMap[side]) map_string += KeyMap[side] + "\n\n"; + } + if(property != "key" && KeyMap[side]){ + map_string += KeyMap[side] + "\n\n"; + } + } + + return map_string; + } + +varargs int eventProcessDoor(mixed door, string property, mixed value, string cote){ + object porte; + int closed, locked; + string other_room; + + if(!door || ! property ){ + write("Wrong number of arguments to eventProcessDoor"); + return 0; + } + + if(!value) value = 0; + + if(objectp(door)) door = base_name(door); + if(last(door,2) != ".c") door += ".c"; + if(!file_exists(door)){ + write("No such door file."); + return 0; + } + + porte = load_object(door); + tmpfile = generate_tmp(porte); + + if(property == "closed" || property == "SetClosed") closed = value; + else closed = this_object()->eventReadValue(door, "SetClosed"); + if(property == "locked" || property == "SetLocked") locked = value; + else locked = this_object()->eventReadValue(door, "SetLocked");; + + contents = "#include \n\n"; + contents += "inherit LIB_DOOR;\n\n"; + contents += "static void create() {\n"; + contents += "door::create();\n\n"; + if(cote) contents += this_object()->eventChangeDoor(door, property, value, cote)+"\n"; + else contents += this_object()->eventChangeDoor(door, property, value)+"\n"; + contents += "SetClosed("+closed+");\n"; + contents += "SetLocked("+locked+");\n"; + contents += "}\n"; + unguarded( (: write_file(tmpfile,contents,1) :) ); + this_object()->eventGeneralStuff(tmpfile); + globalstr2 = door; + unguarded( (: cp(tmpfile, globalstr2) :) ); + unguarded( (: rm(tmpfile) :) ); + reload(door); + reload(environment(this_player())); + other_room = this_object()->GetOtherRoom(door); + if(other_room) reload(other_room); + return 1; +} + +int eventDeleteDoor(string door){ + string this_room, other_room; + this_room = base_name(environment(this_player()))+".c"; + other_room = this_object()->GetOtherRoom(door)+".c"; + foreach( string room in ({this_room, other_room}) ){ + globalstr = room; + unguarded( (: globalstr2 = read_file(globalstr) :) ); + globalstr2 = remove_matching_line(globalstr2, door); + globalstr3 = generate_tmp(load_object(door)); + unguarded( (: write_file(globalstr3, globalstr2, 1) :) ); + unguarded( (: cp(globalstr3, globalstr) :) ); + unguarded( (: rm(globalstr3) :) ); + reload(room); + } + return 1; +} + +string GetOtherRoom(string door){ + string other_room, dir_str; + foreach(string dir in environment(this_player())->GetDoors()){ + if(grepp(environment(this_player())->GetDoor(dir), door)) dir_str = + dir; + } + other_room = environment(this_player())->GetExit(dir_str); + if(other_room) return other_room; + else return ""; +} + +string eventEvaluateDoorSide(object door){ + string *door_array, *door_sides; + string dir_str, ret_str; + + door_array = environment(this_player())->GetDoors(); + door_sides = door->GetSides(); + + foreach(string dir in door_array){ + if(load_object(environment(this_player())->GetDoor(dir)) == door) dir_str = dir; + } + + if(!dir_str) return ""; + + foreach(string side in door_sides){ + if(side == dir_str) ret_str = side; + } + + return ret_str; +} + +int eventCreateDoor(string dir, string filename){ + object my_room, other_room; + object *everyone_here, *everyone_there; + string *temp_array = ({}); + string contents, rep_str, opp_dir, new_line; + + tmpfile = generate_tmp(filename); + + my_room = environment(this_player()); + my_room_file = base_name(my_room)+".c"; + other_room_file = my_room->GetExit(dir)+".c"; + if(!file_exists(other_room_file)) { + tell_room(my_room,"The new door fades away and disappears."); + return 0; + } + unguarded( (: my_room_contents = read_file(my_room_file) :) ); + unguarded( (: other_room_contents = read_file(other_room_file) :) ); + other_room = load_object(other_room_file); + everyone_here = get_livings(my_room,1); + everyone_there = get_livings(other_room,1); + + contents = read_file("/obj/door.c"); + + if(grepp(contents,"DIR_X")) rep_str = "X"; + else rep_str = "Y"; + + contents = replace_string(contents, "DIR_"+rep_str, dir); + contents = replace_string(contents, rep_str+"_SIDE", dir); + + opp_dir = opposite_dir(dir); + if(opp_dir && opp_dir != "" && grepp(contents,"DIR_Y")){ + rep_str = "Y"; + contents = replace_string(contents, "DIR_"+rep_str, opp_dir); + contents = replace_string(contents, rep_str+"_SIDE", opp_dir); + } + + temp_array = explode(my_room_contents,"\n"); + foreach(string line in temp_array) { + if(grepp(line,"SetDoor")){ + if(grepp(line,truncate(filename,2)) || grepp(line,"\""+dir+"\"")){ + my_room_contents = remove_matching_line(my_room_contents, line); + } + } + } + + new_line = "SetDoor(\""+dir+"\", \""+filename+"\");"; + my_room_contents = this_object()->eventAppendLast(my_room_contents,"create", "\n"+new_line+"\n"); + + temp_array = explode(other_room_contents,"\n"); + foreach(string line in temp_array) { + if(grepp(line,"SetDoor")){ + if(grepp(line,truncate(filename,2)) || grepp(line,"\""+opp_dir+"\"")){ + other_room_contents = remove_matching_line(other_room_contents, line); + } + } + } + + new_line = "SetDoor(\""+opp_dir+"\", \""+filename+"\");"; + other_room_contents = this_object()->eventAppendLast(other_room_contents,"create","\n"+new_line+"\n"); + + globalstr2 = filename; + globalstr3 = contents; + + unguarded( (: write_file( tmpfile, globalstr3,1 ) :) ); + this_object()->eventGeneralStuff(tmpfile); + unguarded( (: cp(tmpfile, globalstr2) :) ); + + globalstr3 = my_room_contents; + unguarded( (: write_file( tmpfile, globalstr3,1 ) :) ); + this_object()->eventGeneralStuff(tmpfile); + unguarded( (: cp(tmpfile, my_room_file) :) ); + + globalstr3 = other_room_contents; + unguarded( (: write_file( tmpfile, globalstr3,1 ) :) ); + this_object()->eventGeneralStuff(tmpfile); + unguarded( (: cp(tmpfile, other_room_file) :) ); + + reload(filename); + reload(my_room_file); + reload(other_room_file); + + unguarded( (: rm(tmpfile) :) ); + + return 1; + + +} + + diff --git a/lib/secure/modules/file.c b/lib/secure/modules/file.c new file mode 100644 index 0000000..abd8961 --- /dev/null +++ b/lib/secure/modules/file.c @@ -0,0 +1,527 @@ +#include +#include + +string array eventReadFunctions(string source); +int eventModString(string file, string param, string replace); + +string first_arg, globalstr, globalstr2, globalstr3; +string *global_array; +mixed globalmixed; +string *where_append; + +string eventAppendLast(string file, string fun, string addendum){ + int done; + string *source; + string junk1, junk2, junk3, junk4, junk5; + string ret = ""; + globalstr = file; + + if(!grepp(file,"\n") && unguarded( (:file_exists(globalstr):) ) && !check_privs(this_player(),globalstr)){ + write("You do not appear to have write access to this file. Modification aborted."); + return ""; + } + if(!grepp(file,"\n") && unguarded( (: file_exists(globalstr):) )) { + file = unguarded( (: read_file(globalstr) :) ); + } + + unguarded( (: global_array = this_object()->eventReadFunctions(globalstr) :) ); + source = global_array; + foreach(string func in source){ + if(sscanf(func,"%s"+fun+"%s(%s)%s\n%s",junk1, junk2, junk3, junk4, junk5) == 5 && !done){ + func = reverse_string(func); + func = replace_string(func,"}","SIHT_ECALPER",1); + func = reverse_string(func); + func = replace_string(func,"REPLACE_THIS",addendum+"\n}"); + done = 1; +} +ret += func + "\n"; +} +return ret; +} + +string eventAppend(string file, string *params, string addendum){ + int found, count, primary_line, secondary_line; + string *file_arr; + string *top_array; + string *bottom_array; + string search_str, new_string; + int tmpnull = 0; + + if(!grepp(file,"\n") && file_exists(file)) globalstr = read_file(file); + else globalstr = file; + + if(!grepp(globalstr,"\n") && unguarded( (: file_exists(globalstr):) ) && !check_privs(this_player(),globalstr)){ + write("You do not appear to have write access to this file. Modification aborted."); + return ""; + } + if(!grepp(globalstr,"\n") && unguarded( (: file_exists(globalstr):) )) { + file = unguarded( (: read_file(globalstr) :) ); + } + foreach(string param in params){ + if(!found && param && sizeof(param) && param != "" && stringp(param)){ + if(strsrch(file,param) != -1){ + search_str = param; + found = 1; + } + } + } + + if(!found || !search_str || search_str == ""){ + + return file; + } + + file_arr = explode(file,"\n"); + + foreach(string line in file_arr){ + if(line && line != "" && strsrch(line, search_str) != -1) { + primary_line = member_array(line, file_arr); + count = primary_line; + } + if(primary_line > tmpnull){ + count++; + if(last(line,1,1) == ";" ) { + secondary_line = count; + } + } + if(secondary_line) break; + } + + top_array = file_arr[0..secondary_line-1]; + bottom_array = file_arr[secondary_line..sizeof(file_arr)-1]; + new_string = implode(top_array,"\n"); + new_string += addendum; + new_string += implode(bottom_array,"\n"); + + return new_string; +} + +varargs mapping eventReadMapping(string file, string *params, int destructive){ + int numero, count, found, primary_line, secondary_line; + string *file_arr; + string *mapping_array; + string filename, new_string, search_str, mapping_string, junk1, junk2; + mapping new_mapping = ([]); + mixed mixed_var; + + if(file_exists(file) && !check_privs(this_player(),file)){ + write("You do not appear to have write access to this file. Modification aborted."); + return ([]); + } + + if(!grepp(file,"\n") && file_exists(file)) { + first_arg = file; + file = read_file(file); + } + + foreach(string param in params){ + if(!found){ + if(strsrch(file,param) != -1) + search_str = param; + found = 1; + } + } + + if(!found){ + return ([]); + } + + file_arr = explode(file,"\n"); + + foreach(string line in file_arr){ + if(strsrch(line, search_str) != -1) { + primary_line = member_array(line, file_arr); + count = primary_line - 1; + } + if(primary_line){ + count++; + if(last(line,1,1 ) == ";") { + secondary_line = count; + } + } + if(secondary_line) break; + } + + + if(primary_line != secondary_line ) + mapping_array = file_arr[primary_line..secondary_line]; + else mapping_array = ({ file_arr[primary_line] }); + + mapping_array = file_arr[primary_line..secondary_line]; + + new_string = implode(mapping_array," "); + if(!new_string) write("Problem here."); + if(sscanf(new_string,"%s([%s])%s",junk1,mapping_string, junk2) < 3){ + write("It's a null mapping"); + return ([]); + } + mapping_array = explode(mapping_string,","); + foreach(string foo in mapping_array){ + string *sub_array; + if(!foo) break; + if(strsrch(foo,":") == -1) break; + sub_array = explode(foo,":"); + if(sub_array[0] && sub_array[1]) { + sub_array[0] = trim(replace_string(replace_string(sub_array[0]," \t",""),"\"","")); + sub_array[1] = trim(replace_string(replace_string(sub_array[1]," \t",""),"\"","")); + if(sscanf(sub_array[1],"%d",numero) == 1) mixed_var = numero; + else mixed_var = sub_array[1]; + new_mapping[sub_array[0]] = mixed_var; + } + } + + if(!first_arg) first_arg = "NULL"; + + found = 0; + + globalstr3 = search_str; + unguarded( (: globalstr = remove_matching_line(read_file(first_arg),globalstr3,1) :) ); + globalstr2 = generate_tmp(file); + if(destructive) { + unguarded( (: write_file(globalstr2, globalstr,1) :) ); + unguarded( (: cp(globalstr2, first_arg) :) ); + } + if(sizeof(new_mapping)) return copy(new_mapping); + else return ([]); +} + +string array eventReadLines(string source){ + if(file_exists(source) && !check_privs(this_player(),source)){ + write("You do not appear to have write access to this file. Modification aborted."); + return ({}); + } + globalstr = source; + unguarded( (: global_array = explode(globalstr,"\n") :) ); + return global_array; +} + +string array eventReadFunctions(string source){ + string tmpsource, headers; + string *ret, *types, *primitives, *beginners, *fun_arr; + int i, element, infunc; + mixed line; + element = -1; + headers = ""; + line = ""; + fun_arr = allocate(999); + primitives = ({"private","static","nomask","varargs"}); + types = ({"int","void","buffer","mapping","mixed","string","array","float"}); + beginners = primitives + types; + + if(grepp(source,"\n") && !file_exists(source)) { + globalstr2 = source; + globalstr = generate_tmp(this_player()); + unguarded( (: write_file(globalstr, globalstr2,1) :) ); + source = globalstr; + } + + tmpsource = generate_tmp(source); + + if(file_exists(source) && !check_privs(this_player(),source)){ + write("You do not appear to have write access to this file. Modification aborted."); + return ({}); + } + + if(file_exists(tmpsource) && !check_privs(this_player(),tmpsource)){ + write("You do not appear to have write access to this file. Modification aborted."); + return ({}); + } + globalstr3 = tmpsource; + globalstr = source; + unguarded( (: cp(globalstr, globalstr3) :) ); + if(!file_exists(source)) return ({"Source read failed."}); + if(!file_exists(tmpsource)) return ({"Read failed."}); + + + for(i=1; line; i++){ + if(!line = read_file(source, i, 1)) break; + if(!line || !stringp(line) || line == "") break; + + + if(line && !infunc && !starts_with_arr(line, beginners)) headers += line; + + + + else if(line && !infunc && starts_with_arr(line, beginners) ){ + + element++; + infunc = 1; + if(!sizeof(fun_arr[element])) fun_arr[element] = line; + else fun_arr[element] += line; + } + + else if(line && infunc && !starts_with_arr(line, beginners) ){ + + fun_arr[element] += line; + } + + else if(line && infunc && starts_with_arr(line, beginners) && !grepp(line,"(")){ + fun_arr[element] += line; + } + + + else if(line && infunc && starts_with_arr(line, beginners) && grepp(line,"(")){ + infunc = 0; + i--; + } + } + + ret = ({headers}); + foreach(string item in fun_arr){ + if(item && sizeof(item)) ret += ({newline_trim(item)}); + } + rm(tmpsource); + return ret; + } + + int eventAddInit(string file){ + string *contents, *temparray, *temparray2, *beginners; + string tmpfile; + int done, add, memnum; + + globalstr = tmpfile; + globalstr2 = file; + + if(file_exists(file) && !check_privs(this_player(),file)){ + write("You do not appear to have write access to this file. Modification aborted."); + return 1; + } + + tmpfile = generate_tmp(file); + temparray = ({}); + temparray2 = ({}); + contents = unguarded( (: eventReadFunctions(globalstr2) :) ); + beginners = ({"private","static","nomask","varargs"}); + beginners += ({"int","void","buffer","mapping","mixed","string","array","float"}); + + foreach(string func in contents){ + if(member_array(func,contents) != 0 && grepp(func,"void init")) memnum = member_array(func,contents); + } + + if(memnum && memnum != -1){ + if(!grepp(contents[memnum],"::init()")){ + temparray = explode(contents[memnum],"\n"); + foreach(string line in temparray){ + if(line && !starts_with_arr(line, beginners)) add = 1; + if(add && !done) { + temparray2 += ({"::init();"}); + temparray2 += ({line}); + done = 1; + } + else { + temparray2 += ({line}); + } + } + contents[memnum] = implode(temparray2,"\n"); + global_array = contents; + globalstr3 = tmpfile; + unguarded( (: write_file(globalstr3,implode(global_array,"\n"),1) :) ); + } + + else { + return 2; + } + } + + else { + contents += ({ "void init(){\n::init();\n}" }); + global_array = contents; + globalstr3 = tmpfile; + unguarded( (: write_file(globalstr3,implode(global_array,"\n"),1) :) ); + } + globalstr = tmpfile; + globalstr2 = file; + done = unguarded( (: cp(globalstr, globalstr2) :) ); + unguarded( (: rm(globalstr) :) ); + return done; + } + +varargs int eventModString(string file, string param, mixed replace, string *params){ + string check_include, ret, tmpfile; + int terrain_include = 0; + if(file_exists(file) && !check_privs(this_player(),file)){ + write("You do not appear to have write access to this file. Modification aborted."); + return 1; + } + if(!params) where_append = ({"SetLong","SetShort"}); + if(params && !sizeof(params)) where_append = ({"SetLong","SetShort"}); + else where_append = params; + + tmpfile = generate_tmp(file); + + globalstr = file; + globalstr2 = tmpfile; + globalstr3 = param; + globalmixed = replace; + + if(stringp(replace)) { + if(globalstr3 == "SetArmorType" || globalstr3 == "SetMealType" || + globalstr3 == "SetPosition" || globalstr3 == "SetTerrainType" || + globalstr3 == "AddTerrainType" || globalstr3 == "SetSize" || + globalstr3 == "SetBodyType" || globalstr3 == "SetRespiration" || + globalstr3 == "SetVendorType" || globalstr3 == "SetDamageType"){ + replace = upper_case(replace); + if(globalstr3 == "SetArmorType") check_include = "/include/armor_types.h"; + if(globalstr3 == "SetVendorType") check_include = "/include/vendor_types.h"; + if(globalstr3 == "SetDamageType") check_include = "/include/damage_types.h"; + if(globalstr3 == "SetMealType") check_include = "/include/meal_types.h"; + if(globalstr3 == "SetPosition") check_include = "/include/position.h"; + if(globalstr3 == "SetTerrainType") check_include = "/include/terrain_types.h"; + if(globalstr3 == "AddTerrainType") check_include = "/include/terrain_types.h"; + if(globalstr3 == "SetSize") check_include = "/include/size_types.h"; + if(globalstr3 == "SetRespiration") check_include = "/include/respiration_types.h"; + if(globalstr3 == "SetBodyType") check_include = "/include/body_types.h"; + if(globalstr3 == "SetSize" && !grepp(replace,"S_")) replace = "S_"+replace; + if(globalstr3 == "SetRespiration" && !grepp(replace,"R_")) replace = "R_"+replace; + if(globalstr3 == "SetBodyType" && !grepp(replace,"B_")) replace = "B_"+replace; + if(globalstr3 == "SetVendorType" && !grepp(replace,"VT_")) replace = "VT_"+replace; + if(globalstr3 == "SetArmorType" && !grepp(replace,"A_")) replace = "A_"+replace; + if(globalstr3 == "SetTerrainType" && !grepp(replace,"T_")) replace = "T_"+replace; + if(globalstr3 == "AddTerrainType" && !grepp(replace,"T_")) replace = "T_"+replace; + if(grepp(replace,"T_")) terrain_include = 1; + if(globalstr3 == "SetMealType" && !grepp(replace,"MEAL_")) replace = "MEAL_"+replace; + if(globalstr3 == "SetPosition" && !grepp(replace,"POSITION_")) replace = "POSITION_"+replace; + if(!grepp(read_file(check_include),replace)) { + write("Invalid type. Please review "+check_include+" for valid types."); + return 1; + } + if(grepp(replace,"MEAL_ALCOHOL")) replace = "MEAL_DRINK | MEAL_ALCOHOL"; + if(grepp(replace,"MEAL_CAFFEINE")) replace = "MEAL_DRINK | MEAL_CAFFEINE"; + + globalmixed = replace; + } + else globalmixed = "\""+replace+"\""; + } + if(unguarded( (: grepp(read_file(globalstr),globalstr3):) )) + ret = unguarded( (: replace_matching_line(read_file(globalstr), globalstr3, globalstr3+"("+globalmixed+");") :) ); + else ret = unguarded( (: eventAppend(read_file(globalstr),where_append,"\n"+globalstr3+"("+globalmixed+");\n") :) ); + if(terrain_include && !grepp(ret,"terrain_types.h")) ret = "#include \n" + ret; + globalstr3 = ret; + unguarded( (: write_file(globalstr2, globalstr3, 1) :) ); + globalstr = file; + unguarded( (: cp(globalstr2, globalstr) :) ); + unguarded( (: rm(globalstr2) :) ); + return 1; +} + +int eventModHeader(object ob, string what, string value){ + string newcontents, newline; + string tmpfile = generate_tmp(ob); + globalstr = tmpfile; + globalstr2 = base_name(ob)+".c"; + + unguarded( (: cp(globalstr2, globalstr) :) ); + unguarded( (: globalstr3 = read_file(globalstr) :) ); + + if(what == "include") { + what = "#include <"; + if(!grepp(value,".h")) value += ".h>"; + else value += ">"; + newline = "\n"+what + value+"\n"; + } + + if(what == "inherit") { + value = upper_case(value); + if(!grepp(value,"LIB_")) value = "LIB_"+value; + newline = "\n"+what +" "+value+";\n"; + } + + if(grepp(globalstr3,value)) { + write("That object already contains that line."); + return 1; + } + if(what == "inherit"){ + globalstr3 = this_object()->eventAppend(globalstr3,({"inherit "}),newline); + } + + else { + if(grepp(globalstr3,what)){ + globalstr3 = replace_string(globalstr3,".h>\n",".h>;\n"); + globalstr3 = replace_string(globalstr3,".h\"\n",".h\";\n"); + unguarded( (: write_file(globalstr,globalstr3,1) :) ); + + globalstr3 = this_object()->eventAppend(globalstr3,({"#include "}),newline); + globalstr3 = replace_string(globalstr3,".h>;\n",".h>\n"); + globalstr3 = replace_string(globalstr3,".h\";\n",".h\"\n"); + + } + else { + globalstr3 = this_object()->eventAppend(globalstr3,({"inherit "}),newline); + } + } + + globalstr = generate_tmp(ob); + unguarded( (: write_file(globalstr,globalstr3,1) :) ); + + if( catch(load_object(globalstr))){ + write("This change would hose up the object. Modification aborted."); + return 1; + } + + unguarded( (: cp(globalstr, globalstr2) :) ); + reload(ob); + rm(tmpfile); + return 1; +} + +int eventAddCreate(string file){ + string *contents, *temparray, *temparray2, *beginners; + string tmpfile; + int done, add, memnum; + + globalstr = tmpfile; + globalstr2 = file; + + if(file_exists(file) && !check_privs(this_player(),file)){ + write("You do not appear to have write access to this file. Modification aborted."); + return 1; + } + + tmpfile = generate_tmp(file); + temparray = ({}); + temparray2 = ({}); + contents = unguarded( (: eventReadFunctions(globalstr2) :) ); + beginners = ({"private","static","nomask","varargs"}); + beginners += ({"int","void","buffer","mapping","mixed","string","array","float"}); + + foreach(string func in contents){ + if(member_array(func,contents) != 0 && grepp(func,"void create")) memnum = member_array(func,contents); + } + + if(memnum && memnum != -1){ + if(!grepp(contents[memnum],"::create()")){ + temparray = explode(contents[memnum],"\n"); + foreach(string line in temparray){ + if(line && !starts_with_arr(line, beginners)) add = 1; + if(add && !done) { + temparray2 += ({"::create();"}); + temparray2 += ({line}); + done = 1; + } + else { + temparray2 += ({line}); + } + } + contents[memnum] = implode(temparray2,"\n"); + global_array = contents; + globalstr3 = tmpfile; + unguarded( (: write_file(globalstr3,implode(global_array,"\n"),1) :) ); + } + + else { + return 2; + } + } + + global_array = contents; + globalstr3 = tmpfile; + unguarded( (: write_file(globalstr3,implode(global_array,"\n"),1) :) ); + globalstr = tmpfile; + globalstr2 = file; + done = unguarded( (: cp(globalstr, globalstr2) :) ); + unguarded( (: rm(globalstr) :) ); + return done; +} + + + diff --git a/lib/secure/modules/generic.c b/lib/secure/modules/generic.c new file mode 100644 index 0000000..8b0afa9 --- /dev/null +++ b/lib/secure/modules/generic.c @@ -0,0 +1,254 @@ +#include +#include +#include +#include ROOMS_H + +int eventGetArray(string str); +int eventDoAddition(string str); + +string globalstr, globalstr2, temporary, func, v2, repstr; +object target; +string *NewArr = ({}); +string *array_val = ({}); +mapping InvMap = ([]); + +mixed gmake(string str) { + string thingy, filename, val, dir, area_dir; + string creation; + string *legal_dirs; + object template; + + if(sscanf(str, "%s %s %s",thingy, val, filename) == 3) true(); + else if(sscanf(str,"%s %s",thingy, filename) !=2) thingy = str; + switch(thingy){ + case "item" : creation = "thing"; dir = "obj";break; + case "book" : creation = "book"; dir = "obj";break; + case "thing" : creation = "thing"; dir = "obj";break; + case "weap" : creation = "weapon"; dir = "weap";break; + case "weapon" : creation = "weapon"; dir = "weap";break; + case "armor" : creation = "armor"; dir = "armor";break; + case "arm" : creation = "armor"; dir = "armor";break; + case "chair" : creation = "chair"; dir = "obj";break; + case "bed" : creation = "bed"; dir = "obj";break; + case "storage" : creation = "container"; dir = "obj";break; + case "container" : creation = "container"; dir = "obj";break; + case "table" : creation = "table"; dir = "obj";break; + case "door" : creation = "door"; dir = "doors";break; + case "barkeep" : creation = "barkeep"; dir = "npc";break; + case "vendor" : creation = "vendor"; dir = "npc";break; + case "trainer" : creation = "trainer"; dir = "npc";break; + case "npc" : creation = "npc"; dir = "npc";break; + case "mob" : creation = "npc"; dir = "npc";break; + case "mon" : creation = "npc"; dir = "npc";break; + case "monst" : creation = "npc"; dir = "npc";break; + case "monster" : creation = "npc"; dir = "npc";break; + case "meal" : creation = "meal"; dir = "meals";break; + case "food" : creation = "meal"; dir = "meals";break; + case "drink" : creation = "drink"; dir = "meals";break; + case "worn" : creation = "worn_storage"; dir = "armor";break; + case "wornstorage" : creation = "worn_storage"; dir = "armor";break; + case "worn_storage" : creation = "worn_storage"; dir = "armor";break; + default : true(); + } + + legal_dirs = ({"meals","doors", "obj","armor","weap","npc"}); + if(member_array(dir, legal_dirs) == -1) { + write("That is not a valid argument. You may create the following: room, npc, "+ + "door, weapon, armor, container, item, table, chair, bed, meal, worn_storage."); + return 1; + } + + else if(!filename || filename == ""){ + write("You must specify a filename. For example: create "+creation+ + " "+thingy+"_14.c"); + write("or: create "+thingy+" /realms/my_name/area/"+dir+"/my_first_"+creation+".c"); + return 1; + } + + filename = replace_string(filename, " ", "_"); + + if(last(filename,2) != ".c") filename += ".c"; + + if(!this_player()->query_cwd()){ + write("You have no current working directory. Please type: cd\nthen try again."); + return 1; + } + + if(grepp(filename,"/") && directory_exists(path_prefix(filename)) && + check_privs(this_player(), filename)){ + write("Ok, using yer filename: "+filename); + } + else if(last_string_element(this_player()->query_cwd(),"/") == dir && + check_privs(this_player(), this_player()->query_cwd())){ + write("Using your cwd: "+this_player()->query_cwd()+"/"+filename); + filename = this_player()->query_cwd()+"/"+filename; + } + else if(this_player()->query_cwd() != "/" && + member_array(dir,get_dir(this_player()->query_cwd()+"/")) != -1 && + check_privs(this_player(), this_player()->query_cwd()+"/"+dir)){ + write("Using your cwd plus "+dir+": "+this_player()->query_cwd()+"/"+dir+"/"+filename); + filename = this_player()->query_cwd()+"/"+dir+"/"+filename; + } + else if(member_array(dir,get_dir(path_prefix(this_player()->query_cwd())+"/")) != -1 && + check_privs(this_player(), path_prefix(this_player()->query_cwd())+"/"+dir)){ + write("Using your cwd plus ../"+dir+": "+path_prefix(this_player()->query_cwd())+"/"+dir+"/"+filename); + filename = path_prefix(this_player()->query_cwd())+"/"+dir+"/"+filename; + } + else { + area_dir = homedir(this_player())+"/area"; + write("I'm going to go with the appropriate area directory: "+area_dir+"/"+dir+"/"+ + replace_string(filename,"/","")); + filename = area_dir+"/"+dir+"/"+replace_string(filename,"/",""); + + } + + creation = "/obj/"+creation+".c"; + if(file_exists(creation) && cp(creation,filename)) true(); + else { + write("Creation failed."); + return 1; + } + + if(thingy != "door") { + template = new(filename); + template->eventMove(environment(this_player())); + write("You wave your hand mysteriously and "+template->GetShort()+" materializes!"); + say(this_player()->GetCapName()+" waves "+possessive(this_player())+" hand mysteriously and "+template->GetShort()+" materializes!"); + } + + else { + write("You wave your hand mysteriously and a new door begins to materialize."); + say(this_player()->GetCapName()+" waves "+possessive(this_player())+" hand mysteriously and a new door begins to materialize."); + this_object()->eventCreateDoor(val, filename); + } + return 1; +} + +varargs int eventStartGenericQuestions(object ob, string tempfile, string *new_arr, string what){ + target = ob; + temporary = tempfile; + NewArr -= ({ 0 }); + NewArr = new_arr; + func = what; + write("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."); + if(NewArr && sizeof(NewArr)) array_val = NewArr; + else array_val = ({}); + array_val -= ({0}); + array_val -= ({"0"}); + if(sizeof(array_val)) + write("You may now enter the next value. So far, we have: "+identify(array_val)); + else write("You may now enter the next value. So far, it is blank."); + write("If you're done entering values, enter a dot on a blank line."); + + input_to( (: eventGetArray :) ); + return 1; +} + +int eventGetArray(string str){ + if(!str || str == "" || str == "."){ + write("Entries complete. Final array is: "+identify(array_val)); + NewArr = array_val; + if(!sizeof(array_val)){ + write("Blank array. Modification cancelled."); + return 1; + } + if(target->GetDoor() || inherits(LIB_DOOR,target)){ + this_object()->eventReceiveId(target, NewArr); + } + else this_object()->eventResumeArrayMod(target, temporary, NewArr, func); + array_val = ({}); + return 1; + } + else { + array_val += ({str}); + array_val -= ({0}); + array_val -= ({"0"}); + if(sizeof(array_val)) + write("You may now enter the next value. So far, we have: "+identify(array_val)); + else write("You may now enter the next value. So far, it is blank."); + write("If you're done entering values, enter a dot on a blank line."); + input_to( (: eventGetArray :) ); + } + + return 1; +} +int eventDeleteItem(object ob1, object ob2){ + string name, tmpname; + mapping Inventory; + + name = base_name(ob1); + if(!check_privs(this_player(), base_name(ob2)) ){ + write("Insufficient privileges. Addition halted."); + return 1; + } + + tmpname = generate_tmp(); + Inventory = this_object()->QueryMap("SetInventory",ob2); + if(sizeof(Inventory[name])) map_delete(Inventory,name); + else if(sizeof(Inventory[name+".c"])) map_delete(Inventory,name+".c"); + map_delete(Inventory,name); + map_delete(Inventory,name+".c"); + globalstr = tmpname; + globalstr2 = base_name(ob2)+".c"; + unguarded( (: cp(globalstr2, globalstr) :) ); + this_object()->eventResumeMappingChange(ob2, tmpname, Inventory, "SetInventory"); + unguarded( (: rm(globalstr) :) ); + return 1; +} + +int eventAddItem(object ob, string addendum){ + target = ob; + v2 = addendum; + if(!check_privs(this_player(), base_name(target))){ + write("Insufficient privileges. Addition halted."); + return 1; + } + this_object()->eventGeneralStuff(base_name(ob)+".c"); + + InvMap = this_object()->QueryMap("SetInventory",ob); + if(!inherits(LIB_NPC,ob)){ + write("Please enter the number of these that you want to add:"); + } + else write("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:"); + input_to( (: eventDoAddition :) ); + return 1; +} + +int eventDoAddition(string str){ + this_object()->GetTheValue("AUTOMATED",target, generate_tmp(target), v2, str, InvMap, "SetInventory"); + return 1; +} + +int eventGeneralStuff(string str){ + string fpath = path_prefix(str); + mixed player = this_player(); + repstr = ""; + globalstr = str; + unguarded( (: globalstr2 = read_file(globalstr) :) ); + unguarded( (: this_object()->eventAddInit(globalstr) :) ); + if(sscanf(globalstr, "/realms/%s/workroom.c", player)){ + globalstr2 = replace_string(globalstr2, "./area/customdefs.h", + "/realms/"+player+"/area/customdefs.h"); + } + if(query_verb() != "copy"){ + if(grepp(globalstr2,"./customdefs.h")){ + string j1, j2, tmppath; + sscanf(globalstr2,"%sinclude \"%scustomdefs.h%s",j1,tmppath,j2); + if(tmppath) repstr = absolute_path(fpath,tmppath+"customdefs.h"); + unguarded( (: globalstr2 = replace_line(globalstr2 ,({"./customdefs.h"}), "#include \""+repstr+"\"") :) ); + } + } + globalstr2 = replace_string(globalstr2,"\n\n\n","\n\n"); + globalstr2 = replace_string(globalstr2,"//funs",""); + globalstr2 = replace_string(globalstr2,"//snuf",""); + globalstr2 = replace_string(globalstr2,"//extras",""); + unguarded( (: write_file(globalstr, globalstr2, 1) :) ); + write("Indenting file..."); + unguarded( (: indent_file(globalstr) :) ); + repstr = ""; + return 1; +} diff --git a/lib/secure/modules/mapping.c b/lib/secure/modules/mapping.c new file mode 100644 index 0000000..f623dfa --- /dev/null +++ b/lib/secure/modules/mapping.c @@ -0,0 +1,348 @@ +#include +#include +#include + +string globaltmp, globalstr, globalstr2, func, data, temporary; +int automated; +object target; +mixed newval; + +int GetKey(string str); +varargs mapping GetTheValue(string str, object targ, string tempy, string k1, string v1, mapping MapThing, string passed_fun); + +string *key_arr = ({}); +mapping NewMap = ([]); + +int eventStoreMapping(string savefile, mapping plan){ + string filename = "/tmp/"+savefile; + if(file_exists(filename) && !check_privs(this_player(),filename)){ + write("You do not appear to have write access to this file. Modification aborted."); + return 1; + } + store_variable("data", plan); +} + +varargs int eventStartMappingQuestions(mapping oldmap, object ob, string tmpfile, string auto){ + if(ob) target = ob; + if(tmpfile) temporary = tmpfile; + if(auto && auto != "") { + automated = 1; + func = auto; + } + + if(ob && !check_privs(this_player(),ob)){ + write("You do not appear to have write access to this file. Modification aborted."); + return 1; + } + + if(file_exists(temporary) && !check_privs(this_player(),temporary)){ + write("You do not appear to have write access to this file. Modification aborted."); + return 1; + } + if(sizeof(oldmap)) NewMap = oldmap; + else NewMap = ([]); + key_arr = ({}); + write("If you don't understand these questions, type the letter q on a blank "+ + "line and hit enter.\n"); + write("Please enter the first key element for this mapping:\n"); + input_to( (: GetKey :) ); + return 1; +} + +int GetKey(string str){ + if(file_exists(temporary) && !check_privs(this_player(),temporary)){ + write("You do not appear to have write access to this file. Modification aborted."); + return 1; + } + if(str && str == "q" ) { + write("Aborting modification. For information on mappings, type: help mappings"); + rm(temporary); + return 1; + } + if(!str || str == "" || str == "."){ + if(!sizeof(key_arr)){ + write("Aborting modification. For information on mappings, type: help mappings"); + rm(temporary); + return 1; + } + write("Please enter the value for key "+identify(key_arr)+":\n"); + input_to( (: GetTheValue :) ); + return 1; + } + else { + key_arr += ({ str }); + write("Please enter the next key element, or enter a single dot to " + "finish entering key elements."); + input_to( (: GetKey :) ); + return 1; + } +} + +varargs mapping GetTheValue(string str, object targ, string tempy, string k1, string v1, mapping MapThing, string passed_fun){ + int i; + string repl_key; + string *mapkeys; + + if(!str && !targ && !tempy && !k1 && !v1){ + return 0; + } + if(str == "AUTOMATED"){ + NewMap = ([]); + automated = 1; + target = targ; + key_arr = ({ k1 }); + temporary = tempy; + str = v1; + if(sizeof(MapThing)) NewMap = MapThing; + func = passed_fun; + unguarded( (: cp(base_name(target)+".c",temporary) :) ); + } + if(file_exists(temporary) && !check_privs(this_player(),temporary)){ + write("You do not appear to have write access to this file. Modification aborted."); + return ([]); + } + if(!str || str == "" || str == "." || str == "q") { + write("Aborting modification. For information on mappings, type: help mappings"); + rm(temporary); + return ([]); + } + + if(sscanf(str,"%d",i) == 1) newval = i; + else newval = str; + + if(sizeof(replace_string(str, itoa(i), ""))) newval = str; + + mapkeys = keys(NewMap); + foreach(mixed llave in mapkeys){ + foreach(string nueva_llave in key_arr){ + if(arrayp(llave) && member_array(nueva_llave,llave) != -1) repl_key = llave; + else if(stringp(llave) && nueva_llave == llave ) repl_key = llave; + } + } + + if(repl_key || repl_key != "") map_delete(NewMap, repl_key); + if(sizeof(key_arr) > 1) NewMap[key_arr] = newval; + else NewMap[key_arr[0]] = newval; + if(automated){ + automated = 0; + if(func) this_object()->eventResumeMappingChange(target, temporary, NewMap, func); + else this_object()->eventResumeMappingChange(target, temporary, NewMap); + } + return copy(NewMap); +} + +varargs string eventStringifyMap(mapping source, string key_excl, string val_excl){ + string map_str, key; + mixed val; + + if(!key_excl) key_excl = ""+time(); + if(!val_excl) val_excl = ""+time(); + + map_str = "([\n"; + + foreach( key, val in source){ + if(intp(val)){ + map_str += identify(key) + " : " + val +",\n"; + } + else if(stringp(val) && last(val,1) == "'" && first(val,1) == "'"){ + val = replace_string(val,"'",""); + map_str += identify(key) + " : " + val +",\n"; + } + else + map_str += identify(key) + " : " + identify(val) +",\n"; + } + map_str += "])"; + return map_str; +} + + + +string eventReadThing(string map){ + // This doesn't actually work yet, and perhaps never will, + // but I'm leaving it here to remind myself to fix it. + // -Crat + + string new_string; + int i, iterations; + string *arr; + string *new_arr = ({}); + + new_string = ""; + arr = explode(map,":"); + + foreach(string element in arr){ + string s1, s2, type; + int num; + if(!sizeof(new_arr)) new_arr = ({ replace_string(element,"\"", "") }); + else if(sizeof(element) && element != ""){ + + if(sscanf(element,"%d ,%s",num,s1) != 2) { + sscanf(element,"%d,%s",num,s1); + type = "int"; + } + if(!s1 || s1 == "") { + sscanf(element,"(:%s:)%s", s1, s2); + type = "function"; + } + if(!s2 || s2 == "") { + sscanf(element,"([%s])%s", s1, s2); + type = "mapping"; + } + if(!s2 || s2 == "") { + sscanf(element,"\"%s\"%s", s1, s2); + type = "string"; + } + if(!s2 || s2 == "") { + s1 = element; + type = "null"; + } + + if(!type || type == ""){ + write("Whoops! An incomprehensible error occurs."); + return ""; + } + + if(type == "int") new_arr += ({ ""+num }); + else if(type == "function") new_arr += ({ "(: "+s1+" :)" }); + else if(type == "mapping") new_arr += ({ "([ "+s1+" ])" }); + else if(type == "string") new_arr += ({ "\""+s1+"\"" }); + else if(type == "null") new_arr += ({ replace_string(s1,",","",1) }); + } + } + + iterations = sizeof(new_arr); + + for( i = 0; i < (iterations -2) ; i = i+2 ){ + new_string += new_arr[i]+" : "+new_arr[i+1]+",\n"; + } + new_string += new_arr[iterations -1]+"\n"; + + new_string += "])"; + + return new_string; +} + +int eventSpecialMapHandler(object ob, string func, mixed mode, mixed value){ + string tmp, filename, func2, junk, junk2; + string *plural_maps; + int integer; + mapping NewMap = ([]); + mapping FirstMap = ([]); + mapping SecondMap = ([]); + + plural_maps = ({ "SetProperties" }); + if(stringp(value)) value = trim(replace_string(value,mode,"")); + + if(stringp(value) && !grepp(lower_case(func),"prop") ){ + if(sscanf(value,"%d",integer) != 1 && + sscanf(value,"%d %s",integer,junk) != 2) { + sscanf(value,"%s %s",tmp,junk); + if(!tmp || !junk) value = 0; + else if(sscanf(junk,"%d",integer) != 1) sscanf(junk,"%d %s",integer,junk2); + if(tmp) mode += " "+tmp; + } + if(integer) value = integer; + else value = 0; + if(!intp(value)) value = 0; + } + + else { + if(sscanf(value,"%s %s",tmp, junk) == 2){ + mode += " "+tmp; + value = trim(junk); + } + } + + filename = base_name(ob)+".c"; + if(!check_privs(this_player(),filename)){ + write("You do not appear to have write access to this file. Modification aborted."); + return 1; + } + if(!mode || !value){ + write("Invalid entry. Modification cancelled."); + return 1; + } + + globalstr = filename; + unguarded( (: globalstr2 = read_file(globalstr) :) ); + + + switch(func){ + case "SetProperties" : func2 = "SetProperty";break; + case "SetSkills" : func2 = "SetSkill";break; + case "SetStats" : func2 = "SetStat";break; + } + + FirstMap = this_object()->eventReadPair(filename, func2, 1); + SecondMap = this_object()->eventReadMapping(filename, ({ func }), 1); + NewMap = add_maps(FirstMap, SecondMap); + if(stringp(value) && sscanf(value,"%d",integer) == 1) { + NewMap[mode] = integer; + } + else NewMap[mode] = value; + globaltmp = generate_tmp(ob); + unguarded( (: write_file(globaltmp,globalstr2,1) :) ); + + if(member_array(func,plural_maps) != -1) + this_object()->eventResumeMappingChange(ob,globaltmp,copy(NewMap),func); + else this_object()->eventAddSettings(ob,globaltmp,copy(NewMap),func2); + return 1; +} + +mapping eventReadPair(string filename, string param, int destructive){ + mixed numerator, denominator; + int integer; + string s1, junk, contents, tmp; + string *file_arr, *line_arr; + mapping NewMap = ([]); + + if(file_exists(filename) && !check_privs(this_player(),filename)){ + write("You do not appear to have write access to this file. Modification aborted."); + return ([]); + } + + globalstr = filename; + if(file_exists(filename)) { + unguarded( (: globalstr2 = read_file(globalstr) :) ); + } + contents = globalstr2; + file_arr = explode(contents,"\n"); + line_arr = ({}); + + foreach(string line in file_arr){ + if(grepp(line,param)) line_arr += ({ line }); + } + + if(!sizeof(line_arr)) return ([]); + + foreach(string element in line_arr){ + element = trim(element); + if(sscanf(element,param+"(%s);",s1) != -1) sscanf(element,param+"(%s) ;",s1); + if(!s1) sscanf(element,param+" (%s);",s1,junk); + sscanf(s1,"%s,%s",denominator,numerator); + numerator = trim(numerator); + denominator = trim(denominator); + if(sscanf(denominator,"\"%s\"",junk) == 1) denominator = junk; + if(sscanf(numerator,"%d",integer) == 1) numerator = integer; + else if(sscanf(numerator,"\"%s\"",junk) == 1) numerator = junk; + if(stringp(numerator)) numerator = trim(numerator); + denominator = trim(denominator); + NewMap[denominator] = numerator; + } + + if(destructive) { + globalstr2 = remove_matching_line(globalstr2, param, 1); + globalstr = generate_tmp(); + unguarded( (: write_file(globalstr,globalstr2,1) :) ); + tmp = globalstr; + globalstr = filename; + globalstr2 = tmp; + unguarded( (: cp(globalstr2, globalstr) :) ); + rm(tmp); + } + return copy(NewMap); +} + + + + diff --git a/lib/secure/modules/money.c b/lib/secure/modules/money.c new file mode 100644 index 0000000..ec7c06b --- /dev/null +++ b/lib/secure/modules/money.c @@ -0,0 +1,105 @@ +#include +#include +#include +#include +#include +#include ROOMS_H + + +string globalstr, globalstr2, globalstr3, globaltmp; +mapping TmpMap = ([]); +mapping LoadMap = ([]); + +int eventModCost(object ob, string type, mixed val); + +int eventModMoney(object ob, string type, mixed val){ + string junk1; + int amount, npc; + mapping NewMap; + + TmpMap = ([]); + NewMap = ([]); + LoadMap = ([]); + globalstr = ""; + globalstr2 = ""; + globalstr3 = ""; + + + if(inherits(LIB_NPC,ob)) npc = 1; + + if(!intp(val) ) sscanf(val,"%s %d",junk1,amount); + if(amount) val = amount; + else val = 0; + amount = 0; + + globalstr3 = base_name(ob)+".c"; + globalstr = generate_tmp(ob); + unguarded( (: cp(globalstr3, globalstr) :) ); + if(!check_privs(this_player(),globalstr3)){ + write("You do not appear to have write access to this file. Modification aborted."); + return 1; + } + if(npc){ + unguarded( (: TmpMap = this_object()->eventMappifyLine(globalstr,"SetCurrency") :) ); + LoadMap = this_object()->eventParsePair(globalstr,"AddCurrency","string","literal"); + foreach(string foo, mixed bar in LoadMap) if(stringp(bar)) LoadMap[foo] = amount; + unguarded( (: globaltmp = remove_matching_line(globalstr,"AddCurrency",1) :) ); + unguarded( (: globaltmp = remove_matching_line(globaltmp,"SetCurrency",1) :) ); + globalstr2 = "SetCurrency( "; + NewMap = add_maps(LoadMap,TmpMap); + } + + else { + unguarded( (: TmpMap = this_object()->eventMappifyLine(globalstr,"SetMoney") :) ); + LoadMap = this_object()->eventParsePair(globalstr,"AddMoney","string","literal"); + foreach(string foo, mixed bar in LoadMap) if(stringp(bar)) LoadMap[foo] = amount; + unguarded( (: globaltmp = remove_matching_line(globalstr,"AddMoney",1) :) ); + unguarded( (: globaltmp = remove_matching_line(globaltmp,"SetMoney",1) :) ); + globalstr2 = "SetMoney( "; + NewMap = add_maps(copy(LoadMap),copy(TmpMap)); + } + + if(stringp(val)) val = amount; + NewMap[type] = val; + globalstr2 += this_object()->eventStringifyMap(NewMap) + " );"; + globaltmp = this_object()->eventAppend(read_file(globaltmp),({"SetItems","SetInventory","SetLong"}),"\n"+globalstr2+"\n"); + unguarded( (: write_file(globalstr,globaltmp,1) :) ); + this_object()->eventGeneralStuff(globalstr); + unguarded( (: cp(globalstr,globalstr3) :) ); + unguarded( (: rm(globalstr) :) ); + reload(ob); + return 1; +} + +int eventModCost(object ob, string type, mixed val){ + string new_line, junk; + int amount; + + if(stringp(val)) sscanf(val,"%s %d",junk,amount); + else amount = val; + globalstr = base_name(ob)+".c"; + if(!check_privs(this_player(),globalstr)){ + write("You do not appear to have write access to this file. Modification aborted."); + return 1; + } + + unguarded( (: globalstr2 = read_file(globalstr) :) ); + + globalstr2 = remove_matching_line(globalstr2,"SetBaseCost",1); + globalstr2 = remove_matching_line(globalstr2,"SetDollarCost",1); + globalstr2 = remove_matching_line(globalstr2,"SetCost",1); + globalstr2 = remove_matching_line(globalstr2,"SetValue",1); + + if(!type) type = "silver"; + + new_line = "SetBaseCost(\""+type+"\", "+amount+");"; + globalstr2 = this_object()->eventAppend(globalstr2,({"SetMass","SetItems","SetLong","SetInventory","SetVendorType"}), "\n"+new_line+"\n"); + + unguarded( (: write_file(globalstr, globalstr2, 1) :) ); + + this_object()->eventGeneralStuff(globalstr); + reload(ob); + + + return 1; +} diff --git a/lib/secure/modules/read.c b/lib/secure/modules/read.c new file mode 100644 index 0000000..5756292 --- /dev/null +++ b/lib/secure/modules/read.c @@ -0,0 +1,120 @@ +#include +#include +string globalstr, globalstr2, globalstr3; + +mixed eventReadValue(string str, string method){ + string val, junk1, junk2; + int value, quid; + string substr = this_object()->ReadMatchingLine(str,method); + quid = sscanf(substr,"%s"+last(method,2)+"("+"%s"+")%s",junk1, val, junk2); + if(quid < 3) return 0; + val = trim(val); + sscanf(val,"%d",value); + if(value) return value; + else return this_object()->eventCleanString(val); +} + +varargs string ReadMatchingLine(string target, string substring, string exclude){ + int omit, done, tail_search, i; + string line, filename, new_file; + globalstr = ""; + globalstr2 = ""; + globalstr3 = ""; + + if(!grepp(target,"\n") && file_exists(target)) target = read_file(target); + + if(!target) return ""; + if(strsrch(target,substring) == -1) return ""; + if(strsrch(target,"\n") == -1) return ""; + filename = generate_tmp(this_object()); + new_file = ""; + if(!exclude) exclude = filename; + + write_file(filename,target); + + omit = 1; + for(i=1; !done; i++){ + line = read_file(filename, i, 1); + if(!line) break; + if(grepp(line,substring) ) { + omit =0; + } + if(!omit && truncate(last(line,2,1),1) != ";") { + tail_search = 1; + } + else { + tail_search = 0; + } + + if(!omit) { + new_file += line; + } + + if(!tail_search) omit = 1; + if(!line) done = 100; + if(i == 999) done = 100; + } + + rm(filename); + return new_file; +} + +mapping eventParsePair(string file, string param, string type, string mode){ + mixed val, key; + string func, junk; + int tempint; + mapping RetMap = ([]); + string line = this_object()->ReadMatchingLine(file, param); + sscanf(line,"%s(%s,%s);%s",func,key,val,junk); + if(!key || !val) { + return ([]); + } + if(sscanf(val,"%d",tempint) && !alphap(val)) val = tempint; + key = this_object()->eventCleanString(key); + if(stringp(val)) val = this_object()->eventCleanString(val); + RetMap[key] = val; + return RetMap; +} + +string eventCleanString(string str){ + str = replace_string(str,"\n",""); + str = replace_string(str,"\t",""); + str = replace_string(str,"\"",""); + str = space_trim(str); + str = trim(str); + return str; +} + +mapping eventMappifyLine(string file, string param){ + mixed RetMap; + string schmutz; + + schmutz = this_object()->ReadMatchingLine(file, param); + if(!grepp(schmutz,param)) return ([]); + schmutz = this_object()->eventExtractMapString(schmutz); + schmutz = replace_string(schmutz,"\n",""); + schmutz = replace_string(schmutz,"\t",""); + schmutz = replace_string(schmutz," : ",":"); + schmutz = space_trim(schmutz); + schmutz = replace_string(schmutz,", \"",",\""); + schmutz = trim(schmutz); + if(last(schmutz,1) != ","){ + schmutz = "(["+schmutz+",])"; + } + else schmutz = "(["+schmutz+"])"; + RetMap = restore_variable(schmutz); + if(!mapp(RetMap)){ + write("Mappification unsuccessful."); + return ([]); + } + else return RetMap; +} + +string eventExtractMapString(string str){ + string meat, junk1, junk2; + str = replace_string(str,"[","OPENBRACKET",1); + str = reverse_string(replace_string(reverse_string(str),"]","TEKCARBESOLC",1)); + sscanf(str,"%sOPENBRACKET%sCLOSEBRACKET%s",junk1,meat,junk2); + return meat; +} + diff --git a/lib/secure/modules/room.c b/lib/secure/modules/room.c new file mode 100644 index 0000000..79d9bd2 --- /dev/null +++ b/lib/secure/modules/room.c @@ -0,0 +1,556 @@ +#include +#include + +private string globalstr, globalstr2, globaltmp; +private string globalroom, globalfile; + +varargs int eventCreateExit(string dir, string room, string file, int remote); +varargs int eventCreateEnter(string dir, string room, string file, int remote); +int eventRemoveExit(string dir, string filename); +varargs mixed eventProcessExits(string filename, string dir, string location); +varargs mixed eventProcessEnters(string filename, string dir, string location, object room); +string eventCopyRoom(string source, string dest); + +string *cardinal_dirs = ( ({"none", "north","south","east","west", "northeast","northwest","southeast","southwest","up","down", "out"}) ); + +mixed make(string str) { + int enter; + int blank = 0; + string *exits; + string *enters; + string foo, current_dir, current_room, this_room, new_room, room_dir; + string tmp_path, new_file, arg1, arg2, s1, s2; + object room; + globalstr = globalstr2 = globaltmp = ""; + + if(!str || str == "") { + write("You'll need to be more specific. Try 'help create'"); + return 1; + } + + if(environment(this_player())->GetDirectionMap()){ + write("This is a virtual room. It cannot be modified with the QCS."); + return 1; + } + + if(sscanf(str," %s %s", s1, s2) == 2){ + arg1 = s1; + arg2 = s2; + if(sizeof(opposite_dir(arg1))) enter = 0; + else enter = 1; + } + else { + write("Usage: create room "); + return 1; + } + + if(arg1 == "none") blank = 1; + + foo = ""+time(); + room = environment(this_player()); + current_dir = this_player()->query_cwd(); + current_room = base_name(room); + if(!blank) room_dir = path_prefix(current_room); + else room_dir = current_dir; + + if(file_exists(current_room+".c") && !check_privs(this_player(),current_room+".c")){ + write("You do not appear to have write access to this room file. Modification aborted."); + return 1; + } + + if(!write_file(room_dir+"/"+foo+".foo","",1)) { + write("You do not have write privileges to this area."); + return 1; + } + + rm(room_dir+"/"+foo+".foo"); + write("It appears you have write access to this area."); + this_room = read_file(current_room+".c"); + new_room = read_file("/obj/room.c"); + + if(!blank){ + + if(environment(this_player())->GetNoModify() ){ + write("This should be edited by hand. Change cancelled."); + write("Please see http://dead-souls.net/ds-creator-faq.html#2.69"); + return 1; + } + + exits = room->GetExits(); + enters = room->GetEnters(); + + if(member_array(arg1,exits) != -1){ + write("This room already has an exit in that direction."); + return 1; + } + + if(member_array(arg1,enters) != -1){ + write("This room already has an enter by that name."); + return 1; + } + } + + if(strsrch(arg2,".c") == -1) arg2 += ".c"; + if(strsrch(arg2," ") != -1) arg2 = replace_string(arg2," ","_"); + + if(file_exists(arg2)) new_file = arg2; + else if(strsrch(arg2,"./") != -1) { + arg2 = replace_string(arg2,"./",""); + new_file = absolute_path(this_player()->query_cwd(), arg2); + } + else if(directory_exists(path_prefix(arg2))){ + new_file = arg2; + } + else if(grepp(arg2,"/")){ + new_file = room_dir +"/"+ last_string_element(arg2,"/"); + } + + else { + new_file = room_dir +"/"+ arg2; + } + + if(!check_privs(this_player(),new_file)){ + write("Invalid directory."); + return 1; + } + + if(new_file[0..7] == "/realms/" && strsrch(new_file,"/area/room/") != -1){ + if(!file_exists(new_file)) cp("/obj/area_room.c",new_file); + } + else { + if(!file_exists(new_file)) cp("/obj/room.c",new_file); + } + + if(blank){ + reload(new_file); + this_player()->eventMoveLiving(new_file); + return 1; + } + + if(enter == 0) eventCreateExit(arg1, current_room+".c", new_file); + else eventCreateEnter(arg1, current_room+".c", new_file); + if(file_exists(new_file) && + grepp(read_file(new_file),"SetShort(\"a blank room\");") ) { + eventCopyRoom(current_room+".c", new_file); + reload(new_file); + } + return 1; +} + +varargs int eventCreateExit(string dir, string room, string file, int remote){ + string param; + string *file_arr; + + if(file_exists(room) && !check_privs(this_player(),room)){ + write("You do not appear to have write access to this room file. Modification aborted."); + return 1; + } + + if(member_array(dir,cardinal_dirs) == -1) { + this_object()->eventCreateEnter(dir, room, file, remote); + return 1; + } + + globalstr = room; + unguarded( (: globaltmp = read_file(globalstr) :) ); + file_arr = explode(globaltmp,"\n"); + + if(remote && member_array(dir,load_object(room)->GetExits()) != -1) return 0; + + if(strsrch(globaltmp,"SetExits") != -1) param = "SetExits"; + else if(strsrch(globaltmp,"AddExit") != -1) param = "AddExit"; + else if(strsrch(globaltmp,"SetLong") != -1) param = "SetLong"; + else { + } + globaltmp = remove_matching_line(globaltmp,"SetObviousExits",1); + globaltmp = remove_matching_line(globaltmp,"//extras",1); + unguarded( (: write_file(globalstr,globaltmp,1) :) ); + reload(room); + eventProcessExits(room, dir, file); + + if(!remote) { + eventCreateExit(opposite_dir(dir), file, room, 1 ); + write("You begin uttering a magical incantation."); + say(this_player()->GetCapName()+" begins uttering a magical incantation."); + this_object()->eventGeneralStuff(room); + } + this_object()->eventAddInit(room); + if(remote){ + this_object()->eventGeneralStuff(room); + write("You wave your hand, and a new exit appears."); + say(this_player()->GetCapName()+" waves "+possessive(this_player())+" hand and a new exit appears."); + } + return 1; +} + +int eventRemoveExit(string dir, string filename){ + string contents, search_str, map_str, key, val, new_file, tmpfile; + string *file_arr; + mapping PointlessMap; + mapping ExitsMap = load_object(filename)->GetExitMap(); + + if(file_exists(filename) && !check_privs(this_player(),filename)){ + write("You do not appear to have write access to this room's file. Modification aborted."); + return 1; + } + + tmpfile = generate_tmp(load_object(filename)); + globalstr = filename; + globaltmp = tmpfile; + unguarded( (: globalstr2 = read_file(globalstr) :) ); + contents = globalstr2; + PointlessMap = ([]); + + PointlessMap = load_object(filename)->GetFullExitData(); + + if( member_array(dir,load_object(filename)->GetExits()) != -1 + && !functionp(PointlessMap[dir]["pre"]) + && !functionp(PointlessMap[dir]["post"]) ) { + this_object()->eventReadMapping(filename,({"SetExits"}), 1); + map_delete(ExitsMap,dir); + map_str = "SetExits( ([ \n"; + foreach( key, val in ExitsMap){ + if(!functionp(PointlessMap[key]["pre"]) + && !functionp(PointlessMap[key]["post"])) map_str += "\""+key+"\" : \""+val+"\",\n"; + } + map_str += "]) );"; + + unguarded( (: globalstr2 = read_file(globalstr) :) ); + contents = globalstr2; + + new_file = remove_matching_line(contents, "SetExits", 1); + new_file = this_object()->eventAppend(new_file,({"SetItems","SetLong","SetDayLong","SetNightLong"}),"\n"+map_str+"\n"); + new_file = remove_matching_line(new_file,"SetObviousExits"); + new_file = remove_matching_line(new_file,"//extras"); + new_file = remove_matching_line(new_file,"AddExit(", 1, ":)"); + globalstr2 = new_file; + unguarded( (: write_file(globaltmp,globalstr2,1) :) ); + this_object()->eventGeneralStuff(tmpfile); + globalstr = tmpfile; + globalstr2 = filename; + unguarded( (: cp(globalstr, globalstr2) :) ); + reload(filename); + rm(tmpfile); + write("With a puff of smoke, an exit vanishes!"); + return 1; + } + + + if(member_array(dir,load_object(filename)->GetExits()) != -1){ + globalstr = filename; + new_file = read_file(filename); + file_arr = explode(read_file(filename),"\n"); + foreach(string linea in file_arr){ + if(strsrch(linea,"AddExit") != -1 && strsrch(linea,dir) != -1) { + search_str = linea; + } + } + globalstr = tmpfile; + globalstr2 = filename; + globaltmp = remove_matching_line(new_file, search_str); + unguarded( (: write_file(globalstr,globaltmp,1) :) ); + unguarded( (: cp(globalstr, globalstr2) :) ); + eventProcessExits(filename); + reload(filename); + rm(tmpfile); + write("With a puff of smoke, an exit vanishes!"); + return 1; + } + + write("This room's SetExits does not contain that direction."); + return 1; +} + +varargs mixed eventProcessExits(string filename, string dir, string location){ + string map_str, key, val, new_file; + mapping PointlessMap; + + mapping ExitsMap = load_object(filename)->GetExitMap(); + + if(file_exists(filename) && !check_privs(this_player(),filename)){ + write("You do not appear to have write access to this file. Modification aborted."); + return 1; + } + + PointlessMap = load_object(filename)->GetFullExitData(); + map_str = "SetExits( ([\n"; + + this_object()->eventReadMapping(filename,({"SetExits"}), 1); + new_file = remove_matching_line(read_file(filename),"SetObviousExits"); + new_file = remove_matching_line(new_file,"//extras"); + new_file = remove_matching_line(new_file, "AddExit(", 1, ":)"); + + foreach( key, val in ExitsMap){ + if(!functionp(PointlessMap[key]["pre"]) && + !functionp(PointlessMap[key]["post"])) map_str += "\""+key+"\" : \""+val+"\",\n"; + } + if(dir && location && member_array(dir,load_object(filename)->GetExits()) == -1){ + map_str += "\""+dir+"\" : \""+location+"\",\n"; + } + map_str += "]) );"; + + globalstr = filename; + globaltmp = generate_tmp(); + + globalstr2 = this_object()->eventAppend(new_file,({"SetItems","SetLong","SetDayLong","SetNightLong","SetShort","create()","create"}),"\n"+map_str+"\n"); + unguarded( (: write_file(globaltmp,globalstr2,1) :) ); + unguarded( (: cp(globaltmp,globalstr) :) ); + reload(filename); + rm(globaltmp); + return 1; +} + +string eventCopyRoom(string source, string dest){ + string homedir, areadir, tmpsource, map_str, new_file; + mapping DestExits; + + if(file_exists(source) && (!check_privs(this_player(),source) && + strsrch(source,"/obj/"))){ + write("You do not appear to have write access to this file. Modification aborted."); + return ""; + } + + if(file_exists(dest) && !check_privs(this_player(),dest)){ + write("You do not appear to have write access to that file. Modification aborted."); + return ""; + } + + tmpsource = generate_tmp(source); + globalstr2 = source; + globalstr = tmpsource; + unguarded( (: cp(globalstr2, globalstr) :) ); + globalstr2 = dest; + if(!file_exists(source)) return "Source read has failed."; + if(!file_exists(tmpsource)) return "Read failed."; + if(!file_exists(dest)) return "Destination read failed."; + homedir = "/realms/"+this_player()->GetKeyName(); + areadir = homedir+"/area"; + + unguarded( (: this_object()->eventReadMapping(globalstr,({"SetExits"}),1) :) ); + unguarded( (: this_object()->eventReadMapping(globalstr2,({"SetExits"}),1) :) ); + DestExits = load_object(dest)->GetExitMap(); + + unguarded( (: globaltmp = read_file(globalstr) :) ); + + map_str = "SetExits("+this_object()->eventStringifyMap(DestExits)+");\n"; + new_file = this_object()->eventAppend(globaltmp,({"SetItems","SetLong","SetDayLong"}),"\n"+map_str+"\n"); + new_file = replace_line(new_file,({"SetShort(",");"}),"SetShort(\"copy of "+last_string_element(source,"/")+"\");"); + replace_string(new_file,"\n\n\n","\n\n"); + new_file = remove_matching_line(new_file, "SetDoor", 1); + + if(query_verb() == "copy" && grepp(new_file, "customdefs\.h")){ + string *tmparr = explode(new_file,"\n"); + string *tmparr2 = explode(read_file(dest),"\n"); + string bad_def = ""; + string good_def = ""; + foreach(string element in tmparr2){ + if(!strsrch(element,"#include")){ + if(grepp(element,"customdefs.h")){ + good_def = element; + } + } + } + tmparr2 = ({}); + foreach(string element in tmparr){ + if(!strsrch(element,"#include")){ + if(grepp(element,"customdefs.h")) element = good_def; + } + tmparr2 += ({ element }); + } + new_file = implode(tmparr2,"\n"); + } + + write_file(tmpsource,new_file,1); + + globalstr = tmpsource; + globalstr2 = dest; + + if(!unguarded( (: cp(globalstr, globalstr2) :) )){ + return "Write failed."; + } + + this_object()->eventAddInit(dest); + this_object()->eventGeneralStuff(dest); + rm(tmpsource); + return "Room data copy complete."; +} + +varargs int eventCreateEnter(string dir, string room, string file, int remote){ + + if(file_exists(room) && !check_privs(this_player(),room)){ + write("You do not appear to have write access to this room file. Modification aborted."); + return 1; + } + + if(!present(dir,environment(this_player()))){ + write("This room needs a corresponding SetItem to make a SetEnter "); + write("of "+dir); + return 1; + } + + globalroom = room; + globalfile = file; + globaltmp = ""; + + if(remote) unguarded( (: globaltmp = read_file(globalroom) :) ); + else unguarded( (: globaltmp = read_file(globalfile) :) ); + + if(remote && member_array("out",load_object(room)->GetExits()) != -1) return 0; + + globaltmp = remove_matching_line(globaltmp,"SetEnters",1); + globaltmp = remove_matching_line(globaltmp,"//extras",1); + unguarded( (: write_file(globalfile,globaltmp,1) :) ); + + if(!remote) { + eventProcessEnters(room, dir, file); + this_object()->eventCreateExit("out", file, room, 1 ); + say(this_player()->GetCapName()+" waves "+possessive(this_player())+" hand and a new enter appears."); + this_object()->eventGeneralStuff(room); + } + this_object()->eventAddInit(room); + if(remote){ + this_object()->eventGeneralStuff(room); + write("You begin uttering a magical incantation."); + write("You wave your hand, and a new enter appears."); + say(this_player()->GetCapName()+" begins uttering a magical incantation."); + + } + reload(room); + reload(file); + room = ""; + file = ""; + globalroom = ""; + globalfile = ""; + globaltmp =""; + return 1; +} + +int eventRemoveEnter(string dir, string filename){ + string contents, search_str, map_str, new_file, tmpfile; + mixed *key; + mixed val; + string *file_arr; + mixed *key_arr; + mapping PointlessMap; + mapping EntersMap = load_object(filename)->GetEnterMap(); + + if(file_exists(filename) && !check_privs(this_player(),filename)){ + write("You do not appear to have write access to this room's file. Modification aborted."); + return 1; + } + + tmpfile = generate_tmp(load_object(filename)); + globalstr = filename; + globaltmp = tmpfile; + unguarded( (: globalstr2 = read_file(globalstr) :) ); + contents = globalstr2; + PointlessMap = ([]); + + PointlessMap = load_object(filename)->GetEnterMap(); + + if( member_array(dir,load_object(filename)->GetEnters()) != -1) { + this_object()->eventReadMapping(filename,({"SetEnters"}), 1); + foreach(key,val in EntersMap){ + if(arrayp(key) && member_array(dir,key) != -1) + key_arr = key; + true(); + } + map_delete(EntersMap,key_arr); + map_str = "SetEnters( ([ \n"; + foreach( key, val in EntersMap){ + map_str += "\""+key[0]+"\" : \""+val+"\",\n"; + } + map_str += "]) );"; + + unguarded( (: globalstr2 = read_file(globalstr) :) ); + contents = globalstr2; + + new_file = remove_matching_line(contents, "SetEnters", 1); + new_file = this_object()->eventAppend(new_file,({"AddItem","SetItems"}),"\n"+map_str+"\n"); + new_file = remove_matching_line(new_file,"SetObviousEnters"); + new_file = remove_matching_line(new_file,"//extras"); + new_file = remove_matching_line(new_file,"AddEnter(", 1); + globalstr2 = new_file; + unguarded( (: write_file(globaltmp,globalstr2,1) :) ); + this_object()->eventGeneralStuff(tmpfile); + globalstr = tmpfile; + globalstr2 = filename; + unguarded( (: cp(globalstr, globalstr2) :) ); + rm(tmpfile); + reload(filename); + write("With a puff of smoke, an enter vanishes!"); + return 1; + } + + + if(member_array(dir,load_object(filename)->GetEnters()) != -1){ + globalstr = filename; + new_file = read_file(filename); + file_arr = explode(read_file(filename),"\n"); + foreach(string linea in file_arr){ + if(strsrch(linea,"AddEnter") != -1 && strsrch(linea,dir) != -1) { + search_str = linea; + } + } + globalstr = tmpfile; + globalstr2 = filename; + globaltmp = remove_matching_line(new_file, search_str); + unguarded( (: write_file(globalstr,globaltmp,1) :) ); + unguarded( (: cp(globalstr, globalstr2) :) ); + eventProcessEnters(filename); + reload(filename); + rm(tmpfile); + write("With a puff of smoke, an enter vanishes!"); + return 1; + } + + write("This room's SetEnters does not contain that direction."); + return 1; +} + +varargs mixed eventProcessEnters(string filename, string dir, string location, object room) { + string map_str, key, val, new_file; + string *id_array; + object *dummies; + mapping PointlessMap; + + mapping EntersMap = load_object(filename)->GetEnterMap(); + id_array = ({}); + dummies = load_object(filename)->GetDummyItems(); + if(sizeof(dummies)) foreach(object dumdum in dummies){ + id_array += dumdum->GetId(); + } + + if(file_exists(filename) && !check_privs(this_player(),filename)){ + write("You do not appear to have write access to this file. Modification aborted."); + return 1; + } + + PointlessMap = load_object(filename)->GetEnterMap(); + map_str = "SetEnters( ([\n"; + globalstr = filename; + + unguarded( (: this_object()->eventReadMapping(globalstr,({"SetEnters"}), 1) :) ); + new_file = remove_matching_line(unguarded( (: read_file(globalstr) :) ),"SetObviousExits"); + new_file = remove_matching_line(new_file,"//extras"); + new_file = remove_matching_line(new_file, "AddEnter(", 1, ":)"); + + foreach( key, val in EntersMap){ + map_str += "\""+key[0]+"\" : \""+val+"\",\n"; + } + + if(dir && location && member_array(dir,id_array) != -1){ + map_str += "\""+dir+"\" : \""+location+"\",\n"; + } + map_str += "]) );"; + + globalstr = filename; + globaltmp = generate_tmp(load_object(filename)); + + globalstr2 = this_object()->eventAppend(new_file,({"AddItem","SetItems","SetExits","AddExit"}),"\n"+map_str+"\n"); + unguarded( (: write_file(globaltmp,globalstr2,1) :) ); + unguarded( (: cp(globaltmp,globalstr) :) ); + reload(filename); + rm(globaltmp); + return 1; +} diff --git a/lib/secure/npc/arch_wraith.c b/lib/secure/npc/arch_wraith.c new file mode 100644 index 0000000..4d1083a --- /dev/null +++ b/lib/secure/npc/arch_wraith.c @@ -0,0 +1,193 @@ +#include +#include +#include ROOMS_H + +inherit LIB_SENTIENT; +object *enemies = ({}); +object quarry; +int draining, self_destruct; +string qname, ip; + +int eventDrain(mixed args...){ + int avoid; + if(!environment()) return 1; + enemies = this_object()->GetEnemies(); + if(quarry && draining) enemies += ({ quarry }); + if(!sizeof(enemies)) return 1; + enemies = filter(enemies, (: environment($1) :)); + enemies = filter(enemies, (: environment($1) == environment() :)); + if(!sizeof(enemies)) return 1; + if(sizeof(enemies) > 5) enemies = scramble_array(enemies)[0..4]; + foreach(object enemy in enemies){ + int which, level; + string what; + mixed *skills = enemy->GetSkills(); + mixed *stats = enemy->GetStats(); + if(quarry && enemy == quarry && random(100) > draining) avoid = 100; + switch(which = random(8)+avoid){ + case 0 : + what = skills[random(sizeof(skills)-1)]; + level = enemy->GetSkillLevel(what); + level = level/2; + enemy->SetSkill(what,level); + break; + case 1 : + what = stats[random(sizeof(stats)-1)]; + level = enemy->GetStatLevel(what); + level = level/2; + enemy->SetStat(what,level); + break; + case 2 : + what = "level"; + level = enemy->GetLevel(); + level = level/2; + enemy->ChangeLevel(level); + break; + case 3 : + what = "health"; + level = enemy->GetHealthPoints(); + level = level/2; + enemy->AddHP(-level); + break; + case 4 : + what = "stamina"; + level = enemy->GetStaminaPoints(); + level = level/2; + enemy->AddStaminaPoints(-level); + break; + case 5 : + what = "stamina"; + level = enemy->GetMagicPoints(); + level = level/2; + enemy->AddMagicPoints(-level); + break; + case 6 : + what = "experience"; + level = enemy->GetExperiencePoints(); + level = level/2; + enemy->AddExperiencePoints(-level); + break; + case 7 : + what = "quest"; + level = enemy->GetQuestPoints(); + level = level/2; + enemy->AddQuestPoints(-level); + break; + default: break; + } + if(which < 100){ + tell_object(enemy,"The wraith drains your vital essence!"); + tell_room(environment(this_object()), "The wraith drains "+ + enemy->GetName()+" of precious bodily essence!", ({ enemy })); + } + } + return 0; +} + +static void create() { + object tp = this_player(); + if(!tp || !archp(tp)) self_destruct = 1; + sentient::create(); + SetKeyName("archwraith"); + SetAdjectives( ({"arch", "shadowy", "undead", "unholy", "malevolent", "spiteful"}) ); + SetId( ({"archwraith", "wraith", "specter", "ghost", "apparition", "manifestation"}) ); + SetShort("an archwraith"); + SetLong("This shadowy manifestation is an undead, unholy apparition, oozing malevolence and spite."); + SetPosition(POSITION_FLYING); + SetRace("wraith"); + SetClass("fighter"); + SetLevel(20); + SetMelee(1); + SetInvis(1); + SetGender("neuter"); + SetUndead(1); + SetUndeadType("wraith"); + SetAttackable(0); + //SetPacifist(1); + SetCombatAction(100, (: eventDrain :)); + SetNoClean(1); +} + +varargs int eventReceiveDamage(mixed args...){ + return 0; +} + +void init(){ + ::init(); + add_action("add_target","wraithseek"); + add_action("track_target","wraithtrack"); +} + +void heart_beat(){ + int here; + mixed *dest; + ::heart_beat(); + if(!quarry && qname) quarry = find_player(qname); + if(quarry && environment(quarry) && environment(quarry) == environment()){ + eventDrain(quarry); + } + if(sizeof(enemies) || quarry){ + foreach(object enemy in enemies + ({ quarry })){ + if(!enemy) continue; + if(environment(enemy) && environment(enemy) == environment()){ + here = 1; + } + } + if(!here){ + dest = filter(enemies, (: environment($1) :)); + if(quarry) dest = (environment(quarry) ? ({ quarry }) : dest ); + if(sizeof(dest)){ + eventMove(environment(dest[random(sizeof(dest)-1)])); + } + else { + this_object()->eventMove(load_object(ROOM_DEATH)); + } + } + } +} + +int add_target(string str){ + object target = find_player(str); + if(!this_player() || (this_player() && !adminp(this_player()))){ + return 0; + } + if(target){ + write("seeking "+str); + if(environment(target)){ + this_object()->eventMove(environment(target)); + this_object()->AddEnemy(target); + } + } + return 1; +} + +int track_target(string str){ + object target = find_player(str); + if(!this_player() || (this_player() && !adminp(this_player()))){ + return 0; + } + qname = str; + if(target){ + write("tracking "+str); + if(environment(target)){ + quarry = target; + this_object()->eventMove(environment(target)); + } + } + return 1; +} + +int eventDestruct(){ + if(this_player() && adminp(this_player())){ + return ::eventDestruct(); + } + return 0; +} + +int SetDraining(int i){ + if(!this_player() || (this_player() && !adminp(this_player()))){ + return 0; + } + draining = i; + return draining; +} diff --git a/lib/secure/npc/cambot.c b/lib/secure/npc/cambot.c new file mode 100644 index 0000000..54e4147 --- /dev/null +++ b/lib/secure/npc/cambot.c @@ -0,0 +1,194 @@ +#include +#include + +inherit LIB_SENTIENT; +inherit LIB_TURN; +int recording; +string baseshort, recfile, gstr, gstr2; +mixed owner; + +static void create() { + sentient::create(); + SetKeyName("cambot"); + SetId( ({"bot", "robot"}) ); + SetAdjectives(({"non-player", "non player"})); + SetShort("a cambot"); + SetLong("This is a metallic sphere, about one foot in diameter, with numerous lenses affixed to its surface."); + SetPosition(POSITION_FLYING); + SetLevel(1); + SetPacifist(1); + SetNoClean(1); + SetRace("bot"); + SetClass("observer"); + SetGender("neuter"); + SetPolyglot(1); + baseshort = GetShort(); + +} + +void init(){ + ::init(); + add_action("SetRecordingFile","setfile"); +} + +static mixed SetOwner(mixed foo){ + owner = foo; + return owner; +} + +mixed GetOwner(){ + return owner; +} + +int SetRecordingFile(string str){ + string pprefix, filename; + if(!sizeof(str) && sizeof(recfile)){ + write("The recording file is currently: "+recfile); + return 1; + } + if(!sizeof(str)){ + str = truncate(generate_tmp(),2)+".txt"; + } + if(directory_exists(str)){ + write("Please specify a file, not a directory."); + return 1; + } + pprefix = path_prefix(str); + if(!directory_exists(pprefix)){ + write("That is not a valid path."); + return 1; + } + filename = last_string_element(str); + gstr2 = str; + if(!check_privs(this_player(),str) || !unguarded( (: write_file(gstr2,"New log: "+timestamp()+"\n") :) )){ + write("That is not a valid path."); + return 1; + } + if(last(str,2) == ".c" || last(str,2) == ".h" || + last(str,4) == ".cfg"){ + write("That file has an invalid extension for recording over."); + return 1; + } + recfile = str; + owner = previous_object(); + write("Setting recording file to: "+recfile); + unguarded( (: write_file(recfile,"New log: "+timestamp()+"\n") :) ); + return 1; +} + +void catch_tell( string message ){ + this_object()->receive_message("catch_tell",message); +} + +void receive_message(string s1, string s2){ + if(s2){ + gstr = replace_string(s2,"%^CYAN%^",""); + gstr = replace_string(gstr,"%%^^CYAN%%^^",""); + if(recording) unguarded( (: write_file(recfile,timestamp()+": "+gstr+"\n") :) ); + } +} + +varargs mixed eventHearTalk(object who, object target, int cls, string verb, + string msg, string lang) { + this_object()->receive_message("me",who->GetName()+" "+verb+"s: "+msg) ; + return; +} + +varargs int doPrint(string msg, string msg_class){ + this_object()->receive_message("me again",msg) ; + return 1; +} + +varargs int eventPrint(string msg, string msg_class){ + doPrint( msg, msg_class) ; + return 1; +} + +int eventTurnOn(object ob){ + if(this_player() != environment() && environment(this_player()) !=environment()) { + write("It isn't within reach."); + return 1; + } + if(!archp(this_player())){ + write("This is an arch-level cambot. You may not tamper with it."); + return 0; + } + if(!recording){ + write("You turn on the cambot."); + say(this_player()->GetName()+" turns on a cambot."); + SetShort(baseshort+" %^BOLD%^RED%^%^FLASH%^recording%^RESET%^"); + if(!sizeof(recfile)) recfile = truncate(generate_tmp(),2)+".txt"; + write("Recording file is: "+recfile); + unguarded( (: write_file(recfile,"New log: "+timestamp()+"\n") :) ); + recording = 1; + return 1; + } + if(recording){ + write("It is already on."); + return 1; + } +} + +varargs mixed eventTurnOff(string str){ + if(this_player() != environment() && environment(this_player()) !=environment()) { write("It isn't within reach."); return 1; } + if(!archp(this_player())){ + write("This is an arch-level cambot. You may not tamper with it."); + return 0; + } + if(recording){ + write("You turn off the cambot."); + say(this_player()->GetName()+" turns off a cambot."); + SetShort(baseshort); + recording = 0; + return 1; + } + if(!recording){ + write("It is already off."); + return 1; + } +} + +int eventDestruct(){ + if(!this_player()) return 0; + if(!archp(this_player())){ + write("This is an arch-level cambot. You may not tamper with it."); + return 0; + } + else return sentient::eventDestruct(); +} + +int eventDie(){ + if(!this_player()) return 0; + if(!archp(this_player())){ + write("This is an arch-level cambot. You may not tamper with it."); + this_object()->AddHP(1000); + return 0; + } + else return sentient::eventDie(); +} + +int eventForce(string str){ + if(!this_player()) return 0; + if(!archp(this_player())){ + write("This is an arch-level cambot. You may not tamper with it."); + return 0; + } + else return sentient::eventForce(str); +} + +int eventMove(mixed dest){ + if(recording){ + write("Cambot cannot move while in recording mode."); + return 0; + } + else return sentient::eventMove(dest); +} + +int eventMoveLiving(mixed dest){ + if(recording){ + write("Cambot cannot travel while in recording mode."); + return 0; + } + else return sentient::eventMoveLiving(dest); +} + diff --git a/lib/secure/npc/drone.c b/lib/secure/npc/drone.c new file mode 100644 index 0000000..8b8ed69 --- /dev/null +++ b/lib/secure/npc/drone.c @@ -0,0 +1,182 @@ +#include +#include +#include + +int eventReceiveCommand(string butt, string munch); +//varargs int SetOwner(string str, mixed arg); +int SetOwner(string str); +string GetOwner(); +int ListenUp(int foo); +int itemcheck,listening; +mixed arguments; +string owner, mm, vv, printvar,owner; +string mensaje, clase_mensaje,desc,control_code; +object dude,ww, ownerob; +void doPrint(string str1, string str2); + +void validate(){ + if(base_name(previous_object()) != "/secure/obj/control" || + previous_object()->GetControlCode() != control_code){ + if(ownerob){ + tell_object(ownerob,"%^RED%^Security violation. Someone is attempting to "+ + "hijack your drone. Guilty object stack: %^YELLOW%^"+ + identify(previous_object(-1))+"%^RESET%^"); + } + error("Illegal control attempt by: "+identify(previous_object(-1))+", "+get_stack()); + } + return; +} + +int doCheckLiving(object ob){ + if(living(ob) && ob->GetInvis() !=1){ + if(file_name(ob) != file_name(this_object()) ) + desc += ob->GetShort()+" is here.\n"; + } + return 1; +} + +int doCheckItem(object ob){ + string s1; + if(!living(ob) + && !sscanf(file_name(ob),"/lib/std/dummy#%s",s1) ){ + if(itemcheck==0){ + desc+="Here you see:\n"; + itemcheck=1; + } + if(ob->GetInvis() != 1) desc += ob->GetShort()+"\n"; + } + return 1; +} + +int ListenUp(int i){ + listening=i; + return 1; + this_object()->set_heart_beat(1); +} +void init(){ + itemcheck=0; + this_object()->set_heart_beat(1); + this_object()->SetNoClean(1); +} + +void receive_message(string s1, string s2){ + if(ownerob && listening) tell_object(ownerob,"Remote: "+s2); +} + +varargs mixed eventHearTalk(object who, object target, int cls, string verb, + string msg, string lang) { + ww=who; + vv=verb; + mm=msg; + dude=this_object()->GetShadowedObject(); + this_object()->receive_message("me",ww->GetName()+" "+vv+"s: "+mm) ; + return; +} + +varargs int doPrint(string msg, string msg_class){ + printvar=msg; + this_object()->receive_message("me again",printvar) ; + return 1; +} + +varargs int eventPrint(string msg, string msg_class){ + mensaje = msg; + clase_mensaje = msg_class; + doPrint( mensaje, clase_mensaje) ; + return 1; +} + +int eventDescribeEnvironment(mixed args){ + dude=this_object()->GetShadowedObject(); + arguments = args; + unguarded((: tell_object(ownerob,this_object()->eDE()+"\n") :)); + return 1; +} + +int eventReceiveCommand(string str){ + string thing; + + validate(); + + if(!query_heart_beat(this_object())) this_object()->set_heart_beat(1); + if(ownerob && str != "look" && str != "l") this_object()->eventForce(str); + else if(ownerob){ + unguarded((: this_object()->eventDescribeEnvironment() :)) ; + } + else if(!ownerob) return 0; + return 1; +} + +varargs int SetOwner(string str, mixed arg){ + if(sizeof(owner) && this_object()->GetOwner() != "NONE") { + validate(); + } + if(str == "NONE") { + control_code = ""; + owner = "NONE"; + ownerob = 0; + listening = 0; + return 1; + } + owner=str; + if(arg && objectp(arg)) ownerob=arg; + else ownerob=find_player(owner); + listening=1; + this_object()->set_heart_beat(1); + return 1; +} + +string GetOwner(){ + if(owner) return owner; + else return "NONE"; +} + + +int SetControlCode(string str){ + if(sizeof(control_code) && GetOwner() != "NONE" ){ + if(ownerob){ + tell_object(ownerob,"%^RED%^Security violation. Someone is attempting to " + "hijack your drone. Guilty object stack: %^YELLOW%^"+ + identify(previous_object(-1))+"%^RESET%^"); + } + error("Illegal control attempt by: "+identify(previous_object(-1))+", "+get_stack()); + } + else control_code = str; + return 1; +} + +string eDE(int brief) { + object env; + object *invarr; + mixed tmp; + string *shorts; + string smell, sound, touch; + int i, maxi; + dude=this_object()->GetShadowedObject(); + if(!(env = environment(this_object()->GetShadowedObject()))) { + eventPrint(dude->GetName()); + eventPrint(file_name(dude)); + eventPrint(base_name(environment(find_object(file_name(dude))))); + eventPrint("You are nowhere.","Room Desc"); + return; + } + desc = env->GetObviousExits() || ""; + desc = capitalize(env->GetInternalShort() || env->GetShort() || "") + + " [" + desc + "]\n"; + desc += (env->GetInternalLong() || env->GetLong() || ""); + smell = env->GetSmell(); + sound = env->GetListen(); + touch = env->GetTouch(); + + if( smell ) desc += "%^GREEN%^\n"; + if( sound ) desc += "%^CYAN%^\n"; + if( touch ) desc += "%^YELLOW%^\n"; + + invarr = all_inventory(env); + filter(invarr, (: doCheckLiving($1) :) ); + filter(invarr, (: doCheckItem($1) :) ); + desc += "\n"; + return desc; +} + +int GetDrone() { return 1; } diff --git a/lib/secure/obj/arch_board.c b/lib/secure/obj/arch_board.c new file mode 100644 index 0000000..a1ae6e9 --- /dev/null +++ b/lib/secure/obj/arch_board.c @@ -0,0 +1,83 @@ +#include +#include + +inherit LIB_SECURE_BOARD; + +void create(){ + ::create(); + + SetKeyName("chalkboard"); + SetId(({ "board", "chalkboard" })); + set_board_id("admin_board"); + SetShort("The Arch Board"); + SetLong("This is the Arch board. You know how to use it."); +} + +void init(){ + ::init(); +} + +void validate(){ + if( !this_player() || !archp(this_player()) ) + error("Illegal attempt to access arch board: "+get_stack()+" "+identify(previous_object(-1))); +} + +int cmd_read(string str) { + validate(); + return ::cmd_read(str); +} + +int cmd_post(string str) { + validate(); + return ::cmd_post(str); +} + +void continue_post(string subj, string file) { + validate(); + return ::continue_post(subj, file); +} + +void end_post(string subj, string mail) { + validate(); + return ::end_post(subj, mail); +} + +int cmd_followup_and_respond(string str) { + validate(); + return ::cmd_followup_and_respond(str); +} + + +void continue_followup(mapping post, string subj, string file) { + validate(); + return ::continue_followup(post, subj, file); +} + +void continue_mail(mapping post, string subj, string file) { + validate(); + return ::continue_mail(post, subj, file); +} + +int cmd_remove(string str){ + validate(); + return ::cmd_remove(str); +} + +int cmd_edit(string str){ + validate(); + return ::cmd_edit(str); +} + +void end_edit(string subj, int num) { + validate(); + return ::end_edit(subj, num); +} + +string GetExternalDesc() { + validate(); + return ::GetExternalDesc(); +} + + + + diff --git a/lib/secure/obj/control.c b/lib/secure/obj/control.c new file mode 100644 index 0000000..d7773f5 --- /dev/null +++ b/lib/secure/obj/control.c @@ -0,0 +1,137 @@ +/* remote control by Cratylus @ Frontiers + * Sep 21 2005 + */ + +#include +#include +inherit LIB_ITEM; +int controlling; +string remote, control_code; +object owner; + +void create(){ + ::create(); + SetKeyName("remote control"); + SetId(({"device","controller","remote","control"})); + SetAdjectives(({"small","electronic"})); + SetShort("a remote control"); + SetLong("This is a small electronic "+ + "device with various labeled buttons on it. "+ + "It seems you can \"control something\" with "+ + "it, and also \"release\" it. To command your "+ + "remote servant, you evidently have to preface the command "+ + "with the ] character (example: ] look at menu)."); + SetProperties(([ + "no steal" : 1, + ])); + SetMass(20); + SetVendorType(VT_TREASURE); + control_code = alpha_crypt(16); +} + +void init(){ + ::init(); + if(living(environment())) owner = environment(); + else owner = 0; + add_action("control","control"); + add_action("release","release"); + add_action("do_control","]"); +} + +int control(string str){ + object ob; + string *eyedees; + if(!str){ + return 0; + } + ob=present(str, environment(this_player())); + if(!ob){ + write("There is no such thing to be controlled here."); + return 1; + } + if(!builderp(this_player())){ + write("Your puny mortal mind can't wrap itself around the use " + "of this powerful instrument."); + log_file("adm/control",capitalize(this_player()->GetKeyName())+ + " attempted to use the remote control on "+str+": "+timestamp()+"\n"); + tell_creators("SECURITY: "+capitalize(this_player()->GetKeyName())+ + " attempted to use the remote control on "+str+"."); + return 1; + } + if(!living(ob)){ + write(capitalize(ob->GetKeyName())+" is not a living thing."); + return 1; + } + + if(!creatorp(this_player()) && strsrch(base_name(ob), homedir(this_player()))){ + write("Only creators can control NPC's that don't belong to them."); + say(this_player()->GetName()+" tries to establish control over "+ob->GetName()+" and fails.\n"); + return 1; + } + if(!strsrch(base_name(ob),"/secure") ){ + write(ob->GetName()+" is not controllable with this device."); + say(this_player()->GetName()+" tries to establish control over "+ob->GetName()+" and fails.\n"); + return 1; + } + if(controlling){ + write("Your remote control is busy controlling some other creature."); + return 1; + } + if(ob->GetOwner() && ob->GetOwner() != "NONE"){ + write("That creature is already in someone's thrall."); + return 1; + } + if(!(ob->GetOwner())) new("/shadows/drone")->eventShadow(ob); + remote=file_name(ob); + ob->SetOwner(this_player()->GetKeyName(), this_player()); + ob->SetListen(1); + ob->SetControlCode(control_code); + eyedees = ob->GetId(); + eyedees += ({"servant","drone","thrall"}); + ob->SetId(eyedees); + write("You establish a remote control connection with "+capitalize(str)+"."); + say(this_player()->GetName()+" establishes a control link with "+capitalize(str)+"."); + controlling=1; + return 1; +} + +int do_control(string str){ + object obj; + if(!controlling){ + write("You are not currently linked to any living thing."); + return 1; + } + if(!str || str == ""){ + write("Nothing happens."); + return 1; + } + if(environment() != owner){ + write("You don't seem to be in possession of the remote control."); + tell_object(environment(),"Possible security violation on remote control."); + error("Illegal access of remote control: "+get_stack()+" "+identify(previous_object(-1))); + return 1; + } + obj=find_object(remote); + if(obj) obj->eventReceiveCommand(str); + else { + write("There seems to be a problem."); + this_object()->release(); + } + return 1; +} + +int release(){ + object dingus; + if(remote && dingus=find_object(remote) ){ + dingus->SetOwner("NONE"); + remove_shadow(dingus); + } + controlling=0; + write("You release your remote link."); + return 1; +} + +string GetControlCode(){ + if(base_name(previous_object()) != "/shadows/drone") return alpha_crypt(16); + else return control_code; +} diff --git a/lib/secure/obj/floodmapper.c b/lib/secure/obj/floodmapper.c new file mode 100644 index 0000000..f5dcb3a --- /dev/null +++ b/lib/secure/obj/floodmapper.c @@ -0,0 +1,59 @@ +#include +#include +#include ROOMS_H + +inherit LIB_FLOW; + +void create() { + ::create(); + set_heart_beat(1); + SetDoorStopped(0); + enable_commands(); + set_heart_beat(1); + SetHBOverride(1); +} + +void init(){ + ::init(); +} + +void heart_beat(){ + ::heart_beat(); + set_heart_beat(1); +} + +int GetMapper(){ + return 1; +} + +int GetPressure(){ + return 5; +} + +int eventMove(mixed dest){ + int ret; + string *avoids = ({ "/domains/town/virtual/space", + "/domains/town/virtual/surface", + "/domains/town/virtual/sub", "/domains/town/virtual/bottom" }); + object envr = environment(); + string location, sdest; + + if(objectp(dest)) sdest = base_name(dest); + else sdest = dest; + foreach(mixed avoid in avoids){ + if(!strsrch(sdest, avoid)){ + this_object()->eventDestruct(); + return 0; + } + } + + if(envr){ + if(clonep(envr)) location = file_name(envr); + else location = base_name(envr); + } + + if(location) this_object()->SetProperty("LastLocation", location); + ret = ::eventMove(dest); + return ret; +} + diff --git a/lib/secure/obj/glasses.c b/lib/secure/obj/glasses.c new file mode 100644 index 0000000..e48eb05 --- /dev/null +++ b/lib/secure/obj/glasses.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include + +inherit LIB_ARMOR; +//bane provides protection from germs and parasites +inherit LIB_BANE; +//the modules below provide qcs functionality +inherit MODULES_ARMOR; +inherit MODULES_CREATE; +inherit MODULES_MAPPING; +inherit MODULES_GENERIC; +inherit MODULES_ROOM; +inherit MODULES_FILE; +inherit MODULES_MONEY; +inherit MODULES_READ; +inherit MODULES_DOOR; + +static void create(){ + armor::create(); + SetKeyName("glasses"); + //the tanstaafl id enables this object to function like a + //qcs staff + SetId(({"tanstaafl"})); + SetAdjectives(({"wire", "rimmed"})); + SetShort("wire-rimmed glasses"); + SetLong("A pair of glasses with magic properties for Creators."); + SetMass(5); + SetDamagePoints(1); + SetProtection(BLUNT,1); + SetProtection(BLADE,1); + SetProtection(KNIFE,1); + SetArmorType(A_VISOR); + //full protection from all diseases + SetBane(({"all"})); +} +void init(){ + ::init(); +} diff --git a/lib/secure/obj/include/gossip_folder.h b/lib/secure/obj/include/gossip_folder.h new file mode 100644 index 0000000..770ef6d --- /dev/null +++ b/lib/secure/obj/include/gossip_folder.h @@ -0,0 +1,8 @@ +#ifndef l_gossip_folder_h +#define l_gossip_folder_h + +static void create(string user); +void SetPostRead(string group, int post); +mixed *GetPostsRead(string group); + +#endif /* l_gossip_folder_h */ diff --git a/lib/secure/obj/include/post.h b/lib/secure/obj/include/post.h new file mode 100644 index 0000000..99b84fb --- /dev/null +++ b/lib/secure/obj/include/post.h @@ -0,0 +1,77 @@ +#ifndef __POST_H +#define __POST_H + +static private void restore_box(string folder); +static private void save_box(); +static private void destruct_box(string str); +static private int valid_folder(string str); +void start_post(string str); +static private void primary_prompt(); +static private void secondary_prompt(); +varargs static private void postal_error(string str, string ind, mixed args); +varargs static private void postal_success(string str, string ind, mixed args); +varargs static void indices(int x, string str); +varargs static void aliases(string str); +varargs static void options(string str); +static private void help(string arg, string ind); +static private void index_menu(); +static private void alias_menu(); +static private void option_menu(); +static private void help_menu(string ind); +static void index_cmd(string str); +static void alias_cmd(string str); +static void option_cmd(string str); +static void help_cmd(string str, string ind); +static private string postal_time(mixed val); +static private string header(mapping borg); +static void change_folder(string str); +static void next_folder(string str, string folder); +static void get_folder(string str); +static private void delete_letter(string cmd, string args); +static void unread_delete(string str, int *milk); +static private void quit_box(string cmd); +static private void really_quit(string cmd); +static void confirm_quit(string str, string cmd); +static void confirm_delete(string str); +static private void save_letter(string cmd, string args); +static void get_save_location(string str, mixed *vals); +static private void read_letter(int x); +void end_read(); +static private void alias_members(string cmd, string args); +static void get_alias(string str, string cmd); +static void get_members(string str, string *args); +static private void alias_creation(string cmd, string args); +static void get_alias_name(string str, string cmd); +static void get_new_alias_members(string str, string *args); +static private void list_alias(string str); +static private void save_options(); +static private void change_option(int x); +static void really_change_option(string str, int x); +static private void reply(string str); +static void get_reply_confirm(string str); +static void get_reply_list(string str); +static private void query_reply_text(); +static private void forward_letter(string str, int flag); +static void get_forward_list(string str); +static void confirm_comments(string str); +static private string query_forward_text(); +static void confirm_forward_abort(string str); +static private void send_letter(string *args); +static void get_to(string str); +static void get_subject(string str); +static void confirm_subject(string str); +static void get_cc(string str); +void complete_send(); +static private string query_signature(); +static private void confirm_send(); +static void handle_send_choice(string str); +static private void notify_send(string *failures); +void incoming_mail(); +int order_box(mapping borg); +void complete_send(); +void abort(); +void end_help(); +static private void help(string arg, string ind); + +#endif __POST_H + diff --git a/lib/secure/obj/include/roommaker.h b/lib/secure/obj/include/roommaker.h new file mode 100644 index 0000000..d0371bf --- /dev/null +++ b/lib/secure/obj/include/roommaker.h @@ -0,0 +1,35 @@ +#ifndef l_roommaker_h +#define l_roommaker_h + +static void create(); +void eventAbort(); +varargs mixed eventCreateRoom(string file, string climate); +static void eventPrintTitle(string title); +static void MainMenu(); +static void MainMenuCommand(string str); +static void ClimateMenu(); +static void ClimateMenuCommand(string cmd); +static void TownMenu(); +static void TownMenuCommand(string cmd); +static void PropertiesMenu(); +static void PropertiesMenuCommand(string cmd, string *props); +static void ShortMenu(); +static void ShortMenuCommand(string str); +static void LongMenu(); +static void LongMenuCommand(string cmd); +static void InventoryMenu(); +static void InventoryMenuCommand(string cmd, string *items); +static void ItemsMenu(); +static void ItemsMenuCommand(string cmd, string *items); +void CompleteItem(string *items); +static void PropertiesMenu(); +static void PropertiesMenuCommand(string cmd, string *props); +static void DirsMenu(string type); +static void DirsMenuCommand(string cmd, string type, string *sorties); +static void ObviousExitsMenu(); +static void ObviousExitsMenuCommand(string cmd); +static void SaveRoom(); + +varargs static string GetValue(mixed val, string str); + +#endif /* l_roommaker_h */ diff --git a/lib/secure/obj/key.c b/lib/secure/obj/key.c new file mode 100644 index 0000000..deb8017 --- /dev/null +++ b/lib/secure/obj/key.c @@ -0,0 +1,22 @@ +#include + +inherit LIB_ITEM; + +string RetStr(){ + return file_name(this_object()); +} + +static void create() { + item::create(); + SetKeyName("key"); + SetId( ({ "key", "sample key" }) ); + SetAdjectives( ({ "simple","sample" }) ); + SetShort((: RetStr :)); + SetLong((: RetStr :)); + SetMass(50); + SetBaseCost(1); + SetDisableChance(100); +} +void init(){ + ::init(); +} diff --git a/lib/secure/obj/machine.c b/lib/secure/obj/machine.c new file mode 100644 index 0000000..0934d62 --- /dev/null +++ b/lib/secure/obj/machine.c @@ -0,0 +1,284 @@ +#include +#include +#include +#include +inherit LIB_ITEM; + +int count, state, blocked, short, logged, forwarding; +int lastchecked, lastmessage; +string message, announce, name, final, tempy, cratty, f_global, forwardee; +object owner; + +int read_it(string str); + +int validate(){ + object prev = previous_object(); + if(prev && prev->GetForced()) return 0; + if(this_player() && this_player()->GetForced()) return 0; + if(!name || (owner && this_player() == owner)) return 1; + return 0; +} + +void create(){ + ::create(); + AddSave(({"state","forwarding","name","forwardee","announce","message", + "lastchecked","lastmessage"})); + SetKeyName("answering machine"); + SetId( ({"machine","voicemail"}) ); + SetShort("an answering machine"); + SetLong("This is a portable answering machine. There is a label on " + "it you can read."); + SetItems(([ + "label" : "A label you can read.", + ])); + SetRead(([ + "label" : (: read_it :), + ])); + SetDefaultRead("Try: read label on machine"); + SetProperties(([ + "no steal" : 1, + ])); + SetMass(1); + SetVendorType(VT_TREASURE); + state=0; + count = 0; + set_heart_beat(10); +} + +void init(){ + ::init(); + add_action("toggle_answer","answer"); + add_action("check_it","check"); + add_action("set_ann","announce"); + add_action("check_mess","tells"); + add_action("erase","erase"); + //add_action("tellforward","tellforward"); + add_action("arch_it","archive"); + if(owner){ + this_object()->get_ann(); + } + else { + if(name && owner) return; + if(environment() && interactive(environment())){ + unguarded( (: owner = environment() :) ); + unguarded( (: name = owner->GetKeyName() :) ); + } + } +} + +void heart_beat(){ + count++; + if(!clonep(this_object())) return; + if(name && !owner){ + if(!(owner = unguarded( (: find_player(name) :) ))){ + this_object()->eventDestruct(); + } + } + if(count > 36){ + count = 0; + if(lastchecked < lastmessage){ + if(environment()){ + environment()->eventPrint("The answering machine %^GREEN%^"+ + "BEEPS%^RESET%^."); + } + } + } +} + +int tellforward(string str){ + object env = environment(); + //This functionality is incomplete + return 0; + if(!validate()) return 0; + if(!env || !this_player() || env != this_player() ){ + return 0; + } + if(!str){ + if(forwardee && forwarding){ + write("You are forwarding tells to "+forwardee+"."); + } + else { + write("There is no current forwarding recipient."); + } + return 1; + } + if(str == "off"){ + write("Disabling tell forwarding."); + forwarding = 0; + forwardee = 0; + return 1; + } + write("You are now forwarding tells to: "+str); + forwardee = str; + forwarding = 1; + return 1; +} + +int toggle_answer(string str){ + if(str=="on"){ + if(state==1){ + write("The answering machine is already on.\n"); + return 1; + } + state=1; + blocked=1; + short=1; + logged=1; + unguarded( (: owner = this_player() :) ); + unguarded( (: name = this_player()->GetKeyName() :) ); + this_object()->log_it("*** Answering machine activated on "+ + local_ctime(time())+".\n"); + write("The answering machine is on.\n"); + return 1; + } + if(str=="off"){ + if(state==0){ + write("The machine is already turned off.\n"); + return 1; + } + state=0; + blocked=0; + short=0; + logged=0; + name=0; + owner=0; + cratty=0; + tempy=0; + forwardee=0; + forwarding=0; + write("The answering machine is off.\n"); + return 1; + } +} + +int query_answer(){ + return state; +} + +int do_tell(string wut){ + owner->eventForce(wut); + return 1; +} + +int get_message(string str){ + object prev = previous_object(); + if(!prev || + (base_name(prev) != CMD_TELL && base_name(prev) != SERVICES_D)){ + return 0; + } + cratty=""; + if(forwarding && forwardee){ + string localtemp; + cratty += "(forwarded to "+forwardee+") "; + localtemp = "tell "+forwardee+" "+str; + tempy = replace_string(localtemp,"tells you",""); + unguarded( (: do_tell, tempy :) ); + } + tempy = 0; + cratty += str; + this_object()->final(); + lastmessage = time(); + return 1; +} + +string send_message(){ + if(!sizeof(announce)) this_object()->get_ann(); + return announce; +} + +static int log_it(string str){ + f_global=str; + name=lower_case(owner->GetKeyName()); + unguarded((: write_file(homedir(owner)+"/log/messages", f_global+"\n") :)); + return 1; +} + +static int final(){ + tempy = local_ctime(time())+":\n"+cratty+"\n\n"; + if(!blocked){ + message("info",final+"\n", environment(this_object())); + } + if(logged){ + unguarded( (: this_object()->log_it(tempy) :) ); + } + cratty = 0; + tempy = 0; + return 1; +} + +int set_ann(string str){ + if(!validate()) return 0; + if(!state){ + write("The machine is not turned on.\n"); + return 1; + } + announce=str; + rm(homedir(owner)+"/log/annc"); + write_file(homedir(this_player())+"/log/annc", announce); + return 1; +} + +int get_ann(){ + if(file_size(homedir(owner)+"/log/annc") > 0){ + unguarded( (: announce=read_file(homedir(owner)+"/log/annc") :) ); + } + if(!sizeof(announce)){ + announce=capitalize(name)+" cannot "+ + "answer your tell right now. Your message has been recorded "+ + "and "+nominative(owner)+" will get back to you as soon as possible."; + } + return 1; +} + +int check_mess(string str){ + if(!validate()) return 0; + if(!str){ + lastchecked = time(); + owner->more(homedir(owner)+"/log/messages"); + return 1; + } +} + +string read_it(string str){ + string ret = "\n"+ + "answer on/off - on activates the machine. off doesn't.\n"+ + "announce - '' is whatever you want the sender to see.\n"+ + "tells - lists messages by date, time and sender.\n"+ + "erase tape - erases all messages on the machine.\n"+ + "archive tape - copies tape onto backup archive file.\n"+ + //"tellforward - Forwards any tells you receive to the "+ + //"person specifed. Use with GREAT caution.\n"+ + "\n"+ + "\n"; + return ret; +} + +int erase(string str){ + if(!validate()) return 1; + if(str=="tape"){ + write("You erase the answering machine tape.\n"); + rm(homedir(owner)+"/log/messages"); + return 1; + } +} + +int arch_it(string str){ + string temp; + if(!validate()) return 0; + if(str=="tape"){ + write("You save the contents of the answering machine tape " + "into "+homedir(owner)+"/log/archive.\n"); + temp=read_file(homedir(owner)+"/log/messages"); + write_file(homedir(owner)+"/log/archive", temp); + return 1; + } +} + +int clean_tape(string str){ + if(!validate()) return 0; + if(str=="tape"){ + this_object()->arch_it("tape"); + this_object()->erase("tape"); + return 1; + } +} diff --git a/lib/secure/obj/meditate_mojo.c b/lib/secure/obj/meditate_mojo.c new file mode 100644 index 0000000..0203458 --- /dev/null +++ b/lib/secure/obj/meditate_mojo.c @@ -0,0 +1,85 @@ +#include +#include +#include +inherit LIB_ITEM; +int damage1(); +int damage2(); +int damage3(); +int damage4(); +object victim; +int counter, duration; + +void create(){ + ::create(); + SetKeyName("meditate mojo"); + SetId(({"meditate mojo"})); + SetLong(" "); + SetInvis(1); + set_heart_beat(1); + counter = 0; +} + +void init(){ + if(living(environment())){ + victim = environment(); + } +} + + +int eventMojofy(){ + int x; + x=random(100); + if(x < 5) damage4(); + else if(x < 20) damage3(); + else if(x < 35) damage2(); + else if(x < 50) damage1(); + return 1; +} + +int damage1(){ + if(victim) victim->AddStaminaPoints(random(5)+1); + return 1; +} + +int damage2(){ + if(victim) victim->AddHP(random(2)+1); + if(victim) victim->AddStaminaPoints(random(5)+1); + return 1; +} + +int damage3(){ + if(victim) victim->AddHP(random(3)+1); + if(victim) victim->AddStaminaPoints(random(5)+1); + return 1; +} + +int damage4(){ + if(victim) victim->AddHP(random(4)+1); + if(victim) victim->AddStaminaPoints(random(5)+1); + return 1; +} + +void heart_beat(){ + if(environment() && !living(environment())) this_object()->eventDestruct(); + if(counter == (30 + duration)){ + if(environment()) tell_object(environment(),"%^CYAN%^You feel the effects of your meditation wear off.%^RESET%^"); + this_object()->eventMove("/domains/town/room/furnace"); + } + + counter++; + eventMojofy(); +} + +int AddDuration(int x){ + return duration += x; +} + +int eventDispel(){ + counter = (30 + duration); + heart_beat(); + return 1; +} + +mixed CanGet(object ob) { return " ";} +mixed CanDrop(object ob) { return " ";} + diff --git a/lib/secure/obj/medtric.c b/lib/secure/obj/medtric.c new file mode 100644 index 0000000..6733f5a --- /dev/null +++ b/lib/secure/obj/medtric.c @@ -0,0 +1,1350 @@ +#include +#include +inherit LIB_ITEM; + +void analyze(string butt); +object scanner,tricorder,person; +object *gstuff,*ngstuff; +mixed *statlist,*skilllist; +mapping this_stat,this_skill; +int allowed,statpoints,statlevel,statclass,tempint,i; +int skilllevel,skillclass,skillpoints; +string name; +string *stumps; +string warning = "We remind you that the tricorder cannot speak. In the event "+ +"that it does speak, you are instructed to disregard its advice."; + +void create(){ + item::create(); + SetKeyName("creator tricorder"); + SetId(({"tricorder","scanner","device","tool","medtric","tric"})); + SetAdjectives(({"electronic","admin","diagnostic"})); + SetShort("a medical tricorder"); + SetLong("This is a palm-sized electronic device designed to run various "+ + "medical tests and provide treatment of disease and injury. "+ + "Written in bold red letters across its face are the words: \"%^BOLD%^RED%^FOR AUTHORIZED TEST CHARACTER "+ + "USE ONLY%^RESET%^\".\n%^YELLOW%^NOTE: Some functions do not work "+ + "with drones. This is due to safeguards in the master object security "+ + "model, and it will not be \"fixed\".%^RESET%^\n"+ + "There is a warning on the tricorder you can read.\n"+ + "\n Labeled buttons on this device read:\n"+ + //"* medscan: scan for disease, poison, etc\t%^RED%^offline%^RESET%^\n"+ + "* fscan: readout of all files inherited\t\t%^GREEN%^ONLINE%^RESET%^\n"+ + //"* enshadow: move a shadow to an object\t\t%^RED%^offline%^RESET%^\n"+ + "* deshadow: remove all shadows from an object\t%^GREEN%^ONLINE%^RESET%^\n"+ + //"* inject: insert substance into patient\t\t%^RED%^offline%^RESET%^\n"+ + "* extract: remove a foreign body or substance\t%^GREEN%^ONLINE%^RESET%^ (slugs only)\n"+ + "* modhealth: raise or lower health level\t%^GREEN%^ONLINE%^RESET%^\n"+ + "* modcaff: raise or lower caffeine level\t%^GREEN%^ONLINE%^RESET%^\n"+ + "* modalc: raise or lower alcohol level\t\t%^GREEN%^ONLINE%^RESET%^\n"+ + "* modfood: raise or lower food level\t\t%^GREEN%^ONLINE%^RESET%^\n"+ + "* moddrink: raise or lower drink level\t\t%^GREEN%^ONLINE%^RESET%^\n"+ + "* modmag: raise or lower magic level\t\t%^GREEN%^ONLINE%^RESET%^\n"+ + "* modstam: raise or lower stamina\t\t%^GREEN%^ONLINE%^RESET%^\n"+ + "* modtox: raise or lower poison\t\t\t%^GREEN%^ONLINE%^RESET%^\n"+ + "* setskill: set skill level\t\t\t%^GREEN%^ONLINE%^RESET%^\n"+ + "* setstat: set stat level\t\t\t%^GREEN%^ONLINE%^RESET%^\n"+ + "* amputate: remove limb\t\t\t\t%^GREEN%^ONLINE%^RESET%^\n"+ + "* regenerate: restore all amputated limbs\t%^GREEN%^ONLINE%^RESET%^\n"+ + "* cure: eliminate known diseases\t\t%^GREEN%^ONLINE%^RESET%^\n"+ + "* infect: introduce disease into patient\t%^GREEN%^ONLINE%^RESET%^\n"+ + //"* inoculate: raise immunity to a disease\t%^RED%^offline%^RESET%^\n"+ + //"* posture: change your own posture.\t\t%^RED%^offline%^RESET%^\n"+ + ""); + SetRead( "default" , warning); + SetRead( "warning", warning ); + SetProperties(([ + "no steal" : 1, + ])); + SetMass(12); + SetVendorType(VT_TREASURE); +} + +void init(){ + ::init(); + add_action("fscan","fscan"); + add_action("assess","assess"); + add_action("assess","diagnose"); + add_action("extract","extract"); + add_action("addhp","addhp"); + add_action("addhp","modhealth"); + add_action("modcaff","modcaff"); + add_action("modalc","modalc"); + add_action("modfood","modfood"); + add_action("moddrink","moddrink"); + add_action("modmag","modmag"); + add_action("modstam","modstam"); + add_action("modtox","modtox"); + add_action("setstat","setstat"); + add_action("setskill","setskill"); + add_action("regenerate","regenerate"); + add_action("amputate","amputate"); + add_action("infect","infect"); + add_action("germ_scan","germscan"); + add_action("germ_squash","cure"); + add_action("medscan","medscan"); + add_action("posture","posture"); + add_action("enshadow","enshadow"); + add_action("deshadow","deshadow"); + add_action("TestFun","HEINEKEN"); +} + +int TestFun(){ + write("WOOHOO"); + return 1; +} + +varargs int preAction(int restricted){ + scanner=this_player(); + tricorder=this_object(); + + if(!this_player()) return 0; + + if(!present(tricorder, scanner)){ + write("You are not holding the tricorder."); + return 2; + } + + if(restricted && !creatorp(this_player())){ + write("This function is not permitted to builders."); + return 2; + } + if(!builderp(this_player())){ + write("Your puny mortal mind can't wrap itself around the use " + "of this powerful instrument."); + log_file("adm/tricorder",capitalize(this_player()->GetKeyName())+ + " attempted to use the medical tricorder: "+timestamp()+"\n"); + tell_creators("SECURITY: "+capitalize(this_player()->GetKeyName())+ + " attempted to use the medical tricorder."); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 2; + } + + say(scanner->GetName()+" operates a medical tricorder.",scanner); + write("The tricorder makes a low, warbling sound."); + return 1; +} + +int posture(int i){ + allowed=preAction(); + if(allowed == 2) return 1; + if(!i) { + write("Please include the position number desired."); + return 0; + } + this_player()->SetPosition(i); + return i; +} + +int deshadow(string str){ + object target; + allowed=preAction(1); + if(allowed == 2) return 1; + if(str == "me") str = this_player()->GetKeyName(); + if(!target = present(str,this_player())){ + target = present(str,environment(this_player())); + } + if(!target){ + write("That's not here."); + return 1; + } + else { + if(shadow(target,0)){ + remove_shadow(target); + write("You deshadow "+str); + } + else write("No shadows there."); + } + return 1; +} + +int enshadow(string str){ + object target; + string s1,s2,s3,file; + allowed=preAction(1); + if(allowed == 2) return 1; + if(sscanf(str,"%sshadow/%s %s",s1,s2,s3) > 0) file = s2; + else if(sscanf(str,"%sshadow/%s.c %s",s1,s2,s3) > 0) file = s2; + else if(sscanf(str,"%s %s",s1,s2) > 0) file = s1; + else { + write("You must specify a file within /shadows and a target."); + return 1; + } + if( s3 && s3 != "") target = present(s3,environment(this_player())); + else if(s3 == "me") target = this_player(); + else target = present(s2,environment(this_player())); + + if(!target) { + write("Please specify a file within /shadows and a target."); + return 1; + } + + if(file_size("/shadow/"+file) < 1){ + write("That is not a valid shadow."); + return 1; + } + + new("/shadow/"+file)->eventShadow(target); + write("You enshadow "+target->GetName()+" with /shadow/"+file); + return 1; +} + +int medscan(string str){ + allowed=preAction(); + if(allowed == 2) return 1; + if(!str || str == "") { + write("Please rephrase, including your target this time."); + return 1; + } + if(str == "me") str = this_player()->GetKeyName(); + person=present(str,environment(scanner)); + if(!person || !living(person)){ + write("Disease check: No such being found"); + return 1; + } + write("Scanning for germs..."); + this_object()->germ_scan(str); + write("Germ scan complete.\n"); + write("Wound scan currently offline."); + return 1; +} + +int germ_scan(mixed strob ){ + int i; + string a,b,c,str; + if(stringp(strob)) { + str = strob; + if(str == "me") str = this_player()->GetKeyName(); + person=present(str,environment(scanner)); + if(!person || !living(person)){ + write("This being was not found."); + return 2; + } + } + if(objectp(strob)){ + person = strob; + str = person->GetName(); + } + if(!str || str == "") { + write("Please rephrase, including your target this time."); + return 1; + } + if(!living(person)){ + write("This thing is not alive."); + return 2; + } + ngstuff=all_inventory(person); + gstuff = ({}); + say(scanner->GetName()+" waves a tricorder at "+person->GetName()+".",({scanner,person}) ); + tell_object(person,scanner->GetName()+" waves a tricorder at you."); + + for(i=0;iisGerm()== 1 && !sizeof(gstuff)) gstuff = ({ngstuff[i]}); + if(ngstuff[i]->isGerm()== 1 && sizeof(gstuff) > 0 ) gstuff += ({ngstuff[i]}); + } + if(!sizeof(gstuff)){ + write(person->GetName()+" has no detectable diseases."); + return 2; + } + for(i=0;iGetKeyName() || a == "" ) a = "generic disease"; + if(!b=gstuff[i]->GetType() || b == "" ) b = "unknown type"; + if(intp(gstuff[i]->GetCure())) c=gstuff[i]->GetCure(); + if(!c) c = 0; + write("Disease: "+a+", type: "+b+", severity: "+c); + return 1; + } + write("Please specify a living being that shares your current location."); + return 2; +} + +int germ_squash(string str){ + int i,bar,c; + object array whom; + allowed=preAction(1); + if(allowed == 2) return 1; + if(!str || str == "") { + write("Please specify a living thing, or \"all\" for everything in "+ + "your environment."); + return 1; + } + if(str == "me") str = this_player()->GetKeyName(); + person=present(str,environment(scanner)); + whom = ({}); + if(!person && str !="all"){ + write("Disease check: No such being found"); + return 1; + } + + if( str !="all" && !living(person)){ + write("Disease check: No such living being found"); + return 1; + } + if(str =="all") whom = get_livings(environment(this_player())); + if(str !="all") whom = ({person}); + foreach(object ingrate in whom){ + i=germ_scan(ingrate); + if(i!=2 && intp(gstuff[i]->GetCure()) ) bar=gstuff[i]->GetCure(); + if(i!=2 && !intp(gstuff[i]->GetCure()) ) write("GetCureType: "+typeof(gstuff[i]->GetCure())); + if(!i) { write("Extremely weird error here."); return 1; } + for(i=0;iisGerm() ){ + c=10; + gstuff[i]->SetCure(c); + if(intp(gstuff[i]->GetCure()) ){ + gstuff[i]->eventCure(ingrate,c,gstuff[i]->GetType()); + write("You cure "+ingrate->GetName()+"'s disease."); + say(ingrate->GetName()+" looks healthier.",ingrate); + tell_object(ingrate,"You feel less sick."); + } + if(gstuff[i] && gstuff[i]->isGerm() && !intp(gstuff[i]->GetCure())){ + write("This disease uses a functional as its SetCure condition."); + write("It will not be cured by this device. You will have to "+ + "manually review the germ's code to determine what will cure it."); + write("SetCure() data type: "+typeof(gstuff[i]->GetCure())); + write("Filename: "+base_name(gstuff[i])+"\n"); + } + } + } + gstuff=({}); + } + return 1; +} + +int infect(string str){ + string whom,what,disease; + object ob; + mixed foo; + allowed=preAction(1); + if(allowed == 2) return 1; + if(!str){ + write("Please indicate whom to infect, and with what. Example:"); + write("infect doofus cold"); + write("Current valid diseases: cold, flu, fleas, lice, h1n1"); + return 1; + } + if(sscanf(str,"%s %s",whom,what)) { + if(!whom || !what || whom == "" || what == ""){ + write("Please indicate whom to infect, and with what. Example:"); + write("infect doofus cold"); + write("Current valid diseases: cold, flu, fleas, lice"); + return 1; + } + } + if(!whom || !what || whom == "" || what == ""){ + write("Please indicate whom to infect, and with what. Example:"); + write("infect doofus cold"); + write("Current valid diseases: cold, flu, fleas, lice"); + return 1; + } + if(whom == "me") whom = this_player()->GetKeyName(); + person=present(whom,environment(scanner)); + if(!person || !living(person)){ + write("This being was not found."); + return 1; + } + if(what == "cold") disease = "/domains/town/obj/cold"; + else if(what == "flu") disease = "/domains/town/obj/flu"; + else if(what == "fleas") disease = "/domains/town/obj/fleas"; + else if(what == "lice") disease = "/domains/town/obj/lice"; + else if(what == "rage") disease = "/domains/town/obj/rage"; + else if(what == "h1n1") disease = "/domains/town/obj/h1n1"; + else if(what != "") { + write("That isn't a valid disease."); + return 1; + } + if(person){ + write(person->GetName()+" located. Infecting..."); + say(scanner->GetName()+" waves a tricorder at "+person->GetName()+".",person); + if(present(whom,environment(scanner))) { + tell_object(person,scanner->GetName()+" waves a tricorder at you."); + } + } + ob=new(disease); + if(ob) foo = ob->eventInfect(person); + else write("There's a problem with that parasite."); + return 1; +} + +int amputate(string str){ + string whom,which,limb,both; + allowed=preAction(); + if(allowed == 2) return 1; + if(!str){ + write("Please indicate whose limbs you wish to amputate, and which. Example:"); + write("amputate joey left hand"); + return 1; + } + if(sscanf(str,"%s %s %s",whom,which,limb)) { + if(!limb) sscanf(str,"%s %s",whom,limb); + } + if(whom && whom == "me") whom = this_player()->GetKeyName(); + if(!whom || !limb){ + write("Please indicate whose limbs you wish to amputate, and which. Example:"); + write("amputate joey left hand"); + return 1; + } + if(!person=present(whom,environment(scanner))){ + write(capitalize(whom)+" isn't here."); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(!creatorp(this_player()) && strsrch(base_name(person), homedir(this_player()))){ + write("Builders can only do this to NPC's that belong to them."); + return 1; + } + both = limb; + if(which && which !="") both = which+" "+limb; + //write("both: "+both); + + if(!person->RemoveLimb(both, scanner)){ + write("You wave your tricorder menacingly, but nothing happens."); + tell_room(environment(person),scanner->GetName()+" waves a tricorder at "+person->GetName()+" in a threatening manner.", ({ scanner,person }) ); + tell_object(person,scanner->GetName()+" waves "+possessive(scanner)+" tricorder menacingly at you."); + return 1; + } + + if(both == "head"){ + tell_room(environment(person),scanner->GetName()+" waves a tricorder at "+person->GetName()+", and "+ + person->GetName()+"'s head falls off!", ({ scanner,person }) ); + write("You decapitate "+person->GetName()+"."); + tell_object(person,scanner->GetName()+" decapitates you with a wave of "+possessive(scanner)+" tricorder!"); + //person->RemoveLimb(both, scanner); + return 1; + } + stumps=person->GetLimbs(); + if(!stumps) { + write(person->GetName()+" hasn't any limbs."); + say(scanner->GetName()+" waves a tricorder at "+person->GetName()+".",scanner,person); + tell_object(person,scanner->GetName()+" waves a tricorder at you."); + return 1; + } + if(member_array(both,stumps) != -1){ + person->RemoveLimb(both, scanner); + write("You amputate "+person->GetName()+"'s "+both); + say(scanner->GetName()+" has amputated "+person->GetName()+"'s "+both+" "+ + "with an energy beam from a medical tricorder.",scanner,person); + tell_object(person,scanner->GetName()+" waves a tricorder at you and "+ + "your "+both+" is severed."); + return 1; + } + if(member_array(limb,stumps)!= -1){ + //person->RemoveLimb(limb, scanner); + write("You amputate "+person->GetName()+"'s "+limb+"."); + say(scanner->GetName()+" has amputated "+person->GetName()+"'s "+both+" "+ + "with an energy beam from a medical tricorder.",scanner,person); + tell_object(person,scanner->GetName()+" waves a tricorder at you and"+ + "your "+limb+" is severed."); + return 1; + } + //write("There is some sort of problem, it looks like. No "+ + //"limbs are severed."); + return 1; +} + +int regenerate(string str){ + allowed=preAction(); + if(allowed==2) return 1; + if(!str){ + write("Please indicate whose limbs you wish to regenerate."); + return 1; + } + if(str == "me") str = this_player()->GetKeyName(); + if(!person=present(str,environment(scanner))){ + write(capitalize(str)+" isn't here."); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + stumps=person->GetMissingLimbs(); + if(!stumps) { + write(person->GetName()+" isn't missing any limbs."); + say(scanner->GetName()+" waves a tricorder at "+person->GetName()+".",scanner,person); + tell_object(person,scanner->GetName()+" waves a tricorder at you."); + return 1; + } + if(!creatorp(this_player()) && strsrch(base_name(person), homedir(this_player()))){ + write("Builders can only do this to NPC's that belong to them."); + return 1; + } + for(i=0;iRestoreLimb(stumps[i]); + write("You regenerate "+person->GetName()+"'s "+stumps[i]+"."); + say(scanner->GetName()+" regenerates "+person->GetName()+"'s "+stumps[i]+".",scanner,person); + tell_object(person,scanner->GetName()+" regenerates your "+stumps[i]+"."); + } + return 1; +} + +int DoSkillChange(string str, int i){ + int more_or_less; + if(str == "me") str = this_player()->GetKeyName(); + this_skill = person->GetSkill(str); + if(this_skill["level"] < i) more_or_less = 1; + skillclass=this_skill["class"]; + person->SetSkill(str,i,skillclass); + say(scanner->GetName()+" waves a medical tricorder at "+person->GetName()+".",({person,scanner})); + tell_object(person,scanner->GetName()+" waves a medical tricorder at you."); + if(more_or_less == 1) tell_room(environment(person), person->GetName()+" looks somehow more experienced.",({person}) ); + if(more_or_less != 1) tell_room(environment(person), person->GetName()+" looks somehow less experienced.",({person}) ); + write("You've set "+person->GetName()+"'s "+str+" to level "+i+"."); + return 1; +} +int DoAllSkills(int foo){ + int i; + for(i=0;iGetSkill(skilllist[i]); + skillclass=this_skill["class"]; + person->SetSkill(skilllist[i],foo,skillclass); + write("You've set "+person->GetName()+"'s "+skilllist[i]+" to level "+foo+"."); + } + say(scanner->GetName()+" waves a medical tricorder at "+person->GetName()+".",({person,scanner})); + say(person->GetName()+" seems to undergo an almost undetectable, subtle transformation.",({person,scanner})); + tell_object(person,scanner->GetName()+" waves a medical tricorder at you."); + return 1; +} +int setskill(string str){ + string whom,skill; + string skill1,skill2,rubbish; + int amt; + allowed=preAction(); + if(allowed==2) return 1; + if(!str) { + write("Syntax: setskill "); + write("If there is a space in the skill name, replace it with "+ + "an underscore. Example:\nsetskill schmucky blade_attack 5"); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(!sscanf(str,"%s %s %d",whom,skill,amt)) { sscanf(str,"%s %s",whom,skill); } + if(sscanf(str,"%s %s_%s ",rubbish,skill1,skill2) && skill1 && skill2){ + whom = rubbish; + skill = skill1 + " " +skill2; + } + write("skill: "+skill); + if(!whom || whom == ""){ + write("Syntax: setskill "); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(whom == "me") whom = this_player()->GetKeyName(); + if(!person=present(whom,environment(scanner))){ + write(capitalize(whom)+" isn't here."); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(!creatorp(this_player()) && strsrch(base_name(person), homedir(this_player()))){ + write("Builders can only do this to NPC's that belong to them."); + return 1; + } + this_skill = ([]); + skilllist = ({}); + skilllist = person->GetSkills(); + if(amt < 0) amt = 0; + if(allowed==2) return 1; + if ( !whom || !skill || !amt || !intp(amt) ){ + write("Syntax: setskill "); + write("If there is a space in the skill name, replace it with "+ + "an underscore. Example:\nsetskill schmucky blade_attack 5"); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(skill == "all") { DoAllSkills(amt); return 1; } + if(member_array(skill,skilllist) == -1) { + write(capitalize(whom)+" doesn't have that skill."); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + DoSkillChange(skill, amt); + return 1; +} +int DoStatChange(string str, int i){ + if(str == "me") str = this_player()->GetKeyName(); + this_stat = person->GetStat(str); + statclass=this_stat["class"]; + person->SetStat(str,i,statclass); + say(scanner->GetName()+" waves a medical tricorder at "+person->GetName()+".",({person,scanner})); + tell_object(person,scanner->GetName()+" waves a medical tricorder at you."); + write("You've set "+person->GetName()+"'s "+str+" to level "+i+"."); + return 1; +} +int DoAllStats(int foo){ + int i; + for(i=0;iGetStat(statlist[i]); + statclass=this_stat["class"]; + person->SetStat(statlist[i],foo,statclass); + write("You've set "+person->GetName()+"'s "+statlist[i]+" to level "+foo+"."); + } + say(scanner->GetName()+" waves a medical tricorder at "+person->GetName()+".",({person,scanner})); + tell_object(person,scanner->GetName()+" waves a medical tricorder at you."); + return 1; +} +int setstat(string str){ + string whom,stat; + int amt; + allowed=preAction(); + if(allowed==2) return 1; + if(!str) { + write("Syntax: setstat "); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(!sscanf(str,"%s %s %d",whom,stat,amt)) { sscanf(str,"%s %s",whom,stat); } + if(!whom || whom == ""){ + write("Syntax: setstat "); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(whom == "me") whom = this_player()->GetKeyName(); + if(!person=present(whom,environment(scanner))){ + write(capitalize(whom)+" isn't here."); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(!creatorp(this_player()) && strsrch(base_name(person), homedir(this_player()))){ + write("Builders can only do this to NPC's that belong to them."); + return 1; + } + this_stat = ([]); + statlist = ({}); + statlist = person->GetStats(); + if(amt < 0) amt = 0; + if(allowed==2) return 1; + if ( !whom || !stat || !amt || !intp(amt) ){ + write("Syntax: setstat "); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(stat == "all") { DoAllStats(amt); return 1; } + if(member_array(stat,statlist) == -1) { + write(capitalize(whom)+" doesn't have that stat."); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + DoStatChange(stat, amt); + return 1; +} +int modstam(string str, int stamina){ + string whom; + int tempint,staminalevel; + object person; + allowed=preAction(); + if(allowed==2) return 1; + if(!str){ + write("Syntax: modstam "); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + sscanf(str,"%s %d",whom,stamina); + if (!whom || !stamina){ + write("Syntax: modstam "); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(whom == "me") whom = this_player()->GetKeyName(); + if(!intp(stamina)){ + write("Syntax: modstam "); + write("Where is an integer. For example:\nmodstam joe 3\nmodstam mike -10\n"); + say(scanner->GetName()+" fumbles stupidly with a medical tricorder.",scanner); + return 1; + } + person=present(whom,environment(scanner)); + if(!person){ + write(capitalize(whom)+" isn't here."); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(!creatorp(this_player()) && strsrch(base_name(person), homedir(this_player()))){ + write("Builders can only do this to NPC's that belong to them."); + return 1; + } + staminalevel=person->GetStaminaPoints(); + tempint = staminalevel + stamina; + if(tempint < 0) { + stamina = stamina + absolute_value(tempint); + } + person->AddStaminaPoints(stamina); + if(stamina > 0){ + say(scanner->GetName()+" points a medical tricorder at "+capitalize(whom)+", "+ + "and "+nominative(person)+" looks a bit more at ease.", ({person,scanner}) ); + tell_object(person,scanner->GetName()+" points a medical tricorder at you and you "+ + "suddenly feel stronger."); + write("You've raised "+capitalize(whom)+"'s stamina level by "+stamina+" points."); + return 1; + } + if(stamina < 0){ + stamina=absolute_value(stamina); + say(scanner->GetName()+" points a medical tricorder at "+capitalize(whom)+", "+ + "and "+nominative(person)+" looks uncomfortable.", ({person,scanner}) ); + tell_object(person,scanner->GetName()+" points a medical tricorder at you and you "+ + "suddenly feel weaker."); + write("You've lowered "+capitalize(whom)+"'s stamina level by "+stamina+" points."); + return 1; + } + write("Aucun effet."); + return 1; +} +int modtox(string str, int poison){ + string whom; + int tempint,poisonlevel; + object person; + allowed=preAction(); + if(allowed==2) return 1; + if(!str){ + write("Syntax: modtox "); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + sscanf(str,"%s %d",whom,poison); + if (!whom || !poison){ + write("Syntax: modtox "); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(whom == "me") whom = this_player()->GetKeyName(); + if(!intp(poison)){ + write("Syntax: modtox "); + write("Where is an integer. For example:\nmodtox joe 3\nmodtox mike -10\n"); + say(scanner->GetName()+" fumbles stupidly with a medical tricorder.",scanner); + return 1; + } + person=present(whom,environment(scanner)); + if(!person){ + write(capitalize(whom)+" isn't here."); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(!creatorp(this_player()) && strsrch(base_name(person), homedir(this_player()))){ + write("Builders can only do this to NPC's that belong to them."); + return 1; + } + poisonlevel=person->GetPoison(); + tempint = poisonlevel + poison; + if(tempint < 0) { + poison = poison + absolute_value(tempint); + } + person->AddPoison(poison); + if(poison > 0){ + say(scanner->GetName()+" points a medical tricorder at "+capitalize(whom)+", "+ + "and "+nominative(person)+" looks paler and shaky.", ({person,scanner}) ); + tell_object(person,scanner->GetName()+" points a medical tricorder at you and you "+ + "suddenly feel ill."); + write("You've raised "+capitalize(whom)+"'s poison level by "+poison+" points."); + return 1; + } + if(poison < 0){ + poison=absolute_value(poison); + say(scanner->GetName()+" points a medical tricorder at "+capitalize(whom)+", "+ + "and "+nominative(person)+" looks less ill.", ({person,scanner}) + ); + tell_object(person,scanner->GetName()+" points a medical tricorder at you and you "+ + "suddenly feel better than before."); + write("You've lowered "+capitalize(whom)+"'s poison level by "+poison+" points."); + return 1; + } + write("Aucun effet."); + return 1; +} +int modmag(string str, int magic){ + string whom; + int tempint,magiclevel; + object person; + allowed=preAction(); + if(allowed==2) return 1; + if(!str){ + write("Syntax: modmagic "); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + sscanf(str,"%s %d",whom,magic); + if (!whom || !magic){ + write("Syntax: modmagic "); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(whom == "me") whom = this_player()->GetKeyName(); + + if(!intp(magic)){ + write("Syntax: modmagic "); + write("Where is an integer. For example:\nmodmagic joe 3\nmodmagic mike -10\n"); + say(scanner->GetName()+" fumbles stupidly with a medical tricorder.",scanner); + return 1; + } + person=present(whom,environment(scanner)); + if(!person){ + write(capitalize(whom)+" isn't here."); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(!creatorp(this_player()) && strsrch(base_name(person), homedir(this_player()))){ + write("Builders can only do this to NPC's that belong to them."); + return 1; + } + magiclevel=person->GetMagicPoints(); + tempint = magiclevel + magic; + if(tempint < 0) { + magic = magic + absolute_value(tempint); + } + person->AddMagicPoints(magic); + if(magic > 0){ + say(scanner->GetName()+" points a medical tricorder at "+capitalize(whom)+", "+ + "and "+nominative(person)+" glows briefly.", ({person,scanner}) ); + tell_object(person,scanner->GetName()+" points a medical tricorder at you and you "+ + "suddenly feel more magical."); + write("You've raised "+capitalize(whom)+"'s magic level by "+magic+" points."); + return 1; + } + if(magic < 0){ + magic=absolute_value(magic); + say(scanner->GetName()+" points a medical tricorder at "+capitalize(whom)+", "+ + "and "+nominative(person)+" looks somehow more plain.", ({person,scanner}) ); + tell_object(person,scanner->GetName()+" points a medical tricorder at you and you "+ + "suddenly feel less magical."); + write("You've lowered "+capitalize(whom)+"'s magic level by "+magic+" points."); + return 1; + } + write("Aucun effet."); + return 1; +} +int moddrink(string str, int drink){ + string whom; + int tempint,drinklevel; + object person; + allowed=preAction(); + if(allowed==2) return 1; + if(!str){ + write("Syntax: moddrink "); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + sscanf(str,"%s %d",whom,drink); + if (!whom || !drink){ + write("Syntax: moddrink "); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(whom == "me") whom = this_player()->GetKeyName(); + + if(!intp(drink)){ + write("Syntax: moddrink "); + write("Where is an integer. For example:\nmoddrink joe 3\nmoddrink mike -10\n"); + say(scanner->GetName()+" fumbles stupidly with a medical tricorder.",scanner); + return 1; + } + person=present(whom,environment(scanner)); + if(!person){ + write(capitalize(whom)+" isn't here."); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(!creatorp(this_player()) && strsrch(base_name(person), homedir(this_player()))){ + write("Builders can only do this to NPC's that belong to them."); + return 1; + } + drinklevel=person->GetDrink(); + tempint = drinklevel + drink; + if(tempint < 0) { + drink = drink + absolute_value(tempint); + } + person->AddDrink(drink); + if(drink > 0){ + say(scanner->GetName()+" points a medical tricorder at "+capitalize(whom)+", "+ + "and "+nominative(person)+" looks a bit more at ease.", ({person,scanner}) ); + tell_object(person,scanner->GetName()+" points a medical tricorder at you and you "+ + "suddenly feel more hydrated."); + write("You've raised "+capitalize(whom)+"'s drink level by "+drink+" points."); + return 1; + } + if(drink < 0){ + drink=absolute_value(drink); + say(scanner->GetName()+" points a medical tricorder at "+capitalize(whom)+", "+ + "and "+nominative(person)+" looks uncomfortable.", ({person,scanner}) ); + tell_object(person,scanner->GetName()+" points a medical tricorder at you and you "+ + "suddenly feel thirstier."); + write("You've lowered "+capitalize(whom)+"'s drink level by "+drink+" points."); + return 1; + } + write("Aucun effet."); + return 1; +} +int modfood(string str, int food){ + string whom; + int tempint,foodlevel; + object person; + allowed=preAction(); + if(allowed==2) return 1; + if(!str){ + write("Syntax: modfood "); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + sscanf(str,"%s %d",whom,food); + if (!whom || !food){ + write("Syntax: modfood "); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(whom == "me") whom = this_player()->GetKeyName(); + + if(!intp(food)){ + write("Syntax: modfood "); + write("Where is an integer. For example:\nmodfood joe 3\nmodfood mike -10\n"); + say(scanner->GetName()+" fumbles stupidly with a medical tricorder.",scanner); + return 1; + } + person=present(whom,environment(scanner)); + if(!person){ + write(capitalize(whom)+" isn't here."); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(!creatorp(this_player()) && strsrch(base_name(person), homedir(this_player()))){ + write("Builders can only do this to NPC's that belong to them."); + return 1; + } + foodlevel=person->GetFood(); + tempint = foodlevel + food; + if(tempint < 0) { + food = food + absolute_value(tempint); + } + person->AddFood(food); + if(food > 0){ + say(scanner->GetName()+" points a medical tricorder at "+capitalize(whom)+", "+ + "and "+nominative(person)+" looks a bit more at ease.", ({person,scanner}) ); + tell_object(person,scanner->GetName()+" points a medical tricorder at you and you "+ + "suddenly feel more nourished."); + write("You've raised "+capitalize(whom)+"'s food level by "+food+" points."); + return 1; + } + if(food < 0){ + food=absolute_value(food); + say(scanner->GetName()+" points a medical tricorder at "+capitalize(whom)+", "+ + "and "+nominative(person)+" looks uncomfortable.", ({person,scanner}) ); + tell_object(person,scanner->GetName()+" points a medical tricorder at you and you "+ + "suddenly feel hungrier."); + write("You've lowered "+capitalize(whom)+"'s food level by "+food+" points."); + return 1; + } + write("Aucun effet."); + return 1; +} +int modcaff(string str, int caff){ + string whom; + int tempint,cafflevel; + object person; + allowed=preAction(); + if(allowed==2) return 1; + if(!str){ + write("Syntax: modcaff "); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + sscanf(str,"%s %d",whom,caff); + if (!whom || !caff){ + write("Syntax: modcaff "); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(whom == "me") whom = this_player()->GetKeyName(); + + if(!intp(caff)){ + write("Syntax: modcaff "); + write("Where is an integer. For example:\nmodcaff joe 3\nmodcaff mike -10\n"); + say(scanner->GetName()+" fumbles stupidly with a medical tricorder.",scanner); + return 1; + } + person=present(whom,environment(scanner)); + if(!person){ + write(capitalize(whom)+" isn't here."); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(!creatorp(this_player()) && strsrch(base_name(person), homedir(this_player()))){ + write("Builders can only do this to NPC's that belong to them."); + return 1; + } + cafflevel=person->GetCaffeine(); + tempint = cafflevel + caff; + if(tempint < 0) { + caff = caff + absolute_value(tempint); + } + person->AddCaffeine(caff); + if(caff > 0){ + say(scanner->GetName()+" points a medical tricorder at "+capitalize(whom)+", "+ + "and "+nominative(person)+" looks a bit keener.", ({person,scanner}) ); + tell_object(person,scanner->GetName()+" points a medical tricorder at you and you "+ + "suddenly feel tipsy."); + write("You've raised "+capitalize(whom)+"'s caffeine level by "+caff+" points."); + return 1; + } + if(caff < 0){ + caff=absolute_value(caff); + say(scanner->GetName()+" points a medical tricorder at "+capitalize(whom)+", "+ + "and "+nominative(person)+" looks more focused and alert.", ({person,scanner}) ); + tell_object(person,scanner->GetName()+" points a medical tricorder at you and you "+ + "suddenly feel more awake."); + write("You've lowered "+capitalize(whom)+"'s caffeine level by "+caff+" points."); + return 1; + } + write("Aucun effet."); + return 1; +} +int modalc(string str, int alc){ + string whom; + int tempint,alclevel; + object person; + allowed=preAction(); + if(allowed==2) return 1; + if(!str){ + write("Syntax: modalc "); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + sscanf(str,"%s %d",whom,alc); + if (!whom || !alc){ + write("Syntax: modalc "); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(whom == "me") whom = this_player()->GetKeyName(); + + if(!intp(alc)){ + write("Syntax: modalc "); + write("Where is an integer. For example:\nmodalc joe 3\nmodalc mike -10\n"); + say(scanner->GetName()+" fumbles stupidly with a medical tricorder.",scanner); + return 1; + } + + person=present(whom,environment(scanner)); + if(!person){ + write(capitalize(whom)+" isn't here."); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(!creatorp(this_player()) && strsrch(base_name(person), homedir(this_player()))){ + write("Builders can only do this to NPC's that belong to them."); + return 1; + } + alclevel=person->GetAlcohol(); + tempint = alclevel + alc; + if(tempint < 0) { + alc = alc + absolute_value(tempint); + } + + person->AddAlcohol(alc); + if(alc > 0){ + say(scanner->GetName()+" points a medical tricorder at "+capitalize(whom)+", "+ + "and "+nominative(person)+" looks dizzier and more disoriented.", ({person,scanner}) ); + tell_object(person,scanner->GetName()+" points a medical tricorder at you and you "+ + "suddenly feel tipsy."); + write("You've raised "+capitalize(whom)+"'s alcohol level by "+alc+" points."); + return 1; + } + if(alc < 0){ + alc=absolute_value(alc); + say(scanner->GetName()+" points a medical tricorder at "+capitalize(whom)+", "+ + "and "+nominative(person)+" looks more focused and alert.", ({person,scanner}) ); + tell_object(person,scanner->GetName()+" points a medical tricorder at you and you "+ + "suddenly feel more sober."); + write("You've lowered "+capitalize(whom)+"'s alcohol level by "+alc+" points."); + return 1; + } + write("Aucun effet."); + return 1; +} +int addhp(string str, int hp){ + string whom; + object person; + allowed=preAction(); + if(allowed==2) return 1; + if(!str){ + write("Syntax: addhp "); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + sscanf(str,"%s %d",whom,hp); + if (!whom || !hp){ + write("Syntax: addhp "); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(whom == "me") whom = this_player()->GetKeyName(); + + if(!intp(hp)){ + write("Syntax: addhp "); + write("Where is an integer. For example:\naddhp joe 3\naddhp mike -10\n"); + say(scanner->GetName()+" fumbles stupidly with a medical tricorder.",scanner); + return 1; + } + person=present(whom,environment(scanner)); + if(!person){ + write(capitalize(whom)+" isn't here."); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(!creatorp(this_player()) && strsrch(base_name(person), homedir(this_player()))){ + write("Builders can only do this to NPC's that belong to them."); + return 1; + } + person->AddHP(hp); + if(hp > 0){ + say(scanner->GetName()+" points a medical tricorder at "+capitalize(whom)+", "+ + "and "+nominative(person)+" looks stronger and more refreshed.", ({person,scanner}) ); + tell_object(person,scanner->GetName()+" points a medical tricorder at you and you "+ + "suddenly feel stronger and more refreshed."); + write("You've raised "+capitalize(whom)+"'s health by "+hp+" points."); + return 1; + } + if(hp < 0){ + hp=absolute_value(hp); + say(scanner->GetName()+" points a medical tricorder at "+capitalize(whom)+", "+ + "and "+nominative(person)+" looks weaker and duller.", ({person,scanner}) ); + tell_object(person,scanner->GetName()+" points a medical tricorder at you and you "+ + "suddenly feel weaker and more frail."); + write("You've lowered "+capitalize(whom)+"'s health by "+hp+" points."); + return 1; + } + write("Aucun effet."); + return 1; +} +int extract(string str){ + string what,whom; + object person, slug; + int rifleshot_wounds,firearms_wounds,wounds; + allowed=preAction(); + if(allowed==2) return 1; + if(!str){ + write("Extract what from whom?"); + write("Example: extract slug from "); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + sscanf(str,"%s from %s",what,whom); + if (!what || ! whom){ + write("Extract what from whom?"); + write("Example: extract slug from "); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(whom == "me") whom = this_player()->GetKeyName(); + person=present(whom,environment(scanner)); + if(!person){ + write(capitalize(whom)+" isn't here."); + say(scanner->GetName()+" fumbles with a medical tricorder.",scanner); + return 1; + } + if(!creatorp(this_player()) && strsrch(base_name(person), homedir(this_player()))){ + write("Builders can only do this to NPC's that belong to them."); + return 1; + } + slug=present("firearms_wound",person); + wounds=0; + wounds=person->GetLead("gunshot_wounds"); + wounds+=person->GetLead("rifleshot_wounds"); + if(!slug && what=="slug"){ + write(capitalize(whom)+" has no gunshot injury."); + say(scanner->GetName()+" looks a bit silly waving a medical tricorder at "+capitalize(whom)+".",({ scanner, person }) ); + tell_object(person,scanner->GetName()+" looks a bit silly waving a medical tricorder at you."); + return 1; + } + if(slug && what=="slug" && wounds > 0 ){ + write("You extract a lead slug from "+capitalize(whom)+"'s body."); + say(scanner->GetName()+" deftly extracts a lead slug from "+capitalize(whom)+" with a medical tricorder.",({ scanner, person }) ); + tell_object(person,scanner->GetName()+" deftly extracts a lead slug from you with a medical tricorder."); + firearms_wounds=person->GetLead("firearms_wounds"); + rifleshot_wounds=person->GetLead("rifleshot_wounds"); + slug=new("/domains/town/obj/spent"); + if(person->GetLead("gunshot_wounds") > 0) { + person->AddLead("gunshot_wounds", -1); + slug->SetShort("a spent pistol slug"); + --wounds; + slug->eventMove(environment(scanner)); + if(person->GetLead() < 1){ + slug=present("firearms_wound",person); + if(slug) slug->eventDestruct(); + return 1; + } + return 1; + } + if(person->GetLead("rifleshot_wounds") > 0) { + person->AddLead("rifleshot_wounds", -1); + slug->SetShort("a spent rifle slug"); + --wounds; + slug->eventMove(environment(scanner)); + if(person->GetLead() < 1){ + if(slug) slug->eventDestruct(); + slug=present("firearms_wound",person); + if(slug) slug->eventDestruct(); + return 1; + } + } + slug->eventMove(environment(scanner)); + slug=present("firearms_wound",person); + if(wounds < 1 && slug){ + slug->eventDestruct(); + return 1; + } + } + return 1; +} +int fscan(string str){ + object ob; + object *stuffs; + mixed *stuff; + allowed=preAction(); + if(allowed==2) return 1; + if(!str || str=="" || str=="here") { + ob = environment(this_player()); + name = ob->GetShort(); + str = base_name(ob); + } + if(str == "me") str = this_player()->GetKeyName(); + if(present(str,this_player())) { + ob = present(str,this_player()); + name = ob->GetName(); + } + if(present(str,environment(this_player()))) { + ob=present(str,environment(this_player())); + name = ob->GetName(); + } + if(!ob){ + write("The tricorder fails to locate any such person, object, or environment.\n"); + say(this_player()->GetName()+" scans around aimlessly with "+ + " a medical tricorder.\n"); + return 1; + } + write("You perform a file scan of "+name+".\n\n"); + write("\n"+name+" is in posession of the following items:"); + write("-------------------------------------------"); + say(this_player()->GetName()+" performs a tricorder scan of "+name+".\n",ob); + tell_object(ob,this_player()->GetName()+" scans you with "+ + "a medical tricorder.\n"); + stuffs=deep_inventory(ob); + filter(stuffs, (: this_object()->analyze(file_name($1)) :), this_object()); + filter(stuffs, (: this_object()->getname($1) :), this_object()); + stuff=deep_inherit_list(ob); + write("\n"+name+" is composed of the following files:\n"); + write("-------------------------------------------"); + foreach(mixed gene in deep_inherit_list(ob)) { + if(!stringp(gene)) break; + if(!gene) gene=""; + write(gene); + } + write("\nSCAN COMPLETE"); + return 1; +} +void analyze(string str){ + string temp, temp2; + sscanf(str,"%s#%s",temp,temp2); + if(temp=="/lib/corpse"){ + write("Found a corpse. Absolute name:\n"+str); + return; + } + return; +} +string getname(object ob){ + string temp, temp2; + if(!ob) return "No object found."; + else + sscanf(file_name(ob),"%s#%s",temp,temp2); + write(ob->GetName()+",\t\tfilename: "+temp+".c"); + return ob->GetName(); +} +mixed assess(string args) { + string *lines, *arr, *limbs; + object ob; + string tmp1, tmp2; + int i, x, y, cols; + if( args == "" || !args ) return 0; + if(args == "me") args = this_player()->GetKeyName(); + 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."; + if(!creatorp(this_player()) && strsrch(base_name(ob), homedir(this_player()))){ + write("Builders can only do this to NPC's that belong to them."); + return 1; + } + if(tmp1 = ob->GetGender()) { + cols = ((int *)this_player()->GetScreen())[0]; + tmp1 = ob->GetCapName() + " aka " + ob->GetShort() + + ", level " + ob->GetLevel() + " " + ob->GetGender(); + if( !(tmp2 = ob->GetRace()) ) tmp2 = "blob"; + tmp1 += " " + tmp2; + if( !(tmp2 = ob->GetClass()) ) tmp2 = "drifter"; + tmp1 += " " + capitalize(tmp2); + if( tmp2 = ob->GetSpouse() ) + tmp1 += " (spouse: " + tmp2 + ")"; + lines = ({ center(tmp1, cols) }); + if( ob->GetUndead() ) tmp1 = "Undead"; + else tmp1 = "Alive"; + if( ob->GetSleeping() ) tmp1 += " / Sleeping"; + else tmp1 += " / Awake"; + if( ob->GetParalyzed() ) tmp1 += " / Paralyzed"; + lines += ({ center(tmp1, cols), "" }); + lines += ({ center("Health: " +ob->GetHealthPoints() + "/"+ + ob->GetMaxHealthPoints() + " Magic: " + + ob->GetMagicPoints() + "/" + + ob->GetMaxMagicPoints() + " Stamina: " + + ob->GetStaminaPoints() + "/" + + to_int((float)ob->GetMaxStaminaPoints()) + " Carry: " + + ob->GetCarriedMass() + "/" + + ob->GetMaxCarry(), cols) }); + lines += ({ center("Food: " + ob->GetFood() + " " + + "Drink: " + ob->GetDrink() + " " + + "Alcohol: " + ob->GetAlcohol() + " " + + "Caffeine: " + ob->GetCaffeine() + " " + + "Poison: " + ob->GetPoison() + " ", cols) }); + lines += ({ center("Training Points: " + ob->GetTrainingPoints()) }); + lines += ({ "", "Limbs:" }); + limbs = ob->GetWieldingLimbs(); + arr = map(ob->GetLimbs(), + (: sprintf("%:-14s%s (%d) %d/%d", $1, + ((member_array($1, $(limbs)) == -1) ? " " : "*"), + ($(ob))->GetLimbClass($1), + ($(ob))->GetHealthPoints($1), + ($(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(ob->GetSkills(), + function(string skill, object who) { + mapping mp = who->GetSkill(skill); + int x; + x = to_int(percent(mp["points"], + who->GetMaxSkillPoints(skill, mp["level"]))); + return sprintf("%:-18s (%d) %:2d%% - %d/%d", + skill, mp["class"], x, + who->GetSkillLevel(skill), mp["level"] ); + }, 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(ob->GetStats(), + (: sprintf("%:-12s (%d) %d/%d", $1, + ($(ob))->GetStatClass($1), + ($(ob))->GetStatLevel($1), + ($(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 += ({ "", ob->GetName()+" has amassed a net worth of " + + ( ob->GetNetWorth() * currency_rate("gold") ) + " gold."}); + arr = filter( map(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; + } + else { + write("You can't stat a non-living object!"); + return 1; + } +} diff --git a/lib/secure/obj/memo.c b/lib/secure/obj/memo.c new file mode 100644 index 0000000..bbc6a4e --- /dev/null +++ b/lib/secure/obj/memo.c @@ -0,0 +1,87 @@ +/* memo pad by Cratylus @ Frontiers + * Sep 21 2005 + */ + +int read_memo(string str); +int help_msg(); + +string ReadFun(mixed args...){ + help_msg(); + return ""; +} + +#include +#include +inherit LIB_ITEM; +int dirchecked; +string ownerstr,capownerstr,fileread; +object ownerob; +void create(){ + ::create(); + SetKeyName("memo pad"); + SetId( ({"pad","memo","memo pad","notepad"}) ); + SetShort("a yellow memo pad"); + SetLong("A yellow pad of papers to write your memos on. "+ + "There seems to be instructions written on it."); + SetMass(20); + SetVendorType(VT_TREASURE); + SetItems(([ ({"instruction", "instructions", "words"}) : "Words that "+ + "explain how to use the notepad. Try: read instructions on notepad.", + ]) ); + SetRead( ([ ({"instruction", "instructions", "words"}) : (: ReadFun :), + "default" : (: read_memo :), + ]) ); +} + +void init(){ + ::init(); + add_action("memo","memo"); + add_action("clean_memo","fresh"); + add_action("erase_memo","erase"); + ownerob=environment(this_object()); + if(living(ownerob)) capownerstr=capitalize(ownerob->GetKeyName()); + if(capownerstr) ownerstr=lower_case(capownerstr); + dirchecked=0; +} +int memo(string str){ + if(!dirchecked){ + this_object()->checkdir(); + } + if(!str){ + write("You do not write anything on your memo pad.\n"); + return 1; + } + write_file(homedir(this_player())+"/log/memo",str+"\n"); + write("You add a memorandum to your memo pad.\n"); + say(capownerstr+" scribbles in "+possessive(this_player())+" memo pad."); + return 1; +} +int read_memo(mixed str...){ + if(!dirchecked){ + this_object()->checkdir(); + } + fileread=read_file(homedir(this_player())+"/log/memo"); + if(!fileread){ + write("The memo pad is blank.\n"); + write("For instructions: read instructions on memo pad"); + return 1; + } + write("The pad reads:\n"+fileread+"\n"); + say(capownerstr+" flips through "+possessive(this_player())+" memo pad.\n"); + return 1; +} +int help_msg(){ + write("The back of the pad reads:\n\n"+ + "cReMem Memo Pad, For your note-taking needs! Memo pad commands:\n"+ + "----------\n"+ + "memo : Writes into the pad.\n"+ + "read memo : Reads the contents of your memo pad.\n"+ + "----------\n"); + say(capownerstr+" reads the back of a memo pad.\n"); + return 1; +} +int checkdir(){ + if(file_size(homedir(this_player())+"/log") != -2) mkdir(homedir(this_player())+"/log"); + dirchecked=1; + return 1; +} diff --git a/lib/secure/obj/mojo.c b/lib/secure/obj/mojo.c new file mode 100644 index 0000000..f79863e --- /dev/null +++ b/lib/secure/obj/mojo.c @@ -0,0 +1,74 @@ +#include +#include +#include +inherit LIB_ITEM; +int damage1(); +int damage2(); +int damage3(); +int damage4(); +object victim; +int counter; + +void create(){ + ::create(); + SetKeyName("clepius mojo"); + SetId(({"clepius mojo"})); + SetLong(" "); + SetInvis(1); + set_heart_beat(1); + counter = 0; +} + +void init(){ + if(living(environment())){ + victim = environment(); + } +} + + +int eventMojofy(){ + int x; + x=random(100); + if(x < 5) damage4(); + else if(x < 20) damage3(); + else if(x < 35) damage2(); + else if(x < 50) damage1(); + return 1; +} + +int damage1(){ + if( victim && victim->GetStaminaPoints() < 50) victim->AddStaminaPoints(random(5)+1); + return 1; +} + +int damage2(){ + if(victim) victim->AddHP(1); + return 1; +} + +int damage3(){ + if(victim) victim->AddHP(2); + return 1; +} + +int damage4(){ + if(victim) victim->AddHP(3); + return 1; +} + +void heart_beat(){ + if(environment() && !living(environment())) this_object()->eventDestruct(); + if(counter == 100){ + if(environment()) tell_object(environment(),"You feel the effects of the healing salve wear off."); + this_object()->eventMove("/domains/town/room/furnace"); + } + + counter++; + eventMojofy(); +} + + + +mixed CanGet(object ob) { return " ";} +mixed CanDrop(object ob) { return " ";} + diff --git a/lib/secure/obj/pingy.c b/lib/secure/obj/pingy.c new file mode 100644 index 0000000..d003150 --- /dev/null +++ b/lib/secure/obj/pingy.c @@ -0,0 +1,76 @@ +#include +#include +inherit LIB_ITEM; + +int count = 0; +int interval = 0; +string keepalive = ""; + +void validate(){ + if(!this_player() || !environment() || !(this_player() == environment())){ + error("Pingy violation. Stack: "+get_stack()); + } +} + +void create(){ + ::create(); + + SetKeyName("pinger"); + SetId( ({"pinger"}) ); + SetAdjectives( ({"pinger"}) ); + SetShort("a pinger"); + SetLong("This thing can be set to periodically output a string, " + "with the purpose of keeping fickle telnet connections up. " + "\nTo set the interval: interval \n" + "To set the string: vassily \n" + "\nNote that this object is deprecated in favor of the " + "keepalive command."); + SetNoCondition(1); + SetMass(20); + SetBaseCost("silver",10); + set_heart_beat(1); + SetVendorType(VT_TREASURE); +} + +int SetInterval(string str){ + validate(); + interval = atoi(str); + if(!intp(interval)){ + write("That is not a valid integer."); + return 1; + } + + write("Interval set to "+interval+" heartbeats."); + return 1; +} + +int SetKeepalive(string str){ + validate(); + if(!str || str == "") keepalive = "\n"; + else keepalive = str; + write("Keepalive set."); + return 1; +} + +void init(){ + ::init(); + add_action("SetInterval","interval"); + add_action("SetKeepalive","vassily"); +} + +void heart_beat(){ + count++; + if(interval > 0 && count > interval){ + count = 0; + if(living(environment(this_object())) && + true()){ + if(query_idle(environment(this_object())) > 240){ + if(environment(this_object())) + environment(this_object())->eventPrint(keepalive); + //Do not use the below line unless you understand + //the security hazard it poses + //environment(this_object())->eventForce(keepalive); + } + } + } +} diff --git a/lib/secure/obj/portal_blue.c b/lib/secure/obj/portal_blue.c new file mode 100644 index 0000000..348b027 --- /dev/null +++ b/lib/secure/obj/portal_blue.c @@ -0,0 +1,174 @@ +#include +#include +#include ROOMS_H + +inherit LIB_STORAGE; + +string DescribeItems(mixed var); +string DescribeLiving(mixed var); +void RegisterPortal(); + +object dest; + +mixed direct_enter_obj(){ + return 1; +} + +mixed direct_enter_into_obj(){ + return direct_enter_obj(); +} + +void create() { + object tmp; + ::create(); + tmp = PORTAL_D->GetOrangePortal(); + if(tmp) dest = tmp; + else catch( dest = load_object(ROOM_START) ); + SetKeyName("portal"); + SetAdjectives( ({"strangely","glowing","pulsating","blue"}) ); + SetId( ({ "aperture" }) ); + SetShort("a glowing blue portal"); + SetLong("A strangely glowing and pulsating portal."); + SetMass(0); + SetBaseCost("silver",1); + SetMaxCarry(0); + SetPreventGet("You fail."); + SetNoClean(1); + SetNoCondition(1); + call_out( (: RegisterPortal :), 0); +} + +void RegisterPortal(){ + object env = room_environment(this_object()); + eventMove(env); + dest = PORTAL_D->GetOrangePortal(); + PORTAL_D->RegisterPortal(env); +} + +int eventEnter(object who){ + object tmp = PORTAL_D->GetOrangePortal(); + mixed pg; + if(tmp) dest = tmp; + if(dest == environment(who)){ + dest = 0; + pg = filter(deep_inventory(who), + (: base_name($1) == "/domains/default/obj/generator" :) ); + if(sizeof(pg)) pg = pg[0]; + if(pg && objectp(pg)) pg->eventMove(environment(who)); + while(!dest){ + string room = random(1000)+","+random(1000)+","+random(1000); + catch(dest = load_object("/domains/town/virtual/space/"+room)); + } + } + if(dest){ + who->eventMoveLiving(dest); + } + else { + write("You are unable to enter it."); + } + return 1; +} + +mixed eventDescribeEndpoint() { + int i; + string file, str; + object env, *livings, *items; + + dest = PORTAL_D->GetOrangePortal(); + str = "in the portal"; + env = dest; + if(dest) file = base_name(dest)+".c"; + + if(!env || env->GetProperty("no peer")){ + return "You can't see anything in there."; + } + if( (i = this_player()->GetEffectiveVision(file,1)) > 5 ) + return "It is too bright in there."; + else if( i < 3 ) + return "It is too dark there."; + + items = filter(all_inventory(env), + (: !$1->GetInvis(this_player()) :) ); + items = items - (livings = filter(items, (: living :))); + message("my_action", "%^GREEN%^" + "Looking "+str+" you see...", + this_player() ); + message("other_action", + this_player()->GetCapName()+" looks "+str+".", + environment(this_player()), this_player() ); + message("room_description", + ("\n"+env->GetLong(0)+"\n" || "\nA void.\n"), + this_player() ); + if( sizeof(items) ) + message("room_inventory", + "%^MAGENTA%^" + DescribeItems(items) + "%^RESET%^\n", + this_player() ); + if( sizeof(livings) ) + message("room_inventory", + "%^BOLD%^%^RED%^" + DescribeLiving(livings) + "%^RESET%^", + this_player() ); + return 1; +} + +string DescribeItems(mixed var) { + mapping m = ([ ]); + string *shorts, ret; + int i, max; + + if( !arrayp(var) ) return ""; + i = sizeof( shorts = map(var, (: $1->GetShort() :)) ); + while(i--) { + if( !sizeof(shorts[i]) ) continue; + if( m[ shorts[i] ] ) m[ shorts[i] ]++; + else m[ shorts[i] ] = 1; + } + i = max = sizeof( shorts = keys(m) ); + ret = ""; + for(i=0; i1 || m[ shorts[i] ] > 1 ) ret += " are here."; + else ret += " is here."; + } + else if( i == (max - 2) ) ret += ", and "; + else ret += ", "; + } + return capitalize(ret); +} + +string DescribeLiving(mixed var) { + mapping m = ([ ]); + string *shorts, ret; + int i; + if( !arrayp(var) ) return ""; + i = sizeof( shorts = map(var, (: $1->GetShort() :)) ); + while(i--) { + if( !sizeof(shorts[i]) ) continue; + if( m[ shorts[i] ] ) m[ shorts[i] ]++; + else m[ shorts[i] ] = 1; + } + ret = ""; + i = sizeof( shorts = keys(m) ); + while(i--) if( m[ shorts[i] ] > 1 ) + ret += (consolidate(m[shorts[i]], shorts[i]) + "\n"); + else ret += (shorts[i] + "\n"); + return ret; +} + +varargs mixed eventShowInterior(object who, object target){ + eventDescribeEndpoint(); + return 1; +} + +mixed eventFall(){ + return 0; +} + +mixed eventSink(){ + return 0; +} + +void init(){ + ::init(); +} diff --git a/lib/secure/obj/portal_orange.c b/lib/secure/obj/portal_orange.c new file mode 100644 index 0000000..b1d9e51 --- /dev/null +++ b/lib/secure/obj/portal_orange.c @@ -0,0 +1,175 @@ +#include +#include +#include ROOMS_H + +inherit LIB_STORAGE; + +string DescribeItems(mixed var); +string DescribeLiving(mixed var); +void RegisterPortal(); + +object dest; + +mixed direct_enter_obj(){ + return 1; +} + +mixed direct_enter_into_obj(){ + return direct_enter_obj(); +} + +void create() { + object tmp; + ::create(); + tmp = PORTAL_D->GetBluePortal(); + if(tmp) dest = tmp; + else catch( dest = load_object(ROOM_START) ); + SetKeyName("portal"); + SetAdjectives( ({"strangely","glowing","pulsating","orange"}) ); + SetId( ({ "aperture" }) ); + SetShort("a glowing orange portal"); + SetLong("A strangely glowing and pulsating portal."); + SetMass(0); + SetBaseCost("silver",1); + SetMaxCarry(0); + SetPreventGet("You fail."); + SetNoClean(1); + SetNoCondition(1); + call_out( (: RegisterPortal :), 0); +} + +void RegisterPortal(){ + object env = room_environment(this_object()); + eventMove(env); + dest = PORTAL_D->GetBluePortal(); + PORTAL_D->RegisterPortal(env); +} + + +int eventEnter(object who){ + object tmp = PORTAL_D->GetBluePortal(); + mixed pg; + if(tmp) dest = tmp; + if(dest == environment(who)){ + dest = 0; + pg = filter(deep_inventory(who), + (: base_name($1) == "/domains/default/obj/generator" :) ); + if(sizeof(pg)) pg = pg[0]; + if(pg && objectp(pg)) pg->eventMove(environment(who)); + while(!dest){ + string room = random(1000)+","+random(1000)+","+random(1000); + catch(dest = load_object("/domains/town/virtual/space/"+room)); + } + } + if(dest){ + who->eventMoveLiving(dest); + } + else { + write("You are unable to enter it."); + } + return 1; +} + +mixed eventDescribeEndpoint() { + int i; + string file, str; + object env, *livings, *items; + dest = PORTAL_D->GetBluePortal(); + + str = "in the portal"; + env = dest; + if(dest) file = base_name(dest)+".c"; + + if(!env || env->GetProperty("no peer")){ + return "You can't see anything in there."; + } + if( (i = this_player()->GetEffectiveVision(file,1)) > 5 ) + return "It is too bright in there."; + else if( i < 3 ) + return "It is too dark there."; + + items = filter(all_inventory(env), + (: !$1->GetInvis(this_player()) :) ); + items = items - (livings = filter(items, (: living :))); + message("my_action", "%^GREEN%^" + "Looking "+str+" you see...", + this_player() ); + message("other_action", + this_player()->GetCapName()+" looks "+str+".", + environment(this_player()), this_player() ); + message("room_description", + ("\n"+env->GetLong(0)+"\n" || "\nA void.\n"), + this_player() ); + if( sizeof(items) ) + message("room_inventory", + "%^MAGENTA%^" + DescribeItems(items) + "%^RESET%^\n", + this_player() ); + if( sizeof(livings) ) + message("room_inventory", + "%^BOLD%^%^RED%^" + DescribeLiving(livings) + "%^RESET%^", + this_player() ); + return 1; +} + +string DescribeItems(mixed var) { + mapping m = ([ ]); + string *shorts, ret; + int i, max; + + if( !arrayp(var) ) return ""; + i = sizeof( shorts = map(var, (: $1->GetShort() :)) ); + while(i--) { + if( !sizeof(shorts[i]) ) continue; + if( m[ shorts[i] ] ) m[ shorts[i] ]++; + else m[ shorts[i] ] = 1; + } + i = max = sizeof( shorts = keys(m) ); + ret = ""; + for(i=0; i1 || m[ shorts[i] ] > 1 ) ret += " are here."; + else ret += " is here."; + } + else if( i == (max - 2) ) ret += ", and "; + else ret += ", "; + } + return capitalize(ret); +} + +string DescribeLiving(mixed var) { + mapping m = ([ ]); + string *shorts, ret; + int i; + if( !arrayp(var) ) return ""; + i = sizeof( shorts = map(var, (: $1->GetShort() :)) ); + while(i--) { + if( !sizeof(shorts[i]) ) continue; + if( m[ shorts[i] ] ) m[ shorts[i] ]++; + else m[ shorts[i] ] = 1; + } + ret = ""; + i = sizeof( shorts = keys(m) ); + while(i--) if( m[ shorts[i] ] > 1 ) + ret += (consolidate(m[shorts[i]], shorts[i]) + "\n"); + else ret += (shorts[i] + "\n"); + return ret; +} + +varargs mixed eventShowInterior(object who, object target){ + eventDescribeEndpoint(); + return 1; +} + +mixed eventFall(){ + return 0; +} + +mixed eventSink(){ + return 0; +} + +void init(){ + ::init(); +} diff --git a/lib/secure/obj/post.c b/lib/secure/obj/post.c new file mode 100644 index 0000000..fa64634 --- /dev/null +++ b/lib/secure/obj/post.c @@ -0,0 +1,1495 @@ +/* /lib/obj/post.c + * from Foundation II + * the user front end to the IIPS version 3.1 + * created by Descartes of Borg 940509 + */ + +#include +#include +#include +#include "include/post.h" + +inherit LIB_ITEM; + +static private int __Screen, __Lines, __NumLetters; +static private int __Begin,__Current,__CommandLine,__FromMenu,__IncomingFlag; +static private string __Folder, __Owner, __CurrentMenu; +static private mapping __Options, __TmpPost, __ChangedOptions; +static private int *__Delete; +static private string *__FwdRply; +static private mapping *__BoxInfo, *__PostalOptions; + +void create() { + item::create(); + SetKeyName("post box"); + SetId( ({ "post box", "box", POSTAL_ID }) ); + SetAdjectives( ({ "post", "a", "imaginary" }) ); + SetShort("a post box"); + SetLong("A post box."); + SetProperty("no steal", 1); + SetInvis(1); + SetMass(0); + SetValue(0); + SetPreventGet( (: Destruct :) ); + SetPreventDrop( (: Destruct :) ); + SetPreventPut( (: Destruct :) ); + __PostalOptions = ({ + ([ "key":"askcc", "value":({"N","Y"}), "desc":"Prompt for cc when " + "sending mail:" ]), + (["key":"quit", "value":({"N","Y"}), "desc":"Confirm quit from mail:"]), + (["key":"metoo", "value":({"N","Y"}),"desc":"Send mail to yourself " + "with you in alias:"]), + (["key":"delete", "value":({"N","Y"}), "desc":"Confirm deletion of " + "letters:" ]), + (["key":"notify", "value":({"N","Y"}), "desc":"Notify me when new mail " + "is received:" ]), + ([ "key":"message", "value":"New mail has arrived from $N\n" + "Subject: $S", "desc":"Mail message when notify occurs:" ]), + ([ "key": "content", "value":({"message only", "header and message"}), + "desc":"Content of letters when reading mail:" ]), + ([ "key":"forward", "value":"none", "desc":"Address to forward " + "incoming mail to:" ]), + ([ "key":"sig file", "value":"none", "desc":"Signature file:" ]), + ([ "key":"commands", "value":({"N","Y"}), "desc":"Exclude command " + "listing from menus:" ]), + ([ "key":"read", "value":({"N","Y"}), "desc":"Read letter when you make " + "it current:" ]) + }); +} + +string tmpmail(){ + mixed tmpmaildir = homedir(this_player()); + if(!tmpmaildir || !directory_exists(tmpmaildir)) return "/tmp/"+this_player()->GetKeyName(); + else return tmpmaildir+"/tmp/mail.tmp"; +} + +void init() { + item::init(); + if(this_player() != environment(this_object())) { + this_object()->eventDestruct(); + return; + } + __Options = OPTIONS_D->query_options(__Owner = + this_player()->GetKeyName()); + if(!(__Lines = to_int(this_player()->GetEnvVar("LINES")))) + __Lines = 24; + if(!(__Screen = to_int(this_player()->GetEnvVar("SCREEN")))) + __Screen = 80; + if((__NumLetters = __Lines - 10) < 0) __NumLetters = 5; +} + +static private void restore_box(string folder) { + int x; + + if(!pointerp(__BoxInfo=FOLDERS_D->query_box_info(__Owner, folder))) + __BoxInfo = ({}); + __Folder = folder; + __TmpPost = ([]); + __Delete = allocate(x = sizeof(__BoxInfo)); + if(!x) __Current = -1; + else __Current = 0; + __Begin = 0; +} + +static private void save_box() { + FOLDERS_D->delete_posts(__Owner, __Folder, __Delete); +} + +static private void destruct_box(string str) { + message("mail", str, this_player()); + this_object()->eventDestruct(); +} + +static private int valid_folder(string str) { + int i; + + if(str == "" || !str) return 0; + if(str[0] != '=' && str != "new") return 0; + i = strlen(str = lower_case(str)); + while(i-- > 1) if(str[i] < 'a' || str[i] > 'z') return 0; + return 1; +} + +static private int set_current(mixed val) { + int i; + + if(intp(val)) __Current = val; + else { + i = sizeof(__BoxInfo); + while(i--) { + if(__BoxInfo[i]["id"] == val) { + __Current = i; + break; + } + } + } + if(__Current < __Begin) __Begin = __Current; + else if(__Current >= __Begin+10) __Begin = __Current-9; + return __Current; +} + +void start_post(string str) { + string *args; + int i, maxi;; + + if(str && str != "") { + maxi = sizeof(args = explode(str, ",")); + if(args[0][0] == '-' && strlen(args[0]) == 2) { + switch(args[0][1]) { + case 'r': + restore_box("new"); + index_cmd(""); + return; + case 'f': + if(maxi < 2) { + message("mail", "No folder named.", this_player()); + this_object()->eventDestruct(); + return; + } + else if(maxi>2 || (!valid_folder(args[1]) && + args[1] != "new")) { + message("mail", "Illegal folder name.", this_player()); + this_object()->eventDestruct(); + return; + } + else { + restore_box(args[1]); + indices(0); + return; + } + case 'a': + __CommandLine = 1; + if(maxi < 2) index_cmd("a"); + else index_cmd(implode(args[1..maxi-1], " ")); + return; + } + } + __CommandLine = 1; + __TmpPost = ([]); + __FwdRply = 0; + send_letter(args); + return; + } + restore_box("new"); + indices(0); +} + +static private void primary_prompt() { + message("prompt", "\nCommand: \n", this_player()); +} + +static private void secondary_prompt() { + message("prompt", sprintf("\nCommand (%s for %s menu): \n", + __CurrentMenu[0..0], __CurrentMenu), + this_player()); +} + +varargs static private void postal_error(string str, string ind, mixed args) { + message("mail", sprintf("\n%%^RED%%^%s\n", str), this_player()); + primary_prompt(); + if(args) input_to(sprintf("%s_cmd", (ind ? ind : __CurrentMenu)), args); + else input_to(sprintf("%s_cmd", (ind ? ind : __CurrentMenu))); +} + +varargs static private void postal_success(string str,string ind,mixed args) { + message("mail", sprintf("\n%%^GREEN%%^%s\n", str), this_player()); + secondary_prompt(); + if(args) input_to(sprintf("%s_cmd", (ind ? ind : __CurrentMenu)), args); + else input_to(sprintf("%s_cmd", (ind ? ind : __CurrentMenu))); +} + +varargs static void indices(int x, string str) { + int i, maxi; + + __CurrentMenu = "index"; + if(str && str != "") { + index_cmd(str); + return; + } + __Begin = x; + __FromMenu = 1; + message("mail", "\n%^INITTERM%^Imaginary Intermud Postal Service " + "(IIPS) 3.1 Descartes of Borg 1993, 1994", this_player()); + message("mail", sprintf("\n%%^CYAN%%^%s", center(sprintf("Folder is %s " + "with %s.\n",__Folder,consolidate(maxi=sizeof(__BoxInfo),"one letter\n")), + __Screen)), this_player()); + if(!maxi) __Current = -1; + else for(i=x; i 99) ? (""+(i+1)) : ((i+1 > 9) ? (" "+(i+1)) : (" "+(i+1)))), + (__BoxInfo[i]["read"] ? " " : "N"), + (__Delete[i] ? "D" : " "), + arrange_string(capitalize(__BoxInfo[i]["from"]), 30), + arrange_string(postal_time(__BoxInfo[i]["date"]), 7), + arrange_string(__BoxInfo[i]["subject"], __Screen-40)), this_player()); + index_menu(); +} + +varargs static void aliases(string str) { + __CurrentMenu = "alias"; + if(str && str != "") { + alias_cmd(str); + return; + } + message("mail", "\n%^INITTERM%^Imaginary Intermud Postal Service " + "(IIPS) 3.1 Descartes of Borg 1993, 1994", this_player()); + message("mail", sprintf("\n%%^CYAN%%^%s", center(sprintf("%s and " + "Personal Alias Menu", mud_name()))), this_player()); + message("mail", sprintf("\n%s\n", + format_page(keys(OPTIONS_D->query_groups(__Owner) + + LOCALPOST_D->query_mud_groups()),__Screen/20)),this_player()); + alias_menu(); +} + +varargs static void options(string str) { + string tmp; + int i, maxi; + + __CurrentMenu = "option"; + if(str && str != "") { + option_cmd(str); + return; + } + message("mail", "\n%^INITTERM%^Imaginary Intermud Postal Service " + "(IIPS) 3.1 Descartes of Borg 1993, 1994", this_player()); + message("mail", sprintf("\n%%^CYAN%%^%s", center("IIPS 3.1 Options Menu\n", + __Screen)), this_player()); + maxi = sizeof(__PostalOptions); + for(i=0; i9) ? (i+1)+"" :" "+(i+1), + __PostalOptions[i]["desc"], tmp), + this_player()); + } + option_menu(); +} + +static private void help(string arg, string ind) { + if(!ind) ind = __CurrentMenu; + if(arg && arg != "") { + help_cmd(arg, ind); + return; + } + message("mail", "\n%^INITTERM%^Imaginary Intermud Postal Service " + "(IIPS) 3.1 Descartes of Borg 1993, 1994", this_player()); + message("mail",sprintf("\n%%^CYAN%%^%s\n",center("IIPS 3.1 Help Menu", + __Screen)), this_player()); + help_menu(ind); +} + +static private void index_menu() { + if(__Options["commands"]) { + primary_prompt(); + input_to("index_cmd"); + return; + } + message("mail", "\n"+center("a)lias menu, c)hange folder, d)elete, " + "f)orward, h)elp, m)ail,", __Screen), this_player()); + message("mail", center("n)ext letter, o)ptions menu, p)revious " + "letter, q)uit, Q)uit without saving,", __Screen), this_player()); + message("mail", center("s)ave to folder, S)ave to file, " + "u)ndelete", __Screen), this_player()); + message("mail", center(" to read selected letter\n", __Screen), + this_player()); + primary_prompt(); + input_to("index_cmd"); +} + +static private void alias_menu() { + if(__Options["commands"]) { + primary_prompt(); + input_to("alias_cmd"); + return; + } + message("mail", center("d)elete from an alias, e)nter into an alias, " + "h)elp, i)ndex menu, ", __Screen), this_player()); + message("mail", center("l)ist an alias, m)ake an alias, o)ptions menu, " + "q)uit, Q)uit without saving, ", __Screen), this_player()); + message("mail", center("r)emove an alias\n", __Screen),this_player()); + primary_prompt(); + input_to("alias_cmd"); +} + +static private void option_menu() { + if(__Options["commands"]) { + primary_prompt(); + input_to("option_cmd"); + return; + } + message("mail", "\n"+center("Enter the number of an option to " + "change it.", __Screen), this_player()); + message("mail", center("a)lias menu, h)elp, i)ndex menu, " + "q)uit, Q)uit without saving,", __Screen), this_player()); + message("mail", center("s)ave option changes\n", __Screen), this_player()); + primary_prompt(); + input_to("option_cmd"); +} + +static private void help_menu(string ind) { + int i, maxi; + + message("help", "\n\n\tEnter one of the following to visit " + "another menu:", this_player()); + message("help", center("a)lias menu, i)ndex menu, o)ptions menu", + __Screen), this_player()); + message("help", "\n\tOr enter one of the following for detailed help:", + this_player()); + switch(ind) { + case "index": + message("help", center("c)hange folder, d)elete, f)orward, " + "m)ail letter, n)ext letter,", __Screen), this_player()); + message("help", center("p)revious letter, q)uit, " + "Q)uit without saving, r)eply,", __Screen), this_player()); + message("help", center("s)ave to folder, S)ave to file,", + __Screen), this_player()); + message("help", center("x) help from another menu, y) detailed " + "IIPS user manual\n", __Screen), this_player()); + break; + case "alias": + message("help", center("d)elete from an alias, e)nter into " + "an alias, m)ake an alias, q)uit,", __Screen), this_player()); + message("help", center("Q)uit without saving, r)emove " + "an alias,", __Screen), this_player()); + message("help", center("x) help from another menu, y) detailed " + "IIPS user manual\n", __Screen), this_player()); + break; + case "option": + for(i=0, maxi = sizeof(__PostalOptions); i= sizeof(__BoxInfo)) { + postal_error("No current letter set."); + return; + } + if(__FromMenu) read_letter(__Current); + else if(set_current(__Current+1) < sizeof(__BoxInfo)) + read_letter(__Current); + else read_letter(set_current(__Current - 1)); + return; + } + if(sscanf(str, "%d", x) && x) { + if(x>0 && x <= sizeof(__BoxInfo)) { + if(__Options["read"]) read_letter(set_current(x-1)); + else { + set_current(x-1); + indices(__Begin); + } + } + else postal_error("Invalid letter number."); + return; + } + if(!sizeof(tmp = explode(str, " "))) cmd = ""; + else cmd = tmp[0][0..0]; + if(sizeof(tmp) > 1) args = implode(tmp = tmp[1..sizeof(tmp)-1], " "); + else { + args = ""; + tmp = ({}); + } + switch(cmd) { + case "a": aliases(args); return; + case "c": change_folder(args); return; + case "d": case "u": delete_letter(cmd, args); return; + case "f": forward_letter(args, 0); return; + case "h": help(args, "index"); return; + case "i": + indices(__Current < __Begin+__NumLetters ? __Begin : + __Current-(__NumLetters-1), args); + return; + case "m": + __FwdRply = 0; + __TmpPost = ([]); + send_letter(tmp); + return; + case "n": index_cmd(""+(__Current+2)); return; + case "o": options(args); return; + case "p": index_cmd(""+(__Current)); return; + case "q": case "Q": quit_box(cmd); return; + case "r": reply(args); return; + case "s": case "S": save_letter(cmd, args); return; + default: + postal_error("Invalid postal command."); + return; + } +} + +static void alias_cmd(string str) { + string cmd, args; + string *tmp; + + __CurrentMenu = "alias"; + if(str == "" || !str) { + if(__CommandLine) destruct_box("Invalid alias command."); + else postal_error("Invalid alias command."); + return; + } + cmd = (tmp = explode(str, " "))[0][0..0]; + if(sizeof(tmp) > 1) args = implode(tmp[1..sizeof(tmp)-1], " "); + else args = ""; + switch(cmd) { + case "a": aliases(args); return; + case "d": case "e": alias_members(cmd, args); return; + case "m": case "r": alias_creation(cmd, args); return; + case "h": help(args, "alias"); return; + case "i": + indices(__Current < __Begin+__NumLetters ? __Begin : + __Current-(__NumLetters-1), args); + return; + case "l": list_alias(args); return; + case "o": options(args); return; + case "q": case "Q": quit_box(cmd); return; + case "s": aliases(args); return; + default: alias_cmd(0); return; + } +} + +static void option_cmd(string str) { + string cmd, args; + string *tmp; + int x; + + __CurrentMenu = "option"; + if(str == "" || !str) { + postal_error("Invalid option command."); + return; + } + if(sscanf(str, "%d", x) && x) { + change_option(x-1); + return; + } + cmd = (tmp = explode(str, " "))[0][0..0]; + if(sizeof(tmp) > 1) args = implode(tmp[1..sizeof(tmp)-1], " "); + else args = ""; + switch(cmd) { + case "a": aliases(args); return; + case "h": help(args, "option"); return; + case "i": + indices(__Current < __Begin+__NumLetters ? __Begin : + __Current-(__NumLetters-1), args); + return; + case "o": options(args); return; + case "q": case "Q": quit_box(cmd); return; + case "s": save_options(); return; + default: option_cmd(0); return; + } +} + +static void help_cmd(string str, string ind) { + string tmp, file; if(str == "" || !str) { + postal_error("Invalid help command.", "help", ind); + return; + } + switch(str = str[0..0]) { + case "a": aliases(""); return; + case "i": indices(__Begin); return; + case "o": options(""); return; + case "q": case "Q": file = "quitting"; break; + } + if(!(tmp = read_file(DIR_POSTAL_HELP+"/"+file))) tmp = "Not found.\n"; + this_player()->eventPage(explode(tmp, "\n"), "help", (: end_help :)); +} + +void end_help() { + secondary_prompt(); + input_to("help_cmd"); +} + +static private string postal_time(mixed val) { + string *parts; + string heure; + int x; + + if(stringp(val) && x = to_int(val)) heure = ctime(time()); + else if(stringp(val)) heure = val; + else heure = ctime(val); + parts = explode(replace_string(heure, " ", " "), " "); + return sprintf("%s %s", parts[2], parts[1]); +} + +static private string header(mapping borg) { + int x; + + return sprintf("%s from %%^GREEN%%^%s%%^RESET%%^\nTo: %s%s" + "Subject: %%^GREEN%%^%s", + (stringp(borg["date"]) ? ((x=to_int(borg["date"])) ? ctime(x) : + borg["date"]) : ctime(borg["date"])), capitalize(borg["from"]), + wrap(implode(borg["to"], ", "), __Screen), + (sizeof(borg["cc"]) ? sprintf("Cc: %s",wrap(implode(borg["cc"], ", "), + __Screen)) : ""), borg["subject"]); +} + +static void change_folder(string str) { + if(str == "" || !str) { + message("prompt", "Change to which folder? \n", this_player()); + input_to("get_folder"); + return; + } + if(!valid_folder(str)) { + __FromMenu = 1; + postal_error("Invalid folder name."); + return; + } + if(!__Options["delete"] || member_array(1, __Delete) == -1) + next_folder("", str); + else { + message("prompt", "Delete marked letters (default 'y')? \n", + this_player()); + input_to("next_folder", str); + } +} + +static void next_folder(string str, string folder) { + if(str == "" || !str) str = "y"; + else str = (lower_case(str)[0..0]); + if(str == "y") save_box(); + else if(str != "n") { + message("prompt", "Invalid command. Enter 'y' or 'n': \n",this_player()); + input_to("next_folder"); + } + restore_box(folder); + indices(__Begin); +} + +static void get_folder(string str) { + if(str == "" || !str) { + __FromMenu = 1; + postal_error("Invalid folder name."); + return; + } + change_folder(str); +} + +static private void delete_letter(string cmd, string args) { + int x, i, from, to, maxi; + + if(args == "" || !args) { + from = __Current; + to = __Current; + } + else { + sscanf(args, "%d-%d", from, to); + if(!to) to = from-1; + else to--; + from--; + } + if(from > to || from < 0 || to >= sizeof(__BoxInfo)) { + postal_error("Invalid letter range."); + return; + } + for(i= from; i < to+1; i++) { + if(cmd == "u" && !__Delete[i]) { + __FromMenu = 1; + postal_error(sprintf("Letter %d is not marked for deletion!",i+1)); + } + else if(cmd == "d" && __Delete[i]) + postal_error(sprintf("Letter %d is already marked for deletion!",i+1)); + else if(!__BoxInfo[i]["read"] && cmd == "d" && + !__Options["unread delete"]) { + message("mail", sprintf("\n%%^RED%%^Letter %d is still unread!", + i+1), this_player()); + message("prompt","Delete it anyways (default n): \n",this_player()); + input_to("unread_delete", ({ i+1, to+1 })); + return; + } + else __Delete[i] = (cmd == "u" ? 0 : 1); + } + if(cmd == "d" && (args == "" || !args)) { + for(i=__Current, maxi = sizeof(__BoxInfo); ieventDestruct(); + return; + } + if(!__Options["delete"]) { + save_box(); + message("mail", "\nExiting from IIPS.\n", this_player()); + this_object()->eventDestruct(); + return; + } + i = sizeof(__Delete); + while(i--) { + if(__Delete[i]) { + message("prompt", "Delete marked letters (default 'y')? \n", + this_player()); + input_to("confirm_delete"); + return; + } + } + message("mail", "\nExiting from IIPS.\n", + this_player()); + this_object()->eventDestruct(); +} + +static void confirm_quit(string str, string cmd) { + if(str == "" || !str) str = "n"; + else str = lower_case(str)[0..0]; + if(str == "y") { + really_quit(cmd); + return; + } + else if(str == "n") { + indices(__Current < __Begin+__NumLetters ? __Begin : + __Current - (__Lines-1)); + return; + } + message("prompt", "Answer 'y' or 'n': \n", this_player()); + input_to("confirm_quit", cmd); +} + +static void confirm_delete(string str) { + if(str == "" || !str) str = "y"; + else str = lower_case(str)[0..0]; + if(str == "y") { + save_box(); + message("mail", "\nExiting from IIPS.\n", this_player()); + this_object()->eventDestruct(); + return; + } + else if(str == "n") { + message("mail", "\nMarked letters will remain undeleted.\n" + "Exiting from IIPS.\n", this_player()); + this_object()->eventDestruct(); + return; + } + message("prompt", "Answer 'y' or 'n': \n", this_player()); + input_to("confirm_delete"); +} + +static private void save_letter(string cmd, string args) { + string *tmp; + string folder; + int letter, i, maxi; + + if(args && args != "") { + if(sizeof(tmp = explode(args, " ")) == 2) { + if(!sscanf(tmp[0], "%d", letter) || !letter) { + sscanf(tmp[1], "%d", letter); + folder = tmp[0]; + } + else folder = tmp[1]; + } + else if(!sscanf(args, "%d", letter) || !letter) folder = args; + else folder = args; + } + else { + folder = 0; + letter = 0; + } + if(!letter) letter = __Current; + else letter--; + if(!folder) { + if(cmd == "S") message("prompt","Save to which file? \n",this_player()); + else message("prompt", sprintf("Save to which folder (default %s)? \n", + sprintf("=%s", convert_name(__BoxInfo[letter]["from"]))), + this_player()); + input_to("get_save_location", ({ letter, cmd })); + return; + } + if(cmd == "s") { + if(!valid_folder(folder)) { + postal_error("Invalid folder name."); + return; + } + FOLDERS_D->add_post(__Owner, folder, __BoxInfo[letter]); + message("mail", "\nLetter saved.\n", this_player()); + set_current(letter); + __Delete[__Current] = 1; + } + else if(cmd == "S") { + folder = absolute_path(this_player()->get_path(), folder); + if(!creatorp(this_player()) || + !(master()->valid_write(folder, this_player()))) { + postal_error("Access denied."); + return; + } + write_file(folder, + LETTERS_D->query_letter(__BoxInfo[letter]["id"])); + message("mail", sprintf("Letter saved to %s.\n", folder), + this_player()); + set_current(letter); + __Delete[__Current] = 1; + } + if(!__FromMenu) + for(i=__Current, maxi = sizeof(__BoxInfo); iquery_letter(__BoxInfo[x]["id"])); + if(!__BoxInfo[x]["read"]) FOLDERS_D->mark_read(__Owner, __Folder, x); + __BoxInfo[x]["read"] = 1; + this_player()->eventPage(explode(tmp, "\n"), "mail", (: end_read :)); +} + +void end_read() { + __FromMenu = 0; + secondary_prompt(); + input_to("index_cmd"); +} + +static private void alias_members(string cmd, string args) { + string *members, *old_members; + string grp; + + if(args == "" || !args) { + message("prompt", sprintf("%s which alias? \n", + (cmd == "e" ? "Enter into" : "Delete from")), this_player()); + input_to("get_alias", cmd); + return; + } + if(sizeof(members = explode(args, " ")) == 1) { + message("prompt", sprintf("%s which members? \n", + (cmd == "e" ? "Enter" : "Delete")), this_player()); + input_to("get_members", ({ cmd, args })); + return; + } + if(!sizeof(members -= ({ grp = members[0] }))) { + if(__CommandLine) destruct_box("Invalid alias member."); + else postal_error("Invalid alias member."); + return; + } + if(user_exists(grp = lower_case(grp)) || + LOCALPOST_D->query_mud_group(grp)) { + if(__CommandLine) destruct_box("Invalid alias."); + else postal_error("Invalid alias."); + return; + } + if(!(old_members = OPTIONS_D->query_group(__Owner, grp))) { + if(__CommandLine) destruct_box("No such alias."); + else postal_error(sprintf("No such alias %s.", grp)); + return; + } + if(cmd == "e") members = distinct_array(members + old_members); + else if(!sizeof(members = old_members - members)) members = 0; + OPTIONS_D->set_group(__Owner, grp, members); + if(cmd == "d") { + if(!members) + message("mail", "\n%^GREEN%^All members deleted.\n", this_player()); + else message("mail", "\n%^GREEN%^Members deleted from alias.\n", + this_player()); + } + else message("mail", "\n%^GREEN%^Members entered into alias.\n", + this_player()); + if(__CommandLine) this_object()->eventDestruct(); + else { + secondary_prompt(); + input_to("alias_cmd"); + } +} + +static void get_alias(string str, string cmd) { + if(str == "" || !str) { + if(__CommandLine) destruct_box("Invalid alias name."); + else postal_error("Invalid alias name."); + return; + } + alias_members(cmd, str); +} + +static void get_members(string str, string *args) { + if(str == "" || !str) { + if(__CommandLine) destruct_box("Invalid alias members."); + else postal_error("Invalid alias members."); + return; + } + alias_members(args[0], sprintf("%s %s", args[1], str)); +} + +static private void alias_creation(string cmd, string args) { + string *members; + + if(args == "" || !args) { + message("prompt", sprintf("Name of alias to %s: \n", + (cmd == "m" ? "make" : "remove")), this_player()); + input_to("get_alias_name", cmd); + return; + } + if(cmd == "m" && sizeof(members=explode(args=lower_case(args)," ")) == 1) { + message("prompt", "Enter members for the alias: \n", this_player()); + input_to("get_new_alias_members", ({ cmd, args })); + return; + } + else if(cmd == "m") members = members - ({ args = members[0] }); + else members = 0; + if(cmd == "m" && (user_exists(args) || LOCALPOST_D->query_mud_group(args))) { + if(__CommandLine) destruct_box("Invalid alias name."); + else postal_error("Invalid alias name."); + return; + } + if(!(OPTIONS_D->query_group(__Owner, args))) { + if(cmd == "r") { + if(__CommandLine) destruct_box("No such alias to remove."); + else postal_error("No such alias to remove."); + return; + } + } + else if(cmd == "m") { + if(__CommandLine) destruct_box("Alias already exists."); + else postal_error("That alias already exists."); + return; + } + OPTIONS_D->set_group(__Owner, args, members); + if(__CommandLine) + destruct_box(sprintf("Alias %s.", (cmd == "m" ? "made" : "removed"))); + else + postal_success(sprintf("Alias %s.", (cmd == "m" ? "made" : "removed"))); +} + +static void get_alias_name(string str, string cmd) { + if(str == "" || !str) { + if(__CommandLine) destruct_box("Invalid alias name."); + else postal_error("Invalid alias name."); + return; + } + alias_creation(cmd, lower_case(str)); +} + +static void get_new_alias_members(string str, string *args) { + if(str == "" || !str) { + if(__CommandLine) destruct_box("Invalid alias members."); + else postal_error("Invalid alias members."); + return; + } + alias_creation(args[0], sprintf("%s %s", args[1], lower_case(str))); +} + +static private void list_alias(string str) { + string *who; + + if(str == "" || !str) { + if(__CommandLine) destruct_box("Invalid alias name."); + else postal_error("Invalid alias name."); + return; + } + if(!(who = LOCALPOST_D->query_mud_group(str=lower_case(str)))) { + who = OPTIONS_D->query_group(__Owner, str); + } + if(!who) { + if(__CommandLine) destruct_box("No such alias exists."); + else postal_error("No such alias exists."); + return; + } + message("mail", "\n%^INITTERM%^"+center(sprintf("Alias: %s", str), + __Screen), this_player()); + message("mail", "\n\n"+implode(who, ", "), this_player()); + if(__CommandLine) this_object()->eventDestruct(); + else { + secondary_prompt(); + input_to("alias_cmd"); + } +} + +static private void save_options() { + string *cles; + int i; + + if(!__ChangedOptions) { + postal_error("No options have changed."); + return; + } + i = sizeof(cles = keys(__ChangedOptions)); + while(i--) + OPTIONS_D->set_option(__Owner, cles[i], __ChangedOptions[cles[i]]); + __Options = OPTIONS_D->query_options(__Owner); + postal_success("New options now saved."); +} + +static private void change_option(int x) { + if(pointerp(__PostalOptions[x]["value"])) { + message("mail", sprintf("%s\n\t0) %s\n\t1) %s\n", + __PostalOptions[x]["desc"], + __PostalOptions[x]["value"][0], __PostalOptions[x]["value"][1]), + this_player()); + } + else message("mail", __PostalOptions[x]["desc"], this_player()); + message("prompt", "Enter in a proper value: \n", this_player()); + input_to("really_change_option", 0, x); +} + +static void really_change_option(string str, int x) { + int y; + + if(!__ChangedOptions) __ChangedOptions = ([]); + if(pointerp(__PostalOptions[x]["value"])) { + if((y=to_int(str)) != 0 && y != 1) { + postal_error("Invalid value. No option has changed."); + return; + } + __ChangedOptions[__PostalOptions[x]["key"]] = y; + } + else __ChangedOptions[__PostalOptions[x]["key"]] = (str == "" ? 0 : str); + postal_success("You must remember to save for this option to take effect."); +} + +static private void reply(string str) { + int x, i; + + if(str == "" || !str) x = __Current; + else x = to_int(str)-1; + if(x < 0 || x >= sizeof(__BoxInfo)) { + postal_error("Invalid letter number for reply."); + return; + } + set_current(x); + __TmpPost = ([ "date":time(), "from": this_player()->GetKeyName()]); + if((__TmpPost["subject"] = __BoxInfo[x]["subject"])[0..2] != "Re:") + __TmpPost["subject"] = sprintf("Re: %s", __TmpPost["subject"]); + message("prompt", "Include original text (default 'n'): \n", this_player()); + input_to("get_reply_confirm"); +} + +static void get_reply_confirm(string str) { + if(str == "" || !str) str = "n"; + else str = lower_case(str)[0..0]; + if(str == "y") __FwdRply = ({ "r", query_reply_text() }); + else if(str != "n") { + message("prompt", "Answer 'y' or 'n': \n", this_player()); + input_to("get_reply_confirm"); + return; + } + else __FwdRply = 0; + message("mail", sprintf("\n%s", center("Reply to: a)ll, c)c list and " + "sender, s)ender only, t)o list and sender",__Screen)), this_player()); + message("prompt", "\nEnter choice (default 's'): \n", this_player()); + input_to("get_reply_list"); +} + +static void get_reply_list(string str) { + int i; + + if(str == "" || !str) str = "s"; + else str = lower_case(str)[0..0]; + __TmpPost["to"] = ({ convert_name(__BoxInfo[__Current]["from"]) }); + switch(str) { + case "a": + __TmpPost["to"] += __BoxInfo[__Current]["to"]; + __TmpPost["cc"] = __BoxInfo[__Current]["cc"]; + break; + case "c": __TmpPost["cc"] = __BoxInfo[i]["cc"]; break; + case "s": __TmpPost["cc"] = ({}); break; + case "t": + __TmpPost["to"] += __BoxInfo[__Current]["to"]; + __TmpPost["cc"] = ({}); + break; + default: + message("prompt","Invalid choice. Choose again: \n", this_player()); + input_to("get_reply_list"); + return; + } + if(!__Options["askcc"]) get_cc(""); + else { + message("prompt", "Copies to: \n", this_player()); + input_to("get_cc"); + } +} + +static private string query_reply_text() { + string tmp; + + tmp = LETTERS_D->query_letter(__BoxInfo[__Current]["id"]); + return sprintf("\n>%s\n", replace_string(tmp, "\n", "\n>")); +} + +static private void forward_letter(string str, int flag) { + string *args; + int i, x; + + if(str == "" || !str) { + message("prompt", "To: \n", this_player()); + input_to("get_forward_list"); + return; + } + i = sizeof(args = explode(lower_case(str), " ")); + if(!flag) { + while(i--) if(sscanf(args[i], "%d", x) && x) break; + if(!x) x = __Current; + else { + x--; + if( !i ) { + if(sizeof(args) == 1) args = ({}); + else args = args[1..]; + } + else if( i == sizeof(args)) { + args = args[0..<2]; + } + else if(sizeof(args) == 1) + args = ({}); + else args = args[0..(i-1)] + args[(i+1)..]; + } + if(x < 0 || x > sizeof(__BoxInfo)) { + postal_error("Letter number is out of range."); + return; + } + if(!sizeof(args)) { + forward_letter(0, 1); + return; + } + } + set_current(x); + __TmpPost["to"] = args; + if((__TmpPost["subject"]=__BoxInfo[__Current]["subject"])[0..4] != + "(fwd)") __TmpPost["subject"] = sprintf("(fwd) %s",__TmpPost["subject"]); + __TmpPost["from"] = this_player()->GetKeyName(); + __TmpPost["date"] = time(); + message("prompt", "Comment on original letter (default 'n')? \n", + this_player()); + input_to("confirm_comments"); +} + +static void get_forward_list(string str) { + if(str == "" || !str) { + message("prompt","Invalid recipients. Abort forward (default 'y')? \n", + this_player()); + input_to("confirm_forward_abort"); + return; + } + else forward_letter(str, 1); +} + +static void confirm_comments(string str) { + if(str == "" || !str) str = "n"; + else str = lower_case(str)[0..0]; + if(str == "y") __FwdRply = ({ "f", query_forward_text() }); + else if(str == "n") { + __FwdRply = 0; + __TmpPost["message"] = query_forward_text(); + } + else { + message("prompt", "Answer 'y' or 'n': \n", this_player()); + input_to("confirm_comments"); + return; + } + if(!__Options["askcc"]) get_cc(""); + else { + message("prompt", "Copies to: \n", this_player()); + input_to("get_cc"); + } +} + +static private string query_forward_text() { + string tmp; + + tmp = LETTERS_D->query_letter(__BoxInfo[__Current]["id"]); + tmp = ">"+replace_string(tmp, "\n", "\n>"); + return sprintf("Original letter sent by %s %s:\n%s\n%s\n", + capitalize(__BoxInfo[__Current]["from"]), + postal_time(__BoxInfo[__Current]["date"]), + center("--- --- Begin Forwarded Text --- ---"), tmp); +} + +static void confirm_forward_abort(string str) { + if(str == "" || !str) str = "y"; + else str = lower_case(str)[0..0]; + if(str == "y") { + postal_error("Forward aborted."); + return; + } + else if(str != "n") { + message("prompt", "Answer 'y' or 'n': \n", this_player()); + input_to("confirm_forward_abort"); + return; + } + message("prompt", "To: \n", this_player()); + input_to("get_forward_list"); +} + +static private void send_letter(string *args) { + string flag, tmp; + int j, i, maxi, x; + + if(!args || !sizeof(args)) { + message("prompt", "To: \n", this_player()); + input_to("get_to"); + return; + } + __FwdRply = 0; + __TmpPost = ([ "from": this_player()->GetKeyName(),"date":time()]); + for(i=0, maxi = sizeof(args); i 1) { + if(member_array(args[i][1..1], ({"c","s","i"})) == -1) + continue; + else flag = args[i][1..1]; + } + else if(!flag && args[i][0] == '\\' && strlen(args[i]) > 1) + args[i] = args[i][1..strlen(args[1])-1]; + else if(flag) { + if(args[i][0] != '\'') tmp = args[i]; + else if(args[i][x=strlen(args[i])-1] =='\'') tmp =args[i][1..x-1]; + else { + tmp = args[j=i][1..x]; + while(++j < maxi && args[j][x=strlen(args[j])-1] != '\'') + if(x > 0) tmp += " "+args[j][0..x-1]; + if(args[j][x] == '\'' && x > 1) tmp += " "+args[j][0..x-1]; + i = j; + } + switch(flag) { + case "c": + if(!__TmpPost["cc"]) __TmpPost["cc"] = ({}); + __TmpPost["cc"] += ({ convert_name(tmp) }); + break; + case "s": __TmpPost["subject"] = tmp; break; + case "i": + tmp=absolute_path(this_player()->get_path(),tmp); + if(sscanf(tmp,user_path(this_player())+"%s", flag) != 1 || + !(master()->valid_read(tmp,this_player()))) { + if(__CommandLine) { + this_object()->eventDestruct(); + return; + } + __TmpPost = ([]); + postal_error("Access denied."); + return; + } + if(!file_exists(tmp)) { + if(__CommandLine) { + this_object()->eventDestruct(); + return; + } + __TmpPost = ([]); + postal_error(sprintf("File %s does not exist.",tmp)); + return; + } + if(!(__TmpPost["message"] = read_file(tmp))) + __TmpPost["message"] = "EMPTY FILE"; + break; + } + flag = 0; + } + else { + if(!grepp(args[i],"@")){ + if(!__TmpPost["to"]) __TmpPost["to"] = ({ trim(convert_name(args[i])) }); + else __TmpPost["to"] += ({ trim(convert_name(args[i])) }); + } + else { + if(!__TmpPost["to"]) __TmpPost["to"] = ({ trim(args[i]) }); + else __TmpPost["to"] += ({ trim(args[i]) }); + } + } + } + if(!__TmpPost["to"]) { + message("prompt", "To: \n", this_player()); + input_to("get_to"); + return; + } + if(!__TmpPost["subject"]) { + message("prompt", "Subject:\n ", this_player()); + input_to("get_subject"); + return; + } + else message("mail", sprintf("Subject: %s", __TmpPost["subject"]), + this_player()); + if(!__TmpPost["cc"] && __Options["askcc"]) { + message("prompt", "Copies to: \n", this_player()); + input_to("get_cc"); + return; + } + else if(!__TmpPost["cc"]) __TmpPost["cc"] = ({}); + if(!__TmpPost["message"]) get_cc(""); + else { + __TmpPost["message"] = sprintf("%s%s", __TmpPost["message"], + query_signature()); + confirm_send(); + } +} + +static void get_to(string str) { + if(str == "" || !str) { + if(__CommandLine) { + this_object()->eventDestruct(); + return; + } + postal_error("No recipients given. Mail aborted."); + return; + } + send_letter(explode(str, ",")); +} + +static void get_subject(string str) { + string tmp; + + if(str == "" || !str) { + message("prompt", "No subject given. Continue (default 'n')? \n", + this_player()); + input_to("confirm_subject"); + return; + } + __TmpPost["subject"] = str; + if(!__TmpPost["cc"] && __Options["askcc"]) { + message("prompt", "Copies to: \n", this_player()); + input_to("get_cc"); + return; + } + else if(!__TmpPost["cc"]) __TmpPost["cc"] = ({}); + if(!__TmpPost["message"]) get_cc(""); + else { + __TmpPost["message"] = sprintf("%s%s", __TmpPost["message"], + query_signature()); + confirm_send(); + } +} + +static void confirm_subject(string str) { + if(str == "" || !str) str = "n"; + else str = lower_case(str)[0..0]; + if(str == "n") { + if(__CommandLine) { + this_object()->eventDestruct(); + return; + } + __TmpPost = ([]); + postal_error("Mail aborted."); + return; + } + else if(str == "y") get_subject("[No Subject]"); + else { + message("prompt", "Answer 'y' or 'n': \n", this_player()); + input_to("confirm_subject"); + return; + } +} + +static void get_cc(string str) { + string tmp; + + if(!__TmpPost["cc"]) __TmpPost["cc"] = ({}); + if(str && str != "") __TmpPost["cc"] += explode(str, ","); + if(__TmpPost["message"]) { + __TmpPost["message"] = sprintf("%s%s", __TmpPost["message"], + query_signature()); + confirm_send(); + return; + } + if(file_exists(tmp = tmpmail())) + rm(tmp); + if(!__FwdRply || __FwdRply[0] == "f") { + message("mail",sprintf("\n%%^INITTERM%%^%s", header(__TmpPost)), + this_player()); + this_player()->eventEdit(tmp, (: complete_send :)); + return; + } + write_file(tmp, __FwdRply[1]); + message("mail", sprintf("\n%%^INITTERM%%^%s", header(__TmpPost)), + this_player()); + this_player()->eventEdit(tmp, (: complete_send :)); +} + +void complete_send() { + string str; + + if( !(str = read_file(tmpmail()))) + str = "No message."; + if(__FwdRply && __FwdRply[0] == "f") + str = sprintf("%s\n%s\n%s", str, __FwdRply[1], query_signature()); + else str = sprintf("%s%s", str, query_signature()); + __TmpPost["message"] = str; + __FwdRply = 0; + confirm_send(); +} + +static private string query_signature() { + string tmp; + + if(!__Options["sig file"]) return ""; + if(strsrch(__Options["sig file"], " ") != -1) + return sprintf("\n%s", __Options["sig file"]); + tmp = absolute_path(homedir(this_player()), + __Options["sig file"]); + if(!(master()->valid_read(tmp, this_player())) || !file_exists(tmp)) { + return sprintf("\n%s", __Options["sig file"]); + } + return read_file(tmp); +} + +static private void confirm_send() { + message("mail", center("e)dit, f)orget, s)end", __Screen), this_player()); + message("prompt", "\nCommand (default 's'): \n", this_player()); + input_to("handle_send_choice"); +} + +static void handle_send_choice(string str) { + string tmp = tmpmail(); + + if(str == "" || !str) str = "s"; + else str = lower_case(str)[0..0]; + switch(str) { + case "s": + notify_send(LOCALPOST_D->send_post(copy(__TmpPost))); + break; + case "f": + __TmpPost = ([]); + postal_error("Mail aborted!"); + break; + case "e": + if(file_exists(tmp)) rm(tmp); + write_file(tmp, __TmpPost["message"]); + map_delete(__TmpPost, "message"); + this_player()->eventEdit(tmp, (: complete_send :)); + break; + default: + message("prompt", "Invalid command. Command: \n", this_player()); + input_to("handle_send_choice"); + break; + } +} + +static private void notify_send(string *failures) { + string *arr; + string tmp; + + if(!sizeof(failures)) + message("mail", "\n\t%^GREEN%^Mail successfully sent!", this_player()); + else { + message("mail", sprintf("\nFailed to send to: %s", + implode(failures, ", ")), this_player()); + if(creatorp(this_player())) { + write_file(tmp=homedir()+"/tmp/dead.letter", + __TmpPost["message"]); + } + else write_file(tmp = sprintf("%s/%s.letter", homedir()+"/tmp", + this_player()->GetKeyName()), __TmpPost["message"]); + message("mail", sprintf("A copy of the letter was saved to %s", tmp), + this_player()); + } + if(sizeof(arr=distinct_array(__TmpPost["to"]+__TmpPost["cc"])-failures)) + message("mail", sprintf("Mail sent to: %s", implode(arr,", ")), + this_player()); + if(__CommandLine) { + this_object()->eventDestruct(); + return; + } + secondary_prompt(); + input_to("index_cmd"); +} + +void incoming_post() { + mixed tmp; + string id; + int *delete; + + if(__Folder != "new") return; + if(file_name(previous_object()) != FOLDERS_D) return; + id = (__Current < 0 ? 0 : __BoxInfo[__Current]["id"]); + delete =map_array(tmp=FOLDERS_D->query_box_info(__Owner,"new"), + "order_box", this_object()); + __BoxInfo = copy(tmp); + set_current(id); + __Delete = copy(delete); + __IncomingFlag = 1; +} + +int order_box(mapping borg) { + int i; + + i = sizeof(__BoxInfo); + while(i--) if(__BoxInfo[i]["id"] == borg["id"]) return __Delete[i]; + return 0; +} diff --git a/lib/secure/obj/replacer.c b/lib/secure/obj/replacer.c new file mode 100644 index 0000000..a1a2750 --- /dev/null +++ b/lib/secure/obj/replacer.c @@ -0,0 +1,191 @@ +// string replacer, by Cratylus. +// Use this carelessly at your own peril. + +#include +#include +inherit LIB_ITEM; +inherit LIB_TURN; + +string a1,a2,a3,line; +int n, active; + +static private void validate() { + if(!this_player()) return 0; + if( !(master()->valid_apply(({ "SECURE" }))) || !securep(this_player())) + error("Illegal attempt to use replacer: "+get_stack()+" "+identify(previous_object(-1))); +} + +void create(){ + ::create(); + SetKeyName("string replacer"); + SetId(({"replacer","thing","gadget","string replacer","device"})); + SetShort("a string replacer"); + SetLong("This is the most dangerous device on the mud.\n"+ + "It allows you to replace strings in files.\n"+ + "To use it, you must first \"turn on replacer\"\n"+ + "Then you have two options:\n"+ + "To replace a word in one file: replace \n"+ + "To replace a word in EVERY FILE IN YOUR CURRENT WORKING DIRECTORY:\n autorep \n\n"+ + "It does not handle spaces or special characters well. Using "+ + "strings with parentheses, brackets, or anything other than "+ + "the english alphabet may have unexpected results."+ + "\n%^RED%^%^BOLD%^ADMIN USE ONLY!%^RESET%^"); + SetMass(20); + SetValue(10); + SetVendorType(VT_TREASURE); + active = 0; +} + +void init(){ + add_action("rep_string","replace"); + add_action("autorep","autorep"); +} + +int eventActivate(){ + validate(); + write("With an unearthly roar, the string replacer comes "+ + "to life. You sense great danger."); + write("\n\nWARNING: Your current working directory is:\n\n"); + write(this_player()->query_cwd()+"\n\n"); + say(this_player()->GetName()+" turns on "+possessive(this_player())+ + " string replacer and you hear a loud, unearthly "+ + "roar that makes the ground tremble."); + active = 1; + return 1; +} + +int eventDeactivate(){ + validate(); + write("The string replacer powers off with a peculiar "+ + "mechanical whine. You feel safer."); + say(this_player()->GetName()+"'s string replacer "+ + "powers down."); + active = 0; + return 1; +} + +varargs mixed eventTurn(string str){ + validate(); + if( this_player() != environment() ) { write("You don't have that."); return 0; } + write("You turn the replacer over in your hands."); + say(this_player()->GetKeyName()+" turns over a string replacer in "+possessive(this_player())+" hands."); + return 1; +} + +int eventTurnOn(object ob){ + validate(); + + if( this_player() != environment() ) { write("You don't have that."); return 0; } + + if(!creatorp(this_player())) { + write("This device is not usable by mortals."); + return 0; + } + + if(active){ + write("It's already on."); + return 0; + } + else eventActivate(); + + return 1; +} + +varargs mixed eventTurnOff(string str){ + validate(); + if( this_player() != environment() ) { write("You don't have that."); return 0; } + if(!active){ + write("It's already off."); + return 0; + } + else eventDeactivate(); + + return 1; +} + +int autorep(string str){ + string dir, a1, a2; + string *listing; + + validate(); + if(!active){ + write("The string replacer is not turned on."); + return 1; + } + + if( !str || str=="" || sscanf(str,"%s %s",a1,a2) != 2){ + write("Syntax: autorep \n"); + eventDeactivate(); + return 1; + } + dir=this_player()->query_cwd()+"/"; + listing=get_dir(dir); + foreach(string file in listing){ + if(file_size(dir+file) > 0) this_object()->rep_string(file+" "+str); + } + eventDeactivate(); + return 1; +} + +int rep_string(string str){ + string dir,file,tempfile,backup; + int valid_line; + + validate(); + if(!active){ + write("The string replacer is not turned on."); + return 1; + } + + valid_line=1; + n=1; + if( !str || str==""){ + write("Syntax: replace \n"); + eventDeactivate(); + return 1; + } + if(sscanf(str,"%s %s %s",a1,a2,a3) == 3){ + dir=this_player()->query_cwd()+"/"; + file=dir+a1; + + if(file_size(file) <= 0 ) { + write("Invalid filename."); + eventDeactivate(); + return 1; + } + + tempfile="/tmp/"+lower_case(this_player()->GetName())+".TempReplace"; + backup="/tmp/"+lower_case(this_player()->GetName())+"."+a1+".bak"; + if(file_size(backup)){ rm(backup); } + if(file_size(tempfile)){ rm(tempfile); } + write("Searching "+a1+" for string: "+a2+".\n"); + while(valid_line){ + line=read_file(file, n, 1); + if(!line || line=="") valid_line=0; + this_object()->replace(line); + if(line) write_file(tempfile,line); + n++; + } + cp(file, backup); + cp(tempfile, file); + if(file_size(backup)){ rm(backup); } + if(file_size(tempfile)){ rm(tempfile); } + write("Replace action complete. File "+file+" modified.\n"); + if(query_verb() == "replace") eventDeactivate(); + return 1; + } + write("Syntax: replace \n"); + eventDeactivate(); + return 1; +} + +int replace(string str){ + string s1,s2; + validate(); + if(sizeof(str) && sscanf(str,"%s"+a2+"%s",s1,s2)>1){ + line=s1+a3+s2; + write("Found string in line "+n+". Replacing with: "+a3+".\n"); + this_object()->replace(line); + } + return 1; +} diff --git a/lib/secure/obj/robot.c b/lib/secure/obj/robot.c new file mode 100644 index 0000000..82d18b6 --- /dev/null +++ b/lib/secure/obj/robot.c @@ -0,0 +1,874 @@ +#include +#include NETWORK_H +#include +#define ANSI(p) sprintf("%c["+(p)+"m", 27) +#define ESC(p) sprintf("%c"+(p), 27) + +inherit LIB_ITEM; + +static int observing = 0; +static int counter = 0, attempting, connected, socket ; +static int dud_count = 0, spawning, last_action, loop_count = 0; +static int maxbox = 32; +static int newbot = 1; +static object person, player; +static string preset, name, passwd, gender; +static string display_name, email, real_name, race; +static string *exits, previous_command; +static string travel = "go "; +static int enable = 0; +static string ip = "127.0.0.1 1111"; +static string local_currency = "silver"; +static string watching = ""; +static int broadcast, onhand, open_account, balance, wander; +static int pocket_money = 600; +static int spent, in_combat, recursion_brake; +static mixed *socks_array = ({}); + +mapping AnsiMap1 = +([ "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":"" ]); +mapping AnsiMap2 = ([]); + +int parse_comm( string str ); +int DoorHandler(string str); +int do_connect(string args); +int do_reset( string args ); +int Setup(); +string eventBolo(string str); +string eventWatch(string str, string watching); +int eventCombatPrep(); + +int report(string str){ + object owner; + if(!this_object() || !(owner = environment(this_object()))){ + return 0; + } + if(!owner || !creatorp(owner)) return 0; + if(observing){ + tell_player(owner, "%^RED%^OBSERVER%^BLUE%^ "+name+"%^RESET%^ "+str); + } + return 1; +} + +varargs static void validate(int i){ + if(i){ + if(!socket_status(i) || !socket_status(i)[5]){ + error("Bad socket, fd "+i); + } + } +} + +static void create(mixed arg) +{ + item::create(); + AnsiMap2 = ([]); + if(arg && stringp(arg)) ip = arg; + SetShort( "a gamebot" ) ; + SetLong( "A gamebot control module."); + SetMass( 5 ) ; + attempting = 0 ; + connected = 0 ; + socket = 0 ; + person = 0 ; + parse_init(); + set_heart_beat(0); + SetNoClean(1); + if(!name) name = alpha_crypt(random(8)+3); + SetId(({"bot","gamebot","module",name})); + name = "xkcd"+name; + SetKeyName(name); + if(!passwd) passwd = "password"; + if(!gender) gender = "male"; + if(!display_name) display_name = "Gamebot"; + if(!email) email = "bot@delete.me"; + if(!real_name) real_name = "Chachamaru Karakuri"; + if(!race) race = "human"; + foreach(mixed key, mixed val in AnsiMap1){ + AnsiMap2[val] = key; + } + if(!undefinedp(arg) && intp(arg)) maxbox = arg; +} + +int eventBroadcastGreen(){ + filter(all_inventory(environment()), (: $1 != this_object() :) )->eventStartBot(ip); + return 1; +} + +int eventStartBot(string str){ + int tmp; + if(attempting || connected) return 0; + if(str) ip = str; + if(str && sscanf(str,"local %d",tmp)){ + ip = "127.0.0.1 "+query_host_port(); + maxbox = tmp; + write("maxbox: "+maxbox); + write("ip: "+ip); + } + set_heart_beat(1); + if(clonep(this_object())) call_out( (: do_connect, ip :), 1); + return 1; +} + +int eventRespawn(){ + object newbox; + string *file_names = ({}); + int boxnum = 0; + + if(!spent){ + foreach(object thing in all_inventory(environment())){ + if(base_name(thing) == base_name(this_object())){ + boxnum++; + file_names += ({ file_name(thing) }); + } + } + if(boxnum < maxbox){ + newbox = new(base_name(this_object()), maxbox); + newbox->eventMove(environment()); + tell_object(environment(newbox), "Respawned box "+boxnum+": "+file_name(newbox)); + } + } + spent = 1; + return 1; +} + +int Setup(){ + if(!enable){ + dud_count++; + if(dud_count > 5){ + if( socket ) + { + socket_close( socket ) ; + } + tell_object(environment(),"I am "+name+" and I have failed. I die."); + parse_comm("dcon"); + if(sizeof(filter(all_inventory(environment()), (: base_name($1) == base_name(this_object()) :) )) > 1) eventDestruct(); + return 1; + } + do_reset("client"); + do_connect(ip); + call_out( (: Setup :), 60); + } + return 1; +} + +string random_act(){ + string ret; + int randy = random(31); + if(!newbot){ + switch(randy){ + case 0 : ret = "inventory";break; + case 1 : ret = "score";break; + case 2 : ret = "who";break; + case 3 : ret = "stat";break; + case 4 : ret = "uptime";break; + case 5 : ret = "hist";break; + case 6 : ret = "env";break; + case 7 : ret = "money";break; + case 8 : ret = "hist newbie";break; + case 9 : ret = "hist gossip";break; + case 10 : ret = "mudlist";break; + case 11 : ret = "version";break; + case 12 : ret = "open door";break; + case 13 : ret = "cast buffer";break; + case 14 : ret = "cast meditate";break; + case 15 : ret = "search";break; + case 16 : ret = "put all in my bag";break; + case 17 : ret = "put all in my box";break; + case 18 : ret = "put all in my chest";break; + case 19 : ret = "wear all";break; + case 20 : ret = "wield a sword in right hand";break; + case 21 : ret = "wield a knife in right hand";break; + case 22 : ret = "wield a club in right hand";break; + case 23 : ret = "kill all";break; + case 24 : ret = "wimpy 30";break; + case 25 : in_combat = 0;ret = "look";break; + case 26 : ret = "position";break; + case 27 : ret = "click heels";break; + case 28 : ret = "push button on omni";break; + case 29 : ret = "pull pin on grenade";break; + case 30 : ret = "env";break; + default : ret = "reply :)";break; + } + } + else { + switch(newbot){ + case 1 : ret = "terminal unknown";break; + default : ret = "customize strength 15";break; + } + if(newbot > 2) newbot = 0; + else newbot++; + } + return ret; +} + +string eventStargate(string str){ + report("stargate: "+str); + if(grepp(str,"idle stargate")){ + int which = random(4); + switch(which){ + case 0 : parse_comm("dial stargate lab");break; + case 1 : parse_comm("dial tower");break; + case 2 : parse_comm("dial campus lab");break; + case 3 : parse_comm("dial praxis");break; + } + } + if(grepp(str,"outbound stargate")){ + parse_comm("enter stargate"); + } + return "wave"; +} + + +int think(string str){ + string tmp, ret = ""; + int this_action = time(); + foreach(mixed element in values(AnsiMap1)){ + str = replace_string(str,element,""); + } + str = strip_colours(str); + report(name+" think(\""+str+"\")"); + if(!sizeof(str)) return 0; + this_object()->eventScanExits(str); + if(this_action - last_action > 10 && enable){ + parse_comm("stand up"); + in_combat = 0; + } + last_action = this_action; + + if(enable) tmp = eventBolo(str); + if(tmp && tmp == "break") return 1; + if(sizeof(watching) < 1){ + if(grepp(str, "You bump into ") && grepp(lower_case(str), "door")){ + DoorHandler(str); + } + if(grepp(str, "A great sea")){ + travel = "swim "; + ret = "swim west"; + } + if(grepp(str, "You stand up.")) travel = "go "; + if(grepp(str, "a portal forms")) ret = "enter stargate"; + if(grepp(str, "Perhaps you should try crawling.")) travel = "crawl "; + if(grepp(str, "You are swimming.")) travel = "swim "; + if(grepp(str, "What name do you wish")) ret = name; + if(grepp(str, "Please enter a new name:")) ret = name; + if(grepp(str, "Do you really wish to be known as ")) ret = "y"; + if(grepp(str, "Are you 13 years of age or older")) ret = "y"; + if(grepp(str, "Create a password of at least 5 letters")) ret = passwd; + if(grepp(str, "Do you use a screen reader for the visuall")) ret = "n"; + if(grepp(str, "Password:")) ret = passwd; + if(grepp(str, "Invalid password.")) ret = "12345"; + if(grepp(str, "Please confirm your password")) ret = passwd; + if(grepp(str, "Please choose an interesting gender")) ret = gender; + if(grepp(str, "Please choose a gender")) ret = gender; + if(grepp(str, "to appear however you wish using spaces")) ret = name; + if(grepp(str, "requires a valid email")) ret = email; + if(grepp(str, "Type 'dcon' to finalize exit.")) ret = "dcon"; + if(grepp(str, "If you do not mind, please enter your real name")) ret = real_name; + if(grepp(str, "You must now pick a race.")) ret = "pick "+race; + if(grepp(str, "No such race.")) ret = "pick roman"; + if(grepp(str, "This mud has enabled AUTO_WIZ.")) ret = "player"; + if(grepp(str, "Autosaving...")) ret = random_act(); + if(grepp(str, "You must now pick a class.")) ret = "pick fighter"; + if(grepp(str, "An interactive copy of you currently exists.")){ + ret = "n"; + name = "xkcd"+alpha_crypt(random(8)+3); + } + if(grepp(str, "No more attempts allowed")) ret = "foo"; + if(grepp(str, "Reconnected.") || grepp(str,"You wear") ) { + ret = random_act(); + enable = 1; + wander = 1; + } + if(grepp(str, "You may choose to regenerate into a new body here.")) ret = "regenerate"; + if(grepp(str, "press enter:")) ret = ""; + if(grepp(str, "press :")) ret = "q"; + if(grepp(str, "%:")) ret = ""; + if(grepp(str, "Press to continue:")) ret = ""; + if(grepp(str, "stargate")){ + ret = eventStargate(str); + } + if(grepp(str, "a portal forms")) ret = "enter stargate"; + previous_command = ret; + } + + else { + ret = eventWatch(str, watching); + } + ret = trim(ret,"green"); + if(ret && ret != "" && sizeof(ret)) { + report(" command: "+ret); + this_object()->parse_comm(ret); + } + return 1; +} + +string eventBolo(string str){ + string ret = ""; + wander = 0; + + if(grepp(str, "Please enter a new name:")){ + name = alpha_crypt(random(8)+3); + SetId(({"bot","gamebot","module",name})); + name = "xkcd"+name; + SetKeyName(name); + parse_comm(name); + } + + if(grepp(str, "To enter a sample set of rooms")){ + parse_comm("customize strength 15"); + parse_comm("pk on"); + parse_comm("pk on"); + parse_comm("wimpy 30"); + parse_comm("chfn"); + return "break"; + } + + if(grepp(str, "Real name ")){ + parse_comm(real_name); + return "break"; + } + + if(grepp(str, "Wimpy mode:") && grepp(str, "off")){ + parse_comm("wimpy 30"); + } + + if(grepp(str, "Reprompt mode:") && grepp(str, "off")){ + parse_comm("reprompt on"); + } + if(grepp(str, "Charmode:") && grepp(str, "off")){ + //parse_comm("charmode on"); + } + if(grepp(str, "Keepalive mode:") && !grepp(str, "off")){ + parse_comm("keepalive off"); + } + + if(grepp(str, "You can't crawl in your current position")){ + parse_comm("position"); + parse_comm("look"); + } + + if(grepp(str, "fight unless you are up")){ + parse_comm("position"); + parse_comm("look"); + } + + if(grepp(str, "Go in which direction?")){ + parse_comm("position"); + parse_comm("look"); + } + + if(grepp(str, "Your injuries prevent easy movement")){ + parse_comm("position"); + parse_comm("look"); + } + + if(grepp(str, "You are prone")){ + travel = "crawl "; + parse_comm("look"); + report("travel: ("+travel+")"); + } + if(grepp(str, "You are sitting")){ + travel = "crawl "; + parse_comm("look"); + } + + if(grepp(str, "You are flying")){ + travel = "fly "; + parse_comm("look"); + } + + if(grepp(str, "You are standing.")){ + travel = "go "; + parse_comm("look"); + } + + if(grepp(str, "You are not ")){ + parse_comm("position"); + } + + if(grepp(str, "press enter:") || grepp(str, "%:") || + grepp(str,"Press to continue:" )){ + parse_comm(""); + } + + if(grepp(str, "a portal forms")){ + parse_comm("enter stargate"); + } + + if(grepp(str, "stargate")){ + eventStargate(str); + } + + if(!recursion_brake){ + if(grepp(str, "table")){ + parse_comm("get all from table"); + } + + if(grepp(str, "wardrobe")&& !grepp(str, "There is no ")) { + parse_comm("open a wardrobe"); + parse_comm("get all from wardrobe"); + parse_comm("wear all"); + } + + if(grepp(str, "chest")&& !grepp(str, "There is no ")) { + parse_comm("open a chest"); + parse_comm("get all from a chest"); + parse_comm("wear all"); + } + + if(grepp(str, "bag") && !grepp(str, "There is no ")){ + parse_comm("open a bag"); + parse_comm("get all from a bag"); + parse_comm("wear all"); + } + + if(grepp(str, "box")&& !grepp(str, "There is no ")) { + parse_comm("open a box"); + parse_comm("get all from a box"); + parse_comm("wear all"); + } + + if(grepp(str, "a knife rack")){ + parse_comm("get all from rack"); + parse_comm("unwield all"); + parse_comm("wield a carving knife in right hand"); + } + + if(grepp(str, "large stove")&& !grepp(str, "There is no ")){ + parse_comm("open stove"); + } + + if(grepp(str, "You get") && (grepp(str, "flesh") || grepp(str, "corpse"))){ + parse_comm("get all from a corpse"); + parse_comm("get all from my a pile"); + } + + if(grepp(str, "You swing at")){ + if(!in_combat){ + eventCombatPrep(); + } + } + + if(grepp(str, " rat ") ){ + parse_comm("kill a rat"); + } + + if(grepp(str, "newt")){ + parse_comm("kill a newt"); + } + + if(grepp(str, "gecko")){ + parse_comm("kill a gecko"); + } + + if(grepp(str, " orc") && ( grepp(str, "is standing here") || grepp(str, "are standing here")) ){ + eventCombatPrep(); + parse_comm("target first orc"); + } + + if(grepp(str, "Mansion Garden")) { + parse_comm("drop ladder"); + parse_comm("climb ladder"); + } + + if(grepp(str, "Otik, the keeper of the shop")){ + parse_comm("wear all"); + parse_comm("unwield all"); + parse_comm("sell all to otik"); + parse_comm("buy sword from otik"); + parse_comm("wield sword in right hand"); + ret = "say Thank you, Otesanek."; + } + + if(grepp(str, "Herkimer the kind wizard")){ + parse_comm("ask herkimer to teach buffer"); + parse_comm("ask herkimer to teach meditate"); + } + recursion_brake = 10; + } + + if(grepp(str,"You must create an account") ){ + parse_comm("say ok, dude"); + parse_comm("request account from zoe"); + } + if(grepp(str, "Dirk the Tired")){ + parse_comm("ask dirk to advance"); + } + + if(grepp(str, "Zoe the bank teller")){ + parse_comm("say hello, Zoe"); + parse_comm("money"); + parse_comm("ask zoe for balance"); + if((onhand - pocket_money) > 0) + parse_comm("ask zoe to deposit "+(onhand - pocket_money)+" "+local_currency); + if(balance - pocket_money + onhand > 0 && (onhand + balance - 5) < pocket_money) + parse_comm("ask zoe to withdraw "+(pocket_money - onhand)+" "+local_currency); + } + + if(grepp(str,"In your pockets you find only")){ + string s1, s2; + int i1; + if(sscanf(str,"%s %d "+local_currency+"%s",s1,i1,s2) < 3) + onhand = 0; + else onhand = i1; + } + + if(grepp(str, "and open an account with") || + grepp(str,"You already have an account with") ) + open_account = 1; + + if(grepp(str, "Your last transaction:")){ + string s1, s2, s3, s4; + int i1; + if(sscanf(str,"%s"+local_currency+"%s:%s\n%s",s1,s2,s3,s4) == 4){ + balance = atoi(trim(s3)); + } + } + wander = 1; + return ret; +} + +void heart_beat(){ + int bots; + counter++; + if(recursion_brake) recursion_brake--; + + if(!environment(this_object())) return; + if(!adminp(environment(this_object()))) return; + if(!clonep(this_object())) return; + bots = sizeof(filter(all_inventory(environment()), + (: base_name($1) == base_name(this_object()) :))); + + if((!spent || bots < 2) && enable && bots < maxbox) + { + call_out( (: eventRespawn :), 2 ); + } + + if(!enable) return; + if(!(counter % 5)) this_object()->eventWalkabout(); + if(!broadcast) eventBroadcastGreen(); + if(!(counter % 20) && travel == "crawl ") parse_comm("stand up"); + if(counter > 1000) counter = 0; +} + +void init(){ + ::init(); + add_action( "do_connect", ({ "connect", "telnet" }) ) ; + add_action( "do_reset", "reset" ) ; + add_action( "do_reconnect", "reconnect" ) ; + add_action( "eventStartBot", "bot"); + add_action( "do_observe","observe"); +} + +int do_observe(string str){ + if(str == name ){ + if(!observing) observing = 1; + else observing = 0; + return 1; + } + return 0; +} + +int DoorHandler(string str){ + string s1; + if(!sscanf(str,"You bump into %s.",s1)){ + parse_comm("open first door"); + return 0; + } + parse_comm("unlock first door with first key"); + parse_comm("unlock first door with second key"); + parse_comm("open "+s1); + parse_comm("open first door"); + return 1; +} + +int eventScanExits(string str){ + string s1, s2, s3; + string *oldexits = ({travel+"north",travel+"south",travel+"east",travel+"west", travel+"up", travel+"down",travel+"out"}); + string *newexits = ({}); + string *dirs = ({}); + str = strip_colours(str); + if(grepp(str,"too dark to see") || grepp(str,"too bright to see") || + grepp(str,"go nowhere at all")){ + exits = ({}); + } + if(!sizeof(exits) && grepp(str," leaves ")){ + if(sscanf(str,"%s leaves %s.",s1,s2) == 2){ + exits = ({travel+s2}); + } + } + if(sscanf(str,"%sObvious exit: %s\n%s",s1,s2,s3) == 3 || + sscanf(str,"%sObvious exits: %s\n%s",s1,s2,s3) == 3 || + sscanf(str,"%sObvious exit: %s",s1,s2) == 2 || + sscanf(str,"%sObvious exits: %s",s1,s2) == 2){ + dirs = explode(s2,", "); + } + else if(sscanf(str,"%s [%s]%s", s1, s2, s3) ){ + if(s2) dirs = explode(s2,","); + } + if(sizeof(dirs)){ + string Esc = sprintf("%c",27); + oldexits = ({}); + foreach(string dir in dirs){ + string junk1, junk2; + if(grepp(dir, Esc)){ + if(sscanf(dir,"%s"+Esc+"%s",junk1,junk2)) dir = junk1; + } + if(!dir || !sizeof(dir)) continue; + dir = trim(dir); + switch(dir){ + case "u" : dir = "up";break; + case "d" : dir = "down";break; + case "o" : dir = "out";break; + case "n" : dir = "north";break; + case "s" : dir = "south";break; + case "e" : dir = "east";break; + case "w" : dir = "west";break; + case "ne" : dir = "northeast";break; + case "nw" : dir = "northwest";break; + case "se" : dir = "southeast";break; + case "sw" : dir = "southwest";break; + } + if(grepp(dir,"enter ")) newexits += ({ dir }); + else newexits += ({ travel+dir }); + } + if(sizeof(newexits)) { + exits = newexits; + enable = 1; + } + } + if(!sizeof(exits)) exits = oldexits; + report("exits: "+identify(exits)); + return 1; +} + +int eventWalkabout(){ + int randy = random(sizeof(exits)); + if(in_combat) return 0; + parse_comm(exits[randy]); + parse_comm("get all"); + return 1; +} + +int eventCombatPrep(){ + parse_comm("unwield all"); + parse_comm("wear all"); + parse_comm("wield first sword in right hand"); + parse_comm("wield first knife in right hand"); + parse_comm("wield first club in right hand"); + parse_comm("wield first axe in right hand"); + parse_comm("wield first dagger in right hand"); + parse_comm("wield first staff in right hand and left hand"); + parse_comm("wield first axe in right hand and left hand"); + parse_comm("wear pack"); + parse_comm("put all in bag"); + parse_comm("put all in pack"); + parse_comm("drop all"); + in_combat = 1; + return 1; +} + +void SetConnection(string str){ + if(str) preset = str; +} + +int do_reconnect() +{ + if( !connected ) + { + notify_fail( "The telnet client is not connected!\n" ) ; + return 0 ; + } + person = this_object() ; + return 1 ; +} + +int do_reset( string args ) +{ + notify_fail( "Usage: reset client\n" ) ; + if( !args || args == "" ) + { + return 0 ; + } + if( args != "client" ) + { + return 0 ; + } + if( connected ) + { + if( socket ) + { + socket_close( socket ) ; + } + } + attempting = 0 ; + connected = 0 ; + socket = 0 ; + person = 0 ; + return 1 ; +} + +int do_connect(string args) +{ + int new_socket, sc_result, port ; + string error, ip_address ; + + if( !args || args == "" ) + { + notify_fail( "You fail." ) ; + return 0 ; + } + if( sscanf( args, "%s %d", ip_address, port ) != 2 ) + { + notify_fail( "You fail." ) ; + return 0 ; + } + if( attempting ) + { + notify_fail( "Telnet connection attempt already in progress.\n" ) ; + return 0 ; + } + if( connected ) + { + notify_fail( "Already connected...\n" ) ; + return 0 ; + } + new_socket = socket_create( STREAM, "read_callback", "close_callback" ) ; + + write("new_socket: "+new_socket); + loop_count++; + if(loop_count > 10) this_object()->eventDestruct(); + + foreach(mixed element in socket_status()){ + if(intp(element[0]) && element[0] != -1 && !grepp(element[3],"*")){ + if(!socks_array) socks_array = ({}); + socks_array += ({ element[0] }); + } + } + socks_array = ({}); + + if( new_socket < 0 ) + { + switch( new_socket ) + { + case EEMODENOTSUPP : + error = "Socket mode not supported.\n" ; + break ; + case EESOCKET : + error = "Problem creating socket.\n" ; + break ; + case EESETSOCKOPT : + error = "Problem with setsockopt.\n" ; + break ; + case EENONBLOCK : + error = "Problem with setting non-blocking mode.\n" ; + break ; + case EENOSOCKS : + error = "No more available efun sockets.\n" ; + break ; + case EESECURITY : + error = "Security violation attempted.\n" ; + break ; + default : + error = "Unknown error code: " + new_socket + ".\n" ; + break ; + } + notify_fail( "Unable to connect, problem with socket_create.\n" + "Reason: " + error ) ; + return 0 ; + } + sc_result = socket_connect( new_socket, ip_address + " " + port, + "read_callback", "write_callback" ) ; + if( sc_result != EESUCCESS ) + { + notify_fail( "Failed to connect.\n" ) ; + return 0 ; + } + attempting = 1 ; + socket = new_socket ; + person = (object)previous_object() ; + player=this_object(); + tell_object(environment(),"I am "+name+" , a.k.a "+file_name(this_object())+ + " and I am connected to "+ip+" on socket"+socket+"\n"); + spent = 0; + return 1 ; +} + +void read_callback( int fd, mixed message ) +{ + validate(fd); + player->eventPrint(message); + player->think(message); +} + +void close_callback( int fd ) +{ + validate(fd); + if( connected ) + { + } + if( attempting ) + { + } + socket_close( fd ) ; + attempting = 0 ; + connected = 0 ; + socket = 0 ; +} + +void write_callback( int fd ) +{ + validate(fd); + attempting = 0 ; + connected = 1 ; +} + +int parse_comm( string str ){ + int write_stat = 0; + string tmpstr = ""; + int i = sizeof(str); + for(int j = 0;j < i;j++){ + if(str[j] == 32) tmpstr += " "; + else if(str[j] > 32 && str[j] < 128) tmpstr += str[j..j]; + } + str = replace_string(tmpstr,sprintf("%c",27)+"[0m",""); + report("parse_comm(\""+str+"\")"); + if(str=="dcon" || str=="quit") + { + socket_close( socket ) ; + attempting = 0 ; + connected = 0 ; + socket = 0 ; + person = 0 ; + this_object()->eventDescribeEnvironment(); + return 1 ; + } else { + if( !connected ) + { + int fco; + enable = 0; + fco = find_call_out("Setup"); + if(fco == -1) Setup(); + return 1 ; + } + if( attempting ) + { + int fco; + enable = 0; + fco = find_call_out("Setup"); + if(fco == -1) Setup(); + return 1 ; + } + validate(socket); + write_stat = socket_write( socket, str + "\n" ) ; + return 1 ; + } +} diff --git a/lib/secure/obj/snooper.c b/lib/secure/obj/snooper.c new file mode 100644 index 0000000..0fdc792 --- /dev/null +++ b/lib/secure/obj/snooper.c @@ -0,0 +1,88 @@ +#include +#include ROOMS_H +#include +#include +inherit LIB_ITEM; + +string guy, stringy; +int seconds; +object ob; + +void create(){ + item::create(); + + SetKeyName("snooper object"); + SetId( ({"thing","item","thang","dingus","snooper","object"}) ); + SetAdjectives( ({"invisible","snooper","snoop"}) ); + SetShort("an invisible object"); + SetLong("This is an object of indeterminate nature and proportions. " + "It is intentionally invisible, and your attempts to " + "understand it may constitute a security breach. You'd " + "be well advised to leave it alone."); + SetInvis(1); + set_heart_beat(10); + SetNoClean(1); + SNOOP_D->RegisterSnooper(); +} + +void init(){ + ::init(); +} + +void stamp_time(){ + seconds = time(); + write_file("/secure/log/adm/"+guy+".log","\n"+timestamp()+"\n"); +} + +void heart_beat(){ + object dude; + if(!guy || !(dude = find_player(guy))) { + eventDestruct(); + } + if(dude && environment(dude) && base_name(environment(dude)) == ROOM_FREEZER) eventDestruct(); + if(time() - seconds > 600 ) stamp_time(); +} + +void receive_snoop(string str){ + stringy = str; + unguarded((: write_file("/secure/log/adm/"+guy+".log",guy+" "+timestamp()+": "+stringy) :)); + SNOOP_D->GetSnoop(guy, stringy); + if( file_size("/secure/log/adm/"+guy+".log") > 200000) { + write_file("/secure/log/adm/"+guy+".log","\nEND-OF-LOG\n"); + if(!directory_exists("/secure/log/adm/archive/")) mkdir("/secure/log/adm/archive/"); + rename("/secure/log/adm/"+guy+".log", "/secure/log/adm/archive/"+guy+"."+time()); + } +} + +int eventStartSnoop(string str){ + string snoopee; + if(!str || str == "") return 0; + snoopee = "nobody"; + str = lower_case(str); + guy = str; + + if(!ob=find_player(str)) { write("Target not found."); return; } + unguarded((: write_file("/secure/log/adm/snoop.err",snoop(this_object(), ob)?"":guy+": snoop failed.\n") :)); + if(query_snooping(this_object())) snoopee = identify(query_snooping(this_object())); + SNOOP_D->RegisterSnooper(); + write_file("/secure/log/adm/"+str+".log","\nNEW SESSION: "+timestamp()+"\n"); + return 1; +} + +void receive_message(string s1, string s2){ + stringy = s2; + unguarded((: write_file("/secure/log/adm/"+guy+".log",guy+": "+stringy) :)); + SNOOP_D->GetSnoop(guy, stringy); +} + +int eventDestruct(){ + if(base_name(previous_object()) != SNOOP_D && !archp(previous_object(2)) && + previous_object() != this_object()) return 0; + SNOOP_D->UnregisterSnooper(); + return item::eventDestruct(); +} + +string GetSnooped(){ + if( !(master()->valid_apply(({ "PRIV_ASSIST", "PRIV_SECURE", "SNOOP_D" }))) ) return ""; + else return guy; +} diff --git a/lib/secure/obj/staff.c b/lib/secure/obj/staff.c new file mode 100644 index 0000000..9f66044 --- /dev/null +++ b/lib/secure/obj/staff.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include + +inherit LIB_ITEM; +inherit MODULES_ARMOR; +inherit MODULES_CREATE; +inherit MODULES_MAPPING; +inherit MODULES_GENERIC; +inherit MODULES_ROOM; +inherit MODULES_FILE; +inherit MODULES_MONEY; +inherit MODULES_READ; +inherit MODULES_DOOR; + +static void create(){ + item::create(); + SetKeyName("staff"); + SetId( ({ "staff", "stick", "tanstaafl" }) ); + SetAdjectives( ({ "wood","wooden","creator","creator's","creation" }) ); + SetShort("a wooden staff"); + SetLong("This staff is old, weathered, "+ + "and lumpy. However, it feels quite sturdy "+ + "and solid. For more info: help staff"); + SetProperties(([ + "no steal" : 1, + ])); + SetDamagePoints(50); + SetClass(100); + SetMass(100); + SetNoCondition(1); + SetWeaponType("blunt"); + SetHands(2); + SetDamageType(BLUNT); +} +void init(){ + ::init(); +} + +int CanSell() { return 0; } diff --git a/lib/secure/obj/tc.c b/lib/secure/obj/tc.c new file mode 100644 index 0000000..4b3417e --- /dev/null +++ b/lib/secure/obj/tc.c @@ -0,0 +1,249 @@ +#include +#include NETWORK_H +inherit LIB_ITEM; + +int attempting, connected, socket ; +object person, player; +string preset; +string DS_IP = "66.197.134.110 8000"; + +static void create() +{ + string myname = mud_name(); + item::create(); + SetKeyName("telnet_room_client"); + SetShort( "a telnet client" ) ; + SetId(({"client","telnet client"})); + SetLong( "It's a small pocket sized telnet terminal.\n" + "It appears customized to connect to Dead Souls MUD only.\n" + "Use 'telnet' or 'connect' to begin.\n\nCommands:\n" + "[connect|telnet] : start telnet session.\nreset [client]" + " : reset the telnet client.\nreconnect : reconnect to session" + " (if you go netdead)\n"); + SetMass(0) ; + attempting = 0 ; + connected = 0 ; + socket = 0 ; + person = 0 ; + set_heart_beat(2); + if(!strsrch(myname, "Dead Souls") && myname != "Dead Souls Prime"){ + DS_IP = "66.197.134.110 6666"; + } +} + +void heart_beat(){ + if(!this_object() || !clonep(this_object())) return; + if(!environment() || !living(environment()) + || !environment(environment())) + eventDestruct(); + if(this_object() && environment() && environment(environment())){ + if(!connected && base_name(environment(environment())) + != "/domains/default/room/telnet_room") + eventDestruct(); + } +} + +void init() +{ + add_action( "do_connect", ({ "connect", "telnet" }) ) ; + add_action( "do_reset", "reset" ) ; + add_action( "do_reconnect", "reconnect" ) ; +} + +void SetConnection(string str){ + if(str) preset = str; +} + +int do_reconnect() +{ + if( !connected ) + { + notify_fail( "The telnet client is not connected!\n" ) ; + return 0 ; + } + write("Reconnecting into telnet session.\n"); + person = this_player() ; + input_to( "parse_comm", 0 ) ; + return 1 ; +} + +int do_reset( string args ) +{ + notify_fail( "Usage: reset client\n" ) ; + if( !args || args == "" ) + { + return 0 ; + } + if( args != "client" ) + { + return 0 ; + } + write("Resetting telnet client ...\n"); + if( connected ) + { + if( socket ) + { + socket_close( socket ) ; + } + } + attempting = 0 ; + connected = 0 ; + socket = 0 ; + person = 0 ; + write("Done!\n"); + return 1 ; +} + +string help() +{ + return "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n" + " Usage : connect [ip_address] [port]\n" + "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n" + "Note: use telnet port number 23 if you \n" + " are connecting to a normal site. \n" + "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n" ; +} + +varargs int do_connect(string args, object whom) +{ + int new_socket, sc_result, port ; + string error, ip_address ; + + if(preset) args = preset; + else args = DS_IP; + + if(args != DS_IP){ + if(!this_player()) return 1; + if(!telnet_privp(this_player())){ + this_player()->eventPrint("You aren't a member of the group of users permitted " + "to use this mud's telnet facility."); + return 1; + } + } + + if( !args || args == "" ) + { + notify_fail( help() ) ; + return 0 ; + } + if( sscanf( args, "%s %d", ip_address, port ) != 2 ) + { + notify_fail( help() ) ; + return 0 ; + } + if( attempting ) + { + notify_fail( "Telnet connection attempt already in progress.\n" ) ; + return 0 ; + } + if( connected ) + { + notify_fail( "Already connected...\n" ) ; + return 0 ; + } + new_socket = socket_create( STREAM, "read_callback", "close_callback" ) ; + if( new_socket < 0 ) + { + switch( new_socket ) + { + case EEMODENOTSUPP : + error = "Socket mode not supported.\n" ; + break ; + case EESOCKET : + error = "Problem creating socket.\n" ; + break ; + case EESETSOCKOPT : + error = "Problem with setsockopt.\n" ; + break ; + case EENONBLOCK : + error = "Problem with setting non-blocking mode.\n" ; + break ; + case EENOSOCKS : + error = "No more available efun sockets.\n" ; + break ; + case EESECURITY : + error = "Security violation attempted.\n" ; + break ; + default : + error = "Unknown error code: " + new_socket + ".\n" ; + break ; + } + notify_fail( "Unable to connect, problem with socket_create.\n" + "Reason: " + error ) ; + return 0 ; + } + sc_result = socket_connect( new_socket, ip_address + " " + port, + "read_callback", "write_callback" ) ; + if( sc_result != EESUCCESS ) + { + notify_fail( "Failed to connect.\n" ) ; + return 0 ; + } + attempting = 1 ; + socket = new_socket ; + person = (object)previous_object() ; + if(!whom) player=this_player(); + else player = whom; + input_to( "parse_comm", 0 ) ; + return 1 ; +} + +void read_callback( int fd, mixed message ) +{ + player->eventPrint(message); +} + +void close_callback( int fd ) +{ + if( connected ) + { + write("Connection closed by foreign host.\n"); + } + if( attempting ) + { + write("Attempt failed.\n"); + } + write("Type 'dcon' to finalize exit.\n"); + socket_close( fd ) ; + attempting = 0 ; + connected = 0 ; + socket = 0 ; +} + +void write_callback( int fd ) +{ + attempting = 0 ; + connected = 1 ; +} + +int parse_comm( string str ) +{ + if(str=="dcon" || str=="quit") + { + write("You return from your visit to another mud!\n"); + socket_close( socket ) ; + attempting = 0 ; + connected = 0 ; + socket = 0 ; + person = 0 ; + this_player()->eventDescribeEnvironment(); + return 1 ; + } else { + if( !connected ) + { + write("You are not connected. Type 'dcon' to exit.\n"); + input_to( "parse_comm", 0 ) ; + return 1 ; + } + if( attempting ) + { + write("Please wait, still attempting connection, " + "type 'dcon' to exit.\n"); + input_to( "parse_comm", 0 ) ; + return 1 ; + } + socket_write( socket, str + "\n" ) ; + input_to( "parse_comm", 0 ) ; + return 1 ; + } +} diff --git a/lib/secure/obj/weirder.c b/lib/secure/obj/weirder.c new file mode 100644 index 0000000..c4a420c --- /dev/null +++ b/lib/secure/obj/weirder.c @@ -0,0 +1,507 @@ +// This is a tool for me, Cratylus, by me, Cratylus. It's +// here because as lib maintainer I reserve the privilege to add +// things for me that are to my convenience. You must never, ever +// use this, and if you do, I do not want to hear about the +// problems it caused. + +#include +#include +#include +#include +inherit LIB_ITEM; + +static int numstress = 1; +string savefile = save_file(SAVE_WEIRDER); +string *lib_dirs = ({ "/lib/comp","/lib/daemons","/lib/events/", + "/lib/lvs", "/lib/lvs", "/lib/props", "/lib/std", + "/lib/user", "/lib/virtual", "/lib","/secure/lib","/secure/lib/net" }); +string *daemon_dirs = ({ "/daemon", "/secure/daemon" }); +string *cmd_dirs = ({ "/cmds/admins", "/cmds/builders", "/cmds/common", + "/cmds/creators", "/cmds/hm", "/cmds/players", "/secure/cmds/admins", + "/secure/cmds/builders", "/secure/cmds/common", "/secure/cmds/creators", + "/secure/cmds/hm", "/secure/cmds/players" }); +string *verb_dirs = ({ "/secure/verbs/creators", "/verbs/admins", + "/verbs/builders", "/verbs/common", "/verbs/creators", "/verbs/items", + "/verbs/players", "/verbs/rooms", "/verbs/spells", "/verbs/undead" }); +string *npc_dirs = ({ "/domains/default/npc", "/domains/town/npc", + "/domains/campus/npc", "/domains/cave/npc" }); +string *room_dirs = ({ "/domains/campus/room", "/domains/default/room", + "/domains/town/room", "/domains/Ylsrim/room", "/domains/Praxis", + "/domains/cave/room", + "/secure/room", "/domains/town/virtual/sub", "/domains/town/virtual/sky", + "/domains/town/virtual/surface", "/domains/town/virtual/bottom", + "/domains/town/virtual/forest", "/domains/town/space" }); +string *obj_dirs = ({ "/domains/campus/obj", "/domains/default/obj", + "/domains/town/obj", "/domains/Ylsrim/obj", "/obj", "/std", + "/secure/obj", "/shadows", "/secure/modules", "/domains/cave/obj" }); +string *weap_dirs = ({ "/domains/campus/weap", "/domains/default/weap", + "/domains/town/weap", "/domains/Ylsrim/weap", "/domains/cave/weap" }); +string *armor_dirs = ({ "/domains/campus/armor", "/domains/default/armor", + "/domains/town/armor", "/domains/Ylsrim/armor", "/domains/cave/armor" }); +string *meals_dirs = ({ "/domains/campus/meals", "/domains/default/meals", + "/domains/town/meals", "/domains/Ylsrim/meals", "/domains/cave/meals" }); +string *doors_dirs = ({ "/domains/campus/doors", "/domains/default/doors", + "/domains/town/doors", "/domains/Ylsrim/doors", "/domains/cave/doors" }); +string *powers_dirs = ({ "/powers/spells", "/powers/psionics", + "/powers/feats", "/powers/trades" }); +string *rooms = ({}); +string *obs = ({}); +string *npcs = ({}); +string *weapons = ({}); +string *armors = ({}); +string *meals = ({}); +string *doors = ({}); +string *libs = ({}); +string *daemons = ({}); +string *cmds = ({}); +string *verbs = ({}); +string *powers = ({}); +int nomore, yeik = 0; +string *exceptions = ({}); +static private string gstr; + +void validate(){ + if(!this_player() || !archp(this_player())){ + error("No."); + } +} + +int yeik(string str){ + int cout, err; + object *blanks; + validate(); + err=catch(blanks=objects((: base_name($1)==LIB_BLANK :))[0..63000]); + if(str){ + cout = call_out("yeik",1,"on"); + nomore = 0; + yeik = 1; + if(err){ + } + if(!environment() || !archp(this_player())){ + error("no!"); + } + for(int i = 400;i>0;i--){ + call_out("yeik",1,"on"); + new(LIB_BLANK); + } + } + else { + if(!nomore) cout = call_out("yeik",2); + yeik = 0; + if(sizeof(blanks)){ + foreach(object blank in blanks){ + destruct(blank); + } + + } + else nomore = 1; + } + return cout; +} + +void create(){ + ::create(); + exceptions = ({ "monty.c","charles.c","charly.c","tree.c","lars.c", + "wraith.c", "archwraith.c","drone2.c","beggar.c","drone.c"}); + SetKeyName("weirding module"); + SetId( ({"module", "box", "weirder"}) ); + SetAdjectives( ({"small","featureless","black"}) ); + SetShort("a small black box"); + SetLong("A small, featureless black box. Whatever it is, " + "you are somehow deeply certain it is not your business, " + "and you must leave it alone."); + SetMass(20); + SetBaseCost("silver",10); + SetVendorType(VT_TREASURE); +} +void init(){ + ::init(); + add_action("stressload","stressload"); + add_action("loadrooms","loadrooms"); + add_action("loadobs","loadobs"); + add_action("loadnpcs","loadnpcs"); + add_action("loadweaps","loadweaps"); + add_action("loadarmors","loadarmors"); + add_action("loadmeals","loadmeals"); + add_action("loaddoors","loaddoors"); + add_action("loadthings","loadthings"); + add_action("loadcmds","loadcmds"); + add_action("loaddaemons","loaddaemons"); + add_action("loadverbs","loadverbs"); + add_action("loadlibs","loadlibs"); + add_action("loadsys","loadsys"); + add_action("loadall","loadall"); + add_action("yeik","yeik"); + add_action("yeik2","yeik2"); + add_action("vargon","vargon"); + add_action("commcheck","commcheck"); + add_action("perfcheck","perfcheck"); +} + +static int loadthing(string str){ + if(last(str,2) == ".c"){ + gstr = str; + if(unguarded( (: find_object(truncate(gstr,2)) :)) ) return 1; + reset_eval_cost(); + catch( update(str) ); + } + return 1; +} + +int loadrooms(){ + validate(); + if(!rooms) rooms = ({}); + foreach(string roomdir in room_dirs){ + string *dir_array = ( get_dir(roomdir+"/") || ({}) ); + foreach(string roomfile in dir_array){ + string loadee = roomdir+"/"+roomfile; + rooms += ({ loadee }); + call_out("loadthing", 0, loadee); + } + } + return 1; +} + +int loadobs(){ + validate(); + if(!obs) obs = ({}); + foreach(string obsdir in obj_dirs){ + foreach(string obfile in get_dir(obsdir+"/")){ + string loadee = obsdir+"/"+obfile; + if(!strsrch(loadee,"/obj/area_room")) continue; + if(!strsrch(loadee,"/obj/stargate")) continue; + obs += ({ loadee }); + call_out("loadthing", 0, loadee); + } + } + return 1; +} + +int loadnpcs(mixed args){ + int i; + validate(); + if(!args) i = 1; + if(intp(args)) i = args; + if(stringp(args)) i = atoi(args); + if(!npcs) npcs = ({}); + foreach(string npcsdir in npc_dirs){ + foreach(string npcfile in get_dir(npcsdir+"/")){ + string loadee; + int x = i; + if(member_array(npcfile, exceptions) != -1){ + tc("skipping "+npcfile,"green"); + continue; + } + loadee = npcsdir+"/"+npcfile; + npcs += ({ loadee }); + while(x){ + call_out("loadthing", 0, loadee); + x--; + } + } + } + return 1; +} + +int loadweaps(){ + validate(); + if(!weapons) weapons = ({}); + foreach(string weapsdir in weap_dirs){ + mixed wdir = get_dir(weapsdir+"/"); + if(!wdir || !sizeof(wdir)) continue; + foreach(string weapfile in wdir){ + string loadee = weapsdir+"/"+weapfile; + weapons += ({ loadee }); + call_out("loadthing", 0, loadee); + } + } + return 1; +} + +int loadarmors(){ + validate(); + if(!armors) armors = ({}); + foreach(string armsdir in armor_dirs){ + mixed adir = get_dir(armsdir+"/"); + if(!adir || !sizeof(adir)) continue; + foreach(string armorfile in adir){ + string loadee = armsdir+"/"+armorfile; + armors += ({ loadee }); + call_out("loadthing", 0, loadee); + } + } + return 1; +} + +int loadmeals(){ + validate(); + if(!meals) meals = ({}); + foreach(string mealsdir in meals_dirs){ + mixed mdir = get_dir(mealsdir+"/"); + if(!mdir || !sizeof(mdir)) continue; + foreach(string mealfile in mdir){ + string loadee = mealsdir+"/"+mealfile; + meals += ({ loadee }); + call_out("loadthing", 0, loadee); + } + } + return 1; +} + +int loaddoors(){ + validate(); + if(!doors) doors = ({}); + foreach(string doorsdir in doors_dirs){ + mixed ddir = get_dir(doorsdir+"/"); + if(!ddir || !sizeof(ddir)) continue; + foreach(string doorfile in ddir){ + string loadee = doorsdir+"/"+doorfile; + doors += ({ loadee }); + call_out("loadthing", 0, loadee); + } + } + return 1; +} + +int loadverbs(){ + validate(); + if(!verbs) verbs = ({}); + foreach(string verbsdir in verb_dirs){ + mixed vdir = get_dir(verbsdir+"/"); + if(!vdir || !sizeof(vdir)) continue; + foreach(string verbfile in vdir){ + string loadee = verbsdir+"/"+verbfile; + verbs += ({ loadee }); + call_out("loadthing", 0, loadee); + } + } + return 1; +} + +int loadcmds(){ + validate(); + if(!cmds) cmds = ({}); + foreach(string cmdsdir in cmd_dirs){ + mixed cdir = get_dir(cmdsdir+"/"); + if(!cdir || !sizeof(cdir)) continue; + foreach(string cmdfile in cdir){ + string loadee = cmdsdir+"/"+cmdfile; + cmds += ({ loadee }); + call_out("loadthing", 0, loadee); + } + } + return 1; +} + +int loaddaemons(){ + validate(); + if(!daemons) daemons = ({}); + foreach(string daemonsdir in daemon_dirs){ + foreach(string daemonfile in get_dir(daemonsdir+"/")){ + string loadee = daemonsdir+"/"+daemonfile; + daemons += ({ loadee }); + call_out("loadthing", 0, loadee); + } + } + return 1; +} + +int loadlibs(){ + validate(); + if(!libs) libs = ({}); + foreach(string libsdir in lib_dirs){ + foreach(string libfile in get_dir(libsdir+"/")){ + string loadee = libsdir+"/"+libfile; + libs += ({ loadee }); + call_out("loadthing", 0, loadee); + } + } + return 1; +} + +int loadpowers(){ + validate(); + if(!powers) powers = ({}); + foreach(string powersdir in powers_dirs){ + foreach(string powerfile in get_dir(powersdir+"/")){ + string loadee = powersdir+"/"+powerfile; + powers += ({ loadee }); + call_out("loadthing", 0, loadee); + } + } + return 1; +} + +int loadthings(){ + validate(); + call_out("loaddoors",0); + call_out("loadmeals",1); + call_out("loadarmors",2); + call_out("loadweaps",3); + call_out("loadobs",4); + call_out("loadnpcs",5); + call_out("loadrooms",6); + return 1; +} + +int loadsys(){ + call_out("loadlibs",0); + call_out("loaddaemons",1); + call_out("loadcmds",2); + call_out("loadverbs",3); + call_out("loadpowers",4); + return 1; +} + +int loadall(){ + call_out("loadsys",0); + call_out("loadthings",10); + return 1; +} + +int stressload(string arg){ + int i; + if(arg) i = atoi(arg); + numstress = (i || 1); + tc("numnstress: "+numstress); + if(!sizeof(rooms)) call_out("loadrooms", 0); + if(!sizeof(npcs)) call_out("loadnpcs", 0); + if(sizeof(rooms) && sizeof(npcs)) this_object()->startstress(); + else call_out("startstress", 9); + return 1; +} + +int startstress(){ + object *newbatch = ({}); + object *targetrooms = filter(rooms, + (: last($1,2) == ".c" && last($1,9) != "furnace.c" && + $1->GetMedium() < 2 && !$1->GetProperty("no attack") :) ); + int victims; + tc("Starting stresstest, multiplier: "+numstress); + foreach(string npcfile in npcs){ + object npc; + int err, x = numstress; + if(last(npcfile,2) != ".c") continue; + while(x){ + err = 0; + npc = new(npcfile); + newbatch += ({ npc }); + while(!err){ + object where; + if(numstress < 11) reset_eval_cost(); + where = targetrooms[abs(random(sizeof(targetrooms))-1)]; + catch(err = npc->eventMove(where)); + } + x--; + } + } + newbatch = filter(newbatch, (: objectp($1) :) ); + victims = to_int(to_float(sizeof(newbatch)) * 0.005)+1; + tc("newbatch size: "+sizeof(newbatch)); + while(victims){ + object germ, who; + int err, batch = sizeof(newbatch); + if(batch){ + err = catch(germ = new("/domains/town/obj/rage")); + who = newbatch[abs(random(batch))]; + if(who && germ) germ->eventInfect(who); + victims--; + } + } + npcs->SetWanderSpeed(1); + npcs->SetPermitLoad(1); + return 1; +} + +int eventDestruct(){ + return ::eventDestruct(); +} + +int yeik2(string str){ + int dirty; + validate(); + if(str == "dirty") dirty = 1; + if(str){ + string file, what = "/lib/blank"; + int on=1, clone, i=2100000000; + object ob=new(what); + write("Starting the bullshit. ob: "+identify(ob)); + sscanf(file_name(ob), "%s#%d", file, clone); + if(!dirty) destruct(ob); + if(on){ + call_out("yeik2", 2); + } + if(!on){ + return; + } + while(i) { + i--; + ob =new(what); + sscanf(file_name(ob), "%s#%d", file, clone); + if(!dirty) destruct(ob); + } + } + else { + write("Stopping the bullshit."); + } + return 1; +} + +int vargon(string str){ + int waves, win; + validate(); + win = sscanf(str,"%d",waves); + if(!win || !waves) waves = 5; + for(win=waves;win > 0;win--){ + INTERMUD_D->RawSend(({ "channel-m", 5, mud_name(), + this_player()->GetKeyName(), 0, 0, "coffee", + this_player()->GetKeyName(), win+" Yes have some." })); + } + return waves; +} + +int commcheck(){ + int i, count = 20; + validate(); + write("Testing comms..."); + write2("\n"); + i = time_expression { + while(count){ + count--; + reset_eval_cost(); + write2("."); + flush_messages(); + } + }; + write2("\n\n"); + write("Microseconds: "+i); + return 1; +} + +int perfcheck(string foo){ + int sauber = 1, i, count = 1000000; + validate(); + write("Testing performance..."); + write("Recorded perfscore: "+MASTER_D->GetPerformanceScore()); + if(sizeof(foo)){ + int tmp = atoi(foo); + sauber = 0; + if(tmp) count = tmp; + } + if(sauber){ + i = time_expression { + while(count){ + count--; + } + }; + } + else { + i = time_expression { + while(count){ + count--; + } + }; + } + write("Microseconds: "+i); + return 1; +} diff --git a/lib/secure/room/arch.c b/lib/secure/room/arch.c new file mode 100644 index 0000000..27354df --- /dev/null +++ b/lib/secure/room/arch.c @@ -0,0 +1,210 @@ +#include +#include +#include + +#ifndef DISABLE_IMC2 +#define DISABLE_IMC2 0 +#endif + +inherit LIB_ROOM; + +int imud_enabled = 0; +string gname; +string *ulist = ({}); +mapping umap = ([]); + +void validate(){ + if(!this_player() || !archp(this_player())){ + error("No."); + } +} + +int ReceiveObs(object ob){ + string bname = base_name(ob); + umap[bname] = (umap[bname] + 1); + return 0; +} + +string ReadScreen(){ + string *base_names = ({}); + string ret = "Top loaded objects:\n"; + int hbs, hbs2, rooms, npcs, meminf; + mixed *foo = ({}); + object *floods = ({}); + validate(); + floods = objects( (: (base_name($1) == LIB_FLOW || inherits(LIB_FLOW, $1)) + && clonep($1) :) ); + ulist = ({}); + umap = ([]); + if(sizeof(objects()) < 8192){ + foo = objects( (: ReceiveObs($1) :) ); + ulist = ({}); + foreach(mixed key, mixed val in umap){ + reset_eval_cost(); + ulist += ({ ({ val, key }) }); + } + ulist = sort_array(ulist, -1)[0..9]; + if(sizeof(ulist)){ + foreach(mixed element in ulist){ + ret += element[1]+" "+element[0]+"\n"; + } + } + } + else { + ret += "Too many objects to sort.\n"; + } + rooms = sizeof(objects( (: inherits(LIB_ROOM, $1) :) ) ); + npcs = sizeof(objects( (: inherits(LIB_NPC, $1) && clonep($1):) ) ); + hbs = sizeof(filter( heart_beats(), (: !living($1) :) )); + hbs2 = sizeof(filter( heart_beats(), (: !living($1) && + !inherits(LIB_ROOM, $1) :) )); + ret += "\nTotal number of loaded objects: "+sizeof(objects())+"\n"; + ret += "Loaded rooms: "+rooms+"\n"; + ret += "Cloned NPC's: "+npcs+"\n\n"; + ret += "Total number of connected users: "+sizeof(users())+"\n"; + ret += "Pending callouts: "+sizeof(call_out_info())+"\n"; + ret += "File descriptors in use: "+ + (sizeof(explode(dump_file_descriptors(),"\n"))-3)+"\n"; + ret += "Nonlivings with heartbeats: "+hbs+", !rooms: "+hbs2+"\n"; + ret += "Flood objects: "+sizeof(floods)+"\n"; + if(true()){ + string tmp; + meminf = memory_info()/1000000; + if(!meminf) tmp = "less than 1 meg"; + else tmp = meminf+" megs"; + if(meminf){ + ret += "Memory in use (allocated memory will be higher): "+ + tmp+"\n"; + } + } + return ret; +} + +string eventReadScreen(){ + validate(); + return unguarded( (: ReadScreen :) ); +} + +mixed eventReadPrintout(){ + return read_file("/doc/old/the_beginning.txt"); +} + +void SetImud(int i){ + if(!i) i = 0; + imud_enabled = i; +} + +int GetImud(){ + return imud_enabled; +} + +string SignRead(){ + string ret = ""; + + if(!INTERMUD_D->GetEnabled()){ + ret += "\"I3 connection: %^B_BLACK%^%^BOLD%^WHITE%^DISABLED%^RESET%^, "; + } + else if(INTERMUD_D->GetConnectedStatus()) + ret += "\"I3 connection: %^BOLD%^GREEN%^ONLINE%^RESET%^, "; + else ret += "\"I3 connection: %^BOLD%^RED%^OFFLINE%^RESET%^, "; + + switch (IMC2_D->getonline()) { + case 1: + ret += "IMC2: %^BOLD%^GREEN%^ONLINE%^RESET%^\""; + break; + case 2: + if(!IMC2_D->GetEnabled()){ + ret += "IMC2: %^B_BLACK%^%^BOLD%^WHITE%^DISABLED%^RESET%^\""; + } + else { + ret += "IMC2: %^BOLD%^YELLOW%^WAITING FOR ACCEPTANCE%^RESET%^\""; + } + break; + case 3: + ret += "IMC2: %^BOLD%^RED%^OFFLINE: CONNECT ERROR%^RESET%^\""; + break; + case 4: + ret += "IMC2: %^BOLD%^RED%^OFFLINE: HUB DOWN%^RESET%^\""; + break; + case 5: + ret += "IMC2: %^BOLD%^RED%^OFFLINE: BANNED%^RESET%^\""; + break; + default: + ret += "IMC2: %^BOLD%^RED%^OFFLINE%^RESET%^\""; + break; + } + return ret; +} + +string LongDesc(){ + string desc = "This is a polished antiseptic room composed of some "+ + "white gleaming material. There is a viewscreen on a wall here, "+ + "with a control panel alongside it. "+ + "A long printout hangs from the panel." + "\nThe network troubleshooting room is down from here."; + desc += "\nA sign on the wall reads: "+SignRead(); + return desc; +} + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Arch Room"); + SetLong( (: LongDesc :) ); + SetItems( ([ ({"wall","walls"}) : "The walls seem composed " + "of some advanced polymer. They are extremely clean and highly " + "polished.", + "room" : "This looks like it might be the control room " + "for the mud.", + //({"screen","viewscreen"}) : "This is a display screen of some sort.", + ({"screen","viewscreen"}) : (: eventReadScreen :) , + ({"printout"}) : (: eventReadPrintout :) , + ({"sign"}) : "A sign you can read.", + ({"panel","control panel"}): "This seems to be the main control " + "panel for the mud. It contains a bewildering array of " + "keypads, but the most prominent feature of the control panel " + "is a metallic plate in its center, shaped in the form of a " + "human hand.", + ({"camera","hal","HAL"}) : "This is the rectangular faceplate of " + "a camera mounted within the wall. On the upper end of the " + "rectangle is a stamped label. On the lower end is the lens, " + "which has at its center a glowing red light.", + ({"label","stamped label"}) : "A stamped metal label. The label " + "reads: 'HAL 9000'.", + ({"plate","metallic plate","identification plate"}) : "This " + "appears to be an identification plate of some sort, designed " + "to accomodate a human hand.", + "portal" : "A portal to another place." ]) ); + SetExits( ([ + "north" : "/domains/default/room/wiz_hall", + "down" : "/secure/room/network.c", + ]) ); + SetEnters( ([ + ]) ); + SetProperties(([ + "no peer" : 1, + ])); + SetRead("screen", (: eventReadScreen :) ); + SetRead("printout", (: eventReadPrintout :) ); + SetRead("sign", (: SignRead :) ); + + SetListen("default", "You can faintly hear a low hum coming from the walls."); + SetListen( ({"wall","walls"}), "You hear a low throbbing sound, as if from machinery."); + SetInventory( ([ + "/secure/obj/arch_board" : 1, + ]) ); + SetCoordinates("-2,2,0"); +} +int CanReceive(object ob) { + if( !archp(ob) && base_name(ob) != "/secure/obj/arch_board"){ + message("info","The arch room is available only to "+ + "admins, sorry.",ob); + return 0; + } + return 1; +} +void init(){ + ::init(); +} diff --git a/lib/secure/room/network.c b/lib/secure/room/network.c new file mode 100644 index 0000000..2687a3f --- /dev/null +++ b/lib/secure/room/network.c @@ -0,0 +1,33 @@ +#include +#include +inherit LIB_ROOM; + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Network room"); + SetLong("This is where all network messages go. It is an extremely " + "noisy and uncomfortable location, just like network rooms all around " + "the world. It is here for debugging and troubleshooting purposes, so " + "if that's not what you're doing, you should probably leave. " + "The arch room is above. The router room is south. " + "The catch_tell room is east."); + SetExits( ([ + "south" : "/secure/room/router", + "up" : "/secure/room/arch", + "east" : "/domains/default/room/catchtell.c", + ]) ); + +} +int CanReceive(object ob) { + if( !archp(ob) ){ + message("info","The network room is available only to "+ + "admins, sorry.",ob); + return 0; + } + return 1; +} +void init(){ + ::init(); +} diff --git a/lib/secure/room/router.c b/lib/secure/room/router.c new file mode 100644 index 0000000..e490d84 --- /dev/null +++ b/lib/secure/room/router.c @@ -0,0 +1,221 @@ +#include +#include +#include +inherit LIB_ROOM; + +int ftp, hftp, http, rcp, i3, oob; + +string LongDesc(){ + string ret = "This room is like the network room to its north, " + "but it receives messages from the various network servers " + "that this mud can run. If this mud does not serve as a " + "network server, this room should be quiet. Otherwise " + "this may be the noisiest damn room on your mud.\n"; + ret += "FTP server monitoring: "+(ftp?"%^GREEN%^online%^RESET%^":"%^RED%^OFFLINE%^RESET%^")+"\n"; + ret += "HFTP server monitoring: "+(hftp?"%^GREEN%^online%^RESET%^":"%^RED%^OFFLINE%^RESET%^")+"\n"; + ret += "HTTP server monitoring: "+(http?"%^GREEN%^online%^RESET%^":"%^RED%^OFFLINE%^RESET%^")+"\n"; + ret += "RCP server monitoring: "+(rcp?"%^GREEN%^online%^RESET%^":"%^RED%^OFFLINE%^RESET%^")+"\n"; + ret += "I3 server monitoring: "+(i3?"%^GREEN%^online%^RESET%^":"%^RED%^OFFLINE%^RESET%^")+"\n"; + ret += "OOB server monitoring: "+(i3?"%^GREEN%^online%^RESET%^":"%^RED%^OFFLINE%^RESET%^")+"\n"; + ret += "\nTo enable server monitoring, you may, for example, type:\n" + "i3 on\n" + "ftp on\n" + "hftp on\n" + "http on\n" + "rcp on\n" + "oob on\n"; + return ret; +} + +static void create() { + object ob; + i3 = 1; + oob = 1; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Server monitoring room"); + SetLong( (: LongDesc :) ); + SetExits(([ + "north" : "/secure/room/network", + ])); +} + +int CanReceive(object ob) { + if( !archp(ob) ){ + message("info","The server room is available only to "+ + "admins, sorry.",ob); + return 0; + } + return 1; +} + +varargs int eventPrint(string msg, mixed arg2, mixed arg3){ + if(arg2 == MSG_FTP && !ftp) return 0; + if(arg2 == MSG_HFTP && !hftp) return 0; + if(arg2 == MSG_HTTP && !http) return 0; + if(arg2 == MSG_RCP && !rcp) return 0; + if(arg2 == MSG_I3 && !i3) return 0; + if(arg2 == MSG_OOB && !oob) return 0; + return ::eventPrint(msg, arg2, arg3); +} + +void init(){ + ::init(); + add_action("ListenFTP","ftp"); + add_action("ListenHFTP","hftp"); + add_action("ListenHTTP","http"); + add_action("ListenRCP","rcp"); + add_action("ListenI3","i3"); + add_action("ListenOOB","oob"); +} + +int ListenI3(string str){ + if(!str || (str != "on" && str != "off")){ + write("Please specify whether you want it on or off."); + return 1; + } + if(str == "on"){ + if(i3){ + write("This room is already receiving i3 data."); + return 1; + } + write(capitalize(this_player()->GetKeyName())+" enables i3 data monitoring."); + say("You enable i3 data monitoring."); + i3 = 1; + return 1; + } + if(!i3){ + write("This room is already blocking i3 data."); + return 1; + } + write(capitalize(this_player()->GetKeyName())+" disables i3 data monitoring."); + say("You disable i3 data monitoring."); + i3 = 0; + return 1; +} + +int ListenFTP(string str){ + if(!str || (str != "on" && str != "off")){ + write("Please specify whether you want it on or off."); + return 1; + } + if(str == "on"){ + if(ftp){ + write("This room is already receiving ftp data."); + return 1; + } + write(capitalize(this_player()->GetKeyName())+" enables ftp data monitoring."); + say("You enable ftp data monitoring."); + ftp = 1; + return 1; + } + if(!ftp){ + write("This room is already blocking ftp data."); + return 1; + } + write(capitalize(this_player()->GetKeyName())+" disables ftp data monitoring."); + say("You disable ftp data monitoring."); + ftp = 0; + return 1; +} + +int ListenHFTP(string str){ + if(!str || (str != "on" && str != "off")){ + write("Please specify whether you want it on or off."); + return 1; + } + if(str == "on"){ + if(hftp){ + write("This room is already receiving hftp data."); + return 1; + } + write(capitalize(this_player()->GetKeyName())+" enables hftp data monitoring."); + say("You enable hftp data monitoring."); + hftp = 1; + return 1; + } + if(!hftp){ + write("This room is already blocking hftp data."); + return 1; + } + write(capitalize(this_player()->GetKeyName())+" disables hftp data monitoring."); + say("You disable hftp data monitoring."); + hftp = 0; + return 1; +} + +int ListenHTTP(string str){ + if(!str || (str != "on" && str != "off")){ + write("Please specify whether you want it on or off."); + return 1; + } + if(str == "on"){ + if(http){ + write("This room is already receiving http data."); + return 1; + } + write(capitalize(this_player()->GetKeyName())+" enables http data monitoring."); + say("You enable http data monitoring."); + http = 1; + return 1; + } + if(!http){ + write("This room is already blocking http data."); + return 1; + } + write(capitalize(this_player()->GetKeyName())+" disables http data monitoring."); + say("You disable http data monitoring."); + http = 0; + return 1; +} + +int ListenRCP(string str){ + if(!str || (str != "on" && str != "off")){ + write("Please specify whether you want it on or off."); + return 1; + } + if(str == "on"){ + if(rcp){ + write("This room is already receiving rcp data."); + return 1; + } + write(capitalize(this_player()->GetKeyName())+" enables rcp data monitoring."); + say("You enable rcp data monitoring."); + rcp = 1; + return 1; + } + if(!rcp){ + write("This room is already blocking rcp data."); + return 1; + } + write(capitalize(this_player()->GetKeyName())+" disables rcp data monitoring."); + say("You disable rcp data monitoring."); + rcp = 0; + return 1; +} + +int ListenOOB(string str){ + if(!str || (str != "on" && str != "off")){ + write("Please specify whether you want it on or off."); + return 1; + } + if(str == "on"){ + if(oob){ + write("This room is already receiving oob data."); + return 1; + } + write(capitalize(this_player()->GetKeyName())+" enables oob data monitoring."); + say("You enable oob data monitoring."); + oob = 1; + return 1; + } + if(!oob){ + write("This room is already blocking oob data."); + return 1; + } + write(capitalize(this_player()->GetKeyName())+" disables oob data monitoring."); + say("You disable oob data monitoring."); + oob = 0; + return 1; +} diff --git a/lib/secure/save/backup/config.1599106166 b/lib/secure/save/backup/config.1599106166 new file mode 100644 index 0000000..ecc923c --- /dev/null +++ b/lib/secure/save/backup/config.1599106166 @@ -0,0 +1,98 @@ +#ifndef s_config_h +#define s_config_h +#define DEFAULT_PROMPT "> " +#define HOST_IP "127.0.0.1" +#define MUD_STATUS "mudlib development" +#define ADMIN_EMAIL "babylon_horuv@zoho.com" +#define DEBUGGER "babylon" +#define LOCAL_NEWS_PREFIX "nm" +#define MUD_IS_LOCKED 0 +#define AUTO_WIZ 0 +#define RESTRICTED_INTERMUD 0 +#define DISABLE_INTERMUD 0 +#define DISABLE_IMC2 0 +#define MINUTES_REBOOT_WARNING 20 +#define TIME_TO_RESET 3600 +#define RESET_ALL 0 +#define GMT_OFFSET -32000 +#define LOCAL_TIME 0 +#define EXTRA_TIME_OFFSET 0 +#define MAX_LOG_SIZE 150000 +#define MAX_NET_DEAD_TIME 1800 +#define MIN_HISTORY_SIZE 50 +#define MAX_HISTORY_SIZE 100 +#define LOGON_TIMEOUT 360 +#define IDLE_TIMEOUT 180000 +#define LINK_WAIT_PERIOD 1800 +#define MAX_PASSWORD_TRIES 3 +#define MIN_USER_NAME_LENGTH 2 +#define MAX_USER_NAME_LENGTH 15 +#define MAX_USER_CAP_NAME_LENGTH 20 +#define LOCKED_ACCESS_ALLOWED ({ "SECURE", "ASSIST", "ELDER", "TEST" }) +#define SUPPORTED_CLIENTS ({ "amcp", "amcp/1.1" }) +#define HOUR_LENGTH 1200 +#define DAY_LENGTH 20 +#define MAX_NEWBIE_LEVEL 0 +#define AUTOSAVE_TIME 200 +#define MORTAL_POSITIONS ({ "player", "high mortal", "ambassador" }) +#define DEFAULT_GRAVITY 1.0 +#define DEFAULT_ITEM_MESSAGE "You do not see that here." +#define RESET_INTERMUD 0 +#define ENGLISH_ONLY 0 +#define HUMANS_ONLY 0 +#define SEVERABLE_LIMBS 1 +#define CLASS_SELECTION 0 +#define PINGING_MUDS ({}) +#define PING_INTERVAL 290 +#define ENABLE_ENCUMBRANCE 0 +#define GLOBAL_MONITOR 0 +#define PLAYER_KILL 0 +#define NPC_CATCH_TELL_DEBUG 0 +#define SAME_IP_MAX 4 +#define COMPAT_MODE 1 +#define RETAIN_ON_QUIT 1 +#define FAST_COMBAT 1 +#define MAX_COMMANDS_PER_SECOND 10 +#define DEFAULT_PARSING 0 +#define CALL_OUT_LOGGING 0 +#define EVENTS_LOGGING 0 +#define DISABLE_REBOOTS 0 +#define BARE_EXITS 1 +#define COMMAND_MATCHING 1 +#define OBJECT_MATCHING 1 +#define LIVEUPGRADE_SERVER "Dead Souls" +#define CARRIAGE_RETURN "\r" +#define OLD_STYLE_PLURALS 1 +#define NM_STYLE_EXITS 0 +#define WEB_SOURCE_IP "204.209.44.12" +#define WEB_SOURCE_NAME "lpmuds.net" +#define DESTRUCT_LOGGING 0 +#define ROUTER_NAME "Alpha" +#define IRN_PASSWORD "Alpha" +#define IRN_PASSWORD1 "Bravo" +#define IRN_PASSWORD2 "Charlie" +#define IRN_PASSWORD3 "Delta" +#define ROUTER_TESTING 1 +#define SEFUN_PLURALIZE 0 +#define LOG_REMOTE_CHANS 0 +#define LOG_LOCAL_CHANS 1 +#define ENABLE_CGI 0 +#define WWW_DIR_LIST 0 +#define ENABLE_CREWEB 0 +#define F_TERMINAL_COLOR 1 +#define MAX_CALL_OUTS 750 +#define REQUIRE_QUESTING 1 +#define AUTO_ADVANCE 1 +#define MAX_INVENTORY_SIZE 2048 +#define MAX_ATTACKS_PER_HB 40 +#define MEMUSE_SOFT_LIMIT 0 +#define MEMUSE_HARD_LIMIT 0 +#define MAX_USERS 0 +#define MIN_PERF 400 +#define MINIMAP 1 +#define WIZMAP 1 +#define GRID 1 +#define ENABLE_INSTANCES 0 +#define CED_DISABLED 1 + +#endif /* s_config_h */ diff --git a/lib/secure/save/backup/config.1599277658 b/lib/secure/save/backup/config.1599277658 new file mode 100644 index 0000000..ecc923c --- /dev/null +++ b/lib/secure/save/backup/config.1599277658 @@ -0,0 +1,98 @@ +#ifndef s_config_h +#define s_config_h +#define DEFAULT_PROMPT "> " +#define HOST_IP "127.0.0.1" +#define MUD_STATUS "mudlib development" +#define ADMIN_EMAIL "babylon_horuv@zoho.com" +#define DEBUGGER "babylon" +#define LOCAL_NEWS_PREFIX "nm" +#define MUD_IS_LOCKED 0 +#define AUTO_WIZ 0 +#define RESTRICTED_INTERMUD 0 +#define DISABLE_INTERMUD 0 +#define DISABLE_IMC2 0 +#define MINUTES_REBOOT_WARNING 20 +#define TIME_TO_RESET 3600 +#define RESET_ALL 0 +#define GMT_OFFSET -32000 +#define LOCAL_TIME 0 +#define EXTRA_TIME_OFFSET 0 +#define MAX_LOG_SIZE 150000 +#define MAX_NET_DEAD_TIME 1800 +#define MIN_HISTORY_SIZE 50 +#define MAX_HISTORY_SIZE 100 +#define LOGON_TIMEOUT 360 +#define IDLE_TIMEOUT 180000 +#define LINK_WAIT_PERIOD 1800 +#define MAX_PASSWORD_TRIES 3 +#define MIN_USER_NAME_LENGTH 2 +#define MAX_USER_NAME_LENGTH 15 +#define MAX_USER_CAP_NAME_LENGTH 20 +#define LOCKED_ACCESS_ALLOWED ({ "SECURE", "ASSIST", "ELDER", "TEST" }) +#define SUPPORTED_CLIENTS ({ "amcp", "amcp/1.1" }) +#define HOUR_LENGTH 1200 +#define DAY_LENGTH 20 +#define MAX_NEWBIE_LEVEL 0 +#define AUTOSAVE_TIME 200 +#define MORTAL_POSITIONS ({ "player", "high mortal", "ambassador" }) +#define DEFAULT_GRAVITY 1.0 +#define DEFAULT_ITEM_MESSAGE "You do not see that here." +#define RESET_INTERMUD 0 +#define ENGLISH_ONLY 0 +#define HUMANS_ONLY 0 +#define SEVERABLE_LIMBS 1 +#define CLASS_SELECTION 0 +#define PINGING_MUDS ({}) +#define PING_INTERVAL 290 +#define ENABLE_ENCUMBRANCE 0 +#define GLOBAL_MONITOR 0 +#define PLAYER_KILL 0 +#define NPC_CATCH_TELL_DEBUG 0 +#define SAME_IP_MAX 4 +#define COMPAT_MODE 1 +#define RETAIN_ON_QUIT 1 +#define FAST_COMBAT 1 +#define MAX_COMMANDS_PER_SECOND 10 +#define DEFAULT_PARSING 0 +#define CALL_OUT_LOGGING 0 +#define EVENTS_LOGGING 0 +#define DISABLE_REBOOTS 0 +#define BARE_EXITS 1 +#define COMMAND_MATCHING 1 +#define OBJECT_MATCHING 1 +#define LIVEUPGRADE_SERVER "Dead Souls" +#define CARRIAGE_RETURN "\r" +#define OLD_STYLE_PLURALS 1 +#define NM_STYLE_EXITS 0 +#define WEB_SOURCE_IP "204.209.44.12" +#define WEB_SOURCE_NAME "lpmuds.net" +#define DESTRUCT_LOGGING 0 +#define ROUTER_NAME "Alpha" +#define IRN_PASSWORD "Alpha" +#define IRN_PASSWORD1 "Bravo" +#define IRN_PASSWORD2 "Charlie" +#define IRN_PASSWORD3 "Delta" +#define ROUTER_TESTING 1 +#define SEFUN_PLURALIZE 0 +#define LOG_REMOTE_CHANS 0 +#define LOG_LOCAL_CHANS 1 +#define ENABLE_CGI 0 +#define WWW_DIR_LIST 0 +#define ENABLE_CREWEB 0 +#define F_TERMINAL_COLOR 1 +#define MAX_CALL_OUTS 750 +#define REQUIRE_QUESTING 1 +#define AUTO_ADVANCE 1 +#define MAX_INVENTORY_SIZE 2048 +#define MAX_ATTACKS_PER_HB 40 +#define MEMUSE_SOFT_LIMIT 0 +#define MEMUSE_HARD_LIMIT 0 +#define MAX_USERS 0 +#define MIN_PERF 400 +#define MINIMAP 1 +#define WIZMAP 1 +#define GRID 1 +#define ENABLE_INSTANCES 0 +#define CED_DISABLED 1 + +#endif /* s_config_h */ diff --git a/lib/secure/save/backup/config.1599371141 b/lib/secure/save/backup/config.1599371141 new file mode 100644 index 0000000..3e2feb5 --- /dev/null +++ b/lib/secure/save/backup/config.1599371141 @@ -0,0 +1,97 @@ +#ifndef s_config_h +#define s_config_h +#define DEFAULT_PROMPT "> " +#define HOST_IP "127.0.0.1" +#define MUD_STATUS "mudlib development" +#define ADMIN_EMAIL "babylon_horuv@zoho.com" +#define DEBUGGER "babylon" +#define LOCAL_NEWS_PREFIX "nm" +#define MUD_IS_LOCKED 0 +#define AUTO_WIZ 0 +#define RESTRICTED_INTERMUD 0 +#define DISABLE_INTERMUD 0 +#define DISABLE_IMC2 1 +#define MINUTES_REBOOT_WARNING 20 +#define TIME_TO_RESET 3600 +#define RESET_ALL 0 +#define GMT_OFFSET -32000 +#define LOCAL_TIME 0 +#define EXTRA_TIME_OFFSET 0 +#define MAX_LOG_SIZE 150000 +#define MAX_NET_DEAD_TIME 1800 +#define MIN_HISTORY_SIZE 50 +#define MAX_HISTORY_SIZE 100 +#define LOGON_TIMEOUT 360 +#define IDLE_TIMEOUT 180000 +#define LINK_WAIT_PERIOD 1800 +#define MAX_PASSWORD_TRIES 3 +#define MIN_USER_NAME_LENGTH 2 +#define MAX_USER_NAME_LENGTH 15 +#define MAX_USER_CAP_NAME_LENGTH 20 +#define LOCKED_ACCESS_ALLOWED ({ "SECURE", "ASSIST", "ELDER", "TEST" }) +#define SUPPORTED_CLIENTS ({ "amcp", "amcp/1.1" }) +#define HOUR_LENGTH 1200 +#define DAY_LENGTH 20 +#define MAX_NEWBIE_LEVEL 0 +#define AUTOSAVE_TIME 200 +#define MORTAL_POSITIONS ({ "player", "high mortal", "ambassador" }) +#define DEFAULT_GRAVITY 1.0 +#define DEFAULT_ITEM_MESSAGE "You do not see that here." +#define RESET_INTERMUD 0 +#define ENGLISH_ONLY 0 +#define HUMANS_ONLY 0 +#define SEVERABLE_LIMBS 1 +#define CLASS_SELECTION 0 +#define PINGING_MUDS ({}) +#define PING_INTERVAL 290 +#define ENABLE_ENCUMBRANCE 0 +#define GLOBAL_MONITOR 0 +#define PLAYER_KILL 0 +#define NPC_CATCH_TELL_DEBUG 0 +#define SAME_IP_MAX 4 +#define COMPAT_MODE 1 +#define RETAIN_ON_QUIT 1 +#define FAST_COMBAT 1 +#define MAX_COMMANDS_PER_SECOND 10 +#define DEFAULT_PARSING 0 +#define CALL_OUT_LOGGING 0 +#define EVENTS_LOGGING 0 +#define DISABLE_REBOOTS 0 +#define BARE_EXITS 1 +#define COMMAND_MATCHING 1 +#define OBJECT_MATCHING 1 +#define LIVEUPGRADE_SERVER "Dead Souls" +#define CARRIAGE_RETURN "\r" +#define OLD_STYLE_PLURALS 1 +#define NM_STYLE_EXITS 0 +#define WEB_SOURCE_IP "204.209.44.12" +#define WEB_SOURCE_NAME "lpmuds.net" +#define DESTRUCT_LOGGING 0 +#define ROUTER_NAME "Alpha" +#define IRN_PASSWORD "Alpha" +#define IRN_PASSWORD1 "Bravo" +#define IRN_PASSWORD2 "Charlie" +#define IRN_PASSWORD3 "Delta" +#define ROUTER_TESTING 1 +#define SEFUN_PLURALIZE 0 +#define LOG_REMOTE_CHANS 0 +#define LOG_LOCAL_CHANS 1 +#define ENABLE_CGI 0 +#define WWW_DIR_LIST 0 +#define ENABLE_CREWEB 0 +#define F_TERMINAL_COLOR 1 +#define MAX_CALL_OUTS 750 +#define REQUIRE_QUESTING 1 +#define AUTO_ADVANCE 1 +#define MAX_INVENTORY_SIZE 2048 +#define MAX_ATTACKS_PER_HB 40 +#define MEMUSE_SOFT_LIMIT 0 +#define MEMUSE_HARD_LIMIT 0 +#define MAX_USERS 0 +#define MIN_PERF 400 +#define MINIMAP 1 +#define WIZMAP 1 +#define GRID 1 +#define ENABLE_INSTANCES 0 +#define CED_DISABLED 1 +#endif /* s_config_h */ diff --git a/lib/secure/save/backup/config.6666.bak b/lib/secure/save/backup/config.6666.bak new file mode 100644 index 0000000..f609a50 --- /dev/null +++ b/lib/secure/save/backup/config.6666.bak @@ -0,0 +1,98 @@ +#ifndef s_config_h +#define s_config_h +#define DEFAULT_PROMPT "> " +#define HOST_IP "127.0.0.1" +#define MUD_STATUS "mudlib development" +#define ADMIN_EMAIL "babylon_horuv@zoho.com" +#define DEBUGGER "DEBUG_NAME" +#define LOCAL_NEWS_PREFIX "nm" +#define MUD_IS_LOCKED 0 +#define AUTO_WIZ 0 +#define RESTRICTED_INTERMUD 0 +#define DISABLE_INTERMUD 0 +#define DISABLE_IMC2 0 +#define MINUTES_REBOOT_WARNING 20 +#define TIME_TO_RESET 3600 +#define RESET_ALL 0 +#define GMT_OFFSET -32000 +#define LOCAL_TIME 0 +#define EXTRA_TIME_OFFSET 0 +#define MAX_LOG_SIZE 150000 +#define MAX_NET_DEAD_TIME 1800 +#define MIN_HISTORY_SIZE 50 +#define MAX_HISTORY_SIZE 100 +#define LOGON_TIMEOUT 360 +#define IDLE_TIMEOUT 180000 +#define LINK_WAIT_PERIOD 1800 +#define MAX_PASSWORD_TRIES 3 +#define MIN_USER_NAME_LENGTH 2 +#define MAX_USER_NAME_LENGTH 15 +#define MAX_USER_CAP_NAME_LENGTH 20 +#define LOCKED_ACCESS_ALLOWED ({ "SECURE", "ASSIST", "ELDER", "TEST" }) +#define SUPPORTED_CLIENTS ({ "amcp", "amcp/1.1" }) +#define HOUR_LENGTH 1200 +#define DAY_LENGTH 20 +#define MAX_NEWBIE_LEVEL 0 +#define AUTOSAVE_TIME 200 +#define MORTAL_POSITIONS ({ "player", "high mortal", "ambassador" }) +#define DEFAULT_GRAVITY 1.0 +#define DEFAULT_ITEM_MESSAGE "You do not see that here." +#define RESET_INTERMUD 0 +#define ENGLISH_ONLY 0 +#define HUMANS_ONLY 0 +#define SEVERABLE_LIMBS 1 +#define CLASS_SELECTION 0 +#define PINGING_MUDS ({}) +#define PING_INTERVAL 290 +#define ENABLE_ENCUMBRANCE 0 +#define GLOBAL_MONITOR 0 +#define PLAYER_KILL 0 +#define NPC_CATCH_TELL_DEBUG 0 +#define SAME_IP_MAX 4 +#define COMPAT_MODE 1 +#define RETAIN_ON_QUIT 1 +#define FAST_COMBAT 1 +#define MAX_COMMANDS_PER_SECOND 10 +#define DEFAULT_PARSING 0 +#define CALL_OUT_LOGGING 0 +#define EVENTS_LOGGING 0 +#define DISABLE_REBOOTS 0 +#define BARE_EXITS 1 +#define COMMAND_MATCHING 1 +#define OBJECT_MATCHING 1 +#define LIVEUPGRADE_SERVER "Dead Souls" +#define CARRIAGE_RETURN "\r" +#define OLD_STYLE_PLURALS 1 +#define NM_STYLE_EXITS 0 +#define WEB_SOURCE_IP "204.209.44.12" +#define WEB_SOURCE_NAME "lpmuds.net" +#define DESTRUCT_LOGGING 0 +#define ROUTER_NAME "Alpha" +#define IRN_PASSWORD "Alpha" +#define IRN_PASSWORD1 "Bravo" +#define IRN_PASSWORD2 "Charlie" +#define IRN_PASSWORD3 "Delta" +#define ROUTER_TESTING 1 +#define SEFUN_PLURALIZE 0 +#define LOG_REMOTE_CHANS 0 +#define LOG_LOCAL_CHANS 1 +#define ENABLE_CGI 0 +#define WWW_DIR_LIST 0 +#define ENABLE_CREWEB 0 +#define F_TERMINAL_COLOR 1 +#define MAX_CALL_OUTS 750 +#define REQUIRE_QUESTING 1 +#define AUTO_ADVANCE 1 +#define MAX_INVENTORY_SIZE 2048 +#define MAX_ATTACKS_PER_HB 40 +#define MEMUSE_SOFT_LIMIT 0 +#define MEMUSE_HARD_LIMIT 0 +#define MAX_USERS 0 +#define MIN_PERF 400 +#define MINIMAP 1 +#define WIZMAP 1 +#define GRID 1 +#define ENABLE_INSTANCES 0 +#define CED_DISABLED 1 + +#endif /* s_config_h */ diff --git a/lib/secure/save/backup/config.orig b/lib/secure/save/backup/config.orig new file mode 100644 index 0000000..8ff2423 --- /dev/null +++ b/lib/secure/save/backup/config.orig @@ -0,0 +1,98 @@ +#ifndef s_config_h +#define s_config_h +#define DEFAULT_PROMPT "> " +#define HOST_IP "127.0.0.1" +#define MUD_STATUS "mudlib development" +#define ADMIN_EMAIL "admin@here" +#define DEBUGGER "DEBUG_NAME" +#define LOCAL_NEWS_PREFIX "nm" +#define MUD_IS_LOCKED 0 +#define AUTO_WIZ 0 +#define RESTRICTED_INTERMUD 0 +#define DISABLE_INTERMUD 0 +#define DISABLE_IMC2 0 +#define MINUTES_REBOOT_WARNING 20 +#define TIME_TO_RESET 3600 +#define RESET_ALL 0 +#define GMT_OFFSET -32000 +#define LOCAL_TIME 0 +#define EXTRA_TIME_OFFSET 0 +#define MAX_LOG_SIZE 150000 +#define MAX_NET_DEAD_TIME 1800 +#define MIN_HISTORY_SIZE 50 +#define MAX_HISTORY_SIZE 100 +#define LOGON_TIMEOUT 360 +#define IDLE_TIMEOUT 180000 +#define LINK_WAIT_PERIOD 1800 +#define MAX_PASSWORD_TRIES 3 +#define MIN_USER_NAME_LENGTH 2 +#define MAX_USER_NAME_LENGTH 15 +#define MAX_USER_CAP_NAME_LENGTH 20 +#define LOCKED_ACCESS_ALLOWED ({ "SECURE", "ASSIST", "ELDER", "TEST" }) +#define SUPPORTED_CLIENTS ({ "amcp", "amcp/1.1" }) +#define HOUR_LENGTH 1200 +#define DAY_LENGTH 20 +#define MAX_NEWBIE_LEVEL 0 +#define AUTOSAVE_TIME 200 +#define MORTAL_POSITIONS ({ "player", "high mortal", "ambassador" }) +#define DEFAULT_GRAVITY 1.0 +#define DEFAULT_ITEM_MESSAGE "You do not see that here." +#define RESET_INTERMUD 0 +#define ENGLISH_ONLY 0 +#define HUMANS_ONLY 0 +#define SEVERABLE_LIMBS 1 +#define CLASS_SELECTION 0 +#define PINGING_MUDS ({}) +#define PING_INTERVAL 290 +#define ENABLE_ENCUMBRANCE 0 +#define GLOBAL_MONITOR 0 +#define PLAYER_KILL 0 +#define NPC_CATCH_TELL_DEBUG 0 +#define SAME_IP_MAX 4 +#define COMPAT_MODE 1 +#define RETAIN_ON_QUIT 1 +#define FAST_COMBAT 1 +#define MAX_COMMANDS_PER_SECOND 10 +#define DEFAULT_PARSING 0 +#define CALL_OUT_LOGGING 0 +#define EVENTS_LOGGING 0 +#define DISABLE_REBOOTS 0 +#define BARE_EXITS 1 +#define COMMAND_MATCHING 1 +#define OBJECT_MATCHING 1 +#define LIVEUPGRADE_SERVER "Dead Souls" +#define CARRIAGE_RETURN "\r" +#define OLD_STYLE_PLURALS 1 +#define NM_STYLE_EXITS 0 +#define WEB_SOURCE_IP "204.209.44.12" +#define WEB_SOURCE_NAME "lpmuds.net" +#define DESTRUCT_LOGGING 0 +#define ROUTER_NAME "Alpha" +#define IRN_PASSWORD "Alpha" +#define IRN_PASSWORD1 "Bravo" +#define IRN_PASSWORD2 "Charlie" +#define IRN_PASSWORD3 "Delta" +#define ROUTER_TESTING 1 +#define SEFUN_PLURALIZE 0 +#define LOG_REMOTE_CHANS 0 +#define LOG_LOCAL_CHANS 1 +#define ENABLE_CGI 0 +#define WWW_DIR_LIST 0 +#define ENABLE_CREWEB 0 +#define F_TERMINAL_COLOR 1 +#define MAX_CALL_OUTS 750 +#define REQUIRE_QUESTING 1 +#define AUTO_ADVANCE 1 +#define MAX_INVENTORY_SIZE 2048 +#define MAX_ATTACKS_PER_HB 40 +#define MEMUSE_SOFT_LIMIT 0 +#define MEMUSE_HARD_LIMIT 0 +#define MAX_USERS 0 +#define MIN_PERF 400 +#define MINIMAP 1 +#define WIZMAP 1 +#define GRID 1 +#define ENABLE_INSTANCES 0 +#define CED_DISABLED 1 + +#endif /* s_config_h */ diff --git a/lib/secure/save/backup/groups.orig b/lib/secure/save/backup/groups.orig new file mode 100644 index 0000000..8bed49d --- /dev/null +++ b/lib/secure/save/backup/groups.orig @@ -0,0 +1,13 @@ +# Names are added to this file to determine groups. +# Groups should be named in all caps. +# The format is: +# (GROUP) name1:name2 + +(SECURE) ADMIN +(ASSIST) ADMIN +(ELDER) ADMIN +(TEST) ADMIN +(INTERMUD) ADMIN +(BUILDER) ADMIN +(TELNET) ADMIN +(EMOTES) ADMIN diff --git a/lib/secure/save/backup/imc2.orig b/lib/secure/save/backup/imc2.orig new file mode 100644 index 0000000..8a45fc8 --- /dev/null +++ b/lib/secure/save/backup/imc2.orig @@ -0,0 +1,1712 @@ +// Tim Johnson +// Started on May 1, 2004. +// Use this however you want. + +#include +#include +#include +#include +#include NETWORK_H +#include +#include +#include + +//Which IMC version you wish to support. +#define IMC_VERSION 2 + +// Connection data for Davion's server +// HostIP overrides HOSTNAME, in case the mud doesn't want to resolve addresses +//#define HOSTNAME "server01.mudbytes.net" +#ifndef IMCTESTING +#define HOSTPORT 5000 +#define HOSTIP "50.116.16.90" +#endif + +// Connection data for Davion's other server +// HostIP overrides HOSTNAME, in case the mud doesn't want to resolve addresses +//#define HOSTPORT 9000 +//#define HOSTIP "74.207.247.83" + +//This is the LPMuds.net experimental IMC2 server. If you are +//already connected to LPMuds.net intermud using Intermud-3, do +//not use the LPMuds.net IMC2 server. +#ifdef IMCTESTING +#define HOSTPORT 8888 +#define HOSTIP "97.107.133.86" +#endif + +// What name the network knows your mud as. Replace MUD_NAME with "whatever" if you want it to be different. +#define MUDNAME (imc2_mud_name()) + +// COMMAND_NAME is the command that people type to use this network. +#define COMMAND_NAME "imc2" + +// NETWORK_ID is what your mud calls this network. +// This is the prefix that comes up on all messages to identify the IMC2 network. +// Tells for example look like: +// NETWORK_ID- Tim@TimMUD tells you: hi +// Make it similar to the command name, so players will understand. +// **OUTDATED +#define NETWORK_ID "IMC2" + +// DATA_LOG is where packets are logged to. +// Turn IMC2_logging off when not working on the system, as it invades privacy. +// Comment this out to turn it off. +#define IMC2_LOGGING + +#ifndef LOG_IMC2 +#define DATA_LOG "/secure/log/intermud/imc2" +#else +#define DATA_LOG LOG_IMC2 +#endif + +// UNKNOWN_DATA_LOG is where unrecognized packets are logged to. +// I wrote handlers for all packets I know of, so this should only pick +// up tests and possibly if anyone is creating new packets. +#define UNKNOWN_DATA_LOG DATA_LOG + +// Your MUD's URL is shared with other muds when building the mud list. +// This you could also put this in your who reply. +#define URL "http://dead-souls.net" + +// ANNOUNCE_LOG is where network announcements get logged to. +// I suggest you keep this turned on. +// These announcements seem to be about channels being created and +// deleted, but may possibly have more. +#define ANNOUNCE_LOG "IMC2_ANNOUNCEMENTS" + +// How many lines you want the backlog to be. +#define BACKLOG_SIZE 20 + +// Minimum permission number for channel to be viewable on the web. +#define BACKLOG_WEB_LEVEL 0 + +// What's the file for the channel daemon? +#ifndef CHANNEL_BOT +#define CHANNEL_BOT CHAT_D +#endif +#ifndef STREAM +#define STREAM 1 +#endif +#ifndef EESUCCESS +#define EESUCCESS 1 /* Call was successful */ +#endif +#ifndef THIS_PLAYER +#define THIS_PLAYER this_player() +#endif +#ifndef FIND_PLAYER +#define FIND_PLAYER(x) find_player(x) +#endif +#ifndef GET_CAP_NAME +#define GET_CAP_NAME(x) replace_string(x->GetName()," ","") +#endif +#ifndef GET_NAME +#define GET_NAME(x) convert_name(x->GetName()) +#endif +#ifndef IMC2_MSG +#define IMC2_MSG(x,y) foreach(tmpstr in explode(x,"\n")){ message("IMC2",tmpstr,y); } +#endif +#ifndef GET_GENDER +#define GET_GENDER(x) x->GetGender() +#endif +#ifndef ADMIN +#define ADMIN(x) archp(x) +#endif +#ifndef VERSION +#define VERSION "Tim's LPC IMC2 client 30-Jan-05 / Dead Souls integrated" +#endif + +#define HTML_LOCATION "http://dead-souls.net/" + +// Other things that could be #define'd... +// INVIS(x) !visible(x) +// TELL_BOT "/u/t/timbot/imc2_invalidtells.c" +// TELL_BOTS ([ "timbot" : "/u/t/timbot/imc2_tellbot.c" ]) +// CHAN_BOT "/u/t/timbot/imc2_chans.c" +// CHAN_BOTS ([ "ichat" : "/u/t/timbot/imc2_ichat.c" ]) +// USER_EXISTS(x) user_exists(x) + +// Mode decides what kind of packet is expected +#define NO_UIDS +#define MODE_CONNECTED 1 +#define MODE_WAITING_ACCEPT 2 +#define MODE_CONNECT_ERROR 3 +// Not used yet, I need to see what the hub sends. +#define MODE_HUB_DOWN 4 +// Not used yet either. +#define MODE_BANNED 5 + +inherit LIB_DAEMON; + +string tmpstr, host, who_str; +static string SaveFile, serverpass, clientpass; + +static int socket_num, counter; +static int heart_count = 0; +int mode, autodisabled = 1; +mapping ping_requests; // Keeps track of who sent a ping request. +// Ping requests aren't labelled with names, so replies are destined to this MUD +// with no idea why, unless we keep track. +string buf=""; // Buffer for incoming packets (aren't always sent 1 at a time) + +// Variables +static int xmit_to_network_room = 1; //enable this to make a lot of noise +static string hub_name, network_name; +float server_version; +static string lterm; +static float client_version = IMC_VERSION; +static mapping chaninfo; +mapping localchaninfo; // (["chan": ([ "perm":1, "name":"something", "users":({ }) ]) ]) +mapping mudinfo; +mapping genders; +mapping tells; +int sequence; + +// Prototypes :) +void create(); +void Setup(); +void remove(); +string pinkfish_to_imc2(string str); +string imc2_to_pinkfish(string str); +string escape(string str); +string unescape(string str); +mapping string_to_mapping(string str); +string main_help(); +void keepalive(string args, object who); + +string clean_str(string str); +private void send_packet(string sender, string packet_type, string target, string destination, string data); +private void send_text(string text); +private void got_packet(string info); +private void start_logon(); +private varargs void send_is_alive(string origin); +private void channel_in(string fromname, string frommud, mapping data); +private void tell_in(string sender, string origin, string target, mapping data); +private void beep_in(string sender, string origin, string target, mapping data); +private void who_reply_in(string origin, string target, mapping data); +private void whois_in(string fromname, string frommud, string targ, mapping data); +private void whois_reply_in(string targ,string fromname,string frommud,mapping data); +private void ping_reply_in(string sender,string origin,string target,mapping data); +private void chanwho_reply_in(string origin, string target, mapping data); +private void send_keepalive_request(); +private int chan_perm_allowed(object user, string chan); +private string localize_channel(string str); +private void chan_who_in(string fromname, string frommud, mapping data); +private void send_ice_refresh(); +private void resolve_callback(string address, string resolved, int key); + +// Sanity check: a null socket write tends to be a crasher +varargs static void validate(int i){ + if(i){ + if(!socket_status(i) || !socket_status(i)[5]){ + tn("%^RED%^BAD SOCKET ALERT. fd "+i+": "+ + identify(socket_status(i)),"red"); + error("Bad socket, fd "+i); + } + } +} + +varargs void write_to_log(string type, string wat){ + if(xmit_to_network_room){ + tn(wat); + } + unguarded( (: log_file($(type), $(wat)) :) ); +} + +// Functions for users to change. +int can_use(object user){ return 1; } // Is this person allowed to use IMC2 at all? This function determines if tells can be sent to the person and such. + +int level(object ob){ + // Outgoing packets are marked with the user's level. + // This function figures it out. + // If you have different ways of ranking, make this function convert them to what IMC2 uses. + // IMC2 uses: Admin=5, Imp=4, Imm=3, Mort=2, or None=1 + if(ADMIN(ob)) return 5; // Admin + //TMI-2: if(wizardp(ob)) return 3; + //TMI-2: if(userp(ob)) return 2; + //Discworld: if(ob->query_creator()) return 3; + if(this_player()) return 2; + return 1; // None +} + +string chan_perm_desc(int i){ + // Given the permission level assigned locally to a channel, return a short + // string describing what the number means. The number means nothing + // outside of this MUD. Also, they are independant of each other, and + // so you can do groups without having to always do subgroups of higher + // ones or anything like 'levels'. BACKLOG_WEB_LEVEL is the only one of + // significance, as it's the only one that the web backlog thing works on. + switch(i){ + case 2: return "arch"; + case 1: return "creator"; + case 0: return "public"; + } + return "invalid"; +} + +int chan_perm_allowed(object user, string chan){ + // Using the permission level assigned locally to a channel, + // return 1 if user is allowed to use the channel, 0 if not. + switch(localchaninfo[chan]["perm"]){ + case 2: if(archp(user)) return 1; return 0; + case 1: if(creatorp(user)) return 1; return 0; + case 0: return 1; + } +} + + +// Shouldn't have to change anything beyond this point. + +void write_callback(int fd){ +#ifdef IMC2_LOGGING + write_to_log(DATA_LOG,"Write_Callback. \n"); +#endif + start_logon(); +} + +void read_callback(int socket, mixed info){ + string a,b,tmp; + int done=0; + counter = time(); + + //tc("read_callback","white"); + //tmp = replace_string(info, "\n", "(LF)"); + //tmp = replace_string(tmp, "\r", "(CR)"); + //tc("read_callback: "+tmp+"\n"); + +#ifdef IMC2_LOGGING + write_to_log(DATA_LOG,"SERVER: "+info+"\n"); +#endif + + if(!sizeof(info)) return 0; + buf += info; + + // The hub groups packets, unfortunately. + switch(mode){ + case MODE_WAITING_ACCEPT: // waiting for Hub to send autosetup + if(sscanf(info, "autosetup %s accept %s"+lterm, + hub_name, network_name)==2){ + mode = MODE_CONNECTED; + if(network_name) network_name = clean_str(network_name); + send_is_alive("*"); + send_keepalive_request(); + send_ice_refresh(); + } else if(sscanf(info, "PW %s %s version=%f %s"+lterm[0..0], + hub_name, serverpass, server_version, network_name)==4){ + mode = MODE_CONNECTED; + if(network_name) network_name = clean_str(network_name); + send_is_alive("*"); + send_keepalive_request(); + send_ice_refresh(); + } else{ // Failed login sends plaintext error message. + tn("IMC2 Failed to connect... "+info); + mode = MODE_CONNECT_ERROR; + set_heart_beat(22000); //Try again much later + return; + } + buf=""; // clear buffer + break; + case MODE_CONNECTED: + while(!done){ + if(sscanf(buf,"%s\n\r%s",a,b)==2){ // found a break... + //if(IMC_VERSION > 2) tc("LFCR: "+a,"red"); + got_packet(a); + buf=b; + } + else if(sscanf(buf,"%s\r\n%s",a,b)==2){ // found a break... + //if(IMC_VERSION < 2.1) tc("CRLF","green"); + got_packet(a); + buf=b; + } + else { // no break... + if(sizeof(b)){ + tmp = replace_string(b, "\n", "(LF)"); + tmp = replace_string(tmp, "\r", "(CR)"); + //tc("remainder: "+identify(tmp)); + got_packet(b+lterm); + } + done = 1; + } + } + break; + } + return; +} + +private void got_packet(string info){ + string str, tmp; + string a,b, my_ip; + int i; + string sender, origin, route, packet_type, target, destination, strdata; + int sequence, my_port; + mapping data; + object who; + if(!sizeof(info)){ + tn("No info?"); + return; + } +#ifdef IMC2_LOGGING + tmp = replace_string(info,"\n","(LF)"); + tmp = replace_string(tmp,"\r","(CR)"); + write_to_log(DATA_LOG,"GOT PACKET: "+tmp+"\n"); +#endif + + counter = time(); + str = info; + // messages end with " \n\r" or "\n" or sometimes just a space + sscanf(str, "%s\n^", str); + sscanf(str, "%s\r^", str); + sscanf(str, "%s ^", str); + sscanf(str, "%s ^", str); + if(sscanf(str, "%s %d %s %s %s %s", + a, sequence, route, packet_type, + b, strdata)==6){ // matches + if(sscanf(b,"%s@%s",target,destination)!=2){ + // Could be MUD instead of Name@MUD or *@MUD + target="*"; destination=b; + } + if(sscanf(a,"%s@%s",sender,origin)!=2){ + sender="*"; origin=a; + } + data = string_to_mapping(strdata); + if(!mudinfo[origin]) mudinfo[origin] = ([ ]); + + switch(packet_type){ + case "is-alive": // For making a MUD list. + if(!mudinfo[origin]) mudinfo[origin] = ([ ]); + // example of info: + // versionid=\"IMC2 AntiFreeze CL-2 SWR 1.0\" url=none md5=1 + //mudinfo[origin]["version"]="blah"; + if(!mudinfo[origin]["online"]){ + CHAT_D->eventSendChannel(origin+"@IMC2","muds", + "%^BOLD%^%^BLUE%^online%^RESET%^",0); + } + mudinfo[origin]+=data; + mudinfo[origin]["online"]=1; + break; + case "close-notify": // Someone disconnected. + if(!mudinfo[data["host"]]) mudinfo[data["host"]] = ([]); + if(mudinfo[data["host"]]["online"]){ + CHAT_D->eventSendChannel(data["host"]+"@IMC2","muds", + "%^BOLD%^%^RED%^offline%^RESET%^",0); + } + mudinfo[data["host"]]["online"]=0; + break; + case "keepalive-request": // Request for is-alive. + send_is_alive(origin); + break; + case "ice-msg-b": // Broadcast channel message. + channel_in(sender, origin, data); + break; + case "tell": // Tells or emotes. + tell_in(sender, origin, target, data); + break; + case "who-reply": + who_reply_in(origin,target,data); + break; + case "whois": // Like I3's locate + whois_in(sender,origin,target,data); + break; + case "whois-reply": + whois_reply_in(target,sender,origin,data); + break; + case "beep": + beep_in(sender, origin, target, data); + break; + case "ice-update": // Reply from ice-refresh. + chaninfo[data["channel"]]=data; + break; + case "wHo": // Drop-through + case "who": + if(sizeof(host)) my_ip = host; + else my_ip = INTERMUD_D->GetMyIp(); + if(my_ip == "127.0.0.1"){ + my_ip = "dead-souls.net"; + my_port = 8000; + } + else my_port = query_host_port(); + who_str=CGI_WHO->gateway(1)+URL+"\ntelnet://"+my_ip+":"+my_port+"\n"; + who_str += repeat_string("_", 75); + send_packet("*","who-reply",sender,origin, + "text="+escape(pinkfish_to_imc2(who_str))); + CHAT_D->eventSendChannel("SYSTEM","intermud","[" + capitalize(sender)+"@"+origin+ + " requests the IMC2 who list]",0); + break; + case "ice-destroy": // Deleting channel. + map_delete(chaninfo,data["channel"]); + break; + case "user-cache": // User info, like I3's ucache service. + if(!genders[origin]) genders[origin]=([ ]); + genders[origin][sender]=data["gender"]; + break; + case "user-cache-reply": // Reply with user info + if(!genders[origin]) genders[origin]=([ ]); + genders[origin][data["user"]]=data["gender"]; + break; + case "user-cache-request": // Request for user info + sscanf(data["user"],"%s@%*s",str); + if(str) who = FIND_PLAYER(lower_case(str)); + if(who +#ifdef INVIS + && !INVIS(who) +#endif + ){ + switch(GET_GENDER(who)){ + case "male" : i=0; break; + case "female" : i=1; break; + default : i=2; break; + } + send_packet("*","user-cache-reply",sender, + origin,sprintf("gender=%d",i)); + } + break; + case "ping": + send_packet("*","ping-reply",sender,origin, + sprintf("path=\"%s\"",route)); + break; + case "ping-reply": + ping_reply_in(sender,origin,target,data); + break; + case "ice-msg-r": // Relayed channel message. + channel_in(sender, origin, data); + CHAT_D->eventSendChannel("IMC2Test:"+sender,"admin","ice-msg-r sender:"+sender+"; origin:" +origin+"; data:"+(string)data); + break; + case "ice-chan-whoreply": // Tell who's listening to a channel. + chanwho_reply_in(origin,target,data); + break; + case "emote": // Channel creation/destruction message... anything else? + CHAT_D->eventSendChannel("IMC2:"+NETWORK_ID,"admin",data["text"]); +#ifdef ANNOUNCE_LOG + write_to_log(ANNOUNCE_LOG,ctime(time())+": "+data["text"]+"\n"); +#endif + break; + case "ice-chan-who": // Check who's listening to a channel. + chan_who_in(sender,origin,data); + break; + case "channel-notify": + // Don't care about this. Useful only if you care when + // people on other MUDs start/stop listening to a channel. + // example: Someone@SomeMUD 1087076772 SomeMUD channel-notify *@* channel=Hub01:ichat status=0 + break; + // The following packets shouldn't be incoming. + case "ice-cmd": // Remote channel administration + case "remote-admin": // For controlling the hub + case "ice-refresh": // Request data about channels + case "ice-msg-p": // Private channel message + break; + default: +#ifdef UNKNOWN_DATA_LOG + write_to_log(UNKNOWN_DATA_LOG,"Unknown packet: "+escape(info)+"\n\n"); +#endif + break; + } + } + else{ + buf += info; +#ifdef BAD_PACKET + write_to_log(BAD_PACKET,"Doesn't match incoming pattern: "+str+"\n"); +#endif + } +} + +private int close_callback(object socket){ + // Connection was closed. +#ifdef IMC2_LOGGING + write_to_log(DATA_LOG,"DISCONNECTED\n"); +#endif + socket_close(socket_num); + mode = MODE_WAITING_ACCEPT; + create(); + return 1; +} + +private void send_text(string text){ + string tmp; + text = clean_str(text); + text += lterm; + tmp = replace_string(text, "\n", "(LF)"); + tmp = replace_string(tmp, "\r", "(CR)"); + // Send a literal string. + // Almost everything should use the send_packet function instead of this. +#ifdef IMC2_LOGGING + write_to_log(DATA_LOG,"CLIENT: "+save_variable(tmp)+"\n"); + //tc("send_text: "+tmp); +#endif + validate(socket_num); + socket_write(socket_num,text); + return; +} + +void create(){ + SaveFile = save_file(SAVE_IMC2); + SetSaveFile(SaveFile); + if(unguarded( (: file_exists(SaveFile) :) )) + RestoreObject(SaveFile); + if(!file_exists(SaveFile) && file_exists(old_savename(SaveFile))){ + cp(old_savename(SaveFile), SaveFile); + } +#if DISABLE_IMC2 + //tn("IMC2: destruicted "+ctime(time())); + //unguarded( (: destruct() :) ); +#else + if(mode != MODE_CONNECT_ERROR){ + set_heart_beat(10); + } + counter = time(); + tn("IMC2: created "+ctime(time())); +#endif + if(client_version > 2){ + lterm = "\r\n"; + } + else { + lterm = "\n\r"; + } + call_out( (: Setup :), 1); +} + +void Setup(){ + int temp, kill, my_port; + string my_ip; + +#ifdef DISABLE_IMC2 + if(DISABLE_IMC2){ + kill = 1; + } +#endif + + if(DISABLE_INTERMUD == 1){ + kill = 1; + } + + if(kill || autodisabled){ + call_out( (: eventDestruct() :), 5); + return; + } + else { + clientpass = SECRETS_D->GetSecret("IMC2_CLIENT_PW"); + serverpass = SECRETS_D->GetSecret("IMC2_SERVER_PW"); + if(sizeof(host)) my_ip = host; + else my_ip = INTERMUD_D->GetMyIp(); + if(my_ip == "127.0.0.1"){ + my_ip = "dead-souls.net"; + my_port = 8000; + } + else my_port = query_host_port(); + who_str = CGI_WHO->gateway(1)+URL+"\ntelnet://"+my_ip+":"+my_port+"\n"; + who_str += repeat_string("_", 75); + } + tn("IMC2: setup "+ctime(time())); +#ifndef NO_UIDS + seteuid(getuid()); +#endif + tn("Creating IMC2 object at "+ctime(time())+".\n"); +#ifdef IMC2_LOGGING + write_to_log(DATA_LOG,"Creating IMC2 object at "+ctime(time())+".\n"); +#endif + if(!mudinfo) mudinfo = ([ ]); + if(!chaninfo) chaninfo = ([ ]); + if(!localchaninfo) localchaninfo = ([ ]); + if(!genders) genders = ([ ]); + if(!tells) tells=([ ]); + ping_requests=([ ]); + mode = MODE_WAITING_ACCEPT; + if(my_ip == "dead-souls.net"){ + catch( host = query_intermud_ip() ); + if(!sizeof(host)) host = "dead-souls.net"; + } + else host = my_ip; +#ifdef HOSTIP + // We already know the IP, go straight to the connecting, just do callback as if it found the IP. + resolve_callback(HOSTIP,HOSTIP,1); +#else + temp = resolve(HOSTNAME, "resolve_callback"); + if(temp == 0){ +#ifdef IMC2_LOGGING + write_to_log(DATA_LOG,"Addr_server is not running, resolve failed.\n"); +#endif + eventDestruct(); + return; + } +#endif + SaveObject(SaveFile, 1); +} + +void heart_beat(){ + int lastmsg = time() - counter; + heart_count++; + if(heart_count > 4){ + mixed sstat = socket_status(socket_num); + heart_count = 0; + if( lastmsg > 300 && lastmsg < 900){ + tn("IMC2 heartbeat: Last message "+time_elapsed(lastmsg)+" ago."); + tn("sending keepalive"); + send_keepalive_request(); + } + if( lastmsg > 400 + ||!sstat || sstat[1] != "DATA_XFER"){ + socket_close(socket_num); + tn("IMC2 heartbeat: reloading IMC2_D due to timeout"); +#ifdef IMC2_LOGGING + write_to_log(DATA_LOG,"IMC2 TIMEOUT! Reloading.\n"); +#endif + + RELOAD_D->eventReload(this_object(), 2, 1); + } + } +} + +void remove(){ + // This object is getting destructed. + tn("removing imc2. stack: "+get_stack(1)); + mode=2; + SaveObject(SaveFile, 1); + socket_close(socket_num); +#ifdef IMC2_LOGGING + write_to_log(DATA_LOG,"IMC2 OBJECT REMOVED\n"); +#endif +} + +static mixed GetChanInfo(){ + mixed foo = copy(chaninfo); + return 1; +} + +string *GetChanList(){ + if(!chaninfo) return ({}); + return keys(chaninfo); +} + +int eventDestruct(){ + remove(); + return ::eventDestruct(); +} + +void resolve_callback( string address, string resolved, int key ) { + // Figured out what the IP is for the address. + int error; + + write_file("/tmp/imc2.log","address: "+address+"\n"); + write_file("/tmp/imc2.log","resolved: "+resolved+"\n"); + write_file("/tmp/imc2.log","key: "+key+"\n"); + + socket_num = socket_create(STREAM, "read_callback", "close_callback"); + if (socket_num < 0) { +#ifdef IMC2_LOGGING + write_to_log(DATA_LOG,"socket_create: " + socket_error(socket_num) + "\n"); +#endif + return; + } +#ifdef IMC2_LOGGING + write_to_log(DATA_LOG,"socket_create: Created Socket " + socket_num + "\n"); +#endif + + error = socket_connect(socket_num, resolved+" "+HOSTPORT, "read_callback", "write_callback"); + if (error != EESUCCESS) { +#ifdef IMC2_LOGGING + write_to_log(DATA_LOG,"socket_connect: " + socket_error(error) + "\n"); +#endif + socket_close(socket_num); + //Timeouts on windows lag the whole mud. This disables the daemon + //to prevent that. + if(query_os_type() == "windows" && grepp(socket_error(error), "Problem with connect")){ + load_object("/secure/cmds/admins/mudconfig")->cmd("imc2 disable"); + } + return; + } +#ifdef IMC2_LOGGING + write_to_log(DATA_LOG,"socket_connect: connected socket " + socket_num + " to " + resolved+" "+HOSTPORT + "\n"); +#endif +} + +void start_logon(){ +#if NOT_AUTO + //tc("1, version: "+IMC_VERSION); + send_text(sprintf("PW %s %s version=%s"+lterm, +#else + //tc("2, version: "+IMC_VERSION); + send_text(sprintf("PW %s %s version=%s autosetup %s"+lterm, +#endif + MUDNAME, + clientpass, IMC_VERSION+"" +#ifndef NOT_AUTO + , serverpass +#endif + )); + buf=""; + /* For invitation-only networks. + //tc("3, wtf"); + send_text(sprintf("PW %s %s version=%s %s"+lterm, + MUDNAME, + clientpass, IMC_VERSION+"", "hub03" + )); + */ + sequence=time(); + } + string clean_str(string str){ + while(sizeof(str) && str[<1] < 32){ + str = str[0..<2]; + } + return str; + } + + string escape(string str){ + str=replace_string(str,"\\","\\\\"); + str=replace_string(str,"\"","\\\""); + str=replace_string(str,"\n","\\n"); + str=replace_string(str,"\r","\\r"); + if(sizeof(explode(str," "))!=1) str = "\""+str+"\""; + return str; + } + + string unescape(string str){ + string a,b=str,output=""; + while(sscanf(b,"%s\\%s",a,b)==2){ + output += a; + if(sizeof(b)){ + switch(b[0]){ + case 34 : output += "\""; break; // '\"' makes warnings. + case '\\' : output += "\\"; break; + case 'n' : output += "\n"; break; + case 'r' : output += "\r"; break; + } + } + b=b[1..]; + } + output += b; + output = replace_string(output,"\n\r","\n"); + if((sizeof(explode(output," "))==1) && sscanf(output,"\\\"%*s\\\"") ) output = "\""+output+"\""; + return output; + } + + mapping string_to_mapping(string str){ + // Picks first element off of string and then repeats? + mapping out=([]); + int i; + string what,data,rest; + + rest = str; + + while(sizeof(rest)>0){ + sscanf(rest, "%s=%s", what, rest); + /* + write("what="+what+", rest="+rest+"\n"); + */ + // At this point, what is the key, rest is value plus rest. + if(rest[0]==34){ // value is in quotes, tons of fun! + // find first quote without a backslash in front? + /* + write("rest begings with a quote\n"); + */ + i = 1; + while(((rest[i]!=34) || (rest[i-1]==92)) && (iGetLocalChannel(data["channel"]); + CHANNEL_BOT->eventSendChannel(sender, localchan, + imc2_to_pinkfish(data["text"]), emote, "", ""); + } + + void channel_out(string user,string chan,string msg,int emote){ + // Send outgoing channel message. + send_packet(user,"ice-msg-b","*","*", sprintf("channel=%s text=%s emote=%d echo=0", chan,escape(pinkfish_to_imc2(msg)),emote)); + } + + varargs static void tell_out(object from, string targname, string targmud, string msg, int reply, int emote){ + string ret = "%^BOLD%^RED%^You tell " + capitalize(targname) + + "@" + targmud + ":%^RESET%^ " + msg; + + //Check for privs to send imc tell + if(RESTRICTED_INTERMUD) { + if(!imud_privp(lower_case(from->GetKeyName()))) { + this_player(1)->eventPrint("You lack the power to send tells to other worlds.", MSG_CONV); + return; + } + } + + // Send outgoing tell. + if(!reply) reply=0; + send_packet(capitalize(from->GetKeyName()),"tell",targname,targmud, + "text="+escape(msg)); + from->eventPrint(ret, MSG_CONV); + from->eventTellHist(ret); + } + + void tell_in(string sender, string origin, string target, mapping data){ + // Incoming tell. Parse and display to user + object who; + int sz; + string blmsg, ret, eret; + if(target){ + who = FIND_PLAYER(lower_case(target)); + INSTANCES_D->SendTell(lower_case(target), data["text"], + sender + "@" + origin); + } + if(who) target = GET_CAP_NAME(who); + else return; + data["text"]=imc2_to_pinkfish(data["text"]); + who->SetProperty("reply",sender+"@"+origin); + who->SetProperty("reply_time", time()); + eret = "%^BOLD%^RED%^" + sender + "@" + origin + + " %^RESET%^ " + data["text"]; + ret = "%^BOLD%^RED%^" + sender + "@" + origin + + " tells you:%^RESET%^ " + data["text"]; + if(who +#ifdef INVIS + && VISIBLE(who) +#endif + && can_use(who) + ){ + switch(data["isreply"]){ + case 2: // emote + ret = eret; + who->eventPrint(ret, MSG_CONV); + blmsg=sprintf("%s@%s %s\n",sender,origin,data["text"]); + break; + case 1: // reply + who->eventPrint(ret, MSG_CONV); + blmsg=sprintf("%s@%s replied to you: %s\n", NETWORK_ID,sender,origin,data["text"]); + break; + default: + who->eventPrint(ret , MSG_CONV); + blmsg=sprintf("%s@%s told you: %s\n", sender,origin,data["text"]); + break; + } + who->eventTellHist(ret); + if(!tells[target]) + tells[target]=([ ]); + tells[target]["reply"] = sprintf("%s@%s",sender,origin); + if(!tells[target]["backlog"] || !arrayp(tells[target]["backlog"])) + tells[target]["backlog"]=({ }); + tells[target]["backlog"] += ({ blmsg }); + sz = sizeof(tells[target]["backlog"]); + if(sz>BACKLOG_SIZE) + tells[target]["backlog"]=tells[target]["backlog"][(sz-BACKLOG_SIZE)..sz]; + } else { +#ifdef TELL_BOTS + // Can have a mapping of bots which can get tells. + if(TELL_BOTS[target]){ + call_other(TELL_BOTS[target],"got_tell",sender, origin, target, data["text"]); + return; + } +#endif +#ifdef TELL_BOT + // They should have got_tell(fromname, frommud, target, text) + // I'll assume bots don't care about emote/reply... tell me if you do? + // TELL_BOT will get told of all tells which don't have a valid target, and + // then the sender will be notified that it didn't get to anyone. + // This would be useful if for example you wanted all tells sent to + // offline people to be mudmailed to them or something. + call_other(TELL_BOT,"got_tell",sender, origin, target, data["text"]); +#endif + send_packet("*","tell",sender,origin, + sprintf("level=-1 text=\"%s is not online on this mud.\" isreply=1",target)); + } + } + + int tell(mixed arg, object who){ + string targmud,targplayer,msg; + int i; + if(!who || !this_player() || who != this_player()) return 0; + if(who->GetForced()){ + return 0; + } + i = sscanf(arg,"%s@%s %s",targplayer, targmud, msg); + if(i != 3 ){ + write("There was an error in your message. See: \"help imc2\""); + return 1; + } + tell_out(who, targplayer, this_object()->find_mud(targmud), msg, 0, 0); + return 1; + } + + string pinkfish_to_imc2(string str){ + // Foreground + str=replace_string(str,"%^BLACK%^","~x"); // Black + str=replace_string(str,"%^RED%^","~R"); // Red + str=replace_string(str,"%^GREEN%^","~G"); // Green + str=replace_string(str,"%^BLUE%^","~B"); // Blue + str=replace_string(str,"%^WHITE%^","~W"); // White + str=replace_string(str,"%^ORANGE%^","~y"); // Orange + str=replace_string(str,"%^CYAN%^","~c"); // Cyan + str=replace_string(str,"%^YELLOW%^","~Y"); // Yellow + str=replace_string(str,"%^MAGENTA%^","~p"); // Magenta -> purple sounds closest + str=replace_string(str,"%^GRAY%^","~w"); // Gray doesn't display on my MUD, bah :( + // Background + str=replace_string(str,"%^B_BLACK%^","^x"); + str=replace_string(str,"%^B_RED%^","^R"); // Red + str=replace_string(str,"%^B_GREEN%^","^G"); // Green + str=replace_string(str,"%^B_BLUE%^","^b"); // Blue + str=replace_string(str,"%^B_WHITE%^","^W"); // White + str=replace_string(str,"%^B_ORANGE%^","^O"); // Orange + str=replace_string(str,"%^B_CYAN%^","^c"); // Cyan + str=replace_string(str,"%^B_YELLOW%^","^Y"); // Yellow + str=replace_string(str,"%^B_MAGENTA%^","^p"); // Magenta -> purple sounds closest + // Misc. + str=replace_string(str,"%^FLASH%^","~$"); // Flash -> Blink + str=replace_string(str,"%^BOLD%^","~L"); // Bold + str=replace_string(str,"%^RESET%^","~!"); + //Replace anything that was done in %^BOLD%^RED%^ format and wasn't already caught + str=replace_string(str,"%^FLASH","~$"); // Flash -> Blink + str=replace_string(str,"%^BOLD","~L"); // Bold + str=replace_string(str,"%^RESET","~!"); + str=replace_string(str,"FLASH%^","~$"); // Flash -> Blink + str=replace_string(str,"BOLD%^","~L"); // Bold + str=replace_string(str,"RESET%^","~!"); + return str; + } + + string imc2_to_pinkfish(string str){ + string output=""; + int sz; + str = replace_string(str+"", "/~", "/~~"); + /* + For colors explanation, refer to IMC Packet Documentation by Xorith. + Thanks very much for putting that out, by the way. :) + Found at http://hub00.muddomain.com/imc2_protocol_doc.txt + */ + sz=sizeof(str)-1; + while(sizeof(str)>1){ + switch(str[0]){ + case '~': // Foreground + switch(str[1]){ + case 'Z': break; // Random + case 'x': output += "%^BLACK%^"; break; // Black + case 'r': output += "%^RED%^"; break; // Dark Red + case 'g': output += "%^GREEN%^"; break; // Dark Green + case 'y': output += "%^ORANGE%^"; break; // Orange + case 'b': output += "%^BLUE%^"; break; // Dark Blue + case 'p': output += "%^MAGENTA%^"; break; // Purple + case 'c': output += "%^CYAN%^"; break; // Cyan + case 'w': output += "%^WHITE%^"; break; // Grey + case 'D': output += "%^BLACK%^"; break; // Dark Grey + case 'z': output += "%^BLACK%^"; break; // Same as ~D + case 'R': output += "%^RED%^"; break; // Red + case 'G': output += "%^GREEN%^"; break; // Green + case 'Y': output += "%^YELLOW%^"; break; // Yellow + case 'B': output += "%^BLUE%^"; break; // Blue + case 'P': output += "%^MAGENTA%^"; break; // Pink + case 'C': output += "%^BLUE%^"; break; // Light Blue + case 'W': output += "%^WHITE%^"; break; // White + + case 'm': output += "%^MAGENTA%^"; break; // same as p + case 'd': output += "%^WHITE%^"; break; // same as w + case 'M': output += "%^MAGENTA%^"; break; // same as P + // Misc. + case '!': output += "%^RESET%^"; break; // Reset + case 'L': output += "%^BOLD%^"; break; // Bold + case 'u': break; // Underline + case '$': output += "%^FLASH%^"; break; // Blink + case 'i': break; // Italic + case 'v': break; // Reverse + case 's': break; // Strike-thru + + case '~': output += "~"; break; // ~~ prints as ~ + default : output += "~"; // Don't skip over this + // (cheap hack is to add a character in front so the [2..] thing still works) + str = " "+str; + break; + } + str=str[2..]; + break; + case '^': // Background + switch(str[1]){ + case 'Z': break; // Random + case 'x': output += "%^B_BLACK%^"; break; // Black + case 'r': output += "%^B_RED%^"; break; // Dark Red + case 'g': output += "%^B_GREEN%^"; break; // Dark Green + case 'O': output += "%^B_ORANGE%^"; break; // Orange + case 'B': output += "%^B_BLUE%^"; break; // Dark Blue + case 'p': output += "%^B_MAGENTA%^"; break; // Purple + case 'c': output += "%^B_CYAN%^"; break; // Cyan + case 'w': output += "%^B_WHITE%^"; break; // Grey + case 'z': output += "%^B_BLACK%^"; break; // Dark Grey + case 'R': output += "%^B_RED%^"; break; // Red + case 'G': output += "%^B_GREEN%^"; break; // Green + case 'Y': output += "%^B_YELLOW%^"; break; // Yellow + case 'b': output += "%^B_BLUE%^"; break; // Blue + case 'P': output += "%^B_MAGENTA%^"; break; // Pink + case 'C': output += "%^B_BLUE%^"; break; // Light Blue + case 'W': output += "%^B_WHITE%^"; break; // White + case '^': output += "^"; break; // ^^ prints as ^ + default : output += "^"; // Don't skip over this + // (cheap hack is to add a character in front so the [2..] thing still works) + str = " "+str; + break; + } + str=str[2..]; + break; + case '`': // Blinking Foreground + switch(str[1]){ + case 'Z': output += "%^FLASH%^"; break; // Random + case 'x': output += "%^FLASH%^%^BLACK%^"; break; // Black + case 'r': output += "%^FLASH%^%^RED%^"; break; // Dark Red + case 'g': output += "%^FLASH%^%^GREEN%^"; break; // Dark Green + case 'O': output += "%^FLASH%^%^ORANGE%^"; break; // Orange + case 'b': output += "%^FLASH%^%^BLUE%^"; break; // Dark Blue + case 'p': output += "%^FLASH%^%^MAGENTA%^"; break; // Purple + case 'c': output += "%^FLASH%^%^CYAN%^"; break; // Cyan + case 'w': output += "%^FLASH%^%^WHITE%^"; break; // Grey + case 'z': output += "%^FLASH%^%^BLACK%^"; break; // Dark Grey + case 'R': output += "%^FLASH%^%^RED%^"; break; // Red + case 'G': output += "%^FLASH%^%^GREEN%^"; break; // Green + case 'Y': output += "%^FLASH%^%^YELLOW%^"; break; // Yellow + case 'B': output += "%^FLASH%^%^BLUE%^"; break; // Blue + case 'P': output += "%^FLASH%^%^MAGENTA%^"; break; // Pink + case 'C': output += "%^FLASH%^%^BLUE%^"; break; // Light Blue + case 'W': output += "%^FLASH%^%^WHITE%^"; break; // White + case '`': output += "`"; break; // `` prints as ` + default : output += "`"; // Don't skip over this + // (cheap hack is to add a character in front so the [2..] thing still works) + str = " "+str; + break; + } + str=str[2..]; + break; + default: + output += str[0..0]; + str=str[1..]; + break; + } + } + output += str; + return output; + } + + private void who_reply_in(string origin, string target, mapping data){ + string output; + object targuser; + if(target) targuser = FIND_PLAYER(lower_case(target)); + if(targuser){ + output = NETWORK_ID+" who reply from: %^CYAN%^"+origin+"%^RESET%^\n"; + output += imc2_to_pinkfish(data["text"])+"\n"; + IMC2_MSG(output,targuser); + } + } + + private void whois_in(string fromname, string frommud, string targ, mapping data){ + if(targ && FIND_PLAYER(lower_case(targ)) +#ifdef INVIS + && !INVIS(FIND_PLAYER(lower_case(targ))) +#endif + && can_use(FIND_PLAYER(lower_case(targ))) + ){ + send_packet(targ,"whois-reply",fromname,frommud,"text=Online"); + } +#ifdef USER_EXISTS + else if(USER_EXISTS(lower_case(targ))){ + send_packet(targ,"whois-reply",fromname,frommud, + "text=\"Exists but is offline\""); + } +#endif + } + + private void whois_reply_in(string targ,string fromname,string frommud,mapping data){ + object who; + if(targ) who = FIND_PLAYER(lower_case(targ)); + if(who){ + IMC2_MSG(sprintf("%s whois reply: %s@%s: %s\n", + NETWORK_ID,fromname,frommud,data["text"]),who); + } + } + + private void beep_in(string sender, string origin, string target, mapping data){ + object who; + if(target) who = FIND_PLAYER(lower_case(target)); + if(who && can_use(who) +#ifdef INVIS + && VISIBLE(who) +#endif + ){ + IMC2_MSG(sprintf("%s- %%^CYAN%%^%s@%s%%^RESET%%^ \abeeps you.\n", + NETWORK_ID,sender,origin,data["text"]), who); + } + else{ + send_packet("*","tell",sender,origin, + sprintf("level=-1 text=\"%s is not online.\" isreply=1",target)); + } + } + + void beep_out(object from, string targname, string targmud){ + send_packet(GET_CAP_NAME(from),"beep",targname,targmud, + sprintf("level=%d ", level(from))); + } + + void send_ice_refresh(){ send_packet("*","ice-refresh","*","*",""); } + + void ping_reply_in(string sender,string origin,string target,mapping data){ + object who; + if((target=="*") && target=ping_requests[sender]){ + target=ping_requests[sender]; + map_delete(ping_requests,sender); + } + if(target) who = FIND_PLAYER(lower_case(target)); + if(who){ + IMC2_MSG(sprintf("%s route to %%^CYAN%%^%s%%^RESET%%^ is: %s\n", + NETWORK_ID,origin,data["path"]), who); + } + } + + void ping_out(string from,string targmud){ send_packet(from,"ping","*",targmud,""); } + varargs void who_out(string from,string targmud,string type){ send_packet(from,"who","*",targmud,(type ? sprintf("type=\"%s\"",type) : "type=who")); } + + void chanwho_out(object from,string chan,string mud){ + send_packet(GET_CAP_NAME(from),"ice-chan-who","*",mud, + sprintf("level=%d channel=%s lname=%s",level(from), + localchaninfo[chan]["name"],chan)); + } + + void chanwho_reply_in(string origin, string target, mapping data){ + string output; + object targuser; + if(target) targuser = FIND_PLAYER(lower_case(target)); + if(targuser){ + output = NETWORK_ID+" chanwho reply from "+origin+" for "+data["channel"]+"\n"; + output += imc2_to_pinkfish(data["list"]); + IMC2_MSG(output,targuser); + } + } + + void chan_who_in(string fromname, string frommud, mapping data){ + // Handles an incoming channel who request. + } + + string find_mud(string str){ + // Makes case-insensitive mud name into the actual mud name, or else 0. + string mud; + string *mudses = filter(keys(mudinfo), (: mudinfo[$1] && + mudinfo[$1]["online"] == 1 :) ); + if (!str) return 0; + if(member_array(str, mudses) != -1) return str; + str = lower_case(str); + foreach(mud in mudses){ + if ( lower_case(mud)==str ) return mud; + } + return 0; + } + + string localize_channel(string str){ + // Tells what the local name for a channel is, given the network name for it, or else 0. + string a; + foreach(a in keys(localchaninfo)){ + if(lower_case(localchaninfo[a]["name"])==lower_case(str)) return a; + } + return 0; + } + + //Returns mud list to user object 'towho' + void mudlist(object towho) { + int x,y; + string output; + string mud,*muds; + + muds = sort_array(filter(keys(mudinfo), (: stringp($1) :)),1); + if (!mode==MODE_CONNECTED) { + message("system",MUDNAME+" is not connected to the "+NETWORK_ID+" network!\n",towho); + return; + } else if (!sizeof(mudinfo)){ + message("system","There are no muds on the "+NETWORK_ID+" network!\n",towho); + return; + } else { + x=0; y=0; + output=sprintf("[%s] %-20s %-20s %-20s\n","U/D?","Name","Network","IMC2 Version"); + foreach (mud in filter(muds, (: mudinfo[$1]["online"] :) )){ + if(!mudinfo[mud]) output += "Error on mud: "+mud+"\n"; + else { + if(mudinfo[mud]["online"]) x++; else y++; + output += sprintf("[%s] %-20s %-20s %-20s\n", + (mudinfo[mud]["online"] ? "%^GREEN%^ UP %^RESET%^" : "%^RED%^DOWN%^RESET%^"), + mud, mudinfo[mud]["networkname"], mudinfo[mud]["versionid"]); + } + } + output += sprintf("%d of %d MUDs are online.\n",x,x+y); + message("system",output,towho); + return; + } + } + + mapping getmudinfo() { + return mudinfo; + } + + //pings mud 'mudname', returns it to user object 'towho' + void mudinfo(string args,object towho) { + string str; + string output; + + if(!args) { + message("system","See info for which MUD?",towho); + return; + } + + str=find_mud(args); + if(!str) { + message("system","MUD isn't known on "+NETWORK_ID+".",towho); + return; + } + + output=("Mud info for: "+str+"\nStatus: "); + + if(mudinfo[str]["online"]) output+=("%^GREEN%^Online%^RESET%^\n"); + else output+=("%^RED%^Offline%^RESET%^\n"); + + if(mudinfo[str]["versionid"]) output+=("Version ID: "+mudinfo[str]["versionid"]+"\n"); + if(mudinfo[str]["url"]) output+=("URL: "+mudinfo[str]["url"]+"\n"); + if(mudinfo[str]["networkname"]) output+=("Network name: "+mudinfo[str]["networkname"]+"\n"); + + message("system",output,towho); + return; + } + + //Gets WHO list from mud 'mudname', returns it to user object 'towho' + void mudwho(string mudname,object towho) { + string str; + if(!mudname) { + message("system","Send who request to which MUD?",towho); + return; + } + str=find_mud(mudname); + if(!str) { + message("system","MUD isn't known on "+NETWORK_ID+".",towho); + return; + } + if(!mudinfo[str]["online"]) { + message("system",str+" is offline right now.",towho); + return; + } + who_out(capitalize(this_player()->GetKeyName()),str); + message("system",NETWORK_ID+" sent a who request to "+str+"\n",towho); + return; + } + + //pings mud 'mudname', returns it to user object 'towho' + mixed pingmud(string mudname,object towho) { + string str; + if(!mudname) { + message("system","Send ping to which MUD?",towho); + return; + } + str=find_mud(mudname); + if(!str) { + message("system","MUD isn't known on "+NETWORK_ID+".",towho); + return; + } + if(!mudinfo[str]["online"]) { + message("system",str+" is offline right now.",towho); + return; + } + ping_out(capitalize(towho->GetKeyName()),str); + message("system","Sent a ping to "+str+".",towho); + return; + } + + //Displays status to user object 'towho' + void getstatus(object towho) { + string output; + + output=sprintf(@EndText + IMC2 NETWORK INFORMATION + ------------------------ + Status: %s + Hub address: %s + Hub port: %d + The hub calls itself: %s + The network calls itself: %s + Command to use this network: %s + The MUD calls this connection: %s + + Packet logging: %s + + The network calls the MUD: %s + The MUD's Version ID: %s + The MUD's URL: %s +EndText, + ((mode==MODE_CONNECTED) ? "Connected" : "Not connected"), +#ifdef HOSTNAME + HOSTNAME, +#else + HOSTIP, +#endif + HOSTPORT,hub_name,network_name,COMMAND_NAME,NETWORK_ID, +#ifdef IMC2_LOGGING + "on", +#else + "off", +#endif + MUDNAME,VERSION,URL); + + message("system",output,towho); + } + + //return mode + int getonline() { + return mode; + } + + //Beeps user@mud stored in 'args', returns it to user object 'towho' + void interbeep(string args, object towho) { + string a,b; + if(!args || sscanf(args,"%s@%s",a,b)!=2) { + message("system","Invalid syntax.",towho); + return; + } + b=find_mud(b); + if(!b) { + message("system","MUD isn't known on "+NETWORK_ID+".",towho); + return; + } + if(!mudinfo[b]["online"]) { + message("system",b+" is offline right now.",towho); + return; + } + beep_out(towho,a,b); + message("system",sprintf("You beep %s@%s.",capitalize(a),b),towho); + return; + } + + //Fingers user@mud stored in 'args', returns it to user object 'towho' + void finger(string args, object towho) { + string a,b; + + if(!args) return notify_fail("Send finger request to who@where?\n");; + if(sscanf(args,"%s@%s",a,b)!=2){ + return notify_fail("Send finger request to who@where?\n");; + } + b=find_mud(b); + who_out(GET_CAP_NAME(towho),b,"finger "+a); + IMC2_MSG(NETWORK_ID"- Sent a finger request to "+a+"@"+b+"\n",THIS_PLAYER); + } + + //Gets whois for user@mud stored in 'args', returns it to user object 'towho' + void whois(string args, object towho) { + if(!args || !sizeof(args)) return notify_fail("Locate who?\n"); + + send_packet(GET_CAP_NAME(THIS_PLAYER),"whois",args,"*", sprintf("level=%d ",level(THIS_PLAYER))); + + IMC2_MSG("Sent a request on "+NETWORK_ID+" looking for "+args+"\n",THIS_PLAYER); + } + + //Gets MUD Info for a mud 'args', returns it to user object 'towho' + void getremotemudinfo(string args, object towho) { + string str; + + if(!args) return notify_fail("Send info request to which MUD?\n"); + + str=find_mud(args); + + if(!str) return notify_fail("MUD isn't known on "+NETWORK_ID+".\n"); + if(!mudinfo[str]["online"]) return notify_fail(NETWORK_ID+"- "+str+" is offline right now.\n"); + + who_out(GET_CAP_NAME(THIS_PLAYER),str,"info"); + IMC2_MSG(NETWORK_ID"- Sent an info request to "+str+"\n",THIS_PLAYER); + } + + //Write list of all channels to screen + void allchans(string args, object towho) { + string output; + string a; + + output=NETWORK_ID+" channels:\n"; + output += sprintf("%-23s %-17s %-7s %-6s %-10s %-10s\n", + "Name","Owner","Policy","Level","Suggested","Local Name"); + + foreach(a in sort_array( + filter(keys(chaninfo), (: stringp($1) :) ),1)){ + output += sprintf("%-23s %-17s %-7s %-6s %-10s %-10s\n", + a,chaninfo[a]["owner"], + chaninfo[a]["policy"], + chaninfo[a]["level"],chaninfo[a]["localname"], + (localize_channel(a) ? localize_channel(a) : "")); + } + IMC2_MSG(output,THIS_PLAYER); + + } + + //Send a channel command to the server + void chancmd(string args, object towho) { + string a, b, c; + + if(!ADMIN(THIS_PLAYER)) return notify_fail("You aren't allowed to use chancmd.\n"); + if(!args || (sscanf(args,"%s:%s %s",a,b,c)!=3)) + return notify_fail("Syntax: "+COMMAND_NAME+" chancmd hub:channel command\n"); + if(!chaninfo[a+":"+b]) + write(a+" is not listed as a channel, sending command anyway...\n"); + send_packet(GET_CAP_NAME(THIS_PLAYER),"ice-cmd","IMC",b, sprintf("channel=%s command=\"%s\"", a+":"+b,escape(c))); + + IMC2_MSG(sprintf("%s- Sent a command for the %s channel to %s\n",NETWORK_ID,a,GET_CAP_NAME(THIS_PLAYER),b),THIS_PLAYER); + } + + int command(string str){ + // Takes the arguments given to the command which does IMC2 stuff. + string cmd, args; + string output; + string a,b,c; + int x,y; + int emote,reply; + object usr, *usrs=({ }); + + if(IMC2_D->getonline() != 1) return 0; + + if(!str) str = "help"; + sscanf(str,"%s %s",cmd,args); + if(!cmd) cmd=str; + if(!args) args = ""; + + switch(cmd){ + case "list": + mudlist(this_player()); + return 1; + break; + case "setup": + getstatus(this_player()); + return 1; + break; + case "info": + mudinfo(args,this_player()); + return 1; + break; + case "ping": + pingmud(args,this_player()); + return 1; + break; + case "who": + mudwho(args,this_player()); + return 1; + break; + case "tell": + tell(args,this_player()); + return 1; + break; + case "finger": + finger(args,this_player()); + return 1; + break; + case "mudinfo": + getremotemudinfo(args,this_player()); + return 1; + break; + case "allchans": case "ice-update": + allchans(args,this_player()); + return 1; + break; + case "beep": + interbeep(args,this_player()); + return 1; + break; + case "whois": + whois(args,this_player()); + return 1; + break; + case "chancmd": + chancmd(args,this_player()); + return 1; + break; + case "keepalive": + send_keepalive_request(); + return 1; + break; + case "is-alive": + send_is_alive(); + return 1; + break; + case "help": // drop through to default + default: + IMC2_MSG(main_help(),THIS_PLAYER); + return 1; + break; + } + } + + string main_help(){ + return sprintf(@EndText + IMC2 system by Tim, set up for %s. + To use this, type the command '%s' followed by one of the following: + info (name) - lists information about a MUD + list - lists the MUDs on this network + finger (name)@(mud) - send a finger request for information about name@mud + ping (mud) - pings a mud + setup - shows information about this IMC2 network + help - see this help message +EndText, NETWORK_ID,COMMAND_NAME); + } + + string html(string str){ + string mud, *muds; + string a,b; + int x=0,y=0; + string output=""; + if(!str) str=""; + sscanf(str,"%s_%s",a,b); + if(!a) a=str; + switch(a){ + case "list": + muds = sort_array(keys(mudinfo),1); + if (!sizeof(mudinfo)){ + return ("There are no muds on the "+NETWORK_ID+" network!\n"); + } + else{ + output="StatusNameNetworkIMC2 Version\n"; + foreach (mud in muds){ + if(mudinfo[mud]["online"]) x++; else y++; + output += sprintf("%s%s%s%s\n", + (mudinfo[mud]["online"] ? "UP" : "DOWN"), + mudinfo[mud]["url"] ? ""+mud+"" : mud, + mudinfo[mud]["networkname"], + mudinfo[mud]["versionid"]); + } + } + return sprintf("%d of %d MUDs are on %s.%s
", + x,x+y,NETWORK_ID,output); + break; + case "backlog": + if(b && localchaninfo[b] && (localchaninfo[b]["perm"]==BACKLOG_WEB_LEVEL)){ + // Show backlog for channel. + return b+" channel backlog:\n"+implode(localchaninfo[b]["backlog"],"\n"); + } + // List the channels + output = NETWORK_ID+" channels on "+MUDNAME+":\n"; + foreach(b in sort_array(keys(localchaninfo),1)){ + if(localchaninfo[b]["perm"]==BACKLOG_WEB_LEVEL) // is public + output += ""; + output += b; + output += " - "+chan_perm_desc(localchaninfo[b]["perm"]); + if(localchaninfo[b]["perm"]==BACKLOG_WEB_LEVEL) // is public + output += " - on web"; + else + output += " - not on web"; + output += "\n"; + } + return output; + break; + default: + return MUDNAME+" uses Tim's LPC IMC2 system to connect to the "+ + NETWORK_ID+" network.\n"+ + "(version:"+VERSION+")\n"+ + "From here, you can look at the list of muds,\n"+ + "view the public channel backlogs,\n"+ + "or go to the main "+MUDNAME+" web site.\n"; + break; + } + } + + int clean_up(){ return 0; } + + + void forget_user(string str){ map_delete(tells,str); } + + static void eventChangeIMC2Passwords(){ + clientpass = alpha_crypt(10); + serverpass = alpha_crypt(10); + SECRETS_D->SetSecret("IMC2_CLIENT_PW", clientpass); + SECRETS_D->SetSecret("IMC2_SERVER_PW", serverpass); + return; + } + + int UnSetAutoDisabled(int x){ + //This is just for taking away automatic disablement. + //For enabling/disabling, see the mudconfig command. + if(!autodisabled) return 0; + autodisabled = 0; + if(x){ + eventChangeIMC2Passwords(); + } + if(unguarded((:directory_exists(path_prefix(SaveFile)):))){ + SaveObject(SaveFile,1); + RELOAD_D->eventReload(this_object(), 2, 1); + } + return autodisabled; + } + + void keepalive(string args, object who){ + send_packet(who->GetName(), "keepalive-request", "*", "*", 0); + } + + int GetEnabled(){ + return !(DISABLE_IMC2); + } + +varargs string *GetMudList(int online){ + mixed muds = filter(keys(mudinfo), (: stringp($1) :)); + if(online) muds = filter(muds, (: mudinfo[$1]["online"] :)); + return muds; +} + +varargs string GetMudName(string name, int online){ + mixed muds = filter(keys((mudinfo || ([]))), (: stringp($1) :)); + if(member_array(name, muds) != -1) return name; + foreach(string mud in muds){ + if(lower_case(mud) == lower_case(name)){ + if(!online) return mud; + else if(mudinfo[mud]["online"]) return mud; + } + } + return 0; +} diff --git a/lib/secure/save/backup/network.6666.orig b/lib/secure/save/backup/network.6666.orig new file mode 100644 index 0000000..f176322 --- /dev/null +++ b/lib/secure/save/backup/network.6666.orig @@ -0,0 +1,35 @@ +#ifndef __NETWORK_H +#define __NETWORK_H + +#include + +#define MUD 0 +#define STREAM 1 +#define DATAGRAM 2 +#define STREAM_BINARY 3 +#define DATAGRAM_BINARY 4 + +#define OFFSET_RCP -10 +#define OFFSET_HFTP -6 +#define OFFSET_HTTP 1 +#define OFFSET_FTP -1 +#define OFFSET_ECHO 2 +#define OFFSET_FLASH 3 +#define OFFSET_OOB 6 +#define OFFSET_ICP 6 + +#define PORT_ADMIN 17010 +#define PORT_ECHO (query_host_port() + OFFSET_ECHO) +#define PORT_FLASH (query_host_port() + OFFSET_FLASH) +#define PORT_FTP (query_host_port() + OFFSET_FTP) +#define PORT_HFTP (query_host_port() + OFFSET_HFTP) +#define PORT_HTTP (query_host_port() + OFFSET_HTTP) +#define PORT_ICP (query_host_port() + OFFSET_ICP) +#define PORT_OOB (query_host_port() + OFFSET_OOB) +#define PORT_RCP (query_host_port() + OFFSET_RCP) +#define PORT_UDP (query_host_port() + 8) + +#define MIN_PASV_PORT (query_host_port() - 65) +#define MAX_PASV_PORT (query_host_port() - 11) + +#endif /* __NETWORK_H */ diff --git a/lib/secure/save/backup/rooms.1599371141 b/lib/secure/save/backup/rooms.1599371141 new file mode 100644 index 0000000..b859dd9 --- /dev/null +++ b/lib/secure/save/backup/rooms.1599371141 @@ -0,0 +1,20 @@ +#ifndef s_rooms_h +#define s_rooms_h + +#include + +#define ROOM_ZERO "/domains/town/room/start" +#define ROOM_ARCH "/secure/room/arch" +#define ROOM_CATCH_TELL DIR_STANDARD_DOMAIN "/room/catchtell" +#define ROOM_DEATH DIR_STANDARD_DOMAIN "/room/death" +#define ROOM_FREEZER DIR_STANDARD_DOMAIN "/room/freezer" +#define ROOM_FURNACE DIR_STANDARD_DOMAIN "/room/furnace" +#define ROOM_NETWORK "/secure/room/network" +#define ROOM_POD DIR_STANDARD_DOMAIN "/room/pod" +#define ROOM_ROUTER "/secure/room/router" +#define ROOM_START DIR_STANDARD_DOMAIN "/room/start" +#define ROOM_VIRT_VOID DIR_STANDARD_DOMAIN "/virtual/void" +#define ROOM_VOID DIR_STANDARD_DOMAIN "/room/void" +#define ROOM_WIZ DIR_STANDARD_DOMAIN "/room/wiz_hall" + +#endif /* s_rooms_h */ diff --git a/lib/secure/save/backup/secrets.orig b/lib/secure/save/backup/secrets.orig new file mode 100644 index 0000000..c5f5541 --- /dev/null +++ b/lib/secure/save/backup/secrets.orig @@ -0,0 +1,11 @@ +#ifndef s_secrets_h +#define s_secrets_h +#define IRN_PASSWORD "Alpha" +#define IRN_PASSWORD1 "Bravo" +#define IRN_PASSWORD2 "Charlie" +#define IRN_PASSWORD3 "Delta" +#define IMC2_CLIENT_PW "clientpass" +#define IMC2_SERVER_PW "serverpass" +#define I3_SERVER_PW 1234567890 +#define INSTANCE_PW "1234567890" +#endif /* s_secrets_h */ diff --git a/lib/secure/save/boards/admin_board.o b/lib/secure/save/boards/admin_board.o new file mode 100644 index 0000000..b397e7c --- /dev/null +++ b/lib/secure/save/boards/admin_board.o @@ -0,0 +1,4 @@ +#/secure/daemon/bboard.c +__Owner "CMDS" +__Posts ({(["author":"Cratylus","time":1259341215,"post":"This is more or less an \"instrument panel\" room for the mud, for admins only. Most of the stuff here is legacy from earlier versions of the lib, so looking at the panel and stuff probably won't do or mean much anymore. However, you can still get a snapshot of what the mud is up to with: exa screen Below here is a network room you can hang out in to monitor network activity. ","subject":"this room","read":({"cratylus",}),]),}) +Location "/secure/room/arch" diff --git a/lib/secure/save/boards/adv_guild_board.o b/lib/secure/save/boards/adv_guild_board.o new file mode 100644 index 0000000..5d14b31 --- /dev/null +++ b/lib/secure/save/boards/adv_guild_board.o @@ -0,0 +1,4 @@ +#/secure/daemon/bboard.c +__Owner "GENERAL" +__Posts ({(["time":1259344301,"author":"Cratylus","post":"You can now be guided through some basic \"getting started\" stuff, even leveling up! Go to Kim's bookstore and \"buy hint book from kim\" The hint book walks you through various hidden features and will get you used to how things in general work. Enjoy! ","read":({"cratylus",}),"subject":"cheats!",]),}) +Location "/domains/town/room/adv_guild" diff --git a/lib/secure/save/boards/builder_board.o b/lib/secure/save/boards/builder_board.o new file mode 100644 index 0000000..060905b --- /dev/null +++ b/lib/secure/save/boards/builder_board.o @@ -0,0 +1,4 @@ +#/secure/daemon/bboard.c +__Owner "GENERAL" +__Posts ({(["time":1203357839,"author":"Cratylus","post":" Hey gang! Dead Souls now has a new type of player called a \"builder\". They can use the QCS but they don't have access to LPC code. See: http://dead-souls.net/ds-admin-faq.html#133 Other than being able to create stuff in their homedirs (which can't be used for game advantage) and being able to teleport to their rooms, they are just like regular players. Builders, please make sure you read the Builders' Guidebook. If you've lost yours, you can get another copy from the chest in your workroom. Type: home Then: open chest Then: look in chest Then: get book from chest Also remember you need to be holding the Creator Staff in order for the QCS commands to work. -Crat ","read":({"cratylus","babylon",}),"subject":"Introducing the Builder position",]),}) +Location "/domains/default/room/builder_hall" diff --git a/lib/secure/save/boards/immortal_board.o b/lib/secure/save/boards/immortal_board.o new file mode 100644 index 0000000..7f0e35d --- /dev/null +++ b/lib/secure/save/boards/immortal_board.o @@ -0,0 +1,4 @@ +#/secure/daemon/bboard.c +__Owner "GENERAL" +__Posts ({(["time":1132694785,"author":"Cratylus","post":"A couple of hints: - Look in your workroom's chest for useful wiz toys. - Read /doc/README for instructions on enabling intermud channels. - There's a creator's manual in your workroom's chest. It is your friend. - Information and documentation is available at: http://dead-souls.net/ - Almost everything you need is in /doc. Whatever isn't there, you wouldn't understand anyway. - Make an effort to find an answer of your own before asking for help. - If you ask for help, be polite. - Have fun. ","read":({"cratylus","babylon","jayren",}),"subject":"Welcome to Dead Souls",]),(["time":1132694930,"author":"Cratylus","post":"- When your stuff won't update, the elog command will help you track down the problem. - When players generate runtime errors, detailed error messages get logged to /log/player_errors . ","read":({"cratylus","babylon","jayren",}),"subject":"player errors",]),(["time":1134153426,"author":"Cratylus","post":"Dead Souls now sports a groovy new creation system. We're still working out the kinks and still adding features, but it's stable enough to try out. The main commands for this new system are: create, modify, add, delete, and copy. For detailed info, type: help creation ","read":({"cratylus","babylon",}),"subject":"NEW creation system",]),}) +Location "/domains/default/room/wiz_hall2" diff --git a/lib/secure/save/boards/visitor_board.o b/lib/secure/save/boards/visitor_board.o new file mode 100644 index 0000000..e20bad2 --- /dev/null +++ b/lib/secure/save/boards/visitor_board.o @@ -0,0 +1,4 @@ +#/secure/daemon/bboard.c +__Owner "GENERAL" +__Posts ({}) +Location "/domains/campus/room/lounge" diff --git a/lib/secure/save/boards/ylsrim.o b/lib/secure/save/boards/ylsrim.o new file mode 100644 index 0000000..2bd4e13 --- /dev/null +++ b/lib/secure/save/boards/ylsrim.o @@ -0,0 +1,4 @@ +#/secure/daemon/bboard.c +__Owner "Ylsrim" +__Posts ({}) +Location "/domains/Ylsrim/room/adv_hall" diff --git a/lib/secure/save/creators/b/babylon.o b/lib/secure/save/creators/b/babylon.o new file mode 100644 index 0000000..7e4bc1e --- /dev/null +++ b/lib/secure/save/creators/b/babylon.o @@ -0,0 +1,132 @@ +#/secure/save/creators/b/babylon.c +InternalDesc 0 +Opacity 0 +PersistentInventory 0 +PersistentInventoryEnabled 0 +ProperNoun 1 +Modify 1 +Short "First Admin $N%^RESET%^%^RESET%^%^RESET%^%^RESET%^" +CapName "Babylon" +ExternalDesc "$N is nondescript." +Invisible 0 +Items ([]) +Properties (["wizmapping":1,"EdWarned":1,"minimapping":0,"LastLocation":"/domains/default/virtual/void/user_babylon",]) +Inventory ({"([\"Wielded\":0,\"Value\":0,\"Class\":1,\"Worn\":0,\"Deterioration\":0,\"Broken\":0,\"Poison\":0,\"Mass\":20,\"#base_name#\":\"/domains/voluntaria/obj/captainkey\",\"Cost\":1000,\"Properties\":([]),])","([\"charge\":90,\"Value\":0,\"Worn\":0,\"Broken\":0,\"Deterioration\":0,\"Poison\":0,\"Mass\":50,\"#base_name#\":\"/domains/default/armor/breather\",\"Cost\":100000,\"Properties\":([]),])","([\"Wielded\":1,\"Value\":0,\"Class\":100,\"Worn\":({\"right hand\",\"left hand\",}),\"Deterioration\":0,\"Broken\":0,\"Poison\":0,\"Mass\":100,\"#base_name#\":\"/secure/obj/staff\",\"Cost\":0,\"Properties\":([\"no steal\":1,]),])","([\"charge\":1000,\"Value\":0,\"Worn\":0,\"Broken\":0,\"Deterioration\":0,\"Poison\":0,\"Mass\":50,\"#base_name#\":\"/domains/default/armor/breather\",\"Cost\":100000,\"Properties\":([]),])",}) +anchored 0 +Messages (["telin":"$N teleports in.","leave":"$N leaves $D.","telout":"$N teleports away.","vis":"$N appears.","home":"$N goes home.","invis":"$N disappears.","come":"$N enters.","dest":"$N dests $O.","clone":"$N clones $O.",]) +RestrictedChannels ({}) +NoChanColors 0 +GagMutes (["remote_mute":0,"remote_gag":0,"local_mute":0,"local_gag":0,]) +Paused 0 +localcmds ({"parserefresh","quit","work","pwd","cwd","popd","pushd","nmsh","cd","nickname","unalias","alias","",}) +parsed_command "" +HistorySize 50 +History ([50:"look ship",49:"l",48:"remove a99",47:"goto start",46:"update",45:"go south",44:"s",43:"n",42:"navicomputer voluntaria",41:"navicompupter voluntaria",40:"navicomp voluntaria",39:"go west",38:"go up",37:"up",36:"open up",35:"unlock up with key",34:"unlock up",33:"enter spaceship",32:"gridconfig reset",31:"create room north bushese",30:"modify here short Tangled Bushes",29:"create room east bushesse",28:"create room north start",27:"create room east bushess",26:"create room south bushessw",25:"look up",24:"get key from corpse",23:"zap galt",22:"navicomputer oogtopia",21:"goto bridge",20:"open airlock",19:"open s",18:"goto airlock",17:"wear a99",16:"get a99 from corpse",15:"take a99",14:"zap handler",13:"enter spaceshup",12:"open south",11:"nevicomputer oogtopia",10:"boards",9:"uptime",8:"people",7:"source /realms/babylon/.profile",6:"south",5:"stand",4:"wield staff",3:"get a99 from chest",2:"get staff from chest",1:"open chest",0:"update bin",]) +Nicknames ([]) +Aliases (["east":"go east","northeast":"go northeast","southeast":"go southeast","mwhere":"findobj $*","prac":"skills","sco":"score","x":"look at $*","w":"go west","u":"go up","out":"go out","t":"tell $*","s":"go south","practice":"skills","vnum":"help find","p":"people","north":"go north","south":"go south","bio":"biography","n":"go north","l":"look $*","west":"go west","k":"kill $*","northwest":"go northwest","southwest":"go southwest","zlist":"domains","i":"inventory","owhere":"findobj $*","e":"go east","d":"go down","c":"cre $*","alist":"ls /domains","nw":"go northwest","inv":"inventory","examine":"look at $*","trophy":"kills","up":"go up","chat":"newbie $*","dc":"dchat $*","sw":"go southwest","exa":"look at $*","ig":"intergossip $*","loot":"get all from $*","ic":"intercre $*","peace":"quell","inf":"score","down":"go down","lp":"lpuni $*","ne":"go northeast","eq":"equipment","exit":"go out","se":"go southeast","sc":"status",]) +Xverbs (["'":"say $*","]":"] $*",":":"emote $*","\"":"say $*",]) +Directories (["current":"/domains/voluntaria/room","home":0,"previous":"/domains/voluntaria",]) +Prompt "cwd" +Terminal "xterm" +Blocked ([]) +Screen ({79,24,}) +MessageQueue 0 +PauseMessages 0 +annoyblock 0 +MessageExceptions 0 +BlockAnnoying 0 +Age 1895 +WhereBlock 0 +Brief 0 +LoginTime 1599391597 +BirthTime 1599031093 +RescueBit 0 +Password "naoccnjm!gcklfkdkkmf`bink`dcld`dcfbkolg`l" +Email "babylon_horuv@zoho.com" +RealName "Babylon" +Rank "citizen" +LoginSite "/domains/voluntaria/room/start" +HostSite "127.0.0.1" +WebPage 0 +News (["admin":1248026806,"general":1233553350,"creator":1233553350,]) +Marriages ({}) +Paranoia (["homeroom":"/tmp/workroom",]) +MaxCarry 0 +PreventDrop 0 +DestructOnDrop 0 +PreventGet 0 +NoSink 0 +Position 2 +Undead 0 +UndeadType 0 +Mount 1 +Riders ({}) +BodyMass 0 +SaveRecurse 0 +Saved ({"Properties",}) +HealthPoints 274 +MagicPoints 349 +ExperiencePoints 4070 +ExperienceDebt 0 +melee 0 +godmode 0 +Alcohol 0 +Caffeine 0 +Food 0 +Drink 0 +Poison 0 +Sleeping 0 +StaminaPoints 277.600006 +Torso "torso" +Biter 0 +keepalive 0 +Fingers (["right hand":5,"left hand":5,]) +Limbs (["head":(["children":({}),"armors":262913,"parent":"neck","class":1,"health":320,]),"right leg":(["children":({"right foot",}),"armors":1049761,"parent":"torso","class":2,"health":160,]),"right foot":(["children":({}),"armors":241,"parent":"right leg","class":4,"health":80,]),"neck":(["children":({"head",}),"armors":786433,"parent":"torso","class":1,"health":320,]),"left foot":(["children":({}),"armors":241,"parent":"left leg","class":4,"health":80,]),"left arm":(["children":({"left hand",}),"armors":1253385,"parent":"torso","class":2,"health":160,]),"torso":(["children":({"neck","right leg","left leg","right arm","left arm",}),"armors":1538049,"parent":0,"class":1,"health":320,]),"left leg":(["children":({"left foot",}),"armors":1049761,"parent":"torso","class":2,"health":160,]),"right hand":(["children":({}),"armors":98319,"parent":"right arm","class":4,"health":80,]),"right arm":(["children":({"right hand",}),"armors":1253385,"parent":"torso","class":2,"health":160,]),"left hand":(["children":({}),"armors":98319,"parent":"left arm","class":4,"health":80,]),]) +MissingLimbs ([]) +firearms_wounds 0 +Falling 0 +FallCount 1 +ExtraChannels ({"explorer","builder","admin","error","cre","newbie","gossip","ds","ds_test","lpuni","death","connections","intercre","dchat","intermud",}) +Agent 0 +Blind 0 +Custom (["stats":15,"deviations":4,"deviating":0,]) +LightSensitivity ({25,7500,}) +Resistance (["low":0,"high":0,"immune":0,"medium":0,"none":134217726,]) +Stats (["agility":(["class":3,"points":0,"level":35,]),"wisdom":(["class":3,"points":0,"level":58,]),"speed":(["class":3,"points":0,"level":44,]),"intelligence":(["class":1,"points":0,"level":45,]),"strength":(["class":3,"points":0,"level":34,]),"durability":(["class":4,"points":0,"level":31,]),"charisma":(["class":2,"points":0,"level":48,]),"coordination":(["class":2,"points":0,"level":42,]),"luck":(["class":3,"points":0,"level":22,]),]) +Polyglot 0 +Languages (["english":(["native":1,"name":"English","points":0,"level":100,]),"common":(["native":0,"name":"Common","points":0,"level":100,]),]) +DefaultLanguage "Common" +TalkHist (["shout":({"2020.09.01-23.40,36 %^BOLD%^BLUE%^Clerk shouts in Common,%^RESET%^ \"This office duly records and announces that Fluffster has divorced Deskarnull!%^RESET%^\"","2020.09.01-23.41,21 %^BOLD%^BLUE%^Clerk shouts in Common,%^RESET%^ \"This office duly records and announces that Deskarnull has divorced Fluffster!%^RESET%^\"",}),"say":({"2020.09.01-19.36,19 Beggar says in Common, \"%^BOLD%^CYAN%^Hi, Babylon.%^RESET%^\"","2020.09.01-23.31,00 Brandy says in Common, \"%^BOLD%^CYAN%^Thank you, Fluffster. Feel free to ask me for my special menu.%^RESET%^\"","2020.09.01-23.31,49 Fluffster says in Common, \"%^BOLD%^CYAN%^\"special menu\".%^RESET%^\"","2020.09.01-23.31,59 Brandy says in Common, \"%^BOLD%^CYAN%^I currently supply guinness for 1, wine for 2, and whiskey for 3.%^RESET%^\"","2020.09.01-23.31,59 Brandy says in Common, \"%^BOLD%^CYAN%^Prices are in gold of course.%^RESET%^\"","2020.09.01-23.32,11 Brandy says in Common, \"%^BOLD%^CYAN%^I currently supply yellow spice for 8, green spice for 12, speedalin for 2, javarin for 1, eve tonic for 50, spazalin for 3, and blue spice for 10.%^RESET%^\"","2020.09.01-23.32,11 Brandy says in Common, \"%^BOLD%^CYAN%^Prices are in gold of course.%^RESET%^\"","2020.09.01-23.33,17 Brandy says in Common, \"%^BOLD%^CYAN%^Thank you, Fluffster. Feel free to ask me for my special menu.%^RESET%^\"","2020.09.01-23.40,36 Clerk says in Common, \"%^BOLD%^CYAN%^The divorce is complete.%^RESET%^\"","2020.09.01-23.40,51 Clerk says in Common, \"%^BOLD%^CYAN%^Fluffster, you are confusing me.%^RESET%^\"","2020.09.01-23.40,58 Clerk says in Common, \"%^BOLD%^CYAN%^Hmmm...%^RESET%^\"","2020.09.01-23.41,21 Clerk says in Common, \"%^BOLD%^CYAN%^The divorce is complete.%^RESET%^\"",}),"tell":({"2020.09.03-03.55,01 %^BOLD%^RED%^Shadyman@QS tells you:%^RESET%^ Don't mind Quix, he's the resident grumpy old man ;)",}),]) +SpeakColor "CYAN%^" +Town "World" +Race "human" +Gender "neuter" +Level 1 +Skills (["psionic defense":(["class":3,"points":0,"level":2,]),"magic defense":(["class":2,"points":0,"level":3,]),"melee defense":(["class":2,"points":1599,"level":2,]),"projectile attack":(["class":1,"points":0,"level":1,]),"blunt defense":(["class":1,"points":0,"level":2,]),"knife defense":(["class":1,"points":0,"level":2,]),"melee attack":(["class":2,"points":265,"level":1,]),"projectile defense":(["class":2,"points":0,"level":1,]),"blade defense":(["class":2,"points":245,"level":2,]),"bargaining":(["class":2,"points":0,"level":4,]),"magic attack":(["class":2,"points":0,"level":3,]),"blunt attack":(["class":1,"points":1268,"level":3,]),"knife attack":(["class":1,"points":0,"level":3,]),"blade attack":(["class":2,"points":0,"level":1,]),]) +Morality 0 +Class "explorer" +Clan 0 +SkillModifiers ([]) +Religion ({0,0,}) +Wimpy 20 +Dead 0 +WimpyCommand "go out" +Currency (["silver":0,]) +Bank ([]) +SpellBook ([]) +QuestPoints 0 +QuestBook ([]) +isPK 0 +Attackable 1 +NoCondition 0 +Titles ({}) +Muffed ({}) +Deaths ({(["date":"Wed Sep 02 00:33:22 2020","enemy":"Fighter",]),(["date":"Fri Sep 04 21:09:21 2020","enemy":"Outer space",]),(["date":"Sat Sep 05 23:12:58 2020","enemy":"Outer space",]),(["date":"Sun Sep 06 04:16:32 2020","enemy":"Outer space",]),}) +TrainingPoints 0 +TitleLength 1 +telopt_ip 0 +showgrid 0 +wizvision 0 +CreatorAge 0 +CreatorBirth 1599031178 +LivingShort "First Admin $N%^RESET%^%^RESET%^%^RESET%^%^RESET%^" diff --git a/lib/secure/save/files.o b/lib/secure/save/files.o new file mode 100644 index 0000000..ed2a67d --- /dev/null +++ b/lib/secure/save/files.o @@ -0,0 +1,4 @@ +#/secure/daemon/file.c +all_dirs ({"/www/client","/domains/learning/etc","/domains/town/room","/domains/alpha/obj","/secure/cmds/hm","/domains/amigara/weap","/secure/cfg","/domains/town/save","/powers/trades","/lib/virtual","/doc/lfun/lib/firearm","/doc/lfun/lib/leader","/secure/tmp","/daemon/services","/domains/town/virtual/void","/domains/amigara/amigara/npc","/verbs/admins","/domains/default/virtual/sky","/domains/cave/weap","/domains/Praxis","/doc/efun/parsing","/doc/lfun/lib/shell","/domains/Ylsrim/obj","/tmp/suicide","/domains/default/vehicles","/log/watch","/doc/lfun/lib/look","/doc/lfun/lib/worn_storage","/obj","/domains/amigara/amigara/armor","/std","/domains/learning/armor","/doc/lfun/lib/server","/lib/daemons","/domains/alpha","/domains/default/etc","/secure/lib/net","/domains/default/virtual/arena","/doc/lfun/lib/body","/doc/lfun/lib/abilities","/domains/default/chamber","/doc/lfun/lib/chat","/doc/tmp","/secure/obj","/domains/learning/npc","/lib/std","/domains/amigara/amigara","/secure/room","/domains/Ylsrim/broken","/domains","/verbs/rooms","/domains/default/vehicle","/doc/help/hm","/domains/default/virtual","/doc/lfun/lib/limb","/www/lpmuds/intermud_files","/domains/amigara/txt","/domains/fort/room/bak","/secure/lib/include","/domains/amigara","/domains/Ylsrim/fish","/domains/town/virtual/oldsky1411894845","/domains/Praxis/adm","/secure/cmds","/secure/cmds/players","/lib/comp","/verbs/rooms/include","/doc/help/races","/domains/amigara/amigara/obj","/secure/include","/lib/include","/doc/lfun/lib/fuel","/domains/Praxis/obj/weapon","/log/law/sites-register","/domains/default/weap","/domains/default/npc","/domains/default","/domains/cave/doors","/doc/efun","/doc/efun/strings","/domains/Ylsrim/armor","/doc/applies","/shadows","/domains/Praxis/death","/domains/campus/txt","/domains/Praxis/obj/armour","/domains/cave/virtual","/cmds/hm","/std/lib","/domains/default/creator","/verbs/spells","/secure/modules","/domains/Praxis/obj/magic","/doc/manual","/log/router","/domains/Ylsrim/virtual","/daemon","/domains/campus","/news","/doc/help/players","/log/chan","/doc/faq","/doc/lfun/lib/room","/doc/efun/arrays","/domains/town/txt","/doc/lfun/lib/ftp_data_connection","/doc/lfun/lib/combat","/daemon/include","/domains/campus/txt/jenny","/secure/cmds/common","/domains/campus/doors","/domains/learning/obj","/domains/fort/etc","/cmds/common","/verbs/items","/doc/lpc/concepts","/verbs/players/include","/doc/lfun/lib","/domains/amigara/virtual/void","/doc/lfun/lib/connect","/doc/lfun/lib/living","/domains/cave/armor","/domains/amigara/adm","/doc","/doc/bguide","/domains/cave/txt","/domains/alpha/virtual","/doc/lfun/lib/spell","/log/law/sites-tempban","/domains/Praxis/orc_valley","/domains/alpha/doors","/save","/log/adm","/doc/efun/compile","/domains/amigara/amigara/chamber","/domains/alpha/room","/domains/town/virtual/oldsky1411894794","/domains/alpha/save","/www/doc","/doc/lfun/lib/clean","/doc/lfun/lib/id","/doc/efun/mappings","/domains/fort/doors","/doc/help/classes","/doc/lfun/lib/client","/domains/examples","/domains/campus/weap","/doc/lpc/etc","/log/errors","/domains/fort/weap","/domains/amigara/amigara/vehicle","/doc/applies/interactive","/verbs/powers","/doc/lfun/lib/classes","/domains/campus/adm","/domains/default/obj","/lib/events","/domains/campus/armor","/cmds","/verbs/creators","/doc/lfun/lib/daemon","/domains/learning/room","/doc/lfun/lib/holder","/log/reports","/domains/amigara/amigara/virtual","/domains/amigara/doors","/domains/learning/save","/domains/amigara/etc","/powers/spells","/lib/lvs","/domains/town/doors","/domains/fort/npc","/cmds/creators","/daemon/tmp","/log/suicides","/save/kills/x","/save/kills/u","/save/kills/t","/domains/alpha/armor","/doc/lfun/lib/position","/save/kills/s","/save/kills/r","/log/law/names","/save/kills/o","/save/kills/n","/doc/lfun/lib/race","/doc/lfun/lib/bonus","/save/kills/m","/doc/lfun/lib/interactive","/save/kills/l","/include","/save/kills/k","/save/kills/j","/save/kills/i","/domains/town/virtual/sub","/save/kills/h","/save/kills/g","/domains/Praxis/cemetery/mon","/save/kills/f","/save/kills/e","/save/kills/d","/save/kills/c","/save/kills/b","/save/kills/a","/verbs/powers/powers","/log/errors/archive","/ftp","/domains/cave/adm","/domains/fort/armor","/verbs/builders","/domains/campus/etc","/domains/amigara/amigara/meals","/verbs/admins/include","/domains/learning/meals","/secure/daemon/imc2server","/doc/lfun/lib/meal","/domains/amigara/room","/doc/lfun/lib/player","/doc/lfun/lib/bank","/domains/campus/txt/ai/charly/bak","/www/errors","/domains/amigara/armor","/doc/phints","/doc/lpc/constructs","/doc/lfun/lib/clip","/doc/efun/mudlib","/domains/amigara/save","/doc/help","/domains/amigara/chamber","/cmds/builders","/domains/cave","/doc/lfun/lib/flashlight","/www/lpmuds/links_files","/domains/amigara/amigara/weap","/log/secure","/domains/town/armor","/domains/cave/room","/domains/cave/save","/doc/lfun/lib/torch","/domains/fort","/domains/amigara/npc","/domains/campus/txt/ai/charles/bak2","/doc/efun/functions","/secure/daemon/i3router","/doc/help/religion","/domains/amigara/vehicle","/verbs/creators/include","/doc/efun/internals","/domains/alpha/txt","/domains/cave/etc","/domains/amigara/virtual","/doc/lfun/lib/vendor","/doc/lpc/advanced","/secure/cfg/races","/domains/alpha/virtual/void","/domains/Praxis/obj","/doc/help/creators","/verbs/undead","/secure/daemon","/www/lpmuds/downloads_files","/lib/props","/domains/town/weap","/doc/misc","/log/author_stats","/doc/efun/numbers","/domains/fort/obj","/domains/campus/npc","/doc/lfun/lib/round","/secure/cmds/players/include","/doc/lfun/lib/load","/powers/feats","/std/board","/doc/lfun/lib/burn","/doc/lfun/lib/corpse","/domains/default/npc/quarantine","/domains/town/virtual","/domains/Praxis/quests","/domains/town/npc","/www","/verbs/common/include","/log","/domains/campus/txt/ai/charles/bak2/bak1","/doc/build","/doc/efun/calls","/domains/cave/npc","/domains/learning/virtual/void","/domains/default/doors","/secure/cfg/classes","/verbs/common","/domains/alpha/adm","/doc/lfun/lib/genetics","/doc/lfun/lib/chapel","/doc/lfun/lib/battery","/doc/lpc/types","/secure/cmds/admins","/powers","/domains/amigara/obj","/domains/default/room","/secure/cmds/creators/include","/domains/town/txt/shame","/domains/default/save","/cmds/admins","/doc/applies/parsing","/doc/lfun/lib/virt_sky","/doc/lfun/lib/npc","/secure/cmds/creators","/domains/cave/meals","/cmds/players","/secure/verbs","/domains/learning/chamber","/domains/Ylsrim/adm","/doc/lfun/lib/light","/doc/lfun/lib/messages","/domains/campus/txt/ai/charles","/www/articles","/www/logs","/domains/amigara/amigara/txt","/doc/lfun/lib/poison","/doc/efun/buffers","/domains/learning","/domains/Ylsrim/room","/domains/Praxis/obj/mon","/doc/lfun/lib/ftp_client","/domains/Ylsrim/save","/doc/lpc","/doc/help/law","/doc/efun/floats","/domains/Ylsrim","/log/law","/domains/learning/vehicle","/doc/guide","/doc/efun/all","/domains/campus/obj","/doc/efun/objects","/doc/lfun/lib/clerk","/doc/lfun/lib/follow","/doc/lfun/lib/fish","/domains/default/armor","/domains/alpha/etc","/doc/efun/system","/lib/user","/domains/learning/virtual","/open","/doc/sefun","/doc/lfun/lib/bot","/log/imc2_server/foo.txt","/www/articles/old","/secure/daemon/include","/doc/lfun/lib/post_office","/domains/campus/txt/ai","/domains/campus/meals","/doc/lfun/lib/clay","/secure/sefun","/log/imc2_server","/powers/prayers","/lib/daemons/include","/domains/town/obj","/secure/cmds/builders","/doc/lfun/lib/donate","/domains/town/virtual/sky","/doc/lfun/lib/clan","/domains/Praxis/cemetery","/obj/book_source","/domains/Ylsrim/etc","/doc/efun/mixed","/domains/campus/chamber","/doc/lfun/lib/door","/verbs/items/include","/doc/applies/master","/save/kills","/log/law/sites-watch","/domains/learning/txt","/domains/Ylsrim/weapon","/domains/alpha/meals","/domains/cave/obj","/doc/help/avatars","/doc/efun/filesystem","/www/lpmuds","/domains/town","/domains/town/virtual/oldsky1411894845/oldsky1411894845","/domains/amigara/amigara/virtual/void","/log/archive","/doc/lfun/lib/armor","/domains/campus/room","/domains/fort/room","/domains/campus/save","/domains/fort/meals","/secure","/log/open","/lib","/domains/amigara/amigara/adm","/secure/lib/net/include","/doc/lfun/lib/weapon","/powers/psionics","/verbs","/doc/lfun/lib/lamp","/doc/old","/doc/lfun/lib/fishing","/domains/alpha/npc","/log/law/email","/secure/verbs/creators","/domains/amigara/meals","/doc/lfun/lib/equip","/log/chan/archive","/doc/lfun/lib/creator","/log/law/adm","/domains/examples/room","/domains/campus/txt/ai/charly","/doc/efun/general","/domains/town/meals","/verbs/players","/domains/alpha/weap","/domains/Praxis/data","/secure/lib","/domains/town/virtual/space","/doc/lfun/lib/furnace","/domains/Ylsrim/npc","/doc/lfun/all","/secure/lib/std","/www/images","/secure/obj/include","/domains/Ylsrim/meal","/doc/lfun/lib/deterioration","/domains/amigara/amigara/etc","/doc/hbook","/doc/efun/interactive","/doc/efun/sockets","/domains/learning/weap","/doc/cheats","/domains/learning/adm","/obj/include","/doc/lfun/lib/container","/doc/lpc/basic","/domains/Ylsrim/virtual/desert","/domains/Praxis/obj/misc","/domains/amigara/amigara/room","/doc/lfun/lib/potion","/cmds/creators/include","/secure/npc","/domains/amigara/amigara/save","/doc/lfun","/domains/Praxis/attic","/domains/town/virtual/bottom","/www/cgi","/doc/lfun/lib/manipulate","/domains/town/virtual/forest","/domains/default/virtual/void","/cfg","/domains/town/virtual/oldsky1411894794/oldsky1411894794","/secure/scripts","/tmp","/domains/town/virtual/surface","/domains/amigara/amigara/doors","/doc/lpc/intermediate","/domains/learning/doors","/doc/lfun/lib/file","/doc/lfun/lib/damage","/domains/Praxis/mountains","/log/law/sites-misc",}) +all_files ({"/std/board/bboard.c","/log/chan/archive/muds-2010.09.24-05.45,48","/log/chan/archive/muds-2010.11.10-17.45,48","/domains/fort/room/west_wall_5.c","/log/chan/archive/muds-2010.10.29-23.45,48","/domains/fort/obj/mtable.c","/save/deviation.o","/log/chan/archive/muds-2010.12.10-06.45,48","/secure/include/network.8888.h","/log/chan/archive/sport-2013.08.03-14.13,15","/log/chan/archive/dgd-2009.03.25-16.11,20","/domains/campus/txt/ai/charly/bak/wins","/secure/cmds/admins/encre.c","/save/kills/h/hkfboocnmig","/log/chan/archive/muds-2009.05.20-09.06,41","/log/archive/runtime-2009.03.16-03.30,39","/secure/cfg/mudos.autobak.8000","/cmds/creators/debug.c","/secure/daemon/include/character.h","/save/portal.2222.o","/save/kills/m/mjfildmmh","/log/chan/archive/muds-2010.09.02-18.45,48","/domains/amigara/amigara/room/guard_room.c","/log/chan/archive/muds-2009.04.10-23.28,44","/domains/town/obj/357shell.c","/doc/lfun/lib/id/GetCapName","/secure/daemon/chat.c","/log/chan/archive/muds-2010.11.16-18.45,48","/log/chan/archive/imudnews-2009.03.27-17.11,20","/log/chan/archive/muds-2010.11.24-04.45,48","/lib/include/bait.h","/log/chan/archive/muds-2010.11.15-11.45,48","/log/chan/archive/muds-2009.05.23-04.21,26","/log/chan/archive/dchat-2010.08.20-15.45,48","/doc/lfun/lib/clip/GetMillimeter","/log/chan/archive/muds-2010.12.15-00.45,48","/domains/town/armor/bandanna.c","/doc/lfun/all/SetAmmoType","/powers/spells/greater_fireball.c","/domains/default/room/wiz_corr_south.c","/log/chan/archive/muds-2013.08.02-01.13,15","/domains/campus/txt/lisa.txt","/log/chan/archive/muds-2010.09.08-19.45,48","/verbs/common/yell.c","/log/chan/archive/i2game-2009.05.16-04.59,29","/secure/include/clock.h","/doc/lfun/lib/body/GetMissingLimbParents","/log/chan/archive/muds-2010.11.10-03.45,48","/save/rooms.4444.o","/daemon/tmp/MOUTH_LIPPED+MOUTH_TOOTHED+MOUTH_TONGUED.c","/log/chan/archive/muds-2010.11.01-10.45,48","/log/chan/archive/intergossip-2010.10.10-00.45,48","/log/chan/archive/muds-2013.07.25-06.13,01","/domains/campus/obj/bag.c","/domains/Praxis/court_room.c","/doc/lfun/lib/shell/SetAmmoType","/cmds/creators/events.c","/verbs/players/nominate.c","/log/chan/archive/intergossip-2010.08.02-20.18,42","/log/chan/*dalet:discworld-chat","/doc/efun/all/exec","/lib/events/apply.c","/log/chan/archive/inews-2013.08.23-02.13,15","/domains/Ylsrim/etc/dug_hole.c","/domains/campus/obj/key1.c","/doc/lfun/lib/body/GetBodyComposition","/log/chan/archive/i2news-2009.05.08-21.58,26","/doc/efun/interactive/receive","/doc/efun/objects/master","/daemon/tmp/balrog.c","/secure/cmds/creators/homeroom.c","/log/chan/archive/muds-2009.03.25-17.11,20","/secure/sefun/events.c","/include/race.h","/doc/lfun/all/eventHealDamage","/log/chan/archive/muds-2010.11.08-18.45,48","/domains/campus/obj/.pedestal2.c.swp","/domains/fort/npc/fighter_plain.c","/save/kills/h/hhkaaiijc","/log/chan/archive/muds-2010.11.07-11.45,48","/domains/cave/room/shop.c","/log/chan/archive/muds-2010.12.08-07.45,48","/log/chan/archive/muds-2013.08.23-22.13,15","/log/chan/archive/muds-2010.08.15-23.45,20","/domains/amigara/amigara/room/passage22.c","/log/chan/archive/muds-2010.07.10-19.16,00","/save/kills/n/ndfjnjo","/log/law/sites-misc/foo.txt","/domains/fort/npc/gate_guard.bak2","/domains/fort/room/sroad2.c","/secure/lib/net/ftp_client.c","/secure/include/config.2222.h","/save/kills/x/xkcdlebakdima","/log/chan/archive/muds-2009.04.02-21.51,27","/domains/fort/obj/needle_trap.c","/log/chan/archive/muds-2009.05.24-17.22,24","/obj/light.c","/domains/Praxis/council_hall.c","/save/kills/o/oiliaeegh","/domains/town/virtual/sky/28,4,1.c","/doc/lfun/lib/burn/SetMinHeat","/www/router_rules.html","/domains/cave/obj/cask4.c","/doc/applies/master/valid_socket","/log/chan/archive/muds-2010.11.02-03.45,48","/log/archive/currency-2009.10.05-02.41,35","/lib/user/autosave.c","/log/archive/runtime-2010.07.09-22.16,00","/doc/efun/all/heart_beats","/secure/scripts/ligana.src","/secure/cfg/races/bird","/domains/fort/room/tunnel4.c","/domains/amigara/room/void.c","/domains/campus/armor/chainmail.c","/doc/applies/parsing/parse_command_id_list","/domains/town/save/0^0domains0^0town0^0obj0^0charity.6666.o","/doc/efun/internals/debugmalloc","/log/chan/archive/intergossip-2013.07.29-20.13,15","/verbs/common/include/whisper.h","/domains/campus/room/npath2.c","/log/chan/archive/intergossip-2010.08.23-22.45,48","/www/cgi/index.html","/log/chan/archive/muds-2009.04.12-09.28,44","/domains/fort/room/storeroom2.c","/www/lpmuds/discworld-faq.html","/secure/cmds/admins/unmonitor.c","/domains/campus/room/science5.c","/domains/Ylsrim/room/kaliid6.c","/std/death.c","/secure/daemon/character.c","/save/kills/k/knm","/log/chan/archive/muds-2011.01.09-00.46,13","/log/chan/archive/muds-2009.03.25-03.11,20","/log/chan/archive/muds-2010.11.08-04.45,48","/domains/fort/obj/50round.c","/verbs/rooms/include/fish.h","/log/chan/archive/inews-2013.08.01-01.13,15","/secure/daemon/icp.c","/cmds/players/rwho.c","/domains/town/virtual/sky/23,8,1.c","/domains/fort/room/common19.c","/domains/examples/room/exroom5.c","/save/kills/x/xkcdjcejenmf","/log/chan/archive/i2game-2009.04.28-21.47,39","/doc/efun/system/function_exists","/domains/town/room/cratshack.c","/domains/Praxis/rogue_join.c","/save/kills/j/jbd","/secure/daemon/resolv.c","/doc/efun/all/socket_listen","/save/kills/j/jnhhkfcjm","/domains/cave/weap/longsword.c","/log/chan/archive/sport-2013.08.16-21.13,15","/domains/fort/room/mstreet3.c","/domains/Praxis/hall2.c","/doc/lfun/all/GetRace","/secure/include/origin.h","/doc/lfun/lib/firearm/CanRelease","/doc/efun/mudlib/find_living","/lib/persist.c","/doc/lfun/lib/body/GetMaxHealthPoints","/doc/efun/system/set_reset","/domains/fort/room/common13.c","/cmds/creators/html.c","/log/chan/archive/imudnews-2010.09.26-04.45,48","/domains/Praxis/pub.c","/secure/sefun/security.c","/save/races.6666.o","/www/articles/old/mudmagic.html","/save/unique.6666.o","/log/chan/archive/dgd-2010.09.02-16.45,48","/domains/default/npc/sheep.c","/domains/Praxis/e_boc_la3.c","/doc/efun/all/query_snooping","/save/kills/x/xkcdghamchii","/log/chan/archive/sport-2013.08.20-06.13,15","/doc/sefun/get_object","/log/chan/archive/sport-2013.08.02-20.13,15","/log/chan/archive/inews-2009.05.13-05.59,29","/domains/fort/armor/pillbox_hat.c","/domains/Ylsrim/etc/roof.c","/save/kills/f/ffde","/log/errors/archive/lib-2011.08.23-08.31,52","/domains/fort/room/bwall2.c","/log/chan/archive/muds-2013.08.25-08.13,15","/lib/std/vendor.c","/include/body_types.h","/doc/lfun/lib/chapel/SetAllowSacrifice","/log/chan/archive/muds-2010.09.10-17.45,48","/daemon/tmp/shop.c","/log/chan/archive/imudnews-2010.08.20-00.45,48","/domains/Ylsrim/weapon/stick.c","/log/chan/archive/intergossip-2013.08.08-15.13,15","/doc/lfun/all/eventInitiate","/log/chan/archive/muds-2010.10.23-21.45,48","/domains/fort/doors/fishmonger.c","/include/astar.h","/doc/help/creators/debugging","/domains/Praxis/yard.c","/log/archive/icp-2009.03.16-11.30,39","/doc/efun/all/bind","/verbs/builders/reload.c","/log/chan/archive/sport-2013.08.17-14.13,15","/domains/campus/txt/ai/charles/bak2/fred","/domains/amigara/amigara/room/passage19.c","/secure/sefun/copy.c","/secure/sefun/economy.c","/domains/campus/weap/9mmpistol_loaded.c","/log/chan/archive/muds-2013.08.02-14.13,15","/doc/efun/all/allocate","/verbs/players/target.c","/domains/cave/obj/rack.c","/verbs/rooms/enter.c","/domains/fort/room/common5.c","/doc/efun/all/in_edit","/doc/lfun/lib/clan/SetClanObject","/log/chan/archive/muds-2010.11.10-16.45,48","/log/chan/dgd","/log/chan/archive/sport-2013.08.12-06.13,15","/doc/lfun/lib/ftp_data_connection/eventDestruct","/save/kills/d/dclmfahebkm","/powers/spells/greater_buffer.c","/domains/amigara/amigara/room/passage13.c","/log/chan/fighter","/doc/efun/all/lower_case","/secure/lib/net/ftp.c","/log/chan/alpha","/log/archive/runtime-2009.03.16-02.30,39","/domains/Ylsrim/broken/cold.c","/doc/sefun/replace_line","/domains/fort/armor/hshirt.c","/log/chan/archive/muds-2009.04.10-22.28,44","/domains/default/npc/kwyjibo.c","/doc/lfun/lib/body/RemoveMagicProtection","/log/law/sites-watch/foo.txt","/log/chan/archive/muds-2010.09.10-03.45,48","/domains/default/armor/arbitersuit.c","/log/chan/archive/muds-2010.10.15-21.45,48","/log/archive/catch-2011.08.23-10.33,05","/domains/campus/npc/monty.c","/log/imc2_server/server_log","/secure/lib/include/bboard.h","/log/chan/archive/muds-2009.05.14-18.59,29","/domains/fort/etc/call_cops.bak","/doc/efun/all/mud_status","/domains/town/doors/mansion.c","/doc/build/Barkeeps","/doc/efun/interactive/ed_cmd","/doc/efun/numbers/random","/secure/include/network.h","/domains/town/armor/visor.c","/log/chan/archive/muds-2010.08.25-08.45,48","/domains/default/room/freezer.c","/domains/Praxis/kataan_vote.c","/domains/town/armor/toga.c","/www/debugging.html","/save/services.4444.o","/include/respiration_types.h","/domains/fort/room/north_gtower_top.c","/doc/build/Guidelines","/log/chan/archive/muds-2010.10.01-20.45,48","/doc/lfun/lib/body/GetPoison","/log/chan/archive/muds-2010.11.02-16.45,48","/doc/lfun/lib/lamp/SetBurnRate","/save/notify.6666.o","/log/chan/archive/muds-2010.11.10-02.45,48","/secure/sefun/names.c","/log/chan/archive/dchat-2010.07.20-18.16,17","/log/chan/archive/dgd-2009.03.26-08.11,20","/save/kills/l/lkfbnmhhjhh","/domains/town/room/clearing.c","/doc/applies/master/valid_seteuid","/log/chan/archive/muds-2010.07.07-19.15,58","/domains/town/room/porch.c","/domains/Ylsrim/room/furnace.c","/domains/fort/armor/cap.c","/doc/sefun/exclude_array","/log/chan/archive/dgd-2009.03.25-01.11,20","/cmds/creators/showgrid.c","/doc/lfun/lib/body/GetDying","/domains/amigara/room/passage24.c","/secure/cmds/creators/findfun.c","/verbs/players/include/follow.h","/daemon/tmp/four.c","/doc/lfun/lib/body/GetWieldingLimbs","/secure/sefun/translate.c","/log/chan/archive/muds-2009.04.11-15.28,44","/log/archive/runtime-2009.06.27-21.35,30","/lib/include/interface.h","/secure/cmds/creators/destfile.c","/log/chan/archive/muds-2009.11.23-09.44,08","/log/chan/archive/muds-2010.11.08-17.45,48","/domains/town/obj/rocks.c","/doc/lfun/lib/battery/eventCharge","/secure/obj/glasses.c","/save/portal.3333.o","/save/kills/c/cmkgkhdbhmd","/doc/efun/all/master","/doc/efun/interactive/users","/secure/cmds/creators/.update.c.swp","/domains/amigara/room/ostorage.c","/verbs/items/include/unwield.h","/domains/Praxis/obj/mon/horace.c","/doc/efun/interactive/userp","/log/chan/archive/muds-2010.10.11-06.45,48","/domains/Praxis/cemetery/mon/ghost5.c","/secure/daemon/.update.patch.swp","/doc/efun/all/save_object","/log/chan/archive/intergossip-2010.11.23-23.45,48","/doc/lfun/all/GetCapName","/doc/efun/all/disable_wizard","/log/chan/archive/sport-2009.04.13-14.29,16","/log/chan/archive/muds-2010.09.08-04.45,48","/save/kills/x/xkcdehgg","/log/chan/archive/muds-2011.01.12-04.46,55","/domains/fort/obj/suitcase.c","/domains/fort/armor/towel.c","/doc/lfun/all/SetMorality","/doc/efun/system/replaceable","/save/kills/o/odiej","/www/lpmuds/downloads_files/smflogo.gif","/log/archive/runtime-2010.07.09-21.16,00","/domains/examples/room/start.c","/cmds/players/screenlock.c","/www/images/lpuni_afiliated.png","/save/kills/c/cdgad","/doc/lfun/all/SetExtraChannels","/domains/campus/chamber/tree.c","/doc/efun/all/query_ip_name","/save/kills/x/xkcdidolmfbinb","/domains/default/npc/quarantine/spencer.c","/log/archive/i3error-2009.05.19-00.00,12","/doc/efun/system/debug_message","/cmds/creators/last.c","/save/kills/g/gjildmcndgc","/secure/sefun/dummy.c","/cmds/creators/lightme.c","/verbs/players/include/news.h","/save/rooms.5555.o","/doc/efun/all/printf","/log/chan/archive/muds-2009.04.12-08.28,44","/secure/cmds/builders/create.c","/doc/lfun/all/eventRetire","/lib/flashlight.c","/log/chan/archive/muds-2009.04.11-01.28,44","/domains/campus/txt/jenny/9.txt","/domains/fort/obj/obag.c","/doc/efun/internals/set_malloc_mask","/domains/Praxis/hall.c","/domains/fort/room/cooper.c","/domains/fort/etc/call_cops.c","/domains/fort/armor/rocketpack.c","/lib/torch.c","/cfg/months.cfg","/log/archive/runtime-2009.11.16-18.09,58","/domains/town/weap/.verysharpsword.c.swp","/lib/spell.c","/domains/town/virtual/sky/22,8,1.c","/secure/scripts/qgreset.src","/domains/town/obj/lamp.c","/domains/Praxis/obj/mon/lars.c","/verbs/items/deactivate.c","/doc/efun/objects/reload_object","/save/kills/x/xkcdhmhncme","/log/chan/archive/muds-2010.12.23-12.45,48","/doc/efun/all/reload_object","/save/kills/l/likoaenlgkn","/domains/fort/obj/toilet.c","/domains/amigara/virtual/void.c","/doc/efun/all/sscanf","/secure/include/config.3333.h","/cmds/creators/shadows.c","/log/chan/archive/ds-2010.07.21-12.16,17","/save/kills/a/agamn","/domains/fort/room/shop.c","/domains/fort/armor/handbag.c","/secure/scripts/walkabout.src","/domains/Ylsrim/room/weaponry_storage.c","/domains/default/obj/reset_button.c","/log/chan/archive/intergossip-2010.09.16-17.45,48","/obj/book_source/chapter2","/domains/fort/room/mstreet.c","/obj/book_source/chapter1","/log/chan/archive/dchat-2010.08.13-12.18,42","/domains/campus/doors/grate.c","/domains/default/armor/ring_light.c","/log/errors/kalinash","/save/kills/m/maamcdoi","/domains/town/obj/scroll_resurrection.c","/doc/lfun/lib/battery/GetDrainable","/www/lpmuds/smflogo.gif","/doc/lfun/lib/player/SetClass","/secure/include/events.h","/domains/fort/obj/rucksack.c","/save/kills/g/gobkdj","/save/kills/e/en","/domains/Ylsrim/etc/adv_board.c","/doc/lfun/lib/flashlight/SetDrainRate","/domains/town/doors/welldoor1.c","/domains/alpha/virtual/server.c","/save/kills/e/ek","/lib/include/leader.h","/save/kills/e/ej","/log/chan/archive/muds-2010.09.29-11.45,48","/domains/campus/armor/badge.c","/save/kills/d/dncgoebl","/log/chan/archive/intergossip-2009.03.25-11.17,31","/domains/fort/armor/goggles.c","/domains/campus/obj/dcell_good.c","/log/chan/archive/muds-2010.12.16-19.45,48","/doc/efun/internals/query_load_average","/log/archive/icp-2009.03.16-10.30,39","/doc/lfun/lib/body/AddLead","/log/chan/archive/muds-2010.12.24-05.45,48","/log/chan/archive/muds-2009.10.03-14.41,27","/daemon/tmp/LIB_DRINK.c","/domains/campus/txt/jenny/10.txt","/save/kills/m/miaif","/daemon/tmp/MOUTH_LIPPED+MOUTH_TOOTHED+MOUTH_TONGUED+MOUTH_FANGED+MOUTH_DISEASED.c","/secure/cfg/mudos.autobak.4444","/domains/amigara/room/banquet.c","/verbs/common/include/help.h","/log/chan/archive/inews-2013.08.28-22.13,15","/doc/efun/all/next_bit","/domains/amigara/room/passage15.c","/doc/lfun/all/eventUnload","/doc/lfun/lib/chat/GetRestrictedChannels","/domains/town/obj/sofa.c","/domains/cave/meals/herring.c","/domains/town/doors/steel_door.c","/std/freezer.c","/domains/fort/room/wroad.c","/domains/Praxis/obj/mon/waitress.c","/doc/lfun/lib/chat/UnrestrictChannel","/log/chan/archive/muds-2010.11.10-15.45,48","/log/chan/archive/muds-2009.04.30-12.48,48","/domains/fort/npc/forest_orc.c","/log/archive/reset-2009.05.21-09.13,36","/domains/town/armor/boobytrap_ring.c","/doc/efun/all/m_values","/log/chan/archive/muds-2009.04.09-16.28,26","/domains/campus/obj/bbucket.c","/doc/sefun/query_snoop","/save/kills/k/knhcjj","/domains/fort/meals/herring.c","/log/chan/archive/muds-2009.05.20-07.06,41","/log/archive/runtime-2009.03.16-01.30,39","/domains/default/armor/combat_pack.c","/cmds/creators/vis.c","/save/kills/d/dfgegjhl","/domains/fort/room/bgate.c","/doc/applies/preload","/doc/lfun/lib/load/eventLoad","/log/chan/archive/muds-2010.10.24-13.45,48","/domains/fort/room/f_road30.c","/domains/fort/obj/357shell.c","/domains/campus/npc/kleiner.c","/doc/lfun/lib/chapel/GetReligion","/secure/sefun/absolute_value.c","/log/chan/archive/muds-2010.11.07-23.45,48","/log/chan/archive/intergossip-2010.10.16-13.45,48","/log/chan/archive/muds-2009.10.04-07.41,27","/domains/fort/obj/d20.c","/save/kills/n/nklfd","/log/chan/archive/intergossip-2010.10.07-20.45,48","/domains/fort/obj/key.c","/lib/include/listen.h","/verbs/common/include/ask.h","/log/chan/archive/muds-2009.09.24-12.07,15","/domains/Ylsrim/etc/key.c","/domains/town/room/south_road2.c","/domains/fort/weap/9mil.c","/save/kills/d/dffl","/daemon/stats.c","/log/chan/archive/discworld-chat-2010.12.22-17.45,48","/secure/sefun/arrays.c","/log/chan/archive/muds-2010.10.11-19.45,48","/domains/default/armor/gray_amulet.c","/save/kills/x/xkcddcgm","/doc/efun/mudlib/domain_stats","/save/kills/o/obclmgnoag","/log/chan/archive/muds-2010.08.24-00.45,48","/domains/default/armor/bearskin.c","/verbs/players/wake.c","/save/kills/x/xkcdgcfdhl","/log/archive/catch-2009.03.28-14.11,36","/log/chan/archive/muds-2010.11.11-08.45,48","/log/chan/archive/intergossip-2010.10.03-19.45,48","/save/kills/k/knklb","/log/chan/archive/muds-2010.11.10-01.45,48","/doc/efun/all/variables","/domains/fort/room/f_road9.c","/save/kills/o/oafll","/domains/cave/obj/table2.c","/doc/sefun/get_livings","/doc/lfun/lib/clan/eventBring","/domains/fort/armor/long_boot_r.c","/log/chan/archive/muds-2013.08.09-07.13,15","/doc/efun/all/undefinedp","/verbs/rooms/include/enter.h","/doc/efun/all/socket_error.h","/log/chan/archive/muds-2013.08.08-00.13,15","/log/chan/archive/muds-2009.04.11-14.28,44","/lib/lvs/position.c","/doc/sefun/shout","/log/archive/runtime.boot-2009.04.26-19.06,12","/doc/sefun/memberp","/doc/efun/objects/heart_beats","/log/archive/catch-2009.05.19-11.00,43","/log/chan/archive/muds-2010.11.17-09.45,48","/log/chan/archive/muds-2009.03.25-15.11,20","/save/kills/m/minebf","/log/chan/archive/muds-2010.11.08-16.45,48","/domains/town/txt/pot.txt","/domains/town/obj/hpoolwater.c","/save/kills/x/xkcdoccb","/log/chan/archive/intergossip-2009.03.26-08.11,20","/log/chan/archive/intergossip-2010.10.08-13.45,48","/domains/town/meals/potion_antidote.c","/domains/fort/room/f_road3.c","/secure/cmds/admins/.shutdown.c.swp","/domains/campus/obj/cup.c","/secure/daemon/economy.c","/doc/efun/all/query_num","/domains/campus/obj/.apple.c.swp","/domains/town/obj/waterwheel.c","/domains/Praxis/attic/class_change.c","/domains/fort/armor/long_boot_l.c","/domains/fort/obj/thing_h.c","/lib/events/sell.c","/lib/include/clan.h","/doc/lfun/lib/race/GetMaxMagicPoints","/domains/fort/room/msquare_n.c","/log/chan/archive/muds-2010.12.25-04.46,44","/doc/lpc/intermediate/Contents","/doc/applies/reset","/domains/town/virtual/space.c","/save/kills/j/joaockb","/secure/include/mudlib.h","/log/archive/runtime-2010.07.09-20.16,00","/doc/sefun/query_host_port","/doc/lfun/all/GetPacifist","/log/chan/archive/inews-2013.08.16-07.13,15","/domains/town/virtual/bottom/33,100000.c","/domains/fort/weap/knife.c","/daemon/tmp/1,1.c","/log/chan/archive/dchat-2011.01.06-18.46,13","/save/kills/j/jklb","/domains/campus/txt/ai/charles/bak2/bak1/blue_wins","/shadows/scout.c","/secure/cfg/races/pegasus","/domains/default/npc/quarantine/kip.c","/domains/Praxis/obj/misc/order.c","/domains/fort/obj/mat.c","/doc/lfun/lib/clan/GetAffectLong","/domains/default/obj/223clip.c","/secure/cmds/creators/removeemote.c","/domains/campus/obj/.dcell_good.c.swp","/doc/lfun/lib/furnace/CanReceive","/doc/efun/all/strsrch","/domains/Praxis/obj/misc/chest.c","/log/chan/archive/muds-2010.10.17-06.45,48","/domains/fort/armor/sandal_r.c","/log/chan/archive/muds-2010.11.09-09.45,48","/domains/town/room/mountain_road.c","/obj/.light.c.swp","/domains/campus/obj/wlocker.c","/domains/Praxis/council_vote.c","/daemon/domains.c","/www/cgi/chanlogs.c","/daemon/tmp/MOUTH_TOOTHED+MOUTH_TONGUED+MOUTH_FANGED.c","/doc/efun/filesystem/cp","/domains/Ylsrim/README","/domains/town/virtual/sky/21,8,1.c","/domains/town/npc/nymph.c","/domains/fort/room/f_road27.c","/doc/efun/strings/strsrch","/doc/efun/all/unique_mapping","/save/portal.4444.o","/secure/cmds/admins/.rid.c.swp","/log/chan/archive/muds-2010.10.03-05.45,48","/cmds/players/charmode.c","/domains/fort/obj/45round.c","/log/chan/havenlib","/log/chan/archive/muds-2009.05.22-22.21,26","/domains/fort/armor/sandal_l.c","/domains/town/weap/.dagger.c.swp","/domains/campus/room/access5.c","/domains/campus/meals/ale.c","/log/chan/archive/sport-2013.08.25-12.13,15","/domains/fort/obj/lice.c","/doc/CREDITS","/log/chan/archive/muds-2009.04.26-19.06,12","/doc/efun/all/present","/domains/fort/room/thall.c","/www/articles/imc2_ban.html","/save/kills/j/jonbnh","/log/chan/archive/muds-2010.08.23-20.45,48","/doc/lfun/all/GetStaminaPoints","/log/chan/archive/muds-2010.09.24-16.45,48","/verbs/items/include/read.h","/domains/fort/room/f_road21.c","/domains/default/etc/death.txt","/doc/sefun/true","/doc/sefun/leaderp","/domains/fort/room/north_wall_3.c","/log/chan/archive/intercre-2009.05.19-12.00,43","/domains/fort/obj/clocktower.c","/verbs/items/unlock.c","/log/chan/archive/intergossip-2010.12.01-10.45,48","/domains/town/obj/.dcell_good.c.swp","/verbs/items/bury.c","/save/rooms.6666.o","/save/kills/k/kkfbhcklgl","/secure/sefun/mud_info.c","/domains/town/obj/pool_ball.c","/cmds/creators/boards.c","/domains/cave/room/food_storage1.c","/verbs/rooms/include/jump.h","/save/kills/x/xkcdmejbgh","/domains/Praxis/obj/misc/donation.c","/log/chan/archive/sport-2013.07.26-16.13,15","/doc/lfun/all/GetDrainable","/domains/town/room/mansion_uhall2.c","/domains/Praxis/forest1.c","/domains/campus/room/snack.c","/domains/Ylsrim/room/church.c","/doc/efun/all/rm","/log/chan/zblah","/www/news.html","/log/chan/archive/muds-2010.08.24-13.45,48","/domains/campus/obj/.pedestal.c.swp","/lib/manycoins.c","/save/kills/k/kam","/secure/cfg/preload.cfg","/domains/town/room/road2.c","/log/chan/archive/muds-2010.09.07-23.45,48","/log/chan/archive/muds-2010.07.08-04.16,00","/log/chan/archive/muds-2010.11.10-14.45,48","/log/chan/archive/dgd-2009.03.20-08.16,52","/secure/include/config.4444.h","/domains/Praxis/obj/mon/balrog.c","/doc/lfun/all/GetCaliber","/log/chan/archive/muds-2010.11.01-21.45,48","/log/archive/currency-2009.10.04-20.41,35","/log/chan/archive/intergossip-2010.11.02-14.45,48","/log/archive/i3error.2009.05.14-17.56,40-2009.05.14-17.59,29","/secure/cmds/creators/profile.c","/domains/campus/obj/omni.c","/doc/efun/strings/strcmp","/verbs/items/include/unlock.h","/log/chan/archive/muds-2013.08.17-06.13,15","/log/archive/runtime-2009.03.16-00.30,39","/domains/fort/obj/rocking_chair.c","/log/chan/archive/muds-2013.08.08-13.13,15","/log/chan/archive/ds-2010.08.10-18.18,42","/domains/fort/weap/orcslayer.c","/log/chan/archive/muds-2009.04.10-20.28,44","/domains/Praxis/west_road3.c","/verbs/players/include/crawl.h","/log/chan/archive/intergossip-2010.10.17-19.45,48","/domains/fort/room/south_wall_3.c","/domains/campus/room/tunnel.c","/secure/cmds/admins/userload.c","/save/parties.o","/log/chan/archive/muds-2009.03.24-21.11,20","/log/chan/archive/sport-2013.07.26-02.13,15","/log/chan/archive/muds-2010.12.16-04.45,48","/doc/applies/master/slow_shutdown","/lib/events/fall.c","/domains/default/armor/wristcomp.c","/domains/campus/doors/hatch.c","/domains/town/obj/ladder.c","/log/chan/archive/muds-2011.01.04-17.46,13","/log/archive/runtime-2009.11.16-17.09,22","/upgrades.txt","/save/kills/x/xkcdkamk","/domains/default/doors/steel_door.c","/save/kills/n/nlbiahofgm","/log/chan/archive/sport-2009.05.15-15.59,29","/domains/town/obj/chest.c","/domains/town/armor/newbie_ring.c","/log/chan/archive/muds-2010.09.16-02.45,48","/www/lpmuds/intermud_files/mudlist.txt","/cmds/players/timezone.c","/log/chan/archive/muds-2010.11.10-00.45,48","/log/archive/currency-2009.10.05-13.41,35","/log/chan/archive/muds-2010.12.02-03.45,48","/secure/include/compat.h","/doc/efun/sockets/socket_error","/secure/tmp/otto_CMD_EVAL_TMP_FILE.c","/domains/fort/room/clerk.c","/daemon/tmp/zeta.c","/doc/efun/objects/save_object","/domains/amigara/amigara/room/kguards.c","/domains/fort/room/f_road18.c","/doc/sefun/path_file","/secure/obj/.meditate_mojo.c.swp","/domains/Ylsrim/save/0^0domains0^0Ylsrim0^0room0^0fighter.o.gz","/doc/efun/all/query_ed_mode","/log/chan/archive/muds-2009.04.11-13.28,44","/doc/build/Doors","/domains/Praxis/w_boc_la3.c","/log/chan/archive/muds-2010.10.25-05.45,48","/log/archive/i3error-2009.05.08-17.58,26","/domains/default/npc/quarantine/job.c","/lib/include/storage.h","/log/chan/archive/muds-2010.10.16-12.45,48","/save/kills/x/xkcdhcfek","/domains/town/room/mansion_room11.c","/log/chan/archive/muds-2010.11.08-15.45,48","/verbs/items/scratch.c","/save/rooms.o","/save/races.8888.o","/secure/include/files.h","/domains/Praxis/pass2.c","/log/chan/archive/muds-2009.04.29-11.10,44","/doc/manual/chapter40","/save/unique.8888.o","/doc/efun/all/tail","/secure/cmds/creators/addemote.c","/secure/cmds/admins/domainadmin.c","/log/archive/catch-2011.08.23-08.31,52","/domains/town/armor/tshirt.c","/cmds/creators/domains.c","/secure/cmds/creators/mv.c","/lib/blank_pile.c","/secure/cmds/creators/restore.c","/domains/fort/room/f_road12.c","/secure/cfg/races/dryad","/doc/applies/get_root_uid","/log/chan/archive/muds-2010.10.03-18.45,48","/lib/lvs/abilities.c","/doc/efun/all/memory_info","/obj/magic_scroll.c","/doc/efun/all/query_snoop","/secure/cmds/admins/vaarsuvius.c","/domains/fort/npc/elim.c","/domains/campus/txt/warning.txt","/log/chan/archive/muds-2013.08.29-20.13,15","/domains/campus/txt/note.txt","/doc/manual/chapter39","/domains/town/room/wtunnel5.c","/doc/manual/chapter38","/daemon/tmp/board.c","/doc/manual/chapter37","/save/kills/l/lji","/log/chan/archive/muds-2010.09.23-22.45,48","/doc/manual/chapter36","/cmds/players/faq.c","/doc/manual/chapter35","/secure/include/rooms.prime","/domains/Ylsrim/fish/shark.c","/doc/manual/chapter34","/doc/efun/objects/present","/domains/town/meals/green_spice.c","/doc/manual/chapter33","/log/crashes","/log/chan/archive/muds-2009.04.12-06.28,44","/doc/manual/chapter32","/doc/manual/chapter31","/doc/manual/chapter30","/doc/lfun/all/eventWelcome","/domains/cave/obj/.ecoli.c.swp","/log/chan/archive/muds-2010.10.08-12.45,48","/log/chan/archive/muds-2010.11.09-08.45,48","/log/chan/archive/muds-2009.04.30-11.48,12","/lib/props/addstuff.c","/domains/fort/armor/chainmail.c","/log/chan/archive/muds-2009.05.24-14.22,17","/log/archive/reset-2009.05.24-18.22,24","/daemon/tmp/A_AMULET.c","/doc/efun/internals/dump_socket_status","/www/lpmuds/parch.jpg","/log/errors/daemon","/lib/props/damage.c","/domains/town/virtual/sky/20,8,1.c","/doc/lfun/all/GetMissingLimbParent","/domains/fort/doors/menagerie_door.c","/doc/help/players/nickname","/domains/campus/meals/.apple.c.swp","/lib/std/wound.c","/verbs/rooms/include/buy.h","/secure/scripts/grid.src","/domains/town/save/0^0domains0^0town0^0obj0^0charity.o.gz","/doc/manual/chapter29","/domains/campus/armor/cap.c","/doc/manual/chapter28","/verbs/items/include/pick.h","/secure/cfg/mudos.autobak","/doc/manual/chapter27","/verbs/rooms/swim.c","/doc/manual/chapter26","/secure/cfg/races/snake","/domains/fort/weap/beads.c","/doc/manual/chapter25","/doc/lfun/lib/firearm/GetAmmoType","/www/ds-faq.html","/domains/campus/room/corridor.c","/doc/manual/chapter24","/doc/manual/chapter23","/domains/town/armor/bearskin.c","/domains/default/room/.telnet_room.c.swp","/doc/manual/chapter22","/secure/cmds/creators/cat10.c","/doc/manual/chapter21","/save/kills/i/ibbldhgg","/doc/manual/chapter20","/domains/fort/room/granary_tower.c","/doc/efun/all/m_indices","/verbs/items/include/smell.h","/save/kills/g/gmcmcg","/domains/town/weap/.shotput.c.swp","/save/types.1111.o","/log/events","/secure/cfg/races/elemental","/doc/lfun/all/NewBody","/save/kills/x/xkcdmebn","/domains/town/obj/maglite.c","/log/chan/archive/sport-2013.08.11-10.13,15","/doc/efun/calls/this_object","/save/services.6666.o","/domains/fort/room/east_wall_4.c","/doc/lfun/lib/chapel/SetReligion","/doc/efun/all/function_profile","/save/notify.8888.o","/log/archive/runtime-2009.03.16-13.30,39","/secure/include/global.h","/log/chan/archive/muds-2010.08.17-06.45,20","/save/kills/f/fjofob","/log/chan/archive/muds-2009.05.21-03.13,36","/domains/Praxis/obj/mon/execution_d.c","/doc/efun/functions/bind","/doc/efun/filesystem/read_file","/log/chan/archive/intergossip-2010.07.15-23.16,17","/doc/efun/all/origin","/save/kills/x/xkcdcjaj","/log/chan/archive/intergossip-2010.10.25-18.45,48","/doc/manual/chapter19","/doc/manual/chapter18","/doc/manual/chapter17","/doc/build/Quests","/secure/cfg/races/gnome","/doc/manual/chapter16","/daemon/include/intermud.h","/doc/manual/chapter15","/doc/manual/chapter14","/secure/include/link.h","/news/fighter","/doc/manual/chapter13","/lib/include/combatmsg.h","/doc/manual/chapter12","/doc/manual/chapter11","/log/chan/archive/intergossip-2009.05.14-15.59,29","/domains/campus/obj/spam.c","/doc/manual/chapter10","/doc/efun/strings/crypt","/verbs/items/skin.c","/domains/town/npc/bear.c","/domains/default/virtual/void.c","/domains/campus/room/mailroom.c","/doc/lfun/lib/genetics/GetStats","/doc/efun/interactive/query_idle","/save/kills/f/fhallckokl","/domains/Praxis/freezer.c","/save/portal.5555.o","/domains/campus/adm/void.c","/save/kills/n/njbhfaog","/save/kills/m/mkjijghamn","/save/2","/doc/efun/objects/first_inventory","/save/1","/domains/campus/weap/staff.c","/log/chan/furry","/domains/town/armor/ring.c","/secure/cfg/races/half-elf","/cfg/moons.cfg","/save/kills/x/xkcdmibddj","/log/chan/archive/muds-2010.11.10-13.45,48","/domains/town/doors/m6.c","/cmds/players/brief.c","/log/chan/archive/intergossip-2010.09.08-15.45,48","/domains/campus/txt/dali.txt","/domains/campus/room/red_room3.c","/save/kills/f/filbeinegl","/lib/meal.c","/log/archive/catch-2014.10.31-12.00,32","/domains/town/room/bwalk1.c","/domains/Ylsrim/room/armory.c","/secure/cfg/races/gnoll","/log/chan/archive/inews-2013.08.23-12.13,15","/doc/manual/chapter09","/doc/manual/chapter08","/domains/fort/armor/overcoat.c","/domains/amigara/room/passage8.c","/doc/manual/chapter07","/doc/manual/chapter06","/doc/manual/chapter05","/log/chan/archive/muds-2010.10.25-18.45,48","/log/chan/archive/intergossip-2010.07.16-16.16,17","/doc/manual/chapter04","/domains/campus/obj/357shell.c","/doc/manual/chapter03","/doc/lfun/lib/battery/eventUse","/secure/cmds/admins/switchrouter.c","/doc/manual/chapter02","/doc/manual/chapter01","/daemon/tmp/thorg.c","/domains/cave/etc/cave_room.c","/lib/.teller.c.swp","/doc/efun/strings/clear_bit","/cmds/creators/wiz.c","/secure/cfg/races/dwarf","/domains/fort/obj/room_item.c","/doc/efun/all/named_livings","/log/chan/french","/log/chan/archive/muds-2010.12.07-10.45,48","/domains/Praxis/s_centre2.c","/doc/sefun/get_verbs","/doc/efun/system/external_start","/log/chan/archive/connections-2009.11.27-15.59,14","/lib/include/npc.h","/secure/daemon/include/imc2_code.h","/log/chan/archive/muds-2013.08.03-04.13,15","/domains/amigara/room/passage2.c","/secure/lib/net/echo_server.c","/doc/lfun/all/SetPacifist","/domains/cave/room/dining1.c","/lib/events/dig_with.c","/doc/applies/valid_override","/daemon/banish.c","/save/kills/l/lhmahen","/log/adm/eval","/domains/Praxis/adm/master.c","/verbs/items/include/drop.h","/secure/include/socket.h","/lib/events/roll.c","/log/chan/archive/dchat-2010.12.17-10.45,48","/domains/fort/armor/cloak.c","/doc/efun/interactive/command","/save/kills/a/akeebe","/lib/events/pull.c","/save/kills/x/xkcdceofi","/domains/fort/armor/vest.c","/www/lpmuds/lp_versus_diku.html","/lib/currency.c","/domains/fort/armor/leather_suit.c","/domains/default/armor/glove_r.c","/domains/Praxis/highway3.c","/save/kills/c/cgokf","/domains/Praxis/obj/mon/armageddon.c","/daemon/tmp/dirk.c","/doc/applies/valid_seteuid","/secure/include/config.5555.h","/log/chan/archive/dchat-2010.10.20-10.45,48","/domains/Praxis/building.c","/domains/town/room/confroom.c","/save/kills/h/hnjokaijhdc","/doc/applies/master/log_error","/save/kills/x/xkcdllmnc","/domains/cave/armor/leather_armor.c","/verbs/players/ignore.c","/cmds/common/help.c","/log/chan/archive/muds-2010.09.02-00.45,48","/domains/Ylsrim/broken/README","/doc/sefun/event","/domains/default/npc/drone3.c","/domains/campus/room/science.c","/doc/lfun/lib/connect/GetCapName","/secure/cfg/races/demi-god","/log/chan/archive/dgd-2010.10.04-09.45,48","/domains/cave/obj/gate_key.c","/log/chan/archive/muds-2010.11.08-14.45,48","/log/chan/archive/muds-2010.11.16-00.45,48","/domains/default/npc/quarantine/lester.c","/log/chan/archive/dgd-2010.08.13-08.18,42","/log/chan/archive/muds-2009.04.12-12.29,16","/domains/default/armor/glove_l.c","/log/chan/archive/intergossip-2010.08.17-19.45,20","/log/watch/foo.txt","/log/chan/archive/ds-2010.09.22-15.45,48","/save/kills/l/ldegi","/log/chan/archive/muds-2010.07.10-15.16,00","/daemon/include/command.h","/open/prog.c","/domains/Praxis/death/death_room.c","/save/kills/j/jd","/log/chan/archive/muds-2011.01.05-09.46,13","/save/kills/j/ja","/log/chan/archive/i2news-2009.05.12-22.59,29","/lib/flow.c","/lib/elevator.c","/doc/applies/master/get_root_uid","/obj/armor.c","/log/chan/archive/muds-2010.10.02-10.45,48","/save/kills/x/xkcdhelbndgcaj","/save/kills/c/cgjoii","/domains/town/room/mansion_room8.c","/domains/town/armor/.chainmail.c.swp","/domains/Praxis/cemetery/grave_yard6.c","/save/kills/x/xkcddia","/doc/help/creators/debug_hints","/doc/lfun/lib/body/AddHP","/doc/efun/all/reg_assoc","/log/chan/archive/mudnews-2013.08.22-10.13,15","/domains/fort/obj/generator.c","/doc/applies/parse_command_id_list","/doc/help/players/vendors","/save/kills/s/slymenstra","/doc/lfun/lib/body/GetLimbs","/log/chan/archive/muds-2010.11.09-07.45,48","/log/chan/archive/muds-2009.04.30-10.48,12","/domains/town/room/mansion_room2.c","/secure/cfg/mudos.autobak.1111","/log/chan/archive/muds-2010.08.17-19.45,20","/domains/fort/obj/45case.c","/domains/campus/weap/9mil.c","/log/chan/archive/muds-2013.08.24-11.13,15","/log/chan/archive/muds-2010.08.16-12.45,20","/domains/campus/armor/wglove_r.c","/verbs/items/drink.c","/include/terrain_types.h","/save/kills/j/jdgdllk","/log/archive/i3error.2009.05.15-19.20,45-2009.05.15-19.59,29","/secure/daemon/ping.c","/domains/default/obj/stargate.c","/log/chan/archive/muds-2010.07.10-01.16,00","/secure/cmds/admins/removeraces.c","/doc/build/Climates","/cmds/creators/mstatus.c","/log/i3error","/doc/efun/all/arrayp","/secure/daemon/alchemist.c","/daemon/tmp/foo.c","/verbs/rooms/go.c","/log/chan/archive/intergossip-2010.12.16-16.45,48","/domains/cave/room/cavepass4.c","/secure/cfg/races/hobbit","/log/chan/archive/muds-2013.08.11-17.13,15","/domains/default/weap/9mil.c","/doc/efun/all/socket_address","/cmds/players/new.c","/domains/town/obj/9mmclip.c","/daemon/tmp/testyone.c","/log/chan/archive/muds-2009.10.04-18.41,35","/domains/campus/armor/wglove_l.c","/save/kills/n/nccgadohl","/doc/sefun/write","/log/chan/archive/intergossip-2013.08.11-03.13,15","/log/chan/archive/intergossip-2010.08.25-18.45,48","/doc/efun/mixed/undefinedp","/domains/town/npc/bubb.c","/domains/town/obj/fleas.c","/domains/campus/armor/.jeans.c.swp","/log/chan/archive/intergossip-2010.09.16-14.45,48","/domains/fort/doors/school.c","/doc/lfun/lib/bank/teller_check","/save/kills/x/xkcdkgdf","/log/chan/archive/intergossip-2010.09.07-21.45,48","/include/marriage.h","/daemon/tmp/kam.c","/secure/cfg/mudos.cfg","/lib/comp/weapon.c","/domains/town/obj/round2.c","/domains/town/obj/slip_cure.c","/daemon/tmp/MOUTH_LIPPED+MOUTH_TOOTHED+MOUTH_TONGUED+MOUTH_DISEASED.c","/secure/daemon/voting.c","/log/archive/runtime-2009.03.16-12.30,39","/doc/efun/all/seteuid","/doc/RELEASE_NOTES_HTTP","/log/errors/one","/domains/fort/room/cell2.c","/domains/fort/armor/steel_glove_r.c","/log/chan/archive/muds-2013.08.16-11.13,15","/lib/props/radiance.c","/domains/default/npc/unicorn.c","/secure/sefun/ordinal.c","/doc/efun/all/commands","/log/archive/currency-2009.11.07-08.08,14","/lib/std/storage.c","/domains/town/obj/needle_trap3.c","/doc/efun/all/index","/lib/learn.c","/domains/fort/obj/flask.c","/doc/applies/interactive/catch_tell","/log/chan/archive/dchat-2013.08.27-18.13,15","/doc/efun/floats/floor","/doc/efun/all/error","/doc/efun/all/author_stats","/lib/include/follow.h","/log/chan/archive/muds-2013.08.11-03.13,15","/domains/fort/armor/steel_glove_l.c","/log/chan/archive/muds-2010.08.25-18.45,48","/lib/money.c","/doc/lfun/lib/body/eventHealDamage","/domains/Ylsrim/etc/hole.c","/doc/sefun/mud_currencies","/domains/town/armor/helmet2.c","/domains/campus/txt/ai/charly/fred","/log/chan/archive/muds-2010.11.10-12.45,48","/domains/town/weap/.fellsword.c.swp","/domains/default/armor/long_boot.c","/doc/lfun/lib/body/CanFly","/log/chan/archive/muds-2013.07.25-15.13,01","/domains/fort/armor/shirt.c","/save/portal.o","/doc/lfun/lib/race/GetMaxStaminaPoints","/lib/virtual/virt_land.c","/doc/efun/floats/pow","/domains/cave/obj/cup.c","/save/types.2222.o","/www/cgi/edit.c","/secure/cfg/mudos.5555.cfg","/log/chan/archive/broken_gossip-2011.01.08-20.46,13","/verbs/players/marry.c","/log/chan/archive/discworld-chat-2010.10.16-09.45,48","/doc/lfun/lib/body/GetExtraChannels","/secure/cfg/races/tortoise","/doc/lfun/all/GetMinHeat","/log/chan/archive/muds-2013.08.08-11.13,15","/log/chan/archive/muds-2010.09.11-06.45,48","/doc/lpc/constructs/for","/doc/efun/all/call_out_info","/doc/efun/all/TODO","/save/classes.1111.o","/domains/Ylsrim/virtual/README","/log/chan/archive/intergossip-2010.10.17-17.45,48","/log/archive/reset-2009.05.22-10.21,24","/log/chan/archive/imudnews-2010.10.18-10.45,48","/log/chan/archive/dchat-2013.07.27-15.13,15","/save/kills/x/xkcdeikdkg","/domains/campus/armor/bluedress.c","/domains/town/doors/house_door.c","/domains/campus/obj/dcell_crappy.c","/doc/efun/buffers/crc32","/log/chan/archive/muds-2010.12.08-16.45,48","/doc/efun/all/stat","/secure/lib/net/include/ftp.h","/domains/default/obj/guide.c","/domains/cave/obj/fishbarrel.c","/save/kills/j/jbdclilaog","/log/chan/archive/muds-2013.08.03-03.13,15","/cmds/players/status.c","/doc/lfun/all/eventCompareLimbs","/log/chan/archive/muds-2010.08.25-04.45,48","/doc/lfun/all/eventCollapse","/log/chan/archive/muds-2010.10.02-23.45,48","/lib/include/smell.h","/log/chan/archive/muds-2010.09.08-14.45,48","/log/chan/archive/muds-2010.11.11-05.45,48","/doc/applies/interactive/window_size","/domains/fort/obj/testbag2.c","/lib/comp/surface.c","/save/portal.6666.o","/domains/Praxis/obj/mon/orc_shaman.c","/doc/misc/ed.txt","/doc/lfun/all/SetCaliber","/cmds/admins/channel.c","/doc/lfun/lib/body/HealLimb","/domains/town/room/well3.c","/lib/events/crawl.c","/doc/lfun/lib/manipulate/CanManipulate","/domains/campus/txt/ai/charles/bak2/percent","/log/archive/i3error-2009.05.19-10.00,12","/doc/help/creators/ds","/secure/cmds/admins/notify.c","/log/chan/archive/broken_gossip-2011.01.09-13.46,13","/domains/amigara/room/death.c","/domains/Praxis/obj/misc/watchtower.c","/save/kills/x/xkcdbdlfibe","/log/chan/archive/sport-2009.10.06-16.42,38","/doc/lfun/lib/clan/GetClanSkill","/domains/town/virtual/sky.c","/log/chan/archive/muds-2009.04.11-11.28,44","/daemon/tmp/S_GIGANTIC.c","/lib/include/fuel.h","/log/chan/archive/dchat-2010.07.27-14.17,46","/domains/Praxis/quests/dragon.c","/doc/lfun/all/GetDying","/save/kills/g/gajnjmgefic","/log/chan/archive/muds-2010.11.08-13.45,48","/doc/efun/mudlib/geteuid","/log/chan/archive/muds-2009.05.20-22.13,36","/doc/efun/all/ed","/verbs/items/move.c","/domains/town/obj/donation_box.c","/doc/lfun/lib/firearm/SetAmmoType","/daemon/tmp/LIB_NMSH.c","/domains/fort/armor/tshirt.c","/save/rooms.8888.o","/log/chan/archive/muds-2010.10.12-09.45,48","/log/chan/archive/dchat-2010.10.26-10.45,48","/domains/campus/room/square.c","/cmds/creators/astar.c","/log/archive/i3error-2009.04.24-14.41,34","/log/chan/archive/muds-2010.09.09-07.45,48","/domains/town/obj/leaflet.c","/domains/town/meals/claritin.c","/daemon/stargate.c","/domains/default/armor/collar.c","/doc/efun/all/dumpallobj","/save/kills/x/xkcdngaikl","/log/chan/archive/intergossip-2010.08.04-15.18,42","/domains/default/room/pod.c","/daemon/include/verbs.h","/secure/cfg/races/griffin","/save/kills/b/bjidcolbngg","/domains/cave/armor/foodsmock.c","/domains/fort/npc/provost_guard.c","/log/chan/archive/inews-2013.08.07-11.13,15","/daemon/tmp/A_WEAPON.c","/secure/sefun/tail.c","/doc/efun/filesystem/rmdir","/include/message_class.h","/log/chan/archive/intergossip-2010.09.24-13.45,48","/domains/town/meals/latte.c","/log/chan/archive/muds-2009.04.12-04.28,44","/doc/lfun/lib/combat/eventDie","/domains/Praxis/obj/weapon/orc_slayer.c","/log/chan/archive/muds-2010.10.09-17.45,48","/domains/town/meals/potion_cure.c","/domains/campus/txt/ai/charles/bak2/bak1/switches","/doc/lfun/all/GetClanName","/verbs/items/dig.c","/save/kills/m/mjankifjoai","/doc/efun/objects/file_name","/log/chan/archive/muds-2010.11.09-06.45,48","/secure/cfg/mudos.orig","/save/kills/b/bcbnmnlbki","/log/chan/archive/muds-2009.04.13-04.29,16","/doc/lfun/all/GetMaxMagicPoints","/save/kills/m/mengbck","/cmds/creators/wizmap.c","/save/kills/x/xkcdlfdcmomla","/domains/fort/npc/henrik.c","/log/chan/archive/dchat-2010.10.18-10.45,48","/verbs/players/include/party.h","/daemon/tmp/cavetroll.c","/log/chan/archive/muds-2010.12.24-15.45,48","/secure/obj/machine.c","/doc/lfun/lib/creator/eventReconnect","/doc/efun/all/cp","/log/chan/irc","/doc/lfun/lib/container/CanRelease","/domains/fort/obj/pedestal2.c","/domains/fort/npc/troll.c","/log/errors/powers","/domains/town/room/stables.c","/doc/lfun/all/eventRemoveItem","/secure/sefun/pointers.c","/secure/sefun/query_invis.c","/domains/campus/txt/ai/charles/bak2/bak1/runs","/secure/sefun/identify.c","/log/chan/archive/mudnews-2013.08.15-16.13,15","/cmds/players/dispel.c","/save/kills/c/cratylus","/domains/fort/obj/rayovac.c","/doc/lfun/all/AddCaffeine","/doc/applies/master/flag","/verbs/common/channels.c","/daemon/tmp/S_TINY.c","/save/kills/o/ojgo","/log/chan/archive/muds-2010.09.15-20.45,48","/www/articles/old/forum_chat.html","/log/archive/reset-2009.05.24-16.22,17","/domains/town/virtual/sub.c","/log/chan/archive/muds-2010.12.10-14.45,48","/log/chan/cre","/domains/Ylsrim/npc/lars.c","/save/kills/h/hcackb","/domains/campus/txt/ai/charles/runs","/verbs/items/bait.c","/log/chan/archive/dgd-2009.05.15-19.59,29","/domains/cave/room/void.c","/save/kills/i/ilhhljea","/doc/lfun/lib/holder/CanReceive","/log/archive/runtime-2009.03.16-11.30,39","/doc/efun/sockets/socket_listen","/log/chan/archive/muds-2010.09.10-12.45,48","/save/kills/c/cnghajl","/doc/lfun/lib/chat/GetNoChanColors","/save/kills/m/mih","/domains/default/obj/pinger.c","/save/kills/h/hkck","/domains/Ylsrim/armor/helm.c","/log/chan/archive/muds-2010.12.07-22.45,48","/log/chan/archive/intergossip-2010.11.16-12.45,48","/log/chan/archive/dchat-2010.09.21-19.45,48","/save/kills/x/xkcdmfobf","/save/kills/f/fkngd","/log/chan/archive/intergossip-2010.12.08-15.45,48","/log/chan/archive/muds-2013.08.03-16.13,15","/domains/town/virtual/bottom/5,0.c","/doc/lfun/lib/clip/CanRelease","/log/archive/reset-2010.09.23-10.45,48","/domains/Praxis/setter.c","/domains/Praxis/data/cleric_crypt.o.gz","/include/gossip.h","/www/favicon.ico","/lib/events/manipulate.c","/log/chan/archive/muds-2010.09.25-06.45,48","/log/chan/archive/muds-2010.07.09-08.16,00","/save/kills/l/lmoaomi","/log/chan/archive/muds-2010.09.16-13.45,48","/log/i3error.2009.05.17-22.31,52","/lib/teller.c","/doc/lfun/lib/chat/SetNoChanColors","/domains/fort/room/sroad.c","/daemon/tmp/95.c","/log/chan/archive/muds-2011.01.11-20.46,55","/log/chan/archive/muds-2010.11.10-11.45,48","/log/chan/archive/intergossip-2010.10.02-22.45,48","/doc/efun/system/shallow_inherit_list","/log/chan/discworld-chat","/log/chan/archive/muds-2010.12.02-14.45,48","/domains/Praxis/fighter_join.c","/doc/lfun/all/eventReceiveThrow","/log/chan/archive/muds-2010.08.20-09.45,48","/domains/fort/room/gate.bak2","/save/kills/m/mhk","/domains/town/room/road.c","/doc/efun/internals/trace","/doc/efun/strings/repeat_string","/save/kills/j/jjjmacmicd","/log/chan/archive/muds-2013.08.08-10.13,15","/cmds/players/customize.c","/doc/efun/system/reset_eval_cost","/domains/fort/doors/quartermaster.c","/log/chan/archive/muds-2010.09.02-12.45,48","/log/chan/archive/inews-2009.05.21-15.14,07","/save/kills/o/oeang","/secure/sefun/.translate.c.swp","/lib/events/stop.c","/secure/daemon/autoexec.c","/secure/cfg/races/unicorn","/log/chan/archive/muds-2010.11.16-12.45,48","/domains/campus/txt/jenny/15.txt","/log/chan/ooc","/log/chan/archive/muds-2009.11.22-11.44,08","/doc/lfun/lib/body/GetRace","/log/chan/archive/sport-2013.08.19-09.13,15","/secure/include/objects.h","/lib/include/items.h","/domains/campus/txt/ai/charles/bak2/bak1/percent","/core","/verbs/items/include/show.h","/log/chan/archive/intergossip-2009.04.13-17.29,16","/lib/events/close.c","/daemon/include/news.h","/domains/fort/weap/357pistol.c","/log/chan/archive/inews-2013.08.29-11.13,15","/doc/applies/slow_shutdown","/domains/fort/obj/gchair.c","/domains/town/obj/h1n1.c","/doc/efun/strings/next_bit","/www/lpmuds/links_files/print.css","/doc/efun/internals/traceprefix","/daemon/services/who.c","/secure/cfg/classes/fighter","/domains/default/npc/dryad.c","/domains/default/obj/javelin_bin.c","/log/chan/archive/muds-2010.11.11-04.45,48","/save/kills/x/xkcdgnlnobm","/doc/lfun/lib/bonus/GetBonusDuration","/save/kills/m/mgl","/domains/Praxis/supply2.c","/verbs/items/judge1.c","/domains/fort/obj/flashlight.c","/doc/efun/interactive/get_char","/doc/efun/buffers/allocate_buffer","/save/kills/x/xkcdfdbibjif","/doc/help/creators/shadows","/doc/help/creators/admin","/domains/amigara/amigara/room/passage6.c","/doc/lfun/lib/chapel/AddSacrificeType","/doc/build/Sentients","/log/chan/archive/muds-2010.09.03-05.45,48","/domains/amigara/amigara/room/ocommon.c","/log/chan/archive/muds-2010.10.17-16.45,48","/cmds/players/newbie.c","/log/chan/archive/dgd-2009.03.14-06.46,02","/log/chan/*dalet:imud_gossip","/domains/Praxis/quest_room.c","/doc/sefun/conjunction","/log/chan/archive/muds-2009.03.26-00.17,31","/log/chan/archive/muds-2010.11.09-19.45,48","/domains/fort/armor/long_sock.c","/domains/campus/room/sewer2.c","/save/types.3333.o","/log/chan/archive/muds-2010.11.08-12.45,48","/log/chan/archive/muds-2010.12.09-08.45,48","/domains/campus/txt/jenny/5.txt","/log/archive/i3error-2009.05.16-20.59,29","/save/classes.2222.o","/doc/applies/parse_command","/log/chan/archive/muds-2010.07.10-13.16,00","/domains/fort/room/gstreet2.c","/domains/fort/armor/belt.c","/doc/efun/all/cos","/domains/fort/weap/gstaff.c","/doc/efun/interactive/say","/doc/lfun/all/CanExtinguish","/save/kills/g/gmhadbeajjb","/log/chan/archive/muds-2010.12.23-21.45,48","/log/chan/archive/muds-2010.11.03-04.45,48","/save/kills/i/ielmig","/domains/town/obj/omni.c","/verbs/items/include/give.h","/domains/fort/npc/human.c","/include/materials.h","/doc/efun/interactive/disable_commands","/verbs/players/lead.c","/domains/campus/room/stairwell2c.c","/save/kills/d/doibimicibh","/log/archive/runtime-2009.12.29-14.59,57","/domains/town/meals/ale.c","/doc/lfun/lib/potion/SetSkills","/doc/efun/all/replace_program","/domains/Praxis/inn105.c","/doc/lfun/lib/body/eventReceiveDamage","/log/chan/archive/muds-2009.04.12-03.28,44","/domains/campus/obj/.dcell.c.swp","/www/lpmuds/links_files/script.js","/log/chan/archive/dchat-2010.12.05-07.45,48","/domains/fort/armor/glove.c","/domains/fort/obj/cigar.c","/doc/lpc/constructs/while","/doc/lfun/lib/combat/GetBaseStatLevel","/log/chan/archive/muds-2010.11.09-05.45,48","/domains/fort/doors/gate.c","/domains/Praxis/spider_pit.c","/doc/help/creators/plan","/save/kills/f/ffkkageg","/domains/fort/npc/dude.c","/domains/town/armor/magical_platemail.c","/domains/amigara/amigara/room/oguard.c","/doc/lfun/all/AddMoJo","/log/chan/archive/intergossip-2009.05.21-00.13,36","/domains/default/room/menagerie.c","/log/chan/archive/intergossip-2010.09.10-11.45,48","/log/chan/archive/imudnews-2010.11.26-11.45,48","/verbs/players/pray.c","/log/chan/archive/muds-2010.12.15-21.45,48","/domains/fort/room/locksmith.c","/save/kills/x/xkcdfflh","/secure/sefun/domains.c","/secure/cfg/races/wraith","/doc/applies/connect","/domains/default/npc/quarantine/pip.c","/domains/campus/txt/dork.txt","/doc/efun/filesystem/write_bytes","/secure/cmds/builders/unvirt.c","/domains/alpha/room/void.c","/log/chan/archive/intercre-2010.07.31-11.18,42","/domains/fort/npc/wtf2.c","/doc/help/creators/emotes","/doc/efun/system/flush_messages","/log/chan/archive/muds-2010.10.09-02.45,48","/log/chan/archive/intergossip-2010.07.26-19.17,46","/doc/lfun/lib/firearm/SetMillimeter","/domains/fort/weap/carving_knife.c","/domains/fort/room/west_wall_4.c","/obj/thing.c","/daemon/tmp/A_RING.c","/cmds/creators/reset.c","/log/archive/runtime-2009.09.22-11.02,54","/log/archive/runtime-2009.03.16-10.30,39","/domains/Ylsrim/virtual/desert.c","/doc/lpc/concepts/message_doc","/save/kills/m/mdb","/doc/efun/objects/next_inventory","/doc/lpc/etc/error_msgs","/save/kills/o/ol","/secure/cfg/races/lizard","/save/kills/o/ok","/verbs/items/include/weigh.h","/secure/sefun/rooms.c","/domains/fort/obj/medtool.c","/log/chan/archive/intergossip-2010.10.16-22.45,48","/save/kills/o/og","/save/kills/k/kgjnlmcjdj","/doc/lfun/all/GetHeartRate","/log/chan/ds_test","/log/chan/archive/muds-2013.08.12-08.13,15","/doc/sefun/version","/domains/Praxis/obj/misc/pedestal.c","/doc/sefun/domain_master","/daemon/tmp/kurogane.c","/lib/teacher.c","/domains/fort/obj/slip_heal.c","/www/articles/old/tacitus2.html","/doc/lfun/lib/potion/GetStats","/log/chan/archive/muds-2010.10.10-21.45,48","/log/chan/archive/muds-2010.11.11-17.45,48","/doc/efun/all/floatp","/log/chan/archive/i2game-2009.05.16-11.59,29","/log/chan/archive/muds-2010.11.10-10.45,48","/domains/campus/room/medlab.c","/doc/lfun/lib/shell/GetFirearmType","/doc/lfun/lib/classes/GetClass","/lib/include/body.h","/doc/efun/objects/set_hide","/lib/include/fishing.h","/log/chan/archive/muds-2013.07.26-06.13,15","/domains/fort/obj/bin.c","/verbs/creators/wizlock.c","/log/chan/gossip","/domains/campus/room/usquare.c","/save/kills/x/xkcdagfmhhb","/save/kills/f/fegg","/log/chan/archive/muds-2010.09.03-18.45,48","/domains/default/weap/plasma.c","/log/chan/archive/muds-2009.04.11-23.28,44","/domains/campus/txt/ai/charles/bak2/bak1/red_wins","/save/kills/m/mndiclmkji","/domains/amigara/amigara/room/passage27.c","/log/chan/archive/i2news-2009.03.25-04.11,20","/lib/npc.c","/domains/default/obj/gps.c","/doc/efun/all/set_debug_level","/daemon/include/time.h","/save/kills/n/nnhgch","/save/kills/f/fiocffeeo","/lib/include/chat.h","/domains/default/obj/handbook.c","/log/chan/archive/muds-2009.05.24-04.21,26","/domains/default/npc/kender.c","/secure/obj/portal_blue.c","/save/kills/m/mbo","/daemon/tmp/A_BODY_ARMOR.c","/daemon/tmp/drone.c","/domains/examples/room/ex.h","/log/chan/archive/intergossip-2010.12.08-00.45,48","/doc/applies/id","/secure/obj/arch_board.c","/save/kills/f/fgmljfji","/doc/help/players/races","/log/chan/archive/muds-2010.08.25-02.45,48","/domains/Praxis/data/cleric_crypt.o","/doc/lfun/lib/firearm/eventUnload","/secure/include/pov.h","/log/chan/discworld_chat","/domains/fort/room/tunnel9.c","/domains/amigara/amigara/room/passage21.c","/www/ds-charmode-faq.html","/verbs/players/include/,withdraw.h","/log/chan/archive/muds-2010.12.25-13.46,44","/domains/town/obj/ebutton2.c","/domains/fort/armor/f_platemail.c","/doc/sefun/query_custom_command","/log/chan/archive/dchat-2010.07.30-04.17,46","/domains/cave/obj/chair.c","/domains/cave/npc/gorm.c","/log/chan/archive/muds-2010.11.11-03.45,48","/daemon/tmp/B_SNAKE.c","/log/chan/archive/muds-2010.11.02-10.45,48","/secure/obj/pingy.c","/log/chan/archive/intergossip-2010.12.23-20.45,48","/domains/Praxis/obj/mon/atmos.c","/verbs/items/include/get.h","/log/chan/archive/sport-2013.08.05-07.13,15","/log/chan/archive/intergossip-2010.08.12-13.18,42","/domains/fort/room/death.c","/domains/examples/room/entrance.c","/lib/include/carry.h","/doc/lfun/all/SetClanName","/domains/fort/npc/wtf.c","/domains/campus/obj/simple_chair.c","/log/rid","/domains/cave/obj/cask3.c","/domains/town/weap/cue.c","/domains/town/armor/platemail.c","/domains/Ylsrim/room/tower.c","/domains/fort/room/tunnel3.c","/doc/lfun/all/SetMinHeat","/doc/old/the_beginning.txt","/domains/town/obj/spam.c","/log/chan/archive/muds-2010.11.09-18.45,48","/domains/fort/npc/cat2.c","/domains/fort/doors/alpha.c","/log/chan/archive/muds-2010.11.08-11.45,48","/domains/default/npc/fighter.c","/save/kills/m/mai","/save/kills/x/xkcdldfinac","/log/archive/catch-2009.10.29-16.07,29","/domains/campus/room/science4.c","/domains/Ylsrim/room/kaliid5.c","/domains/fort/room/guildhouse.c","/secure/cmds/creators/heal.c","/domains/campus/armor/tshirt.c","/domains/cave/obj/garbage.c","/daemon/tmp/testylus'.c","/log/archive/runtime-2011.08.23-07.31,45","/domains/Praxis/mountains/chamber4.c","/save/kills/x/xkcdniom","/domains/fort/room/common18.c","/domains/examples/room/exroom4.c","/doc/efun/all/strcmp","/doc/efun/all/this_interactive","/domains/fort/armor/orc_boot_r.c","/domains/fort/room/mstreet2.c","/secure/sefun/user_path.c","/log/chan/archive/ds-2010.11.22-11.45,48","/domains/town/armor/cap.c","/secure/cmds/builders/arealist.c","/domains/town/room/vill_road4.c","/domains/fort/obj/cork.c","/doc/sefun/starts_with","/doc/lfun/lib/clay/SetComposition","/log/chan/archive/muds-2010.10.17-01.45,48","/domains/fort/room/common12.c","/domains/cave/armor/armored_glove_r.c","/log/chan/archive/muds-2010.11.09-04.45,48","/save/kills/a/aegdfaobcno","/log/chan/archive/muds-2013.08.25-15.13,15","/save/kills/c/cbnikddk","/domains/fort/weap/9mmpistol_loaded.c","/domains/Praxis/e_boc_la2.c","/doc/lfun/all/SetBodyComposition","/lib/include/command.h","/doc/lfun/lib/burn/eventBurnOut","/log/chan/archive/inews-2013.08.02-01.13,15","/domains/fort/armor/orc_boot_l.c","/save/kills/x/xkcdondmkcica","/doc/applies/parsing/parse_command","/domains/fort/room/bwall1.c","/save/types.4444.o","/lib/lamp.c","/secure/cfg/races/viper","/domains/town/weap/axe.c","/doc/lfun/lib/potion/SetPoints","/save/mudinfo.1111.o","/domains/default/weap/staff.c","/news/admin","/log/chan/archive/muds-2010.12.24-13.45,48","/log/chan/archive/muds-2009.10.03-22.41,27","/domains/fort/room/bpath5.c","/secure/daemon/.master.c.swp","/domains/town/meals/special.c","/domains/Praxis/cemetery/mon/ghost.c","/save/classes.3333.o","/domains/cave/armor/armored_glove_l.c","/secure/scripts/mass_update.src","/doc/efun/filesystem/get_dir","/doc/lfun/all/GetHeat","/log/chan/german","/doc/efun/all/link","/daemon/tmp/MOUTH_BEAKED.c","/domains/fort/room/stables.c","/domains/cave/room/wiz_hall.c","/log/chan/archive/muds-2010.08.24-22.45,48","/doc/lfun/lib/body/GetCellType","/secure/cfg/races/elf","/doc/sefun/remove_matching_line","/doc/lfun/all/RemoveLimb","/log/chan/archive/dchat-2013.07.30-18.13,15","/domains/amigara/amigara/room/passage18.c","/verbs/items/swivel.c","/log/chan/archive/muds-2010.07.08-13.16,00","/domains/Praxis/data/wall.o.gz","/verbs/players/follow.c","/log/chan/archive/muds-2010.11.10-23.45,48","/domains/fort/npc/bus.c","/domains/town/obj/d6.c","/doc/efun/all/next_inventory","/log/chan/igame","/www/lpmuds/sha1.js","/log/archive/reset-2009.05.24-14.22,17","/log/chan/archive/intergossip-2010.11.02-23.45,48","/domains/cave/obj/everstrike_match.c","/secure/daemon/finger.h","/doc/efun/system/eval_cost","/doc/efun/interactive/printf","/verbs/common/include/mail.h","/domains/campus/obj/.dcell_std.c.swp","/secure/daemon/function.c","/doc/efun/system/lpc_info","/shadows/zombie.c","/log/chan/archive/muds-2009.05.20-15.06,45","/domains/town/room/source.c","/domains/fort/room/wiz_hall.c","/secure/sefun/custom_path.c","/secure/daemon/finger.c","/doc/applies/object_name","/log/chan/archive/muds-2013.08.26-08.13,15","/secure/lib/connect","/domains/town/room/training.c","/doc/lfun/all/AddLimb","/log/chan/archive/muds-2013.08.08-22.13,15","/doc/build/Rooms","/save/portal.8888.o","/domains/amigara/amigara/room/osecret.c","/domains/Praxis/immortal_hall.c","/log/secure/foo.txt","/log/chan/inews","/domains/amigara/amigara/room/passage12.c","/log/chan/archive/dgd-2009.03.14-18.46,19","/doc/sefun/answers_to","/verbs/builders/add.c","/secure/daemon/mudinfo.c","/doc/efun/all/all_previous_objects","/obj/table.c","/lib/include/race.h","/domains/amigara/room/oguard.c","/secure/sefun/sockets.c","/log/chan/archive/sport-2013.08.18-14.13,15","/log/chan/archive/muds-2009.05.23-10.21,26","/domains/town/txt/vache.txt","/daemon/tmp/B_BIPED+B_INSECTOID.c","/log/chan/archive/sport-2009.03.15-13.30,39","/domains/amigara/room/guard_room.c","/log/chan/archive/muds-2010.09.17-18.45,48","/domains/campus/obj/mtable.c","/doc/lfun/all/SetMillimeter","/doc/efun/mappings/match_path","/domains/town/room/shop.c","/domains/Ylsrim/weapon/orc_slayer.c","/daemon/tmp/DEFINES_D.c","/log/chan/archive/muds-2010.12.11-05.45,48","/doc/efun/all/this_player","/domains/town/obj/church_wall.c","/secure/cmds/admins/files.c","/domains/cave/obj/letter.c","/domains/campus/doors/red_door.c","/domains/campus/armor/bandanna.c","/save/kills/x/xkcdobif","/domains/default/armor/ring_strength.c","/log/chan/archive/muds-2009.05.20-01.06,41","/log/archive/reset-2009.06.20-02.18,40","/secure/scripts/upgrades.txt","/log/archive/runtime-2009.07.06-13.57,13","/log/chan/archive/muds-2010.10.25-14.45,48","/log/chan/archive/muds-2010.10.16-21.45,48","/save/kills/n/nib","/domains/default/npc/satyr.c","/doc/lfun/lib/clip/SetFirearmType","/domains/amigara/room/passage23.c","/verbs/items/consult.c","/secure/daemon/file.c","/domains/town/weap/.m16rifle_mp.c.swp","/daemon/races.c","/verbs/rooms/include/swim.h","/save/kills/h/hiigknj","/doc/efun/general/index","/log/chan/archive/broken_gossip-2010.12.25-16.46,44","/cmds/creators/bugs.c","/log/chan/archive/inews-2013.07.29-20.13,15","/secure/cmds/admins/unbanish.c","/log/chan/archive/muds-2009.04.25-15.33,23","/domains/alpha/room/start.c","/domains/default/npc/quarantine/han.c","/doc/sefun/strip_colours","/secure/daemon/.instances.c.swp","/secure/include/config.8888.h","/save/kills/n/nbfdkmceoae","/cmds/creators/pwhere.c","/log/chan/archive/muds-2010.10.11-13.45,48","/log/chan/archive/muds-2010.09.09-18.45,48","/doc/lfun/lib/body/eventCheckProtection","/doc/lfun/lib/battery/Spent","/domains/fort/armor/bluedress.c","/doc/lfun/lib/body/AddDrink","/domains/default/npc/troll.c","/domains/cave/obj/.table2.c.swp","/log/chan/archive/muds-2010.11.11-02.45,48","/doc/efun/all/acos","/doc/applies/valid_object","/doc/efun/all/children","/domains/town/obj/medbag.c","/domains/Praxis/cemetery/mon/ghost4.c","/domains/default/room/test.c","/doc/lfun/all/GetNoChanColors","/doc/efun/all/call_out","/save/kills/c/ceoc","/secure/daemon/i3router/send_error.h","/secure/cmds/admins/opcprof.c","/doc/efun/sockets/index","/tmp/muds.txt","/secure/modules/mapping.c","/log/chan/archive/intergossip-2010.07.24-11.16,48","/doc/efun/interactive/resolve","/doc/lfun/lib/firearm/eventLoad","/save/kills/x/xkcdnoje","/log/archive/i3error-2009.05.09-19.58,26","/domains/fort/obj/testbag.c","/secure/cmds/admins/vars.c","/log/chan/archive/muds-2010.10.25-00.45,48","/cmds/creators/whereis.c","/log/chan/archive/muds-2010.11.09-17.45,48","/doc/lfun/lib/room/GetLong","/log/chan/archive/muds-2009.11.23-02.44,08","/log/chan/archive/muds-2010.11.08-10.45,48","/doc/lfun/lib/poison/AddPoison","/doc/lfun/all/SetNoChanColors","/doc/lfun/lib/clan/GetClanObject","/domains/default/npc/lemur.c","/daemon/tmp/LIB_LIE.c","/save/kills/x/xkcdchihcfbk","/domains/fort/obj/toy.c","/doc/lpc/basic/chapter8","/doc/lpc/basic/chapter7","/doc/lpc/basic/chapter6","/log/chan/archive/muds-2010.07.10-11.16,00","/doc/lpc/basic/chapter5","/doc/lpc/basic/chapter4","/doc/lpc/basic/chapter3","/domains/town/weap/verysharpsword.c","/domains/fort/room/livroom.c","/doc/lpc/basic/chapter2","/doc/lpc/basic/chapter1","/doc/applies/interactive/terminal_type","/log/chan/archive/muds-2010.12.26-05.46,44","/lib/events/knock.c","/domains/town/weap/9mil.c","/save/kills/x/xkcdeifikc","/log/chan/newbie","/log/chan/archive/dchat-2010.11.18-10.45,48","/domains/default/npc/hobbit.c","/powers/spells/.buffer.c.swp","/log/chan/archive/ds-2010.12.19-21.45,48","/domains/campus/txt/ai/charly/fblue","/log/chan/archive/dchat-2009.05.16-11.59,29","/doc/lpc/constructs/if","/verbs/items/include/use.h","/domains/fort/armor/dress.c","/daemon/include/classes.h","/save/kills/h/haoahkkocd","/daemon/tmp/workroom.c","/secure/include/voting.h","/domains/fort/armor/riding_boot.c","/lib/include/holder.h","/domains/town/npc/otik.c","/log/chan/archive/dchat-2010.10.13-13.45,48","/log/chan/archive/dchat-2010.10.04-20.45,48","/doc/lfun/lib/chat/returnChannels","/domains/town/obj/bed.c","/domains/Praxis/pit.c","/log/chan/archive/muds-2010.10.18-07.45,48","/domains/Praxis/obj/misc/deed.c","/lib/remote.c","/domains/fort/obj/chair.c","/domains/default/npc/quarantine/wim.c","/secure/cmds/creators/trace.c","/log/chan/archive/muds-2010.11.09-03.45,48","/save/kills/f/feegkdmbnd","/domains/amigara/amigara/room/ocommchamb.c","/log/chan/archive/muds-2013.08.16-21.13,15","/domains/town/room/chamber.c","/log/chan/archive/muds-2010.07.11-04.16,00","/domains/town/npc/clepius.c","/log/chan/archive/dchat-2010.10.28-07.45,48","/domains/fort/room/granary.c","/domains/campus/weap/9mmpistol_mp.c","/doc/applies/catch_tell","/doc/lfun/all/GetLimbs","/doc/efun/all/socket_error","/lib/include/firearm.h","/domains/campus/armor/jeans.c","/log/chan/archive/intergossip-2010.10.24-20.45,48","/doc/efun/arrays/map_array","/log/chan/archive/intergossip-2010.11.16-23.45,48","/doc/help/creators/staff","/save/kills/o/olnfbel","/doc/lfun/lib/chat/RestrictChannel","/doc/help/players/wordwrap","/doc/efun/all/program_info","/doc/efun/all/heart_beat_info","/save/kills/c/caoahm","/domains/cave/room/cavepass13.c","/log/chan/archive/muds-2010.09.24-10.45,48","/doc/lfun/lib/body/SetExtraChannels","/secure/cmds/creators/ced.c","/log/chan/archive/muds-2010.11.10-22.45,48","/doc/efun/mudlib/author_stats","/log/chan/archive/intergossip-2010.11.20-08.45,48","/domains/default/npc/balrog.c","/domains/amigara/room/passage14.c","/doc/lfun/lib/race/eventDie","/doc/lfun/lib/race/GetHeartRate","/doc/lfun/lib/client/eventDestruct","/shadows/rocketpack.c","/secure/daemon/portal.c","/secure/daemon/imc2server/server_log.h","/save/kills/x/xkcdgafhaeoiib","/save/kills/x/xkcdmghlen","/log/open/foo.txt","/domains/fort/room/f_road35.c","/verbs/items/wear.c","/domains/fort/obj/scroll_resurrection.c","/domains/Praxis/monk_join.c","/save/kills/j/jaahfjchfogjkg","/domains/cave/npc/orc_guard5.c","/log/chan/archive/muds-2013.08.25-00.13,15","/domains/default/npc/dwarf.c","/doc/lfun/all/GetResistance","/secure/cfg/races/avidryl","/doc/efun/all/terminal_colour","/save/kills/d/defaa","/domains/fort/npc/rat.c","/doc/applies/master/compile_object","/doc/efun/buffers/read_buffer","/log/chan/archive/intergossip-2009.03.27-18.17,31","/log/chan/archive/dchat-2010.12.20-11.45,48","/domains/town/armor/goggles.c","/log/archive/reset-2009.05.22-20.21,24","/domains/town/obj/church_button.c","/doc/efun/system/inherits","/verbs/players/include/backstab2.h","/domains/town/npc/spider.c","/domains/fort/npc/ariph.c","/save/kills/f/focnl","/daemon/news.c","/domains/town/armor/lvest.c","/domains/campus/txt/spam.txt","/doc/efun/internals/opcprof","/log/chan/archive/muds-2009.11.23-15.44,18","/domains/Praxis/bank_vault.c","/doc/efun/all/allocate_buffer","/save/kills/o/oonibn","/save/types.5555.o","/log/chan/archive/muds-2009.10.05-07.41,35","/domains/fort/npc/mayor.c","/domains/Ylsrim/etc/fighter_door.c","/save/classes.4444.o","/domains/cave/obj/.rack.c.swp","/log/chan/archive/muds-2010.11.02-22.45,48","/domains/town/room/south_road1.c","/log/errors/town","/lib/fish.c","/doc/lfun/lib/body/GetMelee","/domains/town/meals/herring.c","/domains/town/armor/hunting_cap.c","/save/classes.o","/log/chan/archive/dchat-2013.08.04-20.13,15","/log/chan/archive/dchat-2010.10.30-19.45,48","/verbs/players/backstab.c","/log/chan/archive/inews-2013.08.24-14.13,15","/log/archive/runtime-2009.03.18-08.30,39","/doc/efun/arrays/allocate","/tmp/opc.eoper","/domains/town/virtual/forest.c","/log/chan/archive/dgd-2009.03.30-08.51,27","/save/kills/c/cndinkfnbf","/domains/campus/npc/wim.c","/save/map.1111.o","/log/chan/archive/muds-2013.08.09-14.13,15","/domains/Praxis/obj/misc/app_board.c","/doc/efun/all/socket_create","/domains/fort/room/f_road8.c","/log/chan/archive/muds-2009.04.11-21.28,44","/log/chan/archive/muds-2010.09.11-02.45,48","/doc/efun/mappings/m_values","/doc/efun/sockets/socket_close","/log/chan/archive/muds-2010.11.17-16.45,48","/domains/town/virtual/forest/.-13,13.c.swp","/log/chan/archive/muds-2010.11.08-23.45,48","/doc/lfun/lib/interactive/eventReconnect","/save/kills/j/jjijbhef","/domains/amigara/room/kguards.c","/lib/props/inventory.c","/domains/fort/room/msquare_s.c","/secure/cmds/players/.peer.c.swp","/log/chan/archive/muds-2013.08.04-06.13,15","/lib/props/.inventory.c.swp","/secure/cfg/mudos.3333.cfg","/daemon/tmp/fighter_hall.c","/www/articles/old/patches.html","/log/chan/archive/dchat-2009.03.16-13.30,39","/lib/bank.c","/secure/scripts/general_check.txt","/domains/fort/room/f_road2.c","/domains/fort/npc/forest_orc3.c","/domains/default/npc/centaur.c","/log/chan/archive/muds-2010.10.20-05.45,48","/doc/lfun/lib/body/NewBody","/domains/fort/npc/wulkan.c","/log/chan/archive/muds-2010.11.12-08.45,48","/doc/lpc/concepts/preprocessor","/log/chan/archive/muds-2010.11.03-15.45,48","/save/kills/o/ojimkddj","/domains/fort/obj/ebutton2.c","/log/chan/archive/muds-2010.11.11-01.45,48","/doc/sefun/distinct_array","/log/chan/archive/dchat-2010.07.21-17.16,17","/doc/lfun/lib/body/GetCanBite","/domains/campus/meals/.badapple.c.swp","/doc/applies/master/valid_object","/doc/efun/all/match_path","/secure/include/object.h","/lib/include/item.h","/domains/default/weap/grenade.c","/domains/campus/room/tunnel3.c","/doc/lfun/lib/burn/eventExtinguish","/doc/lfun/all/HealLimb","/log/chan/archive/muds-2010.11.09-16.45,48","/save/kills/o/one","/log/chan/archive/muds-2010.11.17-02.45,48","/domains/Praxis/obj/misc/hood.c","/doc/lfun/lib/burn/GetHeat","/log/chan/archive/muds-2009.05.15-03.59,29","/domains/fort/weap/paring_knife.c","/secure/sefun/this_agent.c","/domains/campus/txt/ai/charles/bak2/bak1/wins","/domains/town/weap/carving_knife.c","/cmds/creators/expel.c","/log/chan/i2game","/log/chan/archive/muds-2010.07.10-10.16,00","/domains/town/meals/ham_sand.c","/lib/virtual/virtual.c","/domains/town/obj/223clip.c","/doc/efun/mudlib/living","/secure/include/rooms.1111.h","/domains/town/armor/helmet.c","/verbs/items/include/put.h","/domains/campus/txt/ai/charles/wins","/doc/sefun/query_night","/doc/lfun/all/eventReconnect","/log/chan/archive/muds-2009.04.09-22.28,44","/domains/town/virtual/sky/28,5,1.c","/log/chan/archive/muds-2009.05.20-20.07,28","/domains/town/obj/candlestick.c","/domains/fort/room/f_road26.c","/doc/lfun/lib/messages/GetName","/log/chan/i2news","/domains/campus/obj/50round.c","/doc/sefun/tell_player","/doc/lfun/lib/body/GetHealRate","/secure/cfg/races/satyr","/domains/campus/room/access4.c","/secure/cmds/players/passwd.c","/log/chan/archive/imudnews-2010.09.18-23.45,48","/doc/lfun/all/ChangeClass","/save/kills/d/dm","/secure/cfg/races/troll","/domains/default/npc/rat.c","/save/kills/d/di","/save/kills/b/bhfjd","/doc/lfun/lib/body/eventReconnect","/secure/include/user.h","/domains/cave/armor/loincloth.c","/domains/fort/room/f_road20.c","/log/chan/archive/muds-2010.11.09-02.45,48","/log/chan/archive/intergossip-2013.07.26-17.13,15","/lib/include/vendor.h","/domains/campus/room/void.c","/domains/town/room/magic_shop.c","/secure/cmds/players/afk.c","/domains/town/meals/stein.c","/doc/help/creators/editor","/doc/efun/all/clone_object","/domains/fort/room/north_wall_2.c","/log/archive/runtime-2009.07.16-13.08,40","/save/kills/f/ffccecnfhho","/log/chan/archive/muds-2010.09.10-22.45,48","/doc/lpc/concepts/mappings","/secure/cfg/races/bugbear","/doc/efun/strings/regexp","/secure/cmds/creators/include/gg.h","/domains/town/virtual/sky/23,9,1.c","/doc/efun/all/debug_info","/domains/Praxis/obj/misc/stone.c","/log/chan/archive/sport-2013.08.27-19.13,15","/lib/editor.c","/domains/default/armor/pscoutsuit.c","/save/kills/j/jjji","/log/chan/archive/muds-2009.05.23-22.21,26","/domains/fort/armor/sandalf_r.c","/doc/help/players/map","/domains/default/room/void.c","/domains/Ylsrim/adm/README","/log/servers","/log/chan/archive/muds-2013.08.11-12.13,15","/verbs/items/include/steal.h","/save/kills/h/hmmejjbkih","/www/smflogo.gif","/daemon/tmp/B_FISH.c","/domains/town/room/mansion_uhall1.c","/news/hints.txt","/domains/town/obj/shamelog.c","/cmds/creators/elog.c","/log/chan/archive/muds-2010.09.25-16.45,48","/domains/campus/room/alcove2.c","/save/kills/k/kfkgjknf","/doc/lfun/all/GetMissingLimbs","/log/chan/archive/muds-2010.11.10-21.45,48","/doc/applies/epilog","/domains/fort/weap/filet_knife.c","/cmds/players/mute.c","/log/chan/archive/sport-2013.08.13-18.13,15","/domains/campus/room/green_room.c","/doc/sefun/currency_value","/doc/sefun/reflexive","/log/chan/archive/muds-2009.05.18-19.00,12","/domains/fort/armor/badge2.c","/domains/town/armor/oldstyle_ring.c","/domains/fort/armor/sandalf_l.c","/doc/lfun/lib/potion/GetSkills","/secure/sefun/get_stack.c","/log/chan/archive/muds-2013.07.26-17.13,15","/doc/efun/strings/lower_case","/domains/town/room/road1.c","/doc/efun/all/get_config","/domains/default/room/builder_hall.c","/doc/sefun/add_sky_event","/log/chan/archive/muds-2013.08.17-13.13,15","/domains/town/obj/mailbox.c","/log/errors/two","/log/chan/archive/muds-2010.09.20-08.45,48","/log/chan/archive/muds-2010.08.17-00.45,20","/std/prop_logic.c","/log/reports/foo.txt","/log/chan/archive/muds-2010.09.11-15.45,48","/doc/sefun/user_path","/daemon/time.c","/save/kills/o/okn","/log/chan/test","/log/archive/reset-2010.08.12-01.18,42","/secure/cmds/admins/whobanished.c","/log/chan/archive/muds-2010.12.17-18.45,48","/daemon/tmp/LIB_SIT.c","/domains/amigara/virtual/server.c","/domains/Ylsrim/broken/flu.c","/cmds/admins/objload.c","/secure/cmds/creators/goto.c","/log/chan/archive/muds-2010.12.16-11.45,48","/domains/town/txt/advancement.txt","/log/chan/archive/intergossip-2010.12.09-18.45,48","/domains/Praxis/west_road2.c","/domains/Praxis/orc_valley/treasure.c","/doc/lfun/lib/bonus/SetBonusDuration","/domains/town/armor/.jeans.c.swp","/domains/fort/room/south_wall_2.c","/doc/lfun/all/ParseHook","/www/articles/articles.html","/log/chan/archive/muds-2010.08.25-13.45,48","/domains/town/room/mansion_ext.c","/secure/include/secrets.bak","/log/chan/archive/muds-2010.09.26-09.45,48","/doc/efun/system/shutdown","/doc/lfun/all/CanJoin","/log/chan/archive/muds-2010.09.25-02.45,48","/log/chan/archive/muds-2010.11.11-14.45,48","/domains/fort/armor/long_glove.c","/doc/efun/all/wizardp","/doc/lfun/lib/body/GetStaminaPoints","/save/kills/x/xkcdklli","/log/chan/archive/muds-2009.04.28-13.47,39","/secure/daemon/options.h","/domains/cave/obj/jerkybox2.c","/log/chan/archive/sport-2013.08.04-11.13,15","/doc/lfun/lib/classes/GetMoralityDescription","/secure/daemon/options.c","/log/chan/intercre","/domains/fort/obj/tower_key.c","/log/chan/archive/muds-2013.08.18-06.13,15","/domains/Praxis/app_room.c","/log/chan/archive/muds-2013.08.09-13.13,15","/domains/fort/obj/trash.c","/log/chan/archive/muds-2009.04.11-20.28,44","/cmds/creators/cryptogram.c","/domains/amigara/amigara/room/rats.c","/domains/Praxis/obj/mon/easter_bunny.c","/log/chan/archive/muds-2010.11.08-22.45,48","/daemon/tmp/MOUTH_TONGUED.c","/log/chan/archive/inews-2013.08.11-19.13,15","/domains/campus/txt/skulls.txt","/secure/cmds/admins/whoregistered.c","/domains/fort/room/f_road17.c","/doc/efun/all/classp","/doc/applies/telnet_suboption","/save/kills/x/xkcdfjbgaajd","/save/kills/h/hnecoae","/domains/Praxis/w_boc_la2.c","/www/lpmuds/intermud.html","/doc/lfun/lib/battery/GetCellType","/log/chan/archive/muds-2013.08.04-05.13,15","/lib/std/.room.c.swp","/domains/town/room/mansion_room10.c","/cmds/players/.stat.c.swp","/secure/cmds/creators/more.c","/domains/fort/weap/butcher_knife.c","/domains/Praxis/pass1.c","/log/chan/archive/muds-2011.01.05-17.46,13","/doc/applies/master/retrieve_ed_setup","/save/kills/f/febge","/verbs/items/look.c","/log/chan/archive/muds-2010.09.17-02.45,48","/lib/events/read.c","/cmds/players/.gag.c.swp","/domains/campus/obj/key.c","/doc/lfun/lib/round/GetFirearmType","/doc/lfun/lib/body/GetWielded","/doc/lpc/types/buffer","/log/chan/archive/muds-2010.11.11-00.45,48","/save/types.6666.o","/domains/fort/room/f_road11.c","/doc/lfun/lib/bank/HandleTeller","/log/chan/archive/muds-2010.12.03-03.45,48","/log/chan/archive/intergossip-2013.08.20-18.13,15","/save/mudinfo.3333.o","/secure/include/.runtime_config.h.swp","/save/classes.5555.o","/secure/sefun/.sefun.c.swp","/log/archive/runtime-2009.12.29-11.59,12","/secure/cmds/players/tell.c","/domains/Ylsrim/adm/access.c","/secure/cmds/admins/removeclass.c","/doc/lfun/lib/light/eventLight","/www/articles/router_controversy.html","/verbs/players/include/lead.h","/domains/town/obj/dcell_crappy.c","/domains/fort/armor/steel_boot_r.c","/verbs/items/balance.c","/domains/cave/armor/orc_boot_r.c","/doc/lfun/lib/body/eventRemoveItem","/log/chan/archive/muds-2010.10.26-05.45,48","/save/kills/x/xkcdomf","/domains/town/room/wtunnel4.c","/log/chan/archive/muds-2009.04.27-13.46,44","/log/chan/archive/muds-2010.11.09-15.45,48","/secure/cmds/players/mc.c","/save/map.2222.o","/domains/fort/weap/m16rifle_mp.c","/lib/std/worn_storage.c","/save/kills/x/xkcdbdgd","/verbs/items/smell.c","/lib/undead.c","/domains/Praxis/obj/misc/bag.c","/secure/sefun/communications.c","/save/kills/c/cacab","/domains/fort/armor/steel_boot_l.c","/doc/lfun/lib/player/GetName","/log/chan/archive/intergossip-2010.09.10-21.45,48","/domains/cave/armor/orc_boot_l.c","/lib/events/press.c","/doc/efun/general/restore_variable","/log/chan/archive/muds-2010.10.03-11.45,48","/include/position.h","/doc/efun/all/uptime","/log/chan/archive/muds-2010.11.04-07.45,48","/log/chan/archive/muds-2009.04.26-18.05,53","/domains/town/obj/.bed.c.swp","/log/chan/archive/muds-2013.08.20-18.13,15","/domains/campus/weap/knife.c","/doc/lfun/lib/armor/eventReceiveDamage","/log/chan/archive/mudnews-2013.08.24-18.13,15","/log/chan/archive/dchat-2010.12.28-17.46,48","/domains/Praxis/cleric_join.c","/daemon/tmp/commander.c","/doc/help/classes/cleric","/doc/efun/all/clear_bit","/lib/include/currency.h","/doc/sefun/replace_matching_line","/log/chan/archive/dchat-2011.01.06-10.46,13","/doc/efun/all/sort_array","/secure/cfg/read.cfg","/save/kills/h/hnedckiln","/domains/campus/save/charles.o","/save/kills/x/xkcdcmioag","/log/chan/archive/muds-2009.03.27-07.11,20","/lib/include/trainer.h","/log/chan/fluffos","/domains/fort/obj/wall.c","/log/chan/archive/muds-2010.11.09-01.45,48","/lib/include/clip.h","/log/chan/archive/dchat-2010.07.19-17.16,17","/doc/lfun/lib/body/SetDrainRate","/cmds/players/.who.c.swp","/doc/lfun/lib/clean/eventDestruct","/lib/magic.c","/cmds/creators/rehash.c","/log/chan/archive/free_speech-2013.08.20-08.13,15","/doc/lfun/lib/clan/eventWelcome","/domains/fort/room/east_wall_3.c","/domains/fort/obj/pin.c","/doc/efun/all/throw","/domains/town/meals/spazalin.c","/domains/town/virtual/sky/22,9,1.c","/save/kills/o/ooeijgck","/domains/fort/armor/sock.c","/verbs/players/include/nominate.h","/domains/town/room/start.c","/doc/efun/all/dump_file_descriptors","/save/kills/e/ejjcni","/domains/campus/txt/hug.txt","/log/chan/archive/muds-2013.08.12-18.13,15","/secure/include/clean_up.h","/log/chan/archive/muds-2013.08.20-04.13,15","/domains/default/obj/sofa.c","/save/kills/x/xkcdclm","/log/chan/archive/dchat-2010.09.20-21.45,48","/secure/include/rooms.2222.h","/secure/cfg/mudos.4444.win32","/log/chan/archive/muds-2010.07.09-17.16,00","/lib/.bonus.c.swp","/doc/efun/all/ed_start","/log/chan/archive/muds-2010.11.10-20.45,48","/save/soul.1111.o","/domains/town/weap/javelin.c","/log/chan/archive/muds-2013.07.26-16.13,15","/domains/town/doors/m5.c","/secure/tmp/pilgrim_CMD_EVAL_TMP_FILE.c","/domains/campus/room/red_room2.c","/log/chan/archive/imudnews-2010.07.18-23.16,17","/doc/build/Meals","/log/chan/archive/muds-2009.03.15-18.30,39","/domains/fort/room/tailor.c","/domains/campus/room/green_room3.c","/log/security","/domains/town/room/freezer.c","/domains/fort/armor/overalls.c","/domains/cave/room/pod.c","/secure/modules/create.c","/secure/lib/net/oob.c","/domains/amigara/room/passage7.c","/www/lpmuds/links_files/smflogo.gif","/log/chan/archive/intergossip-2010.11.17-14.45,48","/domains/amigara/amigara/room/furnace.c","/doc/lfun/all/AddQuestPoints","/log/chan/archive/sport-2013.08.27-04.13,15","/domains/town/meals/shark.c","/doc/lfun/lib/potion/GetPoints","/save/kills/e/ebhhnnld","/log/chan/archive/intergossip-2009.05.15-15.59,29","/domains/alpha/room/pod.c","/lib/std/bot_corpse.c","/domains/fort/obj/rack.c","/domains/campus/txt/jenny/11.txt","/doc/efun/all/check_memory","/domains/Praxis/mountains/tunnel3.c","/secure/cfg/races/tree","/domains/campus/txt/ai/charles/switches","/domains/default/npc/helf.c","/domains/Praxis/s_centre1.c","/secure/cmds/players/praise.c","/domains/campus/obj/chair.c","/domains/cave/weap/dagger.c","/domains/amigara/amigara/room/wiz_hall.c","/secure/daemon/i3router/remove_mud.h","/domains/amigara/room/passage1.c","/daemon/tmp/KNIFE.c","/secure/cmds/admins/addclasses.c","/domains/town/armor/workglove_r.c","/save/kills/n/nmchffddkec","/log/archive/reset-2009.05.21-00.13,36","/doc/lfun/lib/body/AddQuestPoints","/doc/lfun/all/eventJoin","/www/lpmuds/downloads_files/print.css","/domains/campus/obj/pack.c","/doc/efun/all/rmdir","/cmds/creators/anchor.c","/log/chan/archive/muds-2010.08.20-04.45,48","/domains/town/room/magic_shop2.c","/log/chan/archive/intergossip-2010.07.24-22.16,48","/secure/cmds/admins/addrace.c","/log/chan/archive/dchat-2010.11.21-13.45,48","/log/chan/archive/dchat-2009.03.23-02.17,00","/domains/fort/room/guardhouse.c","/doc/lfun/all/RestrictChannel","/cmds/players/money.c","/doc/applies/interactive/process_input","/domains/default/obj/chair.c","/domains/Praxis/highway2.c","/doc/sefun/grepp","/secure/cmds/creators/update.c","/secure/cmds/creators/economy.c","/log/chan/archive/intergossip-2010.10.18-18.45,48","/doc/efun/numbers/index","/log/chan/archive/sport-2013.07.28-08.13,15","/domains/fort/doors/test_door2.c","/www/cgi/edit_script.js","/domains/town/obj/room_item.c","/save/kills/c/cgoihaec","/log/chan/archive/muds-2010.11.08-21.45,48","/domains/town/armor/workglove_l.c","/domains/fort/obj/gtable","/doc/sefun/read_database","/log/chan/archive/intergossip-2010.11.18-07.45,48","/log/chan/archive/muds-2010.12.17-03.45,48","/lib/include/touch.h","/domains/cave/obj/stein.c","/daemon/tmp/otto.c","/lib/props/clean.c","/domains/town/obj/flask.c","/std/room.c","/domains/default/armor/.jeans.c.swp","/log/chan/archive/intergossip-2010.12.09-03.45,48","/domains/default/npc/drone2.c","/daemon/include/ftp_port_tracker.h","/secure/cfg/ip_blacklist.cfg","/lib/include/steal.h","/doc/lfun/all/GetEncumbrance","/secure/cmds/creators/cat.c","/domains/campus/txt/jenny/1.txt","/log/chan/archive/muds-2010.08.26-05.45,48","/lib/lead.c","/secure/cfg/races/fish","/log/chan/archive/muds-2009.05.24-20.22,24","/domains/fort/room/bastion.c","/secure/daemon/i3router/broadcast_mudlist.h","/secure/cfg/global_template.cfg","/save/kills/o/odb","/domains/Praxis/void.c","/save/kills/x/xkcdaefe","/verbs/builders/modify.c","/domains/default/npc/giant.c","/save/kills/m/mlanmdh","/save/kills/x/xkcdahheabdlb","/save/kills/x/xkcdjnbllohe","/log/chan/archive/dgd-2009.03.27-05.11,20","/doc/sefun/center","/doc/efun/all/remove_call_out","/domains/campus/txt/ai/charly/percent","/domains/Praxis/hospital.c","/save/deviation.1111.o","/domains/amigara/amigara/room/pod.c","/doc/lfun/lib/body/GetEncumbrance","/log/chan/archive/imudnews-2010.10.01-09.45,48","/domains/town/room/mansion_room7.c","/doc/lfun/lib/potion/SetStats","/domains/default/virtual/server.c","/domains/Praxis/cemetery/grave_yard5.c","/doc/lfun/lib/player/GetLong","/doc/efun/general/save_variable","/daemon/services/oob.c","/log/chan/archive/sport-2013.08.20-23.13,15","/lib/quest.c","/log/chan/archive/muds-2010.09.03-00.45,48","/domains/default/obj/pin.c","/log/chan/archive/muds-2010.10.17-11.45,48","/log/chan/archive/muds-2009.03.26-13.11,20","/doc/lfun/lib/classes/SetClass","/log/chan/archive/muds-2010.11.09-14.45,48","/log/adm/foo.txt","/log/chan/archive/muds-2009.07.23-14.15,28","/save/kills/x/xkcdcjbakgbdmc","/domains/town/weap/sword.c","/domains/campus/npc/dummy.c","/doc/help/creators/creweb","/doc/lfun/all/AddFood","/secure/daemon/wget.c","/www/lpmuds/downloads_files/script.js","/domains/town/room/mansion_room1.c","/domains/cave/room/cavepass9.c","/log/chan/archive/muds-2010.10.04-17.45,48","/domains/fort/obj/m_key.c","/doc/efun/calls/remove_call_out","/log/chan/archive/muds-2010.10.12-03.45,48","/lib/.combat.c.swp","/domains/campus/txt/ai/charles/bak2/runs","/log/chan/archive/muds-2009.04.09-20.28,44","/domains/fort/armor/helmet.c","/log/chan/archive/muds-2010.09.09-01.45,48","/domains/Ylsrim/meal/stew.c","/log/chan/archive/muds-2013.08.20-17.13,15","/save/kills/a/amlmjgbmjho","/secure/daemon/reaper.c","/domains/fort/npc/orc.c","/verbs/items/poison.c","/domains/default/npc/dummy.c","/doc/sefun/indent_file","/doc/lfun/lib/body/SetCanBite","/log/chan/archive/intergossip-2009.10.05-18.41,35","/secure/lib/net/socket.c","/log/chan/archive/inews-2013.08.08-12.13,15","/domains/default/npc/quarantine/ton.c","/save/kills/b/beijg","/log/chan/archive/muds-2010.09.24-21.45,48","/domains/cave/room/cavepass3.c","/domains/town/npc/mp.c","/doc/efun/all/set_eval_limit","/domains/campus/txt/ai/charly/bak/stays","/secure/cmds/admins/resetall.c","/log/chan/archive/muds-2010.12.10-22.45,48","/domains/default/weap/rpg.c","/domains/cave/meals/bread.c","/save/mudinfo.4444.o","/log/chan/archive/inews-2009.03.24-20.11,20","/lib/door.c","/domains/campus/obj/45round.c","/secure/cfg/races/goblin","/save/classes.6666.o","/lib/events/jump.c","/doc/lfun/lib/body/GetAffectLong","/log/chan/archive/muds-2010.11.09-00.45,48","/log/chan/archive/muds-2009.04.14-05.29,16","/domains/fort/room/tguild.c","/log/chan/archive/muds-2010.08.17-12.45,20","/domains/campus/txt/ai/charly/bak/switches","/log/law/email/foo.txt","/secure/obj/portal_orange.c","/daemon/tmp/BOARDS_D.c","/save/map.3333.o","/domains/fort/room/cell1.c","/doc/lfun/lib/virt_sky/CanFly","/domains/fort/armor/robe.c","/domains/default/npc/halfling.c","/verbs/items/open.c","/lib/include/classes.h","/domains/Ylsrim/etc/wall.c","/www/cgi/upload.c","/lib/events/drop.c","/domains/Praxis/mountains/temp.c","/log/chan/archive/muds-2013.08.12-17.13,15","/doc/lfun/lib/chapel/eventSacrifice","/domains/town/obj/needle_trap2.c","/domains/campus/npc/yulia.c","/save/kills/f/fdlgleoao","/doc/applies/parsing/parse_command_plural_id_list","/verbs/items/include/poison.h","/domains/town/obj/orc_rucksack.c","/log/chan/archive/intergossip-2010.10.20-16.45,48","/lib/.chario.c.swp","/domains/fort/obj/shamelog.c","/log/chan/trivia_games","/domains/campus/armor/badge2.c","/log/chan/archive/inews-2009.03.25-13.11,20","/secure/scripts/powerbots.src","/daemon/tmp/MOUTH_TOOTHED+MOUTH_TONGUED.c","/save/kills/x/xkcdnalghll","/domains/fort/npc/bench_guard.c","/doc/sefun/get_cmds","/domains/fort/armor/ring3.c","/domains/fort/armor/plated_pants.c","/log/chan/archive/muds-2009.05.20-11.06,41","/doc/sefun/levenshtein_distance","/doc/lfun/lib/battery/SetCellType","/verbs/common/include/shout.h","/log/chan/archive/intergossip-2009.03.20-14.16,52","/doc/efun/system/time","/log/chan/archive/i2news-2009.03.25-13.11,20","/domains/town/npc/viper.c","/doc/lfun/all/SetDeathEvents","/www/index.html","/log/chan/archive/intergossip-2010.09.03-13.45,48","/domains/fort/obj/cot.c","/doc/lfun/lib/classes/AddSkillPoints","/save/kills/x/xkcdibjj","/domains/town/obj/safe.c","/doc/efun/system/functions","/doc/build/Towns","/doc/lpc/concepts/socket_efuns","/secure/cmds/admins/instconfig.c","/doc/lpc/constructs/switch","/domains/town/npc/troll.c","/domains/campus/txt/rose.txt","/secure/daemon/imc2server/ssocket.c","/log/chan/archive/muds-2010.11.12-19.45,48","/doc/efun/sockets/socket_acquire","/doc/lfun/lib/worn_storage/GetFingers","/doc/applies/valid_compile_to_c","/doc/lfun/lib/body/SetDeathEvents","/domains/fort/room/common1","/verbs/players/ride.c","/log/chan/archive/intergossip-2010.09.09-14.45,48","/save/kills/g/gfeiobck","/doc/lfun/lib/race/GetHealRate","/log/chan/archive/muds-2009.04.28-11.47,39","/log/chan/archive/dgd-2009.03.27-18.11,20","/doc/lpc/basic/Contents","/secure/include/rooms.3333.h","/log/chan/archive/sport-2013.08.13-02.13,15","/domains/town/armor/bearsuit.c","/domains/Praxis/sewer_ent.c","/save/kills/b/bnlgoced","/log/chan/archive/inews-2009.04.13-05.29,16","/doc/lfun/lib/body/AddMoJo","/verbs/rooms/fly.c","/log/chan/archive/muds-2009.10.06-17.42,42","/save/soul.2222.o","/save/kills/i/ig","/log/chan/archive/muds-2009.03.20-14.16,52","/log/chan/archive/dchat-2010.12.22-08.45,48","/lib/base_trainer.c","/domains/town/room/well2.c","/secure/daemon/.imc2.c.swp","/save/kills/i/ib","/lib/events/bait_with.c","/log/chan/archive/muds-2010.10.25-10.45,48","/secure/cfg/races/arachnid","/doc/efun/system/max_eval_cost","/doc/efun/floats/cos","/domains/Praxis/hole.c","/log/chan/archive/muds-2010.11.08-20.45,48","/domains/amigara/room/ocommon.c","/domains/Praxis/orc_valley/open.c","/log/chan/archive/muds-2009.05.19-19.06,41","/domains/default/npc/orc.c","/domains/Praxis/obj/mon/mora.c","/doc/lfun/lib/deterioration/eventReceiveDamage","/secure/sefun/files.c","/log/chan/archive/muds-2009.03.13-22.46,02","/domains/Praxis/data/wall.o","/doc/efun/floats/index","/secure/lib/net/uptime_server.c","/open/CMD_EVAL_TMP_FILE.c","/secure/sefun/visible.c","/log/chan/archive/muds-2010.09.18-07.45,48","/log/chan/archive/muds-2010.11.04-19.45,48","/log/chan/archive/intergossip-2010.10.13-09.45,48","/log/chan/archive/muds-2010.11.12-05.45,48","/domains/town/room/adv_guild.c","/domains/campus/armor/vest.c","/std/wiz_hall.c","/doc/efun/mudlib/set_privs","/doc/lfun/lib/body/eventCheckHealing","/log/chan/foo.txt","/domains/fort/armor/visor.c","/doc/lfun/all/AddDrink","/log/chan/archive/sport-2009.03.22-17.11,20","/doc/efun/all/generate_source","/save/kills/x/xkcdhmnkbdjgn","/log/chan/archive/muds-2009.05.07-09.13,35","/log/chan/archive/ichat2-2011.01.11-21.46,55","/secure/daemon/update.patch","/save/kills/x/xkcdhbofnlgd","/doc/efun/interactive/interactive","/secure/obj/post.c","/log/chan/archive/muds-2010.09.04-06.45,48","/secure/obj/mojo.c","/log/chan/archive/muds-2010.10.18-17.45,48","/log/chan/archive/muds-2009.04.12-11.28,44","/cmds/admins/mfinger.c","/doc/applies/master/save_ed_setup","/secure/sefun/flat_map.c","/secure/cmds/admins/rid.c","/domains/Praxis/realty.c","/log/chan/archive/muds-2010.11.18-06.45,48","/log/chan/archive/intergossip-2010.12.10-21.45,48","/log/chan/archive/muds-2010.11.09-13.45,48","/log/chan/archive/muds-2009.04.14-18.29,16","/secure/cmds/admins/whoallowed.c","/www/mudlist.html","/secure/cmds/creators/qed.c","/save/kills/k/khdkkkmfka","/domains/campus/obj/tree.c","/secure/cmds/admins/allow.c","/log/chan/archive/intergossip-2013.07.25-21.13,15","/log/chan/archive/dchat-2010.12.30-00.46,48","/doc/help/players/communication","/save/kills/b/bbmdcgdmhnj","/doc/lfun/lib/burn/CanExtinguish","/log/chan/bsg","/doc/lfun/all/eventCharge","/secure/tmp/testylus","/doc/efun/all/socket_accept","/log/chan/archive/muds-2011.01.05-01.46,13","/domains/fort/obj/greenbox.c","/save/kills/x/xkcdnmdebici","/domains/town/obj/simple_chair.c","/doc/efun/arrays/unique_array","/www/errors/badgate.html","/secure/scripts/native_version.proto","/log/chan/archive/muds-2010.09.09-00.45,48","/log/chan/archive/muds-2013.08.11-23.13,15","/domains/town/obj/rug.c","/doc/help/players/locate","/lib/props/uniqueness.c","/domains/campus/txt/ai/charles/red_wins","/domains/campus/room/basement.c","/domains/campus/txt/ai/charles/bak2/fgreen","/doc/efun/all/query_ip_port","/log/chan/archive/dchat-2011.01.07-15.46,13","/domains/amigara/room/cave.c","/verbs/items/.use.c.swp","/powers/spells/whip.c","/log/chan/archive/muds-2010.07.08-22.16,00","/domains/fort/obj/trashcan.c","/doc/old/RELEASE_NOTES.old","/log/chan/archive/sport-2013.08.21-15.13,15","/domains/campus/obj/45case.c","/log/chan/archive/inews-2009.05.14-14.59,29","/doc/efun/all/unique_array","/secure/cmds/admins/removerace.c","/log/instances","/save/deviation.2222.o","/save/kills/m/mknlecmdhh","/domains/town/obj/shelf.c","/log/chan/archive/muds-2010.09.20-19.45,48","/doc/lfun/lib/body/GetRandomLimb","/log/chan/archive/mudnews-2013.07.29-21.13,15","/doc/efun/internals/cache_stats","/domains/fort/obj/banner.c","/doc/lfun/all/SetAllowSacrifice","/domains/town/npc/rainman.c","/cmds/players/idle.c","/secure/cfg/classes/explorer","/lib/include/pole.h","/lib/include/lock.h","/domains/campus/room/foyer.c","/doc/lfun/all/GetMissingLimbParents","/secure/cmds/creators/last.c","/log/router/server_log","/domains/default/npc/bear.c","/save/kills/x/xkcdmnekc","/log/chan/archive/muds-2010.10.04-02.45,48","/domains/fort/obj/diamond.c","/domains/fort/room/cobbler.c","/secure/cmds/admins/var.c","/save/kills/g/gjkead","/doc/lfun/lib/bonus/GetStats","/doc/phints/chapter05","/doc/phints/chapter04","/doc/phints/chapter03","/doc/lfun/all/CanRelease","/doc/phints/chapter02","/doc/phints/chapter01","/log/archive/i3error-2009.05.10-20.58,26","/domains/campus/room/uptree.c","/save/kills/x/xkcdnfmlfocmh","/log/archive/runtime-2009.09.08-16.25,07","/domains/town/weap/butcher_knife.c","/domains/fort/obj/ped_button.c","/doc/efun/all/enable_commands","/log/chan/archive/muds-2009.04.30-20.08,36","/daemon/tmp/WATER.c","/doc/lfun/lib/player/eventReconnect","/cmds/creators/clean.c","/domains/town/armor/shield.c","/secure/include/comp.h","/domains/fort/weap/javelin.c","/doc/efun/general/copy","/doc/lfun/lib/body/GetDrink","/domains/town/obj/cigar.c","/secure/sefun/percent.c","/domains/town/virtual/server.c","/save/types.8888.o","/log/chan/archive/muds-2010.09.12-19.45,48","/log/chan/archive/intergossip-2010.08.21-09.45,48","/powers/spells/missile.c","/log/chan/archive/muds-2010.10.25-23.45,48","/log/chan/coffeemud_universe","/domains/town/weap/fellsword.c","/secure/modules/file.c","/secure/include/global.prime","/secure/sefun/.reload.c.swp","/domains/Praxis/obj/misc/easter_egg.c","/doc/applies/crash","/domains/town/weap/board.c","/domains/fort/room/freezer.c","/doc/lfun/lib/creator/GetName","/secure/cmds/creators/localcmds.c","/save/kills/o/ojfofbmdce","/log/chan/archive/muds-2013.08.13-09.13,15","/domains/cave/room/guardroom4.c","/log/archive/runtime-2009.09.09-07.31,11","/lib/events/turn.c","/log/chan/archive/muds-2013.08.04-16.13,15","/doc/efun/all/tell_room","/save/map.4444.o","/log/chan/archive/muds-2010.10.20-15.45,48","/www/cgi/login.c","/log/chan/archive/muds-2010.12.25-21.46,44","/log/chan/archive/ichat2-2010.08.04-15.18,42","/doc/efun/system/replace_program","/save/kills/g/gdgl","/domains/default/doors/steel_door3.c","/secure/sefun/timestamp.c","/domains/amigara/amigara/room/death.c","/save/kills/x/xkcdlddoohfm","/save/kills/m/mncdbhdbig","/log/chan/archive/muds-2010.11.11-11.45,48","/domains/town/obj/wardrobe.c","/secure/daemon/i3router/readme.txt","/cmds/players/stats.c","/log/chan/archive/inews-2009.03.26-05.11,20","/doc/sefun/archp","/save/kills/x/xkcdgmdob","/daemon/tmp/suit.c","/save/kills/h/hkiahlilg","/log/chan/archive/muds-2010.08.21-09.45,48","/log/chan/archive/muds-2010.07.07-21.15,58","/lib/include/shell.h","/doc/efun/all/find_player","/doc/lfun/all/GetMelee","/save/kills/k/khobekcfhci","/log/chan/archive/muds-2010.09.03-12.45,48","/log/chan/archive/dchat-2010.12.13-14.45,48","/secure/cmds/creators/.people.c.swp","/log/chan/archive/muds-2009.03.12-21.45,36","/log/chan/archive/imudnews-2010.12.20-20.45,48","/log/chan/archive/i2news-2009.03.26-05.11,20","/doc/build/Weapons","/domains/fort/room/gstreet7.c","/domains/fort/obj/pwatch.c","/domains/fort/armor/silverring.c","/domains/amigara/amigara/room/passage5.c","/log/chan/archive/muds-2009.05.15-13.59,29","/log/chan/archive/muds-2010.12.09-15.45,48","/domains/town/meals/yellow_spice.c","/log/chan/archive/intergossip-2009.04.14-17.29,16","/domains/campus/txt/ai/charly/bak/red_wins","/log/chan/archive/muds-2013.08.05-09.13,15","/lib/std/base_dummy.c","/daemon/tmp/nmsh.c.c","/secure/daemon/update.blank","/secure/cmds/admins/removeguest.c","/domains/campus/room/sewer1.c","/log/chan/archive/muds-2009.03.14-14.46,19","/log/chan/archive/muds-2010.10.12-15.45,48","/domains/default/npc/goblin.c","/doc/applies/master/valid_compile_to_c","/save/kills/l/lnhiem","/domains/Praxis/adm/access.c","/domains/campus/room/blue_room.c","/secure/daemon/localpost.h","/domains/fort/room/gstreet1.c","/verbs/players/include/evade.h","/doc/lfun/lib/body/AddLimb","/doc/efun/arrays/member_array","/secure/daemon/localpost.c","/lib/include/teller.h","/secure/daemon/i3router/rsocket.c","/lib/rifle.c","/log/chan/archive/dchat-2010.10.22-15.45,48","/secure/cfg/mudos.1111.cfg","/domains/town/room/valley.c","/www/errors/badcmd.html","/log/new_players","/doc/efun/all/trace","/log/archive/reset-2010.12.09-19.45,48","/secure/include/rooms.4444.h","/verbs/players/befriend.c","/domains/campus/room/stairwell2b.c","/doc/efun/all/allocate_mapping","/doc/lfun/lib/interactive/eventMarry","/save/kills/j/jdnjid","/save/kills/d/digmbkami","/doc/lfun/lib/body/SetMelee","/daemon/tmp/stats.c.c","/cmds/players/deviate.c","/log/chan/archive/muds-2010.11.09-12.45,48","/save/soul.3333.o","/save/kills/a/anafcc","/doc/efun/all/member_array","/secure/tmp/cratylus_CMD_EVAL_TMP_FILE.c","/log/archive/reset-2010.10.12-19.45,48","/domains/Praxis/inn104.c","/doc/lfun/lib/bot/GetLong","/doc/efun/floats/to_int","/log/archive/reset-2009.05.24-22.22,24","/domains/campus/txt/finger.txt","/secure/sefun/english.c","/domains/town/room/void.c","/log/chan/archive/i2news-2009.05.13-20.59,29","/domains/campus/armor/helmet.c","/domains/cave/meals/beast.c","/doc/efun/all/read_buffer","/cmds/players/position.c","/doc/lfun/all/eventFall","/cmds/creators/margins.c","/cmds/players/lines.c","/domains/fort/obj/pipe.c","/log/chan/archive/dchat-2010.07.13-13.16,17","/domains/town/room/healer.c","/domains/campus/room/weaplab.c","/secure/sefun/strings.c","/secure/cmds/creators/showfuns.c","/obj/trainer.c","/domains/Ylsrim/virtual/desert_map.c","/log/chan/archive/dchat-2010.10.14-15.45,48","/doc/lfun/all/RemoveMagicProtection","/log/chan/archive/dchat-2010.08.19-10.45,48","/doc/efun/all/set_privs","/verbs/items/weigh.c","/secure/sefun/light.c","/daemon/statistics.c","/secure/cmds/players/suicide.c","/www/cgi/who.c","/log/chan/archive/muds-2010.10.19-09.45,48","/verbs/players/vote.c","/save/stargate.o","/doc/efun/all/upper_case","/www/articles/old/tacitus.html","/log/chan/archive/muds-2010.10.18-02.45,48","/save/kills/c/cggldamfgcn","/lib/.bboard.c.swp","/domains/campus/room/classroom1.c","/log/errors/verbs","/log/chan/archive/muds-2010.08.18-17.45,20","/domains/fort/room/quartermaster2.c","/log/chan/archive/mudnews-2013.08.10-14.13,15","/lib/events/show.c","/doc/lfun/lib/body/RestoreLimb","/doc/efun/all/mapp","/doc/lfun/all/chat_command","/doc/old/README","/save/kills/e/ekabfo","/daemon/tmp/chat.c","/daemon/command.c","/domains/town/virtual/void.c","/doc/lfun/all/GetBonusDuration","/domains/fort/room/west_wall_3.c","/domains/fort/armor/magical_platemail.c","/secure/sefun/reaper.c","/save/kills/c/cilfjce","/log/chan/archive/muds-2010.10.05-08.45,48","/domains/town/obj/gcoinbag.c","/doc/sefun/query_custom_path","/save/types.o","/daemon/include/party.h","/news/moved","/secure/sefun/minimap.c","/domains/amigara/room/osecret.c","/doc/help/players/unalias","/daemon/tmp/A_LONG_GLOVE.c","/domains/town/virtual/sky/19,6,1.c","/domains/fort/obj/flu.c","/www/cgi/logout.c","/cmds/players/pk.c","/lib/include/container.h","/doc/sefun/flat_map","/log/chan/archive/muds-2010.08.25-23.45,48","/save/kills/e/egjjk","/doc/sefun/translate","/save/kills/x/xkcdeiieoln","/log/chan/archive/intergossip-2013.08.12-01.13,15","/doc/lfun/lib/follow/SetLeader","/domains/fort/room/common20.c","/log/chan/archive/muds-2010.09.25-12.45,48","/domains/learning/adm/analytics.c","/domains/fort/obj/clip.c","/doc/applies/interactive/net_dead","/secure/sefun/time.c","/domains/campus/meals/salad.c","/doc/lfun/lib/donate/GetLong","/log/chan/archive/inews-2009.03.26-18.11,20","/log/chan/archive/dchat-2014.09.20-15.08,45","/domains/campus/txt/ai/charly/fgreen","/save/banish.1111.o","/domains/town/room/mansion_dhall3.c","/log/chan/archive/muds-2010.12.11-13.45,48","/secure/cfg/mudos.autobak.6666","/daemon/tmp/cave1.c","/doc/sefun/load_object","/secure/daemon/preload_check.c","/obj/stargate.c","/lib/interface.c","/domains/town/meals/mana_tonic.c","/doc/lfun/lib/creator/GetLong","/log/chan/archive/muds-2010.08.20-15.45,48","/lib/events/shoot.c","/domains/campus/meals/bourbon.c","/log/chan/archive/muds-2010.09.11-11.45,48","/doc/efun/all/receive","/log/chan/archive/muds-2009.03.26-20.17,31","/doc/efun/filesystem/read_bytes","/www/lpmuds/index.html","/save/kills/x/xkcdmklmeji","/secure/sefun/get_verbs.c","/save/deviation.3333.o","/secure/npc/arch_wraith.c","/domains/campus/room/wiz_lab.c","/doc/help/players/deviation","/verbs/items/fill.c","/secure/scripts/oldcrat2.src","/log/chan/archive/sport-2013.07.27-12.13,15","/domains/campus/armor/shirt.c","/domains/amigara/amigara/room/passage26.c","/daemon/tmp/wall.c","/lib/events/give.c","/doc/lfun/lib/body/GetFingers","/domains/town/obj/slip_heal.c","/log/chan/archive/muds-2010.08.26-16.45,48","/secure/obj/key.c","/domains/default/npc/quarantine/graham.c","/domains/fort/room/courtyard.c","/log/chan/archive/intergossip-2010.10.21-07.45,48","/secure/cfg/races/dog","/doc/applies/valid_write","/log/law/sites-tempban/foo.txt","/doc/lfun/lib/body/eventDie","/domains/fort/room/tunnel8.c","/domains/amigara/amigara/room/passage20.c","/domains/town/obj/ebutton1.c","/save/kills/m/mbboiig","/doc/efun/parsing/index","/log/chan/archive/muds-2013.08.19-09.13,15","/powers/spells/light.c","/domains/fort/weap/rod.c","/verbs/admins/include/adverb.h","/doc/efun/all/regexp","/log/chan/archive/sport-2009.05.11-17.59,29","/log/chan/archive/muds-2010.09.04-18.45,48","/domains/fort/room/parapet.c","/secure/cfg/races/giant","/www/errors/notfound.html","/log/chan/archive/muds-2010.09.12-04.45,48","/save/kills/h/hldchhbhgnf","/log/chan/archive/muds-2010.10.26-15.45,48","/domains/cave/obj/cask2.c","/domains/Praxis/orc_valley/passage2.c","/doc/lfun/lib/round/SetMillimeter","/daemon/terminal.c","/domains/fort/room/tunnel2.c","/domains/campus/npc/charles.c","/save/mudinfo.6666.o","/doc/efun/internals/time_expression","/log/chan/archive/muds-2013.08.05-08.13,15","/domains/fort/room/tanner.c","/www/articles/copyright.old","/save/classes.8888.o","/log/chan/archive/muds-2013.08.04-01.13,15","/lib/sentient.c","/doc/lfun/lib/clan/SetLeader","/log/chan/archive/muds-2010.12.26-13.46,48","/save/kills/x/xkcdaejohijb","/log/chan/archive/imudnews-2009.03.24-09.11,20","/domains/fort/weap/wulkan_hammer.c","/domains/default/npc/bacchus.c","/domains/campus/room/science3.c","/domains/Ylsrim/room/kaliid4.c","/doc/lfun/lib/firearm/GetMillimeter","/log/chan/archive/muds-2010.10.20-00.45,48","/verbs/creators/.resurrect.c.swp","/save/kills/l/lbidab","/log/chan/archive/muds-2010.09.09-12.45,48","/domains/town/weap/sharpsword.c","/log/chan/archive/muds-2010.11.03-10.45,48","/doc/lfun/lib/worn_storage/SetFingers","/log/chan/archive/muds-2009.10.06-15.42,34","/doc/lfun/lib/genetics/GetResistance","/doc/efun/sockets/socket_create","/news/avatar","/domains/default/room/telnet_room.c","/secure/cfg/classes/thief","/daemon/tmp/ROOM_START.c","/log/archive/catch-2010.07.14-11.16,17","/log/game_log","/cmds/players/commandecho.c","/domains/Praxis/mountains/chamber3.c","/save/kills/i/ioidcbbelgdkie","/save/kills/x/xkcdcmndcfo","/log/chan/pchat","/domains/fort/room/common17.c","/domains/examples/room/exroom3.c","/domains/default/vehicles/strider.c","/doc/lfun/lib/weapon/GetWielded","/doc/efun/all/query_verb","/domains/campus/txt/ai/charles/bak2/switches","/domains/Praxis/branches.c","/domains/town/room/voters.c","/save/kills/c/cohgmojho","/log/chan/archive/muds-2009.03.13-13.45,36","/domains/town/obj/stargate.c","/doc/efun/all/write_bytes","/save/kills/m/mbmck","/doc/efun/all/get_dir","/log/chan/archive/muds-2010.11.09-11.45,48","/log/chan/archive/intergossip-2010.10.18-01.45,48","/domains/fort/room/bwall6.c","/doc/lfun/lib/body/GetMissingLimbs","/log/chan/archive/muds-2013.08.25-22.13,15","/domains/town/room/vill_road3.c","/domains/Ylsrim/room/adv_hall.c","/doc/applies/valid_read","/daemon/tmp/valley.c","/log/chan/archive/muds-2010.12.09-00.45,48","/domains/fort/room/common11.c","/doc/lpc/constructs/function","/log/chan/archive/muds-2010.08.19-09.45,48","/log/chan/archive/dchat-2010.09.05-11.45,48","/domains/Ylsrim/armor/leather_armor.c","/domains/cave/room/common4.c","/secure/include/parse_com.h","/secure/cmds/builders/areagoto.c","/domains/campus/obj/greenbox.c","/domains/Praxis/e_boc_la1.c","/log/chan/archive/dchat-2010.11.19-11.45,48","/domains/fort/armor/workboot_r.c","/doc/lfun/lib/classes/GetMorality","/doc/efun/all/set_malloc_mask","/secure/daemon/flash_policy.c","/log/chan/archive/inews-2013.07.25-13.13,01","/domains/default/room/wiz_corr_east.c","/log/chan/archive/muds-2009.04.26-14.05,53","/secure/cmds/admins/mudconfig.c","/domains/town/obj/pack.c","/doc/lfun/lib/bonus/SetSkills","/open/foo.c","/domains/campus/txt/ai/charles/bak2/bak1/fblue","/log/chan/archive/intergossip-2010.08.05-13.18,42","/doc/efun/all/socket_close","/doc/efun/all/replaceable","/domains/fort/room/carpenter.c","/domains/fort/room/bpath4.c","/secure/sefun/native_version.c","/domains/fort/room/common9.c","/domains/cave/armor/pajamas.c","/save/kills/a/akodijgka","/domains/campus/obj/trashcan.c","/daemon/tmp/party.c","/domains/town/room/school.c","/domains/fort/obj/rock.c","/save/kills/n/nm","/cfg/where.cfg","/domains/fort/armor/workboot_l.c","/log/chan/archive/dgd-2009.03.15-13.30,39","/daemon/tmp/R_AIR.c","/domains/town/npc/dirk.c","/cmds/players/users.c","/domains/Praxis/cemetery/grave_yard.c","/cmds/creators/.astar.c.swp","/domains/amigara/amigara/room/passage17.c","/doc/applies/retrieve_ed_setup","/daemon/tmp/LIB_PILE.c","/domains/default/weap/orcslayer.c","/log/chan/archive/muds-2013.08.26-15.13,15","/obj/worn_storage.c","/domains/default/npc/gargoyle.c","/log/chan/archive/muds-2013.08.17-22.13,15","/lib/events/fly.c","/doc/lfun/lib/burn/GetBurning","/daemon/defines.c","/secure/include/rooms.5555.h","/domains/fort/room/common3.c","/domains/cave/room/weapon_storage1.c","/domains/campus/obj/rayovac.c","/verbs/items/get.c","/doc/lfun/lib/damage/GetClass","/secure/daemon/.autoexec.c.swp","/save/soul.4444.o","/std/monster.c","/doc/lfun/all/eventExtinguish","/secure/sefun/absolute_path.c","/domains/amigara/amigara/room/passage11.c","/save/kills/m/mnnkkba","/domains/town/virtual/sky/18,6,1.c","/secure/lib/connect.first.c","/secure/cfg/races/replicant","/daemon/tmp/B_CHIMAERA.c","/log/chan/archive/intergossip-2010.07.20-18.16,17","/domains/town/weap/brush.c","/doc/efun/sockets/socket_release","/log/chan/archive/muds-2009.10.05-15.41,35","/domains/fort/armor/toga.c","/save/kills/x/xkcdefie","/log/chan/archive/muds-2010.11.11-23.45,48","/doc/applies/master/valid_override","/domains/campus/room/shaftb.c","/doc/efun/calls/call_out","/save/kills/e/eoknjc","/log/chan/archive/intergossip-2010.09.17-11.45,48","/domains/campus/room/hazlab.c","/log/chan/archive/muds-2013.07.27-19.13,15","/domains/cave/obj/ecoli.c","/domains/fort/armor/shield.c","/doc/efun/internals/mud_status","/log/chan/archive/muds-2013.08.18-15.13,15","/domains/town/obj/chair.c","/doc/applies/parse_command_adjectiv_id_list","/log/errors/default","/domains/town/obj/map.c","/log/chan/archive/muds-2013.08.26-01.13,15","/log/chan/archive/muds-2013.08.09-22.13,15","/log/chan/archive/muds-2010.08.18-02.45,20","/log/chan/archive/intergossip-2013.08.19-08.13,15","/doc/efun/all/new","/log/chan/archive/dchat-2010.10.01-06.45,48","/log/chan/archive/muds-2010.09.20-03.45,48","/lib/events/swivel.c","/secure/sefun/numbers.c","/save/kills/k/kfcbkl","/save/kills/t/testycre","/secure/cmds/admins/chanremove.c","/domains/town/npc/bugg.c","/domains/cave/room/start.c","/secure/cfg/races/pig","/log/chan/archive/muds-2010.11.25-10.45,48","/domains/fort/obj/maglite.c","/domains/campus/room/freezer.c","/doc/sefun/season","/doc/lfun/lib/poison/GetPoison","/secure/scripts/indent.src","/log/archive/reset-2013.08.11-11.13,15","/domains/Praxis/cache.c","/secure/include/logs.h","/log/chan/archive/dchat-2010.08.30-14.45,48","/secure/obj/meditate_mojo.c","/log/errors/Ylsrim","/save/kills/i/iockei","/cmds/players/prompt.c","/verbs/players/withdraw.c","/save/kills/x/xkcdlmkbmmjam","/domains/amigara/room/passage22.c","/daemon/tmp/jenny.c","/log/chan/archive/muds-2009.10.06-08.41,35","/save/kills/x/xkcdbgflbac","/domains/fort/meals/tuna.c","/www/lpmuds/wireless.css","/doc/lfun/lib/body/eventCompleteHeal","/domains/Praxis/roots.c","/daemon/tmp/MOUTH_MANDIBLED.c","/doc/lfun/all/Spent","/domains/Ylsrim/meal/ale.c","/log/chan/archive/muds-2010.09.26-04.45,48","/domains/Praxis/cemetery/mon/ghost9.c","/cmds/creators/man.c","/log/chan/archive/ichat-2009.05.16-02.59,29","/domains/fort/room/sw_wall.c","/cmds/players/score.c","/log/law/sites-register/foo.txt","/log/chan/archive/muds-2010.12.12-05.45,48","/log/chan/archive/muds-2010.12.03-12.45,48","/domains/fort/obj/wardrobe.c","/domains/town/npc/forest_orc.c","/doc/lpc/types/mappings","/log/chan/archive/muds-2013.07.27-05.13,15","/domains/fort/obj/well_lever.c","/doc/efun/floats/acos","/log/chan/archive/dchat-2010.09.27-11.45,48","/save/banish.2222.o","/domains/town/obj/sign.c","/save/kills/n/njend","/domains/campus/txt/ai/charles/bak2/wins","/domains/Praxis/cemetery/mon/ghost3.c","/log/chan/archive/muds-2010.10.17-21.45,48","/doc/old/CHANGES","/log/chan/archive/muds-2010.11.18-17.45,48","/doc/lfun/lib/body/GetSleeping","/doc/lfun/lib/body/GetMaxStaminaPoints","/doc/lfun/lib/shell/SetMillimeter","/log/chan/archive/muds-2009.04.24-23.15,09","/secure/cfg/races/deer","/secure/obj/staff.c","/daemon/tmp/cannon.c","/log/chan/archive/muds-2013.08.05-07.13,15","/domains/town/armor/collar.c","/save/kills/d/dconlahohja","/domains/fort/obj/abox.c","/log/errors/foo.txt","/log/chan/archive/muds-2011.01.06-19.46,13","/log/chan/archive/muds-2010.10.21-06.45,48","/log/chan/archive/muds-2009.03.14-12.46,19","/doc/efun/interactive/query_ip_name","/domains/town/npc/mayor.c","/domains/campus/room/death.c","/doc/lfun/lib/chapel/eventMarry","/doc/efun/all/load_object","/doc/applies/interactive/receive_snoop","/log/chan/archive/muds-2010.11.12-02.45,48","/save/kills/x/xkcdfjnkhanon","/log/chan/archive/muds-2010.12.04-05.45,48","/log/chan/archive/muds-2009.03.10-18.02,51","/log/chan/archive/muds-2009.04.29-01.47,39","/save/kills/c/chidicooblo","/domains/town/obj/cavetroll_key.c","/domains/Ylsrim/npc/shiela.c","/daemon/tmp/osiris.c","/cmds/players/date.c","/domains/town/armor/rocketpack.c","/doc/efun/system/localtime","/secure/sefun/to_object.c","/domains/alpha/room/freezer.c","/doc/efun/interactive/enable_commands","/daemon/notify.c","/domains/default/npc/kender_quiet.c","/secure/cmds/players/bug.c","/secure/cmds/creators/about.c","/doc/lfun/lib/flashlight/eventLight","/doc/efun/strings/replace_string","/doc/applies/save_ed_setup","/log/chan/archive/muds-2010.11.09-10.45,48","/domains/fort/obj/cloak_hood.c","/doc/lfun/all/GetMillimeter","/domains/campus/txt/jenny/6.txt","/log/archive/reset-2009.05.24-20.22,24","/doc/lfun/all/eventUnjoin","/domains/cave/obj/bbucket.c","/cmds/creators/defines.c","/log/chan/archive/intergossip-2009.04.25-23.44,17","/doc/efun/system/find_call_out","/doc/efun/objects/heart_beat_info","/domains/campus/armor/glove.c","/doc/lfun/lib/fish/GetFood","/domains/campus/room/blue_room3.c","/log/archive/runtime.boot-2009.03.28-15.12,22","/domains/fort/room/sunroom.c","/secure/obj/include/post.h","/domains/cave/armor/necklace.c","/doc/help/classes/explorer","/save/kills/n/nammek","/log/chan/archive/muds-2013.08.20-13.13,15","/doc/efun/calls/call_other","/log/chan/archive/ichat-2009.03.27-23.17,31","/domains/amigara/room/passage19.c","/doc/sefun/consolidate","/domains/cave/obj/tall_lamp.c","/domains/town/doors/down.c","/domains/campus/txt/ai/charly/runs","/www/lpmuds/intermud_files/print.css","/save/kills/x/xkcdnbnjnck","/doc/lfun/all/AddHeartModifier","/doc/efun/all/tan","/log/chan/archive/dchat-2010.10.05-20.45,48","/domains/fort/weap/nco_sword.c","/secure/cmds/admins/removeadverb.c","/doc/sefun/remove_sky_event","/save/map.6666.o","/log/chan/archive/imudnews-2009.05.11-23.59,29","/domains/cave/room/cavepass12.c","/secure/cmds/admins/unlink.c","/domains/Praxis/quests/zemoch.c","/domains/alpha/room/wiz_hall.c","/doc/lfun/lib/bonus/SetPoints","/secure/cfg/races/slug","/doc/sefun/last","/domains/cave/weap/sword.c","/domains/amigara/room/passage13.c","/www/articles/olc.html","/domains/campus/doors/blue_door.c","/daemon/guard.c","/www/cgi/showlog.c","/domains/default/armor/jade_ring.c","/domains/learning/room/freezer.c","/lib/std/germ.c","/domains/campus/room/store.c","/domains/fort/room/f_road34.c","/domains/campus/room/shaft2.c","/cmds/creators/anglicize.c","/log/chan/sport","/doc/efun/mixed/mapp","/www/verbs.html","/log/chan/archive/intergossip-2009.03.15-13.30,39","/log/archive/runtime-2014.10.30-09.58,09","/domains/Praxis/ombud_hall.c","/domains/cave/npc/orc_guard4.c","/domains/fort/obj/gcoinbag.c","/save/kills/c/cmddfg","/std/quest_ob.c","/log/archive/runtime-2009.05.22-17.21,24","/save/kills/x/xkcdeleakbk","/log/chan/archive/ichat-2009.03.26-20.11,20","/secure/cfg/races/vehicle","/log/archive/reset-2009.03.27-06.11,20","/lib/events/smoke.c","/domains/fort/armor/platemail.c","/save/kills/x/xkcdeihfak","/domains/fort/room/ghall.c","/log/archive/runtime.boot-2009.04.24-22.15,09","/domains/default/obj/9mmround.c","/doc/lfun/lib/chapel/CanMarry","/verbs/items/empty.c","/log/chan/archive/muds-2010.12.20-04.45,48","/domains/campus/obj/medtool.c","/secure/sefun/.astar.c.swp","/lib/std/boobytrap_shadow.c","/domains/fort/obj/stargate2.c","/secure/cfg/races/amphibian","/domains/fort/obj/pole.c","/log/chan/archive/muds-2013.07.27-18.13,15","/log/chan/archive/muds-2009.05.18-13.00,12","/cmds/admins/fdinfo.c","/domains/town/room/church.c","/secure/cfg/ip_unrestrict.cfg","/log/chan/archive/intergossip-2010.12.03-11.45,48","/domains/fort/obj/9mmclip.c","/domains/town/virtual/bottom.c","/doc/efun/all/random","/log/chan/archive/muds-2009.03.28-15.12,22","/domains/town/obj/clocktower.c","/domains/campus/txt/ai/charles/bak2/red_wins","/secure/scripts/qcs_check.txt","/domains/fort/obj/bench.c","/secure/cmds/admins/register.c","/log/chan/archive/intergossip-2009.03.21-17.16,52","/verbs/items/use.c","/domains/campus/doors/prob_door.c","/log/chan/archive/intergossip-2010.09.04-16.45,48","/domains/default/armor/badge.c","/www/lpmuds/intermud_files/script.js","/verbs/items/include/bury.h","/obj/include/portal.h","/secure/lib/bboard.c","/log/chan/archive/muds-2010.11.17-23.45,48","/domains/town/obj/9mmclip_empty.c","/lib/include/creator.h","/domains/fort/room/f_road7.c","/domains/Praxis/rogue_hall.c","/log/chan/archive/intergossip-2010.11.09-23.45,48","/save/kills/n/nhbjoghhjh","/domains/town/obj/stargate3.c","/log/chan/archive/dchat-2010.09.13-23.45,48","/doc/lfun/lib/spell/GetMorality","/doc/efun/all/explode","/save/soul.5555.o","/domains/Praxis/obj/misc/handcuffs.c","/doc/efun/all/set_bit","/log/chan/archive/muds-2009.10.05-00.41,35","/log/chan/archive/intergossip-2010.07.30-15.18,42","/lib/match.c","/log/chan/archive/muds-2010.09.17-10.45,48","/www/lpmuds/downloads.html","/log/chan/dutch","/doc/SUPPORT","/domains/fort/room/f_road1.c","/domains/fort/npc/forest_orc2.c","/domains/default/obj/bbucket.c","/domains/town/npc/orc2.c","/log/chan/archive/muds-2009.05.19-06.00,12","/secure/daemon/i3router/debug.h","/domains/town/obj/.rack.c.swp","/domains/fort/obj/ebutton1.c","/doc/efun/strings/explode","/include/build_types.h","/doc/efun/strings/set_bit","/doc/build/Vendors","/secure/sefun/fuzzymatch.c","/daemon/tmp/pub.c","/lib/cgi.c","/domains/fort/armor/apron.c","/domains/Ylsrim/npc/priest.c","/save/kills/n/nifle","/domains/town/weap/orcslayer.c","/verbs/common/shout.c","/log/chan/archive/muds-2010.11.09-23.45,48","/log/chan/archive/intergossip-2009.03.27-15.11,20","/domains/campus/room/tunnel2.c","/domains/Praxis/obj/misc/vial.c","/doc/help/creators/addemote_help","/lib/nmsh.c","/doc/lfun/lib/classes/SetMorality","/log/archive/reset-2009.10.05-04.41,35","/www/reference.jpg","/domains/fort/armor/leather_boot_r.c","/domains/Praxis/mage_join.c","/domains/default/npc/klingon.c","/www/lpmuds/xml_board.js","/verbs/items/extinguish.c","/secure/npc/drone.c","/doc/lfun/lib/body/SetFingers","/log/chan/archive/muds-2009.03.14-11.46,19","/lib/std/item.c","/doc/help/players/languages","/log/chan/archive/muds-2010.11.13-08.45,48","/daemon/tmp/seven.c","/domains/default/npc/drone.c","/doc/help/classes/fighter","/domains/campus/room/access9.c","/save/kills/j/jjnmcgkmhi","/domains/fort/armor/leather_boot_l.c","/domains/Ylsrim/room/armory_storage.c","/save/kills/c/cjhh","/obj/portal.c","/doc/efun/all/read_bytes","/doc/efun/all/memory_summary","/domains/campus/meals/burger.c","/secure/daemon/players.c","/doc/efun/filesystem/mkdir","/domains/fort/room/f_road25.c","/log/chan/archive/muds-2010.10.27-06.45,48","/log/chan/jengatest","/log/chan/archive/intergossip-2010.12.20-17.45,48","/verbs/items/touch.c","/secure/cfg/races/half-orc","/log/chan/wileymud","/domains/town/obj/trash.c","/domains/town/obj/.scroll_raise_dead.c.swp","/domains/campus/room/access3.c","/log/chan/archive/muds-2009.03.31-09.51,27","/domains/fort/obj/stargate.c","/daemon/books.c","/doc/lfun/lib/meal/eventDestruct","/verbs/items/steal.c","/domains/campus/adm/pod.c","/save/banish.3333.o","/log/chan/archive/muds-2009.03.30-02.51,27","/lib/combatmsg.c","/save/kills/j/jojj","/doc/applies/master/crash","/domains/fort/obj/box.c","/domains/campus/obj/.ped_button.c.swp","/lib/burn.c","/www/articles/tms.html","/log/chan/archive/imudnews-2010.10.07-05.45,48","/secure/lib/net/web_client.c","/domains/fort/room/north_wall_1.c","/doc/sefun/destruct","/verbs/builders/copy.c","/log/chan/archive/muds-2009.04.25-14.32,37","/log/chan/archive/muds-2013.08.21-19.13,15","/log/archive/i3error-2009.05.13-16.59,29","/log/suicides/two","/log/chan/archive/muds-2010.11.04-01.45,48","/log/chan/archive/muds-2009.04.26-12.05,53","/lib/round.c","/domains/fort/room/tanner2.c","/domains/fort/obj/church_wall.c","/doc/efun/interactive/query_snoop","/domains/amigara/room/ocommchamb.c","/log/chan/archive/inews-2009.03.20-17.16,52","/domains/campus/room/plab.c","/domains/default/armor/rocketpack.c","/cmds/creators/include/showtree.h","/log/chan/archive/intergossip-2010.09.17-23.45,48","/domains/fort/obj/leaflet.c","/save/kills/l/lkhflcaenh","/tmp/opc.efun","/log/chan/archive/intergossip-2010.11.11-21.45,48","/doc/help/creators/creation","/domains/campus/room/alcove1.c","/doc/applies/master/parse_command_prepos_list","/obj/shield.c","/log/chan/archive/intergossip-2009.04.28-20.47,39","/secure/cmds/creators/.ed.c.swp","/domains/campus/doors/testdoor.c","/secure/cfg/races/demon","/domains/learning/virtual/server.c","/domains/Praxis/wild2.c","/domains/Praxis/sewer.c","/cmds/players/biography.c","/secure/sefun/local_time.c","/secure/cfg/races/klingon","/save/kills/g/gabnoc","/domains/town/room/road0.c","/save/kills/m/mfffeanhac","/doc/lfun/all/GetMaxStaminaPoints","/doc/lfun/all/GetMagicPoints","/doc/efun/strings/pluralize","/doc/efun/buffers/write_buffer","/include/size_types.h","/doc/sefun/architecture","/doc/applies/flag","/daemon/tmp/A_EXO.c","/domains/fort/room/tailor2.c","/doc/efun/all/restore_variable","/domains/amigara/room/furnace.c","/domains/fort/obj/ladder.c","/shadows/breather.c","/domains/Praxis/west_road1.c","/doc/efun/all/evaluate","/domains/fort/room/south_wall_1.c","/domains/cave/obj/torch.c","/domains/Ylsrim/etc/church_door.c","/secure/daemon/.rooms.c.swp","/log/errors/secure","/lib/props/carry.c","/doc/lfun/lib/body/GetMagicPoints","/save/kills/o/otto","/log/chan/*dalet:test","/domains/campus/armor/shield.c","/doc/lfun/lib/body/SetSleeping","/lib/domesticate.c","/doc/lfun/lib/body/AddFood","/domains/town/obj/charity.c","/domains/Ylsrim/room/s_bazaar.c","/verbs/items/put.c","/secure/cfg/races/isopod","/doc/efun/all/query_ip_number","/lib/events/swim.c","/doc/efun/all/move_object","/log/chan/archive/muds-2009.03.16-19.30,39","/log/chan/archive/intergossip-2009.05.07-18.13,35","/lib/pager.c","/doc/lfun/lib/round/GetAmmoType","/domains/fort/doors/arena_door.c","/doc/efun/all/geteuid","/domains/campus/txt/hi.txt","/log/chan/archive/muds-2009.03.15-12.30,39","/log/chan/archive/intergossip-2010.10.27-19.45,48","/doc/sefun/year","/doc/sefun/ordinal","/domains/campus/txt/ai/charles/fblue","/doc/lfun/all/GetDrink","/doc/efun/mixed/pointerp","/doc/lfun/lib/position/eventFall","/save/kills/b/binbnli","/lib/lvs/level.c","/log/chan/archive/intergossip-2010.10.26-12.45,48","/save/kills/x/xkcdcbej","/domains/Ylsrim/etc/pole.c","/daemon/tmp/church.c","/secure/sefun/findobs.c","/domains/fort/doors/tower_door1.c","/log/chan/archive/intergossip-2009.03.26-21.11,20","/lib/props/value.c","/domains/cave/armor/chainmail.c","/log/chan/archive/muds-2010.12.17-11.45,48","/log/chan/archive/muds-2013.08.05-19.13,15","/log/chan/archive/dchat-2013.08.19-20.13,15","/lib/include/editor.h","/secure/daemon/.chat.c.swp","/lib/props/cost.txt","/include/boobytraps.h","/domains/campus/npc/rat.c","/domains/fort/room/f_road16.c","/domains/fort/armor/wizard_hat.c","/secure/cfg/races/kobold","/secure/cmds/creators/.wget.c.swp","/domains/Praxis/w_boc_la1.c","/cmds/players/xyzzy.c","/log/chan/archive/muds-2010.09.09-23.45,48","/save/kills/h/hahddlf","/doc/lfun/lib/follow/GetLeader","/verbs/items/include/close.h","/domains/campus/weap/9mmpistol.c","/doc/efun/system/program_info","/www/articles/old/lpu.html","/doc/sefun/reap_dummies","/log/chan/archive/muds-2009.04.15-11.19,33","/doc/lfun/all/SetSkills","/doc/efun/interactive/query_ed_mode","/doc/sefun/possessive_noun","/secure/daemon/i3router/process_channel.h","/domains/default/npc/bird.c","/doc/lfun/lib/bonus/SetStats","/save/kills/b/bdin","/doc/hbook/chapter09","/verbs/items/rock.c","/secure/obj/floodmapper.c","/doc/lpc/basic/Introduction","/doc/hbook/chapter08","/domains/fort/room/f_road10.c","/domains/Praxis/n_centre2.c","/doc/lpc/types/general","/doc/hbook/chapter07","/doc/efun/objects/load_object","/secure/cfg/races/primate","/log/chan/archive/intergossip-2010.07.18-17.16,17","/doc/hbook/chapter06","/doc/hbook/chapter05","/doc/hbook/chapter04","/domains/town/armor/overcoat.c","/doc/hbook/chapter03","/doc/hbook/chapter02","/secure/cmds/creators/include/create.h","/doc/hbook/chapter01","/secure/cmds/admins/pause.c","/domains/town/armor/.vest.c.swp","/domains/default/obj/box.c","/news/creator","/log/chan/archive/muds-2010.11.09-22.45,48","/log/chan/archive/dchat-2010.08.23-19.45,48","/doc/lfun/lib/daemon/eventDestruct","/doc/lfun/all/AddSkillPoints","/lib/events/wield.c","/log/chan/archive/intergossip-2009.03.31-08.51,27","/secure/cmds/admins/sconv.c","/domains/campus/room/lounge.c","/domains/town/room/wtunnel3.c","/cmds/players/inventory.c","/secure/cfg/races/human","/log/router/foo.txt","/log/chan/archive/muds-2010.08.27-06.45,48","/domains/fort/armor/collar.c","/cmds/creators/ascii.c","/save/kills/c/cl","/log/chan/archive/intergossip-2010.10.05-18.45,48","/doc/lfun/lib/clan/eventInitiate","/doc/efun/all/rusage","/doc/lfun/all/ClassMember","/save/kills/c/ci","/daemon/tmp/rain man.c","/www/articles/renaissance.html","/log/dests","/domains/fort/doors/cobbler.c","/save/kills/c/cd","/log/chan/connections","/save/soul.6666.o","/save/kills/x/xkcddjgmig","/domains/fort/armor/beret.c","/cmds/creators/find.c","/domains/learning/room/death.c","/domains/campus/meals/ham_sand.c","/log/chan/archive/muds-2009.03.22-09.16,52","/doc/applies/master/epilog","/doc/lfun/lib/corpse/CanReceive","/secure/cmds/admins/link.c","/save/kills/x/xkcdmcce","/log/chan/archive/muds-2010.10.19-19.45,48","/log/chan/archive/muds-2009.03.21-02.16,52","/domains/default/vehicle/strider.c","/doc/efun/mixed/nullp","/doc/lfun/all/SetBonusDuration","/log/chan/archive/muds-2010.10.18-12.45,48","/save/kills/x/xkcdnkfmkekl","/verbs/players/include/vote.h","/doc/lfun/all/GetCanBite","/doc/efun/all/atan","/save/kills/x/xkcdgiknakc","/secure/sefun/atomize.c","/domains/campus/armor/dress.c","/log/archive/catch-2009.05.24-19.22,24","/doc/efun/all/get_char","/obj/burning_orb.c","/domains/Praxis/east_road3.c","/doc/efun/objects/destruct","/www/lpmuds/sitefaq.html","/domains/learning/room/void.c","/domains/fort/armor/bdu.c","/log/chan/archive/intergossip-2013.08.26-12.13,15","/log/chan/archive/inews-2010.09.26-09.45,48","/doc/help/players/alias","/doc/lfun/all/SetMelee","/doc/efun/interactive/query_snooping","/log/chan/archive/muds-2010.10.13-04.45,48","/log/chan/archive/muds-2009.05.11-08.59,14","/doc/lfun/lib/clan/GetLeader","/lib/include/autosave.h","/doc/sefun/day","/domains/fort/room/east_wall_2.c","/lib/trap.c","/lib/events/climb.c","/include/mouth_types.h","/domains/town/meals/zyqxuwy.c","/verbs/items/capture.c","/lib/poison.c","/domains/default/npc/quarantine/edmund.c","/log/chan/archive/muds-2010.09.25-22.45,48","/doc/lfun/lib/body/AddFingers","/secure/cmds/admins/statconvert.c","/domains/fort/armor/ring.c","/log/chan/archive/dgd-2009.03.16-17.30,39","/save/kills/k/kfagnbfo","/save/kills/j/jcee","/save/kills/x/xkcdkbigha","/log/chan/archive/muds-2009.03.28-07.11,20","/domains/campus/save/charly.o.gz","/daemon/tmp/A_LONG_BOOT.c","/lib/std/story.c","/doc/efun/general/typeof","/cmds/players/save.c","/doc/efun/sockets/socket_accept","/log/chan/archive/muds-2010.09.20-14.45,48","/log/archive/foo.txt","/log/chan/archive/muds-2009.04.25-21.44,17","/doc/lfun/lib/body/DestLimb","/log/chan/archive/intergossip-2010.09.12-14.45,48","/doc/lfun/lib/spell/SetMorality","/secure/obj/include/gossip_folder.h","/domains/town/doors/m4.c","/doc/lfun/all/AddSacrificeType","/save/banish.4444.o","/domains/default/weap/357pistol.c","/doc/lfun/all/AddHealthPoints","/doc/efun/mappings/keys","/doc/sefun/query_snooping","/log/errors/archive/secure-2009.07.12-12.57,22","/domains/town/obj/m_key.c","/save/kills/a/anemaf","/secure/cmds/creators/imc2.c","/domains/campus/room/green_room2.c","/daemon/classes.c","/save/kills/x/xkcdgamdcddmcj","/doc/lfun/lib/bonus/GetSkills","/log/chan/archive/muds-2009.05.10-08.58,26","/domains/amigara/room/passage6.c","/doc/help/creators/force","/save/kills/f/fbdnb","/domains/Praxis/data/booth_votes.o.gz","/log/chan/archive/intergossip-2010.10.21-17.45,48","/verbs/items/apply.c","/lib/std/dummy.c","/log/chan/archive/muds-2010.11.20-13.45,48","/verbs/players/lie.c","/doc/sefun/currency_mass","/log/chan/archive/muds-2010.11.11-20.45,48","/log/chan/archive/dgd-2009.03.21-14.16,52","/cmds/creators/lfuns.c","/log/chan/archive/intergossip-2010.09.26-01.45,48","/www/articles/lpmuds.html","/domains/Praxis/mountains/tunnel2.c","/domains/town/armor/.boot_r.c.swp","/doc/efun/all/command","/log/chan/archive/muds-2013.07.27-16.13,15","/doc/efun/all/set_hide","/verbs/players/request.c","/www/articles/favicon.ico","/log/chan/archive/intergossip-2010.07.27-15.17,46","/domains/town/virtual/surface.c","/log/archive/currency-2011.01.11-08.46,55","/doc/lfun/all/GetReligion","/log/chan/archive/dchat-2010.11.30-13.45,48","/domains/cave/room/cave.c","/save/kills/m/mdgjlmdnd","/save/kills/f/four","/log/archive/i3error.2009.05.17-22.31,52-2009.05.17-22.59,29","/secure/daemon/secrets.c","/verbs/players/teach.c","/log/chan/archive/muds-2010.12.18-17.45,48","/daemon/intermud.c","/domains/fort/obj/candlestick.c","/domains/Praxis/highway1.c","/cfg/days.cfg","/secure/cmds/admins/router.c","/log/chan/archive/broken_gossip-2011.01.04-20.46,13","/include/magic_protection.h","/domains/fort/doors/test_door1.c","/domains/campus/room/stairwell.c","/domains/fort/obj/debris.c","/domains/campus/adm/death.txt","/log/chan/archive/muds-2010.09.27-08.45,48","/log/chan/archive/intergossip-2010.07.20-01.16,17","/log/chan/archive/muds-2010.10.20-10.45,48","/log/chan/archive/muds-2010.09.18-15.45,48","/log/chan/archive/dchat-2010.08.08-17.18,42","/doc/lfun/lib/battery/SetPowerType","/log/chan/archive/muds-2010.11.03-20.45,48","/log/chan/archive/intergossip-2010.10.12-10.45,48","/domains/fort/room/east_wall_south.c","/secure/daemon/i3router/send_startup_reply.h","/domains/town/obj/bag.c","/log/chan/archive/sport-2013.08.06-17.13,15","/doc/efun/calls/call_stack","/log/chan/error","/domains/default/npc/quarantine/rik.c","/domains/town/meals/water.c","/domains/town/meals/red_spice.c","/domains/fort/obj/podium.c","/log/chan/archive/muds-2010.08.21-04.45,48","/domains/alpha/virtual/void.c","/domains/Praxis/rogue_vote.c","/doc/efun/interactive/disable_wizard","/doc/lfun/all/eventDie","/doc/efun/all/snoop","/log/chan/archive/muds-2010.09.12-00.45,48","/doc/efun/objects/index","/log/chan/archive/intergossip-2010.10.19-18.45,48","/secure/cmds/admins/gridconfig.c","/log/chan/archive/dchat-2013.07.29-16.13,15","/save/kills/a/adbkgifiemoooc","/domains/fort/obj/torch.c","/doc/applies/terminal_type","/log/chan/archive/muds-2010.11.09-21.45,48","/doc/lfun/all/SetPoints","/domains/town/room/mansion_room6.c","/doc/lfun/lib/race/GetRace","/save/map.8888.o","/save/kills/t/testybarb","/save/kills/i/iifg","/log/chan/archive/muds-2010.12.18-03.45,48","/log/chan/archive/muds-2010.07.03-15.15,58","/domains/Praxis/cemetery/grave_yard4.c","/doc/efun/mudlib/set_living_name","/log/chan/archive/muds-2009.04.15-10.19,25","/save/kills/e/emojnlfaed","/log/archive/runtime-2009.09.22-18.05,54","/log/chan/archive/muds-2010.09.18-01.45,48","/log/chan/archive/muds-2010.11.04-13.45,48","/domains/Ylsrim/etc/torch.c","/domains/town/obj/.dcell_crappy.c.swp","/secure/cmds/creators/eval.c","/domains/cave/room/cavepass8.c","/doc/lfun/lib/flashlight/CanReceive","/secure/scripts/ruckus.src","/log/chan/archive/sport-2013.08.06-03.13,15","/domains/campus/obj/bench.c","/log/chan/archive/muds-2009.03.15-11.30,11","/log/archive/catch-2009.04.29-15.10,44","/log/chan/archive/muds-2010.09.05-07.45,48","/domains/town/obj/obag.c","/doc/lfun/all/GetWielded","/daemon/tmp/cave.c","/secure/cfg/races/golem","/log/chan/archive/muds-2010.09.04-00.45,48","/log/chan/archive/imudnews-2010.08.02-15.18,42","/verbs/items/lock.c","/domains/fort/obj/slip_regenerate.c","/domains/campus/obj/stargate.c","/save/kills/m/mhcgkjef","/domains/fort/obj/locker.c","/domains/default/npc/quarantine/tom.c","/domains/campus/obj/yellowbox.c","/domains/fort/obj/round2.c","/domains/cave/room/cavepass2.c","/secure/obj/weirder.c","/domains/Praxis/farm.c","/domains/fort/npc/clerk.c","/doc/lfun/lib/vendor/eventBuy","/save/kills/a/ajfo","/domains/learning/virtual/void.c","/log/chan/archive/muds-2009.04.29-22.42,32","/log/chan/archive/intergossip-2010.09.20-13.45,48","/domains/fort/armor/necklace.c","/domains/campus/room/red_room.c","/log/archive/runtime-2010.07.10-09.16,00","/cmds/creators/tellblock.c","/secure/cmds/creators/rss.c","/log/chan/archive/muds-2011.01.06-02.46,13","/log/chan/archive/muds-2010.10.04-10.45,48","/log/chan/archive/intergossip-2010.11.25-20.45,48","/lib/include/close.h","/secure/cfg/races/centaur","/domains/town/virtual/sky/28,6,1.c","/secure/cfg/races/dragon","/lib/detect.c","/domains/amigara/room/pod.c","/daemon/map.c","/domains/town/weap/dagger.c","/save/kills/a/aooiim","/domains/fort/armor/breather.c","/secure/include/rooms.8888.h","/log/chan/archive/inews-2013.08.09-12.13,15","/save/kills/g/gdbiiif","/doc/lfun/all/eventSacrifice","/log/archive/runtime-2014.10.30-19.58,56","/secure/sefun/messaging.c","/obj/vendor.c","/log/chan/archive/sport-2014.09.20-16.08,45","/log/chan/archive/intergossip-2010.11.21-19.45,48","/lib/living.c","/doc/lfun/lib/round/SetAmmoType","/domains/fort/obj/cold.c","/verbs/players/dismount.c","/log/more","/log/chan/archive/muds-2010.10.19-04.45,48","/www/ds-II-faq.html","/lib/comp/seal.c","/doc/efun/all/notify_fail","/save/kills/t/two","/www/lpmuds/print.css","/verbs/items/include/light.h","/lib/vi.c","/lib/events/poison.c","/secure/cfg/races/poleepkwa","/doc/lfun/lib/body/GetProtect","/domains/default/npc/gecko.c","/log/archive/runtime-2009.05.25-22.47,21","/log/chan/mudnews","/log/chan/archive/muds-2010.09.11-20.45,48","/log/chan/archive/intergossip-2010.09.03-20.45,48","/secure/cmds/admins/watch.c","/domains/fort/armor/ring2.c","/save/kills/f/fbdfogff","/domains/town/meals/worm.c","/log/chan/archive/intergossip-2010.11.17-20.45,48","/log/archive/i3error-2009.04.29-16.10,44","/lib/include/files.h","/doc/lfun/lib/flashlight/eventExtinguish","/include/jump.h","/log/chan/archive/muds-2013.08.13-17.13,15","/doc/efun/objects/move_object","/log/chan/archive/muds-2009.03.28-15.17,54","/doc/lfun/all/GetLead","/log/chan/archive/muds-2013.08.21-03.13,15","/log/archive/i3error-2009.05.13-00.59,29","/domains/Praxis/house.c","/save/kills/x/xkcdelkcodhnhc","/log/chan/archive/sport-2009.03.16-23.30,39","/log/chan/archive/muds-2009.04.01-09.51,27","/daemon/tmp/INSTANCES_D.c","/domains/campus/obj/pin.c","/doc/lfun/lib/player/AddHealthPoints","/log/chan/archive/muds-2010.09.26-14.45,48","/doc/lfun/lib/battery/SetDrainRate","/daemon/tmp/shore.c","/domains/town/armor/locket.c","/doc/lfun/lib/npc/GetMaxHealthPoints","/doc/help/creators/mssp","/log/chan/archive/intercre-2009.05.13-00.59,29","/log/chan/archive/dgd-2009.03.16-02.30,39","/domains/cave/armor/boobytrap_ring.c","/doc/lfun/all/teller_check","/doc/sefun/format_string","/domains/fort/obj/labkey.c","/doc/sefun/nominative","/doc/lfun/lib/bonus/GetPoints","/cmds/players/hist.c","/secure/cmds/creators/.rss.c.swp","/domains/Praxis/wall.c","/verbs/common/include/yell.h","/secure/daemon/.icp.c.swp","/verbs/items/include/bait.h","/doc/lfun/lib/body/RemoveExtraChannels","/log/chan/archive/i2news-2009.03.26-13.11,20","/log/archive/runtime-2009.11.08-23.08,14","/domains/default/npc/pegasus.c","/lib/bonus.c","/secure/cmds/creators/gauge.c","/lib/events/describe.c","/log/chan/archive/muds-2010.12.09-23.45,48","/domains/default/room/death.c","/secure/cfg/races/chimera","/domains/town/room/well1.c","/save/kills/s/six","/domains/town/armor/long_boot_r.c","/cmds/creators/format.c","/lib/cylinder.c","/domains/town/obj/bait_can.c","/www/lpmuds/script.js","/save/kills/x/xkcdhdg","/log/chan/archive/muds-2010.08.27-18.45,48","/doc/lfun/lib/chapel/CanSacrifice","/daemon/tmp/HEAT.c","/doc/efun/mudlib/set_light","/save/kills/s/seven","/log/chan/archive/muds-2010.10.21-16.45,48","/log/chan/archive/muds-2010.08.26-11.45,48","/domains/town/npc/james.c","/secure/sefun/get_cmds.c","/secure/include/cfg.h","/domains/default/room/furnace.c","/doc/lfun/lib/damage/SetClass","/doc/efun/all/crc32","/lib/include/meal.h","/log/chan/archive/ds-2009.04.13-19.29,16","/log/chan/archive/muds-2010.11.12-12.45,48","/log/chan/archive/sport-2013.08.15-09.13,15","/domains/fort/weap/std_sword.c","/daemon/tmp/ROOM_FREEZER.c","/domains/default/obj/meter.c","/save/kills/f/ffodiodd","/domains/town/armor/long_boot_l.c","/log/chan/archive/dgd-2009.03.27-11.11,20","/std/pod.c","/log/chan/archive/intergossip-2010.12.04-01.45,48","/save/kills/a/afcdiajkag","/domains/cave/room/chieftain.c","/secure/daemon/.finger.c.swp","/log/chan/archive/dchat-2010.09.28-14.45,48","/secure/sefun/wipe_inv.c","/secure/cfg/races/insect","/doc/guide/chapter09","/doc/guide/chapter08","/doc/efun/objects/all_inventory","/doc/lfun/all/SetPowerType","/doc/guide/chapter07","/log/chan/archive/muds-2009.03.16-03.30,39","/doc/guide/chapter06","/log/chan/archive/muds-2010.10.26-10.45,48","/doc/guide/chapter05","/save/kills/x/xkcdenaaghh","/domains/fort/weap/leostaff.c","/doc/guide/chapter04","/doc/guide/chapter03","/doc/efun/filesystem/write_file","/doc/efun/all/all_inventory","/log/chan/archive/dchat-2013.08.01-16.13,15","/doc/guide/chapter02","/doc/guide/chapter01","/log/chan/archive/muds-2010.11.09-20.45,48","/domains/Praxis/obj/mon/beggar.c","/domains/campus/txt/ai/charly/wins","/doc/efun/all/remove_interactive","/secure/cmds/creators/mudtime.c","/lib/props/body_mass.c","/domains/campus/room/conf2.c","/doc/efun/internals/dumpallobj","/doc/lfun/lib/shell/SetFirearmType","/cmds/creators/message.c","/verbs/items/include/eat.h","/log/archive/runtime-2009.04.29-17.10,44","/domains/campus/armor/collar.c","/daemon/tmp/MOUTH_LIPPED+MOUTH_TOOTHED+MOUTH_TONGUED+MOUTH_TUSKED.c","/save/kills/k/knhhleba","/log/chan/archive/muds-2010.10.22-09.45,48","/domains/town/weap/357pistol.c","/log/chan/archive/muds-2009.03.22-18.11,20","/daemon/tmp/B_SPECTRAL.c","/verbs/items/include/judge.h","/domains/amigara/amigara/room/oleader.c","/doc/applies/master/parse_command_all_word","/log/archive/runtime-2009.09.22-17.05,54","/doc/efun/system/check_memory","/save/bugs.1111.o","/log/chan/*dalet:inews","/domains/fort/room/ptower_top.c","/doc/sefun/absolute_value","/doc/help/creators/foo","/domains/cave/npc/orc_male1.c","/save/kills/g/goie","/doc/efun/all/typeof","/obj/README","/doc/sefun/debug","/log/archive/catch-2009.09.22-15.05,02","/verbs/players/sit.c","/log/chan/archive/muds-2009.04.30-17.45,50","/doc/help/creators/creator_general","/domains/cave/obj/table.c","/domains/fort/npc/praetorian_guard.c","/secure/cfg/mudos.8888.cfg","/log/chan/archive/muds-2009.03.27-12.11,20","/doc/efun/all/shadow","/secure/cfg/races/elephant","/cmds/creators/unanchor.c","/save/banish.o","/log/chan/archive/muds-2009.05.16-00.59,29","/doc/lfun/lib/id/GetName","/lib/events/dig.c","/domains/Ylsrim/room/fighter_hall.c","/log/chan/archive/inews-2013.08.03-10.13,15","/log/chan/archive/intergossip-2010.09.21-19.45,48","/daemon/tmp/S_HUGE.c","/domains/town/obj/canteen.c","/domains/default/npc/kobold.c","/secure/daemon/politics.c","/doc/efun/interactive/query_ip_number","/save/kills/x/xkcdbbg","/log/chan/archive/muds-2010.10.14-09.45,48","/save/kills/l/lecenemnh","/domains/cave/weap/javelin.c","/domains/town/obj/lice.c","/log/archive/runtime-2010.07.10-08.16,00","/secure/cmds/creators/call.c","/domains/town/doors/testdoor2.c","/domains/fort/room/riverbank.c","/domains/fort/obj/test_thing1.c","/verbs/players/include/backstab.h","/secure/cfg/aliases.cfg","/domains/fort/npc/lenny.c","/save/kills/x/xkcdhjcjkdnak","/log/chan/archive/discworld-chat-2010.09.16-12.45,48","/domains/cave/obj/jerkybox.c","/save/kills/j/jiigiadj","/log/chan/archive/sport-2013.07.31-19.13,15","/save/kills/t/testymage","/log/archive/runtime-2014.10.30-18.58,56","/doc/lfun/all/SetReligion","/domains/default/obj/.couch.c.swp","/save/kills/x/xkcdojbobldidf","/domains/cave/room/freezer.c","/save/events.1111.o","/domains/town/weap/.carving_knife.c.swp","/log/chan/archive/muds-2010.12.11-21.45,48","/daemon/tmp/three.c","/daemon/tmp/testybarb.c","/domains/Ylsrim/save/0^0domains0^0Ylsrim0^0room0^0fighter.6666.o","/domains/fort/room/inn.c","/domains/campus/meals/milk.c","/domains/campus/npc/orc.c","/save/kills/e/eeekmgh","/obj/meal.c","/domains/fort/obj/thing.c","/doc/efun/all/bufferp","/doc/lfun/all/SetCanBite","/secure/daemon/oob.c","/doc/lfun/all/eventDestruct","/save/kills/a/ani","/domains/campus/weap/sharpsword.c","/log/decline","/log/chan/archive/intergossip-2010.09.13-19.45,48","/log/chan/archive/intergossip-2009.05.06-22.13,35","/domains/cave/npc/rat.c","/domains/campus/armor/robe.c","/log/chan/archive/muds-2010.10.06-09.45,48","/save/kills/o/osiris","/cmds/creators/i3who.c","/domains/town/armor/boot.c","/log/chan/archive/muds-2013.07.30-06.13,15","/doc/help/players/classes","/domains/campus/txt/huh.txt","/domains/town/obj/rocking_chair.c","/domains/default/npc/moth.c","/secure/cfg/races/faerie","/domains/fort/room/gate.c","/domains/fort/obj/apple.c","/doc/efun/internals/memory_info","/daemon/tmp/MOUTH_BEAKED+MOUTH_TONGUED.c","/save/kills/h/hm","/doc/efun/all/objects","/save/economy.1111.o","/domains/fort/weap/m16rifle.c","/secure/cfg/races/dummy","/save/kills/h/hk","/save/kills/h/hj","/doc/lfun/lib/battery/eventDrain","/doc/efun/system/deep_inherit_list","/doc/efun/all/objectp","/save/kills/h/hg","/save/kills/h/hhgbblcfoc","/save/kills/o/ofncflia","/domains/cave/room/guardroom3.c","/save/kills/h/hd","/log/chan/archive/sport-2013.07.31-05.13,15","/save/kills/h/hb","/log/chan/archive/sport-2013.08.23-08.13,15","/std/furnace.c","/log/chan/archive/muds-2010.12.03-21.45,48","/doc/efun/arrays/sort_array","/doc/efun/all/enable_wizard","/log/chan/archive/dgd-2009.03.13-20.45,36","/domains/default/obj/vial_blue.c","/log/reports/network_error","/domains/campus/armor/bdu.c","/doc/efun/all/query_host_name","/log/chan/archive/intergossip-2010.12.12-00.45,48","/lib/include/digging.h","/domains/default/doors/steel_door2.c","/doc/lpc/concepts/lpc","/secure/cmds/creators/grep.c","/log/chan/archive/muds-2010.09.21-05.45,48","/domains/Praxis/quests/pyr_quest.c","/doc/efun/mappings/map_mapping","/save/soul.8888.o","/doc/lfun/all/SetDrainRate","/domains/Praxis/medium.c","/log/chan/archive/muds-2010.11.27-19.45,48","/doc/efun/all/remove_action","/secure/daemon/instances.c","/lib/battery.c","/domains/amigara/amigara/room/ocommhall.c","/log/chan/archive/intergossip-2010.11.19-19.45,48","/doc/build/ed.hup","/log/chan/archive/sport-2013.08.29-09.13,15","/lib/events/load.c","/doc/applies/init","/doc/lpc/concepts/objects","/doc/efun/all/query_heart_beat","/domains/fort/npc/bigsnake.c","/domains/town/doors/test.c","/domains/fort/weap/9mmpistol_mp.c","/domains/fort/room/gstreet6.c","/domains/campus/txt/jenny/12.txt","/domains/amigara/amigara/room/passage4.c","/doc/efun/interactive/in_input","/cmds/players/languages.c","/domains/town/obj/.dcell_std.c.swp","/verbs/items/buy.c","/log/chan/archive/muds-2010.12.26-21.46,48","/domains/town/obj/hspringwater.c","/doc/lfun/all/AddMagicProtection","/log/chan/archive/muds-2010.10.12-22.45,48","/log/chan/archive/muds-2010.09.18-13.45,48","/domains/fort/obj/scroll_raise_dead.c","/log/chan/archive/muds-2009.05.11-19.59,29","/doc/applies/master/object_name","/domains/default/npc/golem.c","/log/chan/archive/muds-2010.12.13-07.45,48","/doc/sefun/log_file","/lib/events/shake.c","/domains/fort/armor/lvest.c","/doc/efun/all/query_notify_fail","/log/chan/archive/intergossip-2010.11.04-11.45,48","/doc/lfun/lib/npc/eventReconnect","/log/chan/archive/inews-2013.08.26-17.13,15","/doc/lfun/all/eventDrain","/save/kills/d/danhfh","/log/chan/archive/muds-2013.07.28-07.13,15","/lib/include/light.h","/secure/daemon/i3router/process_startup_req.h","/verbs/items/include/balance.h","/domains/campus/meals/gator.c","/log/chan/archive/muds-2010.09.05-19.45,48","/secure/cfg/races/orc","/log/chan/archive/muds-2010.10.27-16.45,48","/log/chan/archive/muds-2010.09.04-12.45,48","/domains/Praxis/inn109.c","/log/chan/archive/muds-2010.10.18-23.45,48","/log/chan/archive/i2news-2009.03.27-05.11,20","/log/chan/archive/muds-2009.03.16-02.30,39","/verbs/items/search.c","/doc/sefun/hiddenp","/domains/default/npc/quarantine/miles.c","/doc/lfun/all/SetClanSkill","/domains/town/obj/cup.c","/domains/amigara/amigara/room/midair.c","/secure/cmds/creators/stupidemote.c","/doc/lfun/all/GetEquippedLimbs","/log/chan/archive/muds-2013.08.06-09.13,15","/domains/campus/room/stairwell2a.c","/log/chan/archive/muds-2013.08.05-02.13,15","/daemon/tmp/rainman.c","/domains/town/obj/chest2.c","/lib/include/exits.h","/domains/campus/txt/jenny/2.txt","/log/chan/archive/ichat-2009.05.18-20.00,12","/log/chan/archive/dchat-2010.11.28-12.45,48","/domains/Praxis/inn103.c","/doc/lfun/lib/classes/SetClan","/doc/efun/all/network_stats","/log/chan/archive/muds-2010.10.21-01.45,48","/lib/events/get_from.c","/doc/efun/all/set_light","/doc/applies/master/valid_read","/doc/sefun/alignment_string","/lib/shop.c","/secure/room/router.c","/doc/efun/all/replace_string","/doc/lfun/all/GetSkills","/save/banish.6666.o","/daemon/tmp/roshd.c","/save/kills/x/xkcdkfdlm","/log/chan/mlp","/doc/efun/mappings/m_indices","/log/archive/runtime-2009.10.28-00.05,38","/domains/default/weap/torpedo.c","/domains/default/obj/generator.c","/doc/efun/mappings/index","/doc/efun/all/environment","/cmds/creators/polyglottize.c","/lib/guard.c","/log/chan/archive/dgd-2009.03.15-21.30,39","/domains/default/obj/module_cloak.c","/doc/lfun/lib/round/eventUnload","/verbs/items/include/search.h","/save/kills/a/ajj","/lib/talk.c","/domains/fort/room/storeroom.c","/save/kills/g/gaghnc","/domains/fort/npc/horse.c","/domains/fort/armor/leather_armor.c","/save/kills/g/gfaoklkdke","/domains/campus/room/sewer.proto.c","/secure/cmds/creators/isql.c","/doc/efun/interactive/message","/doc/lfun/all/RemoveExtraChannels","/domains/town/meals/potion_bigheal.c","/save/kills/n/nmjjann","/log/chan/archive/muds-2010.08.19-03.45,48","/log/chan/archive/muds-2010.10.05-15.45,48","/log/archive/reset-2009.07.15-09.58,36","/log/chan/archive/i2news-2009.05.14-20.59,29","/log/archive/runtime-2010.07.10-07.16,00","/www/articles/old/lpmuds.html","/domains/campus/adm/freezer.c","/doc/lfun/all/eventMoralAct","/log/chan/archive/intergossip-2010.12.17-21.45,48","/domains/fort/room/west_wall_2.c","/lib/genetics.c","/doc/efun/calls/origin","/domains/Praxis/obj/mon/guard.c","/log/chan/archive/dchat-2010.10.15-15.45,48","/doc/applies/valid_hide","/save/bugs.2222.o","/domains/fort/obj/223clip.c","/log/archive/runtime-2014.10.30-17.58,56","/doc/efun/objects/objects","/log/chan/archive/sport-2013.07.30-11.13,15","/domains/default/room/wiz_corr_east3.c","/domains/default/armor/chainmail.c","/domains/campus/obj/torch.c","/save/kills/x/xkcdnddgglmn","/domains/amigara/amigara/room/void.c","/doc/lfun/lib/body/GetLimbClass","/secure/cmds/creators/diff.c","/log/chan/archive/muds-2013.08.27-16.13,15","/domains/town/room/mansion_dhall2.c","/log/chan/archive/muds-2010.08.18-10.45,20","/doc/efun/all/crypt","/domains/cave/obj/omni.c","/secure/cmds/admins/warmboot.c","/doc/phints/.chapter04.swp","/save/kills/c/cjbfkiog","/domains/default/obj/torch.c","/www/versions.html","/domains/fort/obj/table.c","/log/chan/archive/intergossip-2010.11.27-18.45,48","/doc/lfun/lib/shell/GetCaliber","/doc/applies/master/error_handler","/obj/drink.c","/log/chan/archive/muds-2010.10.05-01.45,48","/domains/fort/armor/smock.c","/save/kills/l/llhdgkcejgj","/log/archive/reset-2009.10.04-20.41,35","/domains/default/weap/carving_knife.c","/log/i3error.2009.05.15-19.20,45","/www/print.css","/secure/modules/armor.c","/domains/town/armor/barsmock.c","/domains/default/npc/elemental.c","/log/chan/archive/ichat2-2010.08.13-14.18,42","/domains/amigara/amigara/room/passage25.c","/daemon/meetings.c","/secure/cfg/races/cow","/save/kills/d/ddenc","/log/chan/archive/muds-2010.12.12-13.45,48","/domains/town/save/brandy.o","/doc/applies/process_input","/save/kills/g/gicoh","/doc/help/players/chat","/doc/efun/interactive/this_interactive","/log/chan/archive/muds-2013.08.19-16.13,15","/log/chan/archive/muds-2010.08.21-15.45,48","/log/chan/archive/muds-2013.08.27-02.13,15","/save/events.2222.o","/verbs/items/uninstall.c","/save/kills/g/gcndoclm","/verbs/common/say.c","/obj/book.c","/log/chan/archive/muds-2010.09.12-11.45,48","/domains/fort/room/tunnel7.c","/doc/lfun/lib/body/SetProtect","/domains/fort/room/pod.c","/doc/efun/all/sin","/doc/applies/window_size","/log/chan/archive/sport-2013.07.29-19.13,15","/log/chan/archive/dchat-2010.08.02-13.18,42","/domains/town/obj/painting.c","/doc/lfun/lib/torch/GetLong","/log/chan/archive/muds-2010.11.26-11.45,48","/log/chan/archive/intergossip-2010.10.18-22.45,48","/save/kills/m/mhia","/log/chan/archive/intergossip-2009.03.31-18.51,27","/doc/lfun/all/ModCharge","/domains/fort/npc/limpseur.c","/log/chan/archive/muds-2013.08.14-08.13,15","/domains/town/room/room2.c","/domains/fort/obj/mailbox.c","/domains/cave/obj/cask1.c","/doc/lfun/lib/chapel/GetSacrificeType","/doc/applies/parse_command_all_word","/www/lpmuds/favico.ico","/log/chan/archive/muds-2013.08.13-01.13,15","/lib/include/history.h","/domains/Praxis/orc_valley/passage1.c","/doc/sefun/shutdown","/secure/include/lvs.h","/domains/cave/meals/jerky.c","/cmds/creators/codeblock.c","/save/kills/x/xkcdboicljda","/log/chan/archive/muds-2009.03.14-20.46,19","/domains/fort/room/tunnel1.c","/secure/sefun/values.c","/doc/efun/system/variables","/secure/include/virtual.h","/doc/sefun/first","/save/kills/n/nhjnfneogb","/cmds/players/title.c","/secure/sefun/.users.c.swp","/secure/include/privs.h","/lib/events/scratch.c","/log/chan/archive/intergossip-2010.10.04-21.45,48","/save/economy.2222.o","/log/chan/archive/muds-2010.12.04-13.45,48","/domains/fort/weap/grenade.c","/domains/cave/armor/pants.c","/www/articles.html","/domains/town/weap/.m16rifle.c.swp","/lib/inventory.c","/domains/amigara/amigara/room/kcommon.c","/doc/efun/all/shout","/domains/town/room/forest_well.c","/domains/campus/room/science2.c","/domains/Ylsrim/room/kaliid3.c","/doc/efun/interactive/this_player","/log/chan/archive/muds-2009.05.19-01.00,12","/log/archive/reset-2010.09.03-22.45,48","/domains/fort/obj/gbed.c","/doc/efun/all/catch","/domains/town/obj/.couch.c.swp","/log/chan/archive/muds-2013.08.19-02.13,15","/doc/efun/all/implode","/domains/fort/room/mstreet6.c","/domains/default/npc/boar.c","/domains/Praxis/hall5.c","/doc/sefun/currency_rate","/save/kills/k/klnihj","/doc/applies/get_bb_uid","/log/chan/archive/inews-2009.03.14-00.46,02","/domains/campus/obj/pwatch.c","/domains/Praxis/mountains/chamber2.c","/daemon/services/emoteto.c","/log/chan/archive/muds-2010.11.18-11.45,48","/domains/fort/room/common16.c","/domains/examples/room/exroom2.c","/cmds/admins/broadcast.c","/log/chan/archive/muds-2010.12.19-07.45,48","/powers/spells/meditate.c","/log/chan/archive/muds-2009.04.14-23.29,16","/log/archive/runtime-2009.09.22-16.05,02","/domains/town/room/elevator.c","/cmds/creators/mraces.c","/save/kills/a/adkfalbcjno","/log/chan/archive/muds-2013.08.06-08.13,15","/domains/town/room/mayor.c","/verbs/players/include/attack.h","/secure/cmds/creators/head.c","/secure/cmds/admins/end.c","/log/chan/archive/dchat-2010.11.29-18.45,48","/doc/efun/strings/implode","/cmds/creators/sefuns.c","/domains/fort/room/bwall5.c","/domains/campus/doors/steel_door3.c","/log/chan/archive/muds-2010.08.27-02.45,48","/doc/lfun/lib/race/NewBody","/domains/town/room/vill_road2.c","/secure/cmds/creators/lsed.c","/log/chan/archive/muds-2010.11.05-17.45,48","/domains/town/armor/orc_boot_r.c","/lib/std/lockpick.c","/doc/efun/floats/tan","/domains/cave/doors/food_storage1.c","/domains/fort/room/common10.c","/doc/lfun/all/GetCellType","/log/chan/archive/muds-2010.12.05-06.45,48","/log/chan/archive/muds-2009.03.11-19.02,51","/domains/cave/room/common3.c","/log/chan/archive/inews-2013.07.26-13.13,15","/domains/fort/armor/orc_helmet.c","/log/chan/archive/intergossip-2013.08.21-14.13,15","/daemon/tmp/COLD.c","/www/cgi/connect.c","/domains/cave/armor/.chainmail.c.swp","/domains/Praxis/fighter_hall.c","/log/chan/archive/intergossip-2009.05.10-18.58,26","/secure/include/global.6666","/secure/daemon/i3router/irn.h","/doc/lfun/lib/bonus/SetBonuses","/save/kills/d/dhhekefkio","/doc/lfun/all/GetBodyComposition","/log/archive/runtime-2009.03.28-16.14,40","/domains/town/armor/orc_boot_l.c","/log/chan/archive/muds-2010.10.27-01.45,48","/domains/fort/room/bpath3.c","/domains/fort/room/common8.c","/std/void.c","/log/archive/catch-2011.08.21-09.04,13","/domains/fort/obj/couch.c","/cfg/timezone.cfg","/doc/lfun/all/GetPoints","/log/chan/archive/inews-2009.10.06-09.41,35","/domains/campus/txt/ai/charly/blue_wins","/log/chan/archive/muds-2009.04.29-19.12,38","/domains/amigara/room/midair.c","/domains/amigara/amigara/room/passage16.c","/domains/Ylsrim/room/vote_hall.c","/cmds/players/skills.c","/save/kills/x/xkcdodgjlbgm","/domains/default/npc/tree.c","/domains/fort/armor/newbie_cap.c","/secure/cfg/races/blob","/domains/town/obj/plastic_bag.c","/daemon/tmp/B_CHIROPTEROID.c","/log/archive/runtime-2010.07.10-06.16,00","/domains/fort/room/common2.c","/doc/efun/functions/function_owner","/daemon/tmp/foo.txt","/daemon/tmp/eight.c","/secure/cmds/creators/memcheck.c","/save/kills/x/xkcdgiba","/domains/town/virtual/sky/25,6,1.c","/domains/Ylsrim/meal/shark.c","/log/chan/archive/muds-2009.05.10-18.58,26","/domains/campus/room/crawlspace2.c","/doc/lfun/all/GetBurning","/secure/cfg/races/balrog","/save/kills/c/cmmnochnge","/log/chan/archive/inews-2013.08.18-02.13,15","/doc/help/creators/debug_macro","/cmds/players/quests.c","/domains/amigara/amigara/room/passage10.c","/doc/lfun/lib/round/GetMillimeter","/log/archive/runtime-2014.10.30-16.58,56","/doc/efun/all/write_file","/save/kills/x/xkcdabbbbbl","/log/chan/igossip","/log/chan/archive/muds-2010.12.20-12.45,48","/obj/stargate.example","/domains/campus/obj/diamond.c","/secure/sefun/expand_keys.c","/domains/Praxis/project_room.c","/save/kills/x/xkcdamglcjlll","/log/chan/archive/muds-2010.08.20-21.45,48","/daemon/tmp/sample_three.c","/log/chan/archive/muds-2010.09.21-17.45,48","/doc/efun/interactive/index","/doc/efun/all/ceil","/domains/town/npc/brandy.c","/log/chan/archive/ichat-2009.05.11-15.59,29","/domains/default/armor/pants.c","/save/kills/j/jbfofd","/save/kills/a/agmoemfoa","/domains/fort/doors/sample_door.c","/secure/cmds/creators/longcat.c","/secure/sefun/user_exists.c","/domains/campus/armor/silverring.c","/domains/default/npc/avidryl.c","/domains/amigara/room/passage27.c","/domains/campus/txt/ai/charles/bak2/fblue","/log/chan/archive/sport-2013.08.28-14.13,15","/domains/fort/weap/runic_sword.c","/domains/campus/room/plab2.c","/doc/efun/all/this_object","/verbs/items/install.c","/domains/fort/room/lookout.c","/log/open/currency","/doc/lfun/all/DestLimb","/verbs/rooms/climb.c","/secure/cmds/creators/dbxwhere.c","/daemon/tmp/jennybot.c","/domains/town/virtual/forest/-13,13","/log/chan/archive/muds-2010.10.20-20.45,48","/log/chan/archive/intergossip-2009.05.19-23.06,41","/domains/campus/txt/ai/charles/percent","/doc/lfun/all/GetMaxHealthPoints","/doc/efun/compile/generate_source","/domains/amigara/room/passage21.c","/doc/lfun/all/GetHealthShort","/save/kills/n/nmgeajiek","/doc/efun/sockets/socket_write","/daemon/tmp/S_VERY_SMALL.c","/log/chan/archive/muds-2013.07.28-19.13,15","/log/archive/catch-2009.09.07-19.22,34","/daemon/tmp/fighter.c","/www/errors/denied.html","/domains/Praxis/cemetery/mon/ghost8.c","/domains/fort/obj/medbag.c","/domains/cave/weap/axe.c","/save/bugs.3333.o","/domains/cave/etc/cave_orc.c","/doc/efun/all/mkdir","/domains/default/npc/quarantine/nigel.c","/domains/fort/obj/dcell_good.c","/log/chan/archive/i2news-2009.03.27-17.11,20","/doc/efun/all/resolve","/doc/lfun/lib/bonus/eventDestruct","/log/archive/reset-2009.11.13-22.08,14","/lib/.body.c.swp","/verbs/items/include/wear.h","/save/kills/x/xkcdihbdelnogm","/powers/prayers/healing.c","/doc/lfun/lib/body/GetHealthShort","/doc/efun/system/all_previous_objects","/cmds/creators/ping.c","/.1111.o","/log/archive/reset-2009.10.05-12.41,35","/log/chan/archive/intergossip-2010.07.13-18.16,17","/domains/campus/obj/dcell_std.c","/doc/efun/sockets/socket_connect","/log/chan/beta","/domains/fort/obj/rage.c","/cmds/players/cursefilter.c","/log/chan/archive/intergossip-2010.08.28-08.45,48","/verbs/players/stand.c","/domains/campus/obj/backpack_empty.c","/cmds/players/unmuff.c","/secure/cfg/write.cfg","/cmds/creators/malloc.c","/save/kills/m/mhcd","/log/chan/archive/ds-2009.03.25-10.11,20","/log/chan/archive/muds-2010.12.05-19.45,48","/doc/efun/mudlib/export_uid","/save/kills/e/endlmeb","/domains/campus/obj/thing.c","/include/graphics.h","/lib/std/boobytrap_object.c","/domains/campus/room/crawlspace.c","/doc/lfun/all/GetFingers","/log/chan/archive/muds-2009.04.30-15.45,10","/domains/fort/room/croad.c","/domains/default/obj/case.c","/doc/efun/all/debug_message","/domains/fort/armor/coat.c","/domains/Praxis/obj/misc/stone_pile.c","/doc/efun/mudlib/livings","/save/kills/l/lbhb","/doc/efun/calls/remove_shadow","/save/kills/x/xkcdcihfn","/domains/campus/meals/badapple.c","/log/chan/archive/muds-2010.09.13-03.45,48","/save/kills/x/xkcdchoij","/log/chan/archive/muds-2009.03.27-23.11,20","/domains/default/obj/thing.c","/secure/include/domains.h","/log/chan/archive/sport-2013.07.29-04.13,15","/daemon/include/http.h","/domains/campus/obj/apple.c","/www/lpmuds/links_files/style.css","/save/events.3333.o","/log/chan/archive/muds-2009.04.14-22.29,16","/log/chan/archive/intergossip-2010.07.12-11.16,09","/doc/efun/objects/environment","/log/archive/runtime-2009.09.22-15.05,02","/save/kills/m/mhbf","/log/archive/runtime-2009.04.29-14.10,44","/include/armor_types.h","/lib/include/weapon.h","/powers/spells/buffer.c","/log/chan/archive/muds-2010.08.19-15.45,48","/daemon/tmp/LIB_BODY.c","/log/chan/archive/muds-2010.10.13-13.45,48","/domains/cave/npc/kurogane.c","/save/kills/m/mo","/save/kills/m/ml","/domains/fort/obj/basement_button.c","/doc/efun/all/stringp","/log/chan/archive/muds-2010.11.13-02.45,48","/save/kills/m/mi","/log/archive/runtime-2009.09.22-21.06,15","/save/kills/m/mg","/save/kills/b/bmhekalakjd","/save/kills/m/md","/verbs/common/include/speak.h","/log/chan/archive/inews-2013.08.26-01.13,15","/domains/amigara/room/start.c","/domains/campus/room/blue_room2.c","/secure/obj/.portal_blue.c.swp","/doc/lfun/lib/body/AddHealthPoints","/doc/efun/all/say","/secure/room/network.c","/log/chan/archive/dchat-2009.05.13-17.59,29","/secure/obj/memo.c","/save/economy.3333.o","/doc/efun/strings/upper_case","/daemon/tmp/R_VACUUM.c","/log/chan/archive/muds-2010.09.05-03.45,48","/log/chan/archive/dchat-2010.12.15-05.45,48","/domains/amigara/room/passage18.c","/log/chan/archive/muds-2010.10.19-14.45,48","/save/kills/g/gfaikg","/doc/sefun/cardinal","/log/archive/catch-2011.08.21-08.04,13","/domains/town/npc/lars.c","/domains/town/npc/gecko.c","/doc/lfun/lib/npc/GetName","/secure/cfg/races/sheep","/log/chan/archive/muds-2014.09.21-14.38,03","/doc/lfun/lib/round/SetFirearmType","/doc/efun/interactive/query_host_name","/domains/cave/room/cavepass11.c","/domains/campus/txt/ai/charles/bak2/bak1/green_wins","/secure/cmds/admins/ticktock.c","/log/chan/archive/intergossip-2010.09.30-09.45,48","/cmds/creators/.findobj.c.swp","/save/kills/u/uno","/cmds/players/posting.c","/log/chan/archive/muds-2009.03.23-08.11,20","/lib/daemons/player_stub.c","/domains/amigara/room/passage12.c","/daemon/tmp/201.c","/domains/amigara/room/wiz_hall.c","/save/kills/n/nlcjaonhef","/log/archive/runtime-2010.07.10-05.16,00","/domains/campus/txt/ai/charly/bak/blue_wins","/doc/efun/all/map","/domains/campus/room/bookstore.c","/daemon/tmp/B_INSECTOID.c","/save/kills/x/xkcdchogl","/log/chan/archive/muds-2013.08.30-06.13,15","/log/chan/archive/muds-2010.11.05-02.45,48","/domains/Ylsrim/room/sand_room.c","/log/chan/archive/muds-2013.08.21-13.13,15","/domains/town/virtual/sky/24,6,1.c","/domains/fort/room/f_road33.c","/domains/fort/obj/watch.c","/domains/campus/room/shaft1.c","/domains/campus/npc/hans.c","/secure/include/news.h","/doc/lfun/all/GetHealthPoints","/doc/efun/all/sqrt","/log/chan/archive/dchat-2010.09.02-09.45,48","/lib/stargate.c","/domains/cave/npc/orc_guard3.c","/log/chan/archive/muds-2009.10.05-21.41,35","/daemon/tmp/B_TREE.c","/log/chan/archive/intergossip-2013.08.04-20.13,15","/daemon/tmp/A_BOOT.c","/domains/Praxis/obj/misc/gallows.c","/doc/lfun/all/AddPoison","/cmds/creators/resolve.c","/log/chan/archive/inews-2009.03.27-12.17,31","/log/archive/runtime-2014.10.30-15.58,56","/domains/fort/room/fishmonger.c","/doc/lfun/lib/shell/GetMillimeter","/daemon/services/.tell.c.swp","/log/chan/archive/dgd-2009.03.17-19.30,39","/log/chan/archive/intergossip-2010.11.12-22.45,48","/log/chan/archive/i2news-2009.05.19-07.00,12","/domains/campus/obj/backpack_civilian.c","/domains/fort/weap/poker.c","/doc/efun/numbers/query_num","/domains/fort/npc/zookeeper.c","/save/kills/a/alhokcgjkh","/lib/.interface.c.swp","/secure/include/type.h","/log/chan/archive/muds-2010.09.30-09.45,48","/domains/Praxis/sun2.c","/log/chan/archive/muds-2009.04.15-01.29,16","/log/chan/archive/dchat-2010.10.02-19.45,48","/secure/modules/read.c","/domains/town/txt/quests.txt","/lib/include/lamp.h","/doc/efun/interactive/query_notify_fail","/domains/town/meals/coffee.c","/log/archive/catch-2009.11.11-22.08,14","/log/chan/archive/intergossip-2009.05.08-18.58,26","/domains/default/armor/jeans.c","/domains/town/doors/grate.c","/log/chan/archive/intergossip-2009.03.16-13.30,39","/domains/cave/obj/cot.c","/domains/Praxis/orc_valley/shaman.c","/doc/efun/objects/clonep","/domains/fort/weap/sharpsword.c","/domains/fort/room/msquare_w.c","/doc/efun/all/asin","/domains/town/npc/zoe.c","/doc/lfun/lib/clan/eventRetire","/lib/include/press.h","/doc/efun/objects/tell_room","/log/chan/archive/muds-2010.08.26-21.45,48","/domains/fort/room/f_road6.c","/doc/lpc/concepts/lfun","/doc/applies/valid_bind","/log/chan/archive/intergossip-2010.10.22-19.45,48","/log/chan/archive/intergossip-2010.08.27-14.45,48","/doc/lfun/all/eventUse","/save/kills/x/xkcdgjigff","/save/kills/c/ceglbkbnnkc","/log/chan/archive/intergossip-2010.08.18-21.45,48","/domains/town/obj/stargate2.c","/domains/town/armor/badge.c","/secure/cmds/creators/ed.c","/save/kills/l/laebobljjh","/domains/fort/obj/register.c","/cmds/creators/.bugs.c.swp","/verbs/items/sell.c","/save/kills/h/hoomadboc","/domains/fort/npc/sergeant.c","/doc/lfun/lib/body/AddHeartModifier","/log/chan/archive/sport-2013.08.14-12.13,15","/domains/Ylsrim/etc/roof_wall.c","/domains/town/obj/.d6.c.swp","/doc/lfun/lib/body/CanManipulate","/log/chan/archive/muds-2010.08.30-06.45,48","/log/chan/archive/dgd-2009.03.31-15.51,27","/domains/fort/obj/ladder_simple.c","/www/ds-inst-faq.html","/doc/efun/all/function_owner","/www/cgi/new.c","/log/chan/archive/muds-2013.08.27-00.13,15","/domains/campus/adm/README","/verbs/common/whisper.c","/save/banish.8888.o","/log/chan/archive/muds-2010.09.04-23.45,48","/doc/efun/mappings/values","/doc/efun/all/set_reset","/log/chan/archive/muds-2010.10.26-20.45,48","/domains/campus/doors/blue_door3.c","/doc/lfun/lib/body/CanRemoveItem","/log/chan/archive/muds-2010.11.27-16.45,48","/domains/campus/npc/tim.c","/domains/default/npc/horse.c","/log/archive/catch-2009.10.27-18.31,00","/domains/town/meals/javarin.c","/domains/fort/obj/painting.c","/domains/town/obj/bbucket.c","/doc/lfun/lib/shell/SetCaliber","/doc/lfun/all/SetCellType","/www/cgi/finger.c","/log/chan/intermud","/save/kills/x/xkcdknofboiilg","/domains/Praxis/trunk.c","/domains/fort/obj/altar.c","/daemon/tmp/B_WINGED_MAN.c","/save/kills/x/xkcddkfcnbigh","/log/chan/archive/muds-2010.10.30-05.45,48","/domains/campus/armor/workboot_r.c","/secure/daemon/inet.c","/log/chan/archive/muds-2010.09.27-03.45,48","/log/chan/archive/muds-2009.05.10-23.59,14","/doc/efun/numbers/to_float","/obj/npc.c","/doc/lfun/lib/body/ParseHook","/domains/campus/weap/grenade.c","/doc/lfun/lib/body/GetCaffeine","/doc/lfun/all/GetHealRate","/doc/efun/all/write_buffer","/doc/lfun/lib/server/eventDestruct","/secure/daemon/i3router/send_full_mudlist.h","/save/kills/k/khgc","/doc/lfun/lib/body/GetLimbParent","/verbs/rooms/include/climb.h","/save/kills/n/nlgigi","/doc/lfun/lib/burn/GetFuelRequired","/doc/efun/all/pluralize","/domains/cave/obj/.table.c.swp","/doc/lfun/lib/combat/GetMaxHealthPoints","/log/chan/archive/muds-2010.09.14-09.45,48","/domains/campus/doors/eledoor3.c","/domains/campus/armor/workboot_l.c","/save/kills/b/bdieidaa","/save/kills/k/keffm","/save/kills/c/cddhoba","/lib/props/.save.c.swp","/domains/default/room/catchtell.c","/domains/campus/room/basement4.c","/save/kills/b/bgg","/log/i3","/save/bugs.4444.o","/cmds/players/mem.c","/www/lpmuds/router_debate.html","/domains/fort/room/f_road24.c","/log/chan/archive/muds-2009.04.14-21.29,16","/lib/include/barkeep.h","/domains/cave/room/kurogane.c","/log/chan/archive/broken_gossip-2011.01.06-15.46,13","/doc/lfun/lib/fuel/GetLong","/doc/lfun/lib/burn/SetFuelRequired","/domains/fort/room/north_wall_6.c","/doc/sefun/tell_object","/domains/campus/room/access2.c","/log/chan/archive/dchat-2009.03.18-13.30,39","/log/archive/runtime-2009.04.29-13.10,44","/secure/lib/connect.real","/cmds/players/queue.c","/save/kills/g/gicbi","/domains/Praxis/obj/mon/police.c","/save/kills/i/inoe","/.2222.o","/log/chan/archive/muds-2010.09.19-03.45,48","/domains/town/obj/cheatbook.c","/tmp/objects","/log/chan/ifree","/domains/town/room/orc_fortress.c","/secure/cmds/admins/liveupgrade.c","/domains/default/npc/quarantine/simon.c","/domains/Praxis/obj/weapon/bow.c","/www/editor.html","/doc/lfun/lib/body/GetAlcohol","/doc/lfun/all/CanWear","/daemon/services/auth.c","/verbs/items/include/look.h","/doc/lfun/lib/npc/GetLong","/log/chan/archive/inews-2009.03.28-15.12,22","/lib/.nmsh.c.swp","/lib/props/description.c","/log/chan/archive/muds-2010.09.06-09.45,48","/secure/include/sockets.h","/save/kills/k/kdodkbcabg","/domains/town/weap/staff.c","/doc/lfun/lib/leader/eventJoin","/doc/applies/__INIT","/domains/default/armor/robe.c","/lib/events/bury.c","/doc/efun/all/deep_inherit_list","/www/demo.html","/save/test.txt","/doc/lfun/lib/burn/GetBurnRate","/log/archive/catch-2011.08.21-07.04,13","/doc/efun/objects/query_heart_beat","/doc/efun/internals/debug_info","/secure/cfg/races/cat","/save/kills/x/xkcdkacnc","/secure/cmds/admins/decre.c","/doc/efun/all/nullp","/domains/amigara/obj/lamp.c","/verbs/creators/include/echo.h","/save/kills/i/inna","/lib/events/lie.c","/save/events.4444.o","/doc/sefun/mudlib","/doc/applies/parsing/parse_command_adjectiv_id_list","/doc/efun/all/write","/log/chan/archive/intergossip-2010.11.26-22.45,48","/log/archive/runtime-2010.07.10-04.16,00","/lib/fishing.c","/domains/Praxis/fighter_vote.c","/lib/include/client.h","/domains/Praxis/wild1.c","/doc/efun/interactive/this_user","/lib/vehicle.c","/domains/town/virtual/sky/23,6,1.c","/log/chan/archive/muds-2009.03.29-17.51,27","/log/chan/archive/intergossip-2010.08.06-11.18,42","/domains/town/obj/bigbag.c","/domains/campus/npc/kim.c","/log/chan/archive/muds-2009.03.11-03.02,51","/domains/default/virtual/arena.c","/doc/efun/internals/get_config","/log/chan/archive/intergossip-2010.08.26-20.45,48","/domains/town/room/shack.c","/domains/town/doors/pressure_door.c","/log/archive/runtime-2014.10.30-14.58,56","/domains/fort/room/quarters2.c","/domains/fort/obj/bed.c","/log/chan/archive/sport-2013.08.22-11.13,15","/log/archive/runtime-2010.07.08-19.16,00","/secure/cmds/players/hist.c","/domains/default/npc/red_dragon.c","/doc/lfun/lib/battery/GetRechargeable","/doc/efun/objects/virtualp","/log/chan/archive/muds-2010.08.30-19.45,48","/lib/bboard.c","/domains/default/room/wiz_hall.c","/log/reset","/log/chan/archive/muds-2010.09.30-08.45,48","/secure/cmds/admins/cwgconv.c","/save/economy.4444.o","/log/chan/archive/muds-2009.04.15-00.29,16","/verbs/items/close.c","/domains/town/armor/bdu.c","/domains/fort/obj/d6.c","/verbs/players/include/marry.h","/save/kills/x/xkcdjnfinejaa","/domains/default/armor/long_boot_r.c","/domains/town/obj/weight.c","/doc/lfun/lib/battery/SetRechargeable","/doc/lfun/lib/battery/SetDrainable","/domains/town/armor/long_glove.c","/doc/lfun/lib/body/checkCollapse","/doc/applies/error_handler","/domains/campus/txt/duh.txt","/daemon/services/locate.c","/save/kills/g/ggnjeidlce","/domains/Praxis/obj/misc/torch.c","/save/kills/j/jidlfjbcca","/secure/daemon/i3router/core_stuff.h","/save/kills/x/xkcdlihm","/save/kills/k/kjmmjh","/doc/efun/all/getuid","/log/chan/archive/intergossip-2010.09.28-09.45,48","/verbs/common/ask.c","/domains/default/armor/long_boot_l.c","/secure/scripts/killflow.src","/doc/efun/all/clonep","/doc/efun/compile/index","/log/chan/archive/muds-2010.12.21-03.45,48","/secure/cmds/admins/doctool.c","/domains/campus/obj/maglite.c","/secure/cmds/admins/.mudconfig.c.swp","/log/chan/archive/intergossip-2010.12.05-17.45,48","/domains/fort/room/f_road15.c","/domains/town/armor/.boot_l.c.swp","/lib/props/save.c","/domains/campus/save/jennybot.o","/domains/amigara/amigara/room/oguard2.c","/daemon/tmp/S_HUMAN_SIZED.c","/secure/scripts/mayhem.src","/secure/sefun/duplicates.c","/save/kills/g/ghldmbi","/domains/default/obj/couch.c","/www/ds.html","/doc/efun/all/repeat_string","/log/chan/delta","/verbs/items/disarm.c","/secure/cmds/admins/snoopreport.c","/log/chan/archive/inews-2013.08.21-19.13,15","/save/kills/x/xkcdnmemnkm","/domains/Praxis/n_centre1.c","/doc/efun/all/file_size","/log/chan/archive/broken_gossip-2010.12.26-21.46,48","/domains/town/armor/overalls.c","/log/chan/imudnews","/log/chan/archive/inews-2009.10.04-20.41,35","/domains/campus/armor/workglove_r.c","/save/kills/k/klkfda","/log/archive/reset-2010.11.20-11.45,48","/verbs/items/boobytrap.c","/log/chan/archive/muds-2009.04.24-16.41,34","/lib/daemons/verb.c","/save/kills/i/iblh","/log/chan/archive/muds-2010.08.18-20.45,48","/secure/cmds/admins/.gridconfig.c.swp","/log/chan/archive/muds-2010.10.21-11.45,48","/log/chan/archive/muds-2010.09.19-16.45,48","/lib/include/fish.h","/domains/default/npc/treant.c","/secure/scripts/resetgrid.src","/save/kills/x/xkcdmmh","/log/chan/archive/muds-2010.11.13-14.45,48","/lib/props/properties.c","/domains/town/room/wtunnel2.c","/doc/lfun/all/eventCheckProtection","/domains/Praxis/quests/imp_crown.c","/domains/Praxis/wild2.backup","/doc/lfun/all/AddExtraChannels","/log/chan/archive/discworld-chat-2010.07.25-15.16,48","/save/kills/m/mdmnlocaeka","/lib/props/deterioration.c","/save/kills/o/obhaf","/lib/command.c","/doc/efun/mudlib/index","/doc/help/players/channel","/domains/fort/armor/steel_helmet.c","/domains/fort/obj/redbox.c","/domains/cave/armor/orc_helmet.c","/domains/campus/armor/workglove_l.c","/log/chan/archive/muds-2010.08.22-05.45,48","/lib/include/armor.h","/domains/town/weap/m16rifle_mp.c","/log/chan/archive/i2game-2009.03.24-12.11,20","/log/chan/archive/muds-2010.09.05-15.45,48","/domains/default/doors/west.c","/www/lpmuds/forums.html","/domains/Praxis/monk_hall.c","/log/law/names/foo.txt","/log/chan/archive/muds-2010.11.28-08.45,48","/doc/efun/calls/index","/doc/lfun/lib/body/GetLead","/www/lpmuds/fader.js","/doc/efun/all/query_load_average","/log/chan/archive/muds-2009.04.14-20.29,16","/domains/fort/obj/bluebox.c","/lib/include/bank.h","/doc/lpc/concepts/MudOSdriver","/save/kills/c/cmj","/daemon/include/seasons.h","/daemon/tmp/cratylus.c","/domains/campus/txt/ai/charly/bak/green_wins","/doc/efun/floats/atan","/doc/applies/domain_file","/log/chan/archive/muds-2011.01.07-17.46,13","/save/kills/b/bemkdcai","/domains/Praxis/east_road2.c","/save/kills/b/bah","/doc/lfun/lib/classes/ChangeClass","/domains/fort/obj/9mmbox.c","/log/chan/archive/muds-2011.01.06-10.46,13","/log/archive/runtime-2011.08.21-09.04,13","/log/imc2_server/foo.txt","/secure/modules/door.c","/log/chan/archive/muds-2009.05.19-11.00,43","/domains/fort/obj/elf_manual.c","/secure/cmds/creators/flushobs.c","/doc/lfun/all/HandleTeller","/domains/town/meals/.blue_spice.c.swp","/doc/lfun/all/SetFingers","/domains/fort/room/east_wall_1.c","/domains/fort/npc/sergeant.bak","/domains/campus/txt/ai/charly/stays","/log/chan/archive/intergossip-2010.09.26-22.45,48","/doc/lfun/all/eventWear","/www/images/Thumbs.db","/log/imc2","/log/chan/archive/intergossip-2010.12.21-16.45,48","/domains/default/armor/towel.c","/obj/friend.c","/log/archive/catch-2011.08.21-06.04,13","/daemon/tmp/A_ARMOR.c","/lib/post_office.c","/domains/campus/room/klab.c","/domains/town/obj/torch.c","/daemon/tmp/B_NEBULOUS.c","/log/chan/archive/dchat-2010.09.07-15.45,48","/domains/campus/txt/jenny/7.txt","/domains/Praxis/booth.c","/secure/cmds/creators/dbxframe.c","/domains/cave/obj/chest2.c","/domains/campus/doors/green_door3.c","/cmds/players/version.c","/daemon/tmp/me.c","/log/chan/archive/dchat-2010.12.02-09.45,48","/domains/fort/obj/note.c","/save/kills/a/aojb","/doc/lfun/lib/race/GetAlcohol","/domains/campus/adm/access.c","/log/chan/archive/muds-2011.01.07-03.46,13","/domains/fort/meals/salmon.c","/secure/cmds/admins/setreboot.c","/log/chan/archive/muds-2010.11.06-07.45,48","/log/archive/runtime-2010.07.10-03.16,00","/doc/lfun/lib/npc/eventDie","/save/kills/b/bcfj","/daemon/tmp/LIB_ITEM.c","/doc/efun/system/named_livings","/domains/town/virtual/sky/22,6,1.c","/save/kills/d/djafnffj","/domains/town/doors/m3.c","/.3333.o","/domains/campus/obj/box.c","/daemon/tmp/Ijonnk.c","/log/archive/runtime-2009.04.26-19.06,12","/verbs/items/donate.c","/log/chan/archive/dgd-2013.08.19-11.13,15","/doc/lfun/lib/chat/eventDestruct","/save/kills/x/xkcdolnna","/log/archive/runtime-2014.10.30-13.58,56","/doc/lfun/lib/interactive/CanMarry","/log/chan/archive/intergossip-2010.09.18-22.45,48","/doc/lpc/constructs/prototypes","/domains/cave/npc/rybak.c","/domains/amigara/room/passage5.c","/log/archive/runtime-2010.07.08-18.16,00","/secure/daemon/luget.c","/domains/fort/armor/wglove_r.c","/verbs/items/roll.c","/doc/efun/all/tell_object","/verbs/items/pull.c","/secure/cfg/classes/cleric","/domains/fort/weap/boobytrap_dagger.c","/log/chan/archive/muds-2010.09.30-07.45,48","/verbs/players/describe.c","/domains/Praxis/mountains/tunnel1.c","/doc/applies/privs_file","/domains/Praxis/kataan_join.c","/domains/town/npc/clerk.c","/doc/lfun/lib/chapel/SetSacrificeType","/doc/efun/mixed/bufferp","/domains/fort/obj/wrack.c","/daemon/tmp/stats.c","/doc/efun/all/values","/www/lpmuds/intermud_files/smflogo.gif","/domains/fort/armor/wglove_l.c","/secure/cfg/races/horse","/save/kills/x/xkcdbmbcf","/lib/std/barkeep.c","/verbs/players/include/request.h","/log/chan/archive/muds-2013.08.22-04.13,15","/domains/fort/npc/tower_guard.c","/domains/campus/obj/9mmclip.c","/domains/amigara/amigara/room/kchief.c","/log/chan/archive/muds-2011.01.02-08.46,48","/save/kills/c/cji","/log/chan/archive/muds-2010.10.30-17.45,48","/log/chan/archive/intergossip-2010.07.21-15.16,17","/doc/lfun/all/GetClass","/verbs/items/unload.c","/save/events.5555.o","/daemon/verbs.c","/verbs/items/include/open.h","/log/chan/archive/imudnews-2010.09.01-13.45,48","/log/chan/archive/mudnews-2013.08.17-11.13,15","/save/kills/o/ofeollgagml","/log/chan/archive/muds-2010.09.18-22.45,48","/domains/campus/obj/register.c","/lib/include/poison.h","/doc/efun/mixed/objectp","/save/kills/a/abnaegn","/doc/lfun/all/SetDrainable","/secure/cmds/creators/vi.c","/cmds/creators/efuns.c","/lib/help.c","/cmds/creators/wizroll.c","/log/chan/archive/inews-2009.04.14-13.29,16","/doc/sefun/wrap","/doc/efun/strings/strlen","/log/chan/archive/dgd-2010.11.19-13.45,48","/save/kills/x/xkcdlflidebil","/domains/default/obj/.rack.c.swp","/std/lib/pile.c","/daemon/deviation.c","/log/chan/archive/muds-2010.09.13-14.45,48","/log/chan/archive/muds-2010.09.21-00.45,48","/log/errors/amigara","/save/kills/b/bn","/log/chan/archive/dchat-2010.08.11-02.18,42","/doc/lfun/lib/lamp/GetLong","/save/kills/b/bl","/lib/include/read.h","/save/kills/b/bk","/log/chan/archive/dgd-2009.03.23-18.11,20","/domains/town/npc/grouper.c","/save/kills/b/bj","/domains/campus/obj/watch.c","/doc/efun/all/socket_acquire","/save/economy.5555.o","/save/kills/b/bg","/domains/Praxis/obj/magic/ball.c","/save/kills/b/bf","/log/chan/archive/muds-2010.12.18-10.45,48","/save/kills/b/bd","/doc/applies/receive_snoop","/log/chan/archive/dchat-2010.09.14-21.45,48","/domains/fort/weap/sword.c","/lib/events/sit.c","/log/chan/archive/inews-2009.03.22-16.17,00","/log/chan/archive/muds-2010.08.27-12.45,48","/domains/town/room/mansion_room5.c","/log/chan/archive/muds-2010.09.28-08.45,48","/lib/include/torch.h","/domains/campus/txt/doh.txt","/domains/Praxis/cemetery/grave_yard3.c","/secure/modules/money.c","/domains/campus/room/corridor4.c","/log/chan/archive/dchat-2010.08.09-17.18,42","/doc/help/players/list","/domains/Praxis/square.c","/log/errors/archive/lib-2009.09.22-14.04,12","/log/chan/archive/intergossip-2010.11.05-13.45,48","/save/kills/m/mfged","/obj/order.c","/www/lpmuds/maintenance.html","/domains/amigara/room/oleader.c","/doc/lfun/lib/burn/SetBurnRate","/log/chan/archive/muds-2011.01.10-08.46,13","/save/kills/j/jhmnm","/lib/lvs/.abilities.c.swp","/domains/campus/txt/bye.txt","/log/chan/archive/i2game-2009.03.24-11.11,20","/domains/cave/room/cavepass7.c","/lib/firearm.c","/domains/town/virtual/forest/foo","/doc/applies/creator_file","/secure/cfg/mudos.3333.win32","/log/chan/archive/dchat-2010.11.14-20.45,48","/secure/lib/net/.ftp.c.swp","/domains/fort/weap/waterpistol.c","/doc/efun/all/debugmalloc","/log/chan/archive/muds-2010.10.27-11.45,48","/lib/chapel.c","/log/chan/archive/muds-2009.03.28-13.11,36","/domains/town/armor/riding_boot.c","/doc/applies/log_error","/verbs/players/mount.c","/lib/std/chair.c","/save/kills/x/xkcdbmcnffe","/domains/fort/obj/tlocker.c","/log/chan/archive/muds-2013.08.06-04.13,15","/lib/include/persist.h","/domains/cave/room/cavepass1.c","/log/chan/archive/muds-2010.08.28-05.45,48","/doc/lfun/lib/look/GetLong","/doc/efun/general/fetch_variable","/daemon/disasters.c","/domains/town/txt/praxis_sign.txt","/doc/efun/general/map","/log/chan/archive/muds-2010.10.22-03.45,48","/save/kills/c/cmbmabdcik","/log/archive/runtime-2010.07.10-16.16,00","/save/map.o","/log/archive/runtime-2011.08.21-08.04,13","/domains/cave/npc/chieftain.c","/verbs/items/light.c","/domains/fort/npc/praetorian_guard.bak","/log/chan/archive/imudnews-2010.08.08-23.18,42","/log/chan/archive/intergossip-2013.07.30-14.13,15","/domains/learning/adm/README","/doc/help/creators/profile","/include/medium.h","/secure/tmp/webtemp.html","/domains/town/armor/scarf.c","/secure/lib/net/generic.c","/domains/town/armor/jacket.c","/doc/efun/mixed/functionp","/secure/sefun/users.c","/domains/campus/room/sub_basement2.c","/doc/lfun/all/GetBurntValue","/secure/cmds/players/finger.c","/lib/pile.c","/log/chan/archive/muds-2010.10.28-04.45,48","/domains/fort/obj/backpack.c","/doc/lfun/lib/battery/ModCharge","/daemon/tmp/A_PANTS.c","/save/kills/j/jilik","/domains/cave/room/rubbish.c","/verbs/players/include/withdraw.h","/include/vendor_types.h","/verbs/players/sink.c","/domains/fort/npc/fighter.c","/secure/cmds/admins/whoguests.c","/doc/lfun/lib/body/eventBuy","/domains/default/npc/.dryad.c.swp","/doc/efun/sockets/network_stats","/save/kills/j/jajkboma","/verbs/players/crawl.c","/log/archive/runtime-2009.04.30-11.48,12","/verbs/rooms/include/fly.h","/doc/efun/system/ctime","/obj/whip.c","/domains/town/room/living_room.c","/cmds/creators/file.c","/log/chan/archive/muds-2011.01.08-09.46,13","/doc/efun/system/call_out_info","/log/chan/archive/muds-2010.10.06-17.45,48","/daemon/tmp/training.c","/log/archive/runtime-2010.07.10-02.16,00","/domains/town/room/forest_well2.c","/doc/applies/author_file","/domains/town/obj/9mmround.c","/log/open/terminals","/domains/town/virtual/sky/21,6,1.c","/domains/fort/doors/menagerie.c","/doc/efun/all/this_user","/save/kills/x/xkcdafk","/doc/sefun/month","/daemon/tmp/MOUTH_TOOTHED+MOUTH_TONGUED+MOUTH_VENOMOUS+MOUTH_FANGED.c","/domains/fort/armor/ring1.c","/doc/lfun/all/SetClanObject","/log/chan/*dalet:free_speech","/domains/campus/armor/wizard_hat.c","/log/chan/archive/intergossip-2013.08.13-10.13,15","/lib/mayor.c","/domains/cave/doors/kurogane.c","/domains/campus/armor/ring.c","/www/downloads.html","/log/chan/icode","/log/chan/archive/intergossip-2010.10.30-16.45,48","/domains/town/npc/human_champion.c","/daemon/services.c","/doc/efun/all/swap","/log/archive/runtime-2014.10.30-12.58,56","/doc/efun/all/users","/std/server.txt","/domains/Praxis/orc_valley/guard.c","/doc/efun/all/userp","/log/chan/archive/inews-2009.05.16-15.59,29","/log/archive/runtime-2010.07.08-17.16,00","/cmds/creators/morse.c","/secure/sefun/disable.c","/log/chan/archive/muds-2013.08.28-18.13,15","/domains/default/armor/.chainmail.c.swp","/log/chan/dragon","/doc/efun/internals/malloc_status","/log/chan/archive/muds-2010.09.30-06.45,48","/verbs/items/pour.c","/doc/lfun/all/AddFingers","/daemon/unique.c","/doc/efun/interactive/input_to","/log/chan/archive/intergossip-2009.03.17-17.30,39","/save/kills/x/xkcdcnbff","/log/chan/archive/intergossip-2010.11.18-20.45,48","/domains/town/npc/leo.c","/save/kills/a/acdm","/doc/efun/mappings/filter_mapping","/doc/lfun/lib/firearm/GetFirearmType","/secure/obj/control.c","/save/bugs.6666.o","/cmds/creators/notices.c","/domains/town/meals/speedalin.c","/obj/deed.c","/lib/include/detect.h","/log/chan/archive/muds-2010.09.27-14.45,48","/doc/help/creators/security","/doc/sefun/convert_name","/cmds/players/kills.c","/log/archive/runtime-2009.10.27-18.31,00","/lib/events/consult.c","/domains/Praxis/cleric_hall.c","/domains/fort/obj/lamp.c","/domains/fort/npc/my_fighter.c","/secure/cmds/players/history.c","/cmds/creators/unmorse.c","/lib/include/living.h","/doc/efun/mixed/arrayp","/.4444.o","/secure/cmds/creators/people.c","/lib/include/scroll.h","/doc/efun/all/dump_socket_status","/verbs/items/judge.c","/domains/town/obj/thing.c","/domains/Praxis/hotel.c","/doc/efun/all/m_delete","/verbs/creators/include/codesay.h","/save/kills/g/gogecognbfbajk","/daemon/tmp/S_SMALL.c","/secure/lib/net/ftp_data_connection.c","/log/chan/archive/intergossip-2010.10.28-17.45,48","/save/kills/g/gnjj","/log/chan/archive/muds-2010.11.27-13.45,48","/domains/town/obj/.223round.c.swp","/log/chan/discworld-cre","/domains/fort/obj/stove.c","/domains/Praxis/data/properties.t","/verbs/items/knock.c","/domains/Praxis/data/properties.o","/domains/campus/obj/debris.c","/log/archive/i3error-2009.04.13-04.29,16","/log/chan/archive/sport-2009.03.18-16.30,39","/log/chan/archive/muds-2010.10.31-09.45,48","/domains/Ylsrim/save/0^0domains0^0Ylsrim0^0room0^0fighter.o","/domains/town/room/gate.c","/log/chan/archive/muds-2009.04.24-14.41,34","/domains/amigara/room/kchief.c","/domains/Praxis/obj/weapon/dagger.c","/doc/lfun/lib/post_office/CanReceive","/doc/RELEASE_NOTES","/log/chan/kotaka","/log/chan/archive/muds-2010.12.14-08.45,48","/save/intermud.o","/domains/town/weap/paring_knife.c","/save/kills/a/amnhnaiie","/domains/Praxis/pier1.c","/log/chan/archive/muds-2010.12.13-01.45,48","/log/chan/archive/dchat-2010.07.22-21.16,17","/domains/campus/obj/podium.c","/save/events.6666.o","/log/chan/archive/dgd-2009.03.28-11.11,20","/secure/lib/include/connect.h","/doc/lfun/lib/bot/eventDie","/obj/barkeep.c","/doc/lpc/constructs/inherit","/secure/sefun/legacy.c","/cmds/creators/netstat.c","/domains/town/weap/leostaff.c","/domains/campus/txt/ai/charly/green_wins","/domains/fort/obj/sofa.c","/doc/efun/interactive/find_player","/doc/applies/master/creator_file","/domains/fort/room/mguild.c","/doc/efun/interactive/exec","/domains/Ylsrim/room/bank_roof.c","/log/player_errors","/domains/town/npc/thief.c","/save/kills/c/cokafii","/secure/cmds/creators/snoop.c","/save/races.o","/log/chan/archive/inews-2009.04.01-09.51,27","/lib/include/lead.h","/daemon/services/error.c","/doc/applies/master/valid_write","/secure/cfg/races/prawn","/save/kills/g/ghih","/news/newbie","/cmds/creators/clone.c","/log/chan/archive/muds-2010.10.14-16.45,48","/log/chan/archive/muds-2009.03.23-18.11,20","/domains/town/obj/slip_excise.c","/save/economy.6666.o","/domains/default/npc/quarantine/jan.c","/doc/lfun/all/SetClan","/secure/cmds/creators/mkdir.c","/log/chan/archive/muds-2009.03.19-22.16,52","/log/archive/runtime-2010.07.10-15.16,00","/shadows/drone.c","/save/kills/c/cbf","/doc/efun/interactive/query_ip_port","/log/archive/runtime-2011.08.21-07.04,13","/domains/Ylsrim/broken/jar.c","/lib/include/jump.h","/domains/Ylsrim/armor/shield.c","/secure/include/config.6666","/log/chan/archive/muds-2010.12.05-01.45,48","/log/chan/archive/intergossip-2013.08.22-16.13,15","/doc/lfun/all/InitComposition","/log/errors/lib","/domains/Praxis/monk_vote.c","/log/chan/archive/muds-2009.03.28-21.51,27","/doc/lfun/all/GetSkillModifier","/save/kills/f/fhhnec","/log/chan/archive/inews-2009.03.16-17.30,39","/domains/town/save/0^0domains0^0town0^0obj0^0charity.o","/domains/campus/obj/locker.c","/verbs/builders/dest.c","/lib/events/bait.c","/save/kills/e/ecddncofija","/www/lpmuds/index.php","/secure/include/post.h","/log/archive/catch-2009.04.23-23.15,49","/save/stargate.1111.o","/lib/include/drop.h","/doc/sefun/check_privs","/doc/applies/master/valid_hide","/save/kills/x/xkcdemoammlc","/lib/include/post_office.h","/domains/fort/obj/riverwater.c","/log/chan/archive/intergossip-2013.08.27-10.13,15","/domains/campus/etc/permit.cfg","/domains/default/room/domains_room.c","/save/kills/c/cac","/log/chan/archive/intergossip-2010.09.21-12.45,48","/log/chan/archive/muds-2010.10.14-02.45,48","/domains/Praxis/unnamed1.c","/doc/efun/objects/tell_object","/log/archive/runtime-2010.07.10-01.16,00","/domains/fort/weap/board.c","/doc/sefun/generate_tmp","/log/chan/archive/muds-2013.08.22-16.13,15","/lib/props/id.c","/domains/default/room/quarantine3.c","/log/chan/archive/muds-2013.08.30-02.13,15","/log/chan/archive/dchat-2010.07.15-14.16,17","/domains/town/virtual/sky/20,6,1.c","/cmds/players/env.c","/log/chan/archive/intergossip-2013.08.14-16.13,15","/doc/lfun/lib/body/eventFall","/doc/help/creators/messaging","/lib/cedit.c","/secure/daemon/i3router/clean_fd.h","/log/chan/intergossip","/doc/help/players/.wordwrap.swp","/log/chan/archive/muds-2010.09.26-20.45,48","/lib/include/door.h","/verbs/common/speak.c","/secure/include/.secrets.h.swp","/secure/cmds/admins/chancreate.c","/domains/Praxis/chapel.c","/lib/enter.c","/domains/town/npc/cod.c","/domains/default/obj/223round.c","/log/archive/runtime-2014.10.30-11.58,56","/doc/efun/system/uptime","/log/chan/archive/muds-2010.12.12-21.45,48","/log/chan/archive/intergossip-2010.12.13-14.45,48","/log/archive/runtime-2010.07.08-16.16,00","/verbs/items/eat.c","/doc/efun/floats/sin","/domains/cave/room/guardroom2.c","/log/router/rsocket","/log/chan/archive/muds-2013.08.27-10.13,15","/save/kills/o/ojfnbddbf","/domains/town/obj/.d20.c.swp","/domains/fort/obj/yellowbox.c","/domains/town/npc/horse.c","/doc/efun/arrays/filter_array","/verbs/rooms/cast.c","/save/kills/i/ibjmalgmcc","/domains/fort/room/gate.bak","/domains/town/txt/ylsrim_sign.txt","/domains/amigara/amigara/room/passage9.c","/log/chan/archive/inews-2013.08.20-23.13,15","/log/chan/archive/broken_gossip-2011.01.01-03.46,48","/domains/campus/chamber/elevator.c","/domains/town/weap/m16rifle.c","/doc/lfun/all/GetProtect","/secure/obj/snooper.c","/domains/campus/txt/ai/charly/bak/fred","/doc/efun/all/log","/log/chan/archive/muds-2010.11.22-18.45,48","/doc/lfun/lib/clan/GetClanName","/domains/town/obj/btable.c","/doc/efun/all/filter_array","/log/chan/archive/muds-2010.11.30-04.45,48","/lib/include/genetics.h","/doc/efun/all/find_object","/secure/cmds/admins/shutdown.c","/domains/town/room/narrow_path.c","/secure/sefun/.native_version.c.swp","/log/chan/archive/muds-2010.12.13-14.45,48","/domains/fort/room/gstreet5.c","/domains/amigara/amigara/room/passage3.c","/log/chan/archive/muds-2010.12.04-21.45,48","/domains/town/meals/blue_spice.c","/log/archive/runtime-2010.07.09-09.16,00","/domains/default/npc/quarantine/gavin.c","/domains/campus/obj/labkey.c","/domains/town/room/secret.c","/daemon/tmp/R_AIR+R_WATER.c","/domains/town/armor/silverring.c","/secure/obj/medtric.c","/log/chan/archive/muds-2013.08.28-03.13,15","/save/kills/x/xkcdoeaggka","/save/kills/j/jdlojmef","/lib/events/activate.c","/domains/town/obj/357round.c","/doc/lfun/lib/body/AddAlcohol","/cmds/players/converse.c","/log/chan/archive/muds-2010.09.22-05.45,48","/domains/fort/obj/pool_table.c","/domains/amigara/room/kcommon.c","/domains/Praxis/quests/hellfire.c","/domains/fort/obj/water_pipe.c","/daemon/tmp/R_WATER.c","/lib/include/limb.h","/doc/lfun/all/SetCharge","/domains/fort/room/ptower.c","/domains/town/obj/table.c","/domains/Praxis/quests/chaucer.c","/log/domain_stats","/domains/Praxis/inn108.c","/verbs/players/stealth.c","/save/kills/x/xkcdhbgjfmool","/log/chan/*dalet:imud_code","/doc/applies/master/get_bb_uid","/log/chan/archive/muds-2010.08.28-17.45,48","/lib/std/daemon.c","/log/chan/archive/muds-2010.10.22-15.45,48","/domains/town/obj/safe_key.c","/domains/fort/obj/dining_table.c","/doc/lfun/lib/race/GetMaxHealthPoints","/secure/scripts/bedlam.src","/save/kills/x/xkcdjnegem","/www/lpmuds/downloads_files/style.css","/secure/sefun/wild_card.c","/lib/trainer.c","/log/chan/archive/intergossip-2010.11.06-18.45,48","/doc/efun/all/query_privs","/log/chan/archive/muds-2010.12.05-14.45,48","/doc/efun/all/time_expression","/log/chan/archive/dchat-2013.08.07-23.13,15","/log/chan/archive/muds-2013.07.29-07.13,15","/domains/Praxis/inn102.c","/www/lpmuds/merentha-faq.html","/domains/learning/room/wiz_hall.c","/doc/lfun/all/GetAffectLong","/save/kills/x/xkcdfidibil","/doc/lfun/lib/corpse/GetHealthShort","/save/parties.1111.o","/log/chan/archive/muds-2010.09.06-19.45,48","/domains/campus/weap/357pistol.c","/domains/campus/obj/wrack.c","/domains/campus/obj/clip.c","/log/chan/archive/dchat-2010.11.23-11.45,48","/doc/lfun/lib/room/CanReceive","/www/articles/why_ds.html","/save/kills/x/xkcddofnojoihb","/save/kills/m/mlnmjmdbnl","/log/chan/archive/muds-2010.10.28-16.45,48","/daemon/tmp/B_HUMANOID.c","/secure/cfg/races/artrell","/doc/lfun/lib/body/GetHealthPoints","/.5555.o","/log/chan/archive/intergossip-2010.12.20-20.45,48","/doc/lfun/all/RestoreLimb","/save/kills/f/fnho","/log/chan/archive/sport-2013.08.02-07.13,15","/log/archive/catch-2009.04.25-15.33,23","/include/stargate.h","/obj/door.c","/save/kills/x/xkcdiaeohclca","/log/chan/archive/inews-2013.08.22-09.13,15","/log/chan/i2code","/doc/lfun/all/GetStats","/domains/campus/obj/flashlight.c","/doc/efun/all/socket_write","/lib/std/book.c","/domains/fort/room/west_wall_7.c","/doc/lfun/lib/clan/SetClanSkill","/doc/efun/objects/restore_object","/log/archive/runtime-2010.07.10-14.16,00","/lib/events/search.c","/log/chan/archive/muds-2010.11.14-04.45,48","/log/archive/runtime-2011.08.21-06.04,13","/domains/fort/room/bakery.c","/domains/campus/txt/ai/charles/bak2/green_wins","/log/chan/archive/sport-2013.08.08-08.13,15","/doc/lfun/all/CanBurn","/domains/default/npc/artrell.c","/doc/efun/all/malloc_status","/log/chan/archive/muds-2009.03.11-13.02,51","/doc/efun/mappings/map_delete","/log/chan/archive/inews-2013.08.19-17.13,15","/doc/efun/mixed/stringp","/save/kills/d/dhk","/cmds/admins/cache.c","/domains/fort/room/west_wall_1.c","/domains/fort/armor/jacket.c","/domains/town/room/tavern.c","/domains/campus/obj/backpack.c","/domains/town/obj/wall.c","/log/chan/archive/muds-2010.12.20-20.45,48","/lib/used_meal.c","/save/kills/g/ghca","/domains/town/npc/newt.c","/secure/daemon/i3router/send_mudlist_updates.h","/log/law/adm/foo.txt","/doc/efun/all/map_mapping","/log/chan/archive/intergossip-2010.08.01-13.18,42","/domains/cave/obj/cask.c","/secure/sefun/generic.c","/save/kills/x/xkcdghgc","/log/chan/archive/muds-2013.08.27-23.13,15","/domains/cave/armor/orc_tallboot_r.c","/domains/Praxis/restaurant.c","/doc/sefun/local_time","/domains/default/room/wiz_corr_east2.c","/domains/amigara/amigara/npc/rat.c","/save/kills/d/dmaajo","/save/kills/o/odnacfcf","/domains/fort/obj/357case.c","/daemon/tmp/square.c","/doc/build/Introduction","/save/kills/n/nefnimgd","/doc/lfun/lib/body/GetEquippedLimbs","/secure/cmds/creators/rm.c","/save/kills/g/gc","/log/chan/archive/i2news-2009.05.15-20.59,29","/log/chan/archive/intergossip-2010.10.07-08.45,48","/domains/fort/armor/newbie_ring.c","/doc/lfun/lib/body/SetBodyComposition","/log/archive/runtime-2010.07.10-00.16,00","/doc/sefun/absolute_path","/lib/language.c","/save/kills/l/lmkmgdddlhe","/log/chan/archive/intergossip-2010.08.07-14.18,42","/domains/cave/armor/orc_tallboot_l.c","/domains/fort/obj/9mmround.c","/domains/fort/obj/rug.c","/log/chan/archive/muds-2010.11.30-17.45,48","/log/chan/archive/muds-2010.10.01-07.45,48","/log/chan/archive/intergossip-2010.10.21-21.45,48","/daemon/include/bugs.h","/news/reminders.txt","/secure/cfg/mudos.4444.cfg","/lib/teach.c","/doc/lfun/lib/classes/GetSkillModifier","/log/archive/runtime-2010.07.08-15.16,00","/doc/lfun/all/eventReceiveDamage","/domains/amigara/amigara/room/passage24.c","/www/lpmuds/xml_topic.js","/save/kills/x/xkcdbodcoee","/domains/town/npc/zafo.c","/log/archive/catch-2009.09.22-14.04,12","/log/errors/cratylus","/doc/sefun/total_light","/secure/cfg/races/bot","/log/chan/archive/dchat-2009.05.24-17.22,24","/log/chan/archive/muds-2010.09.22-18.45,48","/domains/town/obj/couch.c","/doc/lfun/lib/armor/GetFingers","/log/chan/archive/muds-2010.09.30-04.45,48","/log/archive/runtime-2009.03.10-04.37,18","/domains/fort/obj/fountain.c","/log/chan/archive/muds-2010.09.21-11.45,48","/verbs/players/attack.c","/doc/efun/parsing/query_verb","/doc/efun/all/socket_release","/log/chan/archive/intergossip-2010.09.13-11.45,48","/save/stargate.2222.o","/lib/comp/object.c","/domains/default/npc/turtle.c","/domains/town/obj/rack.c","/domains/fort/npc/dinsdale.c","/domains/Praxis/sheriff.c","/cmds/players/.prompt.c.swp","/secure/cmds/admins/resetpasswd.c","/domains/fort/room/tunnel6.c","/doc/efun/mudlib/set_author","/doc/lfun/lib/chapel/GetAllowSacrifice","/log/chan/archive/intergossip-2010.07.22-19.16,17","/doc/help/players/points","/domains/default/npc/quarantine/lex.c","/log/chan/archive/muds-2010.08.27-23.45,48","/log/chan/archive/muds-2010.10.21-21.45,48","/domains/fort/room/storeroom4.c","/domains/Praxis/lpc_inner.c","/log/archive/catch-2009.07.12-23.58,36","/domains/town/room/basement.c","/domains/campus/room/science7.c","/secure/cmds/creators/changelog.c","/log/chan/archive/muds-2010.12.22-06.45,48","/secure/cmds/creators/homedir.c","/domains/Ylsrim/obj/stargate.c","/domains/fort/weap/crowbar.c","/log/archive/runtime-2010.07.09-08.16,00","/secure/cmds/players/include/passwd.h","/news/welcome.2222","/cmds/creators/whomuffed.c","/log/errors/cave","/log/chan/archive/intergossip-2010.07.28-12.17,46","/domains/cave/obj/letter3.c","/domains/campus/doors/red_door3.c","/domains/fort/obj/key1.c","/domains/default/vehicle/hoverpod.c","/cmds/players/consider.c","/save/kills/i/ilnlkgdm","/domains/examples/room/exroom7.c","/log/chan/archive/muds-2010.10.27-22.45,48","/domains/campus/room/science1.c","/domains/Praxis/cemetery/mon/ghosta.c","/doc/lfun/lib/firearm/CanReceive","/lib/.chat.c.swp","/domains/default/armor/shirt.c","/cmds/players/nextreboot.c","/domains/cave/obj/waste.c","/log/chan/archive/muds-2010.12.19-14.45,48","/domains/fort/room/mstreet5.c","/domains/Praxis/torture_room.c","/domains/Praxis/hall4.c","/daemon/tmp/secret.c","/verbs/items/press.c","/domains/fort/obj/charity.c","/domains/Praxis/mountains/chamber1.c","/www/lpmuds/lpmud_faq.html","/save/kills/x/xkcdgiiofdgem","/domains/Praxis/cleric_vote.c","/log/chan/archive/dchat-2010.09.23-11.45,48","/verbs/players/party.c","/lib/shadow_hook.c","/domains/fort/room/common15.c","/domains/examples/room/exroom1.c","/log/chan/archive/discworld-chat-2010.11.05-09.45,48","/verbs/items/include/wield.h","/log/chan/archive/muds-2010.10.13-21.45,48","/log/chan/archive/muds-2010.11.14-17.45,48","/domains/Praxis/quests/honor.c","/domains/town/obj/d20.c","/doc/help/players/credits","/domains/town/obj/key.c","/domains/fort/armor/bandanna.c","/lib/events/drink.c","/log/chan/archive/inews-2009.05.18-22.00,12","/save/kills/x/xkcdmdanemhdm","/domains/town/doors/south.c","/domains/fort/room/bwall4.c","/domains/campus/doors/steel_door2.c","/log/runtime","/domains/amigara/amigara/room/food_storage.c","/verbs/items/activate.c","/domains/town/room/vill_road1.c","/domains/town/npc/deer.c","/doc/help/creators/qcs","/daemon/tmp/thog.c","/cmds/creators/classblock.c","/save/kills/x/xkcdfofl","/save/kills/e/enhd","/domains/town/weap/.boobytrap_dagger.c.swp","/domains/Praxis/idle_storage.c","/doc/lfun/all/GetRandomLimb","/lib/std/bed.c","/domains/cave/room/common2.c","/domains/town/armor/.long_sock.c.swp","/domains/examples/room/exroom2b.c","/log/chan/archive/muds-2009.03.18-08.30,39","/domains/town/obj/well_lever.c","/log/chan/archive/muds-2010.09.05-11.45,48","/doc/applies/interactive/write_prompt","/doc/efun/mixed/floatp","/lib/classes.c","/doc/efun/all/restore_object","/secure/cmds/admins/admintool.c","/domains/fort/obj/gstool.c","/www/lpmuds/alternate_router.html","/domains/town/armor/workboot_r.c","/secure/lib/.connect.c.swp","/log/chan/archive/muds-2010.12.19-00.45,48","/lib/combat.c","/doc/lfun/lib/chat/eventReconnect","/save/kills/e/eol","/lib/comp/container.c","/doc/efun/all/destruct","/log/chan/archive/intergossip-2010.09.30-17.45,48","/domains/fort/room/bpath2.c","/domains/fort/room/common7.c","/secure/cmds/creators/indent.c","/secure/modules/room.c","/save/kills/x/xkcdneljdbek","/save/kills/b/bhchoabnoo","/save/kills/d/dci","/domains/default/npc/foochy.c","/domains/default/npc/elf.c","/domains/town/meals/.green_spice.c.swp","/doc/lfun/all/eventBring","/doc/lfun/all/GetFirearmType","/doc/efun/all/read_file","/log/archive/runtime-2010.07.10-13.16,00","/secure/lib/net/remote.c","/log/chan/archive/muds-2010.11.05-10.45,48","/doc/lfun/all/CanSacrifice","/cfg/time.cfg","/log/chan/archive/muds-2009.04.28-01.22,05","/domains/amigara/amigara/room/passage15.c","/secure/include/deputies.h","/save/kills/i/iaaabioh","/domains/town/armor/workboot_l.c","/domains/Ylsrim/armor/artrell_armor.c","/domains/town/txt/spam.txt","/domains/fort/weap/brush.c","/domains/fort/room/common1.c","/doc/efun/system/set_eval_limit","/doc/efun/interactive/in_edit","/doc/efun/all/external_start","/save/kills/f/fbci","/save/bugs.8888.o","/log/chan/archive/intergossip-2010.11.30-16.45,48","/log/chan/archive/muds-2009.05.08-00.13,35","/secure/cmds/admins/tempban.c","/log/chan/archive/muds-2010.09.06-04.45,48","/lib/include/money.h","/doc/lfun/all/GetWorn","/lib/clan.c","/domains/Praxis/obj/mon/spider.c","/lib/std/bot_limb.c","/doc/efun/general/store_variable","/doc/lfun/lib/equip/GetWorn","/ftp/foo.txt","/save/kills/c/cbkjb","/log/chan/archive/muds-2010.09.30-17.45,48","/domains/town/obj/mat.c","/doc/efun/all/export_uid","/daemon/tmp/intermud.c","/cmds/players/mudinfo.c","/cmds/creators/which.c","/save/kills/x/xkcdjknddomoh","/domains/town/obj/cloak_hood.c","/cmds/creators/wizlist.c","/.6666.o","/log/chan/archive/muds-2009.04.10-08.28,44","/log/archive/i3error-2009.05.20-01.06,41","/doc/help/players/banking","/log/chan/archive/muds-2010.10.15-07.45,48","/doc/lfun/all/GetFuelRequired","/domains/Praxis/obj/misc/shovel.c","/doc/lfun/lib/clan/SetClanName","/doc/efun/floats/ceil","/domains/Ylsrim/adm/freezer.c","/doc/sefun/set_eval_limit","/verbs/items/remove.c","/log/chan/archive/muds-2014.09.20-14.08,45","/log/archive/runtime-2014.10.30-10.58,09","/lib/events/get.c","/cmds/creators/showtree.c","/domains/town/virtual/sky/27,7,1.c","/daemon/tmp/A_HELMET.c","/lib/player.c","/domains/amigara/room/passage26.c","/domains/campus/obj/abox.c","/secure/daemon/i3router/blacklist.cfg","/domains/town/armor/pants.c","/doc/lfun/all/SetFuelRequired","/shadows/ring.c","/save/kills/j/jeahiolgaka","/log/chan/archive/muds-2010.12.21-12.45,48","/secure/sefun/log_file.c","/doc/efun/all/map_delete","/save/kills/m/mkllal","/log/archive/runtime-2010.07.08-14.16,00","/secure/include/global.1111.h","/doc/applies/master/valid_bind","/log/chan/archive/i2news-2009.05.07-14.13,35","/log/chan/archive/muds-2010.08.21-21.45,48","/domains/amigara/room/passage20.c","/doc/efun/objects/find_object","/doc/lfun/all/GetSleeping","/secure/sefun/astar.c","/save/events.8888.o","/doc/help/races/poleepkwa","/log/chan/archive/intergossip-2010.08.30-00.45,48","/domains/town/room/orc_temple.c","/doc/efun/internals/swap","/doc/efun/all/opcprof","/doc/lfun/lib/body/CanWear","/log/chan/archive/muds-2009.03.22-16.10,24","/lib/steal.c","/secure/cmds/players/.tell.c.swp","/log/chan/archive/muds-2010.10.06-00.45,48","/domains/town/room/furnace.c","/verbs/items/include/remove.h","/lib/props/move.c","/save/kills/f/fbab","/news/locked","/secure/scripts/testmud.src","/daemon/tmp/S_LARGE.c","/doc/lfun/lib/body/GetMissingLimbParent","/log/chan/dchat","/save/kills/j/jmjeboi","/domains/town/obj/watch.c","/save/kills/k/kmdhjgncjm","/lib/include/stargate.h","/lib/events/look_in.c","/log/chan/archive/intergossip-2010.10.13-20.45,48","/log/chan/archive/intergossip-2009.03.22-22.11,20","/lib/virtual/virt_std.c","/doc/sefun/copy","/domains/default/npc/bat.c","/news/register","/include/vision.h","/verbs/items/include/extinguish.h","/save/kills/c/ckmko","/save/economy.8888.o","/log/archive/runtime-2010.07.09-07.16,00","/save/intermud.1111.o","/doc/efun/all/reclaim_objects","/log/chan/archive/muds-2013.08.29-08.13,15","/log/chan/archive/muds-2010.08.31-07.45,48","/doc/lfun/all/GetName","/doc/lfun/all/GetChannels","/log/chan/archive/muds-2010.08.30-00.45,48","/domains/default/room/wiz_corr1.c","/secure/sefun/mappings.c","/obj/sword.c","/log/chan/archive/mudnews-2013.08.04-13.13,15","/doc/lfun/all/GetMoJo","/log/chan/archive/muds-2009.05.09-19.58,26","/save/kills/x/xkcdmecfjabla","/domains/fort/obj/357round.c","/log/chan/archive/muds-2010.11.28-17.45,48","/log/chan/archive/muds-2009.05.08-12.58,26","/doc/lfun/lib/combat/eventReceiveDamage","/log/chan/archive/inews-2009.03.19-13.16,52","/save/kills/x/xkcdclfiaccf","/log/chan/archive/muds-2010.11.27-10.45,48","/secure/daemon/master.h","/log/chan/archive/sport-2013.08.01-12.13,15","/doc/lfun/lib/burn/CanBurn","/doc/lfun/all/eventMarry","/www/client/client.html","/doc/lfun/lib/flashlight/eventDie","/doc/lfun/lib/body/eventCompareLimbs","/secure/daemon/master.c","/log/icp","/daemon/tmp/ALL_DAMAGE.c","/log/chan/archive/muds-2009.03.24-18.17,31","/doc/efun/functions/evaluate","/save/stargate.3333.o","/lib/std/base_storage.c","/secure/include/daemons.h","/domains/campus/txt/jenny/13.txt","/doc/lfun/all/SetProtect","/log/chan/archive/imudnews-2009.03.25-15.11,20","/domains/fort/obj/safe_key.c","/save/books.1111.o","/domains/Praxis/adv_inner.c","/save/economy.o","/log/chan/archive/muds-2010.12.14-05.45,48","/domains/town/obj/toilet.c","/log/chan/archive/sport-2013.08.16-06.13,15","/secure/lib/net/server.c","/domains/fort/obj/magbox.c","/doc/lfun/all/GetPoison","/doc/lfun/all/SetClass","/doc/efun/strings/index","/secure/include/mssp.h","/doc/efun/all/to_float","/log/chan/archive/inews-2009.03.15-21.30,39","/domains/town/meals/bourbon.c","/domains/cave/armor/platemail.c","/save/kills/o/oahnm","/log/chan/archive/muds-2010.09.14-03.45,48","/save/kills/k/knaod","/domains/town/virtual/forest_map","/log/chan/archive/intergossip-2010.08.10-18.18,42","/doc/lfun/lib/clerk/performMarriage","/domains/town/room/docks.c","/log/chan/archive/muds-2010.11.19-10.45,48","/domains/fort/obj/dcell.c","/www/mudlist.txt","/domains/amigara/room/passage17.c","/domains/town/room/cave_entrance.c","/log/suicide","/log/chan/archive/muds-2010.10.23-06.45,48","/verbs/players/drive.c","/log/chan/archive/dchat-2010.12.01-11.45,48","/domains/campus/txt/jenny/3.txt","/lib/std/base_armor.c","/domains/town/obj/altar.c","/domains/cave/room/cavepass10.c","/log/chan/archive/muds-2010.11.06-16.45,48","/log/archive/runtime-2010.07.10-12.16,00","/doc/efun/all/to_int","/doc/efun/all/strlen","/save/kills/f/fjgdfakamjo","/domains/fort/obj/backpack_civilian.c","/daemon/tmp/50.c","/lib/flask.c","/domains/fort/room/alley.c","/save/kills/k/kgjn","/domains/Ylsrim/npc/max.c","/domains/amigara/room/passage11.c","/save/kills/d/dalklnia","/doc/BASICS","/daemon/tmp/B_QUADRUPED.c","/domains/town/npc/ingrid.c","/domains/fort/room/f_road32.c","/domains/campus/room/shaft0.c","/doc/efun/floats/sqrt","/secure/cmds/admins/unallow.c","/log/chan/archive/intergossip-2010.12.22-18.45,48","/doc/lfun/lib/abilities/GetSkills","/domains/cave/npc/orc_guard2.c","/doc/lfun/lib/body/GetMaxMagicPoints","/doc/efun/all/dump_prog","/lib/events/wear.c","/log/archive/i3error-2009.04.28-14.47,39","/doc/lfun/all/SetComposition","/shadows/pscout.c","/domains/town/room/magic_guild.c","/domains/fort/armor/glove_r.c","/doc/lfun/all/eventCheckHealing","/doc/sefun/ambassadorp","/domains/campus/obj/223clip.c","/cmds/creators/purge.c","/secure/daemon/.file.c.swp","/domains/default/armor/glove.c","/domains/Praxis/sun1.c","/save/kills/x/xkcdkdgdld","/domains/town/meals/potion_healing.c","/doc/lfun/all/eventBuy","/domains/town/virtual/forest/foo2","/secure/include/secrets.1111.h","/domains/fort/armor/glove_l.c","/domains/campus/obj/9mmround.c","/log/chan/archive/muds-2013.08.13-20.13,15","/domains/town/virtual/sky/26,7,1.c","/domains/fort/room/east_wall_3","/save/kills/l/ldndaahb","/secure/scripts/wtf.src","/lib/virtual/virt_subsurface.c","/domains/Ylsrim/armor/normal_helm.c","/secure/cfg/instance_template.cfg","/secure/cmds/creators/source.c","/log/chan/archive/dchat-2009.03.25-15.11,20","/log/chan/archive/muds-2010.11.21-22.45,48","/doc/efun/floats/asin","/log/chan/archive/intergossip-2009.04.29-18.11,41","/daemon/tmp/MOUTH_LIPPED+MOUTH_TOOTHED+MOUTH_TONGUED+MOUTH_FANGED+MOUTH_TUSKED.c","/domains/town/armor/jeans.c","/domains/town/room/hp.c","/daemon/skills.c","/domains/fort/room/quartermaster.c","/doc/applies/valid_link","/log/chan/archive/intergossip-2009.10.01-13.41,27","/domains/fort/room/f_road5.c","/log/archive/runtime-2010.07.08-13.16,00","/domains/fort/weap/dagger.c","/log/chan/archive/intergossip-2010.08.22-13.45,48","/domains/town/meals/fire.c","/domains/town/armor/.boot.c.swp","/log/chan/ievennia","/domains/Praxis/monastery.c","/doc/efun/all/set_living_name","/daemon/tmp/testyguy.c","/domains/amigara/room/oguard2.c","/secure/daemon/persistence.c","/log/chan/archive/muds-2013.08.23-06.13,15","/domains/campus/doors/blue_door2.c","/daemon/tmp/on.c","/log/chan/archive/muds-2010.10.31-19.45,48","/doc/lfun/all/GetLong","/log/chan/archive/intergossip-2013.08.06-13.13,15","/log/chan/archive/muds-2010.09.28-17.45,48","/verbs/items/listen.c","/log/chan/archive/muds-2009.04.29-18.11,41","/domains/campus/doors/top_stairs.c","/doc/lfun/lib/body/eventReceiveThrow","/doc/efun/all/time","/log/chan/archive/intergossip-2010.11.14-15.45,48","/domains/campus/weap/crowbar.c","/cmds/players/equipment.c","/domains/campus/obj/medbag.c","/include/damage_types.h","/log/archive/runtime-2010.07.09-06.16,00","/save/kills/f/foikjffglfl","/log/archive/catch-2009.03.15-18.30,39","/doc/efun/all/add_action","/lib/blank.c","/domains/town/weap/knife.c","/secure/include/parser_error.h","/log/chan/nakki","/log/chan/archive/muds-2010.08.22-13.45,48","/log/archive/runtime-2009.04.28-15.47,39","/doc/lfun/lib/npc/eventDestruct","/doc/lfun/all/GetLimbClass","/secure/npc/cambot.c","/domains/fort/obj/map.c","/doc/sefun/set_privs","/log/chan/free_speech","/log/chan/archive/muds-2010.09.05-23.45,48","/domains/fort/room/f_road29.c","/doc/lfun/lib/body/GetPacifist","/save/kills/x/xkcdlhle","/doc/lfun/lib/armor/SetFingers","/domains/Ylsrim/README.old","/doc/efun/calls/throw","/secure/include/global.2222.h","/save/kills/l/ln","/domains/fort/obj/plastic_bag.c","/domains/campus/room/access7.c","/cmds/players/plugh.c","/domains/campus/doors/eledoor2.c","/secure/cfg/races/mech","/save/kills/x/xkcdldlkflac","/log/chan/archive/inews-2013.08.12-20.13,15","/domains/fort/armor/peasant_pants.c","/domains/Ylsrim/etc/shovel.c","/doc/efun/all/eval_cost","/log/archive/runtime.boot-2009.04.26-23.43,06","/domains/campus/room/basement3.c","/save/kills/h/hhlhfhmjd","/lib/include/get.h","/domains/campus/armor/newbie_cap.c","/domains/campus/armor/foodsmock.c","/secure/cmds/admins/unrid.c","/doc/lfun/all/RemoveBonuses","/log/chan/archive/muds-2010.08.19-21.45,48","/domains/fort/room/f_road23.c","/log/chan/1","/log/archive/icp-2009.03.16-09.30,39","/domains/amigara/amigara/room/start.c","/domains/Praxis/stairs.c","/doc/lfun/all/SetSkillModifier","/log/chan/archive/muds-2010.09.28-03.45,48","/domains/town/save/0^0domains0^0town0^0room0^0secret.o","/secure/include/dirs.h","/log/chan/archive/muds-2010.09.19-10.45,48","/cmds/players/chan.c","/domains/fort/room/north_wall_5.c","/log/chan/archive/muds-2010.12.06-18.45,48","/domains/campus/room/access1.c","/domains/default/obj/locker.c","/domains/default/armor/breather.c","/domains/campus/armor/coat.c","/verbs/common/mail.c","/save/kills/h/hlgdgdik","/domains/town/room/thall.c","/secure/include/lib.h","/secure/daemon/filter.c","/log/chan/archive/muds-2010.09.15-09.45,48","/powers/spells/fireball.c","/doc/lfun/lib/burn/eventLight","/domains/Praxis/README","/domains/campus/doors/plain_door.test","/secure/cfg/races/vulcan","/domains/Praxis/forest3.c","/daemon/tmp/two.c","/doc/lfun/all/GetCharge","/secure/daemon/imc2.c","/log/chan/archive/muds-2013.08.07-06.13,15","/doc/lfun/all/GetHeartModifier","/log/chan/archive/muds-2010.09.01-08.45,48","/log/chan/archive/dgd-2009.04.02-17.51,27","/secure/cfg/races/bat","/log/chan/archive/dchat-2010.12.02-17.45,48","/domains/default/armor/pcannon.c","/daemon/tmp/MOUTH_TOOTHED+MOUTH_FANGED.c","/secure/scripts/sky.lsed","/verbs/items/include/throw.h","/log/chan/archive/muds-2013.07.30-23.13,15","/log/archive/runtime-2010.07.10-11.16,00","/include/combat_messages.h","/domains/town/obj/pipe.c","/daemon/tmp/DEFINES.c","/domains/fort/obj/dcell_std.c","/domains/fort/obj/waterwheel.c","/save/kills/e/emmij","/log/chan/archive/muds-2009.05.12-02.59,29","/doc/applies/interactive/receive_message","/log/chan/archive/intergossip-2013.08.23-19.13,15","/doc/efun/sockets/socket_error.h","/save/stargate.4444.o","/log/chan/archive/inews-2013.08.28-07.13,15","/doc/lfun/all/CanFly","/save/kills/j/jmncaginjf","/www/articles/copyright.html","/secure/tmp/dirs.txt","/domains/town/txt/shame/chapter05","/domains/fort/obj/spent.c","/daemon/bugs.c","/domains/town/txt/shame/chapter04","/save/books.2222.o","/log/chan/archive/intergossip-2009.04.01-11.51,27","/domains/town/txt/shame/chapter03","/domains/town/txt/shame/chapter02","/log/chan/archive/muds-2010.09.07-09.45,48","/log/chan/archive/muds-2009.04.26-23.43,06","/domains/town/txt/shame/chapter01","/doc/lfun/all/SetSleeping","/cmds/creators/quell.c","/secure/daemon/include/estates.h","/domains/fort/room/south_wall_5.c","/domains/fort/obj/h1n1.c","/domains/Praxis/obj/armour/helm.c","/secure/include/config.h","/save/kills/f/foo","/lib/events/sink.c","/domains/campus/txt/ai/charles/bak2/bak1/stays","/log/chan/archive/dchat-2010.12.07-11.45,48","/log/archive/runtime-2009.11.27-15.59,14","/domains/town/obj/50round.c","/domains/campus/armor/pillbox_hat.c","/doc/build/Properties","/domains/Praxis/idle_supply.c","/log/chan/archive/dchat-2010.09.17-09.45,48","/domains/fort/room/quarters1.c","/log/chan/archive/muds-2010.09.21-22.45,48","/save/kills/f/foa","/cmds/creators/wizvision.c","/log/chan/archive/muds-2009.04.10-06.28,44","/log/chan/archive/muds-2010.10.07-19.45,48","/secure/cmds/admins/addadverb.c","/save/kills/o/oboabiecbd","/domains/Praxis/alley2.c","/secure/cmds/admins/addraces.c","/domains/campus/obj/squirtbag.c","/log/archive/runtime-2009.09.22-14.04,12","/lib/pistol.c","/save/kills/x/xkcdajljekbjc","/lib/include/room.h","/domains/fort/room/pub.c","/domains/fort/obj/mlocker.c","/doc/lfun/lib/round/eventLoad","/doc/applies/master/privs_file","/log/chan/archive/dchat-2010.07.16-17.16,17","/save/kills/n/nlcfhimhl","/log/chan/archive/intergossip-2013.08.15-19.13,15","/domains/town/virtual/sky/25,7,1.c","/domains/town/obj/clip.c","/doc/efun/all/lpc_info","/doc/efun/all/query_shadowing","/log/chan/archive/intergossip-2013.08.14-12.13,15","/domains/fort/obj/canteen.c","/doc/help/creators/.instances.swp","/save/notify.o","/doc/sefun/base_name","/doc/efun/all/capitalize","/verbs/items/ring.c","/save/kills/x/xkcdfjegdlcdeb","/save/kills/k/kngalojgca","/cmds/creators/unquell.c","/save/kills/j/jldkke","/lib/donate.c","/log/archive/runtime-2010.07.09-19.16,00","/cmds/players/screen.c","/verbs/items/read.c","/lib/shell.c","/domains/town/room/clerk.c","/daemon/tmp/maintenance.c","/save/kills/c/cihkljjgeal","/log/chan/archive/muds-2010.08.31-19.45,48","/log/archive/runtime-2010.07.08-12.16,00","/log/archive/reset-2010.12.29-08.46,48","/log/chan/archive/muds-2010.08.30-12.45,48","/domains/fort/obj/omni.c","/domains/fort/obj/8ball.c","/doc/applies/interactive/logon","/doc/lfun/lib/body/eventCollapse","/domains/fort/npc/t2.c","/domains/default/obj/.223round.c.swp","/domains/Ylsrim/etc/stool.c","/log/chan/archive/muds-2010.09.13-22.45,48","/domains/fort/room/f_road14.c","/secure/daemon/imc2server/server.c","/log/chan/archive/intergossip-2010.09.14-15.45,48","/doc/lfun/all/CanMarry","/domains/Ylsrim/room/pub.c","/doc/efun/calls/query_shadowing","/log/chan/archive/intergossip-2010.09.05-22.45,48","/lib/events/put.c","/log/chan/archive/muds-2010.11.27-22.45,48","/domains/town/armor/wizard_hat.c","/doc/applies/get_save_file_name","/log/chan/archive/muds-2009.03.22-14.10,24","/doc/efun/sockets/socket_bind","/doc/lfun/all/returnChannels","/log/chan/archive/intergossip-2010.12.19-11.45,48","/domains/fort/room/furnace.c","/www/lpmuds/tmi2-faq.html","/log/chan/archive/mudnews-2013.08.19-19.13,15","/doc/lfun/all/GetRestrictedChannels","/lib/events/look.c","/domains/campus/save/charly.o","/log/chan/archive/muds-2010.10.30-11.45,48","/log/chan/archive/inews-2009.05.08-05.13,35","/log/chan/archive/intergossip-2010.10.23-18.45,48","/domains/default/obj/vial_orange.c","/secure/include/secrets.2222.h","/log/chan/archive/intergossip-2010.08.19-20.45,48","/log/chan/archive/muds-2010.11.13-21.45,48","/log/chan/archive/broken_gossip-2010.12.30-13.46,48","/log/chan/archive/sport-2013.08.24-04.13,15","/domains/town/weap/rod.c","/doc/efun/all/traceprefix","/log/archive/runtime-2010.07.09-05.16,00","/doc/sefun/alignment_ok","/log/chan/archive/intergossip-2010.07.29-16.17,46","/daemon/tmp/A_CLOAK.c","/log/chan/archive/muds-2011.01.10-16.46,13","/lib/include/bboard.h","/domains/amigara/amigara/room/ostorage.c","/log/errors/cmds","/log/chan/archive/muds-2010.09.14-15.45,48","/domains/campus/obj/357round.c","/domains/fort/doors/tailor.c","/cmds/players/spells.c","/secure/cfg/races/bear","/log/chan/archive/muds-2009.03.17-12.30,39","/domains/amigara/room/rats.c","/secure/cmds/creators/include/more.h","/save/kills/n/nnndkcojd","/secure/cmds/admins/groupmod.c","/lib/std/corpse.c","/lib/cigar.c","/save/kills/c/cnidmdjjk","/log/chan/archive/dchat-2010.07.25-09.16,48","/log/chan/archive/dgd-2013.07.30-21.13,15","/domains/fort/room/smithy.c","/doc/efun/all/flush_messages","/log/archive/i3error-2009.04.14-06.29,16","/domains/Praxis/storage.c","/log/chan/archive/dchat-2010.12.10-16.45,48","/secure/include/commands.h","/log/chan/archive/muds-2010.10.31-04.45,48","/log/chan/archive/intergossip-2010.10.15-18.45,48","/log/archive/icp-2009.03.16-08.30,39","/secure/verbs/creators/force.c","/lib/events/disarm.c","/doc/help/creators/instances","/log/chan/archive/muds-2010.12.05-10.45,48","/log/chan/archive/intergossip-2010.11.14-00.45,48","/daemon/tmp/mp.c","/log/chan/archive/sport-2013.08.07-11.13,15","/domains/Praxis/east_road1.c","/daemon/tmp/rifle.c","/domains/default/chamber/coffin.c","/secure/cfg/races/gargoyle","/log/chan/archive/inews-2013.08.18-20.13,15","/doc/efun/all/in_input","/tmp/resets","/cmds/creators/noclip.c","/verbs/rooms/include/cast.h","/obj/room.c","/lib/props/equip.c","/lib/include/nmsh.h","/save/kills/l/lnjjinjjmlk","/secure/cmds/builders/home.c","/obj/weapon.c","/log/chan/archive/muds-2010.11.28-01.45,48","/doc/lfun/all/UnrestrictChannel","/domains/default/room/vacuum.c","/domains/cave/obj/match.c","/save/kills/k/kdigmiki","/log/chan/archive/dchat-2010.12.24-23.46,44","/log/archive/i3error-2009.05.20-12.06,41","/secure/lib/net/http.c","/lib/std/bane.c","/secure/include/global.3333.h","/log/chan/archive/muds-2010.08.29-06.45,48","/save/kills/x/xkcdabljhf","/log/chan/archive/sport-2013.07.25-08.13,01","/secure/sefun/path_file.c","/domains/town/txt/warning_sign.txt","/log/chan/archive/muds-2011.01.07-10.46,13","/obj/container.c","/obj/bed.c","/log/chan/archive/muds-2013.07.30-22.13,15","/daemon/tmp/slymenstra.c","/log/archive/runtime-2010.07.10-10.16,00","/domains/town/armor/towel.c","/log/chan/archive/intergossip-2010.10.06-11.45,48","/lib/fuel.c","/domains/campus/doors/green_door2.c","/log/chan/archive/muds-2010.12.06-03.45,48","/save/kills/n/ngidlfdeh","/doc/lfun/lib/classes/SetSkillModifier","/doc/efun/mixed/classp","/doc/lfun/lib/burn/GetBurntValue","/cmds/creators/trans.c","/doc/lfun/lib/body/AddExtraChannels","/doc/lpc/concepts/heredoc","/doc/lfun/lib/battery/SetCharge","/log/chan/archive/dchat-2010.11.16-14.45,48","/daemon/help.c","/verbs/items/shoot.c","/save/kills/f/fkinibmjnf","/log/archive/runtime-2014.10.30-20.58,56","/domains/town/doors/m2.c","/doc/sefun/hour","/domains/fort/obj/spoon.c","/doc/sefun/format_page","/doc/sefun/moon_light","/doc/sefun/member_group","/domains/default/npc/chimera.c","/domains/fort/npc/fighter_wander.c","/doc/lfun/all/GetAlcohol","/cmds/creators/exits.c","/lib/chamber.c","/domains/town/txt/hints_sign.txt","/domains/Praxis/s_centre4.c","/domains/town/meals/poison.c","/daemon/soul.c","/secure/cmds/creators/ls.c","/log/chan/archive/dchat-2011.01.04-16.46,13","/verbs/items/include/lock.h","/domains/amigara/room/passage4.c","/log/chan/archive/intergossip-2013.08.28-12.13,15","/lib/include/teacher.h","/lib/include/burn.h","/save/intermud.3333.o","/domains/Praxis/mage_hall.c","/secure/scripts/distclean.src","/domains/fort/weap/cue.c","/domains/Praxis/quests/evil.c","/daemon/tmp/BLADE.c","/daemon/tmp/testymage.c","/doc/build/Armours","/save/kills/h/hgmnbkkk","/log/chan/archive/sport-2009.03.28-17.14,40","/domains/campus/obj/pedestal3.c","/www/lpmuds/intermud_files/style.css","/log/archive/runtime-2009.09.22-13.04,12","/www/lpmuds/links.html","/log/chan/archive/muds-2010.11.06-00.45,48","/domains/fort/obj/spam.c","/doc/lfun/all/SetStats","/doc/help/players/wrapping","/lib/messages.c","/domains/town/doors/stone.c","/secure/cmds/creators/tail.c","/save/kills/f/fia","/verbs/items/pick.c","/secure/lib/file.c","/domains/fort/room/bank.c","/domains/fort/armor/mhelmet.c","/domains/town/armor/breather.c","/verbs/players/sleep.c","/lib/shadow.c","/domains/fort/obj/pedestal.c","/save/stargate.5555.o","/log/chan/archive/muds-2010.12.13-23.45,48","/domains/default/armor/horc_shirt.c","/log/chan/archive/intergossip-2010.12.23-09.45,48","/lib/events/lock_with.c","/doc/lfun/lib/body/SetPacifist","/domains/Praxis/supply.c","/log/archive/runtime-2010.07.09-18.16,00","/domains/town/npc/oana.c","/domains/fort/obj/backpack_empty.c","/domains/campus/obj/dcell.c","/domains/campus/obj/.backpack_empty.c.swp","/domains/town/armor/vest.c","/domains/fort/armor/bearskin.c","/doc/efun/all/inherits","/log/chan/archive/muds-2013.08.29-19.13,15","/log/archive/runtime-2010.07.08-11.16,00","/doc/help/creators/grid","/save/books.3333.o","/doc/efun/interactive/notify_fail","/domains/default/npc/slug.c","/daemon/tmp/A_SHIRT.c","/doc/help/players/channels","/log/chan/archive/ichat-2009.05.13-19.59,29","/verbs/items/equate.c","/secure/sefun/interface.c","/secure/include/flags.h","/log/chan/archive/muds-2009.05.08-23.58,26","/domains/fort/doors/plain_door.c","/log/chan/archive/i2news-2009.03.28-14.11,36","/save/kills/x/xkcdnhilcbah","/secure/cfg/mudos.2222.cfg","/log/chan/archive/intergossip-2009.03.17-11.30,39","/domains/town/obj/slip_regenerate.c","/doc/efun/functions/index","/domains/Ylsrim/adm/void.c","/save/kills/m/mmmgee","/doc/efun/filesystem/file_length","/domains/Praxis/cemetery/grave_yard8.c","/doc/lpc/constructs/include","/domains/Praxis/sage_room.c","/shadows/bear.c","/save/kills/l/lbfgddeki","/domains/Ylsrim/npc/segata.c","/domains/town/virtual/sky/19,8,1.c","/log/chan/archive/muds-2009.04.02-03.51,27","/doc/lfun/lib/player/eventDie","/save/kills/x/xkcdagkhmkajgd","/doc/efun/filesystem/rename","/log/chan/archive/muds-2010.09.19-22.45,48","/log/chan/archive/muds-2010.11.22-13.45,48","/doc/applies/receive_message","/log/chan/archive/muds-2010.12.14-16.45,48","/cfg/timezones.cfg","/verbs/items/free.c","/secure/scripts/crat2.src","/domains/town/room/mansion_room4.c","/domains/fort/weap/axe.c","/domains/campus/armor/overalls.c","/domains/default/armor/scoutsuit.c","/domains/fort/weap/zpem.c","/domains/Ylsrim/npc/balrog.c","/log/archive/runtime-2010.07.09-04.16,00","/domains/Praxis/cemetery/grave_yard2.c","/secure/include/network.1111.h","/log/chan/archive/inews-2009.03.31-01.51,27","/domains/campus/room/corridor3.c","/save/kills/x/xkcdhaihahm","/lib/interactive.c","/save/kills/x/xkcdfihhbjik","/save/kills/a/acnbdao","/doc/efun/all/inherit_list","/save/kills/k/klicankao","/daemon/tmp/A_SHIELD.c","/secure/include/secrets.h","/log/chan/archive/sport-2009.10.03-17.41,27","/lib/include/key.h","/doc/lfun/lib/firearm/GetCaliber","/www/articles/mudmagic.html","/log/mssp","/save/kills/t/three","/save/kills/l/longec","/log/chan/archive/intergossip-2010.10.29-18.45,48","/log/chan/archive/imudnews-2010.08.11-22.18,42","/secure/cfg/races/plant","/log/archive/catch-2009.05.20-15.39,16","/doc/lfun/lib/classes/ClassMember","/doc/efun/buffers/index","/doc/applies/master/get_save_file_name","/domains/cave/room/cavepass6.c","/domains/default/armor/wizard_hat.c","/save/kills/m/mcenhknc","/domains/campus/room/spath.c","/doc/efun/internals/dump_prog","/doc/efun/all/rename","/log/chan/archive/inews-2009.04.01-17.51,27","/doc/lpc/concepts/simul_efun","/secure/cmds/creators/monitor.c","/log/chan/archive/dchat-2010.09.15-21.45,48","/domains/fort/npc/test5","/save/kills/x/xkcdiddkkd","/lib/.command.c.swp","/domains/fort/npc/test3","/domains/fort/npc/test2","/doc/efun/all/exp","/log/archive/icp-2009.03.16-07.30,39","/log/chan/archive/intergossip-2009.03.24-19.11,20","/lib/comp/holder.c","/domains/Praxis/obj/mon/knight.c","/log/currency","/log/chan/archive/muds-2010.12.14-02.45,48","/lib/.potion.c.swp","/domains/default/obj/cheatbook.c","/domains/campus/obj/redbox.c","/log/chan/archive/muds-2009.03.11-22.02,51","/secure/cmds/creators/pwd.c","/news/hm","/log/chan/serenity","/domains/fort/room/cell4.c","/domains/fort/obj/needle_trap3.c","/verbs/items/drop.c","/secure/include/secrets.3333.h","/domains/alpha/room/death.c","/log/chan/archive/muds-2010.08.23-04.45,48","/secure/cmds/creators/which.c","/log/chan/archive/muds-2010.09.06-14.45,48","/domains/default/npc/quarantine/ted.c","/doc/lfun/all/eventCompleteHeal","/log/chan/archive/muds-2010.11.29-07.45,48","/save/kills/o/ollb","/doc/efun/strings/terminal_colour","/secure/include/secrets.1","/lib/include/put.h","/domains/campus/room/sub_basement1.c","/daemon/tmp/orisir.c","/cmds/admins/dumpallobj.c","/domains/campus/txt/jenny/spiel.txt","/log/chan/archive/broken_gossip-2010.12.28-13.46,48","/domains/cave/armor/chainmail_collar.c","/domains/Praxis/obj/mon/goblin_fighter.c","/domains/town/obj/stove.c","/log/chan/archive/muds-2009.04.10-18.28,44","/domains/default/room/arena.c","/domains/campus/obj/9mmbox.c","/secure/cmds/admins/removeclasses.c","/domains/campus/obj/workbench.c","/log/chan/archive/muds-2011.01.08-16.46,13","/log/TrainingPoints","/domains/default/armor/.pcannon.c.swp","/save/kills/g/gani","/log/chan/archive/discworld-chat-2010.08.06-15.18,42","/domains/campus/room/start.c","/domains/town/obj/lockpick.c","/domains/campus/txt/ai/charly/bak/fgreen","/www/lpmuds/arren_router.html","/save/kills/x/xkcdafdffk","/doc/lfun/lib/bonus/RemoveBonuses","/secure/lib/net/h_ftpd.c","/log/chan/archive/imudnews-2010.11.09-06.45,48","/save/kills/c/ccbcenandk","/doc/lfun/lib/classes/GetClan","/domains/fort/obj/stick.c","/save/kills/k/khgfcdkc","/secure/daemon/bboard.h","/domains/Ylsrim/etc/church_button.c","/log/chan/archive/intergossip-2013.08.22-10.13,15","/domains/town/room/forest_well1.c","/cmds/creators/return.c","/verbs/common/body.c","/secure/daemon/bboard.c","/log/chan/archive/dchat-2011.01.09-23.46,13","/include/soul.h","/domains/town/virtual/sky/28,3,1.c","/domains/cave/obj/skin.c","/log/chan/archive/muds-2010.10.10-09.45,48","/secure/daemon/i3router/send_chanlist_reply.h","/log/archive/catch-2010.07.11-13.16,09","/doc/help/creators/config","/doc/lfun/all/GetSacrificeType","/daemon/include/stargate.h","/log/chan/archive/muds-2010.10.29-04.45,48","/lib/creator.c","/domains/campus/npc/jennybot.c","/domains/town/room/bridge.c","/domains/default/weap/.m16rifle.c.swp","/doc/sefun/reverse_string","/domains/default/npc/minotaur.c","/domains/Praxis/mudlib.c","/save/kills/o/ofkf","/lib/include/chapel.h","/log/archive/i3error-2009.05.06-16.13,35","/domains/campus/adm/cache.c","/doc/efun/all/test_bit","/domains/campus/txt/ai/charles/bak2/bak1/fgreen","/save/kills/c/cigcdaa","/log/chan/archive/muds-2009.04.10-04.28,44","/domains/campus/room/monty.c","/doc/efun/all/refs","/doc/sefun/mudlib_version","/log/chan/archive/muds-2011.01.08-02.46,13","/domains/town/obj/45round.c","/log/chan/archive/muds-2013.07.31-14.13,15","/log/archive/runtime-2011.08.20-08.02,55","/doc/efun/floats/log","/doc/help/creators/creator","/cmds/creators/praces.c","/lib/include/trap.h","/include/rounds.h","/domains/cave/armor/armored_boot_r.c","/secure/include/global.4444.h","/domains/town/room/riverbank.c","/doc/efun/all/fetch_variable","/secure/cfg/classes/mage","/save/kills/f/fkdhgiig","/doc/lfun/lib/body/AddExperiencePoints","/log/chan/archive/muds-2010.10.30-23.45,48","/doc/lfun/lib/classes/GetReligion","/domains/fort/obj/match.c","/save/kills/f/foalga","/domains/town/obj/pole.c","/doc/sefun/objective","/verbs/items/unwield.c","/log/chan/archive/discworld-chat-2010.12.04-14.45,48","/doc/efun/all/call_other","/domains/town/room/cave1.c","/doc/lfun/lib/door/GetLong","/log/chan/archive/dchat-2010.11.08-13.45,48","/log/chan/archive/intergossip-2010.09.19-21.45,48","/domains/fort/obj/donation_box.c","/domains/cave/npc/orc_female1.c","/save/kills/g/gof","/doc/lfun/all/SetLeader","/save/kills/x/xkcdfdn","/secure/include/council.h","/log/archive/runtime-2010.07.09-17.16,00","/domains/campus/txt/ai/charly/switches","/domains/cave/armor/armored_boot_l.c","/save/kills/x/xkcdhdfnad","/doc/lpc/concepts/sefun","/log/chan/archive/muds-2013.08.28-11.13,15","/domains/amigara/amigara/room/cave.c","/log/chan/archive/intergossip-2010.08.23-17.45,48","/save/kills/a/aa","/domains/Ylsrim/etc/match.c","/domains/Praxis/attic/tmp_hos","/domains/town/room/healer2.c","/domains/Praxis/obj/misc/stargate.c","/log/chan/archive/muds-2009.09.30-21.41,27","/save/kills/c/cmemfhm","/save/kills/x/xkcdjkoole","/save/kills/e/eobchaahkol","/domains/cave/weap/.dagger.c.swp","/secure/daemon/imc2server/1.c","/save/kills/i/imaa","/domains/cave/obj/food_storage1_key.c","/domains/Ylsrim/save/roshd.o","/doc/efun/sockets/socket_address","/doc/efun/all/max_eval_cost","/doc/efun/all/find_living","/doc/efun/all/shutdown","/domains/campus/doors/u_door.c","/doc/.CREDITS.swp","/domains/Praxis/post.c","/www/hotfix.html","/domains/campus/room/furnace.c","/save/kills/g/gnn","/save/intermud.4444.o","/domains/campus/obj/spent.c","/log/chan/archive/intergossip-2013.08.07-17.13,15","/domains/town/virtual/sky/18,8,1.c","/domains/campus/txt/ai/charles/stays","/log/chan/archive/muds-2011.01.02-00.46,48","/doc/lfun/lib/limb/CanReceive","/domains/town/npc/herkimer.c","/daemon/tmp/start.c","/cmds/players/enemies.c","/log/archive/runtime-2010.07.09-03.16,00","/domains/town/obj/needle_trap.c","/secure/scripts/missile.src","/doc/lfun/lib/container/CanReceive","/doc/lfun/lib/clan/CanJoin","/doc/efun/all/shallow_inherit_list","/save/stargate.6666.o","/log/chan/archive/muds-2010.09.23-06.45,48","/doc/lfun/all/eventBurnOut","/domains/cave/room/cavetroll.c","/doc/lfun/all/GetBurnRate","/save/books.4444.o","/doc/lfun/all/GetClanObject","/save/kills/x/xkcdcceiilc","/domains/town/obj/bin.c","/domains/campus/weap/sword.c","/lib/body.c","/daemon/party.c","/log/chan/ichat","/doc/efun/mappings/m_delete","/domains/fort/obj/pebble.c","/log/chan/archive/muds-2010.08.29-18.45,48","/shadows/arbiter.c","/log/chan/archive/muds-2010.10.23-16.45,48","/log/archive/runtime-2009.07.20-22.13,25","/log/chan/archive/muds-2010.08.28-11.45,48","/log/archive/icp-2009.03.16-06.30,39","/daemon/tmp/MOUTH_STATIC.c","/save/kills/x/xkcdjjbl","/domains/fort/obj/round.c","/domains/town/room/shop2.c","/save/kills/j/jgamd","/log/errors/fort","/doc/help/players/password","/daemon/tmp/monty.c","/domains/default/room/menagerie_south.c","/doc/help/races/prawn","/doc/efun/objects/deep_inventory","/secure/sefun/load_object.c","/domains/fort/obj/bag.c","/doc/efun/system/memory_summary","/lib/chat.c","/domains/fort/armor/foodsmock.c","/domains/campus/obj/bluebox.c","/log/chan/archive/intergossip-2009.03.12-14.02,51","/log/chan/archive/inews-2013.08.27-11.13,15","/domains/default/npc/elephant.c","/doc/efun/filesystem/tail","/secure/sefun/compare_array.c","/save/kills/b/bcblh","/secure/include/config.prime","/save/kills/a/aedlhblcf","/secure/cmds/admins/domaincreate.c","/log/chan/archive/muds-2011.01.10-00.46,13","/log/chan/archive/muds-2010.10.29-17.45,48","/domains/town/virtual/sky/21,10,1.c","/doc/lfun/lib/clip/CanReceive","/secure/cmds/admins/chanunban.c","/save/kills/k/kbcjckcngnn","/lib/events/aim.c","/domains/campus/npc/charly.c","/log/chan/archive/dchat-2010.12.07-22.45,48","/log/chan/archive/muds-2010.10.28-10.45,48","/doc/lfun/all/AddMagicPoints","/secure/include/network.2222.h","/save/kills/x/xkcdfao","/domains/fort/obj/church_button.c","/doc/lfun/lib/body/AddCaffeine","/doc/cheats/chapter07","/log/chan/archive/broken_gossip-2010.12.29-19.46,48","/doc/cheats/chapter06","/save/kills/x/xkcdfdngnbdl","/log/chan/archive/intergossip-2010.08.01-21.18,42","/domains/alpha/room/furnace.c","/doc/cheats/chapter05","/doc/cheats/chapter04","/log/archive/catch-2011.08.21-11.04,13","/domains/fort/armor/crimson_helmet.c","/doc/cheats/chapter03","/doc/cheats/chapter02","/daemon/tmp/A_GLOVE.c","/doc/cheats/chapter01","/verbs/creators/resurrect.c","/doc/sefun/convert_ascii","/log/chan/archive/dchat-2010.10.10-22.45,48","/doc/sefun/possessive","/doc/lpc/types/float","/log/chan/archive/intercre-2010.09.25-13.45,48","/save/kills/d/dkffbebeli","/doc/efun/all/remove_shadow","/secure/cmds/admins/unregister.c","/verbs/creators/echo.c","/secure/cmds/admins/cconv.c","/domains/town/room/narrow_path2.c","/domains/default/armor/ring_fencing.c","/domains/Praxis/inn110.c","/www/lpmuds/forum-faq.html","/www/articles/patches.html","/log/chan/archive/muds-2010.11.15-05.45,48","/log/chan/archive/muds-2009.03.23-11.11,20","/domains/fort/armor/boot.c","/doc/lfun/lib/body/AddMagicPoints","/verbs/items/smoke.c","/save/kills/n/nfkn","/domains/town/room/forest_path1.c","/domains/Praxis/party.c","/www/cgi/creweb.c","/domains/Ylsrim/npc/traveler.c","/cmds/players/i3locate.c","/secure/lib/std/access.c","/domains/fort/armor/hunting_cap.c","/secure/cmds/builders/areaclone.c","/log/archive/runtime-2009.04.26-17.05,53","/domains/Ylsrim/npc/roshd.c","/verbs/items/turn.c","/log/chan/archive/sport-2009.03.25-17.11,20","/log/chan/archive/intergossip-2009.04.02-15.51,27","/doc/help/players/handbook","/domains/default/room/quarantine2.c","/doc/lfun/lib/clip/GetAmmoType","/save/kills/f/fklnblmlgg","/log/chan/archive/muds-2010.12.21-21.45,48","/doc/lfun/all/SetBonuses","/log/chan/archive/muds-2010.11.01-04.45,48","/doc/bguide/chapter08","/save/kills/x/xkcdoaggo","/log/chan/archive/discworld-chat-2013.08.28-09.13,15","/doc/bguide/chapter07","/doc/bguide/chapter06","/log/archive/runtime-2010.07.08-23.16,00","/log/archive/runtime-2009.05.24-13.21,49","/domains/Praxis/orc_valley/chamber2.c","/doc/bguide/chapter05","/lib/.missile.c.swp","/doc/bguide/chapter04","/secure/include/secrets.4444.h","/doc/bguide/chapter03","/doc/bguide/chapter02","/doc/bguide/chapter01","/doc/sefun/mud_name","/lib/include/search.h","/cmds/creators/realms.c","/www/ds-creator-faq.html","/log/chan/archive/inews-2013.08.05-10.13,15","/verbs/players/include/,nominate.h","/daemon/seasons.c","/verbs/builders/pulsecheck.c","/log/chan/archive/intergossip-2010.09.22-12.45,48","/domains/cave/room/guardroom1.c","/domains/campus/txt/jenny/8.txt","/save/kills/g/ggelbkdbo","/domains/learning/room/furnace.c","/daemon/tmp/bridge.c","/domains/cave/npc/orc_soldier2.c","/log/chan/archive/muds-2010.11.07-05.45,48","/secure/include/rcp.h","/log/chan/archive/muds-2013.08.23-16.13,15","/log/chan/archive/muds-2010.08.15-17.45,20","/domains/cave/weap/battleaxe.c","/shadows/diag.c","/log/author_stats","/domains/town/virtual/sky/22,7,1.c","/doc/efun/interactive/enable_wizard","/domains/amigara/amigara/room/passage8.c","/log/chan/archive/intergossip-2010.07.21-20.16,17","/secure/obj/robot.c","/log/chan/archive/intergossip-2010.10.31-15.45,48","/save/kills/g/gihockeeef","/log/chan/archive/muds-2010.09.27-20.45,48","/log/chan/archive/dchat-2010.11.09-19.45,48","/domains/campus/obj/pedestal.c","/doc/lfun/lib/clan/eventJoin","/domains/fort/armor/crimson_cloak.c","/log/chan/archive/dchat-2009.04.13-17.29,16","/cmds/players/wimpy.c","/log/chan/archive/muds-2010.10.01-01.45,48","/domains/default/npc/quarantine/duncan.c","/doc/efun/all/livings","/daemon/tmp/LIB_CREATOR.c","/save/parties.6666.o","/log/archive/runtime-2010.07.09-16.16,00","/domains/Ylsrim/room/sand_hole.c","/doc/lfun/lib/flashlight/eventUse","/domains/fort/room/dairy.c","/doc/efun/interactive/remove_action","/lib/chario.c","/domains/town/npc/orc_boss.c","/domains/Praxis/mage_vote.c","/doc/sefun/first_string_element","/std/virtual_void.txt","/domains/fort/room/gstreet4.c","/domains/amigara/amigara/room/passage2.c","/doc/lfun/lib/clip/SetMillimeter","/domains/campus/weap/waterpistol.c","/doc/lfun/all/GetFood","/save/services.o","/secure/daemon/i3router/read_callback.h","/log/chan/archive/intergossip-2010.11.29-19.45,48","/domains/campus/obj/ped_button.c","/log/chan/broken_gossip","/lib/props/mass.c","/cmds/players/chancolors.c","/save/kills/l/llfdmdo","/secure/daemon/i3router/broadcast_chanlist.h","/domains/town/armor/leather_armor.c","/domains/campus/meals/wimp_ale.c","/doc/efun/all/copy","/obj/quest_ob.c","/domains/town/armor/belt.c","/cmds/players/speakcolor.c","/domains/town/virtual/sky/17,8,1.c","/doc/lfun/lib/body/GetWorn","/log/chan/archive/intergossip-2010.09.01-18.45,48","/domains/fort/obj/chest2.c","/verbs/rooms/include/go.h","/log/chan/archive/muds-2010.09.28-13.45,48","/domains/Praxis/inn107.c","/doc/lpc/types/function","/secure/tmp/files.txt","/log/chan/archive/muds-2010.12.23-07.45,48","/log/chan/archive/muds-2009.10.02-16.41,27","/lib/events/buy.c","/secure/include/global.5555.h","/log/chan/archive/intergossip-2009.05.13-19.59,29","/log/bank","/lib/events/smell.c","/lib/std/armor.c","/lib/race.c","/log/chan/archive/intergossip-2009.05.12-12.59,29","/lib/std/limb.c","/log/chan/aleph","/doc/efun/all/ctime","/www/barrel.html","/verbs/players/include/stealth.h","/log/archive/runtime-2010.07.09-02.16,00","/log/chan/archive/imudnews-2010.08.26-09.45,48","/save/kills/i/ioohl","/lib/include/interactive.h","/doc/lfun/lib/corpse/GetRace","/log/chan/archive/intergossip-2013.07.29-00.13,15","/verbs/rooms/stop.c","/log/chan/archive/imudnews-2010.09.09-19.45,48","/domains/default/npc/yattering.c","/domains/campus/room/maintenance.c","/save/kills/l/labbemk","/log/chan/archive/muds-2009.03.18-16.30,39","/domains/fort/armor/badge.c","/domains/Praxis/inn101.c","/secure/tmp/kalinash_CMD_EVAL_TMP_FILE.c","/save/kills/h/hdned","/save/kills/x/xkcdddgofbk","/domains/town/doors/otik_d.c","/log/archive/runtime-2009.03.20-14.16,52","/domains/town/doors/gate.c","/log/chan/dreamverse_gossip","/doc/lfun/all/RemoveChannel","/log/chan/ichat2","/log/chan/archive/muds-2013.08.16-09.13,15","/save/kills/k/kmnbllnlb","/domains/default/obj/bguide.c","/doc/efun/all/deep_inventory","/doc/efun/all/message","/doc/efun/interactive/remove_interactive","/verbs/items/show.c","/secure/cfg/races/android","/daemon/tmp/testylus.c","/domains/amigara/amigara/room/freezer.c","/log/archive/runtime-2010.07.10-21.16,00","/log/archive/icp-2009.03.16-05.30,39","/daemon/tmp/tobylus.c","/save/kills/g/gkacgam","/log/chan/archive/muds-2010.11.14-11.45,48","/log/chan/archive/muds-2010.12.15-07.45,48","/domains/town/armor/cloak.c","/log/chan/archive/muds-2009.05.12-12.59,29","/log/archive/reset-2013.08.29-07.13,15","/domains/fort/obj/bbucket.c","/domains/fort/room/west_wall_6.c","/doc/lfun/all/AddExperiencePoints","/domains/default/obj/collarchest.c","/doc/sefun/event_pending","/doc/efun/all/functions","/doc/efun/all/disable_commands","/log/chan/archive/muds-2013.08.01-01.13,15","/secure/cmds/admins/unpause.c","/domains/campus/obj/tlocker.c","/domains/cave/obj/mug.c","/doc/efun/all/functionp","/doc/sefun/high_mortalp","/log/chan/archive/muds-2010.09.07-19.45,48","/doc/efun/all/set_author","/domains/Praxis/library.c","/domains/campus/txt/ai/charly/red_wins","/domains/default/npc/spider.c","/doc/lfun/lib/firearm/SetCaliber","/doc/help/players/player_general","/log/archive/catch-2011.08.21-10.04,13","/doc/efun/objects/set_heart_beat","/domains/fort/room/east.c","/domains/fort/doors/tanner.c","/domains/cave/obj/lever.c","/cmds/creators/findobj.c","/daemon/phys.c","/doc/efun/all/filter_mapping","/doc/lfun/lib/classes/SetReligion","/doc/efun/mudlib/seteuid","/log/chan/archive/muds-2010.10.23-01.45,48","/save/kills/x/xkcdchgmem","/doc/lfun/lib/body/GetCapName","/daemon/tmp/A_COLLAR.c","/domains/fort/obj/lockpick.c","/domains/campus/weap/zpem.c","/doc/lfun/lib/body/GetName","/log/chan/archive/inews-2013.07.28-14.13,15","/doc/lfun/lib/body/GetResistance","/doc/lfun/lib/body/GetMoJo","/domains/learning/room/start.c","/domains/examples/room/README","/doc/lpc/concepts/efun","/verbs/items/give.c","/secure/daemon/letters.h","/secure/cfg/races/rodent","/log/chan/archive/dchat-2010.11.16-11.45,48","/secure/daemon/letters.c","/save/kills/l/lbiacg","/log/chan/archive/muds-2010.09.07-05.45,48","/secure/cfg/races/ape","/log/chan/archive/muds-2011.01.11-05.46,55","/domains/campus/armor/handbag.c","/doc/applies/make_path_absolute","/doc/efun/all/sprintf","/log/archive/runtime-2010.07.08-22.16,00","/log/archive/instances-2009.03.16-14.30,39","/secure/include/localtime.h","/doc/efun/all/virtualp","/secure/cmds/creators/dsversion.c","/save/kills/d/dolhhibfenl","/save/books.o","/log/chan/archive/intergossip-2010.08.31-15.45,48","/domains/campus/armor/ring1.c","/secure/cmds/creators/rmdir.c","/daemon/tmp/BLUNT.c","/secure/cfg/races/god","/save/kills/g/gef","/log/chan/archive/muds-2009.04.11-09.28,44","/secure/include/network.3333.h","/doc/applies/master/valid_save_binary","/domains/amigara/amigara/room/passage23.c","/daemon/tmp/A_VEST.c","/doc/efun/all/previous_object","/log/chan/archive/muds-2009.04.10-02.28,44","/doc/lfun/lib/spell/SetSkills","/doc/lfun/lib/round/GetCaliber","/log/chan/archive/muds-2011.01.09-07.46,13","/domains/campus/weap/board.c","/log/chan/archive/inews-2009.10.02-09.41,27","/log/chan/archive/discworld-chat-2010.07.21-18.16,17","/save/kills/c/chaijaalkd","/tmp/thingy.txt","/doc/efun/strings/sprintf","/verbs/creators/codesay.c","/domains/amigara/room/ocommhall.c","/save/kills/m/mcmgjgkk","/domains/default/creator/workroom.c","/log/chan/gamma","/lib/virtual/virt_sky.c","/domains/fort/room/msquare.c","/domains/cave/obj/cask5.c","/cmds/creators/inherits.c","/save/kills/x/xkcdgclho","/save/mudinfo.o","/domains/default/npc/snake.c","/www/lpmuds/style.css","/save/kills/t/testylus","/domains/fort/room/tunnel5.c","/www/lpmuds/mudfarm.html","/save/kills/m/mmjloojfa","/doc/sefun/date","/log/chan/archive/intergossip-2010.11.23-17.45,48","/log/catch","/daemon/services/channel.c","/log/chan/archive/muds-2010.12.22-13.45,48","/doc/lfun/lib/battery/GetCharge","/log/chan/archive/sport-2013.08.24-14.13,15","/log/chan/archive/muds-2010.12.13-20.45,48","/log/chan/archive/intercre-2009.05.15-12.59,29","/log/chan/archive/intergossip-2009.10.02-15.41,27","/domains/town/room/death.c","/doc/lfun/all/SetBurnRate","/cmds/creators/callouts.c","/doc/efun/calls/previous_object","/log/chan/archive/intergossip-2010.12.14-13.45,48","/log/archive/runtime-2010.07.09-15.16,00","/domains/fort/room/storeroom3.c","/domains/fort/obj/wlocker.c","/verbs/rooms/include/sell.h","/lib/events/.fall.c.swp","/log/chan/archive/muds-2013.07.28-20.13,15","/domains/campus/room/science6.c","/domains/Ylsrim/room/kaliid7.c","/log/chan/archive/muds-2013.08.29-16.13,15","/domains/Praxis/quests/orcslayer.c","/doc/efun/interactive/commands","/verbs/items/wield.c","/log/chan/archive/muds-2010.09.22-11.45,48","/daemon/tmp/pager.c","/shadows/needle_trap2.c","/domains/Praxis/council.c","/www/cgi/save.c","/secure/include/secrets.5555.h","/save/kills/d/dfigmlg","/domains/cave/obj/letter2.c","/domains/campus/doors/red_door2.c","/log/chan/archive/sport-2013.08.10-13.13,15","/news/priest","/domains/fort/obj/slip_excise.c","/log/chan/archive/muds-2010.10.07-01.45,48","/domains/examples/room/exroom6.c","/log/chan/archive/muds-2010.12.19-21.45,48","/log/chan/archive/intergossip-2010.11.28-11.45,48","/log/archive/i3error-2009.05.16-05.59,29","/daemon/tmp/B_SEMI_BIPEDAL.c","/doc/efun/all/save_variable","/secure/daemon/i3router/hosted_channels.h","/save/kills/h/hok","/domains/town/npc/rat.c","/save/kills/i/icjkb","/log/chan/archive/muds-2010.10.31-14.45,48","/log/chan/archive/muds-2010.09.29-19.45,48","/log/chan/archive/intergossip-2013.08.15-01.13,15","/domains/fort/room/mstreet4.c","/domains/Praxis/hall3.c","/doc/lfun/lib/fishing/CanRelease","/daemon/services/finger.c","/log/archive/runtime-2009.05.20-15.39,16","/daemon/tmp/mansion_uhall1.c","/log/chan/archive/muds-2009.05.22-17.21,24","/domains/town/armor/shirt.c","/domains/town/obj/scroll_raise_dead.c","/domains/fort/room/common14.c","/domains/Praxis/obj/weapon/sword.c","/doc/efun/all/pointerp","/verbs/players/cast.c","/log/chan/archive/muds-2013.08.10-07.13,15","/cmds/creators/stargate.c","/lib/mount.c","/domains/default/npc/pessis.c","/doc/efun/filesystem/stat","/log/archive/runtime-2010.07.09-01.16,00","/save/kills/b/bklmkbeod","/log/chan/archive/muds-2010.08.23-15.45,48","/doc/efun/interactive/snoop","/log/chan/archive/muds-2010.08.31-01.45,48","/news/welcome","/domains/fort/room/bwall3.c","/doc/lfun/lib/limb/GetRace","/log/chan/archive/muds-2010.10.28-22.45,48","/log/archive/catch-2009.07.12-10.57,13","/log/chan/archive/muds-2013.07.24-19.13,01","/cmds/creators/types.c","/log/archive/runtime-2010.07.07-21.15,58","/log/chan/archive/intergossip-2010.11.01-16.45,48","/domains/town/obj/dcell_good.c","/doc/efun/all/socket_connect","/log/chan/archive/inews-2014.09.20-15.08,45","/log/runtime.boot","/log/archive/runtime-2009.03.16-09.30,39","/domains/cave/room/common1.c","/domains/Ylsrim/virtual/server.c","/doc/lfun/all/GetWieldingLimbs","/domains/examples/room/exroom2a.c","/lib/clerk.c","/domains/fort/armor/sunhat.c","/domains/campus/obj/match.c","/secure/include/function.h","/log/chan/archive/dchat-2010.09.24-11.45,48","/lib/clay.c","/doc/lfun/all/AddAlcohol","/log/reports/network_connect","/log/chan/archive/muds-2010.09.01-17.45,48","/secure/sefun/get_object.c","/domains/town/armor/orc_helmet.c","/doc/lfun/lib/clip/eventLoad","/daemon/tmp/A_CUSTOM.c","/log/chan/lpuni","/log/chan/archive/muds-2010.11.15-17.45,48","/doc/lpc/concepts/defines","/log/archive/icp-2009.03.16-04.30,39","/doc/applies/write_prompt","/domains/fort/room/bpath1.c","/domains/fort/room/common6.c","/lib/virtual/virt_map.c","/doc/lfun/lib/clip/SetAmmoType","/cmds/players/uptime.c","/secure/cmds/admins/banish.c","/verbs/players/include/describe.h","/domains/default/obj/match.c","/doc/efun/mappings/unique_mapping","/doc/sefun/unguarded","/log/chan/archive/muds-2010.08.24-08.45,48","/log/chan/archive/dchat-2010.09.10-10.45,48","/log/chan/archive/muds-2013.08.01-00.13,15","/save/kills/k/klol","/log/chan/archive/muds-2010.12.24-19.46,44","/doc/efun/all/set_heart_beat","/doc/efun/all/function_exists","/doc/efun/all/call_stack","/save/kills/x/xkcdfnel","/save/kills/f/fk","/domains/amigara/amigara/room/passage14.c","/doc/sefun/get_random_living","/log/chan/archive/muds-2010.11.10-09.45,48","/domains/default/npc/cow.c","/domains/default/obj/pass_example.c","/doc/sefun/path_prefix","/log/chan/archive/muds-2010.11.01-16.45,48","/cmds/players/language.c","/cmds/players/mudlist.c","/doc/efun/internals/set_debug_level","/log/archive/player_errors-2009.03.10-05.37,18","/doc/lfun/lib/body/GetLong","/save/races.1111.o","/domains/fort/obj/cup.c","/save/unique.1111.o","/secure/include/network.6666","/domains/default/npc/gnome.c","/domains/campus/room/kleiner.c","/www/lpmuds/dead_souls.png","/log/chan/archive/muds-2010.10.24-07.45,48","/log/chan/archive/dgd-2009.04.02-12.51,27","/save/kills/x/xkcdalfkm","/log/chan/archive/muds-2010.10.15-14.45,48","/secure/cmds/admins/.router.c.swp","/log/chan/archive/muds-2010.11.07-17.45,48","/daemon/tmp/B_ORB.c","/log/chan/archive/muds-2010.11.06-10.45,48","/verbs/creators/zap.c","/log/chan/archive/intergossip-2013.07.31-11.13,15","/domains/town/meals/espresso.c","/daemon/tmp/LIB.c","/domains/fort/armor/workglove_r.c","/domains/Praxis/data/booth_votes.o","/log/chan/archive/muds-2009.03.12-12.02,51","/doc/efun/system/reclaim_objects","/save/events.o","/domains/town/obj/cold.c","/domains/town/meals/potion_strength.c","/domains/default/npc/quarantine/cor.c","/daemon/tmp/64.c","/save/intermud.6666.o","/save/kills/x/xkcdifohamc","/log/chan/archive/intergossip-2010.10.30-20.45,48","/domains/Praxis/locked.c","/save/kills/b/bkegl","/log/chan/archive/muds-2010.10.01-13.45,48","/doc/lpc/types/array.2d","/secure/sefun/persist.c","/log/chan/archive/intercre-2010.11.25-10.45,48","/doc/applies/clean_up","/secure/obj/tc.c","/lib/include/talk.h","/domains/amigara/room/passage25.c","/log/chan/archive/intergossip-2010.12.22-12.45,48","/doc/lfun/all/GetQuestPoints","/log/archive/runtime-2010.07.08-21.16,00","/doc/applies/logon","/verbs/players/include/target.h","/domains/fort/armor/workglove_l.c","/domains/fort/weap/gsword.c","/domains/fort/etc/private_room.c","/doc/lfun/lib/body/GetTorso","/domains/fort/npc/clerk.bak","/log/chan/archive/inews-2013.08.14-01.13,15","/domains/town/meals/rebel_yell.c","/secure/cmds/creators/log.c","/log/chan/archive/dchat-2010.11.12-09.45,48","/domains/town/weap/runic_sword.c","/domains/town/obj/dcell.c","/doc/lfun/lib/player/CanReceive","/secure/cmds/admins/whowatched.c","/doc/applies/master/valid_link","/domains/campus/obj/round.c","/doc/lfun/lib/npc/SetClass","/domains/campus/txt/ai/charles/green_wins","/doc/applies/master/preload","/log/chan/archive/muds-2010.10.16-07.45,48","/secure/daemon/i3router/funcs.h","/domains/fort/obj/gchest.c","/save/stargate.8888.o","/log/chan/archive/muds-2010.10.15-00.45,48","/log/chan/archive/muds-2009.03.24-02.11,20","/doc/efun/internals/rusage","/doc/lfun/lib/body/GetQuestPoints","/domains/Praxis/cemetery/mon/ghost6.c","/log/chan/archive/muds-2013.08.14-21.13,15","/lib/leader.c","/save/books.6666.o","/domains/default/weap/m16rifle.c","/domains/town/obj/rayovac.c","/log/archive/dests-2010.08.18-20.45,48","/lib/bot.c","/doc/.RELEASE_NOTES.swp","/save/kills/x/xkcdgjjnm","/verbs/players/evade.c","/verbs/players/bump.c","/domains/fort/obj/lever.c","/domains/Praxis/obj/mon/christmas_bunny.c","/doc/efun/internals/refs","/log/archive/runtime-2009.07.12-12.57,22","/domains/town/obj/basement_button.c","/doc/lfun/lib/body/AddPoison","/doc/applies/master/make_path_absolute","/log/archive/runtime-2010.07.09-14.16,00","/domains/Praxis/bank.c","/doc/applies/interactive/telnet_suboption","/daemon/tmp/B_PLANT.c","/log/chan/archive/muds-2010.08.22-21.45,48","/domains/fort/etc/non_gratae.cfg","/www/lpmuds/fonts-compat.css","/secure/daemon/web_sessions.c","/secure/cmds/admins/unwatch.c","/save/notify.1111.o","/log/archive/runtime-2009.05.18-15.00,12","/news/general","/cmds/players/flee.c","/cmds/players/minimap.c","/shadows/needle_trap.c","/doc/efun/all/store_variable","/shadows/explosive_trap.c","/save/kills/i/iiahmo","/domains/default/npc/quarantine/trevor.c","/doc/lfun/all/GetLimbChildren","/doc/applies/heart_beat","/secure/include/network.4444.h","/secure/daemon/remotepost.h","/domains/default/npc/gnoll.c","/log/chan/archive/muds-2010.08.28-22.45,48","/domains/town/weap/shotput.c","/secure/daemon/remotepost.c","/save/kills/x/xkcdcelacnda","/log/chan/archive/muds-2010.10.22-20.45,48","/save/kills/x/xkcdijjlce","/doc/lfun/lib/file/eventDestruct","/log/chan/archive/muds-2010.11.14-23.45,48","/lib/include/player.h","/doc/efun/all/ed_cmd","/domains/town/obj/.rucksack.c.swp","/doc/efun/all/intp","/domains/town/obj/seawater.c","/save/kills/c/cedhbge","/doc/lfun/all/GetLeader","/log/chan/archive/muds-2013.08.01-13.13,15","/log/archive/runtime-2010.07.09-00.16,00","/secure/cfg/races/halfling","/save/kills/e/ekchjccicje","/log/chan/archive/muds-2013.08.29-01.13,15","/secure/lib/net/client.c","/log/chan/mychannel6","/log/chan/archive/muds-2009.03.18-14.30,39","/verbs/builders/delete.c","/log/chan/ascii_art","/log/chan/archive/muds-2010.11.29-17.45,48","/log/chan/archive/muds-2009.05.09-12.58,26","/domains/Ylsrim/room/fighter.c","/daemon/tmp/A_LONG_SOCK.c","/cmds/creators/replog.c","/domains/default/room/start.c","/domains/town/txt/mystery.txt","/log/archive/runtime-2009.03.16-08.30,39","/domains/town/doors/welldoor2.c","/secure/cmds/creators/variables.c","/verbs/players/include/,vote.h","/secure/cfg/races/kender","/log/chan/archive/intergossip-2009.05.18-11.59,29","/doc/lfun/lib/npc/CanReceive","/doc/efun/mudlib/query_privs","/secure/include/bboard.h","/domains/fort/obj/rocks.c","/domains/fort/weap/verysharpsword.c","/domains/Praxis/lpmud_room.c","/doc/efun/all/find_call_out","/secure/sefun/format_page.c","/domains/town/armor/chainmail.c","/domains/amigara/room/passage16.c","/save/kills/k/kkfoiom","/doc/efun/calls/shadow","/save/kills/x/xkcdiemncak","/log/archive/icp-2009.03.16-03.30,39","/doc/lfun/all/SetSacrificeType","/log/archive/runtime-2011.08.21-11.04,13","/log/chan/archive/connections-2009.03.28-16.14,40","/log/chan/archive/dchat-2010.09.20-09.45,48","/doc/efun/all/map_array","/secure/daemon/estates.c","/domains/fort/obj/safe.c","/include/meal_types.h","/log/archive/runtime-2009.10.06-15.42,34","/domains/default/npc/newt.c","/domains/campus/txt/ai/charles/bak2/bak1/fred","/doc/sefun/domain_exists","/verbs/players/learn.c","/log/chan/archive/muds-2010.11.10-08.45,48","/log/chan/archive/muds-2010.09.15-03.45,48","/domains/amigara/room/passage10.c","/secure/cmds/admins/addclass.c","/log/chan/archive/muds-2010.12.01-04.45,48","/domains/fort/room/f_road31.c","/domains/campus/txt/ai/charles/fred","/doc/cheats/orc_slayer.txt","/log/chan/archive/intergossip-2010.07.23-17.16,48","/domains/cave/npc/orc_guard1.c","/daemon/tmp/MOUTH_NONE.c","/secure/include/network.prime","/domains/town/save/0^0domains0^0town0^0obj0^0charity.2222.o","/log/chan/archive/muds-2009.04.10-14.28,44","/lib/files.c","/secure/cmds/creators/unsnoop.c","/save/kills/h/hgk","/domains/town/weap/gstaff.c","/secure/cmds/players/peer.c","/daemon/.map.c.swp","/domains/amigara/amigara/virtual/server.c","/doc/sefun/exec","/save/kills/x/xkcdhbhog","/log/archive/runtime-2010.07.11-12.16,00","/domains/default/npc/faerie.c","/daemon/tmp/S_SOMEWHAT_SMALL.c","/lib/pipe.c","/save/bugs.o","/domains/town/obj/223round.c","/doc/efun/all/living","/log/chan/archive/muds-2013.08.22-20.13,15","/doc/lfun/all/GetRechargeable","/domains/Praxis/hm_chamber.c","/doc/efun/parsing/TODO","/secure/cfg/mudos.win32","/secure/daemon/update.c","/domains/campus/obj/357case.c","/doc/sefun/file_privs","/cmds/players/who.c","/domains/default/obj/manual.c","/domains/default/npc/wraith.c","/news/ftpd","/lib/include/virtual.h","/domains/campus/room/slab.c","/log/chan/archive/intergossip-2010.11.22-22.45,48","/domains/town/armor/glove.c","/domains/fort/room/yard1.c","/obj/area_room.c","/domains/town/armor/glove_r.c","/log/archive/reset-2010.07.23-08.16,17","/include/motion.h","/verbs/creators/wizunlock.c","/domains/fort/npc/kender.c","/doc/lfun/all/SetRechargeable","/log/archive/runtime-2010.07.08-20.16,00","/doc/applies/master/domain_file","/save/kills/i/ijbamlfficl","/domains/fort/armor/scarf.c","/save/kills/x/xkcdlcfmjoj","/save/kills/m/mbkfco","/doc/lfun/lib/player/eventUse","/include/climb.h","/domains/fort/room/f_road4.c","/log/chan/archive/muds-2009.04.11-07.28,44","/domains/default/room/menagerie_w.c","/domains/default/obj/rack.c","/daemon/weather.c","/log/chan/archive/muds-2009.04.10-00.28,44","/save/races.2222.o","/log/chan/archive/muds-2010.11.08-09.45,48","/domains/fort/npc/gate_guard.bak","/domains/Ylsrim/adm/cache.c","/domains/town/armor/glove_l.c","/log/chan/archive/muds-2009.03.24-01.11,20","/save/unique.2222.o","/domains/cave/obj/chest.c","/save/kills/x/xkcddfloecnfd","/secure/include/rooms.6666","/lib/clip.c","/doc/lfun/all/GetCaffeine","/log/chan/archive/i2game-2009.05.18-18.00,12","/daemon/types.c","/domains/amigara/room/food_storage.c","/doc/lfun/lib/worn_storage/eventReceiveDamage","/log/chan/archive/intergossip-2010.09.29-17.45,48","/domains/campus/txt/map.txt","/log/chan/archive/discworld-chat-2010.07.28-16.17,46","/log/enter","/doc/lfun/all/SetHeat","/secure/daemon/.portal.c.swp","/domains/town/obj/spent.c","/lib/std/furnace.c","/secure/cmds/players/telnet.c","/domains/town/armor/boot_r.c","/domains/campus/txt/ai/charly/bak/fblue","/daemon/tmp/A_BELT.c","/doc/lfun/lib/clan/eventUnjoin","/log/archive/runtime-2010.07.09-13.16,00","/domains/town/weap/9mmpistol_mp.c","/domains/cave/obj/.cask5.c.swp","/save/kills/c/ccmhleneeji","/log/chan/archive/muds-2010.08.31-13.45,48","/log/chan/archive/intergossip-2013.08.01-12.13,15","/log/chan/archive/muds-2010.09.23-16.45,48","/domains/learning/room/pod.c","/secure/sefun/query_time_of_day.c","/log/chan/archive/intergossip-2010.09.15-16.45,48","/doc/sefun/file_exists","/domains/default/npc/triffid.c","/domains/town/room/mansion_mbdroom.c","/domains/campus/room/u_lab.c","/doc/lfun/lib/race/GetResistance","/doc/efun/all/file_name","/domains/campus/doors/green_door.c","/doc/efun/strings/test_bit","/log/chan/archive/intergossip-2009.03.18-13.30,39","/log/chan/archive/inews-2009.05.11-10.59,14","/obj/chair.c","/domains/town/armor/boot_l.c","/www/style.css","/doc/lfun/lib/round/SetCaliber","/domains/default/npc/quarantine/wallace.c","/domains/fort/room/f_road28.c","/log/chan/archive/muds-2013.08.24-06.13,15","/doc/efun/mappings/allocate_mapping","/log/chan/archive/muds-2013.08.06-20.13,15","/save/kills/k/kjecbckhd","/domains/fort/obj/pool_ball.c","/domains/campus/room/access6.c","/domains/amigara/amigara/virtual/void.c","/domains/default/room/menagerie_e.c","/domains/campus/doors/eledoor1.c","/doc/efun/all/input_to","/domains/town/virtual/forest/-13,13.c","/daemon/tmp/hazlab.c","/domains/campus/room/basement2.c","/secure/daemon/snoop.c","/daemon/include/chat.h","/domains/default/npc/deer.c","/doc/efun/interactive/add_action","/domains/fort/room/f_road22.c","/save/kills/b/bijlgee","/doc/lfun/lib/clip/eventUnload","/domains/campus/meals/apple.c","/doc/help/races/orc","/domains/fort/room/north_wall_4.c","/doc/lfun/lib/clip/GetFirearmType","/domains/campus/room/access0.c","/log/chan/archive/ichat-2009.03.24-12.11,20","/lib/events/listen.c","/cmds/creators/rot.c","/domains/campus/npc/gloria.c","/log/shutdowns","/domains/town/virtual/sky/22,10,1.c","/verbs/items/throw.c","/domains/town/obj/8ball.c","/domains/fort/weap/staff.c","/domains/Praxis/obj/mon/receptionist.c","/domains/fort/room/tunnel10.c","/save/kills/c/ckfed","/save/notify.2222.o","/save/kills/i/ildfiambdme","/save/kills/x/xkcddbeakckjob","/log/archive/runtime-2009.03.16-07.30,39","/domains/Praxis/rain_forest.c","/secure/obj/replacer.c","/domains/Ylsrim/room/weaponry.c","/domains/campus/room/npath.c","/www/articles/old/tms.html","/domains/town/room/mansion_uhall3.c","/domains/Ylsrim/room/bazaar.c","/log/archive/i3error-2009.04.25-01.15,09","/domains/Praxis/forest2.c","/domains/fort/weap/9mmpistol.c","/domains/amigara/amigara/room/banquet.c","/log/chan/archive/muds-2010.09.29-03.45,48","/doc/lfun/all/eventLight","/log/chan/archive/muds-2009.05.21-17.14,33","/log/archive/icp-2009.03.16-02.30,39","/secure/include/network.5555.h","/domains/town/virtual/sky/26,99998,1.c","/domains/campus/obj/magbox.c","/log/archive/runtime-2011.08.21-10.04,13","/save/kills/x/xkcdcimhmhneij","/daemon/services/tell.c","/log/chan/archive/muds-2010.12.06-11.45,48","/domains/default/doors/test101.c","/doc/applies/create","/domains/fort/doors/locksmith.c","/log/chan/archive/intercre-2010.09.20-15.45,48","/verbs/rooms/fish.c","/domains/fort/obj/bigbag.c","/domains/Praxis/commands","/doc/efun/general/sizeof","/domains/fort/room/office.c","/doc/lfun/lib/clip/GetCaliber","/log/chan/archive/muds-2010.11.10-07.45,48","/secure/include/iips.h","/log/chan/archive/intergossip-2010.10.01-11.45,48","/domains/campus/save/charles.o.gz","/domains/fort/npc/cat.c","/domains/default/npc/ogre.c","/log/archive/player_errors-2009.03.10-03.37,18","/cmds/players/keepalive.c","/log/chan/archive/dchat-2010.08.25-13.45,48","/domains/fort/room/south_wall_4.c","/shadows/.arbiter.c.swp","/daemon/include/statistics.h","/cmds/creators/scan.c","/secure/daemon/reload.c","/doc/efun/general/filter","/save/kills/x/xkcdohcdhhgno","/domains/fort/room/language.c","/domains/campus/room/bookstore2.c","/save/kills/o/olmcn","/log/chan/archive/muds-2010.08.29-00.45,48","/domains/town/obj/dcell_std.c","/save/rooms.1111.o","/save/kills/m/mcffnfnmiad","/domains/cave/room/shop2.c","/doc/efun/all/cache_stats","/tmp/imc2.log","/domains/fort/obj/weight.c","/save/kills/c/cmec","/doc/efun/objects/clone_object","/secure/lib/net/telnet_client.c","/lib/std/table.c","/domains/fort/npc/gate_guard.c","/secure/cfg/groups.cfg","/secure/daemon/tracker.c","/save/kills/x/xkcdoicgljl","/domains/campus/txt/ai/charly/bak/runs","/doc/applies/parse_command_plural_id_list","/verbs/builders/initfix.c","/log/chan/archive/i2news-2009.04.29-18.11,41","/domains/Praxis/alley1.c","/domains/fort/room/south_gtower_top.c","/domains/fort/npc/test","/secure/daemon/folders.h","/log/chan/archive/muds-2010.09.08-09.45,48","/secure/sefun/sefun.h","/log/chan/archive/dchat-2010.11.25-01.45,48","/doc/efun/interactive/wizardp","/www/example.html","/save/kills/h/hag","/domains/fort/armor/canvas_shorts.c","/doc/lfun/all/PlusAmmo","/save/soul.o","/secure/daemon/folders.c","/log/chan/archive/intergossip-2010.10.02-04.45,48","/domains/cave/room/furnace.c","/secure/sefun/sefun.c","/secure/include/runtime_config.h","/domains/fort/armor/oldstyle_ring.c","/domains/town/npc/orc.c","/domains/fort/room/f_road19.c","/doc/efun/system/index","/domains/Praxis/town_hall.c","/doc/lfun/lib/body/eventWear","/doc/lfun/all/AddLead","/www/articles/lpu.html","/lib/history.c","/doc/efun/system/error","/domains/Ylsrim/npc/traveller.c","/lib/std/room.c","/domains/town/room/mansion_room12.c","/doc/efun/filesystem/link","/domains/Praxis/pass3.c","/domains/Praxis/adv_main.c","/doc/lfun/lib/room/CanFly","/domains/campus/room/conf.c","/doc/efun/all/localtime","/doc/lfun/lib/body/GetHeartModifier","/log/chan/archive/muds-2010.11.08-08.45,48","/domains/fort/npc/t1.c","/secure/cmds/creators/cwd.c","/lib/die.c","/domains/campus/obj/.backpack_civilian.c.swp","/domains/Praxis/obj/mon/unity.c","/domains/fort/room/f_road13.c","/domains/campus/obj/.backpack.c.swp","/domains/fort/obj/dcell_crappy.c","/domains/town/save/0^0domains0^0town0^0obj0^0charity.3333.o","/verbs/items/shake.c","/domains/Ylsrim/obj/cask.c","/cmds/creators/transfer.c","/log/chan/ds","/log/chan/muds","/domains/town/room/shore.c","/secure/cmds/creators/cp.c","/domains/campus/txt/ai/charles/bak2/stays","/log/chan/archive/inews-2009.03.18-06.30,39","/log/archive/icp-2009.03.15-22.30,39","/lib/light.c","/daemon/decay.c","/log/archive/runtime-2009.10.05-14.41,35","/domains/town/room/wtunnel6.c","/domains/town/obj/.orc_rucksack.c.swp","/domains/Ylsrim/etc/road.c","/save/kills/k/km","/save/kills/k/kl","/domains/fort/obj/explosive_trap.c","/log/archive/runtime-2010.07.09-12.16,00","/save/kills/k/ki","/lib/events/rock.c","/verbs/items/strike.c","/save/kills/k/kg","/save/kills/k/kf","/save/kills/c/cjmdk","/www/articles/tacitus.html","/secure/obj/include/roommaker.h","/daemon/tmp/nmsh.c","/save/kills/x/xkcdkeakac","/doc/sefun/currency_inflation","/doc/sefun/say","/doc/sefun/percent","/domains/campus/obj/.dcell_crappy.c.swp","/domains/Praxis/obj/misc/fishing_pole.c","/log/chan/archive/dchat-2010.11.04-07.45,48","/doc/applies/master/author_file","/obj/wed_ring.c","/log/chan/archive/inews-2009.03.23-14.11,20","/log/chan/archive/dchat-2010.08.12-10.18,42","/lib/missile.c","/domains/campus/npc/turret.c","/log/chan/archive/muds-2010.11.28-22.45,48","/log/chan/archive/intergossip-2011.01.10-22.46,55","/log/chan/archive/inews-2013.07.30-23.13,15","/secure/include/global.8888.h","/log/chan/archive/muds-2010.10.08-05.45,48","/domains/campus/doors/steel_door.c","/doc/lfun/lib/spell/GetSkills","/cmds/players/earmuff.c","/doc/efun/floats/exp","/lib/exits.c","/save/kills/k/kgidochelje","/save/kills/j/jcnemk","/doc/lfun/lib/clay/InitComposition","/doc/cheats/basics.txt","/lib/include/pistol.h","/log/chan/archive/imudnews-2010.10.26-18.45,48","/save/races.3333.o","/log/chan/archive/i2news-2009.03.23-14.11,20","/lib/include/messages.h","/domains/campus/obj/note.c","/doc/lfun/lib/battery/GetDrainRate","/secure/cmds/creators/cd.c","/domains/town/obj/cot.c","/save/unique.3333.o","/domains/fort/weap/shotput.c","/domains/Praxis/quests/the_blight_of_the_bog.c","/doc/efun/interactive/shout","/secure/scripts/nm3.lsed","/save/kills/i/ilji","/log/chan/archive/dgd-2010.09.07-14.45,48","/domains/town/room/bank.c","/domains/town/obj/gbed.c","/log/chan/archive/intergossip-2010.12.07-17.45,48","/doc/lfun/all/GetBaseStatLevel","/doc/efun/mudlib/getuid","/domains/fort/obj/seawater.c","/lib/include/donate.h","/domains/town/npc/human_champion_f.c","/secure/include/.config.h.swp","/doc/efun/mixed/intp","/domains/fort/obj/chest.c","/verbs/items/include/strike.h","/doc/efun/all/query_idle","/doc/lfun/lib/player/GetCapName","/log/chan/archive/muds-2010.09.15-15.45,48","/doc/lfun/lib/firearm/SetFirearmType","/domains/campus/room/south_road2.c","/log/chan/archive/intergossip-2011.01.11-15.46,55","/log/chan/archive/dchat-2010.08.04-10.18,42","/domains/fort/room/watchtower.c","/log/archive/runtime-2009.03.16-06.30,39","/doc/sefun/identify","/domains/Ylsrim/etc/chest.c","/domains/campus/obj/map.c","/log/chan/bofh","/log/chan/archive/muds-2010.09.10-07.45,48","/log/chan/archive/muds-2010.10.24-18.45,48","/doc/efun/system/function_profile","/domains/campus/obj/lever.c","/log/chan/archive/muds-2010.10.23-11.45,48","/domains/campus/txt/jenny/14.txt","/log/adm/call","/domains/town/armor/sock.c","/log/chan/archive/muds-2010.11.23-00.45,48","/log/chan/archive/muds-2009.05.13-15.59,29","/log/archive/icp-2009.03.16-01.30,39","/secure/include/std.h","/domains/fort/obj/bench2.c","/domains/Praxis/planning_room.c","/save/kills/g/ggjfkfk","/lib/elevator_button.c","/domains/town/doors/m7.c","/domains/default/room/wiz_hall2.c","/domains/campus/meals/water.c","/domains/default/npc/quarantine/adrian.c","/domains/default/obj/lever.c","/secure/tmp/slymenstra_CMD_EVAL_TMP_FILE.c","/domains/town/weap/zpem.c","/www/articles/forum_chat.html","/www/articles/tacitus2.html","/domains/town/meals/winebottle.c","/save/books.8888.o","/log/chan/archive/muds-2010.11.10-06.45,48","/log/chan/archive/inews-2010.11.27-22.45,48","/domains/Praxis/obj/misc/match.c","/log/errors/campus","/include/talk_type.h","/domains/amigara/room/passage9.c","/save/kills/g/glmncmhbdi","/doc/efun/all/first_inventory","/doc/applies/valid_shadow","/domains/fort/doors/workroom_door.c","/save/kills/x/xkcdekg","/save/kills/x/xkcddboohcd","/secure/scripts/.crat.src.swp","/secure/cmds/players/chfn.c","/domains/town/doors/m1.c","/doc/lfun/lib/ftp_client/eventDestruct","/doc/efun/strings/sscanf","/lib/.race.c.swp","/secure/cmds/builders/grant.c","/save/services.1111.o","/log/chan/archive/muds-2009.04.10-12.28,44","/log/chan/archive/dchat-2010.11.02-20.45,48","/domains/campus/room/sewer.c","/doc/lfun/lib/body/GetExperiencePoints","/domains/Praxis/s_centre3.c","/doc/lfun/lib/burn/SetHeat","/save/notify.3333.o","/log/chan/archive/muds-2010.09.01-00.45,48","/domains/fort/doors/w_door.c","/doc/efun/all/set_this_player","/doc/lfun/lib/connect/eventDestruct","/log/chan/archive/muds-2009.04.29-17.10,44","/domains/amigara/room/passage3.c","/log/chan/archive/muds-2009.05.14-08.59,29","/domains/campus/txt/jenny/4.txt","/doc/lfun/all/GetClan","/secure/include/socket_err.h","/log/chan/archive/sport-2013.08.09-04.13,15","/domains/campus/adm/furnace.c","/save/kills/l/lmnkj","/domains/fort/obj/223round.c","/verbs/rooms/include/stop.h","/secure/include/props.h","/doc/lfun/all/CanManipulate","/domains/cave/obj/lister.c","/domains/campus/obj/pedestal2.c","/secure/cmds/creators/bk.c","/cmds/creators/invis.c","/secure/room/arch.c","/domains/Praxis/data/booth_question","/doc/lfun/all/AddHP","/doc/lfun/all/CanRemoveItem","/doc/efun/objects/children","/log/chan/archive/intergossip-2010.08.03-16.18,42","/domains/default/npc/zookeeper.c","/domains/Praxis/adm/README","/doc/lfun/lib/npc/GetCapName","/log/chan/archive/broken_gossip-2010.12.29-00.46,48","/save/kills/o/omleofm","/domains/default/vehicles/hoverpod.c","/doc/lfun/all/GetMoralityDescription","/domains/default/npc/zoe.c","/log/chan/archive/muds-2009.04.11-05.28,44","/log/chan/archive/muds-2010.10.08-18.45,48","/doc/lfun/lib/flashlight/GetCellType","/log/chan/archive/muds-2010.11.08-07.45,48","/log/chan/archive/muds-2013.08.24-18.13,15","/doc/lfun/all/eventLoad","/secure/sefun/get_livings.c","/log/chan/archive/muds-2010.11.07-00.45,48","/doc/efun/all/floor","/daemon/tmp/lib_Body.c","/domains/campus/weap/dagger.c","/news/deadsouls","/doc/lfun/all/GetLimbParent","/domains/town/obj/stick.c","/domains/town/armor/mhelmet.c","/save/rooms.2222.o","/save/kills/x/xkcdnnlhjbbj","/save/kills/b/badgoc","/log/chan/archive/imudnews-2009.03.26-22.17,31","/doc/efun/internals/index","/domains/town/room/mansion_room9.c","/log/archive/reset-2010.11.01-03.45,48","/domains/town/meals/megapotion.c","/domains/Praxis/cemetery/grave_yard7.c","/domains/fort/doors/dairy.c","/doc/lfun/lib/body/GetHeartRate","/lib/pole.c","/secure/include/secrets.8888.h","/log/chan/archive/muds-2010.10.02-03.45,48","/lib/props/ambiance.c","/lib/follow.c","/save/kills/x/xkcdcdghghc","/save/kills/b/bgcl","/save/kills/x/xkcdkhl","/doc/efun/all/socket_bind","/secure/cfg/runmud_template.bat","/secure/cfg/races/nymph","/log/archive/runtime-2010.07.09-11.16,00","/domains/fort/armor/boot_r.c","/doc/lfun/all/AddChannel","/verbs/players/news.c","/domains/fort/obj/pack.c","/domains/amigara/npc/rat.c","/save/kills/b/bjomgf","/domains/town/room/mansion_room3.c","/domains/fort/obj/item_14.c","/log/chan/archive/muds-2010.09.14-21.45,48","/domains/learning/save/analytics.o","/doc/lfun/README","/domains/town/save/0^0domains0^0town0^0room0^0secret.o.gz","/domains/campus/room/corridor2.c","/doc/lfun/all/GetExtraChannels","/domains/fort/room/test1.c","/cmds/creators/.anchor.c.swp","/log/chan/archive/muds-2009.05.21-09.13,36","/domains/fort/armor/boot_l.c","/domains/default/obj/9mmclip.c","/doc/lfun/lib/living/GetMaxHealthPoints","/domains/town/obj/rage.c","/secure/include/cgi.h","/log/chan/archive/muds-2010.08.16-05.45,20","/domains/fort/npc/tower_guard2.c","/domains/fort/obj/slip_cure.c","/save/kills/o/ogfng","/doc/lfun/all/CanLight","/domains/fort/obj/squirtbag.c","/log/i3error.2009.05.14-17.56,40","/log/chan/archive/intergossip-2010.07.14-22.16,17","/domains/cave/room/cavepass5.c","/domains/campus/npc/seth.c","/domains/default/obj/builder_chest.c","/domains/town/armor/long_sock.c","/daemon/ftp_port_tracker.c","/log/chan/archive/intergossip-2010.08.29-12.45,48","/domains/campus/doors/plain_door2.c","/doc/efun/all/sizeof","/domains/town/obj/match.c","/secure/daemon/i3router/server_log.h","/log/chan/archive/broken_gossip-2010.12.31-12.46,48","/domains/cave/room/death.c","/log/chan/archive/intergossip-2010.11.15-13.45,48","/save/kills/x/xkcdkgb","/doc/applies/valid_save_binary","/cmds/players/terminal.c","/log/chan/archive/muds-2010.08.24-18.45,48","/domains/campus/obj/.223round.c.swp","/www/function.jpg","/doc/lfun/lib/chat/RemoveChannel","/log/terminals","/doc/help/players/mapping","/verbs/items/include/drink.h","/secure/cfg/races/strider","/domains/fort/room/south_gtower_lower.c","/doc/lfun/all/GetDrainRate","/secure/sefun/inventory.c","/log/chan/archive/muds-2010.11.10-19.45,48","/secure/lib/net/include/h_ftpd.h","/lib/events/lock.c","/daemon/tmp/A_VISOR.c","/secure/daemon/rooms.c","/log/chan/archive/muds-2010.09.23-00.45,48","/domains/fort/armor/helmet2.c","/www/lpmuds/spellcheck.js","/domains/fort/room/cell3.c","/domains/fort/obj/needle_trap2.c","/doc/efun/all/filter","/doc/efun/objects/new","/save/kills/x/xkcdegc","/save/kills/h/hjbdbbdidl","/doc/sefun/last_string_element","/log/chan/archive/intergossip-2010.12.02-08.45,48","/doc/lfun/lib/load/eventUnload","/verbs/builders/createfix.c","/domains/default/npc/lynx.c","/save/kills/j/jmibklaamfd","/log/archive/runtime-2009.03.16-05.30,39","/daemon/tmp/access5.c","/log/chan/archive/muds-2009.05.20-18.07,04","/domains/fort/room/chapel.c","/doc/applies/net_dead","/secure/daemon/translation.c","/log/chan/archive/broken_gossip-2011.01.07-20.46,13","/www/lpmuds/favicon.ico","/secure/include/rooms.h","/domains/Praxis/dump.c","/log/chan/archive/muds-2010.08.29-12.45,48","/save/kills/i/idd","/log/chan/archive/i2news-2009.03.24-06.11,20","/log/archive/runtime-2009.07.23-22.15,28","/domains/town/npc/orc_shaman.c","/save/kills/i/idc","/log/chan/archive/muds-2009.11.22-19.44,08","/domains/town/armor/robe.c","/secure/cmds/admins/addguest.c","/doc/efun/strings/reg_assoc","/secure/modules/generic.c","/domains/fort/npc/fighter_wander2.c","/daemon/spells.c","/log/chan/archive/muds-2010.11.06-20.45,48","/log/chan/archive/intergossip-2010.10.15-10.45,48","/log/archive/icp-2009.03.16-00.30,39","/daemon/tmp/one.c","/secure/daemon/events.h","/log/chan/archive/sport-2013.08.09-17.13,15","/domains/cave/npc/cavetroll.c","/doc/lfun/lib/body/GetFood","/verbs/items/include/dig.h","/secure/daemon/events.c","/save/races.4444.o","/domains/town/obj/.table.c.swp","/save/unique.4444.o","/doc/lfun/lib/burn/GetMinHeat","/log/chan/archive/muds-2010.08.24-04.45,48","/daemon/tmp/S_SOMEWHAT_LARGE.c","/log/chan/archive/muds-2010.09.16-07.45,48","/doc/lfun/lib/classes/GetBaseStatLevel","/secure/cfg/flashpolicy.cfg","/log/chan/archive/muds-2010.09.07-14.45,48","/www/lpmuds/help.css","/log/chan/archive/muds-2010.11.10-05.45,48","/domains/campus/obj/lamp.c","/daemon/tmp/otik.c","/secure/cmds/creators/.cat10.c.swp","/log/chan/archive/muds-2010.10.29-11.45,48","/domains/town/virtual/space/1,1,1.c","/doc/lfun/all/GetClanSkill","/save/kills/j/jof","/domains/campus/obj/.labkey.c.swp","/domains/fort/doors/south.c","/daemon/tmp/lounge.c","/log/chan/archive/dchat-2010.08.26-18.45,48","/domains/Praxis/obj/magic/invis.c","/domains/town/room/shower.c","/domains/town/npc/giant_isopod.c","/doc/applies/master/valid_shadow","/doc/lfun/lib/chat/chat_command","/doc/lfun/all/checkCollapse","/log/chan/archive/dchat-2010.09.17-14.45,48","/lib/include/abilities.h","/domains/town/room/mansion_int.c","/doc/build/NPC","/doc/applies/compile_object","/log/chan/archive/muds-2009.04.11-18.28,44","/domains/fort/customdefs.h","/save/kills/m/mifoeideh","/secure/scripts/crat.src","/log/chan/archive/muds-2010.09.02-06.45,48","/cmds/players/emote.c","/log/chan/archive/muds-2011.01.09-16.46,13","/verbs/players/kneel.c","/domains/fort/obj/sign.c","/log/chan/archive/muds-2010.11.16-06.45,48","/log/chan/archive/muds-2009.03.24-12.11,20","/doc/sefun/arrange_string","/domains/fort/obj/mkey.c","/doc/efun/all/domain_stats","/log/chan/archive/muds-2009.05.13-00.59,29","/domains/town/npc/radagast.c","/log/chan/archive/muds-2010.12.07-02.45,48","/lib/daemons/include/verb.h","/domains/town/obj/round.c","/save/kills/j/jnm","/domains/town/room/.church.c.swp","/domains/README","/doc/help/classes/thief","/log/chan/camma","/doc/efun/strings/capitalize","/domains/default/virtual/sky.c","/include/assessment.h","/doc/efun/all/file_length","/log/chan/archive/muds-2010.10.02-16.45,48","/doc/build/Items","/verbs/rooms/jump.c","/log/chan/archive/inews-2009.03.17-11.30,39","/log/chan/archive/muds-2010.12.22-22.45,48","/domains/campus/txt/ai/charles/blue_wins","/doc/sefun/tail","/cmds/players/stat.c","/verbs/players/include/bump.h","/domains/campus/armor/necklace.c","/doc/lfun/all/GetAmmoType","/log/chan/archive/muds-2010.09.07-00.45,48","/doc/lfun/lib/clip/SetCaliber","/secure/sefun/reload.c","/secure/cmds/players/map.c","/log/archive/runtime-2014.11.01-09.00,32","/lib/events/install.c","/lib/include/match.h","/lib/events/.get_from.c.swp","/cmds/players/reprompt.c","/domains/fort/obj/fleas.c","/domains/campus/obj/mlocker.c","/daemon/include/notify.h","/daemon/tmp/MOUTH_LIPPED+MOUTH_TOOTHED+MOUTH_BEAKED+MOUTH_TONGUED+MOUTH_FANGED.c","/save/kills/g/gfoabealakh","/log/chan/archive/inews-2013.08.06-11.13,15","/doc/sefun/pluralize","/log/chan/archive/muds-2009.04.30-09.47,55","/secure/cfg/races/ogre","/log/chan/archive/intergossip-2013.08.29-11.13,15","/domains/town/weap/boobytrap_dagger.c","/log/chan/archive/dchat-2010.11.03-12.45,48","/domains/town/obj/riverwater.c","/domains/campus/obj/sofa.c","/doc/lfun/lib/shell/GetAmmoType","/secure/cmds/players/reply.c","/secure/cfg/mudos.2222.win32","/doc/lfun/all/GetTorso","/domains/campus/txt/ai/charly/bak/percent","/log/chan/archive/muds-2010.10.07-10.45,48","/domains/default/weap/prifle.c","/log/chan/archive/muds-2010.11.08-06.45,48","/log/chan/archive/muds-2010.08.16-18.45,20","/domains/campus/txt/ai/charles/fgreen","/doc/lfun/lib/chat/GetChannels","/domains/town/obj/ladder_simple.c","/verbs/players/abandon.c","/secure/daemon/imc2server/0.c","/log/chan/archive/muds-2010.08.15-11.45,20","/log/chan/archive/dchat-2010.07.17-15.16,17","/domains/fort/obj/cavetroll_key.c","/save/notify.4444.o","/log/chan/archive/muds-2010.10.31-23.45,48","/domains/town/virtual/sky/25,8,1.c","/doc/lfun/all/GetAllowSacrifice","/log/chan/archive/intergossip-2010.11.24-19.45,48","/cmds/creators/godmode.c","/domains/town/obj/.dcell.c.swp","/www/articles/newcomer.html","/domains/town/obj/flu.c","/log/chan/archive/discworld-chat-2010.08.23-09.45,48","/log/chan/archive/muds-2013.08.10-16.13,15","/log/chan/archive/intergossip-2010.12.06-22.45,48","/log/archive/runtime-2010.07.09-10.16,00","/log/archive/runtime-2009.11.17-09.10,44","/secure/sefun/parse_objects.c","/log/chan/archive/intergossip-2010.08.24-17.45,48","/log/archive/catch-2009.11.16-18.09,58","/save/kills/o/okho","/save/kills/b/bddjiimk","/domains/fort/obj/simple_chair.c","/domains/fort/armor/pants.c","/save/kills/x/xkcdghgniijdfc","/save/kills/x/xkcdecc","/log/archive/i3error-2009.04.30-17.45,50","/save/portal.1111.o","/cmds/creators/goto.c","/secure/cmds/admins/chanban.c","/log/chan/archive/intergossip-2010.09.06-20.45,48","/news/welcome.4444","/domains/default/weap/sharpsword.c","/lib/include/corpse.h","/doc/lpc/intermediate/chapter7","/doc/lpc/intermediate/chapter6","/doc/lpc/intermediate/chapter5","/domains/Praxis/obj/misc/cold.c","/doc/lpc/intermediate/chapter4","/doc/lpc/intermediate/chapter3","/doc/lpc/intermediate/chapter2","/doc/lpc/intermediate/chapter1","/doc/lfun/lib/interactive/GetName","/log/chan/archive/muds-2013.08.15-10.13,15","/lib/events/touch.c","/doc/lfun/all/GetExperiencePoints","/log/chan/archive/intergossip-2013.08.16-03.13,15","/domains/fort/obj/pedestal3.c","/save/kills/o/oehm","/log/chan/archive/muds-2009.04.03-02.51,27","/log/chan/archive/muds-2010.11.23-12.45,48","/log/archive/icp-2009.03.16-13.30,39","/log/chan/archive/discworld-chat-2011.01.10-19.46,48","/lib/include/help.h","/log/chan/archive/i2news-2009.05.12-00.59,29","/domains/default/npc/nymph.c","/domains/fort/doors/blacksmith.c","/domains/fort/room/fsquare.c","/doc/help/classes/mage","/save/rooms.3333.o","/doc/lfun/lib/body/AddMagicProtection","/doc/cheats/.chapter04.swp","/domains/amigara/room/freezer.c","/daemon/tmp/SHOCK.c","/lib/include/round.h","/secure/cmds/creators/wget.c","/log/chan/archive/muds-2010.08.23-10.45,48","/log/chan/archive/muds-2010.11.10-18.45,48","/doc/sefun/livings","/doc/lfun/lib/abilities/AddSkillPoints","/log/chan/archive/muds-2011.01.10-20.46,55","/domains/fort/armor/bearsuit.c","/domains/Praxis/arch.c","/doc/lfun/all/CanReceive","/log/chan/archive/muds-2010.12.01-14.45,48","/domains/town/obj/pool_table.c","/domains/Praxis/kataan_hall.c","/domains/town/obj/water_pipe.c","/log/archive/runtime-2009.03.16-04.30,39","/domains/Praxis/jungle.c","/log/archive/runtime-2009.09.22-12.03,17","/domains/town/armor/hshirt.c","/log/chan/archive/inews-2009.03.12-01.02,51","/domains/default/weap/brush.c","/log/chan/archive/muds-2013.08.07-10.13,15","/daemon/tmp/B_GASTROPOD.c","/save/kills/e/eknjmlkj","/secure/daemon/i3router/server.c","/log/archive/reset-2009.05.22-16.21,24","/cmds/players/gag.c","/secure/include/config.1111.h","/save/kills/o/ofagdbcjoee","/save/kills/r/rowsdower","/log/archive/currency-2010.08.17-11.45,20","/domains/fort/room/cpath.c","/log/archive/runtime.boot-2009.03.28-16.14,40","/doc/lfun/lib/chat/AddChannel","/log/chan/archive/intergossip-2010.11.08-19.45,48","/log/chan/archive/muds-2010.12.07-15.45,48","/log/chan/archive/muds-2009.10.03-03.41,27","/daemon/tmp/LIB_CONNECT.c","/daemon/tmp/MOUTH_LIPPED+MOUTH_TOOTHED+MOUTH_TONGUED+MOUTH_FANGED.c","/log/chan/archive/muds-2013.08.02-02.13,15","/doc/applies/master/connect","/save/kills/x/xkcdflcgnlmeic","/log/chan/archive/muds-2010.10.10-15.45,48","/domains/fort/room/adv_guild.c","/save/kills/k/kidckoo","/doc/lpc/intermediate/Copyright","/log/chan/*dalet:dchat","/log/chan/archive/muds-2011.01.11-13.46,55","/log/chan/archive/muds-2010.11.10-04.45,48","/doc/efun/system/inherit_list","/verbs/common/include/say.h","/domains/Praxis/data/properties.o.gz","/doc/lfun/lib/flashlight/SetCellType","/domains/fort/obj/9mmclip_empty.c","/domains/default/room/quarantine1.c","/domains/town/obj/explosive_trap.c","/secure/daemon/log.c","/secure/cfg/mudos.autobak.7777","/domains/default/npc/.drone3.c.swp","/doc/efun/all/interactive","/doc/efun/internals/dump_file_descriptors","/domains/campus/doors/plain_door.c","/log/chan/archive/muds-2009.04.11-17.28,44","/domains/town/doors/trapdoor.c","/domains/Praxis/orc_valley/chamber1.c","/doc/efun/interactive/write","/log/chan/archive/muds-2010.10.16-16.45,48","/log/chan/archive/muds-2009.04.10-10.28,44","/domains/campus/txt/ai/charles/bak2/blue_wins","/save/kills/j/jii","/log/chan/archive/muds-2010.10.24-02.45,48","/doc/lfun/lib/classes/eventMoralAct","/log/chan/archive/muds-2010.11.08-19.45,48","/domains/campus/obj/.pedestal3.c.swp","/doc/sefun/false","/doc/efun/all/pow","/cmds/admins/arch.c","/lib/include/pager.h","/doc/efun/filesystem/index","/doc/sefun/domain","/std/README","/secure/lib/connect.c","/doc/sefun/effective_light","/log/chan/archive/intergossip-2010.08.08-22.18,42","/domains/campus/obj/223round.c","/doc/sefun/snoop","/verbs/items/load.c","/secure/sefun/.strings.c.swp","/log/chan/archive/intergossip-2010.08.16-17.45,20","/doc/applies/move_or_destruct","/log/chan/archive/discworld-chat-2010.11.22-17.45,48","/save/kills/i/iifnfldh","/log/chan/archive/mudnews-2013.08.27-23.13,15","/domains/town/room/garden.c","/domains/cave/npc/orc_soldier1.c","/doc/efun/calls/catch","/domains/fort/armor/boobytrap_ring.c","/doc/applies/parse_command_prepos_list","/lib/include/pile.h","/www/lpmuds/lpmud_list.html","/doc/efun/interactive/ed","/save/kills/o/oeek","/doc/applies/valid_socket","/secure/lib/mssp.h","/domains/town/obj/suitcase.c","/domains/fort/obj/btable.c","/doc/lfun/lib/body/GetLimbChildren","/log/chan/archive/muds-2010.10.10-01.45,48","/std/estate.c","/domains/amigara/amigara/room/passage7.c","/save/races.5555.o","/doc/lpc/concepts/oop","/doc/efun/arrays/index","/log/archive/runtime-2010.07.09-23.16,00","/secure/sefun/make_workroom.c","/save/unique.5555.o","/log/errors/testycre","/domains/default/obj/chest.c","/daemon/tmp/S_MINISCULE.c","/doc/lfun/all/SetFirearmType","/log/chan/archive/muds-2009.03.28-16.14,40","/domains/town/txt/map.txt","/log/chan/archive/inews-2013.08.15-03.13,15","/domains/campus/room/sewer3.c","/log/chan/archive/intergossip-2010.09.24-19.45,48","/doc/lfun/lib/lamp/GetBurnRate","/log/chan/archive/free_speech-2013.08.23-13.13,15","/secure/sefun/ascii.c","/doc/efun/filesystem/file_size","/log/chan/archive/intergossip-2010.09.23-12.45,48","/domains/cave/adm/README","/doc/sefun/user_exists","/log/chan/archive/muds-2009.04.11-03.28,44","/log/chan/archive/muds-2010.10.16-02.45,48","/domains/fort/room/gstreet3.c","/domains/amigara/amigara/room/passage1.c","/domains/fort/room/cistern.c","/save/kills/c/clojoebjb","/log/chan/archive/muds-2010.11.08-05.45,48","/log/chan/archive/ichat2-2010.07.23-07.16,17","/domains/default/obj/phints.c","/secure/daemon/include/chat.h","/domains/fort/obj/workbench.c","/doc/efun/all/keys","/secure/cmds/admins/usage.c","/log/chan/archive/muds-2013.08.15-23.13,15","/domains/Praxis/crypt.c","/cmds/players/annoyblock.c","/log/archive/catch-2009.11.17-19.10,44","/secure/include/garbage.txt","/log/chan/archive/intergossip-2013.08.16-16.13,15","/log/chan/archive/i2news-2009.03.24-14.17,31","/log/chan/nschat","/domains/fort/obj/gkey.c","/doc/lfun/lib/lamp/eventLight","/save/kills/k/klnfnb","/doc/efun/all/reset_eval_cost","/doc/sefun/damerau_levenshtein_distance","/doc/lfun/lib/body/RemoveLimb","/log/chan/archive/muds-2010.09.28-20.45,48","/doc/efun/interactive/ed_start","/domains/town/room/postoffice.c","/save/kills/o/onhfgliamak","/log/chan/archive/muds-2009.04.09-18.28,44","/daemon/tmp/exroom5.c","/log/chan/archive/dgd-2010.09.24-04.45,48","/domains/campus/room/stairwell2d.c","/domains/town/npc/beggar.c","/save/kills/x/xkcdflfeb","/log/chan/archive/muds-2013.08.10-15.13,15","/daemon/tmp/science.c","/log/chan/archive/muds-2013.07.29-21.13,15","/domains/Praxis/inn106.c","/secure/include/modules.h","/doc/lfun/lib/interactive/eventDestruct","/doc/lfun/all/GetDeathEvents","/www/lpmuds/skylib-faq.html","/include/magic.h","/domains/default/armor/helmet.c","/domains/fort/room/fguild.c","/doc/lfun/lib/interactive/GetLong","/doc/lfun/lib/genetics/GetBaseStatLevel","/doc/sefun/minutes","/log/chan/archive/muds-2010.09.23-12.45,48","/domains/town/virtual/sky/23,10,1.c","/www/value.jpg","/domains/default/room/stargate_lab.c","/domains/fort/armor/jeans.c","/doc/lfun/all/GetMorality","/log/archive/i3error-2009.05.07-01.13,35","/log/chan/archive/muds-2010.10.09-09.45,48","/domains/default/obj/abox.c","/domains/town/obj/dining_table.c","/log/chan/archive/dgd-2009.03.24-23.11,20","/secure/sefun/morality.c","/log/chan/archive/discworld-chat-2010.08.29-09.45,48","/domains/town/obj/rucksack.c","/domains/fort/weap/fellsword.c","/doc/lfun/lib/body/GetDeathEvents","/secure/cmds/admins/rotatelogs.c","/doc/lfun/lib/light/CanLight","/save/kills/c/cifmenlj","/log/chan/archive/intergossip-2010.07.14-20.16,17","/domains/Praxis/mountains/entrance.c","/doc/efun/filesystem/rm","/www/router.html","/doc/lfun/all/performMarriage","/www/ds-admin-faq.html","/log/chan/archive/muds-2009.05.23-18.21,26","/log/archive/icp-2009.03.16-12.30,39","/save/kills/x/xkcdhbimlbaabh","/log/chan/archive/sport-2013.08.26-08.13,15","/log/chan/archive/muds-2010.12.15-14.45,48","/doc/efun/interactive/set_this_player","/save/services.3333.o","/save/kills/n/njobgdcfc","/cmds/players/colors.c","/log/chan/archive/muds-2009.05.22-11.21,24","/log/chan/archive/free_speech-2011.01.10-23.46,55","/secure/scripts/update.src","/secure/include/save.h","/save/unique.o","/secure/scripts/crat3.src","/log/chan/archive/i2news-2009.05.10-20.58,26","/save/kills/x/xkcdhgnhf","/lib/potion.c","/daemon/tmp/A_SOCK.c","/save/kills/l/lodibfimdkc","/verbs/items/.look.c.swp","/log/chan/archive/muds-2010.09.16-19.45,48","/domains/cave/armor/orc_dress.c",}) +globaltemp "/secure/verbs/creators" diff --git a/lib/secure/save/functions.o b/lib/secure/save/functions.o new file mode 100644 index 0000000..23ccf2c --- /dev/null +++ b/lib/secure/save/functions.o @@ -0,0 +1,6 @@ +#/secure/daemon/function.c +FileSize (["/lib/std/bed.c":289,"/lib/lamp.c":1382,"/lib/events/put.c":2914,"/lib/virtual/virt_sky.c":2362,"/lib/props/body_mass.c":920,"/lib/events/read.c":4163,"/lib/classes.c":4129,"/lib/events/activate.c":676,"/lib/combat.c":33835,"/lib/genetics.c":10027,"/lib/comp/container.c":1373,"/lib/door.c":13617,"/lib/comp/holder.c":2732,"/lib/fish.c":538,"/lib/events/look.c":7684,"/lib/events/jump.c":3189,"/lib/post_office.c":1274,"/lib/virtual/virt_subsurface.c":571,"/lib/comp/surface.c":159,"/lib/events/touch.c":2827,"/lib/std/daemon.c":1283,"/lib/sentient.c":11943,"/lib/events/crawl.c":111,"/lib/events/turn.c":1719,"/lib/std/worn_storage.c":1237,"/lib/trainer.c":143,"/lib/undead.c":2702,"/lib/props/carry.c":1633,"/lib/meal.c":6398,"/lib/std/table.c":344,"/lib/props/inventory.c":3731,"/lib/events/drop.c":2268,"/lib/domesticate.c":4703,"/lib/events/press.c":2376,"/lib/events/consult.c":2208,"/lib/events/dig.c":1216,"/lib/pole.c":2594,"/lib/props/ambiance.c":368,"/lib/follow.c":1459,"/lib/clan.c":5236,"/lib/bank.c":670,"/lib/events/swim.c":109,"/lib/pager.c":13000,"/lib/cigar.c":970,"/lib/std/corpse.c":5900,"/lib/std/bot_limb.c":1213,"/lib/events/apply.c":463,"/lib/flashlight.c":5477,"/lib/lvs/level.c":1591,"/lib/props/value.c":2228,"/lib/props/description.c":3615,"/lib/std/boobytrap_object.c":2470,"/lib/std/germ.c":8565,"/lib/torch.c":1114,"/lib/mount.c":4814,"/lib/history.c":5968,"/lib/events/disarm.c":1354,"/lib/std/room.c":33331,"/lib/events/bury.c":267,"/secure/daemon/bboard.c":3956,"/lib/std/book.c":1404,"/lib/events/get.c":3247,"/lib/spell.c":21439,"/lib/events/dig_with.c":2521,"/lib/chario.c":8153,"/lib/events/search.c":4339,"/lib/player.c":20454,"/lib/magic.c":5291,"/lib/events/roll.c":1890,"/lib/std/base_dummy.c":3316,"/lib/creator.c":7067,"/lib/die.c":2591,"/lib/manycoins.c":231,"/lib/events/pull.c":2246,"/lib/std/barkeep.c":6746,"/lib/props/equip.c":2439,"/lib/events/smoke.c":225,"/lib/currency.c":3235,"/lib/files.c":1096,"/lib/events/lie.c":1709,"/lib/clerk.c":4350,"/lib/blank.c":38,"/lib/std/boobytrap_shadow.c":6598,"/lib/clay.c":1786,"/lib/fishing.c":6219,"/lib/props/mass.c":1026,"/lib/user/autosave.c":2311,"/lib/pipe.c":1740,"/lib/virtual/virtual.c":654,"/lib/vehicle.c":8761,"/lib/rifle.c":181,"/lib/light.c":1417,"/lib/used_meal.c":173,"/lib/std/bane.c":192,"/lib/virtual/virt_map.c":4867,"/lib/help.c":575,"/lib/events/wield.c":1220,"/lib/events/lock.c":7615,"/lib/events/rock.c":561,"/secure/daemon/rooms.c":22900,"/lib/events/scratch.c":2093,"/lib/teacher.c":6910,"/lib/events/buy.c":375,"/lib/events/fly.c":107,"/lib/steal.c":946,"/lib/events/smell.c":3394,"/lib/fuel.c":1502,"/lib/base_trainer.c":7978,"/lib/std/armor.c":151,"/lib/race.c":9401,"/lib/props/move.c":6248,"/lib/bboard.c":9816,"/lib/inventory.c":4032,"/lib/std/limb.c":2870,"/lib/detect.c":3961,"/lib/flow.c":6105,"/lib/events/bait_with.c":1055,"/lib/events/fall.c":2126,"/lib/elevator.c":1651,"/lib/missile.c":3937,"/lib/language.c":3187,"/lib/living.c":28585,"/lib/match.c":1101,"/lib/exits.c":10200,"/lib/events/look_in.c":2823,"/lib/virtual/virt_std.c":1542,"/lib/events/sit.c":1965,"/lib/comp/seal.c":1322,"/lib/vi.c":46921,"/lib/std/bot_corpse.c":1916,"/lib/chamber.c":9463,"/lib/npc.c":19482,"/lib/events/poison.c":863,"/lib/daemons/player_stub.c":489,"/daemon/soul.c":12189,"/lib/editor.c":1416,"/lib/battery.c":2447,"/lib/persist.c":4097,"/lib/teach.c":2465,"/lib/events/load.c":1665,"/lib/clip.c":4739,"/lib/cgi.c":901,"/secure/daemon/imc2.c":60943,"/lib/events/knock.c":2036,"/lib/events/bait.c":877,"/lib/stargate.c":7594,"/lib/std/lockpick.c":991,"/lib/std/furnace.c":1056,"/lib/nmsh.c":36415,"/lib/events/swivel.c":581,"/lib/firearm.c":15908,"/lib/std/vendor.c":18554,"/lib/messages.c":2152,"/lib/props/save.c":3356,"/lib/events/show.c":382,"/lib/comp/object.c":1257,"/lib/blank_pile.c":781,"/lib/chapel.c":3421,"/lib/std/base_storage.c":5042,"/lib/events/manipulate.c":2256,"/lib/events/shake.c":2160,"/lib/lvs/abilities.c":9268,"/lib/std/item.c":9494,"/lib/std/chair.c":507,"/lib/teller.c":12004,"/lib/events/climb.c":3927,"/lib/trap.c":3733,"/lib/shadow.c":671,"/lib/poison.c":1423,"/lib/remote.c":3373,"/lib/events/lock_with.c":1933,"/lib/props/id.c":5953,"/lib/props/clean.c":3056,"/lib/cedit.c":18693,"/lib/events/sink.c":1648,"/lib/comp/weapon.c":5126,"/lib/std/story.c":3147,"/lib/lead.c":4469,"/lib/daemons/verb.c":1933,"/lib/enter.c":4467,"/lib/body.c":62228,"/lib/elevator_button.c":876,"/lib/leader.c":5969,"/lib/props/properties.c":1095,"/lib/props/uniqueness.c":971,"/lib/bonus.c":3122,"/lib/events/stop.c":1642,"/lib/props/radiance.c":463,"/lib/events/describe.c":14332,"/lib/props/addstuff.c":491,"/lib/events/install.c":2126,"/lib/lvs/position.c":6225,"/lib/interface.c":14097,"/lib/bot.c":3707,"/lib/props/deterioration.c":1995,"/lib/std/storage.c":772,"/lib/command.c":17232,"/lib/events/close.c":2077,"/lib/learn.c":326,"/lib/cylinder.c":358,"/lib/pile.c":3605,"/lib/events/shoot.c":2204,"/lib/combatmsg.c":8365,"/lib/events/get_from.c":6425,"/lib/pistol.c":137,"/lib/events/listen.c":3267,"/lib/props/damage.c":1181,"/lib/shop.c":812,"/lib/chat.c":7864,"/lib/burn.c":4561,"/lib/quest.c":3066,"/lib/std/base_armor.c":15085,"/lib/money.c":661,"/lib/std/wound.c":2372,"/lib/shadow_hook.c":493,"/lib/flask.c":6504,"/lib/events/sell.c":500,"/lib/round.c":3732,"/lib/std/dummy.c":496,"/lib/events/give.c":1468,"/lib/guard.c":4281,"/lib/donate.c":1843,"/lib/events/aim.c":2197,"/lib/interactive.c":18919,"/lib/events/drink.c":611,"/lib/virtual/virt_land.c":5943,"/lib/talk.c":12462,"/lib/shell.c":879,"/lib/potion.c":1132,"/lib/mayor.c":2213,"/lib/events/wear.c":955,]) +FunctionCache (["/lib/std/bed.c":"int CanGet(object who){ void create(){ ","/lib/lamp.c":"string GetShort(){ static void create(){ varargs string GetLong(string unused){ int GetRadiantLight(int ambient){ mixed direct_light_obj(){ mixed eventDarken(){ varargs mixed eventLight(object who, object tool){ static void heart_beat(){ static int SetBurnRate(int x){ int GetBurnRate(){ ","/lib/events/put.c":"static void create(){ varargs mixed CanPut(object who, object what){ mixed direct_put_obj_word_obj(){ mixed direct_put_wrd_wrd_word_obj(){ mixed direct_put_obj_obj(){ mixed GetPreventPut(){ mixed SetPreventPut(mixed val){ ","/lib/virtual/virt_sky.c":"varargs static void create(int x, int y,int z){ mixed eventReceiveObject(object ob){ mixed CanFly(object who, string dir){ mixed eventFly(object who, string dir){ varargs static void Setup(int x, int y,int z){ string GetGround(){ mixed GetPreventLand(){ string SetGround(string str){ mixed SetPreventLand(mixed val){ ","/lib/props/body_mass.c":"int GetMass(){ int SetZPG(int x){ int GetZPG(){ int AddBodyMass(int x){ int GetBodyMass(){ int SetBodyMass(int x){ int GetWeight(){ ","/lib/events/read.c":"varargs mixed eventRead(object who, mixed str){ void SetReads(mapping ReadMap){ string GetRead(string str){ string array GetReads(){ mapping GetReadsMap(){ void RemoveRead(string item){ varargs mixed SetDefaultRead(mixed arg1, mixed desc){ int SetLanguage(string str){ mixed GetLanguage(){ mixed direct_read_obj(){ mixed direct_read_str_word_obj(string str){ mixed direct_read_obj_at_obj(object reader, object readee){ ","/lib/classes.c":"static void create(){ int AddSkillPoints(string skill, int x){ string GetMoralityDescription(){ int eventMoralAct(int degree){ int ClassMember(string class_name){ string SetClass(string class_name){ string GetClass(){ return Class; } mixed ChangeClass(string class_name){ int GetBaseStatLevel(string stat){ return 0; } string GetSkillModifier(string skill){ return SkillModifiers[skill]; } string SetClan(string clan){ return (Clan = clan); } string GetClan(){ return Clan; } int SetMorality(int x){ return (Morality = x); } string array SetReligion(string adj, string noun){ varargs string GetReligion(int flag){ return Religion[flag]; } static string SetSkillModifier(string skill, string stat){ ","/lib/events/activate.c":"int direct_activate_obj_on_obj(object target, object where){ int direct_deactivate_obj(object target){ int direct_deactivate_obj_on_obj(object target, object where){ int direct_activate_str_on_obj(string target, object where){ int direct_deactivate_str_on_obj(string target, object where){ ","/lib/combat.c":"static void heart_beat(){ varargs int eventReceiveDamage(mixed agent, int type, int x, int internal, mixed eventBite(object target){ mixed eventTurn(object who){ static void create(){ int GetLevel(){ int GetMaxCarry(){ varargs int eventDie(mixed agent){ void eventEnemyDied(object ob){ varargs int SetParalyzed(int count, function f){ int GetBaseStatLevel(string stat){ int GetParalyzed(){ return cParalyzed; } static int Destruct(){ int RemoveHostile(object ob){ int eventQuell(){ int eventUnQuell(){ string SetParty(string str){ string GetParty(){ varargs int SetAttack(mixed target, function callback, int type){ string SetWimpyCommand(string cmd){ string GetWimpyCommand(){ int GetMagicChance(int val){ int GetMagicResistance(){ varargs int GetPenalty(object other){ int GetCombatChance(int val){ int GetDefenseChance(int val){ void eventKillEnemy(object ob){ int GetCombatBonus(int level){ static int GetDamage(int power, string skill){ int CanWeapon(object target, string type, int hands, int num){ int CanMelee(object target){ int eventPreAttack(object agent){ varargs int eventReceiveAttack(int speed, string def, object agent){ int eventExecuteAttack(mixed target){ int eventWeaponRound(mixed target, mixed val){ void eventWeaponAttack(object target, object weapon, int num){ int GetInCombat(){ void eventDestroyEnemy(object ob){ int GetDead(){ int eventMeleeRound(mixed target, function f){ void eventMeleeAttack(object target, string limb){ int eventMagicRound(mixed target, function f){ int eventWimpy(int i){ int GetVisibility(){ int SetDead(int i){ object array GetEnemies(){ int AddEnemy(object ob){ int RemoveEnemy(object ob){ object SetCurrentEnemy(object ob){ static object ResetCurrentEnemy(){ object GetCurrentEnemy(){ private static void SortEnemies(){ mixed array AddNonTargets(mixed val){ mixed array RemoveNonTargets(mixed val){ object array GetNonTargets(){ int AddHostile(object ob){ object array GetHostiles(){ object array GetSpecialTarget(){ object array SetSpecialTarget(object array cibles){ ","/lib/genetics.c":"static void create(){ varargs mixed GetEffectiveVision(mixed location, int raw_score){ static void heart_beat(){ string GetResistance(int type){ varargs void SetStat(string stat, int level, int classes){ varargs static int array SetLightSensitivity(mixed array val...){ string array GetStats(){ return keys(Stats); } int GetStatClass(string stat){ int array GetLightSensitivity(){ int AddVisionBonus(int x){ int GetVisionBonus(){ int GetBlind(){ static void RemoveBlindness(){ varargs void AddStat(string stat, int base, int cls){ int GetBaseStatLevel(string stat){ int AddStatPoints(string stat, int x){ int GetMaxStatPoints(string stat, int level){ void AddStatBonus(string stat, mixed f){ varargs void RemoveStatBonus(string stat, object ob){ int GetStatBonus(string stat){ varargs string SetResistance(int type, string level){ int GetCustomStats(){ return Custom[\"stats\"]; } varargs mixed eventBlind(object who, int amt, mixed end){ mixed eventDeviateStat(string stat, int amount){ mixed eventRestoreSight(object who, int amt){ mapping GetResistanceMap(){ int GetCustomDeviations(){ return Custom[\"deviations\"]; } int GetDeviating(){ return Custom[\"deviating\"]; } int SetDeviating(int x){ return (Custom[\"deviating\"] = (x ? 1 : 0)); } mixed eventCustomizeStat(string stat, int amount){ int GetStatLevel(string stat){ mapping GetStatsMap(){ return copy(Stats); } ","/lib/comp/container.c":"int GetOpacity(){ int SetOpacity(int x){ int GetRadiantLight(int ambient){ int CanRelease(object ob){ int CanReceive(object ob){ int eventReceiveObject(object ob){ int eventReleaseObject(object ob){ mixed eventPostRelease(object ob){ ","/lib/door.c":"static void create(){ varargs mixed eventClose(object who){ string GetDefiniteShort(){ varargs int eventOpen(object who, object tool){ varargs string array SetKeys(string side, mixed array args...){ string array GetKeys(string side){ return Sides[side][\"Keys\"]; } mixed CanLock(object who, string foo){ mixed CanUnlock(object who){ varargs mixed eventLock(object who, mixed key, mixed foo){ mixed eventUnlock(object who, object key){ varargs mixed eventKnock(object who, mixed what){ varargs mixed eventScratch(object who, mixed what){ string array GetId(string side){ varargs string GetShort(string side){ string GetLong(string side){ mixed SetLong(string side, mixed long){ int eventRegisterSide(string side){ void SetSide(string side, mapping mp){ mixed SetShort(string side, mixed short){ int GetOpacity(){ int SetOpacity(int x){ int GetHiddenDoor(){ varargs string array SetId(string side, mixed array args...){ int get_closed(){ return GetClosed(); } int SetLockable(string side, int x){ int GetLockable(string side){ object array GetRooms(string side){ return Sides[side][\"Rooms\"]; } int GetPerforated(){ int SetPerforated(int x){ int CanPeer(){ int SetHiddenDoor(int i){ string array GetSides(){ ","/lib/comp/holder.c":"mixed inventory_visible(){ varargs string GetInternalDesc(){ int GetOpacity(){ int SetOpacity(int x){ int CanReceive(object ob){ int eventReceiveObject(object ob){ int eventReleaseObject(object ob){ static void eventLoadInventory(){ static void create(){ int isBag(){ static mixed array AddSave(mixed array vars){ int SetSaveRecurse(int x){ ","/lib/fish.c":"static void create(){ string GetFood(){ return Food; } string SetFood(string str){ return (Food = str); } int SetFight(int x){ return (Fight = x); } int eventCatch(object who){ return 1; } int GetFight(){ return Fight; } ","/lib/events/look.c":"varargs string GetExternalDesc(object who){ string SetExternalDesc(string desc){ mixed SetInvis(mixed val){ varargs mixed AddItem(mixed item, mixed val){ static mixed AddItem_func(mixed foo){ static mixed SetItem_func(mixed foo){ string array GetItems(){ mapping GetItemsMap(){ mapping RemoveItem(mixed item){ mapping SetItems(mapping items){ mapping SetItem_desc(mapping items){ varargs string GetLong(string str){ string SetLong(string str){ varargs mixed eventShow(object who, string component){ mixed direct_look_obj(){ mixed direct_look_at_obj(){ mixed direct_look_on_obj(){ mixed direct_look_at_obj_on_obj(object target, object ob,mixed arg, mixed arg2){ mixed direct_look_at_obj_word_obj(){ mixed direct_look_at_str_on_obj(string str, object target){ varargs int GetInvis(object ob){ ","/lib/events/jump.c":"varargs mixed direct_jump_word_word_obj(mixed args...){ mixed direct_jump_word_obj(string prep, object target, string id){ mapping GetJumps(){ varargs mixed AddJump(string name, mixed saute, int type){ mixed CanJump(object who, string id, int type){ mixed eventJump(object who, string id, int type){ ","/lib/post_office.c":"static void create(){ int CanReceive(object ob){ int eventReleaseObject(object foo){ mixed CanMail(object who, string args){ mixed eventMail(object who, string args){ ","/lib/virtual/virt_subsurface.c":"varargs static void create(int x, int y,int z){ mixed eventReceiveObject(object ob){ varargs static void Setup(int x, int y,int z){ string GetGround(){ string SetGround(string str){ ","/lib/comp/surface.c":"void create(){ int eventPutOn(object player, object item){ ","/lib/events/touch.c":"mixed direct_touch_str_word_obj(string str){ varargs mixed SetTouch(mixed array args...){ mapping RemoveTouch(string item){ varargs mixed eventTouch(object who, string str){ string array GetTouches(){ mixed direct_touch_obj(){ static void create(){ ","/lib/std/daemon.c":"static void create(){ int eventDestruct(){ string GetSaveFile(){ static string SetSaveFile(string str){ varargs int eventRestore(int do_not_zero_out){ varargs int eventSave(int save_zero_values){ ","/lib/sentient.c":"static void heart_beat(){ static int ContinueHeart(){ mixed eventTalkRespond(object who, object targ, int cls, string msg, string lang){ varargs mixed eventReceiveEmote(object who, string verb, string info){ mixed AddConsultResponse(string str, mixed val){ mapping GetConsultResponses(){ int RemoveConsultResponse(string str){ mapping SetConsultResponses(mapping mp){ mapping AddCommandResponses(mapping mp){ mapping GetCommandResponses(){ int RemoveCommandResponse(string str){ mapping SetCommandResponses(mapping mp){ mixed AddEmoteResponse(string verb, mixed val){ mapping GetEmoteResponses(){ int RemoveEmoteResponse(string verb){ mapping SetEmoteResponses(mapping mp){ mapping AddRequestResponses(mapping mp){ mapping GetRequestResponses(){ int RemoveRequestResponse(string str){ mapping SetRequestResponses(mapping mp){ mixed AddTalkResponse(string str, mixed val){ int RemoveTalkResponse(string str){ mapping GetTalkResponses(){ mapping SetTalkResponses(mapping mp){ int SetSpellChance(int i){ int GetSpellChance(){ varargs int SetWander(int speed, mixed array path, int recurse){ mixed array GetWanderPath(){ mixed array SetWanderPath(mixed array path){ int GetWanderRecurse(){ int SetWanderRecurse(int x){ int GetWanderSpeed(){ int SetWanderSpeed(int x){ int SetPermitLoad(mixed i){ int GetPermitLoad(){ mixed eventAsk(object who, string str){ mixed eventConsult(object who, string str){ mixed eventRequest(object who, string str){ mixed eventWander(){ ","/lib/events/crawl.c":"mixed direct_crawl_str(string str){ mixed direct_crawl_into_str(string str){ ","/lib/events/turn.c":"int eventTurn(object who){ int direct_turn_on_obj_on_obj(object target, object thinger){ int indirect_turn_on_obj_on_obj(object thinger, object target){ int direct_turn_off_obj_on_obj(object target, object thinger){ int indirect_turn_off_obj_on_obj(object thinger, object target){ int direct_turn_obj_on_obj_on(object target, object thinger){ int indirect_turn_obj_on_obj_on(object thinger, object target){ int direct_turn_obj_on_obj_off(object target, object thinger){ int indirect_turn_obj_on_obj_off(object thinger, object target){ varargs mixed CanTurn(object who, object what){ int direct_turn_obj_off(object target){ mixed eventTurnOff(object ob){ mixed eventTurnOn(object ob){ varargs mixed CanTurnOn(object who, object what){ varargs mixed CanTurnOff(object who, object what){ ","/lib/std/worn_storage.c":"void create(){ varargs string array AddSave(string array args){ string array GetSave(){ mixed eventEquip(object who, string array limbs){ varargs mixed eventUnequip(object who){ varargs string GetExternalDesc(object who){ mixed direct_remove_obj(){ mixed direct_wear_obj(){ void init(){ varargs string GetEquippedDescription(object who){ string GetEquippedShort(){ ","/lib/trainer.c":"static void create(){ ","/lib/undead.c":"mixed eventBite(object target){ mixed eventTurn(object who){ string GetUndeadType(){ static void heart_beat(){ string SetUndeadType(string str){ int GetGhost(){ ","/lib/props/carry.c":"int SetMaxCarry(int x){ int CanCarry(int amount){ int GetMaxCarry(){ static int SetCarriedMass(int x){ int GetLivingMaxCarry(){ int AddCarriedMass(int x){ int GetCarriedWeight(){ int GetCarriedMass(){ int CalculateCarriedMass(){ ","/lib/meal.c":"string GetShort(){ return item::GetShort(); } static void create(){ int eventDestruct(){ return item::eventDestruct(); } static mixed AddSave(mixed array vars){ return item::AddSave(vars); } int GetValue(){ int eventPoison(object who, object agent, int x){ int GetStrength(){ return MealStrength; } int GetMealType(){ return MealType; } mixed eventDrink(object who){ mixed eventEat(object who){ int SetMealAction(function f){ mixed GetEmptyLong(){ return EmptyLong; } string SetEmptyItem(string file){ return (EmptyItem = file); } string SetEmptyName(string str){ return (EmptyName = str); } mixed direct_drink_obj(){ mixed SetEmptyShort(mixed val){ return (EmptyShort = val); } string GetEmptyName(){ return EmptyName; } string GetEmptyItem(){ return EmptyItem; } mixed GetEmptyShort(){ return EmptyShort; } mixed direct_eat_obj(){ mixed SetEmptyLong(mixed val){ return (EmptyLong = val); } mixed direct_drink_from_obj(){ mixed array GetMealMessages(){ return ({ MyMessage, OtherMessage }); } varargs void SetMealMessages(mixed array val...){ int SetMealType(int x){ int SetStrength(int x){ return (MealStrength = x); } ","/lib/std/table.c":"int CanGet(object who){ void create(){ void init(){ ","/lib/props/inventory.c":"static void eventLoadInventory(){ static void eventLoadItem(string file, mixed args, int count){ mapping GetInventory(){ mapping SetInventoryCheck(mapping newmap){ void heart_beat(){ varargs void reset(){ ","/lib/events/drop.c":"mixed SetPreventDrop(mixed val){ int GetDestructOnDrop(){ int SetDestructOnDrop(int val){ mixed CanDrop(object who){ mixed direct_drop_obj(object target){ mixed GetPreventDrop(){ ","/lib/domesticate.c":"int eventAbandon(object who){ varargs int eventTrainLiving(object who, string what){ varargs int eventUnTrainLiving(object who, string what){ string array GetTrainedSkilles(){ string array SetTrainedSkills(string array skills){ string eventCommandNPC(object who, string cmd){ varargs mixed SetBefriended(mixed who){ varargs mixed GetBefriended(mixed who){ mixed direct_untrain_liv_to_str(){ mixed direct_command_liv_to_str(){ object GetMountOwner(){ int CanTrain(){ mixed direct_train_liv_to_str(){ mixed direct_befriend_liv(){ object SetMountOwner(object who){ int SetCanBefriend(int i){ int SetCanTrain(int i){ int CanAbandon(object who){ mixed direct_abandon_liv(){ int CanUnTrain(){ int SetCanCommand(int i){ int eventBefriend(object who){ ","/lib/events/press.c":"mixed direct_press_obj(object target){ mixed direct_press_str_on_obj(string str, object target){ string array GetPresses(){ mapping RemovePress(string item){ varargs mapping SetPress(mixed key, mixed desc){ varargs mixed CanPress(object who, string component){ varargs mixed eventPress(object who, string component){ ","/lib/events/consult.c":"varargs mixed eventConsult(object who, string component){ string array GetConsults(){ mapping RemoveConsult(string item){ varargs mapping SetConsult(mixed key, mixed desc){ varargs mixed CanConsult(object who, string component){ mixed direct_consult_obj(object target){ mixed direct_consult_str_on_obj(string str, object target){ ","/lib/events/dig.c":"mixed CanDig(object who){ mixed GetDig(){ mixed SetDig(mixed val){ int RemoveDig(){ mixed direct_dig_obj_with_obj(){ mixed eventDig(object who, object tool){ ","/lib/pole.c":"static void create(){ int GetStrength(){ return PoleStrength; } mixed AddSave(mixed array vars){ return ({}); } mixed CanCast(object who){ mixed direct_fish_with_obj(){ int eventBreak(){ int eventFish(object who){ mixed direct_cast_obj(){ int GetChance(){ return CatchChance + GetProperty(\"blessed\"); } int SetChance(int x){ return (CatchChance =x); } mixed eventCatch(object who, string fish){ int SetStrength(int x){ return (PoleStrength = x); } ","/lib/props/ambiance.c":"int GetAmbientLight(){ int SetAmbientLight(int x){ ","/lib/follow.c":"static void create(){ Leader = 0; } object GetLeader(){ return Leader; } varargs mixed CanFollow(object ob){ int IsFollowing(object ob){ int eventFollow(object dest, int fC){ return 0; } mixed direct_follow_liv(){ object SetLeader(object leader){ ","/lib/clan.c":"static void create(){ static void init(){ string GetLeader(){ return Clan->leader; } string SetLeader(string str){ string GetAffectLong(object ob){ int eventInitiate(string str){ int eventRetire(string str){ string GetClanSkill(){ return Clan->skill; } void eventUnjoin(object ob){ string GetClanName(){ return Clan->name; } int eventBring(string str){ string SetClanObject(string str){ string GetClanObject(){ return Clan->objectName; } string SetClanSkill(string str){ string SetClanName(string str){ mixed CanJoin(object ob){ return 1; } void eventWelcome(object ob){ void eventJoin(object ob){ ","/lib/bank.c":"static void create(){ void init(){ mixed teller_check(){ int HandleTeller(string str){ ","/lib/events/swim.c":"mixed direct_swim_into_str(string str){ mixed direct_swim_str(string str){ ","/lib/pager.c":"varargs mixed eventPage(mixed val, mixed msg_class, function f,mixed args...){ string GetHelp(string str){ mixed more(mixed val, string cl, function f, mixed args){ static void cmdPage(string str, mapping file){ varargs static private void RazzleDazzle(mixed args...){ static private string GetPagerPrompt(mapping file){ ","/lib/cigar.c":"static void create(){ varargs string GetLong(string unused){ string GetShort(){ int GetRadiantLight(int ambient){ mixed eventSmoke(object who, object what){ int GetLastPuff(){ ","/lib/std/corpse.c":"int CanReceive(object ob){ return 1; } static void create(){ string GetItemCondition(){ return \"\";} static int Destruct(){ string GetCapName(){ string GetSaveString(){ return 0; } string SetClass(string the_class){ string GetClass(){ string GetGender(){ int GetLevel(){ mapping SetSkills(mapping skills){ string array GetMissingLimbs(){ string GetRace(){ return Race; } mapping SetStats(mapping stats){ mapping GetStats(){ void SetCorpse(object who){ mixed direct_resurrect_obj(){ return 1; } mixed indirect_resurrect_obj(){ return 1; } string GetHealthShort(){ int isFreshCorpse(){ int SetLevel(int level){ string SetGender(string gender){ mapping GetSkills(){ int eventDecay(){ string GetLivingShort(){ int direct_animate_obj(){ int GetCount(int i){ int SetNoDecay(int i){ string SetBaseFile(string file){ int GetNoDecay(){ int SetCount(int i){ string array SetMissingLimbs(string array limbs){ int SetSlowDecay(int i){ int GetSlowDecay(){ string SetLivingLong(string long){ int direct_offer_obj(){ string SetLivingShort(string short){ string GetOwner(){ return Owner; } int isCorpse(){ int isPlayer(){ object GetPlayerob(){ string GetBaseFile(){ string GetLivingLong(){ mapping GetEquipped(){ ","/lib/std/bot_limb.c":"static void create(){ void init(){ void SetLimb(string limb, string owner, string race){ int eventDecay(){ ","/lib/events/apply.c":"mixed CanApply(object applicant){ mixed direct_apply_obj_word_obj(){ mixed indirect_apply_obj_word_obj(){ ","/lib/flashlight.c":"string GetShort(){ int CanReceive(object ob){ void heart_beat(){ void create(){ void init(){ int eventTurnOn(object ob){ varargs mixed eventTurnOff(string str){ int eventDie(){ varargs int eventUse(mixed i, mixed foo){ void regetID(){ int flicker(){ int SetMinCells(int i){ mincells = i; return i; } int SetMaxCells(int i){ maxcells = i; return i; } int SetCellType(string str){celltype=str; return 1; } int GetMinCells(){ return mincells; } int SetHB(int i){ int GetMaxCells(){ return maxcells; } void SetLightLevel(int i){ int SetDrainRate(int i){ string GetCellType(){ return celltype; } int eventRadiate(int i){ int GetHB(){ int CheckPower(){ int GetLightLevel(){ mixed eventExtinguish(){ mixed eventLight(){ ","/lib/lvs/level.c":"int collect_moduli(int mod, int array range){ varargs int ChangeLevel(int i){ ","/lib/props/value.c":"int GetDestroyOnSell(){ int SetDestroyOnSell(int x){ int GetVendorType(){ int SetVendorType(int x){ int SetDollarCost(int x){ varargs int GetValue(string str){ varargs mixed SetBaseCost(mixed arg, int i){ string array GetSave(){ int GetBaseCost(string str){ int SetValue(mixed y){ ","/lib/props/description.c":"string GetShort(){ mixed direct_add_obj_to_obj(){ return 1; } mixed direct_reload_obj(){ return 1; } mixed indirect_reload_obj(){ return 1; } varargs mixed SetShort(mixed val, int proper){ int GetModify(){ int GetNoModify(){ int SetNoModify(int i){ mixed indirect_delete_obj_from_obj(){ string GetDefiniteShort(){ mixed direct_reload_every_str(){ return 1; } mixed indirect_reload_every_str(){ return 1; } mixed direct_copy_obj_to_obj(){ return 1; } mixed indirect_add_obj_to_obj(){ return 1; } mixed indirect_read_obj_at_obj(){ return 1; } mixed indirect_delete_obj_from_here(){ return 1; } mixed direct_delete_obj_from_room(){ return 1; } mixed indirect_delete_obj_from_room(){ return 1; } mixed indirect_add_obj_to_here(){ return 1; } mixed indirect_add_obj_to_room(){ return 1; } mixed direct_createfix_obj(){ mixed direct_copy_obj_str(){ return 1; } mixed direct_initfix_obj(){ object array GetDummyItems(){ mixed direct_modify_obj_str(){ mixed direct_modify_word_str(){ mixed direct_reload_word_obj(){ return 1; } mixed indirect_reload_word_obj(){ return 1; } mixed direct_reload_str_obj(){ return 1; } mixed indirect_reload_str_obj(){ return 1; } mixed direct_reload_str_word(){ return 1; } mixed indirect_reload_str_word(){ return 1; } ","/lib/std/boobytrap_object.c":"void create(){ void init(){ varargs mixed CanBoobytrap(object who, mixed what){ string GetShadowObject(){ int GetTrapType(){ int SetAutoResets(int i){ string SetShadowObject(string str){ int GetAutoResets(){ varargs int eventBoobytrap(object who, mixed target, mixed trap){ int SetTrapType(int i){ ","/lib/std/germ.c":"static void create(){ void init(){ static void heart_beat(){ mixed eventCure(object who, int x, string type){ string GetType(){ mixed eventInfect(object ob){ int GetCannotInfect(){ string SetType(string type){ int SetGermName(string str){ function GetInfect(){ int SetLifeSpan(mixed x){ int SetCannotInfect(int i){ mixed eventMultiply(){ string GetGermName(){ mixed eventEncounter(object who){ int GetCommunicable(){ int SetCommunicable(int x){ void eventSuffer(object ob){ int GetLifeSpan(){ function SetInfect(function f){ int isGerm(){ mixed GetCure(){ mixed SetCure(mixed val){ ","/lib/torch.c":"static void create(){ varargs string GetLong(string unused){ string GetShort(){ int GetRadiantLight(int ambient){ int direct_pray_for_str_for_obj(){ return 1; } ","/lib/mount.c":"int GetMount(){ return Mount; } object array GetRiders(){ mixed direct_ride_word_str(){ mixed direct_ride_str(){ mixed direct_mount_liv(){ mixed direct_dismount_liv(){ mixed direct_dismount_from_liv(){ int eventRide(string direction){ object array AddRider(object ob){ object array RemoveRider(object ob){ varargs mixed eventDismount(object who, int quiet, int forced){ mixed eventBuck(object who){ int SetMount(int x){ varargs mixed eventMount(object who, int quiet, int forced){ ","/lib/history.c":"string GetLastCommand(){ static string Push(string cmd){ string GetHistory(mixed val){ int GetCommandNumber(){ mapping GetHistoryList(){ mapping GetCommandHist(){ int SetHistorySize(int x){ int GetMaxCommandHistSize(){ int SetMaxCommandHistSize(int i){ static string eventHistory(string str){ ","/lib/events/disarm.c":"varargs mixed eventDisarm(mixed arg){ mixed direct_disarm_obj(){ mixed direct_boobytrap_obj_with_obj(){ mixed indirect_boobytrap_obj_with_obj(){ ","/lib/std/room.c":"static void create(){ int eventDestruct(){ int inventory_visible(){ string GetInternalDesc(){ int CanReceive(object ob){ int eventReceiveObject(object ob){ int eventReleaseObject(object ob){ mixed eventPostRelease(object ob){ mixed CanFly(object who, string dest){ void SetSky(){ varargs mixed GetSearch(){ varargs void RemoveSearch(mixed item){ varargs void SetSearch(mixed items, mixed arg){ object array GetDummyItems(){ void heart_beat(){ varargs void reset(int count){ mapping GetItemsMap(){ mapping RemoveItem(mixed item){ mapping SetItems(mixed items){ string GetLong(){ string SetLong(string str){ varargs int eventShow(object who, string args){ varargs void AddItem(mixed item, mixed val, mixed adjectives){ mixed SetProperty(string prop, mixed val){ mixed SetProperties(mapping mp){ int GetAmbientLight(){ varargs void SetRead(mixed items, mixed arg){ void RemoveRead(mixed item){ string array GetId(){ return ({}); } varargs int eventPrint(string msg, mixed arg2, mixed arg3){ string GetClimate(){ return Climate; } int GetResetNumber(){ int GetNightLight(){ int GetDayLight(){ int GetShade(){ varargs mixed DestructEmptyVirtual(object ob){ mixed direct_delete_exit_str(){ mixed indirect_delete_exit_str(){ void CheckActions(){ void SetAction(int chance, mixed val){ mapping GetActionsMap(){ mapping SetActionsMap(mapping ActMap){ int SetFrequency(int tick){ int GetFrequency(){ int GetTerrainType(){ int SetTerrainType(int i){ int AddTerrainType(int i){ int RemoveTerrainType(int i){ function GetBury(){ function SetBury(function what){ static string GetExtraLong(){ int eventMove(){ return 0; } static int SetNightLight(int x){ static int SetDayLight(int x){ int GetRespirationType(){ mixed CanSwim(object who, string dest){ string SetDayLong(string str){ return (DayLong = str); } string GetDayLong(){ return DayLong; } string SetNightLong(string str){ return (NightLong = str); } string GetNightLong(){ return NightLong; } string SetClimate(string str){ float SetGravity(float h){ return (Gravity = h); } float GetGravity(){ return Gravity; } mapping GetSmellMap(){ mapping GetListenMap(){ mapping QueryMap(string str){ varargs void SetSmell(mixed items, mixed arg){ varargs void SetListen(mixed items, mixed arg){ varargs void AddListen(mixed item, mixed val){ varargs void RemoveListen(mixed item){ int SetMedium(int medium){ int GetMedium(){ int GetClimateExposed(){ int SetNoReplace(int x){ return (NoReplace = x); } int GetNoReplace(){ return NoReplace; } int GetPlayerKill(){ int SetPlayerKill(int x){ int AddPoisonGas(int x){ int GetPoisonGas(){ int SetPoisonGas(int x){ varargs void AddRead(mixed item, mixed val, string lang){ static int SetShade(int x){ varargs void AddSearch(mixed item, mixed val){ int SetNoObviousExits(int i){ int GetNoObviousExits(){ int GenerateObviousExits(){ void CompileNeighbors(mixed coords){ string SetFlyRoom(string str){ string SetSinkRoom(string str){ int SetNoSink(int i){ int GetNoSink(){ string SetSkyDomain(string str){ string GetSkyDomain(){ int SetFlowLimit(int i){ int GetFlowLimit(){ int SetRespirationType(int i){ mixed GetNeighbors(){ mixed GetNeighborCoords(){ mixed GetCoords(){ string SetCoordinates(string str){ static void init(){ string GetElevator(){ string SetElevator(string str){ string GetFlyRoom(){ string GetSinkRoom(){ varargs void AddSmell(mixed item, mixed val){ varargs void RemoveSmell(mixed item){ varargs void AddTouch(mixed item, mixed val){ varargs void SetTouch(mixed items, mixed arg){ varargs void RemoveTouch(mixed item){ string GetTown(){ return Town; } string SetTown(string town){ return (Town = town); } int CanAttack( object attacker, object who ){ mixed eventBuryItem(object who, object tool, object what){ varargs mixed eventHearTalk(object who, object target, int cls, string verb, int inventory_accessible(){ int SetNoDefaultExits(int i){ int SetDefaultExits(int i){ int SetCanFly(int i){ int SetCanSwim(int i){ int SetCanStand(int i){ int SetCanSit(int i){ int SetCanKneel(int i){ ","/lib/events/bury.c":"mixed direct_bury_obj_with_obj(){ ","/secure/daemon/bboard.c":"void create() { static private int valid_access() { void add_post(string id, string who, string subj, string msg) { void mark_read(string id, int post, string reader) { mapping array query_posts(string id) { int query_number_posts(string id) { void remove_post(string id, int post) { string list_new_posts(string id){ static private void save_board() { static private void restore_board() { ","/lib/std/book.c":"void create(){ void init(){ void SetTitle(string title){ void SetSource(string source){ void LoadBook(){ string ReadBook(mixed args...){ string ReadBookIndex(){ mixed GetTitle(){ string GetSource(){ mixed array eventLoadChapters(){ string eventLoadIndex(){ ","/lib/events/get.c":"static void create(){ mixed GetPreventGet(){ mixed CanGet(object who){ mixed direct_get_obj(object target){ mixed direct_get_obj_out_of_obj(object target, object src){ mixed direct_get_obj_from_obj(object target, object src){ mixed direct_get_obj_obj(object target, object src){ mixed SetPreventGet(mixed val){ ","/lib/spell.c":"static void create(){ int GetMorality(){ static mapping SetSkills(mapping mp){ varargs static string array SetRules(mixed args...){ int GetDamage(){ int GetSpellType(){ int GetRequiredSkill(string skill){ varargs int CanCast(object who, int level, string limb, object array targets){ string GetVerb(){ int GetRequiredMagic(){ int GetRequiredStamina(){ varargs mixed eventParse(object who, mixed array args...){ varargs object array GetTargets(object who, mixed args...){ int GetAutoHeal(){ static int SetMorality(int x){ string GetErrorMessage(){ int GetDamageType(){ varargs string array GetMessage(int damage, int healing){ varargs int eventCast(object who, int level, mixed limb, object array targets){ string array GetSkills(){ string array GetRules(){ int GetStaminaCost(){ varargs static string array SetReligions(string array religions...){ int GetHealing(){ static varargs int array SetStaminaCost(mixed args...){ static int CanSpellAttack(object who, object array enemies, int power){ varargs static void SetDamage(int type, mixed array rest...){ static int SetRemoteTargets(int x){ static string SetConjure(string str){ int GetDifficulty(){ static int SetAutoDamage(int x){ static int SetSpellType(int x){ static int SetRequiredMagic(int x){ static varargs int array SetMagicCost(mixed args...){ static int SetAutoHeal(int x){ int GetRemoteTargets(){ static int SetDifficulty(int x){ static mixed array SetMessages(mixed array messages){ string array GetReligions(){ static int SetTrainingModifier(int modifier){ int GetTrainingModifier(){ int GetMagicCost(){ static varargs int array SetHealing(mixed args...){ static int SetRequiredStamina(int x){ string GetConjure(){ int GetAutoDamage(){ static string SetVerb(string verb){ ","/lib/events/dig_with.c":"varargs mixed CanBuryWith(object who, object what){ varargs mixed CanDigWith(object who, object what){ mixed direct_dig_with_obj(){ mixed indirect_dig_obj_with_obj(object what){ mixed direct_bury_str_with_obj(string str){ mixed direct_dig_str_with_obj(string what){ mixed eventBuryWith(object who, object what){ varargs mixed eventDigWith(object who, object what){ mixed indirect_bury_obj_with_obj(object what){ ","/lib/chario.c":"void create(){ void heart_beat(){ int GetCharmode(){ static string GetTempbuffer(){ varargs int CancelCharmode(int extra){ void CheckCharmode(){ int rEsc(){ static int ReceiveChars(string str){ int SetCharmode(int x){ static string GetCharbuffer(){ static string SetCharbuffer(string str){ static string SetTempbuffer(string str){ int SetNoEcho(int x){ int GetNoEcho(){ ","/lib/events/search.c":"varargs mixed eventSearch(object who, string str){ mapping GetTraps(){ mapping FoundTraps(){ mixed direct_search_str_word_obj(string str){ string array GetSearches(){ varargs mixed SetSearch(mixed array args...){ mapping RemoveSearch(string item){ mixed direct_search_obj(){ ","/lib/player.c":"int CanReceive(object ob){ return CanCarry(ob->GetMass()); } int eventReleaseObject(object foo){ static void create(){ static int Destruct(){ string SetShort(string irrelevant){ string GetName(){ string GetCapName(){ return interactive::GetCapName(); } varargs string GetLong(string str){ varargs int eventShow(object who, string str){ int Setup(){ static void heart_beat(){ int eventMove(mixed dest){ static void net_dead(){ void eventReconnect(){ varargs mixed GetEffectiveVision(mixed location, int raw_score){ int SetUndead(int x){ mixed eventTurn(object who){ string SetClass(string str){ varargs int eventDie(mixed agent){ void eventLoadObject(mixed array value, int recurse){ } varargs static int AddHealthPoints(int x, string limb, object agent){ int GetLanguageLevel(string lang){ int ResetLevel(){ void eventKillEnemy(object ob){ int AddBank(string bank, string type, int amount){ int AddCurrency(string type, int amount){ mixed GetTeloptIp(){ string GetPlainShort(){ string array GetTitles(){ return Titles; } string array GetMuffed(){ string array AddTitle(mixed title){ mixed eventAsk(object who, string what){ varargs mixed eventDisplayStatus(int simple){ varargs void eventRevive(int nopenalty){ mixed CanUse(){ return 1; } string array SetTitles(string array titles){ mapping array GetDeaths(){ int GetTrainingPoints(){ return TrainingPoints; } int RemoveTrainingPoints(int x){ string array RemoveTitle(mixed title){ int AddTrainingPoints(int x){ static void eventDestroyUndead(object agent){ string array SetMuffed(string array muffed){ string array AddMuffed(string muffed){ string array RemoveMuffed(string unmuffed){ int SetTitleLength(int x){ int GetTitleLength(){ return TitleLength; } varargs int eventTrain(string skill, int points){ mixed SetTeloptIp(mixed str){ ","/lib/magic.c":"varargs mixed CanCast(object spell){ int GetSpellLevel(string spell){ void SetSpellBook(mapping book){ mapping GetSpellBook(){ static void eventTrainSpell(object spell){ static varargs void eventCast(object spell, string limb, object array targs){ varargs mixed eventPrepareCast(string verb, mixed array args...){ mixed eventLearnSpell(string spell){ ","/lib/events/roll.c":"varargs mixed CanRoll(object target, object where){ mixed indirect_roll_obj_on_obj(object target, object where){ mixed indirect_roll_obs_on_obj(mixed target, object where){ mixed direct_roll_obj_here(object target){ mixed direct_roll_obj_on_str(object target, string where){ varargs mixed eventRoll(object ob){ varargs mixed eventResults(mixed args){ ","/lib/std/base_dummy.c":"varargs static void create(string array id, mixed long, string array adj){ static int Destruct(){ varargs mixed eventKnock(object who, mixed what){ varargs mixed eventScratch(object who, mixed what){ varargs string array SetId(mixed ids...){ int isDummy(){ mixed eventMove(mixed dest){ ","/lib/creator.c":"void eventDescribeEnvironment(int verbose){ int inventory_visible(){ return 1; } int eventReleaseObject(object foo2){ static void create(){ static int Destruct(){ string GetName(){ varargs string GetLong(string str){ varargs int eventShow(object who, string str, string on_id){ mixed direct_look_obj(){ return 1; } mixed direct_look_at_obj(){ return 1; } int Setup(){ int eventMove(mixed dest){ static void net_dead(){ void eventReconnect(){ int eventForce(string cmd){ varargs mixed GetEffectiveVision(mixed location, int raw_score){ int inventory_accessible(){ return 1; } int CanCarry(int amount){ return 1; } int is_living(){ return 1; } int eventDie(mixed agent){ mapping GetSpellBook(){ varargs mixed CanCast(mixed spell...){ mixed direct_verb_rule(string verb){ mixed indirect_give_obj_to_liv(object item){ mixed direct_give_liv_obs(){ mixed indirect_give_obs_to_liv(object array item){ mixed direct_marry_liv_to_liv(){ mixed indirect_marry_liv_to_liv(){ mixed direct_give_liv_obj(){ int GetWizVision(){ string GetLivingShort(){ int SetWizVision(int i){ int SetVisibleGrid(int i){ int GetCreatorAge(){ int GetVisibleGrid(){ int GetCreatorBirth(){ return CreatorBirth; } ","/lib/die.c":"int eventMove(mixed dest){ static void create(){ string SetLong(string str){ void init(){ varargs mixed eventRoll(object where){ varargs mixed eventResults(mixed args){ varargs mixed eventShake(object dude, string foo){ varargs mixed CanShake(object who, string component){ varargs mixed eventConsult(object dude, string foo){ varargs mixed CanConsult(object who, string component){ int doRoll(){ int SetDenominator(int denom){ ","/lib/manycoins.c":"int Payment(object who, int value){ int PutCoins(object who){ ","/lib/events/pull.c":"varargs mixed eventPull(object who, string component){ varargs mixed CanPull(object who, string component){ varargs mapping SetPull(mixed key, mixed desc){ string array GetPulls(){ mapping RemovePull(string item){ mixed direct_pull_str_from_obj(string str, object target){ mixed direct_pull_obj(object target){ mixed direct_pull_str_on_obj(string str, object target){ ","/lib/std/barkeep.c":"static void create(){ int CanCarry(int cmt){ int indirect_sell_obj_to_liv(){ mixed CanSell(object who, string item){ string GetLocalCurrency(){ mapping GetSpecialMenuItems(){ string array GetSpecials(){ mapping AddMenuItem(mixed item, string file){ mapping AddSpecialMenuItem(mixed item, string file){ mapping SetSpecialMenuItems(mapping mp){ mapping RemoveSpecialMenuItem(string item){ mixed eventBuyItem(object who, string cmd, string item){ int eventList(object who, string cmd, string args, int special){ mapping RemoveMenuItem(string item){ int GetCost(string array item){ mapping GetMenuItems(){ string SetLocalCurrency(string str){ mapping SetMenuItems(mapping mp){ mixed eventSell(object who, string args){ int eventSpecialList(object who, string cmd){ ","/lib/props/equip.c":"int SetArmorType(int x){ mixed CanEquip(object who, string array limbs){ mixed CanUnequip(object who){ mixed eventEquip(object who, string array limbs){ static void eventRestoreEquip(string array limbs){ mixed eventUnequip(object who){ int GetArmorType(){ string array GetSave(){ static string array SetWorn(string array limbs){ string array GetWorn(){ ","/lib/events/smoke.c":"int direct_smoke_from_obj(object who, object target){ int direct_smoke_obj(object who, object target){ mixed CanSmoke(object who){ ","/lib/currency.c":"int GetCurrency(string type){ return Currency[type]; } static void create(){ mapping GetCurrencyMap(){ return copy(Currency); } varargs int GetCurrencyMass(string type){ int AddBank(string bank, string type, int amount){ int GetBank(string bank, string type){ mapping GetAccountInfo(string bank){ varargs int GetNetWorth(string benjamins){ string array GetCurrencies(){ return keys(Currency); } int AddCurrency(string type, int amount){ void ResetBank(){ Bank = ([]); } void ResetCurrency(){ Currency = ([]); } ","/lib/files.c":"string query_cwd(){ return DIR_TMP; } ","/lib/events/lie.c":"mixed eventReleaseStand(object who){ int CanGet(object who){ mixed direct_lie_down_word_obj(){ object array GetLiers(){ mixed eventReceiveLay(object who){ int GetMaxLiers(){ static int SetMaxLiers(int x){ mixed direct_lie_word_obj(){ ","/lib/clerk.c":"void create(){ mixed performMarriage(object spouse1, object spouse2){ int performDivorce(object ob1){ int MarriageRequest(mixed arg1, mixed arg2, mixed arg3){ int eventRequestDivorce(mixed arg1, mixed arg2, mixed arg3){ ","/lib/blank.c":"","/lib/std/boobytrap_shadow.c":"int eventShadow(object ob){ varargs mixed CanOpen(object who, object tool){ mixed eventClose(object who){ varargs mixed CanClose(object who, string id){ varargs mixed eventOpen(object who, object tool){ void create(){ string GetKeyName(){ string GetShort(){ mixed direct_get_obj_out_of_obj(object target, object src){ mixed direct_get_obj_obj(object target, object src){ mixed direct_get_obj_from_obj(object target, object src){ mixed GetPreventGet(){ mixed CanGet(object who){ mixed CanDrop(object who){ mixed direct_drop_obj(object target){ mixed GetPreventDrop(){ int GetDestructOnDrop(){ mixed CanLock(object who, string id){ mixed CanPick(object who, string id){ mixed direct_pick_str_on_obj_with_obj(string str, object target, object tool, varargs mixed CanUnlock(object who, string id, object key){ varargs mixed eventLock(object who, mixed arg1, mixed arg2){ varargs mixed eventPick(object who, string str, object tool){ varargs mixed eventUnlock(object who, mixed arg1, mixed arg2){ mixed eventSteal(object who){ mixed CanSteal(object who){ varargs mixed eventDisarm(mixed args...){ string GetTrapDescription(){ varargs mixed SpringTrap(mixed arg1, mixed arg2){ int GetTrapLevel(){ mixed eventEquip(object who, string array limbs){ mixed eventUnequip(object who){ int SetTrapType(int i){ int GetTrapType(){ int SetTrapLevel(int i){ string SetTrapDescription(string str){ int SetAutoResets(int i){ int GetAutoResets(){ ","/lib/clay.c":"void create(){ void init(){ varargs string SetComposition(string comp, string name, string array nouns, string array adjs, string void InitComposition(){ ","/lib/fishing.c":"static void create(){ int CanRelease(object who){ void heart_beat(){ mixed eventStop(object who, string str){ mixed CanCast(object who, string where){ mixed CanStop(object who, string str){ mixed eventCast(object who, object pole, string str){ int GetSpeed(){ return Speed; } mapping GetFish(){ return Fish; } mapping SetFish(mapping mp){ return (Fish = mp); } int SetMaxFishing(int x){ return (MaxFishing = x); } int GetChance(){ return Chance; } mapping RemoveFishing(object who){ int SetChance(int x){ return (Chance = x); } int AddFish(string fish, int x){ mapping SetFishing(object who, object pole){ int SetSpeed(int x){ return (Speed = x); } static void eventCatch(object who, string fish, object pole){ int GetMaxFishing(){ return MaxFishing; } ","/lib/props/mass.c":"int GetMass(){ string array GetSave(){ int SetZPG(int x){ int GetZPG(){ int GetWeight(){ mixed direct_weigh_obj(){ int AddMass(int x){ int SetMass(int x){ ","/lib/user/autosave.c":"int Setup(){ static void heart_beat(){ nomask int restore_player(string nom){ nomask void save_player(string nom){ nomask void restore_inventory(){ ","/lib/pipe.c":"string GetShort(){ static void create(){ varargs string GetLong(string unused){ int GetRadiantLight(int ambient){ varargs mixed eventLight(object who, object tool){ mixed direct_light_obj(){ mixed eventDarken(){ static void heart_beat(){ int GetBurnRate(){ static int SetBurnRate(int x){ mixed eventSmoke(object who, object what){ int GetLastPuff(){ ","/lib/virtual/virtual.c":"int GetVirtualSky(){ int GetExemptVirtual(){ int SetExemptVirtual(int i){ int GetVirtualSea(){ ","/lib/vehicle.c":"void create(){ varargs string GetInternalDesc(){ int eventMove(mixed dest){ void init(){ int inventory_accessible(){ varargs int eventDie(mixed agent){ mixed eventMount(object who){ varargs int CanFly(mixed who, mixed where){ object array GetDummyItems(){ mapping GetItemsMap(){ mapping RemoveItem(mixed item){ mapping SetItems(mixed items){ varargs void AddItem(mixed item, mixed val, mixed adjectives){ varargs mixed eventEnter(object who, string what, string verb){ mixed CanGo(object who, string str){ mixed eventGo(object who, string str){ varargs void SetRead(mixed items, mixed arg){ void RemoveRead(mixed item){ void AddRead(mixed item, mixed val){ mixed GetVehicleInterior(){ mixed direct_drive(){ mixed direct_fly_word_str(){ mixed direct_drive_word_str(){ int SetVehicleInterior(mixed arg){ int eventDrive(string direction){ ","/lib/rifle.c":"static void create(){ void init(){ ","/lib/light.c":"static void create(){ string GetShort(){ varargs mixed eventLight(object who, object tool){ static int SetLit(int x){ int GetLit(){ mixed CanLight(object who){ mixed direct_light_obj(){ mixed eventDarken(){ ","/lib/used_meal.c":"static void create(){ ","/lib/std/bane.c":"int SetBane(array arr){ string array GetBane(){ string array QueryBane(){ ","/lib/virtual/virt_map.c":"varargs static void create(string virt_file){ int AddLocation(string str, int array where){ int SetVirtFile( string file){ varargs mixed GetAreaMap(int x, int y, int z){ varargs string array BaseMap(){ //override with actual map varargs mixed SetAreaMap(int y,int x ,int z, string str){ int array GetLocations(string str){return Location[str]; } varargs void InitializeLocations(string tmp){ void SwitchLocations(){ int RemoveLocation(string str){ ","/lib/help.c":"string GetHelp(string topic){ static mapping SetHelp(mixed val){ ","/lib/events/wield.c":"mixed direct_unwield_obj(){ mixed direct_wield_obj_word_str(object target, string wrd, string limb){ ","/lib/events/lock.c":"varargs string array SetKeys(mixed array args...){ string array AddKey(string key){ varargs string array GetKeys(string unused){ int GetLocked(){ int SetLocked(int x){ int GetLockStrength(){ int SetLockStrength(int x){ function GetPick(){ function SetPick(function f){ mixed CanLock(object who, string id){ mixed CanPick(object who, string id){ varargs mixed CanUnlock(object who, string id, object key){ varargs mixed eventLock(object who, mixed arg1, mixed arg2){ varargs mixed eventPick(object who, string id, object tool){ string array GetSave(){ varargs mixed eventUnlock(object who, mixed arg1, mixed arg2){ varargs mixed direct_lock_obj_with_obj(object target, object key, mixed id...){ varargs mixed direct_lock_obj_with_str(object target, mixed key, mixed id...){ varargs mixed direct_pick_str_on_obj(string str, object target, string str2, varargs mixed direct_pick_str_on_obj_with_obj(string str, object target, object tool, varargs mixed direct_unlock_obj_with_obj(object target, object key, string id, string key2){ varargs mixed direct_unlock_obj_with_str(object target, object key, string id, string key2){ mixed direct_wizlock_obj(){ return 1; } mixed direct_wizunlock_obj(){ return 1; } ","/lib/events/rock.c":"mixed direct_rock_obj(object target){ mixed direct_rock_str_on_obj(string str, object target){ varargs mixed eventRock(object who, mixed what){ mixed direct_rock_wrd_obj(object target){ varargs int CanRock(mixed who, mixed what){ ","/secure/daemon/rooms.c":"void create(){ int eventDestruct(){ string GetCoordinates(mixed ob){ static void heart_beat(){ varargs mixed GetDirectionRoom(mixed origin, string direction, int noclip){ varargs mapping GetGridMap(string str){ varargs mixed SetRoom(object arg_ob, object player, string manual){ string GetVoid(mixed ob){ mixed DroneCache(mixed foo){ string GetRoomZero(){ mixed GenerateNames(int x){ int SetDebugging(int i){ mixed validate_last_room(string room, object player){ varargs int UnSetRoom(mixed arg_ob, int auto){ void zero(){ varargs mapping GetWorldMap(string str){ string StrCoord(mapping TmpMap){ varargs mixed SetGrid(string arg_room, string coord, object player, int unset){ mapping GetCoordinateMap(mixed ob){ ","/lib/events/scratch.c":"varargs mixed eventScratch(object who, mixed component){ mixed direct_scratch_str_on_obj(string str, object target){ mixed direct_scratch_on_str_on_obj(string str, object target){ string array GetScratches(){ mapping RemoveScratch(string item){ varargs mixed CanScratch(object who, string component){ varargs mapping SetScratch(mixed key, mixed desc){ mixed direct_scratch_on_obj(object target){ mixed direct_scratch_obj(object target){ ","/lib/teacher.c":"static void create(){ static void init(){ string GetLocalCurrency(){ mapping GetStudents(){ return copy(Students); } int eventStart(object who, string language){ mixed AddTeachingLanguages(string array args){ string Expertise(){ string array GetTeachingLanguages(){ return copy(TeachingLanguages); } int GetCommercial(){ int SetAllLanguages(int i){ int eventTeachLanguage(object who, string verb, string language){ int eventContinue(object who, string language, int x){ int GetTeachingFee(){ mixed RemoveTeachingLanguages(string array args...){ int GetAllLanguages(){ int SetTeachingFee(int i){ static int ContinueTeaching(object who, string language, int x){ int SetCommercial(int i){ int eventHelp(object who, string unused){ string SetLocalCurrency(string str){ int eventComplete(object who, string language){ ","/lib/events/buy.c":"mixed CanSell(object who, string what){ int direct_buy_str_from_liv(string str){ ","/lib/events/fly.c":"mixed direct_fly_str(string str){ mixed direct_fly_into_str(string str){ ","/lib/steal.c":"static void create(){ mixed direct_steal_obj_from_liv(){ return CanSteal(this_player()); } mixed eventSteal(object who){ mixed GetPreventSteal(){ return PreventSteal; } mixed SetPreventSteal(mixed val){ return (PreventSteal = val); } ","/lib/events/smell.c":"varargs mixed SetSmell(mixed array args...){ string array GetSmells(){ varargs mixed eventSmell(object who, string str){ mixed direct_smell_obj(){ mapping GetSmellMap(){ mixed direct_smell_str_word_obj(string str){ mapping RemoveSmell(string item){ ","/lib/fuel.c":"static void create(){ varargs string GetLong(string val){ static int SetFuelAmount(int x){ string GetFuelType(){ mixed eventDecreaseFuel(int x){ mixed eventRefuel(int x){ int GetFuelAmount(){ int GetMaxFuel(){ static int SetMaxFuel(int x){ int GetRefuelable(){ static int SetRefuelable(int x){ static string SetFuelType(string str){ ","/lib/base_trainer.c":"void create(){ static void init(){ int eventTrain(object who, string verb, string skill){ mapping GetStudents(){ return copy(Students); } int eventStart(object who, string skill){ static int ContinueTraining(object who, string skill, int x){ string Expertise(){ string array GetTrainingSkills(){ return copy(TrainingSkills); } int eventContinue(object who, string skill, int x){ mixed RemoveTrainingSkills(string array args){ int GetNoSpells(){ int eventHelp(object who, string unused){ int SetNoSpells(int i){ mixed AddTrainingSkills(string array args){ int eventComplete(object who, string skill){ ","/lib/std/armor.c":"void create(){ void init(){ ","/lib/race.c":"static void heart_beat(){ string GetRace(){ return Race; } void NewBody(string race){ static void create(){ int GetCarriedMass(){ return 0; } int GetMaxCarry(){ varargs int eventDie(mixed agent){ varargs string SetRace(string race, mixed extra){ int SetMaxHealthPoints(int x){ string GetResistance(int type){ return genetics::GetResistance(type); } varargs int GetMaxHealthPoints(string limb){ int GetMaxMagicPoints(){ float GetMaxStaminaPoints(){ int GetAlcohol(){ return body::GetAlcohol(); } int GetHeartRate(){ varargs void SetStat(string stat, int level, int classes){ int GetStatLevel(string stat){ return genetics::GetStatLevel(stat); } string GetGender(){ return Gender; } string GetTown(){ return Town; } string SetTown(string str){ return (Town = str); } int SetRespiration(int i){ mixed eventDrink(object ob){ mixed eventEat(object ob){ string SetGender(string gender){ return (Gender = gender); } int GetLuck(){ int GetMobility(){ mixed CanEat(object ob){ mixed CanDrink(object ob){ int GetRespiration(){ varargs int CanBreathe(object what, object where, int dbg){ ","/lib/props/move.c":"int eventMove(mixed dest){ object GetLastEnvironment(){ int GetAnchored(){ int SetAnchored(int x){ ","/lib/bboard.c":"void create(){ string GetExternalDesc(){ void init(){ void end_edit(string subj, int num){ int cmd_followup_and_respond(string str){ string query_board_time(int x){ void end_post(string subj, string mail){ int cmd_remove(string str){ static void check_include_text(string ans, string subj, string file, mapping static void begin_post(string cmd, string subj, string file, function f){ static private int valid_edit(string author){ void continue_mail(mapping post, string subj, string file){ void set_board_id(string str){ __BoardID = str; } int cmd_read(string str){ int cmd_edit(string str){ void continue_post(string subj, string file){ void continue_followup(mapping post, string subj, string file){ string query_board_id(){ return __BoardID; } int cmd_post(string str){ void RegisterLocation(){ ","/lib/inventory.c":"mapping SetInventoryCheck(mapping newmap){ static void eventLoadItem(string file, mixed args, int count){ mapping GetInventory(){ static void eventLoadInventory(){ void heart_beat(){ varargs void reset(){ ","/lib/std/limb.c":"string GetShort(){ int CanReceive(object ob){ void create(){ string GetItemCondition(){ int Destruct(){ int GetSaveString(){ void init(){ string GetLimb(){ int SetNoDecay(int i){ string GetRace(){ int eventDecay(){ void SetLimb(string limb, string owner, string race){ int GetCount(int i){ int GetNoDecay(){ int GetSlowDecay(){ int SetCount(int i){ int SetSlowDecay(int i){ string GetOwner(){ ","/lib/detect.c":"int direct_detect_wrd_in_obj(string word){ mixed eventDetect(object who, string str, int ability){ ","/lib/flow.c":"int eventMove(mixed dest){ void create(){ varargs int eventPrint(string msg, mixed arg2, mixed arg3){ int eventDestruct(){ void init(){ string GetRoomAffectLong(){ void heart_beat(){ int GeteventPrints() { return 1; } int AddPressure(int x){ void CheckRooms(){ int SetDoorStopped(int i){ void shb(int i){ int GetHBOverride(){ void eventFlood(mixed targets){ int SetPressure(int i){ int SetHBOverride(int x){ int GetDoorStopped(){ int GetPressure(){ ","/lib/events/bait_with.c":"int GetBaitStrength(){ int SetBaitStrength(int x){ mixed indirect_bait_obj_with_obj(){ mixed eventBait(object who, object pole){ ","/lib/events/fall.c":"mixed eventFall(){ ","/lib/elevator.c":"static void create() { int eventMove(mixed foo){ void init(){ int GetSpeed(){ mapping GetFloors(){ mapping SetFloors(mapping floors){ int SetSpeed(int x){ ","/lib/missile.c":"void create(){ string GetName(){ void init(){ int GetDamage(){ int launch(string str){ int GetSpeed(){ varargs object SetOwnerOb(object ob){ object GetOwnerOb(){ void eventDeploy(string str){ mixed eventNegotiateObstacles(){ int SetDamage(int x){ int GetRange(){ string SetCruiseOutMessage(string str){ int eventCruise(string str){ string SetCruiseInMessage(string str){ int SetArmed(int x){ int SetRange(int x){ int SetSpeed(int x){ mixed eventCruiseMessages(object this_room, object next_room, string dir){ mixed eventRunOut(){ int SetDebugging(int x){ mixed eventEncounterBlock(){ int GetDebugging(){ ","/lib/language.c":"varargs void SetLanguage(string lang, int level, int native){ int GetLanguageLevel(string lang){ int GetPolyglot(){ string GetNativeLanguage(){ int GetNextLevel(string lang, int curr_level){ mapping RemoveLanguage(string lang){ mapping SetNativeLanguage(string lang){ mixed SetDefaultLanguage(string str){ string GetDefaultLanguage(){ string GetLanguageName(string lang){ int AddLanguagePoints(string lang, int points){ int GetLanguagePoints(string lang){ int GetStatLevel(string stat){ return 0; } string array GetLanguages(){ int SetPolyglot(int i){ ","/lib/living.c":"int CanCarry(int amount){ return carry::CanCarry(amount); } int AddCarriedMass(int x){ return carry::AddCarriedMass(x); } int GetCarriedMass(){ int GetMaxCarry(){ return combat::GetMaxCarry(); } static void create(){ mixed direct_get_obj(mixed args...){ mixed direct_get_obj_from_obj(mixed args...){ varargs mixed eventShow(object who, string str){ int is_living(){ return 1; } varargs int eventMoveLiving(mixed dest, string omsg, string imsg, mixed dir){ int inventory_accessible(){ return 1; } mixed direct_ride_word_str(){ mixed direct_ride_str(){ mixed direct_mount_liv(){ mixed direct_dismount_liv(){ mixed direct_dismount_from_liv(){ int eventFollow(object dest, int followChance){ int SetDead(int i){ int direct_follow_liv(){ return 1; } int direct_lead_liv(){ return 1; } int direct_evade_liv(){ return 1; } mixed CanAttack(){ int GeteventPrints(){ int direct_gaze(){ return CanReceiveMagic(0, \"gaze\"); } mixed direct_portal_to_liv(){ mixed direct_resurrect_liv(){ mixed direct_scry_liv(){ mixed indirect_zap_liv(){ return 1; } mixed indirect_pulsecheck_liv(){ return 1; } int direct_rockwhip_liv(){ return CanReceiveMagic(1, \"rockwhip\"); } int direct_acidspray_liv(){ return CanReceiveMagic(1, \"acidspray\"); } int direct_annihilate_at_liv(){ return CanReceiveMagic(1, \"annihilate\"); } int direct_annihilate_liv(){ return CanReceiveMagic(1, \"annihilate\"); } int direct_arrow_liv(){ return CanReceiveMagic(1, \"arrow\"); } int direct_arrow_at_liv(){ return CanReceiveMagic(1, \"arrow\"); } int direct_blades_at_liv(){ return CanReceiveMagic(1, \"blades\"); } int direct_blades_liv(){ return CanReceiveMagic(1, \"blades\"); } int direct_corrupt_liv(){ return CanReceiveMagic(1, \"currupt\"); } int direct_demonclaw_liv(){ return CanReceiveMagic(1, \"demonclaw\"); } int direct_dispel_liv(){ return CanReceiveMagic(1, \"dispel\"); } int direct_drain_at_liv(){ return CanReceiveMagic(1, \"drain\"); } int direct_drain_liv(){ return CanReceiveMagic(1, \"drain\"); } int direct_fireball_at_liv(){ return CanReceiveMagic(1, \"fireball\"); } int direct_fireball_liv(){ return CanReceiveMagic(1, \"fireball\"); } int direct_frigidus_at_liv(){ return CanReceiveMagic(1, \"frigidus\"); } int direct_frigidus_liv(){ return CanReceiveMagic(1, \"frigidus\"); } int direct_holylight_liv(){ return CanReceiveMagic(1, \"holylight\"); } int direct_missile_liv(){ return CanReceiveMagic(1, \"missile\"); } int direct_missile_at_liv(){ return CanReceiveMagic(1, \"missile\"); } int direct_shock_liv(){ return CanReceiveMagic(1, \"shock\"); } int direct_palm_liv(){ return CanReceiveMagic(1, \"palm\"); } int direct_immolate_liv(){ return CanReceiveMagic(1, \"immolate\"); } int direct_gale_liv(){ return CanReceiveMagic(1, \"gale\"); } int direct_aura_liv(){ return CanReceiveMagic(0, \"aura\"); } int direct_soulseek_liv(){ return CanReceiveMagic(0, \"soulseek\"); } int direct_cloak_wrd(){ return CanReceiveMagic(0, \"cloak\"); } int direct_stealth_wrd(){ return CanReceiveMagic(0, \"stealth\"); } int direct_backlash_for_liv(){ return CanReceiveMagic(0, \"backlash\"); } int direct_backlash_for_liv_against_wrd(){ return CanReceiveMagic(0, \"backlash\"); } int direct_balance_obj_to_obj(){ return CanReceiveMagic(0, \"balance\"); } int direct_buffer_liv(){ return CanReceiveMagic(0, \"buffer\"); } int direct_calm_liv(){ return CanReceiveMagic(0, \"calm\"); } int direct_cleanse_liv(){ return CanReceiveMagic(0, \"cleanse\"); } int direct_convert_liv(){ return CanReceiveMagic(0, \"convert\"); } int direct_shield_liv(){ return CanReceiveMagic(0, \"shield\"); } int direct_veil_liv_against_wrd_wrd(){ return CanReceiveMagic(0, \"veil\"); } int direct_ward_liv_against_wrd(){ return CanReceiveMagic(0, \"ward\"); } int direct_remedy_liv(){ return CanReceiveMagic(0, \"remedy\"); } int direct_command_str_to_str(){ return CanReceiveMagic(0, \"command\"); } int direct_send_str_to_str(){ return CanReceiveMagic(0, \"send\"); } int direct_connect_str(){ return CanReceiveMagic(0, \"connect\"); } int direct_heal_liv(){ return CanReceiveMagic(0, \"heal\"); } int direct_mend_liv(){ return CanReceiveMagic(0, \"mend\"); } int direct_refresh_liv(){ return CanReceiveMagic(0, \"refresh\"); } int direct_rejuvinate_liv(){ return CanReceiveMagic(0, \"rejuvinate\"); } int direct_farsight_liv(){ return 1; } int direct_bump_liv(){ return 1; } varargs mixed CanCastMagic(int hostile, string spell){ mixed direct_verb_rule(string verb){ mixed direct_attack_liv(){ mixed direct_attack_only_liv(){ mixed direct_attack_liv_only(){ mixed direct_target_liv(){ mixed direct_target_only_liv(){ mixed direct_target_liv_only(){ mixed direct_bite_liv(){ mixed direct_capture_liv_word_obj(){ mixed direct_pray_for_str_against_str_for_liv(){ mixed direct_cast_str_on_obj(){ mixed indirect_give_obj_to_liv(object item){ mixed direct_give_liv_wrd_wrd(object targ, string num, string curr){ mixed direct_give_wrd_wrd_to_liv(string num, string curr){ mixed direct_steal_wrd_from_liv(string wrd){ mixed indirect_steal_obj_from_liv(object item, mixed args...){ int SetPK(int x){ return (isPK = x); } int GetPK(){ return isPK; } int GetNoCondition(){ mixed direct_cast_str_against_str(){ mixed direct_cast_str_on_str_of_obj(){ mixed direct_free_liv_from_obj(){ mixed direct_resurrect_obj(){ return 1; } mixed indirect_resurrect_obj(){ return 1; } mixed direct_show_liv_obj(){ mixed indirect_show_obj_to_liv(object item){ mixed indirect_show_obj_liv(object item){ mixed direct_give_liv_obs(){ mixed indirect_give_obj_liv(object item){ mixed indirect_give_obs_to_liv(object array items){ mixed indirect_give_obs_liv(object array items){ mixed direct_backstab_liv(){ mixed direct_heal_str_of_liv(string limb){ mixed direct_remedy_str_of_liv(string limb){ mixed direct_regen_str_on_liv(string limb){ mixed direct_teleport_to_liv(){ int direct_marry_liv_to_liv(){ return 1; } int direct_party_wrd_liv(){ return 1; } int direct_challenge_liv(){ return 1; } int direct_ignore_liv(){ return 1; } int indirect_throw_obj_at_obj(){ return 1; } int indirect_toss_obj_at_obj(){ return 1; } int indirect_buy_str_from_liv(){ return 1; } int indirect_sell_obj_to_liv(){ return 1; } int indirect_marry_liv_to_liv(){ return 1; } mixed eventCure(object who, int amount, string type){ mixed SetAttackable(mixed foo){ mixed GetAttackable(){ int SetNoCondition(int foo){ mixed direct_give_liv_obj(){ string GetEquippedShort(){ varargs mixed CanReceiveHealing(object who, string limb){ mixed eventInfect(object germ){ varargs mixed eventSteal(object who, mixed what, object target, int skill){ int GetNonCurrencyMass(){ ","/lib/match.c":"mixed eventStrike(object who){ int GetStrikeChance(){ mixed direct_strike_obj(){ static int SetStrikeChance(int x){ ","/lib/exits.c":"static void create(){ string array GetDoors(){ mapping GetFullExitData(){ mapping GetExitMap(){ mixed CanGo(object who, string str){ string array GetExits(){ mapping GetEnterMap(){ mapping GetDoorsMap(){ varargs string CreateDoor(string dir, string odir, string long, string locked, string key){ mixed eventGo(object who, string str){ string SetDoor(string dir, string file){ string GetDirection(string dest){ object GetDummyItem(mixed id){ varargs void AddEnter(string dir, string dest, function pre, function post){ static mapping GetEnterData(string dir){ varargs string array GetEnters(int i){ void RemoveEnter(string dir){ void SetEnters(mapping mp){ string GetEnterMessage(){ string SetEnterMessage(string str){ varargs mapping AddExit(string dir, string dest, function pre, function post){ mapping GetExitData(string str){ mapping RemoveExit(string dir){ mapping SetExits(mapping mp){ string GetGoMessage(){ string SetGoMessage(string str){ string GetObviousExits(){ string SetObviousExits(string str){ string GetSky(){ string SetSky(string str){ string ResolveObjectName(string file){ ","/lib/events/look_in.c":"mixed direct_look_in_obj(){ mixed direct_look_inside_obj(){ mixed indirect_look_at_obj_word_obj(object target){ mixed inventory_visible(){ string GetInternalDesc(){ string SetInternalDesc(string str){ int GetOpacity(){ int SetOpacity(int x){ varargs mixed CanShowInterior(object who, object target){ varargs mixed eventShowInterior(object who, object target){ ","/lib/virtual/virt_std.c":"object compile_object(string fname){ mixed CreateVirtualObject(string fname){ ","/lib/events/sit.c":"object array GetSitters(){ mixed direct_sit_down_word_obj(){ mixed eventReleaseStand(object who){ int CanGet(object who){ int GetMaxSitters(){ mixed eventReceiveSit(object who){ static int SetMaxSitters(int x){ mixed direct_sit_word_obj(){ ","/lib/comp/seal.c":"varargs mixed CanOpen(object who, string id){ varargs mixed eventOpen(object who, object tool){ mixed CanLock(object who, string id){ void create(){ ","/lib/vi.c":"private varargs void _message(object pl, string str, string callback, int hide, private void _file_head(object pl); // »½Ôð˜ŠÓË´»´´Í¸ private void _replace(object pl); // ÚÙ³«Þ†©© private void _help(object pl); // ¹¿Ù”©¡È† private void _down(object pl); // Ôð˜ŠÍ·ÎÃÓËÓ©ÏÏ private void _insert_line(object pl); // ÕõÔð˜ŠÐθ»­ÔÓ©ÏÃÏÏ protected void _goto_line_done(string str, object pl, int rein); // ®í´ÈÏÏ¦Ê private void _right(object pl, int col, int extra); // Ôð˜ŠÍ·ÔÓÓËÓ©ÚÙ protected void _search_done(string str, object pl); // ®í´ÈÝÒÒ—ÚÙ³« protected void _undef_key_done(string str, object pl); // ®í´ÈÙ¹µ¿ ªý›­’ private void _up(object pl); // Ôð˜ŠÍ·ÐÎÓËÓ©ÏÏ protected void _input(string str, object pl, int fresh); // µÂ´Èׄ®‹ÚÙ³« protected void _keymap_done(string str, object pl); // ®í´Èµ¿Ó… ªý›­’ private void _del_char(object pl, int bs); // оþ²Ôð˜ŠÐδýÚÙ private void _write(object pl); // ®í´È³ó³†´´—¹È“þË private void _append(object pl); // ÕõÔð˜ŠßßȆ­ÔÚÙ private void _refresh_screen(object pl, int s_row, int e_row, int s_col) private void _refresh_cursor(object pl); // ¹’ÏÃÔð˜Šð©ÙÈ private void _esc(object pl); // ³Ôׄ®‹ýú×»©Û´»È’ÂŽýú×» private void _file_end(object pl); // »½Ôð˜ŠÓË´»´´ð™ protected void _quit(mixed unused, mixed pl); // Á‹À¬˜€­¡Ë• private void _next_match(object pl); // ÝÒÒ—/Þ†©©Îù÷¸“¦ÎÚÙ³« private void _del_line(object pl); // оþ²Ø“ÏÏ private void _tab(object pl); // È’ÂŽýú×»Îà TAB ­’´ýµ¿ð© private int _dispatcher(object pl) // ¸ÙÊÐٹŽ´»™©Í¼¦¯×» protected void _confirm_save(string str, object pl); // Á‹À¬˜€­¡Ë•Ì—®¸®Î³†´´ private void _insert_exclam_mark(object pl); // ÕõÔð˜ŠÌ—Ȇ™…®‹Ó©¹÷í¹!í ÚÙÕ¬ private void _left(object pl); // Ôð˜ŠÍ·ÚÓËÓ©ÚÙ protected void _write_done(string str, object pl, int quit); // ³ó³†´´—¹ private void _home(object pl); // »½Ôð˜ŠÓË´»ÏÏ×Ú private void _process(object pl); // ³ªÁׄ®‹ýú×»´ýÚÙ³«×„®‹ void start_edit(string filename); // ¦Ÿ»Ï˜€­¡Ë•ú¼À¬×­˜€­¡ private void _backspace(object pl); // оþ²Ôð˜ŠÌ—´ýÚÙ protected void _message_done(string str, object pl); // »ß×°ÒµÎó´ýÎÕ×¾ private void _refresh_status(object pl); // ¹’ÏÃÚ³Þ¼ÂÏ protected void _replace_done(string str, object pl); // ®í´ÈÞ†©©ÚÙ³« private void _page_down(object pl); // Í·ÎþөÓþú¿22 ÏÏú¨ private void _append_line(object pl); // ÕõÔ𘊴ÚÎíÔÓ©ÏÃÏÏ private void _page_up(object pl); // Í·ÐξөÓþú¿22 ÏÏú¨ private void _join(object pl); // »½ÎÃÏÏðýÚÙÓË´»³ÝÏÏßßȆ ","/lib/std/bot_corpse.c":"void create(){ void init(){ void SetCorpse(object who){ int eventDecay(){ ","/lib/chamber.c":"void create(){ varargs string GetInternalDesc(){ int eventMove(mixed dest){ varargs int eventPrint(string msg, mixed arg2, mixed arg3){ void init(){ int inventory_accessible(){ int eventRide(string direction){ varargs int eventDie(mixed agent){ mixed eventMount(object who){ varargs int CanFly(mixed who, mixed where){ varargs mixed eventHearTalk(object who, object target, int cls, string verb, object array GetDummyItems(){ mapping GetItemsMap(){ mapping RemoveItem(mixed item){ mapping SetItems(mixed items){ varargs void AddItem(mixed item, mixed val, mixed adjectives){ varargs mixed GetBefriended(mixed who){ varargs mixed eventEnter(object who, string what, string verb){ mixed CanGo(object who, string str){ mixed eventGo(object who, string str){ varargs void SetRead(mixed items, mixed arg){ void RemoveRead(mixed item){ void AddRead(mixed item, mixed val){ mixed direct_drive(){ mixed GetChamberInterior(){ mixed direct_fly_word_str(){ int SetChamberInterior(mixed arg){ mixed direct_drive_word_str(){ int eventDrive(string direction){ ","/lib/npc.c":"static void create(){ int eventDestruct(){ void eventReconnect(){ } static int cmdAll(string arg){ string GetCommandFail(){ return \"What?\"; } string GetShort(){ int GetRadiantLight(int ambient){ int CanReceive(object ob){ return CanCarry(ob->GetMass()); } int eventReceiveObject(object who){ int eventReleaseObject(object who){ int AddCarriedMass(int x){ return living::AddCarriedMass(x); } int eventMove(mixed dest){ varargs int eventPrint(string msg, mixed arg2, mixed arg3){ string GetName(){ return object::GetName(); } static void heart_beat(){ mixed eventTurn(object who){ mixed array GetCommands(){ return commands(); } int GetLevel(){ return NPCLevel; } string SetClass(string cls){ void SetAction(int chance, mixed val){ int GetActionsEnabled(){ varargs string GetLong(string str){ varargs int eventShow(object who, string str){ mapping SetInventory(mapping mp ){ return (Inventory = mp); } void SetCombatAction(int chance, mixed val){ string SetKeyName(string nom){ string GetCapName(){ return object::GetCapName(); } static void init(){ varargs int eventDie(mixed agent){ int eventCompleteMove(mixed dest){ void eventEnemyDied(object ob){ static int ContinueHeart(){ varargs string SetRace(string race, mixed extra){ int SetLevel(int x){ int SetMagicPoints(int x){ float SetStaminaPoints(float x){ float SetMaxStaminaPoints(float x){ varargs void SetCurrency(mixed val, int amount){ mixed SetEncounter(mixed val){ return (Encounter = val); } string array AddEncounter(string nom){ string array RemoveEncounter(string nom){ mixed GetEncounter(){ return Encounter; } mixed SetDie(mixed val){ return (Die = val); } mixed GetDie(){ return Die; } mixed GetCombatAction(){ return CombatAction; } string array GetEnemyNames(){ return EnemyNames; } int array GetScreen(){ return ({ 80, 24 }); } int AddEnemy(object ob){ mapping GetInventory(){ return copy(Inventory); } void CheckEncounter(){ int SetCustomXP(int i){ int SetMaxMagicPoints(int x){ string GetPlainShort(){ int eventExtraAction(){ return 1; } int GetAutoStand(){ return AutoStand; } string GetMountStyle(){ string SetMountStyle(string str){ int SetVisibleRiders(int i){ int GetCustomXP(){ int GetVisibleRiders(){ int SetAutoStand(int i){ mixed SetAggressive(mixed val){ int DisableActions(int x){ int EnableActions(int x){ ","/lib/events/poison.c":"mixed CanPoison(object who){ mixed eventPoison(object who, object agent, int strength){ string array GetSave(){ int GetPoison(){ int AddPoison(int x){ int SetPoison(int x){ mixed direct_poison_obj_with_obj(){ ","/lib/daemons/player_stub.c":"string GetKeyName(){ string SetKeyName(string str){ ","/daemon/soul.c":"static void create() { static private void validate() { string GetHelp(string arg) { string GetErrorMessage(string verb) { int CanTarget(object who, string verb, object target, string rule) { varargs int AddAdverbs(string array advs...) { varargs int AddRule(string verb, string rle, mixed array msg, int AddVerb(string verb, string err) { int RemoveRule(string emt, string rle) { int RemoveVerb(string verb) { string array GetAdverbs() { varargs mixed array GetChannelEmote(string emote, string parse, string args) { string array GetEmotes() { void SetErrorMessage(string verb, string msg) { string GetRaceAdverb(mixed who) { mapping GetRules(string emote) { mixed can_verb_rule(string verb, string rle) { varargs mixed do_verb_rule(string verb, string rle, mixed args...) { ","/lib/editor.c":"static void create(){ static string process_input(string str){ varargs void eventEdit(string file, function callback){ ","/lib/battery.c":"void create(){ void init(){ void heart_beat(){ int eventUse(int i){ int SetDrainable(int i){ drainable = i; return i; } int eventCharge(int i){ int GetDrainable(){ return drainable; } int SetRechargeable(int i){ rechargeable = i; return i;} int GetRechargeable(){ return rechargeable;} int SetCellType(string str){celltype=str; return 1; } int SetDrainRate(int i){ drainrate = i; return i; } int GetDrainRate(){ return drainrate; } string GetCellType(){ return celltype; } int GetCharge(){ return charge; } int ModCharge(int i){ int SetPowerType(string str){powertype=str; return 1; } string GetPowerType(){ return powertype; } int eventDrain(int i){ int Spent(){ int SetCharge(int i){charge = i; fullcharge = i; return 1; } ","/lib/persist.c":"string GetSaveString(){ static int eventConvertObject(mixed val, int recurse){ int eventLoadObject(mixed val, int recurse){ static mixed array AddSave(mixed array vars){ static int SetSaveRecurse(int flag){ return (SaveRecurse = flag); } mixed array cGetSave(){ return copy(Saved); } mixed array dGetSave(){ return Saved; } int SetRetain(int i){ int GetRetain(){ ","/lib/teach.c":"int eventOfferTeaching(object who, string what){ int direct_teach_liv_to_str(){ return 1;} int eventTeach(object who, string what){ varargs int CanTeach(object whom, string what){ int direct_teach_str_to_liv(){ return 1;} ","/lib/events/load.c":"varargs mixed eventLoad(object what, object where){ varargs mixed CanLoad(object who, object what){ varargs mixed eventUnload(object what, object where){ int SetMaxLoad(int i){ int GetMaxLoaded(){ int GetLoaded(int i){ int SetLoaded(int i){ int direct_unload_obj(object target){ varargs mixed CanUnload(object who, object what){ int direct_load_obj(object target){ int indirect_load_obj_word_obj(object target, object thingus){ int direct_unload_obj_word_obj(object thingus, object target){ int indirect_unload_obj_word_obj(object one, object two, object three){ ","/lib/clip.c":"int CanReceive(object ob){ int CanRelease(object ob){ void create(){ varargs mixed eventLoad(object who, object where){ varargs mixed eventUnload(mixed where){ int SetMillimeter(int x){ millimeter=x; return 1; } string GetFirearmType(){ return firearmtype; } int MinusAmmo(int i){ ammo -= i; return 1; } int SetMaxAmmo(int i){ MaxAmmo=i; return 1; } int PlusAmmo(int i){ ammo += i; return 1; } string GetAmmoType(){ return ammotype; } int GetCaliber(){ return caliber; } int GetMillimeter(){ return millimeter; } int SetFirearmType(string str){firearmtype=str; return 1; } int SetAmmoType(string str){ammotype=str; return 1; } int SetCaliber(int x){ caliber=x; return 1; } ","/lib/cgi.c":"mapping ParsePost(string args){ ","/secure/daemon/imc2.c":"void create(){ int eventDestruct(){ int clean_up(){ return 0; } varargs string GetMudName(string name, int online){ varargs static void validate(int i){ varargs string array GetMudList(int online){ void Setup(){ void heart_beat(){ int level(object ob){ void mudlist(object towho) { private void whois_in(string fromname, string frommud, string targ, mapping data){ void resolve_callback( string address, string resolved, int key ) { int UnSetAutoDisabled(int x){ varargs static void tell_out(object from, string targname, string targmud, string msg, int reply, int emote){ int GetEnabled(){ string localize_channel(string str){ void chan_who_in(string fromname, string frommud, mapping data){ void send_ice_refresh(){ send_packet(\"*\",\"ice-refresh\",\"*\",\"*\",\"\"); } varargs void write_to_log(string type, string wat){ int can_use(object user){ return 1; } // Is this person allowed to use IMC2 at all? This function determines if tells can be sent to the person and such. string chan_perm_desc(int i){ void write_callback(int fd){ void read_callback(int socket, mixed info){ void beep_out(object from, string targname, string targmud){ void ping_out(string from,string targmud){ send_packet(from,\"ping\",\"*\",targmud,\"\"); } varargs void who_out(string from,string targmud,string type){ send_packet(from,\"who\",\"*\",targmud,(type ? sprintf(\"type=\\\"%s\\\"\",type) : \"type=who\")); } void chanwho_out(object from,string chan,string mud){ private int close_callback(object socket){ static mixed GetChanInfo(){ string array GetChanList(){ void channel_out(string user,string chan,string msg,int emote){ void mudinfo(string args,object towho) { void remove(){ string pinkfish_to_imc2(string str){ string imc2_to_pinkfish(string str){ string escape(string str){ string unescape(string str){ mapping string_to_mapping(string str){ string main_help(){ void keepalive(string args, object who){ private void send_text(string text){ private void got_packet(string info){ void start_logon(){ varargs void send_is_alive(string origin){ void channel_in(string fromname, string frommud, mapping data){ void tell_in(string sender, string origin, string target, mapping data){ private void beep_in(string sender, string origin, string target, mapping data){ private void who_reply_in(string origin, string target, mapping data){ private void whois_reply_in(string targ,string fromname,string frommud,mapping data){ void ping_reply_in(string sender,string origin,string target,mapping data){ void chanwho_reply_in(string origin, string target, mapping data){ void send_keepalive_request(){ int chan_perm_allowed(object user, string chan){ string find_mud(string str){ mapping getmudinfo() { void mudwho(string mudname,object towho) { mixed pingmud(string mudname,object towho) { void getstatus(object towho) { void interbeep(string args, object towho) { void finger(string args, object towho) { void allchans(string args, object towho) { void getremotemudinfo(string args, object towho) { int getonline() { void chancmd(string args, object towho) { int command(string str){ string html(string str){ void forget_user(string str){ map_delete(tells,str); } static void eventChangeIMC2Passwords(){ string clean_str(string str){ ","/lib/events/knock.c":"mixed direct_knock_on_str_on_obj(string str, object target){ mapping RemoveKnock(string item){ mixed direct_knock_obj(object target){ varargs mapping SetKnock(mixed key, mixed desc){ varargs mixed CanKnock(object who, string component){ mixed direct_knock_on_obj(object target){ mixed direct_knock_str_on_obj(string str, object target){ string array GetKnocks(){ varargs mixed eventKnock(object who, mixed component){ ","/lib/events/bait.c":"string array GetSave(){ int GetBait(){ mixed CanBait(object who){ int AddBait(int x){ int SetBait(int x){ mixed direct_bait_obj_with_obj(){ int eventBait(object who, object bait){ ","/lib/stargate.c":"void create(){ void init(){ void heart_beat(){ int eventEnter(object who){ string status(){ string displayLong(){ string displayShort(){ mixed cmdDial(string s){ int cmdEnter(string what){ void SetOrigin(string o, string d){ string GetOrigin(){ void eventConnect(string destination){ int eventDisconnect(){ ","/lib/std/lockpick.c":"void create(){ void init(){ varargs mixed CanPick(mixed who, mixed what){ varargs mixed eventPickLock(mixed who, mixed id, mixed tool){ int SetPickingQuality(int i){ int GetPickingQuality(){ mixed indirect_pick_str_on_obj_with_obj(string str, object target, object tool, ","/lib/std/furnace.c":"void create(){ int CanReceive(object ob){ void heart_beat(){ void init(){ ","/lib/nmsh.c":"string GetKeyName(){ return 0; } static void create(){ static int array GetScreen(){ return ({ 79, 24 }); } string get_path(){ return query_cwd(); } int Setup(){ string GetUserPath(){ varargs int GetInvis(){ return 0; } string process_input(string str){ string GetAlias(string alias){ string GetXverb(string xverb){ varargs int erase_prompt(int x){ nomask static int cmd_alias(string str){ nomask static int cmd_unalias(string str){ nomask static int cmd_pwd(){ nomask static int cmd_work(string str){ string GetPromptString(){ nomask static int cmd_cd(string str){ nomask static int cmd_nickname(string str){ nomask static int cmd_nmsh(string str){ nomask static int cmd_pushd(string str){ nomask static int cmd_popd(){ varargs nomask string write_prompt(string str){ nomask static void process_request(string request, string xtra){ static int request_vis(object ob){ private static int set_cwd(string str){ nomask private static string do_nickname(string str){ nomask private static string do_alias(string str){ nomask static string replace_nickname(string str){ void reset_prompt(){ static string user_names(object ob){ string SetUserPath(string str){ string query_prev_wd(){ return Directories[\"previous\"]; } string SetPrompt(string str){ return Prompt = str; } static void EchoCommand(string str){ int query_mp(){ return 1; } int query_max_mp(){ return 10; } int query_hp(){ return 1; } int query_max_hp(){ return 10; } int query_sp(){ return 1; } int query_max_sp(){ return 10; } static int rAscii(string str){ static int rAnsi(string str){ static int rArrow(string str){ static int rDel(){ static int rBackspace(){ static int rCtrl(string str){ static int rEnter(){ mixed RecalculateHist(int x){ ","/lib/events/swivel.c":"varargs mixed eventSwivel(object who, mixed what){ mixed direct_swivel_str(string str){ mixed direct_swivel_wrd_obj(object target){ varargs int CanSwivel(mixed who, mixed what){ mixed direct_swivel_obj(object target){ mixed direct_swivel_str_on_obj(string str, object target){ ","/lib/firearm.c":"int CanReceive(object ob){ int CanRelease(object ob){ mixed CanGetFrom(object who, object item){ mixed CanPutInto(object who, object what){ static void create(){ varargs mixed eventShoot(object ob, mixed target, string dir, string whom){ void init(){ mixed eventLoad(object ob){ int SetLoaded(int i){ loaded=i; return 1; } mixed eventUnload(mixed what){ int GetMaxLoaded(){ int GetLive(){ return loaded; } int SetMillimeter(int x){ Millimeter=x; return 1; } int missed_shot(){ string GetFirearmType(){ return FirearmType; } int eventFire(mixed str){ int SetMaxAmmo(int x){ MaxAmmo=x; return 1; } int GetMaxAmmo(){ return MaxAmmo; } string SetFirearmName(string str){ string GetAmmoType(){ return AmmoType; } string GetFirearmName(){ int CalculateAmmoSize(){ int GetCaliber(){ return Caliber; } int InitRevolver(string array arr){ int GetMag(){ return mag; } int SetAmmoFile(string str){ AmmoFile=str; return 1; } int GetMillimeter(){ return Millimeter; } int GetMagnum(){ int SetMag(int i){ mag=i; return 1; } int SetMagnum(int i){ int doRevolverUnload(string what, string num){ int doMagUnload(){ int SetFirearmType(string str){ FirearmType=str; return 1; } int SetAmmoType(string str){ AmmoType=str; return 1; } int SetCaliber(int x){ Caliber=x; return 1; } ","/lib/std/vendor.c":"static void create(){ int CanCarry(int amount){ return 1; } mixed eventBuy(object who, object array obs){ int indirect_sell_obj_to_liv(){ return 1; } mixed eventAsk(object who, string str){ int GetValue(object ob, object who){ int GetVendorType(){ return VendorType; } int SetVendorType(int x){ return (VendorType = x); } mixed CanSell(object who, string what){ string GetLocalCurrency(){ return LocalCurrency; } mixed CanBuy(object who, object array obs){ int indirect_sell_obs_to_liv(){ return 1; } int GetMaxItems(){ return MaxItems; } int cmdShow(object who, string args){ int cmdBrowse(object who, string args){ int cmdPrice(object who, string args){ string GetStorageRoom(){ return StorageRoom; } int cmdAppraise(object who, string args){ mixed direct_buy_str_from_liv(string str){ int GetCost(object ob, object who){ string SetLocalCurrency(string str){ return (LocalCurrency = str); } string SetStorageRoom(string room){ return (StorageRoom = room); } int SetMaxItems(int x){ return (MaxItems = x); } mixed eventSell(object who, mixed what){ ","/lib/messages.c":"string GetName(){ return 0; } static void create(){ string SetMessage(string msg, string str){ mapping GetMessages(){ return copy(Messages); } ","/lib/props/save.c":"varargs void create(){ string GetSaveName(){ int GetLastSave(){ int SetPersistent(int x){ mixed GetPersistentInventory(){ static varargs int RestoreObject(mixed str, int i){ int eventDestruct(){ static varargs int SaveObject(mixed str, int i){ ","/lib/events/show.c":"mixed indirect_show_liv_obj(object target){ mixed direct_show_obj_liv(){ mixed direct_show_obj_to_liv(){ ","/lib/comp/object.c":"static void create(){ static int Destruct(){ mixed CanDest(){ mixed direct_dest_obj(){ return CanDest(); } mixed indirect_dest_obj(){ return CanDest(); } ","/lib/blank_pile.c":"string GetShort(){ static void create(){ string array GetId(){ ","/lib/chapel.c":"static void create(){ string array GetClasses(){ return Classes; } string array SetReligion(string adj, string noun){ varargs string GetReligion(int flag){ return Religion[flag]; } mixed CanSacrifice(object who, object what, string deus){ mixed CanMarry(object who, object spouse1, object spouse2){ mixed eventMarry(object who, object spouse1, object spouse2){ mixed eventSacrifice(object who, object what, string deus){ string array SetClasses(string array rc){ return (Classes = rc); } string array SetDeities(string array deities){ int SetAllowSacrifice(int x){ return (AllowSacrifice = x); } int SetSacrificeType(int x){ return (SacrificeType = x); } int GetAllowSacrifice(){ return AllowSacrifice; } int GetSacrificeType(){ return SacrificeType; } string array GetDeities(){ return Deities; } int AddSacrificeType(int x){ return (SacrificeType |= x); } ","/lib/std/base_storage.c":"int inventory_visible(){ int GetOpacity(){ int SetOpacity(mixed arg){ varargs mixed CanShowInterior(object who, object target){ int GetRadiantLight(int ambient){ int eventReceiveObject(object ob){ int inventory_accessible(){ mixed CanGetFrom(object who, object item){ mixed CanPutInto(object who, object what){ void create(){ mixed CanClose(object who, string id){ mixed CanOpen(object who, string id){ mixed CanLock(object who, string id){ mixed CanPick(object who, string id){ mixed CanUnlock(object who, string id, object key){ void PutCheck(){ int GetRecurseDepth(){ int AddRecurseDepth(int i){ int SetRecurseDepth(int i){ int GetMaxRecurseDepth(){ int SetMaxRecurseDepth(int i){ int GetCanClose(){ int SetCanClose(int x){ int GetCanLock(){ int SetCanLock(int x){ void SetKey(string key){ ","/lib/events/manipulate.c":"varargs mixed CanManipulate(object who, string component){ varargs mixed eventManipulate(object who, string component){ string array GetManipulates(){ mapping RemoveManipulate(string item){ varargs mapping SetManipulate(mixed key, mixed desc){ mixed direct_move_obj(object target){ mixed direct_move_str_on_obj(string str, object target){ ","/lib/events/shake.c":"varargs mixed eventShake(object who, string component){ string array GetShakes(){ mapping RemoveShake(string item){ varargs mapping SetShake(mixed key, mixed desc){ varargs mixed CanShake(object who, string component){ mixed direct_shake_obj(object target){ mixed direct_shake_str_on_obj(string str, object target){ ","/lib/lvs/abilities.c":"int GetSkillLevel(string skill){ int AddSkillPoints(string name, int x){ int GetLevel(){ varargs void SetSkill(string skill, int level, int cls){ static void create(){ mapping GetSkillsMap(){ string array GetPrimarySkills(){ int GetBaseSkillLevel(string skill){ int ResetLevel(){ int GetMaxSkillLevel(string skill){ int GetMaxSkillPoints(string skill, int level){ void AddSkillBonus(string skill, mixed f){ varargs void RemoveSkillBonus(string skill, object ob){ int GetSkillBonus(string skill){ int SetLevel(int x){ int GetSkillClass(string skill){ ","/lib/std/item.c":"string array GetSave(){ void eventDeteriorate(int type){ string GetItemCondition(){ int eventMove(mixed dest){ static void create(){ varargs mixed direct_get_obj_from_obj(object item, mixed gamma,mixed alfa, mixed beta, mixed epsilon){ static int Destruct(){ mixed eventShow(object who, string component){ string GetExternalDesc(object who){ static mixed array AddSave(mixed array vars){ mixed CanSteal(object who){ void init(){ } string SetQuestId(string name){ string GetQuestId(){ int SetRetainOnDeath(int x){ mixed CanRepair(object who){ varargs mixed CanThrow(object who, object target){ int GetRetainOnDeath(){ mixed direct_balance_obj_to_obj(){ mixed direct_cast_str_on_obj(){ mixed direct_cast_str_on_str_of_obj(){ int SetNoCondition(int i){ void eventRemoveBlessing(){ int eventBless(int amount, int time){ mixed eventThrow(object who, object target){ varargs mixed eventRepair(object who, int strength, int type){ mixed indirect_balance_obj_to_obj(){ mixed direct_compare_obj_to_obj(){ mixed indirect_compare_obj_to_obj(){ mixed direct_judge_obj_to_obj(){ mixed indirect_judge_obj_to_obj(){ mixed direct_use_obj_to_str(){ mixed direct_throw_obj_word_obj(){ mixed indirect_throw_obj_into_obj(){ int direct_sacrifice_obj_to_str(string deus){ mixed direct_bless_obj(){ mixed direct_curse_obj(){ ","/lib/std/chair.c":"int CanGet(object who){ void create(){ ","/lib/teller.c":"static void create(){ mixed GetCurrencies(){ return copy(Currencies); } string GetLocalCurrency(){ return LocalCurrency; } int SetLocalFee(int x){ return (LocalFee = x); } int GetLocalFee(){ return LocalFee; } int eventExchange(object who, int amount, string str1, string str2){ mixed CanBank(object who){ int GetNonLocalFee(){ return NonLocalFee; } int GetOpenFee(){ return OpenFee; } string GetBankName(){ return BankName; } int SetOpenFee(int x){ return (OpenFee = x); } float SetExchangeFee(float x){ return (ExchangeFee = x); } string SetBankName(string str){ return (BankName = str); } int GetExchangeFee(){ return ExchangeFee; } int cmdParse(object who, string cmd, string str, mixed args...){ int eventOpenAccount(object who){ int AddSurcharge(object who, string currency, int amount){ int eventDeposit(object who, string currency, int amount){ mixed SetCurrencies(mixed var){ int SetNonLocalFee(int x){ return (NonLocalFee = x); } string SetLocalCurrency(string str){ return (LocalCurrency = str); } int eventBalance(object who){ int eventWithdraw(object who, string currency, int amount){ ","/lib/events/climb.c":"mixed direct_climb_obj(object ob){ mixed direct_climb_word_obj(string word, object ob){ mixed direct_climb_out_of_obj(object ob){ varargs mixed eventClimb(object who, int type, string where){ mapping GetClimbs(){ int SetCanClimbCarried(int i){ int GetCanClimbCarried(){ varargs static mapping SetClimb(mixed val, int type){ ","/lib/trap.c":"static void heart_beat(){ static void create(){ mixed eventFree(object who, string target){ mixed eventCapture(object who, object target){ int GetEscapeChance(){ int SetEscapeChance(int x){ mixed eventEscape(){ mixed CanCapture(object who, object target){ mixed CanFree(object who, object target){ mixed indirect_free_liv_from_obj(object target){ mixed indirect_capture_liv_word_obj(object target){ int GetMaxCapture(){ object array GetCaptives(){ int SetMaxCapture(int x){ ","/lib/shadow.c":"int eventShadow(object ob){ int eventUnshadow(){ string GetShadowedName(){ object GetShadowedObject(){ ","/lib/poison.c":"static void create(){ int SetPoisonStrength(int x){ return (PoisonStrength = x); } mixed GetPoisonStrength(){ return PoisonStrength; } mixed indirect_poison_obj_with_obj(){ int SetPoisonUses(int x){ return (PoisonUses = x); } int GetPoisonUses(){ return PoisonUses; } mixed eventSpreadPoison(object who, object target){ ","/lib/remote.c":"static void create() { string eventCommand(string cmd, string arg) { string eventWriteFile(string file, string str) { string eventReadFile(string file) { ","/lib/events/lock_with.c":"varargs mixed indirect_lock_obj_with_obj(object target, object key, mixed id){ varargs mixed indirect_lock_obj_with_str(object target, mixed key, mixed id...){ mixed indirect_unlock_obj_with_obj(object target, object key, mixed id...){ varargs mixed indirect_unlock_obj_with_str(object target, mixed key, mixed id){ int GetDisableChance(){ int SetDisableChance(int x){ int SetDisabled(int x){ int GetDisabled(){ mixed array GetSave(){ mixed eventLockLock(object who, object what){ mixed eventUnlockLock(object who, object what){ ","/lib/props/id.c":"string GetName(){ string GetKeyName(){ string array GetId(){ string array GetAdjectives(){ string array GetCanonicalId(){ string array parse_command_id_list(){ string array parse_command_plural_id_list(){ string array parse_command_adjectiv_id_list(){ string SetKeyName(string nom){ string GetCapName(){ varargs void eventAnnounceCanonicalId(object env){ varargs void ReceiveCanonicalId(mixed foo, int leaving){ varargs string array SetAdjectives(mixed adjs...){ string SetCapName(string str){ int SetMatching(int i){ int GetMatching(){ string GetUniqueId(){ varargs string array SetId(mixed val...){ ","/lib/props/clean.c":"int eventDestruct(){ int GetNoClean(){ static int SetNoClean(int x){ int clean_up(int ref_exists){ ","/lib/cedit.c":"void create(){ static int array GetScreen(){ return ({ 79, 24 }); } varargs int SetCedmode(int x, string file){ varargs int RedrawScreen(int topline){ static int UpdateScreen(){ static varargs int CeditCollate(int x){ /* when lines need to be resorted array / static varargs int CeditSave(string file){ int ClearBuffers(){ varargs int StatReport(string str){ static int rAscii(string c){ static int rAnsi(string str){ static int rArrow(string str){ static int rDel(){ static int rBackspace(){ int rCtrl(string c){ static int rEnter(){ int GetCedmode(){ ","/lib/events/sink.c":"int SetNoSink(int i){ int GetNoSink(){ mixed eventSink(){ ","/lib/comp/weapon.c":"int eventStrike(object target){ string array GetSave(){ mixed eventEquip(object who, string array limbs){ mixed CanEquip(object who, string array limbs){ mixed eventUnequip(object who){ int GetHands(){ mixed direct_wear_obj(){ int eventDeteriorate(int type){ string GetWeaponType(){ varargs string GetEquippedDescription(object who){ int SetHands(int x){ mixed SetWield(mixed val){ int GetWielded(){ string SetWeaponType(string str){ mixed direct_remove_obj(){ string GetEquippedShort(){ ","/lib/std/story.c":"string SetTalesDir(string dir){ static void create(){ string GetNoTaleMessage(){ return NoTaleMessage; } string SetNoTaleMessage(string notalemessage){ string GetTalesDir(){ return TalesDir; } int GetTellingTale(){ return AlreadyTellingTale; } void TellTale( int part ){ void PickTale( string taletotell ){ ","/lib/lead.c":"static void create(){ mapping GetFollowerMap(){ return copy(Followers); } object array AddFollower(object follower){ varargs mixed CanLead(object ob){ int SetFollowed(object follower, int followed){ int GetFollowed(object follower){ int AddFollowBonus(object follower, int bonus){ int GetFollowBonus(object follower){ varargs mixed CanEvade(object ob){ int eventMoveFollowers(object dest){ int eventEvade(object ob){ mixed direct_lead_liv(){ mixed direct_evade_liv(){ object array RemoveFollower(object follower){ object array GetFollowers(){ return filter(keys(Followers), (: $1 :)); } ","/lib/daemons/verb.c":"static void create(){ string GetVerb(){ return Verb; } string array GetVerbs(){ return ({ Verb }); } varargs static string array SetRules(mixed array args...){ string array GetRules(){ return copy(Rules); } static string SetErrorMessage(string str){ return (ErrorMessage = str); } string GetErrorMessage(){ return ErrorMessage; } string array GetSynonyms(){ return copy(Synonyms); } static string SetVerb(string str){ varargs static string array SetSynonyms(mixed array args...){ ","/lib/enter.c":"static void create(){ string GetDoor(){ mixed eventClose(object who){ varargs void SetEnter(string dest, function pre, function post){ varargs void SetDoor(string door, string side){ string GetEnter(){ string ResolveObjectName(string file){ varargs mixed eventLock(object who, mixed arg1, mixed arg2){ varargs mixed eventPick(object who, string str, object tool){ mixed direct_open_obj(object target){ mixed direct_open_obj_with_obj(object target, object ob){ mixed eventUnlock(object who, object key){ varargs mixed direct_lock_obj_with_obj(object target, object tool){ mixed direct_pick_str_on_obj(string str, object ob, string id1, string id2){ mixed direct_pick_str_on_obj_with_obj(string str, object ob, object w, mixed direct_unlock_obj_with_obj(object target, object w){ mixed direct_wizlock_obj(){ return 1; } mixed direct_wizunlock_obj(){ return 1; } varargs mixed eventOpen(object who, object tool){ mixed direct_close_obj(object target){ varargs mixed eventEnter(object who, string what, string verb){ mixed direct_enter_into_obj(){ mixed direct_enter_obj(){ varargs mixed eventKnock(object who, mixed what){ varargs mixed eventScratch(object who, object tool){ string GetDoorSide(){ void SetDoorSide(string doorside){ ","/lib/body.c":"mixed eventFall(){ string GetName(){ return 0; } static void heart_beat(){ string GetRace(){ return 0; } varargs int eventReceiveDamage(mixed agent, int type, int x, int internal, void eventCompleteHeal(int x){ varargs int GetHealthPoints(string limb){ void NewBody(string race){ static void create(){ string GetLong(string nom){ string GetCapName(){ return 0; } varargs int eventDie(mixed agent){ int SetHealthPoints(int x){ int GetMass(){ varargs string array GetMissingLimbs(int not_default){ string GetResistance(int type){ return \"none\"; } int GetSize(int decimal){ int GetBodyType(){ int CanFly(){ int CanSwim(){ int AddLead(string ammo,int number){ string array GetEquippedLimbs(){ mixed CanManipulate(){ int HealLimb(string limb){ int DestLimb(string limb){ string GetMissingLimbParent(string limb){ return MissingLimbs[limb][\"parent\"]; } string array GetMissingLimbParents(string limb){ int eventCompareLimbs(string limb1, string limb2){ string GetHealthShort(){ void eventCheckHealing(){ varargs object array GetWorn(string limb){ varargs mixed GetWielded(string limb){ varargs static int AddHealthPoints(int x, string limb, mixed agent){ int AddMagicPoints(int x){ int GetMagicPoints(){ return MagicPoints; } int GetMaxMagicPoints(){ return 0; } float AddStaminaPoints(mixed x){ int GetStaminaPoints(){ return to_int(StaminaPoints); } float GetMaxStaminaPoints(){ return 0; } int AddMagicProtection(class MagicProtection cl){ int RemoveMagicProtection(mixed i){ int SetSleeping(int x){ int AddAlcohol(int x){ int GetAlcohol(){ return Alcohol; } int AddCaffeine(int x){ int GetCaffeine(){ return Caffeine; } int AddFood(int x){ return (Food += x); } int GetFood(){ return Food; } int AddDrink(int x){ return (Drink += x); } int GetDrink(){ return Drink; } int AddPoison(int x){ int GetPoison(){ int GetDying(){ int GetHeartRate(){ int GetHealRate(){ int AddExperiencePoints(mixed x){ int GetExperiencePoints(){ return ExperiencePoints; } int AddExperienceDebt(mixed x) { int GetExperienceDebt() { return ExperienceDebt; } int SetMelee(int i){ melee = i; return melee; } int GetMelee(){ return melee; } mixed SetProtect(function f){ return (Protect = f); } function GetProtect(){ return Protect; } int GetHeartModifier(){ string array RemoveExtraChannels(string array chans){ int GetFalling(){ void eventReconnect(){ string array GetExtraChannels(){ string array AddExtraChannels(string array chans){ int GetSleeping(){ return Sleeping; } string array GetLimbs(){ varargs mixed eventBuy(mixed arg1, mixed arg2, mixed arg3){ varargs int GetLead(string ammo){ int SetDying(int x){ int SetFalling(int i){ varargs int eventHealDamage(int x, int internal, mixed limbs){ int eventCheckProtection(object agent, int type, int damage){ mixed eventReceiveThrow(object who, object what){ int eventRemoveItem(object ob){ int eventWear(object ob, mixed limbs){ mixed CanWear(object ob, string array limbs){ varargs int AddLimb(string limb, string parent, int classes, int array armors){ varargs int RestoreLimb(string limb, int recurse){ varargs int RemoveLimb(string limb, mixed agent, int quiet){ string GetRandomLimb(string targ){ string GetTorso(){ int GetLimbClass(string limb){ string GetLimbParent(string limb){ return Limbs[limb][\"parent\"]; } string array GetLimbChildren(string limb){ string array GetWieldingLimbs(){ varargs int AddFingers(string limb, int x){ int GetFingers(string limb){ int SetMass(int i){ int SetSize(int i){ int SetBodyType(int i){ int GetEncumbrance(){ string SetBodyComposition(string str){ string GetBodyComposition(){ int GetPacifist(){ int SetPacifist(int i){ int SetCanBite(int i){ int GetCanBite(){ string array SetExtraChannels(string array chans){ mixed direct_body_liv(){ mixed direct_turn_liv(){ void eventCheckEnvironment(){ varargs int eventCollapse(int noparalyze){ void ParseHook(string str){ mixed CanRemoveItem(object ob){ return 1; } private void checkCollapse(){ varargs int AddHeartModifier(int x, int t){ int AddHP(int hp){ string GetAffectLong(){ int GetDeathEvents(){ int SetDeathEvents(int i){ int SetGodMode(int i){ int GetGodMode(){ string SetKeepalive(string str){ string GetKeepalive(){ ","/lib/elevator_button.c":"static void create() { object GetElevator(){ object SetElevator(object ob){ string GetButtonId(){ string SetButtonId(string str){ int openDoor(object who) { ","/lib/leader.c":"static void create(){ int eventPreAttack(object ob){ mixed eventAsk(object who, string str){ void eventPreview(object who, string args){ void eventConvert(object who, string args){ int eventTeachPlayer(object who, string spell){ void eventJoin(object who, string args){ ","/lib/props/properties.c":"mixed GetProperty(string prop){ mixed SetProperty(string prop, mixed val){ mapping GetProperties(){ int RemoveProperty(string prop){ mapping SetProperties(mapping props){ mixed AddProperty(string prop, mixed val){ ","/lib/props/uniqueness.c":"int GetUnique(){ int SetUnique(int x){ int array GetRarity(){ int GetMaxClones(){ int SetMaxClones(int x){ int array SetRarity(int count, int days){ ","/lib/bonus.c":"mixed CanDrop(object who){ return 0; } void create(){ mixed CanGet(object who){ return 0; } int eventDestruct(){ mixed CanPut(object who){ return 0; } mixed CanSell(object who){ return 0; } void init(){ mapping SetSkills(mapping arg){ void heart_beat(){ string GetBonusName(){ mapping SetStats(mapping arg){ mapping GetStats(){ mapping GetSkills(){ mapping SetPoints(mapping arg){ mixed CanGive(object who){ return 0; } int GetBonusDuration(){ int RemoveBonuses(){ int SetBonusDuration(int i){ mapping GetPoints(){ int SetBonuses(){ int AddBonusDuration(int i){ string SetBonusName(string name){ ","/lib/events/stop.c":"varargs mixed eventStop(object who, string what, mixed args){ varargs mixed CanStop(object who, string what, mixed args){ ","/lib/props/radiance.c":"int GetRadiantLight(int ambient){ int GetBaseRadiance(int foo){ int SetRadiantLight(int x){ ","/lib/events/describe.c":"void eventDescribeEnvironment(int brief){ ","/lib/props/addstuff.c":"varargs int AddStuff(string array str, int q){ ","/lib/events/install.c":"int direct_uninstall_obj(object what){ int direct_install_obj_word_obj(object thingus, mixed word, object target){ int indirect_uninstall_obj_word_obj(object target, mixed word, object thingus){ int indirect_install_obj_word_obj(object target, mixed word, object thingus){ varargs mixed CanUninstall(object who, object where, object what){ varargs mixed eventInstall(object what, object where){ varargs mixed eventUninstall(object what, object where){ varargs mixed CanInstall(object who, object where, object what){ ","/lib/lvs/position.c":"int GetPosition(){ mixed eventFly(){ int SetPosition(int x){ string GetFurnitureName(){ varargs mixed eventLay(object target){ varargs mixed eventKneel(object target){ varargs mixed eventSit(object target){ mixed eventSwim(){ mixed eventFloat(){ mixed eventLand(){ mixed eventStand(){ ","/lib/interface.c":"static void create(){ int Setup(){ int GetClient(){ return Client; } static string process_input(string str){ string GetKeyName(){ return 0; } varargs int eventPrint(string msg, mixed arg2, mixed arg3){ int array GetScreen(){ return Screen; } static int rAscii(string str){ static int rAnsi(string str){ static int rArrow(string str){ static int rDel(){ static int rBackspace(){ static int rCtrl(string str){ static int rEnter(){ varargs void eventReceive(string message, int noprompt, int noerase){ int GetBlocked(string type){ return (Blocked[\"all\"] || Blocked[type]); } void receive_message(mixed msg_class, string msg){ int eventFlushQueuedMessages(){ varargs int eventPauseMessages(int x, int exceptions){ static varargs int PassengerPrint(string msg, mixed arg2, int GetAnnoyblock(){ string GetTerminal(){ return Terminal; } static void terminal_type(string str){ static void window_size(int width, int height){ static void receive_snoop(string str){ receive_message(\"snoop\", \"%\"+str); } varargs int SetBlocked(string type, int flag){ int SetClient(int x){ int SetLogHarass(int x){ int GetLogHarass(){ return LogHarass; } int array SetScreen(int width, int height){ string SetTerminal(string terminal){ int SetAnnoyblock(int i){ ","/lib/bot.c":"static void create(){ string GetLong(string nom){ void init(){ varargs int eventDie(mixed agent){ string GetHealthShort(){ int GetNoBotCondition(){ int SetNoBotCondition(int foo){ ","/lib/props/deterioration.c":"int eventReceiveDamage(mixed agent, int type, int amt, int i, mixed array l){ string array GetSave(){ int GetBroken(){ int SetBroken(int x){ int SetDamagePoints(int x){ int GetDamagePoints(){ int GetDeterioration(){ string GetItemCondition(){ ","/lib/std/storage.c":"int GetRadiantLight(int ambient){ void create(){ int SetSaveRecurse(int x){ static mixed array AddSave(mixed array vars){ string array GetSave(){ ","/lib/command.c":"static void create(){ string array GetSearchPath(){ return SearchPath; } int GetForced(){ return Forced; } int Setup(){ varargs int eventRetryCommand(string lastcmd, int errtype, mixed args){ string SetCommandFail(string str){ static int cmdAll(string args){ int eventForce(string cmd){ string array AddSearchPath(mixed val){ string array RemoveSearchPath(mixed val){ int GetClient(){ return 0; } string GetCommandFail(){ return CommandFail; } int direct_force_liv_str(){ return 1; } int direct_force_liv_to_str(){ return 1; } static string process_input(string args){ int cmdDebugAll(string args){ int eventForceQueuedCommand(string cmd){ int eventExecuteQueuedCommands(){ int eventQueueCommand(string line){ int DoneTrying(){ int LimbCertain(string str){ string GetCurrentCommand(){ int SetPlayerPaused(int i){ int GetPlayerPaused(){ ","/lib/events/close.c":"int GetOpen(){ mixed eventClose(object who){ varargs mixed CanClose(object who, string id){ int SetOpen(int x){ int SetClosed(int x){ varargs mixed CanOpen(object who, object tool){ varargs mixed eventOpen(object who, object tool){ int inventory_visible(){ mixed direct_close_obj(object target){ mixed direct_open_obj(object target){ int inventory_accessible(){ int GetClosed(){ mixed direct_open_obj_with_obj(object target, object tool){ ","/lib/learn.c":"int direct_learn_str_from_liv(){ return 1;} int direct_learn_to_str_from_liv(){ return 1;} int CanLearn(){ int eventLearn(object who, string what){ ","/lib/cylinder.c":"void create(){ ","/lib/pile.c":"string GetShort(){ int eventMove(mixed dest){ static void create(){ int GetMass(){ string array GetId(){ void init(){ void SetPile(string str, int amt){ void SetCurrency(string str, int amt){ mixed eventGetMoney(object who, int amount, string curr){ mixed direct_get_wrd_wrd_from_obj(string amt, string curr){ mixed direct_get_wrd_wrd_out_of_obj(string num, string curr){ int GetPileAmount(){ return PileAmount; } string GetPileType(){ return PileType; } ","/lib/events/shoot.c":"varargs mixed direct_shoot_obj_with_obj(mixed args...){ varargs mixed indirect_shoot_obj_with_obj(mixed args...){ varargs mixed indirect_shoot_obj_at_obj(mixed args...){ varargs mixed direct_shoot_obj_at_liv(mixed args...){ varargs mixed direct_shoot_liv_with_obj(mixed args...){ varargs mixed indirect_shoot_liv_with_obj(mixed args...){ varargs mixed indirect_shoot_obj_at_liv(mixed args...){ varargs mixed direct_shoot_obj_wrd(mixed args...){ varargs mixed eventShoot(object who, mixed target, string dir, string whom){ int MustCarry(int i){ int MustWield(int i){ mixed CanShoot(object shooter, mixed target){ varargs mixed direct_shoot_obj_wrd_at_wrd(mixed args...){ ","/lib/combatmsg.c":"mixed GetCombatMove(string type, int skill){ varargs void SendMeleeMessages(object target, int x, string targlimb, string limb){ varargs void SendWeaponMessages(object target, int x, object weapon, string limb){ static mixed GetMissData(object targ, int type, string limb){ mixed GetCombatVerbs(string type, int damage){ static void eventSendMissMessages(object target, int x, string limb){ ","/lib/events/get_from.c":"int inventory_visible(){ int inventory_accessible(){ mixed indirect_get_obj_from_obj(object item, object container){ mixed indirect_get_obj_out_of_obj(object item, object container){ mixed indirect_get_obj_obj(object item, object container){ mixed indirect_get_obs_from_obj(object array items, object storage){ mixed indirect_get_obs_out_of_obj(object array items, object storage){ mixed indirect_get_obs_obj(object array items, object storage){ mixed indirect_put_obj_word_obj(object what, string word, object storage){ mixed indirect_put_obj_obj(object what, string word, object storage){ mixed indirect_put_obs_word_obj(object array items, string wrd, object storage){ mixed indirect_put_obs_obj(object array items, string wrd, object storage){ mixed CanGetFrom(object who, object item){ mixed CanPutInto(object who, object item){ mixed CanPutOnto(object who, object item){ mixed eventGetFrom(object who, object array what){ mixed eventPutInto(object who, object what){ mixed eventPutOnto(object who, object what){ ","/lib/pistol.c":"static void create(){ void init(){ ","/lib/events/listen.c":"varargs mixed SetListen(mixed array args...){ varargs string GetListen(string str, object who){ mapping RemoveListen(string item){ mapping GetListenMap(){ varargs mixed eventListen(object who, string str){ string array GetListens(){ mixed direct_listen_to_obj(){ mixed direct_listen_obj(){ mixed direct_listen_to_str_word_obj(string str){ ","/lib/props/damage.c":"int GetDamageType(){ int GetClass(){ int eventStrike(object ob){ int SetClass(int x){ string array GetSave(){ int GetMaxClass(){ int SetDamageType(int x ){ ","/lib/shop.c":"static void create(){ void init(){ int list(string str){ int show(string str){ int appraise(string str){ int price(string str){ ","/lib/chat.c":"static void create(){ int eventDestruct(){ string array GetChannels(){ return keys(Channels); } int GetNoChanColors(){ int SetNoChanColors(int x){ int GetMutedType(string type){ int GetGaggedType(string type){ int SetGagged(string type, mixed x){ int SetMuted(string type, mixed x){ static void net_dead(){ void eventReconnect(){ string array AddChannel(mixed val){ string array RemoveChannel(mixed val){ string array RestrictChannel(mixed val){ string array UnrestrictChannel(mixed val){ string array GetRestrictedChannels(){ return (RestrictedChannels + ({})); } mapping returnChannels(){ static string chat_command(string str){ ","/lib/burn.c":"static void create(){ mixed direct_light_obj(){ mixed eventLight(object who, object what){ static void heart_beat(){ mixed indirect_light_obs_with_obj(object array targets, object source){ static int SetBurntValue(int x){ mixed direct_burn_obj_with_obj(){ mixed direct_extinguish_obj(){ static int SetHeat(int x){ mixed CanExtinguish(object who){ int GetBurning(){ static int SetMinHeat(int x){ int GetHeat(){ static int SetFuelRequired(int x){ mixed indirect_burn_obj_with_obj(object target, object source){ mixed eventBurnOut(){ mixed indirect_burn_obs_with_obj(object array targets, object source){ int GetBurntValue(){ int GetFuelRequired(){ static int SetBurnRate(int x){ mixed direct_light_obj_with_obj(){ int GetBurnRate(){ mixed CanBurn(object who){ mixed indirect_light_obj_with_obj(object target, object source){ int GetMinHeat(){ mixed eventExtinguish(){ ","/lib/quest.c":"void create(){ void AddPartyQuest(string title, string desc){ void AddQuest(string title, string desc){ int SetQuestPoints(int i){ int GetQuestPoints(){ return QuestPoints; } int AddQuestPoints(mixed x){ void AddQuestSkillPoints(string skill, int amount){ void AddQuestStatPoints(string stat, int amount){ void AddQuestCurrency(string type, int amount){ mixed array GetQuests(){ mapping RemoveQuest(string str){ ","/lib/std/base_armor.c":"string array GetSave(){ void eventDeteriorate(int type){ string GetItemCondition(){ int eventMove(mixed dest){ mixed CanEquip(object who, string array limbs){ mixed eventEquip(object who, string array limbs){ varargs mixed eventUnequip(object who){ static void create(){ static int Destruct(){ mixed eventShow(object who, string component){ varargs string GetExternalDesc(object who){ static mixed array AddSave(mixed array vars){ mixed CanSteal(object who){ string array GetRestrictLimbs(){ int GetSize(){ void init(){ int SetRetainOnDeath(int x ){ return (RetainOnDeath = x); } mixed CanRepair(object who){ varargs string GetEquippedDescription(object who){ int GetRetainOnDeath(){ return RetainOnDeath; } int GetFingers(){ int SetSize(int x){ mapping GetProtectionMap(){ varargs mixed eventRepair(object who, int strength, int type){ string GetEquippedShort(){ varargs int restrict(mixed arg, int i){ int GetMaxProtection(int type){ int SetFingers(int x){ string array LimbGuess(object who){ string array GetBaseLimbs(){ int SetProtection(int type, int amount){ int SetAC(int i){ string array SetRestrictLimbs(string array limbs){ string array SetBaseLimbs(string array limbs){ mixed GetWear(){ mixed SetWear(mixed val){ ","/lib/money.c":"int AddMoney(string type, int amount){ varargs void SetMoney(mixed val, int amount){ mapping GetMoneyMap(){ return copy(Money); } ","/lib/std/wound.c":"void create(){ void heart_beat(){ mixed CanGet(object ob) { return \"#Your hands slip on the gunshot wounds.\";} mixed CanDrop(object ob) { return \"#Your hands slip on the gunshot wounds.\";} string GetAffectLong(object ob) { string WoundLong(){ ","/lib/shadow_hook.c":"nomask int AddShadow(object sombra){ nomask int RemoveShadow(object sombra){ nomask mapping GetShadows(){ ","/lib/flask.c":"static void create(){ string GetExternalDesc(){ varargs mixed eventDrink(object who, object target, string foo){ varargs mixed CanDrink(object who, string what){ mixed direct_drink_obj(){ mixed direct_drink_from_obj(){ mixed GetStrength(){ return FlaskStrength; } int GetMealType(){ return MealType; } int direct_pour_out_obj(){ return 1;} int direct_empty_obj(){ return 1;} int direct_pour_obj_out(){ return 1;} int direct_fill_obj_with_obj(){ return 1;} int indirect_pour_from_obj_into_obj(){ return 1;} int direct_fill_obj_from_obj(){ return 1;} int direct_pour_obj_into_obj(){ return 1;} mixed indirect_drink_from_obj(){ int indirect_fill_obj_with_obj(){ return 1;} int indirect_fill_obj_from_obj(){ return 1;} int indirect_pour_obj_into_obj(){ return 1;} int SetMealType(int x){ return (MealType = x); } int SetStrength(int x){ return (FlaskStrength = x); } mixed GetTapped(){ return Tapped; } mixed eventFill(object who, object from){ mixed eventPour(object who, object from){ int CanFillMe(){ int CanFillOther(){ int SetTapped(int x){ int SetFlaskUses(int x){ int GetFlaskUses(){ return FlaskUses; } int SetEverFill(int x){ return (EverFill = x); } int GetEverFill(){ return EverFill; } int SetMaxFlask(int x){ return (MaxFlask = x); } int GetMaxFlask(){ return MaxFlask; } string GetFlaskContents(){ return FlaskContents; } string SetFlaskContents(string str){ varargs mixed eventEmpty(object who){ ","/lib/events/sell.c":"mixed CanSell(object seller){ mixed direct_sell_obj_to_liv(){ mixed indirect_sell_liv_obj(){ ","/lib/round.c":"void create(){ varargs mixed eventLoad(object who, object where){ varargs mixed eventUnload(object where){ string GetAmmoType(){ return ammotype; } string GetFirearmType(){ return firearmtype; } int GetMillimeter(){ return millimeter; } int GetCaliber(){ return caliber; } int SetMillimeter(int x){ millimeter=x; return 1; } int SetCaliber(int x){ caliber=x; return 1; } int SetFirearmType(string str){firearmtype=str; return 1; } int SetAmmoType(string str){ammotype=str; return 1; } int SetRifleType(string str){rifletype=str; return 1; } string GetRifleType(){ return rifletype; } ","/lib/std/dummy.c":"varargs static void create(string array id, mixed long, string array adj){ ","/lib/events/give.c":"mixed direct_give_obj_to_liv(object what, object target){ mixed indirect_give_liv_obj(object target){ mixed direct_give_obj_liv(object what, object target){ ","/lib/guard.c":"void heart_beat(){ void init(){ int AllowPass(object who, object what){ int AllowGet(object who, object what){ varargs mixed SetGuard(mixed what, mixed action, int howlong){ void CheckPending(){ void CheckGuardeds(){ ","/lib/donate.c":"static void create(){ string GetLong(string str){ static void init(){ string GetLocalCurrency(){return LocalCurrency;} int GetAssets(){return TotalAssets;} int AddAssets(int amount){ string SetLocalCurrency(string currency){ string GetOwner(){return Owner;} string SetOwner(string owner){return (Owner = owner);} int eventDonate(string amt, string type){ ","/lib/events/aim.c":"int MustCarry(int i){ int MustWield(int i){ varargs mixed direct_aim_obj_at_liv(mixed args...){ varargs mixed direct_aim_obj_at_obj(mixed args...){ varargs mixed direct_aim_obj_wrd(mixed args...){ varargs mixed indirect_aim_obj_with_obj(mixed args...){ varargs mixed indirect_aim_liv_with_obj(mixed args...){ varargs mixed direct_aim_obj_wrd_at_wrd(mixed args...){ varargs mixed eventAim(object who, mixed target, string dir, string whom){ mixed CanAim(object aimer, mixed target){ varargs mixed indirect_aim_obj_at_liv(mixed args...){ varargs mixed indirect_aim_obj_at_obj(mixed args...){ ","/lib/interactive.c":"string GetShort(){ int GetRadiantLight(int ambient){ nomask int eventReceiveObject(object ob){ static void create(){ int eventDestruct(){ string SetShort(string str){ string GetName(){ return object::GetName(); } string GetKeyName(){ return object::GetKeyName(); } string array GetId(){ return UserId; } string SetKeyName(string str){ string SetCapName(string str){ varargs string array SetId(string array bogus){ varargs string GetLong(){ string SetLong(string str){ varargs int GetInvis(object ob){ return object::GetInvis(ob); } int Setup(){ static void heart_beat(){ string query_cwd(){ return interface::query_cwd(); } int eventMove(mixed dest){ static void net_dead(){ void eventReconnect(){ static string process_input(string str){ string get_path(){ mixed array GetCommands(){ int cmdQuit(){ void SetLastError(mapping m){ mapping GetLastError(){ mixed CanGet(){ int GetBriefMode(){ return Brief; } mixed CanDivorce(){ mixed CanMarry(){ mixed eventDivorce(){ mixed eventMarry(object who, object to_whom){ void cmdParseRefresh(){ int GetAge(){ int GetBirth(){ return BirthTime - (YEAR array 18); } void SetEmail(string str){ string GetEmail(){ int GetLoginTime(){ return LoginTime; } void SetNews(string type, int sz){ News[type] = sz; } int GetNews(string type){ return News[type]; } void SetPassword(string str){ string GetPassword(){ void SetRank(string str){ Rank = str; } string GetRank(){ return Rank; } void SetRealName(string str){ string GetRealName(){ return RealName; } int SetBriefMode(int x){ return (Brief = x); } int SetWhereBlock(){ return (WhereBlock = !WhereBlock); } int GetWhereBlock(){ return WhereBlock; } string GetSpouse(){ mixed GetParanoia(string str){ void move_or_destruct(){ int SetRescueBit(int i){ string GetHostSite(){ string GetWebPage(){ string SetWebPage(string page){ varargs nomask static void validate_paranoia(int prev){ mixed SetParanoia(string str, mixed val){ static nomask void NotifyReceipt(object ob){ ","/lib/events/drink.c":"varargs mixed CanDrink(object who, string substance){ varargs mixed eventDrink(object who, string substance){ mixed direct_drink_str_from_obj(string str){ mixed direct_drink_obj(){ mixed direct_drink_from_obj(){ ","/lib/virtual/virt_land.c":"varargs static void create(int x, int y,int z){ void SetCoordinates(int x, int y, int z){ varargs mixed GetCoordinates(int level){ void ResetLocation(){ string GetAreaType(){ return AreaType;} object GetMasterMap(){ return Map_Master;} varargs string array GetNonExits(string array extra){ mapping GetSurroundAreas(){ return Surrounding_Areas; } void PreAddEnter(mixed dir, string file){ void SetVirtualExits(int x, int y, int z){ varargs void SetLongAndItems(int x, int y, int z){ int SetMasterMap(mixed map_name){ int SetVirtFile( string file ){ string SetResetMessage(mixed str){ Reset_Message = str;} mapping GetDirectionMap(){ string GetReverseDirection(string dir){ varargs mixed GetMapType(int x, int y, int z){ mapping SetSurroundAreas(int x, int y, int z){ void ResetSurroundExits(){ ","/lib/talk.c":"varargs mixed eventHearTalk(object who, object target, int cls, string verb, varargs mixed CanSpeak(object target, string verb, string msg, string lang){ int direct_ask_liv_about_str(){ return 1; } int direct_request_str_from_liv(){ return 1; } int direct_say_to_liv(){ return 1; } int direct_say_to_liv_str(){ return 1; } int direct_whisper_to_liv(){ return 1; } int direct_whisper_in_wrd_to_liv(){ return 1; } int direct_whisper_to_liv_str(){ return 1; } int direct_whisper_in_wrd_to_liv_str(){ return 1; } int direct_whisper_to_liv_in_wrd_str(){ return 1; } string SetSpeakColor(string str){ string GetSpeakColor(){ return SpeakColor; } string array GetTellHistory(){ int eventTalkHist(string str, string type){ string array GetTalkHistory(string type){ string array GetTalkHistTypes(){ int eventTellHist(string str){ int direct_ask_liv_str(){ return 1; } mixed eventTalkRespond(object who, object targ, int cls, string msg, string lang){ int direct_ask_liv_to_str(){ return 1; } int direct_ask_liv_for_str(){ return 1; } varargs mixed eventSpeak(object target, int cls, string msg, string lang){ ","/lib/shell.c":"void create(){ string GetAmmoType(){ return ammotype; } string GetFirearmType(){ return firearmtype; } int GetMillimeter(){ return millimeter; } int GetCaliber(){ return caliber; } int SetMillimeter(int x){ millimeter=x; return 1; } int SetCaliber(int x){ caliber=x; return 1; } int SetFirearmType(string str){firearmtype=str; return 1; } int SetAmmoType(string str){ammotype=str; return 1; } ","/lib/potion.c":"void create(){ mixed eventDrink(object who){ mixed eventEat(object who){ mapping SetSkills(mapping arg){ mapping SetStats(mapping arg){ mapping GetStats(){ mapping GetSkills(){ mapping SetPoints(mapping arg){ int SetDuration(int i){ int GetDuration(){ mapping GetPoints(){ ","/lib/mayor.c":"static void create(){ int GetTax(){ mixed eventRequestCitizenship(object who){ static string SetLocalCurrency(string str){ string GetLocalCurrency(){ static int SetTax(int x){ mixed CanRequestCitizenship(object who){ static void EvaluateCitizenshipRequest(){ ","/lib/events/wear.c":"mixed direct_wear_obj(){ mixed direct_remove_obj(){ mixed direct_wear_obj_on_str(object target, string str){ ",]) +Functions ({"eventTellHist","GetDummyItems","eventEquip","SetTrapType","GetTax","_message","direct_missile_liv","SetScreen","eventOpen","read_callback","channel_out","SetDisabled","GetPoisonUses","CanTrain","SetCommercial","_file_head","SetListen","GetCedmode","indirect_light_obs_with_obj","SetTrapDescription","LoadAuto","regetID","GetClimate","direct_put_obj_obj","GetSaveFile","SetCure","GetBaseSkillLevel","ClassMember","got_packet","SetMillimeter","GetPoison","move_or_destruct","SetVisibleGrid","direct_detect_wrd_in_obj","GetActionsEnabled","GetGoMessage","GetStatBonus","CanUnTrain","SetRead","end_edit","GetMaxLoaded","direct_turn_obj_on_obj_on","GetEnter","direct_stealth_wrd","SetDeviating","can_use","SetBaseCost","SetClient","SetTerrainType","GetPersistentInventory","direct_resurrect_liv","RemoveFollower","SetMass","direct_scratch_str_on_obj","CanPutOnto","send_packet","direct_abandon_liv","eventTallyVotes","direct_fish_with_obj","indirect_roll_obs_on_obj","AddTrainingPoints","GetBlind","SetValue","restore_player","direct_crawl_str","direct_aim_obj_at_liv","id","eventPreview","direct_put_wrd_wrd_word_obj","eventEncounterBlock","SetAction","CanWear","SetCharbuffer","GetAnnoyblock","SetFirearmType","GetWimpy","CanRepair","GetSource","AddEncounter","SetBaseLimbs","GetPenalty","_replace","CanSpeak","direct_train_liv_to_str","indirect_shoot_obj_at_obj","direct_buffer_liv","direct_pray_for_str_for_obj","GetSurroundAreas","eventEmpty","direct_add_obj_to_obj","direct_ride_str","eventLand","SetZPG","eventLoadItem","GetMaxFishing","SetInfect","_help","SetBonusName","GetDeathEvents","GetMagicResistance","SetAutoStand","direct_ask_liv_str","RemoveConsult","SetBonusDuration","SetHiddenDoor","eventDecay","do_verb_rule","CanMelee","GetReligion","GetBaseStatLevel","GetCaliber","SetDayLong","SetCanSwim","GetRifleType","direct_reload_word_obj","AddQuestCurrency","SetFuelName","isCorpse","GetMaxStaminaPoints","direct_enter_into_obj","GetCoords","GetRecurseDepth","query_max_mp","GetLanguages","eventOfferTeaching","SetEmptyShort","GetAmmo","parse_command_id_list","SetLocalFee","RazzleDazzle","GetHealthPoints","GetType","direct_dig_obj_with_obj","GetDestructOnDrop","SetRecurseDepth","direct_body_liv","GetStaminaCost","GetMissData","GetExitData","doRevolverUnload","AddSpecialMenuItem","eventMoveFollowers","GetResistance","GetTitles","SetHealthPoints","validate","indirect_delete_exit_str","AddSacrificeType","SetMaxLiers","eventReceiveDamage","eventDecreaseFuel","SetMagnum","direct_unload_obj","GetDayLight","direct_remove_obj","GetBirth","CanLead","Payment","eventReleaseStand","GetTempbuffer","_down","GetCarriedMass","AddCurrency","GetCurrencyMass","openDoor","direct_rock_str","show","direct_unlock_obj_with_str","eventFly","eventBuryWith","AddExperienceDebt","direct_copy_obj_str","GetCharge","GetMode","eventWithdraw","CanEquip","cmd_followup_and_respond","SetMuffed","CanSpellAttack","eventCheckEnvironment","_insert_line","indirect_marry_liv_to_liv","AddRule","CanTurnOff","SetLockable","SetRules","indirect_delete_obj","ClearBuffers","CanWeapon","NewBody","RemoveRule","GetExitMap","SetVisibleRiders","direct_smoke_obj","GetInvis","CalculateAmmoSize","SetCapName","ParseHook","AddSearchPath","GetOrigin","eventWander","SetBodyComposition","getonline","_goto_line_done","direct_resurrect_obj","eventMultiply","direct_pour_out_obj","GetParalyzed","query_board_time","GetPromptString","eventRegisterSide","direct_rockwhip_liv","SetFingers","GetExtraChannels","SetGoMessage","SetSize","GetAllowSacrifice","eventDrive","imc2_to_pinkfish","SetBefriended","eventLearn","GetAreaType","disconnect","direct_aim_obj_at_obj","RemoveBonuses","eventJump","GetClass","SetPK","Destruct","eventPrepareCast","SetSaveFile","query_max_hp","GetAmmoType","SetSpeakColor","string_to_mapping","indirect_bury_obj_with_obj","rEsc","wild_card","chanwho_reply_in","UpdateScreen","GetRoomAffectLong","SetBane","SetMaxRecurseDepth","SetRestrictLimbs","SetNoDefaultExits","CanShowInterior","eventPutOnto","GetMealMessages","eventPreAttack","GetFollowerMap","GetInventory","SetMaxHealthPoints","GetLocations","SetMealMessages","SetRescueBit","GetProtectionMap","SetExits","direct_command_liv_to_str","_right","rBackspace","html","eventForceQueuedCommand","eventExtraAction","SetNonLocalFee","eventStop","GetHostSite","ParsePost","GetTale","compile_object","GetMagicCost","can_verb_rule","indirect_read_obj_at_obj","GetTalkHistTypes","cmdSmell","SetMaxMagicPoints","eventBuck","launch","SetRifleType","doRoll","eventShow","cmd_pwd","eventMeleeAttack","chancmd","SetCedmode","GetHealthShort","GetHands","SetClimate","SetSky","SetSkill","eventCommand","direct_look_on_obj","QueryMap","GetArmorType","RemoveLocation","indirect_balance_obj_to_obj","SetCommandResponses","write_to_log","SetReligion","RemoveBlindness","GetExchangeFee","GetPreventSteal","direct_shoot_obj_with_obj","SetRetain","SetPreventDrop","GetLanguagePoints","eventKneel","SetWanderSpeed","direct_untrain_liv","SetPreventSteal","eventJoin","GetPrompt","pushd","GetRoom","AddStat","GetEmotes","eventResults","direct_move_obj","send_keepalive_request","eventDisplayStatus","whois_in","GetOwner","direct_free_liv_from_obj","eventFlushQueuedMessages","direct_dispel_liv","indirect_sell_liv_obj","GetPerforated","RemoveStat","GetWeaponType","eventDarken","GetCustomDeviations","CanBuryWith","GetDoorStopped","GetPermitLoad","SetBait","GetKnocks","beep_out","GetDying","eventShake","SetDayLight","AddBonusDuration","eventEscape","GetFrequency","GetMinHeat","_search_done","GetFollowed","direct_look_at_str_on_obj","CanPull","direct_apply_obj_word_obj","SetDead","appraise","_undef_key_done","SetId","eventQuell","eventSell","GetPowerType","AddFingers","eventTurnOff","SetTeachingFee","set_cwd","remove_dots","AddHostile","direct_shock_liv","GetLifeSpan","SetCaliber","direct_lead_liv","parse_command_adjectiv_id_list","SetParalyzed","StrCoord","SetDig","GetAdjectives","SetDie","indirect_turn_obj_on_obj_on","direct_immolate_liv","CanEat","direct_bait_obj_with_obj","SetShort","CanLearn","SetWanderRecurse","GetListens","eventDrink","GetMorality","RemoveScratch","direct_whisper_to_liv_in_wrd_str","GetZPG","GetScreen","eventLay","eventSwim","do_shoot","GetCurrencies","SetVehicleInterior","direct_scratch_on_obj","setOrigin","resolve_callback","eventRunOut","GetVirtualSky","GetAccountInfo","GetBlocked","_up","direct_initfix","GetParty","GetRequestResponses","direct_heal_str_of_liv","SetFuelAmount","GetDefiniteShort","SetTouch","GetListen","SetHB","GetHelp","GetMaxLoad","cmdSearch","GetOpacity","RemoveNonTargets","SetClan","eventMoveLiving","BaseMap","eventRoll","SetInventory","GetClimateExposed","GetHostiles","GetExperiencePoints","_input","direct_put_obj_word_obj","SetAmmoType","GetClient","GetFlyRoom","GetAutoHeal","direct_delete_exit_str","GetEquippedLimbs","direct_swivel_str","eventHelp","SetPreventPut","direct_use_obj","direct_party_wrd_liv","user_name","SetWear","AddTitle","SetMagicCost","GetNativeLanguage","direct_look_in_obj","SetVendorType","direct_read_str_word_obj","direct_shoot_liv_with_obj","SetLeader","RemoveEncounter","GetMaxCells","GetAction","GetChanInfo","GetDrainRate","eventCustomizeStat","GetLastSave","RemoveFishing","cmd_pushd","direct_get_wrd_wrd_from_obj","GetTrainedSkilles","SetHistorySize","direct_farsight_liv","ReadBookIndex","eventDetect","indirect_reload_str_obj","AddSkillBonus","SetArmorType","SetMuted","GetInfect","direct_ask_liv_about_str","CanUnequip","eventEndVoting","_keymap_done","direct_judge_obj_to_obj","CanKneel","GetClanSkill","direct_bless_obj","RemovePress","direct_sit_down_word_obj","GetProtect","indirect_unlock_obj_with_str","indirect_show_liv_obj","SetNoBotCondition","direct_weigh_obj","GetStudents","teller_check","CanTarget","indirect_lock_obj_with_str","GetStats","eventDeploy","GetCellType","SetWander","direct_look_at_obj_word_obj","missed_shot","direct_steal_obj_from_liv","GetEffectiveVision","CanShake","GetCanonicalId","direct_climb_out","GetFlowLimit","catch_tell","direct_calm_liv","GetDebugging","eventTeachLanguage","SetSurroundAreas","eventMount","SetFrequency","RemoveSpecialMenuItem","clean_up","flicker","isBag","GetMagnum","end_post","GetGrid","SetMag","CanPutInto","ShowRounds","GetSitters","GetHistoryList","SetBroken","GetStat","SetPowerType","SetMountOwner","CanBurn","GetVirtualSea","GetAutoResets","GetTalkResponses","eventHearTalk","GetCombatBonus","SetMaxStaminaPoints","GetSlowDecay","GetBaseRadiance","indirect_pulsecheck_liv","SetClosed","RegisterLocation","eventFlood","GetCanLock","CanDrink","eventManipulate","direct_shoot_obj_wrd_at_wrd","AddTerrainType","SetFollowed","direct_cast_str_on_obj","GetMuffed","SetEnter","SetAC","GetMapType","direct_poison_obj_with_obj","GetEmoteResponses","SetAutoDamage","eventRemoveItem","direct_search_obj","RemoveExtraChannels","GetClanObject","eventForce","_del_char","NotifyReceipt","GetMaxClass","direct_read_obj_at_obj","GetProperties","SetRank","InitComposition","SetLifeSpan","PutCoins","GetCurrentEnemy","GetPolyglot","GetItemsMap","direct_aim_obj_wrd","GetSpellBook","GetLightSensitivity","CanPick","GetShadowedName","AddQuestSkillPoints","_write","eventNegotiateObstacles","AddRequestResponse","rEnter","PutCheck","SetWimpy","GetBodyMass","SetCurrentEnemy","SetMorality","GetSky","direct_befriend_liv","GetGravity","remove","eventUnlock","GetRequiredMagic","eventRetire","direct_look_at_obj","GetTitleLength","CanOpen","SetItem_func","AddPressure","ping_reply_in","GetSinkRoom","GetEnemies","eventFall","direct_pull_obj","DisableActions","GetLanguageName","direct_get_obj_out_of_obj","indirect_buy_str_from_liv","direct_annihilate_at_liv","direct_veil_liv_against_wrd_wrd","eventRide","AllowGet","GetPlayerKill","level","SetMinHeat","eventRock","cmdShow","direct_drive","ResetLocation","direct_arrow_liv","GetMaxStatPoints","IsFollowing","SetDrainRate","_append","GetWhereBlock","list","start_logon","GetMasterMap","GetSkillLevel","SetAutoHeal","GetSpecialTarget","GetCouncilMember","GetDoor","GetFollowers","ResetSurroundExits","AddProperty","eventUnload","CanAbandon","direct_pull_str_from_obj","RemoveKnock","eventSpecialList","GetHeat","indirect_shoot_obj_with_obj","direct_attack_liv_only","GetUniqueId","SetExtraChannels","isPlayer","SetMaxCells","SetVirtualExits","GetCarriedWeight","CreateDoor","GetFurnitureName","eventLoadInventory","direct_blades_liv","tell_in","direct_sacrifice_obj_to_str","SetClanSkill","cmd_alias","AddLimb","GetAnchored","eventDeteriorate","SetBlocked","SetLightLevel","eventDrop","GetWorn","SetFirearmName","direct_empty_obj","RemoveLimb","cmdAppraise","eventUnequip","GetRequiredStamina","GetMaxSkillLevel","eventBring","GetLive","SetMaxLoad","SetOpacity","GetDig","GetDie","RemoveTalkResponse","SetNews","SetChance","eventUninstall","direct_sit_word_obj","ChangeLevel","RemoveChannel","SetItem_desc","GetCreatorAge","GetGaggedType","eventCast","GetEmptyName","SetFlowLimit","indirect_apply_obj_word_obj","SetSide","SetDebugging","AddSmell","GetActionsMap","GetRetain","eventTrainSkill","SetInvis","SetFlyRoom","ReadBook","CanPoison","GetPress","rAscii","_refresh_screen","GetPacifist","SetCellType","GetSpellType","FoundTraps","GetCommandHist","_refresh_cursor","SetSlowDecay","GetPreventLand","direct_knock_str_on_obj","GetHealRate","GetNoTaleMessage","indirect_aim_obj_with_obj","direct_scry_liv","eventHistory","GetModify","window_size","direct_can_give_liv_obj","GetElevator","CanFollow","eventDismount","eventPutInto","AddSave","CanPut","GetCurrencyMap","GetName","direct_demonclaw_liv","SetPull","GetAge","CanGetFrom","GetNonExits","direct_verb_rule","eventRadiate","save_player","SetClass","cmd_nmsh","GetLimbs","GetQuestId","indirect_pick_str_on_obj_with_obj","Page","eventUnQuell","getstatus","SetAttack","direct_wield_obj_word_str","SetSpellBook","GetMaxClones","whois","SetCruiseInMessage","eventMarry","direct_consult_obj","direct_modify_obj_str","eventSwivel","direct_regen_str_on_liv","CanApply","eventList","SetPile","cmd_remove","CanReceiveMagic","InitializeLocations","SetProtect","direct_steal_wrd_from_liv","direct_give_liv_wrd_wrd","GetMagicProtection","RemoveTitle","GetWorldMap","SpringTrap","check_include_text","SetDefaultExits","eventReceiveLay","SetRarity","SetHBOverride","GetSpellChance","SetPolyglot","GetPileType","getOrigin","localize_channel","indirect_resurrect_obj","eventBuy","GetDuration","eventBuyItem","direct_wizunlock_obj","direct_ride_word_str","direct_read_obj","GetMaxFuel","eventDestroyEnemy","indirect_shoot_liv_with_obj","direct_ward_liv_against_wrd","SetBodyMass","AddStatBonus","direct_open_obj_with_obj","SetCorpse","eventTurnOn","GetStaminaPoints","AddQuestStatPoints","GetTown","GetEmptyLong","direct_enter_obj","SetHands","direct_burn_obj_with_obj","GetProtection","direct_reload_str_obj","inventory_accessible","LimbCertain","SetMasterMap","SetSinkRoom","GetNightLong","direct_shoot_obj_wrd","SetPreventGet","whois_reply_in","eventSendMissMessages","direct_show_liv_obj","direct_smoke_from_obj","GetCouncil","SetRace","CanJump","direct_look_obj","HealLimb","SetCanLock","GetDoorSide","SetArmed","SetRequestResponses","GetFuelRequired","GetMag","direct_extinguish_obj","GetLong","eventAbandon","GetLeader","cmd_work","direct_whisper_in_wrd_to_liv_str","RemoveMenuItem","GetMaxProtection","SetFuelRequired","SetOwner","GetDirectionRoom","eventReadFile","list_new_posts","direct_delete_obj_from_here","GetTaleKeys","SetMountStyle","eventFloat","indirect_steal_obj_from_liv","GetMenuItems","direct_activate_obj_on_obj","GetPoisonGas","GetCount","GenerateNames","CanStop","direct_close_obj","indirect_sell_obs_to_liv","AddConsultResponse","indirect_aim_liv_with_obj","AddFollowBonus","SetDying","SetGravity","GetKnock","EnableActions","SetAnchored","indirect_free_liv_from_obj","GetNoChanColors","SetEmptyName","eventBalance","AddVisionBonus","direct_unwield_obj","send_text","GetRoomZero","GetLimb","direct_untrain_liv_to_str","direct_pour_obj_out","SetNoChanColors","SetKeys","eventLockLock","direct_deactivate_str_on_obj","MinusAmmo","eventCompleteMove","GetSpecialMenuItems","direct_animate_obj","direct_pulsecheck_liv","SetSpellType","indirect_roll_obj_on_obj","_esc","mudinfo","GetCombatMove","direct_delete_obj_from_room","CanGive","GetCommercial","GetXverb","direct_strike_obj","AddExtraChannels","forget_user","GetConsult","SubtractRound","collect_moduli","direct_scratch_on_str_on_obj","direct_cloak_wrd","indirect_poison_obj_with_obj","GetReadsMap","eventCatch","GetSides","SetBury","direct_attack_only_liv","direct_force_liv_to_str","SetPacifist","direct_ask_liv_for_str","GetMillimeter","eventTalkRespond","SetParty","indirect_bait_obj_with_obj","SetQuestPoints","CanJoin","direct_aim_obj_wrd_at_wrd","GetDummyItem","GetCoordinateMap","GetFalling","SetMaxSitters","eventGetFrom","CanMarry","GetBroken","eventTurn","SetDifficulty","SetMaxClones","SetElevator","GetListenMap","SetDamageType","chan_who_in","SetResetMessage","GetDefaultLanguage","direct_pick_str_on_obj_with_obj","SetLivingLong","MustCarry","GetClosed","GetDeaths","GetSave","indirect_look_at_obj_word_obj","direct_climb_obj","cmdListen","SetCommandFail","SetCoordinates","GetExemptVirtual","GetCharbuffer","ResetBank","indirect_get_obj_out_of_obj","RemoveLanguage","SetPick","eventPickLock","net_dead","SetCanSit","CanSell","SetMoney","GetClasses","SetVerb","SetNoObviousExits","eventSave","get_closed","direct_backlash_for_liv_against_wrd","GetMoneyMap","GetEquippedDescription","SetEmptyLong","RemoveRequestResponse","SetOpen","direct_fireball_at_liv","direct_look_inside_obj","GetConsultResponses","direct_deactivate_obj","LoadRevolver","indirect_show_obj_to_liv","cmdDebugAll","GetQuests","EchoCommand","SetNightLong","SetTalkResponses","GetCommandResponse","GetHiddenDoor","CanSit","SetDuration","GetPrimarySkills","CanSwim","eventTouch","GetTitle","_file_end","AddQuest","eventCompareLimbs","eventCruiseMessages","indirect_put_obs_obj","GetReads","_end","SetFloors","GetSpell","SetManipulate","GetEmptyShort","direct_whisper_in_wrd_to_liv","eventDestroyUndead","SetQuestId","indirect_get_obj_from_obj","SetGround","SetLightSensitivity","AddFish","SetLivingShort","_quit","CheckGuardeds","SetCanStand","RemoveFish","GetVisibleGrid","GetEnterMessage","CanRoll","GetTraps","GetEquipped","ReceiveCanonicalId","direct_roll_obj_here","SetStats","direct_wear_obj","CanDig","SetMenuItems","RemoveSmell","CanAim","direct_gale_liv","DroneCache","SetPoisonGas","GetTellHistory","GetWebPage","abort_edit","direct_activate_obj","GetTerrainType","SetEnterMessage","eventShoot","SetSkills","direct_uninstall_obj","SetDoorSide","SetRequiredMagic","GetTeloptIp","SetDamage","GetMissingLimbs","GetMaxMagicPoints","GetDrainable","AddStuff","GetAlcohol","direct_bury_str_with_obj","AddNonTargets","SetMissingLimbs","GetFirearmType","SetMaxFuel","mudwho","GetLuck","indirect_put_obj_obj","indirect_show_obj_liv","GetChance","GetAmbientLight","GetRespirationType","GetClanName","eventNextDay","eventChangeIMC2Passwords","SetSpecialTarget","indirect_give_liv_obj","SetAmbientLight","SendWeaponMessages","GetCharmode","eventOpenAccount","AddFood","direct_ignore_liv","GetPlayerPaused","direct_challenge_liv","eventShowInterior","eventReceiveThrow","eventPrint","GetTargets","GetBefriended","direct_swim_into_str","AddCaffeine","CanGet","SetPlayerPaused","eventPostRelease","UnSetAutoDisabled","indirect_give_obs_to_liv","eventLock","SetDefaultRead","AddKey","Expertise","eventDeposit","GetRetainOnDeath","_next_match","GetSpeakColor","begin_post","replace_nickname","direct_give_wrd_wrd_to_liv","CheckPower","AllowPass","query_post","GetDirection","channel_in","eventWelcome","SetAmmo","GetPresses","direct_arrow_at_liv","ping_out","SetType","SetMagicPoints","RemoveTerrainType","eventRepair","direct_knock_on_str_on_obj","SetMealAction","GetChamberInterior","SetWanderPath","indirect_reload_every_str","eventRestoreSight","reset_prompt","cmdBrowse","direct_get_obj_obj","direct_climb_word_obj","eventEnter","eventDescribeEnvironment","SetMaxCapture","_search","GetLocalCurrency","direct_holylight_liv","eventLoad","HandleTeller","SetNoCondition","GetResistanceMap","eventBlind","SetDollarCost","eventRevive","SetNightLight","RedrawScreen","GetSpeed","zero","SetNoTaleMessage","GetEnterMap","query_cwd","direct_shoot_obj_at_liv","SetLit","query_number_posts","SetPoints","SetConsult","GetRarity","GetSkillModifier","SetEnters","RemoveStatBonus","eventWimpy","eventRefuel","cmd_nickname","CheckEncounter","AddDrink","direct_turn_obj_on","GetCanClose","direct_turn_off_obj","eventExecuteQueuedCommands","AddItem_func","direct_roll_obj_on_obj","_del_line","direct_fly_into_str","GetScratch","CanBoobytrap","GetButtonId","direct_portal_to_liv","SetStorageRoom","SetFalling","SetComposition","direct_lock_obj_with_obj","GetFullExitData","direct_swivel_str_on_obj","is_living","CanShoot","RestrictChannel","direct_use_obj_to_str","GetRiders","CanManipulate","direct_createfix","RestoreLimb","eventSteal","direct_remedy_liv","indirect_get_obs_from_obj","save_board","SetBurntValue","CanRemoveItem","GetTrainingSkills","direct_annihilate_liv","GetMealType","direct_listen_to_str_word_obj","SetDrainable","SetTapped","GetCommands","GetVoteStatus","CanRock","eventEat","validate_paranoia","GetFish","SetPress","CanCastMagic","validate_last_room","eventConvertObject","GetRange","SetClasses","GetLimbParent","GetDamagePoints","eventRetryCommand","SetStaminaPoints","direct_aura_liv","direct_cleanse_liv","SetTeloptIp","GetVerbs","GetSmell","SetDamagePoints","GetNonLocalFee","Push","GetLanguage","eventFish","direct_dismount_liv","eventReconnect","_tab","RemoveConsultResponse","GetScratches","valid_edit","AddShadow","direct_blades_at_liv","GetEnabled","AddRead","eventAddCandidate","CanDrop","direct_fly_word_str","direct_cast_str_on_str_of_obj","CanRelease","SortEnemies","eventRestore","GetMobility","GetAllLanguages","SetTale","GetNoBotCondition","AddMass","CanInstall","GetMelee","RemoveRead","GetSpouse","GetItems","direct_convert_liv","direct_show_obj_to_liv","eventFire","indirect_delete_obj_from_here","GetMissingLimb","SetAllLanguages","SetClanName","MarriageRequest","SetPickingQuality","eventDisarm","UnSetRoom","GetTrainingModifier","SetBonuses","SetLocked","GetFuelAmount","SetCharmode","CanCast","SetRespiration","GetRequiredSkill","RemoveShadow","GetBaitStrength","GetAreaMap","connect","direct_turn_off_obj_on_obj","eventTeachPlayer","direct_crawl_into_str","SetWebPage","GetSearches","GetPreventDrop","GetFood","SetBaitStrength","AddTeachingLanguages","GetWanderSpeed","direct_mend_liv","heart_beat","checkCollapse","SetSpecialMenuItems","SetAttackable","direct_look_at_obj_on_obj","GetItemCondition","GetCombatAction","SetCruiseOutMessage","direct_shoot_obj_at_obj","indirect_delete_obj_from_room","GetPreventPut","cmd_unalias","RemoveQuest","indirect_dig_obj_with_obj","GetNoDecay","SetRoom","GetVendorType","SetCombatAction","GetCombatVerbs","direct_smell_str_word_obj","cmdDial","eventShadow","GetSmellMap","GetFollowBonus","indirect_burn_obj_with_obj","GetCustomXP","GetVisionBonus","PreAddEnter","GetTrainingPoints","returnChannels","cmdTouch","eventUnlockLock","CanPeer","CanCapture","rDel","GetTeachingFee","send_is_alive","GetResetNumber","GetLoginTime","GetCanClimbCarried","GetMaxFlask","direct_throw_obj_word_obj","CanRequestCitizenship","direct_consult_str_on_obj","GetMinCells","GetStatLevel","GetPlayerob","SetCount","direct_rock_obj","CanSteal","SetKnock","direct_unlock_obj_with_obj","SetCanClose","terminal_type","GetCurrency","eventMagicRound","direct_show_obj_liv","GetNextLevel","SetExemptVirtual","GetFloors","eventEncounter","direct_drink_str_from_obj","GetSleeping","direct_give_liv_obs","indirect_toss_obj_at_obj","PickTale","SetButtonId","eventRequestDivorce","direct_give_liv_obj","GetGermName","GetGround","direct_disarm_obj","direct_copy_obj_to_obj","eventFill","ReceiveChars","CanGo","_dispatcher","direct_turn_on_obj","direct_marry_liv_to_liv","SetConsultResponses","SetHelp","who_reply_in","SetVirtFile","doAutoUnload","ResetCurrency","AddTalkResponse","GetChannels","GetPlainShort","AddAssets","SetMealType","restrict","eventDestruct","continue_mail","GetSkills","GetNoSpells","GetMountOwner","allchans","eventCommandNPC","GetDamage","rArrow","StatReport","AddQuestPoints","SetRefuelable","GetMessage","GetCommandNumber","GetReligions","direct_remedy_str_of_liv","GetShakes","GetTellingTale","GetMaxCarry","GetEscapeChance","eventDisconnect","finger","GetCustomStats","SwitchLocations","GetDeities","eventCheckHealing","GetAutoDamage","GetCost","direct_jump_word_word_obj","SetMedium","SetEscapeChance","GetExperienceDebt","SetScratch","SetLanguage","GetSearchPath","GetReverseDirection","AddLanguagePoints","shb","AddBank","GetEncumbrance","beep_in","SetLoaded","eventInstall","GetCure","eventRequest","GetLastEnvironment","direct_rock_wrd_obj","eventComplete","RemoveShake","GetLit","direct_backlash_for_liv","SetPersistent","eventWriteFile","GetRead","SetRequiredStamina","direct_drink_obj","LimbGuess","AddAlcohol","RecalculateHist","indirect_reload","direct_dig_str_with_obj","SetGagged","GetFight","direct_teleport_to_liv","GetMass","DoneTrying","GetChannel","direct_fill_obj_with_obj","indirect_pour_from_obj_into_obj","AddStaminaPoints","direct_palm_liv","GetInCombat","QueryBane","CanConsult","GetClimbs","eventMeleeRound","direct_reload","eventCure","GetObviousExits","direct_whisper_to_liv_str","keepalive","direct_dest_obj","ModCharge","direct_evade_liv","GetFlaskContents","GetConjure","GetSkillClass","eventRead","cmdEnter","SetObviousExits","SetTitle","_confirm_save","escape","ResetCurrentEnemy","price","SetReads","_insert_exclam_mark","SetNoSink","SetSpell","direct_frigidus_liv","eventMoralAct","GetSpellLevel","_left","direct_capture_liv_word_obj","direct_fill_obj_from_obj","GetHeartRate","direct_listen_obj","direct_initfix_obj","CanTurn","GetNoModify","SetFishing","AddSearch","direct_cast_obj","GetErrorMessage","GetCaptives","SetGrid","CanBreathe","eventParse","SetUndeadType","eventSmoke","GetBriefMode","direct_pour_from_obj_into_obj","GetQuest","SetStat","eventPage","IsCouncilMember","indirect_burn_obs_with_obj","eventFree","direct_say_to_liv_str","SetDeathEvents","direct_jump_word_obj","SetErrorMessage","cGetSave","getremotemudinfo","eventCapture","eventRequestCitizenship","SetCanTrain","GetLightLevel","SetCustomXP","direct_corrupt_liv","ChangeClass","AddFollower","SetRetainOnDeath","GetPoints","direct_light_obj","GetEnters","eventEdit","GetChanList","RemoveSearch","set_board_id","SetPoisonUses","SetMaxFlask","SetAreaMap","GetKeepalive","GetDisableChance","rAnsi","GetEverFill","GetGhost","AddBait","GetSynonyms","GetMudName","direct_force_liv_str","eventPut","direct_drain_liv","GetMudList","direct_delete_obj_from_obj","SetUnique","direct_touch_str_word_obj","GetFlaskUses","direct_createfix_obj","SetMinCells","GetCandidates","GetMaxSkillPoints","RemoveProperty","SetStaminaCost","indirect_give_obs_liv","GetPassword","CanUse","RemoveHostile","SetCurrency","direct_compare_obj_to_obj","direct_reload_obj","SetLocalCurrency","GetSkillsMap","SetSleeping","eventBuryItem","direct_install_obj_word_obj","SetNoDecay","direct_gaze","SetGermName","SetPoisonStrength","SetCarriedMass","direct_fly","eventSearch","ContinueTraining","SetReligions","GetTapped","direct_search_str_word_obj","GetManipulates","SetSkillModifier","eventEnemyDied","AddPoisonGas","GetConsults","eventInitiate","SetAnnoyblock","DestructEmptyVirtual","GetMaxItems","indirect_throw_obj_into_obj","SetNoSpells","parse_command_plural_id_list","GetAdverbs","direct_pour_obj_into_obj","indirect_add_obj","direct_acidspray_liv","SetTrainedSkills","SetUndead","GetRealName","CanSacrifice","AddCommandResponses","eventExtinguish","indirect_put_obj_word_obj","isDummy","SetSaveRecurse","GetMagicChance","GetHeartModifier","_write_done","clean_str","indirect_add_obj_to_here","direct_rejuvinate_liv","eventRestoreEquip","indirect_turn_off_obj_on_obj","AddMagicPoints","SetMaxCarry","eventGetMoney","GetBankName","SetDoor","cmd_read","indirect_drink_from_obj","GetRemoteTargets","SetMaxFishing","GetSize","SetCanBefriend","GetUserPath","SetHeat","direct_swim_str","eventAsk","indirect_give_obj_liv","UnrestrictChannel","eventStart","GetTrapDescription","GetPosition","GetFirearmName","MustWield","direct_swivel_obj","direct_learn_str_from_liv","CheckCharmode","main_help","AddSkill","GetHBOverride","eventBefriend","direct_lie_word_obj","GetBodyType","SetWorn","AddMagicProtection","GetBank","GetLocked","SetCanCommand","SetClimb","GetBane","pingmud","indirect_add_obj_to_room","GetRestrictedChannels","SetSpeed","_home","cmdAll","GetShake","SetAmmoFile","eventConsult","indirect_judge_obj_to_obj","direct_bite_liv","direct_wear_obj_on_str","LoadBook","GetEnemyNames","SetResistance","AddPoison","indirect_get_obs_out_of_obj","direct_dig_with_obj","direct_bump_liv","GetPreventGet","indirect_sell_obj_to_liv","direct_wizlock_obj","GetDefenseChance","direct_swivel_wrd_obj","cmd_edit","GetAlias","SetMessage","GetLimbChildren","command","process_input","GetEmail","CanLock","cmdQuit","SetLanguageComprehension","SetTempbuffer","user_names","CanSmoke","GetLastCommand","_process","SetDeities","cmdPrice","indirect_zap_liv","SetBriefMode","SetTrainingModifier","direct_turn_obj_on_obj_off","eventPauseMessages","eventLight","GetDrink","indirect_unlock_obj_with_obj","AddRider","PlusAmmo","CanDivorce","cmdParseRefresh","GetEmoteResponse","direct_touch_obj","mark_read","RemoveDig","SetNoModify","indirect_lock_obj_with_obj","eventCastVote","SetCanFly","SetDefaultLanguage","GetMountStyle","continue_post","eventMail","GetSkillBonus","SetKeepalive","GetNoObviousExits","GetSkyDomain","GetFuelType","SetFlaskUses","AddLead","RecurseLocations","receive_message","displayLong","SetRange","eventStand","CanLoad","GetHealing","GetEncounter","eventLoadObject","SetExchangeFee","CanFly","direct_pull_str_on_obj","who_out","GetTrapLevel","SetSmell","GetStrength","AddStatPoints","GetVoid","eventPoison","GetRechargeable","SetEverFill","eventCompleteHeal","SetSynonyms","direct_load_obj","SetConjure","CeditCollate","AddTouch","GetBait","SetRechargeable","GetStatus","direct_follow_liv","GetDestroyOnSell","eventBreak","write_callback","CanScratch","tell","AddEnemy","SetDenominator","SetPassword","eventFollow","SetMelee","CheckActions","SetDoorStopped","SetItems","GetDead","GetLevel","AddBodyMass","SetDestructOnDrop","CanDigWith","GetShadowObject","SetTown","GetOpenFee","AddLocation","WoundLong","GetMaxSitters","eventStartVoting","eventBait","eventPress","GetDifficulty","direct_offer_obj","GetDamageType","GetWield","GetSaveName","GetMoralityDescription","SetShadowObject","CanAttack","GetCanBite","GetLivingLong","direct_turn_liv","GetSpecials","cmd_cd","GetPileAmount","direct_install_obj","GetLimbClass","GetLastPuff","chan_perm_desc","AddRound","Setup","SetMaxItems","eventSit","GetMessages","request_vis","SetRealName","CalculateCarriedMass","GetLockStrength","direct_mount_liv","GetBodyComposition","indirect_put_obs_word_obj","GetMedium","GetPressure","doMagUnload","performDivorce","eventTalkHist","GetShade","SetLong","eventTeach","eventTrainLiving","continue_followup","direct_deactivate_obj_on_obj","SetBankName","CanBefriend","GetMaxAmmo","SetLockStrength","eventSpreadPoison","GetLoaded","SetUserPath","direct_buy_str_from_liv","GetClan","eventCruise","ResetLevel","query_board_id","direct_knock_obj","GetDoors","SetPosition","GetDeterioration","create","GetOwnerOb","remove_post","GetMount","AddItem","eventBless","direct_train_liv","GetParanoia","eventDig","direct_connect_str","eventDie","GetGagged","eventAim","GetMutedType","GetGodMode","RemoveItem","direct_request_str_from_liv","SetBodyType","direct_eat_obj","GetWear","start_edit","SetRespirationType","direct_load_obj_word_obj","GetProperty","GetMaxRecurseDepth","SetLimb","eventContinue","cmdPage","SetAllowSacrifice","GetMaxHealthPoints","SetPerforated","GetManipulate","GetSacrificeType","AddCommandResponse","eventCheckProtection","GetNeighborCoords","CanLight","SetWeaponType","eventBoobytrap","SetPermitLoad","eventCharge","GetMissingLimbParent","GetBurnRate","GetNeighbors","init","cmdParse","_keymap","erase_prompt","GetWimpyCommand","GetNoSink","eventWear","eventWeaponAttack","SetGuard","GetQuestPoints","close_callback","eventUnshadow","indirect_delete_obj_from_obj","SetSkyDomain","AddChannel","direct_light_obj_with_obj","SetWimpyCommand","GetLogHarass","direct_command_str_to_str","cmd_eventDestruct","SetSearch","eventDivorce","direct_press_obj","GetNoReplace","CanStand","unescape","restore_board","direct_scratch_obj","indirect_compare_obj_to_obj","CancelCharmode","SetEncounter","AddEnter","direct_add_obj_to_here","direct_listen_to_obj","restore_inventory","eventTrainSpell","RemoveTeachingLanguages","GetCommandFail","Spent","SetAdjectives","GetWielded","SetTrapLevel","GetCommunicable","GetCoordinates","SetChamberInterior","GetCombatChance","eventSink","indirect_give_obj_to_liv","eventGet","eventReleaseObject","SetFlaskContents","SetAggressive","indirect_reload_str_word","GetPK","indirect_boobytrap_obj_with_obj","indirect_throw_obj_at_obj","SetCommunicable","SetCurrencies","GetVoteRoom","CompileNeighbors","SetFuelType","indirect_reload_obj","eventUnTrainLiving","indirect_uninstall_obj_word_obj","indirect_capture_liv_word_obj","displayShort","GetShadowed","eventDeviateStat","GetUnique","GetLead","direct_aim_obj_with_obj","GetMissingLimbParents","direct_modify_word_str","RemovePull","SetGender","eventKnock","direct_backstab_liv","SetStrength","direct_give_obj_liv","direct_turn_obj","eventLoadChapters","eventScratch","direct_add_obj_to_room","GetTorso","CanUnlock","SetNoEcho","CanPress","AddRecurseDepth","GetValue","direct_drink_from_obj","RemoveSearchPath","isGerm","CanFillOther","CeditSave","AddHealthPoints","GetTalkResponse","GetWizVision","direct_sell_obj_to_liv","RemoveSkill","dGetSave","eventDigWith","mudlist","PassengerPrint","direct_boobytrap_obj_with_obj","SetFight","SendMeleeMessages","popd","GetShadowedObject","GetEquippedShort","direct_uninstall_obj_word_obj","InitRevolver","_insert","direct_say_to_liv","SetDisableChance","GetLivingShort","GetRank","eventPour","CanTeach","GetCurrentCommand","EvaluateCitizenshipRequest","CanDest","direct_drain_at_liv","GetUndead","GetWanderPath","GetFurniture","SetHealing","indirect_fill_obj_with_obj","eventRemoveBlessing","direct_move_str_on_obj","GetLastError","CanUnload","SetCanKneel","eventExecuteAttack","GenerateObviousExits","indirect_install_obj_word_obj","GetVehicleInterior","SetMessages","GetLiers","GetMaxCapture","eventAnnounceCanonicalId","SetPressure","GetTerminal","GetKeyName","GetEmptyItem","CheckPending","GetNightLight","_backspace","direct_teach_liv_to_str","direct_shake_obj","SetTitleLength","GetPickingQuality","query_sp","RemoveRider","AddAdverbs","direct_target_liv","GetTeachingLanguages","GetVisibility","indirect_turn_obj_on_obj_off","indirect_fill_obj_from_obj","AddListen","RemoveMagicProtection","SetKey","direct_unload_obj_word_obj","eventReceiveObject","_goto_line","CanReceive","ContinueTeaching","SetParanoia","do_nickname","SetOpenFee","GetItem","direct_knock_on_obj","direct_missile_at_liv","TellTale","chanwho_out","SetProperty","RemoveEmoteResponse","_message_done","SetPoison","getmudinfo","GetId","SetInventoryCheck","AddExit","SetCanBite","SetRemoteTargets","direct_turn_on_obj_on_obj","SetLogHarass","CreateVirtualObject","direct_target_liv_only","SetNoReplace","RemoveExit","GetChannelEmote","RemoveListen","SetAutoResets","GetDirectionMap","direct_learn_to_str_from_liv","GetRules","GetBonusDuration","GetBurntValue","SetBurnRate","eventThrow","_refresh_status","direct_aim_liv_with_obj","chan_perm_allowed","RemoveTouch","GetTalesDir","ResolveObjectName","RemoveTrainingSkills","direct_curse_obj","indirect_get_obs_obj","direct_fireball_liv","SetMaxAmmo","RemoveEnemy","eventClose","SetNativeLanguage","AddCarriedMass","GetTalkHistory","GetMagicPoints","GetNews","GetRequestResponse","get_path","SetClanObject","SetSource","AddSurcharge","SetProperties","GetHB","GetNoClean","GetSaveString","SetOwnerOb","eventSuffer","GetSide","direct_add_obj","SetTax","CanKnock","AddPartyQuest","direct_bury_obj_with_obj","SetLongAndItems","eventDrain","CanSwivel","direct_send_str_to_str","eventListen","direct_frigidus_at_liv","GetStatsMap","eventCollapse","SetGodMode","restart_heart","CanFree","RestoreObject","GetNoCondition","direct_shield_liv","GetCannotInfect","isFreshCorpse","eventConvert","eventRemoveCandidate","do_alias","AddRequestResponses","indirect_aim_obj_at_liv","indirect_pour_obj_into_obj","SetCanClimbCarried","SetWizVision","cache_commands","GetInternalDesc","GetPull","SetCannotInfect","direct_command_liv","SetPreventLand","AddSkillPoints","CanTurnOn","SetPlayerKill","pinkfish_to_imc2","GetExits","SetInternalDesc","GetStorageRoom","GetVisibleRiders","GetTouches","direct_climb_out_of_obj","direct_dismount_from_liv","eventBurnOut","_replace_done","indirect_get_obj_obj","indirect_add_obj_to_obj","query_mp","SetTitles","direct_get_wrd_wrd_out_of_obj","GetJumps","AddExperiencePoints","SetWhereBlock","SetPistolType","GetMatching","_page_down","cmd_post","AddVerb","eventEvade","receive_snoop","eventPull","more","GetAssets","GetWieldingLimbs","SetLastError","GetGridMap","GetAttackable","reset","RemoveVerb","SetShake","direct_soulseek_liv","GetSkill","SetCharge","GetBaseFile","eventInfect","SetEmptyItem","AddMuffed","eventReceiveSit","eventExchange","direct_zap_liv","GetPagerPrompt","SetEmail","SetDestroyOnSell","rCtrl","SetFish","inventory_visible","direct_roll_obj","GetPulls","SetEmoteResponses","SetSpellChance","GetTrapType","status","direct_give_obj_to_liv","ContinueHeart","eventMove","GetStatClass","GetRestrictLimbs","SetTerminal","direct_reload_str_word","GetDisabled","SetOrigin","RemoveTrainingPoints","CanReceiveHealing","direct_drop_obj","eventKillEnemy","direct_get_obj_from_obj","RemoveMuffed","send_ice_refresh","direct_turn_obj_off","eventUnjoin","GetRace","indirect_reload_word_obj","indirect_light_obj_with_obj","direct_drive_word_str","SetActionsMap","direct_delete_obj","GetForced","GetExtraLong","eventClimb","eventReceive","RemoveEnter","indirect_dest_obj","cmd_popd","RemoveSkillBonus","CanThrow","GetSmells","direct_cast_str_against_str","GetMarriages","GetDayLong","direct_refresh_liv","GetExternalDesc","direct_open_obj","_append_line","RemoveCommandResponse","GetRespiration","GetWeight","GetBaseCost","eventTrain","AddHP","CanClose","_page_up","process_request","CanExtinguish","SetExternalDesc","_refresh","eventReceiveAttack","direct_rock_str_on_obj","CheckRooms","query_hp","direct_press_str_on_obj","GetEnterData","GetExit","direct_shake_str_on_obj","DestLimb","CanBank","SetFood","GetShort","performMarriage","direct_heal_liv","GetDeviating","GetSearch","GetAffectLong","write_prompt","SetKeyName","GetCommandResponses","SetTalesDir","SetLevel","GetNonCurrencyMass","GetBurning","GetRefuelable","eventLearnSpell","GetKeys","indirect_aim_obj_at_obj","GetNonTargets","direct_pray_for_str_against_str_for_liv","SetMaxCommandHistSize","AddHeartModifier","eventConnect","chat_command","UnloadAll","GetTouch","eventWeaponRound","SetSacrificeType","SetWield","eventPutOn","tell_out","GetCaffeine","direct_activate_str_on_obj","GetStrikeChance","CanMail","AddMoney","eventSacrifice","direct_teach_str_to_liv","GetBaseLimbs","_undef_key","SetStrikeChance","eventReceiveEmote","GetBury","direct_attack_liv","direct_get_obj","CanFillMe","eventSmell","eventSpeak","AddMenuItem","direct_ask_liv_to_str","direct_lie_down_word_obj","eventGo","GetNetWorth","GetGender","direct_target_only_liv","GetLanguageLevel","SetShade","GetPersistent","GetCapName","GetBonusName","GetLocalFee","eventHealDamage","find_mud","SetProtection","CanEvade","CanCarry","AddTrainingSkills","direct_whisper_to_liv","GetAutoStand","indirect_shoot_obj_at_liv","GetNoEcho","GetMaxCommandHistSize","GetPoisonStrength","add_post","eventBite","direct_reload_every_str","SetPrompt","eventLoadIndex","GetHistory","GetFingers","GetMaxLiers","query_prev_wd","SetMount","direct_pick_str_on_obj","CanBuy","eventBurn","direct_smell_obj","direct_fly_str","GetWanderRecurse","valid_access","direct_climb_word","SetMatching","GetPick","eventStrike","SetNoClean","GetConsultResponse","GetRooms","GetMuted","direct_balance_obj_to_obj","direct_roll_obj_on_str","GetVerb","CanBait","indirect_unload_obj_word_obj","direct_lock_obj_with_str","GetLockable","GetRadiantLight","GetOpen","eventDonate","indirect_load_obj_word_obj","_join","GetShadows","direct_wield_obj","AddJump","CanUninstall","SetBaseFile","AddEmoteResponse","RemoveManipulate","GetRaceAdverb","GetUndeadType","eventPick","SetRadiantLight","eventUse","query_max_sp","indirect_turn_on_obj_on_obj","interbeep","GetLivingMaxCarry","SaveObject","CanClimb","GetRandomLimb","GetCreatorBirth","GetDoorsMap","GetVirtual","query_posts","GeteventPrints","eventQueueCommand",}) +LCFunctions (["getrooms":({"GetRooms",}),"_message":({"_message",}),"getmuted":({"GetMuted",}),"direct_missile_liv":({"direct_missile_liv",}),"getchannel":({"GetChannel",}),"eventputinto":({"eventPutInto",}),"channel_out":({"channel_out",}),"read_callback":({"read_callback",}),"addsave":({"AddSave",}),"getteachingfee":({"GetTeachingFee",}),"setcanlock":({"SetCanLock",}),"setcommunicable":({"SetCommunicable",}),"setskills":({"SetSkills",}),"getname":({"GetName",}),"removeitem":({"RemoveItem",}),"canconsult":({"CanConsult",}),"setpull":({"SetPull",}),"gettellingtale":({"GetTellingTale",}),"_file_head":({"_file_head",}),"setdamage":({"SetDamage",}),"gethiddendoor":({"GetHiddenDoor",}),"getbonusname":({"GetBonusName",}),"getconjure":({"GetConjure",}),"indirect_light_obs_with_obj":({"indirect_light_obs_with_obj",}),"eventmeleeattack":({"eventMeleeAttack",}),"direct_put_obj_obj":({"direct_put_obj_obj",}),"canclimb":({"CanClimb",}),"addlanguagepoints":({"AddLanguagePoints",}),"setitem_func":({"SetItem_func",}),"got_packet":({"got_packet",}),"move_or_destruct":({"move_or_destruct",}),"direct_detect_wrd_in_obj":({"direct_detect_wrd_in_obj",}),"setresetmessage":({"SetResetMessage",}),"eventbait":({"eventBait",}),"setpile":({"SetPile",}),"iscouncilmember":({"IsCouncilMember",}),"end_edit":({"end_edit",}),"direct_turn_obj_on_obj_on":({"direct_turn_obj_on_obj_on",}),"eventevade":({"eventEvade",}),"getplayerob":({"GetPlayerob",}),"eventloadobject":({"eventLoadObject",}),"setfishing":({"SetFishing",}),"direct_stealth_wrd":({"direct_stealth_wrd",}),"can_use":({"can_use",}),"getchance":({"GetChance",}),"direct_resurrect_liv":({"direct_resurrect_liv",}),"setcelltype":({"SetCellType",}),"eventboobytrap":({"eventBoobytrap",}),"checkrooms":({"CheckRooms",}),"direct_scratch_str_on_obj":({"direct_scratch_str_on_obj",}),"cantrain":({"CanTrain",}),"send_packet":({"send_packet",}),"canbreathe":({"CanBreathe",}),"getcurrency":({"GetCurrency",}),"direct_abandon_liv":({"direct_abandon_liv",}),"setresistance":({"SetResistance",}),"gethealrate":({"GetHealRate",}),"direct_fish_with_obj":({"direct_fish_with_obj",}),"indirect_roll_obs_on_obj":({"indirect_roll_obs_on_obj",}),"getsleeping":({"GetSleeping",}),"telltale":({"TellTale",}),"eventbuyitem":({"eventBuyItem",}),"restore_player":({"restore_player",}),"direct_crawl_str":({"direct_crawl_str",}),"id":({"id",}),"direct_aim_obj_at_liv":({"direct_aim_obj_at_liv",}),"direct_put_wrd_wrd_word_obj":({"direct_put_wrd_wrd_word_obj",}),"clearbuffers":({"ClearBuffers",}),"getplainshort":({"GetPlainShort",}),"eventlearnspell":({"eventLearnSpell",}),"settempbuffer":({"SetTempbuffer",}),"addrequestresponse":({"AddRequestResponse",}),"getmountowner":({"GetMountOwner",}),"getfollowers":({"GetFollowers",}),"notifyreceipt":({"NotifyReceipt",}),"eventinstall":({"eventInstall",}),"getflaskcontents":({"GetFlaskContents",}),"eventrequest":({"eventRequest",}),"gettown":({"GetTown",}),"_replace":({"_replace",}),"getenter":({"GetEnter",}),"direct_train_liv_to_str":({"direct_train_liv_to_str",}),"direct_buffer_liv":({"direct_buffer_liv",}),"indirect_shoot_obj_at_obj":({"indirect_shoot_obj_at_obj",}),"getresetnumber":({"GetResetNumber",}),"direct_pray_for_str_for_obj":({"direct_pray_for_str_for_obj",}),"getchannels":({"GetChannels",}),"setpickingquality":({"SetPickingQuality",}),"direct_add_obj_to_obj":({"direct_add_obj_to_obj",}),"direct_ride_str":({"direct_ride_str",}),"setdestroyonsell":({"SetDestroyOnSell",}),"_help":({"_help",}),"setrace":({"SetRace",}),"canjump":({"CanJump",}),"removepull":({"RemovePull",}),"mustwield":({"MustWield",}),"setvalue":({"SetValue",}),"getblind":({"GetBlind",}),"direct_ask_liv_str":({"direct_ask_liv_str",}),"do_verb_rule":({"do_verb_rule",}),"addteachinglanguages":({"AddTeachingLanguages",}),"getwimpy":({"GetWimpy",}),"eventclimb":({"eventClimb",}),"cansit":({"CanSit",}),"cmdpage":({"cmdPage",}),"direct_reload_word_obj":({"direct_reload_word_obj",}),"getlastenvironment":({"GetLastEnvironment",}),"getdamagepoints":({"GetDamagePoints",}),"getlong":({"GetLong",}),"unsetautodisabled":({"UnSetAutoDisabled",}),"getpiletype":({"GetPileType",}),"removeblindness":({"RemoveBlindness",}),"direct_enter_into_obj":({"direct_enter_into_obj",}),"canspeak":({"CanSpeak",}),"setitem_desc":({"SetItem_desc",}),"eventcomparelimbs":({"eventCompareLimbs",}),"query_max_mp":({"query_max_mp",}),"setnobotcondition":({"SetNoBotCondition",}),"setac":({"SetAC",}),"setinventorycheck":({"SetInventoryCheck",}),"setlanguage":({"SetLanguage",}),"parse_command_id_list":({"parse_command_id_list",}),"setbodymass":({"SetBodyMass",}),"setdamagepoints":({"SetDamagePoints",}),"setdebugging":({"SetDebugging",}),"getentermessage":({"GetEnterMessage",}),"direct_dig_obj_with_obj":({"direct_dig_obj_with_obj",}),"eventtrain":({"eventTrain",}),"getnodecay":({"GetNoDecay",}),"direct_body_liv":({"direct_body_liv",}),"getcustomdeviations":({"GetCustomDeviations",}),"eventsit":({"eventSit",}),"setnoreplace":({"SetNoReplace",}),"getcanclose":({"GetCanClose",}),"eventwear":({"eventWear",}),"isfollowing":({"IsFollowing",}),"canstop":({"CanStop",}),"setentermessage":({"SetEnterMessage",}),"validate":({"validate",}),"indirect_delete_exit_str":({"indirect_delete_exit_str",}),"setpoints":({"SetPoints",}),"eventuntrainliving":({"eventUnTrainLiving",}),"getrarity":({"GetRarity",}),"getadverbs":({"GetAdverbs",}),"canmelee":({"CanMelee",}),"setenters":({"SetEnters",}),"setsinkroom":({"SetSinkRoom",}),"setrequiredmagic":({"SetRequiredMagic",}),"getfurniturename":({"GetFurnitureName",}),"direct_unload_obj":({"direct_unload_obj",}),"direct_remove_obj":({"direct_remove_obj",}),"eventpoison":({"eventPoison",}),"candig":({"CanDig",}),"getskillclass":({"GetSkillClass",}),"getlimb":({"GetLimb",}),"_down":({"_down",}),"setstaminacost":({"SetStaminaCost",}),"canaim":({"CanAim",}),"addquestpoints":({"AddQuestPoints",}),"getcanonicalid":({"GetCanonicalId",}),"setkeys":({"SetKeys",}),"eventcapture":({"eventCapture",}),"show":({"show",}),"direct_rock_str":({"direct_rock_str",}),"direct_unlock_obj_with_str":({"direct_unlock_obj_with_str",}),"direct_copy_obj_str":({"direct_copy_obj_str",}),"setlocalcurrency":({"SetLocalCurrency",}),"setwanderpath":({"SetWanderPath",}),"getdoorside":({"GetDoorSide",}),"eventsink":({"eventSink",}),"eventfollow":({"eventFollow",}),"cmd_followup_and_respond":({"cmd_followup_and_respond",}),"cangive":({"CanGive",}),"getspelllevel":({"GetSpellLevel",}),"getmaxstatpoints":({"GetMaxStatPoints",}),"_insert_line":({"_insert_line",}),"indirect_marry_liv_to_liv":({"indirect_marry_liv_to_liv",}),"eventdig":({"eventDig",}),"eventdie":({"eventDie",}),"getdifficulty":({"GetDifficulty",}),"setcarriedmass":({"SetCarriedMass",}),"eventaim":({"eventAim",}),"indirect_delete_obj":({"indirect_delete_obj",}),"getriders":({"GetRiders",}),"setskillmodifier":({"SetSkillModifier",}),"direct_smoke_obj":({"direct_smoke_obj",}),"gettalekeys":({"GetTaleKeys",}),"getrespiration":({"GetRespiration",}),"setbury":({"SetBury",}),"getworldmap":({"GetWorldMap",}),"getbirth":({"GetBirth",}),"setbonusname":({"SetBonusName",}),"setdollarcost":({"SetDollarCost",}),"settapped":({"SetTapped",}),"removechannel":({"RemoveChannel",}),"getcombataction":({"GetCombatAction",}),"eventsmell":({"eventSmell",}),"eventspeak":({"eventSpeak",}),"canjoin":({"CanJoin",}),"getlivingshort":({"GetLivingShort",}),"getlightlevel":({"GetLightLevel",}),"getonline":({"getonline",}),"addrequestresponses":({"AddRequestResponses",}),"setmaxmagicpoints":({"SetMaxMagicPoints",}),"_goto_line_done":({"_goto_line_done",}),"direct_resurrect_obj":({"direct_resurrect_obj",}),"setlanguagecomprehension":({"SetLanguageComprehension",}),"direct_pour_out_obj":({"direct_pour_out_obj",}),"addquestskillpoints":({"AddQuestSkillPoints",}),"getcaptives":({"GetCaptives",}),"query_board_time":({"query_board_time",}),"eventgetfrom":({"eventGetFrom",}),"getclanskill":({"GetClanSkill",}),"getrifletype":({"GetRifleType",}),"getheartmodifier":({"GetHeartModifier",}),"canequip":({"CanEquip",}),"setcombataction":({"SetCombatAction",}),"direct_rockwhip_liv":({"direct_rockwhip_liv",}),"getroomzero":({"GetRoomZero",}),"getwebpage":({"GetWebPage",}),"imc2_to_pinkfish":({"imc2_to_pinkfish",}),"setrules":({"SetRules",}),"setmessage":({"SetMessage",}),"getsave":({"GetSave",}),"isgerm":({"isGerm",}),"disconnect":({"disconnect",}),"direct_aim_obj_at_obj":({"direct_aim_obj_at_obj",}),"getlivingmaxcarry":({"GetLivingMaxCarry",}),"addfollower":({"AddFollower",}),"eventreceivethrow":({"eventReceiveThrow",}),"canget":({"CanGet",}),"getinvis":({"GetInvis",}),"setallowsacrifice":({"SetAllowSacrifice",}),"setdeities":({"SetDeities",}),"removeexit":({"RemoveExit",}),"removesmell":({"RemoveSmell",}),"eventspeciallist":({"eventSpecialList",}),"query_max_hp":({"query_max_hp",}),"getfirearmname":({"GetFirearmName",}),"setlonganditems":({"SetLongAndItems",}),"string_to_mapping":({"string_to_mapping",}),"getsynonyms":({"GetSynonyms",}),"setpick":({"SetPick",}),"addshadow":({"AddShadow",}),"indirect_bury_obj_with_obj":({"indirect_bury_obj_with_obj",}),"addkey":({"AddKey",}),"eventcruise":({"eventCruise",}),"getflowlimit":({"GetFlowLimit",}),"eventpour":({"eventPour",}),"setmaxfuel":({"SetMaxFuel",}),"cansell":({"CanSell",}),"chanwho_reply_in":({"chanwho_reply_in",}),"wild_card":({"wild_card",}),"candivorce":({"CanDivorce",}),"setverb":({"SetVerb",}),"canremoveitem":({"CanRemoveItem",}),"getspouse":({"GetSpouse",}),"removemanipulate":({"RemoveManipulate",}),"eventget":({"eventGet",}),"eventtallyvotes":({"eventTallyVotes",}),"setperforated":({"SetPerforated",}),"getmanipulate":({"GetManipulate",}),"getpassword":({"GetPassword",}),"setopen":({"SetOpen",}),"setwanderrecurse":({"SetWanderRecurse",}),"removemenuitem":({"RemoveMenuItem",}),"setcurrency":({"SetCurrency",}),"removemagicprotection":({"RemoveMagicProtection",}),"direct_command_liv_to_str":({"direct_command_liv_to_str",}),"_right":({"_right",}),"setlocked":({"SetLocked",}),"html":({"html",}),"setsleeping":({"SetSleeping",}),"getclass":({"GetClass",}),"removeencounter":({"RemoveEncounter",}),"eventrestoresight":({"eventRestoreSight",}),"getslowdecay":({"GetSlowDecay",}),"recurselocations":({"RecurseLocations",}),"canswim":({"CanSwim",}),"gethealing":({"GetHealing",}),"setdeathevents":({"SetDeathEvents",}),"compile_object":({"compile_object",}),"can_verb_rule":({"can_verb_rule",}),"indirect_read_obj_at_obj":({"indirect_read_obj_at_obj",}),"getspecialtarget":({"GetSpecialTarget",}),"eventcharge":({"eventCharge",}),"eventforcequeuedcommand":({"eventForceQueuedCommand",}),"getcouncilmember":({"GetCouncilMember",}),"destlimb":({"DestLimb",}),"launch":({"launch",}),"eventequip":({"eventEquip",}),"setnoobviousexits":({"SetNoObviousExits",}),"eventdestroyundead":({"eventDestroyUndead",}),"chancmd":({"chancmd",}),"cmd_pwd":({"cmd_pwd",}),"setconjure":({"SetConjure",}),"getmaxloaded":({"GetMaxLoaded",}),"addfish":({"AddFish",}),"getconsults":({"GetConsults",}),"addspecialmenuitem":({"AddSpecialMenuItem",}),"setlit":({"SetLit",}),"getcarriedweight":({"GetCarriedWeight",}),"eventwritefile":({"eventWriteFile",}),"setexits":({"SetExits",}),"direct_look_on_obj":({"direct_look_on_obj",}),"canscratch":({"CanScratch",}),"eventconsult":({"eventConsult",}),"setadjectives":({"SetAdjectives",}),"canroll":({"CanRoll",}),"getemoteresponse":({"GetEmoteResponse",}),"indirect_balance_obj_to_obj":({"indirect_balance_obj_to_obj",}),"gettrapdescription":({"GetTrapDescription",}),"preaddenter":({"PreAddEnter",}),"write_to_log":({"write_to_log",}),"setaggressive":({"SetAggressive",}),"setcurrencies":({"SetCurrencies",}),"direct_shoot_obj_with_obj":({"direct_shoot_obj_with_obj",}),"querybane":({"QueryBane",}),"getreadsmap":({"GetReadsMap",}),"setmealaction":({"SetMealAction",}),"getmaxflask":({"GetMaxFlask",}),"getescapechance":({"GetEscapeChance",}),"removecommandresponse":({"RemoveCommandResponse",}),"direct_untrain_liv":({"direct_untrain_liv",}),"removeproperty":({"RemoveProperty",}),"getmincells":({"GetMinCells",}),"addrecursedepth":({"AddRecurseDepth",}),"getposition":({"GetPosition",}),"pushd":({"pushd",}),"setescapechance":({"SetEscapeChance",}),"gethands":({"GetHands",}),"send_keepalive_request":({"send_keepalive_request",}),"direct_move_obj":({"direct_move_obj",}),"setskill":({"SetSkill",}),"whois_in":({"whois_in",}),"direct_free_liv_from_obj":({"direct_free_liv_from_obj",}),"indirect_sell_liv_obj":({"indirect_sell_liv_obj",}),"direct_dispel_liv":({"direct_dispel_liv",}),"setmaxsitters":({"SetMaxSitters",}),"getdirectionroom":({"GetDirectionRoom",}),"removeverb":({"RemoveVerb",}),"setcanclose":({"SetCanClose",}),"getenemynames":({"GetEnemyNames",}),"getluck":({"GetLuck",}),"sendweaponmessages":({"SendWeaponMessages",}),"beep_out":({"beep_out",}),"getcommandresponses":({"GetCommandResponses",}),"addconsultresponse":({"AddConsultResponse",}),"_search_done":({"_search_done",}),"direct_look_at_str_on_obj":({"direct_look_at_str_on_obj",}),"getmagicchance":({"GetMagicChance",}),"direct_apply_obj_word_obj":({"direct_apply_obj_word_obj",}),"appraise":({"appraise",}),"getvendortype":({"GetVendorType",}),"getfloors":({"GetFloors",}),"_undef_key_done":({"_undef_key_done",}),"addmagicpoints":({"AddMagicPoints",}),"getmagiccost":({"GetMagicCost",}),"addfood":({"AddFood",}),"setdoorside":({"SetDoorSide",}),"getowner":({"GetOwner",}),"gethboverride":({"GetHBOverride",}),"set_cwd":({"set_cwd",}),"eventempty":({"eventEmpty",}),"enableactions":({"EnableActions",}),"remove_dots":({"remove_dots",}),"getground":({"GetGround",}),"direct_shock_liv":({"direct_shock_liv",}),"direct_lead_liv":({"direct_lead_liv",}),"parse_command_adjectiv_id_list":({"parse_command_adjectiv_id_list",}),"setclanskill":({"SetClanSkill",}),"setrifletype":({"SetRifleType",}),"indirect_turn_obj_on_obj_on":({"indirect_turn_obj_on_obj_on",}),"direct_immolate_liv":({"direct_immolate_liv",}),"direct_bait_obj_with_obj":({"direct_bait_obj_with_obj",}),"getmountstyle":({"GetMountStyle",}),"removeskillbonus":({"RemoveSkillBonus",}),"getmoneymap":({"GetMoneyMap",}),"getdying":({"GetDying",}),"getskillbonus":({"GetSkillBonus",}),"eventdecay":({"eventDecay",}),"getnativelanguage":({"GetNativeLanguage",}),"eventcompletemove":({"eventCompleteMove",}),"direct_whisper_to_liv_in_wrd_str":({"direct_whisper_to_liv_in_wrd_str",}),"addassets":({"AddAssets",}),"getmaxcarry":({"GetMaxCarry",}),"do_shoot":({"do_shoot",}),"settalkresponses":({"SetTalkResponses",}),"getskills":({"GetSkills",}),"resolve_callback":({"resolve_callback",}),"direct_scratch_on_obj":({"direct_scratch_on_obj",}),"getarmortype":({"GetArmorType",}),"getrequiredskill":({"GetRequiredSkill",}),"_up":({"_up",}),"setnodecay":({"SetNoDecay",}),"getdamage":({"GetDamage",}),"setammo":({"SetAmmo",}),"getvotestatus":({"GetVoteStatus",}),"direct_initfix":({"direct_initfix",}),"direct_heal_str_of_liv":({"direct_heal_str_of_liv",}),"setexchangefee":({"SetExchangeFee",}),"settype":({"SetType",}),"getmagicprotection":({"GetMagicProtection",}),"getshakes":({"GetShakes",}),"setflowlimit":({"SetFlowLimit",}),"getbaseskilllevel":({"GetBaseSkillLevel",}),"getclanname":({"GetClanName",}),"strcoord":({"StrCoord",}),"eventtellhist":({"eventTellHist",}),"getlimbparent":({"GetLimbParent",}),"getdefaultlanguage":({"GetDefaultLanguage",}),"setmedium":({"SetMedium",}),"setshort":({"SetShort",}),"getvisibility":({"GetVisibility",}),"canlearn":({"CanLearn",}),"cmdappraise":({"cmdAppraise",}),"eventpull":({"eventPull",}),"setrescuebit":({"SetRescueBit",}),"getpreventput":({"GetPreventPut",}),"eventreceivesit":({"eventReceiveSit",}),"addchannel":({"AddChannel",}),"getstrength":({"GetStrength",}),"_input":({"_input",}),"eventnextday":({"eventNextDay",}),"direct_put_obj_word_obj":({"direct_put_obj_word_obj",}),"eventenemydied":({"eventEnemyDied",}),"setloaded":({"SetLoaded",}),"setsynonyms":({"SetSynonyms",}),"setslowdecay":({"SetSlowDecay",}),"direct_delete_exit_str":({"direct_delete_exit_str",}),"getstaminapoints":({"GetStaminaPoints",}),"direct_swivel_str":({"direct_swivel_str",}),"getchannelemote":({"GetChannelEmote",}),"loadauto":({"LoadAuto",}),"direct_use_obj":({"direct_use_obj",}),"canturnon":({"CanTurnOn",}),"direct_party_wrd_liv":({"direct_party_wrd_liv",}),"getparty":({"GetParty",}),"user_name":({"user_name",}),"settouch":({"SetTouch",}),"direct_look_in_obj":({"direct_look_in_obj",}),"direct_read_str_word_obj":({"direct_read_str_word_obj",}),"performdivorce":({"performDivorce",}),"getwielded":({"GetWielded",}),"direct_shoot_liv_with_obj":({"direct_shoot_liv_with_obj",}),"rctrl":({"rCtrl",}),"setgagged":({"SetGagged",}),"setpassword":({"SetPassword",}),"addexperiencepoints":({"AddExperiencePoints",}),"eventmanipulate":({"eventManipulate",}),"getneighborcoords":({"GetNeighborCoords",}),"cmd_pushd":({"cmd_pushd",}),"direct_get_wrd_wrd_from_obj":({"direct_get_wrd_wrd_from_obj",}),"getpowertype":({"GetPowerType",}),"compileneighbors":({"CompileNeighbors",}),"addnontargets":({"AddNonTargets",}),"getclimbs":({"GetClimbs",}),"eventmove":({"eventMove",}),"getfuelamount":({"GetFuelAmount",}),"direct_farsight_liv":({"direct_farsight_liv",}),"getcommandresponse":({"GetCommandResponse",}),"indirect_reload_str_obj":({"indirect_reload_str_obj",}),"modcharge":({"ModCharge",}),"addlocation":({"AddLocation",}),"getdrainable":({"GetDrainable",}),"direct_ask_liv_about_str":({"direct_ask_liv_about_str",}),"eventdismount":({"eventDismount",}),"setwebpage":({"SetWebPage",}),"addtitle":({"AddTitle",}),"getbodycomposition":({"GetBodyComposition",}),"removesearchpath":({"RemoveSearchPath",}),"_keymap_done":({"_keymap_done",}),"getcoordinatemap":({"GetCoordinateMap",}),"getspecials":({"GetSpecials",}),"direct_judge_obj_to_obj":({"direct_judge_obj_to_obj",}),"getsearchpath":({"GetSearchPath",}),"setproperties":({"SetProperties",}),"direct_bless_obj":({"direct_bless_obj",}),"getmealmessages":({"GetMealMessages",}),"canshowinterior":({"CanShowInterior",}),"eventsacrifice":({"eventSacrifice",}),"getmessages":({"GetMessages",}),"direct_sit_down_word_obj":({"direct_sit_down_word_obj",}),"canrock":({"CanRock",}),"eventdrive":({"eventDrive",}),"addsearch":({"AddSearch",}),"indirect_show_liv_obj":({"indirect_show_liv_obj",}),"indirect_unlock_obj_with_str":({"indirect_unlock_obj_with_str",}),"getfish":({"GetFish",}),"setcantrain":({"SetCanTrain",}),"eventlearn":({"eventLearn",}),"setmealmessages":({"SetMealMessages",}),"getpressure":({"GetPressure",}),"direct_weigh_obj":({"direct_weigh_obj",}),"getcommandfail":({"GetCommandFail",}),"teller_check":({"teller_check",}),"addstatbonus":({"AddStatBonus",}),"indirect_lock_obj_with_str":({"indirect_lock_obj_with_str",}),"eventconvertobject":({"eventConvertObject",}),"eventloaditem":({"eventLoadItem",}),"canbefriend":({"CanBefriend",}),"getgomessage":({"GetGoMessage",}),"direct_look_at_obj_word_obj":({"direct_look_at_obj_word_obj",}),"eventsuffer":({"eventSuffer",}),"setflaskcontents":({"SetFlaskContents",}),"missed_shot":({"missed_shot",}),"direct_steal_obj_from_liv":({"direct_steal_obj_from_liv",}),"setmaxflask":({"SetMaxFlask",}),"setmuted":({"SetMuted",}),"direct_climb_out":({"direct_climb_out",}),"eventlisten":({"eventListen",}),"catch_tell":({"catch_tell",}),"direct_calm_liv":({"direct_calm_liv",}),"removequest":({"RemoveQuest",}),"cankneel":({"CanKneel",}),"setmincells":({"SetMinCells",}),"setposition":({"SetPosition",}),"getpoints":({"GetPoints",}),"clean_up":({"clean_up",}),"eventdivorce":({"eventDivorce",}),"getenters":({"GetEnters",}),"receivechars":({"ReceiveChars",}),"flicker":({"flicker",}),"end_post":({"end_post",}),"getparanoia":({"GetParanoia",}),"sethealing":({"SetHealing",}),"setmagiccost":({"SetMagicCost",}),"addread":({"AddRead",}),"candrop":({"CanDrop",}),"setunique":({"SetUnique",}),"getproperty":({"GetProperty",}),"settale":({"SetTale",}),"addmass":({"AddMass",}),"getstats":({"GetStats",}),"indirect_pulsecheck_liv":({"indirect_pulsecheck_liv",}),"getdirection":({"GetDirection",}),"getmealtype":({"GetMealType",}),"getareamap":({"GetAreaMap",}),"getdrainrate":({"GetDrainRate",}),"canshake":({"CanShake",}),"direct_shoot_obj_wrd_at_wrd":({"direct_shoot_obj_wrd_at_wrd",}),"direct_cast_str_on_obj":({"direct_cast_str_on_obj",}),"setmaxcapture":({"SetMaxCapture",}),"cmdsmell":({"cmdSmell",}),"direct_poison_obj_with_obj":({"direct_poison_obj_with_obj",}),"getattackable":({"GetAttackable",}),"direct_search_obj":({"direct_search_obj",}),"eventloadchapters":({"eventLoadChapters",}),"setundeadtype":({"SetUndeadType",}),"cancast":({"CanCast",}),"_del_char":({"_del_char",}),"addadverbs":({"AddAdverbs",}),"setarmortype":({"SetArmorType",}),"getmenuitems":({"GetMenuItems",}),"direct_read_obj_at_obj":({"direct_read_obj_at_obj",}),"getshadowedobject":({"GetShadowedObject",}),"getentermap":({"GetEnterMap",}),"setemoteresponses":({"SetEmoteResponses",}),"getmaxitems":({"GetMaxItems",}),"getfood":({"GetFood",}),"gettapped":({"GetTapped",}),"eventburywith":({"eventBuryWith",}),"direct_aim_obj_wrd":({"direct_aim_obj_wrd",}),"canreceive":({"CanReceive",}),"eventscratch":({"eventScratch",}),"_write":({"_write",}),"setsaverecurse":({"SetSaveRecurse",}),"getlit":({"GetLit",}),"setpoisonuses":({"SetPoisonUses",}),"direct_befriend_liv":({"direct_befriend_liv",}),"setmaxcarry":({"SetMaxCarry",}),"candrink":({"CanDrink",}),"initrevolver":({"InitRevolver",}),"eventinfect":({"eventInfect",}),"remove":({"remove",}),"setenter":({"SetEnter",}),"generateobviousexits":({"GenerateObviousExits",}),"eventbite":({"eventBite",}),"direct_look_at_obj":({"direct_look_at_obj",}),"setundead":({"SetUndead",}),"eventkneel":({"eventKneel",}),"setroom":({"SetRoom",}),"ping_reply_in":({"ping_reply_in",}),"eventburn":({"eventBurn",}),"direct_get_obj_out_of_obj":({"direct_get_obj_out_of_obj",}),"direct_pull_obj":({"direct_pull_obj",}),"additem_func":({"AddItem_func",}),"canfillme":({"CanFillMe",}),"setclanname":({"SetClanName",}),"indirect_buy_str_from_liv":({"indirect_buy_str_from_liv",}),"direct_annihilate_at_liv":({"direct_annihilate_at_liv",}),"putcoins":({"PutCoins",}),"canboobytrap":({"CanBoobytrap",}),"direct_veil_liv_against_wrd_wrd":({"direct_veil_liv_against_wrd_wrd",}),"getchamberinterior":({"GetChamberInterior",}),"level":({"level",}),"putcheck":({"PutCheck",}),"getshadowed":({"GetShadowed",}),"setwimpy":({"SetWimpy",}),"removedig":({"RemoveDig",}),"woundlong":({"WoundLong",}),"getautodamage":({"GetAutoDamage",}),"getprimaryskills":({"GetPrimarySkills",}),"direct_drive":({"direct_drive",}),"direct_arrow_liv":({"direct_arrow_liv",}),"getquestpoints":({"GetQuestPoints",}),"canpeer":({"CanPeer",}),"eventunjoin":({"eventUnjoin",}),"setstrength":({"SetStrength",}),"_append":({"_append",}),"eventshake":({"eventShake",}),"start_logon":({"start_logon",}),"list":({"list",}),"setpowertype":({"SetPowerType",}),"geterrormessage":({"GetErrorMessage",}),"getnocondition":({"GetNoCondition",}),"eventhealdamage":({"eventHealDamage",}),"getlocked":({"GetLocked",}),"direct_pull_str_from_obj":({"direct_pull_str_from_obj",}),"canextinguish":({"CanExtinguish",}),"setdrainable":({"SetDrainable",}),"indirect_shoot_obj_with_obj":({"indirect_shoot_obj_with_obj",}),"direct_attack_liv_only":({"direct_attack_liv_only",}),"eventquell":({"eventQuell",}),"seterrormessage":({"SetErrorMessage",}),"disableactions":({"DisableActions",}),"eventpick":({"eventPick",}),"tell_in":({"tell_in",}),"direct_blades_liv":({"direct_blades_liv",}),"direct_sacrifice_obj_to_str":({"direct_sacrifice_obj_to_str",}),"getlastcommand":({"GetLastCommand",}),"addpoison":({"AddPoison",}),"cmd_alias":({"cmd_alias",}),"removeshake":({"RemoveShake",}),"registerlocation":({"RegisterLocation",}),"cancelcharmode":({"CancelCharmode",}),"getbonusduration":({"GetBonusDuration",}),"eventopen":({"eventOpen",}),"direct_empty_obj":({"direct_empty_obj",}),"eventdrink":({"eventDrink",}),"getspellbook":({"GetSpellBook",}),"getrefuelable":({"GetRefuelable",}),"setcansit":({"SetCanSit",}),"getdeterioration":({"GetDeterioration",}),"getshadowobject":({"GetShadowObject",}),"eventkillenemy":({"eventKillEnemy",}),"getscratches":({"GetScratches",}),"addcarriedmass":({"AddCarriedMass",}),"setgomessage":({"SetGoMessage",}),"direct_sit_word_obj":({"direct_sit_word_obj",}),"sethelp":({"SetHelp",}),"setshadowobject":({"SetShadowObject",}),"eventaddcandidate":({"eventAddCandidate",}),"getnightlight":({"GetNightLight",}),"gettouches":({"GetTouches",}),"indirect_apply_obj_word_obj":({"indirect_apply_obj_word_obj",}),"setmessages":({"SetMessages",}),"setpressure":({"SetPressure",}),"getterminal":({"GetTerminal",}),"canuse":({"CanUse",}),"_refresh_screen":({"_refresh_screen",}),"saveobject":({"SaveObject",}),"_refresh_cursor":({"_refresh_cursor",}),"setspecialtarget":({"SetSpecialTarget",}),"getpersistent":({"GetPersistent",}),"direct_knock_str_on_obj":({"direct_knock_str_on_obj",}),"getcost":({"GetCost",}),"getresistancemap":({"GetResistanceMap",}),"setprotection":({"SetProtection",}),"indirect_aim_obj_with_obj":({"indirect_aim_obj_with_obj",}),"direct_scry_liv":({"direct_scry_liv",}),"getitemcondition":({"GetItemCondition",}),"setdrainrate":({"SetDrainRate",}),"window_size":({"window_size",}),"direct_can_give_liv_obj":({"direct_can_give_liv_obj",}),"eventuse":({"eventUse",}),"getgermname":({"GetGermName",}),"direct_demonclaw_liv":({"direct_demonclaw_liv",}),"removeextrachannels":({"RemoveExtraChannels",}),"getmaxrecursedepth":({"GetMaxRecurseDepth",}),"setparanoia":({"SetParanoia",}),"addsmell":({"AddSmell",}),"addbank":({"AddBank",}),"direct_verb_rule":({"direct_verb_rule",}),"save_player":({"save_player",}),"cmd_nmsh":({"cmd_nmsh",}),"getcure":({"GetCure",}),"setinvis":({"SetInvis",}),"setdoorstopped":({"SetDoorStopped",}),"indirect_pick_str_on_obj_with_obj":({"indirect_pick_str_on_obj_with_obj",}),"setmenuitems":({"SetMenuItems",}),"setpreventland":({"SetPreventLand",}),"setproperty":({"SetProperty",}),"setvirtfile":({"SetVirtFile",}),"getpress":({"GetPress",}),"getburntvalue":({"GetBurntValue",}),"getmudname":({"GetMudName",}),"getsmellmap":({"GetSmellMap",}),"getmudlist":({"GetMudList",}),"getstorageroom":({"GetStorageRoom",}),"changeclass":({"ChangeClass",}),"getread":({"GetRead",}),"getstatus":({"GetStatus","getstatus",}),"removerule":({"RemoveRule",}),"eventland":({"eventLand",}),"setmealtype":({"SetMealType",}),"direct_wield_obj_word_str":({"direct_wield_obj_word_str",}),"getradiantlight":({"GetRadiantLight",}),"whois":({"whois",}),"checkencounter":({"CheckEncounter",}),"direct_modify_obj_str":({"direct_modify_obj_str",}),"getmass":({"GetMass",}),"direct_consult_obj":({"direct_consult_obj",}),"eventrestoreequip":({"eventRestoreEquip",}),"direct_regen_str_on_liv":({"direct_regen_str_on_liv",}),"cmd_remove":({"cmd_remove",}),"direct_steal_wrd_from_liv":({"direct_steal_wrd_from_liv",}),"setradiantlight":({"SetRadiantLight",}),"direct_give_liv_wrd_wrd":({"direct_give_liv_wrd_wrd",}),"eventremoveblessing":({"eventRemoveBlessing",}),"eventofferteaching":({"eventOfferTeaching",}),"eventconvert":({"eventConvert",}),"limbcertain":({"LimbCertain",}),"getcreatorbirth":({"GetCreatorBirth",}),"settitlelength":({"SetTitleLength",}),"eventstrike":({"eventStrike",}),"setclass":({"SetClass",}),"check_include_text":({"check_include_text",}),"setmaxitems":({"SetMaxItems",}),"getlimbs":({"GetLimbs",}),"setcommandresponses":({"SetCommandResponses",}),"localize_channel":({"localize_channel",}),"addpartyquest":({"AddPartyQuest",}),"indirect_resurrect_obj":({"indirect_resurrect_obj",}),"direct_wizunlock_obj":({"direct_wizunlock_obj",}),"direct_ride_word_str":({"direct_ride_word_str",}),"direct_read_obj":({"direct_read_obj",}),"canattack":({"CanAttack",}),"indirect_shoot_liv_with_obj":({"indirect_shoot_liv_with_obj",}),"direct_ward_liv_against_wrd":({"direct_ward_liv_against_wrd",}),"getemptyname":({"GetEmptyName",}),"restorelimb":({"RestoreLimb",}),"direct_open_obj_with_obj":({"direct_open_obj_with_obj",}),"eventdonate":({"eventDonate",}),"querymap":({"QueryMap",}),"getbaseradiance":({"GetBaseRadiance",}),"canapply":({"CanApply",}),"getpreventget":({"GetPreventGet",}),"canturn":({"CanTurn",}),"direct_enter_obj":({"direct_enter_obj",}),"direct_burn_obj_with_obj":({"direct_burn_obj_with_obj",}),"direct_reload_str_obj":({"direct_reload_str_obj",}),"inventory_accessible":({"inventory_accessible",}),"getspelltype":({"GetSpellType",}),"getmastermap":({"GetMasterMap",}),"getmedium":({"GetMedium",}),"ceditsave":({"CeditSave",}),"domagunload":({"doMagUnload",}),"eventmount":({"eventMount",}),"direct_shoot_obj_wrd":({"direct_shoot_obj_wrd",}),"setcommercial":({"SetCommercial",}),"whois_reply_in":({"whois_reply_in",}),"getcurrentcommand":({"GetCurrentCommand",}),"setgrid":({"SetGrid",}),"getcombatchance":({"GetCombatChance",}),"direct_show_liv_obj":({"direct_show_liv_obj",}),"getexemptvirtual":({"GetExemptVirtual",}),"direct_smoke_from_obj":({"direct_smoke_from_obj",}),"eventloadindex":({"eventLoadIndex",}),"handleteller":({"HandleTeller",}),"setstat":({"SetStat",}),"direct_look_obj":({"direct_look_obj",}),"redrawscreen":({"RedrawScreen",}),"setareamap":({"SetAreaMap",}),"cgetsave":({"cGetSave",}),"getloaded":({"GetLoaded",}),"opendoor":({"openDoor",}),"getburning":({"GetBurning",}),"getmissinglimbparent":({"GetMissingLimbParent",}),"setmillimeter":({"SetMillimeter",}),"setwhereblock":({"SetWhereBlock",}),"direct_extinguish_obj":({"direct_extinguish_obj",}),"eventflood":({"eventFlood",}),"getgagged":({"GetGagged",}),"direct_whisper_in_wrd_to_liv_str":({"direct_whisper_in_wrd_to_liv_str",}),"getmagicpoints":({"GetMagicPoints",}),"cmd_work":({"cmd_work",}),"getdamagetype":({"GetDamageType",}),"addbait":({"AddBait",}),"sethands":({"SetHands",}),"getlivinglong":({"GetLivingLong",}),"rbackspace":({"rBackspace",}),"list_new_posts":({"list_new_posts",}),"direct_delete_obj_from_here":({"direct_delete_obj_from_here",}),"setspellbook":({"SetSpellBook",}),"getpickingquality":({"GetPickingQuality",}),"indirect_steal_obj_from_liv":({"indirect_steal_obj_from_liv",}),"eventforce":({"eventForce",}),"direct_activate_obj_on_obj":({"direct_activate_obj_on_obj",}),"getteachinglanguages":({"GetTeachingLanguages",}),"getmatching":({"GetMatching",}),"calculatecarriedmass":({"CalculateCarriedMass",}),"getreligions":({"GetReligions",}),"direct_close_obj":({"direct_close_obj",}),"indirect_sell_obs_to_liv":({"indirect_sell_obs_to_liv",}),"indirect_aim_liv_with_obj":({"indirect_aim_liv_with_obj",}),"addhealthpoints":({"AddHealthPoints",}),"setcharbuffer":({"SetCharbuffer",}),"indirect_free_liv_from_obj":({"indirect_free_liv_from_obj",}),"getannoyblock":({"GetAnnoyblock",}),"eventreceive":({"eventReceive",}),"setarmed":({"SetArmed",}),"direct_unwield_obj":({"direct_unwield_obj",}),"renter":({"rEnter",}),"send_text":({"send_text",}),"direct_untrain_liv_to_str":({"direct_untrain_liv_to_str",}),"setstaminapoints":({"SetStaminaPoints",}),"direct_pour_obj_out":({"direct_pour_obj_out",}),"getrequestresponses":({"GetRequestResponses",}),"initializelocations":({"InitializeLocations",}),"eventtalkrespond":({"eventTalkRespond",}),"direct_deactivate_str_on_obj":({"direct_deactivate_str_on_obj",}),"canfly":({"CanFly",}),"direct_pulsecheck_liv":({"direct_pulsecheck_liv",}),"direct_animate_obj":({"direct_animate_obj",}),"setowner":({"SetOwner",}),"eventjump":({"eventJump",}),"indirect_roll_obj_on_obj":({"indirect_roll_obj_on_obj",}),"getnobotcondition":({"GetNoBotCondition",}),"getinternaldesc":({"GetInternalDesc",}),"mudinfo":({"mudinfo",}),"setsearch":({"SetSearch",}),"getfingers":({"GetFingers",}),"gethistory":({"GetHistory",}),"_esc":({"_esc",}),"createvirtualobject":({"CreateVirtualObject",}),"eventtrainskill":({"eventTrainSkill",}),"getchanlist":({"GetChanList",}),"direct_delete_obj_from_room":({"direct_delete_obj_from_room",}),"addheartmodifier":({"AddHeartModifier",}),"direct_strike_obj":({"direct_strike_obj",}),"addskillpoints":({"AddSkillPoints",}),"getcount":({"GetCount",}),"getemptylong":({"GetEmptyLong",}),"getdirectionmap":({"GetDirectionMap",}),"getrecursedepth":({"GetRecurseDepth",}),"forget_user":({"forget_user",}),"geteverfill":({"GetEverFill",}),"collect_moduli":({"collect_moduli",}),"direct_cloak_wrd":({"direct_cloak_wrd",}),"setinternaldesc":({"SetInternalDesc",}),"direct_scratch_on_str_on_obj":({"direct_scratch_on_str_on_obj",}),"indirect_poison_obj_with_obj":({"indirect_poison_obj_with_obj",}),"setdying":({"SetDying",}),"getknock":({"GetKnock",}),"eventfly":({"eventFly",}),"foundtraps":({"FoundTraps",}),"getnightlong":({"GetNightLong",}),"removestat":({"RemoveStat",}),"getdisabled":({"GetDisabled",}),"eventturnon":({"eventTurnOn",}),"getnospells":({"GetNoSpells",}),"setterminal":({"SetTerminal",}),"setrecursedepth":({"SetRecurseDepth",}),"direct_attack_only_liv":({"direct_attack_only_liv",}),"direct_force_liv_to_str":({"direct_force_liv_to_str",}),"direct_ask_liv_for_str":({"direct_ask_liv_for_str",}),"gethealthshort":({"GetHealthShort",}),"indirect_bait_obj_with_obj":({"indirect_bait_obj_with_obj",}),"setweapontype":({"SetWeaponType",}),"setdoor":({"SetDoor",}),"direct_aim_obj_wrd_at_wrd":({"direct_aim_obj_wrd_at_wrd",}),"getsize":({"GetSize",}),"gettrainingmodifier":({"GetTrainingModifier",}),"setpermitload":({"SetPermitLoad",}),"setzpg":({"SetZPG",}),"setheat":({"SetHeat",}),"getnoclean":({"GetNoClean",}),"chan_who_in":({"chan_who_in",}),"getshadows":({"GetShadows",}),"eventstop":({"eventStop",}),"getunique":({"GetUnique",}),"direct_pick_str_on_obj_with_obj":({"direct_pick_str_on_obj_with_obj",}),"iscorpse":({"isCorpse",}),"setgermname":({"SetGermName",}),"eventconnect":({"eventConnect",}),"addtrainingskills":({"AddTrainingSkills",}),"getxverb":({"GetXverb",}),"setgender":({"SetGender",}),"getresistance":({"GetResistance",}),"cancastmagic":({"CanCastMagic",}),"indirect_look_at_obj_word_obj":({"indirect_look_at_obj_word_obj",}),"eventbuck":({"eventBuck",}),"direct_climb_obj":({"direct_climb_obj",}),"getpagerprompt":({"GetPagerPrompt",}),"addstatpoints":({"AddStatPoints",}),"echocommand":({"EchoCommand",}),"getsides":({"GetSides",}),"getvirtual":({"GetVirtual",}),"setwanderspeed":({"SetWanderSpeed",}),"canunlock":({"CanUnlock",}),"setworn":({"SetWorn",}),"getbank":({"GetBank",}),"removeshadow":({"RemoveShadow",}),"indirect_get_obj_out_of_obj":({"indirect_get_obj_out_of_obj",}),"doroll":({"doRoll",}),"gettempbuffer":({"GetTempbuffer",}),"eventshow":({"eventShow",}),"getbane":({"GetBane",}),"setspellchance":({"SetSpellChance",}),"setparty":({"SetParty",}),"destructemptyvirtual":({"DestructEmptyVirtual",}),"net_dead":({"net_dead",}),"eventbring":({"eventBring",}),"eventheartalk":({"eventHearTalk",}),"getrealname":({"GetRealName",}),"setemptyname":({"SetEmptyName",}),"canmarry":({"CanMarry",}),"getmaxmagicpoints":({"GetMaxMagicPoints",}),"getcedmode":({"GetCedmode",}),"direct_backlash_for_liv_against_wrd":({"direct_backlash_for_liv_against_wrd",}),"get_closed":({"get_closed",}),"getclimate":({"GetClimate",}),"getbankname":({"GetBankName",}),"getincombat":({"GetInCombat",}),"direct_fireball_at_liv":({"direct_fireball_at_liv",}),"setcankneel":({"SetCanKneel",}),"eventrequestcitizenship":({"eventRequestCitizenship",}),"direct_look_inside_obj":({"direct_look_inside_obj",}),"direct_deactivate_obj":({"direct_deactivate_obj",}),"continueheart":({"ContinueHeart",}),"indirect_show_obj_to_liv":({"indirect_show_obj_to_liv",}),"canlock":({"CanLock",}),"getcanclimbcarried":({"GetCanClimbCarried",}),"setspelltype":({"SetSpellType",}),"setmastermap":({"SetMasterMap",}),"resc":({"rEsc",}),"getuserpath":({"GetUserPath",}),"candigwith":({"CanDigWith",}),"cango":({"CanGo",}),"getquestid":({"GetQuestId",}),"addemoteresponse":({"AddEmoteResponse",}),"eventjoin":({"eventJoin",}),"getundead":({"GetUndead",}),"_file_end":({"_file_end",}),"getkeepalive":({"GetKeepalive",}),"getallowsacrifice":({"GetAllowSacrifice",}),"rascii":({"rAscii",}),"canunload":({"CanUnload",}),"indirect_put_obs_obj":({"indirect_put_obs_obj",}),"getcanbite":({"GetCanBite",}),"getcaffeine":({"GetCaffeine",}),"getexternaldesc":({"GetExternalDesc",}),"getpileamount":({"GetPileAmount",}),"_end":({"_end",}),"setmoney":({"SetMoney",}),"getmaxclones":({"GetMaxClones",}),"getroomaffectlong":({"GetRoomAffectLong",}),"getbodytype":({"GetBodyType",}),"direct_whisper_in_wrd_to_liv":({"direct_whisper_in_wrd_to_liv",}),"getwimpycommand":({"GetWimpyCommand",}),"indirect_get_obj_from_obj":({"indirect_get_obj_from_obj",}),"eventcheckprotection":({"eventCheckProtection",}),"setexternaldesc":({"SetExternalDesc",}),"getrestrictedchannels":({"GetRestrictedChannels",}),"getnomodify":({"GetNoModify",}),"eventwander":({"eventWander",}),"setbefriended":({"SetBefriended",}),"getdummyitem":({"GetDummyItem",}),"addexperiencedebt":({"AddExperienceDebt",}),"setammofile":({"SetAmmoFile",}),"_quit":({"_quit",}),"setwimpycommand":({"SetWimpyCommand",}),"addlead":({"AddLead",}),"direct_roll_obj_here":({"direct_roll_obj_here",}),"getmaxammo":({"GetMaxAmmo",}),"direct_wear_obj":({"direct_wear_obj",}),"getpoisongas":({"GetPoisonGas",}),"canload":({"CanLoad",}),"gettitle":({"GetTitle",}),"getpenalty":({"GetPenalty",}),"direct_gale_liv":({"direct_gale_liv",}),"addquest":({"AddQuest",}),"eventsell":({"eventSell",}),"abort_edit":({"abort_edit",}),"direct_activate_obj":({"direct_activate_obj",}),"eventteachplayer":({"eventTeachPlayer",}),"direct_uninstall_obj":({"direct_uninstall_obj",}),"setdestructondrop":({"SetDestructOnDrop",}),"setreligions":({"SetReligions",}),"addlisten":({"AddListen",}),"getcannotinfect":({"GetCannotInfect",}),"getreads":({"GetReads",}),"eventflushqueuedmessages":({"eventFlushQueuedMessages",}),"getspell":({"GetSpell",}),"setvisiblegrid":({"SetVisibleGrid",}),"getvoid":({"GetVoid",}),"canreceivehealing":({"CanReceiveHealing",}),"eventmarry":({"eventMarry",}),"setcannotinfect":({"SetCannotInfect",}),"getwanderpath":({"GetWanderPath",}),"eventopenaccount":({"eventOpenAccount",}),"getuniqueid":({"GetUniqueId",}),"direct_bury_str_with_obj":({"direct_bury_str_with_obj",}),"getgodmode":({"GetGodMode",}),"getnoobviousexits":({"GetNoObviousExits",}),"setpoison":({"SetPoison",}),"getbait":({"GetBait",}),"setterraintype":({"SetTerrainType",}),"setmaxfishing":({"SetMaxFishing",}),"eventswim":({"eventSwim",}),"getcaliber":({"GetCaliber",}),"setmatching":({"SetMatching",}),"cansacrifice":({"CanSacrifice",}),"gettraps":({"GetTraps",}),"getopenfee":({"GetOpenFee",}),"mudwho":({"mudwho",}),"setstats":({"SetStats",}),"addtrainingpoints":({"AddTrainingPoints",}),"eventpostrelease":({"eventPostRelease",}),"checkcollapse":({"checkCollapse",}),"geteffectivevision":({"GetEffectiveVision",}),"gettalkhistory":({"GetTalkHistory",}),"getdead":({"GetDead",}),"indirect_put_obj_obj":({"indirect_put_obj_obj",}),"getcommandnumber":({"GetCommandNumber",}),"setemptylong":({"SetEmptyLong",}),"indirect_show_obj_liv":({"indirect_show_obj_liv",}),"getlockable":({"GetLockable",}),"setfirearmtype":({"SetFirearmType",}),"getfueltype":({"GetFuelType",}),"setnightlong":({"SetNightLong",}),"settown":({"SetTown",}),"getfuelrequired":({"GetFuelRequired",}),"indirect_give_liv_obj":({"indirect_give_liv_obj",}),"getdummyitems":({"GetDummyItems",}),"addstuff":({"AddStuff",}),"setcancommand":({"SetCanCommand",}),"getstatlevel":({"GetStatLevel",}),"removehostile":({"RemoveHostile",}),"getpreventsteal":({"GetPreventSteal",}),"direct_ignore_liv":({"direct_ignore_liv",}),"eventroll":({"eventRoll",}),"direct_challenge_liv":({"direct_challenge_liv",}),"setfuelrequired":({"SetFuelRequired",}),"setsource":({"SetSource",}),"direct_swim_into_str":({"direct_swim_into_str",}),"setnonlocalfee":({"SetNonLocalFee",}),"getlistenmap":({"GetListenMap",}),"setpreventsteal":({"SetPreventSteal",}),"seteverfill":({"SetEverFill",}),"getnextlevel":({"GetNextLevel",}),"returnchannels":({"returnChannels",}),"eventhelp":({"eventHelp",}),"settrapdescription":({"SetTrapDescription",}),"getequippedshort":({"GetEquippedShort",}),"indirect_give_obs_to_liv":({"indirect_give_obs_to_liv",}),"canswivel":({"CanSwivel",}),"setbonusduration":({"SetBonusDuration",}),"setdisabled":({"SetDisabled",}),"setnospells":({"SetNoSpells",}),"eventpreview":({"eventPreview",}),"_next_match":({"_next_match",}),"removeteachinglanguages":({"RemoveTeachingLanguages",}),"allowget":({"AllowGet",}),"begin_post":({"begin_post",}),"direct_give_wrd_wrd_to_liv":({"direct_give_wrd_wrd_to_liv",}),"replace_nickname":({"replace_nickname",}),"setlong":({"SetLong",}),"query_post":({"query_post",}),"addquestcurrency":({"AddQuestCurrency",}),"channel_in":({"channel_in",}),"eventretrycommand":({"eventRetryCommand",}),"addstaminapoints":({"AddStaminaPoints",}),"direct_arrow_at_liv":({"direct_arrow_at_liv",}),"readbook":({"ReadBook",}),"ping_out":({"ping_out",}),"addbodymass":({"AddBodyMass",}),"getclan":({"GetClan",}),"direct_knock_on_str_on_obj":({"direct_knock_on_str_on_obj",}),"eventlay":({"eventLay",}),"getperforated":({"GetPerforated",}),"eventremoveitem":({"eventRemoveItem",}),"getexperiencepoints":({"GetExperiencePoints",}),"indirect_reload_every_str":({"indirect_reload_every_str",}),"eventfloat":({"eventFloat",}),"reset_prompt":({"reset_prompt",}),"direct_get_obj_obj":({"direct_get_obj_obj",}),"additem":({"AddItem",}),"getstaminacost":({"GetStaminaCost",}),"direct_climb_word_obj":({"direct_climb_word_obj",}),"eventmoveliving":({"eventMoveLiving",}),"getsavename":({"GetSaveName",}),"initcomposition":({"InitComposition",}),"_search":({"_search",}),"direct_holylight_liv":({"direct_holylight_liv",}),"unsetroom":({"UnSetRoom",}),"getwear":({"GetWear",}),"setlimb":({"SetLimb",}),"setnosink":({"SetNoSink",}),"getlastpuff":({"GetLastPuff",}),"eventdarken":({"eventDarken",}),"settitles":({"SetTitles",}),"setfingers":({"SetFingers",}),"getcarriedmass":({"GetCarriedMass",}),"zero":({"zero",}),"direct_shoot_obj_at_liv":({"direct_shoot_obj_at_liv",}),"query_cwd":({"query_cwd",}),"setrealname":({"SetRealName",}),"query_number_posts":({"query_number_posts",}),"setkeepalive":({"SetKeepalive",}),"getassets":({"GetAssets",}),"eventteachlanguage":({"eventTeachLanguage",}),"eventescape":({"eventEscape",}),"eventdestruct":({"eventDestruct",}),"getcombatbonus":({"GetCombatBonus",}),"direct_turn_obj_on":({"direct_turn_obj_on",}),"cmd_nickname":({"cmd_nickname",}),"setmaxclones":({"SetMaxClones",}),"setbankname":({"SetBankName",}),"getadjectives":({"GetAdjectives",}),"getencounter":({"GetEncounter",}),"direct_turn_off_obj":({"direct_turn_off_obj",}),"setcharge":({"SetCharge",}),"setuserpath":({"SetUserPath",}),"direct_roll_obj_on_obj":({"direct_roll_obj_on_obj",}),"_del_line":({"_del_line",}),"direct_fly_into_str":({"direct_fly_into_str",}),"addmuffed":({"AddMuffed",}),"setkey":({"SetKey",}),"eventcatch":({"eventCatch",}),"direct_portal_to_liv":({"direct_portal_to_liv",}),"getcurrencies":({"GetCurrencies",}),"direct_lock_obj_with_obj":({"direct_lock_obj_with_obj",}),"removeskill":({"RemoveSkill",}),"setnoclean":({"SetNoClean",}),"payment":({"Payment",}),"direct_swivel_str_on_obj":({"direct_swivel_str_on_obj",}),"getspeed":({"GetSpeed",}),"is_living":({"is_living",}),"setpoisongas":({"SetPoisonGas",}),"getdisablechance":({"GetDisableChance",}),"setplayerkill":({"SetPlayerKill",}),"direct_use_obj_to_str":({"direct_use_obj_to_str",}),"setbodytype":({"SetBodyType",}),"setemptyshort":({"SetEmptyShort",}),"getreligion":({"GetReligion",}),"getstrikechance":({"GetStrikeChance",}),"direct_createfix":({"direct_createfix",}),"direct_remedy_liv":({"direct_remedy_liv",}),"adddrink":({"AddDrink",}),"indirect_get_obs_from_obj":({"indirect_get_obs_from_obj",}),"setorigin":({"SetOrigin","setOrigin",}),"save_board":({"save_board",}),"setnomodify":({"SetNoModify",}),"getmaxsitters":({"GetMaxSitters",}),"eventreleaseobject":({"eventReleaseObject",}),"direct_annihilate_liv":({"direct_annihilate_liv",}),"setpistoltype":({"SetPistolType",}),"getextrachannels":({"GetExtraChannels",}),"removesearch":({"RemoveSearch",}),"direct_listen_to_str_word_obj":({"direct_listen_to_str_word_obj",}),"eventcomplete":({"eventComplete",}),"setdefaultlanguage":({"SetDefaultLanguage",}),"unloadall":({"UnloadAll",}),"setstrikechance":({"SetStrikeChance",}),"validate_paranoia":({"validate_paranoia",}),"dronecache":({"DroneCache",}),"getkeyname":({"GetKeyName",}),"validate_last_room":({"validate_last_room",}),"getzpg":({"GetZPG",}),"createdoor":({"CreateDoor",}),"removefollower":({"RemoveFollower",}),"getforced":({"GetForced",}),"cmdsearch":({"cmdSearch",}),"sortenemies":({"SortEnemies",}),"getburnrate":({"GetBurnRate",}),"getlead":({"GetLead",}),"direct_aura_liv":({"direct_aura_liv",}),"setcedmode":({"SetCedmode",}),"direct_cleanse_liv":({"direct_cleanse_liv",}),"canshoot":({"CanShoot",}),"heallimb":({"HealLimb",}),"getsmells":({"GetSmells",}),"setclimate":({"SetClimate",}),"removelimb":({"RemoveLimb",}),"switchlocations":({"SwitchLocations",}),"getweight":({"GetWeight",}),"removerider":({"RemoveRider",}),"direct_dismount_liv":({"direct_dismount_liv",}),"setexemptvirtual":({"SetExemptVirtual",}),"_tab":({"_tab",}),"addqueststatpoints":({"AddQuestStatPoints",}),"setquestid":({"SetQuestId",}),"getdeathevents":({"GetDeathEvents",}),"settax":({"SetTax",}),"showrounds":({"ShowRounds",}),"addcurrency":({"AddCurrency",}),"valid_edit":({"valid_edit",}),"direct_blades_at_liv":({"direct_blades_at_liv",}),"setpress":({"SetPress",}),"getretainondeath":({"GetRetainOnDeath",}),"removestatbonus":({"RemoveStatBonus",}),"direct_fly_word_str":({"direct_fly_word_str",}),"direct_cast_str_on_str_of_obj":({"direct_cast_str_on_str_of_obj",}),"eventreadfile":({"eventReadFile",}),"setcanbite":({"SetCanBite",}),"settrainedskills":({"SetTrainedSkills",}),"dgetsave":({"dGetSave",}),"eventdigwith":({"eventDigWith",}),"eventcompleteheal":({"eventCompleteHeal",}),"passengerprint":({"PassengerPrint",}),"getrange":({"GetRange",}),"getactionsenabled":({"GetActionsEnabled",}),"isbag":({"isBag",}),"eventtouch":({"eventTouch",}),"resetlocation":({"ResetLocation",}),"eventuninstall":({"eventUninstall",}),"canuntrain":({"CanUnTrain",}),"direct_show_obj_to_liv":({"direct_show_obj_to_liv",}),"getmaxhealthpoints":({"GetMaxHealthPoints",}),"eventfall":({"eventFall",}),"direct_convert_liv":({"direct_convert_liv",}),"indirect_delete_obj_from_here":({"indirect_delete_obj_from_here",}),"setautoresets":({"SetAutoResets",}),"getsearch":({"GetSearch",}),"setlockable":({"SetLockable",}),"getvoteroom":({"GetVoteRoom",}),"setfueltype":({"SetFuelType",}),"getverbs":({"GetVerbs",}),"getrank":({"GetRank",}),"setbodycomposition":({"SetBodyComposition",}),"eventride":({"eventRide",}),"getsmell":({"GetSmell",}),"eventdetect":({"eventDetect",}),"eventrock":({"eventRock",}),"setcoordinates":({"SetCoordinates",}),"candest":({"CanDest",}),"cmdshow":({"cmdShow",}),"setmaxammo":({"SetMaxAmmo",}),"connect":({"connect",}),"direct_turn_off_obj_on_obj":({"direct_turn_off_obj_on_obj",}),"eventlocklock":({"eventLockLock",}),"direct_crawl_into_str":({"direct_crawl_into_str",}),"eventexecuteattack":({"eventExecuteAttack",}),"getwieldinglimbs":({"GetWieldingLimbs",}),"setclanobject":({"SetClanObject",}),"getnetworth":({"GetNetWorth",}),"checkpower":({"CheckPower",}),"removetouch":({"RemoveTouch",}),"getmelee":({"GetMelee",}),"direct_mend_liv":({"direct_mend_liv",}),"setrequestresponses":({"SetRequestResponses",}),"getsavestring":({"GetSaveString",}),"addmagicprotection":({"AddMagicProtection",}),"heart_beat":({"heart_beat",}),"removeenemy":({"RemoveEnemy",}),"getitems":({"GetItems",}),"setspeakcolor":({"SetSpeakColor",}),"getcurrencymass":({"GetCurrencyMass",}),"direct_look_at_obj_on_obj":({"direct_look_at_obj_on_obj",}),"addfingers":({"AddFingers",}),"eventshoot":({"eventShoot",}),"direct_shoot_obj_at_obj":({"direct_shoot_obj_at_obj",}),"setgodmode":({"SetGodMode",}),"setpreventdrop":({"SetPreventDrop",}),"indirect_delete_obj_from_room":({"indirect_delete_obj_from_room",}),"cmd_unalias":({"cmd_unalias",}),"getgender":({"GetGender",}),"getlanguagepoints":({"GetLanguagePoints",}),"addhostile":({"AddHostile",}),"setcaliber":({"SetCaliber",}),"getneighbors":({"GetNeighbors",}),"indirect_dig_obj_with_obj":({"indirect_dig_obj_with_obj",}),"eventdeploy":({"eventDeploy",}),"getmaxliers":({"GetMaxLiers",}),"eventcheckhealing":({"eventCheckHealing",}),"setopenfee":({"SetOpenFee",}),"canspellattack":({"CanSpellAttack",}),"eventdrop":({"eventDrop",}),"getdefensechance":({"GetDefenseChance",}),"getfollowermap":({"GetFollowerMap",}),"direct_smell_str_word_obj":({"direct_smell_str_word_obj",}),"getaffectlong":({"GetAffectLong",}),"getlistens":({"GetListens",}),"eventcommand":({"eventCommand",}),"getemoteresponses":({"GetEmoteResponses",}),"eventreceiveobject":({"eventReceiveObject",}),"indirect_burn_obj_with_obj":({"indirect_burn_obj_with_obj",}),"eventdisconnect":({"eventDisconnect",}),"getrestrictlimbs":({"GetRestrictLimbs",}),"setprompt":({"SetPrompt",}),"springtrap":({"SpringTrap",}),"getblocked":({"GetBlocked",}),"eventcommandnpc":({"eventCommandNPC",}),"getitem":({"GetItem",}),"settrainingmodifier":({"SetTrainingModifier",}),"setencounter":({"SetEncounter",}),"send_is_alive":({"send_is_alive",}),"getcurrentenemy":({"GetCurrentEnemy",}),"setactionsmap":({"SetActionsMap",}),"addbonusduration":({"AddBonusDuration",}),"eventcast":({"eventCast",}),"addexit":({"AddExit",}),"getopacity":({"GetOpacity",}),"direct_throw_obj_word_obj":({"direct_throw_obj_word_obj",}),"recalculatehist":({"RecalculateHist",}),"removetrainingskills":({"RemoveTrainingSkills",}),"setcurrentenemy":({"SetCurrentEnemy",}),"getproperties":({"GetProperties",}),"direct_consult_str_on_obj":({"direct_consult_str_on_obj",}),"addcommandresponse":({"AddCommandResponse",}),"getsacrificetype":({"GetSacrificeType",}),"eventinitiate":({"eventInitiate",}),"eventresults":({"eventResults",}),"eventpicklock":({"eventPickLock",}),"direct_rock_obj":({"direct_rock_obj",}),"direct_unlock_obj_with_obj":({"direct_unlock_obj_with_obj",}),"eventprint":({"eventPrint",}),"terminal_type":({"terminal_type",}),"direct_show_obj_liv":({"direct_show_obj_liv",}),"direct_drink_str_from_obj":({"direct_drink_str_from_obj",}),"indirect_toss_obj_at_obj":({"indirect_toss_obj_at_obj",}),"direct_give_liv_obs":({"direct_give_liv_obs",}),"getexchangefee":({"GetExchangeFee",}),"getnews":({"GetNews",}),"direct_give_liv_obj":({"direct_give_liv_obj",}),"direct_disarm_obj":({"direct_disarm_obj",}),"direct_copy_obj_to_obj":({"direct_copy_obj_to_obj",}),"getaccountinfo":({"GetAccountInfo",}),"sendmeleemessages":({"SendMeleeMessages",}),"_dispatcher":({"_dispatcher",}),"getside":({"GetSide",}),"direct_turn_on_obj":({"direct_turn_on_obj",}),"direct_marry_liv_to_liv":({"direct_marry_liv_to_liv",}),"setreligion":({"SetReligion",}),"setscreen":({"SetScreen",}),"who_reply_in":({"who_reply_in",}),"setcount":({"SetCount",}),"page":({"Page",}),"eventunlock":({"eventUnlock",}),"eventbefriend":({"eventBefriend",}),"eventretire":({"eventRetire",}),"canfree":({"CanFree",}),"cansteal":({"CanSteal",}),"setknock":({"SetKnock",}),"restrict":({"restrict",}),"restoreobject":({"RestoreObject",}),"continue_mail":({"continue_mail",}),"setchamberinterior":({"SetChamberInterior",}),"allchans":({"allchans",}),"setlisten":({"SetListen",}),"evententer":({"eventEnter",}),"eventreceivelay":({"eventReceiveLay",}),"eventlist":({"eventList",}),"canunequip":({"CanUnequip",}),"eventexecutequeuedcommands":({"eventExecuteQueuedCommands",}),"setburnrate":({"SetBurnRate",}),"eventrequestdivorce":({"eventRequestDivorce",}),"direct_remedy_str_of_liv":({"direct_remedy_str_of_liv",}),"setvirtualexits":({"SetVirtualExits",}),"getteloptip":({"GetTeloptIp",}),"finger":({"finger",}),"gethealthpoints":({"GetHealthPoints",}),"getmaxcapture":({"GetMaxCapture",}),"resolveobjectname":({"ResolveObjectName",}),"getpoison":({"GetPoison",}),"getpull":({"GetPull",}),"eventblind":({"eventBlind",}),"direct_jump_word_word_obj":({"direct_jump_word_word_obj",}),"setcanfly":({"SetCanFly",}),"getprotect":({"GetProtect",}),"parsehook":({"ParseHook",}),"getundeadtype":({"GetUndeadType",}),"getequippeddescription":({"GetEquippedDescription",}),"getfurniture":({"GetFurniture",}),"sethealthpoints":({"SetHealthPoints",}),"removerequestresponse":({"RemoveRequestResponse",}),"getlogintime":({"GetLoginTime",}),"setteachingfee":({"SetTeachingFee",}),"setclient":({"SetClient",}),"getdaylong":({"GetDayLong",}),"getrequiredstamina":({"GetRequiredStamina",}),"getconsultresponses":({"GetConsultResponses",}),"eventwimpy":({"eventWimpy",}),"getgridmap":({"GetGridMap",}),"getrandomlimb":({"GetRandomLimb",}),"getlanguagelevel":({"GetLanguageLevel",}),"getfollowed":({"GetFollowed",}),"shb":({"shb",}),"removeenter":({"RemoveEnter",}),"beep_in":({"beep_in",}),"unrestrictchannel":({"UnrestrictChannel",}),"eventunload":({"eventUnload",}),"direct_rock_wrd_obj":({"direct_rock_wrd_obj",}),"addverb":({"AddVerb",}),"eventreceiveemote":({"eventReceiveEmote",}),"isplayer":({"isPlayer",}),"restrictchannel":({"RestrictChannel",}),"direct_backlash_for_liv":({"direct_backlash_for_liv",}),"getrespirationtype":({"GetRespirationType",}),"setaction":({"SetAction",}),"sethistorysize":({"SetHistorySize",}),"cmddebugall":({"cmdDebugAll",}),"getpoisonuses":({"GetPoisonUses",}),"gettraplevel":({"GetTrapLevel",}),"direct_drink_obj":({"direct_drink_obj",}),"canrepair":({"CanRepair",}),"indirect_reload":({"indirect_reload",}),"direct_dig_str_with_obj":({"direct_dig_str_with_obj",}),"removelocation":({"RemoveLocation",}),"direct_teleport_to_liv":({"direct_teleport_to_liv",}),"getsource":({"GetSource",}),"direct_fill_obj_with_obj":({"direct_fill_obj_with_obj",}),"indirect_pour_from_obj_into_obj":({"indirect_pour_from_obj_into_obj",}),"direct_palm_liv":({"direct_palm_liv",}),"getsitters":({"GetSitters",}),"setkeyname":({"SetKeyName",}),"getmorality":({"GetMorality",}),"addfollowbonus":({"AddFollowBonus",}),"direct_reload":({"direct_reload",}),"direct_whisper_to_liv_str":({"direct_whisper_to_liv_str",}),"keepalive":({"keepalive",}),"eventsteal":({"eventSteal",}),"addvisionbonus":({"AddVisionBonus",}),"direct_dest_obj":({"direct_dest_obj",}),"removetrainingpoints":({"RemoveTrainingPoints",}),"getmaxskillpoints":({"GetMaxSkillPoints",}),"direct_evade_liv":({"direct_evade_liv",}),"setinfect":({"SetInfect",}),"setfish":({"SetFish",}),"getmissinglimbparents":({"GetMissingLimbParents",}),"canbuy":({"CanBuy",}),"eventspreadpoison":({"eventSpreadPoison",}),"getpk":({"GetPK",}),"_confirm_save":({"_confirm_save",}),"escape":({"escape",}),"price":({"price",}),"getremotetargets":({"GetRemoteTargets",}),"_insert_exclam_mark":({"_insert_exclam_mark",}),"getvehicleinterior":({"GetVehicleInterior",}),"getpromptstring":({"GetPromptString",}),"gettalesdir":({"GetTalesDir",}),"getfight":({"GetFight",}),"direct_frigidus_liv":({"direct_frigidus_liv",}),"parsepost":({"ParsePost",}),"_left":({"_left",}),"direct_capture_liv_word_obj":({"direct_capture_liv_word_obj",}),"direct_fill_obj_from_obj":({"direct_fill_obj_from_obj",}),"direct_listen_obj":({"direct_listen_obj",}),"direct_initfix_obj":({"direct_initfix_obj",}),"getcoords":({"GetCoords",}),"eventbuy":({"eventBuy",}),"eventweaponround":({"eventWeaponRound",}),"getrace":({"GetRace",}),"direct_cast_obj":({"direct_cast_obj",}),"setmaxliers":({"SetMaxLiers",}),"gethostiles":({"GetHostiles",}),"eventburnout":({"eventBurnOut",}),"setcomposition":({"SetComposition",}),"eventextinguish":({"eventExtinguish",}),"getlimbclass":({"GetLimbClass",}),"setmaxrecursedepth":({"SetMaxRecurseDepth",}),"getdaylight":({"GetDayLight",}),"getcapname":({"GetCapName",}),"direct_pour_from_obj_into_obj":({"direct_pour_from_obj_into_obj",}),"eventdeviatestat":({"eventDeviateStat",}),"eventstartvoting":({"eventStartVoting",}),"setmaxcommandhistsize":({"SetMaxCommandHistSize",}),"getbaitstrength":({"GetBaitStrength",}),"setpoisonstrength":({"SetPoisonStrength",}),"getnosink":({"GetNoSink",}),"indirect_burn_obs_with_obj":({"indirect_burn_obs_with_obj",}),"direct_jump_word_obj":({"direct_jump_word_obj",}),"direct_say_to_liv_str":({"direct_say_to_liv_str",}),"getremotemudinfo":({"getremotemudinfo",}),"canreceivemagic":({"CanReceiveMagic",}),"settitle":({"SetTitle",}),"gettitles":({"GetTitles",}),"getbasefile":({"GetBaseFile",}),"gethistorylist":({"GetHistoryList",}),"getgravity":({"GetGravity",}),"getstatsmap":({"GetStatsMap",}),"marriagerequest":({"MarriageRequest",}),"direct_corrupt_liv":({"direct_corrupt_liv",}),"getnoncurrencymass":({"GetNonCurrencyMass",}),"setreads":({"SetReads",}),"setmagnum":({"SetMagnum",}),"addsurcharge":({"AddSurcharge",}),"setbaitstrength":({"SetBaitStrength",}),"direct_light_obj":({"direct_light_obj",}),"setspell":({"SetSpell",}),"addskillbonus":({"AddSkillBonus",}),"setdefaultexits":({"SetDefaultExits",}),"gettax":({"GetTax",}),"set_board_id":({"set_board_id",}),"getenemies":({"GetEnemies",}),"eventweaponattack":({"eventWeaponAttack",}),"addterraintype":({"AddTerrainType",}),"gettraptype":({"GetTrapType",}),"sethiddendoor":({"SetHiddenDoor",}),"direct_force_liv_str":({"direct_force_liv_str",}),"direct_drain_liv":({"direct_drain_liv",}),"eventreceiveattack":({"eventReceiveAttack",}),"direct_delete_obj_from_obj":({"direct_delete_obj_from_obj",}),"direct_touch_str_word_obj":({"direct_touch_str_word_obj",}),"getcharge":({"GetCharge",}),"direct_createfix_obj":({"direct_createfix_obj",}),"getexit":({"GetExit",}),"eventtrainliving":({"eventTrainLiving",}),"eventmagicround":({"eventMagicRound",}),"canbank":({"CanBank",}),"eventswivel":({"eventSwivel",}),"setmuffed":({"SetMuffed",}),"getquest":({"GetQuest",}),"setfood":({"SetFood",}),"indirect_give_obs_liv":({"indirect_give_obs_liv",}),"getmaxcommandhistsize":({"GetMaxCommandHistSize",}),"direct_compare_obj_to_obj":({"direct_compare_obj_to_obj",}),"getbuttonid":({"GetButtonId",}),"canweapon":({"CanWeapon",}),"direct_reload_obj":({"direct_reload_obj",}),"getkeys":({"GetKeys",}),"removefish":({"RemoveFish",}),"eventturn":({"eventTurn",}),"direct_install_obj_word_obj":({"direct_install_obj_word_obj",}),"canabandon":({"CanAbandon",}),"direct_gaze":({"direct_gaze",}),"getraceadverb":({"GetRaceAdverb",}),"getorigin":({"GetOrigin","getOrigin",}),"getghost":({"GetGhost",}),"direct_fly":({"direct_fly",}),"getrequestresponse":({"GetRequestResponse",}),"getprotection":({"GetProtection",}),"direct_search_str_word_obj":({"direct_search_str_word_obj",}),"getstudents":({"GetStudents",}),"canmail":({"CanMail",}),"cmdparserefresh":({"cmdParseRefresh",}),"getbasecost":({"GetBaseCost",}),"setnoecho":({"SetNoEcho",}),"setblocked":({"SetBlocked",}),"getheartrate":({"GetHeartRate",}),"getbury":({"GetBury",}),"eventmovefollowers":({"eventMoveFollowers",}),"indirect_throw_obj_into_obj":({"indirect_throw_obj_into_obj",}),"parse_command_plural_id_list":({"parse_command_plural_id_list",}),"getsurroundareas":({"GetSurroundAreas",}),"setmountowner":({"SetMountOwner",}),"direct_pour_obj_into_obj":({"direct_pour_obj_into_obj",}),"indirect_add_obj":({"indirect_add_obj",}),"direct_acidspray_liv":({"direct_acidspray_liv",}),"indirect_put_obj_word_obj":({"indirect_put_obj_word_obj",}),"setopacity":({"SetOpacity",}),"clean_str":({"clean_str",}),"eventcontinue":({"eventContinue",}),"_write_done":({"_write_done",}),"indirect_add_obj_to_here":({"indirect_add_obj_to_here",}),"direct_rejuvinate_liv":({"direct_rejuvinate_liv",}),"getbriefmode":({"GetBriefMode",}),"setrespiration":({"SetRespiration",}),"eventsave":({"eventSave",}),"indirect_turn_off_obj_on_obj":({"indirect_turn_off_obj_on_obj",}),"cmdtouch":({"cmdTouch",}),"setteloptip":({"SetTeloptIp",}),"setdisablechance":({"SetDisableChance",}),"cmd_read":({"cmd_read",}),"indirect_drink_from_obj":({"indirect_drink_from_obj",}),"setlivingshort":({"SetLivingShort",}),"eventgo":({"eventGo",}),"getspecialmenuitems":({"GetSpecialMenuItems",}),"settraplevel":({"SetTrapLevel",}),"direct_swim_str":({"direct_swim_str",}),"indirect_give_obj_liv":({"indirect_give_obj_liv",}),"eventpreattack":({"eventPreAttack",}),"addsearchpath":({"AddSearchPath",}),"setextrachannels":({"SetExtraChannels",}),"direct_swivel_obj":({"direct_swivel_obj",}),"direct_learn_str_from_liv":({"direct_learn_str_from_liv",}),"ceditcollate":({"CeditCollate",}),"setfollowed":({"SetFollowed",}),"eventunshadow":({"eventUnshadow",}),"main_help":({"main_help",}),"addtalkresponse":({"AddTalkResponse",}),"getid":({"GetId",}),"getclimateexposed":({"GetClimateExposed",}),"getflaskuses":({"GetFlaskUses",}),"checkguardeds":({"CheckGuardeds",}),"getpick":({"GetPick",}),"canputonto":({"CanPutOnto",}),"direct_lie_word_obj":({"direct_lie_word_obj",}),"cmd_eventdestruct":({"cmd_eventDestruct",}),"removespecialmenuitem":({"RemoveSpecialMenuItem",}),"checkactions":({"CheckActions",}),"pingmud":({"pingmud",}),"eventgetmoney":({"eventGetMoney",}),"indirect_add_obj_to_room":({"indirect_add_obj_to_room",}),"_home":({"_home",}),"setfirearmname":({"SetFirearmName",}),"getverb":({"GetVerb",}),"canbait":({"CanBait",}),"addmenuitem":({"AddMenuItem",}),"eventmeleeround":({"eventMeleeRound",}),"getpolyglot":({"GetPolyglot",}),"indirect_judge_obj_to_obj":({"indirect_judge_obj_to_obj",}),"direct_bite_liv":({"direct_bite_liv",}),"direct_wear_obj_on_str":({"direct_wear_obj_on_str",}),"gethb":({"GetHB",}),"getopen":({"GetOpen",}),"eventnegotiateobstacles":({"eventNegotiateObstacles",}),"addjump":({"AddJump",}),"indirect_get_obs_out_of_obj":({"indirect_get_obs_out_of_obj",}),"direct_dig_with_obj":({"direct_dig_with_obj",}),"setmorality":({"SetMorality",}),"getcommercial":({"GetCommercial",}),"direct_bump_liv":({"direct_bump_liv",}),"direct_wizlock_obj":({"direct_wizlock_obj",}),"indirect_sell_obj_to_liv":({"indirect_sell_obj_to_liv",}),"direct_swivel_wrd_obj":({"direct_swivel_wrd_obj",}),"cmd_edit":({"cmd_edit",}),"getmarriages":({"GetMarriages",}),"expertise":({"Expertise",}),"addskill":({"AddSkill",}),"command":({"command",}),"canfillother":({"CanFillOther",}),"gettrainedskilles":({"GetTrainedSkilles",}),"process_input":({"process_input",}),"setretainondeath":({"SetRetainOnDeath",}),"user_names":({"user_names",}),"addpressure":({"AddPressure",}),"_process":({"_process",}),"indirect_zap_liv":({"indirect_zap_liv",}),"eventreleasestand":({"eventReleaseStand",}),"setclimb":({"SetClimb",}),"rarrow":({"rArrow",}),"getmillimeter":({"GetMillimeter",}),"getmaxstaminapoints":({"GetMaxStaminaPoints",}),"setprotect":({"SetProtect",}),"setspeed":({"SetSpeed",}),"getwhereblock":({"GetWhereBlock",}),"continuetraining":({"ContinueTraining",}),"direct_turn_obj_on_obj_off":({"direct_turn_obj_on_obj_off",}),"eventunequip":({"eventUnequip",}),"settalesdir":({"SetTalesDir",}),"setretain":({"SetRetain",}),"indirect_unlock_obj_with_obj":({"indirect_unlock_obj_with_obj",}),"getshake":({"GetShake",}),"getskilllevel":({"GetSkillLevel",}),"setdaylong":({"SetDayLong",}),"getcommandhist":({"GetCommandHist",}),"removenontargets":({"RemoveNonTargets",}),"setcanswim":({"SetCanSwim",}),"setdifficulty":({"SetDifficulty",}),"getcustomxp":({"GetCustomXP",}),"direct_touch_obj":({"direct_touch_obj",}),"mark_read":({"mark_read",}),"indirect_lock_obj_with_obj":({"indirect_lock_obj_with_obj",}),"getnontargets":({"GetNonTargets",}),"getdoorstopped":({"GetDoorStopped",}),"getpreventland":({"GetPreventLand",}),"removeconsultresponse":({"RemoveConsultResponse",}),"getprompt":({"GetPrompt",}),"regetid":({"regetID",}),"getdeviating":({"GetDeviating",}),"continue_post":({"continue_post",}),"getemotes":({"GetEmotes",}),"getlasterror":({"GetLastError",}),"getalias":({"GetAlias",}),"setdaylight":({"SetDayLight",}),"getemail":({"GetEmail",}),"setcure":({"SetCure",}),"setcanbefriend":({"SetCanBefriend",}),"getshadowedname":({"GetShadowedName",}),"cansmoke":({"CanSmoke",}),"getcharbuffer":({"GetCharbuffer",}),"setbasefile":({"SetBaseFile",}),"receive_message":({"receive_message",}),"addproperty":({"AddProperty",}),"setlightlevel":({"SetLightLevel",}),"getknocks":({"GetKnocks",}),"removelisten":({"RemoveListen",}),"setread":({"SetRead",}),"who_out":({"who_out",}),"direct_pull_str_on_obj":({"direct_pull_str_on_obj",}),"getdrink":({"GetDrink",}),"setmass":({"SetMass",}),"gettitlelength":({"GetTitleLength",}),"addrider":({"AddRider",}),"getskillsmap":({"GetSkillsMap",}),"cmdlisten":({"cmdListen",}),"getcouncil":({"GetCouncil",}),"getanchored":({"GetAnchored",}),"getlocalfee":({"GetLocalFee",}),"settraptype":({"SetTrapType",}),"direct_load_obj":({"direct_load_obj",}),"eventhistory":({"eventHistory",}),"eventlock":({"eventLock",}),"getlanguagename":({"GetLanguageName",}),"eventencounterblock":({"eventEncounterBlock",}),"canwear":({"CanWear",}),"write_callback":({"write_callback",}),"direct_follow_liv":({"direct_follow_liv",}),"tell":({"tell",}),"setcanclimbcarried":({"SetCanClimbCarried",}),"addpoisongas":({"AddPoisonGas",}),"eventradiate":({"eventRadiate",}),"setrestrictlimbs":({"SetRestrictLimbs",}),"setrange":({"SetRange",}),"cmdenter":({"cmdEnter",}),"setbuttonid":({"SetButtonId",}),"getsavefile":({"GetSaveFile",}),"getscreen":({"GetScreen",}),"setsmell":({"SetSmell",}),"setmanipulate":({"SetManipulate",}),"getweapontype":({"GetWeaponType",}),"getdestructondrop":({"GetDestructOnDrop",}),"getencumbrance":({"GetEncumbrance",}),"calculateammosize":({"CalculateAmmoSize",}),"getpermitload":({"GetPermitLoad",}),"setcapname":({"SetCapName",}),"setbriefmode":({"SetBriefMode",}),"picktale":({"PickTale",}),"direct_offer_obj":({"direct_offer_obj",}),"getlisten":({"GetListen",}),"setsacrificetype":({"SetSacrificeType",}),"mustcarry":({"MustCarry",}),"getcurrencymap":({"GetCurrencyMap",}),"addtouch":({"AddTouch",}),"setbasecost":({"SetBaseCost",}),"getpacifist":({"GetPacifist",}),"setgravity":({"SetGravity",}),"direct_turn_liv":({"direct_turn_liv",}),"getvisibleriders":({"GetVisibleRiders",}),"getlightsensitivity":({"GetLightSensitivity",}),"cmd_cd":({"cmd_cd",}),"addenemy":({"AddEnemy",}),"direct_install_obj":({"direct_install_obj",}),"eventload":({"eventLoad",}),"eventparse":({"eventParse",}),"chan_perm_desc":({"chan_perm_desc",}),"getmissinglimbs":({"GetMissingLimbs",}),"eventsmoke":({"eventSmoke",}),"setmelee":({"SetMelee",}),"getelevator":({"GetElevator",}),"setitems":({"SetItems",}),"request_vis":({"request_vis",}),"getlevel":({"GetLevel",}),"direct_mount_liv":({"direct_mount_liv",}),"indirect_put_obs_word_obj":({"indirect_put_obs_word_obj",}),"resetcurrentenemy":({"ResetCurrentEnemy",}),"getammo":({"GetAmmo",}),"setmissinglimbs":({"SetMissingLimbs",}),"gettype":({"GetType",}),"getmaxcells":({"GetMaxCells",}),"setflaskuses":({"SetFlaskUses",}),"getdoorsmap":({"GetDoorsMap",}),"continue_followup":({"continue_followup",}),"direct_deactivate_obj_on_obj":({"direct_deactivate_obj_on_obj",}),"getclient":({"GetClient",}),"removeread":({"RemoveRead",}),"addhp":({"AddHP",}),"canuninstall":({"CanUninstall",}),"eventreconnect":({"eventReconnect",}),"getwield":({"GetWield",}),"getconsult":({"GetConsult",}),"direct_buy_str_from_liv":({"direct_buy_str_from_liv",}),"setsky":({"SetSky",}),"getambientlight":({"GetAmbientLight",}),"query_board_id":({"query_board_id",}),"eventreceivedamage":({"eventReceiveDamage",}),"direct_knock_obj":({"direct_knock_obj",}),"setleader":({"SetLeader",}),"create":({"create",}),"remove_post":({"remove_post",}),"getaction":({"GetAction",}),"addround":({"AddRound",}),"canlead":({"CanLead",}),"direct_train_liv":({"direct_train_liv",}),"setambientlight":({"SetAmbientLight",}),"direct_connect_str":({"direct_connect_str",}),"canturnoff":({"CanTurnOff",}),"direct_request_str_from_liv":({"direct_request_str_from_liv",}),"direct_eat_obj":({"direct_eat_obj",}),"getfalling":({"GetFalling",}),"start_edit":({"start_edit",}),"getshade":({"GetShade",}),"direct_load_obj_word_obj":({"direct_load_obj_word_obj",}),"getexitmap":({"GetExitMap",}),"getmode":({"GetMode",}),"getconsultresponse":({"GetConsultResponse",}),"eventcheckenvironment":({"eventCheckEnvironment",}),"setfuelname":({"SetFuelName",}),"setpolyglot":({"SetPolyglot",}),"setconsultresponses":({"SetConsultResponses",}),"eventabandon":({"eventAbandon",}),"addrule":({"AddRule",}),"getduration":({"GetDuration",}),"getinfect":({"GetInfect",}),"eventcollapse":({"eventCollapse",}),"isfreshcorpse":({"isFreshCorpse",}),"eventendvoting":({"eventEndVoting",}),"newbody":({"NewBody",}),"getdoors":({"GetDoors",}),"getbefriended":({"GetBefriended",}),"init":({"init",}),"getmount":({"GetMount",}),"_keymap":({"_keymap",}),"erase_prompt":({"erase_prompt",}),"getmissdata":({"GetMissData",}),"removemuffed":({"RemoveMuffed",}),"getexitdata":({"GetExitData",}),"close_callback":({"close_callback",}),"addextrachannels":({"AddExtraChannels",}),"setdeviating":({"SetDeviating",}),"removeterraintype":({"RemoveTerrainType",}),"eventputon":({"eventPutOn",}),"indirect_delete_obj_from_obj":({"indirect_delete_obj_from_obj",}),"setlasterror":({"SetLastError",}),"setvendortype":({"SetVendorType",}),"direct_light_obj_with_obj":({"direct_light_obj_with_obj",}),"cantarget":({"CanTarget",}),"direct_command_str_to_str":({"direct_command_str_to_str",}),"isdummy":({"isDummy",}),"eventbalance":({"eventBalance",}),"push":({"Push",}),"getclasses":({"GetClasses",}),"setwander":({"SetWander",}),"direct_press_obj":({"direct_press_obj",}),"unescape":({"unescape",}),"eventfish":({"eventFish",}),"restore_board":({"restore_board",}),"direct_scratch_obj":({"direct_scratch_obj",}),"eventunlocklock":({"eventUnlockLock",}),"sethboverride":({"SetHBOverride",}),"setsize":({"SetSize",}),"indirect_compare_obj_to_obj":({"indirect_compare_obj_to_obj",}),"checkpending":({"CheckPending",}),"canlight":({"CanLight",}),"setcustomxp":({"SetCustomXP",}),"direct_add_obj_to_here":({"direct_add_obj_to_here",}),"direct_listen_to_obj":({"direct_listen_to_obj",}),"restore_inventory":({"restore_inventory",}),"getreversedirection":({"GetReverseDirection",}),"getwanderspeed":({"GetWanderSpeed",}),"setmountstyle":({"SetMountStyle",}),"indirect_give_obj_to_liv":({"indirect_give_obj_to_liv",}),"getvirtualsky":({"GetVirtualSky",}),"getmaxfishing":({"GetMaxFishing",}),"addencounter":({"AddEncounter",}),"eventstart":({"eventStart",}),"setdig":({"SetDig",}),"setdie":({"SetDie",}),"getmagnum":({"GetMagnum",}),"caneat":({"CanEat",}),"getnotalemessage":({"GetNoTaleMessage",}),"getspellchance":({"GetSpellChance",}),"eventfire":({"eventFire",}),"setguard":({"SetGuard",}),"indirect_reload_str_word":({"indirect_reload_str_word",}),"indirect_boobytrap_obj_with_obj":({"indirect_boobytrap_obj_with_obj",}),"indirect_throw_obj_at_obj":({"indirect_throw_obj_at_obj",}),"getdefiniteshort":({"GetDefiniteShort",}),"indirect_reload_obj":({"indirect_reload_obj",}),"getlimbchildren":({"GetLimbChildren",}),"setbroken":({"SetBroken",}),"eventrepair":({"eventRepair",}),"indirect_uninstall_obj_word_obj":({"indirect_uninstall_obj_word_obj",}),"getmanipulates":({"GetManipulates",}),"getstatclass":({"GetStatClass",}),"setremotetargets":({"SetRemoteTargets",}),"indirect_capture_liv_word_obj":({"indirect_capture_liv_word_obj",}),"setcommandfail":({"SetCommandFail",}),"setbane":({"SetBane",}),"eventputonto":({"eventPutOnto",}),"eventrunout":({"eventRunOut",}),"cmdbrowse":({"cmdBrowse",}),"getmaxclass":({"GetMaxClass",}),"canstand":({"CanStand",}),"setclosed":({"SetClosed",}),"getcombatverbs":({"GetCombatVerbs",}),"direct_aim_obj_with_obj":({"direct_aim_obj_with_obj",}),"direct_modify_word_str":({"direct_modify_word_str",}),"eventeat":({"eventEat",}),"getmutedtype":({"GetMutedType",}),"direct_backstab_liv":({"direct_backstab_liv",}),"getmuffed":({"GetMuffed",}),"direct_give_obj_liv":({"direct_give_obj_liv",}),"addenter":({"AddEnter",}),"getfollowbonus":({"GetFollowBonus",}),"eventexchange":({"eventExchange",}),"eventremovecandidate":({"eventRemoveCandidate",}),"setanchored":({"SetAnchored",}),"setlocalfee":({"SetLocalFee",}),"getminheat":({"GetMinHeat",}),"direct_turn_obj":({"direct_turn_obj",}),"direct_add_obj_to_room":({"direct_add_obj_to_room",}),"getvisionbonus":({"GetVisionBonus",}),"eventencounter":({"eventEncounter",}),"getequippedlimbs":({"GetEquippedLimbs",}),"eventrevive":({"eventRevive",}),"gettale":({"GetTale",}),"setpreventput":({"SetPreventPut",}),"direct_drink_from_obj":({"direct_drink_from_obj",}),"getlanguages":({"GetLanguages",}),"getareatype":({"GetAreaType",}),"getskydomain":({"GetSkyDomain",}),"eventrefuel":({"eventRefuel",}),"direct_sell_obj_to_liv":({"direct_sell_obj_to_liv",}),"setnodefaultexits":({"SetNoDefaultExits",}),"mudlist":({"mudlist",}),"direct_boobytrap_obj_with_obj":({"direct_boobytrap_obj_with_obj",}),"cmdprice":({"cmdPrice",}),"setsavefile":({"SetSaveFile",}),"popd":({"popd",}),"getammotype":({"GetAmmoType",}),"direct_uninstall_obj_word_obj":({"direct_uninstall_obj_word_obj",}),"getalcohol":({"GetAlcohol",}),"cmddial":({"cmdDial",}),"getnoecho":({"GetNoEcho",}),"_insert":({"_insert",}),"direct_say_to_liv":({"direct_say_to_liv",}),"getmaxprotection":({"GetMaxProtection",}),"eventlight":({"eventLight",}),"loadrevolver":({"LoadRevolver",}),"canmanipulate":({"CanManipulate",}),"gettorso":({"GetTorso",}),"eventburyitem":({"eventBuryItem",}),"canpress":({"CanPress",}),"direct_drain_at_liv":({"direct_drain_at_liv",}),"eventdeteriorate":({"eventDeteriorate",}),"eventmoralact":({"eventMoralAct",}),"setpacifist":({"SetPacifist",}),"eventcustomizestat":({"eventCustomizeStat",}),"getvalue":({"GetValue",}),"eventdescribeenvironment":({"eventDescribeEnvironment",}),"setfuelamount":({"SetFuelAmount",}),"indirect_fill_obj_with_obj":({"indirect_fill_obj_with_obj",}),"direct_move_str_on_obj":({"direct_move_str_on_obj",}),"indirect_install_obj_word_obj":({"indirect_install_obj_word_obj",}),"getmaxload":({"GetMaxLoad",}),"getvisiblegrid":({"GetVisibleGrid",}),"setelevator":({"SetElevator",}),"gethostsite":({"GetHostSite",}),"setfight":({"SetFight",}),"eventstand":({"eventStand",}),"generatenames":({"GenerateNames",}),"addstat":({"AddStat",}),"getroom":({"GetRoom",}),"getterraintype":({"GetTerrainType",}),"removeconsult":({"RemoveConsult",}),"setmaxcells":({"SetMaxCells",}),"eventdisplaystatus":({"eventDisplayStatus",}),"resetlevel":({"ResetLevel",}),"_backspace":({"_backspace",}),"canteach":({"CanTeach",}),"direct_teach_liv_to_str":({"direct_teach_liv_to_str",}),"direct_shake_obj":({"direct_shake_obj",}),"gettargets":({"GetTargets",}),"getbaselimbs":({"GetBaseLimbs",}),"getflyroom":({"GetFlyRoom",}),"query_sp":({"query_sp",}),"direct_target_liv":({"direct_target_liv",}),"setbait":({"SetBait",}),"setnativelanguage":({"SetNativeLanguage",}),"performmarriage":({"performMarriage",}),"indirect_turn_obj_on_obj_off":({"indirect_turn_obj_on_obj_off",}),"indirect_fill_obj_from_obj":({"indirect_fill_obj_from_obj",}),"resetcurrency":({"ResetCurrency",}),"addsacrificetype":({"AddSacrificeType",}),"direct_unload_obj_word_obj":({"direct_unload_obj_word_obj",}),"getfirearmtype":({"GetFirearmType",}),"_goto_line":({"_goto_line",}),"eventbreak":({"eventBreak",}),"setsurroundareas":({"SetSurroundAreas",}),"getparalyzed":({"GetParalyzed",}),"getliers":({"GetLiers",}),"getcustomstats":({"GetCustomStats",}),"do_nickname":({"do_nickname",}),"canpull":({"CanPull",}),"setdead":({"SetDead",}),"eventfill":({"eventFill",}),"direct_missile_at_liv":({"direct_missile_at_liv",}),"direct_knock_on_obj":({"direct_knock_on_obj",}),"getpresses":({"GetPresses",}),"setspecialmenuitems":({"SetSpecialMenuItems",}),"chanwho_out":({"chanwho_out",}),"getautostand":({"GetAutoStand",}),"setmaxhealthpoints":({"SetMaxHealthPoints",}),"getlockstrength":({"GetLockStrength",}),"subtractround":({"SubtractRound",}),"setquestpoints":({"SetQuestPoints",}),"_message_done":({"_message_done",}),"getmudinfo":({"getmudinfo",}),"eventunquell":({"eventUnQuell",}),"getvirtualsea":({"GetVirtualSea",}),"getdestroyonsell":({"GetDestroyOnSell",}),"eventdecreasefuel":({"eventDecreaseFuel",}),"getnochancolors":({"GetNoChanColors",}),"getplayerkill":({"GetPlayerKill",}),"direct_turn_on_obj_on_obj":({"direct_turn_on_obj_on_obj",}),"getnonlocalfee":({"GetNonLocalFee",}),"getemptyshort":({"GetEmptyShort",}),"setduration":({"SetDuration",}),"setnocondition":({"SetNoCondition",}),"direct_target_liv_only":({"direct_target_liv_only",}),"setlockstrength":({"SetLockStrength",}),"setchance":({"SetChance",}),"eventpress":({"eventPress",}),"setmag":({"SetMag",}),"direct_learn_to_str_from_liv":({"direct_learn_to_str_from_liv",}),"setnochancolors":({"SetNoChanColors",}),"rdel":({"rDel",}),"_refresh_status":({"_refresh_status",}),"chan_perm_allowed":({"chan_perm_allowed",}),"direct_aim_liv_with_obj":({"direct_aim_liv_with_obj",}),"eventdisarm":({"eventDisarm",}),"addcommandresponses":({"AddCommandResponses",}),"getownerob":({"GetOwnerOb",}),"getretain":({"GetRetain",}),"loadbook":({"LoadBook",}),"direct_curse_obj":({"direct_curse_obj",}),"setup":({"Setup",}),"canburywith":({"CanBuryWith",}),"indirect_get_obs_obj":({"indirect_get_obs_obj",}),"direct_fireball_liv":({"direct_fireball_liv",}),"getfullexitdata":({"GetFullExitData",}),"setattackable":({"SetAttackable",}),"getinventory":({"GetInventory",}),"canpoison":({"CanPoison",}),"setdefaultread":({"SetDefaultRead",}),"getlocations":({"GetLocations",}),"get_path":({"get_path",}),"setconsult":({"SetConsult",}),"eventshowinterior":({"eventShowInterior",}),"getmaxskilllevel":({"GetMaxSkillLevel",}),"gethelp":({"GetHelp",}),"eventtrainspell":({"eventTrainSpell",}),"eventteach":({"eventTeach",}),"getequipped":({"GetEquipped",}),"getnonexits":({"GetNonExits",}),"setdenominator":({"SetDenominator",}),"removepress":({"RemovePress",}),"setcruiseinmessage":({"SetCruiseInMessage",}),"setclan":({"SetClan",}),"direct_add_obj":({"direct_add_obj",}),"getmodify":({"GetModify",}),"direct_bury_obj_with_obj":({"direct_bury_obj_with_obj",}),"getrules":({"GetRules",}),"removelanguage":({"RemoveLanguage",}),"getemptyitem":({"GetEmptyItem",}),"canfollow":({"CanFollow",}),"doautounload":({"doAutoUnload",}),"direct_send_str_to_str":({"direct_send_str_to_str",}),"direct_frigidus_at_liv":({"direct_frigidus_at_liv",}),"getscratch":({"GetScratch",}),"getrequiredmagic":({"GetRequiredMagic",}),"minusammo":({"MinusAmmo",}),"restart_heart":({"restart_heart",}),"plusammo":({"PlusAmmo",}),"setfalling":({"SetFalling",}),"eventloadinventory":({"eventLoadInventory",}),"getlifespan":({"GetLifeSpan",}),"setmaxstaminapoints":({"SetMaxStaminaPoints",}),"eventregisterside":({"eventRegisterSide",}),"eventbless":({"eventBless",}),"direct_shield_liv":({"direct_shield_liv",}),"eventcastvote":({"eventCastVote",}),"canputinto":({"CanPutInto",}),"statreport":({"StatReport",}),"getsky":({"GetSky",}),"setwear":({"SetWear",}),"eventshadow":({"eventShadow",}),"setcruiseoutmessage":({"SetCruiseOutMessage",}),"eventturnoff":({"eventTurnOff",}),"getgaggedtype":({"GetGaggedType",}),"getlocalcurrency":({"GetLocalCurrency",}),"eventdeposit":({"eventDeposit",}),"eventcure":({"eventCure",}),"removebonuses":({"RemoveBonuses",}),"do_alias":({"do_alias",}),"getautoresets":({"GetAutoResets",}),"setskydomain":({"SetSkyDomain",}),"setattack":({"SetAttack",}),"indirect_pour_obj_into_obj":({"indirect_pour_obj_into_obj",}),"getlogharass":({"GetLogHarass",}),"indirect_aim_obj_at_liv":({"indirect_aim_obj_at_liv",}),"cache_commands":({"cache_commands",}),"direct_command_liv":({"direct_command_liv",}),"eventread":({"eventRead",}),"eventwelcome":({"eventWelcome",}),"canknock":({"CanKnock",}),"getcanlock":({"GetCanLock",}),"getmagicresistance":({"GetMagicResistance",}),"pinkfish_to_imc2":({"pinkfish_to_imc2",}),"eventcruisemessages":({"eventCruiseMessages",}),"getmaptype":({"GetMapType",}),"getskillmodifier":({"GetSkillModifier",}),"setautodamage":({"SetAutoDamage",}),"direct_dismount_from_liv":({"direct_dismount_from_liv",}),"direct_climb_out_of_obj":({"direct_climb_out_of_obj",}),"continueteaching":({"ContinueTeaching",}),"_replace_done":({"_replace_done",}),"indirect_get_obj_obj":({"indirect_get_obj_obj",}),"indirect_add_obj_to_obj":({"indirect_add_obj_to_obj",}),"cmdparse":({"cmdParse",}),"query_mp":({"query_mp",}),"getclanobject":({"GetClanObject",}),"receivecanonicalid":({"ReceiveCanonicalId",}),"getstatbonus":({"GetStatBonus",}),"direct_get_wrd_wrd_out_of_obj":({"direct_get_wrd_wrd_out_of_obj",}),"setclasses":({"SetClasses",}),"setrarity":({"SetRarity",}),"getcharmode":({"GetCharmode",}),"_page_down":({"_page_down",}),"cmd_post":({"cmd_post",}),"receive_snoop":({"receive_snoop",}),"getpersistentinventory":({"GetPersistentInventory",}),"more":({"more",}),"getspeakcolor":({"GetSpeakColor",}),"reset":({"reset",}),"setstorageroom":({"SetStorageRoom",}),"classmember":({"ClassMember",}),"eventsendmissmessages":({"eventSendMissMessages",}),"setcorpse":({"SetCorpse",}),"setammotype":({"SetAmmoType",}),"addcaffeine":({"AddCaffeine",}),"eventannouncecanonicalid":({"eventAnnounceCanonicalId",}),"donetrying":({"DoneTrying",}),"resetbank":({"ResetBank",}),"direct_soulseek_liv":({"direct_soulseek_liv",}),"getautoheal":({"GetAutoHeal",}),"eventpage":({"eventPage",}),"eventfree":({"eventFree",}),"basemap":({"BaseMap",}),"getenabled":({"GetEnabled",}),"getexits":({"GetExits",}),"canrelease":({"CanRelease",}),"direct_zap_liv":({"direct_zap_liv",}),"getfrequency":({"GetFrequency",}),"razzledazzle":({"RazzleDazzle",}),"spent":({"Spent",}),"caninstall":({"CanInstall",}),"setpk":({"SetPK",}),"removetalkresponse":({"RemoveTalkResponse",}),"eventedit":({"eventEdit",}),"getjumps":({"GetJumps",}),"getchaninfo":({"GetChanInfo",}),"setbaselimbs":({"SetBaseLimbs",}),"gettrainingskills":({"GetTrainingSkills",}),"inventory_visible":({"inventory_visible",}),"direct_roll_obj":({"direct_roll_obj",}),"getlastsave":({"GetLastSave",}),"setrefuelable":({"SetRefuelable",}),"ransi":({"rAnsi",}),"getcreatorage":({"GetCreatorAge",}),"status":({"status",}),"direct_give_obj_to_liv":({"direct_give_obj_to_liv",}),"getbasestatlevel":({"GetBaseStatLevel",}),"gettalkresponse":({"GetTalkResponse",}),"setbonuses":({"SetBonuses",}),"getwizvision":({"GetWizVision",}),"setshake":({"SetShake",}),"readbookindex":({"ReadBookIndex",}),"setminheat":({"SetMinHeat",}),"displayshort":({"displayShort",}),"setparalyzed":({"SetParalyzed",}),"direct_reload_str_word":({"direct_reload_str_word",}),"getdig":({"GetDig",}),"getactionsmap":({"GetActionsMap",}),"getdie":({"GetDie",}),"geteventprints":({"GeteventPrints",}),"direct_drop_obj":({"direct_drop_obj",}),"eventpreparecast":({"eventPrepareCast",}),"setnightlight":({"SetNightLight",}),"getgrid":({"GetGrid",}),"direct_get_obj_from_obj":({"direct_get_obj_from_obj",}),"getleader":({"GetLeader",}),"send_ice_refresh":({"send_ice_refresh",}),"setlightsensitivity":({"SetLightSensitivity",}),"getskill":({"GetSkill",}),"direct_turn_obj_off":({"direct_turn_obj_off",}),"getwanderrecurse":({"GetWanderRecurse",}),"eventknock":({"eventKnock",}),"setautostand":({"SetAutoStand",}),"removeemoteresponse":({"RemoveEmoteResponse",}),"indirect_reload_word_obj":({"indirect_reload_word_obj",}),"getstat":({"GetStat",}),"indirect_light_obj_with_obj":({"indirect_light_obj_with_obj",}),"direct_drive_word_str":({"direct_drive_word_str",}),"canburn":({"CanBurn",}),"getprotectionmap":({"GetProtectionMap",}),"direct_delete_obj":({"direct_delete_obj",}),"eventtalkhist":({"eventTalkHist",}),"setrequiredstamina":({"SetRequiredStamina",}),"setemail":({"SetEmail",}),"setvisibleriders":({"SetVisibleRiders",}),"evaluatecitizenshiprequest":({"EvaluateCitizenshipRequest",}),"indirect_dest_obj":({"indirect_dest_obj",}),"getrechargeable":({"GetRechargeable",}),"cmd_popd":({"cmd_popd",}),"getpulls":({"GetPulls",}),"direct_cast_str_against_str":({"direct_cast_str_against_str",}),"setpersistent":({"SetPersistent",}),"setrechargeable":({"SetRechargeable",}),"getobviousexits":({"GetObviousExits",}),"direct_refresh_liv":({"direct_refresh_liv",}),"direct_open_obj":({"direct_open_obj",}),"setrespirationtype":({"SetRespirationType",}),"getcoordinates":({"GetCoordinates",}),"_append_line":({"_append_line",}),"eventchangeimc2passwords":({"eventChangeIMC2Passwords",}),"getcelltype":({"GetCellType",}),"_page_up":({"_page_up",}),"process_request":({"process_request",}),"removeknock":({"RemoveKnock",}),"setrank":({"SetRank",}),"setobviousexits":({"SetObviousExits",}),"getmissinglimb":({"GetMissingLimb",}),"canput":({"CanPut",}),"setmagicpoints":({"SetMagicPoints",}),"setinventory":({"SetInventory",}),"_refresh":({"_refresh",}),"getmoralitydescription":({"GetMoralityDescription",}),"getage":({"GetAge",}),"direct_rock_str_on_obj":({"direct_rock_str_on_obj",}),"canpick":({"CanPick",}),"direct_press_str_on_obj":({"direct_press_str_on_obj",}),"query_hp":({"query_hp",}),"setmaxload":({"SetMaxLoad",}),"canrequestcitizenship":({"CanRequestCitizenship",}),"direct_shake_str_on_obj":({"direct_shake_str_on_obj",}),"setburntvalue":({"SetBurntValue",}),"direct_heal_liv":({"direct_heal_liv",}),"canthrow":({"CanThrow",}),"cancapture":({"CanCapture",}),"write_prompt":({"write_prompt",}),"setemptyitem":({"SetEmptyItem",}),"getpreventdrop":({"GetPreventDrop",}),"checkcharmode":({"CheckCharmode",}),"eventput":({"eventPut",}),"getpoisonstrength":({"GetPoisonStrength",}),"getexperiencedebt":({"GetExperienceDebt",}),"eventrestore":({"eventRestore",}),"canopen":({"CanOpen",}),"setvehicleinterior":({"SetVehicleInterior",}),"indirect_aim_obj_at_obj":({"indirect_aim_obj_at_obj",}),"eventqueuecommand":({"eventQueueCommand",}),"canclose":({"CanClose",}),"direct_pray_for_str_against_str_for_liv":({"direct_pray_for_str_against_str_for_liv",}),"setflyroom":({"SetFlyRoom",}),"getcommands":({"GetCommands",}),"chat_command":({"chat_command",}),"changelevel":({"ChangeLevel",}),"tell_out":({"tell_out",}),"removescratch":({"RemoveScratch",}),"direct_activate_str_on_obj":({"direct_activate_str_on_obj",}),"updatescreen":({"UpdateScreen",}),"getbroken":({"GetBroken",}),"setlogharass":({"SetLogHarass",}),"direct_teach_str_to_liv":({"direct_teach_str_to_liv",}),"_undef_key":({"_undef_key",}),"resetsurroundexits":({"ResetSurroundExits",}),"getshort":({"GetShort",}),"direct_get_obj":({"direct_get_obj",}),"direct_attack_liv":({"direct_attack_liv",}),"getclosed":({"GetClosed",}),"setlifespan":({"SetLifeSpan",}),"direct_ask_liv_to_str":({"direct_ask_liv_to_str",}),"getdeaths":({"GetDeaths",}),"setlevel":({"SetLevel",}),"eventdestroyenemy":({"eventDestroyEnemy",}),"direct_lie_down_word_obj":({"direct_lie_down_word_obj",}),"cangetfrom":({"CanGetFrom",}),"setpreventget":({"SetPreventGet",}),"direct_target_only_liv":({"direct_target_only_liv",}),"getextralong":({"GetExtraLong",}),"getalllanguages":({"GetAllLanguages",}),"limbguess":({"LimbGuess",}),"getdoor":({"GetDoor",}),"eventwithdraw":({"eventWithdraw",}),"getcombatmove":({"GetCombatMove",}),"getlanguage":({"GetLanguage",}),"find_mud":({"find_mud",}),"getbodymass":({"GetBodyMass",}),"gettrainingpoints":({"GetTrainingPoints",}),"getheat":({"GetHeat",}),"direct_whisper_to_liv":({"direct_whisper_to_liv",}),"gettouch":({"GetTouch",}),"indirect_shoot_obj_at_liv":({"indirect_shoot_obj_at_liv",}),"setalllanguages":({"SetAllLanguages",}),"setwield":({"SetWield",}),"eventpausemessages":({"eventPauseMessages",}),"add_post":({"add_post",}),"cmdquit":({"cmdQuit",}),"getmobility":({"GetMobility",}),"direct_reload_every_str":({"direct_reload_every_str",}),"allowpass":({"AllowPass",}),"addmoney":({"AddMoney",}),"getcandidates":({"GetCandidates",}),"addlimb":({"AddLimb",}),"query_prev_wd":({"query_prev_wd",}),"setownerob":({"SetOwnerOb",}),"getsinkroom":({"GetSinkRoom",}),"direct_pick_str_on_obj":({"direct_pick_str_on_obj",}),"direct_fly_str":({"direct_fly_str",}),"setid":({"SetId",}),"direct_smell_obj":({"direct_smell_obj",}),"setnotalemessage":({"SetNoTaleMessage",}),"dorevolverunload":({"doRevolverUnload",}),"getworn":({"GetWorn",}),"valid_access":({"valid_access",}),"getmessage":({"GetMessage",}),"eventthrow":({"eventThrow",}),"direct_climb_word":({"direct_climb_word",}),"getlive":({"GetLive",}),"getdebugging":({"GetDebugging",}),"gettalkresponses":({"GetTalkResponses",}),"eventmultiply":({"eventMultiply",}),"getquests":({"GetQuests",}),"getenterdata":({"GetEnterData",}),"setcharmode":({"SetCharmode",}),"setfrequency":({"SetFrequency",}),"eventask":({"eventAsk",}),"setshade":({"SetShade",}),"getdeities":({"GetDeities",}),"setdamagetype":({"SetDamageType",}),"getnoreplace":({"GetNoReplace",}),"setnews":({"SetNews",}),"getmag":({"GetMag",}),"eventclose":({"eventClose",}),"cancarry":({"CanCarry",}),"canevade":({"CanEvade",}),"direct_balance_obj_to_obj":({"direct_balance_obj_to_obj",}),"direct_roll_obj_on_str":({"direct_roll_obj_on_str",}),"setlivinglong":({"SetLivingLong",}),"removefishing":({"RemoveFishing",}),"eventmail":({"eventMail",}),"getplayerpaused":({"GetPlayerPaused",}),"getsearches":({"GetSearches",}),"sethb":({"SetHB",}),"gettalkhisttypes":({"GetTalkHistTypes",}),"indirect_unload_obj_word_obj":({"indirect_unload_obj_word_obj",}),"getmaxfuel":({"GetMaxFuel",}),"direct_lock_obj_with_str":({"direct_lock_obj_with_str",}),"setscratch":({"SetScratch",}),"setautoheal":({"SetAutoHeal",}),"setfloors":({"SetFloors",}),"setside":({"SetSide",}),"setcanstand":({"SetCanStand",}),"removetitle":({"RemoveTitle",}),"setwizvision":({"SetWizVision",}),"indirect_load_obj_word_obj":({"indirect_load_obj_word_obj",}),"_join":({"_join",}),"direct_wield_obj":({"direct_wield_obj",}),"setplayerpaused":({"SetPlayerPaused",}),"setmount":({"SetMount",}),"destruct":({"Destruct",}),"displaylong":({"displayLong",}),"gettellhistory":({"GetTellHistory",}),"setground":({"SetGround",}),"eventsearch":({"eventSearch",}),"setannoyblock":({"SetAnnoyblock",}),"eventdrain":({"eventDrain",}),"cmdall":({"cmdAll",}),"query_max_sp":({"query_max_sp",}),"interbeep":({"interbeep",}),"indirect_turn_on_obj_on_obj":({"indirect_turn_on_obj_on_obj",}),"getitemsmap":({"GetItemsMap",}),"addalcohol":({"AddAlcohol",}),"getcommunicable":({"GetCommunicable",}),"eventextraaction":({"eventExtraAction",}),"query_posts":({"query_posts",}),]) +TmpMap ([]) diff --git a/lib/secure/save/imc2.o b/lib/secure/save/imc2.o new file mode 100644 index 0000000..2aae385 --- /dev/null +++ b/lib/secure/save/imc2.o @@ -0,0 +1,16 @@ +#/secure/daemon/imc2.c +PersistentInventory 0 +PersistentInventoryEnabled 0 +tmpstr 0 +host "50.34.196.5" +who_str "Zebu *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* [ARCH][ELDER]: First Admin Babylon%^RESET%^%^RESET%^ (idle) *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* There is one member of our reality. http://dead-souls.net telnet://50.34.196.5:6666 ___________________________________________________________________________" +mode 2 +autodisabled 0 +ping_requests ([]) +buf "" +server_version 0 +localchaninfo ([]) +mudinfo ([]) +genders ([]) +tells ([]) +sequence 0 diff --git a/lib/secure/save/inet.o b/lib/secure/save/inet.o new file mode 100644 index 0000000..c47118d --- /dev/null +++ b/lib/secure/save/inet.o @@ -0,0 +1,3 @@ +#/secure/daemon/inet.c +Services (["oob":(/6,"/secure/lib/net/oob",0,/),"ftp":(/-1,"/secure/lib/net/ftp",1,/),"hftp":(/-6,"/secure/lib/net/h_ftpd",1,/),"http":(/1,"/secure/lib/net/http",3,/),]) +BlockedIps ([]) diff --git a/lib/secure/save/mailqueue.o b/lib/secure/save/mailqueue.o new file mode 100644 index 0000000..e72fa87 --- /dev/null +++ b/lib/secure/save/mailqueue.o @@ -0,0 +1,4 @@ +#/secure/daemon/remotepost.c +__MailQueue ([]) +Old ([]) +Outgoing ([]) diff --git a/lib/secure/save/mudinfo.o b/lib/secure/save/mudinfo.o new file mode 100644 index 0000000..f446808 --- /dev/null +++ b/lib/secure/save/mudinfo.o @@ -0,0 +1,6 @@ +#/secure/daemon/mudinfo.c +MudList (["DW_Clone":({-1,"82.68.167.68",4242,8765,0,"Discworld 18.0a","DW_Clone","FluffOS v2.28","LPMud","Development","none",(["channel":1,"ftp":4444,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"emoteto":1,"http":80,]),0,}),"Dead_Souls_ptar":({0,"184.152.167.105",6666,6672,6674,"Dead Souls 3.8.6","Dead Souls 3.8.6","FluffOS v2.23-ds03w","LPMud","mudlib development","admin@here",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6672,"emoteto":1,"http":6667,]),(["upsince":"Sun Aug 30 09:28:26 2020","ip":"127.0.0.1","architecture":"Microsoft Windows NT","next boot":"EST Mon Jan 26 18:28:26 2032","os build":"windows","native version":"3.8.6","oob port":6672,]),}),"Darkscapes":({-1,"84.245.8.150",6717,6723,6725,"Dead Souls 3.6","Dead Souls 3.6","FluffOS v2.23-ds01","LPMud","mudlib development","mark@oliekoets.nl",(["channel":1,"mail":1,"ftp":6716,"tell":1,"finger":1,"who":1,"auth":1,"oob":6723,"locate":1,"emoteto":1,"http":6718,]),(["upsince":"Thu Aug 27 10:33:18 2020","ip":"127.0.0.1","next boot":"CET Thu Sep 3 13:33:18 2020","architecture":"Linux","os build":"unix","oob port":6723,"native version":"3.6",]),}),"Muda":({-1,"86.110.43.195",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","root.juur@gmail.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Archipelago":({-1,"88.97.75.68",8000,8006,0,"Discworld 15.0a","Discworld","FluffOS v2.28.3-ARCH","LPMud","open for players","archipelago@the-firebird.net",(["channel":1,"ftp":8002,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"emoteto":1,"http":8004,]),0,}),"LostCraft Reborn":({0,"185.150.190.20",6666,6672,6674,"Dead Souls 3.8.6","Dead Souls 3.8.6","FluffOS v2.23-ds03","LPMud","mudlib development","lostcraftreborn@gmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6672,"emoteto":1,"http":6667,]),(["upsince":"Thu Apr 2 11:05:18 2020","ip":"127.0.0.1","architecture":"Linux","next boot":"EST Fri Aug 29 21:05:18 2031","os build":"unix","native version":"3.8.6","oob port":6672,]),}),"Morkin23":({-1,"86.61.249.216",6666,6672,6674,"Dead Souls 3.8.6","Dead Souls 3.8.6","FluffOS v2.23-ds03","LPMud","mudlib development","marek.jan.cz@gmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6672,"emoteto":1,"http":6667,]),(["upsince":"Wed Sep 2 08:58:05 2020","ip":"127.0.0.1","architecture":"Linux","next boot":"EST Thu Jan 29 17:58:05 2032","os build":"unix","native version":"3.8.6","oob port":6672,]),}),"The Zone-wpr":({-1,"136.144.155.250",8888,8891,8890,"WOTFlib 0.90","LPMud","DGD 1.4.1","LPMud","beta testing","aidil@wotf.org",(["channel":1,"ftp":21,"tell":1,"who":1,"locate":1,"http":8887,]),(["notice":1,"wotf-mail":1,"beep":1,]),}),"Navigate":({-1,"216.136.9.5",2123,2129,2131,"Dead Souls 3.8.6","Dead Souls 3.8.6","FluffOS v2.23-ds03","LPMud","mudlib development","karp1248@gmail.com",(["channel":1,"mail":1,"ftp":2122,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":2129,"emoteto":1,"http":2124,]),(["upsince":"Sat Feb 15 21:57:05 2020","ip":"127.0.0.1","architecture":"Linux","next boot":"EST Mon Jul 14 08:57:05 2031","os build":"unix","native version":"3.8.6","oob port":2129,]),}),"Dead_Souls_greatland":({0,"76.185.16.182",6666,6672,6674,"Dead Souls 3.8.2","Dead Souls 3.8.2","FluffOS v2.23-ds03w","LPMud","mudlib development","greatland@rocketmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6672,"emoteto":1,"http":6667,]),(["upsince":"Tue Sep 01 14:04:54 2020","ip":"127.0.0.1","architecture":"Microsoft Windows NT","next boot":"EST Wed Jan 28 23:04:54 2032","os build":"windows","native version":"3.8.2","oob port":6672,]),}),"Nanvaent":({-1,"207.162.200.121",3000,3001,0,"Nanvaent V.4ish","Nanvaent","NANVAENT 3 (FluffOS v2.18)","LP","open for public","admin@nanvaent.org",(["channel":1,"ftp":4001,"tell":1,"finger":1,"who":1,"auth":1,"locate":1,"ucache":1,"emoteto":1,"file":1,"http":80,]),0,}),"Dark City":({-1,"178.79.173.99",3000,0,0,"Dark City","Merc","AFKMud I3 Driver 2.33","GodWars","Open","tijer@godwars.net",(["finger":1,"who":1,"channel":1,"locate":1,"tell":1,"ucache":1,"emoteto":1,]),(["time":"Thu Aug 27 20:20:01 2020","url":"http://www.godwars.net",]),}),"Avalon":({0,"91.215.74.15",7777,7600,4246,"Avalon","Unitopia","LDMud 3.5.0","LP","open for public","admins@avalon.mud.de",(["channel":1,"mail":1,"tell":1,"finger":1,"who":1,"auth":1,"locate":1,"emoteto":1,"http":80,]),(["url":"http://avalon.mud.de","banner":" +-------------------------------------------------------------------------+ | _____ .__ avalon.intersolute.de (91.215.74.15) 7777 | | / _ \\___ _______ | | ____ ____ LDMud 3.5.0 NATIVE | | / /_\\ \\ \\/ /\\__ \\ | | / _ \\ / \\ http://avalon.mud.de/ | | / | \\ / / __ \\| |_( <_> ) | \\ | | \\____|__ /\\_/ (____ /____/\\____/|___| / | | \\/ \\/ \\/ | +-------------------------------------------------------------------------+ ",]),}),"GTFO":({-1,"138.68.247.72",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Pocket Steam":({-1,"192.81.133.184",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","marisag@pocketmud.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Paradigm MUD":({-1,"45.79.73.28",5555,0,0,"CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud","Beta Testing","alisonclower@gmail.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"The Zone-i4":({-1,"136.144.155.250",8888,8891,8890,"WOTFlib 0.90","LPMud","DGD 1.4.1","LPMud","beta testing","aidil@wotf.org",(["channel":1,"ftp":21,"tell":1,"who":1,"locate":1,"http":8887,]),(["notice":1,"wotf-mail":1,"beep":1,]),}),"Nostalgia":({0,"82.11.250.100",5555,5558,0,"Tmi-2 1.4","Tmi-2 1.4","FluffOS v2.16-ds05w","LPmud","Mudlib Development","Unknown",(["channel":1,"ftp":5554,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"channel-0505":1,"http":5550,]),0,}),"Cyprus MUD":({-1,"173.255.218.223",5555,0,0,"CoffeeMud v5.9.9.1","CoffeeMud v5.9.9.1","CoffeeMud v5.9.9.1","CoffeeMud","Restricted Access","jescat27@live.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"AgeOfHeroes":({-1,"46.32.38.32",2345,0,2347,"AoH 0.5-0","AoH","LDMud 3.6.3 (3.6.3)","LPMud","Mudlib Development","ralph@zitz.dk",(["channel":1,"mail":1,"tell":1,"finger":1,"who":1,"auth":1,"locate":1,"ucache":1,"emoteto":1,]),(["url":"http://aoh.zitz.dk","banner":"",]),}),"SirdudesGurbaLib":({-1,"174.53.232.12",4000,4002,4003,"GurbaLib v0.50","GurbaLib","DGD 1.6.13","LPMud","Mudlib Development","mein@umn.edu",(["who":1,"auth":1,"channel":1,"locate":1,"ftp":4001,"tell":1,]),([]),}),"PLEXUS":({-1,"86.52.128.42",4242,4243,0,"Lima/PLX 0.4","Lima","fluffos v2019.2020050101","LP","game development","tsath@shadowlord.org",(["channel":1,"mail":1,"ftp":21,"tell":1,"finger":1,"who":1,"auth":1,"locate":1,"emoteto":1,"ucache":1,"file":1,"http":80,]),0,}),"Frontiers":({-1,"204.209.44.3",8000,8006,8008,"Dead Souls 2.10","Dead Souls 2.10","FluffOS v2.15-ds05","LPMud","mudlib development","cratylus@comcast.net",(["channel":1,"mail":1,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":8005,"emoteto":1,]),(["upsince":"Sun Aug 30 06:54:01 2020","ip":"127.0.0.1","architecture":"Linux","next boot":"EDT Sun Sep 6 08:54:01 2020","os build":"unix","native version":"2.9a17","oob port":8006,]),}),"Final Realms":({-1,"185.47.42.101",4001,0,0,"FRlib V","Final Realms","FluffOS v2.23","LPMud","open to players","mudadm@fr.hyssing.net",(["channel":1,"ftp":0,"tell":1,"nntp":0,"finger":1,"who":1,"http":0,"smtp":4021,]),0,}),"Waterver_Dev":({0,"71.246.228.190",6666,0,0,"Tim's LPC IMC2 client 30-Jan-05 / Dead Souls integrated","Tim's LPC IMC2 client 30-Jan-05 / Dead Souls integrated","IMC2 client","n/a"," "," ",(["who":1,"channel":1,"tell":1,]),(["port":6666,"url":"http://dead-souls.net","versionid":"Tim's LPC IMC2 client 30-Jan-05 / Dead Souls integrated","host":"71.246.228.190","imc_version":2.000000,]),}),"FR:Development":({0,"185.47.42.101",4002,0,0,"FRlib V","Final Realms","FluffOS v2.28.3","LPMud","closed for players","mudadm@fr.hyssing.net",(["channel":1,"ftp":0,"tell":1,"nntp":0,"finger":1,"who":1,"http":0,"smtp":4021,]),0,}),"UberMud":({-1,"54.202.46.66",5555,0,0,"CoffeeMud v5.9.8","CoffeeMud v5.9.8","CoffeeMud v5.9.8","CoffeeMud","Restricted Access","wbfredrickson@yahoo.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"CoffeeMud":({-1,"104.14.28.106",2323,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Open to the public","zac@coffeemud.net",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Ukiyo":({-1,"212.56.108.81",5555,0,0,"CoffeeMud v5.9.8","CoffeeMud v5.9.8","CoffeeMud v5.9.8","CoffeeMud","Restricted Access","ukiyo@passiverpg.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"BlackDawn":({-1,"45.64.56.66",1701,1706,1709,"BlackDawn II ","DeadSouls 1.1pre","FluffOS v2.28.3","LPMud","Mudlib Development","adam@themud.org",(["channel":1,"ftp":1700,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"emoteto":1,"rcp":1691,"http":1696,]),([]),}),"Portals Inbetween":({-1,"45.33.50.126",5555,0,0,"CoffeeMud v5.9.9.1","CoffeeMud v5.9.9.1","CoffeeMud v5.9.9.1","CoffeeMud","Beta Testing","info@portals.pocketmud.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"ShadowMUDii Dev":({-1,"199.74.141.8",1035,1044,1043,"Nightmare/ShadowLib 3.2.2/0.5","Nightmare/ShadowLib 3.2.2/0.5","FluffOS v2.28.2","LP","beta testing","shadowmudii@hotmail.com",(["finger":1,"who":1,"channel":1,"locate":1,"tell":1,"emoteto":1,]),([]),}),"Testlandia":({-1,"54.88.224.206",6767,6773,6775,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03","LPMud","mudlib development","raven@raven-nc.net",(["channel":1,"mail":1,"ftp":6766,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6773,"emoteto":1,"http":6768,]),(["upsince":"Sun Jun 28 00:00:11 2020","ip":"127.0.0.1","architecture":"Linux","next boot":"EDT Mon Nov 24 14:00:11 2031","os build":"unix","native version":"3.9","oob port":6773,]),}),"Nygaard MUD":({-1,"172.105.9.226",5555,0,0,"CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud","Beta Testing","info@nygaard.pocketmud.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"GreyArea":({-1,"115.166.18.220",2222,2228,2230,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03","LPMud","mudlib development","mordain23@gmail.com",(["channel":1,"mail":1,"ftp":2221,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":2228,"emoteto":1,"http":2223,]),(["upsince":"Tue Sep 1 16:03:53 2020","ip":"127.0.0.1","architecture":"Linux","next boot":"EST Thu Jan 29 03:03:53 2032","os build":"unix","native version":"3.9","oob port":2228,]),}),"Senitan Online":({-1,"71.72.126.17",6666,6672,6674,"Dead Souls 3.8.6","Dead Souls 3.8.6","FluffOS v2.23-ds03","LPMud","mudlib development","rt3388@gmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6672,"emoteto":1,"http":6667,]),(["upsince":"Thu Aug 20 19:19:04 2020","ip":"127.0.0.1","architecture":"Linux","next boot":"EST Sat Jan 17 04:19:04 2032","os build":"unix","native version":"3.8.6","oob port":6672,]),}),"Firefly Sea":({0,"99.99.67.238",7878,7879,0,"Lima 1.0b5","Lima","FluffOS v2.15-ds03w","LP","game development","user@host.name",(["channel":1,"mail":1,"ftp":21,"tell":1,"finger":1,"who":1,"auth":1,"locate":1,"emoteto":1,"ucache":1,"file":1,"http":80,]),0,}),"Planstudio Dungeons":({-1,"80.210.98.67",5555,0,0,"CoffeeMud v5.9.5","CoffeeMud v5.9.5","CoffeeMud v5.9.5","CoffeeMud","Beta Testing","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"FOR_NOW":({-1,"24.19.149.119",5555,0,0,"CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud","Beta Testing","jackvaguely@gmail.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Dead_Souls_maldrin":({0,"72.183.47.232",6666,6672,6674,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03w","LPMud","mudlib development","admin@here",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6672,"emoteto":1,"http":6667,]),(["upsince":"Tue Sep 01 01:06:55 2020","ip":"127.0.0.1","architecture":"Microsoft Windows NT","next boot":"EST Wed Jan 28 10:06:55 2032","os build":"windows","native version":"3.9","oob port":6672,]),}),"Your Muds Name Here":({0,"75.70.133.45",5555,0,0,"CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud","Beta Testing","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Wunderland":({-1,"139.18.11.86",23,4246,4246,"WL-Lib","WL-Lib","LDMud 3.3.720","LPMud","open for public","mud@wl.mud.de",(["channel":1,"mail":1,"ftp":4713,"tell":1,"finger":1,"who":1,"auth":1,"locate":1,"emoteto":1,"ucache":1,"http":80,]),(["url":"http://wl.mud.de","banner":" _ _ _ _ _ ( ) ( )_ _ __ _( ) ___ _ _( ) ___ __ _( ) Adresse: wl.mud.de (23) | ^ | | ) \\/ _ )/ -_\\ ^_) )/ _ ) \\/ _ ) im IPv6: wl.mud.de 4711 \\/ \\/ \\_/|_|_)___)\\___)_| (__)___)_|_)___) WWW : http://wl.mud.de/ ",]),}),"Dead_Souls_excelsior":({0,"117.20.68.194",6666,6672,6674,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03w","LPMud","mudlib development","robk@ningaui.net",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6672,"emoteto":1,"http":6667,]),(["upsince":"Sat Aug 29 14:09:29 2020","ip":"127.0.0.1","architecture":"Microsoft Windows NT","next boot":"EST Mon Jan 26 00:09:29 2032","os build":"windows","native version":"3.9","oob port":6672,]),}),"doomsday":({-1,"94.189.246.51",7000,0,0,"CoffeeMud v5.9.8.1","CoffeeMud v5.9.8.1","CoffeeMud v5.9.8.1","CoffeeMud","Beta Testing","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Realms at War":({0,"185.245.86.149",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Tarmetrotrate":({0,"76.185.16.182",6666,6672,6674,"Dead Souls 3.8.2","Dead Souls 3.8.2","FluffOS v2.23-ds03w","LPMud","mudlib development","greatland@rocketmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6672,"emoteto":1,"http":6667,]),(["upsince":"Tue Sep 01 14:04:54 2020","ip":"127.0.0.1","architecture":"Microsoft Windows NT","next boot":"EST Wed Jan 28 23:04:54 2032","os build":"windows","native version":"3.8.2","oob port":6672,]),}),"Second Contract":({-1,"54.84.108.226",6666,6672,6674,"Dead Souls 3.6","Dead Souls 3.6","FluffOS v2.23-ds01","LPMud","open alpha","admin@second-contract.com",(["channel":1,"mail":1,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6672,"emoteto":1,"http":6667,]),(["upsince":"Mon Jul 20 19:20:51 2020","ip":"50.57.187.30","architecture":"Linux","next boot":"never","os build":"unix","native version":"3.6","oob port":6672,]),}),"OASIS MUD":({-1,"51.91.251.230",5555,0,0,"CoffeeMud v5.9.9.1","CoffeeMud v5.9.9.1","CoffeeMud v5.9.9.1","CoffeeMud","Beta Testing","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"DarkeMUD":({-1,"45.52.9.106",0,0,0," "," "," "," "," "," ",(["who":1,"channel":1,"tell":1,]),(["imc_version":2.000000,]),}),"Forgotten-Gods":({-1,"54.172.123.224",6690,6696,6698,"Dead Souls 3.8.6","Dead Souls 3.8.6","FluffOS v2.23-ds03","LPMud","mudlib development","elohim@technocratia.com",(["channel":1,"mail":1,"ftp":6689,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6696,"emoteto":1,"http":6691,]),(["upsince":"Sat May 5 19:13:37 2018","ip":"127.0.0.1","architecture":"Linux","next boot":"EST Mon Oct 1 05:13:37 2029","os build":"unix","native version":"3.8.6","oob port":6696,]),}),"Unnamed_CoffeeMUD#316468430":({0,"185.245.86.149",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","realmatwar@gmail.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Brandywine MUD":({-1,"45.33.64.28",5555,0,0,"CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud","Beta Testing","info@brandywine.pocketmud.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"InfectedMinds":({-1,"73.245.13.171",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","infected@infectedminds.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Epitaph":({0,"176.126.244.21",23,8765,0,"Epiphany v1.2.13 [release]","Epiphany v1.2.13 [release]","FluffOS v2.26 (MeekOS version)","LPMud","Development","drakkos@imaginary-realities.com",(["channel":1,"ftp":6001,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"emoteto":1,"http":80,]),0,}),"Lemonland":({-1,"91.200.100.76",5555,0,0,"CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud","Beta Testing","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"The Zone":({-1,"136.144.155.250",8888,8891,8890,"WOTFlib 0.90","LPMud","DGD 1.4.1","LPMud","beta testing","aidil@wotf.org",(["channel":1,"ftp":21,"tell":1,"who":1,"locate":1,"http":8887,]),(["notice":1,"wotf-mail":1,"beep":1,]),}),"Dahlookahs MUD":({0,"46.251.35.104",8888,8893,0,"Skylib 1.8","Discworld","FluffOS v2.23","LP","Mudlib Development","quixadhal@gmail.com",(["channel":1,"ftp":8890,"tell":1,"finger":1,"who":1,"locate":1,"emoteto":1,"http":8891,]),([]),}),"Waterver":({0,"71.246.228.190",6666,6672,6674,"Dead Souls 3.8.6","Dead Souls 3.8.6","FluffOS v2.23-ds03","LPMud","mudlib development","jgsmith@gmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6672,"emoteto":1,"http":6667,]),(["upsince":"Tue Sep 1 17:17:14 2020","ip":"127.0.0.1","architecture":"Mac OS X","next boot":"EST Thu Jan 29 02:17:14 2032","os build":"unix","native version":"3.8.6","oob port":6672,]),}),"I3-TheMud-ORG-PGSQL":({-1,"45.64.56.66",5555,5561,5563,"Dead Souls 3.8.6","Dead Souls 3.8.6","FluffOS v2.28.3","LPMud","CLOSED TO PUBLIC","adam@themud.org",(["channel":1,"mail":1,"ftp":5554,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":5561,"emoteto":1,"http":5556,]),(["upsince":"Fri Aug 7 10:39:57 2020","ip":"127.0.0.1","architecture":"Linux/x86-64","next boot":"AES Sun Jan 4 02:39:57 2032","os build":"unix","native version":"3.8.6","oob port":5561,]),}),"Tales of Aeril":({-1,"45.33.10.116",5555,0,0,"CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud","Restricted Access","info@talesofaeril.pocketmud.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Covenant of Lords":({-1,"96.126.100.155",23,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","info@covenantoflords.pocketmud.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Darkness and Despair":({-1,"155.254.17.154",4201,3500,3501,"Nightmare+DnD","Nightmare v3.2","FluffOS v2017.2018120702 (git-7054237-1546244910)","LPMud","Open for public","squid@desolation.org",(["finger":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Multiverse MUD":({-1,"45.33.61.54",5555,0,0,"CoffeeMud v5.9.9.1","CoffeeMud v5.9.9.1","CoffeeMud v5.9.9.1","CoffeeMud","Beta Testing","vaencor@yahoo.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Realm At War":({0,"107.158.155.195",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","realmatwar@gmail.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Pluto MUD":({-1,"172.105.37.194",5555,0,0,"CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud","Beta Testing","info@pluto.pocketmud.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Dead_Souls_babylon":({-1,"50.34.196.5",6666,6672,6674,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03w","LPMud","mudlib development","babylon_horuv@zoho.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6672,"emoteto":1,"http":6667,]),(["upsince":"Wed Sep 02 00:18:52 2020","ip":"127.0.0.1","architecture":"Microsoft Windows NT","next boot":"EST Thu Jan 29 09:18:52 2032","os build":"windows","native version":"3.9","oob port":6672,]),}),"lpcdb":({-1,"136.144.155.250",4000,4002,4003,"lpcdb v1.0 alpha 2","lpcdb","DGD 1.5.4","LPMud","Mudlib Development","aidil@wotf.org",(["who":1,"auth":1,"channel":1,"locate":1,"ftp":4001,"tell":1,]),([]),}),"The Zone-dalet":({-1,"136.144.155.250",8888,8891,8890,"WOTFlib 0.90","LPMud","DGD 1.4.1","LPMud","beta testing","aidil@wotf.org",(["channel":1,"ftp":21,"tell":1,"who":1,"locate":1,"http":8887,]),(["notice":1,"wotf-mail":1,"beep":1,]),}),"Kotaka":({0,"96.41.218.191",61440,0,0,"Kotaka","Kotaka","DGD 1.6.13","DGD","(fill in the purpose of the mud here)","(fill in your admin email here)",(["channel":1,"tell":1,]),([]),}),"Zenith":({-1,"47.12.102.26",4201,4207,4209,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03","LPMud","mudlib development","tim_heinzeroth@hotmail.com",(["channel":1,"mail":1,"ftp":4200,"tell":1,"finger":1,"who":1,"auth":1,"oob":4207,"locate":1,"emoteto":1,"http":4202,]),(["upsince":"Sat Sep 5 17:06:09 2020","ip":"127.0.0.1","next boot":"EST Mon Feb 2 02:06:09 2032","architecture":"Linux","os build":"unix","oob port":4207,"native version":"3.9",]),}),"Eye of the World":({-1,"50.116.55.253",2222,2225,0,"Tmi-2 1.4","Tmi-2 1.4","MudOS v22.2b13","LPmud","Open for Users","shaitan@eyemud.com",(["ftp":2221,"http":2217,]),0,}),"The Brass Ring":({-1,"96.244.229.21",2150,2156,2158,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03","LPMud","mudlib development","n@n.net",(["channel":1,"mail":1,"ftp":2149,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":2156,"emoteto":1,"http":2151,]),(["upsince":"Fri Aug 28 10:26:26 2020","ip":"127.0.0.1","architecture":"Linux","next boot":"never","os build":"unix","native version":"3.9","oob port":2156,]),}),"Ara Labs":({-1,"34.86.104.52",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","hokieines@gmail.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Homebound":({-1,"45.33.46.71",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","matthew.shaun@gmail.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"WileyMUD":({-1,"172.92.143.166",3000,0,0,"WileyMUD III 2.119g","WileyMUD III 2.119g","I3 Driver 2.40b","DikuMUD","Idle","quixadhal@wileymud.themud.org",(["channel":1,"tell":1,"finger":1,"who":1,"locate":1,"ucache":1,"emoteto":1,"beep":1,]),(["time":"Tue Sep 1 02:42:30 2020","url":"http://wileymud.themud.org/~wiley/",]),}),"Unnamed_CoffeeMUD#75852566":({0,"88.105.63.141",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Swashbockle MUD":({-1,"45.33.42.13",5555,0,0,"CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud","Beta Testing","info@swashbockle.pocketmud.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Fantastic mud":({-1,"217.61.6.178",6666,6672,6674,"Dead Souls 3.8.2","Dead Souls 3.8.2","FluffOS v2.23-ds03","LPMud","mudlib development","admin@mud.tdani.hu",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6672,"emoteto":1,"http":6667,]),(["upsince":"Wed Sep 2 07:54:46 2020","ip":"127.0.0.1","architecture":"Linux","next boot":"EST Wed Sep 2 14:54:46 2020","os build":"unix","native version":"3.8.2","oob port":6672,]),}),"Haven":({-1,"23.253.225.109",5000,5005,5008,"Haven 0.1","Haven 0.1","FluffOS v2.9-ds2.14","LPMud","Open - Small playerbase","Hidden from Spammers",(["channel":1,"ftp":4999,"tell":1,"finger":1,"who":1,"locate":1,"emoteto":1,"rcp":4990,"http":80,]),([]),}),"IMUD-FluffOS2019":({-1,"110.232.112.129",1701,1707,1709,"Dead Souls 3.8.6","Dead Souls 3.8.6","fluffos v2019.2020041301","LPMud","driver development","adam@themud.org",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"emoteto":1,"tell":1,]),(["upsince":"Sat Jun 13 13:04:47 2020","ip":"127.0.0.1","architecture":"Linux/x86-64","next boot":"EST Mon Nov 10 00:04:47 2031","os build":"unix","native version":"3.8.6","oob port":1707,]),}),"Old Sol 2020":({-1,"101.80.96.43",7777,7783,7785,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03","LPMud","mudlib development","kengim63@gmail.com",(["channel":1,"mail":1,"ftp":7776,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":7783,"emoteto":1,"http":7778,]),(["upsince":"Sun Aug 30 11:54:33 2020","ip":"127.0.0.1","architecture":"Linux","next boot":"EST Mon Jan 26 21:54:33 2032","os build":"unix","native version":"3.9","oob port":7783,]),}),"savageisle":({-1,"23.25.8.124",5559,0,0,"CoffeeMud v5.9.6","CoffeeMud v5.9.6","CoffeeMud v5.9.6","CoffeeMud","Beta Testing","admin@savageisles.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"The Zone-Kelly":({-1,"136.144.155.250",8888,8891,8890,"WOTFlib 0.90","LPMud","DGD 1.4.1","LPMud","beta testing","aidil@wotf.org",(["channel":1,"ftp":21,"tell":1,"who":1,"locate":1,"http":8887,]),(["notice":1,"wotf-mail":1,"beep":1,]),}),"SingularisMUD":({0,"46.251.35.104",8888,8893,0,"Skylib 1.8","Discworld","FluffOS v2.23","LP","Mudlib Development","quixadhal@gmail.com",(["channel":1,"ftp":8890,"tell":1,"finger":1,"who":1,"locate":1,"emoteto":1,"http":8891,]),([]),}),"Worlds Of Wonder":({-1,"144.217.205.176",2500,2506,2508,"Dead Souls 3.8.2","Dead Souls 3.8.2","FluffOS v2.23-ds03","LPMud","mudlib development","gabriel@wonderteamterrible.com",(["channel":1,"mail":1,"ftp":2499,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":2506,"emoteto":1,"http":2549,]),(["upsince":"Thu Sep 12 21:54:25 2019","ip":"127.0.0.1","architecture":"Linux","next boot":"EST Sat Feb 8 06:54:25 2031","os build":"unix","native version":"3.8.2","oob port":2506,]),}),"KellerMUD":({-1,"104.237.155.126",23,0,0,"CoffeeMud v5.9.6","CoffeeMud v5.9.6","CoffeeMud v5.9.6","CoffeeMud","Restricted Access","info@kellermud.pocketmud.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Dragon's Den":({-1,"74.109.126.27",2222,2223,2223,"Dragon Mudlib 1.1","MudOS v22.2b13","MudOS v22.2b14","LPMud","Open since 1990","cejones1@gmail.com",(["channel":1,"mail":0,"ftp":2223,"tell":1,"news":0,"finger":1,"auth":0,"who":1,"locate":1,"ucache":0,"emoteto":1,"file":0,"http":2080,]),0,}),"The Library":({-1,"65.19.167.66",6666,6672,6674,"Dead Souls 3.7a7","Dead Souls 3.7a7","FluffOS v2.23-ds01","LPMud","mudlib development","z993126@gmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6672,"emoteto":1,"http":6667,]),(["upsince":"Fri Nov 9 18:01:46 2018","ip":"127.0.0.1","architecture":"Linux","next boot":"EST Sun Apr 7 05:01:46 2030","os build":"unix","native version":"3.7a7","oob port":6672,]),}),"Local MUD":({0,"204.195.8.155",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Waterver Dev":({0,"71.246.228.190",6666,6672,6674,"Dead Souls 3.9","Dead Souls 3.9","fluffos v2019.2020082501","LPMud","mudlib development","jgsmith@gmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6672,"emoteto":1,"http":6667,]),(["upsince":"Fri Sep 4 20:19:15 2020","ip":"127.0.0.1","architecture":"Linux/x86-64","next boot":"never","os build":"unix","native version":"3.9","oob port":6672,]),}),"The Rifthome MUD":({-1,"46.4.48.195",5585,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"lpcdb-dev":({0,"87.209.243.234",4000,4002,4003,"lpcdb v1.0 alpha 2","lpcdb","DGD 1.5.5","LPMud","Mudlib Development","aidil@wotf.org",(["auth":1,"who":1,"channel":1,"locate":1,"ftp":4001,"tell":1,]),(["banner":"
html escape test 
",]),}),"Nuke II":({-1,"173.255.201.173",4080,4081,0,"Lima 1.0b5","Lima","fluffos v2019.2020050101","LP","game development","stanach@nuclearwarmud.com",(["channel":1,"mail":1,"ftp":21,"tell":1,"finger":1,"who":1,"auth":1,"locate":1,"emoteto":1,"ucache":1,"file":1,"http":80,]),0,}),"The Beast Within: Resurrected":({-1,"45.33.109.237",5555,0,0,"CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud","Beta Testing","mudadmin@beastwithin.pocketmud.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Itinerantion":({-1,"108.173.162.164",6666,6672,6674,"Dead Souls 3.8.6","Dead Souls 3.8.6","FluffOS v2.23-ds03","LPMud","mudlib development","w.steven.schneider@gmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6672,"emoteto":1,"http":6667,]),(["upsince":"Tue Jul 21 21:56:07 2020","ip":"127.0.0.1","architecture":"unknown architecture","next boot":"MST Thu Dec 18 11:56:07 2031","os build":"unix","native version":"3.8.2","oob port":6672,]),}),"Realm of Shadows":({0,"24.8.206.167",1133,0,0,"Smaug 1.4a","Smaug","I3 Driver 2.40b","DikuMUD","Operational","syriac_ros@gmail.com",(["channel":1,"tell":1,"finger":1,"who":1,"locate":1,"emoteto":1,"ucache":1,"beep":1,]),(["url":"https://realmofshadows.us","time":"Mon Aug 31 10:39:54 2020",]),}),"Realm of Cernunnos":({-1,"50.105.123.230",5555,0,0,"CoffeeMud v5.9.4","CoffeeMud v5.9.4","CoffeeMud v5.9.4","CoffeeMud","Open to the public","admin@cernunnos.net",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Disk World":({-1,"172.92.143.166",4400,4404,0,"Discworld 17.0a","Disk World","FluffOS v2.28.2","LPMud","Development","none",(["channel":1,"ftp":4440,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"emoteto":1,"http":4480,]),0,}),"Indigo":({-1,"87.229.53.104",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Aadarian Realms":({-1,"178.79.173.99",1111,0,0,"ADR 5.06 (build: 19)","ROT","Aadaria I3 Driver 2.33(mod)","DikuMUD","Open","tijer@godwars.net",(["channel":1,"tell":1,"finger":1,"who":1,"locate":1,"ucache":1,"emoteto":1,"beep":1,]),(["time":"Fri Aug 21 14:24:02 2020","url":"http://www.aadaria.net",]),}),"World of ClouseCraft":({-1,"167.172.140.125",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Universes":({-1,"108.252.255.105",3333,3338,3341,"UniLib 1.0a","UniLib 1.0a","MudOS v22.1","LPMud","MudLib Development","ebayer@thetesseract.org",(["finger":1,"who":1,"channel":1,"amcp":"1.1","emoteto":1,"tell":1,"http":80,]),([]),}),"Dead Souls Dev":({-1,"97.107.133.86",8000,8006,8008,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03","LPMud","mudlib development","cratylus@comcast.net",(["channel":1,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"emoteto":1,"http":8001,]),(["upsince":"Fri Oct 18 02:29:02 2019","ip":"127.0.0.1","architecture":"Linux","next boot":"EST Sat Mar 15 11:29:02 2031","os build":"unix","native version":"3.8.2","oob port":8006,]),}),"AsYetUntitled":({-1,"178.62.73.229",6666,6672,6674,"Dead Souls 3.8.6","Dead Souls 3.8.6","FluffOS v2.23-ds03","LPMud","mudlib development","tahoma@tammenta.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6672,"emoteto":1,"http":6663,]),(["upsince":"Sun Jul 19 17:13:28 2020","ip":"127.0.0.1","architecture":"Linux","next boot":"EST Tue Dec 16 02:13:28 2031","os build":"unix","native version":"3.8.6","oob port":6672,]),}),"OglafMUD":({-1,"86.52.128.42",7878,7879,0,"Lima 1.0b5","Lima","fluffos v2019.2020050101","LP","game development","user@host.name",(["channel":1,"mail":1,"ftp":21,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"ucache":1,"emoteto":1,"http":80,"file":1,]),0,}),"Core MUD":({-1,"173.193.107.10",4000,4010,4020,"Colony 1.3","Colony 1.3","MudOS v22.2b14","LPMud","Open to players","dshay01@coremud.org",(["news":0,"auth":0,"who":1,"locate":1,"emoteto":1,"http":80,"file":0,"channel":1,"mail":0,"ftp":0,"tell":1,"nntp":0,"finger":1,"rcp":0,"ucache":1,"smtp":0,]),([]),}),"Zebu":({-1,"50.34.196.5",6666,6672,6674,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03w","LPMud","mudlib development","babylon_horuv@zoho.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"who":1,"auth":1,"oob":6672,"locate":1,"emoteto":1,"http":6667,]),(["upsince":"Wed Sep 02 20:17:11 2020","ip":"127.0.0.1","next boot":" Fri Jan 30 10:17:11 2032","architecture":"Microsoft Windows NT","os build":"windows","oob port":6672,"native version":"3.9",]),}),"Dreamverse":({0,"70.91.196.214",9600,9605,9608,"DV-Nightmare RELENG_1_3","DV-Nightmare RELENG_1_3","fluffos v2019","LPMud","development","hilapdatus@dreamverse.org",(["ftp":9599,"amcp":"1.1","rcp":9585,"http":9595,]),(["architecture":"Linux/x86-64","up since":"Sat Aug 29 13:20:37 2020 GMT-0500","next boot":"Sat Aug 29 13:20:37 2020 GMT-0500",]),}),"Randy Stadham":({-1,"104.237.152.181",23,0,0,"CoffeeMud v5.9.6.4","CoffeeMud v5.9.6.4","CoffeeMud v5.9.6.4","CoffeeMud","Beta Testing","info@randys.pocketmud.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Somavos":({-1,"23.92.30.29",4242,0,0,"CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud","MudLib Development","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Desolation":({-1,"155.254.17.151",8787,8788,0,"Lima 1.0a8","Lima","fluffos v2019","LP","live","squid@desolation.org",(["channel":1,"mail":1,"ftp":21,"tell":1,"finger":1,"who":1,"auth":1,"locate":1,"emoteto":1,"ucache":1,"file":1,"http":80,]),0,}),"Little Mud":({0,"71.230.96.145",5555,0,0,"CoffeeMud v5.9.5","CoffeeMud v5.9.5","CoffeeMud v5.9.5","CoffeeMud","Beta Testing","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"GronMUD":({-1,"92.242.63.65",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Restricted Access","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Ulario":({-1,"96.41.218.191",61440,0,0,"Kotaka","Kotaka","DGD 1.6.13","DGD","(fill in the purpose of the mud here)","(fill in your admin email here)",(["channel":1,"tell":1,]),([]),}),"Dead_Souls_thessius":({0,"170.10.45.190",6666,6672,6674,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03w","LPMud","mudlib development","jessea.mccann@gmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"who":1,"auth":1,"oob":6672,"locate":1,"emoteto":1,"http":6667,]),(["upsince":"Wed Sep 02 12:04:09 2020","ip":"127.0.0.1","next boot":"EST Thu Jan 29 21:04:09 2032","architecture":"Microsoft Windows NT","os build":"windows","oob port":6672,"native version":"3.9",]),}),"RedSouls":({0,"88.106.83.129",5555,5561,5563,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03","LPMud","mudlib development","ron@ron.com",(["channel":1,"mail":1,"ftp":5554,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":5561,"emoteto":1,"http":5556,]),(["upsince":"Wed Aug 26 09:33:00 2020","ip":"127.0.0.1","architecture":"Linux","next boot":"EST Thu Jan 22 18:33:00 2032","os build":"unix","native version":"3.9","oob port":5561,]),}),"Mathers Realms":({0,"69.174.144.117",2323,0,0,"CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud","Beta Testing","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Star Wars: Jedi vs Sith":({-1,"24.222.84.75",8707,0,0,"SWJvS 1.4.1","SWR 1.0 FUSS","AFKMud I3 Driver 2.40a","SWR","Star Wars MUD","michael@themudhost.net",(["channel":1,"tell":1,"finger":1,"who":1,"locate":1,"ucache":1,"emoteto":1,"beep":1,]),(["time":"Wed Jul 29 10:32:59 2020","url":"http://swjvs.themudhost.net/",]),}),"Mansocks World":({-1,"68.68.95.221",6666,6672,6674,"Dead Souls 3.8.2","Dead Souls 3.8.2","FluffOS v2.23-ds03","LPMud","mudlib development","addlema@gmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6672,"emoteto":1,"http":6667,]),(["upsince":"Fri Aug 28 18:11:03 2020","ip":"127.0.0.1","architecture":"Linux","next boot":"EST Sun Jan 25 03:11:03 2032","os build":"unix","native version":"3.8.2","oob port":6672,]),}),"I3-TheMud-ORG":({-1,"45.64.56.66",5555,5561,5563,"Dead Souls 3.8.6","Dead Souls 3.8.6","FluffOS v2.28.3","LPMud","CLOSED TO PUBLIC","adam@themud.org",(["channel":1,"mail":1,"ftp":5554,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":5561,"emoteto":1,"http":5556,]),(["upsince":"Sun Aug 9 12:34:51 2020","ip":"127.0.0.1","architecture":"Linux/x86-64","next boot":"AES Tue Jan 6 04:34:51 2032","os build":"unix","native version":"3.8.6","oob port":5561,]),}),"The Open Door":({-1,"50.116.13.244",5555,0,0,"CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud","Beta Testing","info@opendoor.pocketmud.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Iberia MUD":({-1,"2.81.180.125",5900,0,0,"IME v0.9975","IME","IME","IME","beta testing","joaodiasafonso@gmail.com",(["who":1,"channel":1,"emoteto":1,"tell":1,]),0,}),"WarofLegend":({-1,"178.79.173.99",4200,0,0,"WoL 10.26 (build: 45)","Merc","AFKMud I3 Driver 2.33","DikuMUD","Open","admin@waroflegend.net",(["finger":1,"who":1,"channel":1,"locate":1,"tell":1,"ucache":1,"emoteto":1,]),(["time":"Tue Sep 1 17:18:18 2020","url":"http://www.waroflegend.net",]),}),"TimesLost":({0,"104.48.188.233",3000,0,0,"6Dragons 4.4","Smaug","I3 Driver 2.40b","DikuMUD","Operational","ixliam1@gmail.com",(["channel":1,"tell":1,"finger":1,"who":1,"locate":1,"emoteto":1,"ucache":1,"beep":1,]),(["url":"old.reddit.com/r/wotlmud","time":"Sat Sep 5 20:04:26 2020",]),}),"Occulte":({-1,"199.74.141.8",6677,8765,0,"Discworld 17.0a","Occulte","FluffOS v2.15-ds08","LPMud","Development","none",(["channel":1,"ftp":4444,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"emoteto":1,"http":80,]),0,}),"Nightfall":({-1,"212.83.56.217",4242,4246,4246,"NF","NF","LPMud 3.5.0.2 (3.5.0.2-13-g4572ab8f)","LPMud","open for public","administration@nightfall.org",(["channel":1,"ftp":21,"tell":1,"finger":1,"who":1,"locate":1,"emoteto":1,"http":80,]),(["url":"http://nightfall.org","banner":"------------------------------------------------------------------------------ Nightfall LD-LPMud driver 3.5.0.2 (3.5.0.2-13-g4572ab8f)/mudlib NF III in Dreamland, Germany telnet [nightfall.org 2a00:f48:1003:1::56:66f1 212.83.56.217]:4242 ------------------------------------------------------------------------------ ",]),}),"A.HEGY. ":({-1,"89.133.33.82",1222,1228,1230,"Dead Souls 3.8.6","Dead Souls 3.8.6","FluffOS v2.23-ds03","LPMud","mudlib development","dp@iworld.hu",(["channel":1,"mail":1,"ftp":1221,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":1228,"emoteto":1,"http":1223,]),(["upsince":"Fri Jun 26 10:13:06 2020","ip":"127.0.0.1","architecture":"Linux","next boot":"CET Sun Nov 23 01:13:06 2031","os build":"unix","native version":"3.8.6","oob port":1228,]),}),"LPM":({-1,"18.218.123.244",6666,6672,6674,"Dead Souls 3.8.6","Dead Souls 3.8.6","FluffOS v2.23-ds03","LPMud","mudlib development","cratylus.ds@gmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6672,"emoteto":1,"http":6667,]),(["upsince":"Sat Mar 14 23:50:17 2020","ip":"127.0.0.1","architecture":"Linux","next boot":"EST Mon Aug 11 09:50:17 2031","os build":"unix","native version":"3.8.6","oob port":6672,]),}),"EmpiresEnd":({-1,"74.207.226.164",5555,0,0,"CoffeeMud v5.9.6","CoffeeMud v5.9.6","CoffeeMud v5.9.6","CoffeeMud","Beta Testing","islander@glassislands.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"szetnezek":({0,"87.229.23.214",5555,5560,5563,"Nightmare IVr6","Nightmare IVr6","FluffOS v2.23-ds03","LPMud","mudlib development","borg@imaginary.com",(["channel":1,"ftp":5554,"tell":1,"finger":1,"who":1,"locate":1,"emoteto":1,"ucache":1,"rcp":5545,"http":5550,]),([]),}),"DomeMUD Dev":({0,"73.147.192.82",4000,4002,4003,"Domelib v0.9-a3","Domelib","DGD 1.4.14","LPMud","Mudlib Development","admin@domemud.com",(["who":1,"auth":1,"channel":1,"locate":1,"ftp":4001,"tell":1,]),([]),}),"Way of the Force":({-1,"136.144.155.250",23,3000,3000,"WOTFlib 0.90","LPMud","DGD 1.2.157-WOTF-NET","LPMud","beta testing","aidil@wotf.org",(["channel":1,"ftp":21,"tell":1,"who":1,"locate":1,"http":80,]),(["notice":1,"wotf-mail":1,"beep":1,]),}),"Amethyst Kingdom":({0,"74.81.160.221",6666,6672,6674,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03","LPMud","mudlib development","barryeichelberger@gmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6672,"emoteto":1,"http":6667,]),(["upsince":"Sun Aug 30 21:14:44 2020","ip":"192.168.1.204","architecture":"Linux","next boot":"EST Tue Jan 27 07:14:44 2032","os build":"unix","native version":"3.9","oob port":6672,]),}),"WayPoint":({-1,"74.208.214.165",5555,0,0,"CoffeeMud v5.9.8","CoffeeMud v5.9.8","CoffeeMud v5.9.8","CoffeeMud","Beta Testing","waypoint@model-reality.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Discworld":({-1,"82.68.167.69",23,8765,0,"Discworld 18.0a","Discworld","FluffOS v2.28","LPMud","open for players","trustees@discworld.starturtle.net",(["channel":1,"ftp":4444,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"emoteto":1,"http":80,]),0,}),"Wk-CoffeeMud-Dev":({0,"104.14.28.106",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Open to the public","bo@zimmers.net",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"EotL":({-1,"209.216.23.199",2010,4247,4246,"LPMud EotL 98","LPMud EotL 98","Amylaar 3.2.14","LPMud","Open to players","none",(["who":1,"channel":1,"tell":1,]),([]),}),"Abandoned Codex":({-1,"95.85.50.124",4000,0,0,"Smaug 1.02a modified","Smaug","I3 Driver 2.40b","DikuMUD","Open","admin@abandonedcodex.net",(["finger":1,"who":1,"channel":1,"locate":1,"tell":1,"ucache":1,]),(["time":"Thu Aug 13 17:27:35 2020","url":"abandonedcodex.net",]),}),"Mundo Sangre":({-1,"23.239.11.138",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","info@mundosangre.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"The Savage Soul":({-1,"173.255.210.234",6666,6672,6674,"Dead Souls 3.7a7","Dead Souls 3.7a7","FluffOS v2.23-ds01","LPMud","mudlib development","savagesoul@gmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6672,"emoteto":1,"http":8001,]),(["upsince":"Fri Oct 25 09:10:07 2019","ip":"127.0.0.1","architecture":"Linux","next boot":"PDT Sat Mar 22 17:10:07 2031","os build":"unix","native version":"3.7a7","oob port":6672,]),}),"GreyArea_DS-stock":({-1,"220.253.84.210",6666,6672,6674,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03","LPMud","mudlib development","mordain23@gmail.com",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"who":1,"auth":1,"oob":6672,"locate":1,"emoteto":1,"http":6667,]),(["upsince":"Sat Sep 5 14:00:35 2020","ip":"127.0.0.1","next boot":"EST Mon Feb 2 01:00:35 2032","architecture":"Linux","os build":"unix","oob port":6672,"native version":"3.9",]),}),"Dreath MUD":({-1,"23.92.27.179",23,0,0,"CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud","Beta Testing","info@dreath.pocketmud.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Adventurers Way":({-1,"172.105.188.166",1111,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","imaginingstuff@gmail.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"The Chronicles of Meridian":({-1,"78.90.77.217",7878,7881,7881,"Meridian v0.1","Meridian v0.1","fluffos v2019.2020082501","LPmud","Mudlib Development","vm@angband.eu",(["channel":1,]),(["upsince":"Mon Aug 31 13:36:33 2020","architecture":"Linux/x86-64",]),}),"TimMUD":({-1,"104.154.76.197",5555,5558,0,"Tmi-2 1.4","Tmi-2 1.4","FluffOS v2.28.3","LPmud","Mudlib Development","tim@timboj.com",(["channel":1,"ftp":5554,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"http":5550,]),(["url":"http://timmud.com",]),}),"m3tamud":({0,"88.98.228.197",4000,4002,4003,"GurbaLib v0.50","GurbaLib","DGD 1.6.13","LPMud","Mudlib Development","m3ta@m3ta.uk",(["who":1,"auth":1,"channel":1,"locate":1,"ftp":4001,"tell":1,]),([]),}),"Unnamed_CoffeeMUD#1999742985":({0,"23.243.152.62",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Unnamed_CoffeeMUD#1518426141":({0,"88.105.63.141",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Mystic":({-1,"45.79.130.170",3000,3005,3008,"Realms of Mystic Lib .06b","Realms of Mystic Lib .06b","MudOS v22.2b14","LPMud","now serving","mystic@uprising.net",(["finger":1,"who":1,"channel":1,"locate":1,"tell":1,"emoteto":1,"amcp":"1.1",]),([]),}),"ShadowMUD":({-1,"199.74.141.8",1030,1039,1038,"Nightmare/ShadowLib 3.2.2/0.5","Nightmare/ShadowLib 3.2.2/0.5","FluffOS v2.28.2","LP","beta testing","shadowmudii@hotmail.com",(["finger":1,"who":1,"channel":1,"locate":1,"tell":1,"emoteto":1,]),([]),}),"Steve`s World":({0,"104.179.197.128",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Dead_Souls_pyra":({-1,"69.164.194.158",4000,4006,4008,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03","LPMud","mudlib development","blaketracy23@gmail.com",(["channel":1,"mail":1,"ftp":3999,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":4006,"emoteto":1,"http":4001,]),(["upsince":"Sat May 9 15:45:19 2020","ip":"127.0.0.1","architecture":"Linux","next boot":"EST Mon Oct 6 01:45:19 2031","os build":"unix","native version":"3.9","oob port":4006,]),}),"STiNKBoMB":({-1,"84.197.184.69",4000,4002,4003,"GurbaLib v0.50","GurbaLib","DGD 1.6.2","LPMud","Mudlib Development","cc_StinkBomb@pyromasaur.com",(["who":1,"auth":1,"channel":1,"locate":1,"ftp":4001,"tell":1,]),([]),}),"RavensGate":({0,"67.40.210.180",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Restricted Access","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"MoH":({-1,"178.79.173.99",3500,0,0,"MoH3.0","Merc","AFKMud I3 Driver 2.33","GodWars","Open","tijer@godwars.net",(["channel":1,"tell":1,"finger":1,"who":1,"locate":1,"ucache":1,"emoteto":1,"beep":1,]),(["time":"Thu Aug 13 19:26:59 2020","url":"http://www.godwars.net",]),}),"7thplane":({-1,"69.164.199.238",8888,0,0,"IMC2 Freedom CL-2.2-PlanarDiku","IMC2 Freedom CL-2.2-PlanarDiku","IMC2 client","n/a"," "," ",(["who":1,"channel":1,"tell":1,]),(["port":8888,"versionid":"IMC2 Freedom CL-2.2-PlanarDiku","url":"http://7thplane.ath.cx/","imc_version":2.000000,"host":"7thplane.ath.cx",]),}),"Unnamed_CoffeeMUD#1065668316":({-1,"34.238.162.229",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Adaka":({-1,"85.3.174.248",5555,0,0,"CoffeeMud v5.9.6","CoffeeMud v5.9.6","CoffeeMud v5.9.6","CoffeeMud","Open to the public","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"WWC":({0,"174.109.164.19",4000,0,0,"FRlib III","WWC","FluffOS v2.23","LP","mudlib development","wwc@potato.org",(["channel":1,"ftp":0,"tell":1,"nntp":0,"finger":1,"who":1,"locate":1,"http":0,]),0,}),"Unnamed_CoffeeMUD#1014238178":({0,"49.192.178.83",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Dragon`s Lair":({-1,"173.255.200.146",23,0,0,"CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud v5.9.8.5","CoffeeMud","Beta Testing","telquisjones@yahoo.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Unnamed_CoffeeMUD#1309462931":({0,"68.45.53.176",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Your MUD Name":({-1,"45.33.51.250",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","jordan.obrastoff@gmail.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"EotL-Red":({-1,"163.172.210.70",2010,4247,4246,"LPMud EotL 2019","LPMud EotL 2019","LDMud 3.2.14","LPMud","mudlib development","none",(["who":1,"channel":1,"tell":1,]),([]),}),"SpesMUD":({-1,"45.79.100.63",5555,0,0,"CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud v5.9.9","CoffeeMud","Restricted Access","ampboox@gmail.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"Northlands":({-1,"178.79.160.71",5555,0,0,"CoffeeMud v5.9.9.1","CoffeeMud v5.9.9.1","CoffeeMud v5.9.9.1","CoffeeMud","Beta Testing","loghoover@gmail.com",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),"THOTconMUD":({-1,"64.227.62.127",4000,4002,4003,"GurbaLib v0.50","GurbaLib","DGD 1.6.11","LPMud","Mudlib Development","nyxgeek@gmail.com",(["who":1,"auth":1,"channel":1,"locate":1,"ftp":4001,"tell":1,]),([]),}),"QS":({-1,"174.114.46.52",2525,2531,2533,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03","LPMud","mudlib development","qs@erroraccessdenied.com",(["channel":1,"mail":1,"ftp":2524,"tell":1,"finger":1,"who":1,"auth":1,"oob":2531,"locate":1,"emoteto":1,"http":2526,]),(["upsince":"Wed Sep 2 04:20:30 2020","ip":"127.0.0.1","next boot":"EST Thu Jan 29 13:20:30 2032","architecture":"Linux","os build":"unix","oob port":2531,"native version":"3.9",]),}),"Dead_Souls_naridius":({0,"178.164.162.21",6666,6672,6674,"Dead Souls 3.9","Dead Souls 3.9","FluffOS v2.23-ds03w","LPMud","mudlib development","admin@here",(["channel":1,"mail":1,"ftp":6665,"tell":1,"finger":1,"auth":1,"who":1,"locate":1,"oob":6672,"emoteto":1,"http":6667,]),(["upsince":"Sat Aug 29 10:05:27 2020","ip":"127.0.0.1","architecture":"Microsoft Windows NT","next boot":"EST Sun Jan 25 19:05:27 2032","os build":"windows","native version":"3.9","oob port":6672,]),}),"SWare World":({0,"104.179.197.128",5555,0,0,"CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud v5.9.10","CoffeeMud","Beta Testing","",(["finger":1,"auth":1,"who":1,"channel":1,"locate":1,"tell":1,]),([]),}),]) +Unconnected ([]) +Status ([]) +Confirmed ([]) +queue ({}) diff --git a/lib/secure/save/player_list.o b/lib/secure/save/player_list.o new file mode 100644 index 0000000..f10343e --- /dev/null +++ b/lib/secure/save/player_list.o @@ -0,0 +1,12 @@ +#/secure/daemon/players.c +PlayerDataMap ([]) +UserData ([]) +PendingEncres ({}) +PendingDecres ({}) +PendingPauses ({}) +PendingUnpauses ({}) +players ({"bumble","deskarnull","guest","gumpy","babylon",}) +creators ({"babylon",}) +user_list ({"gumpy","deskarnull","bumble","babylon","fluffster","guest",}) +player_save_file "/secure/save/creators/b/babylon.o" +Levels ([387:(["xp":2132393700,]),386:(["xp":2111281000,]),385:(["xp":2090377300,]),384:(["xp":2069680500,]),383:(["xp":2049188700,]),382:(["xp":2028899800,]),381:(["xp":2008811700,]),380:(["xp":1988922600,]),379:(["xp":1969230400,]),378:(["xp":1949733100,]),377:(["xp":1930428900,]),376:(["xp":1911315800,]),375:(["xp":1892392000,]),374:(["xp":1873655500,]),373:(["xp":1855104500,]),372:(["xp":1836737200,]),371:(["xp":1818551800,]),370:(["xp":1800546300,]),369:(["xp":1782719100,]),368:(["xp":1765068400,]),367:(["xp":1747592500,]),366:(["xp":1730289700,]),365:(["xp":1713158200,]),364:(["xp":1696196300,]),363:(["xp":1679402300,]),362:(["xp":1662774600,]),361:(["xp":1646311500,]),360:(["xp":1630011500,]),359:(["xp":1613872800,]),358:(["xp":1597894000,]),357:(["xp":1582073300,]),356:(["xp":1566409300,]),355:(["xp":1550900400,]),354:(["xp":1535545000,]),353:(["xp":1520341700,]),352:(["xp":1505288900,]),351:(["xp":1490385100,]),350:(["xp":1475628900,]),349:(["xp":1461018800,]),348:(["xp":1446553300,]),347:(["xp":1432231000,]),346:(["xp":1418050600,]),345:(["xp":1404010600,]),344:(["xp":1390109500,]),343:(["xp":1376346100,]),342:(["xp":1362718900,]),341:(["xp":1349226700,]),340:(["xp":1335868100,]),339:(["xp":1322641700,]),338:(["xp":1309546300,]),337:(["xp":1296580600,]),336:(["xp":1283743200,]),335:(["xp":1271032900,]),334:(["xp":1258448500,]),333:(["xp":1245988700,]),332:(["xp":1233652200,]),331:(["xp":1221437900,]),330:(["xp":1209344500,]),329:(["xp":1197370800,]),328:(["xp":1185515700,]),327:(["xp":1173778000,]),326:(["xp":1162156500,]),325:(["xp":1150650100,]),324:(["xp":1139257600,]),323:(["xp":1127977800,]),322:(["xp":1116809800,]),321:(["xp":1105752400,]),320:(["xp":1094804400,]),319:(["xp":1083964900,]),318:(["xp":1073232600,]),317:(["xp":1062606600,]),316:(["xp":1052085800,]),315:(["xp":1041669200,]),314:(["xp":1031355700,]),313:(["xp":1021144300,]),312:(["xp":1011034000,]),311:(["xp":1001023800,]),310:(["xp":991112700,]),309:(["xp":981299800,]),308:(["xp":971584000,]),307:(["xp":961964400,]),306:(["xp":952440100,]),305:(["xp":943010100,]),304:(["xp":933673400,]),303:(["xp":924429200,]),302:(["xp":915276500,]),301:(["xp":906214400,]),300:(["xp":897242000,]),299:(["xp":888358500,]),298:(["xp":879563000,]),297:(["xp":870854500,]),296:(["xp":862232300,]),295:(["xp":853695400,]),294:(["xp":845243000,]),293:(["xp":836874300,]),292:(["xp":828588400,]),291:(["xp":820384600,]),290:(["xp":812262000,]),289:(["xp":804219900,]),288:(["xp":796257400,]),287:(["xp":788373700,]),286:(["xp":780568100,]),285:(["xp":772839800,]),284:(["xp":765188000,]),283:(["xp":757611900,]),282:(["xp":750110800,]),281:(["xp":742684000,]),280:(["xp":735330800,]),279:(["xp":728050400,]),278:(["xp":720842100,]),277:(["xp":713705100,]),276:(["xp":706638800,]),275:(["xp":699642400,]),274:(["xp":692715300,]),273:(["xp":685856800,]),272:(["xp":679066200,]),271:(["xp":672342800,]),270:(["xp":665686000,]),269:(["xp":659095100,]),268:(["xp":652569400,]),267:(["xp":646108400,]),266:(["xp":639711300,]),265:(["xp":633377600,]),264:(["xp":627106600,]),263:(["xp":620897700,]),262:(["xp":614750200,]),261:(["xp":608663600,]),260:(["xp":602637300,]),259:(["xp":596670600,]),258:(["xp":590763000,]),257:(["xp":584913900,]),256:(["xp":579122700,]),255:(["xp":573388900,]),254:(["xp":567711800,]),253:(["xp":562090900,]),252:(["xp":556525700,]),251:(["xp":551015600,]),250:(["xp":545560000,]),249:(["xp":540158400,]),248:(["xp":534810300,]),247:(["xp":529515200,]),246:(["xp":524272500,]),245:(["xp":519081700,]),244:(["xp":513942300,]),243:(["xp":508853800,]),242:(["xp":503815700,]),241:(["xp":498827500,]),240:(["xp":493888700,]),239:(["xp":488998800,]),238:(["xp":484157300,]),237:(["xp":479363700,]),236:(["xp":474617600,]),235:(["xp":469918500,]),234:(["xp":465265900,]),233:(["xp":460659400,]),232:(["xp":456098500,]),231:(["xp":451582700,]),230:(["xp":447111600,]),229:(["xp":442684800,]),228:(["xp":438301800,]),227:(["xp":433962200,]),226:(["xp":429665600,]),225:(["xp":425411500,]),224:(["xp":421199600,]),223:(["xp":417029400,]),222:(["xp":412900400,]),221:(["xp":408812300,]),220:(["xp":404764700,]),219:(["xp":400757200,]),218:(["xp":396789400,]),217:(["xp":392860800,]),216:(["xp":388971200,]),215:(["xp":385120100,]),214:(["xp":381307100,]),213:(["xp":377531800,]),212:(["xp":373793900,]),211:(["xp":370093000,]),210:(["xp":366428800,]),209:(["xp":362800900,]),208:(["xp":359208900,]),207:(["xp":355652400,]),206:(["xp":352131100,]),205:(["xp":348644700,]),204:(["xp":345192800,]),203:(["xp":341775100,]),202:(["xp":338391200,]),201:(["xp":335040900,]),200:(["xp":331723700,]),199:(["xp":328439400,]),198:(["xp":325187600,]),197:(["xp":321968000,]),196:(["xp":318780200,]),195:(["xp":315624000,]),194:(["xp":312499000,]),193:(["xp":309405000,]),192:(["xp":306341600,]),191:(["xp":303308600,]),190:(["xp":300305600,]),189:(["xp":297332300,]),188:(["xp":294388500,]),187:(["xp":291473800,]),186:(["xp":288588000,]),185:(["xp":285730700,]),184:(["xp":282901700,]),183:(["xp":280100800,]),182:(["xp":277327600,]),181:(["xp":274581800,]),180:(["xp":271863200,]),179:(["xp":269171500,]),178:(["xp":266506500,]),177:(["xp":263867900,]),176:(["xp":261255400,]),175:(["xp":258668800,]),174:(["xp":256107800,]),173:(["xp":253572100,]),172:(["xp":251061500,]),171:(["xp":248575800,]),170:(["xp":246114700,]),169:(["xp":243678000,]),168:(["xp":241265400,]),167:(["xp":238876700,]),166:(["xp":236511600,]),165:(["xp":234170000,]),164:(["xp":231851500,]),163:(["xp":229556000,]),162:(["xp":227283200,]),161:(["xp":225032900,]),160:(["xp":222804900,]),159:(["xp":220599000,]),158:(["xp":218414900,]),157:(["xp":216252400,]),156:(["xp":214111300,]),155:(["xp":211991400,]),154:(["xp":209892500,]),153:(["xp":207814400,]),152:(["xp":205756900,]),151:(["xp":203719800,]),150:(["xp":201702800,]),149:(["xp":199705800,]),148:(["xp":197728600,]),147:(["xp":195770900,]),146:(["xp":193832600,]),145:(["xp":191913500,]),144:(["xp":190013400,]),143:(["xp":188132100,]),142:(["xp":186269500,]),141:(["xp":184425300,]),140:(["xp":182599400,]),139:(["xp":180791500,]),138:(["xp":179001500,]),137:(["xp":177229300,]),136:(["xp":175474600,]),135:(["xp":173737300,]),134:(["xp":172017200,]),133:(["xp":170314100,]),132:(["xp":168627900,]),131:(["xp":166958400,]),130:(["xp":165305400,]),129:(["xp":163668800,]),128:(["xp":162048400,]),127:(["xp":160444000,]),126:(["xp":158855500,]),125:(["xp":157282700,]),124:(["xp":155725500,]),123:(["xp":154183700,]),122:(["xp":152657200,]),121:(["xp":151145800,]),120:(["xp":149649400,]),119:(["xp":148167800,]),118:(["xp":146700800,]),117:(["xp":145248400,]),116:(["xp":143810400,]),115:(["xp":142386600,]),114:(["xp":140976900,]),113:(["xp":139581100,]),112:(["xp":138199200,]),111:(["xp":136830900,]),110:(["xp":135476200,]),109:(["xp":134134900,]),108:(["xp":132806900,]),107:(["xp":131492000,]),106:(["xp":130190100,]),105:(["xp":128901100,]),104:(["xp":127624900,]),103:(["xp":126361300,]),102:(["xp":125110200,]),101:(["xp":123871500,]),100:(["xp":122645100,]),99:(["xp":116804900,]),98:(["xp":111242800,]),97:(["xp":105945600,]),96:(["xp":100900600,]),95:(["xp":96095900,]),94:(["xp":91520000,]),93:(["xp":87162000,]),92:(["xp":83011500,]),91:(["xp":79058600,]),90:(["xp":75294000,]),89:(["xp":71708600,]),88:(["xp":68294000,]),87:(["xp":65042000,]),86:(["xp":61944800,]),85:(["xp":58995100,]),84:(["xp":56185900,]),83:(["xp":53510400,]),82:(["xp":50962300,]),81:(["xp":48535600,]),80:(["xp":46224400,]),79:(["xp":44023300,]),78:(["xp":41927000,]),77:(["xp":39930500,]),76:(["xp":38029100,]),75:(["xp":36218200,]),74:(["xp":34493600,]),73:(["xp":32851100,]),72:(["xp":31286800,]),71:(["xp":29797000,]),70:(["xp":28378100,]),69:(["xp":27026800,]),68:(["xp":25739900,]),67:(["xp":24514200,]),66:(["xp":23346900,]),65:(["xp":22235200,]),64:(["xp":21176400,]),63:(["xp":20168000,]),62:(["xp":19207700,]),61:(["xp":18293100,]),60:(["xp":17422000,]),59:(["xp":16592400,]),58:(["xp":15802300,]),57:(["xp":15049900,]),56:(["xp":14333300,]),55:(["xp":13650800,]),54:(["xp":13000800,]),53:(["xp":12381800,]),52:(["xp":11792200,]),51:(["xp":11230700,]),50:(["xp":10696000,]),49:(["xp":9723700,]),48:(["xp":8839800,]),47:(["xp":8036200,]),46:(["xp":7305700,]),45:(["xp":6641600,]),44:(["xp":6037900,]),43:(["xp":5489000,]),42:(["xp":4990000,]),41:(["xp":4536400,]),40:(["qp":450,"xp":4124000,]),39:(["xp":3749100,]),38:(["qp":285,"xp":3408300,]),37:(["xp":3098500,]),36:(["qp":252,"xp":2816900,]),35:(["xp":2560900,]),34:(["qp":221,"xp":2328100,]),33:(["xp":2116500,]),32:(["qp":192,"xp":1924100,]),31:(["xp":1749200,]),30:(["qp":165,"xp":1590200,]),29:(["xp":1445700,]),28:(["qp":140,"xp":1314300,]),27:(["xp":1194900,]),26:(["qp":117,"xp":1086300,]),25:(["xp":987600,]),24:(["qp":96,"xp":823000,]),23:(["xp":685900,]),22:(["qp":77,"xp":571600,]),21:(["xp":476400,]),20:(["title":"the Caesar/the Caesara","qp":60,"xp":397000,]),19:(["title":"the Quaestor/the Quaestrix","xp":330900,]),18:(["title":"the Praetor/the Praetrix","qp":45,"xp":275800,]),17:(["title":"the Archduke/the Archduchess","xp":229900,]),16:(["title":"the Duke/the Duchess","qp":32,"xp":191600,]),15:(["title":"the Marquis/the Marquise","xp":147400,]),14:(["title":"the Earl/the Countess","qp":21,"xp":113400,]),13:(["title":"the Count/the Viscountess","xp":87300,]),12:(["title":"the Baron/the Baroness","qp":12,"xp":67200,]),11:(["title":"the Knight","xp":48000,]),10:(["title":"the Citizen","qp":5,"xp":34300,]),9:(["title":"the Freeman/the Freewoman","xp":22900,]),8:(["title":"the master adventurer/the master adventuress","xp":15300,]),7:(["title":"the great adventurer/the great adventuress","xp":9600,]),6:(["title":"the expert adventurer/the expert adventuress","xp":5700,]),5:(["title":"the experienced adventurer/the experienced adventuress","xp":3200,]),4:(["title":"the adventurer/the adventuress","xp":1700,]),3:(["title":"the beginner","xp":900,]),2:(["title":"the simple novice","xp":500,]),1:(["title":"the utter novice ","qp":0,"xp":0,]),0:(["qp":0,"xp":0,]),]) diff --git a/lib/secure/save/players/b/bumble.o b/lib/secure/save/players/b/bumble.o new file mode 100644 index 0000000..01b66f5 --- /dev/null +++ b/lib/secure/save/players/b/bumble.o @@ -0,0 +1,127 @@ +#/secure/save/players/b/bumble.c +InternalDesc 0 +Opacity 0 +PersistentInventory 0 +PersistentInventoryEnabled 0 +ProperNoun 1 +Modify 1 +Short "$N the unaccomplished" +CapName "Bumble" +ExternalDesc "$N is nondescript." +Invisible 0 +Items ([]) +Properties (["minimapping":1,"brand_spanking_new":0,"LastLocation":"/domains/default/room/death",]) +Inventory ({}) +anchored 0 +Messages (["telin":"$N teleports in.","telout":"$N teleports away.","leave":"$N leaves $D.","vis":"$N appears.","invis":"$N disappears.","home":"$N goes home.","dest":"$N dests $O.","come":"$N enters.","clone":"$N clones $O.",]) +RestrictedChannels ({}) +NoChanColors 0 +GagMutes (["remote_gag":0,"remote_mute":0,"local_mute":0,"local_gag":0,]) +Paused 0 +localcmds ({"parserefresh","quit","nickname","unalias","alias","",}) +parsed_command "quit" +HistorySize 50 +History ([6:"quit",5:"wander",4:"wande",3:"enter oogtopia",2:"update",1:"wear shirt",0:"wear jeans",]) +Nicknames ([]) +Aliases (["east":"go east","mwhere":"findobj $*","southeast":"go southeast","northeast":"go northeast","prac":"skills","sco":"score","x":"look at $*","w":"go west","u":"go up","t":"tell $*","out":"go out","practice":"skills","s":"go south","vnum":"help find","p":"people","south":"go south","north":"go north","n":"go north","bio":"biography","l":"look $*","k":"kill $*","west":"go west","zlist":"domains","southwest":"go southwest","northwest":"go northwest","i":"inventory","owhere":"findobj $*","e":"go east","d":"go down","c":"cre $*","alist":"ls /domains","inv":"inventory","nw":"go northwest","examine":"look at $*","trophy":"kills","up":"go up","chat":"newbie $*","dc":"dchat $*","exa":"look at $*","sw":"go southwest","ig":"intergossip $*","loot":"get all from $*","ic":"intercre $*","peace":"quell","inf":"score","lp":"lpuni $*","down":"go down","ne":"go northeast","exit":"go out","eq":"equipment","se":"go southeast","sc":"status",]) +Xverbs (["'":"say $*","]":"] $*","\"":"say $*",":":"emote $*",]) +Directories (["current":"/","home":0,"previous":"/",]) +Prompt "status" +Terminal "xterm" +Blocked ([]) +Screen ({79,24,}) +MessageQueue 0 +PauseMessages 0 +annoyblock 0 +MessageExceptions 0 +BlockAnnoying 0 +Age 0 +WhereBlock 0 +Brief 0 +LoginTime 1599371465 +BirthTime 1599371444 +RescueBit 0 +Password "ngfl`lig!hgge`fbiobkhahnejiboadmdf`ihgbfb" +Email "babylon_horuv@zoho.com" +RealName "Unknown" +Rank "citizen" +LoginSite "/domains/begin/room/start" +HostSite "127.0.0.1" +WebPage 0 +News (["general":1233553350,]) +Marriages ({}) +Paranoia (["homeroom":"/tmp/workroom",]) +MaxCarry 0 +PreventDrop 0 +DestructOnDrop 0 +PreventGet 0 +NoSink 0 +Position 8 +Undead 0 +UndeadType 0 +Mount 0 +Riders ({}) +BodyMass 0 +SaveRecurse 0 +Saved ({"Properties",}) +HealthPoints 141 +MagicPoints 55 +ExperiencePoints 50 +ExperienceDebt 1 +melee 0 +godmode 0 +Alcohol 0 +Caffeine 0 +Food 91 +Drink 91 +Poison 0 +Sleeping 0 +StaminaPoints 144.500000 +Torso "torso" +Biter 0 +keepalive 0 +Fingers (["right hand":5,"left hand":5,]) +Limbs (["left leg":(["children":({"left foot",}),"armors":1049761,"health":190,"class":2,"parent":"torso",]),"torso":(["children":({"neck","right leg","left leg","right arm","left arm",}),"armors":1538049,"health":380,"class":1,"parent":0,]),"right foot":(["children":({}),"armors":241,"health":100,"class":4,"parent":"right leg",]),"right leg":(["children":({"right foot",}),"armors":1049761,"health":190,"class":2,"parent":"torso",]),"head":(["children":({}),"armors":262913,"health":380,"class":1,"parent":"neck",]),"right hand":(["children":({}),"armors":98319,"health":100,"class":4,"parent":"right arm",]),"neck":(["children":({"head",}),"armors":786433,"health":380,"class":1,"parent":"torso",]),"left arm":(["children":({"left hand",}),"armors":1253385,"health":190,"class":2,"parent":"torso",]),"left foot":(["children":({}),"armors":241,"health":100,"class":4,"parent":"left leg",]),"left hand":(["children":({}),"armors":98319,"health":100,"class":4,"parent":"left arm",]),"right arm":(["children":({"right hand",}),"armors":1253385,"health":190,"class":2,"parent":"torso",]),]) +MissingLimbs ([]) +firearms_wounds 0 +Falling 0 +FallCount 1 +ExtraChannels ({"explorer","gossip","newbie",}) +Agent +Blind 0 +Custom (["stats":15,"deviations":4,"deviating":0,]) +LightSensitivity ({25,7500,}) +Resistance (["low":0,"high":0,"immune":0,"medium":0,"none":134217726,]) +Stats (["agility":(["class":3,"points":0,"level":41,]),"wisdom":(["class":3,"points":0,"level":58,]),"speed":(["class":3,"points":0,"level":46,]),"coordination":(["class":2,"points":0,"level":33,]),"intelligence":(["class":1,"points":0,"level":69,]),"strength":(["class":3,"points":0,"level":34,]),"luck":(["class":3,"points":0,"level":28,]),"durability":(["class":4,"points":0,"level":37,]),"charisma":(["class":2,"points":0,"level":57,]),]) +Polyglot 0 +Languages (["capitalist":(["native":1,"name":"Capitalist","points":0,"level":100,]),"common":(["native":0,"name":"Common","points":0,"level":100,]),]) +DefaultLanguage "Common" +TalkHist ([]) +SpeakColor "CYAN%^" +Town "Town" +Race "ancap" +Gender "female" +Level 1 +Skills (["psionic defense":(["class":3,"points":0,"level":2,]),"magic defense":(["class":2,"points":0,"level":3,]),"melee defense":(["class":2,"points":0,"level":2,]),"projectile attack":(["class":1,"points":0,"level":1,]),"blunt defense":(["class":1,"points":0,"level":2,]),"knife defense":(["class":1,"points":0,"level":2,]),"melee attack":(["class":2,"points":250,"level":1,]),"projectile defense":(["class":2,"points":0,"level":1,]),"blade defense":(["class":2,"points":216,"level":2,]),"bargaining":(["class":2,"points":0,"level":4,]),"magic attack":(["class":2,"points":0,"level":3,]),"blunt attack":(["class":1,"points":0,"level":2,]),"knife attack":(["class":1,"points":0,"level":3,]),"blade attack":(["class":2,"points":0,"level":1,]),]) +Morality 0 +Class "explorer" +Clan 0 +SkillModifiers ([]) +Religion ({0,0,}) +Wimpy 0 +Dead 0 +WimpyCommand "go out" +Currency (["silver":0,]) +Bank ([]) +SpellBook ([]) +QuestPoints 0 +QuestBook ([]) +isPK 0 +Attackable 1 +NoCondition 0 +Titles ({}) +Muffed ({}) +Deaths ({(["date":"Sat Sep 05 22:52:47 2020","enemy":"Ooga",]),}) +TrainingPoints 0 +TitleLength 1 +telopt_ip 0 diff --git a/lib/secure/save/players/d/deskarnull.o b/lib/secure/save/players/d/deskarnull.o new file mode 100644 index 0000000..4ac0463 --- /dev/null +++ b/lib/secure/save/players/d/deskarnull.o @@ -0,0 +1,127 @@ +#/secure/save/players/d/deskarnull.c +InternalDesc 0 +Opacity 0 +PersistentInventory 0 +PersistentInventoryEnabled 0 +ProperNoun 1 +Modify 1 +Short "$N the unaccomplished" +CapName "DeskarNull" +ExternalDesc "$N is nondescript." +Invisible 0 +Items ([]) +Properties (["minimapping":1,"brand_spanking_new":0,"ReturnSite":"/domains/default/room/start","LastLocation":"/domains/default/room/death",]) +Inventory ({}) +anchored 0 +Messages (["telin":"$N teleports in.","leave":"$N leaves $D.","telout":"$N teleports away.","vis":"$N appears.","home":"$N goes home.","invis":"$N disappears.","come":"$N enters.","dest":"$N dests $O.","clone":"$N clones $O.",]) +RestrictedChannels ({}) +NoChanColors 0 +GagMutes (["remote_mute":0,"remote_gag":0,"local_mute":0,"local_gag":0,]) +Paused 0 +localcmds ({"parserefresh","quit","nickname","unalias","alias","",}) +parsed_command "quit" +HistorySize 50 +History ([2:"wander",1:"wear shirt",0:"wear jeans",]) +Nicknames ([]) +Aliases (["east":"go east","northeast":"go northeast","southeast":"go southeast","mwhere":"findobj $*","prac":"skills","sco":"score","x":"look at $*","w":"go west","u":"go up","out":"go out","t":"tell $*","s":"go south","practice":"skills","vnum":"help find","p":"people","north":"go north","south":"go south","bio":"biography","n":"go north","l":"look $*","west":"go west","k":"kill $*","northwest":"go northwest","southwest":"go southwest","zlist":"domains","i":"inventory","owhere":"findobj $*","e":"go east","d":"go down","c":"cre $*","alist":"ls /domains","nw":"go northwest","inv":"inventory","examine":"look at $*","trophy":"kills","up":"go up","chat":"newbie $*","dc":"dchat $*","sw":"go southwest","exa":"look at $*","ig":"intergossip $*","loot":"get all from $*","ic":"intercre $*","peace":"quell","inf":"score","down":"go down","lp":"lpuni $*","ne":"go northeast","eq":"equipment","exit":"go out","se":"go southeast","sc":"status",]) +Xverbs (["'":"say $*","]":"] $*",":":"emote $*","\"":"say $*",]) +Directories (["current":"/","home":0,"previous":"/",]) +Prompt "status" +Terminal "xterm" +Blocked ([]) +Screen ({79,24,}) +MessageQueue 0 +PauseMessages 0 +annoyblock 0 +MessageExceptions 0 +BlockAnnoying 0 +Age 0 +WhereBlock 0 +Brief 0 +LoginTime 1599275869 +BirthTime 1599109682 +RescueBit 0 +Password "nnjonamd!ed`kkomia`edheciffmigmbllghjoldf" +Email "babylon_horuv@zoho.com" +RealName "Unknown" +Rank "citizen" +LoginSite "/domains/default/room/start" +HostSite "127.0.0.1" +WebPage 0 +News (["general":1233553350,]) +Marriages ({}) +Paranoia (["homeroom":"/estates/d/deskarnull/workroom",]) +MaxCarry 0 +PreventDrop 0 +DestructOnDrop 0 +PreventGet 0 +NoSink 0 +Position 8 +Undead 0 +UndeadType 0 +Mount 0 +Riders ({}) +BodyMass 0 +SaveRecurse 0 +Saved ({"Properties",}) +HealthPoints 132 +MagicPoints 8 +ExperiencePoints 50 +ExperienceDebt 1 +melee 0 +godmode 0 +Alcohol 0 +Caffeine 0 +Food 98 +Drink 98 +Poison 0 +Sleeping 0 +StaminaPoints 124.700020 +Torso "torso" +Biter 0 +keepalive 0 +Fingers (["right hand":6,"left hand":6,]) +Limbs (["left leg":(["children":({"left foot",}),"armors":1049761,"health":200,"class":2,"parent":"torso",]),"torso":(["children":({"neck","right leg","left leg","left arm","right arm",}),"armors":1538049,"health":400,"class":1,"parent":0,]),"right foot":(["children":({}),"armors":241,"health":100,"class":4,"parent":"right leg",]),"right leg":(["children":({"right foot",}),"armors":1049761,"health":200,"class":2,"parent":"torso",]),"head":(["children":({}),"armors":262913,"health":400,"class":1,"parent":"neck",]),"right hand":(["children":({}),"armors":98319,"health":100,"class":4,"parent":"right arm",]),"neck":(["children":({"head",}),"armors":786433,"health":400,"class":1,"parent":"torso",]),"left arm":(["children":({"left hand",}),"armors":1253385,"health":200,"class":2,"parent":"torso",]),"left foot":(["children":({}),"armors":241,"health":100,"class":4,"parent":"left leg",]),"left hand":(["children":({}),"armors":98319,"health":100,"class":4,"parent":"left arm",]),"right arm":(["children":({"right hand",}),"armors":1253385,"health":200,"class":2,"parent":"torso",]),]) +MissingLimbs ([]) +firearms_wounds 0 +Falling 0 +FallCount 1 +ExtraChannels ({"explorer","gossip","newbie",}) +Agent 0 +Blind 0 +Custom (["stats":15,"deviations":4,"deviating":0,]) +LightSensitivity ({5,7100,}) +Resistance (["low":0,"high":0,"immune":0,"medium":0,"none":134217726,]) +Stats (["agility":(["class":2,"points":0,"level":31,]),"wisdom":(["class":5,"points":0,"level":3,]),"speed":(["class":2,"points":0,"level":49,]),"intelligence":(["class":3,"points":0,"level":12,]),"strength":(["class":1,"points":0,"level":40,]),"durability":(["class":2,"points":0,"level":39,]),"charisma":(["class":5,"points":0,"level":1,]),"coordination":(["class":3,"points":0,"level":51,]),"luck":(["class":4,"points":0,"level":8,]),]) +Polyglot 0 +Languages (["common":(["native":0,"name":"Common","points":0,"level":100,]),"booga":(["native":1,"name":"Booga","points":0,"level":100,]),]) +DefaultLanguage "Common" +TalkHist ([]) +SpeakColor "CYAN%^" +Town "Town" +Race "ooga" +Gender "male" +Level 1 +Skills (["magic defense":(["class":2,"points":0,"level":3,]),"melee defense":(["class":2,"points":0,"level":2,]),"projectile attack":(["class":1,"points":0,"level":1,]),"knife defense":(["class":1,"points":0,"level":2,]),"blunt defense":(["class":1,"points":0,"level":2,]),"melee attack":(["class":2,"points":0,"level":1,]),"projectile defense":(["class":2,"points":0,"level":1,]),"bargaining":(["class":2,"points":0,"level":4,]),"blade defense":(["class":2,"points":0,"level":1,]),"magic attack":(["class":2,"points":0,"level":3,]),"knife attack":(["class":1,"points":0,"level":3,]),"blunt attack":(["class":1,"points":0,"level":2,]),"blade attack":(["class":2,"points":0,"level":1,]),]) +Morality 0 +Class "explorer" +Clan 0 +SkillModifiers ([]) +Religion ({0,0,}) +Wimpy 0 +Dead 0 +WimpyCommand "go out" +Currency (["silver":0,]) +Bank ([]) +SpellBook ([]) +QuestPoints 0 +QuestBook ([]) +isPK 0 +Attackable 1 +NoCondition 0 +Titles ({}) +Muffed ({}) +Deaths ({(["date":"Fri Sep 04 20:18:07 2020","enemy":"Outer space",]),}) +TrainingPoints 0 +TitleLength 1 +telopt_ip 0 diff --git a/lib/secure/save/players/g/guest.o b/lib/secure/save/players/g/guest.o new file mode 100644 index 0000000..9793ba3 --- /dev/null +++ b/lib/secure/save/players/g/guest.o @@ -0,0 +1,126 @@ +#/secure/save/players/g/guest.c +InternalDesc 0 +Opacity 0 +PersistentInventory 0 +PersistentInventoryEnabled 0 +ProperNoun 1 +Modify 1 +Short "$N the unaccomplished" +CapName "Guest" +ExternalDesc "$N is nondescript." +Invisible 0 +Items ([]) +Properties (["minimapping":1,"brand_spanking_new":0,"LastLocation":"/domains/default/room/start",]) +Inventory ({"([\"Value\":0,\"Mass\":5,\"Worn\":({\"right leg\",\"left leg\",}),\"#base_name#\":\"/domains/default/armor/jeans\",\"Deterioration\":0,\"Broken\":0,\"Cost\":1,\"Properties\":([]),\"Poison\":0,])","([\"Value\":0,\"Mass\":5,\"Worn\":({\"torso\",}),\"#base_name#\":\"/domains/default/armor/shirt\",\"Deterioration\":0,\"Broken\":0,\"Cost\":1,\"Properties\":([]),\"Poison\":0,])","([\"Wielded\":0,\"Value\":0,\"Class\":1,\"Worn\":0,\"Deterioration\":0,\"Broken\":0,\"Poison\":0,\"Mass\":3,\"#base_name#\":\"/domains/default/obj/handbook\",\"Cost\":1000,\"Properties\":([\"no steal\":1,]),])",}) +Messages (["telin":"$N teleports in.","leave":"$N leaves $D.","telout":"$N teleports away.","vis":"$N appears.","home":"$N goes home.","invis":"$N disappears.","come":"$N enters.","dest":"$N dests $O.","clone":"$N clones $O.",]) +RestrictedChannels ({}) +NoChanColors 0 +local_mute 0 +remote_mute 0 +local_gag 0 +remote_gag 0 +Paused 0 +localcmds ({"parserefresh","quit","nickname","unalias","alias","",}) +next_command ({}) +HistorySize 50 +History ([3:"quit",2:"[A",1:"wear shirt",0:"wear jeans",]) +CurrentWorkingDirectory "/" +PreviousWorkingDirectory 0 +Nicknames ([]) +Aliases (["east":"go east","northeast":"go northeast","southeast":"go southeast","mwhere":"findobj $*","prac":"skills","sco":"score","x":"look at $*","w":"go west","u":"go up","out":"go out","t":"tell $*","s":"go south","practice":"skills","vnum":"help find","p":"people","north":"go north","south":"go south","bio":"biography","n":"go north","l":"look $*","west":"go west","k":"kill $*","northwest":"go northwest","southwest":"go southwest","zlist":"domains","i":"inventory","owhere":"findobj $*","e":"go east","d":"go down","c":"cre $*","alist":"ls /domains","nw":"go northwest","inv":"inventory","examine":"look at $*","trophy":"kills","up":"go up","chat":"newbie $*","dc":"dchat $*","sw":"go southwest","exa":"look at $*","ig":"intergossip $*","loot":"get all from $*","ic":"intercre $*","peace":"quell","inf":"score","down":"go down","lp":"lpuni $*","ne":"go northeast","eq":"equipment","exit":"go out","se":"go southeast","sc":"status",]) +Xverbs (["'":"say $*","]":"] $*",":":"emote $*","\"":"say $*",]) +Prompt "status" +Terminal "ansi" +Blocked ([]) +Screen ({79,24,}) +MessageQueue 0 +PauseMessages 0 +annoyblock 0 +MessageExceptions 0 +BlockAnnoying 0 +Age 0 +WhereBlock 0 +Brief 0 +LoginTime 1242677746 +BirthTime 1242059073 +RescueBit 0 +Password "gidddacg!`fkangglfgdobdliill`namhb`bkmloi" +Email "@" +RealName "Unknown" +Rank "citizen" +LoginSite "/domains/default/room/start" +HostSite "127.0.0.1" +WebPage 0 +News (["general":1233549750,"fighter":1152072058,]) +Marriages ({}) +Paranoia ([]) +MaxCarry 0 +PreventDrop 0 +DestructOnDrop 0 +PreventGet 0 +Position 2 +Undead 0 +UndeadType 0 +Mount 0 +Riders ({}) +BodyMass 0 +SaveRecurse 0 +Saved ({"Properties",}) +HealthPoints 400 +MagicPoints 660 +ExperiencePoints 50 +melee 1 +godmode 0 +Alcohol 0 +Caffeine 0 +Food 98 +Drink 98 +Poison 0 +Sleeping 0 +DeathEvents 0 +StaminaPoints 400.000000 +Torso "torso" +Biter 0 +keepalive 0 +Fingers (["right hand":5,"left hand":5,]) +Limbs (["left leg":(["children":({"left foot",}),"armors":1049761,"health":180,"class":2,"parent":"torso",]),"torso":(["children":({"neck","right leg","left leg","right arm","left arm",}),"armors":1538049,"health":360,"class":1,"parent":0,]),"right foot":(["children":({}),"armors":241,"health":90,"class":4,"parent":"right leg",]),"right leg":(["children":({"right foot",}),"armors":1049761,"health":180,"class":2,"parent":"torso",]),"head":(["children":({}),"armors":262913,"health":360,"class":1,"parent":"neck",]),"right hand":(["children":({}),"armors":98319,"health":90,"class":4,"parent":"right arm",]),"neck":(["children":({"head",}),"armors":786433,"health":360,"class":1,"parent":"torso",]),"left arm":(["children":({"left hand",}),"armors":1253385,"health":180,"class":2,"parent":"torso",]),"left foot":(["children":({}),"armors":241,"health":90,"class":4,"parent":"left leg",]),"left hand":(["children":({}),"armors":98319,"health":90,"class":4,"parent":"left arm",]),"right arm":(["children":({"right hand",}),"armors":1253385,"health":180,"class":2,"parent":"torso",]),]) +MissingLimbs ([]) +firearms_wounds 0 +ExtraChannels ({"newbie","gossip","fighter",}) +Agent 0 +Blind 0 +Custom (["stats":15,"deviations":4,"deviating":0,]) +LightSensitivity ({25,7500,}) +Resistance (["low":0,"high":0,"immune":0,"medium":0,"none":134217726,]) +Stats (["agility":(["class":3,"points":0,"level":35,]),"wisdom":(["class":3,"points":0,"level":46,]),"speed":(["class":3,"points":0,"level":44,]),"intelligence":(["class":1,"points":0,"level":61,]),"strength":(["class":3,"points":0,"level":34,]),"durability":(["class":4,"points":0,"level":35,]),"charisma":(["class":2,"points":0,"level":57,]),"coordination":(["class":2,"points":0,"level":45,]),"luck":(["class":3,"points":0,"level":20,]),]) +Polyglot 0 +Languages (["english":(["native":1,"name":"English","points":0,"level":100,]),"common":(["native":0,"name":"Common","points":0,"level":100,]),]) +DefaultLanguage "Common" +TalkHist ([]) +SpeakColor "CYAN%^" +Town "Town" +Race "human" +Gender "male" +Level 1 +Skills (["psionic defense":(["class":3,"points":0,"level":2,]),"multi-weapon":(["class":1,"points":0,"level":4,]),"melee defense":(["class":1,"points":0,"level":4,]),"projectile attack":(["class":1,"points":0,"level":1,]),"multi-hand":(["class":1,"points":0,"level":4,]),"blunt defense":(["class":1,"points":0,"level":4,]),"knife defense":(["class":1,"points":0,"level":4,]),"melee attack":(["class":1,"points":0,"level":4,]),"projectile defense":(["class":1,"points":0,"level":1,]),"blade defense":(["class":1,"points":0,"level":4,]),"bargaining":(["class":4,"points":0,"level":4,]),"blunt attack":(["class":1,"points":0,"level":4,]),"knife attack":(["class":1,"points":0,"level":4,]),"blade attack":(["class":1,"points":0,"level":4,]),]) +Morality 0 +Class "fighter" +Clan 0 +SkillModifiers ([]) +Religion ({0,0,}) +Wimpy 0 +Dead 0 +WimpyCommand "go out" +Currency (["silver":131,]) +Bank ([]) +SpellBook ([]) +QuestPoints 0 +QuestBook ([]) +isPK 0 +Attackable 1 +NoCondition 0 +Titles ({}) +Muffed ({}) +Deaths 0 +TrainingPoints 0 +TitleLength 1 diff --git a/lib/secure/save/players/g/gumpy.o b/lib/secure/save/players/g/gumpy.o new file mode 100644 index 0000000..3b82efc --- /dev/null +++ b/lib/secure/save/players/g/gumpy.o @@ -0,0 +1,127 @@ +#/secure/save/players/g/gumpy.c +InternalDesc 0 +Opacity 0 +PersistentInventory 0 +PersistentInventoryEnabled 0 +ProperNoun 1 +Modify 1 +Short "$N the unaccomplished" +CapName "Gumpy" +ExternalDesc "$N is nondescript." +Invisible 0 +Items ([]) +Properties (["minimapping":1,"brand_spanking_new":0,"LastLocation":"/domains/voluntaria/room/space",]) +Inventory ({"([\"Wielded\":0,\"Value\":0,\"Class\":1,\"Worn\":0,\"Deterioration\":0,\"Broken\":0,\"Poison\":0,\"Mass\":3,\"#base_name#\":\"/domains/default/obj/handbook\",\"Cost\":1000,\"Properties\":([\"no steal\":1,]),])","([\"Value\":0,\"Mass\":5,\"Worn\":({\"torso\",}),\"#base_name#\":\"/domains/default/armor/shirt\",\"Deterioration\":0,\"Broken\":0,\"Cost\":1,\"Properties\":([]),\"Poison\":0,])","([\"Value\":0,\"Mass\":5,\"Worn\":({\"right leg\",\"left leg\",}),\"#base_name#\":\"/domains/default/armor/jeans\",\"Deterioration\":0,\"Broken\":0,\"Cost\":1,\"Properties\":([]),\"Poison\":0,])",}) +anchored 0 +Messages (["telin":"$N teleports in.","telout":"$N teleports away.","leave":"$N leaves $D.","vis":"$N appears.","invis":"$N disappears.","home":"$N goes home.","dest":"$N dests $O.","come":"$N enters.","clone":"$N clones $O.",]) +RestrictedChannels ({}) +NoChanColors 0 +GagMutes (["remote_gag":0,"remote_mute":0,"local_mute":0,"local_gag":0,]) +Paused 0 +localcmds ({"parserefresh","quit","nickname","unalias","alias","",}) +parsed_command "quit" +HistorySize 50 +History ([11:"quit",10:"look babylon",9:"enter ship",8:"open airlock",7:"enter spaceship",6:"go west",5:"w",4:"go north",3:"n",2:"enter oogtopia",1:"wear shirt",0:"wear jeans",]) +Nicknames ([]) +Aliases (["east":"go east","mwhere":"findobj $*","southeast":"go southeast","northeast":"go northeast","prac":"skills","sco":"score","x":"look at $*","w":"go west","u":"go up","t":"tell $*","out":"go out","practice":"skills","s":"go south","vnum":"help find","p":"people","south":"go south","north":"go north","n":"go north","bio":"biography","l":"look $*","k":"kill $*","west":"go west","zlist":"domains","southwest":"go southwest","northwest":"go northwest","i":"inventory","owhere":"findobj $*","e":"go east","d":"go down","c":"cre $*","alist":"ls /domains","inv":"inventory","nw":"go northwest","examine":"look at $*","trophy":"kills","up":"go up","chat":"newbie $*","dc":"dchat $*","exa":"look at $*","sw":"go southwest","ig":"intergossip $*","loot":"get all from $*","ic":"intercre $*","peace":"quell","inf":"score","lp":"lpuni $*","down":"go down","ne":"go northeast","exit":"go out","eq":"equipment","se":"go southeast","sc":"status",]) +Xverbs (["'":"say $*","]":"] $*","\"":"say $*",":":"emote $*",]) +Directories (["current":"/","home":0,"previous":"/",]) +Prompt "status" +Terminal "xterm" +Blocked ([]) +Screen ({79,24,}) +MessageQueue 0 +PauseMessages 0 +annoyblock 0 +MessageExceptions 0 +BlockAnnoying 0 +Age 0 +WhereBlock 0 +Brief 0 +LoginTime 1599375009 +BirthTime 1599374996 +RescueBit 0 +Password "hmifdnaj!mailffmdhfikbfnhfmaglhkmnjhhgijf" +Email "babylon_horuv@zoho.com" +RealName "Unknown" +Rank "citizen" +LoginSite "/domains/voluntaria/room/airlock" +HostSite "127.0.0.1" +WebPage 0 +News (["general":1233553350,]) +Marriages ({}) +Paranoia (["homeroom":"/tmp/workroom",]) +MaxCarry 0 +PreventDrop 0 +DestructOnDrop 0 +PreventGet 0 +NoSink 0 +Position 2 +Undead 0 +UndeadType 0 +Mount 0 +Riders ({}) +BodyMass 0 +SaveRecurse 0 +Saved ({"Properties",}) +HealthPoints 551 +MagicPoints 170 +ExperiencePoints 50 +ExperienceDebt 0 +melee 0 +godmode 0 +Alcohol 0 +Caffeine 0 +Food 69 +Drink 69 +Poison 0 +Sleeping 0 +StaminaPoints 503.000000 +Torso "torso" +Biter 0 +keepalive 0 +Fingers (["right hand":6,"left hand":6,]) +Limbs (["left leg":(["children":({"left foot",}),"armors":1049761,"health":280,"class":2,"parent":"torso",]),"torso":(["children":({"neck","right leg","left leg","left arm","right arm",}),"armors":1538049,"health":550,"class":1,"parent":0,]),"right foot":(["children":({}),"armors":241,"health":140,"class":4,"parent":"right leg",]),"right leg":(["children":({"right foot",}),"armors":1049761,"health":280,"class":2,"parent":"torso",]),"head":(["children":({}),"armors":262913,"health":550,"class":1,"parent":"neck",]),"right hand":(["children":({}),"armors":98319,"health":140,"class":4,"parent":"right arm",]),"neck":(["children":({"head",}),"armors":786433,"health":550,"class":1,"parent":"torso",]),"left arm":(["children":({"left hand",}),"armors":1253385,"health":280,"class":2,"parent":"torso",]),"left foot":(["children":({}),"armors":241,"health":140,"class":4,"parent":"left leg",]),"left hand":(["children":({}),"armors":98319,"health":140,"class":4,"parent":"left arm",]),"right arm":(["children":({"right hand",}),"armors":1253385,"health":280,"class":2,"parent":"torso",]),]) +MissingLimbs ([]) +firearms_wounds 0 +Falling 0 +FallCount 1 +ExtraChannels ({"explorer","gossip","newbie",}) +Agent 0 +Blind 0 +Custom (["stats":15,"deviations":4,"deviating":0,]) +LightSensitivity ({5,7100,}) +Resistance (["low":0,"high":0,"immune":0,"medium":0,"none":134217726,]) +Stats (["wisdom":(["class":5,"points":0,"level":3,]),"agility":(["class":2,"points":0,"level":25,]),"speed":(["class":2,"points":0,"level":58,]),"coordination":(["class":3,"points":0,"level":41,]),"strength":(["class":1,"points":0,"level":44,]),"intelligence":(["class":3,"points":0,"level":12,]),"luck":(["class":4,"points":0,"level":12,]),"durability":(["class":2,"points":0,"level":54,]),"charisma":(["class":5,"points":0,"level":1,]),]) +Polyglot 0 +Languages (["common":(["native":0,"name":"Common","points":0,"level":100,]),"booga":(["native":1,"name":"Booga","points":0,"level":100,]),]) +DefaultLanguage "Common" +TalkHist ([]) +SpeakColor "CYAN%^" +Town "Town" +Race "ooga" +Gender "male" +Level 1 +Skills (["magic defense":(["class":2,"points":0,"level":3,]),"melee defense":(["class":2,"points":0,"level":2,]),"projectile attack":(["class":1,"points":0,"level":1,]),"blunt defense":(["class":1,"points":0,"level":2,]),"knife defense":(["class":1,"points":0,"level":2,]),"melee attack":(["class":2,"points":0,"level":1,]),"projectile defense":(["class":2,"points":0,"level":1,]),"blade defense":(["class":2,"points":0,"level":1,]),"bargaining":(["class":2,"points":0,"level":4,]),"magic attack":(["class":2,"points":0,"level":3,]),"blunt attack":(["class":1,"points":0,"level":2,]),"knife attack":(["class":1,"points":0,"level":3,]),"blade attack":(["class":2,"points":0,"level":1,]),]) +Morality 0 +Class "explorer" +Clan 0 +SkillModifiers ([]) +Religion ({0,0,}) +Wimpy 0 +Dead 0 +WimpyCommand "go out" +Currency (["silver":83,]) +Bank ([]) +SpellBook ([]) +QuestPoints 0 +QuestBook ([]) +isPK 0 +Attackable 1 +NoCondition 0 +Titles ({}) +Muffed ({}) +Deaths 0 +TrainingPoints 0 +TitleLength 1 +telopt_ip 0 diff --git a/lib/secure/save/postal/b/babylon/postalrc.o b/lib/secure/save/postal/b/babylon/postalrc.o new file mode 100644 index 0000000..4692ab3 --- /dev/null +++ b/lib/secure/save/postal/b/babylon/postalrc.o @@ -0,0 +1,3 @@ +#/secure/daemon/options.c +__MyGroups ([]) +__Options (["notify":1,]) diff --git a/lib/secure/save/postal/b/bumble/postalrc.o b/lib/secure/save/postal/b/bumble/postalrc.o new file mode 100644 index 0000000..4692ab3 --- /dev/null +++ b/lib/secure/save/postal/b/bumble/postalrc.o @@ -0,0 +1,3 @@ +#/secure/daemon/options.c +__MyGroups ([]) +__Options (["notify":1,]) diff --git a/lib/secure/save/postal/d/deskarnull/postalrc.o b/lib/secure/save/postal/d/deskarnull/postalrc.o new file mode 100644 index 0000000..4692ab3 --- /dev/null +++ b/lib/secure/save/postal/d/deskarnull/postalrc.o @@ -0,0 +1,3 @@ +#/secure/daemon/options.c +__MyGroups ([]) +__Options (["notify":1,]) diff --git a/lib/secure/save/postal/f/fluffster/postalrc.o b/lib/secure/save/postal/f/fluffster/postalrc.o new file mode 100644 index 0000000..4692ab3 --- /dev/null +++ b/lib/secure/save/postal/f/fluffster/postalrc.o @@ -0,0 +1,3 @@ +#/secure/daemon/options.c +__MyGroups ([]) +__Options (["notify":1,]) diff --git a/lib/secure/save/postal/g/gumpy/postalrc.o b/lib/secure/save/postal/g/gumpy/postalrc.o new file mode 100644 index 0000000..4692ab3 --- /dev/null +++ b/lib/secure/save/postal/g/gumpy/postalrc.o @@ -0,0 +1,3 @@ +#/secure/daemon/options.c +__MyGroups ([]) +__Options (["notify":1,]) diff --git a/lib/secure/save/reload.o b/lib/secure/save/reload.o new file mode 100644 index 0000000..3ab6ef9 --- /dev/null +++ b/lib/secure/save/reload.o @@ -0,0 +1,5 @@ +#/secure/daemon/reload.c +Reloadees ([]) +savefile "/secure/save/reload.o" +grooms ({}) +occupied_rooms ({}) diff --git a/lib/secure/save/votes/voting.o b/lib/secure/save/votes/voting.o new file mode 100644 index 0000000..075a409 --- /dev/null +++ b/lib/secure/save/votes/voting.o @@ -0,0 +1,3 @@ +#/secure/daemon/voting.c +mapVoting (["voted":({}),"votes":(["cleric":([]),"explorer":([]),"thief":([]),"mage":([]),"fighter":([]),]),"status":4,"candidates":(["cleric":({}),"explorer":({}),"thief":({}),"mage":({}),"fighter":({}),]),]) +mapCouncil ([]) diff --git a/lib/secure/scripts/bedlam.src b/lib/secure/scripts/bedlam.src new file mode 100644 index 0000000..c69b835 --- /dev/null +++ b/lib/secure/scripts/bedlam.src @@ -0,0 +1,25 @@ +# +# WARNING +# Do not use this script. It will screw up your mud. +# You were warned. +# +get box from suit +dest my boxes +clone /secure/obj/weirder +reload box +stressload 2 +arch +exa screen +eval return users()->eventForce("pk on") +eval return users()->eventForce("pk on") +eval return users()->SetProperty("wizmapping",1) +eval return objects( (: answers_to("wraith",$1) :) )->eventDestruct() +eval return objects( (: inherits(LIB_ROOM, $1) :) )->SetPlayerKill(1) +eval return objects( (: inherits(LIB_ROOM, $1) :) )->SetNightLight(30) +eval return objects( (: inherits(LIB_ROOM, $1) :) )->SetDayLight(30) +eval return objects( (: inherits(LIB_ROOM, $1) :) )->SetAmbientLight(30) +eval return objects( (: inherits(LIB_ROOM, $1) :) )->SetProperty("no attack",0) +eval return objects( (: living($1) :) )->SetProperty("wizmapping",1) +eval return users()->eventForce("kill all") +exa screen +eval return objects( (: living($1) && !interactive($1) :) )->eventForce("kill all") diff --git a/lib/secure/scripts/crat.src b/lib/secure/scripts/crat.src new file mode 100644 index 0000000..5534c33 --- /dev/null +++ b/lib/secure/scripts/crat.src @@ -0,0 +1,186 @@ +polyglottize me +unalias prac +unalias where +unalias inf +unalias sc +unalias practice +unalias trophy +unalias a +unalias aa +nickname skal Raudhrskal +alias a admin $* +alias nn newbie $* +alias aa go aft +alias sb go starboard +alias pp go port +alias ff go fore +alias lab goto /domains/campus/room/hazlab +alias shop goto /domains/town/room/shop +alias roshd goto /domains/Ylsrim/room/fighter_hall +alias start goto /domains/campus/room/start +alias obj cd /realms/$N/area/obj +alias arm cd /realms/$N/area/armor +alias armor cd /realms/$N/area/armor +alias weap cd /realms/$N/area/weap +alias weapon cd /realms/$N/area/weap +alias npc cd /realms/$N/area/npc +alias room cd /realms/$N/area/room +alias door cd /realms/$N/area/doors +alias town cd /domains/town +alias tobj cd /domains/town/obj +alias tarm cd /domains/town/armor +alias tarmor cd /domains/town/armor +alias tweap cd /domains/town/weap +alias tweapon cd /domains/town/weap +alias tnpc cd /domains/town/npc +alias troom cd /domains/town/room +alias tdoor cd /domains/town/doors +alias camp cd /domains/campus/obj +alias cobj cd /domains/campus/obj +alias carm cd /domains/campus/armor +alias carmor cd /domains/campus/armor +alias cweap cd /domains/campus/weap +alias cweapon cd /domains/campus/weap +alias cnpc cd /domains/campus/npc +alias croom cd /domains/campus/room +alias cdoor cd /domains/campus/doors +alias cave cd /domains/cave/obj +alias kobj cd /domains/cave/obj +alias karm cd /domains/cave/armor +alias karmor cd /domains/cave/armor +alias kweap cd /domains/cave/weap +alias kweapon cd /domains/cave/weap +alias knpc cd /domains/cave/npc +alias kroom cd /domains/cave/room +alias kdoor cd /domains/cave/doors +alias ketc cd /domains/cave/etc +alias default cd /domains/default +alias dobj cd /domains/default/obj +alias darm cd /domains/default/armor +alias darmor cd /domains/default/armor +alias dweap cd /domains/default/weap +alias dweapon cd /domains/default/weap +alias dnpc cd /domains/default/npc +alias droom cd /domains/default/room +alias ddoor cd /domains/default/doors +alias ami cd /domains/amigara +alias aobj cd /domains/amigara/obj +alias aarm cd /domains/amigara/armor +alias aarmor cd /domains/amigara/armor +alias aweap cd /domains/amigara/weap +alias aweapon cd /domains/amigara/weap +alias anpc cd /domains/amigara/npc +alias aroom cd /domains/amigara/room +alias adoor cd /domains/amigara/door +alias fort cd /domains/fort +alias fobj cd /domains/fort/obj +alias farm cd /domains/fort/armor +alias farmor cd /domains/fort/armor +alias fweap cd /domains/fort/weap +alias fweapon cd /domains/fort/weap +alias fnpc cd /domains/fort/npc +alias froom cd /domains/fort/room +alias fdoor cd /domains/fort/doors +alias ige intergossipemote $* +alias ice intercreemote $* +alias ce creemote $* +alias ae adminemote $* +alias fs free_speech $* +alias dw discworld-chat $* +alias cm coffeemud_universe $* +alias err tail /log/runtime +alias ecc tail /log/catch +alias perr tail /log/player_errors +alias area cd /realms/$N/area/ +alias cs codesay $* +alias sec cd /secure +alias sef cd /secure/sefun +alias sobj cd /secure/obj +alias sroom cd /secure/room +alias aw adminemote waves. +alias cw creemote waves. +alias welcome ds hi, $*. you can use this channel to ask questions. it's an intermud channel that dead souls muds listen to. +alias going everything is going extremely well +alias ngreet newbie hi, $*. let me know if you have any questions +alias cgreet cre hi, $*. let me know if you have any questions +alias us update /secure/daemon/imc2server/ssocket +alias uss update /secure/daemon/imc2server/server +alias ui update /secure/daemon/i3router/server +call me->AddChannel("french") +call me->AddChannel("mudnews") +call me->AddChannel("fluffos") +call me->AddChannel("ascii_art") +call me->AddChannel("intergossip") +call me->AddChannel("coffeemud_universe") +call me->AddChannel("free_speech") +call me->AddChannel("discworld-chat") +call me->AddChannel("discworld-cre") +call me->AddChannel("dgd") +call me->AddChannel("dutch") +call me->AddChannel("ibuild") +call me->AddChannel("ichat") +call me->AddChannel("imudnews") +call me->AddChannel("ifree") +call me->AddChannel("pchat") +call me->AddChannel("i2game") +call me->AddChannel("i2news") +call me->AddChannel("irc") +call me->RemoveChannel("havenlib") +call me->AddChannel("muds") +chan block muds +chan block i2game +chan block ibuild +chan block ievennia +chan unblock inews +chan unblock i2news +alias intermud intergossip http://lpmuds.net/intermud.html +alias porch goto /domains/town/room/porch +prompt $T %^BOLD%^%^BLUE%^$M%^RESET%^ %^BOLD%^$P%^RESET%^ > +alias crat source /secure/scripts/crat.src +alias crat2 source -q /secure/scripts/crat2.src +alias crat3 source -q /secure/scripts/crat3.src +alias testmud source -q /secure/scripts/testmud.src +alias ruckus source -q /secure/scripts/ruckus.src +alias bedlam source -q /secure/scripts/bedlam.src +alias mayhem source -q /secure/scripts/mayhem.src +alias indentall source /secure/scripts/indent.src +alias resetgrid source -q /secure/scripts/resetgrid.src +alias distclean source -q /secure/scripts/distclean.src +alias killflow source -q /secure/scripts/killflow.src +alias shutdown say wat +alias 1 dest bots +alias 2 update /secure/obj/robot +alias 3 clone /secure/obj/robot +alias 4 bot +alias 9 charmode on +alias 0 charmode off +unmuff mudbytes +earmuff reuters +earmuff gammon +earmuff azereth +earmuff blackdawn +earmuff sapid +earmuff NZHerald +earmuff TheOnion +earmuff Sandbox +earmuff TMS +earmuff arthmoor +earmuff MudBytes-Files +earmuff SlayRadio +earmuff Metaplace +earmuff SmaugMuds +gag on +godmode on +wizvision on +call me->SetSkill("magic attack",100) +call me->SetSkill("magic defense",100) +call me->SetSkill("conjuring",100) +#screen 80 24 +history 100 +automap on +showgrid on +debug on +commandecho red +save +mudconfig consoletrace on +mudconfig logremote on diff --git a/lib/secure/scripts/crat2.src b/lib/secure/scripts/crat2.src new file mode 100644 index 0000000..62dd815 --- /dev/null +++ b/lib/secure/scripts/crat2.src @@ -0,0 +1,37 @@ +#title %^RED%^Red $N%^RESET%^ +#title %^GREEN%^Green $N%^RESET%^ +#title %^BLUE%^Blue $N%^RESET%^ +describe $N looks a bit rumpled and tired. +home +update +clean +cd ~/area/obj +clone chest +open chest +look in chest +get all from chest +wear robe +wear hat +wear my first glasses +wear my first ring +clone /domains/town/obj/8ball +clone /domains/town/obj/d20 +clone /domains/town/obj/d6 +clone /domains/campus/weap/grenade +clone /domains/campus/weap/waterpistol +clone /domains/campus/obj/omni +clone /domains/town/obj/pipe +clone /domains/town/obj/match +clone /domains/town/obj/match +clone /domains/town/obj/match +clone /domains/town/obj/match +clone /domains/town/obj/match +clone /domains/default/obj/gps +clone /secure/obj/weirder.c +put all in my robe +drop chest +drop bin +cd ~- +save +update + diff --git a/lib/secure/scripts/crat3.src b/lib/secure/scripts/crat3.src new file mode 100644 index 0000000..cccda50 --- /dev/null +++ b/lib/secure/scripts/crat3.src @@ -0,0 +1,126 @@ +start +open door +n +n +s +s +n +goto /domains/Praxis/square +eval return ROOMS_D->SetRoom(environment(this_player()), this_player(), "1000,-1000,0") +goto /domains/Ylsrim/room/bazaar +eval return ROOMS_D->SetRoom(environment(this_player()), this_player(), "1000,1000,0") +n +enter hall +u +start +n +w +open door +s +d +w +push wall +w +w +s +n +n +n +n +n +d +e +e +u +open grate +eval return ROOMS_D->UnSetRoom(environment(this_player())) +start +n +w +w +w +n +n +n +clone /domains/default/npc/drone +clone /domains/default/npc/drone +n +n +e +n +s +s +s +s +e +e +e +e +noclip east +clone /domains/default/npc/drone +clone /domains/default/npc/drone +clone /domains/default/npc/drone +shop +s +w +w +w +w +w +n +n +clone /domains/default/npc/drone +clone /domains/default/npc/drone +clone /domains/default/npc/drone +s +s +w +w +noclip north +noclip west +wiz +e +e +e +s +start +n +w +w +w +s +w +n +s +noclip south +n +e +noclip south +s +n +w +e +e +w +noclip north +n +n +n +n +n +n +w +w +s +noclip south +noclip south +clone /domains/default/npc/drone +clone /domains/default/npc/drone +arch +n +s +d +e +w +s +home diff --git a/lib/secure/scripts/distclean.src b/lib/secure/scripts/distclean.src new file mode 100644 index 0000000..7952cb4 --- /dev/null +++ b/lib/secure/scripts/distclean.src @@ -0,0 +1,6 @@ +restore /secure/include/network.h +#source /secure/scripts/indent.src +dest weirder +clone /secure/obj/weirder +reload weirder +loadall diff --git a/lib/secure/scripts/general_check.txt b/lib/secure/scripts/general_check.txt new file mode 100644 index 0000000..d73ebf7 --- /dev/null +++ b/lib/secure/scripts/general_check.txt @@ -0,0 +1,17 @@ +home +d +n +n +n +n +update +home +d +e +s +s +get medtric from pants +invis +infect elephant rage +infect balrog rage + diff --git a/lib/secure/scripts/grid.src b/lib/secure/scripts/grid.src new file mode 100644 index 0000000..23e31b1 --- /dev/null +++ b/lib/secure/scripts/grid.src @@ -0,0 +1,19 @@ +eval return ROOMS_D->zero() +eval return MAP_D->zero() +goto /domains/campus/room/start +clone /domains/default/npc/drone +goto /domains/Ylsrim/room/tower +gridconfig set here 1000,1001,1 +clone /domains/default/npc/drone +goto /domains/Praxis/square +gridconfig set here 1000,-1000,0 +clone /domains/default/npc/drone +goto /domains/town/room/mansion_int +gridconfig set here -5,3,0 +clone /domains/default/npc/drone +goto /domains/town/room/mansion_uhall1 +gridconfig set here -5,3,1 +clone /domains/default/npc/drone +goto /domains/town/room/cave_entrance +gridconfig set here -7,32,0 +clone /domains/default/npc/drone diff --git a/lib/secure/scripts/indent.src b/lib/secure/scripts/indent.src new file mode 100644 index 0000000..50b05b5 --- /dev/null +++ b/lib/secure/scripts/indent.src @@ -0,0 +1,50 @@ +cd /lib +indent * +indent */* +cd /cmds +indent */* +cd /daemon +indent * +cd /daemon/services +indent * +cd /domains/Ylsrim +indent */* +cd /domains/campus +indent */* +cd /domains/town +indent */* +cd /domains/default +indent */* +cd /domains/fort +indent */* +cd /domains/Praxis +indent * +indent */* +cd /domains/Praxis/obj +indent */* +cd /domains/Praxis/cematary +indent */* +cd /domains/examples +indent */* +cd /obj +indent * +cd /secure +indent */* +cd /secure/cmds +indent */* +cd /secure/lib +indent */* +cd /secure/lib/net +indent */* +cd /secure/daemon +indent */* +cd /spells +indent * +cd /verbs +indent */* +cd /secure/daemon/i3router +indent * +cd /shadows +indent * +cd /www/cgi +indent * diff --git a/lib/secure/scripts/killflow.src b/lib/secure/scripts/killflow.src new file mode 100644 index 0000000..b4fd2a5 --- /dev/null +++ b/lib/secure/scripts/killflow.src @@ -0,0 +1,2 @@ +eval return objects( (: inherits(LIB_FLOW, $1) :) )->eventDestruct() +eval return objects( (: base_name($1) == LIB_FLOW :) )->eventDestruct() diff --git a/lib/secure/scripts/ligana.src b/lib/secure/scripts/ligana.src new file mode 100644 index 0000000..5077c02 --- /dev/null +++ b/lib/secure/scripts/ligana.src @@ -0,0 +1,102 @@ +say 1 +say 2 +say 3 +say 4 +say 5 +say 6 +say 7 +say 8 +say 9 +say 10 +say 11 +say 12 +say 13 +say 14 +say 15 +say 16 +say 17 +say 18 +say 19 +say 20 +say 21 +say 22 +say 23 +say 24 +say 25 +say 26 +say 27 +say 28 +say 29 +say 30 +say 31 +say 32 +say 33 +say 34 +say 35 +say 36 +say 37 +say 38 +say 39 +say 40 +say 41 +say 42 +say 43 +say 44 +say 45 +say 46 +say 47 +say 48 +say 49 +say 50 +say 51 +say 52 +say 53 +say 54 +say 55 +say 56 +say 57 +say 58 +say 59 +say 60 +say 61 +say 62 +say 63 +say 64 +say 65 +say 66 +say 67 +say 68 +say 69 +say 70 +say 71 +say 72 +say 73 +say 74 +say 75 +say 76 +say 77 +say 78 +say 79 +say 80 +say 81 +say 82 +say 83 +say 84 +say 85 +say 86 +say 87 +say 88 +say 89 +say 90 +say 91 +say 92 +say 93 +say 94 +say 95 +say 96 +say 97 +say 98 +say 99 +say 100 + + diff --git a/lib/secure/scripts/mass_update.src b/lib/secure/scripts/mass_update.src new file mode 100644 index 0000000..dee2abe --- /dev/null +++ b/lib/secure/scripts/mass_update.src @@ -0,0 +1,84 @@ +cd /lib +update -r * +cd /cmds +update admins/* +update common/* +update creators/* +update hm/* +update players/* +update builders/* +cd / +update daemon/services/* +update daemon/* +update obj/* +cd /secure/cmds +update admins/* +update common/* +update creators/* +update hm/* +update players/* +update builders/* +cd /secure/ +update daemon/* +update lib/net/* +update lib/* +update modules/* +update npc/* +update obj/* +update room/* +cd verbs +update creators/* +cd / +update shadows/* +update std/* +cd verbs +update admins/* +update common/* +update creators/* +update hm/* +update players/* +update builders/* +update items/* +update rooms/* +update spells/* +update undead/* +cd /domains/campus +update armor/* +update doors/* +update meals/* +update npc/* +update obj/* +update room/* +update weap/* +update vehicles/* +cd /domains/town +update armor/* +update doors/* +update meals/* +update npc/* +update obj/* +update room/* +update weap/* +update vehicles/* +cd /domains/default +update armor/* +update doors/* +update meals/* +update npc/* +update obj/* +update room/* +update weap/* +update vehicles/* +cd /domains/Praxis +update * +cd /domains/Ylsrim +update armor/* +update doors/* +update meals/* +update npc/* +update obj/* +update room/* +update weap/* +update vehicles/* + + diff --git a/lib/secure/scripts/mayhem.src b/lib/secure/scripts/mayhem.src new file mode 100644 index 0000000..5c450c2 --- /dev/null +++ b/lib/secure/scripts/mayhem.src @@ -0,0 +1,30 @@ +# +# WARNING +# Do not use this script. It will screw up your mud. +# You were warned. +# +get box from suit +dest my boxes +clone /secure/obj/weirder +reload box +stressload 2 +arch +exa screen +eval return users()->eventForce("pk on") +eval return users()->eventForce("pk on") +eval return new("/domains/default/npc/drone2")->eventMove(ROOM_START) +eval return new("/domains/default/npc/drone2")->eventMove("/domains/default/room/menagerie")) +eval return new("/domains/default/npc/drone2")->eventMove("/domains/cave/room/chieftain")) +eval return new("/domains/default/npc/drone2")->eventMove("/domains/Praxis/square")) +eval return new("/domains/default/npc/drone2")->eventMove("/domains/Ylsrim/room/bazaar")) +eval return users()->SetProperty("wizmapping",1) +eval return objects( (: answers_to("wraith",$1) :) )->eventDestruct() +eval return objects( (: inherits(LIB_ROOM, $1) :) )->SetPlayerKill(1) +eval return objects( (: inherits(LIB_ROOM, $1) :) )->SetNightLight(30) +eval return objects( (: inherits(LIB_ROOM, $1) :) )->SetDayLight(30) +eval return objects( (: inherits(LIB_ROOM, $1) :) )->SetAmbientLight(30) +eval return objects( (: inherits(LIB_ROOM, $1) :) )->SetProperty("no attack",0) +eval return objects( (: living($1) :) )->SetProperty("wizmapping",1) +eval return users()->eventForce("kill all") +exa screen +eval return objects( (: living($1) && !interactive($1) :) )->eventForce("kill all") diff --git a/lib/secure/scripts/missile.src b/lib/secure/scripts/missile.src new file mode 100644 index 0000000..8e88f29 --- /dev/null +++ b/lib/secure/scripts/missile.src @@ -0,0 +1,3 @@ +clone /lib/missile +call missile->SetRange(100000) +call missile->SetSpeed(100) diff --git a/lib/secure/scripts/native_version.proto b/lib/secure/scripts/native_version.proto new file mode 100644 index 0000000..a017b61 --- /dev/null +++ b/lib/secure/scripts/native_version.proto @@ -0,0 +1 @@ +string native_version() { return "UNKNOWN"; } diff --git a/lib/secure/scripts/nm3.lsed b/lib/secure/scripts/nm3.lsed new file mode 100644 index 0000000..0495b02 --- /dev/null +++ b/lib/secure/scripts/nm3.lsed @@ -0,0 +1,159 @@ +g/inherit INDOOR_ROOM/s/inherit INDOOR_ROOM/inherit LIB_ROOM +g/inherit M_GETTABLE\;/s/inherit M_GETTABLE\;// +g/inherit M_VALUABLE\;/s/inherit M_VALUABLE\;// +g/inherit M_WEARABLE\;/s/inherit M_WEARABLE\;/inherit LIB_ARMOR;/ +g/inherit OBJ\;/s/inherit OBJ\;/inherit LIB_ITEM\; +g/void setup\(\)/s/void setup\(\)/void create\(\) +g/RACE_D/s/RACE_D/RACES_D +g/set\(\"day long\"\,/s/set\(\"day long\"\,/SetDayLong\( +g/set\(\"night long\"\,/s/set\(\"night long\"\,/SetNightLong\( +g/inherit \"\/std\/barkeep\"/s/inherit \"\/std\/barkeep\"/inherit LIB_BARKEEP +g/set_chance/s/set_chance/SetChance +g/set_max_fishing/s/set_max_fishing/SetMaxFishing +g/inherit PIER/s/inherit PIER/inherit LIB_FISHING +g/\-\>move\(/s/\-\>move\(/\-\>eventMove\( +g/remove_item_description/s/remove_item_description/RemoveItem +g/remove_exit/s/remove_exit/RemoveExit +g/query_max_sp/s/query_max_sp/GetMaxStaminaPoints +g/set_sp/s/set_sp/SetStaminaPoints +g/inherit \"\/std\/vendor\"/s/inherit \"\/std\/vendor\"/inherit \"\/lib\/std\/vendor\" +g/\/std\/vote_room/s/\/std\/vote_room/\/domains\/town\/room\/voters +g/inherit \"std\/vault\"/s/inherit \"std\/vault\"/inherit \"\/lib\/std\/room\" +g/add_intox/s/add_intox/AddAlcohol +g/set_day_long/s/set_day_long/SetDayLong +g/set_night_long/s/set_night_long/SetNightLong +g/set_door/s/set_door/SetDoor +g/set_open/s/set_open/SetOpen +g/query_open/s/query_open/GetOpen +g/inherit VAULT/s/inherit VAULT/inherit LIB_ROOM +g/move_player/s/move_player/eventMoveLiving +g/\"\/std\/obj\/torch\"/s/\"\/std\/obj\/torch\"/\"\/domains\/town\/obj\/torch\" +g/\"std\/obj\/torch\"/s/\"std\/obj\/torch\"/\"\/domains\/town\/obj\/torch\" +g/set\(\"long\"\,/s/set\(\"long\"\,/SetLong\( +g/set\(\"short\"\,/s/set\(\"short\"\,/SetShort\( +g/set\(\"race\"\,/s/set\(\"race\"\,/SetRace\( +g/new\(\"std\/weapon\"\)/s/new\(\"std\/weapon\"\)/new\(LIB_ITEM\) +g/new\(WEAPON\)/s/new\(WEAPON\)/new\(LIB_ITEM\) +g/new\(OBJECT\)/s/new\(OBJECT\)/new\(LIB_ITEM\) +g/remove\(\)/s/remove\(\)/destruct\(\) +g/inherit WEAPON/s/inherit WEAPON/inherit LIB_ITEM +g/set_wc/s/set_wc/SetClass +g/set_wield/s/set_wield/SetWield +g/SetWield_string/s/SetWield_string/SetWield +g/\"\/std\/weapon\"/s/\"\/std\/weapon\"/LIB_ITEM +g/set_die/s/set_die/SetDie +g/monster::create/s/monster::create/npc::create +g/monster::init/s/monster::init/npc::init +g/force_me/s/force_me/eventForce +g/add_money/s/add_money/AddCurrency +g/set_currency/s/set_currency/SetLocalCurrency +g/set_item_types/s/set_item_types/SetVendorType +g/set_storage_room/s/set_storage_room/SetStorageRoom +g/inherit BARKEEP/s/inherit BARKEEP/inherit LIB_BARKEEP +g/set_menu/s/set_menu/SetMenu +g/set_max_mp/s/set_max_mp/SetMaxMagicPoints +g/set_stats/s/set_stats/SetStat +g/set_chats/s/set_chats/SetAction +g/set_speech/s/set_speech/SetAction +g/set_skill/s/set_skill/SetSkill +g/set_class/s/set_class/SetClass +g/set_languages/s/set_languages/SetLanguage +g/set_lang_prof/s/set_lang_prof/SetLanguage +g/set_speed/s/set_speed/SetWanderSpeed +g/set_stats/s/set_stats/SetStats +g/set_mp/s/set_mp/SetMagicPoints +g/set_spell_chance/s/set_spell_chance/SetSpellChance +g/set_spells/s/set_spells/SetSpells +g/set_poisoning/s/set_poisoning/SetPoisonStrength +g/\"\/std\/poison\"/s/\"\/std\/poison\"/LIB_MEAL_POISON +g/set_eat/s/set_eat/SetMealMessages +g/set_strength/s/set_strength/SetStrength +g/SetMealStrength/s/SetMealStrength/SetStrength +g/inherit FOOD/s/inherit FOOD/inherit LIB_MEAL +g/set_weight/s/set_weight/SetMass +g/set_no_clean/s/set_no_clean/SetNoClean +g/set_communicable/s/set_communicable/SetCommunicable +g/set_cure/s/set_cure/SetCure +g/set_life_span/s/set_life_span/SetLifeSpan +g/inherit GERM/s/inherit GERM/inherit LIB_GERM +g/set_can_close/s/set_can_close/SetCanClose +g/set_prevent_get/s/set_prevent_get/SetPreventGet +g/set_can_lock/s/set_can_lock/SetCanLock +g/set_key/s/set_key/SetKey +g/OB_COINS/s/OB_COINS/LIB_PILE +g/set_closed/s/set_closed/SetClosed +g/set_locked/s/set_locked/SetLocked +g/set_adjectives/s/set_adjectives/SetAdjectives +g/set_max_encumbrance/s/set_max_encumbrance/SetMaxCarry +g/inherit ROOM/s/inherit ROOM/inherit LIB_ROOM +g/MONSTER/s/MONSTER/LIB_NPC +g/ARMOUR/s/ARMOUR/LIB_ARMOR +g/inherit OBJECT/s/inherit OBJECT/inherit LIB_ITEM +g/inherit STORAGE/s/inherit STORAGE/inherit LIB_STORAGE +g/set_long/s/set_long/SetLong +g/set_short/s/set_short/SetShort +g/set_property/s/set_property/SetProperty +g/set_items/s/set_items/SetItems +g/set_exits/s/set_exits/SetExits +g/query_long/s/query_long/GetLong +g/query_short/s/query_short/GetShort +g/query_property/s/query_property/GetProperty +g/setLong/s/setLong/SetLong +g/inherit \"std\/room\"/s/inherit \"std\/room\"/inherit \"\/lib\/std\/room\" +g/inherit \"\/std\/room\"/s/inherit \"\/std\/room\"/inherit \"\/lib\/std\/room\" +g/inherit \"\/std\/monster\"/s/inherit \"\/std\/monster\"/inherit \"\/lib\/npc\" +g/inherit \"std\/monster\"/s/inherit \"std\/monster\"/inherit \"\/lib\/npc\" +g/\"\/std\/monster\"/s/\"\/std\/monster\"/\"\/lib\/npc\" +g/\"std\/monster\"/s/\"std\/monster\"/\"\/lib\/npc\" +g/\"\/std\/armour\"/s/\"\/std\/armour\"/\"\/lib\/std\/armor\" +g/\"std\/armour\"/s/\"std\/armour\"/\"\/lib\/std\/armor\" +g/#include /s/#include /#include +g/SetName/s/SetName/SetKeyName +g/set_name/s/set_name/SetKeyName +g/set_id/s/set_id/SetId +g/set_aggressive/s/set_aggressive/SetAggressive +g/set_alignment/s/set_alignment/SetMorality +g/set_race/s/set_race/SetRace +g/set_gender/s/set_gender/SetGender +g/set_max_hp/s/set_max_hp/SetMaxHealthPoints +g/set_hp/s/set_hp/SetHealthPoints +g/set_body_type/s/set_body_type/SetRace +g/\"undead\"/s/\"undead\"/\"wraith\" +g/remove_limb/s/remove_limb/RemoveLimb +g/set_level/s/set_level/SetLevel +g/\/obj\/coins/s/\/obj\/coins/\/lib\/pile +g/SetPile/s/SetPile/SetCurrency +g/set_money/s/set_money/SetCurrency +g/add_limb/s/add_limb/AddLimb +g/\/std\/bboard/s/\/std\/bboard/\/lib\/bboard +g/std\/bboard/s/std\/bboard/\/lib\/bboard +g/receive_objects/s/receive_objects/CanReceive +g/add_item_description/s/add_item_description/AddItem +g/add_exit/s/add_exit/AddExit +g/set_light\(1\)/s/set_light\(1\)/SetAmbientLight\(30\) +g/set_properties/s/set_properties/SetProperties +g/set_smell_string/s/set_smell_string/SetSmell +g/set_smell/s/set_smell/SetSmell +g/set_liste/s/set_listen/SetListen +g/SetListen_string/s/SetListen_string/SetListen +g/set_search/s/set_search/SetSearch +g/SetSearch_string/s/SetSearch_string/SetSearch +g/remove_search/s/remove_search/RemoveSearch +g/set_mass/s/set_mass/SetMass +g/set_type/s/set_type/SetType +g/set_limbs/s/set_limbs/SetRestrictLimbs +g/set_wear/s/set_wear/SetWear +g/set_ac/s/set_ac/SetAC +g/set_value/s/set_value/SetValue +g/set_invis/s/set_invis/SetInvis +g/set_prevent_put/s/set_prevent_put/SetPreventPut +g/set_prevent_drop/s/set_prevent_drop/SetPreventDrop +g/\"\/std\/Object\"/s/\"\/std\/Object\"/LIB_ITEM +g/\"std\/Object\"/s/\"std\/Object\"/\"\/lib\/std\/item\" +g/set_read/s/set_read/SetRead +g/set_vendor_type/s/set_vendor_type/SetVendorType +g/set_destroy/s/set_destroy/true +g/\ move\(/s/\ move\(/\ eventMove\( +g/BBOARD/s/BBOARD/LIB_BOARD +g/set_adj/s/set_adj/SetAdjectives + diff --git a/lib/secure/scripts/oldcrat2.src b/lib/secure/scripts/oldcrat2.src new file mode 100644 index 0000000..1baa1e4 --- /dev/null +++ b/lib/secure/scripts/oldcrat2.src @@ -0,0 +1,43 @@ +title %^RED%^Red $N%^RESET%^ +describe $N looks a bit rumpled and tired. +home +update +clean +clone /domains/default/obj/bbucket +remove all +get all +unwield all +put all in bin +cd +cd area/obj +clone chest +open chest +look in chest +get all from chest +dest staff +dest robe +dest hat +clone /domains/default/armor/arbitersuit +#clone /secure/obj/glasses +#clone /realms/$N/area/obj/key +wear arbiter suit +wear first glasses +clone /domains/town/obj/8ball +clone /domains/town/obj/d20 +clone /domains/town/obj/d6 +clone /domains/campus/weap/grenade +clone /domains/campus/weap/waterpistol +clone /domains/campus/obj/omni +clone /domains/town/obj/pipe +clone /domains/town/obj/match +clone /domains/town/obj/match +clone /domains/town/obj/match +clone /domains/town/obj/match +clone /domains/town/obj/match +#clone /domains/default/obj/gps +clone /secure/obj/weirder.c +put all in my arbiter suit +drop chest +drop bin +save + diff --git a/lib/secure/scripts/powerbots.src b/lib/secure/scripts/powerbots.src new file mode 100644 index 0000000..64cdeac --- /dev/null +++ b/lib/secure/scripts/powerbots.src @@ -0,0 +1,12 @@ +# +# WARNING +# Do not use this script. It will screw up your mud. +# You were warned. +# +eval return players()->eventForce("pk on") +eval return players()->eventForce("pk on") +eval return players()->SetProperty("wizmapping",1) +eval return players()->SetClass("fighter") +eval return players()->ChangeLevel(10) +eval return players()->ChangeLevel(11) +eval return players()->SetPolyglot(1) diff --git a/lib/secure/scripts/qcs_check.txt b/lib/secure/scripts/qcs_check.txt new file mode 100644 index 0000000..8d7eafc --- /dev/null +++ b/lib/secure/scripts/qcs_check.txt @@ -0,0 +1,82 @@ +cd +home +go east +go east +create room north test1 +n +modify here short Room One +delete case +create room east test2 +e +modify here short Room 2 +modify here long This is the\nsecond\ntest\nroom +create npc guy +modify npc name guy +modify npc id +dude +fellow +fella +. +modify guy short The Dude +modify guy long This is just some random guy +modify guy adj +just some +random +some +. +create weapon hammer +modify weapon id hammer +warhammer +. +modify hammer name hammer +modify hammer damagetype blunt +modify hammer weapontype blunt +modify hammer mass 700 +modify hammer hands 2 +modify hammer short a heavy war hammer +modify hammer long This is an extremely large and heavy hammer designed to be wielded\nin both hands and used to hurt people very badly indeed. +modify hammer adj +large +heavy +war +. +modify guy level 10 +add hammer to guy +wield hammer +create armor helmet +modify armor name helmet +modify helmet id +helm +headgear +cover +. +modify helmet short a horned viking helmet +modify helmet long Vikings didn't really wear horned helmets into combat, but this one does\nlook formidable with its large bull horns and thick iron construction. It should prove very\nprotective. +modify helmet adj +iron +thick +viking +horned +formidable +protective +modify helmet armortype helmet +modify helmet mass 200 +modify helmet protection +blunt +blade +knife +trauma +. +15 +20 +25 +10 +add helmet to dude +wear helmet +add guy to room +1 +update +look +exa guy + + diff --git a/lib/secure/scripts/qgreset.src b/lib/secure/scripts/qgreset.src new file mode 100644 index 0000000..3898884 --- /dev/null +++ b/lib/secure/scripts/qgreset.src @@ -0,0 +1,10 @@ +eval return objects( (: base_name($1) == "/secure/obj/floodmapper" :) )->eventDestruct() +eval return ROOMS_D->zero() +eval return MAP_D->zero() +goto /domains/campus/room/start +gridconfig set here 0,0,0 +#clone /domains/default/npc/drone +open door +#goto /domains/town/room/vill_road1 +#gridconfig set here -3,6,0 + diff --git a/lib/secure/scripts/resetgrid.src b/lib/secure/scripts/resetgrid.src new file mode 100644 index 0000000..cb1eafd --- /dev/null +++ b/lib/secure/scripts/resetgrid.src @@ -0,0 +1,31 @@ +eval return objects( (: base_name($1) == "/secure/obj/floodmapper" :) )->eventDestruct() +eval return ROOMS_D->zero() +eval return MAP_D->zero() +goto /domains/default/room/start +open door +go north +goto /domains/town/virtual/bottom/33,100000 +gridconfig set here 2,99989,-9 +u +u +u +u +u +u +u +u +u +u +goto /domains/campus/room/start +goto /domains/Ylsrim/room/tower +gridconfig set here 1000,1001,1 +goto /domains/Praxis/square +gridconfig set here 1000,-1000,0 +goto /domains/town/room/mansion_int +gridconfig set here -5,3,0 +goto /domains/town/room/mansion_uhall1 +gridconfig set here -5,3,1 +arch +gridconfig set here -2,2,0 +#goto /domains/town/room/vill_road1 +#gridconfig set here -3,6,0 diff --git a/lib/secure/scripts/ruckus.src b/lib/secure/scripts/ruckus.src new file mode 100644 index 0000000..062ff2f --- /dev/null +++ b/lib/secure/scripts/ruckus.src @@ -0,0 +1,25 @@ +# +# WARNING +# Do not use this script. It will screw up your mud. +# You were warned. +# +get box from suit +dest my boxes +clone /secure/obj/weirder +reload box +stressload 1 +arch +exa screen +eval return users()->eventForce("pk on") +eval return users()->eventForce("pk on") +#eval return users()->SetProperty("wizmapping",1) +eval return objects( (: answers_to("wraith",$1) :) )->eventDestruct() +eval return objects( (: inherits(LIB_ROOM, $1) :) )->SetPlayerKill(1) +eval return objects( (: inherits(LIB_ROOM, $1) :) )->SetNightLight(30) +eval return objects( (: inherits(LIB_ROOM, $1) :) )->SetDayLight(30) +eval return objects( (: inherits(LIB_ROOM, $1) :) )->SetAmbientLight(30) +eval return objects( (: inherits(LIB_ROOM, $1) :) )->SetProperty("no attack",0) +#eval return objects( (: living($1) :) )->SetProperty("wizmapping",1) +eval return users()->eventForce("kill all") +exa screen +eval return objects( (: living($1) && !interactive($1) :) )->eventForce("kill all") diff --git a/lib/secure/scripts/sky.lsed b/lib/secure/scripts/sky.lsed new file mode 100644 index 0000000..9c03f50 --- /dev/null +++ b/lib/secure/scripts/sky.lsed @@ -0,0 +1,167 @@ +g/dest_me\(\)/s/dest_me\(\)/destruct\(\) +g/query_name/s/query_name/GetName +g/set_light/s/set_light/SetLight +g/SetLight/s/SetLight/SetAmbientLight +g/inherit LIB_ROOM_OBJ/s/inherit LIB_ROOM_OBJ/inherit LIB_ROOM +g/add_property/s/add_property/SetProperty +g/TP\-\>/s/TP\-\>/this_player\(\)\-\> +g/inherit INDOOR_ROOM/s/inherit INDOOR_ROOM/inherit LIB_ROOM +g/inherit M_GETTABLE\;/s/inherit M_GETTABLE\;// +g/inherit M_VALUABLE\;/s/inherit M_VALUABLE\;// +g/inherit M_WEARABLE/s/inherit M_WEARABLE/inherit LIB_ARMOR +g/inherit OBJ\;/s/inherit OBJ\;/inherit LIB_ITEM\; +g/void setup\(\)/s/void setup\(\)/void create\(\) +g/RACE_D/s/RACE_D/RACES_D +g/set\(\"day long\"\,/s/set\(\"day long\"\,/SetDayLong\( +g/set\(\"night long\"\,/s/set\(\"night long\"\,/SetNightLong\( +g/inherit \"\/std\/barkeep\"/s/inherit \"\/std\/barkeep\"/inherit LIB_BARKEEP +g/set_chance/s/set_chance/SetChance +g/set_max_fishing/s/set_max_fishing/SetMaxFishing +g/inherit PIER/s/inherit PIER/inherit LIB_FISHING +g/\-\>move\(/s/\-\>move\(/\-\>eventMove\( +g/remove_item_description/s/remove_item_description/RemoveItem +g/remove_exit/s/remove_exit/RemoveExit +g/query_max_sp/s/query_max_sp/GetMaxStaminaPoints +g/set_sp/s/set_sp/SetStaminaPoints +g/inherit \"\/std\/vendor\"/s/inherit \"\/std\/vendor\"/inherit \"\/lib\/std\/vendor\" +g/\/std\/vote_room/s/\/std\/vote_room/\/domains\/town\/room\/voters +g/inherit \"std\/vault\"/s/inherit \"std\/vault\"/inherit \"\/lib\/std\/room\" +g/add_intox/s/add_intox/AddAlcohol +g/set_day_long/s/set_day_long/SetDayLong +g/set_night_long/s/set_night_long/SetNightLong +g/set_door/s/set_door/SetDoor +g/set_open/s/set_open/SetOpen +g/query_open/s/query_open/GetOpen +g/inherit VAULT/s/inherit VAULT/inherit LIB_ROOM +g/move_player/s/move_player/eventMoveLiving +g/\"\/std\/obj\/torch\"/s/\"\/std\/obj\/torch\"/\"\/domains\/town\/obj\/torch\" +g/\"std\/obj\/torch\"/s/\"std\/obj\/torch\"/\"\/domains\/town\/obj\/torch\" +g/set\(\"long\"\,/s/set\(\"long\"\,/SetLong\( +g/set\(\"short\"\,/s/set\(\"short\"\,/SetShort\( +g/set\(\"race\"\,/s/set\(\"race\"\,/SetRace\( +g/new\(\"std\/weapon\"\)/s/new\(\"std\/weapon\"\)/new\(LIB_ITEM\) +g/new\(WEAPON\)/s/new\(WEAPON\)/new\(LIB_ITEM\) +g/new\(OBJECT\)/s/new\(OBJECT\)/new\(LIB_ITEM\) +g/remove\(\)/s/remove\(\)/destruct\(\) +g/inherit WEAPON/s/inherit WEAPON/inherit LIB_ITEM +g/set_wc/s/set_wc/SetClass +g/set_wield/s/set_wield/SetWield +g/SetWield_string/s/SetWield_string/SetWield +g/\"\/std\/weapon\"/s/\"\/std\/weapon\"/LIB_ITEM +g/set_die/s/set_die/SetDie +g/monster::create/s/monster::create/npc::create +g/monster::init/s/monster::init/npc::init +g/force_me/s/force_me/eventForce +g/add_money/s/add_money/AddCurrency +g/set_currency/s/set_currency/SetLocalCurrency +g/set_item_types/s/set_item_types/SetVendorType +g/set_storage_room/s/set_storage_room/SetStorageRoom +g/inherit BARKEEP/s/inherit BARKEEP/inherit LIB_BARKEEP +g/set_menu/s/set_menu/SetMenu +g/set_max_mp/s/set_max_mp/SetMaxMagicPoints +g/set_stats/s/set_stats/SetStat +g/set_chats/s/set_chats/SetAction +g/set_speech/s/set_speech/SetAction +g/set_skill/s/set_skill/SetSkill +g/set_class/s/set_class/SetClass +g/set_languages/s/set_languages/SetLanguage +g/set_lang_prof/s/set_lang_prof/SetLanguage +g/set_speed/s/set_speed/SetWanderSpeed +g/set_stats/s/set_stats/SetStats +g/set_mp/s/set_mp/SetMagicPoints +g/set_spell_chance/s/set_spell_chance/SetSpellChance +g/set_spells/s/set_spells/SetSpells +g/set_poisoning/s/set_poisoning/SetPoisonStrength +g/\"\/std\/poison\"/s/\"\/std\/poison\"/LIB_MEAL_POISON +g/set_eat/s/set_eat/SetMealMessages +g/set_strength/s/set_strength/SetStrength +g/SetMealStrength/s/SetMealStrength/SetStrength +g/inherit FOOD/s/inherit FOOD/inherit LIB_MEAL +g/set_weight/s/set_weight/SetMass +g/set_no_clean/s/set_no_clean/SetNoClean +g/set_communicable/s/set_communicable/SetCommunicable +g/set_cure/s/set_cure/SetCure +g/set_life_span/s/set_life_span/SetLifeSpan +g/inherit GERM/s/inherit GERM/inherit LIB_GERM +g/set_can_close/s/set_can_close/SetCanClose +g/set_prevent_get/s/set_prevent_get/SetPreventGet +g/set_can_lock/s/set_can_lock/SetCanLock +g/set_key/s/set_key/SetKey +g/OB_COINS/s/OB_COINS/LIB_PILE +g/set_closed/s/set_closed/SetClosed +g/set_locked/s/set_locked/SetLocked +g/set_adjectives/s/set_adjectives/SetAdjectives +g/set_max_encumbrance/s/set_max_encumbrance/SetMaxCarry +g/inherit ROOM/s/inherit ROOM/inherit LIB_ROOM +g/MONSTER/s/MONSTER/LIB_NPC +g/ARMOUR/s/ARMOUR/LIB_ARMOR +g/inherit OBJECT/s/inherit OBJECT/inherit LIB_ITEM +g/inherit STORAGE/s/inherit STORAGE/inherit LIB_STORAGE +g/set_long/s/set_long/SetLong +g/set_short/s/set_short/SetShort +g/the_short/s/the_short/GetShort +g/set_property/s/set_property/SetProperty +g/set_items/s/set_items/SetItems +g/set_exits/s/set_exits/SetExits +g/query_long/s/query_long/GetLong +g/query_short/s/query_short/GetShort +g/query_property/s/query_property/GetProperty +g/setLong/s/setLong/SetLong +g/inherit \"std\/room\"/s/inherit \"std\/room\"/inherit \"\/lib\/std\/room\" +g/inherit \"\/std\/room\"/s/inherit \"\/std\/room\"/inherit \"\/lib\/std\/room\" +g/inherit \"\/std\/monster\"/s/inherit \"\/std\/monster\"/inherit \"\/lib\/npc\" +g/inherit \"std\/monster\"/s/inherit \"std\/monster\"/inherit \"\/lib\/npc\" +g/\"\/std\/monster\"/s/\"\/std\/monster\"/\"\/lib\/npc\" +g/\"std\/monster\"/s/\"std\/monster\"/\"\/lib\/npc\" +g/\"\/std\/armour\"/s/\"\/std\/armour\"/\"\/lib\/std\/armor\" +g/\"std\/armour\"/s/\"std\/armour\"/\"\/lib\/std\/armor\" +g/#include /s/#include /#include +g/SetName/s/SetName/SetKeyName +g/set_name/s/set_name/SetKeyName +g/set_id/s/set_id/SetId +g/set_aggressive/s/set_aggressive/SetAggressive +g/set_alignment/s/set_alignment/SetMorality +g/set_race/s/set_race/SetRace +g/set_gender/s/set_gender/SetGender +g/set_max_hp/s/set_max_hp/SetMaxHealthPoints +g/set_hp/s/set_hp/SetHealthPoints +g/set_body_type/s/set_body_type/SetRace +g/\"undead\"/s/\"undead\"/\"wraith\" +g/remove_limb/s/remove_limb/RemoveLimb +g/set_level/s/set_level/SetLevel +g/\/obj\/coins/s/\/obj\/coins/\/lib\/pile +g/SetPile/s/SetPile/SetCurrency +g/set_money/s/set_money/SetCurrency +g/add_limb/s/add_limb/AddLimb +g/\/std\/bboard/s/\/std\/bboard/\/lib\/bboard +g/std\/bboard/s/std\/bboard/\/lib\/bboard +g/receive_objects/s/receive_objects/CanReceive +g/add_item_description/s/add_item_description/AddItem +g/add_exit/s/add_exit/AddExit +g/set_light\(1\)/s/set_light\(1\)/SetAmbientLight\(30\) +g/set_properties/s/set_properties/SetProperties +g/set_smell_string/s/set_smell_string/SetSmell +g/set_smell/s/set_smell/SetSmell +g/set_liste/s/set_listen/SetListen +g/SetListen_string/s/SetListen_string/SetListen +g/set_search/s/set_search/SetSearch +g/SetSearch_string/s/SetSearch_string/SetSearch +g/remove_search/s/remove_search/RemoveSearch +g/set_mass/s/set_mass/SetMass +g/set_type/s/set_type/SetType +g/set_limbs/s/set_limbs/SetRestrictLimbs +g/set_wear/s/set_wear/SetWear +g/set_ac/s/set_ac/SetAC +g/set_value/s/set_value/SetValue +g/set_invis/s/set_invis/SetInvis +g/set_prevent_put/s/set_prevent_put/SetPreventPut +g/set_prevent_drop/s/set_prevent_drop/SetPreventDrop +g/\"\/std\/Object\"/s/\"\/std\/Object\"/LIB_ITEM +g/\"std\/Object\"/s/\"std\/Object\"/\"\/lib\/std\/item\" +g/set_read/s/set_read/SetRead +g/set_vendor_type/s/set_vendor_type/SetVendorType +g/set_destroy/s/set_destroy/true +g/\ move\(/s/\ move\(/\ eventMove\( +g/BBOARD/s/BBOARD/LIB_BOARD +g/set_adj/s/set_adj/SetAdjectives +g/set_read_mess\(/s/set_read_mess\(/SetRead\(\"default\"\, diff --git a/lib/secure/scripts/testmud.src b/lib/secure/scripts/testmud.src new file mode 100644 index 0000000..859b0d8 --- /dev/null +++ b/lib/secure/scripts/testmud.src @@ -0,0 +1,18 @@ +mudconfig maxip 0 +death +connections +unalias shutdown +mudconfig pk on +mudconfig autoadvance on +mudconfig consoletrace on +mudconfig http disable +mudconfig cgi enable +mudconfig dirlist enable +mudconfig creweb enable +mudconfig http enable +mudconfig fastcombat on +mudconfig questrequired on +mudconfig logremote on +mudconfig selectclass on +mudconfig maxidle 3600 +mudconfig ced 1 diff --git a/lib/secure/scripts/update.src b/lib/secure/scripts/update.src new file mode 100644 index 0000000..28d45a6 --- /dev/null +++ b/lib/secure/scripts/update.src @@ -0,0 +1,8 @@ +update armor/* +update doors/* +update meals/* +update npc/* +update obj/* +update room/* +update weap/* +update vehicles/* diff --git a/lib/secure/scripts/upgrades.txt b/lib/secure/scripts/upgrades.txt new file mode 100644 index 0000000..c71e3cb --- /dev/null +++ b/lib/secure/scripts/upgrades.txt @@ -0,0 +1,178 @@ +/cfg +/cfg/timezone.cfg +/cmds +/cmds/creators +/cmds/creators/return.c +/cmds/players +/cmds/players/env.c +/cmds/players/score.c +/cmds/players/automap.c +/daemon +/daemon/services +/daemon/services/auth.c +/daemon/time.c +/domains +/domains/default +/domains/default/room +/domains/default/room/wiz_corr1.c +/domains/default/room/wiz_corr_east.c +/domains/default/room/wiz_corr_east2.c +/domains/default/npc +/domains/default/npc/zookeeper.c +/domains/default/virtual +/domains/default/virtual/arena.c +/domains/default/virtual/server.c +/domains/default/virtual/sky.c +/domains/town +/domains/town/room +/domains/town/room/bank.c +/domains/town/room/shop.c +/domains/town/room/tavern.c +/domains/town/npc +/domains/town/npc/lars.c +/domains/town/npc/otik.c +/domains/town/npc/horse.c +/domains/town/virtual +/domains/town/virtual/forest.c +/domains/town/virtual/server.c +/domains/campus +/domains/campus/room +/domains/campus/room/basement2.c +/domains/campus/npc +/domains/campus/npc/jennybot.c +/lib +/lib/lvs +/lib/lvs/position.c +/lib/events +/lib/events/give.c +/lib/events/fall.c +/lib/comp +/lib/comp/holder.c +/lib/std +/lib/std/armor.c +/lib/std/dummy.c +/lib/std/item.c +/lib/std/room.c +/lib/std/worn_storage.c +/lib/std/furnace.c +/lib/props +/lib/props/clean.c +/lib/props/id.c +/lib/props/inventory.c +/lib/props/move.c +/lib/props/body_mass.c +/lib/include +/lib/include/body.h +/lib/include/race.h +/lib/virtual +/lib/virtual/virt_land.c +/lib/virtual/virt_sky.c +/lib/virtual/virtual.c +/lib/body.c +/lib/bot.c +/lib/combat.c +/lib/command.c +/lib/exits.c +/lib/interactive.c +/lib/living.c +/lib/npc.c +/lib/player.c +/lib/race.c +/lib/spell.c +/lib/mount.c +/lib/bonus.c +/lib/potion.c +/include +/include/medium.h +/include/race.h +/include/vendor_types.h +/save +/save/events.o +/save/races.o +/secure +/secure/sefun/mud_info.c +/secure/cfg +/secure/cfg/races +/secure/cfg/races/horse +/secure/cmds +/secure/cmds/admins +/secure/cmds/admins/admintool.c +/secure/cmds/admins/decre.c +/secure/cmds/admins/encre.c +/secure/cmds/players +/secure/cmds/players/reply.c +/secure/cmds/players/suicide.c +/secure/cmds/creators +/secure/cmds/creators/restore.c +/secure/cmds/creators/source.c +/secure/cmds/creators/update.c +/secure/cmds/creators/showfuns.c +/secure/daemon +/secure/daemon/localpost.c +/secure/daemon/master.c +/secure/daemon/players.c +/secure/daemon/remotepost.c +/secure/daemon/snoop.c +/secure/daemon/update.c +/secure/daemon/function.c +/secure/daemon/reload.c +/secure/daemon/oob.c +/secure/daemon/update.patch +/secure/include +/secure/include/events.h +/secure/include/lib.h +/secure/lib +/secure/lib/net +/secure/lib/net/client.c +/secure/lib/net/server.c +/secure/lib/net/socket.c +/secure/lib/net/ftp_data_connection.c +/secure/lib/net/h_ftpd.c +/secure/lib/net/remote.c +/secure/lib/net/oob.c +/secure/obj +/secure/obj/post.c +/secure/obj/converter.c +/secure/obj/converter_smaug.c +/secure/tmp +/secure/tmp/dirs.txt +/secure/tmp/files.txt +/secure/room +/secure/room/router.c +/secure/modules +/secure/modules/create.c +/secure/modules/generic.c +/secure/scripts +/secure/scripts/crat.src +/secure/scripts/crat2.src +/secure/scripts/qcs_check.txt +/secure/upgrades +/secure/upgrades/files +/secure/upgrades/files/0^0tmp0^0foo.txt +/verbs +/verbs/rooms +/verbs/rooms/go.c +/verbs/creators +/verbs/creators/add.c +/verbs/creators/modify.c +/verbs/items +/verbs/items/give.c +/verbs/items/look.c +/verbs/items/wield.c +/verbs/players +/verbs/players/attack.c +/www +/www/ds-admin-faq.html +/www/ds-creator-faq.html +/www/lpmuds +/www/lpmuds/downloads.html +/www/mudlist.txt +/doc +/doc/hbook +/doc/hbook/chapter03 +/doc/guide +/doc/guide/chapter08 +/doc/RELEASE_NOTES +/std +/std/room.c +/std/furnace.c diff --git a/lib/secure/scripts/walkabout.src b/lib/secure/scripts/walkabout.src new file mode 100644 index 0000000..9214421 --- /dev/null +++ b/lib/secure/scripts/walkabout.src @@ -0,0 +1,22 @@ +start +open door +n +w +w +w +s +w +n +s +s +n +e +n +n +n +n +n +n +e +n + diff --git a/lib/secure/scripts/wtf.src b/lib/secure/scripts/wtf.src new file mode 100644 index 0000000..d13de4a --- /dev/null +++ b/lib/secure/scripts/wtf.src @@ -0,0 +1,9 @@ +eval return objects( (: base_name($1) == "/secure/obj/floodmapper" :) )->eventDestruct() +eval return objects( (: base_name($1) == "/domains/default/npc/drone" :) )->eventDestruct() +eval return objects( (: base_name($1) == "/domains/default/npc/drone2" :) )->eventDestruct() +eval return ROOMS_D->zero() +eval return MAP_D->zero() +goto /domains/campus/room/start +gridconfig set here 0,0,0 +open door +stand diff --git a/lib/secure/sefun/absolute_path.c b/lib/secure/sefun/absolute_path.c new file mode 100644 index 0000000..036ded5 --- /dev/null +++ b/lib/secure/sefun/absolute_path.c @@ -0,0 +1,64 @@ +/* /adm/sefun/absolute_path.c + * from Foundation II + * returns the full path of a string based on a relative path + * created by Huthar@Portals as resolv_path.c + * modifications by Pallando@Dead Souls 930526 + * changed to absolute_path() by Descartes of Borg 940501 + * features added and speed doubled by Pallando, 940531 + */ + +string absolute_path(string curr, string newp) { + int i, len; + string *tmp; + string name, rest; + + if(curr && (curr == "cwd") && this_player()) + curr = this_player()->query_cwd(); + if(!newp || newp == "" || newp == ".") return curr; + if( (newp == "here") && this_player() ) + { + return file_name(environment(this_player())) + ".c"; + } + len = strlen( newp ); + switch( newp[0..0] ) + { + case "~": + if( newp == "~" || newp == "~/" ) + newp = user_path( this_player()-> GetKeyName() )[0..<2]; + else if( newp[1..1] == "/" ) + newp = user_path( this_player()-> GetKeyName() ) + + newp[2..len]; + else if( sscanf( newp, "~%s/%s", name, rest ) == 2 ) + newp = user_path( name ) + rest; + else + newp = user_path( newp[1..len] )[0..<2]; + break; + case "^": + newp = "/domains/" + newp[1..len]; + break; + case "/": + break; + default: + if( curr != "/" ) newp = curr + "/" + newp; + else newp = curr + newp; + } + + if( -1 == strsrch( newp, ".." ) ) return newp; + + if( newp[<1] != '/' ) newp += "/"; + tmp = explode(newp,"/"); + if (!tmp) tmp = ({"/"}); + for(i = 0; i < sizeof(tmp); i++) + if(tmp[i] == "..") { + if(sizeof(tmp) > 2) { + tmp = tmp[0..(i-2)] + tmp[(i+1)..(sizeof(tmp)-1)]; + i -= 2; + } else { + tmp = tmp[2 ..(sizeof(tmp)-1)]; + i = 0; + } + } + newp = "/" + implode(tmp,"/"); + if(newp == "//") newp = "/"; + return newp; +} diff --git a/lib/secure/sefun/absolute_value.c b/lib/secure/sefun/absolute_value.c new file mode 100644 index 0000000..c1acde9 --- /dev/null +++ b/lib/secure/sefun/absolute_value.c @@ -0,0 +1,12 @@ +// /adm/simul_efun/absolute_value.c +// from the Dead Souls mudlib +// an absolute value simul_efun +// created by Descartes 28 april 1993 + +int absolute_value(int x) { + return ( (x>-1) ? x : -x); +} + +int abs(int x) { + return absolute_value(x); +} diff --git a/lib/secure/sefun/arrays.c b/lib/secure/sefun/arrays.c new file mode 100644 index 0000000..f9c2cc2 --- /dev/null +++ b/lib/secure/sefun/arrays.c @@ -0,0 +1,31 @@ +mixed *scramble_array(mixed *arr){ + mixed *ret = copy(arr); + ret = sort_array(ret, (:random(3)-1:) ); + return ret; +} + +mixed *distinct_array(mixed *arr) { + mapping tmp; + int i, maxi; + + for(i = 0, tmp = allocate_mapping(maxi = sizeof(arr)); i + +/* ([ mappos: ({ parent, x, y, g_cost, h_cost, f_cost }), ... ]) */ +static mapping data; + +/* ([ id: ([ "pos": mappos, "fcost": f ]), ... ]) */ +static mapping binaryHeap; + +/* Number of items on the binary heap. */ +static int numItems; +static int maxItems; + +static int l1, l2; + +void initHeap() +{ + l1 = l2 = 0; + maxItems = numItems = 0; + binaryHeap = ([ ]); +} + +int getHeadHeap() { return binaryHeap[1]["pos"]; } + +#undef LOG_FIND + +int findHeap(int d) +{ + int *nodes; + int u, v, f; + int lc, rc; + + /* Sanity check. */ + if(!numItems) return 0; /* Heap is empty, return 0. */ + + if(member_array(d, keys(data)) == -1) return 0; /* Not come across this item before. */ + + if(numItems == 1) + { + + if(d == binaryHeap[1]["pos"]) return 1; + + return 0; + } + + nodes = allocate(numItems + 1); + nodes[0] = 1; + + f = data[d][AS_FCOST]; + v = 1; + + while (v <= numItems) + { + nodes[v]++; + + if(d == binaryHeap[v]["pos"]) break; + + u = v; + rc = (lc = u << 1) + 1; + + if(nodes[u] < 3) + { + + if(rc <= numItems) + { + + if(nodes[u] == 1 && f >= binaryHeap[lc]["fcost"]) v = lc; + else + if(f >= binaryHeap[rc]["fcost"]) + { + nodes[u] = 2; + v = rc; + } + + nodes[0]++; + } + else + if(nodes[u] == 1 && lc <= numItems) + { + + if(f >= binaryHeap[lc]["fcost"]) v = lc; + + nodes[0]++; + } + + } + + if(nodes[u] == 4) + { + v = 0; + break; + } + + if(u == v) + { + v >>= 1; + + if(!v) break; + + } + + } + + if(v > numItems) v = 0; + +#ifdef LOG_FIND + if(l1 < 64 && !v) + { + int i, dx; + + l1++; + + log_file("HEAP", sprintf("Finding %d(%d). Checks made: %d ... Not Found!\n", d, f, nodes[0])); + /* log_file("HEAP", sprintf("binaryHeap = %O\nnodes = %O\n", binaryHeap, nodes)); */ + + i = 1; + + while(i <= numItems) + { + string *tmp = ({ }); + string str = ""; + + dx = (80.0 / (float)i); + + for(int j = i; j < i << 1; j++) + { + + if(j <= numItems) tmp += ({ "|" }); + else tmp += ({ "" }); + + } + + log_file("HEAP", sprintf("%@|"+dx+"s\n", tmp)); + + tmp = ({ }); + tmp = allocate(i); + + for(int j = i; j < i << 1; j++) + { + + if(j <= numItems) + tmp[j - i] = sprintf("%|"+(dx >> 1)+"'_'d", binaryHeap[j]["fcost"]); + else tmp[j - i] = ""; + + } + + i <<= 1; + + log_file("HEAP", sprintf("%@|"+dx+"s\n", tmp)); + } + + log_file("HEAP", "\n"); + } + + if(l2 < 64 && v && numItems > 7) + { + int i, dx; + + l2++; + + log_file("HEAP", sprintf("Finding %d(%d). Checks made: %d ... Result = %d\n", d, f, nodes[0], v)); + /* log_file("HEAP", sprintf("binaryHeap = %O\nnodes = %O\n", binaryHeap, nodes)); */ + + i = 1; + + while(i <= numItems) + { + string *tmp = ({ }); + string str = ""; + + dx = (80.0 / (float)i); + + for(int j = i; j < i << 1; j++) + { + + if(j <= numItems) tmp += ({ "|" }); + else tmp += ({ "" }); + + } + + log_file("HEAP", sprintf("%@|"+dx+"s\n", tmp)); + + tmp = ({ }); + tmp = allocate(i); + + for(int j = i; j < i << 1; j++) + { + + if(j <= numItems) + { + + if(j == v) + tmp[j - i] = sprintf("%|"+(dx >> 1)+"'_'s", "["+binaryHeap[j]["fcost"]+"]"); + else + tmp[j - i] = sprintf("%|"+(dx >> 1)+"'_'d", binaryHeap[j]["fcost"]); + + } + else tmp[j - i] = ""; + + } + + i <<= 1; + + log_file("HEAP", sprintf("%@|"+dx+"s\n", tmp)); + } + + log_file("HEAP", "\n"); + } +#endif + + return v; +} + +void resortHeapDown(int v) +{ + + while(v <= numItems) + { + mapping parent, lchild, rchild; + int u, lc, rc; + + u = v; + + rc = (lc = u << 1) + 1; + + parent = ([ ]) + binaryHeap[u]; + + if(rc <= numItems) + { + lchild = ([ ]) + binaryHeap[lc]; + rchild = ([ ]) + binaryHeap[rc]; + + if(parent["fcost"] > lchild["fcost"] && + parent["fcost"] > rchild["fcost"]) + { + + if(lchild["fcost"] > rchild["fcost"]) v = rc; + else v = lc; + + } + else + if(parent["fcost"] > lchild["fcost"]) v = lc; + else + if(parent["fcost"] > rchild["fcost"]) v = rc; + + } + else + if(lc <= numItems) + { + + if(parent["fcost"] > binaryHeap[lc]["fcost"]) v = lc; + + } + + if(u == v) break; + + binaryHeap[u] = ([ ]) + binaryHeap[v]; + binaryHeap[v] = ([ ]) + parent; + } + +} + +void resortHeapUp(int m) +{ + mapping tmp; + + while(m > 1) + { + int m2 = m >> 1; + + if (binaryHeap[m]["fcost"] >= binaryHeap[m2]["fcost"]) break; + + tmp = ([ ]) + binaryHeap[m]; + binaryHeap[m] = ([ ]) + binaryHeap[m2]; + binaryHeap[m2] = ([ ]) + tmp; + + m = m2; + } + +} + +void addHeap(int d) +{ + numItems++; + + if(numItems > maxItems) maxItems = numItems; + + binaryHeap[numItems] = ([ "pos": d, "fcost": data[d][AS_FCOST] ]); + + if(numItems > 1) resortHeapUp(numItems); + +} + +void removeHeadHeap() +{ + + if(!numItems) return 0; /* Heap is empty, return 0. */ + + /* Replace the head item with the tail item. */ + if(numItems > 1) binaryHeap[1] = ([ ]) + binaryHeap[numItems]; + + /* Chop off the tail. */ + map_delete(binaryHeap, numItems); + + if(--numItems < 2) return; + + resortHeapDown(1); + + return; +} + +int calc_h(int sx, int sy, int ex, int ey) +{ + int dx, dy; + + dx = sx - ex; + dy = sy - ey; + + return (sqrt(dx * dx + dy * dy) * 0.975); + + /* Manhattan method. */ + /* return (abs(dx) + abs(dy)); */ +} + +string make_path(int start, int goal, int goalx, int goaly) +{ + mapping x_dir, y_dir; + string *dirs; + string path; + int i, oldx, oldy, newx, newy; + + path = ""; + i = goal; + oldx = goalx; oldy = goaly; + x_dir = ([ -1: ({ 3, 4, 5 }), 0: ({ 2, 9, 6 }), 1: ({ 1, 0, 7 }) ]); + y_dir = ([ -1: ({ 3, 2, 1 }), 0: ({ 4, 9, 0 }), 1: ({ 5, 6, 7 }) ]); + dirs = ({ "e", "ne", "n", "nw", "w", "sw", "s", "se", "*" }); + + while(i != start) + { + int *xd, *yd; + + i = data[i][AS_PARENT]; + newx = data[i][AS_X]; + newy = data[i][AS_Y]; + + xd = x_dir[oldx - newx]; + yd = y_dir[oldy - newy]; + path = dirs[(xd & yd)[0]] + path; + + oldx = newx; + oldy = newy; + } + + return path; +} + +mixed *find_path(string map, int startx, int starty, int goalx, int goaly, mapping costs) +{ + string *split_map; + int *closed; + int map_width, start, goal; + int currpos; + int newx, newy, newpos; + int oldf, g, h; + int id; + + /* Process the map into an easier-to-use format. */ + split_map = explode(map, "\n"); + map_width = 0; + + /* Find the length of the longest line in the "map" */ + for(int i = sizeof(split_map); i-- ;) + if(map_width < strlen(split_map[i])) + map_width = strlen(split_map[i]); + + /* Make all the lines that length by padding with escape characters. + * (Note: I use escapes because they are an unlikely character to be + * chosen for walking over, and unused characters are 'walls') */ + for(int i = sizeof(split_map); i-- ;) + split_map[i] += sprintf("%" + (map_width - strlen(split_map[i])) + "'\27's", ""); + + /* Sanity checks */ + if(goalx < 0 || goalx >= map_width || goaly < 0 || goaly >= sizeof(split_map)) + return ({ }); + + if(member_array(split_map[starty][startx], keys(costs)) == -1 || + member_array(split_map[goaly][goalx], keys(costs)) == -1) + return ({ }); + + /* Setup initial state. */ + start = startx + starty * map_width; + goal = goalx + goaly * map_width; + + data = ([ ]); + closed = ({ }); + + g = 0; + h = calc_h(startx, starty, goalx, goaly); + write("Distance estimate: " + h + "\n"); + + data[start] = ({ -1, startx, starty, g, h, g + h }); + + /* Initialise the binary heap. */ + initHeap(); + addHeap(start); + + while(numItems && member_array(goal, closed) == -1) + { + currpos = getHeadHeap(); + closed += ({ currpos }); + removeHeadHeap(); + + for(int ineighbour = 0; ineighbour < 8; ineighbour += 2) + { + newx = (currpos % map_width) + ({ 1, 1, 0, -1, -1, -1, 0, 1 })[ineighbour]; + newy = (currpos / map_width) + ({ 0, -1, -1, -1, 0, 1, 1, 1 })[ineighbour]; + + /* Out of bounds, ignore it. */ + if(newx < 0 || newx >= map_width || + newy < 0 || newy >= sizeof(split_map)) + continue; + + /* Solid wall, ignore it. */ + if(member_array(split_map[newy][newx], keys(costs)) == -1) continue; + + newpos = newy * map_width + newx; + /* Already checked, ignore it. */ + if(member_array(newpos, closed) != -1) continue; + + g = data[currpos][AS_GCOST] + costs[split_map[newy][newx]]; + + if(!(id = findHeap(newpos))) + { + h = calc_h(newx, newy, goalx, goaly); + + data[newpos] = allocate(AS_DATA_SZ); + data[newpos][AS_PARENT] = currpos; + data[newpos][AS_X] = newx; + data[newpos][AS_Y] = newy; + data[newpos][AS_GCOST] = g; + data[newpos][AS_HCOST] = h; + data[newpos][AS_FCOST] = g + h; + + addHeap(newpos); + } + else + { + + if(g < data[newpos][AS_GCOST]) + { + oldf = data[newpos][AS_FCOST]; + + h = calc_h(newx, newy, goalx, goaly); + + data[newpos][AS_PARENT] = currpos; + data[newpos][AS_X] = newx; + data[newpos][AS_Y] = newy; + data[newpos][AS_GCOST] = g; + data[newpos][AS_HCOST] = h; + data[newpos][AS_FCOST] = g + h; + + if(g + h != oldf) + { + binaryHeap[id]["fcost"] = g + h; + + if(g + h < oldf) resortHeapUp(id); + else + if(g + h > oldf) resortHeapDown(id); + + } + + } + + } + + } + + } + + write("Maximum binary heap size: " + maxItems + "\n"); + + if(member_array(goal, closed) == -1) return ({ }); + + return ({ make_path(start, goal, goalx, goaly), data }); +} diff --git a/lib/secure/sefun/atomize.c b/lib/secure/sefun/atomize.c new file mode 100644 index 0000000..d801e29 --- /dev/null +++ b/lib/secure/sefun/atomize.c @@ -0,0 +1,17 @@ +string *atomize_string(string str){ + int i; + string *ret = ({}); + for(i=sizeof(str);i > 0;i--){ + ret += ({ str[0..i] }); + } + return ret; +} + +string *atomize_array(string *temp_arr){ + string *ret = ({}); + foreach(string element in temp_arr){ + ret += atomize_string(element); + } + ret += temp_arr; + return distinct_array(ret); +} diff --git a/lib/secure/sefun/communications.c b/lib/secure/sefun/communications.c new file mode 100644 index 0000000..13ab1b3 --- /dev/null +++ b/lib/secure/sefun/communications.c @@ -0,0 +1,121 @@ +/* /secure/sefun/communications.c + * from the Dead Souls Mud Library + * some backwards compat sefuns + */ + +#include +#include ROOMS_H + +object *global_tmp_ob_arr; + +varargs void say(mixed str, mixed ob) { + object *obs; + + if(!this_player()) error("say() makes no sense with no this_player()\n"); + if(!environment(this_player())) return; + if( !ob ) obs = ({ this_player() }); + else if( objectp(ob) ) obs = ({ ob, this_player() }); + else obs = ob + ({ this_player() }); + environment(this_player())->eventPrint(str + "", MSG_ENV, obs); +} + +varargs void tell_object(object ob, mixed str, int mclass){ + if(ob) ob->eventPrint(str, (mclass || MSG_CONV)); +} + +void tell_player(mixed player, string msg){ + object dude; + string str; + if(objectp(player)) str = player->GetKeyName(); + else str = player; + if(!msg || msg == "") return; + if(!dude = find_player(str) ) return; + else tell_object(dude, msg); +} + +static string tc_color_logic(string col){ + string ret; + if(!col) col = "magenta"; + ret = "%^BOLD%^"+upper_case(col)+"%^"; + if(!grepp(ret, "B_")){ + if(grepp(ret, "WHITE")) ret = "%^B_BLACK"+ret; + else if(grepp(ret, "BLACK")) ret = "%^B_WHITE"+ret; + } + return ret; +} + +varargs void tc(string str, string col, object dude){ + string prefix; + if(!col) col = "magenta"; + prefix = tc_color_logic(col); + if(!dude) dude = find_player(DEBUGGER); + if(dude){ + tell_player(dude, prefix+str+"%^RESET%^"); + if(dude) flush_messages(dude); + } + debug_message(strip_colours(str)); +} + +varargs int tn(string str, string col, object room, int mclass){ + string prefix; + if(!col) col = "magenta"; + prefix = tc_color_logic(col); + if(!room) tell_object(load_object(ROOM_NETWORK) ,prefix+str+"%^RESET%^"); + else { + if(!mclass) tell_object(room, prefix+str+"%^RESET%^"); + else tell_object(room, prefix+str+"%^RESET%^",mclass); + } + return 1; +} + +varargs int trr(string str, string col, int mclass){ + if(!mclass) mclass = 0; + tn(str, col, load_object(ROOM_ROUTER), mclass); + return 1; +} + +varargs int debug(mixed msg, string color){ + object *players = filter(users(), (: $1->GetProperty("debug") :) ); + string prevob = ""; + if(!sizeof(players)) return 0; + prevob = file_name(previous_object()); + if(!color || !sizeof(color)) color = "b_blue%^green"; + foreach(object guy in players){ + tc("%^B_BLACK%^BOLD%^WHITE%^DEBUG: %^RESET%^ " + prevob + + "\n" + tc_color_logic(color) + msg, color, guy); + } + return 1; +} + +varargs int tell_creators(string msg, string color){ + object *cres = filter(users(), (: creatorp($1) :) ); + global_tmp_ob_arr = ({}); + if(!sizeof(cres)) return 0; + global_tmp_ob_arr = sort_array(cres, (: member_array($1,global_tmp_ob_arr) == -1 :) ); + cres = global_tmp_ob_arr; + if(!msg) msg = ""; + if(!color) color = "red"; + foreach(object guy in cres){ + tc(msg, color, guy); + } + return 1; +} + +varargs void tell_room(mixed ob, mixed str, mixed exclude){ + if(!ob ) return; + if(stringp(ob) && catch(ob = load_object(ob))) return; + if(ob) ob->eventPrint(str, MSG_ENV, exclude); +} + +varargs void shout(mixed str, mixed exclude) { + if(objectp(exclude)) exclude = ({ exclude }); + else if(!pointerp(exclude)) exclude = ({}); + if(this_player()) exclude += ({ this_player() }); + users()->eventPrint(str + "", MSG_CONV, exclude); +} + +void write2(mixed str){ + object player = this_player(); + if(!player) return; + player->eventReceive(str); +} diff --git a/lib/secure/sefun/compare_array.c b/lib/secure/sefun/compare_array.c new file mode 100644 index 0000000..f25f83c --- /dev/null +++ b/lib/secure/sefun/compare_array.c @@ -0,0 +1,26 @@ +#include +#include + +int compare_array(mixed *arr1, mixed *arr2){ + mixed *temparr1 = copy(arr1); + mixed *temparr2 = copy(arr2); + + if(typeof(arr1) != typeof(arr2)) return 0; + + if(sizeof(temparr1) != sizeof(temparr2)) return 0; + + foreach(mixed item in temparr1){ + if(member_array(item, temparr2) == -1) return 0; + } + + foreach(mixed item2 in temparr2){ + if(member_array(item2, temparr1) == -1) return 0; + } + + return 1; +} + +int arrcmp(mixed *arr1, mixed *arr2){ + return compare_array(arr1, arr2); +} + diff --git a/lib/secure/sefun/copy.c b/lib/secure/sefun/copy.c new file mode 100644 index 0000000..20b0dd6 --- /dev/null +++ b/lib/secure/sefun/copy.c @@ -0,0 +1,26 @@ +/* /adm/simul_efun/copy.c + * from Dead Souls + * returns a copy of an array or mapping rather than that array or mapping + * created by Descartes of Borg 940204 + * based upon an older simul_efun of the same name by Buddha@TMI-2 + */ + +#ifndef __FLUFFOS__ +mixed copy(mixed val) { + mixed *cles; + mixed ret; + int i, maxi; + + if(mapp(val)) { + ret = allocate_mapping(maxi = sizeof(cles = keys(val))); + for(i= 0; i< maxi; i++) ret[cles[i]] = copy(val[cles[i]]); + return ret; + } + else if(pointerp(val)) { + ret = allocate(maxi = sizeof(val)); + for(i=0; i +string *query_custom_path(){ + string custom_path; + if(!creatorp(this_player())) return ({ DIR_PLAYER_CMDS, DIR_SECURE_PLAYER_CMDS }) ; + custom_path = "/realms/"+this_player()->GetKeyName()+"/cmds"; + return ({ custom_path }); +} + +string query_custom_command(string str){ + string custom_path; + if(!str) str = ""; + custom_path = "/realms/"+this_player()->GetKeyName()+"/cmds"; + if( file_size(custom_path) != -2 ) return ""; + if( file_size(custom_path+"/"+str+".c") < 1 ) return ""; + return custom_path+"/"+str+".c"; +} diff --git a/lib/secure/sefun/disable.c b/lib/secure/sefun/disable.c new file mode 100644 index 0000000..40842c9 --- /dev/null +++ b/lib/secure/sefun/disable.c @@ -0,0 +1,29 @@ +mixed hobbled(object ob){ + string *missings; + string *total; + int foot,leg; + mapping ret; + + missings = ob->GetMissingLimbs(); + if(!sizeof(missings)) return "No missing limbs."; + + foot = 0; + leg = 0; + total = ({}); + foreach(string limb in missings) { + string s1; + if(sscanf(limb,"%s foot",s1) > 0 || sscanf(limb,"%spaw",s1) > 0) { + foot += 1; + total += ({ limb }); + } + if(sscanf(limb,"%sleg",s1) > 0){ + leg += 1; + total += ({ limb }); + } + } + + if( foot == 0 && leg == 0 ) return "No missing legs or feet."; + + ret = ([ "feet" : foot, "legs" : leg , "list" : total ]); + return ret; +} diff --git a/lib/secure/sefun/domains.c b/lib/secure/sefun/domains.c new file mode 100644 index 0000000..4d7234f --- /dev/null +++ b/lib/secure/sefun/domains.c @@ -0,0 +1,62 @@ +/* /adm/simul_efun/domains.c + * from Dead Souls + * sefuns for managing domains + * created by Descartes of Borg 931204 + */ + +#include +private string gnom; + +object domain_master(mixed val) { + if(!val) return 0; + if(stringp(val)) { + if(!domain_exists(val)) return 0; + else return load_object(DOMAINS_DIRS+"/"+val+"/adm/master"); + } + else if(objectp(val)) { + if(val = domain(val)) + return load_object(DOMAINS_DIRS+"/"+val+"/adm/master"); + else return 0; + } + error("Bad argument 1 to load_object().\n"); +} + +int domain_exists(string dmn) { + if(!stringp(dmn)) return 0; + return (file_size(DOMAINS_DIRS+"/"+dmn+"/") == -2); +} + +varargs string domain(mixed val, int path) { + string nom, tmp, foo; + int hits; + + if(objectp(val) && domain_exists(tmp=val->GetDomain())){ + if(!path) return tmp; + if(val->GetDomainPath()) return val->GetDomainPath(); + else return tmp; + } + if(stringp(val) && val=load_object(val) && + domain_exists(tmp=val->GetDomain())){ + if(!path) return tmp; + if(val->GetDomainPath()) return val->GetDomainPath(); + else return tmp; + } + nom = (objectp(val) ? file_name(val) : val); + if((hits = (sscanf(nom, DOMAINS_DIRS+"/%s/%*s", tmp)))){ + if(path) return DOMAINS_DIRS+"/"+tmp; + return tmp; + } + gnom = nom; + if((hits = sscanf(nom, REALMS_DIRS+"/%s/%s/%*s", foo, tmp)) > 1 && + unguarded( (: directory_exists(path_prefix(gnom)) :)) ){ + string ret = foo+"/"+tmp; + if(path) return REALMS_DIRS+"/"+ret; + return ret; + } + if((hits = sscanf(nom, ESTATES_DIRS+"/%s/%s/area/%*s", foo, tmp)) > 1 && + unguarded( (: directory_exists(path_prefix(gnom)) :) )){ + if(path) return ESTATES_DIRS+"/"+foo+"/"+tmp+"/area"; + return tmp; + } + return 0; +} diff --git a/lib/secure/sefun/dummy.c b/lib/secure/sefun/dummy.c new file mode 100644 index 0000000..fc6b7c0 --- /dev/null +++ b/lib/secure/sefun/dummy.c @@ -0,0 +1,5 @@ +// This is a dummy sefun file. It's +// a shortcut to avoid fixing some stuff +// before it's necessary. + + diff --git a/lib/secure/sefun/duplicates.c b/lib/secure/sefun/duplicates.c new file mode 100644 index 0000000..b050944 --- /dev/null +++ b/lib/secure/sefun/duplicates.c @@ -0,0 +1,36 @@ +// handling of duplicate objects in inventory. +// +// here we provide the function two objects. If they +// were cloned from the same file AND they have +// different instance numbers, we return "1", because +// they are duplicates, and not just one object. Otherwise, +// we return a "0". Note that 0 can mean the two objects +// were cloned from different files, and it can also mean +// that the objects provided are actually just one object +// in memory. +// +int query_dupes(object ob1,object ob2){ + if(base_name(ob1) == base_name(ob2) && file_name(ob1) != file_name(ob2)) return 1; + else return 0; +} + +// This function is supposed to return an array +// of objects in the inventory of "where" that +// are cloned from the same file as "ob" +object *get_dupes(object ob, object where){ + object *allstuff,*dupes; + int i; + if(!where || !ob) { + //write("missing something"); + return 0; + } + allstuff = all_inventory(where); + if(!sizeof(allstuff)) return 0; + if(member_array(ob,allstuff) == -1) return 0; + for(i=0;i 0 ) dupes += ({allstuff[i]}); + } + if(sizeof(dupes) > 0) return dupes; + else return ({}); +} diff --git a/lib/secure/sefun/economy.c b/lib/secure/sefun/economy.c new file mode 100644 index 0000000..2cb89ce --- /dev/null +++ b/lib/secure/sefun/economy.c @@ -0,0 +1,72 @@ +#include + +float currency_rate(string type) { + return (float)ECONOMY_D->__Query(type, "rate"); +} + +float currency_inflation(string type) { + return (float)ECONOMY_D->__Query(type, "inflation"); +} + +int currency_mass(int x, string type) { + return to_int((float)ECONOMY_D->__Query(type, "weight") * x); +} + +int currency_value(int x, string str) { + return to_int(x * currency_rate(str)); +} + +string *mud_currencies() { return ECONOMY_D->__QueryCurrencies(); } + +int valid_currency(string str){ + if(member_array(str,mud_currencies()) != -1) return 1; + else return 0; +} + +string query_base_currency(){ + string *monies; + string least_valuable; + int base; + monies = ECONOMY_D->__QueryCurrencies(); + foreach(string currency in monies){ + if(!base) base = ECONOMY_D->__Query(currency,"rate"); + if(ECONOMY_D->__Query(currency,"rate") <= base){ + base = ECONOMY_D->__Query(currency,"rate"); + least_valuable = currency; + } + } + return least_valuable; +} + +int query_base_rate(){ + return ECONOMY_D->__Query(query_base_currency(),"rate"); +} + +int query_player_money(object who) { + string *monies; + int base, x; + x = 0; + monies = ECONOMY_D->__QueryCurrencies(); + base = ECONOMY_D->__Query(query_base_currency(),"rate"); + foreach(string currency in monies){ + float rate; + rate = base/ECONOMY_D->__Query(currency,"rate"); + x += who->GetCurrency(currency) * rate; + } + return x; +} + +int query_base_value(string currency, int amount){ + float rate; + rate = ECONOMY_D->__Query(currency,"rate"); + return amount * rate; +} + +int query_value(int amount,string from_currency, string to_currency){ + int rate, baseval; + rate = ECONOMY_D->__Query(to_currency,"rate"); + baseval = query_base_value( from_currency, amount ); + return baseval / rate; +} + + diff --git a/lib/secure/sefun/english.c b/lib/secure/sefun/english.c new file mode 100644 index 0000000..2f9205d --- /dev/null +++ b/lib/secure/sefun/english.c @@ -0,0 +1,469 @@ +/* /adm/simul_efun/english.c + * from Dead Souls + * efuns for dealing with the oddity we know as the English language + * created by Descartes of Borg 940207 + * Version: @(#) english.c 1.5@(#) + * Last modified: 97/01/01 + */ + +#ifndef SEFUN_PLURALIZE +#define SEFUN_PLURALIZE 1 +#endif + +#include + +string *localcmds; + +varargs mixed match_command(string verb, int subs){ + string *local_arr; + localcmds = ({}); + filter(this_player()->GetCommands(), (: localcmds += ({ $1[0] }) :)); + foreach(mixed path in this_player()->GetSearchPath()){ + localcmds += CMD_D->GetCommands(path); + } + localcmds += keys(VERBS_D->GetVerbs()); + if(member_array(verb,localcmds) == -1){ + if(member_array(verb, SOUL_D->GetEmotes()) != -1) return verb; + if(alphap(verb)) local_arr = regexp(localcmds,"^"+verb); + if(sizeof(local_arr)){ + if(!subs){ + if(member_array(verb, local_arr) != -1) return verb; + if(sizeof(local_arr) > 1) return verb; + return local_arr[0]; + } + else return local_arr; + } + } + else { + if(subs) return ({ verb }); + else return verb; + } + return ""; +} + +varargs string add_article(string str, int def) { + if( !stringp(str) ) { + error("Bad argument 1 to add_article().\n"); + } + if( def ) { + str = remove_article(str); + return "the " + str; + } + if( !strlen(str) ) { + return str; + } + switch(str[0]) { + case 'a': case 'e': case 'i': case 'o': case 'u': + case 'A': case 'E': case 'I': case 'O': case 'U': + return "an " + str; + + default: + return "a " + str; + } +} + +string remove_article(string str) { + string tmp; + + if( !stringp(str) ) return(""); + if( sscanf(str, "the %s", tmp) ) return tmp; + if( sscanf(str, "a %s", tmp) ) return tmp; + if( sscanf(str, "an %s", tmp) ) return tmp; + return str; +} + +string array explode_list(string list) { + string array items; + string one, two; + + list = lower_case(list); + if( sscanf(list, "%s and %s", one, two) == 2 ) { + items = explode(one, ",") + explode(two, ","); + } + else { + items = explode(list, ","); + } + items = map(items, function(string str) { + if( !str ) { + return 0; + } + str = trim(str); + if( strlen(str) > 4 && str[0..3] == "and " ) { + str = str[4..]; + } + str = remove_article(str); + if( strlen(str) > 3 && str[0..2] == "my " ) { + str = str[3..]; + } + return str; + }); + return filter(items, (: $1 && $1 != "" :)); +} + +varargs string item_list(mixed array items...) { + mapping list = ([]); + string str; + int maxi; + + if( !sizeof(items) ){ + error("Bad argument 1 to item_list().\n"); + } + if( arrayp(items[0]) ) { + if( !sizeof(items[0]) ) { + return ""; + } + items = items[0]; + } + foreach(mixed value in items) { + if( objectp(value) ) { + if( living(value) ) { + value = value->GetName(); + } + else { + value = value->GetShort(); + } + } + if( !value ) { + continue; + } + if( !list[value] ) { + list[value] = 1; + } + else { + list[value]++; + } + } + maxi = sizeof(items = keys(list)); + if( maxi < 1 ) { + return ""; + } + str = consolidate(list[items[0]], items[0]); + if( maxi == 1 ) { + return str; + } + if( maxi > 2 ) { + str += ","; + } + for(int i=1; iGetName(); + else if(!stringp(val)) error("Bad argument 1 to possessive_noun().\n"); + switch(val[strlen(val)-1]) { + case 'x': case 'z': case 's': return sprintf("%s'", val); + default: return sprintf("%s's", val); + } +} + +string possessive(mixed val) { + switch(objectp(val) ? val->GetGender() : val) { + case "male": return "his"; + case "female": return "her"; + case "neutral": return "hir"; + default: return "its"; + } +} + +string strip_article(mixed val) { + int x; + + if( objectp(val) ) val = val->GetShort(); + x = strlen(val); + if( x <= 2 ) return val; + if( val[0..1] == "a " || val[0..1] == "A " ) return val[2..]; + if( x <= 3 ) return val; + if( val[0..2] == "an " || val[0..2] == "An " ) return val[3..]; + if( x <= 4 ) return val; + if( val[0..3] == "the " || val[0..3] == "The " ) return val[4..]; + return val; +} + +string nominative(mixed val) { + switch(objectp(val) ? val->GetGender() : val) { + case "male": return "he"; + case "female": return "she"; + case "neutral": return "sie"; + default: return "it"; + } +} + +string objective(mixed val) { + switch(objectp(val) ? val->GetGender() : val) { + case "male": return "him"; + case "female": return "her"; + case "neutral": return "hir"; + default: return "it"; + } +} + +string reflexive(mixed val) { return sprintf("%sself", objective(val)); } + +#if SEFUN_PLURALIZE +#define VOWELS ({"a","e","i","o","u"}) + +#define ABNORMAL ([ "moose":"moose", "mouse":"mice", "die":"dice", "index":"indices", "human":"humans", "sheep":"sheep", "fish":"fish", "child":"children", "ox":"oxen", "tooth":"teeth", "deer":"deer", "sphinx":"sphinges" ]) + +string pluralize(mixed single) { + int x, i, y, ind; + string str, tmp, tmp1; + string *words; + string ret = ""; + int reset = 0; + string clean_str = ""; + string modulo = ""; + + if(last(single,9) == "%^RESET%^"){ + reset = 1; + single = truncate(single,9); + } + + if(objectp(single)) { + if(str = single->query_plural_name()){ + return str; + } + else str = single->GetKeyName(); + } + else if(stringp(single)) str = single; + else error("Bad argument 1 to pluralize()"); + + if(!str){ + return str; + } + + clean_str = strip_colours(str); + modulo = replace_string(str, clean_str, ""); + x = strlen(clean_str); + + if(ABNORMAL[strip_colours(str)]){ + if(reset){ + ret = ABNORMAL[clean_str]; + ret = modulo + ret + "%^RESET%^"; + } + else ret = ABNORMAL[strip_colours(str)]; + return ret; + } + + if(x > 1) { + tmp = clean_str[x-2..x-1]; + switch(tmp) { + case "ch": case "sh": + ret = sprintf("%ses", clean_str); + break; + case "ff": case "fe": + ret = sprintf("%sves", clean_str[0..x-3]); + break; + case "us": + ret = sprintf("%si", clean_str[0..x-3]); + break; + case "um": + ret = sprintf("%sa", clean_str[0..x-3]); + break; + case "ef": + ret = sprintf("%ss", clean_str); + break; + } + } + + tmp = clean_str[x-1..x-1]; + switch(tmp) { + case "o": case "x": case "s": + ret = sprintf("%ses", clean_str); + break; + case "f": + ret = sprintf("%sves", clean_str[0..x-2]); + break; + case "y": + if(member_array(clean_str[x-2..x-2],VOWELS)!=-1) + ret = sprintf("%ss",clean_str); + else + ret = sprintf("%sies", clean_str[0..x-2]); + break; + } + if(sizeof(ret)){ + if(reset){ + ret = modulo + ret + "%^RESET%^"; + } + return ret; + } + ret = sprintf("%ss", clean_str); + if(reset){ + ret = modulo + ret + "%^RESET%^"; + } + return ret; +} +#endif + +#ifndef __FLUFFOS__ +string cardinal(int x) { + string tmp; + int a; + + if(!x) return "zero"; + if(x < 0) { + tmp = "negative "; + x = absolute_value(x); + } + else tmp = ""; + switch(x) { + case 1: return tmp+"one"; + case 2: return tmp+"two"; + case 3: return tmp+"three"; + case 4: return tmp+"four"; + case 5: return tmp+"five"; + case 6: return tmp+"six"; + case 7: return tmp+"seven"; + case 8: return tmp+"eight"; + case 9: return tmp+"nine"; + case 10: return tmp+"ten"; + case 11: return tmp+"eleven"; + case 12: return tmp+"twelve"; + case 13: return tmp+"thirteen"; + case 14: return tmp+"fourteen"; + case 15: return tmp+"fifteen"; + case 16: return tmp+"sixteen"; + case 17: return tmp+"seventeen"; + case 18: return tmp+"eighteen"; + case 19: return tmp+"nineteen"; + case 20: return tmp+"twenty"; + default: + if(x > 1000000000) return "over a billion"; + else if(a = x /1000000) { + if(x = x %1000000) + return sprintf("%s million %s", cardinal(a), cardinal(x)); + else return sprintf("%s million", cardinal(a)); + } + else if(a = x / 1000) { + if(x = x % 1000) + return sprintf("%s thousand %s", cardinal(a), cardinal(x)); + else return sprintf("%s thousand", cardinal(a)); + } + else if(a = x / 100) { + if(x = x % 100) + return sprintf("%s hundred %s", cardinal(a), cardinal(x)); + else return sprintf("%s hundred", cardinal(a)); + } + else { + a = x / 10; + if(x = x % 10) tmp = "-"+cardinal(x); + else tmp = ""; + switch(a) { + case 2: return "twenty"+tmp; + case 3: return "thirty"+tmp; + case 4: return "forty"+tmp; + case 5: return "fifty"+tmp; + case 6: return "sixty"+tmp; + case 7: return "seventy"+tmp; + case 8: return "eighty"+tmp; + case 9: return "ninety"+tmp; + default: return "error"; + } + } + } +} +#else +string cardinal(int x){ + string sign; + if(undefinedp(x) || !intp(x)) return sign; + sign = ( x < 0 ? "negative " : ""); + x = abs(x); + return sign+query_num(x); +} +#endif + +varargs string conjunction(mixed expressions, string coordinator) { + int size; + string tmp; + + if(!expressions) error("Bad argument 1 to conjunction().\n"); + else if(stringp(expressions)) expressions = ({ expressions }); + else if(!pointerp(expressions)) + error("Bad argument 1 to conjunction().\n"); + + size = sizeof(expressions); + if(size < 2) return expressions[0]; + + // Form the conjunction. + if(!coordinator) coordinator = "and"; + tmp = ""; + for(int i = 0; i < size; i++) { + tmp += expressions[i]; + if(i < size - 2) tmp += ", "; + else return tmp + ", " + coordinator + " " + expressions[size - 1]; + } +} + +string consolidate(int x, string str) { + string array words; + string tmp; + + if( x == 1 || !sizeof(str) ) return str; + words = explode(str, " "); + if( sscanf(words[<1], "(%s)", tmp) ) { + if( sizeof(words) == 1 ) + return "(" + consolidate(x, tmp) + ")"; + else return consolidate(x, implode(words[0..<2], " ")) + + " (" + tmp + ")"; + } + if( sscanf(words[<1], "[%s]", tmp) ) { + if( sizeof(words) == 1 ) + return "[" + consolidate(x, tmp) + "]"; + else return consolidate(x, implode(words[0..<2], " ")) + + " [" + tmp + "]"; + } + if( words[0][0..1] == "%^" ) { + string array parts; + string part, colour = ""; + int i = 0; + + parts = explode(words[0], "%^"); + if( sizeof(parts) == 1 ) { + if( sizeof(words) == 1 ) return words[0]; + else return words[0] + consolidate(x, implode(words[1..], " ")); + } + + foreach(part in parts) { + if( sizeof(part) && !sizeof(strip_colours("%^" + part + "%^")) ) + colour += ("%^" + part + "%^"); + else return colour + consolidate(x, + (implode(parts[i..], "%^")) + " " + + (implode(words[1..], " ")) ); + i++; + } + return words[0] + " " + consolidate(x, implode(words[1..], " ")); + + } + if( member_array(lower_case(strip_colours(words[0])), + ({"a", "an", "the", "one"}) ) > -1 ) words = words[1..]; + return (cardinal(x) + " " + pluralize(implode(words, " "))); +} + +varargs int ordinalp(string str, int parseflag){ + string *ords = ({ "first", "second", "third", "fourth", "fifth", + "sixth", "seventh", "eighth", "ninth", "tenth", "twelfth" }); + string *suffs = ({ "eenth", "ieth", "edth", "andth", "ionth" }) + ords; + if(parseflag){ + ords += ({ "my", "any", "other", "a", "an" }); + } + if(!str || !stringp(str)) return 0; + if(member_array(str, ords) != -1) return 1; + foreach(string element in suffs){ + if(sizeof(str) >= sizeof(element) && + str[ + +varargs void add_event(string source, string ob, string fun, mixed *args, int when, int repeat){ + if(!archp(this_player())) return; + EVENTS_D->AddEvent(source, ob, fun, args, when, repeat); +} + +varargs void remove_event(int i){ + if(!archp(this_player())) return; + EVENTS_D->RemoveEvent(i); +} + +int event_pending(object ob) { + mapping tmp; + int *cles; + string fn; + int i; + + tmp = EVENTS_D->GetEvents(); + fn = file_name(ob); + i = sizeof(cles = keys(tmp)); + while(i--) if( tmp[cles[i]]["object"] == fn ) return 1; + return 0; +} diff --git a/lib/secure/sefun/expand_keys.c b/lib/secure/sefun/expand_keys.c new file mode 100644 index 0000000..76f9d33 --- /dev/null +++ b/lib/secure/sefun/expand_keys.c @@ -0,0 +1,20 @@ +/* /secure/sefun/expand_keys.c + * from the Dead Souls Mud Library + * takes a mapping with array keys and flattens the arrays + * created by Descartes of Borg 951013 + */ + +mapping expand_keys(mapping mp) { + mapping tmp = ([]); + mixed key, val; + + foreach(key, val in mp) { + if( arrayp(key) ) { + string elem; + + foreach(elem in key) tmp[elem] = val; + } + else tmp[key] = val; + } + return tmp; +} diff --git a/lib/secure/sefun/files.c b/lib/secure/sefun/files.c new file mode 100644 index 0000000..65aabbd --- /dev/null +++ b/lib/secure/sefun/files.c @@ -0,0 +1,117 @@ +/* /secure/sefun/files.c + * from Dead Souls 3.3 + * functions which handle file operations + * created by Descartes of Borg 940926 + */ + +string Port, gtempname, gfilename; + +int file_exists(string str) { + if(!str || !stringp(str)) return 0; + return (file_size(str) > -1); +} + +mixed lpc_file(string str){ + if(!file_exists(str)){ + if(file_exists(str+".c")) return str+".c"; + else return 0; + } + else return str; +} + +mixed object_file(string str){ + if(!file_exists(str)){ + if(file_exists(str+".o")) return str+".o"; + else return 0; + } + else return str; +} + +int directory_exists(string str){ + if(!str || (sizeof(str) < 2 && str != "/")) return 0; + return (file_size(str) == -2); +} + +string player_save_file(string who){ + if( !stringp(who) ) error("Bad argument 1 to save_file()."); + who = convert_name(who); + return master()->player_save_file(who); +} + +string save_file(string what){ + string ret; +#if ENABLE_INSTANCES + ret = new_savename(what); +#else + ret = old_savename(what); +#endif + return ret; +} + +int indent_file(string filename){ + + string tempname; + tempname = "/tmp/indent."+time()+".tmp"; + + write_file(tempname,"I\n"); + + gtempname = tempname; + gfilename = filename; + if(!cp(filename,tempname+".dat")){ + write("You don't have read access to "+filename); + return 0; + } + + load_object("/secure/cmds/creators/lsed")->cmd(tempname+" "+tempname+".dat"); + + if(!unguarded((: cp(gtempname+".dat", gfilename) :)) ){ + write("You don't have write access to "+filename); + rm(tempname+".dat"); + rm(tempname); + return 0; + } + + rm(tempname+".dat"); + rm(tempname); + return 1; +} + +int mkdir_recurse(string path){ + string *path_arr = explode(path,"/"); + string agglutinate = ""; + + if(directory_exists(path)) return 0; + + foreach(string element in path_arr){ + agglutinate += "/"+element; + if(!directory_exists(agglutinate)){ + if(!mkdir(agglutinate)) return 0; + } + } + return 1; +} + +string new_savename(string name){ + string unoed, ported, bare; + int ret; + if(grepp(name, "."+__PORT__)) return name; + if(last(name,2) == ".o") unoed = truncate(name, 2); + else unoed = (name || ""); + bare = replace_string(unoed, ""+__PORT__, ""); + while(last(bare, 1) == "."){ + bare = truncate(bare, 1); + } + ported = bare + "." + __PORT__ + ".o"; + return ported; +} + +string old_savename(string name){ + string pre; + if(name){ + sscanf(name, "%s.%*s", pre); + if(pre) return pre+".o"; + return name+".o"; + } + return 0; +} + diff --git a/lib/secure/sefun/findobs.c b/lib/secure/sefun/findobs.c new file mode 100644 index 0000000..22754ff --- /dev/null +++ b/lib/secure/sefun/findobs.c @@ -0,0 +1,57 @@ +#include +private static string source; + +mixed *findobs(mixed arg){ + object target; + object *targets = ({}); + + if(objectp(arg)) target = arg; + if(stringp(arg) ) { + if(grepp(arg,"/")){ + if(!file_exists(arg)) arg += ".c"; + if(!file_exists(arg)) return ({}); + if(!target = find_object(arg)) return ({}); + } + else { + foreach(object ob in objects()){ + if(answers_to(arg,ob)) targets += ({ ob }); + } + } + } + if(target){ + foreach(object ob in objects()){ + if(base_name(ob) == base_name(target)) targets += ({ ob }); + } + } + return targets; +} + +mixed find_inheritors(mixed arg){ + object *targets = ({}); + if(objectp(arg)) source = base_name(arg); + else { + if(!stringp(arg)) return -2; + if(!file_exists(arg)) arg += ".c"; + if(!file_exists(arg)) return -1; + source = truncate(arg,2); + } + targets = filter(objects(), (: inherits(source, $1) :) ); + if(sizeof(targets)) return targets; + else return ({}); +} + +mixed find_deep_inheritors(mixed arg){ + object *targets = ({}); + if(objectp(arg)) source = base_name(arg)+".c"; + else { + if(!stringp(arg)) return -2; + if(!file_exists(arg)) arg += ".c"; + if(!file_exists(arg)) return -1; + source = arg; + } + + targets = filter(objects(), (: member_array(source, deep_inherit_list($1)) != -1 :) ); + if(sizeof(targets)) return targets; + else return ({}); +} + diff --git a/lib/secure/sefun/flat_map.c b/lib/secure/sefun/flat_map.c new file mode 100644 index 0000000..46e98b8 --- /dev/null +++ b/lib/secure/sefun/flat_map.c @@ -0,0 +1,32 @@ +string flat_map(mapping mp) { + mapping carte = ([]); + mixed key, val; + string retkey, retval, retstring; + + retstring = ""; + + carte = expand_keys(mp); + + foreach( key, val in carte){ + if(arrayp(key)){ + if(!sizeof(key)) retkey = "BLANK ARRAY"; + else retkey = "ARRAY ("+implode(key,", ")+")"; + } + else if(objectp(key)) retkey = "OBJECT ("+file_name(key)+")"; + else if(intp(key)) retkey = ""+key; + else retkey = key; + if(arrayp(val)){ + if(!sizeof(val)) retval = "BLANK ARRAY"; + else retval = "ARRAY ("+implode(val,", ")+")"; + } + else if(objectp(val)) retval = "OBJECT ("+file_name(val)+")"; + else if(intp(val)) retval = ""+val; + else retval = val; + + if(!retstring || retstring == "") retstring = retkey+":"+retval; + else retstring += ", "+retkey+":"+retval; + } + + return retstring; + +} diff --git a/lib/secure/sefun/format_page.c b/lib/secure/sefun/format_page.c new file mode 100644 index 0000000..ae5057c --- /dev/null +++ b/lib/secure/sefun/format_page.c @@ -0,0 +1,51 @@ +varargs string format_page(string *items, int columns, int modifier) { + int width, i, j, x; + string ret; + + if(!columns) columns = 2; + ret = ""; + if( this_player() ) width = ((int *)this_player()->GetScreen())[0]; + else width = 80; + width = (width/columns) + modifier; + for(i=0, x = sizeof(items); i= x) break; + ret += arrange_string(items[i+j], width); + } + ret += "\n"; + } + return ret; +} + +//Allows you to sort in descending columns +varargs string format_page2(string *items, int columns, int modifier){ + int length, rem, counter, height; + int extra, sz = sizeof(items); + string *tmp = ({}); + string *ret = ({}); + while(sz < (columns * 2)) columns--; + if(!columns) columns = 1; + length = sz / columns; + height = length; + rem = sz % columns; + if(rem) height++; + + while(sizeof(items)){ + if(rem > 0) extra = 1; + else extra = 0; + tmp = ({ items[0..((length-1)+extra)] }); + ret += tmp; + items = items[((length-1)+extra+1)..]; + rem--; + } + counter = 0; + tmp = ({}); + while(height){ + foreach(mixed arr in ret){ + if(sizeof(arr) >= (counter + 1) ) tmp += ({ arr[counter] }); + } + height--; + counter++; + } + return format_page(tmp, columns, modifier); +} diff --git a/lib/secure/sefun/fuzzymatch.c b/lib/secure/sefun/fuzzymatch.c new file mode 100644 index 0000000..30f8a8f --- /dev/null +++ b/lib/secure/sefun/fuzzymatch.c @@ -0,0 +1,60 @@ +int levenshtein_distance(string a, string b) { + int alen = sizeof(a); + int blen = sizeof(b); + mixed foo, baz = alen+1; + mixed array dist = ({}); +#ifdef __FLUFFOS__ + while(baz){ + dist += ({ allocate(blen +1) }); + baz--; + } + foreach(foo in dist){ + foo[0] = baz; + baz++; + } + baz = 1; + while(baz < (blen + 1)){ + dist[0][baz] = baz; + baz++; + } + for(int i = 0; i < alen; i++){ + for(int j = 0; j < blen; j++){ + dist[i + 1][j + 1] = min( ({ dist[i][j + 1] + 1, dist[i + 1][j] + 1, dist[i][j] + (a[i] != b[j]) }) ); + } + } + return dist[alen][blen]; +#else + return 1; +#endif +} + +int damerau_levenshtein_distance(string a, string b) { + int alen = sizeof(a); + int blen = sizeof(b); + mixed foo, baz = alen+1; + mixed array dist = ({}); +#ifdef __FLUFFOS__ + while(baz){ + dist += ({ allocate(blen +1) }); + baz--; + } + foreach(foo in dist){ + foo[0] = baz; + baz++; + } + baz = 1; + while(baz < (blen + 1)){ + dist[0][baz] = baz; + baz++; + } + for(int i = 0; i < alen; i++) + for(int j = 0; j < blen; j++) + if(i && j && a[i] == b[j - 1] && a[i - 1] == b[j]) + dist[i + 1][j + 1] = min( ({ dist[i][j + 1] + 1, dist[i + 1][j] + 1, dist[i][j] + (a[i] != b[j]), dist[i - 1][j - 1] + (a[i] != b[j]) }) ); + else + dist[i + 1][j + 1] = min( ({ dist[i][j + 1] + 1, dist[i + 1][j] + 1, dist[i][j] + (a[i] != b[j]) }) ); + return dist[alen][blen]; +#else + return 1; +#endif +} diff --git a/lib/secure/sefun/generic.c b/lib/secure/sefun/generic.c new file mode 100644 index 0000000..d1e0a7a --- /dev/null +++ b/lib/secure/sefun/generic.c @@ -0,0 +1,7 @@ +varargs int true(mixed args...){ + if(args || !args) return 1; +} + +varargs int false(mixed args...){ + if(args || !args) return 0; +} diff --git a/lib/secure/sefun/get_cmds.c b/lib/secure/sefun/get_cmds.c new file mode 100644 index 0000000..2699794 --- /dev/null +++ b/lib/secure/sefun/get_cmds.c @@ -0,0 +1,39 @@ +/* /secure/sefun/get_cmds.c + * returns an array of available commands + * Created by Cratylus 23JAN2005 + * Version: @(#) get_cmds.c 1.1@(#) + * Last modified: 2005/01/23 + */ + +string *get_cmds(){ + int i; + string str; + string *temparr,*cmds,*NULL; + + NULL = ({ "irony" }); + + if(!get_dir("/cmds/")) return NULL; + + foreach(str in get_dir("/cmds/")) + { + temparr=get_dir("/cmds/"+str+"/*.c"); + for(i=0;i 0) cmds += ({temparr[i]}); + } + } + + foreach(str in get_dir("/secure/cmds/")) + { + temparr=get_dir("/secure/cmds/"+str+"/*.c"); + for(i=0;i 0) cmds += ({temparr[i]}); + } + } + + return cmds; + +} diff --git a/lib/secure/sefun/get_livings.c b/lib/secure/sefun/get_livings.c new file mode 100644 index 0000000..df11a2e --- /dev/null +++ b/lib/secure/sefun/get_livings.c @@ -0,0 +1,61 @@ +/* /secure/sefun/get_livings.c + * From the Frontiers LPC Library + * an ugly hack to return an array of living things. + * Give it an integer argument to return interactives only + * Created by Cratylus 23JAN2005 + * Version: @(#) getlivings.c 1.1@(#) + */ + +varargs object array get_livings(object ob,int foo){ + object *stuff,*lstuff,*istuff; + int i; + if(!ob) return ({}); + stuff=all_inventory(ob); + lstuff = ({}); + for(i=0;i 0 && + member_array(stuff[i],lstuff) == -1) lstuff += ({stuff[i]}); + } + + if(foo == 1){ + istuff=({}); + for(i=0;i 0 && + member_array(lstuff[i],istuff) == -1) istuff+= ({lstuff[i]}); + } + if(sizeof(istuff) > 0) return istuff; + if(!sizeof(istuff)) return 0; + } + + if(foo == 2){ + istuff=({}); + for(i=0;i 0 && + member_array(lstuff[i],istuff) == -1) istuff+= ({lstuff[i]}); + } + if(sizeof(istuff) > 0) return istuff; + if(!sizeof(istuff)) return 0; + } + + if(sizeof(lstuff) > 0) return lstuff; + if(!sizeof(lstuff)) return 0; +} + +varargs object get_random_living(object room, int foo){ + object *livings; + + if(!foo) foo = 0; + + livings = get_livings(room, foo); + foo = random(sizeof(livings)); + + return livings[foo]; +} + + + + + diff --git a/lib/secure/sefun/get_object.c b/lib/secure/sefun/get_object.c new file mode 100644 index 0000000..857b553 --- /dev/null +++ b/lib/secure/sefun/get_object.c @@ -0,0 +1,227 @@ +/* +// get_object() and get_objects() +// Created by Pallando@Ephemeral Dale (92-06) +// Created by Watcher@TMI (92-09-27) +// Revised by Watcher and Pallando (92-12-11) +// Re-written by Pallando (92-12-18) +// get_objects() added by Pallando@Tabor (93-03-02) +// changed to use get_path() by Pallando@Dead Souls (93-05-28) +// +// Use all possible methods to locate an object by the inputed +// name and return the object pointer if located. +// Ideas for future expansion (please, anyone feel free to add them if they +// have the time) +// "wizards" - the subset of "users" who are wizards. +// check the capitalized and lower_case version of str +// check wizard's home directories. +// :c - suffix indicating the children() of the previous object's base name. +// :s - shadow of an object +// :>func - the object returned by the base object->func() (useful for things +// like referencing the monster attacking someone. + */ + +private static string gstr; + +varargs object get_object( string str, object player, int living ) +{ + object what,ret; + mixed tmp; + + // Prevent wizards finding things they shouldn't. + + if( !str ) return 0; + if( !player || !living( player ) ) player = this_player(); + if( sscanf( str, "@%s", tmp ) && + ( tmp = get_object( tmp, player ) ) && + ( what = environment( tmp ) ) ){ + return what; + } + if( player ) // Check existance of this_player() + { + if( str == "me" ){ + return player; + } + if( what = present( str, player ) ){ + object env = player; + object *candidates = ({}); + if(!OBJECT_MATCHING){ + return what; + } + gstr = str; + candidates = filter(all_inventory(player), + (: member_array(gstr, $1->GetCanonicalId()) != -1 :) ); + if(living){ + candidates = filter(candidates, (: living($1) :) ); + } + if(sizeof(candidates)){ + return candidates[0]; + } + } + if( what = environment( player ) ) // Environment check + { + if (str == "here" || str == "env" || str == "environment"){ + return what; + } + if( what = present( str, what ) ){ + object env = environment(player); + object *candidates = ({}); + if(!OBJECT_MATCHING){ + return what; + } + gstr = str; + candidates = filter((all_inventory(player)+all_inventory(env)), + (: member_array(gstr, $1->GetCanonicalId()) != -1 :) ); + if(living){ + candidates = filter(candidates, (: living($1) :) ); + } + if(sizeof(candidates)){ + return candidates[0]; + } + } + } + } + + // Call might be made by a room so make a previous_object() check + // first just to be sure + + if( what = present( str, previous_object() ) ){ + return what; + } + + // Check to see if a living object matches the name + + if( what = find_player( str ) ){ + return what; + } + if( what = find_living( str ) ){ + return what; + } + + // Search for a matching file_name, completing path with + // user's present path + + if( player ) + { + // this option removed because Dead Souls doesn't support cwf + // if( str == "cwf" ) str = player-> query( "cwf" ); + str = (absolute_path( player-> get_path(), str ) || ""); + } + + if( catch(ret = find_object(str)) ){ + return 0; + } + if(!ret) ret = to_object(str); + if(!ret && (file_exists(str) || file_exists(str+".c"))) ret = load_object(str); + + // Finally return any object found matching the requested name + return ret; +} + +// Created by Pallando@Tabor (93-03-02) +// player - as per get_object() +// no_arr - if specified, only 0 or an object will be returned, +// otherwise an array of objects may also be returned. +// str - eg +// "pallando" - returns the object, /lib/user#123 +// "pallando:i" - returns pallando's inventory +// "pallando:e" - returns pallando's environment +// "pallando:e:d:12" - returns the 12th object in the deep inventory of +// the room that pallando is in. +// "caractacus:e:lady" - finds a lady of the court of King Caractacus 8-) +// "users:rod" - searches the inventories of all users for a rod. +// "users:e:guard" - searches the environments of all users for a guard. +varargs mixed get_objects( string str, object player, int no_arr ) +{ + mixed base, tmp, ret; + object what; + int i, s; + // Hmm. i and s do several jobs here. It would be clearer to use different + // variables (with longer names) for each job. + // Is it worth slowing the function (using more memory) to do this? + + + if( !str ) return 0; + s = strlen( str ); + i = s; + while( i-- && ( str[i..i] != ":" ) ); // a reverse sscanf + if( ( i > 0 ) && ( i < ( s - 1 ) ) ) // of form "%s:%s" + { + base = get_objects( str[0..(i-1)], player ); + str = str[(i+1)..s]; + if( !base ) return 0; + if( !pointerp( base ) ) base = ({ base }); + s = sizeof( base ); + ret = ({ }); + if( str == "e" ) + { + while( s-- ) + if( tmp = environment( base[s] ) ) + ret += ({ tmp }); + } else if( str == "i" ) { + while( s-- ) + if( tmp = all_inventory( base[s] ) ) + ret += ( pointerp( tmp ) ? tmp : ({ tmp }) ); + } else if( str == "d" ) { + while( s-- ) + if( tmp = deep_inventory( base[s] ) ) + ret += ( pointerp( tmp ) ? tmp : ({ tmp }) ); + } else if( sscanf( str, "%d", i ) ) { + if( ( i > -1 ) && ( i < s ) ) return base[i]; + else return 0; + } else { + // This is the location to add more syntax options if wanted such as + // ith item in jth base object, all such items in all base objects, etc + while( s-- ) + if( what = present( str, base[s] ) ) + return what; + return 0; + } + switch( sizeof( ret ) ) + { + case 0: return 0; + case 1: return ret[0]; + } + return( no_arr ? ret[0] : ret ); + } + if( str == "users" ) + { + ret = users(); + if( !no_arr ) return ret; + if( sizeof( ret ) ) return ret[0]; + return 0; + } + return get_object( str, player ); +} + +/* + NB + + It would be fairly simple to combine these two functions into one + varargs object get_object( string str, object player, int arr_poss ) + which will only return a single object unless the array_possible flag + is passed. + + I have chosen not to do this however, since some muds may not wish to + use the more complicated search routines and keeping get_objects() as + a seperate simul_efun makes it easier to disable. + */ + +object *get_dummies(mixed where){ + object *ret = ({}); + if(stringp(where)) where = to_object(where); + if(!where || !objectp(where)) return ret; + ret = filter(deep_inventory(where), (: inherits(LIB_BASE_DUMMY, $1) || + base_name($1) == LIB_BASE_DUMMY || base_name($1) == LIB_DUMMY :) ); + return ret; +} + +object *get_doors(mixed where){ + object *ret = ({}); + if(stringp(where)) where = to_object(where); + if(!where || !objectp(where)) return ret; + foreach(string element in where->GetDoors()){ + catch( ret += ({ load_object(where->GetDoor(element)) }) ); + } + return ret; +} + diff --git a/lib/secure/sefun/get_stack.c b/lib/secure/sefun/get_stack.c new file mode 100644 index 0000000..8ddb5ff --- /dev/null +++ b/lib/secure/sefun/get_stack.c @@ -0,0 +1,20 @@ +varargs string get_stack(int x) { + int i, s; + string list = ""; + string *stack0 = call_stack(0); + string *stack1 = call_stack(1); + string *stack2 = call_stack(2); + string *stack3 = call_stack(3); + for(i = 0, s = sizeof(stack1); i < s; i++){ + list +="\n"+i+":"+ + "%^RED%^" + identify(stack1[i]) + + "%^RESET%^, %^GREEN%^file: "+stack0[i]+ + "%^RESET%^, %^BLUE%^fun: "+stack2[i]+ + "%^RESET%^, %^MAGENTA%^origin: "+stack3[i]+ + "%^RESET%^"; + } + if(!x){ + list = strip_colours(list); + } + return list; +} diff --git a/lib/secure/sefun/get_verbs.c b/lib/secure/sefun/get_verbs.c new file mode 100644 index 0000000..6907225 --- /dev/null +++ b/lib/secure/sefun/get_verbs.c @@ -0,0 +1,25 @@ +/* /secure/sefun/get_verbs.c + * returns an array of available verbs + * Created by Cratylus 23JAN2005 + * Version: @(#) get_verbs.c 1.1@(#) + * Last modified: 2005/01/23 + */ + +string *get_verbs(){ + int i; + string str; + string *temparr,*verbs; + + foreach(str in get_dir("/verbs/")) + { + temparr=get_dir("/verbs/"+str+"/*.c"); + for(i=0;i 0) verbs += ({temparr[i]}); + } + } + return verbs; + +} + diff --git a/lib/secure/sefun/identify.c b/lib/secure/sefun/identify.c new file mode 100644 index 0000000..f7addec --- /dev/null +++ b/lib/secure/sefun/identify.c @@ -0,0 +1,64 @@ +/* /secure/sefun/identify.c + * from the Dead Souls LPC Library + * represent a variable of any type as a string, now out of date + * remains for backwards compat + * created by Pallando@Dead Souls (Douglas Reay) 921212 + */ + +varargs string identify( mixed a ) +{ + int i, s; + string ret; + mapping RealMap; + + if( undefinedp( a ) ) return "UNDEFINED"; + if( nullp( a ) ) return "0"; + if( intp( a ) ) return "" + a; + if( floatp( a ) ) return "" + a; + if( objectp( a ) ) + { + if( ret = a-> GetKeyName() ) ret += " "; + else ret = ""; + return "OBJ(" + ret + file_name( a ) + ")"; + } + if( stringp( a ) ) + { + a = replace_string( a, "\"", "\\\"" ); + a = "\"" + a + "\""; + a = replace_string( a, "\\", "\\\\" ); + a = replace_string( a, "\\\"", "\"" ); + a = replace_string( a, "\n", "\\n" ); + a = replace_string( a, "\t", "\\t" ); + return a; + } + if(classp(a)){ + ret = replace_string(sprintf("%O",a),"\n",""); + return ret; + } + if( pointerp( a ) ) + { + ret = "({ "; + s = sizeof( a ); + for( i = 0 ; i < s ; i++ ) + { + if( i ) ret += ", "; + ret += identify( a[i] ); + } + return ret + ( s ? " " : "" ) + "})"; + } + if( mapp( a ) ) + { + ret = "([ "; + RealMap = (a); + a = keys( RealMap ); + s = sizeof( a ); + for( i = 0 ; i < s ; i++ ) + { + if( i ) ret += ", "; + ret += identify( a[i] ) + " : " + identify( RealMap[a[i]] ); + } + return ret + ( s ? " " : "" ) + "])"; + } + if(functionp(a)) return sprintf("%O", a); + return "UNKNOWN"; +} diff --git a/lib/secure/sefun/interface.c b/lib/secure/sefun/interface.c new file mode 100644 index 0000000..eb84233 --- /dev/null +++ b/lib/secure/sefun/interface.c @@ -0,0 +1,35 @@ +/* /adm/sefun/interface.c + * from Dead Souls + * user interface sefuns + * created by Descartes of Borg 940215 + */ + +#include + +string strip_colours(string str){ + string ret; + mapping Uncolor = ([ "RESET": "\b", "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": "", "B_BLUE":"", + "ENDTERM":""]); + ret = terminal_colour(str, Uncolor); + return replace_string(ret, "\b", ""); +} + +string strip_colors(string str){ + return strip_colours(str); +} + +string strip_colors_old(string str){ + string output = ""; + string *input = explode(str,"%^"); + string *list = ({ "RED","YELLOW","BLUE","GREEN","MAGENTA","ORANGE","CYAN","BLACK","WHITE"}); + list += ({ "B_RED","B_YELLOW","B_BLUE","B_GREEN","B_MAGENTA","B_ORANGE","B_CYAN","B_BLACK","B_WHITE"}); + list += ({"BOLD","FLASH","RESET"}); + foreach(string color in list) input -= ({ color }); + output = implode(input,""); + if(sizeof(output)) return output; + else return ""; +} diff --git a/lib/secure/sefun/inventory.c b/lib/secure/sefun/inventory.c new file mode 100644 index 0000000..2c21a99 --- /dev/null +++ b/lib/secure/sefun/inventory.c @@ -0,0 +1,21 @@ +int query_carrying(object who, mixed thing){ + if(objectp(thing)) thing = base_name(thing); + if(last(thing,2) == ".c") truncate(thing,2); + + if(!file_exists(thing+".c")) return 0; + + foreach(object ob in deep_inventory(who)){ + if(base_name(ob) == thing) return 1; + } + return 0; +} + +object *containers(object ob){ + object *ret =({}); + if(!ob) ob = previous_object(); + while(environment(ob)){ + ret += ({ environment(ob) }); + ob = environment(ob); + } + return ret; +} diff --git a/lib/secure/sefun/legacy.c b/lib/secure/sefun/legacy.c new file mode 100644 index 0000000..7eebc2c --- /dev/null +++ b/lib/secure/sefun/legacy.c @@ -0,0 +1,128 @@ +#include ROOMS_H +#include + +void set(mixed arg1, mixed arg2){ + string s1, s2; + arg1 = capitalize(arg1); + if(!grepp(arg1,"/")) call_other( previous_object(), ({ "Set"+arg1, arg2 }) ); + else { + sscanf(arg1,"%s/%s",s1,s2); + arg1 = s1; + arg2 = "([\""+s2+"\":"+identify(arg2)+"])"; + call_other( previous_object(), ({ "Set"+arg1, arg2 }) ); + } + return; +} + +void add(mixed arg1, mixed arg2){ + string s1, s2; + arg1 = capitalize(arg1); + if(!grepp(arg1,"/")) call_other( previous_object(), ({ "Add"+arg1, arg2 }) ); + else { + sscanf(arg1,"%s/%s",s1,s2); + arg1 = s1; + arg2 = "([\""+s2+"\":"+identify(arg2)+"])"; + call_other( previous_object(), ({ "Add"+arg1, arg2 }) ); + } + return; +} + +void query(mixed arg1, mixed arg2){ + arg1 = capitalize(arg1); + call_other( previous_object(), ({ "Get"+arg1, arg2 }) ); + return; +} + +varargs mixed dump_variable(mixed foo, mixed bar){ + return identify(foo); +} + +void personal_log(string str){ + tell_room(ROOM_ARCH,str); + return; +} + +void add_sky_event(function f){ + SEASONS_D->AddTimeEvent("night", f); +} + +mixed seteuid(mixed args){ + return args; +} + +mixed getuid(mixed args){ + return args; +} + +mixed geteuid(mixed args){ + return args; +} + +mixed set_verbs(string *args){ + previous_object()->SetCombatAction(5, args); +} + +string day(){ + return SEASONS_D->GetDayName(); +} + +int date(){ + return SEASONS_D->GetDay(); +} + +string month(){ + return SEASONS_D->GetMonth(); +} + +int year(){ + return SEASONS_D->GetCurrentYear(); +} + +varargs int minutes(int x){ + if(!x) x = time(); + return SEASONS_D->GetMinutes(x); +} + +varargs string season(int x){ + if(!x) x = time(); + return SEASONS_D->GetSeason(x); +} + +varargs int hour(int x){ + if(!x) x = time(); + return SEASONS_D->GetHour(x); +} + +string query_time(){ + int hour, minutes; + int *time_of_day; + string hour_string, minute_string; + + time_of_day = SEASONS_D->GetMudTime(); + hour = time_of_day[0]; + minutes = time_of_day[1]; + + if(hour > 12) hour -= 12; + + hour_string = cardinal(hour); + switch(minutes){ + case 0 : minute_string ="o'clock"; break; + case 1 : minute_string = hour_string;hour_string ="one minute past"; break; + case 2 : minute_string = hour_string;hour_string ="two minutes past"; break; + case 3 : minute_string = hour_string;hour_string ="three minutes past"; break; + case 4 : minute_string = hour_string;hour_string ="four minutes past"; break; + case 5 : minute_string = hour_string;hour_string ="five past"; break; + case 6 : minute_string = hour_string;hour_string ="six minutes past"; break; + case 7 : minute_string = hour_string;hour_string ="seven minutes past"; break; + case 8 : minute_string = hour_string;hour_string ="eight minutes past"; break; + case 9 : minute_string = hour_string;hour_string ="nine minutes past"; break; + case 10 : minute_string = hour_string;hour_string ="ten past"; break; + case 15 : minute_string = hour_string;hour_string ="quarter past"; break; + case 45 : minute_string = cardinal(hour+1);hour_string ="quarter of"; break; + case 50 : minute_string = cardinal(hour+1);;hour_string ="ten of"; break; + case 55 : minute_string = cardinal(hour+1);hour_string ="five of"; break; + default : minute_string = cardinal(minutes);break; + } + if(minute_string == "thirteen") minute_string = "one"; + return hour_string+" "+minute_string; +} diff --git a/lib/secure/sefun/light.c b/lib/secure/sefun/light.c new file mode 100644 index 0000000..f890a66 --- /dev/null +++ b/lib/secure/sefun/light.c @@ -0,0 +1,75 @@ +/* /adm/simul_efun/light.c + * from Dead Souls + * light sefuns + * created by Descartes of Borg 940213 + */ + +#include + +varargs int effective_light(object ob) { + object *inv; + int i, x; + + if( !ob ) ob = previous_object(); + x = total_light(ob) + ob->GetSightBonus(); + i = sizeof(inv = all_inventory(ob)); + while(i--) x += inv[i]->GetRadiantLight(); + return x; +} + +varargs int total_light(object ob) { + object *inv; + object env; + int i, x; + + if( !ob ) ob = previous_object(); + if( !(env = environment(ob)) ) return 0; + i = sizeof(inv = all_inventory(env)); + x = env->GetAmbientLight(); + x += ob->GetRadiantLight(); + while(i--) x += inv[i]->GetRadiantLight(); + if( env->GetClimate() == "indoors" ) return x; + switch(SEASONS_D->query_time_of_day()) { + case "day": return x; + case "night": + x += SEASONS_D->GetMoonLight(); + return x; + case "dawn": case "twilight": return (x-1); + default: return x; + } +} + +varargs int visibility(object ob) { + int x; + + if( !ob ) ob = previous_object(); + x = effective_light(ob); + if( x > 5 || x < -2 ) return 0; + else if( x > 3 || x < 0 ) return 1; + else return 2; +} + +mixed check_light(object who) { + int light; + object env; + if(!who) who = this_player(); + env = environment(who); + if(!env) return "You are nowhere."; + if(env->GetMount() || base_name(env) == LIB_CORPSE){ + env = environment(environment(this_player())); + if(!env){ + return "You are in serious trouble. Ask an admin for help."; + } + } + light = who->GetEffectiveVision(env); + if( light < 3 ) { + return "It's too dark to see."; + } + else if( light > 6 ) { + return "It's too bright to see."; + } + else { + return 1; + } +} + diff --git a/lib/secure/sefun/load_object.c b/lib/secure/sefun/load_object.c new file mode 100644 index 0000000..a59f741 --- /dev/null +++ b/lib/secure/sefun/load_object.c @@ -0,0 +1,66 @@ +/* /secure/sefun/load_object.c + * from the Dead Souls LPC Library + * find and object and return it, or load an object and return it + * created by Descartes of Borg 940213 + */ + +#include + +object global_load_ob; + +object load_object(string str) { + object ob; + if(!str) return 0; + if(MEMUSE_HARD_LIMIT && memory_info() > MEMUSE_HARD_LIMIT){ + if(EVENTS_D->GetRebooting()){ + return 0; + } + reap_dummies(); + reset_eval_cost(); + reap_other(); + reset_eval_cost(); + reclaim_objects(); + reset_eval_cost(); + MASTER_D->RequestReset(); + if(memory_info() > MEMUSE_HARD_LIMIT){ + EVENTS_D->eventReboot(MINUTES_REBOOT_WARNING); + return 0; + } + } + if(!stringp(str)) error("Bad argument 1 to load_object().\n"); + if(ob = find_object(str)) return ob; + if(grepp(str, "cratylus")){ + string proof = read_file(str,4,3); + } + catch(call_other(str, "???")); + return find_object(str); +} + +int update(string file){ + object ob; + + if(!file_exists(file)) file += ".c"; + if(!file_exists(file)) return 0; + if(last(file,2) == ".c") file = truncate(file,2); + if(ob = find_object(file)){ + global_load_ob = ob; + unguarded( (: global_load_ob->eventDestruct() :) ); + } + if(find_object(file)) { + if(find_object(file)) destruct(ob); + } + if(find_object(file)) { + if(find_object(file)) reap_other(); + } + if(find_object(file)) { + return 0; + } + catch(call_other(file, "???")); + if(!find_object(file)) { + load_object(file); + } + if(!find_object(file)) { + return 0; + } + return 1; +} diff --git a/lib/secure/sefun/local_time.c b/lib/secure/sefun/local_time.c new file mode 100644 index 0000000..ff2b296 --- /dev/null +++ b/lib/secure/sefun/local_time.c @@ -0,0 +1,102 @@ +/* This file cleane dup by Jonez, + * 21Mar06 + */ + +#include +#include +#include +#include + +string tz; +string *zonearray = explode((read_file(CFG_TIMEZONES)|| ""), "\n"); +mapping months = ([ + 0 : "January", + 1 : "February", + 2 : "March", + 3 : "April", + 4 : "May", + 5 : "June", + 6 : "July", + 7 : "August", + 8 : "September", + 9 : "October", + 10 : "November", + 11 : "December",]); +mapping days = ([ + 0 : "Sunday", + 1 : "Monday", + 2 : "Tuesday", + 3 : "Wednesday", + 4 : "Thursday", + 5 : "Friday", + 6 : "Saturday", + ]); + +string query_tz(){ + if(tz) return tz; + if (file_size("/cfg/timezone.cfg") > 0) + tz = read_file("/cfg/timezone.cfg")[0..2]; + if (!tz) tz = "GMT"; + return tz; +} + +varargs mixed local_ctime(int i, string tzone){ + int x, offset; + if(!tzone || !valid_timezone(tzone)) tzone = query_tz(); + offset = TIME_D->GetOffset(tzone); + offset += EXTRA_TIME_OFFSET; + if(query_os_type() != "windows" ) x = offset * 3600; + else x = 0; + return ctime(i + x); +} + +varargs mixed local_time(mixed val){ + mixed stuff = ({}); + string tzone; + int offset; + if(stringp(val)) { + val = upper_case(val); + if(member_array(val, zonearray) != -1) tzone = val; + } + if(!tzone) tzone = query_tz(); + offset = TIME_D->GetOffset(tzone); + offset += EXTRA_TIME_OFFSET; + offset *= 3600; + + stuff = localtime(time() + offset); + stuff[9] = tzone; + return stuff; +} + +int valid_timezone(string str){ + if(!str || str == "") return 0; + str = upper_case(str)[0..2]; + if(member_array(str,zonearray) == -1) { + return 0; + } + else return 1; +} + +string set_tz(string str){ + if(!str) str = ""; + if( str != "" && !valid_timezone(str)) { + return "Invalid time zone."; + } + tz = str; + if( !(master()->valid_apply(({ "PRIV_ASSIST", "PRIV_SECURE" }))) ) + error("Illegal attempt to modify timezone: "+get_stack()+" "+identify(previous_object(-1))); + unguarded( (: write_file("/cfg/timezone.cfg",tz,1) :) ); + return "Mud time zone is now "+read_file("/cfg/timezone.cfg"); +} + +varargs string system_month(int i, int abbr){ + if(!months[i]) return ""; + if(!abbr) return months[i]; + else return months[i][0..2]; +} + +varargs string system_day(int i, int abbr){ + if(!days[i]) return ""; + if(!abbr) return days[i]; + else return days[i][0..2]; +} diff --git a/lib/secure/sefun/log_file.c b/lib/secure/sefun/log_file.c new file mode 100644 index 0000000..fff2c1d --- /dev/null +++ b/lib/secure/sefun/log_file.c @@ -0,0 +1,30 @@ +/* /adm/simul_efun/log_file.c + * from Dead Souls Mudlib 3.2 + * a simul_efun for logging to the log dir + * created by Descartes of Borg 940121 + */ + +#include +#include + +void log_file(string fl, string msg) { + string prefix = path_prefix(fl); + if(!stringp(fl)) error("Bad argument 1 to log_file().\n"); + if(!stringp(msg)) msg = identify(msg); + if(strsrch(fl, "..") != -1) error("Illegal file reference.\n"); + if(fl[0..0] == "/" && !directory_exists(prefix)){ + fl = last_string_element(fl,"/"); + } + if(fl[0..0] != "/"){ + if(living(previous_object(0)) || previous_object(0) == master()) + fl = DIR_LOGS + "/" + fl; + else if(master()->valid_apply(({ PRIV_CMDS, PRIV_MUDLIB }))) + fl = DIR_LOGS+"/"+fl; + else if(previous_object() && query_privs(previous_object()) && + member_array(PRIV_SECURE,explode(query_privs(previous_object()),":")) + != -1) fl = DIR_LOGS+"/"+fl; + else fl = DIR_LOGS+"/open/"+fl; + } + + master()->master_log_file(fl, msg); +} diff --git a/lib/secure/sefun/make_workroom.c b/lib/secure/sefun/make_workroom.c new file mode 100644 index 0000000..a3689e2 --- /dev/null +++ b/lib/secure/sefun/make_workroom.c @@ -0,0 +1,98 @@ +#include + +private string nom, cdir; + +varargs int make_workroom(mixed dude, int cre) { + string tdir, dir_line, bakdata; + int creator; + + if(!dude) return 0; + + if(objectp(dude)){ + cdir = homedir(dude, cre); + creator = (cre || creatorp(dude)); + if(sizeof(get_dir(REALMS_DIRS+"/")) ==1) creator = 1; + nom = dude->GetKeyName(); + } + + if(stringp(dude)){ + dude = lower_case(dude); + if(cre || member_array(dude, PLAYERS_D->GetCreatorList()) != -1){ + creator = 1; + cdir = REALMS_DIRS + "/" + dude; + } + else { + cdir = ESTATES_DIRS + "/" + dude[0..0] + "/" + dude; + } + nom = dude; + } + + if(unguarded( (: file_size("/realms/template/") :) ) == -1) return 4; + + if(unguarded( (: file_size(cdir+"/area") :) ) == -1){ + tdir = "/realms/template/"; + dir_line = "#define MY_DIR \""+cdir+"\""; + bakdata = "workroom.orig : "+cdir+"/workroom.c\n"; + mkdir(cdir); + mkdir(cdir+"/log"); + mkdir(cdir+"/log/archive"); + mkdir(cdir+"/bak"); + mkdir(cdir+"/tmp"); + mkdir(cdir+"/area"); + mkdir(cdir+"/adm"); + mkdir(cdir+"/area/room"); + mkdir(cdir+"/area/save"); + mkdir(cdir+"/area/weap"); + mkdir(cdir+"/area/obj"); + mkdir(cdir+"/area/npc"); + mkdir(cdir+"/area/armor"); + mkdir(cdir+"/area/etc"); + mkdir(cdir+"/area/doors"); + mkdir(cdir+"/area/meals"); + + if(creator){ + mkdir(cdir+"/cmds"); + mkdir(cdir+"/public_html"); + cp(tdir+"plan", cdir+"/.plan"); + cp(tdir+"evaldefs.h", cdir+"/evaldefs.h"); + cp(tdir+"profile", cdir+"/.profile"); + cp(tdir+"cmds/custom.c", cdir+"/cmds/custom.c"); + cp(tdir+"workroom.c", cdir+"/workroom.c"); + cp(tdir+"workroom.c", cdir+"/workroom.bak"); + cp(tdir+"workroom.c", cdir+"/bak/workroom.orig"); + cp(tdir+"area/obj/chest.c", cdir+"/area/obj/chest.c"); + } + + else { + cp(tdir+"workroom_builder.c", cdir+"/workroom.c"); + cp(tdir+"workroom_builder.c", cdir+"/workroom.bak"); + cp(tdir+"workroom_builder.c", cdir+"/bak/workroom.orig"); + cp(tdir+"area/obj/builder_chest.c", cdir+"/area/obj/builder_chest.c"); + } + + cp(tdir+"adm/remote.c",cdir+"/adm/remote.c"); + write_file(cdir+"/bak/bk.db",bakdata); + cp(tdir+"area/customdefs.part1", cdir+"/area/customdefs.h"); + write_file(cdir+"/area/customdefs.h","\n"+dir_line+"\n"); + write_file(cdir+"/area/customdefs.h",read_file(tdir+"area/customdefs.part2")); + cp(tdir+"area/room/sample_room.c", cdir+"/area/room/sample_room.c"); + cp(tdir+"area/room/sample_two.c", cdir+"/area/room/sample_two.c"); + cp(tdir+"area/weap/sword.c", cdir+"/area/weap/sword.c"); + cp(tdir+"area/obj/table.c", cdir+"/area/obj/table.c"); + cp(tdir+"area/obj/key.c", cdir+"/area/obj/key.c"); + cp(tdir+"area/obj/case.c", cdir+"/area/obj/case.c"); + cp(tdir+"area/obj/cup.c", cdir+"/area/obj/cup.c"); + cp(tdir+"area/obj/pitcher.c", cdir+"/area/obj/pitcher.c"); + cp(tdir+"area/obj/watch.c", cdir+"/area/obj/watch.c"); + cp(tdir+"area/npc/fighter.c", cdir+"/area/npc/fighter.c"); + cp(tdir+"area/armor/chainmail.c", cdir+"/area/armor/chainmail.c"); + cp(tdir+"area/armor/leather_boot_r.c", cdir+"/area/armor/leather_boot_r.c"); + cp(tdir+"area/armor/leather_boot_l.c", cdir+"/area/armor/leather_boot_l.c"); + return 1; + } + + else { + //write("That person already has a homedir."); + return 5; + } +} diff --git a/lib/secure/sefun/mappings.c b/lib/secure/sefun/mappings.c new file mode 100644 index 0000000..5e6e2e3 --- /dev/null +++ b/lib/secure/sefun/mappings.c @@ -0,0 +1,67 @@ +string flat_map(mapping mp) { + mapping carte = ([]); + mixed key, val; + string retkey, retval, retstring; + + retstring = ""; + + carte = expand_keys(mp); + + foreach( key, val in carte){ + if(arrayp(key)){ + if(!sizeof(key)) retkey = "BLANK ARRAY"; + else retkey = "ARRAY ("+implode(key,", ")+")"; + } + else if(objectp(key)) retkey = "OBJECT ("+file_name(key)+")"; + else if(intp(key)) retkey = ""+key; + else retkey = key; + if(arrayp(val)){ + if(!sizeof(val)) retval = "BLANK ARRAY"; + else retval = "ARRAY ("+implode(val,", ")+")"; + } + else if(objectp(val)) retval = "OBJECT ("+file_name(val)+")"; + else if(intp(val)) retval = ""+val; + else retval = val; + + if(!retstring || retstring == "") retstring = retkey+":"+retval; + else retstring += ", "+retkey+":"+retval; + } + + return retstring; + +} + +varargs mapping add_maps(mapping FirstMapping,mapping SecondMapping, int preference){ + mapping OutMap = ([]); + mapping FirstMap = copy(FirstMapping); + mapping SecondMap = copy(SecondMapping); + + foreach(mixed key, mixed val in (FirstMap || ([]))){ + OutMap[copy(key)] = copy(val); + } + + foreach(mixed key, mixed val in (SecondMap || ([]))){ + OutMap[copy(key)] = copy(val); + } + + return OutMap; +} + +int mgrepp(string primary, string *sub){ + foreach(string element in sub){ + if(strsrch(primary,element) != -1) return 0; + } + return 1; +} + +mixed mapping_member(mapping Map, string sub){ + foreach(mixed key, mixed val in Map){ + if(stringp(key) && key == sub) return key; + else if(arrayp(key) && member_array(sub, key) != -1) return key; + } + return 0; +} + + + + diff --git a/lib/secure/sefun/messaging.c b/lib/secure/sefun/messaging.c new file mode 100644 index 0000000..6e9be8d --- /dev/null +++ b/lib/secure/sefun/messaging.c @@ -0,0 +1,569 @@ +/* /secure/sefun/messaging.c + * From the Dead Souls Mud Library + * Messaging efuns, based on ideas shamelessly borrowed from Lima + * Created by Descartes of Borg 961029 + * Version: @(#) messaging.c 1.10@(#) + * Last modified: 96/12/16 + */ + +#include + +string create_message(int pov, string array verb, string message, + string subject, string subject_gen, string targets, + string target_gen, mapping special) { + string array words = explode(message, " "); + string array control = copy(words); + int i, maxi = sizeof(words); + int verb_count = 0; + int c; + + switch(pov) { + case POV_SUBJECT: + for(i=0; i 'z' ) { + punctuation = words[i][<1..<1] + punctuation; + words[i] = words[i][0..<2]; + } + else { + break; + } + } + switch(words[i]) { + case "$agent_verb": + words[i] = verb[verb_count++]; + break; + + case "$agent_name": case "$agent_nominative": + case "$agent_objective": + words[i] = "you"; + break; + + case "$agent_possessive_noun": + words[i] = "your"; + break; + + case "$agent_possessive": + words[i] = "your"; + break; + + case "$agent_reflexive": + words[i] = "yourself"; + break; + + case "$target_verb": + if( targets == subject ) { + words[i] = verb[verb_count]; + } + else { + if( target_gen == "plural" ) { + words[i] = verb[verb_count]; + } + else { + words[i] = pluralize(verb[verb_count]); + } + } + verb_count++; + break; + + case "$target_name": + if( subject == targets ) { // subject? object? + if( i == 0 ) { // certainly subject + words[i] = "you"; + } + else if( i == sizeof(words)-1 ) { // probably object + words[i] = "yourself"; + } + else if( words[i+1] == "$target_verb" ) { // subject? + words[i] = "you"; + } + else if(member_array("$agent_verb",control[0..i]) != -1 ) { + words[i] = "yourself"; // getting desperate here + } + else { // Oh hell + words[i] = "you"; + } + } + else { + words[i] = targets; + } + break; + + case "$target_nominative": + if( subject == targets ) { + words[i] = "you"; + } + else { + if( !target_gen ) { + words[i] = targets; + } + else if( target_gen == "plural" ) { + words[i] = "they"; + } + else { + words[i] = nominative(target_gen); + } + } + break; + + case "$target_objective": + if( subject == targets ) { + words[i] = "yourself"; + } + else { + if( !target_gen ) { + words[i] = targets; + } + else if( target_gen == "plural" ) { + words[i] = "them"; + } + else { + words[i] = objective(target_gen); + } + } + break; + + case "$target_possessive_noun": + if( subject == targets ) { + words[i] = "your"; + } + else { + if( !target_gen ) { + words[i] = possessive_noun(targets); + } + else if( target_gen == "plural" ) { + words[i] = "their"; + } + else { + words[i] = possessive_noun(targets); + } + } + break; + + case "$target_possessive": + if( subject == targets ) { + words[i] = "your"; + } + else { + if( !target_gen ) { + words[i] = possessive_noun(targets); + } + else if( target_gen == "plural" ) { + words[i] = "their"; + } + else { + words[i] = possessive(target_gen); + } + } + break; + + case "$target_reflexive": + if( subject == targets ) { + words[i] = "yourself"; + } + else { + if( !target_gen ) { + words[i] = targets; + } + else if( target_gen == "plural" ) { + words[i] = "themselves"; + } + else { + words[i] = reflexive(target_gen); + } + } + break; + + default: + if( special[words[i]] ) { + words[i] = special[words[i]]; + } + } + words[i] = words[i] + punctuation; + } + return capitalize(implode(words, " ")); + + case POV_TARGET: + for(i=0; i 'z' ) { + punctuation = words[i][<1..<1] + punctuation; + words[i] = words[i][0..<2]; + } + else { + break; + } + } + switch(words[i]) { + case "$agent_verb": + words[i] = pluralize(verb[verb_count++]); + break; + + case "$agent_name": + words[i] = subject; + break; + + case "$agent_nominative": + if( !subject_gen ) { + words[i] = subject; + } + else { + words[i] = nominative(subject_gen); + } + break; + + case "$agent_objective": + if( !subject_gen ) { + words[i] = subject; + } + else { + words[i] = objective(subject_gen); + } + break; + + case "$agent_possessive_noun": + words[i] = possessive_noun(subject); + break; + + case "$agent_possessive": + if( !subject_gen ) { + words[i] = possessive_noun(subject); + } + else { + words[i] = possessive(subject_gen); + } + break; + + case "$agent_reflexive": + if( !subject_gen ) { + words[i] = subject; + } + else { + words[i] = reflexive(subject_gen); + } + break; + + case "$target_verb": + words[i] = verb[verb_count++]; + break; + + case "$target_name": case "$target_nominative": + case "$target_objective": + words[i] = "you"; + break; + + case "$target_possessive_noun": + words[i] = "your"; + break; + + case "$target_possessive": + words[i] = "your"; + break; + + case "$target_reflexive": + words[i] = "yourself"; + break; + + default: + if( special[words[i]] ) { + words[i] = special[words[i]]; + } + } + words[i] = words[i] + punctuation; + } + return capitalize(implode(words, " ")); + + case POV_OBSERVER: + for(i=0; i 'z' ) { + punctuation = words[i][<1..<1] + punctuation; + words[i] = words[i][0..<2]; + } + else { + break; + } + } + switch(words[i]) { + case "$agent_verb": + //Following fixed line provided by Aransus @ Pyloros + words[i] = ""+pluralize(verb[verb_count++]); + break; + + case "$agent_name": + words[i] = subject; + break; + + case "$agent_nominative": + if( !subject_gen ) { + words[i] = subject; + } + else { + words[i] = nominative(subject_gen); + } + break; + + case "$agent_objective": + if( !subject_gen ) { + words[i] = subject; + } + else { + words[i] = objective(subject_gen); + } + break; + + case "$agent_possessive_noun": + words[i] = possessive_noun(subject); + break; + + case "$agent_possessive": + if( !subject_gen ) { + words[i] = possessive_noun(subject); + } + else { + words[i] = possessive(subject_gen); + } + break; + + case "$agent_reflexive": + if( !subject_gen ) { + words[i] = subject; + } + else { + words[i] = reflexive(subject_gen); + } + break; + + case "$target_verb": + if( target_gen != "plural" ) { + words[i] = pluralize(verb[verb_count]); + } + else { + words[i] = verb[verb_count]; + } + verb_count++; + break; + + case "$target_name": + words[i] = targets; + break; + + case "$target_nominative": + if( !target_gen ) { + words[i] = targets; + } + else if( target_gen == "plural" ) { + words[i] = "they"; + } + else { + words[i] = nominative(target_gen); + } + break; + + case "$target_objective": + if( !target_gen ) { + words[i] = targets; + } + else if( target_gen == "plural" ) { + words[i] = "them"; + } + else { + words[i] = objective(target_gen); + } + break; + + case "$target_possessive_noun": + if( !target_gen ) { + words[i] = possessive_noun(targets); + } + else if( target_gen == "plural" ) { + words[i] = "their"; + } + else { + words[i] = possessive_noun(targets); + } + break; + + case "$target_possessive": + if( !target_gen ) { + words[i] = possessive_noun(targets); + } + else if( target_gen == "plural" ) { + words[i] = "their"; + } + else { + words[i] = possessive(target_gen); + } + break; + + case "$target_reflexive": + if( !target_gen ) { + words[i] = targets; + } + else if( target_gen == "plural" ) { + words[i] = "themselves"; + } + else { + words[i] = reflexive(target_gen); + } + break; + + default: + if( special[words[i]] ) { + words[i] = special[words[i]]; + } + } + words[i] = words[i] + punctuation; + } + return capitalize(implode(words, " ")); + + default: + error("Unknown POV type: " + pov + "\n"); + } +} + +void send_messages(mixed verb, string message, object subject, mixed targets, + mixed observers, mapping special) { + string sname = subject->GetName(); + string sgen = (subject->GetGender() || "neuter"); + string tname, tgen; + + if( arrayp(targets) ) { + if( !sizeof(targets) ) { + tname = tgen = 0; + } + else if( sizeof(targets) == 1 ) { + if( living(targets[0]) ) { + tname = targets[0]->GetName(); + tgen = (targets[0]->GetGender() || "neuter"); + } + else { + tname = targets[0]->GetShort(); + tgen = "neuter"; + } + targets = targets[0]; + } + else { + if( member_array(subject, targets) != -1 ) { + targets -= ({ subject }); + if( sizeof(targets) == 1 ) { + if( living(targets[0]) ) { + tname = targets[0]->GetName(); + tgen = (targets[0]->GetGender() || "neuter"); + } + else { + tname = targets[0]->GetShort(); + tgen = "neuter"; + } + targets = targets[0]; + } + else { + tname = item_list(targets); + tgen = "plural"; + } + } + } + } + else if( objectp(targets) ) { + if( living(targets) ) { + tname = targets->GetName(); + tgen = (targets->GetGender() || "neuter"); + } + else { + tname = targets->GetShort(); + tgen = "neuter"; + } + } + else { + tname = 0; + tgen = 0; + } + if( stringp(verb) ) { + verb = ({ verb }); + } + if( subject ) { + string str = create_message(POV_SUBJECT, verb, message, sname, sgen, + tname, tgen, special); + + subject->eventPrint(str); + } + if( targets && targets != subject ) { + string str = create_message(POV_TARGET, verb, message, sname, sgen, + tname, tgen, special); + + targets->eventPrint(str); + } + if( observers ) { + string str = create_message(POV_OBSERVER, verb, message, sname, sgen, + tname, tgen, special); + object array exclude = ({}); + + if( subject ) { + exclude = ({ subject }); + } + if( objectp(targets) ) { + exclude = ({ exclude..., targets }); + } + else if( arrayp(targets) ) { + exclude = ({ exclude..., targets... }); + } + observers->eventPrint(str, exclude); + } +} diff --git a/lib/secure/sefun/minimap.c b/lib/secure/sefun/minimap.c new file mode 100644 index 0000000..9bea6e8 --- /dev/null +++ b/lib/secure/sefun/minimap.c @@ -0,0 +1,52 @@ +string query_door(object what, string direction){ + string door = what->GetDoor(direction); + object puerta; + if(!door) return "#"; + else { + puerta = load_object(door); + if(!puerta) return "#"; + if(puerta->GetClosed()) return "O"; + return "#"; + } + return " "; +} + +varargs string simple_map(mixed arg){ + string *exits; + string *extra_desc = ({}); + string ret = ""; + string line0 = "---------\n"; + string line6 = "---------\n"; + string line1 = "| |\n"; + string line2, line3, line4, line5; + line2 = line3 = line4 = line5 = line1; + if(!arg && !this_player()) return ""; + if(!arg) arg = environment(this_player()); + if(stringp(arg)) arg = load_object(arg); + if(living(arg) || arg->GetMount()) arg = environment(arg); + if(!arg) return ""; + exits = arg->GetExits(); + if(!exits || !sizeof(exits)) return ""; + line3[4..4] = "*"; + + foreach(string element in exits){ + switch(element){ + case "north" : line1[4..4] = query_door(arg, element); line2[4..4] = "|";break; + case "south" : line5[4..4] = query_door(arg, element); line4[4..4] = "|";break; + case "east" : line3[7..7] = query_door(arg, element); line3[5..5] = "-";line3[6..6] = "-";break; + case "west" : line3[1..1] = query_door(arg, element); line3[2..2] = "-";line3[3..3] = "-";break; + case "northeast" : line1[7..7] = query_door(arg, element); line2[6..6] = "/";break; + case "northwest" : line1[1..1] = query_door(arg, element); line2[2..2] = "\\";break; + case "southeast" : line5[7..7] = query_door(arg, element); line4[6..6] = "\\";break; + case "southwest" : line5[1..1] = query_door(arg, element); line4[2..2] = "/";break; + //case "up" : extra_desc += ({ "up" });break; + //case "down" : extra_desc += ({ "down" });break; + default : extra_desc += ({ element });break; + } + } + if(sizeof(extra_desc)){ + line3 = replace_string(line3,"\n"," Also available: "+item_list(extra_desc)+".\n"); + } + ret = line0 + line1 + line2 + line3 + line4 + line5 +line6; + return ret; +} diff --git a/lib/secure/sefun/morality.c b/lib/secure/sefun/morality.c new file mode 100644 index 0000000..435fc67 --- /dev/null +++ b/lib/secure/sefun/morality.c @@ -0,0 +1,41 @@ +/* /secure/sefun/morality.c + * from the Dead Souls Mud Library + * handles moral actions + * created by Descartes of Borg 951016 + */ + +int moral_act(object agent, object target, int amount) { + int am, tm; + + am = agent->GetMorality(); + if( target ) { + tm = target->GetMorality(); + } + else { + tm = 0; + } + if( am < 200 && am > -200 ) { + if( amount >= 200 ) { + if( tm >= 200 ) amount = amount + tm; + else if( tm <= -200 ) amount = 0; + } + else if( amount <= -200 ) { + if( tm >= 200 ) amount *= tm; + if( tm <= -200 ) amount = 0; + } + } + else if( am >= 200 ) { + if( amount >= 200 ) { + if( tm >= 200 ) amount *=tm; + else if( tm <= -200 ) amount = 0; + } + else if( amount <= -200 && tm >=200 ) amount *= tm; + } + else if( amount > 1000 ) amount = 75 + random(25); + else if( amount > 100 ) amount = amount /10; + else if( amount > -1 ) amount = 1 + amount/10; + else if( amount > -100 ) amount = -1 + amount/10; + else if( amount > -1000 ) amount = amount/10; + else amount = -(75 + random(25)); + return agent->eventMoralAct(amount); +} diff --git a/lib/secure/sefun/mud_info.c b/lib/secure/sefun/mud_info.c new file mode 100644 index 0000000..858a686 --- /dev/null +++ b/lib/secure/sefun/mud_info.c @@ -0,0 +1,78 @@ +// /adm/simul_efun/mud_info.c +// from the Dead Souls Mudlib +// gives information simul_efuns about the mud +// created by Descartes of Borg + +#include + +string mud_name(){ + string ret; + if(uptime() < 60) return MUD_NAME; + if(!(ret = MASTER_D->GetMudName())) return MUD_NAME; + return ret; +} + +varargs string imc2_mud_name(string name){ + string mudname; + + if(name) mudname = name; + else mudname = mud_name(); + + return replace_string(mudname," ","_"); +} + +string admin_email() { return ADMIN_EMAIL; } + +#ifdef MUDOS_VERSION +string version() { return MUDOS_VERSION; } +#endif // MUDOS_VERSION + +#ifdef __VERSION__ +string version() { return __VERSION__; } +#endif // __VERSION__ + +#ifdef MUDOS_ARCH +string architecture() { return MUDOS_ARCH; } +#endif // MUDOS_ARCH + +#ifdef __ARCH__ +string architecture() { return __ARCH__; } +#endif // __ARCH__ + +string mudlib() { return "Dead Souls"; } + +string mudlib_version() { return "3.9"; } + +int query_host_port() { return __PORT__; } + +string query_os_type(){ + string config_file, s1, s2, s3; + if(function_exists("architecture",load_object("/secure/sefun/sefun"))){ + string arch = lower_case(architecture()); + if(grepp(arch,"windows") || grepp(arch,"cygwin")) return "windows"; + else return "unix"; + } + if(!file_exists("/secure/cfg/mudos.cfg")) return "unknown"; + config_file = read_matching_line("/secure/cfg/mudos.cfg","mudlib directory :"); + if(!config_file) return ""; + if(sscanf(config_file,"%s:%s:%s",s1,s2,s3) == 3){ + return "windows"; + } + else return "unix"; +} + +int query_windows(){ + string arch = lower_case(architecture()); +#ifdef __WIN32__ + return 1; +#else + if(grepp(arch,"windows") || grepp(arch,"cygwin")) return 1; +#endif + return 0; +} + +string query_intermud_ip(){ + if(INTERMUD_D->GetMudList()[mud_name()]) + return INTERMUD_D->GetMudList()[mud_name()][1]; + else return ""; +} diff --git a/lib/secure/sefun/names.c b/lib/secure/sefun/names.c new file mode 100644 index 0000000..2df63a6 --- /dev/null +++ b/lib/secure/sefun/names.c @@ -0,0 +1,102 @@ +#include +#include + +#ifndef __FLUFFOS__ +string base_name(mixed val) { + string name, base; + int borg; + if(!val) return ""; + if(objectp(val)) name = file_name(val); + else if(val == "") return ""; + else if(stringp(val) && sizeof(val)) name = val; + else name = file_name(val); + if(sscanf(name, "%s#%d", base, borg) ==2) return base; + else return name; +} +#endif + +string convert_name(string str) { + string a, b, ret; + if(!str || str == "") return ""; + if(!grepp(str,"@")){ + str = replace_string(str, " ", ""); + str = replace_string(str, "'", ""); + return lower_case(replace_string(str, "-", "")); + } + if(sscanf(str, "%s@%s", a, b) == 2 && + ret = INTERMUD_D->GetMudName(b)) return a+"@"+ret; + else return str; +} + +string *query_names(object whom) { + string *name = ({}); + string *names = ({}); + if(!whom || !objectp(whom)) return name; + if(inherits(LIB_DOOR,whom) || base_name(whom) == LIB_DOOR) + { + name = ({ "door" }); + } + else { + if(whom->GetName()) name += ({ lower_case(whom->GetName()) }); + if(whom->GetKeyName()) name += ({ lower_case(whom->GetKeyName()) }); + if(sizeof(whom->GetId())) { + if(arrayp(whom->GetId()))name += whom->GetId(); + else name += ({ whom->GetId() }); + } + } + if(sizeof(name)){ + foreach(mixed subst in name){ + if(!subst) continue; + if(arrayp(subst)) names += subst; + else names += ({ lower_case(subst) }); + } + } + return names; +} + +int answers_to(string name, object what){ + string *adjs, *names, *arg_arr, *tmp_arr; + int i, j, arrsize; + if(!name || !what) return 0; + if(!stringp(name) || !objectp(what)) return 0; + adjs = filter((what->GetAdjectives() || ({})), (: lower_case(($1||"")) :)); + names = filter(query_names(what), (: lower_case($1) :)); + name = lower_case(name); + if(member_array(name, names) != -1) return 1; + if(!sizeof(adjs)) return 0; + arg_arr = explode(name," "); + arrsize = sizeof(arg_arr); + if(arrsize == 1) return 0; + tmp_arr = arg_arr; + for(i=0; i < arrsize-1; i++){ + string *elision = ({}); + for(j=i; j < arrsize-1; j++){ + string current_adj = implode(arg_arr[i..j]," "); + if(member_array(current_adj,adjs) != -1){ + elision = arg_arr[i..j]; + break; + } + } + if(!sizeof(elision)){ + return 0; + } + tmp_arr -= elision; + if(!sizeof(tmp_arr)) return 0; + if(member_array(implode(tmp_arr," "), names) != -1) return 1; + } + return 0; +} + +varargs string query_unique_name(mixed ob, int cloned){ + string fn; + if(objectp(ob)){ + if(!clonep(ob)) cloned = 0; + if(cloned) fn = file_name(ob); + else fn = base_name(ob); + } + else if(stringp(ob)) fn = ob; + else return 0; + fn = replace_string(fn, "/", "0^0"); + fn = replace_string(fn, "#", "9^9"); + return fn; +} diff --git a/lib/secure/sefun/native_version.c b/lib/secure/sefun/native_version.c new file mode 100644 index 0000000..8828c54 --- /dev/null +++ b/lib/secure/sefun/native_version.c @@ -0,0 +1 @@ +string native_version() { return "3.9"; } diff --git a/lib/secure/sefun/numbers.c b/lib/secure/sefun/numbers.c new file mode 100644 index 0000000..2a77c76 --- /dev/null +++ b/lib/secure/sefun/numbers.c @@ -0,0 +1,67 @@ +string *bitses = ({}); + +int bool_reverse(mixed arg){ + if(!arg || (intp(arg) && arg < 1)) return 1; + else return 0; +} + +int atoi(string str){ + int integer; + if(str) sscanf(str, "%d", integer); + return integer; +} + +string itoa(mixed i){ + return ""+i; +} + +string comma(mixed x){ + string ret = "", pre = "", post = ""; + int count = 0, i; + if(floatp(x)) sscanf(x+"","%s.%s",pre,post); + else if(intp(x)) pre = itoa(x); + else return 0; + i = sizeof(pre); + while(i){ + count++; + ret = pre[10 ) x = 4; + else x = x%10; + switch(x) { + case 1: return "st"; break; + case 2: return "nd"; break; + case 3: return "rd"; break; + default: return "th"; break; + } +} diff --git a/lib/secure/sefun/parse_objects.c b/lib/secure/sefun/parse_objects.c new file mode 100644 index 0000000..816fe50 --- /dev/null +++ b/lib/secure/sefun/parse_objects.c @@ -0,0 +1,19 @@ +// /adm/simul_efun/parse_objects.c +// from the Dead Souls mudlib +// searches the inventory of an object for a numbered object +// created by Descartes of Borg 25 october 1992 + +object parse_objects(object where, string str) { + int i, skip, which; + string what; + object *inv; + + if(!str) return 0; + if(sscanf(str, "%s %d", what, which) != 2) return 0; + inv = all_inventory(where); + for(i=0, skip = 0; iid(what)) skip ++; + if(skip == which) return inv[i]; + } + return 0; +} diff --git a/lib/secure/sefun/path_file.c b/lib/secure/sefun/path_file.c new file mode 100644 index 0000000..bf59cbe --- /dev/null +++ b/lib/secure/sefun/path_file.c @@ -0,0 +1,30 @@ +/* +// File: path_file.c +// From the wonderful people at Portals. + */ + +mixed *path_file(mixed full_path) { + mixed *tmp, *dirs; + int i; + + if(pointerp(full_path)) { + dirs = allocate(2); + dirs[0] = ({ }); + dirs[1] = ({ }); + for(i = 0; i < sizeof(full_path); i++) { + tmp = path_file(full_path[i]); + dirs[0] = dirs[0] + ({ tmp[0] }); + dirs[1] = dirs[1] + ({ tmp[1] }); + } + return dirs; + } + + if(full_path == "/") + return ({ "/","" }); + + if(file_size(full_path) == -2) + return ({ full_path, "" }); + dirs = explode(full_path,"/"); + tmp = dirs[0 .. sizeof(dirs) - 2]; + return ({ "/" + implode(tmp,"/"), dirs[sizeof(dirs) - 1] }); +} diff --git a/lib/secure/sefun/percent.c b/lib/secure/sefun/percent.c new file mode 100644 index 0000000..536e4d4 --- /dev/null +++ b/lib/secure/sefun/percent.c @@ -0,0 +1,25 @@ +// /adm/simul_efun/percent.c +// from the Dead Souls mudlib +// returns the percent one value is of another +// created by Descartes of Borg 15 april 1993 + +float percent(mixed numerator, mixed denominator) { + float a, b; + + if(!floatp(numerator) && !intp(numerator)) return 0.0; + else a = (floatp(numerator) ? numerator : to_float(numerator)); + if(!floatp(denominator) && !intp(denominator)) return 0.0; + else b = (floatp(denominator) ? denominator : to_float(denominator)); + if((b < 1 && b > -1) || !b || b == 0 || b == 0.0 ) return 0.0; + return ((a/b)*100); +} + +float percent_of(mixed percent, mixed base){ + float a, b; + + a = (floatp(percent) ? percent : to_float(percent)); + b = (floatp(base) ? base : to_float(base)); + if((b < 1 && b > -1) || !b || b == 0 || b == 0.0 ) return 0.0; + return (a * b) / 100.0; +} + diff --git a/lib/secure/sefun/persist.c b/lib/secure/sefun/persist.c new file mode 100644 index 0000000..f4f188a --- /dev/null +++ b/lib/secure/sefun/persist.c @@ -0,0 +1,13 @@ +/* /secure/sefun/persist.c + * from the Dead Souls LPC Library + * handles efuns for persistance support + * created by Beek@Dead Souls 950529 + */ + +#include + +object unique(string fn, int rare) { + return (object)UNIQUE_D->GetUniqueCopy(fn, rare); +} + +int query_reset_number() { return master()->GetResetNumber(); } diff --git a/lib/secure/sefun/pointers.c b/lib/secure/sefun/pointers.c new file mode 100644 index 0000000..46dbc5d --- /dev/null +++ b/lib/secure/sefun/pointers.c @@ -0,0 +1,134 @@ +/* /adm/sefun/pointers.c + * from Dead Souls + * sefuns for testing things + * created by Descartes of Borg 940213 + */ + +#include +#include "sefun.h" +#include +#include + +int ambassadorp(object ob) { + if(!ob) ob = previous_object(); + return (userp(ob) && member_group(ob, "AMBASSADOR")); +} + +int elderp(object ob) { + if(!ob) ob = previous_object(); + return (userp(ob) && member_group(ob, "ELDER")); +} + +int testp(object ob) { + if(!ob) ob = previous_object(); + return (userp(ob) && member_group(ob, "TEST")); +} + +int archp(object ob) { + if(!ob) ob = previous_object(); + if(!creatorp(ob)) return 0; + return (member_group(ob, "ASSIST") || member_group(ob, "SECURE")); +} + +int adminp(object ob){ + return archp(ob); +} + +int imud_privp(mixed guy) { + if(member_group(guy, "INTERMUD")) return 1; + else return 0; +} + +int telnet_privp(mixed guy) { + if(member_group(guy, "TELNET")) return 1; + else return 0; +} + +int securep(mixed guy) { + mixed dude = guy; + if(!guy) guy = previous_object(); + if(!stringp(guy)) guy = guy->GetKeyName(); + if(!guy || guy == "") guy = base_name(dude); + if(member_group(guy, "SECURE")) return 1; + else return 0; +} + +int assistp(mixed guy) { + mixed dude = guy; + if(!guy) guy = previous_object(); + if(!stringp(guy)) guy = guy->GetKeyName(); + if(!guy || guy == "") guy = base_name(dude); + if(member_group(guy, "ASSIST")) return 1; + else return 0; +} + +varargs int creatorp(object ob) { + if(!ob) ob = previous_object(); + if(!ob || !userp(ob)) return 0; + return !(strsrch(file_name(ob), DIR_CRES)); +} + +varargs int wizardp(object ob){ + return creatorp(ob); +} + +int builderp(object ob) { + if(!ob) ob = previous_object(); + if(creatorp(ob)) return 1; + return (userp(ob) && member_group(ob, "BUILDER")); +} + +int snooperp(mixed guy) { + mixed dude = guy; + if(!guy) guy = previous_object(); + if(!stringp(guy)) guy = guy->GetKeyName(); + if(!guy || guy == "") guy = base_name(dude); + if(member_group(guy, "SNOOPER")) return 1; + else return 0; +} + +int hiddenp(object ob) { + if(!objectp(ob)) error("Bad argument 1 to hiddenp().\n"); + return !find_object(file_name(ob)); +} + +int high_mortalp(object ob) { + if(!ob) ob = previous_object(); + return (!creatorp(ob) && (ob->GetLevel() > 24)); +} + +int councilp(object ob) { + int val; + + if(!ob) ob = previous_object(); + if( ! catch( val = VOTING_D->IsCouncilMember(ob) ) ) + return (!creatorp(ob) && ( val )); + return 0; +} + +int avatarp(object ob) { + if( !ob ) ob = previous_object(); + return (!creatorp(ob) && ob->GetLevel() > 49); +} + +int leaderp(object ob) { + if(!ob) ob = previous_object(); + if(!userp(ob) || creatorp(ob)) return 0; + return (ob->GetPosition() != "citizen"); +} + +varargs int playerp(object ob) { + if( !ob ) ob = previous_object(); + return (userp(ob) && !creatorp(ob)); +} + +varargs int newbiep(object ob) { + if(!MAX_NEWBIE_LEVEL) return 0; + if( !ob ) ob = previous_object(); + return (!creatorp(ob) && (ob->GetLevel() <= MAX_NEWBIE_LEVEL)); +} + +varargs int estatep(object ob){ + if( !ob ) ob = previous_object(); + return (!(strsrch(base_name(ob), ESTATES_DIRS))); +} diff --git a/lib/secure/sefun/query_invis.c b/lib/secure/sefun/query_invis.c new file mode 100644 index 0000000..be4879e --- /dev/null +++ b/lib/secure/sefun/query_invis.c @@ -0,0 +1,19 @@ +varargs int query_invis(object lookee, object looker) { + if(!lookee && !looker) lookee = this_object(); + if(!looker) looker = previous_object(); + if(looker == lookee) looker = previous_object(1); + if(!looker || !living(looker)) return 2; + if(!living(lookee) && lookee->GetInvis()) return 1; + if(!lookee->GetInvis()) return 0; + if(creatorp(lookee) && lookee->GetInvis() && !creatorp(looker)) return 1; + if(archp(lookee) && lookee->GetInvis() && !archp(looker)) return 1; + if(living(lookee)){ + int lookeelevel, lookerlevel; + lookeelevel = lookee->GetLevel(); + lookerlevel = looker->GetLevel(); + if(lookeelevel && lookerlevel && lookeelevel >= lookerlevel){ + return 1; + } + } + return 0; +} diff --git a/lib/secure/sefun/query_time_of_day.c b/lib/secure/sefun/query_time_of_day.c new file mode 100644 index 0000000..4c4aecc --- /dev/null +++ b/lib/secure/sefun/query_time_of_day.c @@ -0,0 +1,10 @@ +// /secure/sefun/query_time_of_day.c +// from the Dead Souls mudlib +// returns the time of day name. +// created by Rush 18 december 1995 + +#include + +string query_time_of_day() { return SEASONS_D->GetTimeOfDay(); } + + diff --git a/lib/secure/sefun/reaper.c b/lib/secure/sefun/reaper.c new file mode 100644 index 0000000..8f0e295 --- /dev/null +++ b/lib/secure/sefun/reaper.c @@ -0,0 +1,70 @@ +#include +#include + +private string *glist; +private object thingy; + +string *ExemptArray = ({ LIB_CONNECT, OBJ_SNOOPER, LIB_DOOR, LIB_ROOM, LIB_SERVER, LIB_FTP_DATA_CONN, LIB_SOCKET, SOCKET_HTTP, SEFUN }); + +void reap_dummies(){ + // + // destroys any dummy objects that do not + // have an environment + // + object *dummies = objects((: $1 && base_name($1) == LIB_DUMMY :))[0..30000]; + dummies += objects((: inherits(LIB_DUMMY, $1) :))[0..30000]; + + foreach(object dummy in dummies){ + if(!environment(dummy)) catch( dummy->eventDestruct() ); + } +} + +varargs void reap_other(string s1){ + // + // Destroys any non-special objects and clones that + // do not have an environment, as well as temporary objects. + // + string s2; + int fail; + object *garbage; + object *others; + + if(!this_object()) return; + + garbage = ({}); + others = objects((: ($1 && clonep($1) && !userp($1) && + !inherits(LIB_ROOM, $1) && !environment($1) && + !inherits(LIB_SHADOW, $1) && + member_array(base_name($1), ExemptArray) == -1) || + !strsrch(base_name($1), "/open/") :))[0..6300]; +#ifdef __FLUFFOS__ + garbage = get_garbage()[0..63000]; +#endif + + if(sizeof(others) > 62000 || sizeof(garbage) > 62000){ + call_out("reap_other",5); + } + + foreach(thingy in others){ + int err; + if(thingy) err = catch( unguarded( (: destruct(thingy) :) ) ); + if(thingy) fail = 1; + } + + foreach(thingy in garbage){ + int err; + if(thingy) err = catch( unguarded( (: destruct(thingy) :) ) ); + if(thingy) fail = 1; + } +} + +mixed reap_list(){ + // + // returns a list of cloned objects without an environment + // + string s1,s2; + object *clones = objects((: $1 && clonep($1) && !environment($1) :))[0..6300]; + glist = ({}); + filter(clones, (: glist += ({ file_name($1) }) :)); + return glist; +} diff --git a/lib/secure/sefun/reload.c b/lib/secure/sefun/reload.c new file mode 100644 index 0000000..2badaaa --- /dev/null +++ b/lib/secure/sefun/reload.c @@ -0,0 +1,101 @@ +#include +#include +#include +#include ROOMS_H +#include +mixed mx; +mixed next; +object *dudes; +string filename, args; + +varargs mixed reload(mixed ob, int recursive, int quiet){ + mapping StringFellows = ([]); + int stringed; + object env; + mx = 0; + + if(RELOAD_D->GetWarmBootInProgress()){ + reset_eval_cost(); + } + + if(!ob) return 0; + if(objectp(ob) && inherits(LIB_DAEMON,ob) && !ob->GetDoor()){ + string obname = base_name(ob)+".c"; + ob->eventDestruct(); + if(ob) destruct(ob); + return load_object(obname); + } + if(objectp(ob) && environment(ob)) env = environment(ob); + if(stringp(ob)) { + stringed = 1; + filename = ob; + if(!grepp(filename,"#") && last(filename,2) != ".c") filename += ".c"; + ob = find_object(filename); + if(!ob) ob = load_object(filename); + } + + if(!ob || !objectp(ob)){ + if(!quiet) write("No such object."); + return 0; + } + + if(ob->GetDoor() && sizeof(ob->GetDoor())) { + ob = load_object(ob->GetDoor()); + } + + if(!file_exists(base_name(ob))) filename = base_name(ob)+".c"; + else filename = base_name(ob); + if(!file_exists(filename)){ + } + if(recursive) args = "-a -r "; + else args = "-a "; + if(!grepp(unguarded( (: read_file(filename) :) ),"void init()" || !grepp(unguarded( (: read_file(filename) :) ),"::init()"))) { + if(clonep(ob) && !inherits(LIB_ROOM,ob)){ + if(!strsrch(filename,"/lib/") || ob->isDummy() || inherits(LIB_DAEMON,ob)) true(); + else if(!quiet) + write("This object lacks a working init function. " + "Please run initfix on it as soon as possible."); + } + } + if(inherits(LIB_ROOM,ob)){ + dudes = get_livings(ob,1); + if(dudes) { + foreach(object fellow in dudes){ + string ubi = fellow->GetProperty("LastLocation"); + if(ubi) StringFellows[fellow->GetKeyName()] = ubi; + } + } + unguarded( (: mx = catch(load_object(CMD_UPDATE)->cmd(args + filename)) :) ); + if(mx && !quiet) { + write("There appears to be a problem updating one or more files."); + write("Reload failed."); + } + else { + if(dudes) { + dudes->eventMove(filename); + foreach(object fellow in dudes){ + if(sizeof(StringFellows[fellow->GetKeyName()])){ + fellow->SetProperty("LastLocation",StringFellows[fellow->GetKeyName()]); + } + } + } + if(!quiet) write("Reload complete."); + } + StringFellows = ([]); + return 1; + } + mx = unguarded( (: load_object(CMD_UPDATE)->cmd(args + " "+ filename) :) ); + if((!mx || !intp(mx) || mx == 0) && !quiet) { + write("There appears to be a problem updating one or more files."); + write("Reload failed."); + return 0; + } + + if(ob && !inherits(LIB_DOOR, ob) && !stringed && env) { + unguarded( (: next = clone_object(filename) :) ); + ob->eventMove(ROOM_FURNACE); + if(next && objectp(next) && env) next->eventMove(env); + } + if(!quiet && this_player()) write("Done."); + return 1; +} diff --git a/lib/secure/sefun/rooms.c b/lib/secure/sefun/rooms.c new file mode 100644 index 0000000..c199bb9 --- /dev/null +++ b/lib/secure/sefun/rooms.c @@ -0,0 +1,156 @@ +#include +#include +string namen, ret; + +int reload_room(object ob){ + string name; + object *stuff; + name=base_name(ob); + stuff = deep_inventory(ob); + foreach(object item in stuff){ + object *int_inv = ({}); + int_inv = filter(containers(item), (: interactive($1) :)); + if(!sizeof(int_inv) && !interactive(item)) item->eventDestruct(); + } + ob->eventDestruct(); + load_object(name); + return 1; +} + +int query_night_light(object ob){ + string file; + string filename = base_name(ob)+".c"; + namen = filename; + if(file_size(filename) < 1) return -1; + file = unguarded( (: read_file(namen) :) ); + if(strsrch(file,"SetNightLight") != -1) return 1; + else return 0; +} + +int query_day_light(object ob){ + string filename = base_name(ob)+".c"; + if(file_size(filename) < 1) return -1; + if(strsrch(read_file(filename),"SetDayLight") != -1) return 1; + else return 0; +} + +int query_ambient_light(object ob){ + string filename = base_name(ob)+".c"; + if(file_size(filename) < 1) return -1; + if(strsrch(read_file(filename),"SetAmbientLight") != -1) return 1; + else return 0; +} + +varargs string opposite_dir(string str, int article){ + int classic; + switch(str){ + case "north" : ret = "south";classic = 1;break; + case "south" : ret = "north";classic = 1;break; + case "east" : ret = "west";classic = 1;break; + case "west" : ret = "east";classic = 1;break; + case "northeast" : ret = "southwest";classic = 1;break; + case "northwest" : ret = "southeast";classic = 1;break; + case "southeast" : ret = "northwest";classic = 1;break; + case "southwest" : ret = "northeast";classic = 1;break; + case "up" : ret = (article ? "below" : "down");break; + case "down" : ret = (article ? "above" : "up");break; + + case "fore" : ret = "aft";break; + case "aft" : ret = "fore";break; + case "port" : ret = "starboard";break; + case "starboard" : ret = "port";break; + + case "+y" : ret = "-y";break; + case "-y" : ret = "+y";break; + case "+x" : ret = "-x";break; + case "-x" : ret = "+x";break; + case "+z" : ret = "-z";break; + case "-z" : ret = "+z";break; + + case "+x+y" : ret = "-x-y";break; + case "-x-y" : ret = "+x+y";break; + case "+x-y" : ret = "-x+y";break; + case "-x+y" : ret = "+x-y";break; + + case "+x+z" : ret = "-x-z";break; + case "-x-z" : ret = "+x+z";break; + case "+x-z" : ret = "-x+z";break; + case "-x+z" : ret = "+x-z";break; + + case "+y+z" : ret = "-y-z";break; + case "-y-z" : ret = "+y+z";break; + case "+y-z" : ret = "-y+z";break; + case "-y+z" : ret = "+y-z";break; + + + case "+x+y-z" : ret = "-x-y+z";break; + case "+x+y+z" : ret = "-x-y-z";break; + case "-x-y-z" : ret = "+x+y+z";break; + case "-x-y+z" : ret = "+x+y-z";break; + case "+x-y-z" : ret = "-x+y+z";break; + case "+x-y+z" : ret = "-x+y-z";break; + case "-x+y-z" : ret = "+x-y+z";break; + case "-x+y+z" : ret = "+x-y-z";break; + + default : ret = "";break; + } + if(article){ + if(classic) return "the "+ret; + } + return ret; +} + +varargs mixed coordinates(object ob, string type){ + mixed ret; + object env; + if(!ob) return; + if(!(ret = ROOMS_D->GetCoordinates(ob))){ + if(env = room_environment(ob)){ + ret = ROOMS_D->GetCoordinates(env); + } + } + return ret; +} + +mixed calculate_coordinates(string str, int x, int y, int z, string type){ + mixed ret, str_ret = ({}); + switch(str){ + case "north" : ret = ({ x, y+1, z });break; + case "south" : ret = ({ x, y-1, z });break; + case "east" : ret = ({ x+1, y, z });break; + case "west" : ret = ({ x-1, y, z });break; + case "northeast" : ret = ({ x+1, y+1, z });break; + case "northwest" : ret = ({ x-1, y+1, z });break; + case "southeast" : ret = ({ x+1, y-1, z });break; + case "southwest" : ret = ({ x-1, y-1, z });break; + case "up" : ret = ({ x, y, z+1 });break; + case "down" : ret = ({ x, y, z-1 });break; + default: ret = ({ x, y, z }); break; + } + if(type != "string") return ret; + foreach(int element in ret){ + str_ret += ({ itoa(element) }); + } + return implode(str_ret, ","); +} + +object room_environment(object ob){ + foreach(object element in containers(ob)){ + if(inherits(LIB_ROOM, element)){ + return element; + } + } + return 0; +} + +varargs int bearing(int x1, int y1, int x2, int y2, int reverse){ + float inter = (reverse ? (y1 - y2) : (y2 - y1)); + float mark = (reverse ? (x1 - x2) : (x2 - x1)); + float range = sqrt(pow(mark, 2) + pow(inter, 2)); + int corr, ret; + if(x1 == x2 && y1 == y2) return -1; + corr = ((mark >= 0) ? 0 : 180); + ret = (acos(to_float(corr ? -inter : inter)/range) * (180/3.141592)) + corr; + return ret; +} + diff --git a/lib/secure/sefun/security.c b/lib/secure/sefun/security.c new file mode 100644 index 0000000..7db7b62 --- /dev/null +++ b/lib/secure/sefun/security.c @@ -0,0 +1,104 @@ +/* /secure/sefun/security.c + * from Dead Souls 3.3 + * returns the file privs for any file or directory + * created by Descartes of Borg 940903 + */ + +#include + +string file_privs(string file) { + string *path; + + if(!sizeof(path = explode(file, "/"))) return 0; + switch(path[0]) { + case "adm": return PRIV_SECURE; + case "cmds": return PRIV_CMDS; + case "daemon": return PRIV_MUDLIB; + case "estates": return PRIV_GENERAL; + case "lib": return PRIV_GENERAL; + case "obj": return PRIV_GENERAL; + case "secure": return PRIV_SECURE; + case "shadows": return PRIV_GENERAL; + case "verbs": return PRIV_CMDS; + case "www": return PRIV_GENERAL; + case "realms": + if(sizeof(path) > 1) return lower_case(path[1]); + else return 0; + case "domains": + if(sizeof(path) > 1) return capitalize(lower_case(path[1])); + else return 0; + default: return 0; + } +} + +int member_group(mixed who, string grp) { + string *ppl; + + if(objectp(who)) who = who->GetKeyName(); + if(!(ppl = master()->query_group(grp))) return 0; + return (member_array(who, ppl) != -1); +} + +int domain_admin(mixed pretender, string domain){ + mapping DomainsMap = ([]); + string write_perms = read_file("/secure/cfg/write.cfg"); + string *tmp_array = explode(write_perms, "\n"); + string *admin_array = ({}); + if(objectp(pretender)) pretender = pretender->GetKeyName(); + foreach(string line in tmp_array){ + string where, admins; + if(sscanf(line,"(/domains/%s/) %s", where, admins)){ + DomainsMap[where] = admins; + } + } + if(!sizeof(DomainsMap[domain])) return 0; + admin_array = explode(DomainsMap[domain],":"); + if(member_array(lower_case(pretender), admin_array) == -1){ + return 0; + } + else { + return 1; + } +} + +int check_privs(mixed pretender, mixed target){ + int x; + string domain, junk; + string name = ""; + if(stringp(pretender)) pretender = load_object(pretender); + if(objectp(target)) target = base_name(target)+".c"; + if(!stringp(target)) return 0; + if(!pretender) x= 2; + name = pretender->GetKeyName(); + if(pretender->GetForced() ) x= 3; + foreach(object ob in previous_object(-1)){ + if(ob && ob->GetForced() ) x= 4; + } + if(first_string_element(target,"/",1) == "tmp" ) x= 15; + else if(first_string_element(target,"/",1) == "open") x= 16; + else if(first_string_element(target,"/",1) == "realms" && + grepp(target,homedir(pretender)) ) x= 17; + else if(archp(pretender)) x= 18; + else x= 9; + + if(first_string_element(target,"/",1) == "domains"){ + if(sscanf(target,"/domains/%s/%s", domain, junk) == 2){ + if(domain_admin(pretender, domain)) x = 19; + } + } + + if(!strsrch(target, "/estates/"+name[0..0]+"/"+name)) x = 20; + + if(x < 10) return 0; + if(x > 10) return 1; +} + +int check_read(string file){ + string contents; + if(!file || !file_exists(file)) return 0; + contents = read_file(file); + if(!contents || !sizeof(contents)) return 0; + return 1; +} + +mixed unguarded(function f) { return master()->apply_unguarded(f); } diff --git a/lib/secure/sefun/sefun.c b/lib/secure/sefun/sefun.c new file mode 100644 index 0000000..4d57fc7 --- /dev/null +++ b/lib/secure/sefun/sefun.c @@ -0,0 +1,771 @@ +/* /secure/obj/sefun.c + * from Dead Souls + * the mud sefun object + * created by Descartes of Borg 940213 + */ + +#define MAX_DUMMIES 8192 +#define MAX_OBJECT 1024 + +#include +#include +#include +#include +#include +#include +#include +#include +#include "./sefun.h" + +#include "/secure/sefun/absolute_value.c" +#include "/secure/sefun/names.c" +#include "/secure/sefun/communications.c" +#include "/secure/sefun/copy.c" +#include "/secure/sefun/domains.c" +#include "/secure/sefun/economy.c" +#include "/secure/sefun/english.c" +#include "/secure/sefun/events.c" +#include "/secure/sefun/expand_keys.c" +#include "/secure/sefun/files.c" +#include "/secure/sefun/format_page.c" +#include "/secure/sefun/get_object.c" +#include "/secure/sefun/identify.c" +#include "/secure/sefun/interface.c" +#include "/secure/sefun/light.c" +#include "/secure/sefun/load_object.c" +#include "/secure/sefun/log_file.c" +#include "/secure/sefun/messaging.c" +#include "/secure/sefun/morality.c" +#include "/secure/sefun/mud_info.c" +#include "/secure/sefun/ordinal.c" +#include "/secure/sefun/parse_objects.c" +#include "/secure/sefun/path_file.c" +#include "/secure/sefun/percent.c" +#include "/secure/sefun/persist.c" +#include "/secure/sefun/pointers.c" +#include "/secure/sefun/query_time_of_day.c" +#include "/secure/sefun/absolute_path.c" +#include "/secure/sefun/security.c" +#include "/secure/sefun/strings.c" +#include "/secure/sefun/this_agent.c" +#include "/secure/sefun/time.c" +#include "/secure/sefun/to_object.c" +#include "/secure/sefun/translate.c" +#include "/secure/sefun/users.c" +#include "/secure/sefun/visible.c" +#include "/secure/sefun/tail.c" +#include "/secure/sefun/sockets.c" +#include "/secure/sefun/local_time.c" +#include "/secure/sefun/get_livings.c" +#include "/secure/sefun/get_verbs.c" +#include "/secure/sefun/get_cmds.c" +#include "/secure/sefun/get_stack.c" +#include "/secure/sefun/timestamp.c" +#include "/secure/sefun/duplicates.c" +#include "/secure/sefun/reaper.c" +#include "/secure/sefun/custom_path.c" +#include "/secure/sefun/mappings.c" +#include "/secure/sefun/dummy.c" +#include "/secure/sefun/disable.c" +#include "/secure/sefun/make_workroom.c" +#include "/secure/sefun/query_invis.c" +#include "/secure/sefun/rooms.c" +#include "/secure/sefun/generic.c" +#include "/secure/sefun/arrays.c" +#include "/secure/sefun/reload.c" +#include "/secure/sefun/wipe_inv.c" +#include "/secure/sefun/numbers.c" +#include "/secure/sefun/inventory.c" +#include "/secure/sefun/findobs.c" +#include "/secure/sefun/ascii.c" +#include "/secure/sefun/wild_card.c" +#include "/secure/sefun/compare_array.c" +#include "/secure/sefun/legacy.c" +#include "/secure/sefun/atomize.c" +#ifdef LIVEUPGRADE_SERVER +#include "/secure/sefun/native_version.c" +#endif +#include "/secure/sefun/minimap.c" +#include "/secure/sefun/fuzzymatch.c" +#include "/secure/sefun/astar.c" + +object globalob; +string globalstr; +mixed globalmixed, gargs, gfun, gdelay; +int last_regexp = time(); +int regexp_count = 1; +int max_regexp = 200; +private static string *blacklist = ({}); +private static string *jokes = ({"bind","call_out","call_other", + "unguarded","evaluate"}); + +#ifdef __FLUFFOS__ +mixed copy(mixed val){ + return efun::copy(val); +} + +string base_name(mixed val){ + if(!val) return ""; + return efun::base_name(val); +} +#endif /* __FLUFFOS__ */ + +varargs object clone_object(string name, mixed args...){ + int obsnum; + string prev; + + prev = (base_name(previous_object()) || ""); + + if(strsrch(prev,"/realms/") && strsrch(prev,"/open/")){ + return efun::clone_object(name, args...); + } + + if(MEMUSE_SOFT_LIMIT && memory_info() > MEMUSE_SOFT_LIMIT){ + return 0; + } + + if(last(name,2) == ".c") name = truncate(name,2); + obsnum = sizeof( objects( (: base_name($1) == $(name) :) ) ); + //The following means "allow new dummies up to a total + //of MAX_DUMMIES, but otherwise restrict the number of + //clones created of a particular file by a non-privileged + //object to MAX_OBJECT + if((name != LIB_DUMMY && obsnum > MAX_OBJECT) || obsnum > MAX_DUMMIES){ + error("Too many cloned objects from an unprivileged source."); + } + return efun::clone_object(name, args...); +} + +//Wodan removed saving binaries from FluffOS, causing a crasher +//if that config element is queried for in get_config(). +mixed get_config(int i){ + if(i == 6) return 0; + return efun::get_config(i); +} + +//For some reason, FluffOS read_file() will read +//a zero-length file as a 65535 length T_INVALID variable. +//This tends to screw things up for Dead Souls. +varargs string read_file(string file, int start_line, int number_of_lines){ + int sz = file_size(file); + if(sz < 1 || sz >= get_config(__MAX_STRING_LENGTH__)) return ""; + return efun::read_file(file, start_line, number_of_lines); +} + +//In FluffOS 2.13 and early versions of 2.14, check_memory() +//is a crasher. +string check_memory(int flag){ + string ret; +#if 1 +#ifdef __DEBUGMALLOC__ +#ifdef __DEBUGMALLOC_EXTENSIONS__ +#ifdef __PACKAGE_DEVELOP__ + ret = efun::check_memory(flag); +#endif +#endif +#endif +#endif + if(!ret) ret = ""; + return ret; +} + +mapping rusage(){ +#ifdef __HAS_RUSAGE__ + return efun::rusage(); +#else + return ([ "nivcsw" : 0, "isrss" : 0, "nsignals" : 0, "utime" : 0, + "oublock" : 0, "maxrss" : 0, "stime" : 0, + "nvcsw" : 0, "majflt" : 0, "nswap" : 0, "msgrcv" : 0, + "inblock" : 0, "minflt" : 0, "ixrss" : 0, + "msgsnd" : 0, "idrss" : 0 ]); +#endif +} + +string dump_file_descriptors(){ + if(!this_player() || !archp(this_player())){ + return ""; + } + return efun::dump_file_descriptors(); +} + +void reset_eval_cost(){ + if(master()->valid_apply(({ "SECURE", "ASSIST" }))) + efun::reset_eval_cost(); +} + +void set_eval_limit(int i){ + if(master()->valid_apply(({ "SECURE", "ASSIST" }))) + efun::set_eval_limit(i); +} + +string debug_info(int debuglevel, mixed arg){ + if(master()->valid_apply(({ "SECURE", "ASSIST" }))) + return efun::debug_info(debuglevel, arg); + else return "This sefun is not available to unprivileged objects."; +} + +string array groups(){ + string *group_arr = ({}); + string raw = read_file(CFG_GROUPS); + string *raw_arr = explode(raw,"\n"); + foreach(string element in raw_arr){ + string s1,s2,s3; + if(element[0..0] == "#"){ + continue; + } + if(sscanf(element,"(%s)%s",s1,s2) < 1) + sscanf(element,"%s(%s)%s",s2,s1,s3); + if(s1) group_arr += ({ s1 }); + } + return singular_array(group_arr); +} + +varargs string socket_address(mixed arg, int foo){ + return efun::socket_address(arg, foo); +} + +varargs int call_out(mixed fun, mixed delay, mixed args...){ + object prev = previous_object(); + string prevbase, wat; + mapping callers = ([]); + string *raw = call_out_info(); + int i = sizeof(raw); + mixed ret; + + gargs = args; + gfun = fun; + gdelay = delay; + + get_garbage(); + if(prev) prevbase = base_name(prev); + else error("call_out with no previous_object()"); + + if(sizeof(raw) > MAX_CALL_OUTS && (strsrch(prevbase,"/secure/") && + strsrch(prevbase,"/lib/") && strsrch(prevbase,"/std/") && + strsrch(prevbase,"/obj/") && + strsrch(prevbase,"/daemon/") && strsrch(prevbase,"/domains/"))){ + int err; + globalmixed = prev; + err = catch(unguarded( (: destruct( globalmixed ) :) )); + error(prevbase+": Too many callouts!"); + } + + foreach(string foo in blacklist){ + if(!strsrch(prevbase,foo)){ + error("Object on call_out blacklist."); + } + } + + if(stringp(fun)){ + if(member_array(fun,jokes) != -1){ + error("No jokes, please!"); + } + globalmixed = prev; + fun = bind( (: call_other, globalmixed, gfun :) ,prev); + } + gfun = fun; + + if(!strsrch(prevbase,"/open/")) error("call_out from /open"); + + if(strsrch(prevbase,"/secure/") && strsrch(prevbase,"/daemon/")){ +#if CALL_OUT_LOGGING + unguarded( (: write_file("/log/secure/callouts",timestamp()+" "+ + identify(previous_object(-1))+" "+identify((gargs || gfun))+"\n") :) ); +#endif + + while(i--){ + if(sizeof(raw[i]) && objectp(raw[i][0])){ + string *lol; + string wut; + lol = explode(base_name(raw[i][0]),"/"); + wut = "/"+lol[0]+"/"+lol[1]+"/"; + if(!(callers[wut])) callers[wut] = 1; + else callers[wut]++; + } + } + wat = "/"+explode(prevbase,"/")[0]+"/"+explode(prevbase,"/")[1]; + if(callers[wat] && callers[wat] > 10){ + if(!strsrch(prevbase,REALMS_DIRS) || callers[wat] > 100){ + globalmixed = prev; + blacklist += ({ wat }); + blacklist = singular_array(blacklist); + unguarded( (: destruct(globalmixed) :) ); + error("Too many callouts from an unprivileged directory."); + } + } + } + + if(sizeof(gargs)){ + ret = efun::call_out(gfun, gdelay, gargs...); + } + else { + ret = efun::call_out(gfun, gdelay); + } + return ret; +} + +string query_ip_number(object ob){ + string ret; + if(!ob) ob = previous_object(); + ret = ob->GetTeloptIp(); + if(!ret) ret = efun::query_ip_number(ob); + if(!AUTO_WIZ || ob == previous_object()) return ret; + if(master()->valid_apply(({ "SECURE", "ASSIST" }))) + return ret; + return "0.0.0.0"; +} + +//addr_server calls don't work well on Solaris and spam stderr +string query_ip_name(object ob){ + if(!ob) ob = previous_object(); + if(!strsrch(architecture(), "Solaris") || + ob->GetTeloptIp()) return query_ip_number(ob); + if(!AUTO_WIZ || ob == previous_object()) return efun::query_ip_name(ob); + if(master()->valid_apply(({ "SECURE", "ASSIST" }))) + return efun::query_ip_name(ob); + return "w.x.y.z"; +} + +string *query_local_functions(mixed arg){ + object ob; + string *allfuns; + string *ret = ({}); + if(objectp(arg)) ob = arg; + else if(stringp(arg)) ob = load_object(arg); + allfuns = functions(ob); + foreach(string subfun in allfuns){ + mixed thingy = function_exists(subfun,ob,1); + if(thingy && thingy == base_name(ob) && member_array(subfun,ret) == -1) + ret += ({ subfun }); + } + return ret; +} + +object find_object( string str ){ + object ret; + int err; + string thing; + if(!str || !stringp(str)) return 0; + err = catch(ret = efun::find_object(str)); + if(err || !ret) return 0; + thing = base_name(ret); + if(!strsrch(thing, "/domains/")) return ret; + if(base_name(previous_object()) == SERVICES_D) return ret; + if(master()->valid_apply(({ "SECURE", "ASSIST", "SNOOP_D" }))) return ret; + if(base_name(ret) == "/secure/obj/snooper") return 0; + if(archp(ret) && ret->GetInvis()) return 0; + else return ret; +} + +object find_player( string str ){ + object ret = efun::find_player(str); + if(ret && !ret->GetInvis()) return ret; + if(base_name(previous_object()) == SERVICES_D) return ret; + if(master()->valid_apply(({ "SECURE", "ASSIST", "SNOOP_D" }))) return ret; + if(ret && archp(ret) && ret->GetInvis()) return 0; + else return ret; +} + +object *livings() { + object *privlivs = efun::livings(); + object *unprivlivs = ({}); +#ifdef __FLUFFOS__ + unprivlivs = filter(privlivs, (: !($1->GetInvis() && archp($1)) :) ); +#else + foreach(mixed dude in privlivs){ + if(archp(dude) && dude->GetInvis()) continue; + unprivlivs += ({ dude }); + } +#endif + if(master()->valid_apply(({ "SECURE", "ASSIST", "SNOOP_D" }))) return privlivs; + if(base_name(previous_object()) == SERVICES_D) return privlivs; + else return unprivlivs; +} + +varargs mixed objects(mixed arg1, mixed arg2){ + object array tmp_obs; + + if(!strsrch(base_name(previous_object()),"/secure/")){ + if(base_name(previous_object()) == "/secure/obj/weirder"){ + if(!arg1) return efun::objects(); + return efun::objects(arg1); + } + if(this_player() && adminp(this_player())){ + if(!arg1) return efun::objects(); + return efun::objects(arg1); + } + } + + if(arg1) tmp_obs = efun::objects(arg1); + else tmp_obs = efun::objects(); + + if(!(master()->valid_apply(({ "SECURE", "ASSIST", "SNOOP_D" }))) && + base_name(previous_object()) != SERVICES_D){ +#ifdef __FLUFFOS__ + tmp_obs = filter(tmp_obs, (: !($1->GetInvis() && archp($1)) :) ); +#else + foreach(mixed dude in tmp_obs){ + if(dude && archp(dude) && dude->GetInvis()) tmp_obs -= ({ dude }); + } +#endif + } + if(base_name(previous_object()) == SNOOP_D || archp(this_player())){ + return tmp_obs; + } + if(!arg1){ + return filter(tmp_obs, (: base_name($1) != "/secure/obj/snooper" :) ); + } + + if(arg1 && !arg2) { + object *ret_arr = ({}); + if(!functionp(arg1)) return 0; + foreach(object ob in filter(tmp_obs, (: base_name($1) != "/secure/obj/snooper" :) )){ + if(evaluate(arg1, ob)) ret_arr += ({ ob }); + } + return ret_arr; + } + + if(arg1 && arg2) { + object *ret_arr = ({}); + if(!functionp(arg1)) return 0; + if(!objectp(arg2)) return 0; + foreach(object ob in filter(tmp_obs, (: base_name($1) != "/secure/obj/snooper" :) )){ + if(call_other(arg2, arg1, ob)) ret_arr += ({ ob }); + } + return ret_arr; + } + + else return ({}); +} + +#ifdef __FLUFFOS__ +mixed array users(){ + object *ret = filter(efun::users(), (: ($1) && environment($1) :) ); + if(!(master()->valid_apply(({ "SECURE", "ASSIST", "SNOOP_D" }))) && + base_name(previous_object()) != SERVICES_D) + ret = filter(ret, (: !($1->GetInvis() && archp($1)) :) ); + return ret; +} +#else +mixed array users(){ + object *ret = ({}); + if(sizeof(efun::users())) + foreach(mixed foo in efun::users()){ + if(objectp(foo) && environment(foo)) ret += ({ foo }); + } + if(!(master()->valid_apply(({ "SECURE", "ASSIST", "SNOOP_D" }))) && + base_name(previous_object()) != SERVICES_D) + foreach(mixed foo in ret){ + if(foo->GetInvis() && archp(foo)) ret -= ({ foo }); + } + return ret; +} +#endif + +int destruct(object ob) { + string *privs; + string tmp; + int ok; + if(!ob) return 0; + privs = ({ file_privs(file_name(ob)) }); + + if(!previous_object() || previous_object() == master() || + previous_object() == this_object()) ok = 1; + + else if(master()->valid_apply(({ "ASSIST" }) + privs)) ok = 1; + + else if(previous_object(0) && tmp = query_privs(previous_object(0))){ + if(previous_object(0) == ob) ok = 1; + if(member_array(PRIV_SECURE, explode(tmp, ":")) != -1) ok = 1; + } + + if(DESTRUCT_LOGGING){ + string stat = "FAIL"; + if(ok) stat = "success"; + log_file("destructs",timestamp()+"\n"+stat+"\n"+get_stack(1)+"\n--\n"); + } + if(ob == this_object()){ + if( !(master()->valid_apply(({ "SECURE" }))) ) + error("Illegal attempt to destruct SEFUN: "+get_stack()+" "+identify(previous_object(-1))); + } + if(ok) return efun::destruct(ob); + else return 0; +} + +int valid_event(object dester, object dested){ + string desterbase, destedbase, topdester, topdested; + string contextdester, contextdested; + int i; + if(!dester || !dested) return 0; + return 1; + desterbase = base_name(dester); + destedbase = base_name(dested); + i = sscanf(desterbase,"/%s/%s/%*s", topdester, contextdester); + if(topdester != "realms" && topdester != "open") return 1; + i = sscanf(destedbase,"/%s/%s/%*s", topdested, contextdested); + if(contextdested && contextdester && contextdested == contextdester){ + return 1; + } + return 0; +} + + +static void shutdown_logic(int code){ + efun::shutdown(code); +} + +varargs void shutdown(int code) { + object *persistents; + object portals = find_object(PORTAL_D); + object rooms = find_object(ROOMS_D); + object players = find_object(PLAYERS_D); + if(!(master()->valid_apply(({"ASSIST"}))) && + !(master()->valid_apply(({"SECURE"})))) return; + if(code == -9) efun::shutdown(code); + else call_out( (: shutdown_logic :), 0, code); + if(this_player()) + log_file("shutdowns", this_player()->GetCapName()+ + " shutdown "+mud_name()+" at "+ctime(time())+"\n"); + else log_file("shutdowns", "Game shutdown by "+ + file_name(previous_object(0))+" at "+ctime(time())+"\n"); + persistents = objects( (: $1->GetPersistent() :) ); + if(portals) catch( portals->eventDestruct() ); + if(rooms) catch( rooms->eventDestruct() ); + if(players) catch( players->eventDestruct() ); + persistents->SaveObject(); +} + +int valid_snoop(object snooper, object target){ + if(member_group(target, PRIV_SECURE)) { + message("system", snooper->GetCapName()+" is trying to snoop " + "you.", target); + if(!member_group(snooper, PRIV_SECURE)) return 0; + } + if(archp(snooper)) return 1; + if( base_name(snooper) == "/secure/obj/snooper" ) return 1; + //Uncomment the following line to let cres snoop players + //if(creatorp(snooper) && playerp(target)) return 1; + if(snooperp(snooper) && creatorp(snooper) && playerp(target)) return 1; + return 0; +} + +varargs object snoop(object who, object target) { + if(!target) return efun::snoop(who); + if(!creatorp(who) && base_name(who) != "/secure/obj/snooper" ) return 0; + if(!(master()->valid_apply(({ "ASSIST" })))) { + if(!(target->query_snoopable())) return 0; + else return efun::snoop(who, target); + } + else if(member_group(target, PRIV_SECURE)) { + message("system", who->GetCapName()+" is now snooping " + "you.", target); + return efun::snoop(who, target); + } + else return efun::snoop(who, target); +} + +object query_snoop(object ob) { + if(base_name(previous_object()) != SNOOP_D) + return 0; + return efun::query_snoop(ob); +} + +object query_snooping(object ob) { + if(!(master()->valid_apply(({})))) return 0; + else return efun::query_snooping(ob); +} + +int exec(object target, object src) { + string tmp; + int ret; + tmp = base_name(previous_object()); + if(tmp != LIB_CONNECT && tmp != CMD_ENCRE && tmp != CMD_DECRE + && tmp != SU && tmp != RELOAD_D) return 0; + if(objectp(target) && objectp(src)) ret = efun::exec(target, src); + return ret; +} + +void write(string str) { + if(this_player()) message("my_action", str, this_player()); + else efun::write(str); +} + +void set_privs(object ob, string str) { return; } + +void notify_fail(string str) { + if( !this_player() ) return; + if( str[<1..] == "\n" ) str = str[0..<2]; + this_player()->SetCommandFail(str); +} + +/* want to handle colours, but do it efficiently as possible */ +string capitalize(mixed str) { + string *words, *tmp; + int i; + + if(objectp(str)) str = str->GetKeyName(); + + /* error condition, let it look like an efun + * mmmm let's not + * if( !str || str == "" ) return efun::capitalize(str); + */ + if(!str) str = ""; + /* most strings are not colour strings */ + if( strlen(str) < 2 || str[0..1] != "%^" ) return efun::capitalize(str); + /* god help us */ + words = explode(str, " "); + /* ok, this is strange, but remember, colours are all caps :) */ + tmp = explode(words[0], "%^"); + for(i=0; iGetEfuns(),1); +} + +string *sefuns(){ + return sort_array(functions(this_object()),1); +} + +int efun_exists(string str){ + if(member_array(str,MASTER_D->GetEfuns()) != -1) return 1; + return 0; +} + +int sefun_exists(string str){ + if(member_array(str,functions(this_object())) != -1) return 1; + return 0; +} + +#if efun_defined(query_charmode) +varargs int in_input(object ob){ + int ret; + if(ob) globalob = ob; + else globalob = previous_object(); + if(!(efun::query_charmode(globalob)) && + !(globalob->GetProperty("was_charmode")) && + !(globalob->GetCharmode())){ + if(efun::in_input(globalob)) ret = 2; + } + return (ret ? 1 : 0); +} + +int query_charmode(object ob){ + if(ob) globalob = ob; + else globalob = previous_object(); + return efun::query_charmode(globalob); +} + +#else +int query_charmode(object ob){ + return -1; +} +#endif + +int in_pager(object ob){ + if(ob) globalob = ob; + else globalob = previous_object(); + if(in_edit(globalob) || in_input(globalob)) return 1; + if(globalob->GetProperty("was_charmode") && + !query_charmode(globalob)){ + //Ok, a bit counterintuitive, but the deal is that if you WERE in + //charmode, and aren't anymore, the only reason for this is that + //charmode is temporarily suspended so you can navigate a pager. + return 1; + } + return 0; +} + +varargs void input_to(mixed fun, int flag, mixed args...){ + object prev = previous_object(); + object player = this_player(); + int was; + + gargs = args; + gfun = fun; + gdelay = flag; + + if(!prev){ + error("input_to with no previous_object()"); + } + if(stringp(fun)){ + if(member_array(fun,jokes) != -1){ + error("Please, no jokes!"); + } + globalmixed = prev; + fun = bind( (: call_other, globalmixed, gfun :) ,prev); + } + gfun = fun; + + if(player && player->GetCharmode()){ +#if efun_defined(remove_get_char) + remove_get_char(player); + was = 1; +#endif +#if efun_defined(remove_charmode) + remove_charmode(player); + was = 1; +#endif + player->SetProperty("was_charmode", 1); + } + if(sizeof(gargs)){ + efun::input_to(gfun, gdelay, gargs...); + } + else { + efun::input_to(gfun, gdelay); + } +} + +/* Do not use this sefun directly. */ +varargs mixed file_present_logic(string str, object ob, int i){ + int cloned; + mixed *rets = ({}); + if(objectp(str) || strsrch(str,"/")){ + return efun::present(str, ob); + } + if(grepp(str,"#")) cloned = 1; + foreach(mixed item in all_inventory(ob)){ + if(cloned && file_name(item) == str) rets += ({ item }); + else if(!cloned && base_name(item) == str) rets += ({ item }); + } + if(i && sizeof(rets)) return rets; + else if(sizeof(rets)) return rets[0]; + return 0; +} + +varargs mixed present_file(mixed str, mixed ob, int i){ + object ret, env, *rets = ({}); + if(!str) return 0; + if(objectp(str)) str = base_name(str); + if(ob){ + ret = file_present_logic(str, ob, i); + if(ret) return ret; + } + else { + ob = previous_object(); + if(ob){ + ret = file_present_logic(str, ob, i); + if(ret) return ret; + env = environment(ob); + if(env) ret = file_present_logic(str, env, i); + if(ret) return ret; + } + } + return 0; +} + +varargs mixed present_bonus(mixed str, mixed ob, int i){ + mixed thingies = ( filter( all_inventory(ob), + (: $1->GetBonusName() :) ) || ({}) ); + thingies = filter(thingies,(: $1->GetBonusName() == $(str) :)); + if(!i && sizeof(thingies)) return thingies[0]; + else if(sizeof(thingies)) return thingies; + return 0; +} + +int shadow_unhooked(){ + object ob = previous_object(); + return !(inherits(LIB_SHADOW_HOOK, ob)); +} diff --git a/lib/secure/sefun/sefun.h b/lib/secure/sefun/sefun.h new file mode 100644 index 0000000..d38f226 --- /dev/null +++ b/lib/secure/sefun/sefun.h @@ -0,0 +1,307 @@ +/** + * + * 2006-03-21, jonez + * - changed prototype for update to return int instead of object + * - changed prototype for reload_room to remove the "recurse" argument + * - changed prototype for itoa to return string instead of int + */ + +#ifndef l_sefun_h +#define l_sefun_h + +#ifndef CARRIAGE_RETURN +#define CARRIAGE_RETURN "\r" +#endif + +varargs string socket_address(mixed arg, int foo); +string absolute_path(string curr, string newpth); +int absolute_value(int x); +varargs string add_article(string str, int def); +int ambassadorp(object ob); +string architecture(); +int archp(object ob); +string arrange_string(string str, int x); +string base_name(mixed val); +string cardinal(int x); +varargs string center(string str, int x); +varargs string conjunction(mixed expressions, string coordinator); +string consolidate(int x, string str); +string convert_name(string str); +varargs mixed convert_string(string str, int flag); +mixed copy(mixed val); +varargs int creatorp(object ob); +float currency_inflation(string type); +float currency_rate(string type); +int currency_mass(int x, string type); +int currency_value(int x, string str); +int destruct(object ob); +mixed *distinct_array(mixed *arr); +varargs string domain(mixed val, int path); +int domain_exists(string dmn); +object domain_master(mixed val); +varargs int effective_light(object ob); +varargs void event(string fun, int when, mixed *args, int reg); +mapping expand_keys(mapping mp); +int event_pending(object ob); +int exec(object target, object src); +int file_exists(string str); +string file_privs(string file); +varargs string format_page(string *items, int columns, int modifier); +varargs object get_object(string str, object player, int living); +varargs mixed get_objects(string str, object player, int no_arr); +int hiddenp(object ob); +int high_mortalp(object ob); +//string identify(mixed a); +varargs string identify( mixed a ); +string item_list(mixed *items); +int leaderp(object ob); +object *livings(); +//object load_object(string str); +void log_file(string fl, string msg); +int member_group(mixed who, string grp); +int moral_act(object who, object target, int amount); +string *mud_currencies(); +string mud_name(); +varargs string imc2_mud_name(string name); +string mudlib(); +string mudlib_version(); +varargs int newbiep(object ob); +string nominative(mixed val); +string objective(mixed val); +string ordinal(int x); +object parse_objects(object where, string str); +mixed *path_file(mixed full_path); +float percent(mixed numerator, mixed denominator); +varargs int playerp(object ob); +string possessive(mixed val); +string possessive_noun(mixed val); +int query_date(int x); +string query_day_name(int x); +int query_host_port(); +int query_hour(int x); +int query_minutes(int x); +string query_month(int x); +int query_night(); +int query_reset_number(); +string query_season(int x); +object query_snoop(object snoopee); +object query_snooping(object ob); +string query_time_of_day(); +int query_year(int x); +string reflexive(mixed val); +string remove_article(string str); +string player_save_file(string who); +string save_file(string what); +varargs void say(mixed str, object ob); +void set_eval_limit(int x); +void set_privs(object ob, string str); +varargs void shout(mixed str, mixed exclude); +varargs void shutdown(int code); +varargs object snoop(object who, object target); +string strip_article(mixed val); +string strip_colours(string str); +void tell_object(object ob, mixed str); +varargs void tell_room(object ob, mixed str, mixed exclude); +varargs object this_agent(mixed val); +function time_event(string tod, function f); +object to_object(mixed target); +varargs int total_light(object ob); +string translate(string str, int prof); +string trim(string str); +mixed unguarded(function f); +object unique(string fn, int rare); +int user_exists(string str); +varargs string user_path(string name, int legacy); +string version(); +varargs int visibility(object ob); +varargs int visible(object detectee_obj, object detector_obj); +varargs string wrap(string str, int width); +void write(string str); +int tail(string file); +void tell_player(mixed player, string msg); +string *query_custom_path(); +string query_custom_command(string str); +string dump_socket_status(); +string flat_map(mapping mp); +string *get_cmds(); +string *get_verbs(); +varargs object array get_livings(object ob,int foo); +string local_time(string str); +void reap_dummies(); +varargs void reap_other(string str); +mixed reap_list(); +string timestamp(mixed tz); +object *get_dupes(object ob, object where); +varargs string get_stack(int x); +mixed hobbled(object ob); +string query_base_currency(); +int query_base_rate(); +int query_player_money(object who); +int query_base_value(string currency, int amount); +varargs int make_workroom(mixed dude, int cre); +int valid_currency(string str); +varargs int query_invis(object lookee, object looker); +string set_tz(string str); +string admin_email(); +int query_night_light(object ob); +int query_day_light(object ob); +int query_ambient_light(object ob); +int reload_room(object ob); +void tc(string str); +string opposite_dir(string str); +mixed *singular_array(mixed *arr); +varargs mixed remove_matching_line(string target, string substring, int i, string exclude); +string truncate(string str, int i); +int check_privs(mixed pretender, mixed target); +varargs int true(mixed args...); +varargs int false(mixed args...); +int indent_file(string filename); +string path_prefix(string str); +varargs string first_string_element(string str, string delimiter, int stripfirst); +string last_string_element(string str, string delimiter); +string replace_line(string file, string *params, string repl); +int memberp(mixed *primary, mixed sub); +int reverse_memberp(string primary, string *sub); +int mgrepp(string primary, string *sub); +int grepp(string primary, string sub); +varargs mixed replace_matching_line(string target, string substring, string replace, int i, string exclude); +varargs mixed remove_matching_line(string target, string substring, int i, string exclude); +string first(string str, int i); +varargs string last(string str, int i, int significant); +int starts_with_arr(string primary, string *sub); +int starts_with(string primary, string sub); +string reverse_string(string str); +varargs mixed homedir(mixed ob, int cre); +varargs string generate_tmp(mixed arg); +string newline_trim(string str); +int directory_exists(string str); +mixed reload(object ob); +string query_os_type(); +varargs mixed read_matching_line(string target, string substring, int i, string exclude); +int abs(int x); +int wipe_inv(mixed dude); +int bool_reverse(mixed arg); +mixed check_light(object who); +int query_carrying(object who, mixed thing); +mixed *findobs(mixed arg); +int atoi(string str); +string itoa(int i); +string *query_names(object whom); +int answers_to(string name, object what); +varargs void add_event(string source, string ob, string fun, mixed *args, int when, int repeat); +varargs void remove_event(int i); +int update(string str); +varargs mixed local_ctime(int i, string tzone); +int numericp(mixed arg); +int basic_punctuationp(mixed arg); +mixed mapping_member(mapping Map, string sub); +mixed find_inheritors(mixed arg); +mixed find_deep_inheritors(mixed arg); +int imud_privp(mixed guy); +int securep(mixed guy); +string convert_ascii(int i); +varargs object get_random_living(object room, int foo); +varargs int debug(mixed msg, mixed val, string color); +int valid_timezone(string str); +varargs int tell_creators(string msg, string color); +varargs int tn(string str, string col, object room); +varargs int trr(string str, string col); +varargs string *wild_card(string str); +nomask int remove_dots(string str); +int domain_admin(string pretender, string domain); +int compare_array(mixed *arr1, mixed *arr2); +int arrcmp(mixed *arr1, mixed *arr2); +string append_line(string file, string *params, string repl); +int alphap(mixed arg); +varargs mixed alpha_crypt(mixed arg1, mixed arg2); +void set(mixed arg1, mixed arg2); +void query(mixed arg1, mixed arg2); +void personal_log(string str); +void add_sky_event(function f); +int assistp(mixed guy); +int elderp(object ob); +int testp(object ob); +string alpha_strip(mixed arg); +mixed seteuid(mixed args); +mixed getuid(mixed args); +mixed geteuid(mixed args);string *query_local_functions(mixed arg); +int check_string_length(string str); +varargs mixed print_long_string(object who, string str, int catted); +void add(mixed arg1, mixed arg2); +varargs int wizardp(object ob); +int adminp(object ob); +varargs mixed dump_variable(mixed foo, mixed bar); +string day(); +int date(); +string month(); +int year(); +varargs int minutes(int x); +varargs string season(int x); +string query_time(); +varargs int hour(int x); +varargs string time_elapsed(int arg1, int arg2); +int bitshiftedp(int x); +#if CALL_OUT_LOGGING +int call_out(mixed args...); +#endif +string strip_colors(string str); +string strip_colors_old(string str); +varargs string *chunk_string(string str, int width); +string array groups(); +string query_intermud_ip(); +string *atomize_string(string str); +string *atomize_array(string *temp_arr); +varargs mixed match_command(string verb, int subs); +varargs mixed random_numbers(int n, int integer); +int snooperp(mixed guy); +string native_version(); +string convert_newline(string str); +int clean_newline_file(string str); +mixed convert_into_ascii(string str); +int check_read(string file); +varargs string simple_map(mixed arg); +string query_door(object what, string direction); +int mkdir_recurse(string path); +mixed *socket_names(); +string morse(string msg); +string unmorse(string msg); +int *roll(string alea); +mixed *scramble_array(mixed *arr); +int builderp(object ob); +string socket_ip(int fd); +string unpinkfish(string str); +string repinkfish(string str); +string web_translate(string str); +string *efuns(); +string *sefuns(); +int efun_exists(string str); +int sefun_exists(string str); +varargs int estatep(object ob); +string dbz_colors(string str, int annoying); +mixed lpc_file(string str); +mixed object_file(string str); +int telnet_privp(mixed guy); +object *containers(object ob); +int ordinalp(string str); +object *get_dummies(mixed where); +varargs mixed coordinates(object ob, string type); +mixed calculate_coordinates(string str, int x, int y, int z, string type); +object room_environment(object ob); +int query_windows(); +varargs mixed file_present(mixed str, mixed ob, int i); +varargs mixed present_bonus(mixed str, mixed ob, int i); +varargs string query_unique_name(mixed ob, int cloned); +varargs string system_month(int i, int abbr); +varargs string system_day(int i, int abbr); +void write2(string str); +mixed *remove_member(mixed *arr, int i); +object sefun(); +string cleaned_name(string str); +string cleaned_end(string str); +string new_savename(string name); +string old_savename(string name); +string comma(mixed x); +string *read_big_file(string str); +int valid_event(object dester, object dested); + +#endif /* l_sefun_h */ diff --git a/lib/secure/sefun/sockets.c b/lib/secure/sefun/sockets.c new file mode 100644 index 0000000..5094bda --- /dev/null +++ b/lib/secure/sefun/sockets.c @@ -0,0 +1,44 @@ +string dump_socket_status() { + string ret; + string *finalsocks, *sock_array = ({}); + int i, quant = sizeof(socket_status()); + for(i = 0; i < quant; i++){ + sock_array += ({ socket_status(i) }); + } + finalsocks = sock_array; + + ret = ""; + ret += " Fd State Mode Local Address Remote Address"; + ret += " -- --------- -------- --------------------- ---------------------"; + + foreach (array item in finalsocks) { + int memb = member_array(item, finalsocks); + ret += sprintf("%2d %|9s %|8s %-21s %-21s\n", memb, item[1], item[2], item[3], item[4]); + } + + return ret; +} + +mixed *socket_names(){ + string *finalsocks, *sock_array = ({}); + int i, quant; + i = catch( quant = sizeof(socket_status()) ); + if(i){ + return ({}); + } + for(i = 0; i < quant; i++){ + mixed *tmp = socket_status(i); + tmp[0] = i; + sock_array += ({ tmp }); + } + finalsocks = sock_array; + + return finalsocks; +} + +string socket_ip(int fd){ + string ret = "0"; + mixed sock_stat = socket_status(fd); + if(sock_stat) ret = implode(explode(sock_stat[4],".")[0..3], "."); + return ret; +} diff --git a/lib/secure/sefun/strings.c b/lib/secure/sefun/strings.c new file mode 100644 index 0000000..a232e73 --- /dev/null +++ b/lib/secure/sefun/strings.c @@ -0,0 +1,878 @@ +/* /adm/sefun/strings.c + * from Foundation II + * sefuns for string manipulation + * created by Descartes of Borg 940506 + */ + +#include +#include +#include +#include + +string global_temp_file = ""; + +mapping Morse = ([ "a" : ".-", "b" : "-...", "c" : "-.-.", + "d" : "-..", "e" : ".", "f" : "..-.", "g" : "--.", "h" : "....", "i" : "..", + "j" : ".---", "k" : "-.-", "l" : ".-..", "m" : "--", "n" : "-.", "o" : "---", + "p" : ".--.", "q" : "--.-", "r" : ".-.", "s" : "...", "t" : "-", "u" : "..-", + "v" : "...-", "w" : ".--", "x" : "-..-", "y" : "-.--", "z" : "--..", + "1" : ".----", "2" : "..---", "3" : "...--", "4" : "....-", "5" : ".....", + "6" : " -....", "7" : "--...", "8" : "---..", "9" : "----.","0" : " -----", + "." : ".-.-.-", "," : "--..--", "?" : "..--..", "'" : ".----.", "!" : "-.-.--", + "/" : "-..-.", "(" : "-.--.", ")" : "-.--.-", "&" : ".-...", ":" : "---...", + ";" : "-.-.-.", "=" : "-...-", "+" : ".-.-.", "-" : "-....-", "_" : "..--.-", + "\"" : ".-..-.", "$" : "...-..-", "@" : ".--.-." ]); + +varargs string center(string str, int x) { + int y; + + if(!x) x= 80; + x--; + if((y = strlen(strip_colours(str))) >= x) return str; + x = x + strlen(str) - y; + return sprintf(sprintf("%%|%ds", x), str); +} + +varargs string arrange_string(string str, int x) { + string orig = str; + string bare = strip_colors(str); + if(!x) x = 80; + x += (strlen(orig) - strlen(bare)); + return sprintf(sprintf("%%:-%ds", x), str); +} + +string to_html(string str) { + return TERMINAL_D->GetHTML(str); +} + +string trim(string str) { + string *whitespace; + int j, i = 0; + + j = strlen(str) - 1; + whitespace = ({ ' ', '\t' }); + while(member_array(str[i], whitespace) != -1) i++; + while(i < j && member_array(str[j], whitespace) != -1) j--; + return str[i..j]; +} + +string space_trim(string str) { + string whitespace; + + whitespace = " " ; + while(grepp(str, whitespace)) { + str = replace_string(str," "," "); + } + return str; +} + +string newline_trim(string str) { + string *whitespace; + int j, i = 0; + + j = strlen(str) - 1; + whitespace = ({ '\n' }); + while(member_array(str[i], whitespace) != -1) i++; + while(i < j && member_array(str[j], whitespace) != -1) j--; + return str[i..j]; +} + +varargs string wrap(string str, int x) { + if( !x ) { + if( !this_player() ) x = 79; + else { + int *tmp; + + tmp = (int *)this_player()->GetScreen(); + if( tmp ) x = (tmp[0] || 79); + else x = 79; + } + } + if(sizeof(str) < 7900) return sprintf("%-=" + x + "s\n", str); + else { + string tmpfile = generate_tmp(); + write_file(tmpfile,str); + str = read_bytes(tmpfile,0,7900); + rm(tmpfile); + str += "\n*** TRUNCATED ***\n"; + return sprintf("%-=" + x + "s\n", str); + } +} + +varargs mixed convert_string(string str, int flag) { + mixed *ret = ({ 0, "" }); + + if(!str || !sizeof(str) || str == "") return 0; + + if( (str = trim(str)) == "" ) return 0; + if( str[0] == '(' ) { + switch(str[1]) { + + case '{': + + ret[0] = ({}); + str = str[2..]; + while(str[0] != '}') { + mixed *tmp; + + tmp = convert_string(str, 1); + ret[0] += ({ tmp[0] }); + str = tmp[1]; + while(str[0] == ' ' || str[0] == '\t') str = str[1..]; + if( str[0] != ',' && str[0] != '}' ) + error("Improperly formatted array: " + str + "\n"); + else if( str[0] == ',') { + str = str[1..]; + while(str[0] == ' ' || str[0] == '\t') str = str[1..]; + } + } + if( str[1] != ')' ) { + str = str[2..]; + while(str[0] == ' ' || str[0] == '\t') str = str[1..]; + if( str[0] != ')' ) error("Illegal array terminator.\n"); + else ret[1] = str[1..]; + } + else ret[1] = str[2..]; + if( !flag ) return ret[0]; + while(ret[1][0] == ' ' || ret[1][0] == '\t') ret[1] = ret[1][1..]; + return ret; + + case '[': + + ret[0] = ([]); + str = str[2..]; + while(str[0] != ']') { + mixed *tmp; + mixed cle; + + tmp = convert_string(str, 1); + str = tmp[1]; + while(str[0] == ' ' || str[0] == '\t') str = str[1..]; + if( str[0] != ':' ) + error("Illegally formatting mapping: " + str + "\n"); + cle = tmp[0]; + tmp = convert_string(str[1..], 1); + ret[0][cle] = tmp[0]; + str = tmp[1]; + while(str[0] == ' ' || str[0] == '\t') str = str[1..]; + if( str[0] != ',' && str[0] != ']' ) + error("Illegally formatted mapping: " + str + "n"); + else if( str[0] != ']' ) { + str = str[1..]; + while(str[0] == ' ' || str[0] == '\t') str = str[1..]; + } + } + if( str[1] != ')' ) { + str = str[2..]; + while(str[0] == ' ' || str[0] == '\t') str = str[1..]; + if( str[0] != ')' ) error("Illegal array terminator.\n"); + else ret[1] = str[1..]; + } + else ret[1] = str[2..]; + if( !flag ) return ret[0]; + while(ret[1][0] == ' ' || ret[1][0] == '\t') ret[1] = ret[1][1..]; + return ret; + } +} +else if( str[0] == '"' ) { + string tmp; + + tmp = ""; + while( str[1] != '"' || (str[1] == '"' && str[0] == '\\') ) { + if( str[1] == '"' ) tmp = tmp[0..<2] + "\""; + else tmp += str[1..1]; + str = str[1..]; + } + if( !flag ) return tmp; + if( strlen(str) > 2 ) str = trim(str[2..]); + return ({ tmp, str }); +} +else if( str[0] >= '0' && str[0] <= '9' || str[0] == '-' ) { + string tmp; + int y; + + if( strlen(str) > 1 && str[0] == '-' ) { + tmp = str[0..0]; + str = str[1..]; + } + else { + tmp = ""; + } + if( strlen(str) > 1 && str[0..1] == "0x" ) { + tmp = "0x"; + str = str[2..]; + while(str != "" && (str[0] >= '0' && str[0] <= '9')) { + tmp += str[0..0]; + if( strlen(str) > 1 ) str = str[1..]; + else str = ""; + } + sscanf(tmp, "%x", y); + } + else { + while(str != "" && (str[0] >= '0' && str[0] <= '9')) { + tmp += str[0..0]; + if( strlen(str) > 1 ) str = str[1..]; + else str = ""; + } + sscanf(tmp, "%d", y); + } + if( !flag ) return y; + if( str != "" ) str = trim(str); + return ({ y, str }); +} +else { + string tmp; + + tmp = ""; + while(strlen(str) && ((str[0] >= 'a' && str[0] <= 'z') || + (str[0] >= 'A' && str[0] <= 'Z') || + (str[0] >= '0' && str[0] <= '9') || + (str[0] == '_'))) { + tmp += str[0..0]; + if( strlen(str) > 1 ) str = str[1..]; + else str = ""; + } + if( !flag ) return to_object(tmp); + else return ({ to_object(tmp), str }); +} +error("Gobbledygook in string.\n"); +} + +//this sefun courtesy of Duuk@Haven +string reverse_string(string str) { + int i; + string newstring = ""; + + if (!str) error("The reverse_string sefun needs input."); + + for (i = strlen(str); i >= 0; i--) { + newstring += str[i..i]; + } + return newstring; +} + +int starts_with(string primary, string sub){ + string rev, junk; + //primary = replace_string(primary,"\t"," "); + if(!primary) return 0; + rev = reverse_string(primary); + rev = trim(rev); + if(!rev) return 0; + primary = reverse_string(rev); + if(!sscanf(primary,sub+" %s",junk) > 0) + sscanf(primary,sub+"%s",junk); + if(junk) return 1; + + else return 0; +} + +int starts_with_arr(string primary, string *sub){ + string rev, junk; + if(!primary ||!stringp(primary)) return 0; + if(!rev = reverse_string(primary)) return 0; + rev = trim(rev); + if(!rev) return 0; + primary = reverse_string(rev); + foreach(string element in sub){ + if(sscanf(primary,element+" %s",junk) > 0) return 1; + } + return 0; +} + +// returns the last [i] characters of a string. +varargs string last(string str, int i, int significant){ + if(!str || !sizeof(str) || !stringp(str)) return ""; + return str[ 0) wtf = "wtf"; + if(!target || !file_exists(target)) true(); + else target = read_file(target); + if(!target) return 0; + if(strsrch(target,substring) == -1) return target; + if(strsrch(target,"\n") == -1) return 0; + filename = "/tmp/"+random(time())+time()+".tmp"; + new_file = ""; + if(!exclude) exclude = filename; + + write_file(filename,target); + + for(i=1; !done; i++){ + line = read_file(filename, i, 1); + if(!line) break; + if(strsrch(line,substring) != -1 && strsrch(line,exclude) == -1) omit =1; + if(omit && last(line[0..strlen(line)-2],1,1) != ";") { + tail_search = 1; + } + else tail_search = 0; + + if(omit || tail_search) { + new_file += line; + } + + + if(!tail_search) omit = 0; + if(!line) done = 100; + if(i == 999) done = 100; + } + + rm(filename); + ret_array = explode(new_file,"\n"); + //return ret_array[0]; + if(wtf) return new_file; + else return ret_array[0]; +} + + +//If you try to use replace_matching_line and it doesn't work, +//it may be that the file in question is not a .c file. This sefun +//keys on .c file syntax to know where lines begin and end. If the +//string you're editing doesn't have, for example, semicolons, +//your line replacememnt probably won't work well. Instead use the +//sefun replace_line. +varargs mixed replace_matching_line(string target, string substring, string replace, int i, string exclude){ + int omit, done, tail_search, tag_it; + string line, filename, new_file; + + tag_it = 0; + omit = 0; + + if(!target || !file_exists(target)) true(); + else target = read_file(target); + if(!target) return 0; + if(strsrch(target,substring) == -1) return target; + if(strsrch(target,"\n") == -1) return 0; + filename = "/tmp/"+random(time())+time()+".tmp"; + new_file = ""; + + write_file(filename,target); + + for(i=1; !done; i++){ + line = read_file(filename, i, 1); + if(!line) break; + if(strsrch(line,substring) != -1 ) omit =1; + + if(omit && last(line[0..strlen(line)-2],1,1) != ";") { + tail_search = 1; + } + else { + tail_search = 0; + if(omit) tag_it = 1; + } + + if(!omit && !tail_search) { + new_file += line; + } + + if(tag_it == 1){ + new_file += replace+"\n"; + tag_it = 0; + } + + if(!tail_search) omit = 0; + if(!line) done = 100; + if(i == 999) done = 100; + } + + rm(filename); + return new_file; +} + +int grepp(string primary, string sub){ + if(!primary || ! sub) return 0; + if(strsrch(primary,sub) != -1) return 1; + else return 0; +} + +int memberp(mixed *primary, mixed sub){ + if(member_array(sub,primary) != -1) return 1; + else return 0; +} + +int reverse_memberp(string primary, string *sub){ + foreach(string element in sub){ + if(strsrch(primary,element) != -1) return 1; + } + return 0; +} + +//This sefun is for non-code text. To replace lines in an LPC-code +//formatted string, use replace_matching_line instead. +string replace_line(string file, string *params, string repl){ + string *file_arr; + int alarm; + + if(!file || !stringp(file)) return ""; + file_arr = explode(file, "\n"); + + foreach(string line in file_arr){ + alarm = 0; + + foreach(string element in params){ + if(grepp(line,element)) alarm++; + } + + if(alarm == sizeof(params)){ + file_arr[member_array(line,file_arr)] = repl; + } + + } + return implode(file_arr,"\n"); +} + +string append_line(string file, mixed params, string repl){ + string *file_arr; + int alarm; + + if(!file || !stringp(file)) return ""; + file_arr = explode(file, "\n"); + + if(params){ + if(stringp(params)) params = ({ params }); + } + + foreach(string line in file_arr){ + alarm = 0; + + foreach(string element in params){ + if(grepp(line,element)) alarm++; + } + + if(alarm == sizeof(params)){ + file_arr[member_array(line,file_arr)] += ("\n"+repl); + } + + } + return implode(file_arr,"\n"); +} + +string last_string_element(string str, string delimiter){ + mixed ret; + if(!str || !delimiter || !grepp(str,delimiter)) return ""; + ret = explode(str,delimiter); + if(sizeof(ret)) return ret[<1..][0]; + return ""; +} + +varargs string first_string_element(string str, string delimiter, int stripfirst){ + if(!str || !delimiter || !grepp(str,delimiter)) return ""; + return explode(str,delimiter)[0]; +} + +string path_prefix(string str){ + int i = sizeof(str) - sizeof(last_string_element(str,"/")); + return str[0..i-2]; +} + +varargs mixed homedir(mixed ob, int cre){ + string name = ""; + string initial = ""; + if(!ob) ob = this_player(); + if(!ob) return 0; + if(objectp(ob)) name = ob->GetKeyName(); + else if(stringp(ob)) name = ob; + else return 0; + if(!sizeof(name)) return 0; + initial = name[0..0]; + if(!user_exists(name)) return 0; + if(cre || directory_exists("/realms/"+name)) return "/realms/"+name; + else return DIR_ESTATES + "/"+initial+"/"+name; +} + +varargs mixed random_numbers(int n, int integer){ + string ret = ""; + int i; + if(integer && n > 9) n = 9; + for(i=n;i>0;i--){ + //int tmp = 1; + int tmp = random(10); + if(!sizeof(ret)) tmp = random(9)+1; + ret += itoa(tmp); + } + if(!integer) return ret; + else return(atoi(ret)); +} + +varargs mixed alpha_crypt(mixed arg1, mixed arg2){ + string ret; + if(!intp(arg1) && !arg2) return 0; + if(intp(arg1)) { + if(arg1 > 64) arg1 = 64; + //ret = crypt(""+random(arg1+2)+arg1,""+random(arg1+2)+arg1); + //ret += crypt(""+random(arg1+2)+arg1,""+random(arg1+2)+arg1); + ret = crypt(""+random(arg1+2)+arg1,""+random(999999)*91); + ret += crypt(""+random(arg1+2)+arg1,""+random(999999)*19); + ret = replace_string(ret,"`",""); + ret = replace_string(ret,"!",""); + ret = replace_string(ret,"/",""); + ret = replace_string(ret,".",""); + return ret[0..(arg1 - 1)]; + } + + ret = crypt(arg1, arg2); + ret = replace_string(ret,"`",""); + ret = replace_string(ret,"!",""); + ret = replace_string(ret,"/",""); + ret = replace_string(ret,".",""); + + return ret; +} + + +varargs string generate_tmp(mixed arg){ + string ret; + //string randy = replace_string(replace_string(crypt(""+random(88)+11,""+random(88)+11),"/","XXX"),".","YYY"); + string randy = alpha_crypt(8); + + if(!arg) return "/open/"+time()+"_"+randy+".c"; + + if(objectp(arg) && this_player() && builderp(this_player())) + ret = homedir(this_player())+"/tmp/"+last_string_element(base_name(arg),"/")+randy+time()+".c"; + + else if(objectp(arg) && this_player()) + ret = "/tmp/"+last_string_element(base_name(arg),"/")+randy+time()+".c"; + + else if(stringp(arg) && this_player() && builderp(this_player())) { + if(file_exists(arg)) ret = homedir(this_player())+"/tmp/"+last_string_element(arg,"/")+randy+time()+".c"; + else ret = homedir(this_player())+"/tmp/"+randy+time()+".c"; + //ret = homedir(this_player())+"/tmp/"+last_string_element(arg,"/")+randy+time()+".c"; + } + + else if(stringp(arg) && file_exists(arg) && this_player()) { + if(objectp(load_object(arg))) ret = "/tmp/"+last_string_element(arg,"/")+randy+time()+".c"; + else ret = "/open/"+last_string_element(arg,"/")+randy+time()+".tmp"; + } + + else if(builderp(this_player())) ret = homedir(this_player())+"/tmp/"+randy+time()+".tmp"; + + else ret = "/open/"+randy+time()+".c"; + return ret; +} + +int alphap(mixed arg){ + if(!stringp(arg)) return 0; + foreach(int element in arg){ + if(!((element >= 65 && element <= 90) || + (element >= 97 && element <= 122))) return 0; + } + return 1; +} + +string alpha_strip(mixed arg){ + string raw, ret; + string *blown; + if(!arg || pointerp(arg)) return ""; + if(!sscanf(arg,"%s",raw)) return ""; + if(!sizeof(raw)) return ""; + blown = explode(raw,""); + ret = ""; + foreach(string element in blown){ + if(alphap(element)) ret += element; + } + return ret; +} + +int numericp(mixed arg){ + string *alphabet = ({"1", "2", "3", "4", "5", "6", "7", "8", "9", "0"}); + if(intp(arg)) arg = itoa(arg); + if(!stringp(arg)) return 0; + foreach(string element in alphabet){ + if(grepp(arg,element)) return 1; + } + return 0; +} + +int basic_punctuationp(mixed arg){ + string *alphabet = ({",", ".", "-", "_", "+", "#", ";", "^", "&", "(", ")" }); + alphabet += ({ "@", "!", "$", "%", "=", "{", "}", "[", "]", ":", "<", ">" }); + if(!stringp(arg)) return 0; + foreach(string element in alphabet){ + if(grepp(arg,element)) return 1; + } + return 0; +} + +int check_string_length(string str){ + if(sizeof(str) > __LARGEST_PRINTABLE_STRING__) return 0; + return 1; +} + +varargs string *chunk_string(string str, int width){ + string *ret =({}); + string tmp1 = ""; + string tmpfile = generate_tmp(); + if(!width) width = __LARGEST_PRINTABLE_STRING__ / 2; + while(sizeof(str)){ + write_file(tmpfile,str,1); + if(!(tmp1 = read_bytes(tmpfile, 0, width))) + tmp1 = read_file(tmpfile); + ret += ({ tmp1 }); + str = replace_string(str,tmp1,""); + } + rm(tmpfile); + return ret; +} + +varargs mixed print_long_string(object who, string str, int catted){ + string ret = ""; + string *lines; + string *tmp; + if(!str) return 0; + global_temp_file = generate_tmp(); + lines = explode(str,"\n"); + foreach(string line in lines){ + if(sizeof(line) > __LARGEST_PRINTABLE_STRING__ / 2) + line = implode(chunk_string(line,who->GetScreen()[0]),"\n"); + ret += line+"\n"; + } + write_file(global_temp_file,ret,1); + tmp = explode(ret,"\n"); + foreach(string thing in tmp){ + } + if(!catted){ + who->eventPage(explode(read_file(global_temp_file),"\n"),MSG_SYSTEM); + return unguarded( (: rm(global_temp_file) :) ); + } + else { + foreach(string thing in tmp){ + message("system", thing, who); + } + } + unguarded( (: rm(global_temp_file) :) ); + return 1; +} + +string convert_newline(string str){ + string ret = ""; + if(!str) return ret; + ret = replace_string(str,CARRIAGE_RETURN,"\n"); + return ret; +} + +int clean_newline_file(string str){ + string ret = ""; + if(!file_exists(str)) return 0; + else ret = convert_newline(read_file(str)); + if(ret != "") return write_file(str,ret,1); + else return 0; +} + +string morse(string msg) { + mapping morse = Morse; + string tmp; + int x, i; + msg = lower_case(msg); + for(tmp = "", x = strlen(msg), i=0; i< x; i++) { + if(morse[msg[i..i]]) tmp += morse[msg[i..i]]+" "; + else tmp += msg[i..i]+ " "; + } + return tmp; +} + +string unmorse(string msg) { + mapping morse = ([]); + string tmp = ""; + string *phrase = ({}); + int x, i; + foreach(mixed key, mixed val in Morse){ + morse[val] = key; + } + + phrase = explode(msg," "); + foreach(string element in phrase){ + string *word = explode(element," "); + foreach(string letter in word){ + if(member_array(letter, keys(morse)) != -1){ + tmp += morse[letter]; + } + } + tmp += " "; + } + return tmp; +} + +string unpinkfish(string str){ + if(!str) error("String required."); + str = replace_string(str,"\%\%\^\^","0^^0"); + str = replace_string(str,"\%\^","\%\%\^\^"); + str = replace_string(str,"0^^0","\%\%\^\^"); + return str; +} + +string repinkfish(string str){ + if(!str) error("String required."); + str = replace_string(str,"\%\%\^\^","\%\^"); + return str; +} + +string web_translate(string str){ + if(!str) error("String required"); + str = replace_string(str,"%2F","/"); + str = replace_string(str,"%2B","+"); + return str; +} + +string dbz_colors(string str, int annoying){ + string ret = ""; + string *colors = ({ "RED", "BLUE", "CYAN", "MAGENTA", "ORANGE", + "YELLOW", "GREEN", "WHITE%^%^B_BLACK", "BLACK%^%^B_WHITE" }); + string *b_colors = ({ "B_RED", "B_BLUE", "B_CYAN", "B_MAGENTA", "B_ORANGE", + "B_YELLOW", "B_GREEN" }); + + foreach(mixed element in str){ + int close; + if(random(2)) ret += "%^BOLD%^"; + if(annoying && !random(3) && element != 32){ + ret += "%^" + b_colors[random(sizeof(b_colors)-1)] + "%^"; + close = 1; + } + if(annoying > 1 && !random(5) && element != 32){ + ret += "%^FLASH%^"; + close = 1; + } + ret += "%^" + colors[random(sizeof(colors)-1)] + "%^"; + ret += convert_ascii(element); + if(close) ret += "%^RESET%^"; + } + return ret + "%^RESET%^"; +} + +int query_common_ascii(string str){ + mixed *check_arr = ({}); + mixed *ret_arr = ({}); + int i; + int lst = sizeof(str) - 1; + if(sizeof(str) == 1){ + check_arr = ({ str[0] }); + } + else { + for(i = 0; i < lst; i++){ + check_arr += ({ str[i] }); + } + } + foreach(mixed element in check_arr){ + if(intp(element)){ + if((element >31 && element < 127) + || element == 10 || element == 9 || + (element >160 && element < 256)){ + ret_arr += ({ element }); + } + } + } + if(sizeof(ret_arr) == sizeof(check_arr)) return 1; + return 0; +} + +string cleaned_name(string str){ + if(last(str, 2) == ".o") str = truncate(str, 2); + str = replace_string(str, "."+__PORT__, ""); + return str; +} + +string cleaned_end(string str){ + str = last_string_element(str, "/"); + str = cleaned_name(str); + return str; +} + +string *read_big_file(string str) { + string *arr, *ret = ({}); + mixed tmp; + string stub; + int bigth, ender, bmax = (__LARGEST_PRINTABLE_STRING__ - 1024); + int chunks, rem, currchunk, smax = (get_config(__MAX_STRING_LENGTH__) - 10); + + if( !str || !file_exists(str) ) return ret; + if((bigth = file_size(str)) < smax){ + tmp = read_file(str); + ret = explode(tmp,"\n"); + return ret; + } + chunks = bigth / bmax; + rem = bigth % bmax; + if(rem) chunks++; + while(chunks){ + chunks--; + if(chunks){ + tmp = read_bytes(str, currchunk, bmax); + currchunk += bmax; + } + if(rem && !chunks){ + tmp = read_bytes(str, currchunk, rem); + currchunk += rem; + } + if(tmp[<1..] == "\n") ender = 1; + else ender = 0; + arr = explode(tmp, "\n"); + if(sizeof(stub)) { + arr[0] = stub+arr[0]; + stub = ""; + } + if(ender){ + ret += arr; + } + else { + stub = arr[<1..][0]; + ret += arr[0..<2]; + } + + } + return ret; +} + diff --git a/lib/secure/sefun/tail.c b/lib/secure/sefun/tail.c new file mode 100644 index 0000000..3c5fba5 --- /dev/null +++ b/lib/secure/sefun/tail.c @@ -0,0 +1,17 @@ +int tail(string file) { + string str; + int diff; + + diff = file_size(file); + if (diff < 0) return 0; + + diff -= 1024; + if (diff < 0) diff = 0; + str = read_bytes(file, diff, 1024); + if (!str) return 0; + if (diff) str = str[strsrch(str, "\n")+1..]; + + write(str); + + return 1; +} diff --git a/lib/secure/sefun/this_agent.c b/lib/secure/sefun/this_agent.c new file mode 100644 index 0000000..46123e9 --- /dev/null +++ b/lib/secure/sefun/this_agent.c @@ -0,0 +1,19 @@ +/* /secure/sefun/this_agent.c + * from the Dead Souls Mud Library + * if 0 is the arg, returns the current agent, other wise + * sets a new agent and returns the old + * created by Descartes of Borg 951021 + */ + +private static object Agent; + +varargs object this_agent(mixed val) { + object old_agent; + + if( !val ) return Agent; + old_agent = Agent; + if( intp(val) ) Agent = 0; + else Agent = val; + return old_agent; +} + diff --git a/lib/secure/sefun/time.c b/lib/secure/sefun/time.c new file mode 100644 index 0000000..132f56a --- /dev/null +++ b/lib/secure/sefun/time.c @@ -0,0 +1,73 @@ +/* /secure/sefun/time.c + * from the Dead Souls LPC Library + * simuls reguarding MUD time + * created by Descartes of Borg 950514 + */ + +#include +#include + +#define MIN 60 +#define HOUR (60 * MIN) +#define DAY (24 * HOUR) +#define WEEK ( 7 * DAY) +#define YEAR ( 52 * WEEK) + + +int query_night() { return (SEASONS_D->GetTimeOfDay() == "night"); } + +string query_day_name(int x) { return SEASONS_D->GetDayName(x); } + +int query_date(int x) { return SEASONS_D->GetDay(x); } + +string query_month(int x) { return SEASONS_D->GetMonth(x); } + +int query_year(int x) { return SEASONS_D->GetYear(x); } + +int query_minutes(int x) { return SEASONS_D->GetMinutes(x); } + +string query_season(int x) { return SEASONS_D->GetSeason(x); } + +int query_hour(int x) { return SEASONS_D->GetHour(x); } + +function time_event(string tod, function f) { + if( !functionp(f) ) error("Bad argument 1 to time_event().\n"); + return SEASONS_D->AddTimeEvent(tod, f); +} + +varargs string time_elapsed(int arg1, int arg2){ + int tm, x; + string str; + if(arg2) arg1 = arg2 - arg1; + tm = arg1; + + str = ""; + if (x = (tm / YEAR)) { + str += x + "y "; + tm -= x * YEAR; + } + + 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%^."; + return str; +} + + diff --git a/lib/secure/sefun/timestamp.c b/lib/secure/sefun/timestamp.c new file mode 100644 index 0000000..1595e42 --- /dev/null +++ b/lib/secure/sefun/timestamp.c @@ -0,0 +1,23 @@ +#include +#include +#include + +string *zones_cfg = explode((read_file(CFG_TIMEZONES)|| ""), "\n"); + +varargs string timestamp(mixed tz){ + string rawtz; + int *t, offset; + + if(tz){ + tz = upper_case(tz); + if(member_array(tz, zones_cfg) == -1) tz = 0; + } + + if(!tz) rawtz = query_tz(); + else rawtz = tz; + if(!rawtz) rawtz = upper_case(localtime(time())[LT_ZONE]); + offset = TIME_D->GetOffset(rawtz); + offset += EXTRA_TIME_OFFSET; + t = localtime(time()+(offset*3600)); + return sprintf("%04d.%02d.%02d-%02d.%02d,%02d", t[LT_YEAR], (t[LT_MON])+1, t[LT_MDAY], t[LT_HOUR], t[LT_MIN], t[LT_SEC]); +} diff --git a/lib/secure/sefun/to_object.c b/lib/secure/sefun/to_object.c new file mode 100644 index 0000000..b4da735 --- /dev/null +++ b/lib/secure/sefun/to_object.c @@ -0,0 +1,123 @@ +/* /secure/sefun/to_object.c + * from the Dead Souls.4 Library + * recreated by Blitz@Dead Souls + * + * Purpose: Parse passed string argument and + * return a matching object pointer + * if one is found. + * + * Usage Examples: + * sword (1st sword in inv or env) + * sword@here (find sword in local env) + * sword#4 (find 4th sword) + * sword#2@foo (find 2nd sword on player foo) + * sword@bag#2@foo (find 1st sword in foo's 2nd bag) + * --------------- + * /path/filename (find or load filename) + * /path/file#999 (find unique cloned object) + * %foo (explicitly find player foo) + * $foo (explicitly find npc foo) + * @foo (return foo's environment) + * + * tokens: me, here, sefun + */ + +#include + +object to_object(mixed var) { + object env, ob, *obs; + string tmp, where; + int i, char; + + if( objectp(var) ) return var; + else if( !stringp(var) || !sizeof(var) ) return 0; + if( sscanf(var, "%s@%s", tmp, where) == 2 ) { + var = tmp; + if( !env = to_object(where) ) return 0; + if( !sizeof(var) ) return environment(env); + } + switch(var) { + case "here" : return environment(this_player()); + case "me" : return this_player(); + case "sefun" : return find_object(SEFUN); + } + if( sscanf(var, "%s#%d", tmp, i) == 2 ) { + if( ob = find_object(var) ) return ob; + else var = tmp; + } + else i = 1; + if( i < 1 ) return 0; + if( member_array(var[0], ({ '/', '$', '%', }) ) > -1 ) { + char = var[0]; + var = var[1..]; + } + switch( char ) { + case '/' : + if( var[<2..] != ".c" ) var += ".c"; + if( !file_exists(var) ) return 0; + return load_object(var); + break; + case '%' : + if( !(ob = find_player(var)) ) return 0; + else return ob; + break; + case '$' : + if( env ) { + obs = filter(all_inventory(env), + (: living($1) && !interactive($1) && $1->id($(var)) :)); + if( sizeof(obs) < i ) return 0; + else return obs[i - 1]; + } + if( (ob = find_living(var)) && !interactive(ob) ) return ob; + else return 0; + break; + default: + if( !env ) { + env = this_player(); + } + if( i > 1 ) { + obs = filter(all_inventory(env), (: $1->id($(var)) :)); + if( sizeof(obs) < i ) { + if( !env = environment(env) ) { + ob = 0; + } + else { + obs = filter(all_inventory(env), (: $1->id($(var)) :)); + if( sizeof(obs) < i ) { + ob = 0; + } + else { + ob = obs[i - 1]; + } + } + } + else { + ob = obs[i-1]; + } + if( ob ) { + return ob; + } + } + else { + ob = present(var, env); + if( ob ) return ob; + else if( env = environment(env) ) { + ob = present(var, env); + if( ob ) return ob; + } + if( ob = find_player(var) ) return ob; + if( ob = find_living(var) ) return ob; + if( !this_player() ) { + return 0; + } + var = absolute_path(this_player()->query_cwd(), var); + if(!file_exists(var)) var += ".c"; + if(!file_exists(var)) var = ""; + if( sizeof(var) && ob = load_object(var) ) { + return ob; + } + } + return 0; + } + return 0; +} diff --git a/lib/secure/sefun/translate.c b/lib/secure/sefun/translate.c new file mode 100644 index 0000000..c34da23 --- /dev/null +++ b/lib/secure/sefun/translate.c @@ -0,0 +1,98 @@ +// /adm/simul_efun/translate.c +// from the Dead Souls Mudlib +// translates a string into nonsense for non-proficient speakers +// created by Descartes of Borg 930823 +// based on a speak function by Valodin@Dead Souls + +#define FLUBS ({ "lacunae", "uns", "sur",\ + "HWAET","shaka","jalad", "darmok", "tanagra",\ + "scyld", "sweorda", "narthex", "luft", "mit", "folnar",\ + "temba", "temak", "le","la","nous","avec","mais","foutre",\ + "cyning", "thara", "stanas", "seo", "stanum", "res", "ipso","stana",\ + "meh", "nehi", "samastahum", "tora", "kia-ab", "boltehe", \ + "ata", "mevin", "ivrit", "ktzat", "lo", "ani", "tov","aval", \ + "verstehen", "sie", "bisschen", "sehr", "aber", "etwas", "keinen",\ + "shomo", "mifahmin", "mifahmam", "katalavenete", "hellenika",\ + "spreek", "uw", "vrauw", "nit", "shiz", "se","pericolo",\ + "iskit", "imhud", "halas", "sagud", "imche", "eigoga", "nihongo",\ + "wakarimaska", "wakarimasen", "samastihenh", "iye", "hai",\ + "ni", "huei", "shwa", "potong-hwa", "mah", "wa", "ideahr",\ + "khairei", "hoc", "propter", "auch", "vielen","lurgid",\ + "forshtor", "deuw", "noshk", "puedo", "pero", "debajo" , "atras",\ + "mientras", "desde", "nunca", "haka", "silflay", "embleer", "hraka",\ + "mbembe", "mau-mau","tiki","meka","leka","hai","haini","ho", \ + "chonny","mola","chala","hala","hei","thlon","mey","nikto",\ + "ecgum", "eyne", "sobre","dupa","zum","schlampe","jodio","con",\ + "narfle", "garthak", "hokanda-matuso","oota-goota","mafi","makka",\ + "shukran", "akbar", "mokele", "dapku", "loituma","plurdled",\ + "curiae", "aethelingas", "eorlas","carajo","oder",\ + "ae","aroha","awarua","atua","tenei", "dsfargeg",\ + "tangata","koa","kora","hupane","upane","krankor",\ + "baardaap","droogkloot","asbak","haka",\ + "zaadje","verkloten","teef","moffie","shele",\ + "anasi","atouche","ayir","boos","teezee","shawty",\ + "durka","haista","vittu","kyrpä","räkä","shawtay",\ + "suoro","voi","debil","kunel","shinel","sampo",\ + "sasikumea","zakila","txakurra","soustat","irrumator",\ + "mentula","koproskilo","malakas","la'a'za'zel","zayin",\ + "haakskeekah","noko","shizzle","nizzle","hizzle",\ + "desu","desu","desu","desu","desu","desu","a858de45f56d9bc9",\ + "desu","desu","desu","desu","desu","desu",\ + "desu","desu","desu","desu","desu","desu",\ + "UNITINU","STENDEC","CROATOAN","LATUALATUKA",\ + "LMKUU","puka","degozaimasu","szysznyk", "syzygy",\ + "darklock","confutatis","maledictis","flammis","acribus",\ + "addictis","XYNTA","durian","adzuki","flocka",\ + "ХУИТÐ", "NIBIRU", "tatonka","tralfamadore",\ + "sihulm","koyaanisqatsi","tanstaafl","misunderestimate",\ + "ar","ot","ti","fi","na", "markovian parallax denigrate",\ + "ar","ot","ti","fi","na",\ + "ar","ot","ti","fi","na",\ + "ar","ot","ti","fi","na",\ + "ar","ot","ti","fi","na",\ + "ar","ot","ti","fi","na",\ + "o","u","y","e",\ + "o","u","y","e",\ + "o","u","y","e",\ + "o","u","y","e",\ + "o","u","y","e",\ + "o","u","y","e",\ + "ki","ika","ita","ite","ni",\ + "ki","ika","ita","ite","ni",\ + "ip","ip","ip","ip","ip","ip",\ + "ip","ip","ip","ip","ip","ip",\ + "iq","iq","iq","iq","iq","iq",\ + "iq","iq","iq","iq","iq","iq",\ + "ig","ig","ig","ig","ig","ig",\ + "ig","ig","ig","ig","ig","ig",\ + "kii-oto","kii-oto","kii-oto","kii-oto","kii-oto",\ + "kii-ateh","kii-ateh","kii-ateh","kii-ateh","kii-ateh",\ + "galanga","wanga","ivlivs","kokoh-chula","birichoto",\ + "bukkakke","santorum","habeebit","yotsuba", "obama",\ + "mccain","biden","palin","chitonw","wachovia","wamu",\ + "dogoodi","idoogod","yamaglonchi","hotchka","tacgnol",\ + "zangano","zafacon","doushnou","yanaglonchi","rowsdower",\ + "gleepy","gloop","gloopy","neeby","nabba","nooby","la","la","la",\ + "lo","lo","sabba","sibby","sabba","nooby","abba","nabba",\ + "le","le","le","lo","lo","tooby","ooby","walla","dede","scozzafava",\ + "AUSCANZUKUS","nagua","covfefe","finna",\ +}) + +string translate(string str, int prof) { + if( prof >= 100 ) return str; + else { + string *words; + int fs, i, maxi; + + fs = sizeof(FLUBS); + words = explode(str, " "); + for(i=0, maxi = sizeof(words); i < maxi; i++){ + string prefix = ""; + string suffix = ""; + if(!alphap(first(words[i],1))) prefix = first(words[i],1); + if(!alphap(last(words[i],1))) suffix = last(words[i],1); + if( random(100) >= prof ) words[i] = prefix+FLUBS[random(fs)]+suffix; + } + return implode(words, " "); + } +} diff --git a/lib/secure/sefun/users.c b/lib/secure/sefun/users.c new file mode 100644 index 0000000..4a17261 --- /dev/null +++ b/lib/secure/sefun/users.c @@ -0,0 +1,35 @@ +#include + +int user_exists(string str){ + return master()->player_exists(str); +} + +varargs string user_path(string name, int legacy){ + return PLAYERS_D->GetUserPath(name, legacy); +} + +string *remote_users(){ + mixed *insts = INSTANCES_D->GetInstances(); + mixed tmp, *ret = ({}); + foreach(mixed inst in insts){ + if(inst) tmp = INSTANCES_D->GetRemoteUsers(inst); + if(sizeof(tmp)){ + if(!arrayp(tmp)) ret += ({ tmp }); + else ret += tmp; + } + } + return ret; +} + +string *local_users(){ + string *ret; + ret = map(filter(users(),(: (environment($1) && !($1->GetInvis())) :)), + (: $1->GetKeyName():)); + return ret; +} + +object *players(){ + object *ret; + ret = filter(users(), (: !creatorp($1) :)); + return ret; +} diff --git a/lib/secure/sefun/values.c b/lib/secure/sefun/values.c new file mode 100644 index 0000000..d0f7a0c --- /dev/null +++ b/lib/secure/sefun/values.c @@ -0,0 +1,31 @@ +/* /secure/sefun/value.c + * from the Dead Souls LPC Library + * data conversion simuls + * created by Descartes of Borg 950509 + */ + +#include "sefun.h" + +mixed convert_value(string val) { + return 1; +} + +int round(string f){ + int frac,num; + string str; + if(strsrch(f,".") == -1) { + if(!sscanf(f,"%d",num)) return 0; + else return num; + } + + if(sscanf(f,"%d.%s",num,str) < 2) sscanf(f,".%s",str); + + if(!str || str == "") return -1; + + if(!sscanf(str[0],"%d",frac)) return -2; + + if(frac > 4) num++; + else num--; + return num; +} + diff --git a/lib/secure/sefun/visible.c b/lib/secure/sefun/visible.c new file mode 100644 index 0000000..8e5068b --- /dev/null +++ b/lib/secure/sefun/visible.c @@ -0,0 +1,5 @@ +varargs int visible( object detectee_obj, object detector_obj ) { + return 0; + /* this function is not quite working without uid's + */ +} diff --git a/lib/secure/sefun/wild_card.c b/lib/secure/sefun/wild_card.c new file mode 100644 index 0000000..bbd9733 --- /dev/null +++ b/lib/secure/sefun/wild_card.c @@ -0,0 +1,27 @@ +string *wild_card(string str) { + mixed pf; + string *tmp, cwd; + int i, maxi; + if((cwd = absolute_path(this_player()->query_cwd(), str)) == "/") + return ({ "/" }); + if(cwd[sizeof(cwd) - 1] == '/') cwd = cwd[0..sizeof(cwd) - 2]; + if((string)(pf = path_file(cwd)) == "/") pf[0] = ""; + if(!(tmp = get_dir(cwd))) tmp = ({}); + tmp -= ({ "." }); + tmp -= ({ ".." }); + if(!str || str[0] != '.') + tmp = filter(tmp, "remove_dots", this_object()); + for(i=0, maxi = sizeof(tmp); i < maxi; i++) { + if(file_size(sprintf("%s/%s", pf[0], pf[1])) == -2) tmp[i] = pf[0]; + else tmp[i] = sprintf("%s/%s", pf[0], tmp[i]); + if(strlen(tmp[i]) > 1 && tmp[i][0..1] == "//") + tmp[i] = tmp[i][1..strlen(tmp[i])-1]; + } + return tmp; +} + +nomask int remove_dots(string str){ + return !(str[0] == '.'); +} + + diff --git a/lib/secure/sefun/wipe_inv.c b/lib/secure/sefun/wipe_inv.c new file mode 100644 index 0000000..943bbb1 --- /dev/null +++ b/lib/secure/sefun/wipe_inv.c @@ -0,0 +1,27 @@ +#include +#include + +int wipe_inv(mixed dude){ + string nom, str, orig_file, bak_file, contents; + + if(objectp(dude) && !nom = dude->GetKeyName()) return 0; + if(stringp(dude) && !nom = lower_case(dude)) return -1; + if(!nom || !sizeof(nom)) return -2; + if(!user_exists(nom)) return -3; + + str = DIR_PLAYERS "/" + nom[0..0] + "/" + nom; + if( !str || !file_exists(player_save_file(str)) ) + str = DIR_CRES "/" + nom[0..0] + "/" + nom; + + orig_file = player_save_file(str); + bak_file = player_save_file(str + "_rescue"); + + contents = read_file(orig_file); + if(!contents) return 0; + cp(orig_file, bak_file); + contents = replace_string(contents,"\n",";\n"); + contents = remove_matching_line(contents, "Inventory"); + contents = replace_string(contents, ";\n", "\n"); + write_file(orig_file, contents,1); + return 1; +} diff --git a/lib/secure/tmp/dirs.txt b/lib/secure/tmp/dirs.txt new file mode 100644 index 0000000..6e619be --- /dev/null +++ b/lib/secure/tmp/dirs.txt @@ -0,0 +1,306 @@ +/domains/default/creator +/domains/default/armor +/doc/efun/mixed +/domains/default +/doc/efun/parsing +/domains/campus/weap +/domains/campus/txt/jenny +/lib/events +/doc/efun/calls +/doc/efun/buffers +/domains/campus/txt/ai/charly/bak +/doc/help/avatars +/domains/campus/txt/ai/charly +/obj +/doc/lfun/lib/clean +/domains/campus/txt/ai/charles/bak2/bak1 +/domains/campus/txt/ai/charles/bak2 +/doc/efun/arrays +/domains/campus/txt/ai/charles +/daemon/include +/domains/campus/txt/ai +/domains/campus/txt +/doc/lfun/lib/clerk +/domains/campus/save +/www/logs +/news +/domains/campus/room +/domains/campus/obj +/domains/campus/npc +/domains/campus/meals +/domains/campus/etc +/doc/help/law +/domains/campus/doors +/domains/campus/armor +/domains/campus/adm +/domains/campus +/doc/guide +/domains/Ylsrim/weapon +/spells +/domains/Ylsrim/virtual/desert +/doc/efun/functions +/domains/Ylsrim/virtual +/domains/Ylsrim/save +/lib +/domains/Ylsrim/room +/open +/domains/Ylsrim/obj +/domains/Ylsrim/npc +/domains/Ylsrim/meal +/domains/Ylsrim/fish +/doc/lfun/lib +/domains/Ylsrim/etc +/domains/Ylsrim/broken +/domains/Ylsrim/armor +/domains/Ylsrim/adm +/domains/Praxis/quests +/doc/lfun +/domains/Praxis/orc_valley +/doc/lfun/lib/clan +/doc/build +/doc/efun/strings +/doc/efun/filesystem +/www/lpmuds +/log/watch +/secure/cmds/creators +/doc/applies/parsing +/doc/lpc +/doc/lfun/lib/file +/doc/applies/interactive +/doc/faq +/www/images +/doc/lfun/lib/chat +/www/lpmuds/links_files +/www/lpmuds/intermud_files +/cmds/admins +/secure/cmds/admins +/www/lpmuds/downloads_files +/www/ds-inst-faq_files +/www/ds-creator-faq_files +/daemon/tmp +/www/articles +/verbs/undead +/verbs/spells +/verbs/rooms/include +/doc/hbook +/verbs/rooms +/verbs/players/include/SCCS +/verbs/players/include +/www/doc +/verbs/players +/verbs/items/include +/verbs/items +/verbs/creators/include +/verbs/creators +/doc/help/races +/cmds/creators/include/SCCS +/verbs/common/include +/verbs/common +/verbs/admins/include +/verbs/admins +/doc/lfun/lib/body +/secure/verbs/creators +/doc/lfun/lib/bonus +/secure/verbs +/secure/sefun +/doc/lfun/lib/equip +/doc/lfun/all +/secure/scripts +/secure/room +/doc/help/players +/secure/obj/include +/secure/modules +/secure/lib/std +/doc/efun/system +/cmds/creators/include +/secure/lib/net/include +/lib/std +/secure/lib/net +/doc/help/creators +/secure/lib/include +/secure/include +/secure/npc +/secure/daemon/include +/secure/daemon/i3router +/doc/efun/numbers +/secure/daemon +/doc/efun/floats +/doc/applies/master +/secure/cmds/players/include +/secure/cmds/creators/include +/doc/efun/all +/secure/cmds +/doc/lfun/lib/bot +/secure/cfg/races +/doc/lfun/lib/door +/secure/cfg/classes +/save/kills/o +/doc/efun/objects +/obj/include +/obj/book_source +/doc/lfun/lib/limb +/doc/efun/general +/log/reports +/doc/lfun/lib/light +/log/law/sites-watch +/doc/lfun/lib/leader +/doc/efun/compile +/log/law/sites-tempban +/doc/lfun/lib/lamp +/std/lib +/log/law/sites-register +/doc/lfun/lib/interactive +/doc/applies +/log/law/sites-misc +/doc/lfun/lib/id +/log/law/names +/doc/lfun/lib/genetics +/log/law/email +/doc/lfun/lib/fuel +/log/law/adm +/doc/lfun/lib/ftp_data_connection +/log/archive +/log/adm/archive +/doc/lfun/lib/ftp_client +/ftp +/lib/virtual +/doc/lfun/lib/follow +/lib/include +/doc/lfun/lib/flashlight +/domains/town/weap +/doc/lfun/lib/fish +/domains/town/virtual/forest +/doc/lfun/lib/donate +/shadows +/log/adm +/domains/town/virtual +/doc/help +/doc/lfun/lib/deterioration +/domains/town/txt/shame +/doc/lfun/lib/damage +/tmp +/domains/town/txt +/log/secure +/lib/comp +/doc/lfun/lib/daemon +/secure/obj +/log +/domains/town/room +/doc/lfun/lib/creator +/cmds +/domains/town/obj +/secure +/doc +/domains/town/npc +/doc/lfun/lib/corpse +/domains/town/meals +/doc/lfun/lib/connect +/secure/cmds/players +/domains/town/doors +/doc/lfun/lib/combat +/domains/town/armor +/doc/lfun/lib/client +/domains/town +/domains/examples/room +/doc/lfun/lib/classes +/cmds/players +/doc/lfun/lib/chapel +/domains/default/weap +/daemon +/save/kills +/domains/default/virtual/sky +/domains/default/virtual/arena +/domains/default/virtual +/domains/default/vehicles +/domains/default/room +/daemon/services +/domains/default/obj +/www/errors +/std +/domains/default/npc/quarantine +/verbs +/domains/default/npc +/log/router +/domains +/doc/tmp +/doc/lfun/lib/clay +/lib/props +/log/errors +/doc/help/religion +/doc/efun/mappings +/secure/lib +/doc/old +/lib/user +/doc/manual +/domains/Ylsrim +/domains/Praxis/obj/weapon +/domains/Praxis/obj/mon +/www +/domains/Praxis/obj/misc +/log/law +/domains/Praxis/obj/magic +/domains/Praxis/obj/armour +/domains/Praxis/obj +/cmds/hm +/domains/Praxis/mountains +/domains/Praxis/death +/log/open +/domains/Praxis/data +/domains/Praxis/cemetery/mon +/cmds/creators +/doc/sefun +/doc/efun/mudlib +/domains/Praxis/cemetery +/domains/Praxis/attic +/domains/Praxis/adm +/save +/domains/Praxis +/doc/lpc/types +/doc/lpc/intermediate +/doc/lfun/lib/armor +/std/board +/doc/lpc/etc +/doc/lfun/lib/battery +/doc/lpc/constructs +/doc/lfun/lib/abilities +/doc/lpc/concepts +/doc/lpc/basic +/doc/efun/interactive +/doc/lpc/advanced +/doc/lfun/lib/worn_storage +/doc/lfun/lib/weapon +/doc/lfun/lib/virt_sky +/doc/lfun/lib/vendor +/doc/lfun/lib/torch +/doc/lfun/lib/spell +/doc/lfun/lib/server +/doc/lfun/lib/room +/cfg +/doc/lfun/lib/race +/doc/lfun/lib/potion +/doc/lfun/lib/burn +/doc/lfun/lib/position +/doc/lfun/lib/poison +/doc/lfun/lib/player +/secure/cmds/common +/log/chan +/doc/lfun/lib/npc +/doc/lfun/lib/messages +/doc/lfun/lib/meal +/cmds/common +/doc/lfun/lib/manipulate +/secure/cfg +/doc/lfun/lib/look +/doc/efun/sockets +/doc/lfun/lib/living +/doc/help/classes +/doc/efun +/doc/misc +/lib/lvs +/domains/examples +/include +/doc/efun/internals +/secure/tmp +/domains/default/etc +/domains/default/doors +/doc/help/hm diff --git a/lib/secure/tmp/files.txt b/lib/secure/tmp/files.txt new file mode 100644 index 0000000..1db3f09 --- /dev/null +++ b/lib/secure/tmp/files.txt @@ -0,0 +1,4164 @@ +/doc/lfun/all/GetDrainRate +/doc/lfun/all/GetDeathEvents +/doc/lfun/all/GetClass +/doc/lfun/all/GetClanSkill +/doc/lfun/all/GetClanObject +/doc/lfun/all/GetClanName +/doc/lfun/all/GetClan +/secure/cfg/aliases.cfg +/doc/lfun/all/GetCharge +/doc/lfun/all/GetChannels +/doc/lfun/all/GetCellType +/doc/lfun/all/GetCapName +/doc/lfun/all/GetCanBite +/doc/lfun/all/GetCaffeine +/doc/lfun/all/GetBurntValue +/std/room.c +/doc/lfun/all/GetBurning +/doc/lfun/all/GetBurnRate +/doc/lfun/all/GetBonusDuration +/doc/lfun/all/GetBodyComposition +/doc/lfun/all/GetBaseStatLevel +/doc/lfun/all/GetAllowSacrifice +/doc/lfun/all/GetAlcohol +/doc/lfun/all/GetAffectLong +/doc/lfun/all/DestLimb +/doc/lfun/all/ClassMember +/doc/lfun/all/ChangeClass +/doc/lfun/all/CanWear +/doc/lfun/all/CanSacrifice +/doc/efun/all/shout +/doc/lfun/all/CanRemoveItem +/doc/lfun/all/CanMarry +/doc/lfun/all/CanManipulate +/doc/lfun/all/CanLight +/doc/lfun/all/CanJoin +/doc/lfun/all/CanFly +/doc/lfun/all/CanExtinguish +/doc/lfun/all/CanBurn +/doc/lfun/all/AddSkillPoints +/doc/lfun/all/AddSacrificeType +/doc/lfun/all/AddQuestPoints +/doc/lfun/all/AddPoison +/doc/lfun/all/AddMoJo +/doc/lfun/all/AddMagicProtection +/doc/lfun/all/AddMagicPoints +/doc/lfun/all/AddLimb +/doc/lfun/all/AddLead +/doc/lfun/all/AddHeartModifier +/doc/lfun/all/AddHealthPoints +/doc/lfun/all/AddHP +/doc/lfun/all/AddFood +/doc/lfun/all/AddFingers +/lib/events/drop.c +/lib/events/shoot.c +/doc/lfun/all/AddExtraChannels +/secure/daemon/players.c +/doc/lfun/all/AddExperiencePoints +/lib/props/carry.c +/doc/lfun/all/AddDrink +/secure/lib/net/telnet_client.c +/doc/lfun/all/AddChannel +/secure/sefun/values.c +/doc/lfun/all/AddCaffeine +/verbs/rooms/stop.c +/doc/lfun/all/AddAlcohol +/secure/sefun/compare_array.c +/doc/lfun/README +/doc/help/races/orc +/doc/help/players/vendors +/doc/help/players/unalias +/doc/help/players/points +/doc/help/players/player_general +/doc/help/players/password +/doc/help/players/nickname +/doc/help/players/list +/doc/help/players/languages +/doc/help/players/handbook +/doc/help/players/credits +/secure/room/network.c +/doc/help/players/communication +/doc/help/players/classes +/doc/help/players/chat +/doc/help/players/channels +/doc/help/players/channel +/doc/help/players/banking +/doc/help/players/alias +/doc/help/creators/staff +/doc/help/creators/shadows +/doc/help/creators/security +/doc/help/creators/qcs +/log/archive/imc2.log-2007.12.29-15.46 +/doc/efun/all/catch +/doc/help/creators/profile +/log/archive/imc2.log-2007.12.29-12.46 +/doc/help/creators/plan +/doc/help/creators/messaging +/log/archive/imc2.log-2007.12.29-08.46 +/doc/help/creators/mappings +/log/archive/imc2.log-2007.12.29-03.46 +/doc/help/creators/force +/log/archive/imc2.log-2007.12.28-23.46 +/doc/help/creators/emotes +/doc/help/creators/editor +/log/archive/imc2.log-2007.12.28-20.46 +/daemon/stargate.c +/doc/help/creators/ds +/log/archive/imc2.log-2007.12.28-16.46 +/doc/help/creators/debugging +/cmds/creators/man.c +/log/archive/imc2.log-2007.12.28-12.46 +/doc/help/creators/debug_macro +/log/archive/imc2.log-2007.12.28-08.46 +/doc/help/creators/debug_hints +/log/archive/imc2.log-2007.12.28-05.46 +/doc/help/creators/creator_general +/doc/help/creators/creation +/log/archive/imc2.log-2007.12.28-01.46 +/doc/help/creators/config +/log/archive/imc2.log-2007.12.27-22.46 +/doc/help/creators/admin +/doc/help/creators/addemote_help +/log/archive/imc2.log-2007.12.27-19.46 +/doc/help/classes/thief +/log/archive/imc2.log-2007.12.27-16.45 +/doc/help/classes/mage +/log/adm/file +/log/adm/eval +/doc/help/classes/cleric +/log/adm/call +/doc/hbook/chapter07 +/doc/hbook/chapter06 +/log/adm/archive/file-2008.01.06-15.48 +/lib/virtual/virt_std.c +/doc/hbook/chapter05 +/verbs/common/yell.c +/log/adm/archive/file-2008.01.06-12.47 +/doc/hbook/chapter04 +/lib/props/radiance.c +/log/adm/archive/file-2008.01.06-11.47 +/lib/events/disarm.c +/verbs/players/wake.c +/log/adm/archive/file-2008.01.06-03.47 +/lib/std/lockpick.c +/log/adm/archive/file-2008.01.05-19.47 +/lib/fishing.c +/lib/events/crawl.c +/log/adm/archive/file-2008.01.05-11.47 +/log/adm/archive/file-2008.01.05-03.47 +/log/adm/archive/file-2008.01.03-14.46 +/log/adm/archive/file-2007.12.28-15.46 +/lib/props/cost.txt +/lib/include/weapon.h +/lib/include/virtual.h +/lib/include/verb.h +/lib/include/vendor.h +/lib/include/trap.h +/lib/include/trainer.h +/lib/include/touch.h +/lib/include/torch.h +/lib/include/teller.h +/lib/include/teacher.h +/lib/include/talk.h +/lib/include/storage.h +/lib/include/steal.h +/cmds/creators/rehash.c +/lib/include/stargate.h +/lib/include/smell.h +/lib/include/shell.h +/cmds/creators/lightme.c +/lib/include/search.h +/lib/include/scroll.h +/lib/include/round.h +/lib/include/room.h +/lib/include/read.h +/lib/include/race.h +/lib/include/put.h +/lib/include/press.h +/lib/include/post_office.h +/lib/include/pole.h +/lib/include/poison.h +/lib/include/player.h +/lib/include/pistol.h +/lib/include/pile.h +/lib/include/persist.h +/lib/include/pager.h +/lib/pole.c +/lib/include/npc.h +/lib/include/nmsh.h +/secure/sefun/get_verbs.c +/verbs/items/look.c +/lib/include/money.h +/lib/include/messages.h +/lib/comp/weapon.c +/verbs/creators/resurrect.c +/lib/include/meal.h +/verbs/items/read.c +/lib/include/match.h +/lib/props/deterioration.c +/lib/include/lock.h +/verbs/items/judge.c +/lib/include/living.h +/lib/events/wield.c +/lib/include/listen.h +/lib/include/limb.h +/lib/include/light.h +/lib/include/leader.h +/lib/include/lead.h +/lib/include/lamp.h +/lib/include/key.h +/lib/include/jump.h +/lib/include/items.h +/lib/include/item.h +/lib/include/interface.h +/lib/include/interactive.h +/lib/include/holder.h +/lib/include/history.h +/lib/include/help.h +/lib/include/get.h +/lib/include/genetics.h +/lib/include/fuel.h +/lib/include/follow.h +/lib/include/fishing.h +/lib/include/fish.h +/lib/include/files.h +/lib/include/exits.h +/lib/include/editor.h +/lib/include/drop.h +/lib/include/door.h +/lib/include/donate.h +/lib/include/digging.h +/lib/include/detect.h +/lib/include/currency.h +/lib/include/creator.h +/lib/include/corpse.h +/lib/include/container.h +/lib/include/command.h +/lib/include/combatmsg.h +/lib/include/close.h +/lib/include/clip.h +/lib/include/client.h +/cmds/players/who.c +/lib/include/classes.h +/lib/include/clan.h +/lib/include/chat.h +/lib/include/chapel.h +/lib/include/carry.h +/lib/include/burn.h +/lib/include/body.h +/lib/include/bboard.h +/lib/include/barkeep.h +/lib/include/bank.h +/lib/include/bait.h +/lib/include/autosave.h +/lib/include/armor.h +/lib/include/abilities.h +/lib/std/armor.c +/lib/comp/surface.c +/lib/props/id.c +/lib/events/bait_with.c +/secure/lib/net/oob.c +/secure/cfg/write.cfg +/std/pod.c +/lib/die.c +/verbs/players/describe.c +/verbs/players/vote.c +/daemon/command.c +/secure/sefun/user_path.c +/secure/sefun/get_livings.c +/lib/meal.c +/secure/sefun/wipe_inv.c +/cmds/creators/clean.c +/cmds/creators/classblock.c +/lib/events/wear.c +/lib/teacher.c +/lib/props/addstuff.c +/secure/sefun/economy.c +/lib/virtual/virtual.c +/lib/events/roll.c +/lib/std/germ.c +/verbs/items/wear.c +/lib/shadow.c +/cmds/creators/elog.c +/include/vision.h +/include/talk_type.h +/lib/events/lie.c +/include/stargate.h +/lib/torch.c +/include/soul.h +/secure/sefun/interface.c +/include/rounds.h +/lib/comp/seal.c +/include/race.h +/include/motion.h +/secure/sefun/duplicates.c +/include/message_class.h +/secure/sefun/identify.c +/include/medium.h +/secure/sefun/morality.c +/include/materials.h +/lib/std/bed.c +/include/marriage.h +/doc/efun/all/error +/cmds/creators/invis.c +/include/magic_protection.h +/include/magic.h +/include/jump.h +/include/graphics.h +/doc/efun/all/ed +/cmds/creators/mstatus.c +/include/gossip.h +/include/combat_messages.h +/doc/efun/all/log +/include/climb.h +/include/build_types.h +/include/boobytraps.h +/include/assessment.h +/domains/town/weap/verysharpsword.c +/domains/town/weap/sword.c +/domains/town/weap/staff.c +/domains/town/weap/shotput.c +/secure/sefun/load_object.c +/domains/town/weap/sharpsword.c +/verbs/items/unwield.c +/domains/town/weap/runic_sword.c +/cmds/creators/notices.c +/secure/lib/net/remote.c +/domains/town/weap/rod.c +/verbs/players/crawl.c +/domains/town/weap/paring_knife.c +/secure/sefun/parse_objects.c +/lib/undead.c +/domains/town/weap/orcslayer.c +/secure/sefun/security.c +/domains/town/weap/leostaff.c +/lib/events/drink.c +/domains/town/weap/knife.c +/lib/fuel.c +/lib/body.c +/domains/town/weap/gstaff.c +/verbs/players/befriend.c +/verbs/items/free.c +/verbs/creators/delete.c +/domains/town/weap/fellsword.c +/lib/events/lock.c +/verbs/items/ring.c +/domains/town/weap/dagger.c +/secure/sefun/convert_name.c +/lib/props/uniqueness.c +/domains/town/weap/cue.c +/secure/lib/file.c +/lib/std/worn_storage.c +/lib/donate.c +/domains/town/weap/carving_knife.c +/lib/events/sit.c +/domains/town/weap/butcher_knife.c +/verbs/items/drop.c +/domains/town/weap/brush.c +/lib/props/ambiance.c +/secure/sefun/timestamp.c +/domains/town/weap/boobytrap_dagger.c +/verbs/players/evade.c +/domains/town/weap/board.c +/lib/steal.c +/domains/town/weap/axe.c +/secure/sefun/absolute_value.c +/domains/town/weap/9mmpistol_mp.c +/lib/shell.c +/domains/town/weap/9mil.c +/verbs/players/lie.c +/domains/town/weap/357pistol.c +/daemon/verbs.c +/lib/virtual/virt_sky.c +/domains/town/virtual/server.c +/verbs/items/consult.c +/domains/town/virtual/forest_map +/lib/mayor.c +/domains/town/virtual/forest.c +/spells/buffer.c +/spells/missile.c +/domains/town/txt/ylsrim_sign.txt +/verbs/players/withdraw.c +/verbs/players/drive.c +/domains/town/txt/warning_sign.txt +/lib/sentient.c +/lib/props/equip.c +/verbs/items/bury.c +/lib/flashlight.c +/domains/town/txt/spam.txt +/lib/chapel.c +/secure/sefun/time.c +/domains/town/txt/shame/chapter05 +/lib/events/give.c +/domains/town/txt/shame/chapter04 +/doc/efun/all/rm +/domains/town/txt/shame/chapter03 +/domains/town/txt/shame/chapter02 +/domains/town/txt/shame/chapter01 +/domains/town/txt/quests.txt +/domains/town/txt/praxis_sign.txt +/domains/town/txt/pot.txt +/domains/town/txt/map.txt +/domains/town/txt/hints_sign.txt +/obj/book.c +/domains/town/txt/advancement.txt +/domains/town/room/well3.c +/domains/town/room/well2.c +/domains/town/room/well1.c +/verbs/items/boobytrap.c +/domains/town/room/voters.c +/verbs/items/remove.c +/domains/town/room/void.c +/secure/sefun/messaging.c +/lib/interface.c +/domains/town/room/vill_road4.c +/domains/town/room/vill_road3.c +/domains/town/room/vill_road2.c +/domains/town/room/vill_road1.c +/domains/town/room/valley.c +/doc/hbook/chapter03 +/domains/town/room/training.c +/doc/hbook/chapter02 +/domains/town/room/thall.c +/doc/hbook/chapter01 +/domains/town/room/tavern.c +/doc/guide/chapter09 +/lib/shop.c +/domains/town/room/stables.c +/doc/guide/chapter08 +/domains/town/room/south_road2.c +/doc/guide/chapter07 +/verbs/items/open.c +/domains/town/room/south_road1.c +/doc/guide/chapter06 +/verbs/players/learn.c +/domains/town/room/shower.c +/doc/guide/chapter05 +/lib/detect.c +/domains/town/room/shore.c +/doc/guide/chapter04 +/verbs/players/stealth.c +/domains/town/room/shop2.c +/doc/guide/chapter03 +/verbs/items/roll.c +/domains/town/room/shop.c +/doc/guide/chapter02 +/verbs/common/body.c +/domains/town/room/shack.c +/doc/guide/chapter01 +/spells/fireball.c +/domains/town/room/school.c +/doc/efun/system/variables +/domains/town/room/room2.c +/doc/efun/system/uptime +/domains/town/room/room.c +/doc/efun/system/time +/domains/town/room/road2.c +/doc/efun/system/shutdown +/domains/town/room/road1.c +/doc/efun/system/shallow_inherit_list +/domains/town/room/road.c +/doc/efun/all/refs +/doc/efun/system/set_reset +/domains/town/room/riverbank.c +/lib/pile.c +/doc/efun/system/set_eval_limit +/domains/town/room/postoffice.c +/secure/sefun/rooms.c +/doc/efun/system/reset_eval_cost +/lib/teach.c +/domains/town/room/porch.c +/doc/efun/system/replaceable +/lib/std/bot_limb.c +/domains/town/room/orc_temple.c +/lib/messages.c +/doc/efun/system/replace_program +/domains/town/room/orc_fortress.c +/doc/efun/system/reclaim_objects +/secure/sefun/absolute_path.c +/domains/town/room/narrow_path2.c +/doc/efun/system/program_info +/doc/efun/interactive/query_ip_number +/lib/bot.c +/domains/town/room/narrow_path.c +/doc/efun/system/named_livings +/doc/efun/interactive/query_ip_name +/domains/town/room/mountain_road.c +/lib/help.c +/doc/efun/system/memory_summary +/doc/efun/interactive/query_idle +/domains/town/room/mayor.c +/doc/efun/system/max_eval_cost +/doc/efun/interactive/query_host_name +/domains/town/room/mansion_uhall3.c +/doc/efun/system/lpc_info +/doc/efun/interactive/query_ed_mode +/lib/race.c +/domains/town/room/mansion_uhall2.c +/doc/efun/system/localtime +/doc/efun/interactive/printf +/domains/town/room/mansion_uhall1.c +/doc/efun/system/inherits +/doc/efun/interactive/notify_fail +/lib/clay.c +/domains/town/room/mansion_room9.c +/doc/efun/system/inherit_list +/doc/efun/interactive/message +/domains/town/room/mansion_room8.c +/doc/efun/system/index +/doc/efun/interactive/interactive +/domains/town/room/mansion_room7.c +/doc/efun/system/functions +/doc/efun/interactive/input_to +/domains/town/room/mansion_room6.c +/doc/efun/system/function_profile +/doc/efun/interactive/index +/domains/town/room/mansion_room5.c +/doc/efun/system/function_exists +/doc/efun/interactive/in_input +/domains/town/room/mansion_room4.c +/doc/efun/system/flush_messages +/doc/efun/interactive/in_edit +/domains/town/room/mansion_room3.c +/doc/efun/system/find_call_out +/doc/efun/interactive/get_char +/domains/town/room/mansion_room2.c +/doc/efun/system/external_start +/doc/efun/system/eval_cost +/doc/efun/interactive/find_player +/domains/town/room/mansion_room12.c +/doc/efun/interactive/exec +/doc/efun/system/error +/domains/town/room/mansion_room11.c +/doc/efun/interactive/enable_wizard +/doc/efun/system/deep_inherit_list +/domains/town/room/mansion_room10.c +/doc/efun/system/debug_message +/doc/efun/interactive/enable_commands +/domains/town/room/mansion_room1.c +/doc/efun/system/ctime +/doc/efun/interactive/ed_start +/domains/town/room/mansion_mbdroom.c +/doc/efun/system/check_memory +/doc/efun/interactive/ed_cmd +/domains/town/room/mansion_int.c +/doc/efun/system/call_out_info +/doc/efun/interactive/ed +/domains/town/room/mansion_ext.c +/doc/efun/system/all_previous_objects +/doc/efun/interactive/disable_wizard +/domains/town/room/mansion_dhall3.c +/doc/efun/strings/upper_case +/doc/efun/interactive/disable_commands +/domains/town/room/mansion_dhall2.c +/doc/efun/strings/test_bit +/doc/efun/interactive/commands +/domains/town/room/magic_shop2.c +/doc/efun/strings/terminal_colour +/doc/efun/interactive/command +/domains/town/room/magic_shop.c +/doc/efun/strings/strsrch +/doc/efun/interactive/add_action +/doc/efun/strings/strlen +/domains/town/room/magic_guild.c +/doc/efun/general/typeof +/doc/efun/strings/strcmp +/domains/town/room/living_room.c +/doc/efun/strings/sscanf +/doc/efun/general/store_variable +/domains/town/room/healer2.c +/doc/efun/general/sizeof +/doc/efun/strings/sprintf +/domains/town/room/healer.c +/doc/efun/strings/set_bit +/doc/efun/general/save_variable +/lib/events/shake.c +/domains/town/room/gate.c +/doc/efun/strings/replace_string +/doc/efun/general/restore_variable +/lib/events/fall.c +/domains/town/room/garden.c +/lib/events/turn.c +/doc/efun/strings/repeat_string +/doc/efun/general/map +/domains/town/room/furnace.c +/doc/efun/general/index +/doc/efun/strings/regexp +/domains/town/room/freezer.c +/doc/efun/strings/reg_assoc +/doc/efun/general/filter +/domains/town/room/forest_path1.c +/doc/efun/strings/pluralize +/doc/efun/general/fetch_variable +/domains/town/room/elevator.c +/doc/efun/strings/next_bit +/doc/efun/general/copy +/domains/town/room/death.c +/doc/efun/strings/lower_case +/doc/efun/functions/index +/domains/town/room/cratshack.c +/doc/efun/strings/index +/doc/efun/functions/function_owner +/doc/efun/strings/implode +/domains/town/room/confroom.c +/doc/efun/functions/evaluate +/domains/town/room/clerk.c +/doc/efun/strings/explode +/doc/efun/functions/bind +/doc/efun/strings/crypt +/domains/town/room/clearing.c +/doc/efun/floats/to_int +/doc/efun/strings/clear_bit +/doc/efun/floats/tan +/domains/town/room/church.c +/doc/efun/strings/capitalize +/doc/efun/floats/sqrt +/domains/town/room/chamber.c +/doc/efun/floats/sin +/doc/efun/sockets/socket_write +/domains/town/room/cave_entrance.c +/doc/efun/floats/pow +/domains/town/room/cave1.c +/doc/efun/sockets/socket_release +/doc/efun/floats/log +/domains/town/room/bridge.c +/doc/efun/sockets/socket_listen +/doc/efun/floats/index +/domains/town/room/basement.c +/doc/efun/sockets/socket_error.h +/doc/efun/floats/floor +/domains/town/room/bank.c +/doc/efun/sockets/socket_error +/doc/efun/floats/exp +/domains/town/room/adv_guild.c +/doc/efun/floats/cos +/doc/efun/sockets/socket_create +/domains/town/obj/wound.c +/doc/efun/floats/ceil +/doc/efun/sockets/socket_connect +/doc/efun/floats/atan +/domains/town/obj/well_lever.c +/doc/efun/sockets/socket_close +/domains/town/obj/weight.c +/doc/efun/floats/asin +/doc/efun/sockets/socket_bind +/doc/efun/floats/acos +/domains/town/obj/watch.c +/doc/efun/sockets/socket_address +/doc/efun/filesystem/write_file +/domains/town/obj/wardrobe.c +/domains/town/obj/wall.c +/doc/efun/sockets/socket_acquire +/doc/efun/filesystem/write_bytes +/domains/town/obj/trash.c +/doc/efun/sockets/socket_accept +/doc/efun/filesystem/tail +/domains/town/obj/torch.c +/doc/efun/sockets/index +/doc/efun/filesystem/stat +/domains/town/obj/toilet.c +/doc/efun/parsing/query_verb +/doc/efun/filesystem/rmdir +/domains/town/obj/thing.c +/doc/efun/filesystem/rm +/doc/efun/parsing/index +/domains/town/obj/test.c +/doc/efun/parsing/TODO +/doc/efun/filesystem/rename +/domains/town/obj/table.c +/doc/efun/objects/virtualp +/doc/efun/filesystem/read_file +/domains/town/obj/suitcase.c +/doc/efun/objects/tell_room +/doc/efun/filesystem/read_bytes +/domains/town/obj/stove.c +/doc/efun/objects/tell_object +/doc/efun/filesystem/mkdir +/domains/town/obj/spent.c +/doc/efun/objects/set_hide +/doc/efun/filesystem/link +/domains/town/obj/spam.c +/doc/efun/filesystem/index +/doc/efun/objects/set_heart_beat +/domains/town/obj/sofa.c +/doc/efun/filesystem/get_dir +/doc/efun/objects/save_object +/domains/town/obj/slip_regenerate.c +/doc/efun/filesystem/file_size +/doc/efun/objects/restore_object +/domains/town/obj/slip_heal.c +/doc/efun/filesystem/file_length +/doc/efun/objects/reload_object +/domains/town/obj/slip_excise.c +/doc/efun/filesystem/cp +/doc/efun/objects/query_heart_beat +/domains/town/obj/slip_cure.c +/doc/efun/compile/index +/doc/efun/objects/present +/domains/town/obj/simple_chair.c +/doc/efun/compile/generate_source +/doc/efun/objects/objects +/domains/town/obj/sign.c +/doc/efun/calls/throw +/doc/efun/objects/next_inventory +/domains/town/obj/shamelog.c +/doc/efun/objects/new +/domains/town/obj/seawater.c +/doc/efun/objects/move_object +/domains/town/obj/safe_key.c +/doc/efun/objects/master +/doc/build/Armours +/domains/town/obj/safe.c +/doc/efun/objects/load_object +/domains/town/obj/rug.c +/doc/efun/objects/index +/domains/town/obj/rucksack.c +/doc/efun/objects/heart_beats +/domains/town/obj/round2.c +/doc/efun/objects/heart_beat_info +/domains/town/obj/round.c +/doc/efun/objects/first_inventory +/domains/town/obj/room_item.c +/doc/efun/objects/find_object +/domains/town/obj/rocks.c +/doc/efun/objects/file_name +/domains/town/obj/rocking_chair.c +/doc/efun/objects/environment +/domains/town/obj/riverwater.c +/doc/efun/objects/destruct +/domains/town/obj/rayovac.c +/doc/efun/objects/deep_inventory +/domains/town/obj/rage.c +/doc/efun/objects/clonep +/domains/town/obj/rack.c +/doc/efun/objects/clone_object +/domains/town/obj/pool_table.c +/doc/efun/objects/children +/domains/town/obj/pool_ball.c +/doc/efun/objects/all_inventory +/domains/town/obj/pole.c +/doc/efun/numbers/to_float +/domains/town/obj/plastic_bag.c +/doc/efun/numbers/random +/domains/town/obj/pipe.c +/doc/efun/numbers/index +/domains/town/obj/painting.c +/doc/efun/mudlib/seteuid +/domains/town/obj/pack.c +/lib/talk.c +/doc/efun/mudlib/set_privs +/secure/sefun/atomize.c +/domains/town/obj/omni.c +/doc/efun/mudlib/set_living_name +/lib/events/dig_with.c +/doc/efun/mudlib/set_light +/verbs/creators/createfix.c +/doc/efun/mudlib/set_author +/verbs/rooms/fish.c +/doc/efun/mudlib/query_privs +/lib/std/boobytrap_object.c +/doc/efun/mudlib/livings +/secure/sefun/visible.c +/doc/efun/mudlib/living +/secure/daemon/imc2.c +/doc/efun/mudlib/index +/doc/efun/mudlib/getuid +/doc/efun/mudlib/geteuid +/doc/efun/mudlib/find_living +/doc/efun/mudlib/export_uid +/doc/efun/mudlib/domain_stats +/doc/applies/reset +/doc/efun/mudlib/author_stats +/doc/efun/mixed/undefinedp +/cfg/where.cfg +/doc/efun/mixed/stringp +/doc/efun/mixed/pointerp +/obj/README +/doc/efun/mixed/objectp +/doc/efun/mixed/nullp +/doc/efun/mixed/mapp +/cmds/admins/broadcast.c +/cmds/players/env.c +/doc/efun/mixed/intp +/doc/efun/mixed/functionp +/doc/efun/mixed/floatp +/doc/efun/mixed/classp +/doc/efun/mixed/bufferp +/doc/efun/mixed/arrayp +/doc/efun/mappings/values +/doc/efun/all/rmdir +/doc/efun/mappings/unique_mapping +/doc/efun/mappings/match_path +/doc/efun/mappings/map_mapping +/doc/efun/mappings/map_delete +/obj/door.c +/doc/efun/mappings/m_values +/doc/efun/mappings/m_indices +/doc/efun/mappings/m_delete +/doc/efun/mappings/keys +/doc/efun/mappings/index +/doc/efun/mappings/filter_mapping +/doc/efun/mappings/allocate_mapping +/doc/efun/internals/traceprefix +/doc/efun/internals/trace +/doc/efun/internals/time_expression +/doc/efun/internals/swap +/doc/efun/all/ceil +/doc/efun/internals/set_malloc_mask +/doc/efun/internals/set_debug_level +/doc/efun/internals/rusage +/doc/efun/internals/refs +/doc/efun/internals/query_load_average +/doc/efun/internals/opcprof +/doc/efun/internals/mud_status +/doc/efun/internals/memory_info +/doc/efun/internals/malloc_status +/doc/efun/internals/index +/doc/efun/internals/get_config +/doc/efun/internals/dumpallobj +/doc/efun/internals/dump_socket_status +/doc/efun/internals/dump_prog +/doc/efun/internals/dump_file_descriptors +/doc/efun/internals/debugmalloc +/doc/efun/internals/debug_info +/news/ftpd +/doc/efun/internals/cache_stats +/doc/efun/interactive/write +/doc/efun/interactive/wizardp +/doc/efun/interactive/users +/doc/efun/interactive/userp +/doc/efun/interactive/this_user +/doc/efun/interactive/this_player +/doc/efun/interactive/this_interactive +/doc/efun/interactive/snoop +/doc/efun/interactive/shout +/doc/efun/interactive/set_this_player +/doc/efun/interactive/say +/doc/efun/interactive/resolve +/doc/efun/interactive/remove_interactive +/doc/efun/interactive/remove_action +/doc/efun/interactive/receive +/doc/efun/interactive/query_snooping +/doc/efun/interactive/query_snoop +/cmds/admins/objload.c +/doc/efun/interactive/query_notify_fail +/doc/efun/interactive/query_ip_port +/cfg/time.cfg +/verbs/creators/wizunlock.c +/lib/combat.c +/lib/light.c +/lib/persist.c +/verbs/items/pick.c +/verbs/players/ignore.c +/lib/std/chair.c +/lib/events/listen.c +/verbs/items/give.c +/spells/cure.c +/lib/chat.c +/verbs/rooms/enter.c +/verbs/creators/pulsecheck.c +/verbs/common/say.c +/verbs/items/turn.c +/lib/trap.c +/verbs/items/drink.c +/lib/props/mass.c +/verbs/creators/zap.c +/verbs/items/steal.c +/lib/command.c +/cmds/creators/inherits.c +/domains/town/obj/obag.c +/doc/efun/all/mkdir +/domains/town/obj/needle_trap3.c +/domains/town/obj/needle_trap2.c +/domains/town/obj/needle_trap.c +/domains/town/obj/medbag.c +/domains/town/obj/match.c +/domains/town/obj/mat.c +/domains/town/obj/map.c +/domains/town/obj/mailbox.c +/domains/town/obj/maglite.c +/domains/town/obj/m_key.c +/domains/town/obj/lockpick.c +/domains/town/obj/lice.c +/domains/town/obj/leaflet.c +/domains/town/obj/ladder_simple.c +/domains/town/obj/ladder.c +/domains/town/obj/key.c +/domains/town/obj/gcoinbag.c +/domains/town/obj/gbed.c +/domains/town/obj/flu.c +/domains/town/obj/fleas.c +/domains/town/obj/flask.c +/domains/town/obj/explosive_trap.c +/domains/town/obj/ebutton2.c +/domains/town/obj/ebutton1.c +/doc/faq/lpmud +/cmds/players/save.c +/domains/town/obj/donation_box.c +/cmds/players/rwho.c +/domains/town/obj/dining_table.c +/cmds/players/quests.c +/domains/town/obj/dcell_std.c +/cmds/players/prompt.c +/domains/town/obj/dcell_good.c +/cmds/players/posting.c +/domains/town/obj/dcell_crappy.c +/cmds/players/plugh.c +/cmds/players/nextreboot.c +/domains/town/obj/dcell.c +/domains/town/obj/d6.c +/cmds/players/newbie.c +/cmds/players/mute.c +/domains/town/obj/d20.c +/domains/town/obj/couch.c +/cmds/players/mudlist.c +/cmds/players/money.c +/domains/town/obj/cot.c +/domains/town/obj/cold.c +/cmds/players/locate.c +/cmds/players/lines.c +/domains/town/obj/clocktower.c +/domains/town/obj/cloak_hood.c +/domains/town/obj/clip.c +/domains/town/obj/church_wall.c +/save/bugs.o +/domains/town/obj/church_button.c +/domains/town/obj/chest2.c +/domains/town/obj/chest.c +/domains/town/obj/chair.c +/domains/town/obj/canteen.c +/domains/town/obj/candlestick.c +/domains/town/obj/btable.c +/domains/town/obj/bin.c +/cmds/creators/last.c +/domains/town/obj/bigbag.c +/domains/town/obj/bed.c +/domains/town/obj/bbucket.c +/domains/town/obj/basement_button.c +/domains/town/obj/bag.c +/domains/town/obj/altar.c +/doc/build/Items +/domains/town/obj/9mmround.c +/domains/town/obj/9mmclip_empty.c +/domains/town/obj/9mmclip.c +/domains/town/obj/8ball.c +/domains/town/obj/50round.c +/domains/town/obj/45round.c +/domains/town/obj/357shell.c +/domains/town/obj/357round.c +/domains/town/obj/223round.c +/domains/town/obj/223clip.c +/domains/town/npc/zoe.c +/domains/town/npc/zafo.c +/domains/town/npc/viper.c +/domains/town/npc/troll.c +/domains/town/npc/thief.c +/lib/nmsh.c +/lib/interactive.c +/domains/town/npc/spider.c +/lib/std/corpse.c +/domains/town/npc/rat.c +/domains/town/npc/radagast.c +/domains/town/npc/otik.c +/domains/town/npc/orc_shaman.c +/domains/town/npc/orc_boss.c +/domains/town/npc/orc2.c +/domains/town/npc/orc.c +/domains/town/npc/oana.c +/domains/town/npc/newt.c +/domains/town/npc/mp.c +/domains/town/npc/mayor.c +/domains/town/npc/leo.c +/domains/town/npc/lars.c +/domains/town/npc/james.c +/domains/town/npc/ingrid.c +/domains/town/npc/human_champion_f.c +/domains/town/npc/human_champion.c +/domains/town/npc/horse.c +/domains/town/npc/herkimer.c +/domains/town/npc/gecko.c +/domains/town/npc/forest_orc.c +/domains/town/npc/dirk.c +/domains/town/npc/deer.c +/log/reset +/domains/town/npc/clerk.c +/domains/town/npc/clepius.c +/domains/town/npc/bugg.c +/domains/town/npc/bubb.c +/domains/town/npc/beggar.c +/domains/town/npc/bear.c +/domains/town/meals/zyqxuwy.c +/domains/town/meals/water.c +/domains/town/meals/special.c +/domains/town/meals/shark.c +/domains/town/meals/potion_strength.c +/domains/town/meals/potion_healing.c +/domains/town/meals/potion_bigheal.c +/domains/town/meals/potion_antidote.c +/domains/town/meals/poison.c +/domains/town/meals/megapotion.c +/domains/town/meals/latte.c +/domains/town/meals/herring.c +/domains/town/meals/ham_sand.c +/domains/town/meals/fire.c +/domains/town/meals/espresso.c +/domains/town/meals/coffee.c +/domains/town/meals/claritin.c +/domains/town/meals/bourbon.c +/domains/town/meals/ale.c +/domains/town/doors/welldoor2.c +/domains/town/doors/welldoor1.c +/domains/town/doors/trapdoor.c +/domains/town/doors/testdoor2.c +/domains/town/doors/stone.c +/lib/clerk.c +/lib/spell.c +/lib/potion.c +/domains/town/doors/steel_door.c +/verbs/items/unlock.c +/domains/town/doors/south.c +/secure/lib/net/echo_server.c +/domains/town/doors/mansion.c +/secure/sefun/query_names.c +/domains/town/doors/house_door.c +/verbs/items/strike.c +/domains/town/armor/workglove_r.c +/verbs/players/abandon.c +/verbs/common/shout.c +/domains/town/armor/workglove_l.c +/domains/town/armor/workboot_r.c +/domains/town/armor/workboot_l.c +/domains/town/armor/wizard_hat.c +/domains/town/armor/visor.c +/domains/town/armor/vest.c +/doc/faq/ed +/domains/town/armor/tshirt.c +/domains/town/armor/towel.c +/domains/town/armor/toga.c +/doc/BASICS +/domains/town/armor/sock.c +/cmds/creators/rot.c +/domains/town/armor/silverring.c +/doc/efun/all/keys +/domains/town/armor/shirt.c +/domains/town/armor/shield.c +/domains/town/armor/scarf.c +/domains/town/armor/robe.c +/domains/town/armor/ring.c +/domains/town/armor/riding_boot.c +/doc/efun/all/intp +/domains/town/armor/platemail.c +/domains/town/armor/pants.c +/domains/town/armor/overcoat.c +/domains/town/armor/overalls.c +/domains/town/armor/orc_helmet.c +/domains/town/armor/orc_boot_r.c +/domains/town/armor/orc_boot_l.c +/domains/town/armor/oldstyle_ring.c +/domains/town/armor/newbie_ring.c +/domains/town/armor/mhelmet.c +/domains/town/armor/magical_platemail.c +/domains/town/armor/lvest.c +/domains/town/armor/long_sock.c +/domains/town/armor/long_glove.c +/domains/town/armor/long_boot_r.c +/domains/town/armor/long_boot_l.c +/domains/town/armor/leather_armor.c +/domains/town/armor/jeans.c +/domains/town/armor/jacket.c +/domains/town/armor/hunting_cap.c +/domains/town/armor/hshirt.c +/domains/town/armor/helmet2.c +/domains/town/armor/helmet.c +/domains/town/armor/goggles.c +/domains/town/armor/glove_r.c +/domains/town/armor/glove_l.c +/domains/town/armor/glove.c +/domains/town/armor/collar.c +/daemon/banish.c +/domains/town/armor/cloak.c +/cmds/players/pk.c +/domains/town/armor/chainmail.c +/domains/town/armor/cap.c +/cmds/players/earmuff.c +/domains/town/armor/boot_r.c +/cmds/players/date.c +/domains/town/armor/boot_l.c +/domains/town/armor/boot.c +/doc/build/Meals +/domains/town/armor/boobytrap_ring.c +/cmds/players/mem.c +/lib/events/search.c +/domains/town/armor/belt.c +/secure/lib/net/generic.c +/domains/town/armor/bearsuit.c +/cmds/players/brief.c +/domains/town/armor/bearskin.c +/cmds/players/biography.c +/domains/town/armor/bdu.c +/domains/town/armor/bandanna.c +/lib/std/table.c +/domains/town/armor/badge.c +/lib/props/clean.c +/lib/remote.c +/domains/examples/room/start.c +/verbs/items/search.c +/domains/examples/room/exroom7.c +/lib/round.c +/lib/events/pull.c +/domains/examples/room/exroom6.c +/verbs/players/pray.c +/domains/examples/room/exroom5.c +/lib/events/manipulate.c +/domains/examples/room/exroom4.c +/verbs/rooms/jump.c +/domains/examples/room/exroom3.c +/domains/examples/room/exroom2b.c +/domains/examples/room/exroom2a.c +/domains/examples/room/exroom2.c +/domains/examples/room/exroom1.c +/obj/bed.c +/domains/examples/room/ex.h +/domains/examples/room/entrance.c +/domains/examples/room/README +/doc/lfun/lib/chapel/SetReligion +/domains/default/weap/staff.c +/doc/lfun/lib/chapel/GetSacrificeType +/domains/default/weap/sharpsword.c +/doc/lfun/lib/chapel/GetReligion +/domains/default/weap/orcslayer.c +/doc/lfun/lib/chapel/GetAllowSacrifice +/domains/default/weap/carving_knife.c +/doc/lfun/lib/chapel/CanSacrifice +/domains/default/weap/brush.c +/doc/lfun/lib/chapel/CanMarry +/domains/default/virtual/sky.c +/doc/lfun/lib/chapel/AddSacrificeType +/domains/default/virtual/server.c +/doc/lfun/lib/burn/eventLight +/doc/build/Climates +/domains/default/virtual/arena.c +/doc/lfun/lib/burn/eventExtinguish +/domains/default/vehicles/strider.c +/doc/lfun/lib/burn/eventBurnOut +/domains/default/vehicles/hoverpod.c +/doc/lfun/lib/burn/SetMinHeat +/domains/default/room/wiz_hall2.c +/doc/lfun/lib/burn/SetHeat +/domains/default/room/wiz_hall.c +/doc/lfun/lib/burn/SetFuelRequired +/domains/default/room/wiz_corr_south.c +/doc/lfun/lib/burn/SetBurnRate +/doc/lfun/lib/burn/GetMinHeat +/domains/default/room/wiz_corr_east2.c +/doc/lfun/lib/burn/GetHeat +/domains/default/room/wiz_corr_east.c +/doc/lfun/lib/burn/GetFuelRequired +/domains/default/room/wiz_corr1.c +/doc/lfun/lib/burn/GetBurntValue +/domains/default/room/void.c +/doc/lfun/lib/burn/GetBurning +/domains/default/room/test.c +/doc/lfun/lib/burn/GetBurnRate +/domains/default/room/telnet_room.c +/daemon/intermud.c +/doc/lfun/lib/burn/CanExtinguish +/domains/default/room/start.c +/doc/lfun/lib/burn/CanBurn +/doc/lfun/lib/bot/eventDie +/domains/default/room/stargate_lab.c +/doc/lfun/lib/bot/GetLong +/domains/default/room/quarantine3.c +/doc/lfun/lib/bonus/eventDestruct +/domains/default/room/quarantine2.c +/doc/lfun/lib/bonus/SetStats +/domains/default/room/quarantine1.c +/domains/default/room/pod.c +/doc/lfun/lib/bonus/SetSkills +/domains/default/room/menagerie_w.c +/doc/lfun/lib/bonus/SetPoints +/doc/efun/all/copy +/doc/lfun/lib/bonus/SetBonuses +/domains/default/room/menagerie_south.c +/doc/lfun/lib/bonus/SetBonusDuration +/domains/default/room/menagerie_e.c +/doc/lfun/lib/bonus/RemoveBonuses +/domains/default/room/menagerie.c +/doc/lfun/lib/bonus/GetStats +/domains/default/room/furnace.c +/doc/lfun/lib/bonus/GetSkills +/domains/default/room/freezer.c +/doc/lfun/lib/bonus/GetPoints +/domains/default/room/domains_room.c +/domains/default/room/death.c +/doc/lfun/lib/bonus/GetBonusDuration +/domains/default/room/arena.c +/doc/lfun/lib/body/eventWear +/domains/default/obj/torch.c +/doc/lfun/lib/body/eventRemoveItem +/domains/default/obj/stargate.c +/doc/lfun/lib/body/eventReconnect +/domains/default/obj/reset_button.c +/doc/lfun/lib/body/eventReceiveThrow +/domains/default/obj/pinger.c +/doc/lfun/lib/body/eventReceiveDamage +/domains/default/obj/pass_example.c +/doc/lfun/lib/body/eventHealDamage +/domains/default/obj/module_cloak.c +/doc/lfun/lib/body/eventFall +/domains/default/obj/meter.c +/doc/lfun/lib/body/eventDie +/domains/default/obj/match.c +/doc/lfun/lib/body/eventCompleteHeal +/domains/default/obj/manual.c +/doc/lfun/lib/body/eventCompareLimbs +/domains/default/obj/handbook.c +/doc/lfun/lib/body/eventCollapse +/domains/default/obj/guide.c +/doc/lfun/lib/body/eventCheckProtection +/domains/default/obj/collarchest.c +/doc/lfun/lib/body/eventCheckHealing +/domains/default/obj/chest.c +/doc/lfun/lib/body/eventBuy +/domains/default/obj/box.c +/doc/lfun/lib/body/checkCollapse +/domains/default/obj/bbucket.c +/doc/lfun/lib/body/SetSleeping +/domains/default/npc/zookeeper.c +/domains/default/npc/zoe.c +/doc/lfun/lib/body/SetProtect +/domains/default/npc/yattering.c +/doc/lfun/lib/body/SetPacifist +/doc/lfun/lib/body/SetMelee +/domains/default/npc/wraith.c +/doc/lfun/lib/body/SetFingers +/domains/default/npc/unicorn.c +/doc/lfun/lib/body/SetExtraChannels +/domains/default/npc/turtle.c +/doc/lfun/lib/body/SetDrainRate +/domains/default/npc/troll.c +/doc/lfun/lib/body/SetDeathEvents +/doc/lfun/lib/body/SetCanBite +/doc/lfun/lib/body/SetBodyComposition +/doc/lfun/lib/body/RestoreLimb +/doc/lfun/lib/body/RemoveMagicProtection +/doc/lfun/lib/body/RemoveLimb +/doc/lfun/lib/body/RemoveExtraChannels +/doc/lfun/lib/body/ParseHook +/doc/lfun/lib/body/NewBody +/doc/lfun/lib/body/HealLimb +/doc/lfun/lib/body/GetWorn +/doc/lfun/lib/body/GetWieldingLimbs +/doc/lfun/lib/body/GetWielded +/doc/efun/all/time +/doc/lfun/lib/body/GetTorso +/doc/lfun/lib/body/GetStaminaPoints +/doc/lfun/lib/body/GetSleeping +/doc/lfun/lib/body/GetResistance +/doc/lfun/lib/body/GetRandomLimb +/cmds/creators/file.c +/doc/lfun/lib/body/GetRace +/doc/lfun/lib/body/GetQuestPoints +/verbs/players/teach.c +/doc/lfun/lib/body/GetProtect +/secure/lib/net/ftp_client.c +/doc/lfun/lib/body/GetPoison +/lib/events/poison.c +/doc/lfun/lib/body/GetPacifist +/lib/events/install.c +/doc/lfun/lib/body/GetName +/verbs/items/shoot.c +/doc/lfun/lib/body/GetMoJo +/verbs/items/sell.c +/lib/std/barkeep.c +/doc/lfun/lib/body/GetMissingLimbs +/verbs/players/attack.c +/doc/lfun/lib/body/GetMissingLimbParents +/doc/lfun/lib/body/GetMissingLimbParent +/cmds/creators/expel.c +/doc/lfun/lib/body/GetMelee +/doc/lfun/lib/body/GetMaxStaminaPoints +/cmds/creators/cryptogram.c +/doc/lfun/lib/body/GetMaxMagicPoints +/doc/lfun/lib/body/GetMaxHealthPoints +/doc/lfun/lib/body/GetMagicPoints +/doc/lfun/lib/body/GetLong +/doc/lfun/lib/body/GetLimbs +/doc/build/Barkeeps +/doc/lfun/lib/body/GetLimbParent +/doc/lfun/lib/body/GetLimbClass +/doc/lfun/lib/body/GetLimbChildren +/doc/lfun/lib/body/GetLead +/doc/lfun/lib/body/GetHeartRate +/doc/lfun/lib/body/GetHeartModifier +/secure/daemon/bboard.c +/doc/lfun/lib/body/GetHealthShort +/doc/efun/all/write +/doc/lfun/lib/body/GetHealthPoints +/cmds/creators/wizroll.c +/doc/lfun/lib/body/GetHealRate +/doc/lfun/lib/body/GetFood +/doc/lfun/lib/body/GetFingers +/doc/lfun/lib/body/GetExtraChannels +/doc/lfun/lib/body/GetExperiencePoints +/doc/lfun/lib/body/GetEquippedLimbs +/doc/lfun/lib/body/GetEncumbrance +/doc/lfun/lib/body/GetDying +/doc/lfun/lib/body/GetDrink +/doc/lfun/lib/body/GetDeathEvents +/doc/lfun/lib/body/GetCellType +/doc/lfun/lib/body/GetCapName +/doc/lfun/lib/body/GetCanBite +/doc/lfun/lib/body/GetCaffeine +/doc/lfun/lib/body/GetBodyComposition +/doc/lfun/lib/body/GetAlcohol +/doc/lfun/lib/body/GetAffectLong +/doc/lfun/lib/body/DestLimb +/doc/lfun/lib/body/CanWear +/doc/lfun/lib/body/CanRemoveItem +/doc/lfun/lib/body/CanManipulate +/doc/lfun/lib/body/CanFly +/doc/lfun/lib/body/AddQuestPoints +/doc/lfun/lib/body/AddPoison +/doc/lfun/lib/body/AddMoJo +/doc/lfun/lib/body/AddMagicProtection +/doc/lfun/lib/body/AddMagicPoints +/doc/lfun/lib/body/AddLimb +/doc/lfun/lib/body/AddLead +/doc/lfun/lib/body/AddHeartModifier +/doc/lfun/lib/body/AddHealthPoints +/doc/lfun/lib/body/AddHP +/doc/lfun/lib/body/AddFood +/doc/lfun/lib/body/AddFingers +/doc/lfun/lib/body/AddExtraChannels +/std/void.c +/doc/lfun/lib/body/AddExperiencePoints +/doc/lfun/lib/body/AddDrink +/doc/lfun/lib/body/AddCaffeine +/doc/lfun/lib/body/AddAlcohol +/doc/lfun/lib/battery/eventUse +/lib/door.c +/doc/lfun/lib/battery/eventDrain +/verbs/players/lead.c +/doc/lfun/lib/battery/eventCharge +/lib/events/bury.c +/doc/lfun/lib/battery/Spent +/verbs/items/fill.c +/verbs/items/pour.c +/doc/lfun/lib/battery/SetRechargeable +/secure/sefun/translate.c +/doc/lfun/lib/battery/SetPowerType +/verbs/common/speak.c +/doc/lfun/lib/battery/SetDrainable +/verbs/players/nominate.c +/doc/lfun/lib/battery/SetDrainRate +/verbs/items/shake.c +/verbs/items/close.c +/doc/lfun/lib/battery/SetCharge +/doc/lfun/lib/battery/SetCellType +/doc/lfun/lib/battery/ModCharge +/doc/lfun/lib/battery/GetRechargeable +/doc/lfun/lib/battery/GetDrainable +/doc/lfun/lib/battery/GetDrainRate +/doc/lfun/lib/battery/GetCharge +/doc/lfun/lib/battery/GetCellType +/doc/lfun/lib/armor/eventReceiveDamage +/doc/lfun/lib/armor/SetFingers +/doc/lfun/lib/armor/GetFingers +/doc/lfun/lib/abilities/GetSkills +/doc/lfun/lib/abilities/AddSkillPoints +/doc/lfun/all/returnChannels +/doc/lfun/all/performMarriage +/doc/lfun/all/eventWelcome +/doc/lfun/all/eventWear +/doc/lfun/all/eventUse +/doc/lfun/all/eventUnjoin +/doc/lfun/all/eventSacrifice +/domains/default/npc/triffid.c +/lib/events/smell.c +/domains/default/npc/tree.c +/doc/lfun/all/eventRetire +/lib/events/dig.c +/domains/default/npc/treant.c +/doc/lfun/all/eventRemoveItem +/spells/meditate.c +/secure/sefun/query_invis.c +/domains/default/npc/spider.c +/doc/lfun/all/eventReconnect +/secure/sefun/light.c +/domains/default/npc/snake.c +/doc/lfun/all/eventReceiveThrow +/domains/default/npc/slug.c +/doc/lfun/all/eventReceiveDamage +/doc/efun/calls/this_object +/doc/lfun/all/eventMoralAct +/doc/efun/calls/shadow +/domains/default/npc/sheep.c +/doc/lfun/all/eventMarry +/doc/efun/calls/remove_shadow +/lib/verb.c +/domains/default/npc/satyr.c +/doc/lfun/all/eventLight +/verbs/items/capture.c +/doc/efun/calls/remove_call_out +/domains/default/npc/red_dragon.c +/doc/lfun/all/eventJoin +/secure/lib/bboard.c +/domains/default/npc/rat.c +/doc/efun/calls/query_shadowing +/doc/lfun/all/eventInitiate +/doc/efun/calls/previous_object +/domains/default/npc/quarantine/wim.c +/doc/lfun/all/eventHealDamage +/doc/efun/calls/origin +/domains/default/npc/quarantine/wallace.c +/doc/lfun/all/eventFall +/obj/meal.c +/doc/efun/calls/index +/doc/lfun/all/eventExtinguish +/domains/default/npc/quarantine/trevor.c +/doc/efun/calls/catch +/doc/lfun/all/eventDrain +/doc/efun/calls/call_stack +/domains/default/npc/quarantine/ton.c +/doc/lfun/all/eventDie +/doc/efun/calls/call_out +/doc/lfun/all/eventDestruct +/domains/default/npc/quarantine/tom.c +/doc/efun/calls/call_other +/doc/lfun/all/eventCompleteHeal +/domains/default/npc/quarantine/ted.c +/doc/efun/buffers/write_buffer +/doc/lfun/all/eventCompareLimbs +/doc/efun/buffers/read_buffer +/domains/default/npc/quarantine/spencer.c +/doc/lfun/all/eventCollapse +/doc/efun/buffers/index +/domains/default/npc/quarantine/simon.c +/doc/lfun/all/eventCheckProtection +/doc/efun/buffers/crc32 +/secure/cfg/mudos.cfg +/domains/default/npc/quarantine/rik.c +/doc/lfun/all/eventCheckHealing +/doc/efun/buffers/allocate_buffer +/doc/lfun/all/eventCharge +/domains/default/npc/quarantine/pip.c +/doc/efun/arrays/unique_array +/secure/include/config.h +/doc/lfun/all/eventBuy +/doc/efun/arrays/sort_array +/domains/default/npc/quarantine/nigel.c +/doc/lfun/all/eventBurnOut +/doc/efun/arrays/member_array +/domains/default/npc/quarantine/miles.c +/doc/lfun/all/eventBring +/doc/efun/arrays/map_array +/domains/default/npc/quarantine/lex.c +/doc/efun/arrays/index +/domains/default/npc/quarantine/lester.c +/doc/efun/arrays/filter_array +/doc/efun/arrays/allocate +/domains/default/npc/quarantine/kip.c +/doc/efun/all/write_file +/domains/default/npc/quarantine/job.c +/doc/efun/all/write_bytes +/doc/efun/all/write_buffer +/domains/default/npc/quarantine/jan.c +/doc/efun/all/wizardp +/domains/default/npc/quarantine/han.c +/doc/efun/all/virtualp +/doc/efun/all/variables +/domains/default/npc/quarantine/graham.c +/doc/efun/all/values +/domains/default/npc/quarantine/gavin.c +/doc/efun/all/uptime +/domains/default/npc/quarantine/edmund.c +/doc/efun/all/upper_case +/domains/default/npc/quarantine/duncan.c +/doc/efun/all/unique_mapping +/doc/efun/all/unique_array +/domains/default/npc/quarantine/cor.c +/doc/efun/all/undefinedp +/domains/default/npc/quarantine/adrian.c +/doc/efun/all/typeof +/domains/default/npc/pessis.c +/doc/efun/all/traceprefix +/doc/efun/all/to_int +/domains/default/npc/pegasus.c +/doc/efun/all/to_float +/domains/default/npc/orc.c +/domains/default/npc/ogre.c +/doc/efun/all/time_expression +/doc/efun/all/this_user +/domains/default/npc/nymph.c +/doc/efun/all/this_player +/domains/default/npc/newt.c +/doc/efun/all/this_object +/domains/default/npc/moth.c +/doc/efun/all/this_interactive +/doc/efun/all/tail +/domains/default/npc/minotaur.c +/doc/efun/all/test_bit +/domains/default/npc/lynx.c +/doc/efun/all/terminal_colour +/domains/default/npc/lemur.c +/doc/efun/all/tell_room +/domains/default/npc/kwyjibo.c +/doc/efun/all/tell_object +/domains/default/npc/kobold.c +/doc/efun/all/strsrch +/domains/default/npc/klingon.c +/doc/efun/all/strlen +/doc/efun/all/stringp +/domains/default/npc/kender_quiet.c +/doc/efun/all/strcmp +/domains/default/npc/kender.c +/doc/efun/all/store_variable +/domains/default/npc/horse.c +/doc/efun/all/sscanf +/daemon/classes.c +/domains/default/npc/hobbit.c +/doc/efun/all/sprintf +/domains/default/npc/helf.c +/doc/efun/all/sort_array +/domains/default/npc/halfling.c +/doc/efun/all/socket_write +/domains/default/npc/golem.c +/doc/efun/all/socket_release +/domains/default/npc/goblin.c +/doc/efun/all/socket_listen +/domains/default/npc/gnome.c +/doc/efun/all/socket_error.h +/domains/default/npc/gnoll.c +/doc/efun/all/socket_error +/doc/efun/all/socket_create +/domains/default/npc/giant.c +/doc/efun/all/socket_connect +/domains/default/npc/gecko.c +/doc/efun/all/socket_close +/domains/default/npc/gargoyle.c +/doc/efun/all/socket_bind +/domains/default/npc/foochy.c +/doc/efun/all/socket_address +/domains/default/npc/fighter.c +/doc/efun/all/socket_acquire +/domains/default/npc/faerie.c +/doc/efun/all/socket_accept +/domains/default/npc/elf.c +/doc/efun/all/sizeof +/domains/default/npc/elephant.c +/doc/efun/all/shutdown +/domains/default/npc/elemental.c +/doc/efun/all/shallow_inherit_list +/cmds/admins/arch.c +/doc/efun/all/shadow +/domains/default/npc/dwarf.c +/doc/efun/all/seteuid +/domains/default/npc/dummy.c +/doc/efun/all/set_this_player +/domains/default/npc/dryad.c +/doc/efun/all/set_reset +/domains/default/npc/deer.c +/doc/efun/all/set_privs +/domains/default/npc/cow.c +/doc/efun/all/set_malloc_mask +/domains/default/npc/chimera.c +/doc/efun/all/set_living_name +/domains/default/npc/centaur.c +/doc/efun/all/set_light +/domains/default/npc/boar.c +/doc/efun/all/set_hide +/domains/default/npc/bird.c +/domains/default/npc/bear.c +/doc/efun/all/set_heart_beat +/domains/default/npc/bat.c +/doc/efun/all/set_eval_limit +/domains/default/npc/balrog.c +/doc/efun/all/set_debug_level +/doc/efun/all/set_bit +/domains/default/npc/bacchus.c +/doc/efun/all/set_author +/domains/default/npc/avidryl.c +/doc/efun/all/save_variable +/domains/default/npc/artrell.c +/doc/efun/all/save_object +/domains/default/etc/death.txt +/doc/efun/all/rusage +/domains/default/doors/west.c +/doc/efun/all/restore_variable +/domains/default/doors/test101.c +/doc/efun/all/restore_object +/domains/default/doors/steel_door3.c +/doc/efun/all/resolve +/doc/efun/all/reset_eval_cost +/domains/default/doors/steel_door2.c +/doc/efun/all/replaceable +/domains/default/doors/steel_door.c +/doc/efun/all/replace_string +/domains/default/creator/workroom.c +/cmds/creators/netstat.c +/doc/efun/all/replace_program +/domains/default/armor/wristcomp.c +/doc/efun/all/repeat_string +/domains/default/armor/wizard_hat.c +/doc/efun/all/rename +/domains/default/armor/towel.c +/doc/efun/all/remove_shadow +/domains/default/armor/shirt.c +/doc/efun/all/remove_interactive +/domains/default/armor/robe.c +/doc/efun/all/remove_call_out +/doc/efun/all/remove_action +/domains/default/armor/pants.c +/doc/efun/all/reload_object +/domains/default/armor/long_boot_r.c +/doc/efun/all/regexp +/domains/default/armor/long_boot_l.c +/doc/efun/all/reg_assoc +/domains/default/armor/jeans.c +/doc/efun/all/reclaim_objects +/doc/efun/all/receive +/domains/default/armor/jade_ring.c +/doc/efun/all/read_file +/domains/default/armor/horc_shirt.c +/doc/efun/all/read_bytes +/domains/default/armor/helmet.c +/doc/efun/all/read_buffer +/domains/default/armor/gray_amulet.c +/doc/efun/all/random +/domains/default/armor/glove_r.c +/doc/efun/all/query_verb +/domains/default/armor/glove_l.c +/doc/efun/all/query_snooping +/doc/efun/all/query_snoop +/domains/default/armor/combat_pack.c +/doc/efun/all/query_shadowing +/domains/default/armor/collar.c +/doc/efun/all/query_privs +/domains/default/armor/chainmail.c +/doc/efun/all/query_notify_fail +/domains/default/armor/bearskin.c +/doc/efun/all/query_load_average +/domains/default/armor/badge.c +/doc/efun/all/query_ip_port +/domains/campus/weap/waterpistol.c +/doc/efun/all/query_ip_number +/domains/campus/weap/sword.c +/doc/efun/all/query_ip_name +/doc/efun/all/query_idle +/domains/campus/weap/staff.c +/doc/efun/all/query_host_name +/domains/campus/weap/sharpsword.c +/doc/efun/all/query_heart_beat +/domains/campus/weap/grenade.c +/doc/efun/all/query_ed_mode +/domains/campus/weap/dagger.c +/doc/efun/all/program_info +/domains/campus/weap/board.c +/doc/efun/all/printf +/domains/campus/weap/9mmpistol_mp.c +/doc/efun/all/previous_object +/domains/campus/weap/9mmpistol_loaded.c +/doc/efun/all/present +/domains/campus/weap/9mmpistol.c +/doc/efun/all/pointerp +/doc/efun/all/pluralize +/domains/campus/weap/9mil.c +/doc/efun/all/origin +/domains/campus/weap/357pistol.c +/doc/efun/all/opcprof +/domains/campus/txt/warning.txt +/doc/efun/all/objects +/domains/campus/txt/spam.txt +/doc/efun/all/objectp +/domains/campus/txt/skulls.txt +/doc/efun/all/notify_fail +/domains/campus/txt/rose.txt +/doc/efun/all/next_inventory +/doc/efun/all/next_bit +/domains/campus/txt/note.txt +/domains/campus/txt/map.txt +/doc/efun/all/named_livings +/doc/efun/all/mud_status +/domains/campus/txt/lisa.txt +/doc/efun/all/move_object +/domains/campus/txt/jenny/spiel.txt +/doc/efun/all/message +/domains/campus/txt/jenny/9.txt +/doc/lfun/all/checkCollapse +/doc/efun/all/memory_summary +/doc/lfun/all/chat_command +/domains/campus/txt/jenny/8.txt +/doc/efun/all/memory_info +/doc/lfun/all/UnrestrictChannel +/domains/campus/txt/jenny/7.txt +/doc/efun/all/member_array +/doc/lfun/all/Spent +/domains/campus/txt/jenny/6.txt +/doc/efun/all/max_eval_cost +/doc/lfun/all/SetStats +/doc/efun/all/match_path +/domains/campus/txt/jenny/5.txt +/doc/lfun/all/SetSleeping +/doc/efun/all/master +/domains/campus/txt/jenny/4.txt +/doc/lfun/all/SetSkills +/doc/efun/all/map_mapping +/domains/campus/txt/jenny/3.txt +/doc/lfun/all/SetSkillModifier +/doc/efun/all/map_delete +/domains/campus/txt/jenny/2.txt +/doc/lfun/all/SetSacrificeType +/doc/efun/all/map_array +/cmds/creators/stargate.c +/doc/lfun/all/SetReligion +/domains/campus/txt/jenny/15.txt +/doc/efun/all/malloc_status +/doc/lfun/all/SetRechargeable +/doc/efun/all/m_values +/domains/campus/txt/jenny/14.txt +/doc/lfun/all/SetProtect +/doc/efun/all/m_indices +/domains/campus/txt/jenny/13.txt +/doc/lfun/all/SetPowerType +/doc/efun/all/m_delete +/domains/campus/txt/jenny/12.txt +/doc/lfun/all/SetPoints +/doc/efun/all/lpc_info +/domains/campus/txt/jenny/11.txt +/doc/lfun/all/SetPacifist +/doc/efun/all/lower_case +/domains/campus/txt/jenny/10.txt +/doc/lfun/all/SetNoChanColors +/doc/efun/all/localtime +/doc/efun/all/load_object +/domains/campus/txt/jenny/1.txt +/doc/lfun/all/SetMorality +/doc/lfun/all/SetMinHeat +/doc/efun/all/livings +/domains/campus/txt/huh.txt +/doc/efun/all/living +/domains/campus/txt/hug.txt +/doc/lfun/all/SetMelee +/doc/lfun/all/SetLeader +/doc/efun/all/interactive +/domains/campus/txt/hi.txt +/doc/efun/all/input_to +/doc/lfun/all/SetHeat +/domains/campus/txt/finger.txt +/doc/efun/all/inherits +/domains/campus/txt/duh.txt +/doc/lfun/all/SetFuelRequired +/doc/efun/all/inherit_list +/doc/lfun/all/SetFingers +/domains/campus/txt/dork.txt +/doc/efun/all/in_input +/doc/lfun/all/SetExtraChannels +/domains/campus/txt/doh.txt +/doc/efun/all/in_edit +/doc/lfun/all/SetDrainable +/domains/campus/txt/dali.txt +/doc/efun/all/implode +/doc/lfun/all/SetDrainRate +/domains/campus/txt/bye.txt +/doc/efun/all/heart_beats +/doc/lfun/all/SetDeathEvents +/domains/campus/txt/ai/charly/wins +/doc/efun/all/heart_beat_info +/doc/lfun/all/SetComposition +/doc/efun/all/getuid +/domains/campus/txt/ai/charly/switches +/doc/lfun/all/SetClass +/doc/efun/all/geteuid +/domains/campus/txt/ai/charly/stays +/doc/lfun/all/SetClanSkill +/doc/efun/all/get_dir +/domains/campus/txt/ai/charly/runs +/doc/lfun/all/SetClanObject +/doc/efun/all/get_config +/doc/lfun/all/SetClanName +/domains/campus/txt/ai/charly/red_wins +/doc/efun/all/get_char +/doc/lfun/all/SetClan +/doc/efun/all/generate_source +/domains/campus/txt/ai/charly/percent +/doc/lfun/all/SetCharge +/doc/efun/all/functions +/domains/campus/txt/ai/charly/green_wins +/doc/lfun/all/SetCellType +/doc/efun/all/functionp +/doc/lfun/all/SetCanBite +/domains/campus/txt/ai/charly/fred +/doc/efun/all/function_profile +/doc/lfun/all/SetBurnRate +/domains/campus/txt/ai/charly/fgreen +/doc/lfun/all/SetBonuses +/doc/efun/all/function_owner +/domains/campus/txt/ai/charly/fblue +/doc/lfun/all/SetBonusDuration +/doc/efun/all/function_exists +/domains/campus/txt/ai/charly/blue_wins +/doc/lfun/all/SetBodyComposition +/doc/efun/all/flush_messages +/doc/efun/all/floatp +/doc/lfun/all/SetAllowSacrifice +/domains/campus/txt/ai/charly/bak/wins +/doc/efun/all/first_inventory +/doc/lfun/all/RestrictChannel +/domains/campus/txt/ai/charly/bak/switches +/domains/default/room/catchtell.c +/doc/efun/all/find_player +/doc/efun/all/find_object +/domains/campus/txt/ai/charly/bak/stays +/doc/efun/all/find_living +/domains/campus/txt/ai/charly/bak/runs +/doc/efun/all/find_call_out +/domains/campus/txt/ai/charly/bak/red_wins +/doc/efun/all/filter_mapping +/domains/campus/txt/ai/charly/bak/percent +/doc/efun/all/filter_array +/doc/efun/all/filter +/domains/campus/txt/ai/charly/bak/green_wins +/doc/efun/all/file_size +/doc/efun/all/file_name +/domains/campus/txt/ai/charly/bak/fred +/doc/efun/all/file_length +/domains/campus/txt/ai/charly/bak/fgreen +/domains/campus/txt/ai/charly/bak/fblue +/domains/campus/txt/ai/charly/bak/blue_wins +/domains/campus/txt/ai/charles/wins +/domains/campus/txt/ai/charles/switches +/domains/campus/txt/ai/charles/stays +/domains/campus/txt/ai/charles/runs +/domains/campus/txt/ai/charles/red_wins +/domains/campus/txt/ai/charles/percent +/log/enter +/domains/campus/txt/ai/charles/green_wins +/domains/campus/txt/ai/charles/fred +/domains/campus/txt/ai/charles/fgreen +/domains/campus/txt/ai/charles/fblue +/domains/campus/txt/ai/charles/blue_wins +/domains/campus/txt/ai/charles/bak2/wins +/lib/money.c +/secure/sefun/custom_path.c +/domains/campus/txt/ai/charles/bak2/switches +/lib/mount.c +/domains/campus/txt/ai/charles/bak2/stays +/lib/props/description.c +/verbs/items/balance.c +/domains/campus/txt/ai/charles/bak2/runs +/verbs/creators/echo.c +/secure/lib/net/ftp.c +/domains/campus/txt/ai/charles/bak2/red_wins +/secure/sefun/percent.c +/domains/campus/txt/ai/charles/bak2/percent +/lib/events/show.c +/domains/campus/txt/ai/charles/bak2/green_wins +/secure/sefun/query_time_of_day.c +/domains/campus/txt/ai/charles/bak2/fred +/verbs/items/show.c +/domains/campus/txt/ai/charles/bak2/fgreen +/domains/campus/txt/ai/charles/bak2/fblue +/domains/campus/txt/ai/charles/bak2/blue_wins +/domains/campus/txt/ai/charles/bak2/bak1/wins +/domains/campus/txt/ai/charles/bak2/bak1/switches +/domains/campus/txt/ai/charles/bak2/bak1/stays +/domains/campus/txt/ai/charles/bak2/bak1/runs +/domains/campus/txt/ai/charles/bak2/bak1/red_wins +/domains/campus/txt/ai/charles/bak2/bak1/percent +/domains/campus/txt/ai/charles/bak2/bak1/green_wins +/domains/campus/txt/ai/charles/bak2/bak1/fred +/domains/campus/txt/ai/charles/bak2/bak1/fgreen +/domains/campus/txt/ai/charles/bak2/bak1/fblue +/domains/campus/txt/ai/charles/bak2/bak1/blue_wins +/domains/campus/save/jennybot.o +/domains/campus/save/charly.o +/domains/campus/save/charles.o +/domains/campus/room/wiz_lab.c +/domains/campus/room/void.c +/domains/campus/room/usquare.c +/domains/campus/room/uptree.c +/domains/campus/room/u_lab.c +/domains/campus/room/tunnel3.c +/lib/clan.c +/lib/match.c +/domains/campus/room/tunnel2.c +/secure/sefun/reaper.c +/domains/campus/room/tunnel.c +/secure/sefun/domains.c +/domains/campus/room/store2.c +/secure/sefun/copy.c +/domains/campus/room/store.c +/secure/sefun/this_agent.c +/lib/comp/holder.c +/domains/campus/room/start.c +/lib/teller.c +/domains/campus/room/stairwell.c +/lib/history.c +/domains/campus/room/square.c +/domains/campus/room/spath.c +/domains/campus/room/snack.c +/domains/campus/room/slab.c +/domains/campus/room/sewer2.c +/domains/campus/room/sewer1.c +/domains/campus/room/sewer.proto.c +/domains/campus/room/sewer.c +/domains/campus/room/science2.c +/domains/campus/room/science1.c +/domains/campus/room/science.c +/domains/campus/room/red_room3.c +/domains/campus/room/red_room2.c +/domains/campus/room/red_room.c +/domains/campus/room/plab2.c +/domains/campus/room/plab.c +/domains/campus/room/npath2.c +/domains/campus/room/npath.c +/domains/campus/room/monty.c +/domains/campus/room/mailroom.c +/domains/campus/room/lounge.c +/domains/campus/room/hazlab.c +/domains/campus/room/green_room3.c +/domains/campus/room/green_room2.c +/domains/campus/room/green_room.c +/domains/campus/room/furnace.c +/domains/campus/room/freezer.c +/cmds/admins/mfinger.c +/domains/campus/room/foyer.c +/domains/campus/room/death.c +/domains/campus/room/crawlspace.c +/domains/campus/room/corridor4.c +/domains/campus/room/corridor3.c +/domains/campus/room/corridor2.c +/domains/campus/room/corridor.c +/verbs/items/uninstall.c +/verbs/players/target.c +/lib/std/room.c +/verbs/items/empty.c +/secure/sefun/make_workroom.c +/lib/stargate.c +/verbs/items/touch.c +/cmds/players/faq.c +/lib/std/dummy.c +/lib/std/book.c +/lib/bonus.c +/secure/lib/std/access.c +/cmds/admins/dumpallobj.c +/cmds/creators/malloc.c +/domains/Ylsrim/room/vote_hall.c +/domains/campus/room/conf2.c +/domains/campus/room/conf.c +/domains/campus/room/bookstore2.c +/domains/campus/room/bookstore.c +/domains/campus/room/blue_room3.c +/domains/campus/room/blue_room2.c +/domains/campus/room/blue_room.c +/domains/campus/room/basement2.c +/domains/campus/room/basement.c +/domains/campus/room/access9.c +/domains/campus/room/access7.c +/domains/campus/room/access6.c +/domains/campus/room/access5.c +/domains/campus/room/access4.c +/domains/campus/room/access3.c +/domains/campus/room/access2.c +/domains/campus/room/access1.c +/domains/campus/room/access0.c +/verbs/items/dig.c +/secure/sefun/mud_info.c +/domains/campus/obj/yellowbox.c +/lib/quest.c +/domains/campus/obj/wrack.c +/domains/campus/obj/wound.c +/domains/campus/obj/workbench.c +/domains/campus/obj/wlocker.c +/domains/campus/obj/watch.c +/domains/campus/obj/tree.c +/domains/campus/obj/torch.c +/domains/campus/obj/tlocker.c +/domains/campus/obj/thing.c +/domains/campus/obj/stargate.c +/domains/campus/obj/squirtbag.c +/domains/campus/obj/spent.c +/domains/campus/obj/spam.c +/domains/campus/obj/sofa.c +/domains/campus/obj/round.c +/domains/campus/obj/redbox.c +/domains/campus/obj/rayovac.c +/domains/campus/obj/pwatch.c +/domains/campus/obj/podium.c +/domains/campus/obj/pin.c +/domains/campus/obj/pedestal3.c +/domains/campus/obj/pedestal2.c +/domains/campus/obj/pedestal.c +/domains/campus/obj/ped_button.c +/domains/campus/obj/pack.c +/domains/campus/obj/omni.c +/domains/campus/obj/note.c +/domains/campus/obj/medbag.c +/domains/campus/obj/match.c +/domains/campus/obj/map.c +/domains/campus/obj/maglite.c +/domains/campus/obj/magbox.c +/domains/campus/obj/locker.c +/domains/campus/obj/lever.c +/domains/campus/obj/labkey.c +/domains/campus/obj/key1.c +/domains/campus/obj/key.c +/domains/campus/obj/greenbox.c +/domains/campus/obj/flashlight.c +/verbs/items/equate.c +/secure/sefun/get_stack.c +/domains/campus/obj/debris.c +/lib/player.c +/domains/campus/obj/dcell_std.c +/verbs/creators/wizlock.c +/domains/campus/obj/dcell_good.c +/lib/std/bane.c +/verbs/players/news.c +/domains/campus/obj/dcell_crappy.c +/lib/events/buy.c +/domains/campus/obj/dcell.c +/lib/events/press.c +/domains/campus/obj/clip.c +/domains/campus/obj/chair.c +/domains/campus/obj/box.c +/domains/campus/obj/bluebox.c +/domains/campus/obj/bench.c +/cmds/players/consider.c +/domains/campus/obj/bbucket.c +/cmds/players/chancolors.c +/domains/campus/obj/bag.c +/domains/campus/obj/backpack_empty.c +/domains/campus/obj/backpack_civilian.c +/domains/campus/obj/backpack.c +/domains/campus/obj/apple.c +/domains/campus/obj/abox.c +/domains/campus/obj/9mmround.c +/domains/campus/obj/9mmclip.c +/cmds/creators/clone.c +/domains/campus/obj/9mmbox.c +/domains/campus/obj/50round.c +/domains/campus/obj/45round.c +/secure/lib/net/web_client.c +/domains/campus/obj/45case.c +/verbs/items/throw.c +/secure/sefun/wild_card.c +/domains/campus/obj/357shell.c +/lib/props/properties.c +/domains/campus/obj/357round.c +/secure/sefun/user_exists.c +/cmds/players/language.c +/domains/campus/obj/357case.c +/cmds/players/kills.c +/domains/campus/obj/223round.c +/cmds/players/inventory.c +/domains/campus/obj/223clip.c +/domains/campus/npc/yulia.c +/cmds/creators/quell.c +/domains/campus/npc/wim.c +/domains/campus/npc/tim.c +/domains/campus/npc/seth.c +/cmds/creators/trans.c +/lib/lvs/level.c +/domains/campus/npc/rat.c +/lib/vehicle.c +/domains/campus/npc/kim.c +/lib/blank.c +/daemon/tmp/BLUNT.c +/lib/poison.c +/domains/campus/npc/jennybot.c +/verbs/items/press.c +/domains/campus/npc/hans.c +/daemon/tmp/BLADE.c +/verbs/items/get.c +/domains/campus/npc/gloria.c +/daemon/time.c +/verbs/players/mount.c +/domains/campus/npc/dummy.c +/secure/sefun/expand_keys.c +/domains/campus/npc/charly.c +/secure/sefun/local_time.c +/secure/sefun/tail.c +/domains/campus/npc/charles.c +/daemon/tmp/WATER.c +/lib/std/boobytrap_shadow.c +/domains/campus/meals/wimp_ale.c +/secure/sefun/mappings.c +/daemon/tmp/SHOCK.c +/domains/campus/meals/water.c +/lib/trainer.c +/lib/leader.c +/domains/campus/meals/salad.c +/daemon/tmp/R_AIR.c +/lib/props/inventory.c +/domains/campus/meals/milk.c +/daemon/tmp/KNIFE.c +/verbs/rooms/go.c +/lib/npc.c +/domains/campus/meals/ham_sand.c +/lib/std/vendor.c +/cmds/admins/channel.c +/domains/campus/meals/gator.c +/cmds/creators/callouts.c +/lib/files.c +/verbs/items/activate.c +/lib/domesticate.c +/domains/campus/meals/burger.c +/doc/CREDITS +/lib/living.c +/verbs/creators/initfix.c +/domains/campus/meals/bourbon.c +/daemon/weather.c +/domains/campus/meals/badapple.c +/verbs/rooms/cast.c +/domains/campus/meals/apple.c +/cmds/creators/margins.c +/secure/sefun/numbers.c +/domains/campus/meals/ale.c +/secure/sefun/reload.c +/domains/campus/etc/permit.cfg +/secure/sefun/get_cmds.c +/save/intermud.o +/lib/events/smoke.c +/domains/campus/doors/u_door.c +/daemon/tmp/HEAT.c +/lib/language.c +/domains/campus/doors/top_stairs.c +/lib/magic.c +/lib/events/touch.c +/domains/campus/doors/steel_door2.c +/daemon/unique.c +/lib/blank_pile.c +/domains/campus/doors/steel_door.c +/lib/events/put.c +/cmds/players/idle.c +/domains/campus/doors/red_door3.c +/secure/sefun/base_name.c +/cmds/players/hist.c +/verbs/items/put.c +/domains/campus/doors/red_door2.c +/cmds/players/flee.c +/lib/props/body_mass.c +/domains/campus/doors/red_door.c +/secure/sefun/flat_map.c +/domains/campus/doors/prob_door.c +/lib/std/daemon.c +/lib/combatmsg.c +/domains/campus/doors/plain_door.test +/cmds/admins/cache.c +/verbs/players/backstab.c +/lib/flask.c +/domains/campus/doors/plain_door.c +/verbs/players/stand.c +/domains/campus/doors/green_door3.c +/cmds/creators/mraces.c +/verbs/items/use.c +/lib/lamp.c +/domains/campus/doors/green_door2.c +/lib/std/storage.c +/domains/campus/doors/green_door.c +/doc/efun/all/users +/verbs/items/smell.c +/lib/fish.c +/domains/campus/doors/grate.c +/cmds/creators/wizlist.c +/spells/restoration.c +/domains/campus/doors/blue_door3.c +/doc/efun/all/userp +/secure/sefun/legacy.c +/domains/campus/doors/blue_door2.c +/cmds/creators/wiz.c +/domains/campus/doors/blue_door.c +/daemon/tmp/COLD.c +/domains/campus/armor/wizard_hat.c +/domains/campus/armor/wglove_r.c +/daemon/tmp/B_ORB.c +/domains/campus/armor/wglove_l.c +/domains/campus/armor/vest.c +/domains/campus/armor/tshirt.c +/domains/campus/armor/silverring.c +/domains/campus/armor/shirt.c +/doc/efun/all/acos +/domains/campus/armor/shield.c +/domains/campus/armor/robe.c +/domains/campus/armor/ring1.c +/doc/efun/all/TODO +/domains/campus/armor/ring.c +/domains/campus/armor/pillbox_hat.c +/domains/campus/armor/newbie_cap.c +/domains/campus/armor/necklace.c +/domains/campus/armor/jeans.c +/doc/efun/all/nullp +/domains/campus/armor/helmet.c +/domains/campus/armor/handbag.c +/domains/campus/armor/glove.c +/domains/campus/armor/foodsmock.c +/domains/campus/armor/dress.c +/domains/campus/armor/collar.c +/domains/campus/armor/chainmail.c +/doc/efun/all/index +/domains/campus/armor/bluedress.c +/domains/campus/armor/bdu.c +/domains/campus/armor/badge.c +/doc/applies/epilog +/domains/campus/adm/void.c +/domains/campus/adm/pod.c +/domains/campus/adm/furnace.c +/domains/campus/adm/freezer.c +/doc/applies/logon +/domains/campus/adm/death.txt +/doc/applies/init +/domains/campus/adm/cache.c +/domains/campus/adm/access.c +/doc/applies/id +/domains/campus/adm/README +/daemon/decay.c +/doc/applies/flag +/domains/Ylsrim/weapon/stick.c +/domains/Ylsrim/weapon/orc_slayer.c +/cmds/creators/which.c +/cmds/creators/message.c +/domains/Ylsrim/virtual/server.c +/doc/applies/create +/domains/Ylsrim/virtual/desert_map.c +/cmds/creators/showtree.c +/domains/Ylsrim/virtual/desert.c +/doc/applies/crash +/domains/Ylsrim/virtual/README +/daemon/disasters.c +/doc/applies/__INIT +/domains/Ylsrim/room/weaponry_storage.c +/doc/SUPPORT +/domains/Ylsrim/room/weaponry.c +/daemon/bugs.c +/domains/Ylsrim/room/tower.c +/doc/RELEASE_NOTES +/domains/Ylsrim/room/sand_room.c +/domains/Ylsrim/room/sand_hole.c +/domains/Ylsrim/room/s_bazaar.c +/domains/Ylsrim/room/pub.c +/domains/Ylsrim/room/kaliid7.c +/domains/Ylsrim/room/kaliid6.c +/domains/Ylsrim/room/kaliid5.c +/domains/Ylsrim/room/kaliid4.c +/domains/Ylsrim/room/kaliid3.c +/domains/Ylsrim/room/furnace.c +/domains/Ylsrim/room/fighter_hall.c +/domains/Ylsrim/room/fighter.c +/domains/Ylsrim/room/church.c +/domains/Ylsrim/room/bazaar.c +/domains/Ylsrim/room/bank_roof.c +/domains/Ylsrim/room/armory_storage.c +/domains/Ylsrim/room/armory.c +/domains/Ylsrim/room/adv_hall.c +/domains/Ylsrim/obj/stargate.c +/domains/Ylsrim/npc/traveller.c +/domains/Ylsrim/npc/traveler.c +/domains/Ylsrim/npc/shiela.c +/domains/Ylsrim/npc/priest.c +/domains/Ylsrim/npc/max.c +/domains/Ylsrim/npc/lars.c +/domains/Ylsrim/npc/fighter.c +/domains/Ylsrim/npc/balrog.c +/domains/Ylsrim/meal/stew.c +/domains/Ylsrim/meal/shark.c +/cmds/creators/return.c +/domains/Ylsrim/meal/ale.c +/domains/Ylsrim/fish/shark.c +/domains/Ylsrim/etc/wall.c +/cmds/creators/findobj.c +/domains/Ylsrim/etc/torch.c +/domains/Ylsrim/etc/stool.c +/domains/Ylsrim/etc/shovel.c +/domains/Ylsrim/etc/roof_wall.c +/domains/Ylsrim/etc/roof.c +/domains/Ylsrim/etc/road.c +/save/classes.o +/domains/Ylsrim/etc/pole.c +/domains/Ylsrim/etc/match.c +/domains/Ylsrim/etc/key.c +/domains/Ylsrim/etc/hole.c +/domains/Ylsrim/etc/fighter_door.c +/domains/Ylsrim/etc/dug_hole.c +/domains/Ylsrim/etc/church_door.c +/domains/Ylsrim/etc/church_button.c +/domains/Ylsrim/etc/chest.c +/domains/Ylsrim/etc/adv_board.c +/domains/Ylsrim/broken/jar.c +/domains/Ylsrim/broken/flu.c +/domains/Ylsrim/broken/cold.c +/domains/Ylsrim/broken/README +/domains/Ylsrim/armor/shield.c +/domains/Ylsrim/armor/normal_helm.c +/domains/Ylsrim/armor/leather_armor.c +/domains/Ylsrim/armor/helm.c +/domains/Ylsrim/armor/artrell_armor.c +/domains/Ylsrim/adm/void.c +/domains/Ylsrim/adm/freezer.c +/domains/Ylsrim/adm/cache.c +/domains/Ylsrim/adm/access.c +/domains/Ylsrim/adm/README +/domains/Ylsrim/README.old +/domains/Ylsrim/README +/domains/Praxis/yard.c +/domains/Praxis/wild2.c +/domains/Praxis/wild2.backup +/domains/Praxis/wild1.c +/lib/genetics.c +/domains/Praxis/west_road3.c +/lib/std/item.c +/domains/Praxis/west_road2.c +/verbs/common/mail.c +/domains/Praxis/west_road1.c +/lib/events/get.c +/lib/events/fly.c +/domains/Praxis/wall.c +/lib/manycoins.c +/domains/Praxis/w_boc_la3.c +/secure/sefun/automap.c +/domains/Praxis/w_boc_la2.c +/secure/lib/net/server.c +/domains/Praxis/w_boc_la1.c +/domains/Praxis/void.c +/domains/Praxis/unnamed1.c +/domains/Praxis/trunk.c +/domains/Praxis/town_hall.c +/domains/Praxis/torture_room.c +/doc/efun/all/pow +/domains/Praxis/supply2.c +/domains/Praxis/supply.c +/lib/std/base_dummy.c +/domains/Praxis/sun2.c +/domains/Praxis/sun1.c +/verbs/players/sit.c +/domains/Praxis/storage.c +/domains/Praxis/stairs.c +/lib/clip.c +/lib/events/look.c +/verbs/items/poison.c +/doc/help/players/races +/cmds/players/customize.c +/cmds/players/converse.c +/domains/Praxis/square.c +/domains/Praxis/spider_pit.c +/domains/Praxis/sheriff.c +/domains/Praxis/sewer_ent.c +/domains/Praxis/sewer.c +/domains/Praxis/setter.c +/domains/Praxis/sage_room.c +/domains/Praxis/s_centre4.c +/cmds/creators/codeblock.c +/domains/Praxis/s_centre3.c +/daemon/domains.c +/domains/Praxis/s_centre2.c +/domains/Praxis/s_centre1.c +/domains/Praxis/roots.c +/domains/Praxis/rogue_vote.c +/domains/Praxis/rogue_join.c +/domains/Praxis/rogue_hall.c +/domains/Praxis/restaurant.c +/domains/Praxis/realty.c +/secure/sefun/persist.c +/verbs/items/deactivate.c +/domains/Praxis/rain_forest.c +/secure/sefun/log_file.c +/domains/Praxis/quests/zemoch.c +/lib/events/read.c +/doc/applies/privs_file +/secure/lib/net/h_ftpd.c +/domains/Praxis/quests/the_blight_of_the_bog.c +/doc/applies/preload +/secure/sefun/events.c +/domains/Praxis/quests/pyr_quest.c +/verbs/items/buy.c +/doc/applies/parsing/parse_command_plural_id_list +/domains/Praxis/quests/orcslayer.c +/domains/Praxis/quests/imp_crown.c +/doc/applies/parsing/parse_command_id_list +/domains/Praxis/quests/honor.c +/doc/applies/parsing/parse_command_adjectiv_id_list +/domains/Praxis/quests/hellfire.c +/doc/applies/parsing/parse_command +/domains/Praxis/quests/evil.c +/doc/applies/parse_command_prepos_list +/domains/Praxis/quests/dragon.c +/doc/efun/all/cp +/doc/applies/parse_command_plural_id_list +/domains/Praxis/quests/chaucer.c +/doc/applies/parse_command_id_list +/domains/Praxis/quest_room.c +/domains/Praxis/pub.c +/doc/applies/parse_command_all_word +/domains/Praxis/project_room.c +/doc/applies/parse_command_adjectiv_id_list +/domains/Praxis/post.c +/doc/applies/parse_command +/doc/applies/object_name +/domains/Praxis/planning_room.c +/domains/Praxis/pit.c +/doc/applies/net_dead +/domains/Praxis/pier1.c +/doc/applies/move_or_destruct +/domains/Praxis/pass3.c +/doc/applies/master/valid_write +/domains/Praxis/pass2.c +/doc/applies/master/valid_socket +/lib/currency.c +/domains/Praxis/pass1.c +/doc/applies/master/valid_shadow +/secure/sefun/format_page.c +/domains/Praxis/party.c +/doc/applies/master/valid_seteuid +/domains/Praxis/orc_valley/treasure.c +/doc/applies/master/valid_save_binary +/domains/Praxis/orc_valley/shaman.c +/doc/applies/master/valid_read +/domains/Praxis/orc_valley/passage2.c +/doc/applies/master/valid_override +/domains/Praxis/orc_valley/passage1.c +/doc/applies/master/valid_object +/domains/Praxis/orc_valley/open.c +/doc/applies/master/valid_link +/domains/Praxis/orc_valley/guard.c +/doc/applies/master/valid_hide +/domains/Praxis/orc_valley/chamber2.c +/doc/applies/master/valid_compile_to_c +/domains/Praxis/orc_valley/chamber1.c +/doc/applies/master/valid_bind +/domains/Praxis/ombud_hall.c +/doc/applies/master/slow_shutdown +/lib/lvs/abilities.c +/domains/Praxis/obj/weapon/sword.c +/doc/applies/master/save_ed_setup +/secure/sefun/sefun.c +/domains/Praxis/obj/weapon/orc_slayer.c +/doc/applies/master/retrieve_ed_setup +/domains/Praxis/obj/weapon/dagger.c +/doc/applies/master/privs_file +/domains/Praxis/obj/weapon/bow.c +/doc/applies/master/preload +/domains/Praxis/obj/mon/waitress.c +/doc/applies/master/parse_command_prepos_list +/domains/Praxis/obj/mon/unity.c +/doc/applies/master/parse_command_all_word +/domains/Praxis/obj/mon/spider.c +/doc/applies/master/object_name +/domains/Praxis/obj/mon/receptionist.c +/doc/applies/master/make_path_absolute +/domains/Praxis/obj/mon/police.c +/doc/applies/master/log_error +/domains/Praxis/obj/mon/orc_shaman.c +/doc/applies/master/get_save_file_name +/cfg/moons.cfg +/domains/Praxis/obj/mon/mora.c +/doc/applies/master/get_root_uid +/cfg/days.cfg +/domains/Praxis/obj/mon/lars.c +/doc/applies/master/get_bb_uid +/domains/Praxis/obj/mon/knight.c +/cfg/months.cfg +/doc/applies/master/flag +/domains/Praxis/obj/mon/horace.c +/doc/applies/master/error_handler +/domains/Praxis/obj/mon/guard.c +/doc/applies/master/epilog +/domains/Praxis/obj/mon/goblin_fighter.c +/doc/applies/master/domain_file +/doc/applies/master/creator_file +/domains/Praxis/obj/mon/execution_d.c +/doc/applies/master/crash +/domains/Praxis/obj/mon/easter_bunny.c +/doc/applies/master/connect +/domains/Praxis/obj/mon/christmas_bunny.c +/doc/applies/master/compile_object +/domains/Praxis/obj/mon/beggar.c +/doc/applies/master/author_file +/domains/Praxis/obj/mon/balrog.c +/doc/applies/make_path_absolute +/domains/Praxis/obj/mon/atmos.c +/doc/applies/log_error +/domains/Praxis/obj/mon/armageddon.c +/doc/applies/interactive/write_prompt +/domains/Praxis/obj/misc/watchtower.c +/doc/applies/interactive/window_size +/daemon/notify.c +/domains/Praxis/obj/misc/vial.c +/doc/applies/interactive/terminal_type +/domains/Praxis/obj/misc/torch.c +/doc/applies/interactive/telnet_suboption +/domains/Praxis/obj/misc/stone_pile.c +/doc/applies/interactive/receive_snoop +/domains/Praxis/obj/misc/stone.c +/domains/Praxis/obj/misc/stargate.c +/domains/Praxis/obj/misc/shovel.c +/doc/build/Doors +/domains/Praxis/obj/misc/pedestal.c +/domains/Praxis/obj/misc/order.c +/domains/Praxis/obj/misc/match.c +/domains/Praxis/obj/misc/hood.c +/domains/Praxis/obj/misc/handcuffs.c +/domains/Praxis/obj/misc/gallows.c +/domains/Praxis/obj/misc/fishing_pole.c +/domains/Praxis/obj/misc/easter_egg.c +/domains/Praxis/obj/misc/donation.c +/domains/Praxis/obj/misc/deed.c +/domains/Praxis/obj/misc/cold.c +/domains/Praxis/obj/misc/chest.c +/domains/Praxis/obj/misc/bag.c +/domains/Praxis/obj/misc/app_board.c +/domains/Praxis/obj/magic/invis.c +/domains/Praxis/obj/magic/ball.c +/domains/Praxis/obj/armour/helm.c +/domains/Praxis/n_centre2.c +/domains/Praxis/n_centre1.c +/www/versions.html +/www/verbs.html +/domains/Praxis/mudlib.c +/www/value.jpg +/domains/Praxis/mountains/tunnel3.c +/www/style.css +/www/sflogo.php +/domains/Praxis/mountains/tunnel2.c +/www/router_rules.html +/domains/Praxis/mountains/tunnel1.c +/www/router.html +/domains/Praxis/mountains/temp.c +/www/reference.jpg +/www/qcs.html +/domains/Praxis/mountains/entrance.c +/www/news.html +/www/lpuni_afiliated.png +/domains/Praxis/mountains/chamber4.c +/www/lpmuds/xml_topic.js +/domains/Praxis/mountains/chamber3.c +/www/lpmuds/xml_board.js +/domains/Praxis/mountains/chamber2.c +/www/lpmuds/wireless.css +/www/lpmuds/tmi2-faq.html +/domains/Praxis/mountains/chamber1.c +/www/lpmuds/style.css +/domains/Praxis/monk_vote.c +/www/lpmuds/spellcheck.js +/domains/Praxis/monk_join.c +/www/lpmuds/smflogo.gif +/domains/Praxis/monk_hall.c +/www/lpmuds/skylib-faq.html +/domains/Praxis/monastery.c +/www/lpmuds/sitefaq.html +/domains/Praxis/medium.c +/www/lpmuds/sha1.js +/domains/Praxis/mage_vote.c +/www/lpmuds/script.js +/domains/Praxis/mage_join.c +/www/lpmuds/router_debate.html +/domains/Praxis/mage_hall.c +/www/lpmuds/print.css +/domains/Praxis/lpmud_room.c +/www/lpmuds/parch.jpg +/domains/Praxis/lpc_inner.c +/www/lpmuds/merentha-faq.html +/domains/Praxis/locked.c +/www/lpmuds/maintenance.html +/domains/Praxis/library.c +/www/lpmuds/lpmud_list.html +/domains/Praxis/kataan_vote.c +/www/lpmuds/lpmud_faq.html +/domains/Praxis/kataan_join.c +/www/lpmuds/lp_versus_diku.html +/domains/Praxis/kataan_hall.c +/www/lpmuds/links_files/style.css +/domains/Praxis/jungle.c +/www/lpmuds/links_files/smflogo.gif +/domains/Praxis/inn110.c +/domains/Praxis/inn109.c +/www/lpmuds/links_files/script.js +/domains/Praxis/inn108.c +/www/lpmuds/links_files/print.css +/domains/Praxis/inn107.c +/www/lpmuds/links.html +/domains/Praxis/inn106.c +/www/lpmuds/intermud_files/style.css +/domains/Praxis/inn105.c +/domains/Praxis/inn104.c +/www/lpmuds/intermud_files/smflogo.gif +/domains/Praxis/inn103.c +/www/lpmuds/intermud_files/script.js +/domains/Praxis/inn102.c +/domains/Praxis/inn101.c +/www/lpmuds/intermud_files/print.css +/domains/Praxis/immortal_hall.c +/www/lpmuds/intermud_files/mudlist.txt +/domains/Praxis/idle_supply.c +/www/lpmuds/intermud.html +/www/lpmuds/index.html +/domains/Praxis/idle_storage.c +/www/lpmuds/help.css +/domains/Praxis/house.c +/www/lpmuds/forums.html +/domains/Praxis/hotel.c +/cmds/creators/colors.c +/www/lpmuds/forum-faq.html +/domains/Praxis/hospital.c +/domains/Praxis/hole.c +/www/lpmuds/fonts-compat.css +/www/lpmuds/favicon.ico +/domains/Praxis/hm_chamber.c +/www/lpmuds/favico.ico +/domains/Praxis/highway3.c +/www/lpmuds/fader.js +/domains/Praxis/highway2.c +/domains/Praxis/highway1.c +/www/lpmuds/downloads_files/style.css +/domains/Praxis/hall5.c +/www/lpmuds/downloads_files/smflogo.gif +/domains/Praxis/hall4.c +/domains/Praxis/hall3.c +/www/lpmuds/downloads_files/script.js +/domains/Praxis/hall2.c +/www/lpmuds/downloads_files/print.css +/domains/Praxis/hall.c +/www/lpmuds/downloads.html +/domains/Praxis/freezer.c +/www/lpmuds/discworld-faq.html +/domains/Praxis/forest3.c +/www/lpmuds/dead_souls.png +/domains/Praxis/forest2.c +/www/lpmuds/arren_router.html +/domains/Praxis/forest1.c +/verbs/players/dismount.c +/www/lpmuds/alternate_router.html +/domains/Praxis/fighter_vote.c +/verbs/items/lock.c +/www/issues.html +/verbs/items/eat.c +/domains/Praxis/fighter_join.c +/www/index.html +/domains/Praxis/fighter_hall.c +/www/images/lpuni_afiliated.png +/domains/Praxis/farm.c +/www/images/Thumbs.db +/www/hotfix.html +/domains/Praxis/east_road3.c +/www/function.jpg +/domains/Praxis/east_road2.c +/www/fixes.html +/www/favicon.ico +/domains/Praxis/east_road1.c +/www/example.html +/domains/Praxis/e_boc_la3.c +/www/errors/notfound.html +/domains/Praxis/e_boc_la2.c +/www/errors/badgate.html +/domains/Praxis/e_boc_la1.c +/www/errors/badcmd.html +/domains/Praxis/dump.c +/www/editor.html +/www/ds2.1.html +/domains/Praxis/death/death_room.c +/domains/Praxis/data/wall.o +/www/ds-inst-faq_files/style.css +/domains/Praxis/data/properties.t +/www/ds-inst-faq.html +/www/ds-faq.html +/domains/Praxis/data/properties.o +/www/ds-creator-faq_files/value.jpg +/domains/Praxis/data/cleric_crypt.o +/www/ds-creator-faq_files/reference.jpg +/domains/Praxis/data/booth_votes.o +/domains/Praxis/data/booth_question +/www/ds-creator-faq_files/function.jpg +/www/ds-creator-faq.html +/domains/Praxis/crypt.c +/www/ds-admin-faq.html +/domains/Praxis/court_room.c +/www/ds-II-faq.html +/domains/Praxis/council_vote.c +/www/downloads.html +/www/demo.html +/domains/Praxis/council_hall.c +/www/debugging.html +/domains/Praxis/council.c +/www/barrel.html +/domains/Praxis/commands +/www/articles/why_ds.html +/domains/Praxis/cleric_vote.c +/www/articles/tms.html +/news/admin +/www/articles/tacitus2.html +/domains/Praxis/cleric_join.c +/www/articles/tacitus.html +/domains/Praxis/cleric_hall.c +/news/creator +/www/articles/router_controversy.html +/domains/Praxis/cemetery/mon/ghosta.c +/www/articles/renaissance.html +/domains/Praxis/cemetery/mon/ghost9.c +/www/articles/patches.html +/news/avatar +/domains/Praxis/cemetery/mon/ghost8.c +/www/articles/olc.html +/www/articles/mudmagic.html +/domains/Praxis/cemetery/mon/ghost6.c +/www/articles/lpu.html +/domains/Praxis/cemetery/mon/ghost5.c +/news/hm +/www/articles/lpmuds.html +/domains/Praxis/cemetery/mon/ghost4.c +/www/articles/forum_chat.html +/cmds/creators/boards.c +/www/articles/favicon.ico +/domains/Praxis/cemetery/mon/ghost3.c +/www/articles/copyright.old +/domains/Praxis/cemetery/mon/ghost.c +/www/articles/copyright.html +/cmds/admins/fdinfo.c +/domains/Praxis/cemetery/grave_yard8.c +/www/articles.html +/verbs/rooms/include/stop.h +/domains/Praxis/cemetery/grave_yard7.c +/secure/cfg/groups.cfg +/news/newbie +/verbs/rooms/include/sell.h +/domains/Praxis/cemetery/grave_yard6.c +/verbs/rooms/include/jump.h +/verbs/rooms/include/go.h +/domains/Praxis/cemetery/grave_yard5.c +/verbs/rooms/include/fly.h +/domains/Praxis/cemetery/grave_yard4.c +/verbs/rooms/include/fish.h +/domains/Praxis/cemetery/grave_yard3.c +/verbs/rooms/include/enter.h +/domains/Praxis/cemetery/grave_yard2.c +/verbs/rooms/include/climb.h +/verbs/rooms/include/cast.h +/secure/tmp/files.txt +/domains/Praxis/cemetery/grave_yard.c +/verbs/rooms/include/buy.h +/secure/tmp/dirs.txt +/verbs/players/include/withdraw.h +/verbs/players/include/vote.h +/verbs/players/include/target.h +/verbs/players/include/stealth.h +/verbs/players/include/request.h +/verbs/players/include/party.h +/verbs/players/include/nominate.h +/verbs/players/include/news.h +/verbs/players/include/marry.h +/verbs/players/include/lead.h +/verbs/players/include/follow.h +/doc/faq/admin +/verbs/players/include/evade.h +/cmds/players/automap.c +/verbs/players/include/describe.h +/verbs/players/include/crawl.h +/verbs/players/include/bump.h +/doc/efun/all/crc32 +/verbs/players/include/backstab2.h +/verbs/players/include/backstab.h +/verbs/players/include/attack.h +/cmds/creators/reset.c +/verbs/players/include/SCCS/s.withdraw.h +/verbs/players/include/SCCS/s.vote.h +/verbs/players/include/SCCS/s.nominate.h +/doc/efun/all/bind +/save/notify.o +/verbs/players/include/,withdraw.h +/verbs/players/include/,vote.h +/verbs/players/include/,nominate.h +/doc/efun/all/atan +/doc/efun/all/asin +/cmds/creators/replog.c +/doc/efun/all/sin +/doc/build/Weapons +/doc/build/Vendors +/doc/build/Towns +/std/README +/secure/sefun/files.c +/secure/lib/net/client.c +/lib/std/story.c +/doc/build/Rooms +/secure/sefun/strings.c +/verbs/common/ask.c +/lib/events/climb.c +/lib/std/bot_corpse.c +/lib/battery.c +/doc/build/Quests +/cmds/creators/realms.c +/cmds/creators/morse.c +/doc/build/NPC +/secure/lib/connect.first.c +/lib/props/damage.c +/verbs/creators/modify.c +/verbs/items/pull.c +/news/general +/daemon/tmp/A_CUSTOM.c +/daemon/tmp/A_COLLAR.c +/daemon/tmp/A_CLOAK.c +/daemon/tmp/A_BOOT.c +/daemon/tmp/A_BODY_ARMOR.c +/daemon/tmp/A_BELT.c +/daemon/tmp/A_ARMOR.c +/daemon/tmp/A_AMULET.c +/daemon/statistics.c +/daemon/services/who.c +/daemon/services/tell.c +/daemon/services/oob.c +/daemon/services/locate.c +/daemon/services/finger.c +/daemon/services/error.c +/daemon/services/emoteto.c +/daemon/services/channel.c +/daemon/services/auth.c +/daemon/include/verbs.h +/daemon/include/time.h +/daemon/include/statistics.h +/daemon/include/stargate.h +/daemon/include/seasons.h +/daemon/include/races.h +/daemon/include/party.h +/daemon/include/notify.h +/daemon/include/news.h +/daemon/include/intermud.h +/daemon/include/http.h +/daemon/include/ftp_port_tracker.h +/daemon/include/command.h +/daemon/include/classes.h +/daemon/include/chat.h +/daemon/include/bugs.h +/daemon/ftp_port_tracker.c +/cmds/players/xyzzy.c +/cmds/players/wimpy.c +/cmds/players/version.c +/cmds/players/users.c +/cmds/players/uptime.c +/cmds/players/unmuff.c +/cmds/players/title.c +/cmds/players/terminal.c +/cmds/players/status.c +/cmds/players/stats.c +/cmds/players/stat.c +/cmds/players/spells.c +/cmds/players/speakcolor.c +/cmds/creators/polyglottize.c +/cmds/players/skills.c +/verbs/items/include/wield.h +/daemon/soul.c +/cmds/players/screen.c +/verbs/items/include/wear.h +/cmds/players/score.c +/verbs/items/include/use.h +/daemon/services.c +/verbs/items/include/unwield.h +/daemon/terminal.c +/verbs/items/include/unlock.h +/verbs/items/include/throw.h +/verbs/items/include/strike.h +/verbs/items/include/steal.h +/cmds/creators/tellblock.c +/verbs/items/include/smell.h +/daemon/seasons.c +/verbs/items/include/show.h +/verbs/items/include/search.h +/cmds/creators/ping.c +/verbs/items/include/remove.h +/verbs/items/include/read.h +/verbs/items/include/put.h +/verbs/items/include/poison.h +/doc/efun/all/fetch_variable +/verbs/items/include/pick.h +/verbs/items/include/open.h +/doc/efun/all/external_start +/doc/efun/all/export_uid +/verbs/items/include/look.h +/verbs/items/include/lock.h +/doc/efun/all/explode +/doc/efun/all/evaluate +/verbs/items/include/light.h +/doc/efun/all/eval_cost +/verbs/items/include/judge.h +/doc/efun/all/environment +/verbs/items/include/give.h +/doc/efun/all/enable_wizard +/verbs/items/include/get.h +/doc/efun/all/floor +/doc/efun/all/enable_commands +/daemon/reaper.c +/verbs/items/include/extinguish.h +/doc/efun/all/ed_start +/daemon/spells.c +/verbs/items/include/eat.h +/doc/efun/all/ed_cmd +/verbs/items/include/drop.h +/doc/efun/all/dumpallobj +/daemon/races.c +/verbs/items/include/drink.h +/doc/efun/all/exp +/doc/efun/all/dump_socket_status +/verbs/items/include/dig.h +/doc/efun/all/dump_prog +/doc/applies/interactive/receive_message +/verbs/items/include/close.h +/doc/efun/all/dump_file_descriptors +/doc/applies/interactive/process_input +/verbs/items/include/bury.h +/doc/efun/all/domain_stats +/doc/applies/interactive/net_dead +/verbs/items/include/balance.h +/doc/efun/all/disable_wizard +/doc/applies/interactive/logon +/daemon/party.c +/verbs/items/include/bait.h +/doc/efun/all/disable_commands +/doc/applies/interactive/catch_tell +/verbs/creators/include/echo.h +/doc/efun/all/destruct +/doc/applies/heart_beat +/verbs/creators/include/codesay.h +/doc/efun/all/deep_inventory +/doc/applies/get_save_file_name +/verbs/common/include/yell.h +/doc/efun/all/deep_inherit_list +/doc/applies/get_root_uid +/verbs/common/include/whisper.h +/doc/efun/all/debugmalloc +/doc/applies/get_bb_uid +/verbs/common/include/speak.h +/doc/efun/all/debug_message +/doc/efun/all/ctime +/doc/applies/error_handler +/doc/efun/all/debug_info +/verbs/common/include/shout.h +/doc/applies/domain_file +/verbs/common/include/say.h +/doc/efun/all/commands +/doc/applies/creator_file +/doc/efun/all/command +/verbs/common/include/mail.h +/doc/applies/connect +/doc/efun/all/clonep +/doc/applies/compile_object +/verbs/common/include/help.h +/doc/efun/all/clone_object +/doc/applies/clean_up +/verbs/common/include/ask.h +/doc/efun/all/clear_bit +/doc/applies/catch_tell +/verbs/admins/include/adverb.h +/doc/efun/all/classp +/doc/applies/author_file +/tmp/showfuns.o +/doc/efun/all/children +/doc/RELEASE_NOTES_HTTP +/std/wiz_hall.c +/doc/efun/all/check_memory +/std/quest_ob.c +/daemon/tmp/S_VERY_SMALL.c +/std/prop_logic.c +/doc/efun/all/capitalize +/daemon/tmp/S_TINY.c +/std/monster.c +/doc/efun/all/call_stack +/daemon/tmp/S_SOMEWHAT_SMALL.c +/std/lib/pile.c +/doc/efun/all/call_out_info +/std/furnace.c +/daemon/tmp/S_SOMEWHAT_LARGE.c +/doc/efun/all/call_out +/std/freezer.c +/daemon/tmp/S_SMALL.c +/std/estate.c +/doc/efun/all/call_other +/daemon/tmp/S_MINISCULE.c +/std/death.c +/doc/efun/all/cache_stats +/std/board/bboard.c +/daemon/tmp/S_LARGE.c +/doc/efun/all/bufferp +/shadows/ring.c +/daemon/tmp/S_HUMAN_SIZED.c +/doc/efun/all/author_stats +/shadows/needle_trap.c +/daemon/tmp/S_HUGE.c +/doc/efun/all/arrayp +/shadows/explosive_trap.c +/daemon/tmp/S_GIGANTIC.c +/shadows/drone.c +/doc/efun/all/allocate_mapping +/daemon/tmp/R_WATER.c +/shadows/diag.c +/doc/efun/all/allocate_buffer +/daemon/tmp/R_VACUUM.c +/shadows/bear.c +/daemon/tmp/R_AIR+R_WATER.c +/secure/verbs/creators/force.c +/daemon/tmp/B_WINGED_MAN.c +/secure/tmp/cratylus_CMD_EVAL_TMP_FILE.c +/daemon/tmp/B_TREE.c +/secure/sefun/sefun.h +/daemon/tmp/B_SPECTRAL.c +/secure/scripts/upgrades.txt +/daemon/tmp/B_SNAKE.c +/secure/scripts/update.src +/daemon/tmp/B_SEMI_BIPEDAL.c +/secure/scripts/sky.lsed +/daemon/tmp/B_QUADRUPED.c +/secure/scripts/qcs_check.txt +/daemon/tmp/B_PLANT.c +/secure/scripts/nm3.lsed +/daemon/tmp/B_NEBULOUS.c +/secure/scripts/indent.src +/daemon/tmp/B_INSECTOID.c +/daemon/tmp/B_HUMANOID.c +/secure/scripts/general_check.txt +/secure/scripts/crat2.src +/daemon/tmp/B_GASTROPOD.c +/daemon/tmp/B_FISH.c +/secure/scripts/crat.src +/secure/room/router.c +/daemon/tmp/B_CHIROPTEROID.c +/secure/room/arch.c +/daemon/tmp/B_CHIMAERA.c +/secure/obj/tc.c +/secure/obj/staff.c +/daemon/tmp/B_BIPED+B_INSECTOID.c +/daemon/tmp/A_WEAPON.c +/secure/obj/snooper.c +/secure/obj/robot.c +/daemon/tmp/A_VISOR.c +/secure/obj/replacer.c +/daemon/tmp/A_VEST.c +/secure/obj/post.c +/daemon/tmp/A_SOCK.c +/secure/obj/mojo.c +/daemon/tmp/A_SHIRT.c +/secure/obj/memo.c +/daemon/tmp/A_SHIELD.c +/secure/obj/medtric.c +/daemon/tmp/A_RING.c +/secure/obj/meditate_mojo.c +/daemon/tmp/A_PANTS.c +/secure/obj/machine.c +/daemon/tmp/A_LONG_SOCK.c +/secure/obj/include/roommaker.h +/daemon/tmp/A_LONG_GLOVE.c +/secure/obj/include/post.h +/daemon/tmp/A_LONG_BOOT.c +/secure/obj/include/gossip_folder.h +/daemon/tmp/A_HELMET.c +/secure/obj/glasses.c +/daemon/tmp/A_GLOVE.c +/secure/obj/control.c +/secure/obj/arch_board.c +/secure/npc/drone.c +/secure/npc/cambot.c +/secure/modules/room.c +/secure/modules/read.c +/secure/modules/money.c +/secure/modules/mapping.c +/secure/modules/generic.c +/secure/modules/file.c +/secure/modules/door.c +/secure/modules/create.c +/include/body_types.h +/secure/modules/armor.c +/include/respiration_types.h +/secure/lib/net/include/h_ftpd.h +/include/size_types.h +/secure/lib/net/include/ftp.h +/include/terrain_types.h +/include/position.h +/save/banish.o +/domains/Praxis/chapel.c +/domains/Praxis/cache.c +/news/register +/domains/Praxis/building.c +/domains/Praxis/branches.c +/domains/Praxis/booth.c +/domains/Praxis/bank_vault.c +/domains/Praxis/bank.c +/domains/Praxis/attic/tmp_hos +/domains/Praxis/attic/class_change.c +/domains/Praxis/arch.c +/domains/Praxis/app_room.c +/domains/Praxis/alley2.c +/domains/Praxis/alley1.c +/domains/Praxis/adv_main.c +/domains/Praxis/adv_inner.c +/domains/Praxis/adm/master.c +/domains/Praxis/adm/access.c +/domains/Praxis/README +/doc/sefun/year +/doc/sefun/write +/doc/sefun/wrap +/doc/sefun/version +/doc/sefun/user_path +/cmds/creators/anglicize.c +/doc/sefun/user_exists +/doc/sefun/unguarded +/doc/sefun/true +/doc/sefun/translate +/doc/sefun/total_light +/doc/sefun/tell_player +/doc/sefun/tell_object +/doc/efun/all/new +/doc/sefun/tail +/doc/sefun/strip_colours +/doc/sefun/starts_with +/doc/sefun/snoop +/doc/sefun/shutdown +/doc/sefun/shout +/doc/sefun/set_privs +/doc/sefun/set_eval_limit +/doc/sefun/season +/doc/sefun/say +/doc/sefun/reverse_string +/doc/sefun/replace_matching_line +/doc/sefun/replace_line +/doc/sefun/remove_sky_event +/doc/sefun/remove_matching_line +/secure/lib/net/http.c +/lib/shadow_hook.c +/doc/sefun/reflexive +/lib/enter.c +/doc/sefun/reap_dummies +/verbs/items/bait.c +/doc/sefun/read_database +/lib/events/activate.c +/doc/sefun/query_snooping +/lib/comp/object.c +/doc/sefun/query_snoop +/verbs/items/judge1.c +/doc/sefun/query_night +/lib/props/save.c +/doc/sefun/query_host_port +/doc/sefun/query_custom_path +/doc/sefun/query_custom_command +/doc/sefun/possessive_noun +/doc/sefun/possessive +/doc/sefun/pluralize +/doc/sefun/percent +/doc/sefun/path_prefix +/cmds/creators/unquell.c +/doc/sefun/path_file +/doc/efun/all/allocate +/doc/efun/all/crypt +/doc/efun/all/all_previous_objects +/doc/efun/all/all_inventory +/doc/efun/all/cos +/doc/efun/all/add_action +/doc/build/Sentients +/doc/build/Properties +/doc/build/Introduction +/doc/build/Guidelines +/doc/applies/write_prompt +/doc/applies/window_size +/doc/applies/valid_write +/doc/applies/valid_socket +/doc/applies/valid_shadow +/doc/applies/valid_seteuid +/doc/applies/valid_save_binary +/doc/applies/valid_read +/doc/applies/valid_override +/doc/applies/valid_object +/doc/applies/valid_link +/doc/applies/valid_hide +/doc/applies/valid_compile_to_c +/doc/applies/valid_bind +/doc/applies/terminal_type +/doc/applies/telnet_suboption +/doc/applies/slow_shutdown +/doc/applies/save_ed_setup +/doc/applies/retrieve_ed_setup +/doc/applies/receive_snoop +/doc/applies/receive_message +/doc/applies/process_input +/cmds/creators/events.c +/secure/lib/include/connect.h +/secure/lib/include/bboard.h +/secure/lib/connect.real +/secure/include/voting.h +/secure/include/virtual.h +/secure/include/user.h +/secure/include/type.h +/secure/include/std.h +/secure/include/sockets.h +/secure/include/socket_err.h +/secure/include/socket.h +/secure/include/save.h +/secure/include/runtime_config.h +/secure/include/rooms.h +/doc/efun/all/exec +/secure/include/rcp.h +/secure/include/props.h +/secure/include/privs.h +/secure/include/pov.h +/secure/include/post.h +/doc/efun/all/say +/secure/include/parser_error.h +/secure/include/parse_com.h +/cmds/creators/vis.c +/secure/include/origin.h +/secure/include/objects.h +/secure/include/object.h +/secure/include/news.h +/secure/include/network.h +/secure/include/mudlib.h +/secure/include/modules.h +/secure/include/lvs.h +/secure/include/localtime.h +/secure/include/link.h +/secure/include/lib.h +/secure/include/iips.h +/secure/include/global.h +/secure/include/function.h +/secure/include/flags.h +/secure/include/files.h +/www/mudlist.txt +/secure/include/events.h +/secure/include/dirs.h +/include/meal_types.h +/include/damage_types.h +/secure/include/deputies.h +/secure/include/daemons.h +/include/vendor_types.h +/include/armor_types.h +/secure/include/council.h +/secure/include/compat.h +/secure/include/comp.h +/secure/include/commands.h +/secure/include/clock.h +/tmp/muds.txt +/secure/include/clean_up.h +/secure/include/cfg.h +/secure/include/bboard.h +/secure/daemon/wget.c +/secure/daemon/voting.c +/secure/daemon/update.patch +/secure/daemon/update.c +/secure/daemon/update.blank +/secure/daemon/translation.c +/secure/daemon/snoop.c +/lib/props/value.c +/secure/sefun/ascii.c +/secure/daemon/remotepost.h +/secure/daemon/remotepost.c +/secure/daemon/reload.c +/secure/daemon/preload_check.c +/secure/daemon/politics.c +/secure/daemon/ping.c +/secure/daemon/persistence.c +/secure/daemon/options.h +/secure/daemon/options.c +/secure/daemon/oob.c +/secure/daemon/master.h +/secure/daemon/log.c +/secure/daemon/localpost.h +/secure/daemon/localpost.c +/secure/daemon/letters.h +/secure/daemon/letters.c +/secure/daemon/inet.c +/secure/daemon/include/imc2_code.h +/secure/daemon/include/estates.h +/lib/post_office.c +/verbs/items/light.c +/secure/daemon/include/chat.h +/verbs/items/disarm.c +/secure/daemon/include/character.h +/doc/sefun/ordinal +/secure/daemon/i3router/server_log.h +/doc/sefun/objective +/secure/daemon/i3router/server.c +/doc/sefun/nominative +/doc/sefun/mudlib_version +/secure/daemon/i3router/send_startup_reply.h +/doc/sefun/mudlib +/doc/sefun/mud_name +/secure/daemon/i3router/send_mudlist_updates.h +/doc/sefun/mud_currencies +/doc/sefun/moon_light +/secure/daemon/i3router/send_full_mudlist.h +/doc/sefun/month +/secure/daemon/i3router/send_error.h +/doc/sefun/minutes +/doc/sefun/memberp +/secure/daemon/i3router/send_chanlist_reply.h +/doc/sefun/member_group +/secure/daemon/i3router/rsocket.c +/doc/sefun/log_file +/doc/sefun/local_time +/secure/daemon/i3router/remove_mud.h +/doc/sefun/load_object +/secure/daemon/i3router/readme.txt +/doc/sefun/livings +/doc/sefun/leaderp +/secure/daemon/i3router/read_callback.h +/doc/sefun/last_string_element +/secure/daemon/i3router/process_startup_req.h +/doc/sefun/last +/doc/sefun/indent_file +/secure/daemon/i3router/process_channel.h +/doc/sefun/identify +/doc/sefun/hour +/secure/daemon/i3router/irn.h +/doc/sefun/high_mortalp +/secure/daemon/i3router/hosted_channels.h +/doc/sefun/hiddenp +/secure/daemon/i3router/funcs.h +/doc/sefun/grepp +/doc/sefun/get_verbs +/secure/daemon/i3router/debug.h +/doc/sefun/get_random_living +/secure/daemon/i3router/core_stuff.h +/doc/sefun/get_object +/secure/daemon/i3router/clean_fd.h +/doc/sefun/get_livings +/doc/sefun/get_cmds +/secure/daemon/i3router/broadcast_mudlist.h +/doc/sefun/generate_tmp +/doc/faq/general +/secure/daemon/i3router/broadcast_chanlist.h +/doc/sefun/format_string +/cmds/players/equipment.c +/doc/sefun/format_page +/secure/daemon/i3router/blacklist.cfg +/cmds/players/emote.c +/doc/sefun/flat_map +/secure/daemon/function.c +/doc/sefun/first_string_element +/secure/daemon/folders.h +/doc/sefun/first +/secure/daemon/folders.c +/doc/sefun/file_privs +/secure/daemon/finger.h +/doc/sefun/file_exists +/secure/daemon/finger.c +/doc/sefun/false +/secure/daemon/filter.c +/doc/sefun/exec +/secure/daemon/file.c +/doc/sefun/exclude_array +/secure/daemon/events.h +/doc/sefun/event_pending +/secure/daemon/events.c +/doc/sefun/event +/doc/sefun/effective_light +/secure/daemon/estates.c +/secure/daemon/economy.c +/doc/sefun/domain_master +/doc/sefun/domain_exists +/secure/daemon/chat.c +/doc/sefun/domain +/cmds/creators/include/SCCS/s.showtree.h +/secure/daemon/character.c +/doc/sefun/distinct_array +/secure/daemon/bboard.h +/doc/sefun/destruct +/secure/daemon/bakchat2 +/doc/sefun/debug +/secure/daemon/bakchat +/doc/sefun/day +/secure/daemon/autoexec.c +/doc/sefun/date +/doc/sefun/currency_value +/secure/sefun/communications.c +/secure/daemon/alchemist.c +/verbs/items/donate.c +/secure/cmds/players/tell.c +/doc/sefun/currency_rate +/doc/sefun/currency_mass +/verbs/players/follow.c +/secure/cmds/players/suicide.c +/verbs/creators/add.c +/doc/sefun/currency_inflation +/doc/efun/all/stat +/secure/cmds/players/reply.c +/doc/sefun/copy +/secure/sefun/ordinal.c +/secure/cmds/players/praise.c +/verbs/players/marry.c +/doc/sefun/convert_name +/secure/cmds/players/peer.c +/doc/sefun/convert_ascii +/verbs/creators/copy.c +/secure/cmds/players/passwd.c +/doc/sefun/consolidate +/secure/cmds/players/mc.c +/doc/sefun/conjunction +/cmds/creators/i3who.c +/doc/sefun/check_privs +/secure/cmds/players/include/passwd.h +/doc/sefun/center +/secure/cmds/players/history.c +/doc/sefun/cardinal +/doc/sefun/base_name +/cmds/creators/format.c +/secure/cmds/players/finger.c +/secure/cmds/players/chfn.c +/doc/sefun/arrange_string +/doc/sefun/archp +/secure/cmds/players/bug.c +/doc/sefun/architecture +/doc/build/ed.hup +/secure/cmds/players/afk.c +/doc/sefun/answers_to +/secure/cmds/creators/update.c +/doc/sefun/ambassadorp +/secure/cmds/creators/unsnoop.c +/doc/sefun/alignment_string +/secure/cmds/creators/trace.c +/doc/sefun/alignment_ok +/cmds/creators/goto.c +/secure/cmds/creators/tail.c +/doc/sefun/add_sky_event +/doc/sefun/absolute_value +/secure/cmds/creators/source.c +/cmds/creators/include/showtree.h +/doc/sefun/absolute_path +/secure/cmds/creators/snoop.c +/doc/old/RELEASE_NOTES.old +/secure/cmds/creators/showfuns.c +/doc/old/README +/doc/old/CHANGES +/secure/cmds/creators/rmdir.c +/doc/misc/ed.txt +/secure/cmds/creators/rm.c +/doc/manual/chapter40 +/secure/cmds/creators/restore.c +/doc/manual/chapter39 +/secure/cmds/creators/qed.c +/doc/manual/chapter38 +/secure/cmds/creators/people.c +/doc/manual/chapter37 +/obj/deed.c +/secure/cmds/creators/mv.c +/doc/manual/chapter36 +/doc/manual/chapter35 +/secure/cmds/creators/mudtime.c +/doc/manual/chapter34 +/secure/cmds/creators/more.c +/doc/manual/chapter33 +/secure/cmds/creators/monitor.c +/doc/manual/chapter32 +/secure/cmds/creators/mkdir.c +/doc/manual/chapter31 +/secure/cmds/creators/memcheck.c +/doc/manual/chapter30 +/doc/manual/chapter29 +/secure/cmds/creators/lsed.c +/secure/cmds/creators/ls.c +/doc/manual/chapter28 +/doc/manual/chapter27 +/secure/cmds/creators/longcat.c +/doc/manual/chapter26 +/secure/cmds/creators/log.c +/doc/manual/chapter25 +/secure/cmds/creators/localcmds.c +/doc/manual/chapter24 +/doc/efun/all/swap +/secure/cmds/creators/isql.c +/doc/manual/chapter23 +/secure/cmds/creators/indent.c +/doc/manual/chapter22 +/doc/manual/chapter21 +/secure/cmds/creators/include/more.h +/doc/manual/chapter20 +/secure/cmds/creators/include/gg.h +/doc/manual/chapter19 +/secure/cmds/creators/include/create.h +/doc/manual/chapter18 +/doc/manual/chapter17 +/secure/cmds/creators/imc2.c +/doc/manual/chapter16 +/secure/cmds/creators/home.c +/doc/manual/chapter15 +/secure/cmds/creators/heal.c +/doc/manual/chapter14 +/secure/cmds/creators/head.c +/log/catch +/doc/manual/chapter13 +/secure/cmds/creators/grep.c +/doc/manual/chapter12 +/doc/manual/chapter11 +/secure/cmds/creators/grant.c +/doc/manual/chapter10 +/secure/cmds/creators/gauge.c +/news/locked +/doc/manual/chapter09 +/secure/cmds/creators/flushobs.c +/doc/manual/chapter08 +/secure/cmds/creators/findfun.c +/doc/manual/chapter07 +/secure/cmds/creators/eval.c +/doc/manual/chapter06 +/secure/cmds/creators/ed.c +/doc/manual/chapter05 +/log/runtime +/secure/cmds/creators/economy.c +/doc/manual/chapter04 +/doc/manual/chapter03 +/secure/cmds/creators/dsversion.c +/doc/manual/chapter02 +/secure/cmds/creators/diff.c +/doc/manual/chapter01 +/secure/cmds/creators/dbxwhere.c +/doc/lpc/types/mappings +/secure/cmds/creators/dbxframe.c +/doc/lpc/types/general +/secure/cmds/creators/create.c +/doc/lpc/types/function +/doc/lpc/types/float +/secure/cmds/creators/cp.c +/doc/lpc/types/buffer +/secure/cmds/creators/changelog.c +/doc/lpc/types/array.2d +/secure/cmds/creators/cd.c +/doc/lpc/intermediate/chapter7 +/daemon/meetings.c +/secure/cmds/creators/cat.c +/doc/lpc/intermediate/chapter6 +/secure/cmds/creators/call.c +/secure/cmds/creators/bk.c +/doc/lpc/intermediate/chapter5 +/secure/cmds/creators/about.c +/doc/lpc/intermediate/chapter4 +/secure/cmds/admins/whowatched.c +/doc/lpc/intermediate/chapter3 +/secure/cmds/admins/whoregistered.c +/doc/lpc/intermediate/chapter2 +/secure/cmds/admins/whoguests.c +/doc/lpc/intermediate/chapter1 +/log/crashes +/secure/cmds/admins/whobanished.c +/doc/lpc/intermediate/Copyright +/secure/cmds/admins/whoallowed.c +/doc/lpc/intermediate/Contents +/secure/cmds/admins/watch.c +/doc/lpc/etc/error_msgs +/secure/cmds/admins/usage.c +/doc/lpc/constructs/while +/secure/cmds/admins/unwatch.c +/doc/lpc/constructs/switch +/secure/cmds/admins/unrid.c +/doc/lpc/constructs/prototypes +/doc/lpc/constructs/inherit +/secure/cmds/admins/unregister.c +/doc/lpc/constructs/include +/secure/cmds/admins/unpause.c +/doc/lpc/constructs/if +/secure/cmds/admins/unmonitor.c +/doc/lpc/constructs/function +/secure/cmds/admins/unlink.c +/doc/lpc/constructs/for +/secure/cmds/admins/unbanish.c +/doc/lpc/concepts/socket_efuns +/secure/cmds/admins/unallow.c +/doc/lpc/concepts/simul_efun +/secure/cmds/admins/ticktock.c +/doc/lpc/concepts/preprocessor +/secure/cmds/admins/tempban.c +/doc/lpc/concepts/oop +/secure/cmds/admins/switchrouter.c +/doc/lpc/concepts/objects +/secure/cmds/admins/stupidemote.c +/doc/lpc/concepts/message_doc +/doc/lpc/concepts/lpc +/secure/cmds/admins/statconvert.c +/doc/lpc/concepts/defines +/secure/cmds/admins/snoopreport.c +/doc/lpc/concepts/MudOSdriver +/secure/cmds/admins/shutdown.c +/doc/lpc/basic/chapter8 +/secure/cmds/admins/setreboot.c +/doc/lpc/basic/chapter7 +/secure/cmds/admins/sconv.c +/doc/lpc/basic/chapter6 +/secure/cmds/admins/router.c +/doc/lpc/basic/chapter5 +/secure/cmds/admins/rid.c +/doc/lpc/basic/chapter4 +/secure/cmds/admins/resetpasswd.c +/doc/lpc/basic/chapter3 +/doc/lpc/basic/chapter2 +/secure/cmds/admins/resetall.c +/doc/lpc/basic/chapter1 +/secure/cmds/admins/removeraces.c +/doc/lpc/basic/Introduction +/secure/cmds/admins/removerace.c +/doc/lpc/basic/Contents +/secure/cmds/admins/removeguest.c +/doc/lfun/lib/worn_storage/eventReceiveDamage +/secure/cmds/admins/removeemote.c +/doc/lfun/lib/worn_storage/SetFingers +/secure/cmds/admins/removeclass.c +/secure/cmds/admins/removeadverb.c +/doc/lfun/lib/worn_storage/GetFingers +/secure/cmds/admins/register.c +/doc/lfun/lib/weapon/GetWielded +/secure/cmds/admins/pause.c +/doc/lfun/lib/virt_sky/CanFly +/secure/cmds/admins/opcprof.c +/doc/lfun/lib/vendor/eventBuy +/secure/cmds/admins/notify.c +/doc/lfun/lib/torch/GetLong +/cmds/players/gag.c +/secure/cmds/admins/mudconfig.c +/doc/lfun/lib/spell/SetSkills +/secure/cmds/admins/liveupgrade.c +/doc/lfun/lib/spell/SetMorality +/secure/cmds/admins/link.c +/doc/lfun/lib/spell/GetSkills +/secure/cmds/admins/groupmod.c +/doc/lfun/lib/spell/GetMorality +/secure/cmds/admins/files.c +/doc/lfun/lib/server/eventDestruct +/doc/efun/all/trace +/secure/cmds/admins/end.c +/doc/lfun/lib/room/GetLong +/cmds/creators/whomuffed.c +/secure/cmds/admins/encre.c +/doc/lfun/lib/room/CanFly +/secure/cmds/admins/domaincreate.c +/doc/lfun/lib/race/eventDie +/doc/efun/all/link +/secure/cmds/admins/domainadmin.c +/doc/lfun/lib/race/NewBody +/secure/cmds/admins/doctool.c +/doc/lfun/lib/race/GetResistance +/secure/cmds/admins/decre.c +/doc/lfun/lib/race/GetRace +/secure/cmds/admins/chanunban.c +/doc/lfun/lib/race/GetMaxStaminaPoints +/cmds/creators/transfer.c +/secure/cmds/admins/chanremove.c +/doc/lfun/lib/race/GetMaxMagicPoints +/secure/cmds/admins/chancreate.c +/doc/lfun/lib/race/GetMaxHealthPoints +/secure/cmds/admins/chanban.c +/doc/lfun/lib/race/GetHeartRate +/secure/cmds/admins/banish.c +/doc/lfun/lib/race/GetHealRate +/secure/cmds/admins/allow.c +/doc/lfun/lib/race/GetAlcohol +/secure/cmds/admins/admintool.c +/lib/events/consult.c +/doc/lfun/lib/potion/SetStats +/secure/cmds/admins/addraces.c +/lib/events/lock_with.c +/lib/events/close.c +/doc/lfun/lib/potion/SetSkills +/secure/cmds/admins/addrace.c +/secure/sefun/findobs.c +/doc/lfun/lib/potion/SetPoints +/secure/cmds/admins/addguest.c +/lib/events/get_from.c +/doc/lfun/lib/potion/GetStats +/secure/cmds/admins/addemote.c +/lib/events/jump.c +/lib/virtual/virt_land.c +/doc/lfun/lib/potion/GetSkills +/secure/cmds/admins/addclass.c +/verbs/players/party.c +/doc/lfun/lib/potion/GetPoints +/secure/cmds/admins/addadverb.c +/doc/lfun/lib/position/eventFall +/doc/lfun/lib/poison/GetPoison +/doc/lfun/lib/poison/AddPoison +/doc/lfun/lib/player/eventUse +/doc/lfun/lib/player/eventReconnect +/doc/lfun/lib/player/eventDie +/doc/lfun/lib/player/SetClass +/doc/lfun/lib/player/GetName +/doc/lfun/lib/player/GetLong +/doc/lfun/lib/player/GetCapName +/doc/lfun/lib/player/AddHealthPoints +/doc/lfun/lib/npc/eventReconnect +/doc/lfun/lib/npc/eventDie +/doc/lfun/lib/npc/eventDestruct +/doc/lfun/lib/npc/SetClass +/doc/lfun/lib/npc/GetName +/doc/lfun/lib/npc/GetMaxHealthPoints +/doc/lfun/lib/npc/GetLong +/doc/lfun/lib/npc/GetCapName +/doc/lfun/lib/messages/GetName +/doc/lfun/lib/meal/eventDestruct +/doc/lfun/lib/manipulate/CanManipulate +/doc/lfun/lib/look/GetLong +/doc/lfun/lib/living/GetMaxHealthPoints +/doc/lfun/lib/limb/GetRace +/doc/lfun/lib/light/eventLight +/doc/lfun/lib/light/CanLight +/doc/lfun/lib/leader/eventJoin +/doc/lfun/lib/lamp/eventLight +/doc/lfun/lib/lamp/SetBurnRate +/doc/lfun/lib/lamp/GetLong +/doc/lfun/lib/lamp/GetBurnRate +/doc/lfun/lib/interactive/eventReconnect +/doc/lfun/lib/interactive/eventMarry +/doc/lfun/lib/interactive/eventDestruct +/doc/lfun/lib/interactive/GetName +/doc/lfun/lib/interactive/GetLong +/doc/lfun/lib/interactive/CanMarry +/doc/lfun/lib/id/GetName +/doc/lfun/lib/id/GetCapName +/news/welcome +/doc/lfun/lib/genetics/GetStats +/news/deadsouls +/doc/lfun/lib/genetics/GetResistance +/doc/lfun/lib/genetics/GetBaseStatLevel +/cmds/creators/scan.c +/doc/lfun/lib/fuel/GetLong +/secure/cfg/ip_unrestrict.cfg +/doc/lfun/lib/ftp_data_connection/eventDestruct +/doc/lfun/lib/ftp_client/eventDestruct +/doc/lfun/lib/follow/SetLeader +/doc/lfun/lib/follow/GetLeader +/doc/efun/all/tan +/doc/lfun/lib/flashlight/eventUse +/doc/lfun/lib/flashlight/eventLight +/doc/lfun/lib/flashlight/eventExtinguish +/doc/lfun/lib/flashlight/eventDie +/doc/lfun/lib/flashlight/SetDrainRate +/doc/lfun/lib/flashlight/SetCellType +/doc/lfun/lib/flashlight/GetCellType +/doc/lfun/lib/fish/GetFood +/doc/lfun/lib/file/eventDestruct +/doc/lfun/lib/equip/GetWorn +/doc/lfun/lib/door/GetLong +/doc/lfun/lib/donate/GetLong +/save/races.o +/doc/lfun/lib/deterioration/eventReceiveDamage +/doc/lfun/lib/damage/SetClass +/doc/lfun/lib/damage/GetClass +/doc/lfun/lib/daemon/eventDestruct +/verbs/items/extinguish.c +/secure/sefun/disable.c +/secure/sefun/generic.c +/verbs/items/install.c +/lib/classes.c +/secure/sefun/get_object.c +/secure/sefun/english.c +/verbs/players/request.c +/lib/std/furnace.c +/verbs/players/ride.c +/lib/std/limb.c +/verbs/creators/reload.c +/secure/sefun/sockets.c +/lib/lvs/position.c +/verbs/common/whisper.c +/secure/lib/net/socket.c +/lib/editor.c +/secure/lib/net/uptime_server.c +/lib/burn.c +/secure/lib/net/ftp_data_connection.c +/secure/sefun/query_carrying.c +/lib/bank.c +/secure/sefun/dummy.c +/lib/cylinder.c +/secure/sefun/arrays.c +/verbs/rooms/fly.c +/lib/events/sell.c +/lib/follow.c +/secure/sefun/to_object.c +/verbs/creators/codesay.c +/lib/pager.c +/verbs/creators/dest.c +/verbs/items/listen.c +/lib/events/look_in.c +/lib/comp/container.c +/secure/sefun/pointers.c +/lib/lead.c +/lib/user/autosave.c +/lib/creator.c +/lib/events/bait.c +/doc/efun/all/sqrt +/secure/sefun/path_file.c +/verbs/items/wield.c +/verbs/players/bump.c +/doc/efun/all/map +/verbs/players/cast.c +/secure/lib/connect.c +/secure/cfg/races/wraith +/cmds/creators/ascii.c +/lib/learn.c +/secure/cfg/races/vulcan +/secure/cfg/races/viper +/secure/cfg/races/vehicle +/secure/cfg/races/unicorn +/secure/cfg/races/troll +/secure/cfg/races/tree +/secure/cfg/races/tortoise +/secure/cfg/races/strider +/doc/efun/all/mapp +/secure/cfg/races/snake +/secure/cfg/races/slug +/secure/cfg/races/sheep +/secure/cfg/races/satyr +/secure/cfg/races/rodent +/secure/cfg/races/replicant +/secure/cfg/races/primate +/secure/cfg/races/plant +/secure/cfg/races/pig +/secure/cfg/races/pegasus +/secure/cfg/races/orc +/secure/cfg/races/ogre +/secure/cfg/races/nymph +/secure/cfg/races/mech +/secure/cfg/races/lizard +/secure/cfg/races/kobold +/secure/cfg/preload.cfg +/secure/cfg/races/klingon +/secure/cfg/races/kender +/secure/cfg/races/insect +/secure/cfg/races/human +/secure/cfg/races/horse +/secure/cfg/races/hobbit +/secure/cfg/races/halfling +/secure/cfg/races/half-orc +/secure/cfg/races/half-elf +/secure/cfg/races/griffin +/secure/cfg/races/golem +/secure/cfg/races/god +/secure/cfg/read.cfg +/secure/cfg/races/goblin +/secure/cfg/races/gnome +/secure/cfg/races/gnoll +/secure/scripts/native_version.proto +/secure/cfg/races/giant +/secure/sefun/native_version.c +/secure/cfg/races/gargoyle +/secure/cfg/races/fish +/secure/cfg/races/faerie +/secure/cfg/races/elf +/secure/cfg/races/elephant +/secure/cfg/races/elemental +/secure/cfg/races/dwarf +/secure/cfg/races/dryad +/secure/cfg/races/dragon +/secure/cfg/races/dog +/secure/cfg/races/demon +/secure/cfg/races/demi-god +/secure/cfg/races/deer +/secure/cfg/races/cow +/secure/cfg/races/chimera +/secure/cfg/races/centaur +/secure/cfg/races/cat +/secure/cfg/races/bugbear +/secure/cfg/races/bot +/secure/cfg/races/bird +/secure/cfg/races/bear +/secure/cfg/races/bat +/secure/cfg/races/balrog +/secure/cfg/races/avidryl +/secure/cfg/races/artrell +/secure/cfg/races/arachnid +/secure/cfg/races/ape +/secure/cfg/races/android +/secure/cfg/races/amphibian +/secure/cfg/mudos.win32 +/secure/cfg/classes/thief +/secure/cfg/classes/priest +/secure/cfg/classes/mage +/secure/cfg/classes/fighter +/secure/cfg/classes/explorer +/save/unique.o +/save/stargate.o +/save/soul.o +/doc/lfun/lib/creator/eventReconnect +/save/services.o +/save/kills/o/one +/doc/lfun/lib/creator/GetName +/save/economy.o +/doc/lfun/lib/creator/GetLong +/obj/worn_storage.c +/obj/wed_ring.c +/doc/lfun/lib/corpse/GetRace +/obj/weapon.c +/doc/lfun/lib/corpse/GetHealthShort +/obj/vendor.c +/obj/trainer.c +/doc/lfun/lib/connect/eventDestruct +/obj/thing.c +/doc/lfun/lib/connect/GetCapName +/cfg/timezones.cfg +/obj/table.c +/obj/sword.c +/doc/lfun/lib/combat/eventReceiveDamage +/obj/stargate.example +/doc/lfun/lib/combat/eventDie +/obj/stargate.c +/obj/shield.c +/doc/lfun/lib/combat/GetMaxHealthPoints +/obj/quest_ob.c +/doc/lfun/lib/combat/GetBaseStatLevel +/obj/portal.c +/cfg/timezone.cfg +/obj/order.c +/doc/lfun/lib/client/eventDestruct +/obj/magic_scroll.c +/doc/lfun/lib/clerk/performMarriage +/obj/include/portal.h +/obj/friend.c +/doc/lfun/lib/clean/eventDestruct +/obj/drink.c +/doc/lfun/lib/clay/SetComposition +/obj/container.c +/obj/chair.c +/doc/lfun/lib/clay/InitComposition +/obj/burning_orb.c +/doc/lfun/lib/classes/eventMoralAct +/obj/book_source/chapter2 +/obj/book_source/chapter1 +/doc/lfun/lib/classes/SetSkillModifier +/obj/barkeep.c +/doc/lfun/lib/classes/SetReligion +/obj/armor.c +/news/reminders.txt +/doc/lfun/lib/classes/SetMorality +/news/priest +/doc/lfun/lib/classes/SetClass +/news/hints.txt +/news/fighter +/doc/lfun/lib/classes/SetClan +/log/shutdowns +/doc/lfun/lib/classes/GetSkillModifier +/log/open/currency +/log/new_players +/doc/lfun/lib/classes/GetReligion +/log/mudlist_packet.2008.01.06-16.18 +/doc/lfun/lib/classes/GetMoralityDescription +/log/mudlist_packet +/doc/lfun/lib/classes/GetMorality +/log/intermud +/log/imc2.log +/doc/lfun/lib/classes/GetClass +/log/get_path +/doc/lfun/lib/classes/GetClan +/log/game_log +/log/errors/secure +/doc/lfun/lib/classes/GetBaseStatLevel +/log/errors/one +/log/errors/lib +/doc/lfun/lib/classes/ClassMember +/tmp/imc2.log +/log/errors/intermud +/doc/lfun/lib/classes/ChangeClass +/log/errors/cratylus +/doc/lfun/lib/classes/AddSkillPoints +/log/errors/cmds +/log/domain_stats +/doc/lfun/lib/clan/eventWelcome +/log/channels +/doc/lfun/lib/clan/eventUnjoin +/log/chan/demo-test +/log/chan/connections +/doc/lfun/lib/clan/eventRetire +/log/author_stats +/doc/lfun/lib/clan/eventJoin +/doc/lfun/lib/clan/eventInitiate +/log/archive/mudlist_packet.2008.01.06-14.59-2008.01.06-15.48 +/doc/lfun/lib/clan/eventBring +/lib/bboard.c +/log/archive/mudlist_packet.2008.01.06-14.52-2008.01.06-15.48 +/lib/pistol.c +/doc/lfun/lib/clan/SetLeader +/doc/lfun/lib/clan/SetClanSkill +/log/archive/mudlist_packet.2008.01.06-14.39-2008.01.06-14.47 +/doc/lfun/lib/clan/SetClanObject +/doc/lfun/lib/clan/SetClanName +/log/archive/mudlist_packet.2008.01.06-12.43-2008.01.06-12.47 +/doc/lfun/lib/clan/GetLeader +/log/archive/mudlist_packet.2008.01.06-12.33-2008.01.06-12.47 +/doc/lfun/lib/clan/GetClanSkill +/doc/lfun/lib/clan/GetClanObject +/log/archive/mudlist_packet-2008.01.06-14.47 +/doc/lfun/lib/clan/GetClanName +/log/archive/mudlist_packet-2008.01.06-08.47 +/doc/lfun/lib/clan/GetAffectLong +/log/archive/mudlist_packet-2008.01.06-02.47 +/doc/lfun/lib/clan/CanJoin +/doc/lfun/lib/chat/returnChannels +/log/archive/mudlist_packet-2008.01.05-23.47 +/doc/lfun/lib/chat/eventReconnect +/log/archive/mudlist_packet-2008.01.05-20.47 +/doc/lfun/lib/chat/eventDestruct +/log/archive/mudlist_packet-2008.01.05-14.47 +/doc/lfun/lib/chat/chat_command +/doc/lfun/lib/chat/UnrestrictChannel +/cmds/creators/debug.c +/log/archive/mudlist_packet-2008.01.05-02.47 +/doc/lfun/lib/chat/SetNoChanColors +/log/archive/mudlist_packet-2008.01.05-00.47 +/doc/lfun/lib/chat/RestrictChannel +/log/archive/mudlist_packet-2008.01.04-21.46 +/doc/lfun/lib/chat/RemoveChannel +/log/archive/mudlist_packet-2008.01.04-01.46 +/doc/lfun/lib/chat/GetRestrictedChannels +/doc/lfun/lib/chat/GetNoChanColors +/log/archive/mudlist_packet-2008.01.03-14.46 +/doc/lfun/lib/chat/GetChannels +/obj/area_room.c +/log/archive/mudlist_packet-2008.01.03-07.46 +/doc/lfun/lib/chat/AddChannel +/log/archive/mudlist_packet-2008.01.02-13.46 +/doc/lfun/lib/chapel/eventSacrifice +/doc/lfun/lib/chapel/eventMarry +/log/archive/mudlist_packet-2008.01.01-19.46 +/doc/lfun/lib/chapel/SetSacrificeType +/log/archive/mudlist_packet-2008.01.01-02.46 +/doc/lfun/lib/chapel/SetAllowSacrifice +/log/archive/mudlist_packet-2007.12.31-11.46 +/log/archive/mudlist_packet-2007.12.31-01.46 +/obj/room.c +/log/archive/mudlist_packet-2007.12.30-15.46 +/log/archive/mudlist_packet-2007.12.30-00.46 +/log/archive/mudlist_packet-2007.12.29-19.46 +/log/archive/mudlist_packet-2007.12.29-14.46 +/doc/efun/all/snoop +/log/archive/mudlist_packet-2007.12.29-10.46 +/log/archive/mudlist_packet-2007.12.28-22.46 +/log/archive/mudlist_packet-2007.12.28-12.46 +/log/archive/mudlist_packet-2007.12.28-00.46 +/log/archive/mudlist_packet-2007.12.27-17.46 +/log/archive/mudlist_packet-2007.12.27-13.45 +/log/archive/imc2.log-2008.01.06-15.48 +/log/archive/imc2.log-2008.01.06-14.47 +/log/archive/imc2.log-2008.01.06-12.47 +/log/archive/imc2.log-2008.01.06-11.47 +/log/archive/imc2.log-2008.01.06-06.47 +/log/archive/imc2.log-2008.01.06-02.47 +/log/archive/imc2.log-2008.01.05-23.47 +/log/archive/imc2.log-2008.01.05-20.47 +/log/archive/imc2.log-2008.01.05-17.47 +/log/archive/imc2.log-2008.01.05-15.47 +/log/archive/imc2.log-2008.01.05-12.47 +/log/archive/imc2.log-2008.01.05-08.47 +/cmds/common/help.c +/log/archive/imc2.log-2008.01.05-03.47 +/log/archive/imc2.log-2008.01.04-23.47 +/log/archive/imc2.log-2008.01.04-22.46 +/log/archive/imc2.log-2008.01.04-21.46 +/log/archive/imc2.log-2008.01.04-17.46 +/log/archive/imc2.log-2008.01.04-12.46 +/daemon/news.c +/log/archive/imc2.log-2008.01.04-06.46 +/daemon/help.c +/log/archive/imc2.log-2008.01.04-00.46 +/obj/npc.c +/log/archive/imc2.log-2008.01.03-22.46 +/log/archive/imc2.log-2008.01.03-17.46 +/log/archive/imc2.log-2008.01.03-14.46 +/log/archive/imc2.log-2008.01.03-11.46 +/log/archive/imc2.log-2008.01.03-07.46 +/log/archive/imc2.log-2008.01.03-02.46 +/log/archive/imc2.log-2008.01.02-23.46 +/log/archive/imc2.log-2008.01.02-21.46 +/log/archive/imc2.log-2008.01.02-18.46 +/log/archive/imc2.log-2008.01.02-14.46 +/log/archive/imc2.log-2008.01.02-11.46 +/log/archive/imc2.log-2008.01.02-08.46 +/log/archive/imc2.log-2008.01.02-04.46 +/log/archive/imc2.log-2008.01.02-00.46 +/lib/exits.c +/verbs/rooms/climb.c +/save/events.o +/log/archive/imc2.log-2008.01.01-20.46 +/lib/virtual/virt_map.c +/verbs/items/move.c +/log/archive/imc2.log-2008.01.01-17.46 +/lib/used_meal.c +/doc/lfun/all/RestoreLimb +/log/archive/imc2.log-2008.01.01-15.46 +/lib/props/move.c +/doc/lfun/all/RemoveMagicProtection +/secure/daemon/master.c +/log/archive/imc2.log-2008.01.01-12.46 +/verbs/players/sleep.c +/doc/lfun/all/RemoveLimb +/doc/efun/all/throw +/log/archive/imc2.log-2008.01.01-03.46 +/doc/lfun/all/RemoveExtraChannels +/log/archive/imc2.log-2007.12.31-22.46 +/doc/lfun/all/RemoveChannel +/doc/lfun/all/RemoveBonuses +/cmds/creators/exits.c +/log/archive/imc2.log-2007.12.31-17.46 +/doc/lfun/all/ParseHook +/log/archive/imc2.log-2007.12.31-14.46 +/doc/lfun/all/NewBody +/doc/lfun/all/ModCharge +/log/archive/imc2.log-2007.12.31-11.46 +/doc/lfun/all/InitComposition +/log/archive/imc2.log-2007.12.31-06.46 +/doc/lfun/all/HealLimb +/log/archive/imc2.log-2007.12.31-02.46 +/doc/lfun/all/GetWorn +/log/archive/imc2.log-2007.12.31-00.46 +/doc/lfun/all/GetWieldingLimbs +/doc/lfun/all/GetWielded +/log/archive/imc2.log-2007.12.30-22.46 +/doc/lfun/all/GetTorso +/log/archive/imc2.log-2007.12.30-18.46 +/doc/lfun/all/GetStats +/log/archive/imc2.log-2007.12.30-15.46 +/doc/lfun/all/GetStaminaPoints +/doc/lfun/all/GetSleeping +/log/archive/imc2.log-2007.12.30-11.46 +/doc/lfun/all/GetSkills +/log/archive/imc2.log-2007.12.30-06.46 +/doc/lfun/all/GetSkillModifier +/log/archive/imc2.log-2007.12.30-01.46 +/doc/lfun/all/GetSacrificeType +/log/archive/imc2.log-2007.12.29-23.46 +/doc/lfun/all/GetRestrictedChannels +/doc/lfun/all/GetResistance +/log/archive/imc2.log-2007.12.29-21.46 +/doc/lfun/all/GetReligion +/log/archive/imc2.log-2007.12.29-19.46 +/doc/lfun/all/GetRechargeable +/doc/lfun/all/GetRandomLimb +/doc/lfun/all/GetRace +/doc/lfun/all/GetQuestPoints +/doc/lfun/all/GetProtect +/doc/lfun/all/GetPoison +/doc/lfun/all/GetPoints +/doc/lfun/all/GetPacifist +/cmds/creators/find.c +/doc/lfun/all/GetNoChanColors +/doc/lfun/all/GetName +/doc/lfun/all/GetMoralityDescription +/doc/lfun/all/GetMorality +/doc/lfun/all/GetMoJo +/doc/lfun/all/GetMissingLimbs +/doc/lfun/all/GetMissingLimbParents +/doc/lfun/all/GetMissingLimbParent +/cmds/creators/domains.c +/doc/lfun/all/GetMinHeat +/doc/lfun/all/GetMelee +/doc/lfun/all/GetMaxStaminaPoints +/doc/lfun/all/GetMaxMagicPoints +/doc/lfun/all/GetMaxHealthPoints +/doc/lfun/all/GetMagicPoints +/doc/lfun/all/GetLong +/doc/lfun/all/GetLimbs +/doc/lfun/all/GetLimbParent +/doc/lfun/all/GetLimbClass +/doc/lfun/all/GetLimbChildren +/doc/lfun/all/GetLeader +/doc/lfun/all/GetLead +/doc/lfun/all/GetHeat +/doc/lfun/all/GetHeartRate +/doc/lfun/all/GetHeartModifier +/doc/lfun/all/GetHealthShort +/doc/lfun/all/GetHealthPoints +/doc/lfun/all/GetHealRate +/doc/lfun/all/GetFuelRequired +/cmds/creators/unmorse.c +/doc/lfun/all/GetFood +/doc/lfun/all/GetFingers +/doc/lfun/all/GetExtraChannels +/doc/lfun/all/GetExperiencePoints +/doc/lfun/all/GetEquippedLimbs +/doc/lfun/all/GetEncumbrance +/doc/lfun/all/GetDying +/doc/lfun/all/GetDrink +/doc/lfun/all/GetDrainable diff --git a/lib/secure/upgrades/files/0^0tmp0^0sample.txt b/lib/secure/upgrades/files/0^0tmp0^0sample.txt new file mode 100644 index 0000000..3f6a6b8 --- /dev/null +++ b/lib/secure/upgrades/files/0^0tmp0^0sample.txt @@ -0,0 +1,2 @@ +The quick brown fox +jumped over the lazy dogs. diff --git a/lib/secure/verbs/creators/force.c b/lib/secure/verbs/creators/force.c new file mode 100644 index 0000000..18c1ec9 --- /dev/null +++ b/lib/secure/verbs/creators/force.c @@ -0,0 +1,47 @@ +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("force"); + SetRules("LIV STR", "LIV to STR"); + SetErrorMessage("Force whom to do what?"); + SetHelp("Syntax: \n" + " \n" + "Allows you to command some living things to do " + "your bidding."); +} + +mixed can_force_liv_to_str(string str) { + if(!creatorp(this_player())) return 0; + return 1; +} + +mixed can_force_liv_str(string str) { + return can_force_liv_to_str(str); +} + +mixed do_force_liv_to_str(object target, string cmd) { + object who = this_player(); + + if(!who) return 0; + if(archp(target) && !securep(who)){ + who->eventPrint(target->GetName()+" shakes "+possessive(target)+ + " head and forces you to dest yourself."); + tell_room(environment(who), who->GetName()+" dests "+objective(who)+ + "self while trying to pull a foolish joke on "+target->GetName()+".", who); + tell_player(target,who->GetName()+" tried to force you to "+cmd); + tell_player(target,who->GetName()+" has been dested, instead."); + who->eventDestruct(); + return 1; + } + target->eventPrint(who->GetName() + " forces you to: " + cmd); + who->eventPrint("You force " + target->GetShort() + " to: " + cmd); + target->eventForce(cmd); + return 1; +} + +mixed do_force_liv_str(object ob, string str) { + return do_force_liv_to_str(ob, str); +} diff --git a/lib/shadows/arbiter.c b/lib/shadows/arbiter.c new file mode 100644 index 0000000..01d8392 --- /dev/null +++ b/lib/shadows/arbiter.c @@ -0,0 +1,397 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +inherit LIB_SHADOW; +inherit LIB_ID; + +object me = this_object(); +object suit; +int disguised, reporting = 1; + +int SetDisguised(int i){ + if(i) disguised = 1; + else disguised = 0; + return disguised; +} + +int GetDisguised(){ + return disguised; +} + +int CheckDisguised(){ + object ob; + if(clonep()) ob = GetShadowedObject(); + if(!ob || !disguised) return 0; + else return 1; +} + +int CheckSuit(){ + if(!suit){ + this_object()->unarbitershadow(); + return 0; + } + return 1; +} + +varargs string GetExternalDesc(object who){ + object ob = GetShadowedObject(); + if(!clonep()) return ""; + if(CheckDisguised()) return "A arbiter of the Extant Authority military forces."; + else return ob->GetExternalDesc(who); +} + +varargs string GetLong(object who){ + object ob = GetShadowedObject(); + if(!clonep()) return ""; + if(CheckDisguised()) return "An arbiter of the Extant Authority military forces."; + else return ob->GetLong(who); +} + +string GetName(){ + object ob = GetShadowedObject(); + if(!clonep()) return ""; + if(CheckDisguised() || !ob) return "Arbiter"; + else return ob->GetName(); +} + +string GetCapName(){ + object ob = GetShadowedObject(); + if(!clonep()) return ""; + if(CheckDisguised()) return "Arbiter"; + else return ob->GetCapName(); +} + +string GetKeyName(){ + object ob = GetShadowedObject(); + if(!clonep()) return ""; + if(CheckDisguised()) return "arbiter"; + else return ob->GetKeyName(); +} + +string GetShort(){ + object ob = GetShadowedObject(); + if(!clonep()) return ""; + if(CheckDisguised()) return "a arbiter"; + else return ob->GetShort(); +} + +string GetRace(){ + object ob = GetShadowedObject(); + if(!clonep()) return ""; + if(CheckDisguised()) return "human"; + else return ob->GetRace(); +} + +int eventShadow(object whom){ + object *shadows = keys(whom->GetShadows()); + if(sizeof(shadows)){ + foreach(object shade in shadows){ + if(base_name(shade) == base_name(me)) return 0; + } + } + if(base_name(previous_object()) == "/domains/town/armor/arbitersuit" + || base_name(previous_object()) == "/domains/default/armor/arbitersuit"){ + ::eventShadow(whom); + suit = previous_object(); + if(CheckDisguised()) whom->SetId(({"arbiter"})); + if(CheckDisguised()) whom->cmdParseRefresh(); + return 1; + } + return 0; +} + +int unarbitershadow(){ + object ob = GetShadowedObject(); + if(!ob) return 0; + ob->SetId(); + ob->cmdParseRefresh(); + eventUnshadow(); +} + +string array parse_command_id_list() { + string array ids = (this_object()->GetId() + + (CheckDisguised() ? ({ "arbiter" }) : ({}) ) || ({})); + return filter(ids, (: stringp($1) && ($1 != "") :)); + +} + +string array parse_command_plural_id_list() { + string array ids = (this_object()->GetId() + + (CheckDisguised() ? ({ "arbiter" }) : ({}) ) || ({})); + ids = filter(ids, (: stringp($1) && ($1 != "") :)); + return map(ids, (: pluralize :)); +} + +int GetSkillLevel(string skill) { + object ob = GetShadowedObject(); + int ret; + if(!clonep()) return 0; + if(!CheckSuit()) return 0; + if(!ob) return 0; + if(!suit->GetActive()) return ob->GetSkillLevel(skill); + switch(skill){ + case "melee attack" : ret = ob->GetSkillLevel(skill)+50;break; + default : + } + if(ret){ + suit->eventDecrementCharge(); + return ret; + } + else return ob->GetSkillLevel(skill); +} + +int GetCanBite(){ + return 0; +} + +int GetStatLevel(string stat){ + object ob = GetShadowedObject(); + int ret; + if(!clonep()) return 0; + if(!CheckSuit()) return 0; + if(!ob) return 0; + if(!suit->GetActive()) return ob->GetStatLevel(stat); + switch(stat){ + case "strength" : ret = ob->GetStatLevel(stat)+40;break; + case "agility" : ret = ob->GetStatLevel(stat)+40;break; + case "durability" : ret = ob->GetStatLevel(stat)+40;break; + case "coordination" : ret = ob->GetStatLevel(stat)+40;break; + default : + } + if(ret){ + suit->eventDecrementCharge(); + return ret; + } + else return ob->GetStatLevel(stat); +} + +int GetMelee(){ + object ob = GetShadowedObject(); + if(!clonep()) return 0; + if(!CheckSuit()) return 0; + if(!ob) return 0; + if(!suit->GetActive()) return ob->GetMelee(); + if(!(ob->GetMelee())) suit->eventDecrementCharge(); + return 1; +} + +float AddStaminaPoints(mixed x) { + float y; + object ob = GetShadowedObject(); + if(!clonep()) return 0; + if(!CheckSuit()) return 0; + if(!ob) return 0; + if(!suit->GetActive()) return ob->AddStaminaPoints(x); + + if( !intp(x) && !floatp(x) ) + error("Bad argument 1 to AddStaminaPoints().\n"); + x = abs(x); + suit->eventDecrementCharge(x); + return suit->GetRemainingCharge(); +} + +//This is a bit much +#if 0 +int eventCollapse(){ + object ob = GetShadowedObject(); + if(!ob) return 0; + if(!CheckSuit() || !suit->GetActive()) return ob->eventCollapse(); + suit->eventDecrementCharge(); + return suit->GetRemainingCharge(); +} +#endif + +int RemoveLimb(string limb, mixed agent){ + object ob = GetShadowedObject(); + if(!CheckSuit()) return 0; + if(!ob) return 0; + if(suit->GetActive()){ + suit->eventDecrementCharge(); + return 0; + } + return ob->RemoveLimb(limb, agent); +} + +varargs mixed GetEffectiveVision(mixed location, int raw_score){ + object ob = GetShadowedObject(); + if(!CheckSuit()) return 0; + if(!ob) return 0; + if(suit->GetActive()){ + suit->eventDecrementCharge(); + return VISION_CLEAR; + } + return ob->GetEffectiveVision(location, raw_score); +} + +varargs int CanBreathe(mixed args...){ + object ob = GetShadowedObject(); + int rtype; + if(!ob) return 0; + if(!CheckSuit()) return ob->CanBreathe(args); + rtype = ob->GetRespiration(); + if(suit->GetActive()){ + if(rtype & R_AIR){ + suit->eventDecrementCharge(); + return 1; + } + if(rtype & R_WATER || rtype & R_METHANE) return 0; + } + return ob->CanBreathe(args); +} + +void eventDescribeEnvironment(int verbose) { + object ob = GetShadowedObject(); + object env; + string grid, climate,filename,foo,tmp; + int x,y,z,hud = 1; + object *livings; + string extra = "%^CYAN%^Heads-up display info:%^RESET%^\n"; + mapping invisibles = ([]); + int medium, terrain; + + extra += "Power remaining: "+to_int(percent(suit->GetRemainingCharge(), + suit->GetMaxCharge()))+"%\n"; + + if(!ob) return 0; + if(!CheckSuit() || !suit->GetActive()) return ob->eventDescribeEnvironment(verbose); + + if( !(env = room_environment(ob)) ) { + message("room_description", "No environment.", this_object()); + return; + } + + filename = file_name(env); + livings = filter(get_livings(env), (: $1->GetInvis() :) ); + medium = env->GetMedium(); + terrain = env->GetTerrain(); + climate = env->GetClimate(); + grid = ROOMS_D->GetCoordinates(env); + + if(grid){ + hud = 1; + extra += "Global coordinates: "+grid+"\n"; + } + + foo = last_string_element(filename,"/"); + if(sscanf(foo,"%d,%d,%d", x,y,z) == 3 || + sscanf(foo,"%d,%d", x,y) == 2){ + hud = 1; + extra += "Local coordinates: "+x+","+y+","+z+"\n"; + } + if(climate){ + hud = 1; + extra += "Climate: "+climate+"\n"; + } + if(terrain){ + hud = 1; + extra += "Terrain: "; + if(terrain & T_OUTDOORS) extra += " outdoors "; + if(terrain & T_INDOORS) extra += " indoors "; + if(terrain & T_ROAD) extra += " road "; + if(terrain & T_UNDERWATER) extra += " underwater "; + if(terrain & T_SURFACE) extra += "surface "; + if(terrain & T_MIDAIR) extra += " midair "; + if(terrain & T_SWAMP) extra += " swamp "; + if(terrain & T_WOODS) extra += " woods "; + if(terrain & T_JUNGLE) extra += " jungle "; + if(terrain & T_ROUGH) extra += " rough "; + if(terrain & T_UNDERGROUND) extra += " underground "; + if(terrain & T_SPACE) extra += " space "; + if(terrain & T_MAGMA) extra += " magma "; + if(terrain & T_PLASMA) extra += " plasma "; + if(terrain & T_PLANAR) extra += " planar "; + if(terrain & T_SNOW) extra += " snow "; + if(terrain & T_SAND) extra += " sand "; + if(terrain & T_ICE) extra += " ice "; + if(terrain & T_BIOLOGICAL) extra += " biological "; + if(terrain & T_SEAFLOOR) extra += " seafloor "; + extra += "\n"; + } + + if(medium){ + hud = 1; + extra += "Medium: "; + switch(medium){ + case MEDIUM_LAND : extra += "land\n"; break; + case MEDIUM_AIR : extra += "air\n"; break; + case MEDIUM_SPACE : extra += "space\n"; break; + case MEDIUM_WATER : extra += "water\n"; break; + case MEDIUM_SURFACE : extra += "surface\n"; break; + default: extra += "unknown\n"; + } + } + + if(sizeof(livings)){ + hud = 1; + foreach(object dude in livings){ + if(!invisibles[dude->GetRace()]) invisibles[dude->GetRace()] = 1; + else invisibles[dude->GetRace()]++; + } + foreach(mixed key, mixed val in invisibles){ + if(!key) continue; + extra += "Invisible "+pluralize(key)+": "+val+"\n"; + } + } + + ob->eventDescribeEnvironment(verbose); + if(hud) message("system", extra, ob); +} + +varargs int eventReceiveDamage(mixed agent, int type, int x, int internal, mixed limbs) { + object ob = GetShadowedObject(); + string evidence, limb_string; + + if(!CheckSuit()) return 0; + if(!ob) return 0; + if(internal || !suit->GetActive()) return ob->eventReceiveDamage(agent, type, x, internal, limbs); + + if(reporting){ + string *damtypes = TYPES_D->eventCalculateTypes("damage", type); + evidence = "The powered suit's Heads-Up-Display issues an alert:\n"; + evidence += "%^BOLD%^%^RED%^"; + if(objectp(agent)) evidence += "Damage received!"; + if(type && sizeof(damtypes)) { + string verboid; + if(sizeof(damtypes) > 1) verboid = "s are "; + else verboid = " is "; + + evidence += " Damage type"+verboid; + evidence += lower_case(implode(damtypes,", ")); + } + + else evidence += " Damage type is UNKNOWN"; + } + + if(limbs) { + if(stringp(limbs)) limb_string = limbs; + else if(arrayp(limbs)) { + if(stringp(limbs[0])) limb_string = implode(limbs,", "); + else if(objectp(limbs[0])){ + foreach(object limb in limbs){ + limb_string += limb->GetKeyName()+", "; + } + } + } + } + else limb_string = ". Location indeterminate. "; + if(limbs) { + evidence += ". Location: "; + evidence += limb_string + "."; + } + this_object()->eventPrint(evidence+"%^RESET%^"); + + this_object()->eventPrint("%^YELLOW%^Power level drained: "+x+" units.%^RESET%^"); + suit->eventDecrementCharge(x); + return 1; +} + +int AddLead(string ammo,int number){ + return 0; +} + diff --git a/lib/shadows/bear.c b/lib/shadows/bear.c new file mode 100644 index 0000000..0b127a9 --- /dev/null +++ b/lib/shadows/bear.c @@ -0,0 +1,74 @@ +#include +#include + +inherit LIB_SHADOW; +inherit LIB_ID; + +object me = this_object(); + +varargs string GetExternalDesc(object who){ + return "A large brown bear. Not as huge as a grizzly, but plenty big enough to knock your block off."; +} + +varargs string GetLong(object who){ + return "A large brown bear. Not as huge as a grizzly, but plenty big enough to knock your block off."; +} + +string GetName(){ + return "Bear"; +} + +string GetCapName(){ + return "Bear"; +} + +string GetKeyName(){ + return "bear"; +} + +string GetShort(){ + return "a bear"; +} + +string GetRace(){ + return "bear"; +} + +int eventShadow(object whom){ + object *shadows = keys(whom->GetShadows()); + if(sizeof(shadows)){ + foreach(object shade in shadows){ + if(base_name(shade) == base_name(me)) return 0; + } + } + if(base_name(previous_object()) == "/domains/town/armor/bearsuit"){ + ::eventShadow(whom); + whom->SetId(({"bear"})); + whom->cmdParseRefresh(); + return 1; + } + return 0; +} + +int unbearshadow(){ + object ob = GetShadowedObject(); + if(!ob) return 0; + ob->SetId(); + ob->cmdParseRefresh(); + eventUnshadow(); +} + +string array parse_command_id_list() { + + string array ids = (this_object()->GetId() + ({ "bear" }) || ({})); + + return filter(ids, (: stringp($1) && ($1 != "") :)); + +} + +string array parse_command_plural_id_list() { + string array ids = (this_object()->GetId() + ({"bear"}) || ({})); + + ids = filter(ids, (: stringp($1) && ($1 != "") :)); + return map(ids, (: pluralize :)); +} diff --git a/lib/shadows/breather.c b/lib/shadows/breather.c new file mode 100644 index 0000000..9c9c834 --- /dev/null +++ b/lib/shadows/breather.c @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include + +inherit LIB_SHADOW; + +object breatherob; +int rtype; + +int eventShadow(object whom){ + if(base_name(previous_object()) == "/domains/default/armor/breather" || + base_name(previous_object()) == "/domains/town/armor/breather"){ + breatherob = previous_object(); + ::eventShadow(whom); + rtype = RACES_D->GetRaceRespirationType(whom->GetRace()); + return 1; + } + return 0; +} + +varargs int CanBreathe(mixed args...){ + int ret; + object ob = GetShadowedObject(); + if(!ob) return 0; + rtype = ob->GetRespiration(); + + if(breatherob && breatherob->GetRemainingCharge()){ + if(rtype & R_AIR){ + breatherob->eventDecrementCharge(); + return 1; + } + if(rtype & R_VACUUM) ret = 1; + else if(rtype & R_WATER || rtype & R_METHANE) ret = 0; + } + if(!undefinedp(ret)) return ret; + return ob->CanBreathe(args...); +} + +string GetResistance(int type){ + object ob = GetShadowedObject(); + if(!ob) return 0; + if(type != GAS) return ob->GetResistance(type); + if(breatherob && breatherob->GetRemainingCharge()){ + breatherob->eventDecrementCharge(); + return "immune"; + } + return ob->GetResistance(type); +} diff --git a/lib/shadows/diag.c b/lib/shadows/diag.c new file mode 100644 index 0000000..dc2b1a9 --- /dev/null +++ b/lib/shadows/diag.c @@ -0,0 +1,80 @@ +#include +inherit LIB_SHADOW; + +varargs int eventReceiveDamage(mixed agent, int type, int x, int internal, mixed limbs) { + int hp, damage, damdiff; + object ob = GetShadowedObject(); + string evidence, limb_string; + evidence = ""; + if(objectp(agent)) evidence += "You receive damage from "+agent->GetKeyName(); + else if(stringp(agent)) evidence += "You receive damage from "+agent; + if(type) { + switch(type){ + case BLUNT : evidence += ", damage type is BLUNT";break; + case BLADE : evidence += ", damage type is BLADE";break; + case KNIFE : evidence += ", damage type is KNIFE";break; + case WATER : evidence += ", damage type is WATER";break; + case SHOCK : evidence += ", damage type is SHOCK";break; + case COLD : evidence += ", damage type is COLD";break; + case HEAT : evidence += ", damage type is HEAT";break; + case GAS : evidence += ", damage type is GAS";break; + case ACID : evidence += ", damage type is ACID";break; + case MAGIC : evidence += ", damage type is MAGIC";break; + case POISON : evidence += ", damage type is POISON";break; + case DISEASE : evidence += ", damage type is DISEASE";break; + case TRAUMA : evidence += ", damage type is TRAUMA";break; + case PIERCE : evidence += ", damage type is PIERCE";break; + case PSIONIC : evidence += ", damage type is PSIONIC";break; + case ANOXIA : evidence += ", damage type is ANOXIA";break; + case DEATHRAY : evidence += ", damage type is DEATHRAY";break; + case EMOTIONAL : evidence += ", damage type is EMOTIONAL";break; + case SONIC : evidence += ", damage type is SONIC";break; + case BITE : evidence += ", damage type is BITE";break; + case OTHER : evidence += ", damage type is OTHER";break; + default : evidence += ", damage type is UNKNOWN";break; + } + } + if(x) evidence += ", raw damage is "+x; + if(internal) evidence += ", internal variable is "+internal; + if(limbs) { + if(stringp(limbs)) limb_string = limbs; + else if(arrayp(limbs)) { + if(stringp(limbs[0])) limb_string = implode(limbs,", "); + else if(objectp(limbs[0])){ + foreach(object limb in limbs){ + limb_string += limb->GetKeyName()+", "; + } + } + } + } + else limb_string = ", and I can't tell where I'm hit. "; + if(limbs) { + evidence += ", body part(s) affected: "; + evidence += limb_string + "."; + } + this_object()->eventForce("say "+evidence); + hp = this_object()->GetHealthPoints(); + + if(!agent) agent = this_object(); + if(!type) type = 0; + if(!x) x = 0; + if(!internal) internal = 0; + if(!limbs) limbs = ""; + + if(ob) ob->eventReceiveDamage(agent, type, x, internal, limbs); + + damage = this_object()->GetHealthPoints(); + damdiff = hp - damage; + this_object()->eventForce("say actual damage done: "+damdiff); +} + +int RemoveLimb(string limb, object agent){ + object ob = GetShadowedObject(); + if(!ob) return; + if(ob->GetKeyName() == "dummy"){ + this_object()->eventForce("say My "+limb+" has received enough damage to sever it. " + "However, since I am a training dummy, I'll be keeping it."); + return 1; + } + return ob->RemoveLimb(limb, agent); +} diff --git a/lib/shadows/drone.c b/lib/shadows/drone.c new file mode 100644 index 0000000..1001893 --- /dev/null +++ b/lib/shadows/drone.c @@ -0,0 +1,12 @@ +#include +#include + +inherit "/secure/npc/drone"; +inherit "/lib/shadow"; + +int QueryDrone(){ + return 1; +} + + + diff --git a/lib/shadows/explosive_trap.c b/lib/shadows/explosive_trap.c new file mode 100644 index 0000000..224edcb --- /dev/null +++ b/lib/shadows/explosive_trap.c @@ -0,0 +1,30 @@ +#include +#include +#include + +inherit LIB_BOOBYTRAP_SHADOW; + +varargs mixed SpringTrap(mixed arg1, mixed arg2){ + object ob = this_player(); + mixed *stuffs = ({}); + if(!ob) ob = this_object()->GetShadowedObject(); + if(!ob || !environment(ob)) return 0; + tell_room(environment(ob),"\n----\nKABOOOOM!\n----\n"); + write("You trip an exploding boobytrap!"); + say(ob->GetCapName()+" trips an exploding boobytrap!"); + + stuffs=ob->GetLimbs(); + foreach(string limb in stuffs){ + if(limb != "head" && limb != "torso" && limb != "neck") ob->RemoveLimb(limb,this_object()); + } + + foreach(object victim in get_livings(environment(ob))){ + victim->eventReceiveDamage("explosive device",BLUNT, random(1000)+300, 1); + } + + return boobytrap_shadow::SpringTrap(arg1, arg2); +} + +void create(){ + SetTrapType(BOOBYTRAP_OPEN | BOOBYTRAP_CLOSE |BOOBYTRAP_PICK); +} diff --git a/lib/shadows/needle_trap.c b/lib/shadows/needle_trap.c new file mode 100644 index 0000000..570cbd3 --- /dev/null +++ b/lib/shadows/needle_trap.c @@ -0,0 +1,15 @@ +#include +#include + +inherit LIB_BOOBYTRAP_SHADOW; + +varargs mixed SpringTrap(mixed arg1, mixed arg2){ + write("You are pricked by a poison needle trap!"); + say(this_player()->GetCapName()+" is pricked by a poison needle trap!"); + this_player()->AddPoison(10); + return boobytrap_shadow::SpringTrap(arg1, arg2); +} + +void create(){ + SetTrapType(BOOBYTRAP_ALL); +} diff --git a/lib/shadows/needle_trap2.c b/lib/shadows/needle_trap2.c new file mode 100644 index 0000000..881a746 --- /dev/null +++ b/lib/shadows/needle_trap2.c @@ -0,0 +1,15 @@ +#include +#include + +inherit LIB_BOOBYTRAP_SHADOW; + +varargs mixed SpringTrap(mixed arg1, mixed arg2){ + write("You are pricked by a poison needle trap!"); + say(this_player()->GetCapName()+" is pricked by a poison needle trap!"); + this_player()->AddPoison(90); + return boobytrap_shadow::SpringTrap(arg1, arg2); +} + +void create(){ + SetTrapType(BOOBYTRAP_ALL); +} diff --git a/lib/shadows/pscout.c b/lib/shadows/pscout.c new file mode 100644 index 0000000..6cc4970 --- /dev/null +++ b/lib/shadows/pscout.c @@ -0,0 +1,278 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +inherit LIB_SHADOW; +inherit LIB_ID; + +object me = this_object(); +object suit; +int disguised, reporting = 1; + +int SetDisguised(int i){ + if(i) disguised = 1; + else disguised = 0; + return disguised; +} + +int GetDisguised(){ + return disguised; +} + +int CheckDisguised(){ + object ob; + if(clonep()) ob = GetShadowedObject(); + if(!ob || !disguised) return 0; + else return 1; +} + +int CheckSuit(){ + if(!suit){ + this_object()->unscoutshadow(); + return 0; + } + return 1; +} + +varargs string GetExternalDesc(object who){ + object ob = GetShadowedObject(); + if(!clonep()) return ""; + if(CheckDisguised()) return "A Poleepkwa scout."; + else return ob->GetExternalDesc(who); +} + +varargs string GetLong(object who){ + object ob = GetShadowedObject(); + if(!clonep()) return ""; + if(CheckDisguised()) return "A Poleepkwa scout."; + else return ob->GetLong(who); +} + +string GetName(){ + object ob = GetShadowedObject(); + if(!clonep()) return ""; + if(CheckDisguised()) return "Scout"; + else return ob->GetName(); +} + +string GetCapName(){ + object ob = GetShadowedObject(); + if(!clonep()) return ""; + if(CheckDisguised()) return "Scout"; + else return ob->GetCapName(); +} + +string GetKeyName(){ + object ob = GetShadowedObject(); + if(!clonep()) return ""; + if(CheckDisguised()) return "scout"; + else return ob->GetKeyName(); +} + +string GetShort(){ + object ob = GetShadowedObject(); + if(!clonep()) return ""; + if(CheckDisguised()) return "a scout"; + else return ob->GetShort(); +} + +string GetRace(){ + object ob = GetShadowedObject(); + if(!clonep()) return ""; + if(CheckDisguised()) return "poleepkwa"; + else return ob->GetRace(); +} + +int eventShadow(object whom){ + object *shadows = keys(whom->GetShadows()); + if(sizeof(shadows)){ + foreach(object shade in shadows){ + if(base_name(shade) == base_name(me)) return 0; + } + } + if(base_name(previous_object()) == "/domains/town/armor/pscoutsuit" + || base_name(previous_object()) == "/domains/default/armor/pscoutsuit"){ + ::eventShadow(whom); + suit = previous_object(); + if(CheckDisguised()) whom->SetId(({"scout"})); + if(CheckDisguised()) whom->cmdParseRefresh(); + return 1; + } + return 0; +} + +int unscoutshadow(){ + object ob = GetShadowedObject(); + if(!ob) return 0; + ob->SetId(); + ob->cmdParseRefresh(); + eventUnshadow(); +} + +string array parse_command_id_list() { + string array ids = (this_object()->GetId() + + (CheckDisguised() ? ({ "scout" }) : ({}) ) || ({})); + return filter(ids, (: stringp($1) && ($1 != "") :)); + +} + +string array parse_command_plural_id_list() { + string array ids = (this_object()->GetId() + + (CheckDisguised() ? ({ "scout" }) : ({}) ) || ({})); + ids = filter(ids, (: stringp($1) && ($1 != "") :)); + return map(ids, (: pluralize :)); +} + +int GetCanBite(){ + return 0; +} + +float AddStaminaPoints(mixed x) { + float y; + object ob = GetShadowedObject(); + if(!clonep()) return 0; + if(!CheckSuit()) return 0; + if(!ob) return 0; + if(!suit->GetActive()) return ob->AddStaminaPoints(x); + if( !intp(x) && !floatp(x) ) + error("Bad argument 1 to AddStaminaPoints().\n"); + x = abs(x); + suit->eventDecrementCharge(x); + return suit->GetRemainingCharge(); +} + +int RemoveLimb(string limb, mixed agent){ + object ob = GetShadowedObject(); + if(!CheckSuit()) return 0; + if(!ob) return 0; + if(suit->GetActive()){ + suit->eventDecrementCharge(); + return 0; + } + return ob->RemoveLimb(limb, agent); +} + +varargs mixed GetEffectiveVision(mixed location, int raw_score){ + object ob = GetShadowedObject(); + if(!CheckSuit()) return 0; + if(!ob) return 0; + if(suit->GetActive()){ + suit->eventDecrementCharge(); + return VISION_CLEAR; + } + return ob->GetEffectiveVision(location, raw_score); +} + +string GetResistance(int type){ + object ob = GetShadowedObject(); + string orig = ob->GetResistance(type); + if(!CheckSuit()) return 0; + if(!ob) return 0; + if(suit->GetActive()){ + suit->eventDecrementCharge(); + if(type == GAS) return "immune"; + } + return orig; +} + +varargs int CanBreathe(mixed args...){ + object ob = GetShadowedObject(); + object env = environment(ob); + int rtype, good; + if(!ob || !env) return 0; + good = ob->CanBreathe(args); + if(!CheckSuit()) return good; + rtype = ob->GetRespiration(); + if(suit->GetActive()){ + if(rtype & R_AIR){ + if(!good){ + suit->eventDecrementCharge(); + return 1; + } + } + if(rtype & R_WATER || rtype & R_METHANE) return 0; + } + return ob->CanBreathe(args); +} + +varargs int eventReceiveDamage(mixed agent, int type, int x, int internal, mixed limbs) { + object ob = GetShadowedObject(); + string evidence, limb_string; + + if(!CheckSuit()) return 0; + if(!ob) return 0; + + if(internal || !suit->GetActive() || suit->GetRemainingCharge() < 20){ + return ob->eventReceiveDamage(agent, type, x, internal, limbs); + } + + if(reporting){ + string *damtypes = TYPES_D->eventCalculateTypes("damage", type); + evidence = "The powered suit's Heads-Up-Display issues an alert:\n"; + evidence += "%^BOLD%^%^RED%^"; + if(objectp(agent)) evidence += "Damage received!"; + if(type && sizeof(damtypes)) { + string verboid; + if(sizeof(damtypes) > 1) verboid = "s are "; + else verboid = " is "; + + evidence += " Damage type"+verboid; + evidence += lower_case(implode(damtypes,", ")); + } + + else evidence += " Damage type is UNKNOWN"; + } + + if(limbs) { + if(stringp(limbs)) limb_string = limbs; + else if(arrayp(limbs)) { + if(stringp(limbs[0])) limb_string = implode(limbs,", "); + else if(objectp(limbs[0])){ + foreach(object limb in limbs){ + limb_string += limb->GetKeyName()+", "; + } + } + } + } + else limb_string = ". Location indeterminate. "; + if(limbs) { + evidence += ". Location: "; + evidence += limb_string + "."; + } + this_object()->eventPrint(evidence+"%^RESET%^"); + + this_object()->eventPrint("%^YELLOW%^Juice drained: "+x+" units.%^RESET%^"); + suit->eventDecrementCharge(x); + return 1; +} + +int AddLead(string ammo,int number){ + return 0; +} + +void eventDescribeEnvironment(int verbose) { + object ob = GetShadowedObject(); + object env; + string extra = "%^CYAN%^Suit info:%^RESET%^\n"; + extra += "Juice left: "+to_int(percent(suit->GetRemainingCharge(), + suit->GetMaxCharge()))+"%\n"; + if(!ob) return; + if(!CheckSuit()){ + ob->eventDescribeEnvironment(verbose); + return; + } + //extra += "Mystery number dam: "+suit->GetDamagePoints()+"\n"; + //extra += "Mystery number dets: "+suit->GetDeterioration()+"\n"; + //extra += "Mystery number broken: "+suit->GetBroken()+"\n"; + //extra += "Mystery number remaining: "+suit->GetRemainingCharge()+"\n"; + //extra += "Mystery number max: "+suit->GetMaxCharge()+"\n"; + //extra += "Mystery number active: "+suit->GetActive()+"\n"; + ob->eventDescribeEnvironment(verbose); + message("system", extra, ob); +} + diff --git a/lib/shadows/ring.c b/lib/shadows/ring.c new file mode 100644 index 0000000..773569d --- /dev/null +++ b/lib/shadows/ring.c @@ -0,0 +1,132 @@ +#include +#include +inherit LIB_SHADOW; +int reporting = 1; +int protecting = 1; + +varargs int eventReceiveDamage(mixed agent, int type, int x, int internal, mixed limbs) { + int stamina, fatigue, hp, damage, damdiff; + object ob = GetShadowedObject(); + string evidence, limb_string; + if(reporting){ + string *damtypes = TYPES_D->eventCalculateTypes("damage", type); + evidence = "%^BOLD%^%^RED%^"; + + if(objectp(agent)) evidence += "You receive damage from "+agent->GetKeyName(); + else if(stringp(agent)) evidence += "You receive damage from "+agent; + evidence +="."; + + if(type && sizeof(damtypes)) { + string verboid; + if(sizeof(damtypes) > 1) verboid = "s are "; + else verboid = " is "; + + evidence += " Damage type"+verboid; + evidence += lower_case(implode(damtypes,", ")); + } + else evidence += " Damage type is UNKNOWN"; + + if(x) evidence += ", raw damage is "+x; + if(internal) evidence += ", internal variable is "+internal; + if(limbs) { + if(stringp(limbs)) limb_string = limbs; + else if(arrayp(limbs)) { + if(stringp(limbs[0])) limb_string = implode(limbs,", "); + else if(objectp(limbs[0])){ + foreach(object limb in limbs){ + limb_string += limb->GetKeyName()+", "; + } + } + } + } + else limb_string = ", and you can't tell where you're hit. "; + if(limbs) { + evidence += ", body part(s) affected: "; + evidence += limb_string + "."; + } + this_object()->eventPrint(evidence+"%^RESET%^"); + hp = this_object()->GetHealthPoints(); + stamina = this_object()->GetStaminaPoints(); + + if(!agent) agent = this_object(); + if(!type) type = 0; + if(!x) x = 0; + if(!internal) internal = 0; + if(!limbs) limbs = ""; + + if(x > this_object()->GetHealthPoints() && + !(this_object()->GetGodMode()) ){ + this_object()->eventPrint("%^RED%^This could have been a fatal hit. "+ + "The ring's safety protocol prevents \"actual damage\" calculation "+ + "from proceeding.%^RESET%^"); + return 1; + } + + if(ob) ob->eventReceiveDamage(agent, type, x, internal, limbs); + + damage = this_object()->GetHealthPoints(); + fatigue = stamina - this_object()->GetStaminaPoints(); + damdiff = hp - damage; + this_object()->eventPrint("%^RED%^Actual damage done: "+damdiff+"%^RESET%^"); + this_object()->eventPrint("%^YELLOW%^Stamina sapped: "+fatigue+"%^RESET%^"); + if(protecting && ob){ + ob->AddHP(damdiff+1); + this_object()->AddStaminaPoints(fatigue+1); + } + } + else if(!protecting && ob) + return ob->eventReceiveDamage(agent, type, x, internal, limbs); + return 1; +} + +int RemoveLimb(string limb, object agent){ + object ob = GetShadowedObject(); + if(!ob) return 0; + if(protecting){ + this_object()->eventPrint("you have received enough damage to sever it. "+ + "However, The ring's protection prevents that."); + return 1; + } + else return ob->RemoveLimb(limb, agent); +} + +int AddHP(int hp){ + object ob = GetShadowedObject(); + if(protecting && hp < 0){ + if(reporting) + this_object()->eventPrint(identify(previous_object())+" tried to "+ + "deduct "+abs(hp)+" health. The ring's protection prevents it."); + return 1; + } + if(reporting){ + string operation = "add"; + if(hp < 0) operation = "subtract"; + this_object()->eventPrint(identify(previous_object())+" tried to "+ + operation+" "+abs(hp)+" health."); + } + if(ob) return ob->AddHP(hp); + else return 1; +} + +int JadeProtection(int i){ + object ob = GetShadowedObject(); + if(!this_player()) return 0; + if(!ob || !(this_player() == ob )) return 0; + protecting = i; + return protecting; +} + +int JadeReporting(int i){ + object ob = GetShadowedObject(); + if(!this_player()) return 0; + if(!ob || !(this_player() == ob )) return 0; + reporting = i; + return reporting; +} + +int eventUnshadow(){ + object ob = GetShadowedObject(); + if(!this_player()) return 0; + if(!ob || !(this_player() == ob )) return 0; + return ::eventUnshadow(); +} diff --git a/lib/shadows/rocketpack.c b/lib/shadows/rocketpack.c new file mode 100644 index 0000000..f5b86bc --- /dev/null +++ b/lib/shadows/rocketpack.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include + +inherit LIB_SHADOW; + +object packob; +object person; +int rtype; + +int eventShadow(object whom){ + if(base_name(previous_object()) == "/domains/default/armor/rocketpack" || + base_name(previous_object()) == "/domains/town/armor/rocketpack"){ + person = whom; + packob = previous_object(); + ::eventShadow(whom); + return 1; + } + return 0; +} + +varargs int eventFall(mixed args...){ + if(!packob || !packob->GetRunning()){ + //return person->eventFall(args); + } + packob->eventDecrementCharge(); + return 1; +} + diff --git a/lib/shadows/scout.c b/lib/shadows/scout.c new file mode 100644 index 0000000..6ac0631 --- /dev/null +++ b/lib/shadows/scout.c @@ -0,0 +1,402 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +inherit LIB_SHADOW; +inherit LIB_ID; + +object me = this_object(); +object suit; +int disguised, reporting = 1; + +int SetDisguised(int i){ + if(i) disguised = 1; + else disguised = 0; + return disguised; +} + +int GetDisguised(){ + return disguised; +} + +int CheckDisguised(){ + object ob; + if(clonep()) ob = GetShadowedObject(); + if(!ob || !disguised) return 0; + else return 1; +} + +int CheckSuit(){ + if(!suit){ + this_object()->unscoutshadow(); + return 0; + } + return 1; +} + +varargs string GetExternalDesc(object who){ + object ob = GetShadowedObject(); + if(!clonep()) return ""; + if(CheckDisguised()) return "A scout of the Extant Authority military forces."; + else return ob->GetExternalDesc(who); +} + +varargs string GetLong(object who){ + object ob = GetShadowedObject(); + if(!clonep()) return ""; + if(CheckDisguised()) return "A scout of the Extant Authority military forces."; + else return ob->GetLong(who); +} + +string GetName(){ + object ob = GetShadowedObject(); + if(!clonep()) return ""; + if(CheckDisguised()) return "Scout"; + else return ob->GetName(); +} + +string GetCapName(){ + object ob = GetShadowedObject(); + if(!clonep()) return ""; + if(CheckDisguised()) return "Scout"; + else return ob->GetCapName(); +} + +string GetKeyName(){ + object ob = GetShadowedObject(); + string name; + if(!clonep()) return ""; + if(CheckDisguised()) return "scout"; + name = ob->GetKeyName(); + if(!name) return "unnamed"; + return name; +} + +string GetShort(){ + object ob = GetShadowedObject(); + if(!clonep()) return ""; + if(CheckDisguised()) return "a scout"; + else return ob->GetShort(); +} + +string GetRace(){ + object ob = GetShadowedObject(); + if(!clonep()) return ""; + if(CheckDisguised()) return "human"; + else return ob->GetRace(); +} + +int eventShadow(object whom){ + object *shadows = keys(whom->GetShadows()); + if(sizeof(shadows)){ + foreach(object shade in shadows){ + if(base_name(shade) == base_name(me)) return 0; + } + } + if(base_name(previous_object()) == "/domains/town/armor/scoutsuit" + || base_name(previous_object()) == "/domains/default/armor/scoutsuit"){ + ::eventShadow(whom); + suit = previous_object(); + if(CheckDisguised()) whom->SetId(({"scout"})); + if(CheckDisguised()) whom->cmdParseRefresh(); + return 1; + } + return 0; +} + +int unscoutshadow(){ + object ob = GetShadowedObject(); + if(!ob) return 0; + ob->SetId(); + ob->cmdParseRefresh(); + eventUnshadow(); +} + +string array parse_command_id_list() { + string array ids = (this_object()->GetId() + + (CheckDisguised() ? ({ "scout" }) : ({}) ) || ({})); + return filter(ids, (: stringp($1) && ($1 != "") :)); + +} + +string array parse_command_plural_id_list() { + string array ids = (this_object()->GetId() + + (CheckDisguised() ? ({ "scout" }) : ({}) ) || ({})); + ids = filter(ids, (: stringp($1) && ($1 != "") :)); + return map(ids, (: pluralize :)); +} + +int GetSkillLevel(string skill) { + object ob = GetShadowedObject(); + int ret; + if(!clonep()) return 0; + if(!CheckSuit()) return 0; + if(!ob) return 0; + if(!suit->GetActive()) return ob->GetSkillLevel(skill); + switch(skill){ + case "melee attack" : ret = 50;break; + default : + } + if(ret){ + suit->eventDecrementCharge(); + return ret; + } + else return ob->GetSkillLevel(skill); +} + +int GetCanBite(){ + return 0; +} + +int GetStatLevel(string stat){ + object ob = GetShadowedObject(); + int ret; + if(!clonep()) return 0; + if(!CheckSuit()) return 0; + if(!ob) return 0; + if(!suit->GetActive()) return ob->GetStatLevel(stat); + switch(stat){ + case "strength" : ret = 40;break; + case "agility" : ret = 50;break; + case "durability" : ret = 60;break; + case "coordination" : ret = 70;break; + default : + } + if(ret){ + suit->eventDecrementCharge(); + return ret; + } + else return ob->GetStatLevel(stat); +} + +int GetMelee(){ + object ob = GetShadowedObject(); + if(!clonep()) return 0; + if(!CheckSuit()) return 0; + if(!ob) return 0; + if(!suit->GetActive()) return ob->GetMelee(); + if(!(ob->GetMelee())) suit->eventDecrementCharge(); + return 1; +} + +float AddStaminaPoints(mixed x) { + float y; + object ob = GetShadowedObject(); + if(!clonep()) return 0; + if(!CheckSuit()) return 0; + if(!ob) return 0; + if(!suit->GetActive()) return ob->AddStaminaPoints(x); + + if( !intp(x) && !floatp(x) ) + error("Bad argument 1 to AddStaminaPoints().\n"); + x = abs(x); + suit->eventDecrementCharge(x); + return suit->GetRemainingCharge(); +} + +//This is a bit much +#if 0 +int eventCollapse(){ + object ob = GetShadowedObject(); + if(!ob) return 0; + if(!CheckSuit() || !suit->GetActive()) return ob->eventCollapse(); + suit->eventDecrementCharge(); + return suit->GetRemainingCharge(); +} +#endif + +int RemoveLimb(string limb, mixed agent){ + object ob = GetShadowedObject(); + if(!CheckSuit()) return 0; + if(!ob) return 0; + if(suit->GetActive()){ + suit->eventDecrementCharge(); + return 0; + } + return ob->RemoveLimb(limb, agent); +} + +varargs mixed GetEffectiveVision(mixed location, int raw_score){ + object ob = GetShadowedObject(); + if(!CheckSuit()) return 0; + if(!ob) return 0; + if(suit->GetActive()){ + suit->eventDecrementCharge(); + return VISION_CLEAR; + } + return ob->GetEffectiveVision(location, raw_score); +} + +varargs int CanBreathe(mixed args...){ + object ob = GetShadowedObject(); + int rtype; + if(!ob) return 0; + if(!CheckSuit()) return ob->CanBreathe(args); + rtype = ob->GetRespiration(); + if(suit->GetActive()){ + if(rtype & R_AIR){ + suit->eventDecrementCharge(); + return 1; + } + if(rtype & R_WATER || rtype & R_METHANE) return 0; + } + return ob->CanBreathe(args); +} + +void eventDescribeEnvironment(int verbose) { + object ob = GetShadowedObject(); + object env; + string grid, climate,filename,foo,tmp; + int x,y,z,hud = 1; + object *livings; + string extra = "%^CYAN%^Heads-up display info:%^RESET%^\n"; + mapping invisibles = ([]); + int medium, terrain; + + extra += "Power remaining: "+to_int(percent(suit->GetRemainingCharge(), + suit->GetMaxCharge()))+"%\n"; + + if(!ob) return; + if(!CheckSuit() || !suit->GetActive()){ + ob->eventDescribeEnvironment(verbose); + return; + } + + if( !(env = room_environment(ob)) ) { + message("room_description", "No environment.", this_object()); + return; + } + + filename = file_name(env); + livings = filter(get_livings(env), (: $1->GetInvis() :) ); + medium = env->GetMedium(); + terrain = env->GetTerrain(); + climate = env->GetClimate(); + grid = ROOMS_D->GetCoordinates(env); + + if(grid){ + hud = 1; + extra += "Global coordinates: "+grid+"\n"; + } + + foo = last_string_element(filename,"/"); + if(sscanf(foo,"%d,%d,%d", x,y,z) == 3 || + sscanf(foo,"%d,%d", x,y) == 2){ + hud = 1; + extra += "Local coordinates: "+x+","+y+","+z+"\n"; + } + if(climate){ + hud = 1; + extra += "Climate: "+climate+"\n"; + } + if(terrain){ + hud = 1; + extra += "Terrain: "; + if(terrain & T_OUTDOORS) extra += " outdoors "; + if(terrain & T_INDOORS) extra += " indoors "; + if(terrain & T_ROAD) extra += " road "; + if(terrain & T_UNDERWATER) extra += " underwater "; + if(terrain & T_SURFACE) extra += "surface "; + if(terrain & T_MIDAIR) extra += " midair "; + if(terrain & T_SWAMP) extra += " swamp "; + if(terrain & T_WOODS) extra += " woods "; + if(terrain & T_JUNGLE) extra += " jungle "; + if(terrain & T_ROUGH) extra += " rough "; + if(terrain & T_UNDERGROUND) extra += " underground "; + if(terrain & T_SPACE) extra += " space "; + if(terrain & T_MAGMA) extra += " magma "; + if(terrain & T_PLASMA) extra += " plasma "; + if(terrain & T_PLANAR) extra += " planar "; + if(terrain & T_SNOW) extra += " snow "; + if(terrain & T_SAND) extra += " sand "; + if(terrain & T_ICE) extra += " ice "; + if(terrain & T_BIOLOGICAL) extra += " biological "; + if(terrain & T_SEAFLOOR) extra += " seafloor "; + extra += "\n"; + } + + if(medium){ + hud = 1; + extra += "Medium: "; + switch(medium){ + case MEDIUM_LAND : extra += "land\n"; break; + case MEDIUM_AIR : extra += "air\n"; break; + case MEDIUM_SPACE : extra += "space\n"; break; + case MEDIUM_WATER : extra += "water\n"; break; + case MEDIUM_SURFACE : extra += "surface\n"; break; + default: extra += "unknown\n"; + } + } + + if(sizeof(livings)){ + hud = 1; + foreach(object dude in livings){ + if(!invisibles[dude->GetRace()]) invisibles[dude->GetRace()] = 1; + else invisibles[dude->GetRace()]++; + } + foreach(mixed key, mixed val in invisibles){ + if(!key) continue; + extra += "Invisible "+pluralize(key)+": "+val+"\n"; + } + } + + ob->eventDescribeEnvironment(verbose); + if(hud) message("system", extra, ob); +} + +varargs int eventReceiveDamage(mixed agent, int type, int x, int internal, mixed limbs) { + object ob = GetShadowedObject(); + string evidence, limb_string; + + if(!CheckSuit()) return 0; + if(!ob) return 0; + if(internal || !suit->GetActive()) return ob->eventReceiveDamage(agent, type, x, internal, limbs); + + if(reporting){ + string *damtypes = TYPES_D->eventCalculateTypes("damage", type); + evidence = "The powered suit's Heads-Up-Display issues an alert:\n"; + evidence += "%^BOLD%^%^RED%^"; + if(objectp(agent)) evidence += "Damage received!"; + if(type && sizeof(damtypes)) { + string verboid; + if(sizeof(damtypes) > 1) verboid = "s are "; + else verboid = " is "; + + evidence += " Damage type"+verboid; + evidence += lower_case(implode(damtypes,", ")); + } + + else evidence += " Damage type is UNKNOWN"; + } + + if(limbs) { + if(stringp(limbs)) limb_string = limbs; + else if(arrayp(limbs)) { + if(stringp(limbs[0])) limb_string = implode(limbs,", "); + else if(objectp(limbs[0])){ + foreach(object limb in limbs){ + limb_string += limb->GetKeyName()+", "; + } + } + } + } + else limb_string = ". Location indeterminate. "; + if(limbs) { + evidence += ". Location: "; + evidence += limb_string + "."; + } + this_object()->eventPrint(evidence+"%^RESET%^"); + + this_object()->eventPrint("%^YELLOW%^Power level drained: "+x+" units.%^RESET%^"); + suit->eventDecrementCharge(x); + return 1; +} + +int AddLead(string ammo,int number){ + return 0; +} diff --git a/lib/shadows/zombie.c b/lib/shadows/zombie.c new file mode 100644 index 0000000..76b29d5 --- /dev/null +++ b/lib/shadows/zombie.c @@ -0,0 +1,57 @@ +#include +#include +#include ROOMS_H +#include + +inherit LIB_SHADOW; +int count = 300; + +void heart_beat(){ + object env = room_environment(GetShadowedObject()); + if(!env) return; + count--; + this_object()->eventPrint("You hunger for brains."); + if(!(count % 10) && env){ + tell_room(env,this_object()->GetName()+" shudders and groans.", + ({ this_object() }) ); + GetShadowedObject()->eventReceiveDamage("decay",OTHER,random(50),1); + } + if(count < 0){ + mixed *inv = all_inventory(GetShadowedObject()); + tell_room(env,this_object()->GetName()+" falls apart!", + ({ this_object() }) ); + if(sizeof(inv)) inv->eventMove(env); + foreach(mixed element in this_object()->GetLimbs()){ + this_object()->RemoveLimb(element,"decay",1); + } + this_object()->eventMove(ROOM_FURNACE); + } +} + +int eventForce(string cmd){ + if(interactive(GetShadowedObject())) return 0; + return GetShadowedObject()->eventForce(cmd); +} + +mixed eventTalkRespond(mixed args...){ + string cmd = ""; + string *punct = ({".",",","!","?",";"}); + if(sizeof(args) > 3) cmd = args[3]; + cmd = lower_case(cmd); + if(sizeof(cmd) && member_array(last(cmd, 1), punct) != -1){ + cmd = truncate(cmd, 1); + } + //No commanding players plz + if(interactive(GetShadowedObject())) return 0; + call_out( (: eventForce :), 1, cmd); + return 1; +} + +int eventShadow(object whom){ + if(userp(whom)) return 0; + whom->SetEncounter(0); + whom->SetGuard(0); + whom->SetNoClean(1); + set_heart_beat((query_heart_beat(whom) || 1)); + return ::eventShadow(whom); +} diff --git a/lib/std/README b/lib/std/README new file mode 100644 index 0000000..4bf5e4f --- /dev/null +++ b/lib/std/README @@ -0,0 +1,8 @@ +This directory (grudgingly) exists for backward-compatibility +with backward libs. It is intended to contain files which +don't have much code at all. Rather, they are placeholders for +the files that really *should* be inherited. + +If there *are* code-heavy files here, they are usually lifted +directly from some older lib, and should not be considered a +canonical way of doing things. diff --git a/lib/std/board/bboard.c b/lib/std/board/bboard.c new file mode 100644 index 0000000..d25c1b3 --- /dev/null +++ b/lib/std/board/bboard.c @@ -0,0 +1,11 @@ +#include +inherit LIB_BOARD; + +void create(){ + ::create(); +} + +void init(){ + ::init(); +} + diff --git a/lib/std/death.c b/lib/std/death.c new file mode 100644 index 0000000..9a8de22 --- /dev/null +++ b/lib/std/death.c @@ -0,0 +1,73 @@ +#include +#include +#include ROOMS_H + +inherit LIB_ROOM; + +string FunkyPic(); +int CheckChat(); +int StartHeart(object ob); + +static void create() { + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("off the mortal coil"); + SetLong( (:FunkyPic:) ); + SetObviousExits("no exit"); + set_heart_beat(10); + SetNoModify(1); +} + +void init(){ + ::init(); + add_action("regenerate","regenerate"); + add_action("regenerate","choose"); + add_action("wander","wander"); + this_object()->CheckChat(); +} + +string FunkyPic(){ + return "YOU ARE DEAD!!!"; +} + +int regenerate(){ + write("With a great rush of matter and energy, you rematerialize "+ + "into a corporeal state, and find yourself in a familiar place..."); + this_player()->eventRevive(); + this_player()->eventMoveLiving(ROOM_START); + return 1; +} + +int wander(){ + write("There is a strange, hollow vibration all around you, and you "+ + "realize that some force is compelling your ethereal form elsewhere..."+ + "you find yourself in a place that is known to you, yet oddly new."); + this_player()->eventMoveLiving(ROOM_START); + return 1; +} + +void heart_beat(){ + tell_room(this_object(), "A voice whispers: \" You may choose to "+ + "regenerate into a new body here.\""); + return; +} + + +int CanRelease(object ob){ + if(userp(ob) && ob->GetGhost() && environment(ob) == this_object()) { + tell_player(ob,"\n%^RED%^Your undead spirit is recalled and as you leave "+ + "the underworld a new body regenerates around you. "+ + "You live again!%^RESET%^\n"); + ob->eventRevive(); + } + return 1; +} + +int CanReceive(object ob){ + if(!living(ob)){ + return 0; + } + return ::CanReceive(ob); +} + diff --git a/lib/std/estate.c b/lib/std/estate.c new file mode 100644 index 0000000..1371c5a --- /dev/null +++ b/lib/std/estate.c @@ -0,0 +1,39 @@ +/* /std/estate.c + * from Nightmare IV + * a standard estate entrance + * created by Descartes of Borg 940702 + */ + +#include + +inherit OBJECT; + +string __Exit; + +void create() { + ::create(); + SetId( ({ "estate" }) ); + SetPreventGet("You cannot get an entire estate!"); + SetPreventPut("How could you do that with an estate?"); + SetPreventDrop("One wonders how you got this to begin with."); + SetNoClean(1); +} + +void init() { + ::init(); + add_action("cmd_enter", "enter"); +} + +void set_exit(string str) { __Exit = str; } + +static int cmd_enter(string str) { + if(present(str, environment(this_object())) != this_object()) return 0; + this_player()->move_player(__Exit, "into the estate"); + return 1; +} + +void SetShort(string str) { + SetId(GetId() + ({ lower_case(str) }) ); + ::SetShort(str); +} + diff --git a/lib/std/freezer.c b/lib/std/freezer.c new file mode 100644 index 0000000..896cbbf --- /dev/null +++ b/lib/std/freezer.c @@ -0,0 +1,30 @@ +#include +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetNoClean(1); + SetProperties(([ "login" : ROOM_START ])); + SetShort( "The freezer"); + SetLong( "The local freezer. Go down to leave."); + SetObviousExits("down"); + SetExits( ([ "down" : ROOM_START ]) ); + call_out("clean_room", MAX_NET_DEAD_TIME); + SetNoModify(1); +} + +static void clean_room(){ + object ob; + call_out((: clean_room :), MAX_NET_DEAD_TIME); + foreach(ob in filter(all_inventory(), (: living($1) :))){ + string name = last_string_element(base_name(ob),"/"); + if(!user_exists(name)) continue; + ob->eventDestruct(); + } +} + +void init(){ + ::init(); +} diff --git a/lib/std/furnace.c b/lib/std/furnace.c new file mode 100644 index 0000000..240341a --- /dev/null +++ b/lib/std/furnace.c @@ -0,0 +1,10 @@ +#include + +inherit LIB_FURNACE; + +void create() { + furnace::create(); +} +void init(){ + ::init(); +} diff --git a/lib/std/lib/pile.c b/lib/std/lib/pile.c new file mode 100644 index 0000000..517c7bf --- /dev/null +++ b/lib/std/lib/pile.c @@ -0,0 +1,11 @@ +#include + +inherit LIB_PILE; + +void create(){ + ::create(); +} + +void init(){ + ::init(); +} diff --git a/lib/std/monster.c b/lib/std/monster.c new file mode 100644 index 0000000..ae38de1 --- /dev/null +++ b/lib/std/monster.c @@ -0,0 +1,11 @@ +#include + +inherit LIB_SENTIENT; + +void create(){ + sentient::create(); +} + +void init(){ + sentient::init(); +} diff --git a/lib/std/pod.c b/lib/std/pod.c new file mode 100644 index 0000000..62da2f9 --- /dev/null +++ b/lib/std/pod.c @@ -0,0 +1,16 @@ +#include +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("the incept pod"); + SetLong("The incept pod. Some objects come here to be created "+ + "and identified. Go down to get out."); + SetExits( ([ "down" : ROOM_START ]) ); +} +int CanReceive(object ob){ + return room::CanReceive(ob); +} diff --git a/lib/std/prop_logic.c b/lib/std/prop_logic.c new file mode 100644 index 0000000..3c99472 --- /dev/null +++ b/lib/std/prop_logic.c @@ -0,0 +1,50 @@ +// File: /std/prop_logic.c +// Purpose: generic heirachic property setting mechanism +// History: +// 92-05-01 Buddha@TMI-2 Written for object properties +// 93-03-17 Pallando@Tabor Cleaned up code and modularised. +// 93-06-08 Pallando@Nightmare Used for material properties + +static nomask mixed _query( mapping map, string *parts ) +{ + mixed value; + int i, s; + + value = map; + s = sizeof( parts ); + for( i = 0 ; i < s ; i++ ) + { + if( undefinedp( value = value[parts[i]] ) ) + break; + if( !mapp( value ) ) + break; + } + return value; +} + +static nomask int _delete( mapping map, string *parts ) +{ + if( sizeof( parts ) == 1 ) + { + map_delete( map, parts[0] ); + return 1; + } + if( !map[parts[0]] || !mapp( map[parts[0]] ) ) + return 0; + return _delete( map[parts[0]], parts[1..sizeof( parts )-1] ); +} + +static nomask mixed _set( mapping map, string *parts, mixed value ) +{ + mixed old_value; + + if( sizeof( parts ) == 1 ) + { + old_value = map[parts[0]]; + map[parts[0]] = value; + return old_value; + } + if( !map[parts[0]] || !mapp( map[parts[0]] ) ) + map[parts[0]] = ([ parts[1] : 0 ]); + return _set( map[parts[0]], parts[1..sizeof( parts )-1], value ); +} diff --git a/lib/std/quest_ob.c b/lib/std/quest_ob.c new file mode 100644 index 0000000..3535a17 --- /dev/null +++ b/lib/std/quest_ob.c @@ -0,0 +1,12 @@ +#include +#include + +inherit OBJ_QUEST; + +void create(){ + ::create(); +} + +void init(){ + ::init(); +} diff --git a/lib/std/room.c b/lib/std/room.c new file mode 100644 index 0000000..7685009 --- /dev/null +++ b/lib/std/room.c @@ -0,0 +1,11 @@ +#include + +inherit LIB_ROOM; + +void create(){ + ::create(); +} + +void init(){ + ::init(); +} diff --git a/lib/std/server.txt b/lib/std/server.txt new file mode 100644 index 0000000..7f059a4 --- /dev/null +++ b/lib/std/server.txt @@ -0,0 +1,22 @@ +#define __DIR__ "/domains/CHANGEME/virtual/" + +mixed compile_object(string file) { + string *path; + object ob; + int x, y, z, elements; + if(grepp(file, "/user_") || grepp(file, "/object_")){ + ob = new("/domains/CHANGEME/virtual/void"); + if(!ob){ + return "No void room available."; + } + return ob; + } + path = explode(file, "/"); + if( file_size(__DIR__ + path[3] + ".c") < 1 ) return "bad file"; + if( (elements = sscanf(path[4], "%d,%d,%d", x, y, z)) != 3 ) { + if( (elements = sscanf(path[4], "%d,%d", x, y)) != 2 ) return "missing comma"; + } + if( elements == 2 && !(ob = new(__DIR__ + path[3], x, y)) ) return "failed to compile"; + else if( elements == 3 && !(ob = new(__DIR__ + path[3], x, y, z)) ) return "failed to compile"; + return ob; +} diff --git a/lib/std/virtual_void.txt b/lib/std/virtual_void.txt new file mode 100644 index 0000000..9e86a68 --- /dev/null +++ b/lib/std/virtual_void.txt @@ -0,0 +1,18 @@ +#include +#include +#include +#include +#include +#define __DIR__ "/domains/CHANGEME/virtual/" + +inherit LIB_VIRT_LAND; + +varargs static void create(int x, int y) { + SetNoReplace(1); + virt_land::create(); + SetClimate("temperate"); + SetAmbientLight(30); + SetLong("A featureless void."); + SetShort("an empty place"); + AddExit("down", ROOM_START); +} diff --git a/lib/std/void.c b/lib/std/void.c new file mode 100644 index 0000000..622a4ac --- /dev/null +++ b/lib/std/void.c @@ -0,0 +1,16 @@ +#include +#include ROOMS_H + +inherit LIB_ROOM; + +void create() { + room::create(); + SetAmbientLight(30); + SetShort("the void"); + SetLong("The void. Go down to get out."); + SetExits( ([ "down" : ROOM_START ]) ); + SetNoModify(1); +} +void init(){ + ::init(); +} diff --git a/lib/std/wiz_hall.c b/lib/std/wiz_hall.c new file mode 100644 index 0000000..dba7910 --- /dev/null +++ b/lib/std/wiz_hall.c @@ -0,0 +1,27 @@ +#include +#include ROOMS_H + +inherit LIB_ROOM; + +static void create() { + object ob; + room::create(); + SetClimate("indoors"); + SetAmbientLight(30); + SetShort("Creators' Hall"); + SetLong("A generic Wiz Hall."); + SetProperty("no attack", 1); + SetProperty("nopeer",1); +} + +int CanReceive(object ob) { + if(playerp(ob) && !creatorp(ob) && !present("testchar badge",ob)) { + message("info","Creator staff only, sorry.", ob); + return 0; + } + return ::CanReceive(ob); +} + +void init(){ + ::init(); +} diff --git a/lib/tmp/imc2.log b/lib/tmp/imc2.log new file mode 100644 index 0000000..b33d6c0 --- /dev/null +++ b/lib/tmp/imc2.log @@ -0,0 +1,1503 @@ +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 +address: 50.116.16.90 +resolved: 50.116.16.90 +key: 1 diff --git a/lib/tmp/opc.efun b/lib/tmp/opc.efun new file mode 100644 index 0000000..f1dfd84 --- /dev/null +++ b/lib/tmp/opc.efun @@ -0,0 +1,274 @@ +_to_int : 0 +_to_float : 0 +this_player : 0 +previous_object : 0 +call_stack : 0 +sizeof : 4 +destruct : 0 +file_name : 2 +capitalize : 0 +random : 0 +defer : 0 +all_inventory : 0 +first_inventory : 0 +next_inventory : 0 +move_object : 0 +command : 0 +living : 0 +set_living_name : 0 +find_living : 0 +find_player : 0 +notify_fail : 0 +lower_case : 0 +save_variable : 0 +restore_variable : 0 +write : 0 +shout : 0 +receive : 0 +find_call_out : 0 +values : 0 +keys : 0 +clonep : 0 +intp : 0 +undefinedp : 2 +floatp : 0 +stringp : 4 +virtualp : 0 +functionp : 0 +pointerp : 0 +objectp : 4 +classp : 0 +typeof : 0 +bufferp : 0 +allocate_buffer : 0 +replace_program : 0 +crc32 : 0 +file_size : 2 +mkdir : 0 +rm : 0 +rmdir : 0 +localtime : 0 +query_idle : 0 +query_snoop : 0 +query_snooping : 0 +set_heart_beat : 0 +query_heart_beat : 0 +set_hide : 0 +query_shadowing : 0 +throw : 0 +deep_inherit_list : 0 +shallow_inherit_list : 0 +mapp : 0 +interactive : 2 +has_mxp : 0 +has_zmp : 0 +has_gmcp : 0 +send_gmcp : 0 +in_edit : 0 +in_input : 0 +userp : 0 +get_config : 0 +query_privs : 0 +children : 0 +reload_object : 0 +error : 0 +ed_cmd : 0 +mud_status : 0 +set_eval_limit : 0 +function_profile : 0 +cos : 0 +sin : 0 +tan : 0 +asin : 0 +acos : 0 +atan : 0 +sqrt : 0 +log : 0 +log10 : 0 +log2 : 0 +exp : 0 +floor : 0 +ceil : 0 +round : 0 +norm : 0 +refs : 0 +parse_remove : 0 +remove_shadow : 0 +copy : 0 +pluralize : 0 +file_length : 0 +upper_case : 0 +fetch_variable : 0 +remove_interactive : 0 +debug_message : 0 +function_owner : 0 +base_name : 0 +num_classes : 0 +assemble_class : 0 +disassemble_class : 0 +shuffle : 0 +element_of : 0 +abs : 0 +query_charmode : 0 +remove_charmode : 0 +remove_get_char : 0 +send_nullbyte : 0 +socket_close : 0 +socket_error : 0 +set_author : 0 +_call_other : 0 +_evaluate : 0 +_this_object : 6 +_new : 0 +bind : 0 +explode : 2 +implode : 0 +call_out : 0 +member_array : 0 +input_to : 0 +environment : 0 +deep_inventory : 0 +say : 0 +tell_room : 0 +present : 0 +add_action : 0 +query_verb : 0 +remove_action : 0 +commands : 0 +disable_commands : 0 +enable_commands : 0 +livings : 0 +replace_string : 0 +restore_object : 0 +save_object : 0 +users : 0 +get_dir : 0 +strsrch : 0 +tell_object : 0 +message : 0 +find_object : 0 +allocate_mapping : 0 +map_delete : 0 +match_path : 0 +inherits : 0 +regexp : 0 +reg_assoc : 0 +allocate : 0 +call_out_info : 0 +read_buffer : 0 +write_buffer : 0 +write_file : 0 +rename : 0 +write_bytes : 0 +read_bytes : 0 +read_file : 2 +cp : 0 +link : 0 +clear_bit : 0 +test_bit : 0 +set_bit : 0 +next_bit : 0 +crypt : 0 +oldcrypt : 0 +ctime : 0 +exec : 0 +function_exists : 0 +objects : 0 +query_host_name : 0 +query_ip_name : 0 +query_ip_number : 0 +snoop : 0 +remove_call_out : 0 +shadow : 0 +sort_array : 0 +time : 5 +unique_array : 0 +unique_mapping : 0 +printf : 0 +sprintf : 0 +stat : 0 +send_zmp : 0 +master : 0 +memory_info : 0 +set_privs : 0 +get_char : 0 +uptime : 0 +strcmp : 0 +flush_messages : 0 +ed_start : 0 +query_ed_mode : 0 +cache_stats : 0 +filter : 0 +map : 0 +malloc_status : 0 +dumpallobj : 0 +dump_file_descriptors : 0 +query_load_average : 0 +origin : 0 +reclaim_objects : 0 +opcprof : 1 +resolve : 0 +act_mxp : 0 +request_term_type : 0 +start_request_term_type : 0 +request_term_size : 0 +shutdown : 0 +pow : 0 +dotprod : 0 +distance : 0 +angle : 0 +debug_info : 0 +dump_prog : 0 +id_matrix : 0 +translate : 0 +scale : 0 +rotate_x : 0 +rotate_y : 0 +rotate_z : 0 +lookat_rotate : 0 +parse_init : 0 +parse_refresh : 0 +parse_sentence : 0 +parse_add_rule : 0 +parse_add_synonym : 0 +parse_dump : 0 +parse_my_rules : 0 +query_notify_fail : 0 +named_livings : 0 +functions : 0 +variables : 0 +heart_beats : 0 +terminal_colour : 0 +replaceable : 0 +program_info : 0 +store_variable : 0 +query_ip_port : 0 +zonetime : 0 +is_daylight_savings_time : 0 +repeat_string : 0 +memory_summary : 0 +query_replaced_program : 0 +network_stats : 0 +real_time : 0 +event : 0 +query_num : 0 +get_garbage : 0 +fetch_class_member : 0 +store_class_member : 0 +max : 0 +min : 0 +string_difference : 0 +restore_from_string : 0 +classes : 0 +socket_create : 0 +socket_bind : 0 +socket_listen : 0 +socket_accept : 0 +socket_connect : 0 +socket_write : 0 +socket_release : 0 +socket_acquire : 0 +socket_address : 0 +socket_status : 0 +domain_stats : 0 +author_stats : 0 diff --git a/lib/tmp/opc.eoper b/lib/tmp/opc.eoper new file mode 100644 index 0000000..a87fdae --- /dev/null +++ b/lib/tmp/opc.eoper @@ -0,0 +1,120 @@ +efun0 : 0 +pop : 12 +efun2 : 0 +efun3 : 0 +efun4 : 0 +efun5 : 0 +efun6 : 0 +efun7 : 0 +efun8 : 0 +number : 0 +real : 0 +byte : 18 +-byte : 3 +string : 125 +short_string : 41 +const0 : 15 +const1 : 11 +aggregate : 7 +aggregate_assoc : 3 +branch_ne : 0 +branch_ge : 0 +branch_le : 0 +branch_eq : 0 +branch_when_zero : 18 +branch_when_non_zero : 7 +branch : 4 +bbranch_when_zero : 0 +bbranch_when_non_zero : 0 +bbranch : 0 +bbranch_lt : 0 +foreach : 0 +next_foreach : 0 +exit_foreach : 0 +loop_cond_local : 0 +loop_cond_number : 0 +loop_incr : 0 +while_dec : 0 +|| : 4 +&& : 16 +catch : 0 +end_catch : 0 +time_expression : 0 +end_time_expression : 0 +switch : 0 +call : 8 +call_inherited : 6 +return : 5 +return_zero : 21 +== : 2 +!= : 0 +<= : 0 +< : 2 +>= : 0 +> : 4 +inc(x) : 0 +dec(x) : 0 +++x : 0 +x++ : 0 +--x : 0 +x-- : 0 +transfer_local : 0 +make_ref : 0 +kill_refs : 0 +local : 38 +local_lvalue : 18 +ref : 0 +ref_lvalue : 0 +global : 3 +global_lvalue : 42 +member : 0 +member_lvalue : 0 +index : 0 +index_lvalue : 0 +rindex : 0 +rindex_lvalue : 0 +nn_range : 0 +nn_range_lvalue : 0 +rn_range : 0 +rn_range_lvalue : 0 +rr_range : 0 +rr_range_lvalue : 0 +nr_range : 0 +nr_range_lvalue : 0 +ne_range : 0 +re_range : 0 ++= : 0 +-= : 0 +&= : 0 +|= : 0 +^= : 0 +<<= : 0 +>>= : 0 +*= : 0 +/= : 0 +%= : 0 +assign : 9 +(void)+= : 0 +(void)assign : 51 +(void)assign_local : 6 ++ : 2 +subtract : 0 +* : 0 +/ : 0 +% : 0 +& : 0 +| : 0 +^ : 0 +<< : 0 +>> : 0 +! : 6 +- : 0 +~ : 0 +(::) : 0 +simul_efun : 4 +sscanf : 6 +parse_command : 0 +new_class : 0 +new_empty_class : 0 +expand_varargs : 0 +efun119 : 0 diff --git a/lib/verbs/admins/include/adverb.h b/lib/verbs/admins/include/adverb.h new file mode 100644 index 0000000..bdb6324 --- /dev/null +++ b/lib/verbs/admins/include/adverb.h @@ -0,0 +1,8 @@ +#ifndef l_adverb_h +#define l_adverb_h + +static void create(); +mixed can_adverb_wrd_str(string wrd, string adverb); +mixed do_adverb_wrd_str(string wrd, string adverb); + +#endif /* l_adverb_h */ diff --git a/lib/verbs/builders/add.c b/lib/verbs/builders/add.c new file mode 100644 index 0000000..260bb5d --- /dev/null +++ b/lib/verbs/builders/add.c @@ -0,0 +1,113 @@ +#include +#include +#include ROOMS_H +#include +#include + +inherit LIB_VERB; + +mixed do_add_obj_to_obj(object ob, object ob2); + +static void create() { + verb::create(); + SetVerb("add"); + SetRules("OBJ", "OBJ to OBJ", "OBJ to here", "OBJ to room"); + SetErrorMessage("Add what?"); + SetHelp("Syntax: add to \n" + " add \n" + "This command adds the first object to the permanent " + "inventory of the second object, if you have access " + "privileges to both files. You will be prompted for input. " + "If the taget is an NPC, you can input a command for the " + "NPC to execute when it is created, such as: wear shirt\n" + "Otherwise, enter the number of these items you want when " + "prompted.\n" + "\nSee also: copy, create, delete, modify, reload, initfix "); +} + + + +mixed can_add_obj_to_obj(string one, string two){ + if(!builderp(this_player())) return "This command is not for regular players."; + return 1; +} +mixed can_add_obj_to_here(string one) { return 1; } +mixed can_add_obj(string one) { return 1; } +mixed can_add_obj_to_room(string one) { return 1; } + + +mixed do_add_obj_to_here(object ob){ + return do_add_obj_to_obj(ob, environment(this_player())); +} + +mixed do_add_obj_to_room(object ob){ + return do_add_obj_to_obj(ob, environment(this_player())); +} + +mixed do_add_obj(object ob){ + return do_add_obj_to_obj(ob, environment(this_player())); +} + +mixed do_add_obj_to_obj(object ob, object ob2) { + object staff; + string str, sourcefile; + staff = present("tanstaafl",this_player()); + if(!staff) { + write("You must be holding the creator staff in order to use this command."); + write("If you don't know where you put it, get another one from the chest "); + write("in your workroom."); + return 1; + } + str = base_name(ob2)+".c"; + sourcefile = base_name(ob)+".c"; + + if(userp(ob)){ + write("You can't do that to a player."); + return 1; + } + + if(!living(ob2) && + !inherits(LIB_STORAGE,ob2) && + !inherits(LIB_WORN_STORAGE,ob2) && + !inherits(LIB_ROOM,ob2)){ + write("That object is not intended to contain other objects. Addition halted."); + write("If you are sure this is incorrect, then the target object may be "); + write("missing a working init function. Fix it with the initfix command."); + return 0; + } + + if(!check_privs(this_player(),str)){ + write("You lack sufficient privileges for this operation on "+str+". Addition failed."); + return 0; + } + + if(!check_read(sourcefile)){ + write("You lack sufficient privileges for this operation on "+sourcefile+". Addition failed."); + return 0; + } + + if(!file_exists(sourcefile) || !file_exists(str)) { + write("That file no longer exists."); + return 0; + } + + if(base_name(ob2) == LIB_DUMMY) ob = environment(this_player()); + if(base_name(ob) == LIB_DUMMY) { + write("That's not the kind of thing you can add to something."); + return 1; + } + + if(starts_with(base_name(ob2),"/lib/")) { + write("This appears to be a library object. Canceling modification."); + return 1; + } + + if(ob2->GetNoModify()){ + write("This object must be modified by hand."); + return 1; + } + + if(staff->eventAddItem(ob2, base_name(ob))) + if(ob) ob->eventMove(ROOM_FURNACE); + return 1; +} diff --git a/lib/verbs/builders/copy.c b/lib/verbs/builders/copy.c new file mode 100644 index 0000000..b408764 --- /dev/null +++ b/lib/verbs/builders/copy.c @@ -0,0 +1,136 @@ +#include +#include +#include ROOMS_H +#include +#include + +inherit LIB_VERB; + +mixed do_copy_obj_str(object ob, string str); + +int success; +string sourcefile, targetfile; + +static void create() { + verb::create(); + SetVerb("copy"); + SetRules("STR", "OBJ STR"); + SetErrorMessage("Copy what?"); + SetHelp("Syntax: copy \n" + " copy \n\n" + "With a room's filename as an argument, this command " + "copies everything about that room (except exits) into " + "your current room.\n\n" + "When you specify an object and provide a filename, this " + "command makes a copy of the object's file and gives it " + "the name you provide.\n\n" + "\nSee also: create, delete, modify, reload, initfix, add" ); +} + +mixed can_copy_obj_str(object ob, string str) { return 1; } +mixed can_copy_str(string str) { return 1; } + +mixed do_copy_obj_str(object ob, string str) { + object staff; + staff = present("tanstaafl",this_player()); + if(!staff) { + write("You must be holding the creator staff in order to use this command."); + write("If you don't know where you put it, get another one from the chest "); + write("in your workroom."); + return 1; + } + if(userp(ob)){ + write("No."); + return 1; + } + success = 0; + sourcefile = ""; + targetfile = ""; + if(last(str,2) != ".c") str += ".c"; + str = absolute_path(this_player()->query_cwd(), str); + if( !directory_exists(path_prefix(str)) ) { + write("Directory not found."); + return 1; + } + + sourcefile = base_name(ob)+".c"; + targetfile = str; + if(!check_privs(this_player(),str) || + (!check_privs(this_player(),sourcefile) && + strsrch(sourcefile,"/obj/"))){ + write("You lack sufficient privileges for this operation. Copy failed."); + return 0; + } + if(!file_exists(sourcefile)) { + write("That file no longer exists."); + return 0; + } + else unguarded( (: success = cp(sourcefile, targetfile) :) ); + if(success) { + write("Copy successful."); + return 1; + } + else write("Copy failed."); + return 0; +} + +mixed do_copy_str(string str) { + string str2, tmp, new_room; + mixed source_update; + object staff; + staff = present("tanstaafl",this_player()); + if(!staff) { + write("You must be holding the creator staff in order to use this command."); + write("If you don't know where you put it, get another one from the chest "); + write("in your workroom."); + return 1; + } + str2 = str; + str = absolute_path(this_player()->query_cwd(), str); + + if(last(str,2) != ".c") str += ".c"; + + if( !file_exists(str) ){ + str = path_prefix(base_name(environment(this_player())))+"/"+str2; + if(last(str,2) != ".c") str += ".c"; + } + + if( !file_exists(str) ){ + write("Directory not found."); + return 1; + } + + else if( !(tmp = read_file(str)) || !tmp || tmp == ""){ + write("Unable to read file " + str + "."); + return 1; + } + + if((!check_privs(this_player(),str) && strsrch(str,"/obj/") ) || + !check_privs(this_player(),base_name(environment(this_player()))+".c")){ + write("You lack sufficient privileges for this operation. Copy failed."); + return 1; + } + source_update = load_object("/secure/cmds/creators/update")->cmd("-a "+str); + if(!source_update || !intp(source_update) || source_update == 0) { + write("Your source file doesn't update correctly. Fix it first. Copy aborted."); + return 1; + } + + if(!inherits("/lib/std/room",load_object(str))) { + write("The file you want to copy isn't a recognized room. Copy aborted."); + return 1; + } + + new_room = base_name(environment(this_player())); + + load_object("/secure/cmds/creators/bk")->cmd(new_room+".c"); + write("Backed up this room. To restore from this backup, type: "); + write("restore "+last_string_element(new_room,"/")); + write("Then: update"); + + staff->eventCopyRoom(str,new_room+".c"); + load_object("/secure/cmds/creators/update")->cmd("-a "+new_room); + this_player()->eventMoveLiving(new_room); + write("Room copy complete."); + return 1; +} diff --git a/lib/verbs/builders/createfix.c b/lib/verbs/builders/createfix.c new file mode 100644 index 0000000..80d239d --- /dev/null +++ b/lib/verbs/builders/createfix.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("createfix"); + SetRules("OBJ", "here"); + SetErrorMessage("createfix what?"); + SetHelp("Syntax: createfix \n\n" + "If you have write permissions to the file of the object " + "specified, this command adds a ::create call. Lacking " + "this call makes many objects break or behave unpredictably." + "\nSee also: initfix, copy, create, delete, modify, reload, add"); +} + +mixed can_createfix_obj(string str) { + if(!creatorp(this_player())) + return "This command is only available to builders and creators."; + else return 1; +} + +mixed can_createfix_word(string str) { return can_createfix_obj("foo"); } + +mixed do_createfix_obj(object ob) { + object staff; + string *virts = ({ LIB_VIRT_LAND, LIB_VIRT_SKY, LIB_VIRTUAL, + LIB_VIRT_MAP, LIB_VIRT_SPACE, LIB_VIRT_SURFACE, LIB_VIRT_SUBSURFACE }); + staff = present("tanstaafl",this_player()); + if(!staff) { + write("You must be holding the creator staff in order to use this command."); + write("If you don't know where you put it, get another one from the chest "); + write("in your workroom."); + return 1; + } + + if(ob->GetDoor()) ob = load_object(ob->GetDoor()); + + foreach(string element in virts){ + if(inherits(element, ob)){ + write("This is a virtual item. Aborting modification."); + return 1; + } + } + + if(first(base_name(ob),5) == "/lib/") { + write("This appears to be a lib file. Aborting modification."); + return 1; + } + + if(interactive(ob)) { + write("Players are not createfixable."); + return 1; + } + + if(staff->eventAddCreate(base_name(ob)+".c") == 2) { + write("File already has a working create function."); + } + + else write("Done."); + reload(ob); + return 1; +} + +mixed do_createfix_word(string wrd) { + object ob = environment(this_player()); + return do_createfix_obj(ob); +} diff --git a/lib/verbs/builders/delete.c b/lib/verbs/builders/delete.c new file mode 100644 index 0000000..f0da2c6 --- /dev/null +++ b/lib/verbs/builders/delete.c @@ -0,0 +1,186 @@ +#include +#include +#include ROOMS_H +#include +#include + +inherit LIB_VERB; + +int eventDeleteExit(string str); +int eventDeleteObject(object ob1, object ob2); + +static void create() { + verb::create(); + SetVerb("delete"); + SetRules("enter STR", "room STR", "enter STR", "exit STR", "OBJ", "OBJ from OBJ", "OBJ from here", "OBJ from room"); + SetErrorMessage("Delete what?"); + SetHelp("Syntax: delete exit \n" + " delete \n" + " delete from \n" + " This command removes an object from the permanent " + "inventory of another object. When only one object is specified, " + "this command assumes you mean to remove an object from the " + "inventory of the room you are in.\n" + " If the \"exit\" keyword is used, this command attempts to " + "remove the exit in the direction you specify.\n" + "See also: add, copy, create, delete, modify, reload, initfix"); +} + + +mixed can_delete_exit_str(string str) { + return 1; +} + +mixed can_delete_enter_str(string str) { + return 1; +} + +mixed can_delete_room_str(string str) { + return 1; +} + +mixed can_delete_obj(object ob){ + return 1; +} + +mixed can_delete_obj_from_obj(object ob1, object ob2){ + return 1; +} + +mixed can_delete_obj_from_here(object ob){ + return 1; +} + +mixed can_delete_obj_from_room(object ob){ + return 1; +} + +mixed do_delete_exit_str(string str) { + return eventDeleteExit(str); +} + +mixed do_delete_enter_str(string str) { + return do_delete_exit_str(str); +} + +mixed do_delete_room_str(string str) { + return do_delete_exit_str(str); +} + +mixed do_delete_obj(object ob){ + return eventDeleteObject(ob, environment(this_player())); +} + +mixed do_delete_obj_from_obj(object ob1, object ob2){ + return eventDeleteObject(ob1,ob2); +} + +mixed do_delete_obj_from_room(object ob){ + return do_delete_obj_from_obj(ob, environment(this_player())); +} + +mixed do_delete_obj_from_here(object ob){ + return do_delete_obj_from_obj(ob, environment(this_player())); +} + +int eventDeleteObject(object ob1, object ob2){ + string door; + object staff; + staff = present("tanstaafl",this_player()); + if(!staff) { + write("You must be holding the creator staff in order to use this command."); + write("If you don't know where you put it, get another one from the chest "); + write("in your workroom."); + return 1; + } + + if(userp(ob1) || userp(ob2)){ + write("No."); + return 1; + } + + if(environment(ob1) != ob2) { + write("That doesn't exist there."); + return 1; + } + + if(!check_privs(this_player(),base_name(ob2))){ + write("You lack sufficient privileges for this operation on "+ob2->GetShort()+". Fail."); + return 0; + } + + door = ob1->GetDoor(); + if(door){ + staff->eventDeleteDoor(door); + return 1; + } + + if(starts_with(base_name(ob2),"/lib/")) { + write("This appears to be a library object. Canceling modification."); + return 1; + } + + if(ob2->GetNoModify()){ + write("This object must be modified by hand."); + return 1; + } + + staff->eventGeneralStuff(base_name(ob1)+".c"); + staff->eventGeneralStuff(base_name(ob2)+".c"); + staff->eventDeleteItem(ob1, ob2); + return 1; +} + +int eventDeleteExit(string str){ + string filename; + string *exits; + string *enters; + object *players; + object staff; + staff = present("tanstaafl",this_player()); + if(!staff) { + write("You must be holding the creator staff in order to use this command."); + write("If you don't know where you put it, get another one from the chest "); + write("in your workroom."); + return 1; + } + + filename = base_name(environment(this_player()))+".c"; + exits = load_object(filename)->GetExits(); + enters = load_object(filename)->GetEnters(); + + if(member_array(str,exits) == -1 && member_array(str,enters) == -1) { + write("That exit does not exist here."); + return 1; + } + + if(base_name(environment(this_player())) == ROOM_START){ + write("You should edit the start room by hand. Change cancelled."); + return 1; + } + + if(!check_privs(this_player(),filename)){ + write("You can't delete an exit from a room that is not yours."); + return 1; + } + + players = get_livings(environment(this_player()),1); + if(member_array(str,exits) != -1) staff->eventRemoveExit(str, filename); + else staff->eventRemoveEnter(str, filename); + load_object("/secure/cmds/creators/update")->cmd("-a "+filename); + players->eventMove(load_object(filename)); + + exits = load_object(filename)->GetExits(); + + if(member_array(str,exits) == -1) { + write("Exit successfully removed."); + say(this_player()->GetCapName()+" removes an exit."); + return 1; + } + + else { + write("Exit removal failed."); + return 1; + } + +} diff --git a/lib/verbs/builders/dest.c b/lib/verbs/builders/dest.c new file mode 100644 index 0000000..1f2d1ed --- /dev/null +++ b/lib/verbs/builders/dest.c @@ -0,0 +1,107 @@ +#include +#include +#include +#include ROOMS_H +#include + + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("dest"); + SetRules("OBS"); + SetErrorMessage("dest what?"); + SetHelp("Syntax: dest \n\n" + "Destroy an object.\n" + "See also: zap"); +} + +mixed can_dest_obj(string str){ + if(!builderp(this_player())) return "This command is only available to builders and creators."; + else return 1; +} + +mixed can_dest_str(string str){ + if(!creatorp(this_player())){ + return "Object not found."; + } + return can_dest_obj(str); +} + +mixed do_dest_obj(object ob){ + string name, kn, msg; + if(base_name(ob) == LIB_DUMMY) { + write(capitalize(ob->GetShort())+" isn't a normal destable item. It remains in place."); + return 1; + } + if(archp(ob) && !archp(this_player())){ + write("You can't dest an admin."); + tell_player(ob, this_player()->GetName()+" just tried to dest you."); + return 1; + } + if(!creatorp(this_player()) && strsrch(base_name(ob), homedir(this_player()))){ + write("As a builder, you can only dest items that you created."); + return 1; + } + if(!living(ob)) name = ob->GetShort(); + else { + name = ob->GetName(); + if(interactive(ob)) kn = ob->GetKeyName(); + } + if(kn){ + catch( ob->save_player(kn) ); + } + msg = this_player()->GetMessage( "dest", ob ); + ob->eventDestruct(); + if(ob) destruct(ob); + if(!ob){ + write("You dest "+name+"."); + say(msg); + } + else { + write("The dest fails."); + } + return 1; +} + +mixed do_dest_obs(object *obs) { + foreach(object ob in obs){ + if(!interactive(ob)) do_dest_obj(ob); + } + write("Desting complete."); + return 1; +} + +mixed do_dest_str(string str){ + object ob; + string tmp; + if(last(str,2) == "_D"){ + tmp = DEFINES_D->GetDefine(str); + if(!undefinedp(tmp)) str = tmp; + } + tmp = str; + if(!file_exists(tmp)) tmp += ".c"; + if(!file_exists(tmp)) { + tmp = this_player()->query_cwd()+"/"+str; + } + if(!file_exists(tmp)) tmp += ".c"; + if(!file_exists(tmp)){ + write("Object not found."); + return 1; + } + ob = find_object(tmp); + if(!ob){ + write("Object is not loaded."); + return 1; + } + write("ob: "+identify(ob)); + ob->eventDestruct(); + if(ob) destruct(ob); + if(ob){ + write("Destruct failed."); + return 1; + } + write(str+" destructed."); + return 1; +} diff --git a/lib/verbs/builders/initfix.c b/lib/verbs/builders/initfix.c new file mode 100644 index 0000000..029ba02 --- /dev/null +++ b/lib/verbs/builders/initfix.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("initfix"); + SetRules("OBJ", "here"); + SetErrorMessage("initfix what?"); + SetHelp("Syntax: initfix \n\n" + "If you have write permissions to the file of the object " + "specified, this command adds an init(){} function. Lacking " + "this function makes many objects break or behave unpredictably.\n" + "Please note that initfixing a door also reloads the " + "door's adjoining rooms.\n" + "\nSee also: copy, create, delete, modify, reload, add"); +} + +mixed can_initfix_obj(string str) { + if(!creatorp(this_player())) + return "This command is only available to builders and creators."; + else return 1; +} + +mixed can_initfix_word(string str) { return can_initfix_obj("foo"); } + +mixed do_initfix_obj(object ob) { + object staff; + string *virts = ({ LIB_VIRT_LAND, LIB_VIRT_SKY, LIB_VIRTUAL, + LIB_VIRT_MAP, LIB_VIRT_SPACE, LIB_VIRT_SURFACE, LIB_VIRT_SUBSURFACE }); + staff = present("tanstaafl",this_player()); + if(!staff) { + write("You must be holding the creator staff in order to use this command."); + write("If you don't know where you put it, get another one from the chest "); + write("in your workroom."); + return 1; + } + + if(ob->GetDoor()) ob = load_object(ob->GetDoor()); + + foreach(string element in virts){ + if(inherits(element, ob)){ + write("This is a virtual item. Aborting modification."); + return 1; + } + } + + if(first(base_name(ob),5) == "/lib/") { + write("This appears to be a lib file. Aborting modification."); + return 1; + } + + if(interactive(ob)) { + write("Players are not initfixable."); + return 1; + } + + if(staff->eventAddInit(base_name(ob)+".c") == 2) { + write("File already has a working init function."); + } + + else write("Done."); + if(ob && inherits(LIB_DOOR,ob)){ + string *doors = environment(this_player())->GetDoors(); + if(!sizeof(doors)) return 1; + foreach(string dir in doors){ + string substr = environment(this_player())->GetDoor(dir); + if(last(substr,2) == ".c") substr = truncate(substr,2); + if(substr == base_name(ob)){ + reload(load_object(environment(this_player())->GetExit(dir))); + reload(environment(this_player())); + } + } + } + if(ob) reload(ob); + return 1; +} + +mixed do_initfix_word(string wrd) { + object ob = environment(this_player()); + return do_initfix_obj(ob); +} diff --git a/lib/verbs/builders/modify.c b/lib/verbs/builders/modify.c new file mode 100644 index 0000000..f0e0ca8 --- /dev/null +++ b/lib/verbs/builders/modify.c @@ -0,0 +1,104 @@ +#include +#include +#include ROOMS_H +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("modify"); + SetRules("OBJ STR", "here STR", "room STR"); + SetErrorMessage("Modify what how?"); + SetHelp("Syntax: modify \n\n" + "If you have write permissions to the file of the object " + "specified, this command initiates changes to that file " + "based on the arguments you supply. For example, to change " + "the short description of the room you are in:\n" + "modify here short a nice new room\n" + "To modify an orc npc's desciption (if he's in your current room):\n " + "modify orc long a polite, well-groomed orc.\n\n" + "Available settings are: \n----\n" + "%^GREEN%^room%^RESET%^: "+MODULES_CREATE->GetSettings("room")+"\n--\n" + "%^GREEN%^npc%^RESET%^: "+MODULES_CREATE->GetSettings("npc")+"\n--\n" + "%^GREEN%^barkeep%^RESET%^: "+MODULES_CREATE->GetSettings("barkeep")+"\n--\n" + "%^GREEN%^vendor%^RESET%^: "+MODULES_CREATE->GetSettings("vendor")+"\n--\n" + "%^GREEN%^weapon%^RESET%^: "+MODULES_CREATE->GetSettings("weapon")+"\n--\n" + "%^GREEN%^item%^RESET%^: "+MODULES_CREATE->GetSettings("item")+"\n--\n" + "%^GREEN%^armor%^RESET%^: "+MODULES_CREATE->GetSettings("armor")+"\n--\n" + "%^GREEN%^worn_storage%^RESET%^: "+MODULES_CREATE->GetSettings("worn_storage")+"\n--\n" + "%^GREEN%^chair%^RESET%^: "+MODULES_CREATE->GetSettings("chair")+"\n--\n" + "%^GREEN%^bed%^RESET%^: "+MODULES_CREATE->GetSettings("bed")+"\n--\n" + "%^GREEN%^table%^RESET%^: "+MODULES_CREATE->GetSettings("table")+"\n--\n" + "%^GREEN%^container%^RESET%^: "+MODULES_CREATE->GetSettings("storage")+"\n----\n" + "%^GREEN%^meal%^RESET%^: "+MODULES_CREATE->GetSettings("meal")+"\n----\n" + "%^GREEN%^drink%^RESET%^: "+MODULES_CREATE->GetSettings("meal")+"\n----\n" + "%^GREEN%^door%^RESET%^: "+MODULES_CREATE->GetSettings("door")+"\n----\n" + "%^GREEN%^book%^RESET%^: "+MODULES_CREATE->GetSettings("book")+"\n----\n" + "\nSee also: copy, create, delete, reload, initfix, add"); +} + +mixed can_modify_obj_str(string str) { + if(!builderp(this_player())) return "This command is only available to builders and creators."; + else return 1; +} + +mixed can_modify_word_str(string str) { return can_modify_obj_str("foo"); } + +mixed do_modify_obj_str(object ob, string str) { + object staff; + staff = present("tanstaafl",this_player()); + if(!staff) { + write("You must be holding the creator staff in order to use this command."); + write("If you don't know where you put it, get another one from the chest "); + write("in your workroom."); + return 1; + } + + if(ob->GetDirectionMap()){ + write("This is a virtual thing. It cannot be modified with the QCS."); + return 1; + } + + if(ob->GetNoModify() && !grepp(lower_case(str),"modify")) { + write("This needs to be edited by hand."); + return 1; + } + + if(base_name(ob) == LIB_DUMMY && + !ob->GetDoor()) ob = environment(this_player()); + else if(base_name(ob) == LIB_DUMMY) ob = load_object(ob->GetDoor()); + + if(starts_with(base_name(ob),"/lib/")) { + write("This appears to be a library object. Canceling modification."); + return 1; + } + + if(userp(ob)){ + write("You may not modify a player."); + return 1; + } + + //staff->eventGeneralStuff(base_name(ob)+".c"); + return staff->eventModify(ob, str); +} + +mixed do_modify_word_str(string wrd, string str) { + object staff, ob; + staff = present("tanstaafl",this_player()); + if(!staff) { + write("You must be holding the creator staff in order to use this command."); + write("If you don't know where you put it, get another one from the chest "); + write("in your workroom."); + return 1; + } + + ob = environment(this_player()); + + if(starts_with(base_name(ob),"/lib/")) { + write("This appears to be a library object. Canceling modification."); + return 1; + } + + return do_modify_obj_str(ob, str); +} diff --git a/lib/verbs/builders/pulsecheck.c b/lib/verbs/builders/pulsecheck.c new file mode 100644 index 0000000..b6c8a73 --- /dev/null +++ b/lib/verbs/builders/pulsecheck.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include +#include ROOMS_H +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("pulsecheck"); + SetRules("LVS"); + SetErrorMessage("pulsecheck what?"); + SetHelp("Syntax: pulsecheck \n\n" + "Check a creature's heartbeat.\n" + "See also: zap"); +} + +mixed can_pulsecheck_liv(string str) { + if(!creatorp(this_player())) return "This command is only available to builders and creators."; + else return 1; +} + +mixed do_pulsecheck_liv(object ob){ + string name; + int mhp; + + if(!living(ob)) { + write("You can only pulsecheck living things."); + return 1; + + } + write(ob->GetName()+"'s heart_beat is "+query_heart_beat(ob)+"."); + write(ob->GetName()+"'s HeartRate is "+ob->GetHeartRate()+".\n"); + return 1; +} + +mixed do_pulsecheck_lvs(object *obs) { + foreach(object ob in obs){ + if(!(ob == this_player())) do_pulsecheck_liv(ob); + } + return 1; +} diff --git a/lib/verbs/builders/reload.c b/lib/verbs/builders/reload.c new file mode 100644 index 0000000..73df66b --- /dev/null +++ b/lib/verbs/builders/reload.c @@ -0,0 +1,170 @@ +#include +#include +#include +#include ROOMS_H +#include + +inherit LIB_VERB; + +string libfile = "foo"; +int quiet = 0; + +static void create() { + verb::create(); + SetVerb("reload"); + SetRules("OBJ", "STR OBJ", "STR here", "here", "every STR"); + SetErrorMessage("reload what?"); + SetHelp("Syntax: reload [every] \n\n" + "This command loads into memory the file of the object " + "you specify, and replaces the current copy with a new " + "copy. If you change something about a sword you are " + "holding, for example, \"reload sword\" will update the " + "changes and you will be holding a sword with the updates.\n" + " When used with the -r flag it recursively loads all the objects " + "inherited by the target object. If any of those objects " + "or the target object's file fail to load, the object " + "is not updated.\n" + " If you \"reload every npc\", then any loaded object that " + "inherits LIB_NPC gets reloaded. Other valid lib objects " + "that can be used this way are: room, sentient, armor, item.\n" + "Please note that if there are too many items to reload, " + "the command will fail with \"Too long evaluation\" errors.\n" + " Books, due to their processing-intensive load time, " + "are excluded from the \"every\" keyword.\n" + "Please note that reloading a door also reloads the " + "door's adjoining rooms.\n" + "\nSee also: copy, create, delete, modify, initfix, add"); +} + +mixed can_reload_obj(string str) { + if(!builderp(this_player())) return "This command is only available to builders and creators."; + else return 1; +} + +mixed can_reload_every_str(string str){ + if(!builderp(this_player())) return "This command is only available to builders and creators."; + else return 1; +} + +mixed can_reload_str_obj(string str){ + return can_reload_obj(str); +} + +mixed can_reload_word(string str){ + return can_reload_obj("foo"); +} + +mixed can_reload_str_word(string str, string str2){ + return can_reload_obj("foo"); +} + +mixed do_reload_obj(object ob) { + string s1,s2, foo = "Null object: "; + if(ob && ob->GetDoor()) ob = load_object(ob->GetDoor()); + if(!creatorp(this_player()) && strsrch(base_name(ob), homedir(this_player()))){ + write("Builders can only reload things that belong to them."); + return 1; + } + if(!ob || userp(ob)) { + if(ob) foo = base_name(ob)+": "; + if(!quiet){ + write(foo+"Invalid for reloading."); + } + return -1; + } + if(ob && ob->GetDirectionMap()){ + write(base_name(ob)+" is a virtual room, and not subject to normal reloading."); + return 1; + } + if(!strsrch(base_name(ob),"/open") || + sscanf(base_name(ob),"/realms/%s/tmp/%s",s1,s2) == 2){ + write(base_name(ob)+" is a temp file and not subject to reloading."); + return 1; + } + reload(ob, 0, quiet); + if(ob && inherits(LIB_DOOR,ob)){ + string *doors = environment(this_player())->GetDoors(); + if(!sizeof(doors)) return 1; + foreach(string dir in doors){ + string substr = environment(this_player())->GetDoor(dir); + if(last(substr,2) == ".c") substr = truncate(substr,2); + if(substr == base_name(ob)){ + reload(load_object(environment(this_player())->GetExit(dir))); + reload(environment(this_player())); + } + } + } + return 1; +} + +mixed do_reload_str_obj(string str, object ob) { + if(str == "-r") reload(ob, 1, quiet); + else return reload(ob, 0, quiet); +} + +mixed do_reload_word(string wrd) { + object ob = environment(this_player()); + if(wrd == "here") return do_reload_obj(ob); + else return "failed."; +} + +mixed do_reload_str_word(string wrd1, string wrd2) { + object ob = environment(this_player()); + if(wrd1 == "-r" && wrd2 = "here") reload(ob, 1); + else return "Failed."; +} + +mixed do_reload_every_str(string str){ + object *ob_pool = ({}); + int count; + if(!archp(this_player())){ + write("This verb is intended for arches only."); + return 1; + } + + switch(str){ + case "npc" : libfile = LIB_NPC; break; + case "sentient" : libfile = LIB_SENTIENT; break; + case "room" : libfile = LIB_ROOM; break; + case "weapon" : libfile = LIB_WEAPON; break; + case "item" : libfile = LIB_ITEM; break; + case "container" : libfile = LIB_STORAGE; break; + case "armor" : libfile = LIB_ARMOR; break; + case "worn_storage" : libfile = LIB_WORN_STORAGE; break; + default : libfile = str; + } + + if(!file_exists(libfile) && !file_exists(libfile+".c")){ + write("There is no such library file."); + return 1; + } + + if(last(libfile,2) == ".c") libfile = truncate(libfile,2); + load_object("/secure/cmds/creators/update")->cmd("-a -r "+libfile); + + ob_pool = filter(objects(), (: ( inherits(libfile, $1) ) :) ); + if(!sizeof(ob_pool)) + ob_pool = filter(objects(), (: ( base_name($1) == libfile ) :) ); + + if(!sizeof(ob_pool)) { + write("None found."); + return 1; + } + + quiet = 1; + call_out("unQuiet", 6); + write("Reloading..."); + foreach(object ob in ob_pool){ + if(do_reload_obj(ob) > 0) count++; + } + quiet = 0; + + write("Done. Reloaded "+count+" objects."); + libfile = "foo"; + return 1; +} + +void unQuiet(){ + quiet = 0; +} + diff --git a/lib/verbs/common/ask.c b/lib/verbs/common/ask.c new file mode 100644 index 0000000..0ff6929 --- /dev/null +++ b/lib/verbs/common/ask.c @@ -0,0 +1,118 @@ +/* /verbs/common/ask.c + * from the Dead Souls Object Library + * created by Blitz@Dead Souls + */ + +#include +#include +#include "include/ask.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("ask"); + SetRules("LIV STR", "STR", "LIV to STR", "LIV for STR", "LIV about STR"); + SetErrorMessage("Ask what? Or ask whom to do what?"); + SetHelp("Syntax: ask \n" + " ask \n" + " ask about \n" + " ask to \n" + " ask for \n\n" + "Some npcs and perhaps some inanimate objects will respond " + "when you query the target with a specific question.\n" + "See also: reply, say, shout, speak, tell, whisper, yell"); +} + +mixed can_ask_liv_to_str(string str) { return 1; } + +mixed can_ask_liv_for_str(string str) { return 1; } + +mixed can_ask_liv_about_str(string str) { return 1; } + +mixed can_ask_liv_str(string str) { + string tmp; + + if( !str ) { + str = ""; + } + if( sscanf(str, "to %s", tmp) ) return 1; + else if( sscanf(str, "for %s", tmp) ) return 1; + else return this_player()->CanSpeak(/* ob */0, TALK_LOCAL, str); +} + +mixed can_ask_str(string str) { + return this_player()->CanSpeak(0, TALK_LOCAL, str);; +} + +mixed do_ask_liv_to_str(object ob, string str) { + string lang = this_player()->GetDefaultLanguage(); + //string pre = "In " + lang + ", "; + string pre = "In "; + int lvl; + string msg = translate(str, lvl=(this_player()->GetLanguageLevel(lang))); + if(lvl < 50) pre += "execrable "+lang+", "; + else if(lvl < 60) pre += "very poor "+lang+", "; + else if(lvl < 75) pre += "broken "+lang+", "; + else if(lvl < 99) pre += "imperfect "+lang+", "; + else pre += lang + ", "; + msg = translate(msg, ob->GetLanguageLevel(lang)); + message("my_action", pre + "you ask "+ob->GetName()+" to "+str+".", + this_player() ); + message("other_action", pre + this_player()->GetName()+" asks " + "you to "+msg+".", ob); + message("other_action", pre + this_player()->GetName()+" asks "+ + ob->GetName()+" to do something.", + environment(ob), ({ ob, this_player() }) ); + ob->eventAsk(this_player(), str); + return 1; +} + +mixed do_ask_liv_for_str(object ob, string str) { + string lang = this_player()->GetDefaultLanguage(); + string pre = "In " + lang + ", "; + string msg = translate(str, this_player()->GetLanguageLevel(lang)); + msg = translate(msg, ob->GetLanguageLevel(lang)); + message("my_action", pre + "you ask "+ob->GetName()+" for "+str+".", + this_player() ); + message("other_action", pre + this_player()->GetName()+" asks "+ + ob->GetName()+" for something.", + environment(ob), ({ ob, this_player() }) ); + if( !(ob->eventRequest(this_player(), str)) ) + message("other_action", pre + this_player()->GetName()+" asks " + "you for "+msg+".", ob); + return 1; +} + +mixed do_ask_liv_about_str(object ob, string str) { + string lang = this_player()->GetDefaultLanguage(); + string pre = "In " + lang + ", "; + string msg = translate(str, this_player()->GetLanguageLevel(lang)); + msg = translate(msg, ob->GetLanguageLevel(lang)); + message("my_action", pre + "you ask "+ob->GetName()+" about "+str+".", + this_player() ); + message("other_action", pre + this_player()->GetName()+" asks "+ + ob->GetName()+" about something.", + environment(ob), ({ ob, this_player() }) ); + if( !(ob->eventConsult(this_player(), str)) ) + message("other_action", pre + this_player()->GetName()+" asks " + "you about "+msg+".", ob); + return 1; +} + +mixed do_ask_liv_str(object ob, string str) { + mixed tmp; + if( sscanf(str, "to %s", tmp) ) return do_ask_liv_to_str(ob, tmp); + if( sscanf(str, "for %s", tmp) ) return do_ask_liv_for_str(ob, tmp); + if( sscanf(str, "about %s", tmp) ) return do_ask_liv_about_str(ob, tmp); + if( str[<1] != '?' ) str = capitalize(str) + "?"; + else str = capitalize(str); + return this_player()->eventSpeak(ob, TALK_LOCAL, str); +} + +mixed do_ask_str(string str) { + if( str[<1] != '?' ) str = capitalize(str) + "?"; + else str = capitalize(str); + return this_player()->eventSpeak(0, TALK_LOCAL, str); + return 1; +} diff --git a/lib/verbs/common/body.c b/lib/verbs/common/body.c new file mode 100644 index 0000000..0ca1ec6 --- /dev/null +++ b/lib/verbs/common/body.c @@ -0,0 +1,133 @@ +/* /cmds/player/body.c + * from the Dead Souls LPC Library + * gives player a report based on limb damage + * created by Blitz@Dead Souls + */ + + + +#include +#include + +inherit LIB_VERB; + +varargs void eventCheckBody(object ob, object receiver); + +static void create() { + verb::create(); + SetVerb("body"); + SetRules("", "LIV"); +} + +static string *DamageDegree = ({ + "is in critical condition!", + "is battered beyond recognition.", + "is severely wounded", + "is terribly damaged.", + "is in bad shape.", + "is hurting.", + "has a few bruises.", + "is in decent shape.", + "is in very good shape.", + "is in excellent shape.", + }); + +int livings_are_remote() { return 1; } + +mixed can_body() { + return 1; +} + +mixed can_body_liv() { + if( !creatorp(this_player()) ) + return "Try: help body"; + return 1; +} + +mixed do_body() { + message("other_action", this_player()->GetName()+" checks "+ + reflexive(this_player())+" for injuries.", + environment(this_player()), this_player() ); + eventCheckBody(this_player()); + return 1; +} + +mixed do_body_liv(object ob) { + eventCheckBody(ob, this_player()); + return 1; +} + +varargs void eventCheckBody(object ob, object receiver) { + string ret, name; + string *limbs; + mapping mp; + int i, damage; + int *key; + + mp = ([ ]); + if( !ob ) return; + if( !receiver ) receiver = ob; + i = sizeof(limbs = ob->GetLimbs()); + while(i--) { + damage = to_int( percent( ob->GetHealthPoints(limbs[i]), + ob->GetMaxHealthPoints(limbs[i]) )); + if( !mp[damage] ) mp[damage] = ({ limbs[i] }); + else mp[damage] += ({ limbs[i] }); + } + i = sizeof(key = sort_array(keys(mp), 1)); + name = (ob == receiver ? "Your" : capitalize(possessive(ob))); + ret = possessive_noun(ob->GetCapName()) + " bodily damage " + "report:\n\n"; + foreach(damage in key) { + string str; + string color; + int x; + i = sizeof(limbs = mp[damage]); + while(i--) { + switch(damage) { + case 0..3: color = "%^BOLD%^%^RED%^"; break; + case 4..10: color = "%^RED%^"; break; + case 11..20: color = "%^YELLOW%^"; break; + default: color = ""; + } + if( damage > 97 ) + str = name +" "+ limbs[i] + " is in perfect condition."; + else if( damage < 4 ) + str = name+" "+ limbs[i] +" is about to fall off!"; + else { + x = damage / 10; + if(x>9) x = 9; + str = name +" "+ limbs[i] +" "+ DamageDegree[x]; + } + if( creatorp(receiver) ) + ret += sprintf("%s%-45s %s(%d / 100%%)%s\n", color, str, + "", damage,"%^RESET%^"); + else ret += (color + str + "%^RESET%^\n"); + } + } + if( i = sizeof(limbs = ob->GetMissingLimbs()) ) { + ret += "\n"+(ob == receiver ? + "You are missing " : ob->GetName()+" is missing "); + switch(i) { + case 0: break; + case 1: ret += "a "+limbs[0]+"."; break; + case 2: ret += "a "+limbs[0]+" and a "+limbs[1]+"."; break; + default: ret += "a "+implode(limbs[0..(i-2)], ", ")+" and " + "a "+limbs[i-1]+"."; + } + } + receiver->eventPage(explode(ret, "\n"), "info"); + return; +} + +string GetHelp(string str) { + if( creatorp(this_player()) ) + return "Syntax: body [LIVING]\n\n" + "This command will display the current limb damage " + "statistics of the living object named."; + else + return "Syntax: body\n\n" + "This command will display your current limb damage " + "statistics. The limbs will be displayed in order " + "of the most damaged to the least."; +} diff --git a/lib/verbs/common/channels.c b/lib/verbs/common/channels.c new file mode 100644 index 0000000..2c8a586 --- /dev/null +++ b/lib/verbs/common/channels.c @@ -0,0 +1,104 @@ +#include +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("channels"); + SetRules("", "STR"); + SetHelp("Syntax: channels [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.\n" + "See also: chan, mute, gag, earmuff, env"); + SetSynonyms(({"chans","lines"})); +} + +int cmd(string str); + +mixed can_channels(string str) { return 1; } + +mixed can_channels_str(string str) { return 1; } + +mixed do_channels(string str) { + return cmd(str); +} + +mixed do_channels_str(string str) { + return cmd(str); +} + +int cmd(string str) { + string *channels; + string *remote = ({}); + string *local = ({}); + string *i3 = ({}); + string *imc2 = ({}); + string ret = "", RemChans = CHAT_D->GetRemoteChannels(); + int i; + + channels = distinct_array(this_player()->GetChannels()); + + if(!str) str = ""; + + if(str=="on"){ + for(i=0; iGetBlocked(channels[i])) + this_player()->SetBlocked(channels[i]); + } + } + + if(str=="off"){ + for(i=0; iGetBlocked(channels[i])) + this_player()->SetBlocked(channels[i]); + } + } + + foreach(string chan in channels){ + string tmp = CHAT_D->GetRemoteChannel(chan); + if(member_array(tmp, RemChans) != -1){ + remote += ({ chan }); + if(!strsrch(tmp, "Server") && grepp(tmp, ":")){ + imc2 += ({ chan }); + } + else i3 += ({ chan }); + } + else local += ({ chan }); + } + if(sizeof(remote)){ + ret += "REMOTE CHANNELS\n---------------\n"; + if(sizeof(imc2)){ + imc2 = sort_array(imc2, 1); + ret += "\nIMC2\n----\n"; + foreach(string chan in imc2){ + ret += chan + "\t" + (this_player()->GetBlocked(chan) ? + "(%^RED%^BLOCKED%^RESET%^)" : "") + "\n"; + } + } + if(sizeof(i3)){ + i3 = sort_array(i3, 1); + ret += "\nIntermud-3\n----------\n"; + foreach(string chan in i3){ + ret += chan + "\t" + (this_player()->GetBlocked(chan) ? + "(%^RED%^BLOCKED%^RESET%^)" : "") + "\n"; + } + } + } + if(sizeof(local)){ + local = sort_array(local, 1); + ret += "\n\nLOCAL CHANNELS\n---------------\n"; + foreach(string chan in local){ + ret += chan + "\t" + (this_player()->GetBlocked(chan) ? + "(%^RED%^BLOCKED%^RESET%^)" : "") + "\n"; + } + } + + if(!sizeof(ret)){ + ret = "No channels found."; + } + write(ret); + return 1; +} diff --git a/lib/verbs/common/include/ask.h b/lib/verbs/common/include/ask.h new file mode 100644 index 0000000..08d864e --- /dev/null +++ b/lib/verbs/common/include/ask.h @@ -0,0 +1,13 @@ +#ifndef l_ask_h +#define l_ask_h + +static void create(); + +mixed can_ask_obj_str(string str); +mixed can_ask_str(string str); +mixed do_ask_obj_str(string str); + +mixed do_ask_str(string str); +string GetHelp(string str); + +#endif /* l_ask_h */ diff --git a/lib/verbs/common/include/help.h b/lib/verbs/common/include/help.h new file mode 100644 index 0000000..64cbd1b --- /dev/null +++ b/lib/verbs/common/include/help.h @@ -0,0 +1,15 @@ +#ifndef l_help_h +#define l_help_h + +static void create(); +mixed can_help_str(string str); +mixed do_help_str(string str); +int CanAccess(object who, string index); +varargs void HelpMenu(string index); +static private void LoadIndices(); +string GetHelp(string str); +string GetHelpByIndex(string index, string topic); +varargs string *GetIndices(string topic); +string GetTopic(string index, string topic); + +#endif /* l_help_h */ diff --git a/lib/verbs/common/include/mail.h b/lib/verbs/common/include/mail.h new file mode 100644 index 0000000..7a2d4b4 --- /dev/null +++ b/lib/verbs/common/include/mail.h @@ -0,0 +1,14 @@ +#ifndef l_mail_h +#define l_mail_h + +static void create(); + +mixed can_mail(); +mixed can_mail_str(string str); + +mixed do_mail(); +mixed do_mail_str(string str); + +string GetHelp(string str); + +#endif /* l_mail_h */ diff --git a/lib/verbs/common/include/say.h b/lib/verbs/common/include/say.h new file mode 100644 index 0000000..2f0a06c --- /dev/null +++ b/lib/verbs/common/include/say.h @@ -0,0 +1,15 @@ +#ifndef l_say_h +#define l_say_h + +static void create(); +mixed can_say(); +mixed can_say_to_liv(object ob); +mixed can_say_to_liv_str(object ob, string str); +mixed can_say_str(string str); +mixed do_say(); +mixed do_say_to_liv(object ob); +mixed do_say_to_liv_str(object ob, string str); +mixed do_say_str(string str); +string GetHelp(string str); + +#endif /* l_say_h */ diff --git a/lib/verbs/common/include/shout.h b/lib/verbs/common/include/shout.h new file mode 100644 index 0000000..0b770b2 --- /dev/null +++ b/lib/verbs/common/include/shout.h @@ -0,0 +1,13 @@ +#ifndef l_shout_h +#define l_shout_h + +static void create(); +mixed can_shout(); +mixed can_shout_str(string str); +mixed can_shout_in_wrd_str(string wrd, string str); +mixed do_shout(); +mixed do_shout_str(string str); +mixed do_shout_in_wrd_str(string lang, string str); +string GetHelp(string str); + +#endif /* l_shout_h */ diff --git a/lib/verbs/common/include/speak.h b/lib/verbs/common/include/speak.h new file mode 100644 index 0000000..9d76003 --- /dev/null +++ b/lib/verbs/common/include/speak.h @@ -0,0 +1,15 @@ +#ifndef l_speak_h +#define l_speak_h + +static void create(); +mixed can_speak(); +mixed can_speak_in_wrd(string str); +mixed can_speak_str(string str); +mixed can_speak_in_wrd_str(string word, string str); +mixed do_speak(); +mixed do_speak_in_wrd(string str); +mixed do_speak_str(string str); +mixed do_speak_in_wrd_str(string word, string str); +string GetHelp(string str); + +#endif /* l_speak_h */ diff --git a/lib/verbs/common/include/whisper.h b/lib/verbs/common/include/whisper.h new file mode 100644 index 0000000..62a3c64 --- /dev/null +++ b/lib/verbs/common/include/whisper.h @@ -0,0 +1,21 @@ +#ifndef l_whisper_h +#define l_whisper_h + +static void create(); +mixed can_whisper(); +mixed can_whisper_to_liv(object ob); +mixed can_whisper_in_wrd(string wrd); +mixed can_whisper_in_wrd_to_liv(string wrd, object ob); +mixed can_whisper_to_liv_str(object targ, string str); +mixed can_whisper_in_wrd_to_liv_str(string wrd, object targ, string str); +mixed can_whisper_to_liv_in_wrd_str(object targ, string lang, string str); +mixed do_whisper(); +mixed do_whisper_to_liv(object ob); +mixed do_whisper_in_wrd(string wrd); +mixed do_whisper_in_wrd_to_liv(string wrd, object ob); +mixed do_whisper_to_liv_str(object targ, string str); +mixed do_whisper_in_wrd_to_liv_str(string lang, object targ, string str); +mixed do_whisper_to_liv_in_wrd_str(object targ, string lang, string str); +string GetHelp(string str); + +#endif /* l_whisper_h */ diff --git a/lib/verbs/common/include/yell.h b/lib/verbs/common/include/yell.h new file mode 100644 index 0000000..dc9bb6c --- /dev/null +++ b/lib/verbs/common/include/yell.h @@ -0,0 +1,13 @@ +#ifndef l_yell_h +#define l_yell_h + +static void create(); +mixed can_yell(); +mixed can_yell_str(string str); +mixed can_yell_in_wrd_str(string wrd, string str); +mixed do_yell(); +mixed do_yell_str(string str); +mixed do_yell_in_wrd_str(string lang, string str); +string GetHelp(string str); + +#endif /* l_yell_h */ diff --git a/lib/verbs/common/mail.c b/lib/verbs/common/mail.c new file mode 100644 index 0000000..3c09357 --- /dev/null +++ b/lib/verbs/common/mail.c @@ -0,0 +1,70 @@ +/* /verbs/common/mail.c + * from the Dead Souls Mud Library + * mail + * mail STR + * created by Descartes of Borg 950113 + */ + + + +#include +#include +#include "include/mail.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("mail"); + SetRules("","STR"); +} + +mixed can_mail() { return can_mail_str(""); } + +mixed can_mail_str(string str) { + if( !str ) return 0; + else if( str == "" ) str = 0; + if( !creatorp(this_player()) ) { + mixed tmp; + + tmp = environment(this_player())->CanMail(this_player(), str); + if( !tmp ) return "Does this place look like a post office?"; + else return tmp; + } + return 1; +} + +mixed do_mail() { return do_mail_str(0); } + +mixed do_mail_str(string str) { + object ob; + + if( !creatorp(this_player()) ) + return environment(this_player())->eventMail(this_player(), str); + if( !(ob = new(OBJ_POST)) ) { + this_player()->eventPrint("Failed to load postal object!"); + return 1; + } + if( !(ob->eventMove(this_player())) ) { + this_player()->eventPrint("You can't seem to carry the postal " + "object."); + return 1; + } + this_player()->eventPrint("%^RED%^Remember!%^RESET%^ To end a post, enter a single period on an otherwise blank line, and then hit return."); + ob->start_post(str); + return 1; +} + +string GetHelp(string str) { + return ("Syntax: mail\n" + " mail \n" + " mail \n" + " mail \n\n" + "Allows you to send mail to another player on this game. " + "Without arguments, you are simply set to read your " + "mail. With arguments, you are creating mail to be sent. " + "You may only read mail in your home town. The mailer will " + "properly route any mail you send to the proper home town " + "for the player or players you intend it to go to.\n" + "See also: mudlist"); +} diff --git a/lib/verbs/common/say.c b/lib/verbs/common/say.c new file mode 100644 index 0000000..2fa04ed --- /dev/null +++ b/lib/verbs/common/say.c @@ -0,0 +1,66 @@ +/* /verbs/common/say.c + * from the Dead Souls Object Library + * say + * sat to LIV + * say STR + * say to LIV STR + * created by Descartes of Borg 951118 + */ + +#include +#include +#include "include/say.h" + +inherit LIB_VERB; + +static void create() { + ::create(); + SetVerb("say"); + SetRules("","to LIV STR","STR"); +} + +mixed can_say_to_liv(object ob) { + if( !ob ) return 0; + return "What is it you are trying to say to "+ ob->GetName() + "?"; +} + +mixed can_say_to_liv_str(object targ, string str) { + string lang = this_player()->GetDefaultLanguage() || + this_player()->GetNativeLanguage(); + return this_player()->CanSpeak(targ, TALK_LOCAL, str, lang); +} + +mixed can_say(mixed args...) { + return 1; +} + +mixed can_say_str(string str) { + string lang = this_player()->GetDefaultLanguage() || + this_player()->GetNativeLanguage(); + if( !str ) return 0; + return this_player()->CanSpeak(0, TALK_LOCAL, str, lang); +} + +mixed do_say(mixed args...){ + write("Say what?"); + return "Say whut?"; +} + +mixed do_say_to_liv(object ob) { return 1; } + +mixed do_say_to_liv_str(object targ, string str) { + string lang = this_player()->GetDefaultLanguage() || + this_player()->GetNativeLanguage(); + return this_player()->eventSpeak(targ, TALK_LOCAL, str, lang); +} + +mixed do_say_str(string str) { return do_say_to_liv_str(0, str); } + +string GetHelp(string str) { + return ("Syntax: say \n" + " say to \n\n" + "Sends out a message that everyone in the room can see. If you " + "specify a target, the target person is shown as being the target " + "of the message.\n" + "See also: shout, speak, reply, tell, whisper"); +} diff --git a/lib/verbs/common/shout.c b/lib/verbs/common/shout.c new file mode 100644 index 0000000..9c89500 --- /dev/null +++ b/lib/verbs/common/shout.c @@ -0,0 +1,66 @@ +/* /verbs/common/shout.c + * from the Dead Souls Object Library + * shout + * shout + * let it all out + * created by Descartes of Borg 951119 + */ + +#include +#include +#include "include/shout.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("shout"); + SetRules("","in WRD STR","STR"); +} + +mixed can_shout() { return "Shout what?"; } + +mixed can_shout_str(string str) { + string lang; + if( !str ) return 0; + if(this_player()->GetGaggedType("local")) return 0; + lang = this_player()->GetDefaultLanguage() || + this_player()->GetNativeLanguage(); + return can_shout_in_wrd_str(lang, str); +} + +mixed can_shout_in_wrd_str(string lang, string str) { + if( !lang || !str ) return 0; + if( !creatorp(this_player()) && this_player()->GetStaminaPoints()<100 ) + return "You are too tired to shout."; + if( strlen(str) > 250 ) return "That is way too much to shout!"; + return this_player()->CanSpeak(0, TALK_WORLD, str, lang); +} + +mixed do_shout() { return 1; } + +mixed do_shout_str(string str) { + string lang; + lang = this_player()->GetDefaultLanguage() || + this_player()->GetNativeLanguage(); + return do_shout_in_wrd_str(lang, str); +} + +mixed do_shout_in_wrd_str(string lang, string str) { + int cost = -100; + if(this_player()->GetPlayerPaused()) cost = -300; + if( str[<1] != '!' && str[<1] != '?' && str[<1] != '.' ) + str = capitalize(str) + "."; + else str = capitalize(str); + this_player()->AddStaminaPoints(cost); + return this_player()->eventSpeak(0, TALK_WORLD, str, lang); +} + +string GetHelp(string str) { + return ("Syntax: shout \n" + " shout in \n\n" + "Sends a message to all players on " + mud_name() + ". If you " + "fail to specify a language, your native language is used. " + "Abuse of shouting is a violation of " + mud_name() + " laws.\n" + "See also: reply, say, speak, tell, whisper, yell"); +} diff --git a/lib/verbs/common/speak.c b/lib/verbs/common/speak.c new file mode 100644 index 0000000..f524301 --- /dev/null +++ b/lib/verbs/common/speak.c @@ -0,0 +1,83 @@ +/* /verbs/players/speak.c + * from the Dead Souls Mud Library + * speak + * speak STR + * speak in WRD STR + */ + +#include +#include +#include "include/speak.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("speak"); + SetRules("","in WRD","in WRD STR","STR"); +} + +mixed can_speak() { return "Speak what? In what language?"; } + +mixed can_speak_in_wrd(string str) { + mixed ret = this_player()->CanSpeak(0, TALK_LOCAL, "foo", str); + if(intp(ret)) { + write("You are now speaking in "+capitalize(lower_case(str))+"."); + return 1; + } + else return ret; +} + +mixed can_speak_str(string str) { + string lang; + + if( !str ) return 0; + if( strlen(str) > 3 && str[0..2] == "in " ) return 0; + lang = this_player()->GetDefaultLanguage() || + this_player()->GetNativeLanguage(); + if(this_player()->GetPolyglot()) return 100; + return this_player()->CanSpeak(0, TALK_LOCAL, str, lang); +} + +mixed can_speak_in_wrd_str(string lang, string str) { + if( !lang || !str ) return 0; + if( !environment(this_player()) ) return "You are nowhere right now."; + if(this_player()->GetPolyglot()) return 100; + return this_player()->CanSpeak(0, TALK_LOCAL, str, lang); +} + +mixed do_speak() { return 1; } + +mixed do_speak_in_wrd(string str) { + this_player()->SetDefaultLanguage(str); + return 1; +} + +mixed do_speak_str(string str) { + string lang; + lang = this_player()->GetDefaultLanguage() || + this_player()->GetNativeLanguage(); + return do_speak_in_wrd_str(lang, str); +} + +mixed do_speak_in_wrd_str(string lang, string str) { + if( str[<1] != '.' && str[<1] != '?' && str[<1] != '!' ) + str = capitalize(str) + "."; + else str = capitalize(str); + return this_player()->eventSpeak(0, TALK_LOCAL, str, lang); +} + +string GetHelp(string str) { + return ("Syntax: speak \n" + " speak in [MESSAGE]\n\n" + "Sends the message you specify to all people in the same room " + "as you. If you are an avatar, you have the ability to customize " + "the way these messages come out through the \"message\" " + "command. If you fail to specify a language, your default " + "language will be used.\n" + "To switch your default language to something other than your " + "native language:\n" + "speak in FOO\n" + "See also: message, say, shout, speak, tell"); +} + diff --git a/lib/verbs/common/whisper.c b/lib/verbs/common/whisper.c new file mode 100644 index 0000000..0aec492 --- /dev/null +++ b/lib/verbs/common/whisper.c @@ -0,0 +1,82 @@ +/* /verbs/common/whisper.c + * from the Dead Souls Object Library + * whisper + * whisper to LIV STR + * created by Descartes of Borg 951118 + */ + +#include +#include +#include "include/whisper.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("whisper"); + SetRules("to LIV", "in WRD", "in WRD to LIV", "to LIV STR", + "to LIV in WRD STR", "in WRD to LIV STR"); + SetErrorMessage("Whisper to whom what?"); + SetHelp("Syntax: whisper to \n" + " whisper to in \n" + " whisper in to \n\n" + "Privately sends a message to the targetted person in the " + "language you specify with a small chance of being overheard. " + "If you fail to specify a language, your native language is " + "used.\n" + "See also: say, shout, speak, tell, yell"); +} + +mixed can_whisper_to_liv(object target) { + return "What is it you are trying to whisper?"; +} + +mixed can_whisper_in_wrd(string lang) { + return "Whisper to whom in " + lang + "?"; +} + +mixed can_whisper_in_wrd_to_liv(string wrd, object ob) { + return "What do you mean to whisper?"; +} + +mixed can_whisper_to_liv_str(object targ, string str) { + string lang; + + lang = this_player()->GetNativeLanguage() || "english"; + return can_whisper_to_liv_in_wrd_str(targ, lang, str); +} + +mixed can_whisper_in_wrd_to_liv_str(string lang, object targ, string str) { + return can_whisper_to_liv_in_wrd_str(targ, lang, str); +} + +mixed can_whisper_to_liv_in_wrd_str(object targ, string lang, string str) { + return this_player()->CanSpeak(targ, TALK_SEMI_PRIVATE, str, lang); +} + +mixed do_whisper() { return 1; } + +mixed do_whisper_to_liv(object ob) { return 1; } + +mixed do_whisper_in_wrd(string wrd) { return 1; } + +mixed do_whisper_in_wrd_to_liv(string str, object ob) { return 1; } + +mixed do_whisper_to_liv_str(object targ, string str) { + string lang = this_player()->GetDefaultLanguage() || + this_player()->GetNativeLanguage(); + return do_whisper_to_liv_in_wrd_str(targ, lang, str); +} + +mixed do_whisper_in_wrd_to_liv_str(string lang, object targ, string str) { + return do_whisper_to_liv_in_wrd_str(targ, lang, str); +} + +mixed do_whisper_to_liv_in_wrd_str(object targ, string lang, string str) { + if( sizeof(str) > 1){ + if( str[<1] != '?' && str[<1] != '!' && str[<1] != '.' ) + str = capitalize(str) + "."; + else str = capitalize(str); + } + return this_player()->eventSpeak(targ, TALK_SEMI_PRIVATE, str,lang); +} diff --git a/lib/verbs/common/yell.c b/lib/verbs/common/yell.c new file mode 100644 index 0000000..722a1f7 --- /dev/null +++ b/lib/verbs/common/yell.c @@ -0,0 +1,60 @@ +/* /verbs/common/yell.c + * from the Dead Souls Object Library + * yell + * yell in WRD STR + * yell STR + * created by Descartes of Borg 951119 + */ + +#include +#include +#include "include/yell.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("yell"); + SetRules("","in WRD STR","STR"); +} + +mixed can_yell() { return "Yell what?"; } + +mixed can_yell_str(string str) { + string lang; + + if( !str ) return 0; + lang = this_player()->GetDefaultLanguage() || + this_player()->GetNativeLanguage(); + return can_yell_in_wrd_str(lang, str); +} + +mixed can_yell_in_wrd_str(string lang, string str) { + if( !lang || !str ) return 0; + return this_player()->CanSpeak(0, TALK_AREA, str, lang); +} + +mixed do_yell() { return 1; } + +mixed do_yell_str(string str) { + string lang; + + lang = this_player()->GetDefaultLanguage() || + this_player()->GetNativeLanguage(); + return do_yell_in_wrd_str(lang, str); +} + +mixed do_yell_in_wrd_str(string lang, string str) { + if( str[<1] != '!' && str[<1] != '?' && str[<1] != '.' ) + str = capitalize(str) + "."; + else str = capitalize(str); + return this_player()->eventSpeak(0, TALK_AREA, str, lang); +} + +string GetHelp(string str) { + return ("Syntax: yell \n" + " yell in \n\n" + "Sends a message to the area around you. If you fail to " + "specify a language, your native language is used.\n" + "See also: reply, say, shout, speak, tell, whisper"); +} diff --git a/lib/verbs/creators/codesay.c b/lib/verbs/creators/codesay.c new file mode 100644 index 0000000..41a8a7a --- /dev/null +++ b/lib/verbs/creators/codesay.c @@ -0,0 +1,69 @@ +/* /verbs/common/codesay.c + * from the Dead Souls Object Library + * codesay + * codesay STR + */ + +#include +#include +#include +#include "include/codesay.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("codesay"); + SetRules("STR"); +} + +mixed can_codesay() { return "Say what?"; } + +mixed can_codesay_str(string str) { + if( !str ) return 0; + else return 1; +} + +varargs mixed do_codesay_str(string str) { + string filename = DIR_TMP + "/" + this_player()->GetKeyName() + ".codesay"; + if( !str ) { + write("Huh?"); + return 1; + } + if(!creatorp(this_player())) { + write("This is a command for creators."); + return 1; + } + if(strsrch(str,";") == -1){ + write("You codesay: "+"%^BOLD%^CYAN%^"+str+"%^RESET%^"); + say(this_player()->GetCapName()+" codesays: "+ + "%^BOLD%^CYAN%^"+str+"%^RESET%^"); + } + else { + str = replace_string(str, ";", ";\n"); + str = replace_string(str, "{", "{\n"); + str = replace_string(str, "}", "}\n"); + write_file(filename,str,1); + write_file(filename+"_rule","I",1); + load_object(CMD_LSED)->cmd(filename+"_rule "+filename); + write("You codesay: "); + say(this_player()->GetCapName()+" codesays: "); + tell_room(environment(this_player()),"\n"+ + "%^BOLD%^CYAN%^"+read_file(filename)+"%^RESET%^"); + } + return 1; +} + +mixed do_codesay() { return do_codesay_str(); } + +string GetHelp() { + return ("Syntax: codesay \n\n" + "Sends out a message that everyone in the room can see. " + "This message will be stripped of normal punctuation so " + "that text that needs to be seen literally does not " + "cause confusion. " + "If the message contains a semicolon, this command will attempt " + "to format it in indented LPC style. " + "\n" + "See also: shout, speak, reply, tell, whisper"); +} diff --git a/lib/verbs/creators/echo.c b/lib/verbs/creators/echo.c new file mode 100644 index 0000000..33eedc8 --- /dev/null +++ b/lib/verbs/creators/echo.c @@ -0,0 +1,80 @@ +/* /verbs/creators/echo.c + * from the Dead Souls Mud Library + * echo + * echo STR + * echo to LIV STR + * created by Descartes of Borg 951114 + */ + +#include +#include +#include "include/echo.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("echo"); + SetRules("","to LIV STR","STR"); +} + +int livings_are_remote() { return 1; } + +mixed can_echo() { + if( !creatorp(this_player()) ) return 0; + else return "Echo what? Echo to whom what? Echo to all what?"; +} + +mixed can_echo_to_liv_str(object ob, string str) { + if( !ob || !str ) return 0; + if( !creatorp(this_player()) ) return 0; + return 1; +} + +mixed can_echo_str(string str) { + if( !str || !creatorp(this_player()) ) return 0; + return 1; +} + +mixed do_echo() { return 1; } + +mixed do_echo_to_liv_str(object who, string what) { + eventEcho(({ who }), what); + return 1; +} + +mixed do_echo_str(string str) { + object *obs; + string tmp; + + if( sscanf(str, "to all %s", tmp) && tmp ) { + obs = (users() - ({ this_player() })); + str = tmp; + } + else obs = (all_inventory(environment(this_player())) - ({this_player()})); + eventEcho(obs, str); + return 1; +} + +void eventEcho(object *targs, string str) { + object ob; + + foreach(ob in targs) { + if( archp(ob) ) + ob->eventPrint(this_player()->GetCapName() + + " echoes: " + str, MSG_CONV); + else ob->eventPrint(str, MSG_CONV); + } + this_player()->eventPrint("You echo: " + str, MSG_CONV); +} + +string GetHelp(string str) { + return ("Syntax: echo \n" + " echo to \n" + " echo to all \n\n" + "Sends a message without prefixing around to everyone in the " + "room if you fail to specify to whom you are echoing. You " + "may echo to everyone in the game as well. Abuse of this " + "command is a severe violation of MUD ethics.\n" + "See also: say, tell"); +} diff --git a/lib/verbs/creators/include/codesay.h b/lib/verbs/creators/include/codesay.h new file mode 100644 index 0000000..ddda80c --- /dev/null +++ b/lib/verbs/creators/include/codesay.h @@ -0,0 +1,11 @@ +#ifndef l_codesay_h +#define l_codesay_h + +static void create(); +mixed can_codesay(); +mixed can_codesay_str(string str); +mixed do_codesay(); +varargs mixed do_codesay_str(string str); +string GetHelp(string str); + +#endif /* l_codesay_h */ diff --git a/lib/verbs/creators/include/echo.h b/lib/verbs/creators/include/echo.h new file mode 100644 index 0000000..7afce3b --- /dev/null +++ b/lib/verbs/creators/include/echo.h @@ -0,0 +1,14 @@ +#ifndef l_echo_h +#define l_echo_h + +static void create(); +mixed can_echo(); +mixed can_echo_to_liv_str(object who, string what); +mixed can_echo_str(string str); +mixed do_echo(); +mixed do_echo_to_liv_str(object who, string what); +mixed do_echo_str(string str); +void eventEcho(object *targs, string str); +string GetHelp(string str); + +#endif /* l_echo_h */ diff --git a/lib/verbs/creators/resurrect.c b/lib/verbs/creators/resurrect.c new file mode 100644 index 0000000..40100ac --- /dev/null +++ b/lib/verbs/creators/resurrect.c @@ -0,0 +1,129 @@ +#include +#include +#include +#include ROOMS_H +#include +#include + +inherit LIB_VERB; +string *carried = ({}); + +static void create() { + verb::create(); + SetVerb("resurrect"); + SetRules("OBJ", "here"); + SetErrorMessage("resurrect what?"); + SetHelp("Syntax: resurrect \n\n" + "Bring back to life something that died. When used on the corpse\n" + "of a player, it brings them back from death without skill or\n" + "experience penalties.\n" + "See also: zap, dest"); +} + +mixed can_resurrect_obj(string str) { + if(!creatorp(this_player())) + return "This command is only available to creators."; + else return 1; +} + +mixed do_resurrect_obj(object ob) { + int corpse; + object playerob; + if(ob->isCorpse()) corpse = 1; + if(interactive(ob)) playerob = ob; + if( ob->isPlayer() ) playerob = ob->GetPlayerob(); + if( ob->isPlayer() && !playerob ){ + write("You cannot resurrect a player that isn't logged on."); + return 1; + } + if((playerob && !playerob->GetGhost()) || living(ob)) { + write("You can't resurrect the living."); + return 1; + } + + if(base_name(ob) != LIB_CORPSE){ + write("You can only resurrect flesh-based creatures."); + return 1; + } + + if(environment(ob) != environment(this_player())) { + write(capitalize(ob->GetKeyName())+" isn't here."); + return 1; + } + + tell_player(this_player(),"You wave your hand, and with a flash "+ + "of light, "+ob->GetCapName()+" comes back to life!"); + tell_player(ob,capitalize(this_player()->GetKeyName())+" waves "+ + possessive(this_player())+ + " hand, and with a flash of light, you come back from the dead!"); + tell_room(environment(this_player()),this_player()->GetCapName()+" waves "+ + possessive(this_player())+ + " hand, and with a flash of light, "+ob->GetCapName()+ + " comes back to life!", + ({ob, this_player()}) ); + if(playerob){ + object *inv; + playerob->eventRevive(1); + playerob->eventMove(environment(this_player())); + inv = all_inventory(ob); + if(sizeof(inv)) inv->eventMove(playerob); + inv = all_inventory(ob); + if(sizeof(inv)) inv->eventMove(environment(this_player())); + ob->eventMove(ROOM_FURNACE); + playerob->eventDescribeEnvironment(); + } + else { + object *inv; + object npc; + int err; + string basefile = ob->GetBaseFile(); + err = catch( npc = new(basefile) ); + if(!npc){ + npc = new(LIB_SENTIENT); + npc->SetRace(ob->GetRace()); + npc->SetClass(ob->GetClass()); + npc->SetLevel(ob->GetLevel()); + npc->SetGender(ob->GetGender()); + npc->SetKeyName(lower_case((ob->GetOwner()|| ob->GetRace()))); + npc->SetShort((ob->GetLivingShort()|| "A "+ob->GetRace())); + npc->SetLong((ob->GetLivingLong() || "A "+ob->GetRace())); + } + foreach(mixed key, mixed val in ob->GetSkills()){ + npc->SetSkill(key, val["level"], val["class"]); + } + foreach(mixed key, mixed val in ob->GetStats()){ + npc->SetStat(key, val["level"], val["class"]); + } + npc->eventMove(ROOM_POD); + npc->ResetCurrency(); + if(sizeof(all_inventory(npc))){ + all_inventory(npc)->eventMove(ROOM_FURNACE); + } + inv = all_inventory(ob); + if(sizeof(inv)) inv->eventMove(npc); + inv = all_inventory(ob); + if(sizeof(inv)) inv->eventMove(environment(this_player())); + foreach(string element in ob->GetMissingLimbs()){ + npc->RemoveLimb(element); + } + if(ob){ + mapping oldequipped = ob->GetEquipped(); + string *oldkeys = keys(oldequipped); + foreach(object thing in all_inventory(npc)){ + if(member_array(file_name(thing),oldkeys) != -1){ + object oldob = oldequipped[file_name(thing)]["object"]; + string *where = oldequipped[file_name(thing)]["where"]; + if(objectp(oldob)){ + if(oldob->CanEquip(npc, where)){ + oldob->eventEquip(npc, where); + } + } + } + } + } + npc->SetPosition(POSITION_LYING); + npc->eventMove(environment(this_player())); + ob->eventMove(ROOM_FURNACE); + } + return 1; +} diff --git a/lib/verbs/creators/wizlock.c b/lib/verbs/creators/wizlock.c new file mode 100644 index 0000000..188cb53 --- /dev/null +++ b/lib/verbs/creators/wizlock.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include ROOMS_H +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("wizlock"); + SetRules("OBJ"); + SetErrorMessage("wizlock what?"); + SetHelp("Syntax: wizlock \n\n" + "Magically lock a lockable thing without needing a key.\n" + "See also: wizunlock"); +} + +mixed can_wizlock_obj(string str) { + if(!creatorp(this_player())) + return "This command is only available to creators."; + else return 1; +} + +mixed do_wizlock_obj(object ob){ + string name; + if(living(ob)) { + write("You can only wizlock non-living things."); + return 1; + } + else name = ob->GetShort(); + if(ob->GetDoor()) ob = load_object(ob->GetDoor()); + if(!ob->GetClosed()){ + write("You can't wizlock it because it is not closed."); + return 1; + } + write("You wizlock "+name+"."); + say(this_player()->GetName()+" makes a closed-fist gesture at"+ + " "+name+".",({ob})); + ob->SetLocked(1); + return 1; +} diff --git a/lib/verbs/creators/wizunlock.c b/lib/verbs/creators/wizunlock.c new file mode 100644 index 0000000..ee46c70 --- /dev/null +++ b/lib/verbs/creators/wizunlock.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include ROOMS_H +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("wizunlock"); + SetRules("OBJ"); + SetErrorMessage("wizunlock what?"); + SetHelp("Syntax: wizunlock \n\n" + "Magically unlock a lockable thing without needing a key.\n" + "See also: wizunlock"); +} + +mixed can_wizunlock_obj(string str) { + if(!creatorp(this_player())) + return "This command is only available to creators."; + else return 1; +} + +mixed do_wizunlock_obj(object ob){ + string name; + + if(living(ob)) { + write("You can only wizunlock non-living things."); + return 1; + } + else name = ob->GetShort(); + if(ob->GetDoor()) ob = load_object(ob->GetDoor()); + write("You wizunlock "+name+"."); + say(this_player()->GetName()+" makes an open-hand gesture at"+ + " "+name+".",({ob})); + ob->SetLocked(0); + return 1; +} diff --git a/lib/verbs/creators/zap.c b/lib/verbs/creators/zap.c new file mode 100644 index 0000000..aeb124c --- /dev/null +++ b/lib/verbs/creators/zap.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include ROOMS_H +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("zap"); + SetRules("LVS"); + SetErrorMessage("zap what?"); + SetHelp("Syntax: zap \n\n" + "Deal massive damage to a living thing.\n" + "See also: dest, resurrect"); +} + +mixed can_zap_liv(string str) { + if(!creatorp(this_player())) + return "This command is only available to creators."; + else return 1; +} + +mixed do_zap_liv(object ob){ + string name; + int mhp; + + if(!living(ob)) { + write("You can only zap living things."); + return 1; + + } + else name = ob->GetName(); + mhp = ob->GetMaxHealthPoints(); + if(!mhp) mhp = 99999; + mhp *= 5; + write("You zap "+name+"."); + say(this_player()->GetName()+" raises a hand and %^RED%^ZAPS%^RESET%^"+ + " "+name+"!",({ob})); + tell_object(ob,this_player()->GetName()+" raises a hand and "+ + "%^RED%^ZAPS%^RESET%^ you!"); + ob->eventReceiveDamage(this_player(),DEATHRAY,mhp,0,({ob->GetTorso()})); + return 1; +} + +mixed do_zap_lvs(object *obs) { + foreach(object ob in obs){ + if(!(ob == this_player())) do_zap_liv(ob); + } + return 1; +} diff --git a/lib/verbs/items/activate.c b/lib/verbs/items/activate.c new file mode 100644 index 0000000..535dd79 --- /dev/null +++ b/lib/verbs/items/activate.c @@ -0,0 +1,48 @@ +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("activate"); + SetRules("OBJ","OBJ on OBJ","STR on OBJ"); + SetErrorMessage("Activate something?"); + SetHelp("Syntax: activate THING\n" + " \n" + "See also: deactivate"); +} + +mixed can_activate() { + return this_player()->CanManipulate(); +} + +mixed can_activate_obj(mixed foo) { + return this_player()->CanManipulate(); +} + +mixed can_activate_obj_on_obj(mixed foo) { + return this_player()->CanManipulate(); +} + +mixed can_activate_str_on_obj(mixed foo) { + return this_player()->CanManipulate(); +} + +mixed do_activate() { + return "Activate what?"; + return 1; +} + +varargs mixed do_activate_obj(mixed foo) { + return foo->eventTurnOn(); +} + +varargs mixed do_activate_obj_on_obj(mixed foo, mixed foo2) { + return foo->eventTurnOn(foo2); +} + +varargs mixed do_activate_str_on_obj(mixed foo, mixed foo2) { + return foo2->eventTurnOn(foo); +} + diff --git a/lib/verbs/items/apply.c b/lib/verbs/items/apply.c new file mode 100644 index 0000000..07aca45 --- /dev/null +++ b/lib/verbs/items/apply.c @@ -0,0 +1,32 @@ +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("apply"); + SetRules("OBJ WRD OBJ", "OBJ OBJ"); + SetErrorMessage("Apply what to what?"); + SetHelp("Syntax: apply ITEM to OBJECT\n\n" + "Allows you to put one thing up against another.\n\n" + "See also: turn, activate, install"); +} + +mixed can_apply_obj_word_obj() { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything."; + } + return this_player()->CanManipulate(); +} + +mixed can_apply_obj_obj() { + return can_apply_obj_word_obj(); +} + +mixed do_apply_obj_word_obj(object appliance, object target) { + return appliance->eventApply(this_player(), target ); +} + +mixed do_apply_obj_obj(object appliance, object target) { + return do_apply_obj_word_obj(appliance, target); +} diff --git a/lib/verbs/items/bait.c b/lib/verbs/items/bait.c new file mode 100644 index 0000000..f0970dd --- /dev/null +++ b/lib/verbs/items/bait.c @@ -0,0 +1,34 @@ +/* /verbs/items/bait.c + * from the Dead Souls Mud Library + * bait verb used with /lib/bait.c + * created by Blitz@Dead Souls 960117 + */ + + + +#include +#include "include/bait.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("bait"); + SetRules("OBJ with OBJ"); + SetErrorMessage("Bait what with what?"); + SetHelp("Syntax: bait with \n\n" + "The bait command is normally used to fasten bait onto " + "a fishing pole. The POLE must be a device of some " + "kind which is used for catching fish. The BAIT " + "must be some sort of fishing bait."); +} + +mixed can_bait_obj_with_obj(string verb) { return this_player()->CanManipulate(); } + +mixed do_bait_obj_with_obj(object pole, object bait) { + if( pole == bait ) { + this_player()->eventPrint("You can't use it to bait itself!"); + return 1; + } + return bait->eventBait(this_player(), pole); +} diff --git a/lib/verbs/items/balance.c b/lib/verbs/items/balance.c new file mode 100644 index 0000000..d11bc6b --- /dev/null +++ b/lib/verbs/items/balance.c @@ -0,0 +1,99 @@ +/* /verbs/spells/judge.c + * a skill for players to judge the relative weight of items + * created 96/12/04 by Faldir@Dead Souls + */ + +#include +#include +#include +#include "include/balance.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("balance"); + SetRules("OBJ to OBJ"); + SetErrorMessage("What two things would you like to balance?"); + SetHelp("Syntax: balance OBJ to OBJ\n\n" + "A simple tool for determining which is the heavier of two objects." + "See help: item commands"); +} + +mixed can_balance_obj_to_obj() { + return this_player()->CanCastMagic(1, "balance"); +} + + +mixed do_balance_obj_to_obj(object obj1, object obj2) { + string name1, name2; + object caster = this_player(); + if(!obj1 || !obj2) return "You must judge one thing vs another."; + if(obj1 == obj2) return "That would do a lot of good!"; + /* Check for presence of objects */ + name1 = obj1->GetShort(); + name2 = obj2->GetShort(); + + if( environment(obj1) != caster ) { + caster->eventPrint("You do not have "+name1+"."); + return 1; + } + + if( environment(obj2) != caster ) { + caster->eventPrint("You do not have "+name2+"."); + return 1; + } + + caster->eventPrint("You stare intently at "+name1+" and "+name2+"."); + environment(caster)->eventPrint( caster->GetName() + + " concentrates on " + name1 + " and " + name2 + ".", caster); + if( this_player()->GetInCombat() ) + this_player()->SetAttack(0, + (: eventBalance, this_player(), obj1, obj2 :), + ROUND_OTHER); + else eventBalance(this_player(), obj1, obj2); + return 1; +} + + +int eventBalance(object caster, object obj1, object obj2) { + + int obj1lvl, obj2lvl; + string better; + + int cost = random(50) + 50; + + if( !(obj1 && obj2) ) return 0; + if( (environment(obj1) != caster) || (environment(obj2) != caster) ) { + caster->eventPrint("You must have both items in your possession " + "to compare them."); + return 0; + } + if( cost > caster->GetStaminaPoints() ) { + caster->eventPrint("You are too weary to balance right now."); + environment(caster)->eventPrint( + caster->GetName() + " looks tired.", caster); + return 0; + + } + caster->AddStaminaPoints(-cost); + obj1lvl = obj1->GetMass(); + obj2lvl = obj2->GetMass(); + + /* Return the right answer */ + if(obj1lvl == obj2lvl) { + caster->eventPrint("%^BOLD%^%^WHITE%^" + "You determine that these two items are equally heavy." + ".%^RESET%^"); + return 1; + } + if(obj1lvl > obj2lvl) { + better = obj1->GetShort(); + } + else better = obj2->GetShort(); + caster->eventPrint("%^BOLD%^%^WHITE%^" + "You determine that " + better + "%^BOLD%^%^WHITE%^" + " is the heavier object.%^RESET%^"); + return 1; + +} diff --git a/lib/verbs/items/boobytrap.c b/lib/verbs/items/boobytrap.c new file mode 100644 index 0000000..a1d8763 --- /dev/null +++ b/lib/verbs/items/boobytrap.c @@ -0,0 +1,28 @@ +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("boobytrap"); + SetRules("OBJ with OBJ"); + SetErrorMessage("Boobytrap what with what?"); + SetHelp("Syntax: \n\n" + "The first object is something you wish to boobytrap, like a " + "door or a chest. The second is the thing you wish to use to " + "boobytrap it with.\n\n" + "See also: close, open, pick, disarm"); +} + +mixed can_boobytrap_obj_with_obj(string verb) { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything."; + } + return this_player()->CanManipulate(); +} + +varargs mixed do_boobytrap_obj_with_obj(object target, object trap, mixed *words...) { + string id; + id = remove_article(lower_case(words[0])); + return trap->eventBoobytrap(this_player(), id, trap); +} diff --git a/lib/verbs/items/bury.c b/lib/verbs/items/bury.c new file mode 100644 index 0000000..4a5318a --- /dev/null +++ b/lib/verbs/items/bury.c @@ -0,0 +1,70 @@ +/* /verbs/items/bury.c + * From the Dead Souls Mud Library + * Buries objects where no one can find them + * Created by Descartes of Borg 951030 + */ + +#include +#include +#include + +inherit LIB_VERB; + +static void eventBury(object who, object tool, object what, object check) { + if( !who || environment(who) != check ) { + return; + } + if( !tool || (environment(tool) != who) ) { + who->eventPrint("You have lost your digging equipment."); + return; + } + tool->eventBuryWith(who, what); +} + +varargs static void eventPrepareBury(object who, object tool, object what) { + function f = (: eventBury($(who), $(tool), $(what),environment($(who))) :); + + if( who->GetInCombat() ) { + send_messages("start", "$agent_name $agent_verb to bury " + + "with " + tool->GetShort() + ".", who, 0, + environment(who)); + who->SetAttack(0, f, ROUND_OTHER); + } + else { + evaluate(f); + } +} + +static void create() { + verb::create(); + SetVerb("bury"); + SetErrorMessage("Bury what with what?"); + SetRules("OBJ with OBJ", "STR with OBJ"); + SetHelp("Syntax: \n\n" + "Allows you to use a digging tool to bury things.\n\n" + "See also: dig"); +} + +mixed can_bury_str_with_obj() { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything!"; + } + if( this_player()->GetPosition() != POSITION_STANDING ) { + return "You can only bury things while standing!"; + } + return this_player()->CanManipulate(); +} + +mixed can_bury_obj_with_obj() { + return can_bury_str_with_obj(); +} + +mixed do_bury_str_with_obj(string str, object tool) { + eventPrepareBury(this_player(), tool); + return this_player()->CanManipulate(); +} + +mixed do_bury_obj_with_obj(object what, object tool) { + eventPrepareBury(this_player(), tool, what); + return 1; +} diff --git a/lib/verbs/items/buy.c b/lib/verbs/items/buy.c new file mode 100644 index 0000000..87478b6 --- /dev/null +++ b/lib/verbs/items/buy.c @@ -0,0 +1,37 @@ +/* /verbs/items/buy.c + * From the Dead Souls Mud Library + * Allows players to buy things from living vendors + * Created by Descartes of Borg sometime in 1996 + * Version: @(#) buy.c 1.2@(#) + * Last modified: 97/01/03 + */ + +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("buy"); + SetSynonyms("purchase"); + SetRules("STR from LIV"); + SetErrorMessage("Buy what from whom?"); + SetHelp("Syntax: \n\n" + "When in the presence of vendors, you may buy and sell goods " + "which match the type of goods the vendor in question trades in. " + "The \"buy\" command naturally allows you to buy the items " + "the vendor has for sale.\n\n" + "Synonyms: purchase\n\n" + "See also: ask, sell, vendors"); +} + +mixed can_buy_str_from_liv(string str) { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything."; + } + return this_player()->CanManipulate(); +} + +mixed do_buy_str_from_liv(string str, object vendor) { + return vendor->eventSell(this_player(), remove_article(lower_case(str))); +} diff --git a/lib/verbs/items/capture.c b/lib/verbs/items/capture.c new file mode 100644 index 0000000..cf0ab19 --- /dev/null +++ b/lib/verbs/items/capture.c @@ -0,0 +1,32 @@ +/* /verbs/items/capture.c + * From the Dead Souls Mud Library + * A verb to allow people to capture or catch things with an object + * Creatd by Descartes of Borg 961010 + * Version: @(#) capture.c 1.4@(#) + * Last modified: 96/10/10 + */ + +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("capture"); + SetRules("LIV with OBJ", "LIV in OBJ"); + SetSynonyms("catch", "trap"); + SetErrorMessage("Capture what with what?"); + SetHelp("Syntax: \n\n" + "Some objects can be used to trap living things. This command " + "therefore allows you to capture those things.\n\n" + "Synonyms: catch, trap\n\n" + "See also: free"); +} + +mixed can_capture_liv_word_obj() { + return this_player()->CanManipulate(); +} + +mixed do_capture_liv_word_obj(object target, string word, object tool) { + return tool->eventCapture(this_player(), target); +} diff --git a/lib/verbs/items/close.c b/lib/verbs/items/close.c new file mode 100644 index 0000000..36eb5e3 --- /dev/null +++ b/lib/verbs/items/close.c @@ -0,0 +1,38 @@ +/* /verbs/items/close.c + * from the Dead Souls Mud Library + * close OBJ + * created by Descartes of Borg 960115 + * Version: @(#) close.c 1.2@(#) + * Last modified: 96/10/15 + */ + +#include +#include "include/close.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("close"); + SetRules("OBJ"); + SetSynonyms("shut"); + SetErrorMessage("Close what?"); + SetHelp("Syntax: \n\n" + "Closes a door or chest or some other such object.\n\n" + "Synonyms: shut\n\n" + "See also: lock, open, pick, unlock"); +} + +mixed can_close_obj(string verb) { + if( this_player()->GetParalyzed() ) { + return "You are unable to do anything."; + } + return this_player()->CanManipulate(); +} + +varargs mixed do_close_obj(object ob, mixed *args...) { + string what; + + what = remove_article(lower_case(args[0])); + return ob->eventClose(this_player(), what); +} diff --git a/lib/verbs/items/consult.c b/lib/verbs/items/consult.c new file mode 100644 index 0000000..037d36c --- /dev/null +++ b/lib/verbs/items/consult.c @@ -0,0 +1,39 @@ +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("consult"); + SetRules("OBJ"); + SetErrorMessage("Consult what? Or consult whom?"); + SetHelp("Syntax: \n" + " \n\n" + "Allows you to consult an object or a person.\n" + "\"consult my magic 8 ball\", or simply \"consult ball\".\n\n" + ""); +} + +mixed can_consult_obj() { + return this_player()->CanManipulate(); +} + +//mixed can_consult_liv() { +// return this_player()->CanManipulate(); +//} + +mixed can_consult_str_on_obj() { + return this_player()->CanManipulate(); +} + +mixed do_consult_obj(object target) { + return target->eventConsult(this_player()); +} + +//mixed do_consult_liv(object target) { +// return target->eventConsult(this_player()); +//} + +varargs mixed do_consult_str_on_obj(string thing, object target) { + return target->eventConsult(this_player(), remove_article(lower_case(thing))); +} diff --git a/lib/verbs/items/deactivate.c b/lib/verbs/items/deactivate.c new file mode 100644 index 0000000..3ca96df --- /dev/null +++ b/lib/verbs/items/deactivate.c @@ -0,0 +1,48 @@ +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("deactivate"); + SetRules("", "OBJ","OBJ on OBJ","STR on OBJ"); + SetErrorMessage("Deactivate something?"); + SetHelp("Syntax: deactivate THING\n" + " \n" + "See also: activate"); +} + +mixed can_deactivate() { + return this_player()->CanManipulate(); +} + +mixed can_deactivate_obj(mixed foo) { + return this_player()->CanManipulate(); +} + +mixed can_deactivate_obj_on_obj(mixed foo) { + return this_player()->CanManipulate(); +} + +mixed can_deactivate_str_on_obj(mixed foo) { + return this_player()->CanManipulate(); +} + +mixed do_deactivate() { + return "Deactivate what?"; + return 1; +} + +varargs mixed do_deactivate_obj(mixed foo, mixed foo2) { + return foo->eventTurnOff(); +} + +varargs mixed do_deactivate_obj_on_obj(mixed foo, mixed foo2) { + return foo->eventTurnOff(foo2); +} + +varargs mixed do_deactivate_str_on_obj(mixed foo, mixed foo2) { + return foo2->eventTurnOff(foo); +} + diff --git a/lib/verbs/items/dig.c b/lib/verbs/items/dig.c new file mode 100644 index 0000000..5b72e34 --- /dev/null +++ b/lib/verbs/items/dig.c @@ -0,0 +1,86 @@ +/* /verbs/items/dig.c + * From the Dead Souls Mud Library + * Verb for digging things + * Created by Descartes of Borg 951030 + * Version: @(#) dig.c 1.2@(#) + * Last modified: 97/01/01 + */ + +#include +#include +#include + +inherit LIB_VERB; + +static void eventDig(object who, object tool, object what, object check) { + if( !who || check != environment(who) ) { + return; + } + if( !tool || (environment(tool) != who) ) { + who->eventPrint("You have lost your equipment."); + return; + } + tool->eventDigWith(who, what); +} + +varargs static void eventPrepareDig(object who, object tool, object what) { + function f = (: eventDig($(who), $(tool), $(what), environment($(who))) :); + + if( this_player()->GetInCombat() ) { + send_messages("start", "$agent_name $agent_verb to dig with " + + tool->GetShort() + ".", who, 0, environment(who)); + who->SetAttack(0, f, ROUND_OTHER); + } + else { + evaluate(f); + } +} + +static void create() { + verb::create(); + SetVerb("dig"); + SetRules("with OBJ", "STR with OBJ", "OBJ with OBJ"); + SetErrorMessage("Dig with what? Is there anything in particular to dig?"); + SetHelp("Syntax: \n" + " \n\n" + "Allows you to dig with digging tools. Sometimes you may " + "be required to specify what it is you wish to dig. In " + "that case, you can use the thing field to specify what it is " + "you wish to dig.\n\n" + "See also: bury"); +} + +mixed can_dig_with_obj() { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything!"; + } + if( this_player()->GetPosition() != POSITION_STANDING ) { + return "Dig when you are not standing?"; + } + return this_player()->CanManipulate(); +} + +mixed can_dig_str_with_obj() { + return can_dig_with_obj(); +} + +mixed can_dig_obj_with_obj() { + return can_dig_with_obj(); +} + +mixed do_dig_with_obj(object ob) { + eventPrepareDig(this_player(), ob); + return 1; +} + +mixed do_dig_str_with_obj(string str, object ob) { + if( remove_article(lower_case(str)) != "hole" ) { + return 0; + } + return do_dig_with_obj(ob); +} + +mixed do_dig_obj_with_obj(object what, object ob, string id) { + eventPrepareDig(this_player(), ob, what); + return 1; +} diff --git a/lib/verbs/items/disarm.c b/lib/verbs/items/disarm.c new file mode 100644 index 0000000..933f66a --- /dev/null +++ b/lib/verbs/items/disarm.c @@ -0,0 +1,25 @@ +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("disarm"); + SetRules("OBJ"); + SetErrorMessage("Disarm what?"); + SetHelp("Syntax: \n\n" + "Use this command to try to disarm a boobytrapped object, like " + "a door or a chest.\n\n" + "See also: close, open, pick, disarm"); +} + +varargs mixed can_disarm_obj(mixed args...) { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything."; + } + return this_player()->CanManipulate(); +} + +varargs mixed do_disarm_obj(object target) { + return target->eventDisarm(this_player()); +} diff --git a/lib/verbs/items/donate.c b/lib/verbs/items/donate.c new file mode 100644 index 0000000..de51944 --- /dev/null +++ b/lib/verbs/items/donate.c @@ -0,0 +1,47 @@ +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("donate"); + SetRules("STR STR", "STR STR to STR"); + SetErrorMessage("Donate "); + SetHelp("Syntax: donate \n\n" + "The donate command is used to donate money."); +} + +mixed can_donate_str_str(string amount, string currency){ + return this_player()->CanManipulate(); +} + +mixed can_donate_str_str_to_str(string amount, string currency, string foo){ + return can_donate_str_str(amount, currency); +} + +mixed do_donate_str_str(string amount, string currency) { + object *stuff; + object *donate_boxes; + + donate_boxes = ({}); + + stuff = all_inventory(environment(this_player())); + + foreach(object thing in stuff){ + if(inherits(LIB_DONATE,thing)){ + donate_boxes += ({ thing }); + } + } + + if(sizeof(donate_boxes)){ + donate_boxes[0]->eventDonate(amount, currency); + } + + else write("There is nowhere to donate that."); + + return 1; +} + +mixed do_donate_str_str_to_str(string amount, string currency, string foo){ + return do_donate_str_str(amount, currency); +} diff --git a/lib/verbs/items/drink.c b/lib/verbs/items/drink.c new file mode 100644 index 0000000..8d291a8 --- /dev/null +++ b/lib/verbs/items/drink.c @@ -0,0 +1,53 @@ +/* /verbs/items/drink.c + * from the Dead Souls Mud Library + * drink + * drink OBJ + * created by Descartes of Borg 951113 + */ + + + +#include +#include +#include "include/drink.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("drink"); + SetRules("OBJ", "from OBJ"); + SetErrorMessage("Drink what?"); + SetHelp("Syntax: \n" + " \n\n" + "Allows you to drink a liquid substance. Often these " + "substances come in the form of caffeine, alcohol, and just " + "regular drinks. Different types of drinks have different " + "effects on you which you will learn through experimentation.\n\n" + "See also: bait, cast, eat, fish"); + SetSynonyms("quaff"); +} + +mixed can_drink_obj(string verb) { return this_player()->CanManipulate(); } + +mixed can_drink_from_obj(string verb) { return this_player()->CanManipulate(); } + +mixed do_drink_obj(object ob) { + if( this_player()->GetInCombat() ) + this_player()->SetAttack(0, (: eventDrink, this_player(), ob :), + ROUND_OTHER); + else eventDrink(this_player(), ob); + return 1; +} + +mixed do_drink_from_obj(object ob, string id) { + if( this_player()->GetInCombat() ) + this_player()->SetAttack(0, (: eventDrink, this_player(), ob, id :), + ROUND_OTHER); + else eventDrink(this_player(), ob, id); + return 1; +} + +varargs void eventDrink(object who, object what, string id) { + return what->eventDrink(who, id); +} diff --git a/lib/verbs/items/drop.c b/lib/verbs/items/drop.c new file mode 100644 index 0000000..8810fa7 --- /dev/null +++ b/lib/verbs/items/drop.c @@ -0,0 +1,115 @@ +/* /verbs/items/drop.c + * from the Dead Souls Mud Library + * drop OBJ + * drop OBS + * drop WRD WRD + * created by Descartes of Borg 960113 + */ + + + +#include +#include "include/drop.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("drop"); + SetSynonyms("put down"); + SetRules("OBS", "WRD WRD"); + SetErrorMessage("Drop what?"); + SetHelp("Syntax: \n" + " \n" + " \n" + " \n\n" + "Allows you to drop something you have, or to drop an amount of " + "some currency you have on you.\n\n" + "See also: get, put"); +} + +mixed can_drop_obj(object ob) { return this_player()->CanManipulate(); } + +//mixed can_drop_wrd_wrd(string num, string curr) { +mixed can_drop_wrd_wrd(mixed args...) { + string num, curr; + int amt; + object ob; + + num = args[0]; + curr = args[1]; + + ob = get_object(num+" "+curr); + + if(ob) return can_drop_obj(ob); + + if( !num || !curr ) return 0; + if( (amt = to_int(num)) < 1 ) return "You cannot do that!"; + if( this_player()->GetCurrency(curr) < amt ) + return "You don't have that much " + curr + "."; + if(newbiep(this_player())) return "Newbies can't drop money."; + return this_player()->CanManipulate(); +} + +mixed do_drop_obj(object ob) { + return ob->eventDrop(this_player()); +} + +mixed do_drop_obs(mixed *res) { + object *obs, *eligible; + mixed tmp; + + if( !sizeof(res) ) { + this_player()->eventPrint("You don't have any to drop!"); + return 1; + } + obs = filter(res, (: objectp :)); + if( !sizeof(obs) ) { + mixed *ua; + + ua = unique_array(res, (: $1 :)); + foreach(string *list in ua) this_player()->eventPrint(list[0]); + return 1; + } + eligible=filter(obs, (: (!($1->GetWorn()) && environment($1) == this_player()) :)); + if(!sizeof(eligible)){ + write("Remove or unwield items before trying to drop them."); + eligible = ({}); + return 1; + } + foreach(object ob in eligible) + if( (tmp = ob->eventDrop(this_player())) != 1 ) { + if( stringp(tmp) ) this_player()->eventPrint(tmp); + else this_player()->eventPrint("You cannot drop " + + ob->GetShort() + "."); + } + return 1; +} + +//mixed do_drop_wrd_wrd(string num, string curr) { +mixed do_drop_wrd_wrd(mixed args...) { + object ob, pile, env; + string num, curr; + int amt; + + num = args[0]; + curr = args[1]; + + if(ob = get_object(num+" "+curr)) return do_drop_obj(ob); + + amt = to_int(num); + env = environment(this_player()); + pile = new(LIB_PILE); + pile->SetPile(curr, amt); + if( !(pile->eventMove(env)) || + this_player()->AddCurrency(curr, -amt) == -1 ) { + this_player()->eventPrint("Something prevents your action."); + pile->eventDestruct(); + return 1; + } + this_player()->eventPrint("You drop " + amt + " " + curr + "."); + environment(this_player())->eventPrint(this_player()->GetName() + + " drops some " + curr + ".", + this_player()); + return 1; +} diff --git a/lib/verbs/items/eat.c b/lib/verbs/items/eat.c new file mode 100644 index 0000000..653a2d5 --- /dev/null +++ b/lib/verbs/items/eat.c @@ -0,0 +1,51 @@ +/* /verbs/items/eat.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 951113 + * Version: @(#) eat.c 1.3@(#) + * Last modified: 96/11/03 + */ + + + +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("eat"); + SetSynonyms("swallow"); + SetErrorMessage("Eat what?"); + SetRules("OBJ"); + SetHelp("Syntax: \n\n" + "Allows you to munch on some food. Keeping yourself well fed " + "helps you heal faster from wounds and have greater stamina.\n\n" + "See also: bait, cast, drink, fish"); +} + + +void eventEat(object who, object what) { + if( !what ) { + return; + } + return what->eventEat(who); +} + +mixed can_eat_obj() { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything."; + } + return this_player()->CanManipulate(); +} + +mixed do_eat_obj(object ob) { + if( this_player()->GetInCombat() ) { + this_player()->SetAttack(0, (: eventEat, this_player(), ob :), + ROUND_OTHER); + } + else { + eventEat(this_player(), ob); + } + return 1; +} diff --git a/lib/verbs/items/empty.c b/lib/verbs/items/empty.c new file mode 100644 index 0000000..b570e86 --- /dev/null +++ b/lib/verbs/items/empty.c @@ -0,0 +1,21 @@ + + +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("empty"); + SetRules("OBJ"); + SetErrorMessage("Empty what?"); + SetHelp("Syntax: empty \n\n" + "Removes the fluid from a vessel."); +} + +mixed can_empty_obj(string verb) { return this_player()->CanManipulate(); } + +mixed do_empty_obj(object from) { + return from->eventEmpty(this_player()); +} + diff --git a/lib/verbs/items/equate.c b/lib/verbs/items/equate.c new file mode 100644 index 0000000..80935d7 --- /dev/null +++ b/lib/verbs/items/equate.c @@ -0,0 +1,132 @@ +/* /verbs/spells/judge.c + * a skill for players to judge the relative worth of items + * created 961120 by Bill Gates@Dead Souls + */ + +#include +#include +#include +#include "include/judge.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("judge"); + SetSynonyms("equate"); + SetRules("OBJ to OBJ"); + SetErrorMessage("What two things would you like to equate?"); + SetHelp("Syntax: equate OBJ to OBJ\n\n" + "A bargaining ability which allows people to compare the " + "relative worth of two items. The more experienced you are " + "at bartering, the better chance you have of correctly judging " + "the more valuable item.\n\n" + "See help: item commands"); +} + +mixed can_judge_obj_to_obj() { + if( this_player()->GetLevel() < 6 ) { + this_player()->eventPrint("You are not experienced enough to judge " + "the value of items accurately."); + return 0; + } + return this_player()->CanCastMagic(1, "judge"); +} + + +mixed do_judge_obj_to_obj(object obj1, object obj2) { + int level; + string name1, name2; + object caster = this_player(); + if( !(caster->GetSkillLevel("bargaining")) ) { + return "You do not have the skills to judge items."; } + if (!obj1 || !obj2) return "You must judge one thing vs another."; + if (obj1 == obj2) return "That would do a lot of good!"; + + /* Check for presence of objects */ + name1 = obj1->GetShort(); + name2 = obj2->GetShort(); + + if( environment(obj1) != caster ) { + caster->eventPrint("You do not have "+name1+"."); + return 1; + } + + if( environment(obj2) != caster ) { + caster->eventPrint("You do not have "+name2+"."); + return 1; + } + + level = caster->GetSkillLevel("bargaining"); + caster->eventPrint("You stare intently at "+name1+" and "+name2+"."); + environment(caster)->eventPrint( caster->GetName() + + " concentrates on " + name1 + " and " + name2 + ".", caster); + if( this_player()->GetInCombat() ) + this_player()->SetAttack(0, + (: eventJudge, this_player(), obj1, obj2, level :), + ROUND_OTHER); + else eventJudge(this_player(), obj1, obj2, level); + return 1; +} + + +int eventJudge(object caster, object obj1, object obj2, int level) { + + int obj1lvl, obj2lvl; + string better; + + int cost = random(50) + 50; + + if( !(obj1 && obj2) ) return 0; + if( (environment(obj1) != caster) || (environment(obj2) != caster) ) { + caster->eventPrint("You must have both items in your possesion " + "to compare them."); + return 0; + } + if( cost > caster->GetStaminaPoints() ) { + caster->eventPrint("You are too weary to judge right now."); + environment(caster)->eventPrint( + caster->GetName() + " looks tired.", caster); + return 0; + + } + caster->AddStaminaPoints(-cost); + obj1lvl = obj1->GetValue(); + obj2lvl = obj2->GetValue(); + + if( level < (5 + random(35))) { + + if(random(7)) { + if(random(5) < 2) { + better = obj2->GetShort(); + } + else better = obj1->GetShort(); + caster->eventPrint("%^BOLD%^%^WHITE%^" + "You determine that " + better + "%^BOLD%^%^WHITE%^" + " is the more valuable object.%^RESET%^"); + return 0; + } + else caster->eventPrint("%^BOLD%^%^WHITE%^" + "You determine that these two items are equally valuable." + ".%^RESET%^"); + caster->AddSkillPoints("bargaining",random(25)); + return 1; + } + /* Return the right answer */ + if(obj1lvl == obj2lvl) { + caster->eventPrint("%^BOLD%^%^WHITE%^" + "You determine that these two items are equally valuable." + ".%^RESET%^"); + return 1; + } + if(obj1lvl > obj2lvl) { + better = obj1->GetShort(); + } + else better = obj2->GetShort(); + caster->eventPrint("%^BOLD%^%^WHITE%^" + "You determine that " + better + "%^BOLD%^%^WHITE%^" + " is the more valuable object.%^RESET%^"); + caster->AddSkillPoints("bargaining",random(50)); + return 1; + +} diff --git a/lib/verbs/items/extinguish.c b/lib/verbs/items/extinguish.c new file mode 100644 index 0000000..b029599 --- /dev/null +++ b/lib/verbs/items/extinguish.c @@ -0,0 +1,50 @@ +#include +#include "include/extinguish.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("extinguish"); + SetSynonyms("douse"); + SetRules("OBS"); + SetErrorMessage("Extinguish what?"); + SetHelp("Syntax: \n\n" + "Extinguish a burning thing like a torch or a lamp.\n\n" + "See also: light"); +} + +mixed can_extinguish_obj() { + return this_player()->CanManipulate(); +} + +mixed do_extinguish_obj(object target) { + return do_extinguish_obs(({ target })); +} + +mixed do_extinguish_obs(mixed *targs) { + object *obs; + string tmp; + + if( !sizeof(targs) ) { + this_player()->eventPrint("There is no such thing to be extinguished."); + return 1; + } + obs = filter(targs, (: objectp :)); + if( !sizeof(obs) ) { + mixed *ua; + + ua = unique_array(targs, (: $1 :)); + foreach(string *list in ua) this_player()->eventPrint(list[0]); + return 1; + } + obs = filter(obs, (: $1->eventExtinguish(this_player()) :)); + if( !sizeof(obs) ) return 1; + tmp = item_list(obs); + this_player()->eventPrint("You extinguish " + tmp + "."); + environment(this_player())->eventPrint(this_player()->GetName() + + " extinguishes " + tmp + ".", + this_player()); + return 1; +} + diff --git a/lib/verbs/items/fill.c b/lib/verbs/items/fill.c new file mode 100644 index 0000000..ae1cf11 --- /dev/null +++ b/lib/verbs/items/fill.c @@ -0,0 +1,25 @@ +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("fill"); + SetRules("OBJ with OBJ","OBJ from OBJ"); + SetErrorMessage("Fill what with what?"); + SetHelp("Syntax: fill with \n\n" + "Allows you to fill a vessel designed for containing a substance."); +} + +mixed can_fill_obj_with_obj(string verb) { return this_player()->CanManipulate(); } + +mixed can_fill_obj_from_obj(string verb) { return this_player()->CanManipulate(); } + +mixed do_fill_obj_with_obj(object to, object from) { + return to->eventFill(this_player(), from); +} + +mixed do_fill_obj_from_obj(object to, object from) { + return to->eventFill(this_player(), from); +} + diff --git a/lib/verbs/items/free.c b/lib/verbs/items/free.c new file mode 100644 index 0000000..a742d4b --- /dev/null +++ b/lib/verbs/items/free.c @@ -0,0 +1,31 @@ +/* /verbs/items/free.c + * From the Dead Souls Mud Library + * A verb to allow people to free things from traps + * Creatd by Descartes of Borg 961010 + * Version: @(#) free.c 1.1@(#) + * Last modified: 96/10/10 + */ + +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("free"); + SetRules("LIV from OBJ"); + SetSynonyms("release", "liberate", "emancipate"); + SetErrorMessage("Free what from what?"); + SetHelp("Syntax: \n\n" + "Frees an object from a trap.\n\n" + "Synonyms: emancipate, liberate, release\n\n" + "See also: capture"); +} + +mixed can_free_liv_from_obj() { + return this_player()->CanManipulate(); +} + +mixed do_free_liv_from_obj(object target, object tool) { + return tool->eventFree(this_player(), target); +} diff --git a/lib/verbs/items/get.c b/lib/verbs/items/get.c new file mode 100644 index 0000000..cf5b2de --- /dev/null +++ b/lib/verbs/items/get.c @@ -0,0 +1,224 @@ +/* /verbs/items/get.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 950113 + * Version: @(#) get.c 1.5@(#) + * Last Modified: 96/11/12 + */ + +#include + +inherit LIB_VERB; +int yes; + +static void create() { + verb::create(); + SetVerb("get"); + SetRules("OBS OBJ", "WRD from OBJ", "WRD out of OBJ", "WRD WRD from OBJ", "WRD WRD out of OBJ", + "OBS", "OBS out of OBJ", "OBS from OBJ"); + SetSynonyms("take"); + SetErrorMessage("Get what? Or perhaps get something from somewhere?"); + SetHelp("Syntax: \n" + " \n" + " \n" + " \n" + " \n\n" + "This allows you to get items in the same room as you, or " + "contained inside other items so that you are carrying them. " + "In addition, you can specify partial amounts of currency to " + "pick up from a pile lying around.\n\n" + "Synonyms: take\n\n" + "See also: drop, give, put"); +} + +mixed eventCheckLight(object who) { + int light; + + if( (light = who->GetEffectiveVision()) < 2 ) { + if( 100 + (10*light) < random(100) ) + return "You fumble around in the darkness."; + else return this_player()->CanManipulate(); + } + else if( light > 5 ) { + if( 100 - (10*light) < random(100) ) + return "You fumble around in the blinding light."; + else return this_player()->CanManipulate(); + } + else return this_player()->CanManipulate(); +} + +mixed can_get_obj(string verb) { + return eventCheckLight(this_player()); +} + +varargs mixed can_get_obj_out_of_obj(mixed args...) { + mixed ret = eventCheckLight(this_player()); + object ob; + int which; + if(!(args[3] && ob = to_object(args[3]))) + return ret; + else { + if(ob->GetClosed()){ + return "The "+remove_article(ob->GetShort())+" is closed."; + } + } + return ret; +} + +mixed can_get_obj_obj(string verb, string rule, mixed item, object container) { + return can_get_obj_out_of_obj(verb, rule, item, container); +} + +mixed can_get_obs_obj(string verb,string rule,mixed *item,object container){ + return can_get_obj_out_of_obj(verb, rule, item, container); +} + +mixed can_get_obj_from_obj(mixed args...) { + return can_get_obj_out_of_obj(args...); +} + +mixed can_get_wrd_wrd_out_of_obj(mixed args...) { + mixed ret = eventCheckLight(this_player()); + object ob; + if(sizeof(args) > 5) + if(args[5]) ob = to_object(args[5]); + else if(args[3]) ob = to_object(args[3]); + + if(ob && ob->GetClosed()){ + return "The "+remove_article(ob->GetShort())+" is closed." ; + } + return ret; +} + +mixed can_get_wrd_wrd_from_obj(mixed args...) { + return can_get_wrd_wrd_out_of_obj(args...); +} + +mixed can_get_wrd_out_of_obj(mixed args...) { + mixed ret = eventCheckLight(this_player()); + object ob; + if(args[3]) ob = to_object(args[3]); + + if(ob && ob->GetClosed()){ + return "The "+remove_article(ob->GetShort())+" is closed." ; + } + return ret; +} + +mixed can_get_wrd_from_obj(mixed args...) { + return can_get_wrd_out_of_obj(args...); +} + +mixed do_get_obj(object ob) { + return ob->eventGet(this_player()); +} + +mixed do_get_obj_out_of_obj(object ob, object storage) { + if(!ob) return "No object"; + if(!(environment(ob) == storage)){ + ob = present(ob->GetKeyName(), storage); + if(!ob){ + write("That's not in there."); + return ""; + } + } + return storage->eventGetFrom(this_player(), ({ ob })); +} + +mixed do_get_obj_from_obj(object ob, object storage) { + return do_get_obj_out_of_obj(ob, storage); +} + +mixed do_get_obj_obj(object ob, object storage) { + return do_get_obj_out_of_obj(ob, storage); +} + +mixed do_get_obs(mixed *targs) { + object *obs; + if( !sizeof(targs) ) { + this_player()->eventPrint("There is no such thing to be taken."); + return 1; + } + obs = filter(targs, (: objectp :)); + if( !sizeof(obs) ) { + mapping messages = unique_mapping(targs, (: $1 :)); + + foreach(string msg in keys(messages)) { + this_player()->eventPrint(msg); + } + return 1; + } + foreach(object item in obs) { + + if( item->CanGet(this_player()) != 1 ) continue; + item->eventGet(this_player()); + } + return 1; +} + +mixed do_get_obs_out_of_obj(mixed *targs, object storage) { + object *obs; + if( !sizeof(targs) ) { + this_player()->eventPrint("There is no such thing to be taken."); + return 1; + } + obs = filter(targs, (: objectp :)); + if( !sizeof(obs) ) { + mapping messages = unique_mapping(targs, (: $1 :)); + + foreach(string msg in keys(messages)) { + this_player()->eventPrint(msg); + } + return 1; + } + return storage->eventGetFrom(this_player(), obs); +} + +mixed do_get_obs_from_obj(mixed *obs, object storage) { + return do_get_obs_out_of_obj(obs, storage); +} + +mixed do_get_obs_obj(mixed *obs, object storage) { + return do_get_obs_out_of_obj(obs, storage); +} + +mixed do_get_wrd_wrd_from_obj(mixed args...) { + string num, curr; + mixed pile; + object ob1, ob2; + + num = args[0]; + curr = args[1]; + pile = args[2]; + + ob1 = to_object(num+" "+curr); + ob2 = to_object(implode(args[6..]," ")); + + if(ob1 && ob2) return do_get_obj_from_obj(ob1, ob2); + + return pile->eventGetMoney(this_player(), to_int(num), curr); +} + +mixed do_get_wrd_wrd_out_of_obj(mixed args...) { + return do_get_wrd_wrd_from_obj(args); +} + +mixed do_get_wrd_from_obj(mixed args...) { + string num, curr; + mixed pile; + object ob1, ob2; + + num = args[0]; + curr = args[1]; + pile = args[2]; + + ob1 = to_object(num+" "+curr); + ob2 = to_object(implode(args[6..]," ")); + + if(ob1 && ob2) return do_get_obj_from_obj(ob1, ob2); + + return pile->eventGetMoney(this_player(), to_int(num), curr); +} + +mixed do_get_wrd_out_of_obj(mixed args...) { + return do_get_wrd_from_obj(args); +} diff --git a/lib/verbs/items/give.c b/lib/verbs/items/give.c new file mode 100644 index 0000000..08ac7bc --- /dev/null +++ b/lib/verbs/items/give.c @@ -0,0 +1,172 @@ +/* /verbs/items/give.c + * from the Dead Souls Mud Library + * give LIV OBJ + * give OBJ to LIV + * give LIV WRD WRD + * give WRD WRD to LIV + * created by Descartes of Borg 950113 + */ + +#include +#include "include/give.h" + +inherit LIB_VERB; + +string curr2; + +static void create() { + verb::create(); + SetVerb("give"); + SetRules("LIV WRD WRD", "WRD WRD to LIV", "OBS LIV", "LIV OBS", "OBS to LIV" ); + SetErrorMessage("Give what to whom?"); + SetHelp("Syntax: \n" + " \n" + " \n" + " \n" + " \n" + " \n\n" + "This command allows you to give something you have to " + "someone else.\n\n" + "See also: drop, get, put"); +} + +mixed can_give_liv_obj(mixed args...) { + return can_give_obj_to_liv(); +} + +mixed can_give_obj_liv(mixed args...) { + return can_give_obj_to_liv(); +} + +mixed can_give_obj_to_liv(mixed args...) { + return this_player()->CanManipulate(); } + + mixed can_give_liv_wrd_wrd(object targ, string num, string curr) { + return can_give_wrd_wrd_to_liv(num, curr, targ); + } + +mixed can_give_wrd_wrd_to_liv(string num, string curr, object targ) { + int amt; + curr2 = curr; + if(!valid_currency(curr)) curr = truncate(curr,1); + if(!valid_currency(curr)) curr = truncate(curr,1); + if(!valid_currency(curr)) curr = curr2 +"s"; + if(!valid_currency(curr)) curr = curr2 +"es"; + if(valid_currency(curr)) curr2 = curr; + + if(sscanf(num,"%d",amt) != 1){ + if(valid_currency(curr)) return "Please use a number to specify the amount."; + else return "That isn't a valid currency."; + } + if( amt < 1 ) return "What sort of amount is that?"; + if( amt > this_player()->GetCurrency(lower_case(curr)) ) + return "You don't have that much " + curr + "."; + if(newbiep(this_player())) return "Newbies can't give money."; + return this_player()->CanManipulate(); +} + +//mixed do_give_liv_obj(object target, object what) { +mixed do_give_liv_obj(mixed args...) { + object target, what; + target = args[0]; + what = args[1]; + return do_give_obj_to_liv(what, target); +} + +//mixed do_give_obj_liv(object what, object target) { +mixed do_give_obj_liv(mixed args...) { + object target, what; + target = args[1]; + what = args[0]; + return do_give_obj_to_liv(what, target); +} + +//mixed do_give_obj_to_liv(object what, object target) { +mixed do_give_obj_to_liv(mixed args...) { + object target, what; + target = args[1]; + what = args[0]; + + if(!intp(target->CanManipulate())){ + this_player()->eventPrint(target->GetName()+" is incapable "+ + "of holding that."); + return 1; + } + if( !(what->eventMove(target)) ) { + this_player()->eventPrint("They cannot accept that right now."); + return 1; + } + this_player()->eventPrint("You give " + target->GetName() + " " + + what->GetShort() + "."); + target->eventPrint(this_player()->GetName() + " gives you " + + what->GetShort() + "."); + environment(this_player())->eventPrint(this_player()->GetName() + + " gives " + + target->GetName() + + " " + what->GetShort() +".", + ({ this_player(), target })); + return 1; +} + +mixed do_give_liv_wrd_wrd(object target, string num, string curr) { + return do_give_wrd_wrd_to_liv(num, curr, target); +} + +mixed do_give_wrd_wrd_to_liv(string num, string curr, object target) { + int amt; + if(curr2) curr = curr2; + amt = to_int(num); + if( target->AddCurrency(curr, amt) == -1 ) { + this_player()->eventPrint("You just can't give that money away."); + return 1; + } + if( this_player()->AddCurrency(curr, -amt) == -1 ) { + target->AddCurrency(curr, -amt); + this_player()->eventPrint("The amount of money you have is boggled."); + return 1; + } + this_player()->eventPrint("You give " + target->GetName() + " " + + amt + " " + curr + "."); + target->eventPrint(this_player()->GetName() + " gives you " + + amt + " " + curr + "."); + environment(this_player())->eventPrint(this_player()->GetName() + + " gives " + amt + " " + curr + + " to " + target->GetName() + + ".", ({ target, this_player() })); + return 1; +} + +mixed do_give_liv_obs(object target, mixed *items) { + return do_give_obs_to_liv(items, target); +} + +mixed do_give_obs_liv(mixed *items, object target) { + return do_give_obs_to_liv(items, target); +} + +mixed do_give_obs_to_liv(mixed *items, object target) { + object *obs, *eligible; + + if( sizeof(items) < 1 ) { + this_player()->eventPrint("You don't have any to give."); + return 1; + } + + obs = filter(items, (: objectp :)); + if( !sizeof(obs) ) { + mixed *ua; + + ua = unique_array(items, (: $1 :)); + foreach(string *list in ua) this_player()->eventPrint(list[0]); + return 1; + } + eligible=filter(obs, (: (!($1->GetWorn()) && environment($1) == this_player()) :)); + if(!sizeof(eligible)){ + write("Remove or unwield items before trying to sell them."); + eligible = ({}); + return 1; + } + + foreach(object ob in eligible) do_give_obj_to_liv(ob, target); + return 1; +} diff --git a/lib/verbs/items/include/bait.h b/lib/verbs/items/include/bait.h new file mode 100644 index 0000000..9c7838c --- /dev/null +++ b/lib/verbs/items/include/bait.h @@ -0,0 +1,8 @@ +#ifndef l_bait_h +#define l_bait_h + +static void create(); +mixed can_bait_obj_with_obj(string verb); +mixed do_bait_obj_with_obj(object pole, object bait); + +#endif diff --git a/lib/verbs/items/include/balance.h b/lib/verbs/items/include/balance.h new file mode 100644 index 0000000..dbd6315 --- /dev/null +++ b/lib/verbs/items/include/balance.h @@ -0,0 +1,9 @@ +#ifndef __balance_h__ +#define __balance_h__ + +static void create(); +mixed can_balance_obj_str_obj(string str); +mixed do_balance_obj_str_obj(object obj1, object obj2); +int eventBalance(object caster, object obj1, object obj2); + +#endif diff --git a/lib/verbs/items/include/bury.h b/lib/verbs/items/include/bury.h new file mode 100644 index 0000000..c632a53 --- /dev/null +++ b/lib/verbs/items/include/bury.h @@ -0,0 +1,11 @@ +#ifndef l_bury_h +#define l_bury_h + +static void create(); +mixed can_bury_str_with_obj(string verb); + +mixed do_bury_str_with_obj(string str, object ob); + +void eventBury(object who, object tool, string what); + +#endif /* l_bury_h */ diff --git a/lib/verbs/items/include/close.h b/lib/verbs/items/include/close.h new file mode 100644 index 0000000..efb5416 --- /dev/null +++ b/lib/verbs/items/include/close.h @@ -0,0 +1,10 @@ +#ifndef l_close_h +#define l_close_h + +static void create(); + +mixed can_close(string verb); + +varargs mixed do_close_obj(object ob, mixed *args...); + +#endif /* l_close_h */ diff --git a/lib/verbs/items/include/dig.h b/lib/verbs/items/include/dig.h new file mode 100644 index 0000000..85cf509 --- /dev/null +++ b/lib/verbs/items/include/dig.h @@ -0,0 +1,14 @@ +#ifndef l_dig_h +#define l_dig_h + +static void create(); + +mixed can_dig_with_obj(string verb); +mixed can_dig_obj_with_obj(string verb); + +mixed do_dig_with_obj(object ob); +mixed do_dig_obj_with_obj(object what, object ob, string id); + +void eventDig(object who, object tool, object target, string what); + +#endif /* l_dig_h */ diff --git a/lib/verbs/items/include/drink.h b/lib/verbs/items/include/drink.h new file mode 100644 index 0000000..cdda97d --- /dev/null +++ b/lib/verbs/items/include/drink.h @@ -0,0 +1,14 @@ +#ifndef l_drink_h +#define l_drink_h + +static void create(); + +mixed can_drink_obj(string verb); +mixed can_drink_from_obj(string verb); + +mixed do_drink_obj(object ob); +mixed do_drink_from_obj(object ob, string id); + +varargs void eventDrink(object who, object what, string id); + +#endif /* l_drink_h */ diff --git a/lib/verbs/items/include/drop.h b/lib/verbs/items/include/drop.h new file mode 100644 index 0000000..6d6b8d9 --- /dev/null +++ b/lib/verbs/items/include/drop.h @@ -0,0 +1,13 @@ +#ifndef l_drop_h +#define l_drop_h + +static void create(); + +mixed can_drop_obj(string verb); +mixed can_drop_wrd_wrd(string amt, string curr); + +mixed do_drop_obj(object ob); +mixed do_drop_obs(object *obs); +mixed do_drop_wrd_wrd(string amt, string curr); + +#endif /* l_drop_h */ diff --git a/lib/verbs/items/include/eat.h b/lib/verbs/items/include/eat.h new file mode 100644 index 0000000..127549e --- /dev/null +++ b/lib/verbs/items/include/eat.h @@ -0,0 +1,12 @@ +#ifndef l_eat_h +#define l_eat_h + +static void create(); + +mixed can_eat_obj(string verb); + +mixed do_eat_obj(object ob); + +void eventEat(object who, object what); + +#endif /* l_eat_h */ diff --git a/lib/verbs/items/include/extinguish.h b/lib/verbs/items/include/extinguish.h new file mode 100644 index 0000000..69f8f82 --- /dev/null +++ b/lib/verbs/items/include/extinguish.h @@ -0,0 +1,11 @@ +#ifndef l_extinguish_h +#define l_extinguish_h + +static void create(); + +mixed can_extinguish_obj(); + +mixed do_extinguish_obj(object target); +mixed do_extinguish_obs(mixed *targs); + +#endif /* l_extinguish_h */ diff --git a/lib/verbs/items/include/get.h b/lib/verbs/items/include/get.h new file mode 100644 index 0000000..185c958 --- /dev/null +++ b/lib/verbs/items/include/get.h @@ -0,0 +1,23 @@ +#ifndef l_get_h +#define l_get_h + +static void create(); + +mixed can_get_obj(string verb); +mixed can_get_obj_from_obj(string verb); +mixed can_get_obj_out_of_obj(string verb); +mixed can_get_wrd_wrd_from_obj(string num, string curr); +mixed can_get_wrd_wrd_out_of_obj(string num, string curr); + +mixed do_get_obj(object ob); +mixed do_get_obj_from_obj(object target, object storage); +mixed do_get_obj_out_of_obj(object target, object storage); +mixed do_get_wrd_wrd_from_obj(string num, string curr, object pile); +mixed do_get_wrd_wrd_out_of_obj(string num, string curr, object pile); +mixed do_get_obs(object *obs); +mixed do_get_obs_from_obj(object *obs, object ob); +mixed do_get_obs_out_of_obj(object *obs, object ob); + +mixed eventCheckLight(object who); + +#endif /* l_get_h */ diff --git a/lib/verbs/items/include/give.h b/lib/verbs/items/include/give.h new file mode 100644 index 0000000..0a231e2 --- /dev/null +++ b/lib/verbs/items/include/give.h @@ -0,0 +1,18 @@ +#ifndef l_give_h +#define l_give_h + +static void create(); + +mixed can_give_liv_obj(); +mixed can_give_obj_to_liv(); +mixed can_give_liv_wrd_wrd(object targ, string num, string curr); +mixed can_give_wrd_wrd_to_liv(string num, string curr, object targ); + +mixed do_give_liv_obj(object target, object what); +mixed do_give_obj_to_liv(object what, object target); +mixed do_give_liv_wrd_wrd(object target, string num, string curr); +mixed do_give_wrd_wrd_to_liv(string num, string curr, object target); +mixed do_give_liv_obs(object target, mixed *items); +mixed do_give_obs_to_liv(mixed *items, object target); + +#endif /* l_give_h */ diff --git a/lib/verbs/items/include/judge.h b/lib/verbs/items/include/judge.h new file mode 100644 index 0000000..001035e --- /dev/null +++ b/lib/verbs/items/include/judge.h @@ -0,0 +1,9 @@ +#ifndef __judge_h__ +#define __judge_h__ + +static void create(); +mixed can_judge_obj_str_obj(string str); +mixed do_judge_obj_str_obj(object obj1, object obj2); +int eventJudge(object caster, object obj1, object obj2, int level); + +#endif diff --git a/lib/verbs/items/include/light.h b/lib/verbs/items/include/light.h new file mode 100644 index 0000000..b86a24b --- /dev/null +++ b/lib/verbs/items/include/light.h @@ -0,0 +1,14 @@ +#ifndef l_light_h +#define l_light_h + +static void create(); + +mixed can_light_obj(); +mixed can_light_obj_with_obj(); + +mixed do_light_obj(object target); +mixed do_light_obj_with_obj(object target, object source); +mixed do_light_obs(mixed *targs); +mixed do_light_obs_with_obj(mixed *targs, object source); + +#endif /* l_light_h */ diff --git a/lib/verbs/items/include/lock.h b/lib/verbs/items/include/lock.h new file mode 100644 index 0000000..2a4fd52 --- /dev/null +++ b/lib/verbs/items/include/lock.h @@ -0,0 +1,10 @@ +#ifndef l_lock_h +#define l_lock_h + +static void create(); + +mixed can_lock_obj_with_obj(string verb); + +varargs mixed do_lock_obj_with_obj(object ob, object key, mixed *args...); + +#endif /* l_lock_h */ diff --git a/lib/verbs/items/include/look.h b/lib/verbs/items/include/look.h new file mode 100644 index 0000000..bbdf26e --- /dev/null +++ b/lib/verbs/items/include/look.h @@ -0,0 +1,22 @@ +#ifndef l_look_h +#define l_look_h + +static void create(); + +mixed can_look(); +mixed can_look_at_str(string str, string verb); +mixed can_look_at_obj(string verb, string id); +mixed can_look_in_obj(string verb, string id); +mixed can_look_inside_obj(string verb, string id); +mixed can_look_at_obj_word_obj(string verb, string targ, string store); +mixed can_look_at_str_on_obj(string targ, string verb, string id1, string id2); + +mixed do_look(); +varargs mixed do_look_at_obj(object ob, mixed *args...); +mixed do_look_at_str(string str); +mixed do_look_in_obj(object ob, mixed arg); +mixed do_look_inside_obj(object ob, mixed arg); +mixed do_look_at_obj_word_obj(object target, object storage, mixed arg); +varargs mixed do_look_at_str_on_obj(string id, object ob, mixed args...); + +#endif /* l_look_h */ diff --git a/lib/verbs/items/include/open.h b/lib/verbs/items/include/open.h new file mode 100644 index 0000000..d8db35c --- /dev/null +++ b/lib/verbs/items/include/open.h @@ -0,0 +1,12 @@ +#ifndef l_open_h +#define l_open_h + +static void create(); + +varargs mixed can_open_obj(object ob, mixed *args...); +varargs mixed can_open_obj_with_obj(object ob, object with, mixed *args...); + +varargs mixed do_open_obj(object ob, mixed *args...); +varargs mixed do_open_obj_with_obj(object ob, object with, mixed *args...); + +#endif /* l_open_h */ diff --git a/lib/verbs/items/include/pick.h b/lib/verbs/items/include/pick.h new file mode 100644 index 0000000..49d67b6 --- /dev/null +++ b/lib/verbs/items/include/pick.h @@ -0,0 +1,13 @@ +#ifndef l_pick_h +#define l_pick_h + +static void create(); + +mixed can_pick_str_on_obj(string str); +mixed can_pick_str_on_obj_with_obj(string str); + +varargs mixed do_pick_str_on_obj(string str, object ob, mixed *args...); +varargs mixed do_pick_str_on_obj_with_obj(string str, object ob, object tool, + mixed *args...); + +#endif /* l_pick_h */ diff --git a/lib/verbs/items/include/poison.h b/lib/verbs/items/include/poison.h new file mode 100644 index 0000000..735e0e3 --- /dev/null +++ b/lib/verbs/items/include/poison.h @@ -0,0 +1,12 @@ +#ifndef l_poison_h +#define l_poison_h + +static void create(); + +mixed can_poison_obj_with_obj(string verb); + +mixed do_poison_obj_with_obj(object target, object agent); + +void eventPoison(object who, object target, object agent); + +#endif /* l_poison_h */ diff --git a/lib/verbs/items/include/put.h b/lib/verbs/items/include/put.h new file mode 100644 index 0000000..0db280f --- /dev/null +++ b/lib/verbs/items/include/put.h @@ -0,0 +1,13 @@ +#ifndef l_put_h +#define l_put_h + +static void create(); + +mixed can_put_obj_word_obj(object target, string wrd, object storage); + +mixed do_put_obj_word_obj(object what, string wrd, object storage); +mixed do_put_obs_word_obj(mixed *res, string wrd, object storage); + +mixed eventCheckLight(object who); + +#endif /* l_put_h */ diff --git a/lib/verbs/items/include/read.h b/lib/verbs/items/include/read.h new file mode 100644 index 0000000..883949d --- /dev/null +++ b/lib/verbs/items/include/read.h @@ -0,0 +1,13 @@ +#ifndef l_read_h +#define l_read_h + +static void create(); + +mixed can_read_obj(string verb, string id); +mixed can_read_str_word_obj(string str, string verb); + +varargs mixed do_read_obj(mixed *args...); +mixed do_read_str_from_obj(string str, object ob); +mixed do_read_str_on_obj(string str, object ob); + +#endif /* l_read_h */ diff --git a/lib/verbs/items/include/remove.h b/lib/verbs/items/include/remove.h new file mode 100644 index 0000000..4f20448 --- /dev/null +++ b/lib/verbs/items/include/remove.h @@ -0,0 +1,17 @@ +#ifndef l_remove_h +#define l_remove_h + +static void create(); + +mixed can_remove_obj(string verb); +mixed can_remove_obj_from_obj(); +mixed can_remove_obj_out_of_obj(); + +mixed do_remove_obj(object ob); +mixed do_remove_obs(mixed *res); +mixed do_remove_obj_from_obj(object targ, object container); +mixed do_remove_obj_out_of_obj(object targ, object container); +mixed do_remove_obs_from_obj(mixed *res, object container); +mixed do_remove_obs_out_of_obj(mixed *res, object container); + +#endif /* l_remove_h */ diff --git a/lib/verbs/items/include/search.h b/lib/verbs/items/include/search.h new file mode 100644 index 0000000..190e3b9 --- /dev/null +++ b/lib/verbs/items/include/search.h @@ -0,0 +1,12 @@ +#ifndef l_search_h +#define l_search_h + +static void create(); + +mixed can_search(); +mixed can_search_obj(); + +mixed do_search(); +varargs mixed do_search_obj(object ob, mixed *args...); + +#endif /* l_search_h */ diff --git a/lib/verbs/items/include/show.h b/lib/verbs/items/include/show.h new file mode 100644 index 0000000..f5c2233 --- /dev/null +++ b/lib/verbs/items/include/show.h @@ -0,0 +1,12 @@ +#ifndef l_show_h +#define l_show_h + +static void create(); + +mixed can_show_liv_obj(); +mixed can_show_obj_to_liv(); + +mixed do_show_liv_obj(object target, object what); +mixed do_show_obj_to_liv(object what, object target); + +#endif /* l_show_h */ diff --git a/lib/verbs/items/include/smell.h b/lib/verbs/items/include/smell.h new file mode 100644 index 0000000..83c9e07 --- /dev/null +++ b/lib/verbs/items/include/smell.h @@ -0,0 +1,12 @@ +#ifndef l_smell_h +#define l_smell_h + +static void create(); + +mixed can_smell(); +mixed can_smell_obj(object ob, string id); + +mixed do_smell(); +mixed do_smell_obj(object ob, string id); + +#endif /* l_smell_h */ diff --git a/lib/verbs/items/include/steal.h b/lib/verbs/items/include/steal.h new file mode 100644 index 0000000..74a3247 --- /dev/null +++ b/lib/verbs/items/include/steal.h @@ -0,0 +1,15 @@ +#ifndef l_steal_h +#define l_steal_h + +static void create(); + +mixed can_steal_wrd_from_liv(string wrd); +mixed can_steal_obj_from_liv(); + +mixed do_steal_wrd_from_liv(string wrd, object liv); +mixed do_steal_obj_from_liv(object ob, object liv); +mixed do_steal_obs_from_liv(mixed *res, object liv); + +static void eventSteal(object who, mixed what, object liv); + +#endif /* l_steal_h */ diff --git a/lib/verbs/items/include/strike.h b/lib/verbs/items/include/strike.h new file mode 100644 index 0000000..bf24c6e --- /dev/null +++ b/lib/verbs/items/include/strike.h @@ -0,0 +1,8 @@ +#ifndef l_strike_h +#define l_strike_h + +static void create(); +mixed can_strike_obj(); +mixed do_strike_obj(object ob); + +#endif /* l_strike_h */ diff --git a/lib/verbs/items/include/throw.h b/lib/verbs/items/include/throw.h new file mode 100644 index 0000000..d133c9a --- /dev/null +++ b/lib/verbs/items/include/throw.h @@ -0,0 +1,15 @@ +#ifndef l_throw_h +#define l_throw_h + +static void create(); + +mixed can_throw_obj(); +mixed can_throw_obj_word_obj(); + +mixed do_throw_obj(object ob); +mixed do_throw_obj_at_obj(object what, object where); +mixed do_throw_obj_into_obj(object what, object where); + +void eventThrow(object who, object what, object where); + +#endif /* l_throw_h */ diff --git a/lib/verbs/items/include/unlock.h b/lib/verbs/items/include/unlock.h new file mode 100644 index 0000000..4b759fc --- /dev/null +++ b/lib/verbs/items/include/unlock.h @@ -0,0 +1,12 @@ +#ifndef l_unlock_h +#define l_unlock_h + +static void create(); + +varargs mixed can_unlock_obj_with_obj(object ob, object key, mixed *args...); + +varargs mixed do_unlock_obj_with_obj(object ob, object key, mixed *args...); + +string GetHelp(string str); + +#endif /* l_unlock_h */ diff --git a/lib/verbs/items/include/unwield.h b/lib/verbs/items/include/unwield.h new file mode 100644 index 0000000..adb2404 --- /dev/null +++ b/lib/verbs/items/include/unwield.h @@ -0,0 +1,10 @@ +#ifndef l_unwield_h +#define l_unwield_h + +static void create(); + +mixed can_unwield_obj(string verb); + +mixed do_unwield_obj(object ob); + +#endif /* l_unwield_h */ diff --git a/lib/verbs/items/include/use.h b/lib/verbs/items/include/use.h new file mode 100644 index 0000000..74a8111 --- /dev/null +++ b/lib/verbs/items/include/use.h @@ -0,0 +1,10 @@ +#ifndef l_use_h +#define l_use_h + +static void create(); + +mixed can_use_obj_to_str(string str); + +mixed do_use_obj_to_str(object ob, string str); + +#endif /* l_use_h */ diff --git a/lib/verbs/items/include/wear.h b/lib/verbs/items/include/wear.h new file mode 100644 index 0000000..6ecbf68 --- /dev/null +++ b/lib/verbs/items/include/wear.h @@ -0,0 +1,12 @@ +#ifndef l_wear_h +#define l_wear_h + +static void create(); + +mixed can_wear_obj(); +mixed can_wear_obj_on_str(string str); + +mixed do_wear_obj(object ob); +mixed do_wear_obj_on_str(object ob, string str); + +#endif /* l_wear_h */ diff --git a/lib/verbs/items/include/weigh.h b/lib/verbs/items/include/weigh.h new file mode 100644 index 0000000..ea062a4 --- /dev/null +++ b/lib/verbs/items/include/weigh.h @@ -0,0 +1,9 @@ +#ifndef __balance_h__ +#define __balance_h__ + +static void create(); +mixed can_weigh_obj(); +mixed do_weigh_obj(object obj); +int eventWeigh(object who, object obj); + +#endif diff --git a/lib/verbs/items/include/wield.h b/lib/verbs/items/include/wield.h new file mode 100644 index 0000000..f83d864 --- /dev/null +++ b/lib/verbs/items/include/wield.h @@ -0,0 +1,12 @@ +#ifndef l_wield_h +#define l_wield_h + +static void create(); + +mixed can_wield_obj(); +mixed can_wield_obj_word_str(string str); + +mixed do_wield_obj(object ob); +mixed do_wield_obj_word_str(object ob, string word, string str); + +#endif /* l_wield_h */ diff --git a/lib/verbs/items/install.c b/lib/verbs/items/install.c new file mode 100644 index 0000000..13ddb0f --- /dev/null +++ b/lib/verbs/items/install.c @@ -0,0 +1,39 @@ +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("install"); + SetRules("", "OBJ","OBJ on OBJ","OBJ into OBJ","OBJ in OBJ"); + SetErrorMessage("Install something?"); + SetHelp("Syntax: install THING\n" + " install THING on THING\n" + ""); +} + +mixed can_install() { + return this_player()->CanManipulate(); +} + +mixed can_install_obj(mixed foo) { + return this_player()->CanManipulate(); +} + +mixed can_install_obj_word_obj(mixed foo) { + return this_player()->CanManipulate(); +} + +mixed do_install() { + return "Install what?"; + return 1; +} + +varargs mixed do_install_obj(mixed foo) { + return foo->eventInstall(); +} + +varargs mixed do_install_obj_word_obj(mixed foo, mixed wort, mixed foo2) { + return foo->eventInstall(this_player(), foo2); +} diff --git a/lib/verbs/items/judge.c b/lib/verbs/items/judge.c new file mode 100644 index 0000000..c5ce4df --- /dev/null +++ b/lib/verbs/items/judge.c @@ -0,0 +1,131 @@ +/* /verbs/spells/judge.c + * a skill for players to judge the relative worth of items + * created 961120 by Bill Gates@Dead Souls + */ + +#include +#include +#include +#include "include/judge.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("judge"); + SetSynonyms("equate"); + SetRules("OBJ to OBJ"); + SetErrorMessage("What two things would you like to equate?"); + SetHelp("Syntax: equate OBJ to OBJ\n\n" + "A bargaining ability which allows people to compare the " + "relative worth of two items. The more experienced you are " + "at bartering, the better chance you have of correctly judging " + "the more valuable item.\n\n"); +} + +mixed can_judge_obj_to_obj() { + if( this_player()->GetLevel() < 6 ) { + this_player()->eventPrint("You are not experienced enough to judge " + "the value of items accurately."); + return 0; + } + return this_player()->CanCastMagic(1, "judge"); +} + + +mixed do_judge_obj_to_obj(object obj1, object obj2) { + int level; + string name1, name2; + object caster = this_player(); + if( !(caster->GetSkillLevel("bargaining")) ) { + return "You do not have the skills to judge items."; } + if (!obj1 || !obj2) return "You must judge one thing vs another."; + if (obj1 == obj2) return "That would do a lot of good!"; + + /* Check for presence of objects */ + name1 = obj1->GetShort(); + name2 = obj2->GetShort(); + + if( environment(obj1) != caster ) { + caster->eventPrint("You do not have "+name1+"."); + return 1; + } + + if( environment(obj2) != caster ) { + caster->eventPrint("You do not have "+name2+"."); + return 1; + } + + level = caster->GetSkillLevel("bargaining"); + caster->eventPrint("You stare intently at "+name1+" and "+name2+"."); + environment(caster)->eventPrint( caster->GetName() + + " concentrates on " + name1 + " and " + name2 + ".", caster); + if( this_player()->GetInCombat() ) + this_player()->SetAttack(0, + (: eventJudge, this_player(), obj1, obj2, level :), + ROUND_OTHER); + else eventJudge(this_player(), obj1, obj2, level); + return 1; +} + + +int eventJudge(object caster, object obj1, object obj2, int level) { + + int obj1lvl, obj2lvl; + string better; + + int cost = random(50) + 50; + + if( !(obj1 && obj2) ) return 0; + if( (environment(obj1) != caster) || (environment(obj2) != caster) ) { + caster->eventPrint("You must have both items in your possesion " + "to compare them."); + return 0; + } + if( cost > caster->GetStaminaPoints() ) { + caster->eventPrint("You are too weary to judge right now."); + environment(caster)->eventPrint( + caster->GetName() + " looks tired.", caster); + return 0; + + } + caster->AddStaminaPoints(-cost); + obj1lvl = obj1->GetValue(); + obj2lvl = obj2->GetValue(); + + if( level < (5 + random(35))) { + + if(random(7)) { + if(random(5) < 2) { + better = obj2->GetShort(); + } + else better = obj1->GetShort(); + caster->eventPrint("%^BOLD%^%^WHITE%^" + "You determine that " + better + "%^BOLD%^%^WHITE%^" + " is the more valuable object.%^RESET%^"); + return 0; + } + else caster->eventPrint("%^BOLD%^%^WHITE%^" + "You determine that these two items are equally valuable." + ".%^RESET%^"); + caster->AddSkillPoints("bargaining",random(25)); + return 1; + } + /* Return the right answer */ + if(obj1lvl == obj2lvl) { + caster->eventPrint("%^BOLD%^%^WHITE%^" + "You determine that these two items are equally valuable." + ".%^RESET%^"); + return 1; + } + if(obj1lvl > obj2lvl) { + better = obj1->GetShort(); + } + else better = obj2->GetShort(); + caster->eventPrint("%^BOLD%^%^WHITE%^" + "You determine that " + better + "%^BOLD%^%^WHITE%^" + " is the more valuable object.%^RESET%^"); + caster->AddSkillPoints("bargaining",random(50)); + return 1; + +} diff --git a/lib/verbs/items/judge1.c b/lib/verbs/items/judge1.c new file mode 100644 index 0000000..80935d7 --- /dev/null +++ b/lib/verbs/items/judge1.c @@ -0,0 +1,132 @@ +/* /verbs/spells/judge.c + * a skill for players to judge the relative worth of items + * created 961120 by Bill Gates@Dead Souls + */ + +#include +#include +#include +#include "include/judge.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("judge"); + SetSynonyms("equate"); + SetRules("OBJ to OBJ"); + SetErrorMessage("What two things would you like to equate?"); + SetHelp("Syntax: equate OBJ to OBJ\n\n" + "A bargaining ability which allows people to compare the " + "relative worth of two items. The more experienced you are " + "at bartering, the better chance you have of correctly judging " + "the more valuable item.\n\n" + "See help: item commands"); +} + +mixed can_judge_obj_to_obj() { + if( this_player()->GetLevel() < 6 ) { + this_player()->eventPrint("You are not experienced enough to judge " + "the value of items accurately."); + return 0; + } + return this_player()->CanCastMagic(1, "judge"); +} + + +mixed do_judge_obj_to_obj(object obj1, object obj2) { + int level; + string name1, name2; + object caster = this_player(); + if( !(caster->GetSkillLevel("bargaining")) ) { + return "You do not have the skills to judge items."; } + if (!obj1 || !obj2) return "You must judge one thing vs another."; + if (obj1 == obj2) return "That would do a lot of good!"; + + /* Check for presence of objects */ + name1 = obj1->GetShort(); + name2 = obj2->GetShort(); + + if( environment(obj1) != caster ) { + caster->eventPrint("You do not have "+name1+"."); + return 1; + } + + if( environment(obj2) != caster ) { + caster->eventPrint("You do not have "+name2+"."); + return 1; + } + + level = caster->GetSkillLevel("bargaining"); + caster->eventPrint("You stare intently at "+name1+" and "+name2+"."); + environment(caster)->eventPrint( caster->GetName() + + " concentrates on " + name1 + " and " + name2 + ".", caster); + if( this_player()->GetInCombat() ) + this_player()->SetAttack(0, + (: eventJudge, this_player(), obj1, obj2, level :), + ROUND_OTHER); + else eventJudge(this_player(), obj1, obj2, level); + return 1; +} + + +int eventJudge(object caster, object obj1, object obj2, int level) { + + int obj1lvl, obj2lvl; + string better; + + int cost = random(50) + 50; + + if( !(obj1 && obj2) ) return 0; + if( (environment(obj1) != caster) || (environment(obj2) != caster) ) { + caster->eventPrint("You must have both items in your possesion " + "to compare them."); + return 0; + } + if( cost > caster->GetStaminaPoints() ) { + caster->eventPrint("You are too weary to judge right now."); + environment(caster)->eventPrint( + caster->GetName() + " looks tired.", caster); + return 0; + + } + caster->AddStaminaPoints(-cost); + obj1lvl = obj1->GetValue(); + obj2lvl = obj2->GetValue(); + + if( level < (5 + random(35))) { + + if(random(7)) { + if(random(5) < 2) { + better = obj2->GetShort(); + } + else better = obj1->GetShort(); + caster->eventPrint("%^BOLD%^%^WHITE%^" + "You determine that " + better + "%^BOLD%^%^WHITE%^" + " is the more valuable object.%^RESET%^"); + return 0; + } + else caster->eventPrint("%^BOLD%^%^WHITE%^" + "You determine that these two items are equally valuable." + ".%^RESET%^"); + caster->AddSkillPoints("bargaining",random(25)); + return 1; + } + /* Return the right answer */ + if(obj1lvl == obj2lvl) { + caster->eventPrint("%^BOLD%^%^WHITE%^" + "You determine that these two items are equally valuable." + ".%^RESET%^"); + return 1; + } + if(obj1lvl > obj2lvl) { + better = obj1->GetShort(); + } + else better = obj2->GetShort(); + caster->eventPrint("%^BOLD%^%^WHITE%^" + "You determine that " + better + "%^BOLD%^%^WHITE%^" + " is the more valuable object.%^RESET%^"); + caster->AddSkillPoints("bargaining",random(50)); + return 1; + +} diff --git a/lib/verbs/items/knock.c b/lib/verbs/items/knock.c new file mode 100644 index 0000000..bb3faa1 --- /dev/null +++ b/lib/verbs/items/knock.c @@ -0,0 +1,49 @@ +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("knock"); + SetRules("OBJ", "on OBJ", "STR on OBJ"); + SetSynonyms("rap"); + SetErrorMessage("Knock on what? Or knock what on what?"); + SetHelp("Syntax: \n" + " \n\n" + "Allows you to knock on an object, or perhaps a thing on the " + "object. For example, you might want to " + "\"knock on the window on the wall\", or simply \"knock on door\".\n\n" + "Synonyms: rap"); +} + +mixed can_knock_obj() { + return this_player()->CanManipulate(); +} + +mixed can_knock_on_obj() { + return can_knock_obj(); +} + +mixed can_knock_str_on_obj() { + return this_player()->CanManipulate(); +} + +mixed can_knock_on_str_on_obj() { + return can_knock_str_on_obj(); +} + +mixed do_knock_obj(object target) { + return target->eventKnock(this_player()); +} + +mixed do_knock_on_obj(object target) { + return do_knock_obj(target); +} + +varargs mixed do_knock_str_on_obj(string thing, object target) { + return target->eventKnock(this_player(), remove_article(lower_case(thing))); +} + +varargs mixed do_knock_on_str_on_obj(string thing, object target) { + return do_knock_str_on_obj(thing, target); +} diff --git a/lib/verbs/items/light.c b/lib/verbs/items/light.c new file mode 100644 index 0000000..9ad4992 --- /dev/null +++ b/lib/verbs/items/light.c @@ -0,0 +1,94 @@ +/* /verbs/items/light.c + * from the Dead Souls Mud Library + * a command for lighting things which can be lit + * created by Descartes of Borg 960512 + */ + +#include +#include "include/light.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("light"); + SetRules("OBS", "OBS with OBJ"); + SetErrorMessage("Light what? Or light what with what?"); + SetHelp("Syntax: \n" + " \n\n" + "Using the first syntax, you can light things which " + "do not need another source in order to be lit, like a lamp or " + "a lighter. The second syntax allows you to light objects which " + "require burning sources in order for themselves to be light, " + "like a torch or a camp fire.\n\n" + "See also: extinguish"); +} + +mixed can_light_obj() { + return this_player()->CanManipulate(); +} + +mixed can_light_obj_with_obj() { + return this_player()->CanManipulate(); +} + +mixed do_light_obj(object target) { + return do_light_obs(({ target })); +} + +mixed do_light_obj_with_obj(object target, object source) { + return do_light_obs_with_obj(({ target }), source); +} + +mixed do_light_obs(mixed *targs) { + object *obs; + string tmp; + + if( !sizeof(targs) ) { + this_player()->eventPrint("There is no such thing to be lit."); + return 1; + } + obs = filter(targs, (: objectp :)); + if( !sizeof(obs) ) { + mixed *ua; + + ua = unique_array(targs, (: $1 :)); + foreach(string *list in ua) this_player()->eventPrint(list[0]); + return 1; + } + obs = filter(obs, (: $1->eventLight(this_player()) :)); + if( !sizeof(obs) ) return 1; + tmp = item_list(obs); + this_player()->eventPrint("You light " + tmp + "."); + environment(this_player())->eventPrint(this_player()->GetName() + + " lights " + tmp + ".", + this_player()); + return 1; +} + +mixed do_light_obs_with_obj(mixed *targs, object source) { + object *obs; + string tmp; + if( !sizeof(targs) ) { + this_player()->eventPrint("There is no such thing to be lit."); + return 1; + } + obs = filter(targs, (: objectp :)); + if( !sizeof(obs) ) { + mixed *ua; + + ua = unique_array(targs, (: $1 :)); + foreach(string *list in ua) this_player()->eventPrint(list[0]); + return 1; + } + obs = filter(obs, (: $1->eventLight(this_player(), $(source)) :)); + if( !sizeof(obs) ) return 1; + tmp = item_list(obs); + this_player()->eventPrint("You light " + tmp + " with " + + source->GetShort() + "."); + environment(this_player())->eventPrint(this_player()->GetName() + + " lights " + tmp + " with " + + source->GetShort() + ".", + this_player()); + return 1; +} diff --git a/lib/verbs/items/listen.c b/lib/verbs/items/listen.c new file mode 100644 index 0000000..c426603 --- /dev/null +++ b/lib/verbs/items/listen.c @@ -0,0 +1,79 @@ +/* /verbs/items/listen.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 961014 + * Version: @(#) listen.c 1.1@(#) + * Last modified: 96/10/14 + */ + +#include +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("listen"); + SetRules("", "OBJ", "to OBJ", "to STR on OBJ", "to STR of OBJ"); + SetErrorMessage("Listen to something?"); + SetHelp("Syntax: \n" + " \n\n" + "Without any arguments, this command allowed you to listen " + "to your general surroundings. You may, however, concentrate " + "your listening on any target. If it is making noise and you " + "can hear well, then you will hear any relevant noise it is " + "making.\n\n" + "See also: look, search, smell, touch"); +} + +mixed can_listen() { + if( !environment(this_player()) ) { + return "You are nowhere."; + } + return 1; +} + +mixed can_listen_obj() { + return 1; +} + +mixed can_listen_to_obj() { + return 1; +} + +mixed can_listen_to_str_word_obj() { + return 1; +} + +mixed do_listen() { + mixed val = environment(this_player())->GetListen(); + + if( functionp(val) ) { + if( !(functionp(val) & FP_OWNER_DESTED) ) { + val = evaluate(val, this_player()); + } + else { + val = 0; + } + } + if( !val ) { + val = "You don't hear a thing."; + } + environment(this_player())->eventPrint(this_player()->GetName() + + " puts an ear to the air.", + this_player()); + this_player()->eventPrint(val); + return 1; +} + +mixed do_listen_obj(object ob) { + return ob->eventListen(this_player()); +} + +mixed do_listen_to_obj(object ob) { + return do_listen_obj(ob); +} + +mixed do_listen_to_str_word_obj(string str, object ob) { + return ob->eventListen(this_player(), str); +} diff --git a/lib/verbs/items/load.c b/lib/verbs/items/load.c new file mode 100644 index 0000000..5f88993 --- /dev/null +++ b/lib/verbs/items/load.c @@ -0,0 +1,45 @@ +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("load"); + SetSynonyms("charge", "recharge"); + SetRules("", "OBJ","OBJ with OBJ","OBJ into OBJ","OBJ in OBJ"); + SetErrorMessage("Load something?"); + SetHelp("Syntax: load THING\n" + " load THING on THING\n" + "Synonyms: charge, recharge\n"); +} + +mixed can_load() { + return this_player()->CanManipulate(); +} + +mixed can_load_obj(mixed foo) { + return this_player()->CanManipulate(); +} + +mixed can_load_obj_word_obj(mixed foo) { + return this_player()->CanManipulate(); +} + +mixed do_load() { + write("Load what?"); + return 1; +} + +varargs mixed do_load_obj(mixed foo) { + return foo->eventLoad(); +} + +varargs mixed do_load_obj_word_obj(mixed foo, mixed wort, mixed foo2) { + if(wort == "with"){ + return foo2->eventLoad(this_player(), foo); + } + else { + return foo->eventLoad(this_player(), foo2); + } +} diff --git a/lib/verbs/items/lock.c b/lib/verbs/items/lock.c new file mode 100644 index 0000000..82c9514 --- /dev/null +++ b/lib/verbs/items/lock.c @@ -0,0 +1,49 @@ +/* /verbs/items/lock.c + * from the Dead Souls Mud Library + * lock OBJ with OBJ + * created by Descartes of Borg 951028 + * Version: @(#) lock.c 1.2@(#) + * Last modified: 96/10/15 + */ + +#include +#include "include/lock.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("lock"); + SetRules("OBJ with OBJ","OBJ with STR"); + SetErrorMessage("Lock what with what?"); + SetHelp("Syntax: \n\n" + "The first object is something you wish to lock, like a " + "door or a chest. The second is the key you wish to use to " + "lock it with. If your key is the right key, then " + "lock allows you to lock it.\n\n" + "See also: close, open, pick, unlock"); +} + +varargs mixed can_lock_obj_with_obj(mixed ob1, mixed ob2, + mixed mix1, mixed mix2) { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything."; + } + return this_player()->CanManipulate(); +} + +varargs mixed can_lock_obj_with_str(mixed ob1, mixed ob2, mixed words...) { + object wut = get_object(ob2); + if(wut) ob2 = wut->GetKeyName(); + return can_lock_obj_with_obj(0, 0, words...); +} + +varargs mixed do_lock_obj_with_obj(object target, object key, mixed words...) { + string id; + id = remove_article(lower_case(words[0])); + return target->eventLock(this_player(), id, key); +} + +varargs mixed do_lock_obj_with_str(mixed ob1, mixed ob2, mixed words...) { + return do_lock_obj_with_obj(ob1, (get_object(lower_case(ob2)) || "")); +} diff --git a/lib/verbs/items/look.c b/lib/verbs/items/look.c new file mode 100644 index 0000000..fd2d8c2 --- /dev/null +++ b/lib/verbs/items/look.c @@ -0,0 +1,151 @@ +/* /verbs/items/look.c + * from the Dead Souls Mud Library + * look STR + * look at ITEM + * created by Descartes of Borg 951218 + * Version: @(#) look.c 1.6@(#) + * Last modified: 96/11/14 + */ + +#include +#include +#include +#include "include/look.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("look"); + SetRules("", "STR", "on OBJ", "OBJ", "at STR", "at OBJ", "in OBJ", "inside OBJ", + "at OBJ:v in OBJ", "at OBJ:v inside OBJ", "at OBJ on OBJ", "at STR on OBJ"); + SetErrorMessage("Look at or in something?"); + SetHelp("Syntax: \n" + " \n" + " \n" + " \n" + " \n\n" + "Without any arguments, this command allows you to see a " + "description of the area about you, including what other " + "things are there with you.\n\n" + "If you look at something, then you get a detailed description " + "of the thing at which you are looking. You should be able to " + "look at any thing you see mentioned in the room when you use the " + "look command without arguments. Anything you cannot look at is " + "considered a bug.\n\n" + "See also: peer"); +} + +mixed can_look() { + if( !environment(this_player()) ) return "You are nowhere."; + else return check_light(); +} + +mixed can_look_str(string str, string verb) { + return can_look_at_str(str, verb); +} + +mixed can_look_obj(string verb, string id) { + return can_look_at_obj(verb, id); +} + +mixed can_look_at_str(string str, string verb) { + if( !environment(this_player()) ) return "You are nowhere."; + if( SEASONS_D->GetLong(str) == 0 ) { + //return "There is no " + remove_article(str) + " here."; + } + else { + return check_light(); + } +} + +mixed can_look_at_obj(string verb, string id) { + return check_light(); +} + +mixed can_look_on_obj(string verb, string id) { + return can_look_at_obj(verb, id); +} + +mixed can_look_in_obj(string verb, string id) { + return can_look_inside_obj(verb, id); +} + +mixed can_look_inside_obj(string verb, string id) { + return can_look(); +} + +mixed can_look_at_obj_word_obj(string verb, string targ, string store) { + return can_look(); +} + +mixed can_look_at_obj_on_obj(object targ, object where, string id1, string id2){ + return can_look(); +} + +mixed can_look_at_str_on_obj(string targ, string verb, string id1, string id2){ + return can_look(); +} + + +mixed do_look() { + if(environment(this_player()) && !this_player()->GetInvis() && + !environment(this_player())->GetProperty("meeting room")) + environment(this_player())->eventPrint(this_player()->GetName() + + " looks around.", this_player(), (MSG_ENV|MSG_ANNOYING)); + this_player()->eventDescribeEnvironment(0); + return 1; +} + +varargs mixed do_look_obj(object ob, mixed *args...) { + return do_look_at_obj(ob, args...); +} + +mixed do_look_str(string str) { + return do_look_at_str(str); +} + +varargs mixed do_look_at_obj(object ob, mixed arg) { + if(ob->GetInvis() && !archp(this_player()) && + base_name(ob) != LIB_BASE_DUMMY && !inherits(LIB_BASE_DUMMY,ob) ){ + write("There is no "+arg+" here."); + return 1; + } + return ob->eventShow(this_player()); +} + +varargs mixed do_look_on_obj(object ob, mixed arg){ + return do_look_at_obj(ob, arg); +} + +mixed do_look_at_str(string str) { + //if( SEASONS_D->GetLong(str) == 0 ) { + // return "There is no " + remove_article(str) + " here."; + // } + return SEASONS_D->eventShow(this_player(), + remove_article(lower_case(str))); +} + +mixed do_look_in_obj(object ob, mixed arg){ + return do_look_inside_obj(ob, arg); +} + +mixed do_look_inside_obj(object ob,mixed arg) { + if(ob->GetInvis() && !archp(this_player()) && + base_name(ob) != LIB_BASE_DUMMY && !inherits(LIB_BASE_DUMMY,ob) ){ + return write("There is no "+arg+" here."); + } + return ob->eventShowInterior(this_player()); +} + +mixed do_look_at_obj_word_obj(object target, object storage, mixed arg) { + if(target->GetInvis() && !archp(this_player()) && + base_name(target) != LIB_BASE_DUMMY && !inherits(LIB_BASE_DUMMY,target) ){ + return write("There is no "+arg+" here."); + } + return target->eventShow(this_player()); +} + +varargs mixed do_look_at_str_on_obj(string id, object ob) { + return ob->eventShow(this_player(), remove_article(lower_case(id))); +} diff --git a/lib/verbs/items/move.c b/lib/verbs/items/move.c new file mode 100644 index 0000000..dd436f0 --- /dev/null +++ b/lib/verbs/items/move.c @@ -0,0 +1,33 @@ +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("move"); + SetRules("OBJ", "STR on OBJ"); + SetSynonyms("shove"); + SetErrorMessage("Move what? Or move what on what?"); + SetHelp("Syntax: \n" + " \n\n" + "Allows you to move an object, or perhaps a thing on the " + "object. For example, you might want to " + "\"move the painting on the wall\", or simply \"move carpet\".\n\n" + "Synonyms: shove"); +} + +mixed can_move_obj() { + return 1; +} + +mixed can_move_str_on_obj() { + return 1; +} + +mixed do_move_obj(object target) { + return target->eventManipulate(this_player()); +} + +varargs mixed do_move_str_on_obj(string thing, object target) { + return target->eventManipulate(this_player(), remove_article(lower_case(thing))); +} diff --git a/lib/verbs/items/open.c b/lib/verbs/items/open.c new file mode 100644 index 0000000..35c2376 --- /dev/null +++ b/lib/verbs/items/open.c @@ -0,0 +1,52 @@ +/* /verbs/items/open.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 960115 + * Version: @(#) open.c 1.2@(#) + * Last modified: 96/10/15 + */ + +#include +#include "include/open.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("open"); + SetRules("OBJ", "OBJ with OBJ"); + SetErrorMessage("Open what? Or open what with what?"); + SetHelp("Syntax: \n" + " \n\n" + "Opens a door or chest or some other such object. Some things " + "may be opened by force using items capable of forcing things " + "to open.\n\n" + "See also: close, lock, pick, unlock"); +} + +mixed can_open_obj(string verb, string id) { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything."; + } + return this_player()->CanManipulate(); +} + +mixed can_open_obj_with_obj(string verb, string id1, string id2) { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything."; + } + return this_player()->CanManipulate(); +} + +varargs mixed do_open_obj(object ob, mixed *args...) { + string what; + + what = remove_article(lower_case(args[0])); + return ob->eventOpen(this_player(), what); +} + +varargs mixed do_open_obj_with_obj(object ob, object with, mixed *args...) { + string what; + + what = remove_article(lower_case(args[0])); + return ob->eventOpen(this_player(), what, with); +} diff --git a/lib/verbs/items/pick.c b/lib/verbs/items/pick.c new file mode 100644 index 0000000..576a099 --- /dev/null +++ b/lib/verbs/items/pick.c @@ -0,0 +1,83 @@ +/* /verbs/items/pick.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 951220 + * Version: @(#) pick.c 1.4@(#) + * Last modified: 96/10/15 + */ + +#include +#include +#include "include/pick.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("pick"); + SetRules("STR on OBJ", "STR on OBJ with OBJ", "OBJ"); + SetErrorMessage("You might pick a flower or perhaps pick the lock on " + "something?"); + SetHelp("Syntax: \n" + " \n" + " \n\n" + "Depending on what you are doing, this command captures two " + "different senses of the verb \"pick\". In the first sense, " + ", pick allows you to pick things like flowers or " + "strawberries (not your nose).\n\n" + "The second conext allows you to open locked things without a key. " + "Some tools can help you stealthfully pick a lock, while " + "others may help you pick it through brute force.\n\n" + "See also: close, lock, open, unlock"); +} + +mixed can_pick_obj() { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything."; + } + return this_player()->CanManipulate(); +} + +mixed can_pick_str_on_obj(string str) { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything."; + } + if( this_player()->GetStaminaPoints() < 20 ) { + return "You are too tired."; + } + return this_player()->CanManipulate(); +} + +mixed can_pick_str_on_obj_with_obj(string str) { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything."; + } + if( this_player()->GetStaminaPoints() < 30 ) { + return "You are too tired."; + } + return this_player()->CanManipulate(); +} + +mixed do_pick_obj(object ob, string id) { + return ob->eventPickItem(this_player(), remove_article(lower_case(id))); +} + +mixed do_pick_str_on_obj(string wrd, object ob, mixed *args...) { + wrd = remove_article(lower_case(args[1])); + this_player()->eventPrint("You eye the lock for weaknesses."); + if( this_player()->GetInCombat() ) + this_player()->SetAttack(0, (: $(ob)->eventPick(this_player(), $(wrd)):), + ROUND_OTHER); + else ob->eventPick(this_player(), wrd); + return 1; +} + +mixed do_pick_str_on_obj_with_obj(string wrd, object ob, object tool, + mixed *args...) { + wrd = remove_article(lower_case(args[1])); + this_player()->eventPrint("You eye the lock for weaknesses."); + if( this_player()->GetInCombat() ) + this_player()->SetAttack(0, (: $(ob)->eventPick(this_player(), $(wrd), + $(tool)) :),ROUND_OTHER); + else ob->eventPick(this_player(), wrd, tool); + return 1; +} diff --git a/lib/verbs/items/poison.c b/lib/verbs/items/poison.c new file mode 100644 index 0000000..f059d3a --- /dev/null +++ b/lib/verbs/items/poison.c @@ -0,0 +1,50 @@ +/* /verbs/items/poison.c + * from the Dead Souls Library + * poison + * poison OBJ with OBJ + * created by Blitz@Dead Souls 951020 + * a check for poison uses put in by BillGates 961202 + */ + + + +#include +#include +#include "include/poison.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("poison"); + SetRules("OBJ with OBJ"); + SetErrorMessage("Poison what with what?"); + SetHelp("Syntax: \n\n" + "This command allows you to poison items, provided you " + "have a poisoning agent, and something to poison. The " + "ITEM is the item which you want to poison. The " + "POISON is what you wish to use to poison it with."); +} + +mixed can_poison_obj_with_obj(string verb) { return this_player()->CanManipulate(); } + +mixed do_poison_obj_with_obj(object target, object agent) { + if( this_player()->GetInCombat() ) + this_player()->SetAttack(0, (: eventPoison, this_player(), target, + agent :), ROUND_OTHER); + else eventPoison(this_player(), target, agent); + return 1; +} + +void eventPoison(object who, object target, object agent) { + if( !who ) return; + if( environment(agent) != this_player() ) { + who->eventPrint("You no longer have your poison."); + return; + } + if( !(agent->GetPoisonUses()) ) { + who->eventPrint("Your poison is all used up."); + return; + } + agent->eventSpreadPoison(who, target); +} diff --git a/lib/verbs/items/pour.c b/lib/verbs/items/pour.c new file mode 100644 index 0000000..21fae09 --- /dev/null +++ b/lib/verbs/items/pour.c @@ -0,0 +1,63 @@ + + +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("pour"); + SetRules("from OBJ into OBJ","from OBJ in OBJ", "OBJ in OBJ","OBJ into OBJ","OBJ on OBJ","OBJ onto OBJ","OBJ out","out OBJ"); + SetErrorMessage("Pour what into what?"); + SetHelp("Syntax: pour into \n\n" + "Allows you to pour into a vessel designed for containing a substance."); +} + +mixed can_pour_obj_into_obj(string verb) { return this_player()->CanManipulate(); } + +mixed can_pour_obj_in_obj(string verb) { return this_player()->CanManipulate(); } + +mixed can_pour_obj_onto_obj(string verb) { return this_player()->CanManipulate(); } + +mixed can_pour_obj_on_obj(string verb) { return this_player()->CanManipulate(); } + +mixed can_pour_obj_out(string verb) { return this_player()->CanManipulate(); } + +mixed can_pour_out_obj(string verb) { return this_player()->CanManipulate(); } + +mixed can_pour_from_obj_into_obj(string verb) { return this_player()->CanManipulate(); } + +mixed do_pour_from_obj_into_obj(object from, object to) { + return to->eventPour(this_player(), from); +} + +mixed do_pour_from_obj_in_obj(object from, object to) { + return to->eventPour(this_player(), from); +} + +mixed do_pour_obj_onto_obj(object from, object to) { + return to->eventPour(this_player(), from); +} + +mixed do_pour_obj_on_obj(object from, object to) { + return do_pour_obj_onto_obj(from, to); +} + +mixed do_pour_obj_in_obj(object from, object to) { + return do_pour_obj_onto_obj(from, to); +} + +mixed do_pour_obj_into_obj(object from, object to) { + return do_pour_obj_onto_obj(from, to); +} + +mixed do_pour_obj_out(object from) { + return from->eventEmpty(this_player()); +} + +mixed do_pour_out_obj(object from) { + return from->eventEmpty(this_player()); +} + + + diff --git a/lib/verbs/items/press.c b/lib/verbs/items/press.c new file mode 100644 index 0000000..392fa2a --- /dev/null +++ b/lib/verbs/items/press.c @@ -0,0 +1,40 @@ +/* /verbs/items/press.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 960114 + * Version: @(#) press.c 1.3@(#) + * Last modified: 96/10/18 + */ + +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("press"); + SetRules("OBJ", "STR on OBJ"); + SetSynonyms("push", "poke", "prod"); + SetErrorMessage("Press what? Or press what on what?"); + SetHelp("Syntax: \n" + " \n\n" + "Allows you to press an object, or perhaps a thing on the " + "object. For example, you might want to " + "\"press the button on the wall\", or simply \"press button\".\n\n" + "Synonyms: poke, prod, push"); +} + +mixed can_press_obj() { + return 1; +} + +mixed can_press_str_on_obj() { + return 1; +} + +mixed do_press_obj(object target) { + return target->eventPress(this_player()); +} + +varargs mixed do_press_str_on_obj(string thing, object target) { + return target->eventPress(this_player(), remove_article(lower_case(thing))); +} diff --git a/lib/verbs/items/pull.c b/lib/verbs/items/pull.c new file mode 100644 index 0000000..d126939 --- /dev/null +++ b/lib/verbs/items/pull.c @@ -0,0 +1,41 @@ +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("pull"); + SetRules("OBJ", "STR on OBJ", "STR from OBJ"); + SetSynonyms("yank", "haul", "drag"); + SetErrorMessage("Pull what? Or pull what on what?"); + SetHelp("Syntax: \n" + " \n\n" + "Allows you to pull an object, or perhaps a thing on the " + "object. For example, you might want to " + "\"pull the lever on the wall\", or simply \"pull lever\".\n\n" + "Synonyms: haul, drag, yank"); +} + +mixed can_pull_obj() { + return this_player()->CanManipulate(); +} + +mixed can_pull_str_on_obj() { + return this_player()->CanManipulate(); +} + +mixed can_pull_str_from_obj() { + return this_player()->CanManipulate(); +} + +mixed do_pull_obj(object target) { + return target->eventPull(this_player()); +} + +varargs mixed do_pull_str_on_obj(string thing, object target) { + return target->eventPull(this_player(), remove_article(lower_case(thing))); +} + +varargs mixed do_pull_str_from_obj(string thing, object target) { + return do_pull_str_on_obj(thing, target); +} diff --git a/lib/verbs/items/put.c b/lib/verbs/items/put.c new file mode 100644 index 0000000..bbeede5 --- /dev/null +++ b/lib/verbs/items/put.c @@ -0,0 +1,207 @@ +/* /verbs/items/put.c + * from the Dead Souls Mud Library + * put OBJ in OBJ + * put OBJ into OBJ + * created by Descartes of Borg 950114 + * Version: @(#) put.c 1.2@(#) + * Last modified: 96/12/31 + */ + +#include +#include "include/put.h" + +inherit LIB_VERB; +string *eligible; + +static void create() { + verb::create(); + SetVerb("put"); + SetSynonyms("place", "stick"); + SetRules("OBS in OBJ", "OBS into OBJ", "OBS on OBJ", "OBS onto OBJ", "OBS OBJ", + "WRD WRD in OBJ", "WRD WRD into OBJ", "WRD WRD on OBJ", "WRD WRD onto OBJ"); + SetErrorMessage("Put what where?"); + SetHelp("Syntax: \n" + "Syntax: \n\n" + "Allows you to stick objects into other objects.\n\n" + "Synonyms: place, stick\n\n" + "See also: get, give, drop"); +} + + +mixed can_put_obs_word_obj(object *foo1, string wrd, object foo2) { + if(check_light()) return this_player()->CanManipulate(); + else return 0; +} + +mixed can_put_obs_obj(object *foo1, string wrd, object foo2){ + return can_put_obs_word_obj(foo1, wrd, foo2); +} + +mixed can_put_obj_word_obj(object target, string wrd, object storage) { + object *target_arr; + if(target) target_arr = ({ target }); + return can_put_obs_word_obj(target_arr, wrd, storage); +} + +mixed can_put_obj_obj(object target, string wrd, object storage){ + return can_put_obj_word_obj(target, wrd, storage); +} + +//mixed can_put_wrd_wrd_word_obj(string num, string curr,string wrd, mixed container) { +mixed can_put_wrd_wrd_word_obj(mixed args...) { + int amt; + string num, curr, wrd; + mixed container; + object ob1, ob2; + + num = args[0]; + curr = args[1]; + wrd = args[2]; + container = args[3]; + + ob1 = get_object(num+" "+curr); + ob2 = get_object(implode(args[6..]," ")); + + if(ob1 && ob2) return can_put_obj_word_obj(ob1, wrd, ob2); + + if( !num || !curr ) return 0; + if( (amt = to_int(num)) < 1 ) return "You cannot do that!"; + if( this_player()->GetCurrency(curr) < amt ) + return "You don't have that much " + curr + "."; + if(newbiep(this_player())){ + return "Newbies can't drop money."; + } + if(wrd == "on" || wrd == "onto"){ + if(container && !inherits( LIB_SURFACE, container ) ) return "#That isn't a load-bearing surface."; + } + if(container && container->GetClosed()){ + return "#That's closed."; + } + if(intp(check_light())) return this_player()->CanManipulate(); + else return check_light(); +} + +mixed do_put_obj_word_obj(object what, string wrd, object storage) { + if(storage && storage->GetClosed()){ + write(capitalize(storage->GetShort())+" is closed."); + return 1; + } + if(wrd == "in" || wrd == "into") return storage->eventPutInto(this_player(), what); + if(wrd == "on" || wrd == "onto") return storage->eventPutOnto(this_player(), what); +} + +mixed do_put_obj_obj(object what, object storage){ + string prepo; + if(storage && inherits(LIB_SURFACE,storage)) prepo = "onto"; + else prepo = "into"; + return do_put_obj_word_obj(what, prepo, storage); +} + +mixed do_put_obs_word_obj(mixed *res, string wrd, object storage) { + object *obs; + obs = filter(res, (: objectp :)); + + if( !sizeof(obs) ) { + mixed *ua; + + ua = unique_array(res, (: $1 :)); + foreach(string *lines in ua) { + if(storage && storage->GetClosed()) + write(capitalize(storage->GetShort())+" is closed."); + else write("That doesn't seem possible at the moment."); + return 1; + } + if(storage && storage->GetClosed()) + write(capitalize(storage->GetShort())+" is closed."); + else write("That doesn't seem possible at the moment."); + return 1; + } + if(!sizeof(filter(obs, (: environment($1) == this_player() :)))){ + write("You don't seem to be in possession of that."); + eligible = ({}); + return 1; + } + eligible=filter(obs, (: (!($1->GetWorn()) && environment($1) == this_player()) :)); + if(!sizeof(eligible)){ + write("Remove or unwield items before trying to put them somewhere."); + eligible = ({}); + return 1; + } + if(wrd == "in" || wrd == "into") { + foreach(object ob in eligible) + storage->eventPutInto(this_player(), ob); + } + if(wrd == "on" || wrd == "onto") { + foreach(object ob in eligible) + storage->eventPutOnto(this_player(), ob); + } + eligible = ({}); + return 1; +} + +mixed do_put_obs_obj(mixed *res, object storage){ + string prepo; + if(storage && inherits(LIB_SURFACE,storage)) prepo = "onto"; + else prepo = "into"; + return do_put_obs_word_obj(res, prepo, storage); +} + +//mixed do_put_wrd_wrd_word_obj(string num, string curr, mixed wort, object ob) { +mixed do_put_wrd_wrd_word_obj(mixed args...) { + object pile, env; + int amt; + string num, curr, wort; + mixed container; + object ob, ob1, ob2; + + num = args[0]; + curr = args[1]; + wort = args[2]; + ob = args[3]; + + ob1 = get_object(num+" "+curr); + ob2 = get_object(implode(args[6..]," ")); + + if(ob1 && ob2) return do_put_obj_word_obj(ob1, wort, ob2); + + if(wort == "on") wort = "onto"; + if(wort == "in") wort = "into"; + + if(wort == "onto" && !inherits( LIB_SURFACE, ob ) ) { + write("That isn't a load-bearing surface."); + return 1; + } + if(wort == "into" && inherits( LIB_SURFACE, ob ) ) { + write("That's a surface. Try \"put on\""); + return 1; + } + + if((inherits(LIB_SIT,ob) && sizeof(ob->GetSitters())) || + (inherits(LIB_LIE,ob) && sizeof(ob->GetLiers()))){ + write("There appears to be someone blocking your access."); + return 0; + } + + + amt = to_int(num); + env = environment(this_player()); + pile = new(LIB_PILE); + pile->SetPile(curr, amt); + if( !(pile->eventMove(ob)) || + this_player()->AddCurrency(curr, -amt) == -1 ) { + this_player()->eventPrint("Something prevents your action."); + pile->eventDestruct(); + return 1; + } + this_player()->eventPrint("You put " + amt + " " + curr + + " "+wort+" "+ob->GetShort()+"."); + + environment(this_player())->eventPrint(this_player()->GetName() + + " puts some " + curr + " "+wort+" "+ob->GetShort()+".", + this_player()); + return 1; +} + +mixed eventCheckLight(object who) { + return check_light(who); +} diff --git a/lib/verbs/items/read.c b/lib/verbs/items/read.c new file mode 100644 index 0000000..d1b9b1e --- /dev/null +++ b/lib/verbs/items/read.c @@ -0,0 +1,63 @@ +/* /verbs/items/read.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 960121 + * Version: @(#) read.c 1.2@(#) + * Last modified: 96/10/15 + */ + +#include +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("read"); + SetRules("OBJ", "OBJ at OBJ", "STR in OBJ","STR on OBJ", "STR from OBJ", + "STR of OBJ"); + SetErrorMessage("Read something?"); + SetHelp("Syntax: \n" + " \n" + " \n\n" + "Allows you to read an object with text on it if you have " + "the proper intelligence.\n\n" + "See also: listen, look, search, smell, touch"); +} + +mixed can_read_obj() { + return check_light(); +} + +mixed can_read_obj_at_obj() { + return check_light(); +} + +mixed can_read_str_word_obj() { + return check_light(); +} + +mixed do_read_obj(object ob) { + return ob->eventRead(this_player()); +} + +mixed do_read_obj_at_obj(object ob, object target) { + return ob->eventRead(this_player(), target); +} + +mixed do_read_str_on_obj(string str, object ob) { + if(ob) return ob->eventRead(this_player(), str); +} + +mixed do_read_str_in_obj(string str, object ob) { + if(ob) return ob->eventRead(this_player(), str); +} + +mixed do_read_str_of_obj(string str, object ob) { + return do_read_str_in_obj(str, ob); +} + +//This function courtesy of Manchi +mixed do_read_str_from_obj(string str, object ob) { + return do_read_str_in_obj(str, ob); +} diff --git a/lib/verbs/items/remove.c b/lib/verbs/items/remove.c new file mode 100644 index 0000000..83a3ca1 --- /dev/null +++ b/lib/verbs/items/remove.c @@ -0,0 +1,85 @@ +/* /verbs/items/remove.c + * From the Dead Souls Mud Library + * Allows players to remove armor + * Created by Descartes of Borg 960207 + * Version: @(#) remove.c 1.2@(#) + * Last modified: 97/01/01 + */ + +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("remove"); + SetRules("OBS", "OBS from OBJ", "OBS out of OBJ"); + SetErrorMessage("Remove what?"); + SetHelp("Syntax: \n" + " \n" + " \n\n" + "This verb allows you to remove a piece of armor which you are " + "currently wearing.\n\n" + "The second syntax is simply a synonym for the \"get\" " + "command.\n\n" + "See also: get, wear, wield, unwield"); + SetSynonyms("take off", "unwear"); +} + +mixed can_remove_obj() { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything."; + } + if(intp(check_light())) return this_player()->CanManipulate(); + else return 1; + +} + +mixed can_remove_obj_out_of_obj() { + int light; + + if(intp(check_light())) return this_player()->CanManipulate(); + else return check_light(); +} + +mixed can_remove_obj_from_obj() { + return can_remove_obj_out_of_obj(); +} + +mixed do_remove_obj(object ob) { + return ob->eventUnequip(this_player()); +} + +mixed do_remove_obs(mixed *res) { + object *obs; + + obs = filter(res, (: objectp :)); + if( !sizeof(obs) ) { + mixed *ua; + + ua = unique_array(res, (: $1 :)); + foreach(string *list in ua) + this_player()->eventPrint(list[0]); + return 1; + } + res = (mixed *)obs->eventUnequip(this_player()) - ({ 1 }); + if( !sizeof(res) ) return 1; + else return res[0]; +} + +mixed do_remove_obj_out_of_obj(object targ, object container) { + return container->eventGetFrom(this_player(), ({ targ })); +} + +mixed do_remove_obj_from_obj(object targ, object container) { + return do_remove_obj_out_of_obj(targ, container); +} + +mixed do_remove_obs_out_of_obj(mixed *res, object container) { + return container->eventGetFrom(this_player(), res); +} + +mixed do_remove_obs_from_obj(mixed *res, object container) { + return do_remove_obs_out_of_obj(res, container); +} + diff --git a/lib/verbs/items/ring.c b/lib/verbs/items/ring.c new file mode 100644 index 0000000..b3acc53 --- /dev/null +++ b/lib/verbs/items/ring.c @@ -0,0 +1,58 @@ +/* /verbs/items/ring.c + * From the Dead Souls Mud Library + * Created by Descartes of Borg 961017 + * Version: @(#) ring.c 1.1@(#) + * Last modified: 96/10/17 + */ + +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("ring"); + SetRules("OBJ", "STR on OBJ", "OBJ with OBJ", "STR on OBJ with OBJ"); + SetErrorMessage("Ring what?"); + SetHelp("Syntax: \n" + " \n" + " \n" + " \n\n" + "Allows you to ring things that ring."); +} + +mixed can_ring_obj() { + if( this_player()->GetParalized() > 0 ) { + return "You cannot do anything."; + } + return this_player()->CanManipulate(); +} + +mixed can_ring_str_on_obj() { + return can_ring_obj(); +} + +mixed can_ring_obj_with_obj() { + return can_ring_obj(); +} + +mixed can_ring_str_on_obj_with_obj() { + return can_ring_obj(); +} + +mixed do_ring_obj(object target) { + return target->eventRing(this_player()); +} + +mixed do_ring_str_on_obj(string str, object target) { + return target->eventRing(this_player(), remove_article(lower_case(str))); +} + +mixed do_ring_obj_with_obj(object target, object tool) { + return target->eventRing(this_player(), 0, tool); +} + +mixed do_ring_str_on_obj_with_obj(string str, object target, object tool) { + return target->eventRing(this_player(), remove_article(lower_case(str)), + tool); +} diff --git a/lib/verbs/items/rock.c b/lib/verbs/items/rock.c new file mode 100644 index 0000000..ccd0cff --- /dev/null +++ b/lib/verbs/items/rock.c @@ -0,0 +1,54 @@ +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("rock"); + SetRules("","OBJ", "WRD OBJ", "STR on OBJ"); + SetErrorMessage("Rock what? Or rock what on what?"); + SetHelp("Syntax: \n" + " \n\n" + "Allows you to rock an object, or perhaps a thing on the " + "object. For example, you might want to " + "\"rock the halo\", or simply \"rock in rocking chair\".\n\n" + ""); +} + +mixed can_rock(){ + return 1; +} + +mixed can_rock_obj(){ + return this_player()->CanManipulate(); +} + +mixed can_rock_wrd_obj(){ + return this_player()->CanManipulate(); +} + +mixed can_rock_str_on_obj(){ + return this_player()->CanManipulate(); +} + +mixed do_rock(){ + object furn = this_player()->GetProperty("furniture_object"); + if(furn && objectp(furn)){ + return furn->eventRock(this_player()); + } + write("You rock back and forth."); + say(this_player()->GetCapName()+" rocks back and forth."); + return 1; +} + +mixed do_rock_obj(object target){ + return target->eventRock(this_player()); +} + +mixed do_rock_wrd_obj(string wrd, object target){ + return target->eventRock(this_player()); +} + +varargs mixed do_rock_str_on_obj(string thing, object target){ + return target->eventRock(this_player(), remove_article(lower_case(thing))); +} diff --git a/lib/verbs/items/roll.c b/lib/verbs/items/roll.c new file mode 100644 index 0000000..06ea4df --- /dev/null +++ b/lib/verbs/items/roll.c @@ -0,0 +1,145 @@ +#include +#include + +inherit LIB_VERB; +string globalstr; + +static void create() { + verb::create(); + SetVerb("roll"); + SetRules("OBS","OBS on OBJ","OBS on STR","OBS here","STR","STR on OBJ"); + SetErrorMessage("Roll something?"); + SetHelp("Syntax: roll THING\n" + "roll THING on THING \n" + ""); +} + +mixed can_roll() { + return this_player()->CanManipulate(); +} + +mixed can_roll_obj_here() { + return this_player()->CanManipulate(); +} + +varargs mixed can_roll_obj(mixed arg1, mixed arg2, mixed arg3, mixed arg4) { + return this_player()->CanManipulate(); +} + +varargs mixed can_roll_obj_on_obj(mixed arg1, mixed arg2, mixed arg3, mixed arg4) { + return this_player()->CanManipulate(); +} + +varargs mixed can_roll_obj_on_str(mixed arg1, mixed arg2, mixed arg3, mixed arg4) { + return this_player()->CanManipulate(); +} + +varargs mixed can_roll_str_on_obj(string foo, object where, string arg1, string arg2) { + if(!where && arg2) where = get_object(arg2); + return this_player()->CanManipulate(); +} + +varargs mixed can_roll_str(string foo) { + return this_player()->CanManipulate(); +} + +mixed do_roll() { + return "Roll what?"; +} + +varargs mixed do_roll_obj(mixed arg1, mixed arg2, mixed arg3, mixed arg4) { + return arg1->eventRoll(); +} + +varargs mixed do_roll_obj_here(mixed arg1, mixed arg2, mixed arg3, mixed arg4) { + return arg1->eventRoll(); +} + +varargs mixed do_roll_obj_on_obj(mixed arg1, mixed arg2, mixed arg3, mixed arg4) { + return arg1->eventRoll(arg2); +} + +varargs mixed do_roll_obs(mixed arg1, mixed arg2, mixed arg3, mixed arg4){ + mixed sum; + foreach(object die in arg1){ + if(!sum) sum = die->eventRoll(); + else sum += die->eventRoll(); + } + return arg1[0]->eventResults(sum); +} + +varargs mixed do_roll_obs_here(mixed arg1, mixed arg2, mixed arg3, mixed arg4) { + return do_roll_obs(arg1, arg2); +} + + +varargs mixed do_roll_obs_on_obj(mixed arg1, mixed arg2, mixed arg3, mixed arg4){ + mixed sum; + foreach(object die in arg1){ + if(!sum) sum = die->eventRoll(arg2); + else sum += die->eventRoll(arg2); + } + return arg1[0]->eventResults(sum); +} + +varargs mixed do_roll_obj_on_str(mixed arg1, mixed arg2, mixed arg3, mixed arg4) { + if(arg2 == "floor" || arg2 == "ground" || arg2 == "here") arg2 = environment(this_player()); + else { + write("That's not here."); + return 0; + } + return arg1->eventRoll(arg2); +} + +varargs mixed do_roll_obs_on_str(mixed arg1, mixed arg2, mixed arg3, mixed arg4){ + mixed sum; + foreach(object die in arg1){ + if(!sum) sum = do_roll_obj_on_str(die, arg2); + else sum += do_roll_obj_on_str(die, arg2); + } + return arg1[0]->eventResults(sum); +} + +varargs mixed do_roll_str_on_obj(string foo, object where, string arg1, string arg2) { + object *dice = ({}); + int d1,d2; + mixed sum; + + globalstr = ""; + if(!stringp(foo)) return 0; + if(sscanf(foo,"%dd%d",d1,d2) < 2){ + sscanf(foo,"d%d",d2); + } + if(!d2){ + write("Roll what? Are you sure you have the die?"); + return 0; + } + if(!d1) d1 = 1; + globalstr = "d"+d2; + if(arg2 && !where) where = get_object(arg2, this_player()); + dice = filter(all_inventory(this_player()), (: answers_to(globalstr, $1) :) ); + if(sizeof(dice) < d1){ + write("You seem to lack sufficient dice of that denomination."); + return 0; + } + if(sizeof(dice) > d1){ + dice = dice[0..d1-1]; + } + foreach(object die in dice){ + if(!sum) sum = die->eventRoll(where); + else sum += die->eventRoll(where); + } + + return dice[0]->eventResults(sum); +} + +mixed do_roll_str(string foo) { + object where; + string s1, s2; + + if(sscanf(foo,"%s on %s",s1, s2) == 2){ + where = get_object(s2,this_player()); + foo = s1; + } + return do_roll_str_on_obj(foo,where); +} diff --git a/lib/verbs/items/scratch.c b/lib/verbs/items/scratch.c new file mode 100644 index 0000000..685a13e --- /dev/null +++ b/lib/verbs/items/scratch.c @@ -0,0 +1,48 @@ +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("scratch"); + SetRules("OBJ", "on OBJ", "STR on OBJ"); + SetErrorMessage("Scratch on what? Or scratch what on what?"); + SetHelp("Syntax: \n" + " \n\n" + "Allows you to scratch on an object, or perhaps a thing on the " + "object. For example, you might want to " + "\"scratch on the window on the wall\", or simply \"scratch on door\".\n\n" + "Synonyms: rap"); +} + +mixed can_scratch_obj() { + return 1; +} + +mixed can_scratch_on_obj() { + return can_scratch_obj(); +} + +mixed can_scratch_str_on_obj() { + return 1; +} + +mixed can_scratch_on_str_on_obj() { + return can_scratch_str_on_obj(); +} + +mixed do_scratch_obj(object target) { + return target->eventScratch(this_player()); +} + +mixed do_scratch_on_obj(object target) { + return do_scratch_obj(target); +} + +varargs mixed do_scratch_str_on_obj(string thing, object target) { + return target->eventScratch(this_player(), remove_article(lower_case(thing))); +} + +varargs mixed do_scratch_on_str_on_obj(string thing, object target) { + return do_scratch_str_on_obj(thing, target); +} diff --git a/lib/verbs/items/search.c b/lib/verbs/items/search.c new file mode 100644 index 0000000..9b92463 --- /dev/null +++ b/lib/verbs/items/search.c @@ -0,0 +1,70 @@ +/* /verbs/items/search.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 960121 + * Version: @(#) search.c 1.2@(#) + * Last modified: 96/10/15 + */ + +#include +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("search"); + SetRules("", "OBJ", "STR on OBJ", "STR of OBJ"); + SetErrorMessage("Search something?"); + SetHelp("Syntax: \n" + " \n" + " \n\n" + "Without any arguments, this command allows you to search " + "your general surroundings. You may, however, concentrate " + "your searching on any target.\n\n" + "See also: listen, look, read, smell, touch"); +} + +mixed can_search() { + if( !environment(this_player()) ) { + return "You are nowhere."; + } + return 1; +} + +mixed can_search_obj() { + return 1; +} + + +mixed can_search_str_word_obj() { + return 1; +} + +mixed do_search() { + mixed val = environment(this_player())->GetSearch(); + + if( functionp(val) ) { + if( !(functionp(val) & FP_OWNER_DESTED) ) { + val = evaluate(val, this_player()); + } + else { + val = 0; + } + } + if( !val ) { + val = "You don't find a thing."; + } + environment(this_player())->eventPrint(this_player()->GetName() + + " searches around.", this_player()); + this_player()->eventPrint(val); + return 1; +} + +mixed do_search_obj(object ob) { + return ob->eventSearch(this_player()); +} + +mixed do_search_str_word_obj(string str, object ob) { + return ob->eventSearch(this_player(), str); +} diff --git a/lib/verbs/items/sell.c b/lib/verbs/items/sell.c new file mode 100644 index 0000000..7c8f42c --- /dev/null +++ b/lib/verbs/items/sell.c @@ -0,0 +1,74 @@ +/* /verbs/items/sell.c + * From the Dead Souls Mud Library + * Allows a player to sell stuff to a vendor + * Created by Descartes of Borg 9602?? + * Version: @(#) sell.c 1.2@(#) + * Last modified: 97/01/03 + */ + +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("sell"); + SetRules("OBS to LIV", "LIV OBS"); + SetErrorMessage("Sell what to whom?"); + SetHelp("Syntax: \n\n" + "When in the presence of vendors, you may buy and sell goods " + "which match the type of goods the vendor in question trades in. " + "The \"sell\" command naturally allows you to sell an item " + "to an interested vendor.\n\n" + "See also: ask, sell, vendors"); +} + +mixed can_sell_obj_to_liv() { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything."; + } + return this_player()->CanManipulate(); +} + +mixed can_sell_liv_obs() { + return can_sell_obj_to_liv(); +} + +mixed do_sell_obj_to_liv(object ob, object vendor) { + if(ob->GetWorn()){ + write("Remove or unwield items before trying to sell them."); + return 1; + } + return vendor->eventBuy(this_player(), ({ ob })); +} + +mixed do_sell_liv_obj(object vendor, object item) { + return do_sell_obj_to_liv(item, vendor); +} + +mixed do_sell_obs_to_liv(object array items, object vendor) { + object *obs, *eligible; + + obs = filter(items, (: objectp :)); + if( !sizeof(obs) ) { + mixed array ua; + + ua = unique_array(items, (: $1 :)); + foreach(string array list in ua) { + this_player()->eventPrint(list[0]); + } + return 1; + } + eligible=filter(obs, (: (!($1->GetWorn()) && environment($1) == this_player()) :)); + if(!sizeof(eligible)){ + write("Remove or unwield items before trying to sell them."); + eligible = ({}); + return 1; + } + + return vendor->eventBuy(this_player(), eligible); +} + +mixed do_sell_liv_obs(object vendor, object array items) { + return do_sell_obs_to_liv(items, vendor); +} diff --git a/lib/verbs/items/shake.c b/lib/verbs/items/shake.c new file mode 100644 index 0000000..12ad738 --- /dev/null +++ b/lib/verbs/items/shake.c @@ -0,0 +1,33 @@ +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("shake"); + SetRules("OBJ", "STR on OBJ"); + SetSynonyms("jiggle"); + SetErrorMessage("Shake what? Or shake what on what?"); + SetHelp("Syntax: \n" + " \n\n" + "Allows you to shake an object, or perhaps a thing on the " + "object. For example, you might want to " + "\"shake my magic 8 ball\", or simply \"shake ball\".\n\n" + "Synonyms: jiggle"); +} + +mixed can_shake_obj() { + return this_player()->CanManipulate(); +} + +mixed can_shake_str_on_obj() { + return this_player()->CanManipulate(); +} + +mixed do_shake_obj(object target) { + return target->eventShake(this_player()); +} + +varargs mixed do_shake_str_on_obj(string thing, object target) { + return target->eventShake(this_player(), remove_article(lower_case(thing))); +} diff --git a/lib/verbs/items/shoot.c b/lib/verbs/items/shoot.c new file mode 100644 index 0000000..cc8a6ef --- /dev/null +++ b/lib/verbs/items/shoot.c @@ -0,0 +1,110 @@ +#include + +inherit LIB_VERB; + +mixed can_shoot_obj_with_obj(mixed target,mixed shooter); +mixed can_shoot_obj_at_obj(mixed shooter,mixed target); +varargs mixed do_shoot_obj_at_obj(mixed args...); +varargs mixed do_shoot_obj_with_obj(mixed args...); + +static void create() { + verb::create(); + SetVerb("shoot"); + SetRules("OBJ at OBJ", "OBJ with OBJ", + "OBJ WRD", "OBJ WRD at WRD"); + SetSynonyms("fire", "gat", "gank"); + SetErrorMessage("Shoot what?"); + SetHelp("Syntax: shoot OBJECT at ENEMY\n\n" + "Shoots a target.\n\n"); +} + +varargs mixed eventShoot(mixed device, mixed target, string dir, string whom){ + mixed attackable; + object tmpob, who = this_player(); + + if(!device || !objectp(device) || target == device ){ + write("You can't shoot that with that."); + return 0; + } + if(device->MustCarry() && environment(device) != who) { + write("You are not holding the weapon."); + return 1; + } + if(device->MustWield() && device->GetWorn() == 0 && !creatorp(who)) { + write("You are not wielding the weapon."); + return 1; + } + if((!target || !objectp(target)) && !dir){ + write("It seems that is not a valid target."); + return 0; + } + if(target && !present(target,environment(who)) && + !present(target,environment(device))){ + write("That target is not here."); + return 1; + } + +#if 1 + if(living(target) || target->isDummy()){ + attackable = target->GetAttackable(); + if(!attackable || !intp(attackable) || attackable != 1){ + write("You are unable to shoot "+target->GetShort()+"."); + return 1; + } + } +#endif + return device->eventShoot(who, target, dir, whom); +} + +mixed can_shoot_liv_with_obj(mixed target,mixed shooter){ + return can_shoot_obj_with_obj(target, shooter); +} + +mixed can_shoot_obj_at_liv(mixed shooter,mixed target){ + return can_shoot_obj_at_obj(shooter, target); +} + +mixed can_shoot_obj_with_obj(mixed target,mixed shooter) { + if(intp(check_light())) return this_player()->CanManipulate(); + else return check_light(); +} + +mixed can_shoot_obj_at_obj(mixed shooter,mixed target) { + if(intp(check_light())) return this_player()->CanManipulate(); + else return check_light(); +} + +mixed can_shoot_obj_wrd(mixed shooter,mixed dir) { + if(intp(check_light())) return this_player()->CanManipulate(); + else return check_light(); +} + +mixed can_shoot_obj_wrd_at_wrd(mixed shooter, mixed dir, mixed whom) { + if(intp(check_light())) return this_player()->CanManipulate(); + else return check_light(); +} + +varargs mixed do_shoot_obj_at_liv(object what, object whom) { + return do_shoot_obj_at_obj(what, whom); +} + +varargs mixed do_shoot_liv_with_obj(object whom, object what) { + return do_shoot_obj_at_obj(what, whom); +} + +varargs mixed do_shoot_obj_at_obj(object what, object whom) { + return eventShoot(what, whom); +} + +varargs mixed do_shoot_obj_with_obj(object whom, object what) { + return eventShoot(what, whom); +} + +varargs mixed do_shoot_obj_wrd(object what, string dir) { + return eventShoot(what, 0, dir); +} + +varargs mixed do_shoot_obj_wrd_at_wrd(object what, string dir, string whom) { + return eventShoot(what, 0, dir, whom); +} + diff --git a/lib/verbs/items/show.c b/lib/verbs/items/show.c new file mode 100644 index 0000000..33c2946 --- /dev/null +++ b/lib/verbs/items/show.c @@ -0,0 +1,49 @@ +#include +#include "include/show.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("show"); + SetRules("OBJ LIV", "LIV OBJ", "OBJ to LIV" ); + SetErrorMessage("Show what to whom?"); + SetHelp("Syntax: \n" + " \n" + "This command allows you to show something you have to " + "someone else.\n\n" + "See also: give, drop, get, put"); +} + +mixed can_show_liv_obj() { + return can_show_obj_to_liv(); +} + +mixed can_show_obj_liv(mixed arg1, mixed arg2) { + return can_show_obj_to_liv(); +} + +mixed can_show_obj_to_liv(mixed arg1, mixed arg2) { + return this_player()->CanManipulate(); } + + mixed do_show_liv_obj(object target, object what) { + return do_show_obj_to_liv(what, target); + } + +mixed do_show_obj_liv(object what, object target) { + return do_show_obj_to_liv(what, target); +} + +mixed do_show_obj_to_liv(object what, object target) { + this_player()->eventPrint("You show " + target->GetName() + " " + + what->GetShort() + "."); + target->eventPrint(this_player()->GetName() + " shows you " + + what->GetShort() + "."); + environment(this_player())->eventPrint(this_player()->GetName() + + " shows " + + target->GetName() + + " " + what->GetShort() +".", + ({ this_player(), target })); + what->eventShow(target); + return 1; +} diff --git a/lib/verbs/items/skin.c b/lib/verbs/items/skin.c new file mode 100644 index 0000000..2ab2fda --- /dev/null +++ b/lib/verbs/items/skin.c @@ -0,0 +1,75 @@ +/* /verbs/items/skin.c + * From the Dead Souls Mud Library + * Verb for skinging things + * Created by Descartes of Borg 951030 + * Version: @(#) skin.c 1.2@(#) + * Last modified: 97/01/01 + */ + +#include +#include +#include + +inherit LIB_VERB; + +string skin; + +static void create() { + verb::create(); + SetVerb("skin"); + SetRules("STR with OBJ", "OBJ with OBJ"); + SetErrorMessage("Skin with what? Is there anything in particular to skin?"); + SetHelp("Syntax: \n\n" + "Allows you to skin with skinning tools. Sometimes you may " + "be required to specify what it is you wish to skin. In " + "that case, you can use the thing field to specify what it is " + "you wish to skin.\n\n" + "See also: fillet"); +} + + +static void eventSkin(object who, object tool, object target, object check) { + if( !who || check != environment(who) ) { + return; + } + if( !tool || (environment(tool) != who) ) { + who->eventPrint("You have lost your equipment."); + return; + } + skin = target->GetSkin(); + if(skin){ + // write( "You Skin a " + object->GetShort() + " with a " + tool->GetShort() + "."); + new(skin)->eventMove(environment(who)); + } +} + +varargs static void eventPrepareSkin(object who, object tool, object what) { + function f = (: eventSkin($(who), $(tool), $(what), environment($(who))) :); + if( this_player()->GetInCombat() ) { + send_messages("start", "$agent_name $agent_verb to skin with " + + tool->GetShort() + ".", who, 0, environment(who)); + who->SetAttack(0, f, ROUND_OTHER); + } + else { + evaluate(f); + } +} + +mixed can_skin_with_obj(object tool) { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything!"; + } + if( this_player()->GetPosition() != POSITION_STANDING ) { + return "skin when you are not standing?"; + } + return this_player()->CanManipulate(); +} + +mixed can_skin_obj_with_obj(object corpse, object tool) { + return can_skin_with_obj(tool); +} + +mixed do_skin_obj_with_obj(object what, object ob, string id) { + eventPrepareSkin(this_player(), ob, what); + return 1; +} diff --git a/lib/verbs/items/smell.c b/lib/verbs/items/smell.c new file mode 100644 index 0000000..dcf8962 --- /dev/null +++ b/lib/verbs/items/smell.c @@ -0,0 +1,70 @@ +/* /verbs/items/smell.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 960121 + * Version: @(#) smell.c 1.2@(#) + * Last modified: 96/10/15 + */ + +#include +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("smell"); + SetRules("", "OBJ", "STR on OBJ", "STR of OBJ"); + SetErrorMessage("Smell something?"); + SetHelp("Syntax: \n" + " \n" + " \n\n" + "Without any arguments, this command allows you to smell " + "your general surroundings. You may, however, concentrate " + "your smelling on any target.\n\n" + "See also: listen, look, read, search, touch"); +} + +mixed can_smell() { + if( !environment(this_player()) ) { + return "You are nowhere."; + } + return 1; +} + +mixed can_smell_obj() { + return 1; +} + + +mixed can_smell_str_word_obj() { + return 1; +} + +mixed do_smell() { + mixed val = environment(this_player())->GetSmell(); + + if( functionp(val) ) { + if( !(functionp(val) & FP_OWNER_DESTED) ) { + val = evaluate(val, this_player()); + } + else { + val = 0; + } + } + if( !val ) { + val = "You don't smell a thing."; + } + environment(this_player())->eventPrint(this_player()->GetName() + + " smells around.", this_player()); + this_player()->eventPrint(val); + return 1; +} + +mixed do_smell_obj(object ob) { + return ob->eventSmell(this_player()); +} + +mixed do_smell_str_word_obj(string str, object ob) { + return ob->eventSmell(this_player(), str); +} diff --git a/lib/verbs/items/smoke.c b/lib/verbs/items/smoke.c new file mode 100644 index 0000000..3d299f3 --- /dev/null +++ b/lib/verbs/items/smoke.c @@ -0,0 +1,42 @@ +#include +#include + +inherit LIB_VERB; + +varargs void eventSmoke(object who, object what, string id); + +static void create() { + verb::create(); + SetVerb("smoke"); + SetRules("OBJ", "from OBJ"); + SetErrorMessage("Smoke what?"); + SetHelp("Syntax: \n" + " \n\n" + "Allows you to smoke a smokable item.\n" + "See also: pack"); + SetSynonyms("puff"); +} + +mixed can_smoke_obj(string verb) { return this_player()->CanManipulate(); } + +mixed can_smoke_from_obj(string verb) { return this_player()->CanManipulate(); } + +mixed do_smoke_obj(object ob) { + if( this_player()->GetInCombat() ) + this_player()->SetAttack(0, (: eventSmoke, this_player(), ob :), + ROUND_OTHER); + else eventSmoke(this_player(), ob); + return 1; +} + +mixed do_smoke_from_obj(object ob, string id) { + if( this_player()->GetInCombat() ) + this_player()->SetAttack(0, (: eventSmoke, this_player(), ob, id :), + ROUND_OTHER); + else eventSmoke(this_player(), ob, id); + return 1; +} + +varargs void eventSmoke(object who, object what, string id) { + return what->eventSmoke(who, what); +} diff --git a/lib/verbs/items/steal.c b/lib/verbs/items/steal.c new file mode 100644 index 0000000..02a9dc3 --- /dev/null +++ b/lib/verbs/items/steal.c @@ -0,0 +1,118 @@ +/* /verbs/items/steal.c + * from the Dead Souls Mud Library + * steal WRD from LIV + * steal OBJ from LIV + * created by Descartes of Borg 951218 + */ + + + +#include +#include +#include "include/steal.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("steal"); + SetRules("OBJ from LIV", "WRD from LIV", "OBS from LIV"); + SetErrorMessage("Steal what from whom?"); + SetHelp("Syntax: \n" + " \n" + " \n\n" + "Uses your stealing abilities to rob another of items or money. " + "Items are much harder to steal than money, and trying to steal " + "multiple items in one shot is dangerous."); +} + +mixed can_steal_wrd_from_liv(string wrd) { + if( wrd != "money" ) return 0; + if( this_player()->GetSkillLevel("stealing") < 1 ) + return "You are not skillful enough at stealing."; + if( environment(this_player())->GetProperty("no steal") ) + return "Mystical forces prevent your thievery."; + if( this_player()->GetStaminaPoints() < 10 ) + return "You are too tired for such skullduggery."; + if(intp(check_light())) return this_player()->CanManipulate(); + else return check_light(); +} + +mixed can_steal_obj_from_liv() { + if( this_player()->GetSkillLevel("stealing") < 1 ) + return "You are not skillful enough at stealing."; + if( environment(this_player())->GetProperty("no steal") ) + return "Mystical forces prevent your thievery."; + if( this_player()->GetStaminaPoints() < 20 ) + return "You are too tired for such skullduggery."; + if(intp(check_light())) return this_player()->CanManipulate(); + else return check_light(); +} + +mixed do_steal_wrd_from_liv(string wrd, object liv) { + this_player()->eventPrint("You eye " + liv->GetName() + + " with thoughts on " + possessive(liv) + + " pockets."); + if( this_player()->GetInCombat() ) + this_player()->SetAttack(0, (: eventSteal,this_player(), "money", liv :), + ROUND_OTHER); + else eventSteal(this_player(), "money", liv); + return 1; +} + +mixed do_steal_obj_from_liv(object item, object liv) { + if(!item) return "That's not here."; + if( environment(item) != liv ) { + this_player()->eventPrint(liv->GetName() + " does not have that."); + return 1; + } + if(item->GetProperty("no steal")){ + this_player()->eventPrint("that item cannot be stolen."); + return 1; + } + this_player()->eventPrint("You eye " + liv->GetName() + + " with thoughts on " + possessive(liv) + " " + + remove_article(item->GetShort()) + "."); + if( this_player()->GetInCombat() ) + this_player()->SetAttack(0, (: eventSteal, this_player(), ({ item }), + liv :), ROUND_OTHER); + else eventSteal(this_player(), ({ item }), liv); + return 1; +} + +mixed do_steal_obs_from_liv(mixed *res, object liv) { + object *obs; + + obs = filter(res, (: objectp :)); + if( !sizeof(obs) ) { + mixed *ua; + + ua = unique_array(res, (: $1 :)); + foreach(mixed *lines in ua) this_player()->eventPrint(lines[0]); + return 1; + } + + foreach(mixed thing in res){ + if(objectp(thing) && thing->GetProperty("no steal")){ + this_player()->eventPrint("One of those items cannot be stolen, causing "+ + "you to be distracted from stealing any of the others."); + return 1; + } + } + this_player()->eventPrint("You eye " + liv->GetName() + + " with thoughts on " + possessive(liv) + + " possessions."); + if( this_player()->GetInCombat() ) + this_player()->SetAttack(0, (: eventSteal, this_player(), obs, liv :), + ROUND_OTHER); + else eventSteal(this_player(), obs, liv); + return 1; +} + +static void eventSteal(object who, mixed what, object target) { + if(objectp(what) && what->GetProperty("no steal")){ + write("That item cannot be stolen."); + return; + } + who->eventSteal(who, what, target); +} diff --git a/lib/verbs/items/strike.c b/lib/verbs/items/strike.c new file mode 100644 index 0000000..a5bc946 --- /dev/null +++ b/lib/verbs/items/strike.c @@ -0,0 +1,24 @@ +#include +#include "include/strike.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("strike"); + SetRules("OBJ"); + SetErrorMessage("Strike what?"); + SetHelp("Syntax: \n\n" + "Certain objects are flammable simply by striking them. " + "When you strike such objects, they have a chance of " + "catching fire and burning.\n\n" + "See also: burn, douse, light"); +} + +mixed can_strike_obj() { + return this_player()->CanManipulate(); +} + +mixed do_strike_obj(object ob) { + return ob->eventStrike(this_player()); +} diff --git a/lib/verbs/items/swivel.c b/lib/verbs/items/swivel.c new file mode 100644 index 0000000..5a7e40a --- /dev/null +++ b/lib/verbs/items/swivel.c @@ -0,0 +1,55 @@ +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("swivel"); + SetRules("","OBJ", "WRD OBJ", "STR on OBJ"); + SetSynonyms("spin"); + SetErrorMessage("Swivel what? Or swivel what on what?"); + SetHelp("Syntax: \n" + " \n\n" + "Allows you to swivel an object, or perhaps a thing on the " + "object. For example, you might want to " + "\"swivel the gimbal\", or simply \"swivel in chair\".\n\n" + "Synonyms: spin"); +} + +mixed can_swivel(){ + return 1; +} + +mixed can_swivel_obj(){ + return this_player()->CanManipulate(); +} + +mixed can_swivel_wrd_obj(){ + return this_player()->CanManipulate(); +} + +mixed can_swivel_str_on_obj(){ + return this_player()->CanManipulate(); +} + +mixed do_swivel(){ + object furn = this_player()->GetProperty("furniture_object"); + if(furn && objectp(furn)){ + return furn->eventSwivel(this_player()); + } + write("You swivel to and fro."); + say(this_player()->GetCapName()+" swivels to and fro."); + return 1; +} + +mixed do_swivel_obj(object target){ + return target->eventSwivel(this_player()); +} + +mixed do_swivel_wrd_obj(string wrd, object target){ + return target->eventSwivel(this_player()); +} + +varargs mixed do_swivel_str_on_obj(string thing, object target){ + return target->eventSwivel(this_player(), remove_article(lower_case(thing))); +} diff --git a/lib/verbs/items/throw.c b/lib/verbs/items/throw.c new file mode 100644 index 0000000..5ad307e --- /dev/null +++ b/lib/verbs/items/throw.c @@ -0,0 +1,85 @@ +/* /verbs/items/throw.c + * from the NIghtmare IVr2 Object Library + * created by Descartes of Borg 951029 + * Version: @(#) throw.c 1.3@(#) + * Last modified: 96/10/20 + */ + +#include +#include + +inherit LIB_VERB; + +mixed do_throw_obj_word_obj(object what, string word, object where); +void eventThrow(object who, object what, object where); + +static void create() { + verb::create(); + SetVerb("throw"); + SetSynonyms("toss"); + SetRules("OBJ", "OBJ at OBJ", "OBJ into OBJ"); + SetErrorMessage("Throw what?"); + SetHelp("Syntax: \n" + " \n" + " \n\n" + "Allows you to throw an object. Some object you may also " + "use offensively by throwing them. Other places may simply " + "allow you to throw objects into them, say like throwing " + "equipment down to a friend in a chasm.\n" + "Note that throwing a weapon at someone will initiate " + "combat.\n\n" + "Synonyms: toss"); +} + +mixed can_throw_obj() { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything."; + } + if(intp(check_light())) return this_player()->CanManipulate(); + else return check_light(); +} + +mixed can_throw_obj_word_obj() { + return can_throw_obj(); +} + +mixed do_throw_obj(object ob) { + return do_throw_obj_word_obj(ob, 0, 0); +} + +mixed do_throw_obj_word_obj(object what, string word, object where) { + object enemy; + object env = environment(this_player()); + if( where && living(where) && what->GetClass() > 1 ) { + enemy = where; + } + else { + enemy = 0; + } + if(env && env->GetProperty("no attack")){ + write("A mystical force prevents your malice."); + return 1; + } + if( this_player()->GetInCombat() || enemy ) { + this_player()->eventPrint("You prepare to throw " + + what->GetShort() + "."); + this_player()->SetAttack(enemy, (: eventThrow, this_player(), what, + where :), (enemy ? ROUND_WEAPON : + ROUND_OTHER)); + return 1; + } + eventThrow(this_player(), what, where); + return 1; +} + +void eventThrow(object who, object what, object where) { + + if( !who ) { + return; + } + if( !what || environment(what) != who ) { + who->eventPrint("You no longer have anything to throw."); + return; + } + what->eventThrow(who, where); +} diff --git a/lib/verbs/items/touch.c b/lib/verbs/items/touch.c new file mode 100644 index 0000000..38a1797 --- /dev/null +++ b/lib/verbs/items/touch.c @@ -0,0 +1,41 @@ +/* /verbs/items/touch.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 961014 + * Version: @(#) touch.c 1.1@(#) + * Last modified: 96/10/15 + */ + +#include +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("touch"); + SetRules("OBJ", "STR on OBJ", "STR of OBJ"); + SetErrorMessage("Touch something?"); + SetHelp("Syntax: \n" + " \n\n" + "This command allows you to touch an object to get an idea " + "of any special textural properties it may have.\n\n" + "See also: listen, look, read, search, smell"); +} + +mixed can_touch_obj() { + return 1; +} + + +mixed can_touch_str_word_obj() { + return 1; +} + +mixed do_touch_obj(object ob) { + return ob->eventTouch(this_player()); +} + +mixed do_touch_str_word_obj(string str, object ob) { + return ob->eventTouch(this_player(), str); +} diff --git a/lib/verbs/items/turn.c b/lib/verbs/items/turn.c new file mode 100644 index 0000000..dc8810c --- /dev/null +++ b/lib/verbs/items/turn.c @@ -0,0 +1,79 @@ +/* /verbs/items/turn.c + * from the Frontiers Object Library + * turn STR + * turn on ITEM + * etc + */ + +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("turn"); + SetRules("", "OBJ", "on OBJ", "off OBJ", "OBJ on", "OBJ off"); + SetErrorMessage("Turn on or turn off something?"); + SetHelp("Syntax: \n" + " \n" + " \n" + " \n" + " \n\n" + ""); +} + +mixed can_turn() { + return this_player()->CanManipulate(); +} + +mixed can_turn_obj(mixed foo) { + return this_player()->CanManipulate(); +} + +mixed can_turn_on_obj(mixed foo) { + return this_player()->CanManipulate(); +} + +mixed can_turn_off_obj(mixed foo) { + return this_player()->CanManipulate(); +} + +mixed can_turn_obj_on(mixed foo) { + return this_player()->CanManipulate(); +} + +mixed can_turn_obj_off(mixed foo) { + return this_player()->CanManipulate(); +} + +mixed do_turn() { + environment(this_player())->eventPrint(this_player()->GetName() + + " turns around.", this_player()); + this_player()->eventPrint("You turn around."); + return 1; +} + +varargs mixed do_turn_obj(mixed foo, mixed foo2) { + return foo->eventTurn(); +} + +varargs mixed do_turn_on_obj(mixed foo, mixed foo2) { + return foo->eventTurnOn(); +} + +mixed do_turn_off_obj(mixed foo) { + return foo->eventTurnOff(); +} + +varargs mixed do_turn_obj_on(mixed foo, mixed foo2) { + return foo->eventTurnOn(); +} + +mixed do_turn_obj_off(mixed foo) { + return foo->eventTurnOff(); +} + +mixed do_turn_on_obj_word_obj(mixed foo, mixed foo2) { + return foo2->eventTurnOn(foo); +} diff --git a/lib/verbs/items/uninstall.c b/lib/verbs/items/uninstall.c new file mode 100644 index 0000000..d63b8a8 --- /dev/null +++ b/lib/verbs/items/uninstall.c @@ -0,0 +1,40 @@ +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("uninstall"); + SetRules("OBJ","OBJ from OBJ","OBJ in OBJ","OBJ on OBJ"); + SetErrorMessage("Uninstall something?"); + SetHelp("Syntax: uninstall THING\n" + " uninstall THING from THING\n" + ""); +} + +mixed can_uninstall() { + return this_player()->CanManipulate(); +} + +mixed can_uninstall_obj(mixed foo) { + return this_player()->CanManipulate(); +} + +mixed can_uninstall_obj_word_obj(mixed foo...) { + return this_player()->CanManipulate(); +} + +mixed do_uninstall() { + write("Uninstall what?"); + return 1; +} + +varargs mixed do_uninstall_obj(mixed foo) { + write("Uninstall what from where?"); + return 1; +} + +varargs mixed do_uninstall_obj_word_obj(mixed foo, mixed foo2, mixed foo3) { + return foo->eventUninstall(foo3); +} diff --git a/lib/verbs/items/unload.c b/lib/verbs/items/unload.c new file mode 100644 index 0000000..3bbe7a0 --- /dev/null +++ b/lib/verbs/items/unload.c @@ -0,0 +1,40 @@ +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("unload"); + SetSynonyms("discharge","deplete"); + SetRules("OBJ","OBJ from OBJ","OBJ in OBJ","OBJ on OBJ", "OBJ out of OBJ"); + SetErrorMessage("Unload something?"); + SetHelp("Syntax: unload THING\n" + " unload THING from THING\n" + "Synonyms: discharge, deplete\n"); +} + +mixed can_unload() { + return this_player()->CanManipulate(); +} + +mixed can_unload_obj(mixed foo) { + return this_player()->CanManipulate(); +} + +mixed can_unload_obj_word_obj(mixed foo) { + return this_player()->CanManipulate(); +} + +mixed do_unload() { + return "Unload what?"; + return 1; +} + +varargs mixed do_unload_obj(mixed foo) { + return foo->eventUnload(foo); +} + +varargs mixed do_unload_obj_word_obj(mixed foo, mixed foo2, mixed foo3) { + return foo->eventUnload(foo3); +} diff --git a/lib/verbs/items/unlock.c b/lib/verbs/items/unlock.c new file mode 100644 index 0000000..3590542 --- /dev/null +++ b/lib/verbs/items/unlock.c @@ -0,0 +1,47 @@ +/* /verbs/items/unlock.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 951028 + * Version: @(#) unlock.c 1.3@(#) + * Last modified: 97/01/02 + */ + +#include +#include "include/unlock.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("unlock"); + SetRules("OBJ with OBJ", "OBJ with STR"); + SetErrorMessage("Unlock what with what?"); + SetHelp("Syntax: \n\n" + "The first object is something you wish to unlock, like a " + "door or a chest. The second is the key you wish to use to " + "unlock it with. If your key is the right key, then " + "unlock allows you to unlock it.\n\n" + "See also: close, lock, open, pick"); +} + +varargs mixed can_unlock_obj_with_obj(object foo, object bar, + mixed words...) { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything."; + } + return this_player()->CanManipulate(); +} + +varargs mixed can_unlock_obj_with_str(mixed ob1, mixed ob2, mixed words...) { + object wut = get_object(ob2); + if(wut) ob2 = wut->GetKeyName(); + return can_unlock_obj_with_obj(ob1, ob2, words[1], ob2); +} + +varargs mixed do_unlock_obj_with_obj(object ob1, object ob2, mixed args...) { + return ob1->eventUnlock(this_player(), ob2); +} + +varargs mixed do_unlock_obj_with_str(mixed ob1, mixed ob2, mixed words...) { + return do_unlock_obj_with_obj(ob1, (get_object(lower_case(ob2)) || "")); +} + diff --git a/lib/verbs/items/unwield.c b/lib/verbs/items/unwield.c new file mode 100644 index 0000000..ece852a --- /dev/null +++ b/lib/verbs/items/unwield.c @@ -0,0 +1,56 @@ +/* /verbs/items/unwield.c + * From the Dead Souls Mud Library + * Allows players to stop wielding a weapon + * Created by Descartes of Borg 960207 + * Version: @(#) unwield.c 1.2@(#) + * Last modified: 97/01/01 + */ + +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("unwield"); + SetRules("OBS"); + SetErrorMessage("Unwield what?"); + SetHelp("Syntax: \n" + " \n\n" + "This verb allows you to unwield a weapon which you are " + "currently wielding.\n\n" + "See also: get, remove, wear, wield"); +} + +mixed can_unwield_obj(string verb) { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything."; + } + return 1; +} + +mixed do_unwield_obj(object ob) { + return ob->eventUnequip(this_player()); +} + +mixed do_unwield_obs(mixed array targs) { + object array obs; + + if( !sizeof(targs) ) { + this_player()->eventPrint("There is no such thing to be unwielded."); + return 1; + } + obs = filter(targs, (: objectp :)); + if( !sizeof(obs) ) { + mapping messages = unique_mapping(targs, (: $1 :)); + + foreach(string msg in keys(messages)) { + this_player()->eventPrint(msg); + } + return 1; + } + foreach(object item in obs) { + do_unwield_obj(item); + } + return 1; +} diff --git a/lib/verbs/items/use.c b/lib/verbs/items/use.c new file mode 100644 index 0000000..cc9d77b --- /dev/null +++ b/lib/verbs/items/use.c @@ -0,0 +1,37 @@ +#include +#include "include/use.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("use"); + SetRules("OBJ", "OBJ to STR"); + SetErrorMessage("Use what to do what?"); + SetHelp("Syntax: use OBJ to CMD\n\n" + "Certain objects, like scrolls, allow you to perform acts beyond " + "your naturaly abilities. Of course, the only way to know if an " + "object can so empower you is either to try it or to somehow " + "detect its magic.\n\n" + "See also: detect, discern"); +} + +mixed can_use_obj(mixed args...){ + return 1; +} + +mixed can_use_obj_to_str(mixed args...){ + return 1; +} + +mixed do_use_obj_to_str(object ob, string str) { + if(!ob){ + write("That's not here."); + return 1; + } + return ob->eventUse(this_player(), str); +} + +mixed do_use_obj(object ob) { + return do_use_obj_to_str(ob, 0); +} diff --git a/lib/verbs/items/wear.c b/lib/verbs/items/wear.c new file mode 100644 index 0000000..7c4548b --- /dev/null +++ b/lib/verbs/items/wear.c @@ -0,0 +1,71 @@ +/* /verbs/items/wear.c + * From the Dead Souls Mud Library + * Allows a player to wear armor + * Created by Descartes of Borg 951020 + * Version: @(#) wear.c 1.2@(#) + * Last modified: 97/01/01 + */ + +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("wear"); + SetRules("OBS", "OBJ on STR"); + SetErrorMessage("Wear what? When in doubt, specify a limb to " + "wear it on."); + SetHelp("Syntax: \n" + " \n\n" + "Allows you to take an article of clothing and wear it. Some " + "bits of clothing may be worn in a variety of places, and thus " + "require you to specify where it is they should be worn. For " + "example, a shield could be worn with either the right hand or " + "left hand. So you would type, \"wear shield on right hand\".\n\n" + "See also: wield"); +} + +mixed can_wear_obj() { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything."; + } + return this_player()->CanManipulate(); +} + +mixed can_wear_obj_on_str(string str) { + return can_wear_obj(); +} + +mixed do_wear_obj(object ob) { + return ob->eventEquip(this_player(), ob->GetRestrictLimbs()); +} + +mixed do_wear_obj_on_str(object ob, string str) { + return ob->eventEquip(this_player(), + ({ remove_article(lower_case(str)) })); +} + +mixed do_wear_obs(object array armors) { + object array obs; + + if( !sizeof(armors) ) { + this_player()->eventPrint("There is no such thing to be worn."); + return 1; + } + obs = filter(armors, (: objectp :)); + if( !sizeof(obs) ) { + mixed array ua; + + ua = unique_array(armors, (: $1 :)); + foreach(string array list in ua) { + this_player()->eventPrint(list[0]); + } + return 1; + } + foreach(object armor in obs) { + do_wear_obj(armor); + } + return 1; +} diff --git a/lib/verbs/items/weigh.c b/lib/verbs/items/weigh.c new file mode 100644 index 0000000..7d54159 --- /dev/null +++ b/lib/verbs/items/weigh.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include "include/weigh.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("weigh"); + SetRules("OBJ"); + SetErrorMessage("What would you like to weigh?"); + SetHelp("Syntax: weigh OBJ\n\n" + "A general estimate of how much a thing weighs." + ""); +} + +mixed can_weigh_obj() { + return 1; +} + +mixed do_weigh_obj(object obj) { + string name, verb = "heft"; + if(!obj) return "You must weigh something."; + + /* Check for presence of objects */ + name = obj->GetShort(); + if( environment(obj) != this_player() ) { + this_player()->eventPrint("You do not have "+name+"."); + return 1; + } + + if(obj->GetWorn()) verb = "get a feel for"; + + this_player()->eventPrint("You stare intently at " + name + " and " + + verb + " it."); + environment(this_player())->eventPrint( this_player()->GetName() + + " looks at " + name + ".", this_player()); + if( this_player()->GetInCombat() ) + this_player()->SetAttack(0, + (: eventWeigh, this_player(), obj :), + ROUND_OTHER); + else eventWeigh(this_player(), obj); + return 1; +} + +int eventWeigh(object who, object obj){ + int ret, max, curr, cost, diff; + float tmp, error; + string ret_str, name; + if( !(obj) ) return 0; + name = obj->GetShort(); + cost = random(3) + 1; + max = who->GetMaxStaminaPoints(); + curr = who->GetStaminaPoints(); + diff = max - curr; + if(diff > 0) error = to_float(random(percent(diff, curr))); + else diff = 0; + if((environment(obj) != who)){ + who->eventPrint("You must have the item in your possession " + "to weigh it."); + return 0; + } + if(cost > who->GetStaminaPoints()){ + who->eventPrint("You are too weary to weigh right now."); + environment(who)->eventPrint( + who->GetName() + " looks tired.", who); + return 0; + } + who->AddStaminaPoints(-cost); + ret = obj->GetWeight(); + tmp = to_float(ret) * (error * 0.01); + ret += to_int(tmp); + ret /= 100; + if(ret < 1) ret_str = "less than one pound."; + else if(ret < 2) ret_str = "about one pound."; + else ret_str = "about " + cardinal(ret) + " pounds."; + write("You make a rough estimate that " + name + " weighs " + + ret_str); + return 1; +} diff --git a/lib/verbs/items/wield.c b/lib/verbs/items/wield.c new file mode 100644 index 0000000..48e9a76 --- /dev/null +++ b/lib/verbs/items/wield.c @@ -0,0 +1,125 @@ +/* /verbs/items/wield.c + * From the Dead Souls Mud Library + * The command to allow people to wield weapons + * Created by Descartes of Borg 951018 + * Version: @(#) wield.c 1.2@(#) + * Last modified: 97/01/01 + */ + +#include + +inherit LIB_VERB; + +string array GetFreeLimbs(object who) { + string array limbs = who->GetWieldingLimbs(); + + limbs = filter(limbs, (: !$(who)->GetWielded($1) :)); + return limbs; +} + +static void create() { + verb::create(); + SetVerb("wield"); + SetRules("OBS", "OBS in STR", "OBS with STR"); + SetErrorMessage("Wield what? Perhaps you mean to specify in which " + "limbs?"); + SetHelp( + "Syntax: \n" + " \n" + " \n" + " \n" + "\n" + "This command sets the weapon you name to be wielded in the " + "limb you specify.\n\n" + "Note that a limb can be a single limb, or a list of limbs " + "separated by a comma, or the word \"and\", depending on " + "how many limbs are required for wielding the weapon. For " + "example:\n" + "\twield the rusty sword with my right hand and left hand\n" + "\twield the artrell sword with first hand, second hand, and " + "third hand\n" + "\n" + "See also: wear"); +} + +mixed can_wield_obj() { + if( !sizeof(this_player()->GetWieldingLimbs()) ) { + return "You have no limbs with which to wield!"; + } + if( this_player()->GetParalyzed() ) { + return "You cannot do anything"; + } + return 1; +} + +mixed can_wield_obj_word_str() { + return can_wield_obj(); +} + +mixed do_wield_obj(object ob) { + string array limbs = GetFreeLimbs(this_player()); + int hands = ob->GetHands(); + + if(ob->GetEquipped()) + return write("You're already wielding it!"); + + if( hands < sizeof(limbs) ) { + limbs = limbs[0..(hands-1)]; + } + else if( hands > sizeof(limbs) ) { + return write("You're out of limbs to wield with!"); + } + return ob->eventEquip(this_player(), limbs); +} + +mixed do_wield_obj_word_str(object ob, string word, string str) { + return ob->eventEquip(this_player(), explode_list(str)); +} + +mixed do_wield_obs(mixed array targs) { + object array obs; + + if( !sizeof(targs) ) { + this_player()->eventPrint("There is no such thing to be wielded."); + return 1; + } + obs = filter(targs, (: objectp :)); + if( !sizeof(obs) ) { + mapping messages = unique_mapping(targs, (: $1 :)); + + foreach(string msg in keys(messages)) { + this_player()->eventPrint(msg); + } + return 1; + } + foreach(object item in obs) { + string array limbs = GetFreeLimbs(this_player()); + int hands = item->GetHands(); + + if( sizeof(limbs) < hands ) { + this_player()->eventPrint("You don't have anywhere to wield " + + item->GetDefiniteShort() + "."); + } + else { + mixed tmp; + + if( hands < sizeof(limbs) ) { + limbs = limbs[0..(hands-1)]; + } + tmp = item->CanEquip(this_player(), limbs); + if( tmp != 1 ) { + if( !tmp ) { + this_player()->eventPrint("You cannot wield " + + item->GetDefiniteShort() + "."); + } + else { + this_player()->eventPrint(tmp); + } + } + else { + item->eventEquip(this_player(), limbs); + } + } + } + return 1; +} diff --git a/lib/verbs/players/abandon.c b/lib/verbs/players/abandon.c new file mode 100644 index 0000000..624ae9e --- /dev/null +++ b/lib/verbs/players/abandon.c @@ -0,0 +1,21 @@ +#include + +inherit LIB_VERB; + +static void create() { + ::create(); + SetVerb("abandon"); + SetRules("LIV"); + SetErrorMessage("Whom would you like to abandon?"); + SetHelp("Syntax: abandon \n\n" + "If a living object is specified, this command allows " + "you to leave the creature's companionship.\n" + "See also: mount, dismount, befriend"); +} + +mixed can_abandon_liv() { return 1; } + +mixed do_abandon_liv(object ob) { + ob->eventAbandon(this_player()); + return 1; +} diff --git a/lib/verbs/players/attack.c b/lib/verbs/players/attack.c new file mode 100644 index 0000000..25e506f --- /dev/null +++ b/lib/verbs/players/attack.c @@ -0,0 +1,124 @@ +/* /verbs/players/attack.c + * from the Dead Souls Mud Library + * a very violent command + * created by Descartes of Borg 960512 + * Version: @(#) attack.c 1.3@(#) + * Last Modified: 96/10/20 + */ + +#include +#include +#include +#include "include/attack.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("attack"); + SetRules("LVS", "only LVS","LVS only"); + SetSynonyms("kill", "smite", "waste", "hit", "gank"); + SetErrorMessage("Attack whom?"); + SetHelp("Syntax: attack \n" + " attack all of \n" + " attack all\n\n" + "This command initiates combat with a living being or group " + "of living beings using any wielded weapons or your bare hands. " + "Be very careful not to issue the \"attack all\" with other " + "players in the room or you will be guilty of attempted player " + "killing.\n" + "See also: wimpy, ignore, target"); +} + +varargs mixed can_attack_liv(object target) { + int pos = this_player()->GetPosition(); + + if( this_player()->GetParalyzed() ) { + return "You cannot move!"; + } + if( pos == POSITION_SITTING || pos == POSITION_LYING && + !RACES_D->GetLimblessCombatRace(this_player()->GetRace()) ){ + return "You cannot attack in that position!"; + } + if( this_player() && environment(this_player()) && + environment(this_player())->GetProperty("no attack") ) { + return "A mystical force prevents your malice."; + } + return 1; +} + +mixed can_attack_only_liv(object target){ + return can_attack_liv(target); +} + +mixed can_attack_liv_only(object target){ + return can_attack_liv(target); +} + +mixed do_attack_liv(object target) { + return do_attack_lvs(({ target })); +} + +mixed do_attack_only_liv(object target){ + return do_attack_lvs(({ target }), 1); +} + +mixed do_attack_liv_only(object target){ + return do_attack_lvs(({ target }), 1); +} + +varargs mixed do_attack_lvs(mixed *targets, int exclusive) { + object *obs, *tmpobs; + object *noattack; + string tmp; + + if(this_player()->GetDying()) return 0; + + noattack = ({}); + tmpobs = ({}); + obs = filter(targets, (: objectp($1) && !($1->GetInvis()) :)); + targets -= ({ this_player() }); + + if(!sizeof(targets)){ + write("There is nobody to attack."); + return 1; + } + + if( !sizeof(obs) ) { + mixed *ua; + + ua = unique_array(targets, (: $1 :)); + foreach(string *lines in ua) this_player()->eventPrint(lines[0]); + return 1; + } + if(exclusive){ + foreach(object entity in get_livings(environment(this_player()))){ + if(member_array(entity,obs) == -1) noattack += ({ entity }); + } + if(sizeof(noattack)) this_player()->AddNonTargets(noattack); + } + foreach(object subobj in obs){ + if(subobj == this_player()) continue; + if(member_array(this_player(),subobj->GetEnemies()) != -1 && + member_array(subobj,this_player()->GetNonTargets()) != -1){ + write("You are already fighting "+subobj->GetName()+"!"); + } + else { + mixed attackable = subobj->CanAttack(this_player()); + if(intp(attackable) && attackable) tmpobs += ({ subobj }); + else if(stringp(attackable)) write(attackable); + } + } + + obs = tmpobs; + if(!sizeof(obs)) return 1; + + this_player()->SetAttack(obs); + tmp = item_list(obs); + obs->eventPrint(this_player()->GetName() + " attacks you!"); + environment(this_player())->eventPrint(this_player()->GetName() + + " attacks " + tmp + "!", + ({ this_player(), obs... })); + this_player()->eventPrint("You advance towards " + tmp + "."); + return 1; +} diff --git a/lib/verbs/players/backstab.c b/lib/verbs/players/backstab.c new file mode 100644 index 0000000..fdcbe84 --- /dev/null +++ b/lib/verbs/players/backstab.c @@ -0,0 +1,197 @@ +/* Allows players to possibly backstab a targets + * created by Rush@Dead Souls + * Version: @(#) backstab.c 1.3@(#) + * Last Modified: 96/12/21 + */ + +#include +#include +#include "damage_types.h" +#include "include/backstab.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("backstab"); + SetRules("LIV"); + SetErrorMessage("Who do you want to backstab?"); + SetHelp("Syntax: backstab \n\n" + "This sneaky attack allows more devious players to " + "backstab a specified target."); +} + +mixed can_backstab_liv() { + if( !environment(this_player()) ) return 0; + if( this_player()->GetInCombat() ) + return "You are too busy with combat!"; + else return this_player()->CanManipulate(); +} + +mixed do_backstab_liv(object ob) { + object env; + + if(!(env = environment(this_player()))) return 0; + if( this_player()->GetPosition() != POSITION_STANDING ) + this_player()->eventStand(); + if(!ob || !present(ob, env)) { + this_player()->eventPrint("Your hapless victim is no longer present."); + return 1; + } + this_player()->RemoveNonTargets(({ob})); + this_player()->eventPrint("%^RED%^You sneak up behind " + + ob->GetName() + "...%^RESET%^"); + this_player()->SetAttack(ob, (:eventBackstab, this_player(), ob:)); + return 1; +} + +int eventBackstab(object backstabber, object target) { + object env; + float tmp; + int suprise; + object *weapons; + int numberOfWeapons; + int numberOfStabs; + int i; + + if(!backstabber || !(env = environment(backstabber))) return 0; + if(!target || !present(target, env)) { + backstabber->eventPrint("Your hapless victim is no longer present."); + return 1; + } + + tmp = backstabber->GetSkillLevel("stealth")*1.5; + tmp += backstabber->GetStatLevel("charisma")/2.0; + tmp += backstabber->GetStatLevel("luck")/3.0; + tmp += backstabber->GetMobility()/3.0; + tmp -= target->GetStatLevel("luck")/3.0; + tmp -= target->GetStatLevel("wisdom")/3.0; + tmp -= target->GetMobility()/5.0; + tmp *= 1.0; + if(tmp < 1.0) tmp = 1.0; + suprise = to_int(tmp); + + backstabber->AddSkillPoints("stealth", to_int(suprise * 3.0)); + backstabber->AddStaminaPoints(-(5 + random(5))); + moral_act(backstabber, target, -30); + + if(suprise < random(100) || !present(target, environment(backstabber))) { + backstabber->eventPrint("%^RED%^" + target->GetName() + + " evades your poorly executed backstab.%^RESET%^"); + target->eventPrint("%^RED%^You easily dodge " + possessive_noun(backstabber) + + " attempted backstab.%^RESET%^"); + environment(backstabber)->eventPrint("%^RED%^" + target->GetName() + + " dodges " + possessive_noun(backstabber) + " attempted backstab.%^RESET%^", + ({backstabber, target})); + return 1; + } + + weapons = backstabber->GetWielded(); + numberOfWeapons = sizeof(weapons); + + if(!numberOfWeapons) { + backstabber->eventPrint("%^RED%^You beat your fists ineffectively on " + + possessive_noun(target) + " back.%^RESET%^"); + target->eventPrint("%^RED%^Somebody beats ineffectively upon your back.%^RESET%^"); + environment(backstabber)->eventPrint("%^RED%^" + backstabber->GetName() + + " backstabs " + target->GetName() + " expertly... unfortunately " + + nominative(backstabber) + " forgot " + possessive(backstabber) + " knives.%^RESET%^", + ({backstabber, target})); + return 1; + } + + numberOfStabs = 0; + for(i = 0; i < numberOfWeapons && target; i++) + numberOfStabs += eventStab(backstabber, target, weapons[i]); + if(!numberOfStabs) { + target->eventPrint("%^RED%^You dodge " + possessive_noun(backstabber) + + " attempted backstab.%^RESET%^"); + return 1; + } + + backstabber->eventExecuteAttack(target); + return 1; +} + +int eventStab(object backstabber, object target, object weapon) { + string weaponType; + int damage; + float x; + int percentDamage; + float adjustment; + int numberWielded; + + if(!(weaponType = weapon->GetWeaponType())) return 0; + numberWielded = sizeof(backstabber->GetWielded()); + + x = weapon->GetClass() * 5.0; + x += backstabber->GetSkillLevel(weaponType + " attack")/1.0; + x += backstabber->GetStatLevel("strength")/2.0; + x += backstabber->GetStatLevel("luck")/3.0; + x += backstabber->GetMobility()/3.0; + if(numberWielded > 1) { + adjustment = backstabber->GetSkillLevel("multi-weapon") / (numberWielded / 2.0); + x *= adjustment/100.0; + } + x -= target->GetStatLevel("luck")/3.0; + x *= 0.5; + x = (x + random(x)) / 2.0; + if(weaponType != "knife") x = (x - 50.0) / 4.0; + if(x < 1.0) x = 0.0; + + damage = target->eventReceiveDamage(backstabber, + weapon->GetDamageType(), to_int(x), 0, target->GetTorso()); + if(damage > 0) { + weapon->eventReceiveDamage(BLUNT, damage, 0, target->GetTorso()); + percentDamage = damage * 100 / target->GetMaxHealthPoints(); + if(percentDamage < 1) percentDamage = 0; + } + else percentDamage = 0; + eventPrintDamage(backstabber, target, weapon, percentDamage); + backstabber->AddSkillPoints(weaponType + " attack", 7 + damage/10); + return 1; +} + +int eventPrintDamage(object backstabber, object target, object weapon, int percentDamage) { + string adverb; + string myVerb; + string verb; + + if(!percentDamage) { + backstabber->eventPrint("%^RED%^You fumble awkwardly with your " + + strip_article(weapon->GetShort()) + ".%^RESET%^"); + environment(backstabber)->eventPrint("%^RED%^" + backstabber->GetName() + + " fumbles awkwardly with " + possessive(backstabber) + " " + + strip_article(weapon->GetShort()) + ".%^RESET%^", + ({backstabber, target})); + return 1; + } + + if(percentDamage < 15) { + myVerb = "jab "; + verb = "jabs "; + adverb = "sharply "; + } + else if(percentDamage < 30) { + myVerb = "stab "; + verb = "stabs "; + adverb = "painfully "; + } + else { + myVerb = "slam "; + verb = "slams "; + adverb = "deep "; + } + + backstabber->eventPrint("%^RED%^You " + myVerb + "your " + + strip_article(weapon->GetShort()) + " " + adverb + "into " + + possessive_noun(target) + " back.%^RESET%^"); + target->eventPrint("%^RED%^Your back sears with pain as a " + weapon->GetWeaponType() + + " " + verb + adverb + "into you.%^RESET%^"); + environment(backstabber)->eventPrint("%^RED%^" + backstabber->GetName() + " " + + verb + possessive(backstabber) + " " + strip_article(weapon->GetShort()) + + " " + adverb + "into " + possessive_noun(target) + " back.%^RESET%^", + ({backstabber, target})); + + return 1; +} diff --git a/lib/verbs/players/befriend.c b/lib/verbs/players/befriend.c new file mode 100644 index 0000000..769bbf6 --- /dev/null +++ b/lib/verbs/players/befriend.c @@ -0,0 +1,25 @@ +#include + +inherit LIB_VERB; + +static void create() { + ::create(); + SetVerb("befriend"); + SetRules("LIV"); + SetErrorMessage("Whom would you like to befriend?"); + SetHelp("Syntax: befriend \n\n" + "If a living object is specified, this command allows " + "you to try to make friends. This is a prerequisite to " + "successfully mounting an animal. Note that if your " + "charisma is low " + "enough, you may fail. Also beware that someone with higher " + "charisma may steal your mount.\n" + "See also: mount, dismount, abandon"); +} + +mixed can_befriend_liv() { return 1; } + +mixed do_befriend_liv(object ob) { + ob->eventBefriend(this_player()); + return 1; +} diff --git a/lib/verbs/players/bump.c b/lib/verbs/players/bump.c new file mode 100644 index 0000000..2b932b9 --- /dev/null +++ b/lib/verbs/players/bump.c @@ -0,0 +1,147 @@ +/* /cmds/verbs/player/bump.c + * Allows players to possibly bump a target into another room + * created by Blitz@Dead Souls + */ + +#include +#include +#include "include/bump.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("bump"); + SetRules("LIV"); + SetErrorMessage("Whom would you like to bump?"); + SetHelp( "Syntax: bump \n\n" + "This command allows you bump the living object named " + "into an adjacent room. It is quite possible that " + "bumping may cause you bodily injury."); +} + +mixed can_bump_liv() { + object env = environment(this_player()); + if( !env ) return "You are nowhere!"; + if( env->GetProperty("no bump") ) + return "Mystical forces prevent your pushy actions."; + return 1; +} + +mixed do_bump_liv(object ob) { + int Strength, TargetStrength; + string *Exits; + string NewLocation, OldLocation; + mixed var; + object env; + + if( !ob ) return 0; + if( !(env = environment(ob)) ) return 0; + if( ob->GetProperty("no bump") ) { + message("my_action", "You try to bump "+ + ob->GetCapName()+".", + this_player() ); + message("other_action", this_player()->GetCapName()+" tries " + "to bump "+ob->GetCapName()+".", + environment(ob), ({ ob, this_player() }) ); + message("other_action", this_player()->GetCapName()+" tries " + "to bump you.", + ob); + if( !playerp(ob) ) + ob->eventForce("growl "+this_player()->GetKeyName()); + return 1; + } + if( var = ob->eventBump(this_player()) ) return var; + this_player()->AddStaminaPoints( -(random(15) + 3) ); + if( ( ob->GetStatLevel("agility") / 2 ) > + ( this_player()->GetStatLevel("strength")) ) { + message("my_action", "You deftly sidestep "+ + possessive_noun(this_player()->GetCapName())+" attempt " + "to bump you.", + ob); + message("other_action", ob->GetCapName()+" deftly sidesteps " + "your attempt to bump "+objective(ob)+".", + this_player() ); + message("other_action", ob->GetCapName()+" deftly sidesteps "+ + possessive_noun(this_player()->GetCapName())+" attempt " + "to bump "+objective(ob)+".", + env, ({ this_player(), ob })); + return 1; + } + Strength = this_player()->GetStatLevel("strength") + + random(this_player()->GetStatLevel("speed") / 2); + TargetStrength = ob->GetStatLevel("strength") + + random( ob->GetStatLevel("agility") / 2 ); + if( (Strength - TargetStrength) < -10 ) { + this_player()->eventReceiveDamage(ob, BLUNT, random(5) + 1); + message("other_action", ob->GetCapName()+" shoves you " + "to the ground!", + this_player() ); + message("my_action", this_player()->GetCapName()+" is shoved " + "to the ground while trying to bump you.", + ob); + message("other_action", this_player()->GetCapName()+" is shoved " + "to the ground while trying to bump "+ob->GetCapName()+".", + env, ({ ob, this_player() }) ); + return 1; + } + else if( (Strength - TargetStrength) < (5 + random(20)) ) { + this_player()->eventReceiveDamage(ob, BLUNT, random(3) + 1); + message("my_action", "You fail to bump "+ob->GetCapName()+" out " + "of the way.", this_player() ); + message("other_action", this_player()->GetCapName()+" fails in " + "an attempt to bump you.", + ob); + message("other_action", this_player()->GetCapName()+" fails in " + "an attempt to bump "+ob->GetCapName()+".", + environment(ob), ({ ob, this_player() }) ); + return 1; + } else { + this_player()->AddStatPoints("strength", random(5)); + Exits = env->GetExits(); + Exits = filter(Exits, + (: !(object)$(env)->GetDoor($1) || + !(object)$(env)->GetDoor($1)->GetClosed() :) ); + if( !sizeof(Exits) ) { + message("system", "There is nowhere for "+ob->GetCapName() + +" to go!", this_player() ); + return 1; + } + NewLocation = Exits[ random(sizeof(Exits)) ]; + NewLocation = environment(ob)->GetExit(NewLocation); + OldLocation = base_name(environment(ob)); + message("my_action", "You shove "+ob->GetCapName()+" out " + "of the way!", + this_player() ); + message("other_action", "You are shoved out of the way by "+ + this_player()->GetCapName()+"!", + ob); + message("other_action", this_player()->GetCapName()+" shoves "+ + ob->GetCapName()+" out of the way!", + environment(ob), ({ ob, this_player() }) ); + if( !ob->eventMove(NewLocation) ) { + message("other_action", ob->GetCapName()+" is bounced " + "back into the room.", environment(ob), ob); + message("my_action", "You are bounced back to your original " + "location.", + ob); + } else { + ob->eventDescribeEnvironment(0); + if( !userp(ob) ) + call_out((: MoveBack :), 12 + random(6), ob, OldLocation); + } + if( ob->GetHealthPoints() > 5 ) + ob->eventReceiveDamage(this_player(), BLUNT, random(5)); + return 1; + } + return 0; +} + +void MoveBack(object ob, string where) { + if( !ob ) return; + ob->eventForce("growl"); + tell_room(environment(ob),capitalize(ob->GetShort())+" leaves angrily."); + ob->eventMove(where); + tell_room(environment(ob),capitalize(ob->GetShort())+" enters angrily."); + ob->eventForce("say wtf"); +} diff --git a/lib/verbs/players/cast.c b/lib/verbs/players/cast.c new file mode 100644 index 0000000..6b96b97 --- /dev/null +++ b/lib/verbs/players/cast.c @@ -0,0 +1,76 @@ +/* /verbs/players/cast.c + * From Dead Souls LPMud + * Created by Descartes of Borg 951027 + * Version: @(#) cast.c 1.4@(#) + * Last modified: 96/12/16 + */ + +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("cast"); + SetRules("STR", "STR on OBJ", "STR on STR", "STR on STR of OBJ", + "STR against STR"); + SetErrorMessage("Cast what spell? On whom?"); + SetHelp("Syntax: cast \n" + " cast on \n" + " cast against \n" + " cast on \n" + " cast on of \n\n" + "Allows you to cast any spell using whatever syntax the " + "spell in question requires. To heal someone, for example, " + "\"cast heal on descartes\"."); +} + +mixed can_cast_str(string spell) { + object tmp = SPELLS_D->GetSpell(spell); + + if( tmp ) { + string verb = tmp->GetVerb(); + + if( verb != "cast" ) { + return "That is not a spell you cast."; + } + } + if(intp(this_player()->CanManipulate())) return this_player()->CanCast(tmp); +} + +mixed can_cast_str_on_obj(string spell) { + return can_cast_str(spell); +} + +mixed can_cast_str_on_str(string spell) { + return can_cast_str(spell); +} + +mixed can_cast_str_against_str(string spell) { + return can_cast_str(spell); +} + +mixed can_cast_str_on_str_of_str(string spell) { + return can_cast_str(spell); +} + +mixed do_cast_str(string spell) { + return this_player()->eventPrepareCast(spell); +} + +mixed do_cast_str_on_obj(string spell, object target) { + return this_player()->eventPrepareCast(spell, target); +} + +mixed do_cast_str_against_str(string spell, object target) { + return this_player()->eventPrepareCast(spell, target); +} + +mixed do_cast_str_on_str(string spell, string limb) { + return this_player()->eventPrepareCast(spell, limb); +} + +mixed do_cast_str_on_str_of_obj(string spell, string limb, object target) { + return this_player()->eventPrepareCast(spell, limb, target); +} diff --git a/lib/verbs/players/crawl.c b/lib/verbs/players/crawl.c new file mode 100644 index 0000000..48b7608 --- /dev/null +++ b/lib/verbs/players/crawl.c @@ -0,0 +1,54 @@ +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("crawl"); + SetRules("STR", "into STR"); + SetErrorMessage("Crawl in which direction?"); + SetHelp("Syntax: crawl \n" + " crawl into \n\n" + "Moves you towards the direction you specify, or into the place " + "you specify. The command \"crawl into\" is synonymous with the " + "\"enter\" command."); +} + +mixed can_crawl_str(string str) { + if( !environment(this_player()) ) return "You are nowhere."; + if( this_player()->GetStaminaPoints() <3 ) + return "You are too tired to crawl anywhere right now."; + if(this_player()->GetPosition() != POSITION_LYING && + this_player()->GetPosition() != POSITION_SITTING){ + return "You can't crawl in your current position."; + } + return 1; +} + +mixed can_crawl_into_str(string str) { + if( !environment(this_player()) ) return "You are nowhere."; + if( this_player()->GetStaminaPoints() <3 ) + return "You are too tired right now."; + if(this_player()->GetPosition() != POSITION_LYING && + this_player()->GetPosition() != POSITION_SITTING){ + return "You can't crawl in your current position."; + } + return 1; +} + +mixed do_crawl_str(string str) { + this_player()->AddStaminaPoints(-5); + environment(this_player())->eventGo(this_player(), str); + return 1; +} + +mixed do_crawl_into_str(string str) { + object targ; + str = remove_article(lower_case(str)); + targ = present(str,environment(this_player())); + if(!targ) targ = present(str,this_player()); + if(!targ) return "That's not possible."; + this_player()->AddStaminaPoints(-5); + return targ->eventEnter(this_player(), str,"crawl"); +} diff --git a/lib/verbs/players/describe.c b/lib/verbs/players/describe.c new file mode 100644 index 0000000..20227de --- /dev/null +++ b/lib/verbs/players/describe.c @@ -0,0 +1,34 @@ +/* Allows players to describe themselves. + * created by Rush@Dead Souls + */ + +#include +#include "include/describe.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("describe"); + SetRules("LIV","STR"); + SetErrorMessage("Describe syntax: describe "); + SetHelp("Syntax: describe \n\n" + "Provides a player with a description. You must include " + "an instance of $N at least once in your description to " + "denote your name. Example: If I typed 'describe $N is " + "nondescript.', my description would be 'Rush is " + "nondescript.'"); +} + +mixed can_describe_str(string str) { + if(strsrch(str, "$N") == -1) + return("Your description must include a minimum of one '$N' " + + "to specify your name."); + return 1; +} + +mixed do_describe_str(string str) { + this_player()->SetLong(str); + write("Ok."); + return 1; +} diff --git a/lib/verbs/players/dismount.c b/lib/verbs/players/dismount.c new file mode 100644 index 0000000..1192b4f --- /dev/null +++ b/lib/verbs/players/dismount.c @@ -0,0 +1,55 @@ +#include +#include ROOMS_H +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("dismount"); + SetRules("","LIV", "from LIV"); + SetErrorMessage("Dismount something?"); + SetHelp("Syntax: dismount \n\n" + "This command allows you to get off a " + "creature you are riding.\n" + "See also: mount, befriend, abandon"); +} + +mixed can_dismount_liv() { + if(this_player()->CanManipulate()) + return bool_reverse(this_player()->GetParalyzed()); +} + +mixed can_dismount_from_liv() { + return can_dismount_liv(); +} + +mixed can_dismount() { + return can_dismount_liv(); +} + +mixed do_dismount_liv(object ob) { + return ob->eventDismount(this_player()); +} + +mixed do_dismount_from_liv(object ob) { + return do_dismount_liv(ob); +} + +mixed do_dismount() { + object mount = this_player()->GetProperty("mount"); + if(mount) return do_dismount_liv(mount); + if(base_name(environment(this_player())) == LIB_CORPSE){ + object new_env = environment(environment(this_player())); + if(!new_env) new_env = find_object(ROOM_START); + else { + write("You get off your dead mount."); + say(this_player()->GetName()+" gets off "+possessive(this_player())+ + " dead mount."); + } + this_player()->eventMoveLiving(new_env); + } + else return write("You don't seem to have a mount."); + +} diff --git a/lib/verbs/players/drive.c b/lib/verbs/players/drive.c new file mode 100644 index 0000000..a667266 --- /dev/null +++ b/lib/verbs/players/drive.c @@ -0,0 +1,80 @@ +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("drive"); + SetRules("STR", "into STR" ); + SetErrorMessage("Drive in which direction?"); + SetHelp("Syntax: drive \n" + " drive into \n\n" + "Moves your vehicle towards the direction you specify, or into the place " + "you specify. The command \"drive into\" is synonymous with the " + "\"enter\" command.\n" + "See also: mount, dismount"); +} + +mixed can_drive_str(string str) { + object vehicle = environment(this_player()); + object where; + + if(vehicle) where = environment(vehicle); + if(vehicle && !vehicle->GetMount()) return "You are not mounted."; + + if( !vehicle ) return "You are nowhere."; + if( !where ) return "Your mount is nowhere."; + if( vehicle->GetStaminaPoints() <3 ) + return "Your vehicle lacks fuel."; + if(!stringp(hobbled(vehicle))) return "Your vehicle is incapacitated."; + if(str) switch(str){ + case "n" : str = "north"; break; + case "s" : str = "south"; break; + case "e" : str = "east"; break; + case "w" : str = "west"; break; + case "u" : str = "up"; break; + case "d" : str = "down"; break; + case "ne" : str = "northeast"; break; + case "nw" : str = "northwest"; break; + case "se" : str = "southeast"; break; + case "sw" : str = "southwest"; break; + } + return where->CanGo(vehicle, str); +} + +mixed can_drive_into_str(string str) { + object vehicle = environment(this_player()); + object where; + + if(vehicle) where = environment(vehicle); + if(vehicle && !vehicle->GetMount()) return "You are not mounted."; + + if( !vehicle ) return "You are nowhere."; + if( !where ) return "Your mount is nowhere."; + if( vehicle->GetStaminaPoints() <3 ) + return "Your vehicle has insufficient fuel."; + if(!stringp(hobbled(vehicle))) return "Your vehicle is incapacitated."; + return where->CanEnter(vehicle, str); +} + +mixed do_drive_str(string str) { + object vehicle = environment(this_player()); + if(str) switch(str){ + case "n" : str = "north"; break; + case "s" : str = "south"; break; + case "e" : str = "east"; break; + case "w" : str = "west"; break; + case "u" : str = "up"; break; + case "d" : str = "down"; break; + case "ne" : str = "northeast"; break; + case "nw" : str = "northwest"; break; + case "se" : str = "southeast"; break; + case "sw" : str = "southwest"; break; + } + return vehicle->eventDrive(str); +} + +mixed do_drive_into_str(string str) { + object vehicle = environment(this_player()); + return vehicle->eventDrive("into" + str); +} diff --git a/lib/verbs/players/evade.c b/lib/verbs/players/evade.c new file mode 100644 index 0000000..feb53af --- /dev/null +++ b/lib/verbs/players/evade.c @@ -0,0 +1,30 @@ +/* Allows players to possibly evade a targets + * created by Rush@Dead Souls + */ + +#include +#include "include/evade.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("evade"); + SetRules("LIV"); + SetErrorMessage("Who are you trying to evade?"); + SetHelp("Syntax: evade \n\n" + "Allows one to attempt to evade a living being " + "who is currently following.\n" + "See also: follow, lead, tracking, stealth\n"); +} + +mixed can_evade_liv() { return 1; } + +mixed do_evade_liv(object ob) { + if(!this_player()->SetAllowed(ob, 0)){ + this_player()->eventPrint("You are now evading " + + ob->GetName() + "."); + } + else this_player()->eventPrint("You are not empowered to evade " + ob->GetName() + "."); + return 1; +} diff --git a/lib/verbs/players/follow.c b/lib/verbs/players/follow.c new file mode 100644 index 0000000..41db7e1 --- /dev/null +++ b/lib/verbs/players/follow.c @@ -0,0 +1,88 @@ +/* Allows players to possibly follow a target into another room + * created by Rush@Dead Souls + */ + +#include +#include "include/follow.h" + +inherit LIB_VERB; + +static void create() { + ::create(); + SetVerb("follow"); + SetRules("", "LIV"); + SetErrorMessage("Whom would you like to follow?"); + SetHelp("Syntax: follow [LIVING]\n\n" + "If a living object is specified, this command allows " + "you to begin trailing the living being as it moves " + "through Dead Souls.\n" + "Otherwise, your following status is reported.\n" + "If the living being is interested in having you " + "follow them, they can issue the \"lead\" command " + "in order to avoid accidentally evading you.\n" + "See also: evade, lead, tracking, stealth\n"); +} + +mixed can_follow() { return 1; } + +mixed do_follow() { + object* followers; + string* obs; + object leader; + int size; + string tmp; + + // Format follow string. + if(this_player()->CanLead() && leader = this_player()->GetLeader()) { + tmp = "You are "; + if(leader->GetFollowed(this_player())) tmp += "following"; + else tmp += "trailing"; + tmp += " " + leader->GetName() + ".\n"; + } + else tmp = "You are trailing no one." + "\n"; + + // Get the followers. + followers = this_player()->GetFollowers(); + if(!followers) followers = ({}); + + // Format lead string. + tmp += "You are leading "; + obs = map( + filter(followers, (:this_player()->GetFollowed($1):)), + (:$1->GetName():)); + size = sizeof(obs); + if(size) tmp += conjunction(obs); + else tmp += "no one"; + tmp += ".\n"; + + // Format evasion string. + tmp += "You are evading "; + obs = map( + filter(followers, (:!this_player()->GetFollowed($1):)), + (:$1->GetName():)); + size = sizeof(obs); + if(size) tmp += conjunction(obs); + else tmp += "no one"; + tmp += ".\n"; + + this_player()->eventPrint(tmp); + return 1; +} + +mixed can_follow_liv() { return 1; } + +mixed do_follow_liv(object ob) { + object leader; + + if(leader = this_player()->GetLeader()) { + leader->RemoveFollower(this_player()); + this_player()->eventPrint("You stop trailing " + leader->GetName() + "."); + return 1; + } + + if(member_array(this_player(), ob->AddFollower(this_player())) == -1) + this_player()->eventPrint("You are not empowered to follow " + ob->GetName() + "."); + else this_player()->eventPrint("You are now trailing " + ob->GetName() + "."); + + return 1; +} diff --git a/lib/verbs/players/ignore.c b/lib/verbs/players/ignore.c new file mode 100644 index 0000000..2a9cefc --- /dev/null +++ b/lib/verbs/players/ignore.c @@ -0,0 +1,69 @@ +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("ignore"); + SetRules("LVS",""); + SetErrorMessage("Whom are you trying to ignore?"); + SetHelp("Syntax: ignore \n\n" + "Allows one to stop attacking a living being " + "or beings. Helpful for not wasting time on the " + "wrong targets.\n" + "See also: attack\n"); +} + +mixed can_ignore(){ return 1; } + +mixed can_ignore_liv() { return 1; } + +mixed do_ignore(){ + if(sizeof(this_player()->GetNonTargets())){ + string tmp; + tmp = item_list(this_player()->GetNonTargets()); + this_player()->eventPrint("You are ignoring " + tmp + "."); + return 1; + } + else { + this_player()->eventPrint("Ignore whom?"); + return 0; + } +} + +mixed do_ignore_liv(object ob) { + this_player()->AddNonTargets(ob); + if(member_array(ob,this_player()->GetNonTargets()) != -1){ + + this_player()->eventPrint("You are now ignoring " + ob->GetName() + "."); + ob->eventPrint(this_player()->GetName() + " ignores you!"); + environment(this_player())->eventPrint(this_player()->GetName() + + " ignores " + ob->GetName() + "!", + ({ this_player(), ob })); + } + else this_player()->eventPrint("You are unable to ignore " + ob->GetName() + "."); + return 1; +} + +mixed do_ignore_lvs(mixed *targets) { + object *obs; + string tmp; + + obs = filter(targets, (: objectp :)); + if( !sizeof(obs) ) { + mixed *ua; + + ua = unique_array(targets, (: $1 :)); + foreach(string *lines in ua) this_player()->eventPrint(lines[0]); + return 1; + } + if(member_array(this_player(),obs) != -1) obs -= ({ this_player() }); + this_player()->AddNonTargets(obs); + tmp = item_list(obs); + obs->eventPrint(this_player()->GetName() + " ignores you!"); + environment(this_player())->eventPrint(this_player()->GetName() + + " ignores" + tmp + "!", + ({ this_player(), obs... })); + this_player()->eventPrint("You ignore " + tmp + "."); + return 1; +} diff --git a/lib/verbs/players/include/,nominate.h b/lib/verbs/players/include/,nominate.h new file mode 100644 index 0000000..1a05571 --- /dev/null +++ b/lib/verbs/players/include/,nominate.h @@ -0,0 +1,8 @@ +#ifndef l_nominate_h +#define l_nominate_h + +static void create(); +mixed can_nominate_str(); +mixed do_nominate_str(string str); + +#endif /* l_nominate_h */ diff --git a/lib/verbs/players/include/,vote.h b/lib/verbs/players/include/,vote.h new file mode 100644 index 0000000..3099529 --- /dev/null +++ b/lib/verbs/players/include/,vote.h @@ -0,0 +1,8 @@ +#ifndef l_vote_h +#define l_vote_h + +static void create(); +mixed can_vote_for_str(); +mixed do_vote_for_str(string str); + +#endif /* l_vote_h */ diff --git a/lib/verbs/players/include/,withdraw.h b/lib/verbs/players/include/,withdraw.h new file mode 100644 index 0000000..0c5571e --- /dev/null +++ b/lib/verbs/players/include/,withdraw.h @@ -0,0 +1,8 @@ +#ifndef l_withdraw_h +#define l_withdraw_h + +static void create(); +mixed can_withdraw(); +mixed do_withdraw(); + +#endif /* l_withdraw_h */ diff --git a/lib/verbs/players/include/attack.h b/lib/verbs/players/include/attack.h new file mode 100644 index 0000000..f7ae348 --- /dev/null +++ b/lib/verbs/players/include/attack.h @@ -0,0 +1,11 @@ +#ifndef l_attack_h +#define l_attack_h + +static void create(); + +mixed can_attack_liv(object target); + +mixed do_attack_liv(object target); +varargs mixed do_attack_lvs(mixed *targets, int exclusive); + +#endif /* l_attack_h */ diff --git a/lib/verbs/players/include/backstab.h b/lib/verbs/players/include/backstab.h new file mode 100644 index 0000000..7e0ab75 --- /dev/null +++ b/lib/verbs/players/include/backstab.h @@ -0,0 +1,13 @@ +#ifndef l_backstab_h +#define l_backstab_h + +static void create(); +mixed can_backstab_liv(); +mixed do_backstab_liv(object ob); +int eventBackstab(object backstabber, object target); +int eventStab(object backstabber, object target, object weapon); +int eventPrintDamage(object backstabber, object target, object weapon, int percentDamage); + +#endif /* l_backstab_h */ + + diff --git a/lib/verbs/players/include/backstab2.h b/lib/verbs/players/include/backstab2.h new file mode 100644 index 0000000..19694d1 --- /dev/null +++ b/lib/verbs/players/include/backstab2.h @@ -0,0 +1,14 @@ +#ifndef l_backstab_h +#define l_backstab_h + +static void create(); +mixed can_backstab_liv(object ob); +mixed do_backstab_liv(object ob); +string GetHelp(string str); +int eventBackstab(object backstabber, object target, int suprise); +int eventStab(object backstabber, object target, object weapon); +int eventPrintDamage(object backstabber, object target, object weapon, int percentDamage); + +#endif /* l_backstab_h */ + + diff --git a/lib/verbs/players/include/bump.h b/lib/verbs/players/include/bump.h new file mode 100644 index 0000000..2b5dc82 --- /dev/null +++ b/lib/verbs/players/include/bump.h @@ -0,0 +1,9 @@ +#ifndef l_bump_h +#define l_bump_h + +static void create(); +mixed can_bump_liv(); +mixed do_bump_liv(object ob); +void MoveBack(object ob, string where); + +#endif /* l_bump_h */ diff --git a/lib/verbs/players/include/crawl.h b/lib/verbs/players/include/crawl.h new file mode 100644 index 0000000..e3f5527 --- /dev/null +++ b/lib/verbs/players/include/crawl.h @@ -0,0 +1,12 @@ +#ifndef l_crawl_h +#define l_crawl_h + +static void create(); + +mixed can_crawl_str(string str); +mixed can_crawl_into_str(string str); + +mixed do_crawl_str(string str); +mixed do_crawl_into_str(string str); + +#endif /* l_crawl_h */ diff --git a/lib/verbs/players/include/describe.h b/lib/verbs/players/include/describe.h new file mode 100644 index 0000000..5c4ede2 --- /dev/null +++ b/lib/verbs/players/include/describe.h @@ -0,0 +1,10 @@ +#ifndef l_describe_h +#define l_describe_h + +static void create(); +mixed can_describe_str(string str); +mixed do_describe_str(string str); + +#endif /* l_describe_h */ + + diff --git a/lib/verbs/players/include/evade.h b/lib/verbs/players/include/evade.h new file mode 100644 index 0000000..a9a9201 --- /dev/null +++ b/lib/verbs/players/include/evade.h @@ -0,0 +1,10 @@ +#ifndef l_evade_h +#define l_evade_h + +static void create(); +mixed can_evade_liv(); +mixed do_evade_liv(object ob); + +#endif /* l_evade_h */ + + diff --git a/lib/verbs/players/include/follow.h b/lib/verbs/players/include/follow.h new file mode 100644 index 0000000..c7dbad7 --- /dev/null +++ b/lib/verbs/players/include/follow.h @@ -0,0 +1,12 @@ +#ifndef l_follow_h +#define l_follow_h + +static void create(); +mixed can_follow(); +mixed do_follow(); +mixed can_follow_liv(); +mixed do_follow_liv(object ob); + +#endif /* l_follow_h */ + + diff --git a/lib/verbs/players/include/lead.h b/lib/verbs/players/include/lead.h new file mode 100644 index 0000000..18c307e --- /dev/null +++ b/lib/verbs/players/include/lead.h @@ -0,0 +1,10 @@ +#ifndef l_lead_h +#define l_lead_h + +static void create(); +mixed can_lead_liv(); +mixed do_lead_liv(object ob); + +#endif /* l_lead_h */ + + diff --git a/lib/verbs/players/include/marry.h b/lib/verbs/players/include/marry.h new file mode 100644 index 0000000..342c0c5 --- /dev/null +++ b/lib/verbs/players/include/marry.h @@ -0,0 +1,10 @@ +#ifndef l_marry_h +#define l_marry_h + +static void create(); + +mixed can_marry_liv_to_liv(); + +mixed do_marry_liv_to_liv(object spouse1, object spouse2); + +#endif /* l_marry_h */ diff --git a/lib/verbs/players/include/news.h b/lib/verbs/players/include/news.h new file mode 100644 index 0000000..c055995 --- /dev/null +++ b/lib/verbs/players/include/news.h @@ -0,0 +1,8 @@ + +static void create(); +mixed can_news(); +mixed can_news_str(string str); +mixed do_news(); +mixed do_news_str(string str); + + diff --git a/lib/verbs/players/include/nominate.h b/lib/verbs/players/include/nominate.h new file mode 100644 index 0000000..1a05571 --- /dev/null +++ b/lib/verbs/players/include/nominate.h @@ -0,0 +1,8 @@ +#ifndef l_nominate_h +#define l_nominate_h + +static void create(); +mixed can_nominate_str(); +mixed do_nominate_str(string str); + +#endif /* l_nominate_h */ diff --git a/lib/verbs/players/include/party.h b/lib/verbs/players/include/party.h new file mode 100644 index 0000000..018d6e7 --- /dev/null +++ b/lib/verbs/players/include/party.h @@ -0,0 +1,14 @@ +#ifndef l_party_h +#define l_party_h + +static void create(); +int livings_are_remote(); +mixed can_party_wrd(string cmd); +mixed can_party_wrd_wrd(string cmd, string party); +mixed can_party_wrd_liv(string cmd); +mixed do_party_wrd(string cmd); +mixed do_party_wrd_wrd(string cmd, string party); +mixed do_party_wrd_liv(string cmd, object targ); +string GetHelp(string str); + +#endif /* l_party_h */ diff --git a/lib/verbs/players/include/request.h b/lib/verbs/players/include/request.h new file mode 100644 index 0000000..7811951 --- /dev/null +++ b/lib/verbs/players/include/request.h @@ -0,0 +1,14 @@ +#ifndef l_request_h +#define l_request_h + +static void create(); + +mixed can_request(); +mixed can_request_str_from_liv(string str, object who); + +mixed do_request(); +mixed do_request_str_from_liv(string str, object who); + +string GetHelp(string str); + +#endif /* l_request_h */ diff --git a/lib/verbs/players/include/stealth.h b/lib/verbs/players/include/stealth.h new file mode 100644 index 0000000..e5a8d5e --- /dev/null +++ b/lib/verbs/players/include/stealth.h @@ -0,0 +1,7 @@ + +static void create(); +mixed can_stealth(); +mixed can_stealth_wrd(); +mixed do_stealth_wrd(string args); +int eventStealth(object caster, string args, int skill); + diff --git a/lib/verbs/players/include/target.h b/lib/verbs/players/include/target.h new file mode 100644 index 0000000..b2bc207 --- /dev/null +++ b/lib/verbs/players/include/target.h @@ -0,0 +1,11 @@ +#ifndef l_target_h +#define l_target_h + +static void create(); + +mixed can_target_liv(object target); + +mixed do_target_liv(object target); +varargs mixed do_target_lvs(mixed *targets, int exclusive); + +#endif /* l_target_h */ diff --git a/lib/verbs/players/include/vote.h b/lib/verbs/players/include/vote.h new file mode 100644 index 0000000..3099529 --- /dev/null +++ b/lib/verbs/players/include/vote.h @@ -0,0 +1,8 @@ +#ifndef l_vote_h +#define l_vote_h + +static void create(); +mixed can_vote_for_str(); +mixed do_vote_for_str(string str); + +#endif /* l_vote_h */ diff --git a/lib/verbs/players/include/withdraw.h b/lib/verbs/players/include/withdraw.h new file mode 100644 index 0000000..0c5571e --- /dev/null +++ b/lib/verbs/players/include/withdraw.h @@ -0,0 +1,8 @@ +#ifndef l_withdraw_h +#define l_withdraw_h + +static void create(); +mixed can_withdraw(); +mixed do_withdraw(); + +#endif /* l_withdraw_h */ diff --git a/lib/verbs/players/kneel.c b/lib/verbs/players/kneel.c new file mode 100644 index 0000000..b60553d --- /dev/null +++ b/lib/verbs/players/kneel.c @@ -0,0 +1,60 @@ +#include +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("kneel"); + SetRules("down",""); + SetErrorMessage("Kneel down?"); + SetSynonyms("genuflect"); + SetHelp("Syntax: kneel \n\n" + "Allows you to kneel.\n" + "See also: sit, stand, lie"); +} + +mixed can_kneel_down() { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything."; + } + + if( this_player()->GetPosition() == POSITION_KNEELING ) { + return "You are already kneeling!"; + } + + if(!environment(this_player())->CanKneel(this_player())){ + return "You can't kneel here."; + } + + return 1; +} + +mixed can_kneel(){ + return can_kneel_down(); +} + +mixed can_kneel_word_obj() { + return can_kneel_down(); +} + +mixed can_kneel_down_word_obj() { + return can_kneel_down(); +} + +mixed do_kneel_down() { + return this_player()->eventKneel(); +} + +mixed do_kneel(){ + return do_kneel_down(); +} + +mixed do_kneel_word_obj(string word, object target) { + return this_player()->eventKneel(target); +} + +mixed do_kneel_down_word_obj(string word, object target) { + return this_player()->eventKneel(target); +} diff --git a/lib/verbs/players/lead.c b/lib/verbs/players/lead.c new file mode 100644 index 0000000..d34bfb1 --- /dev/null +++ b/lib/verbs/players/lead.c @@ -0,0 +1,34 @@ +/* Allows players to possibly help a target follow. + * created by Rush@Dead Souls + */ + +#include +#include "include/lead.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("lead"); + SetRules("LIV"); + SetErrorMessage("Whom would you like to lead?"); + SetHelp("Syntax: lead \n\n" + "Allows one to assist a living being who is " + "attempting to follow.\n" + "See also: evade, follow, tracking, stealth\n"); +} + +mixed can_lead_liv() { return 1; } + +mixed do_lead_liv(object ob) { + if(!ob->IsFollowing(this_player())) { + this_player()->eventPrint(ob->GetName() + " is not following you."); + return 1; + } + if( this_player()->SetFollowed(ob, 1) ) { + ob->eventPrint(this_player()->GetName() + " is now leading you."); + this_player()->eventPrint("You are now leading " + ob->GetName() + "."); + } + else this_player()->eventPrint("You are not empowered to lead " + ob->GetName() + "."); + return 1; +} diff --git a/lib/verbs/players/learn.c b/lib/verbs/players/learn.c new file mode 100644 index 0000000..f5d4d44 --- /dev/null +++ b/lib/verbs/players/learn.c @@ -0,0 +1,44 @@ +#include +#include +#include + +inherit LIB_VERB; + +static void create(){ + verb::create(); + SetVerb("learn"); + SetRules("","STR from LIV","to STR from LIV"); + SetErrorMessage("Syntax: learn from "); + SetHelp("Syntax: learn from \n\n" + "This command allows you to learn from another person " + "an ability, spell, or skill.\nSee also: teach"); +} + +mixed can_learn_str_from_liv(string str, object ob){ + int pos = this_player()->GetPosition(); + if( this_player()->GetParalyzed() ) { + return "You cannot move!"; + } + if( pos == POSITION_LYING && + !RACES_D->GetLimblessCombatRace(this_player()->GetRace()) ){ + return "You cannot learn in that position!"; + } + return 1; +} + +mixed can_learn_to_str_from_liv(string str, object ob){ + return can_learn_str_from_liv(str, ob); +} + +mixed can_learn(){ + return "Syntax: learn <%^BOLD%^%^CYAN%^ability%^RESET%^> from <%^BOLD%^%^ORANGE%^person%^RESET%^>\n"; +} + +mixed do_learn_str_from_liv(string spell, object target){ + this_player()->eventLearn(target,spell); + return 1; +} + +mixed do_learn_to_str_from_liv(string spell, object target){ + return do_learn_str_from_liv(spell,target); +} diff --git a/lib/verbs/players/lie.c b/lib/verbs/players/lie.c new file mode 100644 index 0000000..d58a204 --- /dev/null +++ b/lib/verbs/players/lie.c @@ -0,0 +1,54 @@ +/* /verbs/players/lie.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 960711 + * Version: @(#) lie.c 1.4@(#) + * Last Modified: 96/12/21 + */ + +#include +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("lie"); + SetRules("down", "in OBJ", "down in OBJ", "on OBJ", "down on OBJ"); + SetErrorMessage("Lie down?"); + SetSynonyms("lay"); + SetHelp("Syntax: lie [down]\n" + " lie down in \n\n" + "Allows you to lie down on the ground or in a bed.\n" + "See also: sit, stand"); +} + +mixed can_lie_down() { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything."; + } + if( this_player()->GetPosition() == POSITION_LYING ) { + return "You are already lying down!"; + } + return 1; +} + +mixed can_lie_word_obj() { + return can_lie_down(); +} + +mixed can_lie_down_word_obj() { + return can_lie_down(); +} + +mixed do_lie_down() { + return this_player()->eventLay(); +} + +mixed do_lie_word_obj(string word, object target) { + return this_player()->eventLay(target); +} + +mixed do_lie_down_word_obj(string word, object target) { + return this_player()->eventLay(target); +} diff --git a/lib/verbs/players/marry.c b/lib/verbs/players/marry.c new file mode 100644 index 0000000..f098bc5 --- /dev/null +++ b/lib/verbs/players/marry.c @@ -0,0 +1,58 @@ +/* /verbs/players/marry.c + * from the Dead Souls Object Library + * marry + * marry LIV to LIV + * created by Descartes of Borg 951210 + */ + +#include +#include +#include "include/marry.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("marry"); + SetRules("LIV to LIV"); + SetErrorMessage("Marry whom to whom?"); + SetHelp("Syntax: marry to \n\n" + "Allows people of proper divine or legal authority to join two " + "souls in marriage. In order to marry people, you must be in an " + "appropriate location for it.\n" + "See also: divorce"); +} + +mixed can_marry_liv_to_liv() { + if( this_player()->GetSkillLevel("faith") < 5 ){ + return "You do not have enough faith to join two people."; + } + return 1; +} + +mixed do_marry_liv_to_liv(object spouse1, object spouse2) { + mixed tmp; + if( this_player() == spouse1 || this_player() == spouse2 ) + return "You may not perform a marriage on yourself."; + tmp = environment(this_player())->CanMarry(this_player(), + spouse1, spouse2); + if( !tmp ) { + this_player()->eventPrint("This place is not holy to you."); + return 1; + } + else if( stringp(tmp) ) { + this_player()->eventPrint(tmp); + return 1; + } + tmp = environment(this_player())->eventMarry(this_player(), + spouse1, spouse2); + if( tmp == 1 ) { + object ring; + ring = new(OBJ_WED_RING); + ring->SetSpouse(spouse2->GetCapName()); + ring->eventMove(spouse1); + ring = new(OBJ_WED_RING); + ring->SetSpouse(spouse1->GetCapName()); + ring->eventMove(spouse2); + } +} diff --git a/lib/verbs/players/mount.c b/lib/verbs/players/mount.c new file mode 100644 index 0000000..511b0f4 --- /dev/null +++ b/lib/verbs/players/mount.c @@ -0,0 +1,26 @@ +#include +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("mount"); + SetRules("LIV"); + SetErrorMessage("Mount something?"); + SetHelp("Syntax: mount \n\n" + "This command allows you to put yourself astride a " + "creature suitable and ready for riding.\n" + "See also: dismount, befriend, abandon"); +} + +mixed can_mount_liv() { + if(this_player()->CanManipulate()){ + return bool_reverse(this_player()->GetParalyzed()); + } +} + +mixed do_mount_liv(object ob) { + return ob->eventMount(this_player()); +} diff --git a/lib/verbs/players/news.c b/lib/verbs/players/news.c new file mode 100644 index 0000000..326cb6e --- /dev/null +++ b/lib/verbs/players/news.c @@ -0,0 +1,36 @@ +/* Lets you replay the login news. + * created by Rush@Dead Souls & Kalinash@Dead Souls + */ + +#include +#include "include/news.h" + +inherit LIB_VERB; + +static void create() { + ::create(); + SetVerb("news"); + SetRules("", "STR"); + SetErrorMessage("See \"help news\" for more info on this command."); + SetHelp("Syntax: news [|general]\n\n" + "This command allows you to replay the login news."); +} + +mixed can_news() { return can_news_str("general"); } + +mixed can_news_str(string str) { + if(!str) return 0; + if(!file_exists(DIR_NEWS + "/" + str)) return "No " + str + " news."; + if(str == "general" || this_player()->ClassMember(str)) return 1; + if(str == "welcome") return 1; + if(str == "creator" && creatorp(this_player())) return 1; + if(archp(this_player())) return 1; + return "The " + str + " news is not for your eyes."; +} + +mixed do_news() { return do_news_str("general"); } + +mixed do_news_str(string str) { + this_player()->eventPage(DIR_NEWS + "/" + str); + return 1; +} diff --git a/lib/verbs/players/nominate.c b/lib/verbs/players/nominate.c new file mode 100644 index 0000000..bd77bfd --- /dev/null +++ b/lib/verbs/players/nominate.c @@ -0,0 +1,36 @@ +/* /verbs/players/nominate.c + * from the Dead Souls Object Library + * Allows players to vote + * created by Kalinash 961021 + * Version: @(#) nominate.c 1.1@(#) Last modified: 96/10/21 + */ + +#include +#include "include/nominate.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("nominate"); + SetRules("STR"); + SetErrorMessage("Who would you like to nominate?"); + SetHelp("Syntax: nominate \n" + "Nominates a candidate for class voting."); +} + +mixed can_nominate_str() { + object env; + mixed err; + if( !(env = environment(this_player())) ) return 0; + err = env->CanNominate( this_player() ); + if( !err ) return "This doesn't seem the proper place for it."; + else return err; +} + +mixed do_nominate_str( string str ) { + object env; + + if( !str || !(env = environment(this_player())) ) return 0; + return env->eventNominate( this_player(), str ); +} diff --git a/lib/verbs/players/party.c b/lib/verbs/players/party.c new file mode 100644 index 0000000..ef4bce1 --- /dev/null +++ b/lib/verbs/players/party.c @@ -0,0 +1,145 @@ +/* /verbs/players/party.c + * from the Dead Souls Object Library + * party + * party WRD + * party WRD WRD + * party WRD LIV + * created by Descartes of Borg 951121 + */ + +#include +#include +#include "include/party.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("party"); + SetRules("WRD", "WRD WRD", "WRD LIV"); + SetErrorMessage("You must specify an action, see \"help party\"."); +} + +int livings_are_remote() { return 1; } + +mixed can_party_wrd(string cmd) { + if( !cmd ) return 0; + switch( cmd ) { + case "disband": + return PARTY_D->CanRemoveParty(this_player()); + + case "leave": + return PARTY_D->CanLeaveParty(this_player()); + + default: + return "That doesn't seem to be something you can do."; + } +} + +mixed can_party_wrd_wrd(string cmd, string party) { + if( !cmd || !party ) return 0; + if(cmd == "invite"){ + if(!party || !present(party,environment(this_player()))){ + return "That person isn't here."; + } + if(!living(present(party,environment(this_player())))){ + return "That is not a living thing."; + } + } + switch(cmd) { + case "create": + return PARTY_D->CanCreateParty(this_player(), party); + + case "join": + return PARTY_D->CanJoinParty(this_player(), party); + + default: + return "It doesn't work that way."; + } +} + +mixed can_party_wrd_liv(string cmd) { + if( !cmd ) return 0; + switch(cmd) { + case "invite": + case "leader": + case "remove": + return 1; + + default: + return "That is an unknown party action."; + } +} + +mixed do_party_wrd(string cmd) { + switch(cmd) { + case "disband": + return PARTY_D->eventRemoveParty(this_player()); + + case "leave": + return PARTY_D->eventLeaveParty(this_player()); + } +} + +mixed do_party_wrd_wrd(string cmd, string party) { + switch(cmd) { + case "create": + return PARTY_D->eventCreateParty(this_player(), party); + + case "join": + return PARTY_D->eventJoinParty(this_player(), party); + } +} + +mixed do_party_wrd_liv(string cmd, object targ) { + mixed foo; + switch(cmd) { + case "invite": + foo = PARTY_D->CanInviteMember(this_player(), targ); + break; + case "leader": + foo = PARTY_D->CanChangeLeader(this_player(), targ); + break; + case "remove": + foo = PARTY_D->CanRemoveMember(this_player(), targ); + break; + default: + return "You fail to do that."; + } + if( stringp(foo) ) + return this_player()->eventPrint(foo), 1; + if( !foo || !intp(foo) ) return foo; + switch(cmd) { + case "invite": + return PARTY_D->eventInviteMember(this_player(), targ); + + case "leader": + return PARTY_D->eventChangeLeader(this_player(), targ); + + case "remove": + return PARTY_D->eventRemoveMember(this_player(), targ); + } +} + +string GetHelp(string str) { + return ("Syntax: party create \n" + " party disband\n" + " party invite \n" + " party join \n" + " party leader \n" + " party leave\n" + " party remove \n\n" + "This command is the interface to the Dead Souls party system. " + "A party is simply a group of players who are adventuring " + "together. The advantage of a party is that it allows people " + "to share the bounties of a quest or other such venture " + "together. It allows such things as group completions of quests. " + "For example, if the party completes a quest, each member of the " + "party is credited with completing the quest. Note that in " + "order to get such credit, the party must be together upon " + "completion of the quest.\n\nNOTE: In order to invite someone " + "into your party, they must be in the same room as you. Also, " + "joining a party does not mean you automatically follow the " + "leader. To do that, you must use the \"lead\" and \"follow\" " + "commands."); +} diff --git a/lib/verbs/players/pray.c b/lib/verbs/players/pray.c new file mode 100644 index 0000000..5378742 --- /dev/null +++ b/lib/verbs/players/pray.c @@ -0,0 +1,88 @@ +/* /verbs/players/pray.c + * From Dead Souls LPMud + * Created by Descartes of Borg 961101 + * Version: @(#) pray.c 1.3@(#) + * Last modified: 96/11/03 + */ + +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("pray"); + SetRules("for STR", "for STR against STR", "for STR against STR for LIV", + "for STR for OBJ"); + SetErrorMessage("Pray for what?"); + SetHelp("Syntax: pray for \n" + " pray for against \n" + " pray for against for \n\n" + "Allows you to say a prayer to whatever deity you believe in.\n" + "See also: prayers"); +} + +mixed parse_spell(string spell){ + string s1, s2; + int ret; + object target; + if(query_verb() == "cast") return ({ "cast" }); + ret = sscanf(spell,"%s against %s",s1, s2); + if(ret != 2) ret = sscanf(spell,"%s for %s",s1, s2); + if(ret != 2) s1 = spell; + if(s2){ + target = get_object(s2); + } + return ({ s1, ( target || s2 ) }); +} + +mixed can_pray_for_str(string spell) { + object tmp; + string *tmpstr = parse_spell(spell); + tmp = SPELLS_D->GetSpell(spell); + if(!tmp) tmp = SPELLS_D->GetSpell(tmpstr[0]); + + if(!tmp){ + return 0; + } + + if( tmp ) { + string verb = tmp->GetVerb(); + if( verb != "pray" ) { + return "That is not something you pray for."; + } + } + return this_player()->CanCast(tmp); +} + +mixed can_pray_for_str_against_str(string spell) { + return can_pray_for_str(spell); +} + +mixed can_pray_for_str_for_obj(string spell) { + return can_pray_for_str(spell); +} + +mixed can_pray_for_str_against_str_for_liv(string spell) { + return can_pray_for_str(spell); +} + +mixed do_pray_for_str(string spell) { + mixed foo = parse_spell(spell); + if(sizeof(foo) == 2 && foo[1]) + return this_player()->eventPrepareCast(foo[0], foo[1]); + else return this_player()->eventPrepareCast(foo[0]); +} + +mixed do_pray_for_str_against_str(string spell, string ag) { + return this_player()->eventPrepareCast(spell, ag); +} + +mixed do_pray_for_str_for_obj(string spell, object ob) { + return this_player()->eventPrepareCast(spell, ob); +} + +mixed do_pray_for_str_against_str_for_liv(string spell, string ag, object tg) { + return this_player()->eventPrepareCast(spell, ag, tg); +} diff --git a/lib/verbs/players/request.c b/lib/verbs/players/request.c new file mode 100644 index 0000000..ee2516a --- /dev/null +++ b/lib/verbs/players/request.c @@ -0,0 +1,44 @@ +/* /verbs/players/request.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 951219 + */ + +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("request"); + SetRules("STR from LIV"); + SetErrorMessage("Request what from whom?"); + SetHelp("Syntax: request from \n\n" + "This allows you to ask livings things for particular things. " + "For example, in Newbieland, you might 'request clothes from " + "man'. This command behaves identically to 'ask LIVING for " + "SOMETHING'.\n" + "See also: ask"); +} + +mixed can_request_str_from_liv() { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything."; + } + else { + return 1; + } +} + +mixed do_request_str_from_liv(string str, object who) { + this_player()->eventPrint("You request " + str + " from " + + who->GetName() + "."); + environment(this_player())->eventPrint(this_player()->GetName() + + " requests " + str + " from " + + who->GetName() + ".", + ({ who, this_player() })); + if( !(who->eventRequest(this_player(), + remove_article(lower_case(str)))) ) + who->eventPrint(this_player()->GetName() + " requests " + + str + " from you."); + return 1; +} diff --git a/lib/verbs/players/ride.c b/lib/verbs/players/ride.c new file mode 100644 index 0000000..1a50989 --- /dev/null +++ b/lib/verbs/players/ride.c @@ -0,0 +1,81 @@ +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("ride"); + SetRules("STR", "into STR" ); + SetErrorMessage("Ride in which direction?"); + SetHelp("Syntax: ride \n" + " ride into \n\n" + "Moves your mount towards the direction you specify, or " + "into the place " + "you specify. The command \"ride into\" is synonymous with the " + "\"enter\" command.\n" + "See also: mount, dismount"); +} + +mixed can_ride_str(string str) { + object mount = environment(this_player()); + object where; + + if(mount) where = environment(mount); + if(mount && !mount->GetMount()) return "You are not mounted."; + + if( !mount ) return "You are nowhere."; + if( !where ) return "Your mount is nowhere."; + if( mount->GetStaminaPoints() <3 ) + return "Your mount is too tired to go anywhere right now."; + if(!stringp(hobbled(mount))) return "Your mount is incapacitated."; + if(str) switch(str){ + case "n" : str = "north"; break; + case "s" : str = "south"; break; + case "e" : str = "east"; break; + case "w" : str = "west"; break; + case "u" : str = "up"; break; + case "d" : str = "down"; break; + case "ne" : str = "northeast"; break; + case "nw" : str = "northwest"; break; + case "se" : str = "southeast"; break; + case "sw" : str = "southwest"; break; + } + return where->CanGo(mount, str); +} + +mixed can_ride_into_str(string str) { + object mount = environment(this_player()); + object where; + + if(mount) where = environment(mount); + if(mount && !mount->GetMount()) return "You are not mounted."; + + if( !mount ) return "You are nowhere."; + if( !where ) return "Your mount is nowhere."; + if( mount->GetStaminaPoints() <3 ) + return "Your mount is too tired to go anywhere right now."; + if(!stringp(hobbled(mount))) return "Your mount is incapacitated."; + return where->CanEnter(mount, str); +} + +mixed do_ride_str(string str) { + object mount = environment(this_player()); + if(str) switch(str){ + case "n" : str = "north"; break; + case "s" : str = "south"; break; + case "e" : str = "east"; break; + case "w" : str = "west"; break; + case "u" : str = "up"; break; + case "d" : str = "down"; break; + case "ne" : str = "northeast"; break; + case "nw" : str = "northwest"; break; + case "se" : str = "southeast"; break; + case "sw" : str = "southwest"; break; + } + return mount->eventRide(str); +} + +mixed do_ride_into_str(string str) { + object mount = environment(this_player()); + return mount->eventRide("into" + str); +} diff --git a/lib/verbs/players/sink.c b/lib/verbs/players/sink.c new file mode 100644 index 0000000..0690fe2 --- /dev/null +++ b/lib/verbs/players/sink.c @@ -0,0 +1,42 @@ +#include +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("sink"); + SetRules("", "down"); + SetErrorMessage("Sink down?"); + SetHelp("Syntax: sink [down]\n" + "Allows you to stop swimming, or otherwise attempt to " + "sink in your current medium.\n" + "See also: sit, lie, stand, swim, fly"); +} + +mixed can_sink_down() { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything!"; + } + if(this_player()->CanSink()){ + return "You can't sink here."; + } + if( this_player()->GetPosition() == POSITION_FLOATING ) { + return "You are already floating!"; + } + return 1; +} + +mixed can_sink(){ + return can_sink_down(); +} + +mixed do_sink_down(){ + this_player()->SetPosition(POSITION_FLOATING); + return this_player()->eventSink(); +} + +mixed do_sink() { + return do_sink_down(); +} diff --git a/lib/verbs/players/sit.c b/lib/verbs/players/sit.c new file mode 100644 index 0000000..421f2b2 --- /dev/null +++ b/lib/verbs/players/sit.c @@ -0,0 +1,83 @@ +/* /verbs/players/sit.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 960711 + * Version: @(#) sit.c 1.7@(#) + * Last Modified: 96/12/21 + */ + +#include +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("sit"); + SetRules("", "up","down", "down in OBJ", "down on OBJ", "in OBJ", "on OBJ"); + SetErrorMessage("Sit down?"); + SetHelp("Syntax: sit [down]\n" + " sit down in \n\n" + "Allows you to sit down on the ground or in a chair-like object." + "\nSee also: lie, stand"); +} + +mixed can_sit_down() { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything!"; + } + if(!environment(this_player())->CanSit(this_player())){ + return "You can't sit here."; + } + if( this_player()->GetPosition() == POSITION_SITTING ) { + return "You are already seated!"; + } + if( this_player()->GetPosition() != POSITION_STANDING ) { + return "You must be standing in order to sit down!"; + } + return 1; +} + +mixed can_sit_up() { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything!"; + } + if( this_player()->GetPosition() != POSITION_LYING ) { + return "You must be lying in order to sit up!"; + } + return 1; +} + +mixed can_sit(){ + if(this_player()->GetPosition() == POSITION_LYING) return can_sit_up(); + else return can_sit_down(); +} + +mixed can_sit_word_obj() { + return can_sit_down(); +} + +mixed can_sit_down_word_obj() { + return can_sit_down(); +} + +mixed do_sit(){ + return this_player()->eventSit(); +} + +mixed do_sit_down() { + return this_player()->eventSit(); +} + +mixed do_sit_up() { + return this_player()->eventSit(); +} + + +mixed do_sit_word_obj(string word, object target) { + return this_player()->eventSit(target); +} + +mixed do_sit_down_word_obj(string word, object target) { + return this_player()->eventSit(target); +} diff --git a/lib/verbs/players/sleep.c b/lib/verbs/players/sleep.c new file mode 100644 index 0000000..979da00 --- /dev/null +++ b/lib/verbs/players/sleep.c @@ -0,0 +1,33 @@ +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("sleep"); + SetRules(""); + SetErrorMessage("Sleep?"); + SetSynonyms("go to sleep"); + SetHelp("Syntax: sleep\n" + "If lying down, you fall asleep. If not, you collapse " + "asleep. Being attacked will usually wake you up, " + "otherwise you will awaken after a few minutes, stronger " + "and more refreshed."); +} + +mixed can_sleep() { + if( !creatorp(this_player()) && this_player()->GetCaffeine() > 10 ) { + return "You are too wired to sleep right now."; + } + if(this_player()->GetRace()=="elf") return "Elves don't sleep."; + + return 1; +} + +mixed do_sleep() { + tell_player(this_player(),"You fall asleep."); + tell_room(environment(this_player()), this_player()->GetName()+ + " closes "+possessive(this_player())+" eyes and appears to "+ + "lose consciousness.", ({this_player()}) ); + return this_player()->SetSleeping(random(10)+5); +} diff --git a/lib/verbs/players/stand.c b/lib/verbs/players/stand.c new file mode 100644 index 0000000..d787d1f --- /dev/null +++ b/lib/verbs/players/stand.c @@ -0,0 +1,54 @@ +/* /verbs/players/stand.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 960711 + * Version: @(#) stand.c 1.5@(#) + * Last Modified: 96/12/21 + */ + +#include +#include +#include + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("stand"); + SetRules("", "up"); + SetErrorMessage("Stand up?"); + SetSynonyms("get up"); + SetHelp("Syntax: stand [up]\n" + "When sitting down or lying down, you can get up in this " + "most intuitive manner.\n" + "See also: lie, sit"); +} + +mixed can_stand_up() { + if( this_player()->GetParalyzed() ) { + return "You cannot do anything."; + } + if(RACES_D->GetLimblessRace(this_player()->GetRace()) ){ + return "You aren't endowed with limbs with which to stand."; + } + + if(!environment(this_player())->CanStand(this_player())){ + return "You can't stand here."; + } + + if( this_player()->GetPosition() != POSITION_STANDING ) { + return 1; + } + return "You are already standing up!"; +} + +mixed can_stand(){ + return can_stand_up(); +} + +mixed do_stand_up() { + return this_player()->eventStand(); +} + +mixed do_stand() { + return this_player()->eventStand(); +} diff --git a/lib/verbs/players/stealth.c b/lib/verbs/players/stealth.c new file mode 100644 index 0000000..7b624c2 --- /dev/null +++ b/lib/verbs/players/stealth.c @@ -0,0 +1,102 @@ +/* /verbs/players/stealth.c + * by BillGates 961109 + * allows players to move silently from room to room + */ + +#include +#include "include/stealth.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("stealth"); + SetRules("","WRD"); + SetHelp("Syntax: stealth [on | off]\n\n" + "A way to enable or disable sneakiness, if stealth is a " + "skill available to you."); +} + +mixed can_stealth() { + return this_player()->CanCastMagic(0, "stealth"); +} + +mixed can_stealth_wrd() { + return can_stealth(); +} + +mixed do_stealth() { + return do_stealth_wrd(""); +} + +mixed do_stealth_wrd(string args) { + object caster = this_player(); + object env = environment(caster); + + int skill = this_agent()->GetSkillLevel("stealth"); + if( skill < 20 ) { + caster->eventPrint("You are not devious enough."); + return 1; + } + + + if( args == "on" ) { + if( caster->GetStaminaPoints() < 50 ) { + caster->eventPrint("You are too tired to move silently.",env); + env->eventPrint(caster->GetName() + " looks tired.",caster); + return 0; + } + + + if( caster->GetInCombat() ) { + caster->eventPrint("You are too busy fighting at the moment.",env); + return 0; + } + } + eventStealth(caster, args, skill); + return 1; +} + + +int eventStealth(object caster, string args, int skill) { + + if( !(caster) ) return 0; + + if( !environment(caster) ) { + caster->eventPrint("You are nowhere."); + return 0; + } + + if(args == "") { + if(caster->GetProperty("stealthy")) { + caster->eventPrint("You are currently moving silently."); + } + else caster->eventPrint("You are moving as noisily as ever."); + return 1; + } + + if(args == "on") { + if(caster->GetProperty("stealthy")) { + caster->eventPrint("You are already moving quietly!"); + return 0; + } + caster->SetProperty("stealthy",1); + caster->eventPrint("%^RED%^You begin to sneak around."); + caster->AdStaminaPoints(-30 - random(40)); + caster->AddSkillPoints("stealth",skill*skill/8); + return 1; + } + + if(args == "off") { + if(caster->GetProperty("stealthy")) { + caster->SetProperty("stealthy",0); + caster->eventPrint("%^BOLD%^%^CYAN%^You stop your sneaky ways.", + environment(caster)); + return 1; + } + else caster->eventPrint("You are not currently sneaking around!"); + return 0; + } + + return 1; +} diff --git a/lib/verbs/players/target.c b/lib/verbs/players/target.c new file mode 100644 index 0000000..d1252b3 --- /dev/null +++ b/lib/verbs/players/target.c @@ -0,0 +1,86 @@ +#include +#include +#include "include/target.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("target"); + SetRules("LVS", "only LVS","LVS only"); + SetErrorMessage("Target whom?"); + SetHelp("Syntax: target \n" + " target all of \n" + " target \n\n" + "This command initiates exclusive combat with a living " + "being or group of living beings using any wielded weapons " + "or your bare hands. Anyone else in the room at the time " + "you issue this command will be ignored by you, even if " + "they attack you. \n" + "See also: attack, wimpy, ignore, attack"); +} + +mixed can_target_liv(object target) { + int pos = this_player()->GetPosition(); + + if( this_player()->GetParalyzed() ) { + return "You cannot move!"; + } + if( pos == POSITION_SITTING || pos == POSITION_LYING ) { + return "You cannot target in that position!"; + } + if( environment(this_player())->GetProperty("no target") ) { + message("environment", "A mystical force prevents your malice.", + this_player()); + return this_player()->CanManipulate(); + } + return this_player()->CanManipulate(); +} + +mixed can_target_only_liv(object target){ + return can_target_liv(target); +} + +mixed can_target_liv_only(object target){ + return can_target_liv(target); +} + +mixed do_target_liv(object target) { + return do_target_lvs(({ target }), 1); +} + +mixed do_target_only_liv(object target){ + return do_target_lvs(({ target }), 1); +} + +mixed do_target_liv_only(object target){ + return do_target_lvs(({ target }), 1); +} + +varargs mixed do_target_lvs(mixed *targets, int exclusive) { + object *obs; + object *notarget; + string tmp; + + notarget = ({}); + obs = filter(targets, (: objectp :)); + if( !sizeof(obs) ) { + mixed *ua; + + ua = unique_array(targets, (: $1 :)); + foreach(string *lines in ua) this_player()->eventPrint(lines[0]); + return 1; + } + foreach(object entity in get_livings(environment(this_player()))){ + if(member_array(entity,obs) == -1) notarget += ({ entity }); + } + if(sizeof(notarget)) this_player()->AddNonTargets(notarget); + this_player()->SetAttack(obs); + tmp = item_list(obs); + obs->eventPrint(this_player()->GetName() + " targets you!"); + environment(this_player())->eventPrint(this_player()->GetName() + + " targets " + tmp + "!", + ({ this_player(), obs... })); + this_player()->eventPrint("You target " + tmp + "."); + return 1; +} diff --git a/lib/verbs/players/teach.c b/lib/verbs/players/teach.c new file mode 100644 index 0000000..4bbc728 --- /dev/null +++ b/lib/verbs/players/teach.c @@ -0,0 +1,45 @@ +#include +#include +#include + +inherit LIB_VERB; + +static void create(){ + verb::create(); + SetVerb("teach"); + SetRules("","STR to LIV","LIV to STR"); + SetErrorMessage("Syntax: teach to "); + SetHelp("Syntax: teach to \n\n" + "This command allows you to teach another person " + "an ability, spell, or skill.\nSee also: learn"); +} + +mixed can_teach_str_to_liv(string str, object ob){ + int pos = this_player()->GetPosition(); + if( this_player()->GetParalyzed() ) { + return "You cannot move!"; + } + if( pos == POSITION_SITTING || pos == POSITION_LYING && + !RACES_D->GetLimblessCombatRace(this_player()->GetRace()) ){ + return "You cannot teach in that position!"; + } + return 1; +} + +mixed can_teach_liv_to_str(object ob, string str){ + return can_teach_str_to_liv(str, ob); +} + +mixed can_teach(){ + return "Syntax: teach <%^BOLD%^%^CYAN%^ability%^RESET%^> to " + "<%^BOLD%^%^ORANGE%^person%^RESET%^>"; +} + +mixed do_teach_str_to_liv(string spell, object target){ + this_player()->eventOfferTeaching(target,spell); + return 1; +} + +mixed do_teach_liv_to_str(object target, string spell){ + return do_teach_str_to_liv(spell,target); +} diff --git a/lib/verbs/players/vote.c b/lib/verbs/players/vote.c new file mode 100644 index 0000000..78adee9 --- /dev/null +++ b/lib/verbs/players/vote.c @@ -0,0 +1,35 @@ +/* /verbs/players/vote.c + * from the Dead Souls Object Library + * Allows players to vote + * created by Kalinash 961021 + * Version: @(#) vote.c 1.1@(#) Last modified: 96/10/21 + */ + +#include +#include "include/vote.h" + +inherit LIB_VERB; + +static void create(){ + verb::create(); + SetVerb("vote"); + SetRules("for STR"); + SetErrorMessage("For whom would you like to vote?"); + SetHelp("Syntax: vote for \n\n" + "Casts your vote for a candidate if in a voting place."); +} + +mixed can_vote_for_str(){ + object env; + mixed err; + if( !(env = environment(this_player())) ) return 0; + err = env->CanVote( this_player() ); + if( !err ) return "This doesn't seem the proper place for it."; + else return err; +} + +mixed do_vote_for_str( string str ){ + object env; + if( !str || !(env = environment(this_player())) ) return 0; + return env->eventVote( this_player(), str ); +} diff --git a/lib/verbs/players/wake.c b/lib/verbs/players/wake.c new file mode 100644 index 0000000..30b3095 --- /dev/null +++ b/lib/verbs/players/wake.c @@ -0,0 +1,43 @@ +#include + +inherit LIB_VERB; + +static void create(){ + verb::create(); + SetVerb("wake"); + SetRules(""); + SetErrorMessage("Wake?"); + SetSynonyms(({"wake up","awaken","unsleep"})); + SetHelp("Syntax: wake\n" + "If asleep, you become less so."); +} + +mixed can_wake(){ + if( this_player()->GetAlcohol() > 70 ) { + return "You are too drunk to wake right now."; + } + if(this_player()->GetSleeping() < 1) { + return "You are already awake."; + } + return 1; +} + +mixed do_wake(){ + if(creatorp(this_player())){ + this_player()->SetSleeping(0); + tell_player(this_player(),"You rouse from your slumber."); + tell_room(environment(this_player()), this_player()->GetName()+ + " rouses from "+possessive(this_player())+ + " slumber.", ({this_player()}) ); + return 1; + } + if(this_player()->GetSleeping() > 1){ + tell_player(this_player(),"You become somewhat more wakeful."); + tell_room(environment(this_player()), this_player()->GetName()+ + " appears to rouse somewhat from "+possessive(this_player())+ + " slumber.", ({this_player()}) ); + return this_player()->SetSleeping(this_player()->GetSleeping() - 1); + } + else tell_player(this_player(),"You are nearing full wakefulness..."); + return 1; +} diff --git a/lib/verbs/players/withdraw.c b/lib/verbs/players/withdraw.c new file mode 100644 index 0000000..749520e --- /dev/null +++ b/lib/verbs/players/withdraw.c @@ -0,0 +1,34 @@ +/* /verbs/players/withdraw.c + * from the Dead Souls Object Library + * Allows players to withdraw from elections + * created by Kalinash 961021 + * Version: @(#) withdraw.c 1.1@(#) Last modified: 96/10/21 + */ + +#include +#include "include/withdraw.h" + +inherit LIB_VERB; + +static void create(){ + verb::create(); + SetVerb("withdraw"); + SetRules(""); + SetHelp("Syntax: withdraw\n\n" + "Allows you to withdraw from the elections."); +} + +mixed can_withdraw(){ + object env; + mixed err; + if( !(env = environment(this_player())) ) return 0; + err = env->CanWithdraw( this_player() ); + if( !err ) return "This doesn't seem the proper place for it."; + else return err; +} + +mixed do_withdraw(){ + object env; + if( !(env = environment(this_player())) ) return 0; + return env->eventWithdraw( this_player() ); +} diff --git a/lib/verbs/rooms/climb.c b/lib/verbs/rooms/climb.c new file mode 100644 index 0000000..2c67342 --- /dev/null +++ b/lib/verbs/rooms/climb.c @@ -0,0 +1,97 @@ +/* /verbs/items/climb.c + * from the Dead Souls Mud Library + * climb WRD OBJ + * created by Descartes of Borg 951018 + * Version: @(#) climb.c 1.3@(#) + * Last modified: 96/10/20 + */ + +#include +#include +#include + +inherit LIB_VERB; + +mixed do_climb_word_obj(string word, object ob); + +static void create(){ + verb::create(); + SetVerb("climb"); + SetErrorMessage("Climb up or down what?"); + SetRules("up OBJ", "down OBJ", "out of OBJ", "out OBJ", "into OBJ", + "in OBJ", "through OBJ", "OBJ", "out", "down"); + SetHelp("Syntax: climb \n" + " climb up \n" + " climb down \n" + " climb out of \n" + " climb into \n" + " climb through \n" + " climb out\n\n" + "Allows you to use another object to climb down or out of an " + "area.\n" + "See also: enter, go, jump"); +} + +mixed can_climb_obj(){ + if( this_player()->GetParalyzed() ) { + return "You cannot do anything!"; + } + if(!stringp(hobbled(this_player()))){ + return "Your injuries prevent that movement."; + } + return this_player()->CanManipulate(); +} + +mixed can_climb_word_obj(){ + return can_climb_obj(); +} + +mixed can_climb_out_of_obj(){ + return can_climb_obj(); +} + +mixed can_climb_out(){ + return can_climb_obj(); +} + +mixed can_climb_down(){ + return can_climb_obj(); +} + +mixed can_climb_up(){ + return can_climb_obj(); +} + +mixed do_climb_obj(object ob){ + return do_climb_word_obj("up", ob); +} + +mixed do_climb_word_obj(string word, object ob, mixed args...){ + int type; + switch(word) { + case "up": type = CLIMB_UP; break; + case "down": type = CLIMB_DOWN; break; + case "out": type = CLIMB_OUT; break; + case "in": case "into": type = CLIMB_INTO; break; + case "through": type = CLIMB_THROUGH;break; + default: type = CLIMB_UP; break; + } + return ob->eventClimb(this_player(), type); +} + +mixed do_climb_out_of_obj(object ob) { + return do_climb_word_obj("out", ob); +} + +mixed do_climb_out(object ob){ + return do_climb_word_obj("out", (ob || environment(this_player()))); +} + +mixed do_climb_up(object ob){ + return do_climb_word_obj("up", (ob || environment(this_player()))); +} + +mixed do_climb_down(object ob){ + return do_climb_word_obj("down", (ob || environment(this_player()))); +} + diff --git a/lib/verbs/rooms/enter.c b/lib/verbs/rooms/enter.c new file mode 100644 index 0000000..5009eb7 --- /dev/null +++ b/lib/verbs/rooms/enter.c @@ -0,0 +1,44 @@ +/* /verbs/rooms/enter.c + * from the Dead Souls Mud Library + * created by Descartes of Borg 951104 + * Version: @(#) enter.c 1.2@(#) + * Last modified: 96/10/15 + */ + +#include +#include "include/enter.h" + +inherit LIB_VERB; + +static void create(){ + verb::create(); + SetVerb("enter"); + SetRules("into OBJ", "OBJ"); + SetErrorMessage("Enter what?"); + SetHelp("Syntax: enter \n" + " enter into \n\n" + "Moves you into the place you specify. Whereas the \"go\" " + "command is designed for motion towards something, the " + "\"enter\" command is designed for motion into something.\n" + "See also: go"); +} + +mixed can_enter_obj(){ + if( this_player()->GetParalyzed() ){ + return "You cannot do anything."; + } + if(!stringp(hobbled(this_player()))) return "Your injuries prevent easy movement. Perhaps you should try crawling."; + return 1; +} + +mixed can_enter_into_obj(){ + return can_enter_obj(); +} + +mixed do_enter_obj(object targ, string what){ + return targ->eventEnter(this_player(), remove_article(lower_case(what))); +} + +mixed do_enter_into_obj(object targ, string what) { + do_enter_obj(targ, what); +} diff --git a/lib/verbs/rooms/fish.c b/lib/verbs/rooms/fish.c new file mode 100644 index 0000000..174e04b --- /dev/null +++ b/lib/verbs/rooms/fish.c @@ -0,0 +1,38 @@ +/* /verbs/rooms/fish.c + * from the Dead Souls Mud Library + * fish with OBJ + * created by Descartes of Borg 951016 + */ + +#include +#include "include/fish.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("fish"); + SetRules("with OBJ"); + SetErrorMessage("Fish with what?"); + SetHelp("Syntax: fish with \n\n" + "Starts you fishing so long as OBJ is something you can fish " + "with and you are in a place that allows fishing.\n" + "See also: stop"); +} + +mixed can_fish_with_obj(){ + object env; + mixed err; + if( !(env = environment(this_player())) ) return 0; + err = env->CanCast(this_player()); + if( err == 1 ) return this_player()->CanManipulate(); + else if( !err ) return "It doesn't look like there is much fishing here."; + else return err; +} + +mixed do_fish_with_obj(object ob){ + object env; + mixed err; + if( !ob || !(env = environment(this_player())) ) return 0; + if( err = env->eventCast(this_player(), ob) ) return err; +} diff --git a/lib/verbs/rooms/fly.c b/lib/verbs/rooms/fly.c new file mode 100644 index 0000000..8ee8f4e --- /dev/null +++ b/lib/verbs/rooms/fly.c @@ -0,0 +1,103 @@ +/* /verbs/rooms/fly.c + * from the Dead Souls Mud Library + * Like go, except for flying around + * created by Descartes of Borg 961013 + * Version: @(#) fly.c 1.2@(#) + * Last modified: 96/10/13 + */ + +#include +#include +#include +#include +#include "include/fly.h" + +inherit LIB_VERB; + +static void create(){ + verb::create(); + SetVerb("fly"); + SetRules("", "STR", "into STR"); + SetErrorMessage("Fly in which direction?"); + SetHelp("Syntax: fly [DIRECTION]\n" + " fly into \n\n" + "Moves you towards the direction you specify, or into the place " + "you specify. The command \"fly into\" is synonymous with the " + "\"enter\" command.\n" + "See also: climb, enter, go, jump, swim"); +} + +int StaminaCost(){ + int cost = 15; + int bonus = this_player()->GetStatLevel("durability")/10; + bonus += this_player()->GetStatLevel("coordination")/20; + bonus += this_player()->GetFood()/40; + bonus += this_player()->GetDrink()/40; + cost -= bonus; + if(cost < 1) cost = 1; + return cost; +} + +mixed can_fly(){ + object env = environment(this_player()); + if( !env ){ + return "You are nowhere to begin with!"; + } + if(this_player()->GetPosition() == POSITION_FLYING) + return "You are already flying."; + if(env->CanFly(this_player())) return this_player()->CanFly(); + return "You can't fly here."; +} + +mixed can_fly_str(string str){ + object env = environment(this_player()); + int envpos = env->GetPosition(); + if( !env ){ + return "You are nowhere."; + } + if( this_player()->GetStaminaPoints() < 15 ){ + return "You are too tired to fly anywhere right now."; + } + if(env->CanFly(this_player(), str)){ + if(envpos == POSITION_FLYING) return 1; + return this_player()->CanFly(); + } + if(this_player()->GetPosition() != POSITION_FLYING && + envpos != POSITION_FLYING){ + return "You are not flying."; + } + return 0; +} + +mixed can_fly_into_str(string str){ + object env = environment(this_player()); + int envpos = env->GetPosition(); + if( !env ){ + return "You are nowhere."; + } + if( this_player()->GetStaminaPoints() < 3 ) + return "You are too tired right now."; + if(environment(this_player())->CanEnter(this_player(), str)){ + if(envpos == POSITION_FLYING) return 1; + return this_player()->CanFly(); + } + if(this_player()->GetPosition() != POSITION_FLYING && + envpos != POSITION_FLYING){ + return "You are not flying."; + } + else return 0; +} + +mixed do_fly(){ + return this_player()->eventFly(); +} + +mixed do_fly_str(string str){ + this_player()->AddStaminaPoints(-StaminaCost()); + return environment(this_player())->eventGo(this_player(), str); +} + +mixed do_fly_into_str(string str){ + this_player()->AddStaminaPoints(-StaminaCost()); + return environment(this_player())->eventEnter(this_player(), str); +} diff --git a/lib/verbs/rooms/go.c b/lib/verbs/rooms/go.c new file mode 100644 index 0000000..6704355 --- /dev/null +++ b/lib/verbs/rooms/go.c @@ -0,0 +1,50 @@ +/* /verbs/rooms/go.c + * from the Dead Souls Mud Library + * go STR + * go into STR + * created by Descartes of Borg 951104 + */ + +#include +#include "include/go.h" + +inherit LIB_VERB; + +static void create(){ + verb::create(); + SetVerb("go"); + SetRules("STR", "into STR"); + SetErrorMessage("Go in which direction?"); + SetHelp("Syntax: go \n" + " go into \n\n" + "Moves you towards the direction you specify, or into the place " + "you specify. The command \"go into\" is synonymous with the " + "\"enter\" command. Note that most directions are pre-aliased " + "for you to the proper \"go\" commands. For example, " + "\"go south\" has been pre-aliased to \"s\".\n" + "See also: climb, enter, jump, fly, swim"); +} + +mixed can_go_str(string str){ + if( !environment(this_player()) ) return "You are nowhere."; + if( this_player()->GetStaminaPoints() <3 ) + return "You are too tired to go anywhere right now."; + if(!stringp(hobbled(this_player()))) return "Your injuries prevent easy movement. Perhaps you should try crawling."; + return environment(this_player())->CanGo(this_player(), str); +} + +mixed can_go_into_str(string str){ + if( !environment(this_player()) ) return "You are nowhere."; + if( this_player()->GetStaminaPoints() <3 ) + return "You are too tired right now."; + if(!stringp(hobbled(this_player()))) return "Your injuries prevent easy movement. Perhaps you should try crawling."; + return environment(this_player())->CanEnter(this_player(), str); +} + +mixed do_go_str(string str){ + return environment(this_player())->eventGo(this_player(), str); +} + +mixed do_go_into_str(string str){ + return environment(this_player())->eventEnter(this_player(), str); +} diff --git a/lib/verbs/rooms/include/buy.h b/lib/verbs/rooms/include/buy.h new file mode 100644 index 0000000..72e86b2 --- /dev/null +++ b/lib/verbs/rooms/include/buy.h @@ -0,0 +1,9 @@ +#ifndef l_buy_h +#define l_buy_h + +static void create(); +mixed can_buy_str_from_liv(string str); + +mixed do_buy_str_from_liv(string str, object vendor); + +#endif /* l_buy_h */ diff --git a/lib/verbs/rooms/include/cast.h b/lib/verbs/rooms/include/cast.h new file mode 100644 index 0000000..1e61e96 --- /dev/null +++ b/lib/verbs/rooms/include/cast.h @@ -0,0 +1,9 @@ +#ifndef l_cast_h +#define l_cast_h + +static void create(); +mixed can_cast_obj(object ob); +mixed do_cast_obj(object ob); +string help(string str); + +#endif /* l_cast_h */ diff --git a/lib/verbs/rooms/include/climb.h b/lib/verbs/rooms/include/climb.h new file mode 100644 index 0000000..6af47dc --- /dev/null +++ b/lib/verbs/rooms/include/climb.h @@ -0,0 +1,14 @@ +#ifndef l_climb_h +#define l_climb_h + +static void create(); + +mixed can_climb_obj(string verb); +mixed can_climb_word_obj(string verb, string word); +mixed can_climb_out_of_obj(string verb); + +mixed do_climb_obj(object ob, string id); +mixed do_climb_word_obj(string word, object ob, string id); +mixed do_climb_out_of_obj(object ob, string id); + +#endif /* l_climb_h */ diff --git a/lib/verbs/rooms/include/enter.h b/lib/verbs/rooms/include/enter.h new file mode 100644 index 0000000..e4ab6a4 --- /dev/null +++ b/lib/verbs/rooms/include/enter.h @@ -0,0 +1,13 @@ +#ifndef l_enter_h +#define l_enter_h + +static void create(); +mixed can_enter(); +mixed can_enter_str(string str); +mixed can_enter_into_str(string str); +mixed do_enter(); +mixed do_enter_str(string str); +mixed do_enter_into_str(string str); +string GetHelp(string str); + +#endif /* l_enter_h */ diff --git a/lib/verbs/rooms/include/fish.h b/lib/verbs/rooms/include/fish.h new file mode 100644 index 0000000..8dc5237 --- /dev/null +++ b/lib/verbs/rooms/include/fish.h @@ -0,0 +1,10 @@ +#ifndef l_fish_h +#define l_fish_h + +static void create(); + +mixed can_fish_with_obj(); + +mixed do_fish_with_obj(object ob); + +#endif /* l_fish_h */ diff --git a/lib/verbs/rooms/include/fly.h b/lib/verbs/rooms/include/fly.h new file mode 100644 index 0000000..b839768 --- /dev/null +++ b/lib/verbs/rooms/include/fly.h @@ -0,0 +1,12 @@ +#ifndef l_fly_h +#define l_fly_h + +static void create(); + +mixed can_fly_str(string str); +mixed can_fly_into_str(string str); + +mixed do_fly_str(string str); +mixed do_fly_into_str(string str); + +#endif /* l_fly_h */ diff --git a/lib/verbs/rooms/include/go.h b/lib/verbs/rooms/include/go.h new file mode 100644 index 0000000..8a271ee --- /dev/null +++ b/lib/verbs/rooms/include/go.h @@ -0,0 +1,12 @@ +#ifndef l_go_h +#define l_go_h + +static void create(); + +mixed can_go_str(string str); +mixed can_go_into_str(string str); + +mixed do_go_str(string str); +mixed do_go_into_str(string str); + +#endif /* l_go_h */ diff --git a/lib/verbs/rooms/include/jump.h b/lib/verbs/rooms/include/jump.h new file mode 100644 index 0000000..f386986 --- /dev/null +++ b/lib/verbs/rooms/include/jump.h @@ -0,0 +1,21 @@ +#ifndef l_jump_h +#define l_jump_h + +static void create(); + +mixed can_jump_word_obj(); +mixed can_jump_word_word_obj(); + +varargs mixed do_jump_in_obj(object ob, mixed *args...); +varargs mixed do_jump_into_obj(object ob, mixed *args...); +varargs mixed do_jump_off_obj(object ob, mixed *args...); +varargs mixed do_jump_off_of_obj(object ob, mixed *args...); +varargs mixed do_jump_from_obj(object ob, mixed *args...); +varargs mixed do_jump_through_obj(object ob, mixed *args...); +varargs mixed do_jump_across_obj(object ob, mixed *args...); +varargs mixed do_jump_over_obj(object ob, mixed *args...); +varargs mixed do_jump_onto_obj(object ob, mixed *args...); +varargs mixed do_jump_on_obj(object ob, mixed *args...); + +#endif /* l_jump_h */ + diff --git a/lib/verbs/rooms/include/sell.h b/lib/verbs/rooms/include/sell.h new file mode 100644 index 0000000..e4e045b --- /dev/null +++ b/lib/verbs/rooms/include/sell.h @@ -0,0 +1,11 @@ +#ifndef l_sell_h +#define l_sell_h + +static void create(); +mixed can_sell(); +mixed can_sell_obj_to_liv(object ob, object vendor); +mixed do_sell(); +mixed do_sell_obj_to_liv(object ob, object vendor); +string GetHelp(string str); + +#endif /* l_sell_h */ diff --git a/lib/verbs/rooms/include/stop.h b/lib/verbs/rooms/include/stop.h new file mode 100644 index 0000000..e180fd8 --- /dev/null +++ b/lib/verbs/rooms/include/stop.h @@ -0,0 +1,9 @@ +#ifndef l_stop_h +#define l_stop_h + +static void create(); +mixed can_stop_str(string str); +mixed do_stop_str(string str); +string GetHelp(string str); + +#endif /* l_stop_h */ diff --git a/lib/verbs/rooms/include/swim.h b/lib/verbs/rooms/include/swim.h new file mode 100644 index 0000000..89a16dd --- /dev/null +++ b/lib/verbs/rooms/include/swim.h @@ -0,0 +1,12 @@ +#ifndef l_fly_h +#define l_fly_h + +static void create(); + +mixed can_swim_str(string str); +mixed can_swim_into_str(string str); + +mixed do_swim_str(string str); +mixed do_swim_into_str(string str); + +#endif /* l_fly_h */ diff --git a/lib/verbs/rooms/jump.c b/lib/verbs/rooms/jump.c new file mode 100644 index 0000000..a5d43d8 --- /dev/null +++ b/lib/verbs/rooms/jump.c @@ -0,0 +1,106 @@ +/* /verbs/rooms/jump.c + * from the Dead Souls Mud Library + * jump in OBJ + * jump into OBJ + * jump off OBJ + * jump off of OBJ + * jump from OBJ + * jump through OBJ + * jump across OBJ + * jump over OBJ + * jump onto OBJ + * jump on OBJ + * go ahead and jump + * might as well jump + * created by Descartes of Borg 960117 + */ + +#include +#include +#include "include/jump.h" + +inherit LIB_VERB; + +static void create() { + verb::create(); + SetVerb("jump"); + SetRules("in OBJ", "into OBJ", "off OBJ", "off of OBJ", "from OBJ", + "through OBJ", "across OBJ", "over OBJ", "onto OBJ", "on OBJ"); + SetSynonyms("leap"); + SetErrorMessage("Jump from, into, over, on, or through something?"); + SetHelp("Syntax: jump into \n" + " jump off \n" + " jump through \n" + " jump over \n" + " jump on \n\n" + "These six different syntaxes actually represent three very " + "different types of motion. They are thus often used in very " + "different circumstances. All of them do, however, allow you " + "to jump.\n" + "Synonyms: leap\n" + "See also: enter, go"); +} + +mixed can_jump_word_obj(){ + if(!stringp(hobbled(this_player()))){ + return "Your injuries prevent that movement."; + } + return 1; +} + +mixed can_jump_word_word_obj(){ + if(!stringp(hobbled(this_player()))){ + return "Your injuries prevent that movement."; + } + return 1; +} + +varargs mixed do_jump_in_obj(object ob, mixed *args...){ + return do_jump_into_obj(ob, args...); +} + +varargs mixed do_jump_into_obj(object ob, mixed *args...){ + string id; + id = remove_article(lower_case(args[0])); + return ob->eventJump(this_player(), id, JUMP_INTO); +} + +varargs mixed do_jump_off_obj(object ob, mixed *args...){ + return do_jump_from_obj(ob, args...); +} + +varargs mixed do_jump_off_of(object ob, mixed *args...){ + return do_jump_off_of_obj(ob, args...); +} + +varargs mixed do_jump_from_obj(object ob, mixed *args...){ + string id; + id = remove_article(lower_case(args[0])); + return ob->eventJump(this_player(), id, JUMP_FROM); +} + +varargs mixed do_jump_through_obj(object ob, mixed *args...){ + string id; + id = remove_article(lower_case(args[0])); + return ob->eventJump(this_player(), id, JUMP_THROUGH); +} + +varargs mixed do_jump_across_obj(object ob, mixed *args...){ + return do_jump_over_obj(ob, args...); +} + +varargs mixed do_jump_over_obj(object ob, mixed *args...){ + string id; + id = remove_article(lower_case(args[0])); + return ob->eventJump(this_player(), id, JUMP_OVER); +} + +varargs mixed do_jump_onto_obj(object ob, mixed *args...){ + return do_jump_on_obj(ob, args...); +} + +varargs mixed do_jump_on_obj(object ob, mixed *args...){ + string id; + id = remove_article(lower_case(args[0])); + return ob->eventJump(this_player(), id, JUMP_ON); +} diff --git a/lib/verbs/rooms/stop.c b/lib/verbs/rooms/stop.c new file mode 100644 index 0000000..f0a113a --- /dev/null +++ b/lib/verbs/rooms/stop.c @@ -0,0 +1,30 @@ +/* /verbs/rooms/stop.c + * from the Dead Souls Mud Library + * stop STR + * created by Descartes of Borg 951016 + */ + +#include +#include "include/stop.h" + +inherit LIB_VERB; + +static void create(){ + verb::create(); + SetVerb("stop"); + SetRules("STR"); +} + +mixed can_stop_str(string str){ + return this_player()->CanStop(this_player(), str); +} + +mixed do_stop_str(string str){ + return this_player()->eventStop(this_player(), str); +} + +string GetHelp(){ + return ("Syntax: stop [ fishing | fighting ]\n\n" + "Puts an end to the specified activity.\n" + "See also: fish, attack"); +} diff --git a/lib/verbs/rooms/swim.c b/lib/verbs/rooms/swim.c new file mode 100644 index 0000000..3e85db4 --- /dev/null +++ b/lib/verbs/rooms/swim.c @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include "include/swim.h" + +inherit LIB_VERB; + +static void create(){ + verb::create(); + SetVerb("swim"); + SetRules("", "STR", "into STR"); + SetErrorMessage("Swim in which direction?"); + SetHelp("Syntax: swim \n" + " swim into \n\n" + "Moves you towards the direction you specify, or into the place " + "you specify. The command \"swim into\" is synonymous with the " + "\"enter\" command.\n" + "See also: fly, climb, enter, go, jump"); +} + +int StaminaCost(){ + int cost = 20; + int bonus = this_player()->GetStatLevel("durability")/10; + bonus += this_player()->GetStatLevel("strength")/20; + bonus += this_player()->GetFood()/40; + bonus += this_player()->GetDrink()/40; + cost -= bonus; + if(cost < 1) cost = 1; + return cost; +} + +mixed can_swim(){ + object env = environment(this_player()); + if( !env ){ + return "You are nowhere to begin with!"; + } + if(this_player()->GetPosition() == POSITION_SWIMMING) + return "You are already swimming."; + if(!RACES_D->CanSwim(this_player()->GetRace())){ + return capitalize(pluralize(this_player()->GetRace()))+" cannot swim."; + } + if(env->CanSwim(this_player())) return this_player()->CanSwim(); + return "You can't swim here."; +} + +mixed can_swim_str(string str){ + object env = environment(this_player()); + int envpos = env->GetPosition(); + if( !env ){ + return "You are nowhere."; + } + if( this_player()->GetStaminaPoints() < 15 ){ + return "You are too tired to swim anywhere right now."; + } + if(env->CanSwim(this_player(), str)){ + if(envpos == POSITION_SWIMMING) return 1; + return this_player()->CanSwim(); + } + if(this_player()->GetPosition() != POSITION_SWIMMING && + envpos != POSITION_SWIMMING){ + return "You are not swimming."; + } + return 0; +} + +mixed can_swim_into_str(string str){ + object env = environment(this_player()); + int envpos = env->GetPosition(); + if( !env ){ + return "You are nowhere."; + } + if( this_player()->GetStaminaPoints() < 3 ) + return "You are too tired right now."; + if(environment(this_player())->CanEnter(this_player(), str)){ + if(envpos == POSITION_SWIMMING) return 1; + return this_player()->CanSwim(); + } + if(this_player()->GetPosition() != POSITION_SWIMMING && + envpos != POSITION_SWIMMING){ + return "You are not swimming."; + } + return 0; +} + +mixed do_swim(){ + return this_player()->eventSwim(); +} + +mixed do_swim_str(string str){ + this_player()->AddStaminaPoints(-StaminaCost()); + return environment(this_player())->eventGo(this_player(), str); +} + +mixed do_swim_into_str(string str){ + this_player()->AddStaminaPoints(-StaminaCost()); + return environment(this_player())->eventEnter(this_player(), str); +} diff --git a/lib/www/articles.html b/lib/www/articles.html new file mode 100644 index 0000000..93abe31 --- /dev/null +++ b/lib/www/articles.html @@ -0,0 +1,21 @@ + + + + + Dead Souls Articles + + + + +
Dead Souls Articles

No, this page isn't about parts of speech. Occasionally
I'll wax long-winded, and my rantings can qualify as free-standing
articles on a subject. This page allows me to separate that from
the rest of the site, so you can read my rants if you want,
or avoid them if you prefer.

These articles tend to be opinions, not technical
docs, so you can skip them without feeling pain.

If folks submit articles they've written they'd like
me to post here, I'll gladly accept them for consideration.

An Open Letter to Newcomers the Want to Start a MUD

An LPC Renaissance

Why New Muds Should Use Dead Souls

Is OLC Good for LPC?

Intellectual Property and Dead Souls


Dead Souls Homepage

+ + diff --git a/lib/www/articles/copyright.html b/lib/www/articles/copyright.html new file mode 100644 index 0000000..75b9250 --- /dev/null +++ b/lib/www/articles/copyright.html @@ -0,0 +1,11 @@ + + + + + Intellectual property and Dead Souls + + + +
Intellectual Property and Dead Souls

Updated 27 December 2006

When I began work on Dead Souls, I hadn't
thought that I'd have much to worry about, in terms
of intellectual property, or IP. Little did I know!

There have been some areas of concern for
folks in this regard, and this article is intended
to clarify my actions and intent when it comes to
Dead Souls and IP.

First, let's establish some basics:

Basic concepts of copyright in the US
as relevant to MUDs

The main DS IP issues break down into
four main categories:

The legal status of Dead Souls

The controversy over Cygwin GPL violation

The controversy over Mudmagic and GPL revocation


The question of MudOS distribution



Basic concepts of copyright in the US as relevant to MUDs

What copyright is.
When copyright obtains.
Some limitations established.
The meaning of consideration.
The meaning of licensing.
The nature of revocation.
Contracts and revocation.
Public domain.
Disclaimer.
Discussion.

1) Copyright is a feature of US law explicitly outlined in the body
of the US Constitution. It is intended to protect a person's right
to their own creative works in order to provide incentive for
people to enrich society through their creative efforts.

2) The moment you write something original, it obtains copyright. It
is not necessary to "register" it. When you place it into tangible
form, you have copyright. For example, this web page is copyrighted
by me, even if you don't see my name on it, or a date, or that
(c) symbol. If you have a document you didn't write, you must
assume it is copyrighted and treat it as such, until you know
for sure that it is otherwise.

3) When you have copyright on something, it means that nobody can
distribute it, or a work derived from it, without your express permission.
It doesn't matter whether they make money or not. The commercial
use isn't the issue. The copying is the issue. That's why it's
"copyright" not "commerceright".

4) "Consideration" is a legal term which roughly means an exchange
of value. If you give me money (or promise to do so) to use my lawnmower,
that is consideration and really, it isn't "borrowing", because
we've entered into a "contract" involving the use of the lawnmower.

5) "Licensing" is a legal term for allowing people to use your work.
There are many kinds of licensing. If consideration is provided to
secure the licensing, this can constitute a contract. The difference
between "license" and "contract" is important. Note they are
not mutually exclusive.

6) With the exception of something called "estoppel", a copyright
holder can revoke a license at any time, if that license is not
contractual. If you borrow my lawnmower, I can demand to have it
back any time I want.

Yes, this means that GPL can be revoked.

Please re-read that. It is correct.

If you write a program called LeetFooProg, and GPL it, and put it
on SourceForge, you can then go back the next day and tell everyone
who downloaded that program for free that you're revoking GPL and they
can't use it any more.

This is a concept that is very, very upsetting to some people,
because it means that a lot of the software they use (in many
cases, all of the software they use) can go away in a puff of smoke,
if the copyright holder goes crazy and decides to revoke license.

In theory, Linus Torvalds could wake up tomorrow, insist that
the Linux kernel license is now null, and a lot of people would have
to then go use some other operating system.

In the context of a mud, that means that if someone builds some
stuff on your mud for free, then decides to revoke your license to have
it in your mud, you are legally obligated to remove it.

However upsetting this concept is, that's just how it works.

Some people find this 100% intolerable, because it means that they
have to deal with the fact that people over whom they think
they are "boss" actually have authority over features of their mud.
If you are among those people, don't flame me because you wish
things were different. Change your ways or change your mud so that
you are no longer exposed.

For others, it's just unacceptable that the creator of their
codebase could, on a whim, show up and tell them they have to use
some other codebase. If you run Diku, and any one of the Diku
copyright holders showed up and told you to stop using his material,
you need to do so. Period. For some mud owners, that's a pretty
scary thought.

7) If the license is contractual, it may not be possible for the
copyright holder to revoke it. If we enter into a bargain for you to
use my lawnmower for a single week for $10, I cannot then insist on
getting my lawnmower back before the term of the contract expires.
A new contract could be required for that, depending on controlling
legal custom. Similarly, if I pay you to use LeetFooProg, it may
be (depending on the wording of the contract and the applicable
jurisdiction) that you cannot revoke my right to use it.

This is a bit squishier. Your municipality may, for example,
have an overriding Lawnmower Act that supercedes any authority
outlined in a contract within its jurisdiction. Similarly, you
may be a US citizen party to a contract with a foreign national
whose locality invalidates your licensing expectations.

In general, though, the exchange of consideration tends to give
the user somewhat more protection from arbitrary license
revocation (but read that EULA!).

8) A circumstance that obviates the need for license worries
is the use of material which is public domain. Public domain
material does not have a copyright holder, and is therefore
free from copyright-based limitations on its use.

Public domain material is also non-copyrightable. Nobody gets
a second bite at that apple. Once it's free, it's free. If
you add some chapters to the Cratylus, and make some aesthetic
alterations to the original text (redactions perhaps), then
you hold copyright to the additions, but not to the original
text itself. That original still belongs to everyone.

Of course, this assumes you're altering the original ancient
Greek text or using Jowett, since an English-language version
of it could be a copyrighted translation. Never assume your
source material is PD, ph.D.'s.

9) Things are much, much more complex than it might seem
from the above information. Intellectual property law is
a somewhat involved subject. The preceding points are an
introduction to my understanding of how it works relevant to
people interested in running a mud. Before you make decisions
related to copyright, be sure to consult a lawyer with
expertise specific to the legal aspects of the nature of
that decision.

10) You may register disagreement with the preceding points
at the lpmuds.net discussion forum for it. Please note that
impoliteness is not appreciated and flames are moved to a
flame section.


The legal status of Dead Souls

The original, not-touched-by-me version is 1.1pre, and it is public domain.

There is a cleaned up version of 1.1pre, which is called 1.1. It is public domain.

There is a modernized, updated version called 2.1.1. It is NOT public domain.

A new public domain version has been released, composed of most of what
is in 2.1.1. It is Dead Souls II.

For complete details on all the versions, see this page.


The controversy over Cygwin GPL violation

In early 2006, I released a version of Dead Souls
packaged with a Windows-compatible executable. This let
people run Dead Souls on their Windows computer.

For this to work, it needed some special files
called "dll's" to enable the executable to run on computers
which did not have Cygwin software. These Cygwin dll's
are provided by Cygwin under GPL. I included these dll's
in the Dead Souls release.

What I did not understand at the time is that
distributing the dll's without access to their source code
was not permitted by GPL.

I provided access to the source code as required,
and the controversy subsided for a while.

Then there was a new ruckus because the Windows
compatible executable had been compiled using non-GPL
source, but linked with GPL libraries, which in the view
of some people is not permitted by GPL.

So then with the great help of a Dead Souls
stalwart named Saquivor, I ditched Cygwin entirely and used
MinGW to create a Win32 native executable that can be
run on windows without the taint of GPL.

That's it. That's the whole story. Some folks have
chosen to inflate this event into allegations of Dead Souls
containing "stolen" code, which is as baffling to me as it
is untrue.


The controversy over Kyndig and GPL revocation

In early 2006 there was a big hullabaloo over the
actions of a person known as Kyndig. He banned some
people from his site, which caused a lot of displeasure.

Much of Kyndig's unsavory behavior and his policies
were discussed. After examining the
available information, I determined that I did not
want to be associated with Kyndig. I decided to pull
Dead Souls from his repository, and I then revoked his privilege
to host it, for good measure.

This evoked a howl of protest from someone named Tyche,
who spent some effort in excoriating my action as unacceptable.

The ensuing flames unfortunately obscured the issue. For
some time I assumed Tyche simply had a problem with me personally,
due to the fact that he had been the one rudely hounding me
about copyright stuff before (he'd been the prime mover of
the Cygwin controversy and went so far as getting DS removed
from MudMagic back then) and due to the rather unhinged
and disproportionate bombast of his assaults.

Turns out the bigmouth had a point, though.

When I revoked Kyndig's right to host Dead Souls, I had
assumed I couldn't really do that. Like many people even today,
I thought that once a set of bits is GPL'ed, it's
beyond the reach of the whims of the author. However,
as my understanding of copyright law gained in sophistication,
I saw that my action wasn't just an empty gesture of
repudiation. It was an act with actual legal ramifications,
potentially invalidating the licensing on all GPL'ed distributions
of Dead Souls.

Upon arriving at this understanding, I reversed my policy
on Kyndig's privilege to host Dead Souls (not that I expect
him to avail himself of it!). It is no longer a question of
my interest in who does or does not host the files, but
rather a question of whoever wants to host them being
subject to the packaged license and applicable laws.

Unfortunately, the preceding flames had already degenerated
into ad hominem stuff, and it provided occasion for people
who disagreed with me on *anything* to then raise the
specter (purely FUD) of me running around revoking licenses.

Entirely unfounded, from my perspective, but how could
a potential Dead Souls adopter know for sure? The harm was
already done.

I think that the FUD is now effectively mitigated by
the release of Dead Souls II, a public domain version
which is entirely immune from my theoretical revocations.
The fact is that it would be entirely against my interests
to go about doing what Tyche and KaVir have implied
or suggested I might, but if you can't stand even the
slightest chance that I might wake up, lose my marbles,
and start a revocation jihad, then you can just use
Dead Souls II and sleep sound as a baby, knowing your
mud is entirely free of my caprice.


The question of MudOS distribution

The question of MudOS distribution hinges partly on
tradition. It's been a generally accepted custom to include
driver source code with lib distributions, and this is
because sometimes getting a vanilla driver to run one's
lib is not easy, and the idea of a distribution is to
help others get going somewhat conveniently. Including
the lib-customized source for the driver is a logical
and widely approved-of policy.

However, it's good to get permission anyway,
when possible.
I emailed Marius, the current maintainer, for
his permission to bundle MudOS with Dead Souls. I got
no reply, but I came upon this: Marius tells someone off

In that document you can see that Marius would
have been happy to let someone not only copy MudOS, but
actually take it over completely and lead it forward...
if only they had emailed him first. The key part of this
document is where he states,

"That's all it would have taken to get my blessing, either
implicitly as a result of my silence (which is most likely
what you would have gotten), or explicitly by my saying so
in response."

This is about as clear a signal as I was likely
to get as to how the copyright holder felt about the
general distribution (indeed, maintainership) of MudOS.

Then, thanks to the sharp looking out of Skout, I
was able to find Marius and we had the following conversation.
The only editing done here was excluding the noisy "Joe enters the room."
type messages, and formatting for clarity:

You tell Verbal: howdy. i'm the maintainer of dead souls, and i'm told you
maintain mudos. i'd like to ask for your explicit blessing in what I'm doing:
http://dead-souls.net/articles/copyright.html#mudos (this url edited on 27DEC2006 -ed.)

Verbal tells you: Yep, that's me. I am also Marius of mudos.org
Verbal tells you: I got your email, but unfortunately my response bounced.
Verbal tells you: I'm fine with you distributing the MudOS driver bundled with Dead Souls.
Verbal tells you: I would ask that you contribute any patches you've applied to the mudos-patches mailing list, though.

You tell Verbal: sure thing. sorry i had to idle, visiting a friend in the hospital
You tell Verbal: i'll submit the diffs for sure...i'd just thought the list was dead
You tell Verbal: if you don't mind, i'll use a transcript of our conversation
on my webpage, so anyone in doubt can have their mind set at ease.

Verbal tells you: no problem. all of the lists are still alive, though there's
not much traffic.
Verbal tells you: go ahead and use the transcript. that's cool.

To the best of my ability to tell, it really is the
man himself I was talking to. Anyway, I hope it was, because
if it wasn't and he reads this, he might get awful pissed!

Dead Souls Homepage

+ + \ No newline at end of file diff --git a/lib/www/articles/favicon.ico b/lib/www/articles/favicon.ico new file mode 100644 index 0000000..d76c824 Binary files /dev/null and b/lib/www/articles/favicon.ico differ diff --git a/lib/www/articles/newcomer.html b/lib/www/articles/newcomer.html new file mode 100644 index 0000000..baa8ad8 --- /dev/null +++ b/lib/www/articles/newcomer.html @@ -0,0 +1,252 @@ + + + + + Open Letter to the MUD Newcomer + + +"I am very excited to start a mud. I don't know how to code for
+muds, but I have a super great idea for one. All I need is for
+folks to come do what I tell them." +
+
+This, in many different phrasings, is one of the most common +
+requests for help on mud forums. It very often generates
+hostility and ends in sadness. I'm of the opinion that there +
+should be some standard FAQ-style answer to it, in order to +
+minimize the pain that this sort of request generates. This +
+open letter is an attempt at that standard response. +
+
+
+Open Letter to the Newcomer Who Wants to Start A MUD +
+
+Dear Newcomer, +
+
+Welcome! I am very glad you're excited about muds and I +
+hope you stay and become a frequent participant and
+contributor to this forum. I also extend to you my most +
+sincere wish that you succeed in your game. The community +
+benefits from more good games. +
+
+Please forgive any hostile posts you receive as a result +
+of your request for assistance. You may not be aware of +
+some important things about the community of folks who +
+create and run muds (mud developers), and this letter is
+meant to guide you through some things you ought to know. +
+
+* We are volunteers. With very, very few exceptions, +mud
+devs don't get paid for it. They do what they do for their
+own pleasure, and help others out of love for the hobby.
+Remember that! If we seem testy sometimes, it's often
+because we think we are trying to defend something we love. +
+
+* We have been hurt. There are literally thousands of +muds +
+that started, got nowhere, and closed in short order. I'd +
+be willing to bet there have been tens of thousands. Many +
+of us have donated our time, our creativity, our sweat to +
+such muds. Some of us have had it happen more than once. We +
+may still be sore about it. When we see another forum post +
+advertising a mud that we think will do the same, sometimes +
+we have a hard time giving the benefit of doubt, and we say +
+rude things. Please forgive us. +
+
+* We don't want others to be hurt. When we see a post +for +
+a mud that looks like another of these "wasted my time" muds, +
+we sometimes ask very pointed questions to determine the +
+viability of that project. It's not about being jealous of +
+your idea. It's not about hatred of things that are new. We +
+really want to know how serious you are, and how likely you +
+are to waste people's time. Believe it or not, we can usually +
+tell. The fastest way to prove your mud will go nowhere is +
+to respond to such posts in a hostile and immature manner. +
+Avoid that. Just accept that we're trying to help other mud +
+devs know more about you and your project. +
+
+* Lazy people drive us crazy. I am not calling you +lazy. But +
+your post may have made you look that way. Some newcomers +
+say things like "I really just can't code, I've tried." This +
+sounds like you just can't be bothered, and are trying to
+get people to do your job. Coding is very hard for some folks, +
+and it's ok that you're not good at it. But insisting on not +
+coding, and not getting better at it, is a very strong mark +
+against you. It may not *be* laziness, but no matter how you +
+excuse it, it comes off that way. Don't sound lazy. And +
+don't be lazy. Plan on improving your coding skills, and
+explain that this is your plan. +
+
+* We don't need you as a boss. If your idea is good +enough, +
+I can just make my own mud with it, and not bother involving you. +
+You need to explain what role you will play, and why you are +
+the right person to play that role. Remember that this is +
+very much a job interview...but you're not interviewing +
+candidates. You are the candidate. You are showing us why +
+you're the right person to run the mud, and what skills and +
+experience you bring to that job.
+
+* Your awesome idea is one of 10,000. It is important +for +
+you to understand that. Just having an awesome idea doesn't +
+even come close to convincing anyone that the idea needs +
+a mud, and that you need to be the boss of it, and that +
+people should want to come and work on it for you, for free. +
+The idea is important, but it is not the most important part. +
+
+You might feel a bit bewildered at this point. Just what do +
+mud devs want to see that might make them want to join your +
+project? It's not an easy question to answer, but here +
+are some things worth demonstrating: +
+
+- Maturity. Show us you're a grownup that can handle +criticism +
+well and doesn't think he is owed free labor. +
+
+- Planning. The surest way to know I should disregard +a project +
+is that you haven't bothered to research anything. If you don't +
+know a mud host from a web host, you're probably wasting my time. +
+If you have no idea which codebases to investigate for suitability, +
+you haven't done your homework. If you're serious, you'll +
+be able to show your planning.
+
+- Commitment. If you really are serious about this +project, +
+you have work to show us already. Perhaps you've started +
+testing on a codebase. Perhaps you have a design document laid out. +
+Something to show you're not just begging on the street for +
+someone to make you a mud. Explain the work you've done thus far. +
+
+- Motivation. I want to see the fire in your belly. +If I +
+spend my time and share my skills on a project, I want to know +
+it's run by someone determined to make things work.
+
+- Experience. Tell us about the projects you've +managed. If they
+failed, why did they fail? Your experience need not be perfect,
+but you should show how you've learned from it. +
+
+The sad fact is that most muds that start will fail. You have +
+to show prospective mud devs why your mud will not, and why they +
+will not be wasting their time on it.
+
+You might at this point be coming to the realization that +
+you may in fact not really be ready to start a successful +
+project. That is not shameful, it is not a sign of personal +
+fault. We all have to start somewhere. If you're feeling like +
+maybe your project won't meet the standards laid out in this +
+this document, don't just give up. Find a project that can +
+use a newcomer, and learn the ropes. +
+
+That's usually how it works, you see. Newcomers don't usually +
+start as captain, they usually begin as beginners. There's +
+no shame in it, and I'm pretty sure that starting the +
+normal way is a very good way to prepare to eventually run +
+a successful project of your own. +
+
+Your pal, +
+
+-Cratylus +
+
+PS See also: http://www.gammon.com.au/forum/bbshowpost.php?bbsubject_id=2293
+ + diff --git a/lib/www/articles/olc.html b/lib/www/articles/olc.html new file mode 100644 index 0000000..32937c1 --- /dev/null +++ b/lib/www/articles/olc.html @@ -0,0 +1,16 @@ + + + + + Dead Souls and OLC/QCS + + + + +
Is On-Line Creation Good for LPC? 

Dead Souls includes a quick creation system, named,
aptly enough, QCS.

It was an incredible bitch to make, because it had to
account for and parse code that might be written
carelessly, or in accordance with odd formatting rules.

Additionally, the number of possible things to modify
on an LPMud is so mindbogglingly large that it made
for a task that was challenging both in complexity
and in scale.

I sweated through the months of pain not because I
felt it would be a nice feature, but because I felt it was
a *necessary* feature. Early in DS development, I wondered
why it wasn't being adopted more, and started looking
at what other libs had that DS didn't. When I took a
serious look at CoffeeMud, I was totally blown away. Granted,
CM has had 5 or more years of constant development
by a team of more than one person, but the results
really are remarkable.

Their build system was simple and elegant. It
allowed people who were not interested in learning
code to make neat stuff right away. It became immediately
obvious that to a new mud admin, deciding which way to
go, there was really no contest.

Should they go with a mud that requires effort,
discipline, and weeks/months of study before doing
anything cool? Or with CM which they can set up and
build on immediately?

I realized that there was no way at all to compete in
the modern lib marketplace without an OLC.

The arguments in favor of an OLC are predicated on
"wide adoption of one's codebase" being the goal. The
arguments I arrived at were the following:


* Experienced admins already have a codebase preference.
There is no need or point in trying to convert people.

* N00b admins generally will not accept having to work
hard to get a mud up.

* Getting n00bs to use DS necessarily means making it
easy to set up from the start.

* Without an OLC, DS was greek to most n00b admins.

* Even though most n00b muds will fail, having many failed
DS muds is still good progress, because it means many
non-admins will have been exposed to the codebase. It is from
this sort of initial code exposure that preferences
develop.

It was obvious to me that I couldn't get people to
use Dead Souls just because it was technically superior
under the hood. Ask the makers of the Betamax if technical
superiority equals market share. Ask the Macintosh.

Hoping people would see the genius in my code would
not suffice to make them adopt it. The only way to make
DS widely adopted was to make it easy, and make it fun.
That LPC has had a history of being difficult is
irrelevant. Having been one way doesn't mean it had to
stay that way, and indeed, it's probably the main reason
LPC is in decline.

In my mind, Dead Souls's Quick Creation System isn't
really about advocating a feature that makes it
technically superior to other LPMuds. QCS is entirely
neutral in this respect. It does nothing for the
fundamental lib on its own: it just interprets it. If
the underlying code is crap, the QCS can do nothing
to change that.

No, DS QCS isn't about technical superiority. It's
purely marketing. I didn't spend months slaving over
QCS because I thought it made DS *better*. I did it
because I thought it made DS *viable*. Not having it would
be like trying to sell a car without windshield, doors, or
mirrors. It pretty much doesn't matter how good the
engine is. People want what they want, and if you don't
give it to them, they'll go somewhere else.

The obvious argument against this position is
"it doesn't matter if lots of people use the lib, it
just matters that it is pure and beautiful".

That is a valid opinion, but it is not mine. That
opinion assumes that one is the best coder, and
nobody can improve on one's work, and one's work is
perfect. I don't believe that is true of anyone.

I want DS to be great. I know that I am limited
by my experiences, ideas, and expertise. Others
can help DS better. By making DS widespread, more
eyeballs examine it, and the chances are greater
that someone will make DS better in some way. With
enough of this agglutination of minor improvements,
DS can be better than anything I could have made it on
my own. Making sweaty 13 year olds happy with an easy
mudlib is a by-product. By making it easy, and making
it so many people will use it, it increases the
chances that a great coder will find it, love it,
and contribute to its greatness.

So, as goofy and lame as I felt, making a
n00b-friendly "anyone can build here" system, I felt
it was not only important, but *vital* to advancing
my agenda of making Dead Souls the best LPC mudlib
on the planet.



Dead Souls Homepage

+ + diff --git a/lib/www/articles/old/forum_chat.html b/lib/www/articles/old/forum_chat.html new file mode 100644 index 0000000..1979e5f --- /dev/null +++ b/lib/www/articles/old/forum_chat.html @@ -0,0 +1,278 @@ + + + + + security bug forum chat + + +tacitus - 2006/06/17 05:48 
+
+I'm all for healthy competition +and needling each other. I think
+anyone who knows me knows I'm +anything but thin-skinned.
+I enjoy a good romp either on gjs +or on justrage, or whatever.
+
+This thing, though, crossed the +line between rough play
+and actual harm.
+
+I figured Tacitus would be +insufferably smug if he found
+the bug he was looking for, but I +figured that was a small
+price to pay for getting help +securing DS. What I did
+not count on was him taking it +upon himself to delete
+log files.
+
+This is a serious problem, +because he was messing with
+security, and if I can't tell +what he did, I have to
+stop everything and reconstruct +the events by hand.
+
+Whether it was malicious is +actually beside the point.
+Either he's untrustworthy because +he was concealing bad
+behavior, or he's untrustworthy +because he doesn't know
+better than to tromp around +someone's logs as he pleases,
+without so much as a hint of his +intentions to the
+owner.
+
+Either way, it was a breach of +trust I did not expect
+from someone I've been supporting +as a leader in the
+community.
+
+I've been granted guest creator +and sometimes even guest
+admin privileges on other +people's muds, and I have
+never done anything but exactly +what I've announced
+and only with permission, because +it's not my mud
+and I understand that. This is +basic. It's obvious.
+In someone else's house, you ask +before you perform
+potentially irreversible changes, +or you can just
+consider yourself a boor.
+
+So there's that.
+
+According to Tacitus he attempted +to delete logs without
+asking permission out of a +concern that other people
+might happen upon them and learn +the exploit. Aside
+from the obvious objection that +he could have just
+told me so I could decide for +myself, is the bizarre
+fact that he went on gjs +intergossip to announce there
+his achievement, and allowed +thespread of information about how
+he did it. Any casual reader of +the gjs i3 log is
+now in full possession of all the +details needed to
+compromise a Dead Souls mud, if +given Creator status.
+
+How this squares with his stated +intention of protecting
+the community by deleting my logs +I can't say.
+
+There are some folks out there +who find exploits in
+commercial software, and share +the information
+with the public in an attempt to +help people get
+ahead of the curve. Even assuming +this is not
+dangerous, it is common for +professional, responsible
+programmers who find serious +flaws to give the
+manufacturer a few days or weeks +to develop a
+patch before outing the info. As +a colleague, this
+is the least I would have +expected.
+
+Instead I'm now spending what +little of the weekend
+I had for myself reconstructing +free space to
+find potentially deleted files, +and exhaustively
+nailing down each exploit and +subexploit related to
+this incident. Just because +Tacitus couldn't contain
+his glee and pride at rooting me, +and couldn't
+give me a couple of days to deal +with it
+in a more deliberate and measured +way.
+
+Well, Tacitus, you win. The big +bad Dead Souls
+juggernaut had feet of clay, +after all.
+
+However, you've lost any trust I +had in you, any
+good will. Maybe it will change, +but at the moment
+I just don't see myself feeling +up to dealing
+with you. You didn't have to do +it this way.
+I hope the schadenfreude was +worth it.
+
+When you came back from watching +your
+movie, this was your message:
+
+Tacitus@TimMUD +<intergossip> How is that audit coming?
+
+
+It's coming along fine. Thanks.
+
+-Crat
+ 
+

+
+Re:tacitus - 2006/06/17 06:00
+
+I think Cratylus made some very +valid points however I think we all know that I wasn't trying to be +malicious - I was simply excited by my discovery. Furthermore, you told +me you were snooping and then I paged the log file and then proceeded +to delete (However, either the access file hadn't reparsed or you had +already removed me from the arch group so it failed) the log file that +contained the commands (eval and call logs) I used to find the exploit. +From today's events, I can only conclude we didn't truly realize the +lack of trust we had in each other in the first place or you are trying +to use this as some sort of publicity stunt.
+
+As for the information being +released on intermud, I did not release the information directly. +Rather Duuk was cleaver enough to pry enough out of him to figure it +out on his own and then proceed to make fun of you - I can see how your +feelings can be a bit hurt.
+
+I know if this happened to my +lib, I'd be very much embarassed too and I can understand why you are +making this post. I humbly appologize.
+
+P.S. The audit comment was to +Hellmonger because he joking said that he'd audit my mudlib for me. If +you know this and that means that you are now auditing my mudlib, I +look forward to the results.
+
+Post edited by: somerville32, at: +2006/06/17 06:02 Tacitus
+Executive Director
+Research, Education, and +Development
+LPUniversity Foundation
+
+

+
+Re:tacitus - 2006/06/17 +06:18 
+
+For the record, I don't remember +saying anything about
+watching you. While you were +messing with my lib, I was
+in the middle of helping Samael. +That was the level of
+trust I had in you. When you +started crowing about your
+success, I started snooping you, +and saw you trying
+to delete logs. You can imagine +my dismay. Given
+that you were admin, were +deleting logs without telling me,
+and I didn't know what you'd do +next, I ridded you on the spot
+and locked the mud, but alas, +you'd already made yourself
+an elder, so you recreated your +character and logged back
+in. Not knowing what you *had* +done or what you *planned*
+to do, I killed the mud process, +unmounted the filesystem,
+and began the tedious process of +intrusion forensics.
+
+You really don't need to suggest +I feel hurt because of Duuk.
+
+I feel betrayed because of *you*.
+
+You seem intent on provoking me +by claiming that my
+statements are for some purpose +other than telling the truth.
+
+I would suggest you read my +statements as declarations
+of what I believe to be true, +regardless of how uncomfortable
+that might make you.
+
+-Crat
+ + diff --git a/lib/www/articles/old/lpmuds.html b/lib/www/articles/old/lpmuds.html new file mode 100644 index 0000000..caa82ab --- /dev/null +++ b/lib/www/articles/old/lpmuds.html @@ -0,0 +1,24 @@ + + + + + The LPmuds.net Site + + + + +
The lpmuds.net Site

This is starting to become a bit of a frequently
asked question, but the proper answer is long, and the
short answer makes it seem like something hostile is
going on. This page is intended to clarify the origin
and purpose of the lpmuds.net site.

Some months ago I got fed up with the way the
lpuni.org site looked. Its purpose was unclear, its
navigation and priorities, in my opinion, very confusing.
After a long time of arguing and cajoling with Tacitus,
I decided that I'd take the DIY approach and
set up a simple site, with a simple purpose: promoting LP.
That is, both LPmuds and the LPC language. Just a resource
site...no executive boards, no free hosting, no
plenipotentiary council meetings. Just a site, with
an easy to read format, and helpful LP type stuff.

After this, Tacitus presumably understood what I'd
been talking about, and changed lpuni.org a little to
help the newcomer get a better handle on what that site is.

Since then, I haven't done much with the lpmuds.net
site, because I assumed Tacitus would make that site
superfluous.

Today I'm not so sure. It's been months, and not
a single of the "FAQ"'s on the lpuni.org front page got
a link. Dead Souls people have complained to me about
lpuni and even left that organization due to political
disputes. The atmosphere has even made people stop participating
on the forums there, which was pretty much the whole point
of me asking Dead Soulers to go there.

I truly, sincerely hope that lpuni gets itself
together and squared away. I believe in its goals, and
have always been an avid public supporter. I don't think I
need to prove my bona fides on that. I've shown that I'm
more than willing to put my money where my mouth is...I have
actually already done so.

However, given what's been going on, and the fact that
lpuni has been down more than it's been up lately, I've
decided that it's time to revive the old lpmuds.net site
and get it to do the things I've been wishing lpuni would do.

Whether it's fixing up a dead lib, or setting up
my own router, or setting up hosting for lpu, folks should
know by now I'm not a "stand around and hope someone does
something" kind of guy. I'm all about DIY, and that's what
this move is about.

Now, some folks out there are of the opinion that
I'm trying to "compete" with lpuni, and "beat" Tacitus in
some way. I've found myself trying to explain that it is not
so, but I don't think I'll convince all. Let me at least
explain here my thoughts on that...and let the chips fall
where they may.

It is true that I'm planning on spending less time
at the lpuni.org site, and now that Tacitus is not using
Wolfpaw, will have less involvement in general. However,
curtailing my involvement isn't about being huffy. It's not
about my personal feelings regarding Tacitus. It really
just makes sense for me to step away a little, for the following
reasons:

1) I want a forum that all DS'ers feel comfortable in. Since
lpuni doesn't do that, I will be spending more time on lpmuds.net.

2) I have too many conflicts with lpuni. Whether it's my opinion
on donations (accepting them the way lpuni does makes me uncomfortable),
or my attitude toward the way the website used to look, or my
concern about hosting on Kyndig, or any of a variety of other
issues, my viewpoint gets construed as hostile and anti-lpu,
rather than anti-whatever-it-is-I'm-disagreeing-with. I think
this causes unnecessary conflict in the community. Tacitus is
the lpuni boss, I'm ok with him being the absolute authority
there, and I'm walking away from there so that nobody thinks I'm
trying to oppose what lpuni is trying to do.

3) lpmuds.net cannot compete with lpuni.org, because lpuni's
stated strategies involve things I have absolutly no interest
whatsoever in. You're not going to get departments heads,
ministries of education, LPC certification authorities, or
any of that from lpmuds.net. This is just a resource site, with
forums, downloads, and docs. That's it. What's to compete?


Summary:

* I will be spending less time on lpuniversity stuff.

* I will, however, continue to host lpuni meetings as long as lpu wants.

* The lpmuds.net site is going up, and staying up. It is both the
official support site for Dead Souls 2 and a place for LP mud fans
of all stripes to congregate with a minimum of political strife.

* The lpmuds.net site is not intended to compete with lpuni.org in
a hostile way. The way topmudsites.com and mudconnector.com are
both complementary and competitive, so I envision the relationship
between lpmuds.net and lpuni.org.

* LPU people are welcome at lpmuds, and there is already a topic
dedicated to them there.

* Mommy and Daddy still love you. We just have different houses now.



Dead Souls Homepage

+ + diff --git a/lib/www/articles/old/lpu.html b/lib/www/articles/old/lpu.html new file mode 100644 index 0000000..a01be60 --- /dev/null +++ b/lib/www/articles/old/lpu.html @@ -0,0 +1,15 @@ + + + + + Dead Souls and LPU + + + + +
Dead Souls and LPUniversity Libs

There is some question about the
relationship between the Dead Souls mudlib and
the LPUniversity mudlib. Hopefully the description
below will unmuddy those waters.

Think of LPUniversity as a lib designed
from the ground up with LPC education in mind. It
is intended to be a lib coder's lib: crafted to
precise specifications and tight tolerances.

You'll have to ask him, but it's my
impression that Tacitus intends the LPUniversity
lib to be a sort of gold standard of how
LP libs should be.

As such, it's going to take a long time
to get the LPUniversity lib into the kind of
shape it needs to be in order to have a high
adoption rate. You can think of it as a Rolls
Royce under construction, still up on the lift.

Dead Souls is ready for prime-time. Though
it lacks some fun stuff that will be added in
the future, everything you need is there for
making almost whatever you want, right away. It's
not perfect, but it works. If LPUniversity is
a Rolls on the build lift, Dead Souls is the
Honda Civic in your driveway. Nothing to scream
about, really, but it works great and takes you
where you need to go.

The two libs complement each other. The
point of Dead Souls has always been to get more
people using LPC. The point of the LPUniversity
umbrella project (which includes the LPUlib) has
been to get more people using LPC.

By affiliating with Dead Souls, LPU gains
a larger potential base of interested people.
Dead Souls can be downloaded and run now, and put
into production as quickly as you can build your
world for it. This active user base strengthens
the LPUniversity project by participating in the
LPC community.

By affiliating with the LPU project, Dead
Souls gains a resource for LPC discussion that
has been sorely needed. Discussion forums and healthy
competition between libs is the sort of thing that
breeds interest in Dead Souls, breeding interest in
LPC at large.

Everyone wins.

So that's pretty much it. The LPU lib is
the car that's going to r0x0r but isn't ready to
to roll yet. Dead Souls is the car that may not
look as pretty, but has it where it counts. It
actually turns over and gets you around.


Dead Souls Homepage

+ + diff --git a/lib/www/articles/old/mudmagic.html b/lib/www/articles/old/mudmagic.html new file mode 100644 index 0000000..1ef9673 --- /dev/null +++ b/lib/www/articles/old/mudmagic.html @@ -0,0 +1,26 @@ + + + + + Kyndig and Dead Souls + + + + +
Kyndig and Dead Souls

Back in 2005, when the first prototype versions
of Dead Souls were ready to be released, I looked around
for a means to distribute the lib. I hit upon the
obvious, Sourceforge, immediately.

Eventually mudmagic.com came to my attention
because of its widespread recognition, influence in the
"mud community" (whatever *that* is), and obvious
depth and quality of its software archives. My code
was accepted, and soon enough I was granted ownership
of my little Dead Souls corner of the site.

There was a moment during which I found Kyndig's
enforcement a bit precipitous
, but at the time I
reasoned that, lacking thorough documentation on the
issue, I might have pulled the trigger on a GPL
violator just as quickly.

I shrugged off complaints against Kyndig as a
familiar variation of the "admins suck!!1!" song I've
often heard before. Non-admins typically have no idea
how punishing it is to be diligent in your duties, and
the Kyndig complaints sounded pretty much like the
ill-justified wailing of children I was familiar with.
I even went so far as to try to articulate this in
a flame thread that started over a controversial
banning on mudmagic. To my dismay, not only did my
post disappear, the entire mudmagic flame board went
away. This was the event that made me start to see
things differently. Like the "big twist" in an M. Night
Shyamalan movie, everything shifted over just one
degree, but it changed the meaning of everything
that had gone before. And, like an M. Night Shyamalan
movie, I felt dumb for not having seen it before it
was rubbed in my face.

I began to reevaluate the controversial banning
itself. Back when it happened, I'd thought that Tyche
richly deserved some sort of sanction because, well,
frankly, I just didn't like him much. When I heard
that Kyndig banned him, I thought that sounded way too
harsh, but assumed that as much as Tyche had been an
asshat with me, he'd probably been plenty annoying
to Kyndig too, and Kyndig probably just got sick of
dealing with his shit. I've gotten fed up with people
myself, and I wasn't in a position to judge Tyche's
punishment, really. I just shrugged and said, "good
riddance."

When I heard Samson had been banned, I was very
surprised. Based on the dispute I had seen on the
moderator list, it seemed clear to me that Samson
was pretty well justified in being angry, and that his
responses, though intemperate, were reasoned, non-
flaming, and pretty humorous to boot. Nothing I
saw seemed to justify Samson getting kicked, and
this made me extremely uneasy, but, again, I just
assumed I didn't know the whole story, and on Kyndig's
site, he's the boss. I let it go, and, as mentioned
above, even chided people for leaping to conclusions
about it.

The next straw was "the dog that didn't bark."
You know the Sherlock Holmes story where he figures out
the owner was was the culprit because on the night of
the crime the dog didn't bark? The next thing I
expected was a public declaration from Kyndig about
his reasons for his actions. I have led people before,
and good leadership requires that when you cut major
players from a team, you need to explain why in a way
that clearly demonstrates your reasoning, your
justification, and gets buy-in from everyone that you
did it for legitimate reasons, and not pettiness.

The reason this is important is that if you
don't let people in on your decision-making, then
cutting people doesn't look like a justified act of
administration. It looks like a vindictive purge.
There may have been some vague mention about keeping
the site stable and such, but nothing that spoke to
the remaining contributors and moderators in a way
that made the actions sound *right*. To me, anyway.

Even then I thought, "Well, maybe he's not a
good leader. Doesn't make him *wrong*."

Then came the removal of the flame board, and it
started to dawn on me that Kyndig's administration
might not just be flawed, it might be fundamentally
misguided. I'd heard rumors about Kyndig brooking no
dissent, but this was stunning all the same. It's one
thing to frown on people complaining, but to remove a
forum dedicated to complaining, because people complain
about *you*, is damned hard for me to sign off on. To
me it doesn't matter that there are business interests
to protect. Controlling information actually does work,
and it is an efficient means to protect your business,
but an organization that operates this way loses my
respect. It seems to me especially foolhardy to operate
this way in an internet business, where spirits tend to
be high and resistant to censorship.

It was at this time that I made a compromise I
regret. I decided that I might not like the way Kyndig
does business, but it *is* his business, and it is of
benefit to me in distributing my software. I mightn't
like it but his site was useful, and I wanted to continue
to use it to promote my work.

In rapid succession I have learned of more
outrages. I can't know for sure it's all true, because
it isn't first hand experience. But as best as I can
gather, the following has happened:

* People speaking up for Samson and/or Tyche on mudmagic
have been banned.

* People speaking against Kyndig on sites other than
mudmagic have been banned.

* Kyndig has enforced restrictive policies on people
unrelated to these issues, based on affiliation with Samson
and/or Tyche.

These are the things that to the best of my
knowledge actually have happened. There are many other
rumors and allegations I've heard, equally appalling,
that I cannot fairly say probably are true, so I'm
omitting them.

I've come to the conclusion that I can't in good
conscience continue to have Dead Souls hosted on Kyndig's
repository. I find his behavior abhorrent to the
ideals of openness, fairness, and good judgment. I find
his hostility to criticism to be failure of character. I
believe that his weaknesses as a leader make him unfit
to hold any authority over the distribution of Dead Souls.

This will come at some cost to me, I suspect.
Mudmagic was a swell place to host my content, and I
respect and admire many of the the folks still there. I
hold no grudge against them for their decision to stay
there and keep their mouths shut. They have their own
consciences and their own reasons, over which I am
not qualified to pass judgment. For me, I know this will
mean a slower adoption rate of Dead Souls in general.

But I cannot abide the idea of the mud community
seeing any affiliation between Dead Souls and Kyndig.
His association with my software taints it, corrupts
its image, and I find it intolerable.


Update, Sep 1 2006

This document, at this point, used to say this:

"I am therefore asserting my authority as
copyright holder of post v1.1 Dead Souls, and revoking
the privilege of distribution of that software from
Kyndig or any site under his control."

It was, when written, an attempt to sound
important and make a big declaration. At the time, I
had been under the impression that once downloaded,
a GPL licensed work was beyond the reach of its author.

There were various debates going on about
this, and lots of opinions were thrown back and forth.
Persuasive cases were made on both sides of that question,
and frankly I teetered back and forth on which I
thought was correct. In the end though, I was persuaded
that GPL was a great fortress behind which adopters
were proof. Mostly my reasoning was "Why else would
you have it?"

Therefore, to me they were empty words...a
simple gesture with no practical effect, because Kyndig
could easily download the GPL version elsewhere,
slap it on his site, and I'd be powerless to do anything
about it.

The kind readers of the mudconnect site have
updated my understanding of this, and gently redirected
my opinion of my action in this regard. I see that as
author, I do indeed have copyright that supercedes any
verbiage in GPL, and I now see the fragility of
Open Source, which depends on the continued trust of
authors' responsible exercise of copyright.

As a developer, I'd rather have a reputation
for responsible copyright behavior than keep my pride.
I am therefore stating here that my revocation of
Kyndig's right of distribution was made under erroneous
assumptions, and is no longer in force.


Dead Souls Homepage

+ + diff --git a/lib/www/articles/old/patches.html b/lib/www/articles/old/patches.html new file mode 100644 index 0000000..06ef903 --- /dev/null +++ b/lib/www/articles/old/patches.html @@ -0,0 +1,27 @@ + + + + + Patches?!? + + + + +
Patches?!?
(We doan need no steenkin PATCHES!!!)

Updated 09 March 2007


The Principle

My goal is to make Dead Souls the best, most kick-ass
LPC lib ever. I interpret this to mean that when I
see a flaw, or someone else points one out, I want
it fixed. And, well, the fixing falls to me.

Releasing updates lets people share in the cool new stuff,
and it also helps me fix new problems.

Previously, I felt that "my way" of releasing stuff
was good enough. However, since making it convenient
for people to upgrade makes it convenient for me to
develop, I've changed my policy and worked on simple
and convenient upgrading processes.


The History


1) Tarballs

After a while of fixes accumulating, I declared it to be a
new release and off it went, into the world. At first this
caused a lot of grumbling, because it meant people had to
reinstall from scratch every time I made a release,
and this was a bit much for many people.

It occurred to me that I could compile a package that
had only the files that changed between releases. I
put this together, and people seemed to really like
being able to upgrade from one release to another,
without a full reinstall. Over time, this system
has been tweaked and refined somewhat, but in the
end, it's roughly the same type of thing it was back
when I produced the first one: a bunch of files.

However, it's kind of a pain for me. Also, since
people feel it's inconvenient to download the patch
and uncompress it (?!?) they rarely upgrade, so it
defeats the purpose.


2) OOB Liveupgrade

So I decided to set up an "in-mud" upgrade system.
Rather than go on the web, download stuff, and install
it, people would issue commands in the mud to update.

The protocol I chose was I3 OOB, because I wanted to
polish up on it, and because it seemed like it
would be easy to maintain. Sure enough, it worked
great and was easy to maintain. People would issue
the "liveupgrade" command with the correct parameters,
and they would pull updated files from a mud that
worked as a liveupgrade server. Beauty!

Problem was, it was dead slow. I mean, really slow.
It was a line by line transfer with sanity checks
throughout. On a fast system with large bandwidth,
it could take 15 mminutes or more to upgrade to a
new alpha release. On a slow machine sitting on a
skinny pipe, it could take more than an hour.

And on flaky connections, sometimes (rarely, but
occasionally) the upgrade would stall.

Since people don't really have the patience for that
(and really, I know I don't have it), I figured a
new way would make sense. Plus, with the development
of IRN, using OOB for sensitive stuff like this
stopped making sense, from a security standpoint.


3) HTTP Liveupgrade

So starting in 2.3a14, Dead Souls liveupgrades happen
over http connection to dead-souls.net. It is
insanely fast, with a complete upgrade taking around
a minute on a fast machine.

The drawback is that there are still kinks. It is
possible to do a liveupgrade that pulls 404 files,
if your connection is unstable. And, of course, this
means you'd have to restore from backup.


4) Back where we started

If a liveupgrade error hoses things up, there's no
need to panic. Just download the appropriate patch
file from http://dead-souls.net/code/patches and
install the old way. That will fix everything.



The Mechanics
The patching process is just as primitive as it
sounds. You uncompress these files and copy them
over your existing mud. Simple. Efficient.

Player files, directories, and domains that are
created by you are left untouched.

For some people this system is problematic. Some folks
are proficient at modifying lib code, and if they
just overwrite their mud with the contents of a patch,
they might find that their lib work has been clobbered. This
would be bad. That is why my patch instructions
strenuously remind people to back up the current mud
before patching it.

There is no practical solution for this problem that
I can see. Because I am just one guy, and my goal
is lib code, and not patch-process-design, I have
decided to leave things as they are. In theory I could
write code that would analyze and modify files as
needed, rather than simply have the owner overwrite.
However, this is a lot more complicated than it sounds
to implement in LPC within the lib, and it is also
non-trivial to implement this at the OS level, given
that the process would have to work on multiple different
platforms.

It's my opinion that people sophisticated enough to
need a more specialized patching system are
sophisticated enough to work around my shortcomings
in this area. Indeed, I've heard of folks who just
download the complete new version, run diffs against the
old one, and then pick and choose what to add.

For now and the foreseeable future, patches are just
a Big Dumb Ball of Files...with one exception.

Each patch includes a file called /secure/daemon/update.c
which carries out special functions that are not dealt
with by just overwriting files. When you reboot the mud,
update.c will do things like remove broken/dangerous files,
rename files with incorrect names, and modify text in
files (such as config.h) which should not be overwritten
but need to be changed.


The Philosophy and Controversy
Believe it or not, I've had people become irrationally
angry at how often I make releases. Not just "That darn
Crat is driving me crazy", but actual, unhinged flaming
well beyond any reasonable context.

Don't believe me? Check it out for yourself:

http://www.justrage.com/article.php?story=cratylus_dead_souls_mudlib


It *is* true that I'm averaging a release every week
or two. The person is correct in that there are a lot
of bugs to fix, and that releases happen much, much
more often than they do for other muds.

I have no defense against this charge. All I can do
is explain the reason for it, and hope it is justification
enough.

When someone tells me Dead Souls has a bug, I want to
help them. I want to fix it. I feel responsible to the
mud community to do what I can to fix whatever problems
they've run into because they've adopted the lib I
wanted them to. This is probably irrational on my part,
and if I'm lucky, I'll stop feeling this way sometime
soon. But until I do, I feel driven to be a responsive
lib coder, and I fix stuff. And I release it.

The question is, "If Dead Souls is so lame it needs
constant patching, shouldn't you kill it?"

The thing is, Dead Souls is the best LPmud lib out
there that I know of, *right now*. If the standard is
going to be perfection, then there's no lib out there
that should be available. There's no LPC mudlib
out there that you can download that is as featured,
solid, widely adopted, and supported as Dead Souls. If
the criteria for killing a lib is that it's not
perfect, and if Dead Souls is among the libs to be killed,
then just about everything needs a good flush.

It should be noted that Dead Souls doesn't *need*
constant patching. With the exception of security
fixes, any patch, upgrade, or hotfix is entirely
optional. You can stop patching and upgrading at
any time, and strike out in your own direction with
the lib. And as a matter of fact, I'd be tickled
pink if you did. The sprouting of evolutionary branches
off Dead Souls would delight me, because it would be
good evidence that I have begun something that's
going to continue beyond what I've done with my own
little brain.


Summary

For what it's worth, the vast majority of patch
tarball upgraders that follow the patch install instructions
report nothing but a smooth process.


Dead Souls Homepage

+ + diff --git a/lib/www/articles/old/tacitus.html b/lib/www/articles/old/tacitus.html new file mode 100644 index 0000000..51e705b --- /dev/null +++ b/lib/www/articles/old/tacitus.html @@ -0,0 +1,18 @@ + + + + + Tacitus + + + + +
Tacitus

Hey folks,

I'm getting the drift that some people feel there is some
sort of political big deal going on between Tacitus and me.

I just wanted to take this opportunity to clarify things
a bit.

Yes, I *do* have a problem with Tacitus-the-person, who has
personally offended me, put people at risk, and been an
all around source of unpleasantness for me lately.

However, I am not interested in, nor do I have the time for,
some kind of Kyndig/Samson style feud. I appreciate all the
supportive emails, and the kind words both on- and off- the
record. But in the end, all I want to do is make Dead Souls
the best LPC lib ever, and getting into a juvenile pissing match
is exactly the sort of thing that makes that difficult.

So, be aware of the fact that I want people to contribute to his
site, and I want LPU to be successful, because that is an
overall plus for Dead Souls. Please keep up the community
participation.

Whatever I've been doing lately to express my displeasure
with Tacitus has nothing to do with you guys, and I am not
interested in ganging up on anyone. Please just let me
be angry with Tacitus, and carry on with your business.

Thanks.

-Crat


Update 27 June 2006

People who missed the original event have been
puzzled over what I'm talking about here. For their
benefit, I'm posting three consecutive messages from
then which will help illustrate the problem. They
were originally posted on the LPU site.

Dead Souls Homepage

+ + diff --git a/lib/www/articles/old/tacitus2.html b/lib/www/articles/old/tacitus2.html new file mode 100644 index 0000000..c5f2bf7 --- /dev/null +++ b/lib/www/articles/old/tacitus2.html @@ -0,0 +1,889 @@ + + + + + Tacitus Part Deux + + +Tacitus, part 2
+
+If you're one of those people upset by the political angst
+over LPUniversity, you may stop reading at the end of this
+paragraph. With any luck, it's the last article of its
+kind I have to post, so breathe easy. Relief is in sight.
+
+The point of this article is to refute, with specific
+evidence, an accusation made against me by Tacitus. This
+means reviewing logs and such, and is therefore likely
+to be tedious for you, unless you actually care.
+
+For the easily bored, stop here. Just know that Tacitus
+said something rude that was untrue, and these logs demonstrate
+that.
+
+For those offended by petty bickering or crude language,
+this here is a good place to stop.
+
+On to the show.
+
+I'm not sure why, but despite my circumspect and +diplomatic

+explanations of +the new site and why I'll be spending less
+time on LPUni stuff, Tacitus +decided to attack me:
+
+
+

+
+
[2006.09.16-21.56] +somerville32.freenode@RtHBridge <lpuni> You took our hosting +right from under neath us
+[2006.09.16-21.57] +Cratylus@Dead Souls Demo <lpuni> uh
+[2006.09.16-21.57] +eMBee.freenode@RtHBridge <lpuni> ?
+[2006.09.16-21.57] +Cratylus@Dead Souls Demo <lpuni> huh?
+[2006.09.16-21.57] +Cratylus@Dead Souls Demo <lpuni> are you ill?
+[2006.09.16-21.58] Tricky@Rock the +Halo <lpuni> eMBee: You see how easily wars can start?
+[2006.09.16-21.58] +Cratylus@Dead Souls Demo <lpuni> seriously, if you mean that, +there is something wrong with you
+[2006.09.16-21.58] +somerville32.freenode@RtHBridge <lpuni> No Cratylus, I just say +it because I enjoy saying things like that
+[2006.09.16-21.58] +eMBee.freenode@RtHBridge <lpuni> tricky: sure, way to easy
+[2006.09.16-21.58] +Cratylus@Dead Souls Demo <lpuni> whoa dude
+[2006.09.16-21.58] +somerville32.freenode@RtHBridge <lpuni> It is because there is +unresolved "friction" between Cratylus and I
+[2006.09.16-21.59] +Cratylus@Dead Souls Demo <lpuni> how bout i remind you the url of +that tell log. hang on
+[2006.09.16-21.59] +Cratylus@Dead Souls Demo <lpuni> oh i cant tell to you
+[2006.09.16-21.59] <lpuni> +Tricky@Rock the Halo fishes out som WD40
+[2006.09.16-21.59] +Cratylus@Dead Souls Demo <lpuni> mind if i post it, so people can +judge for themselves?
+[2006.09.16-22.00] <lpuni> +eMBee.freenode@RtHBridge wants to know why lpuni can't be hosted on +wolfpaw
+[2006.09.16-22.00] +Cratylus@Dead Souls Demo <lpuni> cuz if yer gonna unload +accusations i feel i should have the right to defend myself
+[2006.09.16-22.01] Tricky@Rock the +Halo <lpuni> Fer frick sake... Post it! Don't ask for permission.
+[2006.09.16-22.01] +Cratylus@Dead Souls Demo <lpuni> it's a tell log. i dont feel +comfortable doing that without his ok
+[2006.09.16-22.01] Tricky@Rock the +Halo <lpuni> FOI
+[2006.09.16-22.01] <lpuni> +eMBee.freenode@RtHBridge agrees
+[2006.09.16-22.02] +somerville32.freenode@RtHBridge <lpuni> No, I'm too tired to +defend myself - I'm getting ready for bed.
+[2006.09.16-22.02] +Cratylus@Dead Souls Demo <lpuni> yer just going to accuse me and +leave
+[2006.09.16-22.02] +Cratylus@Dead Souls Demo <lpuni> nice
+[2006.09.16-22.02] <lpuni> +Tricky@Rock the Halo bangs his head against the table!
+[2006.09.16-22.02] +somerville32.freenode@RtHBridge <lpuni> I'm sorry Cratylus
+[2006.09.16-22.02] <lpuni> +somerville32.freenode@RtHBridge hugs Cratylus.
+[2006.09.16-22.03] +Cratylus@Dead Souls Demo <lpuni> ok i'll just tell the story then +in my own words
+[2006.09.16-22.03] +somerville32.freenode@RtHBridge <lpuni> No no, please, let me
+[2006.09.16-22.03] +Cratylus@Dead Souls Demo <lpuni> tacitus said he'd be using +trenden after all
+[2006.09.16-22.03] +somerville32.freenode@RtHBridge <lpuni> No I didn't
+[2006.09.16-22.03] +Cratylus@Dead Souls Demo <lpuni> so i'm like "fine by me"
+[2006.09.16-22.03] <lpuni> +eMBee.freenode@RtHBridge wants to hear both sides
+[2006.09.16-22.03] +somerville32.freenode@RtHBridge <lpuni> I said we should CONSIDER +it.
+[2006.09.16-22.03] Tricky@Rock the +Halo <lpuni> Err... It will be posted. What is the difference?
+[2006.09.16-22.03] +Cratylus@Dead Souls Demo <lpuni> tacitus you have lost your mind
+[2006.09.16-22.04] +Cratylus@Dead Souls Demo <lpuni> you said you were leaving wolfpaw
+[2006.09.16-22.04] +somerville32.freenode@RtHBridge <lpuni> No, I didn't
+[2006.09.16-22.04] +Cratylus@Dead Souls Demo <lpuni> do i need to ge tthe channel +logs? really?
+[2006.09.16-22.04] +somerville32.freenode@RtHBridge <lpuni> Yes, you do
+[2006.09.16-22.04] +eMBee.freenode@RtHBridge <lpuni> please don;t argue now, this is +not getting anywhere
+[2006.09.16-22.04] +Cratylus@Dead Souls Demo <lpuni> oh man
+[2006.09.16-22.04] +eMBee.freenode@RtHBridge <lpuni> just each of you tell how you +understand the situation
+[2006.09.16-22.04] Tricky@Rock the +Halo <lpuni> Arguing good, leave them to it.
+[2006.09.16-22.05] +somerville32.freenode@RtHBridge <lpuni> Basically, I said we +should consider Trenden since Wolfpaw didn't been working out
+[2006.09.16-22.05] +somerville32.freenode@RtHBridge <lpuni> Because Trenden had moved +to a new server and maybe that would resolve their stability issues +(our reason for leaving)
+[2006.09.16-22.06] +somerville32.freenode@RtHBridge <lpuni> Cratylus was like "ok, +blah blah blah, change the passwd back if you aren't going to use it".
+[2006.09.16-22.06] +somerville32.freenode@RtHBridge <lpuni> I said "ok"
+[2006.09.16-22.06] +somerville32.freenode@RtHBridge <lpuni> and changed it back right +then because I was reading between the lines - I thought he might have +wanted access back regardless, I was trying to be friendly.
+[2006.09.16-22.07] Cratylus@Dead +Souls Demo <lpuni> oh i see get me to look for logs
+[2006.09.16-22.07] +somerville32.freenode@RtHBridge <lpuni> And then before I said I +changed it back so he could use it, he logged in, changed the passwd, +and started uploading his competitor website
+[2006.09.16-22.07] Tricky@Rock the +Halo <lpuni> So... When *is* the wedding?
+[2006.09.16-22.07] Cratylus@Dead +Souls Demo <lpuni> omg
+[2006.09.16-22.07] Cratylus@Dead +Souls Demo <lpuni> dude
+[2006.09.16-22.07] Cratylus@Dead +Souls Demo <lpuni> omg
+[2006.09.16-22.07] Cratylus@Dead +Souls Demo <lpuni> this is unbelievable
+[2006.09.16-22.08] Cratylus@Dead +Souls Demo <lpuni> i'm just flabbergasted
+
+

+All righty. So on 16 September +Tacitus accuses me of pulling the rug
+out from under LPUni, and insists he never said he was moving off
+Wolfpaw. This is the discussion that happened the previous week:
+
+
+

+[2006.09.08-14.08] +Tacitus@LPUniversity <lpuni> Have you heard back from Wolfpaw re: +mod_rewrite?%^RESET%^
+[2006.09.08-14.09] Cratylus@Dead Souls Demo <lpuni> nope. i'll +send him another reminder
+[2006.09.08-14.10] +Tacitus@LPUniversity <lpuni> They may not want to enable +mod_rewrite - that would be a problem.%^RESET%^
+[2006.09.08-14.14] +Tacitus@LPUniversity <lpuni> There is an alternative that you may +want to consider.%^RESET%^
+[2006.09.08-14.25] Cratylus@Dead Souls Demo <lpuni> who, me?
+[2006.09.08-14.26] <lpuni> +Tacitus@LPUniversity nods.%^RESET%^
+[2006.09.08-14.27] Cratylus@Dead Souls Demo <lpuni> go on
+[2006.09.08-14.31] +Tacitus@LPUniversity <lpuni> Well, Trenden is moving to a new +server, new provider, and new OS w/ a very function CP%^RESET%^
+[2006.09.08-14.31] +Tacitus@LPUniversity <lpuni> I talked to Paradigm and he said +that this move would address stability issues.%^RESET%^
+[2006.09.08-14.31] Cratylus@Dead Souls Demo <lpuni> what's cp?
+[2006.09.08-14.31] +Tacitus@LPUniversity <lpuni> Control panel%^RESET%^
+[2006.09.08-14.31] Cratylus@Dead Souls Demo <lpuni> ok
+[2006.09.08-14.32] Cratylus@Dead Souls Demo <lpuni> so you have a +solution that avoids kyndig plus i dont have to pay
+[2006.09.08-14.32] Cratylus@Dead Souls Demo <lpuni> is that it?
+[2006.09.08-14.32] +Tacitus@LPUniversity <lpuni> I thought it is something that you +might want to consider.%^RESET%^
+[2006.09.08-14.33] Cratylus@Dead Souls Demo <lpuni> well there's +nothing to consider. it hits all the bases. fixes your problems, avoids +mine
+[2006.09.08-14.33] Cratylus@Dead Souls Demo <lpuni> what's to +think about?
+[2006.09.08-14.33] +Tacitus@LPUniversity <lpuni> I thought you might have an +opinion%^RESET%^
+[2006.09.08-14.33] Cratylus@Dead Souls Demo <lpuni> well you sure +got it
+[2006.09.08-14.33] <lpuni> +Tacitus@LPUniversity smiles softly.%^RESET%^
+[2006.09.08-14.33] +Tacitus@LPUniversity <lpuni> What do you plan to do with +lpuni.net domain name?%^RESET%^
+[2006.09.08-14.33] Cratylus@Dead Souls Demo <lpuni> cram it up my +butt
+[2006.09.08-14.34] Cratylus@Dead Souls Demo <lpuni> i mean, i +dunno
+[2006.09.08-14.34] +Tacitus@LPUniversity <lpuni> Well, you might be able to get a +rebate but you could also consider pointing it at our new host and we +can take over payment once it expires.%^RESET%^
+[2006.09.08-14.34] +Tacitus@LPUniversity <lpuni> Not a rebate%^RESET%^
+[2006.09.08-14.35] +Tacitus@LPUniversity <lpuni> A refund, lol%^RESET%^
+[2006.09.08-14.35] Cratylus@Dead Souls Demo <lpuni> naw i'll hang +on to it in case people decide to jump ship from your site and start a +new one
+
+
+

+
+Ok...at this point he hasn't come out and said he's moving back to +Trenden,
+but any reasonable reader would come to the strong impression that it
+wasn't just being "considered", it was a plan in motion.
+
+Just in case there remained any doubts, this is the following day:
+
+
+

+
[2006.09.09-10.44] +Tacitus@LPUniversity <lpuni> lpuni.zapto.org <-- Dev +site%^RESET%^
+[2006.09.09-10.44] Tigwyk@LP Heroes +<lpuni> Ah, okay, I'll bookmark that. Thanks, Tac. :)
+[2006.09.09-10.47] +Tacitus@LPUniversity <lpuni> Hopefully we'll be able to launch +the new website soon%^RESET%^
+[2006.09.09-10.48] Tigwyk@LP Heroes +<lpuni> Ack, it didn't bring along my forums I created for the +Education group. Agggh..
+[2006.09.09-10.48] +Tacitus@LPUniversity <lpuni> Sorry, lol%^RESET%^
+[2006.09.09-10.48] Tigwyk@LP Heroes +<lpuni> Oh well, I'll just put in the effort.
+[2006.09.09-10.49] +Tacitus@LPUniversity <lpuni> I can get the latest export if you +want%^RESET%^
+[2006.09.09-10.51] Tigwyk@LP Heroes +<lpuni> That would be generous of you... I put a lot of effort +into the forums.
+[2006.09.09-10.51] Tigwyk@LP Heroes +<lpuni> Thanks Tac, if you manage to do that.
+[2006.09.09-10.56] +Tacitus@LPUniversity <lpuni> Ok, getting the latest sql dump now +from the old site.%^RESET%^
+[2006.09.09-10.56] Tigwyk@LP Heroes +<lpuni> Thanks dude.
+[2006.09.09-10.58] +Tacitus@LPUniversity <lpuni> What did you do exactly?%^RESET%^
+[2006.09.09-10.59] Tigwyk@LP Heroes +<lpuni> Created a forum container called "Education" and created +a bunch of forums for different education aspects, as well as posted in +the newbie forum to welcome people toit.
+[2006.09.09-11.00] +Tacitus@LPUniversity <lpuni> Ok, can you check to see if it is +there now?%^RESET%^
+[2006.09.09-11.00] Tigwyk@LP Heroes +<lpuni> Yep, gimme a sec.
+[2006.09.09-11.00] Tigwyk@LP Heroes +<lpuni> Yeah, it's there. Thanks Tac!
+[2006.09.09-11.01] +Tacitus@LPUniversity <lpuni> <g> :]%^RESET%^
+[2006.09.09-11.03] Cratylus@Dead Souls Demo <lpuni> did you +change the password to the lpuni account?
+[2006.09.09-11.03] +Tacitus@LPUniversity <lpuni> First thing I did%^RESET%^
+[2006.09.09-11.05] Cratylus@Dead Souls Demo <lpuni> if yer not +gonna use it, how about changing it back?
+[2006.09.09-11.05] +Tacitus@LPUniversity <lpuni> Sure.%^RESET%^
+
+
+

+

+Not only is he talking and planning +on moving to this new site, he actually
+has already begun the process and +has a machine he's working on. He's even
+coordinating with someone else about +it. Now, I'll concede he hasn't yet
+uttered the words "We're moving to +Trenden", but given the action in
+progress, no reasonable doubt can +remain as to the intent here.
+
+At this point I log in to the +Wolfpaw account. I had paid for it, on
+behalf of lpuni, so I figured, hey, +if they're not gonna use it, maybe
+I can use it to learn how to use a +database and a forum and whatnot.
+
+The directories were empty, +obviously Tacitus was moved out,
+so I start playing around with forum +software (which I've *never* done
+before, this was the leftmost edge +of the learning curve). After
+a little while, I notice the stuff +I'm setting up is not at all
+working right, no matter how much I +RTFM. I go to a terminal window
+and see I'm logged off of Wolfpaw. +Odd.
+
+I log back in, see that there is +another user logged into the lpuni
+account, and realize that one of the +lpuni people might not have been
+informed by Tacitus about what was +going on. I booted them, figuring
+Tacitus would explain to them the +situation.
+
+Then on my MUD client window, this +happens:
+
+
+

+
+Tacitus@LPUniversity tells you: If +you think you are going to use lpuni.net
+    for some +competitor website - think again. It is pretty low of you to
+    revoke the +hosting too.
+
+You tell Tacitus@LPUniversity: what +on earth are you talking about?
+
+Tacitus@LPUniversity tells you: +You changed the passwd to the shell and now
+    you're +uploading your own crap.
+
+You tell Tacitus@LPUniversity: i +said "if yer not gonna use it, change the
+    password back"
+
+You tell Tacitus@LPUniversity: you +changed it back
+
+You tell Tacitus@LPUniversity: +therefore, you're not going to use it
+
+You tell Tacitus@LPUniversity: did +you not understand the english phrases
+    used?
+
+Tacitus@LPUniversity tells you: I +thought it was just a polite way of asking
+    for getting +access back because you wanted to have the passwd.
+
+You tell Tacitus@LPUniversity: ok, +let's go over this
+
+You tell Tacitus@LPUniversity: +apparently there's a misunderstading
+
+You tell Tacitus@LPUniversity: you +said you were going to use trenden
+
+You tell Tacitus@LPUniversity: i +said "fine"
+
+You tell Tacitus@LPUniversity: today +i see you *are* using non-wolfpaw
+
+You tell Tacitus@LPUniversity: so i +tried to login to wolfpaw
+
+You tell Tacitus@LPUniversity: you +had changed the passwd
+
+You tell Tacitus@LPUniversity: i +said "change it back if yer not gonna use it"
+
+You tell Tacitus@LPUniversity: you +changed it back
+
+You tell Tacitus@LPUniversity: i log +in
+
+You tell Tacitus@LPUniversity: all +the lpuni shit is gone
+
+You tell Tacitus@LPUniversity: so i +go "great. i guess it's my turn to play"
+
+You tell Tacitus@LPUniversity: i +changed the password because i have no idea
+    who has yours
+
+You tell Tacitus@LPUniversity: and i +started to play
+
+You tell Tacitus@LPUniversity: next +thing i know, i get booted off and you're
+    moving shit around
+
+You tell Tacitus@LPUniversity: if +you want to talk about rude, let's talk
+    about YOU
+
+Tacitus@LPUniversity tells you: +Hmmm...
+Tacitus@LPUniversity tells you: Ok.
+Tacitus@LPUniversity tells you: I +guess we misunderstood each other
+
+
+You tell Tacitus@LPUniversity: i'm +waiting to hear your side
+
+You tell Tacitus@LPUniversity: cuz +im rather pissed off at YOUR behavior
+
+Tacitus@LPUniversity tells you: +tell cratylus@Dead Souls Demo: I thought you
+    were being +offensive and were going to setup a competitor website (as you
+    had hinted to +the other day) and were planning to use the lpuni.net
+    domain.
+
+You tell Tacitus@LPUniversity: how +does that justify booting me off my own
+    hosted account?
+
+You tell Tacitus@LPUniversity: that +i paid for
+
+You tell Tacitus@LPUniversity: and +that you abandoned?
+
+Tacitus@LPUniversity tells you: +Because I changed my mind and announced it on
+    Intermud and so +I went to work editing files and what not - Then when I
+    lsed there was +all your crap all over the place so I decided to take
+    defensive +actions.
+
+You tell Tacitus@LPUniversity: you +changed your mind? when?
+
+Tacitus@LPUniversity tells you: on +lpuni
+
+Tacitus@LPUniversity tells you: +And since you had changed the passwd, started
+    to upload +content that was being rendered under the lpuni.net vhost, I was
+    like wtf
+
+Tacitus@LPUniversity tells you: I +was still logged in from earlier when I
+    deleted +everything so that I can upload a newer copy.
+
+You tell Tacitus@LPUniversity: i +dont see it. what did you say to indicate you
+    were staying on +wolfpaw?
+
+Tacitus@LPUniversity tells you: +"Oh, I know what I can use wolfpaw for."
+
+You tell Tacitus@LPUniversity: +backup?
+
+You tell Tacitus@LPUniversity: no
+
+You tell Tacitus@LPUniversity: i'm +not paying to be your backup site dude
+
+Tacitus@LPUniversity tells you: +Well, we can always use it for one of our
+    department +websites.
+
+You tell Tacitus@LPUniversity: no. +that was not the deal. the deal was, you
+    needed hosting, +and i provided it. now you have hosting elsewhere. the
+    end.
+
+Tacitus@LPUniversity tells you: +But what if Trenden going sour again?
+
+You tell Tacitus@LPUniversity: do +you expect a world where choices lack
+    consequences?
+
+Tacitus@LPUniversity tells you: +You know, it's ok - You be like that. Now,
+    lets discuss +the future of the domain.
+
+You tell Tacitus@LPUniversity: i'm +not "being" like anything. you're trying to
+    unilaterally +alter the deal to your advantage
+
+You tell Tacitus@LPUniversity: +that's wrong and fucked up
+
+You tell Tacitus@LPUniversity: and +then you have the gall to boot me off the
+    account i pay for +myself
+
+You tell Tacitus@LPUniversity: and +then you have the gall to get fucking mad
+    at ME
+
+You tell Tacitus@LPUniversity: +there's something wrong with you
+
+You tell Tacitus@LPUniversity: +seriously
+
+You tell Tacitus@LPUniversity: +you're wasting my time
+
+Tacitus@LPUniversity tells you: +TBH, I'm just worried about the domain.
+
+You tell Tacitus@LPUniversity: well +that's the last damn thing on my mind
+    right now, mister
+
+You tell Tacitus@LPUniversity: it's +like you lack borders
+
+You tell Tacitus@LPUniversity: it's +like, if you *can* do a thing, you *do*
+
+You tell Tacitus@LPUniversity: +you're like a damned child
+
+You tell Tacitus@LPUniversity: i'm +starting to think yer still a teenager
+
+You tell Tacitus@LPUniversity: +because you simply do not act like a
+    responsible adult
+
+Tacitus@LPUniversity tells you: +reply Cratylus, I felt threatened by your
+    actions so I +took action. It appeared very much so that you were taking
+    offensive +action against lpuni.
+
+You tell Tacitus@LPUniversity: it +didn't occur to you to *ask*?
+
+Tacitus@LPUniversity tells you: I +thought your actions made it very clear what
+    your intent was
+
+You tell Tacitus@LPUniversity: i +disagree. i think you went off half-cocked,
+    and proceeded to +disrespect me with no need whatseover
+
+You tell Tacitus@LPUniversity: i'm +completely disappointed in you
+
+You tell Tacitus@LPUniversity: every +time you have a choice, you pick
+    childishness, +pettiness, and short-sighted self-interest
+
+You tell Tacitus@LPUniversity: i'm +sick of giving you chances
+
+You tell Tacitus@LPUniversity: at +this point, i just *might* set up a rival
+    site, if i feel +like it
+
+You tell Tacitus@LPUniversity: +you'll just have to see if i do
+
+Tacitus@LPUniversity tells you: +Dammit - why do you always have to be _right_?
+    <.< +>.>
+
+Tacitus@LPUniversity tells you: +*sighs*
+
+You tell Tacitus@LPUniversity: i +don't understand why you have to keep trying
+    to fuck with me. +you lose. every. time.
+
+Tacitus@LPUniversity tells you: It +is like I'm haicapped when ever I argue
+    with you - it +isn't faire.
+
+Tacitus@LPUniversity tells you: +*fair
+
+Tacitus@LPUniversity tells you: +*handicapped
+
+You tell Tacitus@LPUniversity: being +wrong is indeed a major disadvantage in a
+    debate
+
+Tacitus@LPUniversity tells you: I +dunno why we fight all the time either...
+
+You tell Tacitus@LPUniversity: +because you do fucked up shit
+
+Tacitus@LPUniversity tells you: I +don't do fucked up shit to anyone else!
+
+You tell Tacitus@LPUniversity: +you'll have to discuss that with yer therapist
+
+

+
+Ok, so you can pretty much judge for yourself what happened.
+From my point of view, Tacitus took a situation he had
+misunderstood and interpreted it as me having the worst
+possible intentions, and rather than discuss it, he acted
+to intervene and sabotage what I was working on. On an account
+*I* provided to lpuni out of my own pocket, which he had
+abandoned.
+
+I don't understand why Tacitus has decided to not only
+misremember this event, but now is starting to publicly
+accuse me of wrongdoing.
+
+Now, one last, short log from today:
+
+

+
+[2006.09.16-22.08] Cratylus@Dead Souls Demo <lpuni> tacitus, +let's post the tell log, and that'll clear it all up
+[2006.09.16-22.08] Cratylus@Dead Souls Demo <lpuni> ok?
+[2006.09.16-22.08] +somerville32.freenode@RtHBridge <lpuni> I guess you could. It +just shows me getting pissed off for what you were doing and for using +lpuni.net
+[2006.09.16-22.09] +somerville32.freenode@RtHBridge <lpuni> You'll note that I +specifically stated I didn't intent to hand it over
+[2006.09.16-22.09] +somerville32.freenode@RtHBridge <lpuni> And then you were like, +"well I said..." - kind of hard to argue with that
+
+
+
   
+    Simply untrue.
+
+    I thought I had handled Tacitus's behavior of the +9th pretty
+well. I didn't make a big fuss, and I put together an nice explanation
+of the general idea behind me starting a new site. I didn't think
+it was really necessary to get into the gory details of why I was not
+going to be posting content on Tacitus's new site. That I'd finally
+completely lost all faith in him seemed a negative way to start a
+site, and what I wanted to do was something positive.
+
+    But I can't let people travel under the +misimpression that
+Tacitus's wild accusations have a basis in fact. In impugning my
+integrity, he made it necessary for me to explain fully the situation he
+misrepresented.
+
+    I know how petty and silly this looks to people who +aren't
+involved. Heck, it looks pretty petty and silly to me. But I'm posting
+all of this so that people understand. So that, six months from
+now, when Tacitus commits some other outrage (See here for an +earlier one)
+I can simply say "Look at what he did back in September of '06. I
+don't think I need to get into who has the more credibility." And,
+bing, end of argument.
+
+    I hope this can be the last word on what the deal is +with
+Tacitus. I don't know what his problem is with me. No matter how
+much support I've provided LPUni, I'm still persona non-grata. With
+this document I wash my hands and leave Tacitus in your care.
+
+    Do what you will with him, I'm done. I don't see any +use
+in me collaborating with him on any project, though if you choose
+to do so, know I wish you only the best of luck. He's nothing
+so grand as my enemy, I just don't see me working with him
+on anything, because the only trust I have in him is that he'll
+keep trying to undermine me and misrepresent my efforts.  
+

+
+
Dead Souls home + + diff --git a/lib/www/articles/old/tms.html b/lib/www/articles/old/tms.html new file mode 100644 index 0000000..ccaa219 --- /dev/null +++ b/lib/www/articles/old/tms.html @@ -0,0 +1,67 @@ + + + + + Cratylus and Top Mud Sites + + + + +
Cratylus and Top Mud Sites
+
+The management at Top Mud Sites changed and the new admin established a +New Way that was intended to put a lid on flames and mean +people and so on, which is a pretty good idea and something I try to do +on my own forum. Unfortunately, they got a little out of +hand and got to deleting stuff that just didn't need it, in my +opinion.
+
+

+So I expressed my opinion. +Turns out +that this is a banishable offense!

+
+ So, without +further ado, here are pdf printouts of the forum pages where I sealed +my doom. Even though some posts were +deleted by the admins, I attest that I have not modified in anyway the +content...this is the real deal (to the +extent the moderators allowed things to remain).
+
+ +
+ I kind of +wish I'd got a chance to rebut his snarky little jabs about my own +forum. I had a great comeback (til I +realized I was banned), but I think his +statement illustrates the problem with TMS well enough.
+
+ Feel free to +comment on this on the TMC forum page where I announced this: http://www.mudconnect.com/discuss/discuss.cgi?mode=MSG2&area=general&message=19610#19610
+
+

+

+
+
	 	
LPMuds Homepage

+ + diff --git a/lib/www/articles/renaissance.html b/lib/www/articles/renaissance.html new file mode 100644 index 0000000..dc771f7 --- /dev/null +++ b/lib/www/articles/renaissance.html @@ -0,0 +1,34 @@ + + + + + An LPC Renaissance + + + + +
An LPC Renaissance	


This is a long article. My time is valuable, and I presume you
feel the same way about yours. I will therefore begin with a
summary, then attempt to present my arguments in a structured way
to make things as brief as possible, while remaining informative.

There is horrendous and inexcusable bias toward one lib here.
I am its author, so I hope that, even if you don't forgive
me this bias, you'll understand it is just pride and not
disparagement of others.


Summary:
* I am working on a way to promote LPmuds.
* My motivation and reasoning are explained in this article.
* The conclusion I've reached is that at this point, I need content.
* This means I need help.
* I ask for your help, either creating new stuff or donating content.


Section Index:
My Motivation
The Objective
Progress So Far
Assessment of Viability
The Next Step part I
The Next Step part II


My Motivation
-------------

Lib coding is my hobby. I really enjoy it, much the
way a motorcycle freak spends his free time in the garage, or
like a gardening enthusiast constantly in his yard. My code
of choice and expertise is LPC.

It is more fun (for me) to have a hobby shared by
many people than a hobby shared by few. With more LPC coders
out there ideas and projects can be shared, and this is
a fun and cool thing.


The Objective
-------------

I want to lure more people into using LPmud. The
more people use it, the more they will see how great it is
and either they will create their own LPmuds, or join
existing ones. Either way, the continued growth of an LPmud
community can build momentum toward a critical mass, where
a self-sustaining chain-reaction of continual adoption and
innovation can happen without relying on a couple of "movers
and shakers" to make things go.

This objective satisfies my intent, which is to have
more fun in my hobby, by having more people participate in it.


Progress So Far
---------------

I've sucessfully revived an old LP mudlib called
Dead Souls. It's been thoroughly debugged, updated, and
brought in line with the expectations of modern builders. I
don't feel any shame in saying it is, hands down, the best
LP mudlib you can download today
. There are some thirty or
so development muds currently up and using Dead Souls.

I've partnered with Tacitus in promoting a site
called LPUniversity, which uses forums and a different
mudlib to advance the cause of LP.


Assessment of Viability (where I explain muds are not dead)
-----------------------

Probably the first objection any LP old-timer will
have is "what's the point? There are no more mudders."

From the perspective of the typical LP mud, this
probably seems like a clincher. Over the years, LP muds have
seen a decline in their playerbase, and one by one many
of the old LP muds have quietly winked out of existence. The
gjs router is loaded with moribund muds that barely breathe
one or two players a day, if that many. Muds, it seems,
are dead.

This, however, is not so. That dust-covered old
LP geezer is mistaken. There is a strong and vibrant mudding
community out there. More than a thousand muds, certainly
thousands of players, with new ones every day. There is
a thriving mud landscape out there that the LP dinos don't
know about because they're in the old rut of seeing only
as far as their intermud network.

A couple of URL's should be a wakeup call. First,
take a look at http://www.topmudsites.com and scroll down
to the mud list. Connect to any of the top 10, or top 20, or
top 40, and tell me that mudding is dead. Consider also that
not only does the "top" list there go to 100, some of these
are *commercial* muds. People *pay* to be players.

"A few fools a community does not make," you might
say. Poke at a different site. Go to http://mudconnector.com/mud_listings.html
and connect to a few of the muds listed there. There's life
in muds, baby. Just because your mud is stagnant doesn't
mean everyone else has a foot in the grave.

What you are seeing is that LP muds have given up.
Like Detroit in the 80's. No innovation, no keeping up with
the market. Of course the LP intermud is a graveyard. The
world passed us by. Diku, once in ascendance, is now supreme.

But it doesn't have to stay that way.

LP muds are fabulously flexible and easy to learn
compared to the most popular types of muds out there. The mud
scene is largely composed of Diku and its derivatives, not
because of technical superiority or ease of use, but because
the fragmented LP community forgot to keep innovating.

The Diku muds have a dramatic advantage: since all
are written in C, for the most part anything written in one
will work on any other. There are vast repositories of
"snippets" that Diku admins consult...and by plugging this
here and that there, they can have a playable mud with
dozens of areas in a day. Or less.

Their disadvantage is that to do really fancy stuff,
they need someone highly skilled in C. As you know, that is
not so for LP muds. Just a fair knowledge of LPC is needed,
and this is an order of magnitude (at least) easier than
becoming mud-code proficient with C.

Dead Souls 2 has been specifically designed to
compete with Diku. It is super easy to install, and it has
an "On-Line Creation" system that lets you bypass line
editing when creating rooms, npc's, objects, etc. The big
stumbling block for beginners, the ed line editor, is now
just a minor inconvenience, if anything. It's heavily
documented, and I've gone as far as setting up a newbie-
friendly I3 router to support new adopters. It even comes
with a Windows version.

DS2 is poised to be the killer app that swings mass
interest back to LP, and this renaissance of LP adoption
is what I seek, to foster new development and innovation.


The Next Step, part I
---------------------

Why do people write/run muds? If they just did it
for the technical pleasure, they'd just never open. The
majority of mud admins out there do what they do because
it's fun to run a game (or at least, they thought it would
be) and a game without players is, well, not much of a
game.

A mud's success is most often measured in its
playerbase. Therefore, I have to consider this in my
LP Renaissance project. If people decide on an LP codebase,
or specifically DS2 as a lib, it's not usually because they
like me personally, or because the box it came in has a
cool dragon on it. My personality is insufferable, and there is
no box. The reason people would adopt is that they think they can
make a successful mud with it, and this most often means
lots of players.

My job, then, is to convince potential adopters that
players will come. So, what do players want? Good gameplay,
fun challenges, interesting areas. In short, players are
here to be entertained.

However, the stock Dead Souls 2.1 mud doesn't have
much in the way of areas. There are a few sample domains,
sure, and this is enough to demonstrate the basics of what
Dead Souls can do. But to really sell Dead Souls as a viable
option, it needs knock-em-dead areas. Areas that, when a
curious potential adopter installs and logs into their
test DS mud, makes them go "WOW!".

*That* is what sells a codebase. *That* is what can
make or break a lib. I am deeply proud of the work I've
done under the hood, but I do not fool myself about my
level of creativity or imagination. I'm smart enough to
know that I am great at lib work, but mediocre at content
creation.

And I've worked too hard on Dead Souls to resign
myself to mediocrity in one of its most vital aspects: gameplay.

To move forward, DS2 needs fun, exciting, *thrilling*,
stock areas. The current defaults are "just fine". They show
you how to do things, and things work properly. But that isn't
enough. When someone tries out DS2, I don't want them to say
"gee that was easy to install, and everything works properly."

I want them to say "This is GREAT!".

I therefore ask for your help. If you are a good
builder, please join my effort. It's your contribution of an
inspiring, exciting area for Dead Souls that will greatly
enhance its appeal and adoption.

In contributing to a Dead Souls area, you will be
ensuring that your work will live on, beyond just one mud.
Rather than have your work locked away in a single mud, and
hoping that mud doesn't fail, you can be sure that thousands
of people enjoy how you've expressed your creativity.


The Next Step, part II
----------------------

This second part is closely related to the previous
issue. Let's assume that Dead Souls 2 is the vanguard of an
LP renaissance, and what is good for it is good for LP in
general (obviously this is tortured logic, but please humor me).

As wonderful as DS2 is, its Achille's heel is content.
Content, content, content. It isn't enough that DS2 is
technically superior in any way to any other lib. This advantage
is meaningless if people aren't attracted to it in the
first place. And the attraction for adopters is players. And
the attraction for players is content.

The request I'm about to make may well be unprecedented
in its bald, shameless effrontery. If you've read this far, though,
you can probably tell I've lost a lot of those normal behaviors
people associate with prudence.

The request? I want your mud.

Now, don't get me wrong, if you've got players and they
have fun and you run a game, I ask nothing of you. Ignore what
I said.

But there are a few out there that I'm speaking to. The
ones who can't really explain why their mud is still open, since
they haven't seen a serious player in months or years. The ones
that actually closed a mud, and maybe have a backup burned onto
CD, probably never to be played again.

You know who you are. Your content is great, and was once
enjoyed gratefully by many people, but now rather than collect
players, it collects dust. You're either flirting with closing
it, or closed it already.

I ask this of you: if nobody is gaining benefit from
that work, if all it will do is go to Old Mud Heaven...give it
to me.

What I want to do is build a showcase mud. I want to
provide potential adopters an example of what a Dead Souls mud
can be...with players and active creators and everything. I
don't just need content for the default Dead Souls distribution,
I also need content to run a Dead Souls Showcase that attracts the
kind of attention and energy that can make it an engine of
progress for LP.

I resurrected Dead Souls. Download it and see for yourself
how much effort and dedication went into it. You'll know I have
the skill and insane determination it takes to convert your
code, and make your mud breathe again.

Obviously you will admin your content, if you want. And
the Intellectual Property is yours...you wrote it, you have
copyright.

What I want is not to take credit for anything. What I
want is to have a towering beacon of LPC goodness that can
call to new adopters, and serve as a source of potential
players and creators for the Old Guard.

Don't just say "Sounds neat. Hope it works." Help
me. I need your contribution. I can't do all this on my own.

- Crat
cratylus@comcast.net


Dead Souls Homepage

+ + diff --git a/lib/www/articles/router_controversy.html b/lib/www/articles/router_controversy.html new file mode 100644 index 0000000..7f5387e --- /dev/null +++ b/lib/www/articles/router_controversy.html @@ -0,0 +1,11 @@ + + + + + Router Controversy + + + +
The Intermud Router Controversy

"No good deed goes unpunished."

A brief history of Intermud-3
The birth of *yatmim
The death of *gjs
The first conflict
A question of application of authority
A knack for heckling
DIY
Dear darling fascist bullyboys
A New Hope
Going forward



A brief history of Intermud-3:

I3 as a protocol was born of a desire to have communication
between muds. The developers put together a specification and coded
an implementation on a mud that served as a reference. Other muds
used this protocol, and it became a de-facto standard for networked
communication between MudOS muds. Other LP muds have used it, and
even Diku-based codebases have implementations available to them.

The way I3 works is that your mud has a client program
which can be configured to connect to an I3 server. That server is
usually a mud running special server code. That server code is
called the "router" code, and the mud that runs it is called the
"intermud router". The router serves as a central hub for communication,
so muds that want to talk to each other using the I3 protocol will
connect to one router, which will then forward data between them.
When lots of muds connect, you can have a lively, fun community
space for chatting and help and such.

The developers of I3 ran the main intermud router. It
was called *gjs. The asterisk is part of the name, and is meaningful
to internal router processes. However, the asterisk is commonly
dropped from router names when discussing them casually.

*gjs had rules. Using colors on channels was forbidden,
for example. Hate speech was not allowed. Muds who made nuisances of
themselves could find themselves banned from the router.

As the years passed, the router admins seemed to have less
and less interest in the router. The last time I saw any rule
enforced was back in 98 or 99, when StarMUD was banned...and frankly
I don't even remember what they were banned for. My best guess is that
the admins just got bored with running the router, and couldn't
be bothered arguing with jerks about rules.

By 2006, *gjs was extremely unreliable. It would go
down, literally for days, then mysteriously come back up with no
word of explanation. Its flagship chat channel, imud_gossip, had
become such a notorious cesspool that at least one major codebase
maintainer swore off putting I3 code in his work. New muds were
heavily abused, in some cases to the point of destruction. Casual use
of hate speech (stuff instantly censored on any MUD discussion
board I've been on) was common enough to be unremarkable.


The birth of *yatmim:

By that time, I had picked up maintainership of the
Dead Souls codebase. Dead Souls muds had historically been part
of the I3 community, and as the maintainer, I encouraged people to
use intermud as a way to ask questions and share their experiences.

However, the atmosphere of hostility at *gjs and its
unreliability made it hard for me to foster the new community
I wanted to nurture. I decided that I would set up an alternate
router. This would be a router people could count on to actually
be up and running all the time, and a place where they could go
without fear of punishment for just being new.

It was my intention to provide an alternative. If people wanted
to go back to *gjs and its degeneracy, that was fine by me. Nothing
in the code prevented it (and in fact, I added a command to switch
back and forth as one pleased). But at least *new* muds would get a
chance to wade in the shallow end before diving into the the
piranha pit.

The new router was called *yatmim. It was just a
couple dozen Dead Souls muds, mostly empty. The idea never, ever, was
to compete with *gjs. How could I? The eminences of LP mud were there,
probably ossified into their router connections. All *yatmim was
intended to be was a place for new muds to catch their breath, get
their heads on straight, and if they wished, then move elsewhere.

It occurred to me during one of *gjs's long downtimes
that others might want to know about an alternate router, so I
posted an invitation to other muds to join *yatmim, IF they
agreed to abide by the rules.

Since hostility was half the problem I wanted to solve,
*yatmim had rules. Pretty standard stuff, and the kind of thing you'd
expect at a place where community support is the point. Don't
hassle newbies, don't use hate speech, don't spam the channels, etc.
None of it was hard to comply with if you're a normal person, and
none of the DS muds that joined complained.

*yatmim chugged along, a happy, friendly little community
away from the grue of *gjs.


The death of *gjs:

On August 1 2006, *gjs went down again. This was not unusual.
By the summer of 2006, *gjs had become so wildly unstable that it
would be fair to say it was up and down in equal measure. I didn't
think much of it at the time.

Days passed, then weeks, and it became clear that that
this might not be an ordinary failure. After two months, I posted
another invitation to muds. It seemed to me that it would be a nice
kind of public service to offer some refuge to the abandoned. I made
it very clear in every invitation I made, be it posted or personal,
that *yatmim had rules and they were enforced.

Perhaps I should have known better. I've subsequently
been accused of being responsible for the conflicts that came, and
that I should have foreseen them. Maybe that is true. In my defense,
I thought I was being reasonable. I gave people the option to join
or not join, based on their willingness to obey the rules. It's
a bargain we strike all the time, when we enter a home, pub, or
even a public park. It's not a new concept, it's not hard to understand,
and yes, I trusted my fellow humans to make informed decisions on
this point. If that makes me guilty of something, I argue I'm
guilty of common sense expectations of normal behavior.


The first conflict:

Duuk@Haven and Corvin@Nanvaent are folks well known for
the vile content of their speech and their habitual hostility.
One can see them as "adding flavor" to a community I suppose, and
in any case, who cares that much. But once on *yatmim, they were
subject to the rules, which they broke.

Despite frequent pleas on my part, and ever-sterner
warnings, both of them chose to continue to use racist language
on a channel where it is not permitted. Eventually I came to the conclusion
that rules are pointless without enforcement, and as admin, I'd
have to do something about it. So I banned their muds from the
imud_gossip channel.

They could still connect to the router and talk on other channels.
They could do tells to other people, remote who's and finger's. But
since they kept breaking channel rules, I removed them from the
channel they were abusing.

A howl of protest erupted from the people on both muds,
and from someone named Arren, who appeared to take on their cause.
You can read a log of how the conflict was debated here.

The level of rancor was surprising to me. After all, I
thought my actions were not only rational and reasonable, but
inevitable given the rules. I wondered if there was a problem I was
misunderstanding, so I opened up the question to vote and discussion
on a forum site. The vote results and some comments are here.

The final page of the discussion is here.

I had been surprised by the nature of the opposition to
my act, but it was the vote result that surprised me the most.
Out of the 14 people who bothered to vote, exactly one felt that
the rules should be changed.

I was completely taken aback. Certainly more than one person
in the discussion thread opposed the bans...so what was going on?


A question of application of authority:

It seems that the problem Arren had was in how the rules
were applied. It seems that the problem most others had was that
the rules were applied, or that it was me who was applying them.

As far as I can tell, nostalgia for the old laissez-faire
adminship of *gjs was what I was running into. Nobody was really
up to arguing against the rules. And, really, how could they?
They're the most standard, typical rules of moderated forums.

What they didn't like was not being in the decision-making,
and that the rules, fine as they might be, were actually applied
at all.

As I indicated in the discussion thread, I was at a
complete loss as to how to address those concerns. I am unable
to morph into someone else. The router design is based on a
standard I did not develop. Someone has to have admin privs, and
if there are to be rules, that admin has to enforce them, or
they are moot.

I didn't know what I could possibly do to change anything
to people's satisfaction, given that as far as I could tell:

1) The rules were generally agreed to.
2) Muds implicitly agreed to them by joining *yatmim.
3) I had tried to avoid being a jerk, by first warning, and
finally only banning in the most limited way I could.
4) When the muds in question agreed to comply I immediately
let them back on.

The only conclusion I could reach was that the problem
was unhappiness with a single person being in complete control
of the enforcement process. At the end of the thread, I invited
folks to work toward some sort of distributed I3, if this
really was the problem.

I received no responses offering to help in this endeavor.


A knack for heckling:

Throughout these events, the mission of *yatmim has
remained the same. It is a place for new muds to conduct their
business according to the rules I set down. I set them down
for the purposes that suit me, among them providing a space for support
of new muds, particularly Dead Souls muds, the lib I develop.

Following the death of *gjs, refugees are welcome and
I have very much enjoyed their participation, because the
vast majority find the rules unremarkable and ostensibly acceptable.

However, a tiny minority of hecklers appears to have
taken to heart the misconception that *yatmim is the new *gjs.
If that's your assumption, then an obvious set of logical
steps follow: Cratylus is trying to reform people, he's usurping
control over something he has no right to, etc.

Somehow in the noise is lost the fact that this is
a router people volutarily connected to, subject to the rules
which derive from its mission.

*yatmim was never intended to be the new *gjs. *yatmim
started because *gjs was the problem.


DIY:

In the finest traditions of the internet, rather than
complain on *gjs about how unsuitable it was for my purposes,
I just rolled my own. I used Tim@TimMUD's fine router code
to put up *yatmim, because relying on other people to fix my
technical/development problem is something that has just never
quite panned out for me.

I have similarly made it possible for anyone who wants
to run an intermud router to do so. I include the router code in
every single download of Dead Souls. Anyone can download it
and make their own router, where the rules can be or not
be to their heart's content.

It seems to me that if people really want to have *gjs
back, they can either track down the old *gjs admins and
have it out, or they can set up their own router, which is
incredibly easy to do now with Dead Souls.

Instead, a few folks prefer to whine and threaten and complain.

Dear darling fascist bullyboys:

In a way, this article is dedicated to them, because it
is intended to serve as the official response to their continuing
petulance, and those (and yes, there seem to be some) that are
swayed by their ad hominem attacks.

It's hard for me not to respond when someone complains,
because I take Dead Souls seriously, and I take the purpose
of *yatmim seriously. I find it difficult just ignoring people, even when
their position has been shown to be moot, or incorrect, or
just plain mean-spirited and in bad faith. I feel like it starts
me down the path of evil, the dark path of the Admin That Just
Doesn't Care. And so I find myself involved in the exact same
argument with some folks, over and over and over, as if they were
incapable of remembering the rules they agreed to.

As much as I want to continue being a responsive admin,
as much as I want to demonstrate that I am not trying to be their boss,
not interested in their private communications, not invested in
being The Next *gjs....there's a limit to my time. I can't get stuck
in these Groundhog Day debates whenever someone is bored. Continuing
to justify my intentions takes up time I can ill afford on petty
bickering.

Let this article stand as the response to whatever
charge of malicious intermud intent is presented against me. If
it is insufficient, then let the chips fall where they may.


A New Hope:

Arren@Anarres II has set up a new router. Please see the
LPMuds.net intermud page for connection details.

When he set up this router, another Arren debate
occurred. You can see the details here.

A you can see, it's rather confusing. What he'd first
agreed to was being listed on the intermud page, but then he
wanted "primary routership". He agreed with the idea of setting up
an inter router network but then continued to argue for his
being primary router, which in the context of a distributed
network doesn't make sense. If there's an inter router network,
what difference does it make who is the admin of which router?

And finally, though he continually argued against
"fragmentation", when I hesitated to agree to all of his demands
that very night, he decided it was ok to ask muds on *yatmim
over to his router.

I think it's understandable for me to be wary of the
conflicting messages and the aggressive pressuring. I've asked
for comments
on that log on the lpmuds site, because frankly,
I'm not sure I get his deal.

However, I don't have to understand him in order to
know he'll run a reliable router. If you are uncomfortable
with the way I run *yatmim or even if you want a change of scenery,
Arren's router is a perfectly good choice.


UPDATE, 7 July 2007:
By chance I ran across something that explains to me
the reason for Arren's behavior (aka Shevek aka Ben Mankin).

I am no longer puzzled. It appears that rudely fragmenting communities is
actually a habit of his. See the following urls (be patient, the wayback machine
can take a very long time to load pages) (Arren's text is in red):

http://web.archive.org/web/20050206225902/moscow.6o4.ca/shevek_no_apology.html

For context on what they're talking about: http://libspf.userfriendly.net/FAQ

AFAICT Arren and some other guy decided to take over the name (by
incrementing the version number) and development of the spf
library, over the objections and concerns of the developer who wrote it
and was still maintaining it. This was seemingly done as rudely and
aggressively as Arren's attempted maneuver to claim primary i3
router adminship.

I'm no longer so sure about recommending folks to
use Arren's router. It pains me to suggest affiliation
with someone whose behavior is chronically so meanspirited and
underhanded.

However, the fact remains that his router is probably a quite
reliable alternative, and I suppose that's all that matters.


Going forward:

As I mentioned before, those unhappy with *yatmim
can avail themselves of Arren's router. I don't
know what his rules and policies are, so you'll need to
discuss that with him, but believe me, you won't be hurting
my feelings when you go :)



Dead Souls Homepage

+ + \ No newline at end of file diff --git a/lib/www/articles/why_ds.html b/lib/www/articles/why_ds.html new file mode 100644 index 0000000..8a1c2f4 --- /dev/null +++ b/lib/www/articles/why_ds.html @@ -0,0 +1,15 @@ + + + + + New Muds and Dead Souls + + + + +
Why New Muds Should Use Dead Souls 

Normally I like to stay neutral, and say stuff like
'Use whatever codebase you're comfortable with, I don't
want to start a flamewar.' And today that would be half
right. I don't want to start a flamewar.

But I'd like to take a moment out to advocate LPmuds
for new mud admins. If this is going to get you all pissy
and flamey, you can just stop reading here.

I was inspired in part by recent discussions about the
division of labor between 'coders' and 'owners' and such on
other codebases. This seems bizarre to me. It's my opinion
that a mud 'owner' should be just as capable as any person
on her mud to build and code, and manage personnel besides. I
see it kind of like the role of a captain on a ship. The captain
may not have to be in the engine room answering 'ahead one
third', but she damn well should know *how* to, if the
situation calls for it.

A ship captain should know every inch of her ship, how
many lifeboats, etc. If the ship is not performing well,
she should be able to identify this and she should be able
to supervise the corrections, if necessary.

Obviously any metaphor has its limits. You can come up
with all sorts of reasons why the ship metaphor is flawed.
But the main reason I use it is the sense it carries of
ultimate responsibility resting on the shoulders of one
officer. Whatever happens on a ship, however successful its
mission, whatever disaster it incurs, all of it, is the
responsibility of the captain. The buck stops there.

So, to me, 'my mud is failing because I can't get a
coder' doesn't make any sense at all. Obviously a successful
mud will usually have a staff of more than one, but at
first, it's just you and your dream, man. You gotta build
that boat by yourself at first, before you can convince a
proper crew to join you.

And if you just get a prebuilt boat you don't know how
to customize, why should anyone join you, when they can just
get their own? And why should they listen to you, if you
don't even know enough to run it yourself? I see lots of
muds adrift at sea here, with a lone 'captain' at the bow,
calling out in the darkness for an experienced crew that
will never come.

I can only guess that the problem here is either fear
of C or inability to learn it fast enough to suit the admin.
I'm not addressing the newbie admins who are diligently
studying their C textbooks, determined to make a proper go
of it. I'm talking to those newbie admins who have decided
to make a mud and are determined to be admins and not C
coders.

If this is so, then my proposition is, forget about
starting a mud whose guts you don't intend to know inside
out. If C is too hard, and you doubt ever knowing it
well enough to rewrite commands and system code, then
you should drop your C based mud. You should think about
a codebase that uses a language you stand a chance of
picking up quickly and easily.

Yep. LPC. LPC is a 'coding language' in that it has
variables and objects and such. But these variables and
objects are not the 'bare metal' code elements
that you see in naked C. In LPC you have a level of
abstraction between you and that cold, hard C that makes
coding much easier...more like scripting than C coding.

Ok, let me ask you, in a Diku
style mud, how do you set a room so that you can't magically
teleport in or out? In Dead Souls, all you do is add this
to the file:

SetProperty('no teleport', 1);

In a Diku style mud, how would you have a mob respond
to a player saying something to them? In Dead Souls, you
just add this line to the mob's file:

AddTalkResponse('hello', 'hi!');

To make the mob do something when asked, you use AddCommandResponse.
To make it do or say something when *asked*, you use AddRequestResponse.
How would you do it in Diku?

Now, remember. This is not a 'Diku sucks' thread. For Diku
people, this stuff is presumably not that difficult. What I'm
showing you is how *trivial* this is to do, even for non-LPC people,
on LP muds. Don't get me wrong...you still need to spend a lot
of time going through docs, and looking at examples. But the
amount of time it takes to become LPC proficient is a tiny
fraction of the amount of time it takes to become C proficient
enough to handle mud coding.

You want a mud, you're not sure you can learn C fast enough,
and you aren't having luck finding a talented coder that will
bend to your will. I say your choice is obvious. Try an LP mud on
for size. Get your mud on.

Or wait for your knight in shining armor. Whichever comes first.

There are plenty of LP mud libs out there. I suggest you
take a look at Dead Souls. It's super easy to set up, and there is
an online intermud chat community ready to help answer your
questions.


Dead Souls Homepage

+ + diff --git a/lib/www/barrel.html b/lib/www/barrel.html new file mode 100644 index 0000000..7564668 --- /dev/null +++ b/lib/www/barrel.html @@ -0,0 +1,22 @@ + + + + + The Barrel + + +The Barrel
+
+http://xkcd.com/1/
+
+http://xkcd.com/11/
+
+(elsewhere) http://xkcd.com/20/
+
+http://xkcd.com/22/
+
+http://xkcd.com/25/
+
+http://xkcd.com/31/ + + diff --git a/lib/www/cgi/chanlogs.c b/lib/www/cgi/chanlogs.c new file mode 100644 index 0000000..917ffa9 --- /dev/null +++ b/lib/www/cgi/chanlogs.c @@ -0,0 +1,70 @@ +#include +#include +#include +#include + +inherit LIB_DAEMON; +inherit LIB_CGI; + +void validate(){ + if(!master()->valid_apply(({ "SECURE", "ASSIST" })) && + strsrch(base_name(previous_object()), SOCKET_HTTP)){ + string offender = identify(previous_object(-1)); + debug("chanlogs.c SECURITY VIOLATION: "+offender+" ",get_stack(),"red"); + log_file("security", "\n"+timestamp()+" chanlogs.c breach: "+offender+" "+get_stack()); + error("chanlogs.c SECURITY VIOLATION: "+offender+" "+get_stack()); + } +} + +string gateway(mixed args) { + mapping Logs = ([]); + int *times = ({}); + string err, full_name, path, junk1, junk2; + int i; + object ob = previous_object(); + string current_page = ob->GetReferer(); + mapping cookie = ob->GetCookie(); + string name = cookie["name"]; + string shib = cookie["shib"]; + string ret = ""; + + if(ENABLE_CREWEB){ + string *logfiles = ({}); + validate(); + + if(!name || !shib || !WEB_SESSIONS_D->authenticate(name, shib)){ + ret += "Bad session.
"; + ret += ""; + return ret; + } + + foreach(string file in get_dir(DIR_CHANNEL_LOGS+"/")){ + if(!file_exists(DIR_CHANNEL_LOGS+"/"+file)) continue; + Logs[file] = stat(DIR_CHANNEL_LOGS+"/"+file)[1]; + } + times = sort_array(distinct_array(values(Logs)),-1); + foreach(mixed element in times){ + foreach(mixed key, mixed val in Logs){ + string tmp_ret = "";//This shouldn't be needed, but it is. + if(val == element){ + tmp_ret += "Home
"; + ret += "Dead Souls Home
"; + + return ret; +} + diff --git a/lib/www/cgi/connect.c b/lib/www/cgi/connect.c new file mode 100644 index 0000000..6a26706 --- /dev/null +++ b/lib/www/cgi/connect.c @@ -0,0 +1,54 @@ +#include +#include +#include + +inherit LIB_DAEMON; +inherit LIB_CGI; +mapping UploadsMap = ([]); + +void validate(){ + if(!master()->valid_apply(({ "SECURE", "ASSIST" })) && + strsrch(base_name(previous_object()), SOCKET_HTTP)){ + string offender = identify(previous_object(-1)); + debug("upload.c SECURITY VIOLATION: "+offender+" ",get_stack(),"red"); + log_file("security", "\n"+timestamp()+" upload.c breach: "+offender+" "+get_stack()); + error("upload.c SECURITY VIOLATION: "+offender+" "+get_stack()); + } +} + +varargs string gateway(mixed args, mixed args2) { + object ob = previous_object(); + string host = ob->GetHost(); + string port = ob->GetPort(); + string ret = ""; + if(args2){ + host = args; + port = args2; + } + + if(ENABLE_CREWEB){ + //validate(); + + ret += "
"+mud_name()+" Connection Page

"; + ret += ""; + ret += ""; + ret += ""; + ret += ""; + ret += "
Your Browser seems to have no "; + ret += "Java "; + ret += "support. Please get a new browser or enable Java to "; + ret += "see this applet!
"; + ret += "

Home
"; + ret += "Dead Souls Home
"; + } + + else { + ret += "CreWeb is disabled. To enable it: mudconfig creweb enable

"; + ret += "Home
"; + ret += "Dead Souls Home
"; + } + + return ret; +} diff --git a/lib/www/cgi/creweb.c b/lib/www/cgi/creweb.c new file mode 100644 index 0000000..1ae2ccc --- /dev/null +++ b/lib/www/cgi/creweb.c @@ -0,0 +1,49 @@ +#include + +varargs string gateway(mixed args){ + string ret = ""; + string *ret_array; + mixed cookie, session; + + if(ENABLE_CREWEB){ + + if(!args || !stringp(args)) args = "123456789101112"; + + cookie = previous_object()->GetCookie(); + + if(!cookie || !cookie["shib"] || !cookie["name"]){ + ret += "Not logged in."; + ret += ""; + return ret; + } + + session = WEB_SESSIONS_D->GetSession(cookie["name"]); + + if(!sizeof(session) || session["shibboleth"] != cookie["shib"]){ + WEB_SESSIONS_D->EndSession(cookie["name"]); + ret += "Expired or conflicted session. Resetting."; + ret += ""; + return ret; + } + + ret += "Welcome to CreWeb.

"; + ret += "CreWeb is a very simple CGI web application that allows creators to
"; + ret += "log in, browse their home directories, upload and edit files.
"; + ret += "
"; + ret += "To mitigate potential security hazards, "; + ret += "directories outside home dirs may not be browsed.
"; + ret += "
"; + ret += "
"; + ret += "Your home directory is here
"; + ret += "Click here to see channel logs.
"; + ret += "Click here to logout.
"; + } + else { + ret += "CreWeb is disabled. To enable it: mudconfig creweb enable

"; + } + ret += "

Home

"; + ret += "Dead Souls Home"; + ret += "

Your ip is: "+session["ip"]; + + return ret; +} diff --git a/lib/www/cgi/edit.c b/lib/www/cgi/edit.c new file mode 100644 index 0000000..14cf3f2 --- /dev/null +++ b/lib/www/cgi/edit.c @@ -0,0 +1,58 @@ +#include +#include +#include + +inherit LIB_DAEMON; +mapping UploadsMap = ([]); + +void validate(){ + if(!master()->valid_apply(({ "SECURE", "ASSIST" })) && + strsrch(base_name(previous_object()), SOCKET_HTTP)){ + string offender = identify(previous_object(-1)); + debug("edit.c SECURITY VIOLATION: "+offender+" ",get_stack(),"red"); + log_file("security", "\n"+timestamp()+" edit.c breach: "+offender+" "+get_stack()); + error("edit.c SECURITY VIOLATION: "+offender+" "+get_stack()); + } +} + +string eventGenerateEditor(string file, string name, string shib){ + mixed tmp; + string ret = "File not found."; + validate(); + tmp = WEB_SESSIONS_D->eventReadFile(file, name, shib); + if(tmp){ + ret = read_file(DIR_WWW_GATEWAYS+"/edit_script.js")+"
\n"; + ret += "Editing "+file+""; + ret += "

"; + ret += ""; + ret += "

"; + ret += "Write to a different file: GetCookie(); + string current_page = ob->GetReferer(); + string ret = ""; + + if(ENABLE_CREWEB){ + validate(); + + ret += eventGenerateEditor(args, cookie["name"], cookie["shib"]); + } + else { + ret += "CreWeb is disabled. To enable it: mudconfig creweb enable

"; + } + ret += "Home
"; + ret += (ENABLE_CREWEB ? "Back": "
"); + ret += "Dead Souls Home
"; + + return ret; +} diff --git a/lib/www/cgi/edit_script.js b/lib/www/cgi/edit_script.js new file mode 100644 index 0000000..d5c0c58 --- /dev/null +++ b/lib/www/cgi/edit_script.js @@ -0,0 +1,54 @@ + + + diff --git a/lib/www/cgi/finger.c b/lib/www/cgi/finger.c new file mode 100644 index 0000000..909294c --- /dev/null +++ b/lib/www/cgi/finger.c @@ -0,0 +1,31 @@ +#include + +varargs string gateway(mixed who, int strip_html){ + string ret = ""; + string *ret_array; + + if(!who || !stringp(who)) who = "123456789101112"; + + if(!strsrch(who,"user=")) who = lower_case(replace_string(who,"user=","",1)); + + if(!user_exists(who)){ + ret = "No such user."; + } + + else { + ret_array = FINGER_D->GetRemoteFinger(who); + ret += "Name: "+ret_array[0]+"
"; + ret += "Title: "+replace_string(ret_array[1],"$N",ret_array[0])+"
"; + ret += (find_player(who) ? "On since: " : "Last on: ")+ ret_array[4]+"
"; + ret += "Level: "+ret_array[7]+"
"; + ret += (ret_array[8] ? ret_array[8]+"
" : ""); + } + + ret += "

"; + ret += "Finger a user: "; + ret += "

"; + ret += "Home

"; + ret += "Dead Souls Home"; + + return ret; +} diff --git a/lib/www/cgi/index.html b/lib/www/cgi/index.html new file mode 100644 index 0000000..dec598a --- /dev/null +++ b/lib/www/cgi/index.html @@ -0,0 +1,3 @@ + +O hai! + diff --git a/lib/www/cgi/login.c b/lib/www/cgi/login.c new file mode 100644 index 0000000..fc4c7cf --- /dev/null +++ b/lib/www/cgi/login.c @@ -0,0 +1,117 @@ +#include + +mapping Tries = ([]); + +mapping Specials = ([ + "%21" : "\!", + "%40" : "\@", + "%23" : "\#", + "%24" : "\$", + "%25" : "\%", + "%5E" : "\^", + "%26" : "\&", + "%28" : "\(", + "%29" : "\)", + "%2B" : "\+", + "%60" : "\`", + "%7E" : "\~", + "%3D" : "\=", + "%7B" : "\{", + "%7D" : "\}", + "%7C" : "\|", + "%3A" : "\:", + "%22" : "\"", + "%3C" : "\<", + "%3E" : "\>", + "%3F" : "\?", + "%5B" : "\[", + "%5D" : "\]", + "%5C" : "\\", + "%3B" : "\;", + "%27" : "\'", + "%2C" : "\,", + "%2F" : "\/", + ]); + +varargs string gateway(mixed args){ + string pass_hash, who, password, ip; + string ret = ""; + int max_tries = 3; + int no_user = 0; + + if(ENABLE_CREWEB){ + + ip = previous_object()->GetIp(); + + if(!args || !stringp(args)) args = "123456789101112"; + if(sscanf(args,"%s&%s",who, password) != 2){ + ret = "
"; + } + + else { + who = lower_case(who); + + if(!strsrch(who,"username=")){ + who = replace_string(who,"username=","",1); + } + + if(!strsrch(password,"password=")){ + password = replace_string(password,"password=","",1); + if(grepp(password, "%")){ + foreach(string key, string val in Specials){ + password = replace_string(password, key, val); + } + } + } + + if(!ret && !user_exists(who)){ + no_user = 1; + } + + else { + if(!Tries) Tries = ([]); + if(!Tries[ip]) Tries[ip] = 0; + if(no_user){ + pass_hash = alpha_crypt(32); + } + else { + pass_hash = PLAYERS_D->GetPlayerData(who,"Password"); + } + if(pass_hash != crypt(password, pass_hash) || + PLAYERS_D->GetPaused(who)){ + Tries[ip]++; + ret = "Fail! Tries left: "+(max_tries - Tries[ip])+"
"; + if(Tries[ip] >= max_tries){ + previous_object()->eventBlockIp(); + Tries[ip] = 0; + } + } + else { + string shibboleth = alpha_crypt(32); + string packet=who+"."+shibboleth; + WEB_SESSIONS_D->StartSession(ip,who,shibboleth); + ret = "Login successful
"; + Tries[ip] = 0; + ret += ""; + ret += ""; + return ret; + } + } + } + + ret += "Log in to CreWeb using your mud username and mud password.

"; + ret += "
"; + ret += "username:
"; + ret += "password: "; + ret += "

"; + ret += "

"; + ret += "
"; + } + else { + ret += "CreWeb is disabled. To enable it: mudconfig creweb enable

"; + } + ret += "

Home

"; + ret += "Dead Souls Home"; + + return ret; +} diff --git a/lib/www/cgi/logout.c b/lib/www/cgi/logout.c new file mode 100644 index 0000000..00b4bef --- /dev/null +++ b/lib/www/cgi/logout.c @@ -0,0 +1,24 @@ +#include + +varargs string gateway(mixed args){ + object ob = previous_object(); + mixed cookie = ob->GetCookie(); + string ret = ""; + + if(!ENABLE_CREWEB){ + ret += "CreWeb is disabled."; + ret += ""; + return ret; + } + + if(!cookie || !cookie["shib"] || !cookie["name"]){ + ret += "Not logged in."; + ret += ""; + return ret; + } + + WEB_SESSIONS_D->EndSession(cookie["name"]); + ret += "Logging out..."; + ret += ""; + return ret; +} diff --git a/lib/www/cgi/new.c b/lib/www/cgi/new.c new file mode 100644 index 0000000..0e43ee2 --- /dev/null +++ b/lib/www/cgi/new.c @@ -0,0 +1,63 @@ +#include +#include +#include + +inherit LIB_DAEMON; +mapping UploadsMap = ([]); + +void validate(){ + if(!master()->valid_apply(({ "SECURE", "ASSIST" })) && + strsrch(base_name(previous_object()), SOCKET_HTTP)){ + string offender = identify(previous_object(-1)); + debug("edit.c SECURITY VIOLATION: "+offender+" ",get_stack(),"red"); + log_file("security", "\n"+timestamp()+" edit.c breach: "+offender+" "+get_stack()); + error("edit.c SECURITY VIOLATION: "+offender+" "+get_stack()); + } +} + +string gateway(string args) { + object ob = previous_object(); + mapping cookie = ob->GetCookie(); + string current_page = ob->GetReferer(); + string ret = ""; + string operand; + mixed tmp; + + sscanf(args,"%s=%s",args, operand); + + if(ENABLE_CREWEB){ + validate(); + + operand = web_translate(operand); + + if(!operand || strsrch(operand,REALMS_DIRS)) operand = REALMS_DIRS + "/" + cookie["name"]; + if(last(operand,1) == "/") operand = truncate(operand,1); + + tmp = WEB_SESSIONS_D->eventWebCreate(operand, args, cookie["name"], cookie["shib"]); + + if(intp(tmp)){ + ret += "Success!
"; + ret += ""; + } + + else { + //ret += "
args: "+args+"
"; + //ret += "referer: "+current_page+"
"; + //ret += "cookie: "+identify(cookie)+"
"; + //ret += ""; + ret += tmp + "
"; + ret += "Home
"; + ret += "Back"; + ret += "Dead Souls Home
"; + } + } + + else { + ret += "CreWeb is disabled. To enable it: mudconfig creweb enable

"; + ret += "Home
"; + ret += "Dead Souls Home
"; + } + + ret += ""; + return ret; +} diff --git a/lib/www/cgi/save.c b/lib/www/cgi/save.c new file mode 100644 index 0000000..8f631fb --- /dev/null +++ b/lib/www/cgi/save.c @@ -0,0 +1,70 @@ +#include +#include +#include + +inherit LIB_DAEMON; +inherit LIB_CGI; +mapping UploadsMap = ([]); + +void validate(){ + if(!master()->valid_apply(({ "SECURE", "ASSIST" })) && + strsrch(base_name(previous_object()), SOCKET_HTTP)){ + string offender = identify(previous_object(-1)); + debug("save.c SECURITY VIOLATION: "+offender+" ",get_stack(),"red"); + log_file("security", "\n"+timestamp()+" save.c breach: "+offender+" "+get_stack()); + error("save.c SECURITY VIOLATION: "+offender+" "+get_stack()); + } +} + +string gateway(string args) { + object ob = previous_object(); + mapping cookie = ob->GetCookie(); + string current_page = ob->GetReferer(); + string boundary = "--"+ ob->GetBoundary(); + string file, junk,outfile; + string *tmp_arr; + string ret = ""; + mapping Result = ([]); + mapping ParsedPost = ([]); + + if(ENABLE_CREWEB){ + + ParsedPost = ParsePost(args); + + validate(); + + sscanf(current_page,"%s?%s",junk, file); + + if(ParsedPost["copy"] && ParsedPost["copy"] != path_prefix(file)+"/") outfile = ParsedPost["copy"]; + else outfile = file; + + Result = WEB_SESSIONS_D->eventSaveFile(outfile, ParsedPost["EditFile"], cookie["name"], cookie["shib"]); + + if(Result["error"]){ + ret += "
ERROR LOADING FILE!

"; + ret += replace_string(Result["report"],"\n","
")+"

"; + ret += "Home
"; + ret += "Back

"; + ret += "Dead Souls Home
"; + } + + else if(!Result["write"]){ + ret += "Could not write to file!

"; + ret += "Home
"; + ret += "Back"; + } + + else { + ret += "Success!
"; + ret += ""; + } + } + + else { + ret += "CreWeb is disabled. To enable it: mudconfig creweb enable

"; + ret += "Home
"; + ret += "Dead Souls Home
"; + } + + return ret; +} diff --git a/lib/www/cgi/showlog.c b/lib/www/cgi/showlog.c new file mode 100644 index 0000000..38978a0 --- /dev/null +++ b/lib/www/cgi/showlog.c @@ -0,0 +1,108 @@ +#include +#include +#include +#include + +inherit LIB_DAEMON; +inherit LIB_CGI; +string gfile; + +void validate(){ + if(!master()->valid_apply(({ "SECURE", "ASSIST" })) && + strsrch(base_name(previous_object()), SOCKET_HTTP)){ + string offender = identify(previous_object(-1)); + debug("showlog.c SECURITY VIOLATION: "+offender+" ",get_stack(),"red"); + log_file("security", "\n"+timestamp()+" showlog.c breach: "+offender+" "+get_stack()); + error("showlog.c SECURITY VIOLATION: "+offender+" "+get_stack()); + } +} + +string *eventLinkify(string *arg){ + string junk2; + int i; + string *ret = ({}); + if(!sizeof(arg)) return ret; + if(!grepp(implode(arg,"\n"),"ttp://")) return arg; + foreach(string str in arg){ + if(grepp(lower_case(str),"ttp://")){ + string junk1, url; + i = sscanf(str,"%sttp://%s %s",junk1,url,junk2); + if(i != 3) i = sscanf(str,"%sttp://%s)%s",junk1,url,junk2); + else if(i != 3) i = sscanf(str,"%sttp://%s)",junk1,url); + if(i < 3) i = sscanf(str,"%sttp://%s",junk1,url); + + if(junk1){ + str = replace_string(str,url,"1010011101001110100111010011",1); + ret += ({ replace_string(str,"1010011101001110100111010011", + ""+url+"",1) }); + } + else ret += ({ str }); + } + else ret += ({ str }); + } + return ret; +} + +string gateway(mixed args) { + string line_str, log_contents, log_ret; + string *log_arr = ({}); + int i, lines; + object ob = previous_object(); + string current_page = ob->GetReferer(); + mapping cookie = ob->GetCookie(); + string name = cookie["name"]; + string shib = cookie["shib"]; + string ret = ""; + + if(ENABLE_CREWEB){ + string *logfiles = ({}); + validate(); + + if(!name || !shib || !WEB_SESSIONS_D->authenticate(name, shib)){ + ret += "Bad session.
"; + ret += ""; + return ret; + } + + i = sscanf(args,"%s+%s", gfile, line_str); + if(i != 2 || !(lines = atoi(line_str)) || + !(log_contents = read_file(DIR_CHANNEL_LOGS +"/"+ gfile))){ + ret += "Bad request.
"; + ret += "Home
"; + ret += "Dead Souls Home
"; + return ret; + } + if(sizeof(explode(log_contents,"\n")) < lines){ + mapping Archives = ([]); + string *archive_array = get_dir(DIR_CHANNEL_LOGS +"/archive/"); + archive_array = filter(archive_array, (: !strsrch($1,gfile) :) ); + + foreach(string element in archive_array){ + string junk1; + if(sscanf(element,"%s%*d.%*d.%*d-%*d.%*d", junk1) != 6) + continue; + if(truncate(junk1,1) != gfile) continue; + Archives[stat(DIR_CHANNEL_LOGS+"/archive/"+element)[1]] = element; + } + if(sizeof(Archives)){ + mixed *order = sort_array(keys(Archives),-1); + log_contents = (read_file(DIR_CHANNEL_LOGS+"/archive/"+ + Archives[order[0]]) || "") + log_contents; + } + } + + log_arr = eventLinkify(explode(log_contents,"\n")["); + ret += log_ret; + ret += "
"; + } + + else { + ret += "CreWeb is disabled. To enable it: mudconfig creweb enable

"; + } + ret += "Home
"; + ret += "Dead Souls Home
"; + + return ret; +} + diff --git a/lib/www/cgi/upload.c b/lib/www/cgi/upload.c new file mode 100644 index 0000000..e38df75 --- /dev/null +++ b/lib/www/cgi/upload.c @@ -0,0 +1,66 @@ +#include +#include +#include + +inherit LIB_DAEMON; +inherit LIB_CGI; +mapping UploadsMap = ([]); + +void validate(){ + if(!master()->valid_apply(({ "SECURE", "ASSIST" })) && + strsrch(base_name(previous_object()), SOCKET_HTTP)){ + string offender = identify(previous_object(-1)); + debug("upload.c SECURITY VIOLATION: "+offender+" ",get_stack(),"red"); + log_file("security", "\n"+timestamp()+" upload.c breach: "+offender+" "+get_stack()); + error("upload.c SECURITY VIOLATION: "+offender+" "+get_stack()); + } +} + +string gateway(mixed args) { + string err, full_name, path, junk1, junk2; + int i; + object ob = previous_object(); + string current_page = ob->GetReferer(); + mapping cookie = ob->GetCookie(); + string name = cookie["name"]; + string shib = cookie["shib"]; + mapping ProcessedPost = ParsePost(args); + string posted_file = ProcessedPost["upfile"]; + string filename = ProcessedPost["filename"]; + string ret = ""; + + if(ENABLE_CREWEB){ + validate(); + + i = sscanf(current_page,"http://%s/%s",junk1, path); + if(i != 2) i = sscanf(current_page,"/%s",path); + if(i != 1) i = sscanf(current_page,"./%s",path); + + path = "/"+path; + if(last(path,1) != "/") path += "/"; + full_name = path+filename; + + if(!filename || !sizeof(filename)){ + ret += "No file selected.
"; + ret += ""; + return ret; + } + + if(stringp(err = WEB_SESSIONS_D->eventWriteFile(full_name, posted_file, name, shib))){ + ret += err+"
"; + ret += "Return
"; + return ret; + } + + ret += "Success!
"; + ret += ""; + } + + else { + ret += "CreWeb is disabled. To enable it: mudconfig creweb enable

"; + ret += "Home
"; + ret += "Dead Souls Home
"; + } + + return ret; +} diff --git a/lib/www/cgi/who.c b/lib/www/cgi/who.c new file mode 100644 index 0000000..c909639 --- /dev/null +++ b/lib/www/cgi/who.c @@ -0,0 +1,66 @@ +/* Hiccups@Frontiers, 12/16/96 */ +/* Fixes by Haderach, 05 SEP 2005 */ +/* RWHO check by Shadyman, 2006-Sep-12 */ + +#include +#include + +inherit LIB_DAEMON; + +#define SEP repeat_string("*=",37)+"*
"; + +varargs string gateway(int strip_html) { + int p; + string x, tmp="", ret=""; + object *obs; + + p = 0; + obs=users(); + + for (int i=0; iGetKeyName() != last_string_element(base_name(obs[i]),"/")) continue; + if(!obs[i]->GetInvis()) { + if(archp(obs[i])) tmp+="[ARCH]"; + else if(creatorp(obs[i]) ) tmp+="[WIZ]"; + else if(avatarp(obs[i]) ) tmp+="[AVATAR]"; + else if(high_mortalp(obs[i]) ) tmp+="[HIGH MORTAL]"; + else tmp+=sprintf("[%d]", obs[i]->GetLevel() ); + if(elderp(obs[i])) tmp+="[ELDER]"; + if(ambassadorp(obs[i])) tmp+="[AMBASSADOR]"; + 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+=" (sleeping) "; + else if (obs[i]->GetProperty("afk")) tmp+=" (afk)"; + else if (query_idle(obs[i])>240 && obs[i]->GetInCombat()!=1) tmp+=" (idle)"; + else if (in_edit(obs[i])) tmp+=" (edit)"; + else if(obs[i]->GetInCombat()) tmp+=" (combat)"; + tmp+="
"; + p++; + } + } + if(!strip_html){ + ret+="
"+mud_name()+"

"; + } + else { + ret+=mud_name()+"\n"; + } + 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.
"; + ret+=center(x); + if(strip_html){ + ret = replace_string(ret,"
","\n"); + } + return ret; +} diff --git a/lib/www/client/client.html b/lib/www/client/client.html new file mode 100644 index 0000000..01a3eda --- /dev/null +++ b/lib/www/client/client.html @@ -0,0 +1,29 @@ + + + + + + +FMud + + + + + + + + + + + + + + + + diff --git a/lib/www/debugging.html b/lib/www/debugging.html new file mode 100644 index 0000000..c0fb3b5 --- /dev/null +++ b/lib/www/debugging.html @@ -0,0 +1,405 @@ + + + + + Dead Souls debugging + + + + +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:
+
+1 elog
+2 +dbxframe and dbxwhere
+3 +tell_player() and debug()
+4 tail
+5 bk +and restore
+
+
+elog
+
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:

+
> update +sample_room
+
---
*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:


+
> elog
+
/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
individual steps are called frames.

> dbxwhere
*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 +enumerating the steps, dbxwhere
+lets us use dbxframe to get +tighter detail on a given error frame:
+
+> dbxframe +4
+------
+    +/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 encounter 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.
+
+
+
tell_player(), +debug()
+
+    Sometimes it's hard to fix code if you don't know +what it's doing. In
+the above example, you might want to know what the variable "args" is, +if
+your code is behaving unexpectedly. You could find out by adding a line +like:
+
+tell_player("cratylus", "args is: +"+identify(args));
+
+or:
+
+
tell_player("cratylus", +"%^BLUE%^args +is: "+identify(args)+"%^RESET%^");

+
+    You could also use:
+
+debug("args is: ", args);
+
+or:
+
+
debug("args is: ", args, +"blue");

+
+    ...which has the advantage of being shorter to type +and you'll get
+the message more promptly. To be able to receive debug messages,
+you need to enable your debugging mode by typing:
+
+debug on
+
+    debug() is available in 2.0r20 and above.
+

+
tail
+
+    +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:
+
+tail +/log/catch
+tail /log/runtime
+
tail +/log/player_errors
+
+
+
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:
+
+bk +sample_room
+
+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:
+
+ed +sample_npc.c
+bk +sample_npc
+ed +sample_npc.c
+update +sample_npc.c
+<error +occurs here>
+restore +sample_npc
+
+    +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:
+
+restore +sample_npc 1
+
+    +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.
+
+
+
Dead Souls Homepage
+
+
+
+ + diff --git a/lib/www/demo.html b/lib/www/demo.html new file mode 100644 index 0000000..def7695 --- /dev/null +++ b/lib/www/demo.html @@ -0,0 +1,79 @@ + + + + + + + + + Dead Souls Demo Connection + + +
  +The Dead Souls Demo Connector Page
+
+

+
+ + + + + + +
+
+
+ You will be connected to Dead Souls Demo in a few seconds...
+ + +
+ Your Browser seems to have no Java +support. Please get a new browser or enable Java to see this applet! +
+
+
+
+Connecting to the Demo MUD will give you the option to be automatically +promoted to Creator so you can see for yourself how Dead Souls works.
+
+If the applet doesn't work, or you don't like it, you can just telnet +to: dead-souls.net +8000
+
+
Common +player commands: look, l,inventory, i, help, score, stat, who, +tell (example: "tell mike where are you?"), say  (example: +"' hi", "say nice to meet you!")
+
+Common object commands: look +at, look in, examine, exa, get, drop, open, close,  read,  put
+
+Common Movement commands: +enter, n, s, +e, w, u, d, go north, go south, go east, go west, go up, go down, out, +go out, climb 
+
+Common Vendor commands: money, +appraise, price, show, buy, sell + 
+
+Common Creator commands: more, +ls, cd, about, clone, dest, goto
+
+ + + diff --git a/lib/www/downloads.html b/lib/www/downloads.html new file mode 100644 index 0000000..f39e408 --- /dev/null +++ b/lib/www/downloads.html @@ -0,0 +1,524 @@ + + + + + + + + + LPMuds.net - Downloads + + + + + + + + + + +
+ + + + + + + +
LPMuds.net +
+ + + + + + +
A +resource site for LPC, LPMuds, and related stuffs.
+
+ + + + + + + + + + + + + + + + +
  Index Forum Site +FAQ LPMud +FAQ Intermud +   Downloads   Links +  
+

+
+
Downloads: MudOS +libraries
+
+ + + + + + +
THIS SECTION IS INCOMPLETE SO DONT GIMME +NO GUFF
+

+This is  a summary of currently-availableMudOS libs whose installation +difficulty level ranges from "easy-ish" to "moderate". The point of +this +page is to provide a convenient reference to those interested in trying +them out. These downloads are libs bundled with the driver (with +permission of the authors where required) for your convenience.
+
+Non-MudOS libs have a section below.
+
+ Note +about +licensing: Each of these libs comes with its own licensing +information. Do not +assume they are public domain, or GPL, or whatever.
+
+ Note +about +intermud: Most of these libs are designed or preconfigured to +connect to the intermud +router. Please read the router info and rules if you plan +on making use of that communication medium. Also, note this FAQ entry +on intermud security.
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Dead +Souls +2
+Comments: Easy to use, polished, and popular.
+Advantages: Works very well right out of the box, thoroughly +documented. UNIX and Windows version in the same download.
+Disadvantages: Uses the complex verb system. Function names are +different from older libs.
+Download: http://lpmuds.net/files/deadsouls/ds2.10.zip
+(Bleeding edge "alpha" development versions are available, but they are +only for the adventurous. You can look here for them.)
TMI-2
+Comments: Rarely used, except by old-timers. Newly revamped and +includes experimental Windows executable.
+Advantages: It's a solid lib, built by competent coders dedicated to +excellence.
+Disadvantages: It's showing its age. Lacks an advanced parser.
+Download: http://lpmuds.net/files/tmi2_fluffos_v3.zip
+(Note: this lib and included driver source have been modified to +compile and run on modern unix)
Skylib
+Comments: Seems nice enough. v3 is Skylib 1.8 on FluffOS. Windows +executable also included.
+Advantages: Should feel familiar to Discworld types.
+Disadvantages:  see above
+Download/Homepage: http://lpmuds.net/files/skylib_fluffos_v3.zip
+(Note: this lib and included driver source have been modified to +compile and run on modern unix)
Lima
+Comments: Easy to use, polished, and popular. Also work on Windows.
+Advantages: Works well when patched. Designed by experts +to be extremely advanced.
+Disadvantages: Not currently maintained. Not compatible with +add_actions. Perhaps too advanced for beginners.
+Download: http://lpmuds.net/files/lima_fluffos_v1.zip +
+
Merentha
+Comments: Based on the popular Nightmare 3 lib. Windows executable also +included.
+Advantages: Has the "Nightmare feel" and robustness without the +complications of verbs or weird lfun names.
+Disadvantages:  Limited intermud, and little available support.
+Download/Homepage: http://lpmuds.net/files/merentha_fluffos_v2.zip
+(Note: this lib and included driver source have been modified to +compile and run on modern unix)
Discworld
+Comments: Well liked, but rarely used. Newly updated with FluffOS 2.9 +and Windows driver.
+Advantages: The grotesquely popular Discworld MUD uses a +variation of this lib, so it must have something going for it.
+Disadvantages: Few adopters. Limited support.
+Download:  http://lpmuds.net/files/discworld/dw_fluffos_v3.zip
+(Note: this lib and included driver source have been modified to +compile and run on modern unix)
Final +Realms
+Comments: Interesting. Based on Discworld. Newly updated with FluffOS +2.9 and Windows driver.
+Advantages: Lots and lots and lots and lots of example. Also, lots of +examples.
+Disadvantages: Peculiar and idiosyncratic. Fixer-upper.
+Download:  http://lpmuds.net/files/final_realms_fluffos_v1.zip
+(Note: this lib and included driver source have been modified to +compile and run on modern unix)
Dead +Souls +I
+Comments: Dead Souls I is nearly identical to Nightmare IV except the +docs are missing.
+Advantages: Public domain, so lib licensing is no worry. Simpler than +DS2.
+Disadvantages: See "Dead Souls 2" above.  DS1 may contain some +bugs  that are fixed in DS2.
+Download: http://lpmuds.net/files/deadsouls/dsI.zip
+(Note: this lib and included driver source have been modified to +compile and run on modern unix)
LPUniversity +Mudlib
+Comments: Not ready for play. Newly updated with FluffOS. Windows +driver also included.
+Advantages: Provides a chance to build a lib from +the ground up without +having to deal much with the driver.
+Disadvantages: No longer developed. +Fixer-upper.
+Download/Homepage: http://lpmuds.net/files/lpuni_fluffos_v1.zip
+(Note: this lib and included driver source have been modified to +compile and run on modern unix)
+
Nightmare
+Comments: An influential early lib family. Newly revamped: Unix and +Windows +driver included together.
+Advantages: Heavily documented and widely known.
+Disadvantages: NM3 is woefully outdated. NM IV is less so, but still +long in the tooth.
+Nightmare 3 Download: http://lpmuds.net/files/nightmare3_fluffos_v2.zip
+Nightmare IV Download: http://lpmuds.net/files/nightmare4_fluffos_v1.zip
+(Note: this lib and included driver source have been modified to +compile and run on modern unix)
+
Lil
+Comments: This is a fixed up version of the MudOS "testsuite" lib with +MudOS docs added. Unix source and Windows executable included.
+Advantages: Clean as a whistle. You can log in and use a few commands, +but otherwise it's bare metal so you can code from the ground up.
+Disadvantages: This is about as bare bones as it gets without coding +100% from scratch. You really need to know what you're doing. No +intermud. For the seriously leet only!
+Download: http://lpmuds.net/files/lil_0.3.zip
+(Note: this lib and included driver source have been modified to +compile and run on modern unix)
+
Foundation
+Comments: This is a stripped-down version of Nightmare. Unix source and +Windows executable included.
+Advantages: No combat, or limbs, etc. This is good for people who like +NM or DS but feel it is too cluttered.
+Disadvantages: It's much more accessible than Lil, but it is not at all +for LPC beginners. Not even close. Experts +only!
+Foundation I Download: http://lpmuds.net/files/foundation/foundation1_fluffos_v1.zip
+Foundation II Download: http://lpmuds.net/files/foundation/foundation2_fluffos_v1.zip
+(Note: this +lib and included driver source have been modified to +compile and run on modern unix)
+
+
+
+
+
+
External +Downloads: Non-MudOS +libraries
+
+ + + + + + +
THIS SECTION IS ALSO INCOMPLETE SO DONT +GIMME +NO GUFF, STILL
+

+This is  a summary of currently-available libs for non-MudOS +drivers. Most of these downloads are hosted on external sites, and not +LPmuds.net, because I am not involved in their development, or their +easyfication, or anything about them at all. If you download them and +lose your mind trying to install them, your mental health does not +become my responsibility. If the link is dead or does not yield an +actual download, feel free to do the research required on your own, +without bothering me.
+
+
+ Bundled Libs
+ + + + + + + + + +
Phantasmal
+Comments: This is version 0.018 of Phantasmal bundled with DGD 1.2.110
+Advantages: Reputed to be the most complete publicly downloadable lib +for DGD.
+Disadvantages: No intermud.
+Download http://lpmuds.net/files/phantasmal_dgd_v1.tar.gz
+
Gurba
+Comments: Updated Gurba lib plus an intermud-enabled version of DGD.
+Advantages: Currently maintained by a competent coder.
+Disadvantages: Relatively small set of working examples and areas.
+Download http://wotf.org/downloads/gurba/ +(older versions here)
+
+
+
+
+ Unbundled Libs
+ + + + + + + + + + + + + + + + + + +
LDmud ( http://www.bearnip.com/lars/proj/ldmud.html +)
+
+OSB http://www.bearnip.com/ftp/mud/osb-lib-030218.tar.gz
+Heaven 7 (updated by Mordain) http://lpmuds.net/files/heaven7_4a2_pkg-004.tar.gz
+Tublib http://www.tubmud.de/ftp/distributions
+
+
DGD ( http://www.dworkin.nl/dgd/ )
+
+Melville ftp://ftp.dworkin.nl/pub/dgd/lib/Melville/melville_0.9.1.tar.gz
+Gurbalib http://gurba.sytes.net/~erlends/gurba.html
+
+
Shattered World +( http://www.shattered.org/ )
+
+SWlib http://sourceforge.net/projects/swlpc
+
+
CD ( http://www.genesismud.org/students/index +)
+
+CDlib http://www.genesismud.org/svn/mudlib/trunk
+
+
(The Original) +LPmud (aka 2.4.5 aka 3.x aka Amylaar)
+
+
LPmud http://mudbytes.net/index.php?a=files&cid=230
+
+
+
+
+
+
+
  +Other downloads
+
+
+ + + + + + + + + + + + +
+
Windows editors:

The #1 problem in Windows is that the default plaintext
editor, Notepad, produces text that is not 100% compatible with the
mud. Windows plaintext and UNIX plaintext differ, believe it
or not. If you use notepad for editing mudos.cfg, for example,
your mud is likely to just fail to boot. This is because it
can no longer read the "incorrectly" formatted file.

The other big problem with Notepad and Wordpad is that
they often add formatting and characters to text files that
make them very ugly and hard to read from inside the mud.

The solution is to use a text editor that can save in
UNIX text format. The following URLs point to editors that I
have been told will do a good job of this. I can't vouch for
them, as they are 3rd party apps and I've never tested them, but
I am assured they are very good for this.

Notepad++ http://notepad-plus.sourceforge.net/uk/site.htm

WinVi http://www.winvi.de/en/


Notepad2 http://www.flos-freeware.ch/notepad2.html
+
+
Windows clients:

I can't imagine using the default Windows telnet client for
long. It is so bereft of features as to be actually worse than the
crappiest UNIX (or even VMS!) clients from 1993...Windows telnet is
worse than the worst from fifteen years ago.

There are a ton of great Windows mud clients out there.
Anyway, that's what I hear. Back when I used windows, I used a free
version of Zmud, and sometimes a less preferred Gmud. Zmud is now
a non-free application, so you have to buy it to use it. However,
they do still allow free distribution of a crappy, super old
version of the client.


Gmud http://frontiers.wcsu.ctstateu.edu/gmud.exe


Old Zmud 3 from 1996 (not my prob if it's broken)
http://frontiers.wcsu.ctstateu.edu/zmud.zip

+
+
UNIX clients:

The client I use is gmoo 0.5.6. It has its drawbacks, but it
works ok, in general, and I'm used to it. An older version of it is
gMOO 0.4.8, and I've found it's a little easier to compile on some
newer UNIXes, for reasons beyond me.

Though I'd been reluctant to use it (fear of a CLI
client), the TinyFugue client, aka "tf", is a magnificent piece of
work that is worth becoming familiar with.

gmoo 0.5.6 http://frontiers.wcsu.ctstateu.edu/gmoo-0.5.6-11c.tgz
(Debian fixes applied, plus a bugfix for a prompt problem supplied by Haderach @ Frontiers )

gMOO 0.4.8 http://frontiers.wcsu.ctstateu.edu/gMOO-0.4.8.tar.gz

tf http://tinyfugue.sourceforge.net/
+
+
+
+
+
+
+
+ + + diff --git a/lib/www/ds-II-faq.html b/lib/www/ds-II-faq.html new file mode 100644 index 0000000..e52adb1 --- /dev/null +++ b/lib/www/ds-II-faq.html @@ -0,0 +1,74 @@ + + + + + Dead Souls II FAQ + + + + +
Dead Souls II FAQ

Written by Cratylus @ Dead Souls, updated July 2009

What is Dead Souls II?

How does it differ from Dead Souls 2?

Why are you releasing Dead Souls II into the public domain?

Why don't you release Dead Souls 2.x into PD?

Why did you remove the documentation?

Why would anyone want to run this crippleware?

Hey this file doesn't look like it's PD!

I would have let you release my stuff into PD. Why didn't you ask?

Ok, where do I get it?

What's the catch?


What is Dead Souls II?

Dead Souls IIr10 is a public domain version of Dead Souls. It contains
much of what was released as "Dead Souls 2.10", meaning it
is dramatically more featured and complete than the previous
major public domain version, which is Dead Souls 1.1.

It is critical to note that the driver source and
windows executables are most emphatically NOT public domain.
The contents of fluffos*/ and win32/ are copyrighted
material, and it does not belong to me, so I cannot release
the rights to that.

Only the stuff in lib/ in the Dead Souls II distribution
package is public domain.


How does it differ from Dead Souls 2?

The main differences are:
- Roman numerals are used in the name, to distinguish the versions.
- DS II does not contain documentation files in /doc.
- All of the library files (NOT the driver!) are public domain.
- Some files not written by me have been removed or disabled, like stargate stuff.


Why are you releasing Dead Souls II into the public domain?

I started the DS resurrection project for the fun of it. I'm not under the
delusion that this will make me money. I'm in it because I like lib coding,
and it was really fun to do.

DS 1.1 being in the public domain dramatically facilitated the project,
and it has always been my intention to make DS available to the public,
so they can enjoy it as much as I have.

Along the way I've run into all sorts of nasty people who appear to
take pleasure in nitpicking details about licensing and whatnot. I
really couldn't care less about such stuff. I just like to code. The
rest is just a game of "gotcha" that I can't be bothered to participate in.

So, in releasing my code into the public domain, I achieve the following:

1) I give back to the community a little piece of it in shape better than I found it.
2) I increase the likelihood that someone else will pick it up, make it their own, and also give back.
3) I get to not think about licensing, which is just a waste of my time.


Why don't you release Dead Souls 2.x into PD?

As long as 2.x has stuff that doesn't belong to me, it can't
be PD. Since there are docs for DS that will never be mine,
there will probably always be separate "proprietary" and
"public domain" versions.


Why did you remove the documentation?

Two main reasons. First, a lot of it isn't mine, so there's that.

Second, I feel differently about the release of prose. It's one thing
to free code...its use is unambiguous and somehow it just makes sense.

But to me, my prose represents more of an expression of my creativity
than code. It just feels different to me.

This doesn't mean you can't use it. You're welcome to use the
documentation from the non-PD version of Dead Souls. I'm just
not releasing it into the public domain.


Why would anyone want to run this crippleware?

Well, see, it's not crippleware. Sure, there are a few files I
removed because they're not mine, but in terms of code, DS IIr10 and
DS 2.10 are something like 99.99% the same.


Hey this file doesn't look like it's PD!

I've gone through the lib with a fine-toothed comb. Even if it
seems like someone is explicitly retaining rights in a file,
you can safely presume that this file was already PD by the time
I got it.

If you're certain, though, that I've missed something, please
let me know, and I'll address it right away.


I would have let you release my stuff into PD. Why didn't you ask?

The authors of the files I excluded might be surprised that
they weren't asked about including their material in DS II. With
the exception of the authors of a few files that would have been a
hassle to rewrite from scratch, I decided not to contact authors. I
simply didn't include other people's stuff.

The reason isn't that your stuff isn't "good enough".

It's that I wanted everyone to see that I'm putting my
money where my mouth is. Before asking anyone to give up
their IP for free, I wanted to demonstrate that I'm not
asking you to do anything I wouldn't do myself.


Ok, where do I get it?

Download the new public domain version of Dead Souls here:

http://lpmuds.net/files/deadsouls/dsIIr10.zip

+What's the +catch?
+
+You can expect to find a few bugs here and there in Dead Souls II
+that are fixed in more recent versions of the 2.x family. This
+is because DS II is unsupporeted and therefore static.
+
+If you run into trouble running DS II, you can certainly
+ask for help, but if the problem is resolved in later versions of DS 2,
+I'm not going to develop a fix for DS II. If you're using the
+public domain version, I assume it's because you're a DIY kind
+of person. So...DIY.
+
+The only advantage to using DS II over DS 2 is that you know
+you can use the lib in nonstandard ways, like fork lib development,
+sell it to the Chinese, whatever, and I simply cannot prevent
+you from it.
+
+If all you're doing is running a mud, though, DS II really
+doesn't do anything for you. I'd suggest installing one
+of the current, +proprietary versions of DS 2.
+
+But hey, at least now you have a choice one way or another,
+and choice is good.
+
+
+The end.
+
+Dead Souls Homepage
+
+
+ + diff --git a/lib/www/ds-admin-faq.html b/lib/www/ds-admin-faq.html new file mode 100644 index 0000000..c47cb6d --- /dev/null +++ b/lib/www/ds-admin-faq.html @@ -0,0 +1,5450 @@ + + + + + Dead Souls Admin FAQ + + + + +Dead Souls Admin FAQ
+
+Written by Cratylus @ Dead Souls, October 2005
+Updated May 2009
+
+
Note: commands are displayed in boldface, like this: ls -a
+
+What's this FAQ about?

+
+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.
+
+
+0 How do I start?
+
+1 Is there a MUD somewhere running Dead Souls I can log +into?
+
+2 I like Dead Souls and I want to use it, but I don't want +to run a mud.
+
+3 I want to invite my friends to help me code. How do I +promote
+them to creator status?
+

+4 What about intermud? How do I talk on that?
+
+5 I talk on intermud but nobody replies. What's up with +that?
+
+6 How did you know my mud started up?
+
+7 I heard there's an I3 router included in Dead Souls.
+

+8 What's this about a manual on Frontiers?
+
+9 How do I add limbs to a race?
+
+10 How do I add a race?
+
+11 How do I make my friend an admin?
+

+12 I don't like how the who command output looks! You +should change it.
+

+13 Can you please make the FAQ easier to read? It's too +long and complicated.
+

+14 Most of the file headers have only Descartes's name on +them.
+Did you really develop this lib or did he?
+

+15 How can I change the colors of the channel messages?
+

+16 How do I know what other muds use Dead Souls?
+
+17 I was hanging out in the Arch room and the loudspeaker +went off. WTF?
+
+18 I want to test the intermud channel but I don't want +to spam the ds line.
+
+19 What's this "Network room"?
+
+20 The web server and FTP server don't work
+
+21 I tried to log in to the FTP server but I can't!
+
+22 I can't do anything with FTP. It just hangs there.
+

+23 The web server gives me a 404 but I know the directory +is there.
+
+24 I'm using an external FTP server, but the files I +transfer
+become read only!
+
+25 I moved a command from one directory to another. How +do I
+get the new location recognized?
+

+26 The mudtime is all wrong!
+
+27 The time of day is all wrong!
+
+28 What happened to the roommaker and thingmaker?
+

+29 I keep getting 'Connection to address server +(localhost 9999) refused.'
+

+30 Can I charge players a fee for playing on my mud?
+
+31 Can people donate money to me for the mud?
+
+32 I found a bug. For real. Can you please fix it?
+

+33 Where would I edit to change how long someone can be +idle
+before they get disconnected?
+

+34 How do I permit all users who log in to become
+creators automatically?
+

+35 How do I limit the use of intermud channels?
+
+36 How do I get off intermud completely?
+
+37 How do I change the start room for the mud?
+
+38 I don't like having newbies get special treatment.
+
+39 I don't want players to be able to pick non-human +races.
+

+40 I want everyone to speak the same language.
+

+41 I made a change to /lib/player.c and updated it, but +I'm not
+seeing a difference in my character.
+

+42 How do I change the items new players receive?
+

+43 Hey, there's no <foo> class! What's up with that?
+

+44 Where can I get a Dead Souls mud hosted?
+

+45 Your LIB_MXLPLX system is all screwy. I changed it and +it
+works. Wanna see?
+

+46 How are files organized in Dead Souls?
+

+47 What are sefuns and efuns?
+
+48 Whew! Ok now I know where stuff is. What's next?
+

+49 Oh, man, you're kidding! Those are, like, books! Can't +I
+just start making stuff?
+

+50 Everything is su-u-u-u-p-e-e-r-r-r s-s-l-o-o-o-o-w-w-w
+

+51 Dude! One of my creators just kicked me off my own mud!
+

+52 Is Dead Souls secure?
+
+53 I sent you my code a week ago. Is it in or out?
+

+54 Did you finish the bfd() sefun modification I asked +you for last night?
+

+55 QUEEG_D is a horrendous mess. It's inefficient and +frankly offensive.
+

+56 You implemented my code but didn't give me credit.
+
+57 Intermud mail doesn't work
+
+58 The admintool menus let you pick options that aren't +visible
+
+59 What does locking the mud do, exactly?
+

+60 The race help output is inadequate for role-playing. +How do I change it?
+

+61 I need to know what features to expect in the next +release so
+I don't waste time duplicating effort
+

+62 You need a development roadmap and task tracking
+

+63 How do I update a sefun without rebooting the mud?
+

+64 My new sefun updates but I can't seem to use it.
+

+65 What's the point of the apostrophe-stripping for args +in lib/command.c?
+

+66 How does one achieve 'high mortal' or 'ambassador' +positions?
+

+67 I would like XYZ and PDQ to happen every time the mud +boots
+

+68 I can't login! I keep getting: "It seems some work is +being done
+right now, try later."
+

+69 I had a really great idea that revolutionizes ds and +you refuse
+to include it. I am forking ds development and making my +dream come true.
+

+70 What do the version numbers mean?
+
+71 The Dead Souls router is down.
+
+72 I'm going to totally revamp <insert highly complex +system here>.
+Will that be difficult?

+
+73 I've hired an area coder to make a new domain. I want +her
+to be able to use QCS in /domains/MistyDragonShireMysts.

+
+74 How does player voting work?
+
+75 What are "estates"?
+
+
76 What are "events"?
+
+77 Where does user monitor data go?
+
+78 How would you set a race to be selectable by new +players?
+
+79 Where is emote data kept?
+
+80 What are .h and .o files? Where are they kept?
+

+81 But my friend forgot his password! I *have* to edit +his playerfile!
+
+82 How do I change my mud's name?
+
+83 Help! I locked myself out!
+
+84 What are the privileges associated with the groups in +groups.cfg?

+
+85 Why does the documentation refer to LIB_ARMOUR and +armour_types.h?
+
+86 Where are read/write restrictions kept?
+
+87 I need to test day/night descriptions, but I can't +wait around all day.
+
+88 How can I change the default prompt? Can I make it +dynamic?
+
+89 What is "unguarded"?
+
+90 Is intermud communication secure?
+
+91 What are some do's and don'ts?
+
+
92 Is DS2 in any way suited to create a non-english +mud from/with it?
+
+93 I keep losing my intermud connection, and sometimes I'm half +connected

+
+94 I +heard I can run my old TMI-2/Nightmare 3/Skylib/Lima code on Dead +Souls. Is that true?
+
+95 +Why is the version of Dead Souls 2 on Sourceforge different from the +one on dead-souls.net?
+
+96 Good heavens! All I wanted to do was change combat, +and it is so complicated!
+
+97 Editing in Windows is fine and call_out()'s are great. +Your advice sucks!
+
+98 I keep hearing that Dead Souls can do this or that, +but I'm trying and can't.
+
+
99 You appear to have a FAQ for everything!
+
+
100 If I XYZ, will that work?
+
+
102 Hey you skipped question 101!
+
+103
You +are not taking my bug report very seriously.
+
+104
Dude. Just answer +my question. It's just one question, ffs.
+
+105 Is it possible to upgrade to alpha without killing +everything I've done?
+
+106 How do I start an area?
+
+107 I don't want to use a cookie-cutter codebase
+

+108 How do I make my new area the default domain where +new people to arrive?
+
+109 I heard passive mode on the FTP server works now.
+
+110 I boot the mud but nothing happens...the startup +headers
+come up but nothing preloads and I get no error messages. What's
+going on?

+
+111 How do I add a default alias?
+
+
112 How do reset() and clean_up() work?
+

+113 When do reset() and clean_up() happen?
+
+
114 I want a 100% PK mud. Setting rooms PK one by one is +not acceptable.
+
+
115 How do I make +a new skill?
+
+116 +Why +was Descartes so lame?
+
+117 +The +mud is locked whats the command to add someone to the allow list?
+

+
118 Shouldn't you +change all the documentation to reflect the move to FluffOS?
+
+
119 How do I change my timezone?
+
+
120 So I herd u liek mudkip
+

+
121 Where is all +the player information stored?
+
+122 +The +addrace command complains that the race already exists.
+
+123 +I +am confused +about the player/creator distinction.
+
+124 +How +do I prevent people from using channels?
+
+125 How do i disable the rss bot, or other channels?
+
+126 I made a verb but it doesn't work.
+
+127 Does Dead Souls support databases like MYSQL?

+
+128 How do I make my new currency work?
+

+129 My friends can't connect to my mud, but I can!
+
+130 My efun override is not working
+
+131 How do I remove the QCS?
+
+132 I heard you can edit stuff from the interwebs?
+
+133 I want to let people build but I don't want them to +be full creators
+
+134 How do I enable IMC2? What is it?
+
+135 Combat is too slow!
+
+
136 I want players to select their class when they create +their characters
+
+
137 +I am strongly opposed to the use of intermud
+

+138 +I hate one of the sample domains and I want it GONE
+
+139 How do I make help files?
+
+140 How many players will DS handle simultaneously?
+

+141 I heard that Dead Souls for Windows has limitations
+

+142 What are the CPU/RAM/diskspace requirements for Dead +Souls?
+
+143 Who's awesome?

+
+144 I heard you added vi to DS!
+
+145 What is MSSP?

+
+
+How +do +I start?
+
+The first thing to do is follow the installation +FAQ
+to get Dead Souls installed. Then log in, and start reading
+the administrator's guide, by typing these commands:
+
+read index in guide
+
+read chapter 1 in guide
+
+read chapter 2 in guide
+
+etc.
+
+You should also become familiar with the Creator FAQ, in
+particular the +section on getting questions answered.
+
+
+
Is there a MUD +somewhere running Dead Souls I can log into?
+
+As a convenience to the curious, I have set up a "demo" mud
+at dead-souls.net, port 8000. 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 8000 , or use +the java +applet
+at this page: http://dead-souls.net/javaclient/demo.html
+
+
When +you +log in, you'll automatically be made a "creator"
+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 granted those privileges.
+
+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 by default.
+
+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
+

+

+
I like Dead +Souls and I want to use it, but I don't want to run a mud.
+
+Being a mud admin is very different from being just a coder
+or builder, and many people just don't feel like dealing with
+the hassle of running a mud.
+There are a few Dead Souls muds out there that could
+use help from you. Telnet to the Dead Souls development mud
+and type: mudlist -m Dead to +see a list of Dead Souls muds
+that might be hiring.
+You can also just code on the Dead Souls development
+mud. You're welcome to create as you please, and if your
+building gets to the point where you'd like it included in
+the lib, let me know and I'll inspect it for approval.
+
+Please note that starting January 2007, for any of your code to become
+part of the official Dead Souls distribution, you must officially
+disclaim copyright to it, placing it into public domain.
+
+
+
I want to +invite my friends to help me code. How do I
+promote +them to creator status?
+
+encre dude
+
+
To demote them:
+
+decre dude
+
+

+
What about +intermud? How do I talk on that?
+
+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 hello
+and other Dead Souls muds on the i3 network will see
+your message like this:
+
+You@YourMud <ds> hello
+
+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 may meet a hostile reception on
+intercre.
+
+Conversely, dchat is mostly chat.
+
+Note: If you decide to add the intergossip +channel to
+yourself or your creators, be +aware that conversations
+there tend often not to be +PG-rated. You can
+also find yourself baited into a +nasty flaming if
+you're not careful. I protect +newbies as I can, but
+it helps if you can prevent +yourself from being baited.
+Really I'd suggest you avoid the +intergossip channel
+entirely.
+
+The ds channel is for Dead Souls-related conversation. Sometimes
+the topic drifts, but "random chat" should be avoided
+there. Use dchat for off-topic chat.

+
+For information on IMC2, a different intermud network,
+see: http://dead-souls.net/ds-admin-faq.html#134

+
+
+
I talk on +intermud but nobody replies. What's up with that?
+
+If you haven't changed your MUD's name from the
+stock default (ie if your mud name is DeadSoulsWin
+or DeadSoulsNew) then your mud may be conflicting with
+someone else's new mud that is already connected to
+intermud. Change your mud's name and see if this +helps.
+
+Another possible cause is network problems.
+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. To check
+network status, ping Frontiers or Dead Souls. If the
+ping command gets no answer, i3 is probably down, or
+your connection to it has been interrupted. Your mud will
+be aware of this and retry to connect to i3 every
+fifteen minutes or so.
+
+There's also the possibility that nobody who wants to
+chat is listening.
+
+It's also possible that the Dead Souls I3 router has
+changed address or port. Visit this page to get the
+latest connection info:
+
+LPMuds.net I3 Router Page

+
+Under some unusual circumstances, the router might
+be misbehaving. If that happens, post a question on
+the lpmuds intermud topic: http://lpmuds.net/forum/
+
+Please make sure you post on the Intermud topic.
+
+It may also be that you have been earmuffed by
+other people, because you've annoyed them. You
+can avoid this by becoming familiar with the
+proper way to find answers.
+
+
+
How did you +know my mud started up?
+
+Muds on intermud receive notification of a new mud
+joining. Not everyone pays attention to this, but
+a few people do.
+
+Your mud also does periodic "pinging" as a form
+of keepalive.
+
+
+
I heard there's +an I3 router included in Dead Souls.
+
+Yes. It is undocumented because it's my opinion that
+if you don't understand the code, you're in no position
+to run the router. The code is in /secure/daemon/i3router .
+
+
+
What's this +about a manual on Frontiers?
+
+In your workroom is a chest. Open the
+chest and the Dead Souls Creators Manual is
+inside. The text files are in /doc/manual .
+
+
+
How do I add +limbs to a race?
+
+Edit /secure/cfg/races/<race> and make the changes
+you want. Then use removerace +to remove the race from the
+races daemon, then add re-add the race with addrace . For
+example:
+
+removerace tauntaun
+addrace tauntaun
+
+
+
How do I add a +race?
+
+Copy a race in
/secure/cfg/races/ +and edit it.
+For example:
+
+cp
/secure/cfg/races/bear /secure/cfg/races/wampa
+
+Edit the wampa file to reflect what you think a
+wampa is like. If you want new players to be able
+to select wampa as their race, make sure the file
+has this line in it:
+
+PLAYER_RACE 1
+
+Make especially sure to change the +lines RACE and
+LANGUAGE. When you're done +editing, type:
+
+addrace wampa

+
+For details:
+help addrace
+
+
NOTE: It is possible to remove all races. However, please
+read the following discussion to get an idea of the issues
+involved:
+
+[2006.11.20-18.08] Ohm@ashdev +<dead_souls> Hey, if the removeraces command will screw up +something, will removing the races manually from admintool have the +same effect?
+[2006.11.20-18.08] Cratylus@Dead +Souls Demo <dead_souls> ok let's take this one step at a time
+[2006.11.20-18.09] Cratylus@Dead +Souls Demo <dead_souls> removeraces will erase the list of races +held in the races daemon
+[2006.11.20-18.09] Cratylus@Dead +Souls Demo <dead_souls> what this means is that when you try to +clone a bear, you will get a big pukey error message
+[2006.11.20-18.10] Cratylus@Dead +Souls Demo <dead_souls> because bears aren't a race any more, so +the npc you try to clone will error out
+[2006.11.20-18.10] Cratylus@Dead +Souls Demo <dead_souls> i consider that "broken" behavior, +because i dont like it
+[2006.11.20-18.10] Cratylus@Dead +Souls Demo <dead_souls> but you'll only see it if you try to load +npc's, aka mobs
+[Ed note: +removing all races will also hose up your players]
+
[2006.11.20-18.11] +Ohm@ashdev <dead_souls> what if I want to get rid of all those +races, and all of those mobs?
+[2006.11.20-18.11] Cratylus@Dead +Souls Demo <dead_souls> right
+[2006.11.20-18.11] Cratylus@Dead +Souls Demo <dead_souls> before i answer your question
+[2006.11.20-18.12] Cratylus@Dead +Souls Demo <dead_souls> do you plan to have dogs n cats n deer n +stuff?
+[2006.11.20-18.12] Ohm@ashdev +<dead_souls> No. I'm want to completely write all my mobs from +scratch, because they're based on a very specific virtual world.
+[2006.11.20-18.12] Cratylus@Dead +Souls Demo <dead_souls> ok
+[2006.11.20-18.13] Cratylus@Dead +Souls Demo <dead_souls> what you want to do is not complicated
+[2006.11.20-18.13] Cratylus@Dead +Souls Demo <dead_souls> so i hope yer not getting that vibe
+[2006.11.20-18.13] Cratylus@Dead +Souls Demo <dead_souls> the reason i'm cautioning you against it +is
+[2006.11.20-18.14] Cratylus@Dead +Souls Demo <dead_souls> that removing all races basically makes +lots of rooms not work anymore, because they contain npc's that +requireraces to exist
+[2006.11.20-18.14] Syphon@WorldWideResistance <dead_souls> eep, +That's a bit of editing
+[2006.11.20-18.14] Cratylus@Dead +Souls Demo <dead_souls> and disabling sample areas isn't +something i recommend to someone who's starting out
+[2006.11.20-18.15] Ohm@ashdev +<dead_souls> right, that's what I'm trying to figure out. How can +I get rid of the mobs, and other spots that require them so it will run +right.
+[2006.11.20-18.15] Syphon@WorldWideResistance <dead_souls> Can't +he just dest npc in all the rooms ?
+[2006.11.20-18.15] Cratylus@Dead +Souls Demo <dead_souls> ok
+[2006.11.20-18.15] Ohm@ashdev +<dead_souls> I'm newish to ds, but I've worked with plenty of +other muds, and I figured I can reference to the backups if I need help.
+[2006.11.20-18.15] Syphon@WorldWideResistance <dead_souls> How +many rooms are there
+[2006.11.20-18.15] Cratylus@Dead +Souls Demo <dead_souls> desting an npc doesnt permanently remove +it from the room
+[2006.11.20-18.15] Syphon@WorldWideResistance <dead_souls> ah
+[2006.11.20-18.15] Cratylus@Dead +Souls Demo <dead_souls> to permanently remove an npc
+[2006.11.20-18.16] Cratylus@Dead +Souls Demo <dead_souls> walk into the room it's in
+[2006.11.20-18.16] Cratylus@Dead +Souls Demo <dead_souls> and then: delete <npc>
+[2006.11.20-18.16] Syphon@WorldWideResistance <dead_souls> nod
+[2006.11.20-18.16] Cratylus@Dead +Souls Demo <dead_souls> where <npc> is the name of the npc
+[2006.11.20-18.16] <dead_souls> Zeus@Ancient Rome deletes +Cratylus...wait that won't work :P
+[2006.11.20-18.16] <dead_souls> Zeus@Ancient Rome watches the +delete backfire and melts into a pile of goo
+[2006.11.20-18.16] Ohm@ashdev +<dead_souls> yea, but that's not exactly practical in my +situation... I want to get rid of ALL npcs in ALL rooms.
+[2006.11.20-18.17] Cratylus@Dead +Souls Demo <dead_souls> ok
+[2006.11.20-18.18] Ohm@ashdev +<dead_souls> wait, this doesn't make sense... the only npc I see +in the source files is fighter.c
+[2006.11.20-18.19] Cratylus@Dead +Souls Demo <dead_souls> here's what i think then
+[2006.11.20-18.19] Cratylus@Dead +Souls Demo <dead_souls> if the sampel areas are incompatible with +your vision, then just don't use them
+[2006.11.20-18.20] Cratylus@Dead +Souls Demo <dead_souls> not trying to be difficult, but if it's a +lot of trouble to back-port to them, you're probably better off +concentrating on your original areas
+[2006.11.20-18.20] Ohm@ashdev +<dead_souls> when you first load the server, what areas are +loaded, and from where?
+[2006.11.20-18.21] Cratylus@Dead +Souls Demo <dead_souls> the mud expects /domains/default to exist +for some stuff like the default death room and such
+[2006.11.20-18.21] Cratylus@Dead +Souls Demo <dead_souls> but by editing /secure/include/rooms.h +you can just substitute your own rooms for these system functions
+[2006.11.20-18.21] Ohm@ashdev +<dead_souls> Ohhhhhhhhh! Okay. I see now.
+[2006.11.20-18.22] Kriton@Dead Souls Arena <dead_souls> +send_messages needs a man page :P
+[2006.11.20-18.22] Ohm@ashdev +<dead_souls> So you're saying the npcs listed in +domains/default/npc/ are required because rooms listed in rooms.h try +and load some of those npcs.
+[2006.11.20-18.23] Cratylus@Dead +Souls Demo <dead_souls> not quite
+[2006.11.20-18.23] Cratylus@Dead +Souls Demo <dead_souls> hang on crazy 2 yr old
+[2006.11.20-18.28] Cratylus@Dead +Souls Demo <dead_souls> ok
+[2006.11.20-18.28] Cratylus@Dead +Souls Demo <dead_souls> in /secure/include/rooms.h you can see +that special rooms are specified
+[2006.11.20-18.29] Cratylus@Dead +Souls Demo <dead_souls> the start room, the death room, etc
+[2006.11.20-18.29] Ohm@ashdev +<dead_souls> right
+[2006.11.20-18.29] Cratylus@Dead +Souls Demo <dead_souls> the mud needs these to exist, or your +users will be helpless
+[2006.11.20-18.29] Cratylus@Dead +Souls Demo <dead_souls> ok
+[2006.11.20-18.29] Cratylus@Dead +Souls Demo <dead_souls> my point is, you dont need to use the +ones that are there
+[2006.11.20-18.29] Cratylus@Dead +Souls Demo <dead_souls> make your own, and then put the filenames +in the rooms.h file
+[2006.11.20-18.30] Cratylus@Dead +Souls Demo <dead_souls> nobody who plays your mud ever needs to +see a single stock room
+[2006.11.20-18.30] Cratylus@Dead +Souls Demo <dead_souls> they can just exist like an appendix, +unused, unneeded
+[2006.11.20-18.30] Ohm@ashdev +<dead_souls> ok
+[2006.11.20-18.30] Cratylus@Dead +Souls Demo <dead_souls> eventually, once they have no usefulness, +deleted
+[2006.11.20-18.31] Cratylus@Dead +Souls Demo <dead_souls> but for now, i think they *are* useful to +you
+[2006.11.20-18.31] Cratylus@Dead +Souls Demo <dead_souls> as examples
+[2006.11.20-18.31] Cratylus@Dead +Souls Demo <dead_souls> which is why i caution you against just +deleting lots of stuff before you get the hang of how i all works
+[2006.11.20-18.32] Ohm@ashdev +<dead_souls> ok, that makes sense
+[2006.11.20-18.32] Ohm@ashdev +<dead_souls> I really just needed to know what I had to do to +remove all stock rooms from player view
+
+
+
How do I make +my friend an admin?
+
+
+
To make a creator named Xyzzy an assistant admin, type:
+
+groupmod -a ASSIST xyzzy
+
+
Xyzzy then needs to log out and log back in. To
+make her a full admin, you'd add her to the +SECURE group instead.
+See this faq entry +for the difference between ASSIST and SECURE.
+

+
+
I don't like +how the who command output looks! You should change it.
+
+Believe it or not, I actually get requests like this. I also
+get stuff like "the inventory list should be chronological in
+order of acquisition." Maybe that's a good idea, but it's
+your mud, not mine. Make it so for yourself.
+
+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. If a normal action causes a runtime
+error or abnormal behavior, I need to know that. Also typoes, null
+error messages, etc...in short, tell me what's broken.
+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
+Creator's Manual.
+
+
+
Can you please +make the FAQ easier to read? It's too long and complicated.
+
+No.
+
+
+
Most of the +file headers have only Descartes's name on them. Did
+you really +develop this lib or did he?
+
+Both. The lib he released in the late 90's was his, and so almost
+every file on it had his name. I've been working on it since, but
+I am very lazy about headers. I work on lots of files at the
+same time, and authorship attribution tends to rank very low
+on my priority list. Therefore, even though a great majority
+of the files in the lib have been either heavily modified or
+created by me, my name is on very few.
+
+I haven't bothered to go back and revise headers either,
+because, honestly, what a pain in the butt that would be. I'm
+satisfied knowing there's little doubt who has made the many
+changes on the lib.
+
+
+
How can I +change the colors of the channel messages?
+
+The colors are specified in /secure/daemon/chat.c
+
+You will need to replace the color specification in more
+than one spot in that file.
+
+
+
How do I know +what other muds use Dead Souls?
+
+
+mudlist -m Dead
+

+
See the creator's +FAQ for more intermud command info.
+
+
+
I was hanging +out in the Arch room and the loudspeaker went off. WTF?
+

+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 used to be announced in the Arch room. If that is still happening,
+you are probably not running a current version of the lib.
+
+The current behavior is that network messages are
+announced in the network room (below the arch room) and router
+messages are announced in the router room (south of the
+network room).
+
+Note that these messages are normal.
+
+
+
I want to test +the intermud channel but I don't want to spam the ds line.
+
+Type: ds_test test
+
+The ds_test channel is specifically for communication
+testing so that ds can remain spam free.
+
+
+
What's this +"Network room"?
+
+There is a room below the Arch room called the network room.
+It is intended to facilitate troubleshooting of network
+and intermud problems. Unless you're intimately familiar
+with Dead Souls network code, I suggest avoiding this
+room, as it is very messy and very noisy.
+
+
+
The web server +and FTP server don't work
+
+To enable them use the commands: +
+mudconfig inet enable +
+mudconfig http enable +
+
mudconfig ftp enable
+
+These servers 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.
+
+
+
I tried to log +in to the FTP server but I can't!
+
+Make sure you use your mud name and mud password, not the
+username and password of the computer you are on.
+
+
+
I can't do +anything with FTP. It just hangs there.
+
+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. The
+default Dead Souls FTP server does not support passive
+transfers, but an alternate included server does.
+
+See this link for more information.
+
+
+
The web server +gives me a 404 but I know the directory is there.
+
+Like the FTP server, the web server is a very simple program.
+It does not do directory listings by default. To enable
+directory listings, type:
+
+mudconfig dirlist enable
+mudconfig http disable
+mudconfig http enable

+
+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.
+

+
+
I'm using an +external FTP server, but the files I transfer
+become read only!
+
+
You +need +to make sure that the FTP server you use
+runs as the same user as the mud driver does, otherwise
+you'll have permissions conflicts.
+

+

+
I moved a +command from one directory to another. How do I get the new location +recognized?
+
+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
+
+

+
The mudtime is +all wrong!
+
+The mudtime command tells you +what time it is in the game, not what time
+it is in the real world. This mud time, or game time, passes much more
+quickly than normal, real-world time, so you may see a few sunrises and
+sunsets in the game while playing. Hopefully you are sufficiently
+well-adjusted that this will not occur in real life.
+
+
+
The time of day +is all wrong!
+
+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. You may be using a UNIX operating system that is set for
+GMT offsets, rather than local time.
+
+Check your LOCAL_TIME setting in /secure/include/config.h .
+If it is 0, see if setting it to one changes things:
+
+mudconfig localtime yes
+
+If not, figure out how many hours off you are, and
+set that value. For example:
+
+mudconfig extraoffset -5
+
+
+
What happened +to the roommaker and thingmaker?
+
+They produced code that was often incompatible with QCS. They are no
+longer supported.
+
+
+
I keep getting +'Connection to address server (localhost 9999) refused.'
+
+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.
+
+
+
Can I charge +players a fee for playing on my mud?
+
+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.
+
+
+
Can people +donate money to me for the mud?
+
+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.
+
+You should not try to bend the rules. For
+example, public television channels often give trinkets to
+donors as a token of their appreciation. If someone donates
+money to you for your mud and they get a "thank you gift",
+this is a quid-pro-quo, or "something for something", and
+it's not right.
+
+This is a MudOS thing, not a Dead Souls thing.
+If you can't abide by MudOS licensing, just port Dead
+Souls to some driver that lets you do commercial stuff.
+Then please tell me how you did it, so I can pass on the
+leetness to others.
+
+
+
I found a bug. +For real. Can you please fix it?
+
+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.
+
+Make sure you have read this:
+
+http://www.chiark.greenend.org.uk/~sgtatham/bugs.html
+
+
+
+
Where would I +edit to change how long someone can be idle before they get +disconnected?
+
+

+mudconfig maxidle 14400
+
+
To make players get logged off after four hours. Setting the
+number to 0 makes it so there is no idling timeout enforced.
+
+Note that logged-in players need to log off and log back on for
+this change to take effect.
+
+

+
How do I permit +all users who log in to become creators automatically?
+
+
mudconfig autowiz on
+
+

+
How do I limit +the use of intermud channels?
+
+

+mudconfig intermud restrict
+
+Then to let joebob use intermud:
+
+groupmod -a intermud joebob
+groupmod -r intermud jimbob
+
+

+
How do I get +off intermud completely?
+
+
mudconfig intermud disable
+
+

+
How do I change +the start room for the mud?
+
+
mudconfig startroom +/domains/MystyDragonClouds/room/cloud_nine
+

+

+
I don't like +having newbies get special treatment.
+
+
mudconfig newbielevel 0
+

+
+
I don't want +players to be able to pick non-human races.
+
+
mudconfig justhumans 1
+

+Note that this will not affect players who are
+already non-human.

+
+

+
I want everyone +to speak the same language.
+
+
mudconfig justenglish 1
+
+Note that this may not affect players who already
+are not native English speakers. To change them,
+type:
+
+call +players_name_here->SetNativeLanguage("English")

+
+

+
I made a change +to /lib/player.c and updated it, but I'm
+not seeing +a difference in my character.
+
+

+If an object (you) is loaded into memory, it contains
+the features and functions of its file and inherited files
+at the time it was loaded.
+
+Changing those files and updating them doesn't do
+anything to an object that is already loaded using the
+old code.
+
+In a case like this, what you want to do is
+recursively update the file of the object in question,
+then reload the object.
+
+Let's say you modified /lib/npc.c so that
+npc's sit down by default. Say you want the fighter in
+your test room to possess this new functionality.
+
+If you type: reload -r fighter
+
+then the fighter's file is recursively updated,
+the current version of the fighter is whisked away, and
+a new version of the fighter is created, incorporating
+the new auto-sit feature.
+
+If the change in question is to lib/player.c
+or some other file inherited by you, you would
+type:
+
+update -r /lib/creator
+
+But you are still using that same old body as
+before, so you'll need to quit and log back in to
+get a new body using the new code.
+
+Note that disconnecting and logging back in is not enough.
+You have to actually quit, so your old player object
+is completely destroyed.
+
+
Alternately +you +could just refresh your own code
+without quitting with the command:
+
+userload me

+
+
+
How do I change +the items new players receive?
+
+Look in /lib/player.c for the function that gives
+new players jeans and a t-shirt. Modify this
+function to suit you. Make absolutely sure that
+the objects you put there actually clone
+correctly.
+
+Remember to bk /lib/player +before editing this file,
+because if you screw it, then log off without
+restoring a working copy, you will be sad.
+
+
+
Hey, there's no +<foo> class! What's up with that?
+
+True, there is no samurai class, and in fact, as of
+this writing there is no cleric, acrobat, frombotzer,
+or basketweaver.
+
+The reason for this is that the Dead Souls
+mudlib distribution isn't intended to be 100% ready for
+players to show up and start doing quests.
+
+What quests there are, what races, classes,
+areas, objects, rooms, and NPC's you find in the
+distribution are examples. If you open your mud
+to players and what you've got is the Orcslayer and
+newbie mansion quests, you might as well just close down.
+In fact, please do.
+
+Dead Souls is a starting point for a mud.
+I have no way of knowing if you're going to have
+mermen in an aquatic-theme mud. I have no clue
+whether your space aliens will have 8 tentacles or
+16 (they like base2, dontcha know).
+
+So, no, there's no <foo>, because the
+responsibility for making the mud in your creative
+vision is yours, not mine. My job is to give you
+a lib with enough working examples and enough
+documentation so that you can code your own
+basketweaving bugblatter beasts.

+
+

+
Where can I get +a Dead Souls mud hosted?
+
+That's a heck of a good question. There are many mud hosting services
+out there. 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.
+
+Lately I've heard rave reviews for Alternate +Realm +Hosting from
+people with good judgment. If I weren't already happy with
+my arrangements I'd probably give them a day in court. They're
+supposedly inexpensive and have very good service and support.
+
+
I'm told +that the free mud hosting at ISUnlimited is +adequate.
+
+There used to be another free mud hosting service I
+was aware of, and that's FrostMud. +It +was basically a guy and a Linux
+server with room on it for muds. However, there's some sort
+of problem he has and it's going away.
+
+Update: He wrote me an email +saying he's back, so perhaps you
+can still use his service.
+
+There's no such thing as a free lunch. If you want
+a reliably solid, well supported, feature-rich platform for your
+mud, quit being a cheapskate and cough up the $9/mo. That's
+like, what, three espressos a month. Nobody is too hard up to
+host commercially, unless you're on the street.
+
+I've heard good things about the commercial service
+from Arthmoor and Genesis.
+
+Wolfpaw also is an excellent +commercial host: stable and reliable.
+One of my test muds is hosted there, and this is the uptime report,
+as of 25 December 2006:
+
+Dead Souls Arena has been up for 11w +6d 7h 28m 34s.
+

+However, Wolfpaw has become rather tired of dealing with
+newbie mud admins, so unless you're a hardcore do-it-yourselfer
+who just needs a big data pipe and nothing else, you may be
+better off with other hosting.
+
+If you have a DSL or cable modem, and your computer is
+up all the time, you can just use that, too. Your IP may be
+dynamic, making it tough for people to find you, but there are
+dynamic-dns services out there that help keep your ip
+tied to a specific name.
+
+Generally speaking you'll be better off with a VPS +than a
+"mud host", if you have any system admin skills. A VPS
+tends to have vastly more bang-for-buck than a mud host,
+with the drawback of requiring you to have some idea
+what you're doing as a system admin. I've had excellent
+results using Linode.
+
+
+
Your LIB_MXLPLX +system is all screwy. I changed it and it works. Wanna see?
+
+Hell yes. I'm not just in this for my health. I want
+more people coding in LPC so I can look at the fresh ideas and
+new perspectives of other people (read: swipe code).
+
+Send me an invitation to your mud by email or <ds>. I'd
+love to look at your work.
+
+If it is code you are willing to donate to Dead Souls, I
+will gladly accept its submission, also by email. There's no
+guarantee it will make it into any future release, but it just might.
+
+Please be aware that by doing so, you signal you claim no
+copyright to the code (you must make it Public Domain), allowing me to
+publish it and preventing you from ever revoking my right to distribute +it.

+
+You also represent that no third party has copyright to
+the code, and hold me harmless in any subsequent
+dispute between you and any other third party.
+
+If you want to email me code but wish to retain
+copyright, please state so clearly in the body of your email. I
+will honor that request
(and it's the law +so I don't really
+have a choice). Just be aware I will not put code into Dead
+Souls that anyone other than me has copyright to. I can't
+afford the risk of someone deciding I can't distribute
+code that DS may eventually rely on.
+
+
Also, I +don't want to hear from anyone about my
+use of legal terms of art. I know damn well it's more complicated
+than I make it sound. My phrasing is sufficient to make
+the legal practical transaction of ideas possible here.
+

+The point I'm making should be clear. If it isn't,
+please consult applicable laws, etc.
+
+

+
How are files +organized in Dead Souls?
+
+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.
+
+estates/
+
+Where player-owned objects, rooms, logs, etc. are kept.
+
+
+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. Shadows not in this directory will not load.
+
+spells/
+
+Pretty self explanatory. The spells daemon looks for spells here.
+Spells not in this directory will not be available.
+
+std/
+
+Provided for backward-compatibility with older lib
+files. Not needed if you aren't porting from an older
+or different lib (such as TMI-2 or LPUniversity).
+
+
+tmp/
+
+A directory anyone can write to. Generally for swapping
+data between objects, systems, or people. Note: files
+here can't be loaded into memory with the update command,
+for security reasons. If you need to put something in
+a world-writable place but need it to be loadable, use
+/open instead.
+
+verbs/
+
+A 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. Verbs not in this directory will
+not load.
+
+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.
+
+
+
What are sefuns +and efuns?
+
+
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.
+

+
+
+
Whew! Ok now I +know where stuff is. What's next?
+
+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 Creator's 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.
+
+It's also important to read the Administrator's Guide.
+

+
+
Oh, man, you're +kidding! Those are, like, books! Can't I
+just start +making stuff?
+
+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.
+
+Start with chapter +31, like this:
+
+read chapter 31 in my manual
+
+

+
Everything is +su-u-u-u-p-e-e-r-r-r s-s-l-o-o-o-o-w-w-w
+
+First, make sure you are using the latest available version of
+Dead Souls (check 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 may have a +runaway. Most often this involves
+NPC's doing stuff you didn't expect. Reset all loaded rooms
+with the following command (you may need to enter it more
+than once):
+
+warmboot
+
+
perhaps followed by a:
+
+flushobs
+

+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.
+
+
+
Dude! One of my +creators just kicked me off my own mud!
+
+One of the virtues of LPC is that it is flexible and powerful.
+One of the drawbacks of LPC is that it is flexible and powerful.
+
+It is not possible to make an LP mud that is
+immune to abuse from creators. You just can't. The MudOS
+function set is just too complex and sophisticated to eliminate
+every possibility of abuse.
+
+You will therefore *always* be vulnerable to things
+like people coding objects that crash the mud on purpose (I
+won't detail how that can be done, but anyone with intermediate
+LPC skill can do it, and utter newbies can even do it with
+a stupid enough mistake), finding a way to dest admins, or
+continually updating recursively the /lib filesystem. A
+jackass will always find a way to expose you to her jackassery.
+
+This means that you need to know who is coding on your
+mud and what they are doing. Your job as an admin is to
+immediately deal with coders who pose a discipline problem.
+If they fool you once, shame on them. If they fool you
+twice..the..they...they shouldn't fool you twice is what I'm
+saying.
+
+This does not mean that Dead Souls is somehow
+impossible to secure. You can easily prevent unauthorized
+access to lib data. See the next section for how this works.
+
+What you can't prevent is some dude off the internet
+you just met and made a creator from wreaking havoc on your
+mud and creating a nuisance of himself. You have to know who
+these people are and you have to have a level of trust and
+confidence in them, otherwise you need to use the decre
+command.
+
+

+
Is Dead Souls +secure?
+
+No running Internet software I know of is "secure" in the
+sense that you don't need to continually pay attention to it.
+
+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, of course, 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
+simpler. 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. Also see
+the grant command, as well as domainadmin.
+
+Security bugs usually aren't about the security model itself
+being weak, but rather careless code (generally from me). If
+you find such a bug, please let me know right away so I
+can fix it.
+

+
+
I sent you my +code a week ago. Is it in or out?
+
+How long it takes me to review code submissions has nothing
+to do with what I think of you, your skills, or your
+code. It takes me a long time because Dead Souls isn't
+actually my job, and is not a physical member of my
+family, so it has to wait its turn sometimes, for my attention.
+Sometimes I will get to someone else's code sooner even
+though I received yours first. What can I say. Sometimes
+I feel like dealing with a particular thing at a particular
+time.
+
+
+
Did you finish +the bfd() sefun modification I asked you for last night?
+
+I'm on the ds line a lot, and generally accommodate people's
+requests right away if I have time. This makes it seem
+sometimes like I can turn orders around in minutes or
+hours, like a short-order cook.
+This is an illusion. I do this sometimes
+for requests that strike my fancy or that are so simple
+they are not inconvenient, or maybe because I happen to
+be bored at that moment. But my sometimes doing this
+doesn't mean folks should expect some sort of prompt
+turnaround on special requests.
+In general, I am not sitting at my desk waiting
+for code orders. I'm doing something else. If I get to
+your request right away, then good for you. If I don't,
+then I'll get to it when I get to it (if I get to it).
+
+
+
The queeg +daemon is a horrendous mess. It's inefficient and frankly offensive.
+
+I'm not an especially gifted programmer. In fact, I view
+myself rather as a Pakled +from the Star Trek series. I
+look for things that make the code go. I look for things
+that make the code strong. Sometimes, because I am not
+a trained or professional programmer, things are done
+in a way that shock the conscience of more sophisticated
+practitioners.
+
+If you find such code (and I do hope it is rare),
+bringing to my attention that it has been implemented in a
+wretched way doesn't help me. I know that. I wrote it. If
+you want to help, send me an email with the fixed code.
+
+
+
You implemented +my code but didn't give me credit.
+
+Whoops. Send me an email telling me where I goofed and I'll fix it.
+
+
+
Intermud mail +doesn't work
+
+Yes it does. If you tried to send intermud mail to someone
+with Dead Souls and it failed, then one or more of the following is +true:
+
+* You are using a Dead Souls version below 2.4.1.
+* The recipient is using a Dead Souls version below 2.4.1.
+* The recipient has disabled their OOB service.
+* The recipient has disabled their INET service.
+* The recipient is firewalled and cannot accept OOB connections.
+
+
+
The admintool +menus let you pick options that aren't visible
+
+I can't decide whether this is a feature or a bug. I'm
+leaning toward "laziness".
+
+
+
What does +locking the mud do, exactly?
+
+When the mud is locked, only members of the authorized
+groups are permitted to log in. By default, these
+groups are SECURE, ASSIST, ELDER, and TEST. Anyone
+who is not a member of these groups, whether they are
+a creator or a player, is prevented from logging in.
+
+To lock the mud, use the admintool command, option a.
+To add people to groups, use the admintool command, option v.
+
+
+
The race help +output is inadequate for role-playing. How do I change it?
+
+By default, help human will +output various characteristics
+of the human race, as known to the race daemon. If you
+want instead to provide your own help data on the history and
+lore of humans, simply create a file called /doc/help/races/human
+and put your information in it. That information will then
+be what is displayed when requesting help on that race.
+
+
+
I need to know +what features to expect in the next release so I don't
+waste time +duplicating effort
+

+Visit http://dead-souls.net/RELEASE_NOTES +for information on
+the latest releases and what they contain. The topmost
+version is usually not yet available for download, and
+is listed so that folks know what's coming in the
+next release. If this is so the version name will have
+"(unreleased)" next to it.
+
+The dsversion command is +available to
+allow you to query that site from the mud itself.
+
+

+
You need a +development roadmap and task tracking
+
+No, I don't. If I had developers and teams and
+such things, then I'd use all the fancy project
+management stuff available on Sourceforge. But
+I don't want to manage developers, I want to code.
+

+
+
How do I update +a sefun without rebooting the mud?
+
+To have your new nit_pick() sefun take effect in the
+running mud, you might do something like this:
+
+update /secure/sefun/nit_pick.c
+
+update /secure/sefun/sefun.c
+
+
+
My +new +sefun updates but I can't seem to use it.
+

+Make sure the sefun is prototyped in /secure/sefun/sefun.h
+
+If the sefun is in a new file you created, make sure
+that /secure/sefun/sefun.c inherits that file.
+
+
+
What's +the +point of the apostrophe-stripping for args in lib/command.c?
+
+
It was cheap workaround for a parser problem. Dead Souls 2.1 and
+above no longer implement this, as the driver issue has been
+corrected.
+
+
+
How +does +one achieve 'high mortal' or 'ambassador' positions?
+
+
Those are legacy positions from DS v1/Nightmare IV/3. They are
+basically groups, managed by an arch with admintool, which
+can be granted privileges not normally enjoyed by mortals.
+In the current implementation of Dead Souls, those
+positions are vestigial. You can implement them on your
+own mud however you please.
+
+
+
I +would like XYZ and PDQ to happen every time the mud boots
+
+
The most common way to have this happen is to add
+your daemon (and typically that's what you'll
+want to start at boot) to /secure/cfg/preload.cfg .
+This will ensure that it gets loaded
+before the mud accepts any connections. It has the
+added advantage of being included in the list of daemons
+that the mud periodically checks and restarts if they
+have died.
+
+If it isn't a daemon, but rather some
+specific function you want to happen at boot, simply
+add the relevant code to /secure/daemon/autoexec.c
+
+
+
I can't login! +I keep getting: "It seems some work is being
+done right +now, try later."
+
+This is bad. What this means is that some
+files that are needed in order to load your player
+object cannot be loaded. It can be any of a very large
+number of files, which is the problem. Usually this
+happens if you've been, for example, messing around
+with player.c, then broke it, and rebooted the mud. Now
+since player.c can't be loaded, you're locked out.
+It could be any of the files loaded by your
+player object, or other daemon files needed by your
+login. The only way to narrow down the possible list of
+files you corrupted is by examining the output of the
+console (the window where you type the command line
+to start the mud) and reviewing log/runtime and
+log/catch for clues.
+Once you've found the culprit, either fix it,
+or replace it with the original version from the
+Dead Souls distribution package.
+
+

+
I had a really +great idea that revolutionizes ds and you
+refuse to +include it. I am forking ds development and
+making my +dream come true.
+
+Ok then, have fun. All I ask is that you give your
+project a name that isn't going to confuse people
+as to which lib is which. Confusing your user base
+isn't a good way to get started on such an enterprise.
+Send us a post card once in a while.
+
+

+
What do the +version numbers mean?
+
+2.0r16 means "Major version 2, minor version 0, release number 16".
+Releases happen pretty frequently, to add functionality and fix bugs
+from the previous release. When the basic functionality of a minor
+version is as bug free as reasonably possible, a new minor version
+change happens.
+Major version number changes are very rare and represent a
+vast difference from the old major version. Versions 1 and 2 of
+Dead Souls are so different as to be largely incompatible with each
+other's code.
+
+As of this writing, 2.10 is released as the current stable version.
+
+
+
The Dead Souls +router is down.
+
+Use the switchrouter command to change between
+routers. The new default I3 router for Dead Souls muds is called
+*i4 . So far it's been dramatically more reliable than
+the old intermud.org router, which was known as *gjs.
+
+If the router you are on is down, try using the switchrouter
+command to connect to a backup. As of this writing, the *i4
+and *wpr routers serve as +mirrors for each other, so
+that connecting to one will give you access to the same muds
+as those on the other.
+
+For more information on switching between routers, type:
+
+help switchrouter
+
+If the *yatmim router goes down for more than a
+few minutes, make sure to check the router page +to see if
+the IP address or port have changed.
+
+
+
I'm going to +totally revamp <insert highly complex system here>.
+Will that +be difficult?
+
+This is, surprisingly, a fairly common question.
+Basically, the answer is:
+
+"If you have to ask, then the answer is yes."
+
+It's not an impossible task to, say, rewrite
+combat to be just like the combat you're used to on LeetFooMud.
+It's totally doable, and not *all* that difficult for
+an experienced coder.
+
+But if you're new to LPC, you need to concentrate
+on getting the basics down before you put that cart in
+front of that horse. Let me phrase it like this:
+
+"If there's any part of the Creator's Manual you don't
+know and understand, you aren't ready to do lib coding yet."
+
+If you are at 100% grok with the manual, then
+please read chapter +8 +of the Admin's Guide to get started
+on serious lib work.
+
+
+
I've hired an +area coder to make a new domain. I want her
+to be able +to use QCS in /domains/MistyDragonShireMysts
+
+The default behavior of QCS is to try to figure out
+what directory makes most sense to write in. It assumes
+that it's only going to write into areas you have write
+permission to. Since your new coder doesn't have write
+access to /domains/
MistyDragonShireMysts, +QCS +instead will
+write to the next most logical place: her home area directory.
+
+This is true even if you use the grant +command
+to enhance her access. QCS's authentication mechanism is
+entirely separate from the grant/access system, which works
+fine for non-QCS editing.
+
+To make your new domain, use the domaincreate command:
+
+domaincreate MistyDragonShireMysts
+
+To enable your new coder to use QCS in that domain,
+use the domainadmin command to +manage the admins of that
+domain. A domain may have more than one admin at the same time.
+
+For more information on domainadmin, type:
+help domainadmin
+
+For more details on where QCS puts things, be sure
+to read this +Creator FAQ section.
+
+
+How does player +voting work?
+
+The voting system enables players to nominate and
+vote for class leaders. A Fighter can nominate and vote for
+his Fighter leader, Mages can vote for a Mage leader, etc.
+The nomination period usually lasts about a week, then
+nomination closes and voting begins. Voting ends when
+an arch enters the voting room (it's in Town Hall) and
+issues the appropriate command. See the voting room printed
+material for instructions.
+When the voting is ended, the winner becomes
+council member. The high council is composed of
+representatives (the leaders) of the classes. What kinds
+of authority the council should have is entirely up to
+you and your mud. No default powers are enabled, you'll
+need to code your own sets of privileges and responsibilities
+for your councilors.
+Because creators have no business meddling in the
+affairs of mortals, they cannot vote, regardless of their
+class affiliation.
+
+
+What are +"estates"?
+
+Estates are home directories for "builders", and an area
+where player-specific files can be kept.
+
+
+What are +"events"?
+
+Some things should happen regularly. Perhaps
+log rotation, or backing up some .o files. The events
+daemon, or EVENTS_D handles this. To add or remove
+events use the add_event() sefun. For example, to add the
+log rotation event, I issued this command:
+
+eval return +add_event("/secure/daemon/log","/secure/daemon/log","RotateLogs",({ +}),7200,1)
+
+Which said: "Every two hours, call the RotateLogs function in the log +daemon."
+
+To see what events have been scheduled, type:
+events
+
+To remove an event from the events schedule, find its
+next runtime, and use it as an argument to the remove_event() sefun,
+like this:
+
+
events
+
+The following events are pending:
+1145159511 RotateLogs Sun Apr 16 03:51:51 2006 EDT
+
+eval return remove_event(
1145159511)
+
+

+Where does user +monitor data go?
+
+When you monitor someone, or if you enable
+GLOBAL_MONITOR, monitor data is logged into /secure/log/adm.
+
+
+
How would you +set a race to be selectable by new players?
+
+If the race already exists, and it is, say, kobold, type: +
+removerace kobold +
+
+Then see: http://dead-souls.net/ds-admin-faq.html#10
+
+

+
+
Where is emote data kept? Can I +edit it by hand?
+
+Emote data is saved in /save/soul.o
+
+You must never, ever, edit an .o file. Period. It
+is possible to do it without corrupting data, but I do
+not condone it, I don't recommend it, and if you fux your
+mud because you did it anyway, I won't support it.
+
+If you edit an .o file, and now things don't
+work, it is your own fault. If you didn't back things up
+before editing system files, there's nothing anyone can
+do to retroactively save your data.
+
+
+What are .h and +.o files? Where are they kept?
+
+Files with the extension of .h are called header
+files. They have code or variables that are helpful when
+creating some things, so that an armor object uses
+armor_types.h to load some useful information without having
+to hard code it every time you make a piece of armor.
+These global header files are most typically found in
+/include or /secure/include , although local header files
+that are specific to a particular directory (such as
+header files for lib objects) are commonly found in an
+./include subdirectory of the given directory.
+
+Files with an .o extension are object persistence
+files. They contain data, not code. There are some things
+that happen in the lib that should persist across
+reboots, such as races, classes, economy, etc. You could
+just hard code this stuff, but what if you need to make
+changes? What if your economy needs to be flexible to
+accommodate inflation? What if you want to be able to
+add or remove emotes on the fly?
+Persistence files allow you to save data which
+is subject to manipulation, but which needs to be available
+in case the mud restarts.
+
+Because .o files tend to contain information
+that is structured and formatted in a very specific way,
+they should never be edited by hand. They are intended to
+be loaded and saved by objects like daemons. Monkeying
+around with the contents of an .o file is an excellent
+way to damage your mud.
+Another reason to avoid it is that even if you
+make a valid change, it's liable to be overwritten unless
+you fully understand the daemon that uses that file.
+
+
+But my friend +forgot his password! I *have* to edit his playerfile!
+
+Use the command: resetpasswd
+
+
+How do I change +my mud's name?
+
+1) type: admintool
+
+2) select the "Driver" menu option
+
+3) select the "change the MUD's name" option
+
+4) answer yes to rebooting
+
+
+Help! I locked +myself out!
+
+For UNIX administrators, it is natural to create an
+admin character for special admin tasks, and then use
+a regular character for routine stuff.
+There's nothing wrong with that, but if you
+lock the mud, you'll need to have your regular character
+be in either the ELDER or TEST groups in order to log
+in. For more information on modifying groups: help admintool
+
+
+What are the +privileges associated with the groups in groups.cfg?
+
+SECURE gives you 100% +admin privs to the mud.
+
+ASSIST allows reading +to almost all files in /secure, but
+doesn't provide write access to those files. Assist admins
+do report as archp() == 1, so access to writes based on
+that pointer should be carefully managed. Assist admins
+can also read the contents of player directories. See
+/secure/cg/groups/read.cfg and write.cfg for more detail.
+
+ELDER is just a nice +thing to have show up in the who list.
+
+TEST lets the lib know +you are a test character.
+
+All members of the above four groups are permitted to log in when
+the mud is locked.
+
+INTERMUD lets the +member use intermud, if RESTRICTED_INTERMUD
+is enabled.
+
+Any additional special groups or privileges you'll have to code +yourself.
+
+
+Why does the +documentation refer to LIB_ARMOUR and armour_types.h?
+
+The LPC documentation in the Creator's Manual was written by
+Descartes. I have been reluctant to make any changes to it,
+because first, it isn't mine, and second, deviations from the
+current lib are very small.
+
+In this particular case, you evidently have noted that
+the lib uses American spelling for "armor". The original Dead
+Souls distribution, version 1, and the Nightmare lib used the
+British spelling of "armour".
+
+Aside from finding it unnecessary and affected, I
+felt it was distracting and potentially confusing for coders,
+because it was the only word in the lib spelled this way. There
+were no instances of "colour" or "honour", etc. Rather than
+make things uniform by Britishizing them, I made them uniform
+by Americanizing them.
+
+To this day I don't know the reason for that original
+spelling. It may be that Descartes intended to make a
+distinction between, say, an armoury that sells things you
+wear, and an armory that sells things you wield.
+If I remember to, I'll ask him next time we talk.
+
+
+Where are +read/write restrictions kept?
+
+The global perms are listed in /secure/cfg/read.cfg
+and /secure/cfg/write.cfg . However, additional permissions
+may be available to a user based on the access privileges
+defined in a given adm/ subdirectory. See help grant for
+more details on that system.
+

+The permissions logic goes something like this:
+
+uid/euid/gid:
+1) These absolutely do not work in Dead Souls. It is not a supported +security model.
+
+read.cfg:
+1) If a file/directory is not in this file, anyone can read it.
+2) If a file/directory is in this file, only the specified +groups/people can read it.
+
+write.cfg:
+1) If a file/directory is not in this file, only admins can write to it.
+2) If a file/directory is in this file, admins + the groups/people +specified can write to it.
+
+grant command:
+1) A creator may use "grant" to give read and/or write access to files +under her control.
+
+default:
+1) Objects in the /secure dir can arbitrarily limit access to their +data if coded to do so.
+2) Anything not explained by the above rules is a security policy +defined in /secure/daemon/master.c

+
+
+
I need to test +day/night descriptions, but I can't wait around all day.
+
+Type: help ticktock
+
+
+How can I +change the default prompt? Can I make it dynamic?
+
+The default prompt is defined in /secure/lib/connect.c . Look
+for lines containing "SetPrompt".
+
+For details on options available, type:
+
+help prompt
+
+
+What is +"unguarded"?
+
+This is "stack security".
+
+In a typical DS call, there is a chain of objects and their functions.
+For example, if I issue a command, that command has a "call stack"
+that includes me, that command object, whatever that object affects, +etc.
+
+What stack security does is identify the privileges of each of
+the elements in that call stack, and if the privileges of any
+element are outside the permitted privilege scope of the given
+action, the call fails in the manner you described above.
+
+For example, if you code an object in your home directory that tries
+to write to a file in /secure, it will probably fail, because objects
+from your homedir do not have write privileges to /secure. If you
+moved that object to /secure, then that would be more likely to work.
+
+It would not be *guaranteed* to work, however, because even if
+the object itself has privs for writing to /secure, it may be that
+it is called from an object that does not have this privilege, like
+a non-admin user. That object's presence in the call stack would
+likely fail validation.
+
+The way to get around this for specific objects is to use unguarded().
+If the object with the privileged call has it wrapped in unguarded(),
+then the call stack validation is short-circuited and only the
+privileges for that object itself are evaluated.
+
+See man unguarded for syntax +and usage, and examine
+files like /secure/obj/snooper.c for examples. Use with EXTREME caution.
+
+
+
Is intermud +communication secure?
+
+Not in the slightest. Here's how it works:
+
+1) Whoever is running the +router has 100% access to every bit
+of communication that happens across that intermud network. All
+messages are plaintext, and although I personally can promise
+I don't read "private" messages, there is no way for you to
+be sure I'm not lying.
+
+2) All muds connected to an i3 +router can hear anything that
+is said on public channels.
+
+3) Any admin on any mud has +100% access to the i3 packet data
+that comes in and out, meaning they can listen to "private" tells
+between someone on that mud and someone on another mud.
+
+4) Nobody on any client mud is +able to "sniff" or "snoop" data from
+tells between other muds. If Alice@AlphaMud and Bob@BravoMud are
+having a heated "tell" discussion, Carol@CharlieMud can't listen in,
+even if she's an admin on her mud. However, Dave@DeltaMud is
+the admin on the i3 router mud, and he can "hear" everything.
+
+5) Local channels (cre, admin, +newbie, etc) do not get broadcast
+to the i3 router. There is one exception to this. Dead Souls 2.0r22
+had a bug that did just this thing. This bug is not
+seen in earlier versions, and later versions have been fixed to
+prevent this. However, any local admin has full access to any
+local channel.
+
+6) Since this is all plaintext, +anyone at all along the
+network stream (you ISP, their ISP, etc) can listen in,
+whether at the intermud point, or at the point where you
+or your message target telnetted into their mud.
+
+
+Therefore: do not tell secrets across intermud.
+
+
+
+What are some +do's and don'ts?
+
+There aren't too many, but they tend to
+be important, so try to follow these guidelines:
+
+- Your first step should not be deleting everying so you
+can start "from scratch". Dead Souls actually uses
+a lot of the included content for default mud functions.
+Wiping races and areas will leave you with a mud that
+doesn't work, and you'll lack the expertise to fix it.
+Instead, if you want a "clean slate", just create a
+blank domain and make it the default:
+domaincreate blank
+mudconfig defaultdomain /domains/blank
+
+- Do not allow anyone other than full admins (people in
+the SECURE group of /secure/cfg/groups.cfg) to edit
+/lib files. Things like /lib/player.c and such must only
+ever by edited by SECURE folks, because otherwise someone
+can use that editing to elevate themselves to full
+admin privileges. Do not mess with groups.cfg to let
+normal creators edit /lib files, do not modify the mud to
+allow write access there. If you need help with those files,
+hire someone you trust to be full admin. Or simply
+have folks submit code to you that you review before you
+drop it into /lib yourself. By default, neither normal
+creators nor assistant admins can write to /lib, and this
+default is the way you should leave it.
+
+- Don't mess with /realms/template/ unless you know exactly
+what you're doing. Breaking anything there will hose up
+new creators. The same goes for /secure/sefun/make_workroom.c
+
+- Don't be too adventurous with your admin character. I've
+had to change admin tools so people can't remove themselves
+from admin groups, and so that people can't demote themselves
+from creator to player...not because I thought maybe someone
+might do it, but because people have done it. If +you play games
+with your admin's body, gender, stats, whatever, it probably won't be
+fatal, but then, it might. Don't experiment on your admin. Use
+a test character.
+
+- Always always always back up any lib files you mess
+with. The bk and restore commands are your best +friends.
+
+- Don't let just anyone off the street become Creator. You
+need to know and trust your creators.
+
+- Don't let a week go by without a full backup of your mud.
+
+- Don't use color codes in your mud name. It makes people on
+intermud cranky.
+
+- Don't edit files that end in ".o". Those are data files,
+and are very very easy to corrupt if you edit them by hand,
+possibly damaging your mud.
+
+- Don't assume it's anyone's responsibility but your own
+to teach you LPC and how to use Dead Souls.
+
+- You should avoid changing your lib name unless you have
+a good reason for doing so. Changing from "Dead Souls" to
+"MyLib" or whatever probably seems like a fun thing to do, but
+makes you look like you're trying to claim credit that is not due.
+People really do notice, and really can tell. It makes you look bad.
+Keep in mind that most of what is currently in Dead Souls
+was written exclusively by me*, and yet I have not changed +the name.
+Similarly, unless you're actually branching MudOS, don't change
+the name that is reported by it. Leaving the driver and lib names
+alone is perhaps the one way you have to demonstrate your
+gratitude to the dozens of developers that made them available
+to you.
+
+* +After removing docs from each, the uncompressed lib material
+in DS1.1 is about 5 megs contained in about 1000 files, and DS2.10
+is about 19 megs contained in about 2900 files and directories.

+
+
+Is +DS2 +in any way suited to create a non-English mud from/with it?

+First the yes: There is at +least one mud that I know of that uses Dead
+Souls that is in Russian. I think they might have had some trouble using
+the Cyrillic alphabet, but I think they overcame it.
+
+For a while there was a Dead Souls mud in Korean. I don't
+know the name of it, because I never understood anything they said.
+As far as I know, they are not running today.
+
+There's very little about the lib that is incompatible with a different
+language. You can use typical ascii characters, meaning you can
+use accents, and so on. You room descriptions and messages can be
+in most languages you want that you can express in ascii, and +(apparently)
+even some that you can't.
+
+Now the no: The biggest +obstacle to making Dead Souls international
+is the parser. The "natural language parser" is in the driver, not the +lib, and
+it is optimized for English. English is an "analytic" language, so that
+word order dictates the meaning of a sentence. With German, a +"synthetic"
+language, word order is less important than the pre/in/suffix inflection
+and pronoun/noun declination. This kind of sophistication is completely
+beyond what the MudOS parser is designed to do.
+This means that a Dead Souls mud in German would have a hard time
+being 100% grammatically correct in its parsing system.
+
+However...
+
+If you're willing to make compromises with grammar, it can be done to
+a certain extent. For example, If you make "mein", "meiner", "meine", +"meines", +"meinen",
+and "meinem" all applicable to all possessive situations, then it can +work fine.
+To a grammar purist this is a horrible thing to do, but it is available +as an option,
+if you're willing to do some rewriting of the mudlib.
+
+German and Russian are statistical outliers, though. Many European
+languages lack noun cases, and for them, using Dead Souls would be much
+easier, in terms of the parser. You still have to deal with +agglutination,
+though, such as single-word intransitives or reflexives.
+
+So, the summary answer is:
+
+* Yes, you can use Dead Souls with non-English languages for
+descriptions and messages.
+
+* Depending on the language, you will have to make grammar compromises
+if you intend to use the MudOS parser for command processing.
+
+* To convert properly Dead Souls to another language is a non-trivial +task that
+involves reworking the master object, various command/verb system +objects, and
+possibly the MudOS parser to a degree. It *is* possible, but it's +definitely not
+a project for the faint of heart.
+
+* You can avoid this by not using the MudOS parser, and using the
+old-style command system, which depends on add_actions and command
+files to accomplish the job of parsing. This also requires some +substantial
+lib coding. It is more code you'd have to write, but it would be
+less advanced and complicated than refitting the natural language +parser.
+
+* I enjoy the study of languages and grammar, so I'd be delighted to +help
+you if you decided to take on that project. However, my role would be
+of a "helper". I cannot take on the burden of doing the majority of the
+grunt work code for someone else's project.
+
+* I wish I could tell you "Yes, and it's easy." The answer though, is +"Yes, but it's hard."
+
+

+I keep losing +my intermud connection, and sometimes I'm half connected
+
+This happens most frequently when using a wireless connection.
+Intermud is apparently not at all tolerant of the casual manner in which
+many wireless connections work, and as a result your intermud
+connectivity will likely suffer. Perhaps this is old-school of me,
+but I think it's reasonable to suggest that you run your mud on
+a land-line network connection.
+
+Another source of this problem is if you're running off of
+a home broadband connection. Some of these DSL or cable modems change
+IP addresses very frequently, and your connection is interrupted during
+those changes. If your connection is abruptly terminated and you come
+back with a different IP, the intermud router may not handle this
+gracefully. Perhaps this is old-school of me, but I think it's
+reasonable to suggest that you run your mud on a static IP.
+
+Finally, I have seen some home firewall/router devices that
+have an unconscionably short timeout for idle connections. There is
+usually enough intermud traffic that your conenction will receive a
+packet within five minutes, but if your timeout interval appears to +be
+shorter than that, you can tweak your intermud ping interval in
+Dead Souls 2.5a19 and above by typing: mudconfig +pinginterval +120
+

+ That will +shorten your intermud ping interval to 2 minutes,
+which should +keep most such aggressive timeouts from happening.
+It's probably not a good idea to lower your interval below 2 minutes,
+as your mud may wind up getting stuck in an i3 reconnect loop.
+

+Dead Souls muds below 2.5a19 may need to manually edit PING_INTERVAL
+in /secure/include/config.h or /secure/daemon/ping.c and reboot.
+
+

+I +heard +I can run my old TMI-2/Nightmare 3/Skylib/Lima code on Dead +Souls. Is that true?
+
+ Yes and no. +Please read this announcement for the details.
+
+
+
+Why +is +the version of Dead Souls 2 on Sourceforge different from the one on +dead-souls.net?
+
+ It's a +licensing thing. Sourceforge insists on only having Open Source
+stuff on +their site, so the version of Dead Souls you can download there is Open +Source.
+
+Strictly speaking it's "public domain". For more information on that
+version, see:
http://dead-souls.net/ds-II-faq.html
+
+If all +you're looking to do is run a mud, use the latest version from the
+Dead Souls site.
Mud admins don't +need to worry about licensing issues. Only
+those looking to distribute
or fork DS should +be concerned with the licensing.
+
+Short answer: If you don't care +what license you use, then you should
+use the most featured and most current stable version, which is:
http://dead-souls.net/code/dead_souls.zip
+

+
+Good heavens! +All I wanted to do was change combat, and it is so complicated!
+
+This is somewhat related to question 72, +"Will +changing XYZ be hard?". Some
+folks have super-specific ideas about how their mudlib should look, +and, for example,
+want nothing to do with magic, or limbs, or have a problem with combat, +etc.
+I think you'll find Dead Souls 2 can be molded into whatever you want.
+
+However, I would suggest the if you're going to be spending more than
+50% of your time ripping things out of this lib, it might be that this
+lib doesn't actually suit you. You might be happier with TMI-2,
+for example, or Lima, etc. You can choose from a number of
+libs from the LPMuds.net download page: http://lpmuds.net/downloads.html +
+
+If you're going to stick with DS2, though, then it's time for a +reassessment.
+You're looking to modify big, complex systems in a codebase that's not
+that familiar to you. The amazing thing is how far you've gotten
+in so short a time, that you're up for haxing at the combat system. But
+I'd like to make sure your expectations are set correctly: you are messing
+with complex systems fundamental to the operation of the mud. Of
+course it'll be hard, until you're at a higher level of proficiency.
+
+So yes, changing big things is big work. You might want to stop
+and think about whether this really is the lib for you, if you're
+spending most of your time pulling stuff out. Or you might want to
+slow down and work on modifying simpler objects and systems before
+starting to chew on player object inheritables.
+
+Just a thought.
+
+
+
Editing in +Windows is fine and call_out()'s are great. Your advice sucks!
+
+    Astute or adventurous readers may have noticed that +some of my
+statements on the faq are only true up to a point. For example, if you
+have a proper editor, and know what you're doing, there's nothing
+inherently wrong with editing an .o file.
+
+    Similarly, a call_out() here or there isn't wrong, +and in fact is
+the only way to do certain things elegantly (or at all).
+
+    The reason for the stern warnings is that these, and +other subjects,
+involve judgment calls that a novice is not in a position to make. Are
+you 100% sure that windows editor won't add dos formatting? Can you
+be certain that your call_out won't bring the mud to its knees?
+
+    Expert coders and admins can determine their risk +level based on
+experience. Until newcomers gain that experience, I try to dissuade
+them from risky behavior, because getting tripped up in the starting
+gate is no way to win a race.
+
+
+
I keep hearing +that Dead Souls can do this or that, but I'm trying and can't.
+
+    It may be that you downloaded the older, GPL version +of
+Dead Souls. The latest, +non-GPL +version may have the feature
+you're looking for.
+
+    When I refer to the latest version, I mean the latest
+stable release. Cutting-edge "alpha" versions can be downloaded,
+which include the absolute +latest +stuff I've been working on.
+It may be that the feature you're talking about is only available
+on the alpha version, and hasn't been included in a stable
+release yet.
+
+    You can download +the +alpha and run it, but you do so at your
+own risk. Alpha versions have that name for a reason: they aren't
+fully tested and are likely to have bugs.
+
+
+You appear to +have a FAQ for everything!
+
+    I'm not kidding when I call these FAQ's. These +questions
+really do get asked frequently.
+
+    When you start using Dead Souls, when you ask a +question
+on the DS line, you will more often than not get a FAQ url
+from me. This is normal, and is meant to encourage you to
+review the docs on your own.
+
+    If you find that most of your questions
+have FAQ's for answers, you should seriously consider changing
+the way you're going about things. When you're not sure
+about something, check the FAQ's first. That's what
+they're there for.
+
+    Eventually, if all your questions are answered by
+existing documentation, you might find that you get fewer
+and fewer responses from people, as they start tuning
+you out
. Remember that most people refer to the docs: 
+the help and +manual files, command help messages,
+as well as the admin, +creator, debugging, and general
+faqs. There's also the in-game player's handbook, creator's
+manual
, and admin guide, +as +well as web based examples
+and tutorials. There +is also a Dead Souls support forum
+which is searchable.
+
+    There is a ton of documentation for DS, and most +people
+consult it regularly. If you keep asking questions that
+are explicitly answered in docs, you may find yourself
+in the awkward position of not having anyone listening
+to you when you ask for something *not* documented.
+
+    This doesn't mean +"Don't bother us with your newbieness".
+
+    It means "First RTFM. If it's +not in there, ask like
+someone who has tried to find the answer, not like a lazy
+person who wants to be tutored
."
+
+    A very detailed explanation of the reason for this
+is at http://www.catb.org/~esr/faqs/smart-questions.html
+(NOTE: The people that run that +page have nothing to do
+with Dead Souls. Do not try to ask them Dead Souls questions).
+
+I strongly urge you to read that entire document. If you've
+never read it before, it will help you both on DS channels
+and pretty much anywhere else where experts are available
+for questions. I promise there will be benefit from
+reading it.
+
+
+If I XYZ, will +that work?
+
+Try it and see. One of the drawbacks to having exhaustive
+documentation is that folks can get the impression there's
+an example of every test case. As with any coding (programming)
+environment, you'll need to put in a lot of trial and
+error to learn. If it doesn't work, and it's not documented,
+go to the Dead Souls forum, +tell us what you did, where you
+looked, and what you expected.
+
+
+Hey you skipped +question 101!
+
+Yeah I goofed the numbers and now people are using #101 for
+something else. Oh well.
+
+
+You are not +taking my bug report very seriously.
+
+On the contrary. I am fanatically dedicated to making and keeping
+Dead Souls the very best LP lib out there. As you spend more time
+getting acquainted with the DS community and how things work,
+you will see that I am deadly serious about bugs and they
+usually get addressed quickly, if they prevent functionality.
+At a minimum, legitimate bugs end up on my .plan.
+
+I know DS2 has bugs. I'm not under the illusion it's perfect,
+or that I'm a +coding god.
+
+However, I *do* get a lot of reports, and I have to prioritize
+them. DS2 doesn't put food on the table for my family,
+or keep the rain off our heads, so you'll need to keep in mind
+that, as special and wonderful a person as you are, your
+coding confusion is sadly not my personal emergency.
+
+Whether it's a critical security flaw or a typo in a
+file's header, I can promise you I *will* address your problem,
+unless another member of the community gets to it first. You
+may have to just be patient.
+
+Another reason you may feel I'm not addressing your problem
+is that you may not actually have a problem. Specifically,
+if you are a new admin, and something doesn't work the way
+you think it should, I advise you not to immediately
+regard it as a bug. It may well *be* a bug, but assuming it
+is so is not helpful. Consider the following scenarios:
+
+Scenario 1a:
+Noobulator@LeetFooMUD <ds> BUG!! I can't see what's in my toy +chest!!1!
+Cratylus@Dead Souls Demo <ds> k. thx.
+
+Scenario 1b:
+
Noobulator@LeetFooMUD +<ds> +I type "l chest" but I can't see what's in there.
+
Cratylus@Dead +Souls +Demo <ds> try: look in chest
+
+Another common source of "bug reports" is what can charitably
+be called operator error. For example:
+
+Scenario 2:
+
Noobulator@LeetFooMUD +<ds> +lol the schoolhouse is broken lol
+
Cratylus@Dead +Souls +Demo <ds> works for me
+
Noobulator@LeetFooMUD +<ds> +well, it's bugged. I get a million errors when I enter
+
Cratylus@Dead +Souls +Demo <ds> i can't reproduce the problem on my test muds.
+
+Ususally in such a scenario, it turns out that the person
+was *sure* they didn't change anything...and later remember
+they just took out this one line they didn't like from the
+code. Or perhaps they removed the "dwarf" race, and so the
+schoolhouse can't load because it has a dwarf npc in it. Or
+maybe they....etc etc etc.
+
+If you report a bug, and you get something like this from me:
+
+"I can't reproduce your problem."
+

+It means I tried to get the same results, and couldn't.
+You can interpret that as meaning that you've either
+caused the problem yourself, or haven't given me
+enough information to be able to test what you're
+talking about.
+

+If you don't elaborate further, and you don't post your code and
+error messages on the forum, then I'll assume you're going
+to track down your coding mistake on your own.
+
+This doesn't mean I don't like you, or that I think you're
+a loser, or that I don't care about bugs. It means I can't do
+anything useful with the information you've given me. If
+you can provide me with enough information so that I
+can reproduce your problem, then I can work on fixing it.
+Otherwise, what can I do?
+
+I would also ask you to be as open-minded as you would
+like me to be. It isn't easy for me to be nice and polite...
+I've actually a rather abrasive personality by default. If
+I don't know you and I'm being polite to you, the chances are
+that I'm really making an effort. The chances that you're
+asking me something I've never heard, or reporting something
+I'm unaware of, are small, if you are a new admin. If my
+response is not to your liking (for example "check the Creator FAQ",
+or "read the Player's Handbook"), getting hostile and defensive
+with me won't help anything. Given how long I've been working
+on this code, it's very likely that I've given you
+extremely good advice, out of a genuine desire to have you succeed.
+If you react in an adversarial manner, you may wind up
+missing the technical usefulness of what I've said, and
+discourage me from responding promptly to you in the future.
+
+And if it happens that I *am* wrong, which occurs frequently
+enough, then simply following my instructions and explaining to
+me how they didn't work is a perfect way of showing me my mistake.
+
+
+Dude. Just +answer my question. It's just one question, ffs.
+
+If there's one thing that fills me with dread it's the
+prospect of having to RTFM for software I'm totally clueless
+about. Technical people often are terrible docwriters, and it
+can be a real challenge to tease out the information you need.
+
+In fact, sometimes it's necessary to understand what's in a
+manual before you can read it, because of the level of complexity.
+
+So I sympathize with you. Looking at a pile of documentation
+99% of which you don't understand is daunting, and I truly
+appreciate that fact, because I've been there.
+
+So I totally grok when you say "Look, please just tell me how
+to eventNarfle the garthak(). Ok?" I feel it, man. I get you.
+
+What I want you to understand is that when I tell you to RTFM,
+I'm *not* giving you the brush-off because I like it. I'm
+doing it because to you it's one little question. To me, it's
+Creator FAQ #X, which I've answered 24 times before, and for
+which I sat down and wrote out an excruciatingly detailed
+explanation.
+
+Take a look at this FAQ, and the others. There are literally
+hundreds of entries, all of them written by me, in a way as
+clear as I could make it. Take a look at the dozens of chapters
+in the Admin Guide, Player's Handbook, and Creator's Manual.
+That stuff didn't write itself.
+
+I didn't go through the laborious process of all that doc
+work so that I could then do it over again every time someone
+doesn't feel like doing a text search on the FAQ for eventNarfle.
+
+I'm not saying I'm too good to waste my time on you. I'm saying
+I *HAVE* spent the time, I *did* make the effort, and I need
+you to make just a little effort of your own as well.
+
+
+Is it possible +to upgrade to alpha without killing everything I've done?
+
+Probably.
+
+I have been asked whether people can upgrade from the stable
+release to the alpha release, and my answer usually is something
+along those lines. "I imagine so."
+
+And if asked how, I'll typically say something like "very carefully."
+
+The reason is that I do not encourage people to "upgrade" to
+an alpha version. Alpha is by definition a rough draft, lightly
+tested in new functionality, and unstable in the sense that
+new alphas come out often.
+
+I do not put out alpha patches, and I do not make it easy to move
+from a stable release to an alpha release. This is because if I
+did make it easy, most people would do it, even beginners. This
+would be problematic, because if they then run into an alpha bug,
+they have to hear this from me:
+
+"Well, yeah. Alpha has some bugs. I'll get to that one eventually."
+
+And then people would get all gripey, or push me to fix it,
+etc, and I wouldn't like that. The point of the stable release
+is that it's stable. The point of alpha is that it's a testing
+version of new stuff. If you want to go alpha, that's fine with
+me, but you'll need to be experienced enough to do it on your own.
+
+I actually do want people to run alpha so that I can get
+bugreports. But I don't want people running their main production
+muds in alpha, because I will not be making commitments about
+when bugfixes happen. I also don't want total newbies using
+alpha, because I don't want to set them up for disappointment
+when I don't treat their bugreport with extreme dispatch.
+
+So yes...it's a bit elitist of me, but for good reason. If you're
+unsure about being able to safely upgrade to alpha from your
+stable release...then don't.
+
+If you do it and screw up, restore from backup. You did back up
+first, right?
+
+
+
How do I start +an area?
+
+In Dead Souls, a set of related objects, creatures, and rooms that
+add up to the creative vision of a builder is called a "domain".
+It's the same thing as what other codebases refer to as an "area".
+The terms are used interchangeably in the DS community.
+
+Dead Souls domains are comprised of a bunch of LPC files that live
+in a specific directory. If the domain is to be called UlTiMaTe DBZ +PWNAGE
+then that directory (aka "folder") might be called /domains/dragonballz +.
+
+To create that domain, you can use the domaincreate +command, like so:
+
+domaincreate dragonballz
+
+This will generate some standard directories and a start room for
+the domain. At that point you can assign a domain admin with the
+domainadmin command. For more info:
+
+help domaincreate
+help domainadmin
+
+
+I don't want to +use a cookie-cutter codebase
+
+So, this one time, these guys were checking out Dead Souls, and
+one of them was seriously evaluating it, and his buddy was basically
+coming up with reasons why some other lib was better...no matter
+what. For example, the doubter guy was like "feh we don't want
+a medieval mud", to which I replied "check out the firearms
+code", and the reply was "lol, we have our own". You know, a
+total no win sort of deal.
+
+And then the doubter guy said something that got me thinking.
+Among his objections was one that I didn't quite understand.
+
+"We don't want a cookie-cutter lib," he said.
+
+Now, the lib he was advocating was no more or less cookie cutter
+than DS, in my opinion, so it's not like I was dazzled by the
+argument, so much as I was confused by the premise. Just what
+the heck does "cookie cutter" mean?
+
+Cookie cutter as a +bad thing:
+
+I think what people sometimes mean is that they don't want a mud
+that looks like every other mud. Why bother logging into
+LeetDikuHeavilyModifiedMud When DikuHighlyLeetCustomizedMud is
+exactly the same, except the race and skill names are different?
+
+Similarly, there are a few dozen new Dead Souls muds out there.
+They all mostly look the same...why not choose something that
+isn't like Everyone Else?
+
+Cookie cutter as a +good thing:
+
+I would suggest that there are some things for which "cookie
+cutter" as a pejorative term is of limited impact. For example,
+operating systems and air conditioners. There are things that,
+when acquired, aren't acquired for their uniqueness. They are
+acquired for their suitability to a specific application.
+
+In this sense, cookie cutter basically means widely adopted, and
+from the standpoint of someone just trying to get a specific job
+done, it is an advantage that there is wide adoption of what
+you're working on.
+
+Where Dead Souls +fits in:
+
+* A codebase distribution is, necessarily, cookie cutter. It's
+a set of frameworks, presumably standardized during development,
+that are the same for everyone when they first get it. From
+this perspective, anything that you didn't 100% code yourself is
+cookie cutter when you download it.
+
+* If you download a codebase and then just run it with no modifications,
+then the problem in "originality" isn't the codebase, it's you.
+
+* Dead Souls includes a large (perhaps overlarge) amount of
+rooms, creatures, objects, armor, and weapons in the stock distribution.
+When you download and run it, you basically have a working mud with
+quests and pubs and whatnot.
+
+YOU ARE NOT SUPPOSED TO USE +THAT STUFF AS YOUR MUD
+
+Those are examples. They are sample areas. If your mud uses the sample
+areas, they should be one or more of the following
+
+A) Temporary, while you're learning the lib
+B) A joke
+C) Not the areas new players see
+
+If you make no changes to the sample areas and present them to new
+players as a mud, then yes, you have a cookie cutter mud, and you
+really might as well just shut down, because only your friends will
+log on to play, and not for very long.
+
+I think that the problem is that people see this large amount of
+example material and think that they have to use it in their mud. If it +
+were so, then that would be sad and would doom every Dead Souls mud to +be
+exactly like every other.
+
+Instead, your mud can have a Roman Empire theme, with no hint of
+the stock areas in sight when a player logs in. Just the robe and
+sandals they wear and the classical city they must explore. That's
+actually been done, by a mud called, aptly enough, Ancient Rome.
+
+Nothing prevents you from having your new players launched into
+space the moment they log in, or find themselves suiting up for
+a dive into Kaminoan oceans. It's a mud *codebase*, not a mud.
+
+Make it your own.
+
+
+How do I make +my new area the default domain where new people to arrive?
+
+1) +In your new domain, make +sure that the room/ directory contains (working) rooms
+with the following names:
+
+void.c
+death.c
+freezer.c
+furnace.c
+pod.c
+wiz_hall.c
+start.c
+
+See the rooms in /domains/default/room to see what these rooms do and +how they work.
+The domaincreate command generates these rooms by default.
+
+
2) Use the mudconfig command with +the defaultdomain subcommand. If your new
+default domain is
/domains/dragonballz, +you +would type:
+
+mudconfig defaultdomain
/domains/dragonballz
+
+3) reboot (In theory you can do +this without rebooting, but the instructions would be longer)
+
+
+I heard passive +mode on the FTP server works now
+
+As of the current stable version, passive mode FTP works now.
+There are some very important things to keep in mind.
+
+1) Dead Souls now comes with +two ftp servers. The original
+is known to the inet system as ftp. The new, passive-mode
+server is known to the inet system as hftp. To enable hftp,
+run the following mudconfig commands:
+
+mudconfig inet enable
+
+mudconfig hftp enable
+
+2) The default port for the +hftp server is 6 less than your
+mud's telnet port. So if your mud runs on port 6666, then
+the hftp server will be on port 6660. This can be changed
+by editing /secure/include/network.h
+
+3) The mud must know its +correct external ip address. You
+must set this in the config.h file, preferably with the mudconfig
+command, like so:
+
+mudconfig hostip 111.222.333.444
+
+Where "111.222.333.444" would be the actual ip address that
+the external machines will be trying to connect to. If
+you do not know what this address is, leave the default
+of "127.0.0.1" in the config file. This will let the ftp server
+know it needs to try to figure out the address based on information
+it gets from the intermud router.
+
+If it cannot gather this information, or you don't specify
+a valid external ip address, then the passive-mode
+ftp server will not be able to handle incoming connections
+properly.
+
+4) Passive ftp support requires +the use of an additional
+range of ports. The default range of ports reserved by hftp
+starts at -65 from your mud port, to -11 from your mud port.
+This means that if your mud is running on port 6666, then
+ports 6601 to 6655 are reserved for your passive mode transactions.
+If there is a port conflict with another program, you'll
+have problems. You can change the port range by editing
+/secure/include/network.h
+
+5) Once it's been correctly +configured and started, you
+should be able to use passive mode for ftp transfers
+even if your ftp client computer is behind a firewall.
+
+If the mud computer itself is behind a firewall, you will
+need to make sure that the range of ports discussed
+in the above section are being properly forwarded to
+the mud computer. If the mud is behind a router, for
+example, you may need to configure that router to
+forward ports 6601 to 6655 to the mud computer.
+
+6) If all has gone well, then +you can ftp to the mud's
+hftp port, begin a passive session, and while away
+the hours uploading and downloading to your heart's
+content. On a command line ftp client, that might look
+something like this:
+
+myhost: /tmp/foo $ ls -l
+total 32
+drwxr-xr-x   2 myuser     +other        117 Dec 26 18:34 ./
+drwxrwxrwt   7 myuser     +sys         1361 Dec 26 18:33 +../
+myhost: /tmp/foo $ ftp mymud.com 6660
+Connected to mymud.com.
+220- Dead Souls FTP server ready.
+220-                          +FTPD +news
+220-                          +/news/ftpd
+220-
+220 Please login with your creator name or anonymous.
+Name (mymud.com:myuser): myguy
+331 Password required for myguy.
+Password:
+230 User myguy logged in.
+Remote system type is UNIX.
+ftp> passive
+Passive mode on.
+ftp> bin
+200 Type set to I.
+ftp> dir
+227 Entering Passive Mode (1,2,3,4,30,32)
+150 Opening ASCII mode data connection for file list.
+drwxrwxr-x   1  dead_sou +dead_sou       0 Dec 26 18:33 .
+drwxrwxr-x   1  dead_sou +dead_sou       0 Dec 26 18:33 ..
+-rw-rw-r--   1  dead_sou +dead_sou      28 Dec 26 18:33 .plan
+-rw-rw-r--   1  dead_sou +dead_sou      21 Dec 26 18:33 .profile
+drwxrwxr-x   1  dead_sou +dead_sou       0 Dec 26 18:33 adm
+drwxrwxr-x   1  dead_sou +dead_sou       0 Dec 26 18:33 area
+drwxrwxr-x   1  dead_sou +dead_sou       0 Dec 26 18:33 bak
+drwxrwxr-x   1  dead_sou +dead_sou       0 Dec 26 18:33 cmds
+-rw-rw-r--   1  dead_sou +dead_sou     361 Dec 26 18:33 customdefs.h
+drwxrwxr-x   1  dead_sou +dead_sou       0 Dec 26 18:33 log
+drwxrwxr-x   1  dead_sou +dead_sou       0 Dec 26 18:33 tmp
+-rw-rw-r--   1  dead_sou dead_sou    3087 +Dec 26 18:33 workroom.bak
+-rw-rw-r--   1  dead_sou dead_sou    3087 +Dec 26 18:33 workroom.c
+226 Transfer complete.
+811 bytes received in 0.0097 seconds (81.68 Kbytes/s)
+ftp> get workroom.c
+227 Entering Passive Mode (1,2,3,4,30,32)
+150 Opening binary mode data connection for /realms/myguy/workroom.c +(3087 bytes).
+226 Transfer complete.
+local: workroom.c remote: workroom.c
+3087 bytes received in 0.031 seconds (96.91 Kbytes/s)
+ftp> bye
+221 Goodbye.
+myhost: /tmp/foo $ ls -l
+total 48
+drwxr-xr-x   2 myuser     +other        184 Dec 26 18:35 ./
+drwxrwxrwt   7 myuser     +sys         1361 Dec 26 18:33 +../
+-rw-r--r--   1 myuser     +other       3087 Dec 26 18:35 workroom.c

+
+The sharp-eyed among you will no doubt have noticed that
+binary mode ("bin") is being used. This is because ASCII
+mode transfers don't work too reliably, and fail more
+often than not.
+

+7) hftp has NOT been tested for +security or reliability.
+If it doesn't work, you're free to let me know, but do
+not expect me to fix it. If someone hacks into your mud using
+rcp, http, ftp, or hftp, and ruins your life, this is not
+my problem. These servers are provided to you as a convenience,
+not as standards-compliant, production-quality internet
+software. Proceed with extreme care and make regular backups
+a top priority. If in doubt, do the following:
+
+mudconfig inet disable
+

+8) If you find hftp helpful and +useful, please thank Duuk @ Haven
+for being kind enough to let me filch it from his mud, Haven.
+If you *don't* like it, please withhold comment until you have
+a patch to submit to fix a shortcoming.
+
+9) Known issues:
+
+* If you see this:
"netin: Connection +reset by peer" it means
+you're trying to use ASCII mode. Remember to use binary mode.
+
+* Anonymous FTP doesn't work yet.
+
+BIG GIANT NOTE ON HFTP AND PASSIVE MODE
+It is apparently now common for FTP clients to default to EPSV when
+negotiating passive mode. This breaks hftp and just will not work.
+If you keep getting errors like
+
+wrong server: return code must be 229
+
+Or mysterious references to "epsv", this means that your ftp
+client is one of these that makes this assumption. Disable epsv
+right after logging into hftp to prevent this. For example:
+
+
epsv +off
+passive on
+bin

+
+
+
+I boot the mud +but nothing happens...the startup headers
+come up +but nothing preloads and I get no error messages. What's
+going on?
+
+This can happen if your internet connection goes down, and
+you're using name resolution. For example, if you are trying to
+use 1.2.3.4 7777 as your address server, and your network
+connection goes down so that you can't reach 1.2.3.4, then
+if you try to reboot, the driver will hang at that point in
+its startup configuration, waiting for 1.2.3.4 to become
+available.
+
+Simply change that entry in mudos.cfg to something like
+localhost or 127.0.0.1 and you should be able to boot again.
+
+
+How do I add a default alias?
+
+Add it to the Aliases array in /lib/nmsh.c
+
+
+How do reset() and clean_up() work?
+
+LPmuds come from a tradition of trying to be as conservative with
+computer memory as possible. Back when a server with 128 megabytes
+of RAM was worth killing for, people often had to make do with
+scant memory resources. Objects needed to be be either swapped to
+disk, or unloaded from memory entirely, if they weren't really needed.
+
+The clean_up() apply was meant to address this. The driver
+periodically calls clean_up() on every object. Typically, the
+clean_up() function coded into a given object contains instructions
+such as "if you're not in a player's inventory and you're just
+lying around, then destruct yourself", that sort of thing. In
+Dead Souls, clean_up() is a function in LIB_CLEAN, which is
+inherited by most objects.
+
+Some objects should never be unloaded from memory, like daemons,
+and some special objects. Such things should have SetNoClean(1)
+specified in their create() function, so that the clean_up()
+apply doesn't try to destroy them.
+
+Tangible objects (shoes, swords) that are SetNoClean(1) will
+prevent the object they are in (NPC or room) from doing a clean_up().
+
+reset() is another "driver apply", or function that is called by
+the driver. Like clean_up(), reset() is called periodically, but
+it is intended not to be a trigger for auto-destruction, so much
+as a set of instructions to make an object presentable to
+players again.
+
+For example, if Joe Player completes the Orcslayer quest by
+killing a bunch of orcs, then when Jane Player wants to do the
+quest, she's just going to find a bunch of dead orcs. However,
+when reset() gets called on the room, then the inventory can
+reload, so that Jane gets a crack at those orcs as well.
+
+Like clean_up(), reset() is not generally meant to be put in
+run of the mill objects. By default, rooms inherit reset()
+from LIB_ROOM, and it serves the purpose of reloading the
+inventory the room is supposed to have.
+
+
+When do reset() +and clean_up() happen?
+
+The way MudOS works, the driver calls reset() and clean_up()
+on objects based on the interval specified in the runtime
+configuration file.
+
+That means that if mudos.cfg
has a "time to +reset" of
+3600, your reset interval is 1 hour. Orcs will repopulate the
+cave every hour at that rate (assuming they've been killed).
+
+Similarly, "time to clean up" specifies the driver's
+interval between clean_up()'s.
+
+While this is a valid scheme, Dead Souls doesn't rely
+on it. Dead Souls uses the TIME_TO_RESET variable in
+/secure/include/config.h to determine the reset() and
+clean_up() interval. If TIME_TO_RESET is 14400, then the
+master daemon (MASTER_D) will run eventReset() every four
+hours. eventReset() is a function that seeks out objects and
+calls reset() and clean_up() on them.
+
+Note that this may cause set_reset() to behave in a way you don't
+expect, and it means you'll get reset()'s in your mud even if
+you compile the driver not to do so.
+
+Therefore, it's a good idea to set your "time to clean up"
+and
"time +to +reset" in mudos.cfg to something very large
+(like 2000000000, aka 63 years) so that you don't have
+two separate systems doing reset()'s and clean_up()'s.
+
+In Dead Souls 2.4.1 and below, MASTER_D calls reset() and
+clean_up() on 25% of loaded objects at a time, to avoid
+lag on busy muds. 2.5a1 and above can choose to have these
+fuctions called on all loaded objects with the RESET_ALL
+definition in /secure/include/config.h
+
+
+I want a 100% PK mud. Setting rooms PK one by one is +not acceptable.
+
+Setting your DS mud to be 100% PK (pplayer killing) is not that +convenient
+by default, I agree. The reason for this is that from what I've seen,
+unrestricted PK is a great way to ruin a mud, and it should not be
+something you can enable accidentally.
+
+Having said that, this is the procedure you would follow to make
+a Dead Souls mud 100% unrestricted PK.
+
+1) Run the command: mudconfig pk yes
+2) Edit /lib/std/room.c. Change
+
+private static +int      PlayerKill    = 0;
+
+to
+
+private static +int      PlayerKill    = 1;
+
+3) Edit /lib/living.c. Change
+
+    +isPK += 0;
+
+to
+
+    +isPK += 1;
+
+4) Reboot
+
+5) Players created before this change may still need to use the pk command
+to enable player killing for themselves.
+
+

+How do I make a new skill?
+
+What people usually mean by this is Diku style "skills", which are
+more like special commands or spells than Dead Souls skills. In
+Dead Souls, a "skill" is a property of a living thing that allows it
+to be proficient to some specified level at a kind of activity. For
+example, to be able to cast a defensive spell like buffer, you
+may need a particular level of proficiency at the skill of "magic +defense".
+
+That kind of skill isn't "created" in the standard sense. That kind
+of skill is added to a player or NPC programmatically, usually when
+their character is created, or they advance levels, or join a class.
+
+For more information on that kind of skill, please read Section IV
+of Chapter 8 of the Admin +Guide.
+
+In order to make the Diku-style "skill", all you really need to
+do is write a new command. For example, take a look at /cmds/players/flee.c
+
+That's what a Dead Souls command looks like. Pretty straightforward,
+but you'll need to become a little familiar with LPC to make your
+own. Read the Creator's +Manual to become familiar with LPC, then
+play around with making a command of your own by copying flee.c to
+bash.c or whatever, and tinkering with the code.
+
+There's no "quick" way to making a new skill of this kind. This is the
+point where you decide whether to invest the time in learning enough
+LPC to get your vision implemented in earnest.
+
+For the advanced coders, I would suggest creating a new verb, rather
+than a new command. Verbs are far more powerful and sophisticated than
+commands and are suited for just this kind of purpose. However, they
+require intermediate-to-advanced LPC coding skills, so if you are
+new to LPC, please do not try verbs yet.
+
+
+Why was +Descartes so lame?
+
+People have really got the wrong idea here. There are two main +complaints
+against the original author of the Dead Souls lib:
+
+"Descartes was a mean jerk."
+
+and
+
+"Descartes was an incompetent coder and/or docwriter."
+
+My first response is that even if these things were true, it doesn't matter.
+
+Whether Descartes was personally hurtful to you once is totally
+irrelevant to your mud. He has left the mudding community and
+will not hurt you again. Further, Dead Souls 2 was built from
+public domain code, meaning he can never ever revoke your right
+to use Dead Souls. By nursing your old resentments against Descartes,
+you are only casting yourself in a bad light, by seeming petty
+and self-involved.
+
+As to his supposed programming competence, this also is entirely +irrelevant
+to you. I can tell you that as the current maintainer of DS, I am
+intimately familiar with his code and am in an excellent position
+to sit here and bitch about it. The main reason I don't is that:
+
+1) I am eternally grateful he wrote it in the first place.
+2) Given the TENS OF THOUSANDS of lines of good code he's written, a +few
+   stumbles aren't worth getting smarmy about.
+3) Whether the code was written by him, one of his people, or dictated
+   to the lib directly from the mouth of Satan in the pits of +hell, in the end, the
+   original author is not the problem. If the code doesn't do +what you want, there
+   is really no point at all in grousing about it. Either fix +it, ask for help, or
+   get a new lib. If you're an admin it's because you're a +can-do type,
+   and willing to DIY where necessary. If not, blaming and +complaining aren't
+   the answer. Meditation and introspection are. As in, you +should be asking
+   yourself if running a mud is what you should be doing.
+
+Ok, now that I got the ranting out of my system, let's address the +specific accusations:
+
+
"Descartes +was +a mean jerk."
+
+    Yeah, sort of. It really depended on how you +approached him. Really,
+as far as I could tell, he was a normal person with a somewhat low
+threshold for having his buttons pushed. And people enjoyed pushing
+his buttons. A lot. And this lowered his threshold for it. Rinse, +repeat.
+
+    As a result, if you were to publicly approach him in +a way that
+he identified as making you likely to be a button pusher, he'd tend to
+handle you as such. You were less likely to get bile on you if you
+approached him privately, but then, you might just get ignored as
+Yet Another Loser wanting her hand held rather than just putting in
+the work learning how to build her mud.
+
+    On occasion he'd also just be generally irritable, +combative, and argumentative.
+In short, he was a normal person. I have personally been involved in
+plenty of flaming back and forth with Descartes...quite thoroughly +hostile
+and ill-spirited. I doubt either one of us took it personally. This sort
+of behavior was kind of the norm on intermud at the time. If you took it
+personally, really, that's your problem, not his.
+
+    And remember, we're talking about Descartes "in +character". Whenever
+I've communicated with George Reese out of his Descartes character, +he's been
+nothing but polite, courteous, and personable. Don't mistake the player
+for the character.
+
+
"Descartes +was +an incompetent coder and/or docwriter."
+
+    This one bugs me. The main reason is that I don't +think the people
+who say these things are in a position to judge. I think that something +like
+99% of his code is just dandy. It's useful and effective. And most of
+it is quite efficient: remember that Dead Souls was developed on very
+weak machines and was the basis for a very busy mud. It was vital that
+things run efficiently and load economically. 
+
+    That his code contains some weaknesses is beyond +dispute. If I were
+to criticize something about his code, though, it wouldn't be that it is
+shoddy or ill-conceived. Where I run into something that makes me spit,
+usually it's obvious that he meant to finish a thing, and just didn't
+get to it. If you run into something that tempts you to say "bah,
+more DescartesLogic", step back and take a deep breath. The chances are
+that you're really not grasping that bigger picture of the code you're
+examining.
+
+    On the other hand, yes, some objects really seem to +have been handled
+carelessly. I believe I lost a few months off my life from the +aggravation
+of trying to fix various issues in armor. This does not mean Descartes
+was an incompetent coder. It means that, like normal people who work on
+a hobby that does not feed, clothe, or house them, Descartes on occasion
+slapped something together to just get it working and do what he needed +quickly.
+
+    Is that something anyone is not guilty of?
+
+    As to weak docs, remember that his Basic and +Intermediate LPC texts
+are of biblical significance in the history of Dead Souls. They are, +though
+imperfect, a bedrock of documentation that is massive in size and
+greatly detailed. This is in addition to the material in /doc/build. If
+those docs seem inadequate to you, then you simply cannot be pleased.
+
+    In the end, keep this in mind. George Reese is a +professional developer,
+who runs a software business. He is also a professional docwriter, +having
+published technical books that people have paid real money to buy. +Unless
+you have comparable credentials, and/or have published a mudlib yourself
+which thousands of people have used, then you might want to reconsider
+complaining about Descartes and his competence in these areas.
+
+
+The mud is +locked whats the command to add someone to the allow list?
+
+groupmod -a test playername
+
+Note that this tags the player as a test char and
+gives her access to normally restricted areas. For
+details on what groups grant what access, see the
+FAQ entry: http://dead-souls.net/ds-admin-faq.html#84
+   
+
+Shouldn't you change all the documentation to reflect +the move to FluffOS?
+
+No. See this faq entry: http://dead-souls.net/ds-faq.html#driver
+
+Referring to the driver as MudOS is imprecise for the reader if
+she is currently running FluffOS, but it is not altogether
+incorrect and her potential confusion so minimal that I do not
+see a need to rephrase each instance of "MudOS" into "the driver you +are
+using, which may be MudOS for older releases, and FluffOS for newer +ones,
+although FluffOS is a derivative of MudOS and functionally
+indistiguishable at runtime except if you use its extended features,
+in which case you should not be confused anyway".
+
+Where appropriate and convenient, I do from time to time change the
+docs to reflect the migration, but it's not going to be a to-do list +item.
+
+
+How do I change my timezone?
+
+Use the command: admintool
+
+Select option: c
+
+
+So I herd u liek mudkip
+
+You herd right.
+
+
+Where is all the player information stored?
+
+If you mean "where is each player's information stored?",
+the answer is "in their playerfile." In my case, it's
+/secure/save/creators/c/cratylus.o , for a non-creator,
+it might be something like /secure/save/players/t/testguy.o .
+
+Note that .o files +should never be edited.
+
+If you mean "where is the information for all players?",
+then there isn't really any such thing. The best answer to that
+is /secure/save/creators and /secure/save/players, because
+that's where the save files live.
+
+
+The addrace command complains that the race already +exists.
+
+A very common error is to copy an old race file to
+a new name, and try to add it just like that. The
+problem is that the new file contains inside it a
+race name that is already known to the races daemon.
+
+Edit the new file and change the race name in it to
+reflect the name of the new race, and try again.

+
+
+I am confused about the player/creator distinction.
+
+The way it was explained to me is that "imms" on
+Diku-derivative muds are basically "superplayers"...
+that is, powerful and high-level, but not set apart
+from players as fundamentally as is the case on DS.
+
+For example, someone once was shocked to discover
+that I'd never bothered to test lead/follow code
+on creators. My response was something along the lines
+of "I guess I just never figured they'd have much
+use for it," which was even more horrifying.
+
+The thing to realize is that creators are not players
+at all. They cannot be, because +their powers are
+so vast as to subvert any concept of fair play.
+A creator can kill any monster instantly with the
+zap command. She can read the code for a quest and
+complete it with no effort by just cloning the
+desired object, or even just evaluating the proper
+function call to achieve the desired effect. She
+doesn't have to "follow" anyone, she can just instantly
+teleport herself to the intended location.
+
+In fact, on the original Dead Souls 1.1 codebase,
+creators technically didn't even have bodies. They
+were just kind of amorphous entities floating around
+the game...but boy, people hated +that. They wanted
+to wield and wear things, and do other stuff that
+players can do. And so today you can see creators
+strolling about as if they share the same mortal
+limitations players do, but do not be fooled.
+
+Creators are not players. They are godlike beings
+walking among players, able to manipulate the essence
+of their world. Therefore, please expect that lots of
+things simply don't apply to them.
+
+
+How do I prevent people from using channels?
+
+By default, only creators have intermud channel access.
+New players can't use intermud, unless a creator adds
+an intermud channel to them (for example, call joe->AddChannel("dchat") ).
+
+If you want to have more strict control on who can use
+intermud channels, use the mudconfig command to
+restrict intermud:
+
+mudconfig intermud restrict
+
+Once you do that, only people in the INTERMUD group in
+/secure/cfg/groups.cfg can use intermud channels,
+regardless of what channel has been added to them.
+To add someone to the INTERMUD group:
+
+groupmod -a intermud joe
+
+to remove them:
+
+groupmod -r intermud joe
+
+Warning: use great care with the groupmod command.
+
+
+How do i disable the rss bot, or other channels?
+
+By default, creators have some standard channels
+added to them upon their promotion to creator status.
+You can see which channels they are by reading
+/secure/cmds/admins/encre.c and looking for a line similar to this:
+
+
cre_ob->AddChannel(({"cre", +"newbie", +"gossip", "ds", "ds_test", "lpuni", "death", +"connections","intercre","dchat","inews" }));
+
+Modify that line to remove channels that you
+feel new creators do not need, then type:
+
+update
/secure/cmds/admins/encre.c
+
+And people you promote to creator after that won't have
+the channels you removed from that line.
+
+To simply turn off a channel you dislike yourself,
+just type the channel name alone at the command prompt, like:
+
+inews
+
+
+I made a verb but it doesn't work
+
+Please refer to the verb +tutorial, and
+really read the whole thing through. Note that
+the most common error is failing to add the
+appropriate direct_/indirect_ +applies to the
+target object.
+
+
+Does Dead Souls support databases like MYSQL?
+
+Short answer: Not really.
+
+More correct answer: Sort of. FluffOS/MudOS, the driver
+that DS uses as its "engine", has some support for
+databases built in. However, enabling it requires
+recompiling the driver with the proper config options,
+and if you manage to do this correctly by some
+great feat of luck, you'll have a driver that supports
+MYSQL features from back in 2000 or before.
+
+That is to say, relying on the driver's support for
+DB is chancy, and success doesn't mean you actually
+succeed in doing anything useful.
+
+These days, when people want to use a FluffOS/MudOS
+lib like Dead Souls in conjunction with a database,
+the most common and successful approach is to use
+an intermediary script, like perl or python. You
+code a lib object that uses MudOS sockets or
+external_start() to talk to your script/program, and the
+script/program then does the heavy lifting of correctly
+communicating with the database.
+
+There's no DS lib object currently in the release
+that handles this sort of stuff. If you want DB support,
+you'll pretty much have to DIY. The good news is that
+it's certainly doable...folks have done it in the past.
+The bad news is you'll really have to know what you're
+doing for it to work.
+
+
+How do I make my new currency work?
+
+Presumably you've already used admintool options 2
+and j to add a new currency and are now wondering
+what to do to put it in the game.
+
+Currency isn't like a normal "object". When you
+pick up a pile of coins, for example, that pile
+was only a kind of placeholder object. Once you get
+it, it vanishes, and the weight and value it had
+are added to you, without there being a specific
+"money object" you're carrying. When you drop
+money, a pile is created to hold that value, but
+again, when someone picks it up, it goes away.
+
+So, now that there are Quatloos in your game, how
+do you get your hands on some?
+
+As a creator, it couldn't be simpler. Just type:
+
+call me->AddCurrency("quatloos",500)
+
+But I'm guessing what you're really wanting is
+to make Quatloos the standard legal tender for
+your mud. In that case, you'll want your vendors,
+bank tellers, and barkeeps to use that as their
+default currency.
+
+Tanke a look at how this is specified in the following
+commercial NPC's, and modify your own accordingly:
+
+/domains/town/npc/otik.c
+/domains/town/npc/lars.c
+/domains/town/npc/zoe.c
+
+
+My friends can't connect to my mud, but I can!
+
+The most common scenario here is that you are running
+your mud at home, and you are able to telnet to it
+with no problem because you are local to the mud.
+
+However, these days there are usually a couple of
+layers of security between your PC and the internet.
+Chances are that your internet connection is through
+a "router" or "firewall" device. Find the physical
+device that your computer's network port is connected
+to. Examine it to determine its manufacturer name and
+the device's model number.
+
+Now go on Google and do a search for it, for example:
+
++linksys +pos2000 +user +manual
+
+Keep varying the search terms until you find the
+documentation for your device. Then download it and
+read it. It should describe how to log into the
+device and configure its firewalling to allow incoming
+connections to be forwarded to the computer that is
+running the mud.
+
+You'll probably need to know the IP address of the
+mud computer. If it is running windows, open a command
+window and type:
+
+ipconfig /all
+
+(protip: 127.0.0.1 is not the correct IP to forward to)
+
+If you're running UNIX/Linux, try: ifconfig +-a
+
+
Using the documentation for your device, and the networking
+information from the computer, configure your device to
+forward incoming connections to whatever port your
+mud is running (typically port 6666).
+
+If that *still* doesn't work, you may be running a
+software firewall on the mud computer that rejects incoming
+connections. Temprarily disable the computer's firewall and
+see if your friends are then able to connect. If so,
+then you know you need to figure out how to configure your
+software firewall to allow connections on the mud port.
+
+If you can't figure it out, use Google to download
+documentation on your firewall software.
+
+
+My efun override is not working
+
+Put it in /secure/sefun/sefun.c
+
+
+
How do I remove +the QCS?
+
+Amadeus <cre> yo cratylus
+Amadeus <cre> how do i +remove the QCS on my copy of DS?
+Amadeus <cre> I want to 100% +remove it without hurting anything else.
+Cratylus <cre> why not simply avoid using it?
+Amadeus <cre> because its +too tempting for my creators and I want them to learn to code.
+Amadeus <cre> I want to know +where all it's located at etc., so I can remove it safely without +affecting anything else.
+Cratylus <cre> overwrite the files in /secure/modules/ with blank +files
+Cratylus <cre> that'l probably do it
+Cratylus <cre> dont just delete them
+Cratylus <cre> and, of course, back them up first, just in case
+Amadeus <cre> what if i +removed the create command from /secure/cmds/?
+Cratylus <cre> that wasn't the advice i gave you
+Amadeus <cre> Mind telling +me what the point of the QCS would even be?
+Cratylus <cre> please clarify the question
+Amadeus <cre> What is the +point of a quick creation system?
+Cratylus <cre> http://dead-souls.net/articles/olc.html
+Amadeus <cre> Nah... It's +buggy... It doesn't work.
+Cratylus <cre> then why bother removing it?
+Amadeus <cre> It backtracks +you more often than helps you move forward.
+Cratylus <cre> then dont use it
+<cre> Cratylus shrugs.
+Amadeus <cre> I don't even +want it on my MUD.
+Cratylus <cre> well then, follow my instructions, and you'll be +all set
+
+
+
I +heard +you can edit stuff from the interwebs?
+
+Yes! You can now use CreWeb to edit your files.
+
+For folks who hate using ed but don't have shell access, CreWeb
+is just the ticket.
+
+It's basically a bunch of cgi scripts that run from the mud's
+built-in webserver. You log in with your mud name and mud
+password, and you can browse, upload, and edit files.
+
+This is what your homedir looks like: http://lpmuds.net/homedir.jpg
+This is what editing looks like: http://lpmuds.net/editing.jpg
+
+Note that this is purely experimental and may pose security
+risks. CreWeb was coded with security as a priority but I
+cannot guarantee it is 100% safe.
+
+If you want to give it a whirl:
+
+mudconfig http port 8001
+mudconfig http disable
+mudconfig cgi enable
+mudconfig dirlist enable
+mudconfig creweb enable
+mudconfig http enable
+
+(protip: It doesn't have to be port 8001)
+
+And then use your web browser to go to your
+mud's ip with the port you specified...for example:
+
+http://dead-souls.net:8001/cgi/login.html
+
+Note that this url is not your mud, so don't
+bother trying to log in. That's just an example of
+what the URL and the page looks like.
+
+Only Firefox is supported. I can't humor every
+browser out there, and Firefox is the one browser
+I know the largest number of people can download
+and use for free.
+
+
+I want to let people build but I don't want them to be +full creators
+
+Players can use the QCS to create rooms, npc's, weapons, armor,
+etc, if they are members of the BUILDER group. Simply add your new
+builder to the BUILDER group with this command (if her name is +"newbuilder"):
+
+groupmod -a builder newbuilder
+
+And then have her quit and log back in.
+Her stuff will be in /estates/n/newbuilder
+
+Have her issue the command "home", +then +get the
+staff and guidebook from her chest, and start reading.
+
+Note that builders do not have access to commands like
+ed, cd, ls, more, etc. They are meant to be isolated
+from LPC. If you want builders who can view and edit
+LPC code, they'll need to be creators.
+
+However, builders do have a workroom they can home to,
+and can use standard QCS commands like create, modify,
+add, etc.
+
+Note that the game will try to isolate builder stuff from
+live game content. Builder objects will not have value
+at shops, the armor won't protect from "real" in-game
+attacks, and weapons will be effective only against npc's
+from the builder's estate.
+
+
+
How do I enable +IMC2? What is it?
+

+IMC2 is an intermud protocol, like Intermud-3, but it is
+slightly different in how it works, its definition, and
+implementation. You can think of it as another brand of
+intermud...IMC2 and I3 being like Pepsi and Coca-Cola.
+
+The folks at Mudbytes run an IMC2 server network, and your
+mud is preconfigured for it.

+
+To start listening to specific channels, you add them
+to yourself in the same manner as Intermud-3 channels:
+
+chan add ichat
+
+
I +am not in charge of IMC2, do not complain to me about
+it. For more information about channels, rules, specs,
+etc, visit their IMC2 +support page.
+
+

+Combat is too +slow!
+
+    Combat in Dead Souls depends on individual stats.
+If you're a stone golem, your speed will be low, meaning
+your heartbeats are slow, and you only get an attack in
+every 4 seconds or so.
+
+    On the other hand, someone with a very high speed +stat
+could get an attack every two, or even every second.
+
+    The idea is that in having varying combat speeds,
+it makes things a bit more realistic and it means you
+need to use some strategy.
+
+    However, some people are used to codebases that do
+not bother with this sort of thing. They want to see fighting
+scream by their screen, never mind stats. For such people,
+a new configuration option, FAST_COMBAT, has been added to
+config.h. To enable "fast combat, regardless of speed stat",
+issue the command:
+
+mudconfig fastcombat enable
+
+
Fast combat is the current default.
+
+
+I want +players to select their class when they create their characters
+
+
mudconfig selectclass yes
+

+Note that the existing classes are just examples, and are therefore
+unlikely to have all the neat things you will eventually have
+in your mud.
+
+
+I am strongly +opposed to the use of intermud
+
+There are a few common reasons for this, often based on old
+or incorrect assumptions. Obviously you're going to run your
+own mud however it pleases you, but if your decision to disable
+intermud is based on the following beliefs, you may want to
+re-evaluate those reasons:
+
+"People +are mean on intermud"
+
+Some people on some channels are mean, yes. However, Dead Souls
+does not enable those channels for your creators by default.
+The default channels are newbie-friendly and have rules which
+are enforced.
+
+"Liar. I +have seen the logs. +Newbies are eaten alive."
+
+Not anymore. Not on my watch. Old logs are old. If a newbie
+is needlessly aggressed now, the aggressor is confronted.
+If the aggressor does not behave, the aggressor faces...
+consequences.
+
+
"Double +liar. +You were just abusing Hellmonger YESTERDAY!"
+
+This is one of those things that is hard for "newcomers" to
+understand, but on the intergossip channel, what looks like
+bitter, unrelenting abuse is often meant (and taken) as
+warm camaraderie. Oldtimers like Hellmonger, Duuk, and me
+often have ways of communicating that seem like perhaps one
+or more of us may wind up homicided for real. It's just goofing
+around, and it's one of the reasons I strongly discourage
+newcomers from connecting to that channel. As Kalinash very
+aptly put it: +
+
+"As for the content of the I3 channels, dead_souls and dchat are +intended to be helpful and PG-13.  Once you wander into +imud_gossip, it's a frat house full of sailors on shore leave.  +Fortunately, a most of the bile spewing, name calling and other general +rudeness, is still done in good humor."
+

+"Intermud +is +distracting"
+
+You don't have to prevent everyone on the mud from using
+intermud just because you find channels distracting. If you
+don't want to hear from a channel, for example the "ds_test"
+channel, you can issue the command:
+
+ds_test
+
+By itself, the channel name disables or enables the channel
+for you personally, without affecting how others on the
+mud use it.
+
+"People +will try to steal my builders and coders"
+
+This is unlikely. I don't think I've seen very much of this
+in the years I've run the network. It certainly *can* happen
+that your staff leaves your mud for another one. I would
+suggest that this would happen whether you enable intermud
+or not.
+
+You see, when a coder has a question you can't answer, or
+if you're not there, she's going to do a web search, and
+find the lpmuds.net forum, or +log into the Dead +Souls demo
+mud
. She's going to run into friendly, helpful people who
+share their ideas and suggestions, and she's going to
+want more of that. If you block intermud on your mud,
+she's just going to go somewhere else to find support,
+and she might just stay there. And +tell your other staff
+about the new place that isn't so restrictive.
+
+By blocking intermud, you actually make it more likely +you'll
+lose staff, not less.
+
+
"Intermud is +a resource hog"
+
+This is not correct. Your intermud connection generates
+about as much traffic/lag as a single moderately active
+player. I have tested Dead Souls with very large numbers
+of connections, and very large numbers of players, and
+I can assure you, quite confidently, the default intermud
+connection for your mud does not "lag" your mud. This
+might have been true on some other driver, with some other
+lib, in some other era...but not today.
+
+"I +just don't like you, Cratylus"
+
+You don't have to be a fan of mine to benefit from
+intermud. Some of the most established oldbies on intermud
+love nothing more than to give me a hard time on the intergossip
+(read not-very-friendly) channel. If nothing else, intermud
+would allow you to join the intergossip channel and tell
+me exactly how much I suck in real-time.
+
+"I am +afraid that intermud is actually some sort of Trojan or spyware"
+
+Short answer: intermud doesn't spy on you.
+
+Long answer:
+Dead Souls is an LP lib, meaning that it has no secrets. Its
+code is not pre-compiled. What it does, and how it does so is
+completely open for anyone to download and inspect. If you
+know anything at all about me you know there are plenty of
+people who would love +to find spyware/malware/whatever in
+Dead Souls, and make a big deal of it. If intermud worked
+as a spy tool for Dead Souls, it would be the worst thing that
+ever happened to the project.
+
+You can rest assured that intermud is not something
+used for collecting secrets about your mud.
+
+Having said that, intermud does allow people to see some
+things you might not like:
+
+* The list of logged-on players.
+* Finger information about players (except for their IP)
+* Basic information about which driver and lib version you
+run, as well as uptime and such miscellanea.
+
+If that information is something you don't want others to
+see, then disabling intermud would do the trick. However,
+it's really not very secret information...since logging
+in as "guest" would let anyone see the exact same things!
+
+One thing to keep in mind is that even though I do not
+monitor what people say to each other with "intermud tells"
+(different from channels. intermud tells are just between the
+two people), intermud tells go across the router in plain text, so
+you cannot be guaranteed that your intermud tell +will never
+be read by another person. However, regular tells on
+your mud are not intermud tells, and therefore regular
+tells on your mud never reach the intermud.
+
+If you want to see the data your mud sends to the intermud
+router, visit the network room:
+
+goto /secure/room/network
+
+You'll see the raw intermud packets going in and out.
+

+"My game +will have young children. I don't want them exposed to strangers."
+
+You should definitely block intermud then, or at
+least restrict it to adult staff.
+
+"I am +in a country where some opinions are criminal"
+
+
You +should definitely block intermud then, or at
+least restrict it to trusted staff.
+
+
"I +refuse to obey your channel rules"
+
+
You +should definitely block intermud then, or at
+least restrict it to responsible +staff.

+
+
+I hate one of the sample domains and I want it GONE
+
+If you feel strongly about it, then by all means get rid
+of the domain that offends your sensibilities. Before
+you do, however, ask yourself if what you dislike is
+the domain itself and everything it stands for, or
+if the problem is that you just don't want it to be
+something your players see.
+
+The reason you should ask yourself this question is
+that even if you really don't care for one of (or all
+of) the sample domains, they really do serve the
+incredibly useful purpose of providing many, many
+good examples of how to do certain things in Dead Souls.
+Without working examples, you'll be reinventing the
+wheel anytime you want to do something you're
+unfamiliar with that isn't explicitly detailed in
+exisiting documentation.
+
+If you wipe the the Town domain, for example, and
+then want to set up a quest for advancement, you're
+going to have to figure it out by reading and
+understanding the mechanics of the quest lib object
+and level system...rather than just taking a quick
+look at Leo and Dirk for how they implement those
+mechanics. If you're ok with that, then fine, but don't
+be surprised if your request for help on the intermud
+goes something like:
+
+Newcomer@MyMud <dchat> +how do I get an npc to raise my level?
+Cratylus@Dead Souls <dchat> +take a look at dirk
+
Newcomer@MyMud +<dchat> +nah, I deleted that domain, it sucks
+
Cratylus@Dead +Souls +<dchat> +download dead souls again and take a look at dirk
+
+(This chat was simulated. No newbies were harmed in
+the creation of that pretend log)
+

+It's by far simpler and more convenient to
+change the +default domain to something else, rather
+than deleting stuff.
+
+But hey, the beauty part is, it's your +mud. I'm not
+the boss of you, so if obliterating that horrible
+awful set of bits is what you must do, then follow
+your vision, man.
+
+
How +do +I make help files?
+
+Create a text file in the manner you normally do, then when
+you're done, put it somewhere in /doc/help that makes sense.
+for example, a help file about your new combat system might
+be called /doc/help/players/karate
+
+Once you've made the helpfile and put it where it goes,
+update the help daemon and you should be all set:
+
+update /daemon/help
+
+
+
How +many +players will DS handle simultaneously?
+

+General answer:
+As of Dead Souls 2.10, Dead Souls on a unix host
+running a modern OS on modern hardware can handle
+a couple hundred players with no software lag.
+
+Detailed answer:
+I have run tests on Linux and Solaris, firing playerbots
+into a test mud. These bots walk around, pick fights,
+get stuff, drop stuff, examine things, etc. They are
+coded to be as unidle as an extremely busy player...
+typically with less than 2 seconds between commands,
+all the time.
+
+What I found is that with the default settings, a
+DS mud on a unix host with a 2.5GHz proc doesn't
+hit noticeable lag until you're roughly over 200
+very active players. At around +250 V.A.P. you notice
+a little lag, which doesn't change much until about
+350 V.A.P., at which point you'll get occasional,
+definitely noticeable lag.
+
+It doesn't get into "bad lag" territory until around
+400 V.A.P. Above 500 you start getting into annoying
+lag territory, and above 600 or 700 it's "not fun".
+
+Note, however, that real +players are rarely as intensely
+busy as these bots. If you factor in the fact that
+about half your players are idle about half the time,
+the figure for "maximum players with no lag" goes
+up pretty quickly. You can also optimize your mud
+for high connection loads by disabling some of the
+resource-intensive parsing defaults.
+
+So, in theory, a DS mud on unix running on cutting-edge
+hardware and with normal players that are idle about
+half the time and with performance optimized could probably
+handle some 400 or 500 players simultaneously with no
+noticeable software lag. I haven't tested this, though,
+since I can't afford cutting edge hardware.
+
+See the FAQ entry below for DS on Windows.
+
+

+
I +heard +that Dead Souls for Windows has limitations
+
+Yep. They're not on purpose though, and it isn't the
+fault of Bill Gates or whatever. Basically, when
+the driver DS uses was in its early development,
+Windows was not a great target for mud development.
+It wouldn't have been *crazy* to make a mud that
+ran on, say, Windows NT 3.51, but it would be such a
+small audience that that the focus was on a driver
+that ran well on unix.
+
+MudOS therefore has had for a very long time a
+major bias toward code that runs well on unix, and
+this has been so for well over a decade. FluffOS,
+derived from MudOS, shares this legacy.
+
+Nowadays, Windows systems are quite robust and
+perfectly capable of handling even enterprise-level
+server apps. Today is seems *weird* that it's so hard
+to find a mud server that runs natively on Windows.
+To me it seemed natural to try to spread the goodness
+that is Dead Souls by making it easy to run on Windows.
+You will now find in the standard Dead Souls download
+an executable for Windows...and it's actually *easier*
+to install and run DS on Windows now than on unix.
+Go figure.
+
+However, the executable is compiled from unix source
+that heavily favors the unix way of doing business,
+and this is sadly not always compatible with Windows.
+As a result, Dead Souls on Windows has the following
+limitations:
+
+* DS on Windows will not accept more than 64 simultaneous
+network connections, meaning you are limited in the number
+of players you can have logged on at once.
+
+* DS file operations are dramatically slower on Windows.
+This causes performance in general to be weaker in
+comparison to the unix version, and it is the reason
+that some file-intensive operations, such as file
+indexing, are disabled in the Windows version.
+
+* DS CPU time is measured in a way that Windows doesn't
+understand, meaning that operations that under unix DS would
+get cancelled for being too CPU-greedy are allowed to
+run indefinitely in Windows DS. This means it is trivial
+to "lock up" a DS Windows mud by accident, forcing you
+to kill the process and restart.
+
+There are probably a few other limitations, but these
+three illustrate why Dead Souls on Windows is meant to be
+used for testing, development, and evaluating, not for a
+production mud. Your production DS mud (aka mud that is open
+for players and has players logged on) should run on a
+normal unix/Linux host.
+
+Note that if you use Cygwin to compile your own Windows
+executable, you *might* get around some of this stuff...
+but I don't support Cygwin so I can't vouch for it.
+

+

+
What +are +the CPU/RAM/diskspace requirements for Dead Souls?
+
+I usually get this question because someone wants
+to get server hosting somewhere and they want to
+know which "service package" to subscribe to.
+Unfortunately, the answer depends on all sorts of
+things I can't know, such as the speed of the
+machine, how busy your mud will be, etc. Rather
+than try to answer the question, what I can do
+is simply tell you what my usage is.
+
+Dead Souls on Linux 3GHz, +uptime 2w, currently on 8 players:
+  PID USER      PR  NI  +VIRT  RES  SHR S %CPU %MEM    TIME+  +COMMAND
+  XXX XXX       9   0 +11976  11m 1216 S  0.0  0.6 152:48.51 fluffos
+
+So a pretty idle DS mud takes little CPU and about
+11 megs ram, when it's mostly just a few people sitting
+around testing a few objects and chatting on intermud.
+
+Now for a heavy test/dev mud...
+
+Dead Souls on Solaris 2.5GHz, +uptime 2d, currently on 130 players:
+   PID USERNAME LWP PRI NICE  SIZE   RES +STATE    TIME    CPU COMMAND
+   XXX XXX    1  59    +0   30M   28M sleep    2:09  +3.86% driver
+
+In this particular case I think the 30M is probably
+misleading. These 130 players do wander around and
+load rooms and stuff, and I've seen the usage go
+up past 50 megs after a while. Is 50 megs for 130
+players a lot? I don't know. How much ram is your
+browser using right now?
+
+The CPU percentage is also misleading, because "top"
+on multiproc machines tends to divide that percent by
+the number of cores, so in this case the CPU utilization
+is actually more like 7.7%. Is that a lot for 130 very
+active players? I don't think +so, but that's up to you
+to decide.
+
+In any case, those are the two data points I can provide to
+you as a guide of how to shop for your hosting. If you
+find data that contradicts this, or is more useful, feel
+free to post it on the forum.
+
+As for diskspace, the download package itself is about 6M,
+and uncompressed it is:
+
+$ du -ksh ds2.8.4
+28M     ds2.8.4
+
+However, remember that an LP mud is all about files in
+LPC, which is plaintext and they'll take up a bunch of
+room as you go along. And also remember you'll be making
+backups, and possibly logging things, etc.
+
+My test mud takes up about 110M, and if you're going
+to be hiring coders and such, I'd strongly advise going
+above 200M.
+
+For just goofing around and testing, you could probably
+keep it under 100M, but you need to keep an eye on
+your usage.
+
+Summary: Unless you +know for a fact you will immediately
+have hundreds of players, a low-tier plan will probably
+suit you to begin with. Just don't lock yourself in to
+a plan until you've had a chance to determine for yourself
+what your needs are.
+
+
+
Who's +awesome?
+
+I'm awesome.
+

+
+
I +heard +you added vi to DS!
+
+Not exactly. I added an fullscreen-type editor that acts
+like you'd expect an editor to act, letting you move a
+cursor around the file with your arrow keys, for example.
+This editor is neat, and it works, but it comes with
+caveats. For more information, see: http://dead-souls.net/ds-charmode-faq.html
+
+If you don't have charmode enabled, ced won't +work.
+
+

+
What +is +MSSP?
+
+It's a protocol that allows someone else's internet program to
+connect to your mud and ask it for information. For example, your
+mud's name, how many players are on, what your theme is, etc.
+
+It's useful because it lets you maintain an up to date
+source of information on your mud for multiple mud listing
+sites, without having to schlep to each one to update your
+listing to keep it current.
+
+To change your MSSP info, edit /secure/include/mssp.h and
+change the fields you feel need changing.
+
+VITALLY +IMPORTANT +NOTE: If you modify information in that
+file and create broken LPC code, you may render your mud
+impossible to log into, and unbootable. Make 100% certain you
+back up this file before editing it, and once you edit it,
+make sure it works by updating LIB_CONNECT.
+
+bk
/secure/include/mssp.h
+update /secure/lib/connect.c
+
+
+

+- +Cratylus
+
+Dead +Souls +Homepage
+
+ + diff --git a/lib/www/ds-charmode-faq.html b/lib/www/ds-charmode-faq.html new file mode 100644 index 0000000..8354ef7 --- /dev/null +++ b/lib/www/ds-charmode-faq.html @@ -0,0 +1,82 @@ + + + + + Dead Souls Charmode FAQ + + + + +
Dead Souls Character Mode FAQ, v1

Written by Cratylus @ Dead Souls, May 2009


What is Dead Souls Character Mode?

What is it for?

Who can use it?

How do I use it?

What can I do with it?
Reprompt
Command recall
Context-sensitive command recall
Tab completion
Character mode editor

What's broken in it?

What is chario? Why do my errors keep pointing to it?


What is Dead Souls Character Mode?

Telnet
. Wow.

It's a neat protocol that can do a lot more than
people realize. Character mode is one of the two most
common ways to use telnet for mud communication.

The mode that most people are used to is "line mode".
What this means is that when you type a command into your
mud client, the mud client handles all the details of
putting one character after another, and then when you press
<Enter>, the client sends that whole line as a unit to
the mud for processing. It's so common that it seems to be the
default even for telnet clients that are not designed for mudding.

Character mode communicates in a different way. Instead
of sending data line by line, a character mode connection has
your client send your characters to the mud right when you
type them, so that by the time you hit <Enter> the mud already
has the complete line you wish to execute, and the <Enter> just
tells it to go ahead and do so.
 


What is it for?

The main usefulness of character mode in a mud is sending
special control characters and sequences. This allows you to,
for example, have a mud where players can enter a special "pilot"
mode where the arrow keys control an airplane.

In Dead Souls, the default application of character mode
is mostly creator oriented. Being a developer, and being a UNIX
guy, I've sorely missed being able to use filename completion and
such while on my mud. Character mode allows for the extension of
the "Nightmare Shell", or nmsh, into something more homey.



Who can use it?

Not every mud client supports character mode. For example,
trying to use charmode in MUSHclient or TinyFugue will result in
disappointment and confusion. I've heard that some clients do
handle it, but I don't know which and I can't vouch for how well
they do so. Before trying to use charmode with your favorite mud
client, read its documentation to see how to enter character mode
with it.

I use DS charmode from terminal windows, like xterm,
gnome-terminal, and Windows cmd.exe. Other standard terminal clients
like Putty probably support it too.



How do I use it?

Pretty simple, really. One you are logged in to your
mud with a terminal client (or a mud client you are sure handles
character mode), type the command:

charmode on

This sets your connection to character mode and sets your
player object to interpret your input in that manner. To exit
charmode you can either charmode off or <Ctrl>-D. To cancel a
command you've decided not to issue, <Ctrl>-C.

In the inevitable circumstance that someone tries to, say,
use charmode with Zmud32 from 1996, and then becomes hopelessly
entangled in problems and errors while trying to use advanced
charmode functions, your "charmode" flag is reset when you disconnect.
If you get lost or stuck in charmode, just disconnect and reconnect,
and you'll be in linemode again.



What can I do with it?


Reprompt

This is where DS charmode has its origins. A while back some
dudes where complaining along the lines of how the number one
reason LP muds suck is the terrible awful handling of prompts.
I was like "pffshyeah right" but once their complaints were
explained to me in a way I understood, I realized it wasn't
that hard to accommodate that preference...it was just a matter
of erasing the prompt line before printing anything. Not
rocket science. Then it occurred to me to take it a step further.
If the screen receives data while you're in the middle of typing
a command, and you're in reprompt mode, what you typed will be
invisible. You'll just have to remember what it was. This seemed
like it shouldn't be super hard to fix.

A few weeks and efuns later, character mode and character mode
reprompt were available. So now just entering charmode:

charmode on

Enables reprompt mode for you in a way that lets you keep your
prompt at the bottom of the screen, and see your input even if
interrupted by incoming text, and backspace to fix typos.


Command recall

It may sound weird but command recall is one of just two things
I like mud clients for (the other is sound triggers). Now that
DS has it integrated server side, I don't even bother with
clients much.

Basically charmode command recall lets you use your up and down
keyboard arrows to summon entries in your command history
that you can then issue again or modify.


Context sensitive command recall

If, for example, you typed:

give a red ball to the troll

a few commands ago, and now you want to give it
another one, you can type:

give a

and then hit your uparrow key. The command recall system will now
cycle through commands in your history that started with
the string "give a".


Tab completion

I've wanted this in my mud for a long time, and charmode finally
allows me to do it. The most obvious kind of tab completion is
command completion. For example, you can type:

inv<Tab>

(Where <Tab> means you hit the Tab key)

And the mud will present you with this:

({ "inventory", "invis" })

To let you know which commands you might mean. Type one more
matching letter:

inve<Tab>

And the mud will complete the "inventory" typing for you.

DS charmode also does filename completion. If you want to
see the contents of the welcome file, for example, you can:

cd /ne<Tab>

Which will auto complete to

cd /news/

Hit <Enter>, then

more wel
<Tab>

Which will auto complete to

more /news/welcome

Or, more typically, you'd:

more /n<Tab>we<Tab>


DS charmode also does object name completion, so if you're
in a room with a zyqxuwy, you can type:

dest zy<Tab>

Note that object name completion only works for creators,
since giving this to players could result in trivial
revelation of otherwise concealed information.


The character mode editor, "ced"

One of the favorite pet peeves of LP wizards for years has
been the difficulty in getting used to the standard in-game
editor, ed. As a line editor, ed can feel like ancient
arcana and it tends to deter new folks from getting elbow
deep in code like we used to do back in the day.

What ced does is give you an editing interface that uses
a more natural-feeling input mode. Rather than, say, issuing
the commands:

1z
3c

To view code and edit line 3, with ced you just use the
arrow keys to navigate where you need to go. Rather than
replace an entire line just to fix a typo, with ced you
just move the cursor to the typo and overwrite it.

For more details on the use of ced, type:

help ced

IMPORTANT NOTE: ced is not vi, nor modeled on vi. For
"simple to learn and use", vi isn't much different than
ed for the purposes of a mud, and I saw no advantage to
making ced a vi-alike. It would displease people who don't
know vi because vi is weird and difficult. It would displease
people who do know vi because it wouldn't actually be vi and
therefore it would be wrong in any number of ways for them.
Having said that, I like vi and intend to eventually add a
vi-ish editor, but don't hold your breath.

IMPORTANT NOTE 2: If you're used to vi, you will wind up
eventually hitting <esc> while in ced. This is going to lead
to confusion, because now ced is waiting for the rest of your
escape sequence. Hit an arrow key a few times until you see
the cursor move again.

IMPORTANT NOTE 3: Since ced is still somewhat experimental
as of DS 2.10, it is disabled by default. To enable it
and try it, type:

help ced (you should see a warning about disabled stuff)
mudconfig ced on
userload me
charmode on
help ced (warning should be gone)

You should see these as your control characters:
Ctrl-Q -- quit without saving
Ctrl-X -- quit and save
Ctrl-S -- save
Ctrl-I -- enable insert mode
Ctrl-O -- enable overstrike mode
Ctrl-L -- refresh the page
Ctrl-F -- scroll forward one page
Ctrl-B -- scroll backward one page
Ctrl-D -- delete current line
Ctrl-G -- Specify a line to go to
Ctrl-/ -- Search for a string

cd
cp workroom.c wk1.c
ced wk1.c.

IMPORTANT NOTE 4: Since you're editing inside a mud, you'll
eventually get some messages on your screen that you do not want
while editing in ced. To clear your screen of such unwanted
crud, use the "refresh" command: <Ctrl>-L. See also: help codeblock


What's broken in it?


A few caveats and fixmes:

- You can use backspace to fix your typos when issuing commands,
but side-arrow keys for full "command line editing" aren't yet supported
as of DS 2.10.

- Command recall tends not to include commands issued by add_action().
It also can expand your alias to "what the alias was" rather than "what
I literally typed" depending on your DS version. These idiosyncrasies
can make your command history appear to be out of order at times, and
will be made more standard in future releases.

- Using ".." in tabbed file completion yields non-useful
results. This will be fixed in later versions.

- Copying and pasting large amounts of data into the screen while
in charmode will result in a very slow experience for you. This is
because the mud is accepting each char one at a time while at the
same time performing whatever other vital mud functions are going
on that don't include you. This is not actually a "bug" so much as
just how it works. If you need to paste large text into the mud
through your terminal, don't use charmode to do it.

- The ced editor doesn't handle wrapping at all. If your lines extend
past your screen's width, you'll just have to use your imagination
for now.


What is chario? Why do my errors keep pointing to it?

Think of LIB_CHARIO as a traffic cop.

The original design of charmode had all character data being
sent to LIB_NMSH for interpretation. This was fine for
development and testing, but very soon it became apparent
that LIB_NMSH was doing a lot more work than intended. There
was also the problem of having nmsh shunt off input to the
editor. This setup became unwieldy fairly quickly.

LIB_CHARIO is the object that identifies which characters
the mud has received from the user, if charmode is enabled
for that user. Depending on whether the user is editing,
chario (character input/output) determines which lib object
should receive the input, nmsh or ced.

If you use charmode, get used to seeing chario and nmsh
showing up in your runtime error chain. Even though they
themselves may not be the source of the error, the fact that
your command went through them means they are part of
the function/object stack that caused the error to be
generated, and so they'll show up in the error log.


 
+The end.
+
+Dead Souls Homepage
+
+
+ + diff --git a/lib/www/ds-creator-faq.html b/lib/www/ds-creator-faq.html new file mode 100644 index 0000000..c29f999 --- /dev/null +++ b/lib/www/ds-creator-faq.html @@ -0,0 +1,5336 @@ + + + + + Dead Souls Creator FAQ + + + + +Dead +Souls Creator FAQ
+
+Written by Cratylus @ Dead Souls
+
+Updated May 2009.
+
+
Note: commands are +displayed in boldface, like this: ls +-a
+
+What's this FAQ about?

+
+There are common issues and +questions that crop
+up for most new creators. This +document is intended to
+ease or at least shorten what can +be a steep learning
+curve.
+
+
+Section 1: +Getting Started
+
+1.1 +My question isn't on here. Where can I get an answer?
+
+1.2 The ds channel is +too spammy. It's distracting me.
+
+1.3 All I did was change +one thing in a file, and now it won't update. Help!
+
+1.4 The mud editor is +confusing the heck out of me. It's too hard to use.
+
+1.5 When I log in, +everything is screwed up, and I can't do anything!
+
+1.6 Ok, I'm a creator +now. What am I supposed to do?
+
+1.7 This is +weird...where is the online builder? How does new stuff get compiled?
+
+1.8 I explored around in +/domains/Ylsrim and <XYZ> is broken
+
+1.9 I explored around in +/domains/town and <XYZ> is broken
+
+1.10 What are the known +bugs and problems in Dead Souls?
+
+1.11 Why do you keep +asking me to post my code?
+
+1.12 "help modify" breaks.
+
+1.13 There are no help files!
+
+1.14 Where are the help files for skills and stats?
+
+
+Section 2: Code
+
+2.1 What's the QCS?
+
+2.2 SetUnique doesn't +work.
+
+2.3 I made a magic wand +that disappears after 10 minutes.
+But if a player logs out +and log back in, they have another 10 minutes!
+How do I fix this?
+
+2.4 Where is it saved?
+
+2.5 How do I add or +remove emotes?
+
+2.6 How can I tell what files something inherits?

+
+2.7 How can I find the +filename of something?
+
+2.8 What's the largest +integer usable by the mud?
+
+2.9 How can I find out +what functions exist in something?
+

+2.10 object::init() is +broken!
+
+2.11 +if(ob->GetFoo()) seems to break, but I don't know why
+
+2.12 How do I add color +to my descriptions?
+

+2.13 How do I turn the +integer 42 into the string "forty-two"?
+
+2.14 Can I use !=NULL +as a test?
+
+2.15 I want to create +and test a new command for the mud,
+but I'm not admin so I +can't put anything in the normal command paths.
+What can I do?
+
+2.16 How do skills work?
+
+2.17 How do classes +work?
+
+2.18 How do virtual +rooms work?
+

+2.19 How are files +organized in Dead Souls?
+
+2.20 What are applies, lfuns, +sefuns and efuns?
+
+2.21 Why are there more +sefun doc files than sefun files?
+
+2.22 I edited a file +but now the reload command is complaining.
+
+2.23 +this_player()->GetName() returns "A shadow" when the player is invis.
+

+2.24 Is there a sefun +for making a whole string uppercase?
+
+2.25 What is the +difference between filter() and foreach()? How do I use them?
+
+2.26 member_array() is +returning exactly the wrong thing
+
+2.27 I'm trying to add +two mappings together and the results are bizarre
+
+2.28 When str = "abc", +str[1] is 98, not "b". What gives?
+
+2.29 How do I make an +array1 that is the same as array2 but without an element?
+
+2.30 How do I pass +arguments to a pointer in a functional?
+
+2.31 What does the tc() +sefun do?
+
+2.32 How can I find out +how many items are in an array quickly?
+
+2.33 My SetRead isn't +working
+
+2.34 My +SetEnters/SetSmells/SetListens isn't working
+

+2.35 Can I nest loops?
+
+2.36 What should I do +or not do in my code?
+
+2.37 How much different +or heavily modified is Dead Souls than stock LPC?
+
+2.38 +Is there a way to change the "default exit" room messages?
+
+2.39 This dummy item is +not at all behaving like I expected.
+
+2.40 Clan objects do +nothing but screw things up.
+
+2.41 My NPC's stats are +all hosed up.
+
+2.42 This squirrel is +taking *forever* to kill.
+
+2.43 My room should not +be entered/exited by just anyone. How
+do I control this?

+
+2.44 I zapped a +monster, but instead of being dead, now it's undead!
+
+2.45 How does the +format for race files work?
+
+2.46 How does the +format for class files work?
+
+2.47 What do Properties +do?
+
+2.48 How do I add a +prehensile limb to a player or NPC?
+
+2.49 How do I make a +room occasionally display messages?
+
+2.50 My functional +isn't working!
+
+2.51 I've read the +Creator's Manual but I still don't understand mappings and arrays.
+
+2.52 Why are call_outs +so bad?
+
+2.53 Fine. How am I +supposed to create timed events, then?
+
+2.54 I need a list of +all the functions available.
+
+2.55 How do I make an +object you can [ jump on | climb | etc ] ?
+
+2.56 Where is the list +of available skills? How do I add skills?
+
+2.57 Where is the list of available classes? How do I add a class?

+
+2.58 Where is the list +of available races?
+
+2.59 How do languages +work? Is there a list of them?
+
+2.60 When I try to call +test->SetLanguage("Bozo", 50), it sets it to 100%
+
+2.61 How do I update an +.h file?
+
+2.62 I want to put an +object in a room that doesn't show up in the inventory
+but it can be manipulated.

+
+2.63 What is pass by +reference? What is pass by value?
+
+2.64 ZOMG pass by +reference is terrible! How do I avoid it?
+
+2.65 What does the :: +operator do?
+
+2.67 I know this file +is fine. I copied it from another file that
+works, but it won't update. This is driving me insane.

+
+2.68 What is +SetEncounter supposed to do?
+
+
2.69 +I keep getting "This should be edited by hand.Change cancelled."
+
+2.70 zOMGLOLERZ I did what said but no +my workrom really IS broke!!1!
+
+
+2.71 I can't find the SetQuatloos() lfun anywhere!
+
+2.72 You said that what I want to do requires a daemon. +I am afraid.
+
+
2.73 LOL I +tried to +show something to someone in the shop +but the vendor gave an error.
+
+2.74 My object keps failing with an eval cost too high +error.

+
+2.75 Please +explain ( foo ? bar : baz )
+
+2.76 Where are +things like Town and race and starting money set for new players?
+
+2.77 How do I +make my NPC respawn sooner than the reset interval?
+
+2.78 My +TalkResponse NPC doesn't work, but it really really should!
+
+2.79 How do I +load an object?
+
+

+Section 3: +Intermud and channel stuff
+
+3.1 How do I know what +other muds are online on intermud?
+
+3.2 Hey, LeetFooMud is +online! How can I tell if Biff is logged on?
+
+3.3 That's +weird...mudlist says LeetFooMud is there but I'm not getting anything +back.
+
+3.4 I heard there are +intermud channels that talk between other muds,
+not just Dead Souls +muds. How can I use them?
+

+3.5 How do I emote on a +channel?
+
+3.6 How do I see what I +missed on a channel?
+
+3.7 I am sick and tired +of the intermud network going down. Please fix it.
+
+3.8 I just wanna chat. +Is there a dschat channel?
+
+3.9 I'll spam if I want +to. You're not the boss of me.
+

+3.10 This guy keeps +hassling me on an intermud channel
+
+3.11 What's the deal +with channel rules and banning and whatnot?
+
+3.12 Hello? Anyone here? Can someone answer a question for me?

+
+3.13 How come people on IMC2 can't rwho me?
+
+
3.14 How +do I find someone on Intermud-3??
+
+
+Section 4: +Miscellanea
+
+4.1 I'm fighting the +beggar with my staff and he's kicking my ass
+
+4.2 Someone amputated +all my limbs and I can't do anything!
+
+4.3 How do I change my +class?
+
+4.4 People are talking +to me in gibberish, even though it says they're speaking English.
+
+4.5 What's this about +Biff "unknowingly" telling me something?
+

+4.6 How do I find the +location of a verb or command?
+
+4.7 Where is the "exa" +command? Where is the "n" command?
+
+4.8 How do I get +something to happen to a random person in a room?
+
+4.9 My wandering monster +escaped from my workroom! How can I find him?
+
+4.10 I ran findobj on +something but it says no environment. Where is it?
+
+4.11 How do I update +everything in a directory?
+
+4.12 I don't like +getting colors on my screen. How do I stop it?
+
+4.13 Um...I want colors +back now please
+
+4.14 I can type 'n' and +move north, but 'north' doesn't work.
+
+4.15 Why is there a +bunch of stuff in ROOMS_FURNACE?
+
+
4.16 How do I +change my screen and terminal settings?
+
+4.17 ZOMG this is the +best mudlib evar how can I evar thank you?
+
+4.18 Dude this mudlib +sux0rz @ss. What a waste of my time.
+
+4.19 I'm seeing a +filename but I can't read it.
+
+4.20 Is there a command +to go back to your previous directory
+without having to type it all out again?

+
+4.21 When I'm in combat, I keep getting messages about not being
+able to fight while carrying stuff, but I only have X, Y, and Z on me.

+
+4.22 How do light sources work?
+
+
4.23 When +I control +an NPC, sometimes my commands fail +oddly.
+
+4.24 How do I make myself able to cast my new spell?
+

+
+Section 5: +Building
+
+5.1 QCS is putting stuff +where I don't want it.
+
+5.2 How do I make a +blank room, instead of copying the current one?
+
+5.3 How do I build an +area?
+
+5.4 How do I make a +quest?
+
+5.5 Where's Leo?
+
+5.6 Where are the +vehicles and mounts?
+
+5.7 I'm having trouble +adding meals to my barkeep with QCS.
+
+5.8 I heard DS has +stargates. Where's an example?
+
+5.9 I created a vendor, +but he isn't responding to the "list" command.
+
+5.10 I gave room with a +default smell but I cannot get any other smells
+in there,such as 'smell +object' for example
+
+
5.11 +How do I make a weapon more powerful?
+
+5.12 My NPC refuses to +wield his weapon.

+

+
5.13 How +do I add colors to exits?
+
+
5.14 How +do i refresh a room?
+
+5.15 The new room I created with QCS has SetItems I +don't want

+

+5.16 +I'm trying to set my fighter to have a strength of 50 but it won't work.
+
+
+
+
Section +1: Getting +Started
+
+
+1.1 +My question isn't on here. Where can I get an answer?
+
+There are five main ways to get +specific answers:
+
+1) Ask your mud's +administrator, or +other creators on
+your mud by using the cre +channel, like this:
+
+cre does the +flux capacitor use verbs or add_actions?
+
+To know what local channels are +available to you on your
+mud, type: lines
+
+
+2) Your mud is probably on the +Intermud-3 +network. If
+your administrator has not +restricted intermud channels,
+you should be able to ask +questions on the Dead Souls
+intermud channel, with a command +like this:
+
+ds hi! can +someone tell me what room Leo lives in?
+
+
+3) If intermud is down, or +nobody is +answering, or
+you have a bug to report, you can +also try emailing
+me, the author of this doc, at: +<my name here>@comcast.net
+This is a long shot, as I prefer to answer things on
+the forum, where more than just one person will
+benefit. Note that I just might post your emailed
+question on the forum, if I think that's appropriate.
+
+
+4) If intermud is down, you can +also log +into the
+Dead Souls demo mud at dead-souls.net +8000 +
+This mud automatically promotes +users to
+creator status, allowing guests +to get a feel for
+what developing on Dead Souls is +like.
+You can try to log into that mud +and see if anyone
+is available to answer your +question. Intermud is disabled
+for new users there, though, so +you won't be able to use the ds line
+to ask questions.
+
+
+5) There is also the Dead Souls Forum at +http://lpmuds.net/forum/
+This is a really great place to ask for a few reasons:
+
+- If someone doesn't know the answer right away, eventually
+  someone probably will.
+- Sometimes people on intermud know the answer, but are busy and just
+  don't have the time to answer. On the forum, this is less the +case.
+- Some questions have answers that are long, and intermud folks
+  may not want to spend the time on an elaborate answer to a +question
+  that they'll probably see someone else ask later. On a forum,
+  the responder can be reasonably sure that her help will be useful
+  not just to you, but to many others.
+- You can post detailed error messages and logs, and the files(s)
+  that are giving you trouble. That way many eyes can analyze
+  your problem in depth.
+- Once resolved, other people can later refer to that problem so
+  they don't have to ask the same question, or reinvent the wheel.
+
+
+
+Important +note about asking on <ds>:
+
+Part of the reason this FAQ was +written is that
+people who ask questions on the +ds channel often do not
+realize that same question has +been asked many times
+before. If you ask something like +"how do I read the
+channel messages I missed?" +without first bothering to
+read this doc and others, you +just might get a response
+that's less friendly than you +might have expected.
+People on the channel really +want to help you,
+but if it seems like you're not +willing to put in the
+time to try to help yourself, +they might choose to
+ignore you until you gather some +clues on your own.
+
+Something else to remember is +that we are not
+on your mud and we don't see what +you see. "Why won't
+my workroom update?" lacks enough +information to let
+anyone try to help, but "when i +try to update my
+workroom I get <error +message>" might.
+
+Similarly, some things don't +have an answer
+that is suited to ds. "could +someone help me
+understand the score.c file?" or +"how do quests work?"
+have answers that are long and +complex, or are
+already covered in the +documentation available
+to you.
+
+Some stuff just doesn't have an +answer
+that can be explained to you +unless you already
+have the experience you'd need to +know the answer.
+for example:
+
+- How do I make a +stargate that has a dial for
+ going to +different places?
+
+- How do I make it +so a player can be on different
+planes of +existence, and what they see when they
+look around +depends on what plane they're on?
+
+- How do I add limbs +so people can wear stuff
+like kneepads +on the knee only?
+
+These three questions illustrate +things that are
+totally doable, but whose +explanation is so
+complex and full of judgment +calls that there
+is no way of satisfying the +question without
+making you magically understand +intermediate-level
+LPC coding.
+That doesn't mean they're bad +ideas, or
+even that hard to implement. It's +just that
+the questions can't be answered +until you read
+and understand the Creator's +Manual, and by that
+time, you'll know the answer on +your own.
+
+Make sure you've read the docs, +then ask
+the question in a way that makes +it clear you aren't
+just a lazy person who wants +other people to do her
+work, but rather a hardworking +builder who has
+tried to fix something and needs +a specific answer
+to a specific question that isn't +already in the
+FAQ's or the docs.
+
+Critiques are welcome, but they +should
+be constructive. "This combat +system is slow and
+stupid" is unhelpful and might be +taken as a
+hostile statement. Instead you +could phrase it
+in a way such as: "Combat is +slower than I
+expected. Why? I used to play on +LeetFooMud and it
+took less than a minute to kill +Tiamat." It's still
+a bit clueless, but it's a fair +question that can
+be answered on its own terms +without starting
+a flamestorm.
+
+Finally, some things are only +lightly
+documented, or perhaps not at +all. Filling out
+the documentation is an ongoing +project, but as
+with much freeware out there, you +have to be willing
+to put in a little bit of time to +experiment. For
+example, you may not know what +the "importance
+to the class" section in the +class file format is,
+and you may not find the answer +in the docs. In
+such a case, you have to be +willing to experiment a
+little, and plug in different +numbers, to see what
+they do. I can't hold your hand +every step of the
+way. You have to trust your own +intelligence and
+enjoy the sense of adventure in +discovering things
+on your own.
+
+Also, please refer to this Admin FAQ section +
+on how to ask questions in the most productive way.
+
+
+The +ds channel is too spammy. It's distracting me.
+
+Enable or disable a channel by +typing just its name. Like:
+
+ds
+
+
or:
+
+chan block ds
+

+
+All +I did was change one thing in a file, and now it won't update. Help!
+
+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 your file is in the /tmp +directory, it won't update.
+The lib uses /tmp for temporary +system files, and as
+a result, it is a security +feature that files in /tmp can't
+be loaded into memory.
+
+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.
+
+Take a look at the third +party downloads +page for
+some suggestions as to what to +use instead of the default
+Windows editors.
+
+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.
+
+If you're using a relatively recent version of Dead Souls, you
+can avoid some of the pain of the ed +line editor by enabling "CreWeb".
+
+CreWeb is a web-based application that can run from the built-in
+Dead Souls webserver, allowing you to edit and upload files
+without having to mess with ed. For more information, type:
+
+help creweb
+
+
+For screenshots:
+
+Your home directory
+
+Editing a file
+
+
+If you use a character-mode compliant telnet client, you might
+also avail yorself of ced.
+
+
+
+When +I log in, everything is screwed up, and I can't do anything!
+
+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.
+
+If this doesn't work, there's a +good chance that the room
+you're spawning in has a problem. +Try quitting and logging
+in again. If that works ok, then +it's very likely the
+room was at fault. See if there +are any messages in
+/log/runtime pointing to it.
+
+
+Ok, +I'm a creator now. What am I supposed to do?
+
+Ask your admin.
+
+If you're like most other +creators, you have
+a creative vision you want to +implement and share with others.
+you want to create dragons, or +spaceships, perhaps dragons
+in spaceships. This makes you +a +"builder".
+
+As a builder, your job is to +learn how your mud
+works so you can get your neat +ideas turned into a
+virtual reality. As you might +have guessed, nobody is
+going to jack into your brain and +upload coding ability
+into you. You need to learn how +to move around, how
+the creation system works, and +yes, you'll need at least
+some passing acquaintance with +the stuff your mud is
+made of: files written in the LPC +language format.
+
+The good news is that it's +nowhere near as hard
+to learn as C++. LPC is very +powerful, but it doesn't
+require you to be a master to get +simple things done.
+
+Your first steps as a new creator +probably should
+go something like this:
+
+1) Talk to your admin. +Understand what +is expected of
+you, and what the rules of your +mud are.
+
+2) Go to your workroom by +typing: home. Read the helpful +
+notes that are posted there for +you.
+
+3) Read the Player's Handbook, +cover to +cover. It isn't
+long, and you will need every bit +of information in there.
+This is not a +suggestion. You need to read the handbook.
+
+4) Open the chest in your +workroom, and +play around
+with the tools and toys in there. +Having read the
+handbook will help you deal with +any issues you have
+handling these items.
+
+5) Type wiz to go to the Creator's Hall, and +if +there
+are any posts on the board, read +them. To read the
+first post: read 1. To read +the second, read 2, and so on.
+If you decide to write on the +board,
+remember that to exit "writing" +or "input" mode,
+you need to enter a dot on a line +all by itself,
+like this:
+
+.
+
+6) Once you get a feel for how +to move +around,
+what playing here is like, and +how to do stuff, you
+can start exploring your creator +powers. To get
+a grasp of the very basics of +navigating through
+files and directories, type:
+
+more +/doc/BASICS
+
+Yes, you must include capital +letters. Dead
+Souls distinguishes between upper +and lower case
+letters in filenames.
+
+To get a feel for what Dead Souls +LPC code looks like,
+wander about town and use the +about command to read
+code that compose the objects +there. For example:
+
+goto +/domains/town/room/road
+
+about here

+
+about beggar
+
+ Or move around in your own home
+directory and check out the +defaults and templates
+there:
+
+cd +/realms/<yourname>/area/npc
+
+more fighter.c
+
+To bring a copy of that fighter +to life:
+
+clone fighter
+
+To make him dance:
+
+force fighter +to dance
+
+To kill him:
+
+zap fighter
+
+To get rid of his corpse:
+
+dest corpse
+
+7) Once you're done having fun +with your +godlike
+powers, it's time to start +learning how to make
+fun stuff of your own.
+
+For a quick start in building, +you
+can start reading the Creator's +Manual at
+chapter 31, which is where the +QCS section begins:
+
+read chapter +31 in manual
+
+read chapter +32 in manual
+
+and so on.
+
+That's fine to start with, but +eventually
+you'll need to read the whole +Creator's Manual.
+If you don't, 90% of the +questions you ask about
+code could be fairly answered +with: "read the manual."
+
+
+This +is weird...where is the online builder? How does
+new +stuff get compiled?
+
+Dead Souls can be very strange +to people used
+to non-LPC muds. This is because +many other kinds of
+muds use a system where the mud +is written in C++,
+and to make changes, you need to +add C++ code to the
+source, recompile it, then reboot +the mud.
+In that kind of system, building +is done with
+tools where you fill in blanks +and code is generated
+for you. I presume that some C++ +expertise is
+required for doing anything +unusual or fancy.
+
+If you come from this kind of +environment,
+you may be in for a little +disorientation. On a Dead
+Souls mud, there is no need for +compiling code. You
+don't need to reboot the mud for +new stuff to
+be available.
+
+You can add your new Orc God of +War to the
+game (after you code him, of +course) with two
+simple commands:
+
+update +/realms/<you>/area/npc/grimmash.c
+
+clone +/realms/<you>/area/npc/grimmash.c
+
+You're now face to face with +him. This makes
+Dead Souls, like most LPC muds, +very flexible in
+what can be done, and very stable +in terms of
+needing few reboots. Reboots +typically are
+necessary only when someone +breaks important
+code, or to implement major +mud-wide changes.
+
+So, just write your code, and +update it.
+It's that simple. There are two +main ways to do
+this. The easiest way is with the +QCS, or quick
+creation system. With the QCS, +you don't even need
+to look at code. You just issue a +few commands,
+and your new whatever is there. Check out an +example
+of the QCS here.

+
+To learn the QCS, read the +Creator's
+Manual starting on chapter 31.
+
+The other way to create on-line +is
+with the ed command. The ed +editor is a powerful
+and flexible way of editing +files. Some people
+find it difficult at first, and +you might even
+be able to avoid it for a while +if you mostly
+just use QCS. However, you'll +eventually need to
+know a little about ed. For a tutorial, go +here.
+
+For more detailed documentation, +
+type: help ed
+
+
+I +explored around in /domains/Ylsrim and <XYZ> is broken
+
+Ylsrim is kept in the +distribution as a kind of
+sentimental artifact. It's the +demo area that the
+original Dead Souls shipped with, +and although
+it's mostly been fixed up to work +with Dead Souls 2,
+things can behave unexpectedly. +There will be
+no new fixes to Ylsrim. Please +consider it a museum
+exhibit that stands as-is. This +is also true for Praxis.
+
+
+I +explored around in /domains/town and <XYZ> is broken
+
+Please send me an email and let +me know, so I
+can fix it. Also let me know if +something in the default,
+campus, or examples domain is +hosed up.
+
+
+What +are the known bugs and problems in Dead Souls?
+
+I don't remember.
+
+
+Why do you keep asking me to post my code?
+
+Sometimes, when someone asks for help on the intermud
+channels, I will ask them to post their broken file on
+http://lpmuds.net/forum/ to +troubleshoot.
+
+Let me make a few things clear:
+
+- I am not trying to steal your broken newbie code.
+- I am not trying to drive up web site traffic.
+- I am not trying to collect your personal data.
+
+I've actually had more than one person get hostile
+and defiant about posting on the forum, which I
+find mind-boggling considering they were asking for help
+in the first place.
+
+The reason I ask is that, as good as I am with Dead
+Souls and LPC, some things I can't figure out unless
+I see:
+
+1) The errors generated by the code.
+2) The code that generates the error.
+
+If I ask to see your file and you won't post it on the
+forum, I might maybe accept it by email. On the other hand,
+the point of the forum is for people to learn from each
+other, including each other's mistakes. If you won't
+allow your troubled code to be made public so
+people can help you, I'll probably let you work it out
+on your own.
+
+Remember that I release 99% of my code for the
+whole world to see, so I've got limited patience if you're
+going to hoard your precious uber sword of wounding code.
+
+
+
"help +modify" breaks.
+
+This is typically the result of your columns screen
+setting being very large. Type:
+
+screen 80 24
+
+
+There are no help files!
+
+You probably downloaded the public domain version of
+Dead Souls. This version is not recommended for newcomers
+to Dead Souls...it is really for experts or for people
+who have special needs like developing their own lib
+or selling their software. For normal people who are just
+interested in running a mud, the regular version is
+the right choice. Download +and install the regular
+distribution
, instead.
+
+
+Where are the help files for skills and stats?
+
+Things like "strength" or "intelligence" or "knife
+defense" are stats and skills that are used by the
+mud in calculating things like combat effectiveness.
+
+For the most part, they are self-explanatory..."strength"
+is how strong you are, "magic attack" is how good you are
+at, say, hurling fireballs.
+
+For the most part these are not documented in the help
+system because their use should be self-explanatory
+and may not even exist from mud to mud. Please see the
+other faq articles for more details:
+
+http://dead-souls.net/ds-creator-faq.html#2.16
+http://dead-souls.net/ds-creator-faq.html#2.56
+http://dead-souls.net/ds-admin-faq.html#115
+
+Often what querents mean when they ask this question
+is "exactly how does strength and knife attack interact
+in the combat system with the opponent's dexterity,
+armor and knife defense?"
+
+The only answer to this question that I can give and
+retain my sanity is "You're going to have to get familiar
+with the lib, test different weapons and skill/stat
+levels, and see for yourself."
+
+
+
+
+

+
+
Section 2: Code
+
+What's +the QCS?
+
+Please see the QCS example page for an +explanation of this
+important Dead Souls system.
+
+
+SetUnique +doesn't work.
+
+SetUnique() is probably doing +something you
+don't expect. When an item is +loaded into memory, and
+it has an inventory, it first +checks each of those items
+for whether it's supposed to be +unique.
+If it is supposed to be unique, +then we look
+through the list of loaded +objects to see if there is
+one of these items already +cloned. If there is, then
+we don't clone a new one.
+What this means is that if I +kidnap Leo the
+archwizard and hold him in my +workroom, another one will
+not appear in the basement until +my Leo is dested.
+
+Note, however, that this does +NOT mean that the
+mud will never have two Leos. I +can clone however many
+Leos I want. But as long as one +or more cloned Leos
+exist, the basement will not make +another. That's
+what SetUnique means.
+
+Putting a negative number in the +value element
+of a given item in SetInventory +makes it get treated as a
+unique object.
+
+Now, if the behavior you're +seeing is different
+from what I described, maybe +SetUnique is broken,
+and you should email me with what +you're seeing.
+
+
+I +made a magic wand that disappears after 10 minutes.
+But +if a player logs out and log back in, they have
+another +10 minutes! How do I fix this?
+
+What's happening is that you are +keeping
+track of how old the wand is, +perhaps with a
+variable named Age. But if the +player quits and
+logs back in, then the wand gets +cloned again, resetting
+all its values, including Age, to +the original.
+
+The way to make the Age variable +survive
+logouts is with AddSave. If you +give your variable to
+AddSave as an argument, that +variable gets saved when
+the user quits, and when they log +back in, it is restored,
+preventing cheating.
+
+See /obj/wed_ring.c for an +example.
+
+
+Where +is it saved?
+
+In the player's playerfile, along +with the values of all
+the objects they were carrying +when they quit. The file is
+in /secure/save/[ players | +creators ]/<first initial>/<name>.o
+
+Note that AddSave() is not responsible for the act of
+saving data to the playerfile. AddSave() sets in the object
+which variables should be saved. When the player quits
+or the automatic save time is reached (about every 5 minutes),
+the save_player() lfun in LIB_AUTOSAVE checks each carried
+object for its AddSaves(), and saves that data in the
+player object accordingly.
+
+
+How +do I add or remove emotes?
+
+That is an admin job. You admin +would use the
+addemote or removeemote commands.
+
+
+How +can I tell what files something inherits?
+
+Use the showtree command. To know +what files
+are inherited by your robe, for +example:
+
+showtree +/domains/default/armor/robe
+
+

+How +can I find the filename of something?
+
+If it's in your environment: scan here
+If it's in your possession: scan me
+
+The number sign (#) and numbers +at the end are that
+object's unique identifier.
+
+
+What's +the largest integer usable by the mud?
+
+On a 32-bit compiled driver: 2147483647 (Two point one billion)
+On a 64-bit compiled driver: 9223372036854775807 (Nine point two +quintillion)
+
+To know which you're on, type: eval +return MAX_INT
+
+
+How +can I find out what functions exist in something?
+
+Get its filename and use the +functions efun. For example:
+
+eval return +functions(load_object("/domains/town/obj/sign"))
+
+
+object::init() +is broken!
+
+It isn't really. Unless you're +coding a lib
+item, you should not be +inheriting LIB_OBJECT for
+"tangible things" anyway. You +should inherit LIB_ITEM.
+
+The reason object::init() fails +is that LIB_OBJECT
+doesn't have an init() function +to call.
+
+
+if(ob->GetFoo()) +seems to break, but I don't know why
+
+This function will error if ob +does not exist. Unless
+you are 100% positive ob will +exist (and really, even if so),
+it should look like this:
+
+if(ob +&& ob->GetFoo())
+
+
Which means "if ob +exists, and it has a foo".
+This way, if there is no ob, the +check stops right there
+without getting hosed up on the +next step.
+
+
+How +do I add color to my descriptions?
+
+There are various markup tokens +you can use for this. They look like this:
+
+write("%^BOLD%^GREEN%^ This +text would be in bold green letters %^RESET%^ and this would +not.");
+
+To make text blink, use this tag: +%^FLASH%^
+
+The %^RESET% is important. +Without it, unpredictable things can happen.
+
+To know what colors are +available, type: colors
+
+You should probably avoid color +unless there is a compelling
+reason for its use. Many mud +admins discourage it because it can
+distract from the game and cause +uniformity issues: most mud
+admins feel their mud text should +look more or less
+the same everywhere.
+
+
+How +do I turn the integer 42 into the string "forty-two"?
+
+cardinal(42)
+
+There is no function to do the reverse.
+
+
+Can +I use !=NULL as a test?
+
+In theory, I guess so, but I +doubt it'll work by default, and I'd
+discourage you from doing +anything so non-LPC-standard.
+Instead try something like one of +the following:
+
+if(variable)
+if(sizeof(variable))
+if(variable != "")
+
+
+I +want to create and test a new command for the mud,
+but +I'm not admin so I can't put anything in the
+normal +command paths. What can I do?
+
+Put your new command in your +homedir's cmd/
+subdirectory. A sample command is +there already
+to serve as a template. When you +add a command, type:
+
+update +/daemon/command
+
+for it to show up in your path.
+
+
+How +do skills work?
+
+Skills are generally class-based, +meaning that they are
+specified in the class files +found in /secure/cfg/classes.
+Skills are only meaningful in +terms of library objects that
+understand them.
+
+For example, a fighter's blade +attack is useful because
+player.c and combat.c make use of +this skill as a
+modifier.
+
+But adding a basketweaving skill +to a class is not
+helpful unless there are library +objects (looms, perhaps,
+or straw) and verbs (weaving, +maybe?) that make
+use of that skill.
+
+There are also race-based skills, +such
+as poison bite or breath attack. +These skills are
+specified in /secure/cfg/races.
+
+
+How +do classes work?
+
+Basically, having a class gives +you special skills.
+That's it. See the above section, +"How do skills work?"
+
+
+How +do virtual rooms work?
+
+Virtual rooms are rooms generated +on the fly by a
+virtual room server. You program +that server with
+the room descriptions, the number +of them,
+etc, and the virtual server can +make available
+a grid of rooms with your +descriptions.
+
+This allows you to create, for +example,
+a vast desert, or a large jungle, +comprised of
+dozens, or hundreds, or thousands +of rooms
+without having to manually code +each and every
+single room.
+
+For an example, take a look at
+
+/domains/town/virtual/
+
+
+How +are files organized in Dead Souls?
+
+
+See the admin FAQ.
+
+
+What +are applies, lfuns, sefuns and efuns?
+
+
+Sefuns and efuns are functions +available to all objects on the
+mud. Any object may need to know +what time() it is, so rather
+than have a time() function in +every file that needs it, which
+could be many, there is a time() +function built into the
+game that any object can use. An +efun is built into the
+driver, so there is no LPC code +to look at. A sefun is a
+simulated efun, coded in LPC. +Sefuns are kept in /secure/sefun.
+
+Lfuns are functions specific to +library objects. A shirt,
+for example, has functions that a +sword may not need, so
+the LIB_ARMOR and LIB_WEAPON +files contain their own functions,
+not shared by other files (it's +more complicated than this,
+but that's the idea). These +functions are library
+functions, or lfuns. Typically +they are found in the objects
+defined by the files in /lib.
+
+An apply is a function that is called by the +driver. Some
+examples of applies are create() and reset(). Although you
+can call many applies normally from within the mud, the
+point of them is to have some common functions known to the
+driver that it can call on objects. In the case of create(),
+it is a function that the driver calls on any new object
+loaded into memory (like main() in a C program). Many applies
+are security oriented, and are called only in the master object,
+such as valid_read() or valid_socket(). This is a way for the
+driver to be assured that a trusted security object knows
+it's ok to perform the pending "sensitive" operation.
+
+For a lot more detail on efuns +and sefuns, see the admin FAQ.
+
+
+Why +are there more sefun doc files than sefun files?
+
+Sefun files, like +/secure/sefun/strings.c, often contain
+more than just one sefun. +Therefore, there will be more
+files documenting individual +functions than there are
+files containing sefuns.
+
+
+I +edited a file but now the reload command is complaining.
+
+There are two commonly used +commands for loading
+objects: update and reload.
+
+When you want to load a file into +memory, you use
+update, for example: update +/domains/default/room/road
+
+When you want to replace a cloned +object with a
+version that uses the latest code +in a file, you
+use reload, for example: reload my +first red +sword
+
+reload doesn't work on files.
+
+update doesn't work on cloned +objects.
+
+The reason there are two +commands, instead of one all-purpose
+one, is both historical and +functional. The reason "reload"
+exists is that I got sick of +having to dest a thing, update
+its file, then clone the thing +every time I wanted to
+test changes in its code. This +was annoyingly tedious, so I
+coded the reload() sefun and +reload command.
+
+However, update works just fine, +and I wasn't about
+to try to fix something that +wasn't broken. It works, and
+LPC old timers are used to it.
+
+Further, it has a function +sufficiently separate from
+reload that it stands as a +command on its own merits.
+
+
+this_player()->GetName() +returns "A shadow" when the player is invis.
+
+Use +this_player()->GetKeyName() instead.
+
+
+Is +there a sefun for making a whole string uppercase?
+
+upper_case("omgwtfroflmao")
+
+
+What +is the difference between filter() and foreach()? How do I use them?
+
+Both of these efuns can act on +the individual members of an array.
+
+For example, if you wanted to +have an array named mystuff which
+contains the base filenames of +all objects in your inventory that
+inherit LIB_ARMOR:
+
+using filter:
+
+string +*mystuff = ({}); //This has to be a +global var
+object +*stuff = filter(filter(deep_inventory(this_player()),
+(: inherits(LIB_ARMOR,$1) :) ), (: mystuff += ({ base_name($1) }) :) );
+

+using foreach:
+
+string +*mystuff = ({});
+foreach( +object ob in deep_inventory(this_player())){
+if( +inherits(LIB_ARMOR, ob) ) mystuff += ({ base_name(ob)});
+}
+
+There are arguments favoring the +use of either. I won't get into
+it. As far as I can tell, it's +really a question of preference.
+You can structure these +functions more elegantly
+than shown here, to best suit +you. But this is the idea.
+
+
+member_array() +is returning exactly the wrong thing
+
+It probably isn't. member_array() +seems somewhat counterintuitive
+at first, because it often +returns a 0 as a "hit".
+
+What this function is doing is +checking to see whether the
+first argument is a member of the +array specified in the second
+argument, and then tells you +*which* element it is. for example:
+
+member_array( +"bar", ({ "foo", "bar", "baz" }) ) returns: +1
+
+member_array( +"foo", ({ "foo", "bar", "baz" }) ) returns: +0
+
+Why does it return 0? Because +"foo" is element 0 of the
+array. If this_array == ({ "foo", +"bar", "baz" }), then
+this_array[0] is "foo". So +member_array("foo", this_array)
+would return 0.
+
+If the first argument is not a +member of the array, member
+array returns -1. So that:
+
+member_array( +"shiz", ({ "foo", "bar", "baz" }) ) returns: -1
+
+
+Example:
+
+Does this player know how to +polka? Return 1 for yes:
+
+RIGHT: if(member_array("polka +dancing", this_player()->GetSkills()) != -1) return 1;
+
+WRONG: if(member_array("polka +dancing", this_player()->GetSkills()) ) return 1;

+The first way says "If 'polka +dancing' has an element number that isn't -1,
+then it is a member, so let's +return 1"
+
+The second way says "If 'polka +dancing' has an element number that isn't 0,
+then it is a member, so let's +return 1"
+
+The problem with the second way +is that it is possible for "polka dancing"
+to be element 0 in that array, +and if it is, your code will incorrectly
+tell you that you can't polka +dance. But worse than this is that if
+you actually can't polka dance, +this second way will incorrectly tell
+you that you can. Given random +input, the second way would be wrong more than
+half the time.
+
+
+I'm +trying to add two mappings together and the results are bizarre
+
+Adding mappings together has to +be done just so in order for
+it to work the way one might +expect. What can happen in
+mapping arithmetic is that in the +process of trying to
+add the values of one mapping to +another, you can change the
+values of a mapping you didn't +intend to. The deal is a
+conflict between passing data by +reference or by value. To
+be sure that you don't +accidentally modify an innocent
+bystander, use the add_maps() +sefun. For example:
+
+MyMap = add_maps(HisMap, HerMap);
+
+or
+
+MyMap = add_maps(MyMap, HerMap);
+
+
+When +str = "abc", str[1] is 98, not "b". What gives?
+
+What you're getting here is the +ASCII code of element 1.
+If you have to have that element +as a string, use the
+convert_ascii() sefun, like this:
+
+convert_ascii(str[1])
+
+You can instead use ranges, so +that:
+
+str[0..0] == "a"
+str[1..1] == "b"
+str[1..2] == "bc"
+
+If you use ranges, do not use the +convert_ascii() sefun.
+
+
+How +do I make an array1 that is the same as array2 but without an element?
+
+Two ways:
+
+1) array1 = array2 - ({ element +});
+
+2) array1 = filter(array2, (: $1 +!= element :) );
+
+
+How +do I pass arguments to a pointer in a functional?
+
+With commas, like this:
+
+(: eventKill, player :)
+
+Your arguments will likely need +to be constants, tokens, and/or global variables.
+
+
+What +does the tc() sefun do?
+
+It's something I coded for myself +long ago, basically
+a personalized debug(). However, +people have been
+asking for that functionality for +themselves, so
+the debug() sefun now carries +this functionality. For
+more information, type:
+
+man debug
+
+
+How +can I find out how many items are in an array quickly?
+
+sizeof(array)
+
+
+My +SetRead isn't working
+
+
You may need an item for +each read. For example,
+SetRead( ([ ({"alpha", "bravo", +"charlie"}) : "Delta.", ]) )
+
+May need something like this *above* +it:
+
+SetItems( ([ ({"alpha", "bravo", +"charlie"}) : "A thing you can read.", ]) )
+
+
+My +SetEnters/SetSmells/SetListens isn't working
+
+See above.
+
+
+Can +I nest loops?
+
+Can you? Probably. Should you? +Usually not.
+For loops and while loops are +legal LPC, and you may even
+see them here or there in older +lib code. But they
+should be avoided because they +generate much more
+lag than the more efficient +foreach() and filter() efuns.
+
+
+What +should I do or not do in my code?
+
+1) Avoid using call_out() as much +as possible.
+Use heart_beat() to time things +instead.
+
+2) Don't code stuff that +replicates itself.
+
+3) Don't code stuff that +circumvents security. For
+example, knowing that an admin is +logged on but
+invisible isn't much help to you +if he bans you
+for coding a tool to find him.
+
+4) foreach() and filter() are +faster than for() loops,
+and harder to screw up.
+
+5) switch() is faster and more +economical than if()
+for multiple evaluations.
+
+6) Don't use add_action for +something that already
+has a verb. There is no point in +making an add_action
+for "throw", for example. It's +just going to confuse
+players when your "throw" doesn't +behave the way
+"throw" does everywhere else on +the mud.
+
+7) Don't code delays by using +loops. This affects the
+whole mud. If an action is to be +delayed, use heart_beat().
+
+
+How +much different or heavily modified is Dead Souls than stock LPC?
+
+This is a difficult question to +answer on its own terms. It's
+roughly equivalent to:
+
+Is Fedora different from stock +UNIX, or will my Solaris programs work on it?
+
+This DVD movie is in NTSC format, +so my TV can handle it, right?
+
+The terms used roughly +correspond to the same general thing,
+but the assumption +here is that there is a "stock" LPC, and you
+can +transplant code from one LP mud to another.
+
+Sometimes these transplants can +be done. Oftentimes not.
+This is because LPC has been +interpreted and implemented in
+many slightly different ways by +many slightly different versions
+of many different drivers. The +end product of the DVD is a movie
+playing on your TV, but how it +gets there is very different from
+how a videocassette does it, even +if it's the same movie and its
+signal is encoded in NTSC in both +cases.
+
+If you have two LPmuds that use +different drivers, it
+can be much like the difference +between a DVD and a videotape.
+Sometimes, if the drivers are +related, the difference is smaller,
+like VHS versus Betamax, but +you'll still be embarking on a
+major project getting the movies +from one to play on the other.
+
+The result is that a coder from +Discworld and a coder
+from Nightmare can roughly speak +the same language, and discuss
+solutions to their problems that +make sense. And each coder
+could probably visit the other +mud and work with a very
+small learning curve.
+
+But the code itself would +probably require substantial
+retooling to be interchanged.
+
+
+Is +there a way to change the "default exit" room messages?
+
+A lot of folks don't like having +default exits displayed at the
+top. The muds they're used to display them at the bottom of the room
+descriptions, and that's how they want their DS mud to look. They
+don't like the obvious exits up top.
+
+In the current version of Dead Souls this is no longer the default
+behavior. Now obvious exits are displayed at the bottom, in a
+more "natural" style closer to the way LPmuds have historically
+done it.
+
+Your admin  can switch between this new way and the old way with
+the command:
+
+mudconfig nmexits [ yes | no ]
+
+
+This +dummy item is weird.
+
+Dummy items *are* weird. They +exist because the
+parsing system requires objects +to act on. When you "look
+at painting", the parser +doesn't take "painting" +as a
+string to match. Through a +magical mystical process
+deep in the MudOS driver, the +parser turns "painting" into
+an object to act on.
+It tries to find object in the +area that match
+this keyword, and if it finds +one, it sends that object
+a query about whether it can be +looked at. Depending
+on the response, the parser +continues on to determine
+what the verb (the command you +issued) thinks should
+happen to objects that can be +looked at, and tries to
+evaluate that event with the +object as its target. The
+process continues in a complex +dance of "may I?
+how so?" etc, until finally the +painting, the verb, the
+parser, and you come to an +agreement as to what the
+result of this looking should be.
+Crucial to this process is that +the painting
+actually *exist* as an object, so +it can be queried
+for various functions. Without a +"painting object" in
+the room, there's no parsing +that's going to
+happen with it.
+But what if this painting is +just part of the
+room description? You don't want +to add a painting
+to the inventory of a room just +so people can look
+at it. You want people to be able +to "look at painting",
+or "look at wall", or "look at +ceiling" without
+having to have all of these items +be part of the
+room's inventory. What a chore +that would be!
+This is where dummy items come +in. They are
+invisible objects that are set to +respond to the names
+they are assigned, such as +"ceiling", "wall", etc,
+handling the job of providing a +description when
+a person looks at the ceiling, +wall, etc. These kinds
+of dummy items are automatically +created when a room
+is loaded, based on what the +SetItems directive of
+the room contains.
+You'll also find dummy items for +special
+tasks, like a dummy button to +push in the town church.
+
+Because of this specialized +role, dummy
+items are not intended to be +picked up or manipulated
+the way regular items are. If you +clone a dummy
+item, it's not going to behave +the way you want
+it to. A dummy item should only +ever be brought into
+existence by your code, not by +the clone command.
+

+Clan +objects do nothing but screw things up.
+
+Quite right! If you don't code a +clan object
+properly, it's extremely likely +to have little effect
+aside from screwing up a player's +savefile so badly
+that it needs to be destroyed.
+Why is this? Clan object code is +basically
+legacy guild code from Dead Souls +1.x. In the old
+versions of Dead Souls, guilds +were player-run
+institutions, operating basically +as clubs, with
+guild objects as a kind of +membership token.
+The version of LIB_GUILD that +came with
+Dead Souls 1.x was fatally buggy +in various ways.
+The most important way is that +even if you got it
+to work right, it did nothing +useful. There was
+no interaction with a guild or +player daemon,
+so if the guild leader quit, they +lost their
+guild leader status. Aside from +holding an object
+which designated them as a member +of a particular
+guild, LIB_GUILD provided no +advantage.
+I renamed it to LIB_CLAN, +because as a
+social-club object, that's a bit +closer to its
+role than "guild", which tended +to cause much
+confusion.
+Eventually there will be a +CLAN_D, and more
+sophisticated error handling to +prevent character
+file corruption. For now (version +2.x of Dead Souls),
+just avoid using it.
+
+
+My +NPC's stats are all hosed up.
+
+Make sure you have SetLevel() +*after* SetRace() and SetClass().
+Also make sure there's a working +::create() in your create
+function. Some examples are:
+
+::create();
+npc::create();
+vendor::create();
+
+And make sure your init() +function has an:
+
+::init();
+
+
+This +squirrel is taking *forever* to kill.
+
+The mud is calculating its health +points based on level and
+race. If your squirrel has 340hp, +it'll seem unreasonably
+tough. Use SetMaxHealthPoints() +to cap its vitality to
+something like, say, 5.
+
+Also, humans tend to be pretty +crappy at combat, unless
+they are of the fighter class. +Even a rat can be
+a challenge for a wimpy, weak +little level 1 human. Try
+using a dwarf or an orc to fight, +or make your character
+a fighter with: call +me->ChangeClass("fighter")
+
+
+My +room should not be entered/exited by just anyone. How
+do +I control this?
+
+There are a couple of ways of +controlling entry to a room.
+Take a look at the "AddExit" +method in:
+/domains/town/room/valley.c
+
+And also review the "CanReceive" +style in:
+/domains/town/room/wiz_hall.c
+
+To prevent a room being exited +unless certain conditions
+are met, use CanRelease().
+
+These strategies are not +discussed in detail in the Creators Manual,
+but the examples above should +provide ample information as
+to how to structure them.
+
+Note that in general, objects +with a CanReceive() override
+should return ::CanReceive() +unless there is a
+good reason otherwise. It would +look like this:
+
+int +CanReceive(object ob){
+
+    <if blah return 1>

+    +<if bleh +return 0>
+    <etc and so +on>
+
+    +return +::CanReceive();
+}
+
+Obviously the stuff between the +<> symbols is pseudocode and
+not LPC.
+
+
+I +zapped a monster, but instead of being dead, now it's undead!
+
+Take a look at the code for this +NPC. It probably has
+eventDie() overridden in a way +that does not return 1. This is
+not necessarily wrong. You may +*want* a monster that doesn't
+die like normal monsters do. But +if this behavior is unintended,
+that is probably the cause.
+
+
+How does the format for race files work?
+
+Race attributes are specified in +race files. They are found in
+/secure/cfg/races
+
+Here's a template with parameters +in parentheses for clarity:
+
+RACE (race name here)
+SENSITIVITY (low light +threshold):(bright light +threshold)
+LANGUAGE (self-explanatory)
+RESISTANCE (damage type):(how +resistant we are +to the damage)
+STATS (name of the stat):(the +average):(how +important. 1 is high)
+LIMB (limb name):(where it +attaches):(how +important. 1 is high):(armor types)
+SKILL (skill name):(starting +level):(how +important. 1 is high):(unused):(unused)
+
+The unused fields in the skill +section are reserved for
+future implementation.
+
+If the third field in the LIMB +line is 1, losing that
+limb will cause immediate death.
+
+Special keywords can be appended +for particular functionality.
+These are:
+
+FLYINGRACE (enables flying)
+LIMBLESSRACE (enables limbless +travel)
+LIMBLESSCOMBATRACE (enables +limbless combat)
+NONBITINGRACE (some races can't +or won't bite)
+NOT_MEAT (specifies that when +it dies, a meat corpse shouldn't appear)
+SWIMMING_RACE (enables travel +in water)
+PLAYER_RACE +1 (enables the selection +of this race +for players)
+
+Please note that while the +LIB_BODY object does
+specify a number of fingers, they +aren't items that
+can be severed, and their purpose +mostly is determining
+what kind of gloves you can wear.
+
+NOT_MEAT is available in Dead Souls alpha 19 and above.
+If NOT_MEAT is specified, then an npc of that race should
+have SetBodyComposition() in its create() function.
+For example, a rock golem should have:
+
+SetBodyComposition("rock");
+
+Please see /domains/default/npc/dummy.c for an example.
+
+If an npc's race is NOT_MEAT, and it is not a robot,
+and SetBodyComposition() is absent, it may not leave
+any remains at all upon death, unless it has a composition
+set by default in /lib/races.c
+
+There are also the following additional racial options:
+
+ + + + + + + + + + + + + + + + + + + + +
MASS
+
An +integer corresponding roughly +to weight on planet Earth, in pounds, multiplied by 10.
+
SIZE
+
/include/size_types.h
+
RESPIRATION_TYPE
+
/include/respiration_types.h
+
BODY_TYPE
+
/include/body_types.h
+
+
+
+How +does the format for class files work?
+
+Class files have only three types +of
+entry lines that Dead Souls +currently supports.
+The first is the name of the +class.
+
+PLAYER_CLASS is 1 if it's a class available to players. 0 if not.

+Every line after that is +presumed to be
+a skill specification line, in +the following
+format:
+
+skill name:importance to the class (1 is highest):starting level
+
+
+What +do Properties do?
+
+Properties are a way to provide +flexibility in
+the lib. Objects usually work by +having variables
+that are modified by functions. +This allows a player
+to have, for example, a SpellBook +variable which
+contains the spells she knows, +and this variable in
+turn is affected by "spell +learning" functions, etc.
+
+Suppose, however, that I want to +set a
+variable in a player, but that +variable does not
+exist. This is tricky indeed, +because it would
+involve a modification to one or +more library objects,
+and reloading them...possibly +requiring re-logins
+or (very rarely) even rebooting +the mud.
+
+Instead you can use properties +as a quick
+and dirty way to get that +functionality without
+rewriting lib objects. For +example, if you do
+something like this:
+
+present("lamp",this_player())->SetProperty("blessed", +1);
+
+Then that lamp is blessed, and +maybe now
+a monster has a function like +this:
+
+if(present("lamp",this_player())->GetProperty("blessed")) +RunAway();
+
+SetProperty() and +SetProperties() are just
+convenient ways to create and +modify custom variables in
+objects and players on the fly. +Strictly speaking this
+is not good coding practice. +Anything useful enough to
+make into a Property is useful +enough to do in another way.
+However, it is available to you +as another implement
+in your coders' toolbox.
+
+
+How +do I add a prehensile limb to a player or NPC?
+
+victim->AddLimb("tentacle", +"torso", 2, ({A_WEAPON }))
+
+See the Creator's Manual for +details on adding, desting,
+and removing limbs.
+
+If a creature lacks a prehensile limb, they can't do
+things like get objects, wear clothes, wield weapons, etc.
+
+
+How +do I make a room occasionally display messages?
+
+Use SetAction. There is a +well-commented example
+of this in +/domains/town/room/shore.c .
+
+
+My +functional isn't working!
+
+Functionals are a kind of +reference to a function. They
+won't work everywhere. For the +most part they serve as a pointer,
+and are used the way a variable +would be used. If the place you
+put the functional wouldn't make +sense for a variable, it wouldn't
+make sense for the functional +either. For example,
+
+SetLong( (: ShowLong :) );
+
+makes sense, because what's +happening is that instead of
+a string, your argument is a +function that returns a +string.
+
+However, something like this +wouldn't work,
+
+if( Cabbages == Kings ) (: +eventTalk :);
+
+because you're treating a +functional as if it were a function.
+It isn't. In a case like this, +your line should look like this:
+
+if( Cabbages == Kings ) +eventTalk();
+
+
+I've +read the Creator's Manual but I still don't understand mappings and +arrays.
+
+Yeah, they can be tricky to get +a handle on. Let's suppose you're
+going to set up a nautical +commerce system, where you have to keep track
+of ships and their data. You +store ship data in a daemon, which is
+an object that stays loaded in +memory to manage information, but doesn't
+actually exist as a cloned item +in the game. We'll call it SHIPPING_D.
+
+So, SHIPPING_D needs to keep +track of how many ships there are.
+I would do this with an array, +not a mapping, because it is a simple
+list, like this:
+
+string *ship_list = ({ "Caine", +"Bounty" });
+
+That way, when SHIPPING_D gets +queried for a list of all known
+ships, it can just return that +simple list. If you needed to add a
+ship, you'd have the daemon +perform this operation:
+
+ship_list += ({ "Pequod" });
+
+To remove a ship:
+
+ship_list -= ({ "Caine" });
+
+Suppose, however, that not only +do you need to keep track of
+ship names, but also their +captains, crew complement, etc. You could try
+to use an array for this, but it +would be very unwieldy. This is because
+to pick out specific elements, +you need to use a number. For example,
+if the ship_list array is ({ +"Caine", "Bounty", "Pequod" }) then
+ship_list[0] is "Caine" and +ship_list[2] is "Pequod".
+If you were to try having an +array for each ship that
+contained complex information, +you'd have stuff like this:
+
+ship_list += ({ "Caine", "Queeg", +117, "military", "destroyer minesweeper", 0 })
+
+There are a couple of problems +with this. First, the ship_list
+array is going to be a bit of a +mess. Second, you'll have to address the
+ship's data elements by their +array index number. For example, to know
+the Caine's crew complement, +you'll need to do something like this:
+
+foreach(string *ship_data in +ship_list){
+if(ship_data[0] == "Caine") +return ship_data[2];
+}
+
+The first step is to check each +element in ship_list to
+know if its first element is +"Caine", then return its third element,
+which is 117. Not only is this +inelegant and overcomplicated,
+it is not guaranteed to work. +Careless manipulation of your subarrays
+can result in elements being out +of order, with potentially
+disastrous results on your code. +It's just not a wise way to
+go about this. This is where +mappings come in. Rather than the mess
+above, we'd do it like this:
+
+mapping AllShips = ([]);
+
+AllShips["Caine"] = ([ "captain" +: "Queeg", "complement" : 117, "type" : "military",
+"class" : "destroyer +minesweeper", "cargo" : 0 ]);
+
+It looks more complicated, but +in fact it's a major simplification
+of your data and its access. Now +you have a sure-fire way to query
+a specific ship and its specific +data elements without a shadow of doubt
+as to what you'll get back.
+
+Now if you want to know the name +of the Caine's captain,
+it looks like this:
+
+return +AllShips["Caine"]["captain"];
+
+Basically this is a mapping +inside a mapping. The mapping called
+Caine contains the element +"captain". Because the mapping Caine is an
+element in the mapping AllShips, +you access an element in it in the way
+shown above.
+
+In a less complicated example, +mappings might be used, for
+example to store information +about, say, fish:
+
+mapping FishTypes = ([ "carp" : +"freshwater", "tuna" : "saltwater" ]);
+
+So that FishTypes["carp"] is +"freshwater".
+
+To remove a mapping element, use +the map_delete efun:
+
+map_delete( FishTypes, "carp" );
+
+
+Why are call_outs so bad?
+
+Garfield@M*U*D +<ds> I'm wondering.. Why are call_outs so bad?
+
+Cratylus <ds> ya good +question
+
+Cratylus <ds> in themselves +they arent. One call_out more or less wont make the angels cry
+
+Garfield@M*U*D +<ds> From what I can tell, they shouldn't be too bad if not +implemented poorly.
+
+Cratylus <ds> the problem +is that if your creators get the idea call_outs are ok, you'll be +swamped with them
+
+Garfield@M*U*D +<ds> Right. You want 10s of them, not 100s.
+
+Cratylus <ds> and they, for +reasons i cant explain to you because it's driver related, are +expensive to run
+
+Garfield@M*U*D +<ds> Can't explain because you're not familiar with the driver?
+
+Cratylus <ds> right
+
+Garfield@M*U*D +<ds> Right. Fair 'nuff.
+
+Cratylus <ds> but i can +vouch for the truth of the proposition
+
+Cratylus <ds> limbs used to +decompose, each with a call_out of its own
+
+Cratylus <ds> if you +released the rage virus into the menagerie, your mud would eventually +crawl to a stop
+
+<ds> +Garfield@M*U*D hehs.
+
+Garfield@M*U*D +<ds> What amount of call_outs are we talking here? Hundreds? +Thousands?
+
+Cratylus <ds> fewer than +200 as i recall
+
+Cratylus <ds> but the +memory is hazy
+
+Garfield@M*U*D +<ds> Hrm. Ick.
+
+Garfield@M*U*D +<ds> I might peek at how they work.
+
+Cratylus <ds> it also +redlined the processor
+
+Garfield@M*U*D +<ds> Right.
+
+Cratylus <ds> lucky for me +i have a 4-way box
+
+
+Fine. +How am I supposed to create timed events, then?
+
+There is a built in timing +system that uses the heart_beat()
+efun. To enable it, use +set_heart_beat() on the object that is
+to have a timed effect. +set_heart_beat(1) gives the object about one
+heart_beat per second. +set_heart_beat(60) gives it a heart_beat
+about once a minute.
+
+Whenever the object has a +heart_beat happen, the function
+heart_beat() is called in it. So, +for example, an NPC might have
+a heart_beat function like this:
+
+void heart_beat(){
+this_object()->eventForce("say hi!");
+}
+
+If the NPC's create() function +contains a set_heart_beat(10)
+then it will say "Hi!" every ten +seconds.
+
+Another way to control it would +be to have a counter.
+You would define a global integer +variable by putting in in the body
+of the NPC's file before any +functions are defined. For example:
+
+int counter = 0;
+
+somewhere before the create() +function. Then your heart_beat
+function might look like this:
+
+void heart_beat(){
+counter++;
+if(counter > 10) {
+this_object()->eventForce("say hi!");
+counter = 0;
+}
+}
+
+If the NPC's heart_beat is set +to 1, then the NPC will make
+his greeting about every ten +seconds. If its heart_beat is set to
+ten, then it'll take a minute and +forty seconds per greeting. Note
+that at the end of the if() +check, the counter is reset to 0 if
+the action is triggered.
+
+
+I +need a list of all the functions available.
+
+Type the following:
+
+efuns
+lfuns
+sefuns
+
+If you read the section on efuns +and sefuns, you have an
+idea of what they are. They are +documented in /doc/sefun and
+/doc/efun , and doing a list of +the dirs and subdirs there
+will give you a "list" of them. +The documentation on individual
+sefuns and efuns is generally +available through the man command,
+for example: man sscanf
+
+
If you're looking for +lists of library functions,
+such as SetClass in LIB_WEAPON, +your best bet is the help
+command, like this:
+
+help library +objects weapon
+
+help library +objects creator
+
+That will list the functions in +the library object
+you specify. As of this writing, +the documentation on lfuns
+is not yet as thorough as the +documentation on efuns and sefuns,
+but this documentation is an +ongoing project whose output
+should eventually improve.
+
+See also question +2.71
+
+
+How +do I make an object you can [ jump on | climb | etc ] ?
+
+Look for an example, and copy +it. Take a look at the
+code in the newbie mansion ladder +for climb code. Take a look
+at +/domains/Ylsrim/room/bank_roof.c for an example of something
+you can jump from. Other actions +will have similar examples. The
+sample domains are there for you +to explore and find examples
+of what you want to do.
+
+
+Where +is the list of available skills? How do I add skills?
+
+Please read the Administrator's +Guidebook chapter
+entitled "Understanding the Lib", +and skip to section named
+"Section IV: Skills".
+
+
+Where +is the list of available classes? How do I add a class?
+
+Type: ls +/secure/cfg/classes
+
+To add a class, copy one of +those files and call it
+whatever the class should be. For +example:
+
+cd +/secure/cfg/classes
+cp thief farmer
+
+The modify the new file to suit +you. When
+you're done, use admintool to +add the class to the class
+daemon. Type help admintool +for information on that command.
+
+Obviously, you'll need to be an +admin or assistant
+admin for this to work.
+
+
+Where +is the list of available races?
+
+Type: ls /secure/cfg/races
+
+For details on adding races, see +the admin +FAQ.
+
+
+How do languages work? Is there a list of them?
+
+There is no list of languages. +It doesn't work that way.
+There is no centralized language +database, daemon, or anything
+like that. Languages are +basically like a skill: only useful to
+the extent that lib objects make +use of them.
+
+A player might be able to +understand Tamarian, but if
+nobody else in the lib does, it +isn't much use. If no written material
+is in Tamarian besides, then the +player's language ability is a waste.
+
+On the other hand, if a player +wants to be able to
+understand orcs, all she has to +do is find a language teacher
+that can instruct her in that +tongue. After enough lessons,
+she will be at 100% fluency, and +if she encounters written or
+spoken information in Tangetto, +she'll be able to understand
+all of it.
+
+To know what languages you +understand, and to what
+extent, use the command:
+
+language
+
+To make yourself fluent in +English, type:
+
+anglicize me
+
+To make yourself fluent in all +languages, type:
+
+polyglottize me
+
+Obviously these commands are +available only to creators.
+
+
+When +I try to call Bozo->SetLanguage("Clownish", 50), it sets it to 100%
+
+Bozo is probably a newbie. If +Bozo's player level is at or below
+what is defined as newbie in +/secure/include/config.h, then he understands
+all languages at 100%. Raise his +level above that, and you should see
+his proficiency in that language +drop to what you specified.
+
+
+How +do I update an .h file?
+
+You don't, really. That's a +header file, which contains code to
+be included by a .c file. Only a +.c file gets loaded into memory, so
+to "update" an .h file, you +update the .c file that includes it. In
+the case of a global include, +like daemons.h, you would update the
+master object (also called the +master daemon) thusly:
+
+update +/secure/daemon/master
+
+
+
+I +want to put an object in a room that doesn't show up in the inventory
+but +it can be manipulated.
+
+Typically the job of "being +invisible but examinable" is something
+done by dummy items. In FAQ +2.39 you read about how dummy +items work and
+how they let you have things in +rooms that are looked at, but not taken.
+
+Suppose, however, that you want +to have a sittable bench in the long
+description, but you don't want +it to show up in the room's inventory. Or
+a chest that can be opened and +closed, but again, not part of the
+room's inventory list?
+
+You can't just make the item +invisible, because then "look at bench"
+will return "There is no bench +here." The solution is to *inherit* a
+dummy item, and and give it +benchy functionality by also inheriting the
+things a sittable object needs. +For example:
+
+#include <lib.h>
+inherit LIB_BASE_DUMMY;
+inherit LIB_SIT;
+inherit LIB_SURFACE;
+
+static void create() {
+
    base_dummy::create();
+
    +surface::create();
+
    +SetKeyName("bench");
+
    +SetId("bench");
+
    +SetAdjectives("wooden");
+
    +SetShort("a wooden bench");
+
    +SetLong("This is a typical +wooden bench, the sort you might "+
+
        +"see in a park. It appears +designed for sitting on.");
+
    +SetMaxSitters(3);
+
    +SetInvis(1);
+    SetPreventGet(
"The bench does not budge.");
+}
+
+
+You can then add this file to +your room's inventory,
+and now you'll have a bench that +doesn't show up in the
+room's inventory, but can be +examined and used. In the case of
+a chest or a wardrobe, you'd want +to inherit LIB_DUMMY
+and LIB_STORAGE. There are some +key rules to keep in mind when
+doing this:
+
+
    + +
  1. Always inherit +LIB_BASE_DUMMY first.
  2. + +
  3. Always invoke +dummy::create() +before other ::creates()'s.
  4. + +
  5. Make sure you have CanGet() +return an error string.
  6. + +
  7. Make sure the item is +SetInvis(1).
  8. +
+
    + +
+In Dead Souls 2.5a21 and below, +inherit LIB_DUMMY, not
+LIB_BASE_DUMMY, and use dummy::create(); rather than
+base_dummy::create();
+
+

+What +is pass by reference? What is pass by value?
+
+This is a slippery concept to +grasp for many folks. It has
+to do with the way that a +variable is handled, when it interacts
+with a function.
+
+When you pass by value, you send +to the function the
+value that is held by the +variable. When you pass by reference, you
+send to the function a pointer to +the variable, not the value that
+it contains. This is critically +important to what happens to the
+variable when the function is +done doing its work. Let's take a look
+at a sample function:
+
+function drawingThis +is your typical simple function. +It
+wants to be fed some input at the +top, then
+it will digest it in the middle, +and then
+it will poop out whatever the +result of its
+digestion is. That's the return, +down at the
+bottom.
+
+This one wants to be fed an +integer. When you
+put the integer into its feeding +funnel at the
+top, that integer will be stored +in the function's
+local variable "B". B will stand +for that integer.
+
+The function then adds the +integer 1 to B. B is now
+whatever you put into the +function plus one.
+
+This new value is what is now +returned, when the
+function completes.
+
+Pretty straightforward. Let's +look at actually
+sending data to this function.
+
+
+
+pass by valueAt the top of this +illustration you see a variable called "A".
+A is of the type "integer", and +it contains the value 42. We're
+going to feed A to +SimpleFunction. We will "pass by value".
+
+What is happening is that +whatever it is that A contains as a
+value, we are sending to our +function. We therefore are feeding
+the integer 42 to SimpleFunction.
+
+SimpleFunction does its thing. B +is now equal to 42. Then
+we add 1 to it. Now B is equal to +43.
+
+We are done. The function poops +out 43 as the return value.
+B is a local variable, so when +the function ends, its value
+resets and it is null. At the end +of this process:
+return value == 43, A == 42, B == NULL
+
+
+pass by reference
+We will now +send data again, but this +time, we will "pass by reference".
+This is slightly different. In +the previous example, we passed the
+value of A to SimpleFunction. +Instead, we will now pass a +reference to A to the +function. For all +practical purposes we are not sending 42. We are sending the variable A +itself.
+
+The implications are +important. +When we feed A to SimpleFunction,
+B no longer means "a local +variable named B". B becomes a pointer
+to A. This means that even though +the function, as written, reads
+B = B + 1, when you pass by +reference you are actually performing
+the operation on the referenced +variable itself, so what it's actually doing is A = A +1. At the end of +this process:
+return value == 43, A == 43, B == NULL
+
+
+
+You can see why it is vitally +important to grasp this concept.
+If you perform a pass by +reference operation, you will get the exact
+same return, or output, from the +function as if you had passed by
+value. However, you will have +modified the variable you passed to the
+function. If that's what you want +to do, great. But if you do it
+by accident, woe is you.
+
+Note that in ds2.1a16 and above, you can use the "ref" keyword
+to force a simple variable to pass by reference. For an example,
+see /domains/default/obj/pass_example.c
+
+
+ZOMG +pass by reference is terrible! How do I avoid it?
+
+Fortunately, simple LPC +datatypes do not pass by reference
+as default behavior. Strings and +integers pass by
+value, so you don't have to worry +about accidentally mangling
+that data.
+
+However, objects, mappings, +functions, and arrays all
+pass by reference. If you are not +careful in handling those datatypes,
+you can end up with some +extremely puzzling outcomes. When
+manipulating complex datatypes, +it is useful to use the copy()
+sefun, if you don't want to +modify the original variable. for
+example:
+
+string *SubtractElement(string +*InputArray){
+string *LocalArray = +copy(InputArray);
+LocalArray -= ({ LocalArray[0] });
+return LocalArray;
+}
+
+This function takes a string +array as an argument,
+and returns an array that is like +the input array, but without
+its first element. By using the +copy() sefun, we manipulated
+the an array identical to +InputArray in value, while leaving
+InputArray itself alone. If +instead of:
+
+string *LocalArray = +copy(InputArray);
+
+we had used:
+
+string *LocalArray = InputArray;
+
+Then the return value would have +been the same, but
+whatever the array was that we +passed to this function as an
+argument has been modified.
+
+
+What +does the :: operator do?
+
+Detah <ds> does anyone have +time to explain 1 line of code to me please. specifically score.c L15 +daemon::create()
+
+Cratylus +<ds> hmm
+
+Cratylus +<ds> the :: is the "scope resolution operator"
+
+Cratylus +<ds> that line says "in the file i inherited called daemon, run +the create function"
+
+Detah <ds> so to understand +that line, I need to go to daemon.c and read the create() fun there?
+
+Cratylus +<ds> yep
+
+Detah <ds> ty
+
+Cratylus +<ds> np
+
+

+I +know this file is fine. I +copied it from another file that
+works, +but it won't update. This is driving me insane.
+
+There are few circumstances under +which a properly-coded file will not update:
+
+1) Files placed in /tmp will not +update.
+
+2) Verbs placed outside the /verb +dir will not update.
+
+3) Dead Souls does not handle +files with spaces in the name.
+
+4) If the file you copied from +has a relative include (such as #include "./customdefs.h" )
+and you copy that to a different +directory, the relative include will make
+the update fail if you don't +have the header file where it expects it.
+
+5) If the file has a +SetInventory() that contains broken files or broken filenames or
+files that do not exist, the +update will probably fail in some way.
+
+6) Files in directories that +aren't readable to you won't update.
+
+7) .h files do not update.
+
+8) Dead Souls is case-sensitive. +My_New_Room.c is a different file from my_new_room.c .
+
+
+What +is SetEncounter supposed to do?
+
+When objects meet in the same +environment, they call SetEncounter()
+in themselves to see if anything +interesting should occur, based
+on the other items in the +environment.
+
+In the case of an NPC, +SetEncounter(50) means "if a living thing
+comes into the room, and its +charisma is lower than 50, kill it".
+
+To make it always aggressive, +you'd set that to an appropriately
+high number.
+
+Alternately you can put a +function pointer in there, to make a
+more sophisticated condition for +attack, or perhaps something
+other than combat.
+
+See /domains/town/npc/orc.c for +an example.
+
+
+
I keep getting +"This should be edited by hand. Change cancelled."
+
+
+The QCS is carefully designed +and +calibrated to prevent you from
+creating broken objects or damaging working ones. Even so, it is
+possible to make very inconvenient mistakes with it.
+
+One of the most common ways for a newbie to shoot himself in the
+foot is by altering their workroom in a way he doesn't understand,
+then being unable to restore it to its original state.
+
+The workroom therefore has a feature that prevents it from being
+modified with the QCS. If you go to your workroom and type
+more here , you will see that +SetNoModify(1) is in the file. This
+makes the QCS refuse to make changes to the file.
+
+To make changes to your workroom, either use the mud's line editor,
+or use the following command while standing in your workroom:
+modify here setnomodify 0
+
+By setting SetNoModify(0), you enable QCS to make changes to the room.
+
+Note that asking for help fixing a workroom you screwed up
+is an excellent way to brand yourself a Hopeless Newbie.
+
+
+zOMGLOLERZ I +did what said but no my workrom really IS broke!!1!
+
+In the inevitable case of someone damaging their workroom despite
+my warnings and safeguards, your homedir contains a default
+backup workroom file. To restore your workroom to its original,
+working form, type:
+
+cd
+mv workroom.c workroom.fukt1
+cp workroom.bak workroom.c
+update workroom.c
+home
+
+
+I can't find +the SetQuatloos() lfun anywhere!
+
+One of the reasons people want a "list of all functions" is that
+tracking down where a given function is defined can be a real pain.
+
+For users of Dead Souls 2.1.1 and below, the only real option is
+to do the following:
+
+cd <directory to be searched>
+grep SetQuatloos *
+
+This will search the files in your current directory and list to
+you the files that contain your search string...in this case, +SetQuatloos.
+
+Users of 2.1a15 and above have more options available to them. They
+can use recursive grep:
+
+cd /lib
+grep -r SetQuatloos *
+
+This allows you to search not just your current directory, but all
+subdirectories as well.
+
+Neater still is the findfun command:
+
+findfun SetQuatloos
+
+This is more precise than grep. "grep" will tell you where the string
+exists, but this includes places where it is called. "findfun" will tell
+you where in /lib the function is defined, +which means that it tells you
+which files contain the code that SetQuatloos() uses.
+
+For more information on finding and analyzing library functions, see:
+help findfun
+help showfuns
+
+
See also Question 2.54
+

+
+
+You said that what I want to do requires a daemon. I +am afraid.
+
+Think of a daemon as a kind of server program inside the mud. It
+just runs in the background, waiting to be called upon to perform
+some action. What daemons are commonly used for is managing information.
+If I told you that your project probably needs a daemon, it's probably
+because you're planning on saving some kind of information across +reboots
+that needs to be accessible to everyone. For example, if you're going
+to implement a railroad, you probably want to keep track of which
+train is where, what the different ticket prices are, etc. A daemon
+would serve as a repository of that data, managing the information
+and saving it in an object persistence file so it is preserved in
+case of reboot.
+
+There are many kinds of daemons. Some handle intermud connectivity,
+some handle player information. They are nothing to be afraid of, they
+are LPC objects with a job to do. Some of them are very large
+and have complicated code because they have big, complicated jobs.
+If, for example, you aim to play with the "master daemon", which
+handles mud security, you should be very sure you know what you're +doing.
+
+But by examining how other daemons do their thing, and by keeping
+frequent backups, and by the process of patient, persistent trial-
+and-error, you'll eventually ramp up to where your daemon code
+does what you want.
+
+
+
LOL I tried to +show something to someone in the shop but the vendor gave an error.
+
+This, and some other situations on the lib, are "bugs" that I plan
+to leave in place on purpose.
+
+The point is to illustrate an important aspect of parsing on Dead
+Souls. The shops inherit LIB_SHOP, meaning that they have add_action()'s
+that try to intercept some commands and feed them to the vendor in
+a way the vendor finds meaningful...for example, rather than
+"ask oana to show omni", you +can just "show omni" and Oana +gets the
+right idea as to what to do.
+
+If you then want to use the "show" verb, like "show omni to cratylus"
+because you want me to see what you just bought, the shop will intercept
+that "show" command before the verb gets processed, and Oana will
+get involved. If you leave the room, though, the "show" verb is
+no longer overridden by the shop's add_action() and you'll be
+able to impress me with your purchase.
+
+Why am I leaving this "broken" behavior in place? It's important for
+new admins to understand this interaction between add_action()
+parsing and verb parsing. It helps you understand how messy it can
+be when 3 or 4 objects in the same room have add_action()'s with
+the same trigger command, and it makes it more obvious why a lib-wide
+verb handler makes so much sense.
+
+
+
2.74 My object +keeps failing with an eval cost too high error.
+
+MudOS is a single-threaded program. Things have to happen one
+after the other. You cannot, for example, simultaneously search
+a large file for a string while the mud does something else.
+While the string is being looked for, nothing else happens on
+the mud until that operation completes.
+
+What this means is that if someone has coded an object carelessly,
+and it, for example, gets stuck in an enless search for a string,
+then the mud could be hung indefinitely.
+
+Fortunately, MudOS keeps track of how long a specific operation
+has been running, and there is a threshold for aborting an
+operation that has been hogging too much time. If your messed-up
+string search goes on beyond that threshold, the mud will stop
+it and return the eval cost too high error you've seen.
+
+While this might seem, on the surface, presumptuous, it is actually
+a very, very good thing. You do not need your mud lagging every
+few seconds because someone's ill-conceived NPC is hogging the
+thread. Nor do you need your creators able to bring your mud to
+a screeching halt through casual carelessness.
+
+However, sometimes you need to perform an operation that does
+take a long time. For example, you might want a way to index
+the files in your mud. With the DS distribution containing
+thousands of files, and disk I/O being the slowest operation
+a computer does, this would be made difficult.
+
+The answer is to break up the execution of a single operation
+into multiple operations via call_out(). A call_out will schedule
+the call of a function in its own execution stack. If your
+operation can be split up into multiple call_outs, then you
+have a better chance of avoiding the eval cost runtime error.
+
+For a specific example, see how the /secure/daemons/file.c
+daemon does its nightly indexing of lib files.
+
+Note that careless use of the call_out() efun in an attempt
+to evade eval cost restrictions can cause your mud to
+lag horribly. Use call_out() with extreme +caution.
+
+
+Please explain +( foo ? bar : baz )
+
+This is a spiffy and simple way to return a value based on
+the truth of a tested statement.
+
+Basically,
( foo ? bar : +baz ) means:
+
+If foo is true, then the returned value of this statement
+is bar. If it is not true, then the value of this statement
+is baz.
+
+An example might be:
+
+write("Pat folds a " + ( (pat->GetGender() == "female") ? "blouse." +: "shirt." ) );
+
+For the purposes of the test, the integer 0 counts as "not true" while
+a non-zero integer counts as "true". A defined variable of a non-integer
+type will tend to count as "true".
+
+This type of statement is sometimes referred to as a "ternary +conditional".

+
+
+Where are +things like Town and race and starting money set for new players?
+
+The place to start looking is /secure/lib/connect.c
+Then review /lib/player.c for the "enter the game" and setup
+functions called by connect.c
+
+

+How do I make +my NPC respawn sooner than the reset interval?
+
+To make a room check its inventory every 60 seconds and clone
+Lars if he's missing from that room:
+
+    SetInventory(([
+        "/domains/town/npc/lars" : +({ 60, 1})
+      ]) );
+
+You can use this to restock containers as well. For an example
+of an automatically restocking weapons rack, see +/domains/default/obj/rack.c
+in Dead Souls 2.7a27 and above.
+

+Note that if you use this method +for wandering monsters, your mud may
+soon be swamped with them, because the room only checks whether
+the object is in the room, not +whether it is in the mud.
+
+
+
My TalkResponse +NPC doesn't work, but it really really should!
+
+This is most often caused by the NPC not understanding the language
+that the player speaks. If the NPC's level is above MAX_NEWBIE_LEVEL,
+he only understands the languages his race gives him. Therefore
+your 10th level elf soothsayer hears your human's request for
+a prophecy just fine...he just doesn't understand Common or English,
+so he doesn't know what the human is actually saying.
+
+To make an NPC understand all languages, add this to his create() apply:
+
+SetPolyglot(1);
+
+

+
+
How do I load +an object?
+
+Some LP libs use the command "load" to read an object's code into
+memory. On Dead Souls, "load" is a verb used to do things like
+put bullets in a gun.
+
+The command to have the mud read an object's code into memory is +"update":
+
+update /path/to/object
+
+

+
+
Section 3: Intermud and channel stuff
+
+
+How +do I know what other muds are online on intermud?
+
+Type: mudlist
+
+
To see online Dead Souls +muds type: mudlist -m dead
+

+
+
Hey, +LeetFooMud is online! How can I tell if Biff is logged on?
+

+To see who's logged on: rwho +leetfoomud
+To tell Biff hello: tell biff@leetfoomud +hello
+To see if Biff is listening to <ds>: +list ds@leetfoomud
+To check out Biff's personal +info: finger +biff@leetfoomud
+
+

+That's +weird...mudlist says LeetFooMud is there but I'm not getting anything +back.
+
+The mudlist command reports on +data retrieved the last time
+the intermud daemon received an +update. This means that if
+LeetFooMud dropped off, say, 10 +minutes ago, or if your own
+intermud connection is down, your +intermud commands are falling
+into the void.
+
+To see if your intermud +connection is up, type: wiz
+This takes you to the Creator's +Hall, where a sign indicates
+your mud's intermud connection +status.
+
+You can also test your mud's +intermud connection with
+the ping command, like this:
+
+ping dead souls
+
+ping frontiers
+
+
+I +heard there are intermud channels that talk between other muds,
+not +just Dead Souls muds. How can I use them?
+
+Ask your admin. Those channels +may not be open for
+use on your mud.
+
+If you talk on <intercre>, +be polite, and use the same rules
+of common sense and intelligent +questioning that you need
+to follow for <ds>. +<intercre> is for +code +and technical
+questions ONLY. Do not ever +spam it or use it for +chatting.
+
+I strongly discourage you from +talking on <intergossip>. +I
+assure you nothing good will come +of it.
+
+
+How +do I emote on a channel?
+
+Add the word
+"emote" to the channel command. +For example:
+
+creemote +compels your silence.
+
+gets seen on the channel as:
+<cre> +Cratylus compels your +silence.
+
+You can also add a colon to the +message, like this:
+
+cre :compels +your silence.
+
+
or
+
+
cre: wants you to +shut up.
+

+
+How +do I see what I missed on a channel?
+
+To see the recent messages, use +hist. For example:
+
+hist ds
+
+To see older stuff, look in +/log/chan/archive
+
+
+I +am sick and tired of the *gjs intermud network going down. Please fix +it.
+
+See the Dead Souls Intermud +Router page.
+
+
+I +just wanna chat. Is there a dchat channel?
+
+Yes!
+
+If you really want just to chat, +then use <dchat>,
+since that's what it's there for. +Ask your admin for how to
+do this. I'd rather you expose <dchat> +to your boredom
+than <ds>.
+
+You can also try out <intergossip>. +Ask your admin
+for details on that, as well. Be warned that <intergossip>
+can be expected to contain extremely coarse language and
+attitudes. You're really much better off not going there.
+
+Alternately, there's a <ds_test> +channel which is
+intended specifically for spammy +channel tests and such.
+
+
+I'll +spam if I want to. You're not the boss of me.
+
+It's true, I can't do much if +you're determined to be a
+jerk. If you consistently abuse +channels, your admin may
+be asked to limit your channel +access. In extreme cases,
+your mud may find itself banned +from the channel in
+question.
+
+I can only appeal to your sense +of fair play.
+Spamming hurts people who have +nothing to do with whatever
+you're pissed off about. Please +don't make whatever your
+problem is with someone a +headache for everyone.
+
+
+This +guy keeps hassling me on an +intermud channel
+
+Sometimes people just can't leave +well enough alone,
+and they spam. Some people just +don't have anything
+to say that you want to hear. For +such situation,
+use the earmuff command. For +example:
+
+earmuff +tatianna
+
+And you will not receive channel +messages from
+that person. The reverse command +is unmuff.
+Earmuffing is also good when +someone from
+a non-European-language mud sends +well-meaning
+but garbled, escape-code filled +gibberish. If
+she doesn't understand your +English language
+requests to stop spamming, you +can just earmuff her.
+
+
+What's the deal +with channel rules and banning and whatnot?
+
+Here are the router rules: http://lpmuds.net/intermud.html#rules
+
+Basically, if you spam, or try to use the intermud router
+commercially, or try to use it to hack or hurt other people,
+or use hate speech, you're going to run into problems of
+some sort. If I happen to be the one catching it, you're
+liable to be banned for it on the spot, though I usually
+make numerous warnings to a mud before taking the
+drastic step of banning them from a channel.
+
+Note that another vector for channel banning is abusing
+a channel by not respecting the channel topic and customs. If
+you insist on swearing and/or being hostile on <ds> (a channel
+for friendly Dead Souls talk) or <dchat> (a channel for
+friendly general chat) despite being warned, you may
+find that you aren't able to use those channels.
+
+On the other hand, being crude and obnoxious on
+<intergossip> is entirely acceptable, within the
+limits of router rule 5 (no commercial advertising,
+hate speech, etc).
+
+Some people have found it unpleasant that I enforce the
+router rules. I understand that they are people who
+are arguing their point from a good faith belief in the
+righteousness of their position. However, the reality is
+that one guy runs the router, and enforcement is up to
+that one guy, and that's me.
+
+The point of the router is to have a productive environment
+where muds can communicate and conduct their business,
+promoting the health and growth of new LP muds. If I
+have to seem like a fascist in order for that to be
+so, then so be it. But being a fascist is not the point.
+
+For more context:
+http://dead-souls.net/articles/chanban.html
+
+http://lpmuds.net/forum/index.php?webtag=LPC&msg=177.22
+
+

+3.12 Hello? +Anyone here? Can someone answer a question for me?
+
+It's usually better just to ask the question. If you just
+ask the question, then someone who is idle that moment,
+but comes back in a half hour, can see it, and answer it
+if they can. However, if they come back after a half
+hour and what they see is "can someone help me?", then
+they my have less interest in seeing if you're still online
+and still have a question.
+
+Also, keep in mind that if someone says "yes, I'm here,"
+now they are on the spot, and may feel obligated to
+help you. Folks unsure whether they can help may be
+reluctant to put themselves in a position where they
+could look silly. If you just ask, and they *do* know,
+they can respond.
+
+So, just ask, and realize sometimes it takes a while
+to get a response. If you can't wait around for an
+answer and don't know when you'll be back online, then
+post your question on the forum.
+
+
+How come people +on IMC2 can't rwho me?
+
+This is fixed in the current stable version.
+
+
+How do I find someone on Intermud-3?
+
+Type:
+i3locate joe
+

+
+
+
Section +4: Miscellanea
+
+I'm +fighting the beggar with my staff and he's kicking my ass
+
+    +For one thing, you're a creator. Quit goofing around. If
+you want to +fight monsters and stuff, create a test
+player +character.
+
+    +Next, you're probably still a Level 1 character. This
+makes you a +wimp. Raise your level with this command:
+
+call +me->SetLevel(20)
+
+    +Now get the medical tricorder from your workroom's
+chest and +raise your stats. Give yourself 100 strength.
+Why not?
+
+    +If you're carrying a chest, table, chair, and +everything
+else you've +come across, you will be unable to do much
+during +combat. Try to wield a weapon, hold a couple of
+shopping bags +and boxes, and see how well you do against
+a pissed off +real-life enemy. You won't last long. So either
+drop all the +crap you're lugging around, or put it in
+a backpack +and wear the pack.
+
+    +Put the staff in your robe and quit using it as
+a weapon. +It's a creating tool. Not only is it a
+poor weapon, +by default you lack double-handed
+weapon +skills, making you really crappy at using
+a really +crappy weapon. No wonder the orcs were
+beating you +like an animal. Get a carving knife
+from the +mansion. Or an orcslayer. Or hell, just
+use the zap +command and stop wasting time. You
+should have +characters for this.
+
+    See also Question 2.41
+
+
+Someone +amputated all my limbs and I can't do anything!
+
+If your body +gets damaged you can restore yourself to your
+normal +physical status by typing:
+
+heal +me
+
+
+How +do I change my class?
+
+Again +with the pretending to be a +player. Seriously,
+you need a +test player char so that if you screw something
+up, you don't +screw *yourself* up.
+
+But, if +you're determined:
+
+call +me->ChangeClass("thief")
+
+Your +stats and levels will probably be all weird and
+hosed up. +Just raise your player level, that will probably
+fix it.
+
+
+
+People +are talking to me in gibberish, even though it
+says they're speaking English.

+
+If your race +is not human, your default language is not English, +therefore
+someone +speaking in English would not be understood by you. As a
+creator, you +can avoid players' tedious language learning process
+and simply +type:
+
+call +me->SetLanguage("English",100)
+
+    +Obviously this will work for other languages too.
+
+
+
+
+What's +this about Biff "unknowingly" telling me something?
+
+If you are +invis and a player or someone on another mud tells
+to you, they +get an error message about you not being around. So,
+they told to +you, but do not know you actually got the message,
+since you +don't seem logged on.
+
+
+
+How +do I find the location of a verb or command?
+
+Use the which +command. For example:
+
+which +zap
+
+which +update
+
+If 'which' +doesn't find it, the command is probably built into
+some object +you inherit, like the command shell or the
+hooks for the +chat daemon. Or it may be an add_action bound to a
+nearby +object. To see what commands objects or inherited
+files might +be providing you, type:
+
+localcmds
+
+
+
+ Where +are the "exa" and "n" commands?
+
+When you type some commands, +like exa, n, or i,
+what happens is that your command +shell recognizes
+them as aliases, and turns the +alias into the appropriate
+command.
+An alias is like a nickname, or +shorter word,
+for a command or series of +commands. To see the aliases
+you currently have, type:
+alias
+
+To make a new alias:
+alias ml +mudlist
+
+To make an alias that replaces a +specific command
+while permitting you to supply +arguments to it:
+alias ig +intergossip $*
+
+To remove an alias:
+alias ig
+
+
After modifying aliases, +make sure to type:
+save
+
+    +
+ How +do I get something to happen to a random person in a room?
+You +can +pick a +random winner (or victim) for your action by using the +get_random_living()
+sefun. For +details on its usage:
+
+man +get_random_living
+
+You may also +find the get_livings() sefun useful.
+
+
+My +wandering monster escaped from my workroom! How can
+I +find him?
+
+If its name is jabberwock, try:
+
+findobj +jabberwock
+
+You can also probably just:
+
+goto jabberwock
+
+
+I +ran findobj on something but it says no environment. Where is it?
+
+Right where +it says. Some objects create a "master copy" of themselves
+when they are +cloned. This copy remains loaded in memory even if
+that cloned +object goes away. You can distinguish between cloned
+objects and +master copies by the number sign  and number at the end
+of cloned +objects. The master copy has no instance number. It is
+simply loaded +code, and does not "exist" in a way accessible to your player
+object on the +mud.
+
+Sometimes a +cloned object will lose its environment. This is usually
+caused by an +error and is not a good thing. Dead Souls runs a
+"reaper" +daemon that periodically searches memory for cloned
+objects that +lack an environment, and they are destroyed.
+
+
+
+How +do I update everything in a directory?
+
+You really +shouldn't. There are very few cases I can think
+of where +updating an entire directory is something an average
+creator needs +to do. How often do you edit multiple
+files at once +without individually updating them? Good
+coding +practice is to update the one file you just worked on to know
+if it works +at all.
+
+I also +discourage it because when you do this, you lag the mud
+considerably. +I/O is the most resource intensive kind of operation,
+and updating +is on its own quite resource intensive. Updating a
+directory +with dozens of files in it will cause a noticeable hiccup
+in the rest +of the mud.
+
+If you are +determined to do this, though, the +command is :
+
+update +/path/to/dir/*
+
+
+
+I +don't like getting colors on my screen. How do I stop it?
+
+Type: terminal +unknown
+
+then type: save
+
+
+
+Um...I +want colors back now please
+
+Type: terminal +ansi
+
+then type: save
+
+
+
+ I +can type 'n' and move north, but 'north' doesn't work.
+
+Technically, +you can't 'n' either. When you type 'n', what
+it happening +is that your preset alias turns that 'n'
+into the +command line 'go +north'.
+    +Because you do not have an alias 'north' that expands
+to 'go +north', +'north' doesn't +take you anywhere. But
+go +north +will.
+
+
+
+ Why +is there a bunch of stuff in ROOMS_FURNACE?
+
+The QCS is +designed to attempt the graceful handling
+of unusual +events. Sloppy code, non-working objects,
+etc. Part of +this design is avoiding a situation
+where an +object's destruction affects your local
+environment +(and this happens a bit more often than
+you might +think).
+    +To avoid some types of unpleasantness, QCS doesn't
+try to +immediately destruct objects when replacing them.
+Instead, they +are moved, along with whatever problems
+they might +have, to ROOMS_FURNACE. That is a room
+where things +go to be destructed quietly. Every
+second or so, +the contents of that room are destroyed,
+and their +bits recycled.
+    +A few other items in the lib use the furnace,
+notably the +recycling bins and the reload command.
+
+
+How +do I change +my screen and terminal settings?
+
+help +terminal
+
+help +screen
+
+screen +79 24
+
+
+ ZOMG +this is the best mudlib evar how can I evar thank you?
+
+No need, +citizen. Merely doing my job.
+
+Just let me +know what bugs you find, and how I can
+make the lib +better. Also, provide help on the
+intermud channels for those who ask. That's how
+you can "give back."
+
+
+Dude +this mudlib sux0rz @ss. What a waste of my time.
+
+I'm sure Dead Souls has lots of +things that you don't
+like, but I can't fix them if I +don't know what they are.
+Email me so that I can understand +the lameness, and so
+others can benefit for your +suggestions.
+
+
+I'm +seeing a filename but I can't read it.
+
+If you try command and you get +something like:
+
+/secure/foo/bar: No such +reference.
+
+It means you don't have read +access to that
+file or directory.
+
+
+Is +there a command to go back to your previous directory
+without +having to type it all out again?
+
+The shell has a few handy +builtins.
+
+To go up a directory: cd ..
+
+To go to your home dir: cd ~
+
+To go to your area directory cd ~/area
+
+To go to the /domains dir: cd ^
+
+To go to /domains/default: cd ^default
+
+To go to the directory you were +in before the current one: cd ~-
+
+

+When +I'm in combat, I keep getting messages about not being
+able +to fight while carrying stuff, but I only have X, Y, and Z on me.
+
+I was carrying some dishes to the +kitchen a while back, and it
+occurred to me that even if I had +a sword, if someone jumped
+out and started fighting me, the +first thing I'd have to do is
+drop anything I'm not wielding, +or get my butt kicked.
+
+The more I thought about it, the +more it made sense to set up
+an encumbrance system that +prevented proper fighting ability so
+long as you're carrying anything +that isn't worn or wielded,
+no matter how heavy.
+
+If you don't like this behavior, +talk to your admin abour changing
+the encumbrance define in +/secure/include/config.h .
+
+See also questions 2.41 and 4.1
+
+
+
How do light +sources work?
+
+
Your player object looks. This initiates a check of the +environment
+for light. The room has ambient light. Things in the room may have
+radiant light. Ambient light plus radiant light is added together.
+This number is given to your player object. If the number is in your
+vision range, you can see. Torches and flashlights work by having
+radiant light set.
+
+
+
When I control +an NPC, sometimes my commands fail oddly.
+
+NPC's are intentionally simpler creatures than players. When
+a player's command fails, it's very important that she know why,
+otherwise the game can lose its fun. NPC's are not entitled to
+the same regard as players, and therefore their parsing and
+error messages are more primitive, if they exist at all.
+
+If, for example, you try to "force fighter to drop boot",
+you may not only have nothing happen...it might actually
+barf up a runtime error, on older versions of the lib.
+
+This is because NPC's don't get the full luxury of "default
+parsing" that players do. You can "drop boot", and if the lib
+has default parsing enabled, you'll just drop the first
+boot in your inventory. An NPC, however, may need to specify
+"drop first boot". And if it doesn't get the command right,
+that NPC may simply not receive a very helpful error message
+as to why.
+
+Perhaps someday the NPC's will march en masse into my workroom
+and demand equal rights and back pay. Until that day, however,
+please accept that they are just not meant to be as versatile
+in-game avatars as proper player objects are.
+
+
+
How do I make +myself able to cast my new spell?
+
+Normally players learn spells by learning them from an NPC
+that teaches it, like Herkimer. However, if you want to
+test new spells you've created, you can teach them to
+yourself this way:
+
+call me->eventLearnSpell("snowball")
+
+However, this uses the normal player learning process,
+and if you don't happen to have the requisite magic
+skill levels, it may fail. To force yourself to know
+a set of spells at specific levels, you'd use the
+SetSpellBook() function, thusly:
+
+call me->SetSpellBook(([ "buffer" : +100, "meditate" : 100, "snowball" : 100 ]))
+

+

+
+

+Section +5: Building
+
+QCS is putting stuff where I don't want it.
+
+QCS is a way to use simple +commands to manipulate
+complex files. Sometimes the +conversion between simple
+and complex causes unusual +compromises and outcomes.
+
+When you create a new room, what +QCS does
+is look at the room you're +currently in. Let's say
+you're standing in +/realms/you/area/room/test1.c. And
+you issue the command
+
+create room +east test2
+
+In this case, "test2" is +considered a "relative path",
+which means that you didn't +provide QCS with *exactly* where
+you want the file to be. You told +QCS to figure out where
+to put that file.
+When QCS has to guess where a +new room goes,
+it simply assumes that the room +goes in the same directory
+as the current room. So, in this +case, you're going to
+make a file with this path:
+
+/realms/you/area/room/test2.c
+
+Suppose that this is not where +you want the new
+room to be. you want it to go +into /realms/you/testrooms/.
+In this case, you need to tell +QCS the "full path", like this:
+
+create room +east /realms/you/testrooms/test2
+
+When you create non-room +objects, also known as
+tangible items, QCS guesses in a +slightly different way.
+If you provide a relative name, +then QCS looks at your
+current working directory (cwd). +Based on the type of item,
+QCS looks for a directory with +the appropriate name. For
+example, if your cwd is +/realms/you/foo, and the type of
+object is a weapon, then QCS +looks for a directory named
+"/realms/you/foo/weap/". If it +exists, it puts your new
+file there. Otherwise it tries to +put it in "/realms/you/weap/".
+And if that doesn't work, it'll +default to your home area
+weapon directory, which is +"/realms/you/area/weap/".
+
+If you've been granted domain +admin status, and
+you are using QCS to work on your +new domain, it's therefore
+very important that your cwd be +in the right place in the
+domain directory for it to work. +Otherwise, your new stuff may
+wind up in your default area dir, +and you could go nuts
+trying to find it.
+
+Of course, you can avoid all +ambiguity by simply
+using a full path, like:
+
+create weapon +/domains/My_Spiffy_Domain/weap/fruitcake
+

+How +do I make a blank room, instead of copying the current one?
+    +You'll always copy the old room, that's just how
+QCS works. +But you can quickly change it to a blank
+room by +entering the new room and issuing this command:
+
+copy +/obj/room
+
+
+How do I create an area?
+
+    +You have a default area directory in your
+homedir. By +default, your QCS creations get put in there.
+However, if +your area is ever going to be put into
+play, it +could be inconvenient to move it into the
+/domains +directory, because every file reference will
+have to be +changed.
+    +If your admins use unix and perl, this is trivial.
+If not, it's +a real obstacle.
+
+    +Therefore, if you're going to work on an area
+that will +someday be open to the public, it's a
+good idea to +start in the /domains dir. Your admin
+will need to +create the appropriate directories.
+For example, +if the domain is to be FunkyTown, you'll
+need +/domains/FunkyTown, /domains/FunkyTown/room, and
+so on.
+
+    +You will also need to have your admin make
+you a domain +admin of FunkyTown with the domainadmin
+command. This +will permit you to use QCS there.
+
+    +That's the technical part of getting started
+with an area. +The hard part is that you need to
+know what +you're doing, you have to have a creative
+vision, and +the language skills to make it evocative,
+immersive, +and worth playing in. That's up
+to you...I +can't help you with that.
+
+
+How do I make a quest?
+  
+Think of a quest in terms of the +result.
+The result of a quest is a player +receiving quest
+points and a quest title.
+   
+This means that pretty much +anything can
+be a quest. If you've coded a +rock to provide
+quest points and a quest title +when it is
+picked up, well, there's your +Rock Quest. However,
+you usually want to make things a +bit more challenging.
+
+A quest can be as boring as +"pick up the red rock"
+or it can be a challenging +metaphysical inquiry into the
+nature of consciousness. If quest +points and a quest title are
+at the end of a series of +actions, then that series of actions
+is a quest. What those actions +should be are entirely up
+to your imagination. Review the +orcslayer quest in the
+Player's Handbook for an example. +You did read the
+Player's Handbook, right?
+  
+Take a look at Leo the +Archwizard's code for an example of the
+mechanics of solving a quest.
+
+
+Where's +Leo?
+
+Read the +Player's Handbook already, please.
+
+
+Where +are the vehicles and mounts?
+
+As of Dead Souls 2.4.1 mounts +work for getting around and
+storing stuff.
+
+You can see an example of a mount by cloning a mountable horse:
+
+clone /domains/town/npc/horse
+befriend horse
+mount horse
+ride north
+dismount
+abandon horse

+
+Mounted combat is slated for future releases.
+
+
As of 2.5a19, you can see +some basic sample vehicles in
+/domains/default/vehicles

+
+
+I'm +having trouble adding meals to my barkeep with QCS.
+
+Cratylus <ds> ok here's the +deal
+
+<ds> +Daelas@Moraelinost scrunches on the edge of his seat.
+
+Cratylus <ds> menu items +can have more than one id
+
+<ds> +Daelas@Moraelinost nods solemnly.
+
+Cratylus <ds> "ale","first +class ale","beer"
+
+Daelas@Moraelinost +<ds> with you so far.
+
+Cratylus <ds> when you: +modify barkeep menuitems
+
+Cratylus <ds> it asks you +for the id's
+
+Daelas@Moraelinost +<ds> I didn't get that.
+
+Cratylus <ds> when you're +done entering id's, you hit a period
+
+Daelas@Moraelinost +<ds> is it SetMenuItems or menuitmes.
+
+Cratylus <ds> then you +enter the filename to the item sold
+
+
+I +heard DS has stargates. Where's an example?
+
+The following rooms have +stargates:
+
+/domains/Ylsrim/room/tower.c
+
+/domains/default/room/stargate_lab.c
+
+For info on valid gates, type: stargate
+
+

+I +created a vendor, but he isn't responding to the "list" command.
+
+The list command isn't part of +the vendor object. It's
+part of LIB_SHOP, which is a room +that acts as a sort of front-end
+for the vendor. The commands list, +show, price, and appraise are
+not in the vendor, but in the +shop. To get the appropriate responses
+from the vendor, you would use +the following syntax:
+
+list: ask vendor to browse
+show: ask vendor to show +<item>
+price: ask vendor to price +<item>
+appraise: ask vendor to +appraise <item>
+
+

+I +gave room with a default smell but I cannot get any other smells in +there,
+such +as 'smell object' for example
+
+    +SetSmell, like +SetListen, is in the form of a mapping. When using the
+QCS, the +correct formatting is automatically made for you. If coding
+by hand, take +a look at /domains/town/room/riverbank.c for what it
+looks like. +Note that for each Smell or Listen, you need a corresponding
+SetItems +element.
+
+
+How do I make a +weapon more powerful?
+
+Modify SetClass(). SetClass(20), for example, will make the weapon's
+raw damage (before adjusting for armor, the opponent's skills,
+magical protection, etc) be 20. So on a sleeping, naked, unenchanted
+target, the weapon (assuming the wielder is adept) would take
+away 20 health points on a successful strike.
+
+As you can see, there are many modifiers on a weapon's effectiveness,
+including the target's susceptibility to that kind of weapon. There
+is no written-down formula for the exact amount of damage. You'll
+need to make test weapons and test npc's and determine for yourself
+the appropriate balance.
+
+A convenient way to do this is in the arena. Type:
+
+goto /domains/default/room/arena
+
+There you'll see a training dummy and an npc you can use to
+test your weapons and armor. The dummy talks whenever he is
+hit, and describes the kind and extent and location of the
+damage he has received. For a demonstration, type:
+
+force fighter to kill dummy
+
+You can make a weapon cause a certain amount of damage regardless
+of protection by adding the appropriate code in in eventStrike().
+Please see chapter 29 of the Creator's Manual for details and examples.
+
+
+My NPC refuses +to wield his weapon!
+
+There are a number of reasons this might be. If it is a two-handed
+weapon, and he is already wielding something in one hand, that
+would cause a failure. If the NPC is wearing a shield, and you
+don't specify which hand to wield in, the NPC might default to
+trying to wield on the shield hand, and that would fail.
+
+To troubleshoot the problem, have the NPC wield specific things on
+specific limbs to see if that works. For example,
+
+force orc wield a sword in left hand
+force orc wield my first sword in +right hand
+
+etc.
+
+
+How do I add +colors to exits?
+
+modify here obvious %^YELLOW%^east, +west%^RESET%^
+
+To make all exit messages colored, your admin would
+have to edit /lib/std/room.c and add the appropriate
+tags to the obvious exits string.
+
+
+How do i +refresh a room?
+
+Go to the room and type: update
+
+
+The new +room I created with QCS has SetItems I don't want
+
+
Type: modify here delete +SetItems
+
+
+
I'm trying to +set my NPC to have a strength of 30 but it won't work.
+
+You have to place the SetStat() directive *below* SetRace(), because
+otherwise his body's default race characteristics will clobber
+your custom setting.
+

+
+- +Cratylus
+
+<my name +here>@comcast.net
+
+Dead +Souls Homepage
+
+
+
+ + diff --git a/lib/www/ds-faq.html b/lib/www/ds-faq.html new file mode 100644 index 0000000..4f6ac92 --- /dev/null +++ b/lib/www/ds-faq.html @@ -0,0 +1,108 @@ + + + + + Dead Souls FAQ + + + + +
Dead Souls FAQ, v2.5

Written by Cratylus @ Frontiers, October 2005
Updated September 2009

What is Dead Souls?

What is it for?

What is a MUD?

What's a mudlib?


When I configure Dead Souls, it says it is a MUD.
If it is really a mudlib, why would that be?


Is Dead Souls really Nightmare in disguise?


What is Nightmare?

What is the relationship between Nightmare and Dead Souls?

How close?

Why mess with Dead Souls, then?

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]!


What's LPC?

Why is the name "Dead Souls"?

I heard you are controversial. I don't like controversy.

I heard you switched to a driver other than MudOS

Is there a more barebones version available?

How do I get started?


Anything else?


What is Dead Souls?

Dead Souls is a "mudlib".

Dead Souls 1 was a public domain release of a mudlib
called "Nightmare". It was difficult to use, and buggy.

Dead Souls 2 is a re-release that fixes the bugs and
makes it super easy to use for both beginners and advanced admins.

There is also a Dead Souls MUD, but this is not what people
usually mean when they refer to Dead Souls as a game.


What is it for?

It's for building a game. If what you want to do
is play a game, you're looking for something else.
 

What is a MUD?

A MUD is a computer program that uses text (most MUDs do not use
graphics or sound in-game) 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 & 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.

See also:
http://www.catb.org/~esr/jargon/html/M/MUD.html


What's a mudlib?

There are many different types of MUD programs. Some are
executable programs, with all of their virtual worlds
defined in one big file. Others are entirely interpreted,
such as java muds, which are composed of thick forests
of folders containing java files.

LP MUDs are something between the two.

Generally there are two main parts to an LP 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.


When I configure Dead Souls, it says it is a MUD.
If it is really a mudlib,
why would that be?

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.


Is Dead Souls really Nightmare in disguise?

Let's break this question down into its components:

What is Nightmare?

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.

What is the relationship between Nightmare and Dead Souls?

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 a very close one.


How close?

The similarity between Nightmare and Dead Souls can
now best be described as close cousins, rather than twins.


At one time it was 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.


Why mess with Dead Souls, then?

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 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.


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]!


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 few
claims of superiority. 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.


What's LPC?

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.


Why is the name "Dead Souls"?

I don't know for sure. I've had more than one person say that
they are afraid their workplace will discover they are using software
with such a satanic-sounding name. I suggest that if it's really a
problem, do a recursive search and replace of "Dead " to "Saved ".

Though I can't say for sure about the name, I do know that
George Reese had an interest in the Russian language, and "Dead Souls"
is the name of a widely known piece of Russian literature. I suspect
the two facts are not accidentally coincidental.

UPDATE! (23 Feb 2008): I've received an explanation from George
regarding the name. To summarize, He really liked the Nine Inch Nails
cover of the Joy Division song "Dead Souls" (which he also liked)
which was named after the Gogol novel, and he viewed the lib as a ghost town
waiting to be populated by living people replacing the "dead serfs".
Ta-daa!


I heard you are controversial. I don't like controversy.

Using Dead Souls is not controversial. I occasionally
get into forceful debates with forum admins or people that maintain
other codebases. This does not mean that using SmaugFUSS is
a "vote" for its maintainer's opinions, and it doesn't mean that using
Dead Souls is a "vote" for mine. If you find their software useful, use
it. If you find DS useful, then use that. You are not required
to agree with my sense of humor or ideas about forum etiquette
to get support from me or the DS community. In fact, if you
disagree with me, it's probably a good thing for you, in that I'll likely
be extra nice to you just to prove you don't need to be my sycophant
to get along in the DS community.


I heard you switched to a driver other than MudOS

Starting in Dead Souls 2.5a15 the bundled driver is FluffOS.
FluffOS is a derivative of MudOS, maintained by the Discworld MUD team.
There are numerous advantages to using FluffOS: It is currently maintained,
it has superior handling of 64-bit environments, it's been updated
to work in modern libraries (e.g. ualarm changes and the like), and it's
been "battle tested" in a very active mud for a very long time. The
switch to FluffOS is a substantial net plus for Dead Souls, not just
a fashion statement.

Note that this is not a "turning away" from MudOS, since
FluffOS still has MudOS as its base...serving kind of like it chassis.
It is not unreasonable to consider FluffOS the "current fork" of MudOS.

Note also that this does not simplify in any way the
status of the driver licensing for Dead Souls. Because FluffOS is
a MudOS derivative, a Dead Souls mud running it is still
subject to the MudOS team's and Lars Pensjö's restrictions.


Is there a more barebones version available?

Occasionally I'll hear from someone that what i call "full-featured"
they consider to be "bloat." It doesn't hurt my feelings if you're so
advanced that the big new systems like the world grid, flying, vehicles,
etc seem like "bloat" to you. The current focus of the DS lib is to have
as solid and thorough a foundation and set of examples that anyone can
pick it up and get up to speed quickly. If that's not what you need, but
you like the look-and-feel, then there are a few related codebases with
a lot less stuff included:

http://lpmuds.net/files/deadsouls/dsI.zip
http://lpmuds.net/files/nightmare3_fluffos_v2.zip
http://lpmuds.net/files/nightmare4_fluffos_v1.zip

Note that generally speaking, these libs are older and unmaintained.
But if you're a DIY type and know what you're doing, and you can't
stand all the examples in DS2, they might serve you better.


How do I get started?

Download the latest version of Dead Souls from http://dead-souls.net/
and install it.

The distribution file includes both the
Windows and UNIX versions. Read the installation FAQ for details.

Once you log in, read the Players Handbook and the Creators Manual.


Anything else?

Read the Dead Souls Admin FAQ.

Read the Dead Souls Creator's FAQ.

Read the Dead Souls Installation FAQ.

Read the Quick Creation System Example Page.

Read the Debugging Guide.

Read the Editor Tutorial.

+The end.
+
+Dead Souls Homepage
+
+
+ + diff --git a/lib/www/ds-inst-faq.html b/lib/www/ds-inst-faq.html new file mode 100644 index 0000000..c135a77 --- /dev/null +++ b/lib/www/ds-inst-faq.html @@ -0,0 +1,731 @@ + + + + Dead Souls Mudlib - Installation FAQ + + + + + + + + + + + +

FAQ Index

+ + +

Is this FAQ really necessary? (Back +to Top)

+

Normally, no. If you just follow the instructions included in the +Dead Souls packages, you'll be fine 90% of the time. However, a +non-trivial number of folks have run into difficult circumstances. For +those folks, this document is meant to illuminate how the install +process works, why some things are as they are, and suggest some +solutions to the more common obstacles.

+ +

Where do I get Dead Souls? (Back +to Top)

+

You should only ever download from the site listed below. Some other +sites tend to mirror these or copy data, then fail to update their data +regularly. The following will always have the most recent versions.

+

Download the stable version from the following: +

+ +
+Download the latest alpha version here:
+
+ +
+The alpha version often has lots of neat new stuff. Some of the new +stuff is +still not 100% production quality. If new features that are still under +development are upsetting to you, you may be better off using the +"stable" version instead.
+
+
+ +

Where are the separate UNIX and Windows +versions? (Back to Top)

+

Starting in Dead Souls 2.0r22 the two separate versions have been +merged into one distribution download file. Now it doesn't matter +whether you want to use Dead Souls on Windows or UNIX, there's just one +file to download, and it contains everything you need for both +operating systems.

+

This merge accomplishes the following: +

+
    +
  • Ensures 100% identical lib versions for the different OSes.
  • +
  • Limits the clutter involved with releasing new versions.
  • +
  • Lowers the amount of labor and time involved in releasing new +versions.
  • +
  • Simplifies installation and upgrades for new users.
  • +
+ +

Where do I get patches? (Back to +Top)

+

+

+Patches are deprecated in favor of liveupgrade. +For exceptional situations, however, or for very old muds that still +need +them, they are here:
+
+ + +

Should I apply the available patches during an install? (Back to Top)

+

No. Patches are for already-installed Dead Souls muds. A new Dead +Souls install does not need and must not use patches. If you're +upgrading from one Dead Souls version to another, please read the +upgrade section further down in this document.

+ +

How do I install Dead Souls in Windows? (Back to Top)

+

NOTE: If you are using Windows, USE THESE INSTRUCTIONS. There is no +benefit in trying to download Cygwin and modify the UNIX source code +and trying to get it to compile in Windows, unless you know exactly +what you're doing. Yes, people have tried to do this and complained.

+

First make sure you are running Windows NT 4, Windows 2000 or above, +Then: +

+
    +
  1. unzip the distribution file
  2. +
  3. move and rename it so that it is c:\ds, and that the folders +c:\ds\win32 +and c:\ds\lib are where the binary and library files are, respectively.
  4. +
  5. run c:\ds\runmud.bat
  6. +
  7. if you lack a favorite telnet client, open a command line window +by clicking on Start->Run... and entering: cmd
  8. +
  9. connect to your Windows computer by telnetting to port 6666. If +you are using the command window, type: telnet +localhost 6666
  10. +
  11. Enter the name you want your admin to have, and answer the +questions provided. Make sure you are the first person to log in, +because that +first person is automatically made admin.
  12. +
  13. When you finish entering the admin's info, the mud will +automatically reboot.
  14. +
  15. log in as your admin character.
  16. +
  17. change your mud's name with the admintool command. Navigate to +the "driver" +menu (as of this writing, it's option 4, and then the "change the MUD's +name" option (as of this writing, it's option r). Enter the name +desired, allow the mud to shut down.
  18. +
  19. log in again after the mud reboots.
  20. +
  21. check the HOTFIX PAGE +for +late-breaking fixes.
  22. +
  23. See if any upgrades are available by typing: liveupgrade all
  24. +
  25. If files are downloaded, apply the upgrades by typing: liveupgrade apply
  26. +
  27. If you get nothing but a repeating message, cancel the upgrade by +typing: liveupgrade cancel
    +
  28. +
  29. Start reading the guide and the handbook and the manual.
  30. +
+


+

+

Migrating from Windows to UNIX fails horribly (Back +to Top)

+

The main problem you're likely running into is that Windows and UNIX +handle text files differently. In particular, object persistence files +(.o files) saved under Windows may have additional characters that the +UNIX driver won't tolerate.  The  UNIX command "dos2unix" +might help...or it might not. You might need to use the .o files from +the default distribution (sadly losing whatever was in your old ones).
+

+

It may also be that your Windows driver is much older than the +driver for the UNIX version you're migrating to. It might be a good +idea to hunt down the source code for the specific lib release you're +using (for example, 2.1.1) and compile that for your driver.
+

+

The short and sad answer is that such a migration can go wrong in so +many ways that it's beyond the scope of help this document, or I as +maintainer, can provide.
+

+
+ +

Hold up, these Windows instructions aren't working (Back to Top)

+

There are a few common reasons for this. +

+
    +
  • If your friends can't connect, read this: http://dead-souls.net/ds-admin-faq.html#129
    +
  • +
  • If your mud seems superslow when you start it, just be patient. +It is building up a list of the files in your mud, and this can make it +seem like you are hung or crashed.
    +
  • +
  • A recent fix may be available. Check the HOTFIX +PAGE for late-breaking fixes.
  • +
  • Download only from the sites mentioned above. Those are the only +ones sure to have the latest version. Other sites can be out of date.
  • +
  • On at least one occasion, Winzip has somehow corrupted the +archive as it was extracted. Try using another decompression utility, +like winrar.
  • +
  • Most Windows PC's these days have firewall software installed. +If you +try to connect but aren't able to, there's a good chance your +connection is being blocked by your firewall. Disable your firewall +temporarily and try to reconnect. If the problem goes away, you know +now that you have to somehow configure your firewall to allow incoming +TCP connections on port 6666.
    +Note: You may also have to permit outbound TCP connections to +port 23 on IP address 149.152.218.102 if you want your mud to join the +Intermud3 +network.
  • +
  • You might not be using c:\ds as your base directory. Make sure +you are. Putting the mud files on another drive or another folder will +cause the mud not to run.
  • +
  • Trying to use Windows 98, 95, Me, or 3.x will simply not work. +Sorry. Those are not server class operating systems and they use +technology incompatible with the mud's requirements.
  • +
  • If you connect to the mud for the first time, but then it hangs +for more than a few minutes, +look in c:\ds\lib\log\runtime and c:\ds\lib\log\catch. Those are error +log files. If you see stuff about files or directories not existing, +then the problem is probably that your decompression program didn't +unpack the files right. Start over. Download winrar and use that to +uncompress.
  • +
  • If you're seeing errors about stuff like economy.o, and your +computer uses a non-English version of Windows, you may be running into +a character-set problem. On the UNIX version of DS, this is pretty easy +to fix with a runtime variable. On Windows, I am not sure it is +possible. What is happening is that the mud expects numbers in the +form: 3.15 rather than 3,15 and is unable to handle your computer's way +of notating the decimal. I do not know the fix for this: if you find +it, please share it with us.
    +
  • +
  • If the mud starts but you get lots of bizarre errors, there may +be a couple of reasons for this: +
      +
    • If the c:\ filesystem is NTFS, and the user you logged in as +does not +own the ds:\ folder, things will fail in odd ways. What is happening is +that the +mud is trying to write files in a folder it doesn't have permission to, +and +things get all hosed up. Make sure you have read/write privileges to +the c:\ds +folder.
    • +
    • Zip problems. Some unzipping utilities are known to +incorrectly decompress +zip files. Specifically, sometimes an archive that contains empty +folders will +not write those empty folders to your disk. This could cause problems +for the +mud. If you get lots of errors and things don't work right, and you are +sure +that you have read/write access to c:\ds, then try reinstalling but +with a different unzip utility.
    • +
    +
  • +
+ +

How do I install Dead Souls in a Linux/UNIX box? (Back to Top)

+
    +
  • Login to your shell. Follow the instructions provided by your +hosting service or your unix documentation to know how to do this.
  • +
  • If you are using Ubuntu, you may need to install compiler tools +and bison:
    + apt-get +install libc6-dev
    + apt-get +install bison
  • +
  • Download the distribution package. For example: wget +http://dead-souls.net/code/dead_souls_alpha.zip
  • +
  • DO NOT use fileroller (a GUI based app) to decompress the +package. If +you ignore this warning you are very likely to end up with really +confusing errors and problems. Instead use the normal unix command +line. For example: unzip -d ds +dead_souls_alpha.zip
  • +
  • NOTE: If you don't use the "-d" flag to specify the name of the +new directory you want to create, the archive may dump +everything +into your current working directory, which may look ugly if that's +not your intention.
  • +
  • Don't use an existing driver binary, even if it's from a +previous +(or even the same) Dead Souls distribution. If you're doing a fresh +install, always, always, always do the complete and exact installation +procedure, including the driver compile. If what you're looking to do +is an +upgrade, read the upgrade section further down in this document. Once +we're set on those requirements and you've uncompressed the tarball, we +can continue with the installation procedure.
  • +
  • cd to the directory where all mud files reside. Called $MUDHOME +in the rest of these UNIX instructions. You can determine your current +directory by typing pwd at the shell prompt.
    +
  • +
  • cd to the driver source. This may be "v22.2b14" or it may be +"fluffos-2.*"
    +
  • +
  • type: ./configure
  • +
  • type: make
  • +
  • type: make install
  • +
  • If the previous step fails, just manually copy the "driver" file +into +$MUDHOME/bin/
  • +
  • edit $MUDHOME/bin/mudos.cfg (provided). The two lines to change +are mudlib directory and binary directory. For example, if your +$MUDHOME is /home/joe/mud, then the mudlib directory line will look +like this:
    +/home/joe/mud/lib
    +
    +and bin:
    +/home/joe/mud/bin
  • +
  • edit $MUDHOME/bin/startmud (provided) and change the $MUDHOME +definition.
  • +
  • manually run the mud: $MUDHOME/bin/driver +$MUDHOME/bin/mudos.cfg . +If you properly edited the startmud script, you can just type: ./startmud
  • +
  • telnet to your machine, using the port specified in mudos.cfg. +For +example: telnet localhost 6666
  • +
  • Create a new user. Just answer the questions. Make sure you are +the first person to log in, because that person is automatically given +admin privileges.
  • +
  • You'll get booted out. Reboot the MUD, telnet back in, and you're +now running Your Very Own MUD. If startmud is running, the MUD should +restart automatically.
  • +
  • Start reading the guide and the handbook and the manual.
    +
  • +
+ +

I'm having trouble getting Dead Souls for UNIX to work (Back to Top)

+
    +
  • If the configure script complains about not finding a C compiler, +but you know you have one, try: apt-get +install libc6-dev
  • +
  • If the configure script complains about not finding bison or yacc +and you are the server admin: apt-get +install bison
    +
  • +
  • If your mud seems superslow when you start it, just be patient. +It is +building up a list of the files in your mud, and this can make it seem +like you are hung or crashed.
  • +
  • If you get this: "make: *** No rule to make target +`obj/malloc.o', needed by `driver'.  Stop.", just type "make" again, +or "make -j 1"
    +
  • +
  • If you are using a 64 bit Linux SMP kernel, and when you try +to log in the login freezes, try this: +http://lpmuds.net/forum/index.php?topic=490.msg2274#msg2274
  • +
  • Some hosting providers give you a robust environment that +requires UNIX expertise to handle. For example, I know of folks that +use Genesis Muds to host, and run into all sorts of file permission +conflicts, umask issues, etc. While I'm happy to provide guidance to +some degree, you do have to take it upon yourself to become familiar +with the OS you're using. As much as I want to be helpful to you on +this, getting you up to speed on being a UNIX server admin is way +beyond the scope of this little document. Whomever it is that you pay +money to, ask them for documentation. Sorry if it sounds +rude....there's only so much I can take responsibility for.
    +
  • +
  • Your compiler may be trying to run a distributed "make" by +default. That's a no-go for MudOS. Try disabling that at compile time +by using this instead of the normal make command line:
    + make -j 1
    +make install
    +
  • +
  • A recent fix may be available. Check the HOTFIX +PAGE for late-breaking fixes.
  • +
  • Download only from the sites mentioned above. Those are the only +ones sure to have the latest version. Other sites can be out of date.
  • +
  • Most of the problems with unix installs involve permissions +conflicts. If +you uncompress the package as root user, for example, then try to run +it as an unprivileged user, the process won't be able to read and write +to the directories it uses, and errors will result. If you uncompressed +as root and want to run it as another user (in this example, username: +joe), then you'll want to cd to the directory that contains the mud +directory and issue a chown +command, like this:
    + su - root
    +cd /home/joe
    +chown -R joe ds2.10
  • +
  • If you don't follow the instructions, and instead use a +previously compiled driver, you may skip a step which copies a +unix-compatible mudos.cfg file over the default Windows-compatible +mudos.cfg. To correct this, copy the template config into the proper +directory:
    + cd /home/joe/ds2.10
    +cp bin/mudos.cfg.orig lib/secure/cfg/mudos.cfg
  • +
+          Then edit +lib/secure/cfg/mudos.cfg to point to the correct bin +and +lib directories. +
    +
  • Another problem that can occur if you use an older driver is that +the lib may expect options or features that the older driver doesn't +support. If this is what's happening, you need to start over, but this +time actually follow the instructions exactly, step by step.
  • +
  • If you get a bunch of errors about a missing log directory, you +probably used fileroller to uncompress the tarball. Fileroller is +apparently the default uncompression utility for Fedora. Other Linux +distros may also use it. Start your installation over and this time use +the command line as directed in the installation instructions.
  • +
  • If the driver compile fails complaining about extra_ref in +parser.c, then you probably followed older instructions, and not the +instructions included in the latest package. You should no longer use +./build.MudOS (unless you know exactly the ramifications of what you're +doing). Instead use the ./configure script as per the current +instructions, which you should follow closely.
  • +
  • If the driver craps out complaining about a hosed up swap file, +you're +probably running Fedora, and you probably haven't changed your hostname +from the original "localhost.localdomain" or whatever nonsense they +use. What mudos expects is that when it asks your machine for its +hostname, that it receive something like "alpha", and not something +like "alpha.bravo". If your machine is under the impression that its +name is localhost.localdomain, it will supply that name to mudos, which +will eventually choke on it.
    +If you're good at C, you can edit lines 66 and 76 of +v22.2b14/swap.c and correct this behavior. But the common sense fix is +to stop being a noob and give your computer a proper hostname already.
  • +
  • Some hosting services may provide you unix shells so tightly +restricted that you cannot successfully compile the mudos driver. You +may need to submit a problem ticket with your hosting service to +resolve the issue. Let them know that the source compiles fine on +various versions of SuSE and Fedora, as well as Solaris 8, 9, and 10, +various BSD's, and even IRIX (!). If you can get them to give me a free +temporary account for testing purposes, I might take a look and see if +I +can help.
  • +
  • If you've tried everything but the compile keeps breaking, try +compiling as root (obviously a last resort, and just for testing).
  • +
  • On Ubuntu, you will probably need to change your apt-get source +(System->Administration->Software Sources) then apt-get install bison and apt-get install libc6-dev
  • +
  • If you get errors complaining about +not finding bison or yacc, what this means is that compiling the driver +requires these tools, and the configure script can't find them. They +are either in a non-standard location, or your host simply does not +have them installed. If you run the host box, either install bison (or +yacc), or add their path to your PATH environment variable. If you are +not the host computer admin, politely explain to the admins that you +can't compile without bison (or yacc) and could they please install it +for you.
    +
  • +
    +
+ +

Why does compiling the driver for Dead Souls throw so many +warnings? +(Back to Top)

+

Beats me. This is one of those complaints I don't really know how +to respond to. At the end of the compile, you'll have a driver that +works. It's been tested on GCC 2, 3, and 4. It's worked for Fedora +Linux, SuSE Linux, and various other versions of UNIX and UNIX-clone +environments. It works. Ignore +the compile schmutz.

+ +

Why is there a windows-format mudos.cfg in /secure/cfg? I'm running +unix. +(Back to Top)

+

This is a symptom of my obsession to have the Windows lib and the +unix lib be absolutely identical. During a fresh install, this file is +overwritten with a unix version, if you follow the install instructions.

+ +

How do I enable database support? +(Back to Top)

+

I don't know. I don't understand databases at all, so it's pointless +for me +to try to get that driver functionality working. If you develop a +procedure for it, please share it with me and I will document it so +others can +benefit from your leetness. I might suggest that it's probably easier +to do this using LPC sockets in the lib, rather than trying to do it +using driver-level support. If you don't know what that means, you'll +need to play around with Dead Souls for a while, get the hang of it, +and then revisit the question.
+

+ +

How do I upgrade from one version of Dead Souls to another? +(Back to Top)

+

Patches used to be provided, but this was a cumbersome and tedious +process. There is now a liveupgrade command for painless upgrading.
+

+

The upgrade for both Windows and UNIX is the same. Basically a Dead +Souls liveupgrade is a pretty unsophisticated system. It just copies +over new files over old files.
+

+

Obviously, this kind of updating is intended for muds that do +not do extensive lib system rewrites. For example, if your mud creation +has been limited to individual home directories and +the domains/ directories, then an upgrade should +be mostly +painless.

+

On the other hand, if you've done extensive customizing of the +player object, +simulated efun subsystem, daemons, and so forth, then you may run into +problems after an update. The typical update patch does include some +changes to the player object, for example, so the indiscriminate +overwriting of the previous information with the updated files means +that your work basically disappears.

+

For this reason it is critical always to perform a full backup +of +all your mud files before implementing a patch upgrade. Carefully +follow the instructions included in the liveupgrade command to ensure +optimal effect. Because these instructions are not expected to be +static, the details will not be included in this document. Read the /doc/RELEASE_NOTES file +to know what has changed between releases and to determine whether an +upgrade is worth the risk. Please note that RELEASE_NOTES contains an +overview of major changes. It does not document every difference +between versions.
+

+
+

How do I +compile a 64 bit driver?
+

+

Assuming you are using a 64-bit AMD processor and running a 64-bit +OS on it, you can enable the compilation of a 64-bit driver by editing +fluffos*/build.FluffOS and changing:
+

+

ENABLE_M64=0
+
+to
+

+

ENABLE_M64=1
+

+

Then re-do the compile with:
+

+

make distclean
+./configure
+make install
+

+

If this fails, you are probably either not running a 64-bit AMD +processor, or not running a 64-bit OS on it.
+

+

+

When I log out after starting the mud, problems +happen. +(Back to Top)

+

If you're running a modern UNIX, you have two main options for +running the mud in a "backgrounded" way that survives your logout.
+

+

nohup
+

+

The first is the nohup command. This is a sort of legacy command +from modem days, but it does the job of keeping processes running even +if there's no terminal attached. To use nohup in this way, your +commands might be something like this:
+

+

cd +/usr/games/ds/bin
+nohup ./driver +./mudos.cfg  1>/dev/null 2>/dev/null &
+

+

The /dev/null redirects output to a null device. If you don't do +this, nohup will save all stdout/stderr output to a file, and this may +fill up diskspace more quickly than you expect, so make sure to use the +/dev/null redirecton to avoid this problem.
+

+

If your startmud script has been correctly edited (it's important +that it have the correct MUDHOME directory specified, in this case, +"/usr/games/ds"),  then the command lines might be:
+

+

cd +/usr/games/bin
+nohup +./startmud 1>/dev/null 2>/dev/null &
+

+

The advantage to using the startmud script is that if you shutdown +the mud from inside the game, it will automatically restart. The +disadvantage is that you need to log into the shell and kill the script +if you want to actually shut down the mud and keep it down. A potential +risk when using startmud is that if you have not edited it correctly, +or if there is a problem with the mud, you may have the script fire off +a continuous loop of trying to restart the mud. Not only is this ugly +to look at and inconvenient until fixed, it may also anger the person +who runs the computer you're doing this on, as it may chew up +resources. So, if you use the startmud script, *make sure it works* +before running it in background mode with nohup.
+

+

In at least one case, using nohup this was did not work for someone. +I never received a clear explanation of why this was, but for them, the +following technique worked.
+

+

screen
+

+

This command ought to be default in any UNIX anywhere, but alas, it +sometimes is not. If it's not available on your system, you can try to +download the source from here: ftp://ftp.gnu.org/gnu/screen/
+

+

What this program does is let you run console applications in a +virtual terminal, so that you can detach from the terminal, work on +something else, then reattach to resume the program already in +progress. Rather than pausing it, screen just runs whatever it is in a +sort of backgrounded way. Way cool. In the following example, I refer +to the "Ctrl" key like this: <Ctrl> . When you need to press That +key and another key in combination, the notation I use looks like this: +<Ctrl>-a, which means "hold down the 'Ctrl' key, and then press +the 'A' key".
+

+

To run Dead Souls in a screen session, it might look like this:
+

+

cd +/usr/games/ds
+screen -S +deadsouls
+./startmud
+<Ctrl>-a
+d
+

+

You may wonder what that 'd' is doing all by itself there. What +<Ctrl>-a does is tell your screen session to pay attention to the +next key you press, because that is a screen action it needs to take. +In this case, the key is 'd', which means "detach". When in a screen +session, if you type <Ctrl>-a then d, you drop out of the screen +session and resume whatever terminal you were in before you invoked +screen. Your application will be happily chugging along in the virtual +console you left behind. To reconnect to the screen session you +detached from, the command would look like this:
+

+

screen -r +deadsouls
+

+

The full grooviness of the screen command is beyond the scope of +this FAQ. For more info on it, at the UNIX shell type: man screen
+

+Microsoft +Windows
+
+If you're running Windows, then you'll need to figure out how to make +Dead Souls run as a service. One way is to download and use these scripts +contributed by Saquivor @ Eternal Souls.
+Another is to mess around with your windows services and do it +manually. Unfortunately, I am not a Windows server person, so you'll +need to search +Google for the appropriate docs.
+
+
+I put the mud in a +Linux startup script, but it won't start when I reboot!
+
+An apparent peculiarity of Fedora is that if the command line specified +in your start script
+doesn't redirect stderr and stdout to /dev/null, the program fails to +run. Also, if you don't
+properly background it, you may end up hanging the computer and +preventing anything
+else from running.
+
+
+Therefore, in your start script, your command line should have +redirection and backgrounding.
+It might look something like this:
+
+ /mud/ds/bin/startmud > /dev/null 2>&1 &
+
+Other recent Linux distributions may have the same quirk.
+
+
+

Ok, it's running. Now what? (Back +to Top)

+

Log in and read the following:

+ +

The End (Back to Top)

+

Return to Dead Souls +Homepage

+
+

Last Updated December 2007

+ + diff --git a/lib/www/ds.html b/lib/www/ds.html new file mode 100644 index 0000000..d025d05 --- /dev/null +++ b/lib/www/ds.html @@ -0,0 +1,124 @@ + + + + Dead Souls Mudlib + + + + + + + + + + + +

+

What is Dead Souls?

+

+The Dead Souls MUD Library is a multi-user text based adventure +creation system. It allows the user to build their own adventure game +which can be played over the internet simultaneously by many people. It +is designed for both experienced and beginner MUD admins. The download +package includes both the UNIX and Microsoft Windows versions.
+

+

Why use Dead Souls?

+

If you love another mudlib, then go ahead and keep using it. We're +not here to persuade anyone to stop doing what they prefer. Dead Souls +is targeted at three main audiences:

+
    +
  1. People who are new to creating and running a MUD, and need a +mudlib that is well-coded, well-featured, well-documented, and works +great right out of the box. +Dead Souls comes configured with a working combat system, races (with +limbs and detailed body stats), classes, magic system, emotes, postures +(even flying), built-in ftp and web servers, menu-driven MUD +administration tool, intermud network channels, QCS, a sample town +loaded with examples of objects and quests, banking, economics, +variable description based on time-of-day, and much, much more.
  2. +
  3. People who liked the old Nightmare code base and want to get +their hands on a lib with the old Nightmare magic that actually works.
  4. +
  5. Folks who tried their hand at older, unsupported mudlibs but are +looking for something more modern and currently maintained.
    +
  6. +
+ + + + + + + + + + + + +
+

Download Links:

+ +
+

Frequently Asked Questions and Docs

+ +
+

Non-Technical Information

+ +
+

Additional Technical Docs

+ +
+

New! +See the LPMud information page
+

+ +
+ + + + diff --git a/lib/www/editor.html b/lib/www/editor.html new file mode 100644 index 0000000..d67516e --- /dev/null +++ b/lib/www/editor.html @@ -0,0 +1,179 @@ + + + + + Mud Editor Tutorial + + + + +
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 QCS.

But to add special functions to your code, like
magic items, smart NPC's (aka mobs), traps, hidden objects,
etc, you need to edit LPC code.

There is a web-based editing system called
"creweb" that lets you edit mud files from the internet
on your browser. For more info on it: help creweb

But if you can't use creweb, then ed is
the default method for editing files 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":


+
+

> cd /realms/cratylus/area/weap
1) I changed my working directory to my area weapons dir
/realms/cratylus/area/weap:
> ls
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


> ed sword.c
I ran the ed command on the file sword.c.
/realms/cratylus/area/weap/sword.c, 641 bytes
:n
This makes the editor display line numbers next to the lines.
number on, list off
:1z 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);
:z
22 SetVendorType(VT_WEAPON);
23 SetClass(20);
24 SetDamageType(BLADE);
25 SetWeaponType("blade");
26 }
:15 I displayed line 15
15 SetKeyName("short sword");
:15c I used 'c' to replace line 15
15. * SetKeyName("plain sword"); I entered my replacement text
16. * . I entered a single dot on a blank line
:
16 SetId( ({ "sword", "short sword" }) );
:1z 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);
:18 I displayed line 18
18 SetShort("a short sword");
:18c 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
:1z 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);
:x I saved and exited
"/realms/cratylus/area/weap/sword.c" 26 lines 633 bytes
Exit from ed.
> update sword 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:
cd /realms/cratylus/area/weap

2) I listed the contents of that dir: ls

3) I ran the ed command on the file sword.c: ed sword.c

4) Within the editor, I issued the 'n' command. This makes the editor
display line numbers next to the lines.

5) Within the editor, I issued the '1z' command. What 'z' 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 '15z' 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 '1z'.

6) '1z' stopped listing the file at line 22, so I entered 'z' 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 '15'.

8) Now that I'm sure line 15 needs to change, I issue the '15c' command.
'c' indicates that I want to change a line. '15c' 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 '15c',
I am now replacing that line with what I want the line to contain:
SetKeyName("plain sword");

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:
.

11) I'm back in command mode now. When I list the file contents with
'1z' 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 '18c'.

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 'x' command. 'x'
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 'update sword'.


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:

+
+

> ed sword.c started the editor
/realms/cratylus/area/weap/sword.c, 633 bytes
:n enabled line number printing
number on, list off
:15,22 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);
:20a appended to the file after line 20
21. * SetHands(1); entered my added text
22. * . single dot on a blank line to exit input mode
:18,22 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);
:x exited editor and saved
"/realms/cratylus/area/weap/sword.c" 27 lines 646 bytes
Exit from ed.
+
+


Here you can see that instead of 'c', which replaces, I
used 'a', which adds. I decided my new line would go after line
20, so I issued the command '20a'. 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 'z' command. Instead, since I knew where my
changes would go, I decided to list lines 18 through 22 with
the command '18,22'. I then issued the 'x' 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 '20i' 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 'd' commmand:

+
> ed sword.c
+
/realms/cratylus/area/weap/sword.c, 646 bytes
:n enabled line number printing
number on, list off
:1,10 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
:1,5d deleted lines 1 to 5
:1,5 listed (the new) lines 1 to 5
1
2 #include <lib.h>
3 #include <damage_types.h>
4 #include <vendor_types.h>
5
:1d deleted blank line 1
:1z 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 }
:x 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 '1,5d'.
Then, for good measure, I removed the remaining blank line '1d'.
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:

+
> ed sword.c
+
/realms/cratylus/area/weap/sword.c, 476 bytes
:n
enabled line number printing
number on, list off
:g/short/p
searched for and displayed lines containing "short"
10 SetId( ({ "sword", "short sword" }) );
11 SetAdjectives( ({ "short" }) );
13 SetLong("A cheap and rather dull short sword.");
:g/short/s/short/plain
searched for "short" and replaced with "plain"
:g/short/p
searched for "short" again but found none
:1z
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 }
:1
moved to line 1
1 #include <lib.h>
:I
ran automatic indentation
Indenting entire code...
Indentation complete.
:1z
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");
}
:x
exited and saved
"/realms/cratylus/area/weap/sword.c" 21 lines 488 bytes
Exit from ed.
+
+


The command g/short/p showed me all the lines
that contained the substring "short". Then I ran the global
search and replace command to substitute "plain" for "short",
:g/short/s/short/plain
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) Accidental deletion


If you type 1,20d when you meant to type 1,2d 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 'Q'
command:

:Q

To force quit without saving. Of course, if those lines
weren't already in the file, this won't help much.


2) Can't leave the editor


You try to write and exit, but get this:

:x
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 'Q':

:Q
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:

:w /realms/cratylus/sword.c
"/realms/cratylus/sword.c" 20 lines 478 bytes
:Q
Exit from ed.


3) Indent command fails


You try to auto-indent your code but get an error like this:

:I
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) I need to [something] in ed, but don't know how!


While in command mode, type 'h' and enter. You'll get
a handy list of ed commands available to you.


5) My ability/patience/time is limited. I want not to use ed.


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.



Dead Souls Homepage



+ + diff --git a/lib/www/errors/badcmd.html b/lib/www/errors/badcmd.html new file mode 100644 index 0000000..e6183d1 --- /dev/null +++ b/lib/www/errors/badcmd.html @@ -0,0 +1 @@ +Bad command. diff --git a/lib/www/errors/badgate.html b/lib/www/errors/badgate.html new file mode 100644 index 0000000..59c0fcf --- /dev/null +++ b/lib/www/errors/badgate.html @@ -0,0 +1 @@ +Bad gateway. diff --git a/lib/www/errors/denied.html b/lib/www/errors/denied.html new file mode 100644 index 0000000..43acb6e --- /dev/null +++ b/lib/www/errors/denied.html @@ -0,0 +1 @@ +ErrorAccessDenied diff --git a/lib/www/errors/notfound.html b/lib/www/errors/notfound.html new file mode 100644 index 0000000..f1b1cb3 --- /dev/null +++ b/lib/www/errors/notfound.html @@ -0,0 +1 @@ +404 diff --git a/lib/www/example.html b/lib/www/example.html new file mode 100644 index 0000000..bb299d1 --- /dev/null +++ b/lib/www/example.html @@ -0,0 +1,739 @@ + + + + Dead Souls Mudlib - Quick Creation System + + + + + + + + + + + +

Index

+ +

QCS Described

+

The Quick Creation System (or QCS) is a series of commands and +modules that lets you create rooms, objects, exits, and NPCs 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 modify +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"):

+
+
    +
  • create npc new_orc
  • +
  • modify npc name orc
  • +
  • modify orc short a mean-looking orc
  • +
  • modify orc long A typical orc: nasty, +brutish, and short.
  • +
  • modify orc race orc
  • +
+
+

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 are done the same way. For complete +details and examples, read the +QCS chapters in the Creators Manual. The QCS section starts in chapter +31.

+

Example Log

+

Below you will find an excerpt from an short building session using +Dead Souls. This should be more or less exactly what you'll see by +entering +the commands hilighted in red.

+
+

The first thing we need to do is get back to our personal work room. +We can +do this using the home command.

+
+home +
/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.
+
+

Next, we move east to a sample room that is created automatically +for us. +We'll be experimenting in here.

+
+east
+
+
/realms/testycre/area/room/sample_room
Sample Room [e, w]
This is a room you can use as a template.
A simple table is here.
A fighter is standing here.
+
+ +

Room Creation (Back to Top)

+

This is the standard sample room. We're about to create a new room +to the north of it via the create command.

+
+create room north test1 +
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.
+
+

We can now move east to our new room. Notice how it says it's a copy +of our sample room.

+
+n +
/realms/testycre/area/room/test1
Copy of /realms/testycre/area/room/sample_room.c [s]
This is a room you can use as a template.
A simple table is here.
A fighter is standing here.
+
+

Now we'll change the short description to avoid confusion between +our +original sample room and the newly created one. Note that a room's +short +description appears as its title or name near the top of the text when +a +user looks at it.

+
+modify here short Room One +
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.

+
+delete fighter +
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.
+
+

Now we'll make another room.

+
+create room east test2 +
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.
+
+

We'll move east into the newly created room.

+
+e +
/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.
+
+

Once again, we'll rename our new room.

+
+modify here short Room 2 +
Indenting file...
"/tmp/indent.1134436590.tmp.dat" 26 lines 499 bytes
Exit from ed.
+
+

We can now set the room's long description. This will show up as the +body of the room when a player types look.

+
+modify here long This is the second test room. +
Indenting file...
"/tmp/indent.1134436608.tmp.dat" 26 lines 487 bytes
Exit from ed.
+
+

We don't need that table here, let's delete it.

+
+delete table +
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.
+
+

For the sake of self-assurance, we can look at the room's file to +make +sure that our modifications are actually being saved.

+
+more here +
#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();
}
+
+ +

NPC Creation (Back to Top)

+

Now we'll create a new NPC (Mob) called "guy". The file name will +also +be "guy".

+
+create npc guy +
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!
+
+

We can look at our new room and see +the NPC +standing there.

+
+l +
/realms/testycre/area/room/test2
Room 2 [w]
This is the second test room.
A generic npc is standing here.
+
+

The first thing to do is to rename the new NPC in order to avoid +confusion. An NPC's name is what the lib refers to the NPC as.

+
+modify npc name guy +
Indenting file...
"/tmp/indent.1134436801.tmp.dat" 15 lines 417 bytes
Exit from ed.
+
+

We can now set one or more NPC aliases, called "ids". Note that in +the +following example, we enter three different ones, all of which point to +the +same NPC. A player could look at any of +these +IDs and get the NPC.

+
+modify npc id +
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.
dude +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. +fellow +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. +fella +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. +. +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. +
+
+

Now we'll set the NPCs short description, or name. Any condition +such as +"is standing here" is appended to the end of the NPC's short +description, +so don't end it with a period or any other punctuation.

+
+modify guy short The Dude +
Indenting file...
"/tmp/indent.1134436855.tmp.dat" 19 lines 437 bytes
Exit from ed.
+
+

We'll set the long description. This is what is shown when someone +actually +looks directly at the NPC.

+
+modify guy long This is just some random guy +
Indenting file...
"/tmp/indent.1134436904.tmp.dat" 19 lines 408 bytes
Exit from ed.
+
+

Adjectives are useful for complementing NPCs and other objects. For +example, if our guy is 'oily' or 'hairy' as described in his long +description, a player +would be able to do a look oily guy and +see the guy even if "oily" isn't in his actual name/id.

+
+modify guy adj +
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.
just some +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. +random +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. +some +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. +. +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. +
+
+

Let's look at our room and see if the Dude is appearing as expected.

+
+look +
/realms/testycre/area/room/test2
Room 2 [w]
This is the second test room.
The Dude is standing here.
+
+

We'll check out the Dude's file and see how QCS has set up the NPC +for us.

+
+about dude +
/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();
+
+ +

Weapon Creation (Back to Top)

+

Now we'll create a weapon for our NPC. "hammer" is the filename.

+
+create weapon hammer +
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!
+
+

And then set the hammer's ID(s)

+
+modify weapon id hammer +
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.
warhammer +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. +. +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. +
+
+

And now we will set the weapon's name to "hammer".

+
+modify weapon name hammer +
There is no weapon here.
look +/realms/testycre/area/room/test2 +Room 2 [w] +This is the second test room. +A generic weapon is here. +The Dude is standing here. +
+
+

What's happened here is that we changed the weapon's ID before the +name. +Luckily, this is easy to fix.

+
+modify hammer name hammer +
Indenting file...
"/tmp/indent.1134437205.tmp.dat" 22 lines 474 bytes
Exit from ed.
+
+

Now we'll look at the hammer's file to see how it looks.

+
+about hammer +
/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();
}
+
+

We can now set the hammer's damage type to blunt for a nice crushing +effect.

+
+modify hammer damagetype blunt +
Indenting file...
"/tmp/indent.1134437392.tmp.dat" 22 lines 474 bytes
Exit from ed.
+
+

And now set the weapon type.

+
+modify hammer weapontype blunt +
Indenting file...
"/tmp/indent.1134437398.tmp.dat" 22 lines 474 bytes
Exit from ed.
+
+

Similarly, set the mass.

+
+modify hammer mass 700 +
Indenting file...
"/tmp/indent.1134437414.tmp.dat" 22 lines 475 bytes
Exit from ed.
+
+

We will now make the weapon require two hands to use.

+
+modify hammer hands 2 +
Indenting file...
"/tmp/indent.1134437422.tmp.dat" 23 lines 492 bytes
Exit from ed.
+
+

We'll double-check our hammer's file now to see if everything was +set.

+
+about hammer +
/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();
}
+
+

Now we'll set that short description.

+
+modify hammer short a heavy war hammer +
Indenting file...
"/tmp/indent.1134437450.tmp.dat" 23 lines 494 bytes
Exit from ed.
+
+

And our long description...

+
+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. +
Indenting file...
"/tmp/indent.1134437509.tmp.dat" 23 lines 579 bytes
Exit from ed.
+
+

Setting some adjectives.

+
+modify hammer adj +
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.
large +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. +heavy +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. +war +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. +. +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. +
+
+

And finally, look at our hammer file.

+
+about hammer +
/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.

+
+modify guy level 10 +
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.

+
+add hammer to guy +
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:
wield hammer +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. +
+
+

And now we take a look at our guy.

+
+exa guy +
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)
+
+

And check the guy's file.

+
+about guy +
/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();
}
+
+ +

Armor Creation (Back to Top)

+

Making armor is just as easy.

+
+create armor helmet +
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!
modify armor name helmet +Indenting file... +"/tmp/indent.1134437645.tmp.dat" 18 lines 483 bytes +Exit from ed. + +modify helmet id +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. +helm +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. +headgear +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. +cover +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. +. +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. +modify helmet short a horned viking helmet +Indenting file... +"/tmp/indent.1134437692.tmp.dat" 22 lines 544 bytes +Exit from ed. + +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.
+Indenting file... +"/tmp/indent.1134437772.tmp.dat" 22 lines 666 bytes +Exit from ed. +
+modify helmet adj +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. +iron +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. +thick +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. +viking +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. +horned +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. +formidable +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. +protective +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. +. +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. +about helmet +/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(); +} +modify helmet armortype helmet +Indenting file... +"/tmp/indent.1134437818.tmp.dat" 22 lines 718 bytes +Exit from ed. + +modify helmet mass 200 +Indenting file... +"/tmp/indent.1134437830.tmp.dat" 22 lines 719 bytes +Exit from ed. + +modify helmet protection +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. +blunt +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. +blade +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. +knife +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. +trauma +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. +. +Protections list complete. +Please enter the protection value for: BLUNT +15 +Please enter the protection value for: BLADE +20 +Please enter the protection value for: KNIFE +25 +Please enter the protection value for: TRAUMA +10 +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. + +about helmet +/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(); +} +l +/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. + +exa dude +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) + +add helmet to dude +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: +wear helmet +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. +exa dude +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) +
+
+ +

Adding Room Resets (Back to Top)

+

Ok our dude is done. Let's clean up the room by updating it.

+
+update +
Updating environment
/realms/testycre/area/room/test2: Ok
look +/realms/testycre/area/room/test2 +Room 2 [w] +This is the second test room. +pwd +/realms/testycre: +cd area/npc +/realms/testycre/area/npc: +
+
+

We need to have the guy present in order to add him to the room:

+
+clone guy +
Guy wields a heavy war hammer.
Guy wears a horned viking helmet.
You clone The Dude (/realms/testycre/area/npc/guy.c).
add guy to room +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: +1
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. +update +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. +

+
look +
/realms/testycre/area/room/test2
Room 2 [w]
This is the second test room.
The Dude is standing here.

exa dude +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) + +more here +#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(); +} + +quit +Please come back another time! +
+
+
+

The End (Back to Top)

+

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.

+Return to Dead Souls Homepage + + diff --git a/lib/www/favicon.ico b/lib/www/favicon.ico new file mode 100644 index 0000000..d76c824 Binary files /dev/null and b/lib/www/favicon.ico differ diff --git a/lib/www/function.jpg b/lib/www/function.jpg new file mode 100644 index 0000000..1e502b4 Binary files /dev/null and b/lib/www/function.jpg differ diff --git a/lib/www/images/Thumbs.db b/lib/www/images/Thumbs.db new file mode 100644 index 0000000..9b41576 Binary files /dev/null and b/lib/www/images/Thumbs.db differ diff --git a/lib/www/images/lpuni_afiliated.png b/lib/www/images/lpuni_afiliated.png new file mode 100644 index 0000000..cfe2b5e Binary files /dev/null and b/lib/www/images/lpuni_afiliated.png differ diff --git a/lib/www/index.html b/lib/www/index.html new file mode 100644 index 0000000..ec795dc --- /dev/null +++ b/lib/www/index.html @@ -0,0 +1,15 @@ + +

+
+ + + +
+Finger a user: + +
+ +Click here to use CreWeb
+Click here to connect to this mud
+Dead Souls Home + diff --git a/lib/www/lpmuds/alternate_router.html b/lib/www/lpmuds/alternate_router.html new file mode 100644 index 0000000..e4bd7aa --- /dev/null +++ b/lib/www/lpmuds/alternate_router.html @@ -0,0 +1,192 @@ + + + + + + + + + LPMuds.net - Alternate Intermud Router + + + + + + + + + + +
+ + + + + + + +
LPMuds.net +
+ + + + + + +
A +resource site for LPC, LPMuds, and related stuffs.
+
+ + + + + + + + + + + + + + + + +
  Index + Forum Site +FAQ LPMud +FAQ   Intermud   Downloads + Links +  
+

+
+
LPMuds.net: +Alternate Intermud info
+
+ + + + + + +
This is the LPmuds.net backup router. It is connected via an Inter Router Network to yatmim (the primary router). Whether you are connected to i4 or yatmim, you should see the same muds, channels, etc, because the IRN links the two routers. + + +If you have trouble with your connection to yatmim, you can try connecting to i4 instead.
+
+The rules of conduct on yatmim apply to the alternate router as well.
+
+Please see the router faq +and the router +rules for more information.
+
+
+
+
+
  +i4 router
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
name
+
*i4
+
ip address
+
204.209.44.3
+
port
+
8080
+
scheduled maintenance
+
none
+
known issues
+
none
main router:
+
http://lpmuds.net/intermud.html
+
+
+Mudlist:
+
+
+
+
+
+
+
+ + + diff --git a/lib/www/lpmuds/arren_router.html b/lib/www/lpmuds/arren_router.html new file mode 100644 index 0000000..4eba2c1 --- /dev/null +++ b/lib/www/lpmuds/arren_router.html @@ -0,0 +1,191 @@ + + + + + + + + + LPMuds.net - Alternate Intermud Router + + + + + + + + + + +
+ + + + + + + +
LPMuds.net +
+ + + + + + +
A +resource site for LPC, LPMuds, and related stuffs.
+
+ + + + + + + + + + + + + + + + +
  Index + Forum Site +FAQ LPMud +FAQ   Intermud   Downloads + Links +  
+

+
+
LPMuds.net: +Arren's Intermud info
+
+ + + + + + +
This router is not +connected to yatmim/i4. I am not responsible for what happens +on it. The rules of this router, if there are any, are +not written anywhere I know of. I would advise new muds to exercise +caution when +connected to this router. Though I can't vouch for how you'll like +being there, I'm sure it's stable and fast. If you don't like the rules +or their enforcement at yatmim/i4, then adsr can be a good way to make +your feelings known, by voting with your feet. The admin of this router +is Arren at +Anarres II.
+
+You should probably read this (July 7, 2007) update before connecting, +so you know who you're affiliating with if you choose *adsr:
+ http://dead-souls.net/articles/router_controversy.html#update
+
+
+
+
+
  +adsr router
+
+
+ + + + + + + + + + + + + + + + + + + +
name
+
*adsr
+
ip address
+
62.49.9.82
port
+
9000
+
main router:
+
http://lpmuds.net/intermud.html
+
+
+Mudlist:
+
+
+Logs of the more active channels:
+
+Chanlogs
+
+
+
+
+
+
+
+ + + diff --git a/lib/www/lpmuds/dead_souls.png b/lib/www/lpmuds/dead_souls.png new file mode 100644 index 0000000..9599faa Binary files /dev/null and b/lib/www/lpmuds/dead_souls.png differ diff --git a/lib/www/lpmuds/discworld-faq.html b/lib/www/lpmuds/discworld-faq.html new file mode 100644 index 0000000..1d3abc6 --- /dev/null +++ b/lib/www/lpmuds/discworld-faq.html @@ -0,0 +1,224 @@ + + + + + Dead Souls FAQ + + + + +
Discworld Bundle FAQ

Written by Cratylus @ Dead Souls, October 2006

What is the first thing I should know?

What is the second thing I should know?

Who is this for?

What is Discworld?

Aren't you the Dead Souls maintainer? What's your angle here?

Why were you working on Discworld?

Well, you wasted your time. It doesn't work.

It works, but the thing keeps rebooting every 20 minutes.

Where can I get support for Discworld lib, then?

I work with DW lib all the time. It's not that hard to set up.

Where can I get it?

+What is the +first thing I should know?
+
+The Discworld Bundle is NOT DEAD SOULS. It is the Discworld mudlib,
+which is a completely different set of files than those distributed
+with Dead Souls. I, Cratylus, am not the author of Discworld, and
+you can consider this an official disclaim of any credit for its
+brilliance or blame for its pitfalls.
+
+What is the +second thing I should know?
+
+The authors and maintainers of the official Discworld mudlib
+do not take responsibility for this bundle. This is a strictly
+"third party" deal which they will not support in any way. You
+are free to download and use it, but you are not entitled to
+receive support from anyone. Note that I can't give you
+authorization to distribute it either, since I am not the
+copyright holder. If you want to mirror it, you'd be wise
+to ask the Discworld/FluffOS guys first, like I did.
+
+Who is this for?
+
+The Discworld bundle is absolutely not for newbie admins. This
+is not intended to be a "get started on your own mud the
+easy way!" sort of deal. I am making it available as a
+courtesy and favor to mudlib hobbyists who have an interest
+in tinkering with this lib. But if what you're looking for
+is a quick-start kit for your own mud, I strongly recommend
+you stop reading now and look elsewhere, because even though
+the Discworld Bundle makes installation easiER, it does not
+necessarily make it eaSY.
+
+What is +Discworld?
+
+You're best off reading the official definition on the
+Wikipedia entry +for the mud itself.
+
+And this is the entry +for the mudlib.
+
+
+Aren't you the +Dead Souls maintainer? What's your angle here?
+
+I am indeed the maintainer of a different mudlib
+called Dead Souls (which I am not ashamed to plug
+here by pointing you to its Wikipedia +entry). However, I
+have a general affection for the LP mud codebase family.
+During some experimentation I found that I had a
+relatively easier way of installing Discworld that people
+could take advantage of, and it seemed like a nice thing
+to do, making it available generally.
+
+I'm not afraid that people will use Discworld instead of
+Dead Souls. For one thing, I think that "more LPmuds",
+regardless of the codebase, is a net plus for DS. And
+anyway, what kind of lib author would I be, if I was
+afraid to let people compare my work side by side with that
+of others? Let the chips fall where they may.
+
+Why were you +working on Discworld?
+
+During Dead Souls development I decided to take a serious look
+at database integration. I discovered that the work done
+on Dead Souls before I became the maintainer lacked the
+core lib systems that were needed to have the lib and
+driver communicate with a database.
+
+So I started messing around with other libs, to see how they
+did it, to get some inspiration.
+
+Well, you +wasted your time. It doesn't work.
+
+There is such a vast and bewildering array of operating
+system and development software and system hardware architecture
+combinations out there that there is simply no way for
+me to guarantee that the bundle will work for everyone...
+or indeed for most.
+
+I can assure you that the bundle puts you much much closer
+to a successful DW start than you'd be without it. If it
+still doesn't work out of the box, there are a few pointers
+I might suggest:
+
+* I haven't tested this on Cygwin or any other Windows emulation
+or native windows compilation suite. For all I know it is not
+possible to get it to work on Windows.
+
+* DW/FluffOS expects your system to have file compression libraries.
+If you don't have zlib, or it's in an exotic location, or
+your library search path is munged, you will probably experience
+some level of sadness. If sadness what you feel, try ensuring
+that none of those three conditions apply to you.
+
+* Because dw seems to make frequent use of compression both
+for data storage and connections, some events appear to take
+an inordinately long period of time. This will be especially
+noticeable on slower computers. Just be patient.
+
+* Do NOT under ANY CIRCUMSTANCES attempt to contact Discworld
+mud personnel or Discworld mudlib maintainers to complain that
+this bundle is lame or to ask for help with it. It'll be like
+asking Bill Joy to come over and help you install Solaris. His
+involvement with the development of UNIX doesn't entitle you to
+help from him, and the Discworld people don't deserve to be
+exposed to noob brainwaves from people who think they are owed +assistance.
+
+* Perhaps the most important thing you can read is this:
+http://www.catb.org/%7Eesr/faqs/smart-questions.html
+Note that the people on that page also are not to be contacted for +support.
+
+
+It works, but +the thing keeps rebooting every 20 minutes.
+
+You got me there. I never claimed to be a Discworld expert. I
+can set it up so it's not impossible to install, but after that,
+getting it to work *well* is on you.
+
+Where can I get +support for Discworld lib, then?
+
+Once it is installed, it might not be unreasonable to
+ask for advice on the discworld-chat line. Certainly it's
+a good idea to review all the docs at the Discworld site:
+http://discworld.atuin.net/lpc/about/mudlib.html
+
+You're also welcome to visit the LPMuds.net +discussion forum
+and chat there, but don't expect quick turnaround on your
+questions. Discworld lib experts are fewer and far between
+than they once were, so you may have to wait a little
+for a helpful response.
+
+
+I work with DW lib all the time. It's not that hard to +set up.
+
+Now that I've done it, I have a better chance of being able to
+do it again starting from 0 again, in say, under 3 hours.
+
+Old DW'ers need to keep in mind that the driver available out
+there is FluffOS 1.22, which is sufficiently old to present
+inconveniences on newer compilers. The lib itself needs some
+refitting to work, such as the mappingp()/mappp() define
+conflict, and the max-number-of-inheritables problem in
+simul_efun.c. If you don't happen to be handy at truss/strace,
+or gdb, or coredump analysis, some of this stuff is super
+super hard to troubleshoot.
+
+The idea of this bundle is that people with advanced lib
+skills but limited compiling/syscall tracing experience
+can indulge in examining the lib, without having to
+invest days investigating problems that they can't tell
+whether they are lib issues, driver issues, bugs in
+either, or misconfigs.
+
+So, yes, definitely, there are lots of people out there for
+whom slapping dw together and checking it out is fairly
+ho-hum stuff, but the casual mud hobbyist has, from
+everything I've heard, found it too frustrating.
+
+Many people will still run into problems, I'm sure, but
+even for those, this should get them closer to the ballpark.
+
+
+Where can I get it?
+
+http://lpmuds.net/files/discworld/
+
+
+LPMuds.net
+
+
+ + diff --git a/lib/www/lpmuds/downloads.html b/lib/www/lpmuds/downloads.html new file mode 100644 index 0000000..d569a92 --- /dev/null +++ b/lib/www/lpmuds/downloads.html @@ -0,0 +1,523 @@ + + + + + + + + + LPMuds.net - Downloads + + + + + + + + + + +
+ + + + + + + +
LPMuds.net +
+ + + + + + +
A +resource site for LPC, LPMuds, and related stuffs.
+
+ + + + + + + + + + + + + + + + +
  Index Forum Site +FAQ LPMud +FAQ Intermud +   Downloads   Links +  
+

+
+
Downloads: MudOS +libraries
+
+ + + + + + +
THIS SECTION IS INCOMPLETE SO DONT GIMME +NO GUFF
+

+This is  a summary of currently-availableMudOS libs whose installation +difficulty level ranges from "easy-ish" to "moderate". The point of +this +page is to provide a convenient reference to those interested in trying +them out. These downloads are libs bundled with the driver (with +permission of the authors where required) for your convenience.
+
+Non-MudOS libs have a section below.
+
+ Note +about +licensing: Each of these libs comes with its own licensing +information. Do not +assume they are public domain, or GPL, or whatever.
+
+ Note +about +intermud: Most of these libs are designed or preconfigured to +connect to the intermud +router. Please read the router info and rules if you plan +on making use of that communication medium. Also, note this FAQ entry +on intermud security.
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Dead +Souls +2
+Comments: Easy to use, polished, and popular.
+Advantages: Works very well right out of the box, thoroughly +documented. UNIX and Windows version in the same download.
+Disadvantages: Uses the complex verb system. Function names are +different from older libs.
+Download: http://lpmuds.net/files/deadsouls/ds2.8.4.zip
+(Bleeding edge "alpha" development versions are available, but they are +only for the adventurous. You can look here for them.)
TMI-2
+Comments: Rarely used, except by old-timers. Newly revamped and +includes experimental Windows executable.
+Advantages: It's a solid lib, built by competent coders dedicated to +excellence.
+Disadvantages: It's showing its age. Lacks an advanced parser.
+Download: http://lpmuds.net/files/tmi2_fluffos_v2.zip
+(Note: this lib and included driver source have been modified to +compile and run on modern unix)
Skylib
+Comments: Seems nice enough. v3 is Skylib 1.8 on FluffOS. Windows +executable also included.
+Advantages: Should feel familiar to Discworld types.
+Disadvantages:  see above
+Download/Homepage: http://lpmuds.net/files/skylib_fluffos_v3.zip
+(Note: this lib and included driver source have been modified to +compile and run on modern unix)
Lima
+Comments: Easy to use, polished, and popular. Also work on Windows.
+Advantages: Works well when patched. Designed by experts +to be extremely advanced.
+Disadvantages: Not currently maintained. Not compatible with +add_actions. Perhaps too advanced for beginners.
+Download: http://lpmuds.net/files/lima_fluffos_v1.zip +
+
Merentha
+Comments: Based on the popular Nightmare 3 lib. Windows executable also +included.
+Advantages: Has the "Nightmare feel" and robustness without the +complications of verbs or weird lfun names.
+Disadvantages:  Limited intermud, and little available support.
+Download/Homepage: http://lpmuds.net/files/merentha_fluffos_v2.zip
+(Note: this lib and included driver source have been modified to +compile and run on modern unix)
Discworld
+Comments: Well liked, but rarely used. Newly updated with FluffOS 2.9 +and Windows driver.
+Advantages: The grotesquely popular Discworld MUD uses a +variation of this lib, so it must have something going for it.
+Disadvantages: Few adopters. Limited support.
+Download:  http://lpmuds.net/files/discworld/dw_fluffos_v3.zip
+(Note: this lib and included driver source have been modified to +compile and run on modern unix)
Final +Realms
+Comments: Interesting. Based on Discworld. Newly updated with FluffOS +2.9 and Windows driver.
+Advantages: Lots and lots and lots and lots of example. Also, lots of +examples.
+Disadvantages: Peculiar and idiosyncratic. Fixer-upper.
+Download:  http://lpmuds.net/files/final_realms_fluffos_v1.zip
+(Note: this lib and included driver source have been modified to +compile and run on modern unix)
Dead +Souls +I
+Comments: Dead Souls I is nearly identical to Nightmare IV except the +docs are missing.
+Advantages: Public domain, so lib licensing is no worry. Simpler than +DS2.
+Disadvantages: See "Dead Souls 2" above.  DS1 may contain some +bugs  that are fixed in DS2.
+Download: http://lpmuds.net/files/deadsouls/dsI.zip
+(Note: this lib and included driver source have been modified to +compile and run on modern unix)
LPUniversity +Mudlib
+Comments: Not ready for play. Newly updated with FluffOS. Windows +driver also included.
+Advantages: Provides a chance to build a lib from +the ground up without +having to deal much with the driver.
+Disadvantages: No longer developed. +Fixer-upper.
+Download/Homepage: http://lpmuds.net/files/lpuni_fluffos_v1.zip
+(Note: this lib and included driver source have been modified to +compile and run on modern unix)
+
Nightmare
+Comments: An influential early lib family. Newly revamped: Unix and +Windows +driver included together.
+Advantages: Heavily documented and widely known.
+Disadvantages: NM3 is woefully outdated. NM IV is less so, but still +long in the tooth.
+Nightmare 3 Download: http://lpmuds.net/files/nightmare3_fluffos_v2.zip
+Nightmare IV Download: http://lpmuds.net/files/nightmare4_fluffos_v1.zip
+(Note: this lib and included driver source have been modified to +compile and run on modern unix)
+
Lil
+Comments: This is a fixed up version of the MudOS "testsuite" lib with +MudOS docs added. Unix source and Windows executable included.
+Advantages: Clean as a whistle. You can log in and use a few commands, +but otherwise it's bare metal so you can code from the ground up.
+Disadvantages: This is about as bare bones as it gets without coding +100% from scratch. You really need to know what you're doing. No +intermud. For the seriously leet only!
+Download: http://lpmuds.net/files/lil_0.3.zip
+(Note: this lib and included driver source have been modified to +compile and run on modern unix)
+
Foundation
+Comments: This is a stripped-down version of Nightmare. Unix source and +Windows executable included.
+Advantages: No combat, or limbs, etc. This is good for people who like +NM or DS but feel it is too cluttered.
+Disadvantages: It's much more accessible than Lil, but it is not at all +for LPC beginners. Not even close. Experts +only!
+Foundation I Download: http://lpmuds.net/files/foundation/foundation1_fluffos_v1.zip
+Foundation II Download: http://lpmuds.net/files/foundation/foundation2_fluffos_v1.zip
+(Note: this +lib and included driver source have been modified to +compile and run on modern unix)
+
+
+
+
+
+
External +Downloads: Non-MudOS +libraries
+
+ + + + + + +
THIS SECTION IS ALSO INCOMPLETE SO DONT +GIMME +NO GUFF, STILL
+

+This is  a summary of currently-available libs for non-MudOS +drivers. Most of these downloads are hosted on external sites, and not +LPmuds.net, because I am not involved in their development, or their +easyfication, or anything about them at all. If you download them and +lose your mind trying to install them, your mental health does not +become my responsibility. If the link is dead or does not yield an +actual download, feel free to do the research required on your own, +without bothering me.
+
+
+ Bundled Libs
+ + + + + + + + + +
Phantasmal
+Comments: This is version 0.018 of Phantasmal bundled with DGD 1.2.110
+Advantages: Reputed to be the most complete publicly downloadable lib +for DGD.
+Disadvantages: No intermud.
+Download http://lpmuds.net/files/phantasmal_dgd_v1.tar.gz
+
Gurba
+Comments: Updated Gurba lib plus an intermud-enabled version of DGD.
+Advantages: Currently maintained by a competent coder.
+Disadvantages: Relatively small set of working examples and areas.
+Download http://wotf.org/downloads/gurba/ +(older versions here)
+
+
+
+
+ Unbundled Libs
+ + + + + + + + + + + + + + + + + + +
LDmud ( http://www.bearnip.com/lars/proj/ldmud.html +)
+
+OSB http://www.bearnip.com/ftp/mud/osb-lib-030218.tar.gz
+Heaven 7 (updated by Mordain) http://lpmuds.net/files/heaven7_4a2_pkg-004.tar.gz
+Tublib http://www.tubmud.de/ftp/distributions
+
+
DGD ( http://www.dworkin.nl/dgd/ )
+
+Melville ftp://ftp.dworkin.nl/pub/dgd/lib/Melville/melville_0.9.1.tar.gz
+Gurbalib http://gurba.sytes.net/~erlends/gurba.html
+
+
Shattered World +( http://www.shattered.org/ )
+
+SWlib http://sourceforge.net/projects/swlpc
+
+
CD ( http://www.genesismud.org/students/index +)
+
+CDlib http://www.genesismud.org/svn/mudlib/trunk
+
+
(The Original) +LPmud (aka 2.4.5 aka 3.x aka Amylaar)
+
+
LPmud http://mudbytes.net/index.php?a=files&cid=230
+
+
+
+
+
+
+
  +Other downloads
+
+
+ + + + + + + + + + + + +
+
Windows editors:

The #1 problem in Windows is that the default plaintext
editor, Notepad, produces text that is not 100% compatible with the
mud. Windows plaintext and UNIX plaintext differ, believe it
or not. If you use notepad for editing mudos.cfg, for example,
your mud is likely to just fail to boot. This is because it
can no longer read the "incorrectly" formatted file.

The other big problem with Notepad and Wordpad is that
they often add formatting and characters to text files that
make them very ugly and hard to read from inside the mud.

The solution is to use a text editor that can save in
UNIX text format. The following URLs point to editors that I
have been told will do a good job of this. I can't vouch for
them, as they are 3rd party apps and I've never tested them, but
I am assured they are very good for this.

Notepad++ http://notepad-plus.sourceforge.net/uk/site.htm

WinVi http://www.winvi.de/en/


Notepad2 http://www.flos-freeware.ch/notepad2.html
+
+
Windows clients:

I can't imagine using the default Windows telnet client for
long. It is so bereft of features as to be actually worse than the
crappiest UNIX (or even VMS!) clients from 1993...Windows telnet is
worse than the worst from fifteen years ago.

There are a ton of great Windows mud clients out there.
Anyway, that's what I hear. Back when I used windows, I used a free
version of Zmud, and sometimes a less preferred Gmud. Zmud is now
a non-free application, so you have to buy it to use it. However,
they do still allow free distribution of a crappy, super old
version of the client.


Gmud http://frontiers.wcsu.ctstateu.edu/gmud.exe


Old Zmud 3 from 1996 (not my prob if it's broken)
http://frontiers.wcsu.ctstateu.edu/zmud.zip

+
+
UNIX clients:

The client I use is gmoo 0.5.6. It has its drawbacks, but it
works ok, in general, and I'm used to it. An older version of it is
gMOO 0.4.8, and I've found it's a little easier to compile on some
newer UNIXes, for reasons beyond me.

Though I'd been reluctant to use it (fear of a CLI
client), the TinyFugue client, aka "tf", is a magnificent piece of
work that is worth becoming familiar with.

gmoo 0.5.6 http://frontiers.wcsu.ctstateu.edu/gmoo-0.5.6-11c.tgz
(Debian fixes applied, plus a bugfix for a prompt problem supplied by Haderach @ Frontiers )

gMOO 0.4.8 http://frontiers.wcsu.ctstateu.edu/gMOO-0.4.8.tar.gz

tf http://tinyfugue.sourceforge.net/
+
+
+
+
+
+
+
+ + + diff --git a/lib/www/lpmuds/fader.js b/lib/www/lpmuds/fader.js new file mode 100644 index 0000000..97021d5 --- /dev/null +++ b/lib/www/lpmuds/fader.js @@ -0,0 +1,118 @@ +// smfFadeIndex: the current item in smfFadeContent. +var smfFadeIndex = -1; +// smfFadePercent: percent of fade. (-64 to 510.) +var smfFadePercent = 510 +// smfFadeSwitch: direction. (in or out) +var smfFadeSwitch = false; +// smfFadeScroller: the actual div to mess with. +var smfFadeScroller = document.getElementById('smfFadeScroller'); +// The ranges to fade from for R, G, and B. (how far apart they are.) +var smfFadeRange = { + 'r': smfFadeFrom.r - smfFadeTo.r, + 'g': smfFadeFrom.g - smfFadeTo.g, + 'b': smfFadeFrom.b - smfFadeTo.b +}; + +// Divide by 20 because we are doing it 20 times per one ms. +smfFadeDelay /= 20; + +// Start the fader! +window.setTimeout('smfFader();', 20); + +// Main fading function... called 50 times every second. +function smfFader() +{ + if (smfFadeContent.length <= 1) + return; + + // A fix for Internet Explorer 4: wait until the document is loaded so we can use setInnerHTML(). + if (typeof(window.document.readyState) != "undefined" && window.document.readyState != "complete") + { + window.setTimeout('smfFader();', 20); + return; + } + + // Starting out? Set up the first item. + if (smfFadeIndex == -1) + { + setInnerHTML(smfFadeScroller, smfFadeBefore + smfFadeContent[0] + smfFadeAfter); + smfFadeIndex = 1; + + // In Mozilla, text jumps around from this when 1 or 0.5, etc... + if (typeof(smfFadeScroller.style.MozOpacity) != "undefined") + smfFadeScroller.style.MozOpacity = "0.90"; + else if (typeof(smfFadeScroller.style.opacity) != "undefined") + smfFadeScroller.style.opacity = "0.90"; + // In Internet Explorer, we have to define this to use it. + else if (typeof(smfFadeScroller.style.filter) != "undefined") + smfFadeScroller.style.filter = "alpha(opacity=100)"; + } + + // Are we already done fading in? If so, fade out. + if (smfFadePercent >= 510) + smfFadeSwitch = !smfFadeSwitch; + // All the way faded out? + else if (smfFadePercent <= -64) + { + smfFadeSwitch = !smfFadeSwitch; + + // Go to the next item, or first if we're out of items. + setInnerHTML(smfFadeScroller, smfFadeBefore + smfFadeContent[smfFadeIndex++] + smfFadeAfter); + if (smfFadeIndex >= smfFadeContent.length) + smfFadeIndex = 0; + } + + // Increment or decrement the fade percentage. + if (smfFadeSwitch) + smfFadePercent -= 255 / smfFadeDelay * 2; + else + smfFadePercent += 255 / smfFadeDelay * 2; + + // If it's not outside 0 and 256... (otherwise it's just delay time.) + if (smfFadePercent < 256 && smfFadePercent > 0) + { + // Easier... also faster... + var tempPercent = smfFadePercent / 255, rounded; + + if (typeof(smfFadeScroller.style.MozOpacity) != "undefined") + { + rounded = Math.round(tempPercent * 100) / 100; + smfFadeScroller.style.MozOpacity = rounded == 1 ? "0.99" : rounded; + } + else if (typeof(smfFadeScroller.style.opacity) != "undefined") + { + rounded = Math.round(tempPercent * 100) / 100; + smfFadeScroller.style.opacity = rounded == 1 ? "0.99" : rounded; + } + else + { + var done = false; + if (typeof(smfFadeScroller.filters.alpha) != "undefined") + { + // Internet Explorer 4 just can't handle "try". + eval("try\ + {\ + smfFadeScroller.filters.alpha.opacity = Math.round(tempPercent * 100);\ + done = true;\ + }\ + catch (err)\ + {\ + }"); + } + + if (!done) + { + // Get the new R, G, and B. (it should be bottom + (range of color * percent)...) + var r = Math.ceil(smfFadeTo.r + smfFadeRange.r * tempPercent); + var g = Math.ceil(smfFadeTo.g + smfFadeRange.g * tempPercent); + var b = Math.ceil(smfFadeTo.b + smfFadeRange.b * tempPercent); + + // Set the color in the style, thereby fading it. + smfFadeScroller.style.color = 'rgb(' + r + ', ' + g + ', ' + b + ')'; + } + } + } + + // Keep going. + window.setTimeout('smfFader();', 20); +} \ No newline at end of file diff --git a/lib/www/lpmuds/favico.ico b/lib/www/lpmuds/favico.ico new file mode 100644 index 0000000..d76c824 Binary files /dev/null and b/lib/www/lpmuds/favico.ico differ diff --git a/lib/www/lpmuds/favicon.ico b/lib/www/lpmuds/favicon.ico new file mode 100644 index 0000000..d76c824 Binary files /dev/null and b/lib/www/lpmuds/favicon.ico differ diff --git a/lib/www/lpmuds/fonts-compat.css b/lib/www/lpmuds/fonts-compat.css new file mode 100644 index 0000000..001c72f --- /dev/null +++ b/lib/www/lpmuds/fonts-compat.css @@ -0,0 +1,16 @@ +body, td, .normaltext, .windowbg, .windowbg2, .titlebg, .bordercolor, .tborder, .catbg, .catbg2, .windowbg td, .windowbg2 td, .titlebg td +{ + font-size: x-small; +} +.smalltext, td.smalltext, i.smalltext, div.smalltext, .smalltext td, .quote, .quoteheader, .codeheader , .middletext +{ + font-size: xx-small; +} +.code +{ + font-size: xx-small; +} +.largetext +{ + font-size: medium; +} \ No newline at end of file diff --git a/lib/www/lpmuds/forum-faq.html b/lib/www/lpmuds/forum-faq.html new file mode 100644 index 0000000..adc032e --- /dev/null +++ b/lib/www/lpmuds/forum-faq.html @@ -0,0 +1,39 @@ + + + + + LPMuds Forum Software FAQ + + + + +
LPMuds.net Forum Software FAQ

Written by Cratylus @ Frontiers, October 2006

This is the ugliest forum software I have ever seen. Why don't you change it?

You are a tricksy trickster! This is not an LPC site, it is a Dead Souls site!


This is the ugliest forum software I have ever seen. Why don't you change it?

Ok, let me make a few points, which add up to the reason
we are where we are:

* I'm not a web developer *at all*. My idea of a well-designed
page is black text on a white background...period.

* The LPMuds.net forums started up around the same time that the
LPUniversity forums died and LPU closed down. The Beehive software
was the thing I happened to be testing at that point. I realized there
was a pressing need to have forums available, so by happenstance
Beehive happened to draw the short straw.

* Because my aesthetics are simple to the point of primitivity, it
honestly never occurred to me that anyone would complain about the
forum software. I'm not kidding! To me, it's simple, it works, end of story.

* As more and more people gripe about the site, I realize there is
a general feeling of displeasure with the forum software. This is
supported by the informal poll held some weeks back.

* I take these complaints seriously, and for the past few weeks
have been working on trying out different webserver/database/forum
configs. I am, honestly, for real, developing a solution.

* This will take some time. It will take time because I
do not want to have to do it again, and I therefore will be making sure
that it is done right. Since this is my first entanglement with
forum software, I am learning as I work, which slows the process more.

* In theory I could scrap the current stuff and just put up new stuff
immediately. However, I feel very strongly that the site's success
relies on the faith people can have on the integrity of its
continuity. I do not want to establish a reputation, right from the start,
of a site that discards user data and forum content as convenience wills.

* Therefore part of the solution involves a migration plan for the
current database. Since there are limited automated options, I need
to teach myself sufficient SQL (of which I know nothing) to do this
properly. Again, this will take time.

* I look forward to this work. I am actually enjoying developing this
solution. I've wanted an excuse to learn database stuff, and this is
really a wonderful opportunity. You can expect that I will put the
same level of zeal into this solution as I have into the lib work
I've done.

* Those who know me know that I don't do empty promises. What I say
I will do, I do.

* However, most of my waking hours involve me working on things that
actually feed my family and shelter us from the elements. I can offer
you no timetables, nor a specific plan.

* What I can promise is that I will do my best, and I believe it will
suffice. Once I've got things roughly under control, I'll open a test
site where people can offer critiques and comments, etc. Obviously it
will not be possible to please everyone, but I will do my best to be
a responsive site admin.

* In the meantime, I ask for your patience. I'm scrupulously patient
with LPC newbies. Please be patient with my admin site noobicity. We'll
get there, I promise.


You are a tricksy trickster! This is not an LPC site, it is a Dead Souls site!

There is no debate about what, as of this writing, is the overwhelming
content of the site: discussion of the Dead Souls 2 LP mudlib. I maintain
that lib, and I own this site. There is an obvious bias in the current
demographics of the site membership.

I mean...you know. Duh.

However, the point of my work has been not only a revival of Dead Souls, but
a revival of LPC by using Dead Souls as a tool to get to that renaissance.

Perhaps I am deluded in my belief that spreading popularity of Dead Souls
is a net plus for LPC. I grant you that. But don't doubt that this is my
honest belief. My maniacal fanaticism in support of Dead Souls should be
clear evidence that I may not be rational on this point, and merit a
little humoring.

That aside, I do think that a reliable, trustworthy site open to any and all
LPC discussion is sorely needed, and I want to make it possible for that
site to be lpmuds.net. I have been making clear to everyone that all
LPC discussion, regardless of driver or lib, is welcome and encouraged,
and it is my hope that, though started as largely a DS support site, it
becomes a hub for activity and discussion of LPC of all persuasions.

Call me nutty or mistaken. But don't call me deceptive. I'm up front about
what I'm trying to do, and people can decide for themselves whether
they like it.
+The end.
+
+LPMuds Homepage
+
+
+ + diff --git a/lib/www/lpmuds/forums.html b/lib/www/lpmuds/forums.html new file mode 100644 index 0000000..5e3b5a5 --- /dev/null +++ b/lib/www/lpmuds/forums.html @@ -0,0 +1,55 @@ + + + + Other MUD forums + + + + + + + + + + + + + + + +
+

Other (Not-necessarily-LP) MUD Forums

+
+

+http://mudbytes.net/index.php
+
+http://www.topmudsites.com/
+
+http://www.mudconnect.com/
+
+http://www.mudlab.org/
+
+http://www.electricsoup.net/?q=forum
+
+http://lpuni.org (possibly dead)
+
+http://games.groups.yahoo.com/group/codersclub/
+
+
+- Cratylus +
+<my name here>@comcast.net +
+
LPMuds.net +
+
+ + diff --git a/lib/www/lpmuds/help.css b/lib/www/lpmuds/help.css new file mode 100644 index 0000000..98bf3bf --- /dev/null +++ b/lib/www/lpmuds/help.css @@ -0,0 +1,69 @@ +h1 +{ + font-size: 18px; + margin: 1ex 1ex 1ex 1ex; +} +h2 +{ + font-size: 18px; + border-bottom: solid 1px; + padding-bottom: 1ex; +} +h3, h4, h5, h6 +{ + font-size: 16px; + margin: 0; +} +p +{ + margin: 0 0 1.5em 0; +} +.board, .board:link +{ + text-decoration: underline; +} +.board:visited, .board:hover +{ + text-decoration: underline; +} +div.footer +{ + text-align: center; + padding: 3pt; +} +#menu +{ + line-height: 1; +} +#menu p +{ + margin: 0 0 1em 0; + line-height: 2; +} +table#reference1, table#reference2 +{ + border: 1px solid; +} +table#reference1 td, table#reference2 td +{ + vertical-align: top; + border: 1px solid; + font-size: x-small; + } +table#reference1 th, table#reference2 th +{ + font-size: x-small; +} +ol +{ + font-weight: bold; + list-style-type: square; + margin-bottom: 2ex; + margin-top: 3ex; +} +ol.la +{ + font-weight: normal; + list-style-type: circle; + margin: 0 0 2ex 4ex; +} diff --git a/lib/www/lpmuds/index.html b/lib/www/lpmuds/index.html new file mode 100644 index 0000000..19414b4 --- /dev/null +++ b/lib/www/lpmuds/index.html @@ -0,0 +1,206 @@ + + + + + + + + + + LPMuds.net - Index + + + + + + + + + + +
+ + + + + + + +
LPMuds.net +
+ + + + + + +
A +resource site for LPC, LPMuds, and related stuffs.
+
+ + + + + + + + + + + + + + + + +
   Index   Forum Site +FAQ LPMud +FAQ Intermud + Downloads + Links +  
+

+
+
LPMuds.net: +about us
+
+ + + + + + +
This is a site dedicated to a +kind of online, text-only, virtual reality game called LPMud. Here you +can find links to documentation, downloads, and games which use or are +related to LPMud. Please see the linked tabs above for more +information. Detailed information on those links follows:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
Forum
+
This is the main feature of the +site. A place for folks to hang out and talk about LPC and LPMuds in a +friendly atmosphere.
+
Site FAQ
+
Information about why this site +exists, guiding principles and rules.
+
LPMud FAQ
+
An old but still interesting FAQ +on LPMuds from Usenet days.
+
Intermud
+
A reference page for current +status of the official LPMuds.net I3 router, and connection information.
+
Downloads
+
A helpful repository of LPMud +related programs and files.
+
+
+
+
+
+
LPMuds.net: +Recent threads
+
+
+ + + + + + +
These are the most recent +threads from the LPmuds.net forum.
+
+ + + + + + +

+
+
+
+
+
+
+ + + diff --git a/lib/www/lpmuds/index.php b/lib/www/lpmuds/index.php new file mode 100644 index 0000000..19414b4 --- /dev/null +++ b/lib/www/lpmuds/index.php @@ -0,0 +1,206 @@ + + + + + + + + + + LPMuds.net - Index + + + + + + + + + + +
+ + + + + + + +
LPMuds.net +
+ + + + + + +
A +resource site for LPC, LPMuds, and related stuffs.
+
+ + + + + + + + + + + + + + + + +
   Index   Forum Site +FAQ LPMud +FAQ Intermud + Downloads + Links +  
+

+
+
LPMuds.net: +about us
+
+ + + + + + +
This is a site dedicated to a +kind of online, text-only, virtual reality game called LPMud. Here you +can find links to documentation, downloads, and games which use or are +related to LPMud. Please see the linked tabs above for more +information. Detailed information on those links follows:
+
+ + + + + + + + + + + + + + + + + + + + + + + +
Forum
+
This is the main feature of the +site. A place for folks to hang out and talk about LPC and LPMuds in a +friendly atmosphere.
+
Site FAQ
+
Information about why this site +exists, guiding principles and rules.
+
LPMud FAQ
+
An old but still interesting FAQ +on LPMuds from Usenet days.
+
Intermud
+
A reference page for current +status of the official LPMuds.net I3 router, and connection information.
+
Downloads
+
A helpful repository of LPMud +related programs and files.
+
+
+
+
+
+
LPMuds.net: +Recent threads
+
+
+ + + + + + +
These are the most recent +threads from the LPmuds.net forum.
+
+ + + + + + +

+
+
+
+
+
+
+ + + diff --git a/lib/www/lpmuds/intermud.html b/lib/www/lpmuds/intermud.html new file mode 100644 index 0000000..af8d86d --- /dev/null +++ b/lib/www/lpmuds/intermud.html @@ -0,0 +1,882 @@ + + + + + + + + + LPMuds.net - Intermud + + + + + + + + + + +
+ + + + + + + +
LPMuds.net +
+ + + + + + +
A +resource site for LPC, LPMuds, and related stuffs.
+
+ + + + + + + + + + + + + + + + +
  Index Forum Site +FAQ LPMud +FAQ   Intermud   Downloads + Links +  
+

+
+
LPMuds.net: +Intermud info
+
+ + + + + + +
Intermud communication protocols allow muds +which are fitted with the appropriate clients to communicate with each +other. Intermud-3 and IMC2 are intermud protocols that communicate +through a server which acts as a communications hub. The LPMuds.net +intermud network links several hubs together into a single +communication space. This network is most often used for chatting and +asking for technical help.
+
+Please see the faq and the rules +for more information.
+
+
+
+
+
  +LPMuds.net intermud network hubs
+
+
+The hub (or "router") for connecting to LPMuds.net intermud with the Intermud-3 protocol is called *i4 + + + + + + + + + + + + + + + + + + + + + + + +
name
+
*i4
+
ip address
+
204.209.44.3
+
port
+
8080
+
scheduled maintenance
+
None.
+
known issues
+
14 Apr 2009 http://lpmuds.net/forum/index.php?topic=242.msg5113#msg5113
+
+Note: Connecting to *i4 with +an IMC2 client will not work
+
+
+The hub (or "server") for connecting to LPMuds.net intermud with the IMC2 protocol is called Dalet + + + + + + + + + + + + + + + + + + + +
ip address
+
97.107.133.86
+
port
+
8888
+
scheduled maintenance
+
None.
+
known issues
+
The IMC2 hub is in +beta testing. Please report any bugs. SHA-256 is NOT supported.
+
+Note: Connecting to Dalet with +an i3 client will not work
+
+
If your mud is an LP mud, it most likely uses primarily +Intermud-3. If your mud is a Diku derivative, it most likely uses +primarily IMC2.
+

+
+List of muds up and connected to the +LPMuds.net intermud network:
+
+
+Channel logs can be viewed here:
+http://ebspso.dnsalias.org/i3logs/
+
+
+
+
+
+
+
+
+
  +Popular channels
+
+

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Router-side +channel nameDS +local channel nameChannel +topicProtected?
dchat
+
dchat
+
Friendly offtopic chat (PG-13 +rated)*.
+
yes
+
dead_souls
+
ds
+
Friendly Dead Souls talk (PG-13 +rated)*.yes
dead_test4
+
ds_test
+
Channel and connection testing*.
+
yes
dgd
+
dgd
+
Discussion of the DGD driver and +related matters.
+
yes
+
imud_gossip
+
intergossip
+
General offtopic chat (NC-17).
+
yes
imud_code
+
intercre
+
General technical chatter*.
+
yes
lpuni
+
lpuni
+
LPUniversity-related discussion*.
+
yes
ascii_art
+
ascii_artSpammy ascii stuff and related +chat.
+
no
+
inews
+
inewsRSS feeds from popular news sites.
+
no
mudnews
mudnewsRSS feeds from popular mud forums.
+
no
discworld-chat
+
discworld-chatDiscworld MUD and lib chat.
+
no
dutch
+
dutchChat in Nederlands.
+
no
german
+
germanChat in Deutsch.
+
no
bofh
+
bofhTechnical discussion.
+
no
coffeemud-universe
+
coffeemud-universeCoffeemud related talk.
+
no
free_speech
+
free_speechWhere offensive stuff goes.
+
no
+* Asterisk indicates a channel available by default on Dead Souls.
+
+
+ +
+ +
+
+
+
  +Network FAQ
+
+

+
+1. What are the rules?
+
+2. Is it private?
+
+3. Is the network "secure"?
+
+4. What's the point of a new router? Who died and +made you intermud king?
+
+5. ZOMG! The *gjs router is down now! It's your fault!
+
+6. How do I connect to it?
+
+7. It doesn't work.
+
+8. How does the router work?
+
+9. Is router code part of Dead Souls?
+
+10. How do I become my own I3 router?
+
+11. I am so SICK of you being an intermud FASCIST.
+
+12. Why does it suck?
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
What are the rules?
+
+Please read the rules below. Refugees from +*gjs are welcome, so long as they abide by those rules.
+
Is it private?
+
+No. Everyone is welcome.
+
Is the network "secure"?
+
+Nope. Read this: http://dead-souls.net/ds-admin-faq.html#90
+Bottom line: Don't tell secrets on the network.
+
What's the point of a new router? Who died +and made you intermud king?
+
+    On the morning of 27 March 2006, the intermud.org i3 +router stopped functioning. There had been some talk on the dead_souls +channel of how unreliable the i3 router was, and how we should make our +own, etc, yakety schmakety.
+
+    March 27th was the last straw. For Dead Souls +developers, the dead_souls intermud channel was a vital resource for +development discussion and support. I +decided it was time to implement a router that the Dead Souls muds +could count on.
+
ZOMG! The *gjs router is down now! It's +your fault!
+
+I honestly have no idea at all what happened to the gjs router. During +June and July of 2006, it seemed to be up about as often as it was +down...it was unreliable in the extreme. I'd never seen it that bad +before.
+
+Then, in August 2006, while discussing this unreliability:
+
+[2006.08.01-13.45] Salius@Elanathia <imud_gossip> so what keeps +happening, why does it crash
+[2006.08.01-14.03] Cratylus <intergossip> who runs it? are they +ever on?
+[2006.08.01-14.05] Zakk@Lima Bean <imud_gossip> 'run' hahaha etc
+
+And that's the last transmission I'm aware of, as of today, 21 September +2008. As if it weren't bad enough that it looks like it's down for the +count, it also appears Zakk had the last word.
+
+Please note. If I'd known gjs would die, I would not have made the +intergossip channel a default for Dead Souls muds. I had no intent to +be The New Intermud For Everyone, and I didn't know it would happen, so +please don't imagine I'm trying to reform anyone. I'm just running my +own router, to which you're invited if you follow the rules.
+
How do I connect to it?
+
+Instructions for Dead Souls 2 MUDs:
+To switch back and forth between the routers, use the switchrouter +command. For syntax and instructions,
+type: help switchrouter
+
+Other muds will need to follow their intermud subsystem documentation. +Note +that there may be multiple files and multiple parts of those files that +need to be updated with the current information.
+
I3 doesn't work

+    Getting the router name wrong is the number one +cause of errors. Also, once you get it wrong, your own client cache +might keep the old one, even if you change your intermud client code. +Make sure you purge the i3 data cache before you try again.
+
+    Another major cause is that the router name is +right, but you've chosen a mud name someone +else already is using. If your mud's name is "DeadSoulsNew" or "Your +Mud's Name" or "ds-test" or "TestMud" or somesuch, the router won't let +you on because +some other newbie got there before you and now the router has +associated their ip with that that name. Pick something unique and try +again.
+
+    The next most likely reason you can't connect is +that your mud handles intermud passwords incorrectly and your ip +address changed. The way intermud passwords work is this:
+
+1) You connect to the intermud router
+2) It generates a random number and gives it to you. That's your +password.
+3) If you disconnect, then come back with a different ip address, your +mud sends that password to the router which then says "ok I recognize +that password as being for your mud, I'll let you on".
+
+    If your mud's I3 client doesn't save your password +and your ip address changes (which can happen very frequently if your +mud is on a DSL or cable modem) then the router will assume you are not +who you say you are, and deny the connection. To see if this is what's +happening, change your mud name to something new (and unique) and try +again.
+
+    In some cases, some muds misbehave in a way that is +either unacceptable to the router, violates the router rules, or +interferes with the normal operation of the router. If your mud does +not have a useful admin contact email address that it sends to the +router on connection, then nobody can be contacted to help correct this +situation. This means your mud may have been banished or firewalled out +without you knowing about it. If the router in question is yatmim or +i4, send me an email. My name is Cratylus, and I have an email account +with a comcast dot net domain address.
+
+    Under some circumstances, such as an unusually +lossy/unstable network connection, and most specifically a wireless +connection, the router may have a hard time maintaining your mud +online, and once dropped, you may not be able to get back on. At the +risk of being old-fashioned, I suggest that you put your mud on a +stable, land-line internet connection.
+
+    Finally, it may be that the router you've chosen is +dead or temporarily offline. Try one of the routers listed above, or +ask on the intermud +board of the lpmuds.net discussion forum to see if someone has set +up a different router for you to use.
+
How do the hubs work?
+
+    Tim@TimMUD wrote a swell LPC based I3 router that is +basically a bunch of .h files you put into a TMI-2 mud. You tinker with +the settings a bit, and your TMI-2 mud becomes an intermud router.
+
+    I installed it in a Dead Souls mud, and it's been +updated to handle a multiple-hub network, as well as translating IMC2 +data.
+
Is hub code part of Dead Souls?
+
+With Tim's blessing I've included his I3 router in the Dead Souls +distribution, after removing/replacing some non-Tim code. This means +that any Dead Souls mud can serve as a hub, should it wish to +establish its own intermud network. Eventually these individual hubs +may be part of a failover network, but there are no firm plans +for this in place.
+
How do I become my own hub?
+
+Read the code in /secure/daemon/i3router and /secure/daemon/imc2server. +Understand it. Then modify it +to suit you. I won't be posting step-by-step instructions on how to do +this, because I believe this is one of those things that you really +need to figure out on your own. If you can't figure it out by reading +the code, I argue you have no business running the router.
+
I am so SICK of you being an intermud +FASCIST
+
+It's puzzling how often I get this. Even though the router +rules are prominently shown, and I have shown willingness to +confront offenders, some people still insist on trying to make racist +comments on the protected channels, or try to harsh out newbies.
+
+I don't know which part of "this is +not the old router" and "this +router +has enforced rules" is hard to understand. There is, perhaps, a +sense of +entitlement to any channel named "intergossip" regardless of the router.
+
+I really don't ask for much. Just follow the rules on the few protected +channels, and adhere to their declared topics. You're here as a guest, +by choice. If you don't like it, you are free to make your own channel +for trash talk, and of course, you are free to disconnect  at any +time.
+
Why does it suck?
+
+The yatmim router started off as an ad-hoc sort of thing. gjs was down +a lot, and newbies got harshed out a lot, and it seemed reasonable to +slap something together for DS muds to get around those obstacles. From +its start, roughly April 2006, to about September 2006, it was really +only Dead Souls muds that ever connected to it. I spent a long time +tweaking things, and by September the router, I thought, was in dead +solid shape. When gjs went down for the count, I figured yatmim was +ready for prime time.
+
+I was mistaken.
+
+It turns out that there are many ways to interpret the I3 specs. It +also turns out that in spots, the specs are oddly silent, and those +silences can also be interpreted in many ways. Different libs and +codebases have implemented their I3 subsystems and tuned it for their +specific needs, with gjs's specific habits in mind. Tim's +interpretation of the I3 router specs was a solid one, and done in good +faith. But it was different enough from the way gjs conducted business +that some muds have had a tough time adjusting.
+
+An example of this is the recent tuning I did. Some muds send a startup +request packet indicating they are using protocol 2, but the packet +itself is formatted for protocol 3. Tim's router justifiably rejected +such errored data. gjs, apparently, forgave it. I have therefore +changed yatmim to implement that forgiveness, so that old muds with +this legacy header can join. Now imagine a bunch of other minor +variances like this. It's not the sort of stuff you can test for on a +lab system and nail each one...it's real world conflicts that can only +be found and corrected while running in production.
+
+So, because some of this stuff can only be diagnosed live, and because +fixing it requires bringing down the public server, some people have +gotten the idea that "yatmim sucks". This, I think, is not true, and +unfair. yatmim is undergoing some turbulence while I catch and squash +these unexpected problems. However, the code itself is rapidly +approaching the kind of stability that I can be proud of, and I'm happy +to be able to provide that to the community. I3 node uptime regularly +reaches sixteen weeks or more.
+
+The short answer as to why the i3 router sucks +is "It doesn't any more."
+
+The IMC2 +server is still in its very early infancy, though, and there is still +much work to do. If the IMC2 connection to the LPMuds.net network is +not working like you think it should, please let me know +what's going on so I can try to address it.
+
+
+
+
+
+ + +
+
+
+
  +Network Rules
+
+
+1) The point of this network being up is not free +speech.
+
+2) This network is up for the following purposes:
+
+    * To provide technical help for muds.
+    * To provide a friendly space for chat between muds.
+    * To test and improve mud communication systems, +such as intermud mail.
+
+3) The network is not up for testing security of an +intrermud network. Attempting
+   to exploit the hubs is not ok, and not "cool". If you +find
+   a security weakness please email me so I can handle it +discreetly.
+   You will get full credit for the discovery when the patch +comes out.
+
+4) The following are not tolerated on protected +channels: hate speech, social engineering
+   hacks, being Robert Mugabe, unwarranted hostility to newbies, spamming, +commercial advertising. All of
+   these will be judged by my subjective opinion of what +constitutes a violation.
+   Types of violations can be added to this list without +warning by me.
+
+5) Otherwise legitimate use of a non-protected channel +or hub subsystem which
+   interferes with normal function of the network is not +tolerated.
+
+6) You may create intermud channels for your mud. These +channels can
+   have any content you want that is permissible by all +applicable laws. I
+   don't want to control the intermud with an iron hand. I +just want those protected
+   channels listed above to be a safe place for newbies to +congregate, socialize,
+   and/or get work done.
+
+7) If you don't like these rules, set up your own +network.
+
+8) I will not help or support you in any way in setting +up a hub, or
+   in creating a channel for your mud. These undocumented +procedures require
+   expertise to accomplish that you have to earn on your own +by reading
+   the code on your mud and the relevant specs.
+
+9) You can file complaints to me by email, or by +explaining the problem
+   on the appropriate area on lpmuds.net. I prefer to
+   deal with complaints from the admin of the mud in +question, since the
+   responsibility for maintaining that intermud connection is +theirs. Please
+   note that I am not the arbiter of inter-mud disputes. If +someone is
+   being mean to you through tells or on unprotected +channels, you need to
+   find some way of dealing with it yourself. Also, if +someone logs onto your
+   mud and starts abusing channels you haven't secured, this +is not something
+   I'm in a position to control. Logging onto my mud and +complaining that
+   people on your mud are abusing channels is useless (yes, +this really has happened).
+
+10) I'm only human and sometimes I'll err in judgment. +If you think I have
+    made an error, please email me. Perhaps I banned +your mud out of
+    a misunderstanding. Perhaps the problem on your mud +has been fixed.
+    I try to be open minded about this stuff, if you try +to be reasonable.
+
+
+
+Clarifications and suggestions:
+
+- A channel may have customs more restrictive +than the rules here show.
+For example, because ds and dchat are turned on by default on
+Dead Souls muds, and I don't want newbies immediately scared away
+and/or offended, I ask that foul language be avoided when
+possible. On the other hand, a channel like intergossip has
+the tradition of being quite raunchy and not
+geared toward technical talk, so you might find a hostile reaction
+when asking for code help there. Use your common sense and try to
+follow the customs of a channel. Showing up and expecting a
+channel to accept your topic and discussion habits
+no matter what is not really a good idea.
+
+- On a related note, please remember that +this is not gjs, and
+the customs of gjs channels may not be acceptable here, even
+if the channel names are the same.
+
+- An email address in your startup packet is not +explicitly demanded,
+as you can see. However, it's *strongly* urged that you put a valid
+email address in there. This is because if someone on your mud is
+getting out of hand, or your connection is causing technical problems,
+I need a way to talk to someone in charge of things on your mud.
+
+- When someone on a mud is violating rules, they +usually get a
+number of warnings, and if they are not admins, their admins are
+also notified as possible. Whether warnings are issued is obviously
+dependent on the type of behavior. Sufficiently disruptive behavior
+(at my discretion) can subject a mud to immediate action without
+warning. But this is extremely rare. Warnings are provided
+when reasonable. If the behavior doesn't stop, then that mud may be
+banned from the channel where it's causing problems. If the mud
+then causes problems on other channels, it may be banned from
+the router entirely. This is a drastic and very unusual situation.
+
+- Sometimes a mud causes technical problems and +I can't get
+a hold of an admin. In the past, for example, some muds have
+accidentally messed up their intermud daemon, and wound up
+spamming the router with dozens of connection requests
+per second. Because they are not fully connected, they can't be
+contacted through channels, and because their admins weren't
+checking their email, I couldn't get them to stop. In a case
+like this, the mud generally will get firewalled out, so that
+the router stops receiving any data at all from that mud. If
+your mud just won't connect to the router no matter what,
+something like this may have happened. Email me and we'll
+straighten it out.
+
+
+- <my name here> @comcast.net
+
+
+ +
+
+
+ + diff --git a/lib/www/lpmuds/links.html b/lib/www/lpmuds/links.html new file mode 100644 index 0000000..e3bce1c --- /dev/null +++ b/lib/www/lpmuds/links.html @@ -0,0 +1,404 @@ + + + + + + + + + LPMuds.net - Links + + + + + + + + + + +
+ + + + + + + +
LPMuds.net +
+ + + + + + +
A +resource site for LPC, LPMuds, and related stuffs.
+
+ + + + + + + + + + + + + + + + +
  Index + Forum Site +FAQ LPMud +FAQ Intermud + Downloads +   Links   
+

+
+
LPMuds.net: MUD +(not necessarily LP) related forums
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Mudbytes
+
A swell discussion forum. +Largely centered around Diku/Smaug/etc.
+
The Mud Connector
+
The largest MUD community I'm +aware of. Messy on occasion, and contentious, but there is signal with +the noise.
+
Top Mud Sites
+
A sort of sister site to TMC, +but very aggressive on censoring.
+
Mudlab
+
A site dedicated strictly to +design and implementation discussion...no promotions allowed.
+
Electric Soup
+
MUSH discussion. Alien to me, +but they are members of the MUD family, like it or not.
+
LPUniversity
+
Recently revived site. +
+
Mud +Quest
+
Started as an alternative to Top +Mud Sites, focusing on free muds.
+
+
+
+
+
+
+
  +LPMuds.net: MUD related downloads
+
+
+ + + + + + + + + + + + + + + + + + + +
ftp.game.org
+
An extensive repository of much +MUD stuff.
+
LPMuds.net lib list
+
Fixed up, "easy-ish to install" +libs are here.
+
Lysator FTP
+
The ole grandpappy of LPMud +related downloads (not frequently updated)
+
Mudbytes repository
+
A growing archive managed by the +Mudbytes guys
+
+
+
+
+
+
+
+
  +LPMuds.net: Drivers
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MudOS
+
Old Reliable: the most popular +workhorse in the LPMud stable.
+
LDMud
+
Lars Duening's interpretation of +LPC.
+
CD
+
An early fork from original +LPMud, but info +on it is scarce. Run by Genesis +and Outerspace.
+
DGD
+
A clean-room implementation of +LPC which can be commercially licensed, but with a catch.
+
Pike +(aka LPC4)
+
Those who look into it tend to +fall deeply in love. Apparently, however, it requires some commitment +up-front.
+
Amylaar (aka LPMud 3.x)
+
Amylaar is just a name given to +the least old incarnation of the original LPMud driver.
+
Anarres
+
Written by a famously +detail-oriented programmer to be backward compatible (mostly) with +MudOS.
+
+
+
+
+
+
+
  +LPMuds.net: General resource and information sites
+
+
+ + + + + + + + + + + + + + + +
MUDs at The Living +Internet
+
The Living Internet is a sort of +repository of general internet information, and the MUD entry is +interesting.
+
MUDs at WikipediaWikipedia is basically the best +thing ever. This is their article on muds.
+
Archived +CIE Articles
+
Imaginary Realities used to have +some nifty content. It is dead now, but you can read some articles +still.
+
+
+
+
+
+
+
  +LPMuds.net: LP Muds of pedigree
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Genesis LPMud
+
The original LPMud, and still +the 800-pound gorilla.
+
BatMUDOne of the first, and still in +operation.
+
Darker Realms
+
Another of The Old Ones. A +sentimental favorite, as it is where I learned to code LPC.
+
Ancient Anguish
+
A venerable and still popular +LPMud. Friends tried to drag me over there but I was just too stuck on +DR!
+
Discworld
+
An insanely popular LPMud that's +been around for a good while.
+
Nanvaent
+
Somewhat less popular than the +other Old Ones, but still in operation and making mischief.
+
+
+
+
+
+
+ + + diff --git a/lib/www/lpmuds/lp_versus_diku.html b/lib/www/lpmuds/lp_versus_diku.html new file mode 100644 index 0000000..cc13cc9 --- /dev/null +++ b/lib/www/lpmuds/lp_versus_diku.html @@ -0,0 +1,55 @@ + + + + + LP v Diku + + + + +
LP versus Diku


This is an intermud conversation that pretty much explains my
opinion on the LP v Diku question. To read a related rant, click here.


[2006.06.20-10.21] Darque@Steamworks <dead_souls> There are a few general

questions I have about LPC in general and how DS applies to those notions.

[2006.06.20-10.21] Cratylus@Dead Souls <dead_souls> hopefully i'll have the
answers

[2006.06.20-10.21] Darque@Steamworks <dead_souls> I had always assumed that LPC
was very talkerish without typical MUD functions, I assume that I wrong in this
regard.

[2006.06.20-10.22] Daelas@Moraelinost <dead_souls> works :)

[2006.06.20-10.22] Darque@Steamworks <dead_souls> Is there a particular reason
that LPC has not been used as often to make typical MUDs as DIKU and it's
children?

<some stuff removed here>

[2006.06.20-10.28] Cratylus@Dead Souls <dead_souls> ok ya good question

[2006.06.20-10.28] Cratylus@Dead Souls <dead_souls> the problem is historical

[2006.06.20-10.28] Cratylus@Dead Souls <dead_souls> diku uses c

[2006.06.20-10.28] Cratylus@Dead Souls <dead_souls> meaning that pretty much
anything you code for diku mud A will work on diku mud B

[2006.06.20-10.29] Cratylus@Dead Souls <dead_souls> i presume there are exceptions,
but that's generally the case

[2006.06.20-10.29] Cratylus@Dead Souls <dead_souls> this has created a sort of
"snippet culture" in which there are hundreds, if not thousands, of code pieces
called snippets people can download

[2006.06.20-10.29] <dead_souls> Daelas@Moraelinost nods

[2006.06.20-10.30] Cratylus@Dead Souls <dead_souls> they can put these together,
download some pre-fabricated areas, and shazam, they have a mud
people can play on immediately

[2006.06.20-10.30] Cratylus@Dead Souls <dead_souls> because this is relatively
easy to do, there are many diku muds, many more than lpc. because with lpc, you
can't really do that

[2006.06.20-10.30] Cratylus@Dead Souls <dead_souls> each mud is usually
customized right from the start, so that code pieces from one dont work
on another

[2006.06.20-10.31] Cratylus@Dead Souls <dead_souls> add to this the lack of an
olc, and lpc's have dwindled over the years

[2006.06.20-10.31] Cratylus@Dead Souls <dead_souls> because you have to know
what you're doing, in order to make a mud that people will want to play on

[2006.06.20-10.32] Cratylus@Dead Souls <dead_souls> dead souls is supposed to
mitigate that a bit. it has an olc, and an upcomping "compatibility project"
will hopefully cut down on the code incompatibility problems

[2006.06.20-10.32] Cratylus@Dead Souls <dead_souls> the end

[2006.06.20-10.32] <dead_souls> Karri@Dionea applauds!

[2006.06.20-10.32] <dead_souls> Cratylus@Dead Souls bows.

[2006.06.20-10.32] <dead_souls> Daelas@Moraelinost agrees wholeheartedly.

<some stuff removed here>

[2006.06.20-10.35] Daelas@Moraelinost <dead_souls> I'd be lost trying to futz with C.

[2006.06.20-10.35] <dead_souls> Karri@Dionea nods.

[2006.06.20-10.35] Cratylus@Dead Souls <dead_souls> with lpc, doing substantial
modifications requires cubstantial LPC expertise, but it is much easier than C

[2006.06.20-10.36] Cratylus@Dead Souls <dead_souls> if you happen to be a whiz
at C, diku might be the right choice

[2006.06.20-10.36] Cratylus@Dead Souls <dead_souls> there are other advantages
that come with being a C only mud. evaluation speed chief among them

[2006.06.20-10.37] Cratylus@Dead Souls <dead_souls> if the mud doesn't have to
waste time interpreting code, and just runs the binary, you can do things
much more quickly

[2006.06.20-10.38] Cratylus@Dead Souls <dead_souls> the theoretical top limit
of number of simultaneous players, therefore, is higher for diku than lpc on
the same machine

[2006.06.20-10.38] Cratylus@Dead Souls <dead_souls> as an example

[2006.06.20-10.38] Cratylus@Dead Souls <dead_souls> but for the most part these
advantages are not of practical use

[2006.06.20-10.38] Cratylus@Dead Souls <dead_souls> since most muds do not have
hundreds of players, and LPC can easily handle 200 or more

[2006.06.20-10.39] Cratylus@Dead Souls <dead_souls> cf Discworld

[2006.06.20-10.39] <dead_souls> Karri@Dionea thinks C is easier in some ways.
With LPC, I have to figure out where all the files are and how they interact.
With a C program, you have a distinct beginning and end.

[2006.06.20-10.40] Cratylus@Dead Souls <dead_souls> there are definite pluses to
diku. i dont diss it as a codebase. if i seem to sneer at it, it's at the
snippet kiddies that pretend they "run a mud" when they really just run someone
elses code

[2006.06.20-10.40] Zeus@Empire of Rome <dead_souls> thats what I'm doing :P

[2006.06.20-10.41] Cratylus@Dead Souls <dead_souls> not really

[2006.06.20-10.41] Cratylus@Dead Souls <dead_souls> i mean yes i suppose in a way

[2006.06.20-10.41] Cratylus@Dead Souls <dead_souls> but i've visited your mud a bit

[2006.06.20-10.41] Cratylus@Dead Souls <dead_souls> it's clearly your own thing

[2006.06.20-10.41] Zeus@Empire of Rome <dead_souls> your code base though, without
that I couldn't do jack heh

[2006.06.20-10.41] Zeus@Empire of Rome <dead_souls> for which I am thankful

[2006.06.20-10.41] Zeus@Empire of Rome <dead_souls> QCS rocks heh

[2006.06.20-10.42] Cratylus@Dead Souls <dead_souls> it's just a tool.
that's my point. dead souls is a tool you can use, which is itself open
to modification. a lot of dikus are "black boxes" to their owners, who need
to beg for people who know C to come work for them so they can do things
+ +- +Cratylus
+
+<my name here>@comcast.net
+

+LPMuds
+
+
+ + diff --git a/lib/www/lpmuds/lpmud_faq.html b/lib/www/lpmuds/lpmud_faq.html new file mode 100644 index 0000000..f74adfe --- /dev/null +++ b/lib/www/lpmuds/lpmud_faq.html @@ -0,0 +1,138 @@ + + + + + + + + + LPMuds.net - LPMud FAQ + + + + + + + + + + +
+ + + + + + + +
LPMuds.net +
+ + + + + + +
A +resource site for LPC, LPMuds, and related stuffs.
+
+ + + + + + + + + + + + + + + + +
  Index + Forum Site +FAQ   LPMud +FAQ   Intermud + Downloads + Links + 
+

+
+
LPMuds.net: +Frequently Asked Questions
+
+
+ + + + + + +
This is +Descartes's LPMud FAQ from long ago. I am developing a replacement, but +until it is complete, this will have to do.
+
+
+
+
+
  +LPMuds.net - LPMud FAQ
+
+
+ + + +
+
From: George Reese <borg@imaginary.com>
Newsgroups: rec.games.mud.announce, rec.games.mud.lp
Subject: FAQ: [lpmud] rec.games.mud.lp and LPMuds
Reply-To: + + Lib List + + + + + + + +The content of this page has been moved to http://lpmuds.net/downloads.html
+
+You should be redirected there momentarily.
+
+
+ + diff --git a/lib/www/lpmuds/maintenance.html b/lib/www/lpmuds/maintenance.html new file mode 100644 index 0000000..91d74c7 --- /dev/null +++ b/lib/www/lpmuds/maintenance.html @@ -0,0 +1,16 @@ + + + + + LPMuds.net maintenance page + + +LPMuds.net is temporarily unavailable for scheduled maintenance.
+
+We should be back up within the hour. Please try again soon.
+
+-Crat
+
+ + diff --git a/lib/www/lpmuds/merentha-faq.html b/lib/www/lpmuds/merentha-faq.html new file mode 100644 index 0000000..8812c50 --- /dev/null +++ b/lib/www/lpmuds/merentha-faq.html @@ -0,0 +1,205 @@ + + + + + Dead Souls FAQ + + + + +
Merentha Bundle FAQ

Written by Cratylus @ Dead Souls, October 2006

What is the first thing I should know?

What is the second thing I should know?

Who is this for?

What is Merentha?

Aren't you the Dead Souls maintainer? What's your angle here?

Why were you working on Merentha?

Well, you wasted your time. It doesn't work.

It works, but the intermud system is weird and clunky.

Where can I get support for Merentha lib, then?

I work with Merentha lib all the time. It's not that hard to set up.

Where can I get it?

+What is the +first thing I should know?
+
+The Merentha Bundle is NOT DEAD SOULS. It is the Merentha mudlib,
+which is a completely different set of files than those distributed
+with Dead Souls. I, Cratylus, am not the author of Merentha, and
+you can consider this an official disclaim of any credit for its
+brilliance or blame for its pitfalls.
+
+What is the +second thing I should know?
+
+The authors and maintainers of the official Merentha mudlib
+do not take responsibility for this bundle. This is a strictly
+"third party" deal which they will not support in any way. You
+are free to download and use it, but you are not entitled to
+receive support from anyone. Note that I can't give you
+authorization to distribute it either, since I am not the
+copyright holder. If you want to mirror it, you'd be wise
+to ask the Merentha maintainer first, like I did.
+
+Who is this for?
+
+The Merentha bundle is absolutely not for newbie admins. This
+is not intended to be a "get started on your own mud the
+easy way!" sort of deal. I am making it available as a
+courtesy and favor to mudlib hobbyists who have an interest
+in tinkering with this lib. But if what you're looking for
+is a quick-start kit for your own mud, I strongly recommend
+you stop reading now and look elsewhere, because even though
+the Merentha Bundle makes installation easiER, it does not
+necessarily make it eaSY.
+
+What is +Merentha lib?
+
+It's a mudlib based on the Merentha Mud, which was
+originaly based on the Nightmare 3 mudlib.
+
+
+Aren't you the +Dead Souls maintainer? What's your angle here?
+
+I am indeed the maintainer of a different mudlib
+called Dead Souls (which I am not ashamed to plug
+here by pointing you to its Wikipedia +entry). However, I
+have a general affection for the LP mud codebase family.
+During some experimentation I found that I had a
+relatively easier way of installing Merentha that people
+could take advantage of, and it seemed like a nice thing
+to do, making it available generally.
+
+I'm not afraid that people will use Merentha instead of
+Dead Souls. For one thing, I think that "more LPmuds",
+regardless of the codebase, is a net plus for DS. And
+anyway, what kind of lib author would I be, if I was
+afraid to let people compare my work side by side with that
+of others? Let the chips fall where they may.
+
+
+Why were you +working on Merentha?
+
+During Dead Souls development I decided to take a serious look
+other libs after experiencing success experimenting with
+Discworld lib. I got a bit carried away, I'm afraid, and
+decided to see what else I could bundle.
+
+
+Well, you +wasted your time. It doesn't work.
+
+There is such a vast and bewildering array of operating
+system and development software and system hardware architecture
+combinations out there that there is simply no way for
+me to guarantee that the bundle will work for everyone...
+or indeed for most.
+
+I can assure you that the bundle puts you much much closer
+to a successful Merentha start than you'd be without it. If it
+still doesn't work out of the box, please note:
+
+* I haven't tested this on Cygwin or any other Windows emulation
+or native windows compilation suite. For all I know it is not
+possible to get it to work on Windows.
+
+* Do NOT under ANY CIRCUMSTANCES attempt to contact Merentha
+mud personnel or Merentha mudlib maintainers to complain that
+this bundle is lame or to ask for help with it. It'll be like
+asking Bill Joy to come over and help you install Solaris. His
+involvement with the development of UNIX doesn't entitle you to
+help from him, and the Merentha people don't deserve to be
+exposed to noob brainwaves from people who think they are owed +assistance.
+
+* Perhaps the most important thing you can read is this:
+http://www.catb.org/%7Eesr/faqs/smart-questions.html
+Note that the people on that page also are not to be contacted for +support.
+
+
+It works, but +the intermud system is weird and clunky.
+
+Don't blame Merentha for that. Merentha doesn't normally
+come with an Intermud-3 subsystem, so as part of my
+bundling I decided to graft one on, so that new adopters
+could conveniently ask for help once they were online.
+
+I very crudely lifted some of the public domain Dead Souls
+i3 code and bolted it onto Merentha. It sort of mostly
+works, and you can use the following channels:
+
+dead_test4
+dchat
+imud_code
+
+Note that you'll need to either relogin your new admin
+character, or reboot the mud, to have channel access. Once
+you do, test it by typing:
+
+dead_test4 test
+
+I wouldn't be surprised to discover it works poorly or
+insecurely. It's just an ad hoc stopgap. If you don't like
+it, yank it, and/or write yer own.
+
+
+Where can I get +support for Merentha lib, then?
+
+Once it is installed, it might not be unreasonable to
+ask for advice on the imud_code line.
+
+You're also welcome to visit the LPMuds.net +discussion forum
+and chat there, but don't expect quick turnaround on your
+questions. Merentha lib experts are fewer and farther between
+than they once were, so you may have to wait a little
+for a helpful response.
+
+
+I work with Merentha lib all the time. It's not that +hard to +set up.
+
+That's true. The small driver and lib tweaks necessary to
+get Merentha compiled and run on a modern system aren't
+that big a deal, but it seemed like a nice thing to do anyway.
+
+Many people will still run into problems, I'm sure, but
+even for those, this should get them closer to the ballpark.
+
+
+Where can I get it?
+
+http://lpmuds.net/files/
+
+
+LPMuds.net
+
+
+ + diff --git a/lib/www/lpmuds/mudfarm.html b/lib/www/lpmuds/mudfarm.html new file mode 100644 index 0000000..a19a88b --- /dev/null +++ b/lib/www/lpmuds/mudfarm.html @@ -0,0 +1,269 @@ + + + + + + + + + LPMuds.net - Index + + + + + + + + + + +
+ + + + + + + +
LPMuds.net +
+ + + + + + +
A +resource site for LPC, LPMuds, and related stuffs.
+
+ + + + + + + + + + + + + + + + +
   Index   Forum Site +FAQ LPMud +FAQ Intermud + Downloads + Links +  
+

+
+
The LPMuds.net +Mud Farm
+
+
+ + + + + + +
This page sends you to the +connection pages for several LP mudlibs that have been set up for +public view. For now they
+are just stock libs and logins +are player only, but they will eventually all be set to auto-wiz so +that folks can inspect the code
+as well.
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Dead Souls 2
+
The most full-featured, newcomer +friendly LP mudlib today.
+
Lima
+
Developed by the MudOS team. +Advanced but not very friendly to LP newcomers.
+
TMI-2
+
A beloved old lib that's showing +its age but still holds a warm place in the hearts of oldsters.
+
Skylib
+
A Discworld derivative that is +somewhat easier to use and learn than the DW distlib.
+
Merentha
+
Cleaned up derivative of +Nightmare 3.
+
Discworld
+
The distribution lib for one of +the most popular LP muds.
+
Final Realms
+
A quirky Discworld derivative +with lots of examples.
+
LPUniversity
+
A basic lib developed by folks +interested in simplicity and modularity.
+
Dead Souls 1
+
It's spunky and got character, +but this Nightmare V derivative is very outdated compared to Dead Souls +2.
+
Nightmare IV
+
Almost identical to Dead Souls +1, difference being mainly documentation and licensing.
+
Nightmare 3
+
Nightmare 3 is to Nightmare IV +as Windows 3.11 is to Windows 95. It is fondly loved/hated.
+
Lil
+
So barebones there arent even +permissions controls. Will probably have been wrecked by someone
+by the time you log in. Only for hard core, advanced LP folks.
+
Foundation I
+
Extremely stripped version of +Nightmare 3. So bare it lacks a security system.
+
Foundation II
+
A stripped down version of +Nightmare IV.
+
Phantasmal
+
The most complete and easiest to +install lib publicly available for the DGD driver.
+
+
+
+
+
+
+
+
+
+ + + diff --git a/lib/www/lpmuds/parch.jpg b/lib/www/lpmuds/parch.jpg new file mode 100644 index 0000000..e502dce Binary files /dev/null and b/lib/www/lpmuds/parch.jpg differ diff --git a/lib/www/lpmuds/print.css b/lib/www/lpmuds/print.css new file mode 100644 index 0000000..d281106 --- /dev/null +++ b/lib/www/lpmuds/print.css @@ -0,0 +1,9 @@ +#headerarea +{ + display: none; +} + +.tborder +{ + border: none; +} \ No newline at end of file diff --git a/lib/www/lpmuds/router_debate.html b/lib/www/lpmuds/router_debate.html new file mode 100644 index 0000000..5bf19ad --- /dev/null +++ b/lib/www/lpmuds/router_debate.html @@ -0,0 +1,1123 @@ + + + + + router_debate + + +This is a debate that occurred on Arren's +new router. Arren wanted to take over primary router
+adminship. I thought she'd agreed to +be an alternate router. This conflict played out as follows:
+
+

+

+[2007.02.16-19.56] Arren@Anarres II <imud_gossip> Right now, it +seems that a corollary of your intention is to have someone put a lot +of work into something which simply competes with you. I've made it +clear that I do not want to compete with you.

+[2007.02.16-19.57] Cratylus +<intergossip> mmmmmmmmmmmmmmmmmm
+[2007.02.16-19.57] Cratylus +<intergossip> what would i gain from that?
+[2007.02.16-19.57] Cratylus +<intergossip> oh i ge tit
+[2007.02.16-19.57] Cratylus +<intergossip> you fail i laugh
+[2007.02.16-19.58] Cratylus +<intergossip> dunno how i would convince you that's not in my +interest
+[2007.02.16-19.59] Cratylus +<intergossip> only thing i can do is point to my history of not +being that kind of guy
+[2007.02.16-19.59] Mouse@Broken Empire <imud_gossip> What kind of +guy have you been, exactly?
+[2007.02.16-20.00] Cratylus +<intergossip> definitely an excellent driver
+[2007.02.16-20.00] <imud_gossip> Mouse@Broken Empire snickers.
+[2007.02.16-20.00] Cratylus +<intergossip> lookit, before i was router admin i was a regular +ball breaking wise ass like everyone else on gjs
+[2007.02.16-20.01] Cratylus +<intergossip> i set up yatmim and it had a purpose and i +protected it
+[2007.02.16-20.01] Cratylus +<intergossip> i dunno how that made me look like a bad guy
+[2007.02.16-20.01] Mouse@Broken Empire <imud_gossip> Should have +removed intergossip by default in your noob muds.
+[2007.02.16-20.01] Cratylus +<intergossip> but i guess it did
+[2007.02.16-20.01] Cratylus +<intergossip> throughout, whether on gjs or yatmim, i have not +been intentionally malicious
+[2007.02.16-20.02] Cratylus +<intergossip> no doubt i crossed a boundary here or there, but +intentional hurtfulness is not my thing
+[2007.02.16-20.02] Arren@Anarres +II <imud_gossip> I don't think you're always aware of when you're +being malicious.
+[2007.02.16-20.02] Cratylus +<intergossip> even when duuk asked for unix help
+[2007.02.16-20.02] Cratylus +<intergossip> all i did was provide specific helpful information
+[2007.02.16-20.02] Cratylus +<intergossip> so, what kind of guy?
+[2007.02.16-20.02] Cratylus +<intergossip> pretty nice guy
+[2007.02.16-20.03] Cratylus +<intergossip> but somehow being router admin has made me seem +like an evil overfiend, and since i'm just me, i have no idea how to +combat that
+[2007.02.16-20.04] Arren@Anarres +II <imud_gossip> My serious best suggestion is to turn off +igossip by default on DS (I can't actually work out how to turn it on), +and abdicate. If you don't want to do that, I don't mind, and I will +gladly leave you with status quo.
+[2007.02.16-20.05] Cratylus +<intergossip> how about this
+[2007.02.16-20.05] Cratylus +<intergossip> i block intergossip completely on yatmim
+[2007.02.16-20.05] Cratylus +<intergossip> all yatmim traffic has to come here
+[2007.02.16-20.05] Cratylus +<intergossip> all INTERGOSSIP
+[2007.02.16-20.06] Cratylus +<intergossip> all intergossip traffic has to come here
+[2007.02.16-20.06] Mouse@Broken Empire <imud_gossip> Talk about +over reaction.
+[2007.02.16-20.06] Cratylus +<intergossip> i'm not acting
+[2007.02.16-20.06] Cratylus +<intergossip> i'm asking
+[2007.02.16-20.06] Mouse@Broken Empire <imud_gossip> That's why +we think you're an asshole.
+[2007.02.16-20.06] Cratylus +<intergossip> i'm suggesting
+[2007.02.16-20.06] Cratylus +<intergossip> this is a *sugestion* not a confrontation
+[2007.02.16-20.06] Mouse@Broken Empire <imud_gossip> Because when +we offer a solution that would make everyone happy, you threaten to +take your toys and go home.
+[2007.02.16-20.06] Cratylus +<intergossip> some people are able to think in terms other than +"fuck you"
+[2007.02.16-20.06] Arren@Anarres +II <imud_gossip> I don't think that's the best way to achieve an +objective. It's obstructive and malicious, and will do you far fewer +favours than any other suggestion.
+[2007.02.16-20.07] Cratylus +<intergossip> mmm
+[2007.02.16-20.07] Cratylus +<intergossip> let's suppose there's something worng with me
+[2007.02.16-20.08] Cratylus +<intergossip> assume i have a mental defect
+[2007.02.16-20.08] Arren@Anarres +II <imud_gossip> Blocking igossip on yatmim would certainly have +the effect you intend, but you'd piss off more people, and I don't want +you to do that.
+[2007.02.16-20.08] Cratylus +<intergossip> and this defect prevents me from allowing +hate-speech to happen on common channels on a router i run
+[2007.02.16-20.08] Cratylus +<intergossip> like, this defect makes me feel physically ill to +imagine people associate me with that sort of thing
+[2007.02.16-20.09] Tatianna@Anarres II <imud_gossip> hmm
+[2007.02.16-20.09] Cratylus +<intergossip> so that whether ds muds per se are connected to it +is not so much the point
+[2007.02.16-20.09] Cratylus +<intergossip> but that it happens on my watch in my house, is
+[2007.02.16-20.09] Cratylus +<intergossip> again
+[2007.02.16-20.09] Cratylus +<intergossip> defect
+[2007.02.16-20.09] Arren@Anarres +II <imud_gossip> That's not a defect, it's a fair reaction. It +makes you perhaps distant from the norm, but it's not a defect. +However, this distance from the norm might make you a bad politician or +ambassador.
+[2007.02.16-20.09] Cratylus +<intergossip> this is a thought exercise
+[2007.02.16-20.09] Mouse@Broken Empire <imud_gossip> So make +intergossip a "non public" channel
+[2007.02.16-20.10] Cratylus +<intergossip> that's what i'm proposing
+[2007.02.16-20.10] Cratylus +<intergossip> making ig on yatmim non public
+[2007.02.16-20.10] Mouse@Broken Empire <imud_gossip> All you need +to do is remove the words "intergossip" from dead souls mudlib
+[2007.02.16-20.10] Cratylus +<intergossip> so that joe schmoe will come here instead
+[2007.02.16-20.10] Arren@Anarres +II <imud_gossip> Mouse, the question is, can one plan an orderly +reorganisation without Cratylus pissing off any more people.
+[2007.02.16-20.10] Mouse@Broken Empire <imud_gossip> No, you're +not understanding.
+[2007.02.16-20.10] Mouse@Broken Empire <imud_gossip> Just remove +intergossip from the DS lib.
+[2007.02.16-20.10] Mouse@Broken Empire <imud_gossip> Not from the +router.
+[2007.02.16-20.10] Cratylus +<intergossip> you have not been listening mouse
+[2007.02.16-20.11] Mouse@Broken Empire <imud_gossip> So your +noobs won't ever know it exists.
+[2007.02.16-20.11] Arren@Anarres +II <imud_gossip> Mouse, I think we're currently not in the realm +of that solution.
+[2007.02.16-20.11] Mouse@Broken Empire <imud_gossip> Then a +better solution would be for yatmim to cease function and pass +everything to adsr
+[2007.02.16-20.12] Cratylus +<intergossip> i think an orderly migration can be done
+[2007.02.16-20.12] Mouse@Broken Empire <imud_gossip> the +community isn't broken up and Crat doesn't have to be associated with +anything he's unhappy about.
+[2007.02.16-20.12] Cratylus +<intergossip> so long as theres no big rush
+[2007.02.16-20.12] Cratylus +<intergossip> whether people are mad at me is kind of irrelevant +to me
+[2007.02.16-20.12] Cratylus +<intergossip> at this point it's the default
+[2007.02.16-20.12] Cratylus +<intergossip> so it's not worth trying to avoid
+[2007.02.16-20.13] Mouse@Broken Empire <imud_gossip> You say +that, but then you whine about what people will think about you due to +IG
+[2007.02.16-20.13] Arren@Anarres +II <imud_gossip> It matters to me, and it's also fixable. I'd +like to achieve both.
+[2007.02.16-20.13] Cratylus +<intergossip> fine by me, either way
+[2007.02.16-20.14] Arren@Anarres +II <imud_gossip> Cratylus, it honestly sounds like the best +solution to me. It removes you from the site of the problem. People +have very short memories.
+[2007.02.16-20.14] Arren@Anarres +II <imud_gossip> And it avoids fragmenting the network, something +I am very keen to avoid.
+[2007.02.16-20.15] Mouse@Broken Empire <imud_gossip> Also, and +don't take this the wrong way...
+[2007.02.16-20.15] Mouse@Broken Empire <imud_gossip> Arren is +probably better at network socket code.
+[2007.02.16-20.15] Cratylus +<intergossip> heh
+[2007.02.16-20.15] Cratylus +<intergossip> ok
+[2007.02.16-20.15] Cratylus +<intergossip> so the idea then is
+[2007.02.16-20.15] Cratylus +<intergossip> intergossip moves to arrenrouter
+[2007.02.16-20.15] Mouse@Broken Empire <imud_gossip> Arren I'm +sure won't actually care about the DS/Dchat lines
+[2007.02.16-20.16] Mouse@Broken Empire <imud_gossip> Um, no.
+[2007.02.16-20.16] Mouse@Broken Empire <imud_gossip> yatmim +closes.
+[2007.02.16-20.16] Mouse@Broken Empire <imud_gossip> adsr handles +everything.
+[2007.02.16-20.16] Cratylus +<intergossip> and ds by default goes on yatmim
+[2007.02.16-20.16] Mouse@Broken Empire <imud_gossip> Including +your precious dead souls
+[2007.02.16-20.16] Cratylus +<intergossip> mouse you're just not being helpful
+[2007.02.16-20.16] Mouse@Broken Empire <imud_gossip> Which will +help everyone, and you get the benefits of the better maintained router
+[2007.02.16-20.16] Arren@Anarres +II <imud_gossip> Mouse is just disagreeing with you. That's not +the same as "unhelpful".
+[2007.02.16-20.17] Cratylus +<intergossip> heh
+[2007.02.16-20.17] Mouse@Broken Empire <imud_gossip> In +Crat-world it is.
+[2007.02.16-20.17] Mouse@Broken Empire <imud_gossip> Crat, listen.
+[2007.02.16-20.17] Mouse@Broken Empire <imud_gossip> Arren is +better at network code.
+[2007.02.16-20.17] Mouse@Broken Empire <imud_gossip> So you +benefit.
+[2007.02.16-20.17] Mouse@Broken Empire <imud_gossip> You don't +have to seem like an asshat anymore.
+[2007.02.16-20.17] Mouse@Broken Empire <imud_gossip> So you +benefit
+[2007.02.16-20.17] Arren@Anarres +II <imud_gossip> Perhaps we can run this in reverse. What +assertions or references from me would you accept in order to keep I3 +non-fragmented?
+[2007.02.16-20.17] Mouse@Broken Empire <imud_gossip> Dead Souls +still gets its nice, quiet place to hang out
+[2007.02.16-20.18] Tatianna@Anarres II <imud_gossip> and we cvan +all get back the hatred filled crat we knew and loved from gks
+[2007.02.16-20.18] Cratylus +<intergossip> i understand what you are talking about. what i am +telling you is that in my entire experience on line, relying on anyone +else for anything is stupid
+[2007.02.16-20.18] Cratylus +<intergossip> i case about ds
+[2007.02.16-20.18] Cratylus +<intergossip> care
+[2007.02.16-20.18] Cratylus +<intergossip> i have to trust arren to let her do what you say
+[2007.02.16-20.18] Cratylus +<intergossip> this is the first time we ever talk about such a +thing
+[2007.02.16-20.18] Mouse@Broken Empire <imud_gossip> We relied on +Zakk for i3 for 12 years.
+[2007.02.16-20.19] Mouse@Broken Empire <imud_gossip> It worked +out ok.
+[2007.02.16-20.19] Mouse@Broken Empire <imud_gossip> Technically +we relied on Rust.  But he was imaginary.
+[2007.02.16-20.19] Cratylus +<intergossip> mouse, then go back to gjs
+[2007.02.16-20.19] Mouse@Broken Empire <imud_gossip> Now who's +being unhelpful.
+[2007.02.16-20.19] Cratylus +<intergossip> i think it's a valid point
+[2007.02.16-20.19] Arren@Anarres +II <imud_gossip> Cratylus, I have a professionally maintained +server farm with hands and eyes. I have QoS and routing guarantees. I +have nearly 20 years' unix experience and 15 years experience as a +Linux administrator. I run a number of high profile networks and +services for organisations of which you have heard and of which you may +even be a member.
+[2007.02.16-20.20] Arren@Anarres +II <imud_gossip> I can provide references, probably from people +you know; if not, at least from people you have heard of and respect.
+[2007.02.16-20.20] Cratylus +<intergossip> i believe you. i look forward to working with you +as a partner in a nified i3 network
+[2007.02.16-20.20] Mouse@Broken Empire <imud_gossip> Here's the +problem.
+[2007.02.16-20.20] Mouse@Broken Empire <imud_gossip> i3 isn't +exactly high tech.
+[2007.02.16-20.20] Cratylus +<intergossip> if it doesnt work outm then i will carry on on my +own as i have before
+[2007.02.16-20.20] Mouse@Broken Empire <imud_gossip> And I'd +think anyone that spent more than a pittance of time making it so would +be an idiot.
+[2007.02.16-20.21] Mouse@Broken Empire <imud_gossip> Arren is +offering to make a stable network code that is pretty easy to run with +minimal effort
+[2007.02.16-20.21] Cratylus +<intergossip> is that what she said?
+[2007.02.16-20.21] Arren@Anarres +II <imud_gossip> I'm not trying to touch the dead souls project. +I think you do good work there. I think you do less good work with I3, +and I think I3 should not be a fragmented network.
+[2007.02.16-20.21] Mouse@Broken Empire <imud_gossip> You'll +ALWAYS have the ability to update your network page and switch back to +yatmim if you want.
+[2007.02.16-20.21] Cratylus +<intergossip> ok hang on
+[2007.02.16-20.22] Cratylus +<intergossip> do you understand that i've worked essentially a +part time job on ds for the past 2 years?
+[2007.02.16-20.22] Mouse@Broken Empire <imud_gossip> And no one +will change that
+[2007.02.16-20.22] Cratylus +<intergossip> this is not a 5 minutes once a week thing
+[2007.02.16-20.22] Arren@Anarres +II <imud_gossip> I do. Nobody wants to take that away from you. +Least of all me, I couldn't do what you do.
+[2007.02.16-20.22] Mouse@Broken Empire <imud_gossip> Arren is +just offering to host the i3 network and remove that from your list of +problems.
+[2007.02.16-20.22] Cratylus +<intergossip> my fucking blood, thin as it may be, is in it
+[2007.02.16-20.22] Mouse@Broken Empire <imud_gossip> Dead Souls +will stay as you
+[2007.02.16-20.23] Cratylus +<intergossip> and i hav eonly just started talking to arren about +a partnership of *any* kind
+[2007.02.16-20.23] Cratylus +<intergossip> and any time i trusted someone else to do anything +i counted on i have had my ass invaded
+[2007.02.16-20.23] Mouse@Broken Empire <imud_gossip> Which speaks +more to your insecurity than anything else.
+[2007.02.16-20.24] Cratylus +<intergossip> so you can understand, i hope, why i'm not handing +over every last scintilla to arren in this first conversation
+[2007.02.16-20.24] Mouse@Broken Empire <imud_gossip> I honestly +wonder if english is your primary language sometimes.
+[2007.02.16-20.25] Mouse@Broken Empire <imud_gossip> DS = Crat
+[2007.02.16-20.25] Mouse@Broken Empire <imud_gossip> I3 = Arren
+[2007.02.16-20.25] Mouse@Broken Empire <imud_gossip> Everyone == +Happy.
+[2007.02.16-20.25] Arren@Anarres +II <imud_gossip> Cratylus, I have offered you references and +history. I am not asking for DS, nor to change what you're doing to it. +I'm actually offering to help you with the DS project, but I'm also +trying to give I3 a stable and unfragmented basis.
+[2007.02.16-20.26] Cratylus +<intergossip> ok
+[2007.02.16-20.26] Cratylus +<intergossip> i'm with you on that, which is why i keep harping +on thtis inter router thing
+[2007.02.16-20.26] Cratylus +<intergossip> i know nobody is grubbing at ds
+[2007.02.16-20.26] Mouse@Broken Empire <imud_gossip> Here's my +problem with "interrouter"
+[2007.02.16-20.26] Arren@Anarres +II <imud_gossip> Mouse, I can do inter-router. Relax.
+[2007.02.16-20.26] Mouse@Broken Empire <imud_gossip> I'm not +gonna update my i3 daemon because well, i3 isn't that important.
+[2007.02.16-20.27] Arren@Anarres +II <imud_gossip> But I can't do it immediately. I work 14 hour +days. I'm 3 days off inter-router.
+[2007.02.16-20.27] Cratylus +<intergossip> i dont think there's a big hurry, is there?
+[2007.02.16-20.27] Cratylus +<intergossip> we'll get there
+[2007.02.16-20.27] Cratylus +<intergossip> we dont have to walk from this conversation with +everything fixed
+[2007.02.16-20.30] Arren@Anarres +II <imud_gossip> Cratylus, what would assure you that I could run +I3 in such a way as to satisfy you?
+[2007.02.16-20.30] Cratylus +<intergossip> mmmmm
+[2007.02.16-20.30] Cratylus +<intergossip> well
+[2007.02.16-20.30] Cratylus +<intergossip> i know you're well capable of it
+[2007.02.16-20.30] Cratylus +<intergossip> that's not in question
+[2007.02.16-20.30] Cratylus +<intergossip> i've just never relied on you for anything
+[2007.02.16-20.30] Cratylus +<intergossip> and that is hard to get over
+[2007.02.16-20.31] Cratylus +<intergossip> which is why
+[2007.02.16-20.31] Cratylus +<intergossip> i figure
+[2007.02.16-20.31] Cratylus +<intergossip> if you run ig and and are invested in it
+[2007.02.16-20.31] Arren@Anarres +II <imud_gossip> Until you do, you never will have. But many +others have, and this is why I provide references. I'm flattered that +you don't question my ability, even before really interacting with any +of my work.
+[2007.02.16-20.32] Cratylus +<intergossip> no fense, but it isn't rocket science, and you seem +quite capable code wise, so it just makes sense
+[2007.02.16-20.32] Cratylus +<intergossip> what i'm not understanding is
+[2007.02.16-20.32] Cratylus +<intergossip> what is so objectionable about having intergossip +move to asdf
+[2007.02.16-20.32] Cratylus +<intergossip> while ds muds stay on yatmim
+[2007.02.16-20.33] Cratylus +<intergossip> not trying to be argumentative
+[2007.02.16-20.33] Cratylus +<intergossip> just not quite gettin git
+[2007.02.16-20.33] Mouse@Broken Empire <imud_gossip> because +then, in effect, there becomes 2 i3 networks
+[2007.02.16-20.33] Mouse@Broken Empire <imud_gossip> and +splitting the crowd is bad
+[2007.02.16-20.33] Cratylus +<intergossip> until the Grand Unification
+[2007.02.16-20.33] Mouse@Broken Empire <imud_gossip> which will +never happen
+[2007.02.16-20.34] Mouse@Broken Empire <imud_gossip> Trust Uncle +Duukie
+[2007.02.16-20.34] Arren@Anarres +II <imud_gossip> It fragments the network. It means that neither +router is likely to maintain critical mass for a community, and the way +I3 has been hemorrhaging MUDs recently, that's a serious problem.
+[2007.02.16-20.34] Mouse@Broken Empire <imud_gossip> it'll always +get pushed off one more month
+[2007.02.16-20.34] Arren@Anarres +II <imud_gossip> I have two objectives: First, build a community. +Second, keep that community happy. Nonfragmentation is required.
+[2007.02.16-20.35] Arren@Anarres +II <imud_gossip> I've done this before, it's what I do for a job. +It's what I do for a hobby.
+[2007.02.16-20.38] Cratylus +<intergossip> i'm only human. i need time to digest new ideas +that involve changing the way i look at things.
+[2007.02.16-20.39] Cratylus +<intergossip> i will think about what you've said
+[2007.02.16-20.39] Cratylus +<intergossip> by the same token
+[2007.02.16-20.39] Cratylus +<intergossip> i believe my proposition is a reasonable one
+[2007.02.16-20.39] Cratylus +<intergossip> and i hope you do the same
+[2007.02.16-20.40] Reflection@My Nuts In Your Mouth! +<imud_gossip> Test
+[2007.02.16-20.40] Cratylus +<intergossip> howdy
+[2007.02.16-20.41] Reflection@My Nuts In Your Mouth! +<imud_gossip> wich router am I connected to correctly? =)
+[2007.02.16-20.41] Cratylus +<intergossip> arren
+[2007.02.16-20.41] Reflection@My Nuts In Your Mouth! +<imud_gossip> ok =) well, works.  very nice
+[2007.02.16-20.41] Arren@Anarres +II <imud_gossip> I have argued against your proposal. I build +communities. I do not break them. I will not break this one.
+[2007.02.16-20.42] Reflection@My Nuts In Your Mouth! +<imud_gossip> for some reason I couldn't get the sorrows to send +it's startup request correctly, tho it worked fine with gjs
+[2007.02.16-20.44] Reflection@My Nuts In Your Mouth! +<imud_gossip> so whats the argument, to attempt to keep both +routers in play instead of individual groups moving to one or the other?
+[2007.02.16-20.44] Arren@Anarres +II <imud_gossip> I'm trying to help you not to break it either, +and to convince you that other than the personal hurdle, you have +nothing to lose by passing I3 to adsr.
+[2007.02.16-20.45] Reflection@My Nuts In Your Mouth! +<imud_gossip> ahhh. nm.  makes sense now
+[2007.02.16-20.45] Arren@Anarres +II <imud_gossip> You tell me what you want for DS muds, I will +provide it.
+[2007.02.16-20.46] Arren@Anarres +II <imud_gossip> All that remains is the personal hurdle, and +still you lose nothing. DS is a good project.
+[2007.02.16-20.46] Reflection@My Nuts In Your Mouth! +<imud_gossip> back shortly, forgot I named thism ud so horribly +for fun awhile ago
+[2007.02.16-20.46] Cratylus +<intergossip> listen
+[2007.02.16-20.47] Cratylus +<intergossip> my promise to you was adding this router to the +intermud page i run. we went from that to me making everyone move to +your new router
+[2007.02.16-20.47] Cratylus +<intergossip> let's let it cool for a bit while i think about it
+[2007.02.16-20.48] Arren@Anarres +II <imud_gossip> Please don't leave it too long, otherwise the +time will break the community anyway.
+[2007.02.16-20.48] Arren@Anarres +II <imud_gossip> The current situation is the one I'm trying to +avoid.
+[2007.02.16-20.49] Cratylus +<intergossip> it's held for half a year. waht's the rush?
+[2007.02.16-20.49] Arren@Anarres +II <imud_gossip> The current situation is two independent routers.
+[2007.02.16-20.49] Mouse@Broken Empire <imud_gossip> To be +frank...
+[2007.02.16-20.49] Mouse@Broken Empire <imud_gossip> the rush is +that you've become quite an issue of late
+[2007.02.16-20.49] Mouse@Broken Empire <imud_gossip> You're ok +when you're sober.
+[2007.02.16-20.50] Mouse@Broken Empire <imud_gossip> but when +you're drunk you tend to cause many muds to consider permanently +leaving the network.
+[2007.02.16-20.50] Cratylus +<intergossip> mouse i think you should speak for yourself
+[2007.02.16-20.51] Cratylus +<intergossip> if anything your argument favors multiple networks
+[2007.02.16-20.51] Mouse@Broken Empire <imud_gossip> I think you +should understand that we like you.
+[2007.02.16-20.51] Cratylus +<intergossip> let the chicps fall where they may
+[2007.02.16-20.51] Mouse@Broken Empire <imud_gossip> But we hate +the fact that you become "OMG ITS MINE" when you drink.
+[2007.02.16-20.52] Cratylus +<intergossip> have you noticed that it's when people pick on me +that i become combtive
+[2007.02.16-20.52] Cratylus +<intergossip> or when people break rules that i enforce them?
+[2007.02.16-20.52] Cratylus +<intergossip> maybe it's you that needs to work things out
+[2007.02.16-20.54] Arren@Anarres +II <imud_gossip> This is off the point. The point is to establish +a sane and consensual basis for I3 which does not fragment the network.
+[2007.02.16-20.54] Cratylus +<intergossip> i though mouse was just being helpful
+[2007.02.16-20.54] Cratylus +<intergossip> arren i agree with you
+[2007.02.16-20.54] Cratylus +<intergossip> that's something we've agreed on from the start
+[2007.02.16-20.55] Cratylus +<intergossip> you appear to want an immedate answer to a request +to change the way i look at things right this minute
+[2007.02.16-20.55] Cratylus +<intergossip> i'm sorry but i am not yet godhead
+[2007.02.16-20.55] Cratylus +<intergossip> i'm going to need to think about it
+[2007.02.16-20.56] Mouse@Broken Empire <imud_gossip> Well then
+[2007.02.16-20.56] Arren@Anarres +II <imud_gossip> Remember that nothing is being taken from you. +This is just an experienced network administrator offering to +administrate a network service.
+[2007.02.16-20.56] Mouse@Broken Empire <imud_gossip> Please list +Arren's router as an alternate on your precious website.
+[2007.02.16-20.56] Mouse@Broken Empire <imud_gossip> While you +think.
+[2007.02.16-20.56] Cratylus +<intergossip> that was my question actually
+[2007.02.16-20.56] Cratylus +<intergossip> when this thing started it wasnt all that clear i +should do that
+[2007.02.16-20.57] Cratylus +<intergossip> and so i asked the question as to whether i should +list it
+[2007.02.16-20.57] Cratylus +<intergossip> should i do so?
+[2007.02.16-20.57] Mouse@Broken Empire <imud_gossip> I would, yes.
+[2007.02.16-20.57] Mouse@Broken Empire <imud_gossip> Until this +all gets sorted out.
+[2007.02.16-20.57] Cratylus +<intergossip> yeah i caught that
+[2007.02.16-20.58] Arren@Anarres +II <imud_gossip> What is your plan for the future? To persist in +splitting the network? To delay making a decision on the issue? To +resign to a situation de-facto?
+[2007.02.16-20.59] Mouse@Broken Empire <imud_gossip> Obviously i3 +is going to split into 2 factions.
+[2007.02.16-21.00] Reflection@Mirror Ring <imud_gossip> it's not +the first time
+[2007.02.16-21.00] Cratylus +<intergossip> i'm happy either way, though unification is my +preference. i've said it before. i dunno how many times i must repeat +it to arren's satisfaction
+[2007.02.16-21.00] Cratylus +<intergossip> i'm starting to feel like i'm not being listened to
+[2007.02.16-21.00] Arren@Anarres +II <imud_gossip> Well, I would love for a single router to come +under the banner, diplomacy and publicity of the DS project.
+[2007.02.16-21.00] Tatianna@Anarres II <imud_gossip> thats cause +you or sort of contradicting yourself
+[2007.02.16-21.01] Tatianna@Anarres II <imud_gossip> are*
+[2007.02.16-21.01] Cratylus +<intergossip> i like vanilla and ilike pistachio, but i prefer +pistachio
+[2007.02.16-21.01] Cratylus +<intergossip> either way, ice cream
+[2007.02.16-21.01] Cratylus +<intergossip> perhaps those are terms you can understand, tats
+[2007.02.16-21.01] Arren@Anarres +II <imud_gossip> There are more ice cream consumers than there +are MUDs, therefore the manufacturers can afford to make two flavours.
+[2007.02.16-21.01] Arren@Anarres +II <imud_gossip> We do not have that luxury.
+[2007.02.16-21.01] Arren@Anarres +II <imud_gossip> We are down to 21 active MUDs from 90, and we +have lost entire sub-communities.
+[2007.02.16-21.02] Reflection@Mirror Ring <imud_gossip> I'll be +happy with coffeepot back online and in reach, it's the best channel on +any router!
+[2007.02.16-21.02] Cratylus +<intergossip> do you think that saying the same things over and +over will make me answer you to your satisfaction?
+[2007.02.16-21.03] Arren@Anarres +II <imud_gossip> CP is down because of Earth, but I can put +Amethyst on bofh, Amethyst is much more powerful than CP.
+[2007.02.16-21.03] Cratylus +<intergossip> i dunno what cp is
+[2007.02.16-21.03] Cratylus +<intergossip> a channel i suppose
+[2007.02.16-21.03] Arren@Anarres +II <imud_gossip> An AI.
+[2007.02.16-21.03] Reflection@Mirror Ring <imud_gossip> on a +serious note, there are many muds that do not even know about the new +router/routers, wouldn't a campaigne for awareness be a good start... +once you've decided on whose running what I mean
+[2007.02.16-21.03] +<imud_gossip> Arren@Anarres II nods.
+[2007.02.16-21.04] Cratylus +<intergossip> i think this raises a fair point
+[2007.02.16-21.04] Cratylus +<intergossip> which is the same problem i3 had before i showed
+[2007.02.16-21.04] Arren@Anarres +II <imud_gossip> I've reached out to some of the admins of those +muds and communities recently, since I remained in contact with many of +them. I will do so again when this gets resolved.
+[2007.02.16-21.04] Cratylus +<intergossip> "single point of failure"
+[2007.02.16-21.04] Mouse@Broken Empire <imud_gossip> Arren, I'd +suggest you reinvite them to adsr
+[2007.02.16-21.04] Cratylus +<intergossip> and this is why you're not getting any kind of +commitment from me
+[2007.02.16-21.05] Cratylus +<intergossip> the last time i was ok with an spf beyond my direct +control, it died
+[2007.02.16-21.05] Arren@Anarres +II <imud_gossip> Cratylus, the Anarres network has 24x7 +monitoring, support and hands-and-eyes.
+[2007.02.16-21.05] Tatianna@Anarres II <imud_gossip> yeah, but +they never did anything to prevent that, arren wouldnt let it just die +out
+[2007.02.16-21.05] Cratylus +<intergossip> ok, you say so, and it's probably true
+[2007.02.16-21.06] Arren@Anarres +II <imud_gossip> We have a pager network with an ops team of two +always on call.
+[2007.02.16-21.06] Cratylus +<intergossip> but it's still a problem
+[2007.02.16-21.06] Cratylus +<intergossip> heh
+[2007.02.16-21.06] Cratylus +<intergossip> that's not the point
+[2007.02.16-21.06] Arren@Anarres +II <imud_gossip> It rather is the point, this is nearly telecomms +grade.
+[2007.02.16-21.06] Arren@Anarres +II <imud_gossip> These are professional engineers, not casual +coders.
+[2007.02.16-21.06] Reflection@Mirror Ring <imud_gossip> perhaps +Arren could name 1-2 benefactors, for whom should anything happen to +his person, would have access to said router source?  wich nothing +short of death will cause him to cease his maintenance, I know Arren +well enough.  He's solidly deddicated to tasks to the point, he +goes down with a simnking ship' it's what we love about him
+[2007.02.16-21.06] Mouse@Broken Empire <imud_gossip> Crat, your +objection seems to be network stability.
+[2007.02.16-21.06] Mouse@Broken Empire <imud_gossip> Arren offers +that in spades.
+[2007.02.16-21.07] Cratylus +<intergossip> i dont think it is. what you are talking about is +"fuck the inter router network, i want a single router"
+[2007.02.16-21.07] Arren@Anarres +II <imud_gossip> When I go on holiday, there is an entire ops +team to manage the systems, and whom you can contact for maintenance +and administration.
+[2007.02.16-21.07] Cratylus +<intergossip> i think this is a paradigm which has proven to be a +failure
+[2007.02.16-21.07] Tatianna@Anarres II <imud_gossip> i think +crats objection is, i wont be god anymore
+[2007.02.16-21.07] Arren@Anarres +II <imud_gossip> Right now we don't have an inter-router network. +When we have, you will be the first invitee, Cratylus. I will also +offer to code it.
+[2007.02.16-21.07] Mouse@Broken Empire <imud_gossip> Crat... so 1 +router is ok if you run it.  But 1 router is a failure of design +in Arren runs it?
+[2007.02.16-21.07] Arren@Anarres +II <imud_gossip> Do you want it to be your failure, or the +failure of a professional team of telecomms engineers?
+[2007.02.16-21.07] Cratylus +<intergossip> why dont we just code it now?
+[2007.02.16-21.08] Arren@Anarres +II <imud_gossip> Because I started at 10am today, it's now 3am, +and it's been a long time since I've had a day off.
+[2007.02.16-21.08] Cratylus +<intergossip> ok we can start tomorrow
+[2007.02.16-21.08] Arren@Anarres +II <imud_gossip> Tomorrow was going to be my day off.
+[2007.02.16-21.08] Cratylus +<intergossip> then the day after
+[2007.02.16-21.09] Arren@Anarres +II <imud_gossip> Have you ever written a fault tolerant network +system?
+[2007.02.16-21.09] Reflection@Mirror Ring <imud_gossip> Arren is +the most stable and reliable force on i3 this day.  I'd hate to +see i3 split, but I will take sides if it has to be so. =(
+[2007.02.16-21.09] Cratylus +<intergossip> it's been half a year since gjs died. nobody is +going to cease living
+[2007.02.16-21.09] Cratylus +<intergossip> well if people go to arrens router, then fine
+[2007.02.16-21.09] Cratylus +<intergossip> i'll put a mud of my own on there as well
+[2007.02.16-21.09] Cratylus +<intergossip> that's not the point
+[2007.02.16-21.10] Arren@Anarres +II <imud_gossip> Let me write the inter-router code. I have +experience of design and implementation of truly fault tolerant systems.
+[2007.02.16-21.10] Cratylus +<intergossip> making the ds people move there is not something +i'm going to undertake lightly
+[2007.02.16-21.10] Tatianna@Anarres II <imud_gossip> haha, that +sounded like my six, even my two year old "then fine!"
+[2007.02.16-21.10] Cratylus +<intergossip> afaict this is now a game of make cratylus do it +right this minute
+[2007.02.16-21.10] Mouse@Broken Empire <imud_gossip> Crat, we're +trying hard to include you and the DS people
+[2007.02.16-21.10] Cratylus +<intergossip> and i'm not seeing the reason for it
+[2007.02.16-21.11] Cratylus +<intergossip> so it's just making me more skeptical
+[2007.02.16-21.11] Mouse@Broken Empire <imud_gossip> No, this is +a game of "Make Crat admit he's just going to tell all of us to fuck +off anyway"
+[2007.02.16-21.11] Arren@Anarres +II <imud_gossip> The reason is that your delaying, combined with +the publicity of the DS project, is what will cause a fragmentation of +the network.
+[2007.02.16-21.11] Cratylus +<intergossip> tonight?
+[2007.02.16-21.11] Reflection@Mirror Ring <imud_gossip> Ok, so +the favoritism of 'your' mudlib, over all others, over an entire +community wins out.  I thought all this time i3 was a 'mud +community' not a nazi gathering of specific share holders on an +individualist plan of mudworld domination ='(
+[2007.02.16-21.11] Mouse@Broken Empire <imud_gossip> Crat, but +not accepting the idea here, we all know what is about to happen
+[2007.02.16-21.11] Reflection@Mirror Ring <imud_gossip> afk smoke +=(
+[2007.02.16-21.11] Cratylus +<intergossip> well no actually
+[2007.02.16-21.11] Mouse@Broken Empire <imud_gossip> Arren's +router will become the new community, but you'll keep your DS people on +yatmim
+[2007.02.16-21.12] Cratylus +<intergossip> tell me what's going to happen
+[2007.02.16-21.12] Cratylus +<intergossip> ok
+[2007.02.16-21.12] Mouse@Broken Empire <imud_gossip> And you'll +never migrate them.
+[2007.02.16-21.12] Cratylus +<intergossip> and when theres an intermud route rnetwork +everybody will be on it
+[2007.02.16-21.12] Mouse@Broken Empire <imud_gossip> And that's +not good for the overall community either since it brings in no new +blood
+[2007.02.16-21.12] Arren@Anarres +II <imud_gossip> Mouse: Then the publicity hits yatmim, since +that's the router under the DS banner, and the network fragments.
+[2007.02.16-21.12] Cratylus +<intergossip> and it will be transpartent
+[2007.02.16-21.12] Mouse@Broken Empire <imud_gossip> Crat... +that's pointless though.
+[2007.02.16-21.12] Cratylus +<intergossip> i'm missing something here
+[2007.02.16-21.12] Cratylus +<intergossip> i'm not getting something
+[2007.02.16-21.12] Cratylus +<intergossip> someone please explain it
+[2007.02.16-21.13] Arren@Anarres +II <imud_gossip> Mouse was devil's advocate for a minute, and +perhaps you missed it.
+[2007.02.16-21.13] Cratylus +<intergossip> cuz yall are hollering for no urgent reason
+[2007.02.16-21.13] Mouse@Broken Empire <imud_gossip> inter-router +support is a whole lot of code work for a very minor result
+[2007.02.16-21.13] Cratylus +<intergossip> i disagree
+[2007.02.16-21.13] Cratylus +<intergossip> it is the core of the future
+[2007.02.16-21.13] Tatianna@Anarres II <imud_gossip> mouse, its +no use, he cant let go of his control over it, thats why hes insisting +on interrouter, so he still can play god
+[2007.02.16-21.13] Mouse@Broken Empire <imud_gossip> when a +VASTLY easier solution is, "let the network admin run the network"
+[2007.02.16-21.13] Cratylus +<intergossip> a decentralized inter router network fixes +everything
+[2007.02.16-21.13] Cratylus +<intergossip> that is what im arguing for
+[2007.02.16-21.14] Tatianna@Anarres II <imud_gossip> for a lot +more effort
+[2007.02.16-21.14] Tatianna@Anarres II <imud_gossip> effort that +can be avoided
+[2007.02.16-21.14] Cratylus +<intergossip> like you'd lose a drop of sweat, tats
+[2007.02.16-21.14] Arren@Anarres +II <imud_gossip> We haven't got one right now. We aren't going to +have one right now. Choose your next best solution please.
+[2007.02.16-21.14] Mouse@Broken Empire <imud_gossip> Ok, let me +put this another way...
+[2007.02.16-21.14] Mouse@Broken Empire <imud_gossip> Can you code +an inter router network?
+[2007.02.16-21.14] Cratylus +<intergossip> yes
+[2007.02.16-21.14] Mouse@Broken Empire <imud_gossip> Because I +can't.
+[2007.02.16-21.14] Cratylus +<intergossip> i can
+[2007.02.16-21.14] Mouse@Broken Empire <imud_gossip> Then why +haven't you?
+[2007.02.16-21.14] Cratylus +<intergossip> i'd rather have arren help
+[2007.02.16-21.14] Tatianna@Anarres II <imud_gossip> no, i +wouldnt, but im also friends with arren and why would i want her to +spend hours upon hours o coding something that wasnt needed
+[2007.02.16-21.15] Arren@Anarres +II <imud_gossip> Cratylus, I can code IRN solo in under a day, +AND have all kinds of fault tolerance built in that you've never even +heard of.
+[2007.02.16-21.15] Cratylus +<intergossip> great
+[2007.02.16-21.15] Cratylus +<intergossip> let's do it
+[2007.02.16-21.15] Arren@Anarres +II <imud_gossip> But I'm not going to do it today.
+[2007.02.16-21.15] Cratylus +<intergossip> fine
+[2007.02.16-21.15] Cratylus +<intergossip> it can way a few moons
+[2007.02.16-21.15] Cratylus +<intergossip> wait
+[2007.02.16-21.15] Arren@Anarres +II <imud_gossip> But I will commit to give you full access to the +codebase so when it does come out, you can run it.
+[2007.02.16-21.15] Cratylus +<intergossip> i'm not grokking the need for an immediate fix +before bedtime
+[2007.02.16-21.16] Arren@Anarres +II <imud_gossip> In the meantime, please, don't fragment the +network.
+[2007.02.16-21.16] Cratylus +<intergossip> ok
+[2007.02.16-21.16] Arren@Anarres +II <imud_gossip> Please, make a decision.
+[2007.02.16-21.16] Cratylus +<intergossip> fine, "no"
+[2007.02.16-21.16] Mouse@Broken Empire <imud_gossip> Ok.  +Then get lost.
+[2007.02.16-21.16] Arren@Anarres +II <imud_gossip> Not for action right this minute, but a decision.
+[2007.02.16-21.16] Mouse@Broken Empire <imud_gossip> Sorry to put +it that way.
+[2007.02.16-21.16] Cratylus +<intergossip> the decision is, lets do an IRN, and the problem +disappears
+[2007.02.16-21.16] Cratylus +<intergossip> it'll be done by march
+[2007.02.16-21.17] Cratylus +<intergossip> and then everyone is happy
+[2007.02.16-21.17] Cratylus +<intergossip> and the question of a primary router is moot
+[2007.02.16-21.17] Mouse@Broken Empire <imud_gossip> ...assuming +Arren gets a whole day to work on i3 this month.
+[2007.02.16-21.17] Arren@Anarres +II <imud_gossip> Cratylus, I've spent nearly 3 hours discussing +this with you for the basic reason of trying to do you a favour.
+[2007.02.16-21.17] Arren@Anarres +II <imud_gossip> You get shit off I3. I'm trying to remove that +shit and let everyone forget it while actually providing a better +service than you do.
+[2007.02.16-21.17] Arren@Anarres +II <imud_gossip> That's it.
+[2007.02.16-21.17] Cratylus +<intergossip> and i thank you for it
+[2007.02.16-21.18] Cratylus +<intergossip> and it's gonna be great
+[2007.02.16-21.18] Cratylus +<intergossip> i think this is the start of a beautiful partnership
+[2007.02.16-21.18] Cratylus +<intergossip> if you could only learn to cool your fucking jets
+[2007.02.16-21.18] Arren@Anarres +II <imud_gossip> It is no kind of partnership while you us +phrases like "no"
+[2007.02.16-21.18] Cratylus +<intergossip> you'll forgive me for giving you the answer you +dont want while you put the screws on
+[2007.02.16-21.18] Mouse@Broken Empire <imud_gossip> Arren, let +it go.
+[2007.02.16-21.19] Mouse@Broken Empire <imud_gossip> Crat's going +to keep the DS people on yatmim.
+[2007.02.16-21.19] Mouse@Broken Empire <imud_gossip> End of story.
+[2007.02.16-21.19] Mouse@Broken Empire <imud_gossip> Let's work +on getting the non-Crat people onto this router.
+[2007.02.16-21.19] Cratylus +<intergossip> mouse i think you missed the point
+[2007.02.16-21.19] Arren@Anarres +II <imud_gossip> Do you think we can hold the community?
+[2007.02.16-21.19] Mouse@Broken Empire <imud_gossip> Tits, wake +Corvie up.
+[2007.02.16-21.19] Mouse@Broken Empire <imud_gossip> I do, Arren.
+[2007.02.16-21.19] Tatianna@Anarres II <imud_gossip> hes not here +hun
+[2007.02.16-21.19] Tatianna@Anarres II <imud_gossip> prolly +sleeping, he had dinner with the gf tonight
+[2007.02.16-21.20] Arren@Anarres +II <imud_gossip> I can run the network, because it's me plus ops. +I can't get ops to do team management or anything, so I have to rely on +you gyus.
+[2007.02.16-21.20] Mouse@Broken Empire <imud_gossip> I think the +core people will come.  I think that Coffee has an intermud daemon +built in that hasn't been updated since gjs
+[2007.02.16-21.20] Cratylus +<intergossip> they connect to yatmim now
+[2007.02.16-21.20] Cratylus +<intergossip> but you might be able to get zac to change it
+[2007.02.16-21.20] Arren@Anarres +II <imud_gossip> There are a few other communities I wont' +mention immediately, but that we can work with, which might restore a +few more groups.
+[2007.02.16-21.21] Cratylus +<intergossip> heh
+[2007.02.16-21.21] Reflection@Mirror Ring <imud_gossip> Arren, do +you have plans of releaseing a form of your mudlib to the public?  +That would possibly also help usher in new people as well, I can do +some free campaigning here and there, get a little more backing and +some fresh blood possibly =)
+[2007.02.16-21.21] Cratylus +<intergossip> so much for non-fragmentation being your goal
+[2007.02.16-21.21] Cratylus +<intergossip> anyway, back to my question
+[2007.02.16-21.21] Cratylus +<intergossip> do i list asdf?
+[2007.02.16-21.21] Mouse@Broken Empire <imud_gossip> Crat, you're +not getting it.
+[2007.02.16-21.21] Arren@Anarres +II <imud_gossip> I didn't play hard-ball. You did.
+[2007.02.16-21.21] Mouse@Broken Empire <imud_gossip> We wanted to +include you.
+[2007.02.16-21.21] Mouse@Broken Empire <imud_gossip> You decided +that was never going to happen until inter router.
+[2007.02.16-21.21] Arren@Anarres +II <imud_gossip> Yes, please list it.
+[2007.02.16-21.21] Mouse@Broken Empire <imud_gossip> So you're +the one seperated the community.
+[2007.02.16-21.21] Cratylus +<intergossip> whatever guys, you're right, it had to be decided +right this second
+[2007.02.16-21.22] Cratylus +<intergossip> do i list asdf?
+[2007.02.16-21.22] Arren@Anarres +II <imud_gossip> Yes, please list adsr.
+[2007.02.16-21.22] Cratylus +<intergossip> k
+[2007.02.16-21.22] Arren@Anarres +II <imud_gossip> A decision now does not imply action now.
+[2007.02.16-21.22] Arren@Anarres +II <imud_gossip> Remember Kyoto.
+[2007.02.16-21.23] Duuk@Haven <imud_gossip> Better
+[2007.02.16-21.26] Cratylus +<intergossip> there you go http://lpmuds.net/intermud.html
+[2007.02.16-21.26] Cratylus +<intergossip> http://lpmuds.net/forum/ is a good place to announce
+[2007.02.16-21.27] Cratylus +<intergossip> but there are many others, including +http://lpmuds.net/links.html
+[2007.02.16-21.27] +<imud_gossip> Arren@Anarres II looks confused. Now there are +three routers.
+[2007.02.16-21.27] Cratylus +<intergossip> well yes
+[2007.02.16-21.27] Arren@Anarres +II <imud_gossip> Cratylus, it sounds very much as if you want to +compete, rather than cooperate.
+[2007.02.16-21.27] Cratylus +<intergossip> that is what i promised to do
+[2007.02.16-21.27] Cratylus +<intergossip> i'd list you on the intermud page
+[2007.02.16-21.28] Cratylus +<intergossip> i dunno if i can clarify my position any better by +comtinuing to repeat it
+[2007.02.16-21.28] Cratylus +<intergossip> i'll leave it to your chan history
+[2007.02.16-21.29] Duuk@Haven <imud_gossip> You know I've been +picturing you sitting at your desk saying, "My precious..." for like 2 +hours now, right?
+[2007.02.16-21.29] Arren@Anarres +II <imud_gossip> We understand your position, we disagree with +it, we're attempting to persuade you otherwise. You have rejected every +offer which carries consensus or reduces your absolute authority.
+[2007.02.16-21.29] Tatianna@Anarres II <imud_gossip> i can +clarify it for you
+[2007.02.16-21.29] Cratylus +<intergossip> no i haven't
+[2007.02.16-21.29] Cratylus +<intergossip> i have simply asked for time to think about it
+[2007.02.16-21.29] Duuk@Haven <imud_gossip> Yes.  You have.
+[2007.02.16-21.29] Cratylus +<intergossip> which i think is reasonable and proper
+[2007.02.16-21.29] Cratylus +<intergossip> and when forced, my answer is "no"
+[2007.02.16-21.30] Cratylus +<intergossip> which again
+[2007.02.16-21.30] Cratylus +<intergossip> i think is entirely reasonable
+[2007.02.16-21.30] Arren@Anarres +II <imud_gossip> I think thinking time is quite reasonable, +bearing in mind that the network is now fragmented, and the decision +from Cratylus is the only thing that will bring it back together.
+[2007.02.16-21.30] Cratylus +<intergossip> since you're insisting on immediate change of my +view
+[2007.02.16-21.30] Arren@Anarres +II <imud_gossip> So please do think about it.
+[2007.02.16-21.30] Cratylus +<intergossip> k
+
+ + diff --git a/lib/www/lpmuds/script.js b/lib/www/lpmuds/script.js new file mode 100644 index 0000000..799a6b8 --- /dev/null +++ b/lib/www/lpmuds/script.js @@ -0,0 +1,486 @@ +var smf_formSubmitted = false; + +// Define document.getElementById for Internet Explorer 4. +if (typeof(document.getElementById) == "undefined") + document.getElementById = function (id) + { + // Just return the corresponding index of all. + return document.all[id]; + } +// Define XMLHttpRequest for IE 5 and above. (don't bother for IE 4 :/.... works in Opera 7.6 and Safari 1.2!) +else if (!window.XMLHttpRequest && window.ActiveXObject) + window.XMLHttpRequest = function () + { + return new ActiveXObject(navigator.userAgent.indexOf("MSIE 5") != -1 ? "Microsoft.XMLHTTP" : "MSXML2.XMLHTTP"); + }; + +// Some older versions of Mozilla don't have this, for some reason. +if (typeof(document.forms) == "undefined") + document.forms = document.getElementsByTagName("form"); + +// Load an XML document using XMLHttpRequest. +function getXMLDocument(url, callback) +{ + if (!window.XMLHttpRequest) + return false; + + var myDoc = new XMLHttpRequest(); + if (typeof(callback) != "undefined") + { + myDoc.onreadystatechange = function () + { + if (myDoc.readyState != 4) + return; + + if (myDoc.responseXML != null && myDoc.status == 200) + callback(myDoc.responseXML); + }; + } + myDoc.open('GET', url, true); + myDoc.send(null); + + return true; +} + +// Send a post form to the server using XMLHttpRequest. +function sendXMLDocument(url, content, callback) +{ + if (!window.XMLHttpRequest) + return false; + + var sendDoc = new window.XMLHttpRequest(); + if (typeof(callback) != "undefined") + { + sendDoc.onreadystatechange = function () + { + if (sendDoc.readyState != 4) + return; + + if (sendDoc.responseXML != null && sendDoc.status == 200) + callback(sendDoc.responseXML); + else + callback(false); + }; + } + sendDoc.open('POST', url, true); + if (typeof(sendDoc.setRequestHeader) != "undefined") + sendDoc.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + sendDoc.send(content); + + return true; +} + +function textToEntities(text) +{ + var entities = ""; + for (var i = 0; i < text.length; i++) + { + if (text.charCodeAt(i) > 127) + entities += "&#" + text.charCodeAt(i) + ";"; + else + entities += text.charAt(i); + } + + return entities; +} + +// Open a new window. +function reqWin(desktopURL, alternateWidth, alternateHeight, noScrollbars) +{ + if ((alternateWidth && self.screen.availWidth * 0.8 < alternateWidth) || (alternateHeight && self.screen.availHeight * 0.8 < alternateHeight)) + { + noScrollbars = false; + alternateWidth = Math.min(alternateWidth, self.screen.availWidth * 0.8); + alternateHeight = Math.min(alternateHeight, self.screen.availHeight * 0.8); + } + else + noScrollbars = typeof(noScrollbars) != "undefined" && noScrollbars == true; + + window.open(desktopURL, 'requested_popup', 'toolbar=no,location=no,status=no,menubar=no,scrollbars=' + (noScrollbars ? 'no' : 'yes') + ',width=' + (alternateWidth ? alternateWidth : 480) + ',height=' + (alternateHeight ? alternateHeight : 220) + ',resizable=no'); + + // Return false so the click won't follow the link ;). + return false; +} + +// Remember the current position. +function storeCaret(text) +{ + // Only bother if it will be useful. + if (typeof(text.createTextRange) != "undefined") + text.caretPos = document.selection.createRange().duplicate(); +} + +// Replaces the currently selected text with the passed text. +function replaceText(text, textarea) +{ + // Attempt to create a text range (IE). + if (typeof(textarea.caretPos) != "undefined" && textarea.createTextRange) + { + var caretPos = textarea.caretPos; + + caretPos.text = caretPos.text.charAt(caretPos.text.length - 1) == ' ' ? text + ' ' : text; + caretPos.select(); + } + // Mozilla text range replace. + else if (typeof(textarea.selectionStart) != "undefined") + { + var begin = textarea.value.substr(0, textarea.selectionStart); + var end = textarea.value.substr(textarea.selectionEnd); + var scrollPos = textarea.scrollTop; + + textarea.value = begin + text + end; + + if (textarea.setSelectionRange) + { + textarea.focus(); + textarea.setSelectionRange(begin.length + text.length, begin.length + text.length); + } + textarea.scrollTop = scrollPos; + } + // Just put it on the end. + else + { + textarea.value += text; + textarea.focus(textarea.value.length - 1); + } +} + +// Surrounds the selected text with text1 and text2. +function surroundText(text1, text2, textarea) +{ + // Can a text range be created? + if (typeof(textarea.caretPos) != "undefined" && textarea.createTextRange) + { + var caretPos = textarea.caretPos, temp_length = caretPos.text.length; + + caretPos.text = caretPos.text.charAt(caretPos.text.length - 1) == ' ' ? text1 + caretPos.text + text2 + ' ' : text1 + caretPos.text + text2; + + if (temp_length == 0) + { + caretPos.moveStart("character", -text2.length); + caretPos.moveEnd("character", -text2.length); + caretPos.select(); + } + else + textarea.focus(caretPos); + } + // Mozilla text range wrap. + else if (typeof(textarea.selectionStart) != "undefined") + { + var begin = textarea.value.substr(0, textarea.selectionStart); + var selection = textarea.value.substr(textarea.selectionStart, textarea.selectionEnd - textarea.selectionStart); + var end = textarea.value.substr(textarea.selectionEnd); + var newCursorPos = textarea.selectionStart; + var scrollPos = textarea.scrollTop; + + textarea.value = begin + text1 + selection + text2 + end; + + if (textarea.setSelectionRange) + { + if (selection.length == 0) + textarea.setSelectionRange(newCursorPos + text1.length, newCursorPos + text1.length); + else + textarea.setSelectionRange(newCursorPos, newCursorPos + text1.length + selection.length + text2.length); + textarea.focus(); + } + textarea.scrollTop = scrollPos; + } + // Just put them on the end, then. + else + { + textarea.value += text1 + text2; + textarea.focus(textarea.value.length - 1); + } +} + +// Checks if the passed input's value is nothing. +function isEmptyText(theField) +{ + // Copy the value so changes can be made.. + var theValue = theField.value; + + // Strip whitespace off the left side. + while (theValue.length > 0 && (theValue.charAt(0) == ' ' || theValue.charAt(0) == '\t')) + theValue = theValue.substring(1, theValue.length); + // Strip whitespace off the right side. + while (theValue.length > 0 && (theValue.charAt(theValue.length - 1) == ' ' || theValue.charAt(theValue.length - 1) == '\t')) + theValue = theValue.substring(0, theValue.length - 1); + + if (theValue == '') + return true; + else + return false; +} + +// Only allow form submission ONCE. +function submitonce(theform) +{ + smf_formSubmitted = true; +} +function submitThisOnce(form) +{ + // Hateful, hateful fix for Safari 1.3 beta. + if (navigator.userAgent.indexOf('AppleWebKit') != -1) + return !smf_formSubmitted; + + if (typeof(form.form) != "undefined") + form = form.form; + + for (var i = 0; i < form.length; i++) + if (typeof(form[i]) != "undefined" && form[i].tagName.toLowerCase() == "textarea") + form[i].readOnly = true; + + return !smf_formSubmitted; +} + +// Set the "inside" HTML of an element. +function setInnerHTML(element, toValue) +{ + // IE has this built in... + if (typeof(element.innerHTML) != 'undefined') + element.innerHTML = toValue; + // Otherwise, try createContextualFragment(). + else + { + var range = document.createRange(); + range.selectNodeContents(element); + range.deleteContents(); + element.appendChild(range.createContextualFragment(toValue)); + } +} + +// Set the "outer" HTML of an element. +function setOuterHTML(element, toValue) +{ + if (typeof(element.outerHTML) != 'undefined') + element.outerHTML = toValue; + else + { + var range = document.createRange(); + range.setStartBefore(element); + element.parentNode.replaceChild(range.createContextualFragment(toValue), element); + } +} + +// Get the inner HTML of an element. +function getInnerHTML(element) +{ + if (typeof(element.innerHTML) != 'undefined') + return element.innerHTML; + else + { + var returnStr = ''; + for (var i = 0; i < element.childNodes.length; i++) + returnStr += getOuterHTML(element.childNodes[i]); + + return returnStr; + } +} + +function getOuterHTML(node) +{ + if (typeof(node.outerHTML) != 'undefined') + return node.outerHTML; + + var str = ''; + + switch (node.nodeType) + { + // An element. + case 1: + str += '<' + node.nodeName; + + for (var i = 0; i < node.attributes.length; i++) + { + if (node.attributes[i].nodeValue != null) + str += ' ' + node.attributes[i].nodeName + '="' + node.attributes[i].nodeValue + '"'; + } + + if (node.childNodes.length == 0 && in_array(node.nodeName.toLowerCase(), ['hr', 'input', 'img', 'link', 'meta', 'br'])) + str += ' />'; + else + str += '>' + getInnerHTML(node) + ''; + break; + + // 2 is an attribute. + + // Just some text.. + case 3: + str += node.nodeValue; + break; + + // A CDATA section. + case 4: + str += ''; + break; + + // Entity reference.. + case 5: + str += '&' + node.nodeName + ';'; + break; + + // 6 is an actual entity, 7 is a PI. + + // Comment. + case 8: + str += ''; + break; + } + + return str; +} + +// Checks for variable in theArray. +function in_array(variable, theArray) +{ + for (var i = 0; i < theArray.length; i++) + { + if (theArray[i] == variable) + return true; + } + return false; +} + +// Find a specific radio button in its group and select it. +function selectRadioByName(radioGroup, name) +{ + if (typeof(radioGroup.length) == "undefined") + return radioGroup.checked = true; + + for (var i = 0; i < radioGroup.length; i++) + { + if (radioGroup[i].value == name) + return radioGroup[i].checked = true; + } + + return false; +} + +// Invert all checkboxes at once by clicking a single checkbox. +function invertAll(headerfield, checkform, mask) +{ + for (var i = 0; i < checkform.length; i++) + { + if (typeof(checkform[i].name) == "undefined" || (typeof(mask) != "undefined" && checkform[i].name.substr(0, mask.length) != mask)) + continue; + + if (!checkform[i].disabled) + checkform[i].checked = headerfield.checked; + } +} + +// Keep the session alive - always! +var lastKeepAliveCheck = new Date().getTime(); +function smf_sessionKeepAlive() +{ + var curTime = new Date().getTime(); + + // Prevent a Firefox bug from hammering the server. + if (smf_scripturl && curTime - lastKeepAliveCheck > 900000) + { + var tempImage = new Image(); + tempImage.src = smf_scripturl + (smf_scripturl.indexOf("?") == -1 ? "?" : "&") + "action=keepalive;" + curTime; + lastKeepAliveCheck = curTime; + } + + window.setTimeout("smf_sessionKeepAlive();", 1200000); +} +window.setTimeout("smf_sessionKeepAlive();", 1200000); + +// Set a theme option through javascript. +function smf_setThemeOption(option, value, theme, cur_session_id) +{ + // Compatibility. + if (cur_session_id == null) + cur_session_id = smf_session_id; + + var tempImage = new Image(); + tempImage.src = smf_scripturl + (smf_scripturl.indexOf("?") == -1 ? "?" : "&") + "action=jsoption;var=" + option + ";val=" + value + ";sesc=" + cur_session_id + (theme == null ? "" : "&id=" + theme) + ";" + (new Date().getTime()); +} + +function smf_avatarResize() +{ + var possibleAvatars = document.getElementsByTagName ? document.getElementsByTagName("img") : document.all.tags("img"); + + for (var i = 0; i < possibleAvatars.length; i++) + { + if (possibleAvatars[i].className != "avatar") + continue; + + var tempAvatar = new Image(); + tempAvatar.src = possibleAvatars[i].src; + + if (smf_avatarMaxWidth != 0 && tempAvatar.width > smf_avatarMaxWidth) + { + possibleAvatars[i].height = (smf_avatarMaxWidth * tempAvatar.height) / tempAvatar.width; + possibleAvatars[i].width = smf_avatarMaxWidth; + } + else if (smf_avatarMaxHeight != 0 && tempAvatar.height > smf_avatarMaxHeight) + { + possibleAvatars[i].width = (smf_avatarMaxHeight * tempAvatar.width) / tempAvatar.height; + possibleAvatars[i].height = smf_avatarMaxHeight; + } + else + { + possibleAvatars[i].width = tempAvatar.width; + possibleAvatars[i].height = tempAvatar.height; + } + } + + if (typeof(window_oldAvatarOnload) != "undefined" && window_oldAvatarOnload) + { + window_oldAvatarOnload(); + window_oldAvatarOnload = null; + } +} + +function hashLoginPassword(doForm, cur_session_id) +{ + // Compatibility. + if (cur_session_id == null) + cur_session_id = smf_session_id; + + if (typeof(hex_sha1) == "undefined") + return; + // Are they using an email address? + if (doForm.user.value.indexOf("@") != -1) + return; + + // Unless the browser is Opera, the password will not save properly. + if (typeof(window.opera) == "undefined") + doForm.passwrd.autocomplete = "off"; + + doForm.hash_passwrd.value = hex_sha1(hex_sha1(doForm.user.value.toLowerCase() + doForm.passwrd.value) + cur_session_id); + + // It looks nicer to fill it with asterisks, but Firefox will try to save that. + if (navigator.userAgent.indexOf("Firefox/") != -1) + doForm.passwrd.value = ""; + else + doForm.passwrd.value = doForm.passwrd.value.replace(/./g, "*"); +} + +function hashAdminPassword(doForm, username, cur_session_id) +{ + // Compatibility. + if (cur_session_id == null) + cur_session_id = smf_session_id; + + if (typeof(hex_sha1) == "undefined") + return; + + doForm.admin_hash_pass.value = hex_sha1(hex_sha1(username.toLowerCase() + doForm.admin_pass.value) + cur_session_id); + doForm.admin_pass.value = doForm.admin_pass.value.replace(/./g, "*"); +} + +function ajax_indicator(turn_on) +{ + var indicator = document.getElementById("ajax_in_progress"); + if (indicator != null) + { + if (navigator.appName == "Microsoft Internet Explorer" && navigator.userAgent.indexOf("MSIE 7") == -1) + { + indicator.style.top = document.documentElement.scrollTop; + } + indicator.style.display = turn_on ? "block" : "none"; + } +} diff --git a/lib/www/lpmuds/sha1.js b/lib/www/lpmuds/sha1.js new file mode 100644 index 0000000..160e4b4 --- /dev/null +++ b/lib/www/lpmuds/sha1.js @@ -0,0 +1,200 @@ +/* + * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined + * in FIPS PUB 180-1 + * Version 2.1 Copyright Paul Johnston 2000 - 2002. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * Distributed under the BSD License + * See http://pajhome.org.uk/crypt/md5 for details. + */ + +/* + * Configurable variables. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + */ +var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ +var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ +var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ + +/* + * These are the functions you'll usually want to call + * They take string arguments and return either hex or base-64 encoded strings + */ +function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));} +function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));} +function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));} +function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));} +function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));} +function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));} + +/* + * Perform a simple self-test to see if the VM is working + */ +function sha1_vm_test() +{ + return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d"; +} + +/* + * Calculate the SHA-1 of an array of big-endian words, and a bit length + */ +function core_sha1(x, len) +{ + /* append padding */ + x[len >> 5] |= 0x80 << (24 - len % 32); + x[((len + 64 >> 9) << 4) + 15] = len; + + var w = Array(80); + var a = 1732584193; + var b = -271733879; + var c = -1732584194; + var d = 271733878; + var e = -1009589776; + + for (var i = 0; i < x.length; i += 16) + { + var olda = a; + var oldb = b; + var oldc = c; + var oldd = d; + var olde = e; + + for (var j = 0; j < 80; j++) + { + if (j < 16) w[j] = x[i + j]; + else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1); + var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), safe_add(safe_add(e, w[j]), sha1_kt(j))); + e = d; + d = c; + c = rol(b, 30); + b = a; + a = t; + } + + a = safe_add(a, olda); + b = safe_add(b, oldb); + c = safe_add(c, oldc); + d = safe_add(d, oldd); + e = safe_add(e, olde); + } + return Array(a, b, c, d, e); +} + +/* + * Perform the appropriate triplet combination function for the current + * iteration + */ +function sha1_ft(t, b, c, d) +{ + if (t < 20) return (b & c) | ((~b) & d); + if (t < 40) return b ^ c ^ d; + if (t < 60) return (b & c) | (b & d) | (c & d); + return b ^ c ^ d; +} + +/* + * Determine the appropriate additive constant for the current iteration + */ +function sha1_kt(t) +{ + return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : + (t < 60) ? -1894007588 : -899497514; +} + +/* + * Calculate the HMAC-SHA1 of a key and some data + */ +function core_hmac_sha1(key, data) +{ + var bkey = str2binb(key); + if (bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz); + + var ipad = Array(16), opad = Array(16); + for (var i = 0; i < 16; i++) + { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5C5C5C5C; + } + + var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz); + return core_sha1(opad.concat(hash), 512 + 160); +} + +/* + * Add integers, wrapping at 2^32. This uses 16-bit operations internally + * to work around bugs in some JS interpreters. + */ +function safe_add(x, y) +{ + var lsw = (x & 0xFFFF) + (y & 0xFFFF); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); +} + +/* + * Bitwise rotate a 32-bit number to the left. + */ +function rol(num, cnt) +{ + return (num << cnt) | (num >>> (32 - cnt)); +} + +/* + * Convert an 8-bit or 16-bit string to an array of big-endian words + * In 8-bit function, characters >255 have their hi-byte silently ignored. + */ +function str2binb(str) +{ + var bin = Array(); + var mask = (1 << chrsz) - 1; + for (var i = 0; i < str.length * chrsz; i += chrsz) + bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (24 - i%32); + return bin; +} + +/* + * Convert an array of big-endian words to a string + */ +function binb2str(bin) +{ + var str = ""; + var mask = (1 << chrsz) - 1; + for (var i = 0; i < bin.length * 32; i += chrsz) + str += String.fromCharCode((bin[i>>5] >>> (24 - i%32)) & mask); + return str; +} + +/* + * Convert an array of big-endian words to a hex string. + */ +function binb2hex(binarray) +{ + var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; + var str = ""; + for (var i = 0; i < binarray.length * 4; i++) + { + str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) + + hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF); + } + return str; +} + +/* + * Convert an array of big-endian words to a base-64 string + */ +function binb2b64(binarray) +{ + var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + var str = ""; + for (var i = 0; i < binarray.length * 4; i += 3) + { + var triplet = (((binarray[i >> 2] >> 8 * (3 - i %4)) & 0xFF) << 16) + | (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 ) + | ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF); + for (var j = 0; j < 4; j++) + { + if (i * 8 + j * 6 > binarray.length * 32) str += b64pad; + else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); + } + } + return str; +} diff --git a/lib/www/lpmuds/sitefaq.html b/lib/www/lpmuds/sitefaq.html new file mode 100644 index 0000000..21a949e --- /dev/null +++ b/lib/www/lpmuds/sitefaq.html @@ -0,0 +1,418 @@ + + + + + + + + + LPMuds.net - Site FAQ + + + + + + + + + + +
+ + + + + + + +
LPMuds.net +
+ + + + + + +
A +resource site for LPC, LPMuds, and related stuffs.
+
+ + + + + + + + + + + + + + + + +
  Index + Forum   Site +FAQ   LPMud +FAQ Intermud + Downloads + Links +  
+

+ +
+
+
  +LPMuds.net - Site FAQ
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

What's this site about?

+
+

This site is intended to be a resource for information on +LPmuds +and related downloads. Since I have a decided preference for a +particular kind of LPmud, you can expect some bias, but hopefully it +isn't excessive.

+
+
+

What's a MUD?

+
+

A kind of online text-based adventure game that people can +play on +the Internets. See this Wikipedia +entry for details, and this Jargon file entry +for more context.

+
+
+

What's an LPmud?

+
+

An LPmud +is a type of mud program that is programmed in a scripted language +called LPC.

+
+
+

What is LPC?

+
+

It is a scripting language that looks a lot like the C +programming language but is much, much easier to learn than C and is +designed for making muds.

+
+
+

Why dedicate a site to this stuff?

+
+

I spent a lot of time working on an LPmud, and I'm hoping +other +people will, too. It'll make me feel like less of a loser. Right now +Diku-style muds are dominant, and that makes me sad. Hopefully, having +more LP info out there will help people recognize the goodness that is +LPmuds.

+
+
+

What is the advantage/difference of LPmuds +over Diku?

+
+

Please see this online discussion +for an explanation.

+
+
+

What LPmud types are available?

+
+

The different kinds of LPmuds are usually called "libs" +which +stands for "libraries". You can find information on various libs here:

+

The +LPmud lib list

+
+
+

Where can I find documentation on LPC?

+
+

The Dead +Souls +Homepage is a good start.
+

+

See also:
+ http://darkrifts.org/lpcmanual/
+ http://www.geas.de/tutorial/lpc_toc.html
+ http://phantasmal.sourceforge.net/DGD/LPC/
+ http://www.dnd.utwente.nl/~krimud/Docs/
+ http://discworld.atuin.net/external/lpc_for_dummies/index.shtml
+

+
+
+

You are a tricksy trickster! This is +not an LPC site, it is a Dead Souls site!

+
There is no debate about what, as +of this writing, is the overwhelming
+content of the site: discussion of the Dead Souls 2 LP mudlib. I +maintain
+that lib, and I own this site. There is an obvious bias in the current
+demographics of the site membership.
+
+I mean...you know. Duh.
+
+However, the point of my work has been not only a revival of Dead +Souls, but
+ a +revival of LPC by using Dead Souls as a tool to get to that renaissance.
+
+Perhaps I am deluded in my belief that spreading popularity of Dead +Souls
+is a net plus for LPC. I grant you that. But don't doubt that this is my
+honest belief. My maniacal fanaticism in support of Dead Souls should be
+clear evidence that I may not be rational on this point, and merit a
+little humoring.
+
+That aside, I do think that a reliable, trustworthy site open to any +and all
+LPC discussion is sorely needed, and I want to make it possible for that
+site to be lpmuds.net. I have been +making clear to everyone that all
+LPC discussion, regardless of driver or lib, is welcome and encouraged,
+and it is my hope that, though started as largely a DS support site, it
+becomes a hub for activity and discussion of LPC of all persuasions.
+
+Call me nutty or mistaken. But don't call me deceptive. I'm up front +about
+what I'm trying to do, and people can decide for themselves whether
+they like it. 
+
+
+

What are the rules for the forum?

+
+
The previous question should make +it clear that I'm interested in
+promoting a wider adoption of LPMuds. If you are at all familiar with
+the history of LPMuds, it should be obvious that allowing things to
+happen as they have, without intervention, has only promoted decline.
+Therefore it is logical that a successful approach to reviving the
+LPMud community involves something other than what has already been
+happening.
+
+There are various other forums that provide an avenue for
+nearly-no-holds-barred discussion. This, in my opinion, can provide
+for fun debate, but just as often it provides for non-fun flames
+which are not of any constructive help, and tend to deter new people
+from participating.
+
+The participation of new folks is key in my strategy to help
+grow the LPMudding community. In my experience, allowing
+free-fire discussion zones does not help. So, as uncomfortable
+as I am with being a forum nanny (or perhaps as some might term it,
+a forum nazi), the LPMud discussion boards will have a fairly
+restrictive set of rules, which include the following:
+
+1) Offtopic posts may be moved to the appropriate topics or threads.
+
+2) Illegal activity will not be tolerated.
+
+3) Behavior I judge to be in conflict with the stated objectives of +this site won't be tolerated.
+
+4) Undue hostility, flaming, and/or swearing is likely to be moved to +The Toilet.
+
+The Toilet is a sort of compromise. I really dislike being a
+content nazi, but it suits my objectives. In order to maintain
+decorum while using the minimum violence in suppressing
+free speech, I've chosen to create a topic for flames, offensive
+material, etc. This topic is The Toilet. Guests and members do not have
+access to The Toilet by default. You need to send me a Private Message
+asking me to add you to the Pottymouth group, and then you'll have
+access to toilet talk.
+
+I don't really have the spare time to be always fair, I'm afraid,
+so I hope you'll forgive me if I censor material unjustly. Just
+send me a PM explaining why I was unfair, and the chances are I'll
+take the time to go over it with you. If not, too bad. I want
+everyone to have a chance to participate, and your unique
+contribution might interfere with that, so despite its value, it
+may just have to go into the elite, special area called The Toilet.
+
+
+
+
+
+
+
+
+
+
+ + + + + + +
+ + - Cratylus
+<my name here>@comcast.net
+
+ + + diff --git a/lib/www/lpmuds/skylib-faq.html b/lib/www/lpmuds/skylib-faq.html new file mode 100644 index 0000000..ebe40df --- /dev/null +++ b/lib/www/lpmuds/skylib-faq.html @@ -0,0 +1,182 @@ + + + + + Dead Souls FAQ + + + + +
Skylib Bundle FAQ

Written by Cratylus @ Dead Souls, October 2006

What is the first thing I should know?

What is the second thing I should know?

Who is this for?

What is Skylib?

Aren't you the Dead Souls maintainer? What's your angle here?

Why were you working on Skylib?

Well, you wasted your time. It doesn't work.

Where can I get support for Skylib, then?

I work with Skylib all the time. It's not that hard to set up.

Where can I get it?

+What is the +first thing I should know?
+
+The Skylib Bundle is NOT DEAD SOULS. It is the Skylib mudlib,
+which is a completely different set of files than those distributed
+with Dead Souls. I, Cratylus, am not the author of Skylib, and
+you can consider this an official disclaim of any credit for its
+brilliance or blame for its pitfalls.
+
+
+What is the +second thing I should know?
+
+The authors and maintainers of the official Skylib mudlib
+do not take responsibility for this bundle. This is a strictly
+"third party" deal which they will not support in any way. You
+are free to download and use it, but you are not entitled to
+receive support from anyone.
+
+
+Who is this for?
+
+The Skylib bundle is absolutely not for newbie admins. This
+is not intended to be a "get started on your own mud the
+easy way!" sort of deal. I am making it available as a
+courtesy and favor to mudlib hobbyists who have an interest
+in tinkering with this lib. But if what you're looking for
+is a quick-start kit for your own mud, I strongly recommend
+you stop reading now and look elsewhere, because even though
+the Skylib Bundle makes installation easiER, it does not
+necessarily make it eaSY.
+
+
+What is Skylib?
+
+It's a mudlib based on the Skylib Mud, which was
+originally based on the Discworld mudlib.
+
+
+Aren't you the +Dead Souls maintainer? What's your angle here?
+
+I am indeed the maintainer of a different mudlib
+called Dead Souls (which I am not ashamed to plug
+here by pointing you to its Wikipedia +entry). However, I
+have a general affection for the LP mud codebase family.
+During some experimentation I found that I had a
+relatively easier way of installing Skylib that people
+could take advantage of, and it seemed like a nice thing
+to do, making it available generally.
+
+I'm not afraid that people will use Skylib instead of
+Dead Souls. For one thing, I think that "more LPmuds",
+regardless of the codebase, is a net plus for DS. And
+anyway, what kind of lib author would I be, if I was
+afraid to let people compare my work side by side with that
+of others? Let the chips fall where they may.
+
+
+Why were you +working on Skylib?
+
+During Dead Souls development I decided to take a serious look
+other libs after experiencing success experimenting with
+Discworld lib. I got a bit carried away, I'm afraid, and
+decided to see what else I could bundle.
+
+
+Well, you +wasted your time. It doesn't work.
+
+There is such a vast and bewildering array of operating
+system and development software and system hardware architecture
+combinations out there that there is simply no way for
+me to guarantee that the bundle will work for everyone...
+or indeed for most.
+
+I can assure you that the bundle puts you much much closer
+to a successful Skylib start than you'd be without it. If it
+still doesn't work out of the box, please note:
+
+* I haven't tested this on Cygwin or any other Windows emulation
+or native windows compilation suite. For all I know it is not
+possible to get it to work on Windows.
+
+
* Skylib +expects your system to have file compression libraries.
+If you don't have zlib, or it's in an exotic location, or
+your library search path is munged, you will probably experience
+some level of sadness. If sadness what you feel, try ensuring
+that none of those three conditions apply to you.

+
+* Do NOT under ANY CIRCUMSTANCES attempt to contact Skylib
+mud personnel or Skylib mudlib maintainers to complain that
+this bundle is lame or to ask for help with it. It'll be like
+asking Bill Joy to come over and help you install Solaris. His
+involvement with the development of UNIX doesn't entitle you to
+help from him, and the Skylib people don't deserve to be
+exposed to noob brainwaves from people who think they are owed +assistance.
+
+* Perhaps the most important thing you can read is this:
+http://www.catb.org/%7Eesr/faqs/smart-questions.html
+Note that the people on that page also are not to be contacted for +support.
+
+
+Where can I get +support for Skylib?
+
+Once it is installed, it might not be unreasonable to
+ask for advice on the imud_code line.
+
+You're also welcome to visit the LPMuds.net +discussion forum
+and chat there, but don't expect quick turnaround on your
+questions. Skylib experts are fewer and farther between
+than they once were, so you may have to wait a little
+for a helpful response.
+
+
+I work with Skylib all the time. It's not that +hard to +set up.
+
+That's true. The small driver and lib tweaks necessary to
+get Skylib compiled and run on a modern system aren't
+that big a deal, but it seemed like a nice thing to do anyway.
+
+Many people will still run into problems, I'm sure, but
+even for those, this should get them closer to the ballpark.
+
+
+Where can I get it?
+
+http://lpmuds.net/files/
+
+
+LPMuds.net
+
+
+ + diff --git a/lib/www/lpmuds/smflogo.gif b/lib/www/lpmuds/smflogo.gif new file mode 100644 index 0000000..a05139d Binary files /dev/null and b/lib/www/lpmuds/smflogo.gif differ diff --git a/lib/www/lpmuds/spellcheck.js b/lib/www/lpmuds/spellcheck.js new file mode 100644 index 0000000..e920928 --- /dev/null +++ b/lib/www/lpmuds/spellcheck.js @@ -0,0 +1,245 @@ +// These are variables the popup is going to want to access... +var spell_formname, spell_fieldname; + +// Spell check the specified field in the specified form. +function spellCheck(formName, fieldName) +{ + // Grab the spell checking form. + var spellform = document.forms.spell_form; + + spell_formname = formName; + spell_fieldname = fieldName; + spellform.spellstring.value = document.forms[formName][fieldName].value; + + openSpellWin(640, 480); + spellform.submit(); + + return true; +} + +// Private functions ------------------------------- + +// Globals... +var wordindex = -1, offsetindex = 0; +var ignoredWords = []; + +// A "misspelled word" object. +function misp(word, start, end, suggestions) +{ + // The word, start index, end index, and array of suggestions. + this.word = word; + this.start = start; + this.end = end; + this.suggestions = suggestions; +} + +// Replace the word in the misps array at the "wordindex" index. The +// misps array is generated by a PHP script after the string to be spell +// checked is evaluated with pspell. +function replaceWord() +{ + var strstart = ""; + var strend; + + // If this isn't the beginning of the string then get all of the string + // that is before the word we are replacing. + if (misps[wordindex].start != 0) + strstart = mispstr.slice(0, misps[wordindex].start + offsetindex); + + // Get the end of the string after the word we are replacing. + strend = mispstr.slice(misps[wordindex].end + 1 + offsetindex); + + // Rebuild the string with the new word. + mispstr = strstart + document.forms.spellingForm.changeto.value + strend; + + // Update offsetindex to compensate for replacing a word with a word + // of a different length. + offsetindex += document.forms.spellingForm.changeto.value.length - misps[wordindex].word.length; + + // Update the word so future replaceAll calls don't change it. + misps[wordindex].word = document.forms.spellingForm.changeto.value; + + nextWord(false); +} + +// Replaces all instances of currently selected word with contents chosen by user. +// Note: currently only replaces words after highlighted word. I think we can re-index +// all words at replacement or ignore time to have it wrap to the beginning if we want +// to. +function replaceAll() +{ + var strend; + var idx; + var origword; + var localoffsetindex = offsetindex; + + origword = misps[wordindex].word; + + // Re-index everything past the current word. + for (idx = wordindex; idx < misps.length; idx++) + { + misps[idx].start += localoffsetindex; + misps[idx].end += localoffsetindex; + } + + localoffsetindex = 0; + + for (idx = 0; idx < misps.length; idx++) + { + if (misps[idx].word == origword) + { + var strstart = ""; + if (misps[idx].start != 0) + strstart = mispstr.slice(0, misps[idx].start + localoffsetindex); + + // Get the end of the string after the word we are replacing. + strend = mispstr.slice(misps[idx].end + 1 + localoffsetindex); + + // Rebuild the string with the new word. + mispstr = strstart + document.forms.spellingForm.changeto.value + strend; + + // Update offsetindex to compensate for replacing a word with a word + // of a different length. + localoffsetindex += document.forms.spellingForm.changeto.value.length - misps[idx].word.length; + } + + // We have to re-index everything after replacements. + misps[idx].start += localoffsetindex; + misps[idx].end += localoffsetindex; + } + + // Add the word to the ignore array. + ignoredWords[origword] = true; + + // Reset offsetindex since we re-indexed. + offsetindex = 0; + + nextWord(false); +} + +// Highlight the word that was selected using the nextWord function. +function highlightWord() +{ + var strstart = ""; + var strend; + + // If this isn't the beginning of the string then get all of the string + // that is before the word we are replacing. + if (misps[wordindex].start != 0) + strstart = mispstr.slice(0, misps[wordindex].start + offsetindex); + + // Get the end of the string after the word we are replacing. + strend = mispstr.slice(misps[wordindex].end + 1 + offsetindex); + + // Rebuild the string with a span wrapped around the misspelled word + // so we can highlight it in the div the user is viewing the string in. + var divptr, newValue; + divptr = document.getElementById("spellview"); + + newValue = htmlspecialchars(strstart) + '' + misps[wordindex].word + '' + htmlspecialchars(strend); + setInnerHTML(divptr, newValue.replace(/_\|_/g, '
')); + + // We could use scrollIntoView, but it's just not that great anyway. + var spellview_height = typeof(document.getElementById("spellview").currentStyle) != "undefined" ? parseInt(document.getElementById("spellview").currentStyle.height) : document.getElementById("spellview").offsetHeight; + var word_position = document.getElementById("h1").offsetTop; + var current_position = document.getElementById("spellview").scrollTop; + + // The spellview is not tall enough! Scroll down! + if (spellview_height <= (word_position + current_position)) + document.getElementById("spellview").scrollTop = word_position + current_position - spellview_height + 32; +} + +// Display the next misspelled word to the user and populate the suggested spellings box. +function nextWord(ignoreall) +{ + // Push ignored word onto ignoredWords array. + if (ignoreall) + ignoredWords[misps[wordindex].word] = true; + + // Update the index of all words we have processed... + // This must be done to accomodate the replaceAll function. + if (wordindex >= 0) + { + misps[wordindex].start += offsetindex; + misps[wordindex].end += offsetindex; + } + + // Increment the counter for the array of misspelled words. + wordindex++; + + // Draw it and quit if there are no more misspelled words to evaluate. + if (misps.length <= wordindex) + { + var divptr; + divptr = document.getElementById("spellview"); + setInnerHTML(divptr, htmlspecialchars(mispstr).replace(/_\|_/g, "
")); + + while (document.forms.spellingForm.suggestions.options.length > 0) + document.forms.spellingForm.suggestions.options[0] = null; + + alert(txt['done']); + document.forms.spellingForm.change.disabled = true; + document.forms.spellingForm.changeall.disabled = true; + document.forms.spellingForm.ignore.disabled = true; + document.forms.spellingForm.ignoreall.disabled = true; + + // Put line feeds back... + mispstr = mispstr.replace(/_\|_/g, "\n"); + + // Get a handle to the field we need to re-populate. + window.opener.document.forms[spell_formname][spell_fieldname].value = mispstr; + window.opener.document.forms[spell_formname][spell_fieldname].focus(); + window.close(); + return true; + } + + // Check to see if word is supposed to be ignored. + if (typeof(ignoredWords[misps[wordindex].word]) != "undefined") + { + nextWord(false); + return false; + } + + // Clear out the suggestions box! + while (document.forms.spellingForm.suggestions.options.length > 0) + document.forms.spellingForm.suggestions.options[0] = null; + + // Re-populate the suggestions box if there are any suggested spellings for the word. + if (misps[wordindex].suggestions.length) + { + for (var sugidx = 0; sugidx < misps[wordindex].suggestions.length; sugidx++) + { + var newopt = new Option(misps[wordindex].suggestions[sugidx], misps[wordindex].suggestions[sugidx]); + document.forms.spellingForm.suggestions.options[sugidx] = newopt; + + if (sugidx == 0) + { + newopt.selected = true; + document.forms.spellingForm.changeto.value = newopt.value; + document.forms.spellingForm.changeto.select(); + } + } + } + + if (document.forms.spellingForm.suggestions.options.length == 0) + document.forms.spellingForm.changeto.value = ""; + + highlightWord(); + + return false; +} + +function htmlspecialchars(thetext) +{ + thetext = thetext.replace(/\/g, ">"); + thetext = thetext.replace(/\n/g, "
"); + thetext = thetext.replace(/\ \ /g, "  "); + + return thetext; +} + +function openSpellWin(width, height) +{ + window.open("", "spellWindow", "toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=no,width=" + width + ",height=" + height); +} \ No newline at end of file diff --git a/lib/www/lpmuds/style.css b/lib/www/lpmuds/style.css new file mode 100644 index 0000000..d5f6d49 --- /dev/null +++ b/lib/www/lpmuds/style.css @@ -0,0 +1,449 @@ +/* Normal, standard links. */ +a:link +{ + color: #476C8E; + text-decoration: none; +} +a:visited +{ + color: #476C8E; + text-decoration: none; +} +a:hover +{ + text-decoration: underline; +} + +/* Navigation links - for the link tree. */ +.nav, .nav:link, .nav:visited +{ + color: #000000; + text-decoration: none; +} +a.nav:hover +{ + color: #cc3333; + text-decoration: underline; +} + +/* Tables should show empty cells. */ +table +{ + empty-cells: show; +} + +/* By default (td, body..) use verdana in black. */ +body, td, th , tr +{ + color: #000000; + font-size: small; + font-family: verdana, sans-serif; +} + +/* The main body of the entire forum. */ +body +{ + background-color: #E5E5E8; + margin: 0px; + padding: 12px 30px 4px 30px; +} + +/* Input boxes - just a bit smaller than normal so they align well. */ +input, textarea, button +{ + color: #000000; + font-family: verdana, sans-serif; +} +input, button +{ + font-size: 90%; +} + +textarea +{ + font-size: 100%; + color: #000000; + font-family: verdana, sans-serif; +} + +/* All input elements that are checkboxes or radio buttons. */ +input.check +{ +} + +/* Selects are a bit smaller, because it makes them look even better 8). */ +select +{ + font-size: 90%; + font-weight: normal; + color: #000000; + font-family: verdana, sans-serif; +} + +/* Standard horizontal rule.. ([hr], etc.) */ +hr, .hrcolor +{ + height: 1px; + border: 0; + color: #666666; + background-color: #666666; +} + +/* No image should have a border when linked */ +a img{ +border: 0; +} +/* A quote, perhaps from another post. */ +.quote +{ + color: #000000; + background-color: #D7DAEC; + border: 1px solid #000000; + margin: 1px; + padding: 1px; + font-size: x-small; + line-height: 1.4em; +} + +/* A code block - maybe even PHP ;). */ +.code +{ + color: #000000; + background-color: #dddddd; + font-family: "courier new", "times new roman", monospace; + font-size: x-small; + line-height: 1.3em; + /* Put a nice border around it. */ + border: 1px solid #000000; + margin: 1px auto 1px auto; + padding: 1px; + width: 99%; + /* Don't wrap its contents, and show scrollbars. */ + white-space: nowrap; + overflow: auto; + /* Stop after about 24 lines, and just show a scrollbar. */ + max-height: 24em; +} + +/* The "Quote:" and "Code:" header parts... */ +.quoteheader, .codeheader +{ + color: #000000; + text-decoration: none; + font-style: normal; + font-weight: bold; + font-size: x-small; + line-height: 1.2em; +} + +/* Generally, those [?] icons. This makes your cursor a help icon. */ +.help +{ + cursor: help; +} + +/* /me uses this a lot. (emote, try typing /me in a post.) */ +.meaction +{ + color: red; +} + +/* The main post box - this makes it as wide as possible. */ +.editor +{ + width: 96%; +} + +/* Highlighted text - such as search results. */ +.highlight +{ + background-color: yellow; + font-weight: bold; + color: black; +} + +/* Alternating backgrounds for posts, and several other sections of the forum. */ +.windowbg +{ + color: #000000; + background-color: #ECEDF3; +} +.windowbg2 +{ + color: #000000; + background-color: #F6F6F6; +} +.windowbg3 +{ + color: #000000; + background-color: #E0E1E8; +} +/* the today container in calendar */ +.calendar_today +{ + background-color: #FFFFFF; +} + +/* These are used primarily for titles, but also for headers (the row that says what everything in the table is.) */ +.titlebg, tr.titlebg th, tr.titlebg td, .titlebg2, tr.titlebg2 th, tr.titlebg2 td +{ + color: black; + font-style: normal; + background: url(images/titlebg.jpg) #E9F0F6 repeat-x; + border-bottom: solid 1px #9BAEBF; + border-top: solid 1px #FFFFFF; + padding-left: 10px; + padding-right: 10px; +} +.titlebg, .titlebg a:link, .titlebg a:visited +{ + font-weight: bold; + color: black; + font-style: normal; +} + +.titlebg a:hover +{ + color: #404040; +} +/* same as titlebg, but used where bold text is not needed */ +.titlebg2 a:link, .titlebg2 a:visited +{ + color: black; + font-style: normal; + text-decoration: underline; +} + +.titlebg2 a:hover +{ + text-decoration: underline; +} + +/* This is used for categories, page indexes, and several other areas in the forum. +.catbg and .catbg2 is for boardindex, while .catbg3 is for messageindex and display headers*/ +.catbg , tr.catbg td , .catbg3 , tr.catbg3 td +{ + background: url(images/catbg.jpg) #88A6C0 repeat-x; + color: #ffffff; + padding-left: 10px; + padding-right: 10px; +} +.catbg2 , tr.catbg2 td +{ + background: url(images/catbg2.jpg) #A1BFD9 repeat-x; + color: #ffffff; + padding-left: 10px; + padding-right: 10px; +} +.catbg, .catbg2, .catbg3 +{ + border-bottom: solid 1px #375576; +} +.catbg, .catbg2 +{ + font-weight: bold; +} +.catbg3, tr.catbg3 td, .catbg3 a:link, .catbg3 a:visited +{ + font-size: 95%; + color: white; + text-decoration: none; +} +.catbg a:link, .catbg a:visited , .catbg2 a:link, .catbg2 a:visited +{ + color: white; + text-decoration: none; +} +.catbg a:hover, .catbg2 a:hover, .catbg3 a:hover +{ + color: #e0e0ff; +} +/* This is used for tables that have a grid/border background color (such as the topic listing.) */ +.bordercolor +{ + background-color: #ADADAD; + padding: 0px; +} + +/* This is used on tables that should just have a border around them. */ +.tborder +{ + padding: 1px; + border: 1px solid #696969; + background-color: #FFFFFF; +} + +/* Default font sizes: small (8pt), normal (10pt), and large (14pt). */ +.smalltext +{ + font-size: x-small; + font-family: verdana, sans-serif; +} +.middletext +{ + font-size: 90%; +} +.normaltext +{ + font-size: small; +} +.largetext +{ + font-size: large; +} + + +/* Posts and personal messages displayed throughout the forum. */ +.post, .personalmessage +{ + width: 100%; + overflow: auto; + line-height: 1.3em; +} + +/* All the signatures used in the forum. If your forum users use Mozilla, Opera, or Safari, you might add max-height here ;). */ +.signature +{ + width: 100%; + overflow: auto; + padding-bottom: 3px; + line-height: 1.3em; +} + +/* Sometimes there will be an error when you post */ +.error{ + color: red; +} + + +/* definitions for the main tab, active means the tab reflects which page is displayed */ +.maintab_first, .maintab_back, .maintab_last, .maintab_active_first, .maintab_active_back, .maintab_active_last +{ + color: white; + text-transform: uppercase; + vertical-align: top; +} +.maintab_back, .maintab_active_back +{ + color: white; + text-decoration: none; + font-size: 9px; + vertical-align: top; + padding: 2px 6px 6px 6px; + font-family: tahoma, sans-serif; +} + +.maintab_first +{ + background: url(images/maintab_first.gif) left bottom no-repeat; + width: 10px; +} +.maintab_back +{ + background: url(images/maintab_back.gif) left bottom repeat-x; +} +.maintab_last +{ + background: url(images/maintab_last.gif) left bottom no-repeat; + width: 8px; +} +.maintab_active_first +{ + background: url(images/maintab_active_first.gif) left bottom no-repeat; + width: 6px; +} +.maintab_active_back +{ + background: url(images/maintab_active_back.gif) left bottom repeat-x; +} +.maintab_active_last +{ + background: url(images/maintab_active_last.gif) left bottom no-repeat; + width: 8px; +} + +/* how links behave in main tab. */ +.maintab_back a:link , .maintab_back a:visited, .maintab_active_back a:link , .maintab_active_back a:visited +{ + color: white; + text-decoration: none; +} + +.maintab_back a:hover, .maintab_active_back a:hover +{ + color: #e0e0ff; + text-decoration: none; +} +/* definitions for the mirror tab */ +.mirrortab_first, .mirrortab_back, .mirrortab_last, .mirrortab_active_first, .mirrortab_active_back, .mirrortab_active_last +{ + color: white; + text-transform: uppercase; + vertical-align: top; +} +.mirrortab_back, .mirrortab_active_back +{ + color: white; + text-decoration: none; + font-size: 9px; + vertical-align: bottom; + padding: 6px 6px 2px 6px; + font-family: tahoma, sans-serif; +} + +.mirrortab_first +{ + background: url(images/mirrortab_first.gif) no-repeat; + width: 10px; +} +.mirrortab_back +{ + background: url(images/mirrortab_back.gif) repeat-x; +} +.mirrortab_last +{ + background: url(images/mirrortab_last.gif) no-repeat; + width: 6px; +} +.mirrortab_active_first +{ + background: url(images/mirrortab_active_first.gif) no-repeat; + width: 6px; +} +.mirrortab_active_back +{ + background: url(images/mirrortab_active_back.gif) repeat-x; +} +.mirrortab_active_last +{ + background: url(images/mirrortab_active_last.gif) no-repeat; + width: 8px; +} + +/* how links behave in mirror tab. */ +.mirrortab_back a:link , .mirrortab_back a:visited, .mirrortab_active_back a:link , .mirrortab_active_back a:visited +{ + color: white; + text-decoration: none; +} + +.mirrortab_back a:hover, .mirrortab_active_back a:hover +{ + color: #e0e0ff; + text-decoration: none; +} + +/* The AJAX notifier */ +#ajax_in_progress +{ + background: #32CD32; + color: white; + text-align: center; + font-weight: bold; + font-size: 18pt; + padding: 3px; + width: 100%; + position: fixed; + top: 0; + left: 0; +} \ No newline at end of file diff --git a/lib/www/lpmuds/tmi2-faq.html b/lib/www/lpmuds/tmi2-faq.html new file mode 100644 index 0000000..aff79d7 --- /dev/null +++ b/lib/www/lpmuds/tmi2-faq.html @@ -0,0 +1,177 @@ + + + + + Dead Souls FAQ + + + + +
TMI-2 Bundle FAQ

Written by Cratylus @ Dead Souls, October 2006

What is the first thing I should know?

What is the second thing I should know?

Who is this for?

What is TMI-2?

Aren't you the Dead Souls maintainer? What's your angle here?

Why were you working on TMI-2?

Well, you wasted your time. It doesn't work.

Where can I get support for TMI-2, then?

I work with TMI-2 all the time. It's not that hard to set up.

Where can I get it?

+What is the +first thing I should know?
+
+The TMI-2 Bundle is NOT DEAD SOULS. It is the TMI-2 mudlib,
+which is a completely different set of files than those distributed
+with Dead Souls. I, Cratylus, am not the author of TMI-2, and
+you can consider this an official disclaim of any credit for its
+brilliance or blame for its pitfalls.
+
+
+What is the +second thing I should know?
+
+The authors and maintainers of the official TMI-2 mudlib
+do not take responsibility for this bundle. This is a strictly
+"third party" deal which they will not support in any way. You
+are free to download and use it, but you are not entitled to
+receive support from anyone.
+
+
+Who is this for?
+
+The TMI-2 bundle is absolutely not for newbie admins. This
+is not intended to be a "get started on your own mud the
+easy way!" sort of deal. I am making it available as a
+courtesy and favor to mudlib hobbyists who have an interest
+in tinkering with this lib. But if what you're looking for
+is a quick-start kit for your own mud, I strongly recommend
+you stop reading now and look elsewhere, because even though
+the TMI-2 Bundle makes installation easiER, +it does not
+necessarily make it eaSY.
+
+
+What is TMI-2?
+
+You'll want to refer to the Wikipedia article +on this. It's a
+lib for which many LPC old timers have a nostalgic fondness.
+
+
+Aren't you the +Dead Souls maintainer? What's your angle here?
+
+I am indeed the maintainer of a different mudlib
+called Dead Souls (which I am not ashamed to plug
+here by pointing you to its Wikipedia +entry). However, I
+have a general affection for the LP mud codebase family.
+During some experimentation I found that I had a
+relatively easier way of installing TMI-2 that people
+could take advantage of, and it seemed like a nice thing
+to do, making it available generally.
+
+I'm not afraid that people will use TMI-2 instead of
+Dead Souls. For one thing, I think that "more LPmuds",
+regardless of the codebase, is a net plus for DS. And
+anyway, what kind of lib author would I be, if I was
+afraid to let people compare my work side by side with that
+of others? Let the chips fall where they may.
+
+
+Why were you +working on TMI-2?
+
+During Dead Souls development I decided to take a serious look
+other libs after experiencing success experimenting with
+Discworld lib. I got a bit carried away, I'm afraid, and
+decided to see what else I could bundle.
+
+
+Well, you +wasted your time. It doesn't work.
+
+There is such a vast and bewildering array of operating
+system and development software and system hardware architecture
+combinations out there that there is simply no way for
+me to guarantee that the bundle will work for everyone...
+or indeed for most.
+
+If it doesn't work out of the box, please note:
+
+* I haven't tested this on Cygwin or any other Windows emulation
+or native windows compilation suite. For all I know it is not
+possible to get it to work on Windows.
+
+
* Do NOT under ANY +CIRCUMSTANCES attempt to contact TMI-2
+mud personnel or TMI-2 mudlib maintainers to complain that
+this bundle is lame or to ask for help with it. It'll be like
+asking Bill Joy to come over and help you install Solaris. His
+involvement with the development of UNIX doesn't entitle you to
+help from him, and the TMI-2 people don't deserve to be
+exposed to noob brainwaves from people who think they are owed +assistance.
+
+* Perhaps the most important thing you can read is this:
+http://www.catb.org/%7Eesr/faqs/smart-questions.html
+Note that the people on that page also are not to be contacted for +support.
+
+
+Where can I get +support for TMI-2?
+
+Once it is installed, it might not be unreasonable to
+ask for advice on the imud_code line.
+
+You're also welcome to visit the LPMuds.net +discussion forum
+and chat there, but don't expect quick turnaround on your
+questions. TMI-2 experts are fewer and farther between
+than they once were, so you may have to wait a little
+for a helpful response.
+
+
+I work with TMI-2 all the time. It's not that +hard to +set up.
+
+That's true. The small driver and lib tweaks necessary to
+get TMI-2 compiled and run on a modern system aren't
+that big a deal, but it seemed like a nice thing to do anyway.
+
+Many people will still run into problems, I'm sure, but
+even for those, this should get them closer to the ballpark.
+
+
+Where can I get it?
+
+http://lpmuds.net/files/
+
+
+LPMuds.net
+
+
+ + diff --git a/lib/www/lpmuds/wireless.css b/lib/www/lpmuds/wireless.css new file mode 100644 index 0000000..6062ed6 --- /dev/null +++ b/lib/www/lpmuds/wireless.css @@ -0,0 +1,30 @@ +.catbg, tr.catbg td +{ + background-color: #6d92aa; + color: #ffffff; +} +.titlebg, .titlebg a, .titlebg a:link, .titlebg a:visited +{ + background-color: #b6dbff; + color: #000000; + text-decoration: none; +} +.windowbg, tr.windowbg td +{ + background-color: #ffffff; + color: #000000; +} +.windowbg2, tr.windowbg2 td +{ + background-color: #c0c0c0; + color: #000000; +} +.new, a:link.new, a:visited.new +{ + background-color: #2f2fc0; + color: #ffffff; +} +.updated +{ + color: #ff0000; +} \ No newline at end of file diff --git a/lib/www/lpmuds/xml_board.js b/lib/www/lpmuds/xml_board.js new file mode 100644 index 0000000..d6082ba --- /dev/null +++ b/lib/www/lpmuds/xml_board.js @@ -0,0 +1,100 @@ +var cur_topic_id, cur_msg_id, buff_subject, cur_subject_div, in_edit_mode = 0; +var hide_prefixes = Array(); + +function modify_topic(topic_id, first_msg_id, cur_session_id) +{ + if (!window.XMLHttpRequest) + return; + if (typeof(window.opera) != "undefined") + { + var test = new XMLHttpRequest(); + if (typeof(test.setRequestHeader) != "function") + return; + } + cur_topic_id = topic_id; + + if (in_edit_mode == 1) + modify_topic_cancel(); + in_edit_mode = 1; + + if (typeof window.ajax_indicator == "function") + ajax_indicator(true); + + getXMLDocument(smf_scripturl + "?action=quotefast;quote=" + first_msg_id + ";sesc=" + cur_session_id + ";modify;xml", onDocReceived_modify_topic); +} + +function onDocReceived_modify_topic(XMLDoc) +{ + cur_msg_id = XMLDoc.getElementsByTagName("message")[0].getAttribute("id"); + + cur_subject_div = document.getElementById('msg_' + cur_msg_id.substr(4)); + buff_subject = getInnerHTML(cur_subject_div); + + // Here we hide any other things they want hiding on edit. + set_hidden_topic_areas('none'); + + modify_topic_show_edit(XMLDoc.getElementsByTagName("subject")[0].childNodes[0].nodeValue); + + if (typeof window.ajax_indicator == "function") + ajax_indicator(false); +} + +function modify_topic_cancel() +{ + setInnerHTML(cur_subject_div, buff_subject); + set_hidden_topic_areas(''); + + in_edit_mode = 0; + return false; +} + +function modify_topic_save(cur_session_id) +{ + if (!in_edit_mode) + return true; + + var i, x = new Array(); + x[x.length] = 'subject=' + escape(textToEntities(document.forms.quickModForm['subject'].value)).replace(/\+/g, "%2B"); + x[x.length] = 'topic=' + parseInt(document.forms.quickModForm.elements['topic'].value); + x[x.length] = 'msg=' + parseInt(document.forms.quickModForm.elements['msg'].value); + + if (typeof window.ajax_indicator == "function") + ajax_indicator(true); + + sendXMLDocument(smf_scripturl + "?action=jsmodify;topic=" + parseInt(document.forms.quickModForm.elements['topic'].value) + ";sesc=" + cur_session_id + ";xml", x.join("&"), modify_topic_done); + + return false; +} + +function modify_topic_done(XMLDoc) +{ + if (!XMLDoc) + { + modify_topic_cancel(); + return true; + } + + var message = XMLDoc.getElementsByTagName("smf")[0].getElementsByTagName("message")[0]; + var subject = message.getElementsByTagName("subject")[0].childNodes[0].nodeValue; + + modify_topic_hide_edit(subject); + + set_hidden_topic_areas(''); + + in_edit_mode = 0; + + if (typeof window.ajax_indicator == "function") + ajax_indicator(false); + + return false; +} + +// Simply restore any hidden bits during topic editing. +function set_hidden_topic_areas(set_style) +{ + for (var i = 0; i < hide_prefixes.length; i++) + { + if (document.getElementById(hide_prefixes[i] + cur_msg_id.substr(4)) != null) + document.getElementById(hide_prefixes[i] + cur_msg_id.substr(4)).style.display = set_style; + } +} diff --git a/lib/www/lpmuds/xml_topic.js b/lib/www/lpmuds/xml_topic.js new file mode 100644 index 0000000..8ab00b4 --- /dev/null +++ b/lib/www/lpmuds/xml_topic.js @@ -0,0 +1,206 @@ +var smf_topic, smf_start, smf_show_modify, quickReplyCollapsed, buff_message; +var cur_msg_id, cur_msg_div, buff_subject, cur_subject_div, in_edit_mode = 0; + +function doQuote(messageid, cur_session_id) +{ + if (quickReplyCollapsed) + window.location.href = smf_scripturl + "?action=post;quote=" + messageid + ";topic=" + smf_topic + "." + smf_start + ";sesc=" + cur_session_id; + else + { + if (window.XMLHttpRequest) + { + if (typeof window.ajax_indicator == "function") + ajax_indicator(true); + getXMLDocument(smf_scripturl + "?action=quotefast;quote=" + messageid + ";sesc=" + cur_session_id + ";xml", onDocReceived); + } + else + reqWin(smf_scripturl + "?action=quotefast;quote=" + messageid + ";sesc=" + cur_session_id, 240, 90); + + if (navigator.appName == "Microsoft Internet Explorer") + window.location.hash = "quickreply"; + else + window.location.hash = "#quickreply"; + } +} + +function onDocReceived(XMLDoc) +{ + var text = ""; + for (var i = 0; i < XMLDoc.getElementsByTagName("quote")[0].childNodes.length; i++) + text += XMLDoc.getElementsByTagName("quote")[0].childNodes[i].nodeValue; + + replaceText(text, document.forms.postmodify.message); + if (typeof window.ajax_indicator == "function") + ajax_indicator(false); +} + + +function modify_msg(msg_id, cur_session_id) +{ + if (!window.XMLHttpRequest) + return; + if (typeof(window.opera) != "undefined") + { + var test = new XMLHttpRequest(); + if (typeof(test.setRequestHeader) != "function") + return; + } + if (in_edit_mode == 1) + modify_cancel(); + in_edit_mode = 1; + if (typeof window.ajax_indicator == "function") + ajax_indicator(true); + getXMLDocument(smf_scripturl + '?action=quotefast;quote=' + msg_id + ';sesc=' + cur_session_id + ';modify;xml', onDocReceived_modify); +} + +function onDocReceived_modify(XMLDoc) +{ + var text = ""; + var subject = ""; + + // Grab the message ID. + cur_msg_id = XMLDoc.getElementsByTagName("message")[0].getAttribute("id"); + + // Replace the body part. + for (var i = 0; i < XMLDoc.getElementsByTagName("message")[0].childNodes.length; i++) + text += XMLDoc.getElementsByTagName("message")[0].childNodes[i].nodeValue; + cur_msg_div = document.getElementById(cur_msg_id); + buff_message = getInnerHTML(cur_msg_div); + + // Actually create the content, with a bodge for dissapearing dollar signs. + text = text.replace(/\$/g,"{&dollarfix;$}"); + text = smf_template_body_edit.replace(/%body%/, text).replace(/%msg_id%/g, cur_msg_id.substr(4)); + text = text.replace(/\{&dollarfix;\$\}/g,"$"); + setInnerHTML(cur_msg_div, text); + + // Replace the subject part. + cur_subject_div = document.getElementById('subject_' + cur_msg_id.substr(4)); + buff_subject = getInnerHTML(cur_subject_div); + + subject = XMLDoc.getElementsByTagName("subject")[0].childNodes[0].nodeValue; + subject = subject.replace(/\$/g,"{&dollarfix;$}"); + subject = smf_template_subject_edit.replace(/%subject%/, subject); + subject = subject.replace(/\{&dollarfix;\$\}/g,"$"); + setInnerHTML(cur_subject_div, subject); + if (typeof window.ajax_indicator == "function") + ajax_indicator(false); +} + +function modify_cancel() +{ + // Roll back the HTML to its original state. + setInnerHTML(cur_msg_div, buff_message); + setInnerHTML(cur_subject_div, buff_subject); + + // No longer in edit mode, that's right. + in_edit_mode = 0; + + return false; +} + +function modify_save(cur_session_id) +{ + if (!in_edit_mode) + return true; + + var i, x = new Array(); + x[x.length] = 'subject=' + escape(textToEntities(document.forms.quickModForm['subject'].value.replace(/&#/g, "&#"))).replace(/\+/g, "%2B"); + x[x.length] = 'message=' + escape(textToEntities(document.forms.quickModForm['message'].value.replace(/&#/g, "&#"))).replace(/\+/g, "%2B"); + x[x.length] = 'topic=' + parseInt(document.forms.quickModForm.elements['topic'].value); + x[x.length] = 'msg=' + parseInt(document.forms.quickModForm.elements['msg'].value); + + if (typeof window.ajax_indicator == "function") + ajax_indicator(true); + + sendXMLDocument(smf_scripturl + "?action=jsmodify;topic=" + smf_topic + ";sesc=" + cur_session_id + ";xml", x.join("&"), modify_done); + + return false; +} + +function modify_done(XMLDoc) +{ + if (!XMLDoc) + { + modify_cancel(); + return; + } + + var message = XMLDoc.getElementsByTagName("smf")[0].getElementsByTagName("message")[0]; + var body = message.getElementsByTagName("body")[0]; + var error = message.getElementsByTagName("error")[0]; + + if (body) + { + // Show new body. + var bodyText = ""; + for (i = 0; i < body.childNodes.length; i++) + bodyText += body.childNodes[i].nodeValue; + + bodyText = bodyText.replace(/\$/g,"{&dollarfix;$}"); + bodyText = smf_template_body_normal.replace(/%body%/, bodyText); + bodyText = bodyText.replace(/\{&dollarfix;\$\}/g,"$"); + setInnerHTML(cur_msg_div, bodyText); + buff_message = bodyText; + + // Show new subject. + var subject = message.getElementsByTagName("subject")[0]; + var subject_text = subject.childNodes[0].nodeValue; + subject_text = subject_text.replace(/\$/g,"{&dollarfix;$}"); + var subject_html = smf_template_subject_normal.replace(/%msg_id%/g, cur_msg_id.substr(4)).replace(/%subject%/, subject_text); + subject_html = subject_html.replace(/\{&dollarfix;\$\}/g,"$"); + setInnerHTML(cur_subject_div, subject_html); + buff_subject = subject_html; + + // If this is the first message, also update the topic subject. + if (subject.getAttribute("is_first") == 1) + { + var subject_top = smf_template_top_subject.replace(/%subject%/, subject_text); + subject_text = subject_text.replace(/\{&dollarfix;\$\}/g,"$"); + setInnerHTML(document.getElementById("top_subject"), subject_text); + } + + // Show this message as "modified on x by y". + if (smf_show_modify) + { + var cur_modify_div = document.getElementById('modified_' + cur_msg_id.substr(4)); + setInnerHTML(cur_modify_div, message.getElementsByTagName("modified")[0].childNodes[0].nodeValue); + } + } + else if (error) + { + setInnerHTML(document.getElementById("error_box"), error.childNodes[0].nodeValue); + document.forms.quickModForm.message.style.border = error.getAttribute("in_body") == "1" ? "1px solid red" : ""; + document.forms.quickModForm.subject.style.border = error.getAttribute("in_subject") == "1" ? "1px solid red" : ""; + } + + if (typeof window.ajax_indicator == "function") + ajax_indicator(false); +} + +function showModifyButtons() +{ + var numImages = document.images.length; + for (var i = 0; i < numImages; i++) + if (document.images[i].id.substr(0, 14) == 'modify_button_') + document.images[i].style.display = ''; +} + +function expandThumb(thumbID) +{ + var img = document.getElementById('thumb_' + thumbID); + var link = document.getElementById('link_' + thumbID); + var tmp = img.src; + img.src = link.href; + link.href = tmp; + img.style.width = ''; + img.style.height = ''; + return false; +} + +function swapQuickReply() +{ + document.getElementById("quickReplyExpand").src = smf_images_url + "/" + (quickReplyCollapsed ? "collapse.gif" : "expand.gif"); + document.getElementById("quickReplyOptions").style.display = quickReplyCollapsed ? "" : "none"; + + quickReplyCollapsed = !quickReplyCollapsed; +} diff --git a/lib/www/mudlist.txt b/lib/www/mudlist.txt new file mode 100644 index 0000000..89595ac --- /dev/null +++ b/lib/www/mudlist.txt @@ -0,0 +1,125 @@ +2020.09.06-05.39,13 +Zebu recognizes one hundred and twenty-two muds matching your query: + +7thplane n/a IMC2 client IMC2 Freedom CL-2. 69.164.199.238 8888 +A.HEGY. LPMud FluffOS v2.23-d Dead Souls 3.8.6 89.133.33.82 1222 +Aadarian Realms DikuMU Aadaria I3 Driv ADR 5.06 (build: 1 178.79.173.99 1111 +Abandoned Codex DikuMU I3 Driver 2.40b Smaug 1.02a modifi 95.85.50.124 4000 +Adaka Coffee CoffeeMud v5.9. CoffeeMud v5.9.6 85.3.174.248 5555 +Adventurers Way Coffee CoffeeMud v5.9. CoffeeMud v5.9.10 172.105.188.166 1111 +Ara Labs Coffee CoffeeMud v5.9. CoffeeMud v5.9.10 34.86.104.52 5555 +AsYetUntitled LPMud FluffOS v2.23-d Dead Souls 3.8.6 178.62.73.229 6666 +BlackDawn LPMud FluffOS v2.28.3 BlackDawn II 45.64.56.66 1701 +Brandywine MUD Coffee CoffeeMud v5.9. CoffeeMud v5.9.9 45.33.64.28 5555 +CoffeeMud Coffee CoffeeMud v5.9. CoffeeMud v5.9.10 104.14.28.106 2323 +Core MUD LPMud MudOS v22.2b14 Colony 1.3 173.193.107.10 4000 +Covenant of Lor Coffee CoffeeMud v5.9. CoffeeMud v5.9.10 96.126.100.155 23 +Cyprus MUD Coffee CoffeeMud v5.9. CoffeeMud v5.9.9.1 173.255.218.223 5555 +DW_Clone LPMud FluffOS v2.28 Discworld 18.0a 82.68.167.68 4242 +Dark City GodWar AFKMud I3 Drive Dark City 178.79.173.99 3000 +DarkeMUD 45.52.9.106 0 +Darkness and De LPMud FluffOS v2017.2 Nightmare+DnD 155.254.17.154 4201 +Darkscapes LPMud FluffOS v2.23-d Dead Souls 3.6 84.245.8.150 6717 +Dead Souls Dev LPMud FluffOS v2.23-d Dead Souls 3.9 97.107.133.86 8000 +Dead_Souls_pyra LPMud FluffOS v2.23-d Dead Souls 3.9 69.164.194.158 4000 +Desolation LP fluffos v2019 Lima 1.0a8 155.254.17.151 8787 +Discworld LPMud FluffOS v2.28 Discworld 18.0a 82.68.167.69 23 +Disk World LPMud FluffOS v2.28.2 Discworld 17.0a 172.92.143.166 4400 +Dragon's Den LPMud MudOS v22.2b14 Dragon Mudlib 1.1 74.109.126.27 2222 +Dragon`s Lair Coffee CoffeeMud v5.9. CoffeeMud v5.9.8.5 173.255.200.146 23 +Dreath MUD Coffee CoffeeMud v5.9. CoffeeMud v5.9.8.5 23.92.27.179 23 +EmpiresEnd Coffee CoffeeMud v5.9. CoffeeMud v5.9.6 74.207.226.164 5555 +EotL LPMud Amylaar 3.2.14 LPMud EotL 98 209.216.23.199 2010 +EotL-Red LPMud LDMud 3.2.14 LPMud EotL 2019 163.172.210.70 2010 +Eye of the Worl LPmud MudOS v22.2b13 Tmi-2 1.4 50.116.55.253 2222 +FOR_NOW Coffee CoffeeMud v5.9. CoffeeMud v5.9.9 24.19.149.119 5555 +Fantastic mud LPMud FluffOS v2.23-d Dead Souls 3.8.2 217.61.6.178 6666 +Final Realms LPMud FluffOS v2.23 FRlib V 185.47.42.101 4001 +Forgotten-Gods LPMud FluffOS v2.23-d Dead Souls 3.8.6 54.172.123.224 6690 +Frontiers LPMud FluffOS v2.15-d Dead Souls 2.10 204.209.44.3 8000 +GTFO Coffee CoffeeMud v5.9. CoffeeMud v5.9.10 138.68.247.72 5555 +GreyArea LPMud FluffOS v2.23-d Dead Souls 3.9 220.253.84.210 2222 +GreyArea_DS-sto LPMud FluffOS v2.23-d Dead Souls 3.9 220.253.84.210 6666 +GronMUD Coffee CoffeeMud v5.9. CoffeeMud v5.9.10 92.242.63.65 5555 +Haven LPMud FluffOS v2.9-ds Haven 0.1 23.253.225.109 5000 +Homebound Coffee CoffeeMud v5.9. CoffeeMud v5.9.10 45.33.46.71 5555 +I3-TheMud-ORG LPMud FluffOS v2.28.3 Dead Souls 3.8.6 45.64.56.66 5555 +I3-TheMud-ORG-P LPMud FluffOS v2.28.3 Dead Souls 3.8.6 45.64.56.66 5555 +IMUD-FluffOS201 LPMud fluffos v2019.2 Dead Souls 3.8.6 110.232.112.129 1701 +Iberia MUD IME IME IME v0.9975 2.81.180.125 5900 +Indigo Coffee CoffeeMud v5.9. CoffeeMud v5.9.10 87.229.53.104 5555 +InfectedMinds Coffee CoffeeMud v5.9. CoffeeMud v5.9.10 73.245.13.171 5555 +Itinerantion LPMud FluffOS v2.23-d Dead Souls 3.8.6 108.173.162.164 6666 +KellerMUD Coffee CoffeeMud v5.9. CoffeeMud v5.9.6 104.237.155.126 23 +LPM LPMud FluffOS v2.23-d Dead Souls 3.8.6 18.218.123.244 6666 +Mansocks World LPMud FluffOS v2.23-d Dead Souls 3.8.2 68.68.95.221 6666 +MoH GodWar AFKMud I3 Drive MoH3.0 178.79.173.99 3500 +Muda Coffee CoffeeMud v5.9. CoffeeMud v5.9.10 86.110.43.195 5555 +Multiverse MUD Coffee CoffeeMud v5.9. CoffeeMud v5.9.9.1 45.33.61.54 5555 +Mundo Sangre Coffee CoffeeMud v5.9. CoffeeMud v5.9.10 23.239.11.138 5555 +Mystic LPMud MudOS v22.2b14 Realms of Mystic L 45.79.130.170 3000 +Nanvaent LP NANVAENT 3 (Flu Nanvaent V.4ish 207.162.200.121 3000 +Navigate LPMud FluffOS v2.23-d Dead Souls 3.8.6 216.136.9.5 2123 +Nightfall LPMud LPMud 3.5.0.2 ( NF 212.83.56.217 4242 +Northlands Coffee CoffeeMud v5.9. CoffeeMud v5.9.9.1 178.79.160.71 5555 +Nuke II LP fluffos v2019.2 Lima 1.0b5 173.255.201.173 4080 +Nygaard MUD Coffee CoffeeMud v5.9. CoffeeMud v5.9.8.5 172.105.9.226 5555 +OASIS MUD Coffee CoffeeMud v5.9. CoffeeMud v5.9.9.1 51.91.251.230 5555 +Occulte LPMud FluffOS v2.15-d Discworld 17.0a 199.74.141.8 6677 +OglafMUD LP fluffos v2019.2 Lima 1.0b5 86.52.128.42 7878 +PLEXUS LP fluffos v2019.2 Lima/PLX 0.4 86.52.128.42 4242 +Paradigm MUD Coffee CoffeeMud v5.9. CoffeeMud v5.9.8.5 45.79.73.28 5555 +Planstudio Dung Coffee CoffeeMud v5.9. CoffeeMud v5.9.5 80.210.98.67 5555 +Pluto MUD Coffee CoffeeMud v5.9. CoffeeMud v5.9.8.5 172.105.37.194 5555 +Pocket Steam Coffee CoffeeMud v5.9. CoffeeMud v5.9.10 192.81.133.184 5555 +Portals Inbetwe Coffee CoffeeMud v5.9. CoffeeMud v5.9.9.1 45.33.50.126 5555 +Randy Stadham Coffee CoffeeMud v5.9. CoffeeMud v5.9.6.4 104.237.152.181 23 +Realm of Cernun Coffee CoffeeMud v5.9. CoffeeMud v5.9.4 50.105.123.230 5555 +Realm of Shadow DikuMU I3 Driver 2.40b Smaug 1.4a 24.9.9.201 1133 +STiNKBoMB LPMud DGD 1.6.2 GurbaLib v0.50 84.197.184.69 4000 +Second Contract LPMud FluffOS v2.23-d Dead Souls 3.6 54.84.108.226 6666 +Senitan Online LPMud FluffOS v2.23-d Dead Souls 3.8.6 71.72.126.17 6666 +ShadowMUD LP FluffOS v2.28.2 Nightmare/ShadowLi 199.74.141.8 1030 +ShadowMUDii Dev LP FluffOS v2.28.2 Nightmare/ShadowLi 199.74.141.8 1035 +SingularisMUD LP FluffOS v2017.2 Skylib 1.8 46.251.35.104 8888 +SirdudesGurbaLi LPMud DGD 1.6.13 GurbaLib v0.50 174.53.232.12 4000 +Somavos Coffee CoffeeMud v5.9. CoffeeMud v5.9.9 23.92.30.29 4242 +SpesMUD Coffee CoffeeMud v5.9. CoffeeMud v5.9.9 45.79.100.63 5555 +Star Wars: Jedi SWR AFKMud I3 Drive SWJvS 1.4.1 24.222.84.75 8707 +Swashbockle MUD Coffee CoffeeMud v5.9. CoffeeMud v5.9.8.5 45.33.42.13 5555 +THOTconMUD LPMud DGD 1.6.11 GurbaLib v0.50 64.227.62.127 4000 +Tales of Aeril Coffee CoffeeMud v5.9. CoffeeMud v5.9.9 45.33.10.116 5555 +Testlandia LPMud FluffOS v2.23-d Dead Souls 3.9 54.88.224.206 6767 +The Beast Withi Coffee CoffeeMud v5.9. CoffeeMud v5.9.9 45.33.109.237 5555 +The Brass Ring LPMud FluffOS v2.23-d Dead Souls 3.9 96.244.229.21 2150 +The Chronicles LPmud fluffos v2019.2 Meridian v0.1 78.90.77.217 7878 +The Library LPMud FluffOS v2.23-d Dead Souls 3.7a7 65.19.167.66 6666 +The Open Door Coffee CoffeeMud v5.9. CoffeeMud v5.9.8.5 50.116.13.244 5555 +The Rifthome MU Coffee CoffeeMud v5.9. CoffeeMud v5.9.10 46.4.48.195 5585 +The Savage Soul LPMud FluffOS v2.23-d Dead Souls 3.7a7 173.255.210.234 6666 +The Zone LPMud DGD 1.4.1 WOTFlib 0.90 136.144.155.250 8888 +The Zone-Kelly LPMud DGD 1.4.1 WOTFlib 0.90 136.144.155.250 8888 +The Zone-dalet LPMud DGD 1.4.1 WOTFlib 0.90 136.144.155.250 8888 +The Zone-i4 LPMud DGD 1.4.1 WOTFlib 0.90 136.144.155.250 8888 +The Zone-wpr LPMud DGD 1.4.1 WOTFlib 0.90 136.144.155.250 8888 +TimMUD LPmud FluffOS v2.28.3 Tmi-2 1.4 104.154.76.197 5555 +UberMud Coffee CoffeeMud v5.9. CoffeeMud v5.9.8 54.202.46.66 5555 +Ukiyo Coffee CoffeeMud v5.9. CoffeeMud v5.9.8 212.56.108.81 5555 +Universes LPMud MudOS v22.1 UniLib 1.0a 108.252.255.105 3333 +Unnamed_CoffeeM Coffee CoffeeMud v5.9. CoffeeMud v5.9.10 34.238.162.229 5555 +WarofLegend DikuMU AFKMud I3 Drive WoL 10.26 (build: 178.79.173.99 4200 +Waterver Dev LPMud fluffos v2019.2 Dead Souls 3.9 71.246.228.190 6666 +Waterver_Dev n/a IMC2 client Tim's LPC IMC2 cli 71.246.228.190 6666 +Way of the Forc LPMud DGD 1.2.157-WOT WOTFlib 0.90 136.144.155.250 23 +WayPoint Coffee CoffeeMud v5.9. CoffeeMud v5.9.8 74.208.214.165 5555 +WileyMUD DikuMU I3 Driver 2.40b WileyMUD III 2.123 172.92.143.166 3000 +World of Clouse Coffee CoffeeMud v5.9. CoffeeMud v5.9.10 167.172.140.125 5555 +Worlds Of Wonde LPMud FluffOS v2.23-d Dead Souls 3.8.2 144.217.205.176 2500 +Wunderland LPMud LDMud 3.3.720 WL-Lib 139.18.11.86 23 +Your MUD Name Coffee CoffeeMud v5.9. CoffeeMud v5.9.10 45.33.51.250 5555 +Zebu LPMud FluffOS v2.23-d Dead Souls 3.9 50.34.196.5 6666 +Zenith LPMud FluffOS v2.23-d Dead Souls 3.9 47.12.102.26 4201 +doomsday Coffee CoffeeMud v5.9. CoffeeMud v5.9.8.1 94.189.246.51 7000 +lpcdb LPMud DGD 1.5.4 lpcdb v1.0 alpha 2 136.144.155.250 4000 +lpcdb-dev LPMud DGD 1.5.5 lpcdb v1.0 alpha 2 87.209.243.234 4000 +savageisle Coffee CoffeeMud v5.9. CoffeeMud v5.9.6 23.25.8.124 5559 \ No newline at end of file diff --git a/lib/www/news.html b/lib/www/news.html new file mode 100644 index 0000000..7765ef8 --- /dev/null +++ b/lib/www/news.html @@ -0,0 +1,1227 @@ + + + + Dead Souls News Page + + + + + + +
+
+
+
+
+
The +Dead Souls News +Page
+
+
+

+11 September 06
+
+News
+
+    I'd like to start announcing things on the http://lpmuds.net
+site. It's less painful for me, and plus people can respond
+with questions.
+
+    So, from now on, please visit here +to see Dead Souls News.
+
+Hosting
+
+    The hosting situation is a bit +confusing. Maybe this will
+explain things a little:
+
+Saquivor@Eternal Souls +<lpuni> whats up with lpuni.net dudes
+Cratylus <lpuni> ok here's the deal
+Cratylus <lpuni> tacitus was going to host on kyndig, because he +was sick of trenden
+Cratylus <lpuni> i said no let's try something else, and hooked +him up with wolfpaw
+Cratylus <lpuni> i happened to own the lpuni.net domain from +before, so i put it on lpuni's new wolfpaw account
+Cratylus <lpuni> so the New Lpuni was using lpuni.net, and the +old one still used lpuni.org
+Cratylus <lpuni> then tacitus changed his mind about wolfpaw and +decided to use trenden after all
+Cratylus <lpuni> so he removed the stuff from the wolfpaw account +
+Cratylus <lpuni> i figured "well, it's a shame to let a perfectly +good hosted
+account go to waste"
+Cratylus <lpuni> so i decided to move lpmuds.net to wolfpaw
+Cratylus <lpuni> however, wolfpaw hasn't updated the host/ip +thing yet, so lpmuds.net isn't on there yet
+Cratylus <lpuni> the only way to reach what-will-be-lpmuds.net +right now is lpuni.net
+Cratylus <lpuni> the end
+Cratylus <lpuni> oh, and lpuni.org is down because they broke +trenden's
+machine somehow, so they have to find hosting elsewhere
+
+
+09 September 06
+
+    Tacitus has decided not to accept Wolfpaw's generous
+hosting offer, even though I'm the one paying for the
+service. He's sticking with Trenden, and I wish him
+the best.
+
+    That leaves me, of course, with a professionally
+hosted account on Wolfpaw to play with, so I've been
+messing around a little with forum software. To my amazement,
+I got a forum up and running with very little effort.
+
+    Unfortunately, right this minute, the only URL
+bound to it is lpuni.net, +but as soon as
+Wolfpaw changes the hostname stuff it'll be available
+at lpmuds.net.
+
+
+05 September 06
+
+    hotfix +update
+
+    Zaphod@Hodge Podge found a security flaw in +admintool. Please
+visit the hotfix page +and update your admintool file ASAP. Note
+that I always thought it was a bit silly to encre/decre with the
+admintool, so I've simply removed it. From now on, just use the
+commands
when promoting/demoting someone.
+
+
+30 August 06
+
+alpha code
+
+    I've decided to make alpha code available for +download.
+Having others poke at my code before official releases might
+be nice, and I want to see if that's a workable model for
+doing things. Alpha code will not come with patches...that
+is, if you want to try out alpha code, you have to download
+the whole deal, not upgrade from previous versions.
+
+    This is because I don't want people to apply alpha
+patches to their production muds and then flip out because
+the alpha code doesn't work right.
+
+    If that suits you, you can download from: http://dead-souls.net/code/alpha/
+
+distribution packages
+
+    The default 2.0r26 and 2.1 package files have changed
+somewhat. They now have a "b" added to the filename to
+reflect this change. Basically, each distro is as it was,
+except that intergossip and intercre are no longer
+enabled by default for creators.
+
+    It's a minor change, and I didn't want to go through +the
+hassle of a whole new version change for this one thing, so
+I expect the filename change will suffice to let people
+know...if they even care.
+
+    The change is due to the situation on the router. +I've been
+absolutely loath to start banning people or muds, except
+where I just have no other alternative. In removing these
+two channels as default, I feel I have performed my due
+diligence in avoiding newbies getting trashed or offended
+on the yatmim router.
+
+    It's a unique situation, in that many of the +"offenders"
+that have been causing problems on the router seem to
+be genuinely unaware of the rules, and sometimes even
+unaware of the router not being the same as the old one.
+I just don't have time to educate every ignoramus who
+gets offended when I call them on their behavior, and I
+just don't have the heart to punish entire muds just because
+a few nincompoops can't remember where they are.
+
+    This doesn't mean it's open season now on newbies
+found on intergossip and intercre. It just means I
+don't have to shepherd every new mud through the
+gauntlet...something I, again, just don't have time for.
+
+    Also there's a new channel enabled by default for +creators on
+new muds called "dchat". To join, type: call me->AddChannel("dchat")
+
+
+25 August 06
+
+other-lib compat
+
+    This isn't something I've announced with great +fanfare,
+so I thought I'd give it a mention here. I'm working on lib
+compatibility systems. The idea is that I'd like it to be
+possible for people who have old areas they wrote for other
+muds to be able to use those areas in DS with minimum pain.
+    There are two main ways to accomplish this:
+
+1) A translation system to turn old code to DS code
+2) An interpretation system to read old code and use it as if it were +DS code
+
+    The first one is rather easier to do. I've put +together
+some lsed scripts that can be run to transmogrify Nightmare 3
+code into Dead Souls 2 code. You can see this script in
+/secure/scripts on the demo mud.
+    I've already translated Praxis from NM3 into DS2 +code.
+You can log onto +the demo mud and check out /domains/Praxis
+for yourself. I'm done with the basics there, and will be
+seeing about getting the fancier stuff in there working.
+
+    The second one is harder. Getting funky old +TMI-2/NM3/Skylib/LPUni*
+code to work natively on DS is a tall order. I've put together
+a header file called compat.h which is enabled with the new
+COMPAT_MODE define in config.h. This enables the lib to
+read things like set_property as SetProperty, etc.  You
+can read this file on the demo mud, as /secure/include/compat.h
+
+     Even with that file, some of the scary old +habits of
+TMI-2 code break things. For example, there's no good way to
+make set("foo","bar"); into SetFoo("bar"); using a preprocessor
+define that I know of (please tell me if I'm wrong!). To get
+around this kind of behavior, I've added a new sefun file:
+/secure/sefun/legacy.c
+
+    That file takes the hypergeneral contructors like +set(),
+add(), and query(), and parses them into code DS2 can more
+properly understand. It's not a foolproof fix, but it's working
+pretty well for a lot of objects.
+
+    You can take a look at working TMI-2 code on the demo
+mud in /domains/Fooland. The majority of stuff there still doesn't
+work....it's still a work in progress. But type: goto /domains/Fooland/hall
+and: lightme 30 and about here and you'll see for +yourself that TMI-2 code
+*can* work on DS2. Sometimes it'll just work, sometimes it needs
+minor adjustments, but at least you won't have to do a drastic
+rewrite of every file in your old domain.
+
+    Don't get me wrong, you obviously have a lot of work +to
+do if you're going to migrate to DS2 from another lib. Your
+paths will be different, you may need to add some lines or remove some.
+The idea isn't to have 100% drop-in compatibility with other libs.
+
+    I mean, heck, you can't even do that with many muds
+running the same +lib.
+
+    No, the idea is to facilitate your migration. I want +DS2 to be
+a kind of Rosetta Stone for MudOS, a lib that people can use and
+refer to in a way that is as close to MudOS lib agnostic as possible.
+
+    Of course, DGD or Cold or other driver based libs +are beyond
+the scope of my expertise. Maybe I can tackle those once we
+have a unified MudOS paradigm.
+
+    I don't expect to be able to do this for all MudOS +libs,
+either. Lima, for example, is so weird that I don't even know if
+it's possible. The example objects and areas aren't enough for
+me to base a translation engine on...so if you have a Lima
+area you're not using, please donate it so I can us it as a
+base for translation.
+
+    Remember, this is *NOT* +in the regular distribution. Don't
+try to get your old code to work on ds2.1. These capabilities
+are currently (mostly) only available on the demo and devel muds.
+    Compat features will be more generally available in +the next release.
+
+*I'm +told that LPUni code is not TMI-2, it has "TMI-II compatability (sic)"
+
+
+23 August 06
+
+Releases:
+    I am really getting comfortable with not having to +release
+stuff every five minutes. Yet...I'm starting to feel like I'm
+hoarding goodies, +and that's not nice. So I'm going to work
+out some sort of release schedule soon, so I can at least
+have a target date to miss. :)
+
+Connection page:
+    I added a connection page +to make it easier for the
+casual visitor to the Dead Souls site to log into the demo
+mud and check it out for themselves. I know the java client is
+ugly, but it has the virtue of working well. If you know
+of another java client that works +(believe me I've played
+with the mudmagic one and others and have not gotten them
+to behave) please let me know.
+
+LPUni:
+    There has been recent turmoil +in the LPUni community
+about the prospect of moving the site onto a server run
+by Kyndig. Dale at Wolfpaw has come to the rescue and offered
+a hosting package that I think is acceptable to everyone.
+
+    I don't think Wolfpaw will be able to rival Kyndig's
+customer service for a couple of reasons. First, Dale doesn't
+do it as his primary job, so there will necessarily be some
+lag between service requests and action. Second, Dale doesn't
+have anything to prove. I suspect that Kyndig was Mr. Johnny-
+on-the-spot for Tacitus because he wanted to demonstrate stellar
+support, in order to facilitate the decision to have LPUni
+move there. For Tacitus the choice was a no-brainer. With
+support requests handled within minutes of filing them, and
+FREE service besides, well, it's a done deal right there...
+unless you actually care about the moral aspects of entering into
+a pact with Kyndig, which I did.
+
+    My thrust is that folks shouldn't expect the kind of
+lightning-fast service Kyndig was providing in order to prove
+a point. Wolfpaw is a solid hosting solution, solid enough to
+handle mudconnector.com, which is the premier mud resource
+site. Having to wait a day or two for service requests on
+our discounted hosting package is part of the price we will
+pay for keeping our hands clean.
+
+    If none of that stuff made sense to you, you probably
+don't know about the Kyndig situation, and really, you're
+not missing anything. It's a big dumb political brouhaha
+that you're just as well not knowing about.
+
+    I've received some threats about being nominated for +an
+LPUni council position. Please note that I feel I am already
+participating to the best of my ability in the LPUni
+community, and me being in such a council would not have the
+effect folks think it would. Please don't bother
+nominating me. Thanks.
+
+
+10 August 06
+
+    Ok. That wraps it up for the load testing. My
+fears were largely unfounded. I fired hundreds of playerbots
+into a mud running on Linux on a 1.2GHz laptop with .5 gig ram.
+The bots are created by an AI routine that telnets to the
+target mud, automatically creates a character, and then
+walks around the mud, picking things up, picking fights
+with orcs, and doing typical player things. They were coded
+to avoid idleness of more than 4 seconds, though a few
+malfunctioned due to unexpected stimuli.
+
+
+The results:
+
    +
  • Around 300 players, a slight lag could be found, if you were +looking for it.
  • +
  • Around 400 there was a minor lag.
  • +
  • Around 500 there was definite lag, as in "you could not miss +this" type lag. However, I remember playing on a mud back in the day +which had heavier lag with just 30 players on.
    +
  • +
  • Around 600 players there was undeniably heavy lag. Most commands +ran in under 1 second, but some took a few seconds to complete, and +some errored out because the mud was too busy.
  • +
  • Around 700 players the mud was in definite "I'd rather not play +here" mode. Most commands ran in under 2 seconds, but some took several +seconds to complete.
  • +
+
+   These tests have proven very valuable in shaking out
+bugs I would not have spotted otherwise.
+
+   I got as far as 710 players before running the tests
+started to get inconvenient for me (the bot generation process
+is a bit awkward). At this point I'm satisfied that if
+people run into a performance bottleneck when using Dead Souls
+it is *not* due to the base lib or MudOS efficiency.
+
+    The news, therefore, is good for people running Linux
+on modern PC hardware. Even if your mud becomes the busiest in
+non-commercial mudding history, the software will keep up with you.
+As for bandwidth and clean area coding, that's on you.
+
+    The news for Windows users...not so good.
+
+    I don't know why, but it seems that you can't
+get more than 64 (or so) players logged on simultaneously
+to a Windows DS mud.
+
+    It's possible that recompiling MudOS for Windows
+using Cygwin fixes this, but I don't know for sure and
+I will not be testing that in the near future. If
+you're running DS on windows and you really +really need
+to be able to have more than 64 players on at once
+right away, let me know and we'll discuss your options.
+    Otherwise, I'm shelving that for now.
+
+    Someday I'll have a newer PC to play with and
+I'll shoot for the 1024 player barrier. But that day
+is not today. 
+   
+
+09 August 06
+
+    I'm just about done playing with load testing.
+The results have been fascinating, because I've
+just never had occasion to review data from "too
+many players" problems.
+
+    The bad news is that MudOS is coded using many
+f*()'s, which limits the use of file descriptors
+in most cases to 255. Determining whether this is
+the obstacle it *looks* like will be a task for
+the future, as I need more time and beefier computers
+to extract the results I need and perform the
+tests I want.
+
+    At some point last night I did an
+eval return sizeof(users()) and I got the staggering
+value of 407. However, there were errors all
+over, and the mud was, for all practical purposes,
+unusuable. It's not clear to me how far it'll
+go and still be usable in any way. I'm actually
+wondering if I hallucinated that because I
+haven't been able to reproduce it since.
+
+    Anyway, that's the bad news. Right now you
+can't have a ludicrous number of players on
+simultaneously.
+
+    The good news is that you can have a large number
+ of players on simultaneously. I've set it
+up so that my development mud (not the demo mud)
+has 160+ players at all times. This is to see
+what it's like to conduct business on a very,
+very busy DS mud. So far the lag is so minor as
+to be easily ignored.
+
+    The system is a bargain basement beige box
+running an 800MHz Duron with a gig and a half
+of ram. Even with all those players bumping around,
+the process hovers around 40% cpu, and the amount
+of ram used is 81 megs. My guess is that with a
+3G proc and above, running on modern (eg not
+2002) hardware, you'd have scant chance of noticing
+200+ players, except for all the dying and
+shouting of course.
+
+    Take a look if you'd like, by telnetting to
+rugose.com port 5050. Note that it's just a
+cable modem, and I use it for all my net traffic,
+so whatever lag you get is 90% network-based.
+
+
+07 August 06
+
+    In order to load-test DS, I've coded a playerbot
+object that telnets to the test mud and does
+typical player things: pick things up, wear them,
+wander about, open doors, etc. It does something
+at least once per 5 heartbeats, so it's quite a
+noisy thing.
+
+    I also coded it to permit the rapid loading of
+many of them at once. The idea is to know what
+kind of bugs await me at the 200+ player threshold.
+
+    The results are interesting, and rather better
+than I expected. On a half-broken, 512Mb ram,
+p3 1.2GHz laptop, I can run 180 of these busy little
+guys with no noticeable lag.
+
+    Around that point, though, I start hitting
+some weirdness. It doesn't involve "performance",
+quite. It's more a matter of the existing systems not
+really being set up to handle 100 objects
+each with a separate short description in one room.
+That sort of thing. It's encouraging, though, that
+the problems I'm running into don't involve
+capacity, so much as tweaking functionality.
+
+
+02 August 06
+
+Intermud:
+    I've received some negative feedback from the
+DS community about the participation of muds from
+the old gjs router on our new yatmim. Intergossip,
+which used to be mostly PG-13 if not PG is now
+edging toward an R rating.
+    I don't like it much, myself, because it tends
+to deter some people from participating, and the
+point of the router is participation.
+    However, I feel bound by the rules I set down,
+and by the spirit in which I developed them. The
+idea is to foster community and support. My idea
+of community is not the only one, nor is it necessarily
+the correct one. I am reluctant to take it upon
+myself to dictate that only happy talk is permitted.
+    I am committed to preventing abuse of newbies
+from happening on the 5 default DS channels, and
+I will be strict in enforcing the rules outlined
+on the router rules page. But I am loath to try to
+enforce politeness, because frankly I don't think
+I have the time or energy for it.
+    I made yatmim a public router because I felt
+that it was a good idea to avoid a stagnant,
+insular atmosphere on intermud. I'm still confident
+I made the right choice, and unless things get out
+of hand, I will continue to enforce the rules as I
+have been.
+    However, if what I start to see is a hostile,
+counterproductive atmosphere, I will interpret this
+as against the intent of the channels, and will
+feel unpleasant obligations.
+
+RELEASE_NOTES:
+    After some thought, I've decided to share the
+RELEASE_NOTES of the +unreleased 2.1r* versions. This
+doesn't mean any releases are coming anytime soon.
+    The idea is that I'd like folks to see that
+their bug fixes and requests are being addressed,
+and not just falling into a black hole.
+    I also want people to know DS development
+continues, even though the release schedule is
+dramatically slowed.
+
+    For those asking "why not just make releases
+like before?", the reason is that the packaging
+process is a very time-consuming one. It also tends to
+make it difficult to work on long-term projects, because
+every little thing has to be wrapped up and clean.
+    This way I can have a big, messy, sprawling
+lib that lets me work on a piece here and a piece
+there as I see fit without worrying about having
+all the moving parts working right away.
+
+    The changes in the release notes will sometimes
+be reflected in the demo mud, and sometimes not.
+Don't expect always to see the latest nifty
+thing show up on the demo mud when you see it on
+the release notes, but you should see it there eventually,
+when I do my periodic (sometimes piecemeal) porting.
+
+LPU:
+    It looks like Tacitus is more or less retiring
+from his role as admin of LPUni. I don't know anything
+more about it that you guys, so I have no special
+insight as to where things are going with LPUni.
+    However, it would be sad if it went away, because
+the forums and Wiki do seem to be a great benefit
+to the DS community, and potentially to the LP
+community at large.
+    I hope that even if Tacitus is not able to play
+as active a role in the management of the site as
+he used to, that he leaves it up for the community
+to use as a resource for communication.
+
+
+
+28 July 06
+
+    Added a reaper fix to the fixes page.
+
+    I've completed the new doctool system, and have
+begun plowing into the lfun documentation gap. To see
+what the lfun docs will look like, log into the
+demo mud and poke through the files in /doc/lfun .
+Please note that the demo mud is not where I write
+the docs, so if it looks like the list isn't getting
+bigger, it has nothing to do with the amount of
+documentation I'm producing. I copy over to the demo
+mud as I remember to do so.
+
+    I've also added the Praxis domain to the demo
+mud, so you can review the code. Remember it is still
+not completely ported, and even when it is done, it
+will not be "production quality" stuff. It's just
+a sample of what Dead Souls/Nightmare used to look like.
+
+    Please remember that Dead Souls is made stronger
+by word of mouth. The more people try it, then the more
+people will adopt it, and the more work happens on it, and
+the better it becomes.
+
+    You can contribute to this cycle by replying to
+any of the following forum threads as you see fit:
+
+
+http://mudconnector.com/discuss/discuss.cgi?mode=REPLY&area=promotions&message=15115
+
+http://www.topmudsites.com/cgi-bin/ikonboard/ikonboard.cgi?s=44ca0daf3613ffff;act=ST;f=14;t=535
+
+
+    Your contribution to keeping Dead Souls on the front
+burner of mud discussion is vital in widening the public
+awareness of it. Even just a one-line opinion, "It rocks" or "It sucks"
+is helpful. Just post something!
+
+
+25 July 06
+
+    I've added a General/Minor Fixes page +to handle
+bugfixes that aren't critical to security or functionality.
+
+    I want to keep such minor bugfixes separate from
+hotfixes, which are meant to be important, and shouldn't
+get buried under the clutter of numerous small corrections.
+
+    I also don't intend to get sucked into frequent patch
+level releases, so that fixes page is where folks should
+expect to find their "upgrades" for a while. Please run
+diffs against the files in http://dead-souls.net/code/fixes/
+if you want to know what's changed.
+
+
+24 July 06
+
+    Well, I appear to have lost my mind. I'm
+advertising +for builders. And, in what I suspect
+is an unprecedented display of utter shamelessness,
+I'm making an open plea +for someone to give me their mud.
+
+    Well, read the +article in its entirety to
+understand the motivation.
+
+    Whether this fails or succeeds, I think it'll
+work great for me. If people do sign up and/or
+I get a dead mud to revive, it'll advance my sinister
+agenda of world domination.
+
+    If both pleas go unanswered, I'll be able to
+devote my time only to the current DS projects.
+
+    I'm honestly not sure which I'd prefer. Let
+the Fates decide.
+
+
+19 July 06
+
+    Porting other LP mudlibs to Dead Souls is
+rather more of a pain in the neck than I'd realized,
+but I'm making good progress, I think.
+
+    I have about 85% of the Nightmare 3 Praxis
+area ported over. The monsters don't work yet, but
+the rooms seem quite stable. To take a look
+around, telnet to the dev (not the demo) mud
+at rugose.com 5050, open the +reception room door,
+go north, then go west 5 times, then go north into
+the campus stargate lab. Type: dial +praxis,
+then type: enter gate. Don't +forget your way back
+to the gate after wandering in Praxis.
+
+    The dev mud does not +auto-wiz you. Don't be
+surprised that you are not a Creator.
+
+    On a separate note, Tyche's rudeness has
+given me an excellent opportunity to explain my
+side of the licensing disagreement, which
+I have attempted to do here:
+
+http://www.mudconnect.com/discuss2/discuss.cgi?mode=MSG&area=promotions&message=15678#15678
+
+    I encourage everyone to chip in with their opinion,
+as I'm very interested in knowing what the DS
+community thinks of the situation.
+
+
+15 July 06
+
+    So evidently some GPL militant informed on
+me to Sourceforge, and they've asked me to comply
+with OSS or remove my project.
+    I gave it some thought, and decided to follow
+their "formerly OSS" policy, leaving an older,
+GPL version of Dead Souls available for download,
+and removing the newer stuff. Probably this will
+satisfy nobody but me. But given how some people
+have been approaching the subject, I'm disinclined
+to try to please anyone else with DS licensing.
+    Sourceforge web maintenance stuff is down,
+but as soon as it comes back up I'll fix the
+project page to reflect the New Way.
+
+   On a brighter-still note, very few complaints
+or bug reports have surfaced since the release of
+Dead Souls 2.1. W00t!
+
+    As mentioned before, please don't expect
+patches or upgrades anytime soon. Please operate
+as if DS development is over. It isn't, and I
+will be developing new stuff, but it would be
+unwise for you to operate in expectation of it.
+
+
+12 July 06
+
+    As I suspected, someone has flown into a
+tizzy over my revocation +of GPL. Their rant is
+a perfect example of the sort of vitriol that
+made me choose to do that in the first place.
+Have a look at the discussion here.
+
+    The 2.1 release is going a little slower than
+I expected. I've gotten a case of the "perfects",
+and I keep going over and over things to make
+sure it's all ok.
+
+    We're still on track for "sometime this week."
+
+    UPDATE: +W00t! I can't tell you how relieved
+I am to be done. Dead Souls 2.1 is now available
+for download from the front page.
+
+    If you find bugs, please tell me about it, but
+also expect a slower schedule for the release of
+patches. I need a break.
+
+    Patches to upgrade to 2.1 will be available
+later today or tomorrow, as will be diffs.
+
+
+11 July 06
+
+    I've disposed of all the items in the todo
+list of July 7. There is nothing wrong with
+the stargate. The example file has been renamed
+to avoid confusion, and to avoid it accidentally
+going live on the stargate network.
+
+    I've killed the bugs found by the playtesters
+in the past few days, and unless something major
+happens, Dead Souls 2.1 will be released this week.
+
+
+10 July 06
+
+    Things are going just great. At this point,
+the number and type of bug report coming in is
+such that I'm running out of things to do. I
+need playtesters, so please, if you get a chance,
+log into rugose.com 6666 and +beat on that mud.
+Let me know what bugs you find. Thanks!
+
+    Oh, by the way, 2.0r29 is out. +We're getting
+closer and closer to 2.1! +W00t!
+
+
+07 July 06
+
+    A really surprising thing happened today. I
+decided to reorganize my .plan file and remove
+anything that wasn't either an important feature
+enhancement or a bugfix. I wanted to know *exactly*
+how close I am to releasing Dead Souls 2.1.
+
+    After slogging through and tearing out pages
+of wishlists and maybes, this is what was left:
+
+- fix /obj/stargate
+- update colors with %%^^ data
+- verbify force
+- can't delete glass case?
+- are people defaulting to the start room?
+- sell machine to cat
+- make an npc's living body go away BEFORE the corpse is moved into the +room
+- make channels understand ) after : can have non emote messages after
+- SetMaxHealth shouldn't need to be in init()
+- help area
+- help newbie
+- apostrophes
+- add damage types to dummy
+- intergossip logging to two files?
+- review setinventory, is addstuff necessary?
+- Beggar says in English, "Hi, A mangy little rat."
+- shop in the town is confusing the maglite with the cheap one.
+- If a piece of gear is set for a "left foot" attribute, why can I also +wear it on my right foot?
+- the handbook says that its easier to kill things as a mage,
+- bug: cp sefun.c  /
+- delete mfinger
+- SetEmptyName(), SetEmptyLong() and SetEmptyShort().
+- install faq: if compile problems, try as root, try non 64bit amd
+- wipe the unused tc's
+
+    That's it. Now compare the size of this list with
+the size of stuff in the release +notes. That's how close
+I am. I was shocked.
+
+    So folks, I need your help. Any bugs that have been
+bothering you but you haven't gotten around to telling me,
+this is the time. If you feel like knocking about the code
+trying to break stuff, please log into the demo mud
+at rugose.com 6666 and have at +it.
+
+    It's ok that you'll make the list longer. That's
+what I *want*. I want to get these bufixes as over with
+as possible.
+
+
+06 July 06
+
+more update news:
+
+    I overlooked a couple of important things when
+I released 2.0r27. They have been addressed in
+2.0r28.
+
+    There may be a compat buster here. One of the
+things that needed fixing was a peculiar bug that
+would generate extra corpses under unusual circumstances,
+during combat. This bug had some relationship to
+another combat bug that prevented the accurate
+recording of a player's deaths.
+
+    In the end, the fixes for these two involved the
+manipulation of persistent player variables. The
+good news is that things now seem to work just fine,
+and the bugs are seemingly gone.
+
+    The bad news is that since new player variables
+are involved, you may find that test chars created
+before an upgrade to r28 do weird things in combat...
+like not fight.
+
+    The fix is to create new test chars.
+
+    If Dead Souls was widespread enough that that
+there were muds out there that were open, with players,
+I'd look into some sort of system for updating
+older player files. Since this is not the case,
+I expect that people will be able to tolerate this
+minor inconvenience with minimal discomfort.
+
+
+
+05 July 2006
+
+router news:
+    The gjs router has been down for a week now, and
+we may see some refugee muds start to make their
+home on our router, yatmim (which by the way, stands
+for Yet Another TMI Mud, which is how the router
+started out. It's a DS mud now.) Yatmim is public and
+so all are welcome, but there are some rules folks
+need to abide by. The point of yatmim was to have
+a reliable router for DS muds, but also one where
+new people wouldn't be afraid to ask for help.
+
+    Please see the new router rules page +for more info.
+
+update news:
+    Version 2.0r27 is out. I'm ever grateful to the
+folks who find problems and report them...without
+their help Dead Souls would take much longer to
+get where it's going. Thanks, guys.
+
+    It probably still has a bug or two, specifically in
+message boards. As usual, hotfixes will be posted
+on the hotfix page. As +usual, please let me know what
+bugs you find.
+
+    One of the new features in r27 is that the install
+process will now work on Wolfpaw servers, so you folks
+staying away because you couldn't get it to work, come
+on in. The water's fine. Just be sure to run make -j 1
+instead of just make.
+
+    For those uncomfortable with frequent patching,
+please be aware that it isn't absolutely necessary.
+See the patch +article for more details.
+
+    Note that for those unwilling to follow the
+standard patch procedure, diffs are being made
+available here.
+
+LPUni news:
+    Tacitus has made some improvements to the front page.
+Let's hope he keeps that up and fleshes out the rough
+draft we see today.
+
+    He has also set up a "mud farm", with various LP
+lib flavors running. Take a look in particular at the
+Dead Souls 1.1 mud he's hosting. It should be interesting
+to see how different it is from DS2. The address is:
+lpuni.org 6501
+
+
+Sourceforge news:
+    In case you haven't noticed, I'm relying less
+and less on Sourceforge. They're great and everything,
+but lately they've been down a lot, and it made me
+realize I'm depending on them for stuff I can do
+myself. The download stats are totally misleading,
+and all their fancy project management stuff is just
+a waste on me.
+    So you can pretty much figure on releases and
+patches showing up here first and more often than
+on Sourceforge.
+   
+
+23 June 2006
+
+    I've been frustrated for some time with the way
+the LPUniversity site seems almost intentionally
+designed to be confusing and inscrutable to newbie
+mudders. For example, if I didn't happen to know
+the site is supposed to be an LPC mud resource, the
+front page wouldn't be much help in informing me.
+
+    So I bought a domain with the single purpose
+of clarifying things. It's a shame I had to take it
+upon myself, but you know what they say about things
+done right.
+
+    The lpmuds.net site +is intended to be a simple,
+easy-to-read description of LP muds. What they are,
+where you can get some, and where you can go to
+talk about them. None of this fancy calendaring,
+plenipotentiary council executive meetings, soup for
+the needy, whatever.
+
+    It's just a web site with information that I
+hope is useful.
+
+    If you have any suggestions or requests about
+what the site should have, please let me know.
+
+    On another note, please be aware that Dead Souls
+is no longer GPL. For more information, please see
+this +article.
+
+    Saquivor has found a neat creation GUI that he's
+adapting for DS use. Keep an eye on the downloads page
+for a DS template. It should be available soon.
+
+
+18 June 2006
+
+    The 2.0r26 +patch is out. Anyone under that rev is
+subject to having their mud compromised by any creator
+at any time. Please upgrade NOW if +you haven't already
+done so.
+
+    As to the issue of Tacitus, please see this link.
+
+
+16 June 2006
+
+    As usual, good news and bad news. The good news +first. Tacitus
+helped discover a serious security flaw in Dead Souls. Woot!
+Congratulations to him for being clever, and thanks for
+helping secure DS.
+
+    The bad news is that all versions of DS are +affected, so
+you should lock your DS muds (using admintool) and avoid
+promoting anyone to a Creator position until the patch
+is in place. Hopefully I'll be able to cook something up
+this evening.
+
+    The other bad news is that I found Tacitus trying
+to delete log files on the dev Dead Souls mud. I think I
+was fortunate that he missed a couple of details in rooting
+me, so he failed. However, until I can account for every
+free inode with recovery software, the dev mud will
+be locked also. Sadface.
+
+    For some reason, he also chose to go online and +announce
+the details of the flaw without giving me a chance to
+address it. This means you are rather exposed, so please
+make sure to only allow very +trusted people to Creator postions.
+
+
+
+13 June 2006
+
+    The I3 +router box suffered a storage subsystem failure:
+around 8pm the fiber array crapped out and took down the raid volume
+the I3 router mud was on. As of 9:20 I3 is back up.
+
+
+09 June 2006
+
+    ROXOR. I discussed with Marius the MudOS bundling
+question. Here's the +scoop.
+
+
+
+06 June 2006
+
+    I am so delighted I could pop any moment. Earlier
+today I checked the LPU forums while at a work site,
+and was just blown away to see Saquivor had solved
+the Windows sockets problem. I was all smiles, and
+could barely wait to get to my desk to poke at it.
+
+    Then...sadface. It looked like we solved the +technical
+problem of networking, but the next problem involved GPL
+code. MinGW used libcrypto that I could not be sure
+was not GPL, and the native Win32 binary we made required
+that dll.
+
+    In a burst of uncharacteristic optimism, I went
+about seeing if I could obviate the GPL library in
+question, and eventually solved the problem by using
+the MudOS built-in MD5 hash auth mechanism. JOY. I
+had to get pretty violent with the crypto code, but
+it appears to work well, and is far more secure than
+the old system.
+
+    The only drawback is that new passwords are not +compatible
+with old passwords. A driver change will mean some
+pain. Fortunately this is an unusual situation.
+
+    In the interest of cross-platform compatibility I
+plan to make the Unix side of the DS distro MD5 auth
+also. This will probably happen in the release following
+the release I plan to make this evening.
+
+
+
+05 June 2006
+
+    I spent the entire weekend hacking at MudOS to
+try to compile a native Win32 binary. I made a solid
+amount of progress, and I'm almost there, but I
+need help. Please see if you +can lend a hand.
+
+    I called RedHat bright and early today, to get
+in touch with the Cygwin licensing people. Predictably,
+I got no straight answers, and I am now officially waiting
+for a call beck from a Sales Rep named Mike within
+then next two to three business days.
+
+    What do you suppose are the chances that a Sales
+representative will offer me what I want for free?
+----
+
+    He got back to me! And the verdict is:
+
+" That license costs 25K per +year.  I did not mention it as an option +because you mentioned you we looking for a free/low cost option. The +Buyout license doesn't qualify.
+Mike "
+----
+
+   
CASE CLOSED.
+
+
+
+
03 June 2006
+
+    The good news is that version 2.0r24 of Dead Souls
+is now available for download +from Sourceforge.
+
+    The bad news is that thanks to another +observation
+from that member of the mud community
, it's come to my
+attention that despite my best efforts, the Windows
+version of Dead Souls *still* may violate GPL.
+
+    I am erring on the side of caution and have unbundled
+the Windows binary and Cygwin dll's from the Dead Souls
+distribution.
+
+    I very much hope to have a Windows solution soon,
+as a substantial number of the Dead Souls userbase
+is on Windows, and presumably there are other folks
+interested in using it.
+
+    If you can provide me with instructions on how to
+make a non-license-violating MudOS binary, or if
+you wish to provide me that binary already compiled,
+I'd be delighted to accept that contribution for
+consideration.
+
+Until then, hang tight. We'll figure something out.
+
+
+
+
01Jun06
+
+
+    Dead Souls has been removed from the mudmagic file
+repository. For details, please read this article.
+
+    I'm delighted to announce that Alexander +Tau has been
+promoted to a position of substantial admin authority at
+LPUniversity, and he has created a Dead +Souls forum just
+for us! W00t! Congratulations, Alex. I'm certain you will
+do an excellent job.
+
+    I've released a new article dealing with Dead Souls
+and intellectual property
, which tends toward the dry side,
+but it addresses issues that Dead Souls admins may have
+brought up to them. It's intended as a reference for the
+"official" position of Dead Souls on such matters.
+
+    You may have noticed a sexy new CSS style format for
+some of the pages on the DS site. This is thanks to
+Kelvin's +efforts. He took my challenge of "if you don't
+like the site's look, do something about it" seriously,
+and boy, it sure is easier to read, isn't it? Thank you,
+Kelvin.
+
+
+
+
+22May06
+
+    If there's one thing that bugs me it's news pages for
+projects that turn into personal blogs. I can't promise it
+won't happen here, but I'll make the effort.
+
+    I've updated the front page a bit for clarity. It was
+getting so *I* couldn't read it. I'm a fan of simple readable
+text, and I hope it's easier to get what you need from it.
+    Also added a cute little favicon.
+
+    As of the current version, 2.0r22, Dead Souls is now +a
+single download package...just one file to download whether
+you run the Windows version or the UNIX/source code version.
+    The same is true for the patch. One file to rule +them.
+
+    I've been asked by people how they can give back to
+the Dead Souls community. Easy. Evangelize. Tell people what
+you honestly think of the lib. If someone's in doubt as
+to which codebase to choose, point them our way.
+
+    If you can help me promote the lib, you've done a
+good service. The more people use Dead Souls, the stronger
+we are as a community. Join the MUD forums and spread the
+word, or if that's not your style, lurk until the opportunity
+presents itself to give us a good old shameless plug.
+
+    Also, spend some time on the LPUniversity +forums.
+(Update, 27sep06: go to http://lpmuds.net/forum/ +instead)
+Create a login, and chat a bit. Liven the place up.
+
+
+ +
+
+
Dead Souls Home  +
+ + diff --git a/lib/www/print.css b/lib/www/print.css new file mode 100644 index 0000000..d281106 --- /dev/null +++ b/lib/www/print.css @@ -0,0 +1,9 @@ +#headerarea +{ + display: none; +} + +.tborder +{ + border: none; +} \ No newline at end of file diff --git a/lib/www/reference.jpg b/lib/www/reference.jpg new file mode 100644 index 0000000..9a7cc04 Binary files /dev/null and b/lib/www/reference.jpg differ diff --git a/lib/www/router.html b/lib/www/router.html new file mode 100644 index 0000000..973c57e --- /dev/null +++ b/lib/www/router.html @@ -0,0 +1,19 @@ + + + + Dead Souls I3 router + + + + + + + +The content of this page has been moved to http://lpmuds.net/intermud.html
+
+You should be redirected there momentarily.
+
+
+ + diff --git a/lib/www/router_rules.html b/lib/www/router_rules.html new file mode 100644 index 0000000..40023b8 --- /dev/null +++ b/lib/www/router_rules.html @@ -0,0 +1,19 @@ + + + + Dead Souls I3 router + + + + + + + +The content of this page has been moved to http://lpmuds.net/intermud.html#rules
+
+You should be redirected there momentarily.
+
+
+ + diff --git a/lib/www/smflogo.gif b/lib/www/smflogo.gif new file mode 100644 index 0000000..b97cbc1 Binary files /dev/null and b/lib/www/smflogo.gif differ diff --git a/lib/www/style.css b/lib/www/style.css new file mode 100644 index 0000000..3f4ecab --- /dev/null +++ b/lib/www/style.css @@ -0,0 +1,133 @@ +div#header { + border-bottom:3px outset blue; +} + +p#headertext { + text-align:center; + font-size:x-large; + margin:0px; + padding-top:5px; +} + +p#subheadertext { + text-align:center; + margin:0px; + padding:0px; + padding-bottom:10px; +} + +div#bodytextcontainer { + margin-left:7px; + margin-right:7px; +} + +div#footer { + border-top:3px inset blue; + padding:2px; + text-align:right; + padding-top:5px; + margin-top:10px; + height:45px; +} + +div#footer img, p, a, div { + vertical-align:middle; +} + +table { + margin-left:auto; + margin-right:auto; +} + +td { + vertical-align: top; + padding:3px; + padding-left:8px; + border:1px outset navy; + padding-bottom:15px; + background: rgb(236,240,255); + color:black; +} + +h1 { + font-size:large; +} + +h2 { + padding:2px; + margin:2px; + font-size:medium; + border-bottom:1px solid gray; +} + +ul { + padding-top:0px; + padding-bottom:0px; + margin:0px; +} + +li { + padding-top:2px; + padding-bottom:2px; +} + +ul.input { + list-style-type:none; + padding-left:10px; +} + +div.inputcontainer { + border:1px solid gray; + background:rgb(236,240,255); + color:black; + font-family:monospace; + padding:5px; +} + +hr { + border: 1px dashed navy; +} + +img { + border:none; +} + +a { + color:blue; +} + +a:visited { + color:navy; +} + +a:hover { + color:red; +} + +a:active { + color:purple; +} + +p { + padding:0px; +} + +.centered { + margin-left:auto; + margin-right:auto; +} + +.centered_txt { + text-align:center; +} + +.command { + color:red; + font-weight:bold; + font-family:monospace; +} + +.backtotop { + font-size:small; + font-weight:normal; +} diff --git a/lib/www/value.jpg b/lib/www/value.jpg new file mode 100644 index 0000000..bf5ab98 Binary files /dev/null and b/lib/www/value.jpg differ diff --git a/lib/www/verbs.html b/lib/www/verbs.html new file mode 100644 index 0000000..1e398bb --- /dev/null +++ b/lib/www/verbs.html @@ -0,0 +1,126 @@ + + + + + Verb Tutorial + + + + +
The Verb

Note: This page is for advanced coders who need to
create new verbs, or modify existing ones. Newbie
coders should not assume they need to know anything
here.

The verb is like anything else. Exactly as
good as you make it, no more and no less. Deconstructing
a new verb for the first time can be confusing, but
in doing so you will gain a better understanding of
the parsing system Dead Souls uses.

Please note, if there's anything here hard to
follow or understand, you need to review the Creator's
Manual for key LPC concepts.


The verb itself

Rules and tokens

can's and do's

The object: direct_ and indirect_

References


The verb itself

Let's take a look at the code for a verb, and dissect
it for meaning.
+
#include <lib.h>

inherit LIB_VERB;

static void create() {
verb::create();
SetVerb("buy");
SetSynonyms("purchase");
SetRules("STR from LIV");
SetErrorMessage("Buy what from whom?");
SetHelp("Syntax: <buy ITEM from VENDOR>\n\n"
"Blah blah this is the help message.");
}

mixed can_buy_str_from_liv(string str) {
if( this_player()->GetParalyzed() ) {
return "You cannot do anything.";
}
return this_player()->CanManipulate();
}

mixed do_buy_str_from_liv(string str, object vendor) {
return vendor->eventSell(this_player(), remove_article(lower_case(str)));
}


If you never looked at a verb before, it can
look rather alien and disgusting, like a dead facehugger.
But like the facehugger, it's actually quite beautiful
in its own way.
Let's dissect and comment it now:


#include <lib.h>
// This include statement allows us to use macros, or nicknames,
// for certain things. Specifically, the lib include gives us
// knowledge of what we mean by LIB_VERB.

inherit LIB_VERB;
// This line tells us that we will be inheriting all the
// functions and variables defined in /lib/verb.c .

static void create() {
// The create function is like main() in C/C++. A function that
// is *always* called when an object is loaded. Therefore,
// anything important goes inside here.

verb::create();
// The :: operator is called the "scope resolution operator".
// That's a fancy way of saying that we are trying to use
// a function that exists somewhere in the inheritance tree, and
// not in this individual file. The verb::create() line above
// is saying "At this point, execute any directives in the
// create() function of LIB_VERB". This is necessary because
// the create() function we define here will override the create()
// function we inherit, and that overridden function might have
// had important stuff in it we need to have happen.
// If you didn't understand any of that, you should probably
// stop reading this tutorial and get started on reading
// the Creator's manual.

SetVerb("buy");
// This identifies what word the parser should associate
// with this verb.

SetSynonyms("purchase");
// Self explanatory. This is where you specify words with a
// similar meaning that should also be associated with this verb.

SetRules("STR from LIV");
// Here's one of the new and exotic features of verbs. Rules and tokens.
// When the parser catches the "buy" word from the user's input,
// it will check to see if the rest of the words in the
// command line conform the the known set of rules for the verb.
// if they don't, the parser will error. We'll go over the rules
// a bit further on.

SetErrorMessage("Buy what from whom?");
// By default, the parser's error messages aren't terribly
// descriptive or helpful...usually it's along the lines
// of "You can't X the Y". The line above lets you provide the
// user a clue as to how to better avail themselves of the
// verb's functionality.

SetHelp("Blah blah this is the help message.");
// When the user types "help buy", this is what they get.

// The create function ends here, with the close brace
// below this line.
}


mixed can_buy_str_from_liv(string str) {
// This function does some very rudimentary checks of
// whether the user can use the verb. The can_* type
// functions will be discussed in more detail a bit
// further on.

if( this_player()->GetParalyzed() ) {
return "You cannot do anything.";
}
// Pretty self-explanatory. An obvious check.

return this_player()->CanManipulate();
// The player object has a CanManipulate() function. If
// the player has no prehensile limbs (i.e. "wielding limbs",
// like hands) then the CanManipulate() function in their
// object returns 0. Since the line above returns whatever
// CanManipulate() returns, that means that if the player
// is missing both hands, he can't sell anything. The verb
// will fail.

mixed do_buy_str_from_liv(string str, object vendor) {
// Like the can_* functions, do_ functions will get more
// treatment further on. This is generally where the actual
// "doing" of the verb gets fired off, if appropriate.

return vendor->eventSell(this_player(), remove_article(lower_case(str)));
// Did you notice that this function is declared as type "mixed"?
// This allows us to return weird stuff, like in this case where
// we're returning the result of a function call. We're not
// 100% sure what data type eventSell() in the vendor returns,
// so mixed covers all the bases. Whatever eventSell() returns,
// that's what gets returned here. If the parser got this far,
// then the verb's execution was successful.
// That doesn't necessarily mean that the player successfully
// sold anything. It may be he lacks enough quatloos for the
// shizbat. But that is no concern of the verb. That is the
// business of the eventSell() function it called on the vendor.
}


Rules and tokens

By a magic I do not fully understand myself, the
parser (which lives in the compiled driver binary, meaning
it was written in C and therefore inscrutable to me) can
actually work out from your command line what object you meant
to do what to with what.

For example, if you are in a room full of orcs,
and you type:

kill orcs

The parser actually susses out that orcs are objects
in your environment, and that you intend to act on more than
one of them. The parser will go on to check the attack verb
for its known rules. The rules for "attack" look like this:

SetRules("LVS", "only LVS","LVS only")

The parser sees that you meant two objects that
are living, and sure enough, the attack verb will accept
"multiple living things" as a rule. In this case, the
matched rule is the first one, with the token LVS.

Hold on there, you say. What if I typed kill orc ,
in the singular? This would still match the first rule,
because LVS doesn't just stand for "multiple living things".
It's rather more like "one or more living things".

If the first attack token were LIV instead, then
killing a singular orc would succeed in the parser, but
killing plural orcs would probably fail.

The second rule has two tokens. One is an object
token, LVS, where object is meant in a semi-grammatical sense.
The other is a prepositional token, which is also meant in
a semi-grammatical sense.

The way "object" and "preposition" are handled in
the parser's grammar is not the way they are handled in
English grammar. For example, you may be feeling indignant
at being told that "only" is a preposition. Obviously, in
English, it isn't. However, the parser isn't as linguistically
sophisticated as you. For the parser, anything used
periverbally that isn't an object is a preposition. Please don't
email me telling me I don't know my English grammar. When I
talk subject, object, and preposition here, I am using
the parser's simplified grammar.

As you might have guessed, an "object token" in this case
is the noun that the verb will be working with. Note that the
subject is assumed to be the caller, or player, that invoked the
verb's execution, and does not have an explicit token identified.

So, back to our second rule. "only LVS" means that
I can issue a command like this:

kill only the second orc

And the parser will not reject it. However, failing
to use the preposition token explicitly allowed in a rule
will cause the parser to error. Trying to:

kill merely the second orc

will not bring joy.

The known object tokens are:

LIV - one living thing
LVS - one or more living things
OBJ - one object
OBS - one or more objects
STR - a string of characters
WRD - a generic thing that may be a string, object, or living thing

To get a list of known preposition tokens, type:

eval return MASTER_D->parse_command_prepos_list()


can's and do's

Following the create() fun you saw two types of functions:
can_* and do_*. These are sometimes called "applies". When you see
someone referring to an apply, they mean a function called by the driver.

Notionally, the can_ applies are meant to test the
validity of the verb's execution, and the do_ applies are
meant to perform the actions required.

In practice, this is only somewhat the case. Whether
it's a bug or feature, the can_ applies tend to mangle the
arguments they receive. Pretty much no matter what the
argument is, it gets turned into a string. It's a peculiar
"gotcha" that will have you spinning your wheels for a long time
if you don't happen to know it.

That doesn't mean the can_ applies are useless. They are
in fact necessary. If the can_ apply doesn't exist, or doesn't
return a positive integer, the do_ apply won't happen, meaning your
verb won't execute. Since the can_ applies are somewhat hobbled,
use them for quick, obvious sanity checks, like "is this
player dead" or "does she have hands to manipulate anything with".

If you need to do a check, for example, to ensure that
the vendor is an elf, that means that you need to make a
call to that vendor object. Since the can_ applies won't
handle object arguments, this check will need to happen in the
do_ function.

Some examples of can_ and do_ verb applies:

can_throw_obj()

Pretty obvious. The command in question would be something
like "throw switch" perhaps.

can_throw_obj_word_obj()

A little trickier. Now we're allowing for a wildcard prepositional token. Here
the command might be "throw ball at benny", but because the token
is not explicitly listed (that would be
something like can_throw_obj_at_obj())
and the target is not explicitly a living thing, this apply
also matches "throw the sword in the lake". Note it won't match
"throw the jacks on the floor".


do_read_str_on_obj(string str, object ob)

If your verb has a can
_read_str_word_obj(string str, object ob) apply that
returned 1, then this sweet baby gets called. Presumably here you'd
have the verb call the object and tell it to do something with the
arguments provided. Here is where the actual reading action begins.


Alas, the work of parser applies is not done. The object in
question must have matching direct_ and indirect_ applies, otherwise,
error occurs. These applies are discussed in the next section.



The object: direct_ and indirect_

As you can see, the thing that gives a do_ apply
its whammy is a call to an object. That's the point of a verb,
is doing something, and in the case above, its:

return vendor->eventSell(this_player(), remove_article(lower_case(str)));

However, if you make a verb like this, and then
just try to use it, it'll fail. This is because the driver
needs the objects it acts on to have applies that
correspond to the do_ applies.

The corresponding applies are direct_ and indirect_ ,
and the appropriate one must exist in the object.

Verb applies are usually added to the lib
objects that are appropriate. For example, let's take
the "press" verb. When you "push the button", the parser
checks with the verb daemon, VERBS_D, to find out if
"push" means anything. Sure enough, it's a synonym for
"press", so the parser checks out the rules for press.

Eventually the parser decides all the t's are
crossed and i's are dotted, and it's time to actually
see whether the "button" you're talking about is
pressable. It does this by calling the following apply
in the button object:

direct_press_obj(<the button object is the argument here>)

If the button does not have this function,
or if the function returns 0, the parser errors, assuming
that you're trying to press something that isn't
supposed to be pressable. Therefore, if you're going to
make a button somewhere, or a wall or anything that
should do something when pushed, it will need to
have that function in it. The way it looks is something
like this:


mixed direct_press_obj(object target) {
return CanPress(this_player());
}

Now, this gets complicated, because the CanPress()
fun is a function that checks to see whether the
relationship between the button, the presser, and the lib
permits the pressing.

If you're going to have an object that is
pressed, it's going to be a right pain in the butt to
code all the necessary checks into that object. Fortunately,
you don't need to. If you make a pressable thing, you don't
need to code all that stuff yourself. Just have it
inherit LIB_PRESS, which is a file that already
contains the applies you need.

But, we're not done. You'll need to understand
a couple more things to be able to construct your new verb.

direct and indirect refer to the relationship
of two objects on a command line. If all you have is
"throw ball", there's no need to worry about object relationship.
But what if the command is "shoot nice guy eddy with pistol"?
Or, suppose the player types "shoot pistol at eddy"?

The parser needs to differentiate between the two,
but it isn't nearly sophisticated enough to understand the
concept of who is acting on whom. The parser just needs to
know which is first and which is second. therefore, in
LIB_SELL you'll see:


mixed direct_sell_obj_to_liv()

where the direct object is obj and the indirect object
is liv, and:

mixed indirect_sell_liv_obj()

where the direct object is liv and the indirect object is obj.
Again, this is not English grammar, it's parser grammar.



References

Though sparse, there are other sources of information
on verbs and the parser. Some of it is quite thorough but
incomprehensible. Some of it is crystal clear but not applicable
to the current version of MudOS and/or Dead Souls.

You're encouraged to visit the following sites
to gain more insight into the parser, but be warned that I
cannot vouch for the intelligibility or applicability of
their information.

Please let me know if you find others.


http://www.dnd.utwente.nl/~krimud/Docs/NMAdmin/Parser/


http://www.islandsofmyth.org/wiz/parser_guide.html



Within the mud, you should read and understand the
parser related man page, specifically:

man parse_command



Dead Souls Homepage

+ + diff --git a/lib/www/versions.html b/lib/www/versions.html new file mode 100644 index 0000000..4c5d7ee --- /dev/null +++ b/lib/www/versions.html @@ -0,0 +1,142 @@ + + + + + Dead Souls FAQ + + + + +
Dead Souls Versions

Written by Cratylus @ Dead Souls, November 2006
Updated May 2009

Dead Souls has a ridiculous number of versions. It's likely a symptom of disorganization
and carelessness, and it certainly wasn't out of a desire to confuse folks. This page
is intended to explain what each version's deal is.

If you're deciding, and aren't interested in which license does what, Dead Souls 2.10.x
is your best bet.


+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Version
+
Description
+
License
+
+
Dead Souls 1.1pre
+
Original release
+
public domain
+
+
Dead Souls 1.1
+
Easy-to-install version of the +original
+
public +domain
+
Dead Souls I
+
Updated 1.1, using FluffOS as a +driver and including a Windows executable
+
public domain
+
+
Dead Souls 2.0r26
+
Old stable version of 2.x (not +recommended)
+
GPL
+
+
Dead Souls 2.10.x
+
Radically updated and debugged +version
+
Proprietary
+
+
Dead Souls II
+
Derived from 2 but without +some material
+
public +domain
+
Dead Souls 2.XaX
+
"bleeding edge" Alpha versions: +under current development
+
Proprietary
+


Dead Souls 1.1pre

This is the original. In 1997 or 1998 (there are conflicting
histories), Descartes decided to release his development lib to the public
domain. It was a fine basis for any mud, but it was released without a
driver, and for various reasons including FUD and difficulty setting it
up, people just didn't use it much.

This distribution is largely a historical artifact at this point.
It can certainly serve as a basis for someone else's new lib distribution
project, or it can serve as a vital reference for those interested in the
minutiae of the development of the DS family. However it is not helpful
for "newbie" mud admins/owners. The learning curve required to
get this fine, but limited, lib is very steep.

You can download it here: http://lpmuds.net/files/deadsouls/ds1.1pre.tar.gz


Dead Souls 1.1

In terms of lib code, this is almost identical to
Dead Souls 1.1pre. The main difference is that it includes the driver,
and has been fixed up to boot and work reasonably well upon installation.
It's also configured to connect to the yatmim intermud router.

This version of Dead Souls (but not the driver) is also public
domain. Like Dead Souls 1.1pre it is mostly useful as a curiosity,
museum piece, or research specimen.

You can download it here: http://lpmuds.net/files/deadsouls/ds1.1.tar.gz


Dead Souls I

Pretty much the same as 1.1 but using FluffOS as a driver
to allow for greater compatibility with modern OS'es and PC's, and
it includes the Windows executable.

Available here: http://lpmuds.net/files/deadsouls/dsI.zip


Dead Souls 2.0r26

The difference between Dead Souls 1.1 and 2.0r26 is dramatic.
Numerous samples exist, including a sample town. There is a "code-free"
online creation system
. Many, many bugs are fixed, and useful new systems
implemented, such as a menu based administration tool.

2.0r26 also contains the documentation that Descartes had pulled
from 1.1pre. With his permission, I added his old Nightmare docs, which
are something like 99.99% applicable to Dead Souls. In addition to those
docs, 2.0r26 contains DS-specific documentation.

Finally, 2.0r26 contains not only driver source for UNIX
installs, it also contains a pre-compiled driver executable for Windows,
so that in a single distribution, you have everything you need to run
Dead Souls on either UNIX or Microsoft Windows.

2.0r26 is not public domain software. Unlike the 1.x versions,
2.0r26 is distributed under the GPL. This is actually not very meaningful
for software that is designed to run from interpreted plaintext files.
It was a futile attempt to comply with the licensing of other software
that it used to be bundled with. It's no longer bundled with GPL
stuff, so again, there's not much point in it being GPL.

The fact that 2.0r26 is still distributed under GPL is largely
due to 1) laziness on my part 2) the requirement of SourceForge to
have only OSS software hosted on their site 3) I think that's it.
Laziness and convenience.

You can download it here: http://lpmuds.net/files/deadsouls/dead_souls_2.0r26b.zip


Dead Souls 2.10.x

2.10.x represents a "finished, stable product".
While in theory you could easily run a successful mud with 2.0r26, if
you run into a bug or a problem, the answer in almost every case is
"upgrade to 2.10.x", so I generally encourage people to avoid 2.0r26
and download 2.10.x instead. It also has major new improvements
both in features and security.

The licensing for 2.10.x is not GPL and not PD. It's a sort of
muddled proprietary license which basically says "you can use this as
a mud, modify it, whatever, have fun, but I retain copyright". It's vague
because I simply am sick of thinking about licensing. It's not GPL
because I'm even sicker of people telling me what I can or can't do
with my GPL'ed software.

My "I can't be bothered to think about licensing" attitude
tends to freak out some people for whom licensing is Really Really
Important. So you may see flames back and forth between me and such
people on various mud discussion forums. I think that's pretty
normal. If you hear anyone referring to Dead Souls and licensing
issues, it's almost certainly a reference to the controversy and
friction caused by my adversarial relationship with folks I affectionately
refer to as the License Taliban.

You can download it here: http://dead-souls.net/code/dead_souls.zip


Dead Souls II

This is a version of Dead Souls derived from 2.x, but which
has had documentation removed. It also has had various files that I did
not write removed. The result is a lib which is about 98 to 99% code-identical
to 2.x, but is actually public domain.

The reasons for releasing years' worth of work into the public
domain are explained in the Dead Souls II FAQ.

You can download it here: http://lpmuds.net/files/deadsouls/dsIIr8.zip


Dead Souls 2.XaX

"Alpha versions" are rough, pre-release packages that are like the official
release, except they are more cutting edge. That makes them both fun to try
out (which is why I make them available) but also not really stable to use
for your production mud, because often with new features come new bugs.

One of the big reasons I'm not doing frequent public releases, with
patches, is that a great many of the things I'm doing represent compatibility
breakers with stable releases. If I did frequent "official" releases and upgrades,
people would be running into compat problems continually.

Instead, I'm holding off until I'm more confident that the big compat busters
are taken care of, so that subsequent releases and upgrades are less painful.
The idea is to have big compat pain just the once.

So, that's the idea of making sneak-peek alphas available, but not officially
supported releases.

Having said that, the alpha releases are as runtime stable and more
feature-rich than any released lpmud lib you'll find out there, so when I say
they are "unstable", it is relative to what I expect DS official releases
to be, and also in part refers to the fact that alphas are subject to frequent
updates and changes.

For information on the big differences between recent alphas and the stable
release, read this: http://dead-souls.net/RELEASE_NOTES

Alphas (if available) can be found here: http://dead-souls.net/code/alpha/

+The end.
+
+Dead Souls Homepage
+
+
+ + diff --git a/runmud.bat b/runmud.bat new file mode 100644 index 0000000..f3beebf --- /dev/null +++ b/runmud.bat @@ -0,0 +1,7 @@ +# This improved batch file courtesy of Brodbane @ Eve +goto start +:start +win32\driver.exe lib\secure\cfg\mudos.win32 +# Add a '#' to the following line to prevent auto-restarts +goto start +:end diff --git a/win32/driver.exe b/win32/driver.exe new file mode 100644 index 0000000..476b284 Binary files /dev/null and b/win32/driver.exe differ